From b1d7448be0c2aff866de6449749441fb7e1d4f98 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 2 Jan 2014 00:40:32 -0600 Subject: [PATCH 0001/2527] WIP ES6 lol --- Gruntfile.js | 66 + bower.json | 7 + package.json | 8 +- packages/activemodel-adapter/lib/main.js | 11 +- packages/activemodel-adapter/lib/system.js | 6 +- .../lib/system/active_model_adapter.js | 16 +- .../lib/system/active_model_serializer.js | 12 +- .../lib/system/embedded_records_mixin.js | 10 +- packages/ember-data/lib/adapters.js | 6 +- .../lib/adapters/fixture_adapter.js | 9 +- .../ember-data/lib/adapters/rest_adapter.js | 10 +- packages/ember-data/lib/core.js | 2 + packages/ember-data/lib/ext.js | 1 - packages/ember-data/lib/initializers.js | 5 +- packages/ember-data/lib/main.js | 105 +- .../lib/serializers/json_serializer.js | 4 +- .../lib/serializers/rest_serializer.js | 7 +- packages/ember-data/lib/system/adapter.js | 9 +- packages/ember-data/lib/system/changes.js | 24 +- .../lib/system/changes/attribute_change.js | 4 +- .../lib/system/changes/relationship_change.js | 112 +- packages/ember-data/lib/system/debug.js | 7 +- .../lib/system/debug/debug_adapter.js | 9 +- .../ember-data/lib/system/debug/debug_info.js | 6 +- packages/ember-data/lib/system/model.js | 8 +- .../ember-data/lib/system/model/attributes.js | 9 +- packages/ember-data/lib/system/model/model.js | 13 +- .../ember-data/lib/system/model/states.js | 2 +- .../lib/system/record_array_manager.js | 7 +- .../ember-data/lib/system/record_arrays.js | 15 +- .../adapter_populated_record_array.js | 7 +- .../record_arrays/filtered_record_array.js | 6 +- .../lib/system/record_arrays/many_array.js | 11 +- .../lib/system/record_arrays/record_array.js | 7 +- .../ember-data/lib/system/relationships.js | 9 +- .../lib/system/relationships/belongs_to.js | 8 +- .../lib/system/relationships/ext.js | 11 +- .../lib/system/relationships/has_many.js | 6 +- packages/ember-data/lib/system/store.js | 15 +- packages/ember-data/lib/transforms.js | 7 + packages/ember-data/lib/transforms/base.js | 4 +- packages/ember-data/lib/transforms/boolean.js | 4 +- packages/ember-data/lib/transforms/date.js | 5 +- packages/ember-data/lib/transforms/index.js | 5 - packages/ember-data/lib/transforms/number.js | 5 +- packages/ember-data/lib/transforms/string.js | 5 +- .../tests/integration/application_test.js | 2 +- packages/ember-inflector/lib/ext/string.js | 6 +- packages/ember-inflector/lib/main.js | 14 +- packages/ember-inflector/lib/system.js | 16 +- .../ember-inflector/lib/system/inflections.js | 4 +- .../ember-inflector/lib/system/inflector.js | 2 +- packages/ember-inflector/lib/system/string.js | 11 +- tasks/browser.js | 14 + tests/ember-data-setup.js | 60 + tests/ember_configuration.js | 74 +- tests/index.html | 21 + tests/qunit_configuration.js | 217 ++ tests/vendor/qunit.css | 244 ++ tests/vendor/qunit.js | 2212 +++++++++++++++++ vendor/loader.js | 53 + 61 files changed, 3316 insertions(+), 259 deletions(-) create mode 100644 Gruntfile.js create mode 100644 bower.json delete mode 100644 packages/ember-data/lib/ext.js create mode 100644 packages/ember-data/lib/transforms.js delete mode 100644 packages/ember-data/lib/transforms/index.js create mode 100644 tasks/browser.js create mode 100644 tests/ember-data-setup.js create mode 100644 tests/index.html create mode 100644 tests/qunit_configuration.js create mode 100644 tests/vendor/qunit.css create mode 100644 tests/vendor/qunit.js create mode 100644 vendor/loader.js diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 00000000000..02d9ecfdc0e --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,66 @@ +var matchdep = require('matchdep'); + +function nameFor(path) { + var result, match; + if (match = path.match(/^(?:lib|test|test\/tests)\/(.*?)(?:\.js)?$/)) { + result = match[1]; + } else { + result = path; + } + + return path; +} +module.exports = function(grunt){ + + matchdep.filterDev('grunt-*').forEach(grunt.loadNpmTasks); + grunt.loadTasks('tasks'); + + grunt.initConfig({ + pkg: require('./package.json'), + clean: { + main: [ 'tmp/**/*' ] + }, + transpile: { + amd: { + type: 'amd', + moduleName: nameFor, + files: [{ + expand: true, + cwd: 'packages/', + src: [ '**/lib/**/*.js', ], + dest: 'tmp', + ext: '.amd.js' + }] + } + }, + concat: { + amd: { + src: [ 'tmp/**/*.amd.js' ], + dest: 'tmp/ember-data.amd.js' + }, + globals: { + src: [ 'vendor/loader.js', 'tmp/**/*.amd.js' ], + dest: 'tmp/ember-data.browser1.js' + }, + tests: { + src: [ 'packages/**/tests/**/*.js' ], + dest: 'tmp/tests.js', + options: { + separator: ';\n', + process: function(src, filepath){ + return "(function(){\n" + src + "\n})()"; + } + } + } + }, + + browser: { + dist: { + src: 'tmp/ember-data.browser1.js', + dest: 'dist/ember-data.js' + } + } + }); + + grunt.registerTask('default', [ 'clean', 'transpile:amd', 'concat:globals', 'browser:dist', 'concat:tests' ]); +}; diff --git a/bower.json b/bower.json new file mode 100644 index 00000000000..a5eb8116a3c --- /dev/null +++ b/bower.json @@ -0,0 +1,7 @@ +{ + "name": "ember-data", + "private": true, + "dependencies": { + "ember": "~1.2.0" + } +} diff --git a/package.json b/package.json index 220f69ecaee..d1f0fea3a7c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,12 @@ { + "name": "ember-data", + "namespace": "DS", "devDependencies": { "defeatureify": "~0.1.4", - "yuidocjs": "~0.3.46" + "yuidocjs": "~0.3.46", + "grunt-es6-module-transpiler": "~0.6.0", + "grunt": "~0.4.2", + "grunt-contrib-clean": "~0.5.0", + "grunt-contrib-concat": "~0.3.0" } } diff --git a/packages/activemodel-adapter/lib/main.js b/packages/activemodel-adapter/lib/main.js index bc31a629fc8..5fd4a857bee 100644 --- a/packages/activemodel-adapter/lib/main.js +++ b/packages/activemodel-adapter/lib/main.js @@ -1,2 +1,9 @@ -require('activemodel-adapter/system'); -require('activemodel-adapter/initializers'); +import {ActiveModelAdapter, ActiveModelSerializer, EmbeddedRecordsMixin} from "./system"; + +import "./initializers"; + +export { + ActiveModelAdapter, + ActiveModelSerializer, + EmbeddedRecordsMixin +}; diff --git a/packages/activemodel-adapter/lib/system.js b/packages/activemodel-adapter/lib/system.js index 3e4c578ee9d..eb77bcb9460 100644 --- a/packages/activemodel-adapter/lib/system.js +++ b/packages/activemodel-adapter/lib/system.js @@ -1 +1,5 @@ -require('activemodel-adapter/system/active_model_adapter'); \ No newline at end of file +import EmbeddedRecordsMixin from "./system/embedded_records_mixin"; +import ActiveModelAdapter from "./system/active_model_adapter"; +import ActiveModelSerializer from "./system/active_model_serializer"; + +export {EmbeddedRecordsMixin, ActiveModelAdapter, ActiveModelSerializer}; diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index acdf3e6825a..400e25612f5 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -1,6 +1,8 @@ -require('ember-data/adapters/rest_adapter'); -require('activemodel-adapter/system/active_model_serializer'); -require('activemodel-adapter/system/embedded_records_mixin'); +import {RESTAdapter} from "../../../ember-data/lib/adapters"; +import {InvalidError} from "../../../ember-data/lib/system/adapter"; +import {pluralize} from "../../../ember-inflector/lib/main"; +import ActiveModelSerializer from "./active_model_serializer"; +import EmbeddedRecordsMixin from "./embedded_records_mixin"; /** @module ember-data @@ -57,7 +59,7 @@ var forEach = Ember.EnumerableUtils.forEach; @extends DS.Adapter **/ -DS.ActiveModelAdapter = DS.RESTAdapter.extend({ +var ActiveModelAdapter = RESTAdapter.extend({ defaultSerializer: '_ams', /** The ActiveModelAdapter overrides the `pathForType` method to build @@ -74,7 +76,7 @@ DS.ActiveModelAdapter = DS.RESTAdapter.extend({ */ pathForType: function(type) { var decamelized = Ember.String.decamelize(type); - return Ember.String.pluralize(decamelized); + return pluralize(decamelized); }, /** @@ -104,9 +106,11 @@ DS.ActiveModelAdapter = DS.RESTAdapter.extend({ errors[Ember.String.camelize(key)] = jsonErrors[key]; }); - return new DS.InvalidError(errors); + return new InvalidError(errors); } else { return error; } } }); + +export default ActiveModelAdapter; diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index 0ae8f35da0e..cacb2cd6ddd 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -1,5 +1,5 @@ -require('ember-data/serializers/rest_serializer'); - +import {singularize} from "../../../ember-inflector/lib/system"; +import RESTSerializer from "../../../ember-data/lib/serializers/rest_serializer"; /** @module ember-data */ @@ -7,7 +7,7 @@ require('ember-data/serializers/rest_serializer'); var get = Ember.get; var forEach = Ember.EnumerableUtils.forEach; -DS.ActiveModelSerializer = DS.RESTSerializer.extend({ +var ActiveModelSerializer = RESTSerializer.extend({ // SERIALIZE /** @@ -35,7 +35,7 @@ DS.ActiveModelSerializer = DS.RESTSerializer.extend({ if (kind === "belongsTo") { return key + "_id"; } else if (kind === "hasMany") { - return Ember.String.singularize(key) + "_ids"; + return singularize(key) + "_ids"; } else { return key; } @@ -86,7 +86,7 @@ DS.ActiveModelSerializer = DS.RESTSerializer.extend({ */ typeForRoot: function(root) { var camelized = Ember.String.camelize(root); - return Ember.String.singularize(camelized); + return singularize(camelized); }, /** @@ -203,3 +203,5 @@ DS.ActiveModelSerializer = DS.RESTSerializer.extend({ } } }); + +export default ActiveModelSerializer; diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index a4033e4a6e1..caa0ec4cd9f 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -1,6 +1,8 @@ var get = Ember.get; var forEach = Ember.EnumerableUtils.forEach; +import {pluralize} from "../../../ember-inflector/lib/main"; + /** The EmbeddedRecordsMixin allows you to add embedded record support to your serializers. @@ -20,7 +22,7 @@ var forEach = Ember.EnumerableUtils.forEach; @class EmbeddedRecordsMixin @namespace DS */ -DS.EmbeddedRecordsMixin = Ember.Mixin.create({ +var EmbeddedRecordsMixin = Ember.Mixin.create({ /** Serialize has-may relationship when it is configured as embedded objects. @@ -67,7 +69,7 @@ DS.EmbeddedRecordsMixin = Ember.Mixin.create({ */ extractArray: function(store, type, payload) { var root = this.keyForAttribute(type.typeKey), - partials = payload[Ember.String.pluralize(root)]; + partials = payload[pluralize(root)]; forEach(partials, function(partial) { updatePayloadWithEmbedded(store, this, type, partial, payload); @@ -119,4 +121,6 @@ function updatePayloadWithEmbedded(store, serializer, type, partial, payload) { delete partial[attribute]; } }, serializer); -} \ No newline at end of file +} + +export default EmbeddedRecordsMixin; diff --git a/packages/ember-data/lib/adapters.js b/packages/ember-data/lib/adapters.js index e7122b6707a..6042aa99f0b 100644 --- a/packages/ember-data/lib/adapters.js +++ b/packages/ember-data/lib/adapters.js @@ -2,5 +2,7 @@ @module ember-data */ -require("ember-data/adapters/fixture_adapter"); -require("ember-data/adapters/rest_adapter"); +import FixtureAdapter from "./adapters/fixture_adapter"; +import RESTAdapter from "./adapters/rest_adapter"; + +export {RESTAdapter, FixtureAdapter}; diff --git a/packages/ember-data/lib/adapters/fixture_adapter.js b/packages/ember-data/lib/adapters/fixture_adapter.js index 9271d24ff29..e11033375bb 100644 --- a/packages/ember-data/lib/adapters/fixture_adapter.js +++ b/packages/ember-data/lib/adapters/fixture_adapter.js @@ -1,6 +1,3 @@ -require("ember-data/core"); -require("ember-data/system/adapter"); - /** @module ember-data */ @@ -10,6 +7,8 @@ var get = Ember.get, fmt = Ember.String.fmt, var counter = 0; +import Adapter from "../system/adapter"; + /** `DS.FixtureAdapter` is an adapter that loads records from memory. Its primarily used for development and testing. You can also use @@ -27,7 +26,7 @@ var counter = 0; @namespace DS @extends DS.Adapter */ -DS.FixtureAdapter = DS.Adapter.extend({ +var FixtureAdapter = Adapter.extend({ // by default, fixtures are already in normalized form serializer: null, @@ -339,3 +338,5 @@ DS.FixtureAdapter = DS.Adapter.extend({ }, "DS: FixtureAdapter#simulateRemoteCall"); } }); + +export default FixtureAdapter; diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 7face2244c2..145ac4503ea 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -1,12 +1,8 @@ -require("ember-data/core"); -require('ember-data/system/adapter'); - -require('ember-data/serializers/rest_serializer'); - /** @module ember-data */ +import Adapter from "../system/adapter"; var get = Ember.get, set = Ember.set; var forEach = Ember.ArrayPolyfills.forEach; @@ -108,7 +104,7 @@ var forEach = Ember.ArrayPolyfills.forEach; @namespace DS @extends DS.Adapter */ -DS.RESTAdapter = DS.Adapter.extend({ +var RESTAdapter = Adapter.extend({ defaultSerializer: '_rest', /** @@ -549,3 +545,5 @@ DS.RESTAdapter = DS.Adapter.extend({ } }); + +export default RESTAdapter; diff --git a/packages/ember-data/lib/core.js b/packages/ember-data/lib/core.js index 72871a8e77b..5d26529b546 100644 --- a/packages/ember-data/lib/core.js +++ b/packages/ember-data/lib/core.js @@ -28,3 +28,5 @@ if ('undefined' === typeof DS) { Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); } } + +export default DS; diff --git a/packages/ember-data/lib/ext.js b/packages/ember-data/lib/ext.js deleted file mode 100644 index 151e5d98741..00000000000 --- a/packages/ember-data/lib/ext.js +++ /dev/null @@ -1 +0,0 @@ -require('ember-data/ext/date'); diff --git a/packages/ember-data/lib/initializers.js b/packages/ember-data/lib/initializers.js index 48775bd7183..a5d885c59ef 100644 --- a/packages/ember-data/lib/initializers.js +++ b/packages/ember-data/lib/initializers.js @@ -1,6 +1,5 @@ -require("ember-data/serializers/json_serializer"); -require("ember-data/system/debug/debug_adapter"); -require("ember-data/transforms/index"); +import JSONSerializer from "./serializers/json_serializer"; +import DebugAdapter from "./system/debug/debug_adapter"; /** @module ember-data diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index f14be59e351..a2a15adecb5 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -5,15 +5,96 @@ @main ember-data */ -require("ember-data/core"); -require("ember-data/initializers"); -require("ember-data/ext"); -require("ember-data/system/store"); -require("ember-data/system/model"); -require("ember-data/system/changes"); -require("ember-data/system/relationships"); -require("ember-data/system/record_arrays"); -require("ember-data/system/record_array_manager"); -require("ember-data/system/adapter"); -require("ember-data/adapters"); -require("ember-data/system/debug"); +import DS from "./core"; +import "./ext/date"; + +import {Store, PromiseArray, PromiseObject} from "./system/store"; +import {Model, RootState, attr} from "./system/model"; +import { + AttributeChange, + RelationshipChange, + RelationshipChangeAdd, + RelationshipChangeRemove, + OneToManyChange, + ManyToNoneChange, + OneToOneChange, + ManyToManyChange +} from "./system/changes"; +import {InvalidError, Adapter} from "./system/adapter"; +import DebugAdapter from "./system/debug"; +import { + RecordArray, + FilteredRecordArray, + AdapterPopulatedRecordArray, + ManyArray +} from "./system/record_arrays"; +import RecordArrayManager from "./system/record_array_manager"; +import {RESTAdapter, FixtureAdapter} from "./adapters"; +import JSONSerializer from "./serializers/json_serializer"; +import RESTSerializer from "./serializers/rest_serializer"; +import "../../ember-inflector/lib/main"; +import { + ActiveModelAdapter, + ActiveModelSerializer, + EmbeddedRecordsMixin +} from "../../activemodel-adapter/lib/main"; + +import { + Transform, + DateTransform, + NumberTransform, + StringTransform, + BooleanTransform +} from "./transforms"; + +import {hasMany, belongsTo} from "./system/relationships"; +import "./initializers"; + +DS.Store = Store; +DS.PromiseArray = PromiseArray; +DS.PromiseObject = PromiseObject; + +DS.Model = Model; +DS.RootState = RootState; +DS.attr = attr; + +DS.AttributeChange = AttributeChange; +DS.RelationshipChange = RelationshipChange; +DS.RelationshipChangeAdd = RelationshipChangeAdd; +DS.OneToManyChange = OneToManyChange; +DS.ManyToNoneChange = OneToManyChange; +DS.OneToOneChange = OneToOneChange; +DS.ManyToManyChange = ManyToManyChange; + +DS.Adapter = Adapter; +DS.InvalidError = InvalidError; + +DS.DebugAdapter = DebugAdapter; + +DS.RecordArray = RecordArray; +DS.FilteredRecordArray = FilteredRecordArray; +DS.AdapterPopulatedRecordArray = AdapterPopulatedRecordArray; +DS.ManyArray = ManyArray; + +DS.RecordArrayManager = RecordArrayManager; + +DS.RESTAdapter = RESTAdapter; +DS.FixtureAdapter = FixtureAdapter; + +DS.RESTSerializer = RESTSerializer; +DS.JSONSerializer = JSONSerializer; + +DS.Transform = Transform; +DS.DateTransform = DateTransform; +DS.StringTransform = StringTransform; +DS.NumberTransform = NumberTransform; +DS.BooleanTransform = BooleanTransform; + +DS.ActiveModelAdapter = ActiveModelAdapter; +DS.ActiveModelSerializer = ActiveModelSerializer; +DS.EmbeddedRecordsMixin = EmbeddedRecordsMixin; + +DS.belongsTo = belongsTo; +DS.hasMany = hasMany; + +export default DS; diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 818ebfa8ecf..2192aaea139 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -23,7 +23,7 @@ function aliasMethod(methodName) { @class JSONSerializer @namespace DS */ -DS.JSONSerializer = Ember.Object.extend({ +var JSONSerializer = Ember.Object.extend({ /** The primaryKey is used when serializing and deserializing data. Ember Data always uses the `id` propery to store the id of @@ -724,3 +724,5 @@ DS.JSONSerializer = Ember.Object.extend({ return transform; } }); + +export default JSONSerializer; diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index ea2bcd14f32..013b1243969 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -1,9 +1,8 @@ -require('ember-data/serializers/json_serializer'); - /** @module ember-data */ +import JSONSerializer from "./json_serializer"; var get = Ember.get, set = Ember.set; var forEach = Ember.ArrayPolyfills.forEach; var map = Ember.ArrayPolyfills.map; @@ -52,7 +51,7 @@ function coerceId(id) { @namespace DS @extends DS.JSONSerializer */ -DS.RESTSerializer = DS.JSONSerializer.extend({ +var RESTSerializer = JSONSerializer.extend({ /** If you want to do normalizations specific to some part of the payload, you can specify those under `normalizeHash`. @@ -794,3 +793,5 @@ DS.RESTSerializer = DS.JSONSerializer.extend({ json[key + "Type"] = belongsTo.constructor.typeKey; } }); + +export default RESTSerializer; diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 305ae7ba371..db31ac067a4 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -36,7 +36,7 @@ var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'n @class InvalidError @namespace DS */ -DS.InvalidError = function(errors) { +var InvalidError = function(errors) { var tmp = Error.prototype.constructor.call(this, "The backend rejected the commit because it was invalid: " + Ember.inspect(errors)); this.errors = errors; @@ -44,7 +44,7 @@ DS.InvalidError = function(errors) { this[errorProps[i]] = tmp[errorProps[i]]; } }; -DS.InvalidError.prototype = Ember.create(Error.prototype); +InvalidError.prototype = Ember.create(Error.prototype); /** An adapter is an object that receives requests from a store and @@ -97,7 +97,7 @@ DS.InvalidError.prototype = Ember.create(Error.prototype); @extends Ember.Object */ -DS.Adapter = Ember.Object.extend({ +var Adapter = Ember.Object.extend({ /** The `find()` method is invoked when the store is asked for a record that @@ -421,3 +421,6 @@ DS.Adapter = Ember.Object.extend({ return Ember.RSVP.all(promises); } }); + +export {InvalidError, Adapter}; +export default Adapter; diff --git a/packages/ember-data/lib/system/changes.js b/packages/ember-data/lib/system/changes.js index 804c91eef5b..de8df779187 100644 --- a/packages/ember-data/lib/system/changes.js +++ b/packages/ember-data/lib/system/changes.js @@ -2,5 +2,25 @@ @module ember-data */ -require("ember-data/system/changes/attribute_change"); -require("ember-data/system/changes/relationship_change"); +import AttributeChange from "./changes/attribute_change"; + +import { + RelationshipChange, + RelationshipChangeAdd, + RelationshipChangeRemove, + OneToManyChange, + ManyToNoneChange, + OneToOneChange, + ManyToManyChange +} from "./changes/relationship_change"; + +export { + AttributeChange, + RelationshipChange, + RelationshipChangeAdd, + RelationshipChangeRemove, + OneToManyChange, + ManyToNoneChange, + OneToOneChange, + ManyToManyChange +}; diff --git a/packages/ember-data/lib/system/changes/attribute_change.js b/packages/ember-data/lib/system/changes/attribute_change.js index 145e94db79d..00479fd49a6 100644 --- a/packages/ember-data/lib/system/changes/attribute_change.js +++ b/packages/ember-data/lib/system/changes/attribute_change.js @@ -12,7 +12,7 @@ @private @constructor */ -var AttributeChange = DS.AttributeChange = function(options) { +var AttributeChange = function(options) { this.record = options.record; this.store = options.store; this.name = options.name; @@ -46,3 +46,5 @@ AttributeChange.prototype = { delete this.record._changesToSync[this.name]; } }; + +export default AttributeChange; diff --git a/packages/ember-data/lib/system/changes/relationship_change.js b/packages/ember-data/lib/system/changes/relationship_change.js index b977d10e83a..27fb528b0e3 100644 --- a/packages/ember-data/lib/system/changes/relationship_change.js +++ b/packages/ember-data/lib/system/changes/relationship_change.js @@ -2,6 +2,8 @@ @module ember-data */ +import {Model} from "../model"; + var get = Ember.get, set = Ember.set; var forEach = Ember.EnumerableUtils.forEach; @@ -11,7 +13,7 @@ var forEach = Ember.EnumerableUtils.forEach; @private @construtor */ -DS.RelationshipChange = function(options) { +var RelationshipChange = function(options) { this.parentRecord = options.parentRecord; this.childRecord = options.childRecord; this.firstRecord = options.firstRecord; @@ -32,8 +34,8 @@ DS.RelationshipChange = function(options) { @private @construtor */ -DS.RelationshipChangeAdd = function(options){ - DS.RelationshipChange.call(this, options); +var RelationshipChangeAdd = function(options){ + RelationshipChange.call(this, options); }; /** @@ -42,39 +44,39 @@ DS.RelationshipChangeAdd = function(options){ @private @construtor */ -DS.RelationshipChangeRemove = function(options){ - DS.RelationshipChange.call(this, options); +var RelationshipChangeRemove = function(options){ + RelationshipChange.call(this, options); }; -DS.RelationshipChange.create = function(options) { - return new DS.RelationshipChange(options); +RelationshipChange.create = function(options) { + return new RelationshipChange(options); }; -DS.RelationshipChangeAdd.create = function(options) { - return new DS.RelationshipChangeAdd(options); +RelationshipChangeAdd.create = function(options) { + return new RelationshipChangeAdd(options); }; -DS.RelationshipChangeRemove.create = function(options) { - return new DS.RelationshipChangeRemove(options); +RelationshipChangeRemove.create = function(options) { + return new RelationshipChangeRemove(options); }; -DS.OneToManyChange = {}; -DS.OneToNoneChange = {}; -DS.ManyToNoneChange = {}; -DS.OneToOneChange = {}; -DS.ManyToManyChange = {}; +var OneToManyChange = {}; +var OneToNoneChange = {}; +var ManyToNoneChange = {}; +var OneToOneChange = {}; +var ManyToManyChange = {}; -DS.RelationshipChange._createChange = function(options){ +RelationshipChange._createChange = function(options){ if(options.changeType === "add"){ - return DS.RelationshipChangeAdd.create(options); + return RelationshipChangeAdd.create(options); } if(options.changeType === "remove"){ - return DS.RelationshipChangeRemove.create(options); + return RelationshipChangeRemove.create(options); } }; -DS.RelationshipChange.determineRelationshipType = function(recordType, knownSide){ +RelationshipChange.determineRelationshipType = function(recordType, knownSide){ var knownKey = knownSide.key, key, otherKind; var knownKind = knownSide.kind; @@ -99,33 +101,33 @@ DS.RelationshipChange.determineRelationshipType = function(recordType, knownSide }; -DS.RelationshipChange.createChange = function(firstRecord, secondRecord, store, options){ +RelationshipChange.createChange = function(firstRecord, secondRecord, store, options){ // Get the type of the child based on the child's client ID var firstRecordType = firstRecord.constructor, changeType; - changeType = DS.RelationshipChange.determineRelationshipType(firstRecordType, options); + changeType = RelationshipChange.determineRelationshipType(firstRecordType, options); if (changeType === "oneToMany"){ - return DS.OneToManyChange.createChange(firstRecord, secondRecord, store, options); + return OneToManyChange.createChange(firstRecord, secondRecord, store, options); } else if (changeType === "manyToOne"){ - return DS.OneToManyChange.createChange(secondRecord, firstRecord, store, options); + return OneToManyChange.createChange(secondRecord, firstRecord, store, options); } else if (changeType === "oneToNone"){ - return DS.OneToNoneChange.createChange(firstRecord, secondRecord, store, options); + return OneToNoneChange.createChange(firstRecord, secondRecord, store, options); } else if (changeType === "manyToNone"){ - return DS.ManyToNoneChange.createChange(firstRecord, secondRecord, store, options); + return ManyToNoneChange.createChange(firstRecord, secondRecord, store, options); } else if (changeType === "oneToOne"){ - return DS.OneToOneChange.createChange(firstRecord, secondRecord, store, options); + return OneToOneChange.createChange(firstRecord, secondRecord, store, options); } else if (changeType === "manyToMany"){ - return DS.ManyToManyChange.createChange(firstRecord, secondRecord, store, options); + return ManyToManyChange.createChange(firstRecord, secondRecord, store, options); } }; -DS.OneToNoneChange.createChange = function(childRecord, parentRecord, store, options) { +OneToNoneChange.createChange = function(childRecord, parentRecord, store, options) { var key = options.key; - var change = DS.RelationshipChange._createChange({ + var change = RelationshipChange._createChange({ parentRecord: parentRecord, childRecord: childRecord, firstRecord: childRecord, @@ -140,9 +142,9 @@ DS.OneToNoneChange.createChange = function(childRecord, parentRecord, store, opt return change; }; -DS.ManyToNoneChange.createChange = function(childRecord, parentRecord, store, options) { +ManyToNoneChange.createChange = function(childRecord, parentRecord, store, options) { var key = options.key; - var change = DS.RelationshipChange._createChange({ + var change = RelationshipChange._createChange({ parentRecord: childRecord, childRecord: parentRecord, secondRecord: childRecord, @@ -157,14 +159,14 @@ DS.ManyToNoneChange.createChange = function(childRecord, parentRecord, store, op }; -DS.ManyToManyChange.createChange = function(childRecord, parentRecord, store, options) { +ManyToManyChange.createChange = function(childRecord, parentRecord, store, options) { // If the name of the belongsTo side of the relationship is specified, // use that // If the type of the parent is specified, look it up on the child's type // definition. var key = options.key; - var change = DS.RelationshipChange._createChange({ + var change = RelationshipChange._createChange({ parentRecord: parentRecord, childRecord: childRecord, firstRecord: childRecord, @@ -182,7 +184,7 @@ DS.ManyToManyChange.createChange = function(childRecord, parentRecord, store, op return change; }; -DS.OneToOneChange.createChange = function(childRecord, parentRecord, store, options) { +OneToOneChange.createChange = function(childRecord, parentRecord, store, options) { var key; // If the name of the belongsTo side of the relationship is specified, @@ -197,7 +199,7 @@ DS.OneToOneChange.createChange = function(childRecord, parentRecord, store, opti Ember.assert("You must pass either a parentType or belongsToName option to OneToManyChange.forChildAndParent", false); } - var change = DS.RelationshipChange._createChange({ + var change = RelationshipChange._createChange({ parentRecord: parentRecord, childRecord: childRecord, firstRecord: childRecord, @@ -215,11 +217,11 @@ DS.OneToOneChange.createChange = function(childRecord, parentRecord, store, opti return change; }; -DS.OneToOneChange.maintainInvariant = function(options, store, childRecord, key){ +OneToOneChange.maintainInvariant = function(options, store, childRecord, key){ if (options.changeType === "add" && store.recordIsMaterialized(childRecord)) { var oldParent = get(childRecord, key); if (oldParent){ - var correspondingChange = DS.OneToOneChange.createChange(childRecord, oldParent, store, { + var correspondingChange = OneToOneChange.createChange(childRecord, oldParent, store, { parentType: options.parentType, hasManyName: options.hasManyName, changeType: "remove", @@ -231,7 +233,7 @@ DS.OneToOneChange.maintainInvariant = function(options, store, childRecord, key) } }; -DS.OneToManyChange.createChange = function(childRecord, parentRecord, store, options) { +OneToManyChange.createChange = function(childRecord, parentRecord, store, options) { var key; // If the name of the belongsTo side of the relationship is specified, @@ -240,14 +242,14 @@ DS.OneToManyChange.createChange = function(childRecord, parentRecord, store, opt // definition. if (options.parentType) { key = options.parentType.inverseFor(options.key).name; - DS.OneToManyChange.maintainInvariant( options, store, childRecord, key ); + OneToManyChange.maintainInvariant( options, store, childRecord, key ); } else if (options.key) { key = options.key; } else { Ember.assert("You must pass either a parentType or belongsToName option to OneToManyChange.forChildAndParent", false); } - var change = DS.RelationshipChange._createChange({ + var change = RelationshipChange._createChange({ parentRecord: parentRecord, childRecord: childRecord, firstRecord: childRecord, @@ -266,11 +268,11 @@ DS.OneToManyChange.createChange = function(childRecord, parentRecord, store, opt }; -DS.OneToManyChange.maintainInvariant = function(options, store, childRecord, key){ +OneToManyChange.maintainInvariant = function(options, store, childRecord, key){ if (options.changeType === "add" && childRecord) { var oldParent = get(childRecord, key); if (oldParent){ - var correspondingChange = DS.OneToManyChange.createChange(childRecord, oldParent, store, { + var correspondingChange = OneToManyChange.createChange(childRecord, oldParent, store, { parentType: options.parentType, hasManyName: options.hasManyName, changeType: "remove", @@ -286,7 +288,7 @@ DS.OneToManyChange.maintainInvariant = function(options, store, childRecord, key @class RelationshipChange @namespace DS */ -DS.RelationshipChange.prototype = { +RelationshipChange.prototype = { getSecondRecordName: function() { var name = this.secondRecordName, parent; @@ -352,16 +354,16 @@ DS.RelationshipChange.prototype = { } }; -DS.RelationshipChangeAdd.prototype = Ember.create(DS.RelationshipChange.create({})); -DS.RelationshipChangeRemove.prototype = Ember.create(DS.RelationshipChange.create({})); +RelationshipChangeAdd.prototype = Ember.create(RelationshipChange.create({})); +RelationshipChangeRemove.prototype = Ember.create(RelationshipChange.create({})); // the object is a value, and not a promise function isValue(object) { return typeof object === 'object' && (!object.then || typeof object.then !== 'function'); } -DS.RelationshipChangeAdd.prototype.changeType = "add"; -DS.RelationshipChangeAdd.prototype.sync = function() { +RelationshipChangeAdd.prototype.changeType = "add"; +RelationshipChangeAdd.prototype.sync = function() { var secondRecordName = this.getSecondRecordName(), firstRecordName = this.getFirstRecordName(), firstRecord = this.getFirstRecord(), @@ -370,7 +372,7 @@ DS.RelationshipChangeAdd.prototype.sync = function() { //Ember.assert("You specified a hasMany (" + hasManyName + ") on " + (!belongsToName && (newParent || oldParent || this.lastParent).constructor) + " but did not specify an inverse belongsTo on " + child.constructor, belongsToName); //Ember.assert("You specified a belongsTo (" + belongsToName + ") on " + child.constructor + " but did not specify an inverse hasMany on " + (!hasManyName && (newParent || oldParent || this.lastParentRecord).constructor), hasManyName); - if (secondRecord instanceof DS.Model && firstRecord instanceof DS.Model) { + if (secondRecord instanceof Model && firstRecord instanceof Model) { if(this.secondRecordKind === "belongsTo"){ secondRecord.suspendRelationshipObservers(function(){ set(secondRecord, secondRecordName, firstRecord); @@ -385,7 +387,7 @@ DS.RelationshipChangeAdd.prototype.sync = function() { } } - if (firstRecord instanceof DS.Model && secondRecord instanceof DS.Model && get(firstRecord, firstRecordName) !== secondRecord) { + if (firstRecord instanceof Model && secondRecord instanceof Model && get(firstRecord, firstRecordName) !== secondRecord) { if(this.firstRecordKind === "belongsTo"){ firstRecord.suspendRelationshipObservers(function(){ set(firstRecord, firstRecordName, secondRecord); @@ -402,8 +404,8 @@ DS.RelationshipChangeAdd.prototype.sync = function() { this.coalesce(); }; -DS.RelationshipChangeRemove.prototype.changeType = "remove"; -DS.RelationshipChangeRemove.prototype.sync = function() { +RelationshipChangeRemove.prototype.changeType = "remove"; +RelationshipChangeRemove.prototype.sync = function() { var secondRecordName = this.getSecondRecordName(), firstRecordName = this.getFirstRecordName(), firstRecord = this.getFirstRecord(), @@ -412,7 +414,7 @@ DS.RelationshipChangeRemove.prototype.sync = function() { //Ember.assert("You specified a hasMany (" + hasManyName + ") on " + (!belongsToName && (newParent || oldParent || this.lastParent).constructor) + " but did not specify an inverse belongsTo on " + child.constructor, belongsToName); //Ember.assert("You specified a belongsTo (" + belongsToName + ") on " + child.constructor + " but did not specify an inverse hasMany on " + (!hasManyName && (newParent || oldParent || this.lastParentRecord).constructor), hasManyName); - if (secondRecord instanceof DS.Model && firstRecord instanceof DS.Model) { + if (secondRecord instanceof Model && firstRecord instanceof Model) { if(this.secondRecordKind === "belongsTo"){ secondRecord.suspendRelationshipObservers(function(){ set(secondRecord, secondRecordName, null); @@ -426,7 +428,7 @@ DS.RelationshipChangeRemove.prototype.sync = function() { } } - if (firstRecord instanceof DS.Model && get(firstRecord, firstRecordName)) { + if (firstRecord instanceof Model && get(firstRecord, firstRecordName)) { if(this.firstRecordKind === "belongsTo"){ firstRecord.suspendRelationshipObservers(function(){ set(firstRecord, firstRecordName, null); @@ -442,3 +444,5 @@ DS.RelationshipChangeRemove.prototype.sync = function() { this.coalesce(); }; + +export {RelationshipChange, RelationshipChangeAdd, RelationshipChangeRemove, OneToManyChange, ManyToNoneChange, OneToOneChange, ManyToManyChange}; diff --git a/packages/ember-data/lib/system/debug.js b/packages/ember-data/lib/system/debug.js index 6aa6a17b7e8..6858402e7b1 100644 --- a/packages/ember-data/lib/system/debug.js +++ b/packages/ember-data/lib/system/debug.js @@ -1,5 +1,8 @@ /** @module ember-data */ -require("ember-data/system/debug/debug_info"); -require("ember-data/system/debug/debug_adapter"); + +import "./debug/debug_info"; +import DebugAdapter from "./debug/debug_adapter"; + +export default DebugAdapter; diff --git a/packages/ember-data/lib/system/debug/debug_adapter.js b/packages/ember-data/lib/system/debug/debug_adapter.js index 251cca649e3..546cf62e853 100644 --- a/packages/ember-data/lib/system/debug/debug_adapter.js +++ b/packages/ember-data/lib/system/debug/debug_adapter.js @@ -1,7 +1,8 @@ /** @module ember-data */ -var get = Ember.get, capitalize = Ember.String.capitalize, underscore = Ember.String.underscore, DS = window.DS ; +import {Model} from "../model"; +var get = Ember.get, capitalize = Ember.String.capitalize, underscore = Ember.String.underscore; /** Extend `Ember.DataAdapter` with ED specific code. @@ -11,7 +12,7 @@ var get = Ember.get, capitalize = Ember.String.capitalize, underscore = Ember.St @extends Ember.DataAdapter @private */ -DS.DebugAdapter = Ember.DataAdapter.extend({ +var DebugAdapter = Ember.DataAdapter.extend({ getFilters: function() { return [ { name: 'isNew', desc: 'New' }, @@ -21,7 +22,7 @@ DS.DebugAdapter = Ember.DataAdapter.extend({ }, detect: function(klass) { - return klass !== DS.Model && DS.Model.detect(klass); + return klass !== Model && Model.detect(klass); }, columnsForType: function(type) { @@ -107,3 +108,5 @@ DS.DebugAdapter = Ember.DataAdapter.extend({ } }); + +export default DebugAdapter; diff --git a/packages/ember-data/lib/system/debug/debug_info.js b/packages/ember-data/lib/system/debug/debug_info.js index 315c61a873d..7a1c5b0cdfe 100644 --- a/packages/ember-data/lib/system/debug/debug_info.js +++ b/packages/ember-data/lib/system/debug/debug_info.js @@ -1,6 +1,6 @@ -require("ember-data/system/model/model"); +import {Model} from "../model"; -DS.Model.reopen({ +Model.reopen({ /** Provides info about the model for debugging purposes @@ -66,3 +66,5 @@ DS.Model.reopen({ } }); + +export default Model; diff --git a/packages/ember-data/lib/system/model.js b/packages/ember-data/lib/system/model.js index 6d8dc955887..df7e7972583 100644 --- a/packages/ember-data/lib/system/model.js +++ b/packages/ember-data/lib/system/model.js @@ -2,6 +2,8 @@ @module ember-data */ -require("ember-data/system/model/model"); -require("ember-data/system/model/states"); -require("ember-data/system/model/attributes"); +import Model from "./model/model"; +import attr from "./model/attributes"; +import RootState from "./model/states"; + +export {Model, RootState, attr}; diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 4a54b805637..25f1e25e76d 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -1,4 +1,4 @@ -require("ember-data/system/model/model"); +import Model from "./model"; /** @module ember-data @@ -10,7 +10,7 @@ var get = Ember.get; @class Model @namespace DS */ -DS.Model.reopenClass({ +Model.reopenClass({ /** A map whose keys are the attributes of the model (properties described by DS.attr) and whose values are the meta object for the @@ -198,7 +198,7 @@ DS.Model.reopenClass({ }); -DS.Model.reopen({ +Model.reopen({ eachAttribute: function(callback, binding) { this.constructor.eachAttribute(callback, binding); } @@ -262,7 +262,7 @@ function getValue(record, key) { @return {Attribute} */ -DS.attr = function(type, options) { +var attr = function(type, options) { options = options || {}; var meta = { @@ -297,3 +297,4 @@ DS.attr = function(type, options) { }).property('data').meta(meta); }; +export default attr; diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 9404368801b..d4f97cf73fc 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1,5 +1,4 @@ -require("ember-data/system/model/states"); - +import RootState from "./states"; /** @module ember-data */ @@ -20,7 +19,7 @@ var retrieveFromCurrentState = Ember.computed('currentState', function(key, valu @extends Ember.Object @uses Ember.Evented */ -DS.Model = Ember.Object.extend(Ember.Evented, { +var Model = Ember.Object.extend(Ember.Evented, { /** If this property is `true` the record is in the `empty` state. Empty is the first state all records enter after they have @@ -381,7 +380,7 @@ DS.Model = Ember.Object.extend(Ember.Evented, { _data: null, init: function() { - set(this, 'currentState', DS.RootState.empty); + set(this, 'currentState', RootState.empty); this._super(); this._setup(); }, @@ -977,7 +976,7 @@ DS.Model = Ember.Object.extend(Ember.Evented, { } }); -DS.Model.reopenClass({ +Model.reopenClass({ /** Alias DS.Model's `create` method to `_create`. This allows us to create DS.Model @@ -988,7 +987,7 @@ DS.Model.reopenClass({ @private @static */ - _create: DS.Model.create, + _create: Model.create, /** Override the class' `create()` method to raise an error. This @@ -1005,3 +1004,5 @@ DS.Model.reopenClass({ throw new Ember.Error("You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set."); } }); + +export default Model; diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index 760a493241c..a7d09797157 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -703,4 +703,4 @@ function wireState(object, parent, name) { RootState = wireState(RootState, null, "root"); -DS.RootState = RootState; +export default RootState; diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index 3a952220450..286773426ce 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -2,6 +2,7 @@ @module ember-data */ +import {ManyArray} from "./record_arrays"; var get = Ember.get, set = Ember.set; var once = Ember.run.once; var forEach = Ember.EnumerableUtils.forEach; @@ -12,7 +13,7 @@ var forEach = Ember.EnumerableUtils.forEach; @private @extends Ember.Object */ -DS.RecordArrayManager = Ember.Object.extend({ +var RecordArrayManager = Ember.Object.extend({ init: function() { this.filteredRecordArrays = Ember.MapWithDefault.create({ defaultValue: function() { return []; } @@ -153,7 +154,7 @@ DS.RecordArrayManager = Ember.Object.extend({ @return {DS.ManyArray} */ createManyArray: function(type, records) { - var manyArray = DS.ManyArray.create({ + var manyArray = ManyArray.create({ type: type, content: records, store: this.store @@ -196,3 +197,5 @@ DS.RecordArrayManager = Ember.Object.extend({ record._loadingRecordArrays = loadingRecordArrays; } }); + +export default RecordArrayManager; diff --git a/packages/ember-data/lib/system/record_arrays.js b/packages/ember-data/lib/system/record_arrays.js index 9e419d9c52b..625a8185291 100644 --- a/packages/ember-data/lib/system/record_arrays.js +++ b/packages/ember-data/lib/system/record_arrays.js @@ -2,7 +2,14 @@ @module ember-data */ -require('ember-data/system/record_arrays/record_array'); -require('ember-data/system/record_arrays/filtered_record_array'); -require('ember-data/system/record_arrays/adapter_populated_record_array'); -require('ember-data/system/record_arrays/many_array'); +import RecordArray from "./record_arrays/record_array"; +import FilteredRecordArray from "./record_arrays/filtered_record_array"; +import AdapterPopulatedRecordArray from "./record_arrays/adapter_populated_record_array"; +import ManyArray from "./record_arrays/many_array"; + +export { + RecordArray, + FilteredRecordArray, + AdapterPopulatedRecordArray, + ManyArray +}; diff --git a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js index fd41520f316..affd364d33a 100644 --- a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js @@ -1,5 +1,4 @@ -require("ember-data/system/record_arrays/record_array"); - +import RecordArray from "./record_array"; /** @module ember-data */ @@ -16,7 +15,7 @@ var get = Ember.get, set = Ember.set; @namespace DS @extends DS.RecordArray */ -DS.AdapterPopulatedRecordArray = DS.RecordArray.extend({ +var AdapterPopulatedRecordArray = RecordArray.extend({ query: null, replace: function() { @@ -45,3 +44,5 @@ DS.AdapterPopulatedRecordArray = DS.RecordArray.extend({ Ember.run.once(this, 'trigger', 'didLoad'); } }); + +export default AdapterPopulatedRecordArray; diff --git a/packages/ember-data/lib/system/record_arrays/filtered_record_array.js b/packages/ember-data/lib/system/record_arrays/filtered_record_array.js index 8cc43e71377..c953b63fd36 100644 --- a/packages/ember-data/lib/system/record_arrays/filtered_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/filtered_record_array.js @@ -1,4 +1,4 @@ -require("ember-data/system/record_arrays/record_array"); +import RecordArray from "./record_array"; /** @module ember-data @@ -16,7 +16,7 @@ var get = Ember.get; @namespace DS @extends DS.RecordArray */ -DS.FilteredRecordArray = DS.RecordArray.extend({ +var FilteredRecordArray = RecordArray.extend({ /** The filterFunction is a function used to test records from the store to determine if they should be part of the record array. @@ -60,3 +60,5 @@ DS.FilteredRecordArray = DS.RecordArray.extend({ manager.updateFilter(this, get(this, 'type'), get(this, 'filterFunction')); }, 'filterFunction') }); + +export default FilteredRecordArray; diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index ec5f0519bb8..6522a7c2b80 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -1,4 +1,5 @@ -require("ember-data/system/record_arrays/record_array"); +import RecordArray from "./record_array"; +import {RelationshipChange} from "../changes"; /** @module ember-data @@ -43,7 +44,7 @@ var map = Ember.EnumerableUtils.map; @namespace DS @extends DS.RecordArray */ -DS.ManyArray = DS.RecordArray.extend({ +var ManyArray = RecordArray.extend({ init: function() { this._super.apply(this, arguments); this._changesToSync = Ember.OrderedSet.create(); @@ -153,7 +154,7 @@ DS.ManyArray = DS.RecordArray.extend({ for (var i=index; i to the window', function() { + this.files.forEach(function(f) { + var output = ['(function(global) {']; + + output.push.apply(output, f.src.map(grunt.file.read)); + + output.push("global.<%= pkg.namespace %> = requireModule('<%= pkg.name %>/lib/main')['default'];"); + output.push('}(window));'); + + grunt.file.write(f.dest, grunt.template.process(output.join('\n'))); + }); + }); +}; diff --git a/tests/ember-data-setup.js b/tests/ember-data-setup.js new file mode 100644 index 00000000000..35f2b9bfef5 --- /dev/null +++ b/tests/ember-data-setup.js @@ -0,0 +1,60 @@ +;(function(){ + + Ember.RSVP.configure('onerror', function(reason) { + // only print error messages if they're exceptions; + // otherwise, let a future turn of the event loop + // handle the error. + if (reason && reason instanceof Error) { + Ember.Logger.log(reason, reason.stack) + throw reason; + } + }); + + Ember.RSVP.resolve = syncForTest(Ember.RSVP.resolve); + + Ember.View.reopen({ + _insertElementLater: syncForTest() + }); + + DS.Store.reopen({ + save: syncForTest(), + createRecord: syncForTest(), + deleteRecord: syncForTest(), + push: syncForTest(), + pushMany: syncForTest(), + filter: syncForTest(), + find: syncForTest(), + findMany: syncForTest(), + findByIds: syncForTest(), + didSaveRecord: syncForTest(), + didSaveRecords: syncForTest(), + didUpdateAttribute: syncForTest(), + didUpdateAttributes: syncForTest(), + didUpdateRelationship: syncForTest(), + didUpdateRelationships: syncForTest() + }); + + DS.Model.reopen({ + save: syncForTest(), + reload: syncForTest(), + deleteRecord: syncForTest(), + dataDidChange: Ember.observer(syncForTest(), 'data'), + updateRecordArraysLater: syncForTest() + }); + + var transforms = { + 'boolean': DS.BooleanTransform.create(), + 'date': DS.DateTransform.create(), + 'number': DS.NumberTransform.create(), + 'string': DS.StringTransform.create() + }; + + // Prevent all tests involving serialization to require a container + DS.JSONSerializer.reopen({ + transformFor: function(attributeType) { + return this._super(attributeType, true) || transforms[attributeType]; + } + }); + + Ember.RSVP.Promise.prototype.then = syncForTest(Ember.RSVP.Promise.prototype.then); +})(); diff --git a/tests/ember_configuration.js b/tests/ember_configuration.js index bd258bc8c2d..53c0ca301e5 100644 --- a/tests/ember_configuration.js +++ b/tests/ember_configuration.js @@ -1,6 +1,7 @@ /*globals EmberDev ENV QUnit */ -(function() { +(function RESET() { + console.log('RESETTING'); window.Ember = window.Ember || {}; Ember.config = {}; @@ -11,7 +12,7 @@ var extendPrototypes = QUnit.urlParams.extendprototypes; ENV['EXTEND_PROTOTYPES'] = !!extendPrototypes; - if (EmberDev.jsHint) { + if (typeof EmberDev !== 'undefined' && EmberDev.jsHint) { // jsHint makes its own Object.create stub, we don't want to use this ENV['STUB_OBJECT_CREATE'] = !Object.create; } @@ -84,7 +85,7 @@ return setupStore(options).store; }; - var syncForTest = function(fn) { + var syncForTest = window.syncForTest = function(fn) { var callSuper; if (typeof fn !== "function") { callSuper = true; } @@ -130,70 +131,13 @@ }); }; - minispade.register('ember-data/~test-setup', function() { - Ember.RSVP.configure('onerror', function(reason) { - // only print error messages if they're exceptions; - // otherwise, let a future turn of the event loop - // handle the error. - if (reason && reason instanceof Error) { - Ember.Logger.log(reason, reason.stack) - throw reason; - } - }); - - Ember.RSVP.resolve = syncForTest(Ember.RSVP.resolve); - - Ember.View.reopen({ - _insertElementLater: syncForTest() - }); - - DS.Store.reopen({ - save: syncForTest(), - createRecord: syncForTest(), - deleteRecord: syncForTest(), - push: syncForTest(), - pushMany: syncForTest(), - filter: syncForTest(), - find: syncForTest(), - findMany: syncForTest(), - findByIds: syncForTest(), - didSaveRecord: syncForTest(), - didSaveRecords: syncForTest(), - didUpdateAttribute: syncForTest(), - didUpdateAttributes: syncForTest(), - didUpdateRelationship: syncForTest(), - didUpdateRelationships: syncForTest() - }); - - DS.Model.reopen({ - save: syncForTest(), - reload: syncForTest(), - deleteRecord: syncForTest(), - dataDidChange: Ember.observer(syncForTest(), 'data'), - updateRecordArraysLater: syncForTest() - }); - var transforms = { - 'boolean': DS.BooleanTransform.create(), - 'date': DS.DateTransform.create(), - 'number': DS.NumberTransform.create(), - 'string': DS.StringTransform.create() + if (typeof EmberDev !== 'undefined') { + EmberDev.distros = { + spade: 'ember-data-spade.js', + build: 'ember-data.js' }; - - // Prevent all tests involving serialization to require a container - DS.JSONSerializer.reopen({ - transformFor: function(attributeType) { - return this._super(attributeType, true) || transforms[attributeType]; - } - }); - - Ember.RSVP.Promise.prototype.then = syncForTest(Ember.RSVP.Promise.prototype.then); - }); - - EmberDev.distros = { - spade: 'ember-data-spade.js', - build: 'ember-data.js' - }; + } // Generate the jQuery expando on window ahead of time // to make the QUnit global check run clean diff --git a/tests/index.html b/tests/index.html new file mode 100644 index 00000000000..387da462db4 --- /dev/null +++ b/tests/index.html @@ -0,0 +1,21 @@ + + + + + QUnit Example + + + +
+
+ + + + + + + + + + + diff --git a/tests/qunit_configuration.js b/tests/qunit_configuration.js new file mode 100644 index 00000000000..b8dac772545 --- /dev/null +++ b/tests/qunit_configuration.js @@ -0,0 +1,217 @@ +(function() { + window.EmberDev = window.EmberDev || {}; + + EmberDev.afterEach = function() { + if (Ember && Ember.View) { + var viewIds = [], id; + for (id in Ember.View.views) { + if (Ember.View.views[id] != null) { + viewIds.push(id); + } + } + + if (viewIds.length > 0) { + deepEqual(viewIds, [], "Ember.View.views should be empty"); + Ember.View.views = []; + } + } + + if (Ember && Ember.TEMPLATES) { + var templateNames = [], name; + for (name in Ember.TEMPLATES) { + if (Ember.TEMPLATES[name] != null) { + templateNames.push(name); + } + } + + if (templateNames.length > 0) { + deepEqual(templateNames, [], "Ember.TEMPLATES should be empty"); + Ember.TEMPLATES = {}; + } + } + }; + + window.globalFailedTests = []; + window.globalTestResults = null; + window.lastAssertionTime = new Date().getTime(); + + var currentTest, assertCount; + + QUnit.testStart(function(data) { + // Reset the assertion count + assertCount = 0; + + currentTest = { + name: data.name, + failedAssertions: [], + total: 0, + passed: 0, + failed: 0, + start: new Date(), + time: 0 + }; + + }) + + QUnit.log(function(data) { + assertCount++; + lastAssertionTime = new Date().getTime(); + + // Ignore passing assertions + if (!data.result) { + currentTest.failedAssertions.push(data); + } + }); + + QUnit.testDone(function(data) { + currentTest.time = (new Date()).getTime() - currentTest.start.getTime(); // ms + currentTest.total = data.total; + currentTest.passed = data.passed; + currentTest.failed = data.failed; + + if (currentTest.failed > 0) + window.globalFailedTests.push(currentTest) + + currentTest = null; + }); + + QUnit.done(function( details ) { + details.failedTests = globalFailedTests; + + window.globalTestResults = details; + }); + + // hack qunit to not suck for Ember objects + var originalTypeof = QUnit.jsDump.typeOf; + + QUnit.jsDump.typeOf = function(obj) { + if (Ember && Ember.Object && Ember.Object.detectInstance(obj)) { + return "emberObject"; + } + + return originalTypeof.call(this, obj); + }; + + QUnit.jsDump.parsers.emberObject = function(obj) { + return obj.toString(); + }; + + var originalModule = module; + module = function(name, origOpts) { + var opts = {}; + if (origOpts && origOpts.setup) { opts.setup = origOpts.setup; } + opts.teardown = function() { + if (origOpts && origOpts.teardown) { origOpts.teardown(); } + + if (Ember && Ember.run) { + if (Ember.run.currentRunLoop) { + ok(false, "Should not be in a run loop at end of test"); + while (Ember.run.currentRunLoop) { + Ember.run.end(); + } + } + if (Ember.run.hasScheduledTimers()) { + // Use `ok` so we get full description. + // Gate inside of `if` so that we don't mess up `expects` counts + ok(false, "Ember run should not have scheduled timers at end of test"); + Ember.run.cancelTimers(); + } + } + + if (EmberDev.afterEach) { + EmberDev.afterEach(); + } + }; + return originalModule(name, opts); + }; + + // Tests should time out after 5 seconds + QUnit.config.testTimeout = 5000; + + // Handle JSHint + QUnit.config.urlConfig.push('nojshint'); + + EmberDev.jsHint = !QUnit.urlParams.nojshint; + + EmberDev.jsHintReporter = function (file, errors) { + if (!errors) { return ''; } + + var len = errors.length, + str = '', + error, idx; + + if (len === 0) { return ''; } + + for (idx=0; idx li:last-child { + border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + -webkit-border-bottom-right-radius: 5px; + -webkit-border-bottom-left-radius: 5px; +} + +#qunit-tests .fail { color: #000000; background-color: #EE5757; } +#qunit-tests .fail .test-name, +#qunit-tests .fail .module-name { color: #000000; } + +#qunit-tests .fail .test-actual { color: #EE5757; } +#qunit-tests .fail .test-expected { color: green; } + +#qunit-banner.qunit-fail { background-color: #EE5757; } + + +/** Result */ + +#qunit-testresult { + padding: 0.5em 0.5em 0.5em 2.5em; + + color: #2b81af; + background-color: #D2E0E6; + + border-bottom: 1px solid white; +} +#qunit-testresult .module-name { + font-weight: bold; +} + +/** Fixture */ + +#qunit-fixture { + position: absolute; + top: -10000px; + left: -10000px; + width: 1000px; + height: 1000px; +} diff --git a/tests/vendor/qunit.js b/tests/vendor/qunit.js new file mode 100644 index 00000000000..84c73907de4 --- /dev/null +++ b/tests/vendor/qunit.js @@ -0,0 +1,2212 @@ +/** + * QUnit v1.12.0 - A JavaScript Unit Testing Framework + * + * http://qunitjs.com + * + * Copyright 2013 jQuery Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license/ + */ + +(function( window ) { + +var QUnit, + assert, + config, + onErrorFnPrev, + testId = 0, + fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + // Keep a local reference to Date (GH-283) + Date = window.Date, + setTimeout = window.setTimeout, + defined = { + setTimeout: typeof window.setTimeout !== "undefined", + sessionStorage: (function() { + var x = "qunit-test-string"; + try { + sessionStorage.setItem( x, x ); + sessionStorage.removeItem( x ); + return true; + } catch( e ) { + return false; + } + }()) + }, + /** + * Provides a normalized error string, correcting an issue + * with IE 7 (and prior) where Error.prototype.toString is + * not properly implemented + * + * Based on http://es5.github.com/#x15.11.4.4 + * + * @param {String|Error} error + * @return {String} error message + */ + errorString = function( error ) { + var name, message, + errorString = error.toString(); + if ( errorString.substring( 0, 7 ) === "[object" ) { + name = error.name ? error.name.toString() : "Error"; + message = error.message ? error.message.toString() : ""; + if ( name && message ) { + return name + ": " + message; + } else if ( name ) { + return name; + } else if ( message ) { + return message; + } else { + return "Error"; + } + } else { + return errorString; + } + }, + /** + * Makes a clone of an object using only Array or Object as base, + * and copies over the own enumerable properties. + * + * @param {Object} obj + * @return {Object} New object with only the own properties (recursively). + */ + objectValues = function( obj ) { + // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392. + /*jshint newcap: false */ + var key, val, + vals = QUnit.is( "array", obj ) ? [] : {}; + for ( key in obj ) { + if ( hasOwn.call( obj, key ) ) { + val = obj[key]; + vals[key] = val === Object(val) ? objectValues(val) : val; + } + } + return vals; + }; + +function Test( settings ) { + extend( this, settings ); + this.assertions = []; + this.testNumber = ++Test.count; +} + +Test.count = 0; + +Test.prototype = { + init: function() { + var a, b, li, + tests = id( "qunit-tests" ); + + if ( tests ) { + b = document.createElement( "strong" ); + b.innerHTML = this.nameHtml; + + // `a` initialized at top of scope + a = document.createElement( "a" ); + a.innerHTML = "Rerun"; + a.href = QUnit.url({ testNumber: this.testNumber }); + + li = document.createElement( "li" ); + li.appendChild( b ); + li.appendChild( a ); + li.className = "running"; + li.id = this.id = "qunit-test-output" + testId++; + + tests.appendChild( li ); + } + }, + setup: function() { + if ( + // Emit moduleStart when we're switching from one module to another + this.module !== config.previousModule || + // They could be equal (both undefined) but if the previousModule property doesn't + // yet exist it means this is the first test in a suite that isn't wrapped in a + // module, in which case we'll just emit a moduleStart event for 'undefined'. + // Without this, reporters can get testStart before moduleStart which is a problem. + !hasOwn.call( config, "previousModule" ) + ) { + if ( hasOwn.call( config, "previousModule" ) ) { + runLoggingCallbacks( "moduleDone", QUnit, { + name: config.previousModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + }); + } + config.previousModule = this.module; + config.moduleStats = { all: 0, bad: 0 }; + runLoggingCallbacks( "moduleStart", QUnit, { + name: this.module + }); + } + + config.current = this; + + this.testEnvironment = extend({ + setup: function() {}, + teardown: function() {} + }, this.moduleTestEnvironment ); + + this.started = +new Date(); + runLoggingCallbacks( "testStart", QUnit, { + name: this.testName, + module: this.module + }); + + /*jshint camelcase:false */ + + + /** + * Expose the current test environment. + * + * @deprecated since 1.12.0: Use QUnit.config.current.testEnvironment instead. + */ + QUnit.current_testEnvironment = this.testEnvironment; + + /*jshint camelcase:true */ + + if ( !config.pollution ) { + saveGlobal(); + } + if ( config.notrycatch ) { + this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert ); + return; + } + try { + this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert ); + } catch( e ) { + QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); + } + }, + run: function() { + config.current = this; + + var running = id( "qunit-testresult" ); + + if ( running ) { + running.innerHTML = "Running:
" + this.nameHtml; + } + + if ( this.async ) { + QUnit.stop(); + } + + this.callbackStarted = +new Date(); + + if ( config.notrycatch ) { + this.callback.call( this.testEnvironment, QUnit.assert ); + this.callbackRuntime = +new Date() - this.callbackStarted; + return; + } + + try { + this.callback.call( this.testEnvironment, QUnit.assert ); + this.callbackRuntime = +new Date() - this.callbackStarted; + } catch( e ) { + this.callbackRuntime = +new Date() - this.callbackStarted; + + QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); + // else next test will carry the responsibility + saveGlobal(); + + // Restart the tests if they're blocking + if ( config.blocking ) { + QUnit.start(); + } + } + }, + teardown: function() { + config.current = this; + if ( config.notrycatch ) { + if ( typeof this.callbackRuntime === "undefined" ) { + this.callbackRuntime = +new Date() - this.callbackStarted; + } + this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert ); + return; + } else { + try { + this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert ); + } catch( e ) { + QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); + } + } + checkPollution(); + }, + finish: function() { + config.current = this; + if ( config.requireExpects && this.expected === null ) { + QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack ); + } else if ( this.expected !== null && this.expected !== this.assertions.length ) { + QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); + } else if ( this.expected === null && !this.assertions.length ) { + QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); + } + + var i, assertion, a, b, time, li, ol, + test = this, + good = 0, + bad = 0, + tests = id( "qunit-tests" ); + + this.runtime = +new Date() - this.started; + config.stats.all += this.assertions.length; + config.moduleStats.all += this.assertions.length; + + if ( tests ) { + ol = document.createElement( "ol" ); + ol.className = "qunit-assert-list"; + + for ( i = 0; i < this.assertions.length; i++ ) { + assertion = this.assertions[i]; + + li = document.createElement( "li" ); + li.className = assertion.result ? "pass" : "fail"; + li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" ); + ol.appendChild( li ); + + if ( assertion.result ) { + good++; + } else { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + + // store result when possible + if ( QUnit.config.reorder && defined.sessionStorage ) { + if ( bad ) { + sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad ); + } else { + sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName ); + } + } + + if ( bad === 0 ) { + addClass( ol, "qunit-collapsed" ); + } + + // `b` initialized at top of scope + b = document.createElement( "strong" ); + b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; + + addEvent(b, "click", function() { + var next = b.parentNode.lastChild, + collapsed = hasClass( next, "qunit-collapsed" ); + ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" ); + }); + + addEvent(b, "dblclick", function( e ) { + var target = e && e.target ? e.target : window.event.srcElement; + if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) { + target = target.parentNode; + } + if ( window.location && target.nodeName.toLowerCase() === "strong" ) { + window.location = QUnit.url({ testNumber: test.testNumber }); + } + }); + + // `time` initialized at top of scope + time = document.createElement( "span" ); + time.className = "runtime"; + time.innerHTML = this.runtime + " ms"; + + // `li` initialized at top of scope + li = id( this.id ); + li.className = bad ? "fail" : "pass"; + li.removeChild( li.firstChild ); + a = li.firstChild; + li.appendChild( b ); + li.appendChild( a ); + li.appendChild( time ); + li.appendChild( ol ); + + } else { + for ( i = 0; i < this.assertions.length; i++ ) { + if ( !this.assertions[i].result ) { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + } + + runLoggingCallbacks( "testDone", QUnit, { + name: this.testName, + module: this.module, + failed: bad, + passed: this.assertions.length - bad, + total: this.assertions.length, + duration: this.runtime + }); + + QUnit.reset(); + + config.current = undefined; + }, + + queue: function() { + var bad, + test = this; + + synchronize(function() { + test.init(); + }); + function run() { + // each of these can by async + synchronize(function() { + test.setup(); + }); + synchronize(function() { + test.run(); + }); + synchronize(function() { + test.teardown(); + }); + synchronize(function() { + test.finish(); + }); + } + + // `bad` initialized at top of scope + // defer when previous test run passed, if storage is available + bad = QUnit.config.reorder && defined.sessionStorage && + +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); + + if ( bad ) { + run(); + } else { + synchronize( run, true ); + } + } +}; + +// Root QUnit object. +// `QUnit` initialized at top of scope +QUnit = { + + // call on start of module test to prepend name to all tests + module: function( name, testEnvironment ) { + config.currentModule = name; + config.currentModuleTestEnvironment = testEnvironment; + config.modules[name] = true; + }, + + asyncTest: function( testName, expected, callback ) { + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + QUnit.test( testName, expected, callback, true ); + }, + + test: function( testName, expected, callback, async ) { + var test, + nameHtml = "" + escapeText( testName ) + ""; + + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + if ( config.currentModule ) { + nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml; + } + + test = new Test({ + nameHtml: nameHtml, + testName: testName, + expected: expected, + async: async, + callback: callback, + module: config.currentModule, + moduleTestEnvironment: config.currentModuleTestEnvironment, + stack: sourceFromStacktrace( 2 ) + }); + + if ( !validTest( test ) ) { + return; + } + + test.queue(); + }, + + // Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through. + expect: function( asserts ) { + if (arguments.length === 1) { + config.current.expected = asserts; + } else { + return config.current.expected; + } + }, + + start: function( count ) { + // QUnit hasn't been initialized yet. + // Note: RequireJS (et al) may delay onLoad + if ( config.semaphore === undefined ) { + QUnit.begin(function() { + // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first + setTimeout(function() { + QUnit.start( count ); + }); + }); + return; + } + + config.semaphore -= count || 1; + // don't start until equal number of stop-calls + if ( config.semaphore > 0 ) { + return; + } + // ignore if start is called more often then stop + if ( config.semaphore < 0 ) { + config.semaphore = 0; + QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) ); + return; + } + // A slight delay, to avoid any current callbacks + if ( defined.setTimeout ) { + setTimeout(function() { + if ( config.semaphore > 0 ) { + return; + } + if ( config.timeout ) { + clearTimeout( config.timeout ); + } + + config.blocking = false; + process( true ); + }, 13); + } else { + config.blocking = false; + process( true ); + } + }, + + stop: function( count ) { + config.semaphore += count || 1; + config.blocking = true; + + if ( config.testTimeout && defined.setTimeout ) { + clearTimeout( config.timeout ); + config.timeout = setTimeout(function() { + QUnit.ok( false, "Test timed out" ); + config.semaphore = 1; + QUnit.start(); + }, config.testTimeout ); + } + } +}; + +// `assert` initialized at top of scope +// Assert helpers +// All of these must either call QUnit.push() or manually do: +// - runLoggingCallbacks( "log", .. ); +// - config.current.assertions.push({ .. }); +// We attach it to the QUnit object *after* we expose the public API, +// otherwise `assert` will become a global variable in browsers (#341). +assert = { + /** + * Asserts rough true-ish result. + * @name ok + * @function + * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); + */ + ok: function( result, msg ) { + if ( !config.current ) { + throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + result = !!result; + msg = msg || (result ? "okay" : "failed" ); + + var source, + details = { + module: config.current.module, + name: config.current.testName, + result: result, + message: msg + }; + + msg = "" + escapeText( msg ) + ""; + + if ( !result ) { + source = sourceFromStacktrace( 2 ); + if ( source ) { + details.source = source; + msg += "
Source:
" + escapeText( source ) + "
"; + } + } + runLoggingCallbacks( "log", QUnit, details ); + config.current.assertions.push({ + result: result, + message: msg + }); + }, + + /** + * Assert that the first two arguments are equal, with an optional message. + * Prints out both actual and expected values. + * @name equal + * @function + * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); + */ + equal: function( actual, expected, message ) { + /*jshint eqeqeq:false */ + QUnit.push( expected == actual, actual, expected, message ); + }, + + /** + * @name notEqual + * @function + */ + notEqual: function( actual, expected, message ) { + /*jshint eqeqeq:false */ + QUnit.push( expected != actual, actual, expected, message ); + }, + + /** + * @name propEqual + * @function + */ + propEqual: function( actual, expected, message ) { + actual = objectValues(actual); + expected = objectValues(expected); + QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name notPropEqual + * @function + */ + notPropEqual: function( actual, expected, message ) { + actual = objectValues(actual); + expected = objectValues(expected); + QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name deepEqual + * @function + */ + deepEqual: function( actual, expected, message ) { + QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name notDeepEqual + * @function + */ + notDeepEqual: function( actual, expected, message ) { + QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name strictEqual + * @function + */ + strictEqual: function( actual, expected, message ) { + QUnit.push( expected === actual, actual, expected, message ); + }, + + /** + * @name notStrictEqual + * @function + */ + notStrictEqual: function( actual, expected, message ) { + QUnit.push( expected !== actual, actual, expected, message ); + }, + + "throws": function( block, expected, message ) { + var actual, + expectedOutput = expected, + ok = false; + + // 'expected' is optional + if ( typeof expected === "string" ) { + message = expected; + expected = null; + } + + config.current.ignoreGlobalErrors = true; + try { + block.call( config.current.testEnvironment ); + } catch (e) { + actual = e; + } + config.current.ignoreGlobalErrors = false; + + if ( actual ) { + // we don't want to validate thrown error + if ( !expected ) { + ok = true; + expectedOutput = null; + // expected is a regexp + } else if ( QUnit.objectType( expected ) === "regexp" ) { + ok = expected.test( errorString( actual ) ); + // expected is a constructor + } else if ( actual instanceof expected ) { + ok = true; + // expected is a validation function which returns true is validation passed + } else if ( expected.call( {}, actual ) === true ) { + expectedOutput = null; + ok = true; + } + + QUnit.push( ok, actual, expectedOutput, message ); + } else { + QUnit.pushFailure( message, null, "No exception was thrown." ); + } + } +}; + +/** + * @deprecated since 1.8.0 + * Kept assertion helpers in root for backwards compatibility. + */ +extend( QUnit, assert ); + +/** + * @deprecated since 1.9.0 + * Kept root "raises()" for backwards compatibility. + * (Note that we don't introduce assert.raises). + */ +QUnit.raises = assert[ "throws" ]; + +/** + * @deprecated since 1.0.0, replaced with error pushes since 1.3.0 + * Kept to avoid TypeErrors for undefined methods. + */ +QUnit.equals = function() { + QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); +}; +QUnit.same = function() { + QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); +}; + +// We want access to the constructor's prototype +(function() { + function F() {} + F.prototype = QUnit; + QUnit = new F(); + // Make F QUnit's constructor so that we can add to the prototype later + QUnit.constructor = F; +}()); + +/** + * Config object: Maintain internal state + * Later exposed as QUnit.config + * `config` initialized at top of scope + */ +config = { + // The queue of tests to run + queue: [], + + // block until document ready + blocking: true, + + // when enabled, show only failing tests + // gets persisted through sessionStorage and can be changed in UI via checkbox + hidepassed: false, + + // by default, run previously failed tests first + // very useful in combination with "Hide passed tests" checked + reorder: true, + + // by default, modify document.title when suite is done + altertitle: true, + + // when enabled, all tests must call expect() + requireExpects: false, + + // add checkboxes that are persisted in the query-string + // when enabled, the id is set to `true` as a `QUnit.config` property + urlConfig: [ + { + id: "noglobals", + label: "Check for Globals", + tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." + }, + { + id: "notrycatch", + label: "No try-catch", + tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." + } + ], + + // Set of all modules. + modules: {}, + + // logging callback queues + begin: [], + done: [], + log: [], + testStart: [], + testDone: [], + moduleStart: [], + moduleDone: [] +}; + +// Export global variables, unless an 'exports' object exists, +// in that case we assume we're in CommonJS (dealt with on the bottom of the script) +if ( typeof exports === "undefined" ) { + extend( window, QUnit.constructor.prototype ); + + // Expose QUnit object + window.QUnit = QUnit; +} + +// Initialize more QUnit.config and QUnit.urlParams +(function() { + var i, + location = window.location || { search: "", protocol: "file:" }, + params = location.search.slice( 1 ).split( "&" ), + length = params.length, + urlParams = {}, + current; + + if ( params[ 0 ] ) { + for ( i = 0; i < length; i++ ) { + current = params[ i ].split( "=" ); + current[ 0 ] = decodeURIComponent( current[ 0 ] ); + // allow just a key to turn on a flag, e.g., test.html?noglobals + current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; + urlParams[ current[ 0 ] ] = current[ 1 ]; + } + } + + QUnit.urlParams = urlParams; + + // String search anywhere in moduleName+testName + config.filter = urlParams.filter; + + // Exact match of the module name + config.module = urlParams.module; + + config.testNumber = parseInt( urlParams.testNumber, 10 ) || null; + + // Figure out if we're running the tests from a server or not + QUnit.isLocal = location.protocol === "file:"; +}()); + +// Extend QUnit object, +// these after set here because they should not be exposed as global functions +extend( QUnit, { + assert: assert, + + config: config, + + // Initialize the configuration options + init: function() { + extend( config, { + stats: { all: 0, bad: 0 }, + moduleStats: { all: 0, bad: 0 }, + started: +new Date(), + updateRate: 1000, + blocking: false, + autostart: true, + autorun: false, + filter: "", + queue: [], + semaphore: 1 + }); + + var tests, banner, result, + qunit = id( "qunit" ); + + if ( qunit ) { + qunit.innerHTML = + "

" + escapeText( document.title ) + "

" + + "

" + + "
" + + "

" + + "
    "; + } + + tests = id( "qunit-tests" ); + banner = id( "qunit-banner" ); + result = id( "qunit-testresult" ); + + if ( tests ) { + tests.innerHTML = ""; + } + + if ( banner ) { + banner.className = ""; + } + + if ( result ) { + result.parentNode.removeChild( result ); + } + + if ( tests ) { + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = "Running...
     "; + } + }, + + // Resets the test setup. Useful for tests that modify the DOM. + /* + DEPRECATED: Use multiple tests instead of resetting inside a test. + Use testStart or testDone for custom cleanup. + This method will throw an error in 2.0, and will be removed in 2.1 + */ + reset: function() { + var fixture = id( "qunit-fixture" ); + if ( fixture ) { + fixture.innerHTML = config.fixture; + } + }, + + // Trigger an event on an element. + // @example triggerEvent( document.body, "click" ); + triggerEvent: function( elem, type, event ) { + if ( document.createEvent ) { + event = document.createEvent( "MouseEvents" ); + event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, + 0, 0, 0, 0, 0, false, false, false, false, 0, null); + + elem.dispatchEvent( event ); + } else if ( elem.fireEvent ) { + elem.fireEvent( "on" + type ); + } + }, + + // Safe object type checking + is: function( type, obj ) { + return QUnit.objectType( obj ) === type; + }, + + objectType: function( obj ) { + if ( typeof obj === "undefined" ) { + return "undefined"; + // consider: typeof null === object + } + if ( obj === null ) { + return "null"; + } + + var match = toString.call( obj ).match(/^\[object\s(.*)\]$/), + type = match && match[1] || ""; + + switch ( type ) { + case "Number": + if ( isNaN(obj) ) { + return "nan"; + } + return "number"; + case "String": + case "Boolean": + case "Array": + case "Date": + case "RegExp": + case "Function": + return type.toLowerCase(); + } + if ( typeof obj === "object" ) { + return "object"; + } + return undefined; + }, + + push: function( result, actual, expected, message ) { + if ( !config.current ) { + throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); + } + + var output, source, + details = { + module: config.current.module, + name: config.current.testName, + result: result, + message: message, + actual: actual, + expected: expected + }; + + message = escapeText( message ) || ( result ? "okay" : "failed" ); + message = "" + message + ""; + output = message; + + if ( !result ) { + expected = escapeText( QUnit.jsDump.parse(expected) ); + actual = escapeText( QUnit.jsDump.parse(actual) ); + output += ""; + + if ( actual !== expected ) { + output += ""; + output += ""; + } + + source = sourceFromStacktrace(); + + if ( source ) { + details.source = source; + output += ""; + } + + output += "
    Expected:
    " + expected + "
    Result:
    " + actual + "
    Diff:
    " + QUnit.diff( expected, actual ) + "
    Source:
    " + escapeText( source ) + "
    "; + } + + runLoggingCallbacks( "log", QUnit, details ); + + config.current.assertions.push({ + result: !!result, + message: output + }); + }, + + pushFailure: function( message, source, actual ) { + if ( !config.current ) { + throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + + var output, + details = { + module: config.current.module, + name: config.current.testName, + result: false, + message: message + }; + + message = escapeText( message ) || "error"; + message = "" + message + ""; + output = message; + + output += ""; + + if ( actual ) { + output += ""; + } + + if ( source ) { + details.source = source; + output += ""; + } + + output += "
    Result:
    " + escapeText( actual ) + "
    Source:
    " + escapeText( source ) + "
    "; + + runLoggingCallbacks( "log", QUnit, details ); + + config.current.assertions.push({ + result: false, + message: output + }); + }, + + url: function( params ) { + params = extend( extend( {}, QUnit.urlParams ), params ); + var key, + querystring = "?"; + + for ( key in params ) { + if ( hasOwn.call( params, key ) ) { + querystring += encodeURIComponent( key ) + "=" + + encodeURIComponent( params[ key ] ) + "&"; + } + } + return window.location.protocol + "//" + window.location.host + + window.location.pathname + querystring.slice( 0, -1 ); + }, + + extend: extend, + id: id, + addEvent: addEvent, + addClass: addClass, + hasClass: hasClass, + removeClass: removeClass + // load, equiv, jsDump, diff: Attached later +}); + +/** + * @deprecated: Created for backwards compatibility with test runner that set the hook function + * into QUnit.{hook}, instead of invoking it and passing the hook function. + * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. + * Doing this allows us to tell if the following methods have been overwritten on the actual + * QUnit object. + */ +extend( QUnit.constructor.prototype, { + + // Logging callbacks; all receive a single argument with the listed properties + // run test/logs.html for any related changes + begin: registerLoggingCallback( "begin" ), + + // done: { failed, passed, total, runtime } + done: registerLoggingCallback( "done" ), + + // log: { result, actual, expected, message } + log: registerLoggingCallback( "log" ), + + // testStart: { name } + testStart: registerLoggingCallback( "testStart" ), + + // testDone: { name, failed, passed, total, duration } + testDone: registerLoggingCallback( "testDone" ), + + // moduleStart: { name } + moduleStart: registerLoggingCallback( "moduleStart" ), + + // moduleDone: { name, failed, passed, total } + moduleDone: registerLoggingCallback( "moduleDone" ) +}); + +if ( typeof document === "undefined" || document.readyState === "complete" ) { + config.autorun = true; +} + +QUnit.load = function() { + runLoggingCallbacks( "begin", QUnit, {} ); + + // Initialize the config, saving the execution queue + var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, + urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter, + numModules = 0, + moduleNames = [], + moduleFilterHtml = "", + urlConfigHtml = "", + oldconfig = extend( {}, config ); + + QUnit.init(); + extend(config, oldconfig); + + config.blocking = false; + + len = config.urlConfig.length; + + for ( i = 0; i < len; i++ ) { + val = config.urlConfig[i]; + if ( typeof val === "string" ) { + val = { + id: val, + label: val, + tooltip: "[no tooltip available]" + }; + } + config[ val.id ] = QUnit.urlParams[ val.id ]; + urlConfigHtml += ""; + } + for ( i in config.modules ) { + if ( config.modules.hasOwnProperty( i ) ) { + moduleNames.push(i); + } + } + numModules = moduleNames.length; + moduleNames.sort( function( a, b ) { + return a.localeCompare( b ); + }); + moduleFilterHtml += ""; + + // `userAgent` initialized at top of scope + userAgent = id( "qunit-userAgent" ); + if ( userAgent ) { + userAgent.innerHTML = navigator.userAgent; + } + + // `banner` initialized at top of scope + banner = id( "qunit-header" ); + if ( banner ) { + banner.innerHTML = "" + banner.innerHTML + " "; + } + + // `toolbar` initialized at top of scope + toolbar = id( "qunit-testrunner-toolbar" ); + if ( toolbar ) { + // `filter` initialized at top of scope + filter = document.createElement( "input" ); + filter.type = "checkbox"; + filter.id = "qunit-filter-pass"; + + addEvent( filter, "click", function() { + var tmp, + ol = document.getElementById( "qunit-tests" ); + + if ( filter.checked ) { + ol.className = ol.className + " hidepass"; + } else { + tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; + ol.className = tmp.replace( / hidepass /, " " ); + } + if ( defined.sessionStorage ) { + if (filter.checked) { + sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); + } else { + sessionStorage.removeItem( "qunit-filter-passed-tests" ); + } + } + }); + + if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { + filter.checked = true; + // `ol` initialized at top of scope + ol = document.getElementById( "qunit-tests" ); + ol.className = ol.className + " hidepass"; + } + toolbar.appendChild( filter ); + + // `label` initialized at top of scope + label = document.createElement( "label" ); + label.setAttribute( "for", "qunit-filter-pass" ); + label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." ); + label.innerHTML = "Hide passed tests"; + toolbar.appendChild( label ); + + urlConfigCheckboxesContainer = document.createElement("span"); + urlConfigCheckboxesContainer.innerHTML = urlConfigHtml; + urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input"); + // For oldIE support: + // * Add handlers to the individual elements instead of the container + // * Use "click" instead of "change" + // * Fallback from event.target to event.srcElement + addEvents( urlConfigCheckboxes, "click", function( event ) { + var params = {}, + target = event.target || event.srcElement; + params[ target.name ] = target.checked ? true : undefined; + window.location = QUnit.url( params ); + }); + toolbar.appendChild( urlConfigCheckboxesContainer ); + + if (numModules > 1) { + moduleFilter = document.createElement( "span" ); + moduleFilter.setAttribute( "id", "qunit-modulefilter-container" ); + moduleFilter.innerHTML = moduleFilterHtml; + addEvent( moduleFilter.lastChild, "change", function() { + var selectBox = moduleFilter.getElementsByTagName("select")[0], + selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value); + + window.location = QUnit.url({ + module: ( selectedModule === "" ) ? undefined : selectedModule, + // Remove any existing filters + filter: undefined, + testNumber: undefined + }); + }); + toolbar.appendChild(moduleFilter); + } + } + + // `main` initialized at top of scope + main = id( "qunit-fixture" ); + if ( main ) { + config.fixture = main.innerHTML; + } + + if ( config.autostart ) { + QUnit.start(); + } +}; + +addEvent( window, "load", QUnit.load ); + +// `onErrorFnPrev` initialized at top of scope +// Preserve other handlers +onErrorFnPrev = window.onerror; + +// Cover uncaught exceptions +// Returning true will suppress the default browser handler, +// returning false will let it run. +window.onerror = function ( error, filePath, linerNr ) { + var ret = false; + if ( onErrorFnPrev ) { + ret = onErrorFnPrev( error, filePath, linerNr ); + } + + // Treat return value as window.onerror itself does, + // Only do our handling if not suppressed. + if ( ret !== true ) { + if ( QUnit.config.current ) { + if ( QUnit.config.current.ignoreGlobalErrors ) { + return true; + } + QUnit.pushFailure( error, filePath + ":" + linerNr ); + } else { + QUnit.test( "global failure", extend( function() { + QUnit.pushFailure( error, filePath + ":" + linerNr ); + }, { validTest: validTest } ) ); + } + return false; + } + + return ret; +}; + +function done() { + config.autorun = true; + + // Log the last module results + if ( config.currentModule ) { + runLoggingCallbacks( "moduleDone", QUnit, { + name: config.currentModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + }); + } + delete config.previousModule; + + var i, key, + banner = id( "qunit-banner" ), + tests = id( "qunit-tests" ), + runtime = +new Date() - config.started, + passed = config.stats.all - config.stats.bad, + html = [ + "Tests completed in ", + runtime, + " milliseconds.
    ", + "", + passed, + " assertions of ", + config.stats.all, + " passed, ", + config.stats.bad, + " failed." + ].join( "" ); + + if ( banner ) { + banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); + } + + if ( tests ) { + id( "qunit-testresult" ).innerHTML = html; + } + + if ( config.altertitle && typeof document !== "undefined" && document.title ) { + // show ✖ for good, ✔ for bad suite result in title + // use escape sequences in case file gets loaded with non-utf-8-charset + document.title = [ + ( config.stats.bad ? "\u2716" : "\u2714" ), + document.title.replace( /^[\u2714\u2716] /i, "" ) + ].join( " " ); + } + + // clear own sessionStorage items if all tests passed + if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { + // `key` & `i` initialized at top of scope + for ( i = 0; i < sessionStorage.length; i++ ) { + key = sessionStorage.key( i++ ); + if ( key.indexOf( "qunit-test-" ) === 0 ) { + sessionStorage.removeItem( key ); + } + } + } + + // scroll back to top to show results + if ( window.scrollTo ) { + window.scrollTo(0, 0); + } + + runLoggingCallbacks( "done", QUnit, { + failed: config.stats.bad, + passed: passed, + total: config.stats.all, + runtime: runtime + }); +} + +/** @return Boolean: true if this test should be ran */ +function validTest( test ) { + var include, + filter = config.filter && config.filter.toLowerCase(), + module = config.module && config.module.toLowerCase(), + fullName = (test.module + ": " + test.testName).toLowerCase(); + + // Internally-generated tests are always valid + if ( test.callback && test.callback.validTest === validTest ) { + delete test.callback.validTest; + return true; + } + + if ( config.testNumber ) { + return test.testNumber === config.testNumber; + } + + if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) { + return false; + } + + if ( !filter ) { + return true; + } + + include = filter.charAt( 0 ) !== "!"; + if ( !include ) { + filter = filter.slice( 1 ); + } + + // If the filter matches, we need to honour include + if ( fullName.indexOf( filter ) !== -1 ) { + return include; + } + + // Otherwise, do the opposite + return !include; +} + +// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) +// Later Safari and IE10 are supposed to support error.stack as well +// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack +function extractStacktrace( e, offset ) { + offset = offset === undefined ? 3 : offset; + + var stack, include, i; + + if ( e.stacktrace ) { + // Opera + return e.stacktrace.split( "\n" )[ offset + 3 ]; + } else if ( e.stack ) { + // Firefox, Chrome + stack = e.stack.split( "\n" ); + if (/^error$/i.test( stack[0] ) ) { + stack.shift(); + } + if ( fileName ) { + include = []; + for ( i = offset; i < stack.length; i++ ) { + if ( stack[ i ].indexOf( fileName ) !== -1 ) { + break; + } + include.push( stack[ i ] ); + } + if ( include.length ) { + return include.join( "\n" ); + } + } + return stack[ offset ]; + } else if ( e.sourceURL ) { + // Safari, PhantomJS + // hopefully one day Safari provides actual stacktraces + // exclude useless self-reference for generated Error objects + if ( /qunit.js$/.test( e.sourceURL ) ) { + return; + } + // for actual exceptions, this is useful + return e.sourceURL + ":" + e.line; + } +} +function sourceFromStacktrace( offset ) { + try { + throw new Error(); + } catch ( e ) { + return extractStacktrace( e, offset ); + } +} + +/** + * Escape text for attribute or text content. + */ +function escapeText( s ) { + if ( !s ) { + return ""; + } + s = s + ""; + // Both single quotes and double quotes (for attributes) + return s.replace( /['"<>&]/g, function( s ) { + switch( s ) { + case "'": + return "'"; + case "\"": + return """; + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + } + }); +} + +function synchronize( callback, last ) { + config.queue.push( callback ); + + if ( config.autorun && !config.blocking ) { + process( last ); + } +} + +function process( last ) { + function next() { + process( last ); + } + var start = new Date().getTime(); + config.depth = config.depth ? config.depth + 1 : 1; + + while ( config.queue.length && !config.blocking ) { + if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { + config.queue.shift()(); + } else { + setTimeout( next, 13 ); + break; + } + } + config.depth--; + if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { + done(); + } +} + +function saveGlobal() { + config.pollution = []; + + if ( config.noglobals ) { + for ( var key in window ) { + if ( hasOwn.call( window, key ) ) { + // in Opera sometimes DOM element ids show up here, ignore them + if ( /^qunit-test-output/.test( key ) ) { + continue; + } + config.pollution.push( key ); + } + } + } +} + +function checkPollution() { + var newGlobals, + deletedGlobals, + old = config.pollution; + + saveGlobal(); + + newGlobals = diff( config.pollution, old ); + if ( newGlobals.length > 0 ) { + QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); + } + + deletedGlobals = diff( old, config.pollution ); + if ( deletedGlobals.length > 0 ) { + QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); + } +} + +// returns a new Array with the elements that are in a but not in b +function diff( a, b ) { + var i, j, + result = a.slice(); + + for ( i = 0; i < result.length; i++ ) { + for ( j = 0; j < b.length; j++ ) { + if ( result[i] === b[j] ) { + result.splice( i, 1 ); + i--; + break; + } + } + } + return result; +} + +function extend( a, b ) { + for ( var prop in b ) { + if ( hasOwn.call( b, prop ) ) { + // Avoid "Member not found" error in IE8 caused by messing with window.constructor + if ( !( prop === "constructor" && a === window ) ) { + if ( b[ prop ] === undefined ) { + delete a[ prop ]; + } else { + a[ prop ] = b[ prop ]; + } + } + } + } + + return a; +} + +/** + * @param {HTMLElement} elem + * @param {string} type + * @param {Function} fn + */ +function addEvent( elem, type, fn ) { + // Standards-based browsers + if ( elem.addEventListener ) { + elem.addEventListener( type, fn, false ); + // IE + } else { + elem.attachEvent( "on" + type, fn ); + } +} + +/** + * @param {Array|NodeList} elems + * @param {string} type + * @param {Function} fn + */ +function addEvents( elems, type, fn ) { + var i = elems.length; + while ( i-- ) { + addEvent( elems[i], type, fn ); + } +} + +function hasClass( elem, name ) { + return (" " + elem.className + " ").indexOf(" " + name + " ") > -1; +} + +function addClass( elem, name ) { + if ( !hasClass( elem, name ) ) { + elem.className += (elem.className ? " " : "") + name; + } +} + +function removeClass( elem, name ) { + var set = " " + elem.className + " "; + // Class name may appear multiple times + while ( set.indexOf(" " + name + " ") > -1 ) { + set = set.replace(" " + name + " " , " "); + } + // If possible, trim it for prettiness, but not necessarily + elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, ""); +} + +function id( name ) { + return !!( typeof document !== "undefined" && document && document.getElementById ) && + document.getElementById( name ); +} + +function registerLoggingCallback( key ) { + return function( callback ) { + config[key].push( callback ); + }; +} + +// Supports deprecated method of completely overwriting logging callbacks +function runLoggingCallbacks( key, scope, args ) { + var i, callbacks; + if ( QUnit.hasOwnProperty( key ) ) { + QUnit[ key ].call(scope, args ); + } else { + callbacks = config[ key ]; + for ( i = 0; i < callbacks.length; i++ ) { + callbacks[ i ].call( scope, args ); + } + } +} + +// Test for equality any JavaScript type. +// Author: Philippe Rathé +QUnit.equiv = (function() { + + // Call the o related callback with the given arguments. + function bindCallbacks( o, callbacks, args ) { + var prop = QUnit.objectType( o ); + if ( prop ) { + if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { + return callbacks[ prop ].apply( callbacks, args ); + } else { + return callbacks[ prop ]; // or undefined + } + } + } + + // the real equiv function + var innerEquiv, + // stack to decide between skip/abort functions + callers = [], + // stack to avoiding loops from circular referencing + parents = [], + parentsB = [], + + getProto = Object.getPrototypeOf || function ( obj ) { + /*jshint camelcase:false */ + return obj.__proto__; + }, + callbacks = (function () { + + // for string, boolean, number and null + function useStrictEquality( b, a ) { + /*jshint eqeqeq:false */ + if ( b instanceof a.constructor || a instanceof b.constructor ) { + // to catch short annotation VS 'new' annotation of a + // declaration + // e.g. var i = 1; + // var j = new Number(1); + return a == b; + } else { + return a === b; + } + } + + return { + "string": useStrictEquality, + "boolean": useStrictEquality, + "number": useStrictEquality, + "null": useStrictEquality, + "undefined": useStrictEquality, + + "nan": function( b ) { + return isNaN( b ); + }, + + "date": function( b, a ) { + return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); + }, + + "regexp": function( b, a ) { + return QUnit.objectType( b ) === "regexp" && + // the regex itself + a.source === b.source && + // and its modifiers + a.global === b.global && + // (gmi) ... + a.ignoreCase === b.ignoreCase && + a.multiline === b.multiline && + a.sticky === b.sticky; + }, + + // - skip when the property is a method of an instance (OOP) + // - abort otherwise, + // initial === would have catch identical references anyway + "function": function() { + var caller = callers[callers.length - 1]; + return caller !== Object && typeof caller !== "undefined"; + }, + + "array": function( b, a ) { + var i, j, len, loop, aCircular, bCircular; + + // b could be an object literal here + if ( QUnit.objectType( b ) !== "array" ) { + return false; + } + + len = a.length; + if ( len !== b.length ) { + // safe and faster + return false; + } + + // track reference to avoid circular references + parents.push( a ); + parentsB.push( b ); + for ( i = 0; i < len; i++ ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + aCircular = parents[j] === a[i]; + bCircular = parentsB[j] === b[i]; + if ( aCircular || bCircular ) { + if ( a[i] === b[i] || aCircular && bCircular ) { + loop = true; + } else { + parents.pop(); + parentsB.pop(); + return false; + } + } + } + if ( !loop && !innerEquiv(a[i], b[i]) ) { + parents.pop(); + parentsB.pop(); + return false; + } + } + parents.pop(); + parentsB.pop(); + return true; + }, + + "object": function( b, a ) { + /*jshint forin:false */ + var i, j, loop, aCircular, bCircular, + // Default to true + eq = true, + aProperties = [], + bProperties = []; + + // comparing constructors is more strict than using + // instanceof + if ( a.constructor !== b.constructor ) { + // Allow objects with no prototype to be equivalent to + // objects with Object as their constructor. + if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || + ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { + return false; + } + } + + // stack constructor before traversing properties + callers.push( a.constructor ); + + // track reference to avoid circular references + parents.push( a ); + parentsB.push( b ); + + // be strict: don't ensure hasOwnProperty and go deep + for ( i in a ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + aCircular = parents[j] === a[i]; + bCircular = parentsB[j] === b[i]; + if ( aCircular || bCircular ) { + if ( a[i] === b[i] || aCircular && bCircular ) { + loop = true; + } else { + eq = false; + break; + } + } + } + aProperties.push(i); + if ( !loop && !innerEquiv(a[i], b[i]) ) { + eq = false; + break; + } + } + + parents.pop(); + parentsB.pop(); + callers.pop(); // unstack, we are done + + for ( i in b ) { + bProperties.push( i ); // collect b's properties + } + + // Ensures identical properties name + return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); + } + }; + }()); + + innerEquiv = function() { // can take multiple arguments + var args = [].slice.apply( arguments ); + if ( args.length < 2 ) { + return true; // end transition + } + + return (function( a, b ) { + if ( a === b ) { + return true; // catch the most you can + } else if ( a === null || b === null || typeof a === "undefined" || + typeof b === "undefined" || + QUnit.objectType(a) !== QUnit.objectType(b) ) { + return false; // don't lose time with error prone cases + } else { + return bindCallbacks(a, callbacks, [ b, a ]); + } + + // apply transition with (1..n) arguments + }( args[0], args[1] ) && innerEquiv.apply( this, args.splice(1, args.length - 1 )) ); + }; + + return innerEquiv; +}()); + +/** + * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | + * http://flesler.blogspot.com Licensed under BSD + * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 + * + * @projectDescription Advanced and extensible data dumping for Javascript. + * @version 1.0.0 + * @author Ariel Flesler + * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} + */ +QUnit.jsDump = (function() { + function quote( str ) { + return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\""; + } + function literal( o ) { + return o + ""; + } + function join( pre, arr, post ) { + var s = jsDump.separator(), + base = jsDump.indent(), + inner = jsDump.indent(1); + if ( arr.join ) { + arr = arr.join( "," + s + inner ); + } + if ( !arr ) { + return pre + post; + } + return [ pre, inner + arr, base + post ].join(s); + } + function array( arr, stack ) { + var i = arr.length, ret = new Array(i); + this.up(); + while ( i-- ) { + ret[i] = this.parse( arr[i] , undefined , stack); + } + this.down(); + return join( "[", ret, "]" ); + } + + var reName = /^function (\w+)/, + jsDump = { + // type is used mostly internally, you can fix a (custom)type in advance + parse: function( obj, type, stack ) { + stack = stack || [ ]; + var inStack, res, + parser = this.parsers[ type || this.typeOf(obj) ]; + + type = typeof parser; + inStack = inArray( obj, stack ); + + if ( inStack !== -1 ) { + return "recursion(" + (inStack - stack.length) + ")"; + } + if ( type === "function" ) { + stack.push( obj ); + res = parser.call( this, obj, stack ); + stack.pop(); + return res; + } + return ( type === "string" ) ? parser : this.parsers.error; + }, + typeOf: function( obj ) { + var type; + if ( obj === null ) { + type = "null"; + } else if ( typeof obj === "undefined" ) { + type = "undefined"; + } else if ( QUnit.is( "regexp", obj) ) { + type = "regexp"; + } else if ( QUnit.is( "date", obj) ) { + type = "date"; + } else if ( QUnit.is( "function", obj) ) { + type = "function"; + } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { + type = "window"; + } else if ( obj.nodeType === 9 ) { + type = "document"; + } else if ( obj.nodeType ) { + type = "node"; + } else if ( + // native arrays + toString.call( obj ) === "[object Array]" || + // NodeList objects + ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) + ) { + type = "array"; + } else if ( obj.constructor === Error.prototype.constructor ) { + type = "error"; + } else { + type = typeof obj; + } + return type; + }, + separator: function() { + return this.multiline ? this.HTML ? "
    " : "\n" : this.HTML ? " " : " "; + }, + // extra can be a number, shortcut for increasing-calling-decreasing + indent: function( extra ) { + if ( !this.multiline ) { + return ""; + } + var chr = this.indentChar; + if ( this.HTML ) { + chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); + } + return new Array( this.depth + ( extra || 0 ) ).join(chr); + }, + up: function( a ) { + this.depth += a || 1; + }, + down: function( a ) { + this.depth -= a || 1; + }, + setParser: function( name, parser ) { + this.parsers[name] = parser; + }, + // The next 3 are exposed so you can use them + quote: quote, + literal: literal, + join: join, + // + depth: 1, + // This is the list of parsers, to modify them, use jsDump.setParser + parsers: { + window: "[Window]", + document: "[Document]", + error: function(error) { + return "Error(\"" + error.message + "\")"; + }, + unknown: "[Unknown]", + "null": "null", + "undefined": "undefined", + "function": function( fn ) { + var ret = "function", + // functions never have name in IE + name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1]; + + if ( name ) { + ret += " " + name; + } + ret += "( "; + + ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" ); + return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" ); + }, + array: array, + nodelist: array, + "arguments": array, + object: function( map, stack ) { + /*jshint forin:false */ + var ret = [ ], keys, key, val, i; + QUnit.jsDump.up(); + keys = []; + for ( key in map ) { + keys.push( key ); + } + keys.sort(); + for ( i = 0; i < keys.length; i++ ) { + key = keys[ i ]; + val = map[ key ]; + ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); + } + QUnit.jsDump.down(); + return join( "{", ret, "}" ); + }, + node: function( node ) { + var len, i, val, + open = QUnit.jsDump.HTML ? "<" : "<", + close = QUnit.jsDump.HTML ? ">" : ">", + tag = node.nodeName.toLowerCase(), + ret = open + tag, + attrs = node.attributes; + + if ( attrs ) { + for ( i = 0, len = attrs.length; i < len; i++ ) { + val = attrs[i].nodeValue; + // IE6 includes all attributes in .attributes, even ones not explicitly set. + // Those have values like undefined, null, 0, false, "" or "inherit". + if ( val && val !== "inherit" ) { + ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" ); + } + } + } + ret += close; + + // Show content of TextNode or CDATASection + if ( node.nodeType === 3 || node.nodeType === 4 ) { + ret += node.nodeValue; + } + + return ret + open + "/" + tag + close; + }, + // function calls it internally, it's the arguments part of the function + functionArgs: function( fn ) { + var args, + l = fn.length; + + if ( !l ) { + return ""; + } + + args = new Array(l); + while ( l-- ) { + // 97 is 'a' + args[l] = String.fromCharCode(97+l); + } + return " " + args.join( ", " ) + " "; + }, + // object calls it internally, the key part of an item in a map + key: quote, + // function calls it internally, it's the content of the function + functionCode: "[code]", + // node calls it internally, it's an html attribute value + attribute: quote, + string: quote, + date: quote, + regexp: literal, + number: literal, + "boolean": literal + }, + // if true, entities are escaped ( <, >, \t, space and \n ) + HTML: false, + // indentation unit + indentChar: " ", + // if true, items in a collection, are separated by a \n, else just a space. + multiline: true + }; + + return jsDump; +}()); + +// from jquery.js +function inArray( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; +} + +/* + * Javascript Diff Algorithm + * By John Resig (http://ejohn.org/) + * Modified by Chu Alan "sprite" + * + * Released under the MIT license. + * + * More Info: + * http://ejohn.org/projects/javascript-diff-algorithm/ + * + * Usage: QUnit.diff(expected, actual) + * + * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over" + */ +QUnit.diff = (function() { + /*jshint eqeqeq:false, eqnull:true */ + function diff( o, n ) { + var i, + ns = {}, + os = {}; + + for ( i = 0; i < n.length; i++ ) { + if ( !hasOwn.call( ns, n[i] ) ) { + ns[ n[i] ] = { + rows: [], + o: null + }; + } + ns[ n[i] ].rows.push( i ); + } + + for ( i = 0; i < o.length; i++ ) { + if ( !hasOwn.call( os, o[i] ) ) { + os[ o[i] ] = { + rows: [], + n: null + }; + } + os[ o[i] ].rows.push( i ); + } + + for ( i in ns ) { + if ( hasOwn.call( ns, i ) ) { + if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) { + n[ ns[i].rows[0] ] = { + text: n[ ns[i].rows[0] ], + row: os[i].rows[0] + }; + o[ os[i].rows[0] ] = { + text: o[ os[i].rows[0] ], + row: ns[i].rows[0] + }; + } + } + } + + for ( i = 0; i < n.length - 1; i++ ) { + if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && + n[ i + 1 ] == o[ n[i].row + 1 ] ) { + + n[ i + 1 ] = { + text: n[ i + 1 ], + row: n[i].row + 1 + }; + o[ n[i].row + 1 ] = { + text: o[ n[i].row + 1 ], + row: i + 1 + }; + } + } + + for ( i = n.length - 1; i > 0; i-- ) { + if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && + n[ i - 1 ] == o[ n[i].row - 1 ]) { + + n[ i - 1 ] = { + text: n[ i - 1 ], + row: n[i].row - 1 + }; + o[ n[i].row - 1 ] = { + text: o[ n[i].row - 1 ], + row: i - 1 + }; + } + } + + return { + o: o, + n: n + }; + } + + return function( o, n ) { + o = o.replace( /\s+$/, "" ); + n = n.replace( /\s+$/, "" ); + + var i, pre, + str = "", + out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), + oSpace = o.match(/\s+/g), + nSpace = n.match(/\s+/g); + + if ( oSpace == null ) { + oSpace = [ " " ]; + } + else { + oSpace.push( " " ); + } + + if ( nSpace == null ) { + nSpace = [ " " ]; + } + else { + nSpace.push( " " ); + } + + if ( out.n.length === 0 ) { + for ( i = 0; i < out.o.length; i++ ) { + str += "" + out.o[i] + oSpace[i] + ""; + } + } + else { + if ( out.n[0].text == null ) { + for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { + str += "" + out.o[n] + oSpace[n] + ""; + } + } + + for ( i = 0; i < out.n.length; i++ ) { + if (out.n[i].text == null) { + str += "" + out.n[i] + nSpace[i] + ""; + } + else { + // `pre` initialized at top of scope + pre = ""; + + for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { + pre += "" + out.o[n] + oSpace[n] + ""; + } + str += " " + out.n[i].text + nSpace[i] + pre; + } + } + } + + return str; + }; +}()); + +// for CommonJS environments, export everything +if ( typeof exports !== "undefined" ) { + extend( exports, QUnit.constructor.prototype ); +} + +// get at whatever the global object is, like window in browsers +}( (function() {return this;}.call()) )); diff --git a/vendor/loader.js b/vendor/loader.js new file mode 100644 index 00000000000..54d178b76d8 --- /dev/null +++ b/vendor/loader.js @@ -0,0 +1,53 @@ +var define, requireModule, require, requirejs; + +(function() { + var registry = {}, seen = {}; + + define = function(name, deps, callback) { + registry[name] = { deps: deps, callback: callback }; + }; + + requirejs = require = requireModule = function(name) { + requirejs._eak_seen = registry; + + if (seen[name]) { return seen[name]; } + seen[name] = {}; + + if (!registry[name]) { + throw new Error("Could not find module " + name); + } + + var mod = registry[name], + deps = mod.deps, + callback = mod.callback, + reified = [], + exports; + + for (var i=0, l=deps.length; i Date: Sat, 4 Jan 2014 18:04:24 -0600 Subject: [PATCH 0002/2527] move grunt tasks into folders --- .jshintrc | 6 ++-- Gruntfile.js | 65 +++++------------------------------- package.json | 8 ++++- tasks/options/browser.js | 6 ++++ tasks/options/clean.js | 3 ++ tasks/options/concat.js | 20 +++++++++++ tasks/options/connect.js | 8 +++++ tasks/options/jshint.js | 6 ++++ tasks/options/qunit.js | 7 ++++ tasks/options/transpile.js | 25 ++++++++++++++ tests/ember_configuration.js | 3 +- 11 files changed, 95 insertions(+), 62 deletions(-) create mode 100644 tasks/options/browser.js create mode 100644 tasks/options/clean.js create mode 100644 tasks/options/concat.js create mode 100644 tasks/options/connect.js create mode 100644 tasks/options/jshint.js create mode 100644 tasks/options/qunit.js create mode 100644 tasks/options/transpile.js diff --git a/.jshintrc b/.jshintrc index 185af7956de..c62eeaa8d32 100644 --- a/.jshintrc +++ b/.jshintrc @@ -34,9 +34,8 @@ ], "node" : false, - "es3" : true, "browser" : true, - + "es3": true, "boss" : true, "curly": false, "debug": false, @@ -58,5 +57,6 @@ "sub": true, "strict": false, "white": false, - "eqnull": true + "eqnull": true, + "esnext": true } diff --git a/Gruntfile.js b/Gruntfile.js index 02d9ecfdc0e..77bbe1c15db 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,66 +1,17 @@ var matchdep = require('matchdep'); - -function nameFor(path) { - var result, match; - if (match = path.match(/^(?:lib|test|test\/tests)\/(.*?)(?:\.js)?$/)) { - result = match[1]; - } else { - result = path; - } - - return path; -} module.exports = function(grunt){ matchdep.filterDev('grunt-*').forEach(grunt.loadNpmTasks); grunt.loadTasks('tasks'); + var config = require('load-grunt-config')(grunt, { + configPath: __dirname + '/tasks/options', + init: false + }); - grunt.initConfig({ - pkg: require('./package.json'), - clean: { - main: [ 'tmp/**/*' ] - }, - transpile: { - amd: { - type: 'amd', - moduleName: nameFor, - files: [{ - expand: true, - cwd: 'packages/', - src: [ '**/lib/**/*.js', ], - dest: 'tmp', - ext: '.amd.js' - }] - } - }, - concat: { - amd: { - src: [ 'tmp/**/*.amd.js' ], - dest: 'tmp/ember-data.amd.js' - }, - globals: { - src: [ 'vendor/loader.js', 'tmp/**/*.amd.js' ], - dest: 'tmp/ember-data.browser1.js' - }, - tests: { - src: [ 'packages/**/tests/**/*.js' ], - dest: 'tmp/tests.js', - options: { - separator: ';\n', - process: function(src, filepath){ - return "(function(){\n" + src + "\n})()"; - } - } - } - }, + config.pkg = require('./package'); + config.env = process.env; - browser: { - dist: { - src: 'tmp/ember-data.browser1.js', - dest: 'dist/ember-data.js' - } - } - }); + grunt.initConfig(config); - grunt.registerTask('default', [ 'clean', 'transpile:amd', 'concat:globals', 'browser:dist', 'concat:tests' ]); + grunt.registerTask('default', [ 'clean', 'transpile:amd', 'concat:globals', 'browser:dist', 'jshint', 'concat:tests', 'connect', 'qunit' ]); }; diff --git a/package.json b/package.json index d1f0fea3a7c..0b9e34efb8b 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,12 @@ "grunt-es6-module-transpiler": "~0.6.0", "grunt": "~0.4.2", "grunt-contrib-clean": "~0.5.0", - "grunt-contrib-concat": "~0.3.0" + "grunt-contrib-concat": "~0.3.0", + "load-grunt-config": "~0.7.0", + "load-grunt-tasks": "~0.2.1", + "matchdep": "~0.3.0", + "grunt-contrib-jshint": "~0.8.0", + "grunt-contrib-qunit": "~0.3.0", + "grunt-contrib-connect": "~0.6.0" } } diff --git a/tasks/options/browser.js b/tasks/options/browser.js new file mode 100644 index 00000000000..30f532233db --- /dev/null +++ b/tasks/options/browser.js @@ -0,0 +1,6 @@ +module.exports = { + dist: { + src: 'tmp/ember-data.browser1.js', + dest: 'dist/ember-data.js' + } +}; diff --git a/tasks/options/clean.js b/tasks/options/clean.js new file mode 100644 index 00000000000..ef55f92eb78 --- /dev/null +++ b/tasks/options/clean.js @@ -0,0 +1,3 @@ +module.exports = { + main: [ 'tmp/**/*' ] +}; diff --git a/tasks/options/concat.js b/tasks/options/concat.js new file mode 100644 index 00000000000..81ab434a49e --- /dev/null +++ b/tasks/options/concat.js @@ -0,0 +1,20 @@ +module.exports = { + amd: { + src: [ 'tmp/**/*.amd.js' ], + dest: 'tmp/ember-data.amd.js' + }, + globals: { + src: [ 'vendor/loader.js', 'tmp/**/*.amd.js' ], + dest: 'tmp/ember-data.browser1.js' + }, + tests: { + src: [ 'packages/**/tests/**/*.js' ], + dest: 'tmp/tests.js', + options: { + separator: ';\n', + process: function(src, filepath){ + return "(function(){\n" + src + "\n})();"; + } + } + } +}; diff --git a/tasks/options/connect.js b/tasks/options/connect.js new file mode 100644 index 00000000000..a8c6251734b --- /dev/null +++ b/tasks/options/connect.js @@ -0,0 +1,8 @@ +module.exports = { + main: { + options: { + port: '9997', + base: '.' + } + } +}; diff --git a/tasks/options/jshint.js b/tasks/options/jshint.js new file mode 100644 index 00000000000..72f344c70a4 --- /dev/null +++ b/tasks/options/jshint.js @@ -0,0 +1,6 @@ +module.exports = { + options: { + jshintrc: ".jshintrc" + }, + src: [ 'dist/ember-data.js' ] +}; diff --git a/tasks/options/qunit.js b/tasks/options/qunit.js new file mode 100644 index 00000000000..3249c1b3313 --- /dev/null +++ b/tasks/options/qunit.js @@ -0,0 +1,7 @@ +module.exports = { + all: { + options: { + urls: [ 'http://localhost:9997/tests/index.html' ] + } + } +}; diff --git a/tasks/options/transpile.js b/tasks/options/transpile.js new file mode 100644 index 00000000000..28dc770dc66 --- /dev/null +++ b/tasks/options/transpile.js @@ -0,0 +1,25 @@ + +function nameFor(path) { + var result, match; + if (match = path.match(/^(?:lib|test|test\/tests)\/(.*?)(?:\.js)?$/)) { + result = match[1]; + } else { + result = path; + } + + return path; +} + +module.exports = { + amd: { + type: 'amd', + moduleName: nameFor, + files: [{ + expand: true, + cwd: 'packages/', + src: [ '**/lib/**/*.js', ], + dest: 'tmp', + ext: '.amd.js' + }] + } +}; diff --git a/tests/ember_configuration.js b/tests/ember_configuration.js index 53c0ca301e5..6e76d90e5c6 100644 --- a/tests/ember_configuration.js +++ b/tests/ember_configuration.js @@ -6,8 +6,9 @@ Ember.config = {}; Ember.testing = true; + Ember.LOG_VERSION = false; - window.ENV = { TESTING: true }; + window.ENV = { TESTING: true, LOG_VERSION: false }; var extendPrototypes = QUnit.urlParams.extendprototypes; ENV['EXTEND_PROTOTYPES'] = !!extendPrototypes; From 5a9134affc1f5a3c13ceac8b4d169be148c20b83 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 4 Jan 2014 18:17:36 -0600 Subject: [PATCH 0003/2527] move some requires around --- .../lib/system/active_model_serializer.js | 2 +- tests/ember_configuration.js | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index cacb2cd6ddd..cba754b32c7 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -1,4 +1,4 @@ -import {singularize} from "../../../ember-inflector/lib/system"; +import {singularize} from "../../../ember-inflector/lib/main"; import RESTSerializer from "../../../ember-data/lib/serializers/rest_serializer"; /** @module ember-data diff --git a/tests/ember_configuration.js b/tests/ember_configuration.js index 6e76d90e5c6..4bfb9282d06 100644 --- a/tests/ember_configuration.js +++ b/tests/ember_configuration.js @@ -13,11 +13,6 @@ var extendPrototypes = QUnit.urlParams.extendprototypes; ENV['EXTEND_PROTOTYPES'] = !!extendPrototypes; - if (typeof EmberDev !== 'undefined' && EmberDev.jsHint) { - // jsHint makes its own Object.create stub, we don't want to use this - ENV['STUB_OBJECT_CREATE'] = !Object.create; - } - window.async = function(callback, timeout) { stop(); @@ -132,14 +127,6 @@ }); }; - - if (typeof EmberDev !== 'undefined') { - EmberDev.distros = { - spade: 'ember-data-spade.js', - build: 'ember-data.js' - }; - } - // Generate the jQuery expando on window ahead of time // to make the QUnit global check run clean jQuery(window).data('testing', true); From caaac7d3abfc158b8b040212439483f6cade74bc Mon Sep 17 00:00:00 2001 From: bmac Date: Sat, 18 Jan 2014 21:03:56 -0500 Subject: [PATCH 0004/2527] Do not call adapter.deleteRecord for a record that is already saved and deleted. --- packages/ember-data/lib/system/model/states.js | 6 +++++- packages/ember-data/lib/system/store.js | 4 +++- .../tests/integration/adapter/rest_adapter_test.js | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index afd9a28883f..4416286a63c 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -661,7 +661,11 @@ var RootState = { invokeLifecycleCallbacks: function(record) { record.triggerLater('didDelete', record); record.triggerLater('didCommit', record); - } + }, + + willCommit: Ember.K, + + didCommit: Ember.K } }, diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 0d3df735517..a92dffc9e02 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -915,7 +915,9 @@ DS.Store = Ember.Object.extend({ adapter = this.adapterFor(record.constructor), operation; - if (get(record, 'isNew')) { + if (get(record, 'currentState.stateName') === 'root.deleted.saved') { + return resolver.resolve(record); + } else if (get(record, 'isNew')) { operation = 'createRecord'; } else if (get(record, 'isDeleted')) { operation = 'deleteRecord'; diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 21a92ebd18c..81e67566327 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -460,6 +460,20 @@ test("delete - a payload with sideloaded updates pushes the updates", function() })); }); +test("delete - deleting a newly created record should not throw an error", function() { + var post = store.createRecord('post'); + + post.deleteRecord(); + post.save().then(async(function(post) { + equal(passedUrl, null, "There is no ajax call to delete a record that has never been saved."); + equal(passedVerb, null, "There is no ajax call to delete a record that has never been saved."); + equal(passedHash, null, "There is no ajax call to delete a record that has never been saved."); + + equal(post.get('isDeleted'), true, "the post is now deleted"); + equal(post.get('isError'), false, "the post is not an error"); + })); +}); + test("findAll - returning an array populates the array", function() { ajaxResponse({ posts: [ From 83a2bc21ffbcfa11528e9d6c92f611a0cd6e17c6 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 19 Jan 2014 11:05:14 -0500 Subject: [PATCH 0005/2527] Remove DS.AttributeChange. --- packages/ember-data/lib/system/changes.js | 1 - .../lib/system/changes/attribute_change.js | 48 ------------------- 2 files changed, 49 deletions(-) delete mode 100644 packages/ember-data/lib/system/changes/attribute_change.js diff --git a/packages/ember-data/lib/system/changes.js b/packages/ember-data/lib/system/changes.js index 804c91eef5b..0c710dd3825 100644 --- a/packages/ember-data/lib/system/changes.js +++ b/packages/ember-data/lib/system/changes.js @@ -2,5 +2,4 @@ @module ember-data */ -require("ember-data/system/changes/attribute_change"); require("ember-data/system/changes/relationship_change"); diff --git a/packages/ember-data/lib/system/changes/attribute_change.js b/packages/ember-data/lib/system/changes/attribute_change.js deleted file mode 100644 index 145e94db79d..00000000000 --- a/packages/ember-data/lib/system/changes/attribute_change.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - @module ember-data -*/ - -/** - An AttributeChange object is created whenever a record's - attribute changes value. It is used to track changes to a - record between transaction commits. - - @class AttributeChange - @namespace DS - @private - @constructor -*/ -var AttributeChange = DS.AttributeChange = function(options) { - this.record = options.record; - this.store = options.store; - this.name = options.name; - this.value = options.value; - this.oldValue = options.oldValue; -}; - -AttributeChange.createChange = function(options) { - return new AttributeChange(options); -}; - -AttributeChange.prototype = { - sync: function() { - if (this.value !== this.oldValue) { - this.record.send('becomeDirty'); - this.record.updateRecordArraysLater(); - } - - // TODO: Use this object in the commit process - this.destroy(); - }, - - /** - If the AttributeChange is destroyed (either by being rolled back - or being committed), remove it from the list of pending changes - on the record. - - @method destroy - */ - destroy: function() { - delete this.record._changesToSync[this.name]; - } -}; From a24f1984b44b16b08e2cbb9c441d280664d36d2a Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sun, 19 Jan 2014 11:36:56 -0600 Subject: [PATCH 0006/2527] add watch option, fix some test oddities --- .travis.yml | 2 +- Gruntfile.js | 12 ++- package.json | 3 +- packages/ember-data/lib/main.js | 3 +- packages/ember-data/lib/system/model.js | 3 +- tasks/options/watch.js | 12 +++ tests/ember_configuration.js | 115 ++++++++++++------------ 7 files changed, 88 insertions(+), 62 deletions(-) create mode 100644 tasks/options/watch.js diff --git a/.travis.yml b/.travis.yml index 8df7c0b0b53..8821b8ae12e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ install: - "bin/cached-npm install" - "bin/cached-bundle install --deployment" - sudo apt-get update && sudo apt-get install git -script: rake test[all] +script: grunt after_success: bundle exec rake publish_build env: global: diff --git a/Gruntfile.js b/Gruntfile.js index 77bbe1c15db..ec7d10e3455 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -13,5 +13,15 @@ module.exports = function(grunt){ grunt.initConfig(config); - grunt.registerTask('default', [ 'clean', 'transpile:amd', 'concat:globals', 'browser:dist', 'jshint', 'concat:tests', 'connect', 'qunit' ]); + grunt.registerTask('buildPackages', [ + 'clean', + 'transpile:amd', + 'concat:globals', + 'browser:dist', + 'jshint' + ]); + + grunt.registerTask('buildTests', ['concat:tests']); + grunt.registerTask('dev', [ 'connect', 'watch' ]); + grunt.registerTask('default', ['buildPackages', 'buildTests', 'connect', 'qunit']); }; diff --git a/package.json b/package.json index 0b9e34efb8b..5930a58ada7 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "matchdep": "~0.3.0", "grunt-contrib-jshint": "~0.8.0", "grunt-contrib-qunit": "~0.3.0", - "grunt-contrib-connect": "~0.6.0" + "grunt-contrib-connect": "~0.6.0", + "grunt-contrib-watch": "~0.5.3" } } diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index a2a15adecb5..5b3f3823551 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -9,7 +9,7 @@ import DS from "./core"; import "./ext/date"; import {Store, PromiseArray, PromiseObject} from "./system/store"; -import {Model, RootState, attr} from "./system/model"; +import {Model, Errors, RootState, attr} from "./system/model"; import { AttributeChange, RelationshipChange, @@ -57,6 +57,7 @@ DS.PromiseObject = PromiseObject; DS.Model = Model; DS.RootState = RootState; DS.attr = attr; +DS.Errors = Errors; DS.AttributeChange = AttributeChange; DS.RelationshipChange = RelationshipChange; diff --git a/packages/ember-data/lib/system/model.js b/packages/ember-data/lib/system/model.js index df7e7972583..646c51bccb7 100644 --- a/packages/ember-data/lib/system/model.js +++ b/packages/ember-data/lib/system/model.js @@ -5,5 +5,6 @@ import Model from "./model/model"; import attr from "./model/attributes"; import RootState from "./model/states"; +import Errors from "./model/errors"; -export {Model, RootState, attr}; +export {Model, RootState, attr, Errors}; diff --git a/tasks/options/watch.js b/tasks/options/watch.js new file mode 100644 index 00000000000..f721a497a98 --- /dev/null +++ b/tasks/options/watch.js @@ -0,0 +1,12 @@ +module.exports = { + + packages: { + files: [ 'packages/**/*.js', '!packages/**/test/**/*.js'], + tasks: [ 'buildPackages', 'buildTests', 'qunit' ] + }, + + tests: { + files: [ 'packages/**/test/**/*.js' ], + tasks: [ 'buildTests', 'qunit' ] + } +}; diff --git a/tests/ember_configuration.js b/tests/ember_configuration.js index 6fb7fdc245b..7a1be420d67 100644 --- a/tests/ember_configuration.js +++ b/tests/ember_configuration.js @@ -1,7 +1,6 @@ /*globals ENV QUnit */ -(function RESET() { - console.log('RESETTING'); +(function (){ window.Ember = window.Ember || {}; Ember.config = {}; @@ -127,69 +126,71 @@ }); }; - Ember.RSVP.configure('onerror', function(reason) { - // only print error messages if they're exceptions; - // otherwise, let a future turn of the event loop - // handle the error. - if (reason && reason instanceof Error) { - Ember.Logger.log(reason, reason.stack) - throw reason; - } - }); + QUnit.begin(function(){ + Ember.RSVP.configure('onerror', function(reason) { + // only print error messages if they're exceptions; + // otherwise, let a future turn of the event loop + // handle the error. + if (reason && reason instanceof Error) { + Ember.Logger.log(reason, reason.stack) + throw reason; + } + }); - Ember.RSVP.resolve = syncForTest(Ember.RSVP.resolve); + Ember.RSVP.resolve = syncForTest(Ember.RSVP.resolve); - Ember.View.reopen({ - _insertElementLater: syncForTest() - }); + Ember.View.reopen({ + _insertElementLater: syncForTest() + }); - DS.Store.reopen({ - save: syncForTest(), - createRecord: syncForTest(), - deleteRecord: syncForTest(), - push: syncForTest(), - pushMany: syncForTest(), - filter: syncForTest(), - find: syncForTest(), - findMany: syncForTest(), - findByIds: syncForTest(), - didSaveRecord: syncForTest(), - didSaveRecords: syncForTest(), - didUpdateAttribute: syncForTest(), - didUpdateAttributes: syncForTest(), - didUpdateRelationship: syncForTest(), - didUpdateRelationships: syncForTest() - }); + DS.Store.reopen({ + save: syncForTest(), + createRecord: syncForTest(), + deleteRecord: syncForTest(), + push: syncForTest(), + pushMany: syncForTest(), + filter: syncForTest(), + find: syncForTest(), + findMany: syncForTest(), + findByIds: syncForTest(), + didSaveRecord: syncForTest(), + didSaveRecords: syncForTest(), + didUpdateAttribute: syncForTest(), + didUpdateAttributes: syncForTest(), + didUpdateRelationship: syncForTest(), + didUpdateRelationships: syncForTest() + }); - DS.Model.reopen({ - save: syncForTest(), - reload: syncForTest(), - deleteRecord: syncForTest(), - dataDidChange: Ember.observer(syncForTest(), 'data'), - updateRecordArraysLater: syncForTest() - }); + DS.Model.reopen({ + save: syncForTest(), + reload: syncForTest(), + deleteRecord: syncForTest(), + dataDidChange: Ember.observer(syncForTest(), 'data'), + updateRecordArraysLater: syncForTest() + }); - DS.Errors.reopen({ - add: syncForTest(), - remove: syncForTest(), - clear: syncForTest() - }); + DS.Errors.reopen({ + add: syncForTest(), + remove: syncForTest(), + clear: syncForTest() + }); - var transforms = { - 'boolean': DS.BooleanTransform.create(), - 'date': DS.DateTransform.create(), - 'number': DS.NumberTransform.create(), - 'string': DS.StringTransform.create() - }; + var transforms = { + 'boolean': DS.BooleanTransform.create(), + 'date': DS.DateTransform.create(), + 'number': DS.NumberTransform.create(), + 'string': DS.StringTransform.create() + }; - // Prevent all tests involving serialization to require a container - DS.JSONSerializer.reopen({ - transformFor: function(attributeType) { - return this._super(attributeType, true) || transforms[attributeType]; - } - }); + // Prevent all tests involving serialization to require a container + DS.JSONSerializer.reopen({ + transformFor: function(attributeType) { + return this._super(attributeType, true) || transforms[attributeType]; + } + }); - Ember.RSVP.Promise.prototype.then = syncForTest(Ember.RSVP.Promise.prototype.then); + Ember.RSVP.Promise.prototype.then = syncForTest(Ember.RSVP.Promise.prototype.then); + }); // Generate the jQuery expando on window ahead of time // to make the QUnit global check run clean From a61d701dcaf62bf09446e9a82150413193954aea Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 19 Jan 2014 14:31:28 -0500 Subject: [PATCH 0007/2527] Do not trigger didSetProperty if value is unchanged. Also, fix determination of oldValue (previous a falsy value would not be found in `this._attributes`). --- .../ember-data/lib/system/model/attributes.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 49b793ebbd1..6ff8a72d4fa 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -274,14 +274,16 @@ DS.attr = function(type, options) { return Ember.computed(function(key, value) { if (arguments.length > 1) { Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.constructor.toString(), key !== 'id'); - var oldValue = this._attributes[key] || this._inFlightAttributes[key] || this._data[key]; - - this.send('didSetProperty', { - name: key, - oldValue: oldValue, - originalValue: this._data[key], - value: value - }); + var oldValue = getValue(this, key); + + if (value !== oldValue) { + this.send('didSetProperty', { + name: key, + oldValue: oldValue, + originalValue: this._data[key], + value: value + }); + } this._attributes[key] = value; return value; From d977f345e1638b57e850a138869775987d366eda Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 23 Jan 2014 09:43:01 -0600 Subject: [PATCH 0008/2527] fix banner generation a bit --- Gruntfile.js | 2 +- generators/license.js | 2 +- package.json | 4 +++- tasks/browser.js | 6 ++---- tasks/options/concat.js | 2 ++ tasks/options/uglify.js | 13 +++++++++++++ 6 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 tasks/options/uglify.js diff --git a/Gruntfile.js b/Gruntfile.js index ec7d10e3455..1758ce55907 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -23,5 +23,5 @@ module.exports = function(grunt){ grunt.registerTask('buildTests', ['concat:tests']); grunt.registerTask('dev', [ 'connect', 'watch' ]); - grunt.registerTask('default', ['buildPackages', 'buildTests', 'connect', 'qunit']); + grunt.registerTask('default', ['buildPackages', 'buildTests', 'connect', 'qunit', 'uglify']); }; diff --git a/generators/license.js b/generators/license.js index 21dff7fa06c..e64ffc66342 100644 --- a/generators/license.js +++ b/generators/license.js @@ -3,5 +3,5 @@ * @copyright Copyright 2011-2014 Tilde Inc. and contributors. * Portions Copyright 2011 LivingSocial Inc. * @license Licensed under MIT license (see license.js) - * @version VERSION_STRING_PLACEHOLDER + * @version <%= pkg.version %> */ diff --git a/package.json b/package.json index 5930a58ada7..948e855b1b2 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "name": "ember-data", + "version": "1.0.0-beta.5", "namespace": "DS", "devDependencies": { "defeatureify": "~0.1.4", @@ -14,6 +15,7 @@ "grunt-contrib-jshint": "~0.8.0", "grunt-contrib-qunit": "~0.3.0", "grunt-contrib-connect": "~0.6.0", - "grunt-contrib-watch": "~0.5.3" + "grunt-contrib-watch": "~0.5.3", + "grunt-contrib-uglify": "~0.3.0" } } diff --git a/tasks/browser.js b/tasks/browser.js index af05782dfd1..983be43ac10 100644 --- a/tasks/browser.js +++ b/tasks/browser.js @@ -2,13 +2,11 @@ module.exports = function(grunt) { grunt.registerMultiTask('browser', 'Export the object in <%= pkg.name %> to the window', function() { this.files.forEach(function(f) { var output = ['(function(global) {']; - output.push.apply(output, f.src.map(grunt.file.read)); - output.push("global.<%= pkg.namespace %> = requireModule('<%= pkg.name %>/lib/main')['default'];"); output.push('}(window));'); - - grunt.file.write(f.dest, grunt.template.process(output.join('\n'))); + var banner = grunt.template.process(grunt.file.read(__dirname + "/../generators/license.js")); + grunt.file.write(f.dest, banner + grunt.template.process(output.join('\n'))); }); }); }; diff --git a/tasks/options/concat.js b/tasks/options/concat.js index 81ab434a49e..8775371205a 100644 --- a/tasks/options/concat.js +++ b/tasks/options/concat.js @@ -1,3 +1,5 @@ +var grunt = require('grunt'); + module.exports = { amd: { src: [ 'tmp/**/*.amd.js' ], diff --git a/tasks/options/uglify.js b/tasks/options/uglify.js new file mode 100644 index 00000000000..9f0017eaaca --- /dev/null +++ b/tasks/options/uglify.js @@ -0,0 +1,13 @@ +var grunt = require('grunt'); +module.exports = { + options: { + report: 'gzip', + banner: grunt.file.read('generators/license.js'), + }, + dist: { + files: [{ + src: 'dist/ember-data.js', + dest: 'dist/ember-data.min.js', + }] + } +}; From 10660adab53a7034943c6fe75a965a64022b5e47 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 23 Jan 2014 10:06:22 -0600 Subject: [PATCH 0009/2527] fix build, import more test helper definitions from ember-dev --- .../activemodel-adapter/lib/initializers.js | 10 +- packages/ember-data/lib/initializers.js | 2 +- packages/ember-data/lib/serializers.js | 4 + .../tests/integration/application_test.js | 1 - tests/qunit_configuration.js | 245 ++++++++++++++---- 5 files changed, 208 insertions(+), 54 deletions(-) create mode 100644 packages/ember-data/lib/serializers.js diff --git a/packages/activemodel-adapter/lib/initializers.js b/packages/activemodel-adapter/lib/initializers.js index c17b4990b32..349c5280aff 100644 --- a/packages/activemodel-adapter/lib/initializers.js +++ b/packages/activemodel-adapter/lib/initializers.js @@ -1,18 +1,20 @@ -require("ember-data/system/container_proxy"); +import ContainerProxy from "../../ember-data/lib/system/container_proxy"; +import ActiveModelSerializer from "./system/active_model_serializer"; +import ActiveModelAdapter from "./system/active_model_adapter"; Ember.onLoad('Ember.Application', function(Application) { Application.initializer({ name: "activeModelAdapter", initialize: function(container, application) { - var proxy = new DS.ContainerProxy(container); + var proxy = new ContainerProxy(container); proxy.registerDeprecations([ {deprecated: 'serializer:_ams', valid: 'serializer:-active-model'}, {deprecated: 'adapter:_ams', valid: 'adapter:-active-model'} ]); - application.register('serializer:-active-model', DS.ActiveModelSerializer); - application.register('adapter:-active-model', DS.ActiveModelAdapter); + application.register('serializer:-active-model', ActiveModelSerializer); + application.register('adapter:-active-model', ActiveModelAdapter); } }); }); diff --git a/packages/ember-data/lib/initializers.js b/packages/ember-data/lib/initializers.js index f4231ffb624..7161f13db10 100644 --- a/packages/ember-data/lib/initializers.js +++ b/packages/ember-data/lib/initializers.js @@ -1,7 +1,7 @@ import {JSONSerializer, RESTSerializer} from "./serializers"; import {RESTAdapter} from "./adapters"; import DebugAdapter from "./system/debug/debug_adapter"; -import ContainerFactory from "./system/container_proxy"; +import ContainerProxy from "./system/container_proxy"; import { BooleanTransform, DateTransform, diff --git a/packages/ember-data/lib/serializers.js b/packages/ember-data/lib/serializers.js new file mode 100644 index 00000000000..0a78729af51 --- /dev/null +++ b/packages/ember-data/lib/serializers.js @@ -0,0 +1,4 @@ +import JSONSerializer from "./serializers/json_serializer"; +import RESTSerializer from "./serializers/rest_serializer"; + +export { JSONSerializer, RESTSerializer }; diff --git a/packages/ember-data/tests/integration/application_test.js b/packages/ember-data/tests/integration/application_test.js index 90099129ae4..ed4519fa3d5 100644 --- a/packages/ember-data/tests/integration/application_test.js +++ b/packages/ember-data/tests/integration/application_test.js @@ -94,4 +94,3 @@ test("a deprecation is made when looking up adapter:_rest", function(){ container.lookup('serializer:_default'); },"You tried to look up 'serializer:_default', but this has been deprecated in favor of 'serializer:-default'."); }); ->>>>>>> 58451d1ca50d9ef88c4e397afccc6a0a79622645 diff --git a/tests/qunit_configuration.js b/tests/qunit_configuration.js index b8dac772545..716affd867e 100644 --- a/tests/qunit_configuration.js +++ b/tests/qunit_configuration.js @@ -151,67 +151,216 @@ return str + "\n" + len + ' error' + ((len === 1) ? '' : 's'); }; - // Add `expectAssertion` which replaces - // `raises` to detect uncatchable assertions - function expectAssertion(fn, expectedMessage) { - var originalAssert = Ember.assert, - actualMessage, actualTest, - arity, sawAssertion; - - var AssertionFailedError = new Error('AssertionFailed'); - - try { - Ember.assert = function(message, test) { - arity = arguments.length; - actualMessage = message; - actualTest = test; + // A light class for stubbing + // + function MethodCallExpectation(target, property){ + this.target = target; + this.property = property; + }; - if (!test) { - throw AssertionFailedError; - } + MethodCallExpectation.prototype = { + handleCall: function(){ + this.sawCall = true; + return this.originalMethod.apply(this.target, arguments); + }, + stubMethod: function(fn){ + var context = this; + this.originalMethod = this.target[this.property]; + this.target[this.property] = function(){ + return context.handleCall.apply(context, arguments); }; - + }, + restoreMethod: function(){ + this.target[this.property] = this.originalMethod; + }, + runWithStub: function(fn){ try { + this.stubMethod(); fn(); - } catch(error) { - if (error === AssertionFailedError) { - sawAssertion = true; - } else { - throw error; - } + } finally { + this.restoreMethod(); } + }, + assert: function(fn) { + this.runWithStub(); + ok(this.sawCall, "Expected "+this.property+" to be called."); + } + }; - if (!sawAssertion) { - ok(false, "Expected Ember.assert: '" + expectedMessage + "', but no assertions were run"); - } else if (arity === 2) { + function AssertExpectation(message){ + MethodCallExpectation.call(this, Ember, 'assert'); + this.expectedMessage = message; + }; + AssertExpectation.Error = function(){}; + AssertExpectation.prototype = Object.create(MethodCallExpectation.prototype); + AssertExpectation.prototype.handleCall = function(message, test){ + this.sawCall = true; + if (test) return; // Only get message for failures + this.actualMessage = message; + // Halt execution + throw new AssertExpectation.Error(); + }; + AssertExpectation.prototype.assert = function(fn){ + try { + this.runWithStub(fn); + } catch (e) { + if (!(e instanceof AssertExpectation.Error)) + throw e; + } - if (expectedMessage) { - if (expectedMessage instanceof RegExp) { - ok(expectedMessage.test(actualMessage), "Expected Ember.assert: '" + expectedMessage + "', but got '" + actualMessage + "'"); - }else{ - equal(actualMessage, expectedMessage, "Expected Ember.assert: '" + expectedMessage + "', but got '" + actualMessage + "'"); - } + // Run assertions in an order that is useful when debugging a test failure. + // + if (!this.sawCall) { + ok(false, "Expected Ember.assert to be called (Not called with any value)."); + } else if (!this.actualMessage) { + ok(false, 'Expected a failing Ember.assert (Ember.assert called, but without a failing test).'); + } else { + if (this.expectedMessage) { + if (this.expectedMessage instanceof RegExp) { + ok(this.expectedMessage.test(this.actualMessage), "Expected failing Ember.assert: '" + this.expectedMessage + "', but got '" + this.actualMessage + "'."); } else { - ok(!actualTest); + equal(this.actualMessage, this.expectedMessage, "Expected failing Ember.assert: '" + this.expectedMessage + "', but got '" + this.actualMessage + "'."); } - } else if (arity === 1) { - ok(!actualTest); } else { - ok(false, 'Ember.assert was called without the assertion'); + // Positive assertion that assert was called + ok(true, 'Expected a failing Ember.assert.'); + } + } + }; + + // Looks for an exception raised within the fn. + // + // expectAssertion(function(){ + // Ember.assert("Homie don't roll like that"); + // } /* , optionalMessageStringOrRegex */); + // + window.expectAssertion = function expectAssertion(fn, message){ + (new AssertExpectation(message)).assert(fn); + }; + + EmberDev.deprecations = { + NONE: 99, // 99 problems and a deprecation ain't one + expecteds: null, + actuals: null, + stubEmber: function(){ + if (!EmberDev.deprecations.originalEmberDeprecate && Ember.deprecate !== EmberDev.deprecations.originalEmberDeprecate) { + EmberDev.deprecations.originalEmberDeprecate = Ember.deprecate; + } + Ember.deprecate = function(msg, test) { + EmberDev.deprecations.actuals = EmberDev.deprecations.actuals || []; + EmberDev.deprecations.actuals.push([msg, test]); + }; + }, + restoreEmber: function(){ + Ember.deprecate = EmberDev.deprecations.originalEmberDeprecate; + } + }; + + // Expects no deprecation to happen from the time of calling until + // the end of the test. + // + // expectNoDeprecation(/* optionalStringOrRegex */); + // Ember.deprecate("Old And Busted"); + // + window.expectNoDeprecation = function(message) { + if (typeof EmberDev.deprecations.expecteds === 'array') { + throw("No deprecation was expected after expectDeprecation was called!"); + } + EmberDev.deprecations.stubEmber(); + EmberDev.deprecations.expecteds = EmberDev.deprecations.NONE; + }; + + // Expect a deprecation to happen within a function, or if no function + // is pass, from the time of calling until the end of the test. Can be called + // multiple times to assert deprecations with different specific messages + // were fired. + // + // expectDeprecation(function(){ + // Ember.deprecate("Old And Busted"); + // }, /* optionalStringOrRegex */); + // + // expectDeprecation(/* optionalStringOrRegex */); + // Ember.deprecate("Old And Busted"); + // + window.expectDeprecation = function(fn, message) { + if (EmberDev.deprecations.expecteds === EmberDev.deprecations.NONE) { + throw("A deprecation was expected after expectNoDeprecation was called!"); + } + EmberDev.deprecations.stubEmber(); + EmberDev.deprecations.expecteds = EmberDev.deprecations.expecteds || []; + if (fn && typeof fn !== 'function') { + // fn is a message + EmberDev.deprecations.expecteds.push(fn); + } else { + EmberDev.deprecations.expecteds.push(message || /.*/); + if (fn) { + fn(); + window.assertDeprecation(); } + } + }; - } finally { - Ember.assert = originalAssert; + // Forces an assert the deprecations occurred, and resets the globals + // storing asserts for the next run. + // + // expectNoDeprecation(/Old/); + // setTimeout(function(){ + // Ember.deprecate("Old And Busted"); + // assertDeprecation(); + // }); + // + // assertDeprecation is called after each test run to catch any expectations + // without explicit asserts. + // + window.assertDeprecation = function() { + var expecteds = EmberDev.deprecations.expecteds, + actuals = EmberDev.deprecations.actuals || []; + if (!expecteds) { + EmberDev.deprecations.actuals = null; + return; } - } - window.expectAssertion = expectAssertion; + EmberDev.deprecations.restoreEmber(); + EmberDev.deprecations.actuals = null; + EmberDev.deprecations.expecteds = null; + + if (expecteds === EmberDev.deprecations.NONE) { + var actualMessages = []; + for (var actual in actuals) { + actualMessages.push(actual[0]); + } + ok(actuals.length === 0, "Expected no deprecation call, got: "+actualMessages.join(', ')); + } else { + for (var o=0;o < expecteds.length; o++) { + var expected = expecteds[o], match; + for (var i=0;i < actuals.length; i++) { + var actual = actuals[i]; + if (!actual[1]) { + if (expected instanceof RegExp) { + if (expected.test(actual[0])) { + match = actual; + break; + } + } else { + if (expected === actual[0]) { + match = actual; + break; + } + } + } + } - Ember.assert = function(msg, test) { - // only assert on failure - // // to not change number of assertions - if (!test) { - ok(false, 'Assertion failed: ' + msg); - } - } + if (!actual) + ok(false, "Recieved no deprecate calls at all, expecting: "+expected); + else if (match && !match[1]) + ok(true, "Recieved failing deprecation with message: "+match[0]); + else if (match && match[1]) + ok(false, "Expected failing deprecation, got succeeding with message: "+match[0]); + else if (actual[1]) + ok(false, "Did not receive failing deprecation matching '"+expected+"', last was success with '"+actual[0]+"'"); + else if (!actual[1]) + ok(false, "Did not receive failing deprecation matching '"+expected+"', last was failure with '"+actual[0]+"'"); + } + } + }; })(); From d6c82e9c18f0ec45b0e4f67d24ca7ea4ed7683c6 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 23 Jan 2014 10:09:54 -0600 Subject: [PATCH 0010/2527] readd ContainerProxy to DS namespace --- packages/ember-data/lib/main.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index 5b3f3823551..ec72dffa93f 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -50,6 +50,8 @@ import { import {hasMany, belongsTo} from "./system/relationships"; import "./initializers"; +import ContainerProxy from "./system/container_proxy"; + DS.Store = Store; DS.PromiseArray = PromiseArray; DS.PromiseObject = PromiseObject; @@ -98,4 +100,6 @@ DS.EmbeddedRecordsMixin = EmbeddedRecordsMixin; DS.belongsTo = belongsTo; DS.hasMany = hasMany; +DS.ContainerProxy = ContainerProxy; + export default DS; From 12309bb7f9ceb2715f4d9b6098d176d17330c68b Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 23 Jan 2014 10:13:10 -0600 Subject: [PATCH 0011/2527] update README with grunt workflow --- README.md | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 067801fe7ee..db6e4d70f8c 100644 --- a/README.md +++ b/README.md @@ -51,32 +51,20 @@ You also have the option to build ember-data.js yourself. Clone the repository, ### Setup -1. Install Ruby 1.9.3+. There are many resources on the web can help; one of the best is [rvm](https://rvm.io/). +1. Install Node.js from http://nodejs.org or your favorite package manager. -2. Install Bundler: `gem install bundler` +2. Install grunt and bower. `npm install -g grunt bower` -3. Run `bundle` inside the project root to install the gem dependencies. +3. Run `npm install && bower install` inside the project root to install the JS dependencies. ### In Your Browser -1. To start the development server, run `rackup`. - -2. Then visit: `http://localhost:9292/?package=PACKAGE_NAME`. Replace `PACKAGE_NAME` with the name of the package you want to run. For example: - - * [Ember.js Data](http://localhost:9292/?package=ember-data) - -To run multiple packages, you can separate them with commas. You can run all the tests using the `all` package: - - - -You can also pass `jquery=VERSION` in the test URL to test different versions of jQuery. Default is 1.9.0. +1. To start the development server, run `grunt dev`. ### From the CLI 1. Install phantomjs from http://phantomjs.org -2. Run `rake test` to run a basic test suite or run `rake test[all]` to - run a more comprehensive suite. +2. Run `grunt test` -3. (Mac OS X Only) Run `rake autotest` to automatically re-run tests - when any files are changed. +3. Run `grunt dev` to automatically re-run tests when any files are changed. From 1939044a936149ca1501334dddec838e50255221 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 23 Jan 2014 12:08:49 -0600 Subject: [PATCH 0012/2527] add grunt and bower install to .travis.yml --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 8821b8ae12e..4399a0df5b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,8 @@ install: - "bin/cached-npm install" - "bin/cached-bundle install --deployment" - sudo apt-get update && sudo apt-get install git +- "bin/cached-npm install -g grunt-cli bower" +- "bower install" script: grunt after_success: bundle exec rake publish_build env: From 238bb5ce574c3f57df45d04b21a61d1a2baf6dca Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sat, 25 Jan 2014 20:45:46 -0500 Subject: [PATCH 0013/2527] Post release version bump. --- Gemfile.lock | 2 +- VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index d11863db5ef..0b76070e67a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -27,7 +27,7 @@ GIT PATH remote: . specs: - ember-data-source (1.0.0.beta.6.canary) + ember-data-source (1.0.0.beta.7.canary) ember-source GEM diff --git a/VERSION b/VERSION index ce1302c500a..6dbac21a7aa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0-beta.6+canary +1.0.0-beta.7+canary From 50dd18dba09fd38989b68aafceb8ef374291c75d Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sat, 25 Jan 2014 22:14:48 -0500 Subject: [PATCH 0014/2527] Remove remnants of Ruby-land. --- Gemfile | 9 ----- Gemfile.lock | 91 --------------------------------------------------- Rakefile | 32 ------------------ ember-dev.yml | 22 ------------- 4 files changed, 154 deletions(-) delete mode 100644 Gemfile delete mode 100644 Gemfile.lock delete mode 100644 Rakefile delete mode 100644 ember-dev.yml diff --git a/Gemfile b/Gemfile deleted file mode 100644 index debeb92af8d..00000000000 --- a/Gemfile +++ /dev/null @@ -1,9 +0,0 @@ -source 'https://rubygems.org' - -gem 'rake-pipeline', :git => 'https://github.com/livingsocial/rake-pipeline.git' -gem 'ember-dev', :git => 'https://github.com/emberjs/ember-dev.git', :branch => 'master' - -gem 'ember-source', '~> 1.0' -gem 'puma' - -gemspec diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 0b76070e67a..00000000000 --- a/Gemfile.lock +++ /dev/null @@ -1,91 +0,0 @@ -GIT - remote: https://github.com/emberjs/ember-dev.git - revision: 48ce37b50c2f59658ba70824a8b692bf9d690b9e - branch: master - specs: - ember-dev (0.1) - aws-sdk - colored - execjs - grit - kicker - puma - rack - rake-pipeline (~> 0.8.0) - rake-pipeline-web-filters (~> 0.7.0) - uglifier - -GIT - remote: https://github.com/livingsocial/rake-pipeline.git - revision: a75d96fbadcc659a35a0ae59212e0bc60b58cc54 - specs: - rake-pipeline (0.8.0) - json - rake (~> 10.1.0) - thor - -PATH - remote: . - specs: - ember-data-source (1.0.0.beta.7.canary) - ember-source - -GEM - remote: https://rubygems.org/ - specs: - aws-sdk (1.32.0) - json (~> 1.4) - nokogiri (>= 1.4.4) - uuidtools (~> 2.1) - colored (1.2) - diff-lcs (1.2.5) - ember-source (1.3.1.1) - handlebars-source (~> 1.2.1) - execjs (2.0.2) - ffi (1.9.3) - grit (2.5.0) - diff-lcs (~> 1.1) - mime-types (~> 1.15) - posix-spawn (~> 0.3.6) - handlebars-source (1.2.1) - json (1.8.1) - kicker (3.0.0) - listen (~> 1.3.0) - notify (~> 0.5.2) - listen (1.3.1) - rb-fsevent (>= 0.9.3) - rb-inotify (>= 0.9) - rb-kqueue (>= 0.2) - mime-types (1.25.1) - mini_portile (0.5.2) - nokogiri (1.6.1) - mini_portile (~> 0.5.0) - notify (0.5.2) - posix-spawn (0.3.8) - puma (2.7.1) - rack (>= 1.1, < 2.0) - rack (1.5.2) - rake (10.1.1) - rake-pipeline-web-filters (0.7.0) - rack - rake-pipeline (~> 0.6) - rb-fsevent (0.9.4) - rb-inotify (0.9.3) - ffi (>= 0.5.0) - rb-kqueue (0.2.0) - ffi (>= 0.5.0) - thor (0.18.1) - uglifier (2.4.0) - execjs (>= 0.3.0) - json (>= 1.8.0) - uuidtools (2.1.4) - -PLATFORMS - ruby - -DEPENDENCIES - ember-data-source! - ember-dev! - ember-source (~> 1.0) - puma - rake-pipeline! diff --git a/Rakefile b/Rakefile deleted file mode 100644 index 35b7062eee4..00000000000 --- a/Rakefile +++ /dev/null @@ -1,32 +0,0 @@ -require "bundler/setup" -require "ember-dev/tasks" - -require 'pathname' -require 'fileutils' - -directory "tmp" - -task :docs => "ember:docs" -task :clean => "ember:clean" -task :dist => "ember:dist" -task :test, [:suite] => "ember:test" -task :default => :test - -task :publish_build => [:dist, :docs, 'ember:generate_static_test_site'] do - root_dir = Pathname.new(__FILE__).dirname - dist_dir = root_dir.join('dist') - - FileUtils.cp root_dir.join('docs', 'build', 'data.json'), - dist_dir.join('ember-data-docs.json') - - files = %w{ember-data.js ember-data-docs.json - ember-data-spade.js ember-data-tests.js - ember-data-tests.html} - - EmberDev::Publish.to_s3({ - :access_key_id => ENV['S3_ACCESS_KEY_ID'], - :secret_access_key => ENV['S3_SECRET_ACCESS_KEY'], - :bucket_name => ENV['S3_BUCKET_NAME'], - :files => files.map { |f| dist_dir.join(f) } - }) -end diff --git a/ember-dev.yml b/ember-dev.yml deleted file mode 100644 index a63e7d51972..00000000000 --- a/ember-dev.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: Ember Data -assetfile: 'Assetfile' -testing_suites: - default: - - "package=all" - all: - - "package=all&emberchannel=release" - - "package=all&emberchannel=beta" - - "package=all&emberchannel=canary" - - "package=all&jquery=1.7.2&nojshint=true" - - "package=all&jquery=1.8.3&nojshint=true" - - "package=all&jquery=1.9.1&nojshint=true" - - "package=all&extendprototypes=true&nojshint=true" - - "package=all&extendprototypes=true&jquery=1.9.1&nojshint=true" - - "package=all&dist=build&nojshint=true&emberchannel=release" - - "package=all&dist=build&nojshint=true&emberchannel=beta" - - "package=all&dist=build&nojshint=true&emberchannel=canary" -testing_packages: - - ember-data - - ember-inflector - - activemodel-adapter From b0cc327f48c881a3facfc7ec01baecefc9180eff Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sat, 25 Jan 2014 22:17:08 -0500 Subject: [PATCH 0015/2527] Remove ruby-land tasks from Travis. --- .travis.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4399a0df5b8..28e4f65f01d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,11 @@ --- -rvm: -- 1.9.3 +node_js: + - "0.10" install: - "bin/cached-npm install" -- "bin/cached-bundle install --deployment" -- sudo apt-get update && sudo apt-get install git - "bin/cached-npm install -g grunt-cli bower" - "bower install" script: grunt -after_success: bundle exec rake publish_build env: global: - S3_BUILD_CACHE_BUCKET=emberjs-build-cache From 3ad96d02ce0c157589662e0c28f1b2af23ae3559 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sun, 26 Jan 2014 10:32:51 +0100 Subject: [PATCH 0016/2527] Add `bower_components` to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index dda4bf08f01..0945db04706 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ docs/build/ docs/node_modules/ node_modules/ +bower_components/ From 69752883cb6a90ed444e0942954bda065aefef41 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sun, 26 Jan 2014 10:37:47 +0100 Subject: [PATCH 0017/2527] Register already imported transforms instead of `DS.XXX` --- packages/ember-data/lib/initializers.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/initializers.js b/packages/ember-data/lib/initializers.js index 7161f13db10..68fc464ca3b 100644 --- a/packages/ember-data/lib/initializers.js +++ b/packages/ember-data/lib/initializers.js @@ -77,10 +77,10 @@ Ember.onLoad('Ember.Application', function(Application) { before: "store", initialize: function(container, application) { - application.register('transform:boolean', DS.BooleanTransform); - application.register('transform:date', DS.DateTransform); - application.register('transform:number', DS.NumberTransform); - application.register('transform:string', DS.StringTransform); + application.register('transform:boolean', BooleanTransform); + application.register('transform:date', DateTransform); + application.register('transform:number', NumberTransform); + application.register('transform:string', StringTransform); } }); From d54dc447c32ba7b511e0dc989e27f4e888193c03 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sun, 26 Jan 2014 10:50:02 +0100 Subject: [PATCH 0018/2527] Import `Store` instead of referencing it via `DS.Store` --- packages/ember-data/lib/initializers.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/initializers.js b/packages/ember-data/lib/initializers.js index 68fc464ca3b..bfa7f8cbd4e 100644 --- a/packages/ember-data/lib/initializers.js +++ b/packages/ember-data/lib/initializers.js @@ -1,3 +1,4 @@ +import {Store} from "./system/store"; import {JSONSerializer, RESTSerializer} from "./serializers"; import {RESTAdapter} from "./adapters"; import DebugAdapter from "./system/debug/debug_adapter"; @@ -50,7 +51,7 @@ Ember.onLoad('Ember.Application', function(Application) { name: "store", initialize: function(container, application) { - application.register('store:main', application.Store || DS.Store); + application.register('store:main', application.Store || Store); // allow older names to be looked up From 8435ce8267a81c28769842d647e66c700866c006 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sun, 26 Jan 2014 11:11:41 +0100 Subject: [PATCH 0019/2527] Use `expectDeprecation` helper in lookup tests --- .../tests/integration/application_test.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/ember-data/tests/integration/application_test.js b/packages/ember-data/tests/integration/application_test.js index ed4519fa3d5..6a7e341a514 100644 --- a/packages/ember-data/tests/integration/application_test.js +++ b/packages/ember-data/tests/integration/application_test.js @@ -69,22 +69,28 @@ test("the DS namespace should be accessible", function() { }); test("the deprecated serializer:_default is resolved as serializer:default", function(){ - var deprecated = container.lookup('serializer:_default'), - valid = container.lookup('serializer:-default'); + var deprecated, valid = container.lookup('serializer:-default'); + expectDeprecation(function() { + deprecated = container.lookup('serializer:_default'); + }); ok(deprecated === valid, "they should resolve to the same thing"); }); test("the deprecated serializer:_rest is resolved as serializer:rest", function(){ - var deprecated = container.lookup('serializer:_rest'), - valid = container.lookup('serializer:-rest'); + var deprecated, valid = container.lookup('serializer:-rest'); + expectDeprecation(function() { + deprecated = container.lookup('serializer:_rest'); + }); ok(deprecated === valid, "they should resolve to the same thing"); }); test("the deprecated adapter:_rest is resolved as adapter:rest", function(){ - var deprecated = container.lookup('adapter:_rest'), - valid = container.lookup('adapter:-rest'); + var deprecated, valid = container.lookup('adapter:-rest'); + expectDeprecation(function() { + deprecated = container.lookup('adapter:_rest'); + }); ok(deprecated === valid, "they should resolve to the same thing"); }); From 63557a82279e092a9ef0d1e3981f4799537a36e2 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sun, 26 Jan 2014 12:17:13 +0100 Subject: [PATCH 0020/2527] Export `Store` as default from ./system/store This allows it to import it simply via `import Store from "./system/store"` instead of `import {Store} from "./system/store"`. --- packages/ember-data/lib/initializers.js | 2 +- packages/ember-data/lib/system/store.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/initializers.js b/packages/ember-data/lib/initializers.js index bfa7f8cbd4e..30e561a999d 100644 --- a/packages/ember-data/lib/initializers.js +++ b/packages/ember-data/lib/initializers.js @@ -1,4 +1,4 @@ -import {Store} from "./system/store"; +import Store from "./system/store"; import {JSONSerializer, RESTSerializer} from "./serializers"; import {RESTAdapter} from "./adapters"; import DebugAdapter from "./system/debug/debug_adapter"; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 9c685b58506..a272b521780 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1681,3 +1681,4 @@ function _commit(adapter, store, operation, record) { } export {Store, PromiseArray, PromiseObject}; +export default Store; From 1f052f7a72bbda303b3a34d260551e3e29fbad71 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Sun, 26 Jan 2014 22:47:13 +0900 Subject: [PATCH 0021/2527] Add missing task `grunt test` This command for test is documented in [README.md#from-the-cli](https://github.com/emberjs/data#from-the-cli). --- Gruntfile.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index 1758ce55907..795123853d3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -23,5 +23,6 @@ module.exports = function(grunt){ grunt.registerTask('buildTests', ['concat:tests']); grunt.registerTask('dev', [ 'connect', 'watch' ]); - grunt.registerTask('default', ['buildPackages', 'buildTests', 'connect', 'qunit', 'uglify']); + grunt.registerTask('test', ['buildPackages', 'buildTests', 'connect', 'qunit', 'uglify']); + grunt.registerTask('default', ['test']); }; From 95b387ca7897ea09a92a8d4737b51140937f17ad Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Sun, 26 Jan 2014 22:58:48 +0900 Subject: [PATCH 0022/2527] Fix ember-data version Currently, `package.json` is used for built ember-data version instead of `VERSION` file or `VERSION_STRING_PLACEHOLDER ` string. --- package.json | 2 +- packages/ember-data/lib/core.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 948e855b1b2..53c4fafa79f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.5", + "version": "1.0.0-beta.7+canary", "namespace": "DS", "devDependencies": { "defeatureify": "~0.1.4", diff --git a/packages/ember-data/lib/core.js b/packages/ember-data/lib/core.js index 5d26529b546..a03f0ae2fca 100644 --- a/packages/ember-data/lib/core.js +++ b/packages/ember-data/lib/core.js @@ -13,11 +13,11 @@ if ('undefined' === typeof DS) { /** @property VERSION @type String - @default 'VERSION_STRING_PLACEHOLDER' + @default '<%= pkg.version %>' @static */ DS = Ember.Namespace.create({ - VERSION: 'VERSION_STRING_PLACEHOLDER' + VERSION: '<%= pkg.version %>' }); if ('undefined' !== typeof window) { From 368a9a4d4bb6d307c127614087a11152445d4de9 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Sun, 26 Jan 2014 23:42:50 +0900 Subject: [PATCH 0023/2527] Now ember-data is built by `grunt buildPackages` `bundle` is no longer used. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index db6e4d70f8c..17e548b0271 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ The latest passing build from the "master" branch is available on [http://emberj Similarly the latest passing build from the "beta" branch can be found on [http://emberjs.com/builds/#/beta](http://emberjs.com/builds/#/beta) -You also have the option to build ember-data.js yourself. Clone the repository, run `bundle` then `rake dist`. You'll find ember-data.js in the `dist` directory. +You also have the option to build ember-data.js yourself. Clone the repository, run `grunt buildPackages` after [setup](#setup). You'll find ember-data.js in the `dist` directory. #### Roadmap From f5261e8a354a13c80a04d1a15169b2901e3581d9 Mon Sep 17 00:00:00 2001 From: Dimitri Suls Date: Sun, 26 Jan 2014 17:25:23 +0100 Subject: [PATCH 0024/2527] Should install grunt-cli globally. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 17e548b0271..1978cc3a0f7 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ You also have the option to build ember-data.js yourself. Clone the repository, 1. Install Node.js from http://nodejs.org or your favorite package manager. -2. Install grunt and bower. `npm install -g grunt bower` +2. Install grunt and bower. `npm install -g grunt-cli bower` 3. Run `npm install && bower install` inside the project root to install the JS dependencies. From 1fb102a598c14184d18a02f0a2660b72ddb12da3 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 27 Jan 2014 00:09:19 -0500 Subject: [PATCH 0025/2527] Revert "DateTransform serializes as a number instead of string. The deserializer was already considering this case. Adds millisecond precision to DateTransform" This reverts commit 47e43938d43cd012c2e89a51c6ea49f74c1c2840. This change causes errors when server-side handling does not support numeric values for dates. Example (Rails backend): ``` PG::DatatypeMismatch: ERROR: column "received_at" is of type timestamp without time zone but expression is of type bigint ``` --- packages/ember-data/lib/transforms/date.js | 26 +++++++++++++++++--- packages/ember-data/tests/unit/model_test.js | 9 +++---- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/packages/ember-data/lib/transforms/date.js b/packages/ember-data/lib/transforms/date.js index d2fd469eec3..44a45f26ea0 100644 --- a/packages/ember-data/lib/transforms/date.js +++ b/packages/ember-data/lib/transforms/date.js @@ -38,12 +38,32 @@ var DateTransform = Transform.extend({ serialize: function(date) { if (date instanceof Date) { - // Serialize it as a number to maintain millisecond precision - return Number(date); + var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; + var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + + var pad = function(num) { + return num < 10 ? "0"+num : ""+num; + }; + + var utcYear = date.getUTCFullYear(), + utcMonth = date.getUTCMonth(), + utcDayOfMonth = date.getUTCDate(), + utcDay = date.getUTCDay(), + utcHours = date.getUTCHours(), + utcMinutes = date.getUTCMinutes(), + utcSeconds = date.getUTCSeconds(); + + + var dayOfWeek = days[utcDay]; + var dayOfMonth = pad(utcDayOfMonth); + var month = months[utcMonth]; + + return dayOfWeek + ", " + dayOfMonth + " " + month + " " + utcYear + " " + + pad(utcHours) + ":" + pad(utcMinutes) + ":" + pad(utcSeconds) + " GMT"; } else { return null; } - } + } }); diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index e6183c3c636..4652c020858 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -319,9 +319,8 @@ test("a DS.Model can describe Date attributes", function() { converts('date', null, null); converts('date', undefined, undefined); - var date = new Date("Sat, 31 Dec 2011 00:08:16 GMT"); - date.setMilliseconds(54); - var expectedSerializedDate = Number(date); + var dateString = "Sat, 31 Dec 2011 00:08:16 GMT"; + var date = new Date(dateString); var store = createStore(); @@ -335,8 +334,8 @@ test("a DS.Model can describe Date attributes", function() { deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); })); - convertsFromServer('date', expectedSerializedDate, date); - convertsWhenSet('date', date, expectedSerializedDate); + convertsFromServer('date', dateString, date); + convertsWhenSet('date', date, dateString); }); test("don't allow setting", function(){ From b52bca0c65b8d6453de1f9286879a206676dddc7 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 27 Jan 2014 10:03:18 -0500 Subject: [PATCH 0026/2527] Pass arguments to `options.defaultValue` if a function. --- .../ember-data/lib/system/model/attributes.js | 2 +- packages/ember-data/tests/unit/model_test.js | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 071577ee9bb..56776f43cb1 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -206,7 +206,7 @@ Model.reopen({ function getDefaultValue(record, options, key) { if (typeof options.defaultValue === "function") { - return options.defaultValue(); + return options.defaultValue.apply(null, arguments); } else { return options.defaultValue; } diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index 4652c020858..14985ed8056 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -149,6 +149,23 @@ test("a defaultValue for an attribute can be a function", function() { equal(get(tag, 'createdAt'), "le default value", "the defaultValue function is evaluated"); }); +test("a defaultValue function gets the record, options, and key", function() { + expect(2); + + var Tag = DS.Model.extend({ + createdAt: DS.attr('string', { + defaultValue: function(record, options, key) { + deepEqual(record, tag, "the record is passed in properly"); + equal(key, 'createdAt', "the attribute being defaulted is passed in properly"); + return "le default value"; + } + }) + }); + + var tag = store.createRecord(Tag); + get(tag, 'createdAt'); +}); + test("setting a property to undefined on a newly created record should not impact the current state", function() { var Tag = DS.Model.extend({ name: DS.attr('string') From 6c414a952b3980c0dadcf28df075744b1b23feed Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 27 Jan 2014 14:47:30 -0500 Subject: [PATCH 0027/2527] Remove incorrect return documentation on store#pushPayload --- packages/ember-data/lib/system/store.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 9c685b58506..ac7c512a4d3 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1187,7 +1187,6 @@ Store = Ember.Object.extend({ @method pushPayload @param {String} type @param {Object} payload - @return {DS.Model} the record that was created or updated. */ pushPayload: function (type, payload) { var serializer; From f8904dd17c8a67eac6a97bab28880f177b2f0749 Mon Sep 17 00:00:00 2001 From: tchak Date: Tue, 28 Jan 2014 01:20:24 +0100 Subject: [PATCH 0028/2527] lazy create errors object on models --- packages/ember-data/lib/system/model/model.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 5c76b11b8a5..9731b60ba03 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -285,7 +285,17 @@ var Model = Ember.Object.extend(Ember.Evented, { @property errors @type {Object} */ - errors: null, + errors: Ember.computed(function() { + var errors = Errors.create(); + + errors.registerHandlers(this, function() { + this.send('becameInvalid'); + }, function() { + this.send('becameValid'); + }); + + return errors; + }), /** Create a JSON representation of the record, using the serialization @@ -382,13 +392,6 @@ var Model = Ember.Object.extend(Ember.Evented, { init: function() { set(this, 'currentState', DS.RootState.empty); - var errors = Errors.create(); - errors.registerHandlers(this, function() { - this.send('becameInvalid'); - }, function() { - this.send('becameValid'); - }); - set(this, 'errors', errors); this._super(); this._setup(); }, From c948da9bb8fee215b0e7d36f4729c8c75b0086f0 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 27 Jan 2014 22:38:11 -0500 Subject: [PATCH 0029/2527] postinstall bower install --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 53c4fafa79f..da51076fa34 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,9 @@ "name": "ember-data", "version": "1.0.0-beta.7+canary", "namespace": "DS", + "scripts": { + "postinstall": "bower install", + }, "devDependencies": { "defeatureify": "~0.1.4", "yuidocjs": "~0.3.46", From c2cf62ab77d5d8181c3f0832b84f9f33adf7fa73 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 27 Jan 2014 22:38:40 -0500 Subject: [PATCH 0030/2527] add `grunt server`, and ensure the server(dev) version builds tests, so you can run tests --- Gruntfile.js | 3 ++- package.json | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index 795123853d3..dde7e1eb49e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -22,7 +22,8 @@ module.exports = function(grunt){ ]); grunt.registerTask('buildTests', ['concat:tests']); - grunt.registerTask('dev', [ 'connect', 'watch' ]); + grunt.registerTask('dev', [ 'buildPackages', 'buildTests', 'connect', 'watch' ]); + grunt.registerTask('server', 'dev'); grunt.registerTask('test', ['buildPackages', 'buildTests', 'connect', 'qunit', 'uglify']); grunt.registerTask('default', ['test']); }; diff --git a/package.json b/package.json index da51076fa34..01348909bdb 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "namespace": "DS", "scripts": { "postinstall": "bower install", + "test": "grunt test" }, "devDependencies": { "defeatureify": "~0.1.4", From 1c95ba2ae20d666d328bea8a8b118f513eb3642b Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 27 Jan 2014 22:47:03 -0500 Subject: [PATCH 0031/2527] once is already saved off at the top of the file --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index ac7c512a4d3..0a111f8ca5c 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -570,7 +570,7 @@ Store = Ember.Object.extend({ } else { if (resolver) { resolver.resolve(); } manyArray.set('isLoaded', true); - Ember.run.once(manyArray, 'trigger', 'didLoad'); + once(manyArray, 'trigger', 'didLoad'); } return manyArray; From e240a1cc7b3734f3fff6aedce4c81eb41408c656 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 27 Jan 2014 23:25:47 -0500 Subject: [PATCH 0032/2527] misc cleanup --- .../lib/system/changes/attribute_change.js | 4 ++-- .../ember-data/lib/system/debug/debug_info.js | 1 - .../ember-data/lib/system/model/attributes.js | 8 ++++---- packages/ember-data/lib/system/model/model.js | 10 ++++++---- .../ember-data/lib/system/model/states.js | 8 ++++---- .../adapter_populated_record_array.js | 2 +- .../lib/system/record_arrays/many_array.js | 9 +++++---- .../lib/system/relationships/belongs_to.js | 19 ++++++++++++------- .../lib/system/relationships/has_many.js | 8 ++++---- packages/ember-data/lib/system/store.js | 4 ++-- packages/ember-data/lib/transforms/boolean.js | 2 +- packages/ember-data/lib/transforms/number.js | 4 +++- packages/ember-data/lib/transforms/string.js | 2 +- 13 files changed, 45 insertions(+), 36 deletions(-) diff --git a/packages/ember-data/lib/system/changes/attribute_change.js b/packages/ember-data/lib/system/changes/attribute_change.js index 00479fd49a6..e86af23738d 100644 --- a/packages/ember-data/lib/system/changes/attribute_change.js +++ b/packages/ember-data/lib/system/changes/attribute_change.js @@ -12,13 +12,13 @@ @private @constructor */ -var AttributeChange = function(options) { +function AttributeChange(options) { this.record = options.record; this.store = options.store; this.name = options.name; this.value = options.value; this.oldValue = options.oldValue; -}; +} AttributeChange.createChange = function(options) { return new AttributeChange(options); diff --git a/packages/ember-data/lib/system/debug/debug_info.js b/packages/ember-data/lib/system/debug/debug_info.js index 7a1c5b0cdfe..a5a1f4bdb2a 100644 --- a/packages/ember-data/lib/system/debug/debug_info.js +++ b/packages/ember-data/lib/system/debug/debug_info.js @@ -64,7 +64,6 @@ Model.reopen({ } }; } - }); export default Model; diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 03528e29ae5..b59a096a82e 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -262,7 +262,7 @@ function getValue(record, key) { @return {Attribute} */ -var attr = function(type, options) { +function attr(type, options) { options = options || {}; var meta = { @@ -271,7 +271,7 @@ var attr = function(type, options) { options: options }; - return Ember.computed(function(key, value) { + return Ember.computed('data', function(key, value) { if (arguments.length > 1) { Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.constructor.toString(), key !== 'id'); var oldValue = getValue(this, key); @@ -296,7 +296,7 @@ var attr = function(type, options) { // `data` is never set directly. However, it may be // invalidated from the state manager's setData // event. - }).property('data').meta(meta); -}; + }).meta(meta); +} export default attr; diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 9731b60ba03..a9e2ba71f76 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -5,7 +5,8 @@ import Errors from "./errors"; */ var get = Ember.get, set = Ember.set, - merge = Ember.merge; + merge = Ember.merge, + Promise = Ember.RSVP.Promise; var retrieveFromCurrentState = Ember.computed('currentState', function(key, value) { return get(get(this, 'currentState'), key); @@ -261,13 +262,14 @@ var Model = Ember.Object.extend(Ember.Evented, { @type {String} */ id: null, - transaction: null, + /** @property currentState @private @type {Object} */ currentState: null, + /** When the record is in the `invalid` state this object will contain any errors returned by the adapter. When present the errors hash @@ -386,7 +388,7 @@ var Model = Ember.Object.extend(Ember.Evented, { data: Ember.computed(function() { this._data = this._data || {}; return this._data; - }).property(), + }), _data: null, @@ -915,7 +917,7 @@ var Model = Ember.Object.extend(Ember.Evented, { var record = this; var promiseLabel = "DS: Model#reload of " + this; - var promise = new Ember.RSVP.Promise(function(resolve){ + var promise = new Promise(function(resolve){ record.send('reloadRecord', resolve); }, promiseLabel).then(function() { record.set('isReloading', false); diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index 05a3e67c5fa..dce2412d8df 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -172,7 +172,7 @@ var get = Ember.get, set = Ember.set; @class RootState */ -var hasDefinedProperties = function(object) { +function hasDefinedProperties(object) { // Ignore internal property defined by simulated `Ember.create`. var names = Ember.keys(object); var i, l, name; @@ -182,9 +182,9 @@ var hasDefinedProperties = function(object) { } return false; -}; +} -var didSetProperty = function(record, context) { +function didSetProperty(record, context) { if (context.value === context.originalValue) { delete record._attributes[context.name]; record.send('propertyWasReset', context.name); @@ -193,7 +193,7 @@ var didSetProperty = function(record, context) { } record.updateRecordArraysLater(); -}; +} // Implementation notes: // diff --git a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js index affd364d33a..cfa77740e49 100644 --- a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js @@ -40,7 +40,7 @@ var AdapterPopulatedRecordArray = RecordArray.extend({ meta: meta }); - // TODO: does triggering didLoad event should be the last action of the runLoop? + // TODO: should triggering didLoad event be the last action of the runLoop? Ember.run.once(this, 'trigger', 'didLoad'); } }); diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 6522a7c2b80..f8d718eb154 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -8,6 +8,10 @@ import {RelationshipChange} from "../changes"; var get = Ember.get, set = Ember.set; var map = Ember.EnumerableUtils.map; +function sync(change) { + change.sync(); +} + /** A `ManyArray` is a `RecordArray` that represents the contents of a has-many relationship. @@ -199,9 +203,7 @@ var ManyArray = RecordArray.extend({ // in arrayContentWillChange, so that the array // membership test in the sync() logic operates // on the final results. - this._changesToSync.forEach(function(change) { - change.sync(); - }); + this._changesToSync.forEach(sync); this._changesToSync.clear(); } @@ -228,7 +230,6 @@ var ManyArray = RecordArray.extend({ return record; } - }); export default ManyArray; diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index 2383cb12aaa..ffd1f69ef24 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -8,7 +8,7 @@ import {Model} from "../model"; */ function asyncBelongsTo(type, options, meta) { - return Ember.computed(function(key, value) { + return Ember.computed('data', function(key, value) { var data = get(this, 'data'), store = get(this, 'store'), promiseLabel = "DS: Async belongsTo " + this + " : " + key; @@ -31,7 +31,7 @@ function asyncBelongsTo(type, options, meta) { } else { return null; } - }).property('data').meta(meta); + }).meta(meta); } /** @@ -81,7 +81,7 @@ function asyncBelongsTo(type, options, meta) { @param {Object} options a hash of options @return {Ember.computed} relationship */ -var belongsTo = function(type, options) { +function belongsTo(type, options) { if (typeof type === 'object') { options = type; type = undefined; @@ -91,13 +91,18 @@ var belongsTo = function(type, options) { options = options || {}; - var meta = { type: type, isRelationship: true, options: options, kind: 'belongsTo' }; + var meta = { + type: type, + isRelationship: true, + options: options, + kind: 'belongsTo' + }; if (options.async) { return asyncBelongsTo(type, options, meta); } - return Ember.computed(function(key, value) { + return Ember.computed('data', function(key, value) { var data = get(this, 'data'), store = get(this, 'store'), belongsTo, typeClass; @@ -119,8 +124,8 @@ var belongsTo = function(type, options) { store.fetchRecord(belongsTo); return belongsTo; - }).property('data').meta(meta); -}; + }).meta(meta); +} /** These observers observe all `belongsTo` relationships on the record. See diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index f85a5bd251f..5bec9c6c1a0 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -59,13 +59,13 @@ function hasRelationship(type, options) { return asyncHasMany(type, options, meta); } - return Ember.computed(function(key, value) { + return Ember.computed('data', function(key, value) { return buildRelationship(this, key, options, function(store, data) { var records = data[key]; Ember.assert("You looked up the '" + key + "' relationship on '" + this + "' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", Ember.A(records).everyProperty('isEmpty', false)); return store.findMany(this, data[key], meta.type); }); - }).property('data').meta(meta); + }).meta(meta); } /** @@ -146,12 +146,12 @@ function hasRelationship(type, options) { @param {Object} options a hash of options @return {Ember.computed} relationship */ -var hasMany = function(type, options) { +function hasMany(type, options) { if (typeof type === 'object') { options = type; type = undefined; } return hasRelationship(type, options); -}; +} export default hasMany; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 0a111f8ca5c..802523ca9ac 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -36,9 +36,9 @@ var Store, PromiseObject, PromiseArray; // and lose type information. For example, Ember's router may put a record's // ID into the URL, and if we later try to deserialize that URL and find the // corresponding record, we will not know if it is a string or a number. -var coerceId = function(id) { +function coerceId(id) { return id == null ? null : id+''; -}; +} /** The store contains all of the data for records loaded from the server. diff --git a/packages/ember-data/lib/transforms/boolean.js b/packages/ember-data/lib/transforms/boolean.js index 7ec8bcd3c3c..5e29db0eb4e 100644 --- a/packages/ember-data/lib/transforms/boolean.js +++ b/packages/ember-data/lib/transforms/boolean.js @@ -1,3 +1,4 @@ +import Transform from "./base"; /** The `DS.BooleanTransform` class is used to serialize and deserialize @@ -20,7 +21,6 @@ @extends DS.Transform @namespace DS */ -import Transform from "./base"; var BooleanTransform = Transform.extend({ deserialize: function(serialized) { var type = typeof serialized; diff --git a/packages/ember-data/lib/transforms/number.js b/packages/ember-data/lib/transforms/number.js index ae13e562ea5..9053ee7ae13 100644 --- a/packages/ember-data/lib/transforms/number.js +++ b/packages/ember-data/lib/transforms/number.js @@ -1,4 +1,7 @@ +import Transform from "./base"; + var empty = Ember.isEmpty; + /** The `DS.NumberTransform` class is used to serialize and deserialize numeric attributes on Ember Data record objects. This transform is @@ -20,7 +23,6 @@ var empty = Ember.isEmpty; @extends DS.Transform @namespace DS */ -import Transform from "./base"; var NumberTransform = Transform.extend({ deserialize: function(serialized) { diff --git a/packages/ember-data/lib/transforms/string.js b/packages/ember-data/lib/transforms/string.js index 0ea29f9a32e..82d7a9d95a7 100644 --- a/packages/ember-data/lib/transforms/string.js +++ b/packages/ember-data/lib/transforms/string.js @@ -1,3 +1,4 @@ +import Transform from "./base"; var none = Ember.isNone; /** @@ -21,7 +22,6 @@ var none = Ember.isNone; @extends DS.Transform @namespace DS */ -import Transform from "./base"; var StringTransform = Transform.extend({ deserialize: function(serialized) { From 9e75162f8a9bf01df1778df3742bc6fad258f95b Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 27 Jan 2014 23:29:54 -0500 Subject: [PATCH 0033/2527] allow connect port to be configurable --- tasks/options/connect.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tasks/options/connect.js b/tasks/options/connect.js index a8c6251734b..ab6a5059ebf 100644 --- a/tasks/options/connect.js +++ b/tasks/options/connect.js @@ -1,7 +1,8 @@ +var port = process.env.PORT || '9997'; module.exports = { main: { options: { - port: '9997', + port: port, base: '.' } } From bd0ba573a8813b84ef537b28d63d09b39f7de480 Mon Sep 17 00:00:00 2001 From: tchak Date: Tue, 28 Jan 2014 10:28:28 +0100 Subject: [PATCH 0034/2527] mark more model properties as readOnly --- packages/ember-data/lib/system/model/model.js | 4 ++-- .../tests/integration/adapter/store_adapter_test.js | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index a9e2ba71f76..d202e51d7c2 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -297,7 +297,7 @@ var Model = Ember.Object.extend(Ember.Evented, { }); return errors; - }), + }).readOnly(), /** Create a JSON representation of the record, using the serialization @@ -388,7 +388,7 @@ var Model = Ember.Object.extend(Ember.Evented, { data: Ember.computed(function() { this._data = this._data || {}; return this._data; - }), + }).readOnly(), _data: null, diff --git a/packages/ember-data/tests/integration/adapter/store_adapter_test.js b/packages/ember-data/tests/integration/adapter/store_adapter_test.js index 9842b6aa0cc..20532ff0d0a 100644 --- a/packages/ember-data/tests/integration/adapter/store_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/store_adapter_test.js @@ -335,10 +335,6 @@ test("if a created record is marked as invalid by the server, it enters an error set(yehuda, 'updatedAt', true); equal(get(yehuda, 'isValid'), false, "the record is still invalid"); - // This tests that we handle undefined values without blowing up - var errors = get(yehuda, 'errors'); - set(errors, 'other_bound_property', undefined); - set(yehuda, 'errors', errors); set(yehuda, 'name', "Brohuda Brokatz"); equal(get(yehuda, 'isValid'), true, "the record is no longer invalid after changing"); From da354762c2d57189b7d8b942b6b4bd358a7370f0 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 28 Jan 2014 08:59:12 -0500 Subject: [PATCH 0035/2527] Ensure that bower is installed. --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 01348909bdb..f851ed01d70 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "grunt-contrib-qunit": "~0.3.0", "grunt-contrib-connect": "~0.6.0", "grunt-contrib-watch": "~0.5.3", - "grunt-contrib-uglify": "~0.3.0" + "grunt-contrib-uglify": "~0.3.0", + "bower": "~1.2" } } From cc417adbe8bee67ad024810607271d33bf96c60f Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 28 Jan 2014 11:49:54 -0500 Subject: [PATCH 0036/2527] Use the new naming for active_model_adapter integration tests. As the tests were written they worked just fine, but this may help anyone that comes along and looks to the tests for inspiration. --- .../tests/integration/active_model_serializer_test.js | 8 ++++---- .../tests/integration/embedded_records_mixin_test.js | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js index fc49beb7e23..3b289ac7d62 100644 --- a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js +++ b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js @@ -41,10 +41,10 @@ module("integration/active_model - ActiveModelSerializer", { env.store.modelFor('doomsdayDevice'); env.store.modelFor('mediocreVillain'); env.container.register('serializer:application', DS.ActiveModelSerializer); - env.container.register('serializer:ams', DS.ActiveModelSerializer); - env.container.register('adapter:ams', DS.ActiveModelAdapter); - env.amsSerializer = env.container.lookup("serializer:ams"); - env.amsAdapter = env.container.lookup("adapter:ams"); + env.container.register('serializer:-active-model', DS.ActiveModelSerializer); + env.container.register('adapter:-active-model', DS.ActiveModelAdapter); + env.amsSerializer = env.container.lookup("serializer:-active-model"); + env.amsAdapter = env.container.lookup("adapter:-active-model"); }, teardown: function() { diff --git a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js index ed2b6efc15a..77b0b6afbe0 100644 --- a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js +++ b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js @@ -33,10 +33,10 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { env.store.modelFor('evilMinion'); env.store.modelFor('comment'); env.container.register('serializer:application', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); - env.container.register('serializer:ams', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); - env.container.register('adapter:ams', DS.ActiveModelAdapter); - env.amsSerializer = env.container.lookup("serializer:ams"); - env.amsAdapter = env.container.lookup("adapter:ams"); + env.container.register('serializer:-active-model', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); + env.container.register('adapter:-active-model', DS.ActiveModelAdapter); + env.amsSerializer = env.container.lookup("serializer:-active-model"); + env.amsAdapter = env.container.lookup("adapter:-active-model"); }, teardown: function() { @@ -428,4 +428,4 @@ test("serialize with embedded objects", function() { home_planet_id: get(league, "id") }] }); -}); \ No newline at end of file +}); From 602b3464f73c360792293a50f44758c1321d46ea Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 28 Jan 2014 12:00:31 -0500 Subject: [PATCH 0037/2527] Prefer Promise.cast over resolve. This alleviates some unneeded intermediate promises This provides a polyfil for Promise.cast with Promise.resolve for older RSVP versions --- packages/ember-data/lib/main.js | 3 ++ .../lib/system/relationships/belongs_to.js | 16 +++++-- packages/ember-data/lib/system/store.js | 44 ++++++++++--------- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index ec72dffa93f..185ce6cf4b9 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -5,6 +5,9 @@ @main ember-data */ +// support RSVP 2.x via resolve, but prefer RSVP 3.x's Promise.cast +Ember.RSVP.Promise.cast = Ember.RSVP.Promise.cast || Ember.RSVP.resolve; + import DS from "./core"; import "./ext/date"; diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index ffd1f69ef24..21d61727315 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -1,6 +1,8 @@ var get = Ember.get, set = Ember.set, isNone = Ember.isNone; +var Promise = Ember.RSVP.Promise; + import {Model} from "../model"; /** @@ -15,19 +17,25 @@ function asyncBelongsTo(type, options, meta) { if (arguments.length === 2) { Ember.assert("You can only add a '" + type + "' record to this relationship", !value || value instanceof store.modelFor(type)); - return value === undefined ? null : DS.PromiseObject.create({ promise: Ember.RSVP.resolve(value, promiseLabel) }); + return value === undefined ? null : DS.PromiseObject.create({ + promise: Promise.cast(value, promiseLabel) + }); } var link = data.links && data.links[key], belongsTo = data[key]; if(!isNone(belongsTo)) { - var promise = store.fetchRecord(belongsTo) || Ember.RSVP.resolve(belongsTo, promiseLabel); - return DS.PromiseObject.create({ promise: promise}); + var promise = store.fetchRecord(belongsTo) || Promise.cast(belongsTo, promiseLabel); + return DS.PromiseObject.create({ + promise: promise + }); } else if (link) { var resolver = Ember.RSVP.defer("DS: Async belongsTo (link) " + this + " : " + key); store.findBelongsTo(this, link, meta, resolver); - return DS.PromiseObject.create({ promise: resolver.promise }); + return DS.PromiseObject.create({ + promise: resolver.promise + }); } else { return null; } diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 802523ca9ac..7a1d7c28b8d 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -11,7 +11,7 @@ var isNone = Ember.isNone; var forEach = Ember.EnumerableUtils.forEach; var indexOf = Ember.EnumerableUtils.indexOf; var map = Ember.EnumerableUtils.map; -var resolve = Ember.RSVP.resolve; +var Promise = Ember.RSVP.Promise; var copy = Ember.copy; var Store, PromiseObject, PromiseArray; @@ -162,7 +162,9 @@ Store = Ember.Object.extend({ } if (DS.Adapter.detect(adapter)) { - adapter = adapter.create({ container: this.container }); + adapter = adapter.create({ + container: this.container + }); } return adapter; @@ -361,9 +363,9 @@ Store = Ember.Object.extend({ type = this.modelFor(type); var record = this.recordForId(type, id); + var fetchedRecord = this.fetchRecord(record); - var promise = this.fetchRecord(record) || resolve(record, "DS: Store#findById " + type + " with id: " + id); - return promiseObject(promise); + return promiseObject(fetchedRecord || record, "DS: Store#findById " + type + " with id: " + id); }, /** @@ -646,16 +648,12 @@ Store = Ember.Object.extend({ var array = this.recordArrayManager .createAdapterPopulatedRecordArray(type, query); - var adapter = this.adapterFor(type), - promiseLabel = "DS: Store#findQuery " + type, - resolver = Ember.RSVP.defer(promiseLabel); + var adapter = this.adapterFor(type); Ember.assert("You tried to load a query but you have no adapter (for " + type + ")", adapter); Ember.assert("You tried to load a query but your adapter does not implement `findQuery`", adapter.findQuery); - resolver.resolve(_findQuery(adapter, this, type, query, array)); - - return promiseArray(resolver.promise); + return promiseArray(_findQuery(adapter, this, type, query, array)); }, /** @@ -813,7 +811,7 @@ Store = Ember.Object.extend({ var array = this.recordArrayManager .createFilteredRecordArray(type, filter); - promise = promise || resolve(array); + promise = promise || Promise.cast(array); return promiseArray(promise.then(function() { return array; @@ -1530,12 +1528,16 @@ PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin); */ PromiseObject = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin); -function promiseObject(promise) { - return PromiseObject.create({ promise: promise }); +function promiseObject(promise, label) { + return PromiseObject.create({ + promise: Promise.cast(promise, label) + }); } -function promiseArray(promise) { - return PromiseArray.create({ promise: promise }); +function promiseArray(promise, label) { + return PromiseArray.create({ + promise: Promise.cast(promise, label) + }); } function isThenable(object) { @@ -1576,7 +1578,7 @@ function _find(adapter, store, type, id) { var promise = adapter.find(store, type, id), serializer = serializerForAdapter(adapter, type); - return resolve(promise, "DS: Handle Adapter#find of " + type + " with id: " + id).then(function(payload) { + return Promise.cast(promise, "DS: Handle Adapter#find of " + type + " with id: " + id).then(function(payload) { Ember.assert("You made a request for a " + type.typeKey + " with id " + id + ", but the adapter's response did not have any data", payload); payload = serializer.extract(store, type, payload, id, 'find'); @@ -1592,7 +1594,7 @@ function _findMany(adapter, store, type, ids, owner) { var promise = adapter.findMany(store, type, ids, owner), serializer = serializerForAdapter(adapter, type); - return resolve(promise, "DS: Handle Adapter#findMany of " + type).then(function(payload) { + return Promise.cast(promise, "DS: Handle Adapter#findMany of " + type).then(function(payload) { payload = serializer.extract(store, type, payload, null, 'findMany'); Ember.assert("The response from a findMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1605,7 +1607,7 @@ function _findHasMany(adapter, store, record, link, relationship) { var promise = adapter.findHasMany(store, record, link, relationship), serializer = serializerForAdapter(adapter, relationship.type); - return resolve(promise, "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type).then(function(payload) { + return Promise.cast(promise, "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type).then(function(payload) { payload = serializer.extract(store, relationship.type, payload, null, 'findHasMany'); Ember.assert("The response from a findHasMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1619,7 +1621,7 @@ function _findBelongsTo(adapter, store, record, link, relationship) { var promise = adapter.findBelongsTo(store, record, link, relationship), serializer = serializerForAdapter(adapter, relationship.type); - return resolve(promise, "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type).then(function(payload) { + return Promise.cast(promise, "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type).then(function(payload) { payload = serializer.extract(store, relationship.type, payload, null, 'findBelongsTo'); var record = store.push(relationship.type, payload); @@ -1632,7 +1634,7 @@ function _findAll(adapter, store, type, sinceToken) { var promise = adapter.findAll(store, type, sinceToken), serializer = serializerForAdapter(adapter, type); - return resolve(promise, "DS: Handle Adapter#findAll of " + type).then(function(payload) { + return Promise.cast(promise, "DS: Handle Adapter#findAll of " + type).then(function(payload) { payload = serializer.extract(store, type, payload, null, 'findAll'); Ember.assert("The response from a findAll must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1647,7 +1649,7 @@ function _findQuery(adapter, store, type, query, recordArray) { var promise = adapter.findQuery(store, type, query, recordArray), serializer = serializerForAdapter(adapter, type); - return resolve(promise, "DS: Handle Adapter#findQuery of " + type).then(function(payload) { + return Promise.cast(promise, "DS: Handle Adapter#findQuery of " + type).then(function(payload) { payload = serializer.extract(store, type, payload, null, 'findQuery'); Ember.assert("The response from a findQuery must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); From 3a02497f34f8f4ce4265f284a68cc80743f438f0 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 28 Jan 2014 12:01:18 -0500 Subject: [PATCH 0038/2527] Use defeatureify to strip debug statements from output. * Adds `grunt-ember-defeatureify` * Adds `dist` task, which now is roughly equivalent to previous `rake dist`. * Removes `uglify` from `test` task (moved to `dist`). --- Gruntfile.js | 3 ++- package.json | 3 ++- tasks/options/emberDefeatureify.js | 18 ++++++++++++++++++ tasks/options/uglify.js | 2 +- 4 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 tasks/options/emberDefeatureify.js diff --git a/Gruntfile.js b/Gruntfile.js index dde7e1eb49e..41f19d75d23 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -24,6 +24,7 @@ module.exports = function(grunt){ grunt.registerTask('buildTests', ['concat:tests']); grunt.registerTask('dev', [ 'buildPackages', 'buildTests', 'connect', 'watch' ]); grunt.registerTask('server', 'dev'); - grunt.registerTask('test', ['buildPackages', 'buildTests', 'connect', 'qunit', 'uglify']); + grunt.registerTask('test', ['buildPackages', 'buildTests', 'connect', 'qunit']); + grunt.registerTask('dist', ['buildPackages', 'emberDefeatureify:stripDebug', 'uglify']); grunt.registerTask('default', ['test']); }; diff --git a/package.json b/package.json index f851ed01d70..8cb56af6994 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "grunt-contrib-connect": "~0.6.0", "grunt-contrib-watch": "~0.5.3", "grunt-contrib-uglify": "~0.3.0", - "bower": "~1.2" + "bower": "~1.2", + "grunt-ember-defeatureify": "~0.1.0" } } diff --git a/tasks/options/emberDefeatureify.js b/tasks/options/emberDefeatureify.js new file mode 100644 index 00000000000..8fbdfd33c8b --- /dev/null +++ b/tasks/options/emberDefeatureify.js @@ -0,0 +1,18 @@ +module.exports = { + options: { + debugStatements: [ + "Ember.warn", + "Ember.assert", + "Ember.deprecate", + "Ember.debug", + "Ember.Logger.info" + ] + }, + stripDebug: { + options: { + enableStripDebug: true + }, + src: 'dist/ember-data.js', + dest: 'dist/ember-data.prod.js' + } +}; diff --git a/tasks/options/uglify.js b/tasks/options/uglify.js index 9f0017eaaca..201521236d3 100644 --- a/tasks/options/uglify.js +++ b/tasks/options/uglify.js @@ -6,7 +6,7 @@ module.exports = { }, dist: { files: [{ - src: 'dist/ember-data.js', + src: 'dist/ember-data.prod.js', dest: 'dist/ember-data.min.js', }] } From 9191db3a0cdac062cf256314206da95ac2b1080d Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 28 Jan 2014 17:13:03 +0100 Subject: [PATCH 0039/2527] Upgrade QUnit to v1.13.0 Start using a bower installed version of QUnit. --- bower.json | 3 +- tests/index.html | 6 +- tests/qunit_configuration.js | 6 + tests/vendor/qunit.css | 244 ---- tests/vendor/qunit.js | 2212 ---------------------------------- 5 files changed, 11 insertions(+), 2460 deletions(-) delete mode 100644 tests/vendor/qunit.css delete mode 100644 tests/vendor/qunit.js diff --git a/bower.json b/bower.json index a5eb8116a3c..28375cb53db 100644 --- a/bower.json +++ b/bower.json @@ -2,6 +2,7 @@ "name": "ember-data", "private": true, "dependencies": { - "ember": "~1.2.0" + "ember": "~1.2.0", + "qunit": "~1.13.0" } } diff --git a/tests/index.html b/tests/index.html index 387da462db4..5490b0694ee 100644 --- a/tests/index.html +++ b/tests/index.html @@ -2,15 +2,15 @@ - QUnit Example - + Ember Data +
    - + diff --git a/tests/qunit_configuration.js b/tests/qunit_configuration.js index 716affd867e..618e8985eae 100644 --- a/tests/qunit_configuration.js +++ b/tests/qunit_configuration.js @@ -92,6 +92,12 @@ return originalTypeof.call(this, obj); }; + // raises is deprecated, but we likely want to keep it around for our es3 + // test runs. + // taken from emberjs/ember-dev here: http://git.io/sQhl3A + QUnit.constructor.prototype.raises = QUnit['throws']; + window.raises = QUnit['throws']; + QUnit.jsDump.parsers.emberObject = function(obj) { return obj.toString(); }; diff --git a/tests/vendor/qunit.css b/tests/vendor/qunit.css deleted file mode 100644 index 7ba3f9a30b8..00000000000 --- a/tests/vendor/qunit.css +++ /dev/null @@ -1,244 +0,0 @@ -/** - * QUnit v1.12.0 - A JavaScript Unit Testing Framework - * - * http://qunitjs.com - * - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - */ - -/** Font Family and Sizes */ - -#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { - font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; -} - -#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } -#qunit-tests { font-size: smaller; } - - -/** Resets */ - -#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { - margin: 0; - padding: 0; -} - - -/** Header */ - -#qunit-header { - padding: 0.5em 0 0.5em 1em; - - color: #8699a4; - background-color: #0d3349; - - font-size: 1.5em; - line-height: 1em; - font-weight: normal; - - border-radius: 5px 5px 0 0; - -moz-border-radius: 5px 5px 0 0; - -webkit-border-top-right-radius: 5px; - -webkit-border-top-left-radius: 5px; -} - -#qunit-header a { - text-decoration: none; - color: #c2ccd1; -} - -#qunit-header a:hover, -#qunit-header a:focus { - color: #fff; -} - -#qunit-testrunner-toolbar label { - display: inline-block; - padding: 0 .5em 0 .1em; -} - -#qunit-banner { - height: 5px; -} - -#qunit-testrunner-toolbar { - padding: 0.5em 0 0.5em 2em; - color: #5E740B; - background-color: #eee; - overflow: hidden; -} - -#qunit-userAgent { - padding: 0.5em 0 0.5em 2.5em; - background-color: #2b81af; - color: #fff; - text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; -} - -#qunit-modulefilter-container { - float: right; -} - -/** Tests: Pass/Fail */ - -#qunit-tests { - list-style-position: inside; -} - -#qunit-tests li { - padding: 0.4em 0.5em 0.4em 2.5em; - border-bottom: 1px solid #fff; - list-style-position: inside; -} - -#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { - display: none; -} - -#qunit-tests li strong { - cursor: pointer; -} - -#qunit-tests li a { - padding: 0.5em; - color: #c2ccd1; - text-decoration: none; -} -#qunit-tests li a:hover, -#qunit-tests li a:focus { - color: #000; -} - -#qunit-tests li .runtime { - float: right; - font-size: smaller; -} - -.qunit-assert-list { - margin-top: 0.5em; - padding: 0.5em; - - background-color: #fff; - - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} - -.qunit-collapsed { - display: none; -} - -#qunit-tests table { - border-collapse: collapse; - margin-top: .2em; -} - -#qunit-tests th { - text-align: right; - vertical-align: top; - padding: 0 .5em 0 0; -} - -#qunit-tests td { - vertical-align: top; -} - -#qunit-tests pre { - margin: 0; - white-space: pre-wrap; - word-wrap: break-word; -} - -#qunit-tests del { - background-color: #e0f2be; - color: #374e0c; - text-decoration: none; -} - -#qunit-tests ins { - background-color: #ffcaca; - color: #500; - text-decoration: none; -} - -/*** Test Counts */ - -#qunit-tests b.counts { color: black; } -#qunit-tests b.passed { color: #5E740B; } -#qunit-tests b.failed { color: #710909; } - -#qunit-tests li li { - padding: 5px; - background-color: #fff; - border-bottom: none; - list-style-position: inside; -} - -/*** Passing Styles */ - -#qunit-tests li li.pass { - color: #3c510c; - background-color: #fff; - border-left: 10px solid #C6E746; -} - -#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } -#qunit-tests .pass .test-name { color: #366097; } - -#qunit-tests .pass .test-actual, -#qunit-tests .pass .test-expected { color: #999999; } - -#qunit-banner.qunit-pass { background-color: #C6E746; } - -/*** Failing Styles */ - -#qunit-tests li li.fail { - color: #710909; - background-color: #fff; - border-left: 10px solid #EE5757; - white-space: pre; -} - -#qunit-tests > li:last-child { - border-radius: 0 0 5px 5px; - -moz-border-radius: 0 0 5px 5px; - -webkit-border-bottom-right-radius: 5px; - -webkit-border-bottom-left-radius: 5px; -} - -#qunit-tests .fail { color: #000000; background-color: #EE5757; } -#qunit-tests .fail .test-name, -#qunit-tests .fail .module-name { color: #000000; } - -#qunit-tests .fail .test-actual { color: #EE5757; } -#qunit-tests .fail .test-expected { color: green; } - -#qunit-banner.qunit-fail { background-color: #EE5757; } - - -/** Result */ - -#qunit-testresult { - padding: 0.5em 0.5em 0.5em 2.5em; - - color: #2b81af; - background-color: #D2E0E6; - - border-bottom: 1px solid white; -} -#qunit-testresult .module-name { - font-weight: bold; -} - -/** Fixture */ - -#qunit-fixture { - position: absolute; - top: -10000px; - left: -10000px; - width: 1000px; - height: 1000px; -} diff --git a/tests/vendor/qunit.js b/tests/vendor/qunit.js deleted file mode 100644 index 84c73907de4..00000000000 --- a/tests/vendor/qunit.js +++ /dev/null @@ -1,2212 +0,0 @@ -/** - * QUnit v1.12.0 - A JavaScript Unit Testing Framework - * - * http://qunitjs.com - * - * Copyright 2013 jQuery Foundation and other contributors - * Released under the MIT license. - * https://jquery.org/license/ - */ - -(function( window ) { - -var QUnit, - assert, - config, - onErrorFnPrev, - testId = 0, - fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), - toString = Object.prototype.toString, - hasOwn = Object.prototype.hasOwnProperty, - // Keep a local reference to Date (GH-283) - Date = window.Date, - setTimeout = window.setTimeout, - defined = { - setTimeout: typeof window.setTimeout !== "undefined", - sessionStorage: (function() { - var x = "qunit-test-string"; - try { - sessionStorage.setItem( x, x ); - sessionStorage.removeItem( x ); - return true; - } catch( e ) { - return false; - } - }()) - }, - /** - * Provides a normalized error string, correcting an issue - * with IE 7 (and prior) where Error.prototype.toString is - * not properly implemented - * - * Based on http://es5.github.com/#x15.11.4.4 - * - * @param {String|Error} error - * @return {String} error message - */ - errorString = function( error ) { - var name, message, - errorString = error.toString(); - if ( errorString.substring( 0, 7 ) === "[object" ) { - name = error.name ? error.name.toString() : "Error"; - message = error.message ? error.message.toString() : ""; - if ( name && message ) { - return name + ": " + message; - } else if ( name ) { - return name; - } else if ( message ) { - return message; - } else { - return "Error"; - } - } else { - return errorString; - } - }, - /** - * Makes a clone of an object using only Array or Object as base, - * and copies over the own enumerable properties. - * - * @param {Object} obj - * @return {Object} New object with only the own properties (recursively). - */ - objectValues = function( obj ) { - // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392. - /*jshint newcap: false */ - var key, val, - vals = QUnit.is( "array", obj ) ? [] : {}; - for ( key in obj ) { - if ( hasOwn.call( obj, key ) ) { - val = obj[key]; - vals[key] = val === Object(val) ? objectValues(val) : val; - } - } - return vals; - }; - -function Test( settings ) { - extend( this, settings ); - this.assertions = []; - this.testNumber = ++Test.count; -} - -Test.count = 0; - -Test.prototype = { - init: function() { - var a, b, li, - tests = id( "qunit-tests" ); - - if ( tests ) { - b = document.createElement( "strong" ); - b.innerHTML = this.nameHtml; - - // `a` initialized at top of scope - a = document.createElement( "a" ); - a.innerHTML = "Rerun"; - a.href = QUnit.url({ testNumber: this.testNumber }); - - li = document.createElement( "li" ); - li.appendChild( b ); - li.appendChild( a ); - li.className = "running"; - li.id = this.id = "qunit-test-output" + testId++; - - tests.appendChild( li ); - } - }, - setup: function() { - if ( - // Emit moduleStart when we're switching from one module to another - this.module !== config.previousModule || - // They could be equal (both undefined) but if the previousModule property doesn't - // yet exist it means this is the first test in a suite that isn't wrapped in a - // module, in which case we'll just emit a moduleStart event for 'undefined'. - // Without this, reporters can get testStart before moduleStart which is a problem. - !hasOwn.call( config, "previousModule" ) - ) { - if ( hasOwn.call( config, "previousModule" ) ) { - runLoggingCallbacks( "moduleDone", QUnit, { - name: config.previousModule, - failed: config.moduleStats.bad, - passed: config.moduleStats.all - config.moduleStats.bad, - total: config.moduleStats.all - }); - } - config.previousModule = this.module; - config.moduleStats = { all: 0, bad: 0 }; - runLoggingCallbacks( "moduleStart", QUnit, { - name: this.module - }); - } - - config.current = this; - - this.testEnvironment = extend({ - setup: function() {}, - teardown: function() {} - }, this.moduleTestEnvironment ); - - this.started = +new Date(); - runLoggingCallbacks( "testStart", QUnit, { - name: this.testName, - module: this.module - }); - - /*jshint camelcase:false */ - - - /** - * Expose the current test environment. - * - * @deprecated since 1.12.0: Use QUnit.config.current.testEnvironment instead. - */ - QUnit.current_testEnvironment = this.testEnvironment; - - /*jshint camelcase:true */ - - if ( !config.pollution ) { - saveGlobal(); - } - if ( config.notrycatch ) { - this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert ); - return; - } - try { - this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert ); - } catch( e ) { - QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); - } - }, - run: function() { - config.current = this; - - var running = id( "qunit-testresult" ); - - if ( running ) { - running.innerHTML = "Running:
    " + this.nameHtml; - } - - if ( this.async ) { - QUnit.stop(); - } - - this.callbackStarted = +new Date(); - - if ( config.notrycatch ) { - this.callback.call( this.testEnvironment, QUnit.assert ); - this.callbackRuntime = +new Date() - this.callbackStarted; - return; - } - - try { - this.callback.call( this.testEnvironment, QUnit.assert ); - this.callbackRuntime = +new Date() - this.callbackStarted; - } catch( e ) { - this.callbackRuntime = +new Date() - this.callbackStarted; - - QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); - // else next test will carry the responsibility - saveGlobal(); - - // Restart the tests if they're blocking - if ( config.blocking ) { - QUnit.start(); - } - } - }, - teardown: function() { - config.current = this; - if ( config.notrycatch ) { - if ( typeof this.callbackRuntime === "undefined" ) { - this.callbackRuntime = +new Date() - this.callbackStarted; - } - this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert ); - return; - } else { - try { - this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert ); - } catch( e ) { - QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); - } - } - checkPollution(); - }, - finish: function() { - config.current = this; - if ( config.requireExpects && this.expected === null ) { - QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack ); - } else if ( this.expected !== null && this.expected !== this.assertions.length ) { - QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); - } else if ( this.expected === null && !this.assertions.length ) { - QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); - } - - var i, assertion, a, b, time, li, ol, - test = this, - good = 0, - bad = 0, - tests = id( "qunit-tests" ); - - this.runtime = +new Date() - this.started; - config.stats.all += this.assertions.length; - config.moduleStats.all += this.assertions.length; - - if ( tests ) { - ol = document.createElement( "ol" ); - ol.className = "qunit-assert-list"; - - for ( i = 0; i < this.assertions.length; i++ ) { - assertion = this.assertions[i]; - - li = document.createElement( "li" ); - li.className = assertion.result ? "pass" : "fail"; - li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" ); - ol.appendChild( li ); - - if ( assertion.result ) { - good++; - } else { - bad++; - config.stats.bad++; - config.moduleStats.bad++; - } - } - - // store result when possible - if ( QUnit.config.reorder && defined.sessionStorage ) { - if ( bad ) { - sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad ); - } else { - sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName ); - } - } - - if ( bad === 0 ) { - addClass( ol, "qunit-collapsed" ); - } - - // `b` initialized at top of scope - b = document.createElement( "strong" ); - b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; - - addEvent(b, "click", function() { - var next = b.parentNode.lastChild, - collapsed = hasClass( next, "qunit-collapsed" ); - ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" ); - }); - - addEvent(b, "dblclick", function( e ) { - var target = e && e.target ? e.target : window.event.srcElement; - if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) { - target = target.parentNode; - } - if ( window.location && target.nodeName.toLowerCase() === "strong" ) { - window.location = QUnit.url({ testNumber: test.testNumber }); - } - }); - - // `time` initialized at top of scope - time = document.createElement( "span" ); - time.className = "runtime"; - time.innerHTML = this.runtime + " ms"; - - // `li` initialized at top of scope - li = id( this.id ); - li.className = bad ? "fail" : "pass"; - li.removeChild( li.firstChild ); - a = li.firstChild; - li.appendChild( b ); - li.appendChild( a ); - li.appendChild( time ); - li.appendChild( ol ); - - } else { - for ( i = 0; i < this.assertions.length; i++ ) { - if ( !this.assertions[i].result ) { - bad++; - config.stats.bad++; - config.moduleStats.bad++; - } - } - } - - runLoggingCallbacks( "testDone", QUnit, { - name: this.testName, - module: this.module, - failed: bad, - passed: this.assertions.length - bad, - total: this.assertions.length, - duration: this.runtime - }); - - QUnit.reset(); - - config.current = undefined; - }, - - queue: function() { - var bad, - test = this; - - synchronize(function() { - test.init(); - }); - function run() { - // each of these can by async - synchronize(function() { - test.setup(); - }); - synchronize(function() { - test.run(); - }); - synchronize(function() { - test.teardown(); - }); - synchronize(function() { - test.finish(); - }); - } - - // `bad` initialized at top of scope - // defer when previous test run passed, if storage is available - bad = QUnit.config.reorder && defined.sessionStorage && - +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); - - if ( bad ) { - run(); - } else { - synchronize( run, true ); - } - } -}; - -// Root QUnit object. -// `QUnit` initialized at top of scope -QUnit = { - - // call on start of module test to prepend name to all tests - module: function( name, testEnvironment ) { - config.currentModule = name; - config.currentModuleTestEnvironment = testEnvironment; - config.modules[name] = true; - }, - - asyncTest: function( testName, expected, callback ) { - if ( arguments.length === 2 ) { - callback = expected; - expected = null; - } - - QUnit.test( testName, expected, callback, true ); - }, - - test: function( testName, expected, callback, async ) { - var test, - nameHtml = "" + escapeText( testName ) + ""; - - if ( arguments.length === 2 ) { - callback = expected; - expected = null; - } - - if ( config.currentModule ) { - nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml; - } - - test = new Test({ - nameHtml: nameHtml, - testName: testName, - expected: expected, - async: async, - callback: callback, - module: config.currentModule, - moduleTestEnvironment: config.currentModuleTestEnvironment, - stack: sourceFromStacktrace( 2 ) - }); - - if ( !validTest( test ) ) { - return; - } - - test.queue(); - }, - - // Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through. - expect: function( asserts ) { - if (arguments.length === 1) { - config.current.expected = asserts; - } else { - return config.current.expected; - } - }, - - start: function( count ) { - // QUnit hasn't been initialized yet. - // Note: RequireJS (et al) may delay onLoad - if ( config.semaphore === undefined ) { - QUnit.begin(function() { - // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first - setTimeout(function() { - QUnit.start( count ); - }); - }); - return; - } - - config.semaphore -= count || 1; - // don't start until equal number of stop-calls - if ( config.semaphore > 0 ) { - return; - } - // ignore if start is called more often then stop - if ( config.semaphore < 0 ) { - config.semaphore = 0; - QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) ); - return; - } - // A slight delay, to avoid any current callbacks - if ( defined.setTimeout ) { - setTimeout(function() { - if ( config.semaphore > 0 ) { - return; - } - if ( config.timeout ) { - clearTimeout( config.timeout ); - } - - config.blocking = false; - process( true ); - }, 13); - } else { - config.blocking = false; - process( true ); - } - }, - - stop: function( count ) { - config.semaphore += count || 1; - config.blocking = true; - - if ( config.testTimeout && defined.setTimeout ) { - clearTimeout( config.timeout ); - config.timeout = setTimeout(function() { - QUnit.ok( false, "Test timed out" ); - config.semaphore = 1; - QUnit.start(); - }, config.testTimeout ); - } - } -}; - -// `assert` initialized at top of scope -// Assert helpers -// All of these must either call QUnit.push() or manually do: -// - runLoggingCallbacks( "log", .. ); -// - config.current.assertions.push({ .. }); -// We attach it to the QUnit object *after* we expose the public API, -// otherwise `assert` will become a global variable in browsers (#341). -assert = { - /** - * Asserts rough true-ish result. - * @name ok - * @function - * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); - */ - ok: function( result, msg ) { - if ( !config.current ) { - throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); - } - result = !!result; - msg = msg || (result ? "okay" : "failed" ); - - var source, - details = { - module: config.current.module, - name: config.current.testName, - result: result, - message: msg - }; - - msg = "" + escapeText( msg ) + ""; - - if ( !result ) { - source = sourceFromStacktrace( 2 ); - if ( source ) { - details.source = source; - msg += "
    Source:
    " + escapeText( source ) + "
    "; - } - } - runLoggingCallbacks( "log", QUnit, details ); - config.current.assertions.push({ - result: result, - message: msg - }); - }, - - /** - * Assert that the first two arguments are equal, with an optional message. - * Prints out both actual and expected values. - * @name equal - * @function - * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); - */ - equal: function( actual, expected, message ) { - /*jshint eqeqeq:false */ - QUnit.push( expected == actual, actual, expected, message ); - }, - - /** - * @name notEqual - * @function - */ - notEqual: function( actual, expected, message ) { - /*jshint eqeqeq:false */ - QUnit.push( expected != actual, actual, expected, message ); - }, - - /** - * @name propEqual - * @function - */ - propEqual: function( actual, expected, message ) { - actual = objectValues(actual); - expected = objectValues(expected); - QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); - }, - - /** - * @name notPropEqual - * @function - */ - notPropEqual: function( actual, expected, message ) { - actual = objectValues(actual); - expected = objectValues(expected); - QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); - }, - - /** - * @name deepEqual - * @function - */ - deepEqual: function( actual, expected, message ) { - QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); - }, - - /** - * @name notDeepEqual - * @function - */ - notDeepEqual: function( actual, expected, message ) { - QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); - }, - - /** - * @name strictEqual - * @function - */ - strictEqual: function( actual, expected, message ) { - QUnit.push( expected === actual, actual, expected, message ); - }, - - /** - * @name notStrictEqual - * @function - */ - notStrictEqual: function( actual, expected, message ) { - QUnit.push( expected !== actual, actual, expected, message ); - }, - - "throws": function( block, expected, message ) { - var actual, - expectedOutput = expected, - ok = false; - - // 'expected' is optional - if ( typeof expected === "string" ) { - message = expected; - expected = null; - } - - config.current.ignoreGlobalErrors = true; - try { - block.call( config.current.testEnvironment ); - } catch (e) { - actual = e; - } - config.current.ignoreGlobalErrors = false; - - if ( actual ) { - // we don't want to validate thrown error - if ( !expected ) { - ok = true; - expectedOutput = null; - // expected is a regexp - } else if ( QUnit.objectType( expected ) === "regexp" ) { - ok = expected.test( errorString( actual ) ); - // expected is a constructor - } else if ( actual instanceof expected ) { - ok = true; - // expected is a validation function which returns true is validation passed - } else if ( expected.call( {}, actual ) === true ) { - expectedOutput = null; - ok = true; - } - - QUnit.push( ok, actual, expectedOutput, message ); - } else { - QUnit.pushFailure( message, null, "No exception was thrown." ); - } - } -}; - -/** - * @deprecated since 1.8.0 - * Kept assertion helpers in root for backwards compatibility. - */ -extend( QUnit, assert ); - -/** - * @deprecated since 1.9.0 - * Kept root "raises()" for backwards compatibility. - * (Note that we don't introduce assert.raises). - */ -QUnit.raises = assert[ "throws" ]; - -/** - * @deprecated since 1.0.0, replaced with error pushes since 1.3.0 - * Kept to avoid TypeErrors for undefined methods. - */ -QUnit.equals = function() { - QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); -}; -QUnit.same = function() { - QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); -}; - -// We want access to the constructor's prototype -(function() { - function F() {} - F.prototype = QUnit; - QUnit = new F(); - // Make F QUnit's constructor so that we can add to the prototype later - QUnit.constructor = F; -}()); - -/** - * Config object: Maintain internal state - * Later exposed as QUnit.config - * `config` initialized at top of scope - */ -config = { - // The queue of tests to run - queue: [], - - // block until document ready - blocking: true, - - // when enabled, show only failing tests - // gets persisted through sessionStorage and can be changed in UI via checkbox - hidepassed: false, - - // by default, run previously failed tests first - // very useful in combination with "Hide passed tests" checked - reorder: true, - - // by default, modify document.title when suite is done - altertitle: true, - - // when enabled, all tests must call expect() - requireExpects: false, - - // add checkboxes that are persisted in the query-string - // when enabled, the id is set to `true` as a `QUnit.config` property - urlConfig: [ - { - id: "noglobals", - label: "Check for Globals", - tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." - }, - { - id: "notrycatch", - label: "No try-catch", - tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." - } - ], - - // Set of all modules. - modules: {}, - - // logging callback queues - begin: [], - done: [], - log: [], - testStart: [], - testDone: [], - moduleStart: [], - moduleDone: [] -}; - -// Export global variables, unless an 'exports' object exists, -// in that case we assume we're in CommonJS (dealt with on the bottom of the script) -if ( typeof exports === "undefined" ) { - extend( window, QUnit.constructor.prototype ); - - // Expose QUnit object - window.QUnit = QUnit; -} - -// Initialize more QUnit.config and QUnit.urlParams -(function() { - var i, - location = window.location || { search: "", protocol: "file:" }, - params = location.search.slice( 1 ).split( "&" ), - length = params.length, - urlParams = {}, - current; - - if ( params[ 0 ] ) { - for ( i = 0; i < length; i++ ) { - current = params[ i ].split( "=" ); - current[ 0 ] = decodeURIComponent( current[ 0 ] ); - // allow just a key to turn on a flag, e.g., test.html?noglobals - current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; - urlParams[ current[ 0 ] ] = current[ 1 ]; - } - } - - QUnit.urlParams = urlParams; - - // String search anywhere in moduleName+testName - config.filter = urlParams.filter; - - // Exact match of the module name - config.module = urlParams.module; - - config.testNumber = parseInt( urlParams.testNumber, 10 ) || null; - - // Figure out if we're running the tests from a server or not - QUnit.isLocal = location.protocol === "file:"; -}()); - -// Extend QUnit object, -// these after set here because they should not be exposed as global functions -extend( QUnit, { - assert: assert, - - config: config, - - // Initialize the configuration options - init: function() { - extend( config, { - stats: { all: 0, bad: 0 }, - moduleStats: { all: 0, bad: 0 }, - started: +new Date(), - updateRate: 1000, - blocking: false, - autostart: true, - autorun: false, - filter: "", - queue: [], - semaphore: 1 - }); - - var tests, banner, result, - qunit = id( "qunit" ); - - if ( qunit ) { - qunit.innerHTML = - "

    " + escapeText( document.title ) + "

    " + - "

    " + - "
    " + - "

    " + - "
      "; - } - - tests = id( "qunit-tests" ); - banner = id( "qunit-banner" ); - result = id( "qunit-testresult" ); - - if ( tests ) { - tests.innerHTML = ""; - } - - if ( banner ) { - banner.className = ""; - } - - if ( result ) { - result.parentNode.removeChild( result ); - } - - if ( tests ) { - result = document.createElement( "p" ); - result.id = "qunit-testresult"; - result.className = "result"; - tests.parentNode.insertBefore( result, tests ); - result.innerHTML = "Running...
       "; - } - }, - - // Resets the test setup. Useful for tests that modify the DOM. - /* - DEPRECATED: Use multiple tests instead of resetting inside a test. - Use testStart or testDone for custom cleanup. - This method will throw an error in 2.0, and will be removed in 2.1 - */ - reset: function() { - var fixture = id( "qunit-fixture" ); - if ( fixture ) { - fixture.innerHTML = config.fixture; - } - }, - - // Trigger an event on an element. - // @example triggerEvent( document.body, "click" ); - triggerEvent: function( elem, type, event ) { - if ( document.createEvent ) { - event = document.createEvent( "MouseEvents" ); - event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, - 0, 0, 0, 0, 0, false, false, false, false, 0, null); - - elem.dispatchEvent( event ); - } else if ( elem.fireEvent ) { - elem.fireEvent( "on" + type ); - } - }, - - // Safe object type checking - is: function( type, obj ) { - return QUnit.objectType( obj ) === type; - }, - - objectType: function( obj ) { - if ( typeof obj === "undefined" ) { - return "undefined"; - // consider: typeof null === object - } - if ( obj === null ) { - return "null"; - } - - var match = toString.call( obj ).match(/^\[object\s(.*)\]$/), - type = match && match[1] || ""; - - switch ( type ) { - case "Number": - if ( isNaN(obj) ) { - return "nan"; - } - return "number"; - case "String": - case "Boolean": - case "Array": - case "Date": - case "RegExp": - case "Function": - return type.toLowerCase(); - } - if ( typeof obj === "object" ) { - return "object"; - } - return undefined; - }, - - push: function( result, actual, expected, message ) { - if ( !config.current ) { - throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); - } - - var output, source, - details = { - module: config.current.module, - name: config.current.testName, - result: result, - message: message, - actual: actual, - expected: expected - }; - - message = escapeText( message ) || ( result ? "okay" : "failed" ); - message = "" + message + ""; - output = message; - - if ( !result ) { - expected = escapeText( QUnit.jsDump.parse(expected) ); - actual = escapeText( QUnit.jsDump.parse(actual) ); - output += ""; - - if ( actual !== expected ) { - output += ""; - output += ""; - } - - source = sourceFromStacktrace(); - - if ( source ) { - details.source = source; - output += ""; - } - - output += "
      Expected:
      " + expected + "
      Result:
      " + actual + "
      Diff:
      " + QUnit.diff( expected, actual ) + "
      Source:
      " + escapeText( source ) + "
      "; - } - - runLoggingCallbacks( "log", QUnit, details ); - - config.current.assertions.push({ - result: !!result, - message: output - }); - }, - - pushFailure: function( message, source, actual ) { - if ( !config.current ) { - throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); - } - - var output, - details = { - module: config.current.module, - name: config.current.testName, - result: false, - message: message - }; - - message = escapeText( message ) || "error"; - message = "" + message + ""; - output = message; - - output += ""; - - if ( actual ) { - output += ""; - } - - if ( source ) { - details.source = source; - output += ""; - } - - output += "
      Result:
      " + escapeText( actual ) + "
      Source:
      " + escapeText( source ) + "
      "; - - runLoggingCallbacks( "log", QUnit, details ); - - config.current.assertions.push({ - result: false, - message: output - }); - }, - - url: function( params ) { - params = extend( extend( {}, QUnit.urlParams ), params ); - var key, - querystring = "?"; - - for ( key in params ) { - if ( hasOwn.call( params, key ) ) { - querystring += encodeURIComponent( key ) + "=" + - encodeURIComponent( params[ key ] ) + "&"; - } - } - return window.location.protocol + "//" + window.location.host + - window.location.pathname + querystring.slice( 0, -1 ); - }, - - extend: extend, - id: id, - addEvent: addEvent, - addClass: addClass, - hasClass: hasClass, - removeClass: removeClass - // load, equiv, jsDump, diff: Attached later -}); - -/** - * @deprecated: Created for backwards compatibility with test runner that set the hook function - * into QUnit.{hook}, instead of invoking it and passing the hook function. - * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. - * Doing this allows us to tell if the following methods have been overwritten on the actual - * QUnit object. - */ -extend( QUnit.constructor.prototype, { - - // Logging callbacks; all receive a single argument with the listed properties - // run test/logs.html for any related changes - begin: registerLoggingCallback( "begin" ), - - // done: { failed, passed, total, runtime } - done: registerLoggingCallback( "done" ), - - // log: { result, actual, expected, message } - log: registerLoggingCallback( "log" ), - - // testStart: { name } - testStart: registerLoggingCallback( "testStart" ), - - // testDone: { name, failed, passed, total, duration } - testDone: registerLoggingCallback( "testDone" ), - - // moduleStart: { name } - moduleStart: registerLoggingCallback( "moduleStart" ), - - // moduleDone: { name, failed, passed, total } - moduleDone: registerLoggingCallback( "moduleDone" ) -}); - -if ( typeof document === "undefined" || document.readyState === "complete" ) { - config.autorun = true; -} - -QUnit.load = function() { - runLoggingCallbacks( "begin", QUnit, {} ); - - // Initialize the config, saving the execution queue - var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, - urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter, - numModules = 0, - moduleNames = [], - moduleFilterHtml = "", - urlConfigHtml = "", - oldconfig = extend( {}, config ); - - QUnit.init(); - extend(config, oldconfig); - - config.blocking = false; - - len = config.urlConfig.length; - - for ( i = 0; i < len; i++ ) { - val = config.urlConfig[i]; - if ( typeof val === "string" ) { - val = { - id: val, - label: val, - tooltip: "[no tooltip available]" - }; - } - config[ val.id ] = QUnit.urlParams[ val.id ]; - urlConfigHtml += ""; - } - for ( i in config.modules ) { - if ( config.modules.hasOwnProperty( i ) ) { - moduleNames.push(i); - } - } - numModules = moduleNames.length; - moduleNames.sort( function( a, b ) { - return a.localeCompare( b ); - }); - moduleFilterHtml += ""; - - // `userAgent` initialized at top of scope - userAgent = id( "qunit-userAgent" ); - if ( userAgent ) { - userAgent.innerHTML = navigator.userAgent; - } - - // `banner` initialized at top of scope - banner = id( "qunit-header" ); - if ( banner ) { - banner.innerHTML = "" + banner.innerHTML + " "; - } - - // `toolbar` initialized at top of scope - toolbar = id( "qunit-testrunner-toolbar" ); - if ( toolbar ) { - // `filter` initialized at top of scope - filter = document.createElement( "input" ); - filter.type = "checkbox"; - filter.id = "qunit-filter-pass"; - - addEvent( filter, "click", function() { - var tmp, - ol = document.getElementById( "qunit-tests" ); - - if ( filter.checked ) { - ol.className = ol.className + " hidepass"; - } else { - tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; - ol.className = tmp.replace( / hidepass /, " " ); - } - if ( defined.sessionStorage ) { - if (filter.checked) { - sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); - } else { - sessionStorage.removeItem( "qunit-filter-passed-tests" ); - } - } - }); - - if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { - filter.checked = true; - // `ol` initialized at top of scope - ol = document.getElementById( "qunit-tests" ); - ol.className = ol.className + " hidepass"; - } - toolbar.appendChild( filter ); - - // `label` initialized at top of scope - label = document.createElement( "label" ); - label.setAttribute( "for", "qunit-filter-pass" ); - label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." ); - label.innerHTML = "Hide passed tests"; - toolbar.appendChild( label ); - - urlConfigCheckboxesContainer = document.createElement("span"); - urlConfigCheckboxesContainer.innerHTML = urlConfigHtml; - urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input"); - // For oldIE support: - // * Add handlers to the individual elements instead of the container - // * Use "click" instead of "change" - // * Fallback from event.target to event.srcElement - addEvents( urlConfigCheckboxes, "click", function( event ) { - var params = {}, - target = event.target || event.srcElement; - params[ target.name ] = target.checked ? true : undefined; - window.location = QUnit.url( params ); - }); - toolbar.appendChild( urlConfigCheckboxesContainer ); - - if (numModules > 1) { - moduleFilter = document.createElement( "span" ); - moduleFilter.setAttribute( "id", "qunit-modulefilter-container" ); - moduleFilter.innerHTML = moduleFilterHtml; - addEvent( moduleFilter.lastChild, "change", function() { - var selectBox = moduleFilter.getElementsByTagName("select")[0], - selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value); - - window.location = QUnit.url({ - module: ( selectedModule === "" ) ? undefined : selectedModule, - // Remove any existing filters - filter: undefined, - testNumber: undefined - }); - }); - toolbar.appendChild(moduleFilter); - } - } - - // `main` initialized at top of scope - main = id( "qunit-fixture" ); - if ( main ) { - config.fixture = main.innerHTML; - } - - if ( config.autostart ) { - QUnit.start(); - } -}; - -addEvent( window, "load", QUnit.load ); - -// `onErrorFnPrev` initialized at top of scope -// Preserve other handlers -onErrorFnPrev = window.onerror; - -// Cover uncaught exceptions -// Returning true will suppress the default browser handler, -// returning false will let it run. -window.onerror = function ( error, filePath, linerNr ) { - var ret = false; - if ( onErrorFnPrev ) { - ret = onErrorFnPrev( error, filePath, linerNr ); - } - - // Treat return value as window.onerror itself does, - // Only do our handling if not suppressed. - if ( ret !== true ) { - if ( QUnit.config.current ) { - if ( QUnit.config.current.ignoreGlobalErrors ) { - return true; - } - QUnit.pushFailure( error, filePath + ":" + linerNr ); - } else { - QUnit.test( "global failure", extend( function() { - QUnit.pushFailure( error, filePath + ":" + linerNr ); - }, { validTest: validTest } ) ); - } - return false; - } - - return ret; -}; - -function done() { - config.autorun = true; - - // Log the last module results - if ( config.currentModule ) { - runLoggingCallbacks( "moduleDone", QUnit, { - name: config.currentModule, - failed: config.moduleStats.bad, - passed: config.moduleStats.all - config.moduleStats.bad, - total: config.moduleStats.all - }); - } - delete config.previousModule; - - var i, key, - banner = id( "qunit-banner" ), - tests = id( "qunit-tests" ), - runtime = +new Date() - config.started, - passed = config.stats.all - config.stats.bad, - html = [ - "Tests completed in ", - runtime, - " milliseconds.
      ", - "", - passed, - " assertions of ", - config.stats.all, - " passed, ", - config.stats.bad, - " failed." - ].join( "" ); - - if ( banner ) { - banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); - } - - if ( tests ) { - id( "qunit-testresult" ).innerHTML = html; - } - - if ( config.altertitle && typeof document !== "undefined" && document.title ) { - // show ✖ for good, ✔ for bad suite result in title - // use escape sequences in case file gets loaded with non-utf-8-charset - document.title = [ - ( config.stats.bad ? "\u2716" : "\u2714" ), - document.title.replace( /^[\u2714\u2716] /i, "" ) - ].join( " " ); - } - - // clear own sessionStorage items if all tests passed - if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { - // `key` & `i` initialized at top of scope - for ( i = 0; i < sessionStorage.length; i++ ) { - key = sessionStorage.key( i++ ); - if ( key.indexOf( "qunit-test-" ) === 0 ) { - sessionStorage.removeItem( key ); - } - } - } - - // scroll back to top to show results - if ( window.scrollTo ) { - window.scrollTo(0, 0); - } - - runLoggingCallbacks( "done", QUnit, { - failed: config.stats.bad, - passed: passed, - total: config.stats.all, - runtime: runtime - }); -} - -/** @return Boolean: true if this test should be ran */ -function validTest( test ) { - var include, - filter = config.filter && config.filter.toLowerCase(), - module = config.module && config.module.toLowerCase(), - fullName = (test.module + ": " + test.testName).toLowerCase(); - - // Internally-generated tests are always valid - if ( test.callback && test.callback.validTest === validTest ) { - delete test.callback.validTest; - return true; - } - - if ( config.testNumber ) { - return test.testNumber === config.testNumber; - } - - if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) { - return false; - } - - if ( !filter ) { - return true; - } - - include = filter.charAt( 0 ) !== "!"; - if ( !include ) { - filter = filter.slice( 1 ); - } - - // If the filter matches, we need to honour include - if ( fullName.indexOf( filter ) !== -1 ) { - return include; - } - - // Otherwise, do the opposite - return !include; -} - -// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) -// Later Safari and IE10 are supposed to support error.stack as well -// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack -function extractStacktrace( e, offset ) { - offset = offset === undefined ? 3 : offset; - - var stack, include, i; - - if ( e.stacktrace ) { - // Opera - return e.stacktrace.split( "\n" )[ offset + 3 ]; - } else if ( e.stack ) { - // Firefox, Chrome - stack = e.stack.split( "\n" ); - if (/^error$/i.test( stack[0] ) ) { - stack.shift(); - } - if ( fileName ) { - include = []; - for ( i = offset; i < stack.length; i++ ) { - if ( stack[ i ].indexOf( fileName ) !== -1 ) { - break; - } - include.push( stack[ i ] ); - } - if ( include.length ) { - return include.join( "\n" ); - } - } - return stack[ offset ]; - } else if ( e.sourceURL ) { - // Safari, PhantomJS - // hopefully one day Safari provides actual stacktraces - // exclude useless self-reference for generated Error objects - if ( /qunit.js$/.test( e.sourceURL ) ) { - return; - } - // for actual exceptions, this is useful - return e.sourceURL + ":" + e.line; - } -} -function sourceFromStacktrace( offset ) { - try { - throw new Error(); - } catch ( e ) { - return extractStacktrace( e, offset ); - } -} - -/** - * Escape text for attribute or text content. - */ -function escapeText( s ) { - if ( !s ) { - return ""; - } - s = s + ""; - // Both single quotes and double quotes (for attributes) - return s.replace( /['"<>&]/g, function( s ) { - switch( s ) { - case "'": - return "'"; - case "\"": - return """; - case "<": - return "<"; - case ">": - return ">"; - case "&": - return "&"; - } - }); -} - -function synchronize( callback, last ) { - config.queue.push( callback ); - - if ( config.autorun && !config.blocking ) { - process( last ); - } -} - -function process( last ) { - function next() { - process( last ); - } - var start = new Date().getTime(); - config.depth = config.depth ? config.depth + 1 : 1; - - while ( config.queue.length && !config.blocking ) { - if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { - config.queue.shift()(); - } else { - setTimeout( next, 13 ); - break; - } - } - config.depth--; - if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { - done(); - } -} - -function saveGlobal() { - config.pollution = []; - - if ( config.noglobals ) { - for ( var key in window ) { - if ( hasOwn.call( window, key ) ) { - // in Opera sometimes DOM element ids show up here, ignore them - if ( /^qunit-test-output/.test( key ) ) { - continue; - } - config.pollution.push( key ); - } - } - } -} - -function checkPollution() { - var newGlobals, - deletedGlobals, - old = config.pollution; - - saveGlobal(); - - newGlobals = diff( config.pollution, old ); - if ( newGlobals.length > 0 ) { - QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); - } - - deletedGlobals = diff( old, config.pollution ); - if ( deletedGlobals.length > 0 ) { - QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); - } -} - -// returns a new Array with the elements that are in a but not in b -function diff( a, b ) { - var i, j, - result = a.slice(); - - for ( i = 0; i < result.length; i++ ) { - for ( j = 0; j < b.length; j++ ) { - if ( result[i] === b[j] ) { - result.splice( i, 1 ); - i--; - break; - } - } - } - return result; -} - -function extend( a, b ) { - for ( var prop in b ) { - if ( hasOwn.call( b, prop ) ) { - // Avoid "Member not found" error in IE8 caused by messing with window.constructor - if ( !( prop === "constructor" && a === window ) ) { - if ( b[ prop ] === undefined ) { - delete a[ prop ]; - } else { - a[ prop ] = b[ prop ]; - } - } - } - } - - return a; -} - -/** - * @param {HTMLElement} elem - * @param {string} type - * @param {Function} fn - */ -function addEvent( elem, type, fn ) { - // Standards-based browsers - if ( elem.addEventListener ) { - elem.addEventListener( type, fn, false ); - // IE - } else { - elem.attachEvent( "on" + type, fn ); - } -} - -/** - * @param {Array|NodeList} elems - * @param {string} type - * @param {Function} fn - */ -function addEvents( elems, type, fn ) { - var i = elems.length; - while ( i-- ) { - addEvent( elems[i], type, fn ); - } -} - -function hasClass( elem, name ) { - return (" " + elem.className + " ").indexOf(" " + name + " ") > -1; -} - -function addClass( elem, name ) { - if ( !hasClass( elem, name ) ) { - elem.className += (elem.className ? " " : "") + name; - } -} - -function removeClass( elem, name ) { - var set = " " + elem.className + " "; - // Class name may appear multiple times - while ( set.indexOf(" " + name + " ") > -1 ) { - set = set.replace(" " + name + " " , " "); - } - // If possible, trim it for prettiness, but not necessarily - elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, ""); -} - -function id( name ) { - return !!( typeof document !== "undefined" && document && document.getElementById ) && - document.getElementById( name ); -} - -function registerLoggingCallback( key ) { - return function( callback ) { - config[key].push( callback ); - }; -} - -// Supports deprecated method of completely overwriting logging callbacks -function runLoggingCallbacks( key, scope, args ) { - var i, callbacks; - if ( QUnit.hasOwnProperty( key ) ) { - QUnit[ key ].call(scope, args ); - } else { - callbacks = config[ key ]; - for ( i = 0; i < callbacks.length; i++ ) { - callbacks[ i ].call( scope, args ); - } - } -} - -// Test for equality any JavaScript type. -// Author: Philippe Rathé -QUnit.equiv = (function() { - - // Call the o related callback with the given arguments. - function bindCallbacks( o, callbacks, args ) { - var prop = QUnit.objectType( o ); - if ( prop ) { - if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { - return callbacks[ prop ].apply( callbacks, args ); - } else { - return callbacks[ prop ]; // or undefined - } - } - } - - // the real equiv function - var innerEquiv, - // stack to decide between skip/abort functions - callers = [], - // stack to avoiding loops from circular referencing - parents = [], - parentsB = [], - - getProto = Object.getPrototypeOf || function ( obj ) { - /*jshint camelcase:false */ - return obj.__proto__; - }, - callbacks = (function () { - - // for string, boolean, number and null - function useStrictEquality( b, a ) { - /*jshint eqeqeq:false */ - if ( b instanceof a.constructor || a instanceof b.constructor ) { - // to catch short annotation VS 'new' annotation of a - // declaration - // e.g. var i = 1; - // var j = new Number(1); - return a == b; - } else { - return a === b; - } - } - - return { - "string": useStrictEquality, - "boolean": useStrictEquality, - "number": useStrictEquality, - "null": useStrictEquality, - "undefined": useStrictEquality, - - "nan": function( b ) { - return isNaN( b ); - }, - - "date": function( b, a ) { - return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); - }, - - "regexp": function( b, a ) { - return QUnit.objectType( b ) === "regexp" && - // the regex itself - a.source === b.source && - // and its modifiers - a.global === b.global && - // (gmi) ... - a.ignoreCase === b.ignoreCase && - a.multiline === b.multiline && - a.sticky === b.sticky; - }, - - // - skip when the property is a method of an instance (OOP) - // - abort otherwise, - // initial === would have catch identical references anyway - "function": function() { - var caller = callers[callers.length - 1]; - return caller !== Object && typeof caller !== "undefined"; - }, - - "array": function( b, a ) { - var i, j, len, loop, aCircular, bCircular; - - // b could be an object literal here - if ( QUnit.objectType( b ) !== "array" ) { - return false; - } - - len = a.length; - if ( len !== b.length ) { - // safe and faster - return false; - } - - // track reference to avoid circular references - parents.push( a ); - parentsB.push( b ); - for ( i = 0; i < len; i++ ) { - loop = false; - for ( j = 0; j < parents.length; j++ ) { - aCircular = parents[j] === a[i]; - bCircular = parentsB[j] === b[i]; - if ( aCircular || bCircular ) { - if ( a[i] === b[i] || aCircular && bCircular ) { - loop = true; - } else { - parents.pop(); - parentsB.pop(); - return false; - } - } - } - if ( !loop && !innerEquiv(a[i], b[i]) ) { - parents.pop(); - parentsB.pop(); - return false; - } - } - parents.pop(); - parentsB.pop(); - return true; - }, - - "object": function( b, a ) { - /*jshint forin:false */ - var i, j, loop, aCircular, bCircular, - // Default to true - eq = true, - aProperties = [], - bProperties = []; - - // comparing constructors is more strict than using - // instanceof - if ( a.constructor !== b.constructor ) { - // Allow objects with no prototype to be equivalent to - // objects with Object as their constructor. - if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || - ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { - return false; - } - } - - // stack constructor before traversing properties - callers.push( a.constructor ); - - // track reference to avoid circular references - parents.push( a ); - parentsB.push( b ); - - // be strict: don't ensure hasOwnProperty and go deep - for ( i in a ) { - loop = false; - for ( j = 0; j < parents.length; j++ ) { - aCircular = parents[j] === a[i]; - bCircular = parentsB[j] === b[i]; - if ( aCircular || bCircular ) { - if ( a[i] === b[i] || aCircular && bCircular ) { - loop = true; - } else { - eq = false; - break; - } - } - } - aProperties.push(i); - if ( !loop && !innerEquiv(a[i], b[i]) ) { - eq = false; - break; - } - } - - parents.pop(); - parentsB.pop(); - callers.pop(); // unstack, we are done - - for ( i in b ) { - bProperties.push( i ); // collect b's properties - } - - // Ensures identical properties name - return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); - } - }; - }()); - - innerEquiv = function() { // can take multiple arguments - var args = [].slice.apply( arguments ); - if ( args.length < 2 ) { - return true; // end transition - } - - return (function( a, b ) { - if ( a === b ) { - return true; // catch the most you can - } else if ( a === null || b === null || typeof a === "undefined" || - typeof b === "undefined" || - QUnit.objectType(a) !== QUnit.objectType(b) ) { - return false; // don't lose time with error prone cases - } else { - return bindCallbacks(a, callbacks, [ b, a ]); - } - - // apply transition with (1..n) arguments - }( args[0], args[1] ) && innerEquiv.apply( this, args.splice(1, args.length - 1 )) ); - }; - - return innerEquiv; -}()); - -/** - * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | - * http://flesler.blogspot.com Licensed under BSD - * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 - * - * @projectDescription Advanced and extensible data dumping for Javascript. - * @version 1.0.0 - * @author Ariel Flesler - * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} - */ -QUnit.jsDump = (function() { - function quote( str ) { - return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\""; - } - function literal( o ) { - return o + ""; - } - function join( pre, arr, post ) { - var s = jsDump.separator(), - base = jsDump.indent(), - inner = jsDump.indent(1); - if ( arr.join ) { - arr = arr.join( "," + s + inner ); - } - if ( !arr ) { - return pre + post; - } - return [ pre, inner + arr, base + post ].join(s); - } - function array( arr, stack ) { - var i = arr.length, ret = new Array(i); - this.up(); - while ( i-- ) { - ret[i] = this.parse( arr[i] , undefined , stack); - } - this.down(); - return join( "[", ret, "]" ); - } - - var reName = /^function (\w+)/, - jsDump = { - // type is used mostly internally, you can fix a (custom)type in advance - parse: function( obj, type, stack ) { - stack = stack || [ ]; - var inStack, res, - parser = this.parsers[ type || this.typeOf(obj) ]; - - type = typeof parser; - inStack = inArray( obj, stack ); - - if ( inStack !== -1 ) { - return "recursion(" + (inStack - stack.length) + ")"; - } - if ( type === "function" ) { - stack.push( obj ); - res = parser.call( this, obj, stack ); - stack.pop(); - return res; - } - return ( type === "string" ) ? parser : this.parsers.error; - }, - typeOf: function( obj ) { - var type; - if ( obj === null ) { - type = "null"; - } else if ( typeof obj === "undefined" ) { - type = "undefined"; - } else if ( QUnit.is( "regexp", obj) ) { - type = "regexp"; - } else if ( QUnit.is( "date", obj) ) { - type = "date"; - } else if ( QUnit.is( "function", obj) ) { - type = "function"; - } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { - type = "window"; - } else if ( obj.nodeType === 9 ) { - type = "document"; - } else if ( obj.nodeType ) { - type = "node"; - } else if ( - // native arrays - toString.call( obj ) === "[object Array]" || - // NodeList objects - ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) - ) { - type = "array"; - } else if ( obj.constructor === Error.prototype.constructor ) { - type = "error"; - } else { - type = typeof obj; - } - return type; - }, - separator: function() { - return this.multiline ? this.HTML ? "
      " : "\n" : this.HTML ? " " : " "; - }, - // extra can be a number, shortcut for increasing-calling-decreasing - indent: function( extra ) { - if ( !this.multiline ) { - return ""; - } - var chr = this.indentChar; - if ( this.HTML ) { - chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); - } - return new Array( this.depth + ( extra || 0 ) ).join(chr); - }, - up: function( a ) { - this.depth += a || 1; - }, - down: function( a ) { - this.depth -= a || 1; - }, - setParser: function( name, parser ) { - this.parsers[name] = parser; - }, - // The next 3 are exposed so you can use them - quote: quote, - literal: literal, - join: join, - // - depth: 1, - // This is the list of parsers, to modify them, use jsDump.setParser - parsers: { - window: "[Window]", - document: "[Document]", - error: function(error) { - return "Error(\"" + error.message + "\")"; - }, - unknown: "[Unknown]", - "null": "null", - "undefined": "undefined", - "function": function( fn ) { - var ret = "function", - // functions never have name in IE - name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1]; - - if ( name ) { - ret += " " + name; - } - ret += "( "; - - ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" ); - return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" ); - }, - array: array, - nodelist: array, - "arguments": array, - object: function( map, stack ) { - /*jshint forin:false */ - var ret = [ ], keys, key, val, i; - QUnit.jsDump.up(); - keys = []; - for ( key in map ) { - keys.push( key ); - } - keys.sort(); - for ( i = 0; i < keys.length; i++ ) { - key = keys[ i ]; - val = map[ key ]; - ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); - } - QUnit.jsDump.down(); - return join( "{", ret, "}" ); - }, - node: function( node ) { - var len, i, val, - open = QUnit.jsDump.HTML ? "<" : "<", - close = QUnit.jsDump.HTML ? ">" : ">", - tag = node.nodeName.toLowerCase(), - ret = open + tag, - attrs = node.attributes; - - if ( attrs ) { - for ( i = 0, len = attrs.length; i < len; i++ ) { - val = attrs[i].nodeValue; - // IE6 includes all attributes in .attributes, even ones not explicitly set. - // Those have values like undefined, null, 0, false, "" or "inherit". - if ( val && val !== "inherit" ) { - ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" ); - } - } - } - ret += close; - - // Show content of TextNode or CDATASection - if ( node.nodeType === 3 || node.nodeType === 4 ) { - ret += node.nodeValue; - } - - return ret + open + "/" + tag + close; - }, - // function calls it internally, it's the arguments part of the function - functionArgs: function( fn ) { - var args, - l = fn.length; - - if ( !l ) { - return ""; - } - - args = new Array(l); - while ( l-- ) { - // 97 is 'a' - args[l] = String.fromCharCode(97+l); - } - return " " + args.join( ", " ) + " "; - }, - // object calls it internally, the key part of an item in a map - key: quote, - // function calls it internally, it's the content of the function - functionCode: "[code]", - // node calls it internally, it's an html attribute value - attribute: quote, - string: quote, - date: quote, - regexp: literal, - number: literal, - "boolean": literal - }, - // if true, entities are escaped ( <, >, \t, space and \n ) - HTML: false, - // indentation unit - indentChar: " ", - // if true, items in a collection, are separated by a \n, else just a space. - multiline: true - }; - - return jsDump; -}()); - -// from jquery.js -function inArray( elem, array ) { - if ( array.indexOf ) { - return array.indexOf( elem ); - } - - for ( var i = 0, length = array.length; i < length; i++ ) { - if ( array[ i ] === elem ) { - return i; - } - } - - return -1; -} - -/* - * Javascript Diff Algorithm - * By John Resig (http://ejohn.org/) - * Modified by Chu Alan "sprite" - * - * Released under the MIT license. - * - * More Info: - * http://ejohn.org/projects/javascript-diff-algorithm/ - * - * Usage: QUnit.diff(expected, actual) - * - * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over" - */ -QUnit.diff = (function() { - /*jshint eqeqeq:false, eqnull:true */ - function diff( o, n ) { - var i, - ns = {}, - os = {}; - - for ( i = 0; i < n.length; i++ ) { - if ( !hasOwn.call( ns, n[i] ) ) { - ns[ n[i] ] = { - rows: [], - o: null - }; - } - ns[ n[i] ].rows.push( i ); - } - - for ( i = 0; i < o.length; i++ ) { - if ( !hasOwn.call( os, o[i] ) ) { - os[ o[i] ] = { - rows: [], - n: null - }; - } - os[ o[i] ].rows.push( i ); - } - - for ( i in ns ) { - if ( hasOwn.call( ns, i ) ) { - if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) { - n[ ns[i].rows[0] ] = { - text: n[ ns[i].rows[0] ], - row: os[i].rows[0] - }; - o[ os[i].rows[0] ] = { - text: o[ os[i].rows[0] ], - row: ns[i].rows[0] - }; - } - } - } - - for ( i = 0; i < n.length - 1; i++ ) { - if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && - n[ i + 1 ] == o[ n[i].row + 1 ] ) { - - n[ i + 1 ] = { - text: n[ i + 1 ], - row: n[i].row + 1 - }; - o[ n[i].row + 1 ] = { - text: o[ n[i].row + 1 ], - row: i + 1 - }; - } - } - - for ( i = n.length - 1; i > 0; i-- ) { - if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && - n[ i - 1 ] == o[ n[i].row - 1 ]) { - - n[ i - 1 ] = { - text: n[ i - 1 ], - row: n[i].row - 1 - }; - o[ n[i].row - 1 ] = { - text: o[ n[i].row - 1 ], - row: i - 1 - }; - } - } - - return { - o: o, - n: n - }; - } - - return function( o, n ) { - o = o.replace( /\s+$/, "" ); - n = n.replace( /\s+$/, "" ); - - var i, pre, - str = "", - out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), - oSpace = o.match(/\s+/g), - nSpace = n.match(/\s+/g); - - if ( oSpace == null ) { - oSpace = [ " " ]; - } - else { - oSpace.push( " " ); - } - - if ( nSpace == null ) { - nSpace = [ " " ]; - } - else { - nSpace.push( " " ); - } - - if ( out.n.length === 0 ) { - for ( i = 0; i < out.o.length; i++ ) { - str += "" + out.o[i] + oSpace[i] + ""; - } - } - else { - if ( out.n[0].text == null ) { - for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { - str += "" + out.o[n] + oSpace[n] + ""; - } - } - - for ( i = 0; i < out.n.length; i++ ) { - if (out.n[i].text == null) { - str += "" + out.n[i] + nSpace[i] + ""; - } - else { - // `pre` initialized at top of scope - pre = ""; - - for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { - pre += "" + out.o[n] + oSpace[n] + ""; - } - str += " " + out.n[i].text + nSpace[i] + pre; - } - } - } - - return str; - }; -}()); - -// for CommonJS environments, export everything -if ( typeof exports !== "undefined" ) { - extend( exports, QUnit.constructor.prototype ); -} - -// get at whatever the global object is, like window in browsers -}( (function() {return this;}.call()) )); From 30ea403607c20b6ee7d8bbdfd70e0cd5e4371495 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 28 Jan 2014 12:12:13 -0500 Subject: [PATCH 0040/2527] Cleanup. - Ember.computed takes the DK as a first argument, no need to all property on it again - misc formatting as I go. --- .../lib/system/relationships/has_many.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index 5bec9c6c1a0..ffbf260318e 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -5,7 +5,7 @@ var get = Ember.get, set = Ember.set, setProperties = Ember.setProperties; function asyncHasMany(type, options, meta) { - return Ember.computed(function(key, value) { + return Ember.computed('data', function(key, value) { var relationship = this._relationships[key], promiseLabel = "DS: Async hasMany " + this + " : " + key; @@ -31,8 +31,10 @@ function asyncHasMany(type, options, meta) { return relationship; }, null, "DS: Async hasMany records received"); - return DS.PromiseArray.create({ promise: promise }); - }).property('data').meta(meta); + return DS.PromiseArray.create({ + promise: promise + }); + }).meta(meta); } function buildRelationship(record, key, options, callback) { @@ -46,14 +48,21 @@ function buildRelationship(record, key, options, callback) { var relationship = rels[key] = callback.call(record, store, data); return setProperties(relationship, { - owner: record, name: key, isPolymorphic: options.polymorphic + owner: record, + name: key, + isPolymorphic: options.polymorphic }); } function hasRelationship(type, options) { options = options || {}; - var meta = { type: type, isRelationship: true, options: options, kind: 'hasMany' }; + var meta = { + type: type, + isRelationship: true, + options: options, + kind: 'hasMany' + }; if (options.async) { return asyncHasMany(type, options, meta); From 035d2bf7555a9b727edbcaa158583ad5f65a10d0 Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 28 Jan 2014 18:28:17 +0100 Subject: [PATCH 0041/2527] Use latest stable Ember.js Note: the jQuery dependency needs to be specified explicitely since Ember.js v1.3.1 does not support jQuery 2.1 --- bower.json | 3 ++- tests/index.html | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index 28375cb53db..5e9e626699f 100644 --- a/bower.json +++ b/bower.json @@ -2,7 +2,8 @@ "name": "ember-data", "private": true, "dependencies": { - "ember": "~1.2.0", + "ember": "~1.3.1", + "jquery": "~2.0", "qunit": "~1.13.0" } } diff --git a/tests/index.html b/tests/index.html index 5490b0694ee..9cb637bb6e0 100644 --- a/tests/index.html +++ b/tests/index.html @@ -12,7 +12,7 @@ - + From dd964d2b7fe87ef7368336bd401c40834950f736 Mon Sep 17 00:00:00 2001 From: Luke Melia Date: Tue, 28 Jan 2014 13:25:02 -0500 Subject: [PATCH 0042/2527] Avoid instance of aliasMethod due to problems with Chrome debugger --- .../lib/serializers/json_serializer.js | 48 ++++++++++++------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 7d4eccafafa..8be3b91b355 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -1,13 +1,5 @@ var get = Ember.get, set = Ember.set, isNone = Ember.isNone; -// Simple dispatcher to support overriding the aliased -// method in subclasses. -function aliasMethod(methodName) { - return function() { - return this[methodName].apply(this, arguments); - }; -} - /** In Ember Data a Serializer is used to serialize and deserialize records when they are transferred in and out of an external source. @@ -475,7 +467,9 @@ var JSONSerializer = Ember.Object.extend({ @param {Object} payload @return {Array} array An array of deserialized objects */ - extractFindAll: aliasMethod('extractArray'), + extractFindAll: function(store, type, payload){ + return this.extractArray(store, type, payload); + }, /** `extractFindQuery` is a hook into the extract method used when a call is made to `DS.Store#findQuery`. By default this method is an @@ -487,7 +481,9 @@ var JSONSerializer = Ember.Object.extend({ @param {Object} payload @return {Array} array An array of deserialized objects */ - extractFindQuery: aliasMethod('extractArray'), + extractFindQuery: function(store, type, payload){ + return this.extractArray(store, type, payload); + }, /** `extractFindMany` is a hook into the extract method used when a call is made to `DS.Store#findMany`. By default this method is @@ -499,7 +495,9 @@ var JSONSerializer = Ember.Object.extend({ @param {Object} payload @return {Array} array An array of deserialized objects */ - extractFindMany: aliasMethod('extractArray'), + extractFindMany: function(store, type, payload){ + return this.extractArray(store, type, payload); + }, /** `extractFindHasMany` is a hook into the extract method used when a call is made to `DS.Store#findHasMany`. By default this method is @@ -511,7 +509,9 @@ var JSONSerializer = Ember.Object.extend({ @param {Object} payload @return {Array} array An array of deserialized objects */ - extractFindHasMany: aliasMethod('extractArray'), + extractFindHasMany: function(store, type, payload){ + return this.extractArray(store, type, payload); + }, /** `extractCreateRecord` is a hook into the extract method used when a @@ -524,7 +524,9 @@ var JSONSerializer = Ember.Object.extend({ @param {Object} payload @return {Object} json The deserialized payload */ - extractCreateRecord: aliasMethod('extractSave'), + extractCreateRecord: function(store, type, payload) { + return this.extractSave(store, type, payload); + }, /** `extractUpdateRecord` is a hook into the extract method used when a call is made to `DS.Store#update`. By default this method is alias @@ -536,7 +538,9 @@ var JSONSerializer = Ember.Object.extend({ @param {Object} payload @return {Object} json The deserialized payload */ - extractUpdateRecord: aliasMethod('extractSave'), + extractUpdateRecord: function(store, type, payload) { + return this.extractSave(store, type, payload); + }, /** `extractDeleteRecord` is a hook into the extract method used when a call is made to `DS.Store#deleteRecord`. By default this method is @@ -548,7 +552,9 @@ var JSONSerializer = Ember.Object.extend({ @param {Object} payload @return {Object} json The deserialized payload */ - extractDeleteRecord: aliasMethod('extractSave'), + extractDeleteRecord: function(store, type, payload) { + return this.extractSave(store, type, payload); + }, /** `extractFind` is a hook into the extract method used when @@ -561,7 +567,9 @@ var JSONSerializer = Ember.Object.extend({ @param {Object} payload @return {Object} json The deserialized payload */ - extractFind: aliasMethod('extractSingle'), + extractFind: function(store, type, payload) { + return this.extractSingle(store, type, payload); + }, /** `extractFindBelongsTo` is a hook into the extract method used when a call is made to `DS.Store#findBelongsTo`. By default this method is @@ -573,7 +581,9 @@ var JSONSerializer = Ember.Object.extend({ @param {Object} payload @return {Object} json The deserialized payload */ - extractFindBelongsTo: aliasMethod('extractSingle'), + extractFindBelongsTo: function(store, type, payload) { + return this.extractSingle(store, type, payload); + }, /** `extractSave` is a hook into the extract method used when a call is made to `DS.Model#save`. By default this method is alias @@ -585,7 +595,9 @@ var JSONSerializer = Ember.Object.extend({ @param {Object} payload @return {Object} json The deserialized payload */ - extractSave: aliasMethod('extractSingle'), + extractSave: function(store, type, payload) { + return this.extractSingle(store, type, payload); + }, /** `extractSingle` is used to deserialize a single record returned From 70e61723e88d590cd7f74a1d0e5abd6cd99ac192 Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 28 Jan 2014 22:47:57 +0100 Subject: [PATCH 0043/2527] Fix bug where an undefined id would trigger a `findAll` This has been observed by the eagle eyes of @stefanpenner, reported in issue #1705. --- packages/ember-data/lib/system/store.js | 5 ++++- .../tests/integration/adapter/find_test.js | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index a20785acf35..e3774ba3fd1 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -338,7 +338,10 @@ Store = Ember.Object.extend({ @return {Promise} promise */ find: function(type, id) { - if (id === undefined) { + Ember.assert("You need to pass a type to the store's find method", arguments.length >= 1); + Ember.assert("You may not pass `" + id + "` as id to the store's find method", arguments.length === 1 || !Ember.isNone(id)); + + if (arguments.length === 1) { return this.findAll(type); } diff --git a/packages/ember-data/tests/integration/adapter/find_test.js b/packages/ember-data/tests/integration/adapter/find_test.js index 28eb8503d84..6d90e13c7c6 100644 --- a/packages/ember-data/tests/integration/adapter/find_test.js +++ b/packages/ember-data/tests/integration/adapter/find_test.js @@ -16,6 +16,26 @@ module("integration/adapter/find - Finding Records", { } }); +test("It raises an assertion when no type is passed", function() { + store = createStore(); + + expectAssertion(function() { + store.find(); + }, "You need to pass a type to the store's find method"); +}); + +test("It raises an assertion when `undefined` is passed as id (#1705)", function() { + store = createStore(); + + expectAssertion(function() { + store.find(Person, undefined); + }, "You may not pass `undefined` as id to the store's find method"); + + expectAssertion(function() { + store.find(Person, null); + }, "You may not pass `null` as id to the store's find method"); +}); + test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function() { expect(2); From 97f68ccfc5f0cbd4627e37682516be6c9416fdb3 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 28 Jan 2014 23:51:48 -0500 Subject: [PATCH 0044/2527] Object.create does not exist in old IE. --- tests/qunit_configuration.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/qunit_configuration.js b/tests/qunit_configuration.js index 618e8985eae..ff7c2f10f24 100644 --- a/tests/qunit_configuration.js +++ b/tests/qunit_configuration.js @@ -157,6 +157,18 @@ return str + "\n" + len + ' error' + ((len === 1) ? '' : 's'); }; + var o_create = Object.create || (function(){ + function F(){} + + return function(o) { + if (arguments.length !== 1) { + throw new Error('Object.create implementation only accepts one parameter.'); + } + F.prototype = o; + return new F(); + }; + }()); + // A light class for stubbing // function MethodCallExpectation(target, property){ @@ -198,7 +210,7 @@ this.expectedMessage = message; }; AssertExpectation.Error = function(){}; - AssertExpectation.prototype = Object.create(MethodCallExpectation.prototype); + AssertExpectation.prototype = o_create(MethodCallExpectation.prototype); AssertExpectation.prototype.handleCall = function(message, test){ this.sawCall = true; if (test) return; // Only get message for failures From 08851b54f4093d24358e9d12c36d740603181d0d Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 29 Jan 2014 06:43:23 +0100 Subject: [PATCH 0045/2527] Remove restriction for jQuery version in bower.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was needed since Ember v1.3.1 only works with jQuery <2.1, but the bower config for this version didn't specify this restriction. Since this has been fixed by Señor @rjackson (http://git.io/B2xRbQ) the specific jQuery version is removed again from `bower.json`. --- bower.json | 1 - 1 file changed, 1 deletion(-) diff --git a/bower.json b/bower.json index 5e9e626699f..acc56ea2137 100644 --- a/bower.json +++ b/bower.json @@ -3,7 +3,6 @@ "private": true, "dependencies": { "ember": "~1.3.1", - "jquery": "~2.0", "qunit": "~1.13.0" } } From fec5fc853dfaf037e229e081e6b444f53dc0eb42 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 29 Jan 2014 00:06:34 -0500 Subject: [PATCH 0046/2527] Allow testing against multiple versions of Ember & jQuery. * Adds ability to test against multiple versions of Ember via the `emberchannel` query param (defaults to local Bower version). * Adds ability to test against multiple jQuery versions via the `jquery` query param (defaults to local Bower version). --- tests/index.html | 53 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/tests/index.html b/tests/index.html index 9cb637bb6e0..d63452f67aa 100644 --- a/tests/index.html +++ b/tests/index.html @@ -4,18 +4,53 @@ Ember Data + + + + + + + + + + + + + + + + +
      - - - - - - - - - From b9e709b6abb3ce6304ad10f65c2629ace32fcec3 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 29 Jan 2014 00:20:20 -0500 Subject: [PATCH 0047/2527] Enable multi-channel testing. Adds the following tasks: * `test:local` (alias to previous `test` task) * `test:release` (tests against current release builds of Ember) * `test:beta` (tests against current beta builds of Ember) * `test:canary` (tests against current canary builds of Ember) * `test:all` (tests against all channels of Ember) Changes the default Travis test script to `test:all`. --- .travis.yml | 2 +- Gruntfile.js | 14 +++++++++++--- tasks/options/qunit.js | 17 ++++++++++++++++- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 28e4f65f01d..1744aa40964 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ install: - "bin/cached-npm install" - "bin/cached-npm install -g grunt-cli bower" - "bower install" -script: grunt +script: grunt test:all env: global: - S3_BUILD_CACHE_BUCKET=emberjs-build-cache diff --git a/Gruntfile.js b/Gruntfile.js index 41f19d75d23..bc631d2fea2 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -21,10 +21,18 @@ module.exports = function(grunt){ 'jshint' ]); - grunt.registerTask('buildTests', ['concat:tests']); - grunt.registerTask('dev', [ 'buildPackages', 'buildTests', 'connect', 'watch' ]); + grunt.registerTask('prepareTests', ['buildPackages', 'concat:tests', 'connect']); + + grunt.registerTask('test', ['prepareTests', 'qunit:local']); + grunt.registerTask('test:local', 'test'); + grunt.registerTask('test:release', ['prepareTests', 'qunit:release']); + grunt.registerTask('test:beta', ['prepareTests', 'qunit:beta']); + grunt.registerTask('test:canary', ['prepareTests', 'qunit:canary']); + grunt.registerTask('test:all', ['prepareTests', 'qunit:local', 'qunit:release', 'qunit:beta', 'qunit:canary']); + + grunt.registerTask('dev', [ 'prepareTests', 'watch' ]); grunt.registerTask('server', 'dev'); - grunt.registerTask('test', ['buildPackages', 'buildTests', 'connect', 'qunit']); + grunt.registerTask('dist', ['buildPackages', 'emberDefeatureify:stripDebug', 'uglify']); grunt.registerTask('default', ['test']); }; diff --git a/tasks/options/qunit.js b/tasks/options/qunit.js index 3249c1b3313..4aa56c5b1c2 100644 --- a/tasks/options/qunit.js +++ b/tasks/options/qunit.js @@ -1,7 +1,22 @@ module.exports = { - all: { + local: { options: { urls: [ 'http://localhost:9997/tests/index.html' ] } + }, + release: { + options: { + urls: [ 'http://localhost:9997/tests/index.html?emberchannel=release' ] + } + }, + beta: { + options: { + urls: [ 'http://localhost:9997/tests/index.html?emberchannel=beta' ] + } + }, + canary: { + options: { + urls: [ 'http://localhost:9997/tests/index.html?emberchannel=canary' ] + } } }; From a5b8ab5c5b08fc206bd562ad7c070b4d5390bd2b Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 29 Jan 2014 11:24:59 -0500 Subject: [PATCH 0048/2527] Fix the links to DS.Model and DS.Transform in the DS Namespace method docs --- packages/ember-data/lib/system/model/attributes.js | 4 ++-- packages/ember-data/lib/system/relationships/belongs_to.js | 2 +- packages/ember-data/lib/system/relationships/has_many.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index b59a096a82e..928d9021c8c 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -229,12 +229,12 @@ function getValue(record, key) { } /** - `DS.attr` defines an attribute on a [DS.Model](DS.Model.html). + `DS.attr` defines an attribute on a [DS.Model](/api/data/classes/DS.Model.html). By default, attributes are passed through as-is, however you can specify an optional type to have the value automatically transformed. Ember Data ships with four basic transform types: `string`, `number`, `boolean` and `date`. You can define your own transforms by subclassing - [DS.Transform](DS.Transform.html). + [DS.Transform](/api/data/classes/DS.Transform.html). `DS.attr` takes an optional hash as a second parameter, currently supported options are: diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index 21d61727315..42ff635c033 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -44,7 +44,7 @@ function asyncBelongsTo(type, options, meta) { /** `DS.belongsTo` is used to define One-To-One and One-To-Many - relationships on a [DS.Model](DS.Model.html). + relationships on a [DS.Model](/api/data/classes/DS.Model.html). `DS.belongsTo` takes an optional hash as a second parameter, currently diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index ffbf260318e..269a158e1ed 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -79,7 +79,7 @@ function hasRelationship(type, options) { /** `DS.hasMany` is used to define One-To-Many and Many-To-Many - relationships on a [DS.Model](DS.Model.html). + relationships on a [DS.Model](/api/data/classes/DS.Model.html). `DS.hasMany` takes an optional hash as a second parameter, currently supported options are: From c8aa176490a9ec96dacafab24ff8a18a5d732ef4 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 29 Jan 2014 11:57:07 -0500 Subject: [PATCH 0049/2527] Add build publishing to builds.emberjs.com. --- .travis.yml | 1 + package.json | 3 +- tasks/options/publish.js | 32 +++++++++++++++++++ tasks/publish.js | 67 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 tasks/options/publish.js create mode 100644 tasks/publish.js diff --git a/.travis.yml b/.travis.yml index 1744aa40964..2e0e075b65d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ install: - "bin/cached-npm install -g grunt-cli bower" - "bower install" script: grunt test:all +after_success: grunt publish env: global: - S3_BUILD_CACHE_BUCKET=emberjs-build-cache diff --git a/package.json b/package.json index 8cb56af6994..cc22e662369 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "grunt-contrib-watch": "~0.5.3", "grunt-contrib-uglify": "~0.3.0", "bower": "~1.2", - "grunt-ember-defeatureify": "~0.1.0" + "grunt-ember-defeatureify": "~0.1.0", + "aws-sdk": "~2.0.0-rc8" } } diff --git a/tasks/options/publish.js b/tasks/options/publish.js new file mode 100644 index 00000000000..2c8033f8460 --- /dev/null +++ b/tasks/options/publish.js @@ -0,0 +1,32 @@ +var date = new Date().toISOString().replace(/-/g, '').replace(/T.+/, '') +var sha = process.env.TRAVIS_COMMIT; + +function destinationsForType(extension){ + var filename = 'ember-data' + extension; + + return ['CHANNEL/' + filename, + 'CHANNEL/daily/' + date + '/' + filename, + 'CHANNEL/shas/' + sha + '/' + filename] +} + +module.exports = { + debug: { + files: [{ + src: 'dist/ember-data.js', + dest: destinationsForType('.js') + }] + }, + prod: { + files: [{ + src: 'dist/ember-data.prod.js', + dest: destinationsForType('.prod.js') + }] + }, + min: { + files: [{ + src: 'dist/ember-data.min.js', + dest: destinationsForType('.min.js') + }] + } +}; + diff --git a/tasks/publish.js b/tasks/publish.js new file mode 100644 index 00000000000..3d78e674e66 --- /dev/null +++ b/tasks/publish.js @@ -0,0 +1,67 @@ +var path = require('path'); + +var S3_BUCKET_NAME = process.env.S3_BUCKET_NAME, + S3_ACCESS_KEY_ID = process.env.S3_ACCESS_KEY_ID, + S3_SECRET_ACCESS_KEY = process.env.S3_SECRET_ACCESS_KEY, + TRAVIS_BRANCH = process.env.TRAVIS_BRANCH, + AWS, s3; + +function uploadFile(data, type, destination, callback) { + if (!AWS) { + AWS = require('aws-sdk'); + AWS.config.update({accessKeyId: S3_ACCESS_KEY_ID, secretAccessKey: S3_SECRET_ACCESS_KEY}); + } + + if (!s3) { s3 = new AWS.S3(); } + + s3.putObject({ + Body: data, + Bucket: S3_BUCKET_NAME, + ContentType: type, + Key: destination + }, callback) +} + +module.exports = function(grunt) { + grunt.registerMultiTask('publish', 'Publish files to S3', function() { + if (!S3_BUCKET_NAME || !S3_ACCESS_KEY_ID || !S3_SECRET_ACCESS_KEY) { + grunt.log.writeln('No AWS credentials exist.'); + return; + } + + var done = this.async(); + var uploadPendingCount = 0; + + function finish(err, result){ + if (err) { + grunt.log.writeln("Error: " + err + "; Result: " + result); + } + + uploadPendingCount--; + if (uploadPendingCount === 0) { done() } + } + + this.files.forEach(function(f) { + f.dest.forEach(function(dest){ + var finalDestination; + var channel; + + if(dest.indexOf('CHANNEL') > -1) { + if (TRAVIS_BRANCH === 'master') { channel = 'canary'; } + if (TRAVIS_BRANCH === 'beta') { channel = 'beta'; } + if (TRAVIS_BRANCH === 'stable') { channel = 'release'; } + + finalDestination = dest.replace('CHANNEL', channel); + } else { + finalDestination = dest; + } + + if (finalDestination) { + uploadPendingCount++; + grunt.log.writeln("Uploading " + f.src + " -> " + finalDestination); + uploadFile(grunt.file.read(f.src), 'text/javascript', finalDestination, finish); + } + }); + }); + }); +}; From 848d6ae0f6ab707bfb4fa628594394f77635b2a2 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 29 Jan 2014 14:23:22 -0500 Subject: [PATCH 0050/2527] Ensure builds are generated before publishing. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2e0e075b65d..e50c97283a1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ install: - "bin/cached-npm install -g grunt-cli bower" - "bower install" script: grunt test:all -after_success: grunt publish +after_success: grunt dist publish env: global: - S3_BUILD_CACHE_BUCKET=emberjs-build-cache From 4a972e63f6ce3de699e5411db365788c487b5dcb Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 29 Jan 2014 16:03:40 -0500 Subject: [PATCH 0051/2527] Fix `grunt server` automated testing upon file change. --- Gruntfile.js | 15 ++++++++------- tasks/options/watch.js | 4 ++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index bc631d2fea2..9462b87f7d2 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -21,16 +21,17 @@ module.exports = function(grunt){ 'jshint' ]); - grunt.registerTask('prepareTests', ['buildPackages', 'concat:tests', 'connect']); + grunt.registerTask('prepareTests', ['buildPackages', 'concat:tests']); - grunt.registerTask('test', ['prepareTests', 'qunit:local']); + grunt.registerTask('test:server', ['prepareTests', 'connect']); + grunt.registerTask('test', ['test:server', 'qunit:local']); grunt.registerTask('test:local', 'test'); - grunt.registerTask('test:release', ['prepareTests', 'qunit:release']); - grunt.registerTask('test:beta', ['prepareTests', 'qunit:beta']); - grunt.registerTask('test:canary', ['prepareTests', 'qunit:canary']); - grunt.registerTask('test:all', ['prepareTests', 'qunit:local', 'qunit:release', 'qunit:beta', 'qunit:canary']); + grunt.registerTask('test:release', ['test:server', 'qunit:release']); + grunt.registerTask('test:beta', ['test:server', 'qunit:beta']); + grunt.registerTask('test:canary', ['test:server', 'qunit:canary']); + grunt.registerTask('test:all', ['test:server', 'qunit:local', 'qunit:release', 'qunit:beta', 'qunit:canary']); - grunt.registerTask('dev', [ 'prepareTests', 'watch' ]); + grunt.registerTask('dev', [ 'test:server', 'watch' ]); grunt.registerTask('server', 'dev'); grunt.registerTask('dist', ['buildPackages', 'emberDefeatureify:stripDebug', 'uglify']); diff --git a/tasks/options/watch.js b/tasks/options/watch.js index f721a497a98..9b12a0e0cfd 100644 --- a/tasks/options/watch.js +++ b/tasks/options/watch.js @@ -2,11 +2,11 @@ module.exports = { packages: { files: [ 'packages/**/*.js', '!packages/**/test/**/*.js'], - tasks: [ 'buildPackages', 'buildTests', 'qunit' ] + tasks: [ 'buildPackages', 'prepareTests', 'qunit:local' ] }, tests: { files: [ 'packages/**/test/**/*.js' ], - tasks: [ 'buildTests', 'qunit' ] + tasks: [ 'prepareTests', 'qunit:local' ] } }; From d15d1e31971510ec140916ebba46e76e167d03c4 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 29 Jan 2014 16:26:01 -0500 Subject: [PATCH 0052/2527] keep a local version of grunt-cli (dev only) --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index cc22e662369..b155d841f92 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "grunt-contrib-uglify": "~0.3.0", "bower": "~1.2", "grunt-ember-defeatureify": "~0.1.0", - "aws-sdk": "~2.0.0-rc8" + "aws-sdk": "~2.0.0-rc8", + "grunt-cli": "~0.1.13" } } From 8aa0c0e036f6a80f5c61b1e22746c05f3b558efe Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 29 Jan 2014 17:17:59 -0500 Subject: [PATCH 0053/2527] Add current revision back to build output. --- Gruntfile.js | 1 + generators/license.js | 2 +- packages/ember-data/lib/core.js | 2 +- tasks/setVersionStamp.js | 11 +++++++++++ 4 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tasks/setVersionStamp.js diff --git a/Gruntfile.js b/Gruntfile.js index 9462b87f7d2..81c4eaa8254 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -14,6 +14,7 @@ module.exports = function(grunt){ grunt.initConfig(config); grunt.registerTask('buildPackages', [ + 'setVersionStamp', 'clean', 'transpile:amd', 'concat:globals', diff --git a/generators/license.js b/generators/license.js index e64ffc66342..8e4ea61b311 100644 --- a/generators/license.js +++ b/generators/license.js @@ -3,5 +3,5 @@ * @copyright Copyright 2011-2014 Tilde Inc. and contributors. * Portions Copyright 2011 LivingSocial Inc. * @license Licensed under MIT license (see license.js) - * @version <%= pkg.version %> + * @version <%= versionStamp %> */ diff --git a/packages/ember-data/lib/core.js b/packages/ember-data/lib/core.js index a03f0ae2fca..4e1e135633d 100644 --- a/packages/ember-data/lib/core.js +++ b/packages/ember-data/lib/core.js @@ -13,7 +13,7 @@ if ('undefined' === typeof DS) { /** @property VERSION @type String - @default '<%= pkg.version %>' + @default '<%= versionStamp %>' @static */ DS = Ember.Namespace.create({ diff --git a/tasks/setVersionStamp.js b/tasks/setVersionStamp.js new file mode 100644 index 00000000000..d47bcdf1cbc --- /dev/null +++ b/tasks/setVersionStamp.js @@ -0,0 +1,11 @@ +module.exports = function(grunt) { + grunt.registerTask('setVersionStamp', 'Add the currentRevision and versionStamp values to the global grunt config', function() { + var done = this.async(); + + grunt.util.spawn({cmd: 'git', args: ['rev-list', 'HEAD', '-n', '1']}, function(error, result, code){ + grunt.config('currentRevision', result.toString()); + grunt.config('versionStamp', grunt.config('pkg.version') + '.' + grunt.config('currentRevision').substr(0,8)); + done(); + }) + }); +}; From cb47d402a95bcce4e7c168ac5d467dc3de402a49 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 29 Jan 2014 17:25:07 -0500 Subject: [PATCH 0054/2527] Do not generate a gzip report from uglify:dist. We currently discard the gzipped output, and this is solely used to display the results to the screen. This adds between 5x and 10x to the total time required for the `uglify` task. To see the full `gzip` report, run `grunt uglify:report`. --- Gruntfile.js | 2 +- tasks/options/uglify.js | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 81c4eaa8254..079a9579820 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -35,6 +35,6 @@ module.exports = function(grunt){ grunt.registerTask('dev', [ 'test:server', 'watch' ]); grunt.registerTask('server', 'dev'); - grunt.registerTask('dist', ['buildPackages', 'emberDefeatureify:stripDebug', 'uglify']); + grunt.registerTask('dist', ['buildPackages', 'emberDefeatureify:stripDebug', 'uglify:dist']); grunt.registerTask('default', ['test']); }; diff --git a/tasks/options/uglify.js b/tasks/options/uglify.js index 201521236d3..6886bbd0ae0 100644 --- a/tasks/options/uglify.js +++ b/tasks/options/uglify.js @@ -1,7 +1,7 @@ var grunt = require('grunt'); module.exports = { options: { - report: 'gzip', + report: 'min', banner: grunt.file.read('generators/license.js'), }, dist: { @@ -9,5 +9,14 @@ module.exports = { src: 'dist/ember-data.prod.js', dest: 'dist/ember-data.min.js', }] - } + }, + report: { + options:{ + report: 'gzip' + }, + files: [{ + src: 'dist/ember-data.prod.js', + dest: 'dist/ember-data.min.js', + }] + }, }; From dc4a7c79ea84981921fdfe7621a52ed33bc2b709 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 29 Jan 2014 17:32:09 -0500 Subject: [PATCH 0055/2527] Use local versions of grunt and bower for Travis. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e50c97283a1..fee73a5a45b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ node_js: - "0.10" install: - "bin/cached-npm install" -- "bin/cached-npm install -g grunt-cli bower" - "bower install" script: grunt test:all after_success: grunt dist publish From e26ca8f113eb24d553bdcc298cc333eae8a436a1 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 29 Jan 2014 18:04:43 -0500 Subject: [PATCH 0056/2527] Add `grunt docs` task. --- Gruntfile.js | 2 ++ docs/package.json | 7 ------- docs/yuidoc.json | 16 ---------------- package.json | 3 ++- tasks/options/yuidoc.js | 18 ++++++++++++++++++ 5 files changed, 22 insertions(+), 24 deletions(-) delete mode 100644 docs/package.json delete mode 100644 docs/yuidoc.json create mode 100644 tasks/options/yuidoc.js diff --git a/Gruntfile.js b/Gruntfile.js index 079a9579820..a5fbf742734 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -37,4 +37,6 @@ module.exports = function(grunt){ grunt.registerTask('dist', ['buildPackages', 'emberDefeatureify:stripDebug', 'uglify:dist']); grunt.registerTask('default', ['test']); + + grunt.registerTask('docs', ['setVersionStamp', 'yuidoc']); }; diff --git a/docs/package.json b/docs/package.json deleted file mode 100644 index 2196f4f90ca..00000000000 --- a/docs/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "ember-docs", - "version": "0.0.1", - "dependencies": { - "yuidoc": "git://github.com/wagenet/yuidoc.git" - } -} diff --git a/docs/yuidoc.json b/docs/yuidoc.json deleted file mode 100644 index 24995e5a278..00000000000 --- a/docs/yuidoc.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "The ember-data API", - "description": "The ember-data API: a data persistence library for Ember.js", - "version": "Revision 12", - "logo": "http://f.cl.ly/items/1A1L432s022u1O1q1V3p/ember%20logo.png", - "url": "https://github.com/emberjs/data", - "options": { - "paths": [ - "../packages/ember-data/lib", - "../packages/activemodel-adapter/lib", - "../packages/ember-inflector/lib" - ], - "exclude": "vendor", - "outdir": "./build" - } -} diff --git a/package.json b/package.json index b155d841f92..7e7f69208b2 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "bower": "~1.2", "grunt-ember-defeatureify": "~0.1.0", "aws-sdk": "~2.0.0-rc8", - "grunt-cli": "~0.1.13" + "grunt-cli": "~0.1.13", + "grunt-contrib-yuidoc": "~0.5.0" } } diff --git a/tasks/options/yuidoc.js b/tasks/options/yuidoc.js new file mode 100644 index 00000000000..9a7b17a2259 --- /dev/null +++ b/tasks/options/yuidoc.js @@ -0,0 +1,18 @@ +module.exports = { + compile: { + "name": "The ember-data API", + "description": "The ember-data API: a data persistence library for Ember.js", + "version": '<%= versionStamp %>', + "logo": "http://f.cl.ly/items/1A1L432s022u1O1q1V3p/ember%20logo.png", + "url": "https://github.com/emberjs/data", + "options": { + "paths": [ + "packages/ember-data/lib", + "packages/activemodel-adapter/lib", + "packages/ember-inflector/lib" + ], + "exclude": "vendor", + "outdir": "docs/build" + } + } +} From 4002c59a6a39c3b80e700a5e75658b3193e1659d Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 29 Jan 2014 18:06:05 -0500 Subject: [PATCH 0057/2527] Remove Ruby remnants. --- Assetfile | 40 ---------------------------------------- config.ru | 5 ----- 2 files changed, 45 deletions(-) delete mode 100644 Assetfile delete mode 100644 config.ru diff --git a/Assetfile b/Assetfile deleted file mode 100644 index 44f5c3dc56e..00000000000 --- a/Assetfile +++ /dev/null @@ -1,40 +0,0 @@ -require 'ember-dev' -distros = { - :full => %w(ember-data ember-inflector activemodel-adapter) -} - -#MEGAHAX -ember_spade_postprocess = "filter EmberAddMicroLoader, :global => true" - -instance_eval File.read(EmberDev.support_path.join('Assetfile')) - -distros.each do |name, modules| - name = "ember-data" - - input "dist/modules" do - module_paths = modules.map{|m| "#{m}.js" } - match "{#{module_paths.join(',')}}" do - concat(module_paths){ ["#{name}.js", "#{name}.prod.js"] } - filter EmberAddMicroLoader - end - - match "#{name}.js" do - filter EmberLicenseFilter - filter AddProjectVersionNumber - end - - # Strip dev code - match "#{name}.prod.js" do - filter EmberLicenseFilter - filter AddProjectVersionNumber - filter(EmberStripDebugMessagesFilter) { ["#{name}.prod.js", "min/#{name}.js"] } - end - - # Minify - match "min/#{name}.js" do - uglify{ "#{name}.min.js" } - end - end -end - -# vim: filetype=ruby diff --git a/config.ru b/config.ru deleted file mode 100644 index 598d87200a9..00000000000 --- a/config.ru +++ /dev/null @@ -1,5 +0,0 @@ -require 'bundler/setup' -require 'ember/source' -require 'ember-dev' - -run EmberDev::Server.new From a6b6d2f4bab686a2c5c3d1d6f164136153330fb0 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 29 Jan 2014 18:07:17 -0500 Subject: [PATCH 0058/2527] Remove 0.13 era architecture file. --- docs/ARCHITECTURE.md | 236 ------------------------------------------- 1 file changed, 236 deletions(-) delete mode 100644 docs/ARCHITECTURE.md diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md deleted file mode 100644 index 2aae1b0bea2..00000000000 --- a/docs/ARCHITECTURE.md +++ /dev/null @@ -1,236 +0,0 @@ -# Ember Data Architecture - -## Roles & Responsibilities - -### DS.Store - -The store is the primary interface between the application developer -and the data store. It is responsible for managing all available -records, both materialized and immaterialized. At its core, it is a -bookkeeping object that indexes loaded hashes, and serves as a -coordinator between the other objects in the system. - -* Indexes data hashes by type and ID -* Supplies a `clientId` for each requested record, and maps type/ID - to `clientId`s and vice versa. -* Serves as an identity map for records of a given type/ID -* Creates new records and transactions - * By default, `Post.createRecord()` asks the default store to - create the record. - * Optionally, coordinates with adapter to generate a client-generated - ID for new records. -* Coordinates with the adapter to request records (find, findMany, - findAll, findQuery). -* Sends lifecycle events to records. For example, the store notifies - a record when the adapter has saved its pending changes (`didCommit`) -* Serves as the callback target for the adapter (`didCreateRecord`, et - al) -* Responsible for managing indexes that power live record arrays - * Filters: when a new data hash is loaded into the store, it updates - any filters registered on that type. Records notify the store - (via `hashWasUpdated`) when any properties change, causing the - filters to update. - * `find()`: `find()` is a special filter that matches all records - for a given type. - -### DS.Model - -A model defines the attributes and relationships for a given type. -Instances of models, called records, are objects that provide an Ember -interface to JSON hashes returned by the server. Internally, records -keep track of their original JSON hash and any unsaved changes (see -`DataProxy` below for more details). - -Records move through states in a state manager throughout their life. -For example, a newly created record begins its life in the -`loaded.created` state. A record requested from the server starts in the -`loading` state, and moves into the `loaded.saved` state once the server -returns its JSON hash. - -When a store materializes a record, it asks the adapter (see below) to -extract the record's attributes and relationships and normalize their -names. This means that records will always have normalized data hashes. - -* Has a series of lifecycle flags (`isLoaded`, etc.) -* Serializes the record into a persistable JSON hash, accepting - adapter-provided options (such as `includeForeignKeys`). -* Manages an underlying `DataProxy` -* Manages a `StateManager` and sends any events to its state manager -* Tracks its current transaction -* Sends events to the transaction when the record becomes dirty -* Updates materialized `ManyArrays` if the underlying data changes -* Aliases store methods that require a type parameter to the `DS.Model` - type. For example, instead of requiring you to call - `store.find(App.Person, 1)`, you can say `App.Person.find(1)`. - -### DataProxy - -A record's `DataProxy` wraps its server-returned JSON hash plus any -unsaved changes in a single object. - -It also supports `commit`, which collapses the unsaved changes into -the saved changes, and `rollback`, which discards any unsaved changes. - -### Record State Manager - -Manages the current state of a record. Every record has its own instance -of the `StateManager`. - -When events occur to the record (e.g. the data hash changes, the store -acknowledges its commit), the record sends events to the state manager. -This allows the record to have context-specific responses to these -events, and initiate state transitions in response to events. - -There is a lot of specific documentation in `system/model/states.js`. - -### DS.Transaction - -A transaction represents a unit of work that can be atomically committed -to the adapter. When a transaction is committed, it is responsible for -providing all of the changes to the adapter to save. A transaction can -also be rolled back, which reverts any changes that occurred but had not -yet been saved to the adapter. - -Every record must belong to a transaction. By default, records belong -to the default transaction, which is a transaction that is implicitly -created with the store. - -Transactions are ephemeral objects. Once committed or rolled back, they -should not be used again. - -* Stores references to records, grouped by the current state of the - record. - * For example, a newly created record is saved in the `created` - bucket, while a record that has attributes changed is saved in the - `updated` bucket. -* Stores descriptions of changed relationships. When a relationship - changes, information about its old parent, new parent, and new child - is saved in the transaction. -* Raises an exception if changes in relationships are made between - records that are in different transactions. -* Able to move records into itself from another transaction if it is - legal. -* When committed, provides changed records to the adapter and - responsible for moving those records into an `inFlight` state. -* After committing or rolling back, moves clean records into the store's - default transaction. -* When rolled back, the transaction notifies all changed records to - discard changes. - -### DS.RecordArray - -Record arrays represent an ordered list of records. They are backed by -an array of client IDs. When retrieving a record from the record array, -it will be materialized lazily if necessary. - -`DS.RecordArray` is an abstract base class that provides many of the -features needed by its concrete implementations, described below. - -### DS.ManyArray - -Represents a one-to-many relationship. When the relationship is -retrieved from a record, a `ManyArray` is created that contains an -array of the client IDs that belong to that record. - -* Notifies the transaction if the relationship is modified -* Tracks aggregate state of member records via `isLoaded` flag -* Updates added records to point their inverse relationship to the new - parent. - -### DS.AdapterPopulatedRecordArray - -Represents an ordered list of records whose order and membership is -determined by the adapter. For example, a query sent to the adapter may -trigger a search on the server, whose results would be loaded into an -instance of the `AdapterPopulatedRecordArray`. - -### DS.FilteredRecordArray - -Represents a list of records whose membership is determined by the -store. As records are created, loaded, or modified, the store evaluates -them to determine if they should be part of the record array. - -### DS.Adapter - -The adapter is responsible for translating a store request into the -appropriate action to take against a persistence layer. For example, a -REST adapter may translate the request to find a record of type -`App.Photo` with ID `1` into an HTTP `GET` request to -`/photos/1`. - -The responsibility of the adapter fall into two general categories: -retrieving records and committing changes to records. - -#### Finding Via an Adapter - -* Loading records into the store in response to `find()` -* Loading multiple records into the store in response to `findMany()` -* Loading the results of a query into an `AdapterPopulatedRecordArray` - in response to a `findQuery()` -* Loading records into the store in response to `findAll()` - -#### Saving Changes - -The adapter receives a list of all changes from a transaction in -its `commit()` method. It is responsible for evaluating those changes, -figuring out what to do in order to persist them, and letting the -store know when the server acknowledged the save for a given -record. - -As part of this process, the adapter receives a list of all -created, updated, and deleted records, as well as a list of all -changes to relationships. - -In order to make this easy for an adapter to implement this pattern, -the `DS.Adapter` abstract class offers some conveniences: - -* If a record has no attribute changes, but is involved in a - relationship change, the abstract `DS.Adapter` calls the - `shouldCommit` method with the ambiguous record and the - relationship changes. - * In a relational model, for example, the adapter will return - true if the record is the child of a relationship change - and false if the record is the old or new parent. - * If the `shouldCommit` method returns false, the abstract - `commit` method will immediately call `didUpdateRecord` - on the store. -* If a record is involved in a relationship change, the abstract - `commit` method will call the adapter's `willCommit` method - with the record and the list of relationships. - * This gives the adapter an opportunity to pend the record. - For example, if a child record needs a foreign key, but - the parent record's ID does not exist yet, the adapter - can wait for the parent ID to become populated. -* The abstract `commit` method will call `createRecords`, - `updateRecords`, and `deleteRecords` to allow the adapter - to break up the commits to the server in an appropriate way. - -#### Client-Side ID Generation - -Adapters can specify a mechanism for new records to generate client-side -IDs. In general, this method should return a UUID or something with -extremely low collission possibility. - -When a store creates a new record, it first consults the adapter to -determine whether the ID can be generated on the client. If so, it will -apply the generated ID to the record immediately. - -One major benefit of generating IDs on the client is that records do not -need to wait for related records to be saved in order to retrieve -their foreign keys. - -#### Naming Conventions - -The adapter is also responsible for normalizing a server-provided data -hash to the naming expected by Ember. - -In general, this means converting underscored names to camelcased names. - -It is also responsible for converting dirty records into a data hash -expected by the server. For example, the adapter may need to add a -foreign key to the data hash by adding `_id` to its relationship. - -The abstract adapter class provides normalization functions that call -into the `namingConvention` hash in the concrete classes. For very -custom logic, the concrete classes may want to override the -normalization directly, but that should be very rare. From 1e8e4510f1c45549aa895a8423c6023946f10bf3 Mon Sep 17 00:00:00 2001 From: Steven Lindberg Date: Wed, 29 Jan 2014 12:24:37 -0800 Subject: [PATCH 0059/2527] Maintain consistency of internal changed attributes hash. This makes sure that the `_attributes` hash used to determine current attribute values (and dirty state) is always in sync with the record's original values. --- .../ember-data/lib/system/model/attributes.js | 5 ++++- packages/ember-data/tests/unit/model_test.js | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 928d9021c8c..8c78ae2a1ad 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -277,6 +277,10 @@ function attr(type, options) { var oldValue = getValue(this, key); if (value !== oldValue) { + // Add the new value to the changed attributes hash; it will get deleted by + // the 'didSetProperty' handler if it is no different from the original value + this._attributes[key] = value; + this.send('didSetProperty', { name: key, oldValue: oldValue, @@ -285,7 +289,6 @@ function attr(type, options) { }); } - this._attributes[key] = value; return value; } else if (hasValue(this, key)) { return getValue(this, key); diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index 14985ed8056..58159011c11 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -183,6 +183,22 @@ test("setting a property to undefined on a newly created record should not impac equal(get(tag, 'currentState.stateName'), "root.loaded.created.uncommitted"); }); +// NOTE: this is a 'backdoor' test that ensures internal consistency, and should be +// thrown out if/when the current `_attributes` hash logic is removed. +test("setting a property back to its original value removes the property from the `_attributes` hash", function() { + store.find(Person, 1).then(async(function(person) { + equal(person._attributes.name, undefined, "the `_attributes` hash is clean"); + + set(person, 'name', "Niceguy Dale"); + + equal(person._attributes.name, "Niceguy Dale", "the `_attributes` hash contains the changed value"); + + set(person, 'name', "Scumbag Dale"); + + equal(person._attributes.name, undefined, "the `_attributes` hash is reset"); + })); +}); + module("unit/model - with a simple Person model", { setup: function() { array = [{ id: 1, name: "Scumbag Dale" }, { id: 2, name: "Scumbag Katz" }, { id: 3, name: "Scumbag Bryn" }]; From c90bbf16f91645f0dde575f70c4ae8111f1033f8 Mon Sep 17 00:00:00 2001 From: Adolfo Builes Date: Wed, 29 Jan 2014 22:13:08 -0200 Subject: [PATCH 0060/2527] Update instructions for running tests. --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 90feadf48a9..fd23b558f61 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -58,8 +58,8 @@ We love pull requests. Here's a quick guide: 1. Fork the repo. 2. Run the tests. We only take pull requests with passing tests, and it's great -to know that you have a clean slate: `bundle && rake test[all]`. (To see tests -in the browser, run `rackup` and open `http://localhost:9292/?package=all`.) +to know that you have a clean slate, see notes on how to run unit tests [here](https://github.com/emberjs/data#how-to-run-unit-tests). (To see tests in the browser, +run `grunt dev` and open `http://localhost:9997/tests/?package=all`.) 3. Add a test for your change. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, we need From 32db3f6cbcc2b52619fccc0761a9505bf1914074 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 29 Jan 2014 21:37:10 -0500 Subject: [PATCH 0061/2527] Improved assertion if an non-ember-data model has snuck in this far. We need to come up with a strategy to simulate some sort of type safety.. --- packages/ember-data/lib/system/store.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index e3774ba3fd1..cd648f681b4 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1253,6 +1253,7 @@ Store = Ember.Object.extend({ idToRecord = typeMap.idToRecord; Ember.assert('The id ' + id + ' has already been used with another record of type ' + type.toString() + '.', !id || !idToRecord[id]); + Ember.assert("`" + Ember.inspect(type)+ "` does not appear to be an ember-data model", (typeof type._create === 'function') ); // lookupFactory should really return an object that creates // instances with the injections applied From a1501e5a3894295e36854805b44889f80cd46447 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 30 Jan 2014 11:01:06 -0500 Subject: [PATCH 0062/2527] hasMany relationship property are essentially readOnly, lets mark them as such. This also fixes a potential issue with minified code changing the arity of these CPs. This happens because "value"'s only purpose is to increase the arity to 2, such that setting to this CP has no effect. Unfortunately, when minified it does have an effect. Also, allowing this property to be set to, even though it has no outcome, is just straight up misleading. --- .../lib/system/relationships/has_many.js | 8 ++--- .../relationships/has_many_test.js | 33 ++++++++++++++++--- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index 269a158e1ed..d363736e6d8 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -5,7 +5,7 @@ var get = Ember.get, set = Ember.set, setProperties = Ember.setProperties; function asyncHasMany(type, options, meta) { - return Ember.computed('data', function(key, value) { + return Ember.computed('data', function(key) { var relationship = this._relationships[key], promiseLabel = "DS: Async hasMany " + this + " : " + key; @@ -34,7 +34,7 @@ function asyncHasMany(type, options, meta) { return DS.PromiseArray.create({ promise: promise }); - }).meta(meta); + }).meta(meta).readOnly(); } function buildRelationship(record, key, options, callback) { @@ -68,13 +68,13 @@ function hasRelationship(type, options) { return asyncHasMany(type, options, meta); } - return Ember.computed('data', function(key, value) { + return Ember.computed('data', function(key) { return buildRelationship(this, key, options, function(store, data) { var records = data[key]; Ember.assert("You looked up the '" + key + "' relationship on '" + this + "' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", Ember.A(records).everyProperty('isEmpty', false)); return store.findMany(this, data[key], meta.type); }); - }).meta(meta); + }).meta(meta).readOnly(); } /** diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index f6e350984f7..904fcc4083e 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -330,10 +330,8 @@ test("When a record is created on the client, its async hasMany arrays should be comments: DS.hasMany('comment', { async: true }) }); - var post; - - Ember.run(function() { - post = env.store.createRecord('post'); + var post = Ember.run(function() { + return env.store.createRecord('post'); }); ok(get(post, 'isLoaded'), "The post should have isLoaded flag"); @@ -345,3 +343,30 @@ test("When a record is created on the client, its async hasMany arrays should be }); }); + +test("a records SYNC HM relationship property is readOnly", function(){ + expect(1); + var post = Ember.run(function() { + return env.store.createRecord('post'); + }); + + raises(function(){ + post.set('comments'); + }, 'Cannot Set: comments on: ' + Ember.inspect(post)); +}); + + +test("a records ASYNC HM relationship property is readOnly", function(){ + expect(1); + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + var post = Ember.run(function() { + return env.store.createRecord('post'); + }); + + raises(function(){ + post.set('comments'); + }, 'Cannot Set: comments on: ' + Ember.inspect(post)); +}); From fbabbda32cccf43d79782bbcaa3192fbeecaeb18 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 31 Jan 2014 10:28:48 -0500 Subject: [PATCH 0063/2527] reduce reusing argument variables, as it reduces clarity and makes debugging harder. --- packages/ember-data/lib/system/store.js | 39 +++++++++++++++---------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index cd648f681b4..ef61b83b94f 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1582,9 +1582,9 @@ function _find(adapter, store, type, id) { var promise = adapter.find(store, type, id), serializer = serializerForAdapter(adapter, type); - return Promise.cast(promise, "DS: Handle Adapter#find of " + type + " with id: " + id).then(function(payload) { - Ember.assert("You made a request for a " + type.typeKey + " with id " + id + ", but the adapter's response did not have any data", payload); - payload = serializer.extract(store, type, payload, id, 'find'); + return Promise.cast(promise, "DS: Handle Adapter#find of " + type + " with id: " + id).then(function(adapterPayload) { + Ember.assert("You made a request for a " + type.typeKey + " with id " + id + ", but the adapter's response did not have any data", adapterPayload); + var payload = serializer.extract(store, type, adapterPayload, id, 'find'); return store.push(type, payload); }, function(error) { @@ -1598,8 +1598,8 @@ function _findMany(adapter, store, type, ids, owner) { var promise = adapter.findMany(store, type, ids, owner), serializer = serializerForAdapter(adapter, type); - return Promise.cast(promise, "DS: Handle Adapter#findMany of " + type).then(function(payload) { - payload = serializer.extract(store, type, payload, null, 'findMany'); + return Promise.cast(promise, "DS: Handle Adapter#findMany of " + type).then(function(adapterPayload) { + var payload = serializer.extract(store, type, adapterPayload, null, 'findMany'); Ember.assert("The response from a findMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1611,8 +1611,8 @@ function _findHasMany(adapter, store, record, link, relationship) { var promise = adapter.findHasMany(store, record, link, relationship), serializer = serializerForAdapter(adapter, relationship.type); - return Promise.cast(promise, "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type).then(function(payload) { - payload = serializer.extract(store, relationship.type, payload, null, 'findHasMany'); + return Promise.cast(promise, "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type).then(function(adapterPayload) { + var payload = serializer.extract(store, relationship.type, adapterPayload, null, 'findHasMany'); Ember.assert("The response from a findHasMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1625,10 +1625,10 @@ function _findBelongsTo(adapter, store, record, link, relationship) { var promise = adapter.findBelongsTo(store, record, link, relationship), serializer = serializerForAdapter(adapter, relationship.type); - return Promise.cast(promise, "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type).then(function(payload) { - payload = serializer.extract(store, relationship.type, payload, null, 'findBelongsTo'); - + return Promise.cast(promise, "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type).then(function(adapterPayload) { + var payload = serializer.extract(store, relationship.type, adapterPayload, null, 'findBelongsTo'); var record = store.push(relationship.type, payload); + record.updateBelongsTo(relationship.key, record); return record; }, null, "DS: Extract payload of " + record + " : " + relationship.type); @@ -1638,8 +1638,8 @@ function _findAll(adapter, store, type, sinceToken) { var promise = adapter.findAll(store, type, sinceToken), serializer = serializerForAdapter(adapter, type); - return Promise.cast(promise, "DS: Handle Adapter#findAll of " + type).then(function(payload) { - payload = serializer.extract(store, type, payload, null, 'findAll'); + return Promise.cast(promise, "DS: Handle Adapter#findAll of " + type).then(function(adapterPayload) { + var payload = serializer.extract(store, type, adapterPayload, null, 'findAll'); Ember.assert("The response from a findAll must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1653,8 +1653,8 @@ function _findQuery(adapter, store, type, query, recordArray) { var promise = adapter.findQuery(store, type, query, recordArray), serializer = serializerForAdapter(adapter, type); - return Promise.cast(promise, "DS: Handle Adapter#findQuery of " + type).then(function(payload) { - payload = serializer.extract(store, type, payload, null, 'findQuery'); + return Promise.cast(promise, "DS: Handle Adapter#findQuery of " + type).then(function(adapterPayload) { + var payload = serializer.extract(store, type, adapterPayload, null, 'findQuery'); Ember.assert("The response from a findQuery must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1670,8 +1670,15 @@ function _commit(adapter, store, operation, record) { Ember.assert("Your adapter's '" + operation + "' method must return a promise, but it returned " + promise, isThenable(promise)); - return promise.then(function(payload) { - if (payload) { payload = serializer.extract(store, type, payload, get(record, 'id'), operation); } + return promise.then(function(adapterPayload) { + var payload; + + if (adapterPayload) { + payload = serializer.extract(store, type, adapterPayload, get(record, 'id'), operation); + } else { + payload = adapterPayload; + } + store.didSaveRecord(record, payload); return record; }, function(reason) { From 85542902d5816e7dc78af7665102fd79becf000d Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 31 Jan 2014 10:44:16 -0500 Subject: [PATCH 0064/2527] create promise labels outside of already visually complex code-paths --- packages/ember-data/lib/system/store.js | 35 +++++++++++++++---------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index ef61b83b94f..ef39894cb63 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1580,9 +1580,10 @@ function serializerForAdapter(adapter, type) { function _find(adapter, store, type, id) { var promise = adapter.find(store, type, id), - serializer = serializerForAdapter(adapter, type); + serializer = serializerForAdapter(adapter, type), + label = "DS: Handle Adapter#find of " + type + " with id: " + id; - return Promise.cast(promise, "DS: Handle Adapter#find of " + type + " with id: " + id).then(function(adapterPayload) { + return Promise.cast(promise, label).then(function(adapterPayload) { Ember.assert("You made a request for a " + type.typeKey + " with id " + id + ", but the adapter's response did not have any data", adapterPayload); var payload = serializer.extract(store, type, adapterPayload, id, 'find'); @@ -1596,9 +1597,10 @@ function _find(adapter, store, type, id) { function _findMany(adapter, store, type, ids, owner) { var promise = adapter.findMany(store, type, ids, owner), - serializer = serializerForAdapter(adapter, type); + serializer = serializerForAdapter(adapter, type), + label = "DS: Handle Adapter#findMany of " + type; - return Promise.cast(promise, "DS: Handle Adapter#findMany of " + type).then(function(adapterPayload) { + return Promise.cast(promise, label).then(function(adapterPayload) { var payload = serializer.extract(store, type, adapterPayload, null, 'findMany'); Ember.assert("The response from a findMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1609,9 +1611,10 @@ function _findMany(adapter, store, type, ids, owner) { function _findHasMany(adapter, store, record, link, relationship) { var promise = adapter.findHasMany(store, record, link, relationship), - serializer = serializerForAdapter(adapter, relationship.type); + serializer = serializerForAdapter(adapter, relationship.type), + label = "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type; - return Promise.cast(promise, "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type).then(function(adapterPayload) { + return Promise.cast(promise, label).then(function(adapterPayload) { var payload = serializer.extract(store, relationship.type, adapterPayload, null, 'findHasMany'); Ember.assert("The response from a findHasMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1623,9 +1626,10 @@ function _findHasMany(adapter, store, record, link, relationship) { function _findBelongsTo(adapter, store, record, link, relationship) { var promise = adapter.findBelongsTo(store, record, link, relationship), - serializer = serializerForAdapter(adapter, relationship.type); + serializer = serializerForAdapter(adapter, relationship.type), + label = "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type; - return Promise.cast(promise, "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type).then(function(adapterPayload) { + return Promise.cast(promise, label).then(function(adapterPayload) { var payload = serializer.extract(store, relationship.type, adapterPayload, null, 'findBelongsTo'); var record = store.push(relationship.type, payload); @@ -1636,9 +1640,10 @@ function _findBelongsTo(adapter, store, record, link, relationship) { function _findAll(adapter, store, type, sinceToken) { var promise = adapter.findAll(store, type, sinceToken), - serializer = serializerForAdapter(adapter, type); + serializer = serializerForAdapter(adapter, type), + label = "DS: Handle Adapter#findAll of " + type; - return Promise.cast(promise, "DS: Handle Adapter#findAll of " + type).then(function(adapterPayload) { + return Promise.cast(promise, label).then(function(adapterPayload) { var payload = serializer.extract(store, type, adapterPayload, null, 'findAll'); Ember.assert("The response from a findAll must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1651,9 +1656,10 @@ function _findAll(adapter, store, type, sinceToken) { function _findQuery(adapter, store, type, query, recordArray) { var promise = adapter.findQuery(store, type, query, recordArray), - serializer = serializerForAdapter(adapter, type); + serializer = serializerForAdapter(adapter, type), + label = "DS: Handle Adapter#findQuery of " + type; - return Promise.cast(promise, "DS: Handle Adapter#findQuery of " + type).then(function(adapterPayload) { + return Promise.cast(promise, label).then(function(adapterPayload) { var payload = serializer.extract(store, type, adapterPayload, null, 'findQuery'); Ember.assert("The response from a findQuery must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1666,7 +1672,8 @@ function _findQuery(adapter, store, type, query, recordArray) { function _commit(adapter, store, operation, record) { var type = record.constructor, promise = adapter[operation](store, type, record), - serializer = serializerForAdapter(adapter, type); + serializer = serializerForAdapter(adapter, type), + label = "DS: Extract and notify about " + operation + " completion of " + record; Ember.assert("Your adapter's '" + operation + "' method must return a promise, but it returned " + promise, isThenable(promise)); @@ -1689,7 +1696,7 @@ function _commit(adapter, store, operation, record) { } throw reason; - }, "DS: Extract and notify about " + operation + " completion of " + record); + }, label); } export {Store, PromiseArray, PromiseObject}; From 2690c56a1151b84b40c3925730fe5db3a04c6f5e Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 31 Jan 2014 11:44:43 -0500 Subject: [PATCH 0065/2527] A records initial currentState can be on the prototype. Not need in doing the extra set on each init --- packages/ember-data/lib/system/model/model.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index d202e51d7c2..024d9092a61 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -268,7 +268,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @private @type {Object} */ - currentState: null, + currentState: RootState.empty, /** When the record is in the `invalid` state this object will contain @@ -393,7 +393,6 @@ var Model = Ember.Object.extend(Ember.Evented, { _data: null, init: function() { - set(this, 'currentState', DS.RootState.empty); this._super(); this._setup(); }, From 61996fb027390c446c700b86ee5e533ed5b9851e Mon Sep 17 00:00:00 2001 From: bmac Date: Sat, 1 Feb 2014 16:02:48 -0500 Subject: [PATCH 0066/2527] Wait on all the findMany promises to resolve before resolving the store#fetchMany promise. --- packages/ember-data/lib/system/store.js | 6 ++- .../tests/unit/store/adapter_interop_test.js | 42 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index ef39894cb63..1dcd205c00f 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -494,6 +494,8 @@ Store = Ember.Object.extend({ recordsByTypeMap.get(record.constructor).push(record); }); + var promises = []; + forEach(recordsByTypeMap, function(type, records) { var ids = records.mapProperty('id'), adapter = this.adapterFor(type); @@ -501,8 +503,10 @@ Store = Ember.Object.extend({ Ember.assert("You tried to load many records but you have no adapter (for " + type + ")", adapter); Ember.assert("You tried to load many records but your adapter does not implement `findMany`", adapter.findMany); - resolver.resolve(_findMany(adapter, this, type, ids, owner)); + promises.push(_findMany(adapter, this, type, ids, owner)); }, this); + + resolver.resolve(Ember.RSVP.all(promises)); }, /** diff --git a/packages/ember-data/tests/unit/store/adapter_interop_test.js b/packages/ember-data/tests/unit/store/adapter_interop_test.js index f3501229b5f..a8e4c8e7ca7 100644 --- a/packages/ember-data/tests/unit/store/adapter_interop_test.js +++ b/packages/ember-data/tests/unit/store/adapter_interop_test.js @@ -305,3 +305,45 @@ test("records inside a collection view should have their ids updated", function( container.destroy(); })); }); + + +test("store.fetchMany should not resolve until all the records are resolve", function() { + var Person = DS.Model.extend(); + var Phone = DS.Model.extend(); + + var adapter = TestAdapter.extend({ + findMany: function(store, type, ids) { + var wait = (type === Person)? 5 : 15; + + var records = ids.map(function(id) { + return {id: id}; + }); + + return new Ember.RSVP.Promise(function(resolve, reject) { + Ember.run.later(function() { + resolve(records); + }, wait); + }); + } + }); + + var store = createStore({ + adapter: adapter + }); + + + var owner = store.createRecord(Person), + resolver = Ember.RSVP.defer(); + + var records = Ember.A([ + store.recordForId(Person, 10), + store.recordForId(Phone, 20), + store.recordForId(Phone, 21) + ]); + + store.fetchMany(records, owner, resolver); + resolver.promise.then(async(function() { + var unloadedRecords = records.filterBy('isEmpty'); + equal(get(unloadedRecords, 'length'), 0, 'All unloaded records should be loaded'); + })); +}); From f34d87a0e8d4ed94a30b86ef07b3cf476748c3f6 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 5 Feb 2014 15:49:15 -0500 Subject: [PATCH 0067/2527] remove unneeded and misleading "async" test helpers --- .../unit/model/lifecycle_callbacks_test.js | 26 +++---- .../ember-data/tests/unit/model/merge_test.js | 8 +-- .../tests/unit/model/relationships_test.js | 72 +++++++++---------- .../tests/unit/model/rollback_test.js | 8 +-- packages/ember-data/tests/unit/model_test.js | 52 +++++++------- .../tests/unit/record_array_test.js | 12 ++-- .../tests/unit/store/adapter_interop_test.js | 27 ++++--- .../ember-data/tests/unit/store/push_test.js | 16 ++--- .../tests/unit/store/unload_test.js | 16 ++--- 9 files changed, 118 insertions(+), 119 deletions(-) diff --git a/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js b/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js index 4898ae3ef06..cd99dda2b70 100644 --- a/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js +++ b/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js @@ -20,10 +20,10 @@ test("a record receives a didLoad callback when it has finished loading", functi adapter: adapter }); - store.find(Person, 1).then(async(function(person) { + store.find(Person, 1).then(function(person) { equal(person.get('id'), "1", "The person's ID is available"); equal(person.get('name'), "Foo", "The person's properties are available"); - })); + }); }); test("a record receives a didUpdate callback when it has finished updating", function() { @@ -58,12 +58,12 @@ test("a record receives a didUpdate callback when it has finished updating", fun var asyncPerson = store.find(Person, 1); equal(callCount, 0, "precond - didUpdate callback was not called yet"); - asyncPerson.then(async(function(person) { + asyncPerson.then(function(person) { person.set('bar', "Bar"); return person.save(); - })).then(async(function() { + }).then(function() { equal(callCount, 1, "didUpdate called after update"); - })); + }); }); test("a record receives a didCreate callback when it has finished updating", function() { @@ -93,9 +93,9 @@ test("a record receives a didCreate callback when it has finished updating", fun var person = store.createRecord(Person, { id: 69, name: "Newt Gingrich" }); - person.save().then(async(function() { + person.save().then(function() { equal(callCount, 1, "didCreate called after commit"); - })); + }); }); test("a record receives a didDelete callback when it has finished deleting", function() { @@ -131,12 +131,12 @@ test("a record receives a didDelete callback when it has finished deleting", fun var asyncPerson = store.find(Person, 1); equal(callCount, 0, "precond - didDelete callback was not called yet"); - asyncPerson.then(async(function(person) { + asyncPerson.then(function(person) { person.deleteRecord(); return person.save(); - })).then(async(function() { + }).then(function() { equal(callCount, 1, "didDelete called after delete"); - })); + }); }); test("a record receives a becameInvalid callback when it became invalid", function() { @@ -175,12 +175,12 @@ test("a record receives a becameInvalid callback when it became invalid", functi // Make sure that the error handler has a chance to attach before // save fails. Ember.run(function() { - asyncPerson.then(async(function(person) { + asyncPerson.then(function(person) { person.set('bar', "Bar"); return person.save(); - })).then(null, async(function() { + }).then(null, function() { equal(callCount, 1, "becameInvalid called after invalidating"); - })); + }); }); }); diff --git a/packages/ember-data/tests/unit/model/merge_test.js b/packages/ember-data/tests/unit/model/merge_test.js index e52ee1c1290..e402988113d 100644 --- a/packages/ember-data/tests/unit/model/merge_test.js +++ b/packages/ember-data/tests/unit/model/merge_test.js @@ -101,9 +101,9 @@ test("A record with no changes can still be saved", function() { var person = store.push(Person, { id: 1, name: "Tom Dale" }); - person.save().then(async(function() { + person.save().then(function() { equal(person.get('name'), "Thomas Dale", "the updates occurred"); - })); + }); }); test("A dirty record can be reloaded", function() { @@ -119,9 +119,9 @@ test("A dirty record can be reloaded", function() { person.set('name', "Tomasz Dale"); - person.reload().then(async(function() { + person.reload().then(function() { equal(person.get('isDirty'), true, "the person is dirty"); equal(person.get('name'), "Tomasz Dale", "the local changes remain"); equal(person.get('city'), "Portland", "the new changes apply"); - })); + }); }); diff --git a/packages/ember-data/tests/unit/model/relationships_test.js b/packages/ember-data/tests/unit/model/relationships_test.js index 36d407bf8ea..e75c842bea7 100644 --- a/packages/ember-data/tests/unit/model/relationships_test.js +++ b/packages/ember-data/tests/unit/model/relationships_test.js @@ -72,7 +72,7 @@ test("hasMany handles pre-loaded relationships", function() { var wycats; - store.find('person', 1).then(async(function(person) { + store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); var tags = get(person, 'tags'); @@ -89,12 +89,12 @@ test("hasMany handles pre-loaded relationships", function() { store.push('person', { id: 3, name: "KSelden" }); return store.find('person', 3); - })).then(async(function(kselden) { + }).then(function(kselden) { equal(get(get(kselden, 'tags'), 'length'), 0, "a relationship that has not been supplied returns an empty array"); store.push('person', { id: 4, name: "Cyvid Hamluck", pets: [4] }); return store.find('person', 4); - })).then(async(function(cyvid) { + }).then(function(cyvid) { equal(get(cyvid, 'name'), "Cyvid Hamluck", "precond - retrieves person record from store"); var pets = get(cyvid, 'pets'); @@ -104,7 +104,7 @@ test("hasMany handles pre-loaded relationships", function() { store.push(Person, { id: 4, name: "Cyvid Hamluck", pets: [4, 12] }); equal(pets, get(cyvid, 'pets'), "a relationship returns the same object every time"); equal(get(get(cyvid, 'pets'), 'length'), 2, "the length is updated after new data is loaded"); - })); + }); }); test("hasMany lazily loads async relationships", function() { @@ -154,7 +154,7 @@ test("hasMany lazily loads async relationships", function() { wycats: wycats, tags: wycats.get('tags') }); - })).then(async(function(records) { + })).then(function(records) { equal(get(records.tags, 'length'), 1, "the list of tags should have the correct length"); equal(get(records.tags.objectAt(0), 'name'), "oohlala", "the first tag should be a Tag"); @@ -162,10 +162,10 @@ test("hasMany lazily loads async relationships", function() { asyncEqual(records.tags.objectAt(0), store.find(Tag, 12), "relationship objects are the same as objects retrieved directly"); return get(wycats, 'tags'); - })).then(async(function(tags) { + }).then(function(tags) { var newTag = store.createRecord(Tag); tags.pushObject(newTag); - })); + }); }); test("should be able to retrieve the type for a hasMany relationship from its metadata", function() { @@ -255,10 +255,10 @@ test("relationships work when declared with a string path", function() { env.store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); env.store.push('person', { id: 1, name: "Tom Dale", tags: [5, 2] }); - env.store.find('person', 1).then(async(function(person) { + env.store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); equal(get(person, 'tags.length'), 2, "the list of tags should have the correct length"); - })); + }); }); test("hasMany relationships work when the data hash has not been loaded", function() { @@ -293,15 +293,15 @@ test("hasMany relationships work when the data hash has not been loaded", functi return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", tags: [5, 2] }); }; - store.find('person', 1).then(async(function(person) { + store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return person.get('tags'); - })).then(async(function(tags) { + }).then(function(tags) { equal(get(tags, 'length'), 2, "the tags object still exists"); equal(get(tags.objectAt(0), 'name'), "friendly", "Tom Dale is now friendly"); equal(get(tags.objectAt(0), 'isLoaded'), true, "Tom Dale is now loaded"); - })); + }); }); test("it is possible to add a new item to a relationship", function() { @@ -325,7 +325,7 @@ test("it is possible to add a new item to a relationship", function() { store.push('person', { id: 1, name: "Tom Dale", tags: [ 1 ] }); store.push('tag', { id: 1, name: "ember" }); - store.find(Person, 1).then(async(function(person) { + store.find(Person, 1).then(function(person) { var tag = get(person, 'tags').objectAt(0); equal(get(tag, 'name'), "ember", "precond - relationships work"); @@ -334,7 +334,7 @@ test("it is possible to add a new item to a relationship", function() { get(person, 'tags').pushObject(tag); equal(get(person, 'tags').objectAt(1), tag, "newly added relationship works"); - })); + }); }); test("it is possible to remove an item from a relationship", function() { @@ -354,7 +354,7 @@ test("it is possible to remove an item from a relationship", function() { store.push('person', { id: 1, name: "Tom Dale", tags: [ 1 ] }); store.push('tag', { id: 1, name: "ember" }); - store.find('person', 1).then(async(function(person) { + store.find('person', 1).then(function(person) { var tag = get(person, 'tags').objectAt(0); equal(get(tag, 'name'), "ember", "precond - relationships work"); @@ -362,7 +362,7 @@ test("it is possible to remove an item from a relationship", function() { get(person, 'tags').removeObject(tag); equal(get(person, 'tags.length'), 0, "object is removed from the relationship"); - })); + }); }); test("it is possible to add an item to a relationship, remove it, then add it again", function() { @@ -440,13 +440,13 @@ test("can create child record from a hasMany relationship", function() { store.push('person', { id: 1, name: "Tom Dale"}); - store.find('person', 1).then(async(function(person) { + store.find('person', 1).then(function(person) { person.get("tags").createRecord({ name: "cool" }); equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); equal(get(person, 'tags.length'), 1, "tag is added to the parent record"); equal(get(person, 'tags').objectAt(0).get("name"), "cool", "tag values are passed along"); - })); + }); }); module("unit/model/relationships - DS.belongsTo"); @@ -470,7 +470,7 @@ test("belongsTo lazily loads relationships as needed", function() { store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); store.push('person', { id: 1, name: "Tom Dale", tag: 5 }); - store.find('person', 1).then(async(function(person) { + store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); @@ -478,7 +478,7 @@ test("belongsTo lazily loads relationships as needed", function() { strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); asyncEqual(get(person, 'tag'), store.find('tag', 5), "relationship object is the same as object retrieved directly"); - })); + }); }); test("async belongsTo relationships work when the data hash has not been loaded", function() { @@ -506,14 +506,14 @@ test("async belongsTo relationships work when the data hash has not been loaded" } }; - store.find('person', 1).then(async(function(person) { + store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return get(person, 'tag'); - })).then(async(function(tag) { + }).then(function(tag) { equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); - })); + }); }); test("async belongsTo relationships work when the data hash has already been loaded", function() { @@ -532,13 +532,13 @@ test("async belongsTo relationships work when the data hash has already been loa store.push('tag', { id: 2, name: "friendly"}); store.push('person', { id: 1, name: "Tom Dale", tag: 2}); - store.find('person', 1).then(async(function(person) { + store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return get(person, 'tag'); - })).then(async(function(tag) { + }).then(function(tag) { equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); - })); + }); }); test("calling createRecord and passing in an undefined value for a relationship should be treated as if null", function () { @@ -557,9 +557,9 @@ test("calling createRecord and passing in an undefined value for a relationship store.createRecord('person', {id: 1, tag: undefined}); - store.find(Person, 1).then(async(function(person) { + store.find(Person, 1).then(function(person) { strictEqual(person.get('tag'), null, "undefined values should return null relationships"); - })); + }); }); test("findMany is passed the owner record for adapters when some of the object graph is already loaded", function() { @@ -590,17 +590,17 @@ test("findMany is passed the owner record for adapters when some of the object g store.push('person', { id: 1, name: "Tom Dale", occupations: [5, 2] }); - store.find('person', 1).then(async(function(person) { + store.find('person', 1).then(function(person) { equal(get(person, 'isLoaded'), true, "isLoaded should be true"); equal(get(person, 'name'), "Tom Dale", "the person is still Tom Dale"); return get(person, 'occupations'); - })).then(async(function(occupations) { + }).then(function(occupations) { equal(get(occupations, 'length'), 2, "the list of occupations should have the correct length"); equal(get(occupations.objectAt(0), 'description'), "fifth", "the occupation is the fifth"); equal(get(occupations.objectAt(0), 'isLoaded'), true, "the occupation is now loaded"); - })); + }); }); test("findMany is passed the owner record for adapters when none of the object graph is loaded", function() { @@ -636,15 +636,15 @@ test("findMany is passed the owner record for adapters when none of the object g return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", occupations: [5, 2] }); }; - store.find('person', 1).then(async(function(person) { + store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return get(person, 'occupations'); - })).then(async(function(occupations) { + }).then(function(occupations) { equal(get(occupations, 'length'), 2, "the occupation objects still exist"); equal(get(occupations.objectAt(0), 'description'), "fifth", "the occupation is the fifth"); equal(get(occupations.objectAt(0), 'isLoaded'), true, "the occupation is now loaded"); - })); + }); }); test("belongsTo supports relationships to models with id 0", function() { @@ -666,7 +666,7 @@ test("belongsTo supports relationships to models with id 0", function() { store.pushMany('tag', [{ id: 0, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); store.push('person', { id: 1, name: "Tom Dale", tag: 0 }); - store.find('person', 1).then(async(function(person) { + store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); @@ -674,5 +674,5 @@ test("belongsTo supports relationships to models with id 0", function() { strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); asyncEqual(get(person, 'tag'), store.find(Tag, 0), "relationship object is the same as object retrieved directly"); - })); + }); }); diff --git a/packages/ember-data/tests/unit/model/rollback_test.js b/packages/ember-data/tests/unit/model/rollback_test.js index 92ffa91060a..1ccdee44207 100644 --- a/packages/ember-data/tests/unit/model/rollback_test.js +++ b/packages/ember-data/tests/unit/model/rollback_test.js @@ -50,9 +50,9 @@ test("changes to attributes made after a record is in-flight only rolls back the equal(person.get('lastName'), "Dale"); equal(person.get('isSaving'), true); - saving.then(async(function() { + saving.then(function() { equal(person.get('isDirty'), false, "The person is now clean"); - })); + }); }); }); @@ -65,14 +65,14 @@ test("a record's changes can be made if it fails to save", function() { person.set('firstName', "Thomas"); - person.save().then(null, async(function() { + person.save().then(null, function() { equal(person.get('isError'), true); person.rollback(); equal(person.get('firstName'), "Tom"); equal(person.get('isError'), false); - })); + }); }); test("new record can be rollbacked", function() { diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index 58159011c11..8b8f28b6a35 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -27,39 +27,39 @@ test("can have a property set on it", function() { test("setting a property on a record that has not changed does not cause it to become dirty", function() { store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); - store.find(Person, 1).then(async(function(person) { + store.find(Person, 1).then(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); person.set('name', "Peter"); person.set('isDrugAddict', true); equal(person.get('isDirty'), false, "record does not become dirty after setting property to old value"); - })); + }); }); test("resetting a property on a record cause it to become clean again", function() { store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); - store.find(Person, 1).then(async(function(person) { + store.find(Person, 1).then(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); person.set('isDrugAddict', false); equal(person.get('isDirty'), true, "record becomes dirty after setting property to a new value"); person.set('isDrugAddict', true); equal(person.get('isDirty'), false, "record becomes clean after resetting property to the old value"); - })); + }); }); test("a record reports its unique id via the `id` property", function() { store.push(Person, { id: 1 }); - store.find(Person, 1).then(async(function(record) { + store.find(Person, 1).then(function(record) { equal(get(record, 'id'), 1, "reports id as id by default"); - })); + }); }); test("a record's id is included in its toString representation", function() { store.push(Person, { id: 1 }); - store.find(Person, 1).then(async(function(record) { + store.find(Person, 1).then(function(record) { equal(record.toString(), '<(subclass of DS.Model):'+Ember.guidFor(record)+':1>', "reports id in toString"); - })); + }); }); test("trying to set an `id` attribute should raise", function() { @@ -77,9 +77,9 @@ test("trying to set an `id` attribute should raise", function() { test("it should use `_reference` and not `reference` to store its reference", function() { store.push(Person, { id: 1 }); - store.find(Person, 1).then(async(function(record) { + store.find(Person, 1).then(function(record) { equal(record.get('reference'), undefined, "doesn't shadow reference key"); - })); + }); }); test("it should cache attributes", function() { @@ -94,11 +94,11 @@ test("it should cache attributes", function() { store.push(Post, { id: 1 }); - store.find(Post, 1).then(async(function(record) { + store.find(Post, 1).then(function(record) { record.set('updatedAt', date); deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); strictEqual(get(record, 'updatedAt'), get(record, 'updatedAt'), "second get still returns the same object"); - })); + }); }); module("unit/model - DS.Model updating", { @@ -116,10 +116,10 @@ module("unit/model - DS.Model updating", { }); test("a DS.Model can update its attributes", function() { - store.find(Person, 2).then(async(function(person) { + store.find(Person, 2).then(function(person) { set(person, 'name', "Brohuda Katz"); equal(get(person, 'name'), "Brohuda Katz", "setting took hold"); - })); + }); }); test("a DS.Model can have a defaultValue", function() { @@ -186,7 +186,7 @@ test("setting a property to undefined on a newly created record should not impac // NOTE: this is a 'backdoor' test that ensures internal consistency, and should be // thrown out if/when the current `_attributes` hash logic is removed. test("setting a property back to its original value removes the property from the `_attributes` hash", function() { - store.find(Person, 1).then(async(function(person) { + store.find(Person, 1).then(function(person) { equal(person._attributes.name, undefined, "the `_attributes` hash is clean"); set(person, 'name', "Niceguy Dale"); @@ -196,7 +196,7 @@ test("setting a property back to its original value removes the property from th set(person, 'name', "Scumbag Dale"); equal(person._attributes.name, undefined, "the `_attributes` hash is reset"); - })); + }); }); module("unit/model - with a simple Person model", { @@ -277,9 +277,9 @@ var converts = function(type, provided, expected) { testStore.push(Model, serializer.normalize(Model, { id: 1, name: provided })); testStore.push(Model, serializer.normalize(Model, { id: 2 })); - testStore.find('model', 1).then(async(function(record) { + testStore.find('model', 1).then(function(record) { deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); - })); + }); // See: Github issue #421 // record = testStore.find(Model, 2); @@ -298,9 +298,9 @@ var convertsFromServer = function(type, provided, expected) { serializer = DS.JSONSerializer.create({ store: testStore, container: container }); testStore.push(Model, serializer.normalize(Model, { id: "1", name: provided })); - testStore.find('model', 1).then(async(function(record) { + testStore.find('model', 1).then(function(record) { deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); - })); + }); }; var convertsWhenSet = function(type, provided, expected) { @@ -311,10 +311,10 @@ var convertsWhenSet = function(type, provided, expected) { var testStore = createStore({model: Model}); testStore.push(Model, { id: 2 }); - var record = testStore.find('model', 2).then(async(function(record) { + var record = testStore.find('model', 2).then(function(record) { set(record, 'name', provided); deepEqual(record.serialize().name, expected, type + " saves " + provided + " as " + expected); - })); + }); }; test("a DS.Model can describe String attributes", function() { @@ -362,10 +362,10 @@ test("a DS.Model can describe Date attributes", function() { }); store.push(Person, { id: 1 }); - store.find(Person, 1).then(async(function(record) { + store.find(Person, 1).then(function(record) { record.set('updatedAt', date); deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); - })); + }); convertsFromServer('date', dateString, date); convertsWhenSet('date', date, dateString); @@ -391,10 +391,10 @@ test("ensure model exits loading state, materializes data and fulfills promise o }) }); - store.find(Person, 1).then(async(function(person) { + store.find(Person, 1).then(function(person) { equal(get(person, 'currentState.stateName'), 'root.loaded.saved', 'model is in loaded state'); equal(get(person, 'isLoaded'), true, 'model is loaded'); - })); + }); }); test("A DS.Model can be JSONified", function() { diff --git a/packages/ember-data/tests/unit/record_array_test.js b/packages/ember-data/tests/unit/record_array_test.js index 870a6fb25ec..578ac4d50b5 100644 --- a/packages/ember-data/tests/unit/record_array_test.js +++ b/packages/ember-data/tests/unit/record_array_test.js @@ -17,11 +17,11 @@ test("a record array is backed by records", function() { var store = createStore(); store.pushMany(Person, array); - store.findByIds(Person, [1,2,3]).then(async(function(records) { + store.findByIds(Person, [1,2,3]).then(function(records) { for (var i=0, l=get(array, 'length'); i Date: Wed, 5 Feb 2014 16:26:24 -0500 Subject: [PATCH 0068/2527] Break Down JSONSerializer#serializeBelongsTo Test There were multiple assertions in "serializeBelongsTo" test. Break it into two to make things easier to understand. --- .../tests/integration/serializers/json_serializer_test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index ce78ec5025b..ddfe9b8a915 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -62,17 +62,17 @@ test("serializeBelongsTo", function() { deepEqual(json, { post: "1" }); +}); - json = {}; - - set(comment, 'post', null); +test("serializeBelongsTo with null", function() { + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: null}); + var json = {}; env.serializer.serializeBelongsTo(comment, json, {key: "post", options: {}}); deepEqual(json, { post: null }, "Can set a belongsTo to a null value"); - }); test("serializeBelongsTo respects keyForRelationship", function() { From e6ed22d8cdbe17d1be4cd9b0086eef64772c1e08 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 5 Feb 2014 16:39:08 -0500 Subject: [PATCH 0069/2527] Revert "remove unneeded and misleading "async" test helpers" This reverts commit f34d87a0e8d4ed94a30b86ef07b3cf476748c3f6. Failures on beta tests, will invetigate shortly. --- .../unit/model/lifecycle_callbacks_test.js | 26 +++---- .../ember-data/tests/unit/model/merge_test.js | 8 +-- .../tests/unit/model/relationships_test.js | 72 +++++++++---------- .../tests/unit/model/rollback_test.js | 8 +-- packages/ember-data/tests/unit/model_test.js | 52 +++++++------- .../tests/unit/record_array_test.js | 12 ++-- .../tests/unit/store/adapter_interop_test.js | 27 +++---- .../ember-data/tests/unit/store/push_test.js | 16 ++--- .../tests/unit/store/unload_test.js | 16 ++--- 9 files changed, 119 insertions(+), 118 deletions(-) diff --git a/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js b/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js index cd99dda2b70..4898ae3ef06 100644 --- a/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js +++ b/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js @@ -20,10 +20,10 @@ test("a record receives a didLoad callback when it has finished loading", functi adapter: adapter }); - store.find(Person, 1).then(function(person) { + store.find(Person, 1).then(async(function(person) { equal(person.get('id'), "1", "The person's ID is available"); equal(person.get('name'), "Foo", "The person's properties are available"); - }); + })); }); test("a record receives a didUpdate callback when it has finished updating", function() { @@ -58,12 +58,12 @@ test("a record receives a didUpdate callback when it has finished updating", fun var asyncPerson = store.find(Person, 1); equal(callCount, 0, "precond - didUpdate callback was not called yet"); - asyncPerson.then(function(person) { + asyncPerson.then(async(function(person) { person.set('bar', "Bar"); return person.save(); - }).then(function() { + })).then(async(function() { equal(callCount, 1, "didUpdate called after update"); - }); + })); }); test("a record receives a didCreate callback when it has finished updating", function() { @@ -93,9 +93,9 @@ test("a record receives a didCreate callback when it has finished updating", fun var person = store.createRecord(Person, { id: 69, name: "Newt Gingrich" }); - person.save().then(function() { + person.save().then(async(function() { equal(callCount, 1, "didCreate called after commit"); - }); + })); }); test("a record receives a didDelete callback when it has finished deleting", function() { @@ -131,12 +131,12 @@ test("a record receives a didDelete callback when it has finished deleting", fun var asyncPerson = store.find(Person, 1); equal(callCount, 0, "precond - didDelete callback was not called yet"); - asyncPerson.then(function(person) { + asyncPerson.then(async(function(person) { person.deleteRecord(); return person.save(); - }).then(function() { + })).then(async(function() { equal(callCount, 1, "didDelete called after delete"); - }); + })); }); test("a record receives a becameInvalid callback when it became invalid", function() { @@ -175,12 +175,12 @@ test("a record receives a becameInvalid callback when it became invalid", functi // Make sure that the error handler has a chance to attach before // save fails. Ember.run(function() { - asyncPerson.then(function(person) { + asyncPerson.then(async(function(person) { person.set('bar', "Bar"); return person.save(); - }).then(null, function() { + })).then(null, async(function() { equal(callCount, 1, "becameInvalid called after invalidating"); - }); + })); }); }); diff --git a/packages/ember-data/tests/unit/model/merge_test.js b/packages/ember-data/tests/unit/model/merge_test.js index e402988113d..e52ee1c1290 100644 --- a/packages/ember-data/tests/unit/model/merge_test.js +++ b/packages/ember-data/tests/unit/model/merge_test.js @@ -101,9 +101,9 @@ test("A record with no changes can still be saved", function() { var person = store.push(Person, { id: 1, name: "Tom Dale" }); - person.save().then(function() { + person.save().then(async(function() { equal(person.get('name'), "Thomas Dale", "the updates occurred"); - }); + })); }); test("A dirty record can be reloaded", function() { @@ -119,9 +119,9 @@ test("A dirty record can be reloaded", function() { person.set('name', "Tomasz Dale"); - person.reload().then(function() { + person.reload().then(async(function() { equal(person.get('isDirty'), true, "the person is dirty"); equal(person.get('name'), "Tomasz Dale", "the local changes remain"); equal(person.get('city'), "Portland", "the new changes apply"); - }); + })); }); diff --git a/packages/ember-data/tests/unit/model/relationships_test.js b/packages/ember-data/tests/unit/model/relationships_test.js index e75c842bea7..36d407bf8ea 100644 --- a/packages/ember-data/tests/unit/model/relationships_test.js +++ b/packages/ember-data/tests/unit/model/relationships_test.js @@ -72,7 +72,7 @@ test("hasMany handles pre-loaded relationships", function() { var wycats; - store.find('person', 1).then(function(person) { + store.find('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); var tags = get(person, 'tags'); @@ -89,12 +89,12 @@ test("hasMany handles pre-loaded relationships", function() { store.push('person', { id: 3, name: "KSelden" }); return store.find('person', 3); - }).then(function(kselden) { + })).then(async(function(kselden) { equal(get(get(kselden, 'tags'), 'length'), 0, "a relationship that has not been supplied returns an empty array"); store.push('person', { id: 4, name: "Cyvid Hamluck", pets: [4] }); return store.find('person', 4); - }).then(function(cyvid) { + })).then(async(function(cyvid) { equal(get(cyvid, 'name'), "Cyvid Hamluck", "precond - retrieves person record from store"); var pets = get(cyvid, 'pets'); @@ -104,7 +104,7 @@ test("hasMany handles pre-loaded relationships", function() { store.push(Person, { id: 4, name: "Cyvid Hamluck", pets: [4, 12] }); equal(pets, get(cyvid, 'pets'), "a relationship returns the same object every time"); equal(get(get(cyvid, 'pets'), 'length'), 2, "the length is updated after new data is loaded"); - }); + })); }); test("hasMany lazily loads async relationships", function() { @@ -154,7 +154,7 @@ test("hasMany lazily loads async relationships", function() { wycats: wycats, tags: wycats.get('tags') }); - })).then(function(records) { + })).then(async(function(records) { equal(get(records.tags, 'length'), 1, "the list of tags should have the correct length"); equal(get(records.tags.objectAt(0), 'name'), "oohlala", "the first tag should be a Tag"); @@ -162,10 +162,10 @@ test("hasMany lazily loads async relationships", function() { asyncEqual(records.tags.objectAt(0), store.find(Tag, 12), "relationship objects are the same as objects retrieved directly"); return get(wycats, 'tags'); - }).then(function(tags) { + })).then(async(function(tags) { var newTag = store.createRecord(Tag); tags.pushObject(newTag); - }); + })); }); test("should be able to retrieve the type for a hasMany relationship from its metadata", function() { @@ -255,10 +255,10 @@ test("relationships work when declared with a string path", function() { env.store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); env.store.push('person', { id: 1, name: "Tom Dale", tags: [5, 2] }); - env.store.find('person', 1).then(function(person) { + env.store.find('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); equal(get(person, 'tags.length'), 2, "the list of tags should have the correct length"); - }); + })); }); test("hasMany relationships work when the data hash has not been loaded", function() { @@ -293,15 +293,15 @@ test("hasMany relationships work when the data hash has not been loaded", functi return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", tags: [5, 2] }); }; - store.find('person', 1).then(function(person) { + store.find('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return person.get('tags'); - }).then(function(tags) { + })).then(async(function(tags) { equal(get(tags, 'length'), 2, "the tags object still exists"); equal(get(tags.objectAt(0), 'name'), "friendly", "Tom Dale is now friendly"); equal(get(tags.objectAt(0), 'isLoaded'), true, "Tom Dale is now loaded"); - }); + })); }); test("it is possible to add a new item to a relationship", function() { @@ -325,7 +325,7 @@ test("it is possible to add a new item to a relationship", function() { store.push('person', { id: 1, name: "Tom Dale", tags: [ 1 ] }); store.push('tag', { id: 1, name: "ember" }); - store.find(Person, 1).then(function(person) { + store.find(Person, 1).then(async(function(person) { var tag = get(person, 'tags').objectAt(0); equal(get(tag, 'name'), "ember", "precond - relationships work"); @@ -334,7 +334,7 @@ test("it is possible to add a new item to a relationship", function() { get(person, 'tags').pushObject(tag); equal(get(person, 'tags').objectAt(1), tag, "newly added relationship works"); - }); + })); }); test("it is possible to remove an item from a relationship", function() { @@ -354,7 +354,7 @@ test("it is possible to remove an item from a relationship", function() { store.push('person', { id: 1, name: "Tom Dale", tags: [ 1 ] }); store.push('tag', { id: 1, name: "ember" }); - store.find('person', 1).then(function(person) { + store.find('person', 1).then(async(function(person) { var tag = get(person, 'tags').objectAt(0); equal(get(tag, 'name'), "ember", "precond - relationships work"); @@ -362,7 +362,7 @@ test("it is possible to remove an item from a relationship", function() { get(person, 'tags').removeObject(tag); equal(get(person, 'tags.length'), 0, "object is removed from the relationship"); - }); + })); }); test("it is possible to add an item to a relationship, remove it, then add it again", function() { @@ -440,13 +440,13 @@ test("can create child record from a hasMany relationship", function() { store.push('person', { id: 1, name: "Tom Dale"}); - store.find('person', 1).then(function(person) { + store.find('person', 1).then(async(function(person) { person.get("tags").createRecord({ name: "cool" }); equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); equal(get(person, 'tags.length'), 1, "tag is added to the parent record"); equal(get(person, 'tags').objectAt(0).get("name"), "cool", "tag values are passed along"); - }); + })); }); module("unit/model/relationships - DS.belongsTo"); @@ -470,7 +470,7 @@ test("belongsTo lazily loads relationships as needed", function() { store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); store.push('person', { id: 1, name: "Tom Dale", tag: 5 }); - store.find('person', 1).then(function(person) { + store.find('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); @@ -478,7 +478,7 @@ test("belongsTo lazily loads relationships as needed", function() { strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); asyncEqual(get(person, 'tag'), store.find('tag', 5), "relationship object is the same as object retrieved directly"); - }); + })); }); test("async belongsTo relationships work when the data hash has not been loaded", function() { @@ -506,14 +506,14 @@ test("async belongsTo relationships work when the data hash has not been loaded" } }; - store.find('person', 1).then(function(person) { + store.find('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return get(person, 'tag'); - }).then(function(tag) { + })).then(async(function(tag) { equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); - }); + })); }); test("async belongsTo relationships work when the data hash has already been loaded", function() { @@ -532,13 +532,13 @@ test("async belongsTo relationships work when the data hash has already been loa store.push('tag', { id: 2, name: "friendly"}); store.push('person', { id: 1, name: "Tom Dale", tag: 2}); - store.find('person', 1).then(function(person) { + store.find('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return get(person, 'tag'); - }).then(function(tag) { + })).then(async(function(tag) { equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); - }); + })); }); test("calling createRecord and passing in an undefined value for a relationship should be treated as if null", function () { @@ -557,9 +557,9 @@ test("calling createRecord and passing in an undefined value for a relationship store.createRecord('person', {id: 1, tag: undefined}); - store.find(Person, 1).then(function(person) { + store.find(Person, 1).then(async(function(person) { strictEqual(person.get('tag'), null, "undefined values should return null relationships"); - }); + })); }); test("findMany is passed the owner record for adapters when some of the object graph is already loaded", function() { @@ -590,17 +590,17 @@ test("findMany is passed the owner record for adapters when some of the object g store.push('person', { id: 1, name: "Tom Dale", occupations: [5, 2] }); - store.find('person', 1).then(function(person) { + store.find('person', 1).then(async(function(person) { equal(get(person, 'isLoaded'), true, "isLoaded should be true"); equal(get(person, 'name'), "Tom Dale", "the person is still Tom Dale"); return get(person, 'occupations'); - }).then(function(occupations) { + })).then(async(function(occupations) { equal(get(occupations, 'length'), 2, "the list of occupations should have the correct length"); equal(get(occupations.objectAt(0), 'description'), "fifth", "the occupation is the fifth"); equal(get(occupations.objectAt(0), 'isLoaded'), true, "the occupation is now loaded"); - }); + })); }); test("findMany is passed the owner record for adapters when none of the object graph is loaded", function() { @@ -636,15 +636,15 @@ test("findMany is passed the owner record for adapters when none of the object g return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", occupations: [5, 2] }); }; - store.find('person', 1).then(function(person) { + store.find('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return get(person, 'occupations'); - }).then(function(occupations) { + })).then(async(function(occupations) { equal(get(occupations, 'length'), 2, "the occupation objects still exist"); equal(get(occupations.objectAt(0), 'description'), "fifth", "the occupation is the fifth"); equal(get(occupations.objectAt(0), 'isLoaded'), true, "the occupation is now loaded"); - }); + })); }); test("belongsTo supports relationships to models with id 0", function() { @@ -666,7 +666,7 @@ test("belongsTo supports relationships to models with id 0", function() { store.pushMany('tag', [{ id: 0, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); store.push('person', { id: 1, name: "Tom Dale", tag: 0 }); - store.find('person', 1).then(function(person) { + store.find('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); @@ -674,5 +674,5 @@ test("belongsTo supports relationships to models with id 0", function() { strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); asyncEqual(get(person, 'tag'), store.find(Tag, 0), "relationship object is the same as object retrieved directly"); - }); + })); }); diff --git a/packages/ember-data/tests/unit/model/rollback_test.js b/packages/ember-data/tests/unit/model/rollback_test.js index 1ccdee44207..92ffa91060a 100644 --- a/packages/ember-data/tests/unit/model/rollback_test.js +++ b/packages/ember-data/tests/unit/model/rollback_test.js @@ -50,9 +50,9 @@ test("changes to attributes made after a record is in-flight only rolls back the equal(person.get('lastName'), "Dale"); equal(person.get('isSaving'), true); - saving.then(function() { + saving.then(async(function() { equal(person.get('isDirty'), false, "The person is now clean"); - }); + })); }); }); @@ -65,14 +65,14 @@ test("a record's changes can be made if it fails to save", function() { person.set('firstName', "Thomas"); - person.save().then(null, function() { + person.save().then(null, async(function() { equal(person.get('isError'), true); person.rollback(); equal(person.get('firstName'), "Tom"); equal(person.get('isError'), false); - }); + })); }); test("new record can be rollbacked", function() { diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index 8b8f28b6a35..58159011c11 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -27,39 +27,39 @@ test("can have a property set on it", function() { test("setting a property on a record that has not changed does not cause it to become dirty", function() { store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); - store.find(Person, 1).then(function(person) { + store.find(Person, 1).then(async(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); person.set('name', "Peter"); person.set('isDrugAddict', true); equal(person.get('isDirty'), false, "record does not become dirty after setting property to old value"); - }); + })); }); test("resetting a property on a record cause it to become clean again", function() { store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); - store.find(Person, 1).then(function(person) { + store.find(Person, 1).then(async(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); person.set('isDrugAddict', false); equal(person.get('isDirty'), true, "record becomes dirty after setting property to a new value"); person.set('isDrugAddict', true); equal(person.get('isDirty'), false, "record becomes clean after resetting property to the old value"); - }); + })); }); test("a record reports its unique id via the `id` property", function() { store.push(Person, { id: 1 }); - store.find(Person, 1).then(function(record) { + store.find(Person, 1).then(async(function(record) { equal(get(record, 'id'), 1, "reports id as id by default"); - }); + })); }); test("a record's id is included in its toString representation", function() { store.push(Person, { id: 1 }); - store.find(Person, 1).then(function(record) { + store.find(Person, 1).then(async(function(record) { equal(record.toString(), '<(subclass of DS.Model):'+Ember.guidFor(record)+':1>', "reports id in toString"); - }); + })); }); test("trying to set an `id` attribute should raise", function() { @@ -77,9 +77,9 @@ test("trying to set an `id` attribute should raise", function() { test("it should use `_reference` and not `reference` to store its reference", function() { store.push(Person, { id: 1 }); - store.find(Person, 1).then(function(record) { + store.find(Person, 1).then(async(function(record) { equal(record.get('reference'), undefined, "doesn't shadow reference key"); - }); + })); }); test("it should cache attributes", function() { @@ -94,11 +94,11 @@ test("it should cache attributes", function() { store.push(Post, { id: 1 }); - store.find(Post, 1).then(function(record) { + store.find(Post, 1).then(async(function(record) { record.set('updatedAt', date); deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); strictEqual(get(record, 'updatedAt'), get(record, 'updatedAt'), "second get still returns the same object"); - }); + })); }); module("unit/model - DS.Model updating", { @@ -116,10 +116,10 @@ module("unit/model - DS.Model updating", { }); test("a DS.Model can update its attributes", function() { - store.find(Person, 2).then(function(person) { + store.find(Person, 2).then(async(function(person) { set(person, 'name', "Brohuda Katz"); equal(get(person, 'name'), "Brohuda Katz", "setting took hold"); - }); + })); }); test("a DS.Model can have a defaultValue", function() { @@ -186,7 +186,7 @@ test("setting a property to undefined on a newly created record should not impac // NOTE: this is a 'backdoor' test that ensures internal consistency, and should be // thrown out if/when the current `_attributes` hash logic is removed. test("setting a property back to its original value removes the property from the `_attributes` hash", function() { - store.find(Person, 1).then(function(person) { + store.find(Person, 1).then(async(function(person) { equal(person._attributes.name, undefined, "the `_attributes` hash is clean"); set(person, 'name', "Niceguy Dale"); @@ -196,7 +196,7 @@ test("setting a property back to its original value removes the property from th set(person, 'name', "Scumbag Dale"); equal(person._attributes.name, undefined, "the `_attributes` hash is reset"); - }); + })); }); module("unit/model - with a simple Person model", { @@ -277,9 +277,9 @@ var converts = function(type, provided, expected) { testStore.push(Model, serializer.normalize(Model, { id: 1, name: provided })); testStore.push(Model, serializer.normalize(Model, { id: 2 })); - testStore.find('model', 1).then(function(record) { + testStore.find('model', 1).then(async(function(record) { deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); - }); + })); // See: Github issue #421 // record = testStore.find(Model, 2); @@ -298,9 +298,9 @@ var convertsFromServer = function(type, provided, expected) { serializer = DS.JSONSerializer.create({ store: testStore, container: container }); testStore.push(Model, serializer.normalize(Model, { id: "1", name: provided })); - testStore.find('model', 1).then(function(record) { + testStore.find('model', 1).then(async(function(record) { deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); - }); + })); }; var convertsWhenSet = function(type, provided, expected) { @@ -311,10 +311,10 @@ var convertsWhenSet = function(type, provided, expected) { var testStore = createStore({model: Model}); testStore.push(Model, { id: 2 }); - var record = testStore.find('model', 2).then(function(record) { + var record = testStore.find('model', 2).then(async(function(record) { set(record, 'name', provided); deepEqual(record.serialize().name, expected, type + " saves " + provided + " as " + expected); - }); + })); }; test("a DS.Model can describe String attributes", function() { @@ -362,10 +362,10 @@ test("a DS.Model can describe Date attributes", function() { }); store.push(Person, { id: 1 }); - store.find(Person, 1).then(function(record) { + store.find(Person, 1).then(async(function(record) { record.set('updatedAt', date); deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); - }); + })); convertsFromServer('date', dateString, date); convertsWhenSet('date', date, dateString); @@ -391,10 +391,10 @@ test("ensure model exits loading state, materializes data and fulfills promise o }) }); - store.find(Person, 1).then(function(person) { + store.find(Person, 1).then(async(function(person) { equal(get(person, 'currentState.stateName'), 'root.loaded.saved', 'model is in loaded state'); equal(get(person, 'isLoaded'), true, 'model is loaded'); - }); + })); }); test("A DS.Model can be JSONified", function() { diff --git a/packages/ember-data/tests/unit/record_array_test.js b/packages/ember-data/tests/unit/record_array_test.js index 578ac4d50b5..870a6fb25ec 100644 --- a/packages/ember-data/tests/unit/record_array_test.js +++ b/packages/ember-data/tests/unit/record_array_test.js @@ -17,11 +17,11 @@ test("a record array is backed by records", function() { var store = createStore(); store.pushMany(Person, array); - store.findByIds(Person, [1,2,3]).then(function(records) { + store.findByIds(Person, [1,2,3]).then(async(function(records) { for (var i=0, l=get(array, 'length'); i Date: Wed, 29 Jan 2014 12:13:42 -0500 Subject: [PATCH 0070/2527] Destroying the store now: - unload's all Records - unload's all RecordArrays - destroy's all records (so life cycle hooks get called for cleanup) - destroy's all RecordArrays Unloading a record now: - is allowed, unless the record is inflight. (previously it was disallowed for all dirty states) also, now once a record has been destroyed attempts to unload it will be black holed --- .../lib/adapters/fixture_adapter.js | 2 +- packages/ember-data/lib/system/model/model.js | 16 ++- .../ember-data/lib/system/model/states.js | 20 +++- .../lib/system/record_array_manager.js | 40 ++++++- .../lib/system/record_arrays/record_array.js | 17 +++ packages/ember-data/lib/system/store.js | 30 ++++- .../integration/record_array_manager_test.js | 99 ++++++++++++++++ .../tests/integration/records/unload_test.js | 54 +++++++-- .../relationships/belongs_to_test.js | 28 ++++- .../tests/integration/store_test.js | 106 ++++++++++++++++++ .../tests/unit/store/unload_test.js | 12 +- 11 files changed, 397 insertions(+), 27 deletions(-) create mode 100644 packages/ember-data/tests/integration/record_array_manager_test.js create mode 100644 packages/ember-data/tests/integration/store_test.js diff --git a/packages/ember-data/lib/adapters/fixture_adapter.js b/packages/ember-data/lib/adapters/fixture_adapter.js index e11033375bb..0d7c6901837 100644 --- a/packages/ember-data/lib/adapters/fixture_adapter.js +++ b/packages/ember-data/lib/adapters/fixture_adapter.js @@ -206,7 +206,7 @@ var FixtureAdapter = Adapter.extend({ findQuery: function(store, type, query, array) { var fixtures = this.fixturesForType(type); - Ember.assert("Unable to find fixtures for model type "+type.toString(), fixtures); + Ember.assert("Unable to find fixtures for model type " + type.toString(), fixtures); fixtures = this.queryFixtures(fixtures, query, type); diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 024d9092a61..88a8d387aa6 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -22,6 +22,9 @@ var retrieveFromCurrentState = Ember.computed('currentState', function(key, valu @uses Ember.Evented */ var Model = Ember.Object.extend(Ember.Evented, { + _recordArrays: undefined, + _relationships: undefined, + _loadingRecordArrays: undefined, /** If this property is `true` the record is in the `empty` state. Empty is the first state all records enter after they have @@ -576,7 +579,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @private */ unloadRecord: function() { - Ember.assert("You can only unload a loaded, non-dirty record.", !get(this, 'isDirty')); + if (this.isDestroyed) { return; } this.send('unloadRecord'); }, @@ -590,8 +593,10 @@ var Model = Ember.Object.extend(Ember.Evented, { if (relationship.kind === 'belongsTo') { set(this, name, null); } else if (relationship.kind === 'hasMany') { - var hasMany = this._relationships[relationship.name]; - if (hasMany) { hasMany.clear(); } + var hasMany = this._relationships[name]; + if (hasMany) { // relationships are created lazily + hasMany.destroy(); + } } }, this); }, @@ -997,6 +1002,11 @@ var Model = Ember.Object.extend(Ember.Evented, { } this._deferredTriggers.length = 0; + }, + + willDestroy: function() { + this._super(); + this.clearRelationships(); } }); diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index dce2412d8df..3d6e0fc90f0 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -301,6 +301,10 @@ var DirtyState = { becomeDirty: Ember.K, pushedData: Ember.K, + unloadRecord: function(record) { + Ember.assert("You can only unload a record which is not inFlight. `" + Ember.inspect(record) + " `", false); + }, + // TODO: More robust semantics around save-while-in-flight willCommit: Ember.K, @@ -391,7 +395,6 @@ function dirtyState(options) { var createdState = dirtyState({ dirtyType: 'created', - // FLAGS isNew: true }); @@ -416,6 +419,12 @@ createdState.uncommitted.rollback = function(record) { createdState.uncommitted.propertyWasReset = Ember.K; +function assertAgainstUnloadRecord(record) { + Ember.assert("You can only unload a record which is not inFlight. `" + Ember.inspect(record) + "`", false); +} + +updatedState.inFlight.unloadRecord = assertAgainstUnloadRecord; + updatedState.uncommitted.deleteRecord = function(record) { record.transitionTo('deleted.uncommitted'); record.clearRelationships(); @@ -439,6 +448,13 @@ var RootState = { // in-flight state, rolling back the record doesn't move // you out of the in-flight state. rolledBack: Ember.K, + unloadRecord: function(record) { + // clear relationships before moving to deleted state + // otherwise it fails + record.clearRelationships(); + record.transitionTo('deleted.saved'); + }, + propertyWasReset: Ember.K, @@ -632,6 +648,8 @@ var RootState = { // EVENTS + unloadRecord: assertAgainstUnloadRecord, + // TODO: More robust semantics around save-while-in-flight willCommit: Ember.K, didCommit: function(record) { diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index f72cdc83bab..0dd3a8665f0 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -19,6 +19,7 @@ var RecordArrayManager = Ember.Object.extend({ }); this.changedRecords = []; + this._adapterPopulatedRecordArrays = []; }, recordDidChange: function(record) { @@ -219,12 +220,16 @@ var RecordArrayManager = Ember.Object.extend({ @return {DS.AdapterPopulatedRecordArray} */ createAdapterPopulatedRecordArray: function(type, query) { - return DS.AdapterPopulatedRecordArray.create({ + var array = DS.AdapterPopulatedRecordArray.create({ type: type, query: query, content: Ember.A(), store: this.store }); + + this._adapterPopulatedRecordArrays.push(array); + + return array; }, /** @@ -254,7 +259,40 @@ var RecordArrayManager = Ember.Object.extend({ var loadingRecordArrays = record._loadingRecordArrays || []; loadingRecordArrays.push(array); record._loadingRecordArrays = loadingRecordArrays; + }, + + willDestroy: function(){ + this._super(); + + flatten(values(this.filteredRecordArrays.values)).forEach(destroy); + this._adapterPopulatedRecordArrays.forEach(destroy); } }); +function values(obj) { + var result = []; + var keys = Ember.keys(obj); + + for (var i = 0; i < keys.length; i++) { + result.push(obj[keys[i]]); + } + + return result; +} + +function destroy(entry) { + entry.destroy(); +} + +function flatten(list) { + var length = list.length; + var result = Ember.A(); + + for (var i = 0; i < length; i++) { + result = result.concat(list[i]); + } + + return result; +} + export default RecordArrayManager; diff --git a/packages/ember-data/lib/system/record_arrays/record_array.js b/packages/ember-data/lib/system/record_arrays/record_array.js index bf5fc6639d2..4ff52c96722 100644 --- a/packages/ember-data/lib/system/record_arrays/record_array.js +++ b/packages/ember-data/lib/system/record_arrays/record_array.js @@ -162,6 +162,23 @@ var RecordArray = Ember.ArrayProxy.extend(Ember.Evented, { }, null, "DS: RecordArray#save apply Ember.NativeArray"); return PromiseArray.create({ promise: promise }); + }, + + _dissociateFromOwnRecords: function() { + var array = this; + + this.forEach(function(record){ + var recordArrays = record._recordArrays; + + if (recordArrays) { + recordArrays.remove(array); + } + }); + }, + + willDestroy: function(){ + this._dissociateFromOwnRecords(); + this._super(); } }); diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 1dcd205c00f..deb25b04817 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -753,13 +753,15 @@ Store = Ember.Object.extend({ @param {String or subclass of DS.Model} type */ unloadAll: function(type) { - type = this.modelFor(type); - - var typeMap = this.typeMapFor(type), - records = typeMap.records.splice(0), record; + var modelType = this.modelFor(type); + var typeMap = this.typeMapFor(modelType); + var records = typeMap.records.slice(); + var record; - while(record = records.pop()) { + for (var i = 0; i < records.length; i++) { + record = records[i]; record.unloadRecord(); + record.destroy(); // maybe within unloadRecord } typeMap.findAllCache = null; @@ -1023,7 +1025,8 @@ Store = Ember.Object.extend({ typeMap = { idToRecord: {}, records: [], - metadata: {} + metadata: {}, + type: type }; typeMaps[guid] = typeMap; @@ -1408,6 +1411,21 @@ Store = Ember.Object.extend({ var adapter = this.adapterFor(type); return serializerFor(this.container, type.typeKey, adapter && adapter.defaultSerializer); + }, + + willDestroy: function() { + var map = this.typeMaps; + var keys = Ember.keys(map); + var store = this; + var types = keys.map(byType); + + this.recordArrayManager.destroy(); + + types.forEach(this.unloadAll, this); + + function byType(entry) { + return map[entry].type; + } } }); diff --git a/packages/ember-data/tests/integration/record_array_manager_test.js b/packages/ember-data/tests/integration/record_array_manager_test.js new file mode 100644 index 00000000000..90307601cd1 --- /dev/null +++ b/packages/ember-data/tests/integration/record_array_manager_test.js @@ -0,0 +1,99 @@ +var store, env; + +var Person = DS.Model.extend({ + name: DS.attr('string'), + cars: DS.hasMany('car') +}); + +Person.toString = function() { return "Person"; }; + +var Car = DS.Model.extend({ + make: DS.attr('string'), + model: DS.attr('string'), + person: DS.belongsTo('person') +}); + +Car.toString = function() { return "Car"; }; + +var manager; + +module("integration/record_array_manager- destroy", { + setup: function(){ + env = setupStore({ + adapter: DS.FixtureAdapter.extend() + }); + store = env.store; + + manager = DS.RecordArrayManager.create({ + store: store + }); + + env.container.register('model:car', Car); + env.container.register('model:person', Person); + } +}); + +function tap(obj, methodName, callback) { + var old = obj[methodName]; + + var summary = { called: [] }; + + obj[methodName] = function() { + var result = old.apply(obj, arguments); + if (callback) { + callback.apply(obj, arguments); + } + summary.called.push(arguments); + return result; + }; + + return summary; +} + +test("destroying the store correctly cleans everything up", function() { + var query = { }; + + store.push('car', { + id: 1, + make: 'BMC', + model: 'Mini Cooper', + person: 1 + }); + + var person = store.push('person', { + id: 1, + name: 'Tom Dale', + cars: [1] + }); + + var filterd = manager.createFilteredRecordArray(Person, function(){ return true; }); + var filterd2 = manager.createFilteredRecordArray(Person, function(){ return true; }); + var adapterPopulated = manager.createAdapterPopulatedRecordArray(Person, query); + + var filterdSummary = tap(filterd, 'willDestroy'); + var filterd2Summary = tap(filterd2, 'willDestroy'); + + var adapterPopulatedSummary = tap(adapterPopulated, 'willDestroy'); + + equal(filterdSummary.called.length, 0); + equal(adapterPopulatedSummary.called.length, 0); + + equal(filterd2Summary.called.length, 0); + + equal(person._recordArrays.list.length, 2, 'expected the person to be a member of 2 recordArrays'); + + Ember.run(filterd2, filterd2.destroy); + + equal(person._recordArrays.list.length, 1, 'expected the person to be a member of 1 recordArrays'); + + equal(filterd2Summary.called.length, 1); + + Ember.run(manager, manager.destroy); + + equal(person._recordArrays.list.length, 0, 'expected the person to be a member of no recordArrays'); + + equal(filterd2Summary.called.length, 1); + + equal(filterdSummary.called.length, 1); + equal(adapterPopulatedSummary.called.length, 1); +}); diff --git a/packages/ember-data/tests/integration/records/unload_test.js b/packages/ember-data/tests/integration/records/unload_test.js index f808d410b34..5a18e3e4b93 100644 --- a/packages/ember-data/tests/integration/records/unload_test.js +++ b/packages/ember-data/tests/integration/records/unload_test.js @@ -1,16 +1,28 @@ var get = Ember.get, set = Ember.set; var attr = DS.attr; -var Person, env; +var belongsTo = DS.belongsTo; +var hasMany = DS.hasMany; +var env; -module("integration/unload - Unloading Records", { - setup: function() { - Person = DS.Model.extend({ - name: attr('string') - }); +var Person = DS.Model.extend({ + name: attr('string'), + cars: hasMany('car') +}); + +var Car = DS.Model.extend({ + make: attr('string'), + model: attr('string'), + person: belongsTo('person') +}); - Person.toString = function() { return "Person"; }; +Person.toString = function() { return "Person"; }; - env = setupStore({ person: Person }); +module("integration/unload - Unloading Records", { + setup: function() { + env = setupStore({ + person: Person, + car: Car + }); }, teardown: function() { @@ -66,3 +78,29 @@ test("unloading all records also updates record array from all()", function() { equal(all.get('length'), 0); }); + + +test("unloading a record also clears it's relationship", function() { + var adam = env.store.push('person', { + id: 1, + name: "Adam Sunderland", + cars: [1] + }); + + var bob = env.store.push('car', { + id: 1, + make: "Lotus", + model: "Exige", + person: 1 + }); + + env.store.find('person', 1).then(function(person){ + equal(person.get('cars.length'), 1, 'aaaa'); + + Ember.run(function(){ + person.unloadRecord(); + }); + + equal(person.get('cars.length'), undefined); + }); +}); diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index 0861ad44347..1c71291764b 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -15,24 +15,28 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { messages: hasMany('message', {polymorphic: true}), favouriteMessage: belongsTo('message', {polymorphic: true}) }); + User.toString = stringify('User'); Message = DS.Model.extend({ user: belongsTo('user'), created_at: attr('date') }); + Message.toString = stringify('Message'); Post = Message.extend({ title: attr('string'), comments: hasMany('comment') }); + Post.toString = stringify('Post'); Comment = Message.extend({ body: DS.attr('string'), message: DS.belongsTo('message', { polymorphic: true }) }); + Comment.toString = stringify('Comment'); env = setupStore({ @@ -60,15 +64,23 @@ test("The store can materialize a non loaded monomorphic belongsTo association", expect(1); env.store.modelFor('post').reopen({ - user: DS.belongsTo('user', { async: true }) + user: DS.belongsTo('user', { + async: true, + inverse: 'messages' + }) }); env.adapter.find = function(store, type, id) { ok(true, "The adapter's find method should be called"); - return Ember.RSVP.resolve({ id: 1 }); + return Ember.RSVP.resolve({ + id: 1 + }); }; - env.store.push('post', { id: 1, user: 2}); + env.store.push('post', { + id: 1, + user: 2 + }); env.store.find('post', 1).then(async(function(post) { post.get('user'); @@ -81,7 +93,10 @@ test("Only a record of the same type can be used with a monomorphic belongsTo re store.push('post', { id: 1 }); store.push('comment', { id: 2 }); - hash({ post: store.find('post', 1), comment: store.find('comment', 2) }).then(async(function(records) { + hash({ + post: store.find('post', 1), + comment: store.find('comment', 2) + }).then(async(function(records) { expectAssertion(function() { records.post.set('user', records.comment); }, /You can only add a 'user' record to this relationship/); @@ -119,7 +134,10 @@ test("The store can load a polymorphic belongsTo association", function() { env.store.push('post', { id: 1 }); env.store.push('comment', { id: 2, message: 1, messageType: 'post' }); - hash({ message: store.find('post', 1), comment: store.find('comment', 2) }).then(async(function(records) { + hash({ + message: store.find('post', 1), + comment: store.find('comment', 2) + }).then(async(function(records) { equal(records.comment.get('message'), records.message); })); }); diff --git a/packages/ember-data/tests/integration/store_test.js b/packages/ember-data/tests/integration/store_test.js new file mode 100644 index 00000000000..deef5f20bb0 --- /dev/null +++ b/packages/ember-data/tests/integration/store_test.js @@ -0,0 +1,106 @@ +var store, env; + +var Person = DS.Model.extend({ + name: DS.attr('string'), + cars: DS.hasMany('car') +}); + +Person.toString = function() { return "Person"; }; + +var Car = DS.Model.extend({ + make: DS.attr('string'), + model: DS.attr('string'), + person: DS.belongsTo('person') +}); + +Car.toString = function() { return "Car"; }; + +module("integration/store - destroy", { + setup: function(){ + env = setupStore({ + adapter: DS.FixtureAdapter.extend() + }); + store = env.store; + + env.container.register('model:car', Car); + env.container.register('model:person', Person); + } +}); + +function tap(obj, methodName, callback) { + var old = obj[methodName]; + + var summary = { called: [] }; + + obj[methodName] = function() { + var result = old.apply(obj, arguments); + if (callback) { + callback.apply(obj, arguments); + } + summary.called.push(arguments); + return result; + }; + + return summary; +} + + +test("destroying the store correctly cleans everything up", function() { + var car = store.push('car', { + id: 1, + make: 'BMC', + model: 'Mini', + person: 1 + }); + + var person = store.push('person', { + id: 1, + name: 'Tom Dale', + cars: [1] + }); + + var personWillDestroy = tap(person, 'willDestroy'); + var carWillDestroy = tap(car, 'willDestroy'); + var carsWillDestroy = tap(car.get('person.cars'), 'willDestroy'); + + env.adapter.findQuery = function() { + return [{ + id: 2, + name: 'Yehuda' + }]; + }; + + var adapterPopulatedPeople = store.find('person', { + someCrazy: 'query' + }); + + var filterdPeople = store.filter('person', function(){ return true; }); + + var filterdPeopleWillDestroy = tap(filterdPeople.content, 'willDestroy'); + var adapterPopulatedPeopleWillDestroy = tap(adapterPopulatedPeople.content, 'willDestroy'); + + var adapterPopulatedPerson = store.find('person', 2); + + equal(personWillDestroy.called.length, 0, 'expected person.willDestroy to not have been called'); + equal(carWillDestroy.called.length, 0, 'expected car.willDestroy to not have been called'); + equal(carsWillDestroy.called.length, 0, 'expected cars.willDestroy to not have been called'); + equal(adapterPopulatedPeopleWillDestroy.called.length, 0, 'expected adapterPopulatedPeople.willDestroy to not have been called'); + equal(filterdPeopleWillDestroy.called.length, 0, 'expected filterdPeople.willDestroy to not have been called'); + + equal(filterdPeople.get('length'), 2, 'expected filterdPeople to have 2 entries'); + + equal(car.get('person'), person, "expected car's person to be the correct person"); + equal(person.get('cars.firstObject'), car, " expected persons cars's firstRecord to be the correct car"); + + Ember.run(person, person.destroy); + Ember.run(store, 'destroy'); + + equal(car.get('person'), null, "expected car.person to no longer be present"); + equal(person.get('cars'), undefined, "expected person.cars to be empty"); + + equal(personWillDestroy.called.length, 1, 'expected person to have recieved willDestroy once'); + equal(carWillDestroy.called.length, 1, 'expected car to recieve willDestroy once'); + equal(carsWillDestroy.called.length, 1, 'expected cars to recieve willDestroy once'); + equal(adapterPopulatedPeopleWillDestroy.called.length, 1, 'expected adapterPopulatedPeople to recieve willDestroy once'); + equal(filterdPeopleWillDestroy.called.length, 1, 'expected filterdPeople.willDestroy to have been called once'); +}); diff --git a/packages/ember-data/tests/unit/store/unload_test.js b/packages/ember-data/tests/unit/store/unload_test.js index 167647c6bc8..a03848ed8bb 100644 --- a/packages/ember-data/tests/unit/store/unload_test.js +++ b/packages/ember-data/tests/unit/store/unload_test.js @@ -22,15 +22,23 @@ module("unit/store/unload - Store unloading records", { }); test("unload a dirty record", function() { - store.push(Record, {id: 1, title: 'toto'}); + store.push(Record, { + id: 1, + title: 'toto' + }); store.find(Record, 1).then(async(function(record) { record.set('title', 'toto2'); + record.send('willCommit'); equal(get(record, 'isDirty'), true, "record is dirty"); + expectAssertion(function() { record.unloadRecord(); - }, "You can only unload a loaded, non-dirty record.", "can not unload dirty record"); + }, "You can only unload a record which is not inFlight. `" + Ember.inspect(record) + "`", "can not unload dirty record"); + + // force back into safe to unload mode. + record.transitionTo('deleted.saved'); })); }); From 659822715a8dd0767d4aab495a75934f555f9a9e Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 6 Feb 2014 11:40:02 -0500 Subject: [PATCH 0071/2527] Ensure the SHA is included in the VERSION. Closes #1736. --- packages/ember-data/lib/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/core.js b/packages/ember-data/lib/core.js index 4e1e135633d..91c50c53d4f 100644 --- a/packages/ember-data/lib/core.js +++ b/packages/ember-data/lib/core.js @@ -17,7 +17,7 @@ if ('undefined' === typeof DS) { @static */ DS = Ember.Namespace.create({ - VERSION: '<%= pkg.version %>' + VERSION: '<%= versionStamp %>' }); if ('undefined' !== typeof window) { From ce46992061f7c503c0c7d21473b1e700fcd13d34 Mon Sep 17 00:00:00 2001 From: James Herdman Date: Thu, 6 Feb 2014 18:15:30 -0500 Subject: [PATCH 0072/2527] Remove Dead Code from RESTAdapter's Test --- .../integration/adapter/rest_adapter_test.js | 133 ------------------ 1 file changed, 133 deletions(-) diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 21a92ebd18c..df32c86e516 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -1002,13 +1002,6 @@ test('buildURL - with camelized names', function() { test('normalizeKey - to set up _ids and _id', function() { env.container.register('serializer:application', DS.RESTSerializer.extend({ keyForAttribute: function(attr) { - //if (kind === 'hasMany') { - //key = key.replace(/_ids$/, ''); - //key = Ember.String.pluralize(key); - //} else if (kind === 'belongsTo') { - //key = key.replace(/_id$/, ''); - //} - return Ember.String.underscore(attr); }, @@ -1071,129 +1064,3 @@ test('normalizeKey - to set up _ids and _id', function() { deepEqual(post.get('comments').mapBy('body'), ["Rails is unagi", "What is omakase?"]); })); }); - -//test("creating a record with a 422 error marks the records as invalid", function(){ - //expect(1); - - //var mockXHR = { - //status: 422, - //responseText: JSON.stringify({ errors: { name: ["can't be blank"]} }) - //}; - - //jQuery.ajax = function(hash) { - //hash.error.call(hash.context, mockXHR, "Unprocessable Entity"); - //}; - - //var post = store.createRecord(Post, { name: "" }); - - //post.on("becameInvalid", function() { - //ok(true, "becameInvalid is called"); - //}); - - //post.on("becameError", function() { - //ok(false, "becameError is not called"); - //}); - - //post.save(); -//}); - -//test("changing A=>null=>A should clean up the record", function() { - //var store = DS.Store.create({ - //adapter: DS.RESTAdapter - //}); - //var Kidney = DS.Model.extend(); - //var Person = DS.Model.extend(); - - //Kidney.reopen({ - //person: DS.belongsTo(Person) - //}); - //Kidney.toString = function() { return "Kidney"; }; - - //Person.reopen({ - //name: DS.attr('string'), - //kidneys: DS.hasMany(Kidney) - //}); - //Person.toString = function() { return "Person"; }; - - //store.load(Person, { id: 1, kidneys: [1, 2] }); - //store.load(Kidney, { id: 1, person: 1 }); - //store.load(Kidney, { id: 2, person: 1 }); - - //var person = store.find(Person, 1); - //var kidney1 = store.find(Kidney, 1); - //var kidney2 = store.find(Kidney, 2); - - //deepEqual(person.get('kidneys').toArray(), [kidney1, kidney2], "precond - person should have both kidneys"); - //equal(kidney1.get('person'), person, "precond - first kidney should be in the person"); - - //person.get('kidneys').removeObject(kidney1); - - //ok(person.get('isDirty'), "precond - person should be dirty after operation"); - //ok(kidney1.get('isDirty'), "precond - first kidney should be dirty after operation"); - - //deepEqual(person.get('kidneys').toArray(), [kidney2], "precond - person should have only the second kidney"); - //equal(kidney1.get('person'), null, "precond - first kidney should be on the operating table"); - - //person.get('kidneys').addObject(kidney1); - - //ok(!person.get('isDirty'), "person should be clean after restoration"); - //ok(!kidney1.get('isDirty'), "first kidney should be clean after restoration"); - - //deepEqual(person.get('kidneys').toArray(), [kidney2, kidney1], "person should have both kidneys again"); - //equal(kidney1.get('person'), person, "first kidney should be in the person again"); -//}); - -//test("changing A=>B=>A should clean up the record", function() { - //var store = DS.Store.create({ - //adapter: DS.RESTAdapter - //}); - //var Kidney = DS.Model.extend(); - //var Person = DS.Model.extend(); - - //Kidney.reopen({ - //person: DS.belongsTo(Person) - //}); - //Kidney.toString = function() { return "Kidney"; }; - - //Person.reopen({ - //name: DS.attr('string'), - //kidneys: DS.hasMany(Kidney) - //}); - //Person.toString = function() { return "Person"; }; - - //store.load(Person, { person: { id: 1, name: "John Doe", kidneys: [1, 2] }}); - //store.load(Person, { person: { id: 2, name: "Jane Doe", kidneys: [3]} }); - //store.load(Kidney, { kidney: { id: 1, person_id: 1 } }); - //store.load(Kidney, { kidney: { id: 2, person_id: 1 } }); - //store.load(Kidney, { kidney: { id: 3, person_id: 2 } }); - - //var john = store.find(Person, 1); - //var jane = store.find(Person, 2); - //var kidney1 = store.find(Kidney, 1); - //var kidney2 = store.find(Kidney, 2); - //var kidney3 = store.find(Kidney, 3); - - //deepEqual(john.get('kidneys').toArray(), [kidney1, kidney2], "precond - john should have the first two kidneys"); - //deepEqual(jane.get('kidneys').toArray(), [kidney3], "precond - jane should have the third kidney"); - //equal(kidney2.get('person'), john, "precond - second kidney should be in john"); - - //kidney2.set('person', jane); - - //ok(john.get('isDirty'), "precond - john should be dirty after operation"); - //ok(jane.get('isDirty'), "precond - jane should be dirty after operation"); - //ok(kidney2.get('isDirty'), "precond - second kidney should be dirty after operation"); - - //deepEqual(john.get('kidneys').toArray(), [kidney1], "precond - john should have only the first kidney"); - //deepEqual(jane.get('kidneys').toArray(), [kidney3, kidney2], "precond - jane should have the other two kidneys"); - //equal(kidney2.get('person'), jane, "precond - second kidney should be in jane"); - - //kidney2.set('person', john); - - //ok(!john.get('isDirty'), "john should be clean after restoration"); - //ok(!jane.get('isDirty'), "jane should be clean after restoration"); - //ok(!kidney2.get('isDirty'), "second kidney should be clean after restoration"); - - //deepEqual(john.get('kidneys').toArray(), [kidney1, kidney2], "john should have the first two kidneys again"); - //deepEqual(jane.get('kidneys').toArray(), [kidney3], "jane should have the third kidney again"); - //equal(kidney2.get('person'), john, "second kidney should be in john again"); -//}); From 43dab244e9fedf97953d4f8993a99f4b1d6d3667 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 10 Feb 2014 10:45:15 -0500 Subject: [PATCH 0073/2527] explicitly set a handlebars dependency to a version known to work. --- bower.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index acc56ea2137..c9d9b549686 100644 --- a/bower.json +++ b/bower.json @@ -2,7 +2,8 @@ "name": "ember-data", "private": true, "dependencies": { - "ember": "~1.3.1", - "qunit": "~1.13.0" + "ember": "~1.3.2", + "qunit": "~1.13.0", + "handlebars": "~1.3.0" } } From 2ee1b58c74e1e1920ba5372242b30a6710570884 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 10 Feb 2014 11:13:42 -0500 Subject: [PATCH 0074/2527] force jshint on failure --- tasks/options/jshint.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tasks/options/jshint.js b/tasks/options/jshint.js index 72f344c70a4..1a2e11778e1 100644 --- a/tasks/options/jshint.js +++ b/tasks/options/jshint.js @@ -1,6 +1,7 @@ module.exports = { options: { - jshintrc: ".jshintrc" + jshintrc: ".jshintrc", + force: true }, src: [ 'dist/ember-data.js' ] }; From 7ab338bea001437002b05a1965367e3e94c404c8 Mon Sep 17 00:00:00 2001 From: Marcio Junior Date: Wed, 12 Feb 2014 22:25:44 -0200 Subject: [PATCH 0075/2527] Don't pass the resolver where it's not needed --- .../lib/system/relationships/belongs_to.js | 10 +++++----- packages/ember-data/lib/system/store.js | 17 ++++++++--------- .../tests/unit/store/adapter_interop_test.js | 7 ++----- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index 42ff635c033..84c11f4cbf9 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -13,7 +13,8 @@ function asyncBelongsTo(type, options, meta) { return Ember.computed('data', function(key, value) { var data = get(this, 'data'), store = get(this, 'store'), - promiseLabel = "DS: Async belongsTo " + this + " : " + key; + promiseLabel = "DS: Async belongsTo " + this + " : " + key, + promise; if (arguments.length === 2) { Ember.assert("You can only add a '" + type + "' record to this relationship", !value || value instanceof store.modelFor(type)); @@ -26,15 +27,14 @@ function asyncBelongsTo(type, options, meta) { belongsTo = data[key]; if(!isNone(belongsTo)) { - var promise = store.fetchRecord(belongsTo) || Promise.cast(belongsTo, promiseLabel); + promise = store.fetchRecord(belongsTo) || Promise.cast(belongsTo, promiseLabel); return DS.PromiseObject.create({ promise: promise }); } else if (link) { - var resolver = Ember.RSVP.defer("DS: Async belongsTo (link) " + this + " : " + key); - store.findBelongsTo(this, link, meta, resolver); + promise = store.findBelongsTo(this, link, meta); return DS.PromiseObject.create({ - promise: resolver.promise + promise: promise }); } else { return null; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 1dcd205c00f..139df3bb3c6 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -480,9 +480,9 @@ Store = Ember.Object.extend({ @private @param {Array} records @param {DS.Model} owner - @param {Resolver} resolver + @return {Promise} promise */ - fetchMany: function(records, owner, resolver) { + fetchMany: function(records, owner) { if (!records.length) { return; } // Group By Type @@ -506,7 +506,7 @@ Store = Ember.Object.extend({ promises.push(_findMany(adapter, this, type, ids, owner)); }, this); - resolver.resolve(Ember.RSVP.all(promises)); + return Ember.RSVP.all(promises); }, /** @@ -575,7 +575,7 @@ Store = Ember.Object.extend({ this.recordArrayManager.registerWaitingRecordArray(record, manyArray); }, this); - this.fetchMany(unloadedRecords, owner, resolver); + resolver.resolve(this.fetchMany(unloadedRecords, owner)); } else { if (resolver) { resolver.resolve(); } manyArray.set('isLoaded', true); @@ -601,8 +601,7 @@ Store = Ember.Object.extend({ @param {DS.Model} owner @param {any} link @param {String or subclass of DS.Model} type - @param {Resolver} resolver - @return {DS.ManyArray} + @return {Promise} promise */ findHasMany: function(owner, link, relationship, resolver) { var adapter = this.adapterFor(owner.constructor); @@ -621,15 +620,15 @@ Store = Ember.Object.extend({ @param {DS.Model} owner @param {any} link @param {Relationship} relationship - @param {Resolver} resolver + @return {Promise} promise */ - findBelongsTo: function(owner, link, relationship, resolver) { + findBelongsTo: function(owner, link, relationship) { var adapter = this.adapterFor(owner.constructor); Ember.assert("You tried to load a belongsTo relationship but you have no adapter (for " + owner.constructor + ")", adapter); Ember.assert("You tried to load a belongsTo relationship from a specified `link` in the original payload but your adapter does not implement `findBelongsTo`", adapter.findBelongsTo); - resolver.resolve(_findBelongsTo(adapter, this, owner, link, relationship)); + return _findBelongsTo(adapter, this, owner, link, relationship); }, /** diff --git a/packages/ember-data/tests/unit/store/adapter_interop_test.js b/packages/ember-data/tests/unit/store/adapter_interop_test.js index a8e4c8e7ca7..fb5efa11c44 100644 --- a/packages/ember-data/tests/unit/store/adapter_interop_test.js +++ b/packages/ember-data/tests/unit/store/adapter_interop_test.js @@ -331,9 +331,7 @@ test("store.fetchMany should not resolve until all the records are resolve", fun adapter: adapter }); - - var owner = store.createRecord(Person), - resolver = Ember.RSVP.defer(); + var owner = store.createRecord(Person); var records = Ember.A([ store.recordForId(Person, 10), @@ -341,8 +339,7 @@ test("store.fetchMany should not resolve until all the records are resolve", fun store.recordForId(Phone, 21) ]); - store.fetchMany(records, owner, resolver); - resolver.promise.then(async(function() { + store.fetchMany(records, owner).then(async(function() { var unloadedRecords = records.filterBy('isEmpty'); equal(get(unloadedRecords, 'length'), 0, 'All unloaded records should be loaded'); })); From ec0698625402268a19466278536ea5128b613074 Mon Sep 17 00:00:00 2001 From: Sylvain MINA Date: Thu, 13 Feb 2014 09:56:43 +0100 Subject: [PATCH 0076/2527] [DOC] Fix extractArray It makes the use of extractSingle consistent with the signature see #1743 As a side note I realize the store is not used in the extractSingle function, but I guess it could be usefull for people overriding it ? --- packages/ember-data/lib/serializers/json_serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 8be3b91b355..b0567ff184c 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -636,7 +636,7 @@ var JSONSerializer = Ember.Object.extend({ App.PostSerializer = DS.JSONSerializer.extend({ extractArray: function(store, type, payload) { return payload.map(function(json) { - return this.extractSingle(json); + return this.extractSingle(store, type, json); }, this); } }); From 7e83ed158034cf7fedf2a7113a82de5d5ce67e76 Mon Sep 17 00:00:00 2001 From: Mark van Seventer Date: Fri, 14 Feb 2014 10:31:09 -0500 Subject: [PATCH 0077/2527] Use Ember getter instead of accessing the property directly. --- packages/ember-data/lib/adapters/rest_adapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index c59b2259b09..3fa7e443d04 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -599,8 +599,8 @@ var RESTAdapter = Adapter.extend({ hash.data = JSON.stringify(hash.data); } - if (this.headers !== undefined) { - var headers = this.headers; + var headers = get(this, 'headers'); + if (headers !== undefined) { hash.beforeSend = function (xhr) { forEach.call(Ember.keys(headers), function(key) { xhr.setRequestHeader(key, headers[key]); From c5a6164565f16bca5777ae5467119a22f0f2ab30 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 14 Feb 2014 20:00:15 -0600 Subject: [PATCH 0078/2527] lock server while compiling assets --- package.json | 3 ++- tasks/lock.js | 11 +++++++++++ tasks/options/clean.js | 2 +- tasks/options/connect.js | 18 +++++++++++++++++- tasks/options/watch.js | 4 ++-- 5 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 tasks/lock.js diff --git a/package.json b/package.json index 7e7f69208b2..c1b2a2639e2 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "grunt-ember-defeatureify": "~0.1.0", "aws-sdk": "~2.0.0-rc8", "grunt-cli": "~0.1.13", - "grunt-contrib-yuidoc": "~0.5.0" + "grunt-contrib-yuidoc": "~0.5.0", + "lockfile": "~0.4.2" } } diff --git a/tasks/lock.js b/tasks/lock.js new file mode 100644 index 00000000000..5b7547e8ac6 --- /dev/null +++ b/tasks/lock.js @@ -0,0 +1,11 @@ +var lockFile = require('lockfile'); +var grunt = require('grunt'); +var LOCKFILE = __dirname + "/../tmp/connect.lock"; + +grunt.registerTask('lock', function(){ + lockFile.lockSync(LOCKFILE); +}); + +grunt.registerTask('unlock', function(){ + lockFile.unlockSync(LOCKFILE); +}); diff --git a/tasks/options/clean.js b/tasks/options/clean.js index ef55f92eb78..0f18cb2aa0e 100644 --- a/tasks/options/clean.js +++ b/tasks/options/clean.js @@ -1,3 +1,3 @@ module.exports = { - main: [ 'tmp/**/*' ] + main: [ 'tmp/!connect.lock' ] }; diff --git a/tasks/options/connect.js b/tasks/options/connect.js index ab6a5059ebf..f6e95757f25 100644 --- a/tasks/options/connect.js +++ b/tasks/options/connect.js @@ -1,9 +1,25 @@ +var lockFile = require('lockfile'); +var lockMiddleware = function(req, res, next) { + if (!lockFile.checkSync(__dirname + '/../../tmp/connect.lock')) { + return next(); + } else { + setTimeout(function(){ + lockMiddleware(req, res, next); + }, 10); + } +}; + + var port = process.env.PORT || '9997'; module.exports = { main: { options: { port: port, - base: '.' + base: '.', + middleware: function(connect, options){ + var base = options.base; + return [ lockMiddleware, connect.static(base), connect.directory(base) ]; + } } } }; diff --git a/tasks/options/watch.js b/tasks/options/watch.js index 9b12a0e0cfd..ce21c345502 100644 --- a/tasks/options/watch.js +++ b/tasks/options/watch.js @@ -2,11 +2,11 @@ module.exports = { packages: { files: [ 'packages/**/*.js', '!packages/**/test/**/*.js'], - tasks: [ 'buildPackages', 'prepareTests', 'qunit:local' ] + tasks: [ 'lock', 'buildPackages', 'prepareTests', 'unlock', 'qunit:local' ] }, tests: { files: [ 'packages/**/test/**/*.js' ], - tasks: [ 'prepareTests', 'qunit:local' ] + tasks: [ 'lock', 'prepareTests', 'unlock', 'qunit:local' ] } }; From 96aad6daf8f91d25b94750b9b173767ef4512a30 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Mon, 17 Feb 2014 01:23:30 +0900 Subject: [PATCH 0079/2527] Update ember version to 1.4.0 --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index c9d9b549686..f086c49f2d6 100644 --- a/bower.json +++ b/bower.json @@ -2,7 +2,7 @@ "name": "ember-data", "private": true, "dependencies": { - "ember": "~1.3.2", + "ember": "~1.4.0", "qunit": "~1.13.0", "handlebars": "~1.3.0" } From e5f2e7263f7bd841a49240b54c3f6fff31631ec3 Mon Sep 17 00:00:00 2001 From: "A. Speller" Date: Sun, 16 Feb 2014 22:21:52 +0000 Subject: [PATCH 0080/2527] Fix rollback on invalid record after set --- .../ember-data/lib/system/model/states.js | 4 ++ .../tests/unit/model/rollback_test.js | 53 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index 3d6e0fc90f0..48e4ccfe747 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -357,6 +357,10 @@ var DirtyState = { invokeLifecycleCallbacks: function(record) { record.triggerLater('becameInvalid', record); + }, + + exit: function(record) { + record._inFlightAttributes = {}; } } }; diff --git a/packages/ember-data/tests/unit/model/rollback_test.js b/packages/ember-data/tests/unit/model/rollback_test.js index 92ffa91060a..ed0cc2d73b1 100644 --- a/packages/ember-data/tests/unit/model/rollback_test.js +++ b/packages/ember-data/tests/unit/model/rollback_test.js @@ -111,6 +111,12 @@ test("invalid record can be rollbacked", function() { var adapter = this; return new Ember.RSVP.Promise(function(resolve, reject) { + /* If InvalidError is passed back in the reject it will throw the + exception which will bubble up the call stack (crashing the test) + instead of hitting the failure route of the promise. + So wrapping the reject in an Ember.run.next makes it so save + completes without failure and the failure hits the failure route + of the promise instead of crashing the save. */ Ember.run.next(function(){ reject(adapter.ajaxError({name: 'is invalid'})); }); @@ -134,3 +140,50 @@ test("invalid record can be rollbacked", function() { ok(dog.get('isValid')); })); }); + +test("invalid record is rolled back to correct state after set", function() { + Dog = DS.Model.extend({ + name: DS.attr(), + breed: DS.attr() + }); + + var adapter = DS.RESTAdapter.extend({ + ajax: function(url, type, hash) { + var adapter = this; + + return new Ember.RSVP.Promise(function(resolve, reject) { + /* If InvalidError is passed back in the reject it will throw the + exception which will bubble up the call stack (crashing the test) + instead of hitting the failure route of the promise. + So wrapping the reject in an Ember.run.next makes it so save + completes without failure and the failure hits the failure route + of the promise instead of crashing the save. */ + Ember.run.next(function(){ + reject(adapter.ajaxError({name: 'is invalid'})); + }); + }); + }, + + ajaxError: function(jqXHR) { + return new DS.InvalidError(jqXHR); + } + }); + + env = setupStore({ dog: Dog, adapter: adapter}); + var dog = env.store.push('dog', { id: 1, name: "Pluto", breed: "Disney" }); + + dog.set('name', "is a dwarf planet"); + dog.set('breed', 'planet'); + + dog.save().then(null, async(function() { + equal(dog.get('name'), "is a dwarf planet"); + equal(dog.get('breed'), "planet"); + dog.set('name', 'Seymour Asses'); + equal(dog.get('name'), "Seymour Asses"); + equal(dog.get('breed'), "planet"); + dog.rollback(); + equal(dog.get('name'), "Pluto"); + equal(dog.get('breed'), "Disney"); + ok(dog.get('isValid')); + })); +}); From a4e0979ff791055cca29078dad40a74fe79d9ee9 Mon Sep 17 00:00:00 2001 From: Kerrick Long Date: Mon, 17 Feb 2014 14:11:55 -0600 Subject: [PATCH 0081/2527] Document required structure for DS.InvalidError --- packages/ember-data/lib/system/adapter.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 12ca9177506..b6f7a22701b 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -32,6 +32,17 @@ var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'n } }); ``` + + The `DS.InvalidError` must be constructed with a single object whose + keys are the invalid model properties, and whose values are the + corresponding error messages. For example: + + ```javascript + return new DS.InvalidError({ + length: 'Must be less than 15', + name: 'Must not be blank + }); + ``` @class InvalidError @namespace DS From e16a7576b09485d763ce761b87ce5e81b3e6ab95 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 19 Feb 2014 16:06:54 -0600 Subject: [PATCH 0082/2527] 1.0.0-beta.6 changelog --- CHANGELOG.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d6c160c349..ac8609549df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,35 @@ # Ember Data Changelog +### Ember Data 1.0.0-beta.6 _(January 25, 2014)_ + +* DateTransform serializes as a number instead of string. The deserializer was already considering this case. Adds millisecond precision to DateTransform +* Remove unused helper. +* Updates DS.Model.rollback documentation +* Fix a typo in DS.filter doc +* Prefix built-in serializers and adapters with a dash. +* Spelling corrections in docs. +* Fix spelling in JSONSerializer class docs. +* Don't assume typeKey is always camelized. +* Deprecate former underscored names. +* Fix documentation for DS.Model.isNew +* [BUGFIX] Possible undefined errors in response via ActiveModelAdapter +* [BUGFIX] missing return statement in RecordArray#update +* Fixes a small typo in DS.Store deleteRecord docs +* Setting a property to undefined on a new record should not transition the record to root.deleted.saved +* Revert "Merge pull request #1652 from abuiles/camelize-in-pathForType" +* Don't assume that factory.typeKey is always camelized. +* Normalize typeNames when comparing against typeKey. +* Force underscore after decamelizing typeKey. +* Set default Rakefile task to :test +* Remove underscores and rename +* The store's adapter property requires a string +* Rename dataAdapter to data-adapter +* Calls rake test[all] using bundle exec since CI was failing +* DateTransform serializes as a number instead of string. The deserializer was already considering this case. Adds millisecond precision to DateTransform +* fixed behaviour of store.all() in combination with store.unloadAll() which caused elements to stay in the RecordArray, even if they should have been removed. ref #1611 +* another quick fix, which should reduce run-loop pressure. +* Don't bother with Ember.run.once, as we can detect an impending flush by inspecting the size of the local queue of _deferredTriggers + ### Ember Data 1.0.0-beta.5 _(January 11, 2014)_ * Normalize key in modelFor when a factory is not given. From f482da046e2d4e05c202befe2ebab39e44b4eb50 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 19 Feb 2014 16:12:01 -0600 Subject: [PATCH 0083/2527] Release 1.0.0-beta.7 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6dbac21a7aa..284fe0bbb10 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0-beta.7+canary +1.0.0-beta.7 From 0e7240e382e42f4723d64f0147f43f3fbfb61065 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 19 Feb 2014 16:14:45 -0600 Subject: [PATCH 0084/2527] Post release VERSION bump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 284fe0bbb10..6dbac21a7aa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0-beta.7 +1.0.0-beta.7+canary From d815ede00fc0beb6d995b006a5a66fd5222679fa Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 19 Feb 2014 16:18:04 -0600 Subject: [PATCH 0085/2527] 1.0.0-beta.7 CHANGELOG --- CHANGELOG.md | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac8609549df..56de2212041 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,86 @@ # Ember Data Changelog +### Ember DAta 1.0.0-beta.7 _(February 19, 2014)_ + +* Release 1.0.0-beta.7 +* Document required structure for DS.InvalidError +* Update ember version to 1.4.0 +* lock server while compiling assets +* [DOC] Fix extractArray +* Don't pass the resolver where it's not needed +* force jshint on failure +* explicitly set a handlebars dependency to a version known to work. +* Remove Dead Code from RESTAdapter's Test +* Ensure the SHA is included in the VERSION. +* Destroying the store now: +* Revert "remove unneeded and misleading "async" test helpers" +* Break Down JSONSerializer#serializeBelongsTo Test +* remove unneeded and misleading "async" test helpers +* Wait on all the findMany promises to resolve before resolving the store#fetchMany promise. +* A records initial currentState can be on the prototype. Not need in doing the extra set on each init +* create promise labels outside of already visually complex code-paths +* reduce reusing argument variables, as it reduces clarity and makes debugging harder. +* hasMany relationship property are essentially readOnly, lets mark them as such. +* Improved assertion if an non-ember-data model has snuck in this far. +* Update instructions for running tests. +* Maintain consistency of internal changed attributes hash. +* Remove 0.13 era architecture file. +* Remove Ruby remnants. +* Add `grunt docs` task. +* Use local versions of grunt and bower for Travis. +* Do not generate a gzip report from uglify:dist. +* Add current revision back to build output. +* keep a local version of grunt-cli (dev only) +* Fix `grunt server` automated testing upon file change. +* Ensure builds are generated before publishing. +* Add build publishing to builds.emberjs.com. +* Fix the links to DS.Model and DS.Transform in the DS Namespace method docs +* Enable multi-channel testing. +* Allow testing against multiple versions of Ember & jQuery. +* Remove restriction for jQuery version in bower.json +* Object.create does not exist in old IE. +* Fix bug where an undefined id would trigger a `findAll` +* Avoid instance of aliasMethod due to problems with Chrome debugger +* Use latest stable Ember.js +* Cleanup. - Ember.computed takes the DK as a first argument, no need to all property on it again - misc formatting as I go. +* Upgrade QUnit to v1.13.0 +* Use defeatureify to strip debug statements from output. +* Prefer Promise.cast over resolve. +* Use the new naming for active_model_adapter integration tests. +* Ensure that bower is installed. +* mark more model properties as readOnly +* allow connect port to be configurable +* misc cleanup +* once is already saved off at the top of the file +* add `grunt server`, and ensure the server(dev) version builds tests, so you can run tests +* postinstall bower install +* lazy create errors object on models +* Remove incorrect return documentation on store#pushPayload +* Pass arguments to `options.defaultValue` if a function. +* Revert "DateTransform serializes as a number instead of string. The deserializer was already considering this case. Adds millisecond precision to DateTransform" +* Should install grunt-cli globally. +* Now ember-data is built by `grunt buildPackages` +* Fix ember-data version +* Add missing task `grunt test` +* Export `Store` as default from ./system/store +* Use `expectDeprecation` helper in lookup tests +* Import `Store` instead of referencing it via `DS.Store` +* Register already imported transforms instead of `DS.XXX` +* Add `bower_components` to .gitignore +* Remove ruby-land tasks from Travis. +* Remove remnants of Ruby-land. +* Post release version bump. +* add grunt and bower install to .travis.yml +* update README with grunt workflow +* readd ContainerProxy to DS namespace +* fix build, import more test helper definitions from ember-dev +* fix banner generation a bit +* Do not trigger didSetProperty if value is unchanged. +* add watch option, fix some test oddities +* move some requires around +* move grunt tasks into folders +* ES6! + ### Ember Data 1.0.0-beta.6 _(January 25, 2014)_ * DateTransform serializes as a number instead of string. The deserializer was already considering this case. Adds millisecond precision to DateTransform From b45e23babb7865a0e6659ecbd54977b275576c23 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 19 Feb 2014 16:27:09 -0600 Subject: [PATCH 0086/2527] actually update version for post-release version bump --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6dbac21a7aa..4603afe218d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0-beta.7+canary +1.0.0-beta.8+canary From 115d9aa2c6ed6cf55bc0e11aa55608c8f9062220 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 20 Feb 2014 09:40:52 -0600 Subject: [PATCH 0087/2527] fix small typo in CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56de2212041..64fafc8c205 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Ember Data Changelog -### Ember DAta 1.0.0-beta.7 _(February 19, 2014)_ +### Ember Data 1.0.0-beta.7 _(February 19, 2014)_ * Release 1.0.0-beta.7 * Document required structure for DS.InvalidError From 03c630b42261bb3d3f9fc43d13f236f3393463bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ug=CC=A7is=20Ozols?= Date: Sat, 22 Feb 2014 22:23:53 +0200 Subject: [PATCH 0088/2527] Remove duplicate changelog entry. --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64fafc8c205..e102e045dac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -106,7 +106,6 @@ * The store's adapter property requires a string * Rename dataAdapter to data-adapter * Calls rake test[all] using bundle exec since CI was failing -* DateTransform serializes as a number instead of string. The deserializer was already considering this case. Adds millisecond precision to DateTransform * fixed behaviour of store.all() in combination with store.unloadAll() which caused elements to stay in the RecordArray, even if they should have been removed. ref #1611 * another quick fix, which should reduce run-loop pressure. * Don't bother with Ember.run.once, as we can detect an impending flush by inspecting the size of the local queue of _deferredTriggers From 615a186dadcaf29ad4e70d149d1da861559d30ff Mon Sep 17 00:00:00 2001 From: "A. Speller" Date: Fri, 28 Feb 2014 14:24:26 +0000 Subject: [PATCH 0089/2527] Improve store docs to use container lookup not concrete class --- packages/ember-data/lib/system/store.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 60157744ac6..b44d0cd053a 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -66,7 +66,7 @@ function coerceId(id) { specify which store should be used: ```javascript - var person = store.find(App.Person, 123); + var person = store.find('person', 123); ``` By default, the store will talk to your backend using a standard @@ -325,7 +325,7 @@ Store = Ember.Object.extend({ parameter: ```javascript - store.find(App.Person, { page: 1 }); + store.find('person', { page: 1 }); ``` This will ask the adapter's `findQuery` method to find the records for @@ -719,7 +719,7 @@ Store = Ember.Object.extend({ Example ```javascript - var local_posts = store.all(App.Post); + var local_posts = store.all('post'); ``` @method all @@ -745,7 +745,7 @@ Store = Ember.Object.extend({ This method unloads all of the known records for a given type. ```javascript - store.unloadAll(App.Post); + store.unloadAll('post'); ``` @method unloadAll @@ -789,7 +789,7 @@ Store = Ember.Object.extend({ Example ```javascript - store.filter(App.Post, {unread: true}, function(post) { + store.filter('post', {unread: true}, function(post) { return post.get('unread'); }).then(function(unreadPosts) { unreadPosts.get('length'); // 5 @@ -834,9 +834,9 @@ Store = Ember.Object.extend({ Example ```javascript - store.recordIsLoaded(App.Post, 1); // false - store.find(App.Post, 1).then(function() { - store.recordIsLoaded(App.Post, 1); // true + store.recordIsLoaded('post', 1); // false + store.find('post', 1).then(function() { + store.recordIsLoaded('post', 1); // true }); ``` From 63e28770c9701d9dd8f99d77a8798476423f9f49 Mon Sep 17 00:00:00 2001 From: "A. Speller" Date: Fri, 28 Feb 2014 14:38:28 +0000 Subject: [PATCH 0090/2527] Use string model lookup instead of class lookup --- packages/ember-data/lib/system/model/model.js | 14 +++++++------- .../lib/system/record_arrays/record_array.js | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 88a8d387aa6..14760500849 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -59,7 +59,7 @@ var Model = Ember.Object.extend(Ember.Evented, { Example ```javascript - var record = store.createRecord(App.Model); + var record = store.createRecord('model'); record.get('isLoaded'); // true store.find('model', 1).then(function(model) { @@ -81,7 +81,7 @@ var Model = Ember.Object.extend(Ember.Evented, { Example ```javascript - var record = store.createRecord(App.Model); + var record = store.createRecord('model'); record.get('isDirty'); // true store.find('model', 1).then(function(model) { @@ -105,7 +105,7 @@ var Model = Ember.Object.extend(Ember.Evented, { Example ```javascript - var record = store.createRecord(App.Model); + var record = store.createRecord('model'); record.get('isSaving'); // false var promise = record.save(); record.get('isSaving'); // true @@ -130,7 +130,7 @@ var Model = Ember.Object.extend(Ember.Evented, { Example ```javascript - var record = store.createRecord(App.Model); + var record = store.createRecord('model'); record.get('isDeleted'); // false record.deleteRecord(); record.get('isDeleted'); // true @@ -150,7 +150,7 @@ var Model = Ember.Object.extend(Ember.Evented, { Example ```javascript - var record = store.createRecord(App.Model); + var record = store.createRecord('model'); record.get('isNew'); // true record.save().then(function(model) { @@ -186,7 +186,7 @@ var Model = Ember.Object.extend(Ember.Evented, { Example ```javascript - var record = store.createRecord(App.Model); + var record = store.createRecord('model'); record.get('dirtyType'); // 'created' ``` @@ -253,7 +253,7 @@ var Model = Ember.Object.extend(Ember.Evented, { attribute. ```javascript - var record = store.createRecord(App.Model); + var record = store.createRecord('model'); record.get('id'); // null store.find('model', 1).then(function(model) { diff --git a/packages/ember-data/lib/system/record_arrays/record_array.js b/packages/ember-data/lib/system/record_arrays/record_array.js index 4ff52c96722..5cbc9ab27b2 100644 --- a/packages/ember-data/lib/system/record_arrays/record_array.js +++ b/packages/ember-data/lib/system/record_arrays/record_array.js @@ -45,7 +45,7 @@ var RecordArray = Ember.ArrayProxy.extend(Ember.Evented, { Example ```javascript - var people = store.all(App.Person); + var people = store.all('person'); people.get('isLoaded'); // true ``` @@ -59,7 +59,7 @@ var RecordArray = Ember.ArrayProxy.extend(Ember.Evented, { Example ```javascript - var people = store.all(App.Person); + var people = store.all('person'); people.get('isUpdating'); // false people.update(); people.get('isUpdating'); // true @@ -100,7 +100,7 @@ var RecordArray = Ember.ArrayProxy.extend(Ember.Evented, { Example ```javascript - var people = store.all(App.Person); + var people = store.all('person'); people.get('isUpdating'); // false people.update(); people.get('isUpdating'); // true @@ -145,7 +145,7 @@ var RecordArray = Ember.ArrayProxy.extend(Ember.Evented, { Example ```javascript - var messages = store.all(App.Message); + var messages = store.all('message'); messages.forEach(function(message) { message.set('hasBeenSeen', true); }); From 0a5995bb3c38fa20fdd5228c4dbb85246de17955 Mon Sep 17 00:00:00 2001 From: Ujjwal Thaakar Date: Sat, 1 Mar 2014 01:56:17 +0530 Subject: [PATCH 0091/2527] Fixed typo in isDirty example It should be a get call instead of a set call --- packages/ember-data/lib/system/model/model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 14760500849..3220f7e3050 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -87,7 +87,7 @@ var Model = Ember.Object.extend(Ember.Evented, { store.find('model', 1).then(function(model) { model.get('isDirty'); // false model.set('foo', 'some value'); - model.set('isDirty'); // true + model.get('isDirty'); // true }); ``` From 0628a8f82ecd1c97f36b52805eab8b680244f695 Mon Sep 17 00:00:00 2001 From: bmac Date: Sun, 2 Mar 2014 09:26:06 -0500 Subject: [PATCH 0092/2527] Use the ApplicationAdapter property instead of creating a custom Store just to create a custom adapter. --- packages/ember-data/lib/system/adapter.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index b6f7a22701b..2237059fff9 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -32,11 +32,11 @@ var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'n } }); ``` - + The `DS.InvalidError` must be constructed with a single object whose keys are the invalid model properties, and whose values are the corresponding error messages. For example: - + ```javascript return new DS.InvalidError({ length: 'Must be less than 15', @@ -67,20 +67,26 @@ InvalidError.prototype = Ember.create(Error.prototype); ### Creating an Adapter - First, create a new subclass of `DS.Adapter`: + Create a new subclass of `DS.Adapter` then assign + it to the `ApplicationAdapter` property. ```javascript - App.MyAdapter = DS.Adapter.extend({ + var MyAdapter = DS.Adapter.extend({ // ...your code here }); + + App.ApplicationAdapter = MyAdapter; ``` - To tell your store which adapter to use, set its `adapter` property: + Model specific adapters can be created by assigning the adapter + class to the `ModelName` + `Adapter` property. ```javascript - App.store = DS.Store.create({ - adapter: 'MyAdapter' + var MyPostAdapter = DS.Adapter.extend({ + // ...post specific adapter code goes here }); + + App.PostAdapter = MyPostAdapter; ``` `DS.Adapter` is an abstract base class that you should override in your From a89d96588c2e5862e24470e4219dd5f1dc139561 Mon Sep 17 00:00:00 2001 From: Griffin Smith Date: Mon, 3 Mar 2014 11:03:28 -0700 Subject: [PATCH 0093/2527] Copy-editing --- packages/ember-data/lib/system/adapter.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 2237059fff9..52e9dd9534d 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -67,8 +67,8 @@ InvalidError.prototype = Ember.create(Error.prototype); ### Creating an Adapter - Create a new subclass of `DS.Adapter` then assign - it to the `ApplicationAdapter` property. + Create a new subclass of `DS.Adapter`, then assign + it to the `ApplicationAdapter` property of the application. ```javascript var MyAdapter = DS.Adapter.extend({ @@ -78,12 +78,12 @@ InvalidError.prototype = Ember.create(Error.prototype); App.ApplicationAdapter = MyAdapter; ``` - Model specific adapters can be created by assigning the adapter - class to the `ModelName` + `Adapter` property. + Model-specific adapters can be created by assigning your adapter + class to the `ModelName` + `Adapter` property of the application. ```javascript var MyPostAdapter = DS.Adapter.extend({ - // ...post specific adapter code goes here + // ...Post-specific adapter code goes here }); App.PostAdapter = MyPostAdapter; From 7e517246073515f4ef039d6df35c1f267e0066b1 Mon Sep 17 00:00:00 2001 From: Denis Nazarov Date: Tue, 4 Mar 2014 17:09:18 -0500 Subject: [PATCH 0094/2527] change documentation from hash to payload --- packages/ember-data/lib/serializers/rest_serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index ab58a9f6e80..800ef189b49 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -197,7 +197,7 @@ var RESTSerializer = JSONSerializer.extend({ @method normalizePayload @param {subclass of DS.Model} type - @param {Object} hash + @param {Object} payload @returns {Object} the normalized payload */ normalizePayload: function(type, payload) { From 9745f8c60e405046f5e64c57936093f718c7dbe3 Mon Sep 17 00:00:00 2001 From: mfeckie Date: Wed, 5 Mar 2014 22:46:21 +0800 Subject: [PATCH 0095/2527] Minor typo --- .../activemodel-adapter/lib/system/embedded_records_mixin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index caa0ec4cd9f..992be981a3a 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -25,7 +25,7 @@ import {pluralize} from "../../../ember-inflector/lib/main"; var EmbeddedRecordsMixin = Ember.Mixin.create({ /** - Serialize has-may relationship when it is configured as embedded objects. + Serialize has-many relationship when it is configured as embedded objects. @method serializeHasMany */ From 289c18fc3b9f00d231949da1011f9812654895a3 Mon Sep 17 00:00:00 2001 From: Teddy Zeenny Date: Wed, 5 Mar 2014 17:51:13 +0200 Subject: [PATCH 0096/2527] Update data adapter test with new Ember version --- packages/ember-data/tests/integration/debug_adapter_test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/tests/integration/debug_adapter_test.js b/packages/ember-data/tests/integration/debug_adapter_test.js index f25b19f20d2..bf33c9b5afb 100644 --- a/packages/ember-data/tests/integration/debug_adapter_test.js +++ b/packages/ember-data/tests/integration/debug_adapter_test.js @@ -23,7 +23,7 @@ module("DS.DebugAdapter", { debugAdapter.reopen({ getModelTypes: function() { - return Ember.A([App.Post]); + return Ember.A([{ klass: App.Post, name: 'post' }]); } }); }, @@ -37,7 +37,7 @@ test("Watching Model Types", function() { var added = function(types) { equal(types.length, 1); - equal(types[0].name, 'App.Post'); + equal(types[0].name, 'post'); equal(types[0].count, 0); strictEqual(types[0].object, App.Post); }; From 1bb0d9562a0e99c7995ca81310d9d6bc4000b550 Mon Sep 17 00:00:00 2001 From: Teddy Zeenny Date: Wed, 5 Mar 2014 19:01:22 +0200 Subject: [PATCH 0097/2527] Make sure data adapter tests pass for Ember <= 1.4 --- .../ember-data/tests/integration/debug_adapter_test.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/tests/integration/debug_adapter_test.js b/packages/ember-data/tests/integration/debug_adapter_test.js index bf33c9b5afb..9e305ff4b7d 100644 --- a/packages/ember-data/tests/integration/debug_adapter_test.js +++ b/packages/ember-data/tests/integration/debug_adapter_test.js @@ -23,7 +23,12 @@ module("DS.DebugAdapter", { debugAdapter.reopen({ getModelTypes: function() { - return Ember.A([{ klass: App.Post, name: 'post' }]); + // Support Ember < 1.5. + // TODO: Remove this workaround (if statement) when Ember 1.5 is released. + if (!this.get('containerDebugAdapter')) { + return Ember.A([App.Post]); + } + return Ember.A([{ klass: App.Post, name: 'App.Post' }]); } }); }, @@ -37,7 +42,7 @@ test("Watching Model Types", function() { var added = function(types) { equal(types.length, 1); - equal(types[0].name, 'post'); + equal(types[0].name, 'App.Post'); equal(types[0].count, 0); strictEqual(types[0].object, App.Post); }; From 34278718f281b3d7a0d8da853ce9359d423aa6da Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 5 Mar 2014 15:36:44 -0500 Subject: [PATCH 0098/2527] Document the store#update method. --- packages/ember-data/lib/system/store.js | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index b44d0cd053a..2217beaf957 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1207,6 +1207,38 @@ Store = Ember.Object.extend({ serializer.pushPayload(this, payload); }, + /** + Update existing records in the store. Unlike [push](#method_push), + update will merge the new data properties with the existing + properties. This makes it safe to use with a subset of record + attributes. This method expects normalized data. + + `update` is useful if you app broadcasts partial updates to + records. + + ```js + App.Person = DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string') + }); + + store.get('person', 1).then(function(tom) { + tom.get('firstName'); // Tom + tom.get('lastName'); // Dale + + var updateEvent = {id: 1, firstName: "TomHuda"}; + store.update('person', updateEvent); + + tom.get('firstName'); // TomHuda + tom.get('lastName'); // Dale + }); + ``` + + @method update + @param {String} type + @param {Object} data + @return {DS.Model} the record that was updated. + */ update: function(type, data) { Ember.assert("You must include an `id` in a hash passed to `update`", data.id != null); From 937c962328adc44a06e8b63a02c9cd5fde090bf2 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 5 Mar 2014 16:44:48 -0500 Subject: [PATCH 0099/2527] Document the difference between Store push() vs. createRecord() ect. --- packages/ember-data/lib/system/store.js | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 2217beaf957..97a30b542cb 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -82,6 +82,39 @@ function coerceId(id) { You can learn more about writing a custom adapter by reading the `DS.Adapter` documentation. + ### Store createRecord() vs. push() vs. pushPayload() vs. update() + + The store provides multiple ways to create new records object. They have + some subtle differences in their use which are detailed below: + + [createRecord](#method_createRecord) is used for creating new + records on the client side. This will return a new record in the + `created.uncommitted` state. In order to persist this record to the + backend you will need to call `record.save()`. + + [push](#method_push) is used to notify Ember Data's store of new or + updated records that exist in the backend. This will return a record + in the `loaded.saved` state. The primary use-case for `store#push` is + to notify Ember Data about record updates that happen + outside of the normal adapter methods (for example + [SSE](http://dev.w3.org/html5/eventsource/) or [Web + Sockets](http://www.w3.org/TR/2009/WD-websockets-20091222/)). + + [pushPayload](#method_pushPayload) is a convenience wrapper for + `store#push` that will deserialize payloads if the model's + Serializer implements a `pushPayload` method. + + [update](#method_update) works like `push` accept it can handle + partial attributes without overwriting the existing record + properties. + + Note: When creating a new record using any of the above methods + Ember Data will update `DS.RecordArray`s such as those returned by + `store#all()`, `store#findAll()` or `store#filter()`. This means any + data bindings or computed properties that depend on the RecordArray + will automatically be synced to include the new or updated record + values. + @class Store @namespace DS @extends Ember.Object From e7c5efeef45da21bc2db5c16749a3856ecd8d206 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 11 Mar 2014 20:24:40 -0400 Subject: [PATCH 0100/2527] Remove `window` references in favor of `Ember.lookup`. --- packages/ember-data/lib/core.js | 4 ---- packages/ember-data/lib/main.js | 2 ++ tasks/browser.js | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/ember-data/lib/core.js b/packages/ember-data/lib/core.js index 91c50c53d4f..f1a357760b9 100644 --- a/packages/ember-data/lib/core.js +++ b/packages/ember-data/lib/core.js @@ -20,10 +20,6 @@ if ('undefined' === typeof DS) { VERSION: '<%= versionStamp %>' }); - if ('undefined' !== typeof window) { - window.DS = DS; - } - if (Ember.libraries) { Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); } diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index 185ce6cf4b9..5d1d7ccf8c2 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -105,4 +105,6 @@ DS.hasMany = hasMany; DS.ContainerProxy = ContainerProxy; +Ember.lookup.DS = DS; + export default DS; diff --git a/tasks/browser.js b/tasks/browser.js index 983be43ac10..c9dae679f94 100644 --- a/tasks/browser.js +++ b/tasks/browser.js @@ -1,10 +1,10 @@ module.exports = function(grunt) { - grunt.registerMultiTask('browser', 'Export the object in <%= pkg.name %> to the window', function() { + grunt.registerMultiTask('browser', 'Export the object in <%= pkg.name %> to Ember.lookup', function() { this.files.forEach(function(f) { var output = ['(function(global) {']; output.push.apply(output, f.src.map(grunt.file.read)); output.push("global.<%= pkg.namespace %> = requireModule('<%= pkg.name %>/lib/main')['default'];"); - output.push('}(window));'); + output.push('}(Ember.lookup));'); var banner = grunt.template.process(grunt.file.read(__dirname + "/../generators/license.js")); grunt.file.write(f.dest, banner + grunt.template.process(output.join('\n'))); }); From 2277f0618a900f5e17cb1264d44a92171b9f9949 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 11 Mar 2014 21:23:54 -0500 Subject: [PATCH 0101/2527] [doc] camelize `all` example for consistency --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 97a30b542cb..a7318b8c7f4 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -752,7 +752,7 @@ Store = Ember.Object.extend({ Example ```javascript - var local_posts = store.all('post'); + var localPosts = store.all('post'); ``` @method all From ab015eed0effaa68ac2abd33b58b7d2003861a3c Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 12 Mar 2014 10:45:30 -0400 Subject: [PATCH 0102/2527] Fix a typo, accept -> except --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index a7318b8c7f4..fdef6680a5b 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -104,7 +104,7 @@ function coerceId(id) { `store#push` that will deserialize payloads if the model's Serializer implements a `pushPayload` method. - [update](#method_update) works like `push` accept it can handle + [update](#method_update) works like `push`, except it can handle partial attributes without overwriting the existing record properties. From 47fb2e481bb33ad978e55b2ab2554eec23e7509f Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 14 Mar 2014 00:56:16 -0400 Subject: [PATCH 0103/2527] Deprecate App.Store in favor of App.ApplicationStore. This makes the application level store lookup much closer to the reset of our conventions (ala `App.ApplicationAdapter` and `App.ApplicationSerializer`). This change also allows specifying a custom store when using non-global resolver (i.e. EAK/ember-cli). Previously, we were only looking for a property `Store` hung off of the application instance. Now you can have a module named (in the case of stock EAK setup): `app/stores/application` or `app/application/store.js` (pods structure). A deprecation warning was added, and the prior technique still works so this is not a breaking change (although I believe that we should remove before the prior lookup prior to 1.0). --- packages/ember-data/lib/initializers.js | 10 ++++++--- .../tests/integration/application_test.js | 22 ++++++++++++++++++- .../tests/integration/debug_adapter_test.js | 2 +- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/packages/ember-data/lib/initializers.js b/packages/ember-data/lib/initializers.js index 30e561a999d..75f1ebaf396 100644 --- a/packages/ember-data/lib/initializers.js +++ b/packages/ember-data/lib/initializers.js @@ -20,6 +20,7 @@ var set = Ember.set; This code registers an injection for Ember.Application. If an Ember.js developer defines a subclass of DS.Store on their application, + as `App.ApplicationStore` (or via a module system that resolves to `store:application`) this code will automatically instantiate it and make it available on the router. @@ -28,7 +29,7 @@ var set = Ember.set; For example, imagine an Ember.js application with the following classes: - App.Store = DS.Store.extend({ + App.ApplicationStore = DS.Store.extend({ adapter: 'custom' }); @@ -36,7 +37,7 @@ var set = Ember.set; // ... }); - When the application is initialized, `App.Store` will automatically be + When the application is initialized, `App.ApplicationStore` will automatically be instantiated, and the instance of `App.PostsController` will have its `store` property set to that instance. @@ -51,7 +52,10 @@ Ember.onLoad('Ember.Application', function(Application) { name: "store", initialize: function(container, application) { - application.register('store:main', application.Store || Store); + Ember.deprecate('Specifying a custom Store for Ember Data on your global namespace as `App.Store` ' + + 'has been deprecated. Please use `App.ApplicationStore` instead.', !application.Store); + + application.register('store:main', container.lookupFactory('store:application') || application.Store || Store); // allow older names to be looked up diff --git a/packages/ember-data/tests/integration/application_test.js b/packages/ember-data/tests/integration/application_test.js index 6a7e341a514..11693fe8890 100644 --- a/packages/ember-data/tests/integration/application_test.js +++ b/packages/ember-data/tests/integration/application_test.js @@ -9,7 +9,7 @@ module("integration/application - Injecting a Custom Store", { setup: function() { Ember.run(function() { app = Ember.Application.create({ - Store: DS.Store.extend({ isCustom: true }), + ApplicationStore: DS.Store.extend({ isCustom: true }), FooController: Ember.Controller.extend(), ApplicationView: Ember.View.extend(), BazController: {}, @@ -35,6 +35,26 @@ test("If a store is instantiated, it should be made available to each controller ok(fooController.get('store.isCustom'), "the custom store was injected"); }); +test("registering App.Store is deprecated but functional", function(){ + Ember.run(app, 'destroy'); + + expectDeprecation(function(){ + Ember.run(function() { + app = Ember.Application.create({ + Store: DS.Store.extend({ isCustomButDeprecated: true }), + FooController: Ember.Controller.extend(), + }); + }); + }, 'Specifying a custom Store for Ember Data on your global namespace as `App.Store` ' + + 'has been deprecated. Please use `App.ApplicationStore` instead.'); + + container = app.__container__; + ok(container.lookup('store:main').get('isCustomButDeprecated'), "the custom store was instantiated"); + + var fooController = container.lookup('controller:foo'); + ok(fooController.get('store.isCustomButDeprecated'), "the custom store was injected"); +}); + module("integration/application - Injecting the Default Store", { setup: function() { Ember.run(function() { diff --git a/packages/ember-data/tests/integration/debug_adapter_test.js b/packages/ember-data/tests/integration/debug_adapter_test.js index 9e305ff4b7d..746a1734955 100644 --- a/packages/ember-data/tests/integration/debug_adapter_test.js +++ b/packages/ember-data/tests/integration/debug_adapter_test.js @@ -7,7 +7,7 @@ module("DS.DebugAdapter", { toString: function() { return 'App'; } }); - App.Store = DS.Store.extend({ + App.ApplicationStore = DS.Store.extend({ adapter: DS.Adapter.extend() }); From f1069a92af9612e1f87d365a90987d4cac5e0473 Mon Sep 17 00:00:00 2001 From: Kerrick Long Date: Sat, 15 Mar 2014 17:06:48 -0500 Subject: [PATCH 0104/2527] Remove reliance on global DS Most changes favor using imports, only using Ember.lookup.DS to avoid circular references. This is related to emberjs/data/#1800. --- .../ember-data/lib/serializers/json_serializer.js | 3 ++- packages/ember-data/lib/system/model/model.js | 7 ++++--- .../ember-data/lib/system/record_array_manager.js | 8 ++++---- .../lib/system/relationships/belongs_to.js | 14 ++++++++------ .../lib/system/relationships/has_many.js | 3 ++- packages/ember-data/lib/system/store.js | 7 ++++--- 6 files changed, 24 insertions(+), 18 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index b0567ff184c..37c4120eae1 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -1,3 +1,4 @@ +import {RelationshipChange} from "../system/changes"; var get = Ember.get, set = Ember.set, isNone = Ember.isNone; /** @@ -381,7 +382,7 @@ var JSONSerializer = Ember.Object.extend({ serializeHasMany: function(record, json, relationship) { var key = relationship.key; - var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship); + var relationshipType = RelationshipChange.determineRelationshipType(record.constructor, relationship); if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') { json[key] = get(record, key).mapBy('id'); diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 3220f7e3050..2802a21da20 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1,5 +1,6 @@ import RootState from "./states"; import Errors from "./errors"; +import {PromiseObject} from "../store"; /** @module ember-data */ @@ -337,7 +338,7 @@ var Model = Ember.Object.extend(Ember.Evented, { */ toJSON: function(options) { // container is for lazy transform lookups - var serializer = DS.JSONSerializer.create({ container: this.container }); + var serializer = Ember.lookup.DS.JSONSerializer.create({ container: this.container }); return serializer.serialize(this, options); }, @@ -888,7 +889,7 @@ var Model = Ember.Object.extend(Ember.Evented, { this._inFlightAttributes = this._attributes; this._attributes = {}; - return DS.PromiseObject.create({ promise: resolver.promise }); + return PromiseObject.create({ promise: resolver.promise }); }, /** @@ -932,7 +933,7 @@ var Model = Ember.Object.extend(Ember.Evented, { throw reason; }, "DS: Model#reload complete, update flags"); - return DS.PromiseObject.create({ promise: promise }); + return PromiseObject.create({ promise: promise }); }, // FOR USE DURING COMMIT PROCESS diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index 0dd3a8665f0..d6128f49c41 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -2,7 +2,7 @@ @module ember-data */ -import {ManyArray} from "./record_arrays"; +import {RecordArray, FilteredRecordArray, AdapterPopulatedRecordArray, ManyArray} from "./record_arrays"; var get = Ember.get, set = Ember.set; var forEach = Ember.EnumerableUtils.forEach; @@ -177,7 +177,7 @@ var RecordArrayManager = Ember.Object.extend({ @return {DS.RecordArray} */ createRecordArray: function(type) { - var array = DS.RecordArray.create({ + var array = RecordArray.create({ type: type, content: Ember.A(), store: this.store, @@ -198,7 +198,7 @@ var RecordArrayManager = Ember.Object.extend({ @return {DS.FilteredRecordArray} */ createFilteredRecordArray: function(type, filter) { - var array = DS.FilteredRecordArray.create({ + var array = FilteredRecordArray.create({ type: type, content: Ember.A(), store: this.store, @@ -220,7 +220,7 @@ var RecordArrayManager = Ember.Object.extend({ @return {DS.AdapterPopulatedRecordArray} */ createAdapterPopulatedRecordArray: function(type, query) { - var array = DS.AdapterPopulatedRecordArray.create({ + var array = AdapterPopulatedRecordArray.create({ type: type, query: query, content: Ember.A(), diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index 84c11f4cbf9..b5421b32597 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -4,6 +4,8 @@ var get = Ember.get, set = Ember.set, var Promise = Ember.RSVP.Promise; import {Model} from "../model"; +import {PromiseObject} from "../store"; +import {RelationshipChange} from "../changes"; /** @module ember-data @@ -18,7 +20,7 @@ function asyncBelongsTo(type, options, meta) { if (arguments.length === 2) { Ember.assert("You can only add a '" + type + "' record to this relationship", !value || value instanceof store.modelFor(type)); - return value === undefined ? null : DS.PromiseObject.create({ + return value === undefined ? null : PromiseObject.create({ promise: Promise.cast(value, promiseLabel) }); } @@ -28,12 +30,12 @@ function asyncBelongsTo(type, options, meta) { if(!isNone(belongsTo)) { promise = store.fetchRecord(belongsTo) || Promise.cast(belongsTo, promiseLabel); - return DS.PromiseObject.create({ + return PromiseObject.create({ promise: promise }); } else if (link) { promise = store.findBelongsTo(this, link, meta); - return DS.PromiseObject.create({ + return PromiseObject.create({ promise: promise }); } else { @@ -94,7 +96,7 @@ function belongsTo(type, options) { options = type; type = undefined; } else { - Ember.assert("The first argument DS.belongsTo must be a model type or string, like DS.belongsTo(App.Person)", !!type && (typeof type === 'string' || DS.Model.detect(type))); + Ember.assert("The first argument DS.belongsTo must be a model type or string, like DS.belongsTo(App.Person)", !!type && (typeof type === 'string' || Model.detect(type))); } options = options || {}; @@ -157,7 +159,7 @@ Model.reopen({ if (oldParent) { var store = get(record, 'store'), - change = DS.RelationshipChange.createChange(record, oldParent, store, { key: key, kind: "belongsTo", changeType: "remove" }); + change = RelationshipChange.createChange(record, oldParent, store, { key: key, kind: "belongsTo", changeType: "remove" }); change.sync(); this._changesToSync[key] = change; @@ -178,7 +180,7 @@ Model.reopen({ if (newParent) { var store = get(record, 'store'), - change = DS.RelationshipChange.createChange(record, newParent, store, { key: key, kind: "belongsTo", changeType: "add" }); + change = RelationshipChange.createChange(record, newParent, store, { key: key, kind: "belongsTo", changeType: "add" }); change.sync(); } diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index d363736e6d8..83ad05a81e2 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -2,6 +2,7 @@ @module ember-data */ +import {PromiseArray} from "../store"; var get = Ember.get, set = Ember.set, setProperties = Ember.setProperties; function asyncHasMany(type, options, meta) { @@ -31,7 +32,7 @@ function asyncHasMany(type, options, meta) { return relationship; }, null, "DS: Async hasMany records received"); - return DS.PromiseArray.create({ + return PromiseArray.create({ promise: promise }); }).meta(meta).readOnly(); diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index fdef6680a5b..c50d05efc05 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -5,6 +5,7 @@ @module ember-data */ +import Adapter from "./adapter"; var get = Ember.get, set = Ember.set; var once = Ember.run.once; var isNone = Ember.isNone; @@ -128,7 +129,7 @@ Store = Ember.Object.extend({ init: function() { // internal bookkeeping; not observable this.typeMaps = {}; - this.recordArrayManager = DS.RecordArrayManager.create({ + this.recordArrayManager = Ember.lookup.DS.RecordArrayManager.create({ store: this }); this._relationshipChanges = {}; @@ -188,7 +189,7 @@ Store = Ember.Object.extend({ defaultAdapter: Ember.computed('adapter', function() { var adapter = get(this, 'adapter'); - Ember.assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name or a factory', !(adapter instanceof DS.Adapter)); + Ember.assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name or a factory', !(adapter instanceof Adapter)); if (typeof adapter === 'string') { adapter = this.container.lookup('adapter:' + adapter) || this.container.lookup('adapter:application') || this.container.lookup('adapter:-rest'); @@ -1519,7 +1520,7 @@ function normalizeRelationships(store, type, data, record) { } function deserializeRecordId(store, data, key, relationship, id) { - if (isNone(id) || id instanceof DS.Model) { + if (isNone(id) || id instanceof Ember.lookup.DS.Model) { return; } From 207081863a89aee95c3796ba0cd0a46b1994396a Mon Sep 17 00:00:00 2001 From: Kerrick Long Date: Sat, 15 Mar 2014 19:19:47 -0500 Subject: [PATCH 0105/2527] Remove internal reliance on Ember.lookup.DS in favor of requireModule(). --- packages/ember-data/lib/system/model/model.js | 4 +++- packages/ember-data/lib/system/store.js | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 2802a21da20..909ce26aba7 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -9,6 +9,7 @@ var get = Ember.get, set = Ember.set, merge = Ember.merge, Promise = Ember.RSVP.Promise; +var JSONSerializer; var retrieveFromCurrentState = Ember.computed('currentState', function(key, value) { return get(get(this, 'currentState'), key); }).readOnly(); @@ -337,8 +338,9 @@ var Model = Ember.Object.extend(Ember.Evented, { @returns {Object} A JSON representation of the object. */ toJSON: function(options) { + if (!JSONSerializer) { JSONSerializer = requireModule("ember-data/lib/serializers/json_serializer")["default"]; } // container is for lazy transform lookups - var serializer = Ember.lookup.DS.JSONSerializer.create({ container: this.container }); + var serializer = JSONSerializer.create({ container: this.container }); return serializer.serialize(this, options); }, diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index c50d05efc05..dc63c1dc4bf 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -14,7 +14,7 @@ var indexOf = Ember.EnumerableUtils.indexOf; var map = Ember.EnumerableUtils.map; var Promise = Ember.RSVP.Promise; var copy = Ember.copy; -var Store, PromiseObject, PromiseArray; +var Store, PromiseObject, PromiseArray, RecordArrayManager, Model; // Implementors Note: // @@ -128,8 +128,9 @@ Store = Ember.Object.extend({ */ init: function() { // internal bookkeeping; not observable + if (!RecordArrayManager) { RecordArrayManager = requireModule("ember-data/lib/system/record_array_manager")["default"]; } this.typeMaps = {}; - this.recordArrayManager = Ember.lookup.DS.RecordArrayManager.create({ + this.recordArrayManager = RecordArrayManager.create({ store: this }); this._relationshipChanges = {}; @@ -1520,7 +1521,8 @@ function normalizeRelationships(store, type, data, record) { } function deserializeRecordId(store, data, key, relationship, id) { - if (isNone(id) || id instanceof Ember.lookup.DS.Model) { + if (!Model) { Model = requireModule("ember-data/lib/system/model")["Model"]; } + if (isNone(id) || id instanceof Model) { return; } From f7ea0ffec91ed5829b2cab1b824e96929eb190e4 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 14 Mar 2014 14:11:36 -0400 Subject: [PATCH 0106/2527] Store#pushPayload should use the type's serializer for normalizing --- .../lib/serializers/rest_serializer.js | 5 +- .../ember-data/tests/unit/store/push_test.js | 73 ++++++++++++++++++- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index 800ef189b49..2383dfe7966 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -568,11 +568,12 @@ var RESTSerializer = JSONSerializer.extend({ for (var prop in payload) { var typeName = this.typeForRoot(prop), - type = store.modelFor(typeName); + type = store.modelFor(typeName), + typeSerializer = store.serializerFor(type); /*jshint loopfunc:true*/ var normalizedArray = map.call(Ember.makeArray(payload[prop]), function(hash) { - return this.normalize(type, hash, prop); + return typeSerializer.normalize(type, hash, prop); }, this); store.pushMany(typeName, normalizedArray); diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index ba9fb9fb182..56d5a17967f 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -210,8 +210,43 @@ test("Calling pushPayload allows pushing singular payload properties", function equal(post.get('postTitle'), "Ember rocks (updated)", "You can update data in the store"); }); -test("Calling pushPayload without a type uses application serializer", function () { - expect(2); +test("Calling pushPayload should use the type's serializer for normalizing", function () { + expect(4); + env.container.register('serializer:post', DS.RESTSerializer.extend({ + normalize: function(store, payload) { + ok(true, "normalized is called on Post serializer"); + return this._super(store, payload); + } + })); + env.container.register('serializer:person', DS.RESTSerializer.extend({ + normalize: function(store, payload) { + ok(true, "normalized is called on Person serializer"); + return this._super(store, payload); + } + })); + + store.pushPayload('post', { + posts: [{ + id: 1, + postTitle: "Ember rocks" + }], + people: [{ + id: 2, + firstName: "Yehuda" + }] + }); + + var post = store.getById('post', 1); + + equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); + + var person = store.getById('person', 2); + + equal(person.get('firstName'), "Yehuda", "you can push raw JSON into the store"); +}); + +test("Calling pushPayload without a type uses application serializer's pushPayload method", function () { + expect(1); env.container.register('serializer:application', DS.RESTSerializer.extend({ pushPayload: function(store, payload) { @@ -224,8 +259,42 @@ test("Calling pushPayload without a type uses application serializer", function id: '1', postTitle: "Ember rocks" }]}); +}); + +test("Calling pushPayload without a type should use a model's serializer when normalizing", function () { + expect(4); + + env.container.register('serializer:post', DS.RESTSerializer.extend({ + normalize: function(store, payload) { + ok(true, "normalized is called on Post serializer"); + return this._super(store, payload); + } + })); + + env.container.register('serializer:application', DS.RESTSerializer.extend({ + normalize: function(store, payload) { + ok(true, "normalized is called on Application serializer"); + return this._super(store, payload); + } + })); + + + store.pushPayload({ + posts: [{ + id: '1', + postTitle: "Ember rocks" + }], + people: [{ + id: '2', + firstName: 'Yehuda' + }] + }); var post = store.getById('post', 1); equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); + + var person = store.getById('person', 2); + + equal(person.get('firstName'), "Yehuda", "you can push raw JSON into the store"); }); From 72f376c0f9a310633702f7286751940928193575 Mon Sep 17 00:00:00 2001 From: Dan McClain Date: Tue, 18 Mar 2014 21:04:11 -0400 Subject: [PATCH 0107/2527] Documents invalid use of `attr` for attribute of `id` There is an assertion that prevents the use of `attr` to define a attributes named `id`, this adds API documentation of that fact --- packages/ember-data/lib/system/model/attributes.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 8c78ae2a1ad..8e1da13fa27 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -236,6 +236,8 @@ function getValue(record, key) { `boolean` and `date`. You can define your own transforms by subclassing [DS.Transform](/api/data/classes/DS.Transform.html). + Note that you cannot use `attr` to define an attribute of `id`. + `DS.attr` takes an optional hash as a second parameter, currently supported options are: From 46d9d8ac3f912c2705b883fcee119fc71c947368 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 19 Mar 2014 18:32:43 -0400 Subject: [PATCH 0108/2527] Clarify adapter header documentation --- .../ember-data/lib/adapters/rest_adapter.js | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 3fa7e443d04..ebc1d4113e8 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -87,8 +87,10 @@ var forEach = Ember.ArrayPolyfills.forEach; ### Headers customization - Some APIs require HTTP headers, e.g. to provide an API key. An array of - headers can be added to the adapter which are passed with every request: + Some APIs require HTTP headers, e.g. to provide an API key. Arbitrary + headers can be set as key/value pairs on the `RESTAdapter`'s `headers` + object and Ember Data will send them along with each ajax request. + ```js DS.RESTAdapter.reopen({ @@ -99,6 +101,20 @@ var forEach = Ember.ArrayPolyfills.forEach; }); ``` + `headers` can also be used as a computed property to support dynamic + headers. + + ```js + App.ApplicationAdapter = DS.RESTAdapter.extend({ + headers: function() { + return { + "API_KEY": this.get("session.authToken"), + "ANOTHER_HEADER": "Some header value" + }; + }.property("session.authToken") + }); + ``` + @class RESTAdapter @constructor @namespace DS @@ -138,8 +154,9 @@ var RESTAdapter = Adapter.extend({ */ /** - Some APIs require HTTP headers, e.g. to provide an API key. An array of - headers can be added to the adapter which are passed with every request: + Some APIs require HTTP headers, e.g. to provide an API key. Arbitrary + headers can be set as key/value pairs on the `RESTAdapter`'s `headers` + object and Ember Data will send them along with each ajax request. ```javascript DS.RESTAdapter.reopen({ From a3bcc3966c1acf79a21c9e228917e6953c954a71 Mon Sep 17 00:00:00 2001 From: Dan McClain Date: Thu, 20 Mar 2014 06:43:21 -0400 Subject: [PATCH 0109/2527] Expands isDeleted documentation Expands the example to show deletion states --- packages/ember-data/lib/system/model/model.js | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 909ce26aba7..6d093c5c8b8 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -133,9 +133,25 @@ var Model = Ember.Object.extend(Ember.Evented, { ```javascript var record = store.createRecord('model'); - record.get('isDeleted'); // false + record.get('isDeleted'); // false record.deleteRecord(); - record.get('isDeleted'); // true + + // Locally deleted + record.get('isDeleted'); // true + record.get('isDirty'); // true + record.get('isSaving'); // false + + // Persisting the deletion + var promise = record.save(); + record.get('isDeleted'); // true + record.get('isSaving'); // true + + // Deletion Persisted + promise.then(function() { + record.get('isDeleted'); // true + record.get('isSaving'); // false + record.get('isDirty'); // false + }); ``` @property isDeleted From cb6d0862d6a7e9eb80468d8f08431f06183e54cb Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 21 Mar 2014 14:59:15 -0400 Subject: [PATCH 0110/2527] Add an example of sending cookie information in the header and updated confusing reopen example. --- .../ember-data/lib/adapters/rest_adapter.js | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index ebc1d4113e8..dbe92a2c284 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -93,7 +93,7 @@ var forEach = Ember.ArrayPolyfills.forEach; ```js - DS.RESTAdapter.reopen({ + App.ApplicationAdapter = DS.RESTAdapter.extend({ headers: { "API_KEY": "secret key", "ANOTHER_HEADER": "Some header value" @@ -102,7 +102,8 @@ var forEach = Ember.ArrayPolyfills.forEach; ``` `headers` can also be used as a computed property to support dynamic - headers. + headers. In the example below, the `session` object has been + injected into an adapter by Ember's container. ```js App.ApplicationAdapter = DS.RESTAdapter.extend({ @@ -115,6 +116,24 @@ var forEach = Ember.ArrayPolyfills.forEach; }); ``` + In some cases, your dynamic headers may require data from some + object outside of Ember's observer system (for example + `document.cookie`). You can use the + [volatile](/api/classes/Ember.ComputedProperty.html#method_volatile) + function to set the property into a non-chached mode causing the headers to + be recomputed with every request. + + ```js + App.ApplicationAdapter = DS.RESTAdapter.extend({ + headers: function() { + return { + "API_KEY": Ember.get(document.cookie.match(/apiKey\=([^;]*)/), "1"), + "ANOTHER_HEADER": "Some header value" + }; + }.property().volatile(); + }); + ``` + @class RESTAdapter @constructor @namespace DS @@ -154,12 +173,14 @@ var RESTAdapter = Adapter.extend({ */ /** - Some APIs require HTTP headers, e.g. to provide an API key. Arbitrary - headers can be set as key/value pairs on the `RESTAdapter`'s `headers` - object and Ember Data will send them along with each ajax request. + Some APIs require HTTP headers, e.g. to provide an API + key. Arbitrary headers can be set as key/value pairs on the + `RESTAdapter`'s `headers` object and Ember Data will send them + along with each ajax request. For dynamic headers see [headers + customization](/api/data/classes/DS.RESTAdapter.html#toc_headers-customization). ```javascript - DS.RESTAdapter.reopen({ + App.ApplicationAdapter = DS.RESTAdapter.extend({ headers: { "API_KEY": "secret key", "ANOTHER_HEADER": "Some header value" From f13dfe400bbe77b374407ade5bf4767a28d79e8f Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 21 Mar 2014 16:04:35 -0400 Subject: [PATCH 0111/2527] Fix the ActiveModelAdapter @extends docstring The RESTAdapter properties should show up on the ActiveModelAdapter api docs page. --- packages/activemodel-adapter/lib/system/active_model_adapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index 61179d58862..bff0d7537db 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -58,7 +58,7 @@ var decamelize = Ember.String.decamelize, @class ActiveModelAdapter @constructor @namespace DS - @extends DS.Adapter + @extends DS.RESTAdapter **/ var ActiveModelAdapter = RESTAdapter.extend({ From 90d299e4f794fb102a69dc1516cfb8638266aa41 Mon Sep 17 00:00:00 2001 From: Cory Forsyth Date: Mon, 24 Mar 2014 18:16:08 -0700 Subject: [PATCH 0112/2527] Fix typo additonal -> additional --- packages/ember-inflector/tests/system/inflector_test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ember-inflector/tests/system/inflector_test.js b/packages/ember-inflector/tests/system/inflector_test.js index 21addd219f7..7cf0618b6d4 100644 --- a/packages/ember-inflector/tests/system/inflector_test.js +++ b/packages/ember-inflector/tests/system/inflector_test.js @@ -8,7 +8,7 @@ module('ember-inflector.dsl', { } }); -test('ability to add additonal pluralization rules', function(){ +test('ability to add additional pluralization rules', function(){ equal(inflector.pluralize('cow'), 'cow', 'no pluralization rule'); inflector.plural(/$/, 's'); @@ -16,7 +16,7 @@ test('ability to add additonal pluralization rules', function(){ equal(inflector.pluralize('cow'), 'cows', 'pluralization rule was applied'); }); -test('ability to add additonal singularization rules', function(){ +test('ability to add additional singularization rules', function(){ equal(inflector.singularize('cows'), 'cows', 'no singularization rule was applied'); inflector.singular(/s$/, ''); @@ -24,7 +24,7 @@ test('ability to add additonal singularization rules', function(){ equal(inflector.singularize('cows'), 'cow', 'singularization rule was applied'); }); -test('ability to add additonal uncountable rules', function(){ +test('ability to add additional uncountable rules', function(){ inflector.plural(/$/, 's'); equal(inflector.pluralize('cow'), 'cows', 'pluralization rule was applied'); @@ -32,7 +32,7 @@ test('ability to add additonal uncountable rules', function(){ equal(inflector.pluralize('cow'), 'cow', 'pluralization rule NOT was applied'); }); -test('ability to add additonal irregular rules', function(){ +test('ability to add additional irregular rules', function(){ inflector.singular(/s$/, ''); inflector.plural(/$/, 's'); From eed663e27034b38ad2d2f9779d29d112e5750255 Mon Sep 17 00:00:00 2001 From: Cory Forsyth Date: Mon, 24 Mar 2014 18:04:34 -0700 Subject: [PATCH 0113/2527] Import 'defaultRules', fixes missing Inflector.defaultRules --- packages/ember-inflector/lib/main.js | 4 +-- .../tests/system/inflector_test.js | 29 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/packages/ember-inflector/lib/main.js b/packages/ember-inflector/lib/main.js index fc3aad59594..f7c6900ec1f 100644 --- a/packages/ember-inflector/lib/main.js +++ b/packages/ember-inflector/lib/main.js @@ -1,6 +1,6 @@ -import {Inflector, inflections, pluralize, singularize} from "./system"; +import {Inflector, defaultRules, pluralize, singularize} from "./system"; -Inflector.defaultRules = inflections; +Inflector.defaultRules = defaultRules; Ember.Inflector = Inflector; Ember.String.pluralize = pluralize; diff --git a/packages/ember-inflector/tests/system/inflector_test.js b/packages/ember-inflector/tests/system/inflector_test.js index 7cf0618b6d4..e3e4f092dac 100644 --- a/packages/ember-inflector/tests/system/inflector_test.js +++ b/packages/ember-inflector/tests/system/inflector_test.js @@ -233,3 +233,32 @@ test('inflect.advancedRules', function(){ equal(inflector.inflect('ox', rules), 'oxen'); }); + +test('Inflector.defaultRules', function(){ + expect(1); + + var rules = Ember.Inflector.defaultRules; + ok(rules, 'has defaultRules'); +}); + +test('Ember.Inflector.inflector exists', function(){ + expect(1); + + ok(Ember.Inflector.inflector, 'Ember.Inflector.inflector exists'); +}); + +test('new Ember.Inflector with defaultRules matches docs', function(){ + expect(4); + + var inflector = new Ember.Inflector(Ember.Inflector.defaultRules); + + // defaultRules includes these special rules + equal(inflector.pluralize('cow'), 'kine'); + equal(inflector.singularize('kine'), 'cow'); + + // defaultRules adds 's' to singular + equal(inflector.pluralize('item'), 'items'); + + // defaultRules removes 's' from plural + equal(inflector.singularize('items'), 'item'); +}); From 8e93d62f6244d3ff7d23e92a769009e3b2789e54 Mon Sep 17 00:00:00 2001 From: CodeOfficer Date: Tue, 25 Mar 2014 16:26:09 -0700 Subject: [PATCH 0114/2527] Explicitly define a bower install directory bower install will put its files into a folder specified by the first .bowerrc file it finds in or above the project root. It's possible for bower to install its files in a place we do not expect without this explicit declaration. --- .bowerrc | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .bowerrc diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 00000000000..69fad358018 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "bower_components" +} From d8ffa0c10df75313849a43e25071b5901d2f4cd6 Mon Sep 17 00:00:00 2001 From: Luzi Humm Date: Tue, 25 Mar 2014 13:11:12 +0100 Subject: [PATCH 0115/2527] Fix error assertion's message This fixes the error message to reflect the changes described in [Defining Relationships in Models](https://github.com/emberjs/data/blob/master/TRANSITION.md#defining-relationships-in-models). --- packages/ember-data/lib/system/relationships/belongs_to.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index b5421b32597..e9bc7d35e26 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -96,7 +96,7 @@ function belongsTo(type, options) { options = type; type = undefined; } else { - Ember.assert("The first argument DS.belongsTo must be a model type or string, like DS.belongsTo(App.Person)", !!type && (typeof type === 'string' || Model.detect(type))); + Ember.assert("The first argument to DS.belongsTo must be a string representing a model type key, e.g. use DS.belongsTo('person') to define a relation to the App.Person model", !!type && (typeof type === 'string' || Model.detect(type))); } options = options || {}; From 1decc09df6b6210fa212e857308d0f88e1c61fc7 Mon Sep 17 00:00:00 2001 From: Mike Munroe Date: Fri, 28 Mar 2014 14:07:10 -0400 Subject: [PATCH 0116/2527] add semicolons to example code --- packages/ember-inflector/lib/system/inflector.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/ember-inflector/lib/system/inflector.js b/packages/ember-inflector/lib/system/inflector.js index 1e2a96c1de6..5d3ddf798d3 100644 --- a/packages/ember-inflector/lib/system/inflector.js +++ b/packages/ember-inflector/lib/system/inflector.js @@ -35,8 +35,8 @@ function loadIrregular(rules, irregularPairs) { ```js var inflector = new Ember.Inflector(Ember.Inflector.defaultRules); - inflector.pluralize('cow') //=> 'kine' - inflector.singularize('kine') //=> 'cow' + inflector.pluralize('cow'); //=> 'kine' + inflector.singularize('kine'); //=> 'cow' ``` Creating an inflector and adding rules later. @@ -44,13 +44,13 @@ function loadIrregular(rules, irregularPairs) { ```javascript var inflector = Ember.Inflector.inflector; - inflector.pluralize('advice') // => 'advices' + inflector.pluralize('advice'); // => 'advices' inflector.uncountable('advice'); - inflector.pluralize('advice') // => 'advice' + inflector.pluralize('advice'); // => 'advice' - inflector.pluralize('formula') // => 'formulas' + inflector.pluralize('formula'); // => 'formulas' inflector.irregular('formula', 'formulae'); - inflector.pluralize('formula') // => 'formulae' + inflector.pluralize('formula'); // => 'formulae' // you would not need to add these as they are the default rules inflector.plural(/$/, 's'); From 81e6edbf2c61b539a000ef877dab98bf347a6512 Mon Sep 17 00:00:00 2001 From: Mike Munroe Date: Fri, 28 Mar 2014 21:55:46 -0400 Subject: [PATCH 0117/2527] change 'the the' to 'the' --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index dc63c1dc4bf..e9e76d63681 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1562,7 +1562,7 @@ function addUnsavedRecords(record, key, data) { // Delegation to the adapter and promise management /** A `PromiseArray` is an object that acts like both an `Ember.Array` - and a promise. When the promise is resolved the the resulting value + and a promise. When the promise is resolved the resulting value will be set to the `PromiseArray`'s `content` property. This makes it easy to create data bindings with the `PromiseArray` that will be updated when the promise resolves. From 51bf49822232dd29828fa834fd96af00cf22da35 Mon Sep 17 00:00:00 2001 From: Mike Munroe Date: Fri, 28 Mar 2014 22:05:15 -0400 Subject: [PATCH 0118/2527] change its to it's and remove 'do' that is not needed --- packages/ember-data/lib/adapters/fixture_adapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/adapters/fixture_adapter.js b/packages/ember-data/lib/adapters/fixture_adapter.js index 0d7c6901837..0b9135c8c8d 100644 --- a/packages/ember-data/lib/adapters/fixture_adapter.js +++ b/packages/ember-data/lib/adapters/fixture_adapter.js @@ -11,11 +11,11 @@ import Adapter from "../system/adapter"; /** `DS.FixtureAdapter` is an adapter that loads records from memory. - Its primarily used for development and testing. You can also use + It's primarily used for development and testing. You can also use `DS.FixtureAdapter` while working on the API but are not ready to integrate yet. It is a fully functioning adapter. All CRUD methods are implemented. You can also implement query logic that a remote - system would do. Its possible to do develop your entire application + system would do. It's possible to develop your entire application with `DS.FixtureAdapter`. For information on how to use the `FixtureAdapter` in your From 10b8f23e3f42a773c443be87cfce7bc559177537 Mon Sep 17 00:00:00 2001 From: Jimmy Lauzau Date: Tue, 8 Apr 2014 14:26:52 -0400 Subject: [PATCH 0119/2527] Fix incorrect documentation for isError. If the server returns a validation error, then isError is not set to true. --- packages/ember-data/lib/system/model/model.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 6d093c5c8b8..662ec435d62 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -216,15 +216,14 @@ var Model = Ember.Object.extend(Ember.Evented, { /** If `true` the adapter reported that it was unable to save local - changes to the backend. This may also result in the record having - its `isValid` property become false if the adapter reported that - server-side validations failed. + changes to the backend for any reason other than a server-side + validation error. Example ```javascript record.get('isError'); // false - record.set('foo', 'invalid value'); + record.set('foo', 'valid value'); record.save().then(null, function() { record.get('isError'); // true }); From d25e23f622a3677b8372db535b2ab824ad306a16 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Tue, 8 Apr 2014 22:15:32 -0400 Subject: [PATCH 0120/2527] Refactor Ember initializer to use DS._setupContainer The container setup used by Ember-Data has been coupled to the Ember.js application initialization code. This splits the container setup into a separate set of files, allowing container setup to be used in testing environments that have not booted an application. Testing environments should use the new `DS._setupContainer` API: var container = new Ember.Container(); DS._setupContainer(container); var store = container.lookup('store:main'); `DS._setupContainer` will configure the container for ember-data proper and for the activemode-adapter package. This API uses an _ as a warning to consumers: It may change. --- .../activemodel-adapter/lib/initializers.js | 20 ---- packages/activemodel-adapter/lib/main.js | 2 - .../lib/setup-container.js | 14 +++ packages/ember-data/lib/ember-initializer.js | 18 +++ packages/ember-data/lib/initializers.js | 113 ------------------ .../lib/initializers/data_adapter.js | 12 ++ packages/ember-data/lib/initializers/store.js | 37 ++++++ .../lib/initializers/store_injections.js | 13 ++ .../ember-data/lib/initializers/transforms.js | 20 ++++ packages/ember-data/lib/main.js | 5 +- packages/ember-data/lib/setup-container.js | 54 +++++++++ .../tests/integration/application_test.js | 79 +++++------- .../tests/integration/setup-container-test.js | 66 ++++++++++ 13 files changed, 265 insertions(+), 188 deletions(-) delete mode 100644 packages/activemodel-adapter/lib/initializers.js create mode 100644 packages/activemodel-adapter/lib/setup-container.js create mode 100644 packages/ember-data/lib/ember-initializer.js delete mode 100644 packages/ember-data/lib/initializers.js create mode 100644 packages/ember-data/lib/initializers/data_adapter.js create mode 100644 packages/ember-data/lib/initializers/store.js create mode 100644 packages/ember-data/lib/initializers/store_injections.js create mode 100644 packages/ember-data/lib/initializers/transforms.js create mode 100644 packages/ember-data/lib/setup-container.js create mode 100644 packages/ember-data/tests/integration/setup-container-test.js diff --git a/packages/activemodel-adapter/lib/initializers.js b/packages/activemodel-adapter/lib/initializers.js deleted file mode 100644 index 349c5280aff..00000000000 --- a/packages/activemodel-adapter/lib/initializers.js +++ /dev/null @@ -1,20 +0,0 @@ -import ContainerProxy from "../../ember-data/lib/system/container_proxy"; -import ActiveModelSerializer from "./system/active_model_serializer"; -import ActiveModelAdapter from "./system/active_model_adapter"; - -Ember.onLoad('Ember.Application', function(Application) { - Application.initializer({ - name: "activeModelAdapter", - - initialize: function(container, application) { - var proxy = new ContainerProxy(container); - proxy.registerDeprecations([ - {deprecated: 'serializer:_ams', valid: 'serializer:-active-model'}, - {deprecated: 'adapter:_ams', valid: 'adapter:-active-model'} - ]); - - application.register('serializer:-active-model', ActiveModelSerializer); - application.register('adapter:-active-model', ActiveModelAdapter); - } - }); -}); diff --git a/packages/activemodel-adapter/lib/main.js b/packages/activemodel-adapter/lib/main.js index 5fd4a857bee..bf5aa03c387 100644 --- a/packages/activemodel-adapter/lib/main.js +++ b/packages/activemodel-adapter/lib/main.js @@ -1,7 +1,5 @@ import {ActiveModelAdapter, ActiveModelSerializer, EmbeddedRecordsMixin} from "./system"; -import "./initializers"; - export { ActiveModelAdapter, ActiveModelSerializer, diff --git a/packages/activemodel-adapter/lib/setup-container.js b/packages/activemodel-adapter/lib/setup-container.js new file mode 100644 index 00000000000..602fc7384cf --- /dev/null +++ b/packages/activemodel-adapter/lib/setup-container.js @@ -0,0 +1,14 @@ +import ContainerProxy from "../../ember-data/lib/system/container_proxy"; +import ActiveModelSerializer from "./system/active_model_serializer"; +import ActiveModelAdapter from "./system/active_model_adapter"; + +export default function setupActiveModelAdapter(container, application){ + var proxy = new ContainerProxy(container); + proxy.registerDeprecations([ + {deprecated: 'serializer:_ams', valid: 'serializer:-active-model'}, + {deprecated: 'adapter:_ams', valid: 'adapter:-active-model'} + ]); + + container.register('serializer:-active-model', ActiveModelSerializer); + container.register('adapter:-active-model', ActiveModelAdapter); +}; diff --git a/packages/ember-data/lib/ember-initializer.js b/packages/ember-data/lib/ember-initializer.js new file mode 100644 index 00000000000..ee474797c1a --- /dev/null +++ b/packages/ember-data/lib/ember-initializer.js @@ -0,0 +1,18 @@ +import setupContainer from './setup-container'; + +/** + @module ember-data +*/ + +var set = Ember.set; + +/* + This code initializes Ember-Data onto an Ember application. +*/ + +Ember.onLoad('Ember.Application', function(Application) { + Application.initializer({ + name: "ember-data", + initialize: setupContainer + }); +}); diff --git a/packages/ember-data/lib/initializers.js b/packages/ember-data/lib/initializers.js deleted file mode 100644 index 75f1ebaf396..00000000000 --- a/packages/ember-data/lib/initializers.js +++ /dev/null @@ -1,113 +0,0 @@ -import Store from "./system/store"; -import {JSONSerializer, RESTSerializer} from "./serializers"; -import {RESTAdapter} from "./adapters"; -import DebugAdapter from "./system/debug/debug_adapter"; -import ContainerProxy from "./system/container_proxy"; -import { - BooleanTransform, - DateTransform, - StringTransform, - NumberTransform -} from "./transforms"; - -/** - @module ember-data -*/ - -var set = Ember.set; - -/* - This code registers an injection for Ember.Application. - - If an Ember.js developer defines a subclass of DS.Store on their application, - as `App.ApplicationStore` (or via a module system that resolves to `store:application`) - this code will automatically instantiate it and make it available on the - router. - - Additionally, after an application's controllers have been injected, they will - each have the store made available to them. - - For example, imagine an Ember.js application with the following classes: - - App.ApplicationStore = DS.Store.extend({ - adapter: 'custom' - }); - - App.PostsController = Ember.ArrayController.extend({ - // ... - }); - - When the application is initialized, `App.ApplicationStore` will automatically be - instantiated, and the instance of `App.PostsController` will have its `store` - property set to that instance. - - Note that this code will only be run if the `ember-application` package is - loaded. If Ember Data is being used in an environment other than a - typical application (e.g., node.js where only `ember-runtime` is available), - this code will be ignored. -*/ - -Ember.onLoad('Ember.Application', function(Application) { - Application.initializer({ - name: "store", - - initialize: function(container, application) { - Ember.deprecate('Specifying a custom Store for Ember Data on your global namespace as `App.Store` ' + - 'has been deprecated. Please use `App.ApplicationStore` instead.', !application.Store); - - application.register('store:main', container.lookupFactory('store:application') || application.Store || Store); - - // allow older names to be looked up - - var proxy = new ContainerProxy(container); - proxy.registerDeprecations([ - {deprecated: 'serializer:_default', valid: 'serializer:-default'}, - {deprecated: 'serializer:_rest', valid: 'serializer:-rest'}, - {deprecated: 'adapter:_rest', valid: 'adapter:-rest'} - ]); - - // new go forward paths - application.register('serializer:-default', JSONSerializer); - application.register('serializer:-rest', RESTSerializer); - application.register('adapter:-rest', RESTAdapter); - - // Eagerly generate the store so defaultStore is populated. - // TODO: Do this in a finisher hook - container.lookup('store:main'); - } - }); - - Application.initializer({ - name: "transforms", - before: "store", - - initialize: function(container, application) { - application.register('transform:boolean', BooleanTransform); - application.register('transform:date', DateTransform); - application.register('transform:number', NumberTransform); - application.register('transform:string', StringTransform); - } - }); - - Application.initializer({ - name: "data-adapter", - before: "store", - - initialize: function(container, application) { - application.register('data-adapter:main', DebugAdapter); - } - }); - - Application.initializer({ - name: "injectStore", - before: "store", - - initialize: function(container, application) { - application.inject('controller', 'store', 'store:main'); - application.inject('route', 'store', 'store:main'); - application.inject('serializer', 'store', 'store:main'); - application.inject('data-adapter', 'store', 'store:main'); - } - }); - -}); diff --git a/packages/ember-data/lib/initializers/data_adapter.js b/packages/ember-data/lib/initializers/data_adapter.js new file mode 100644 index 00000000000..52093ad3073 --- /dev/null +++ b/packages/ember-data/lib/initializers/data_adapter.js @@ -0,0 +1,12 @@ +import DebugAdapter from "../system/debug/debug_adapter"; + +/** + Configures a container with injections on Ember applications + for the Ember-Data store. Accepts an optional namespace argument. + + @method initializeStoreInjections + @param {Ember.Container} container +*/ +export default function initializeDebugAdapter(container){ + container.register('data-adapter:main', DebugAdapter); +}; diff --git a/packages/ember-data/lib/initializers/store.js b/packages/ember-data/lib/initializers/store.js new file mode 100644 index 00000000000..ff43db1cdd5 --- /dev/null +++ b/packages/ember-data/lib/initializers/store.js @@ -0,0 +1,37 @@ +import {JSONSerializer, RESTSerializer} from "../serializers"; +import {RESTAdapter} from "../adapters"; +import ContainerProxy from "../system/container_proxy"; +import Store from "../system/store"; + +/** + Configures a container for use with an Ember-Data + store. Accepts an optional namespace argument. + + @method initializeStore + @param {Ember.Container} container + @param {Object} [application] an application namespace +*/ +export default function initializeStore(container, application){ + Ember.deprecate('Specifying a custom Store for Ember Data on your global namespace as `App.Store` ' + + 'has been deprecated. Please use `App.ApplicationStore` instead.', !(application && application.Store)); + + container.register('store:main', container.lookupFactory('store:application') || (application && application.Store) || Store); + + // allow older names to be looked up + + var proxy = new ContainerProxy(container); + proxy.registerDeprecations([ + {deprecated: 'serializer:_default', valid: 'serializer:-default'}, + {deprecated: 'serializer:_rest', valid: 'serializer:-rest'}, + {deprecated: 'adapter:_rest', valid: 'adapter:-rest'} + ]); + + // new go forward paths + container.register('serializer:-default', JSONSerializer); + container.register('serializer:-rest', RESTSerializer); + container.register('adapter:-rest', RESTAdapter); + + // Eagerly generate the store so defaultStore is populated. + // TODO: Do this in a finisher hook + container.lookup('store:main'); +}; diff --git a/packages/ember-data/lib/initializers/store_injections.js b/packages/ember-data/lib/initializers/store_injections.js new file mode 100644 index 00000000000..6dd460a5f68 --- /dev/null +++ b/packages/ember-data/lib/initializers/store_injections.js @@ -0,0 +1,13 @@ +/** + Configures a container with injections on Ember applications + for the Ember-Data store. Accepts an optional namespace argument. + + @method initializeStoreInjections + @param {Ember.Container} container +*/ +export default function initializeStoreInjections(container){ + container.injection('controller', 'store', 'store:main'); + container.injection('route', 'store', 'store:main'); + container.injection('serializer', 'store', 'store:main'); + container.injection('data-adapter', 'store', 'store:main'); +}; diff --git a/packages/ember-data/lib/initializers/transforms.js b/packages/ember-data/lib/initializers/transforms.js new file mode 100644 index 00000000000..05943e93db8 --- /dev/null +++ b/packages/ember-data/lib/initializers/transforms.js @@ -0,0 +1,20 @@ +import { + BooleanTransform, + DateTransform, + StringTransform, + NumberTransform +} from "../transforms"; + +/** + Configures a container for use with Ember-Data + transforms. + + @method initializeTransforms + @param {Ember.Container} container +*/ +export default function initializeTransforms(container){ + container.register('transform:boolean', BooleanTransform); + container.register('transform:date', DateTransform); + container.register('transform:number', NumberTransform); + container.register('transform:string', StringTransform); +}; diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index 5d1d7ccf8c2..2fd77b8954f 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -51,7 +51,8 @@ import { } from "./transforms"; import {hasMany, belongsTo} from "./system/relationships"; -import "./initializers"; +import "./ember-initializer"; +import setupContainer from "./setup-container"; import ContainerProxy from "./system/container_proxy"; @@ -105,6 +106,8 @@ DS.hasMany = hasMany; DS.ContainerProxy = ContainerProxy; +DS._setupContainer = setupContainer; + Ember.lookup.DS = DS; export default DS; diff --git a/packages/ember-data/lib/setup-container.js b/packages/ember-data/lib/setup-container.js new file mode 100644 index 00000000000..64c07cc64e1 --- /dev/null +++ b/packages/ember-data/lib/setup-container.js @@ -0,0 +1,54 @@ +import initializeStore from './initializers/store'; +import initializeTransforms from './initializers/transforms'; +import initializeStoreInjections from './initializers/store_injections'; +import initializeDataAdapter from './initializers/data_adapter'; +import setupActiveModelContainer from '../../../activemodel-adapter/lib/setup-container'; + +/** + @module ember-data +*/ + +var set = Ember.set; + +/* + This code registers an injection for Ember.Application. + + If an Ember.js developer defines a subclass of DS.Store on their application, + as `App.ApplicationStore` (or via a module system that resolves to `store:application`) + this code will automatically instantiate it and make it available on the + router. + + Additionally, after an application's controllers have been injected, they will + each have the store made available to them. + + For example, imagine an Ember.js application with the following classes: + + App.ApplicationStore = DS.Store.extend({ + adapter: 'custom' + }); + + App.PostsController = Ember.ArrayController.extend({ + // ... + }); + + When the application is initialized, `App.ApplicationStore` will automatically be + instantiated, and the instance of `App.PostsController` will have its `store` + property set to that instance. + + Note that this code will only be run if the `ember-application` package is + loaded. If Ember Data is being used in an environment other than a + typical application (e.g., node.js where only `ember-runtime` is available), + this code will be ignored. +*/ + +export default function setupContainer(container, application){ + // application is not a required argument. This ensures + // testing setups can setup a container without booting an + // entire ember application. + + initializeDataAdapter(container, application); + initializeTransforms(container, application); + initializeStoreInjections(container, application); + initializeStore(container, application); + setupActiveModelContainer(container, application); +}; diff --git a/packages/ember-data/tests/integration/application_test.js b/packages/ember-data/tests/integration/application_test.js index 11693fe8890..46b0f51023e 100644 --- a/packages/ember-data/tests/integration/application_test.js +++ b/packages/ember-data/tests/integration/application_test.js @@ -1,3 +1,11 @@ +var run = Ember.run, + Application = Ember.Application, + Controller = Ember.Controller, + View = Ember.View, + Store = DS.Store, + Namespace = Ember.Namespace, + Object = Ember.Object; + var app, container; /** @@ -7,13 +15,13 @@ var app, container; module("integration/application - Injecting a Custom Store", { setup: function() { - Ember.run(function() { - app = Ember.Application.create({ - ApplicationStore: DS.Store.extend({ isCustom: true }), - FooController: Ember.Controller.extend(), - ApplicationView: Ember.View.extend(), + run(function() { + app = Application.create({ + ApplicationStore: Store.extend({ isCustom: true }), + FooController: Controller.extend(), + ApplicationView: View.extend(), BazController: {}, - ApplicationController: Ember.View.extend() + ApplicationController: View.extend() }); }); @@ -21,7 +29,7 @@ module("integration/application - Injecting a Custom Store", { }, teardown: function() { - app.destroy(); + run(app, app.destroy); Ember.BOOTED = false; } }); @@ -36,14 +44,14 @@ test("If a store is instantiated, it should be made available to each controller }); test("registering App.Store is deprecated but functional", function(){ - Ember.run(app, 'destroy'); + run(app, 'destroy'); expectDeprecation(function(){ - Ember.run(function() { - app = Ember.Application.create({ - Store: DS.Store.extend({ isCustomButDeprecated: true }), - FooController: Ember.Controller.extend(), - }); + run(function() { + app = Application.create({ + Store: DS.Store.extend({ isCustomButDeprecated: true }), + FooController: Controller.extend(), + }); }); }, 'Specifying a custom Store for Ember Data on your global namespace as `App.Store` ' + 'has been deprecated. Please use `App.ApplicationStore` instead.'); @@ -57,12 +65,12 @@ test("registering App.Store is deprecated but functional", function(){ module("integration/application - Injecting the Default Store", { setup: function() { - Ember.run(function() { - app = Ember.Application.create({ - FooController: Ember.Controller.extend(), - ApplicationView: Ember.View.extend(), + run(function() { + app = Application.create({ + FooController: Controller.extend(), + ApplicationView: View.extend(), BazController: {}, - ApplicationController: Ember.View.extend() + ApplicationController: View.extend() }); }); @@ -85,38 +93,5 @@ test("If a store is instantiated, it should be made available to each controller }); test("the DS namespace should be accessible", function() { - ok(Ember.Namespace.byName('DS') instanceof Ember.Namespace, "the DS namespace is accessible"); -}); - -test("the deprecated serializer:_default is resolved as serializer:default", function(){ - var deprecated, valid = container.lookup('serializer:-default'); - expectDeprecation(function() { - deprecated = container.lookup('serializer:_default'); - }); - - ok(deprecated === valid, "they should resolve to the same thing"); -}); - -test("the deprecated serializer:_rest is resolved as serializer:rest", function(){ - var deprecated, valid = container.lookup('serializer:-rest'); - expectDeprecation(function() { - deprecated = container.lookup('serializer:_rest'); - }); - - ok(deprecated === valid, "they should resolve to the same thing"); -}); - -test("the deprecated adapter:_rest is resolved as adapter:rest", function(){ - var deprecated, valid = container.lookup('adapter:-rest'); - expectDeprecation(function() { - deprecated = container.lookup('adapter:_rest'); - }); - - ok(deprecated === valid, "they should resolve to the same thing"); -}); - -test("a deprecation is made when looking up adapter:_rest", function(){ - expectDeprecation(function(){ - container.lookup('serializer:_default'); - },"You tried to look up 'serializer:_default', but this has been deprecated in favor of 'serializer:-default'."); + ok(Namespace.byName('DS') instanceof Namespace, "the DS namespace is accessible"); }); diff --git a/packages/ember-data/tests/integration/setup-container-test.js b/packages/ember-data/tests/integration/setup-container-test.js new file mode 100644 index 00000000000..04a1f74888b --- /dev/null +++ b/packages/ember-data/tests/integration/setup-container-test.js @@ -0,0 +1,66 @@ +var run = Ember.run, + Container = Ember.Container, + Store = DS.Store, + Object = Ember.Object, + setupContainer = DS._setupContainer; + +var container; + +/** + These tests ensure that Ember Data works with Ember.js' container + initialization and dependency injection API. +*/ + +module("integration/setup-container - Setting up a container", { + setup: function() { + container = new Container(); + setupContainer(container); + }, + + teardown: function() { + run(container, container.destroy); + } +}); + +test("The store should be registered into a container.", function() { + ok(container.lookup('store:main') instanceof Store, "the custom store is instantiated"); +}); + +test("If a store is instantiated, it should be made available to each controller.", function() { + container.register('controller:foo', Object.extend({})); + var fooController = container.lookup('controller:foo'); + ok(fooController.get('store') instanceof Store, "the store was injected"); +}); + +test("the deprecated serializer:_default is resolved as serializer:default", function(){ + var deprecated, valid = container.lookup('serializer:-default'); + expectDeprecation(function() { + deprecated = container.lookup('serializer:_default'); + }); + + ok(deprecated === valid, "they should resolve to the same thing"); +}); + +test("the deprecated serializer:_rest is resolved as serializer:rest", function(){ + var deprecated, valid = container.lookup('serializer:-rest'); + expectDeprecation(function() { + deprecated = container.lookup('serializer:_rest'); + }); + + ok(deprecated === valid, "they should resolve to the same thing"); +}); + +test("the deprecated adapter:_rest is resolved as adapter:rest", function(){ + var deprecated, valid = container.lookup('adapter:-rest'); + expectDeprecation(function() { + deprecated = container.lookup('adapter:_rest'); + }); + + ok(deprecated === valid, "they should resolve to the same thing"); +}); + +test("a deprecation is made when looking up adapter:_rest", function(){ + expectDeprecation(function(){ + container.lookup('serializer:_default'); + },"You tried to look up 'serializer:_default', but this has been deprecated in favor of 'serializer:-default'."); +}); From 0c36175e1e6a558ae46e7962791f22ed54d36344 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Thu, 10 Apr 2014 19:05:16 -0400 Subject: [PATCH 0121/2527] Drop spurious var set statements --- packages/ember-data/lib/ember-initializer.js | 4 ---- packages/ember-data/lib/setup-container.js | 4 ---- 2 files changed, 8 deletions(-) diff --git a/packages/ember-data/lib/ember-initializer.js b/packages/ember-data/lib/ember-initializer.js index ee474797c1a..36ff1ea5a42 100644 --- a/packages/ember-data/lib/ember-initializer.js +++ b/packages/ember-data/lib/ember-initializer.js @@ -2,11 +2,7 @@ import setupContainer from './setup-container'; /** @module ember-data -*/ - -var set = Ember.set; -/* This code initializes Ember-Data onto an Ember application. */ diff --git a/packages/ember-data/lib/setup-container.js b/packages/ember-data/lib/setup-container.js index 64c07cc64e1..dd5b64274ef 100644 --- a/packages/ember-data/lib/setup-container.js +++ b/packages/ember-data/lib/setup-container.js @@ -6,11 +6,7 @@ import setupActiveModelContainer from '../../../activemodel-adapter/lib/setup-co /** @module ember-data -*/ - -var set = Ember.set; -/* This code registers an injection for Ember.Application. If an Ember.js developer defines a subclass of DS.Store on their application, From 0da4d5a77e210277076594081e274f1cb951241a Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Fri, 11 Apr 2014 10:27:15 -0400 Subject: [PATCH 0122/2527] Bring back deprecated initializers Libraries such as ic-ajax are dependent on the old initializers in ember-data (such as "store"). This brings them back temporarially, but they will eventually be removed and are non-functional. --- packages/ember-data/lib/ember-initializer.js | 35 ++++++++ .../tests/integration/application_test.js | 80 ++++++++++++++++++- 2 files changed, 114 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/ember-initializer.js b/packages/ember-data/lib/ember-initializer.js index 36ff1ea5a42..03412ae1f63 100644 --- a/packages/ember-data/lib/ember-initializer.js +++ b/packages/ember-data/lib/ember-initializer.js @@ -1,5 +1,7 @@ import setupContainer from './setup-container'; +var K = Ember.K; + /** @module ember-data @@ -7,8 +9,41 @@ import setupContainer from './setup-container'; */ Ember.onLoad('Ember.Application', function(Application) { + Application.initializer({ name: "ember-data", initialize: setupContainer }); + + // Deprecated initializers to satisfy old code that depended on them + + Application.initializer({ + name: "store", + after: "ember-data", + initialize: K + }); + + Application.initializer({ + name: "activeModelAdapter", + before: "store", + initialize: K + }); + + Application.initializer({ + name: "transforms", + before: "store", + initialize: K + }); + + Application.initializer({ + name: "data-adapter", + before: "store", + initialize: K + }); + + Application.initializer({ + name: "injectStore", + before: "store", + initialize: K + }); }); diff --git a/packages/ember-data/tests/integration/application_test.js b/packages/ember-data/tests/integration/application_test.js index 46b0f51023e..5c6cba4400a 100644 --- a/packages/ember-data/tests/integration/application_test.js +++ b/packages/ember-data/tests/integration/application_test.js @@ -6,7 +6,7 @@ var run = Ember.run, Namespace = Ember.Namespace, Object = Ember.Object; -var app, container; +var app, App, container; /** These tests ensure that Ember Data works with Ember.js' application @@ -95,3 +95,81 @@ test("If a store is instantiated, it should be made available to each controller test("the DS namespace should be accessible", function() { ok(Namespace.byName('DS') instanceof Namespace, "the DS namespace is accessible"); }); + +module("integration/application - Attaching initializer", { + setup: function() { + App = Application.extend(); + }, + + teardown: function() { + if (app) { + run(app, app.destroy); + } + Ember.BOOTED = false; + } +}); + +test("ember-data initializer is run", function(){ + var ran = false; + App.initializer({ + name: "after-ember-data", + after: "ember-data", + initialize: function(){ ran = true; } + }); + + app = App.create(); + + ok(ran, 'ember-data initializer was found'); +}); + +test("store initializer is run (DEPRECATED)", function(){ + var ran = false; + App.initializer({ + name: "after-store", + after: 'store', + initialize: function(){ ran = true; } + }); + + app = App.create(); + + ok(ran, 'store initializer was found'); +}); + +test("injectStore initializer is run (DEPRECATED)", function(){ + var ran = false; + App.initializer({ + name: "after-store", + after: 'injectStore', + initialize: function(){ ran = true; } + }); + + app = App.create(); + + ok(ran, 'injectStore initializer was found'); +}); + +test("transforms initializer is run (DEPRECATED)", function(){ + var ran = false; + App.initializer({ + name: "after-store", + after: 'transforms', + initialize: function(){ ran = true; } + }); + + app = App.create(); + + ok(ran, 'transforms initializer was found'); +}); + +test("activeModelAdapter initializer is run (DEPRECATED)", function(){ + var ran = false; + App.initializer({ + name: "after-store", + after: 'activeModelAdapter', + initialize: function(){ ran = true; } + }); + + app = App.create(); + + ok(ran, 'activeModelAdapter initializer was found'); +}); From bce78d5d5b28fd468b7b4f8346cf51f0326cf54f Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 11 Apr 2014 11:15:17 -0400 Subject: [PATCH 0123/2527] Fix warnings generated by yuidoc --- .../lib/system/active_model_adapter.js | 4 ++-- .../lib/system/active_model_serializer.js | 10 ++++---- .../ember-data/lib/adapters/rest_adapter.js | 22 ++++++++--------- .../lib/serializers/rest_serializer.js | 10 ++++---- .../ember-data/lib/system/model/errors.js | 8 +++++-- packages/ember-data/lib/system/model/model.js | 4 ++-- packages/ember-data/lib/system/store.js | 24 +++++++++---------- 7 files changed, 43 insertions(+), 39 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index bff0d7537db..3c4dce3360d 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -74,7 +74,7 @@ var ActiveModelAdapter = RESTAdapter.extend({ @method pathForType @param {String} type - @returns String + @return String */ pathForType: function(type) { var decamelized = decamelize(type); @@ -96,7 +96,7 @@ var ActiveModelAdapter = RESTAdapter.extend({ @method ajaxError @param jqXHR - @returns error + @return error */ ajaxError: function(jqXHR) { var error = this._super(jqXHR); diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index e7fec0e7cb2..f767084f599 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -19,7 +19,7 @@ var ActiveModelSerializer = RESTSerializer.extend({ @method keyForAttribute @param {String} attribute - @returns String + @return String */ keyForAttribute: function(attr) { return decamelize(attr); @@ -32,7 +32,7 @@ var ActiveModelSerializer = RESTSerializer.extend({ @method keyForRelationship @param {String} key @param {String} kind - @returns String + @return String */ keyForRelationship: function(key, kind) { key = decamelize(key); @@ -45,7 +45,7 @@ var ActiveModelSerializer = RESTSerializer.extend({ } }, - /** + /* Does not serialize hasMany relationships by default. */ serializeHasMany: Ember.K, @@ -86,7 +86,7 @@ var ActiveModelSerializer = RESTSerializer.extend({ @method typeForRoot @param {String} root - @returns String the model's typeKey + @return String the model's typeKey */ typeForRoot: function(root) { var camelized = camelize(root); @@ -124,7 +124,7 @@ var ActiveModelSerializer = RESTSerializer.extend({ @param {subclass of DS.Model} type @param {Object} hash @param {String} prop - @returns Object + @return Object */ normalize: function(type, hash, prop) { diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index ebc1d4113e8..eea6df501e2 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -184,7 +184,7 @@ var RESTAdapter = Adapter.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {String} id - @returns {Promise} promise + @return {Promise} promise */ find: function(store, type, id) { return this.ajax(this.buildURL(type.typeKey, id), 'GET'); @@ -202,7 +202,7 @@ var RESTAdapter = Adapter.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {String} sinceToken - @returns {Promise} promise + @return {Promise} promise */ findAll: function(store, type, sinceToken) { var query; @@ -229,7 +229,7 @@ var RESTAdapter = Adapter.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Object} query - @returns {Promise} promise + @return {Promise} promise */ findQuery: function(store, type, query) { return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query }); @@ -267,7 +267,7 @@ var RESTAdapter = Adapter.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Array} ids - @returns {Promise} promise + @return {Promise} promise */ findMany: function(store, type, ids) { return this.ajax(this.buildURL(type.typeKey), 'GET', { data: { ids: ids } }); @@ -300,7 +300,7 @@ var RESTAdapter = Adapter.extend({ @param {DS.Store} store @param {DS.Model} record @param {String} url - @returns {Promise} promise + @return {Promise} promise */ findHasMany: function(store, record, url) { var host = get(this, 'host'), @@ -339,7 +339,7 @@ var RESTAdapter = Adapter.extend({ @param {DS.Store} store @param {DS.Model} record @param {String} url - @returns {Promise} promise + @return {Promise} promise */ findBelongsTo: function(store, record, url) { var id = get(record, 'id'), @@ -362,7 +362,7 @@ var RESTAdapter = Adapter.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {DS.Model} record - @returns {Promise} promise + @return {Promise} promise */ createRecord: function(store, type, record) { var data = {}; @@ -387,7 +387,7 @@ var RESTAdapter = Adapter.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {DS.Model} record - @returns {Promise} promise + @return {Promise} promise */ updateRecord: function(store, type, record) { var data = {}; @@ -409,7 +409,7 @@ var RESTAdapter = Adapter.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {DS.Model} record - @returns {Promise} promise + @return {Promise} promise */ deleteRecord: function(store, type, record) { var id = get(record, 'id'); @@ -430,7 +430,7 @@ var RESTAdapter = Adapter.extend({ @method buildURL @param {String} type @param {String} id - @returns {String} url + @return {String} url */ buildURL: function(type, id) { var url = [], @@ -505,7 +505,7 @@ var RESTAdapter = Adapter.extend({ @method pathForType @param {String} type - @returns {String} path + @return {String} path **/ pathForType: function(type) { var camelized = Ember.String.camelize(type); diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index 2383dfe7966..ed0afd2c096 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -163,7 +163,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {subclass of DS.Model} type @param {Object} hash @param {String} prop - @returns {Object} + @return {Object} */ normalize: function(type, hash, prop) { this.normalizeId(hash); @@ -198,7 +198,7 @@ var RESTSerializer = JSONSerializer.extend({ @method normalizePayload @param {subclass of DS.Model} type @param {Object} payload - @returns {Object} the normalized payload + @return {Object} the normalized payload */ normalizePayload: function(type, payload) { return payload; @@ -349,7 +349,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {Object} payload @param {String} id @param {'find'|'createRecord'|'updateRecord'|'deleteRecord'} requestType - @returns {Object} the primary response to the original request + @return {Object} the primary response to the original request */ extractSingle: function(store, primaryType, payload, recordId, requestType) { payload = this.normalizePayload(primaryType, payload); @@ -494,7 +494,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {subclass of DS.Model} type @param {Object} payload @param {'findAll'|'findMany'|'findHasMany'|'findQuery'} requestType - @returns {Array} The primary array that was returned in response + @return {Array} The primary array that was returned in response to the original query. */ extractArray: function(store, primaryType, payload) { @@ -598,7 +598,7 @@ var RESTSerializer = JSONSerializer.extend({ @method typeForRoot @param {String} root - @returns {String} the model's typeKey + @return {String} the model's typeKey */ typeForRoot: function(root) { return Ember.String.singularize(root); diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index 7079d931216..338927ca53d 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -59,13 +59,17 @@ var Errors = Ember.Object.extend(Ember.Enumerable, Ember.Evented, { @method errorsFor @param {String} attribute - @returns {Array} + @return {Array} */ errorsFor: function(attribute) { return get(this, 'errorsByAttributeName').get(attribute); }, /** + An array containing all of the error messages for this record. + + @property messages + @type {Array} */ messages: Ember.computed.mapBy('content', 'message'), @@ -190,7 +194,7 @@ var Errors = Ember.Object.extend(Ember.Enumerable, Ember.Evented, { @method has @param {String} attribute - @returns {Boolean} true if there some errors on given attribute + @return {Boolean} true if there some errors on given attribute */ has: function(attribute) { return !isEmpty(this.errorsFor(attribute)); diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 6d093c5c8b8..dd8cc6d489c 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -332,7 +332,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @method serialize @param {Object} options - @returns {Object} an object whose values are primitive JSON values only + @return {Object} an object whose values are primitive JSON values only */ serialize: function(options) { var store = get(this, 'store'); @@ -351,7 +351,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @method toJSON @param {Object} options - @returns {Object} A JSON representation of the object. + @return {Object} A JSON representation of the object. */ toJSON: function(options) { if (!JSONSerializer) { JSONSerializer = requireModule("ember-data/lib/serializers/json_serializer")["default"]; } diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index e9e76d63681..3b709f31c8c 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -185,7 +185,7 @@ Store = Ember.Object.extend({ @property defaultAdapter @private - @returns DS.Adapter + @return DS.Adapter */ defaultAdapter: Ember.computed('adapter', function() { var adapter = get(this, 'adapter'); @@ -225,7 +225,7 @@ Store = Ember.Object.extend({ @param {String} type @param {Object} properties a hash of properties to set on the newly created record. - @returns {DS.Model} record + @return {DS.Model} record */ createRecord: function(type, properties) { type = this.modelFor(type); @@ -263,7 +263,7 @@ Store = Ember.Object.extend({ @method _generateId @private @param {String} type - @returns {String} if the adapter can generate one, an ID + @return {String} if the adapter can generate one, an ID */ _generateId: function(type) { var adapter = this.adapterFor(type); @@ -414,7 +414,7 @@ Store = Ember.Object.extend({ @method findByIds @param {String} type @param {Array} ids - @returns {Promise} promise + @return {Promise} promise */ findByIds: function(type, ids) { var store = this; @@ -432,7 +432,7 @@ Store = Ember.Object.extend({ @method fetchRecord @private @param {DS.Model} record - @returns {Promise} promise + @return {Promise} promise */ fetchRecord: function(record) { if (isNone(record)) { return null; } @@ -550,7 +550,7 @@ Store = Ember.Object.extend({ @method hasRecordForId @param {String or subclass of DS.Model} type @param {String|Integer} id - @returns {Boolean} + @return {Boolean} */ hasRecordForId: function(type, id) { id = coerceId(id); @@ -566,7 +566,7 @@ Store = Ember.Object.extend({ @private @param {String or subclass of DS.Model} type @param {String|Integer} id - @returns {DS.Model} record + @return {DS.Model} record */ recordForId: function(type, id) { type = this.modelFor(type); @@ -718,7 +718,7 @@ Store = Ember.Object.extend({ @private @param {DS.Model} type @param {DS.RecordArray} array - @returns {Promise} promise + @return {Promise} promise */ fetchAll: function(type, array) { var adapter = this.adapterFor(type), @@ -1099,7 +1099,7 @@ Store = Ember.Object.extend({ @method modelFor @param {String or subclass of DS.Model} key - @returns {subclass of DS.Model} + @return {subclass of DS.Model} */ modelFor: function(key) { var factory; @@ -1178,7 +1178,7 @@ Store = Ember.Object.extend({ @method push @param {String or subclass of DS.Model} type @param {Object} data - @returns {DS.Model} the record that was created or + @return {DS.Model} the record that was created or updated. */ push: function(type, data, _partial) { @@ -1319,7 +1319,7 @@ Store = Ember.Object.extend({ @param {subclass of DS.Model} type @param {String} id @param {Object} data - @returns {DS.Model} record + @return {DS.Model} record */ buildRecord: function(type, id, data) { var typeMap = this.typeMapFor(type), @@ -1439,7 +1439,7 @@ Store = Ember.Object.extend({ @method adapterFor @private @param {subclass of DS.Model} type - @returns DS.Adapter + @return DS.Adapter */ adapterFor: function(type) { var container = this.container, adapter; From 431e9fe28026713e36f2a4a20d18b99e42b775c5 Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 14 Apr 2014 12:05:15 -0700 Subject: [PATCH 0124/2527] Update error messages from push and update Error messages now include model type for ease of debugging --- packages/ember-data/lib/system/store.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 3b709f31c8c..9eb36fed7c8 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1186,7 +1186,7 @@ Store = Ember.Object.extend({ // If passed, it means that the data should be // merged into the existing data, not replace it. - Ember.assert("You must include an `id` in a hash passed to `push`", data.id != null); + Ember.assert("You must include an `id` for " + type + " in a hash passed to `push`", data.id != null); type = this.modelFor(type); @@ -1275,7 +1275,7 @@ Store = Ember.Object.extend({ @return {DS.Model} the record that was updated. */ update: function(type, data) { - Ember.assert("You must include an `id` in a hash passed to `update`", data.id != null); + Ember.assert("You must include an `id` for " + type + " in a hash passed to `update`", data.id != null); return this.push(type, data, true); }, From 1fcf82fe74fd836b6a7282d9a40d4cfbcc2b68a7 Mon Sep 17 00:00:00 2001 From: Adolfo Builes Date: Mon, 14 Apr 2014 22:20:59 -0300 Subject: [PATCH 0125/2527] Extend from Controller for ApplicationController. --- packages/ember-data/tests/integration/application_test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/tests/integration/application_test.js b/packages/ember-data/tests/integration/application_test.js index 46b0f51023e..d19080b49b8 100644 --- a/packages/ember-data/tests/integration/application_test.js +++ b/packages/ember-data/tests/integration/application_test.js @@ -21,7 +21,7 @@ module("integration/application - Injecting a Custom Store", { FooController: Controller.extend(), ApplicationView: View.extend(), BazController: {}, - ApplicationController: View.extend() + ApplicationController: Controller.extend() }); }); @@ -70,7 +70,7 @@ module("integration/application - Injecting the Default Store", { FooController: Controller.extend(), ApplicationView: View.extend(), BazController: {}, - ApplicationController: View.extend() + ApplicationController: Controller.extend() }); }); From ced958ce5fe0e7dacb8c318f529a4d6fd2705faa Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 18 Apr 2014 14:53:50 -0400 Subject: [PATCH 0126/2527] Add examples to the DS.Errors api docs. --- .../ember-data/lib/system/model/errors.js | 137 +++++++++++++++++- packages/ember-data/lib/system/model/model.js | 2 +- 2 files changed, 136 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index 338927ca53d..3b209c7491e 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -7,6 +7,65 @@ var get = Ember.get, isEmpty = Ember.isEmpty; /** Holds validation errors for a given record organized by attribute names. + Every DS.Model has an `errors` property that is an instance of + `DS.Errors`. This can be used to display validation error + messages returned from the server when a `record.save()` rejects. + + For Example, if you had an `User` model that looked like this: + + ```javascript + App.User = DS.Model.extend({ + username: attr('string'), + email: attr('string') + }); + ``` + And you attempted to save a record that did not validate on the backend. + + ```javascript + var user = store.createRecord('user', { + username: 'tomster', + email: 'invalidEmail' + }); + user.save(); + ``` + + Your backend data store might return a response that looks like + this. This response will be used to populate the error object. + + ```javascript + { + "errors": { + "username": ["This username is already taken!"], + "email": ["Doesn't look like a valid email."] + } + } + ``` + + Errors can be displayed to the user by accessing their property name + or using the `messages` property to get an array of all errors. + + ```handlebars + {{#each errors.messages}} +
      + {{message}} +
      + {{/each}} + + + {{#each errors.username}} +
      + {{message}} +
      + {{/each}} + + + {{#each errors.email}} +
      + {{message}} +
      + {{/each}} + ``` + @class Errors @namespace DS @extends Ember.Object @@ -57,6 +116,16 @@ var Errors = Ember.Object.extend(Ember.Enumerable, Ember.Evented, { /** Returns errors for a given attribute + ```javascript + var user = store.createRecord('user', { + username: 'tomster', + email: 'invalidEmail' + }); + user.save().catch(function(){ + user.get('errors').errorsFor('email'); // ["Doesn't look like a valid email."] + }); + ``` + @method errorsFor @param {String} attribute @return {Array} @@ -66,8 +135,17 @@ var Errors = Ember.Object.extend(Ember.Enumerable, Ember.Evented, { }, /** - An array containing all of the error messages for this record. - + An array containing all of the error messages for this + record. This is useful for displaying all errors to the user. + + ```handlebars + {{#each errors.messages}} +
      + {{message}} +
      + {{/each}} + ``` + @property messages @type {Array} */ @@ -120,6 +198,14 @@ var Errors = Ember.Object.extend(Ember.Enumerable, Ember.Evented, { Adds error messages to a given attribute and sends `becameInvalid` event to the record. + Example: + + ```javascript + if (!user.get('username') { + user.get('errors').add('username', 'This field is required'); + } + ``` + @method add @param {String} attribute @param {Array|String} messages @@ -157,6 +243,27 @@ var Errors = Ember.Object.extend(Ember.Enumerable, Ember.Evented, { Removes all error messages from the given attribute and sends `becameValid` event to the record if there no more errors left. + Example: + + ```javascript + App.User = DS.Model.extend({ + email: DS.attr('string'), + twoFactorAuth: DS.attr('boolean'), + phone: DS.attr('string') + }); + + App.UserEditRoute = Ember.Route.extend({ + actions: { + save: function(user) { + if (!user.get('twoFactorAuth')) { + user.get('errors').remove('phone'); + } + user.save(); + } + } + }); + ``` + @method remove @param {String} attribute */ @@ -178,6 +285,19 @@ var Errors = Ember.Object.extend(Ember.Enumerable, Ember.Evented, { Removes all error messages and sends `becameValid` event to the record. + Example: + + ```javascript + App.UserEditRoute = Ember.Route.extend({ + actions: { + retrySave: function(user) { + user.get('errors').clear(); + user.save(); + } + } + }); + ``` + @method clear */ clear: function() { @@ -192,6 +312,19 @@ var Errors = Ember.Object.extend(Ember.Enumerable, Ember.Evented, { /** Checks if there is error messages for the given attribute. + ```javascript + App.UserEditRoute = Ember.Route.extend({ + actions: { + save: function(user) { + if (user.get('errors').has('email')) { + return alert('Please update your email before attempting to save.'); + } + user.save(); + } + } + }); + ``` + @method has @param {String} attribute @return {Boolean} true if there some errors on given attribute diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index dd8cc6d489c..2eded9f7553 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -306,7 +306,7 @@ var Model = Ember.Object.extend(Ember.Evented, { ``` @property errors - @type {Object} + @type {DS.Errors} */ errors: Ember.computed(function() { var errors = Errors.create(); From e2794ceca16198aa2ec7395ffbd7293852515ba2 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Tue, 22 Apr 2014 10:12:53 -0400 Subject: [PATCH 0127/2527] add bower to getting ember data section --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 1978cc3a0f7..40f6b6f9a19 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,10 @@ A [guide is provided on the Ember.js site](http://emberjs.com/guides/models/) th #### Getting ember-data +```no-highlight +bower install ember-data --save +``` + The latest passing build from the "master" branch is available on [http://emberjs.com/builds/#/canary](http://emberjs.com/builds/#/canary). Similarly the latest passing build from the "beta" branch can be found on [http://emberjs.com/builds/#/beta](http://emberjs.com/builds/#/beta) From fe6663ce0930305e850afcca6396524118c65356 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Tue, 22 Apr 2014 10:52:08 -0400 Subject: [PATCH 0128/2527] Update changelog for initializer and container setup changes --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e102e045dac..9a87b7d40ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Ember Data Changelog +### Master + +* Introduce `DS._setupContainer()` for use in testing +* Deprecate the 5 Ember initializers, use just one named "ember-data" + ### Ember Data 1.0.0-beta.7 _(February 19, 2014)_ * Release 1.0.0-beta.7 From 34f6605cd38efae9ddf7096df76381ae20ef1ed2 Mon Sep 17 00:00:00 2001 From: Bill Heaton Date: Tue, 22 Apr 2014 09:35:00 -0700 Subject: [PATCH 0129/2527] Fix validation comments for - Api docs included comments on failing client-side validation - DS.model doesn't have client side validation - Only code that sets errors and changes is a result of an invalid response from server --- packages/ember-data/lib/system/model/model.js | 6 +++--- packages/ember-data/lib/system/model/states.js | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index dd8cc6d489c..c2b6db25b2f 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -182,9 +182,9 @@ var Model = Ember.Object.extend(Ember.Evented, { */ isNew: retrieveFromCurrentState, /** - If this property is `true` the record is in the `valid` state. A - record will be in the `valid` state when no client-side - validations have failed and the adapter did not report any + If this property is `true` the record is in the `valid` state. + + A record will be in the `valid` state when the adapter did not report any server-side validation failures. @property isValid diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index 48e4ccfe747..6ede0c1efe6 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -220,8 +220,8 @@ function didSetProperty(record, context) { // adapter reported that server-side validations failed. // * isNew: The record was created on the client and the adapter // did not yet report that it was successfully saved. -// * isValid: No client-side validations have failed and the -// adapter did not report any server-side validation failures. +// * isValid: The adapter did not report any server-side validation +// failures. // The dirty state is a abstract state whose functionality is // shared between the `created` and `updated` states. @@ -326,8 +326,7 @@ var DirtyState = { } }, - // A record is in the `invalid` state when its client-side - // invalidations have failed, or if the adapter has indicated + // A record is in the `invalid` if the adapter has indicated // the the record failed server-side invalidations. invalid: { // FLAGS From 1427731af460cb9dbc2fae974ee5907b06162600 Mon Sep 17 00:00:00 2001 From: Bill Heaton Date: Tue, 22 Apr 2014 17:42:26 -0700 Subject: [PATCH 0130/2527] [DOC beta] Clarify adapter settings with ActiveModel::Serializers --- .../activemodel-adapter/lib/system/active_model_adapter.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index 3c4dce3360d..e357e6fb404 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -14,10 +14,11 @@ var decamelize = Ember.String.decamelize, /** The ActiveModelAdapter is a subclass of the RESTAdapter designed to integrate - with a JSON API that uses an underscored naming convention instead of camelcasing. + with a JSON API that uses an underscored naming convention instead of camelCasing. It has been designed to work out of the box with the [active_model_serializers](http://github.com/rails-api/active_model_serializers) - Ruby gem. + Ruby gem. This Adapter expects specific settings using ActiveModel::Serializers, + `embed :ids, include: true` which sideloads the records. This adapter extends the DS.RESTAdapter by making consistent use of the camelization, decamelization and pluralization methods to normalize the serialized JSON into a From 1d0d70ba867d8bb7919a36c74caed4853ad131de Mon Sep 17 00:00:00 2001 From: tchak Date: Wed, 23 Apr 2014 22:14:21 +0200 Subject: [PATCH 0131/2527] allow saving records from invalid state tests by @alexspeller --- .../ember-data/lib/system/model/states.js | 5 + .../integration/adapter/store_adapter_test.js | 93 +++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index 48e4ccfe747..aeffe322c4c 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -347,6 +347,11 @@ var DirtyState = { becomeDirty: Ember.K, + willCommit: function(record) { + get(record, 'errors').clear(); + record.transitionTo('inFlight'); + }, + rolledBack: function(record) { get(record, 'errors').clear(); }, diff --git a/packages/ember-data/tests/integration/adapter/store_adapter_test.js b/packages/ember-data/tests/integration/adapter/store_adapter_test.js index 20532ff0d0a..bf5e25aa0a5 100644 --- a/packages/ember-data/tests/integration/adapter/store_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/store_adapter_test.js @@ -352,6 +352,50 @@ test("if a created record is marked as invalid by the server, it enters an error }); }); +test("if a created record is marked as invalid by the server, you can attempt the save again", function() { + var saveCount = 0; + adapter.createRecord = function(store, type, record) { + equal(type, Person, "the type is correct"); + saveCount++; + + if (get(record, 'name').indexOf('Bro') === -1) { + return Ember.RSVP.reject(new DS.InvalidError({ name: ['common... name requires a "bro"'] })); + } else { + return Ember.RSVP.resolve(); + } + }; + + var yehuda = store.createRecord('person', { id: 1, name: "Yehuda Katz" }); + + // Wrap this in an Ember.run so that all chained async behavior is set up + // before flushing any scheduled behavior. + Ember.run(function() { + yehuda.save().then(null, async(function(reason) { + equal(saveCount, 1, "The record has been saved once"); + ok(reason.message.match("The backend rejected the commit because it was invalid"), "It should fail due to being invalid"); + equal(get(yehuda, 'isValid'), false, "the record is invalid"); + equal(get(yehuda, 'isDirty'), true, "the record has outstanding changes"); + ok(get(yehuda, 'errors.name'), "The errors.name property exists"); + equal(get(yehuda, 'isNew'), true, "precond - record is still new"); + return yehuda.save(); + })).then(null, async(function(reason) { + equal(saveCount, 2, "The record has been saved twice"); + ok(reason.message.match("The backend rejected the commit because it was invalid"), "It should fail due to being invalid"); + equal(get(yehuda, 'isValid'), false, "the record is still invalid"); + equal(get(yehuda, 'isDirty'), true, "the record has outstanding changes"); + ok(get(yehuda, 'errors.name'), "The errors.name property exists"); + equal(get(yehuda, 'isNew'), true, "precond - record is still new"); + set(yehuda, 'name', 'Brohuda Brokatz'); + return yehuda.save() + })).then(async(function(person) { + equal(saveCount, 3, "The record has been saved thrice"); + equal(get(yehuda, 'isValid'), true, "record is valid"); + equal(get(yehuda, 'isDirty'), false, "record is not dirty"); + equal(get(yehuda, 'errors.isEmpty'), true, "record has no errors"); + })); + }); +}); + test("if a created record is marked as erred by the server, it enters an error state", function() { adapter.createRecord = function(store, type, record) { return Ember.RSVP.reject(); @@ -409,6 +453,55 @@ test("if an updated record is marked as invalid by the server, it enters an erro }); }); + +test("if an updated record is marked as invalid by the server, you can attempt the save again", function() { + var saveCount = 0; + adapter.updateRecord = function(store, type, record) { + equal(type, Person, "the type is correct"); + saveCount++; + if (get(record, 'name').indexOf('Bro') === -1) { + return Ember.RSVP.reject(new DS.InvalidError({ name: ['common... name requires a "bro"'] })); + } else { + return Ember.RSVP.resolve(); + } + }; + + var yehuda = store.push('person', { id: 1, name: "Brohuda Brokatz" }); + + Ember.run(function() { + store.find('person', 1).then(async(function(person) { + equal(person, yehuda, "The same object is passed through"); + + equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); + set(yehuda, 'name', "Yehuda Katz"); + equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); + + equal(get(yehuda, 'isDirty'), true, "the record is dirty"); + + return yehuda.save(); + })).then(null, async(function(reason) { + equal(saveCount, 1, "The record has been saved once"); + ok(reason.message.match("The backend rejected the commit because it was invalid"), "It should fail due to being invalid"); + equal(get(yehuda, 'isDirty'), true, "the record is still dirty"); + equal(get(yehuda, 'isValid'), false, "the record is invalid"); + return yehuda.save(); + })).then(null, async(function(reason) { + equal(saveCount, 2, "The record has been saved twice"); + ok(reason.message.match("The backend rejected the commit because it was invalid"), "It should fail due to being invalid"); + equal(get(yehuda, 'isValid'), false, "record is still invalid"); + equal(get(yehuda, 'isDirty'), true, "record is still dirty"); + set(yehuda, 'name', 'Brohuda Brokatz'); + return yehuda.save() + })).then(async(function(person) { + equal(saveCount, 3, "The record has been saved thrice"); + equal(get(yehuda, 'isValid'), true, "record is valid"); + equal(get(yehuda, 'isDirty'), false, "record is not dirty"); + equal(get(yehuda, 'errors.isEmpty'), true, "record has no errors"); + })); + }); +}); + + test("if a updated record is marked as erred by the server, it enters an error state", function() { adapter.updateRecord = function(store, type, record) { return Ember.RSVP.reject(); From 7124bfa8ab289406d0deda4711681dbaeabaa9f0 Mon Sep 17 00:00:00 2001 From: Kerrick Long Date: Thu, 24 Apr 2014 11:27:06 -0500 Subject: [PATCH 0132/2527] Import InvalidError instead of looking at global DS --- packages/ember-data/lib/system/store.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 3b709f31c8c..965d8aadb0d 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -5,7 +5,7 @@ @module ember-data */ -import Adapter from "./adapter"; +import {InvalidError, Adapter} from "./adapter"; var get = Ember.get, set = Ember.set; var once = Ember.run.once; var isNone = Ember.isNone; @@ -1778,7 +1778,7 @@ function _commit(adapter, store, operation, record) { store.didSaveRecord(record, payload); return record; }, function(reason) { - if (reason instanceof DS.InvalidError) { + if (reason instanceof InvalidError) { store.recordWasInvalid(record, reason.errors); } else { store.recordWasError(record, reason); From 2d40e0c1366e403ab50be6c9aaa603a67825a4c8 Mon Sep 17 00:00:00 2001 From: Alex Speller Date: Fri, 25 Apr 2014 17:37:10 +0100 Subject: [PATCH 0133/2527] Add a better transform example --- packages/ember-data/lib/transforms/base.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/transforms/base.js b/packages/ember-data/lib/transforms/base.js index c6763836597..49ade892518 100644 --- a/packages/ember-data/lib/transforms/base.js +++ b/packages/ember-data/lib/transforms/base.js @@ -8,12 +8,13 @@ Example ```javascript - App.RawTransform = DS.Transform.extend({ + // Converts centigrade in the JSON to fahrenheit in the app + App.TemperatureTransform = DS.Transform.extend({ deserialize: function(serialized) { - return serialized; + return (serialized * 1.8) + 32; }, serialize: function(deserialized) { - return deserialized; + return (deserialized - 32) / 1.8; } }); ``` From be797b992acba75e28a8e07007e2c4b15508661e Mon Sep 17 00:00:00 2001 From: Cory Forsyth Date: Fri, 25 Apr 2014 13:21:32 -0400 Subject: [PATCH 0134/2527] [DOC] Fix docs for method signature of extractSingle, extractArray --- .../lib/system/embedded_records_mixin.js | 4 ++-- .../lib/serializers/rest_serializer.js | 18 ++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index 992be981a3a..482aab5a798 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -52,13 +52,13 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ @method extractSingle */ - extractSingle: function(store, primaryType, payload, recordId, requestType) { + extractSingle: function(store, primaryType, payload, recordId) { var root = this.keyForAttribute(primaryType.typeKey), partial = payload[root]; updatePayloadWithEmbedded(store, this, primaryType, partial, payload); - return this._super(store, primaryType, payload, recordId, requestType); + return this._super(store, primaryType, payload, recordId); }, /** diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index ed0afd2c096..8865ad92a2e 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -310,12 +310,12 @@ var RESTSerializer = JSONSerializer.extend({ ```js App.PostSerializer = DS.RESTSerializer.extend({ // First, restructure the top-level so it's organized by type - extractSingle: function(store, type, payload, id, requestType) { + extractSingle: function(store, type, payload, id) { var comments = payload._embedded.comment; delete payload._embedded; payload = { comments: comments, post: payload }; - return this._super(store, type, payload, id, requestType); + return this._super(store, type, payload, id); }, normalizeHash: { @@ -345,13 +345,12 @@ var RESTSerializer = JSONSerializer.extend({ @method extractSingle @param {DS.Store} store - @param {subclass of DS.Model} type + @param {subclass of DS.Model} primaryType @param {Object} payload - @param {String} id - @param {'find'|'createRecord'|'updateRecord'|'deleteRecord'} requestType + @param {String} recordId @return {Object} the primary response to the original request */ - extractSingle: function(store, primaryType, payload, recordId, requestType) { + extractSingle: function(store, primaryType, payload, recordId) { payload = this.normalizePayload(primaryType, payload); var primaryTypeName = primaryType.typeKey, @@ -439,7 +438,7 @@ var RESTSerializer = JSONSerializer.extend({ App.PostSerializer = DS.RESTSerializer.extend({ // First, restructure the top-level so it's organized by type // and the comments are listed under a post's `comments` key. - extractArray: function(store, type, payload, id, requestType) { + extractArray: function(store, type, payload) { var posts = payload._embedded.post; var comments = []; var postCache = {}; @@ -457,7 +456,7 @@ var RESTSerializer = JSONSerializer.extend({ payload = { comments: comments, posts: payload }; - return this._super(store, type, payload, id, requestType); + return this._super(store, type, payload); }, normalizeHash: { @@ -491,9 +490,8 @@ var RESTSerializer = JSONSerializer.extend({ @method extractArray @param {DS.Store} store - @param {subclass of DS.Model} type + @param {subclass of DS.Model} primaryType @param {Object} payload - @param {'findAll'|'findMany'|'findHasMany'|'findQuery'} requestType @return {Array} The primary array that was returned in response to the original query. */ From 96e36b8b9003cc1cd1669ec1ff850216b18f250d Mon Sep 17 00:00:00 2001 From: Cory Forsyth Date: Fri, 25 Apr 2014 13:23:59 -0400 Subject: [PATCH 0135/2527] [DOC] `bower install` is part of `npm install`, removing it from README --- README.md | 4 +++- package.json | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 40f6b6f9a19..bfcf3341957 100644 --- a/README.md +++ b/README.md @@ -59,12 +59,14 @@ You also have the option to build ember-data.js yourself. Clone the repository, 2. Install grunt and bower. `npm install -g grunt-cli bower` -3. Run `npm install && bower install` inside the project root to install the JS dependencies. +3. Run `npm install` inside the project root to install the JS dependencies. ### In Your Browser 1. To start the development server, run `grunt dev`. +2. Visit http://localhost:9997/tests + ### From the CLI 1. Install phantomjs from http://phantomjs.org diff --git a/package.json b/package.json index c1b2a2639e2..0388913a297 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,10 @@ "bower": "~1.2", "grunt-ember-defeatureify": "~0.1.0", "aws-sdk": "~2.0.0-rc8", - "grunt-cli": "~0.1.13", "grunt-contrib-yuidoc": "~0.5.0", "lockfile": "~0.4.2" + }, + "peerDependencies": { + "grunt-cli": "~0.1.13" } } From 64dc4acdd178d27d0dbc301bc1a9bd97237ba4f3 Mon Sep 17 00:00:00 2001 From: Alex Brinkman Date: Mon, 28 Apr 2014 22:42:08 -0600 Subject: [PATCH 0136/2527] Fixes a typo in the documentation of the serializeAttribute method of json_serializer.js --- packages/ember-data/lib/serializers/json_serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 37c4120eae1..a06a103ec6a 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -277,7 +277,7 @@ var JSONSerializer = Ember.Object.extend({ `serializeAttribute` can be used to customize how `DS.attr` properties are serialized - For example if you wanted to ensure all you attributes were always + For example if you wanted to ensure all your attributes were always serialized as properties on an `attributes` object you could write: From 88ea9cb057ec498f82ee240afb998d8aaede9fc5 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Fri, 2 May 2014 01:32:13 +0900 Subject: [PATCH 0137/2527] Specify language as Node.js on Travis CI Without `language` section, Travis CI detects Ruby as build language: * https://travis-ci.org/emberjs/data/builds/24150621#L18 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index fee73a5a45b..0c84773b393 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ --- +language: node_js node_js: - "0.10" install: From 4c8b7241112dd9032c7a7f18685202ab5eb4f6be Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Fri, 2 May 2014 02:19:46 +0900 Subject: [PATCH 0138/2527] Use npm-scripts to run test * https://www.npmjs.org/doc/misc/npm-scripts.html --- .travis.yml | 3 +-- package.json | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0c84773b393..dcf01158174 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,7 @@ node_js: install: - "bin/cached-npm install" - "bower install" -script: grunt test:all -after_success: grunt dist publish +after_success: npm publish env: global: - S3_BUILD_CACHE_BUCKET=emberjs-build-cache diff --git a/package.json b/package.json index 0388913a297..9c2b805b240 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "namespace": "DS", "scripts": { "postinstall": "bower install", - "test": "grunt test" + "test": "grunt test:all", + "publish": "grunt dist publish" }, "devDependencies": { "defeatureify": "~0.1.4", @@ -25,9 +26,7 @@ "grunt-ember-defeatureify": "~0.1.0", "aws-sdk": "~2.0.0-rc8", "grunt-contrib-yuidoc": "~0.5.0", - "lockfile": "~0.4.2" - }, - "peerDependencies": { + "lockfile": "~0.4.2", "grunt-cli": "~0.1.13" } } From 7d7ccfa44cc3f597d3d30727382a05ddb9335089 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Fri, 2 May 2014 00:45:56 +0900 Subject: [PATCH 0139/2527] Use `package.json` as gem version --- VERSION | 1 - ember-data-source.gemspec | 2 +- lib/ember/data/version.rb | 6 +++++- 3 files changed, 6 insertions(+), 3 deletions(-) delete mode 100644 VERSION diff --git a/VERSION b/VERSION deleted file mode 100644 index 4603afe218d..00000000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -1.0.0-beta.8+canary diff --git a/ember-data-source.gemspec b/ember-data-source.gemspec index 86b71812f8f..827eccd53aa 100644 --- a/ember-data-source.gemspec +++ b/ember-data-source.gemspec @@ -14,5 +14,5 @@ Gem::Specification.new do |gem| gem.add_dependency "ember-source" - gem.files = %w(VERSION) + Dir['dist/ember-data*.js', 'lib/ember/data/*.rb'] + gem.files = Dir['dist/ember-data*.js', 'lib/ember/data/*.rb'] end diff --git a/lib/ember/data/version.rb b/lib/ember/data/version.rb index 670c6d033f6..67e860b6e2a 100644 --- a/lib/ember/data/version.rb +++ b/lib/ember/data/version.rb @@ -1,5 +1,9 @@ +require 'json' + module Ember module Data - VERSION = File.read(File.expand_path('../../../../VERSION', __FILE__)).strip.gsub(/[-\+]/, '.') + package = File.read(File.expand_path('../../../../package.json', __FILE__)) + + VERSION = JSON.parse(package)['version'].strip.gsub(/[-\+]/, '.') end end From 8d51583738cb71c7d070d55399ab286d95b489b7 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Fri, 2 May 2014 00:46:22 +0900 Subject: [PATCH 0140/2527] Fix to update ember-data version Now, ember-data is versioned as 1.0.0-beta.8+canary. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9c2b805b240..a59b09133f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.7+canary", + "version": "1.0.0-beta.8+canary", "namespace": "DS", "scripts": { "postinstall": "bower install", From 3715083fe8f2df2ce6fa3a5af4c56595f78a94c8 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Fri, 2 May 2014 02:41:53 +0900 Subject: [PATCH 0141/2527] Cleanup scripts * Remove old script `bin/cached-bundle` * Fix to update comment for `bin/cached-npm` --- bin/cached-bundle | 60 ----------------------------------------------- bin/cached-npm | 4 ++-- 2 files changed, 2 insertions(+), 62 deletions(-) delete mode 100755 bin/cached-bundle diff --git a/bin/cached-bundle b/bin/cached-bundle deleted file mode 100755 index 330effa1899..00000000000 --- a/bin/cached-bundle +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env bash -# Usage: cached-bundle install --deployment -# -# After running `bundle`, caches the `vendor/bundle` directory to S3. -# On the next run, restores the cached directory before running `bundle`. -# When `Gemfile.lock` changes, the cache gets rebuilt. -# -# Requirements: -# - Gemfile.lock -# - TRAVIS_REPO_SLUG -# - TRAVIS_RUBY_VERSION -# - S3_BUILD_CACHE_BUCKET -# - script/s3-put -# - bundle -# - curl -# -# Author: Mislav Marohnić - -set -e - -compute_md5() { - local output="$(openssl md5)" - echo "${output##* }" -} - -download() { - curl --tcp-nodelay -qsfL "$1" -o "$2" -} - -script_dir=$(dirname "${BASH_SOURCE[0]}") -bundle_path="vendor/bundle" -cache_buster="${BUNDLE_GEMFILE:-Gemfile}.lock" -if [ ! -f $cache_buster ]; then - cache_buster="$GEMSPEC" -fi -cache_busting_hash="$(compute_md5 <"$cache_buster")" - -cache_name="bundler-${TRAVIS_RUBY_VERSION}-${cache_busting_hash}.tgz" -fetch_url="http://${S3_BUILD_CACHE_BUCKET}.s3.amazonaws.com/${TRAVIS_REPO_SLUG}/${cache_name}" - -if download "$fetch_url" "$cache_name"; then - echo "Reusing cached bundle ${cache_name}" - tar xzf "$cache_name" -fi - -bundle "$@" - -if [ ! -f "$cache_name" ]; then - if [ -z "$S3_SECRET_ACCESS_KEY" ] || [ -z "$S3_ACCESS_KEY_ID" ] - then - echo "Enviroment variables not set. Exiting..." - exit 0 - fi - - echo "Caching \`${bundle_path}' to S3" - tar czf "$cache_name" "$bundle_path" - $script_dir/s3-put "$cache_name" "${S3_BUILD_CACHE_BUCKET}:${TRAVIS_REPO_SLUG}/${cache_name}" -fi - -# vim: filetype=sh diff --git a/bin/cached-npm b/bin/cached-npm index 8861f976072..5c7795bb9f6 100755 --- a/bin/cached-npm +++ b/bin/cached-npm @@ -6,12 +6,12 @@ # When `package.json` changes, the cache gets rebuilt. # # Requirements: -# - Gemfile.lock +# - package.json # - TRAVIS_REPO_SLUG # - TRAVIS_NODE_VERSION # - S3_BUILD_CACHE_BUCKET # - script/s3-put -# - bundle +# - npm # - curl # # Author: Mislav Marohnić From 79310f7ff962f3c57e0c8f6a6c2a4c11bbe48ce4 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Fri, 2 May 2014 02:51:11 +0900 Subject: [PATCH 0142/2527] Add `repository` field to package.json To suppress warning from npm: ``` npm WARN package.json ember-data@1.0.0-beta.7+canary No repository field. ``` --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 9c2b805b240..c6c6270e4dc 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "ember-data", "version": "1.0.0-beta.7+canary", "namespace": "DS", + "repository": "git://github.com/emberjs/data.git", "scripts": { "postinstall": "bower install", "test": "grunt test:all", From 7c415231bfc1845cb40aa0522ad84c6f324c47d3 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Fri, 2 May 2014 02:55:44 +0900 Subject: [PATCH 0143/2527] Add `license` field to package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index c6c6270e4dc..b40dd650623 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.0.0-beta.7+canary", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", + "license": "MIT", "scripts": { "postinstall": "bower install", "test": "grunt test:all", From 528ee0e06646b59faadc8eb0814670b2bf9de1bd Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 5 May 2014 11:21:20 -0400 Subject: [PATCH 0144/2527] incase jQuery.ajax returns a null or undefined jqXHR --- packages/ember-data/lib/adapters/rest_adapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index eea6df501e2..6a753aa8df7 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -547,7 +547,7 @@ var RESTAdapter = Adapter.extend({ @return {Object} jqXHR */ ajaxError: function(jqXHR) { - if (jqXHR) { + if (jqXHR && typeof jqXHR === 'object') { jqXHR.then = null; } From 89ff226a190e8d8668c60307b5db828807987fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20B=C3=B6hi?= Date: Sun, 27 Apr 2014 22:55:53 +0200 Subject: [PATCH 0145/2527] Allow belongs to associations to be saved when the associated object is null. --- .../lib/system/active_model_serializer.js | 8 +++++++- .../tests/integration/active_model_serializer_test.js | 8 ++++++++ packages/ember-data/lib/serializers/json_serializer.js | 7 ++++++- packages/ember-data/lib/serializers/rest_serializer.js | 7 ++++++- .../tests/integration/serializers/rest_serializer_test.js | 8 ++++++++ 5 files changed, 35 insertions(+), 3 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index f767084f599..b0b6489b97a 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -76,7 +76,13 @@ var ActiveModelSerializer = RESTSerializer.extend({ var key = relationship.key, belongsTo = get(record, key); key = this.keyForAttribute(key); - json[key + "_type"] = capitalize(camelize(belongsTo.constructor.typeKey)); + + if (Ember.isNone(belongsTo)) { + json[key + "_type"] = null; + } else { + json[key + "_type"] = capitalize(camelize(belongsTo.constructor.typeKey)); + } + }, // EXTRACT diff --git a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js index 3b289ac7d62..4099c6b15e5 100644 --- a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js +++ b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js @@ -189,6 +189,14 @@ test("serialize polymorphic when type key is not camelized", function() { deepEqual(json["evil_minion_type"], "YellowMinion"); }); +test("serialize polymorphic when associated object is null", function() { + var ray = env.store.createRecord(DoomsdayDevice, {name: "DeathRay"}); + + var json = env.amsSerializer.serialize(ray); + + deepEqual(json["evil_minion_type"], null); +}); + test("extractPolymorphic hasMany", function() { env.container.register('adapter:yellowMinion', DS.ActiveModelAdapter); MediocreVillain.toString = function() { return "MediocreVillain"; }; diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 37c4120eae1..14d3b1d77aa 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -404,7 +404,12 @@ var JSONSerializer = Ember.Object.extend({ var key = relationship.key, belongsTo = get(record, key); key = this.keyForAttribute ? this.keyForAttribute(key) : key; - json[key + "_type"] = belongsTo.constructor.typeKey; + + if (Ember.isNone(belongsTo)) { + json[key + "_type"] = null; + } else { + json[key + "_type"] = capitalize(camelize(belongsTo.constructor.typeKey)); + } } }); ``` diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index ed0afd2c096..5e24d2b43e2 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -791,7 +791,12 @@ var RESTSerializer = JSONSerializer.extend({ var key = relationship.key, belongsTo = get(record, key); key = this.keyForAttribute ? this.keyForAttribute(key) : key; - json[key + "Type"] = Ember.String.camelize(belongsTo.constructor.typeKey); + + if (Ember.isNone(belongsTo)) { + json[key + "Type"] = null; + } else { + json[key + "Type"] = Ember.String.camelize(belongsTo.constructor.typeKey); + } } }); diff --git a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js index 27fcf55a20c..3cf263a3cb0 100644 --- a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js @@ -112,6 +112,14 @@ test("serialize polymorphicType with decamelized typeKey", function() { deepEqual(json["evilMinionType"], "yellowMinion"); }); +test("serialize polymorphic when associated object is null", function() { + var ray = env.store.createRecord(DoomsdayDevice, {name: "DeathRay"}); + + var json = env.restSerializer.serialize(ray); + + deepEqual(json["evilMinionType"], null); +}); + test("extractArray can load secondary records of the same type without affecting the query count", function() { var json_hash = { comments: [{id: "1", body: "Parent Comment", root: true, children: [2, 3]}], From 586a21ce628aff737572b900a8445dfc27ab454d Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 5 May 2014 16:30:32 -0400 Subject: [PATCH 0146/2527] Remove incorrect semicolon from pathForType example. Also changed the example to use .extend instead of reopen --- packages/ember-data/lib/adapters/rest_adapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index eea6df501e2..6780e1c6dbd 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -495,11 +495,11 @@ var RESTAdapter = Adapter.extend({ endpoint of "/line_items/". ```js - DS.RESTAdapter.reopen({ + App.ApplicationAdapter = DS.RESTAdapter.extend({ pathForType: function(type) { var decamelized = Ember.String.decamelize(type); return Ember.String.pluralize(decamelized); - }; + } }); ``` From 789f859994c48f1189a9174dad162e2a9cee0e20 Mon Sep 17 00:00:00 2001 From: Bill Heaton Date: Wed, 8 Jan 2014 23:42:59 -0800 Subject: [PATCH 0147/2527] [BUGFIX] Add missing support for belongsTo in DS.EmbeddedRecordsMixin - active_model_serializer gem `has_one` setting allows embedding objects - Add attrs options for serialize/deserialize using records or ids - Add attrs options for not serializing relationships using serialize:no -Add a hook called removeEmbeddedForeignKey for optional removal of foreign key reference from the embedded record --- TRANSITION.md | 5 +- .../lib/system/active_model_serializer.js | 15 +- .../lib/system/embedded_records_mixin.js | 473 ++++++++++++++++-- .../embedded_records_mixin_test.js | 449 ++++++++++++++++- 4 files changed, 860 insertions(+), 82 deletions(-) diff --git a/TRANSITION.md b/TRANSITION.md index 145df9f056b..5ea7a688edd 100644 --- a/TRANSITION.md +++ b/TRANSITION.md @@ -772,10 +772,11 @@ App.ApplicationSerializer = DS.RESTSerializer.extend({ ### Embedded Records -Explicit support for embedded records is gone for now. +Explicit support for embedded records has been moved into a mixin within +the activemodel-adapter package. You can handle embedded records yourself by implementing `extractSingle` -and reorganizing the payload. +and reorganizing the payload, or using the DS.EmbeddedRecordsMixin Consider this payload: diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index f767084f599..015243d87c8 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -15,7 +15,7 @@ var ActiveModelSerializer = RESTSerializer.extend({ // SERIALIZE /** - Converts camelcased attributes to underscored when serializing. + Converts camelCased attributes to underscored when serializing. @method keyForAttribute @param {String} attribute @@ -75,8 +75,11 @@ var ActiveModelSerializer = RESTSerializer.extend({ serializePolymorphicType: function(record, json, relationship) { var key = relationship.key, belongsTo = get(record, key); - key = this.keyForAttribute(key); - json[key + "_type"] = capitalize(camelize(belongsTo.constructor.typeKey)); + + if (belongsTo) { + key = this.keyForAttribute(key); + json[key + "_type"] = capitalize(camelize(belongsTo.constructor.typeKey)); + } }, // EXTRACT @@ -94,10 +97,9 @@ var ActiveModelSerializer = RESTSerializer.extend({ }, /** - Add extra step to `DS.RESTSerializer.normalize` so links are - normalized. + Add extra step to `DS.RESTSerializer.normalize` so links are normalized. - If your payload looks like this + If your payload looks like: ```js { @@ -108,6 +110,7 @@ var ActiveModelSerializer = RESTSerializer.extend({ } } ``` + The normalized version would look like this ```js diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index 992be981a3a..7522b73c4a7 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -1,23 +1,32 @@ var get = Ember.get; var forEach = Ember.EnumerableUtils.forEach; +var camelize = Ember.String.camelize; import {pluralize} from "../../../ember-inflector/lib/main"; /** - The EmbeddedRecordsMixin allows you to add embedded record support to your - serializers. - To set up embedded records, you include the mixin into the serializer and then - define your embedded relations. + DS.EmbeddedRecordsMixin supports serializing embedded records. + + To set up embedded records, include the mixin into a serializer then define + embedded (model) relationships. + + Below is an example of a per type serializer (post type). ```js App.PostSerializer = DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - comments: {embedded: 'always'} + author: {embedded: 'always'}, + comments: {serialize: 'ids'} } }) ``` - Currently only `{embedded: 'always'}` records are supported. + The `attrs` option for a resource `{embedded: 'always'}` is shorthand for: + `{serialize: 'records', deserialize: 'records'}`. Embedded records are extracted + from a nested document, so the default option for `deserialize` is `records`. + + When serializing, a resource's `attrs` option may be set to use `ids` or `records` + for the `serialize` setting. @class EmbeddedRecordsMixin @namespace DS @@ -25,102 +34,456 @@ import {pluralize} from "../../../ember-inflector/lib/main"; var EmbeddedRecordsMixin = Ember.Mixin.create({ /** - Serialize has-many relationship when it is configured as embedded objects. + Serialize `belongsTo` relationship when it is configured as an embedded object. + + This example of an author model belongs to a post model: + + ```js + Post = DS.Model.extend({ + title: DS.attr('string'), + body: DS.attr('string'), + author: DS.belongsTo('author') + }); + + Author = DS.Model.extend({ + name: DS.attr('string'), + post: DS.belongsTo('post') + }); + ``` + + Use a custom (type) serializer for the post model to configure embedded author + + ```js + App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + author: {embedded: 'always'} + } + }) + ``` + + A payload with an attribute configured for embedded records can serialize + the records together under the root attribute's payload: + + ```js + { + "post": { + "id": "1" + "title": "Rails is omakase", + "author": { + "id": "2" + "name": "dhh" + } + } + } + ``` + + @method serializeBelongsTo + @param {DS.Model} record + @param {Object} json + @param {Object} relationship + */ + serializeBelongsTo: function(record, json, relationship) { + var attr = relationship.key; + var attrs = this.get('attrs'); + + var includeIds = hasSerializeIdsOption(attrs, attr) || noSerializeOptionSpecified(attrs, attr); + var includeRecords = hasSerializeRecordsOption(attrs, attr); + + var embeddedRecord = record.get(attr); + if (includeIds) { + key = this.keyForRelationship(attr, relationship.kind); + if (!embeddedRecord) { + json[key] = null; + } else { + json[key] = get(embeddedRecord, 'id'); + } + } else if (includeRecords) { + var key = this.keyForRelationship(attr); + if (!embeddedRecord) { + json[key] = null; + } else { + json[key] = embeddedRecord.serialize({includeId: true}); + this.removeEmbeddedForeignKey(record, embeddedRecord, relationship, json[key]); + } + } + }, + + /** + Serialize `hasMany` relationship when it is configured as embedded objects. + + This example of a post model has many comments: + + ```js + Post = DS.Model.extend({ + title: DS.attr('string'), + body: DS.attr('string'), + comments: DS.hasMany('comment') + }); + + Comment = DS.Model.extend({ + body: DS.attr('string'), + post: DS.belongsTo('post') + }); + ``` + + Use a custom (type) serializer for the post model to configure embedded comments + + ```js + App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + comments: {embedded: 'always'} + } + }) + ``` + + A payload with an attribute configured for embedded records can serialize + the records together under the root attribute's payload: + + ```js + { + "post": { + "id": "1" + "title": "Rails is omakase", + "body": "I want this for my ORM, I want that for my template language..." + "comments": [{ + "id": "1", + "body": "Rails is unagi" + }, { + "id": "2", + "body": "Omakase O_o" + }] + } + } + ``` + + The attrs options object can use more specific instruction for extracting and + serializing. When serializing, an option to embed `ids` or `records` can be set. + When extracting the only option is `records`. + + So `{embedded: 'always'}` is shorthand for: + `{serialize: 'records', deserialize: 'records'}` + + To embed the `ids` for a related object (using a hasMany relationship): + + ```js + App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + comments: {serialize: 'ids', deserialize: 'records'} + } + }) + ``` + + ```js + { + "post": { + "id": "1" + "title": "Rails is omakase", + "body": "I want this for my ORM, I want that for my template language..." + "comments": ["1", "2"] + } + } + ``` @method serializeHasMany + @param {DS.Model} record + @param {Object} json + @param {Object} relationship */ serializeHasMany: function(record, json, relationship) { - var key = relationship.key, - attrs = get(this, 'attrs'), - embed = attrs && attrs[key] && attrs[key].embedded === 'always'; + var attr = relationship.key; + var attrs = this.get('attrs'); + var includeIds = hasSerializeIdsOption(attrs, attr); + var includeRecords = hasSerializeRecordsOption(attrs, attr); + var key; + + if (includeIds) { + key = this.keyForRelationship(attr, relationship.kind); + json[key] = get(record, attr).mapBy('id'); + } else if (includeRecords) { + key = this.keyForAttribute(attr); + json[key] = get(record, attr).map(function(embeddedRecord) { + var serializedEmbeddedRecord = embeddedRecord.serialize({includeId: true}); + this.removeEmbeddedForeignKey(record, embeddedRecord, relationship, serializedEmbeddedRecord); + return serializedEmbeddedRecord; + }, this); + } + }, - if (embed) { - json[this.keyForAttribute(key)] = get(record, key).map(function(relation) { - var data = relation.serialize(), - primaryKey = get(this, 'primaryKey'); + /* + When serializing an embedded record, modify the property (in the json payload) + that refers to the parent record (foreign key for relationship). - data[primaryKey] = get(relation, primaryKey); + Serializing a `belongsTo` relationship removes the property that refers to the + parent record - return data; - }, this); + Serializing a `hasMany` relationship does not remove the property that refers to + the parent record. + + @method removeEmbeddedForeignKey + @param {DS.Model} record + @param {DS.Model} embeddedRecord + @param {Object} relationship + @param {Object} json + */ + removeEmbeddedForeignKey: function (record, embeddedRecord, relationship, json) { + if (relationship.kind === 'hasMany') { + return; + } else if (relationship.kind === 'belongsTo') { + var parentRecord = record.constructor.inverseFor(relationship.key); + if (parentRecord) { + var name = parentRecord.name; + var embeddedSerializer = this.store.serializerFor(embeddedRecord.constructor); + var parentKey = embeddedSerializer.keyForRelationship(name, parentRecord.kind); + if (parentKey) { + delete json[parentKey]; + } + } } }, /** - Extract embedded objects out of the payload for a single object - and add them as sideloaded objects instead. + Extract an embedded object from the payload for a single object + and add the object in the compound document (side-loaded) format instead. + + A payload with an attribute configured for embedded records needs to be extracted: + + ```js + { + "post": { + "id": 1 + "title": "Rails is omakase", + "author": { + "id": 2 + "name": "dhh" + } + "comments": [] + } + } + ``` + + Ember Data is expecting a payload with a compound document (side-loaded) like: + + ```js + { + "post": { + "id": "1" + "title": "Rails is omakase", + "author": "2" + "comments": [] + }, + "authors": [{ + "id": "2" + "post": "1" + "name": "dhh" + }] + "comments": [] + } + ``` + + The payload's `author` attribute represents an object with a `belongsTo` relationship. + The `post` attribute under `author` is the foreign key with the id for the post @method extractSingle + @param {DS.Store} store + @param {subclass of DS.Model} primaryType + @param {Object} payload + @param {String} recordId + @param {'find'|'createRecord'|'updateRecord'|'deleteRecord'} requestType + @return Object the primary response to the original request */ extractSingle: function(store, primaryType, payload, recordId, requestType) { var root = this.keyForAttribute(primaryType.typeKey), partial = payload[root]; - updatePayloadWithEmbedded(store, this, primaryType, partial, payload); + updatePayloadWithEmbedded(this, store, primaryType, payload, partial); return this._super(store, primaryType, payload, recordId, requestType); }, /** - Extract embedded objects out of a standard payload - and add them as sideloaded objects instead. + Extract embedded objects in an array when an attr is configured for embedded, + and add them as side-loaded objects instead. + + A payload with an attr configured for embedded records needs to be extracted: + + ```js + { + "post": { + "id": "1" + "title": "Rails is omakase", + "comments": [{ + "id": "1", + "body": "Rails is unagi" + }, { + "id": "2", + "body": "Omakase O_o" + }] + } + } + ``` + + Ember Data is expecting a payload with compound document (side-loaded) like: + + ```js + { + "post": { + "id": "1" + "title": "Rails is omakase", + "comments": ["1", "2"] + }, + "comments": [{ + "id": "1", + "body": "Rails is unagi" + }, { + "id": "2", + "body": "Omakase O_o" + }] + } + ``` + + The payload's `comments` attribute represents records in a `hasMany` relationship @method extractArray + @param {DS.Store} store + @param {subclass of DS.Model} primaryType + @param {Object} payload + @return {Array} The primary array that was returned in response + to the original query. */ - extractArray: function(store, type, payload) { - var root = this.keyForAttribute(type.typeKey), + extractArray: function(store, primaryType, payload) { + var root = this.keyForAttribute(primaryType.typeKey), partials = payload[pluralize(root)]; forEach(partials, function(partial) { - updatePayloadWithEmbedded(store, this, type, partial, payload); + updatePayloadWithEmbedded(this, store, primaryType, payload, partial); }, this); - return this._super(store, type, payload); + return this._super(store, primaryType, payload); } }); -function updatePayloadWithEmbedded(store, serializer, type, partial, payload) { +// checks config for attrs option to embedded (always) - serialize and deserialize +function hasEmbeddedAlwaysOption(attrs, attr) { + var option = attrsOption(attrs, attr); + return option && option.embedded === 'always'; +} + +// checks config for attrs option to serialize ids +function hasSerializeRecordsOption(attrs, attr) { + var alwaysEmbed = hasEmbeddedAlwaysOption(attrs, attr); + var option = attrsOption(attrs, attr); + return alwaysEmbed || (option && (option.serialize === 'records')); +} + +// checks config for attrs option to serialize records +function hasSerializeIdsOption(attrs, attr) { + var option = attrsOption(attrs, attr); + return option && (option.serialize === 'ids' || option.serialize === 'id'); +} + +// checks config for attrs option to serialize records +function noSerializeOptionSpecified(attrs, attr) { + var option = attrsOption(attrs, attr); + var serializeRecords = hasSerializeRecordsOption(attrs, attr); + var serializeIds = hasSerializeIdsOption(attrs, attr); + return !(option && (option.serialize || option.embedded)); +} + +// checks config for attrs option to deserialize records +// a defined option object for a resource is treated the same as +// `deserialize: 'records'` +function hasDeserializeRecordsOption(attrs, attr) { + var alwaysEmbed = hasEmbeddedAlwaysOption(attrs, attr); + var option = attrsOption(attrs, attr); + var hasSerializingOption = option && (option.deserialize || option.serialize); + return alwaysEmbed || hasSerializingOption /* option.deserialize === 'records' */; +} + +function attrsOption(attrs, attr) { + return attrs && (attrs[Ember.String.camelize(attr)] || attrs[attr]); +} + +// chooses a relationship kind to branch which function is used to update payload +// does not change payload if attr is not embedded +function updatePayloadWithEmbedded(serializer, store, type, payload, partial) { var attrs = get(serializer, 'attrs'); if (!attrs) { return; } - type.eachRelationship(function(key, relationship) { - var expandedKey, embeddedTypeKey, attribute, ids, - config = attrs[key], - serializer = store.serializerFor(relationship.type.typeKey), - primaryKey = get(serializer, "primaryKey"); - - if (relationship.kind !== "hasMany") { - return; + if (hasDeserializeRecordsOption(attrs, key)) { + if (relationship.kind === "hasMany") { + updatePayloadWithEmbeddedHasMany(serializer, store, key, relationship, payload, partial); + } + if (relationship.kind === "belongsTo") { + updatePayloadWithEmbeddedBelongsTo(serializer, store, key, relationship, payload, partial); + } } + }); +} - if (config && (config.embedded === 'always' || config.embedded === 'load')) { - // underscore forces the embedded records to be side loaded. - // it is needed when main type === relationship.type - embeddedTypeKey = '_' + Ember.String.pluralize(relationship.type.typeKey); - expandedKey = this.keyForRelationship(key, relationship.kind); - attribute = this.keyForAttribute(key); - ids = []; +// handles embedding for `hasMany` relationship +function updatePayloadWithEmbeddedHasMany(serializer, store, primaryType, relationship, payload, partial) { + var embeddedSerializer = store.serializerFor(relationship.type.typeKey); + var primaryKey = get(serializer, 'primaryKey'); + var attr = relationship.type.typeKey; + // underscore forces the embedded records to be side loaded. + // it is needed when main type === relationship.type + var embeddedTypeKey = '_' + serializer.typeForRoot(relationship.type.typeKey); + var expandedKey = serializer.keyForRelationship(primaryType, relationship.kind); + var attribute = serializer.keyForAttribute(primaryType); + var ids = []; - if (!partial[attribute]) { - return; - } + if (!partial[attribute]) { + return; + } + + payload[embeddedTypeKey] = payload[embeddedTypeKey] || []; + + forEach(partial[attribute], function(data) { + var embeddedType = store.modelFor(attr); + updatePayloadWithEmbedded(embeddedSerializer, store, embeddedType, payload, data); + ids.push(data[primaryKey]); + payload[embeddedTypeKey].push(data); + }); + + partial[expandedKey] = ids; + delete partial[attribute]; +} - payload[embeddedTypeKey] = payload[embeddedTypeKey] || []; +// handles embedding for `belongsTo` relationship +function updatePayloadWithEmbeddedBelongsTo(serializer, store, primaryType, relationship, payload, partial) { + var attrs = serializer.get('attrs'); - forEach(partial[attribute], function(data) { - var embeddedType = store.modelFor(relationship.type.typeKey); - updatePayloadWithEmbedded(store, serializer, embeddedType, data, payload); - ids.push(data[primaryKey]); - payload[embeddedTypeKey].push(data); - }); + if (!attrs || + !(hasDeserializeRecordsOption(attrs, Ember.String.camelize(primaryType)) || + hasDeserializeRecordsOption(attrs, primaryType))) { + return; + } + var attr = relationship.type.typeKey; + var _serializer = store.serializerFor(relationship.type.typeKey); + var primaryKey = get(_serializer, 'primaryKey'); + var embeddedTypeKey = Ember.String.pluralize(attr); // TODO don't use pluralize + var expandedKey = _serializer.keyForRelationship(primaryType, relationship.kind); + var attribute = _serializer.keyForAttribute(primaryType); - partial[expandedKey] = ids; - delete partial[attribute]; + if (!partial[attribute]) { + return; + } + payload[embeddedTypeKey] = payload[embeddedTypeKey] || []; + var embeddedType = store.modelFor(relationship.type.typeKey); + for (var key in partial) { + if (partial.hasOwnProperty(key) && camelize(key) === attr) { + updatePayloadWithEmbedded(_serializer, store, embeddedType, payload, partial[key]); } - }, serializer); + } + partial[expandedKey] = partial[attribute].id; + // Need to move an embedded `belongsTo` object into a pluralized collection + payload[embeddedTypeKey].push(partial[attribute]); + // Need a reference to the parent so relationship works between both `belongsTo` records + partial[attribute][relationship.parentType.typeKey + '_id'] = partial.id; + delete partial[attribute]; } export default EmbeddedRecordsMixin; diff --git a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js index 77b0b6afbe0..69cbb1a6aa5 100644 --- a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js +++ b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js @@ -1,35 +1,51 @@ var get = Ember.get, set = Ember.set; -var HomePlanet, league, SuperVillain, superVillain, EvilMinion, Comment, env; +var HomePlanet, SuperVillain, EvilMinion, SecretLab, SecretWeapon, Comment, + league, superVillain, evilMinion, secretWeapon, env; module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { setup: function() { SuperVillain = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - homePlanet: DS.belongsTo("homePlanet"), - evilMinions: DS.hasMany("evilMinion") + firstName: DS.attr('string'), + lastName: DS.attr('string'), + homePlanet: DS.belongsTo("homePlanet"), + secretLab: DS.belongsTo("secretLab"), + secretWeapons: DS.hasMany("secretWeapon"), + evilMinions: DS.hasMany("evilMinion") }); HomePlanet = DS.Model.extend({ - name: DS.attr('string'), - villains: DS.hasMany('superVillain') + name: DS.attr('string'), + villains: DS.hasMany('superVillain') + }); + SecretLab = DS.Model.extend({ + minionCapacity: DS.attr('number'), + vicinity: DS.attr('string'), + superVillain: DS.belongsTo('superVillain') + }); + SecretWeapon = DS.Model.extend({ + name: DS.attr('string'), + superVillain: DS.belongsTo('superVillain') }); EvilMinion = DS.Model.extend({ - superVillain: DS.belongsTo('superVillain'), - name: DS.attr('string') + superVillain: DS.belongsTo('superVillain'), + name: DS.attr('string') }); Comment = DS.Model.extend({ - body: DS.attr('string'), - root: DS.attr('boolean'), - children: DS.hasMany('comment') + body: DS.attr('string'), + root: DS.attr('boolean'), + children: DS.hasMany('comment') }); env = setupStore({ - superVillain: SuperVillain, - homePlanet: HomePlanet, - evilMinion: EvilMinion, - comment: Comment + superVillain: SuperVillain, + homePlanet: HomePlanet, + secretLab: SecretLab, + secretWeapon: SecretWeapon, + evilMinion: EvilMinion, + comment: Comment }); env.store.modelFor('superVillain'); env.store.modelFor('homePlanet'); + env.store.modelFor('secretLab'); + env.store.modelFor('secretWeapon'); env.store.modelFor('evilMinion'); env.store.modelFor('comment'); env.container.register('serializer:application', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); @@ -406,9 +422,9 @@ test("extractArray with embedded objects of same type, but from separate attribu equal(env.store.recordForId("superVillain", "6").get("firstName"), "Trek", "Secondary records found in the store"); }); -test("serialize with embedded objects", function() { +test("serialize with embedded objects (hasMany relationship)", function() { league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); - var tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league }); + var tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -425,7 +441,402 @@ test("serialize with embedded objects", function() { id: get(tom, "id"), first_name: "Tom", last_name: "Dale", - home_planet_id: get(league, "id") + home_planet_id: get(league, "id"), + secret_lab_id: null + }] + }); +}); + +test("serialize with embedded objects (hasMany relationship) supports serialize:no", function() { + league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); + var tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); + + env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: {serialize: 'no'} + } + })); + var serializer = env.container.lookup("serializer:homePlanet"); + + var json = serializer.serialize(league); + + deepEqual(json, { + name: "Villain League", + }); +}); + +test("serialize with (new) embedded objects (hasMany relationship)", function() { + league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); + var superVillain = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league }); + + env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: {embedded: 'always'} + } + })); + var serializer = env.container.lookup("serializer:homePlanet"); + + var json = serializer.serialize(league); + deepEqual(json, { + name: "Villain League", + villains: [{ + first_name: "Tom", + last_name: "Dale", + home_planet_id: get(league, "id"), + secret_lab_id: null }] }); }); + +test("serialize with embedded objects (hasMany relationships, including related objects not embedded)", function() { + superVillain = env.store.createRecord(SuperVillain, { id: 1, firstName: "Super", lastName: "Villian" }); + evilMinion = env.store.createRecord(EvilMinion, { id: 1, name: "Evil Minion", superVillian: superVillain }); + secretWeapon = env.store.createRecord(SecretWeapon, { id: 1, name: "Secret Weapon", superVillain: superVillain }); + superVillain.get('evilMinions').pushObject(evilMinion); + superVillain.get('secretWeapons').pushObject(secretWeapon); + + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + evilMinions: {serialize: 'records', deserialize: 'records'}, + secretWeapons: {serialize: 'ids'} + } + })); + var serializer = env.container.lookup("serializer:superVillain"); + + var json = serializer.serialize(superVillain); + deepEqual(json, { + first_name: get(superVillain, "firstName"), + last_name: get(superVillain, "lastName"), + home_planet_id: null, + evil_minions: [{ + id: get(evilMinion, "id"), + name: get(evilMinion, "name"), + super_villain_id: "1" + }], + secret_lab_id: null, + secret_weapon_ids: [ "1" ] + }); +}); + +test("extractSingle with embedded object (belongsTo relationship)", function() { + expect(4); + env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: {embedded: 'always'} + } + })); + + var serializer = env.container.lookup("serializer:superVillain"); + + var json_hash = { + super_villain: { + id: "1", + first_name: "Tom", + last_name: "Dale", + home_planet_id: "123", + evil_minion_ids: ["1", "2", "3"], + secret_lab: { + minion_capacity: 5000, + vicinity: "California, USA", + id: "101" + }, + secret_weapon_ids: [] + } + }; + + var json = serializer.extractSingle(env.store, SuperVillain, json_hash); + + deepEqual(json, { + "id": "1", + "firstName": "Tom", + "lastName": "Dale", + "homePlanet": "123", + "evilMinions": ["1", "2", "3"], + "secretLab": "101", + "secretWeapons": [] + }); + + env.store.find("secretLab", 101).then(async(function(secretLab) { + equal(secretLab.get('id'), '101'); + equal(secretLab.get('minionCapacity'), 5000); + equal(secretLab.get('vicinity'), 'California, USA'); + })); +}); + +test("serialize with embedded object (belongsTo relationship)", function() { + env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: {embedded: 'always'} + } + })); + var serializer = env.container.lookup("serializer:superVillain"); + + // records with an id, persisted + + var tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + + var json = serializer.serialize(tom); + deepEqual(json, { + first_name: get(tom, "firstName"), + last_name: get(tom, "lastName"), + home_planet_id: get(tom, "homePlanet").get("id"), + secret_lab: { + id: get(tom, "secretLab").get("id"), + minion_capacity: get(tom, "secretLab").get("minionCapacity"), + vicinity: get(tom, "secretLab").get("vicinity") + } + }); +}); + +test("serialize with embedded object (belongsTo relationship) works with different primaryKeys", function() { + env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + primaryKey: '_id', + attrs: { + secretLab: {embedded: 'always'} + } + })); + env.container.register('serializer:secretLab', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + primaryKey: 'crazy_id', + })); + + var serializer = env.container.lookup("serializer:superVillain"); + + // records with an id, persisted + + var tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + + var json = serializer.serialize(tom); + deepEqual(json, { + first_name: get(tom, "firstName"), + last_name: get(tom, "lastName"), + home_planet_id: get(tom, "homePlanet").get("id"), + secret_lab: { + crazy_id: get(tom, "secretLab").get("id"), + minion_capacity: get(tom, "secretLab").get("minionCapacity"), + vicinity: get(tom, "secretLab").get("vicinity") + } + }); +}); + +test("serialize with embedded object (belongsTo relationship, new no id)", function() { + env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: {embedded: 'always'} + } + })); + + var serializer = env.container.lookup("serializer:superVillain"); + + // records without ids, new + + var tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", + secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA" }), + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + + var json = serializer.serialize(tom); + deepEqual(json, { + first_name: get(tom, "firstName"), + last_name: get(tom, "lastName"), + home_planet_id: get(tom, "homePlanet").get("id"), + secret_lab: { + minion_capacity: get(tom, "secretLab").get("minionCapacity"), + vicinity: get(tom, "secretLab").get("vicinity") + } + }); +}); + +test("serialize with embedded object (belongsTo relationship) supports serialize:ids", function() { + env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: {serialize: 'ids'} + } + })); + var serializer = env.container.lookup("serializer:superVillain"); + + // records with an id, persisted + + var tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + + var json = serializer.serialize(tom); + deepEqual(json, { + first_name: get(tom, "firstName"), + last_name: get(tom, "lastName"), + home_planet_id: get(tom, "homePlanet").get("id"), + secret_lab_id: get(tom, "secretLab").get("id"), + }); +}); + +test("serialize with embedded object (belongsTo relationship) supports serialize:id", function() { + env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: {serialize: 'id'} + } + })); + + var serializer = env.container.lookup("serializer:superVillain"); + + // records with an id, persisted + + var tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + + var json = serializer.serialize(tom); + deepEqual(json, { + first_name: get(tom, "firstName"), + last_name: get(tom, "lastName"), + home_planet_id: get(tom, "homePlanet").get("id"), + secret_lab_id: get(tom, "secretLab").get("id"), + }); +}); + +test("serialize with embedded object (belongsTo relationship) supports serialize:no", function() { + env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: {serialize: 'no'} + } + })); + var serializer = env.container.lookup("serializer:superVillain"); + + // records with an id, persisted + + var tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + + var json = serializer.serialize(tom); + deepEqual(json, { + first_name: get(tom, "firstName"), + last_name: get(tom, "lastName"), + home_planet_id: get(tom, "homePlanet").get("id"), + }); +}); + +test("serialize with embedded object (belongsTo relationship) serializes the id by default if no option specified", function() { + env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); + var serializer = env.container.lookup("serializer:superVillain"); + + // records with an id, persisted + + var tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + + var json = serializer.serialize(tom); + deepEqual(json, { + first_name: get(tom, "firstName"), + last_name: get(tom, "lastName"), + home_planet_id: get(tom, "homePlanet").get("id"), + secret_lab_id: get(tom, "secretLab").get("id") + }); +}); + +test("when related record is not present, serialize embedded record (with a belongsTo relationship) as null", function() { + env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: {embedded: 'always'} + } + })); + var serializer = env.container.lookup("serializer:superVillain"); + + var tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", id: "1", + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + + var json = serializer.serialize(tom); + deepEqual(json, { + first_name: get(tom, "firstName"), + last_name: get(tom, "lastName"), + home_planet_id: get(tom, "homePlanet").get("id"), + secret_lab: null + }); +}); + +test("extractSingle with multiply-nested belongsTo", function() { + env.container.register('adapter:evilMinion', DS.ActiveModelAdapter); + env.container.register('serializer:evilMinion', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + superVillain: {embedded: 'always'} + } + })); + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + homePlanet: {embedded: 'always'} + } + })); + + var serializer = env.container.lookup("serializer:evilMinion"); + var json_hash = { + evil_minion: { + id: "1", + name: "Alex", + super_villain: { + id: "1", + first_name: "Tom", + last_name: "Dale", + evil_minion_ids: ["1"], + home_planet: { + id: "1", + name: "Umber", + super_villain_ids: ["1"] + } + } + } + }; + var json = serializer.extractSingle(env.store, EvilMinion, json_hash); + + deepEqual(json, { + id: "1", + name: "Alex", + superVillain: "1" + }, "Primary array was correct"); + + equal(env.store.recordForId("superVillain", "1").get("firstName"), "Tom", "Secondary record, Tom, found in the steore"); + equal(env.store.recordForId("homePlanet", "1").get("name"), "Umber", "Nested Secondary record, Umber, found in the store"); +}); From b7fa9366b6968b79b9a3572e6755ec55fbf968ff Mon Sep 17 00:00:00 2001 From: jondayton Date: Thu, 8 May 2014 13:05:37 -0400 Subject: [PATCH 0148/2527] [Bugfix] when a record which exists in an adapterPopulatedRecordArray is destroyed, it is also now removed from the array @goDownhillFast & @joebartels --- .../lib/system/record_array_manager.js | 3 +- .../adapter_populated_record_array.js | 4 ++ .../adapter_populated_record_array_test.js | 44 +++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 packages/ember-data/tests/unit/adapter_populated_record_array_test.js diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index d6128f49c41..7be5daf82e1 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -224,7 +224,8 @@ var RecordArrayManager = Ember.Object.extend({ type: type, query: query, content: Ember.A(), - store: this.store + store: this.store, + manager: this }); this._adapterPopulatedRecordArrays.push(array); diff --git a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js index cfa77740e49..4d6fea6c5d5 100644 --- a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js @@ -40,6 +40,10 @@ var AdapterPopulatedRecordArray = RecordArray.extend({ meta: meta }); + records.forEach(function(record) { + this.manager.recordArraysForRecord(record).add(this); + }, this); + // TODO: should triggering didLoad event be the last action of the runLoop? Ember.run.once(this, 'trigger', 'didLoad'); } diff --git a/packages/ember-data/tests/unit/adapter_populated_record_array_test.js b/packages/ember-data/tests/unit/adapter_populated_record_array_test.js new file mode 100644 index 00000000000..14b310f4ec2 --- /dev/null +++ b/packages/ember-data/tests/unit/adapter_populated_record_array_test.js @@ -0,0 +1,44 @@ +var get = Ember.get, set = Ember.set; +var indexOf = Ember.EnumerableUtils.indexOf; + +var Person, array, store; + +var adapter = DS.Adapter.extend({ + deleteRecord: function(){ + return Ember.RSVP.Promise.resolve(); + } +}); + +module("unit/adapter_populated_record_array - DS.AdapterPopulatedRecordArray", { + setup: function() { + + store = createStore({ + adapter: adapter + }); + + array = [{ id: '1', name: "Scumbag Dale" }, + { id: '2', name: "Scumbag Katz" }, + { id: '3', name: "Scumbag Bryn" }]; + + Person = DS.Model.extend({ + name: DS.attr('string') + }); + } +}); + +test("when a record is deleted in an adapter populated record array, it should be removed", function() { + var recordArray = store.recordArrayManager + .createAdapterPopulatedRecordArray(Person, null); + + Ember.run(function(){ + recordArray.load(array); + }); + + equal(recordArray.get('length'), 3, "expected recordArray to contain exactly 3 records"); + + Ember.run(function(){ + recordArray.get('firstObject').destroyRecord(); + }) + + equal(recordArray.get('length'), 2, "expected recordArray to contain exactly 2 records"); +}); \ No newline at end of file From d629918245b3b628ed5a5be45c6bb8f6935b672b Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 8 May 2014 14:32:30 -0400 Subject: [PATCH 0149/2527] Setting a filter function on a filteredRecordArray should only cause 1 re-filter per run-loop --- .../system/record_arrays/filtered_record_array.js | 6 +++++- .../ember-data/tests/integration/filter_test.js | 13 ++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/ember-data/lib/system/record_arrays/filtered_record_array.js b/packages/ember-data/lib/system/record_arrays/filtered_record_array.js index c953b63fd36..43b61818d2b 100644 --- a/packages/ember-data/lib/system/record_arrays/filtered_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/filtered_record_array.js @@ -55,9 +55,13 @@ var FilteredRecordArray = RecordArray.extend({ @method updateFilter @private */ - updateFilter: Ember.observer(function() { + _updateFilter: function() { var manager = get(this, 'manager'); manager.updateFilter(this, get(this, 'type'), get(this, 'filterFunction')); + }, + + updateFilter: Ember.observer(function() { + Ember.run.once(this, this._updateFilter); }, 'filterFunction') }); diff --git a/packages/ember-data/tests/integration/filter_test.js b/packages/ember-data/tests/integration/filter_test.js index c468631b361..7649f34706a 100644 --- a/packages/ember-data/tests/integration/filter_test.js +++ b/packages/ember-data/tests/integration/filter_test.js @@ -108,8 +108,10 @@ test("a Record Array can update its filter", function() { shouldNotContain(recordArray, records.bryn); shouldNotContain(recordArray, dickens); - recordArray.set('filterFunction', function(hash) { - if (hash.get('name').match(/Katz/)) { return true; } + Ember.run(function() { + recordArray.set('filterFunction', function(hash) { + if (hash.get('name').match(/Katz/)) { return true; } + }); }); equal(get(recordArray, 'length'), 1, "The Record Array should have one object on it"); @@ -163,8 +165,10 @@ test("a Record Array can update its filter and notify array observers", function recordArray.addArrayObserver(arrayObserver); - recordArray.set('filterFunction', function(hash) { - if (hash.get('name').match(/Katz/)) { return true; } + Ember.run(function() { + recordArray.set('filterFunction', function(hash) { + if (hash.get('name').match(/Katz/)) { return true; } + }); }); Ember.RSVP.all([ asyncDale, asyncKatz, asyncBryn ]).then(async(function() { @@ -437,4 +441,3 @@ test("a Record Array can update its filter after server-side creates multiple re serverResponds(); equal(get(recordArray, 'length'), 5, "The record array updates when the server creates multiple records"); }); - From 6acac713f22d5c45d7a52ce0be7dbf6cb26b9456 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 8 May 2014 17:08:23 -0400 Subject: [PATCH 0150/2527] filteredRecordArray derived from filterFn + query, should retain its query (just as adapterPopulated does) --- .../lib/system/record_array_manager.js | 4 +++- packages/ember-data/lib/system/store.js | 14 ++++++++--- .../tests/integration/filter_test.js | 23 +++++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index 7be5daf82e1..b150e0973db 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -195,10 +195,12 @@ var RecordArrayManager = Ember.Object.extend({ @method createFilteredRecordArray @param {Class} type @param {Function} filter + @param {Object} query (optional @return {DS.FilteredRecordArray} */ - createFilteredRecordArray: function(type, filter) { + createFilteredRecordArray: function(type, filter, query) { var array = FilteredRecordArray.create({ + query: query, type: type, content: Ember.A(), store: this.store, diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 965d8aadb0d..397a6287a64 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -842,9 +842,12 @@ Store = Ember.Object.extend({ */ filter: function(type, query, filter) { var promise; + var length = arguments.length; + var array; + var hasQuery = length === 3; // allow an optional server query - if (arguments.length === 3) { + if (hasQuery) { promise = this.findQuery(type, query); } else if (arguments.length === 2) { filter = query; @@ -852,10 +855,15 @@ Store = Ember.Object.extend({ type = this.modelFor(type); - var array = this.recordArrayManager - .createFilteredRecordArray(type, filter); + if (hasQuery) { + array = this.recordArrayManager.createFilteredRecordArray(type, filter, query); + } else { + array = this.recordArrayManager.createFilteredRecordArray(type, filter); + } + promise = promise || Promise.cast(array); + return promiseArray(promise.then(function() { return array; }, null, "DS: Store#filter of " + type)); diff --git a/packages/ember-data/tests/integration/filter_test.js b/packages/ember-data/tests/integration/filter_test.js index 7649f34706a..84d14f0a140 100644 --- a/packages/ember-data/tests/integration/filter_test.js +++ b/packages/ember-data/tests/integration/filter_test.js @@ -47,6 +47,7 @@ test("when a DS.Model updates its attributes, its changes affect its filtered Ar set(person, 'name', "Yehuda Katz-Foo"); + equal(get(people, 'query'), null, 'expected no query object set'); equal(get(people, 'length'), 0, "there are now no items"); }); @@ -248,6 +249,28 @@ test("a filter created after a record is already loaded works", function() { asyncEqual(filter.objectAt(0), store.find('person', 1)); }); +test("filter with query persists query on the resulting filteredRecordArray", function() { + set(store, 'adapter', DS.Adapter.extend({ + findQuery: function(store, type, id) { + return Ember.RSVP.resolve([{ + id: id, + name: "Tom Dale" + }]); + } + })); + + var filter = store.filter(Person, { foo: 1 }, function(person) { + return true; + }); + + Ember.run(function() { + filter.then(function(array) { + deepEqual(get(array, 'query'), { foo: 1 }, 'has expected query'); + }); + }); +}); + + test("it is possible to filter by state flags", function() { set(store, 'adapter', DS.Adapter.extend({ find: function(store, type, id) { From 488b93dcb19024a272c9bed3e18425ebc2a47fa8 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 9 May 2014 10:13:30 -0400 Subject: [PATCH 0151/2527] Fix publishing of builds. --- .travis.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dcf01158174..0ae97436e49 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ node_js: install: - "bin/cached-npm install" - "bower install" -after_success: npm publish +after_success: npm run-script publish-build env: global: - S3_BUILD_CACHE_BUCKET=emberjs-build-cache diff --git a/package.json b/package.json index b40dd650623..fb9c9a9a2ff 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "scripts": { "postinstall": "bower install", "test": "grunt test:all", - "publish": "grunt dist publish" + "publish-build": "grunt dist publish" }, "devDependencies": { "defeatureify": "~0.1.4", From d700d1b9ca76c1fe69ac5431ab8af7518defff91 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Sat, 10 May 2014 21:16:54 +0900 Subject: [PATCH 0152/2527] [DOC] Fix jsdoc for `Serializer#extractSingle` Now the argument `requestType` is unused. This commit is the part of be797b992 . --- TRANSITION.md | 10 +++++----- .../lib/system/active_model_serializer.js | 2 +- .../lib/system/embedded_records_mixin.js | 3 +-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/TRANSITION.md b/TRANSITION.md index 5ea7a688edd..f5950a9a9c9 100644 --- a/TRANSITION.md +++ b/TRANSITION.md @@ -517,7 +517,7 @@ totally work. ```js App.PostSerializer = DS.RESTSerializer.extend({ - extractSingle: function(store, type, payload, id, requestType) { + extractSingle: function(store, type, payload, id) { var post = {}, commentIds = []; post.id = payload.id; @@ -536,7 +536,7 @@ App.PostSerializer = DS.RESTSerializer.extend({ var post_payload = { post: post, comments: comments }; - return this._super(store, type, post_payload, id, requestType); + return this._super(store, type, post_payload, id); } }); ``` @@ -547,7 +547,7 @@ normalization to do on different pieces of the JSON. ```js App.PostSerializer = DS.RESTSerializer.extend({ - extractSingle: function(store, type, payload, id, requestType) { + extractSingle: function(store, type, payload, id) { var post = {}, commentIds = []; post.id = payload.id; @@ -562,7 +562,7 @@ App.PostSerializer = DS.RESTSerializer.extend({ var post_payload = { post: post, comments: comments }; - return this._super(store, type, post_payload, id, requestType); + return this._super(store, type, post_payload, id); }, normalizeHash: { @@ -800,7 +800,7 @@ You could handle embedded records like this: ```js App.PostSerializer = DS.RESTSerializer.extend({ - extractSingle: function(store, type, payload, id, requestType) { + extractSingle: function(store, type, payload, id) { var comments = payload.post.comments, commentIds = comments.mapProperty('id'); diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index 015243d87c8..bbf8e14ec74 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -140,7 +140,7 @@ var ActiveModelSerializer = RESTSerializer.extend({ Convert `snake_cased` links to `camelCase` @method normalizeLinks - @param {Object} hash + @param {Object} data */ normalizeLinks: function(data){ diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index 0ba8e263ee7..3c86a3f2cf4 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -209,7 +209,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ } }, - /* + /** When serializing an embedded record, modify the property (in the json payload) that refers to the parent record (foreign key for relationship). @@ -288,7 +288,6 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ @param {subclass of DS.Model} primaryType @param {Object} payload @param {String} recordId - @param {'find'|'createRecord'|'updateRecord'|'deleteRecord'} requestType @return Object the primary response to the original request */ extractSingle: function(store, primaryType, payload, recordId) { From 95e1de9feca9bf2f427787965e776129530f6214 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Mon, 12 May 2014 14:30:57 -0400 Subject: [PATCH 0153/2527] Put the initialization docs back with the initializers --- packages/ember-data/lib/ember-initializer.js | 30 ++++++++++++++++++ packages/ember-data/lib/setup-container.js | 33 -------------------- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/packages/ember-data/lib/ember-initializer.js b/packages/ember-data/lib/ember-initializer.js index 03412ae1f63..c9eea9dac3d 100644 --- a/packages/ember-data/lib/ember-initializer.js +++ b/packages/ember-data/lib/ember-initializer.js @@ -4,8 +4,38 @@ var K = Ember.K; /** @module ember-data +*/ + +/** This code initializes Ember-Data onto an Ember application. + + If an Ember.js developer defines a subclass of DS.Store on their application, + as `App.ApplicationStore` (or via a module system that resolves to `store:application`) + this code will automatically instantiate it and make it available on the + router. + + Additionally, after an application's controllers have been injected, they will + each have the store made available to them. + + For example, imagine an Ember.js application with the following classes: + + App.ApplicationStore = DS.Store.extend({ + adapter: 'custom' + }); + + App.PostsController = Ember.ArrayController.extend({ + // ... + }); + + When the application is initialized, `App.ApplicationStore` will automatically be + instantiated, and the instance of `App.PostsController` will have its `store` + property set to that instance. + + Note that this code will only be run if the `ember-application` package is + loaded. If Ember Data is being used in an environment other than a + typical application (e.g., node.js where only `ember-runtime` is available), + this code will be ignored. */ Ember.onLoad('Ember.Application', function(Application) { diff --git a/packages/ember-data/lib/setup-container.js b/packages/ember-data/lib/setup-container.js index dd5b64274ef..c8b05f629ac 100644 --- a/packages/ember-data/lib/setup-container.js +++ b/packages/ember-data/lib/setup-container.js @@ -4,39 +4,6 @@ import initializeStoreInjections from './initializers/store_injections'; import initializeDataAdapter from './initializers/data_adapter'; import setupActiveModelContainer from '../../../activemodel-adapter/lib/setup-container'; -/** - @module ember-data - - This code registers an injection for Ember.Application. - - If an Ember.js developer defines a subclass of DS.Store on their application, - as `App.ApplicationStore` (or via a module system that resolves to `store:application`) - this code will automatically instantiate it and make it available on the - router. - - Additionally, after an application's controllers have been injected, they will - each have the store made available to them. - - For example, imagine an Ember.js application with the following classes: - - App.ApplicationStore = DS.Store.extend({ - adapter: 'custom' - }); - - App.PostsController = Ember.ArrayController.extend({ - // ... - }); - - When the application is initialized, `App.ApplicationStore` will automatically be - instantiated, and the instance of `App.PostsController` will have its `store` - property set to that instance. - - Note that this code will only be run if the `ember-application` package is - loaded. If Ember Data is being used in an environment other than a - typical application (e.g., node.js where only `ember-runtime` is available), - this code will be ignored. -*/ - export default function setupContainer(container, application){ // application is not a required argument. This ensures // testing setups can setup a container without booting an From 92d2ddd454f25b45cf00a0eb9c71d11ac05bbbc2 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Mon, 12 May 2014 14:48:04 -0400 Subject: [PATCH 0154/2527] Update the docs on pushPayload to clarify how model is used --- packages/ember-data/lib/system/store.js | 30 +++++++++++++++++-------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 397a6287a64..d3fbe1a4f50 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -102,7 +102,7 @@ function coerceId(id) { Sockets](http://www.w3.org/TR/2009/WD-websockets-20091222/)). [pushPayload](#method_pushPayload) is a convenience wrapper for - `store#push` that will deserialize payloads if the model's + `store#push` that will deserialize payloads if the Serializer implements a `pushPayload` method. [update](#method_update) works like `push`, except it can handle @@ -1209,13 +1209,9 @@ Store = Ember.Object.extend({ /** Push some raw data into the store. - The data will be automatically deserialized using the - serializer for the `type` param. - This method can be used both to push in brand new - records, as well as to update existing records. - - You can push in more than one type of object at once. + records, as well as to update existing records. You + can push in more than one type of object at once. All objects should be in the format expected by the serializer. @@ -1231,11 +1227,27 @@ Store = Ember.Object.extend({ ] } - store.pushPayload('post', pushData); + store.pushPayload(pushData); + ``` + + By default, the data will be deserialized using a default + serializer (the application serializer if it exists). + + Alternativly, `pushPayload` will accept a model type which + will determine which serializer will process the payload. + However, the serializer itself (processing this data via + `normalizePayload`) will not know which model it is + deserializing. + + ```js + App.ApplicationSerializer = DS.ActiveModelSerializer; + App.PostSerializer = DS.JSONSerializer; + store.pushPayload('comment', pushData); // Will use the ApplicationSerializer + store.pushPayload('post', pushData); // Will use the PostSerializer ``` @method pushPayload - @param {String} type + @param {String} type Optionally, a model used to determine which serializer will be used @param {Object} payload */ pushPayload: function (type, payload) { From 30d5d4ba33ad3772492f13c74c485b266ef6c046 Mon Sep 17 00:00:00 2001 From: Maximilian Tagher Date: Tue, 13 May 2014 13:44:47 -0700 Subject: [PATCH 0155/2527] Use SVG for the Travis badge in the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bfcf3341957..903085df0d9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Ember Data [![Build Status](https://secure.travis-ci.org/emberjs/data.png?branch=master)](http://travis-ci.org/emberjs/data) +## Ember Data [![Build Status](https://secure.travis-ci.org/emberjs/data.svg?branch=master)](http://travis-ci.org/emberjs/data) Ember Data is a library for loading data from a persistence layer (such as a JSON API), mapping this data to a set of models within your client application, From 766f0c9a8cdc8d21b99d80378c01678f8c404aa3 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Fri, 25 Apr 2014 09:39:38 -0400 Subject: [PATCH 0156/2527] [BUGFIX] Normalize typeKeys to always be camelCase typeKeys must have a strong formatting convention, since they are used for comparison in several spots of the code. Prior to this commit: * The container's normalized version of the factory name was set to the typeKey. This leaked the container concerns about name formatting up to Ember-Data, and to the user's interaction with API calls like `find('some-module')` * The typeKey property of a model class was allowed to pass into the code without normalization. In general, for a developer to know which to pick of `find('some-car')`, `find('someCar')` or `find('some_cars')` they had to understand which resolver their container was using. This demonstrates a bad coupling, and makes documenting Ember-Data exceedingly hard (we should not need to mention a caveat about picking a resolver). This commit normalizes typeKeys to always be camelCase, both those returned by `typeForRoot` (for which the documentation has been improved) and for those set on factories by `modelFor`. From here on, `find('someCar')` should be considered the standard format for multi-word model names. --- .../lib/system/active_model_serializer.js | 14 +---- .../lib/serializers/rest_serializer.js | 53 ++++++++++++---- packages/ember-data/lib/system/store.js | 23 ++++++- .../tests/unit/store/create_record_test.js | 60 ++++++++++++++++++- .../tests/unit/store/model_for_test.js | 34 +++++++++-- 5 files changed, 151 insertions(+), 33 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index bbf8e14ec74..afc79cf3a7c 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -78,24 +78,12 @@ var ActiveModelSerializer = RESTSerializer.extend({ if (belongsTo) { key = this.keyForAttribute(key); - json[key + "_type"] = capitalize(camelize(belongsTo.constructor.typeKey)); + json[key + "_type"] = capitalize(belongsTo.constructor.typeKey); } }, // EXTRACT - /** - Extracts the model typeKey from underscored root objects. - - @method typeForRoot - @param {String} root - @return String the model's typeKey - */ - typeForRoot: function(root) { - var camelized = camelize(root); - return singularize(camelized); - }, - /** Add extra step to `DS.RESTSerializer.normalize` so links are normalized. diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index 8865ad92a2e..56326798127 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -7,6 +7,9 @@ var get = Ember.get, set = Ember.set; var forEach = Ember.ArrayPolyfills.forEach; var map = Ember.ArrayPolyfills.map; +import {singularize} from "ember-inflector/lib/system/string"; +var camelize = Ember.String.camelize; + function coerceId(id) { return id == null ? null : id+''; } @@ -579,27 +582,50 @@ var RESTSerializer = JSONSerializer.extend({ }, /** - You can use this method to normalize the JSON root keys returned - into the model type expected by your store. + This method is used to convert each JSON root key in the payload + into a typeKey that it can use to look up the appropriate model for + that part of the payload. By default the typeKey for a model is its + name in camelCase, so if your JSON root key is 'fast-car' you would + use typeForRoot to convert it to 'fastCar' so that Ember Data finds + the `FastCar` model. + + If you diverge from this norm you should also consider changes to + store._normalizeTypeKey as well. + + For example, your server may return prefixed root keys like so: + + ```js + { + "response-fast-car": { + "id": "1", + "name": "corvette" + } + } + ``` - For example, your server may return underscored root keys rather than - the expected camelcased versions. + In order for Ember Data to know that the model corresponding to + the 'response-fast-car' hash is `FastCar` (typeKey: 'fastCar'), + you can override typeForRoot to convert 'response-fast-car' to + 'fastCar' like so: ```js App.ApplicationSerializer = DS.RESTSerializer.extend({ typeForRoot: function(root) { - var camelized = Ember.String.camelize(root); - return Ember.String.singularize(camelized); + // 'response-fast-car' should become 'fast-car' + var subRoot = root.substring(9); + + // _super normalizes 'fast-car' to 'fastCar' + return this._super(subRoot); } }); ``` @method typeForRoot - @param {String} root + @param {String} key @return {String} the model's typeKey */ - typeForRoot: function(root) { - return Ember.String.singularize(root); + typeForRoot: function(key) { + return camelize(singularize(key)); }, // SERIALIZE @@ -752,7 +778,9 @@ var RESTSerializer = JSONSerializer.extend({ /** You can use this method to customize the root keys serialized into the JSON. - By default the REST Serializer sends camelized root keys. + By default the REST Serializer sends the typeKey of a model, whih is a camelized + version of the name. + For example, your server may expect underscored root objects. ```js @@ -771,8 +799,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {Object} options */ serializeIntoHash: function(hash, type, record, options) { - var root = Ember.String.camelize(type.typeKey); - hash[root] = this.serialize(record, options); + hash[type.typeKey] = this.serialize(record, options); }, /** @@ -789,7 +816,7 @@ var RESTSerializer = JSONSerializer.extend({ var key = relationship.key, belongsTo = get(record, key); key = this.keyForAttribute ? this.keyForAttribute(key) : key; - json[key + "Type"] = Ember.String.camelize(belongsTo.constructor.typeKey); + json[key + "Type"] = belongsTo.constructor.typeKey; } }); diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index d3fbe1a4f50..d9e1b184bcc 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -6,6 +6,7 @@ */ import {InvalidError, Adapter} from "./adapter"; +import {singularize} from "ember-inflector/lib/system/string"; var get = Ember.get, set = Ember.set; var once = Ember.run.once; var isNone = Ember.isNone; @@ -16,6 +17,8 @@ var Promise = Ember.RSVP.Promise; var copy = Ember.copy; var Store, PromiseObject, PromiseArray, RecordArrayManager, Model; +var camelize = Ember.String.camelize; + // Implementors Note: // // The variables in this file are consistently named according to the following @@ -1118,10 +1121,13 @@ Store = Ember.Object.extend({ factory = this.container.lookupFactory(normalizedKey); if (!factory) { throw new Ember.Error("No model was found for '" + key + "'"); } - factory.typeKey = normalizedKey.split(':', 2)[1]; + factory.typeKey = this._normalizeTypeKey(normalizedKey.split(':', 2)[1]); } else { - // A factory already supplied. + // A factory already supplied. Ensure it has a normalized key. factory = key; + if (factory.typeKey) { + factory.typeKey = this._normalizeTypeKey(factory.typeKey); + } } factory.store = this; @@ -1512,6 +1518,19 @@ Store = Ember.Object.extend({ function byType(entry) { return map[entry].type; } + }, + + /** + All typeKeys are camelCase internally. Changing this function may + require changes to other normalization hooks (such as typeForRoot). + + @method _normalizeTypeKey + @private + @param {String} type + @return {String} if the adapter can generate one, an ID + */ + _normalizeTypeKey: function(key) { + return camelize(singularize(key)); } }); diff --git a/packages/ember-data/tests/unit/store/create_record_test.js b/packages/ember-data/tests/unit/store/create_record_test.js index 7f16935efa0..75a0d5f3bb9 100644 --- a/packages/ember-data/tests/unit/store/create_record_test.js +++ b/packages/ember-data/tests/unit/store/create_record_test.js @@ -1,5 +1,5 @@ var get = Ember.get, set = Ember.set; -var store, Record; +var store, container, Record; module("unit/store/createRecord - Store creating records", { setup: function() { @@ -18,3 +18,61 @@ test("doesn't modify passed in properties hash", function(){ deepEqual(attributes, { foo: 'bar' }, "The properties hash is not modified"); }); + +module("unit/store/createRecord - Store with models by dash", { + setup: function() { + var env = setupStore({ + 'some-thing': DS.Model.extend({ foo: DS.attr('string') }) + }); + store = env.store; + container = env.container; + container.normalize = function(key){ + return Ember.String.dasherize(key); + }; + } +}); + +test("creating a record by camel-case string finds the model", function(){ + var attributes = { foo: 'bar' }, + record = store.createRecord('someThing', attributes); + + equal(record.get('foo'), attributes.foo, "The record is created"); + equal(store.modelFor('someThing').typeKey, 'someThing'); +}); + +test("creating a record by dasherize string finds the model", function(){ + var attributes = { foo: 'bar' }, + record = store.createRecord('some-thing', attributes); + + equal(record.get('foo'), attributes.foo, "The record is created"); + equal(store.modelFor('some-thing').typeKey, 'someThing'); +}); + +module("unit/store/createRecord - Store with models by camelCase", { + setup: function() { + var env = setupStore({ + 'someThing': DS.Model.extend({ foo: DS.attr('string') }) + }); + store = env.store; + container = env.container; + container.normalize = function(key){ + return Ember.String.camelize(key); + }; + } +}); + +test("creating a record by camel-case string finds the model", function(){ + var attributes = { foo: 'bar' }, + record = store.createRecord('someThing', attributes); + + equal(record.get('foo'), attributes.foo, "The record is created"); + equal(store.modelFor('someThing').typeKey, 'someThing'); +}); + +test("creating a record by dasherize string finds the model", function(){ + var attributes = { foo: 'bar' }, + record = store.createRecord('some-thing', attributes); + + equal(record.get('foo'), attributes.foo, "The record is created"); + equal(store.modelFor('some-thing').typeKey, 'someThing'); +}); diff --git a/packages/ember-data/tests/unit/store/model_for_test.js b/packages/ember-data/tests/unit/store/model_for_test.js index 8cf4fb30ca4..88dc74a4e8e 100644 --- a/packages/ember-data/tests/unit/store/model_for_test.js +++ b/packages/ember-data/tests/unit/store/model_for_test.js @@ -1,8 +1,14 @@ var container, store; +var camelize = Ember.String.camelize, + dasherize = Ember.String.dasherize; + module("unit/store/model_for - DS.Store#modelFor", { setup: function() { - store = createStore({blogPost: DS.Model.extend()}); + store = createStore({ + blogPost: DS.Model.extend(), + "blog-post": DS.Model.extend() + }); container = store.container; }, @@ -12,10 +18,30 @@ module("unit/store/model_for - DS.Store#modelFor", { } }); -test("sets a normalized key as typeKey", function() { +test("when fetching factory from string, sets a normalized key as typeKey", function() { + container.normalize = function(fullName){ + return camelize(fullName); + }; + + equal(container.normalize('some.post'), 'somePost', 'precond - container camelizes'); + equal(store.modelFor("blog.post").typeKey, "blogPost", "typeKey is normalized to camelCase"); +}); + +test("when fetching factory from string and dashing normalizer, sets a normalized key as typeKey", function() { container.normalize = function(fullName){ - return Ember.String.camelize(fullName); + return dasherize(camelize(fullName)); }; - ok(store.modelFor("blog.post").typeKey, "blogPost", "typeKey is normalized"); + equal(container.normalize('some.post'), 'some-post', 'precond - container dasherizes'); + equal(store.modelFor("blog.post").typeKey, "blogPost", "typeKey is normalized to camelCase"); +}); + +test("when returning passed factory, sets a normalized key as typeKey", function() { + var factory = {typeKey: 'some-thing'}; + equal(store.modelFor(factory).typeKey, "someThing", "typeKey is normalized to camelCase"); +}); + +test("when returning passed factory without typeKey, allows it", function() { + var factory = {typeKey: undefined}; + equal(store.modelFor(factory).typeKey, undefined, "typeKey is undefined"); }); From 503a42f742cceb21e4e00003bd1b2f3f170ee1e3 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Tue, 13 May 2014 22:48:14 -0400 Subject: [PATCH 0157/2527] normalizePayload only gets the payload normalizePayload has been living a lie. It claims to be passed the model type when called, but in often does not receive this argument (null is passed instead). This only serves to confuse the use-case for normalizePayload, and encourage its use when overriding an extraction helper is actually the right choice. This tradeoff, dropping the argument of type in all cases, means normalizePayload can still be run over data added with pushPayload. pushPayload knows nothing of which model is being pushed, and thus cannot provide the type reliably. --- CHANGELOG.md | 1 + .../lib/serializers/rest_serializer.js | 12 +++--- .../serializers/rest_serializer_test.js | 38 ++++++++++++++----- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a87b7d40ce..1e634736a4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Master +* Drop the `type` argument from `normalizePayload` calls. This argument was not consistently passed. Overridding the `extract` functions on the serializer is a suggested alternative if you require the model type. * Introduce `DS._setupContainer()` for use in testing * Deprecate the 5 Ember initializers, use just one named "ember-data" diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index 8865ad92a2e..ad3993edfb9 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -187,7 +187,7 @@ var RESTSerializer = JSONSerializer.extend({ ```js App.ApplicationSerializer = DS.RESTSerializer.extend({ - normalizePayload: function(type, payload) { + normalizePayload: function(payload) { delete payload.version; delete payload.status; return payload; @@ -196,11 +196,10 @@ var RESTSerializer = JSONSerializer.extend({ ``` @method normalizePayload - @param {subclass of DS.Model} type @param {Object} payload @return {Object} the normalized payload */ - normalizePayload: function(type, payload) { + normalizePayload: function(payload) { return payload; }, @@ -351,8 +350,7 @@ var RESTSerializer = JSONSerializer.extend({ @return {Object} the primary response to the original request */ extractSingle: function(store, primaryType, payload, recordId) { - payload = this.normalizePayload(primaryType, payload); - + payload = this.normalizePayload(payload); var primaryTypeName = primaryType.typeKey, primaryRecord; @@ -496,7 +494,7 @@ var RESTSerializer = JSONSerializer.extend({ to the original query. */ extractArray: function(store, primaryType, payload) { - payload = this.normalizePayload(primaryType, payload); + payload = this.normalizePayload(payload); var primaryTypeName = primaryType.typeKey, primaryArray; @@ -562,7 +560,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {Object} payload */ pushPayload: function(store, payload) { - payload = this.normalizePayload(null, payload); + payload = this.normalizePayload(payload); for (var prop in payload) { var typeName = this.typeForRoot(prop), diff --git a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js index 27fcf55a20c..48cd88dc23e 100644 --- a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js @@ -54,12 +54,12 @@ test("extractArray with custom typeForRoot", function() { return Ember.String.singularize(camelized); }; - var json_hash = { + var jsonHash = { home_planets: [{id: "1", name: "Umber", superVillains: [1]}], super_villains: [{id: "1", firstName: "Tom", lastName: "Dale", homePlanet: "1"}] }; - var array = env.restSerializer.extractArray(env.store, HomePlanet, json_hash); + var array = env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); deepEqual(array, [{ "id": "1", @@ -78,13 +78,13 @@ test("extractArray failure with custom typeForRoot", function() { return Ember.String.singularize(root); }; - var json_hash = { + var jsonHash = { home_planets: [{id: "1", name: "Umber", superVillains: [1]}], super_villains: [{id: "1", firstName: "Tom", lastName: "Dale", homePlanet: "1"}] }; raises(function(){ - env.restSerializer.extractArray(env.store, HomePlanet, json_hash); + env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); }, "No model was found for 'home_planets'", "raised error message expected to contain \"No model was found for 'home_planets'\""); }); @@ -112,8 +112,26 @@ test("serialize polymorphicType with decamelized typeKey", function() { deepEqual(json["evilMinionType"], "yellowMinion"); }); +test("normalizePayload is called during extractSingle", function() { + env.container.register('serializer:application', DS.RESTSerializer.extend({ + normalizePayload: function(payload) { + return payload.response; + } + })); + + var jsonHash = { response: { + evilMinion: {id: "1", name: "Tom Dale", superVillain: 1}, + superVillains: [{id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1"}] + } }; + + var applicationSerializer = env.container.lookup('serializer:application'); + var data = applicationSerializer.extractSingle(env.store, EvilMinion, jsonHash); + + equal(data.name, jsonHash.response.evilMinion.name, "normalize reads off the response"); +}); + test("extractArray can load secondary records of the same type without affecting the query count", function() { - var json_hash = { + var jsonHash = { comments: [{id: "1", body: "Parent Comment", root: true, children: [2, 3]}], _comments: [ { id: "2", body: "Child Comment 1", root: false }, @@ -121,7 +139,7 @@ test("extractArray can load secondary records of the same type without affecting ] }; - var array = env.restSerializer.extractArray(env.store, Comment, json_hash); + var array = env.restSerializer.extractArray(env.store, Comment, jsonHash); deepEqual(array, [{ "id": "1", @@ -146,12 +164,12 @@ test("extractSingle loads secondary records with correct serializer", function() } })); - var json_hash = { + var jsonHash = { evilMinion: {id: "1", name: "Tom Dale", superVillain: 1}, superVillains: [{id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1"}] }; - var array = env.restSerializer.extractSingle(env.store, EvilMinion, json_hash); + var array = env.restSerializer.extractSingle(env.store, EvilMinion, jsonHash); equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); }); @@ -166,12 +184,12 @@ test("extractArray loads secondary records with correct serializer", function() } })); - var json_hash = { + var jsonHash = { evilMinions: [{id: "1", name: "Tom Dale", superVillain: 1}], superVillains: [{id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1"}] }; - var array = env.restSerializer.extractArray(env.store, EvilMinion, json_hash); + var array = env.restSerializer.extractArray(env.store, EvilMinion, jsonHash); equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); }); From 2361fe283bb8e175fe770a9c736d228c6e054cce Mon Sep 17 00:00:00 2001 From: Mehul Kar Date: Wed, 14 May 2014 12:55:14 -0700 Subject: [PATCH 0158/2527] Add a base fiddle for mocked data requests with Ember Data --- CONTRIBUTING.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fd23b558f61..12b83c63f6f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,10 @@ this bug already. 3. Provide JSFiddle or JSBin demo that specifically shows the problem. This demo should be fully operational with the exception of the bug you want to -demonstrate. The more pared down, the better. +demonstrate. The more pared down, the better. A preconfigured JSFiddle with +mocked requests is available [here][1]. + +[1]: http://jsfiddle.net/mehulkar/Q5NPs/ 4. If possible, submit a Pull Request with a failing test. Better yet, take a stab at fixing the bug yourself if you can! From 228acc2f5fa6e4dfd8926d49b5192bb8415aef3c Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 14 May 2014 16:16:35 -0700 Subject: [PATCH 0159/2527] Removed unused resolver from ManyArray.fetch --- packages/ember-data/lib/system/record_arrays/many_array.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index f8d718eb154..ee273f2f5c9 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -119,11 +119,10 @@ var ManyArray = RecordArray.extend({ fetch: function() { var records = get(this, 'content'), store = get(this, 'store'), - owner = get(this, 'owner'), - resolver = Ember.RSVP.defer("DS: ManyArray#fetch " + get(this, 'type')); + owner = get(this, 'owner'); var unloadedRecords = records.filterProperty('isEmpty', true); - store.fetchMany(unloadedRecords, owner, resolver); + store.fetchMany(unloadedRecords, owner); }, // Overrides Ember.Array's replace method to implement From e2aab477b3b406cac4affdbde5421b3d0f876179 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Sat, 17 May 2014 12:37:44 -0400 Subject: [PATCH 0160/2527] Do not cache model factories on meta, or on other model CPs Relationships are hard. Ember-Data has been storing data about a relationship on the meta value for that CP. CPs hang around though, and as a result that data on the meta becomes a cache. For some details about a relationship, this is fine. If User has many Posts, and you use User via a container, it would cache a reference to the Post factory. But if you then destroy that container, the reference to Post still exists in the CP meta. Furthermore, if you create a new container and use User and Post via that new container, the cache factory value for Post will be that of the old container and not the new container. This only is a problem if you expect to have Post be a different factory in each container. In ember-cli, MODEL_FACTORY_INJECTIONS are enabled. This means all factories are extended before being returned by the container. So every time you have a new container, you have a new factory (though it looks and behaves the same). This change gets rid of that cache on meta. Instead it creates a function that accepts the store and meta, and returns the relationship object expected throughout Ember-Data. Two alternatives were considered: 1. Always check against typeKey instead of instanceof, but this felt like a dodge of the real problem and would leave the issue for others to find, or 2. Create a new first-class relationship object, but this would be a far more invasive change, and would impact much of the codebase that the current relationship object has already leaked through. Additionally, the types were being cached on model class-level CPs. For this patch, those have simply been marked cacheable(false). A later patch should refactor the CPs out of the way, or at least re-write their consumers to expect a relationship object without the factory itself already fetched. --- .../lib/system/relationship-meta.js | 28 +++++++++++++ .../lib/system/relationships/belongs_to.js | 10 +++-- .../lib/system/relationships/ext.js | 39 ++++++------------- .../lib/system/relationships/has_many.js | 12 ++++-- .../relationships/belongs_to_test.js | 36 +++++++++++++++++ 5 files changed, 91 insertions(+), 34 deletions(-) create mode 100644 packages/ember-data/lib/system/relationship-meta.js diff --git a/packages/ember-data/lib/system/relationship-meta.js b/packages/ember-data/lib/system/relationship-meta.js new file mode 100644 index 00000000000..cd4904f8b87 --- /dev/null +++ b/packages/ember-data/lib/system/relationship-meta.js @@ -0,0 +1,28 @@ +import {singularize} from "../../../ember-inflector/lib/system"; + +export function typeForRelationshipMeta(store, meta) { + var typeKey, type; + + typeKey = meta.type || meta.key; + if (typeof typeKey === 'string') { + if (meta.kind === 'hasMany') { + typeKey = singularize(typeKey); + } + type = store.modelFor(typeKey); + } else { + type = meta.type; + } + + return type; +} + +export function relationshipFromMeta(store, meta) { + return { + key: meta.key, + kind: meta.kind, + type: typeForRelationshipMeta(store, meta), + options: meta.options, + parentType: meta.parentType, + isRelationship: true + }; +} diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index e9bc7d35e26..298b801997f 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -6,6 +6,7 @@ var Promise = Ember.RSVP.Promise; import {Model} from "../model"; import {PromiseObject} from "../store"; import {RelationshipChange} from "../changes"; +import {relationshipFromMeta, typeForRelationshipMeta} from "../relationship-meta"; /** @module ember-data @@ -18,8 +19,10 @@ function asyncBelongsTo(type, options, meta) { promiseLabel = "DS: Async belongsTo " + this + " : " + key, promise; + meta.key = key; + if (arguments.length === 2) { - Ember.assert("You can only add a '" + type + "' record to this relationship", !value || value instanceof store.modelFor(type)); + Ember.assert("You can only add a '" + type + "' record to this relationship", !value || value instanceof typeForRelationshipMeta(store, meta)); return value === undefined ? null : PromiseObject.create({ promise: Promise.cast(value, promiseLabel) }); @@ -34,7 +37,7 @@ function asyncBelongsTo(type, options, meta) { promise: promise }); } else if (link) { - promise = store.findBelongsTo(this, link, meta); + promise = store.findBelongsTo(this, link, relationshipFromMeta(store, meta)); return PromiseObject.create({ promise: promise }); @@ -105,7 +108,8 @@ function belongsTo(type, options) { type: type, isRelationship: true, options: options, - kind: 'belongsTo' + kind: 'belongsTo', + key: null }; if (options.async) { diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 06056c13da3..166fbf68e22 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -1,4 +1,5 @@ import {singularize} from "../../../../ember-inflector/lib/system"; +import {typeForRelationshipMeta, relationshipFromMeta} from "../relationship-meta"; import {Model} from "../model"; var get = Ember.get, set = Ember.set; @@ -198,18 +199,15 @@ Model.reopenClass({ // If the computed property is a relationship, add // it to the map. if (meta.isRelationship) { - if (typeof meta.type === 'string') { - meta.type = this.store.modelFor(meta.type); - } - - var relationshipsForType = map.get(meta.type); + meta.key = name; + var relationshipsForType = map.get(typeForRelationshipMeta(this.store, meta)); relationshipsForType.push({ name: name, kind: meta.kind }); } }); return map; - }), + }).cacheable(false), /** A hash containing lists of the model's relationships, grouped @@ -289,11 +287,8 @@ Model.reopenClass({ // in relationships this.eachComputedProperty(function(name, meta) { if (meta.isRelationship) { - type = meta.type; - - if (typeof type === 'string') { - type = get(this, type, false) || this.store.modelFor(type); - } + meta.key = name; + type = typeForRelationshipMeta(this.store, meta); Ember.assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", type); @@ -305,7 +300,7 @@ Model.reopenClass({ }); return types; - }), + }).cacheable(false), /** A map whose keys are the relationships of a model and whose values are @@ -339,29 +334,19 @@ Model.reopenClass({ @readOnly */ relationshipsByName: Ember.computed(function() { - var map = Ember.Map.create(), type; + var map = Ember.Map.create(); this.eachComputedProperty(function(name, meta) { if (meta.isRelationship) { meta.key = name; - type = meta.type; - - if (!type && meta.kind === 'hasMany') { - type = singularize(name); - } else if (!type) { - type = name; - } - - if (typeof type === 'string') { - meta.type = this.store.modelFor(type); - } - - map.set(name, meta); + var relationship = relationshipFromMeta(this.store, meta); + relationship.type = typeForRelationshipMeta(this.store, meta); + map.set(name, relationship); } }); return map; - }), + }).cacheable(false), /** A map whose keys are the fields of the model and whose values are strings diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index 83ad05a81e2..b8835ce63c0 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -4,21 +4,24 @@ import {PromiseArray} from "../store"; var get = Ember.get, set = Ember.set, setProperties = Ember.setProperties; +import {relationshipFromMeta, typeForRelationshipMeta} from "../relationship-meta"; function asyncHasMany(type, options, meta) { return Ember.computed('data', function(key) { var relationship = this._relationships[key], promiseLabel = "DS: Async hasMany " + this + " : " + key; + meta.key = key; + if (!relationship) { var resolver = Ember.RSVP.defer(promiseLabel); relationship = buildRelationship(this, key, options, function(store, data) { var link = data.links && data.links[key]; var rel; if (link) { - rel = store.findHasMany(this, link, meta, resolver); + rel = store.findHasMany(this, link, relationshipFromMeta(store, meta), resolver); } else { - rel = store.findMany(this, data[key], meta.type, resolver); + rel = store.findMany(this, data[key], typeForRelationshipMeta(store, meta), resolver); } // cache the promise so we can use it // when we come back and don't need to rebuild @@ -62,7 +65,8 @@ function hasRelationship(type, options) { type: type, isRelationship: true, options: options, - kind: 'hasMany' + kind: 'hasMany', + key: null }; if (options.async) { @@ -73,7 +77,7 @@ function hasRelationship(type, options) { return buildRelationship(this, key, options, function(store, data) { var records = data[key]; Ember.assert("You looked up the '" + key + "' relationship on '" + this + "' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", Ember.A(records).everyProperty('isEmpty', false)); - return store.findMany(this, data[key], meta.type); + return store.findMany(this, data[key], typeForRelationshipMeta(store, meta)); }); }).meta(meta).readOnly(); } diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index 1c71291764b..cbbcea19986 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -251,3 +251,39 @@ test("TODO (embedded): The store can serialize an embedded polymorphic belongsTo //equal(serialized.favourite_message.id, 1); //equal(serialized.favourite_message.embeddedType, 'comment'); }); + +test("relationshipsByName does not cache a factory", function() { + + // The model is loaded up via a container. It has relationshipsByName + // called on it. + var modelViaFirstFactory = store.modelFor('user'); + get(modelViaFirstFactory, 'relationshipsByName'); + + // An app is reset, or the container otherwise destroyed. + env.container.destroy(); + + // A new model for a relationship is created. Note that this may happen + // due to an extend call internal to MODEL_FACTORY_INJECTIONS. + NewMessage = Message.extend(); + NewMessage.toString = stringify('Message'); + + // A new store is created. + env = setupStore({ + user: User, + message: NewMessage + }); + store = env.store; + + // relationshipsByName is called again. + var modelViaSecondFactory = store.modelFor('user'), + relationshipsByName = get(modelViaSecondFactory, 'relationshipsByName'), + messageType = relationshipsByName.get('messages').type; + + // A model is looked up in the store based on a string, via user input + var messageModelFromStore = store.modelFor('message'); + // And the model is lookup up internally via the relationship type + var messageModelFromRelationType = store.modelFor(messageType); + + equal( messageModelFromRelationType, messageModelFromStore, + "model factory based on relationship type matches the model based on store.modelFor" ); +}); From 07760a5383475be0bd143d4ea1d4bd1ba295d1f4 Mon Sep 17 00:00:00 2001 From: Miguel Madero Date: Fri, 25 Oct 2013 14:34:23 -0700 Subject: [PATCH 0161/2527] Makes sure extractArray is normalizing each record in the array instead of trying to normalize the whole payload as an object. This was causing `applyTransforms` to do the transforms in properties of the array instead. --- .../lib/serializers/json_serializer.js | 10 +++++++--- .../serializers/json_serializer_test.js | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index a06a103ec6a..648dbb2e676 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -1,5 +1,6 @@ import {RelationshipChange} from "../system/changes"; -var get = Ember.get, set = Ember.set, isNone = Ember.isNone; +var get = Ember.get, set = Ember.set, isNone = Ember.isNone, + map = Ember.ArrayPolyfills.map; /** In Ember Data a Serializer is used to serialize and deserialize @@ -649,8 +650,11 @@ var JSONSerializer = Ember.Object.extend({ @param {Object} payload @return {Array} array An array of deserialized objects */ - extractArray: function(store, type, payload) { - return this.normalize(type, payload); + extractArray: function(store, type, arrayPayload) { + var serializer = this; + return map.call(arrayPayload, function(singlePayload) { + return serializer.normalize(type, singlePayload); + }); }, /** diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index ddfe9b8a915..9ea7b3a3c7f 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -112,3 +112,22 @@ test("serializePolymorphicType", function() { postTYPE: "post" }); }); + + +test("extractArray normalizes each record in the array", function() { + var postNormalizeCount = 0; + var posts = [ + { title: "Rails is omakase"}, + { title: "Another Post"} + ]; + + env.container.register('serializer:post', DS.JSONSerializer.extend({ + normalize: function () { + postNormalizeCount++; + return this._super.apply(this, arguments); + } + })); + + env.container.lookup("serializer:post").extractArray(env.store, Post, posts); + equal(postNormalizeCount, 2, "two posts are normalized"); +}); From 3027fcb6f4d13921152ff3d5d0f11181147be47b Mon Sep 17 00:00:00 2001 From: Bill Heaton Date: Fri, 14 Feb 2014 15:07:20 -0800 Subject: [PATCH 0162/2527] Use keyForRelationship in JSONSerializer's serializeHasMany method - serializeBelongsTo uses the same already --- .../lib/serializers/json_serializer.js | 4 ++-- .../serializers/json_serializer_test.js | 20 ++++++++++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 37c4120eae1..2760b025716 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -381,11 +381,11 @@ var JSONSerializer = Ember.Object.extend({ */ serializeHasMany: function(record, json, relationship) { var key = relationship.key; - + var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, "hasMany") : key; var relationshipType = RelationshipChange.determineRelationshipType(record.constructor, relationship); if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') { - json[key] = get(record, key).mapBy('id'); + json[payloadKey] = get(record, key).mapBy('id'); // TODO support for polymorphic manyToNone and manyToMany relationships } }, diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index ddfe9b8a915..b532cb50bff 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -4,7 +4,8 @@ var Post, post, Comment, comment, env; module("integration/serializer/json - JSONSerializer", { setup: function() { Post = DS.Model.extend({ - title: DS.attr('string') + title: DS.attr('string'), + comments: DS.hasMany('comment', {inverse:null}) }); Comment = DS.Model.extend({ body: DS.attr('string'), @@ -92,6 +93,23 @@ test("serializeBelongsTo respects keyForRelationship", function() { }); }); +test("serializeHasMany respects keyForRelationship", function() { + env.container.register('serializer:post', DS.JSONSerializer.extend({ + keyForRelationship: function(key, type) { + return key.toUpperCase(); + } + })); + post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1"}); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post, id: "1"}); + var json = {}; + + env.container.lookup("serializer:post").serializeHasMany(post, json, {key: "comments", options: {}}); + + deepEqual(json, { + COMMENTS: ["1"] + }); +}); + test("serializePolymorphicType", function() { env.container.register('serializer:comment', DS.JSONSerializer.extend({ serializePolymorphicType: function(record, json, relationship) { From a1d7135d18d4a2aa496dd4e4cccb6367fba5cf36 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 14 May 2014 16:44:21 -0700 Subject: [PATCH 0163/2527] [BUGFIX] store.fetchMany should always return a promise. --- packages/ember-data/lib/system/store.js | 4 +++- .../tests/unit/store/adapter_interop_test.js | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index d3fbe1a4f50..4c88cb409cc 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -518,7 +518,9 @@ Store = Ember.Object.extend({ @return {Promise} promise */ fetchMany: function(records, owner) { - if (!records.length) { return; } + if (!records.length) { + return Ember.RSVP.resolve(records); + } // Group By Type var recordsByTypeMap = Ember.MapWithDefault.create({ diff --git a/packages/ember-data/tests/unit/store/adapter_interop_test.js b/packages/ember-data/tests/unit/store/adapter_interop_test.js index fb5efa11c44..e81edcb082a 100644 --- a/packages/ember-data/tests/unit/store/adapter_interop_test.js +++ b/packages/ember-data/tests/unit/store/adapter_interop_test.js @@ -306,6 +306,22 @@ test("records inside a collection view should have their ids updated", function( })); }); +test("store.fetchMany should always return a promise", function() { + var Person = DS.Model.extend(); + var store = createStore({ + adapter: TestAdapter.extend() + }); + var owner = store.createRecord(Person); + var records = Ember.A([]); + + var results = store.fetchMany(records, owner); + ok(results, "A call to store.fetchMany() should return a result"); + ok(results.then, "A call to store.fetchMany() should return a promise"); + + results.then(async(function(returnedRecords) { + equal(returnedRecords, records, "The empty record sets should match"); + })); +}); test("store.fetchMany should not resolve until all the records are resolve", function() { var Person = DS.Model.extend(); From 07d93115f08f096e4b21da2fa7dee9df22cff212 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Sun, 18 May 2014 14:51:20 +0900 Subject: [PATCH 0164/2527] Add package.json to built gem `Ember::Data::VERSION` is defined by `package.json` since 7d7ccfa44. Without thi file, ember-data-source couldn't resolve own version. --- ember-data-source.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ember-data-source.gemspec b/ember-data-source.gemspec index 827eccd53aa..67ad870b5a4 100644 --- a/ember-data-source.gemspec +++ b/ember-data-source.gemspec @@ -14,5 +14,5 @@ Gem::Specification.new do |gem| gem.add_dependency "ember-source" - gem.files = Dir['dist/ember-data*.js', 'lib/ember/data/*.rb'] + gem.files = %w(package.json) + Dir['dist/ember-data*.js', 'lib/ember/data/*.rb'] end From db4febb497934bd51cc6496516928ae8c82006ce Mon Sep 17 00:00:00 2001 From: Tom Dale Date: Mon, 19 May 2014 10:32:47 +0100 Subject: [PATCH 0165/2527] Update README --- README.md | 175 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 142 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 903085df0d9..234e0034f4a 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,164 @@ ## Ember Data [![Build Status](https://secure.travis-ci.org/emberjs/data.svg?branch=master)](http://travis-ci.org/emberjs/data) -Ember Data is a library for loading data from a persistence layer (such as -a JSON API), mapping this data to a set of models within your client application, -updating those models, then saving the changes back to a persistence layer. It -provides many of the facilities you'd find in server-side ORMs like ActiveRecord, but is -designed specifically for the unique environment of JavaScript in the browser. +Ember Data is a library for robustly managing model data in your +Ember.js applications. -Ember Data provides a central Data Store, which can be configured with a range of -provided Adapters, but two core Adapters are provided: the RESTAdapter and FixtureAdapter. +Ember Data is designed to be agnostic to the underlying persistence +mechanism, so it works just as well with JSON APIs over HTTP as it does +with streaming WebSockets or local IndexedDB storage. -The RESTAdapter is configured for use by default. You can read more about it in -the [Guides](http://emberjs.com/guides/models/connecting-to-an-http-server/). It provides a fully -RESTful mechanism for communicating with your persistence layer, and is the preferred -and recommended choice for use with Ember Data. +It provides many of the facilities you'd find in server-side ORMs like +ActiveRecord, but is designed specifically for the unique environment of +JavaScript in the browser. -This is definitely alpha-quality. The basics of RESTAdapter work, but there are for -sure edge cases that are not yet handled. Please report any bugs or feature -requests, and pull requests are always welcome. +In particular, Ember Data uses Promises/A+-compatible promises from the +ground up to manage loading and saving records, so integrating with +other JavaScript APIs is easy. -#### Is It Good? +## Using Ember Data -Yes. +### Getting Ember Data -#### Is It "Production Ready™"? +```no-highlight +bower install ember-data --save +``` -No. The API should not be considered stable until 1.0. Breaking changes, -and how to update accordingly, are listed in [`TRANSITION.md`](https://github.com/emberjs/data/blob/master/TRANSITION.md). +The latest passing build from the "master" branch is available on +[http://emberjs.com/builds/#/canary](http://emberjs.com/builds/#/canary). -A [guide is provided on the Ember.js site](http://emberjs.com/guides/models/) that is accurate as of Ember Data 1.0 beta. +Similarly the latest passing build from the "beta" branch can be found +on [http://emberjs.com/builds/#/beta](http://emberjs.com/builds/#/beta) -#### Getting ember-data +You also have the option to build ember-data.js yourself. Clone the +repository, run `grunt buildPackages` after [setup](#setup). You'll find +ember-data.js in the `dist` directory. -```no-highlight -bower install ember-data --save +### Instantiating the Store + +In Ember Data, the _store_ is responsible for managing the lifecycle of +your models. Every time you need a model or a collection of models, +you'll ask the store for it. + +To create a store, you don't need to do anything. Just by loading the +Ember Data library, all of the routes and controllers in your +application will get a new `store` property. This property is an +instance of `DS.Store` that will be shared across all of the routes and +controllers in your app. + +### Defining Your Models + +First thing's first: tell Ember Data about the models in your +application. For example, imagine we're writing a blog reader app. +Here's what your model definition would look like if you're using +globals (that is, not something like Ember App Kit or ember-cli): + +```js +var attr = DS.attr, + hasMany = DS.hasMany, + belongsTo = DS.belongsTo; + +App.BlogPost = DS.Model.extend({ + title: attr(), + createdAt: attr('date'), + + comments: hasMany('comment') +}); + +App.Comment = DS.Model.extend({ + body: attr(), + username: attr(), + + post: belongsTo('blogPost') +}); +``` + +If you're using ES6 modules (via Ember App Kit or ember-cli), your +models would look like this: + +```js +// app/models/blog-post.js +var attr = DS.attr, + hasMany = DS.hasMany; + +export default DS.Model.extend({ + title: attr(), + createdAt: attr('date'), + + comments: hasMany('comment') +}); + +// app/models/comment.js +var attr = DS.attr, + belongsTo = DS.belongsTo; + +export default DS.Model.extend({ + body: attr(), + username: attr(), + + post: belongsTo('blogPost') +}); +``` + +### A Brief Note on Adapters + +Without immediately diving in to the depths of the architecture, one +thing you _should_ know is that Ember Data uses an object called an +_adapter_ to know how to talk to your server. + +An adapter is just an object that knows how to translate requests from +Ember Data into requests on your server. For example, if I ask the Ember +Data store for a record of type `person` with an ID of `123`, the +adapter translates that into an XHR request to (for example) +`api.example.com/v3/person/123.json`. + +By default, Ember Data will use the `RESTAdapter`, which adheres to a +set of RESTful JSON conventions. + +Ember Data also ships with the `FixtureAdapter`, useful for testing and +prototyping before you have a server, and the `ActiveModelAdapter`, +which is designed to work out-of-the-box with the +[`ActiveModel::Serializers`](https://github.com/rails-api/active_model_serializers) +gem for Rails. + +To learn more about adapters, including what conventions the +`RESTAdapter` follows and how to build your own, see the Ember.js +Guides: [Connecting to an HTTP +Server](http://emberjs.com/guides/models/connecting-to-an-http-server/). + +### Fetching a Collection of Models + +From your route or controller: + +```js +this.store.find('blogPost'); +``` + +This returns a promise that resolves to the collection of records. + +### Fetching a Single Model + +```js +this.store.find('blogPost', 123); ``` -The latest passing build from the "master" branch is available on [http://emberjs.com/builds/#/canary](http://emberjs.com/builds/#/canary). +This returns a promise that resolves to the requested record. If the +record can't be found or there was an error during the request, the +promise will be rejected. -Similarly the latest passing build from the "beta" branch can be found on [http://emberjs.com/builds/#/beta](http://emberjs.com/builds/#/beta) +### Even More Documentation +For much more detail on how to use Ember Data, see the [Ember.js Guides +on models](http://emberjs.com/guides/models/). -You also have the option to build ember-data.js yourself. Clone the repository, run `grunt buildPackages` after [setup](#setup). You'll find ember-data.js in the `dist` directory. +## API Stability -#### Roadmap +Ember Data is still under active development and is currently beta +quality. That being said, the API has largely stabilized and many +companies are using it in production. -* Handle error states -* Better built-in attributes -* Editing "forked" records -* Out-of-the-box support for Rails apps that follow the - [`active_model_serializers`](https://github.com/rails-api/active_model_serializers) gem's conventions. -* Handle partially-loaded records +For details on anticipated changes before the 1.0 release, see the blog +post [The Road to Ember Data +1.0](http://emberjs.com/blog/2014/03/18/the-road-to-ember-data-1-0.html). ## How to Run Unit Tests From a994c5eef2db4c59f83f3dbcb9fca751cfe05951 Mon Sep 17 00:00:00 2001 From: Matthew Beale Date: Wed, 14 May 2014 11:04:14 -0400 Subject: [PATCH 0166/2527] Do not presume returned data arrays support .pushObjects Returned data will cannot be assumed to be an Ember array object. A test should not pass in an Ember array as API response data. --- packages/ember-data/lib/system/store.js | 2 +- .../ember-data/tests/integration/adapter/store_adapter_test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index af68f396790..1691f5239df 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1577,7 +1577,7 @@ function deserializeRecordIds(store, data, key, relationship, ids) { // in the payload, so add them back in manually. function addUnsavedRecords(record, key, data) { if(record) { - data.pushObjects(record.get(key).filterBy('isNew')); + Ember.A(data).pushObjects(record.get(key).filterBy('isNew')); } } diff --git a/packages/ember-data/tests/integration/adapter/store_adapter_test.js b/packages/ember-data/tests/integration/adapter/store_adapter_test.js index bf5e25aa0a5..e65b3236f4b 100644 --- a/packages/ember-data/tests/integration/adapter/store_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/store_adapter_test.js @@ -624,7 +624,7 @@ test("async hasMany always returns a promise", function() { adapter.createRecord = function(store, type, record) { var hash = { name: "Tom Dale" }; - hash.dogs = Ember.A(); + hash.dogs = []; hash.id = 1; return Ember.RSVP.resolve(hash); }; From 10aa3ae0c00939774fa91e07e1a493d949de8283 Mon Sep 17 00:00:00 2001 From: Dominik Boehi Date: Tue, 20 May 2014 23:20:02 +0200 Subject: [PATCH 0167/2527] Remove accidentally added capitalize and camelize --- packages/ember-data/lib/serializers/json_serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 14d3b1d77aa..bf6982ce9af 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -408,7 +408,7 @@ var JSONSerializer = Ember.Object.extend({ if (Ember.isNone(belongsTo)) { json[key + "_type"] = null; } else { - json[key + "_type"] = capitalize(camelize(belongsTo.constructor.typeKey)); + json[key + "_type"] = belongsTo.constructor.typeKey; } } }); From e4c58ae15efeb04b2b183509163d01e216aa0aac Mon Sep 17 00:00:00 2001 From: Bill Heaton Date: Wed, 21 May 2014 12:18:55 -0700 Subject: [PATCH 0168/2527] Remove unnessary loop in extracting single using DS.EmbeddedRecordsMixin - updatePayloadWithEmbeddedBelongsTo: removed unnessary loop --- .../lib/system/embedded_records_mixin.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index 3c86a3f2cf4..9041015c4a3 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -472,11 +472,8 @@ function updatePayloadWithEmbeddedBelongsTo(serializer, store, primaryType, rela } payload[embeddedTypeKey] = payload[embeddedTypeKey] || []; var embeddedType = store.modelFor(relationship.type.typeKey); - for (var key in partial) { - if (partial.hasOwnProperty(key) && camelize(key) === attr) { - updatePayloadWithEmbedded(_serializer, store, embeddedType, payload, partial[key]); - } - } + // Recursive call for nested record + updatePayloadWithEmbedded(_serializer, store, embeddedType, payload, partial[attribute]); partial[expandedKey] = partial[attribute].id; // Need to move an embedded `belongsTo` object into a pluralized collection payload[embeddedTypeKey].push(partial[attribute]); From ebc333ec00e9e343808ce0cbd11c17e1b84d5b55 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 21 May 2014 09:12:33 -0400 Subject: [PATCH 0169/2527] JSONSerializer should use the attrs hash when extracting records Also breaks the _super chain in normalize to preserve ordering in the RESTSerializer --- .../lib/serializers/json_serializer.js | 51 +++++++++++++++++++ .../lib/serializers/rest_serializer.js | 24 +-------- .../serializers/json_serializer_test.js | 31 ++++++++++- 3 files changed, 83 insertions(+), 23 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index d866e0525de..d78a2763b00 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -40,6 +40,35 @@ var JSONSerializer = Ember.Object.extend({ */ primaryKey: 'id', + /** + The `attrs` object can be used to declare a simple mapping between + property names on `DS.Model` records and payload keys in the + serialized JSON object representing the record. An object with the + propery `key` can also be used to designate the attribute's key on + the response payload. + + Example + + ```javascript + App.Person = DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + occupation: DS.attr('string'), + admin: DS.attr('boolean') + }); + + App.PersonSerializer = DS.JSONSerializer.extend({ + attrs: { + admin: 'is_admin', + occupation: {key: 'career'} + } + }); + ``` + + @property attrs + @type {Object} + */ + /** Given a subclass of `DS.Model` and a JSON object this method will iterate through each attribute of the `DS.Model` and invoke the @@ -100,10 +129,32 @@ var JSONSerializer = Ember.Object.extend({ normalize: function(type, hash) { if (!hash) { return hash; } + this.normalizeUsingDeclaredMapping(type, hash); this.applyTransforms(type, hash); return hash; }, + /** + @method normalizeUsingDeclaredMapping + @private + */ + normalizeUsingDeclaredMapping: function(type, hash) { + var attrs = get(this, 'attrs'), payloadKey, key; + + if (attrs) { + for (key in attrs) { + payloadKey = attrs[key]; + if (payloadKey && payloadKey.key) { + payloadKey = payloadKey.key; + } + if (typeof payloadKey === 'string') { + hash[key] = hash[payloadKey]; + delete hash[payloadKey]; + } + } + } + }, + // SERIALIZE /** Called when a record is saved in order to convert the diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index bfa0048f3f5..52e6c8469a9 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -179,7 +179,8 @@ var RESTSerializer = JSONSerializer.extend({ this.normalizeHash[prop](hash); } - return this._super(type, hash, prop); + this.applyTransforms(type, hash); + return hash; }, /** @@ -219,27 +220,6 @@ var RESTSerializer = JSONSerializer.extend({ delete hash[primaryKey]; }, - /** - @method normalizeUsingDeclaredMapping - @private - */ - normalizeUsingDeclaredMapping: function(type, hash) { - var attrs = get(this, 'attrs'), payloadKey, key; - - if (attrs) { - for (key in attrs) { - payloadKey = attrs[key]; - if (payloadKey && payloadKey.key) { - payloadKey = payloadKey.key; - } - if (typeof payloadKey === 'string') { - hash[key] = hash[payloadKey]; - delete hash[payloadKey]; - } - } - } - }, - /** @method normalizeAttributes @private diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index eac2ed1403d..e616bf90681 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -131,7 +131,6 @@ test("serializePolymorphicType", function() { }); }); - test("extractArray normalizes each record in the array", function() { var postNormalizeCount = 0; var posts = [ @@ -149,3 +148,33 @@ test("extractArray normalizes each record in the array", function() { env.container.lookup("serializer:post").extractArray(env.store, Post, posts); equal(postNormalizeCount, 2, "two posts are normalized"); }); + +test('Serializer should respect the attrs hash when extracting records', function(){ + env.container.register("serializer:post", DS.JSONSerializer.extend({ + attrs: { + title: "title_payload_key" + } + })); + + var jsonHash = { + title_payload_key: "Rails is omakase" + }; + + var post = env.container.lookup("serializer:post").extractSingle(env.store, Post, jsonHash); + + equal(post.title, "Rails is omakase"); +}); + +test('Serializer should respect the attrs hash when serializing records', function(){ + env.container.register("serializer:post", DS.JSONSerializer.extend({ + attrs: { + title: "title_payload_key" + } + })); + + post = env.store.createRecord("post", { title: "Rails is omakase"}); + + var payload = env.container.lookup("serializer:post").serialize(post); + + equal(payload.title_payload_key, "Rails is omakase"); +}); From 01e65238fb6d57f86aefbb92af24fc005825c628 Mon Sep 17 00:00:00 2001 From: Cameron Ketcham Date: Mon, 5 May 2014 15:11:47 -0400 Subject: [PATCH 0170/2527] moved normalizeId to JSONSerializer --- .../lib/serializers/json_serializer.js | 13 ++++++++++ .../lib/serializers/rest_serializer.js | 13 ---------- .../serializers/json_serializer_test.js | 25 +++++++++++++++++++ 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index d78a2763b00..18618412b4a 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -129,6 +129,7 @@ var JSONSerializer = Ember.Object.extend({ normalize: function(type, hash) { if (!hash) { return hash; } + this.normalizeId(hash); this.normalizeUsingDeclaredMapping(type, hash); this.applyTransforms(type, hash); return hash; @@ -154,6 +155,18 @@ var JSONSerializer = Ember.Object.extend({ } } }, + /** + @method normalizeId + @private + */ + normalizeId: function(hash) { + var primaryKey = get(this, 'primaryKey'); + + if (primaryKey === 'id') { return; } + + hash.id = hash[primaryKey]; + delete hash[primaryKey]; + }, // SERIALIZE /** diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index 52e6c8469a9..6884e26c1a6 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -207,19 +207,6 @@ var RESTSerializer = JSONSerializer.extend({ return payload; }, - /** - @method normalizeId - @private - */ - normalizeId: function(hash) { - var primaryKey = get(this, 'primaryKey'); - - if (primaryKey === 'id') { return; } - - hash.id = hash[primaryKey]; - delete hash[primaryKey]; - }, - /** @method normalizeAttributes @private diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index e616bf90681..cb1107013bf 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -178,3 +178,28 @@ test('Serializer should respect the attrs hash when serializing records', functi equal(payload.title_payload_key, "Rails is omakase"); }); + +test("Serializer should respect the primaryKey attribute when extracting records", function() { + env.container.register('serializer:post', DS.JSONSerializer.extend({ + primaryKey: '_ID_' + })); + + var jsonHash = { "_ID_": 1, title: "Rails is omakase"}; + + post = env.container.lookup("serializer:post").extractSingle(env.store, Post, jsonHash); + + equal(post.id, "1"); + equal(post.title, "Rails is omakase"); +}); + +test("Serializer should respect the primaryKey attribute when serializing records", function() { + env.container.register('serializer:post', DS.JSONSerializer.extend({ + primaryKey: '_ID_' + })); + + post = env.store.createRecord("post", { id: "1", title: "Rails is omakase"}); + + var payload = env.container.lookup("serializer:post").serialize(post, {includeId: true}); + + equal(payload._ID_, "1"); +}); From b04181770fd1ff5390ca547bd6ff598c5f2eed5e Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 21 May 2014 19:00:47 -0400 Subject: [PATCH 0171/2527] Add a doc heading for the ActiveModelSerializer class to so its page shows up in the API docs --- .../lib/system/active_model_serializer.js | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index afc79cf3a7c..de1fce1846b 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -10,7 +10,56 @@ var get = Ember.get, capitalize = Ember.String.capitalize, decamelize = Ember.String.decamelize, underscore = Ember.String.underscore; +/** + The ActiveModelSerializer is a subclass of the RESTSerializer designed to integrate + with a JSON API that uses an underscored naming convention instead of camelCasing. + It has been designed to work out of the box with the + [active_model_serializers](http://github.com/rails-api/active_model_serializers) + Ruby gem. This Serializer expects specific settings using ActiveModel::Serializers, + `embed :ids, include: true` which sideloads the records. + + This serializer extends the DS.RESTSerializer by making consistent + use of the camelization, decamelization and pluralization methods to + normalize the serialized JSON into a format that is compatible with + a conventional Rails backend and Ember Data. + + ## JSON Structure + + The ActiveModelSerializer expects the JSON returned from your server + to follow the REST adapter conventions substituting underscored keys + for camelcased ones. + + ### Conventional Names + + Attribute names in your JSON payload should be the underscored versions of + the attributes in your Ember.js models. + + For example, if you have a `Person` model: + + ```js + App.FamousPerson = DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + occupation: DS.attr('string') + }); + ``` + + The JSON returned should look like this: + + ```js + { + "famous_person": { + "first_name": "Barack", + "last_name": "Obama", + "occupation": "President" + } + } + ``` + @class ActiveModelSerializer + @namespace DS + @extends DS.RESTSerializer +*/ var ActiveModelSerializer = RESTSerializer.extend({ // SERIALIZE From c3999f5d4d61d66608218a60dab3cec1fce05b42 Mon Sep 17 00:00:00 2001 From: IgorT Date: Thu, 22 May 2014 17:17:40 -0300 Subject: [PATCH 0172/2527] Copy metadata when it is assigned to recordArrays Currently metadata is saved on Model classes, such that there is only ever 1 instance of the meta object in existence. Often however metadata is a property of a particular array of records and not the record type. A good example is pagination. It should be possible to do `store.findQuery()` twice and get two arrays where each has it's own meta information. However, because metadata is stored on the Model class, any subsequent request will modify the original pagination metadata. This commit enables each recordArray to have it's own unchanging Meta object. --- CHANGELOG.md | 1 + .../adapter_populated_record_array.js | 2 +- .../integration/adapter/rest_adapter_test.js | 24 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e634736a4d..db5895031b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Master +* Each RecordArray gets a copy of the models's metada object instead of sharing the same meta object. Enables several paginated arrays to coexist without clobbering each other * Drop the `type` argument from `normalizePayload` calls. This argument was not consistently passed. Overridding the `extract` functions on the serializer is a suggested alternative if you require the model type. * Introduce `DS._setupContainer()` for use in testing * Deprecate the 5 Ember initializers, use just one named "ember-data" diff --git a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js index 4d6fea6c5d5..4a3d17cc8c7 100644 --- a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js @@ -37,7 +37,7 @@ var AdapterPopulatedRecordArray = RecordArray.extend({ this.setProperties({ content: Ember.A(records), isLoaded: true, - meta: meta + meta: Ember.copy(meta) }); records.forEach(function(record) { diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index df32c86e516..c4855591ceb 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -600,6 +600,30 @@ test("findQuery - payload 'meta' is accessible on the record array", function() })); }); +test("findQuery - each record array can have it's own meta object", function() { + ajaxResponse({ + meta: { offset: 5 }, + posts: [{id: 1, name: "Rails is very expensive sushi"}] + }); + + store.findQuery('post', { page: 2 }).then(async(function(posts) { + equal( + posts.get('meta.offset'), + 5, + "Reponse metadata can be accessed with recordArray.meta" + ); + ajaxResponse({ + meta: { offset: 1 }, + posts: [{id: 1, name: "Rails is very expensive sushi"}] + }); + store.findQuery('post', { page: 1}).then(async(function(newPosts){ + equal(newPosts.get('meta.offset'), 1, 'new array has correct metadata'); + equal(posts.get('meta.offset'), 5, 'metadata on the old array hasnt been clobbered'); + })); + })); +}); + + test("findQuery - returning an array populates the array", function() { ajaxResponse({ posts: [ From 1be953ad5b32dec25439a99950893aa49d9901bb Mon Sep 17 00:00:00 2001 From: Bill Heaton Date: Fri, 23 May 2014 15:31:56 -0700 Subject: [PATCH 0173/2527] DS.EmbeddedRecordsMixin methods for serializing relationships call super if needed [Fixes #1971] --- .../lib/system/embedded_records_mixin.js | 15 ++-- .../embedded_records_mixin_test.js | 85 +++++++++++++++++-- 2 files changed, 89 insertions(+), 11 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index 9041015c4a3..312a61937ab 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -85,10 +85,12 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ serializeBelongsTo: function(record, json, relationship) { var attr = relationship.key; var attrs = this.get('attrs'); - - var includeIds = hasSerializeIdsOption(attrs, attr) || noSerializeOptionSpecified(attrs, attr); + if (noSerializeOptionSpecified(attrs, attr)) { + this._super(record, json, relationship); + return; + } + var includeIds = hasSerializeIdsOption(attrs, attr); var includeRecords = hasSerializeRecordsOption(attrs, attr); - var embeddedRecord = record.get(attr); if (includeIds) { key = this.keyForRelationship(attr, relationship.kind); @@ -107,7 +109,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ } } }, - + /** Serialize `hasMany` relationship when it is configured as embedded objects. @@ -192,10 +194,13 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ serializeHasMany: function(record, json, relationship) { var attr = relationship.key; var attrs = this.get('attrs'); + if (noSerializeOptionSpecified(attrs, attr)) { + this._super(record, json, relationship); + return; + } var includeIds = hasSerializeIdsOption(attrs, attr); var includeRecords = hasSerializeRecordsOption(attrs, attr); var key; - if (includeIds) { key = this.keyForRelationship(attr, relationship.kind); json[key] = get(record, attr).mapBy('id'); diff --git a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js index 69cbb1a6aa5..9fe37ee7472 100644 --- a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js +++ b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js @@ -1,6 +1,8 @@ var get = Ember.get, set = Ember.set; +var camelize = Ember.String.camelize; +var singularize = Ember.String.singularize; var HomePlanet, SuperVillain, EvilMinion, SecretLab, SecretWeapon, Comment, - league, superVillain, evilMinion, secretWeapon, env; + league, superVillain, evilMinion, secretWeapon, homePlanet, secretLab, env; module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { setup: function() { @@ -461,7 +463,7 @@ test("serialize with embedded objects (hasMany relationship) supports serialize: var json = serializer.serialize(league); deepEqual(json, { - name: "Villain League", + name: "Villain League" }); }); @@ -605,7 +607,7 @@ test("serialize with embedded object (belongsTo relationship) works with differe } })); env.container.register('serializer:secretLab', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { - primaryKey: 'crazy_id', + primaryKey: 'crazy_id' })); var serializer = env.container.lookup("serializer:superVillain"); @@ -689,7 +691,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize first_name: get(tom, "firstName"), last_name: get(tom, "lastName"), home_planet_id: get(tom, "homePlanet").get("id"), - secret_lab_id: get(tom, "secretLab").get("id"), + secret_lab_id: get(tom, "secretLab").get("id") }); }); @@ -718,7 +720,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize first_name: get(tom, "firstName"), last_name: get(tom, "lastName"), home_planet_id: get(tom, "homePlanet").get("id"), - secret_lab_id: get(tom, "secretLab").get("id"), + secret_lab_id: get(tom, "secretLab").get("id") }); }); @@ -745,7 +747,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize deepEqual(json, { first_name: get(tom, "firstName"), last_name: get(tom, "lastName"), - home_planet_id: get(tom, "homePlanet").get("id"), + home_planet_id: get(tom, "homePlanet").get("id") }); }); @@ -840,3 +842,74 @@ test("extractSingle with multiply-nested belongsTo", function() { equal(env.store.recordForId("superVillain", "1").get("firstName"), "Tom", "Secondary record, Tom, found in the steore"); equal(env.store.recordForId("homePlanet", "1").get("name"), "Umber", "Nested Secondary record, Umber, found in the store"); }); + +test("serializing relationships with an embedded and without calls super when not attr not present", function() { + homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); + secretLab = env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); + superVillain = env.store.createRecord(SuperVillain, { + id: "1", firstName: "Super", lastName: "Villian", homePlanet: homePlanet, secretLab: secretLab + }); + secretWeapon = env.store.createRecord(SecretWeapon, { id: "1", name: "Secret Weapon", superVillain: superVillain }); + superVillain.get('secretWeapons').pushObject(secretWeapon); + evilMinion = env.store.createRecord(EvilMinion, { id: "1", name: "Evil Minion", superVillian: superVillain }); + superVillain.get('evilMinions').pushObject(evilMinion); + + var calledSerializeBelongsTo = false, calledSerializeHasMany = false; + + var Serializer = DS.RESTSerializer.extend({ + keyForAttribute: function(attr) { + return camelize(attr); + }, + keyForRelationship: function(key, kind) { + key = camelize(key); + if (kind === "belongsTo") { + key += "Id"; + } else if (kind === "hasMany") { + key = singularize(key) + "Ids"; + } + return key; + }, + serializeBelongsTo: function(record, json, relationship) { + calledSerializeBelongsTo = true; + return DS.RESTSerializer.prototype.serializeBelongsTo.call(this, record, json, relationship); + }, + serializeHasMany: function(record, json, relationship) { + calledSerializeHasMany = true; + var key = relationship.key; + var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, "hasMany") : key; + var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship); + // "manyToOne" not supported in DS.RESTSerializer.prototype.serializeHasMany + // See: https://github.com/emberjs/data/pull/1751#issuecomment-43424605 + var relationshipTypes = Ember.String.w('manyToNone manyToMany manyToOne'); + if (relationshipTypes.indexOf(relationshipType) > -1) { + json[payloadKey] = get(record, key).mapBy('id'); + } + } + }); + env.container.register('serializer:evilMinion', Serializer); + env.container.register('serializer:secretWeapon', Serializer); + env.container.register('serializer:superVillain', Serializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + evilMinions: {serialize: 'records', deserialize: 'records'} + // some relationships are not listed here, so super should be called on those + // e.g. secretWeapons: {serialize: 'ids'} + } + })); + var serializer = env.container.lookup("serializer:superVillain"); + + var json = serializer.serialize(superVillain); + deepEqual(json, { + firstName: get(superVillain, "firstName"), + lastName: get(superVillain, "lastName"), + homePlanetId: "123", + evilMinions: [{ + id: get(evilMinion, "id"), + name: get(evilMinion, "name"), + superVillainId: "1" + }], + secretLabId: "101", + secretWeaponIds: ["1"] + }); + ok(calledSerializeBelongsTo); + ok(calledSerializeHasMany); +}); From 866d81d06c95bd18be8c57a71f7e381661c687a1 Mon Sep 17 00:00:00 2001 From: Bill Heaton Date: Thu, 22 May 2014 16:37:03 -0700 Subject: [PATCH 0174/2527] [Docs] Update documentation for the EmbeddedRecordsMixin --- .../lib/system/embedded_records_mixin.js | 63 ++++++++++++++++--- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index 9041015c4a3..5ef212107f2 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -5,12 +5,14 @@ var camelize = Ember.String.camelize; import {pluralize} from "../../../ember-inflector/lib/main"; /** - DS.EmbeddedRecordsMixin supports serializing embedded records. + ## Using Embedded Records - To set up embedded records, include the mixin into a serializer then define - embedded (model) relationships. + `DS.EmbeddedRecordsMixin` supports serializing embedded records. - Below is an example of a per type serializer (post type). + To set up embedded records, include the mixin when extending a serializer + then define and configure embedded (model) relationships. + + Below is an example of a per-type serializer ('post' type). ```js App.PostSerializer = DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { @@ -22,11 +24,54 @@ import {pluralize} from "../../../ember-inflector/lib/main"; ``` The `attrs` option for a resource `{embedded: 'always'}` is shorthand for: - `{serialize: 'records', deserialize: 'records'}`. Embedded records are extracted - from a nested document, so the default option for `deserialize` is `records`. - When serializing, a resource's `attrs` option may be set to use `ids` or `records` - for the `serialize` setting. + ```js + {serialize: 'records', deserialize: 'records'} + ``` + + ### Configuring Attrs + + A resource's `attrs` option may be set to use `ids` or `records` for the + `serialize` setting. + + Embedded records are extracted from a nested document, so the default option + for `deserialize` is `records`. + + The `attrs` property can be set on the ApplicationSerializer or a per-type + serializer. + + In the case where embedded JSON is expected while extracting a payoad (reading) + the setting is `deserialize: 'records'`, there is no need to use `ids` when + extracting as that is the default behavior without this mixin. Likewise, to + embed JSON in the payload while serializing `serialize: 'records'` is the + setting to use. There is an option of not embedding JSON in the serialized + payload by using `serialize: 'ids'`. + + + ### Model Relationships + + Embedded records must have a model defined to be extracted and serialized. + + To successfully extract and serialize embedded records the model relationships + must be setup correcty See the + [defining relationships](/guides/models/defining-models/#toc_defining-relationships) + section of the **Defining Models** guide page. + + Records without an `id` property are not considered embedded records, model + instances must have an `id` property to be used with Ember Data. + + ### Example JSON payloads, Models and Serializers + + **When customizing a serializer it is imporant to grok what the cusomizations + are, please read the docs for the methods this mixin provides, in case you need + to modify to fit your specific needs.** + + For example review the docs for each method of this mixin: + + * [extractArray](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_extractArray) + * [extractSingle](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_extractSingle) + * [serializeBelongsTo](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeBelongsTo) + * [serializeHasMany](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeHasMany) @class EmbeddedRecordsMixin @namespace DS @@ -107,7 +152,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ } } }, - + /** Serialize `hasMany` relationship when it is configured as embedded objects. From 6e2544a819670d5e4c91b01e685cb66004a7ef08 Mon Sep 17 00:00:00 2001 From: IgorT Date: Mon, 26 May 2014 23:33:54 -0300 Subject: [PATCH 0175/2527] Cleanup embedded docs --- .../lib/system/embedded_records_mixin.js | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index 5ef212107f2..860a62967db 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -31,29 +31,34 @@ import {pluralize} from "../../../ember-inflector/lib/main"; ### Configuring Attrs - A resource's `attrs` option may be set to use `ids` or `records` for the - `serialize` setting. - - Embedded records are extracted from a nested document, so the default option - for `deserialize` is `records`. + A resource's `attrs` option may be set to use `ids`, `records` or `no` for the + `serialize` and `deserialize` settings. The `attrs` property can be set on the ApplicationSerializer or a per-type serializer. In the case where embedded JSON is expected while extracting a payoad (reading) the setting is `deserialize: 'records'`, there is no need to use `ids` when - extracting as that is the default behavior without this mixin. Likewise, to - embed JSON in the payload while serializing `serialize: 'records'` is the - setting to use. There is an option of not embedding JSON in the serialized - payload by using `serialize: 'ids'`. + extracting as that is the default behavior without this mixin if you are using + the vanilla ActiveModelAdapter. Likewise, to embed JSON in the payload while + serializing `serialize: 'records'` is the setting to use. There is an option of + not embedding JSON in the serialized payload by using `serialize: 'ids'`. If you + do not want the relationship sent at all, you can use `serialize: 'no'`. + + + ### ActiveModelSerializer defaults + If you do not overwrite `attrs` for a specific relationship, the `ActiveModelSerializer` + will behave in the following way: + BelongsTo: `{serialize:'id', deserialize:'id'}` + HasMany: `{serialize:no, deserialize:'ids'}` ### Model Relationships Embedded records must have a model defined to be extracted and serialized. To successfully extract and serialize embedded records the model relationships - must be setup correcty See the + must be setup correcty See the [defining relationships](/guides/models/defining-models/#toc_defining-relationships) section of the **Defining Models** guide page. From b5c4771a1d418c3c3aec1bffa34a2d4573e9520f Mon Sep 17 00:00:00 2001 From: Trym Skaar Date: Tue, 22 Oct 2013 01:04:53 +0200 Subject: [PATCH 0176/2527] Add failing test for hasMany relationships If adapter does not return any data for a hasMany relationship, the unsaved hasMany records disappear from the relationship. --- .../relationships/has_many_test.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 904fcc4083e..566e80b0239 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -370,3 +370,22 @@ test("a records ASYNC HM relationship property is readOnly", function(){ post.set('comments'); }, 'Cannot Set: comments on: ' + Ember.inspect(post)); }); + +test("When a record is saved, its unsaved hasMany records should be kept", function () { + expect(1); + + var post, comment; + + env.adapter.createRecord = function(store, type, record) { + return Ember.RSVP.resolve({ id: 1 }); + }; + + Ember.run(function () { + post = env.store.createRecord('post'); + comment = env.store.createRecord('comment'); + post.get('comments').pushObject(comment); + post.save(); + }); + + equal(get(post, 'comments.length'), 1, "The unsaved comment should be in the post's comments array"); +}); From e2ad0fdcd22ce0b96caf7a622bc409d697d210c6 Mon Sep 17 00:00:00 2001 From: Trym Skaar Date: Tue, 22 Oct 2013 01:24:55 +0200 Subject: [PATCH 0177/2527] Fixes #1466 --- packages/ember-data/lib/system/store.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index a4de6b1f650..3e16f2c48df 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1550,7 +1550,13 @@ function normalizeRelationships(store, type, data, record) { var kind = relationship.kind, value = data[key]; - if (value == null) { return; } + if (value == null) { + if (kind === 'hasMany') { + value = data[key] = Ember.A(); + addUnsavedRecords(record, key, value); + } + return; + } if (kind === 'belongsTo') { deserializeRecordId(store, data, key, relationship, value); From 51d675ec05da49c5401461c0da5ab88eb47ee632 Mon Sep 17 00:00:00 2001 From: IgorT Date: Tue, 27 May 2014 00:06:19 -0300 Subject: [PATCH 0178/2527] Always keep the hasMany around when payload arrives We should always keep the current hasMany value if the payload has no relationships with that key --- packages/ember-data/lib/system/store.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 3e16f2c48df..31287799758 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1551,9 +1551,8 @@ function normalizeRelationships(store, type, data, record) { value = data[key]; if (value == null) { - if (kind === 'hasMany') { - value = data[key] = Ember.A(); - addUnsavedRecords(record, key, value); + if (kind === 'hasMany' && record) { + value = data[key] = record.get(key).toArray(); } return; } From 79650f3206bfdb7f71abd1c0b2f5234856daac51 Mon Sep 17 00:00:00 2001 From: Alexandre de Oliveira Date: Mon, 13 Jan 2014 10:11:10 -0200 Subject: [PATCH 0179/2527] Fixes hasMany records being duplicated after payload returns from server There is an edge case where a hasMany record gets duplicated (same ID). Basically, if we generate a record locally using UUID or any custom ID format, then push it to production which will return the same ID previously defined, the store's array that holds records to be resolved is going to duplicate both items, even if they have the same ID. This commit fixes that by not allowing duplicated IDs in that array. --- packages/ember-data/lib/system/store.js | 10 ++++++- .../integration/adapter/rest_adapter_test.js | 27 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 3231a935a87..01a68ba9aa1 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1596,10 +1596,18 @@ function deserializeRecordIds(store, data, key, relationship, ids) { // in the payload, so add them back in manually. function addUnsavedRecords(record, key, data) { if(record) { - Ember.A(data).pushObjects(record.get(key).filterBy('isNew')); + var unsavedRecords = uniqById(Ember.A(data), record.get(key).filterBy('isNew')); + Ember.A(data).pushObjects(unsavedRecords); } } +function uniqById(data, records) { + var currentIds = data.mapBy("id"); + return records.reject(function(record) { + return Ember.A(currentIds).contains(record.id); + }); +} + // Delegation to the adapter and promise management /** A `PromiseArray` is an object that acts like both an `Ember.Array` diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index df32c86e516..99bfb21e544 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -301,6 +301,33 @@ test("create - a record on the many side of a hasMany relationship should update })); }); +test("create - relationships are not duplicated", function() { + var post, comment; + + Post.reopen({ comments: DS.hasMany('comment') }); + Comment.reopen({ post: DS.belongsTo('post') }); + + post = store.createRecord('post', { name: "Tomtomhuda" }); + comment = store.createRecord('comment', { id: 2, name: "Comment title" }); + + ajaxResponse({ post: [{ id: 1, name: "Rails is omakase", comments: [] }] }); + + post.save().then(async(function(post) { + equal(post.get('comments.length'), 0, "post has 0 comments"); + post.get('comments').pushObject(comment); + equal(post.get('comments.length'), 1, "post has 1 comment"); + + ajaxResponse({ + post: [{ id: 1, name: "Rails is omakase", comments: [2] }], + comments: [{ id: 2, name: "Comment title" }] + }); + + return post.save(); + })).then(async(function(post) { + equal(post.get('comments.length'), 1, "post has 1 comment"); + })); +}); + test("update - an empty payload is a basic success", function() { store.push('post', { id: 1, name: "Rails is omakase" }); From 9cd49f4bb074f08085b2936bfabb0685edbf4aaf Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 28 May 2014 10:49:06 -0500 Subject: [PATCH 0180/2527] v1.0.0-beta.8 Changelog --- CHANGELOG.md | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index db5895031b3..59df2019531 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,99 @@ ### Master +### Ember Data 1.0.0-beta.8 _(May 28, 2014)_ + * Each RecordArray gets a copy of the models's metada object instead of sharing the same meta object. Enables several paginated arrays to coexist without clobbering each other * Drop the `type` argument from `normalizePayload` calls. This argument was not consistently passed. Overridding the `extract` functions on the serializer is a suggested alternative if you require the model type. * Introduce `DS._setupContainer()` for use in testing * Deprecate the 5 Ember initializers, use just one named "ember-data" +* fix merge conflicts +* DS.EmbeddedRecordsMixin methods for serializing relationships call super if needed +* Copy metadata when it is assigned to recordArrays +* Add a doc heading for the ActiveModelSerializer class to so its page shows up in the API docs +* moved normalizeId to JSONSerializer +* JSONSerializer should use the attrs hash when extracting records Also breaks the _super chain in normalize to preserve ordering in the RESTSerializer +* Remove unnessary loop in extracting single using DS.EmbeddedRecordsMixin +* Do not presume returned data arrays support .pushObjects +* Update README +* Add package.json to built gem +* [BUGFIX] store.fetchMany should always return a promise. +* Use keyForRelationship in JSONSerializer's serializeHasMany method +* Makes sure extractArray is normalizing each record in the array instead of trying to normalize the whole payload as an object. +* Do not cache model factories on meta, or on other model CPs +* Removed unused resolver from ManyArray.fetch +* Add a base fiddle for mocked data requests with Ember Data +* normalizePayload only gets the payload +* [BUGFIX] Normalize typeKeys to always be camelCase +* Use SVG for the Travis badge in the README +* Update the docs on pushPayload to clarify how model is used +* Put the initialization docs back with the initializers +* [DOC] Fix jsdoc for `Serializer#extractSingle` +* Fix publishing of builds. +* filteredRecordArray derived from filterFn + query, should retain its query (just as adapterPopulated does) +* Setting a filter function on a filteredRecordArray should only cause 1 re-filter per run-loop +* [Bugfix] when a record which exists in an adapterPopulatedRecordArray is destroyed, it is also now removed from the array +* [BUGFIX] Add missing support for belongsTo in DS.EmbeddedRecordsMixin +* Remove incorrect semicolon from pathForType example. Also changed the example to use .extend instead of reopen +* incase jQuery.ajax returns a null or undefined jqXHR +* Add `license` field to package.json +* Add `repository` field to package.json +* Cleanup scripts +* Fix to update ember-data version +* Use `package.json` as gem version +* Use npm-scripts to run test +* Specify language as Node.js on Travis CI +* Fixes a typo in the documentation of the serializeAttribute method of json_serializer.js +* [DOC] `bower install` is part of `npm install`, removing it from README +* [DOC] Fix docs for method signature of extractSingle, extractArray +* Add a better transform example +* Import InvalidError instead of looking at global DS +* allow saving records from invalid state +* [DOC beta] Clarify adapter settings with ActiveModel::Serializers +* Fix validation comments for +* Update changelog for initializer and container setup changes +* add bower to getting ember data section +* Add examples to the DS.Errors api docs. +* Extend from Controller for ApplicationController. +* Update error messages from push and update +* Fix warnings generated by yuidoc +* Bring back deprecated initializers +* Drop spurious var set statements +* Refactor Ember initializer to use DS._setupContainer +* Fix incorrect documentation for isError. +* change its to it's and remove 'do' that is not needed +* change 'the the' to 'the' +* add semicolons to example code +* Fix error assertion's message +* Explicitly define a bower install directory +* Import 'defaultRules', fixes missing Inflector.defaultRules +* Fix typo additonal -> additional +* Fix the ActiveModelAdapter @extends docstring +* Add an example of sending cookie information in the header and updated confusing reopen example. +* Expands isDeleted documentation +* Clarify adapter header documentation +* Documents invalid use of `attr` for attribute of `id` +* Store#pushPayload should use the type's serializer for normalizing +* Remove internal reliance on Ember.lookup.DS in favor of requireModule(). +* Remove reliance on global DS +* Deprecate App.Store in favor of App.ApplicationStore. +* Fix a typo, accept -> except +* [doc] camelize `all` example for consistency +* Remove `window` references in favor of `Ember.lookup`. +* Document the difference between Store push() vs. createRecord() ect. +* Document the store#update method. +* Make sure data adapter tests pass for Ember <= 1.4 +* Update data adapter test with new Ember version +* Minor typo +* change documentation from hash to payload +* Copy-editing +* Use the ApplicationAdapter property instead of creating a custom Store just to create a custom adapter. +* Fixed typo in isDirty example +* Use string model lookup instead of class lookup +* Improve store docs to use container lookup not concrete class +* Remove duplicate changelog entry. +* fix small typo in CHANGELOG.md +* actually update version for post-release version bump ### Ember Data 1.0.0-beta.7 _(February 19, 2014)_ From e804fc2e08d75868e610f7572c10d49495b5c911 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 28 May 2014 10:56:52 -0500 Subject: [PATCH 0181/2527] remove CHANGELOG cruft --- CHANGELOG.md | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59df2019531..35d0f422579 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,68 +8,43 @@ * Drop the `type` argument from `normalizePayload` calls. This argument was not consistently passed. Overridding the `extract` functions on the serializer is a suggested alternative if you require the model type. * Introduce `DS._setupContainer()` for use in testing * Deprecate the 5 Ember initializers, use just one named "ember-data" -* fix merge conflicts * DS.EmbeddedRecordsMixin methods for serializing relationships call super if needed * Copy metadata when it is assigned to recordArrays -* Add a doc heading for the ActiveModelSerializer class to so its page shows up in the API docs * moved normalizeId to JSONSerializer * JSONSerializer should use the attrs hash when extracting records Also breaks the _super chain in normalize to preserve ordering in the RESTSerializer * Remove unnessary loop in extracting single using DS.EmbeddedRecordsMixin * Do not presume returned data arrays support .pushObjects -* Update README -* Add package.json to built gem * [BUGFIX] store.fetchMany should always return a promise. * Use keyForRelationship in JSONSerializer's serializeHasMany method * Makes sure extractArray is normalizing each record in the array instead of trying to normalize the whole payload as an object. * Do not cache model factories on meta, or on other model CPs * Removed unused resolver from ManyArray.fetch -* Add a base fiddle for mocked data requests with Ember Data * normalizePayload only gets the payload * [BUGFIX] Normalize typeKeys to always be camelCase -* Use SVG for the Travis badge in the README * Update the docs on pushPayload to clarify how model is used * Put the initialization docs back with the initializers * [DOC] Fix jsdoc for `Serializer#extractSingle` -* Fix publishing of builds. * filteredRecordArray derived from filterFn + query, should retain its query (just as adapterPopulated does) * Setting a filter function on a filteredRecordArray should only cause 1 re-filter per run-loop * [Bugfix] when a record which exists in an adapterPopulatedRecordArray is destroyed, it is also now removed from the array * [BUGFIX] Add missing support for belongsTo in DS.EmbeddedRecordsMixin -* Remove incorrect semicolon from pathForType example. Also changed the example to use .extend instead of reopen * incase jQuery.ajax returns a null or undefined jqXHR -* Add `license` field to package.json -* Add `repository` field to package.json -* Cleanup scripts -* Fix to update ember-data version -* Use `package.json` as gem version -* Use npm-scripts to run test -* Specify language as Node.js on Travis CI * Fixes a typo in the documentation of the serializeAttribute method of json_serializer.js * [DOC] `bower install` is part of `npm install`, removing it from README * [DOC] Fix docs for method signature of extractSingle, extractArray -* Add a better transform example * Import InvalidError instead of looking at global DS * allow saving records from invalid state * [DOC beta] Clarify adapter settings with ActiveModel::Serializers -* Fix validation comments for -* Update changelog for initializer and container setup changes -* add bower to getting ember data section * Add examples to the DS.Errors api docs. * Extend from Controller for ApplicationController. * Update error messages from push and update -* Fix warnings generated by yuidoc * Bring back deprecated initializers -* Drop spurious var set statements * Refactor Ember initializer to use DS._setupContainer * Fix incorrect documentation for isError. -* change its to it's and remove 'do' that is not needed -* change 'the the' to 'the' * add semicolons to example code * Fix error assertion's message * Explicitly define a bower install directory * Import 'defaultRules', fixes missing Inflector.defaultRules -* Fix typo additonal -> additional -* Fix the ActiveModelAdapter @extends docstring * Add an example of sending cookie information in the header and updated confusing reopen example. * Expands isDeleted documentation * Clarify adapter header documentation @@ -78,23 +53,15 @@ * Remove internal reliance on Ember.lookup.DS in favor of requireModule(). * Remove reliance on global DS * Deprecate App.Store in favor of App.ApplicationStore. -* Fix a typo, accept -> except -* [doc] camelize `all` example for consistency * Remove `window` references in favor of `Ember.lookup`. * Document the difference between Store push() vs. createRecord() ect. * Document the store#update method. * Make sure data adapter tests pass for Ember <= 1.4 * Update data adapter test with new Ember version -* Minor typo * change documentation from hash to payload -* Copy-editing * Use the ApplicationAdapter property instead of creating a custom Store just to create a custom adapter. -* Fixed typo in isDirty example * Use string model lookup instead of class lookup * Improve store docs to use container lookup not concrete class -* Remove duplicate changelog entry. -* fix small typo in CHANGELOG.md -* actually update version for post-release version bump ### Ember Data 1.0.0-beta.7 _(February 19, 2014)_ From cdcf911097dbf5aaf7e7da38abf2a7bd4fd2193b Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 28 May 2014 13:15:04 -0300 Subject: [PATCH 0182/2527] changelog cleanup --- CHANGELOG.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35d0f422579..e3ac7f6e1ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,6 @@ * Introduce `DS._setupContainer()` for use in testing * Deprecate the 5 Ember initializers, use just one named "ember-data" * DS.EmbeddedRecordsMixin methods for serializing relationships call super if needed -* Copy metadata when it is assigned to recordArrays * moved normalizeId to JSONSerializer * JSONSerializer should use the attrs hash when extracting records Also breaks the _super chain in normalize to preserve ordering in the RESTSerializer * Remove unnessary loop in extracting single using DS.EmbeddedRecordsMixin @@ -28,6 +27,7 @@ * Setting a filter function on a filteredRecordArray should only cause 1 re-filter per run-loop * [Bugfix] when a record which exists in an adapterPopulatedRecordArray is destroyed, it is also now removed from the array * [BUGFIX] Add missing support for belongsTo in DS.EmbeddedRecordsMixin +* Add support for serializing hasMany as ids * incase jQuery.ajax returns a null or undefined jqXHR * Fixes a typo in the documentation of the serializeAttribute method of json_serializer.js * [DOC] `bower install` is part of `npm install`, removing it from README @@ -41,8 +41,6 @@ * Bring back deprecated initializers * Refactor Ember initializer to use DS._setupContainer * Fix incorrect documentation for isError. -* add semicolons to example code -* Fix error assertion's message * Explicitly define a bower install directory * Import 'defaultRules', fixes missing Inflector.defaultRules * Add an example of sending cookie information in the header and updated confusing reopen example. From 03a153f430b306bbe28f4aba03231ebab3b44283 Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 28 May 2014 14:11:52 -0300 Subject: [PATCH 0183/2527] Add missed changelog entries --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3ac7f6e1ee..37489212b91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,9 @@ * Use the ApplicationAdapter property instead of creating a custom Store just to create a custom adapter. * Use string model lookup instead of class lookup * Improve store docs to use container lookup not concrete class +* Do not call adapter.deleteRecord for a record that is already saved and deleted +* Remove DS.AttributeChange +* Fix rollback on invalid record after set ### Ember Data 1.0.0-beta.7 _(February 19, 2014)_ From b3bb83b065aa9e1780f95ec2b342dce03bcdd57b Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 28 May 2014 22:12:29 -0500 Subject: [PATCH 0184/2527] ie8 fixes --- bower.json | 3 ++- .../tests/integration/embedded_records_mixin_test.js | 3 ++- packages/ember-data/lib/system/model/errors.js | 3 ++- .../ember-data/lib/system/record_array_manager.js | 4 ++-- packages/ember-data/lib/system/store.js | 12 +++++++----- .../tests/integration/debug_adapter_test.js | 6 ++---- .../integration/serializers/rest_serializer_test.js | 2 +- tests/index.html | 2 +- 8 files changed, 19 insertions(+), 16 deletions(-) diff --git a/bower.json b/bower.json index f086c49f2d6..3d8e4951e6d 100644 --- a/bower.json +++ b/bower.json @@ -2,8 +2,9 @@ "name": "ember-data", "private": true, "dependencies": { - "ember": "~1.4.0", + "ember": "~1.6.0-beta.5", "qunit": "~1.13.0", + "jquery": "~1.10.x", "handlebars": "~1.3.0" } } diff --git a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js index 9fe37ee7472..c7447b9adc4 100644 --- a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js +++ b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js @@ -3,6 +3,7 @@ var camelize = Ember.String.camelize; var singularize = Ember.String.singularize; var HomePlanet, SuperVillain, EvilMinion, SecretLab, SecretWeapon, Comment, league, superVillain, evilMinion, secretWeapon, homePlanet, secretLab, env; +var indexOf = Ember.EnumerableUtils.indexOf; module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { setup: function() { @@ -881,7 +882,7 @@ test("serializing relationships with an embedded and without calls super when no // "manyToOne" not supported in DS.RESTSerializer.prototype.serializeHasMany // See: https://github.com/emberjs/data/pull/1751#issuecomment-43424605 var relationshipTypes = Ember.String.w('manyToNone manyToMany manyToOne'); - if (relationshipTypes.indexOf(relationshipType) > -1) { + if (indexOf(relationshipTypes, relationshipType) > -1) { json[payloadKey] = get(record, key).mapBy('id'); } } diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index 3b209c7491e..8fb65993c90 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -1,4 +1,5 @@ var get = Ember.get, isEmpty = Ember.isEmpty; +var map = Ember.EnumerableUtils.map; /** @module ember-data @@ -231,7 +232,7 @@ var Errors = Ember.Object.extend(Ember.Enumerable, Ember.Evented, { _findOrCreateMessages: function(attribute, messages) { var errors = this.errorsFor(attribute); - return Ember.makeArray(messages).map(function(message) { + return map(Ember.makeArray(messages), function(message) { return errors.findBy('message', message) || { attribute: attribute, message: message diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index b150e0973db..c45c940c9fa 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -267,8 +267,8 @@ var RecordArrayManager = Ember.Object.extend({ willDestroy: function(){ this._super(); - flatten(values(this.filteredRecordArrays.values)).forEach(destroy); - this._adapterPopulatedRecordArrays.forEach(destroy); + forEach(flatten(values(this.filteredRecordArrays.values)), destroy); + forEach(this._adapterPopulatedRecordArrays, destroy); } }); diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index a4de6b1f650..33f95d9d4b8 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1510,18 +1510,20 @@ Store = Ember.Object.extend({ }, willDestroy: function() { - var map = this.typeMaps; - var keys = Ember.keys(map); + var typeMaps = this.typeMaps; + var keys = Ember.keys(typeMaps); var store = this; - var types = keys.map(byType); + + var types = map(keys, byType); this.recordArrayManager.destroy(); - types.forEach(this.unloadAll, this); + forEach(types, this.unloadAll, this); function byType(entry) { - return map[entry].type; + return typeMaps[entry]['type']; } + }, /** diff --git a/packages/ember-data/tests/integration/debug_adapter_test.js b/packages/ember-data/tests/integration/debug_adapter_test.js index 746a1734955..fab8dad9265 100644 --- a/packages/ember-data/tests/integration/debug_adapter_test.js +++ b/packages/ember-data/tests/integration/debug_adapter_test.js @@ -3,9 +3,8 @@ var App, store, debugAdapter, get = Ember.get; module("DS.DebugAdapter", { setup: function() { Ember.run(function() { - App = Ember.Application.create({ - toString: function() { return 'App'; } - }); + App = Ember.Application.create(); + App.toString = function(){ return 'App'; }; App.ApplicationStore = DS.Store.extend({ adapter: DS.Adapter.extend() @@ -15,7 +14,6 @@ module("DS.DebugAdapter", { title: DS.attr('string') }); - App.advanceReadiness(); }); store = App.__container__.lookup('store:main'); diff --git a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js index 48cd88dc23e..e6c7bd5acb0 100644 --- a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js @@ -83,7 +83,7 @@ test("extractArray failure with custom typeForRoot", function() { super_villains: [{id: "1", firstName: "Tom", lastName: "Dale", homePlanet: "1"}] }; - raises(function(){ + throws(function(){ env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); }, "No model was found for 'home_planets'", "raised error message expected to contain \"No model was found for 'home_planets'\""); diff --git a/tests/index.html b/tests/index.html index d63452f67aa..b1b3fca4f22 100644 --- a/tests/index.html +++ b/tests/index.html @@ -1,4 +1,4 @@ - + From da8194a284822c0fec0b561e622d0945c52efe36 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 29 May 2014 12:29:23 -0500 Subject: [PATCH 0185/2527] post-release version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0899927cc54..3ea0647289a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.8+canary", + "version": "1.0.0-beta.9+canary", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", From ebd21ec07bec67eea91b095eb5b40c17da34bd75 Mon Sep 17 00:00:00 2001 From: Boris Zhidkov Date: Fri, 30 May 2014 12:52:37 +0400 Subject: [PATCH 0186/2527] Fixes #1973 Failure in Firefox when record id equals 'watch' . Gecko adds watch function to Object.prototype (as described here: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Ob jects/Object/watch) --- packages/ember-data/lib/system/store.js | 8 ++++---- packages/ember-data/tests/unit/model_test.js | 9 +++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 33f95d9d4b8..d0f79a078ac 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -577,10 +577,10 @@ Store = Ember.Object.extend({ type = this.modelFor(type); id = coerceId(id); + var idToRecord = this.typeMapFor(type).idToRecord; + var record = idToRecord[id]; - var record = this.typeMapFor(type).idToRecord[id]; - - if (!record) { + if (!record || !idToRecord.hasOwnProperty(id)) { record = this.buildRecord(type, id); } @@ -1355,7 +1355,7 @@ Store = Ember.Object.extend({ var typeMap = this.typeMapFor(type), idToRecord = typeMap.idToRecord; - Ember.assert('The id ' + id + ' has already been used with another record of type ' + type.toString() + '.', !id || !idToRecord[id]); + Ember.assert('The id ' + id + ' has already been used with another record of type ' + type.toString() + '.', !id || !idToRecord.hasOwnProperty(id)); Ember.assert("`" + Ember.inspect(type)+ "` does not appear to be an ember-data model", (typeof type._create === 'function') ); // lookupFactory should really return an object that creates diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index 58159011c11..4f649fdfb4d 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -74,6 +74,15 @@ test("trying to set an `id` attribute should raise", function() { }, /You may not set `id`/); }); +test("a collision of a record's id with object function's name", function() { + Object.prototype.watch = function(){}; + store.push(Person, { id: 'watch' }); + store.find(Person, 'watch').then(async(function(record) { + equal(get(record, 'id'), 'watch', "record is successfully created and could be found by its id"); + })); + delete Object.prototype.watch; +}); + test("it should use `_reference` and not `reference` to store its reference", function() { store.push(Person, { id: 1 }); From d4f2d7c09c2a88afc29e687372432e3d321dddf4 Mon Sep 17 00:00:00 2001 From: Boris Zhidkov Date: Fri, 30 May 2014 16:53:33 +0400 Subject: [PATCH 0187/2527] add checking if Object.prototype.watch is exist Object.prototype.watch function is used in model unit test to check a collision of a record's id with object function's name. So we create this function if needed and remove after test if it was not defined before. --- packages/ember-data/tests/unit/model_test.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index 4f649fdfb4d..40b79ea0ce3 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -75,12 +75,17 @@ test("trying to set an `id` attribute should raise", function() { }); test("a collision of a record's id with object function's name", function() { - Object.prototype.watch = function(){}; + var hasWatchMethod = Object.prototype.watch; + if (!hasWatchMethod) { + Object.prototype.watch = function(){}; + } store.push(Person, { id: 'watch' }); store.find(Person, 'watch').then(async(function(record) { equal(get(record, 'id'), 'watch', "record is successfully created and could be found by its id"); })); - delete Object.prototype.watch; + if (!hasWatchMethod) { + delete Object.prototype.watch; + } }); test("it should use `_reference` and not `reference` to store its reference", function() { From 91909b793213d4203ea1001f8110772521ffadde Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Fri, 30 May 2014 11:03:57 -0700 Subject: [PATCH 0188/2527] Improve error message --- packages/ember-data/lib/adapters/fixture_adapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/adapters/fixture_adapter.js b/packages/ember-data/lib/adapters/fixture_adapter.js index 0b9135c8c8d..eec2c1226d0 100644 --- a/packages/ember-data/lib/adapters/fixture_adapter.js +++ b/packages/ember-data/lib/adapters/fixture_adapter.js @@ -138,7 +138,7 @@ var FixtureAdapter = Adapter.extend({ var fixtures = this.fixturesForType(type), fixture; - Ember.assert("Unable to find fixtures for model type "+type.toString(), fixtures); + Ember.assert("Unable to find fixtures for model type "+type.toString() +". If you're defining your fixtures using `Model.FIXTURES = ...`, please change it to `Model.reopenClass({ FIXTURES: ... })`.", fixtures); if (fixtures) { fixture = Ember.A(fixtures).findProperty('id', id); From db181d192471d9594289bdc953fa0c54e511ee57 Mon Sep 17 00:00:00 2001 From: IgorT Date: Fri, 30 May 2014 16:10:59 -0300 Subject: [PATCH 0189/2527] Wrap model test in try/finally Before if the test crashed in the middle we would have leaked the prototype changes. Now we make sure we clean up in a finally block. --- packages/ember-data/tests/unit/model_test.js | 21 +++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index 40b79ea0ce3..645450ee69c 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -76,15 +76,18 @@ test("trying to set an `id` attribute should raise", function() { test("a collision of a record's id with object function's name", function() { var hasWatchMethod = Object.prototype.watch; - if (!hasWatchMethod) { - Object.prototype.watch = function(){}; - } - store.push(Person, { id: 'watch' }); - store.find(Person, 'watch').then(async(function(record) { - equal(get(record, 'id'), 'watch', "record is successfully created and could be found by its id"); - })); - if (!hasWatchMethod) { - delete Object.prototype.watch; + try { + if (!hasWatchMethod) { + Object.prototype.watch = function(){}; + } + store.push(Person, { id: 'watch' }); + store.find(Person, 'watch').then(async(function(record) { + equal(get(record, 'id'), 'watch', "record is successfully created and could be found by its id"); + })); + } finally { + if (!hasWatchMethod) { + delete Object.prototype.watch; + } } }); From 123b1277b08da444ebe63bbdd187a7399efb0933 Mon Sep 17 00:00:00 2001 From: kingpin2k Date: Sun, 1 Jun 2014 17:05:42 -0600 Subject: [PATCH 0190/2527] documentation fix should be string 'no' --- .../activemodel-adapter/lib/system/embedded_records_mixin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index 4021702d8cc..10521b97f90 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -51,7 +51,7 @@ import {pluralize} from "../../../ember-inflector/lib/main"; will behave in the following way: BelongsTo: `{serialize:'id', deserialize:'id'}` - HasMany: `{serialize:no, deserialize:'ids'}` + HasMany: `{serialize:'no', deserialize:'ids'}` ### Model Relationships From 70a1f842c47cd6827f6131c270e8bd68f74c65f0 Mon Sep 17 00:00:00 2001 From: Eduardo Figarola Date: Tue, 3 Jun 2014 10:35:49 -0500 Subject: [PATCH 0191/2527] Add example for expected JSON relationship keys. --- .../lib/system/active_model_adapter.js | 37 +++++++++++++++++++ .../lib/system/active_model_serializer.js | 37 +++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index e357e6fb404..973e1948e6b 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -49,6 +49,7 @@ var decamelize = Ember.String.decamelize, ```js { "famous_person": { + "id": 1, "first_name": "Barack", "last_name": "Obama", "occupation": "President" @@ -56,6 +57,42 @@ var decamelize = Ember.String.decamelize, } ``` + Let's imagine that `Occupation` is just another model: + + ```js + App.Person = DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + occupation: DS.belongsTo('occupation') + }); + + App.Occupation = DS.Model.extend({ + name: DS.attr('string'), + salary: DS.attr('number'), + people: DS.hasMany('person') + }); + ``` + + The JSON needed to avoid extra server calls, should look like this: + + ```js + { + "people": [{ + "id": 1, + "first_name": "Barack", + "last_name": "Obama", + "occupation_id": 1 + }], + + "occupations": [{ + "id": 1, + "name": "President", + "salary": 100000, + "person_ids": [1] + }] + } + ``` + @class ActiveModelAdapter @constructor @namespace DS diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index de1fce1846b..d6b8e9b0ee1 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -49,6 +49,7 @@ var get = Ember.get, ```js { "famous_person": { + "id": 1, "first_name": "Barack", "last_name": "Obama", "occupation": "President" @@ -56,6 +57,42 @@ var get = Ember.get, } ``` + Let's imagine that `Occupation` is just another model: + + ```js + App.Person = DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + occupation: DS.belongsTo('occupation') + }); + + App.Occupation = DS.Model.extend({ + name: DS.attr('string'), + salary: DS.attr('number'), + people: DS.hasMany('person') + }); + ``` + + The JSON needed to avoid extra server calls, should look like this: + + ```js + { + "people": [{ + "id": 1, + "first_name": "Barack", + "last_name": "Obama", + "occupation_id": 1 + }], + + "occupations": [{ + "id": 1, + "name": "President", + "salary": 100000, + "person_ids": [1] + }] + } + ``` + @class ActiveModelSerializer @namespace DS @extends DS.RESTSerializer From 0c91533eea1352e92e71636ed49b7e51fb593918 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Tue, 3 Jun 2014 16:56:01 +0100 Subject: [PATCH 0192/2527] Fixes typo in `pushPayload` documentation --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 1fab2203128..ecfb0a7e76f 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1243,7 +1243,7 @@ Store = Ember.Object.extend({ By default, the data will be deserialized using a default serializer (the application serializer if it exists). - Alternativly, `pushPayload` will accept a model type which + Alternatively, `pushPayload` will accept a model type which will determine which serializer will process the payload. However, the serializer itself (processing this data via `normalizePayload`) will not know which model it is From 97ab2bcc4a7c21f4a8d3189ca2372d4eeacf07cd Mon Sep 17 00:00:00 2001 From: Bill Heaton Date: Mon, 26 May 2014 10:04:15 -0700 Subject: [PATCH 0193/2527] [Bugfix] Decouple DS.EmbeddedRecordsMixin from DS.ActiveModelSerializer [Fixes #1974] --- .../lib/system/embedded_records_mixin.js | 21 ++++--- .../embedded_records_mixin_test.js | 58 +++++++++++++------ 2 files changed, 55 insertions(+), 24 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index 10521b97f90..d54698aa8e6 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -255,7 +255,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ key = this.keyForRelationship(attr, relationship.kind); json[key] = get(record, attr).mapBy('id'); } else if (includeRecords) { - key = this.keyForAttribute(attr); + key = getKeyForAttribute.call(this, attr); json[key] = get(record, attr).map(function(embeddedRecord) { var serializedEmbeddedRecord = embeddedRecord.serialize({includeId: true}); this.removeEmbeddedForeignKey(record, embeddedRecord, relationship, serializedEmbeddedRecord); @@ -346,8 +346,9 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ @return Object the primary response to the original request */ extractSingle: function(store, primaryType, payload, recordId) { - var root = this.keyForAttribute(primaryType.typeKey), - partial = payload[root]; + var key = primaryType.typeKey; + var root = getKeyForAttribute.call(this, key); + var partial = payload[root]; updatePayloadWithEmbedded(this, store, primaryType, payload, partial); @@ -405,8 +406,9 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ to the original query. */ extractArray: function(store, primaryType, payload) { - var root = this.keyForAttribute(primaryType.typeKey), - partials = payload[pluralize(root)]; + var key = primaryType.typeKey; + var root = getKeyForAttribute.call(this, key); + var partials = payload[pluralize(root)]; forEach(partials, function(partial) { updatePayloadWithEmbedded(this, store, primaryType, payload, partial); @@ -416,6 +418,11 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ } }); +// `keyForAttribute` is optional but may be defined when extending a serializer prototype +var getKeyForAttribute = function(attr) { + return (this.keyForAttribute) ? this.keyForAttribute(attr) : attr; +}; + // checks config for attrs option to embedded (always) - serialize and deserialize function hasEmbeddedAlwaysOption(attrs, attr) { var option = attrsOption(attrs, attr); @@ -486,7 +493,7 @@ function updatePayloadWithEmbeddedHasMany(serializer, store, primaryType, relati // it is needed when main type === relationship.type var embeddedTypeKey = '_' + serializer.typeForRoot(relationship.type.typeKey); var expandedKey = serializer.keyForRelationship(primaryType, relationship.kind); - var attribute = serializer.keyForAttribute(primaryType); + var attribute = getKeyForAttribute.call(serializer, primaryType); var ids = []; if (!partial[attribute]) { @@ -520,7 +527,7 @@ function updatePayloadWithEmbeddedBelongsTo(serializer, store, primaryType, rela var primaryKey = get(_serializer, 'primaryKey'); var embeddedTypeKey = Ember.String.pluralize(attr); // TODO don't use pluralize var expandedKey = _serializer.keyForRelationship(primaryType, relationship.kind); - var attribute = _serializer.keyForAttribute(primaryType); + var attribute = getKeyForAttribute.call(_serializer, primaryType); if (!partial[attribute]) { return; diff --git a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js index c7447b9adc4..6ed74325809 100644 --- a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js +++ b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js @@ -844,6 +844,42 @@ test("extractSingle with multiply-nested belongsTo", function() { equal(env.store.recordForId("homePlanet", "1").get("name"), "Umber", "Nested Secondary record, Umber, found in the store"); }); +test("Mixin can be used with RESTSerializer which does not define keyForAttribute", function() { + homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); + secretLab = env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); + superVillain = env.store.createRecord(SuperVillain, { + id: "1", firstName: "Super", lastName: "Villian", homePlanet: homePlanet, secretLab: secretLab + }); + secretWeapon = env.store.createRecord(SecretWeapon, { id: "1", name: "Secret Weapon", superVillain: superVillain }); + superVillain.get('secretWeapons').pushObject(secretWeapon); + evilMinion = env.store.createRecord(EvilMinion, { id: "1", name: "Evil Minion", superVillian: superVillain }); + superVillain.get('evilMinions').pushObject(evilMinion); + + env.container.register('serializer:evilMinion', DS.RESTSerializer); + env.container.register('serializer:secretWeapon', DS.RESTSerializer); + env.container.register('serializer:superVillain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + evilMinions: {serialize: 'records', deserialize: 'records'} + } + })); + var serializer = env.container.lookup("serializer:superVillain"); + + var json = serializer.serialize(superVillain); + deepEqual(json, { + firstName: get(superVillain, "firstName"), + lastName: get(superVillain, "lastName"), + homePlanet: "123", + evilMinions: [{ + id: get(evilMinion, "id"), + name: get(evilMinion, "name"), + superVillain: "1" + }], + secretLab: "101" + // "manyToOne" relation does not serialize ids + // sersecretWeapons: ["1"] + }); +}); + test("serializing relationships with an embedded and without calls super when not attr not present", function() { homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); secretLab = env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); @@ -858,18 +894,6 @@ test("serializing relationships with an embedded and without calls super when no var calledSerializeBelongsTo = false, calledSerializeHasMany = false; var Serializer = DS.RESTSerializer.extend({ - keyForAttribute: function(attr) { - return camelize(attr); - }, - keyForRelationship: function(key, kind) { - key = camelize(key); - if (kind === "belongsTo") { - key += "Id"; - } else if (kind === "hasMany") { - key = singularize(key) + "Ids"; - } - return key; - }, serializeBelongsTo: function(record, json, relationship) { calledSerializeBelongsTo = true; return DS.RESTSerializer.prototype.serializeBelongsTo.call(this, record, json, relationship); @@ -880,7 +904,6 @@ test("serializing relationships with an embedded and without calls super when no var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, "hasMany") : key; var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship); // "manyToOne" not supported in DS.RESTSerializer.prototype.serializeHasMany - // See: https://github.com/emberjs/data/pull/1751#issuecomment-43424605 var relationshipTypes = Ember.String.w('manyToNone manyToMany manyToOne'); if (indexOf(relationshipTypes, relationshipType) > -1) { json[payloadKey] = get(record, key).mapBy('id'); @@ -902,14 +925,15 @@ test("serializing relationships with an embedded and without calls super when no deepEqual(json, { firstName: get(superVillain, "firstName"), lastName: get(superVillain, "lastName"), - homePlanetId: "123", + homePlanet: "123", evilMinions: [{ id: get(evilMinion, "id"), name: get(evilMinion, "name"), - superVillainId: "1" + superVillain: "1" }], - secretLabId: "101", - secretWeaponIds: ["1"] + secretLab: "101", + // customized serializeHasMany method to generate ids for "manyToOne" relation + secretWeapons: ["1"] }); ok(calledSerializeBelongsTo); ok(calledSerializeHasMany); From 4626b751e00611729b5264fe5d5ee57e9ec074ba Mon Sep 17 00:00:00 2001 From: givanse Date: Wed, 4 Jun 2014 21:46:02 -0500 Subject: [PATCH 0194/2527] fix a few typos --- .../activemodel-adapter/lib/system/embedded_records_mixin.js | 2 +- packages/ember-data/lib/adapters/fixture_adapter.js | 2 +- packages/ember-data/lib/adapters/rest_adapter.js | 2 +- packages/ember-data/lib/serializers/rest_serializer.js | 2 +- packages/ember-data/lib/system/model/states.js | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index 10521b97f90..0d329a03c25 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -37,7 +37,7 @@ import {pluralize} from "../../../ember-inflector/lib/main"; The `attrs` property can be set on the ApplicationSerializer or a per-type serializer. - In the case where embedded JSON is expected while extracting a payoad (reading) + In the case where embedded JSON is expected while extracting a payload (reading) the setting is `deserialize: 'records'`, there is no need to use `ids` when extracting as that is the default behavior without this mixin if you are using the vanilla ActiveModelAdapter. Likewise, to embed JSON in the payload while diff --git a/packages/ember-data/lib/adapters/fixture_adapter.js b/packages/ember-data/lib/adapters/fixture_adapter.js index eec2c1226d0..7f10d821b7f 100644 --- a/packages/ember-data/lib/adapters/fixture_adapter.js +++ b/packages/ember-data/lib/adapters/fixture_adapter.js @@ -12,7 +12,7 @@ import Adapter from "../system/adapter"; /** `DS.FixtureAdapter` is an adapter that loads records from memory. It's primarily used for development and testing. You can also use - `DS.FixtureAdapter` while working on the API but are not ready to + `DS.FixtureAdapter` while working on the API but is not ready to integrate yet. It is a fully functioning adapter. All CRUD methods are implemented. You can also implement query logic that a remote system would do. It's possible to develop your entire application diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 51267db56be..cb6e6d26070 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -120,7 +120,7 @@ var forEach = Ember.ArrayPolyfills.forEach; object outside of Ember's observer system (for example `document.cookie`). You can use the [volatile](/api/classes/Ember.ComputedProperty.html#method_volatile) - function to set the property into a non-chached mode causing the headers to + function to set the property into a non-cached mode causing the headers to be recomputed with every request. ```js diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index 6884e26c1a6..bfc1688f703 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -27,7 +27,7 @@ function coerceId(id) { ## Across the Board Normalization - There are also a number of hooks that you might find useful to defined + There are also a number of hooks that you might find useful to define across-the-board rules for your payload. These rules will be useful if your server is consistent, or if you're building an adapter for an infrastructure service, like Parse, and want to encode service diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index c3d6384a40f..203c894d6bf 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -16,7 +16,7 @@ var get = Ember.get, set = Ember.set; it would be in the `root.loaded.created.uncommitted` state. If a record has had local modifications made to it that are in the process of being saved, the record would be in the - `root.loaded.updated.inFlight` state. (These state paths will be + `root.loaded.updated.inFlight` state. (This state paths will be explained in more detail below.) Events are sent by the record or its store to the record's @@ -60,7 +60,7 @@ var get = Ember.get, set = Ember.set; * loading ``` - The `DS.Model` states are themselves stateless. What we mean is + The `DS.Model` states are themselves stateless. What that means is that, the hierarchical states that each of *those* points to is a shared data structure. For performance reasons, instead of each record getting its own copy of the hierarchy of states, each record From 9543ed50dcd74acb22f7e5c4a229c545ad1a83c6 Mon Sep 17 00:00:00 2001 From: Dave Choi Date: Thu, 5 Jun 2014 17:30:55 -0400 Subject: [PATCH 0195/2527] [DOC] Add note about expected JSON for ActiveModelAdapter relationships This is covered in the recently added example, but not explicit. --- .../activemodel-adapter/lib/system/active_model_adapter.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index 973e1948e6b..dfa877ba332 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -28,6 +28,10 @@ var decamelize = Ember.String.decamelize, The ActiveModelAdapter expects the JSON returned from your server to follow the REST adapter conventions substituting underscored keys for camelcased ones. + + Unlike the DS.RESTAdapter, async relationship keys must be the singular form + of the relationship name, followed by "_id" for DS.belongsTo relationships, + or "_ids" for DS.hasMany relationships. ### Conventional Names From f2ffe0715e6a778db05c65a501248a2d500100e5 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Thu, 5 Jun 2014 23:40:43 -0400 Subject: [PATCH 0196/2527] better error for missing inverse on hasMany/belongsTo --- .../lib/system/relationships/ext.js | 9 ++++++-- .../inverse_relationships_test.js | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 166fbf68e22..49666fad414 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -114,11 +114,16 @@ Model.reopenClass({ if (options.inverse === null) { return null; } - var inverseName, inverseKind; + var inverseName, inverseKind, inverse; if (options.inverse) { inverseName = options.inverse; - inverseKind = Ember.get(inverseType, 'relationshipsByName').get(inverseName).kind; + inverse = Ember.get(inverseType, 'relationshipsByName').get(inverseName); + + Ember.assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.typeKey + + "' model. This is most likely due to a missing attribute on your model definition.", !Ember.isBlank(inverse)); + + inverseKind = inverse.kind; } else { var possibleRelationships = findPossibleInverses(this, inverseType); diff --git a/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js b/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js index d438c837f7a..b22836fc22c 100644 --- a/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js +++ b/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js @@ -23,6 +23,29 @@ test("When a record is added to a has-many relationship, the inverse belongsTo i equal(comment.get('post'), post, "post was set on the comment"); }); +test("Inverse relationships that don't exist throw a nice error", function () { + User = DS.Model.extend(); + Comment = DS.Model.extend(); + + Post = DS.Model.extend({ + comments: DS.hasMany(Comment, { inverse: 'testPost' }), + user: DS.belongsTo(User, { inverse: 'testPost' }) + }); + + var env = setupStore({ post: Post, comment: Comment, user: User }); + var post = env.store.createRecord('post'); + var user = env.store.createRecord('user'); + var comment = env.store.createRecord('comment'); + + expectAssertion(function() { + post.set('user', user); + }, /We found no inverse relationships by the name of 'testPost' on the 'user' model/); + + expectAssertion(function() { + post.get('comments').addRecord(comment); + }, /We found no inverse relationships by the name of 'testPost' on the 'comment' model/); +}); + test("Inverse relationships can be explicitly nullable", function () { User = DS.Model.extend(); From f5d9ae3511088284e40db9b4d23b8c2c1679ff06 Mon Sep 17 00:00:00 2001 From: IgorT Date: Fri, 6 Jun 2014 13:22:47 -0300 Subject: [PATCH 0197/2527] Revert "better error for missing inverse on hasMany/belongsTo" The commit was using Ember.isBlank which is still feature flagged. This reverts commit f2ffe0715e6a778db05c65a501248a2d500100e5. --- .../lib/system/relationships/ext.js | 9 ++------ .../inverse_relationships_test.js | 23 ------------------- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 49666fad414..166fbf68e22 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -114,16 +114,11 @@ Model.reopenClass({ if (options.inverse === null) { return null; } - var inverseName, inverseKind, inverse; + var inverseName, inverseKind; if (options.inverse) { inverseName = options.inverse; - inverse = Ember.get(inverseType, 'relationshipsByName').get(inverseName); - - Ember.assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.typeKey + - "' model. This is most likely due to a missing attribute on your model definition.", !Ember.isBlank(inverse)); - - inverseKind = inverse.kind; + inverseKind = Ember.get(inverseType, 'relationshipsByName').get(inverseName).kind; } else { var possibleRelationships = findPossibleInverses(this, inverseType); diff --git a/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js b/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js index b22836fc22c..d438c837f7a 100644 --- a/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js +++ b/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js @@ -23,29 +23,6 @@ test("When a record is added to a has-many relationship, the inverse belongsTo i equal(comment.get('post'), post, "post was set on the comment"); }); -test("Inverse relationships that don't exist throw a nice error", function () { - User = DS.Model.extend(); - Comment = DS.Model.extend(); - - Post = DS.Model.extend({ - comments: DS.hasMany(Comment, { inverse: 'testPost' }), - user: DS.belongsTo(User, { inverse: 'testPost' }) - }); - - var env = setupStore({ post: Post, comment: Comment, user: User }); - var post = env.store.createRecord('post'); - var user = env.store.createRecord('user'); - var comment = env.store.createRecord('comment'); - - expectAssertion(function() { - post.set('user', user); - }, /We found no inverse relationships by the name of 'testPost' on the 'user' model/); - - expectAssertion(function() { - post.get('comments').addRecord(comment); - }, /We found no inverse relationships by the name of 'testPost' on the 'comment' model/); -}); - test("Inverse relationships can be explicitly nullable", function () { User = DS.Model.extend(); From bd31e6e68e7e5f4c31b485a9e10136e38fc5b638 Mon Sep 17 00:00:00 2001 From: jwahdatehagh Date: Sat, 7 Jun 2014 20:22:31 +0200 Subject: [PATCH 0198/2527] adapt usage example for TemperatureTransform Adapt usage example to reflect the TemperatureTransform. 'raw' doesn't make sense here as it is not registered as such. --- packages/ember-data/lib/transforms/base.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/transforms/base.js b/packages/ember-data/lib/transforms/base.js index 49ade892518..42bafab90af 100644 --- a/packages/ember-data/lib/transforms/base.js +++ b/packages/ember-data/lib/transforms/base.js @@ -25,7 +25,7 @@ var attr = DS.attr; App.Requirement = DS.Model.extend({ name: attr('string'), - optionsArray: attr('raw') + temperature: attr('temperature') }); ``` From 4a77cd3b3ae8f1ebf337c97a20686c56f127dae0 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Fri, 6 Jun 2014 14:10:04 -0400 Subject: [PATCH 0199/2527] Better error for missing inverse on hasMany/belongsTo --- .../lib/system/relationships/ext.js | 13 +++++++--- .../inverse_relationships_test.js | 25 +++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 166fbf68e22..9813439d1aa 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -114,17 +114,24 @@ Model.reopenClass({ if (options.inverse === null) { return null; } - var inverseName, inverseKind; + var inverseName, inverseKind, inverse; if (options.inverse) { inverseName = options.inverse; - inverseKind = Ember.get(inverseType, 'relationshipsByName').get(inverseName).kind; + inverse = Ember.get(inverseType, 'relationshipsByName').get(inverseName); + + Ember.assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.typeKey + + "' model. This is most likely due to a missing attribute on your model definition.", !Ember.isNone(inverse)); + + inverseKind = inverse.kind; } else { var possibleRelationships = findPossibleInverses(this, inverseType); if (possibleRelationships.length === 0) { return null; } - Ember.assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + this + " were found on " + inverseType + ". Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", possibleRelationships.length === 1); + Ember.assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + + this + " were found on " + inverseType + ". Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", + possibleRelationships.length === 1); inverseName = possibleRelationships[0].name; inverseKind = possibleRelationships[0].kind; diff --git a/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js b/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js index d438c837f7a..ba4fb8d2e25 100644 --- a/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js +++ b/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js @@ -216,3 +216,28 @@ test("When a record's polymorphic belongsTo relationship is set, it can specify equal(post.get('youMessages.length'), 0, "youMessages has no posts"); equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); }); + +test("Inverse relationships that don't exist throw a nice error", function () { + User = DS.Model.extend(); + Comment = DS.Model.extend(); + + Post = DS.Model.extend({ + comments: DS.hasMany(Comment, { inverse: 'testPost' }), + user: DS.belongsTo(User, { inverse: 'testPost' }) + }); + + var env = setupStore({ post: Post, comment: Comment, user: User }); + var post = env.store.createRecord('post'); + var user = env.store.createRecord('user'); + var comment = env.store.createRecord('comment'); + + expectAssertion(function() { + post.set('user', user); + }, /We found no inverse relationships by the name of 'testPost' on the 'user' model/); + + expectAssertion(function() { + post.get('comments').addRecord(comment); + }, /We found no inverse relationships by the name of 'testPost' on the 'comment' model/); +}); + + From f93621e9e3d40c5c18761fd5f119385e842c9100 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Tue, 10 Jun 2014 22:26:46 +0900 Subject: [PATCH 0200/2527] Fix class name in debugging message `RestAdapter` should be `RESTAdapter`. --- packages/ember-data/lib/adapters/rest_adapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index cb6e6d26070..561e77d99fd 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -614,7 +614,7 @@ var RESTAdapter = Adapter.extend({ }; Ember.$.ajax(hash); - }, "DS: RestAdapter#ajax " + type + " to " + url); + }, "DS: RESTAdapter#ajax " + type + " to " + url); }, /** From 92163810d8fe9c129cc00e6e2d8bebf39f3b1aa6 Mon Sep 17 00:00:00 2001 From: "Ruben Martinez Jr." Date: Tue, 10 Jun 2014 15:04:47 -0500 Subject: [PATCH 0201/2527] Fixed a loose semicolon Semicolon was unnecessary and causing a javascript error. --- packages/ember-data/lib/adapters/rest_adapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 561e77d99fd..8a7df464370 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -130,7 +130,7 @@ var forEach = Ember.ArrayPolyfills.forEach; "API_KEY": Ember.get(document.cookie.match(/apiKey\=([^;]*)/), "1"), "ANOTHER_HEADER": "Some header value" }; - }.property().volatile(); + }.property().volatile() }); ``` From cb937467d1b817cde94afe96bb3bc33f41fb6965 Mon Sep 17 00:00:00 2001 From: David Adams Date: Wed, 11 Jun 2014 22:04:42 -0500 Subject: [PATCH 0202/2527] updated '_links' to just 'links' --- TRANSITION.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TRANSITION.md b/TRANSITION.md index f5950a9a9c9..7987f4f5d10 100644 --- a/TRANSITION.md +++ b/TRANSITION.md @@ -496,7 +496,7 @@ Ember Data 1.0.beta.1 is expecting a payload like this: "id": 1 "title": "Rails is omakase", "comments": ["1", "2"], - "_links": { + "links": { "user": "/people/dhh" }, }, @@ -522,7 +522,7 @@ App.PostSerializer = DS.RESTSerializer.extend({ post.id = payload.id; post.title = payload.title; - post._links = { user: payload._links.mapProperty('user').findProperty('href').href }; + post.links = { user: payload._links.mapProperty('user').findProperty('href').href }; // Leave the original un-normalized comments alone, but put them // in the right place in the payload. We'll normalize the comments @@ -552,7 +552,7 @@ App.PostSerializer = DS.RESTSerializer.extend({ post.id = payload.id; post.title = payload.title; - post._links = { user: payload._links.mapProperty('user').findProperty('href').href }; + post.links = { user: payload._links.mapProperty('user').findProperty('href').href }; // Leave the original un-normalized comments alone, but put them // in the right place in the payload. We'll normalize the comments From aef325e514e399e7c0fecc9e7ac210ba635e04ad Mon Sep 17 00:00:00 2001 From: Florian Thomas Date: Thu, 12 Jun 2014 09:59:58 +0200 Subject: [PATCH 0203/2527] fix documentation of `getById` --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index ecfb0a7e76f..5b5e5c5694c 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -468,7 +468,7 @@ Store = Ember.Object.extend({ @method getById @param {String or subclass of DS.Model} type @param {String|Integer} id - @param {DS.Model} record + @return {DS.Model|null} record */ getById: function(type, id) { if (this.hasRecordForId(type, id)) { From 2a02b14b84f7610531445d7fb6a659ffed957ebd Mon Sep 17 00:00:00 2001 From: Jeff Belser Date: Thu, 12 Jun 2014 22:03:46 -0500 Subject: [PATCH 0204/2527] fix documentation of 'attr' --- packages/ember-data/lib/serializers/json_serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 18618412b4a..cd40e1afe15 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -44,7 +44,7 @@ var JSONSerializer = Ember.Object.extend({ The `attrs` object can be used to declare a simple mapping between property names on `DS.Model` records and payload keys in the serialized JSON object representing the record. An object with the - propery `key` can also be used to designate the attribute's key on + property `key` can also be used to designate the attribute's key on the response payload. Example From c44e71701071dcf20afeb9fcde49b9707273ad1f Mon Sep 17 00:00:00 2001 From: Whitney Young Date: Thu, 12 Jun 2014 22:42:13 -0700 Subject: [PATCH 0205/2527] Added documentation for ajaxError with DS.Errors. --- packages/ember-data/lib/system/model/errors.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index 8fb65993c90..c2e830fa654 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -11,6 +11,9 @@ var map = Ember.EnumerableUtils.map; Every DS.Model has an `errors` property that is an instance of `DS.Errors`. This can be used to display validation error messages returned from the server when a `record.save()` rejects. + This works automatically with `DS.ActiveModelAdapter`, but you + can implement [ajaxError](api/data/classes/DS.RESTAdapter.html#method_ajaxError) + in other adapters as well. For Example, if you had an `User` model that looked like this: From abb269c6ebd140adbd602992f80572ada78bf430 Mon Sep 17 00:00:00 2001 From: Doug Yun Date: Fri, 13 Jun 2014 14:39:34 -0400 Subject: [PATCH 0206/2527] rest_adapter: Remove unused `set` definition --- packages/ember-data/lib/adapters/rest_adapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 8a7df464370..e233a4e84c9 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -3,7 +3,7 @@ */ import Adapter from "../system/adapter"; -var get = Ember.get, set = Ember.set; +var get = Ember.get; var forEach = Ember.ArrayPolyfills.forEach; /** From d3f33374a4d4c4f5fdb4378f51f4684db3bddac7 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Sat, 14 Jun 2014 21:58:54 +0900 Subject: [PATCH 0207/2527] Stop using deprecated methods Replace to use some methods that Ember.js recommends. * `findProperty` -> `findBy` * `mapProperty` -> `mapBy` * `filterProperty` -> `filterBy` * `everyProperty` -> `isEvery` --- TRANSITION.md | 8 ++++---- packages/ember-data/lib/adapters/fixture_adapter.js | 2 +- packages/ember-data/lib/serializers/json_serializer.js | 2 +- packages/ember-data/lib/serializers/rest_serializer.js | 2 +- .../ember-data/lib/system/record_arrays/many_array.js | 2 +- packages/ember-data/lib/system/relationships/has_many.js | 2 +- packages/ember-data/lib/system/store.js | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/TRANSITION.md b/TRANSITION.md index 7987f4f5d10..920340da992 100644 --- a/TRANSITION.md +++ b/TRANSITION.md @@ -522,7 +522,7 @@ App.PostSerializer = DS.RESTSerializer.extend({ post.id = payload.id; post.title = payload.title; - post.links = { user: payload._links.mapProperty('user').findProperty('href').href }; + post.links = { user: payload._links.mapBy('user').findBy('href').href }; // Leave the original un-normalized comments alone, but put them // in the right place in the payload. We'll normalize the comments @@ -552,13 +552,13 @@ App.PostSerializer = DS.RESTSerializer.extend({ post.id = payload.id; post.title = payload.title; - post.links = { user: payload._links.mapProperty('user').findProperty('href').href }; + post.links = { user: payload._links.mapBy('user').findBy('href').href }; // Leave the original un-normalized comments alone, but put them // in the right place in the payload. We'll normalize the comments // below in `normalizeHash` var comments = payload._embedded.comments; - post.comments = comments.mapProperty('ID_'); + post.comments = comments.mapBy('ID_'); var post_payload = { post: post, comments: comments }; @@ -802,7 +802,7 @@ You could handle embedded records like this: App.PostSerializer = DS.RESTSerializer.extend({ extractSingle: function(store, type, payload, id) { var comments = payload.post.comments, - commentIds = comments.mapProperty('id'); + commentIds = comments.mapBy('id'); payload.comments = comments; payload.post.comments = commentIds; diff --git a/packages/ember-data/lib/adapters/fixture_adapter.js b/packages/ember-data/lib/adapters/fixture_adapter.js index 7f10d821b7f..fc668adbf6b 100644 --- a/packages/ember-data/lib/adapters/fixture_adapter.js +++ b/packages/ember-data/lib/adapters/fixture_adapter.js @@ -141,7 +141,7 @@ var FixtureAdapter = Adapter.extend({ Ember.assert("Unable to find fixtures for model type "+type.toString() +". If you're defining your fixtures using `Model.FIXTURES = ...`, please change it to `Model.reopenClass({ FIXTURES: ... })`.", fixtures); if (fixtures) { - fixture = Ember.A(fixtures).findProperty('id', id); + fixture = Ember.A(fixtures).findBy('id', id); } if (fixture) { diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index cd40e1afe15..7dd5fce76a8 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -228,7 +228,7 @@ var JSONSerializer = Ember.Object.extend({ var json = { POST_TTL: post.get('title'), POST_BDY: post.get('body'), - POST_CMS: post.get('comments').mapProperty('id') + POST_CMS: post.get('comments').mapBy('id') } if (options.includeId) { diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index bfc1688f703..cadc55d95ee 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -654,7 +654,7 @@ var RESTSerializer = JSONSerializer.extend({ var json = { POST_TTL: post.get('title'), POST_BDY: post.get('body'), - POST_CMS: post.get('comments').mapProperty('id') + POST_CMS: post.get('comments').mapBy('id') } if (options.includeId) { diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index ee273f2f5c9..b7d470d40eb 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -121,7 +121,7 @@ var ManyArray = RecordArray.extend({ store = get(this, 'store'), owner = get(this, 'owner'); - var unloadedRecords = records.filterProperty('isEmpty', true); + var unloadedRecords = records.filterBy('isEmpty', true); store.fetchMany(unloadedRecords, owner); }, diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index b8835ce63c0..420b73f5023 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -76,7 +76,7 @@ function hasRelationship(type, options) { return Ember.computed('data', function(key) { return buildRelationship(this, key, options, function(store, data) { var records = data[key]; - Ember.assert("You looked up the '" + key + "' relationship on '" + this + "' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", Ember.A(records).everyProperty('isEmpty', false)); + Ember.assert("You looked up the '" + key + "' relationship on '" + this + "' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", Ember.A(records).isEvery('isEmpty', false)); return store.findMany(this, data[key], typeForRelationshipMeta(store, meta)); }); }).meta(meta).readOnly(); diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 5b5e5c5694c..7add1b3ba95 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -537,7 +537,7 @@ Store = Ember.Object.extend({ var promises = []; forEach(recordsByTypeMap, function(type, records) { - var ids = records.mapProperty('id'), + var ids = records.mapBy('id'), adapter = this.adapterFor(type); Ember.assert("You tried to load many records but you have no adapter (for " + type + ")", adapter); @@ -601,7 +601,7 @@ Store = Ember.Object.extend({ records = Ember.A(records); - var unloadedRecords = records.filterProperty('isEmpty', true), + var unloadedRecords = records.filterBy('isEmpty', true), manyArray = this.recordArrayManager.createManyArray(type, records); forEach(unloadedRecords, function(record) { From 38058a96b0fc0742f62765f94e84a01232a7b378 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Tue, 17 Jun 2014 10:49:40 -0400 Subject: [PATCH 0208/2527] fix docs for Store#getById --- packages/ember-data/lib/system/store.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 7add1b3ba95..e2d35961847 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -458,11 +458,16 @@ Store = Ember.Object.extend({ /** Get a record by a given type and ID without triggering a fetch. - This method will synchronously return the record if it's available. - Otherwise, it will return null. + This method will synchronously return the record if it is available in the store, + otherwise it will return `null`. A record is available if it has been fetched earlier, or + pushed manually into the store. + + _Note: This is an synchronous method and does not return a promise._ ```js var post = store.getById('post', 1); + + post.get('id'); // 1 ``` @method getById From a7829aad37c9fc79a76ccd3691108d04a2582a24 Mon Sep 17 00:00:00 2001 From: Huafu Gandon Date: Thu, 19 Jun 2014 20:24:08 +0700 Subject: [PATCH 0209/2527] [FIX] typeof null actually === 'object' Fixed an issue where calling `isValue` with null would throw a `TypeError` (Cannot read property then of null) --- packages/ember-data/lib/system/changes/relationship_change.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/changes/relationship_change.js b/packages/ember-data/lib/system/changes/relationship_change.js index f613c847678..bf99298124e 100644 --- a/packages/ember-data/lib/system/changes/relationship_change.js +++ b/packages/ember-data/lib/system/changes/relationship_change.js @@ -359,7 +359,7 @@ RelationshipChangeRemove.prototype = Ember.create(RelationshipChange.create({})) // the object is a value, and not a promise function isValue(object) { - return typeof object === 'object' && (!object.then || typeof object.then !== 'function'); + return object && typeof object === 'object' && (!object.then || typeof object.then !== 'function'); } RelationshipChangeAdd.prototype.changeType = "add"; From 8aee28fd9c333bb2f2d6021c260926c81e569a34 Mon Sep 17 00:00:00 2001 From: Mehul Kar Date: Fri, 20 Jun 2014 16:52:51 -0700 Subject: [PATCH 0210/2527] Add a starter JSBin with associations example. --- CONTRIBUTING.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 12b83c63f6f..1ef9ea3901e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,10 +24,11 @@ this bug already. 3. Provide JSFiddle or JSBin demo that specifically shows the problem. This demo should be fully operational with the exception of the bug you want to -demonstrate. The more pared down, the better. A preconfigured JSFiddle with -mocked requests is available [here][1]. +demonstrate. The more pared down, the better. A preconfigured [JSFiddle][1] | +[JSBin][2] with mocked requests is available. [1]: http://jsfiddle.net/mehulkar/Q5NPs/ +[2]: http://emberjs.jsbin.com/vuxijava/1/edit 4. If possible, submit a Pull Request with a failing test. Better yet, take a stab at fixing the bug yourself if you can! @@ -61,7 +62,7 @@ We love pull requests. Here's a quick guide: 1. Fork the repo. 2. Run the tests. We only take pull requests with passing tests, and it's great -to know that you have a clean slate, see notes on how to run unit tests [here](https://github.com/emberjs/data#how-to-run-unit-tests). (To see tests in the browser, +to know that you have a clean slate, see notes on how to run unit tests [here](https://github.com/emberjs/data#how-to-run-unit-tests). (To see tests in the browser, run `grunt dev` and open `http://localhost:9997/tests/?package=all`.) 3. Add a test for your change. Only refactoring and documentation changes From 32bf2e256614b6861e04d2faa15ec8b2e549326c Mon Sep 17 00:00:00 2001 From: Greg Babiars Date: Tue, 24 Jun 2014 21:11:35 -0700 Subject: [PATCH 0211/2527] Docs use model on controller instead of route Changed the documentation so that the model property referenced is on the controller of the route rather than the route itself. Since the route already has a method called model, referencing the model property as an Ember-Data model can be confusing. --- packages/ember-data/lib/system/model/model.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index a8971983eaa..c79bcf2d39e 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -547,13 +547,13 @@ var Model = Ember.Object.extend(Ember.Evented, { App.ModelDeleteRoute = Ember.Route.extend({ actions: { softDelete: function() { - this.get('model').deleteRecord(); + this.controller.get('model').deleteRecord(); }, confirm: function() { - this.get('model').save(); + this.controller.get('model').save(); }, undo: function() { - this.get('model').rollback(); + this.controller.get('model').rollback(); } } }); @@ -575,7 +575,7 @@ var Model = Ember.Object.extend(Ember.Evented, { actions: { delete: function() { var controller = this.controller; - this.get('model').destroyRecord().then(function() { + controller.get('model').destroyRecord().then(function() { controller.transitionToRoute('model.index'); }); } @@ -922,7 +922,7 @@ var Model = Ember.Object.extend(Ember.Evented, { App.ModelViewRoute = Ember.Route.extend({ actions: { reload: function() { - this.get('model').reload(); + this.controller.get('model').reload(); } } }); From a23e0dfc05dc6675b9a36f31ead8f09fcaccfe7f Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 25 Jun 2014 13:41:25 -0400 Subject: [PATCH 0212/2527] cleanup: align es6 (and other coding patterns) with ember's own --- packages/ember-data/lib/adapters.js | 5 +- .../lib/adapters/fixture_adapter.js | 9 ++- .../ember-data/lib/adapters/rest_adapter.js | 4 +- packages/ember-data/lib/main.js | 23 ++++-- packages/ember-data/lib/serializers.js | 5 +- .../lib/serializers/json_serializer.js | 12 ++-- .../lib/serializers/rest_serializer.js | 8 +-- packages/ember-data/lib/system/adapter.js | 23 ++++-- .../lib/system/changes/relationship_change.js | 70 +++++++++---------- .../ember-data/lib/system/container_proxy.js | 8 +-- .../lib/system/debug/debug_adapter.js | 24 ++++--- .../ember-data/lib/system/debug/debug_info.js | 2 +- packages/ember-data/lib/system/model.js | 7 +- .../ember-data/lib/system/model/attributes.js | 6 +- .../ember-data/lib/system/model/errors.js | 7 +- packages/ember-data/lib/system/model/model.js | 9 +-- .../ember-data/lib/system/model/states.js | 3 +- .../lib/system/record_array_manager.js | 14 ++-- .../adapter_populated_record_array.js | 7 +- .../record_arrays/filtered_record_array.js | 4 +- .../lib/system/record_arrays/many_array.js | 4 +- .../lib/system/record_arrays/record_array.js | 9 ++- .../lib/system/relationship-meta.js | 2 +- .../ember-data/lib/system/relationships.js | 5 +- .../lib/system/relationships/belongs_to.js | 17 +++-- .../lib/system/relationships/ext.js | 14 ++-- .../lib/system/relationships/has_many.js | 13 +++- packages/ember-data/lib/system/store.js | 16 +++-- packages/ember-data/lib/transforms.js | 8 ++- packages/ember-data/lib/transforms/base.js | 5 +- packages/ember-data/lib/transforms/boolean.js | 3 +- packages/ember-data/lib/transforms/date.js | 56 ++++++++++----- packages/ember-data/lib/transforms/number.js | 5 +- packages/ember-data/lib/transforms/string.js | 7 +- 34 files changed, 244 insertions(+), 170 deletions(-) diff --git a/packages/ember-data/lib/adapters.js b/packages/ember-data/lib/adapters.js index 6042aa99f0b..052381fef5f 100644 --- a/packages/ember-data/lib/adapters.js +++ b/packages/ember-data/lib/adapters.js @@ -5,4 +5,7 @@ import FixtureAdapter from "./adapters/fixture_adapter"; import RESTAdapter from "./adapters/rest_adapter"; -export {RESTAdapter, FixtureAdapter}; +export { + RESTAdapter, + FixtureAdapter +}; diff --git a/packages/ember-data/lib/adapters/fixture_adapter.js b/packages/ember-data/lib/adapters/fixture_adapter.js index fc668adbf6b..adf0541f5e6 100644 --- a/packages/ember-data/lib/adapters/fixture_adapter.js +++ b/packages/ember-data/lib/adapters/fixture_adapter.js @@ -2,8 +2,9 @@ @module ember-data */ -var get = Ember.get, fmt = Ember.String.fmt, - indexOf = Ember.EnumerableUtils.indexOf; +var get = Ember.get; +var fmt = Ember.String.fmt; +var indexOf = Ember.EnumerableUtils.indexOf; var counter = 0; @@ -26,7 +27,7 @@ import Adapter from "../system/adapter"; @namespace DS @extends DS.Adapter */ -var FixtureAdapter = Adapter.extend({ +export default Adapter.extend({ // by default, fixtures are already in normalized form serializer: null, @@ -338,5 +339,3 @@ var FixtureAdapter = Adapter.extend({ }, "DS: FixtureAdapter#simulateRemoteCall"); } }); - -export default FixtureAdapter; diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index e233a4e84c9..87318bbd424 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -139,7 +139,7 @@ var forEach = Ember.ArrayPolyfills.forEach; @namespace DS @extends DS.Adapter */ -var RESTAdapter = Adapter.extend({ +export default Adapter.extend({ defaultSerializer: '-rest', /** Endpoint paths can be prefixed with a `namespace` by setting the namespace @@ -651,5 +651,3 @@ var RESTAdapter = Adapter.extend({ } }); - -export default RESTAdapter; diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index 2fd77b8954f..bde44e19cf6 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -11,8 +11,17 @@ Ember.RSVP.Promise.cast = Ember.RSVP.Promise.cast || Ember.RSVP.resolve; import DS from "./core"; import "./ext/date"; -import {Store, PromiseArray, PromiseObject} from "./system/store"; -import {Model, Errors, RootState, attr} from "./system/model"; +import { + Store, + PromiseArray, + PromiseObject +} from "./system/store"; +import { + Model, + Errors, + RootState, + attr +} from "./system/model"; import { AttributeChange, RelationshipChange, @@ -23,7 +32,10 @@ import { OneToOneChange, ManyToManyChange } from "./system/changes"; -import {InvalidError, Adapter} from "./system/adapter"; +import { + InvalidError, + Adapter +} from "./system/adapter"; import DebugAdapter from "./system/debug"; import { RecordArray, @@ -32,7 +44,10 @@ import { ManyArray } from "./system/record_arrays"; import RecordArrayManager from "./system/record_array_manager"; -import {RESTAdapter, FixtureAdapter} from "./adapters"; +import { + RESTAdapter, + FixtureAdapter +} from "./adapters"; import JSONSerializer from "./serializers/json_serializer"; import RESTSerializer from "./serializers/rest_serializer"; import "../../ember-inflector/lib/main"; diff --git a/packages/ember-data/lib/serializers.js b/packages/ember-data/lib/serializers.js index 0a78729af51..79652eb07de 100644 --- a/packages/ember-data/lib/serializers.js +++ b/packages/ember-data/lib/serializers.js @@ -1,4 +1,7 @@ import JSONSerializer from "./serializers/json_serializer"; import RESTSerializer from "./serializers/rest_serializer"; -export { JSONSerializer, RESTSerializer }; +export { + JSONSerializer, + RESTSerializer +}; diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 7dd5fce76a8..d0ab9e77efa 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -1,6 +1,8 @@ -import {RelationshipChange} from "../system/changes"; -var get = Ember.get, set = Ember.set, isNone = Ember.isNone, - map = Ember.ArrayPolyfills.map; +import { RelationshipChange } from "../system/changes"; +var get = Ember.get; +var set = Ember.set; +var isNone = Ember.isNone; +var map = Ember.ArrayPolyfills.map; /** In Ember Data a Serializer is used to serialize and deserialize @@ -17,7 +19,7 @@ var get = Ember.get, set = Ember.set, isNone = Ember.isNone, @class JSONSerializer @namespace DS */ -var JSONSerializer = Ember.Object.extend({ +export default Ember.Object.extend({ /** The primaryKey is used when serializing and deserializing data. Ember Data always uses the `id` property to store the id of @@ -807,5 +809,3 @@ var JSONSerializer = Ember.Object.extend({ return transform; } }); - -export default JSONSerializer; diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index cadc55d95ee..f3cc1cfbcc0 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -6,10 +6,10 @@ import JSONSerializer from "./json_serializer"; var get = Ember.get, set = Ember.set; var forEach = Ember.ArrayPolyfills.forEach; var map = Ember.ArrayPolyfills.map; - -import {singularize} from "ember-inflector/lib/system/string"; var camelize = Ember.String.camelize; +import { singularize } from "ember-inflector/lib/system/string"; + function coerceId(id) { return id == null ? null : id+''; } @@ -54,7 +54,7 @@ function coerceId(id) { @namespace DS @extends DS.JSONSerializer */ -var RESTSerializer = JSONSerializer.extend({ +export default JSONSerializer.extend({ /** If you want to do normalizations specific to some part of the payload, you can specify those under `normalizeHash`. @@ -784,5 +784,3 @@ var RESTSerializer = JSONSerializer.extend({ json[key + "Type"] = belongsTo.constructor.typeKey; } }); - -export default RESTSerializer; diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 52e9dd9534d..f7ab5450f90 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -2,10 +2,19 @@ @module ember-data */ -var get = Ember.get, set = Ember.set; +var get = Ember.get; +var set = Ember.set; var map = Ember.ArrayPolyfills.map; -var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; +var errorProps = [ + 'description', + 'fileName', + 'lineNumber', + 'message', + 'name', + 'number', + 'stack' +]; /** A `DS.InvalidError` is used by an adapter to signal the external API @@ -47,14 +56,15 @@ var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'n @class InvalidError @namespace DS */ -var InvalidError = function(errors) { +function InvalidError(errors) { var tmp = Error.prototype.constructor.call(this, "The backend rejected the commit because it was invalid: " + Ember.inspect(errors)); this.errors = errors; for (var i=0, l=errorProps.length; i self.attributeLimit) { return false; } var desc = capitalize(underscore(name).replace('_', ' ')); @@ -40,8 +47,8 @@ var DebugAdapter = Ember.DataAdapter.extend({ }, getRecordColumnValues: function(record) { - var self = this, count = 0, - columnValues = { id: get(record, 'id') }; + var self = this, count = 0; + var columnValues = { id: get(record, 'id') }; record.eachAttribute(function(key) { if (count++ > self.attributeLimit) { @@ -54,7 +61,8 @@ var DebugAdapter = Ember.DataAdapter.extend({ }, getRecordKeywords: function(record) { - var keywords = [], keys = Ember.A(['id']); + var keywords = []; + var keys = Ember.A(['id']); record.eachAttribute(function(key) { keys.push(key); }); @@ -108,5 +116,3 @@ var DebugAdapter = Ember.DataAdapter.extend({ } }); - -export default DebugAdapter; diff --git a/packages/ember-data/lib/system/debug/debug_info.js b/packages/ember-data/lib/system/debug/debug_info.js index a5a1f4bdb2a..fefd94183c1 100644 --- a/packages/ember-data/lib/system/debug/debug_info.js +++ b/packages/ember-data/lib/system/debug/debug_info.js @@ -1,4 +1,4 @@ -import {Model} from "../model"; +import { Model } from "../model"; Model.reopen({ diff --git a/packages/ember-data/lib/system/model.js b/packages/ember-data/lib/system/model.js index 646c51bccb7..cc36b5f433d 100644 --- a/packages/ember-data/lib/system/model.js +++ b/packages/ember-data/lib/system/model.js @@ -7,4 +7,9 @@ import attr from "./model/attributes"; import RootState from "./model/states"; import Errors from "./model/errors"; -export {Model, RootState, attr, Errors}; +export { + Model, + RootState, + attr, + Errors +}; diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 8e1da13fa27..5eb5937902f 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -264,7 +264,7 @@ function getValue(record, key) { @return {Attribute} */ -function attr(type, options) { +export default function attr(type, options) { options = options || {}; var meta = { @@ -302,6 +302,4 @@ function attr(type, options) { // invalidated from the state manager's setData // event. }).meta(meta); -} - -export default attr; +}; diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index c2e830fa654..7ed82ae7b47 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -1,4 +1,5 @@ -var get = Ember.get, isEmpty = Ember.isEmpty; +var get = Ember.get; +var isEmpty = Ember.isEmpty; var map = Ember.EnumerableUtils.map; /** @@ -76,7 +77,7 @@ var map = Ember.EnumerableUtils.map; @uses Ember.Enumerable @uses Ember.Evented */ -var Errors = Ember.Object.extend(Ember.Enumerable, Ember.Evented, { +export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { /** Register with target handler @@ -337,5 +338,3 @@ var Errors = Ember.Object.extend(Ember.Enumerable, Ember.Evented, { return !isEmpty(this.errorsFor(attribute)); } }); - -export default Errors; diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index a8971983eaa..fbb397e91a7 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1,13 +1,14 @@ import RootState from "./states"; import Errors from "./errors"; -import {PromiseObject} from "../store"; +import { PromiseObject } from "../store"; /** @module ember-data */ -var get = Ember.get, set = Ember.set, - merge = Ember.merge, - Promise = Ember.RSVP.Promise; +var get = Ember.get; +var set = Ember.set; +var merge = Ember.merge; +var Promise = Ember.RSVP.Promise; var JSONSerializer; var retrieveFromCurrentState = Ember.computed('currentState', function(key, value) { diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index 203c894d6bf..396478dfc33 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -2,7 +2,8 @@ @module ember-data */ -var get = Ember.get, set = Ember.set; +var get = Ember.get; +var set = Ember.set; /* This file encapsulates the various states that a record can transition through during its lifecycle. diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index c45c940c9fa..d42de47cd5f 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -2,8 +2,14 @@ @module ember-data */ -import {RecordArray, FilteredRecordArray, AdapterPopulatedRecordArray, ManyArray} from "./record_arrays"; -var get = Ember.get, set = Ember.set; +import { + RecordArray, + FilteredRecordArray, + AdapterPopulatedRecordArray, + ManyArray +} from "./record_arrays"; +var get = Ember.get; +var set = Ember.set; var forEach = Ember.EnumerableUtils.forEach; /** @@ -12,7 +18,7 @@ var forEach = Ember.EnumerableUtils.forEach; @private @extends Ember.Object */ -var RecordArrayManager = Ember.Object.extend({ +export default Ember.Object.extend({ init: function() { this.filteredRecordArrays = Ember.MapWithDefault.create({ defaultValue: function() { return []; } @@ -297,5 +303,3 @@ function flatten(list) { return result; } - -export default RecordArrayManager; diff --git a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js index 4a3d17cc8c7..636e6ba9be0 100644 --- a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js @@ -3,7 +3,8 @@ import RecordArray from "./record_array"; @module ember-data */ -var get = Ember.get, set = Ember.set; +var get = Ember.get; +var set = Ember.set; /** Represents an ordered list of records whose order and membership is @@ -15,7 +16,7 @@ var get = Ember.get, set = Ember.set; @namespace DS @extends DS.RecordArray */ -var AdapterPopulatedRecordArray = RecordArray.extend({ +export default RecordArray.extend({ query: null, replace: function() { @@ -48,5 +49,3 @@ var AdapterPopulatedRecordArray = RecordArray.extend({ Ember.run.once(this, 'trigger', 'didLoad'); } }); - -export default AdapterPopulatedRecordArray; diff --git a/packages/ember-data/lib/system/record_arrays/filtered_record_array.js b/packages/ember-data/lib/system/record_arrays/filtered_record_array.js index 43b61818d2b..037a0e92d13 100644 --- a/packages/ember-data/lib/system/record_arrays/filtered_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/filtered_record_array.js @@ -16,7 +16,7 @@ var get = Ember.get; @namespace DS @extends DS.RecordArray */ -var FilteredRecordArray = RecordArray.extend({ +export default RecordArray.extend({ /** The filterFunction is a function used to test records from the store to determine if they should be part of the record array. @@ -64,5 +64,3 @@ var FilteredRecordArray = RecordArray.extend({ Ember.run.once(this, this._updateFilter); }, 'filterFunction') }); - -export default FilteredRecordArray; diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index b7d470d40eb..90eb3fa9bef 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -48,7 +48,7 @@ function sync(change) { @namespace DS @extends DS.RecordArray */ -var ManyArray = RecordArray.extend({ +export default RecordArray.extend({ init: function() { this._super.apply(this, arguments); this._changesToSync = Ember.OrderedSet.create(); @@ -230,5 +230,3 @@ var ManyArray = RecordArray.extend({ return record; } }); - -export default ManyArray; diff --git a/packages/ember-data/lib/system/record_arrays/record_array.js b/packages/ember-data/lib/system/record_arrays/record_array.js index 5cbc9ab27b2..5d3d1677dce 100644 --- a/packages/ember-data/lib/system/record_arrays/record_array.js +++ b/packages/ember-data/lib/system/record_arrays/record_array.js @@ -2,8 +2,9 @@ @module ember-data */ -import {PromiseArray} from "../store"; -var get = Ember.get, set = Ember.set; +import { PromiseArray } from "../store"; +var get = Ember.get; +var set = Ember.set; /** A record array is an array that contains records of a certain type. The record @@ -18,7 +19,7 @@ var get = Ember.get, set = Ember.set; @uses Ember.Evented */ -var RecordArray = Ember.ArrayProxy.extend(Ember.Evented, { +export default Ember.ArrayProxy.extend(Ember.Evented, { /** The model type contained by this record array. @@ -181,5 +182,3 @@ var RecordArray = Ember.ArrayProxy.extend(Ember.Evented, { this._super(); } }); - -export default RecordArray; diff --git a/packages/ember-data/lib/system/relationship-meta.js b/packages/ember-data/lib/system/relationship-meta.js index cd4904f8b87..7d3eedb18b7 100644 --- a/packages/ember-data/lib/system/relationship-meta.js +++ b/packages/ember-data/lib/system/relationship-meta.js @@ -1,4 +1,4 @@ -import {singularize} from "../../../ember-inflector/lib/system"; +import { singularize } from "../../../ember-inflector/lib/system"; export function typeForRelationshipMeta(store, meta) { var typeKey, type; diff --git a/packages/ember-data/lib/system/relationships.js b/packages/ember-data/lib/system/relationships.js index f0b24c0356e..0b3c4fd9d94 100644 --- a/packages/ember-data/lib/system/relationships.js +++ b/packages/ember-data/lib/system/relationships.js @@ -7,4 +7,7 @@ import hasMany from "./relationships/has_many"; import "../system/relationships/ext"; -export {belongsTo, hasMany}; +export { + belongsTo, + hasMany +}; diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index 298b801997f..46bc6bbc1dc 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -1,12 +1,15 @@ -var get = Ember.get, set = Ember.set, - isNone = Ember.isNone; - +var get = Ember.get; +var set = Ember.set; +var isNone = Ember.isNone; var Promise = Ember.RSVP.Promise; -import {Model} from "../model"; -import {PromiseObject} from "../store"; -import {RelationshipChange} from "../changes"; -import {relationshipFromMeta, typeForRelationshipMeta} from "../relationship-meta"; +import { Model } from "../model"; +import { PromiseObject } from "../store"; +import { RelationshipChange } from "../changes"; +import { + relationshipFromMeta, + typeForRelationshipMeta +} from "../relationship-meta"; /** @module ember-data diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 9813439d1aa..df58aba2e11 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -1,8 +1,12 @@ -import {singularize} from "../../../../ember-inflector/lib/system"; -import {typeForRelationshipMeta, relationshipFromMeta} from "../relationship-meta"; -import {Model} from "../model"; - -var get = Ember.get, set = Ember.set; +import { singularize } from "../../../../ember-inflector/lib/system"; +import { + typeForRelationshipMeta, + relationshipFromMeta +} from "../relationship-meta"; +import { Model } from "../model"; + +var get = Ember.get; +var set = Ember.set; /** @module ember-data diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index 420b73f5023..a22eaddc16d 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -2,9 +2,16 @@ @module ember-data */ -import {PromiseArray} from "../store"; -var get = Ember.get, set = Ember.set, setProperties = Ember.setProperties; -import {relationshipFromMeta, typeForRelationshipMeta} from "../relationship-meta"; +import { PromiseArray } from "../store"; + +import { + relationshipFromMeta, + typeForRelationshipMeta +} from "../relationship-meta"; + +var get = Ember.get; +var set = Ember.set; +var setProperties = Ember.setProperties; function asyncHasMany(type, options, meta) { return Ember.computed('data', function(key) { diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index e2d35961847..51afb842aca 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -5,9 +5,13 @@ @module ember-data */ -import {InvalidError, Adapter} from "./adapter"; -import {singularize} from "ember-inflector/lib/system/string"; -var get = Ember.get, set = Ember.set; +import { + InvalidError, + Adapter +} from "./adapter"; +import { singularize } from "ember-inflector/lib/system/string"; +var get = Ember.get; +var set = Ember.set; var once = Ember.run.once; var isNone = Ember.isNone; var forEach = Ember.EnumerableUtils.forEach; @@ -1846,5 +1850,9 @@ function _commit(adapter, store, operation, record) { }, label); } -export {Store, PromiseArray, PromiseObject}; +export { + Store, + PromiseArray, + PromiseObject +}; export default Store; diff --git a/packages/ember-data/lib/transforms.js b/packages/ember-data/lib/transforms.js index b91ea6c1caf..4372e14dbd8 100644 --- a/packages/ember-data/lib/transforms.js +++ b/packages/ember-data/lib/transforms.js @@ -4,4 +4,10 @@ import DateTransform from "./transforms/date"; import StringTransform from "./transforms/string"; import BooleanTransform from "./transforms/boolean"; -export { Transform, NumberTransform, DateTransform, StringTransform, BooleanTransform }; +export { + Transform, + NumberTransform, + DateTransform, + StringTransform, + BooleanTransform +}; diff --git a/packages/ember-data/lib/transforms/base.js b/packages/ember-data/lib/transforms/base.js index 42bafab90af..7e0ce26e73f 100644 --- a/packages/ember-data/lib/transforms/base.js +++ b/packages/ember-data/lib/transforms/base.js @@ -32,7 +32,7 @@ @class Transform @namespace DS */ -var Transform = Ember.Object.extend({ +export default Ember.Object.extend({ /** When given a deserialized value from a record attribute this method must return the serialized value. @@ -68,7 +68,4 @@ var Transform = Ember.Object.extend({ @return The deserialized value */ deserialize: Ember.required() - }); - -export default Transform; diff --git a/packages/ember-data/lib/transforms/boolean.js b/packages/ember-data/lib/transforms/boolean.js index 5e29db0eb4e..b2989a122c4 100644 --- a/packages/ember-data/lib/transforms/boolean.js +++ b/packages/ember-data/lib/transforms/boolean.js @@ -21,7 +21,7 @@ import Transform from "./base"; @extends DS.Transform @namespace DS */ -var BooleanTransform = Transform.extend({ +export default Transform.extend({ deserialize: function(serialized) { var type = typeof serialized; @@ -40,4 +40,3 @@ var BooleanTransform = Transform.extend({ return Boolean(deserialized); } }); -export default BooleanTransform; diff --git a/packages/ember-data/lib/transforms/date.js b/packages/ember-data/lib/transforms/date.js index 44a45f26ea0..65f3c2f7d3c 100644 --- a/packages/ember-data/lib/transforms/date.js +++ b/packages/ember-data/lib/transforms/date.js @@ -18,7 +18,12 @@ @namespace DS */ import Transform from "./base"; -var DateTransform = Transform.extend({ + +function pad(num) { + return num < 10 ? "0"+num : ""+num; +} + +export default Transform.extend({ deserialize: function(serialized) { var type = typeof serialized; @@ -38,21 +43,37 @@ var DateTransform = Transform.extend({ serialize: function(date) { if (date instanceof Date) { - var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; - var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; - - var pad = function(num) { - return num < 10 ? "0"+num : ""+num; - }; - - var utcYear = date.getUTCFullYear(), - utcMonth = date.getUTCMonth(), - utcDayOfMonth = date.getUTCDate(), - utcDay = date.getUTCDay(), - utcHours = date.getUTCHours(), - utcMinutes = date.getUTCMinutes(), - utcSeconds = date.getUTCSeconds(); + var days = [ + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat" + ]; + var months = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + ]; + var utcYear = date.getUTCFullYear(); + var utcMonth = date.getUTCMonth(); + var utcDayOfMonth = date.getUTCDate(); + var utcDay = date.getUTCDay(); + var utcHours = date.getUTCHours(); + var utcMinutes = date.getUTCMinutes(); + var utcSeconds = date.getUTCSeconds(); var dayOfWeek = days[utcDay]; var dayOfMonth = pad(utcDayOfMonth); @@ -63,8 +84,5 @@ var DateTransform = Transform.extend({ } else { return null; } - } - + } }); - -export default DateTransform; diff --git a/packages/ember-data/lib/transforms/number.js b/packages/ember-data/lib/transforms/number.js index 9053ee7ae13..08d91a60962 100644 --- a/packages/ember-data/lib/transforms/number.js +++ b/packages/ember-data/lib/transforms/number.js @@ -23,8 +23,7 @@ var empty = Ember.isEmpty; @extends DS.Transform @namespace DS */ -var NumberTransform = Transform.extend({ - +export default Transform.extend({ deserialize: function(serialized) { return empty(serialized) ? null : Number(serialized); }, @@ -33,5 +32,3 @@ var NumberTransform = Transform.extend({ return empty(deserialized) ? null : Number(deserialized); } }); - -export default NumberTransform; diff --git a/packages/ember-data/lib/transforms/string.js b/packages/ember-data/lib/transforms/string.js index 82d7a9d95a7..7f71ba64b73 100644 --- a/packages/ember-data/lib/transforms/string.js +++ b/packages/ember-data/lib/transforms/string.js @@ -22,16 +22,11 @@ var none = Ember.isNone; @extends DS.Transform @namespace DS */ -var StringTransform = Transform.extend({ - +export default Transform.extend({ deserialize: function(serialized) { return none(serialized) ? null : String(serialized); }, - serialize: function(deserialized) { return none(deserialized) ? null : String(deserialized); } - }); - -export default StringTransform; From 0c2e3a178b2dd9812285a11768f5f3d650ec8d10 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 26 Jun 2014 12:43:49 -0400 Subject: [PATCH 0213/2527] improve debug ergonomics (as I debug) * re-using argument variables makes it quite hard to see the original value, also it has some negative performance side-effects. * using the comma operator for long variable declarations, especially if they include method invocations makes it impossible to easily set breakpoints. --- .../lib/serializers/rest_serializer.js | 71 ++++++++++--------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index f3cc1cfbcc0..1ef00b91e65 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -3,7 +3,8 @@ */ import JSONSerializer from "./json_serializer"; -var get = Ember.get, set = Ember.set; +var get = Ember.get; +var set = Ember.set; var forEach = Ember.ArrayPolyfills.forEach; var map = Ember.ArrayPolyfills.map; var camelize = Ember.String.camelize; @@ -11,7 +12,7 @@ var camelize = Ember.String.camelize; import { singularize } from "ember-inflector/lib/system/string"; function coerceId(id) { - return id == null ? null : id+''; + return id == null ? null : id + ''; } /** @@ -319,32 +320,33 @@ export default JSONSerializer.extend({ @param {String} recordId @return {Object} the primary response to the original request */ - extractSingle: function(store, primaryType, payload, recordId) { - payload = this.normalizePayload(payload); - var primaryTypeName = primaryType.typeKey, - primaryRecord; + extractSingle: function(store, primaryType, rawPayload, recordId) { + var payload = this.normalizePayload(rawPayload); + var primaryTypeName = primaryType.typeKey; + var primaryRecord; for (var prop in payload) { - var typeName = this.typeForRoot(prop), - type = store.modelFor(typeName), - isPrimary = type.typeKey === primaryTypeName; + var typeName = this.typeForRoot(prop); + var type = store.modelFor(typeName); + var isPrimary = type.typeKey === primaryTypeName; + var value = payload[prop]; // legacy support for singular resources - if (isPrimary && Ember.typeOf(payload[prop]) !== "array" ) { - primaryRecord = this.normalize(primaryType, payload[prop], prop); + if (isPrimary && Ember.typeOf(value) !== "array" ) { + primaryRecord = this.normalize(primaryType, value, prop); continue; } /*jshint loopfunc:true*/ - forEach.call(payload[prop], function(hash) { - var typeName = this.typeForRoot(prop), - type = store.modelFor(typeName), - typeSerializer = store.serializerFor(type); + forEach.call(value, function(hash) { + var typeName = this.typeForRoot(prop); + var type = store.modelFor(typeName); + var typeSerializer = store.serializerFor(type); hash = typeSerializer.normalize(type, hash, prop); - var isFirstCreatedRecord = isPrimary && !recordId && !primaryRecord, - isUpdatedRecord = isPrimary && coerceId(hash.id) === recordId; + var isFirstCreatedRecord = isPrimary && !recordId && !primaryRecord; + var isUpdatedRecord = isPrimary && coerceId(hash.id) === recordId; // find the primary record. // @@ -463,25 +465,24 @@ export default JSONSerializer.extend({ @return {Array} The primary array that was returned in response to the original query. */ - extractArray: function(store, primaryType, payload) { - payload = this.normalizePayload(payload); - - var primaryTypeName = primaryType.typeKey, - primaryArray; + extractArray: function(store, primaryType, rawPayload) { + var payload = this.normalizePayload(rawPayload); + var primaryTypeName = primaryType.typeKey; + var primaryArray; for (var prop in payload) { - var typeKey = prop, - forcedSecondary = false; + var typeKey = prop; + var forcedSecondary = false; if (prop.charAt(0) === '_') { forcedSecondary = true; typeKey = prop.substr(1); } - var typeName = this.typeForRoot(typeKey), - type = store.modelFor(typeName), - typeSerializer = store.serializerFor(type), - isPrimary = (!forcedSecondary && (type.typeKey === primaryTypeName)); + var typeName = this.typeForRoot(typeKey); + var type = store.modelFor(typeName); + var typeSerializer = store.serializerFor(type); + var isPrimary = (!forcedSecondary && (type.typeKey === primaryTypeName)); /*jshint loopfunc:true*/ var normalizedArray = map.call(payload[prop], function(hash) { @@ -529,13 +530,13 @@ export default JSONSerializer.extend({ @param {DS.Store} store @param {Object} payload */ - pushPayload: function(store, payload) { - payload = this.normalizePayload(payload); + pushPayload: function(store, rawPayload) { + var payload = this.normalizePayload(rawPayload); for (var prop in payload) { - var typeName = this.typeForRoot(prop), - type = store.modelFor(typeName), - typeSerializer = store.serializerFor(type); + var typeName = this.typeForRoot(prop); + var type = store.modelFor(typeName); + var typeSerializer = store.serializerFor(type); /*jshint loopfunc:true*/ var normalizedArray = map.call(Ember.makeArray(payload[prop]), function(hash) { @@ -778,8 +779,8 @@ export default JSONSerializer.extend({ @param {Object} relationship */ serializePolymorphicType: function(record, json, relationship) { - var key = relationship.key, - belongsTo = get(record, key); + var key = relationship.key; + var belongsTo = get(record, key); key = this.keyForAttribute ? this.keyForAttribute(key) : key; json[key + "Type"] = belongsTo.constructor.typeKey; } From a73edba3785046735483394a0299bdba6dd54cdd Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 26 Jun 2014 22:51:33 -0400 Subject: [PATCH 0214/2527] more breakpoint friendly refactoring --- .../lib/system/active_model_serializer.js | 2 +- .../lib/serializers/json_serializer.js | 4 +- .../lib/system/relationships/belongs_to.js | 43 +++-- packages/ember-data/lib/system/store.js | 178 +++++++++--------- 4 files changed, 115 insertions(+), 112 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index d6b8e9b0ee1..799d74fa081 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -255,10 +255,10 @@ var ActiveModelSerializer = RESTSerializer.extend({ @private */ normalizeRelationships: function(type, hash) { - var payloadKey, payload; if (this.keyForRelationship) { type.eachRelationship(function(key, relationship) { + var payloadKey, payload; if (relationship.options.polymorphic) { payloadKey = this.keyForAttribute(key); payload = hash[payloadKey]; diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index d0ab9e77efa..e36127dd6e3 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -365,7 +365,8 @@ export default Ember.Object.extend({ */ serializeAttribute: function(record, json, key, attribute) { var attrs = get(this, 'attrs'); - var value = get(record, key), type = attribute.type; + var value = get(record, key); + var type = attribute.type; if (type) { var transform = this.transformFor(type); @@ -406,7 +407,6 @@ export default Ember.Object.extend({ */ serializeBelongsTo: function(record, json, relationship) { var key = relationship.key; - var belongsTo = get(record, key); key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo") : key; diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index 46bc6bbc1dc..2ba087d4043 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -3,13 +3,13 @@ var set = Ember.set; var isNone = Ember.isNone; var Promise = Ember.RSVP.Promise; -import { Model } from "../model"; -import { PromiseObject } from "../store"; -import { RelationshipChange } from "../changes"; +import { Model } from '../model'; +import { PromiseObject } from '../store'; +import { RelationshipChange } from '../changes'; import { relationshipFromMeta, typeForRelationshipMeta -} from "../relationship-meta"; +} from '../relationship-meta'; /** @module ember-data @@ -17,10 +17,10 @@ import { function asyncBelongsTo(type, options, meta) { return Ember.computed('data', function(key, value) { - var data = get(this, 'data'), - store = get(this, 'store'), - promiseLabel = "DS: Async belongsTo " + this + " : " + key, - promise; + var data = get(this, 'data'); + var store = get(this, 'store'); + var promiseLabel = "DS: Async belongsTo " + this + " : " + key; + var promise; meta.key = key; @@ -31,10 +31,10 @@ function asyncBelongsTo(type, options, meta) { }); } - var link = data.links && data.links[key], - belongsTo = data[key]; + var link = data.links && data.links[key]; + var belongsTo = data[key]; - if(!isNone(belongsTo)) { + if (!isNone(belongsTo)) { promise = store.fetchRecord(belongsTo) || Promise.cast(belongsTo, promiseLabel); return PromiseObject.create({ promise: promise @@ -120,8 +120,9 @@ function belongsTo(type, options) { } return Ember.computed('data', function(key, value) { - var data = get(this, 'data'), - store = get(this, 'store'), belongsTo, typeClass; + var data = get(this, 'data'); + var store = get(this, 'store'); + var belongsTo, typeClass; if (typeof type === 'string') { typeClass = store.modelFor(type); @@ -165,8 +166,12 @@ Model.reopen({ var oldParent = get(record, key); if (oldParent) { - var store = get(record, 'store'), - change = RelationshipChange.createChange(record, oldParent, store, { key: key, kind: "belongsTo", changeType: "remove" }); + var store = get(record, 'store'); + var change = RelationshipChange.createChange(record, oldParent, store, { + key: key, + kind: 'belongsTo', + changeType: 'remove' + }); change.sync(); this._changesToSync[key] = change; @@ -186,8 +191,12 @@ Model.reopen({ var newParent = get(record, key); if (newParent) { - var store = get(record, 'store'), - change = RelationshipChange.createChange(record, newParent, store, { key: key, kind: "belongsTo", changeType: "add" }); + var store = get(record, 'store'); + var change = RelationshipChange.createChange(record, newParent, store, { + key: key, + kind: 'belongsTo', + changeType: 'add' + }); change.sync(); } diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 51afb842aca..9797cf76c0b 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -234,10 +234,9 @@ Store = Ember.Object.extend({ newly created record. @return {DS.Model} record */ - createRecord: function(type, properties) { - type = this.modelFor(type); - - properties = copy(properties) || {}; + createRecord: function(typeName, inputPropoperties) { + var type = this.modelFor(typeName); + var properties = copy(inputPropoperties) || {}; // If the passed properties do not include a primary key, // give the adapter an opportunity to generate one. Typically, @@ -404,9 +403,8 @@ Store = Ember.Object.extend({ @param {String|Integer} id @return {Promise} promise */ - findById: function(type, id) { - type = this.modelFor(type); - + findById: function(typeName, id) { + var type = this.modelFor(typeName); var record = this.recordForId(type, id); var fetchedRecord = this.fetchRecord(record); @@ -426,6 +424,7 @@ Store = Ember.Object.extend({ findByIds: function(type, ids) { var store = this; var promiseLabel = "DS: Store#findByIds " + type; + return promiseArray(Ember.RSVP.all(map(ids, function(id) { return store.findById(type, id); })).then(Ember.A, null, "DS: Store#findByIds of " + type + " complete")); @@ -446,9 +445,8 @@ Store = Ember.Object.extend({ if (record._loadingPromise) { return record._loadingPromise; } if (!get(record, 'isEmpty')) { return null; } - var type = record.constructor, - id = get(record, 'id'); - + var type = record.constructor; + var id = get(record, 'id'); var adapter = this.adapterFor(type); Ember.assert("You tried to find a record but you have no adapter (for " + type + ")", adapter); @@ -470,7 +468,7 @@ Store = Ember.Object.extend({ ```js var post = store.getById('post', 1); - + post.get('id'); // 1 ``` @@ -500,9 +498,9 @@ Store = Ember.Object.extend({ @return {Promise} promise */ reloadRecord: function(record) { - var type = record.constructor, - adapter = this.adapterFor(type), - id = get(record, 'id'); + var type = record.constructor; + var adapter = this.adapterFor(type); + var id = get(record, 'id'); Ember.assert("You cannot reload a record without an ID", id); Ember.assert("You tried to reload a record but you have no adapter (for " + type + ")", adapter); @@ -566,9 +564,9 @@ Store = Ember.Object.extend({ @param {String|Integer} id @return {Boolean} */ - hasRecordForId: function(type, id) { - id = coerceId(id); - type = this.modelFor(type); + hasRecordForId: function(typeName, inputId) { + var type = this.modelFor(typeName); + var id = coerceId(inputId); return !!this.typeMapFor(type).idToRecord[id]; }, @@ -582,10 +580,9 @@ Store = Ember.Object.extend({ @param {String|Integer} id @return {DS.Model} record */ - recordForId: function(type, id) { - type = this.modelFor(type); - - id = coerceId(id); + recordForId: function(typeName, inputId) { + var type = this.modelFor(typeName); + var id = coerceId(inputId); var idToRecord = this.typeMapFor(type).idToRecord; var record = idToRecord[id]; @@ -605,13 +602,11 @@ Store = Ember.Object.extend({ @param {Resolver} resolver @return {DS.ManyArray} records */ - findMany: function(owner, records, type, resolver) { - type = this.modelFor(type); - - records = Ember.A(records); - - var unloadedRecords = records.filterBy('isEmpty', true), - manyArray = this.recordArrayManager.createManyArray(type, records); + findMany: function(owner, inputRecords, typeName, resolver) { + var type = this.modelFor(typeName); + var records = Ember.A(inputRecords); + var unloadedRecords = records.filterBy('isEmpty', true); + var manyArray = this.recordArrayManager.createManyArray(type, records); forEach(unloadedRecords, function(record) { record.loadingData(); @@ -697,9 +692,8 @@ Store = Ember.Object.extend({ @param {any} query an opaque query to be used by the adapter @return {Promise} promise */ - findQuery: function(type, query) { - type = this.modelFor(type); - + findQuery: function(typeName, query) { + var type = this.modelFor(typeName); var array = this.recordArrayManager .createAdapterPopulatedRecordArray(type, query); @@ -721,8 +715,8 @@ Store = Ember.Object.extend({ @param {String or subclass of DS.Model} type @return {DS.AdapterPopulatedRecordArray} */ - findAll: function(type) { - type = this.modelFor(type); + findAll: function(typeName) { + var type = this.modelFor(typeName); return this.fetchAll(type, this.all(type)); }, @@ -735,8 +729,8 @@ Store = Ember.Object.extend({ @return {Promise} promise */ fetchAll: function(type, array) { - var adapter = this.adapterFor(type), - sinceToken = this.typeMapFor(type).metadata.since; + var adapter = this.adapterFor(type); + var sinceToken = this.typeMapFor(type).metadata.since; set(array, 'isUpdating', true); @@ -775,11 +769,10 @@ Store = Ember.Object.extend({ @param {String or subclass of DS.Model} type @return {DS.RecordArray} */ - all: function(type) { - type = this.modelFor(type); - - var typeMap = this.typeMapFor(type), - findAllCache = typeMap.findAllCache; + all: function(typeName) { + var type = this.modelFor(typeName); + var typeMap = this.typeMapFor(type); + var findAllCache = typeMap.findAllCache; if (findAllCache) { return findAllCache; } @@ -973,9 +966,9 @@ Store = Ember.Object.extend({ this._pendingSave = []; forEach(pending, function(tuple) { - var record = tuple[0], resolver = tuple[1], - adapter = this.adapterFor(record.constructor), - operation; + var record = tuple[0], resolver = tuple[1]; + var adapter = this.adapterFor(record.constructor); + var operation; if (get(record, 'currentState.stateName') === 'root.deleted.saved') { return resolver.resolve(record); @@ -1053,8 +1046,8 @@ Store = Ember.Object.extend({ @param {Object} data */ updateId: function(record, data) { - var oldId = get(record, 'id'), - id = coerceId(data.id); + var oldId = get(record, 'id'); + var id = coerceId(data.id); Ember.assert("An adapter cannot assign a new id to a record that already has an id. " + record + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId); @@ -1072,9 +1065,9 @@ Store = Ember.Object.extend({ @return {Object} typeMap */ typeMapFor: function(type) { - var typeMaps = get(this, 'typeMaps'), - guid = Ember.guidFor(type), - typeMap; + var typeMaps = get(this, 'typeMaps'); + var guid = Ember.guidFor(type); + var typeMap; typeMap = typeMaps[guid]; @@ -1107,8 +1100,8 @@ Store = Ember.Object.extend({ the existing data, not replace it. */ _load: function(type, data, partial) { - var id = coerceId(data.id), - record = this.recordForId(type, id); + var id = coerceId(data.id); + var record = this.recordForId(type, id); record.setupData(data, partial); this.recordArrayManager.recordDidChange(record); @@ -1128,7 +1121,6 @@ Store = Ember.Object.extend({ modelFor: function(key) { var factory; - if (typeof key === 'string') { var normalizedKey = this.container.normalize('model:' + key); @@ -1208,14 +1200,14 @@ Store = Ember.Object.extend({ @return {DS.Model} the record that was created or updated. */ - push: function(type, data, _partial) { + push: function(typeName, data, _partial) { // _partial is an internal param used by `update`. // If passed, it means that the data should be // merged into the existing data, not replace it. - Ember.assert("You must include an `id` for " + type + " in a hash passed to `push`", data.id != null); + Ember.assert("You must include an `id` for " + typeName+ " in a hash passed to `push`", data.id != null); - type = this.modelFor(type); + var type = this.modelFor(typeName); // normalize relationship IDs into records data = normalizeRelationships(this, type, data); @@ -1269,13 +1261,15 @@ Store = Ember.Object.extend({ @param {String} type Optionally, a model used to determine which serializer will be used @param {Object} payload */ - pushPayload: function (type, payload) { + pushPayload: function (type, inputPayload) { var serializer; - if (!payload) { + var payload; + if (!inputPayload) { payload = type; serializer = defaultSerializer(this.container); Ember.assert("You cannot use `store#pushPayload` without a type unless your default serializer defines `pushPayload`", serializer.pushPayload); } else { + payload = inputPayload; serializer = this.serializerFor(type); } serializer.pushPayload(this, payload); @@ -1343,8 +1337,8 @@ Store = Ember.Object.extend({ @param {String or subclass of DS.Model} type @param {Object} metadata */ - metaForType: function(type, metadata) { - type = this.modelFor(type); + metaForType: function(typeName, metadata) { + var type = this.modelFor(typeName); Ember.merge(this.typeMapFor(type).metadata, metadata); }, @@ -1361,8 +1355,8 @@ Store = Ember.Object.extend({ @return {DS.Model} record */ buildRecord: function(type, id, data) { - var typeMap = this.typeMapFor(type), - idToRecord = typeMap.idToRecord; + var typeMap = this.typeMapFor(type); + var idToRecord = typeMap.idToRecord; Ember.assert('The id ' + id + ' has already been used with another record of type ' + type.toString() + '.', !id || !idToRecord.hasOwnProperty(id)); Ember.assert("`" + Ember.inspect(type)+ "` does not appear to be an ember-data model", (typeof type._create === 'function') ); @@ -1403,9 +1397,9 @@ Store = Ember.Object.extend({ @param {DS.Model} record */ dematerializeRecord: function(record) { - var type = record.constructor, - typeMap = this.typeMapFor(type), - id = get(record, 'id'); + var type = record.constructor; + var typeMap = this.typeMapFor(type); + var id = get(record, 'id'); record.updateRecordArrays(); @@ -1422,8 +1416,8 @@ Store = Ember.Object.extend({ // ........................ addRelationshipChangeFor: function(childRecord, childKey, parentRecord, parentKey, change) { - var clientId = childRecord.clientId, - parentClientId = parentRecord ? parentRecord : parentRecord; + var clientId = childRecord.clientId; + var parentClientId = parentRecord ? parentRecord : parentRecord; var key = childKey + parentKey; var changes = this._relationshipChanges; if (!(clientId in changes)) { @@ -1439,8 +1433,8 @@ Store = Ember.Object.extend({ }, removeRelationshipChangeFor: function(clientRecord, childKey, parentRecord, parentKey, type) { - var clientId = clientRecord.clientId, - parentClientId = parentRecord ? parentRecord.clientId : parentRecord; + var clientId = clientRecord.clientId; + var parentClientId = parentRecord ? parentRecord.clientId : parentRecord; var changes = this._relationshipChanges; var key = childKey + parentKey; if (!(clientId in changes) || !(parentClientId in changes[clientId]) || !(key in changes[clientId][parentClientId])){ @@ -1712,9 +1706,9 @@ function defaultSerializer(container) { } function serializerForAdapter(adapter, type) { - var serializer = adapter.serializer, - defaultSerializer = adapter.defaultSerializer, - container = adapter.container; + var serializer = adapter.serializer; + var defaultSerializer = adapter.defaultSerializer; + var container = adapter.container; if (container && serializer === undefined) { serializer = serializerFor(container, type.typeKey, defaultSerializer); @@ -1730,9 +1724,9 @@ function serializerForAdapter(adapter, type) { } function _find(adapter, store, type, id) { - var promise = adapter.find(store, type, id), - serializer = serializerForAdapter(adapter, type), - label = "DS: Handle Adapter#find of " + type + " with id: " + id; + var promise = adapter.find(store, type, id); + var serializer = serializerForAdapter(adapter, type); + var label = "DS: Handle Adapter#find of " + type + " with id: " + id; return Promise.cast(promise, label).then(function(adapterPayload) { Ember.assert("You made a request for a " + type.typeKey + " with id " + id + ", but the adapter's response did not have any data", adapterPayload); @@ -1747,9 +1741,9 @@ function _find(adapter, store, type, id) { } function _findMany(adapter, store, type, ids, owner) { - var promise = adapter.findMany(store, type, ids, owner), - serializer = serializerForAdapter(adapter, type), - label = "DS: Handle Adapter#findMany of " + type; + var promise = adapter.findMany(store, type, ids, owner); + var serializer = serializerForAdapter(adapter, type); + var label = "DS: Handle Adapter#findMany of " + type; return Promise.cast(promise, label).then(function(adapterPayload) { var payload = serializer.extract(store, type, adapterPayload, null, 'findMany'); @@ -1761,9 +1755,9 @@ function _findMany(adapter, store, type, ids, owner) { } function _findHasMany(adapter, store, record, link, relationship) { - var promise = adapter.findHasMany(store, record, link, relationship), - serializer = serializerForAdapter(adapter, relationship.type), - label = "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type; + var promise = adapter.findHasMany(store, record, link, relationship); + var serializer = serializerForAdapter(adapter, relationship.type); + var label = "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type; return Promise.cast(promise, label).then(function(adapterPayload) { var payload = serializer.extract(store, relationship.type, adapterPayload, null, 'findHasMany'); @@ -1776,9 +1770,9 @@ function _findHasMany(adapter, store, record, link, relationship) { } function _findBelongsTo(adapter, store, record, link, relationship) { - var promise = adapter.findBelongsTo(store, record, link, relationship), - serializer = serializerForAdapter(adapter, relationship.type), - label = "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type; + var promise = adapter.findBelongsTo(store, record, link, relationship); + var serializer = serializerForAdapter(adapter, relationship.type); + var label = "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type; return Promise.cast(promise, label).then(function(adapterPayload) { var payload = serializer.extract(store, relationship.type, adapterPayload, null, 'findBelongsTo'); @@ -1790,9 +1784,9 @@ function _findBelongsTo(adapter, store, record, link, relationship) { } function _findAll(adapter, store, type, sinceToken) { - var promise = adapter.findAll(store, type, sinceToken), - serializer = serializerForAdapter(adapter, type), - label = "DS: Handle Adapter#findAll of " + type; + var promise = adapter.findAll(store, type, sinceToken); + var serializer = serializerForAdapter(adapter, type); + var label = "DS: Handle Adapter#findAll of " + type; return Promise.cast(promise, label).then(function(adapterPayload) { var payload = serializer.extract(store, type, adapterPayload, null, 'findAll'); @@ -1806,9 +1800,9 @@ function _findAll(adapter, store, type, sinceToken) { } function _findQuery(adapter, store, type, query, recordArray) { - var promise = adapter.findQuery(store, type, query, recordArray), - serializer = serializerForAdapter(adapter, type), - label = "DS: Handle Adapter#findQuery of " + type; + var promise = adapter.findQuery(store, type, query, recordArray); + var serializer = serializerForAdapter(adapter, type); + var label = "DS: Handle Adapter#findQuery of " + type; return Promise.cast(promise, label).then(function(adapterPayload) { var payload = serializer.extract(store, type, adapterPayload, null, 'findQuery'); @@ -1821,10 +1815,10 @@ function _findQuery(adapter, store, type, query, recordArray) { } function _commit(adapter, store, operation, record) { - var type = record.constructor, - promise = adapter[operation](store, type, record), - serializer = serializerForAdapter(adapter, type), - label = "DS: Extract and notify about " + operation + " completion of " + record; + var type = record.constructor; + var promise = adapter[operation](store, type, record); + var serializer = serializerForAdapter(adapter, type); + var label = "DS: Extract and notify about " + operation + " completion of " + record; Ember.assert("Your adapter's '" + operation + "' method must return a promise, but it returned " + promise, isThenable(promise)); From 3caf340f1b2db0405b3e2ae6ba984530f71203bd Mon Sep 17 00:00:00 2001 From: Bill Heaton Date: Wed, 2 Jul 2014 12:13:39 -0700 Subject: [PATCH 0215/2527] [Bugfix] embedded records mixin: key variable needed to be declared --- .../activemodel-adapter/lib/system/embedded_records_mixin.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index e67c40fcb70..2cfb85dad6d 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -142,6 +142,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ var includeIds = hasSerializeIdsOption(attrs, attr); var includeRecords = hasSerializeRecordsOption(attrs, attr); var embeddedRecord = record.get(attr); + var key; if (includeIds) { key = this.keyForRelationship(attr, relationship.kind); if (!embeddedRecord) { @@ -150,7 +151,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ json[key] = get(embeddedRecord, 'id'); } } else if (includeRecords) { - var key = this.keyForRelationship(attr); + key = getKeyForAttribute.call(this, attr); if (!embeddedRecord) { json[key] = null; } else { From d8a09e76a82eec1f8ce0c234f7a0bf2b7e1f0107 Mon Sep 17 00:00:00 2001 From: Jonathan Jackson Date: Thu, 3 Jul 2014 16:06:25 -0400 Subject: [PATCH 0216/2527] Publish to canary branch of components/ember-data repo. --- .travis.yml | 4 +- Gruntfile.js | 10 +++-- bin/bower-ember-data-build | 50 +++++++++++++++++++++ config/package_manager_files/.gitignore | 5 +++ config/package_manager_files/Makefile | 8 ++++ config/package_manager_files/README.md | 12 +++++ config/package_manager_files/bower.json | 8 ++++ config/package_manager_files/component.json | 16 +++++++ config/package_manager_files/composer.json | 26 +++++++++++ config/package_manager_files/package.json | 12 +++++ lib/utilities/ember-data-version.js | 34 ++++++++++++++ package.json | 3 +- tasks/options/copy.js | 11 +++++ tasks/setVersionStamp.js | 11 ----- 14 files changed, 194 insertions(+), 16 deletions(-) create mode 100755 bin/bower-ember-data-build create mode 100644 config/package_manager_files/.gitignore create mode 100644 config/package_manager_files/Makefile create mode 100644 config/package_manager_files/README.md create mode 100644 config/package_manager_files/bower.json create mode 100644 config/package_manager_files/component.json create mode 100644 config/package_manager_files/composer.json create mode 100644 config/package_manager_files/package.json create mode 100644 lib/utilities/ember-data-version.js create mode 100644 tasks/options/copy.js delete mode 100644 tasks/setVersionStamp.js diff --git a/.travis.yml b/.travis.yml index 0ae97436e49..fbcf263ac57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,9 @@ node_js: install: - "bin/cached-npm install" - "bower install" -after_success: npm run-script publish-build +after_success: +- npm run-script publish-build +- "./bin/bower-ember-data-build" env: global: - S3_BUILD_CACHE_BUCKET=emberjs-build-cache diff --git a/Gruntfile.js b/Gruntfile.js index a5fbf742734..8a68bb98ea9 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,4 +1,5 @@ var matchdep = require('matchdep'); +var emberDataVersion = require('./lib/utilities/ember-data-version'); module.exports = function(grunt){ matchdep.filterDev('grunt-*').forEach(grunt.loadNpmTasks); @@ -13,13 +14,15 @@ module.exports = function(grunt){ grunt.initConfig(config); + grunt.config('versionStamp', emberDataVersion()); + grunt.registerTask('buildPackages', [ - 'setVersionStamp', 'clean', 'transpile:amd', 'concat:globals', 'browser:dist', - 'jshint' + 'jshint', + 'copy:bower' ]); grunt.registerTask('prepareTests', ['buildPackages', 'concat:tests']); @@ -32,11 +35,12 @@ module.exports = function(grunt){ grunt.registerTask('test:canary', ['test:server', 'qunit:canary']); grunt.registerTask('test:all', ['test:server', 'qunit:local', 'qunit:release', 'qunit:beta', 'qunit:canary']); + grunt.registerTask('dev', [ 'test:server', 'watch' ]); grunt.registerTask('server', 'dev'); grunt.registerTask('dist', ['buildPackages', 'emberDefeatureify:stripDebug', 'uglify:dist']); grunt.registerTask('default', ['test']); - grunt.registerTask('docs', ['setVersionStamp', 'yuidoc']); + grunt.registerTask('docs', ['yuidoc']); }; diff --git a/bin/bower-ember-data-build b/bin/bower-ember-data-build new file mode 100755 index 00000000000..e1e5472e0d3 --- /dev/null +++ b/bin/bower-ember-data-build @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +git config --global user.email "tomster@emberjs.com" +git config --global user.name "Tomster" + +# This specifies the repository we are going to work with. This will most likely be set to 'ember' +COMPONENTS_EMBER_REPO_SLUG="components/ember-data" + +# This specifies the user who is associated to the GH_TOKEN +USER="rjackson" + +# This ensure that no directories within dist will be copied when script is run. +INCLUDED_FILES=`find dist -maxdepth 1 -type f` + +echo -e "COMPONENTS_EMBER_REPO_SLUG: ${COMPONENTS_EMBER_REPO_SLUG}\n" +echo -e "INCLUDED_FILES: ${INCLUDED_FILES}\n" +echo -e "CURRENT_BRANCH: ${TRAVIS_BRANCH}\n" + +# Set channel to publish to. If no suitable branch is found exit successfully. +case $TRAVIS_BRANCH in + "master" ) + CHANNEL="canary" ;; + "beta" ) + CHANNEL="beta" ;; + "stable" ) + CHANNEL="release" ;; + "release" ) + CHANNEL="release" ;; + * ) + echo "Not a bower release branch. Exiting!" + exit 0 ;; +esac +echo -e "CHANNEL: ${CHANNEL}\n" + +# sending output to /dev/null to prevent GH_TOKEN leak on error +git clone --branch ${CHANNEL} https://${USER}:${GH_TOKEN}@github.com/${COMPONENTS_EMBER_REPO_SLUG}.git bower_ember &> /dev/null +rm -rf bower_ember/* +cp -r ${INCLUDED_FILES} bower_ember/ +cd bower_ember +git remote rm origin + +# sending output to /dev/null to prevent GH_TOKEN leak on error +git remote add origin https://${USER}:${GH_TOKEN}@github.com/${COMPONENTS_EMBER_REPO_SLUG}.git &> /dev/null +git add -A +git commit -m "Ember Data Bower Auto build for https://github.com/emberjs/data/commits/${TRAVIS_COMMIT}." + +# sending output to /dev/null to prevent GH_TOKEN leak on error +git push -fq origin ${CHANNEL} &> /dev/null +echo -e "Done\n" + diff --git a/config/package_manager_files/.gitignore b/config/package_manager_files/.gitignore new file mode 100644 index 00000000000..13e46501386 --- /dev/null +++ b/config/package_manager_files/.gitignore @@ -0,0 +1,5 @@ +components +node_modules +vendor +composer.lock +data diff --git a/config/package_manager_files/Makefile b/config/package_manager_files/Makefile new file mode 100644 index 00000000000..b0359bf8d0a --- /dev/null +++ b/config/package_manager_files/Makefile @@ -0,0 +1,8 @@ +VERSION=VERSION_STRING_PLACEHOLDER + +default: + @curl -O http://builds.emberjs.com/tags/$(VERSION)/ember-data.js + @curl -O http://builds.emberjs.com/tags/$(VERSION)/ember-data.min.js + @curl -O http://builds.emberjs.com/tags/$(VERSION)/ember-data.prod.js + +.PHONY: default diff --git a/config/package_manager_files/README.md b/config/package_manager_files/README.md new file mode 100644 index 00000000000..6b3f5ca015e --- /dev/null +++ b/config/package_manager_files/README.md @@ -0,0 +1,12 @@ +Ember Data +========== + +Shim repository for the [Ember.js Data](http://github.com/emberjs/data) component. + + +Package Managers +---------------- + +* [Bower](http://bower.io): `ember-data` +* [Component](http://component.io): `components/ember-data` +* [Composer](http://packagist.org/packages/components/ember): `components/ember-data` diff --git a/config/package_manager_files/bower.json b/config/package_manager_files/bower.json new file mode 100644 index 00000000000..620bbc12b21 --- /dev/null +++ b/config/package_manager_files/bower.json @@ -0,0 +1,8 @@ +{ + "name": "ember-data", + "version": "VERSION_STRING_PLACEHOLDER", + "main": "ember-data.js", + "dependencies": { + "ember": ">= 1.0.0" + } +} diff --git a/config/package_manager_files/component.json b/config/package_manager_files/component.json new file mode 100644 index 00000000000..cce479429d1 --- /dev/null +++ b/config/package_manager_files/component.json @@ -0,0 +1,16 @@ +{ + "name": "ember-data", + "repo": "components/ember-data", + "description": "A data persistence library for Ember.js.", + "version": "VERSION_STRING_PLACEHOLDER", + "main": "ember-data.js", + "scripts": [ + "ember-data.js", + "ember-data.min.js", + "ember-data.prod.js" + ], + "dependencies": { + "components/ember": "~1.0" + }, + "license": "MIT" +} diff --git a/config/package_manager_files/composer.json b/config/package_manager_files/composer.json new file mode 100644 index 00000000000..97e914b70ef --- /dev/null +++ b/config/package_manager_files/composer.json @@ -0,0 +1,26 @@ +{ + "name": "components/ember-data", + "description": "A data persistence library for Ember.js.", + "type": "component", + "license": "MIT", + "require": { + "components/ember": "1.*" + }, + "extra": { + "component": { + "scripts": [ + "ember-data.js" + ], + "files": [ + "ember-data.min.js", + "ember-data.prod.js" + ], + "shim": { + "exports": "Ember", + "deps": [ + "ember" + ] + } + } + } +} diff --git a/config/package_manager_files/package.json b/config/package_manager_files/package.json new file mode 100644 index 00000000000..5112c9219d6 --- /dev/null +++ b/config/package_manager_files/package.json @@ -0,0 +1,12 @@ +{ + name: "components-ember-data", + version: "VERSION_STRING_PLACEHOLDER", + description: "A data persistence library for Ember.js.", + keywords: [ + "ember" + ], + main: "./ember-data.js", + dependencies: { + ember: "> 1.0.0" + } +} diff --git a/lib/utilities/ember-data-version.js b/lib/utilities/ember-data-version.js new file mode 100644 index 00000000000..6d293cf8f61 --- /dev/null +++ b/lib/utilities/ember-data-version.js @@ -0,0 +1,34 @@ +'use strict'; + +var fs = require('fs'); +var path = require('path'); + +module.exports = function () { + var output = [require('../../package.json').version]; + var gitPath = path.join(__dirname, '..','..','.git'); + var headFilePath = path.join(gitPath, 'HEAD'); + + try { + if (fs.existsSync(headFilePath)) { + var branchSHA; + var headFile = fs.readFileSync(headFilePath, {encoding: 'utf8'}); + var branchName = headFile.split('/').slice(-1)[0].trim(); + var refPath = headFile.split(' ')[1]; + + if (refPath) { + var branchPath = path.join(gitPath, refPath.trim()); + branchSHA = fs.readFileSync(branchPath); + } else { + branchSHA = branchName; + } + + output.push(branchName); + + output.push(branchSHA.slice(0,10)); + } + } catch (err) { + console.error(err.stack); + } + + return output.join('-'); +}; diff --git a/package.json b/package.json index 3ea0647289a..3c8f7150fa3 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "aws-sdk": "~2.0.0-rc8", "grunt-contrib-yuidoc": "~0.5.0", "lockfile": "~0.4.2", - "grunt-cli": "~0.1.13" + "grunt-cli": "~0.1.13", + "grunt-contrib-copy": "^0.5.0" } } diff --git a/tasks/options/copy.js b/tasks/options/copy.js new file mode 100644 index 00000000000..ea73e3c9d87 --- /dev/null +++ b/tasks/options/copy.js @@ -0,0 +1,11 @@ +var emberDataVersion = require('../../lib/utilities/ember-data-version.js'); +module.exports = { + bower: { + src: 'config/package_manager_files/*', dest: 'dist/', flatten: true, expand: true, + options: { + process: function (content, srcpath) { + return content.replace(/VERSION_STRING_PLACEHOLDER/g, emberDataVersion()); + } + } + } +}; diff --git a/tasks/setVersionStamp.js b/tasks/setVersionStamp.js deleted file mode 100644 index d47bcdf1cbc..00000000000 --- a/tasks/setVersionStamp.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = function(grunt) { - grunt.registerTask('setVersionStamp', 'Add the currentRevision and versionStamp values to the global grunt config', function() { - var done = this.async(); - - grunt.util.spawn({cmd: 'git', args: ['rev-list', 'HEAD', '-n', '1']}, function(error, result, code){ - grunt.config('currentRevision', result.toString()); - grunt.config('versionStamp', grunt.config('pkg.version') + '.' + grunt.config('currentRevision').substr(0,8)); - done(); - }) - }); -}; From 31bd39d1d40413b43578eb2e2d5bd37e667645c1 Mon Sep 17 00:00:00 2001 From: Alex Speller Date: Mon, 7 Jul 2014 21:06:34 +0100 Subject: [PATCH 0217/2527] Update store docs from old style adapter specification --- packages/ember-data/lib/system/store.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 9797cf76c0b..6e681079626 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -82,10 +82,8 @@ function coerceId(id) { backend by specifying a custom adapter: ```javascript - MyApp.store = DS.Store.create({ - adapter: 'MyApp.CustomAdapter' - }); - ``` + MyApp.ApplicationAdapter = MyApp.CustomAdapter + ``` You can learn more about writing a custom adapter by reading the `DS.Adapter` documentation. From 2866d216fa59c5e714ca3502e7ca625fa2d8db45 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 7 Jul 2014 22:31:35 -0400 Subject: [PATCH 0218/2527] Add token. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index fbcf263ac57..ab34679e253 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,3 +22,5 @@ env: UvaE/CbWMxO/6FszR02gJHaF+YyfU5WAS0ahFFLHuC1twMtQPxi+nScjKZEs kLwKiKgRNhindV3WvbUcoiIrmrgBMCiBRRd4eyVBlhbZ8RTo1Ig=' + + - secure: "hJZXijsot2wMiMsxbDImH+nB5v77a7O7lQ7bicOQEQxmnTtXSvqfa4X4vQ/d4o7NNYYYHUuOpyILgRV+arqI6UOi7XEVGka/7M5q58R5exS6bk0cY0jnpUhUVW/8mpKEUgcVeE6mIDWaR090l3uaT2JhU/WSLkzbj45e38HaF/4=" From f1771686ed4931d66f69777962dd86aafce2e7aa Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 7 Jul 2014 22:56:17 -0400 Subject: [PATCH 0219/2527] Update version calculation to match Ember.js. --- lib/utilities/ember-data-version.js | 43 +++++++++++++++-------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/lib/utilities/ember-data-version.js b/lib/utilities/ember-data-version.js index 6d293cf8f61..3f5a776190f 100644 --- a/lib/utilities/ember-data-version.js +++ b/lib/utilities/ember-data-version.js @@ -4,31 +4,34 @@ var fs = require('fs'); var path = require('path'); module.exports = function () { - var output = [require('../../package.json').version]; + var packageVersion = require('../../package.json').version; + var output = [packageVersion]; var gitPath = path.join(__dirname, '..','..','.git'); var headFilePath = path.join(gitPath, 'HEAD'); - try { - if (fs.existsSync(headFilePath)) { - var branchSHA; - var headFile = fs.readFileSync(headFilePath, {encoding: 'utf8'}); - var branchName = headFile.split('/').slice(-1)[0].trim(); - var refPath = headFile.split(' ')[1]; + if (packageVersion.indexOf('+') > -1) { + try { + if (fs.existsSync(headFilePath)) { + var headFile = fs.readFileSync(headFilePath, {encoding: 'utf8'}); + var branchName = headFile.split('/').slice(-1)[0].trim(); + var refPath = headFile.split(' ')[1]; + var branchSHA; - if (refPath) { - var branchPath = path.join(gitPath, refPath.trim()); - branchSHA = fs.readFileSync(branchPath); - } else { - branchSHA = branchName; - } - - output.push(branchName); + if (refPath) { + var branchPath = path.join(gitPath, refPath.trim()); + branchSHA = fs.readFileSync(branchPath); + } else { + branchSHA = branchName; + } - output.push(branchSHA.slice(0,10)); + output.push(branchSHA.slice(0,10)); + } + } catch (err) { + console.error(err.stack); } - } catch (err) { - console.error(err.stack); - } - return output.join('-'); + return output.join('.'); + } else { + return packageVersion; + } }; From 03d13565afd225b0430ee7a693ca9b4c497385aa Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 7 Jul 2014 22:58:24 -0400 Subject: [PATCH 0220/2527] Remove Makefile. --- config/package_manager_files/Makefile | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 config/package_manager_files/Makefile diff --git a/config/package_manager_files/Makefile b/config/package_manager_files/Makefile deleted file mode 100644 index b0359bf8d0a..00000000000 --- a/config/package_manager_files/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -VERSION=VERSION_STRING_PLACEHOLDER - -default: - @curl -O http://builds.emberjs.com/tags/$(VERSION)/ember-data.js - @curl -O http://builds.emberjs.com/tags/$(VERSION)/ember-data.min.js - @curl -O http://builds.emberjs.com/tags/$(VERSION)/ember-data.prod.js - -.PHONY: default From 5e6666a5c3ab4f16fd97967ee9e3f6a7d6f478a4 Mon Sep 17 00:00:00 2001 From: Jonathan Jackson Date: Tue, 8 Jul 2014 14:31:48 -0400 Subject: [PATCH 0221/2527] Migrate s3 publishing to ember publisher --- bin/publish_to_s3.js | 19 ++++++++++++ package.json | 27 ++++++++-------- tasks/options/publish.js | 32 ------------------- tasks/publish.js | 67 ---------------------------------------- 4 files changed, 33 insertions(+), 112 deletions(-) create mode 100755 bin/publish_to_s3.js delete mode 100644 tasks/options/publish.js delete mode 100644 tasks/publish.js diff --git a/bin/publish_to_s3.js b/bin/publish_to_s3.js new file mode 100755 index 00000000000..a7e590d47d1 --- /dev/null +++ b/bin/publish_to_s3.js @@ -0,0 +1,19 @@ +#!/usr/bin/env node + +// To invoke this from the commandline you need the following to env vars to exist: +// +// S3_BUCKET_NAME +// TRAVIS_BRANCH +// TRAVIS_TAG +// TRAVIS_COMMIT +// S3_SECRET_ACCESS_KEY +// S3_ACCESS_KEY_ID +// +// Once you have those you execute with the following: +// +// ```sh +// ./bin/publish_to_s3.js +// ``` +var S3Publisher = require('ember-publisher'); +publisher = new S3Publisher({project: 'ember-data'}); +publisher.publish(); diff --git a/package.json b/package.json index 3c8f7150fa3..eef5cc003bc 100644 --- a/package.json +++ b/package.json @@ -7,29 +7,30 @@ "scripts": { "postinstall": "bower install", "test": "grunt test:all", - "publish-build": "grunt dist publish" + "publish-build": "grunt dist && ./bin/publish_to_s3" }, "devDependencies": { + "aws-sdk": "~2.0.0-rc8", + "bower": "~1.2", "defeatureify": "~0.1.4", - "yuidocjs": "~0.3.46", - "grunt-es6-module-transpiler": "~0.6.0", + "ember-publisher": "0.0.2", "grunt": "~0.4.2", + "grunt-cli": "~0.1.13", "grunt-contrib-clean": "~0.5.0", "grunt-contrib-concat": "~0.3.0", - "load-grunt-config": "~0.7.0", - "load-grunt-tasks": "~0.2.1", - "matchdep": "~0.3.0", + "grunt-contrib-connect": "~0.6.0", + "grunt-contrib-copy": "^0.5.0", "grunt-contrib-jshint": "~0.8.0", "grunt-contrib-qunit": "~0.3.0", - "grunt-contrib-connect": "~0.6.0", - "grunt-contrib-watch": "~0.5.3", "grunt-contrib-uglify": "~0.3.0", - "bower": "~1.2", - "grunt-ember-defeatureify": "~0.1.0", - "aws-sdk": "~2.0.0-rc8", + "grunt-contrib-watch": "~0.5.3", "grunt-contrib-yuidoc": "~0.5.0", + "grunt-ember-defeatureify": "~0.1.0", + "grunt-es6-module-transpiler": "~0.6.0", + "load-grunt-config": "~0.7.0", + "load-grunt-tasks": "~0.2.1", "lockfile": "~0.4.2", - "grunt-cli": "~0.1.13", - "grunt-contrib-copy": "^0.5.0" + "matchdep": "~0.3.0", + "yuidocjs": "~0.3.46" } } diff --git a/tasks/options/publish.js b/tasks/options/publish.js deleted file mode 100644 index 2c8033f8460..00000000000 --- a/tasks/options/publish.js +++ /dev/null @@ -1,32 +0,0 @@ -var date = new Date().toISOString().replace(/-/g, '').replace(/T.+/, '') -var sha = process.env.TRAVIS_COMMIT; - -function destinationsForType(extension){ - var filename = 'ember-data' + extension; - - return ['CHANNEL/' + filename, - 'CHANNEL/daily/' + date + '/' + filename, - 'CHANNEL/shas/' + sha + '/' + filename] -} - -module.exports = { - debug: { - files: [{ - src: 'dist/ember-data.js', - dest: destinationsForType('.js') - }] - }, - prod: { - files: [{ - src: 'dist/ember-data.prod.js', - dest: destinationsForType('.prod.js') - }] - }, - min: { - files: [{ - src: 'dist/ember-data.min.js', - dest: destinationsForType('.min.js') - }] - } -}; - diff --git a/tasks/publish.js b/tasks/publish.js deleted file mode 100644 index 3d78e674e66..00000000000 --- a/tasks/publish.js +++ /dev/null @@ -1,67 +0,0 @@ -var path = require('path'); - -var S3_BUCKET_NAME = process.env.S3_BUCKET_NAME, - S3_ACCESS_KEY_ID = process.env.S3_ACCESS_KEY_ID, - S3_SECRET_ACCESS_KEY = process.env.S3_SECRET_ACCESS_KEY, - TRAVIS_BRANCH = process.env.TRAVIS_BRANCH, - AWS, s3; - -function uploadFile(data, type, destination, callback) { - if (!AWS) { - AWS = require('aws-sdk'); - AWS.config.update({accessKeyId: S3_ACCESS_KEY_ID, secretAccessKey: S3_SECRET_ACCESS_KEY}); - } - - if (!s3) { s3 = new AWS.S3(); } - - s3.putObject({ - Body: data, - Bucket: S3_BUCKET_NAME, - ContentType: type, - Key: destination - }, callback) -} - -module.exports = function(grunt) { - grunt.registerMultiTask('publish', 'Publish files to S3', function() { - if (!S3_BUCKET_NAME || !S3_ACCESS_KEY_ID || !S3_SECRET_ACCESS_KEY) { - grunt.log.writeln('No AWS credentials exist.'); - return; - } - - var done = this.async(); - var uploadPendingCount = 0; - - function finish(err, result){ - if (err) { - grunt.log.writeln("Error: " + err + "; Result: " + result); - } - - uploadPendingCount--; - if (uploadPendingCount === 0) { done() } - } - - this.files.forEach(function(f) { - f.dest.forEach(function(dest){ - var finalDestination; - var channel; - - if(dest.indexOf('CHANNEL') > -1) { - if (TRAVIS_BRANCH === 'master') { channel = 'canary'; } - if (TRAVIS_BRANCH === 'beta') { channel = 'beta'; } - if (TRAVIS_BRANCH === 'stable') { channel = 'release'; } - - finalDestination = dest.replace('CHANNEL', channel); - } else { - finalDestination = dest; - } - - if (finalDestination) { - uploadPendingCount++; - grunt.log.writeln("Uploading " + f.src + " -> " + finalDestination); - uploadFile(grunt.file.read(f.src), 'text/javascript', finalDestination, finish); - } - }); - }); - }); -}; From a5ab4301238eb62c3d5f64181753c0ccf7a4c6fb Mon Sep 17 00:00:00 2001 From: Jonathan Jackson Date: Tue, 8 Jul 2014 14:47:55 -0400 Subject: [PATCH 0222/2527] [Fix] Add extension to publish-build ( publish_to_s3 -> publish_to_s3.js ) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eef5cc003bc..e1a6372226d 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "scripts": { "postinstall": "bower install", "test": "grunt test:all", - "publish-build": "grunt dist && ./bin/publish_to_s3" + "publish-build": "grunt dist && ./bin/publish_to_s3.js" }, "devDependencies": { "aws-sdk": "~2.0.0-rc8", From be34aa5bd2a5dd78116b3a7f5b2f359268be479d Mon Sep 17 00:00:00 2001 From: Jonathan Jackson Date: Tue, 8 Jul 2014 15:02:18 -0400 Subject: [PATCH 0223/2527] Bump to fixed ember publisher version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eef5cc003bc..88cd897d3c0 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "aws-sdk": "~2.0.0-rc8", "bower": "~1.2", "defeatureify": "~0.1.4", - "ember-publisher": "0.0.2", + "ember-publisher": "0.0.3", "grunt": "~0.4.2", "grunt-cli": "~0.1.13", "grunt-contrib-clean": "~0.5.0", From 95dbc45bced4b8eab7715e8ed8b9ae8f67c50745 Mon Sep 17 00:00:00 2001 From: Kalman Hazins Date: Thu, 10 Jul 2014 15:14:15 -0400 Subject: [PATCH 0224/2527] typo then => than --- packages/ember-data/lib/system/adapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index f7ab5450f90..e23689ebc3e 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -131,7 +131,7 @@ var Adapter = Ember.Object.extend({ set the `defaultSerializer` property to be the name of the custom serializer. - Note the `defaultSerializer` serializer has a lower priority then + Note the `defaultSerializer` serializer has a lower priority than a model specific serializer (i.e. `PostSerializer`) or the `application` serializer. From 41c4a0bfd773c51080cd5e1d017f339d4ece6b68 Mon Sep 17 00:00:00 2001 From: Justin Bull Date: Thu, 10 Jul 2014 13:25:47 -0400 Subject: [PATCH 0225/2527] Favour declared mapping over keyForAttribute, if defined; keyForAttribute, if defined, is useful for defining custom changes for all keys on a particular serializer, be it for the application or just a particular resource. The custom attr-based mapping should be maintained, and should precedence, over the keyForAttribute. Broke down the ternary operators for increased readability. Adds integration test for mapping > `keyForAttribute` precedence --- .../lib/serializers/json_serializer.js | 6 +++++- .../integration/adapter/rest_adapter_test.js | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index e36127dd6e3..2b0c3610531 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -375,7 +375,11 @@ export default Ember.Object.extend({ // if provided, use the mapping provided by `attrs` in // the serializer - key = attrs && attrs[key] || (this.keyForAttribute ? this.keyForAttribute(key) : key); + if (attrs && attrs[key]) { + key = attrs[key]; + } else if (this.keyForAttribute) { + key = this.keyForAttribute(key); + } json[key] = value; }, diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 8df62951e2c..d0973055a11 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -254,6 +254,26 @@ test("create - a serializer's attributes are consulted when building the payload })); }); +test("create - a serializer's attribute mapping takes precdence over keyForAttribute when building the payload", function() { + env.container.register('serializer:post', DS.RESTSerializer.extend({ + attrs: { + name: 'given_name' + }, + + keyForAttribute: function(attr) { + return attr.toUpperCase(); + } + })); + + ajaxResponse(); + + var post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); + + post.save().then(async(function(post) { + deepEqual(passedHash.data, { post: { 'given_name': "The Parley Letter", id: "some-uuid" } }); + })); +}); + test("create - a record on the many side of a hasMany relationship should update relationships when data is sideloaded", function() { expect(3); From a979c52acfeaba076453194403f8f645de4d0c4f Mon Sep 17 00:00:00 2001 From: Justin Bull Date: Thu, 10 Jul 2014 13:38:33 -0400 Subject: [PATCH 0226/2527] Allow `attr` mapping in `belongsTo` & `hasMany` attributes; Related attributes should still be able to have mappings defined for them. The normalizing compliment to these mappings, `JSONSerializer#normalizeUsingDeclaredMapping`, are applied to all attributes including `belongsTo` and `hasMany`. Adds integration test for mapping > `keyForRelationship` precedence; --- .../lib/serializers/json_serializer.js | 23 ++++++++- .../integration/adapter/rest_adapter_test.js | 47 +++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 2b0c3610531..a4fa3310260 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -410,10 +410,17 @@ export default Ember.Object.extend({ @param {Object} relationship */ serializeBelongsTo: function(record, json, relationship) { + var attrs = get(this, 'attrs'); var key = relationship.key; var belongsTo = get(record, key); - key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo") : key; + // if provided, use the mapping provided by `attrs` in + // the serializer + if (attrs && attrs[key]) { + key = attrs[key]; + } else if (this.keyForRelationship) { + key = this.keyForRelationship(key, "belongsTo"); + } if (isNone(belongsTo)) { json[key] = belongsTo; @@ -451,8 +458,20 @@ export default Ember.Object.extend({ @param {Object} relationship */ serializeHasMany: function(record, json, relationship) { + var attrs = get(this, 'attrs'); var key = relationship.key; - var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, "hasMany") : key; + var payloadKey; + + // if provided, use the mapping provided by `attrs` in + // the serializer + if (attrs && attrs[key]) { + payloadKey = attrs[key]; + } else if (this.keyForRelationship) { + payloadKey = this.keyForRelationship(key, "hasMany"); + } else { + payloadKey = key; + } + var relationshipType = RelationshipChange.determineRelationshipType(record.constructor, relationship); if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') { diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index d0973055a11..13f46754ebf 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -274,6 +274,53 @@ test("create - a serializer's attribute mapping takes precdence over keyForAttri })); }); +test("create - a serializer's attribute mapping takes precedence over keyForRelationship (belongsTo) when building the payload", function() { + env.container.register('serializer:comment', DS.RESTSerializer.extend({ + attrs: { + post: 'article' + }, + + keyForRelationship: function(attr, kind) { + return attr.toUpperCase(); + } + })); + + ajaxResponse(); + + Comment.reopen({ post: DS.belongsTo('post') }); + + var post = store.createRecord('post', { id: "a-post-id", name: "The Parley Letter" }); + var comment = store.createRecord('comment', { id: "some-uuid", name: "Letters are fun", post: post }); + + comment.save().then(async(function(post) { + deepEqual(passedHash.data, { comment: { article: "a-post-id", id: "some-uuid", name: "Letters are fun" } }); + })); +}); + +test("create - a serializer's attribute mapping takes precedence over keyForRelationship (hasMany) when building the payload", function() { + env.container.register('serializer:post', DS.RESTSerializer.extend({ + attrs: { + comments: 'opinions' + }, + + keyForRelationship: function(attr, kind) { + return attr.toUpperCase(); + } + })); + + ajaxResponse(); + + Post.reopen({ comments: DS.hasMany('comment') }); + + var comment = store.createRecord('comment', { id: "a-comment-id", name: "First!" }); + var post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); + post.get('comments').pushObject(comment); + + post.save().then(async(function(post) { + deepEqual(passedHash.data, { post: { opinions: [ "a-comment-id" ], id: "some-uuid", name: "The Parley Letter" } }); + })); +}); + test("create - a record on the many side of a hasMany relationship should update relationships when data is sideloaded", function() { expect(3); From 9ed580fb6c9cb7d686e4b2f53cd1a9c3285f3ed0 Mon Sep 17 00:00:00 2001 From: Alex Baizeau Date: Thu, 10 Jul 2014 16:22:42 -0400 Subject: [PATCH 0227/2527] Fixes embedded hasMany primary key lookup. --- .../lib/system/embedded_records_mixin.js | 4 +- .../embedded_records_mixin_test.js | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index e67c40fcb70..09b7f98aa82 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -487,7 +487,7 @@ function updatePayloadWithEmbedded(serializer, store, type, payload, partial) { // handles embedding for `hasMany` relationship function updatePayloadWithEmbeddedHasMany(serializer, store, primaryType, relationship, payload, partial) { var embeddedSerializer = store.serializerFor(relationship.type.typeKey); - var primaryKey = get(serializer, 'primaryKey'); + var embeddedPrimaryKey = get(embeddedSerializer, 'primaryKey'); var attr = relationship.type.typeKey; // underscore forces the embedded records to be side loaded. // it is needed when main type === relationship.type @@ -505,7 +505,7 @@ function updatePayloadWithEmbeddedHasMany(serializer, store, primaryType, relati forEach(partial[attribute], function(data) { var embeddedType = store.modelFor(attr); updatePayloadWithEmbedded(embeddedSerializer, store, embeddedType, payload, data); - ids.push(data[primaryKey]); + ids.push(data[embeddedPrimaryKey]); payload[embeddedTypeKey].push(data); }); diff --git a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js index 6ed74325809..b5e6f99d6a7 100644 --- a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js +++ b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js @@ -311,6 +311,46 @@ test("extractArray with embedded objects", function() { })); }); +test("extractArray with embedded objects with custom primary key", function() { + expect(2); + env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend({ + primaryKey: 'villain_id' + })); + env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: {embedded: 'always'} + } + })); + + var serializer = env.container.lookup("serializer:homePlanet"); + + var json_hash = { + home_planets: [{ + id: "1", + name: "Umber", + villains: [{ + villain_id: "1", + first_name: "Alex", + last_name: "Baizeau" + }] + }] + }; + + var array = serializer.extractArray(env.store, HomePlanet, json_hash); + + deepEqual(array, [{ + id: "1", + name: "Umber", + villains: ["1"] + }]); + + return env.store.find("superVillain", 1).then(function(minion){ + env.container.unregister('serializer:superVillain'); + equal(minion.get('firstName'), "Alex"); + + }); +}); test("extractArray with embedded objects of same type as primary type", function() { env.container.register('adapter:comment', DS.ActiveModelAdapter); env.container.register('serializer:comment', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { From bc708ffef9e1b5cfb50c482e22c7f17882b65596 Mon Sep 17 00:00:00 2001 From: Alex Baizeau Date: Fri, 11 Jul 2014 13:13:55 -0400 Subject: [PATCH 0228/2527] Add guard before deleting partial[attribute] --- .../lib/system/embedded_records_mixin.js | 4 +- .../embedded_records_mixin_test.js | 39 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index 09b7f98aa82..23de154195f 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -510,7 +510,9 @@ function updatePayloadWithEmbeddedHasMany(serializer, store, primaryType, relati }); partial[expandedKey] = ids; - delete partial[attribute]; + if(expandedKey !== attribute) { + delete partial[attribute]; + } } // handles embedding for `belongsTo` relationship diff --git a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js index b5e6f99d6a7..8f0a188b04a 100644 --- a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js +++ b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js @@ -351,6 +351,45 @@ test("extractArray with embedded objects with custom primary key", function() { }); }); +test("extractArray with embedded objects with identical relationship and attribute key ", function() { + expect(2); + env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: {embedded: 'always'} + }, + //Makes the keyForRelationship and keyForAttribute collide. + keyForRelationship: function(key, type) { + return this.keyForAttribute(key, type); + } + })); + + var serializer = env.container.lookup("serializer:homePlanet"); + + var json_hash = { + home_planets: [{ + id: "1", + name: "Umber", + villains: [{ + id: "1", + first_name: "Alex", + last_name: "Baizeau" + }] + }] + }; + + var array = serializer.extractArray(env.store, HomePlanet, json_hash); + + deepEqual(array, [{ + id: "1", + name: "Umber", + villains: ["1"] + }]); + + return env.store.find("superVillain", 1).then(function(minion){ + equal(minion.get('firstName'), "Alex"); + }); +}); test("extractArray with embedded objects of same type as primary type", function() { env.container.register('adapter:comment', DS.ActiveModelAdapter); env.container.register('serializer:comment', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { From 3de853a8ef6d16b817809ed075f2904c21e32e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Mu=C3=B1oz?= Date: Fri, 11 Jul 2014 20:15:55 -0400 Subject: [PATCH 0229/2527] Fix computed property check --- packages/ember-data/lib/system/relationships/ext.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index df58aba2e11..1ae22d49343 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -51,7 +51,7 @@ Model.reopen({ */ didDefineProperty: function(proto, key, value) { // Check if the value being set is a computed property. - if (value instanceof Ember.Descriptor) { + if (value instanceof Ember.ComputedProperty) { // If it is, get the metadata for the relationship. This is // populated by the `DS.belongsTo` helper when it is creating From 628c7fd2c2cda32fb6ac8866a4dcdac8dbe389b5 Mon Sep 17 00:00:00 2001 From: Norik Davtian Date: Mon, 14 Jul 2014 19:13:05 -0700 Subject: [PATCH 0230/2527] Expected closing tag for payload._embedded.comment.forEach used in api docs http://emberjs.com/api/data/classes/DS.RESTSerializer.html Signed-off-by: Norik Davtian --- packages/ember-data/lib/serializers/rest_serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index 1ef00b91e65..5a866d69a69 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -422,7 +422,7 @@ export default JSONSerializer.extend({ comments.push(comment); postCache[comment.post_id].comments.push(comment); delete comment.post_id; - } + }); payload = { comments: comments, posts: payload }; From c28df3f17a6cdc9c6d13b7e4e27d204e9bf89e29 Mon Sep 17 00:00:00 2001 From: Brendan Date: Tue, 15 Jul 2014 09:47:12 -0500 Subject: [PATCH 0231/2527] Fixed grammatical issue on DS.PromiseObject page --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 1d0e81b2720..20b36a07d43 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1651,7 +1651,7 @@ function uniqById(data, records) { PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin); /** A `PromiseObject` is an object that acts like both an `Ember.Object` - and a promise. When the promise is resolved the the resulting value + and a promise. When the promise is resolved, then the resulting value will be set to the `PromiseObject`'s `content` property. This makes it easy to create data bindings with the `PromiseObject` that will be updated when the promise resolves. From d266dff6714b37a56015c1e9b145b1014cb8ae20 Mon Sep 17 00:00:00 2001 From: Jonathan Collins Date: Thu, 29 May 2014 23:22:45 -0700 Subject: [PATCH 0232/2527] drop server responses if they are no longer relevant --- packages/ember-data/lib/system/store.js | 63 ++++++++++++++-- .../tests/integration/store_test.js | 73 +++++++++++++++++-- 2 files changed, 122 insertions(+), 14 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 20b36a07d43..531122cd757 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1726,19 +1726,46 @@ function serializerForAdapter(adapter, type) { return serializer; } +function _objectIsAlive(object) { + return !(get(object, "isDestroyed") || get(object, "isDestroying")); +} + +function _guard(promise, test) { + var guarded = promise['finally'](function() { + if (!test()) { + guarded._subscribers.length = 0; + } + }); + + return guarded; +} + +function _bind(fn) { + var args = Array.prototype.slice.call(arguments, 1); + + return function() { + return fn.apply(undefined, args); + }; +} + function _find(adapter, store, type, id) { var promise = adapter.find(store, type, id); var serializer = serializerForAdapter(adapter, type); var label = "DS: Handle Adapter#find of " + type + " with id: " + id; - return Promise.cast(promise, label).then(function(adapterPayload) { + promise = Promise.cast(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + + return promise.then(function(adapterPayload) { Ember.assert("You made a request for a " + type.typeKey + " with id " + id + ", but the adapter's response did not have any data", adapterPayload); var payload = serializer.extract(store, type, adapterPayload, id, 'find'); return store.push(type, payload); }, function(error) { var record = store.getById(type, id); - record.notFound(); + if (record) { + record.notFound(); + } throw error; }, "DS: Extract payload of '" + type + "'"); } @@ -1747,8 +1774,12 @@ function _findMany(adapter, store, type, ids, owner) { var promise = adapter.findMany(store, type, ids, owner); var serializer = serializerForAdapter(adapter, type); var label = "DS: Handle Adapter#findMany of " + type; + var guardedPromise; + + promise = Promise.cast(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); - return Promise.cast(promise, label).then(function(adapterPayload) { + return promise.then(function(adapterPayload) { var payload = serializer.extract(store, type, adapterPayload, null, 'findMany'); Ember.assert("The response from a findMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1762,7 +1793,11 @@ function _findHasMany(adapter, store, record, link, relationship) { var serializer = serializerForAdapter(adapter, relationship.type); var label = "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type; - return Promise.cast(promise, label).then(function(adapterPayload) { + promise = Promise.cast(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + promise = _guard(promise, _bind(_objectIsAlive, record)); + + return promise.then(function(adapterPayload) { var payload = serializer.extract(store, relationship.type, adapterPayload, null, 'findHasMany'); Ember.assert("The response from a findHasMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1777,7 +1812,11 @@ function _findBelongsTo(adapter, store, record, link, relationship) { var serializer = serializerForAdapter(adapter, relationship.type); var label = "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type; - return Promise.cast(promise, label).then(function(adapterPayload) { + promise = Promise.cast(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + promise = _guard(promise, _bind(_objectIsAlive, record)); + + return promise.then(function(adapterPayload) { var payload = serializer.extract(store, relationship.type, adapterPayload, null, 'findBelongsTo'); var record = store.push(relationship.type, payload); @@ -1791,7 +1830,10 @@ function _findAll(adapter, store, type, sinceToken) { var serializer = serializerForAdapter(adapter, type); var label = "DS: Handle Adapter#findAll of " + type; - return Promise.cast(promise, label).then(function(adapterPayload) { + promise = Promise.cast(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + + return promise.then(function(adapterPayload) { var payload = serializer.extract(store, type, adapterPayload, null, 'findAll'); Ember.assert("The response from a findAll must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1807,7 +1849,10 @@ function _findQuery(adapter, store, type, query, recordArray) { var serializer = serializerForAdapter(adapter, type); var label = "DS: Handle Adapter#findQuery of " + type; - return Promise.cast(promise, label).then(function(adapterPayload) { + promise = Promise.cast(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + + return promise.then(function(adapterPayload) { var payload = serializer.extract(store, type, adapterPayload, null, 'findQuery'); Ember.assert("The response from a findQuery must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -1825,6 +1870,10 @@ function _commit(adapter, store, operation, record) { Ember.assert("Your adapter's '" + operation + "' method must return a promise, but it returned " + promise, isThenable(promise)); + promise = Promise.cast(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + promise = _guard(promise, _bind(_objectIsAlive, record)); + return promise.then(function(adapterPayload) { var payload; diff --git a/packages/ember-data/tests/integration/store_test.js b/packages/ember-data/tests/integration/store_test.js index deef5f20bb0..bc1271c0aa6 100644 --- a/packages/ember-data/tests/integration/store_test.js +++ b/packages/ember-data/tests/integration/store_test.js @@ -15,15 +15,19 @@ var Car = DS.Model.extend({ Car.toString = function() { return "Car"; }; +initializeStore = function(adapter) { + env = setupStore({ + adapter: adapter + }); + store = env.store; + + env.container.register('model:car', Car); + env.container.register('model:person', Person); +} + module("integration/store - destroy", { setup: function(){ - env = setupStore({ - adapter: DS.FixtureAdapter.extend() - }); - store = env.store; - - env.container.register('model:car', Car); - env.container.register('model:person', Person); + initializeStore(DS.FixtureAdapter.extend()); } }); @@ -44,6 +48,61 @@ function tap(obj, methodName, callback) { return summary; } +asyncTest("destroying record during find doesn't cause error", function() { + expect(0); + + var TestAdapter = DS.FixtureAdapter.extend({ + find: function() { + return new Ember.RSVP.Promise(function(resolve, reject) { + Ember.run.next(function() { + store.unloadAll(type); + reject(); + }); + }); + } + }); + + initializeStore(TestAdapter); + + var type = "car"; + var id = 1 + + done = function() { + start(); + }; + + store.find(type, id).then(done, done); +}); + +asyncTest("find calls do not resolve when the store is destroyed", function() { + expect(0); + + var TestAdapter = DS.FixtureAdapter.extend({ + find: function() { + store.destroy(); + Ember.RSVP.resolve(null); + } + }); + + initializeStore(TestAdapter); + + + var type = "car"; + var id = 1; + + store.push = function() { + Ember.assert("The test should have destroyed the store by now", store.get("isDestroyed")); + + throw "We shouldn't be pushing data into the store when it is destroyed" + } + + store.find(type, id); + + setTimeout(function() { + start(); + }, 500); +}); + test("destroying the store correctly cleans everything up", function() { var car = store.push('car', { From 5b85573fa268627adae26069487b88c8e526b13a Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 17 Jul 2014 00:44:00 -0400 Subject: [PATCH 0233/2527] PERF: O(n) -> O(1) record within recordArray check If a record changes, we attempt to re-add it to the array, addRecord only adds unique records to the array but does so with an O(n) indexOf. A proper solution would be for addRecord to utilize an index, unfortunately it does not (yet). Luckily we already have just such an index, that records recordArrays map. --- packages/ember-data/lib/system/record_array_manager.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index d42de47cd5f..a10f6d2a791 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -117,8 +117,10 @@ export default Ember.Object.extend({ var recordArrays = this.recordArraysForRecord(record); if (shouldBeInArray) { - recordArrays.add(array); - array.addRecord(record); + if (!recordArrays.has(array)) { + array.addRecord(record); + recordArrays.add(array); + } } else if (!shouldBeInArray) { recordArrays.remove(array); array.removeRecord(record); From 084f97c60627dd9f8dd41039f5f5276b76ec0843 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 18 Jul 2014 09:41:27 -0400 Subject: [PATCH 0234/2527] Update Bower publishing to use correct username. --- bin/bower-ember-data-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bower-ember-data-build b/bin/bower-ember-data-build index e1e5472e0d3..869d59c2e34 100755 --- a/bin/bower-ember-data-build +++ b/bin/bower-ember-data-build @@ -7,7 +7,7 @@ git config --global user.name "Tomster" COMPONENTS_EMBER_REPO_SLUG="components/ember-data" # This specifies the user who is associated to the GH_TOKEN -USER="rjackson" +USER="rwjblue" # This ensure that no directories within dist will be copied when script is run. INCLUDED_FILES=`find dist -maxdepth 1 -type f` From 67fed4b1c88a55f984218b638c3fafa5b5943be9 Mon Sep 17 00:00:00 2001 From: IgorT Date: Thu, 17 Jul 2014 19:41:53 +0200 Subject: [PATCH 0235/2527] Refactored EmbeddedRecordsMixin to push records instead of sideload Previously EmbeddedRecordsMixin just moved records around and relied on sideloading for their extraction. Now they are pushed to the store as they are parsed. Benefits include: 1. Less confusing code 2. Out of the box sideloading support 3. Support for using EmbeddedRecordsMixin with JSONSerializer --- .../lib/system/embedded_records_mixin.js | 263 +++++------------- .../embedded_records_mixin_test.js | 2 +- .../lib/serializers/json_serializer.js | 8 +- 3 files changed, 83 insertions(+), 190 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index 8e67de8b918..9d6c62e47a3 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -72,9 +72,7 @@ import {pluralize} from "../../../ember-inflector/lib/main"; to modify to fit your specific needs.** For example review the docs for each method of this mixin: - - * [extractArray](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_extractArray) - * [extractSingle](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_extractSingle) + * [normalize](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_normalize) * [serializeBelongsTo](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeBelongsTo) * [serializeHasMany](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeHasMany) @@ -83,6 +81,47 @@ import {pluralize} from "../../../ember-inflector/lib/main"; */ var EmbeddedRecordsMixin = Ember.Mixin.create({ + /** + Normalize the record and recursively normalize/extract all the embedded records + while pushing them into the store as they are encountered + + A payload with an attr configured for embedded records needs to be extracted: + + ```js + { + "post": { + "id": "1" + "title": "Rails is omakase", + "comments": [{ + "id": "1", + "body": "Rails is unagi" + }, { + "id": "2", + "body": "Omakase O_o" + }] + } + } + ``` + @method normalize + @param {subclass of DS.Model} type + @param {Object} hash to be normalized + @param {String} key the hash has been referenced by + @return {Object} the normalized hash + **/ + normalize: function(type, hash, prop) { + hash = this._super(type, hash, prop); + hash = extractEmbeddedRecords(this, this.store, type, hash); + return hash; + }, + + keyForRelationship: function(key, type){ + if (hasDeserializeRecordsOption(this.attrs, key)) { + return this.keyForAttribute(key); + } else { + return this._super(key, type) || key; + } + }, + /** Serialize `belongsTo` relationship when it is configured as an embedded object. @@ -151,7 +190,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ json[key] = get(embeddedRecord, 'id'); } } else if (includeRecords) { - key = getKeyForAttribute.call(this, attr); + key = this.keyForAttribute(attr); if (!embeddedRecord) { json[key] = null; } else { @@ -256,7 +295,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ key = this.keyForRelationship(attr, relationship.kind); json[key] = get(record, attr).mapBy('id'); } else if (includeRecords) { - key = getKeyForAttribute.call(this, attr); + key = this.keyForAttribute(attr); json[key] = get(record, attr).map(function(embeddedRecord) { var serializedEmbeddedRecord = embeddedRecord.serialize({includeId: true}); this.removeEmbeddedForeignKey(record, embeddedRecord, relationship, serializedEmbeddedRecord); @@ -295,135 +334,9 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ } } } - }, - - /** - Extract an embedded object from the payload for a single object - and add the object in the compound document (side-loaded) format instead. - - A payload with an attribute configured for embedded records needs to be extracted: - - ```js - { - "post": { - "id": 1 - "title": "Rails is omakase", - "author": { - "id": 2 - "name": "dhh" - } - "comments": [] - } - } - ``` - - Ember Data is expecting a payload with a compound document (side-loaded) like: - - ```js - { - "post": { - "id": "1" - "title": "Rails is omakase", - "author": "2" - "comments": [] - }, - "authors": [{ - "id": "2" - "post": "1" - "name": "dhh" - }] - "comments": [] - } - ``` - - The payload's `author` attribute represents an object with a `belongsTo` relationship. - The `post` attribute under `author` is the foreign key with the id for the post - - @method extractSingle - @param {DS.Store} store - @param {subclass of DS.Model} primaryType - @param {Object} payload - @param {String} recordId - @return Object the primary response to the original request - */ - extractSingle: function(store, primaryType, payload, recordId) { - var key = primaryType.typeKey; - var root = getKeyForAttribute.call(this, key); - var partial = payload[root]; - - updatePayloadWithEmbedded(this, store, primaryType, payload, partial); - - return this._super(store, primaryType, payload, recordId); - }, - - /** - Extract embedded objects in an array when an attr is configured for embedded, - and add them as side-loaded objects instead. - - A payload with an attr configured for embedded records needs to be extracted: - - ```js - { - "post": { - "id": "1" - "title": "Rails is omakase", - "comments": [{ - "id": "1", - "body": "Rails is unagi" - }, { - "id": "2", - "body": "Omakase O_o" - }] - } - } - ``` - - Ember Data is expecting a payload with compound document (side-loaded) like: - - ```js - { - "post": { - "id": "1" - "title": "Rails is omakase", - "comments": ["1", "2"] - }, - "comments": [{ - "id": "1", - "body": "Rails is unagi" - }, { - "id": "2", - "body": "Omakase O_o" - }] - } - ``` - - The payload's `comments` attribute represents records in a `hasMany` relationship - - @method extractArray - @param {DS.Store} store - @param {subclass of DS.Model} primaryType - @param {Object} payload - @return {Array} The primary array that was returned in response - to the original query. - */ - extractArray: function(store, primaryType, payload) { - var key = primaryType.typeKey; - var root = getKeyForAttribute.call(this, key); - var partials = payload[pluralize(root)]; - - forEach(partials, function(partial) { - updatePayloadWithEmbedded(this, store, primaryType, payload, partial); - }, this); - - return this._super(store, primaryType, payload); } }); -// `keyForAttribute` is optional but may be defined when extending a serializer prototype -var getKeyForAttribute = function(attr) { - return (this.keyForAttribute) ? this.keyForAttribute(attr) : attr; -}; - // checks config for attrs option to embedded (always) - serialize and deserialize function hasEmbeddedAlwaysOption(attrs, attr) { var option = attrsOption(attrs, attr); @@ -457,8 +370,7 @@ function noSerializeOptionSpecified(attrs, attr) { function hasDeserializeRecordsOption(attrs, attr) { var alwaysEmbed = hasEmbeddedAlwaysOption(attrs, attr); var option = attrsOption(attrs, attr); - var hasSerializingOption = option && (option.deserialize || option.serialize); - return alwaysEmbed || hasSerializingOption /* option.deserialize === 'records' */; + return alwaysEmbed || (option && option.deserialize === 'records'); } function attrsOption(attrs, attr) { @@ -467,84 +379,59 @@ function attrsOption(attrs, attr) { // chooses a relationship kind to branch which function is used to update payload // does not change payload if attr is not embedded -function updatePayloadWithEmbedded(serializer, store, type, payload, partial) { +function extractEmbeddedRecords(serializer, store, type, partial) { var attrs = get(serializer, 'attrs'); if (!attrs) { - return; + return partial; } + type.eachRelationship(function(key, relationship) { if (hasDeserializeRecordsOption(attrs, key)) { + var embeddedType = store.modelFor(relationship.type.typeKey); if (relationship.kind === "hasMany") { - updatePayloadWithEmbeddedHasMany(serializer, store, key, relationship, payload, partial); + extractEmbeddedHasMany(store, key, embeddedType, partial); } if (relationship.kind === "belongsTo") { - updatePayloadWithEmbeddedBelongsTo(serializer, store, key, relationship, payload, partial); + extractEmbeddedBelongsTo(store, key, embeddedType, partial); } } }); + + return partial; } // handles embedding for `hasMany` relationship -function updatePayloadWithEmbeddedHasMany(serializer, store, primaryType, relationship, payload, partial) { - var embeddedSerializer = store.serializerFor(relationship.type.typeKey); - var embeddedPrimaryKey = get(embeddedSerializer, 'primaryKey'); - var attr = relationship.type.typeKey; - // underscore forces the embedded records to be side loaded. - // it is needed when main type === relationship.type - var embeddedTypeKey = '_' + serializer.typeForRoot(relationship.type.typeKey); - var expandedKey = serializer.keyForRelationship(primaryType, relationship.kind); - var attribute = getKeyForAttribute.call(serializer, primaryType); - var ids = []; - - if (!partial[attribute]) { - return; +function extractEmbeddedHasMany(store, key, embeddedType, hash) { + if (!hash[key]) { + return hash; } - payload[embeddedTypeKey] = payload[embeddedTypeKey] || []; + var ids = []; - forEach(partial[attribute], function(data) { - var embeddedType = store.modelFor(attr); - updatePayloadWithEmbedded(embeddedSerializer, store, embeddedType, payload, data); - ids.push(data[embeddedPrimaryKey]); - payload[embeddedTypeKey].push(data); + var embeddedSerializer = store.serializerFor(embeddedType.typeKey); + forEach(hash[key], function(data) { + var embeddedRecord = embeddedSerializer.normalize(embeddedType, data, null); + store.push(embeddedType, embeddedRecord); + ids.push(embeddedRecord.id); }); - partial[expandedKey] = ids; - if(expandedKey !== attribute) { - delete partial[attribute]; - } + hash[key] = ids; + return hash; } -// handles embedding for `belongsTo` relationship -function updatePayloadWithEmbeddedBelongsTo(serializer, store, primaryType, relationship, payload, partial) { - var attrs = serializer.get('attrs'); - - if (!attrs || - !(hasDeserializeRecordsOption(attrs, Ember.String.camelize(primaryType)) || - hasDeserializeRecordsOption(attrs, primaryType))) { - return; +function extractEmbeddedBelongsTo(store, key, embeddedType, hash) { + if (!hash[key]) { + return hash; } - var attr = relationship.type.typeKey; - var _serializer = store.serializerFor(relationship.type.typeKey); - var primaryKey = get(_serializer, 'primaryKey'); - var embeddedTypeKey = Ember.String.pluralize(attr); // TODO don't use pluralize - var expandedKey = _serializer.keyForRelationship(primaryType, relationship.kind); - var attribute = getKeyForAttribute.call(_serializer, primaryType); - - if (!partial[attribute]) { - return; - } - payload[embeddedTypeKey] = payload[embeddedTypeKey] || []; - var embeddedType = store.modelFor(relationship.type.typeKey); - // Recursive call for nested record - updatePayloadWithEmbedded(_serializer, store, embeddedType, payload, partial[attribute]); - partial[expandedKey] = partial[attribute].id; - // Need to move an embedded `belongsTo` object into a pluralized collection - payload[embeddedTypeKey].push(partial[attribute]); - // Need a reference to the parent so relationship works between both `belongsTo` records - partial[attribute][relationship.parentType.typeKey + '_id'] = partial.id; - delete partial[attribute]; + + var embeddedSerializer = store.serializerFor(embeddedType.typeKey); + var embeddedRecord = embeddedSerializer.normalize(embeddedType, hash[key], null); + store.push(embeddedType, embeddedRecord); + + hash[key] = embeddedRecord.id; + //TODO Need to add a reference to the parent later so relationship works between both `belongsTo` records + return hash; } export default EmbeddedRecordsMixin; diff --git a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js index 8f0a188b04a..2b8d00aefa7 100644 --- a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js +++ b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js @@ -975,7 +975,7 @@ test("serializing relationships with an embedded and without calls super when no var Serializer = DS.RESTSerializer.extend({ serializeBelongsTo: function(record, json, relationship) { calledSerializeBelongsTo = true; - return DS.RESTSerializer.prototype.serializeBelongsTo.call(this, record, json, relationship); + return this._super(record, json, relationship); }, serializeHasMany: function(record, json, relationship) { calledSerializeHasMany = true; diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index a4fa3310260..1ad5c3df6dd 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -794,7 +794,9 @@ export default Ember.Object.extend({ @param {String} key @return {String} normalized key */ - + keyForAttribute: function(key){ + return key; + }, /** `keyForRelationship` can be used to define a custom key when @@ -817,6 +819,10 @@ export default Ember.Object.extend({ @return {String} normalized key */ + keyForRelationship: function(key, type){ + return key; + }, + // HELPERS /** From a93503d61b79766deea31da30cc77ac63774a4cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Gallego?= Date: Sun, 1 Jun 2014 23:44:30 +0200 Subject: [PATCH 0236/2527] Add a test for embedded belongsTo with a custom primaryKey --- .../embedded_records_mixin_test.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js index 2b8d00aefa7..4ad3b41deca 100644 --- a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js +++ b/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js @@ -959,6 +959,40 @@ test("Mixin can be used with RESTSerializer which does not define keyForAttribut }); }); +test("normalize with custom belongsTo primary key", function() { + env.container.register('adapter:evilMinion', DS.ActiveModelAdapter); + env.container.register('serializer:evilMinion', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + superVillain: {embedded: 'always'} + } + })); + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend({ + primaryKey: 'custom' + })); + + var serializer = env.container.lookup("serializer:evilMinion"); + var json_hash = { + evil_minion: { + id: "1", + name: "Alex", + super_villain: { + custom: "1", + first_name: "Tom", + last_name: "Dale" + } + } + }; + var json = serializer.extractSingle(env.store, EvilMinion, json_hash); + + deepEqual(json, { + id: "1", + name: "Alex", + superVillain: "1" + }, "Primary array was correct"); + + equal(env.store.recordForId("superVillain", "1").get("firstName"), "Tom", "Secondary record, Tom, found in the steore"); +}); + test("serializing relationships with an embedded and without calls super when not attr not present", function() { homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); secretLab = env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); From 1a1e6ab80ac5b780c28b74748de6b99e12dee42e Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 18 Jul 2014 16:07:29 -0400 Subject: [PATCH 0237/2527] Add a store.normalize() method to make it easy to normalize record data for store.push() --- packages/ember-data/lib/system/store.js | 25 +++++++++++++++++++ .../ember-data/tests/unit/store/push_test.js | 17 +++++++++++++ 2 files changed, 42 insertions(+) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 531122cd757..8c946b75c37 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1273,6 +1273,31 @@ Store = Ember.Object.extend({ serializer.pushPayload(this, payload); }, + /** + `normalize` converts a json payload into the normalized form that + [push](#method_push) expects. + + Example + + ```js + socket.on('message', function(message) { + var modelName = message.model; + var data = message.data; + store.push(modelName, store.normalize(modelName, data)); + }); + ``` + + @method normalize + @param {String} The name of the model type for this payload + @param {Object} payload + @return {Object} The normalized payload + */ + normalize: function (type, payload) { + var serializer = this.serializerFor(type); + var model = this.modelFor(type); + return serializer.normalize(model, payload); + }, + /** Update existing records in the store. Unlike [push](#method_push), update will merge the new data properties with the existing diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index 56d5a17967f..bf36c7bbeb8 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -298,3 +298,20 @@ test("Calling pushPayload without a type should use a model's serializer when no equal(person.get('firstName'), "Yehuda", "you can push raw JSON into the store"); }); + + + +test("Calling normalize should normalize the payload ", function () { + expect(1); + + var normalizedPayload = store.normalize('post', { + id: '1', + post_title: 'Ember rocks' + }); + + deepEqual(normalizedPayload, { + id: '1', + postTitle: 'Ember rocks' + }); + +}); From 7386736b39aeb7e72325405c82e7ee1aafaee997 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 18 Jul 2014 10:11:33 -0400 Subject: [PATCH 0238/2527] Throw and error if a user attempts to add a `data` property to a subclass of DS.Model --- packages/ember-data/lib/system/model/model.js | 6 ++++++ packages/ember-data/tests/unit/model_test.js | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 92d281f1901..a9120997279 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1026,6 +1026,12 @@ var Model = Ember.Object.extend(Ember.Evented, { willDestroy: function() { this._super(); this.clearRelationships(); + }, + + // This is a temporary solution until we refactor DS.Model to not + // rely on the data property. + willMergeMixin: function(props) { + Ember.assert('`data` is a reserved property name on DS.Model objects. Please choose a different property name for ' + this.constructor.toString(), !props.data); } }); diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index 645450ee69c..adbc46af45f 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -423,3 +423,15 @@ test("A DS.Model can be JSONified", function() { var record = store.createRecord('person', { name: "TomHuda" }); deepEqual(record.toJSON(), { name: "TomHuda" }); }); + +test("A subclass of DS.Model can not use the `data` property", function() { + var Person = DS.Model.extend({ + data: DS.attr('string') + }); + + var store = createStore({ person: Person }); + + expectAssertion(function() { + var record = store.createRecord('person', { name: "TomHuda" }); + }, /`data` is a reserved property name on DS.Model objects/); +}); From 75d89a6781b0d7712c80e78a0a61086a5b04d9ef Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 18 Jun 2014 15:36:49 -0400 Subject: [PATCH 0239/2527] Moved several normalize helper methods to the JSONSerializer - Move `normalizeAttributes` to the `JSONSerializer` (mirrors `serializeAttributes`) - Move `normalizeRelationships` to the `JSONSerializer` - Move `normalizePayload` to the `JSONSerializer` --- .../lib/serializers/json_serializer.js | 65 +++++++++++++++++++ .../lib/serializers/rest_serializer.js | 59 ----------------- .../serializers/json_serializer_test.js | 49 ++++++++++++++ 3 files changed, 114 insertions(+), 59 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 1ad5c3df6dd..9ac7f38ff2b 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -132,11 +132,74 @@ export default Ember.Object.extend({ if (!hash) { return hash; } this.normalizeId(hash); + this.normalizeAttributes(type, hash); + this.normalizeRelationships(type, hash); + this.normalizeUsingDeclaredMapping(type, hash); this.applyTransforms(type, hash); return hash; }, + /** + You can use this method to normalize all payloads, regardless of whether they + represent single records or an array. + + For example, you might want to remove some extraneous data from the payload: + + ```js + App.ApplicationSerializer = DS.JSONSerializer.extend({ + normalizePayload: function(payload) { + delete payload.version; + delete payload.status; + return payload; + } + }); + ``` + + @method normalizePayload + @param {Object} payload + @return {Object} the normalized payload + */ + normalizePayload: function(payload) { + return payload; + }, + + /** + @method normalizeAttributes + @private + */ + normalizeAttributes: function(type, hash) { + var payloadKey, key; + + if (this.keyForAttribute) { + type.eachAttribute(function(key) { + payloadKey = this.keyForAttribute(key); + if (key === payloadKey) { return; } + + hash[key] = hash[payloadKey]; + delete hash[payloadKey]; + }, this); + } + }, + + /** + @method normalizeRelationships + @private + */ + normalizeRelationships: function(type, hash) { + var payloadKey, key; + + if (this.keyForRelationship) { + type.eachRelationship(function(key, relationship) { + payloadKey = this.keyForRelationship(key, relationship.kind); + if (key === payloadKey) { return; } + + hash[key] = hash[payloadKey]; + delete hash[payloadKey]; + }, this); + } + }, + /** @method normalizeUsingDeclaredMapping @private @@ -714,6 +777,7 @@ export default Ember.Object.extend({ @return {Object} json The deserialized payload */ extractSingle: function(store, type, payload) { + payload = this.normalizePayload(payload); return this.normalize(type, payload); }, @@ -740,6 +804,7 @@ export default Ember.Object.extend({ @return {Array} array An array of deserialized objects */ extractArray: function(store, type, arrayPayload) { + arrayPayload = this.normalizePayload(arrayPayload); var serializer = this; return map.call(arrayPayload, function(singlePayload) { return serializer.normalize(type, singlePayload); diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index 5a866d69a69..8698d9bf8d7 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -184,65 +184,6 @@ export default JSONSerializer.extend({ return hash; }, - /** - You can use this method to normalize all payloads, regardless of whether they - represent single records or an array. - - For example, you might want to remove some extraneous data from the payload: - - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ - normalizePayload: function(payload) { - delete payload.version; - delete payload.status; - return payload; - } - }); - ``` - - @method normalizePayload - @param {Object} payload - @return {Object} the normalized payload - */ - normalizePayload: function(payload) { - return payload; - }, - - /** - @method normalizeAttributes - @private - */ - normalizeAttributes: function(type, hash) { - var payloadKey, key; - - if (this.keyForAttribute) { - type.eachAttribute(function(key) { - payloadKey = this.keyForAttribute(key); - if (key === payloadKey) { return; } - - hash[key] = hash[payloadKey]; - delete hash[payloadKey]; - }, this); - } - }, - - /** - @method normalizeRelationships - @private - */ - normalizeRelationships: function(type, hash) { - var payloadKey, key; - - if (this.keyForRelationship) { - type.eachRelationship(function(key, relationship) { - payloadKey = this.keyForRelationship(key, relationship.kind); - if (key === payloadKey) { return; } - - hash[key] = hash[payloadKey]; - delete hash[payloadKey]; - }, this); - } - }, /** Called when the server has returned a payload representing diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index cb1107013bf..3a97906e1c9 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -203,3 +203,52 @@ test("Serializer should respect the primaryKey attribute when serializing record equal(payload._ID_, "1"); }); + +test("Serializer should respect keyForAttribute when extracting records", function() { + env.container.register('serializer:post', DS.JSONSerializer.extend({ + keyForAttribute: function(key) { + return key.toUpperCase(); + } + })); + + var jsonHash = {id: 1, TITLE: 'Rails is omakase'}; + + post = env.container.lookup("serializer:post").normalize(Post, jsonHash); + + equal(post.id, "1"); + equal(post.title, "Rails is omakase"); +}); + +test("Serializer should respect keyForRelationship when extracting records", function() { + env.container.register('serializer:post', DS.JSONSerializer.extend({ + keyForRelationship: function(key, type) { + return key.toUpperCase(); + } + })); + + var jsonHash = {id: 1, title: 'Rails is omakase', COMMENTS: ['1']}; + + post = env.container.lookup("serializer:post").normalize(Post, jsonHash); + + deepEqual(post.comments, ['1']); +}); + +test("normalizePayload is called during extractSingle", function() { + env.container.register('serializer:post', DS.JSONSerializer.extend({ + normalizePayload: function(payload) { + return payload.response; + } + })); + + var jsonHash = { + response: { + id: 1, + title: "Rails is omakase" + } + }; + + post = env.container.lookup("serializer:post").extractSingle(env.store, Post, jsonHash); + + equal(post.id, "1"); + equal(post.title, "Rails is omakase"); +}); From ce7220952061966a3c4dd400d12953a637d33696 Mon Sep 17 00:00:00 2001 From: jaaksarv Date: Tue, 4 Mar 2014 20:42:20 +0200 Subject: [PATCH 0240/2527] Added id and requestType back to extract* hooks id and requestType parameters went missing in when removing aliasMethod. See commit dd964d2b7fe87ef7368336bd401c40834950f736 : https://github.com/emberjs/data/commit/dd964d2b7fe87ef7368336bd401c40834950f736 --- .../lib/serializers/json_serializer.js | 68 +++++++++++++------ 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 9ac7f38ff2b..4328a0630d4 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -619,10 +619,12 @@ export default Ember.Object.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Object} payload + @param {String or Number} id + @param {String} requestType @return {Array} array An array of deserialized objects */ - extractFindAll: function(store, type, payload){ - return this.extractArray(store, type, payload); + extractFindAll: function(store, type, payload, id, requestType){ + return this.extractArray(store, type, payload, id, requestType); }, /** `extractFindQuery` is a hook into the extract method used when a @@ -633,10 +635,12 @@ export default Ember.Object.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Object} payload + @param {String or Number} id + @param {String} requestType @return {Array} array An array of deserialized objects */ - extractFindQuery: function(store, type, payload){ - return this.extractArray(store, type, payload); + extractFindQuery: function(store, type, payload, id, requestType){ + return this.extractArray(store, type, payload, id, requestType); }, /** `extractFindMany` is a hook into the extract method used when a @@ -647,10 +651,12 @@ export default Ember.Object.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Object} payload + @param {String or Number} id + @param {String} requestType @return {Array} array An array of deserialized objects */ - extractFindMany: function(store, type, payload){ - return this.extractArray(store, type, payload); + extractFindMany: function(store, type, payload, id, requestType){ + return this.extractArray(store, type, payload, id, requestType); }, /** `extractFindHasMany` is a hook into the extract method used when a @@ -661,10 +667,12 @@ export default Ember.Object.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Object} payload + @param {String or Number} id + @param {String} requestType @return {Array} array An array of deserialized objects */ - extractFindHasMany: function(store, type, payload){ - return this.extractArray(store, type, payload); + extractFindHasMany: function(store, type, payload, id, requestType){ + return this.extractArray(store, type, payload, id, requestType); }, /** @@ -676,10 +684,12 @@ export default Ember.Object.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Object} payload + @param {String or Number} id + @param {String} requestType @return {Object} json The deserialized payload */ - extractCreateRecord: function(store, type, payload) { - return this.extractSave(store, type, payload); + extractCreateRecord: function(store, type, payload, id, requestType) { + return this.extractSave(store, type, payload, id, requestType); }, /** `extractUpdateRecord` is a hook into the extract method used when @@ -690,10 +700,12 @@ export default Ember.Object.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Object} payload + @param {String or Number} id + @param {String} requestType @return {Object} json The deserialized payload */ - extractUpdateRecord: function(store, type, payload) { - return this.extractSave(store, type, payload); + extractUpdateRecord: function(store, type, payload, id, requestType) { + return this.extractSave(store, type, payload, id, requestType); }, /** `extractDeleteRecord` is a hook into the extract method used when @@ -704,10 +716,12 @@ export default Ember.Object.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Object} payload + @param {String or Number} id + @param {String} requestType @return {Object} json The deserialized payload */ - extractDeleteRecord: function(store, type, payload) { - return this.extractSave(store, type, payload); + extractDeleteRecord: function(store, type, payload, id, requestType) { + return this.extractSave(store, type, payload, id, requestType); }, /** @@ -719,10 +733,12 @@ export default Ember.Object.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Object} payload + @param {String or Number} id + @param {String} requestType @return {Object} json The deserialized payload */ - extractFind: function(store, type, payload) { - return this.extractSingle(store, type, payload); + extractFind: function(store, type, payload, id, requestType) { + return this.extractSingle(store, type, payload, id, requestType); }, /** `extractFindBelongsTo` is a hook into the extract method used when @@ -733,10 +749,12 @@ export default Ember.Object.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Object} payload + @param {String or Number} id + @param {String} requestType @return {Object} json The deserialized payload */ - extractFindBelongsTo: function(store, type, payload) { - return this.extractSingle(store, type, payload); + extractFindBelongsTo: function(store, type, payload, id, requestType) { + return this.extractSingle(store, type, payload, id, requestType); }, /** `extractSave` is a hook into the extract method used when a call @@ -747,10 +765,12 @@ export default Ember.Object.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Object} payload + @param {String or Number} id + @param {String} requestType @return {Object} json The deserialized payload */ - extractSave: function(store, type, payload) { - return this.extractSingle(store, type, payload); + extractSave: function(store, type, payload, id, requestType) { + return this.extractSingle(store, type, payload, id, requestType); }, /** @@ -774,9 +794,11 @@ export default Ember.Object.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Object} payload + @param {String or Number} id + @param {String} requestType @return {Object} json The deserialized payload */ - extractSingle: function(store, type, payload) { + extractSingle: function(store, type, payload, id, requestType) { payload = this.normalizePayload(payload); return this.normalize(type, payload); }, @@ -801,9 +823,11 @@ export default Ember.Object.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Object} payload + @param {String or Number} id + @param {String} requestType @return {Array} array An array of deserialized objects */ - extractArray: function(store, type, arrayPayload) { + extractArray: function(store, type, arrayPayload, id, requestType) { arrayPayload = this.normalizePayload(arrayPayload); var serializer = this; return map.call(arrayPayload, function(singlePayload) { From 5c774c9ab4026054fce9cbe506abd9069295e479 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 18 Jul 2014 10:29:34 -0400 Subject: [PATCH 0241/2527] Added a failing test for #2088. This test ensures the serializer does not confuse a new record returned in response to a delete with the original record when both records are of the same type. --- .../integration/adapter/rest_adapter_test.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 13f46754ebf..80b3738ba97 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -554,6 +554,27 @@ test("delete - a payload with sideloaded updates pushes the updates", function() })); }); +test("delete - a payload with sidloaded updates pushes the updates when the original record is omitted", function() { + store.push('post', { id: 1, name: "Rails is omakase" }); + + store.find('post', 1).then(async(function(post) { + ajaxResponse({ posts: [{ id: 2, name: "The Parley Letter" }] }); + + post.deleteRecord(); + return post.save(); + })).then(async(function(post) { + equal(passedUrl, "/posts/1"); + equal(passedVerb, "DELETE"); + equal(passedHash, undefined); + + equal(post.get('isDirty'), false, "the original post isn't dirty anymore"); + equal(post.get('isDeleted'), true, "the original post is now deleted"); + + var newPost = store.getById('post', 2); + equal(newPost.get('name'), "The Parley Letter", "The new post was added to the store"); + })); +}); + test("delete - deleting a newly created record should not throw an error", function() { var post = store.createRecord('post'); From 8f28a37eed0bf6492dfe58ea779f6bc1c399c757 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 22 Jul 2014 14:58:24 -0400 Subject: [PATCH 0242/2527] Fix incorrect adapter example. Closes #1668 Thanks @aprescott --- packages/ember-data/lib/system/adapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index e23689ebc3e..8e2700f6c17 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -157,7 +157,7 @@ var Adapter = Ember.Object.extend({ ```javascript App.ApplicationAdapter = DS.Adapter.extend({ find: function(store, type, id) { - var url = [type, id].join('/'); + var url = [type.typeKey, id].join('/'); return new Ember.RSVP.Promise(function(resolve, reject) { jQuery.getJSON(url).then(function(data) { From ad11c021919f3106361229029ddf4b62306688f2 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 22 Jul 2014 15:18:10 -0400 Subject: [PATCH 0243/2527] Update bower dependency to fix npm install error. Closes #2108 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8edf879daa2..d025895e5c8 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ }, "devDependencies": { "aws-sdk": "~2.0.0-rc8", - "bower": "~1.2", + "bower": "~1.3", "defeatureify": "~0.1.4", "ember-publisher": "0.0.3", "grunt": "~0.4.2", From ce8254cd26d28d46eebc233913bb046b07131b7c Mon Sep 17 00:00:00 2001 From: Bradley Priest Date: Thu, 29 May 2014 22:59:52 +0800 Subject: [PATCH 0244/2527] DateTransform serialises into ISO8601 string --- CHANGELOG.md | 2 + packages/ember-data/lib/transforms/date.js | 65 ++++++++------------ packages/ember-data/tests/unit/model_test.js | 4 +- 3 files changed, 29 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37489212b91..409ea7aaba3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Master +* DS.DateTransform now serializes to ISO8601 format by default. Adds millisecond precision to serializing dates + ### Ember Data 1.0.0-beta.8 _(May 28, 2014)_ * Each RecordArray gets a copy of the models's metada object instead of sharing the same meta object. Enables several paginated arrays to coexist without clobbering each other diff --git a/packages/ember-data/lib/transforms/date.js b/packages/ember-data/lib/transforms/date.js index 65f3c2f7d3c..ef2301fb12f 100644 --- a/packages/ember-data/lib/transforms/date.js +++ b/packages/ember-data/lib/transforms/date.js @@ -19,8 +19,30 @@ */ import Transform from "./base"; -function pad(num) { - return num < 10 ? "0"+num : ""+num; +// Date.prototype.toISOString shim +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString +var toISOString = Date.prototype.toISOString || function() { + function pad(number) { + if ( number < 10 ) { + return '0' + number; + } + return number; + } + + return this.getUTCFullYear() + + '-' + pad( this.getUTCMonth() + 1 ) + + '-' + pad( this.getUTCDate() ) + + 'T' + pad( this.getUTCHours() ) + + ':' + pad( this.getUTCMinutes() ) + + ':' + pad( this.getUTCSeconds() ) + + '.' + (this.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + + 'Z'; +}; + +if (Ember.SHIM_ES5) { + if (!Date.prototype.toISOString) { + Date.prototype.toISOString = toISOString; + } } export default Transform.extend({ @@ -43,44 +65,7 @@ export default Transform.extend({ serialize: function(date) { if (date instanceof Date) { - var days = [ - "Sun", - "Mon", - "Tue", - "Wed", - "Thu", - "Fri", - "Sat" - ]; - var months = [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec" - ]; - - var utcYear = date.getUTCFullYear(); - var utcMonth = date.getUTCMonth(); - var utcDayOfMonth = date.getUTCDate(); - var utcDay = date.getUTCDay(); - var utcHours = date.getUTCHours(); - var utcMinutes = date.getUTCMinutes(); - var utcSeconds = date.getUTCSeconds(); - - var dayOfWeek = days[utcDay]; - var dayOfMonth = pad(utcDayOfMonth); - var month = months[utcMonth]; - - return dayOfWeek + ", " + dayOfMonth + " " + month + " " + utcYear + " " + - pad(utcHours) + ":" + pad(utcMinutes) + ":" + pad(utcSeconds) + " GMT"; + return toISOString.call(date); } else { return null; } diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index adbc46af45f..d909143de6d 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -369,8 +369,8 @@ test("a DS.Model can describe Date attributes", function() { converts('date', null, null); converts('date', undefined, undefined); - var dateString = "Sat, 31 Dec 2011 00:08:16 GMT"; - var date = new Date(dateString); + var dateString = "2011-12-31T00:08:16.000Z"; + var date = new Date(Ember.Date.parse(dateString)); var store = createStore(); From 0456a0711308a54803a4a012d31fc7ebe1740c2a Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 22 Jul 2014 12:37:35 -0500 Subject: [PATCH 0245/2527] allow attributes to be excluded via the attrs hash adds a shorthnad versus overriding serializeAttribute or serialize and using this._super --- .../lib/serializers/json_serializer.js | 29 +++++++++++++++++++ .../serializers/json_serializer_test.js | 16 ++++++++++ 2 files changed, 45 insertions(+) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 4328a0630d4..d04c0041528 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -67,6 +67,30 @@ export default Ember.Object.extend({ }); ``` + You can also remove attributes by setting the `serialize` key to + false in your mapping object. + + Example + + ```javascript + App.PersonSerializer = DS.JSONSerializer.extend({ + attrs: { + admin: {serialize: false}, + occupation: {key: 'career'} + } + }); + ``` + + When serialized: + + ```javascript + { + "career": "magician" + } + ``` + + Note that the `admin` is now not included in the payload. + @property attrs @type {Object} */ @@ -436,6 +460,11 @@ export default Ember.Object.extend({ value = transform.serialize(value); } + // If attrs.key.serialize is false, do not include the value in the + // response to the server at all. + if (attrs && attrs[key] && attrs[key].serialize === false) { + return; + } // if provided, use the mapping provided by `attrs` in // the serializer if (attrs && attrs[key]) { diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index 3a97906e1c9..37153491b6c 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -179,6 +179,22 @@ test('Serializer should respect the attrs hash when serializing records', functi equal(payload.title_payload_key, "Rails is omakase"); }); +test('Serializer respects `serialize: false` on the attrs hash', function(){ + expect(2); + env.container.register("serializer:post", DS.JSONSerializer.extend({ + attrs: { + title: {serialize: false} + } + })); + + post = env.store.createRecord("post", { title: "Rails is omakase"}); + + var payload = env.container.lookup("serializer:post").serialize(post); + + ok(!payload.hasOwnProperty('title'), "Does not add the key to instance"); + ok(!payload.hasOwnProperty('[object Object]'),"Does not add some random key like [object Object]"); +}); + test("Serializer should respect the primaryKey attribute when extracting records", function() { env.container.register('serializer:post', DS.JSONSerializer.extend({ primaryKey: '_ID_' From 1eed136296674ae3bc02d281255061ff9e1dc807 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 23 Jul 2014 11:43:07 -0400 Subject: [PATCH 0246/2527] cleanup --- .../lib/adapters/fixture_adapter.js | 8 ++--- .../ember-data/lib/adapters/rest_adapter.js | 32 +++++++++---------- packages/ember-data/lib/initializers/store.js | 6 ++-- .../lib/serializers/json_serializer.js | 5 +-- .../lib/system/changes/relationship_change.js | 4 +-- .../ember-data/lib/system/container_proxy.js | 10 +++--- .../lib/system/debug/debug_adapter.js | 4 +-- .../ember-data/lib/system/model/attributes.js | 4 +-- packages/ember-data/lib/system/model/model.js | 30 +++++++++-------- .../ember-data/lib/system/model/states.js | 4 +-- .../lib/system/record_array_manager.js | 10 +++--- .../adapter_populated_record_array.js | 8 ++--- .../lib/system/record_arrays/many_array.js | 24 +++++++------- .../lib/system/record_arrays/record_array.js | 4 +-- .../lib/system/relationships/ext.js | 23 +++++++------ .../lib/system/relationships/has_many.js | 8 ++--- packages/ember-data/lib/system/store.js | 3 ++ 17 files changed, 99 insertions(+), 88 deletions(-) diff --git a/packages/ember-data/lib/adapters/fixture_adapter.js b/packages/ember-data/lib/adapters/fixture_adapter.js index adf0541f5e6..6702fa52066 100644 --- a/packages/ember-data/lib/adapters/fixture_adapter.js +++ b/packages/ember-data/lib/adapters/fixture_adapter.js @@ -136,8 +136,8 @@ export default Adapter.extend({ @return {Promise} promise */ find: function(store, type, id) { - var fixtures = this.fixturesForType(type), - fixture; + var fixtures = this.fixturesForType(type); + var fixture; Ember.assert("Unable to find fixtures for model type "+type.toString() +". If you're defining your fixtures using `Model.FIXTURES = ...`, please change it to `Model.reopenClass({ FIXTURES: ... })`.", fixtures); @@ -279,7 +279,7 @@ export default Adapter.extend({ deleteLoadedFixture: function(type, record) { var existingFixture = this.findExistingFixture(type, record); - if(existingFixture) { + if (existingFixture) { var index = indexOf(type.FIXTURES, existingFixture); type.FIXTURES.splice(index, 1); return true; @@ -307,7 +307,7 @@ export default Adapter.extend({ */ findFixtureById: function(fixtures, id) { return Ember.A(fixtures).find(function(r) { - if(''+get(r, 'id') === ''+id) { + if (''+get(r, 'id') === ''+id) { return true; } else { return false; diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 87318bbd424..12dd13441b2 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -324,9 +324,9 @@ export default Adapter.extend({ @return {Promise} promise */ findHasMany: function(store, record, url) { - var host = get(this, 'host'), - id = get(record, 'id'), - type = record.constructor.typeKey; + var host = get(this, 'host'); + var id = get(record, 'id'); + var type = record.constructor.typeKey; if (host && url.charAt(0) === '/' && url.charAt(1) !== '/') { url = host + url; @@ -363,8 +363,8 @@ export default Adapter.extend({ @return {Promise} promise */ findBelongsTo: function(store, record, url) { - var id = get(record, 'id'), - type = record.constructor.typeKey; + var id = get(record, 'id'); + var type = record.constructor.typeKey; return this.ajax(this.urlPrefix(url, this.buildURL(type, id)), 'GET'); }, @@ -454,9 +454,9 @@ export default Adapter.extend({ @return {String} url */ buildURL: function(type, id) { - var url = [], - host = get(this, 'host'), - prefix = this.urlPrefix(); + var url = []; + var host = get(this, 'host'); + var prefix = this.urlPrefix(); if (type) { url.push(this.pathForType(type)); } if (id) { url.push(id); } @@ -477,9 +477,9 @@ export default Adapter.extend({ @return {String} urlPrefix */ urlPrefix: function(path, parentURL) { - var host = get(this, 'host'), - namespace = get(this, 'namespace'), - url = []; + var host = get(this, 'host'); + var namespace = get(this, 'namespace'); + var url = []; if (path) { // Absolute path @@ -599,11 +599,11 @@ export default Adapter.extend({ @param {Object} hash @return {Promise} promise */ - ajax: function(url, type, hash) { + ajax: function(url, type, options) { var adapter = this; return new Ember.RSVP.Promise(function(resolve, reject) { - hash = adapter.ajaxOptions(url, type, hash); + var hash = adapter.ajaxOptions(url, type, options); hash.success = function(json) { Ember.run(null, resolve, json); @@ -625,8 +625,8 @@ export default Adapter.extend({ @param {Object} hash @return {Object} hash */ - ajaxOptions: function(url, type, hash) { - hash = hash || {}; + ajaxOptions: function(url, type, options) { + var hash = options || {}; hash.url = url; hash.type = type; hash.dataType = 'json'; @@ -646,8 +646,6 @@ export default Adapter.extend({ }; } - return hash; } - }); diff --git a/packages/ember-data/lib/initializers/store.js b/packages/ember-data/lib/initializers/store.js index ff43db1cdd5..7c84d2b8a0d 100644 --- a/packages/ember-data/lib/initializers/store.js +++ b/packages/ember-data/lib/initializers/store.js @@ -21,9 +21,9 @@ export default function initializeStore(container, application){ var proxy = new ContainerProxy(container); proxy.registerDeprecations([ - {deprecated: 'serializer:_default', valid: 'serializer:-default'}, - {deprecated: 'serializer:_rest', valid: 'serializer:-rest'}, - {deprecated: 'adapter:_rest', valid: 'adapter:-rest'} + { deprecated: 'serializer:_default', valid: 'serializer:-default' }, + { deprecated: 'serializer:_rest', valid: 'serializer:-rest' }, + { deprecated: 'adapter:_rest', valid: 'adapter:-rest' } ]); // new go forward paths diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 4328a0630d4..f6f32c7157d 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -828,9 +828,10 @@ export default Ember.Object.extend({ @return {Array} array An array of deserialized objects */ extractArray: function(store, type, arrayPayload, id, requestType) { - arrayPayload = this.normalizePayload(arrayPayload); + var normalizedPayload = this.normalizePayload(arrayPayload); var serializer = this; - return map.call(arrayPayload, function(singlePayload) { + + return map.call(normalizedPayload, function(singlePayload) { return serializer.normalize(type, singlePayload); }); }, diff --git a/packages/ember-data/lib/system/changes/relationship_change.js b/packages/ember-data/lib/system/changes/relationship_change.js index bb845f8695a..ea686c23409 100644 --- a/packages/ember-data/lib/system/changes/relationship_change.js +++ b/packages/ember-data/lib/system/changes/relationship_change.js @@ -68,10 +68,10 @@ var OneToOneChange = {}; var ManyToManyChange = {}; RelationshipChange._createChange = function(options){ - if(options.changeType === "add"){ + if (options.changeType === "add"){ return RelationshipChangeAdd.create(options); } - if(options.changeType === "remove"){ + if (options.changeType === "remove"){ return RelationshipChangeRemove.create(options); } }; diff --git a/packages/ember-data/lib/system/container_proxy.js b/packages/ember-data/lib/system/container_proxy.js index 442601a806d..c39659c9cfa 100644 --- a/packages/ember-data/lib/system/container_proxy.js +++ b/packages/ember-data/lib/system/container_proxy.js @@ -36,10 +36,12 @@ ContainerProxy.prototype.registerDeprecation = function(deprecated, valid) { }; ContainerProxy.prototype.registerDeprecations = function(proxyPairs) { - for (var i = proxyPairs.length; i > 0; i--) { - var proxyPair = proxyPairs[i - 1], - deprecated = proxyPair['deprecated'], - valid = proxyPair['valid']; + var i, proxyPair, deprecated, valid, proxy; + + for (i = proxyPairs.length; i > 0; i--) { + proxyPair = proxyPairs[i - 1]; + deprecated = proxyPair['deprecated']; + valid = proxyPair['valid']; this.registerDeprecation(deprecated, valid); } diff --git a/packages/ember-data/lib/system/debug/debug_adapter.js b/packages/ember-data/lib/system/debug/debug_adapter.js index e9910fbd510..08f71085b69 100644 --- a/packages/ember-data/lib/system/debug/debug_adapter.js +++ b/packages/ember-data/lib/system/debug/debug_adapter.js @@ -91,8 +91,8 @@ export default Ember.DataAdapter.extend({ }, observeRecord: function(record, recordUpdated) { - var releaseMethods = Ember.A(), self = this, - keysToObserve = Ember.A(['id', 'isNew', 'isDirty']); + var releaseMethods = Ember.A(), self = this; + var keysToObserve = Ember.A(['id', 'isNew', 'isDirty']); record.eachAttribute(function(key) { keysToObserve.push(key); diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 5eb5937902f..69b671a6edd 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -56,7 +56,7 @@ Model.reopenClass({ }); return map; - }), + }).readOnly(), /** A map whose keys are the attributes of the model (properties @@ -99,7 +99,7 @@ Model.reopenClass({ }); return map; - }), + }).readOnly(), /** Iterates through the attributes of the model, calling the passed function on each diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index a9120997279..cfc2fccd872 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -453,16 +453,16 @@ var Model = Ember.Object.extend(Ember.Evented, { // POSSIBLE TODO: Remove this code and replace with // always having direct references to state objects - var pivotName = name.split(".", 1), - currentState = get(this, 'currentState'), - state = currentState; + var pivotName = name.split('.', 1); + var currentState = get(this, 'currentState'); + var state = currentState; do { if (state.exit) { state.exit(this); } state = state.parentState; } while (!state.hasOwnProperty(pivotName)); - var path = name.split("."); + var path = name.split('.'); var setups = [], enters = [], i, l; @@ -651,10 +651,10 @@ var Model = Ember.Object.extend(Ember.Evented, { and value is an [oldProp, newProp] array. */ changedAttributes: function() { - var oldData = get(this, '_data'), - newData = get(this, '_attributes'), - diffData = {}, - prop; + var oldData = get(this, '_data'); + var newData = get(this, '_attributes'); + var diffData = {}; + var prop; for (prop in newData) { diffData[prop] = [oldData[prop], newData[prop]]; @@ -907,7 +907,9 @@ var Model = Ember.Object.extend(Ember.Evented, { this._inFlightAttributes = this._attributes; this._attributes = {}; - return PromiseObject.create({ promise: resolver.promise }); + return PromiseObject.create({ + promise: resolver.promise + }); }, /** @@ -937,8 +939,7 @@ var Model = Ember.Object.extend(Ember.Evented, { reload: function() { set(this, 'isReloading', true); - var record = this; - + var record = this; var promiseLabel = "DS: Model#reload of " + this; var promise = new Promise(function(resolve){ record.send('reloadRecord', resolve); @@ -951,7 +952,9 @@ var Model = Ember.Object.extend(Ember.Evented, { throw reason; }, "DS: Model#reload complete, update flags"); - return PromiseObject.create({ promise: promise }); + return PromiseObject.create({ + promise: promise + }); }, // FOR USE DURING COMMIT PROCESS @@ -1016,7 +1019,7 @@ var Model = Ember.Object.extend(Ember.Evented, { }, _triggerDeferredTriggers: function() { - for (var i=0, l=this._deferredTriggers.length; i Date: Thu, 24 Jul 2014 08:41:03 +0200 Subject: [PATCH 0247/2527] Added a test for findMany using the correct URL --- .../integration/adapter/rest_adapter_test.js | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 80b3738ba97..d8d988bff9e 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -842,6 +842,26 @@ test("findQuery - data is normalized through custom serializers", function() { })); }); +test("findMany - findMany uses a correct URL to access the records", function() { + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + + store.push('post', { id: 1, name: "Rails is omakase", comments: [ 1, 2, 3 ] }); + + var post = store.getById('post', 1); + ajaxResponse({ + comments: [ + { id: 1, name: "FIRST" }, + { id: 2, name: "Rails is unagi" }, + { id: 3, name: "What is omakase?" } + ] + }); + post.get('comments').then(async(function(comments) { + equal(passedUrl, "/comments"); + deepEqual(passedHash, {data: {ids: ["1", "2", "3"]}}); + })); +}); + + test("findMany - returning an array populates the array", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); From 51728a806426309f494de5d8930b9f8951ffac6a Mon Sep 17 00:00:00 2001 From: IgorT Date: Sat, 7 Jun 2014 15:52:32 -0300 Subject: [PATCH 0248/2527] Coalesce find requests, add support for preloading data This PR brings following improvements/changes: 1. Find calls from the same runloop will be coalesced into findMany requests if the adapter has a findMany method 2. Adds a groupRecordsForFindMany hook on the adapter that allows you to decide how to coalesce the record requests. This will enable fixing of bugs such as #651, by segmenting on the number of records 3. Allows users to preset attributes and relationships on a model when doing a find call. For relationships you can either pass in a record or an id 4. Gives rudimentary support for nested urls, by passing in the record object to the buildUrl method 5. Removes the owner being passed to findMany becuase it can be looked up on the original record 6. Adds couple special cased SSOT features that were needed for buildUrl/removal of owner property to be viable This PR lays the groundwork for: 1. Adding support for reloading hasManys 2. Making nice sugar for nestedUrls in the RestAdater --- .../ember-data/lib/adapters/rest_adapter.js | 143 ++++++- packages/ember-data/lib/system/adapter.js | 53 +-- packages/ember-data/lib/system/model/model.js | 62 ++++ .../ember-data/lib/system/model/states.js | 8 + .../lib/system/record_arrays/many_array.js | 2 +- .../lib/system/relationships/belongs_to.js | 10 +- .../lib/system/relationships/has_many.js | 15 +- packages/ember-data/lib/system/store.js | 241 ++++++++---- .../integration/adapter/rest_adapter_test.js | 162 ++++++++ .../relationships/has_many_test.js | 8 +- .../tests/unit/model/relationships_test.js | 43 +-- .../tests/unit/store/adapter_interop_test.js | 351 +++++++++++++++++- .../tests/unit/store/unload_test.js | 5 +- tests/ember_configuration.js | 4 +- 14 files changed, 942 insertions(+), 165 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 12dd13441b2..056458b254b 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -141,6 +141,50 @@ var forEach = Ember.ArrayPolyfills.forEach; */ export default Adapter.extend({ defaultSerializer: '-rest', + + /** + By default the RESTAdapter will send each find request coming from a `store.find` + or from accessing a relationship separately to the server. If your server supports passing + ids as a query string, you can set coalesceFindRequests to true to coalesce all find requests + within a single runloop. + + For example, if you have an initial payload of + ```javascript + post: { + id:1, + comments: [1,2] + } + ``` + + By default calling `post.get('comments')` will trigger the following requests(assuming the + comments haven't been loaded before): + + ``` + GET /comments/1 + GET /comments/2 + ``` + + If you set coalesceFindRequests to `true` it will instead trigger the following request: + + ``` + GET /comments?ids[]=1&ids[]=2 + ``` + + Setting coalesceFindRequests to `true` also works for `store.find` requests and `belongsTo` + relationships accessed within the same runloop. If you set `coalesceFindRequests: true` + + ```javascript + store.find('comment', 1); + store.find('comment', 2); + ``` + + will also send a request to: `GET /comments?ids[]=1&ids[]=2` + + @property coalesceFindRequests + @type {boolean} + */ + coalesceFindRequests: false, + /** Endpoint paths can be prefixed with a `namespace` by setting the namespace property on the adapter: @@ -205,10 +249,11 @@ export default Adapter.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {String} id + @param {DS.Model} record @return {Promise} promise */ - find: function(store, type, id) { - return this.ajax(this.buildURL(type.typeKey, id), 'GET'); + find: function(store, type, id, record) { + return this.ajax(this.buildURL(type.typeKey, id, record), 'GET'); }, /** @@ -257,9 +302,7 @@ export default Adapter.extend({ }, /** - Called by the store in order to fetch a JSON array for - the unloaded records in a has-many relationship that were originally - specified as IDs. + Called by the store in order to fetch several records together if `coalesceFindRequests` is true For example, if the original payload looks like: @@ -288,10 +331,11 @@ export default Adapter.extend({ @param {DS.Store} store @param {subclass of DS.Model} type @param {Array} ids + @param {Array} records @return {Promise} promise */ - findMany: function(store, type, ids) { - return this.ajax(this.buildURL(type.typeKey), 'GET', { data: { ids: ids } }); + findMany: function(store, type, ids, records) { + return this.ajax(this.buildURL(type.typeKey, ids, records), 'GET', { data: { ids: ids } }); }, /** @@ -391,7 +435,7 @@ export default Adapter.extend({ serializer.serializeIntoHash(data, type, record, { includeId: true }); - return this.ajax(this.buildURL(type.typeKey), "POST", { data: data }); + return this.ajax(this.buildURL(type.typeKey, null, record), "POST", { data: data }); }, /** @@ -418,7 +462,7 @@ export default Adapter.extend({ var id = get(record, 'id'); - return this.ajax(this.buildURL(type.typeKey, id), "PUT", { data: data }); + return this.ajax(this.buildURL(type.typeKey, id, record), "PUT", { data: data }); }, /** @@ -435,7 +479,7 @@ export default Adapter.extend({ deleteRecord: function(store, type, record) { var id = get(record, 'id'); - return this.ajax(this.buildURL(type.typeKey, id), "DELETE"); + return this.ajax(this.buildURL(type.typeKey, id, record), "DELETE"); }, /** @@ -451,15 +495,20 @@ export default Adapter.extend({ @method buildURL @param {String} type @param {String} id + @param {DS.Model} record @return {String} url */ - buildURL: function(type, id) { - var url = []; - var host = get(this, 'host'); - var prefix = this.urlPrefix(); + buildURL: function(type, id, record) { + var url = [], + host = get(this, 'host'), + prefix = this.urlPrefix(); if (type) { url.push(this.pathForType(type)); } - if (id) { url.push(id); } + + //We might get passed in an array of ids from findMany + //in which case we don't want to modify the url, as the + //ids will be passed in through a query param + if (id && !Ember.isArray(id)) { url.push(id); } if (prefix) { url.unshift(prefix); } @@ -504,6 +553,60 @@ export default Adapter.extend({ return url.join('/'); }, + _stripIDFromURL: function(store, record) { + var type = store.modelFor(record); + var url = this.buildURL(type.typeKey, record.get('id'), record); + + var expandedURL = url.split('/'); + //Case when the url is of the format ...something/:id + var lastSegment = expandedURL[ expandedURL.length - 1 ]; + var id = record.get('id'); + if (lastSegment === id) { + expandedURL[expandedURL.length - 1] = ""; + } else if(endsWith(lastSegment, '?id=' + id)) { + //Case when the url is of the format ...something?id=:id + expandedURL[expandedURL.length - 1] = lastSegment.substring(0, lastSegment.length - id.length - 1); + } + + return expandedURL.join('/'); + }, + + /** + Organize records into groups, each of which is to be passed to separate + calls to `findMany`. + + This implementation groups together records that have the same base URL but + differing ids. For example `/comments/1` and `/comments/2` will be grouped together + because we know findMany can coalesce them together as `/comments?ids[]=1&ids[]=2` + + It also supports urls where ids are passed as a query param, such as `/comments?id=1` + but not those where there is more than 1 query param such as `/comments?id=2&name=David` + Currently only the query param of `id` is supported. If you need to support others, please + override this or the `_stripIDFromURL` method. + + It does not group records that have differing base urls, such as for example: `/posts/1/comments/2` + and `/posts/2/comments/3` + + @method groupRecordsForFindMany + @param {Array} records + @returns {Array} an array of arrays of records, each of which is to be + loaded separately by `findMany`. + */ + groupRecordsForFindMany: function (store, records) { + var groups = Ember.MapWithDefault.create({defaultValue: function(){return [];}}); + var adapter = this; + forEach.call(records, function(record){ + var baseUrl = adapter._stripIDFromURL(store, record); + groups.get(baseUrl).push(record); + }); + var groupsArray = []; + groups.forEach(function(key, group){ + groupsArray.push(group); + }); + + return groupsArray; + }, + /** Determines the pathname for a given type. @@ -649,3 +752,13 @@ export default Adapter.extend({ return hash; } }); + +//From http://stackoverflow.com/questions/280634/endswith-in-javascript +function endsWith(string, suffix){ + if (typeof String.prototype.endsWith !== 'function') { + return string.indexOf(suffix, string.length - suffix.length) !== -1; + } else { + return string.endsWith(suffix); + } +} + diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 8e2700f6c17..d5777ae98fe 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -417,42 +417,43 @@ var Adapter = Ember.Object.extend({ deleteRecord: Ember.required(Function), /** - Find multiple records at once. + By default the store will try to coalesce all `fetchRecord` calls within the same runloop + into as few requests as possible by calling groupRecordsForFindMany and passing it into a findMany call. + You can opt out of this behaviour by either not implementing the findMany hook or by setting + coalesceFindRequests to false - By default, it loops over the provided ids and calls `find` on each. - May be overwritten to improve performance and reduce the number of - server requests. - - Example + @property coalesceFindRequests + @type {boolean} + */ + coalesceFindRequests: true, - ```javascript - App.ApplicationAdapter = DS.Adapter.extend({ - findMany: function(store, type, ids) { - var url = type; - return new Ember.RSVP.Promise(function(resolve, reject) { - jQuery.getJSON(url, {ids: ids}).then(function(data) { - Ember.run(null, resolve, data); - }, function(jqXHR) { - jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); - }); - }); - } - }); - ``` + /** + Find multiple records at once if coalesceFindRequests is true @method findMany @param {DS.Store} store @param {subclass of DS.Model} type the DS.Model class of the records @param {Array} ids + @param {Array} records @return {Promise} promise */ - findMany: function(store, type, ids) { - var promises = map.call(ids, function(id) { - return this.find(store, type, id); - }, this); - return Ember.RSVP.all(promises); + /** + Organize records into groups, each of which is to be passed to separate + calls to `findMany`. + + For example, if your api has nested URLs that depend on the parent, you will + want to group records by their parent. + + The default implementation returns the records as a single group. + + @method groupRecordsForFindMany + @param {Array} records + @returns {Array} an array of arrays of records, each of which is to be + loaded separately by `findMany`. + */ + groupRecordsForFindMany: function (store, records) { + return [records]; } }); diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index cfc2fccd872..13abf5393f9 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -9,6 +9,7 @@ var get = Ember.get; var set = Ember.set; var merge = Ember.merge; var Promise = Ember.RSVP.Promise; +var forEach = Ember.ArrayPolyfills.forEach; var JSONSerializer; var retrieveFromCurrentState = Ember.computed('currentState', function(key, value) { @@ -629,6 +630,67 @@ var Model = Ember.Object.extend(Ember.Evented, { get(this, 'store').dataWasUpdated(this.constructor, this); }, + /** + When a find request is triggered on the store, the user can optionally passed in + attributes and relationships to be preloaded. These are meant to behave as if they + came back from the server, expect the user obtained them out of band and is informing + the store of their existence. The most common use case is for supporting client side + nested URLs, such as `/posts/1/comments/2` so the user can do + `store.find('comment', 2, {post:1})` without having to fetch the post. + + Preloaded data can be attributes and relationships passed in either as IDs or as actual + models. + + @method _preloadData + @private + @param {Object} preload + */ + _preloadData: function(preload) { + var record = this; + //TODO(Igor) consider the polymorphic case + forEach.call(Ember.keys(preload), function(key) { + var preloadValue = get(preload, key); + var relationshipMeta = record.constructor.metaForProperty(key); + if (relationshipMeta.isRelationship) { + record._preloadRelationship(key, preloadValue); + } else { + get(record, '_data')[key] = preloadValue; + } + }); + }, + + _preloadRelationship: function(key, preloadValue) { + var relationshipMeta = this.constructor.metaForProperty(key); + var type = relationshipMeta.type; + if (relationshipMeta.kind === 'hasMany'){ + this._preloadHasMany(key, preloadValue, type); + } else { + this._preloadBelongsTo(key, preloadValue, type); + } + }, + + _preloadHasMany: function(key, preloadValue, type) { + Ember.assert("You need to pass in an array to set a hasMany property on a record", Ember.isArray(preloadValue)); + var record = this; + + forEach.call(preloadValue, function(recordToPush) { + recordToPush = record._convertStringOrNumberIntoRecord(recordToPush, type); + get(record, key).pushObject(recordToPush); + }); + }, + + _preloadBelongsTo: function(key, preloadValue, type){ + var recordToPush = this._convertStringOrNumberIntoRecord(preloadValue, type); + set(this, key, recordToPush); + }, + + _convertStringOrNumberIntoRecord: function(value, type) { + if (Ember.typeOf(value) === 'string' || Ember.typeOf(value) === 'number'){ + return this.store.recordForId(type, value); + } + return value; + }, + /** Returns an object, whose keys are changed properties, and value is an [oldProp, newProp] array. diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index 941eddd5429..ee653a39a9e 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -254,6 +254,10 @@ var DirtyState = { // EVENTS didSetProperty: didSetProperty, + //TODO(Igor) reloading now triggers a + //loadingData event, though it seems fine? + loadingData: Ember.K, + propertyWasReset: function(record, name) { var stillDirty = false; @@ -536,6 +540,10 @@ var RootState = { // FLAGS isLoaded: true, + //TODO(Igor) Reloading now triggers a loadingData event, + //but it should be ok? + loadingData: Ember.K, + // SUBSTATES // If there are no local changes to a record, it remains diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index e34df9f34c4..33f262dc7f6 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -122,7 +122,7 @@ export default RecordArray.extend({ var owner = get(this, 'owner'); var unloadedRecords = records.filterBy('isEmpty', true); - store.fetchMany(unloadedRecords, owner); + store.scheduleFetchMany(unloadedRecords, owner); }, // Overrides Ember.Array's replace method to implement diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index 2ba087d4043..d75c6a2033f 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -35,7 +35,13 @@ function asyncBelongsTo(type, options, meta) { var belongsTo = data[key]; if (!isNone(belongsTo)) { - promise = store.fetchRecord(belongsTo) || Promise.cast(belongsTo, promiseLabel); + var inverse = this.constructor.inverseFor(key); + //but for now only in the oneToOne case + if (inverse && inverse.kind === 'belongsTo'){ + set(belongsTo, inverse.name, this); + } + //TODO(Igor) after OR doesn't seem that will be called + promise = store.findById(belongsTo.constructor, belongsTo.get('id')) || Promise.cast(belongsTo, promiseLabel); return PromiseObject.create({ promise: promise }); @@ -139,7 +145,7 @@ function belongsTo(type, options) { if (isNone(belongsTo)) { return null; } - store.fetchRecord(belongsTo); + store.findById(belongsTo.constructor, belongsTo.get('id')); return belongsTo; }).meta(meta); diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index 17211e743db..ce9ea7fce52 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -12,6 +12,7 @@ import { var get = Ember.get; var set = Ember.set; var setProperties = Ember.setProperties; +var map = Ember.EnumerableUtils.map; function asyncHasMany(type, options, meta) { return Ember.computed('data', function(key) { @@ -28,7 +29,19 @@ function asyncHasMany(type, options, meta) { if (link) { rel = store.findHasMany(this, link, relationshipFromMeta(store, meta), resolver); } else { - rel = store.findMany(this, data[key], typeForRelationshipMeta(store, meta), resolver); + //This is a temporary workaround for setting owner on the relationship + //until single source of truth lands. It only works for OneToMany atm + var records = data[key]; + var inverse = this.constructor.inverseFor(key); + var owner = this; + if (inverse && records) { + if (inverse.kind === 'belongsTo'){ + map(records, function(record){ + set(record, inverse.name, owner); + }); + } + } + rel = store.findMany(owner, data[key], typeForRelationshipMeta(store, meta), resolver); } // cache the promise so we can use it // when we come back and don't need to rebuild diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index fc7d9303068..0a0fb7403c4 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -141,6 +141,8 @@ Store = Ember.Object.extend({ }); this._relationshipChanges = {}; this._pendingSave = []; + //Used to keep track of all the find requests that need to be coalesced + this._pendingFetch = Ember.Map.create(); }, /** @@ -349,6 +351,30 @@ Store = Ember.Object.extend({ --- + You can optionally preload specific attributes and relationships that you know of + by passing them as the third argument to find. + + For example, if your Ember route looks like `/posts/1/comments/2` and you API route + for the comment also looks like `/posts/1/comments/2` if you want to fetch the comment + without fetching the post you can pass in the post to the `find` call: + + ```javascript + store.find('comment', 2, {post: 1}); + ``` + + If you have access to the post model you can also pass the model itself: + + ```javascript + var myPostModel = store.find('post', 1); + store.find('comment', 2, {post: myPostModel}); + ``` + + This way, your adapter's `find` or `buildURL` method will be able to look up the + relationship on the record and construct the nested URL without having to first + fetch the post. + + --- + To find all records for a type, call `find` with no additional parameters: ```javascript @@ -377,7 +403,7 @@ Store = Ember.Object.extend({ @param {Object|String|Integer|null} id @return {Promise} promise */ - find: function(type, id) { + find: function(type, id, preload) { Ember.assert("You need to pass a type to the store's find method", arguments.length >= 1); Ember.assert("You may not pass `" + id + "` as id to the store's find method", arguments.length === 1 || !Ember.isNone(id)); @@ -390,7 +416,7 @@ Store = Ember.Object.extend({ return this.findQuery(type, id); } - return this.findById(type, coerceId(id)); + return this.findById(type, coerceId(id), preload); }, /** @@ -402,10 +428,22 @@ Store = Ember.Object.extend({ @param {String|Integer} id @return {Promise} promise */ - findById: function(typeName, id) { + findById: function(typeName, id, preload) { + var fetchedRecord; + var type = this.modelFor(typeName); var record = this.recordForId(type, id); - var fetchedRecord = this.fetchRecord(record); + + if (preload) { + record._preloadData(preload); + } + + if (get(record, 'isEmpty')) { + fetchedRecord = this.scheduleFetch(record); + //TODO double check about reloading + } else if (get(record, 'isLoading')){ + fetchedRecord = record._loadingPromise; + } return promiseObject(fetchedRecord || record, "DS: Store#findById " + type + " with id: " + id); }, @@ -440,22 +478,125 @@ Store = Ember.Object.extend({ @return {Promise} promise */ fetchRecord: function(record) { - if (isNone(record)) { return null; } - if (record._loadingPromise) { return record._loadingPromise; } - if (!get(record, 'isEmpty')) { return null; } + var type = record.constructor, + id = get(record, 'id'); - var type = record.constructor; - var id = get(record, 'id'); var adapter = this.adapterFor(type); Ember.assert("You tried to find a record but you have no adapter (for " + type + ")", adapter); Ember.assert("You tried to find a record but your adapter (for " + type + ") does not implement 'find'", adapter.find); - var promise = _find(adapter, this, type, id); + var promise = _find(adapter, this, type, id, record); + return promise; + }, + + scheduleFetchMany: function(records) { + return Ember.RSVP.all(map(records, this.scheduleFetch, this)); + }, + + scheduleFetch: function(record) { + var type = record.constructor; + if (isNone(record)) { return null; } + if (record._loadingPromise) { return record._loadingPromise; } + + var resolver = Ember.RSVP.defer("Fetching " + type + "with id: " + record.get('id')); + var recordResolverPair = {record: record, resolver: resolver}; + var promise = resolver.promise; + record.loadingData(promise); + + if (!this._pendingFetch.get(type)){ + this._pendingFetch.set(type, [recordResolverPair]); + } else { + this._pendingFetch.get(type).push(recordResolverPair); + } + Ember.run.scheduleOnce('afterRender', this, this.flushAllPendingFetches); + return promise; }, + flushAllPendingFetches: function(){ + if (this.isDestroyed || this.isDestroying) { + return; + } + + this._pendingFetch.forEach(this._flushPendingFetchForType, this); + this._pendingFetch = Ember.Map.create(); + }, + + _flushPendingFetchForType: function (type, recordResolverPairs) { + var store = this; + var adapter = store.adapterFor(type); + var shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; + var records = Ember.A(recordResolverPairs).mapBy('record'); + var resolvers = Ember.A(recordResolverPairs).mapBy('resolver'); + + function _fetchRecord(recordResolverPair) { + var resolver = recordResolverPair.resolver; + store.fetchRecord(recordResolverPair.record).then(function(record){ + resolver.resolve(record); + }, function(error){ + resolver.reject(error); + }); + } + + function resolveFoundRecords(records) { + forEach(records, function(record){ + var pair = Ember.A(recordResolverPairs).findBy('record', record); + if (pair){ + var resolver = pair.resolver; + resolver.resolve(record); + } + }); + } + + function makeMissingRecordsRejector(requestedRecords) { + return function rejectMissingRecords(resolvedRecords) { + var missingRecords = requestedRecords.without(resolvedRecords); + rejectRecords(missingRecords); + }; + } + + function makeRecordsRejector(records) { + return function (error) { + rejectRecords(records, error); + }; + } + + function rejectRecords(records, error) { + forEach(records, function(record){ + var pair = Ember.A(recordResolverPairs).findBy('record', record); + if (pair){ + var resolver = pair.resolver; + resolver.reject(error); + } + }); + } + + if (recordResolverPairs.length === 1) { + _fetchRecord(recordResolverPairs[0]); + } else if (shouldCoalesce) { + var groups = adapter.groupRecordsForFindMany(this, records); + forEach(groups, function (groupOfRecords) { + var requestedRecords = Ember.A(groupOfRecords); + var ids = requestedRecords.mapBy('id'); + if (ids.length > 1) { + _findMany(adapter, store, type, ids, requestedRecords). + then(resolveFoundRecords). + then(makeMissingRecordsRejector(requestedRecords)). + then(null, makeRecordsRejector(requestedRecords)); + } else if (ids.length === 1) { + var pair = Ember.A(recordResolverPairs).findBy('record', groupOfRecords[0]); + _fetchRecord(pair); + } else { + Ember.assert("You cannot return an empty array from adapter's method groupRecordsForFindMany", false); + } + }); + } else { + forEach(recordResolverPairs, _fetchRecord); + } + }, + /** Get a record by a given type and ID without triggering a fetch. @@ -505,54 +646,7 @@ Store = Ember.Object.extend({ Ember.assert("You tried to reload a record but you have no adapter (for " + type + ")", adapter); Ember.assert("You tried to reload a record but your adapter does not implement `find`", adapter.find); - return _find(adapter, this, type, id); - }, - - /** - This method takes a list of records, groups the records by type, - converts the records into IDs, and then invokes the adapter's `findMany` - method. - - The records are grouped by type to invoke `findMany` on adapters - for each unique type in records. - - It is used both by a brand new relationship (via the `findMany` - method) or when the data underlying an existing relationship - changes. - - @method fetchMany - @private - @param {Array} records - @param {DS.Model} owner - @return {Promise} promise - */ - fetchMany: function(records, owner) { - if (!records.length) { - return Ember.RSVP.resolve(records); - } - - // Group By Type - var recordsByTypeMap = Ember.MapWithDefault.create({ - defaultValue: function() { return Ember.A(); } - }); - - forEach(records, function(record) { - recordsByTypeMap.get(record.constructor).push(record); - }); - - var promises = []; - - forEach(recordsByTypeMap, function(type, records) { - var ids = records.mapBy('id'), - adapter = this.adapterFor(type); - - Ember.assert("You tried to load many records but you have no adapter (for " + type + ")", adapter); - Ember.assert("You tried to load many records but your adapter does not implement `findMany`", adapter.findMany); - - promises.push(_findMany(adapter, this, type, ids, owner)); - }, this); - - return Ember.RSVP.all(promises); + return this.scheduleFetch(record); }, /** @@ -604,13 +698,9 @@ Store = Ember.Object.extend({ findMany: function(owner, inputRecords, typeName, resolver) { var type = this.modelFor(typeName); var records = Ember.A(inputRecords); - var unloadedRecords = records.filterBy('isEmpty', true); - var manyArray = this.recordArrayManager.createManyArray(type, records); - - forEach(unloadedRecords, function(record) { - record.loadingData(); - }); + var unloadedRecords = records.filterProperty('isEmpty', true); + var manyArray = this.recordArrayManager.createManyArray(type, records); manyArray.loadingRecordsCount = unloadedRecords.length; if (unloadedRecords.length) { @@ -618,7 +708,7 @@ Store = Ember.Object.extend({ this.recordArrayManager.registerWaitingRecordArray(record, manyArray); }, this); - resolver.resolve(this.fetchMany(unloadedRecords, owner)); + resolver.resolve(this.scheduleFetchMany(unloadedRecords, owner)); } else { if (resolver) { resolver.resolve(); } manyArray.set('isLoaded', true); @@ -1776,10 +1866,10 @@ function _bind(fn) { }; } -function _find(adapter, store, type, id) { - var promise = adapter.find(store, type, id); - var serializer = serializerForAdapter(adapter, type); - var label = "DS: Handle Adapter#find of " + type + " with id: " + id; +function _find(adapter, store, type, id, record) { + var promise = adapter.find(store, type, id, record), + serializer = serializerForAdapter(adapter, type), + label = "DS: Handle Adapter#find of " + type + " with id: " + id; promise = Promise.cast(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); @@ -1798,12 +1888,12 @@ function _find(adapter, store, type, id) { }, "DS: Extract payload of '" + type + "'"); } -function _findMany(adapter, store, type, ids, owner) { - var promise = adapter.findMany(store, type, ids, owner); - var serializer = serializerForAdapter(adapter, type); - var label = "DS: Handle Adapter#findMany of " + type; - var guardedPromise; +function _findMany(adapter, store, type, ids, records) { + var promise = adapter.findMany(store, type, ids, records), + serializer = serializerForAdapter(adapter, type), + label = "DS: Handle Adapter#findMany of " + type; + var guardedPromise; promise = Promise.cast(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); @@ -1812,7 +1902,7 @@ function _findMany(adapter, store, type, ids, owner) { Ember.assert("The response from a findMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); - store.pushMany(type, payload); + return store.pushMany(type, payload); }, null, "DS: Extract payload of " + type); } @@ -1929,4 +2019,5 @@ export { PromiseArray, PromiseObject }; + export default Store; diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index d8d988bff9e..2277db9f760 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -844,6 +844,7 @@ test("findQuery - data is normalized through custom serializers", function() { test("findMany - findMany uses a correct URL to access the records", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; store.push('post', { id: 1, name: "Rails is omakase", comments: [ 1, 2, 3 ] }); @@ -861,9 +862,29 @@ test("findMany - findMany uses a correct URL to access the records", function() })); }); +test("findMany - findMany does not coalesce by default", function() { + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + + store.push('post', { id: 1, name: "Rails is omakase", comments: [ 1, 2, 3 ] }); + + var post = store.getById('post', 1); + //It's still ok to return this even without coalescing because RESTSerializer supports sideloading + ajaxResponse({ + comments: [ + { id: 1, name: "FIRST" }, + { id: 2, name: "Rails is unagi" }, + { id: 3, name: "What is omakase?" } + ] + }); + post.get('comments').then(async(function(comments) { + equal(passedUrl, "/comments/3"); + equal(passedHash, null); + })); +}); test("findMany - returning an array populates the array", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; store.push('post', { id: 1, name: "Rails is omakase", comments: [ 1, 2, 3 ] }); @@ -896,6 +917,7 @@ return post.get('comments'); test("findMany - returning sideloaded data loads the data", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; store.push('post', { id: 1, name: "Rails is omakase", comments: [ 1, 2, 3 ] }); @@ -940,6 +962,7 @@ test("findMany - a custom serializer is used if present", function() { attrs: { name: '_NAME_' } })); + adapter.coalesceFindRequests = true; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); store.push('post', { id: 1, name: "Rails is omakase", comments: [ 1, 2, 3 ] }); @@ -1007,6 +1030,7 @@ test("findHasMany - returning an array populates the array", function() { test("findMany - returning sideloaded data loads the data", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; store.push( 'post', @@ -1172,6 +1196,144 @@ test('buildURL - with camelized names', function() { })); }); +test('buildURL - buildURL takes a record from find', function() { + Comment.reopen({ post: DS.belongsTo('post') }); + adapter.buildURL = function(type, id, record) { + return "/posts/" + record.get('post.id') + '/comments/' + record.get('id'); + }; + + ajaxResponse({ comments: [{ id: 1 }] }); + + var post = store.push('post', { id: 2 }); + store.find('comment', 1, {post: post}).then(async(function(post) { + equal(passedUrl, "/posts/2/comments/1"); + })); +}); + +test('buildURL - buildURL takes the records from findMany', function() { + Comment.reopen({ post: DS.belongsTo('post') }); + Post.reopen({ comments: DS.hasMany('comment', {async: true}) }); + + adapter.buildURL = function(type, ids, records) { + return "/posts/" + records.get('firstObject.post.id') + '/comments/'; + }; + adapter.coalesceFindRequests = true; + + ajaxResponse({ comments: [{ id: 1 }, {id:2}, {id:3}] }); + + var post = store.push('post', { id: 2, comments: [1,2,3] }); + + post.get('comments').then(async(function(post) { + equal(passedUrl, "/posts/2/comments/"); + })); +}); + +test('buildURL - buildURL takes a record from create', function() { + Comment.reopen({ post: DS.belongsTo('post') }); + adapter.buildURL = function(type, id, record) { + return "/posts/" + record.get('post.id') + '/comments/'; + }; + + ajaxResponse({ comments: [{ id: 1 }] }); + + var post = store.push('post', { id: 2 }); + var comment = store.createRecord('comment'); + comment.set('post', post); + comment.save().then(async(function(post) { + equal(passedUrl, "/posts/2/comments/"); + })); +}); + +test('buildURL - buildURL takes a record from update', function() { + Comment.reopen({ post: DS.belongsTo('post') }); + adapter.buildURL = function(type, id, record) { + return "/posts/" + record.get('post.id') + '/comments/' + record.get('id'); + }; + + ajaxResponse({ comments: [{ id: 1 }] }); + + var post = store.push('post', { id: 2 }); + var comment = store.push('comment', { id: 1 }); + comment.set('post', post); + comment.save().then(async(function(post) { + equal(passedUrl, "/posts/2/comments/1"); + })); +}); + +test('buildURL - buildURL takes a record from delete', function() { + Comment.reopen({ post: DS.belongsTo('post') }); + adapter.buildURL = function(type, id, record) { + return '/comments/' + record.get('id'); + }; + + ajaxResponse({ comments: [{ id: 1 }] }); + + var post = store.push('post', { id: 2 }); + var comment = store.push('comment', { id: 1 }); + + comment.set('post', post); + comment.deleteRecord(); + comment.save().then(async(function(post) { + equal(passedUrl, "/comments/1"); + })); +}); + +test('groupRecordsForFindMany groups records based on their url', function() { + Comment.reopen({ post: DS.belongsTo('post') }); + Post.reopen({ comments: DS.hasMany('comment', {async: true}) }); + adapter.coalesceFindRequests = true; + + adapter.buildURL = function(type, id, record) { + if (id === '1'){ + return '/comments/1'; + } else { + return '/other_comments/' + id; + } + }; + + adapter.find = function(store, type, id, record ) { + equal(id, '1'); + return Ember.RSVP.resolve({comments: {id:1}}); + }; + + adapter.findMany = function(store, type, ids, records ) { + deepEqual(ids, ['2', '3']); + return Ember.RSVP.resolve({comments: [{id:2}, {id:3}]}); + }; + + var post = store.push('post', { id: 2, comments: [1,2,3] }); + + post.get('comments'); +}); + +test('groupRecordsForFindMany groups records correctly when singular URLs are encoded as query params', function() { + Comment.reopen({ post: DS.belongsTo('post') }); + Post.reopen({ comments: DS.hasMany('comment', {async: true}) }); + adapter.coalesceFindRequests = true; + + adapter.buildURL = function(type, id, record) { + if (id === '1'){ + return '/comments?id=1'; + } else { + return '/other_comments?id=' + id; + } + }; + + adapter.find = function(store, type, id, record ) { + equal(id, '1'); + return Ember.RSVP.resolve({comments: {id:1}}); + }; + + adapter.findMany = function(store, type, ids, records ) { + deepEqual(ids, ['2', '3']); + return Ember.RSVP.resolve({comments: [{id:2}, {id:3}]}); + }; + + var post = store.push('post', { id: 2, comments: [1,2,3] }); + + post.get('comments'); +}); + test('normalizeKey - to set up _ids and _id', function() { env.container.register('serializer:application', DS.RESTSerializer.extend({ keyForAttribute: function(attr) { diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 566e80b0239..1a4c4399bb0 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -163,16 +163,16 @@ test("When a polymorphic hasMany relationship is accessed, the adapter's findMan })); }); -test("When a polymorphic hasMany relationship is accessed, the store can call multiple adapters' findMany method if the records are not loaded", function() { +test("When a polymorphic hasMany relationship is accessed, the store can call multiple adapters' findMany or find methods if the records are not loaded", function() { User.reopen({ messages: hasMany('message', { polymorphic: true, async: true }) }); - env.adapter.findMany = function(store, type) { + env.adapter.find = function(store, type) { if (type === Post) { - return Ember.RSVP.resolve([{ id: 1 }]); + return Ember.RSVP.resolve({ id: 1 }); } else if (type === Comment) { - return Ember.RSVP.resolve([{ id: 3 }]); + return Ember.RSVP.resolve({ id: 3 }); } }; diff --git a/packages/ember-data/tests/unit/model/relationships_test.js b/packages/ember-data/tests/unit/model/relationships_test.js index 36d407bf8ea..4d7a3e1b4fa 100644 --- a/packages/ember-data/tests/unit/model/relationships_test.js +++ b/packages/ember-data/tests/unit/model/relationships_test.js @@ -279,6 +279,7 @@ test("hasMany relationships work when the data hash has not been loaded", functi var env = setupStore({ tag: Tag, person: Person }), store = env.store; + env.adapter.coalesceFindRequests = true; env.adapter.findMany = function(store, type, ids) { equal(type, Tag, "type should be Tag"); deepEqual(ids, ['5', '2'], "ids should be 5 and 2"); @@ -562,7 +563,7 @@ test("calling createRecord and passing in an undefined value for a relationship })); }); -test("findMany is passed the owner record for adapters when some of the object graph is already loaded", function() { +test("When finding a hasMany relationship the inverse belongsTo relationship is available immediately", function() { var Occupation = DS.Model.extend({ description: DS.attr('string'), person: DS.belongsTo('person') @@ -580,14 +581,13 @@ test("findMany is passed the owner record for adapters when some of the object g var env = setupStore({ occupation: Occupation, person: Person }), store = env.store; - env.adapter.findMany = function(store, type, ids, owner) { - equal(type, Occupation, "type should be Occupation"); - deepEqual(ids, ['5', '2'], "ids should be 5 and 2"); - equal(get(owner, 'id'), 1, "the owner record id should be 1"); - + env.adapter.findMany = function(store, type, ids, records) { + equal(records[0].get('person.id'), '1'); return Ember.RSVP.resolve([{ id: 5, description: "fifth" }, { id: 2, description: "second" }]); }; + env.adapter.coalesceFindRequests = true; + store.push('person', { id: 1, name: "Tom Dale", occupations: [5, 2] }); store.find('person', 1).then(async(function(person) { @@ -603,7 +603,8 @@ test("findMany is passed the owner record for adapters when some of the object g })); }); -test("findMany is passed the owner record for adapters when none of the object graph is loaded", function() { +test("When finding a belongsTo relationship the inverse belongsTo relationship is available immediately", function() { + expect(1); var Occupation = DS.Model.extend({ description: DS.attr('string'), person: DS.belongsTo('person') @@ -613,7 +614,7 @@ test("findMany is passed the owner record for adapters when none of the object g var Person = DS.Model.extend({ name: DS.attr('string'), - occupations: DS.hasMany('occupation', { async: true }) + occupation: DS.belongsTo('occupation', { async: true }) }); Person.toString = function() { return "Person"; }; @@ -621,30 +622,14 @@ test("findMany is passed the owner record for adapters when none of the object g var env = setupStore({ occupation: Occupation, person: Person }), store = env.store; - env.adapter.findMany = function(store, type, ids, owner) { - equal(type, Occupation, "type should be Occupation"); - deepEqual(ids, ['5', '2'], "ids should be 5 and 2"); - equal(get(owner, 'id'), 1, "the owner record id should be 1"); - - return Ember.RSVP.resolve([{ id: 5, description: "fifth" }, { id: 2, description: "second" }]); - }; - - env.adapter.find = function(store, type, id) { - equal(type, Person, "type should be Person"); - equal(id, 1, "id should be 1"); - - return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", occupations: [5, 2] }); + env.adapter.find = function(store, type, id, record) { + equal(record.get('person.id'), '1'); + return Ember.RSVP.resolve({ id: 5, description: "fifth" }); }; - store.find('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "The person is now populated"); + store.push('person', { id: 1, name: "Tom Dale", occupation: 5 }); - return get(person, 'occupations'); - })).then(async(function(occupations) { - equal(get(occupations, 'length'), 2, "the occupation objects still exist"); - equal(get(occupations.objectAt(0), 'description'), "fifth", "the occupation is the fifth"); - equal(get(occupations.objectAt(0), 'isLoaded'), true, "the occupation is now loaded"); - })); + store.getById('person', 1).get('occupation'); }); test("belongsTo supports relationships to models with id 0", function() { diff --git a/packages/ember-data/tests/unit/store/adapter_interop_test.js b/packages/ember-data/tests/unit/store/adapter_interop_test.js index e81edcb082a..bbc233c87b2 100644 --- a/packages/ember-data/tests/unit/store/adapter_interop_test.js +++ b/packages/ember-data/tests/unit/store/adapter_interop_test.js @@ -34,14 +34,15 @@ test('Adapter can not be set as an instance', function() { }); test("Calling Store#find invokes its adapter#find", function() { - expect(4); + expect(5); var adapter = TestAdapter.extend({ - find: function(store, type, id) { + find: function(store, type, id, record) { ok(true, "Adapter#find was called"); equal(store, currentStore, "Adapter#find was called with the right store"); equal(type, currentType, "Adapter#find was called with the type passed into Store#find"); equal(id, 1, "Adapter#find was called with the id passed into Store#find"); + equal(record.get('id'), '1', "Adapter#find was called with the record created from Store#find"); return Ember.RSVP.resolve({ id: 1 }); } @@ -53,6 +54,32 @@ test("Calling Store#find invokes its adapter#find", function() { currentStore.find(currentType, 1); }); +test("Calling Store#findById multiple times coalesces the calls into a adapter#findMany call", function() { + expect(2); + + var adapter = TestAdapter.extend({ + find: function(store, type, id) { + ok(false, "Adapter#find was not called"); + }, + findMany: function(store, type, ids) { + start(); + ok(true, "Adapter#findMany was called"); + deepEqual(ids, ["1","2"], 'Correct ids were passed in to findMany'); + return Ember.RSVP.resolve([{ id: 1 }, { id:2}] ); + }, + coalesceFindRequests: true + }); + + var currentStore = createStore({ adapter: adapter }); + var currentType = DS.Model.extend(); + currentType.typeKey = "test"; + stop(); + Ember.run(function(){ + currentStore.find(currentType, 1); + currentStore.find(currentType, 2); + }); +}); + test("Returning a promise from `find` asynchronously loads data", function() { var adapter = TestAdapter.extend({ find: function(store, type, id) { @@ -274,6 +301,122 @@ test("if an id is supplied in the initial data hash, it can be looked up using ` })); }); +test("initial values of attributes can be passed in as the third argument to find", function() { + var adapter = TestAdapter.extend({ + find: function(store, type, query) { + return new Ember.RSVP.Promise(function(){}); + } + }); + + var store = createStore({ + adapter: adapter + }); + + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + + store.find(Person, 1, {name: 'Test'}); + equal(store.getById(Person, 1).get('name'), 'Test', 'Preloaded attribtue set'); +}); + +test("initial values of belongsTo can be passed in as the third argument to find as records", function() { + var adapter = TestAdapter.extend({ + find: function(store, type, query) { + return new Ember.RSVP.Promise(function(){}); + } + }); + + var store = createStore({ + adapter: adapter + }); + + var Person = DS.Model.extend({ + name: DS.attr('string'), + friend: DS.belongsTo('person') + }); + + store.container.register('model:person', Person); + + var tom = store.push(Person, {id:2, name:'Tom'}); + + store.find(Person, 1, {friend: tom}); + + equal(store.getById(Person, 1).get('friend.name'), 'Tom', 'Preloaded belongsTo set'); +}); + +test("initial values of belongsTo can be passed in as the third argument to find as ids", function() { + var adapter = TestAdapter.extend({ + find: function(store, type, query) { + return new Ember.RSVP.Promise(function(){}); + } + }); + + var store = createStore({ + adapter: adapter + }); + + var Person = DS.Model.extend({ + name: DS.attr('string'), + friend: DS.belongsTo('person') + }); + + store.container.register('model:person', Person); + + store.find(Person, 1, {friend: 2}); + + equal(store.getById(Person, 1).get('friend.id'), '2', 'Preloaded belongsTo set'); +}); + +test("initial values of hasMany can be passed in as the third argument to find as records", function() { + var adapter = TestAdapter.extend({ + find: function(store, type, query) { + return new Ember.RSVP.Promise(function(){}); + } + }); + + var store = createStore({ + adapter: adapter + }); + + var Person = DS.Model.extend({ + name: DS.attr('string'), + friends: DS.hasMany('person') + }); + + store.container.register('model:person', Person); + + var tom = store.push(Person, {id:2, name:'Tom'}); + + store.find(Person, 1, {friends: [tom]}); + + equal(store.getById(Person, 1).get('friends').toArray()[0].get('name'), 'Tom', 'Preloaded hasMany set'); +}); + +test("initial values of hasMany can be passed in as the third argument to find as ids", function() { + var adapter = TestAdapter.extend({ + find: function(store, type, query) { + return new Ember.RSVP.Promise(function(){}); + } + }); + + var store = createStore({ + adapter: adapter + }); + + var Person = DS.Model.extend({ + name: DS.attr('string'), + friends: DS.hasMany('person') + }); + + store.container.register('model:person', Person); + + store.find(Person, 1, {friends: [2]}); + + equal(store.getById(Person, 1).get('friends').toArray()[0].get('id'), '2', 'Preloaded hasMany set'); +}); + test("records inside a collection view should have their ids updated", function() { var Person = DS.Model.extend(); @@ -314,22 +457,34 @@ test("store.fetchMany should always return a promise", function() { var owner = store.createRecord(Person); var records = Ember.A([]); - var results = store.fetchMany(records, owner); - ok(results, "A call to store.fetchMany() should return a result"); - ok(results.then, "A call to store.fetchMany() should return a promise"); + var results = store.scheduleFetchMany(records); + ok(results, "A call to store.scheduleFetchMany() should return a result"); + ok(results.then, "A call to store.scheduleFetchMany() should return a promise"); results.then(async(function(returnedRecords) { - equal(returnedRecords, records, "The empty record sets should match"); + deepEqual(returnedRecords, [], "The correct records are returned"); })); }); -test("store.fetchMany should not resolve until all the records are resolve", function() { +test("store.scheduleFetchMany should not resolve until all the records are resolve", function() { var Person = DS.Model.extend(); var Phone = DS.Model.extend(); var adapter = TestAdapter.extend({ + find: function (store, type, id) { + var wait = 5; + + var record = { id: id }; + + return new Ember.RSVP.Promise(function(resolve, reject) { + Ember.run.later(function() { + resolve(record); + }, wait); + }); + }, + findMany: function(store, type, ids) { - var wait = (type === Person)? 5 : 15; + var wait = 15; var records = ids.map(function(id) { return {id: id}; @@ -355,8 +510,186 @@ test("store.fetchMany should not resolve until all the records are resolve", fun store.recordForId(Phone, 21) ]); - store.fetchMany(records, owner).then(async(function() { + store.scheduleFetchMany(records).then(async(function() { var unloadedRecords = records.filterBy('isEmpty'); equal(get(unloadedRecords, 'length'), 0, 'All unloaded records should be loaded'); })); }); + +test("the store calls adapter.findMany according to groupings returned by adapter.groupRecordsForFindMany", function() { + expect(3); + + var callCount = 0; + var Person = DS.Model.extend(); + + var adapter = TestAdapter.extend({ + groupRecordsForFindMany: function (store, records) { + return [ + [records[0]], + [records[1], records[2]] + ]; + }, + + find: function(store, type, id) { + equal(id, "10", "The first group is passed to find"); + return Ember.RSVP.resolve({id:id}); + }, + + findMany: function(store, type, ids) { + var records = ids.map(function(id) { + return {id: id}; + }); + + deepEqual(ids, ["20", "21"], "The second group is passed to findMany"); + + return new Ember.RSVP.Promise(function(resolve, reject) { + resolve(records); + }); + } + }); + + var store = createStore({ + adapter: adapter + }); + + var records = Ember.A([ + store.recordForId(Person, 10), + store.recordForId(Person, 20), + store.recordForId(Person, 21) + ]); + + store.scheduleFetchMany(records).then(async(function() { + var ids = records.mapBy('id'); + deepEqual(ids, ["10", "20", "21"], "The promise fulfills with the records"); + })); +}); + +test("the promise returned by `scheduleFetch`, when it resolves, does not depend on the promises returned to other calls to `scheduleFetch` that are in the same run loop, but different groups", function() { + expect(2); + var Person = DS.Model.extend(); + var davidResolved = false; + + var adapter = TestAdapter.extend({ + groupRecordsForFindMany: function (store, records) { + return [ + [records[0]], + [records[1]] + ]; + }, + + find: function(store, type, id) { + var record = {id: id}; + + return new Ember.RSVP.Promise(function(resolve, reject) { + if (id === 'igor') { + resolve(record); + } else { + Ember.run.later(function () { + davidResolved = true; + resolve(record); + }, 5); + } + }); + } + }); + + var store = createStore({ + adapter: adapter + }); + + Ember.run(function () { + var davidPromise = store.find(Person, 'david'); + var igorPromise = store.find(Person, 'igor'); + + igorPromise.then(async(function () { + equal(davidResolved, false, "Igor did not need to wait for David"); + })); + + davidPromise.then(async(function () { + equal(davidResolved, true, "David resolved"); + })); + }); +}); + +test("the promise returned by `scheduleFetch`, when it rejects, does not depend on the promises returned to other calls to `scheduleFetch` that are in the same run loop, but different groups", function() { + expect(2); + var Person = DS.Model.extend(); + var davidResolved = false; + + var adapter = TestAdapter.extend({ + groupRecordsForFindMany: function (store, records) { + return [ + [records[0]], + [records[1]] + ]; + }, + + find: function(store, type, id) { + var record = {id: id}; + + return new Ember.RSVP.Promise(function(resolve, reject) { + if (id === 'igor') { + reject(record); + } else { + Ember.run.later(function () { + davidResolved = true; + resolve(record); + }, 5); + } + }); + } + }); + + var store = createStore({ + adapter: adapter + }); + + Ember.run(function () { + var davidPromise = store.find(Person, 'david'); + var igorPromise = store.find(Person, 'igor'); + + igorPromise.then(null, async(function () { + equal(davidResolved, false, "Igor did not need to wait for David"); + })); + + davidPromise.then(async(function () { + equal(davidResolved, true, "David resolved"); + })); + }); +}); + +test("store.fetchRecord reject records that were not found, even when those requests were coalesced with records that were found", function() { + expect(2); + var Person = DS.Model.extend(); + + var adapter = TestAdapter.extend({ + findMany: function(store, type, ids) { + var records = ids.map(function(id) { + return {id: id}; + }); + + return new Ember.RSVP.Promise(function(resolve, reject) { + resolve([ + records[0] + ]); + }); + } + }); + + var store = createStore({ + adapter: adapter + }); + + Ember.run(function () { + var davidPromise = store.find(Person, 'david'); + var igorPromise = store.find(Person, 'igor'); + + davidPromise.then(async(function () { + ok(true, "David resolved"); + })); + + igorPromise.then(null, async(function () { + ok(true, "Igor rejected"); + })); + }); +}); diff --git a/packages/ember-data/tests/unit/store/unload_test.js b/packages/ember-data/tests/unit/store/unload_test.js index a03848ed8bb..fc274e4b5a2 100644 --- a/packages/ember-data/tests/unit/store/unload_test.js +++ b/packages/ember-data/tests/unit/store/unload_test.js @@ -55,8 +55,9 @@ test("unload a record", function() { equal(get(record, 'isDeleted'), true, "record is deleted"); tryToFind = false; - store.find(Record, 1); - equal(tryToFind, true, "not found record with id 1"); + store.find(Record, 1).then(async(function(){ + equal(tryToFind, true, "not found record with id 1"); + })); })); }); diff --git a/tests/ember_configuration.js b/tests/ember_configuration.js index 07d4647adf7..fe57ce2f218 100644 --- a/tests/ember_configuration.js +++ b/tests/ember_configuration.js @@ -158,7 +158,9 @@ didUpdateAttribute: syncForTest(), didUpdateAttributes: syncForTest(), didUpdateRelationship: syncForTest(), - didUpdateRelationships: syncForTest() + didUpdateRelationships: syncForTest(), + scheduleFetch: syncForTest(), + scheduleFetchMany: syncForTest() }); DS.Model.reopen({ From 43210eff7f7394f6a4ab36d67cb81073b23791ed Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 24 Jul 2014 11:02:43 -0400 Subject: [PATCH 0249/2527] update ember-inflector (now with a cache inflection) --- packages/ember-inflector/lib/ext/string.js | 5 +- packages/ember-inflector/lib/main.js | 12 ++- packages/ember-inflector/lib/system.js | 5 +- .../ember-inflector/lib/system/inflections.js | 4 +- .../ember-inflector/lib/system/inflector.js | 92 +++++++++++++++++-- packages/ember-inflector/lib/system/string.js | 14 ++- .../tests/system/inflector_test.js | 23 ++++- 7 files changed, 135 insertions(+), 20 deletions(-) diff --git a/packages/ember-inflector/lib/ext/string.js b/packages/ember-inflector/lib/ext/string.js index 735b6760863..12c46d115da 100644 --- a/packages/ember-inflector/lib/ext/string.js +++ b/packages/ember-inflector/lib/ext/string.js @@ -1,4 +1,7 @@ -import {pluralize, singularize} from "../system/string"; +import { + pluralize, + singularize +} from "../system/string"; if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { /** diff --git a/packages/ember-inflector/lib/main.js b/packages/ember-inflector/lib/main.js index f7c6900ec1f..6f8f86b4492 100644 --- a/packages/ember-inflector/lib/main.js +++ b/packages/ember-inflector/lib/main.js @@ -1,4 +1,9 @@ -import {Inflector, defaultRules, pluralize, singularize} from "./system"; +import { + Inflector, + defaultRules, + pluralize, + singularize +} from "./system"; Inflector.defaultRules = defaultRules; Ember.Inflector = Inflector; @@ -10,4 +15,7 @@ import "./ext/string"; export default Inflector; -export {pluralize, singularize}; +export { + pluralize, + singularize +}; diff --git a/packages/ember-inflector/lib/system.js b/packages/ember-inflector/lib/system.js index e9cd300dd4c..a169677cf17 100644 --- a/packages/ember-inflector/lib/system.js +++ b/packages/ember-inflector/lib/system.js @@ -1,5 +1,8 @@ import Inflector from "./system/inflector"; -import {pluralize, singularize} from "./system/string"; +import { + pluralize, + singularize +} from "./system/string"; import defaultRules from "./system/inflections"; Inflector.inflector = new Inflector(defaultRules); diff --git a/packages/ember-inflector/lib/system/inflections.js b/packages/ember-inflector/lib/system/inflections.js index 04096a7fcdc..d6d545c6f6d 100644 --- a/packages/ember-inflector/lib/system/inflections.js +++ b/packages/ember-inflector/lib/system/inflections.js @@ -1,4 +1,4 @@ -var defaultRules = { +export default { plurals: [ [/$/, 's'], [/s$/i, 's'], @@ -76,5 +76,3 @@ var defaultRules = { 'police' ] }; - -export default defaultRules; diff --git a/packages/ember-inflector/lib/system/inflector.js b/packages/ember-inflector/lib/system/inflector.js index 5d3ddf798d3..678646a96ac 100644 --- a/packages/ember-inflector/lib/system/inflector.js +++ b/packages/ember-inflector/lib/system/inflector.js @@ -12,8 +12,13 @@ function loadIrregular(rules, irregularPairs) { for (var i = 0, length = irregularPairs.length; i < length; i++) { pair = irregularPairs[i]; + //pluralizing rules.irregular[pair[0].toLowerCase()] = pair[1]; + rules.irregular[pair[1].toLowerCase()] = pair[1]; + + //singularizing rules.irregularInverse[pair[1].toLowerCase()] = pair[0]; + rules.irregularInverse[pair[0].toLowerCase()] = pair[0]; } } @@ -77,28 +82,93 @@ function loadIrregular(rules, irregularPairs) { */ function Inflector(ruleSet) { ruleSet = ruleSet || {}; - ruleSet.uncountable = ruleSet.uncountable || {}; - ruleSet.irregularPairs = ruleSet.irregularPairs || {}; + ruleSet.uncountable = ruleSet.uncountable || makeDictionary(); + ruleSet.irregularPairs = ruleSet.irregularPairs || makeDictionary(); var rules = this.rules = { plurals: ruleSet.plurals || [], singular: ruleSet.singular || [], - irregular: {}, - irregularInverse: {}, - uncountable: {} + irregular: makeDictionary(), + irregularInverse: makeDictionary(), + uncountable: makeDictionary() }; loadUncountable(rules, ruleSet.uncountable); loadIrregular(rules, ruleSet.irregularPairs); + + this.enableCache(); +} + +if (!Object.create && !Object.create(null).hasOwnProperty) { + throw new Error("This browser does not support Object.create(null), please polyfil with es5-sham: http://git.io/yBU2rg"); +} + +function makeDictionary() { + var cache = Object.create(null); + cache['_dict'] = null; + delete cache['_dict']; + return cache; } Inflector.prototype = { + /** + @public + + As inflections can be costly, and commonly the same subset of words are repeatedly + inflected an optional cache is provided. + + @method enableCache + */ + enableCache: function() { + this.purgeCache(); + + this.singularize = function(word) { + this._cacheUsed = true; + return this._sCache[word] || (this._sCache[word] = this._singularize(word)); + }; + + this.pluralize = function(word) { + this._cacheUsed = true; + return this._pCache[word] || (this._pCache[word] = this._pluralize(word)); + }; + }, + + /** + @public + + @method purgedCache + */ + purgeCache: function() { + this._cacheUsed = false; + this._sCache = makeDictionary(); + this._pCache = makeDictionary(); + }, + + /** + @public + disable caching + + @method disableCache; + */ + disableCache: function() { + this._sCache = null; + this._pCache = null; + this.singularize = function(word) { + return this._singularize(word); + }; + + this.pluralize = function(word) { + return this._pluralize(word); + }; + }, + /** @method plural @param {RegExp} regex @param {String} string */ plural: function(regex, string) { + if (this._cacheUsed) { this.purgeCache(); } this.rules.plurals.push([regex, string.toLowerCase()]); }, @@ -108,6 +178,7 @@ Inflector.prototype = { @param {String} string */ singular: function(regex, string) { + if (this._cacheUsed) { this.purgeCache(); } this.rules.singular.push([regex, string.toLowerCase()]); }, @@ -116,6 +187,7 @@ Inflector.prototype = { @param {String} regex */ uncountable: function(string) { + if (this._cacheUsed) { this.purgeCache(); } loadUncountable(this.rules, [string.toLowerCase()]); }, @@ -125,6 +197,7 @@ Inflector.prototype = { @param {String} plural */ irregular: function (singular, plural) { + if (this._cacheUsed) { this.purgeCache(); } loadIrregular(this.rules, [[singular, plural]]); }, @@ -133,14 +206,21 @@ Inflector.prototype = { @param {String} word */ pluralize: function(word) { - return this.inflect(word, this.rules.plurals, this.rules.irregular); + return this._pluralize(word); }, + _pluralize: function(word) { + return this.inflect(word, this.rules.plurals, this.rules.irregular); + }, /** @method singularize @param {String} word */ singularize: function(word) { + return this._singularize(word); + }, + + _singularize: function(word) { return this.inflect(word, this.rules.singular, this.rules.irregularInverse); }, diff --git a/packages/ember-inflector/lib/system/string.js b/packages/ember-inflector/lib/system/string.js index 0d4324ebbff..8fa3ef39d99 100644 --- a/packages/ember-inflector/lib/system/string.js +++ b/packages/ember-inflector/lib/system/string.js @@ -1,10 +1,14 @@ import Inflector from "./inflector"; -var pluralize = function(word) { + +function pluralize(word) { return Inflector.inflector.pluralize(word); -}; +} -var singularize = function(word) { +function singularize(word) { return Inflector.inflector.singularize(word); -}; +} -export {pluralize, singularize}; +export { + pluralize, + singularize +}; diff --git a/packages/ember-inflector/tests/system/inflector_test.js b/packages/ember-inflector/tests/system/inflector_test.js index e3e4f092dac..2edffa1a928 100644 --- a/packages/ember-inflector/tests/system/inflector_test.js +++ b/packages/ember-inflector/tests/system/inflector_test.js @@ -91,16 +91,35 @@ test('singularization',function(){ equal(inflector.singularize('apple'), 'apple'); }); -test('singularization of irregulars', function(){ +test('singularization of irregular singulars', function(){ expect(1); var inflector = new Ember.Inflector({ + singular: [ + [/s$/i, ''], + [/(ss)$/i, '$1'] + ], + irregularPairs: [ + ['lens', 'lenses'] + ] + }); + + equal(inflector.singularize('lens'), 'lens'); +}); + +test('pluralization of irregular plurals', function(){ + expect(1); + + var inflector = new Ember.Inflector({ + plurals: [ + [/$/,'s'] + ], irregularPairs: [ ['person', 'people'] ] }); - equal(inflector.singularize('person'), 'person'); + equal(inflector.pluralize('people'), 'people'); }); test('plural',function(){ From 15b724611683509f225df75754669310a52bfa4f Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 24 Jul 2014 11:17:01 -0400 Subject: [PATCH 0250/2527] =?UTF-8?q?don=E2=80=99t=20include=20inflector?= =?UTF-8?q?=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tests/system/inflector_test.js | 283 ------------------ .../tests/system/integration_test.js | 17 -- 2 files changed, 300 deletions(-) delete mode 100644 packages/ember-inflector/tests/system/inflector_test.js delete mode 100644 packages/ember-inflector/tests/system/integration_test.js diff --git a/packages/ember-inflector/tests/system/inflector_test.js b/packages/ember-inflector/tests/system/inflector_test.js deleted file mode 100644 index 2edffa1a928..00000000000 --- a/packages/ember-inflector/tests/system/inflector_test.js +++ /dev/null @@ -1,283 +0,0 @@ -var inflector; -module('ember-inflector.dsl', { - setup: function() { - inflector = new Ember.Inflector(/* no rulest == no rules */); - }, - teardown: function() { - inflector = undefined; - } -}); - -test('ability to add additional pluralization rules', function(){ - equal(inflector.pluralize('cow'), 'cow', 'no pluralization rule'); - - inflector.plural(/$/, 's'); - - equal(inflector.pluralize('cow'), 'cows', 'pluralization rule was applied'); -}); - -test('ability to add additional singularization rules', function(){ - equal(inflector.singularize('cows'), 'cows', 'no singularization rule was applied'); - - inflector.singular(/s$/, ''); - - equal(inflector.singularize('cows'), 'cow', 'singularization rule was applied'); -}); - -test('ability to add additional uncountable rules', function(){ - inflector.plural(/$/, 's'); - equal(inflector.pluralize('cow'), 'cows', 'pluralization rule was applied'); - - inflector.uncountable('cow'); - equal(inflector.pluralize('cow'), 'cow', 'pluralization rule NOT was applied'); -}); - -test('ability to add additional irregular rules', function(){ - inflector.singular(/s$/, ''); - inflector.plural(/$/, 's'); - - equal(inflector.singularize('cows'), 'cow', 'regular singularization rule was applied'); - equal(inflector.pluralize('cow'), 'cows', 'regular pluralization rule was applied'); - - inflector.irregular('cow', 'kine'); - - equal(inflector.singularize('kine'), 'cow', 'irregular singularization rule was applied'); - equal(inflector.pluralize('cow'), 'kine', 'irregular pluralization rule was applied'); -}); - -test('ability to add identical singular and pluralizations',function(){ - - inflector.singular(/s$/, ''); - inflector.plural(/$/, 's'); - - equal(inflector.singularize('settings'),'setting','regular singularization rule was applied'); - equal(inflector.pluralize('setting'),'settings','regular pluralization rule was applied'); - - inflector.irregular('settings','settings'); - inflector.irregular('userPreferences','userPreferences'); - - equal(inflector.singularize('settings'),'settings','irregular singularization rule was applied on lowercase word'); - equal(inflector.pluralize('settings'),'settings','irregular pluralization rule was applied on lowercase word'); - - equal(inflector.singularize('userPreferences'),'userPreferences','irregular singularization rule was applied on camelcase word'); - equal(inflector.pluralize('userPreferences'),'userPreferences','irregular pluralization rule was applied on camelcase word'); -}); - -module('ember-inflector.unit'); - -test('plurals', function() { - expect(1); - - var inflector = new Ember.Inflector({ - plurals: [ - [/$/, 's'], - [/s$/i, 's'] - ] - }); - - equal(inflector.pluralize('apple'), 'apples'); -}); - -test('singularization',function(){ - expect(1); - - var inflector = new Ember.Inflector({ - singular: [ - [/s$/i, ''], - [/(ss)$/i, '$1'] - ] - }); - - equal(inflector.singularize('apple'), 'apple'); -}); - -test('singularization of irregular singulars', function(){ - expect(1); - - var inflector = new Ember.Inflector({ - singular: [ - [/s$/i, ''], - [/(ss)$/i, '$1'] - ], - irregularPairs: [ - ['lens', 'lenses'] - ] - }); - - equal(inflector.singularize('lens'), 'lens'); -}); - -test('pluralization of irregular plurals', function(){ - expect(1); - - var inflector = new Ember.Inflector({ - plurals: [ - [/$/,'s'] - ], - irregularPairs: [ - ['person', 'people'] - ] - }); - - equal(inflector.pluralize('people'), 'people'); -}); - -test('plural',function(){ - expect(1); - - var inflector = new Ember.Inflector({ - plurals: [ - ['1', '1'], - ['2', '2'], - ['3', '3'] - ] - }); - - equal(inflector.rules.plurals.length, 3); -}); - -test('singular',function(){ - expect(1); - - var inflector = new Ember.Inflector({ - singular: [ - ['1', '1'], - ['2', '2'], - ['3', '3'] - ] - }); - - equal(inflector.rules.singular.length, 3); -}); - -test('irregular',function(){ - expect(6); - - var inflector = new Ember.Inflector({ - irregularPairs: [ - ['1', '12'], - ['2', '22'], - ['3', '32'] - ] - }); - - equal(inflector.rules.irregular['1'], '12'); - equal(inflector.rules.irregular['2'], '22'); - equal(inflector.rules.irregular['3'], '32'); - - equal(inflector.rules.irregularInverse['12'], '1'); - equal(inflector.rules.irregularInverse['22'], '2'); - equal(inflector.rules.irregularInverse['32'], '3'); -}); - -test('uncountable',function(){ - expect(3); - - var inflector = new Ember.Inflector({ - uncountable: [ - '1', - '2', - '3' - ] - }); - - equal(inflector.rules.uncountable['1'], true); - equal(inflector.rules.uncountable['2'], true); - equal(inflector.rules.uncountable['3'], true); -}); - -test('inflect.nothing', function(){ - expect(2); - - var inflector = new Ember.Inflector(); - - equal(inflector.inflect('', []), ''); - equal(inflector.inflect(' ', []), ' '); -}); - -test('inflect.noRules',function(){ - expect(1); - - var inflector = new Ember.Inflector(); - - equal(inflector.inflect('word', []),'word'); -}); - -test('inflect.uncountable', function(){ - expect(1); - - var inflector = new Ember.Inflector({ - plural: [ - [/$/,'s'] - ], - uncountable: [ - 'word' - ] - }); - - var rules = []; - - equal(inflector.inflect('word', rules), 'word'); -}); - -test('inflect.irregular', function(){ - expect(2); - - var inflector = new Ember.Inflector({ - irregularPairs: [ - ['word', 'wordy'] - ] - }); - - var rules = []; - - equal(inflector.inflect('word', rules, inflector.rules.irregular), 'wordy'); - equal(inflector.inflect('wordy', rules, inflector.rules.irregularInverse), 'word'); -}); - -test('inflect.basicRules', function(){ - expect(1); - - var inflector = new Ember.Inflector(); - var rules = [[/$/, 's']]; - - equal(inflector.inflect('word', rules ), 'words'); -}); - -test('inflect.advancedRules', function(){ - expect(1); - - var inflector = new Ember.Inflector(); - var rules = [[/^(ox)$/i, '$1en']]; - - equal(inflector.inflect('ox', rules), 'oxen'); -}); - -test('Inflector.defaultRules', function(){ - expect(1); - - var rules = Ember.Inflector.defaultRules; - ok(rules, 'has defaultRules'); -}); - -test('Ember.Inflector.inflector exists', function(){ - expect(1); - - ok(Ember.Inflector.inflector, 'Ember.Inflector.inflector exists'); -}); - -test('new Ember.Inflector with defaultRules matches docs', function(){ - expect(4); - - var inflector = new Ember.Inflector(Ember.Inflector.defaultRules); - - // defaultRules includes these special rules - equal(inflector.pluralize('cow'), 'kine'); - equal(inflector.singularize('kine'), 'cow'); - - // defaultRules adds 's' to singular - equal(inflector.pluralize('item'), 'items'); - - // defaultRules removes 's' from plural - equal(inflector.singularize('items'), 'item'); -}); diff --git a/packages/ember-inflector/tests/system/integration_test.js b/packages/ember-inflector/tests/system/integration_test.js deleted file mode 100644 index 9a9e3b59c26..00000000000 --- a/packages/ember-inflector/tests/system/integration_test.js +++ /dev/null @@ -1,17 +0,0 @@ -module("ember-inflector.integration"); - -test("pluralize", function(){ - expect(3); - - equal(Ember.String.pluralize('word'), 'words'); - equal(Ember.String.pluralize('ox'), 'oxen'); - equal(Ember.String.pluralize('octopus'), 'octopi'); -}); - -test("singularize", function(){ - expect(3); - - equal(Ember.String.singularize('words'), 'word'); - equal(Ember.String.singularize('oxen'), 'ox'); - equal(Ember.String.singularize('octopi'), 'octopus'); -}); From 50f7e74afa242f4529a1de8b76fe7b3900f00989 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 24 Jul 2014 11:17:10 -0400 Subject: [PATCH 0251/2527] misc cleanup --- packages/activemodel-adapter/lib/main.js | 6 +++++- packages/activemodel-adapter/lib/setup-container.js | 4 ++-- packages/activemodel-adapter/lib/system.js | 6 +++++- .../lib/system/active_model_adapter.js | 2 +- .../lib/system/active_model_serializer.js | 10 +++++----- .../lib/system/embedded_records_mixin.js | 7 +++---- 6 files changed, 21 insertions(+), 14 deletions(-) diff --git a/packages/activemodel-adapter/lib/main.js b/packages/activemodel-adapter/lib/main.js index bf5aa03c387..28a0ab26fba 100644 --- a/packages/activemodel-adapter/lib/main.js +++ b/packages/activemodel-adapter/lib/main.js @@ -1,4 +1,8 @@ -import {ActiveModelAdapter, ActiveModelSerializer, EmbeddedRecordsMixin} from "./system"; +import { + ActiveModelAdapter, + ActiveModelSerializer, + EmbeddedRecordsMixin +} from "./system"; export { ActiveModelAdapter, diff --git a/packages/activemodel-adapter/lib/setup-container.js b/packages/activemodel-adapter/lib/setup-container.js index 602fc7384cf..a5ca72fa63e 100644 --- a/packages/activemodel-adapter/lib/setup-container.js +++ b/packages/activemodel-adapter/lib/setup-container.js @@ -5,8 +5,8 @@ import ActiveModelAdapter from "./system/active_model_adapter"; export default function setupActiveModelAdapter(container, application){ var proxy = new ContainerProxy(container); proxy.registerDeprecations([ - {deprecated: 'serializer:_ams', valid: 'serializer:-active-model'}, - {deprecated: 'adapter:_ams', valid: 'adapter:-active-model'} + { deprecated: 'serializer:_ams', valid: 'serializer:-active-model' }, + { deprecated: 'adapter:_ams', valid: 'adapter:-active-model' } ]); container.register('serializer:-active-model', ActiveModelSerializer); diff --git a/packages/activemodel-adapter/lib/system.js b/packages/activemodel-adapter/lib/system.js index eb77bcb9460..70f71c6f5ec 100644 --- a/packages/activemodel-adapter/lib/system.js +++ b/packages/activemodel-adapter/lib/system.js @@ -2,4 +2,8 @@ import EmbeddedRecordsMixin from "./system/embedded_records_mixin"; import ActiveModelAdapter from "./system/active_model_adapter"; import ActiveModelSerializer from "./system/active_model_serializer"; -export {EmbeddedRecordsMixin, ActiveModelAdapter, ActiveModelSerializer}; +export { + EmbeddedRecordsMixin, + ActiveModelAdapter, + ActiveModelSerializer +}; diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index dfa877ba332..065bf8d6a0e 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -28,7 +28,7 @@ var decamelize = Ember.String.decamelize, The ActiveModelAdapter expects the JSON returned from your server to follow the REST adapter conventions substituting underscored keys for camelcased ones. - + Unlike the DS.RESTAdapter, async relationship keys must be the singular form of the relationship name, followed by "_id" for DS.belongsTo relationships, or "_ids" for DS.hasMany relationships. diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index 799d74fa081..5c8f8b112f8 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -1,4 +1,4 @@ -import {singularize} from "../../../ember-inflector/lib/main"; +import { singularize } from "../../../ember-inflector/lib/main"; import RESTSerializer from "../../../ember-data/lib/serializers/rest_serializer"; /** @module ember-data @@ -120,8 +120,8 @@ var ActiveModelSerializer = RESTSerializer.extend({ @param {String} kind @return String */ - keyForRelationship: function(key, kind) { - key = decamelize(key); + keyForRelationship: function(rawKey, kind) { + var key = decamelize(rawKey); if (kind === "belongsTo") { return key + "_id"; } else if (kind === "hasMany") { @@ -159,8 +159,8 @@ var ActiveModelSerializer = RESTSerializer.extend({ @param relationship */ serializePolymorphicType: function(record, json, relationship) { - var key = relationship.key, - belongsTo = get(record, key); + var key = relationship.key; + var belongsTo = get(record, key); if (belongsTo) { key = this.keyForAttribute(key); diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index 9d6c62e47a3..d1eb489ec2b 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -2,7 +2,7 @@ var get = Ember.get; var forEach = Ember.EnumerableUtils.forEach; var camelize = Ember.String.camelize; -import {pluralize} from "../../../ember-inflector/lib/main"; +import { pluralize } from "../../../ember-inflector/lib/main"; /** ## Using Embedded Records @@ -109,9 +109,8 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ @return {Object} the normalized hash **/ normalize: function(type, hash, prop) { - hash = this._super(type, hash, prop); - hash = extractEmbeddedRecords(this, this.store, type, hash); - return hash; + var normalizedHash = this._super(type, hash, prop); + return extractEmbeddedRecords(this, this.store, type, normalizedHash); }, keyForRelationship: function(key, type){ From f980e1acf33457df449816899f0830f816f972c8 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 24 Jul 2014 12:27:41 -0400 Subject: [PATCH 0252/2527] the string splitting in transitionTo is wasteful and for large payloads can be surprisingly costly. As they never actually change, we should simply cache and forget about them. some numbers for (1000 model pushPayload) 18.3ms -> 3.2ms for transitionTo --- packages/ember-data/lib/system/model/model.js | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 13abf5393f9..88adfb25b8b 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -16,6 +16,21 @@ var retrieveFromCurrentState = Ember.computed('currentState', function(key, valu return get(get(this, 'currentState'), key); }).readOnly(); +var _extractPivotNameCache = Object.create(null); +var _splitOnDotCache = Object.create(null); + +function splitOnDot(name) { + return _splitOnDotCache[name] || ( + _splitOnDotCache[name] = name.split('.') + ); +} + +function extractPivotName(name) { + return _extractPivotNameCache[name] || ( + _extractPivotNameCache[name] = splitOnDot(name)[0] + ); +} + /** The model class that all Ember Data records descend from. @@ -454,7 +469,7 @@ var Model = Ember.Object.extend(Ember.Evented, { // POSSIBLE TODO: Remove this code and replace with // always having direct references to state objects - var pivotName = name.split('.', 1); + var pivotName = extractPivotName(name); var currentState = get(this, 'currentState'); var state = currentState; @@ -463,8 +478,7 @@ var Model = Ember.Object.extend(Ember.Evented, { state = state.parentState; } while (!state.hasOwnProperty(pivotName)); - var path = name.split('.'); - + var path = splitOnDot(name); var setups = [], enters = [], i, l; for (i=0, l=path.length; i Date: Thu, 24 Jul 2014 14:26:36 -0400 Subject: [PATCH 0253/2527] since the recordArrayManager already maintains the uniq index, we can use that to simply push the record onto the record array without needing the safety of addRecords dupe guard. This prevents another O(n) operation --- .../ember-data/lib/system/record_array_manager.js | 2 +- .../lib/system/record_arrays/record_array.js | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index 0b3c0e98676..1fafec70c58 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -118,7 +118,7 @@ export default Ember.Object.extend({ if (shouldBeInArray) { if (!recordArrays.has(array)) { - array.addRecord(record); + array.pushRecord(record); recordArrays.add(array); } } else if (!shouldBeInArray) { diff --git a/packages/ember-data/lib/system/record_arrays/record_array.js b/packages/ember-data/lib/system/record_arrays/record_array.js index f9b4e4ce725..f1cf154481e 100644 --- a/packages/ember-data/lib/system/record_arrays/record_array.js +++ b/packages/ember-data/lib/system/record_arrays/record_array.js @@ -119,7 +119,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { }, /** - Adds a record to the `RecordArray`. + Adds a record to the `RecordArray` without duplicates @method addRecord @private @@ -129,6 +129,18 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { get(this, 'content').addObject(record); }, + /** + Adds a record to the `RecordArray`, but allows duplicates + + @method pushRecord + @private + @param {DS.Model} record + */ + pushRecord: function(record) { + get(this, 'content').pushObject(record); + }, + + /** Removes a record to the `RecordArray`. From f376db36f33fcd67793931f4d8cf2926956a8183 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 24 Jul 2014 14:31:51 -0400 Subject: [PATCH 0254/2527] =?UTF-8?q?prefer=20Object.create(null)=20for=20?= =?UTF-8?q?typeMap=20backing=20stores.=20Cache=20misses=20are=20faster,=20?= =?UTF-8?q?and=20won=E2=80=99t=20collide=20with=20prototype=20pollution?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../record_arrays/adapter_populated_record_array.js | 10 +++++++++- packages/ember-data/lib/system/store.js | 8 ++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js index 7c602d62777..fcc2b80221b 100644 --- a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js @@ -6,6 +6,14 @@ import RecordArray from "./record_array"; var get = Ember.get; var set = Ember.set; +function cloneNull(source) { + var clone = Object.create(null); + for (var key in source) { + clone[key] = source[key]; + } + return clone; +} + /** Represents an ordered list of records whose order and membership is determined by the adapter. For example, a query sent to the adapter @@ -38,7 +46,7 @@ export default RecordArray.extend({ this.setProperties({ content: Ember.A(records), isLoaded: true, - meta: Ember.copy(meta) + meta: cloneNull(meta) }); records.forEach(function(record) { diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 0a0fb7403c4..ca7c062a0e6 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -679,7 +679,7 @@ Store = Ember.Object.extend({ var idToRecord = this.typeMapFor(type).idToRecord; var record = idToRecord[id]; - if (!record || !idToRecord.hasOwnProperty(id)) { + if (!record || !idToRecord[id]) { record = this.buildRecord(type, id); } @@ -1163,9 +1163,9 @@ Store = Ember.Object.extend({ if (typeMap) { return typeMap; } typeMap = { - idToRecord: {}, + idToRecord: Object.create(null), records: [], - metadata: {}, + metadata: Object.create(null), type: type }; @@ -1472,7 +1472,7 @@ Store = Ember.Object.extend({ var typeMap = this.typeMapFor(type); var idToRecord = typeMap.idToRecord; - Ember.assert('The id ' + id + ' has already been used with another record of type ' + type.toString() + '.', !id || !idToRecord.hasOwnProperty(id)); + Ember.assert('The id ' + id + ' has already been used with another record of type ' + type.toString() + '.', !id || !idToRecord[id]); Ember.assert("`" + Ember.inspect(type)+ "` does not appear to be an ember-data model", (typeof type._create === 'function') ); // lookupFactory should really return an object that creates From 1b4414fe6c355d3e0dca7982b1cb9092b189d13a Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 26 Jul 2014 15:51:12 -0500 Subject: [PATCH 0255/2527] move import statements to fully qualified path --- packages/activemodel-adapter/lib/main.js | 2 +- .../lib/setup-container.js | 6 +-- packages/activemodel-adapter/lib/system.js | 6 +-- .../lib/system/active_model_adapter.js | 12 ++--- .../lib/system/active_model_serializer.js | 4 +- .../lib/system/embedded_records_mixin.js | 2 +- packages/ember-data/lib/adapters.js | 4 +- .../lib/adapters/fixture_adapter.js | 2 +- .../ember-data/lib/adapters/rest_adapter.js | 2 +- packages/ember-data/lib/ember-initializer.js | 2 +- .../lib/initializers/data_adapter.js | 2 +- packages/ember-data/lib/initializers/store.js | 8 +-- .../ember-data/lib/initializers/transforms.js | 2 +- packages/ember-data/lib/main.js | 38 ++++++------- packages/ember-data/lib/serializers.js | 4 +- .../lib/serializers/json_serializer.js | 2 +- .../lib/serializers/rest_serializer.js | 4 +- packages/ember-data/lib/setup-container.js | 10 ++-- packages/ember-data/lib/system/changes.js | 2 +- .../lib/system/changes/relationship_change.js | 2 +- packages/ember-data/lib/system/debug.js | 4 +- .../lib/system/debug/debug_adapter.js | 2 +- .../ember-data/lib/system/debug/debug_info.js | 2 +- packages/ember-data/lib/system/model.js | 8 +-- .../ember-data/lib/system/model/attributes.js | 2 +- packages/ember-data/lib/system/model/model.js | 8 +-- .../lib/system/record_array_manager.js | 2 +- .../ember-data/lib/system/record_arrays.js | 8 +-- .../adapter_populated_record_array.js | 2 +- .../record_arrays/filtered_record_array.js | 2 +- .../lib/system/record_arrays/many_array.js | 4 +- .../lib/system/record_arrays/record_array.js | 2 +- .../lib/system/relationship-meta.js | 2 +- .../ember-data/lib/system/relationships.js | 2 +- .../lib/system/relationships/belongs_to.js | 8 +-- .../lib/system/relationships/ext.js | 10 ++-- .../lib/system/relationships/has_many.js | 4 +- packages/ember-data/lib/system/store.js | 8 +-- packages/ember-data/lib/transforms.js | 10 ++-- packages/ember-data/lib/transforms/boolean.js | 2 +- packages/ember-data/lib/transforms/date.js | 2 +- packages/ember-data/lib/transforms/number.js | 2 +- packages/ember-data/lib/transforms/string.js | 2 +- tests/index.html | 3 +- vendor/loader.js | 53 ------------------- 45 files changed, 109 insertions(+), 161 deletions(-) delete mode 100644 vendor/loader.js diff --git a/packages/activemodel-adapter/lib/main.js b/packages/activemodel-adapter/lib/main.js index bf5aa03c387..81795a57cf3 100644 --- a/packages/activemodel-adapter/lib/main.js +++ b/packages/activemodel-adapter/lib/main.js @@ -1,4 +1,4 @@ -import {ActiveModelAdapter, ActiveModelSerializer, EmbeddedRecordsMixin} from "./system"; +import {ActiveModelAdapter, ActiveModelSerializer, EmbeddedRecordsMixin} from "activemodel-adapter/system"; export { ActiveModelAdapter, diff --git a/packages/activemodel-adapter/lib/setup-container.js b/packages/activemodel-adapter/lib/setup-container.js index 602fc7384cf..3b711b4d01f 100644 --- a/packages/activemodel-adapter/lib/setup-container.js +++ b/packages/activemodel-adapter/lib/setup-container.js @@ -1,6 +1,6 @@ -import ContainerProxy from "../../ember-data/lib/system/container_proxy"; -import ActiveModelSerializer from "./system/active_model_serializer"; -import ActiveModelAdapter from "./system/active_model_adapter"; +import ContainerProxy from "ember-data/system/container_proxy"; +import ActiveModelSerializer from "activemodel-adapter/system/active_model_serializer"; +import ActiveModelAdapter from "activemodel-adapter/system/active_model_adapter"; export default function setupActiveModelAdapter(container, application){ var proxy = new ContainerProxy(container); diff --git a/packages/activemodel-adapter/lib/system.js b/packages/activemodel-adapter/lib/system.js index eb77bcb9460..15cfaafe3f3 100644 --- a/packages/activemodel-adapter/lib/system.js +++ b/packages/activemodel-adapter/lib/system.js @@ -1,5 +1,5 @@ -import EmbeddedRecordsMixin from "./system/embedded_records_mixin"; -import ActiveModelAdapter from "./system/active_model_adapter"; -import ActiveModelSerializer from "./system/active_model_serializer"; +import EmbeddedRecordsMixin from "activemodel-adapter/system/embedded_records_mixin"; +import ActiveModelAdapter from "activemodel-adapter/system/active_model_adapter"; +import ActiveModelSerializer from "activemodel-adapter/system/active_model_serializer"; export {EmbeddedRecordsMixin, ActiveModelAdapter, ActiveModelSerializer}; diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index dfa877ba332..f72414dde64 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -1,8 +1,8 @@ -import {RESTAdapter} from "../../../ember-data/lib/adapters"; -import {InvalidError} from "../../../ember-data/lib/system/adapter"; -import {pluralize} from "../../../ember-inflector/lib/main"; -import ActiveModelSerializer from "./active_model_serializer"; -import EmbeddedRecordsMixin from "./embedded_records_mixin"; +import {RESTAdapter} from "ember-data/adapters"; +import {InvalidError} from "ember-data/system/adapter"; +import {pluralize} from "ember-inflector"; +import ActiveModelSerializer from "activemodel-adapter/system/active_model_serializer"; +import EmbeddedRecordsMixin from "activemodel-adapter/system/embedded_records_mixin"; /** @module ember-data @@ -28,7 +28,7 @@ var decamelize = Ember.String.decamelize, The ActiveModelAdapter expects the JSON returned from your server to follow the REST adapter conventions substituting underscored keys for camelcased ones. - + Unlike the DS.RESTAdapter, async relationship keys must be the singular form of the relationship name, followed by "_id" for DS.belongsTo relationships, or "_ids" for DS.hasMany relationships. diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index 799d74fa081..ea7d478b385 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -1,5 +1,5 @@ -import {singularize} from "../../../ember-inflector/lib/main"; -import RESTSerializer from "../../../ember-data/lib/serializers/rest_serializer"; +import {singularize} from "ember-inflector"; +import RESTSerializer from "ember-data/serializers/rest_serializer"; /** @module ember-data */ diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index 8e67de8b918..2579cbace27 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -2,7 +2,7 @@ var get = Ember.get; var forEach = Ember.EnumerableUtils.forEach; var camelize = Ember.String.camelize; -import {pluralize} from "../../../ember-inflector/lib/main"; +import {pluralize} from "ember-inflector"; /** ## Using Embedded Records diff --git a/packages/ember-data/lib/adapters.js b/packages/ember-data/lib/adapters.js index 052381fef5f..201a3831b8f 100644 --- a/packages/ember-data/lib/adapters.js +++ b/packages/ember-data/lib/adapters.js @@ -2,8 +2,8 @@ @module ember-data */ -import FixtureAdapter from "./adapters/fixture_adapter"; -import RESTAdapter from "./adapters/rest_adapter"; +import FixtureAdapter from "ember-data/adapters/fixture_adapter"; +import RESTAdapter from "ember-data/adapters/rest_adapter"; export { RESTAdapter, diff --git a/packages/ember-data/lib/adapters/fixture_adapter.js b/packages/ember-data/lib/adapters/fixture_adapter.js index adf0541f5e6..6f1b0246538 100644 --- a/packages/ember-data/lib/adapters/fixture_adapter.js +++ b/packages/ember-data/lib/adapters/fixture_adapter.js @@ -8,7 +8,7 @@ var indexOf = Ember.EnumerableUtils.indexOf; var counter = 0; -import Adapter from "../system/adapter"; +import Adapter from "ember-data/system/adapter"; /** `DS.FixtureAdapter` is an adapter that loads records from memory. diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 87318bbd424..ef670ff84e0 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -2,7 +2,7 @@ @module ember-data */ -import Adapter from "../system/adapter"; +import Adapter from "ember-data/system/adapter"; var get = Ember.get; var forEach = Ember.ArrayPolyfills.forEach; diff --git a/packages/ember-data/lib/ember-initializer.js b/packages/ember-data/lib/ember-initializer.js index c9eea9dac3d..fcaca86a8c1 100644 --- a/packages/ember-data/lib/ember-initializer.js +++ b/packages/ember-data/lib/ember-initializer.js @@ -1,4 +1,4 @@ -import setupContainer from './setup-container'; +import setupContainer from 'ember-data/setup-container'; var K = Ember.K; diff --git a/packages/ember-data/lib/initializers/data_adapter.js b/packages/ember-data/lib/initializers/data_adapter.js index 52093ad3073..1657a70a88d 100644 --- a/packages/ember-data/lib/initializers/data_adapter.js +++ b/packages/ember-data/lib/initializers/data_adapter.js @@ -1,4 +1,4 @@ -import DebugAdapter from "../system/debug/debug_adapter"; +import DebugAdapter from "ember-data/system/debug/debug_adapter"; /** Configures a container with injections on Ember applications diff --git a/packages/ember-data/lib/initializers/store.js b/packages/ember-data/lib/initializers/store.js index ff43db1cdd5..c3430cab38b 100644 --- a/packages/ember-data/lib/initializers/store.js +++ b/packages/ember-data/lib/initializers/store.js @@ -1,7 +1,7 @@ -import {JSONSerializer, RESTSerializer} from "../serializers"; -import {RESTAdapter} from "../adapters"; -import ContainerProxy from "../system/container_proxy"; -import Store from "../system/store"; +import {JSONSerializer, RESTSerializer} from "ember-data/serializers"; +import {RESTAdapter} from "ember-data/adapters"; +import ContainerProxy from "ember-data/system/container_proxy"; +import Store from "ember-data/system/store"; /** Configures a container for use with an Ember-Data diff --git a/packages/ember-data/lib/initializers/transforms.js b/packages/ember-data/lib/initializers/transforms.js index 05943e93db8..80b6685ea1f 100644 --- a/packages/ember-data/lib/initializers/transforms.js +++ b/packages/ember-data/lib/initializers/transforms.js @@ -3,7 +3,7 @@ import { DateTransform, StringTransform, NumberTransform -} from "../transforms"; +} from "ember-data/transforms"; /** Configures a container for use with Ember-Data diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index bde44e19cf6..a868b3d256a 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -8,20 +8,20 @@ // support RSVP 2.x via resolve, but prefer RSVP 3.x's Promise.cast Ember.RSVP.Promise.cast = Ember.RSVP.Promise.cast || Ember.RSVP.resolve; -import DS from "./core"; -import "./ext/date"; +import DS from "ember-data/core"; +import "ember-data/ext/date"; import { Store, PromiseArray, PromiseObject -} from "./system/store"; +} from "ember-data/system/store"; import { Model, Errors, RootState, attr -} from "./system/model"; +} from "ember-data/system/model"; import { AttributeChange, RelationshipChange, @@ -31,31 +31,31 @@ import { ManyToNoneChange, OneToOneChange, ManyToManyChange -} from "./system/changes"; +} from "ember-data/system/changes"; import { InvalidError, Adapter -} from "./system/adapter"; -import DebugAdapter from "./system/debug"; +} from "ember-data/system/adapter"; +import DebugAdapter from "ember-data/system/debug"; import { RecordArray, FilteredRecordArray, AdapterPopulatedRecordArray, ManyArray -} from "./system/record_arrays"; -import RecordArrayManager from "./system/record_array_manager"; +} from "ember-data/system/record_arrays"; +import RecordArrayManager from "ember-data/system/record_array_manager"; import { RESTAdapter, FixtureAdapter -} from "./adapters"; -import JSONSerializer from "./serializers/json_serializer"; -import RESTSerializer from "./serializers/rest_serializer"; -import "../../ember-inflector/lib/main"; +} from "ember-data/adapters"; +import JSONSerializer from "ember-data/serializers/json_serializer"; +import RESTSerializer from "ember-data/serializers/rest_serializer"; +import "ember-inflector"; import { ActiveModelAdapter, ActiveModelSerializer, EmbeddedRecordsMixin -} from "../../activemodel-adapter/lib/main"; +} from "activemodel-adapter"; import { Transform, @@ -63,13 +63,13 @@ import { NumberTransform, StringTransform, BooleanTransform -} from "./transforms"; +} from "ember-data/transforms"; -import {hasMany, belongsTo} from "./system/relationships"; -import "./ember-initializer"; -import setupContainer from "./setup-container"; +import {hasMany, belongsTo} from "ember-data/system/relationships"; +import "ember-data/ember-initializer"; +import setupContainer from "ember-data/setup-container"; -import ContainerProxy from "./system/container_proxy"; +import ContainerProxy from "ember-data/system/container_proxy"; DS.Store = Store; DS.PromiseArray = PromiseArray; diff --git a/packages/ember-data/lib/serializers.js b/packages/ember-data/lib/serializers.js index 79652eb07de..c6d0f631832 100644 --- a/packages/ember-data/lib/serializers.js +++ b/packages/ember-data/lib/serializers.js @@ -1,5 +1,5 @@ -import JSONSerializer from "./serializers/json_serializer"; -import RESTSerializer from "./serializers/rest_serializer"; +import JSONSerializer from "ember-data/serializers/json_serializer"; +import RESTSerializer from "ember-data/serializers/rest_serializer"; export { JSONSerializer, diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index a4fa3310260..361d4e39420 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -1,4 +1,4 @@ -import { RelationshipChange } from "../system/changes"; +import { RelationshipChange } from "ember-data/system/changes"; var get = Ember.get; var set = Ember.set; var isNone = Ember.isNone; diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index 5a866d69a69..b2a83413c26 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -2,14 +2,14 @@ @module ember-data */ -import JSONSerializer from "./json_serializer"; +import JSONSerializer from "ember-data/serializers/json_serializer"; var get = Ember.get; var set = Ember.set; var forEach = Ember.ArrayPolyfills.forEach; var map = Ember.ArrayPolyfills.map; var camelize = Ember.String.camelize; -import { singularize } from "ember-inflector/lib/system/string"; +import { singularize } from "ember-inflector/system/string"; function coerceId(id) { return id == null ? null : id + ''; diff --git a/packages/ember-data/lib/setup-container.js b/packages/ember-data/lib/setup-container.js index c8b05f629ac..6e7e24597d3 100644 --- a/packages/ember-data/lib/setup-container.js +++ b/packages/ember-data/lib/setup-container.js @@ -1,8 +1,8 @@ -import initializeStore from './initializers/store'; -import initializeTransforms from './initializers/transforms'; -import initializeStoreInjections from './initializers/store_injections'; -import initializeDataAdapter from './initializers/data_adapter'; -import setupActiveModelContainer from '../../../activemodel-adapter/lib/setup-container'; +import initializeStore from 'ember-data/initializers/store'; +import initializeTransforms from 'ember-data/initializers/transforms'; +import initializeStoreInjections from 'ember-data/initializers/store_injections'; +import initializeDataAdapter from 'ember-data/initializers/data_adapter'; +import setupActiveModelContainer from 'activemodel-adapter/setup-container'; export default function setupContainer(container, application){ // application is not a required argument. This ensures diff --git a/packages/ember-data/lib/system/changes.js b/packages/ember-data/lib/system/changes.js index 2cf8d3df96d..4d2000bcfd1 100644 --- a/packages/ember-data/lib/system/changes.js +++ b/packages/ember-data/lib/system/changes.js @@ -10,7 +10,7 @@ import { ManyToNoneChange, OneToOneChange, ManyToManyChange -} from "./changes/relationship_change"; +} from "ember-data/system/changes/relationship_change"; export { RelationshipChange, diff --git a/packages/ember-data/lib/system/changes/relationship_change.js b/packages/ember-data/lib/system/changes/relationship_change.js index fa7a5bc332b..711600f3812 100644 --- a/packages/ember-data/lib/system/changes/relationship_change.js +++ b/packages/ember-data/lib/system/changes/relationship_change.js @@ -2,7 +2,7 @@ @module ember-data */ -import { Model } from "../model"; +import { Model } from "ember-data/system/model"; var get = Ember.get; var set = Ember.set; diff --git a/packages/ember-data/lib/system/debug.js b/packages/ember-data/lib/system/debug.js index 6858402e7b1..35dbf23c72c 100644 --- a/packages/ember-data/lib/system/debug.js +++ b/packages/ember-data/lib/system/debug.js @@ -2,7 +2,7 @@ @module ember-data */ -import "./debug/debug_info"; -import DebugAdapter from "./debug/debug_adapter"; +import "ember-data/system/debug/debug_info"; +import DebugAdapter from "ember-data/system/debug/debug_adapter"; export default DebugAdapter; diff --git a/packages/ember-data/lib/system/debug/debug_adapter.js b/packages/ember-data/lib/system/debug/debug_adapter.js index e9910fbd510..3617bd075b8 100644 --- a/packages/ember-data/lib/system/debug/debug_adapter.js +++ b/packages/ember-data/lib/system/debug/debug_adapter.js @@ -1,7 +1,7 @@ /** @module ember-data */ -import { Model } from "../model"; +import { Model } from "ember-data/system/model"; var get = Ember.get; var capitalize = Ember.String.capitalize; var underscore = Ember.String.underscore; diff --git a/packages/ember-data/lib/system/debug/debug_info.js b/packages/ember-data/lib/system/debug/debug_info.js index fefd94183c1..f1699eca5a3 100644 --- a/packages/ember-data/lib/system/debug/debug_info.js +++ b/packages/ember-data/lib/system/debug/debug_info.js @@ -1,4 +1,4 @@ -import { Model } from "../model"; +import { Model } from "ember-data/system/model"; Model.reopen({ diff --git a/packages/ember-data/lib/system/model.js b/packages/ember-data/lib/system/model.js index cc36b5f433d..dfb8a0c185c 100644 --- a/packages/ember-data/lib/system/model.js +++ b/packages/ember-data/lib/system/model.js @@ -2,10 +2,10 @@ @module ember-data */ -import Model from "./model/model"; -import attr from "./model/attributes"; -import RootState from "./model/states"; -import Errors from "./model/errors"; +import Model from "ember-data/system/model/model"; +import attr from "ember-data/system/model/attributes"; +import RootState from "ember-data/system/model/states"; +import Errors from "ember-data/system/model/errors"; export { Model, diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 5eb5937902f..790bf639e46 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -1,4 +1,4 @@ -import Model from "./model"; +import Model from "ember-data/system/model/model"; /** @module ember-data diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 92d281f1901..82dfdd72c3f 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1,6 +1,6 @@ -import RootState from "./states"; -import Errors from "./errors"; -import { PromiseObject } from "../store"; +import RootState from "ember-data/system/model/states"; +import Errors from "ember-data/system/model/errors"; +import { PromiseObject } from "ember-data/system/store"; /** @module ember-data */ @@ -354,7 +354,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @return {Object} A JSON representation of the object. */ toJSON: function(options) { - if (!JSONSerializer) { JSONSerializer = requireModule("ember-data/lib/serializers/json_serializer")["default"]; } + if (!JSONSerializer) { JSONSerializer = requireModule("ember-data/serializers/json_serializer")["default"]; } // container is for lazy transform lookups var serializer = JSONSerializer.create({ container: this.container }); return serializer.serialize(this, options); diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index a10f6d2a791..e9cf9cfeb2a 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -7,7 +7,7 @@ import { FilteredRecordArray, AdapterPopulatedRecordArray, ManyArray -} from "./record_arrays"; +} from "ember-data/system/record_arrays"; var get = Ember.get; var set = Ember.set; var forEach = Ember.EnumerableUtils.forEach; diff --git a/packages/ember-data/lib/system/record_arrays.js b/packages/ember-data/lib/system/record_arrays.js index 625a8185291..fe1679b1981 100644 --- a/packages/ember-data/lib/system/record_arrays.js +++ b/packages/ember-data/lib/system/record_arrays.js @@ -2,10 +2,10 @@ @module ember-data */ -import RecordArray from "./record_arrays/record_array"; -import FilteredRecordArray from "./record_arrays/filtered_record_array"; -import AdapterPopulatedRecordArray from "./record_arrays/adapter_populated_record_array"; -import ManyArray from "./record_arrays/many_array"; +import RecordArray from "ember-data/system/record_arrays/record_array"; +import FilteredRecordArray from "ember-data/system/record_arrays/filtered_record_array"; +import AdapterPopulatedRecordArray from "ember-data/system/record_arrays/adapter_populated_record_array"; +import ManyArray from "ember-data/system/record_arrays/many_array"; export { RecordArray, diff --git a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js index 636e6ba9be0..d93beda8cc2 100644 --- a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js @@ -1,4 +1,4 @@ -import RecordArray from "./record_array"; +import RecordArray from "ember-data/system/record_arrays/record_array"; /** @module ember-data */ diff --git a/packages/ember-data/lib/system/record_arrays/filtered_record_array.js b/packages/ember-data/lib/system/record_arrays/filtered_record_array.js index 037a0e92d13..00c28161927 100644 --- a/packages/ember-data/lib/system/record_arrays/filtered_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/filtered_record_array.js @@ -1,4 +1,4 @@ -import RecordArray from "./record_array"; +import RecordArray from "ember-data/system/record_arrays/record_array"; /** @module ember-data diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 90eb3fa9bef..d97fcab1edf 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -1,5 +1,5 @@ -import RecordArray from "./record_array"; -import {RelationshipChange} from "../changes"; +import RecordArray from "ember-data/system/record_arrays/record_array"; +import {RelationshipChange} from "ember-data/system/changes"; /** @module ember-data diff --git a/packages/ember-data/lib/system/record_arrays/record_array.js b/packages/ember-data/lib/system/record_arrays/record_array.js index 5d3d1677dce..d43a60bf9ed 100644 --- a/packages/ember-data/lib/system/record_arrays/record_array.js +++ b/packages/ember-data/lib/system/record_arrays/record_array.js @@ -2,7 +2,7 @@ @module ember-data */ -import { PromiseArray } from "../store"; +import { PromiseArray } from "ember-data/system/store"; var get = Ember.get; var set = Ember.set; diff --git a/packages/ember-data/lib/system/relationship-meta.js b/packages/ember-data/lib/system/relationship-meta.js index 7d3eedb18b7..dbf472bfc18 100644 --- a/packages/ember-data/lib/system/relationship-meta.js +++ b/packages/ember-data/lib/system/relationship-meta.js @@ -1,4 +1,4 @@ -import { singularize } from "../../../ember-inflector/lib/system"; +import { singularize } from "ember-inflector/system"; export function typeForRelationshipMeta(store, meta) { var typeKey, type; diff --git a/packages/ember-data/lib/system/relationships.js b/packages/ember-data/lib/system/relationships.js index 0b3c4fd9d94..4d5c1bca0d0 100644 --- a/packages/ember-data/lib/system/relationships.js +++ b/packages/ember-data/lib/system/relationships.js @@ -5,7 +5,7 @@ import belongsTo from "./relationships/belongs_to"; import hasMany from "./relationships/has_many"; -import "../system/relationships/ext"; +import "ember-data/system/relationships/ext"; export { belongsTo, diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index 2ba087d4043..cf43161e2c1 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -3,13 +3,13 @@ var set = Ember.set; var isNone = Ember.isNone; var Promise = Ember.RSVP.Promise; -import { Model } from '../model'; -import { PromiseObject } from '../store'; -import { RelationshipChange } from '../changes'; +import { Model } from 'ember-data/system/model'; +import { PromiseObject } from 'ember-data/system/store'; +import { RelationshipChange } from 'ember-data/system/changes'; import { relationshipFromMeta, typeForRelationshipMeta -} from '../relationship-meta'; +} from 'ember-data/system/relationship-meta'; /** @module ember-data diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 1ae22d49343..2c2a4324612 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -1,9 +1,9 @@ -import { singularize } from "../../../../ember-inflector/lib/system"; +import { singularize } from "ember-inflector/system"; import { typeForRelationshipMeta, relationshipFromMeta -} from "../relationship-meta"; -import { Model } from "../model"; +} from "ember-data/system/relationship-meta"; +import { Model } from "ember-data/system/model"; var get = Ember.get; var set = Ember.set; @@ -124,7 +124,7 @@ Model.reopenClass({ inverseName = options.inverse; inverse = Ember.get(inverseType, 'relationshipsByName').get(inverseName); - Ember.assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.typeKey + + Ember.assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.typeKey + "' model. This is most likely due to a missing attribute on your model definition.", !Ember.isNone(inverse)); inverseKind = inverse.kind; @@ -133,7 +133,7 @@ Model.reopenClass({ if (possibleRelationships.length === 0) { return null; } - Ember.assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + + Ember.assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + this + " were found on " + inverseType + ". Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", possibleRelationships.length === 1); diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index a22eaddc16d..7144c9615dd 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -2,12 +2,12 @@ @module ember-data */ -import { PromiseArray } from "../store"; +import { PromiseArray } from "ember-data/system/store"; import { relationshipFromMeta, typeForRelationshipMeta -} from "../relationship-meta"; +} from "ember-data/system/relationship-meta"; var get = Ember.get; var set = Ember.set; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 531122cd757..d0551b70b98 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -8,8 +8,8 @@ import { InvalidError, Adapter -} from "./adapter"; -import { singularize } from "ember-inflector/lib/system/string"; +} from "ember-data/system/adapter"; +import { singularize } from "ember-inflector/system/string"; var get = Ember.get; var set = Ember.set; var once = Ember.run.once; @@ -133,7 +133,7 @@ Store = Ember.Object.extend({ */ init: function() { // internal bookkeeping; not observable - if (!RecordArrayManager) { RecordArrayManager = requireModule("ember-data/lib/system/record_array_manager")["default"]; } + if (!RecordArrayManager) { RecordArrayManager = requireModule("ember-data/system/record_array_manager")["default"]; } this.typeMaps = {}; this.recordArrayManager = RecordArrayManager.create({ store: this @@ -1572,7 +1572,7 @@ function normalizeRelationships(store, type, data, record) { } function deserializeRecordId(store, data, key, relationship, id) { - if (!Model) { Model = requireModule("ember-data/lib/system/model")["Model"]; } + if (!Model) { Model = requireModule("ember-data/system/model")["Model"]; } if (isNone(id) || id instanceof Model) { return; } diff --git a/packages/ember-data/lib/transforms.js b/packages/ember-data/lib/transforms.js index 4372e14dbd8..5bb2a521508 100644 --- a/packages/ember-data/lib/transforms.js +++ b/packages/ember-data/lib/transforms.js @@ -1,8 +1,8 @@ -import Transform from "./transforms/base"; -import NumberTransform from "./transforms/number"; -import DateTransform from "./transforms/date"; -import StringTransform from "./transforms/string"; -import BooleanTransform from "./transforms/boolean"; +import Transform from "ember-data/transforms/base"; +import NumberTransform from "ember-data/transforms/number"; +import DateTransform from "ember-data/transforms/date"; +import StringTransform from "ember-data/transforms/string"; +import BooleanTransform from "ember-data/transforms/boolean"; export { Transform, diff --git a/packages/ember-data/lib/transforms/boolean.js b/packages/ember-data/lib/transforms/boolean.js index b2989a122c4..69f72819f2a 100644 --- a/packages/ember-data/lib/transforms/boolean.js +++ b/packages/ember-data/lib/transforms/boolean.js @@ -1,4 +1,4 @@ -import Transform from "./base"; +import Transform from "ember-data/transforms/base"; /** The `DS.BooleanTransform` class is used to serialize and deserialize diff --git a/packages/ember-data/lib/transforms/date.js b/packages/ember-data/lib/transforms/date.js index 65f3c2f7d3c..716d59c5c4b 100644 --- a/packages/ember-data/lib/transforms/date.js +++ b/packages/ember-data/lib/transforms/date.js @@ -17,7 +17,7 @@ @extends DS.Transform @namespace DS */ -import Transform from "./base"; +import Transform from "ember-data/transforms/base"; function pad(num) { return num < 10 ? "0"+num : ""+num; diff --git a/packages/ember-data/lib/transforms/number.js b/packages/ember-data/lib/transforms/number.js index 08d91a60962..525aba0ad77 100644 --- a/packages/ember-data/lib/transforms/number.js +++ b/packages/ember-data/lib/transforms/number.js @@ -1,4 +1,4 @@ -import Transform from "./base"; +import Transform from "ember-data/transforms/base"; var empty = Ember.isEmpty; diff --git a/packages/ember-data/lib/transforms/string.js b/packages/ember-data/lib/transforms/string.js index 7f71ba64b73..180a1973590 100644 --- a/packages/ember-data/lib/transforms/string.js +++ b/packages/ember-data/lib/transforms/string.js @@ -1,4 +1,4 @@ -import Transform from "./base"; +import Transform from "ember-data/transforms/base"; var none = Ember.isNone; /** diff --git a/tests/index.html b/tests/index.html index b1b3fca4f22..0a0bf0d6d70 100644 --- a/tests/index.html +++ b/tests/index.html @@ -5,6 +5,7 @@ Ember Data + @@ -47,7 +48,7 @@ - +
      diff --git a/vendor/loader.js b/vendor/loader.js deleted file mode 100644 index 54d178b76d8..00000000000 --- a/vendor/loader.js +++ /dev/null @@ -1,53 +0,0 @@ -var define, requireModule, require, requirejs; - -(function() { - var registry = {}, seen = {}; - - define = function(name, deps, callback) { - registry[name] = { deps: deps, callback: callback }; - }; - - requirejs = require = requireModule = function(name) { - requirejs._eak_seen = registry; - - if (seen[name]) { return seen[name]; } - seen[name] = {}; - - if (!registry[name]) { - throw new Error("Could not find module " + name); - } - - var mod = registry[name], - deps = mod.deps, - callback = mod.callback, - reified = [], - exports; - - for (var i=0, l=deps.length; i Date: Sat, 26 Jul 2014 15:52:07 -0500 Subject: [PATCH 0256/2527] begin broccolification --- .jshintrc | 1 + Brocfile.js | 163 +++++++++++ Gruntfile.js | 5 +- bower.json | 4 + config/package_manager_files/package.json | 14 +- config/testem-beta.json | 7 + config/testem-canary.json | 7 + config/testem-stable.json | 7 + package.json | 20 +- packages/ember-inflector/lib/ext/string.js | 23 -- packages/ember-inflector/lib/main.js | 13 - packages/ember-inflector/lib/system.js | 12 - .../ember-inflector/lib/system/inflections.js | 80 ------ .../ember-inflector/lib/system/inflector.js | 199 ------------- packages/ember-inflector/lib/system/string.js | 10 - packages/ember-inflector/package.json | 23 -- .../tests/system/inflector_test.js | 264 ------------------ .../tests/system/integration_test.js | 17 -- tasks/browser.js | 12 - tasks/lock.js | 11 - tasks/options/browser.js | 6 - tasks/options/clean.js | 2 +- tasks/options/concat.js | 22 -- tasks/options/connect.js | 25 -- tasks/options/emberDefeatureify.js | 18 -- tasks/options/jshint.js | 7 - tasks/options/qunit.js | 22 -- tasks/options/transpile.js | 25 -- tasks/options/uglify.js | 22 -- tasks/options/watch.js | 12 - testem.json | 7 + 31 files changed, 223 insertions(+), 837 deletions(-) create mode 100644 Brocfile.js create mode 100644 config/testem-beta.json create mode 100644 config/testem-canary.json create mode 100644 config/testem-stable.json delete mode 100644 packages/ember-inflector/lib/ext/string.js delete mode 100644 packages/ember-inflector/lib/main.js delete mode 100644 packages/ember-inflector/lib/system.js delete mode 100644 packages/ember-inflector/lib/system/inflections.js delete mode 100644 packages/ember-inflector/lib/system/inflector.js delete mode 100644 packages/ember-inflector/lib/system/string.js delete mode 100644 packages/ember-inflector/package.json delete mode 100644 packages/ember-inflector/tests/system/inflector_test.js delete mode 100644 packages/ember-inflector/tests/system/integration_test.js delete mode 100644 tasks/browser.js delete mode 100644 tasks/lock.js delete mode 100644 tasks/options/browser.js delete mode 100644 tasks/options/concat.js delete mode 100644 tasks/options/connect.js delete mode 100644 tasks/options/emberDefeatureify.js delete mode 100644 tasks/options/jshint.js delete mode 100644 tasks/options/qunit.js delete mode 100644 tasks/options/transpile.js delete mode 100644 tasks/options/uglify.js delete mode 100644 tasks/options/watch.js create mode 100644 testem.json diff --git a/.jshintrc b/.jshintrc index b4aacc90eda..366dd7cb390 100644 --- a/.jshintrc +++ b/.jshintrc @@ -11,6 +11,7 @@ "ember_deprecate", "ember_deprecateFunc", "require", + "define", "setupStore", "createStore", "equal", diff --git a/Brocfile.js b/Brocfile.js new file mode 100644 index 00000000000..8d6512e4f74 --- /dev/null +++ b/Brocfile.js @@ -0,0 +1,163 @@ +var es6 = require('broccoli-es6-module-transpiler'); +var concat = require('broccoli-concat'); +var uglify = require('broccoli-uglify-js'); +var es3SafeRecast = require('broccoli-es3-safe-recast'); +var env = require('broccoli-env').getEnv(); +var pickFiles = require('broccoli-static-compiler'); +var merge = require('broccoli-merge-trees'); +var moveFile = require('broccoli-file-mover'); +var removeFile = require('broccoli-file-remover'); +var wrap = require('broccoli-wrap'); +var jshint = require('broccoli-jshint'); +var defeatureify = require('broccoli-defeatureify'); +var version = require('./lib/utilities/ember-data-version')(); +var renderTemplate = require('broccoli-render-template'); +var yuidoc = require('broccoli-yuidoc'); + +function moveFromLibAndMainJS(packageName, vendored){ + var root = vendored ? 'bower_components/' + packageName + "/packages/" + packageName + '/lib': + 'packages/' + packageName + '/lib'; + var tree = pickFiles(root, { + srcDir: '/', + files: [ '**/*.js' ], + destDir: '/' + packageName + }); + tree = moveFile(tree, { + srcFile: packageName + '/main.js', + destFile: '/' + packageName + '.js' + }); + tree = es6(tree, {moduleName: true}); + return tree; +} + +function minify(tree, name){ + var config = require('./tasks/options/emberDefeatureify'); + tree = defeatureify(tree, { + debugStatements: config.options.debugStatements, + enableStripDebug: config.stripDebug + }); + tree = moveFile(tree, { + srcFile: name + '.js', + destFile: '/' + name + '.prod.js' + }); + var uglified = moveFile(uglify(tree, {mangle: true}),{ + srcFile: name + '.prod.js', + destFile: '/' + name + '.min.js' + }); + return merge([uglified, tree]); +} + +function testTree(libTree, packageName){ + var test = pickFiles('packages/' + packageName + '/tests', { + srcDir: '/', + files: [ '**/*.js' ], + destDir: '/' + }); + var jshinted = jshint(libTree); + jshinted = wrap(jshinted, { + wrapper: [ "if (!QUnit.urlParams.nojshint) {\n", "\n}"] + }); + return merge([jshinted, test]); +} + +// Moves the file to .ejs, compiles it, moves it back. +function versionStamp(tree, fileName){ + var ejsName = fileName + '.ejs'; + tree = moveFile(tree, { + srcFile: fileName, + destFile: '/' + ejsName + }); + tree = renderTemplate(tree, { + versionStamp: version + }); + return moveFile(tree, { + srcFile: ejsName.replace(/\.ejs$/, '.html'), + destFile: fileName + }); +} + +var emberDataFiles = moveFromLibAndMainJS('ember-data', false); +var activeModelAdapterFiles = moveFromLibAndMainJS('activemodel-adapter', false); +var emberInflectorFiles = moveFromLibAndMainJS('ember-inflector', true); +var loaderJS = pickFiles('bower_components/loader.js', { + srcDir: '/', + files: [ 'loader.js' ], + destDir: '/' +}); + +var yuidocTree = yuidoc('packages', { + srcDir: '/', + destDir: 'docs', + yuidoc: { + "name": "The ember-data API", + "description": "The ember-data API: a data persistence library for Ember.js", + "version": version, + "logo": "http://f.cl.ly/items/1A1L432s022u1O1q1V3p/ember%20logo.png", + "url": "https://github.com/emberjs/data", + "options": { + "paths": [ + "packages/ember-data/lib", + "packages/activemodel-adapter/lib", + "packages/ember-inflector/lib" + ], + "exclude": "vendor", + "outdir": "docs/build" + } + } +}); + +var libFiles = merge([emberInflectorFiles, emberDataFiles, activeModelAdapterFiles]); + +var testFiles = merge([ + testTree(emberDataFiles, 'ember-data'), + testTree(activeModelAdapterFiles, 'activemodel-adapter') +]); + +var namedAMDBuild = concat(libFiles, { + inputFiles: ['**/*.js'], + separator: '\n', + outputFile: '/ember-data.named-amd.js' +}); + +var globalBuild = concat(merge([libFiles, loaderJS]), { + inputFiles: ['loader.js', '**/*.js'], + separator: '\n', + outputFile: '/ember-data.js' +}); + +globalBuild = wrap(globalBuild, { + wrapper: [ "(function(global){\n", "\n global.DS = requireModule('ember-data')['default'];\n })(this);"] +}); + +globalBuild = versionStamp(globalBuild, 'ember-data.js'); +namedAMDBuild = versionStamp(namedAMDBuild, 'ember-data.named-amd.js'); + +testFiles = concat(testFiles, { + inputFiles: ['**/*.js'], + separator: '\n', + wrapInEval: true, + wrapInFunction: true, + outputFile: '/tests.js' +}); + +var testRunner = pickFiles('tests', { + srcDir: '/', + inputFiles: [ '**/*' ], + destDir: '/' +}); + +var bower = pickFiles('bower_components', { + srcDir: '/', + inputFiles: [ '**/*' ], + destDir: '/bower_components' +}); + +var trees = merge([testFiles, globalBuild, namedAMDBuild, yuidocTree, testRunner, bower]); + +if (env === 'production') { + var minifiedAMD = minify(namedAMDBuild, 'ember-data.named-amd'); + var minifiedGlobals = minify(globalBuild, 'ember-data'); + trees = merge([trees, minifiedAMD, minifiedGlobals]); +} + +module.exports = trees; \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 8a68bb98ea9..4dfaf7fcd48 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -25,7 +25,7 @@ module.exports = function(grunt){ 'copy:bower' ]); - grunt.registerTask('prepareTests', ['buildPackages', 'concat:tests']); + grunt.registerTask('prepareTests', []); grunt.registerTask('test:server', ['prepareTests', 'connect']); grunt.registerTask('test', ['test:server', 'qunit:local']); @@ -35,12 +35,9 @@ module.exports = function(grunt){ grunt.registerTask('test:canary', ['test:server', 'qunit:canary']); grunt.registerTask('test:all', ['test:server', 'qunit:local', 'qunit:release', 'qunit:beta', 'qunit:canary']); - grunt.registerTask('dev', [ 'test:server', 'watch' ]); grunt.registerTask('server', 'dev'); grunt.registerTask('dist', ['buildPackages', 'emberDefeatureify:stripDebug', 'uglify:dist']); grunt.registerTask('default', ['test']); - - grunt.registerTask('docs', ['yuidoc']); }; diff --git a/bower.json b/bower.json index 3d8e4951e6d..4953e768015 100644 --- a/bower.json +++ b/bower.json @@ -6,5 +6,9 @@ "qunit": "~1.13.0", "jquery": "~1.10.x", "handlebars": "~1.3.0" + }, + "devDependencies": { + "loader.js": "~1.0.0", + "ember-inflector": "git@github.com:stefanpenner/ember-inflector.git#9ddd559d848ea27143fccd0943af360795c1af3b" } } diff --git a/config/package_manager_files/package.json b/config/package_manager_files/package.json index 5112c9219d6..cddbc539fbc 100644 --- a/config/package_manager_files/package.json +++ b/config/package_manager_files/package.json @@ -1,12 +1,12 @@ { - name: "components-ember-data", - version: "VERSION_STRING_PLACEHOLDER", - description: "A data persistence library for Ember.js.", - keywords: [ + "name": "components-ember-data", + "version": "VERSION_STRING_PLACEHOLDER", + "description": "A data persistence library for Ember.js.", + "keywords": [ "ember" ], - main: "./ember-data.js", - dependencies: { - ember: "> 1.0.0" + "main": "./ember-data.js", + "dependencies": { + "ember": "> 1.0.0" } } diff --git a/config/testem-beta.json b/config/testem-beta.json new file mode 100644 index 00000000000..3a09f88dfb9 --- /dev/null +++ b/config/testem-beta.json @@ -0,0 +1,7 @@ +{ + "test_page": "tests/index.html?emberchannel=beta", + "serve_files": [ + "dist/**/*.js", + "tests/**/*" + ] +} \ No newline at end of file diff --git a/config/testem-canary.json b/config/testem-canary.json new file mode 100644 index 00000000000..619c1fb87f4 --- /dev/null +++ b/config/testem-canary.json @@ -0,0 +1,7 @@ +{ + "test_page": "tests/index.html?emberchannel=canary", + "serve_files": [ + "dist/**/*.js", + "tests/**/*" + ] +} \ No newline at end of file diff --git a/config/testem-stable.json b/config/testem-stable.json new file mode 100644 index 00000000000..835cb13e596 --- /dev/null +++ b/config/testem-stable.json @@ -0,0 +1,7 @@ +{ + "test_page": "tests/index.html?emberchannel=stable", + "serve_files": [ + "dist/**/*.js", + "tests/**/*" + ] +} \ No newline at end of file diff --git a/package.json b/package.json index 8edf879daa2..7b55c2dc5ff 100644 --- a/package.json +++ b/package.json @@ -12,12 +12,27 @@ "devDependencies": { "aws-sdk": "~2.0.0-rc8", "bower": "~1.2", + "broccoli": "^0.12.3", + "broccoli-concat": "0.0.7", + "broccoli-defeatureify": "^0.3.0", + "broccoli-env": "0.0.1", + "broccoli-es3-safe-recast": "0.0.8", + "broccoli-es6-module-transpiler": "^0.1.1", + "broccoli-es6-transpiler": "^0.1.0", + "broccoli-file-mover": "~0.2.0", + "broccoli-file-remover": "^0.2.2", + "broccoli-jshint": "^0.5.1", + "broccoli-merge-trees": "^0.1.4", + "broccoli-render-template": "0.0.3", + "broccoli-static-compiler": "^0.1.4", + "broccoli-uglify-js": "^0.1.3", + "broccoli-wrap": "0.0.2", + "broccoli-yuidoc": "^1.3.0", "defeatureify": "~0.1.4", + "ejs": "^1.0.0", "ember-publisher": "0.0.3", "grunt": "~0.4.2", "grunt-cli": "~0.1.13", - "grunt-contrib-clean": "~0.5.0", - "grunt-contrib-concat": "~0.3.0", "grunt-contrib-connect": "~0.6.0", "grunt-contrib-copy": "^0.5.0", "grunt-contrib-jshint": "~0.8.0", @@ -31,6 +46,7 @@ "load-grunt-tasks": "~0.2.1", "lockfile": "~0.4.2", "matchdep": "~0.3.0", + "testem-multi": "^0.4.2", "yuidocjs": "~0.3.46" } } diff --git a/packages/ember-inflector/lib/ext/string.js b/packages/ember-inflector/lib/ext/string.js deleted file mode 100644 index 735b6760863..00000000000 --- a/packages/ember-inflector/lib/ext/string.js +++ /dev/null @@ -1,23 +0,0 @@ -import {pluralize, singularize} from "../system/string"; - -if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { - /** - See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}} - - @method pluralize - @for String - */ - String.prototype.pluralize = function() { - return pluralize(this); - }; - - /** - See {{#crossLink "Ember.String/singularize"}}{{/crossLink}} - - @method singularize - @for String - */ - String.prototype.singularize = function() { - return singularize(this); - }; -} diff --git a/packages/ember-inflector/lib/main.js b/packages/ember-inflector/lib/main.js deleted file mode 100644 index f7c6900ec1f..00000000000 --- a/packages/ember-inflector/lib/main.js +++ /dev/null @@ -1,13 +0,0 @@ -import {Inflector, defaultRules, pluralize, singularize} from "./system"; - -Inflector.defaultRules = defaultRules; -Ember.Inflector = Inflector; - -Ember.String.pluralize = pluralize; -Ember.String.singularize = singularize; - -import "./ext/string"; - -export default Inflector; - -export {pluralize, singularize}; diff --git a/packages/ember-inflector/lib/system.js b/packages/ember-inflector/lib/system.js deleted file mode 100644 index e9cd300dd4c..00000000000 --- a/packages/ember-inflector/lib/system.js +++ /dev/null @@ -1,12 +0,0 @@ -import Inflector from "./system/inflector"; -import {pluralize, singularize} from "./system/string"; -import defaultRules from "./system/inflections"; - -Inflector.inflector = new Inflector(defaultRules); - -export { - Inflector, - singularize, - pluralize, - defaultRules -}; diff --git a/packages/ember-inflector/lib/system/inflections.js b/packages/ember-inflector/lib/system/inflections.js deleted file mode 100644 index 04096a7fcdc..00000000000 --- a/packages/ember-inflector/lib/system/inflections.js +++ /dev/null @@ -1,80 +0,0 @@ -var defaultRules = { - plurals: [ - [/$/, 's'], - [/s$/i, 's'], - [/^(ax|test)is$/i, '$1es'], - [/(octop|vir)us$/i, '$1i'], - [/(octop|vir)i$/i, '$1i'], - [/(alias|status)$/i, '$1es'], - [/(bu)s$/i, '$1ses'], - [/(buffal|tomat)o$/i, '$1oes'], - [/([ti])um$/i, '$1a'], - [/([ti])a$/i, '$1a'], - [/sis$/i, 'ses'], - [/(?:([^f])fe|([lr])f)$/i, '$1$2ves'], - [/(hive)$/i, '$1s'], - [/([^aeiouy]|qu)y$/i, '$1ies'], - [/(x|ch|ss|sh)$/i, '$1es'], - [/(matr|vert|ind)(?:ix|ex)$/i, '$1ices'], - [/^(m|l)ouse$/i, '$1ice'], - [/^(m|l)ice$/i, '$1ice'], - [/^(ox)$/i, '$1en'], - [/^(oxen)$/i, '$1'], - [/(quiz)$/i, '$1zes'] - ], - - singular: [ - [/s$/i, ''], - [/(ss)$/i, '$1'], - [/(n)ews$/i, '$1ews'], - [/([ti])a$/i, '$1um'], - [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '$1sis'], - [/(^analy)(sis|ses)$/i, '$1sis'], - [/([^f])ves$/i, '$1fe'], - [/(hive)s$/i, '$1'], - [/(tive)s$/i, '$1'], - [/([lr])ves$/i, '$1f'], - [/([^aeiouy]|qu)ies$/i, '$1y'], - [/(s)eries$/i, '$1eries'], - [/(m)ovies$/i, '$1ovie'], - [/(x|ch|ss|sh)es$/i, '$1'], - [/^(m|l)ice$/i, '$1ouse'], - [/(bus)(es)?$/i, '$1'], - [/(o)es$/i, '$1'], - [/(shoe)s$/i, '$1'], - [/(cris|test)(is|es)$/i, '$1is'], - [/^(a)x[ie]s$/i, '$1xis'], - [/(octop|vir)(us|i)$/i, '$1us'], - [/(alias|status)(es)?$/i, '$1'], - [/^(ox)en/i, '$1'], - [/(vert|ind)ices$/i, '$1ex'], - [/(matr)ices$/i, '$1ix'], - [/(quiz)zes$/i, '$1'], - [/(database)s$/i, '$1'] - ], - - irregularPairs: [ - ['person', 'people'], - ['man', 'men'], - ['child', 'children'], - ['sex', 'sexes'], - ['move', 'moves'], - ['cow', 'kine'], - ['zombie', 'zombies'] - ], - - uncountable: [ - 'equipment', - 'information', - 'rice', - 'money', - 'species', - 'series', - 'fish', - 'sheep', - 'jeans', - 'police' - ] -}; - -export default defaultRules; diff --git a/packages/ember-inflector/lib/system/inflector.js b/packages/ember-inflector/lib/system/inflector.js deleted file mode 100644 index 5d3ddf798d3..00000000000 --- a/packages/ember-inflector/lib/system/inflector.js +++ /dev/null @@ -1,199 +0,0 @@ -var BLANK_REGEX = /^\s*$/; - -function loadUncountable(rules, uncountable) { - for (var i = 0, length = uncountable.length; i < length; i++) { - rules.uncountable[uncountable[i].toLowerCase()] = true; - } -} - -function loadIrregular(rules, irregularPairs) { - var pair; - - for (var i = 0, length = irregularPairs.length; i < length; i++) { - pair = irregularPairs[i]; - - rules.irregular[pair[0].toLowerCase()] = pair[1]; - rules.irregularInverse[pair[1].toLowerCase()] = pair[0]; - } -} - -/** - Inflector.Ember provides a mechanism for supplying inflection rules for your - application. Ember includes a default set of inflection rules, and provides an - API for providing additional rules. - - Examples: - - Creating an inflector with no rules. - - ```js - var inflector = new Ember.Inflector(); - ``` - - Creating an inflector with the default ember ruleset. - - ```js - var inflector = new Ember.Inflector(Ember.Inflector.defaultRules); - - inflector.pluralize('cow'); //=> 'kine' - inflector.singularize('kine'); //=> 'cow' - ``` - - Creating an inflector and adding rules later. - - ```javascript - var inflector = Ember.Inflector.inflector; - - inflector.pluralize('advice'); // => 'advices' - inflector.uncountable('advice'); - inflector.pluralize('advice'); // => 'advice' - - inflector.pluralize('formula'); // => 'formulas' - inflector.irregular('formula', 'formulae'); - inflector.pluralize('formula'); // => 'formulae' - - // you would not need to add these as they are the default rules - inflector.plural(/$/, 's'); - inflector.singular(/s$/i, ''); - ``` - - Creating an inflector with a nondefault ruleset. - - ```javascript - var rules = { - plurals: [ /$/, 's' ], - singular: [ /\s$/, '' ], - irregularPairs: [ - [ 'cow', 'kine' ] - ], - uncountable: [ 'fish' ] - }; - - var inflector = new Ember.Inflector(rules); - ``` - - @class Inflector - @namespace Ember -*/ -function Inflector(ruleSet) { - ruleSet = ruleSet || {}; - ruleSet.uncountable = ruleSet.uncountable || {}; - ruleSet.irregularPairs = ruleSet.irregularPairs || {}; - - var rules = this.rules = { - plurals: ruleSet.plurals || [], - singular: ruleSet.singular || [], - irregular: {}, - irregularInverse: {}, - uncountable: {} - }; - - loadUncountable(rules, ruleSet.uncountable); - loadIrregular(rules, ruleSet.irregularPairs); -} - -Inflector.prototype = { - /** - @method plural - @param {RegExp} regex - @param {String} string - */ - plural: function(regex, string) { - this.rules.plurals.push([regex, string.toLowerCase()]); - }, - - /** - @method singular - @param {RegExp} regex - @param {String} string - */ - singular: function(regex, string) { - this.rules.singular.push([regex, string.toLowerCase()]); - }, - - /** - @method uncountable - @param {String} regex - */ - uncountable: function(string) { - loadUncountable(this.rules, [string.toLowerCase()]); - }, - - /** - @method irregular - @param {String} singular - @param {String} plural - */ - irregular: function (singular, plural) { - loadIrregular(this.rules, [[singular, plural]]); - }, - - /** - @method pluralize - @param {String} word - */ - pluralize: function(word) { - return this.inflect(word, this.rules.plurals, this.rules.irregular); - }, - - /** - @method singularize - @param {String} word - */ - singularize: function(word) { - return this.inflect(word, this.rules.singular, this.rules.irregularInverse); - }, - - /** - @protected - - @method inflect - @param {String} word - @param {Object} typeRules - @param {Object} irregular - */ - inflect: function(word, typeRules, irregular) { - var inflection, substitution, result, lowercase, isBlank, - isUncountable, isIrregular, isIrregularInverse, rule; - - isBlank = BLANK_REGEX.test(word); - - if (isBlank) { - return word; - } - - lowercase = word.toLowerCase(); - - isUncountable = this.rules.uncountable[lowercase]; - - if (isUncountable) { - return word; - } - - isIrregular = irregular && irregular[lowercase]; - - if (isIrregular) { - return isIrregular; - } - - for (var i = typeRules.length, min = 0; i > min; i--) { - inflection = typeRules[i-1]; - rule = inflection[0]; - - if (rule.test(word)) { - break; - } - } - - inflection = inflection || []; - - rule = inflection[0]; - substitution = inflection[1]; - - result = word.replace(rule, substitution); - - return result; - } -}; - -export default Inflector; diff --git a/packages/ember-inflector/lib/system/string.js b/packages/ember-inflector/lib/system/string.js deleted file mode 100644 index 0d4324ebbff..00000000000 --- a/packages/ember-inflector/lib/system/string.js +++ /dev/null @@ -1,10 +0,0 @@ -import Inflector from "./inflector"; -var pluralize = function(word) { - return Inflector.inflector.pluralize(word); -}; - -var singularize = function(word) { - return Inflector.inflector.singularize(word); -}; - -export {pluralize, singularize}; diff --git a/packages/ember-inflector/package.json b/packages/ember-inflector/package.json deleted file mode 100644 index a2c30156bc9..00000000000 --- a/packages/ember-inflector/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "ember-inflector", - "summary": "Ember Inflections", - "descrption": "", - "homepage": "http://github.com/emberjs/ember.js", - "author": ["Stefan Penner"], - "version": "1.0.0-beta.1", - - "directories":{ - "lib": "lib" - }, - - "dependencies": { - "ember-runtime": "1.0.0" - }, - - "bpm:build": { - "bpm_lib.js": { - "files": ["lib"], - "modes": "*" - } - } -} diff --git a/packages/ember-inflector/tests/system/inflector_test.js b/packages/ember-inflector/tests/system/inflector_test.js deleted file mode 100644 index e3e4f092dac..00000000000 --- a/packages/ember-inflector/tests/system/inflector_test.js +++ /dev/null @@ -1,264 +0,0 @@ -var inflector; -module('ember-inflector.dsl', { - setup: function() { - inflector = new Ember.Inflector(/* no rulest == no rules */); - }, - teardown: function() { - inflector = undefined; - } -}); - -test('ability to add additional pluralization rules', function(){ - equal(inflector.pluralize('cow'), 'cow', 'no pluralization rule'); - - inflector.plural(/$/, 's'); - - equal(inflector.pluralize('cow'), 'cows', 'pluralization rule was applied'); -}); - -test('ability to add additional singularization rules', function(){ - equal(inflector.singularize('cows'), 'cows', 'no singularization rule was applied'); - - inflector.singular(/s$/, ''); - - equal(inflector.singularize('cows'), 'cow', 'singularization rule was applied'); -}); - -test('ability to add additional uncountable rules', function(){ - inflector.plural(/$/, 's'); - equal(inflector.pluralize('cow'), 'cows', 'pluralization rule was applied'); - - inflector.uncountable('cow'); - equal(inflector.pluralize('cow'), 'cow', 'pluralization rule NOT was applied'); -}); - -test('ability to add additional irregular rules', function(){ - inflector.singular(/s$/, ''); - inflector.plural(/$/, 's'); - - equal(inflector.singularize('cows'), 'cow', 'regular singularization rule was applied'); - equal(inflector.pluralize('cow'), 'cows', 'regular pluralization rule was applied'); - - inflector.irregular('cow', 'kine'); - - equal(inflector.singularize('kine'), 'cow', 'irregular singularization rule was applied'); - equal(inflector.pluralize('cow'), 'kine', 'irregular pluralization rule was applied'); -}); - -test('ability to add identical singular and pluralizations',function(){ - - inflector.singular(/s$/, ''); - inflector.plural(/$/, 's'); - - equal(inflector.singularize('settings'),'setting','regular singularization rule was applied'); - equal(inflector.pluralize('setting'),'settings','regular pluralization rule was applied'); - - inflector.irregular('settings','settings'); - inflector.irregular('userPreferences','userPreferences'); - - equal(inflector.singularize('settings'),'settings','irregular singularization rule was applied on lowercase word'); - equal(inflector.pluralize('settings'),'settings','irregular pluralization rule was applied on lowercase word'); - - equal(inflector.singularize('userPreferences'),'userPreferences','irregular singularization rule was applied on camelcase word'); - equal(inflector.pluralize('userPreferences'),'userPreferences','irregular pluralization rule was applied on camelcase word'); -}); - -module('ember-inflector.unit'); - -test('plurals', function() { - expect(1); - - var inflector = new Ember.Inflector({ - plurals: [ - [/$/, 's'], - [/s$/i, 's'] - ] - }); - - equal(inflector.pluralize('apple'), 'apples'); -}); - -test('singularization',function(){ - expect(1); - - var inflector = new Ember.Inflector({ - singular: [ - [/s$/i, ''], - [/(ss)$/i, '$1'] - ] - }); - - equal(inflector.singularize('apple'), 'apple'); -}); - -test('singularization of irregulars', function(){ - expect(1); - - var inflector = new Ember.Inflector({ - irregularPairs: [ - ['person', 'people'] - ] - }); - - equal(inflector.singularize('person'), 'person'); -}); - -test('plural',function(){ - expect(1); - - var inflector = new Ember.Inflector({ - plurals: [ - ['1', '1'], - ['2', '2'], - ['3', '3'] - ] - }); - - equal(inflector.rules.plurals.length, 3); -}); - -test('singular',function(){ - expect(1); - - var inflector = new Ember.Inflector({ - singular: [ - ['1', '1'], - ['2', '2'], - ['3', '3'] - ] - }); - - equal(inflector.rules.singular.length, 3); -}); - -test('irregular',function(){ - expect(6); - - var inflector = new Ember.Inflector({ - irregularPairs: [ - ['1', '12'], - ['2', '22'], - ['3', '32'] - ] - }); - - equal(inflector.rules.irregular['1'], '12'); - equal(inflector.rules.irregular['2'], '22'); - equal(inflector.rules.irregular['3'], '32'); - - equal(inflector.rules.irregularInverse['12'], '1'); - equal(inflector.rules.irregularInverse['22'], '2'); - equal(inflector.rules.irregularInverse['32'], '3'); -}); - -test('uncountable',function(){ - expect(3); - - var inflector = new Ember.Inflector({ - uncountable: [ - '1', - '2', - '3' - ] - }); - - equal(inflector.rules.uncountable['1'], true); - equal(inflector.rules.uncountable['2'], true); - equal(inflector.rules.uncountable['3'], true); -}); - -test('inflect.nothing', function(){ - expect(2); - - var inflector = new Ember.Inflector(); - - equal(inflector.inflect('', []), ''); - equal(inflector.inflect(' ', []), ' '); -}); - -test('inflect.noRules',function(){ - expect(1); - - var inflector = new Ember.Inflector(); - - equal(inflector.inflect('word', []),'word'); -}); - -test('inflect.uncountable', function(){ - expect(1); - - var inflector = new Ember.Inflector({ - plural: [ - [/$/,'s'] - ], - uncountable: [ - 'word' - ] - }); - - var rules = []; - - equal(inflector.inflect('word', rules), 'word'); -}); - -test('inflect.irregular', function(){ - expect(2); - - var inflector = new Ember.Inflector({ - irregularPairs: [ - ['word', 'wordy'] - ] - }); - - var rules = []; - - equal(inflector.inflect('word', rules, inflector.rules.irregular), 'wordy'); - equal(inflector.inflect('wordy', rules, inflector.rules.irregularInverse), 'word'); -}); - -test('inflect.basicRules', function(){ - expect(1); - - var inflector = new Ember.Inflector(); - var rules = [[/$/, 's']]; - - equal(inflector.inflect('word', rules ), 'words'); -}); - -test('inflect.advancedRules', function(){ - expect(1); - - var inflector = new Ember.Inflector(); - var rules = [[/^(ox)$/i, '$1en']]; - - equal(inflector.inflect('ox', rules), 'oxen'); -}); - -test('Inflector.defaultRules', function(){ - expect(1); - - var rules = Ember.Inflector.defaultRules; - ok(rules, 'has defaultRules'); -}); - -test('Ember.Inflector.inflector exists', function(){ - expect(1); - - ok(Ember.Inflector.inflector, 'Ember.Inflector.inflector exists'); -}); - -test('new Ember.Inflector with defaultRules matches docs', function(){ - expect(4); - - var inflector = new Ember.Inflector(Ember.Inflector.defaultRules); - - // defaultRules includes these special rules - equal(inflector.pluralize('cow'), 'kine'); - equal(inflector.singularize('kine'), 'cow'); - - // defaultRules adds 's' to singular - equal(inflector.pluralize('item'), 'items'); - - // defaultRules removes 's' from plural - equal(inflector.singularize('items'), 'item'); -}); diff --git a/packages/ember-inflector/tests/system/integration_test.js b/packages/ember-inflector/tests/system/integration_test.js deleted file mode 100644 index 9a9e3b59c26..00000000000 --- a/packages/ember-inflector/tests/system/integration_test.js +++ /dev/null @@ -1,17 +0,0 @@ -module("ember-inflector.integration"); - -test("pluralize", function(){ - expect(3); - - equal(Ember.String.pluralize('word'), 'words'); - equal(Ember.String.pluralize('ox'), 'oxen'); - equal(Ember.String.pluralize('octopus'), 'octopi'); -}); - -test("singularize", function(){ - expect(3); - - equal(Ember.String.singularize('words'), 'word'); - equal(Ember.String.singularize('oxen'), 'ox'); - equal(Ember.String.singularize('octopi'), 'octopus'); -}); diff --git a/tasks/browser.js b/tasks/browser.js deleted file mode 100644 index c9dae679f94..00000000000 --- a/tasks/browser.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = function(grunt) { - grunt.registerMultiTask('browser', 'Export the object in <%= pkg.name %> to Ember.lookup', function() { - this.files.forEach(function(f) { - var output = ['(function(global) {']; - output.push.apply(output, f.src.map(grunt.file.read)); - output.push("global.<%= pkg.namespace %> = requireModule('<%= pkg.name %>/lib/main')['default'];"); - output.push('}(Ember.lookup));'); - var banner = grunt.template.process(grunt.file.read(__dirname + "/../generators/license.js")); - grunt.file.write(f.dest, banner + grunt.template.process(output.join('\n'))); - }); - }); -}; diff --git a/tasks/lock.js b/tasks/lock.js deleted file mode 100644 index 5b7547e8ac6..00000000000 --- a/tasks/lock.js +++ /dev/null @@ -1,11 +0,0 @@ -var lockFile = require('lockfile'); -var grunt = require('grunt'); -var LOCKFILE = __dirname + "/../tmp/connect.lock"; - -grunt.registerTask('lock', function(){ - lockFile.lockSync(LOCKFILE); -}); - -grunt.registerTask('unlock', function(){ - lockFile.unlockSync(LOCKFILE); -}); diff --git a/tasks/options/browser.js b/tasks/options/browser.js deleted file mode 100644 index 30f532233db..00000000000 --- a/tasks/options/browser.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - dist: { - src: 'tmp/ember-data.browser1.js', - dest: 'dist/ember-data.js' - } -}; diff --git a/tasks/options/clean.js b/tasks/options/clean.js index 0f18cb2aa0e..57a8e0e56ef 100644 --- a/tasks/options/clean.js +++ b/tasks/options/clean.js @@ -1,3 +1,3 @@ module.exports = { - main: [ 'tmp/!connect.lock' ] + main: [ 'dist' ] }; diff --git a/tasks/options/concat.js b/tasks/options/concat.js deleted file mode 100644 index 8775371205a..00000000000 --- a/tasks/options/concat.js +++ /dev/null @@ -1,22 +0,0 @@ -var grunt = require('grunt'); - -module.exports = { - amd: { - src: [ 'tmp/**/*.amd.js' ], - dest: 'tmp/ember-data.amd.js' - }, - globals: { - src: [ 'vendor/loader.js', 'tmp/**/*.amd.js' ], - dest: 'tmp/ember-data.browser1.js' - }, - tests: { - src: [ 'packages/**/tests/**/*.js' ], - dest: 'tmp/tests.js', - options: { - separator: ';\n', - process: function(src, filepath){ - return "(function(){\n" + src + "\n})();"; - } - } - } -}; diff --git a/tasks/options/connect.js b/tasks/options/connect.js deleted file mode 100644 index f6e95757f25..00000000000 --- a/tasks/options/connect.js +++ /dev/null @@ -1,25 +0,0 @@ -var lockFile = require('lockfile'); -var lockMiddleware = function(req, res, next) { - if (!lockFile.checkSync(__dirname + '/../../tmp/connect.lock')) { - return next(); - } else { - setTimeout(function(){ - lockMiddleware(req, res, next); - }, 10); - } -}; - - -var port = process.env.PORT || '9997'; -module.exports = { - main: { - options: { - port: port, - base: '.', - middleware: function(connect, options){ - var base = options.base; - return [ lockMiddleware, connect.static(base), connect.directory(base) ]; - } - } - } -}; diff --git a/tasks/options/emberDefeatureify.js b/tasks/options/emberDefeatureify.js deleted file mode 100644 index 8fbdfd33c8b..00000000000 --- a/tasks/options/emberDefeatureify.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - options: { - debugStatements: [ - "Ember.warn", - "Ember.assert", - "Ember.deprecate", - "Ember.debug", - "Ember.Logger.info" - ] - }, - stripDebug: { - options: { - enableStripDebug: true - }, - src: 'dist/ember-data.js', - dest: 'dist/ember-data.prod.js' - } -}; diff --git a/tasks/options/jshint.js b/tasks/options/jshint.js deleted file mode 100644 index 1a2e11778e1..00000000000 --- a/tasks/options/jshint.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - options: { - jshintrc: ".jshintrc", - force: true - }, - src: [ 'dist/ember-data.js' ] -}; diff --git a/tasks/options/qunit.js b/tasks/options/qunit.js deleted file mode 100644 index 4aa56c5b1c2..00000000000 --- a/tasks/options/qunit.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = { - local: { - options: { - urls: [ 'http://localhost:9997/tests/index.html' ] - } - }, - release: { - options: { - urls: [ 'http://localhost:9997/tests/index.html?emberchannel=release' ] - } - }, - beta: { - options: { - urls: [ 'http://localhost:9997/tests/index.html?emberchannel=beta' ] - } - }, - canary: { - options: { - urls: [ 'http://localhost:9997/tests/index.html?emberchannel=canary' ] - } - } -}; diff --git a/tasks/options/transpile.js b/tasks/options/transpile.js deleted file mode 100644 index 28dc770dc66..00000000000 --- a/tasks/options/transpile.js +++ /dev/null @@ -1,25 +0,0 @@ - -function nameFor(path) { - var result, match; - if (match = path.match(/^(?:lib|test|test\/tests)\/(.*?)(?:\.js)?$/)) { - result = match[1]; - } else { - result = path; - } - - return path; -} - -module.exports = { - amd: { - type: 'amd', - moduleName: nameFor, - files: [{ - expand: true, - cwd: 'packages/', - src: [ '**/lib/**/*.js', ], - dest: 'tmp', - ext: '.amd.js' - }] - } -}; diff --git a/tasks/options/uglify.js b/tasks/options/uglify.js deleted file mode 100644 index 6886bbd0ae0..00000000000 --- a/tasks/options/uglify.js +++ /dev/null @@ -1,22 +0,0 @@ -var grunt = require('grunt'); -module.exports = { - options: { - report: 'min', - banner: grunt.file.read('generators/license.js'), - }, - dist: { - files: [{ - src: 'dist/ember-data.prod.js', - dest: 'dist/ember-data.min.js', - }] - }, - report: { - options:{ - report: 'gzip' - }, - files: [{ - src: 'dist/ember-data.prod.js', - dest: 'dist/ember-data.min.js', - }] - }, -}; diff --git a/tasks/options/watch.js b/tasks/options/watch.js deleted file mode 100644 index ce21c345502..00000000000 --- a/tasks/options/watch.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - - packages: { - files: [ 'packages/**/*.js', '!packages/**/test/**/*.js'], - tasks: [ 'lock', 'buildPackages', 'prepareTests', 'unlock', 'qunit:local' ] - }, - - tests: { - files: [ 'packages/**/test/**/*.js' ], - tasks: [ 'lock', 'prepareTests', 'unlock', 'qunit:local' ] - } -}; diff --git a/testem.json b/testem.json new file mode 100644 index 00000000000..7412750afab --- /dev/null +++ b/testem.json @@ -0,0 +1,7 @@ +{ + "test_page": "tests/index.html", + "serve_files": [ + "dist/**/*.js", + "tests/**/*" + ] +} \ No newline at end of file From 831a4b1c22cbb672129396a4d0ad8ea19b578766 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 26 Jul 2014 15:58:48 -0500 Subject: [PATCH 0257/2527] remove testem-multi --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 58592aa3a37..3a003c3026e 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,6 @@ "load-grunt-tasks": "~0.2.1", "lockfile": "~0.4.2", "matchdep": "~0.3.0", - "testem-multi": "^0.4.2", "yuidocjs": "~0.3.46" } } From f531ce4acbcdde960cd14eead15d8f78c38c0189 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 26 Jul 2014 16:10:03 -0500 Subject: [PATCH 0258/2527] update test commands --- .travis.yml | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ab34679e253..b65d4b3a640 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,11 @@ node_js: install: - "bin/cached-npm install" - "bower install" +script: + - testem + - testem -f config/testem-beta.json + - testem -f config/testem-canary.json + - testem -f config/testem-stable.json after_success: - npm run-script publish-build - "./bin/bower-ember-data-build" diff --git a/package.json b/package.json index 3a003c3026e..c87ad0aece4 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "license": "MIT", "scripts": { "postinstall": "bower install", - "test": "grunt test:all", + "test": "rm -rf dist && broccoli build dist && testem ci", "publish-build": "grunt dist && ./bin/publish_to_s3.js" }, "devDependencies": { From 431e2704ad312b3853c8b90a7e635a0ca9534343 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 26 Jul 2014 17:09:49 -0500 Subject: [PATCH 0259/2527] configuration tweaks for broccoli --- .travis.yml | 2 ++ Brocfile.js | 22 +++++++++++-- Gruntfile.js | 43 ------------------------- config/package_manager_files/bower.json | 8 ++++- config/testem-beta.json | 13 ++++++-- config/testem-canary.json | 10 ++++-- config/testem-stable.json | 10 ++++-- package.json | 19 ++--------- tasks/options/clean.js | 3 -- tasks/options/copy.js | 11 ------- tasks/options/yuidoc.js | 18 ----------- testem.json | 8 +++-- tests/index.html | 10 +++--- 13 files changed, 67 insertions(+), 110 deletions(-) delete mode 100644 Gruntfile.js delete mode 100644 tasks/options/clean.js delete mode 100644 tasks/options/copy.js delete mode 100644 tasks/options/yuidoc.js diff --git a/.travis.yml b/.travis.yml index b65d4b3a640..3a46fadaf83 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ node_js: install: - "bin/cached-npm install" - "bower install" +- "broccoli build dist" script: - testem - testem -f config/testem-beta.json @@ -15,6 +16,7 @@ after_success: - "./bin/bower-ember-data-build" env: global: + - BROCCOLI_ENV="production" - S3_BUILD_CACHE_BUCKET=emberjs-build-cache - S3_BUCKET_NAME=builds.emberjs.com - secure: ! 'S+DIdzEPvqQenk1cFq5UjbkoEKDY4j3E/g+Wlz798xxyTkrKQZxoazLXng8I diff --git a/Brocfile.js b/Brocfile.js index 8d6512e4f74..c314cffcee3 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -13,6 +13,7 @@ var defeatureify = require('broccoli-defeatureify'); var version = require('./lib/utilities/ember-data-version')(); var renderTemplate = require('broccoli-render-template'); var yuidoc = require('broccoli-yuidoc'); +var replace = require('broccoli-string-replace'); function moveFromLibAndMainJS(packageName, vendored){ var root = vendored ? 'bower_components/' + packageName + "/packages/" + packageName + '/lib': @@ -27,6 +28,9 @@ function moveFromLibAndMainJS(packageName, vendored){ destFile: '/' + packageName + '.js' }); tree = es6(tree, {moduleName: true}); + if (env === 'production'){ + tree = es3SafeRecast(tree); + } return tree; } @@ -152,7 +156,21 @@ var bower = pickFiles('bower_components', { destDir: '/bower_components' }); -var trees = merge([testFiles, globalBuild, namedAMDBuild, yuidocTree, testRunner, bower]); +var configurationFiles = pickFiles('config/package_manager_files', { + srcDir: '/', + destDir: '/', + inputFiles: [ '**/*' ] +}); + +configurationFiles = replace(configurationFiles, { + files: [ '**/*' ], + pattern: { + match: /VERSION_STRING_PLACEHOLDER/g, + replacement: version + } +}); + +var trees = merge([testFiles, globalBuild, namedAMDBuild, yuidocTree, testRunner, bower, configurationFiles]); if (env === 'production') { var minifiedAMD = minify(namedAMDBuild, 'ember-data.named-amd'); @@ -160,4 +178,4 @@ if (env === 'production') { trees = merge([trees, minifiedAMD, minifiedGlobals]); } -module.exports = trees; \ No newline at end of file +module.exports = trees; diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index 4dfaf7fcd48..00000000000 --- a/Gruntfile.js +++ /dev/null @@ -1,43 +0,0 @@ -var matchdep = require('matchdep'); -var emberDataVersion = require('./lib/utilities/ember-data-version'); -module.exports = function(grunt){ - - matchdep.filterDev('grunt-*').forEach(grunt.loadNpmTasks); - grunt.loadTasks('tasks'); - var config = require('load-grunt-config')(grunt, { - configPath: __dirname + '/tasks/options', - init: false - }); - - config.pkg = require('./package'); - config.env = process.env; - - grunt.initConfig(config); - - grunt.config('versionStamp', emberDataVersion()); - - grunt.registerTask('buildPackages', [ - 'clean', - 'transpile:amd', - 'concat:globals', - 'browser:dist', - 'jshint', - 'copy:bower' - ]); - - grunt.registerTask('prepareTests', []); - - grunt.registerTask('test:server', ['prepareTests', 'connect']); - grunt.registerTask('test', ['test:server', 'qunit:local']); - grunt.registerTask('test:local', 'test'); - grunt.registerTask('test:release', ['test:server', 'qunit:release']); - grunt.registerTask('test:beta', ['test:server', 'qunit:beta']); - grunt.registerTask('test:canary', ['test:server', 'qunit:canary']); - grunt.registerTask('test:all', ['test:server', 'qunit:local', 'qunit:release', 'qunit:beta', 'qunit:canary']); - - grunt.registerTask('dev', [ 'test:server', 'watch' ]); - grunt.registerTask('server', 'dev'); - - grunt.registerTask('dist', ['buildPackages', 'emberDefeatureify:stripDebug', 'uglify:dist']); - grunt.registerTask('default', ['test']); -}; diff --git a/config/package_manager_files/bower.json b/config/package_manager_files/bower.json index 620bbc12b21..f8e2930c85c 100644 --- a/config/package_manager_files/bower.json +++ b/config/package_manager_files/bower.json @@ -4,5 +4,11 @@ "main": "ember-data.js", "dependencies": { "ember": ">= 1.0.0" - } + }, + "ignore": [ + "**/*_configuration.js", + "ember-data-setup.js", + "docs", + "**/*.html" + ] } diff --git a/config/testem-beta.json b/config/testem-beta.json index 3a09f88dfb9..5c5232a3b65 100644 --- a/config/testem-beta.json +++ b/config/testem-beta.json @@ -1,7 +1,14 @@ { - "test_page": "tests/index.html?emberchannel=beta", + "test_page": "tests/index.html?emberchannel=beta&nojshint=true", "serve_files": [ "dist/**/*.js", "tests/**/*" - ] -} \ No newline at end of file + ], + "launch_in_ci": [ + "PhantomJS" + ], + "routes": { + "/ember-data.js": "dist/ember-data.js", + "/tests/tests.js": "dist/tests.js" + } +} diff --git a/config/testem-canary.json b/config/testem-canary.json index 619c1fb87f4..fe39ae668f2 100644 --- a/config/testem-canary.json +++ b/config/testem-canary.json @@ -1,7 +1,11 @@ { - "test_page": "tests/index.html?emberchannel=canary", + "test_page": "tests/index.html?emberchannel=canary&nojshint=true", "serve_files": [ "dist/**/*.js", "tests/**/*" - ] -} \ No newline at end of file + ], + "routes": { + "/ember-data.js": "dist/ember-data.js", + "/tests/tests.js": "dist/tests.js" + } +} diff --git a/config/testem-stable.json b/config/testem-stable.json index 835cb13e596..2d36917b938 100644 --- a/config/testem-stable.json +++ b/config/testem-stable.json @@ -1,7 +1,11 @@ { - "test_page": "tests/index.html?emberchannel=stable", + "test_page": "tests/index.html?emberchannel=stable&nojshint=true", "serve_files": [ "dist/**/*.js", "tests/**/*" - ] -} \ No newline at end of file + ], + "routes": { + "/ember-data.js": "dist/ember-data.js", + "/tests/tests.js": "dist/tests.js" + } +} diff --git a/package.json b/package.json index c87ad0aece4..c8884e8737d 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,9 @@ "license": "MIT", "scripts": { "postinstall": "bower install", + "start": "broccoli serve", "test": "rm -rf dist && broccoli build dist && testem ci", - "publish-build": "grunt dist && ./bin/publish_to_s3.js" + "publish-build": "rm -rf dist && broccoli build dist && ./bin/publish_to_s3.js" }, "devDependencies": { "aws-sdk": "~2.0.0-rc8", @@ -25,27 +26,13 @@ "broccoli-merge-trees": "^0.1.4", "broccoli-render-template": "0.0.3", "broccoli-static-compiler": "^0.1.4", + "broccoli-string-replace": "0.0.2", "broccoli-uglify-js": "^0.1.3", "broccoli-wrap": "0.0.2", "broccoli-yuidoc": "^1.3.0", "defeatureify": "~0.1.4", "ejs": "^1.0.0", "ember-publisher": "0.0.3", - "grunt": "~0.4.2", - "grunt-cli": "~0.1.13", - "grunt-contrib-connect": "~0.6.0", - "grunt-contrib-copy": "^0.5.0", - "grunt-contrib-jshint": "~0.8.0", - "grunt-contrib-qunit": "~0.3.0", - "grunt-contrib-uglify": "~0.3.0", - "grunt-contrib-watch": "~0.5.3", - "grunt-contrib-yuidoc": "~0.5.0", - "grunt-ember-defeatureify": "~0.1.0", - "grunt-es6-module-transpiler": "~0.6.0", - "load-grunt-config": "~0.7.0", - "load-grunt-tasks": "~0.2.1", - "lockfile": "~0.4.2", - "matchdep": "~0.3.0", "yuidocjs": "~0.3.46" } } diff --git a/tasks/options/clean.js b/tasks/options/clean.js deleted file mode 100644 index 57a8e0e56ef..00000000000 --- a/tasks/options/clean.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - main: [ 'dist' ] -}; diff --git a/tasks/options/copy.js b/tasks/options/copy.js deleted file mode 100644 index ea73e3c9d87..00000000000 --- a/tasks/options/copy.js +++ /dev/null @@ -1,11 +0,0 @@ -var emberDataVersion = require('../../lib/utilities/ember-data-version.js'); -module.exports = { - bower: { - src: 'config/package_manager_files/*', dest: 'dist/', flatten: true, expand: true, - options: { - process: function (content, srcpath) { - return content.replace(/VERSION_STRING_PLACEHOLDER/g, emberDataVersion()); - } - } - } -}; diff --git a/tasks/options/yuidoc.js b/tasks/options/yuidoc.js deleted file mode 100644 index 9a7b17a2259..00000000000 --- a/tasks/options/yuidoc.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - compile: { - "name": "The ember-data API", - "description": "The ember-data API: a data persistence library for Ember.js", - "version": '<%= versionStamp %>', - "logo": "http://f.cl.ly/items/1A1L432s022u1O1q1V3p/ember%20logo.png", - "url": "https://github.com/emberjs/data", - "options": { - "paths": [ - "packages/ember-data/lib", - "packages/activemodel-adapter/lib", - "packages/ember-inflector/lib" - ], - "exclude": "vendor", - "outdir": "docs/build" - } - } -} diff --git a/testem.json b/testem.json index 7412750afab..830eadffd11 100644 --- a/testem.json +++ b/testem.json @@ -3,5 +3,9 @@ "serve_files": [ "dist/**/*.js", "tests/**/*" - ] -} \ No newline at end of file + ], + "routes": { + "/ember-data.js": "dist/ember-data.js", + "/tests/tests.js": "dist/tests.js" + } +} diff --git a/tests/index.html b/tests/index.html index 0a0bf0d6d70..a9890e4f9df 100644 --- a/tests/index.html +++ b/tests/index.html @@ -6,7 +6,7 @@ - + - + - - - + + +
      From 130981438afb25305aa112c0ab8cec77fdf92954 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 26 Jul 2014 17:17:17 -0500 Subject: [PATCH 0260/2527] make ember-inflector publicly installable --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 4953e768015..4a0c057db72 100644 --- a/bower.json +++ b/bower.json @@ -9,6 +9,6 @@ }, "devDependencies": { "loader.js": "~1.0.0", - "ember-inflector": "git@github.com:stefanpenner/ember-inflector.git#9ddd559d848ea27143fccd0943af360795c1af3b" + "ember-inflector": "https://github.com/stefanpenner/ember-inflector.git#4cab0648fc828dc050ec9ee50fec1f8064ff9974" } } From 023dd5513a288109ddaeb461d293933b2ead5f9a Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 26 Jul 2014 17:25:50 -0500 Subject: [PATCH 0261/2527] use package.json for broccoli commands --- .travis.yml | 2 +- package.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3a46fadaf83..a490eaa3a54 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ node_js: install: - "bin/cached-npm install" - "bower install" -- "broccoli build dist" +- "npm run-script build" script: - testem - testem -f config/testem-beta.json diff --git a/package.json b/package.json index c8884e8737d..ab549881cc9 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "scripts": { "postinstall": "bower install", "start": "broccoli serve", - "test": "rm -rf dist && broccoli build dist && testem ci", + "build": "rm -rf dist && broccoli build dist", + "test": "testem ci", "publish-build": "rm -rf dist && broccoli build dist && ./bin/publish_to_s3.js" }, "devDependencies": { From a6e6a808ae9eb78eb0d52984a4ef047ec6dad6a1 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 26 Jul 2014 17:28:49 -0500 Subject: [PATCH 0262/2527] apparently build is a thing already in package.json --- .travis.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a490eaa3a54..d97d1ad47b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ node_js: install: - "bin/cached-npm install" - "bower install" -- "npm run-script build" +- "npm run-script dist" script: - testem - testem -f config/testem-beta.json diff --git a/package.json b/package.json index ab549881cc9..85f2813de94 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "scripts": { "postinstall": "bower install", "start": "broccoli serve", - "build": "rm -rf dist && broccoli build dist", + "dist": "rm -rf dist && broccoli build dist", "test": "testem ci", "publish-build": "rm -rf dist && broccoli build dist && ./bin/publish_to_s3.js" }, From 8483684bcd02084a76ad21cf8e7fea5bac03592c Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 26 Jul 2014 17:32:18 -0500 Subject: [PATCH 0263/2527] broccoli-cli needed for travis --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 85f2813de94..77f9d2edc9f 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "aws-sdk": "~2.0.0-rc8", "bower": "~1.3", "broccoli": "^0.12.3", + "broccoli-cli": "0.0.1", "broccoli-concat": "0.0.7", "broccoli-defeatureify": "^0.3.0", "broccoli-env": "0.0.1", From 6263b3dcd3219191105885693b0e7de94c883ffb Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 26 Jul 2014 17:38:06 -0500 Subject: [PATCH 0264/2527] add ember-defeatureify options back in --- Brocfile.js | 2 +- config/ember-defeatureify.js | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 config/ember-defeatureify.js diff --git a/Brocfile.js b/Brocfile.js index c314cffcee3..4dfd23cf516 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -35,7 +35,7 @@ function moveFromLibAndMainJS(packageName, vendored){ } function minify(tree, name){ - var config = require('./tasks/options/emberDefeatureify'); + var config = require('./config/ember-defeatureify'); tree = defeatureify(tree, { debugStatements: config.options.debugStatements, enableStripDebug: config.stripDebug diff --git a/config/ember-defeatureify.js b/config/ember-defeatureify.js new file mode 100644 index 00000000000..63e7b5a86d1 --- /dev/null +++ b/config/ember-defeatureify.js @@ -0,0 +1,18 @@ +module.exports = { + options: { + debugStatements: [ + "Ember.warn", + "Ember.assert", + "Ember.deprecate", + "Ember.debug", + "Ember.Logger.info" + ] + }, + stripDebug: { + options: { + enableStripDebug: true + }, + src: 'dist/ember-data.js', + dest: 'dist/ember-data.prod.js' + } +}; \ No newline at end of file From 9421036d2ed162cc8107dd838cda87142caeb686 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 26 Jul 2014 17:47:09 -0500 Subject: [PATCH 0265/2527] update testem to run from package.json --- .travis.yml | 8 ++++---- config/testem-canary.json | 3 +++ config/testem-stable.json | 3 +++ package.json | 7 ++++++- testem.json | 5 ++++- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index d97d1ad47b4..417f5b3c526 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,10 @@ install: - "bower install" - "npm run-script dist" script: - - testem - - testem -f config/testem-beta.json - - testem -f config/testem-canary.json - - testem -f config/testem-stable.json + - npm run-script testem-local + - npm run-script testem-beta + - npm run-script testem-stable + - npm run-script testem-canary after_success: - npm run-script publish-build - "./bin/bower-ember-data-build" diff --git a/config/testem-canary.json b/config/testem-canary.json index fe39ae668f2..1fe5ad2d3fb 100644 --- a/config/testem-canary.json +++ b/config/testem-canary.json @@ -4,6 +4,9 @@ "dist/**/*.js", "tests/**/*" ], + "launch_in_ci": [ + "PhantomJS" + ], "routes": { "/ember-data.js": "dist/ember-data.js", "/tests/tests.js": "dist/tests.js" diff --git a/config/testem-stable.json b/config/testem-stable.json index 2d36917b938..ba21d9f305f 100644 --- a/config/testem-stable.json +++ b/config/testem-stable.json @@ -4,6 +4,9 @@ "dist/**/*.js", "tests/**/*" ], + "launch_in_ci": [ + "PhantomJS" + ], "routes": { "/ember-data.js": "dist/ember-data.js", "/tests/tests.js": "dist/tests.js" diff --git a/package.json b/package.json index 77f9d2edc9f..cef5b7a7ae0 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,11 @@ "start": "broccoli serve", "dist": "rm -rf dist && broccoli build dist", "test": "testem ci", - "publish-build": "rm -rf dist && broccoli build dist && ./bin/publish_to_s3.js" + "publish-build": "rm -rf dist && broccoli build dist && ./bin/publish_to_s3.js", + "testem-local": "testem ci", + "testem-beta": "testem -f config/testem-beta.json ci", + "testem-canary": "testem -f config/testem-canary.json ci", + "testem-stable": "testem -f config/testem-stable.json ci" }, "devDependencies": { "aws-sdk": "~2.0.0-rc8", @@ -35,6 +39,7 @@ "defeatureify": "~0.1.4", "ejs": "^1.0.0", "ember-publisher": "0.0.3", + "testem": "^0.6.17", "yuidocjs": "~0.3.46" } } diff --git a/testem.json b/testem.json index 830eadffd11..0bc083fa12a 100644 --- a/testem.json +++ b/testem.json @@ -7,5 +7,8 @@ "routes": { "/ember-data.js": "dist/ember-data.js", "/tests/tests.js": "dist/tests.js" - } + }, + "launch_in_ci": [ + "PhantomJS" + ] } From 7ed090705f33f221704103b8b4315bb4bbf00457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Fr=C3=B6ding=20Hatlen?= Date: Sun, 27 Jul 2014 16:09:52 +0200 Subject: [PATCH 0266/2527] Documentation fix, (find returns promises) --- packages/ember-data/lib/system/store.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 0a0fb7403c4..931d35eb846 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -68,14 +68,16 @@ function coerceId(id) { for a specific id, use `DS.Store`'s `find()` method: ```javascript - var person = store.find('person', 123); + store.find('person', 123).then(function (person) { + }); ``` If your application has multiple `DS.Store` instances (an unusual case), you can specify which store should be used: ```javascript - var person = store.find('person', 123); + store.find('person', 123).then(function (person) { + }); ``` By default, the store will talk to your backend using a standard @@ -365,8 +367,9 @@ Store = Ember.Object.extend({ If you have access to the post model you can also pass the model itself: ```javascript - var myPostModel = store.find('post', 1); - store.find('comment', 2, {post: myPostModel}); + store.find('post', 1).then(function (myPostModel) { + store.find('comment', 2, {post: myPostModel}); + }); ``` This way, your adapter's `find` or `buildURL` method will be able to look up the From b6e5fa2387f608066e5b092ade61d8eda7b4d7ed Mon Sep 17 00:00:00 2001 From: IgorT Date: Mon, 28 Jul 2014 13:16:04 +0200 Subject: [PATCH 0267/2527] Add serializeIntoHash to the JSON Serializer --- .../lib/serializers/json_serializer.js | 31 ++++++++++++++++++- .../serializers/json_serializer_test.js | 12 +++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index f6f32c7157d..ed93f3b00b8 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -2,7 +2,8 @@ import { RelationshipChange } from "../system/changes"; var get = Ember.get; var set = Ember.set; var isNone = Ember.isNone; -var map = Ember.ArrayPolyfills.map; +var map = Ember.ArrayPolyfills.map; +var merge = Ember.merge; /** In Ember Data a Serializer is used to serialize and deserialize @@ -403,6 +404,34 @@ export default Ember.Object.extend({ return json; }, + /** + You can use this method to customize how a serialized record is added to the complete + JSON hash to be sent to the server. By default the JSON Serializer does not namespace + the payload and just sends the raw serialized JSON object. + If your server expects namespaced keys, you should consider using the RESTSerializer. + Otherwise you can override this method to customize how the record is added to the hash. + + For example, your server may expect underscored root objects. + + ```js + App.ApplicationSerializer = DS.RESTSerializer.extend({ + serializeIntoHash: function(data, type, record, options) { + var root = Ember.String.decamelize(type.typeKey); + data[root] = this.serialize(record, options); + } + }); + ``` + + @method serializeIntoHash + @param {Object} hash + @param {subclass of DS.Model} type + @param {DS.Model} record + @param {Object} options + */ + serializeIntoHash: function(hash, type, record, options) { + merge(hash, this.serialize(record, options)); + }, + /** `serializeAttribute` can be used to customize how `DS.attr` properties are serialized diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index 3a97906e1c9..679df2f815f 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -110,6 +110,18 @@ test("serializeHasMany respects keyForRelationship", function() { }); }); +test("serializeIntoHash", function() { + post = env.store.createRecord("post", { title: "Rails is omakase"}); + var json = {}; + + env.serializer.serializeIntoHash(json, Post, post); + + deepEqual(json, { + title: "Rails is omakase", + comments: [] + }); +}); + test("serializePolymorphicType", function() { env.container.register('serializer:comment', DS.JSONSerializer.extend({ serializePolymorphicType: function(record, json, relationship) { From ebe3bc04492044a6b28caa59c26a1b3110437d2a Mon Sep 17 00:00:00 2001 From: Jonathan Jackson Date: Mon, 28 Jul 2014 10:29:52 -0400 Subject: [PATCH 0268/2527] Move s3 publishing config from ember-publisher to ember data --- bin/publish_to_s3.js | 3 ++- config/s3ProjectConfig.js | 31 +++++++++++++++++++++++++++++++ package.json | 2 +- 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 config/s3ProjectConfig.js diff --git a/bin/publish_to_s3.js b/bin/publish_to_s3.js index a7e590d47d1..bc1c9c0e0ce 100755 --- a/bin/publish_to_s3.js +++ b/bin/publish_to_s3.js @@ -15,5 +15,6 @@ // ./bin/publish_to_s3.js // ``` var S3Publisher = require('ember-publisher'); -publisher = new S3Publisher({project: 'ember-data'}); +var configPath = require('path').join(__dirname, '../config/s3ProjectConfig.js') +publisher = new S3Publisher({projectConfigPath: configPath}); publisher.publish(); diff --git a/config/s3ProjectConfig.js b/config/s3ProjectConfig.js new file mode 100644 index 00000000000..652ca09a1af --- /dev/null +++ b/config/s3ProjectConfig.js @@ -0,0 +1,31 @@ +module.exports = function(revision, tag, date){ + return { + 'ember-data.js': fileObject('ember-data', '.js', 'text/javascript', revision, tag, date), + 'ember-data.min.js': fileObject('ember-data.min', '.js', 'text/javascript', revision, tag, date), + 'ember-data.prod.js': fileObject('ember-data.prod', '.js', 'text/javascript', revision, tag, date) + } +} + +function fileObject(baseName, extension, contentType, currentRevision, tag, date) { + var fullName = "/" + baseName + extension; + return { + contentType: contentType, + destinations: { + canary: [ + 'canary' + fullName, + 'canary/daily/' + date + fullName, + 'canary/shas/' + currentRevision + fullName + ], + stable: [ + 'stable' + fullName, + 'stable/daily/' + date + fullName, + 'stable/shas/' + currentRevision + fullName + ], + beta: [ + 'beta' + fullName, + 'beta/daily/' + date + fullName, + 'beta/shas/' + currentRevision + fullName + ] + } + } +} diff --git a/package.json b/package.json index d025895e5c8..4f94a6b4c68 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "aws-sdk": "~2.0.0-rc8", "bower": "~1.3", "defeatureify": "~0.1.4", - "ember-publisher": "0.0.3", + "ember-publisher": "0.0.6", "grunt": "~0.4.2", "grunt-cli": "~0.1.13", "grunt-contrib-clean": "~0.5.0", From ab562191440b0b13580ee32c9beb7ba9fb113948 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 28 Jul 2014 18:19:02 -0500 Subject: [PATCH 0269/2527] testem should use dot reporter instead of TAP --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index c489e8557a0..654c96b9079 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,12 @@ "postinstall": "bower install", "start": "broccoli serve", "dist": "rm -rf dist && broccoli build dist", - "test": "testem ci", + "test": "testem -R dot ci", "publish-build": "rm -rf dist && broccoli build dist && ./bin/publish_to_s3.js", - "testem-local": "testem ci", - "testem-beta": "testem -f config/testem-beta.json ci", - "testem-canary": "testem -f config/testem-canary.json ci", - "testem-stable": "testem -f config/testem-stable.json ci" + "testem-local": "testem -R dot ci", + "testem-beta": "testem -f config/testem-beta.json -R dot ci", + "testem-canary": "testem -f config/testem-canary.json -R dot ci", + "testem-stable": "testem -f config/testem-stable.json -R dot ci" }, "devDependencies": { "aws-sdk": "~2.0.0-rc8", From 7a20b276339ed4465dc0b430cb751492b34e76a4 Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Tue, 22 Jul 2014 14:19:07 +0200 Subject: [PATCH 0270/2527] Don't normalize the key if not present in the hash This make possible to call store.normalize within store.update --- .../lib/system/active_model_serializer.js | 1 + .../active_model_serializer_test.js | 4 +++ .../lib/serializers/json_serializer.js | 6 ++++ .../serializers/json_serializer_test.js | 36 +++++++++++++++++++ .../ember-data/tests/unit/store/push_test.js | 35 +++++++++--------- 5 files changed, 65 insertions(+), 17 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index 5c8f8b112f8..df878c920eb 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -272,6 +272,7 @@ var ActiveModelSerializer = RESTSerializer.extend({ } } else { payloadKey = this.keyForRelationship(key, relationship.kind); + if (!hash.hasOwnProperty(payloadKey)) { return; } payload = hash[payloadKey]; } diff --git a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js index 3b289ac7d62..3679781e676 100644 --- a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js +++ b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js @@ -94,6 +94,10 @@ test("serializeIntoHash with decamelized types", function() { test("normalize", function() { + SuperVillain.reopen({ + yellowMinion: DS.belongsTo('yellowMinion') + }) + var superVillain_hash = {first_name: "Tom", last_name: "Dale", home_planet_id: "123", evil_minion_ids: [1,2]}; var json = env.amsSerializer.normalize(SuperVillain, superVillain_hash, "superVillain"); diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index ed93f3b00b8..b41794359a3 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -87,6 +87,8 @@ export default Ember.Object.extend({ */ applyTransforms: function(type, data) { type.eachTransformedAttribute(function(key, type) { + if (!data.hasOwnProperty(key)) { return; } + var transform = this.transformFor(type); data[key] = transform.deserialize(data[key]); }, this); @@ -176,6 +178,7 @@ export default Ember.Object.extend({ type.eachAttribute(function(key) { payloadKey = this.keyForAttribute(key); if (key === payloadKey) { return; } + if (!hash.hasOwnProperty(payloadKey)) { return; } hash[key] = hash[payloadKey]; delete hash[payloadKey]; @@ -194,6 +197,7 @@ export default Ember.Object.extend({ type.eachRelationship(function(key, relationship) { payloadKey = this.keyForRelationship(key, relationship.kind); if (key === payloadKey) { return; } + if (!hash.hasOwnProperty(payloadKey)) { return; } hash[key] = hash[payloadKey]; delete hash[payloadKey]; @@ -214,6 +218,8 @@ export default Ember.Object.extend({ if (payloadKey && payloadKey.key) { payloadKey = payloadKey.key; } + if (!hash.hasOwnProperty(payloadKey)) { continue; } + if (typeof payloadKey === 'string') { hash[key] = hash[payloadKey]; delete hash[payloadKey]; diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index 679df2f815f..2f0a04f6dfc 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -264,3 +264,39 @@ test("normalizePayload is called during extractSingle", function() { equal(post.id, "1"); equal(post.title, "Rails is omakase"); }); + +test("Calling normalize should normalize the payload (only the passed keys)", function () { + expect(1); + var Person = DS.Model.extend({ + posts: DS.hasMany('post') + }); + env.container.register('serializer:post', DS.JSONSerializer.extend({ + attrs: { + notInHash: 'aCustomAttrNotInHash', + inHash: 'aCustomAttrInHash' + } + })); + + env.container.register('model:person', Person); + + Post.reopen({ + content: DS.attr('string'), + author: DS.belongsTo('person'), + notInHash: DS.attr('string'), + inHash: DS.attr('string') + }); + + var normalizedPayload = env.container.lookup("serializer:post").normalize(Post, { + id: '1', + title: 'Ember rocks', + author: 1, + aCustomAttrInHash: 'blah' + }); + + deepEqual(normalizedPayload, { + id: '1', + title: 'Ember rocks', + author: 1, + inHash: 'blah' + }); +}); diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index bf36c7bbeb8..bc54e0987e3 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -106,6 +106,24 @@ test("Calling update with partial records updates just those attributes", functi })); }); +test("Calling update on normalize allows partial updates with raw JSON", function () { + env.container.register('serializer:person', DS.RESTSerializer); + + var person = store.push('person', { + id: '1', + firstName: "Robert", + lastName: "Jackson" + }); + + store.update('person', store.normalize('person', { + id: '1', + firstName: "Jacquie" + })); + + equal(person.get('firstName'), "Jacquie", "you can push raw JSON into the store"); + equal(person.get('lastName'), "Jackson", "existing fields are untouched"); +}); + test("Calling push with a normalized hash containing related records returns a record", function() { var number1 = store.push('phone-number', { id: 1, @@ -298,20 +316,3 @@ test("Calling pushPayload without a type should use a model's serializer when no equal(person.get('firstName'), "Yehuda", "you can push raw JSON into the store"); }); - - - -test("Calling normalize should normalize the payload ", function () { - expect(1); - - var normalizedPayload = store.normalize('post', { - id: '1', - post_title: 'Ember rocks' - }); - - deepEqual(normalizedPayload, { - id: '1', - postTitle: 'Ember rocks' - }); - -}); From 2a9f945ee6edcf9b41321978d439d8c26be76f4d Mon Sep 17 00:00:00 2001 From: IgorT Date: Tue, 29 Jul 2014 13:35:22 +0200 Subject: [PATCH 0271/2527] Refactor JSON serializer to use _getMappedKey Before we used to lookup the key from attrs hash every time manually which was error prone. Now we use _getMappedKey to lookup the key. --- .../lib/serializers/json_serializer.js | 63 ++++++++++++------- .../serializers/json_serializer_test.js | 17 +++-- 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index b41794359a3..ac44a4a898f 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -214,19 +214,17 @@ export default Ember.Object.extend({ if (attrs) { for (key in attrs) { - payloadKey = attrs[key]; - if (payloadKey && payloadKey.key) { - payloadKey = payloadKey.key; - } + payloadKey = this._getMappedKey(key); if (!hash.hasOwnProperty(payloadKey)) { continue; } - if (typeof payloadKey === 'string') { + if (payloadKey !== key) { hash[key] = hash[payloadKey]; delete hash[payloadKey]; } } } }, + /** @method normalizeId @private @@ -240,6 +238,33 @@ export default Ember.Object.extend({ delete hash[primaryKey]; }, + /** + Looks up the property key that was set by the custom `attr` mapping + passed to the serializer. + + @method _getMappedKey + @private + @param {String} key + @return {String} key + */ + _getMappedKey: function(key) { + var attrs = get(this, 'attrs'); + var mappedKey; + if (attrs && attrs[key]) { + mappedKey = attrs[key]; + //We need to account for both the {title: 'post_title'} and + //{title: {key: 'post_title'}} forms + if (mappedKey.key){ + mappedKey = mappedKey.key; + } + if (typeof mappedKey === 'string'){ + key = mappedKey; + } + } + + return key; + }, + // SERIALIZE /** Called when a record is saved in order to convert the @@ -473,13 +498,13 @@ export default Ember.Object.extend({ // if provided, use the mapping provided by `attrs` in // the serializer - if (attrs && attrs[key]) { - key = attrs[key]; - } else if (this.keyForAttribute) { - key = this.keyForAttribute(key); + var payloadKey = this._getMappedKey(key); + + if (payloadKey === key && this.keyForAttribute) { + payloadKey = this.keyForAttribute(key); } - json[key] = value; + json[payloadKey] = value; }, /** @@ -514,16 +539,15 @@ export default Ember.Object.extend({ // if provided, use the mapping provided by `attrs` in // the serializer - if (attrs && attrs[key]) { - key = attrs[key]; - } else if (this.keyForRelationship) { - key = this.keyForRelationship(key, "belongsTo"); + var payloadKey = this._getMappedKey(key); + if (payloadKey === key && this.keyForRelationship) { + payloadKey = this.keyForRelationship(key, "belongsTo"); } if (isNone(belongsTo)) { - json[key] = belongsTo; + json[payloadKey] = belongsTo; } else { - json[key] = get(belongsTo, 'id'); + json[payloadKey] = get(belongsTo, 'id'); } if (relationship.options.polymorphic) { @@ -562,12 +586,9 @@ export default Ember.Object.extend({ // if provided, use the mapping provided by `attrs` in // the serializer - if (attrs && attrs[key]) { - payloadKey = attrs[key]; - } else if (this.keyForRelationship) { + payloadKey = this._getMappedKey(key); + if (payloadKey === key && this.keyForRelationship) { payloadKey = this.keyForRelationship(key, "hasMany"); - } else { - payloadKey = key; } var relationshipType = RelationshipChange.determineRelationshipType(record.constructor, relationship); diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index 2f0a04f6dfc..eba561a7391 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -164,31 +164,40 @@ test("extractArray normalizes each record in the array", function() { test('Serializer should respect the attrs hash when extracting records', function(){ env.container.register("serializer:post", DS.JSONSerializer.extend({ attrs: { - title: "title_payload_key" + title: "title_payload_key", + comments: { key: 'my_comments' } } })); var jsonHash = { - title_payload_key: "Rails is omakase" + title_payload_key: "Rails is omakase", + my_comments: [1, 2] }; var post = env.container.lookup("serializer:post").extractSingle(env.store, Post, jsonHash); equal(post.title, "Rails is omakase"); + deepEqual(post.comments, [1,2]); }); test('Serializer should respect the attrs hash when serializing records', function(){ + Post.reopen({ + parentPost: DS.belongsTo('post') + }); env.container.register("serializer:post", DS.JSONSerializer.extend({ attrs: { - title: "title_payload_key" + title: "title_payload_key", + parentPost: {key: 'my_parent'} } })); - post = env.store.createRecord("post", { title: "Rails is omakase"}); + var parentPost = env.store.push("post", { id:2, title: "Rails is omakase"}); + post = env.store.createRecord("post", { title: "Rails is omakase", parentPost: parentPost}); var payload = env.container.lookup("serializer:post").serialize(post); equal(payload.title_payload_key, "Rails is omakase"); + equal(payload.my_parent, '2'); }); test("Serializer should respect the primaryKey attribute when extracting records", function() { From c6402b4d031ac6821fc11aa8e9d73739a7d23696 Mon Sep 17 00:00:00 2001 From: Doug Yun Date: Tue, 29 Jul 2014 10:15:07 -0400 Subject: [PATCH 0272/2527] ActiveModelAdapter - Use predefined `camelize`. --- .../activemodel-adapter/lib/system/embedded_records_mixin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js index d1eb489ec2b..f7791746b64 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/activemodel-adapter/lib/system/embedded_records_mixin.js @@ -373,7 +373,7 @@ function hasDeserializeRecordsOption(attrs, attr) { } function attrsOption(attrs, attr) { - return attrs && (attrs[Ember.String.camelize(attr)] || attrs[attr]); + return attrs && (attrs[camelize(attr)] || attrs[attr]); } // chooses a relationship kind to branch which function is used to update payload From f2de957abd65ff6e07d6a8bcb334978e1745fbc0 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 29 Jul 2014 09:21:21 -0500 Subject: [PATCH 0273/2527] update README --- README.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 234e0034f4a..0ba8af0313f 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Similarly the latest passing build from the "beta" branch can be found on [http://emberjs.com/builds/#/beta](http://emberjs.com/builds/#/beta) You also have the option to build ember-data.js yourself. Clone the -repository, run `grunt buildPackages` after [setup](#setup). You'll find +repository, run `broccoli build dist` after [setup](#setup). You'll find ember-data.js in the `dist` directory. ### Instantiating the Store @@ -166,20 +166,18 @@ post [The Road to Ember Data 1. Install Node.js from http://nodejs.org or your favorite package manager. -2. Install grunt and bower. `npm install -g grunt-cli bower` +2. Install broccoli and bower. `npm install -g broccoli-cli bower` 3. Run `npm install` inside the project root to install the JS dependencies. ### In Your Browser -1. To start the development server, run `grunt dev`. +1. To start the development server, run `npm start`. -2. Visit http://localhost:9997/tests +2. Visit http://localhost:4200 ### From the CLI 1. Install phantomjs from http://phantomjs.org -2. Run `grunt test` - -3. Run `grunt dev` to automatically re-run tests when any files are changed. +2. Run `npm test` From 45902552f606068b7ff5e266d6be1c2f5b5be78e Mon Sep 17 00:00:00 2001 From: IgorT Date: Tue, 29 Jul 2014 16:48:20 +0200 Subject: [PATCH 0274/2527] Do not serialize fixtures when deleting There was no point in doing this and it only increased complexity. Couldn't figure out a nice way to test it, but no new behaviour is added so seems ok. The delete fixture test was broken, so fixed the test as well. --- packages/ember-data/lib/adapters/fixture_adapter.js | 4 +--- .../tests/integration/adapter/fixture_adapter_test.js | 6 ++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ember-data/lib/adapters/fixture_adapter.js b/packages/ember-data/lib/adapters/fixture_adapter.js index 6702fa52066..3a64a86ada0 100644 --- a/packages/ember-data/lib/adapters/fixture_adapter.js +++ b/packages/ember-data/lib/adapters/fixture_adapter.js @@ -260,9 +260,7 @@ export default Adapter.extend({ @return {Promise} promise */ deleteRecord: function(store, type, record) { - var fixture = this.mockJSON(store, type, record); - - this.deleteLoadedFixture(type, fixture); + this.deleteLoadedFixture(type, record); return this.simulateRemoteCall(function() { // no payload in a deletion diff --git a/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js b/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js index 2f58559251f..aac861a59d4 100644 --- a/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js @@ -151,7 +151,10 @@ test("should delete record asynchronously when it is committed", function() { var paul = env.store.push('person', { id: 'paul', firstName: 'Paul', lastName: 'Chavard', height: 70 }); - paul.deleteRecord(); + paul.save().then(function(){ + paul.deleteRecord(); + paul.save(); + }); paul.on('didDelete', function() { clearTimeout(timer); @@ -163,7 +166,6 @@ test("should delete record asynchronously when it is committed", function() { equal(Person.FIXTURES.length, 0, "Record removed from FIXTURES"); }); - paul.save(); }); test("should follow isUpdating semantics", function() { From 4935e7340886a0e0361757e52bff4dc3bf8ee87e Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 29 Jul 2014 16:33:39 -0500 Subject: [PATCH 0275/2527] build with ember-cli! \o/ --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 654c96b9079..a04904163ba 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,10 @@ "license": "MIT", "scripts": { "postinstall": "bower install", - "start": "broccoli serve", - "dist": "rm -rf dist && broccoli build dist", + "start": "ember serve", + "dist": "rm -rf dist && ember build", "test": "testem -R dot ci", - "publish-build": "rm -rf dist && broccoli build dist && ./bin/publish_to_s3.js", + "publish-build": "rm -rf dist && ember build && ./bin/publish_to_s3.js", "testem-local": "testem -R dot ci", "testem-beta": "testem -f config/testem-beta.json -R dot ci", "testem-canary": "testem -f config/testem-canary.json -R dot ci", @@ -38,6 +38,7 @@ "broccoli-yuidoc": "^1.3.0", "defeatureify": "~0.1.4", "ejs": "^1.0.0", + "ember-cli": "0.0.40", "ember-publisher": "0.0.6", "testem": "^0.6.17", "yuidocjs": "~0.3.46" From 9167efedb0668ad6ddfe8aef960bd1fcfb9df7c0 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 29 Jul 2014 18:52:50 -0500 Subject: [PATCH 0276/2527] use --environment production compared to broccoli-env --- Brocfile.js | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Brocfile.js b/Brocfile.js index 4dfd23cf516..3b944ab9574 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -2,7 +2,7 @@ var es6 = require('broccoli-es6-module-transpiler'); var concat = require('broccoli-concat'); var uglify = require('broccoli-uglify-js'); var es3SafeRecast = require('broccoli-es3-safe-recast'); -var env = require('broccoli-env').getEnv(); +var env = process.env.EMBER_ENV; var pickFiles = require('broccoli-static-compiler'); var merge = require('broccoli-merge-trees'); var moveFile = require('broccoli-file-mover'); diff --git a/package.json b/package.json index a04904163ba..adfde6d488f 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ "scripts": { "postinstall": "bower install", "start": "ember serve", - "dist": "rm -rf dist && ember build", + "dist": "rm -rf dist && ember build --environment production", "test": "testem -R dot ci", - "publish-build": "rm -rf dist && ember build && ./bin/publish_to_s3.js", + "publish-build": "rm -rf dist && ember build --environment production && ./bin/publish_to_s3.js", "testem-local": "testem -R dot ci", "testem-beta": "testem -f config/testem-beta.json -R dot ci", "testem-canary": "testem -f config/testem-canary.json -R dot ci", From 840f9022b34642b32e61d0ad5aaad1cac31be237 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 29 Jul 2014 19:06:31 -0500 Subject: [PATCH 0277/2527] change broccoli-cli to ember-cli in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0ba8af0313f..080ea6ee355 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ post [The Road to Ember Data 1. Install Node.js from http://nodejs.org or your favorite package manager. -2. Install broccoli and bower. `npm install -g broccoli-cli bower` +2. Install broccoli and bower. `npm install -g ember-cli bower` 3. Run `npm install` inside the project root to install the JS dependencies. From 6d9a0148422f98563f04810f194ae62bce1341b4 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 30 Jul 2014 16:56:48 -0400 Subject: [PATCH 0278/2527] factor out promise usage --- packages/ember-data/lib/system/store.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 696516a6823..17bbfbe7b39 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -535,12 +535,7 @@ Store = Ember.Object.extend({ var resolvers = Ember.A(recordResolverPairs).mapBy('resolver'); function _fetchRecord(recordResolverPair) { - var resolver = recordResolverPair.resolver; - store.fetchRecord(recordResolverPair.record).then(function(record){ - resolver.resolve(record); - }, function(error){ - resolver.reject(error); - }); + recordResolverPair.resolver.resolve(store.fetchRecord(recordResolverPair.record)); } function resolveFoundRecords(records) { From 9efc7ed0bbfb4a2d08fe4e23ae8edb7031d7909e Mon Sep 17 00:00:00 2001 From: Brendan Briggs Date: Thu, 31 Jul 2014 16:39:48 -0400 Subject: [PATCH 0279/2527] Updated ember-inflector --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 4a0c057db72..f7a3a668970 100644 --- a/bower.json +++ b/bower.json @@ -9,6 +9,6 @@ }, "devDependencies": { "loader.js": "~1.0.0", - "ember-inflector": "https://github.com/stefanpenner/ember-inflector.git#4cab0648fc828dc050ec9ee50fec1f8064ff9974" + "ember-inflector": "https://github.com/stefanpenner/ember-inflector.git#v1.0.0" } } From 8bff41c2b3505bd623be9b25df84fdea48168ffe Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 31 Jul 2014 18:09:01 -0400 Subject: [PATCH 0280/2527] Correct various yuidoc warnings to clean up some console noise when build the api docs --- packages/ember-data/lib/adapters/rest_adapter.js | 2 +- packages/ember-data/lib/ember-initializer.js | 2 +- packages/ember-data/lib/system/adapter.js | 2 +- .../ember-data/tests/integration/adapter/store_adapter_test.js | 2 +- packages/ember-data/tests/integration/application_test.js | 2 +- packages/ember-data/tests/integration/setup-container-test.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 62318744425..60d36ff59a2 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -589,7 +589,7 @@ export default Adapter.extend({ @method groupRecordsForFindMany @param {Array} records - @returns {Array} an array of arrays of records, each of which is to be + @return {Array} an array of arrays of records, each of which is to be loaded separately by `findMany`. */ groupRecordsForFindMany: function (store, records) { diff --git a/packages/ember-data/lib/ember-initializer.js b/packages/ember-data/lib/ember-initializer.js index fcaca86a8c1..a42031bc254 100644 --- a/packages/ember-data/lib/ember-initializer.js +++ b/packages/ember-data/lib/ember-initializer.js @@ -6,7 +6,7 @@ var K = Ember.K; @module ember-data */ -/** +/* This code initializes Ember-Data onto an Ember application. diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index d5777ae98fe..3d12b1865da 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -449,7 +449,7 @@ var Adapter = Ember.Object.extend({ @method groupRecordsForFindMany @param {Array} records - @returns {Array} an array of arrays of records, each of which is to be + @return {Array} an array of arrays of records, each of which is to be loaded separately by `findMany`. */ groupRecordsForFindMany: function (store, records) { diff --git a/packages/ember-data/tests/integration/adapter/store_adapter_test.js b/packages/ember-data/tests/integration/adapter/store_adapter_test.js index e65b3236f4b..49fac1c46a7 100644 --- a/packages/ember-data/tests/integration/adapter/store_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/store_adapter_test.js @@ -1,4 +1,4 @@ -/** +/* This is an integration test that tests the communication between a store and its adapter. diff --git a/packages/ember-data/tests/integration/application_test.js b/packages/ember-data/tests/integration/application_test.js index ac7b1c7b58a..757e69ab8ca 100644 --- a/packages/ember-data/tests/integration/application_test.js +++ b/packages/ember-data/tests/integration/application_test.js @@ -8,7 +8,7 @@ var run = Ember.run, var app, App, container; -/** +/* These tests ensure that Ember Data works with Ember.js' application initialization and dependency injection APIs. */ diff --git a/packages/ember-data/tests/integration/setup-container-test.js b/packages/ember-data/tests/integration/setup-container-test.js index 04a1f74888b..5bf8e49efbb 100644 --- a/packages/ember-data/tests/integration/setup-container-test.js +++ b/packages/ember-data/tests/integration/setup-container-test.js @@ -6,7 +6,7 @@ var run = Ember.run, var container; -/** +/* These tests ensure that Ember Data works with Ember.js' container initialization and dependency injection API. */ From b5b09d205276dc0f523d113df4af07378f833f77 Mon Sep 17 00:00:00 2001 From: Jeff Lage Date: Thu, 31 Jul 2014 19:06:41 -0400 Subject: [PATCH 0281/2527] Move EmbeddedRecordsMixin to core from activemodel Embedded record relationships within a payload has utility even when the backend is not ActiveModel. Moved the mixin to the lib/serializers dir --- .gitignore | 16 ++++++++++++++++ packages/activemodel-adapter/lib/main.js | 6 ++---- packages/activemodel-adapter/lib/system.js | 2 -- .../lib/system/active_model_adapter.js | 1 - packages/ember-data/lib/main.js | 4 ++-- .../lib/serializers}/embedded_records_mixin.js | 8 ++++---- .../serializers}/embedded_records_mixin_test.js | 0 7 files changed, 24 insertions(+), 13 deletions(-) rename packages/{activemodel-adapter/lib/system => ember-data/lib/serializers}/embedded_records_mixin.js (98%) rename packages/{activemodel-adapter/tests/integration => ember-data/tests/integration/serializers}/embedded_records_mixin_test.js (100%) diff --git a/.gitignore b/.gitignore index 0945db04706..eb99c12126a 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,19 @@ docs/node_modules/ node_modules/ bower_components/ + +.idea/.name + +.idea/ember-data.iml + +.idea/encodings.xml + +.idea/misc.xml + +.idea/modules.xml + +.idea/scopes/scope_settings.xml + +.idea/vcs.xml + +.idea/workspace.xml diff --git a/packages/activemodel-adapter/lib/main.js b/packages/activemodel-adapter/lib/main.js index 4b9396890df..95fa5f1bfd9 100644 --- a/packages/activemodel-adapter/lib/main.js +++ b/packages/activemodel-adapter/lib/main.js @@ -1,11 +1,9 @@ import { ActiveModelAdapter, - ActiveModelSerializer, - EmbeddedRecordsMixin + ActiveModelSerializer } from "activemodel-adapter/system"; export { ActiveModelAdapter, - ActiveModelSerializer, - EmbeddedRecordsMixin + ActiveModelSerializer }; diff --git a/packages/activemodel-adapter/lib/system.js b/packages/activemodel-adapter/lib/system.js index c004281d577..e11f032cd3f 100644 --- a/packages/activemodel-adapter/lib/system.js +++ b/packages/activemodel-adapter/lib/system.js @@ -1,9 +1,7 @@ -import EmbeddedRecordsMixin from "activemodel-adapter/system/embedded_records_mixin"; import ActiveModelAdapter from "activemodel-adapter/system/active_model_adapter"; import ActiveModelSerializer from "activemodel-adapter/system/active_model_serializer"; export { - EmbeddedRecordsMixin, ActiveModelAdapter, ActiveModelSerializer }; diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index f72414dde64..fb4088e7e8d 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -2,7 +2,6 @@ import {RESTAdapter} from "ember-data/adapters"; import {InvalidError} from "ember-data/system/adapter"; import {pluralize} from "ember-inflector"; import ActiveModelSerializer from "activemodel-adapter/system/active_model_serializer"; -import EmbeddedRecordsMixin from "activemodel-adapter/system/embedded_records_mixin"; /** @module ember-data diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index a868b3d256a..fece95a5748 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -51,10 +51,10 @@ import { import JSONSerializer from "ember-data/serializers/json_serializer"; import RESTSerializer from "ember-data/serializers/rest_serializer"; import "ember-inflector"; +import EmbeddedRecordsMixin from "ember-data/serializers/embedded_records_mixin"; import { ActiveModelAdapter, - ActiveModelSerializer, - EmbeddedRecordsMixin + ActiveModelSerializer } from "activemodel-adapter"; import { diff --git a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js b/packages/ember-data/lib/serializers/embedded_records_mixin.js similarity index 98% rename from packages/activemodel-adapter/lib/system/embedded_records_mixin.js rename to packages/ember-data/lib/serializers/embedded_records_mixin.js index 4cf1242b0ee..915dddee3e7 100644 --- a/packages/activemodel-adapter/lib/system/embedded_records_mixin.js +++ b/packages/ember-data/lib/serializers/embedded_records_mixin.js @@ -15,7 +15,7 @@ import {pluralize} from "ember-inflector"; Below is an example of a per-type serializer ('post' type). ```js - App.PostSerializer = DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { author: {embedded: 'always'}, comments: {serialize: 'ids'} @@ -40,14 +40,14 @@ import {pluralize} from "ember-inflector"; In the case where embedded JSON is expected while extracting a payload (reading) the setting is `deserialize: 'records'`, there is no need to use `ids` when extracting as that is the default behavior without this mixin if you are using - the vanilla ActiveModelAdapter. Likewise, to embed JSON in the payload while + the vanilla EmbeddedRecordsMixin. Likewise, to embed JSON in the payload while serializing `serialize: 'records'` is the setting to use. There is an option of not embedding JSON in the serialized payload by using `serialize: 'ids'`. If you do not want the relationship sent at all, you can use `serialize: 'no'`. - ### ActiveModelSerializer defaults - If you do not overwrite `attrs` for a specific relationship, the `ActiveModelSerializer` + ### EmbeddedRecordsMixin defaults + If you do not overwrite `attrs` for a specific relationship, the `EmbeddedRecordsMixin` will behave in the following way: BelongsTo: `{serialize:'id', deserialize:'id'}` diff --git a/packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js similarity index 100% rename from packages/activemodel-adapter/tests/integration/embedded_records_mixin_test.js rename to packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js From b7d515efdb98ac8f751d799bb4bf64c0b4c619bf Mon Sep 17 00:00:00 2001 From: Jeff Lage Date: Thu, 31 Jul 2014 19:15:18 -0400 Subject: [PATCH 0282/2527] reverting .gitignore pulling webstorm project files out --- .gitignore | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.gitignore b/.gitignore index eb99c12126a..0945db04706 100644 --- a/.gitignore +++ b/.gitignore @@ -17,19 +17,3 @@ docs/node_modules/ node_modules/ bower_components/ - -.idea/.name - -.idea/ember-data.iml - -.idea/encodings.xml - -.idea/misc.xml - -.idea/modules.xml - -.idea/scopes/scope_settings.xml - -.idea/vcs.xml - -.idea/workspace.xml From 4e144b351bfc9940581d9f566ffe4d041b7d6b64 Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Thu, 31 Jul 2014 18:12:55 +0200 Subject: [PATCH 0283/2527] add test for multiwords typeKey --- .../tests/integration/serializers/rest_serializer_test.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js index e6c7bd5acb0..0e45f12916d 100644 --- a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js @@ -48,6 +48,14 @@ module("integration/serializer/rest - RESTSerializer", { } }); +test("typeForRoot returns always same typeKey even for uncountable multi words keys", function() { + expect(2); + Ember.Inflector.inflector.uncountable('words'); + expectedTypeKey = 'multiWords'; + equal(env.restSerializer.typeForRoot('multi_words'), expectedTypeKey); + equal(env.restSerializer.typeForRoot('multiWords'), expectedTypeKey); +}); + test("extractArray with custom typeForRoot", function() { env.restSerializer.typeForRoot = function(root) { var camelized = Ember.String.camelize(root); From ff371b5d60904cff92ee4e01c1d9890ffb51d310 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 1 Aug 2014 14:08:25 -0400 Subject: [PATCH 0284/2527] cleanup --- .../lib/system/changes/relationship_change.js | 204 +++++++++--------- packages/ember-data/lib/system/store.js | 40 ++-- 2 files changed, 122 insertions(+), 122 deletions(-) diff --git a/packages/ember-data/lib/system/changes/relationship_change.js b/packages/ember-data/lib/system/changes/relationship_change.js index 55cfd6e6115..6acfa05b2a0 100644 --- a/packages/ember-data/lib/system/changes/relationship_change.js +++ b/packages/ember-data/lib/system/changes/relationship_change.js @@ -2,7 +2,7 @@ @module ember-data */ -import { Model } from "ember-data/system/model"; +import Model from "ember-data/system/model/model"; var get = Ember.get; var set = Ember.set; @@ -68,10 +68,10 @@ var OneToOneChange = {}; var ManyToManyChange = {}; RelationshipChange._createChange = function(options){ - if (options.changeType === "add"){ + if (options.changeType === 'add') { return RelationshipChangeAdd.create(options); } - if (options.changeType === "remove"){ + if (options.changeType === 'remove') { return RelationshipChangeRemove.create(options); } }; @@ -83,18 +83,18 @@ RelationshipChange.determineRelationshipType = function(recordType, knownSide){ var inverse = recordType.inverseFor(knownKey); - if (inverse){ + if (inverse) { key = inverse.name; otherKind = inverse.kind; } - if (!inverse){ - return knownKind === "belongsTo" ? "oneToNone" : "manyToNone"; + if (!inverse) { + return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone'; } else { - if(otherKind === "belongsTo"){ - return knownKind === "belongsTo" ? "oneToOne" : "manyToOne"; + if (otherKind === 'belongsTo') { + return knownKind === 'belongsTo' ? 'oneToOne' : 'manyToOne'; } else { - return knownKind === "belongsTo" ? "oneToMany" : "manyToMany"; + return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany'; } } @@ -104,17 +104,17 @@ RelationshipChange.createChange = function(firstRecord, secondRecord, store, opt // Get the type of the child based on the child's client ID var firstRecordType = firstRecord.constructor, changeType; changeType = RelationshipChange.determineRelationshipType(firstRecordType, options); - if (changeType === "oneToMany"){ + if (changeType === 'oneToMany') { return OneToManyChange.createChange(firstRecord, secondRecord, store, options); - } else if (changeType === "manyToOne"){ + } else if (changeType === 'manyToOne') { return OneToManyChange.createChange(secondRecord, firstRecord, store, options); - } else if (changeType === "oneToNone"){ + } else if (changeType === 'oneToNone') { return OneToNoneChange.createChange(firstRecord, secondRecord, store, options); - } else if (changeType === "manyToNone"){ + } else if (changeType === 'manyToNone') { return ManyToNoneChange.createChange(firstRecord, secondRecord, store, options); - } else if (changeType === "oneToOne"){ + } else if (changeType === 'oneToOne') { return OneToOneChange.createChange(firstRecord, secondRecord, store, options); - } else if (changeType === "manyToMany"){ + } else if (changeType === 'manyToMany') { return ManyToManyChange.createChange(firstRecord, secondRecord, store, options); } }; @@ -122,13 +122,13 @@ RelationshipChange.createChange = function(firstRecord, secondRecord, store, opt OneToNoneChange.createChange = function(childRecord, parentRecord, store, options) { var key = options.key; var change = RelationshipChange._createChange({ - parentRecord: parentRecord, - childRecord: childRecord, - firstRecord: childRecord, - store: store, - changeType: options.changeType, - firstRecordName: key, - firstRecordKind: "belongsTo" + parentRecord: parentRecord, + childRecord: childRecord, + firstRecord: childRecord, + store: store, + changeType: options.changeType, + firstRecordName: key, + firstRecordKind: 'belongsTo' }); store.addRelationshipChangeFor(childRecord, key, parentRecord, null, change); @@ -139,13 +139,13 @@ OneToNoneChange.createChange = function(childRecord, parentRecord, store, option ManyToNoneChange.createChange = function(childRecord, parentRecord, store, options) { var key = options.key; var change = RelationshipChange._createChange({ - parentRecord: childRecord, - childRecord: parentRecord, - secondRecord: childRecord, - store: store, - changeType: options.changeType, - secondRecordName: options.key, - secondRecordKind: "hasMany" + parentRecord: childRecord, + childRecord: parentRecord, + secondRecord: childRecord, + store: store, + changeType: options.changeType, + secondRecordName: options.key, + secondRecordKind: 'hasMany' }); store.addRelationshipChangeFor(childRecord, key, parentRecord, null, change); @@ -161,20 +161,19 @@ ManyToManyChange.createChange = function(childRecord, parentRecord, store, optio var key = options.key; var change = RelationshipChange._createChange({ - parentRecord: parentRecord, - childRecord: childRecord, - firstRecord: childRecord, - secondRecord: parentRecord, - firstRecordKind: "hasMany", - secondRecordKind: "hasMany", - store: store, - changeType: options.changeType, - firstRecordName: key + parentRecord: parentRecord, + childRecord: childRecord, + firstRecord: childRecord, + secondRecord: parentRecord, + firstRecordKind: 'hasMany', + secondRecordKind: 'hasMany', + store: store, + changeType: options.changeType, + firstRecordName: key }); store.addRelationshipChangeFor(childRecord, key, parentRecord, null, change); - return change; }; @@ -190,19 +189,19 @@ OneToOneChange.createChange = function(childRecord, parentRecord, store, options } else if (options.key) { key = options.key; } else { - Ember.assert("You must pass either a parentType or belongsToName option to OneToManyChange.forChildAndParent", false); + Ember.assert('You must pass either a parentType or belongsToName option to OneToManyChange.forChildAndParent', false); } var change = RelationshipChange._createChange({ - parentRecord: parentRecord, - childRecord: childRecord, - firstRecord: childRecord, - secondRecord: parentRecord, - firstRecordKind: "belongsTo", - secondRecordKind: "belongsTo", - store: store, - changeType: options.changeType, - firstRecordName: key + parentRecord: parentRecord, + childRecord: childRecord, + firstRecord: childRecord, + secondRecord: parentRecord, + firstRecordKind: 'belongsTo', + secondRecordKind: 'belongsTo', + store: store, + changeType: options.changeType, + firstRecordName: key }); store.addRelationshipChangeFor(childRecord, key, parentRecord, null, change); @@ -211,17 +210,17 @@ OneToOneChange.createChange = function(childRecord, parentRecord, store, options }; OneToOneChange.maintainInvariant = function(options, store, childRecord, key){ - if (options.changeType === "add" && store.recordIsMaterialized(childRecord)) { + if (options.changeType === 'add' && store.recordIsMaterialized(childRecord)) { var oldParent = get(childRecord, key); - if (oldParent){ + if (oldParent) { var correspondingChange = OneToOneChange.createChange(childRecord, oldParent, store, { - parentType: options.parentType, - hasManyName: options.hasManyName, - changeType: "remove", - key: options.key - }); + parentType: options.parentType, + hasManyName: options.hasManyName, + changeType: 'remove', + key: options.key + }); store.addRelationshipChangeFor(childRecord, key, options.parentRecord , null, correspondingChange); - correspondingChange.sync(); + correspondingChange.sync(); } } }; @@ -239,19 +238,19 @@ OneToManyChange.createChange = function(childRecord, parentRecord, store, option } else if (options.key) { key = options.key; } else { - Ember.assert("You must pass either a parentType or belongsToName option to OneToManyChange.forChildAndParent", false); + Ember.assert('You must pass either a parentType or belongsToName option to OneToManyChange.forChildAndParent', false); } var change = RelationshipChange._createChange({ - parentRecord: parentRecord, - childRecord: childRecord, - firstRecord: childRecord, - secondRecord: parentRecord, - firstRecordKind: "belongsTo", - secondRecordKind: "hasMany", - store: store, - changeType: options.changeType, - firstRecordName: key + parentRecord: parentRecord, + childRecord: childRecord, + firstRecord: childRecord, + secondRecord: parentRecord, + firstRecordKind: 'belongsTo', + secondRecordKind: 'hasMany', + store: store, + changeType: options.changeType, + firstRecordName: key }); store.addRelationshipChangeFor(childRecord, key, parentRecord, change.getSecondRecordName(), change); @@ -261,15 +260,15 @@ OneToManyChange.createChange = function(childRecord, parentRecord, store, option OneToManyChange.maintainInvariant = function(options, store, childRecord, key){ - if (options.changeType === "add" && childRecord) { + if (options.changeType === 'add' && childRecord) { var oldParent = get(childRecord, key); - if (oldParent){ + if (oldParent) { var correspondingChange = OneToManyChange.createChange(childRecord, oldParent, store, { - parentType: options.parentType, - hasManyName: options.hasManyName, - changeType: "remove", - key: options.key - }); + parentType: options.parentType, + hasManyName: options.hasManyName, + changeType: 'remove', + key: options.key + }); store.addRelationshipChangeFor(childRecord, key, options.parentRecord, correspondingChange.getSecondRecordName(), correspondingChange); correspondingChange.sync(); } @@ -281,7 +280,6 @@ OneToManyChange.maintainInvariant = function(options, store, childRecord, key){ @namespace DS */ RelationshipChange.prototype = { - getSecondRecordName: function() { var name = this.secondRecordName, parent; @@ -304,8 +302,7 @@ RelationshipChange.prototype = { @return {String} */ getFirstRecordName: function() { - var name = this.firstRecordName; - return name; + return this.firstRecordName; }, /** @@ -335,10 +332,10 @@ RelationshipChange.prototype = { coalesce: function(){ var relationshipPairs = this.store.relationshipChangePairsFor(this.firstRecord); - forEach(relationshipPairs, function(pair){ - var addedChange = pair["add"]; - var removedChange = pair["remove"]; - if(addedChange && removedChange) { + forEach(relationshipPairs, function(pair) { + var addedChange = pair['add']; + var removedChange = pair['remove']; + if (addedChange && removedChange) { addedChange.destroy(); removedChange.destroy(); } @@ -354,7 +351,7 @@ function isValue(object) { return object && typeof object === 'object' && (!object.then || typeof object.then !== 'function'); } -RelationshipChangeAdd.prototype.changeType = "add"; +RelationshipChangeAdd.prototype.changeType = 'add'; RelationshipChangeAdd.prototype.sync = function() { var secondRecordName = this.getSecondRecordName(); var firstRecordName = this.getFirstRecordName(); @@ -365,14 +362,12 @@ RelationshipChangeAdd.prototype.sync = function() { //Ember.assert("You specified a belongsTo (" + belongsToName + ") on " + child.constructor + " but did not specify an inverse hasMany on " + (!hasManyName && (newParent || oldParent || this.lastParentRecord).constructor), hasManyName); if (secondRecord instanceof Model && firstRecord instanceof Model) { - if(this.secondRecordKind === "belongsTo"){ - secondRecord.suspendRelationshipObservers(function(){ + if (this.secondRecordKind === 'belongsTo') { + secondRecord.suspendRelationshipObservers(function() { set(secondRecord, secondRecordName, firstRecord); }); - - } - else if(this.secondRecordKind === "hasMany"){ - secondRecord.suspendRelationshipObservers(function(){ + } else if (this.secondRecordKind === 'hasMany') { + secondRecord.suspendRelationshipObservers(function() { var relationship = get(secondRecord, secondRecordName); if (isValue(relationship)) { relationship.addObject(firstRecord); } }); @@ -380,13 +375,12 @@ RelationshipChangeAdd.prototype.sync = function() { } if (firstRecord instanceof Model && secondRecord instanceof Model && get(firstRecord, firstRecordName) !== secondRecord) { - if(this.firstRecordKind === "belongsTo"){ - firstRecord.suspendRelationshipObservers(function(){ + if (this.firstRecordKind === 'belongsTo') { + firstRecord.suspendRelationshipObservers(function() { set(firstRecord, firstRecordName, secondRecord); }); - } - else if(this.firstRecordKind === "hasMany"){ - firstRecord.suspendRelationshipObservers(function(){ + } else if (this.firstRecordKind === 'hasMany') { + firstRecord.suspendRelationshipObservers(function() { var relationship = get(firstRecord, firstRecordName); if (isValue(relationship)) { relationship.addObject(secondRecord); } }); @@ -396,7 +390,7 @@ RelationshipChangeAdd.prototype.sync = function() { this.coalesce(); }; -RelationshipChangeRemove.prototype.changeType = "remove"; +RelationshipChangeRemove.prototype.changeType = 'remove'; RelationshipChangeRemove.prototype.sync = function() { var secondRecordName = this.getSecondRecordName(); var firstRecordName = this.getFirstRecordName(); @@ -407,13 +401,12 @@ RelationshipChangeRemove.prototype.sync = function() { //Ember.assert("You specified a belongsTo (" + belongsToName + ") on " + child.constructor + " but did not specify an inverse hasMany on " + (!hasManyName && (newParent || oldParent || this.lastParentRecord).constructor), hasManyName); if (secondRecord instanceof Model && firstRecord instanceof Model) { - if(this.secondRecordKind === "belongsTo"){ - secondRecord.suspendRelationshipObservers(function(){ + if (this.secondRecordKind === 'belongsTo') { + secondRecord.suspendRelationshipObservers(function() { set(secondRecord, secondRecordName, null); }); - } - else if(this.secondRecordKind === "hasMany"){ - secondRecord.suspendRelationshipObservers(function(){ + } else if (this.secondRecordKind === 'hasMany') { + secondRecord.suspendRelationshipObservers(function() { var relationship = get(secondRecord, secondRecordName); if (isValue(relationship)) { relationship.removeObject(firstRecord); } }); @@ -421,15 +414,14 @@ RelationshipChangeRemove.prototype.sync = function() { } if (firstRecord instanceof Model && get(firstRecord, firstRecordName)) { - if(this.firstRecordKind === "belongsTo"){ - firstRecord.suspendRelationshipObservers(function(){ + if (this.firstRecordKind === 'belongsTo') { + firstRecord.suspendRelationshipObservers(function() { set(firstRecord, firstRecordName, null); }); - } - else if(this.firstRecordKind === "hasMany"){ - firstRecord.suspendRelationshipObservers(function(){ - var relationship = get(firstRecord, firstRecordName); - if (isValue(relationship)) { relationship.removeObject(secondRecord); } + } else if (this.firstRecordKind === 'hasMany') { + firstRecord.suspendRelationshipObservers(function() { + var relationship = get(firstRecord, firstRecordName); + if (isValue(relationship)) { relationship.removeObject(secondRecord); } }); } } diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 17bbfbe7b39..73641108c10 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -481,9 +481,8 @@ Store = Ember.Object.extend({ @return {Promise} promise */ fetchRecord: function(record) { - var type = record.constructor, - id = get(record, 'id'); - + var type = record.constructor; + var id = get(record, 'id'); var adapter = this.adapterFor(type); Ember.assert("You tried to find a record but you have no adapter (for " + type + ")", adapter); @@ -502,8 +501,11 @@ Store = Ember.Object.extend({ if (isNone(record)) { return null; } if (record._loadingPromise) { return record._loadingPromise; } - var resolver = Ember.RSVP.defer("Fetching " + type + "with id: " + record.get('id')); - var recordResolverPair = {record: record, resolver: resolver}; + var resolver = Ember.RSVP.defer('Fetching ' + type + 'with id: ' + record.get('id')); + var recordResolverPair = { + record: record, + resolver: resolver + }; var promise = resolver.promise; record.loadingData(promise); @@ -697,8 +699,8 @@ Store = Ember.Object.extend({ var type = this.modelFor(typeName); var records = Ember.A(inputRecords); var unloadedRecords = records.filterProperty('isEmpty', true); - var manyArray = this.recordArrayManager.createManyArray(type, records); + manyArray.loadingRecordsCount = unloadedRecords.length; if (unloadedRecords.length) { @@ -1565,9 +1567,9 @@ Store = Ember.Object.extend({ //TODO(Igor) What about the other side var changesObject = this._relationshipChanges[record.clientId]; for (var objKey in changesObject){ - if(changesObject.hasOwnProperty(objKey)){ + if (changesObject.hasOwnProperty(objKey)){ for (var changeKey in changesObject[objKey]){ - if(changesObject[objKey].hasOwnProperty(changeKey)){ + if (changesObject[objKey].hasOwnProperty(changeKey)){ toReturn.push(changesObject[objKey][changeKey]); } } @@ -1666,8 +1668,8 @@ function normalizeRelationships(store, type, data, record) { return; } - var kind = relationship.kind, - value = data[key]; + var kind = relationship.kind; + var value = data[key]; if (value == null) { if (kind === 'hasMany' && record) { @@ -1865,9 +1867,9 @@ function _bind(fn) { } function _find(adapter, store, type, id, record) { - var promise = adapter.find(store, type, id, record), - serializer = serializerForAdapter(adapter, type), - label = "DS: Handle Adapter#find of " + type + " with id: " + id; + var promise = adapter.find(store, type, id, record); + var serializer = serializerForAdapter(adapter, type); + var label = "DS: Handle Adapter#find of " + type + " with id: " + id; promise = Promise.cast(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); @@ -1888,10 +1890,16 @@ function _find(adapter, store, type, id, record) { function _findMany(adapter, store, type, ids, records) { - var promise = adapter.findMany(store, type, ids, records), - serializer = serializerForAdapter(adapter, type), - label = "DS: Handle Adapter#findMany of " + type; + var promise = adapter.findMany(store, type, ids, records); + var serializer = serializerForAdapter(adapter, type); + var label = "DS: Handle Adapter#findMany of " + type; + + if (promise === undefined) { + throw new Error('adapter.findMany returned undefined, this was very likely a mistake'); + } + var guardedPromise; + promise = Promise.cast(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); From 994d8a088128831a37fd32ff159267fee5479681 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 1 Aug 2014 17:20:38 -0400 Subject: [PATCH 0285/2527] loosen constraint of adapter method return values --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 73641108c10..9be4e4590f3 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1992,7 +1992,7 @@ function _commit(adapter, store, operation, record) { var serializer = serializerForAdapter(adapter, type); var label = "DS: Extract and notify about " + operation + " completion of " + record; - Ember.assert("Your adapter's '" + operation + "' method must return a promise, but it returned " + promise, isThenable(promise)); + Ember.assert("Your adapter's '" + operation + "' method must return a value, but it returned `undefined", promise !==undefined); promise = Promise.cast(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); From 2bd95b85c8904f7bd3f5ba5d60fe1f4e98bfbab7 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 1 Aug 2014 17:05:57 -0400 Subject: [PATCH 0286/2527] =?UTF-8?q?[Bugfix]=20relationship=20changes=20s?= =?UTF-8?q?houldn=E2=80=99t=20cause=20async=20fetches?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As it turns out, we never actuality apply relationship syncing to async relationships, all the code would do was get the relationship which could cause fetches and the bail before the synchronization occurred. This merely moves the guard higher, and changes the guard to be side-affect free. Later work must happen to introduce relationship syncing for async relationships. --- .../lib/system/changes/relationship_change.js | 28 +++++----- .../relationships/belongs_to_test.js | 51 +++++++++++++++++++ 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/packages/ember-data/lib/system/changes/relationship_change.js b/packages/ember-data/lib/system/changes/relationship_change.js index 6acfa05b2a0..b7516778dc6 100644 --- a/packages/ember-data/lib/system/changes/relationship_change.js +++ b/packages/ember-data/lib/system/changes/relationship_change.js @@ -76,7 +76,6 @@ RelationshipChange._createChange = function(options){ } }; - RelationshipChange.determineRelationshipType = function(recordType, knownSide){ var knownKey = knownSide.key, key, otherKind; var knownKind = knownSide.kind; @@ -97,7 +96,6 @@ RelationshipChange.determineRelationshipType = function(recordType, knownSide){ return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany'; } } - }; RelationshipChange.createChange = function(firstRecord, secondRecord, store, options){ @@ -258,7 +256,6 @@ OneToManyChange.createChange = function(childRecord, parentRecord, store, option return change; }; - OneToManyChange.maintainInvariant = function(options, store, childRecord, key){ if (options.changeType === 'add' && childRecord) { var oldParent = get(childRecord, key); @@ -346,9 +343,11 @@ RelationshipChange.prototype = { RelationshipChangeAdd.prototype = Ember.create(RelationshipChange.create({})); RelationshipChangeRemove.prototype = Ember.create(RelationshipChange.create({})); -// the object is a value, and not a promise -function isValue(object) { - return object && typeof object === 'object' && (!object.then || typeof object.then !== 'function'); +function isSyncRelationship(record, relationshipName) { + var meta = Ember.meta(record); + var desc = meta.descs[relationshipName]; + + return desc && !desc._meta.options.async; } RelationshipChangeAdd.prototype.changeType = 'add'; @@ -366,10 +365,10 @@ RelationshipChangeAdd.prototype.sync = function() { secondRecord.suspendRelationshipObservers(function() { set(secondRecord, secondRecordName, firstRecord); }); - } else if (this.secondRecordKind === 'hasMany') { + } else if (this.secondRecordKind === 'hasMany' && isSyncRelationship(secondRecord, secondRecordName)) { secondRecord.suspendRelationshipObservers(function() { var relationship = get(secondRecord, secondRecordName); - if (isValue(relationship)) { relationship.addObject(firstRecord); } + relationship.addObject(firstRecord); }); } } @@ -379,14 +378,13 @@ RelationshipChangeAdd.prototype.sync = function() { firstRecord.suspendRelationshipObservers(function() { set(firstRecord, firstRecordName, secondRecord); }); - } else if (this.firstRecordKind === 'hasMany') { + } else if (this.firstRecordKind === 'hasMany' && isSyncRelationship(secondRecord, secondRecordName)) { firstRecord.suspendRelationshipObservers(function() { var relationship = get(firstRecord, firstRecordName); - if (isValue(relationship)) { relationship.addObject(secondRecord); } + relationship.addObject(secondRecord); }); } } - this.coalesce(); }; @@ -405,10 +403,10 @@ RelationshipChangeRemove.prototype.sync = function() { secondRecord.suspendRelationshipObservers(function() { set(secondRecord, secondRecordName, null); }); - } else if (this.secondRecordKind === 'hasMany') { + } else if (this.secondRecordKind === 'hasMany' && isSyncRelationship(secondRecord, secondRecordName)) { secondRecord.suspendRelationshipObservers(function() { var relationship = get(secondRecord, secondRecordName); - if (isValue(relationship)) { relationship.removeObject(firstRecord); } + relationship.removeObject(firstRecord); }); } } @@ -418,10 +416,10 @@ RelationshipChangeRemove.prototype.sync = function() { firstRecord.suspendRelationshipObservers(function() { set(firstRecord, firstRecordName, null); }); - } else if (this.firstRecordKind === 'hasMany') { + } else if (this.firstRecordKind === 'hasMany' && isSyncRelationship(firstRecord, firstRecordName)) { firstRecord.suspendRelationshipObservers(function() { var relationship = get(firstRecord, firstRecordName); - if (isValue(relationship)) { relationship.removeObject(secondRecord); } + relationship.removeObject(secondRecord); }); } } diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index cbbcea19986..a232579b24d 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -287,3 +287,54 @@ test("relationshipsByName does not cache a factory", function() { equal( messageModelFromRelationType, messageModelFromStore, "model factory based on relationship type matches the model based on store.modelFor" ); }); + +test("asdf", function() { + expect(2); + + /* Scenario: + * --------- + * + * post HM async comments + * comments bt sync post + * + * scenario: + * - post hm C [1,2,3] + * - post has a partially realized comments array comment#1 has been realized + * - comment has not yet realized its post relationship + * - comment is destroyed + */ + + env.store.modelFor('post').reopen({ + comments: DS.hasMany('comment', { + async: true, + inverse: 'post' + }) + }); + + env.store.modelFor('comment').reopen({ + post: DS.belongsTo('post', { + }) + }); + + var post = env.store.push('post', { + id: 1, + comments: [1, 2, 3] + }); + + var comment = env.store.push('comment', { + id: 1, + post: 1 + }); + + env.adapter.deleteRecord = function(store, type, record) { + ok(record instanceof type); + equal(record.id, 1, 'should first comment') + return record; + }; + + env.adapter.findMany = function(store, type, ids, records) { + ok(false, 'should not need to findMay more comments, but attempted to anyways'); + }; + + comment.destroyRecord(); +}); From 1e5062db7f8fc2d38bfa6380c1ab1ab70596c97e Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Sat, 2 Aug 2014 18:30:04 -0400 Subject: [PATCH 0287/2527] cleanup brocfile --- Brocfile.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Brocfile.js b/Brocfile.js index 3b944ab9574..a6f2d9f33a8 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -110,7 +110,11 @@ var yuidocTree = yuidoc('packages', { } }); -var libFiles = merge([emberInflectorFiles, emberDataFiles, activeModelAdapterFiles]); +var libFiles = merge([ + emberInflectorFiles, + emberDataFiles, + activeModelAdapterFiles +]); var testFiles = merge([ testTree(emberDataFiles, 'ember-data'), @@ -170,7 +174,15 @@ configurationFiles = replace(configurationFiles, { } }); -var trees = merge([testFiles, globalBuild, namedAMDBuild, yuidocTree, testRunner, bower, configurationFiles]); +var trees = merge([ + testFiles, + globalBuild, + namedAMDBuild, + yuidocTree, + testRunner, + bower, + configurationFiles +]); if (env === 'production') { var minifiedAMD = minify(namedAMDBuild, 'ember-data.named-amd'); From 7dccea8dbf7393461ed1605c332656e9a217d3e3 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Sat, 2 Aug 2014 18:30:28 -0400 Subject: [PATCH 0288/2527] move yuidoc to production (its slow) --- Brocfile.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Brocfile.js b/Brocfile.js index a6f2d9f33a8..6448e1a5156 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -178,7 +178,6 @@ var trees = merge([ testFiles, globalBuild, namedAMDBuild, - yuidocTree, testRunner, bower, configurationFiles @@ -187,7 +186,12 @@ var trees = merge([ if (env === 'production') { var minifiedAMD = minify(namedAMDBuild, 'ember-data.named-amd'); var minifiedGlobals = minify(globalBuild, 'ember-data'); - trees = merge([trees, minifiedAMD, minifiedGlobals]); + trees = merge([ + yuidocTree, + trees, + minifiedAMD, + minifiedGlobals + ]); } module.exports = trees; From 8a95d381f5abd94c1a36311109fccb555eaedd5f Mon Sep 17 00:00:00 2001 From: Cyril Fluck Date: Mon, 4 Aug 2014 11:09:22 -0700 Subject: [PATCH 0289/2527] Changing an async belongsTo association does not load unfetched record. [Fixes #1567] --- .../lib/system/changes/relationship_change.js | 8 +--- .../lib/system/relationship-meta.js | 7 ++++ .../lib/system/relationships/belongs_to.js | 5 ++- .../relationships/belongs_to_test.js | 37 ++++++++++++++++++- 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/packages/ember-data/lib/system/changes/relationship_change.js b/packages/ember-data/lib/system/changes/relationship_change.js index b7516778dc6..aa46e65008e 100644 --- a/packages/ember-data/lib/system/changes/relationship_change.js +++ b/packages/ember-data/lib/system/changes/relationship_change.js @@ -3,6 +3,7 @@ */ import Model from "ember-data/system/model/model"; +import { isSyncRelationship } from 'ember-data/system/relationship-meta'; var get = Ember.get; var set = Ember.set; @@ -343,13 +344,6 @@ RelationshipChange.prototype = { RelationshipChangeAdd.prototype = Ember.create(RelationshipChange.create({})); RelationshipChangeRemove.prototype = Ember.create(RelationshipChange.create({})); -function isSyncRelationship(record, relationshipName) { - var meta = Ember.meta(record); - var desc = meta.descs[relationshipName]; - - return desc && !desc._meta.options.async; -} - RelationshipChangeAdd.prototype.changeType = 'add'; RelationshipChangeAdd.prototype.sync = function() { var secondRecordName = this.getSecondRecordName(); diff --git a/packages/ember-data/lib/system/relationship-meta.js b/packages/ember-data/lib/system/relationship-meta.js index dbf472bfc18..bd6979b91cc 100644 --- a/packages/ember-data/lib/system/relationship-meta.js +++ b/packages/ember-data/lib/system/relationship-meta.js @@ -26,3 +26,10 @@ export function relationshipFromMeta(store, meta) { isRelationship: true }; } + +export function isSyncRelationship(record, relationshipName) { + var meta = Ember.meta(record); + var desc = meta.descs[relationshipName]; + + return desc && !desc._meta.options.async; +} diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index 9deedb71286..2299a720ae5 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -8,7 +8,8 @@ import { PromiseObject } from 'ember-data/system/store'; import { RelationshipChange } from 'ember-data/system/changes'; import { relationshipFromMeta, - typeForRelationshipMeta + typeForRelationshipMeta, + isSyncRelationship } from 'ember-data/system/relationship-meta'; /** @@ -168,7 +169,7 @@ Model.reopen({ @param key */ belongsToWillChange: Ember.beforeObserver(function(record, key) { - if (get(record, 'isLoaded')) { + if (get(record, 'isLoaded') && isSyncRelationship(record, key)) { var oldParent = get(record, key); if (oldParent) { diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index a232579b24d..711e1b8e45b 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -328,7 +328,7 @@ test("asdf", function() { env.adapter.deleteRecord = function(store, type, record) { ok(record instanceof type); - equal(record.id, 1, 'should first comment') + equal(record.id, 1, 'should first comment'); return record; }; @@ -338,3 +338,38 @@ test("asdf", function() { comment.destroyRecord(); }); + +test("Destroying a record with an unloaded aync belongsTo association does not fetch the record", function() { + expect(2); + var post; + + env.store.modelFor('message').reopen({ + user: DS.hasMany('user', { + async: true + }) + }); + + env.store.modelFor('post').reopen({ + user: DS.belongsTo('user', { + async: true, + inverse: 'messages' + }) + }); + + post = env.store.push('post', { + id: 1, + user: 2 + }); + + env.adapter.find = function() { + throw new Error("Adapter's find method should not be called"); + }; + + env.adapter.deleteRecord = function(store, type, record) { + ok(record instanceof type); + equal(record.id, 1, 'should first post'); + return record; + }; + + post.destroyRecord(); +}); From 35ce2c832930deefa5fc07a0b8a3aebe3d52b6f1 Mon Sep 17 00:00:00 2001 From: Garrett Heinlen Date: Tue, 5 Aug 2014 14:15:26 +1000 Subject: [PATCH 0290/2527] Update TRANSITION.md Fixing syntax. --- TRANSITION.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TRANSITION.md b/TRANSITION.md index 920340da992..dd9eea014f9 100644 --- a/TRANSITION.md +++ b/TRANSITION.md @@ -767,7 +767,7 @@ App.ApplicationSerializer = DS.RESTSerializer.extend({ json[key] = value; } -} +}); ``` ### Embedded Records From e9b9ba6e7afe37c2a2512cacb63922642929eff2 Mon Sep 17 00:00:00 2001 From: Mitch Lloyd Date: Tue, 5 Aug 2014 10:14:08 -0400 Subject: [PATCH 0291/2527] Fix typo --- packages/ember-data/lib/system/store.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 9be4e4590f3..523855b7845 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -237,9 +237,9 @@ Store = Ember.Object.extend({ newly created record. @return {DS.Model} record */ - createRecord: function(typeName, inputPropoperties) { + createRecord: function(typeName, inputProperties) { var type = this.modelFor(typeName); - var properties = copy(inputPropoperties) || {}; + var properties = copy(inputProperties) || {}; // If the passed properties do not include a primary key, // give the adapter an opportunity to generate one. Typically, From fa279d545bee73b5b11f937e8c82a224eefef703 Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 6 Aug 2014 00:44:31 +0100 Subject: [PATCH 0292/2527] Expose embedded options Exposes embedded options helpers while keeping them private. It is useful to have access to these, for example if one wanted to make embedding records the default behaviour for their serializer they could do that by overriding the helper methods. --- .../lib/serializers/embedded_records_mixin.js | 94 +++++++++---------- 1 file changed, 45 insertions(+), 49 deletions(-) diff --git a/packages/ember-data/lib/serializers/embedded_records_mixin.js b/packages/ember-data/lib/serializers/embedded_records_mixin.js index 915dddee3e7..765775b150f 100644 --- a/packages/ember-data/lib/serializers/embedded_records_mixin.js +++ b/packages/ember-data/lib/serializers/embedded_records_mixin.js @@ -114,7 +114,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ }, keyForRelationship: function(key, type){ - if (hasDeserializeRecordsOption(this.attrs, key)) { + if (this.hasDeserializeRecordsOption(key)) { return this.keyForAttribute(key); } else { return this._super(key, type) || key; @@ -173,12 +173,12 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ serializeBelongsTo: function(record, json, relationship) { var attr = relationship.key; var attrs = this.get('attrs'); - if (noSerializeOptionSpecified(attrs, attr)) { + if (this.noSerializeOptionSpecified(attr)) { this._super(record, json, relationship); return; } - var includeIds = hasSerializeIdsOption(attrs, attr); - var includeRecords = hasSerializeRecordsOption(attrs, attr); + var includeIds = this.hasSerializeIdsOption(attr); + var includeRecords = this.hasSerializeRecordsOption(attr); var embeddedRecord = record.get(attr); var key; if (includeIds) { @@ -283,12 +283,12 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ serializeHasMany: function(record, json, relationship) { var attr = relationship.key; var attrs = this.get('attrs'); - if (noSerializeOptionSpecified(attrs, attr)) { + if (this.noSerializeOptionSpecified(attr)) { this._super(record, json, relationship); return; } - var includeIds = hasSerializeIdsOption(attrs, attr); - var includeRecords = hasSerializeRecordsOption(attrs, attr); + var includeIds = this.hasSerializeIdsOption(attr); + var includeRecords = this.hasSerializeRecordsOption(attr); var key; if (includeIds) { key = this.keyForRelationship(attr, relationship.kind); @@ -333,60 +333,56 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ } } } - } -}); + }, -// checks config for attrs option to embedded (always) - serialize and deserialize -function hasEmbeddedAlwaysOption(attrs, attr) { - var option = attrsOption(attrs, attr); - return option && option.embedded === 'always'; -} + // checks config for attrs option to embedded (always) - serialize and deserialize + hasEmbeddedAlwaysOption: function (attr) { + var option = this.attrsOption(attr); + return option && option.embedded === 'always'; + }, -// checks config for attrs option to serialize ids -function hasSerializeRecordsOption(attrs, attr) { - var alwaysEmbed = hasEmbeddedAlwaysOption(attrs, attr); - var option = attrsOption(attrs, attr); - return alwaysEmbed || (option && (option.serialize === 'records')); -} + // checks config for attrs option to serialize ids + hasSerializeRecordsOption: function(attr) { + var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); + var option = this.attrsOption(attr); + return alwaysEmbed || (option && (option.serialize === 'records')); + }, -// checks config for attrs option to serialize records -function hasSerializeIdsOption(attrs, attr) { - var option = attrsOption(attrs, attr); - return option && (option.serialize === 'ids' || option.serialize === 'id'); -} + // checks config for attrs option to serialize records + hasSerializeIdsOption: function(attr) { + var option = this.attrsOption(attr); + return option && (option.serialize === 'ids' || option.serialize === 'id'); + }, -// checks config for attrs option to serialize records -function noSerializeOptionSpecified(attrs, attr) { - var option = attrsOption(attrs, attr); - var serializeRecords = hasSerializeRecordsOption(attrs, attr); - var serializeIds = hasSerializeIdsOption(attrs, attr); - return !(option && (option.serialize || option.embedded)); -} + // checks config for attrs option to serialize records + noSerializeOptionSpecified: function(attr) { + var option = this.attrsOption(attr); + var serializeRecords = this.hasSerializeRecordsOption(attr); + var serializeIds = this.hasSerializeIdsOption(attr); + return !(option && (option.serialize || option.embedded)); + }, -// checks config for attrs option to deserialize records -// a defined option object for a resource is treated the same as -// `deserialize: 'records'` -function hasDeserializeRecordsOption(attrs, attr) { - var alwaysEmbed = hasEmbeddedAlwaysOption(attrs, attr); - var option = attrsOption(attrs, attr); - return alwaysEmbed || (option && option.deserialize === 'records'); -} + // checks config for attrs option to deserialize records + // a defined option object for a resource is treated the same as + // `deserialize: 'records'` + hasDeserializeRecordsOption: function(attr) { + var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); + var option = this.attrsOption(attr); + return alwaysEmbed || (option && option.deserialize === 'records'); + }, -function attrsOption(attrs, attr) { - return attrs && (attrs[camelize(attr)] || attrs[attr]); -} + attrsOption: function(attr) { + var attrs = this.get('attrs'); + return attrs && (attrs[camelize(attr)] || attrs[attr]); + } +}); // chooses a relationship kind to branch which function is used to update payload // does not change payload if attr is not embedded function extractEmbeddedRecords(serializer, store, type, partial) { - var attrs = get(serializer, 'attrs'); - - if (!attrs) { - return partial; - } type.eachRelationship(function(key, relationship) { - if (hasDeserializeRecordsOption(attrs, key)) { + if (serializer.hasDeserializeRecordsOption(key)) { var embeddedType = store.modelFor(relationship.type.typeKey); if (relationship.kind === "hasMany") { extractEmbeddedHasMany(store, key, embeddedType, partial); From d4c65d79a3dbb07a227b9d7154d2dc8f0a38e017 Mon Sep 17 00:00:00 2001 From: Jonathan Collins Date: Sun, 3 Aug 2014 17:25:19 -0700 Subject: [PATCH 0293/2527] Batch hasMany requests with many id's to avoid max URL length issues --- .../ember-data/lib/adapters/rest_adapter.js | 31 +++++++++- .../integration/adapter/rest_adapter_test.js | 61 +++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 60d36ff59a2..6b833b7b5a1 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -595,13 +595,42 @@ export default Adapter.extend({ groupRecordsForFindMany: function (store, records) { var groups = Ember.MapWithDefault.create({defaultValue: function(){return [];}}); var adapter = this; + forEach.call(records, function(record){ var baseUrl = adapter._stripIDFromURL(store, record); groups.get(baseUrl).push(record); }); + + function splitGroupToFitInUrl(group, maxUrlLength) { + var baseUrl = adapter._stripIDFromURL(store, group[0]); + var idsSize = 0; + var splitGroups = [[]]; + + forEach.call(group, function(record) { + var additionalLength = '&ids[]='.length + record.get('id.length'); + if (baseUrl.length + idsSize + additionalLength >= maxUrlLength) { + idsSize = 0; + splitGroups.push([]); + } + + idsSize += additionalLength; + + var lastGroupIndex = splitGroups.length - 1; + splitGroups[lastGroupIndex].push(record); + }); + + return splitGroups; + } + var groupsArray = []; groups.forEach(function(key, group){ - groupsArray.push(group); + // http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers + var maxUrlLength = 2048; + var splitGroups = splitGroupToFitInUrl(group, maxUrlLength); + + forEach.call(splitGroups, function(splitGroup) { + groupsArray.push(splitGroup); + }); }); return groupsArray; diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 2277db9f760..10d0aa7ad35 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -1399,3 +1399,64 @@ test('normalizeKey - to set up _ids and _id', function() { deepEqual(post.get('comments').mapBy('body'), ["Rails is unagi", "What is omakase?"]); })); }); + +test('groupRecordsForFindMany splits up calls for large ids', function() { + Comment.reopen({ post: DS.belongsTo('post') }); + Post.reopen({ comments: DS.hasMany('comment', {async: true}) }); + + expect(2); + + function repeatChar(character, n) { + return Array(n+1).join(character); + } + + var a2000 = repeatChar('a', 2000); + var b2000 = repeatChar('b', 2000); + var post = store.push('post', { id: 1, comments: [a2000, b2000] }); + + adapter.coalesceFindRequests = true; + + adapter.find = function(store, type, id, record) { + if (id === a2000 || id === b2000) { + ok(true, "Found " + id) + } + + return Ember.RSVP.resolve({ comments: { id: id } }); + }; + + adapter.findMany = function(store, type, ids, records) { + ok(false, "findMany should not be called - we expect 2 calls to find for a2000 and b2000") + return Ember.RSVP.reject(); + } + + post.get('comments'); +}); + +test('groupRecordsForFindMany groups calls for small ids', function() { + Comment.reopen({ post: DS.belongsTo('post') }); + Post.reopen({ comments: DS.hasMany('comment', {async: true}) }); + + expect(1); + + function repeatChar(character, n) { + return Array(n+1).join(character); + } + + var a100 = repeatChar('a', 100); + var b100 = repeatChar('b', 100); + var post = store.push('post', { id: 1, comments: [a100, b100] }); + + adapter.coalesceFindRequests = true; + + adapter.find = function(store, type, id, record) { + ok(false, "find should not be called - we expect 1 call to findMany for a100 and b100") + return Ember.RSVP.reject(); + }; + + adapter.findMany = function(store, type, ids, records) { + deepEqual(ids, [a100, b100]); + return Ember.RSVP.resolve({ comments: { id: ids } }); + } + + post.get('comments'); +}); From 35969eae4895627fdd2e1ca9ea12524f129886f7 Mon Sep 17 00:00:00 2001 From: Tom Dale Date: Wed, 6 Aug 2014 17:37:08 -0700 Subject: [PATCH 0294/2527] Refactor hasMany code for comments and clarity --- .../lib/system/relationships/has_many.js | 138 +++++++++++------- 1 file changed, 84 insertions(+), 54 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index 8093ab79092..6dd013f44be 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -14,42 +14,71 @@ var set = Ember.set; var setProperties = Ember.setProperties; var map = Ember.EnumerableUtils.map; -function asyncHasMany(type, options, meta) { +/** + Returns a computed property that synchronously returns a ManyArray for + this relationship. If not all of the records in this relationship are + loaded, it will raise an exception. +*/ + +function syncHasMany(type, options, meta) { return Ember.computed('data', function(key) { - var relationship = this._relationships[key]; - var promiseLabel = "DS: Async hasMany " + this + " : " + key; + return buildRelationship(this, key, options, function(store, data) { + // Configure the metadata for the computed property to contain + // the key. + meta.key = key; + + var records = data[key]; + + Ember.assert("You looked up the '" + key + "' relationship on '" + this + "' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", Ember.A(records).isEvery('isEmpty', false)); + + return store.findMany(this, data[key], typeForRelationshipMeta(store, meta)); + }); + }).meta(meta).readOnly(); +} + +/** + Returns a computed property that itself returns a promise that resolves to a + ManyArray. + */ +function asyncHasMany(type, options, meta) { + return Ember.computed('data', function(key) { + // Configure the metadata for the computed property to contain + // the key. meta.key = key; - if (!relationship) { + var relationship = buildRelationship(this, key, options, function(store, data) { + var link = data.links && data.links[key]; + var rel; + var promiseLabel = "DS: Async hasMany " + this + " : " + key; var resolver = Ember.RSVP.defer(promiseLabel); - relationship = buildRelationship(this, key, options, function(store, data) { - var link = data.links && data.links[key]; - var rel; - if (link) { - rel = store.findHasMany(this, link, relationshipFromMeta(store, meta), resolver); - } else { - //This is a temporary workaround for setting owner on the relationship - //until single source of truth lands. It only works for OneToMany atm - var records = data[key]; - var inverse = this.constructor.inverseFor(key); - var owner = this; - if (inverse && records) { - if (inverse.kind === 'belongsTo'){ - map(records, function(record){ - set(record, inverse.name, owner); - }); - } + + if (link) { + rel = store.findHasMany(this, link, relationshipFromMeta(store, meta), resolver); + } else { + + //This is a temporary workaround for setting owner on the relationship + //until single source of truth lands. It only works for OneToMany atm + var records = data[key]; + var inverse = this.constructor.inverseFor(key); + var owner = this; + if (inverse && records) { + if (inverse.kind === 'belongsTo'){ + map(records, function(record){ + set(record, inverse.name, owner); + }); } - rel = store.findMany(owner, data[key], typeForRelationshipMeta(store, meta), resolver); } - // cache the promise so we can use it - // when we come back and don't need to rebuild - // the relationship. - set(rel, 'promise', resolver.promise); - return rel; - }); - } + + rel = store.findMany(owner, data[key], typeForRelationshipMeta(store, meta), resolver); + } + + // Cache the promise so we can use it when we come back and don't + // need to rebuild the relationship. + set(rel, 'promise', resolver.promise); + + return rel; + }); var promise = relationship.get('promise').then(function() { return relationship; @@ -61,6 +90,12 @@ function asyncHasMany(type, options, meta) { }).meta(meta).readOnly(); } +/* + Builds the ManyArray for a relationship using the provided callback, + but only if it had not been created previously. After building, it + sets some metadata on the created ManyArray, such as the record which + owns it and the name of the relationship. +*/ function buildRelationship(record, key, options, callback) { var rels = record._relationships; @@ -78,30 +113,6 @@ function buildRelationship(record, key, options, callback) { }); } -function hasRelationship(type, options) { - options = options || {}; - - var meta = { - type: type, - isRelationship: true, - options: options, - kind: 'hasMany', - key: null - }; - - if (options.async) { - return asyncHasMany(type, options, meta); - } - - return Ember.computed('data', function(key) { - return buildRelationship(this, key, options, function(store, data) { - var records = data[key]; - Ember.assert("You looked up the '" + key + "' relationship on '" + this + "' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", Ember.A(records).isEvery('isEmpty', false)); - return store.findMany(this, data[key], typeForRelationshipMeta(store, meta)); - }); - }).meta(meta).readOnly(); -} - /** `DS.hasMany` is used to define One-To-Many and Many-To-Many relationships on a [DS.Model](/api/data/classes/DS.Model.html). @@ -185,7 +196,26 @@ function hasMany(type, options) { options = type; type = undefined; } - return hasRelationship(type, options); + + options = options || {}; + + // Metadata about relationships is stored on the meta of + // the relationship. This is used for introspection and + // serialization. Note that `key` is populated lazily + // the first time the CP is called. + var meta = { + type: type, + isRelationship: true, + options: options, + kind: 'hasMany', + key: null + }; + + if (options.async) { + return asyncHasMany(type, options, meta); + } else { + return syncHasMany(type, options, meta); + } } export default hasMany; From f6317206d0851affb625abbf760286fd37ab41f1 Mon Sep 17 00:00:00 2001 From: Doug Yun Date: Mon, 11 Aug 2014 22:02:46 -0400 Subject: [PATCH 0295/2527] Brocfile: Adds hinting for node. * Won't complain about `process` anymore. --- Brocfile.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Brocfile.js b/Brocfile.js index 6448e1a5156..b97fcaf15d9 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -1,3 +1,5 @@ +/* jshint node: true */ + var es6 = require('broccoli-es6-module-transpiler'); var concat = require('broccoli-concat'); var uglify = require('broccoli-uglify-js'); From 3c164079c2e3937f84bad1a1a60703d05b6a3688 Mon Sep 17 00:00:00 2001 From: Doug Yun Date: Mon, 11 Aug 2014 22:27:04 -0400 Subject: [PATCH 0296/2527] Adds JSHint globals. * Adds semicolons. --- tests/ember-data-setup.js | 4 +++- tests/ember_configuration.js | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/ember-data-setup.js b/tests/ember-data-setup.js index 35f2b9bfef5..c023b5d5ee7 100644 --- a/tests/ember-data-setup.js +++ b/tests/ember-data-setup.js @@ -1,3 +1,5 @@ +/* globals syncForTest */ + ;(function(){ Ember.RSVP.configure('onerror', function(reason) { @@ -5,7 +7,7 @@ // otherwise, let a future turn of the event loop // handle the error. if (reason && reason instanceof Error) { - Ember.Logger.log(reason, reason.stack) + Ember.Logger.log(reason, reason.stack); throw reason; } }); diff --git a/tests/ember_configuration.js b/tests/ember_configuration.js index fe57ce2f218..d0d80ac5c11 100644 --- a/tests/ember_configuration.js +++ b/tests/ember_configuration.js @@ -1,4 +1,4 @@ -/*globals ENV QUnit */ +/* globals ENV, QUnit */ (function (){ window.Ember = window.Ember || {}; @@ -132,7 +132,7 @@ // otherwise, let a future turn of the event loop // handle the error. if (reason && reason instanceof Error) { - Ember.Logger.log(reason, reason.stack) + Ember.Logger.log(reason, reason.stack); throw reason; } }); From bc7cd77eca7bb47a1964187bae8985453e20c087 Mon Sep 17 00:00:00 2001 From: Jonathan Jackson Date: Tue, 12 Aug 2014 13:31:28 -0400 Subject: [PATCH 0297/2527] Remove unused requires This includes removeFile which is not referenced anywhere in the Brocfile. It also removes the top require for defeaturify which is required locally within minify() --- Brocfile.js | 1 - package.json | 1 - 2 files changed, 2 deletions(-) diff --git a/Brocfile.js b/Brocfile.js index b97fcaf15d9..49bf6571aa0 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -8,7 +8,6 @@ var env = process.env.EMBER_ENV; var pickFiles = require('broccoli-static-compiler'); var merge = require('broccoli-merge-trees'); var moveFile = require('broccoli-file-mover'); -var removeFile = require('broccoli-file-remover'); var wrap = require('broccoli-wrap'); var jshint = require('broccoli-jshint'); var defeatureify = require('broccoli-defeatureify'); diff --git a/package.json b/package.json index adfde6d488f..43a5a35b403 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "broccoli-es6-module-transpiler": "^0.1.1", "broccoli-es6-transpiler": "^0.1.0", "broccoli-file-mover": "~0.2.0", - "broccoli-file-remover": "^0.2.2", "broccoli-jshint": "^0.5.1", "broccoli-merge-trees": "^0.1.4", "broccoli-render-template": "0.0.3", From b3c6d248b0f20b12a47b05819cb81d083258147e Mon Sep 17 00:00:00 2001 From: Pepe Cano Date: Wed, 13 Aug 2014 17:17:21 +0200 Subject: [PATCH 0298/2527] Add support for JSONSerializer.attrs.key.serialize for `hasMany` and `belongsTo` relationships --- .../lib/serializers/json_serializer.js | 105 ++++++++++-------- .../serializers/json_serializer_test.js | 36 ++++++ 2 files changed, 96 insertions(+), 45 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 78b658a97f6..24679eb43e6 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -289,6 +289,21 @@ export default Ember.Object.extend({ return key; }, + /** + Check attrs.key.serialize property to inform if the `key` + can be serialized + + @method _canSerialize + @private + @param {String} key + @return {boolean} true if the key can be serialized + */ + _canSerialize: function(key) { + var attrs = get(this, 'attrs'); + + return !attrs || !attrs[key] || attrs[key].serialize !== false; + }, + // SERIALIZE /** Called when a record is saved in order to convert the @@ -511,29 +526,25 @@ export default Ember.Object.extend({ @param {Object} attribute */ serializeAttribute: function(record, json, key, attribute) { - var attrs = get(this, 'attrs'); - var value = get(record, key); var type = attribute.type; - if (type) { - var transform = this.transformFor(type); - value = transform.serialize(value); - } + if (this._canSerialize(key)) { + var value = get(record, key); + if (type) { + var transform = this.transformFor(type); + value = transform.serialize(value); + } - // If attrs.key.serialize is false, do not include the value in the - // response to the server at all. - if (attrs && attrs[key] && attrs[key].serialize === false) { - return; - } - // if provided, use the mapping provided by `attrs` in - // the serializer - var payloadKey = this._getMappedKey(key); + // if provided, use the mapping provided by `attrs` in + // the serializer + var payloadKey = this._getMappedKey(key); - if (payloadKey === key && this.keyForAttribute) { - payloadKey = this.keyForAttribute(key); - } + if (payloadKey === key && this.keyForAttribute) { + payloadKey = this.keyForAttribute(key); + } - json[payloadKey] = value; + json[payloadKey] = value; + } }, /** @@ -562,25 +573,27 @@ export default Ember.Object.extend({ @param {Object} relationship */ serializeBelongsTo: function(record, json, relationship) { - var attrs = get(this, 'attrs'); var key = relationship.key; - var belongsTo = get(record, key); - // if provided, use the mapping provided by `attrs` in - // the serializer - var payloadKey = this._getMappedKey(key); - if (payloadKey === key && this.keyForRelationship) { - payloadKey = this.keyForRelationship(key, "belongsTo"); - } + if (this._canSerialize(key)) { + var belongsTo = get(record, key); - if (isNone(belongsTo)) { - json[payloadKey] = belongsTo; - } else { - json[payloadKey] = get(belongsTo, 'id'); - } + // if provided, use the mapping provided by `attrs` in + // the serializer + var payloadKey = this._getMappedKey(key); + if (payloadKey === key && this.keyForRelationship) { + payloadKey = this.keyForRelationship(key, "belongsTo"); + } - if (relationship.options.polymorphic) { - this.serializePolymorphicType(record, json, relationship); + if (isNone(belongsTo)) { + json[payloadKey] = belongsTo; + } else { + json[payloadKey] = get(belongsTo, 'id'); + } + + if (relationship.options.polymorphic) { + this.serializePolymorphicType(record, json, relationship); + } } }, @@ -609,22 +622,24 @@ export default Ember.Object.extend({ @param {Object} relationship */ serializeHasMany: function(record, json, relationship) { - var attrs = get(this, 'attrs'); var key = relationship.key; - var payloadKey; - // if provided, use the mapping provided by `attrs` in - // the serializer - payloadKey = this._getMappedKey(key); - if (payloadKey === key && this.keyForRelationship) { - payloadKey = this.keyForRelationship(key, "hasMany"); - } + if (this._canSerialize(key)) { + var payloadKey; - var relationshipType = RelationshipChange.determineRelationshipType(record.constructor, relationship); + // if provided, use the mapping provided by `attrs` in + // the serializer + payloadKey = this._getMappedKey(key); + if (payloadKey === key && this.keyForRelationship) { + payloadKey = this.keyForRelationship(key, "hasMany"); + } + + var relationshipType = RelationshipChange.determineRelationshipType(record.constructor, relationship); - if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') { - json[payloadKey] = get(record, key).mapBy('id'); - // TODO support for polymorphic manyToNone and manyToMany relationships + if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') { + json[payloadKey] = get(record, key).mapBy('id'); + // TODO support for polymorphic manyToNone and manyToMany relationships + } } }, diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index 07a2573190e..bf008130866 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -216,6 +216,42 @@ test('Serializer respects `serialize: false` on the attrs hash', function(){ ok(!payload.hasOwnProperty('[object Object]'),"Does not add some random key like [object Object]"); }); +test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` property', function(){ + expect(1); + env.container.register("serializer:post", DS.JSONSerializer.extend({ + attrs: { + comments: {serialize: false} + } + })); + + post = env.store.createRecord("post", { title: "Rails is omakase"}); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + + var serializer = env.container.lookup("serializer:post"); + var serializedProperty = serializer.keyForRelationship('comments', 'hasMany'); + + var payload = serializer.serialize(post); + ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); +}); + +test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` property', function(){ + expect(1); + env.container.register("serializer:comment", DS.JSONSerializer.extend({ + attrs: { + post: {serialize: false} + } + })); + + post = env.store.createRecord("post", { title: "Rails is omakase"}); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + + var serializer = env.container.lookup("serializer:comment"); + var serializedProperty = serializer.keyForRelationship('post', 'belongsTo'); + + var payload = serializer.serialize(comment); + ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); +}); + test("Serializer should respect the primaryKey attribute when extracting records", function() { env.container.register('serializer:post', DS.JSONSerializer.extend({ primaryKey: '_ID_' From 8ed4a76a7e4f50c72e3cded2388df91a0f3c0ce4 Mon Sep 17 00:00:00 2001 From: Pepe Cano Date: Wed, 13 Aug 2014 20:05:07 +0200 Subject: [PATCH 0299/2527] Substitute serialize:no to serialize:false in EmbeddedRecordsMixin --- .../lib/serializers/embedded_records_mixin.js | 6 ++--- .../embedded_records_mixin_test.js | 26 ++++++++++++++++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/packages/ember-data/lib/serializers/embedded_records_mixin.js b/packages/ember-data/lib/serializers/embedded_records_mixin.js index 765775b150f..3d115ce2d80 100644 --- a/packages/ember-data/lib/serializers/embedded_records_mixin.js +++ b/packages/ember-data/lib/serializers/embedded_records_mixin.js @@ -31,7 +31,7 @@ import {pluralize} from "ember-inflector"; ### Configuring Attrs - A resource's `attrs` option may be set to use `ids`, `records` or `no` for the + A resource's `attrs` option may be set to use `ids`, `records` or false for the `serialize` and `deserialize` settings. The `attrs` property can be set on the ApplicationSerializer or a per-type @@ -43,7 +43,7 @@ import {pluralize} from "ember-inflector"; the vanilla EmbeddedRecordsMixin. Likewise, to embed JSON in the payload while serializing `serialize: 'records'` is the setting to use. There is an option of not embedding JSON in the serialized payload by using `serialize: 'ids'`. If you - do not want the relationship sent at all, you can use `serialize: 'no'`. + do not want the relationship sent at all, you can use `serialize: false`. ### EmbeddedRecordsMixin defaults @@ -51,7 +51,7 @@ import {pluralize} from "ember-inflector"; will behave in the following way: BelongsTo: `{serialize:'id', deserialize:'id'}` - HasMany: `{serialize:'no', deserialize:'ids'}` + HasMany: `{serialize:false, deserialize:'ids'}` ### Model Relationships diff --git a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js index 4ad3b41deca..7126c7fe601 100644 --- a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js +++ b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js @@ -504,6 +504,24 @@ test("extractArray with embedded objects of same type, but from separate attribu equal(env.store.recordForId("superVillain", "6").get("firstName"), "Trek", "Secondary records found in the store"); }); +test("serialize supports serialize:false on non-relationship properties", function() { + var tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", id: '1' }); + + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + firstName: {serialize: false} + } + })); + var serializer = env.container.lookup("serializer:superVillain"); + var json = serializer.serialize(tom); + + deepEqual(json, { + last_name: "Dale", + home_planet_id: null, + secret_lab_id: null + }); +}); + test("serialize with embedded objects (hasMany relationship)", function() { league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); var tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); @@ -529,13 +547,13 @@ test("serialize with embedded objects (hasMany relationship)", function() { }); }); -test("serialize with embedded objects (hasMany relationship) supports serialize:no", function() { +test("serialize with embedded objects (hasMany relationship) supports serialize:false", function() { league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); var tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - villains: {serialize: 'no'} + villains: {serialize: false} } })); var serializer = env.container.lookup("serializer:homePlanet"); @@ -804,11 +822,11 @@ test("serialize with embedded object (belongsTo relationship) supports serialize }); }); -test("serialize with embedded object (belongsTo relationship) supports serialize:no", function() { +test("serialize with embedded object (belongsTo relationship) supports serialize:false", function() { env.container.register('adapter:superVillain', DS.ActiveModelAdapter); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - secretLab: {serialize: 'no'} + secretLab: {serialize: false} } })); var serializer = env.container.lookup("serializer:superVillain"); From 3ec29287b1058d6c5670092b1bbe576b23b3384d Mon Sep 17 00:00:00 2001 From: Philip Nelson Date: Thu, 14 Aug 2014 08:21:49 -0700 Subject: [PATCH 0300/2527] [DOC] Add plural example for REST adapter. --- .../ember-data/lib/adapters/rest_adapter.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 6b833b7b5a1..de82599600b 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -34,6 +34,24 @@ var forEach = Ember.ArrayPolyfills.forEach; } ``` + Similarly, in response to a `GET` request for `/posts`, the JSON should + look like this: + + ```js + { + "posts": [ + { + "title": "I'm Running to Reform the W3C's Tag", + "author": "Yehuda Katz" + }, + { + "title": "Rails is omakase", + "author": "D2H" + } + ] + } + ``` + ### Conventional Names Attribute names in your JSON payload should be the camelCased versions of From b17fb9cc3dc1f2e99dd94fd44d59d9cc6a8de6cc Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 14 Aug 2014 10:24:19 -0500 Subject: [PATCH 0301/2527] temporarily use uncached npm --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 417f5b3c526..2f127a5a49c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: node_js node_js: - "0.10" install: -- "bin/cached-npm install" +- "npm install" - "bower install" - "npm run-script dist" script: From d2625c3a1de14e637d488d6083023dfbf066f4e5 Mon Sep 17 00:00:00 2001 From: Bill Heaton Date: Thu, 14 Aug 2014 10:21:44 -0700 Subject: [PATCH 0302/2527] [Doc] Fix typo, your, not you in DS.Store#update method comments --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 523855b7845..7225ff39a62 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1395,7 +1395,7 @@ Store = Ember.Object.extend({ properties. This makes it safe to use with a subset of record attributes. This method expects normalized data. - `update` is useful if you app broadcasts partial updates to + `update` is useful if your app broadcasts partial updates to records. ```js From 239b76024630094adad50818ba0837678205077f Mon Sep 17 00:00:00 2001 From: Jeff Winkler Date: Thu, 14 Aug 2014 14:31:48 -0400 Subject: [PATCH 0303/2527] "records object" -> "record objects" --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 7225ff39a62..6038848908b 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -93,7 +93,7 @@ function coerceId(id) { ### Store createRecord() vs. push() vs. pushPayload() vs. update() - The store provides multiple ways to create new records object. They have + The store provides multiple ways to create new record objects. They have some subtle differences in their use which are detailed below: [createRecord](#method_createRecord) is used for creating new From 3d7d4a216db4a0daa42fd2a7ffb416555dd86bef Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Fri, 15 Aug 2014 10:42:31 -0400 Subject: [PATCH 0304/2527] [DOCS] Add ids to RESTAdapter JSON payload examples --- packages/ember-data/lib/adapters/rest_adapter.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index de82599600b..e97ac590624 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -28,6 +28,7 @@ var forEach = Ember.ArrayPolyfills.forEach; ```js { "post": { + "id": 1, "title": "I'm Running to Reform the W3C's Tag", "author": "Yehuda Katz" } @@ -41,10 +42,12 @@ var forEach = Ember.ArrayPolyfills.forEach; { "posts": [ { + "id": 1, "title": "I'm Running to Reform the W3C's Tag", "author": "Yehuda Katz" }, { + "id": 2, "title": "Rails is omakase", "author": "D2H" } @@ -72,6 +75,7 @@ var forEach = Ember.ArrayPolyfills.forEach; ```js { "person": { + "id": 5, "firstName": "Barack", "lastName": "Obama", "occupation": "President" From c07d74fa2b32e5f1f3575dd57ad726e6e8bb1a56 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sun, 17 Aug 2014 17:17:23 -0500 Subject: [PATCH 0305/2527] bring in ember-inflector 1.1.0 --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index f7a3a668970..611d7a639b3 100644 --- a/bower.json +++ b/bower.json @@ -9,6 +9,6 @@ }, "devDependencies": { "loader.js": "~1.0.0", - "ember-inflector": "https://github.com/stefanpenner/ember-inflector.git#v1.0.0" + "ember-inflector": "https://github.com/stefanpenner/ember-inflector.git#v1.1.0" } } From f0f68a9b2cfa9439fa6e4228b3702d2959f95c84 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sun, 17 Aug 2014 17:37:47 -0500 Subject: [PATCH 0306/2527] v 1.0.0-beta.9 changelog --- CHANGELOG.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 409ea7aaba3..f46b438eca0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,51 @@ ### Master +### Ember Data 1.0.0-beta.9 _(August 18, 2014)_ + +* bring in ember-inflector 1.1.0 +* [DOCS] Add ids to RESTAdapter JSON payload examples +* [Doc] Fix typo, your, not you in DS.Store#update method comments +* [DOC] Add plural example for REST adapter. +* Substitute serialize:no to serialize:false in EmbeddedRecordsMixin +* Add support for JSONSerializer.attrs.key.serialize for `hasMany` and `belongsTo` relationships +* Refactor hasMany code for comments and clarity +* Batch hasMany requests with many id's to avoid max URL length issues +* Expose embedded options +* Changing an async belongsTo association does not load unfetched record. +* [Bugfix] relationship changes shouldn’t cause async fetches +* loosen constraint of adapter method return values +* Move EmbeddedRecordsMixin to core from activemodel +* Correct various yuidoc warnings to clean up some console noise when build the api docs +* factor out promise usage +* Do not serialize fixtures when deleting +* Refactor JSON serializer to use _getMappedKey +* Don't normalize the key if not present in the hash +* Add serializeIntoHash to the JSON Serializer +* prefer Object.create(null) for typeMap backing stores. Cache misses are faster, and won’t collide with prototype pollution +* since the recordArrayManager already maintains the uniq index, we can use that to simply push the record onto the record array without needing the safety of addRecords dupe guard. This prevents another O(n) operation +* the string splitting in transitionTo is wasteful and for large payloads can be surprisingly costly. As they never actually change, we should simply cache and forget about them. +* Coalesce find requests, add support for preloading data +* allow attributes to be excluded via the attrs hash * DS.DateTransform now serializes to ISO8601 format by default. Adds millisecond precision to serializing dates +* Added id and requestType back to extract* hooks +* Moved several normalize helper methods to the JSONSerializer - Move `normalizeAttributes` to the `JSONSerializer` (mirrors `serializeAttributes`) - Move `normalizeRelationships` to the `JSONSerializer` - Move `normalizePayload` to the `JSONSerializer` +* Throw an error if a user attempts to add a `data` property to a subclass of DS.Model +* Add a store.normalize() method to make it easy to normalize record data for store.push() +* Add a test for embedded belongsTo with a custom primaryKey +* Refactored EmbeddedRecordsMixin to push records instead of sideload +* PERF: O(n) -> O(1) record within recordArray check +* Add guard before deleting partial[attribute] +* Fixes embedded hasMany primary key lookup. +* Allow `attr` mapping in `belongsTo` & `hasMany` attributes; +* Favour declared mapping over keyForAttribute, if defined; +* improve debug ergonomics (as I debug) +* rest_adapter: Remove unused `set` definition +* Added documentation for ajaxError with DS.Errors. +* updated '_links' to just 'links' +* Better error for missing inverse on hasMany/belongsTo +* adapt usage example for TemperatureTransform +* [Bugfix] Decouple DS.EmbeddedRecordsMixin from DS.ActiveModelSerializer ### Ember Data 1.0.0-beta.8 _(May 28, 2014)_ From 44dbabf50cdc1fd4517367946f85f791455198f7 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sun, 17 Aug 2014 17:41:05 -0500 Subject: [PATCH 0307/2527] add note about IE8 needing Object.create shim --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f46b438eca0..8cd31ad641a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ ### Ember Data 1.0.0-beta.9 _(August 18, 2014)_ +**Important:** IE8 and other environments which don't support `Object.create` +correctly will need a shim for Object.create. + * bring in ember-inflector 1.1.0 * [DOCS] Add ids to RESTAdapter JSON payload examples * [Doc] Fix typo, your, not you in DS.Store#update method comments From 88da70e4cd8aea20863a97a01cfac2ba1d1b8e73 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sun, 17 Aug 2014 17:43:26 -0500 Subject: [PATCH 0308/2527] release v1.0.0-beta.9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 43a5a35b403..196b86a2971 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.9+canary", + "version": "1.0.0-beta.9", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", From e704d90ec673732d7983a654b4f8ceef93d49d53 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sun, 17 Aug 2014 17:45:21 -0500 Subject: [PATCH 0309/2527] post release version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 196b86a2971..d9fce8a2e3d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.9", + "version": "1.0.0-beta.10+canary", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", From 72a901b685767b095e9b7485b068a54e5c1fb3c8 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Tue, 19 Aug 2014 14:02:27 +0100 Subject: [PATCH 0310/2527] [Documentation] typo in `find` documentation --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 6038848908b..30ec3c9ba84 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -356,7 +356,7 @@ Store = Ember.Object.extend({ You can optionally preload specific attributes and relationships that you know of by passing them as the third argument to find. - For example, if your Ember route looks like `/posts/1/comments/2` and you API route + For example, if your Ember route looks like `/posts/1/comments/2` and your API route for the comment also looks like `/posts/1/comments/2` if you want to fetch the comment without fetching the post you can pass in the post to the `find` call: From a9c9dc047fb801a893e66274e8b7374b7babd1db Mon Sep 17 00:00:00 2001 From: Craig Tataryn Date: Tue, 19 Aug 2014 10:52:53 -0500 Subject: [PATCH 0311/2527] Added documentation for preload parameter Documented the purpose of the `preload` parameter on the `find` and `findById` functions --- packages/ember-data/lib/system/store.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 30ec3c9ba84..9f360d2191c 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -404,6 +404,7 @@ Store = Ember.Object.extend({ @method find @param {String or subclass of DS.Model} type @param {Object|String|Integer|null} id + @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models @return {Promise} promise */ find: function(type, id, preload) { @@ -429,6 +430,7 @@ Store = Ember.Object.extend({ @private @param {String or subclass of DS.Model} type @param {String|Integer} id + @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models @return {Promise} promise */ findById: function(typeName, id, preload) { From 2d354c41bde4cd7b70b78045fe92857226ebfe84 Mon Sep 17 00:00:00 2001 From: gslot Date: Tue, 19 Aug 2014 10:53:43 -0500 Subject: [PATCH 0312/2527] Update model.js --- packages/ember-data/lib/system/model/model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 373520680ca..059a640a3a4 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -645,7 +645,7 @@ var Model = Ember.Object.extend(Ember.Evented, { }, /** - When a find request is triggered on the store, the user can optionally passed in + When a find request is triggered on the store, the user can optionally pass in attributes and relationships to be preloaded. These are meant to behave as if they came back from the server, expect the user obtained them out of band and is informing the store of their existence. The most common use case is for supporting client side From f393c10441ba358910e16d0fc9e0fd916b38f792 Mon Sep 17 00:00:00 2001 From: Craig Tataryn Date: Tue, 19 Aug 2014 20:04:41 -0500 Subject: [PATCH 0313/2527] Added an example of how to use the preload arg As per @bmac's suggestion to swipe the example from system/model.js's _preloadData function --- packages/ember-data/lib/system/store.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 9f360d2191c..b9eeb92250f 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -401,6 +401,13 @@ Store = Ember.Object.extend({ the query, and return a promise that will be resolved once the server responds. + When a find request is triggered on the store, the user can optionally pass in + attributes and relationships to be preloaded. These are meant to behave as if they + came back from the server, expect the user obtained them out of band and is informing + the store of their existence. The most common use case is for supporting client side + nested URLs, such as `/posts/1/comments/2` so the user can do + `store.find('comment', 2, {post:1})` without having to fetch the post. + @method find @param {String or subclass of DS.Model} type @param {Object|String|Integer|null} id From 908a2798ec02ae068f663094ef3bd1ee9d7f9a49 Mon Sep 17 00:00:00 2001 From: Craig Tataryn Date: Tue, 19 Aug 2014 22:21:19 -0500 Subject: [PATCH 0314/2527] Fixed typo Fixed typo caught by @chrisvariety --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index b9eeb92250f..821162a5884 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -403,7 +403,7 @@ Store = Ember.Object.extend({ When a find request is triggered on the store, the user can optionally pass in attributes and relationships to be preloaded. These are meant to behave as if they - came back from the server, expect the user obtained them out of band and is informing + came back from the server, except the user obtained them out of band and is informing the store of their existence. The most common use case is for supporting client side nested URLs, such as `/posts/1/comments/2` so the user can do `store.find('comment', 2, {post:1})` without having to fetch the post. From e4cec8de772df40c4513cb1e196e19755403f531 Mon Sep 17 00:00:00 2001 From: Craig Tataryn Date: Tue, 19 Aug 2014 22:25:07 -0500 Subject: [PATCH 0315/2527] Fixed typo Fixed typo caught in https://github.com/emberjs/data/pull/2198 --- packages/ember-data/lib/system/model/model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 059a640a3a4..cf944d54690 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -647,7 +647,7 @@ var Model = Ember.Object.extend(Ember.Evented, { /** When a find request is triggered on the store, the user can optionally pass in attributes and relationships to be preloaded. These are meant to behave as if they - came back from the server, expect the user obtained them out of band and is informing + came back from the server, except the user obtained them out of band and is informing the store of their existence. The most common use case is for supporting client side nested URLs, such as `/posts/1/comments/2` so the user can do `store.find('comment', 2, {post:1})` without having to fetch the post. From 52b08fa092dd045b4636fb9fc5c72caed43c7ade Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 20 Aug 2014 10:32:56 +0100 Subject: [PATCH 0316/2527] Don't use the DOM in the store tests Using the DOM in the store test was breaking the build on Travis due to Runloop complaints. There really isn't a reason why the DOM use is needed, so I refactored the test instead of messing with the Runloop. --- .../tests/unit/store/adapter_interop_test.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/ember-data/tests/unit/store/adapter_interop_test.js b/packages/ember-data/tests/unit/store/adapter_interop_test.js index bbc233c87b2..b248818794f 100644 --- a/packages/ember-data/tests/unit/store/adapter_interop_test.js +++ b/packages/ember-data/tests/unit/store/adapter_interop_test.js @@ -417,7 +417,7 @@ test("initial values of hasMany can be passed in as the third argument to find a equal(store.getById(Person, 1).get('friends').toArray()[0].get('id'), '2', 'Preloaded hasMany set'); }); -test("records inside a collection view should have their ids updated", function() { +test("records should have their ids updated when the adapter returns the id data", function() { var Person = DS.Model.extend(); var idCounter = 1; @@ -431,21 +431,15 @@ test("records inside a collection view should have their ids updated", function( adapter: adapter }); - var container = Ember.CollectionView.create({ - content: store.all(Person) - }); - - container.appendTo('#qunit-fixture'); + var people = store.all(Person); var tom = store.createRecord(Person, {name: 'Tom Dale'}); var yehuda = store.createRecord(Person, {name: 'Yehuda Katz'}); Ember.RSVP.all([ tom.save(), yehuda.save() ]).then(async(function() { - container.content.forEach(function(person, index) { + people.forEach(function(person, index) { equal(person.get('id'), index + 1, "The record's id should be correct."); }); - - container.destroy(); })); }); From 14c5bbaeec33e1fcce6bc0a5603dd050c90e7c32 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 20 Aug 2014 10:36:49 -0500 Subject: [PATCH 0317/2527] modelFor is used constantly, the extra normalization and string splitting was causing measurable slowdown. --- packages/ember-data/lib/system/store.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 30ec3c9ba84..e43b83385ad 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1211,11 +1211,11 @@ Store = Ember.Object.extend({ var factory; if (typeof key === 'string') { - var normalizedKey = this.container.normalize('model:' + key); - - factory = this.container.lookupFactory(normalizedKey); - if (!factory) { throw new Ember.Error("No model was found for '" + key + "'"); } - factory.typeKey = this._normalizeTypeKey(normalizedKey.split(':', 2)[1]); + factory = this.container.lookupFactory('model:' + key); + if (!factory) { + throw new Ember.Error("No model was found for '" + key + "'"); + } + factory.typeKey = factory.typeKey || this._normalizeTypeKey(key); } else { // A factory already supplied. Ensure it has a normalized key. factory = key; From 4284a062ce06a1cc9b50afc4f04c4bf42ea2cd17 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 20 Aug 2014 10:54:55 -0500 Subject: [PATCH 0318/2527] name some common anonymous functions --- .../ember-data/lib/serializers/json_serializer.js | 2 +- packages/ember-data/lib/system/model/model.js | 14 +++++++------- packages/ember-data/lib/system/store.js | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index ac71a087542..f7e2ece6163 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -110,7 +110,7 @@ export default Ember.Object.extend({ @return {Object} data The transformed data object */ applyTransforms: function(type, data) { - type.eachTransformedAttribute(function(key, type) { + type.eachTransformedAttribute(function applyTransform(key, type) { if (!data.hasOwnProperty(key)) { return; } var transform = this.transformFor(type); diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index cf944d54690..5a5cb685f4b 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -770,9 +770,7 @@ var Model = Ember.Object.extend(Ember.Evented, { if (!data) { return; } - this.suspendRelationshipObservers(function() { - this.notifyPropertyChange('data'); - }); + this._dataDidChange(); }, /** @@ -846,9 +844,7 @@ var Model = Ember.Object.extend(Ember.Evented, { if (data) { this.pushedData(); } - this.suspendRelationshipObservers(function() { - this.notifyPropertyChange('data'); - }); + this._dataDidChange(); }, materializeId: function(id) { @@ -915,7 +911,11 @@ var Model = Ember.Object.extend(Ember.Evented, { this.send('rolledBack'); - this.suspendRelationshipObservers(function() { + this._dataDidChange(); + }, + + _dataDidChange: function() { + this.suspendRelationshipObservers(function _dataDidChange_suspectRelationshipObservers() { this.notifyPropertyChange('data'); }); }, diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 30ec3c9ba84..51ee3111b0a 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1438,7 +1438,7 @@ Store = Ember.Object.extend({ @return {Array} */ pushMany: function(type, datas) { - return map(datas, function(data) { + return map(datas, function pushEach(data) { return this.push(type, data); }, this); }, From ab26542b58ea8a8e50391883c24a9e2b20a0c311 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 20 Aug 2014 12:00:26 -0500 Subject: [PATCH 0319/2527] small perf, this map was unfortunately adding 5ms -> 8ms overhead for pushMany of N=1000. Removing it removed the overhead entirely. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Maybe at some point runtimes will actually optimize this… --- packages/ember-data/lib/system/store.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index e43b83385ad..d5fabc0bbcb 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1438,9 +1438,14 @@ Store = Ember.Object.extend({ @return {Array} */ pushMany: function(type, datas) { - return map(datas, function(data) { - return this.push(type, data); - }, this); + var length = datas.length; + var result = new Array(length); + + for (var i = 0; i < length; i++) { + result[i] = this.push(type, datas[i]); + } + + return result; }, /** From c2ba64f4c1a1939c17064b78ce1dc13444aae7a8 Mon Sep 17 00:00:00 2001 From: Craig Tataryn Date: Wed, 20 Aug 2014 12:55:11 -0500 Subject: [PATCH 0320/2527] Removed a duplicate explanation of preload Removed what is essentially a duplicate explanation of `preload` as per @igorT --- packages/ember-data/lib/system/store.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 821162a5884..3087fca41fa 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -353,7 +353,7 @@ Store = Ember.Object.extend({ --- - You can optionally preload specific attributes and relationships that you know of + You can optionally `preload` specific attributes and relationships that you know of by passing them as the third argument to find. For example, if your Ember route looks like `/posts/1/comments/2` and your API route @@ -401,13 +401,6 @@ Store = Ember.Object.extend({ the query, and return a promise that will be resolved once the server responds. - When a find request is triggered on the store, the user can optionally pass in - attributes and relationships to be preloaded. These are meant to behave as if they - came back from the server, except the user obtained them out of band and is informing - the store of their existence. The most common use case is for supporting client side - nested URLs, such as `/posts/1/comments/2` so the user can do - `store.find('comment', 2, {post:1})` without having to fetch the post. - @method find @param {String or subclass of DS.Model} type @param {Object|String|Integer|null} id From 85edb78b5ad811b55f2ea4f9dc0709a72098b2c2 Mon Sep 17 00:00:00 2001 From: Josh Padnick Date: Wed, 20 Aug 2014 21:02:08 -0700 Subject: [PATCH 0321/2527] Updated docs to warn against use of async:true with EmbeddedRecodsMixin --- .../lib/serializers/embedded_records_mixin.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/embedded_records_mixin.js b/packages/ember-data/lib/serializers/embedded_records_mixin.js index 3d115ce2d80..61f8a42894e 100644 --- a/packages/ember-data/lib/serializers/embedded_records_mixin.js +++ b/packages/ember-data/lib/serializers/embedded_records_mixin.js @@ -22,6 +22,11 @@ import {pluralize} from "ember-inflector"; } }) ``` + Note that this use of `{embedded: 'always'}` is unrelated to + the `{embedded: 'always'}` that is defined as an option on `DS.attr` as part of + defining a model while working with the ActiveModelSerializer. Nevertheless, + using `{embedded: 'always'}` as an option to DS.attr is not a valid way to setup + embedded records. The `attrs` option for a resource `{embedded: 'always'}` is shorthand for: @@ -55,7 +60,11 @@ import {pluralize} from "ember-inflector"; ### Model Relationships - Embedded records must have a model defined to be extracted and serialized. + Embedded records must have a model defined to be extracted and serialized. Note that + when defining any relationships on your model such as `belongsTo` and `hasMany`, you + should not both specify `async:true` and also indicate through the serializer's + `attrs` attribute that the related model should be embedded. If a model is + declared embedded, then do not use `async:true`. To successfully extract and serialize embedded records the model relationships must be setup correcty See the From 98308740d561685c6bc41fa356996d4e52670596 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 23 Aug 2014 13:12:14 -0500 Subject: [PATCH 0322/2527] remove unused variables and enforce in jshint fixes GH-2209 --- .jshintrc | 3 ++- .../lib/system/active_model_adapter.js | 1 - packages/ember-data/lib/main.js | 16 ++++++++------- .../lib/serializers/embedded_records_mixin.js | 6 ------ .../lib/serializers/json_serializer.js | 5 ++--- .../lib/serializers/rest_serializer.js | 1 - packages/ember-data/lib/system/adapter.js | 2 -- .../ember-data/lib/system/container_proxy.js | 2 +- .../ember-data/lib/system/model/states.js | 20 ++----------------- .../lib/system/record_array_manager.js | 1 - .../adapter_populated_record_array.js | 1 - .../lib/system/record_arrays/record_array.js | 1 - .../lib/system/relationships/ext.js | 2 -- packages/ember-data/lib/system/store.js | 9 --------- 14 files changed, 16 insertions(+), 54 deletions(-) diff --git a/.jshintrc b/.jshintrc index 366dd7cb390..0f501422da4 100644 --- a/.jshintrc +++ b/.jshintrc @@ -61,5 +61,6 @@ "strict": false, "white": false, "eqnull": true, - "esnext": true + "esnext": true, + "unused": "vars" } diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index fb4088e7e8d..c1c0b65b04e 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -1,7 +1,6 @@ import {RESTAdapter} from "ember-data/adapters"; import {InvalidError} from "ember-data/system/adapter"; import {pluralize} from "ember-inflector"; -import ActiveModelSerializer from "activemodel-adapter/system/active_model_serializer"; /** @module ember-data diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index fece95a5748..38ad17421df 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -80,13 +80,15 @@ DS.RootState = RootState; DS.attr = attr; DS.Errors = Errors; -DS.AttributeChange = AttributeChange; -DS.RelationshipChange = RelationshipChange; -DS.RelationshipChangeAdd = RelationshipChangeAdd; -DS.OneToManyChange = OneToManyChange; -DS.ManyToNoneChange = OneToManyChange; -DS.OneToOneChange = OneToOneChange; -DS.ManyToManyChange = ManyToManyChange; +DS.AttributeChange = AttributeChange; +DS.RelationshipChange = RelationshipChange; +DS.RelationshipChangeAdd = RelationshipChangeAdd; +DS.RelationshipChangeRemove = RelationshipChangeRemove; +DS.ManyToNoneChange = ManyToNoneChange; +DS.OneToManyChange = OneToManyChange; +DS.ManyToNoneChange = OneToManyChange; +DS.OneToOneChange = OneToOneChange; +DS.ManyToManyChange = ManyToManyChange; DS.Adapter = Adapter; DS.InvalidError = InvalidError; diff --git a/packages/ember-data/lib/serializers/embedded_records_mixin.js b/packages/ember-data/lib/serializers/embedded_records_mixin.js index 3d115ce2d80..b866c8f2a13 100644 --- a/packages/ember-data/lib/serializers/embedded_records_mixin.js +++ b/packages/ember-data/lib/serializers/embedded_records_mixin.js @@ -2,8 +2,6 @@ var get = Ember.get; var forEach = Ember.EnumerableUtils.forEach; var camelize = Ember.String.camelize; -import {pluralize} from "ember-inflector"; - /** ## Using Embedded Records @@ -172,7 +170,6 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ */ serializeBelongsTo: function(record, json, relationship) { var attr = relationship.key; - var attrs = this.get('attrs'); if (this.noSerializeOptionSpecified(attr)) { this._super(record, json, relationship); return; @@ -282,7 +279,6 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ */ serializeHasMany: function(record, json, relationship) { var attr = relationship.key; - var attrs = this.get('attrs'); if (this.noSerializeOptionSpecified(attr)) { this._super(record, json, relationship); return; @@ -357,8 +353,6 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ // checks config for attrs option to serialize records noSerializeOptionSpecified: function(attr) { var option = this.attrsOption(attr); - var serializeRecords = this.hasSerializeRecordsOption(attr); - var serializeIds = this.hasSerializeIdsOption(attr); return !(option && (option.serialize || option.embedded)); }, diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index ac71a087542..0eddcd0d2ae 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -1,6 +1,5 @@ import { RelationshipChange } from "ember-data/system/changes"; var get = Ember.get; -var set = Ember.set; var isNone = Ember.isNone; var map = Ember.ArrayPolyfills.map; var merge = Ember.merge; @@ -196,7 +195,7 @@ export default Ember.Object.extend({ @private */ normalizeAttributes: function(type, hash) { - var payloadKey, key; + var payloadKey; if (this.keyForAttribute) { type.eachAttribute(function(key) { @@ -215,7 +214,7 @@ export default Ember.Object.extend({ @private */ normalizeRelationships: function(type, hash) { - var payloadKey, key; + var payloadKey; if (this.keyForRelationship) { type.eachRelationship(function(key, relationship) { diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index bc0d6e201d3..a96bd85d21a 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -4,7 +4,6 @@ import JSONSerializer from "ember-data/serializers/json_serializer"; var get = Ember.get; -var set = Ember.set; var forEach = Ember.ArrayPolyfills.forEach; var map = Ember.ArrayPolyfills.map; var camelize = Ember.String.camelize; diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 3d12b1865da..bc65550a500 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -3,8 +3,6 @@ */ var get = Ember.get; -var set = Ember.set; -var map = Ember.ArrayPolyfills.map; var errorProps = [ 'description', diff --git a/packages/ember-data/lib/system/container_proxy.js b/packages/ember-data/lib/system/container_proxy.js index c39659c9cfa..55a74da5a84 100644 --- a/packages/ember-data/lib/system/container_proxy.js +++ b/packages/ember-data/lib/system/container_proxy.js @@ -36,7 +36,7 @@ ContainerProxy.prototype.registerDeprecation = function(deprecated, valid) { }; ContainerProxy.prototype.registerDeprecations = function(proxyPairs) { - var i, proxyPair, deprecated, valid, proxy; + var i, proxyPair, deprecated, valid; for (i = proxyPairs.length; i > 0; i--) { proxyPair = proxyPairs[i - 1]; diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index ee653a39a9e..470383b8d31 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -173,18 +173,6 @@ var set = Ember.set; @class RootState */ -function hasDefinedProperties(object) { - // Ignore internal property defined by simulated `Ember.create`. - var names = Ember.keys(object); - var i, l, name; - for (i = 0, l = names.length; i < l; i++ ) { - name = names[i]; - if (object.hasOwnProperty(name) && object[name]) { return true; } - } - - return false; -} - function didSetProperty(record, context) { if (context.value === context.originalValue) { delete record._attributes[context.name]; @@ -259,12 +247,8 @@ var DirtyState = { loadingData: Ember.K, propertyWasReset: function(record, name) { - var stillDirty = false; - - for (var prop in record._attributes) { - stillDirty = true; - break; - } + var length = Ember.keys(record._attributes); + var stillDirty = length > 0; if (!stillDirty) { record.send('rolledBack'); } }, diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index a46d877b71e..3ed70e6e584 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -9,7 +9,6 @@ import { ManyArray } from "ember-data/system/record_arrays"; var get = Ember.get; -var set = Ember.set; var forEach = Ember.EnumerableUtils.forEach; /** diff --git a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js index 8aa70e30f46..8da086d3e73 100644 --- a/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/adapter_populated_record_array.js @@ -4,7 +4,6 @@ import RecordArray from "ember-data/system/record_arrays/record_array"; */ var get = Ember.get; -var set = Ember.set; function cloneNull(source) { var clone = Object.create(null); diff --git a/packages/ember-data/lib/system/record_arrays/record_array.js b/packages/ember-data/lib/system/record_arrays/record_array.js index a33785c450d..aeaa27ca095 100644 --- a/packages/ember-data/lib/system/record_arrays/record_array.js +++ b/packages/ember-data/lib/system/record_arrays/record_array.js @@ -4,7 +4,6 @@ import { PromiseArray } from "ember-data/system/store"; var get = Ember.get; -var set = Ember.set; /** A record array is an array that contains records of a certain type. The record diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index ebadd756824..dbfdcdc99bb 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -1,4 +1,3 @@ -import { singularize } from "ember-inflector/system"; import { typeForRelationshipMeta, relationshipFromMeta @@ -6,7 +5,6 @@ import { import { Model } from "ember-data/system/model"; var get = Ember.get; -var set = Ember.set; /** @module ember-data diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index d2028f04938..1bec21796c7 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -465,7 +465,6 @@ Store = Ember.Object.extend({ */ findByIds: function(type, ids) { var store = this; - var promiseLabel = "DS: Store#findByIds " + type; return promiseArray(Ember.RSVP.all(map(ids, function(id) { return store.findById(type, id); @@ -536,7 +535,6 @@ Store = Ember.Object.extend({ var adapter = store.adapterFor(type); var shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; var records = Ember.A(recordResolverPairs).mapBy('record'); - var resolvers = Ember.A(recordResolverPairs).mapBy('resolver'); function _fetchRecord(recordResolverPair) { recordResolverPair.resolver.resolve(store.fetchRecord(recordResolverPair.record)); @@ -1638,7 +1636,6 @@ Store = Ember.Object.extend({ willDestroy: function() { var typeMaps = this.typeMaps; var keys = Ember.keys(typeMaps); - var store = this; var types = map(keys, byType); @@ -1817,10 +1814,6 @@ function promiseArray(promise, label) { }); } -function isThenable(object) { - return object && typeof object.then === 'function'; -} - function serializerFor(container, type, defaultSerializer) { return container.lookup('serializer:'+type) || container.lookup('serializer:application') || @@ -1905,8 +1898,6 @@ function _findMany(adapter, store, type, ids, records) { throw new Error('adapter.findMany returned undefined, this was very likely a mistake'); } - var guardedPromise; - promise = Promise.cast(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); From 50fd30f8736091c46bf13ef051b18566a38a0070 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 23 Aug 2014 14:28:15 -0500 Subject: [PATCH 0323/2527] [BUGFIX] fixture adapter copies defined fixtures Otherwise, they will get mutated by Ember Data in various serialize hooks. fixes GH-1454 --- .../lib/adapters/fixture_adapter.js | 5 +-- .../adapter/fixture_adapter_test.js | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/adapters/fixture_adapter.js b/packages/ember-data/lib/adapters/fixture_adapter.js index a5813a67b69..4f44a4ac3a0 100644 --- a/packages/ember-data/lib/adapters/fixture_adapter.js +++ b/packages/ember-data/lib/adapters/fixture_adapter.js @@ -323,15 +323,16 @@ export default Adapter.extend({ var adapter = this; return new Ember.RSVP.Promise(function(resolve) { + var value = Ember.copy(callback.call(context), true); if (get(adapter, 'simulateRemoteResponse')) { // Schedule with setTimeout Ember.run.later(function() { - resolve(callback.call(context)); + resolve(value); }, get(adapter, 'latency')); } else { // Asynchronous, but at the of the runloop with zero latency Ember.run.schedule('actions', null, function() { - resolve(callback.call(context)); + resolve(value); }); } }, "DS: FixtureAdapter#simulateRemoteCall"); diff --git a/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js b/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js index aac861a59d4..3d2db5c39e9 100644 --- a/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js @@ -261,3 +261,35 @@ test("should throw if ids are not defined in the FIXTURES", function() { ok(false, "should not get here"); }); }); + +asyncTest("copies fixtures instead of passing the direct reference", function(){ + var returnedFixture; + + expect(2); + + Person.FIXTURES = [{ + id: '1', + firstName: 'Katie', + lastName: 'Gengler' + }]; + + var PersonAdapter = DS.FixtureAdapter.extend({ + find: function(store, type, id){ + return this._super(store, type, id).then(function(fixture){ + return returnedFixture = fixture; + }); + } + }); + + Ember.run(function(){ + env.container.register('adapter:person', PersonAdapter); + }); + + env.store.find('person', 1).then(function(){ + start(); + ok(Person.FIXTURES[0] !== returnedFixture, 'returnedFixture does not have object identity with defined fixture'); + deepEqual(Person.FIXTURES[0], returnedFixture); + }, function(err){ + ok(false, 'got error' + err); + }); +}); From 1c210ba85fc40410434fa09364e7b303bb59455e Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 23 Aug 2014 13:56:25 -0500 Subject: [PATCH 0324/2527] improve error message for push fixes GH-2201 --- packages/ember-data/lib/system/store.js | 4 ++-- .../ember-data/tests/unit/store/push_test.js | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 1bec21796c7..f6af3e29f57 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1293,8 +1293,8 @@ Store = Ember.Object.extend({ // _partial is an internal param used by `update`. // If passed, it means that the data should be // merged into the existing data, not replace it. - - Ember.assert("You must include an `id` for " + typeName+ " in a hash passed to `push`", data.id != null); + Ember.assert("Expected an object as `data` in a call to push for " + typeName + " , but was " + data, Ember.typeOf(data) === 'object'); + Ember.assert("You must include an `id` for " + typeName + " in an object passed to `push`", data.id != null); var type = this.modelFor(typeName); diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index bc54e0987e3..55478beae49 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -316,3 +316,23 @@ test("Calling pushPayload without a type should use a model's serializer when no equal(person.get('firstName'), "Yehuda", "you can push raw JSON into the store"); }); + +test('calling push without data argument as an object raises an error', function(){ + var invalidValues = [ + undefined, + null, + 1, + 'string', + Ember.Object.create(), + Ember.Object.extend(), + true + ]; + + expect(invalidValues.length); + + Ember.EnumerableUtils.forEach(invalidValues, function(invalidValue){ + throws(function(){ + store.push('person', invalidValue); + }, /object/); + }); +}); From 4419a3b3dba42fc3f2b1367042bcb6b6d886f194 Mon Sep 17 00:00:00 2001 From: Maximilian Neger Date: Mon, 25 Aug 2014 10:35:29 +0200 Subject: [PATCH 0325/2527] Fixed typo Fixed a typo in rest_serializer#serializeIntoHash --- packages/ember-data/lib/serializers/rest_serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index a96bd85d21a..13e1dc1b82b 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -684,7 +684,7 @@ export default JSONSerializer.extend({ /** You can use this method to customize the root keys serialized into the JSON. - By default the REST Serializer sends the typeKey of a model, whih is a camelized + By default the REST Serializer sends the typeKey of a model, which is a camelized version of the name. For example, your server may expect underscored root objects. From aea9ccc00ed8774fe3e44d18603ccfbbebbed196 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 28 Aug 2014 09:40:26 -0600 Subject: [PATCH 0326/2527] typo in embedded_records_mixin docs --- .../ember-data/lib/serializers/embedded_records_mixin.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/serializers/embedded_records_mixin.js b/packages/ember-data/lib/serializers/embedded_records_mixin.js index 93b89405ed7..a82700f111e 100644 --- a/packages/ember-data/lib/serializers/embedded_records_mixin.js +++ b/packages/ember-data/lib/serializers/embedded_records_mixin.js @@ -74,9 +74,9 @@ var camelize = Ember.String.camelize; ### Example JSON payloads, Models and Serializers - **When customizing a serializer it is imporant to grok what the cusomizations - are, please read the docs for the methods this mixin provides, in case you need - to modify to fit your specific needs.** + **When customizing a serializer it is important to grok what the customizations + are. Please read the docs for the methods this mixin provides, in case you need + to modify it to fit your specific needs.** For example review the docs for each method of this mixin: * [normalize](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_normalize) From bd58e3a51623ffed548ada5881e67a6a127e043c Mon Sep 17 00:00:00 2001 From: Jimmy Bourassa Date: Fri, 1 Aug 2014 11:08:46 -0400 Subject: [PATCH 0327/2527] Add support for embedded polymorphic hasMany --- .../lib/serializers/embedded_records_mixin.js | 29 +++++++++- .../embedded_records_mixin_test.js | 57 +++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/embedded_records_mixin.js b/packages/ember-data/lib/serializers/embedded_records_mixin.js index a82700f111e..2477534c592 100644 --- a/packages/ember-data/lib/serializers/embedded_records_mixin.js +++ b/packages/ember-data/lib/serializers/embedded_records_mixin.js @@ -388,7 +388,12 @@ function extractEmbeddedRecords(serializer, store, type, partial) { if (serializer.hasDeserializeRecordsOption(key)) { var embeddedType = store.modelFor(relationship.type.typeKey); if (relationship.kind === "hasMany") { - extractEmbeddedHasMany(store, key, embeddedType, partial); + if (relationship.options.polymorphic) { + extractEmbeddedHasManyPolymorphic(store, key, partial); + } + else { + extractEmbeddedHasMany(store, key, embeddedType, partial); + } } if (relationship.kind === "belongsTo") { extractEmbeddedBelongsTo(store, key, embeddedType, partial); @@ -418,6 +423,28 @@ function extractEmbeddedHasMany(store, key, embeddedType, hash) { return hash; } +function extractEmbeddedHasManyPolymorphic(store, key, hash) { + if (!hash[key]) { + return hash; + } + + var ids = []; + + forEach(hash[key], function(data) { + var typeKey = data.type; + var embeddedSerializer = store.serializerFor(typeKey); + var embeddedType = store.modelFor(typeKey); + var primaryKey = get(embeddedSerializer, 'primaryKey'); + + var embeddedRecord = embeddedSerializer.normalize(embeddedType, data, null); + store.push(embeddedType, embeddedRecord); + ids.push({ id: embeddedRecord[primaryKey], type: typeKey }); + }); + + hash[key] = ids; + return hash; +} + function extractEmbeddedBelongsTo(store, key, embeddedType, hash) { if (!hash[key]) { return hash; diff --git a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js index 7126c7fe601..e4320ce96b4 100644 --- a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js +++ b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js @@ -28,6 +28,9 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { name: DS.attr('string'), superVillain: DS.belongsTo('superVillain') }); + LightSaber = SecretWeapon.extend({ + color: DS.attr('string') + }); EvilMinion = DS.Model.extend({ superVillain: DS.belongsTo('superVillain'), name: DS.attr('string') @@ -42,6 +45,7 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { homePlanet: HomePlanet, secretLab: SecretLab, secretWeapon: SecretWeapon, + lightSaber: LightSaber, evilMinion: EvilMinion, comment: Comment }); @@ -49,6 +53,7 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { env.store.modelFor('homePlanet'); env.store.modelFor('secretLab'); env.store.modelFor('secretWeapon'); + env.store.modelFor('lightSaber'); env.store.modelFor('evilMinion'); env.store.modelFor('comment'); env.container.register('serializer:application', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); @@ -941,6 +946,58 @@ test("extractSingle with multiply-nested belongsTo", function() { equal(env.store.recordForId("homePlanet", "1").get("name"), "Umber", "Nested Secondary record, Umber, found in the store"); }); +test("extractSingle with polymorphic hasMany", function() { + SuperVillain.reopen({ + secretWeapons: DS.hasMany("secretWeapon", {polymorphic: true}), + }); + + env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretWeapons: {embedded: 'always'} + } + })); + var serializer = env.container.lookup("serializer:superVillain"); + + var json_hash = { + super_villain: { + id: "1", + first_name: "Tom", + last_name: "Dale", + secret_weapons: [ + { + id: "1", + type: "LightSaber", + name: "Tom's LightSaber", + color: "Red" + }, + { + id: "1", + type: "SecretWeapon", + name: "The Death Star" + } + ] + } + }; + + var json = serializer.extractSingle(env.store, SuperVillain, json_hash); + + deepEqual(json, { + id: "1", + firstName: "Tom", + lastName: "Dale", + secretWeapons: [ + {id: "1", type: "lightSaber"}, + {id: "1", type: "secretWeapon"} + ] + }, "Primary array was correct"); + + equal(env.store.recordForId("secretWeapon", "1").get("name"), "The Death Star", "Embedded polymorphic SecretWeapon found"); + equal(env.store.recordForId("lightSaber", "1").get("name"), "Tom's LightSaber", "Embedded polymorphic LightSaber found"); + + +}); + test("Mixin can be used with RESTSerializer which does not define keyForAttribute", function() { homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); secretLab = env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); From c9825d4a022dadf7f9cf17922dcfb3f228f8af0e Mon Sep 17 00:00:00 2001 From: IgorT Date: Sat, 16 Aug 2014 04:43:13 +0100 Subject: [PATCH 0328/2527] Refactor relationship handling code This commit refactors relationship handling code. It adds full support for loading relationships described on only one side in the api. It sets up the infrastructure for separating server vs local updates to relationships. In a future PR, we will use that infrastructure to add support for rollback, relationship dirtying and relationship merging. Lots of old, crappy code, removed, -550 lines before new tests. Pushing records into the store is now 15-20% faster. Relationships now properly refetch if the links value is updated. We no longer churn records that are not changed in a hasMany push. fixes #1919 fixes #1814 fixes #2057 fixes #2191 fixes #2177 fixes #2125 fixes #2100 fixes #1790 fixes #1532 fixes #1389 --- packages/ember-data/lib/main.js | 24 +- .../lib/serializers/json_serializer.js | 3 +- packages/ember-data/lib/system/changes.js | 23 - .../lib/system/changes/relationship_change.js | 432 ------------------ packages/ember-data/lib/system/model/model.js | 137 ++---- .../ember-data/lib/system/model/states.js | 5 +- .../ember-data/lib/system/promise_proxies.js | 82 ++++ .../lib/system/record_arrays/many_array.js | 119 +---- .../lib/system/record_arrays/record_array.js | 14 +- .../lib/system/relationship-meta.js | 7 - .../lib/system/relationships/belongs_to.js | 144 +----- .../lib/system/relationships/ext.js | 35 +- .../lib/system/relationships/has_many.js | 139 +----- .../lib/system/relationships/relationship.js | 278 +++++++++++ packages/ember-data/lib/system/store.js | 275 +++-------- .../integration/adapter/find_all_test.js | 3 + .../adapter/fixture_adapter_test.js | 13 +- .../integration/adapter/rest_adapter_test.js | 1 + .../tests/integration/records/unload_test.js | 1 + .../relationships/belongs_to_test.js | 13 +- .../relationships/has_many_test.js | 107 ++++- .../inverse_relationships_test.js | 145 +++++- .../relationships/many_to_many_test.js | 130 ++++++ .../relationships/one_to_many_test.js | 297 ++++++++++++ .../relationships/one_to_one_test.js | 169 +++++++ .../embedded_records_mixin_test.js | 8 +- .../tests/unit/store/adapter_interop_test.js | 24 +- .../tests/unit/store/unload_test.js | 1 + 28 files changed, 1423 insertions(+), 1206 deletions(-) delete mode 100644 packages/ember-data/lib/system/changes.js delete mode 100644 packages/ember-data/lib/system/changes/relationship_change.js create mode 100644 packages/ember-data/lib/system/promise_proxies.js create mode 100644 packages/ember-data/lib/system/relationships/relationship.js create mode 100644 packages/ember-data/tests/integration/relationships/many_to_many_test.js create mode 100644 packages/ember-data/tests/integration/relationships/one_to_many_test.js create mode 100644 packages/ember-data/tests/integration/relationships/one_to_one_test.js diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index 38ad17421df..dbea0e7e6ee 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -12,9 +12,11 @@ import DS from "ember-data/core"; import "ember-data/ext/date"; import { - Store, PromiseArray, PromiseObject +} from "ember-data/system/promise_proxies"; +import { + Store } from "ember-data/system/store"; import { Model, @@ -22,16 +24,6 @@ import { RootState, attr } from "ember-data/system/model"; -import { - AttributeChange, - RelationshipChange, - RelationshipChangeAdd, - RelationshipChangeRemove, - OneToManyChange, - ManyToNoneChange, - OneToOneChange, - ManyToManyChange -} from "ember-data/system/changes"; import { InvalidError, Adapter @@ -80,16 +72,6 @@ DS.RootState = RootState; DS.attr = attr; DS.Errors = Errors; -DS.AttributeChange = AttributeChange; -DS.RelationshipChange = RelationshipChange; -DS.RelationshipChangeAdd = RelationshipChangeAdd; -DS.RelationshipChangeRemove = RelationshipChangeRemove; -DS.ManyToNoneChange = ManyToNoneChange; -DS.OneToManyChange = OneToManyChange; -DS.ManyToNoneChange = OneToManyChange; -DS.OneToOneChange = OneToOneChange; -DS.ManyToManyChange = ManyToManyChange; - DS.Adapter = Adapter; DS.InvalidError = InvalidError; diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index be5edc26cdd..dc1e54d3fe7 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -1,4 +1,3 @@ -import { RelationshipChange } from "ember-data/system/changes"; var get = Ember.get; var isNone = Ember.isNone; var map = Ember.ArrayPolyfills.map; @@ -633,7 +632,7 @@ export default Ember.Object.extend({ payloadKey = this.keyForRelationship(key, "hasMany"); } - var relationshipType = RelationshipChange.determineRelationshipType(record.constructor, relationship); + var relationshipType = record.constructor.determineRelationshipType(relationship); if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') { json[payloadKey] = get(record, key).mapBy('id'); diff --git a/packages/ember-data/lib/system/changes.js b/packages/ember-data/lib/system/changes.js deleted file mode 100644 index 4d2000bcfd1..00000000000 --- a/packages/ember-data/lib/system/changes.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - @module ember-data -*/ - -import { - RelationshipChange, - RelationshipChangeAdd, - RelationshipChangeRemove, - OneToManyChange, - ManyToNoneChange, - OneToOneChange, - ManyToManyChange -} from "ember-data/system/changes/relationship_change"; - -export { - RelationshipChange, - RelationshipChangeAdd, - RelationshipChangeRemove, - OneToManyChange, - ManyToNoneChange, - OneToOneChange, - ManyToManyChange -}; diff --git a/packages/ember-data/lib/system/changes/relationship_change.js b/packages/ember-data/lib/system/changes/relationship_change.js deleted file mode 100644 index aa46e65008e..00000000000 --- a/packages/ember-data/lib/system/changes/relationship_change.js +++ /dev/null @@ -1,432 +0,0 @@ -/** - @module ember-data -*/ - -import Model from "ember-data/system/model/model"; -import { isSyncRelationship } from 'ember-data/system/relationship-meta'; - -var get = Ember.get; -var set = Ember.set; -var forEach = Ember.EnumerableUtils.forEach; - -/** - @class RelationshipChange - @namespace DS - @private - @constructor -*/ -var RelationshipChange = function(options) { - this.parentRecord = options.parentRecord; - this.childRecord = options.childRecord; - this.firstRecord = options.firstRecord; - this.firstRecordKind = options.firstRecordKind; - this.firstRecordName = options.firstRecordName; - this.secondRecord = options.secondRecord; - this.secondRecordKind = options.secondRecordKind; - this.secondRecordName = options.secondRecordName; - this.changeType = options.changeType; - this.store = options.store; - - this.committed = {}; -}; - -/** - @class RelationshipChangeAdd - @namespace DS - @private - @constructor -*/ -function RelationshipChangeAdd(options){ - RelationshipChange.call(this, options); -} - -/** - @class RelationshipChangeRemove - @namespace DS - @private - @constructor -*/ -function RelationshipChangeRemove(options){ - RelationshipChange.call(this, options); -} - -RelationshipChange.create = function(options) { - return new RelationshipChange(options); -}; - -RelationshipChangeAdd.create = function(options) { - return new RelationshipChangeAdd(options); -}; - -RelationshipChangeRemove.create = function(options) { - return new RelationshipChangeRemove(options); -}; - -var OneToManyChange = {}; -var OneToNoneChange = {}; -var ManyToNoneChange = {}; -var OneToOneChange = {}; -var ManyToManyChange = {}; - -RelationshipChange._createChange = function(options){ - if (options.changeType === 'add') { - return RelationshipChangeAdd.create(options); - } - if (options.changeType === 'remove') { - return RelationshipChangeRemove.create(options); - } -}; - -RelationshipChange.determineRelationshipType = function(recordType, knownSide){ - var knownKey = knownSide.key, key, otherKind; - var knownKind = knownSide.kind; - - var inverse = recordType.inverseFor(knownKey); - - if (inverse) { - key = inverse.name; - otherKind = inverse.kind; - } - - if (!inverse) { - return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone'; - } else { - if (otherKind === 'belongsTo') { - return knownKind === 'belongsTo' ? 'oneToOne' : 'manyToOne'; - } else { - return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany'; - } - } -}; - -RelationshipChange.createChange = function(firstRecord, secondRecord, store, options){ - // Get the type of the child based on the child's client ID - var firstRecordType = firstRecord.constructor, changeType; - changeType = RelationshipChange.determineRelationshipType(firstRecordType, options); - if (changeType === 'oneToMany') { - return OneToManyChange.createChange(firstRecord, secondRecord, store, options); - } else if (changeType === 'manyToOne') { - return OneToManyChange.createChange(secondRecord, firstRecord, store, options); - } else if (changeType === 'oneToNone') { - return OneToNoneChange.createChange(firstRecord, secondRecord, store, options); - } else if (changeType === 'manyToNone') { - return ManyToNoneChange.createChange(firstRecord, secondRecord, store, options); - } else if (changeType === 'oneToOne') { - return OneToOneChange.createChange(firstRecord, secondRecord, store, options); - } else if (changeType === 'manyToMany') { - return ManyToManyChange.createChange(firstRecord, secondRecord, store, options); - } -}; - -OneToNoneChange.createChange = function(childRecord, parentRecord, store, options) { - var key = options.key; - var change = RelationshipChange._createChange({ - parentRecord: parentRecord, - childRecord: childRecord, - firstRecord: childRecord, - store: store, - changeType: options.changeType, - firstRecordName: key, - firstRecordKind: 'belongsTo' - }); - - store.addRelationshipChangeFor(childRecord, key, parentRecord, null, change); - - return change; -}; - -ManyToNoneChange.createChange = function(childRecord, parentRecord, store, options) { - var key = options.key; - var change = RelationshipChange._createChange({ - parentRecord: childRecord, - childRecord: parentRecord, - secondRecord: childRecord, - store: store, - changeType: options.changeType, - secondRecordName: options.key, - secondRecordKind: 'hasMany' - }); - - store.addRelationshipChangeFor(childRecord, key, parentRecord, null, change); - return change; -}; - - -ManyToManyChange.createChange = function(childRecord, parentRecord, store, options) { - // If the name of the belongsTo side of the relationship is specified, - // use that - // If the type of the parent is specified, look it up on the child's type - // definition. - var key = options.key; - - var change = RelationshipChange._createChange({ - parentRecord: parentRecord, - childRecord: childRecord, - firstRecord: childRecord, - secondRecord: parentRecord, - firstRecordKind: 'hasMany', - secondRecordKind: 'hasMany', - store: store, - changeType: options.changeType, - firstRecordName: key - }); - - store.addRelationshipChangeFor(childRecord, key, parentRecord, null, change); - - return change; -}; - -OneToOneChange.createChange = function(childRecord, parentRecord, store, options) { - var key; - - // If the name of the belongsTo side of the relationship is specified, - // use that - // If the type of the parent is specified, look it up on the child's type - // definition. - if (options.parentType) { - key = options.parentType.inverseFor(options.key).name; - } else if (options.key) { - key = options.key; - } else { - Ember.assert('You must pass either a parentType or belongsToName option to OneToManyChange.forChildAndParent', false); - } - - var change = RelationshipChange._createChange({ - parentRecord: parentRecord, - childRecord: childRecord, - firstRecord: childRecord, - secondRecord: parentRecord, - firstRecordKind: 'belongsTo', - secondRecordKind: 'belongsTo', - store: store, - changeType: options.changeType, - firstRecordName: key - }); - - store.addRelationshipChangeFor(childRecord, key, parentRecord, null, change); - - return change; -}; - -OneToOneChange.maintainInvariant = function(options, store, childRecord, key){ - if (options.changeType === 'add' && store.recordIsMaterialized(childRecord)) { - var oldParent = get(childRecord, key); - if (oldParent) { - var correspondingChange = OneToOneChange.createChange(childRecord, oldParent, store, { - parentType: options.parentType, - hasManyName: options.hasManyName, - changeType: 'remove', - key: options.key - }); - store.addRelationshipChangeFor(childRecord, key, options.parentRecord , null, correspondingChange); - correspondingChange.sync(); - } - } -}; - -OneToManyChange.createChange = function(childRecord, parentRecord, store, options) { - var key; - - // If the name of the belongsTo side of the relationship is specified, - // use that - // If the type of the parent is specified, look it up on the child's type - // definition. - if (options.parentType) { - key = options.parentType.inverseFor(options.key).name; - OneToManyChange.maintainInvariant( options, store, childRecord, key ); - } else if (options.key) { - key = options.key; - } else { - Ember.assert('You must pass either a parentType or belongsToName option to OneToManyChange.forChildAndParent', false); - } - - var change = RelationshipChange._createChange({ - parentRecord: parentRecord, - childRecord: childRecord, - firstRecord: childRecord, - secondRecord: parentRecord, - firstRecordKind: 'belongsTo', - secondRecordKind: 'hasMany', - store: store, - changeType: options.changeType, - firstRecordName: key - }); - - store.addRelationshipChangeFor(childRecord, key, parentRecord, change.getSecondRecordName(), change); - - return change; -}; - -OneToManyChange.maintainInvariant = function(options, store, childRecord, key){ - if (options.changeType === 'add' && childRecord) { - var oldParent = get(childRecord, key); - if (oldParent) { - var correspondingChange = OneToManyChange.createChange(childRecord, oldParent, store, { - parentType: options.parentType, - hasManyName: options.hasManyName, - changeType: 'remove', - key: options.key - }); - store.addRelationshipChangeFor(childRecord, key, options.parentRecord, correspondingChange.getSecondRecordName(), correspondingChange); - correspondingChange.sync(); - } - } -}; - -/** - @class RelationshipChange - @namespace DS -*/ -RelationshipChange.prototype = { - getSecondRecordName: function() { - var name = this.secondRecordName, parent; - - if (!name) { - parent = this.secondRecord; - if (!parent) { return; } - - var childType = this.firstRecord.constructor; - var inverse = childType.inverseFor(this.firstRecordName); - this.secondRecordName = inverse.name; - } - - return this.secondRecordName; - }, - - /** - Get the name of the relationship on the belongsTo side. - - @method getFirstRecordName - @return {String} - */ - getFirstRecordName: function() { - return this.firstRecordName; - }, - - /** - @method destroy - @private - */ - destroy: function() { - var childRecord = this.childRecord; - var belongsToName = this.getFirstRecordName(); - var hasManyName = this.getSecondRecordName(); - var store = this.store; - - store.removeRelationshipChangeFor(childRecord, belongsToName, this.parentRecord, hasManyName, this.changeType); - }, - - getSecondRecord: function(){ - return this.secondRecord; - }, - - /** - @method getFirstRecord - @private - */ - getFirstRecord: function() { - return this.firstRecord; - }, - - coalesce: function(){ - var relationshipPairs = this.store.relationshipChangePairsFor(this.firstRecord); - forEach(relationshipPairs, function(pair) { - var addedChange = pair['add']; - var removedChange = pair['remove']; - if (addedChange && removedChange) { - addedChange.destroy(); - removedChange.destroy(); - } - }); - } -}; - -RelationshipChangeAdd.prototype = Ember.create(RelationshipChange.create({})); -RelationshipChangeRemove.prototype = Ember.create(RelationshipChange.create({})); - -RelationshipChangeAdd.prototype.changeType = 'add'; -RelationshipChangeAdd.prototype.sync = function() { - var secondRecordName = this.getSecondRecordName(); - var firstRecordName = this.getFirstRecordName(); - var firstRecord = this.getFirstRecord(); - var secondRecord = this.getSecondRecord(); - - //Ember.assert("You specified a hasMany (" + hasManyName + ") on " + (!belongsToName && (newParent || oldParent || this.lastParent).constructor) + " but did not specify an inverse belongsTo on " + child.constructor, belongsToName); - //Ember.assert("You specified a belongsTo (" + belongsToName + ") on " + child.constructor + " but did not specify an inverse hasMany on " + (!hasManyName && (newParent || oldParent || this.lastParentRecord).constructor), hasManyName); - - if (secondRecord instanceof Model && firstRecord instanceof Model) { - if (this.secondRecordKind === 'belongsTo') { - secondRecord.suspendRelationshipObservers(function() { - set(secondRecord, secondRecordName, firstRecord); - }); - } else if (this.secondRecordKind === 'hasMany' && isSyncRelationship(secondRecord, secondRecordName)) { - secondRecord.suspendRelationshipObservers(function() { - var relationship = get(secondRecord, secondRecordName); - relationship.addObject(firstRecord); - }); - } - } - - if (firstRecord instanceof Model && secondRecord instanceof Model && get(firstRecord, firstRecordName) !== secondRecord) { - if (this.firstRecordKind === 'belongsTo') { - firstRecord.suspendRelationshipObservers(function() { - set(firstRecord, firstRecordName, secondRecord); - }); - } else if (this.firstRecordKind === 'hasMany' && isSyncRelationship(secondRecord, secondRecordName)) { - firstRecord.suspendRelationshipObservers(function() { - var relationship = get(firstRecord, firstRecordName); - relationship.addObject(secondRecord); - }); - } - } - this.coalesce(); -}; - -RelationshipChangeRemove.prototype.changeType = 'remove'; -RelationshipChangeRemove.prototype.sync = function() { - var secondRecordName = this.getSecondRecordName(); - var firstRecordName = this.getFirstRecordName(); - var firstRecord = this.getFirstRecord(); - var secondRecord = this.getSecondRecord(); - - //Ember.assert("You specified a hasMany (" + hasManyName + ") on " + (!belongsToName && (newParent || oldParent || this.lastParent).constructor) + " but did not specify an inverse belongsTo on " + child.constructor, belongsToName); - //Ember.assert("You specified a belongsTo (" + belongsToName + ") on " + child.constructor + " but did not specify an inverse hasMany on " + (!hasManyName && (newParent || oldParent || this.lastParentRecord).constructor), hasManyName); - - if (secondRecord instanceof Model && firstRecord instanceof Model) { - if (this.secondRecordKind === 'belongsTo') { - secondRecord.suspendRelationshipObservers(function() { - set(secondRecord, secondRecordName, null); - }); - } else if (this.secondRecordKind === 'hasMany' && isSyncRelationship(secondRecord, secondRecordName)) { - secondRecord.suspendRelationshipObservers(function() { - var relationship = get(secondRecord, secondRecordName); - relationship.removeObject(firstRecord); - }); - } - } - - if (firstRecord instanceof Model && get(firstRecord, firstRecordName)) { - if (this.firstRecordKind === 'belongsTo') { - firstRecord.suspendRelationshipObservers(function() { - set(firstRecord, firstRecordName, null); - }); - } else if (this.firstRecordKind === 'hasMany' && isSyncRelationship(firstRecord, firstRecordName)) { - firstRecord.suspendRelationshipObservers(function() { - var relationship = get(firstRecord, firstRecordName); - relationship.removeObject(secondRecord); - }); - } - } - - this.coalesce(); -}; - -export { - RelationshipChange, - RelationshipChangeAdd, - RelationshipChangeRemove, - OneToManyChange, - ManyToNoneChange, - OneToOneChange, - ManyToManyChange -}; diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 5a5cb685f4b..def2cf24f1a 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1,6 +1,8 @@ import RootState from "ember-data/system/model/states"; import Errors from "ember-data/system/model/errors"; -import { PromiseObject } from "ember-data/system/store"; +import { PromiseObject } from "ember-data/system/promise_proxies"; +import { createRelationshipFor } from "ember-data/system/relationships/relationship"; + /** @module ember-data */ @@ -10,6 +12,7 @@ var set = Ember.set; var merge = Ember.merge; var Promise = Ember.RSVP.Promise; var forEach = Ember.ArrayPolyfills.forEach; +var map = Ember.ArrayPolyfills.map; var JSONSerializer; var retrieveFromCurrentState = Ember.computed('currentState', function(key, value) { @@ -442,6 +445,12 @@ var Model = Ember.Object.extend(Ember.Evented, { this._attributes = {}; this._inFlightAttributes = {}; this._relationships = {}; + var model = this; + //TODO Move into a getter for better perf + this.constructor.eachRelationship(function(key, descriptor) { + model._relationships[key] = createRelationshipFor(model, descriptor, model.store); + }); + }, /** @@ -624,13 +633,11 @@ var Model = Ember.Object.extend(Ember.Evented, { */ clearRelationships: function() { this.eachRelationship(function(name, relationship) { - if (relationship.kind === 'belongsTo') { - set(this, name, null); - } else if (relationship.kind === 'hasMany') { - var hasMany = this._relationships[name]; - if (hasMany) { // relationships are created lazily - hasMany.destroy(); - } + var rel = this._relationships[name]; + if (rel){ + //TODO(Igor) figure out whether we want to clear or disconnect + rel.clear(); + rel.destroy(); } }, this); }, @@ -687,15 +694,20 @@ var Model = Ember.Object.extend(Ember.Evented, { Ember.assert("You need to pass in an array to set a hasMany property on a record", Ember.isArray(preloadValue)); var record = this; - forEach.call(preloadValue, function(recordToPush) { - recordToPush = record._convertStringOrNumberIntoRecord(recordToPush, type); - get(record, key).pushObject(recordToPush); + var recordsToSet = map.call(preloadValue, function(recordToPush) { + return record._convertStringOrNumberIntoRecord(recordToPush, type); }); + //We use the pathway of setting the hasMany as if it came from the adapter + //because the user told us that they know this relationships exists already + this._relationships[key].updateRecordsFromAdapter(recordsToSet); }, _preloadBelongsTo: function(key, preloadValue, type){ - var recordToPush = this._convertStringOrNumberIntoRecord(preloadValue, type); - set(this, key, recordToPush); + var recordToSet = this._convertStringOrNumberIntoRecord(preloadValue, type); + + //We use the pathway of setting the hasMany as if it came from the adapter + //because the user told us that they know this relationships exists already + this._relationships[key].setRecord(recordToSet); }, _convertStringOrNumberIntoRecord: function(value, type) { @@ -770,7 +782,7 @@ var Model = Ember.Object.extend(Ember.Evented, { if (!data) { return; } - this._dataDidChange(); + this.notifyPropertyChange('data'); }, /** @@ -782,32 +794,6 @@ var Model = Ember.Object.extend(Ember.Evented, { this.updateRecordArraysLater(); }, - dataDidChange: Ember.observer(function() { - this.reloadHasManys(); - }, 'data'), - - reloadHasManys: function() { - var relationships = get(this.constructor, 'relationshipsByName'); - this.updateRecordArraysLater(); - relationships.forEach(function(name, relationship) { - if (this._data.links && this._data.links[name]) { return; } - if (relationship.kind === 'hasMany') { - this.hasManyDidChange(relationship.key); - } - }, this); - }, - - hasManyDidChange: function(key) { - var hasMany = this._relationships[key]; - - if (hasMany) { - var records = this._data[key] || []; - - set(hasMany, 'content', Ember.A(records)); - set(hasMany, 'isLoaded', true); - hasMany.trigger('didLoad'); - } - }, /** @method updateRecordArraysLater @@ -835,16 +821,9 @@ var Model = Ember.Object.extend(Ember.Evented, { this._data = data; } - var relationships = this._relationships; - - this.eachRelationship(function(name, rel) { - if (data.links && data.links[name]) { return; } - if (rel.options.async) { relationships[name] = null; } - }); - if (data) { this.pushedData(); } - this._dataDidChange(); + this.notifyPropertyChange('data'); }, materializeId: function(id) { @@ -860,27 +839,6 @@ var Model = Ember.Object.extend(Ember.Evented, { this._data[name] = value; }, - /** - @method updateHasMany - @private - @param {String} name - @param {Array} records - */ - updateHasMany: function(name, records) { - this._data[name] = records; - this.hasManyDidChange(name); - }, - - /** - @method updateBelongsTo - @private - @param {String} name - @param {DS.Model} record - */ - updateBelongsTo: function(name, record) { - this._data[name] = record; - }, - /** If the model `isDirty` this function will discard any unsaved changes @@ -911,52 +869,13 @@ var Model = Ember.Object.extend(Ember.Evented, { this.send('rolledBack'); - this._dataDidChange(); - }, - - _dataDidChange: function() { - this.suspendRelationshipObservers(function _dataDidChange_suspectRelationshipObservers() { - this.notifyPropertyChange('data'); - }); + this.notifyPropertyChange('data'); }, toStringExtension: function() { return get(this, 'id'); }, - /** - The goal of this method is to temporarily disable specific observers - that take action in response to application changes. - - This allows the system to make changes (such as materialization and - rollback) that should not trigger secondary behavior (such as setting an - inverse relationship or marking records as dirty). - - The specific implementation will likely change as Ember proper provides - better infrastructure for suspending groups of observers, and if Array - observation becomes more unified with regular observers. - - @method suspendRelationshipObservers - @private - @param callback - @param binding - */ - suspendRelationshipObservers: function(callback, binding) { - var observers = get(this.constructor, 'relationshipNames').belongsTo; - var self = this; - - try { - this._suspendedRelationships = true; - Ember._suspendObservers(self, observers, null, 'belongsToDidChange', function() { - Ember._suspendBeforeObservers(self, observers, null, 'belongsToWillChange', function() { - callback.call(binding || self); - }); - }); - } finally { - this._suspendedRelationships = false; - } - }, - /** Save the record and persist any changes to the record to an extenal source via the adapter. diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index 470383b8d31..a870e8e2371 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -473,10 +473,7 @@ var RootState = { loadedData: function(record) { record.transitionTo('loaded.created.uncommitted'); - - record.suspendRelationshipObservers(function() { - record.notifyPropertyChange('data'); - }); + record.notifyPropertyChange('data'); }, pushedData: function(record) { diff --git a/packages/ember-data/lib/system/promise_proxies.js b/packages/ember-data/lib/system/promise_proxies.js new file mode 100644 index 00000000000..54cb397057a --- /dev/null +++ b/packages/ember-data/lib/system/promise_proxies.js @@ -0,0 +1,82 @@ +var Promise = Ember.RSVP.Promise; + +/** + A `PromiseArray` is an object that acts like both an `Ember.Array` + and a promise. When the promise is resolved the resulting value + will be set to the `PromiseArray`'s `content` property. This makes + it easy to create data bindings with the `PromiseArray` that will be + updated when the promise resolves. + + For more information see the [Ember.PromiseProxyMixin + documentation](/api/classes/Ember.PromiseProxyMixin.html). + + Example + + ```javascript + var promiseArray = DS.PromiseArray.create({ + promise: $.getJSON('/some/remote/data.json') + }); + + promiseArray.get('length'); // 0 + + promiseArray.then(function() { + promiseArray.get('length'); // 100 + }); + ``` + + @class PromiseArray + @namespace DS + @extends Ember.ArrayProxy + @uses Ember.PromiseProxyMixin +*/ +var PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin); + +/** + A `PromiseObject` is an object that acts like both an `Ember.Object` + and a promise. When the promise is resolved, then the resulting value + will be set to the `PromiseObject`'s `content` property. This makes + it easy to create data bindings with the `PromiseObject` that will + be updated when the promise resolves. + + For more information see the [Ember.PromiseProxyMixin + documentation](/api/classes/Ember.PromiseProxyMixin.html). + + Example + + ```javascript + var promiseObject = DS.PromiseObject.create({ + promise: $.getJSON('/some/remote/data.json') + }); + + promiseObject.get('name'); // null + + promiseObject.then(function() { + promiseObject.get('name'); // 'Tomster' + }); + ``` + + @class PromiseObject + @namespace DS + @extends Ember.ObjectProxy + @uses Ember.PromiseProxyMixin +*/ +var PromiseObject = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin); + +var promiseObject = function(promise, label) { + return PromiseObject.create({ + promise: Promise.resolve(promise, label) + }); +}; + +var promiseArray = function(promise, label) { + return PromiseArray.create({ + promise: Promise.resolve(promise, label) + }); +}; + +export { + PromiseArray, + PromiseObject, + promiseArray, + promiseObject +}; diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 02dfaf02e01..90cf09c7e4e 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -1,16 +1,10 @@ import RecordArray from "ember-data/system/record_arrays/record_array"; -import {RelationshipChange} from "ember-data/system/changes"; /** @module ember-data */ var get = Ember.get, set = Ember.set; -var map = Ember.EnumerableUtils.map; - -function sync(change) { - change.sync(); -} /** A `ManyArray` is a `RecordArray` that represents the contents of a has-many @@ -51,7 +45,6 @@ function sync(change) { export default RecordArray.extend({ init: function() { this._super.apply(this, arguments); - this._changesToSync = Ember.OrderedSet.create(); }, /** @@ -82,6 +75,16 @@ export default RecordArray.extend({ isLoaded: false, + /** + The relationship which manages this array. + + @property {DS.Model} owner + @private + */ + + relationship: null, + + /** Used for async `hasMany` arrays to keep track of when they will resolve. @@ -112,99 +115,14 @@ export default RecordArray.extend({ } }, - /** - @method fetch - @private - */ - fetch: function() { - var records = get(this, 'content'); - var store = get(this, 'store'); - var owner = get(this, 'owner'); - - var unloadedRecords = records.filterBy('isEmpty', true); - store.scheduleFetchMany(unloadedRecords, owner); - }, - - // Overrides Ember.Array's replace method to implement - replaceContent: function(index, removed, added) { - // Map the array of record objects into an array of client ids. - added = map(added, function(record) { - Ember.assert("You cannot add '" + record.constructor.typeKey + "' records to this relationship (only '" + this.type.typeKey + "' allowed)", !this.type || record instanceof this.type); - return record; - }, this); - - this._super(index, removed, added); - }, - - arrangedContentDidChange: function() { - Ember.run.once(this, 'fetch'); - }, - - arrayContentWillChange: function(index, removed, added) { - var owner = get(this, 'owner'); - var name = get(this, 'name'); - - if (!owner._suspendedRelationships) { - // This code is the first half of code that continues inside - // of arrayContentDidChange. It gets or creates a change from - // the child object, adds the current owner as the old - // parent if this is the first time the object was removed - // from a ManyArray, and sets `newParent` to null. - // - // Later, if the object is added to another ManyArray, - // the `arrayContentDidChange` will set `newParent` on - // the change. - for (var i=index; i 0){ + records = get(this, 'content').slice(idx, idx+amt); + this.get('relationship').removeRecords(records); } - - return this._super.apply(this, arguments); - }, - - arrayContentDidChange: function(index, removed, added) { - this._super.apply(this, arguments); - - var owner = get(this, 'owner'); - var name = get(this, 'name'); - var store = get(this, 'store'); - - if (!owner._suspendedRelationships) { - // This code is the second half of code that started in - // `arrayContentWillChange`. It gets or creates a change - // from the child object, and adds the current owner as - // the new parent. - for (var i=index; i1) { + if ( value === undefined ) { + value = null; + } + this._relationships[key].setRecord(value); } - belongsTo = data[key]; - - if (isNone(belongsTo)) { return null; } - - store.findById(belongsTo.constructor, belongsTo.get('id')); - - return belongsTo; + return this._relationships[key].getRecord(); }).meta(meta); } @@ -160,57 +86,13 @@ function belongsTo(type, options) { @namespace DS */ Model.reopen({ + notifyBelongsToAdded: function(key, relationship) { + this.notifyPropertyChange(key); + }, - /** - @method belongsToWillChange - @private - @static - @param record - @param key - */ - belongsToWillChange: Ember.beforeObserver(function(record, key) { - if (get(record, 'isLoaded') && isSyncRelationship(record, key)) { - var oldParent = get(record, key); - - if (oldParent) { - var store = get(record, 'store'); - var change = RelationshipChange.createChange(record, oldParent, store, { - key: key, - kind: 'belongsTo', - changeType: 'remove' - }); - - change.sync(); - this._changesToSync[key] = change; - } - } - }), - - /** - @method belongsToDidChange - @private - @static - @param record - @param key - */ - belongsToDidChange: Ember.immediateObserver(function(record, key) { - if (get(record, 'isLoaded')) { - var newParent = get(record, key); - - if (newParent) { - var store = get(record, 'store'); - var change = RelationshipChange.createChange(record, newParent, store, { - key: key, - kind: 'belongsTo', - changeType: 'add' - }); - - change.sync(); - } - } - - delete this._changesToSync[key]; - }) + notifyBelongsToRemoved: function(key) { + this.notifyPropertyChange(key); + } }); export default belongsTo; diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index dbfdcdc99bb..28d8ab100b6 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -56,11 +56,6 @@ Model.reopen({ // the computed property. var meta = value.meta(); - if (meta.isRelationship && meta.kind === 'belongsTo') { - Ember.addObserver(proto, key, null, 'belongsToDidChange'); - Ember.addBeforeObserver(proto, key, null, 'belongsToWillChange'); - } - meta.parentType = proto.constructor; } } @@ -442,7 +437,28 @@ Model.reopenClass({ get(this, 'relatedTypes').forEach(function(type) { callback.call(binding, type); }); + }, + + determineRelationshipType: function(knownSide) { + var knownKey = knownSide.key; + var knownKind = knownSide.kind; + var inverse = this.inverseFor(knownKey); + var key, otherKind; + + if (!inverse) { + return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone'; + } + + key = inverse.name; + otherKind = inverse.kind; + + if (otherKind === 'belongsTo') { + return knownKind === 'belongsTo' ? 'oneToOne' : 'manyToOne'; + } else { + return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany'; + } } + }); Model.reopen({ @@ -457,5 +473,14 @@ Model.reopen({ */ eachRelationship: function(callback, binding) { this.constructor.eachRelationship(callback, binding); + }, + + relationshipFor: function(name) { + return get(this.constructor, 'relationshipsByName').get(name); + }, + + inverseFor: function(key) { + return this.constructor.inverseFor(key); } + }); diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index 6dd013f44be..b3931a26348 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -2,116 +2,7 @@ @module ember-data */ -import { PromiseArray } from "ember-data/system/store"; - -import { - relationshipFromMeta, - typeForRelationshipMeta -} from "ember-data/system/relationship-meta"; - -var get = Ember.get; -var set = Ember.set; -var setProperties = Ember.setProperties; -var map = Ember.EnumerableUtils.map; - -/** - Returns a computed property that synchronously returns a ManyArray for - this relationship. If not all of the records in this relationship are - loaded, it will raise an exception. -*/ - -function syncHasMany(type, options, meta) { - return Ember.computed('data', function(key) { - return buildRelationship(this, key, options, function(store, data) { - // Configure the metadata for the computed property to contain - // the key. - meta.key = key; - - var records = data[key]; - - Ember.assert("You looked up the '" + key + "' relationship on '" + this + "' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", Ember.A(records).isEvery('isEmpty', false)); - - return store.findMany(this, data[key], typeForRelationshipMeta(store, meta)); - }); - }).meta(meta).readOnly(); -} - -/** - Returns a computed property that itself returns a promise that resolves to a - ManyArray. - */ - -function asyncHasMany(type, options, meta) { - return Ember.computed('data', function(key) { - // Configure the metadata for the computed property to contain - // the key. - meta.key = key; - - var relationship = buildRelationship(this, key, options, function(store, data) { - var link = data.links && data.links[key]; - var rel; - var promiseLabel = "DS: Async hasMany " + this + " : " + key; - var resolver = Ember.RSVP.defer(promiseLabel); - - if (link) { - rel = store.findHasMany(this, link, relationshipFromMeta(store, meta), resolver); - } else { - - //This is a temporary workaround for setting owner on the relationship - //until single source of truth lands. It only works for OneToMany atm - var records = data[key]; - var inverse = this.constructor.inverseFor(key); - var owner = this; - if (inverse && records) { - if (inverse.kind === 'belongsTo'){ - map(records, function(record){ - set(record, inverse.name, owner); - }); - } - } - - rel = store.findMany(owner, data[key], typeForRelationshipMeta(store, meta), resolver); - } - - // Cache the promise so we can use it when we come back and don't - // need to rebuild the relationship. - set(rel, 'promise', resolver.promise); - - return rel; - }); - - var promise = relationship.get('promise').then(function() { - return relationship; - }, null, "DS: Async hasMany records received"); - - return PromiseArray.create({ - promise: promise - }); - }).meta(meta).readOnly(); -} - -/* - Builds the ManyArray for a relationship using the provided callback, - but only if it had not been created previously. After building, it - sets some metadata on the created ManyArray, such as the record which - owns it and the name of the relationship. -*/ -function buildRelationship(record, key, options, callback) { - var rels = record._relationships; - - if (rels[key]) { return rels[key]; } - - var data = get(record, 'data'); - var store = get(record, 'store'); - - var relationship = rels[key] = callback.call(record, store, data); - - return setProperties(relationship, { - owner: record, - name: key, - isPolymorphic: options.polymorphic - }); -} +import { Model } from "ember-data/system/model"; /** `DS.hasMany` is used to define One-To-Many and Many-To-Many @@ -211,11 +102,29 @@ function hasMany(type, options) { key: null }; - if (options.async) { - return asyncHasMany(type, options, meta); - } else { - return syncHasMany(type, options, meta); - } + return Ember.computed(function(key) { + var relationship = this._relationships[key]; + return relationship.getRecords(); + }).meta(meta).readOnly(); } +Model.reopen({ + notifyHasManyAdded: function(key, record, idx) { + var relationship = this._relationships[key]; + var manyArray = relationship.manyArray; + manyArray.addRecord(record, idx); + //We need to notifyPropertyChange in the adding case because we need to make sure + //we fetch the newly added record in case it is unloaded + //TODO(Igor): Consider whether we could do this only if the record state is unloaded + this.notifyPropertyChange(key); + }, + + notifyHasManyRemoved: function(key, record) { + var relationship = this._relationships[key]; + var manyArray = relationship.manyArray; + manyArray.removeRecord(record); + } +}); + + export default hasMany; diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js new file mode 100644 index 00000000000..182e2b9ee52 --- /dev/null +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -0,0 +1,278 @@ +import { + PromiseArray, + PromiseObject +} from "ember-data/system/promise_proxies"; + +var Relationship = function(store, record, inverseKey, relationshipMeta) { + this.members = new Ember.OrderedSet(); + this.store = store; + this.key = relationshipMeta.key; + this.inverseKey = inverseKey; + this.record = record; + this.key = relationshipMeta.key; + this.isAsync = relationshipMeta.options.async; + this.relationshipMeta = relationshipMeta; +}; + +Relationship.prototype = { + constructor: Relationship, + hasFetchedLink: false, + + destroy: Ember.K, + + clear: function() { + this.members.forEach(function(member) { + this.removeRecord(member); + }, this); + }, + + removeRecords: function(records){ + var that = this; + records.forEach(function(record){ + that.removeRecord(record); + }); + }, + + addRecords: function(records, idx){ + var that = this; + records.forEach(function(record){ + that.addRecord(record, idx); + if (idx !== undefined) { + idx++; + } + }); + }, + + + addRecord: function(record, idx) { + if (!this.members.has(record)) { + this.members.add(record); + this.notifyRecordRelationshipAdded(record, idx); + if (this.inverseKey) { + record._relationships[this.inverseKey].addRecord(this.record); + } + } + }, + + removeRecord: function(record) { + if (this.members.has(record)) { + this.members.remove(record); + this.notifyRecordRelationshipRemoved(record); + if (this.inverseKey) { + var inverseRelationship = record._relationships[this.inverseKey]; + //Need to check for existence, as the record might unloading at the moment + if (inverseRelationship) { + inverseRelationship.removeRecord(this.record); + } + } + } + }, + + updateLink: function(link) { + if (link !== this.link) { + this.link = link; + this.hasFetchedLink = false; + this.record.notifyPropertyChange(this.key); + } + }, + + updateRecordsFromAdapter: function(records) { + //TODO Once we have adapter support, we need to handle updated and canonical changes + this.computeChanges(records); + } +}; + +var ManyRelationship = function(store, record, inverseKey, relationshipMeta) { + this._super$constructor(store, record, inverseKey, relationshipMeta); + this.belongsToType = relationshipMeta.type; + this.manyArray = store.recordArrayManager.createManyArray(this.belongsToType, Ember.A()); + this.manyArray.relationship = this; + this.isPolymorphic = relationshipMeta.options.polymorphic; + this.manyArray.isPolymorphic = this.isPolymorphic; +}; + +ManyRelationship.prototype = Object.create(Relationship.prototype); +ManyRelationship.prototype.constructor = ManyRelationship; +ManyRelationship.prototype._super$constructor = Relationship; + +ManyRelationship.prototype.destroy = function() { + this.manyArray.destroy(); +}; + +ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) { + Ember.assert("You cannot add '" + record.constructor.typeKey + "' records to this relationship (only '" + this.belongsToType.typeKey + "' allowed)", !this.belongsToType || record instanceof this.belongsToType); + this.record.notifyHasManyAdded(this.key, record, idx); +}; + +ManyRelationship.prototype.notifyRecordRelationshipRemoved = function(record) { + this.record.notifyHasManyRemoved(this.key, record); +}; + +ManyRelationship.prototype.computeChanges = function(records) { + var members = this.members; + + records = setForArray(records); + + members.forEach(function(member) { + if (records.has(member)) return; + + this.removeRecord(member); + }, this); + + var hasManyArray = this.manyArray; + + records.forEach(function(record, index) { + //Need to preserve the order of incoming records + if (hasManyArray.objectAt(index) === record ) return; + + this.removeRecord(record); + this.addRecord(record, index); + }, this); +}; + + +ManyRelationship.prototype.getRecords = function() { + if (this.isAsync) { + var self = this; + var promise; + if (this.link && !this.hasFetchedLink) { + promise = this.store.findHasMany(this.record, this.link, this.belongsToType).then(function(records){ + self.updateRecordsFromAdapter(records); + self.hasFetchedLink = true; + //TODO(Igor) try to abstract the isLoaded part + self.manyArray.set('isLoaded', true); + return self.manyArray; + }); + } else { + var manyArray = this.manyArray; + promise = this.store.findMany(manyArray.toArray()).then(function(){ + self.manyArray.set('isLoaded', true); + return manyArray; + }); + } + return PromiseArray.create({ + promise: promise + }); + } else { + Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.constructor.typeKey + "' with id " + this.record.get('id') + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); + + this.manyArray.set('isLoaded', true); + return this.manyArray; + } +}; + +var BelongsToRelationship = function(store, record, inverseKey, relationshipMeta) { + this._super$constructor(store, record, inverseKey, relationshipMeta); + this.members.add(record); + this.record = record; + this.key = relationshipMeta.key; + this.inverseKey = inverseKey; + this.inverseRecord = null; +}; + +BelongsToRelationship.prototype = Object.create(Relationship.prototype); +BelongsToRelationship.prototype.constructor = BelongsToRelationship; +BelongsToRelationship.prototype._super$constructor = Relationship; + +BelongsToRelationship.prototype.setRecord = function(newRecord) { + if (newRecord) { + this.addRecord(newRecord); + } else if (this.inverseRecord) { + this.removeRecord(this.inverseRecord); + } +}; + +BelongsToRelationship.prototype._super$addRecord = Relationship.prototype.addRecord; +BelongsToRelationship.prototype.addRecord = function(newRecord) { + if (this.members.has(newRecord)){ return;} + var type = this.relationshipMeta.type; + Ember.assert("You can only add a '" + type.typeKey + "' record to this relationship", newRecord instanceof type); + + if (this.inverseRecord && this.inverseKey) { + this.removeRecord(this.inverseRecord); + } + + this.inverseRecord = newRecord; + this._super$addRecord(newRecord); +}; + +BelongsToRelationship.prototype.notifyRecordRelationshipAdded = function(newRecord) { + this.record.notifyBelongsToAdded(this.key, this); +}; + +BelongsToRelationship.prototype.notifyRecordRelationshipRemoved = function(record) { + this.record.notifyBelongsToRemoved(this.key, this); +}; + +BelongsToRelationship.prototype._super$removeRecord = Relationship.prototype.removeRecord; +BelongsToRelationship.prototype.removeRecord = function(record) { + if (!this.members.has(record)){ return;} + this._super$removeRecord(record); + this.inverseRecord = null; +}; + +BelongsToRelationship.prototype.currentOtherSideFor = function() { + return this.inverseRecord; +}; + +BelongsToRelationship.prototype.getRecord = function() { + if (this.isAsync) { + var promise; + + if (this.link && !this.hasFetchedLink){ + var self = this; + promise = this.store.findBelongsTo(this.record, this.link, this.relationshipMeta).then(function(record){ + self.addRecord(record); + self.hasFetchedLink = true; + return record; + }); + } else if (this.inverseRecord) { + promise = this.store._findByRecord(this.inverseRecord); + } else { + promise = Ember.RSVP.Promise.resolve(null); + } + + return PromiseObject.create({ + promise: promise + }); + } else { + Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.constructor.typeKey + "' with id " + this.record.get('id') + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", this.inverseRecord === null || !this.inverseRecord.get('isEmpty')); + return this.inverseRecord; + } +}; + +function setForArray(array) { + var set = new Ember.OrderedSet(); + + if (array) { + for (var i=0, l=array.length; i -1) { diff --git a/packages/ember-data/tests/unit/store/adapter_interop_test.js b/packages/ember-data/tests/unit/store/adapter_interop_test.js index b248818794f..f437379aeb4 100644 --- a/packages/ember-data/tests/unit/store/adapter_interop_test.js +++ b/packages/ember-data/tests/unit/store/adapter_interop_test.js @@ -347,9 +347,10 @@ test("initial values of belongsTo can be passed in as the third argument to find }); test("initial values of belongsTo can be passed in as the third argument to find as ids", function() { + expect(1); var adapter = TestAdapter.extend({ - find: function(store, type, query) { - return new Ember.RSVP.Promise(function(){}); + find: function(store, type, id) { + return Ember.RSVP.Promise.resolve({id: id}); } }); @@ -359,14 +360,16 @@ test("initial values of belongsTo can be passed in as the third argument to find var Person = DS.Model.extend({ name: DS.attr('string'), - friend: DS.belongsTo('person') + friend: DS.belongsTo('person', {async: true}) }); store.container.register('model:person', Person); store.find(Person, 1, {friend: 2}); - equal(store.getById(Person, 1).get('friend.id'), '2', 'Preloaded belongsTo set'); + store.getById(Person, 1).get('friend').then(async(function(friend) { + equal(friend.get('id'), '2', 'Preloaded belongsTo set'); + })); }); test("initial values of hasMany can be passed in as the third argument to find as records", function() { @@ -395,9 +398,11 @@ test("initial values of hasMany can be passed in as the third argument to find a }); test("initial values of hasMany can be passed in as the third argument to find as ids", function() { + expect(1); + var adapter = TestAdapter.extend({ - find: function(store, type, query) { - return new Ember.RSVP.Promise(function(){}); + find: function(store, type, id) { + return Ember.RSVP.resolve({id:id}); } }); @@ -407,14 +412,17 @@ test("initial values of hasMany can be passed in as the third argument to find a var Person = DS.Model.extend({ name: DS.attr('string'), - friends: DS.hasMany('person') + friends: DS.hasMany('person', {async: true}) }); store.container.register('model:person', Person); store.find(Person, 1, {friends: [2]}); - equal(store.getById(Person, 1).get('friends').toArray()[0].get('id'), '2', 'Preloaded hasMany set'); + store.getById(Person, 1).get('friends').then(async(function(friends){ + equal(friends.objectAt(0).get('id'), '2', 'Preloaded hasMany set'); + })); + }); test("records should have their ids updated when the adapter returns the id data", function() { diff --git a/packages/ember-data/tests/unit/store/unload_test.js b/packages/ember-data/tests/unit/store/unload_test.js index fc274e4b5a2..edb1338619a 100644 --- a/packages/ember-data/tests/unit/store/unload_test.js +++ b/packages/ember-data/tests/unit/store/unload_test.js @@ -63,6 +63,7 @@ test("unload a record", function() { module("DS.Store - unload record with relationships"); + test("can commit store after unload record with relationships", function() { store = createStore({ adapter: DS.Adapter.extend({ find: function() { From 9dd04e6df4d709d2b76d09d4fc3ae48bcb60933f Mon Sep 17 00:00:00 2001 From: IgorT Date: Fri, 5 Sep 2014 09:01:58 +0200 Subject: [PATCH 0329/2527] Update recordArrays whenever there are changes to relationships Previously we weren't correctly refreshing record arrays when there were relationship changes. This was causing `store.filter` not to update correctly whenever there were relationship changes fixes #2222 --- packages/ember-data/lib/main.js | 3 ++ .../lib/system/relationships/relationship.js | 2 ++ .../tests/integration/filter_test.js | 31 +++++++++++++++++-- tests/ember_configuration.js | 3 ++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index dbea0e7e6ee..6e349a893c8 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -62,6 +62,7 @@ import "ember-data/ember-initializer"; import setupContainer from "ember-data/setup-container"; import ContainerProxy from "ember-data/system/container_proxy"; +import {Relationship} from "ember-data/system/relationships/relationship"; DS.Store = Store; DS.PromiseArray = PromiseArray; @@ -103,6 +104,8 @@ DS.EmbeddedRecordsMixin = EmbeddedRecordsMixin; DS.belongsTo = belongsTo; DS.hasMany = hasMany; +DS.Relationship = Relationship; + DS.ContainerProxy = ContainerProxy; DS._setupContainer = setupContainer; diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index 182e2b9ee52..a3e3cf19b30 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -51,6 +51,7 @@ Relationship.prototype = { if (this.inverseKey) { record._relationships[this.inverseKey].addRecord(this.record); } + this.record.updateRecordArrays(); } }, @@ -65,6 +66,7 @@ Relationship.prototype = { inverseRelationship.removeRecord(this.record); } } + this.record.updateRecordArrays(); } }, diff --git a/packages/ember-data/tests/integration/filter_test.js b/packages/ember-data/tests/integration/filter_test.js index 84d14f0a140..fa5c518a12d 100644 --- a/packages/ember-data/tests/integration/filter_test.js +++ b/packages/ember-data/tests/integration/filter_test.js @@ -14,8 +14,8 @@ var shouldNotContain = function(array, item) { module("integration/filter - DS.Model updating", { setup: function() { - array = [{ id: 1, name: "Scumbag Dale" }, { id: 2, name: "Scumbag Katz" }, { id: 3, name: "Scumbag Bryn" }]; - Person = DS.Model.extend({ name: DS.attr('string') }); + array = [{ id: 1, name: "Scumbag Dale", bestFriend: 2 }, { id: 2, name: "Scumbag Katz" }, { id: 3, name: "Scumbag Bryn" }]; + Person = DS.Model.extend({ name: DS.attr('string'), bestFriend: DS.belongsTo('person') }); env = setupStore({ person: Person }); store = env.store; @@ -51,6 +51,33 @@ test("when a DS.Model updates its attributes, its changes affect its filtered Ar equal(get(people, 'length'), 0, "there are now no items"); }); +test("when a DS.Model updates its relationships, its changes affect its filtered Array membership", function() { + store.pushMany('person', array); + + var people = store.filter('person', function(person) { + if (person.get('bestFriend') && person.get('bestFriend.name').match(/Katz$/)) { return true; } + }); + + equal(get(people, 'length'), 1, "precond - one item is in the RecordArray"); + + var person = people.objectAt(0); + + equal(get(person, 'name'), "Scumbag Dale", "precond - the item is correct"); + + set(person, 'bestFriend', null); + + equal(get(people, 'length'), 0, "there are now 0 items"); + + var erik = store.getById('person', 3); + var yehuda = store.getById('person', 2); + erik.set('bestFriend', yehuda); + + person = people.objectAt(0); + equal(get(people, 'length'), 1, "there is now 1 item"); + equal(get(person, 'name'), "Scumbag Bryn", "precond - the item is correct"); +}); + + test("a record array can have a filter on it", function() { store.pushMany('person', array); diff --git a/tests/ember_configuration.js b/tests/ember_configuration.js index d0d80ac5c11..896c69a2036 100644 --- a/tests/ember_configuration.js +++ b/tests/ember_configuration.js @@ -177,6 +177,9 @@ clear: syncForTest() }); + DS.Relationship.prototype.addRecord = syncForTest(DS.Relationship.prototype.addRecord); + DS.Relationship.prototype.removeRecord = syncForTest(DS.Relationship.prototype.removeRecord); + var transforms = { 'boolean': DS.BooleanTransform.create(), 'date': DS.DateTransform.create(), From fd5e9cb0e9044ceda953dbb859d7153d018b1943 Mon Sep 17 00:00:00 2001 From: Jay Phelps Date: Thu, 4 Sep 2014 16:03:17 -0700 Subject: [PATCH 0330/2527] Added ember-addon support via npm --- lib/ember-addon-main.js | 26 ++++++++++++++++++++++++++ package.json | 13 ++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 lib/ember-addon-main.js diff --git a/lib/ember-addon-main.js b/lib/ember-addon-main.js new file mode 100644 index 00000000000..5574e7f6cd8 --- /dev/null +++ b/lib/ember-addon-main.js @@ -0,0 +1,26 @@ +'use strict'; + +module.exports = { + name: 'ember-data', + init: function() { + this.treePaths.vendor = 'dist'; + }, + included: function(app) { + this.app = app; + var options = { + exports: { + 'ember-data': [ + 'default' + ] + } + }; + + // This will use the pre-built version distributed with our package + // but still allow consumers to bower install their own version that + // will override ours. + this.app.import({ + development: 'vendor/ember-data/ember-data.js', + production: 'vendor/ember-data/ember-data.prod.js' + }, options); + } +}; \ No newline at end of file diff --git a/package.json b/package.json index d9fce8a2e3d..588040acc52 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,19 @@ "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", + "keywords": [ + "ember-addon" + ], + "ember-addon": { + "main": "lib/ember-addon-main.js" + }, "scripts": { "postinstall": "bower install", + "prepublish": "ember build --output-path=dist/ember-data/ --environment production", "start": "ember serve", - "dist": "rm -rf dist && ember build --environment production", + "dist": "ember build --environment production", "test": "testem -R dot ci", - "publish-build": "rm -rf dist && ember build --environment production && ./bin/publish_to_s3.js", + "publish-build": "npm run dist && ./bin/publish_to_s3.js", "testem-local": "testem -R dot ci", "testem-beta": "testem -f config/testem-beta.json -R dot ci", "testem-canary": "testem -f config/testem-canary.json -R dot ci", @@ -37,7 +44,7 @@ "broccoli-yuidoc": "^1.3.0", "defeatureify": "~0.1.4", "ejs": "^1.0.0", - "ember-cli": "0.0.40", + "ember-cli": "0.0.43", "ember-publisher": "0.0.6", "testem": "^0.6.17", "yuidocjs": "~0.3.46" From 5f34cbe43e055d7a6f0abb60bc683277f564d3a5 Mon Sep 17 00:00:00 2001 From: IgorT Date: Thu, 22 May 2014 18:30:33 -0300 Subject: [PATCH 0331/2527] Add ajaxSuccess hook to the RESTAdapter Previously there was no easy way to extract data from response headers or to reject promises after a 200OK response. --- .../ember-data/lib/adapters/rest_adapter.js | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index e97ac590624..59bb1bc3c14 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -2,8 +2,9 @@ @module ember-data */ -import Adapter from "ember-data/system/adapter"; +import {Adapter, InvalidError} from "ember-data/system/adapter"; var get = Ember.get; +var set = Ember.set; var forEach = Ember.ArrayPolyfills.forEach; /** @@ -729,6 +730,31 @@ export default Adapter.extend({ return jqXHR; }, + /** + Takes an ajax response, and returns the json payload. + + By default this hook just returns the jsonPayload passed to it. + You might want to override it in two cases: + + 1. Your API might return useful results in the request headers. + If you need to access these, you can override this hook to copy them + from jqXHR to the payload object so they can be processed in you serializer. + + + 2. Your API might return errors as successful responses with status code + 200 and an Errors text or object. You can return a DS.InvalidError from + this hook and it will automatically reject the promise and put your record + into the invald state. + + @method ajaxError + @param {Object} jqXHR + @return {Object} jqXHR + */ + + ajaxSuccess: function(jsonPayload, jqXHR) { + return jsonPayload; + }, + /** Takes a URL, an HTTP method and a hash of data, and makes an HTTP request. @@ -759,8 +785,13 @@ export default Adapter.extend({ return new Ember.RSVP.Promise(function(resolve, reject) { var hash = adapter.ajaxOptions(url, type, options); - hash.success = function(json) { - Ember.run(null, resolve, json); + hash.success = function(json, textStatus, jqXHR) { + json = this.ajaxSuccess(json, jqXHR); + if (InvalidError.detectInstance(json)){ + Ember.run(null, reject, json); + } else { + Ember.run(null, resolve, json); + } }; hash.error = function(jqXHR, textStatus, errorThrown) { From 89b8c9738345a0e67a7b5896328eab4a44fc5695 Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 11 Jun 2014 17:51:09 -0300 Subject: [PATCH 0332/2527] temp --- packages/ember-data/lib/adapters/rest_adapter.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 59bb1bc3c14..ee96b3670b2 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -720,9 +720,10 @@ export default Adapter.extend({ @method ajaxError @param {Object} jqXHR + @param {Object} responseText @return {Object} jqXHR */ - ajaxError: function(jqXHR) { + ajaxError: function(jqXHR, responseText) { if (jqXHR && typeof jqXHR === 'object') { jqXHR.then = null; } @@ -748,10 +749,11 @@ export default Adapter.extend({ @method ajaxError @param {Object} jqXHR + @param {Object} jsonPayload @return {Object} jqXHR */ - ajaxSuccess: function(jsonPayload, jqXHR) { + ajaxSuccess: function(jqXHR, jsonPayload) { return jsonPayload; }, @@ -786,7 +788,7 @@ export default Adapter.extend({ var hash = adapter.ajaxOptions(url, type, options); hash.success = function(json, textStatus, jqXHR) { - json = this.ajaxSuccess(json, jqXHR); + json = this.ajaxSuccess(jqXHR, json); if (InvalidError.detectInstance(json)){ Ember.run(null, reject, json); } else { @@ -795,7 +797,7 @@ export default Adapter.extend({ }; hash.error = function(jqXHR, textStatus, errorThrown) { - Ember.run(null, reject, adapter.ajaxError(jqXHR)); + Ember.run(null, reject, adapter.ajaxError(jqXHR, jqXHR.responseText)); }; Ember.$.ajax(hash); From 760a0a18be2f86e9370616158dab7391e8b7fed3 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 6 Sep 2014 12:44:18 -0500 Subject: [PATCH 0333/2527] tests and typo fix for ajaxSuccess/ajaxError --- .../ember-data/lib/adapters/rest_adapter.js | 12 +++-- .../integration/adapter/rest_adapter_test.js | 48 +++++++++++++++++++ 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index ee96b3670b2..7b4bf67ac56 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -2,9 +2,11 @@ @module ember-data */ -import {Adapter, InvalidError} from "ember-data/system/adapter"; +import { + Adapter, + InvalidError +} from "ember-data/system/adapter"; var get = Ember.get; -var set = Ember.set; var forEach = Ember.ArrayPolyfills.forEach; /** @@ -745,7 +747,7 @@ export default Adapter.extend({ 2. Your API might return errors as successful responses with status code 200 and an Errors text or object. You can return a DS.InvalidError from this hook and it will automatically reject the promise and put your record - into the invald state. + into the invald state. @method ajaxError @param {Object} jqXHR @@ -788,8 +790,8 @@ export default Adapter.extend({ var hash = adapter.ajaxOptions(url, type, options); hash.success = function(json, textStatus, jqXHR) { - json = this.ajaxSuccess(jqXHR, json); - if (InvalidError.detectInstance(json)){ + json = adapter.ajaxSuccess(jqXHR, json); + if (json instanceof InvalidError) { Ember.run(null, reject, json); } else { Ember.run(null, resolve, json); diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 47ba5bb0dbe..5fc44719cef 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -1461,3 +1461,51 @@ test('groupRecordsForFindMany groups calls for small ids', function() { post.get('comments'); }); + +test("calls adapter.ajaxSuccess with the jqXHR and json", function(){ + expect(2); + var originalAjax = Ember.$.ajax; + var jqXHR = {}; + var data = { + post: { + id: "1", + name: "Docker is amazing" + } + }; + + var receivedData, receivedJqXHR; + + Ember.$.ajax = function(hash){ + hash.success(data, 'ok', jqXHR); + }; + + adapter.ajaxSuccess = function(xhr, json) { + deepEqual(jqXHR, xhr); + deepEqual(json, data); + return json; + }; + + store.find('post', '1'); + Ember.$.ajax = originalAjax; +}); + +test('calls ajaxError with jqXHR, jqXHR.responseText', function(){ + expect(2); + var originalAjax = Ember.$.ajax; + var jqXHR = { + responseText: 'Nope lol' + }; + + Ember.$.ajax = function(hash){ + hash.error(jqXHR, jqXHR.responseText); + }; + + adapter.ajaxError = function(xhr, responseText) { + deepEqual(xhr, jqXHR); + deepEqual(responseText, jqXHR.responseText); + return {error: {nope: 'lol'}}; + }; + + store.find('post', '1'); + Ember.$.ajax = originalAjax; +}); From 6219cce535aac0c6f1ff5907ada56622fc5c9c35 Mon Sep 17 00:00:00 2001 From: Jay Phelps Date: Sun, 7 Sep 2014 13:42:39 -0700 Subject: [PATCH 0334/2527] ember add-on vendor tree is relative to this file, so needs to go back a dir --- lib/ember-addon-main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ember-addon-main.js b/lib/ember-addon-main.js index 5574e7f6cd8..f87b3be599a 100644 --- a/lib/ember-addon-main.js +++ b/lib/ember-addon-main.js @@ -3,7 +3,7 @@ module.exports = { name: 'ember-data', init: function() { - this.treePaths.vendor = 'dist'; + this.treePaths.vendor = '../dist'; }, included: function(app) { this.app = app; @@ -23,4 +23,4 @@ module.exports = { production: 'vendor/ember-data/ember-data.prod.js' }, options); } -}; \ No newline at end of file +}; From 9852f0bd7b629d440963018132c5ba7c2c572bbd Mon Sep 17 00:00:00 2001 From: Jay Phelps Date: Sun, 7 Sep 2014 14:35:23 -0700 Subject: [PATCH 0335/2527] Add-on uses blueprint `addBowerPackageToProject()` hook to add ed as bower dep instead of including a pre-built version --- lib/ember-addon-main.js | 26 ------------------- .../blueprints/ember-data/index.js | 13 ++++++++++ lib/ember-addon/index.js | 26 +++++++++++++++++++ package.json | 10 ++++--- 4 files changed, 45 insertions(+), 30 deletions(-) delete mode 100644 lib/ember-addon-main.js create mode 100644 lib/ember-addon/blueprints/ember-data/index.js create mode 100644 lib/ember-addon/index.js diff --git a/lib/ember-addon-main.js b/lib/ember-addon-main.js deleted file mode 100644 index f87b3be599a..00000000000 --- a/lib/ember-addon-main.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -module.exports = { - name: 'ember-data', - init: function() { - this.treePaths.vendor = '../dist'; - }, - included: function(app) { - this.app = app; - var options = { - exports: { - 'ember-data': [ - 'default' - ] - } - }; - - // This will use the pre-built version distributed with our package - // but still allow consumers to bower install their own version that - // will override ours. - this.app.import({ - development: 'vendor/ember-data/ember-data.js', - production: 'vendor/ember-data/ember-data.prod.js' - }, options); - } -}; diff --git a/lib/ember-addon/blueprints/ember-data/index.js b/lib/ember-addon/blueprints/ember-data/index.js new file mode 100644 index 00000000000..1141dee6c2c --- /dev/null +++ b/lib/ember-addon/blueprints/ember-data/index.js @@ -0,0 +1,13 @@ +'use strict'; + +module.exports = { + normalizeEntityName: function() { + // this prevents an error when the entityName is + // not specified (since that doesn't actually matter + // to us + }, + + afterInstall: function() { + return this.addBowerPackageToProject('ember-data', '1.0.0-beta.9'); + } +}; \ No newline at end of file diff --git a/lib/ember-addon/index.js b/lib/ember-addon/index.js new file mode 100644 index 00000000000..9e15c8f3638 --- /dev/null +++ b/lib/ember-addon/index.js @@ -0,0 +1,26 @@ +'use strict'; + +var path = require('path'); + +module.exports = { + name: 'ember-data', + blueprintsPath: function() { + return path.join(__dirname, 'blueprints'); + }, + included: function(app) { + this._super.included(app); + + var options = { + exports: { + 'ember-data': [ + 'default' + ] + } + }; + + this.app.import({ + development: app.bowerDirectory + '/ember-data/ember-data.js', + production: app.bowerDirectory + '/ember-data/ember-data.prod.js' + }, options); + } +}; \ No newline at end of file diff --git a/package.json b/package.json index 588040acc52..2660ef2fb8f 100644 --- a/package.json +++ b/package.json @@ -8,13 +8,15 @@ "ember-addon" ], "ember-addon": { - "main": "lib/ember-addon-main.js" + "main": "lib/ember-addon/index.js" }, + "files": [ + "lib/ember-addon" + ], "scripts": { - "postinstall": "bower install", - "prepublish": "ember build --output-path=dist/ember-data/ --environment production", + "prepublish": "bower install", "start": "ember serve", - "dist": "ember build --environment production", + "dist": "ember build --environment=production", "test": "testem -R dot ci", "publish-build": "npm run dist && ./bin/publish_to_s3.js", "testem-local": "testem -R dot ci", From 2c74207c31bf5186c9b203657861d48271a5b37d Mon Sep 17 00:00:00 2001 From: IgorT Date: Tue, 9 Sep 2014 03:00:56 +0200 Subject: [PATCH 0336/2527] Do not clear own relationships when deleting records If a record had a relationship, such as a `comment` having a `post`, previously if you did `comment.deleteRecord()`, `comment.get('post')` would immediately be set to `null`. This behavior was wrong for several reasons: 1.It prevented future rollback support for relationships 2.If you had nested URLs, you would not be able to send a DELETE request to /post/1/comments/1 because comment.get('post') would already have been deleted We now only clear the inverse side of the relationships when the record is deleted. The resulting refactor also enables us to add support for a record in a `404` state to be removed from relationships and for removing records from manyArrays that do not have inverses. --- packages/ember-data/lib/system/model/model.js | 6 +++ .../ember-data/lib/system/model/states.js | 8 ++-- .../lib/system/relationships/relationship.js | 42 ++++++++++------- .../relationships/many_to_many_test.js | 22 +++++++++ .../relationships/one_to_many_test.js | 45 +++++++++++++++++++ .../relationships/one_to_one_test.js | 24 ++++++++++ 6 files changed, 126 insertions(+), 21 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index def2cf24f1a..661c696b83a 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -642,6 +642,12 @@ var Model = Ember.Object.extend(Ember.Evented, { }, this); }, + disconnectRelationships: function() { + this.eachRelationship(function(name, relationship) { + this._relationships[name].disconnect(); + }, this); + }, + /** @method updateRecordArrays @private diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index a870e8e2371..a6389c824a2 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -324,7 +324,7 @@ var DirtyState = { // EVENTS deleteRecord: function(record) { record.transitionTo('deleted.uncommitted'); - record.clearRelationships(); + record.disconnectRelationships(); }, didSetProperty: function(record, context) { @@ -405,7 +405,7 @@ var updatedState = dirtyState({ }); createdState.uncommitted.deleteRecord = function(record) { - record.clearRelationships(); + record.disconnectRelationships(); record.transitionTo('deleted.saved'); }; @@ -424,7 +424,7 @@ updatedState.inFlight.unloadRecord = assertAgainstUnloadRecord; updatedState.uncommitted.deleteRecord = function(record) { record.transitionTo('deleted.uncommitted'); - record.clearRelationships(); + record.disconnectRelationships(); }; var RootState = { @@ -565,7 +565,7 @@ var RootState = { deleteRecord: function(record) { record.transitionTo('deleted.uncommitted'); - record.clearRelationships(); + record.disconnectRelationships(); }, unloadRecord: function(record) { diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index a3e3cf19b30..880e1a9f1bf 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -26,6 +26,12 @@ Relationship.prototype = { }, this); }, + disconnect: function(){ + this.members.forEach(function(member) { + this.removeRecordFromInverse(member); + }, this); + }, + removeRecords: function(records){ var that = this; records.forEach(function(record){ @@ -43,7 +49,6 @@ Relationship.prototype = { }); }, - addRecord: function(record, idx) { if (!this.members.has(record)) { this.members.add(record); @@ -57,19 +62,27 @@ Relationship.prototype = { removeRecord: function(record) { if (this.members.has(record)) { - this.members.remove(record); - this.notifyRecordRelationshipRemoved(record); + this.removeRecordFromOwn(record); if (this.inverseKey) { - var inverseRelationship = record._relationships[this.inverseKey]; - //Need to check for existence, as the record might unloading at the moment - if (inverseRelationship) { - inverseRelationship.removeRecord(this.record); - } + this.removeRecordFromInverse(record); } - this.record.updateRecordArrays(); } }, + removeRecordFromInverse: function(record) { + var inverseRelationship = record._relationships[this.inverseKey]; + //Need to check for existence, as the record might unloading at the moment + if (inverseRelationship) { + inverseRelationship.removeRecordFromOwn(this.record); + } + }, + + removeRecordFromOwn: function(record) { + this.members.remove(record); + this.notifyRecordRelationshipRemoved(record); + this.record.updateRecordArrays(); + }, + updateLink: function(link) { if (link !== this.link) { this.link = link; @@ -165,7 +178,6 @@ ManyRelationship.prototype.getRecords = function() { var BelongsToRelationship = function(store, record, inverseKey, relationshipMeta) { this._super$constructor(store, record, inverseKey, relationshipMeta); - this.members.add(record); this.record = record; this.key = relationshipMeta.key; this.inverseKey = inverseKey; @@ -206,17 +218,13 @@ BelongsToRelationship.prototype.notifyRecordRelationshipRemoved = function(recor this.record.notifyBelongsToRemoved(this.key, this); }; -BelongsToRelationship.prototype._super$removeRecord = Relationship.prototype.removeRecord; -BelongsToRelationship.prototype.removeRecord = function(record) { +BelongsToRelationship.prototype._super$removeRecordFromOwn = Relationship.prototype.removeRecordFromOwn; +BelongsToRelationship.prototype.removeRecordFromOwn = function(record) { if (!this.members.has(record)){ return;} - this._super$removeRecord(record); + this._super$removeRecordFromOwn(record); this.inverseRecord = null; }; -BelongsToRelationship.prototype.currentOtherSideFor = function() { - return this.inverseRecord; -}; - BelongsToRelationship.prototype.getRecord = function() { if (this.isAsync) { var promise; diff --git a/packages/ember-data/tests/integration/relationships/many_to_many_test.js b/packages/ember-data/tests/integration/relationships/many_to_many_test.js index 9711a2ebd09..9752c83309c 100644 --- a/packages/ember-data/tests/integration/relationships/many_to_many_test.js +++ b/packages/ember-data/tests/integration/relationships/many_to_many_test.js @@ -127,4 +127,26 @@ test("Removing a record from a hasMany reflects on the other hasMany side - sync }); +/* +Deleting tests +*/ +test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - async", function () { + var user = store.push('user', {id:1, name: 'Stanley', topics: [2]}); + var topic = store.push('topic', {id: 2, title: 'EmberFest was great'}); + topic.deleteRecord(); + topic.get('users').then(async(function(fetchedUsers) { + equal(fetchedUsers.get('length'), 1, 'Users are still there'); + })); + user.get('topics').then(async(function(fetchedTopics) { + equal(fetchedTopics.get('length'), 0, 'Topic got removed from the user'); + })); +}); + +test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function () { + var account = store.push('account', {id:2 , state: 'lonely'}); + var user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + account.deleteRecord(); + equal(account.get('users.length'), 1, 'Users are still there'); + equal(user.get('accounts.length'), 0, 'Acocount got removed from the user'); +}); diff --git a/packages/ember-data/tests/integration/relationships/one_to_many_test.js b/packages/ember-data/tests/integration/relationships/one_to_many_test.js index 2a3ba143e2f..b3f1ec09097 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_many_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_many_test.js @@ -295,3 +295,48 @@ test("Setting the belongsTo side to null removes the record from the hasMany sid equal(user.get('accounts.length'), 0, 'the account got removed correctly'); }); + +/* +Deleting +*/ + +test("When deleting a record that has a belongsTo it is removed from the hasMany side but not the belongsTo side- async", function () { + var user = store.push('user', {id:1, name: 'Stanley', messages: [2]}); + var message = store.push('message', {id: 2, title: 'EmberFest was great'}); + message.deleteRecord(); + message.get('user').then(async(function(fetchedUser) { + equal(fetchedUser, user, 'Message still has the user'); + })); + user.get('messages').then(async(function(fetchedMessages) { + equal(fetchedMessages.get('length'), 0, 'User was removed from the messages'); + })); +}); + +test("When deleting a record that has a belongsTo it is removed from the hasMany side but not the belongsTo side- sync", function () { + var account = store.push('account', {id:2 , state: 'lonely'}); + var user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + account.deleteRecord(); + equal(user.get('accounts.length'), 0, "User was removed from the accounts"); + equal(account.get('user'), user, 'Account still has the user'); +}); + +test("When deleting a record that has a hasMany it is removed from the belongsTo side but not the hasMany side- async", function () { + var user = store.push('user', {id:1, name: 'Stanley', messages: [2]}); + var message = store.push('message', {id: 2, title: 'EmberFest was great'}); + user.deleteRecord(); + message.get('user').then(async(function(fetchedUser) { + equal(fetchedUser, null, 'Message does not have the user anymore'); + })); + user.get('messages').then(async(function(fetchedMessages) { + equal(fetchedMessages.get('length'), 1, 'User still has the messages'); + })); +}); + +test("When deleting a record that has a hasMany it is removed from the belongsTo side but not the hasMany side - sync", function () { + var account = store.push('account', {id:2 , state: 'lonely'}); + var user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + user.deleteRecord(); + equal(user.get('accounts.length'), 1, "User still has the accounts"); + equal(account.get('user'), null, 'Account no longer has the user'); +}); + diff --git a/packages/ember-data/tests/integration/relationships/one_to_one_test.js b/packages/ember-data/tests/integration/relationships/one_to_one_test.js index 45d1835759e..4dabff8985c 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_one_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_one_test.js @@ -167,3 +167,27 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu equal(newBetterJob.get('user'), user, 'New job setup correctly'); }); +/* +Deleting tests +*/ + +test("When deleting a record that has a belongsTo relationship, the record is removed from the inverse but still has access to its own relationship - async", function () { + var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); + var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + stanley.deleteRecord(); + stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { + equal(fetchedUser, null, 'Stanley got removed'); + })); + stanley.get('bestFriend').then(async(function(fetchedUser) { + equal(fetchedUser, stanleysFriend, 'Stanleys friend did not get removed'); + })); +}); + +test("When deleting a record that has a belongsTo relationship, the record is removed from the inverse but still has access to its own relationship - sync", function () { + var job = store.push('job', {id:2 , isGood: true}); + var user = store.push('user', {id:1, name: 'Stanley', job:2 }); + job.deleteRecord(); + equal(user.get('job'), null, 'Job got removed from the user'); + equal(job.get('user'), user, 'Job still has the user'); +}); + From a97b492a055ff2a1a3d88eade8a1bb88c1a4da83 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 8 Sep 2014 22:39:59 -0500 Subject: [PATCH 0337/2527] add es5-shim/sham requirement to README also add es5-shim to bower_components for test and use IE conditional comments to load them. --- README.md | 4 ++++ bower.json | 3 ++- tests/index.html | 6 ++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 080ea6ee355..5dc996b543a 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,10 @@ You also have the option to build ember-data.js yourself. Clone the repository, run `broccoli build dist` after [setup](#setup). You'll find ember-data.js in the `dist` directory. +#### Internet Explorer 8 + +If you need to support Internet Explorer, you will need to use es5-shim.js and es5-sham.js from [es5-shim](https://github.com/es-shims/es5-shim). + ### Instantiating the Store In Ember Data, the _store_ is responsible for managing the lifecycle of diff --git a/bower.json b/bower.json index 611d7a639b3..1290510f7ed 100644 --- a/bower.json +++ b/bower.json @@ -9,6 +9,7 @@ }, "devDependencies": { "loader.js": "~1.0.0", - "ember-inflector": "https://github.com/stefanpenner/ember-inflector.git#v1.1.0" + "ember-inflector": "https://github.com/stefanpenner/ember-inflector.git#v1.1.0", + "es5-shim": "~4.0.3" } } diff --git a/tests/index.html b/tests/index.html index a9890e4f9df..7e3d1a63451 100644 --- a/tests/index.html +++ b/tests/index.html @@ -32,6 +32,7 @@ // Close the script tag to make sure document.write happens + + + From 48e2a63ff4084ceb869863235506a0c1e86b131f Mon Sep 17 00:00:00 2001 From: "Alessandro D'Aquino (elara)" Date: Tue, 9 Sep 2014 16:40:38 +0200 Subject: [PATCH 0338/2527] Bring back relationship parameter for findHasMany & findBelongsTo Signed-off-by: Alessandro D'Aquino (elara) --- packages/ember-data/lib/adapters/rest_adapter.js | 4 ++-- .../lib/system/relationships/relationship.js | 2 +- packages/ember-data/lib/system/store.js | 14 +++++++------- .../integration/relationships/has_many_test.js | 9 ++++++--- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 7b4bf67ac56..8ef73a7ada0 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -392,7 +392,7 @@ export default Adapter.extend({ @param {String} url @return {Promise} promise */ - findHasMany: function(store, record, url) { + findHasMany: function(store, record, url, relationship) { var host = get(this, 'host'); var id = get(record, 'id'); var type = record.constructor.typeKey; @@ -431,7 +431,7 @@ export default Adapter.extend({ @param {String} url @return {Promise} promise */ - findBelongsTo: function(store, record, url) { + findBelongsTo: function(store, record, url, relationship) { var id = get(record, 'id'); var type = record.constructor.typeKey; diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index a3e3cf19b30..2d66b921ad8 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -138,7 +138,7 @@ ManyRelationship.prototype.getRecords = function() { var self = this; var promise; if (this.link && !this.hasFetchedLink) { - promise = this.store.findHasMany(this.record, this.link, this.belongsToType).then(function(records){ + promise = this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function(records){ self.updateRecordsFromAdapter(records); self.hasFetchedLink = true; //TODO(Igor) try to abstract the isLoaded part diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 910921a9df8..c9c932fdc9d 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1765,23 +1765,23 @@ function _findMany(adapter, store, type, ids, records) { }, null, "DS: Extract payload of " + type); } -function _findHasMany(adapter, store, record, link, type) { - var promise = adapter.findHasMany(store, record, link); - var serializer = serializerForAdapter(adapter, type); - var label = "DS: Handle Adapter#findHasMany of " + record + " : " + type; +function _findHasMany(adapter, store, record, link, relationship) { + var promise = adapter.findHasMany(store, record, link, relationship); + var serializer = serializerForAdapter(adapter, relationship.type); + var label = "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type; promise = Promise.cast(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); promise = _guard(promise, _bind(_objectIsAlive, record)); return promise.then(function(adapterPayload) { - var payload = serializer.extract(store, type, adapterPayload, null, 'findHasMany'); + var payload = serializer.extract(store, relationship.type, adapterPayload, null, 'findHasMany'); Ember.assert("The response from a findHasMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); - var records = store.pushMany(type, payload); + var records = store.pushMany(relationship.type, payload); return records; - }, null, "DS: Extract payload of " + record + " : hasMany " + type); + }, null, "DS: Extract payload of " + record + " : hasMany " + relationship.type); } function _findBelongsTo(adapter, store, record, link, relationship) { diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index b8cf3d1cedb..452d6b6b439 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -99,8 +99,9 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi throw new Error("Adapter's findMany should not be called"); }; - env.adapter.findHasMany = function(store, record, link) { + env.adapter.findHasMany = function(store, record, link, relationship) { equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); + equal(relationship.type.typeKey, "comment", "relationship was passed correctly"); return Ember.RSVP.resolve([ { id: 1, body: "First" }, @@ -118,12 +119,14 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi }); test("An updated `links` value should invalidate a relationship cache", function() { - expect(6); + expect(8); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - env.adapter.findHasMany = function(store, record, link) { + env.adapter.findHasMany = function(store, record, link, relationship) { + equal(relationship.type.typeKey, "comment", "relationship was passed correctly"); + if (link === '/first') { return Ember.RSVP.resolve([ { id: 1, body: "First" }, From e588cf7ccbc4dabe513185f6d4521620f6154c08 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 9 Sep 2014 16:42:00 -0500 Subject: [PATCH 0339/2527] update changelog for beta.10 --- CHANGELOG.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cd31ad641a..aeb272af3a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,30 @@ ### Master +### Ember Data 1.0.0-beta.10 _(September 9, 2014)_ + +* Bring back relationship parameter for findHasMany & findBelongsTo +* add es5-shim/sham requirement to README +* Add-on uses blueprint `addBowerPackageToProject()` hook to add ed as bower dep instead of including a pre-built version +* ember add-on vendor tree is relative to this file, so needs to go back a dir +* tests and typo fix for ajaxSuccess/ajaxError +* Add ajaxSuccess hook to the RESTAdapter +* Added ember-addon support via npm +* Update recordArrays whenever there are changes to relationships +* Refactor relationship handling code +* Add support for embedded polymorphic hasMany +* improve error message for push +* [BUGFIX] fixture adapter copies defined fixtures +* remove unused variables and enforce in jshint +* Updated docs to warn against use of async:true with EmbeddedRecodsMixin +* Removed a duplicate explanation of preload +* small perf, this map was unfortunately adding 5ms -> 8ms overhead for pushMany of N=1000. Removing it removed the overhead entirely. +* modelFor was used constantly, the extra normalization and string splitting was causing measurable slowdown. +* Don't use the DOM in the store tests +* Added an example of how to use the preload arg +* Added documentation for preload parameter +* [Documentation] typo in `find` documentation + ### Ember Data 1.0.0-beta.9 _(August 18, 2014)_ **Important:** IE8 and other environments which don't support `Object.create` From 69abb31b8e7b8657bb4fad7366b801d8399171c7 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 9 Sep 2014 16:47:44 -0500 Subject: [PATCH 0340/2527] update for beta.10 --- lib/ember-addon/blueprints/ember-data/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ember-addon/blueprints/ember-data/index.js b/lib/ember-addon/blueprints/ember-data/index.js index 1141dee6c2c..ded2b37ae4d 100644 --- a/lib/ember-addon/blueprints/ember-data/index.js +++ b/lib/ember-addon/blueprints/ember-data/index.js @@ -8,6 +8,6 @@ module.exports = { }, afterInstall: function() { - return this.addBowerPackageToProject('ember-data', '1.0.0-beta.9'); + return this.addBowerPackageToProject('ember-data', '1.0.0-beta.10'); } -}; \ No newline at end of file +}; From bca0460daa7b929489f0ed2a0f895860cfc08cba Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 9 Sep 2014 16:49:07 -0500 Subject: [PATCH 0341/2527] package.json should reflect ember v1.0.0-beta.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2660ef2fb8f..c72b1d616bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.10+canary", + "version": "1.0.0-beta.10", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", From 12ecc96f404346f6122ee7da35eec462b702cf7c Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 9 Sep 2014 16:55:35 -0500 Subject: [PATCH 0342/2527] post release version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c72b1d616bb..60b799bf3a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.10", + "version": "1.0.0-beta.11+canary", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", From 131119a162d222e8e36a6c9b26cc1f49f3be5edf Mon Sep 17 00:00:00 2001 From: Sam Selikoff Date: Wed, 10 Sep 2014 13:54:02 -0400 Subject: [PATCH 0343/2527] Small typo in #normalize documentation --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index c9c932fdc9d..c7af3f74a86 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1386,7 +1386,7 @@ Store = Ember.Object.extend({ ``` @method normalize - @param {String} The name of the model type for this payload + @param {String} type The name of the model type for this payload @param {Object} payload @return {Object} The normalized payload */ From 4b472f15a397df06282622fa87e4db4186b2061f Mon Sep 17 00:00:00 2001 From: IgorT Date: Thu, 11 Sep 2014 12:35:18 +0200 Subject: [PATCH 0344/2527] Fix the build by making more things syncForTest :( --- tests/ember_configuration.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/ember_configuration.js b/tests/ember_configuration.js index 896c69a2036..229d06c3382 100644 --- a/tests/ember_configuration.js +++ b/tests/ember_configuration.js @@ -168,7 +168,8 @@ reload: syncForTest(), deleteRecord: syncForTest(), dataDidChange: Ember.observer(syncForTest(), 'data'), - updateRecordArraysLater: syncForTest() + updateRecordArraysLater: syncForTest(), + updateRecordArrays: syncForTest() }); DS.Errors.reopen({ @@ -179,6 +180,8 @@ DS.Relationship.prototype.addRecord = syncForTest(DS.Relationship.prototype.addRecord); DS.Relationship.prototype.removeRecord = syncForTest(DS.Relationship.prototype.removeRecord); + DS.Relationship.prototype.removeRecordFromInverse = syncForTest(DS.Relationship.prototype.removeRecordFromInverse); + DS.Relationship.prototype.removeRecordFromOwn = syncForTest(DS.Relationship.prototype.removeRecordFromOwn); var transforms = { 'boolean': DS.BooleanTransform.create(), From 64fb2faf7aea25261816e93375dec24f2eb608f2 Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Thu, 11 Sep 2014 14:39:01 +0200 Subject: [PATCH 0345/2527] removed private unused properties in ManyArray --- .../lib/system/record_arrays/many_array.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 90cf09c7e4e..1ec57d2b8ee 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -47,22 +47,6 @@ export default RecordArray.extend({ this._super.apply(this, arguments); }, - /** - The property name of the relationship - - @property {String} name - @private - */ - name: null, - - /** - The record to which this relationship belongs. - - @property {DS.Model} owner - @private - */ - owner: null, - /** `true` if the relationship is polymorphic, `false` otherwise. From 5d7c01575abc42bdf927056d12a5888146e055e8 Mon Sep 17 00:00:00 2001 From: Pepe Cano Date: Tue, 26 Aug 2014 12:54:15 +0200 Subject: [PATCH 0346/2527] Add a test for an async belongsTo with buildURL --- .../integration/adapter/rest_adapter_test.js | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 5fc44719cef..d5c3c2330b1 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -1245,6 +1245,30 @@ test('buildURL - buildURL takes a record from create', function() { })); }); +test('buildURL - buildURL takes a record from create to query a resolved async belongsTo relationship', function() { + Comment.reopen({ post: DS.belongsTo('post', {async: true}) }); + + ajaxResponse({ posts: [{ id: 2 }] }); + + store.find('post', 2).then(async(function(post) { + equal(post.get('id'), 2); + + adapter.buildURL = function(type, id, record) { + return "/posts/" + record.get('post.id') + '/comments/'; + }; + + ajaxResponse({ comments: [{ id: 1 }] }); + + var comment = store.createRecord('comment'); + comment.set('post', post); + comment.save().then(async(function(post) { + equal(passedUrl, "/posts/2/comments/"); + })); + + })); + +}); + test('buildURL - buildURL takes a record from update', function() { Comment.reopen({ post: DS.belongsTo('post') }); adapter.buildURL = function(type, id, record) { From 12301b9405c4ffde31d9dd027c8b266c1231d0f8 Mon Sep 17 00:00:00 2001 From: IgorT Date: Thu, 11 Sep 2014 15:34:48 +0200 Subject: [PATCH 0347/2527] preload the belongsTo to be available synchronously --- packages/ember-data/lib/system/relationships/relationship.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index d060d306b4d..b131f0ae68b 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -243,7 +243,8 @@ BelongsToRelationship.prototype.getRecord = function() { } return PromiseObject.create({ - promise: promise + promise: promise, + content: this.inverseRecord }); } else { Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.constructor.typeKey + "' with id " + this.record.get('id') + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", this.inverseRecord === null || !this.inverseRecord.get('isEmpty')); From aa91b3c78e69c73049b085fc66d59c36204121d4 Mon Sep 17 00:00:00 2001 From: IgorT Date: Thu, 11 Sep 2014 15:55:56 +0200 Subject: [PATCH 0348/2527] Update jsfiddle/jsbin to latest ember-data in CONTRIBUTING.md --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1ef9ea3901e..053333b5bf0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,11 +24,11 @@ this bug already. 3. Provide JSFiddle or JSBin demo that specifically shows the problem. This demo should be fully operational with the exception of the bug you want to -demonstrate. The more pared down, the better. A preconfigured [JSFiddle][1] | -[JSBin][2] with mocked requests is available. +demonstrate. The more pared down, the better. A preconfigured [JSBin][1] | +[JSFiddle][2] with mocked requests is available. -[1]: http://jsfiddle.net/mehulkar/Q5NPs/ -[2]: http://emberjs.jsbin.com/vuxijava/1/edit +[1]: http://emberjs.jsbin.com/butef/1/edit +[2]: http://jsfiddle.net/ty6xgfqc/ 4. If possible, submit a Pull Request with a failing test. Better yet, take a stab at fixing the bug yourself if you can! From 51786b1e02950e47f8ad16b067712b086252eb75 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Tue, 16 Sep 2014 11:13:52 -0400 Subject: [PATCH 0349/2527] [DOCS] Cleanup "USING EMBEDDED RECORDS" API readability --- .../lib/serializers/embedded_records_mixin.js | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/ember-data/lib/serializers/embedded_records_mixin.js b/packages/ember-data/lib/serializers/embedded_records_mixin.js index 2477534c592..db564bff7ae 100644 --- a/packages/ember-data/lib/serializers/embedded_records_mixin.js +++ b/packages/ember-data/lib/serializers/embedded_records_mixin.js @@ -15,21 +15,24 @@ var camelize = Ember.String.camelize; ```js App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - author: {embedded: 'always'}, - comments: {serialize: 'ids'} + author: { embedded: 'always' }, + comments: { serialize: 'ids' } } - }) + }); ``` - Note that this use of `{embedded: 'always'}` is unrelated to - the `{embedded: 'always'}` that is defined as an option on `DS.attr` as part of + Note that this use of `{ embedded: 'always' }` is unrelated to + the `{ embedded: 'always' }` that is defined as an option on `DS.attr` as part of defining a model while working with the ActiveModelSerializer. Nevertheless, - using `{embedded: 'always'}` as an option to DS.attr is not a valid way to setup + using `{ embedded: 'always' }` as an option to DS.attr is not a valid way to setup embedded records. - The `attrs` option for a resource `{embedded: 'always'}` is shorthand for: + The `attrs` option for a resource `{ embedded: 'always' }` is shorthand for: ```js - {serialize: 'records', deserialize: 'records'} + { + serialize: 'records', + deserialize: 'records' + } ``` ### Configuring Attrs @@ -53,8 +56,8 @@ var camelize = Ember.String.camelize; If you do not overwrite `attrs` for a specific relationship, the `EmbeddedRecordsMixin` will behave in the following way: - BelongsTo: `{serialize:'id', deserialize:'id'}` - HasMany: `{serialize:false, deserialize:'ids'}` + BelongsTo: `{ serialize: 'id', deserialize: 'id' }` + HasMany: `{ serialize: false, deserialize: 'ids' }` ### Model Relationships From c09427b932eb831f9415c959a0b6f6765da9adc5 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Tue, 16 Sep 2014 11:15:34 -0400 Subject: [PATCH 0350/2527] Remove extra space in code example --- packages/ember-data/lib/serializers/embedded_records_mixin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/embedded_records_mixin.js b/packages/ember-data/lib/serializers/embedded_records_mixin.js index db564bff7ae..3b0d9633488 100644 --- a/packages/ember-data/lib/serializers/embedded_records_mixin.js +++ b/packages/ember-data/lib/serializers/embedded_records_mixin.js @@ -57,7 +57,7 @@ var camelize = Ember.String.camelize; will behave in the following way: BelongsTo: `{ serialize: 'id', deserialize: 'id' }` - HasMany: `{ serialize: false, deserialize: 'ids' }` + HasMany: `{ serialize: false, deserialize: 'ids' }` ### Model Relationships From f80eb16d3b1707a2ffd9ca33c54ac4d580634c4f Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 17 Sep 2014 18:59:29 +0200 Subject: [PATCH 0351/2527] Serialize belongsTo where id===null as null --- .../ember-data/lib/serializers/json_serializer.js | 5 +++-- .../serializers/json_serializer_test.js | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index dc1e54d3fe7..552b100a7bc 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -583,8 +583,9 @@ export default Ember.Object.extend({ payloadKey = this.keyForRelationship(key, "belongsTo"); } - if (isNone(belongsTo)) { - json[payloadKey] = belongsTo; + //Need to check whether the id is there for new&async records + if (isNone(belongsTo) || isNone(get(belongsTo, 'id'))) { + json[payloadKey] = null; } else { json[payloadKey] = get(belongsTo, 'id'); } diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index bf008130866..8a07ffd6e05 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -76,6 +76,20 @@ test("serializeBelongsTo with null", function() { }, "Can set a belongsTo to a null value"); }); +test("async serializeBelongsTo with null", function() { + Comment.reopen({ + post: DS.belongsTo('post', {async:true}) + }); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: null}); + var json = {}; + + env.serializer.serializeBelongsTo(comment, json, {key: "post", options: {}}); + + deepEqual(json, { + post: null + }, "Can set a belongsTo to a null value"); +}); + test("serializeBelongsTo respects keyForRelationship", function() { env.container.register('serializer:post', DS.JSONSerializer.extend({ keyForRelationship: function(key, type) { From fb3acadfaa264567a0ad67ff86709e3b991dd312 Mon Sep 17 00:00:00 2001 From: IgorT Date: Fri, 19 Sep 2014 01:19:24 +0200 Subject: [PATCH 0352/2527] Improve comments for the inverseFor method --- .../lib/system/relationships/ext.js | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 28d8ab100b6..4ef39889ffc 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -102,17 +102,41 @@ Model.reopenClass({ return relationship && relationship.type; }, + /* + Find the relationship which is the inverse of the one asked for. + + For example, if you define models like this: + + ```javascript + App.Post = DS.Model.extend({ + comments: DS.hasMany('message', {inverse: null}) + }); + + App.Message = DS.Model.extend({ + owner: DS.belongsTo('post') + }); + ``` + + App.Post.inverseFor('comments') -> {type: App.Message, name:'owner', kind:'belongsTo'} + App.Message.inverseFor('owner') -> {type: App.Post, name:'comments', kind:'hasMany'} + + @method inverseFor + @static + @param {String} name the name of the relationship + @return {Object} the inverse relationship, or null + */ inverseFor: function(name) { - var inverseType = this.typeForRelationship(name); + var inverseType = this.typeForRelationship(name); if (!inverseType) { return null; } + //If inverse is manually specified to be null, like `comments: DS.hasMany('message', {inverse: null})` var options = this.metaForProperty(name).options; - if (options.inverse === null) { return null; } var inverseName, inverseKind, inverse; + //If inverse is specified manually, return the inverse if (options.inverse) { inverseName = options.inverse; inverse = Ember.get(inverseType, 'relationshipsByName').get(inverseName); @@ -122,6 +146,7 @@ Model.reopenClass({ inverseKind = inverse.kind; } else { + //No inverse was specified manually, we need to use a heuristic to guess one var possibleRelationships = findPossibleInverses(this, inverseType); if (possibleRelationships.length === 0) { return null; } @@ -145,6 +170,7 @@ Model.reopenClass({ possibleRelationships.push.apply(possibleRelationships, relationshipMap.get(type)); } + //Recurse to support polymorphism if (type.superclass) { findPossibleInverses(type.superclass, inverseType, possibleRelationships); } From 51360955bac2082ce35c7c1096ff74e607b22ce9 Mon Sep 17 00:00:00 2001 From: IgorT Date: Tue, 9 Sep 2014 05:34:09 +0200 Subject: [PATCH 0353/2527] Added implicit relationships We now correctly remove a record from a manyArray when it is deleted even if the record does not have a belongsTo relationship to the manyArray --- packages/ember-data/lib/system/model/model.js | 25 +++++++++++++++++++ .../lib/system/relationships/relationship.js | 18 +++++++++++-- .../tests/unit/record_array_test.js | 16 ++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 661c696b83a..5056dc4a687 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -445,6 +445,27 @@ var Model = Ember.Object.extend(Ember.Evented, { this._attributes = {}; this._inFlightAttributes = {}; this._relationships = {}; + /* + implicit relationships are relationship which have not been declared but the inverse side exists on + another record somewhere + For example if there was + ``` + App.Comment = DS.Model.extend({ + name: DS.attr() + }) + ``` + but there is also + ``` + App.Post = DS.Model.extend({ + name: DS.attr(), + comments: DS.hasMany('comment') + }) + ``` + + would have a implicit post relationship in order to be do things like remove ourselves from the post + when we are deleted + */ + this._implicitRelationships = Object.create(null); var model = this; //TODO Move into a getter for better perf this.constructor.eachRelationship(function(key, descriptor) { @@ -646,6 +667,10 @@ var Model = Ember.Object.extend(Ember.Evented, { this.eachRelationship(function(name, relationship) { this._relationships[name].disconnect(); }, this); + var model = this; + forEach.call(Ember.keys(this._implicitRelationships), function(key) { + model._implicitRelationships[key].disconnect(); + }); }, /** diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index b131f0ae68b..ab3c195b7f9 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -12,6 +12,9 @@ var Relationship = function(store, record, inverseKey, relationshipMeta) { this.key = relationshipMeta.key; this.isAsync = relationshipMeta.options.async; this.relationshipMeta = relationshipMeta; + //This probably breaks for polymorphic relationship in complex scenarios, due to + //multiple possible typeKeys + this.inversKeyForimplicit = this.typeKey + this.key; }; Relationship.prototype = { @@ -55,6 +58,11 @@ Relationship.prototype = { this.notifyRecordRelationshipAdded(record, idx); if (this.inverseKey) { record._relationships[this.inverseKey].addRecord(this.record); + } else { + if (!record._implicitRelationships[this.inverseKeyForimplicit]) { + record._implicitRelationships[this.inverseKeyForimplicit] = new Relationship(this.store, record, this.key, {options:{}}); + } + record._implicitRelationships[this.inverseKeyForimplicit].addRecord(this.record); } this.record.updateRecordArrays(); } @@ -65,6 +73,10 @@ Relationship.prototype = { this.removeRecordFromOwn(record); if (this.inverseKey) { this.removeRecordFromInverse(record); + } else { + if (record._implicitRelationships[this.inverseKeyForimplicit]) { + record._implicitRelationships[this.inverseKeyForimplicit].removeRecord(this.record); + } } } }, @@ -94,7 +106,10 @@ Relationship.prototype = { updateRecordsFromAdapter: function(records) { //TODO Once we have adapter support, we need to handle updated and canonical changes this.computeChanges(records); - } + }, + + notifyRecordRelationshipAdded: Ember.K, + notifyRecordRelationshipRemoved: Ember.K }; var ManyRelationship = function(store, record, inverseKey, relationshipMeta) { @@ -180,7 +195,6 @@ var BelongsToRelationship = function(store, record, inverseKey, relationshipMeta this._super$constructor(store, record, inverseKey, relationshipMeta); this.record = record; this.key = relationshipMeta.key; - this.inverseKey = inverseKey; this.inverseRecord = null; }; diff --git a/packages/ember-data/tests/unit/record_array_test.js b/packages/ember-data/tests/unit/record_array_test.js index 870a6fb25ec..2bc41ae323a 100644 --- a/packages/ember-data/tests/unit/record_array_test.js +++ b/packages/ember-data/tests/unit/record_array_test.js @@ -72,6 +72,22 @@ test("a loaded record is removed from a record array when it is deleted", functi })); }); +test("a loaded record is removed from a record array when it is deleted even if the belongsTo side isn't defined", function() { + var Tag = DS.Model.extend({ + people: DS.hasMany('person') + }); + + var env = setupStore({ tag: Tag, person: Person }), + store = env.store; + + var scumbag = store.push('person', {id:1, name: 'Scumbag Tom'}); + var tag = store.push('tag', { id: 1, people:[1] }); + + scumbag.deleteRecord(); + + equal(tag.get('people.length'), 0, "record is removed from the record array"); +}); + // GitHub Issue #168 test("a newly created record is removed from a record array when it is deleted", function() { var store = createStore(), From 16c0851862ae2676ec334f550cd96ea3517236fe Mon Sep 17 00:00:00 2001 From: Sylvain MINA Date: Fri, 19 Sep 2014 11:05:13 +0200 Subject: [PATCH 0354/2527] [DOC fix] Remove misleading {inverse: null} --- packages/ember-data/lib/system/relationships/ext.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 4ef39889ffc..493c1d1482d 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -109,7 +109,7 @@ Model.reopenClass({ ```javascript App.Post = DS.Model.extend({ - comments: DS.hasMany('message', {inverse: null}) + comments: DS.hasMany('message') }); App.Message = DS.Model.extend({ From 19f2eb34425bc8b427d4711d9f6e0af384c608ed Mon Sep 17 00:00:00 2001 From: IgorT Date: Fri, 30 May 2014 20:16:12 -0300 Subject: [PATCH 0355/2527] Added a reload to the ManyArray It works both with links and with URLs --- .../lib/system/record_arrays/many_array.js | 31 +++++++ .../relationships/has_many_test.js | 86 +++++++++++++++++++ tests/ember_configuration.js | 5 ++ 3 files changed, 122 insertions(+) diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 1ec57d2b8ee..30ba05cc29b 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -109,6 +109,37 @@ export default RecordArray.extend({ this.get('relationship').addRecords(objects, idx); } }, + /** + @method reload + @public + */ + reload: function() { + //todo guard against reloading while already reloading + //monitor reloading state + //handle failure + var record = get(this, 'owner'); + var data = get(record, 'data'); + var key = get(this, 'name'); + var link = data.links && data.links[key]; + var store = get(this, 'store'); + var promiseLabel = "DS: Async hasMany reloading " + record + " : " + key; + var resolver = Ember.RSVP.defer(promiseLabel); + var promise; + var manyArray = this; + if (link) { + store.findHasMany(record, link, relationshipFromMeta(store, record.constructor.metaForProperty(key)), resolver); + promise = resolver.promise.then(function(){ + return manyArray; + }); + } else { + var records = get(this, 'content'); + promise = Ember.RSVP.all( records.map( function(record) { return record.reload(); }) ).then(function(){ return manyArray;}); + } + + return PromiseArray.create({ + promise: promise + }); + }, /** Create a child record within the owner diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 452d6b6b439..67de699b682 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -118,6 +118,92 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi })); }); +test("A hasMany relationship can be reloaded if it was fetched via a link", function() { + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + env.adapter.find = function(store, type, id) { + equal(type, Post, "find type was Post"); + equal(id, "1", "find id was 1"); + + return Ember.RSVP.resolve({ id: 1, links: { comments: "/posts/1/comments" } }); + }; + + env.adapter.findHasMany = function(store, record, link, relationship) { + equal(relationship.type, Comment, "findHasMany relationship type was Comment"); + equal(relationship.key, 'comments', "findHasMany relationship key was comments"); + equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); + + return Ember.RSVP.resolve([ + { id: 1, body: "First" }, + { id: 2, body: "Second" } + ]); + }; + + env.store.find('post', 1).then(async(function(post) { + return post.get('comments'); + })).then(async(function(comments) { + equal(comments.get('isLoaded'), true, "comments are loaded"); + equal(comments.get('length'), 2, "comments have 2 length"); + + env.adapter.findHasMany = function(store, record, link, relationship) { + equal(relationship.type, Comment, "findHasMany relationship type was Comment"); + equal(relationship.key, 'comments', "findHasMany relationship key was comments"); + equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); + + return Ember.RSVP.resolve([ + { id: 1, body: "First" }, + { id: 2, body: "Second" }, + { id: 3, body: "Thirds" } + ]); + }; + + return comments.reload(); + })).then(async(function(newComments){ + equal(newComments.get('length'), 3, "reloaded comments have 3 length"); + })); +}); + +test("A hasMany relationship can be reloaded if it was fetched via ids", function() { + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + debugger + env.adapter.find = function(store, type, id) { + equal(type, Post, "find type was Post"); + equal(id, "1", "find id was 1"); + + return Ember.RSVP.resolve({ id: 1, comments: [1,2] }); + }; + + env.adapter.findMany = function(store, type, ids, records) { + return Ember.RSVP.resolve([ + { id: 1, body: "First" }, + { id: 2, body: "Second" } + ]); + }; + + env.store.find('post', 1).then(async(function(post) { + return post.get('comments'); + })).then(async(function(comments) { + equal(comments.get('isLoaded'), true, "comments are loaded"); + equal(comments.get('length'), 2, "comments have 2 length"); + + env.adapter.findMany = function(store, type, ids, records) { + return Ember.RSVP.resolve([ + { id: 1, body: "FirstUpdated" }, + { id: 2, body: "Second" } + ]); + }; + + return comments.reload(); + })).then(async(function(newComments){ + equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); + })); +}); + test("An updated `links` value should invalidate a relationship cache", function() { expect(8); Post.reopen({ diff --git a/tests/ember_configuration.js b/tests/ember_configuration.js index 229d06c3382..c1da5c46ed1 100644 --- a/tests/ember_configuration.js +++ b/tests/ember_configuration.js @@ -152,6 +152,7 @@ filter: syncForTest(), find: syncForTest(), findMany: syncForTest(), + findHasMany: syncForTest(), findByIds: syncForTest(), didSaveRecord: syncForTest(), didSaveRecords: syncForTest(), @@ -172,6 +173,10 @@ updateRecordArrays: syncForTest() }); + DS.ManyArray.reopen({ + reload: syncForTest() + }); + DS.Errors.reopen({ add: syncForTest(), remove: syncForTest(), From dfdeeb82303a266000870cabc094d6edf016df76 Mon Sep 17 00:00:00 2001 From: Tom Coquereau Date: Fri, 19 Sep 2014 10:03:42 +0200 Subject: [PATCH 0356/2527] Add a test for reload on sync hasMany relationships --- .../relationships/has_many_test.js | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 67de699b682..a72e9a9036f 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -165,12 +165,46 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func })); }); +test("A sync hasMany relationship can be reloaded if it was fetched via ids", function() { + Post.reopen({ + comments: DS.hasMany('comment') + }); + + debugger; + + env.adapter.find = function(store, type, id) { + equal(type, Post, "find type was Post"); + equal(id, "1", "find id was 1"); + + return Ember.RSVP.resolve({ id: 1, comments: [ 1, 2 ] }); + }; + + env.store.pushMany('comment', [{ id: 1, body: "First" }, { id: 2, body: "Second" }]); + + env.store.find('post', 1).then(async(function(post) { + var comments = post.get('comments'); + equal(comments.get('isLoaded'), true, "comments are loaded"); + equal(comments.get('length'), 2, "comments have a length of 2"); + + env.adapter.findMany = function(store, type, ids, records) { + return Ember.RSVP.resolve([ + { id: 1, body: "FirstUpdated" }, + { id: 2, body: "Second" } + ]); + }; + + return comments.reload(); + })).then(async(function(newComments){ + // equal(newComments.get('length'), 3, "reloaded comments have a length of 3"); + equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); + })); +}); + test("A hasMany relationship can be reloaded if it was fetched via ids", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - debugger env.adapter.find = function(store, type, id) { equal(type, Post, "find type was Post"); equal(id, "1", "find id was 1"); From d1d347327d12c33301a9368f39bd69a3227d8b87 Mon Sep 17 00:00:00 2001 From: Tom Coquereau Date: Fri, 19 Sep 2014 10:40:19 +0200 Subject: [PATCH 0357/2527] Add a test for calling reload directly on the promiseProxy --- .../relationships/has_many_test.js | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index a72e9a9036f..b0fe01b5516 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -170,8 +170,6 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu comments: DS.hasMany('comment') }); - debugger; - env.adapter.find = function(store, type, id) { equal(type, Post, "find type was Post"); equal(id, "1", "find id was 1"); @@ -195,7 +193,6 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu return comments.reload(); })).then(async(function(newComments){ - // equal(newComments.get('length'), 3, "reloaded comments have a length of 3"); equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); })); }); @@ -238,6 +235,34 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio })); }); +test("A hasMany relationship can be directly reloaded if it was fetched via ids", function() { + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + env.adapter.find = function(store, type, id) { + equal(type, Post, "find type was Post"); + equal(id, "1", "find id was 1"); + + return Ember.RSVP.resolve({ id: 1, comments: [1,2] }); + }; + + env.adapter.findMany = function(store, type, ids, records) { + return Ember.RSVP.resolve([ + { id: 1, body: "FirstUpdated" }, + { id: 2, body: "Second" } + ]); + }; + + env.store.find('post', 1).then(async(function(post) { + return post.get('comments').reload().then(async(function(comments) { + equal(comments.get('isLoaded'), true, "comments are loaded"); + equal(comments.get('length'), 2, "comments have 2 length"); + equal(comments.get('firstObject.body'), "FirstUpdated", "Record body was correctly updated"); + })); + })); +}); + test("An updated `links` value should invalidate a relationship cache", function() { expect(8); Post.reopen({ From 076929154cd3202925ef0e3f8d6a2cd6993e1fe6 Mon Sep 17 00:00:00 2001 From: Tomster Date: Fri, 19 Sep 2014 15:21:36 +0200 Subject: [PATCH 0358/2527] HasMany relationships now reload correctly --- .../ember-data/lib/system/promise_proxies.js | 27 +++++++++++++- .../lib/system/record_arrays/many_array.js | 26 +------------ .../lib/system/relationships/relationship.js | 37 ++++++++++++++----- 3 files changed, 55 insertions(+), 35 deletions(-) diff --git a/packages/ember-data/lib/system/promise_proxies.js b/packages/ember-data/lib/system/promise_proxies.js index 54cb397057a..286882a1fc9 100644 --- a/packages/ember-data/lib/system/promise_proxies.js +++ b/packages/ember-data/lib/system/promise_proxies.js @@ -1,4 +1,5 @@ var Promise = Ember.RSVP.Promise; +var get = Ember.get; /** A `PromiseArray` is an object that acts like both an `Ember.Array` @@ -74,9 +75,33 @@ var promiseArray = function(promise, label) { }); }; +/** + A PromiseManyArray is a PromiseArray that also proxies certain method calls + to the underlying manyArray. + Right now we proxy: + `reload()` +*/ + +var PromiseManyArray = PromiseArray.extend({ + reload: function() { + //I don't think this should ever happen right now, but worth guarding if we refactor the async relationships + Ember.assert('You are trying to reload an async manyArray before it has been created', get(this, 'content')); + return get(this, 'content').reload(); + } +}); + +var promiseManyArray = function(promise, label) { + return PromiseManyArray.create({ + promise: Promise.resolve(promise, label) + }); +}; + + export { PromiseArray, PromiseObject, + PromiseManyArray, promiseArray, - promiseObject + promiseObject, + promiseManyArray }; diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 30ba05cc29b..6374941d088 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -114,31 +114,7 @@ export default RecordArray.extend({ @public */ reload: function() { - //todo guard against reloading while already reloading - //monitor reloading state - //handle failure - var record = get(this, 'owner'); - var data = get(record, 'data'); - var key = get(this, 'name'); - var link = data.links && data.links[key]; - var store = get(this, 'store'); - var promiseLabel = "DS: Async hasMany reloading " + record + " : " + key; - var resolver = Ember.RSVP.defer(promiseLabel); - var promise; - var manyArray = this; - if (link) { - store.findHasMany(record, link, relationshipFromMeta(store, record.constructor.metaForProperty(key)), resolver); - promise = resolver.promise.then(function(){ - return manyArray; - }); - } else { - var records = get(this, 'content'); - promise = Ember.RSVP.all( records.map( function(record) { return record.reload(); }) ).then(function(){ return manyArray;}); - } - - return PromiseArray.create({ - promise: promise - }); + return this.relationship.reload(); }, /** diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index ab3c195b7f9..9066654829e 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -1,5 +1,5 @@ import { - PromiseArray, + PromiseManyArray, PromiseObject } from "ember-data/system/promise_proxies"; @@ -138,6 +138,19 @@ ManyRelationship.prototype.notifyRecordRelationshipRemoved = function(record) { this.record.notifyHasManyRemoved(this.key, record); }; +ManyRelationship.prototype.reload = function() { + var self = this; + if (this.link) { + return this.fetchLink(); + } else { + return this.store.scheduleFetchMany(this.manyArray.toArray()).then(function() { + //Goes away after the manyArray refactor + self.manyArray.set('isLoaded', true); + return self.manyArray; + }); + } +}; + ManyRelationship.prototype.computeChanges = function(records) { var members = this.members; @@ -160,27 +173,33 @@ ManyRelationship.prototype.computeChanges = function(records) { }, this); }; +ManyRelationship.prototype.fetchLink = function() { + var self = this; + return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function(records){ + self.updateRecordsFromAdapter(records); + self.hasFetchedLink = true; + //Goes away after the manyArray refactor + self.manyArray.set('isLoaded', true); + return self.manyArray; + }); +}; ManyRelationship.prototype.getRecords = function() { if (this.isAsync) { var self = this; var promise; if (this.link && !this.hasFetchedLink) { - promise = this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function(records){ - self.updateRecordsFromAdapter(records); - self.hasFetchedLink = true; - //TODO(Igor) try to abstract the isLoaded part - self.manyArray.set('isLoaded', true); - return self.manyArray; - }); + promise = this.fetchLink(); } else { var manyArray = this.manyArray; promise = this.store.findMany(manyArray.toArray()).then(function(){ + //Goes away after the manyArray refactor self.manyArray.set('isLoaded', true); return manyArray; }); } - return PromiseArray.create({ + return PromiseManyArray.create({ + content: this.manyArray, promise: promise }); } else { From 7859acb0816c63e5df9c391e3830f3dfe0ed0161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=8Anio=20Lopes?= Date: Thu, 18 Sep 2014 22:19:29 -0300 Subject: [PATCH 0359/2527] Makes it possible to custom define inverses on only one side This also adds a cache to inverseFor --- .../lib/system/relationships/ext.js | 50 +++++++- .../tests/integration/inverse_test.js | 119 ++++++++++++++++++ 2 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 packages/ember-data/tests/integration/inverse_test.js diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 4ef39889ffc..f084aa26b1d 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -5,6 +5,7 @@ import { import { Model } from "ember-data/system/model"; var get = Ember.get; +var filter = Ember.ArrayPolyfills.filter; /** @module ember-data @@ -79,6 +80,17 @@ Model.reopen({ */ Model.reopenClass({ + + reopen: function(){ + this.inverseMap = Ember.Map.create(); + return this._super.apply(this, arguments); + }, + + extend: function(){ + var newClass = this._super.apply(this, arguments); + newClass.inverseMap = Ember.Map.create(); + return newClass; + }, /** For a given relationship name, returns the model type of the relationship. @@ -102,6 +114,8 @@ Model.reopenClass({ return relationship && relationship.type; }, + inverseMap: null, + /* Find the relationship which is the inverse of the one asked for. @@ -126,6 +140,16 @@ Model.reopenClass({ @return {Object} the inverse relationship, or null */ inverseFor: function(name) { + if (this.inverseMap.has(name)) { + return this.inverseMap.get(name); + } else { + var inverse = this.findInverseFor(name); + this.inverseMap.set(name, inverse); + return inverse; + } + }, + //Calculate the inverse, ignoring the cache + findInverseFor: function(name) { var inverseType = this.typeForRelationship(name); if (!inverseType) { return null; } @@ -151,6 +175,19 @@ Model.reopenClass({ if (possibleRelationships.length === 0) { return null; } + var filteredRelationships = filter.call(possibleRelationships, function(possibleRelationship) { + var optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options; + return name === optionsForRelationship.inverse; + }); + + Ember.assert("You defined the '" + name + "' relationship on " + this + ", but you defined the inverse relationships of type " + + inverseType.toString() + " multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", + filteredRelationships.length < 2); + + if (filteredRelationships.length === 1 ) { + possibleRelationships = filteredRelationships; + } + Ember.assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + this + " were found on " + inverseType + ". Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", possibleRelationships.length === 1); @@ -166,8 +203,19 @@ Model.reopenClass({ if (!relationshipMap) { return; } var relationships = relationshipMap.get(type); + + relationships = filter.call(relationships, function(relationship) { + var optionsForRelationship = inverseType.metaForProperty(relationship.name).options; + + if (!optionsForRelationship.inverse){ + return true; + } + + return name === optionsForRelationship.inverse; + }); + if (relationships) { - possibleRelationships.push.apply(possibleRelationships, relationshipMap.get(type)); + possibleRelationships.push.apply(possibleRelationships, relationships); } //Recurse to support polymorphism diff --git a/packages/ember-data/tests/integration/inverse_test.js b/packages/ember-data/tests/integration/inverse_test.js new file mode 100644 index 00000000000..cfe555576cd --- /dev/null +++ b/packages/ember-data/tests/integration/inverse_test.js @@ -0,0 +1,119 @@ +var env, store, User, Job; + +var attr = DS.attr, belongsTo = DS.belongsTo; + +function stringify(string) { + return function() { return string; }; +} + +module('integration/inverse_test - inverseFor', { + setup: function() { + User = DS.Model.extend({ + name: attr('string'), + bestFriend: belongsTo('user', {async: true}), + job: belongsTo('job') + }); + + User.toString = stringify('user'); + + Job = DS.Model.extend({ + isGood: attr(), + user: belongsTo('user') + }); + + Job.toString = stringify('job'); + + env = setupStore({ + user: User, + job: Job + }); + + store = env.store; + }, + + teardown: function() { + env.container.destroy(); + } +}); + +test("Finds the inverse when there is only one possible available", function () { + //Maybe store is evaluated lazily, so we need this :( + var user = store.push('user', {id:1}); + + deepEqual(Job.inverseFor('user'), { + type: User, + name: 'job', + kind: 'belongsTo' + }, 'Gets correct type, name and kind'); +}); + +test("Finds the inverse when only one side has defined it manually", function () { + Job.reopen({ + owner: belongsTo('user', {inverse: 'previousJob'}) + }) + + User.reopen({ + previousJob: belongsTo('job') + }) + + //Maybe store is evaluated lazily, so we need this :( + var user = store.push('user', {id:1}); + var job = store.push('user', {id:1}); + + deepEqual(Job.inverseFor('owner'), { + type: User, //the model's type + name: 'previousJob', //the models relationship key + kind: 'belongsTo' + }, 'Gets correct type, name and kind'); + + deepEqual(User.inverseFor('previousJob'), { + type: Job, //the model's type + name: 'owner', //the models relationship key + kind: 'belongsTo' + }, 'Gets correct type, name and kind'); +}); + +test("Returns null if inverse relationship it is manually set with a different relationship key", function () { + Job.reopen({ + user: belongsTo('user', {inverse: 'previousJob'}) + }); + + User.reopen({ + job: belongsTo('job') + }); + //Maybe store is evaluated lazily, so we need this :( + var user = store.push('user', {id:1}); + + equal(User.inverseFor('job'), null, 'There is no inverse'); +}); + +test("Errors out if you define 2 inverses to the same model", function () { + Job.reopen({ + user: belongsTo('user', {inverse: 'job'}), + owner: belongsTo('user', {inverse: 'job'}) + }); + + User.reopen({ + job: belongsTo('job') + }); + + //Maybe store is evaluated lazily, so we need this :( + expectAssertion(function() { + var user = store.push('user', {id:1}); + User.inverseFor('job'); + }, "You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses"); +}); + + +test("Caches findInverseFor return value", function () { + expect(1); + //Maybe store is evaluated lazily, so we need this :( + var user = store.push('user', {id:1}); + var inverseForUser = Job.inverseFor('user'); + + Job.findInverseFor = function(){ + ok(false, 'Find is not called anymore'); + }; + + equal(inverseForUser, Job.inverseFor('user'), 'Inverse cached succesfully'); +}); From fa107679240481aba0cd3c5ac1e8cf514a075571 Mon Sep 17 00:00:00 2001 From: Tomster Date: Sun, 21 Sep 2014 15:50:30 +0200 Subject: [PATCH 0360/2527] Do not reuse argument values when calculating inverses --- packages/ember-data/lib/system/relationships/ext.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 493c1d1482d..6daa8d36876 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -159,8 +159,8 @@ Model.reopenClass({ inverseKind = possibleRelationships[0].kind; } - function findPossibleInverses(type, inverseType, possibleRelationships) { - possibleRelationships = possibleRelationships || []; + function findPossibleInverses(type, inverseType, relationshipsSoFar) { + var possibleRelationships = relationshipsSoFar || []; var relationshipMap = get(inverseType, 'relationships'); if (!relationshipMap) { return; } From 21339947c16f590886fad7d3821d5fcb0eefacae Mon Sep 17 00:00:00 2001 From: IgorT Date: Fri, 19 Sep 2014 04:36:30 +0200 Subject: [PATCH 0361/2527] Refactor inverseFor cache --- .../lib/system/relationships/ext.js | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index f084aa26b1d..ae82aa71ed0 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -81,16 +81,6 @@ Model.reopen({ Model.reopenClass({ - reopen: function(){ - this.inverseMap = Ember.Map.create(); - return this._super.apply(this, arguments); - }, - - extend: function(){ - var newClass = this._super.apply(this, arguments); - newClass.inverseMap = Ember.Map.create(); - return newClass; - }, /** For a given relationship name, returns the model type of the relationship. @@ -114,7 +104,9 @@ Model.reopenClass({ return relationship && relationship.type; }, - inverseMap: null, + inverseMap: Ember.computed(function() { + return Object.create(null); + }), /* Find the relationship which is the inverse of the one asked for. @@ -140,19 +132,23 @@ Model.reopenClass({ @return {Object} the inverse relationship, or null */ inverseFor: function(name) { - if (this.inverseMap.has(name)) { - return this.inverseMap.get(name); + var inverseMap = get(this, 'inverseMap'); + if (inverseMap[name]) { + return inverseMap[name]; } else { - var inverse = this.findInverseFor(name); - this.inverseMap.set(name, inverse); + var inverse = this._findInverseFor(name); + inverseMap[name] = inverse; return inverse; } }, + //Calculate the inverse, ignoring the cache - findInverseFor: function(name) { + _findInverseFor: function(name) { var inverseType = this.typeForRelationship(name); - if (!inverseType) { return null; } + if (!inverseType) { + return null; + } //If inverse is manually specified to be null, like `comments: DS.hasMany('message', {inverse: null})` var options = this.metaForProperty(name).options; From 6706a3f181f8e2ad1334f42fb69cfb17ffc60b34 Mon Sep 17 00:00:00 2001 From: Tom Coquereau Date: Mon, 22 Sep 2014 19:27:03 +0200 Subject: [PATCH 0362/2527] Update recordArrays when record has reloaded --- packages/ember-data/lib/system/model/model.js | 1 + .../tests/integration/filter_test.js | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 5056dc4a687..6959cc1a148 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -970,6 +970,7 @@ var Model = Ember.Object.extend(Ember.Evented, { var promise = new Promise(function(resolve){ record.send('reloadRecord', resolve); }, promiseLabel).then(function() { + record.updateRecordArrays(); record.set('isReloading', false); record.set('isError', false); return record; diff --git a/packages/ember-data/tests/integration/filter_test.js b/packages/ember-data/tests/integration/filter_test.js index fa5c518a12d..5483e2496cc 100644 --- a/packages/ember-data/tests/integration/filter_test.js +++ b/packages/ember-data/tests/integration/filter_test.js @@ -379,6 +379,32 @@ test("it is possible to filter created records by dirtiness", function() { })); }); +test("it is possible to filter created records by isReloading", function() { + set(store, 'adapter', DS.Adapter.extend({ + find: function() { + return Ember.RSVP.resolve({ + id: 1, + name: "Tom Dalle" + }); + } + })); + + var filter = store.filter('person', function(person) { + return !person.get('isReloading'); + }); + + var person = store.createRecord('person', { + id: 1, + name: "Tom Dale" + }); + + debugger; + + person.reload().then(async(function(person) { + equal(filter.get('length'), 1, "isReloading is set to false on the reloaded object"); + })); +}); + // SERVER SIDE TESTS var edited; From e2868f24c9bffb75e26f830542e5f2bfd827b7ad Mon Sep 17 00:00:00 2001 From: Tom Coquereau Date: Mon, 22 Sep 2014 19:35:07 +0200 Subject: [PATCH 0363/2527] Fix jshint --- packages/ember-data/tests/integration/filter_test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/ember-data/tests/integration/filter_test.js b/packages/ember-data/tests/integration/filter_test.js index 5483e2496cc..2a2811a162b 100644 --- a/packages/ember-data/tests/integration/filter_test.js +++ b/packages/ember-data/tests/integration/filter_test.js @@ -398,8 +398,6 @@ test("it is possible to filter created records by isReloading", function() { name: "Tom Dale" }); - debugger; - person.reload().then(async(function(person) { equal(filter.get('length'), 1, "isReloading is set to false on the reloaded object"); })); From 4061e8639d814a6d0dc176462e448a0913c531c3 Mon Sep 17 00:00:00 2001 From: Tom Coquereau Date: Mon, 22 Sep 2014 19:52:09 +0200 Subject: [PATCH 0364/2527] Update tests on filters returning reloaded objects --- packages/ember-data/lib/system/model/model.js | 5 +++-- packages/ember-data/tests/integration/filter_test.js | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 6959cc1a148..f19c12aea5d 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -970,14 +970,15 @@ var Model = Ember.Object.extend(Ember.Evented, { var promise = new Promise(function(resolve){ record.send('reloadRecord', resolve); }, promiseLabel).then(function() { - record.updateRecordArrays(); record.set('isReloading', false); record.set('isError', false); return record; }, function(reason) { record.set('isError', true); throw reason; - }, "DS: Model#reload complete, update flags"); + }, "DS: Model#reload complete, update flags").finally(function () { + record.updateRecordArrays(); + }); return PromiseObject.create({ promise: promise diff --git a/packages/ember-data/tests/integration/filter_test.js b/packages/ember-data/tests/integration/filter_test.js index 2a2811a162b..3a36f259456 100644 --- a/packages/ember-data/tests/integration/filter_test.js +++ b/packages/ember-data/tests/integration/filter_test.js @@ -399,7 +399,7 @@ test("it is possible to filter created records by isReloading", function() { }); person.reload().then(async(function(person) { - equal(filter.get('length'), 1, "isReloading is set to false on the reloaded object"); + equal(filter.get('length'), 1, "the filter correctly returned a reloaded object"); })); }); From 27d1b3b4a35d52380cb5aeb709797b249c239fdc Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Mon, 22 Sep 2014 17:41:23 +0200 Subject: [PATCH 0365/2527] Fix typo (was silent in simple case) --- .../lib/system/relationships/relationship.js | 2 +- .../tests/unit/record_array_test.js | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index 9066654829e..137d6808416 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -14,7 +14,7 @@ var Relationship = function(store, record, inverseKey, relationshipMeta) { this.relationshipMeta = relationshipMeta; //This probably breaks for polymorphic relationship in complex scenarios, due to //multiple possible typeKeys - this.inversKeyForimplicit = this.typeKey + this.key; + this.inverseKeyForimplicit = this.store.modelFor(this.record.constructor).typeKey + this.key; }; Relationship.prototype = { diff --git a/packages/ember-data/tests/unit/record_array_test.js b/packages/ember-data/tests/unit/record_array_test.js index 2bc41ae323a..091abb19c9b 100644 --- a/packages/ember-data/tests/unit/record_array_test.js +++ b/packages/ember-data/tests/unit/record_array_test.js @@ -88,6 +88,31 @@ test("a loaded record is removed from a record array when it is deleted even if equal(tag.get('people.length'), 0, "record is removed from the record array"); }); +test("a loaded record is removed both from the record array and from the belongs to, even if the belongsTo side isn't defined", function() { + var Tag = DS.Model.extend({ + people: DS.hasMany('person') + }); + + var Tool = DS.Model.extend({ + person: DS.belongsTo('person') + }); + + var env = setupStore({ tag: Tag, person: Person, tool: Tool }), + store = env.store; + + var scumbag = store.push('person', {id:1, name: 'Scumbag Tom'}); + var tag = store.push('tag', { id: 1, people:[1] }); + var tool = store.push('tool', {id: 1, person:1}); + + equal(tag.get('people.length'), 1, "record is in the record array"); + equal(tool.get('person'), scumbag, "the tool belongs to the record"); + + scumbag.deleteRecord(); + + equal(tag.get('people.length'), 0, "record is removed from the record array"); + equal(tool.get('person'), null, "the tool is now orphan"); +}); + // GitHub Issue #168 test("a newly created record is removed from a record array when it is deleted", function() { var store = createStore(), From 5ad77847bd1c99bf3b1baf17667ab3b3c79c805a Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 17 Sep 2014 20:20:48 +0200 Subject: [PATCH 0366/2527] Unwrap promises when setting a belongsTo --- .../lib/system/relationships/belongs_to.js | 6 +- .../lib/system/relationships/relationship.js | 6 ++ .../relationships/one_to_one_test.js | 57 +++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index fe488cc857f..3ea24a28c2b 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -71,7 +71,11 @@ function belongsTo(type, options) { if ( value === undefined ) { value = null; } - this._relationships[key].setRecord(value); + if (value && value.then) { + this._relationships[key].setRecordPromise(value); + } else { + this._relationships[key].setRecord(value); + } } return this._relationships[key].getRecord(); diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index 137d6808416..53a393a6ab2 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -243,6 +243,12 @@ BelongsToRelationship.prototype.addRecord = function(newRecord) { this._super$addRecord(newRecord); }; +BelongsToRelationship.prototype.setRecordPromise = function(newPromise) { + var content = newPromise.get && newPromise.get('content'); + Ember.assert("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); + this.setRecord(content); +}; + BelongsToRelationship.prototype.notifyRecordRelationshipAdded = function(newRecord) { this.record.notifyBelongsToAdded(this.key, this); }; diff --git a/packages/ember-data/tests/integration/relationships/one_to_one_test.js b/packages/ember-data/tests/integration/relationships/one_to_one_test.js index 4dabff8985c..656ac116efa 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_one_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_one_test.js @@ -119,6 +119,63 @@ test("Setting a OneToOne relationship reflects correctly on the other side- sync equal(job.get('user'), user, 'User relationship was set up correctly'); }); +test("Setting a BelongsTo to a promise unwraps the promise before setting- async", function () { + var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); + var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + var newFriend = store.push('user', {id:3, name: "New friend"}); + newFriend.set('bestFriend', stanleysFriend.get('bestFriend')); + stanley.get('bestFriend').then(async(function(fetchedUser) { + equal(fetchedUser, newFriend, 'User relationship was updated correctly'); + })); + newFriend.get('bestFriend').then(async(function(fetchedUser) { + equal(fetchedUser, stanley, 'User relationship was updated correctly'); + })); +}); + +test("Setting a BelongsTo to a promise works when the promise returns null- async", function () { + store.push('user', {id:1, name: 'Stanley'}); + var igor = store.push('user', {id:2, name: "Igor"}); + var newFriend = store.push('user', {id:3, name: "New friend", bestFriend:1}); + newFriend.set('bestFriend', igor.get('bestFriend')); + newFriend.get('bestFriend').then(async(function(fetchedUser) { + equal(fetchedUser, null, 'User relationship was updated correctly'); + })); +}); + +test("Setting a BelongsTo to a promise that didn't come from a relationship errors out", function () { + var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); + var igor = store.push('user', {id:3, name: 'Igor'}); + expectAssertion(function() { + stanley.set('bestFriend', Ember.RSVP.resolve(igor)); + }, /You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call./); +}); + +test("Setting a BelongsTo to a promise multiple times is resistant to race conditions- async", function () { + expect(1); + var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); + var igor = store.push('user', {id:3, name: "Igor", bestFriend:5}); + var newFriend = store.push('user', {id:7, name: "New friend"}); + env.adapter.find = function(store, type, id) { + if (id === '5') { + return Ember.RSVP.resolve({id:5, name: "Igor's friend"}); + } else if (id === '2') { + stop(); + return new Ember.RSVP.Promise(function(resolve, reject) { + setTimeout(function(){ + start(); + resolve({id:2, name:"Stanley's friend"}); + }, 1); + }); + } + }; + + newFriend.set('bestFriend', stanley.get('bestFriend')); + newFriend.set('bestFriend', igor.get('bestFriend')); + newFriend.get('bestFriend').then(async(function(fetchedUser) { + equal(fetchedUser.get('name'), "Igor's friend", 'User relationship was updated correctly'); + })); +}); + test("Setting a OneToOne relationship to null reflects correctly on the other side - async", function () { var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend:1}); From e2b96fcf33d8a0bfff6fbc968b3f3f0326f410e2 Mon Sep 17 00:00:00 2001 From: IgorT Date: Tue, 9 Sep 2014 06:45:33 +0200 Subject: [PATCH 0367/2527] Add support for rollback of relationships from deleted state Building upon #2208 and #2260 this commit enables reconnecting relationships so we can rollback the relationship state from a deleted record fixes #2036 fixes #1824 fixes #2010 fixes #1922 --- packages/ember-data/lib/system/model/model.js | 14 ++++++ .../lib/system/relationships/relationship.js | 12 +++++ .../relationships/many_to_many_test.js | 26 ++++++++++ .../relationships/one_to_many_test.js | 47 +++++++++++++++++++ .../relationships/one_to_one_test.js | 25 ++++++++++ tests/ember_configuration.js | 3 ++ 6 files changed, 127 insertions(+) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 5056dc4a687..38677f43c24 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -673,6 +673,13 @@ var Model = Ember.Object.extend(Ember.Evented, { }); }, + reconnectRelationships: function() { + this.eachRelationship(function(name, relationship) { + this._relationships[name].reconnect(); + }, this); + }, + + /** @method updateRecordArrays @private @@ -894,6 +901,13 @@ var Model = Ember.Object.extend(Ember.Evented, { set(this, 'isError', false); } + //Eventually rollback will always work for relationships + //For now we support it only out of deleted state, because we + //have an explicit way of knowing when the server acked the relationship change + if (get(this, 'isDeleted')) { + this.reconnectRelationships(); + } + if (!get(this, 'isValid')) { this._inFlightAttributes = {}; } diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index 53a393a6ab2..5fa411bd5a3 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -35,6 +35,12 @@ Relationship.prototype = { }, this); }, + reconnect: function(){ + this.members.forEach(function(member) { + this.addRecordToInverse(member); + }, this); + }, + removeRecords: function(records){ var that = this; records.forEach(function(record){ @@ -81,6 +87,12 @@ Relationship.prototype = { } }, + addRecordToInverse: function(record) { + if (this.inverseKey) { + record._relationships[this.inverseKey].addRecord(this.record); + } + }, + removeRecordFromInverse: function(record) { var inverseRelationship = record._relationships[this.inverseKey]; //Need to check for existence, as the record might unloading at the moment diff --git a/packages/ember-data/tests/integration/relationships/many_to_many_test.js b/packages/ember-data/tests/integration/relationships/many_to_many_test.js index 9752c83309c..430f92d8d2b 100644 --- a/packages/ember-data/tests/integration/relationships/many_to_many_test.js +++ b/packages/ember-data/tests/integration/relationships/many_to_many_test.js @@ -150,3 +150,29 @@ test("Deleting a record that has a hasMany relationship removes it from the othe equal(account.get('users.length'), 1, 'Users are still there'); equal(user.get('accounts.length'), 0, 'Acocount got removed from the user'); }); + +/* + Rollback tests +*/ + +test("Rollbacking a deleted record that has a ManyToMany relationship works correctly - async", function () { + var user = store.push('user', {id:1, name: 'Stanley', topics: [2]}); + var topic = store.push('topic', {id: 2, title: 'EmberFest was great'}); + topic.deleteRecord(); + topic.rollback(); + topic.get('users').then(async(function(fetchedUsers) { + equal(fetchedUsers.get('length'), 1, 'Users are still there'); + })); + user.get('topics').then(async(function(fetchedTopics) { + equal(fetchedTopics.get('length'), 1, 'Topic got rollbacked into the user'); + })); +}); + +test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function () { + var account = store.push('account', {id:2 , state: 'lonely'}); + var user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + account.deleteRecord(); + account.rollback(); + equal(account.get('users.length'), 1, 'Users are still there'); + equal(user.get('accounts.length'), 1, 'Account got rolledback correctly into the user'); +}); diff --git a/packages/ember-data/tests/integration/relationships/one_to_many_test.js b/packages/ember-data/tests/integration/relationships/one_to_many_test.js index b3f1ec09097..81e65480e78 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_many_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_many_test.js @@ -340,3 +340,50 @@ test("When deleting a record that has a hasMany it is removed from the belongsTo equal(account.get('user'), null, 'Account no longer has the user'); }); +/* +Rollback from deleted state +*/ + +test("Rollbacking a deleted record works correctly when the hasMany side has been deleted - async", function () { + var user = store.push('user', {id:1, name: 'Stanley', messages: [2]}); + var message = store.push('message', {id: 2, title: 'EmberFest was great'}); + message.deleteRecord(); + message.rollback(); + message.get('user').then(async(function(fetchedUser) { + equal(fetchedUser, user, 'Message still has the user'); + })); + user.get('messages').then(async(function(fetchedMessages) { + equal(fetchedMessages.objectAt(0), message, 'User has the message'); + })); +}); + +test("Rollbacking a deleted record works correctly when the hasMany side has been deleted - sync", function () { + var account = store.push('account', {id:2 , state: 'lonely'}); + var user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + account.deleteRecord(); + account.rollback(); + equal(user.get('accounts.length'), 1, "Accounts are rolled back"); + equal(account.get('user'), user, 'Account still has the user'); +}); + +test("Rollbacking a deleted record works correctly when the belongsTo side has been deleted - async", function () { + var user = store.push('user', {id:1, name: 'Stanley', messages: [2]}); + var message = store.push('message', {id: 2, title: 'EmberFest was great'}); + user.deleteRecord(); + user.rollback(); + message.get('user').then(async(function(fetchedUser) { + equal(fetchedUser, user, 'Message has the user again'); + })); + user.get('messages').then(async(function(fetchedMessages) { + equal(fetchedMessages.get('length'), 1, 'User still has the messages'); + })); +}); + +test("Rollbacking a deleted record works correctly when the belongsTo side has been deleted - sync", function () { + var account = store.push('account', {id:2 , state: 'lonely'}); + var user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + user.deleteRecord(); + user.rollback(); + equal(user.get('accounts.length'), 1, "User still has the accounts"); + equal(account.get('user'), user, 'Account has the user again'); +}); diff --git a/packages/ember-data/tests/integration/relationships/one_to_one_test.js b/packages/ember-data/tests/integration/relationships/one_to_one_test.js index 656ac116efa..92779ab62b8 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_one_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_one_test.js @@ -248,3 +248,28 @@ test("When deleting a record that has a belongsTo relationship, the record is re equal(job.get('user'), user, 'Job still has the user'); }); +/* +Rollback tests +*/ + +test("Rollbacking a deleted record restores the relationship on both sides - async", function () { + var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); + var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + stanley.deleteRecord(); + stanley.rollback(); + stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { + equal(fetchedUser, stanley, 'Stanley got rollbacked correctly'); + })); + stanley.get('bestFriend').then(async(function(fetchedUser) { + equal(fetchedUser, stanleysFriend, 'Stanleys friend did not get removed'); + })); +}); + +test("Rollbacking a deleted record restores the relationship on both sides - async", function () { + var job = store.push('job', {id:2 , isGood: true}); + var user = store.push('user', {id:1, name: 'Stanley', job:2 }); + job.deleteRecord(); + job.rollback(); + equal(user.get('job'), job, 'Job got rollbacked correctly'); + equal(job.get('user'), user, 'Job still has the user'); +}); diff --git a/tests/ember_configuration.js b/tests/ember_configuration.js index c1da5c46ed1..bdfdad15bee 100644 --- a/tests/ember_configuration.js +++ b/tests/ember_configuration.js @@ -185,9 +185,12 @@ DS.Relationship.prototype.addRecord = syncForTest(DS.Relationship.prototype.addRecord); DS.Relationship.prototype.removeRecord = syncForTest(DS.Relationship.prototype.removeRecord); + DS.Relationship.prototype.removeRecordFromInverse = syncForTest(DS.Relationship.prototype.removeRecordFromInverse); DS.Relationship.prototype.removeRecordFromOwn = syncForTest(DS.Relationship.prototype.removeRecordFromOwn); + DS.Relationship.prototype.addRecordToInverse = syncForTest(DS.Relationship.prototype.addRecordToInverse); + var transforms = { 'boolean': DS.BooleanTransform.create(), 'date': DS.DateTransform.create(), From 77e12d95e509873a2471e94569d12e5a4b37df90 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Mon, 22 Sep 2014 21:16:24 +0200 Subject: [PATCH 0368/2527] Implemented rollbacking of implicit relationships --- packages/ember-data/lib/system/model/model.js | 4 ++ .../lib/system/relationships/relationship.js | 12 ++-- .../relationships/belongs_to_test.js | 39 ++++++++++-- .../relationships/has_many_test.js | 60 ++++++++++++++++++- .../relationships/one_to_many_test.js | 5 +- .../relationships/one_to_one_test.js | 8 +-- 6 files changed, 107 insertions(+), 21 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 38677f43c24..a5747e92758 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -677,6 +677,10 @@ var Model = Ember.Object.extend(Ember.Evented, { this.eachRelationship(function(name, relationship) { this._relationships[name].reconnect(); }, this); + var model = this; + forEach.call(Ember.keys(this._implicitRelationships), function(key) { + model._implicitRelationships[key].reconnect(); + }); }, diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index 5fa411bd5a3..50e3aa4a1bb 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -14,7 +14,7 @@ var Relationship = function(store, record, inverseKey, relationshipMeta) { this.relationshipMeta = relationshipMeta; //This probably breaks for polymorphic relationship in complex scenarios, due to //multiple possible typeKeys - this.inverseKeyForimplicit = this.store.modelFor(this.record.constructor).typeKey + this.key; + this.inverseKeyForImplicit = this.store.modelFor(this.record.constructor).typeKey + this.key; }; Relationship.prototype = { @@ -65,10 +65,10 @@ Relationship.prototype = { if (this.inverseKey) { record._relationships[this.inverseKey].addRecord(this.record); } else { - if (!record._implicitRelationships[this.inverseKeyForimplicit]) { - record._implicitRelationships[this.inverseKeyForimplicit] = new Relationship(this.store, record, this.key, {options:{}}); + if (!record._implicitRelationships[this.inverseKeyForImplicit]) { + record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, {options:{}}); } - record._implicitRelationships[this.inverseKeyForimplicit].addRecord(this.record); + record._implicitRelationships[this.inverseKeyForImplicit].addRecord(this.record); } this.record.updateRecordArrays(); } @@ -80,8 +80,8 @@ Relationship.prototype = { if (this.inverseKey) { this.removeRecordFromInverse(record); } else { - if (record._implicitRelationships[this.inverseKeyForimplicit]) { - record._implicitRelationships[this.inverseKeyForimplicit].removeRecord(this.record); + if (record._implicitRelationships[this.inverseKeyForImplicit]) { + record._implicitRelationships[this.inverseKeyForImplicit].removeRecord(this.record); } } } diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index 557a629bb6d..70cd2c8a9d0 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -15,35 +15,44 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { messages: hasMany('message', {polymorphic: true}) //favouriteMessage: belongsTo('message', {polymorphic: true}) }); - User.toString = stringify('User'); Message = DS.Model.extend({ user: belongsTo('user'), created_at: attr('date') }); - Message.toString = stringify('Message'); Post = Message.extend({ title: attr('string'), comments: hasMany('comment') }); - Post.toString = stringify('Post'); Comment = Message.extend({ body: DS.attr('string'), message: DS.belongsTo('message', { polymorphic: true }) }); - Comment.toString = stringify('Comment'); + Book = DS.Model.extend({ + name: attr('string'), + author: belongsTo('author') + }); + Book.toString = stringify('Book'); + + Author = DS.Model.extend({ + name: attr('string') + }); + Author.toString = stringify('Author'); + env = setupStore({ user: User, post: Post, comment: Comment, - message: Message + message: Message, + book: Book, + author: Author }); env.container.register('serializer:user', DS.JSONSerializer.extend({ @@ -382,3 +391,23 @@ test("A sync belongsTo errors out if the record is unlaoded", function() { }, /You looked up the 'user' relationship on a 'message' with id 1 but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async \(`DS.belongsTo\({ async: true }\)`\)/); }); +test("Rollbacking a deleted record restores implicit relationship - async", function () { + Book.reopen({ + author: DS.belongsTo('author', { async: true }) + }); + var book = env.store.push('book', { id: 1, name: "Stanley's Amazing Adventures", author: 2 }); + var author = env.store.push('author', { id: 2, name: 'Stanley' }); + author.deleteRecord(); + author.rollback(); + book.get('author').then(async(function(fetchedAuthor) { + equal(fetchedAuthor, author, 'Book has an author after rollback'); + })); +}); + +test("Rollbacking a deleted record restores implicit relationship - sync", function () { + var book = env.store.push('book', { id: 1, name: "Stanley's Amazing Adventures", author: 2 }); + var author = env.store.push('author', { id: 2, name: 'Stanley' }); + author.deleteRecord(); + author.rollback(); + equal(book.get('author'), author, 'Book has an author after rollback'); +}); \ No newline at end of file diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index b0fe01b5516..b489a2ee609 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -46,6 +46,23 @@ module("integration/relationships/has_many - Has-Many Relationships", { }); Comment.toString = stringify('Comment'); + Book = DS.Model.extend({ + title: attr(), + chapters: hasMany('chapter', { async: true }) + }); + Book.toString = stringify('Book'); + + Chapter = DS.Model.extend({ + title: attr() + }); + Chapter.toString = stringify('Chapter'); + + Page = DS.Model.extend({ + number: attr('number'), + chapter: belongsTo('chapter') + }); + Page.toString = stringify('Page'); + env = setupStore({ user: User, contact: Contact, @@ -53,7 +70,10 @@ module("integration/relationships/has_many - Has-Many Relationships", { phone: Phone, post: Post, comment: Comment, - message: Message + message: Message, + book: Book, + chapter: Chapter, + page: Page }); }, @@ -604,3 +624,41 @@ test("If reordered hasMany data has been pushed to the store, the many array ref deepEqual(post.get('comments').toArray(), [comment4, comment2, comment3, comment1], 'Updated ordering is correct'); }); +test("Rollbacking a deleted record restores implicit relationship correctly when the hasMany side has been deleted - async", function () { + var book = env.store.push('book', { id: 1, title: "Stanley's Amazing Adventures", chapters: [2] }); + var chapter = env.store.push('chapter', { id: 2, title: 'Sailing the Seven Seas' }); + chapter.deleteRecord(); + chapter.rollback(); + book.get('chapters').then(async(function(fetchedChapters) { + equal(fetchedChapters.objectAt(0), chapter, 'Book has a chapter after rollback'); + })); +}); + +test("Rollbacking a deleted record restores implicit relationship correctly when the hasMany side has been deleted - sync", function () { + var book = env.store.push('book', { id: 1, title: "Stanley's Amazing Adventures", chapters: [2] }); + var chapter = env.store.push('chapter', { id: 2, title: 'Sailing the Seven Seas' }); + chapter.deleteRecord(); + chapter.rollback(); + equal(book.get('chapters.firstObject'), chapter, "Book has a chapter after rollback"); +}); + +test("Rollbacking a deleted record restores implicit relationship correctly when the belongsTo side has been deleted - async", function () { + Page.reopen({ + chapter: DS.belongsTo('chapter', { async: true }) + }); + var chapter = env.store.push('chapter', { id: 2, title: 'Sailing the Seven Seas' }); + var page = env.store.push('page', { id: 3, number: 1, chapter: 2 }); + chapter.deleteRecord(); + chapter.rollback(); + page.get('chapter').then(async(function(fetchedChapter) { + equal(fetchedChapter, chapter, 'Page has a chapter after rollback'); + })); +}); + +test("Rollbacking a deleted record restores implicit relationship correctly when the belongsTo side has been deleted - sync", function () { + var chapter = env.store.push('chapter', { id: 2, title: 'Sailing the Seven Seas' }); + var page = env.store.push('page', { id: 3, number: 1, chapter: 2 }); + chapter.deleteRecord(); + chapter.rollback(); + equal(page.get('chapter'), chapter, "Page has a chapter after rollback"); +}); \ No newline at end of file diff --git a/packages/ember-data/tests/integration/relationships/one_to_many_test.js b/packages/ember-data/tests/integration/relationships/one_to_many_test.js index 81e65480e78..bfcb398cfd0 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_many_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_many_test.js @@ -16,21 +16,18 @@ module('integration/relationships/one_to_many_test - OneToMany relationships', { messages: hasMany('message', {async: true}), accounts: hasMany('account') }); - User.toString = stringify('User'); Account = DS.Model.extend({ state: attr(), user: belongsTo('user') }); - Account.toString = stringify('Account'); Message = DS.Model.extend({ title: attr('string'), user: belongsTo('user', {async: true}) }); - Message.toString = stringify('Message'); env = setupStore({ @@ -386,4 +383,4 @@ test("Rollbacking a deleted record works correctly when the belongsTo side has b user.rollback(); equal(user.get('accounts.length'), 1, "User still has the accounts"); equal(account.get('user'), user, 'Account has the user again'); -}); +}); \ No newline at end of file diff --git a/packages/ember-data/tests/integration/relationships/one_to_one_test.js b/packages/ember-data/tests/integration/relationships/one_to_one_test.js index 92779ab62b8..d2e27a5f3ad 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_one_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_one_test.js @@ -13,15 +13,13 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', { bestFriend: belongsTo('user', {async: true}), job: belongsTo('job') }); - User.toString = stringify('User'); Job = DS.Model.extend({ isGood: attr(), user: belongsTo('user') }); - - Job.toString = stringify('Account'); + Job.toString = stringify('Job'); env = setupStore({ user: User, @@ -265,11 +263,11 @@ test("Rollbacking a deleted record restores the relationship on both sides - asy })); }); -test("Rollbacking a deleted record restores the relationship on both sides - async", function () { +test("Rollbacking a deleted record restores the relationship on both sides - sync", function () { var job = store.push('job', {id:2 , isGood: true}); var user = store.push('user', {id:1, name: 'Stanley', job:2 }); job.deleteRecord(); job.rollback(); equal(user.get('job'), job, 'Job got rollbacked correctly'); equal(job.get('user'), user, 'Job still has the user'); -}); +}); \ No newline at end of file From 8a6119d71987d0ab807813d66e8d27fb8ea34a01 Mon Sep 17 00:00:00 2001 From: Miguel Camba Date: Fri, 26 Sep 2014 14:56:53 +0100 Subject: [PATCH 0369/2527] Remove es3 rule in .jshintrc --- .jshintrc | 1 - 1 file changed, 1 deletion(-) diff --git a/.jshintrc b/.jshintrc index 0f501422da4..98e577bb2c0 100644 --- a/.jshintrc +++ b/.jshintrc @@ -38,7 +38,6 @@ "node" : false, "browser" : true, - "es3": true, "boss" : true, "curly": false, "debug": false, From deb493e1ab94594226caa872242b648091ac06dd Mon Sep 17 00:00:00 2001 From: IgorT Date: Fri, 26 Sep 2014 16:22:47 +0200 Subject: [PATCH 0370/2527] Make JSLint happy --- packages/ember-data/lib/system/model/model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 5241eb22a94..bf75c02250b 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -994,7 +994,7 @@ var Model = Ember.Object.extend(Ember.Evented, { }, function(reason) { record.set('isError', true); throw reason; - }, "DS: Model#reload complete, update flags").finally(function () { + }, "DS: Model#reload complete, update flags")['finally'](function () { record.updateRecordArrays(); }); From 623b53a570b7179e522affc93c4c9098b5d3bd44 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 29 Sep 2014 11:49:18 -0500 Subject: [PATCH 0371/2527] temporarily disable beta and canary --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2f127a5a49c..b5bd5564d71 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,9 +8,9 @@ install: - "npm run-script dist" script: - npm run-script testem-local - - npm run-script testem-beta - npm run-script testem-stable - - npm run-script testem-canary + # - npm run-script testem-beta + # - npm run-script testem-canary after_success: - npm run-script publish-build - "./bin/bower-ember-data-build" From 60b688c3c44ed41afbded20bde8152f76e942753 Mon Sep 17 00:00:00 2001 From: IgorT Date: Tue, 23 Sep 2014 23:24:42 +0200 Subject: [PATCH 0372/2527] Refactor relationships with links --- .../lib/system/relationships/relationship.js | 71 +++++++++++++------ .../relationships/has_many_test.js | 68 +++++++++++++++++- 2 files changed, 116 insertions(+), 23 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index 50e3aa4a1bb..36c041b7b7f 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -15,11 +15,12 @@ var Relationship = function(store, record, inverseKey, relationshipMeta) { //This probably breaks for polymorphic relationship in complex scenarios, due to //multiple possible typeKeys this.inverseKeyForImplicit = this.store.modelFor(this.record.constructor).typeKey + this.key; + //Cached promise when fetching the relationship from a link + this.linkPromise = null; }; Relationship.prototype = { constructor: Relationship, - hasFetchedLink: false, destroy: Ember.K, @@ -110,11 +111,23 @@ Relationship.prototype = { updateLink: function(link) { if (link !== this.link) { this.link = link; - this.hasFetchedLink = false; + this.linkPromise = null; this.record.notifyPropertyChange(this.key); } }, + findLink: function() { + if (this.linkPromise) { + return this.linkPromise; + } else { + var promise = this.fetchLink(); + this.linkPromise = promise; + return promise.then(function(result) { + return result; + }); + } + }, + updateRecordsFromAdapter: function(records) { //TODO Once we have adapter support, we need to handle updated and canonical changes this.computeChanges(records); @@ -189,26 +202,29 @@ ManyRelationship.prototype.fetchLink = function() { var self = this; return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function(records){ self.updateRecordsFromAdapter(records); - self.hasFetchedLink = true; - //Goes away after the manyArray refactor - self.manyArray.set('isLoaded', true); return self.manyArray; }); }; +ManyRelationship.prototype.findRecords = function() { + var manyArray = this.manyArray; + return this.store.findMany(manyArray.toArray()).then(function(){ + //Goes away after the manyArray refactor + manyArray.set('isLoaded', true); + return manyArray; + }); +}; + ManyRelationship.prototype.getRecords = function() { if (this.isAsync) { var self = this; var promise; - if (this.link && !this.hasFetchedLink) { - promise = this.fetchLink(); - } else { - var manyArray = this.manyArray; - promise = this.store.findMany(manyArray.toArray()).then(function(){ - //Goes away after the manyArray refactor - self.manyArray.set('isLoaded', true); - return manyArray; + if (this.link) { + promise = this.findLink().then(function() { + return self.findRecords(); }); + } else { + promise = this.findRecords(); } return PromiseManyArray.create({ content: this.manyArray, @@ -276,21 +292,32 @@ BelongsToRelationship.prototype.removeRecordFromOwn = function(record) { this.inverseRecord = null; }; +BelongsToRelationship.prototype.findRecord = function() { + if (this.inverseRecord) { + return this.store._findByRecord(this.inverseRecord); + } else { + return Ember.RSVP.Promise.resolve(null); + } +}; + +BelongsToRelationship.prototype.fetchLink = function() { + var self = this; + return this.store.findBelongsTo(this.record, this.link, this.relationshipMeta).then(function(record){ + self.addRecord(record); + return record; + }); +}; + BelongsToRelationship.prototype.getRecord = function() { if (this.isAsync) { var promise; - - if (this.link && !this.hasFetchedLink){ + if (this.link){ var self = this; - promise = this.store.findBelongsTo(this.record, this.link, this.relationshipMeta).then(function(record){ - self.addRecord(record); - self.hasFetchedLink = true; - return record; + promise = this.findLink().then(function() { + return self.findRecord(); }); - } else if (this.inverseRecord) { - promise = this.store._findByRecord(this.inverseRecord); } else { - promise = Ember.RSVP.Promise.resolve(null); + promise = this.findRecord(); } return PromiseObject.create({ diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index b489a2ee609..57accdf8be3 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -138,6 +138,72 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi })); }); +test("Accessing a hasMany backed by a link multiple times triggers only one request", function() { + expect(2); + var count = 0; + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + Comment.reopen({ + message: DS.belongsTo('post', { async: true }) + }); + + var post = env.store.push('post', { id: 1, links: {comments: '/posts/1/comments'}}); + env.adapter.findHasMany = function(store, record, link, relationship) { + start(); + count++; + equal(count, 1, "findHasMany has only been called once"); + stop(); + return new Ember.RSVP.Promise(function(resolve, reject) { + setTimeout(function(){ + var value = [ + { id: 1, body: "First" }, + { id: 2, body: "Second" } + ]; + resolve(value); + }, 100); + }); + }; + + stop(); + var promise1 = post.get('comments'); + //Invalidate the post.comments CP + env.store.push('comment', { id:1, message: 1 }); + var promise2 = post.get('comments'); + Ember.RSVP.all([promise1, promise2]).then(function() { + start(); + }); + equal(promise1.promise, promise2.promise, "Same promise is returned both times"); +}); + +test("A hasMany backed by a link remains a promise after a record has been added to it", function() { + expect(1); + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + Comment.reopen({ + message: DS.belongsTo('post', { async: true }) + }); + + env.adapter.findHasMany = function(store, record, link, relationship) { + return Ember.RSVP.resolve([ + { id: 1, body: "First" }, + { id: 2, body: "Second" } + ]); + }; + + var post = env.store.push('post', { id: 1, links: {comments: '/posts/1/comments'}}); + + post.get('comments').then(async(function() { + env.store.push('comment', { id:3, message: 1 }); + post.get('comments').then(async(function() { + ok(true, 'Promise was called'); + })); + })); +}); + test("A hasMany relationship can be reloaded if it was fetched via a link", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) @@ -661,4 +727,4 @@ test("Rollbacking a deleted record restores implicit relationship correctly when chapter.deleteRecord(); chapter.rollback(); equal(page.get('chapter'), chapter, "Page has a chapter after rollback"); -}); \ No newline at end of file +}); From 33b51dc5ff3bceac44f5e28e75d74d38e807d254 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 29 Sep 2014 11:12:05 -0500 Subject: [PATCH 0373/2527] use new Em.Map function signatures --- packages/ember-data/lib/adapters/rest_adapter.js | 2 +- .../ember-data/lib/system/debug/debug_adapter.js | 2 +- packages/ember-data/lib/system/model/attributes.js | 4 ++-- .../ember-data/lib/system/record_array_manager.js | 4 ++-- .../lib/system/record_arrays/record_array.js | 2 +- .../ember-data/lib/system/relationships/ext.js | 2 +- .../lib/system/relationships/relationship.js | 14 ++++++++++---- packages/ember-data/lib/system/store.js | 2 +- 8 files changed, 19 insertions(+), 13 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 8ef73a7ada0..e26eb1325cb 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -648,7 +648,7 @@ export default Adapter.extend({ } var groupsArray = []; - groups.forEach(function(key, group){ + groups.forEach(function(group, key){ // http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers var maxUrlLength = 2048; var splitGroups = splitGroupToFitInUrl(group, maxUrlLength); diff --git a/packages/ember-data/lib/system/debug/debug_adapter.js b/packages/ember-data/lib/system/debug/debug_adapter.js index 958b75f6ebb..ac8f67b2343 100644 --- a/packages/ember-data/lib/system/debug/debug_adapter.js +++ b/packages/ember-data/lib/system/debug/debug_adapter.js @@ -34,7 +34,7 @@ export default Ember.DataAdapter.extend({ }]; var count = 0; var self = this; - get(type, 'attributes').forEach(function(name, meta) { + get(type, 'attributes').forEach(function(meta, name) { if (count++ > self.attributeLimit) { return false; } var desc = capitalize(underscore(name).replace('_', ' ')); columns.push({ name: name, desc: desc }); diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 51dbd1fa466..132991b6212 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -143,7 +143,7 @@ Model.reopenClass({ @static */ eachAttribute: function(callback, binding) { - get(this, 'attributes').forEach(function(name, meta) { + get(this, 'attributes').forEach(function(meta, name) { callback.call(binding, name, meta); }, binding); }, @@ -191,7 +191,7 @@ Model.reopenClass({ @static */ eachTransformedAttribute: function(callback, binding) { - get(this, 'transformedAttributes').forEach(function(name, type) { + get(this, 'transformedAttributes').forEach(function(type, name) { callback.call(binding, name, type); }); } diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index 3ed70e6e584..07a6df9a3f6 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -67,7 +67,7 @@ export default Ember.Object.extend({ if (!recordArrays) { return; } - forEach(recordArrays, function(array) { + recordArrays.forEach(function(array){ array.removeRecord(record); }); }, @@ -121,7 +121,7 @@ export default Ember.Object.extend({ recordArrays.add(array); } } else if (!shouldBeInArray) { - recordArrays.remove(array); + recordArrays.delete(array); array.removeRecord(record); } }, diff --git a/packages/ember-data/lib/system/record_arrays/record_array.js b/packages/ember-data/lib/system/record_arrays/record_array.js index 70a3f449536..c724ccadbbd 100644 --- a/packages/ember-data/lib/system/record_arrays/record_array.js +++ b/packages/ember-data/lib/system/record_arrays/record_array.js @@ -191,7 +191,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { var recordArrays = record._recordArrays; if (recordArrays) { - recordArrays.remove(array); + recordArrays.delete(array); } }); }, diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 3a227539bc5..56a0505aa9c 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -487,7 +487,7 @@ Model.reopenClass({ @param {any} binding the value to which the callback's `this` should be bound */ eachRelationship: function(callback, binding) { - get(this, 'relationshipsByName').forEach(function(name, relationship) { + get(this, 'relationshipsByName').forEach(function(relationship, name) { callback.call(binding, name, relationship); }); }, diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index 36c041b7b7f..b5760355fa8 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -103,7 +103,7 @@ Relationship.prototype = { }, removeRecordFromOwn: function(record) { - this.members.remove(record); + this.members.delete(record); this.notifyRecordRelationshipRemoved(record); this.record.updateRecordArrays(); }, @@ -180,16 +180,22 @@ ManyRelationship.prototype.computeChanges = function(records) { var members = this.members; records = setForArray(records); + var recordsToRemove = []; members.forEach(function(member) { if (records.has(member)) return; - this.removeRecord(member); - }, this); + recordsToRemove.push(member); + }); + this.removeRecords(recordsToRemove); var hasManyArray = this.manyArray; - records.forEach(function(record, index) { + // Using records.toArray() since currently using + // removeRecord can modify length, messing stuff up + // forEach since it directly looks at "length" each + // iteration + records.toArray().forEach(function(record, index) { //Need to preserve the order of incoming records if (hasManyArray.objectAt(index) === record ) return; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index c7af3f74a86..8b72b61e451 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -540,7 +540,7 @@ Store = Ember.Object.extend({ this._pendingFetch = Ember.Map.create(); }, - _flushPendingFetchForType: function (type, recordResolverPairs) { + _flushPendingFetchForType: function (recordResolverPairs, type) { var store = this; var adapter = store.adapterFor(type); var shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; From 521fd0cdbb275b8efcaa6c8f4fa41050ae75e1fd Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 29 Sep 2014 16:12:08 -0500 Subject: [PATCH 0374/2527] update testem --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 60b799bf3a0..7ef8a30d6ca 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "ejs": "^1.0.0", "ember-cli": "0.0.43", "ember-publisher": "0.0.6", - "testem": "^0.6.17", + "testem": "^0.6.19", "yuidocjs": "~0.3.46" } } From 2eb1c971029af15dd78eee2332a9047c0cfdf1b4 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 29 Sep 2014 23:14:02 -0500 Subject: [PATCH 0375/2527] polyfill Ember.Map behavior --- .../ember-data/lib/adapters/rest_adapter.js | 5 +- packages/ember-data/lib/system/map.js | 78 +++++++++++++++++++ .../ember-data/lib/system/model/attributes.js | 7 +- .../ember-data/lib/system/model/errors.js | 6 +- .../lib/system/record_array_manager.js | 8 +- .../lib/system/relationships/ext.js | 10 ++- .../lib/system/relationships/relationship.js | 7 +- packages/ember-data/lib/system/store.js | 7 +- 8 files changed, 115 insertions(+), 13 deletions(-) create mode 100644 packages/ember-data/lib/system/map.js diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index e26eb1325cb..2d6ca38202c 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -6,6 +6,9 @@ import { Adapter, InvalidError } from "ember-data/system/adapter"; +import { + MapWithDefault +} from "ember-data/system/map"; var get = Ember.get; var forEach = Ember.ArrayPolyfills.forEach; @@ -618,7 +621,7 @@ export default Adapter.extend({ loaded separately by `findMany`. */ groupRecordsForFindMany: function (store, records) { - var groups = Ember.MapWithDefault.create({defaultValue: function(){return [];}}); + var groups = MapWithDefault.create({defaultValue: function(){return [];}}); var adapter = this; forEach.call(records, function(record){ diff --git a/packages/ember-data/lib/system/map.js b/packages/ember-data/lib/system/map.js new file mode 100644 index 00000000000..4363830e777 --- /dev/null +++ b/packages/ember-data/lib/system/map.js @@ -0,0 +1,78 @@ +/** + * Polyfill Ember.Map behavior for Ember <= 1.7 + * This can probably be removed before 1.0 final +*/ +var mapForEach, deleteFn; + +function OrderedSet(){ + Ember.OrderedSet.apply(this, arguments); +} + +function Map() { + Ember.Map.apply(this, arguments); +} + +function MapWithDefault(){ + Ember.MapWithDefault.apply(this, arguments); +} + +var testMap = Ember.Map.create(); +testMap.set('key', 'value'); + +var usesOldBehavior = false; + +testMap.forEach(function(value, key){ + usesOldBehavior = value === 'key' && key === 'value'; +}); + +Map.prototype = Object.create(Ember.Map.prototype); +MapWithDefault.prototype = Object.create(Ember.MapWithDefault.prototype); +OrderedSet.prototype = Object.create(Ember.OrderedSet.prototype); + +OrderedSet.create = function(){ + return new OrderedSet(); +}; + +function translate(valueKeyOrderedCallback){ + return function(key, value){ + valueKeyOrderedCallback.call(this, value, key); + }; +} + +// old, non ES6 compliant behavir +if (usesOldBehavior){ + mapForEach = function(callback, thisArg){ + Ember.Map.prototype.forEach.call(this, translate(callback), thisArg); + }; + + /* alias to remove */ + deleteFn = function(thing){ + this.remove.apply(this, arguments); + }; + + Map.prototype.forEach = mapForEach; + Map.prototype.delete = deleteFn; + + MapWithDefault.prototype.forEach = mapForEach; + MapWithDefault.prototype.delete = deleteFn; + + OrderedSet.prototype.delete = deleteFn; +} + +MapWithDefault.constructor = MapWithDefault; +Map.constructor = Map; + +MapWithDefault.create = function(options){ + if (options) { + return new MapWithDefault(options); + } else { + return new Map(); + } +}; + +Map.create = function(){ + return new this.constructor(); +}; + +export default Map; +export {Map, MapWithDefault, OrderedSet}; diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 132991b6212..6a17b07af11 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -1,4 +1,7 @@ import Model from "ember-data/system/model/model"; +import { + Map +} from "ember-data/system/map"; /** @module ember-data @@ -44,7 +47,7 @@ Model.reopenClass({ @readOnly */ attributes: Ember.computed(function() { - var map = Ember.Map.create(); + var map = Map.create(); this.eachComputedProperty(function(name, meta) { if (meta.isAttribute) { @@ -90,7 +93,7 @@ Model.reopenClass({ @readOnly */ transformedAttributes: Ember.computed(function() { - var map = Ember.Map.create(); + var map = Map.create(); this.eachAttribute(function(key, meta) { if (meta.type) { diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index 7ed82ae7b47..9f53fb7d9e3 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -2,6 +2,10 @@ var get = Ember.get; var isEmpty = Ember.isEmpty; var map = Ember.EnumerableUtils.map; +import { + MapWithDefault +} from "ember-data/system/map"; + /** @module ember-data */ @@ -98,7 +102,7 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { */ errorsByAttributeName: Ember.reduceComputed("content", { initialValue: function() { - return Ember.MapWithDefault.create({ + return MapWithDefault.create({ defaultValue: function() { return Ember.A(); } diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index 07a6df9a3f6..37bf0e079a2 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -8,6 +8,10 @@ import { AdapterPopulatedRecordArray, ManyArray } from "ember-data/system/record_arrays"; +import { + MapWithDefault, + OrderedSet +} from "ember-data/system/map"; var get = Ember.get; var forEach = Ember.EnumerableUtils.forEach; @@ -19,7 +23,7 @@ var forEach = Ember.EnumerableUtils.forEach; */ export default Ember.Object.extend({ init: function() { - this.filteredRecordArrays = Ember.MapWithDefault.create({ + this.filteredRecordArrays = MapWithDefault.create({ defaultValue: function() { return []; } }); @@ -34,7 +38,7 @@ export default Ember.Object.extend({ }, recordArraysForRecord: function(record) { - record._recordArrays = record._recordArrays || Ember.OrderedSet.create(); + record._recordArrays = record._recordArrays || OrderedSet.create(); return record._recordArrays; }, diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 56a0505aa9c..2e0459ab4bf 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -3,6 +3,10 @@ import { relationshipFromMeta } from "ember-data/system/relationship-meta"; import { Model } from "ember-data/system/model"; +import { + Map, + MapWithDefault +} from "ember-data/system/map"; var get = Ember.get; var filter = Ember.ArrayPolyfills.filter; @@ -263,7 +267,7 @@ Model.reopenClass({ @readOnly */ relationships: Ember.computed(function() { - var map = new Ember.MapWithDefault({ + var map = new MapWithDefault({ defaultValue: function() { return []; } }); @@ -413,7 +417,7 @@ Model.reopenClass({ @readOnly */ relationshipsByName: Ember.computed(function() { - var map = Ember.Map.create(); + var map = Map.create(); this.eachComputedProperty(function(name, meta) { if (meta.isRelationship) { @@ -463,7 +467,7 @@ Model.reopenClass({ @readOnly */ fields: Ember.computed(function() { - var map = Ember.Map.create(); + var map = Map.create(); this.eachComputedProperty(function(name, meta) { if (meta.isRelationship) { diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index b5760355fa8..d9ed43eac4a 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -2,9 +2,12 @@ import { PromiseManyArray, PromiseObject } from "ember-data/system/promise_proxies"; +import { + OrderedSet +} from "ember-data/system/map"; var Relationship = function(store, record, inverseKey, relationshipMeta) { - this.members = new Ember.OrderedSet(); + this.members = new OrderedSet(); this.store = store; this.key = relationshipMeta.key; this.inverseKey = inverseKey; @@ -337,7 +340,7 @@ BelongsToRelationship.prototype.getRecord = function() { }; function setForArray(array) { - var set = new Ember.OrderedSet(); + var set = new OrderedSet(); if (array) { for (var i=0, l=array.length; i Date: Mon, 29 Sep 2014 23:18:10 -0500 Subject: [PATCH 0376/2527] re enable beta and canary channel builds --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b5bd5564d71..29b781382c3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,8 @@ install: script: - npm run-script testem-local - npm run-script testem-stable - # - npm run-script testem-beta - # - npm run-script testem-canary + - npm run-script testem-beta + - npm run-script testem-canary after_success: - npm run-script publish-build - "./bin/bower-ember-data-build" From 019e9e1148263041dccaa0c1930cee7b032c3adb Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 29 Sep 2014 23:26:13 -0500 Subject: [PATCH 0377/2527] update comments for map.js --- packages/ember-data/lib/system/map.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/map.js b/packages/ember-data/lib/system/map.js index 4363830e777..ed73c5b521b 100644 --- a/packages/ember-data/lib/system/map.js +++ b/packages/ember-data/lib/system/map.js @@ -33,13 +33,21 @@ OrderedSet.create = function(){ return new OrderedSet(); }; +/** + * returns a function that calls the original + * callback function in the correct order. + * if we are in pre-Ember.1.8 land, Map/MapWithDefault + * forEach calls with key, value, in that order. + * >= 1.8 forEach is called with the order value, key as per + * the ES6 spec. +*/ function translate(valueKeyOrderedCallback){ return function(key, value){ valueKeyOrderedCallback.call(this, value, key); }; } -// old, non ES6 compliant behavir +// old, non ES6 compliant behavior if (usesOldBehavior){ mapForEach = function(callback, thisArg){ Ember.Map.prototype.forEach.call(this, translate(callback), thisArg); From 7742069255891fdb604c9fb0152a8038d49609fd Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 30 Sep 2014 09:55:37 -0500 Subject: [PATCH 0378/2527] use a for loop for ie compat and performance --- .../lib/system/relationships/relationship.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index d9ed43eac4a..36bc434ef94 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -181,9 +181,12 @@ ManyRelationship.prototype.reload = function() { ManyRelationship.prototype.computeChanges = function(records) { var members = this.members; + var recordsToRemove = []; + var length; + var record; + var i; records = setForArray(records); - var recordsToRemove = []; members.forEach(function(member) { if (records.has(member)) return; @@ -198,13 +201,17 @@ ManyRelationship.prototype.computeChanges = function(records) { // removeRecord can modify length, messing stuff up // forEach since it directly looks at "length" each // iteration - records.toArray().forEach(function(record, index) { + records = records.toArray(); + length = records.length; + for (i = 0; i < length; i++){ + record = records[i]; //Need to preserve the order of incoming records - if (hasManyArray.objectAt(index) === record ) return; - + if (hasManyArray.objectAt(i) === record ) { + continue; + } this.removeRecord(record); - this.addRecord(record, index); - }, this); + this.addRecord(record, i); + } }; ManyRelationship.prototype.fetchLink = function() { From 8e0554912ae8eb66603eb3ec3846d8393e2b1630 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 30 Sep 2014 17:46:08 -0500 Subject: [PATCH 0379/2527] don't use call, instead invoke the super function by aliasing it --- packages/ember-data/lib/system/map.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/map.js b/packages/ember-data/lib/system/map.js index ed73c5b521b..a87fd60bb97 100644 --- a/packages/ember-data/lib/system/map.js +++ b/packages/ember-data/lib/system/map.js @@ -50,18 +50,20 @@ function translate(valueKeyOrderedCallback){ // old, non ES6 compliant behavior if (usesOldBehavior){ mapForEach = function(callback, thisArg){ - Ember.Map.prototype.forEach.call(this, translate(callback), thisArg); + this.__super$forEach(translate(callback), thisArg); }; /* alias to remove */ deleteFn = function(thing){ - this.remove.apply(this, arguments); + this.remove(thing); }; + Map.prototype.__super$forEach = Ember.Map.prototype.forEach; Map.prototype.forEach = mapForEach; Map.prototype.delete = deleteFn; MapWithDefault.prototype.forEach = mapForEach; + MapWithDefault.prototype.__super$forEach = Ember.MapWithDefault.prototype.forEach; MapWithDefault.prototype.delete = deleteFn; OrderedSet.prototype.delete = deleteFn; From 683faa7155539bb32be5f2c827d864832ea282fb Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Wed, 1 Oct 2014 11:40:02 +0200 Subject: [PATCH 0380/2527] Always remove the inverse record (if exists) from a belongsTo relationship fixes #2331 --- .../lib/system/relationships/relationship.js | 2 +- .../relationships/inverse_relationships_test.js | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index 36bc434ef94..6c8836d6750 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -279,7 +279,7 @@ BelongsToRelationship.prototype.addRecord = function(newRecord) { var type = this.relationshipMeta.type; Ember.assert("You can only add a '" + type.typeKey + "' record to this relationship", newRecord instanceof type); - if (this.inverseRecord && this.inverseKey) { + if (this.inverseRecord) { this.removeRecord(this.inverseRecord); } diff --git a/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js b/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js index 00dd7c8cd98..0c75ca4edcd 100644 --- a/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js +++ b/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js @@ -191,6 +191,7 @@ test("When setting a belongsTo, the OneToOne invariant is commutative", function }); test("OneToNone relationship works", function() { + expect(3); Post = DS.Model.extend({ name: DS.attr('string') }); @@ -203,11 +204,17 @@ test("OneToNone relationship works", function() { store = env.store; var comment = store.createRecord('comment'); - var post = store.createRecord('post'); + var post1 = store.createRecord('post'); + var post2 = store.createRecord('post'); - comment.set('post', post); + comment.set('post', post1); + equal(comment.get('post'), post1, 'the post is set to the first one'); - equal(comment.get('post'), post); + comment.set('post', post2); + equal(comment.get('post'), post2, 'the post is set to the second one'); + + comment.set('post', post1); + equal(comment.get('post'), post1, 'the post is re-set to the first one'); }); From 4927b45676d86b2a69dae02b1a54ad5a20357b55 Mon Sep 17 00:00:00 2001 From: "Jose A. Salguero" Date: Thu, 2 Oct 2014 15:21:31 +0200 Subject: [PATCH 0381/2527] Added note about empty ids in async relationships issue --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aeb272af3a1..9118c76aee2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Ember Data 1.0.0-beta.10 _(September 9, 2014)_ +**NOTE:** A bug was introduced in this version where the saving of a model with async hasMany property will send an empty list to the server in the payload, so is discouraged to use this version if you have such relationships on your application. For more details https://github.com/emberjs/data/issues/2339 + * Bring back relationship parameter for findHasMany & findBelongsTo * add es5-shim/sham requirement to README * Add-on uses blueprint `addBowerPackageToProject()` hook to add ed as bower dep instead of including a pre-built version From c2bf2a5b3f9b4ea9d4c3c909159b986ef40f4f0d Mon Sep 17 00:00:00 2001 From: silatham99 Date: Mon, 6 Oct 2014 10:46:27 -0500 Subject: [PATCH 0382/2527] Fix typo in DS.Model.save in-code documetation --- packages/ember-data/lib/system/model/model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index bf75c02250b..d3eb5769a58 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -927,7 +927,7 @@ var Model = Ember.Object.extend(Ember.Evented, { /** Save the record and persist any changes to the record to an - extenal source via the adapter. + external source via the adapter. Example From 3681fcf463204bfc0acf307cbe8ff0aa4e95efb9 Mon Sep 17 00:00:00 2001 From: Calvin Metcalf Date: Mon, 6 Oct 2014 12:27:15 -0400 Subject: [PATCH 0383/2527] pass ids through encodeURIComponent when turning them into urls --- .../ember-data/lib/adapters/rest_adapter.js | 2 +- .../tests/unit/adapters/rest_adapter/ajax.js | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 packages/ember-data/tests/unit/adapters/rest_adapter/ajax.js diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 2d6ca38202c..29f75e560c2 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -536,7 +536,7 @@ export default Adapter.extend({ //We might get passed in an array of ids from findMany //in which case we don't want to modify the url, as the //ids will be passed in through a query param - if (id && !Ember.isArray(id)) { url.push(id); } + if (id && !Ember.isArray(id)) { url.push(encodeURIComponent(id)); } if (prefix) { url.unshift(prefix); } diff --git a/packages/ember-data/tests/unit/adapters/rest_adapter/ajax.js b/packages/ember-data/tests/unit/adapters/rest_adapter/ajax.js new file mode 100644 index 00000000000..f49c35dbe2a --- /dev/null +++ b/packages/ember-data/tests/unit/adapters/rest_adapter/ajax.js @@ -0,0 +1,39 @@ +var get = Ember.get, set = Ember.set; +var Person, Place, store, adapter, env; + +module("integration/adapter/ajax - building requests", { + setup: function() { + Person = {typeKey: 'person'}; + Place = {typeKey: 'place'}; + env = setupStore({adapter: DS.RESTAdapter, person: Person, place: Place }); + store = env.store; + adapter = env.adapter; + }, + + teardown: function() { + store.destroy(); + env.container.destroy(); + + } +}); + +test("When an id is searched, the correct url should be generated", function() { + expect(2); + var count = 0; + adapter.ajax = function(url, method) { + if (count === 0) {equal(url, '/people/1', "should create the correct url");} + if (count === 1) {equal(url, '/places/1', "should create the correct url");} + count++; + return Ember.RSVP.resolve(); + }; + adapter.find(store, Person, 1); + adapter.find(store, Place, 1); +}); +test("id's should be sanatized", function() { + expect(1); + adapter.ajax= function(url, method) { + equal(url, '/people/..%2Fplace%2F1', "should create the correct url"); + return Ember.RSVP.resolve(); + }; + adapter.find(store, Person, '../place/1'); +}); \ No newline at end of file From 1f018de833162504ba75f9aed479fbe971aea1e0 Mon Sep 17 00:00:00 2001 From: Steffen Brem Date: Tue, 7 Oct 2014 21:54:17 +0200 Subject: [PATCH 0384/2527] Added assertion for updateLink Added an assertion for string type. Since you could also pass objects to `updateLink` (which would always result in false in the next if statement) containing a link. This PR notifies creators of serializers so they always use a string when handling links. Added test for links with type other than string Removed a duplicate line. Added test case for push link with null value --- .../lib/system/relationships/relationship.js | 2 +- .../ember-data/tests/unit/store/push_test.js | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index 6c8836d6750..803f851b79e 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -12,7 +12,6 @@ var Relationship = function(store, record, inverseKey, relationshipMeta) { this.key = relationshipMeta.key; this.inverseKey = inverseKey; this.record = record; - this.key = relationshipMeta.key; this.isAsync = relationshipMeta.options.async; this.relationshipMeta = relationshipMeta; //This probably breaks for polymorphic relationship in complex scenarios, due to @@ -112,6 +111,7 @@ Relationship.prototype = { }, updateLink: function(link) { + Ember.assert("You have pushed a record of type '" + this.record.constructor.typeKey + "' with '" + this.key + "' as a link, but the value of that link is not a string.", typeof link === 'string' || link === null); if (link !== this.link) { this.link = link; this.linkPromise = null; diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index 55478beae49..ede4128cc7d 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -336,3 +336,30 @@ test('calling push without data argument as an object raises an error', function }, /object/); }); }); + +test('Calling push with a link containing an object throws an assertion error', function() { + expectAssertion(function() { + store.push('person', { + id: '1', + links: { + phoneNumbers: { + href: '/api/people/1/phone-numbers' + } + } + }); + }, "You have pushed a record of type 'person' with 'phoneNumbers' as a link, but the value of that link is not a string."); +}); + +test('Calling push with a link containing the value null', function() { + store.push('person', { + id: '1', + firstName: 'Tan', + links: { + phoneNumbers: null + } + }); + + var person = store.getById('person', 1); + + equal(person.get('firstName'), "Tan", "you can use links that contain null as a value"); +}); From e482269f41fe4d15b1d662b032d6920e9299bed2 Mon Sep 17 00:00:00 2001 From: sandstrom Date: Wed, 8 Oct 2014 00:35:55 +0200 Subject: [PATCH 0385/2527] Update build command, plus minor text adjustments --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5dc996b543a..d6304cec71e 100644 --- a/README.md +++ b/README.md @@ -26,16 +26,16 @@ bower install ember-data --save The latest passing build from the "master" branch is available on [http://emberjs.com/builds/#/canary](http://emberjs.com/builds/#/canary). -Similarly the latest passing build from the "beta" branch can be found +Similarly, the latest passing build from the "beta" branch can be found on [http://emberjs.com/builds/#/beta](http://emberjs.com/builds/#/beta) -You also have the option to build ember-data.js yourself. Clone the -repository, run `broccoli build dist` after [setup](#setup). You'll find -ember-data.js in the `dist` directory. +Or build ember-data.js yourself. Clone the repository and run `npm run dist` +after [setup](#setup). You'll find ember-data.js in the `dist` directory. #### Internet Explorer 8 -If you need to support Internet Explorer, you will need to use es5-shim.js and es5-sham.js from [es5-shim](https://github.com/es-shims/es5-shim). +If you need to support Internet Explorer, you will need to use es5-shim.js and +es5-sham.js from [es5-shim](https://github.com/es-shims/es5-shim). ### Instantiating the Store From b29d7d64db5c5a01e87027af1091e33a7a7c9550 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Sat, 27 Sep 2014 02:09:42 -0400 Subject: [PATCH 0386/2527] =?UTF-8?q?a=20bit=20verbose,=20but=20lets=20ens?= =?UTF-8?q?ure=20we=20don=E2=80=99t=20deoptimize=20these=20functions=20in?= =?UTF-8?q?=20some=20runtimes.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * passing arguments object to another function (other then via apply) deoptimizes function body * materializing the arguments object via splice deoptimizes the function body --- packages/ember-data/lib/system/model/model.js | 23 ++++++++++++++++--- packages/ember-data/tests/unit/model_test.js | 4 +++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index d3eb5769a58..f558d14d998 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1054,13 +1054,30 @@ var Model = Ember.Object.extend(Ember.Evented, { @private @param name */ - trigger: function(name) { - Ember.tryInvoke(this, name, [].slice.call(arguments, 1)); + trigger: function() { + var length = arguments.length; + var args = new Array(length - 1); + var name = arguments[0]; + + for (var i = 1; i < length; i++ ){ + args[i - 1] = arguments[i]; + } + + Ember.tryInvoke(this, name, args); this._super.apply(this, arguments); }, triggerLater: function() { - if (this._deferredTriggers.push(arguments) !== 1) { return; } + var length = arguments.length; + var args = new Array(length); + + for (var i = 0; i < length; i++ ){ + args[i] = arguments[i]; + } + + if (this._deferredTriggers.push(args) !== 1) { + return; + } Ember.run.schedule('actions', this, '_triggerDeferredTriggers'); }, diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index d909143de6d..75ca57867ee 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -270,7 +270,9 @@ test("when an event is triggered on a record the method with the same name is in test("when a method is invoked from an event with the same name the arguments are passed through", function(){ var eventMethodArgs = null; - var F = function() { eventMethodArgs = arguments; }; + var F = function() { + eventMethodArgs = arguments; + }; var record = store.createRecord(Person); record.eventThatTriggersMethod = F; From cb73f55243888a44aeb5711a87e65878901a0c93 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 17 Oct 2013 18:18:17 -0400 Subject: [PATCH 0387/2527] some failing async/sync HM -> BT relationship tests --- .../relationships/has_many_test.js | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 57accdf8be3..8189026b744 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -630,6 +630,41 @@ test("When a record is saved, its unsaved hasMany records should be kept", funct equal(get(post, 'comments.length'), 1, "The unsaved comment should be in the post's comments array"); }); +test("dual non-async HM <-> BT", function(){ + Post.reopen({ + comments: DS.hasMany('comment', { inverse: 'post' }) + }); + + Comment.reopen({ + post: DS.belongsTo('post') + }); + + env.adapter.createRecord = function(store, type, record) { + var data = record.serialize(); + data.id = 2; + return Ember.RSVP.resolve(data); + }; + + var post = env.store.push('post', { id: 1, comments: [ 1 ] }); + var firstComment = env.store.push('comment', { id: 1, post: 1 }); + + Ember.run(function(){ + return env.store.createRecord('comment', { + post: post + }).save(); + }).then(function(comment){ + var commentPost = comment.get('post'); + var postComments = comment.get('post.comments'); + var postCommentsLength = comment.get('post.comments.length'); + + deepEqual(post, commentPost, 'expect the new comments post, to be the correct post'); + ok(postComments, "comments should exist"); + equal(postCommentsLength, 2, "comment's post should have a reference back to comment"); + ok(postComments && postComments.indexOf(firstComment) !== -1, 'expect to contain first comment'); + ok(postComments && postComments.indexOf(comment) !== -1, 'expected to contain the new comment'); + }); +}); + test("When an unloaded record is added to the hasMany, it gets fetched once the hasMany is accessed even if the hasMany has been already fetched", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) From 920751043286c98fd6787f43c3c80def72cf70ff Mon Sep 17 00:00:00 2001 From: Artem Suschev Date: Thu, 2 Oct 2014 00:52:22 +0400 Subject: [PATCH 0388/2527] added failing test --- .../tests/integration/filter_test.js | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/packages/ember-data/tests/integration/filter_test.js b/packages/ember-data/tests/integration/filter_test.js index 3a36f259456..9cbb5068a46 100644 --- a/packages/ember-data/tests/integration/filter_test.js +++ b/packages/ember-data/tests/integration/filter_test.js @@ -27,6 +27,23 @@ module("integration/filter - DS.Model updating", { } }); +function tapFn(fn, callback) { + var old_fn = fn; + + var new_fn = function() { + var result = old_fn.apply(this, arguments); + if (callback) { + callback.apply(obj, arguments); + } + new_fn.summary.called.push(arguments); + return result; + }; + new_fn.summary = { called: [] }; + + return new_fn; +} + + test("when a DS.Model updates its attributes, its changes affect its filtered Array membership", function() { store.pushMany('person', array); @@ -515,3 +532,40 @@ test("a Record Array can update its filter after server-side creates multiple re serverResponds(); equal(get(recordArray, 'length'), 5, "The record array updates when the server creates multiple records"); }); + +test("a Record Array can update its filter after server-side creates multiple records", function() { + setup({ + createRecord: function(store, type, record) { + switch (record.get('name')) { + case "Client-side Mike": + return Ember.RSVP.resolve({id: 4, name: "Scumbag Server-side Mike"}); + case "Client-side David": + return Ember.RSVP.resolve({id: 5, name: "Scumbag Server-side David"}); + } + } + }); + + clientCreates(["Mike", "David"]); + equal(get(recordArray, 'length'), 3, "The record array does not include non-matching records"); + + serverResponds(); + equal(get(recordArray, 'length'), 5, "The record array updates when the server creates multiple records"); +}); + +test("destroying filteredRecordArray unregisters models from being filtered", function() { + var filterFn = tapFn( function(){ return true; } ); + + var person = store.push('person', { + id: 1, + name: 'Tom Dale' + }); + + var recordArray = store.filter('person', filterFn); + + equal(filterFn.summary.called.length, 1); + + Ember.run(recordArray, recordArray.destroy); + person.set('name', 'Tom'); + + equal(filterFn.summary.called.length, 1, 'expected the filter function not being called anymore'); +}); From 6db9981fb4d5d64a0d9915131ee7ec2b835f9a18 Mon Sep 17 00:00:00 2001 From: Artem Suschev Date: Wed, 8 Oct 2014 18:41:51 +0400 Subject: [PATCH 0389/2527] updated test --- packages/ember-data/tests/integration/filter_test.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/tests/integration/filter_test.js b/packages/ember-data/tests/integration/filter_test.js index 9cbb5068a46..1dd435d240f 100644 --- a/packages/ember-data/tests/integration/filter_test.js +++ b/packages/ember-data/tests/integration/filter_test.js @@ -564,8 +564,12 @@ test("destroying filteredRecordArray unregisters models from being filtered", fu equal(filterFn.summary.called.length, 1); - Ember.run(recordArray, recordArray.destroy); - person.set('name', 'Tom'); + Ember.run(function(){ + recordArray.then(function(array){ + array.destroy() + }); + }); + clientEdits([1]); equal(filterFn.summary.called.length, 1, 'expected the filter function not being called anymore'); }); From 59a6c6e3516ff5fe7c0d2ade99471348984261c4 Mon Sep 17 00:00:00 2001 From: Artem Suschev Date: Wed, 8 Oct 2014 18:42:35 +0400 Subject: [PATCH 0390/2527] made the test pass --- .../ember-data/lib/system/record_array_manager.js | 13 +++++++++++++ .../system/record_arrays/filtered_record_array.js | 15 ++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index 37bf0e079a2..bf1a06e6c94 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -264,6 +264,19 @@ export default Ember.Object.extend({ this.updateFilter(array, type, filter); }, + /** + Unregister a FilteredRecordArray. + So manager will not update this array. + + @method unregisterFilteredRecordArray + @param {DS.RecordArray} array + */ + unregisterFilteredRecordArray: function(array) { + var recordArrays = this.filteredRecordArrays.get(array.type); + var index = recordArrays.indexOf(array); + recordArrays.splice(index, 1); + }, + // Internally, we maintain a map of all unloaded IDs requested by // a ManyArray. As the adapter loads data into the store, the // store notifies any interested ManyArrays. When the ManyArray's diff --git a/packages/ember-data/lib/system/record_arrays/filtered_record_array.js b/packages/ember-data/lib/system/record_arrays/filtered_record_array.js index 00c28161927..6f1d7032ea3 100644 --- a/packages/ember-data/lib/system/record_arrays/filtered_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/filtered_record_array.js @@ -62,5 +62,18 @@ export default RecordArray.extend({ updateFilter: Ember.observer(function() { Ember.run.once(this, this._updateFilter); - }, 'filterFunction') + }, 'filterFunction'), + + /** + @method _unregisterFromManager + @private + */ + _unregisterFromManager: function(){ + this.manager.unregisterFilteredRecordArray(this); + }, + + willDestroy: function(){ + this._unregisterFromManager(); + this._super(); + } }); From 73d23b275a27ad9ebdaca8f8339bbd7241dc4588 Mon Sep 17 00:00:00 2001 From: Artem Suschev Date: Fri, 10 Oct 2014 16:38:45 +0400 Subject: [PATCH 0391/2527] added note about coalescing and custom URLs --- packages/ember-data/lib/adapters/rest_adapter.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 29f75e560c2..fab0d585411 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -208,6 +208,9 @@ export default Adapter.extend({ will also send a request to: `GET /comments?ids[]=1&ids[]=2` + Note: Requests coalescing rely on URL building strategy. So if you override `buildUrl` in your app + `groupRecordsForFindMany` more likely should be overriden as well in order for coalescing to work. + @property coalesceFindRequests @type {boolean} */ From 49897a783c9c74b83647554c3003bf9738f9c2cc Mon Sep 17 00:00:00 2001 From: IgorT Date: Sun, 12 Oct 2014 03:34:43 +0300 Subject: [PATCH 0392/2527] Temporary fix for #2344 rollback after delete for recordArrays This is a temporary fix, it's clear this code needs to be refactored. Moreover I am not sure that removing deleted records from recordArrays before they are deleted is a correct design decision. --- packages/ember-data/lib/system/record_array_manager.js | 2 ++ .../tests/integration/records/delete_record_test.js | 9 +++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index 37bf0e079a2..935043d0152 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -74,6 +74,8 @@ export default Ember.Object.extend({ recordArrays.forEach(function(array){ array.removeRecord(record); }); + + record._recordArrays = null; }, _recordWasChanged: function (record) { diff --git a/packages/ember-data/tests/integration/records/delete_record_test.js b/packages/ember-data/tests/integration/records/delete_record_test.js index e0b648029c1..e26280f61c3 100644 --- a/packages/ember-data/tests/integration/records/delete_record_test.js +++ b/packages/ember-data/tests/integration/records/delete_record_test.js @@ -49,12 +49,9 @@ test("when deleted records are rolled back, they are still in their previous rec equal(all.get('length'), 2, 'precond - we start with two people'); equal(filtered.get('length'), 2, 'precond - we start with two people'); - - Ember.run(function () { - jaime.deleteRecord(); - jaime.rollback(); - }); - + jaime.deleteRecord(); + jaime.rollback(); equal(all.get('length'), 2, 'record was not removed'); equal(filtered.get('length'), 2, 'record was not removed'); + }); From 0f5599b4eded2d658bef9f86ff860e4c03ebdeac Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sun, 5 Oct 2014 13:02:28 -0500 Subject: [PATCH 0393/2527] warn instead of throw when resolving keys to model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this commit, if you had a payload like: ```javascript { “posts”: [] } ``` But didn’t have a “post” model defined, Ember Data would blow up. As discussed in the data team meeting, we decided to warn if the model could not be resolved. In this spirit, Ember Data just doesn’t process what it doesn’t understand, but can still provide you with a better debugging message to give you hints on what your payload should look like. fixes GH-2337 --- .jshintrc | 5 +- config/ember-defeatureify.js | 10 +- .../lib/serializers/rest_serializer.js | 24 ++- packages/ember-data/lib/system/store.js | 6 +- .../serializers/rest_serializer_test.js | 192 +++++++++++++++++- tests/ember_configuration.js | 33 +++ 6 files changed, 256 insertions(+), 14 deletions(-) diff --git a/.jshintrc b/.jshintrc index 98e577bb2c0..a6cbabaf4be 100644 --- a/.jshintrc +++ b/.jshintrc @@ -32,8 +32,9 @@ "invokeAsync", "jQuery", "expectAssertion", - "expectDeprecation" - + "expectDeprecation", + "warns", + "noWarns" ], "node" : false, diff --git a/config/ember-defeatureify.js b/config/ember-defeatureify.js index 63e7b5a86d1..67c344ce9a3 100644 --- a/config/ember-defeatureify.js +++ b/config/ember-defeatureify.js @@ -2,10 +2,16 @@ module.exports = { options: { debugStatements: [ "Ember.warn", + "emberWarn", "Ember.assert", + "emberAssert", "Ember.deprecate", + "emberDeprecate", "Ember.debug", - "Ember.Logger.info" + "emberDebug", + "Ember.Logger.info", + "Ember.runInDebug", + "runInDebug" ] }, stripDebug: { @@ -15,4 +21,4 @@ module.exports = { src: 'dist/ember-data.js', dest: 'dist/ember-data.prod.js' } -}; \ No newline at end of file +}; diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index 13e1dc1b82b..448931abee2 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -54,7 +54,7 @@ function coerceId(id) { @namespace DS @extends DS.JSONSerializer */ -export default JSONSerializer.extend({ +var RESTSerializer = JSONSerializer.extend({ /** If you want to do normalizations specific to some part of the payload, you can specify those under `normalizeHash`. @@ -267,6 +267,10 @@ export default JSONSerializer.extend({ for (var prop in payload) { var typeName = this.typeForRoot(prop); + if (!store.modelFactoryFor(typeName)){ + Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false); + continue; + } var type = store.modelFor(typeName); var isPrimary = type.typeKey === primaryTypeName; var value = payload[prop]; @@ -420,6 +424,10 @@ export default JSONSerializer.extend({ } var typeName = this.typeForRoot(typeKey); + if (!store.modelFactoryFor(typeName)) { + Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false); + continue; + } var type = store.modelFor(typeName); var typeSerializer = store.serializerFor(type); var isPrimary = (!forcedSecondary && (type.typeKey === primaryTypeName)); @@ -475,6 +483,10 @@ export default JSONSerializer.extend({ for (var prop in payload) { var typeName = this.typeForRoot(prop); + if (!store.modelFactoryFor(typeName, prop)){ + Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false); + continue; + } var type = store.modelFor(typeName); var typeSerializer = store.serializerFor(type); @@ -729,3 +741,13 @@ export default JSONSerializer.extend({ } } }); + +Ember.runInDebug(function(){ + RESTSerializer.reopen({ + warnMessageNoModelForKey: function(prop, typeKey){ + return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + typeKey + '" (resolved model name using ' + this.constructor.toString() + '.typeForRoot("' + prop + '"))'; + } + }); +}); + +export default RESTSerializer; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 73b833bd7e1..b42a84b1f98 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1208,7 +1208,7 @@ Store = Ember.Object.extend({ var factory; if (typeof key === 'string') { - factory = this.container.lookupFactory('model:' + key); + factory = this.modelFactoryFor(key); if (!factory) { throw new Ember.Error("No model was found for '" + key + "'"); } @@ -1225,6 +1225,10 @@ Store = Ember.Object.extend({ return factory; }, + modelFactoryFor: function(key){ + return this.container.lookupFactory('model:' + key); + }, + /** Push some data for a given type into the store. diff --git a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js index 23c93cc9776..8704f5f8a25 100644 --- a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js @@ -1,5 +1,6 @@ var get = Ember.get, set = Ember.set; var HomePlanet, league, SuperVillain, superVillain, EvilMinion, YellowMinion, DoomsdayDevice, Comment, env; +var run = Ember.run; module("integration/serializer/rest - RESTSerializer", { setup: function() { @@ -80,21 +81,196 @@ test("extractArray with custom typeForRoot", function() { })); }); -test("extractArray failure with custom typeForRoot", function() { +test("extractArray warning with custom typeForRoot", function() { + var homePlanets; env.restSerializer.typeForRoot = function(root) { - //should be camelized too, but, whoops, the developer forgot! - return Ember.String.singularize(root); + //return some garbage that won"t resolve in the container + return "garbage"; }; var jsonHash = { - home_planets: [{id: "1", name: "Umber", superVillains: [1]}], - super_villains: [{id: "1", firstName: "Tom", lastName: "Dale", homePlanet: "1"}] + home_planets: [{id: "1", name: "Umber", superVillains: [1]}] }; - throws(function(){ + warns(function(){ env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); - }, "No model was found for 'home_planets'", - "raised error message expected to contain \"No model was found for 'home_planets'\""); + }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); + + // should not warn if a model is found. + env.restSerializer.typeForRoot = function(root){ + return Ember.String.camelize(Ember.String.singularize(root)); + }; + + jsonHash = { + home_planets: [{id: "1", name: "Umber", superVillains: [1]}] + }; + + noWarns(function(){ + homePlanets = Ember.A(env.restSerializer.extractArray(env.store, HomePlanet, jsonHash)); + }); + + equal(get(homePlanets, "length"), 1); + equal(get(homePlanets, "firstObject.name"), "Umber"); + deepEqual(get(homePlanets, "firstObject.superVillains"), [1]); +}); + +test("extractSingle warning with custom typeForRoot", function() { + var homePlanet; + env.restSerializer.typeForRoot = function(root) { + //return some garbage that won"t resolve in the container + return "garbage"; + }; + + var jsonHash = { + home_planet: {id: "1", name: "Umber", superVillains: [1]} + }; + + warns(Ember.run.bind(null, function(){ + env.restSerializer.extractSingle(env.store, HomePlanet, jsonHash); + }), /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); + + // should not warn if a model is found. + env.restSerializer.typeForRoot = function(root){ + return Ember.String.camelize(Ember.String.singularize(root)); + }; + + jsonHash = { + home_planet: {id: "1", name: "Umber", superVillains: [1]} + }; + + noWarns(function(){ + homePlanet = env.restSerializer.extractSingle(env.store, HomePlanet, jsonHash); + }); + + equal(get(homePlanet, "name"), "Umber"); + deepEqual(get(homePlanet, "superVillains"), [1]); +}); + +test("pushPayload - single record payload - warning with custom typeForRoot", function() { + var homePlanet; + var HomePlanetRestSerializer = DS.RESTSerializer.extend({ + typeForRoot: function(root){ + //return some garbage that won"t resolve in the container + if (root === "home_planet") { + return "garbage"; + } else { + return Ember.String.singularize(Ember.String.camelize(root)); + } + } + }); + + env.container.register("serializer:homePlanet", HomePlanetRestSerializer); + + var jsonHash = { + home_planet: {id: "1", name: "Umber", superVillains: [1]}, + super_villains: [ + { + "id": "1", + "firstName": "Stanley" + } + ] + }; + + warns(function(){ + env.store.pushPayload("homePlanet", jsonHash); + }, /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); + + + // assert non-warned records get pushed into store correctly + var superVillain = env.store.getById("superVillain", "1"); + equal(get(superVillain, "firstName"), "Stanley"); + + // Serializers are singletons, so that"s why we use the store which + // looks at the container to look it up + env.store.serializerFor("homePlanet").reopen({ + typeForRoot: function(root){ + // should not warn if a model is found. + return Ember.String.camelize(Ember.String.singularize(root)); + } + }); + + jsonHash = { + home_planet: {id: "1", name: "Umber", superVillains: [1]}, + super_villains: [ + { + "id": "1", + "firstName": "Stanley" + } + ] + }; + + noWarns(function(){ + env.store.pushPayload("homePlanet", jsonHash); + run(function(){ + homePlanet = env.store.getById("homePlanet", "1"); + }); + }); + + equal(get(homePlanet, "name"), "Umber"); + deepEqual(get(homePlanet, "superVillains.firstObject.firstName"), "Stanley"); +}); + +test("pushPayload - multiple record payload (extractArray) - warning with custom typeForRoot", function() { + var homePlanet; + var HomePlanetRestSerializer = DS.RESTSerializer.extend({ + typeForRoot: function(root){ + //return some garbage that won"t resolve in the container + if (root === "home_planets") { + return "garbage"; + } else { + return Ember.String.singularize(Ember.String.camelize(root)); + } + } + }); + + env.container.register("serializer:homePlanet", HomePlanetRestSerializer); + + var jsonHash = { + home_planets: [{id: "1", name: "Umber", superVillains: [1]}], + super_villains: [ + { + "id": "1", + "firstName": "Stanley" + } + ] + }; + + warns(function(){ + env.store.pushPayload("homePlanet", jsonHash); + }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); + + // assert non-warned records get pushed into store correctly + var superVillain = env.store.getById("superVillain", "1"); + equal(get(superVillain, "firstName"), "Stanley"); + + // Serializers are singletons, so that"s why we use the store which + // looks at the container to look it up + env.store.serializerFor("homePlanet").reopen({ + typeForRoot: function(root){ + // should not warn if a model is found. + return Ember.String.camelize(Ember.String.singularize(root)); + } + }); + + jsonHash = { + home_planets: [{id: "1", name: "Umber", superVillains: [1]}], + super_villains: [ + { + "id": "1", + "firstName": "Stanley" + } + ] + }; + + noWarns(function(){ + env.store.pushPayload("homePlanet", jsonHash); + run(function(){ + homePlanet = env.store.getById("homePlanet", "1"); + }); + }); + + equal(get(homePlanet, "name"), "Umber"); + deepEqual(get(homePlanet, "superVillains.firstObject.firstName"), "Stanley"); }); test("serialize polymorphicType", function() { diff --git a/tests/ember_configuration.js b/tests/ember_configuration.js index bdfdad15bee..764e1d5bb0d 100644 --- a/tests/ember_configuration.js +++ b/tests/ember_configuration.js @@ -212,4 +212,37 @@ // to make the QUnit global check run clean jQuery(window).data('testing', true); + window.warns = function(callback, regex){ + var warnWasCalled = false; + var oldWarn = Ember.warn; + Ember.warn = function Ember_assertWarning(message, test){ + warnWasCalled = true; + if (regex && !test) { + ok(regex.test(message), 'Ember.warn called with expected message, but was called with ' + message); + } else if (test) { + ok(false, "Expected warn to receive a falsy test, but got a truthy test"); + } + }; + try { + callback(); + ok(warnWasCalled, 'expected Ember.warn to warn, but was not called'); + } finally { + Ember.warn = oldWarn; + } + }; + + window.noWarns = function(callback){ + var oldWarn = Ember.warn; + var warnWasCalled = false; + Ember.warn = function Ember_noWarn(message, test){ + warnWasCalled = !test; + }; + try { + callback(); + } finally { + ok(!warnWasCalled, 'Ember.warn warned when it should not have warned'); + Ember.warn = oldWarn; + } + }; + })(); From 6090b06a12ed48acef9358d4db576e9792002a85 Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Wed, 8 Oct 2014 10:03:08 +0200 Subject: [PATCH 0394/2527] Rollback after delete record failure failing test for #2344 --- .../tests/unit/model/rollback_test.js | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/tests/unit/model/rollback_test.js b/packages/ember-data/tests/unit/model/rollback_test.js index ed0cc2d73b1..0da409758b7 100644 --- a/packages/ember-data/tests/unit/model/rollback_test.js +++ b/packages/ember-data/tests/unit/model/rollback_test.js @@ -75,6 +75,28 @@ test("a record's changes can be made if it fails to save", function() { })); }); +test("a deleted record can be rollbacked if it fails to save, record arrays are updated accordingly", function() { + expect(6); + env.adapter.deleteRecord = function(store, type, record) { + return Ember.RSVP.reject(); + }; + + var person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); + people = store.all('person'); + person.deleteRecord(); + equal(people.get('length'), 0, "a deleted record does not appear in record array anymore"); + + person.save().then(null, async(function() { + equal(person.get('isError'), true); + equal(person.get('isDeleted'), true); + person.rollback(); + equal(person.get('isDeleted'), false); + equal(person.get('isError'), false); + })).then(async(function() { + equal(people.get('length'), 1, "the underlying record array is updated accordingly in an asynchronous way"); + })); +}); + test("new record can be rollbacked", function() { var person = store.createRecord('person', { id: 1 }); @@ -90,13 +112,15 @@ test("new record can be rollbacked", function() { test("deleted record can be rollbacked", function() { var person = store.push('person', { id: 1 }); + var people = store.all('person'); person.deleteRecord(); + equal(people.get('length'), 0, "a deleted record does not appear in record array anymore"); equal(person.get('isDeleted'), true, "must be deleted"); person.rollback(); - + equal(people.get('length'), 1, "the rollbacked record should appear again in the record array"); equal(person.get('isDeleted'), false, "must not be deleted"); equal(person.get('isDirty'), false, "must not be dirty"); }); From 508878f0189ef6a6d67622d5fd5536f30c9602ce Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 13 Oct 2014 11:09:53 -0400 Subject: [PATCH 0395/2527] Add missing type information to the API docs. --- .../lib/system/active_model_adapter.js | 2 +- .../lib/system/active_model_serializer.js | 2 +- packages/ember-data/lib/ext/date.js | 3 ++- packages/ember-data/lib/serializers/rest_serializer.js | 5 +++-- packages/ember-data/lib/system/model/model.js | 2 +- packages/ember-data/lib/system/record_array_manager.js | 6 +++--- packages/ember-data/lib/system/relationships/ext.js | 6 +++--- packages/ember-data/lib/system/store.js | 2 +- packages/ember-data/lib/transforms/base.js | 8 ++++---- 9 files changed, 19 insertions(+), 17 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index c1c0b65b04e..6c75f72e93e 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -135,7 +135,7 @@ var ActiveModelAdapter = RESTAdapter.extend({ https://tools.ietf.org/html/rfc4918#section-11.2 @method ajaxError - @param jqXHR + @param {Object} jqXHR @return error */ ajaxError: function(jqXHR) { diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index 2b5d9169c12..67ca7cd4d6b 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -156,7 +156,7 @@ var ActiveModelSerializer = RESTSerializer.extend({ @method serializePolymorphicType @param {DS.Model} record @param {Object} json - @param relationship + @param {Object} relationship */ serializePolymorphicType: function(record, json, relationship) { var key = relationship.key; diff --git a/packages/ember-data/lib/ext/date.js b/packages/ember-data/lib/ext/date.js index efe37ed8764..ba35e0d72f7 100644 --- a/packages/ember-data/lib/ext/date.js +++ b/packages/ember-data/lib/ext/date.js @@ -19,7 +19,8 @@ var origParse = Date.parse, numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ]; /** @method parse - @param date + @param {Date} date + @return {Number} timestamp */ Ember.Date.parse = function (date) { var timestamp, struct, minutesOffset = 0; diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index 448931abee2..4602ff5b039 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -687,8 +687,9 @@ var RESTSerializer = JSONSerializer.extend({ ``` @method serialize - @param record - @param options + @param {subclass of DS.Model} record + @param {Object} options + @return {Object} json */ serialize: function(record, options) { return this._super.apply(this, arguments); diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index f558d14d998..e35b6ca6e36 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1052,7 +1052,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @method trigger @private - @param name + @param {String} name */ trigger: function() { var length = arguments.length; diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index 935043d0152..a09f87aa72b 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -140,9 +140,9 @@ export default Ember.Object.extend({ method is invoked when the filter is created in th first place. @method updateFilter - @param array - @param type - @param filter + @param {Array} array + @param {String} type + @param {Function} filter */ updateFilter: function(array, type, filter) { var typeMap = this.store.typeMapFor(type); diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 2e0459ab4bf..53231308e76 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -48,9 +48,9 @@ Model.reopen({ property returned by `DS.belongsTo` as the value. @method didDefineProperty - @param proto - @param key - @param value + @param {Object} proto + @param {String} key + @param {Ember.ComputedProperty} value */ didDefineProperty: function(proto, key, value) { // Check if the value being set is a computed property. diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index b42a84b1f98..63b5739d731 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1147,7 +1147,7 @@ Store = Ember.Object.extend({ @method typeMapFor @private - @param type + @param {subclass of DS.Model} type @return {Object} typeMap */ typeMapFor: function(type) { diff --git a/packages/ember-data/lib/transforms/base.js b/packages/ember-data/lib/transforms/base.js index 7e0ce26e73f..7e956b61ae5 100644 --- a/packages/ember-data/lib/transforms/base.js +++ b/packages/ember-data/lib/transforms/base.js @@ -46,8 +46,8 @@ export default Ember.Object.extend({ ``` @method serialize - @param deserialized The deserialized value - @return The serialized value + @param {mixed} deserialized The deserialized value + @return {mixed} The serialized value */ serialize: Ember.required(), @@ -64,8 +64,8 @@ export default Ember.Object.extend({ ``` @method deserialize - @param serialized The serialized value - @return The deserialized value + @param {mixed} serialized The serialized value + @return {mixed} The deserialized value */ deserialize: Ember.required() }); From e3a423bc596daefa99aaadd655febb9c1da18b4a Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 13 Oct 2014 10:32:42 -0500 Subject: [PATCH 0396/2527] update ember-local version --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 1290510f7ed..8a667c89c40 100644 --- a/bower.json +++ b/bower.json @@ -2,7 +2,7 @@ "name": "ember-data", "private": true, "dependencies": { - "ember": "~1.6.0-beta.5", + "ember": "~1.7.0", "qunit": "~1.13.0", "jquery": "~1.10.x", "handlebars": "~1.3.0" From d630cc53821ba58a0f1892e51b006099a9b59018 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 13 Oct 2014 10:47:07 -0500 Subject: [PATCH 0397/2527] beta.11 changelog and package.json updates --- CHANGELOG.md | 32 ++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aeb272af3a1..1e7886418b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,38 @@ ### Master +### Ember Data 1.0.0-beta.11 _(October 13, 2014)_ + +* Rollback after delete record failure +* warn instead of throw when resolving keys to model +* added note about coalescing and custom URLs +* pass ids through encodeURIComponent when turning them into urls +* Always remove the inverse record (if exists) from a belongsTo relationship fixes #2331 +* polyfill Ember.Map behavior +* use new Em.Map function signatures +* Refactor relationships with links +* Implemented rollbacking of implicit relationships +* Add support for rollback of relationships from deleted state +* Unwrap promises when setting a belongsTo +* Update tests on filters returning reloaded objects +* Update recordArrays when record has reloaded +* Refactor inverseFor cache +* Makes it possible to custom define inverses on only one side +* HasMany relationships now reload correctly +* Add a test for calling reload directly on the promiseProxy +* Add a test for reload on sync hasMany relationships +* Added a reload to the ManyArray +* [DOC fix] Remove misleading {inverse: null} +* Added implicit relationships +* Improve comments for the inverseFor method +* Serialize belongsTo where id===null as null +* [DOCS] Cleanup "USING EMBEDDED RECORDS" API readability +* preload the belongsTo to be available synchronously +* Add a test for an async belongsTo with buildURL +* removed private unused properties in ManyArray +* Small typo in #normalize documentation +* Do not clear own relationships when deleting records + ### Ember Data 1.0.0-beta.10 _(September 9, 2014)_ * Bring back relationship parameter for findHasMany & findBelongsTo diff --git a/package.json b/package.json index 7ef8a30d6ca..0952b8e2806 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.11+canary", + "version": "1.0.0-beta.11", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", From fd864318166b7a1b5e05ec6270def89c74e21ecd Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 13 Oct 2014 10:59:52 -0500 Subject: [PATCH 0398/2527] add beta.11 to ember addon --- lib/ember-addon/blueprints/ember-data/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ember-addon/blueprints/ember-data/index.js b/lib/ember-addon/blueprints/ember-data/index.js index ded2b37ae4d..e2eb2d6df23 100644 --- a/lib/ember-addon/blueprints/ember-data/index.js +++ b/lib/ember-addon/blueprints/ember-data/index.js @@ -8,6 +8,6 @@ module.exports = { }, afterInstall: function() { - return this.addBowerPackageToProject('ember-data', '1.0.0-beta.10'); + return this.addBowerPackageToProject('ember-data', '1.0.0-beta.11'); } }; From 4b6c4cdf627225380f75289a031773664d2a64d0 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 13 Oct 2014 11:03:17 -0500 Subject: [PATCH 0399/2527] post-release version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0952b8e2806..3e5558a924c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.11", + "version": "1.0.0-beta.12-canary", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", From 28bcabef4702f868f5e259c9a62e00d94415e208 Mon Sep 17 00:00:00 2001 From: Levi Thornton Date: Mon, 13 Oct 2014 17:54:42 -0700 Subject: [PATCH 0400/2527] [DOC] Fix typos in `ajaxSuccess` --- packages/ember-data/lib/adapters/rest_adapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index fab0d585411..175377e5abf 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -753,9 +753,9 @@ export default Adapter.extend({ 2. Your API might return errors as successful responses with status code 200 and an Errors text or object. You can return a DS.InvalidError from this hook and it will automatically reject the promise and put your record - into the invald state. + into the invalid state. - @method ajaxError + @method ajaxSuccess @param {Object} jqXHR @param {Object} jsonPayload @return {Object} jqXHR From 7dc1a25362c2bd81e196cdf83fa627dbbbe5a22a Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Tue, 14 Oct 2014 11:12:18 +0900 Subject: [PATCH 0401/2527] [DOC] Update usage of AMS `include` option is renamed as `embed_in_root` in current stable version 0.9. * https://github.com/rails-api/active_model_serializers/blob/0-9-stable/lib/active_model/serializer/association.rb#L11 --- packages/activemodel-adapter/lib/system/active_model_adapter.js | 2 +- .../activemodel-adapter/lib/system/active_model_serializer.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index 6c75f72e93e..d1a5d33f6d8 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -16,7 +16,7 @@ var decamelize = Ember.String.decamelize, It has been designed to work out of the box with the [active_model_serializers](http://github.com/rails-api/active_model_serializers) Ruby gem. This Adapter expects specific settings using ActiveModel::Serializers, - `embed :ids, include: true` which sideloads the records. + `embed :ids, embed_in_root: true` which sideloads the records. This adapter extends the DS.RESTAdapter by making consistent use of the camelization, decamelization and pluralization methods to normalize the serialized JSON into a diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index 67ca7cd4d6b..6fdf40d848f 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -16,7 +16,7 @@ var get = Ember.get, It has been designed to work out of the box with the [active_model_serializers](http://github.com/rails-api/active_model_serializers) Ruby gem. This Serializer expects specific settings using ActiveModel::Serializers, - `embed :ids, include: true` which sideloads the records. + `embed :ids, embed_in_root: true` which sideloads the records. This serializer extends the DS.RESTSerializer by making consistent use of the camelization, decamelization and pluralization methods to From 824ac3255cffcb249981f8bc33ff1c2a688b29b7 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Wed, 15 Oct 2014 15:36:29 +0900 Subject: [PATCH 0402/2527] Remove unnecessary `Function#call` --- packages/ember-data/lib/system/record_arrays/many_array.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 6374941d088..5a5cae1e483 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -132,7 +132,7 @@ export default RecordArray.extend({ Ember.assert("You cannot add '" + type.typeKey + "' records to this polymorphic relationship.", !get(this, 'isPolymorphic')); - record = store.createRecord.call(store, type, hash); + record = store.createRecord(type, hash); this.pushObject(record); return record; From d3ca0772475fc43d2fd69a0a4be485312cfc1874 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Wed, 15 Oct 2014 15:42:15 +0900 Subject: [PATCH 0403/2527] [DOC] Fix to apply js doc style to DS.ManyArray --- .../ember-data/lib/system/record_arrays/many_array.js | 8 +++++--- packages/ember-data/lib/system/relationships/ext.js | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 6374941d088..6dd5647cbc6 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -55,17 +55,19 @@ export default RecordArray.extend({ */ isPolymorphic: false, - // LOADING STATE + /** + The loading state of this array + @property {Boolean} isLoaded + */ isLoaded: false, /** The relationship which manages this array. - @property {DS.Model} owner + @property {ManyRelationship} relationship @private */ - relationship: null, diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 53231308e76..9689b4639bc 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -112,7 +112,7 @@ Model.reopenClass({ return Object.create(null); }), - /* + /** Find the relationship which is the inverse of the one asked for. For example, if you define models like this: From 898305138fa9ab928fd95b69662ad48b34c820f8 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Wed, 15 Oct 2014 15:43:15 +0900 Subject: [PATCH 0404/2527] [DOC] Fix usage of DS.Model.fields `DS.Model.fields` is a `Ember.Map`. Its behavior changed at 2eb1c971 . --- packages/ember-data/lib/system/relationships/ext.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 9689b4639bc..44b6555184d 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -450,7 +450,7 @@ Model.reopenClass({ }); var fields = Ember.get(App.Blog, 'fields'); - fields.forEach(function(field, kind) { + fields.forEach(function(kind, field) { console.log(field, kind); }); From 82ddfd90b3d08c49f5899887c07b484534b8bfba Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 15 Oct 2014 10:04:43 -0400 Subject: [PATCH 0405/2527] Make dependencies clearer. This is mostly just for easier discovery/understanding for passers by looking at the `bower.json` in the root of the repo. The actual `bower.json` that we put in components/ember-data is correct already. --- bower.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bower.json b/bower.json index 8a667c89c40..a7c79f8cd77 100644 --- a/bower.json +++ b/bower.json @@ -2,12 +2,12 @@ "name": "ember-data", "private": true, "dependencies": { - "ember": "~1.7.0", - "qunit": "~1.13.0", - "jquery": "~1.10.x", - "handlebars": "~1.3.0" + "ember": "~1.7.0" }, "devDependencies": { + "qunit": "~1.13.0", + "jquery": "~1.10.x", + "handlebars": "~1.3.0", "loader.js": "~1.0.0", "ember-inflector": "https://github.com/stefanpenner/ember-inflector.git#v1.1.0", "es5-shim": "~4.0.3" From 4884933497adb4894a3621ad8726cc63c7d910d2 Mon Sep 17 00:00:00 2001 From: Andrew Hacking Date: Thu, 16 Oct 2014 11:53:25 +1000 Subject: [PATCH 0406/2527] Refactored InvalidError handling into a serializer concern. --- .../lib/system/active_model_adapter.js | 14 +----- .../integration/active_model_adapter_test.js | 4 +- .../ember-data/lib/adapters/rest_adapter.js | 10 ++++- .../lib/serializers/json_serializer.js | 45 +++++++++++++++++++ packages/ember-data/lib/system/adapter.js | 6 ++- packages/ember-data/lib/system/store.js | 4 +- 6 files changed, 64 insertions(+), 19 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index d1a5d33f6d8..0046c5d197b 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -6,7 +6,6 @@ import {pluralize} from "ember-inflector"; @module ember-data */ -var forEach = Ember.EnumerableUtils.forEach; var decamelize = Ember.String.decamelize, underscore = Ember.String.underscore; @@ -142,18 +141,7 @@ var ActiveModelAdapter = RESTAdapter.extend({ var error = this._super(jqXHR); if (jqXHR && jqXHR.status === 422) { - var response = Ember.$.parseJSON(jqXHR.responseText), - errors = {}; - - if (response.errors !== undefined) { - var jsonErrors = response.errors; - - forEach(Ember.keys(jsonErrors), function(key) { - errors[Ember.String.camelize(key)] = jsonErrors[key]; - }); - } - - return new InvalidError(errors); + return new InvalidError(Ember.$.parseJSON(jqXHR.responseText)); } else { return error; } diff --git a/packages/activemodel-adapter/tests/integration/active_model_adapter_test.js b/packages/activemodel-adapter/tests/integration/active_model_adapter_test.js index 14d7c2116ce..c2724325083 100644 --- a/packages/activemodel-adapter/tests/integration/active_model_adapter_test.js +++ b/packages/activemodel-adapter/tests/integration/active_model_adapter_test.js @@ -21,7 +21,7 @@ test('buildURL - decamelizes names', function() { }); test('ajaxError - returns invalid error if 422 response', function() { - var error = new DS.InvalidError({ name: "can't be blank" }); + var error = new DS.InvalidError({ errors: { name: "can't be blank" } }); var jqXHR = { status: 422, @@ -32,7 +32,7 @@ test('ajaxError - returns invalid error if 422 response', function() { }); test('ajaxError - invalid error has camelized keys', function() { - var error = new DS.InvalidError({ firstName: "can't be blank" }); + var error = new DS.InvalidError({ errors: { firstName: "can't be blank" } }); var jqXHR = { status: 422, diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 175377e5abf..c020c9aefb2 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -697,19 +697,25 @@ export default Adapter.extend({ }, /** - Takes an ajax response, and returns a relevant error. + Takes an ajax response, and returns an error payload. Returning a `DS.InvalidError` from this method will cause the record to transition into the `invalid` state and make the `errors` object available on the record. + This function should return the entire payload as received from the + server. Error object extraction and normalization of model errors + should be performed by `extractErrors` on the serializer. + + Example + ```javascript App.ApplicationAdapter = DS.RESTAdapter.extend({ ajaxError: function(jqXHR) { var error = this._super(jqXHR); if (jqXHR && jqXHR.status === 422) { - var jsonErrors = Ember.$.parseJSON(jqXHR.responseText)["errors"]; + var jsonErrors = Ember.$.parseJSON(jqXHR.responseText); return new DS.InvalidError(jsonErrors); } else { diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 552b100a7bc..ab479634332 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -260,6 +260,16 @@ export default Ember.Object.extend({ delete hash[primaryKey]; }, + /** + @method normalizeErrors + @private + */ + normalizeErrors: function(type, hash) { + this.normalizeId(hash); + this.normalizeAttributes(type, hash); + this.normalizeRelationships(type, hash); + }, + /** Looks up the property key that was set by the custom `attr` mapping passed to the serializer. @@ -970,6 +980,41 @@ export default Ember.Object.extend({ } }, + /** + `extractErrors` is used to extract model errors when a call is made + to `DS.Model#save` which fails with an InvalidError`. By default + Ember Data expects error information to be located on the `errors` + property of the payload object. + + Example + + ```javascript + App.PostSerializer = DS.JSONSerializer.extend({ + extractErrors: function(store, type, payload, id) { + if (payload && typeof payload === 'object' && payload._problems) { + payload = payload._problems; + this.normalizeErrors(type, payload); + } + return payload; + } + }); + ``` + + @method extractErrors + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @param {String or Number} id + @return {Object} json The deserialized errors + */ + extractErrors: function(store, type, payload, id) { + if (payload && typeof payload === 'object' && payload.errors) { + payload = payload.errors; + this.normalizeErrors(type, payload); + } + return payload; + }, + /** `keyForAttribute` can be used to define rules for how to convert an attribute name in your model to a key in your JSON. diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index bc65550a500..8aabb4ffb28 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -23,6 +23,10 @@ var errorProps = [ transition to the `invalid` state and the errors will be set to the `errors` property on the record. + This function should return the entire payload as received from the + server. Error object extraction and normalization of model errors + should be performed by `extractErrors` on the serializer. + Example ```javascript @@ -31,7 +35,7 @@ var errorProps = [ var error = this._super(jqXHR); if (jqXHR && jqXHR.status === 422) { - var jsonErrors = Ember.$.parseJSON(jqXHR.responseText)["errors"]; + var jsonErrors = Ember.$.parseJSON(jqXHR.responseText); return new DS.InvalidError(jsonErrors); } else { return error; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 63b5739d731..c1514a86d1f 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1869,7 +1869,9 @@ function _commit(adapter, store, operation, record) { return record; }, function(reason) { if (reason instanceof InvalidError) { - store.recordWasInvalid(record, reason.errors); + var errors = serializer.extractErrors(store, type, reason.errors, get(record, 'id')); + store.recordWasInvalid(record, errors); + reason = new InvalidError(errors); } else { store.recordWasError(record, reason); } From 564899a2fbca76005e111e63e62d2b025aa9c785 Mon Sep 17 00:00:00 2001 From: grishace Date: Thu, 16 Oct 2014 13:25:19 -0600 Subject: [PATCH 0407/2527] Fixing an issue when grouping requests could result in URL longer than configured length. --- .../ember-data/lib/adapters/rest_adapter.js | 18 ++++--- packages/ember-data/lib/system/adapter.js | 1 + .../group_records_for_find_many_test.js | 49 +++++++++++++++++++ 3 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 packages/ember-data/tests/unit/adapters/rest_adapter/group_records_for_find_many_test.js diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index c020c9aefb2..35a916cf27c 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -585,7 +585,7 @@ export default Adapter.extend({ }, _stripIDFromURL: function(store, record) { - var type = store.modelFor(record); + var type = record.constructor; var url = this.buildURL(type.typeKey, record.get('id'), record); var expandedURL = url.split('/'); @@ -602,6 +602,11 @@ export default Adapter.extend({ return expandedURL.join('/'); }, + /** + http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers + */ + maxUrlLength: 2048, + /** Organize records into groups, each of which is to be passed to separate calls to `findMany`. @@ -619,6 +624,7 @@ export default Adapter.extend({ and `/posts/2/comments/3` @method groupRecordsForFindMany + @param {DS.Store} store @param {Array} records @return {Array} an array of arrays of records, each of which is to be loaded separately by `findMany`. @@ -626,19 +632,20 @@ export default Adapter.extend({ groupRecordsForFindMany: function (store, records) { var groups = MapWithDefault.create({defaultValue: function(){return [];}}); var adapter = this; + var maxUrlLength = this.maxUrlLength; forEach.call(records, function(record){ var baseUrl = adapter._stripIDFromURL(store, record); groups.get(baseUrl).push(record); }); - function splitGroupToFitInUrl(group, maxUrlLength) { + function splitGroupToFitInUrl(group, maxUrlLength, paramNameLength) { var baseUrl = adapter._stripIDFromURL(store, group[0]); var idsSize = 0; var splitGroups = [[]]; forEach.call(group, function(record) { - var additionalLength = '&ids[]='.length + record.get('id.length'); + var additionalLength = encodeURIComponent(record.get('id')).length + paramNameLength; if (baseUrl.length + idsSize + additionalLength >= maxUrlLength) { idsSize = 0; splitGroups.push([]); @@ -655,9 +662,8 @@ export default Adapter.extend({ var groupsArray = []; groups.forEach(function(group, key){ - // http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers - var maxUrlLength = 2048; - var splitGroups = splitGroupToFitInUrl(group, maxUrlLength); + var paramNameLength = '&ids%5B%5D='.length; + var splitGroups = splitGroupToFitInUrl(group, maxUrlLength, paramNameLength); forEach.call(splitGroups, function(splitGroup) { groupsArray.push(splitGroup); diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 8aabb4ffb28..837b58055e6 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -450,6 +450,7 @@ var Adapter = Ember.Object.extend({ The default implementation returns the records as a single group. @method groupRecordsForFindMany + @param {DS.Store} store @param {Array} records @return {Array} an array of arrays of records, each of which is to be loaded separately by `findMany`. diff --git a/packages/ember-data/tests/unit/adapters/rest_adapter/group_records_for_find_many_test.js b/packages/ember-data/tests/unit/adapters/rest_adapter/group_records_for_find_many_test.js new file mode 100644 index 00000000000..9fd538239a4 --- /dev/null +++ b/packages/ember-data/tests/unit/adapters/rest_adapter/group_records_for_find_many_test.js @@ -0,0 +1,49 @@ +var GroupsAdapter, Store; +var maxLength = -1; +var lengths = []; + +module("unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAdapter#groupRecordsForFindMany", { + setup: function() { + GroupsAdapter = DS.RESTAdapter.extend({ + + coalesceFindRequests: true, + + find: function(store, type, id) { + return Ember.RSVP.Promise.resolve({ id: id }); + }, + + ajax: function(url, type, options) { + var queryString = options.data.ids.map(function(i) { + return encodeURIComponent('ids[]') + '=' + encodeURIComponent(i); + }).join('&'); + var fullUrl = url + '?' + queryString; + + maxLength = this.get('maxUrlLength'); + lengths.push(fullUrl.length); + + return Ember.RSVP.Promise.resolve({ 'testRecords' : [] }); + } + + }); + + Store = createStore({ + adapter: GroupsAdapter, + testRecord: DS.Model.extend() + }); + + } +}); + +test('groupRecordsForFindMany - findMany', function() { + + Ember.run(function() { + for(var i = 1; i <= 1024; i++) { + Store.find('testRecord', i); + } + }); + + ok(lengths.every(function(len) { + return len <= maxLength; + }), "Some URLs are longer than " + maxLength + " chars"); + +}); From 035f95a7e0fa2ce7ff64338c3efd83c54fbf6b57 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Mon, 13 Oct 2014 13:18:17 +0200 Subject: [PATCH 0408/2527] Nicer errors when pushing belongsTo/hasMany with invalid values --- packages/ember-data/lib/system/store.js | 5 ++- .../ember-data/tests/unit/store/push_test.js | 35 ++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index c1514a86d1f..3035376d281 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1644,6 +1644,7 @@ function deserializeRecordId(store, data, key, relationship, id) { if (isNone(id) || id instanceof Model) { return; } + Ember.assert("A " + relationship.parentType + " record was pushed into the store with the value of " + key + " being " + Ember.inspect(id) + ", but " + key + " is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.", !Ember.isArray(id)); var type; @@ -1665,9 +1666,11 @@ function typeFor(relationship, key, data) { } function deserializeRecordIds(store, data, key, relationship, ids) { - if (!Ember.isArray(ids)) { + if (isNone(ids)) { return; } + + Ember.assert("A " + relationship.parentType + " record was pushed into the store with the value of " + key + " being '" + Ember.inspect(ids) + "', but " + key + " is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.", Ember.isArray(ids)); for (var i=0, l=ids.length; i Date: Fri, 17 Oct 2014 17:45:26 +0400 Subject: [PATCH 0409/2527] use indexOf polyfill --- packages/ember-data/lib/system/record_array_manager.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index bf1a06e6c94..855d98c6438 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -14,6 +14,7 @@ import { } from "ember-data/system/map"; var get = Ember.get; var forEach = Ember.EnumerableUtils.forEach; +var indexOf = Ember.EnumerableUtils.indexOf; /** @class RecordArrayManager @@ -273,7 +274,7 @@ export default Ember.Object.extend({ */ unregisterFilteredRecordArray: function(array) { var recordArrays = this.filteredRecordArrays.get(array.type); - var index = recordArrays.indexOf(array); + var index = indexOf(recordArrays, array); recordArrays.splice(index, 1); }, From cb3a3a5088c520833ccf84c9861f9f535b2e1187 Mon Sep 17 00:00:00 2001 From: Vlad Filippov Date: Sat, 18 Oct 2014 22:07:48 -0400 Subject: [PATCH 0410/2527] Fixes method_ajaxError link Currently links to http://emberjs.com/api/data/classes/api/data/classes/DS.RESTAdapter.html#method_ajaxError Please review. --- packages/ember-data/lib/system/model/errors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index 9f53fb7d9e3..8e26ca78e4f 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -17,7 +17,7 @@ import { `DS.Errors`. This can be used to display validation error messages returned from the server when a `record.save()` rejects. This works automatically with `DS.ActiveModelAdapter`, but you - can implement [ajaxError](api/data/classes/DS.RESTAdapter.html#method_ajaxError) + can implement [ajaxError](/api/data/classes/DS.RESTAdapter.html#method_ajaxError) in other adapters as well. For Example, if you had an `User` model that looked like this: From 10a3fd0198ba5beb2f97891be513df7417260292 Mon Sep 17 00:00:00 2001 From: Justin Bull Date: Mon, 20 Oct 2014 13:58:13 -0400 Subject: [PATCH 0411/2527] Fix ajaxSuccess docblock return value --- packages/ember-data/lib/adapters/rest_adapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 35a916cf27c..9e1f8ea01c0 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -770,7 +770,7 @@ export default Adapter.extend({ @method ajaxSuccess @param {Object} jqXHR @param {Object} jsonPayload - @return {Object} jqXHR + @return {Object} jsonPayload */ ajaxSuccess: function(jqXHR, jsonPayload) { From 571c032a3c3f0135489ca00a91dfc2f5bb71ceca Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 20 Oct 2014 15:53:08 -0500 Subject: [PATCH 0412/2527] disable canary until we figure out how to load Hbs canary recently introduced Handlebars 2.0, and that's why canary is currently failing. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 29b781382c3..bf9dbc38cae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ script: - npm run-script testem-local - npm run-script testem-stable - npm run-script testem-beta - - npm run-script testem-canary + # - npm run-script testem-canary after_success: - npm run-script publish-build - "./bin/bower-ember-data-build" From b303387aa43a34d99678aed3176a86deac074d6a Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 21 Oct 2014 13:57:44 -0500 Subject: [PATCH 0413/2527] load handlebars 2.0 for canary --- .travis.yml | 2 +- tests/index.html | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index bf9dbc38cae..29b781382c3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ script: - npm run-script testem-local - npm run-script testem-stable - npm run-script testem-beta - # - npm run-script testem-canary + - npm run-script testem-canary after_success: - npm run-script publish-build - "./bin/bower-ember-data-build" diff --git a/tests/index.html b/tests/index.html index 7e3d1a63451..f190c624249 100644 --- a/tests/index.html +++ b/tests/index.html @@ -7,7 +7,7 @@ - + + From 59b1821af7fd09e636145fcb7bc4a9caecbcf2a7 Mon Sep 17 00:00:00 2001 From: Kate Gengler Date: Wed, 22 Oct 2014 10:29:55 -0400 Subject: [PATCH 0414/2527] Update model.js Add documentation of the fact that reloading a model will fulfill with the reloaded model. --- packages/ember-data/lib/system/model/model.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index e35b6ca6e36..72ae90e8f96 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -969,7 +969,9 @@ var Model = Ember.Object.extend(Ember.Evented, { App.ModelViewRoute = Ember.Route.extend({ actions: { reload: function() { - this.controller.get('model').reload(); + this.controller.get('model').reload().then(function(model) { + // do something with the reloaded model + }); } } }); From 408112f097710381d22bbc3886aba14267f61092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Grosjean?= Date: Wed, 22 Oct 2014 23:05:59 +0300 Subject: [PATCH 0415/2527] Update explanation on how to run tests in browser --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 053333b5bf0..8774703845b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,7 +63,7 @@ We love pull requests. Here's a quick guide: 2. Run the tests. We only take pull requests with passing tests, and it's great to know that you have a clean slate, see notes on how to run unit tests [here](https://github.com/emberjs/data#how-to-run-unit-tests). (To see tests in the browser, -run `grunt dev` and open `http://localhost:9997/tests/?package=all`.) +run `npm start` and open `http://localhost:4200`.) 3. Add a test for your change. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, we need From bd612bdc69c773f17752e3a28911fc9d3994501c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Grosjean?= Date: Thu, 23 Oct 2014 00:05:12 +0300 Subject: [PATCH 0416/2527] Add `createRecord` to PromiseArray so it proxies to ManyArray --- .../ember-data/lib/system/promise_proxies.js | 7 +++++ .../relationships/has_many_test.js | 26 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/packages/ember-data/lib/system/promise_proxies.js b/packages/ember-data/lib/system/promise_proxies.js index 286882a1fc9..9207efa2b54 100644 --- a/packages/ember-data/lib/system/promise_proxies.js +++ b/packages/ember-data/lib/system/promise_proxies.js @@ -80,6 +80,7 @@ var promiseArray = function(promise, label) { to the underlying manyArray. Right now we proxy: `reload()` + `createRecord()` */ var PromiseManyArray = PromiseArray.extend({ @@ -87,6 +88,12 @@ var PromiseManyArray = PromiseArray.extend({ //I don't think this should ever happen right now, but worth guarding if we refactor the async relationships Ember.assert('You are trying to reload an async manyArray before it has been created', get(this, 'content')); return get(this, 'content').reload(); + }, + + createRecord: function() { + var content = get(this, 'content'); + content.createRecord.apply(content, arguments); + return this; } }); diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 8189026b744..858125b3a28 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -349,6 +349,32 @@ test("A hasMany relationship can be directly reloaded if it was fetched via ids" })); }); +test("PromiseArray proxies createRecord to its ManyArray once hasMany is loaded", function() { + expect(3); + + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + env.adapter.findHasMany = function(store, record, link, relationship) { + return Ember.RSVP.resolve([ + { id: 1, body: "First" }, + { id: 2, body: "Second" } + ]); + }; + + var post = env.store.push('post', {id:1, links: {comments: 'someLink'}}); + + post.get('comments').then(async(function(comments) { + equal(comments.get('isLoaded'), true, "comments are loaded"); + equal(comments.get('length'), 2, "comments have 2 length"); + + post.get('comments').createRecord().then(async(function() { + equal(comments.get('length'), 3, "comments have 3 length, including new record"); + })); + })); +}); + test("An updated `links` value should invalidate a relationship cache", function() { expect(8); Post.reopen({ From 2538b96a9dd207357a5e70561a53554a9613f31e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Grosjean?= Date: Thu, 23 Oct 2014 02:05:19 +0300 Subject: [PATCH 0417/2527] createRecord on PromiseManyArray returns the new record instead of a Promise --- packages/ember-data/lib/system/promise_proxies.js | 3 +-- .../tests/integration/relationships/has_many_test.js | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/ember-data/lib/system/promise_proxies.js b/packages/ember-data/lib/system/promise_proxies.js index 9207efa2b54..397f89c18e8 100644 --- a/packages/ember-data/lib/system/promise_proxies.js +++ b/packages/ember-data/lib/system/promise_proxies.js @@ -92,8 +92,7 @@ var PromiseManyArray = PromiseArray.extend({ createRecord: function() { var content = get(this, 'content'); - content.createRecord.apply(content, arguments); - return this; + return content.createRecord.apply(content, arguments); } }); diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 858125b3a28..130a32544cd 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -349,8 +349,8 @@ test("A hasMany relationship can be directly reloaded if it was fetched via ids" })); }); -test("PromiseArray proxies createRecord to its ManyArray once hasMany is loaded", function() { - expect(3); +test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loaded", function() { + expect(4); Post.reopen({ comments: DS.hasMany('comment', { async: true }) @@ -369,9 +369,9 @@ test("PromiseArray proxies createRecord to its ManyArray once hasMany is loaded" equal(comments.get('isLoaded'), true, "comments are loaded"); equal(comments.get('length'), 2, "comments have 2 length"); - post.get('comments').createRecord().then(async(function() { - equal(comments.get('length'), 3, "comments have 3 length, including new record"); - })); + var newComment = post.get('comments').createRecord({body: 'Third'}); + equal(newComment.get('body'), 'Third', "new comment is returned"); + equal(comments.get('length'), 3, "comments have 3 length, including new record"); })); }); From 7d9911d805fc7c431eb63c481677af0c2ac01d6e Mon Sep 17 00:00:00 2001 From: Miguel Camba Date: Fri, 24 Oct 2014 23:25:16 +0100 Subject: [PATCH 0418/2527] Use git-repo-version to generate version number with SHA Ember now uses the same thing (but with only the first 8 characters of the SHA) --- Brocfile.js | 2 +- lib/utilities/ember-data-version.js | 37 ----------------------------- package.json | 3 ++- 3 files changed, 3 insertions(+), 39 deletions(-) delete mode 100644 lib/utilities/ember-data-version.js diff --git a/Brocfile.js b/Brocfile.js index 49bf6571aa0..ba43ff851ff 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -11,7 +11,7 @@ var moveFile = require('broccoli-file-mover'); var wrap = require('broccoli-wrap'); var jshint = require('broccoli-jshint'); var defeatureify = require('broccoli-defeatureify'); -var version = require('./lib/utilities/ember-data-version')(); +var version = require('git-repo-version')(10); var renderTemplate = require('broccoli-render-template'); var yuidoc = require('broccoli-yuidoc'); var replace = require('broccoli-string-replace'); diff --git a/lib/utilities/ember-data-version.js b/lib/utilities/ember-data-version.js deleted file mode 100644 index 3f5a776190f..00000000000 --- a/lib/utilities/ember-data-version.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -var fs = require('fs'); -var path = require('path'); - -module.exports = function () { - var packageVersion = require('../../package.json').version; - var output = [packageVersion]; - var gitPath = path.join(__dirname, '..','..','.git'); - var headFilePath = path.join(gitPath, 'HEAD'); - - if (packageVersion.indexOf('+') > -1) { - try { - if (fs.existsSync(headFilePath)) { - var headFile = fs.readFileSync(headFilePath, {encoding: 'utf8'}); - var branchName = headFile.split('/').slice(-1)[0].trim(); - var refPath = headFile.split(' ')[1]; - var branchSHA; - - if (refPath) { - var branchPath = path.join(gitPath, refPath.trim()); - branchSHA = fs.readFileSync(branchPath); - } else { - branchSHA = branchName; - } - - output.push(branchSHA.slice(0,10)); - } - } catch (err) { - console.error(err.stack); - } - - return output.join('.'); - } else { - return packageVersion; - } -}; diff --git a/package.json b/package.json index 3e5558a924c..44cd7a17d7a 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "ember-cli": "0.0.43", "ember-publisher": "0.0.6", "testem": "^0.6.19", - "yuidocjs": "~0.3.46" + "yuidocjs": "~0.3.46", + "git-repo-version": "0.0.2" } } From 1a9c7530c2b0ef3d9ee1ae7680ed9840460c2f7b Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Sun, 26 Oct 2014 21:37:26 +0900 Subject: [PATCH 0419/2527] Extract function to proxy `PromiseManyArray`'s method to `content` --- packages/ember-data/lib/system/promise_proxies.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/promise_proxies.js b/packages/ember-data/lib/system/promise_proxies.js index 397f89c18e8..a3d556c1225 100644 --- a/packages/ember-data/lib/system/promise_proxies.js +++ b/packages/ember-data/lib/system/promise_proxies.js @@ -83,6 +83,13 @@ var promiseArray = function(promise, label) { `createRecord()` */ +function proxyToContent(method) { + return function() { + var content = get(this, 'content'); + return content[method].apply(content, arguments); + }; +} + var PromiseManyArray = PromiseArray.extend({ reload: function() { //I don't think this should ever happen right now, but worth guarding if we refactor the async relationships @@ -90,10 +97,7 @@ var PromiseManyArray = PromiseArray.extend({ return get(this, 'content').reload(); }, - createRecord: function() { - var content = get(this, 'content'); - return content.createRecord.apply(content, arguments); - } + createRecord: proxyToContent('createRecord') }); var promiseManyArray = function(promise, label) { From 1b3176e3785407a1cfcde6297f5f061816ee1f40 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Sun, 26 Oct 2014 22:19:18 +0900 Subject: [PATCH 0420/2527] `PromiseManyArray` proxies `Ember.Evented` methods to its `content` --- .../ember-data/lib/system/promise_proxies.js | 17 ++++++- .../relationships/has_many_test.js | 45 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/promise_proxies.js b/packages/ember-data/lib/system/promise_proxies.js index a3d556c1225..ff9b8cde9b5 100644 --- a/packages/ember-data/lib/system/promise_proxies.js +++ b/packages/ember-data/lib/system/promise_proxies.js @@ -81,6 +81,11 @@ var promiseArray = function(promise, label) { Right now we proxy: `reload()` `createRecord()` + `on()` + `one()` + `trigger()` + `off()` + `has()` */ function proxyToContent(method) { @@ -97,7 +102,17 @@ var PromiseManyArray = PromiseArray.extend({ return get(this, 'content').reload(); }, - createRecord: proxyToContent('createRecord') + createRecord: proxyToContent('createRecord'), + + on: proxyToContent('on'), + + one: proxyToContent('one'), + + trigger: proxyToContent('trigger'), + + off: proxyToContent('off'), + + has: proxyToContent('has') }); var promiseManyArray = function(promise, label) { diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 130a32544cd..d1ea11cb0a0 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -375,6 +375,51 @@ test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loa })); }); +test("PromiseArray proxies evented methods to its ManyArray", function() { + expect(6); + + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + env.adapter.findHasMany = function(store, record, link, relationship) { + return Ember.RSVP.resolve([ + { id: 1, body: "First" }, + { id: 2, body: "Second" } + ]); + }; + + var post = env.store.push('post', {id:1, links: {comments: 'someLink'}}); + + var comments = post.get('comments'); + + comments.on('on-event', function() { + ok(true); + }); + + comments.trigger('on-event'); + + equal(comments.has('on-event'), true); + + comments.on('off-event', function() { + ok(false); + }); + + comments.off('off-event'); + + equal(comments.has('off-event'), false); + + comments.one('one-event', function() { + ok(true); + }); + + equal(comments.has('one-event'), true); + + comments.trigger('one-event'); + + equal(comments.has('one-event'), false); +}); + test("An updated `links` value should invalidate a relationship cache", function() { expect(8); Post.reopen({ From e4ae5c6d306ac735a64f4c4998cf61cd21792038 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 29 Oct 2014 00:21:03 +0100 Subject: [PATCH 0421/2527] Improve warns() test helper to better handle multiple calls --- tests/ember_configuration.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ember_configuration.js b/tests/ember_configuration.js index 764e1d5bb0d..b3c09de0ca8 100644 --- a/tests/ember_configuration.js +++ b/tests/ember_configuration.js @@ -216,11 +216,11 @@ var warnWasCalled = false; var oldWarn = Ember.warn; Ember.warn = function Ember_assertWarning(message, test){ - warnWasCalled = true; - if (regex && !test) { - ok(regex.test(message), 'Ember.warn called with expected message, but was called with ' + message); - } else if (test) { - ok(false, "Expected warn to receive a falsy test, but got a truthy test"); + if (!test) { + warnWasCalled = true; + if (regex) { + ok(regex.test(message), 'the call to Ember.warn got an unexpected message: ' + message); + } } }; try { From a590c9597315adc97c219b84dbcc8a3065c886c3 Mon Sep 17 00:00:00 2001 From: Nick Dreckshage Date: Thu, 5 Jun 2014 22:48:11 -0400 Subject: [PATCH 0422/2527] failing test for #2007 --- .../integration/adapter/rest_adapter_test.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index d5c3c2330b1..2456c1e0f64 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -369,6 +369,28 @@ test("create - a record on the many side of a hasMany relationship should update })); }); +test("create - sideloaded belongsTo relationships are both marked as loaded", function () { + expect(4); + var post, comment; + + Post.reopen({ comment: DS.belongsTo('comment') }); + Comment.reopen({ post: DS.belongsTo('post') }); + + post = store.createRecord('post', { name: "man" }); + + ajaxResponse({ + posts: [{ id: 1, comment: 1, name: "marked" }], + comments: [{ id: 1, post: 1, name: "Comcast is a bargain" }] + }); + + post.save().then(async(function(record) { + equal(store.getById('post', 1).get('comment.isLoaded'), true, "post's comment isLoaded (via store)"); + equal(store.getById('comment', 1).get('post.isLoaded'), true, "comment's post isLoaded (via store)"); + equal(record.get('comment.isLoaded'), true, "post's comment isLoaded (via record)"); + equal(record.get('comment.post.isLoaded'), true, "post's comment's post isLoaded (via record)"); + })); +}); + test("create - relationships are not duplicated", function() { var post, comment; From d849b10b900c13b9ab817aa5f8f2181d9298c3c6 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 29 Oct 2014 01:41:28 +0100 Subject: [PATCH 0423/2527] Don't allow empty strings as id in push/update --- packages/ember-data/lib/system/store.js | 6 ++---- .../ember-data/tests/unit/store/push_test.js | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 3035376d281..e66784c992f 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1294,8 +1294,8 @@ Store = Ember.Object.extend({ // _partial is an internal param used by `update`. // If passed, it means that the data should be // merged into the existing data, not replace it. - Ember.assert("Expected an object as `data` in a call to push for " + typeName + " , but was " + data, Ember.typeOf(data) === 'object'); - Ember.assert("You must include an `id` for " + typeName + " in an object passed to `push`", data.id != null); + Ember.assert("Expected an object as `data` in a call to `push`/`update` for " + typeName + " , but was " + data, Ember.typeOf(data) === 'object'); + Ember.assert("You must include an `id` for " + typeName + " in an object passed to `push`/`update`", data.id != null && data.id !== ''); var type = this.modelFor(typeName); @@ -1436,8 +1436,6 @@ Store = Ember.Object.extend({ @return {DS.Model} the record that was updated. */ update: function(type, data) { - Ember.assert("You must include an `id` for " + type + " in a hash passed to `update`", data.id != null); - return this.push(type, data, true); }, diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index d10534b1b76..e397e750611 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -391,6 +391,22 @@ test('calling push with hasMany relationship the value must be an array', functi }); }); +test('calling push with missing or invalid `id` throws assertion error', function(){ + var invalidValues = [ + {}, + { id: null }, + { id: '' }, + ]; + + expect(invalidValues.length); + + Ember.EnumerableUtils.forEach(invalidValues, function(invalidValue){ + throws(function() { + store.push('person', invalidValue); + }, /You must include an `id`/); + }); +}); + test('calling push with belongsTo relationship the value must not be an array', function(){ throws(function() { store.push('phone-number', { id: 1, person: [1] }); From e7efd5738f9c2468d48034c16bc0321bc9d1f077 Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 29 Oct 2014 07:41:02 +0200 Subject: [PATCH 0424/2527] Relationship rollback from created state --- .../ember-data/lib/system/model/states.js | 1 + .../lib/system/relationships/relationship.js | 4 +- .../relationships/many_to_many_test.js | 24 +++++++++ .../relationships/one_to_many_test.js | 50 ++++++++++++++++++- .../relationships/one_to_one_test.js | 22 +++++++- 5 files changed, 98 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index a6389c824a2..eb62dc217bc 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -397,6 +397,7 @@ var createdState = dirtyState({ }); createdState.uncommitted.rolledBack = function(record) { + record.clearRelationships(); record.transitionTo('deleted.saved'); }; diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index 803f851b79e..4e7611524b3 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -249,7 +249,9 @@ ManyRelationship.prototype.getRecords = function() { } else { Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.constructor.typeKey + "' with id " + this.record.get('id') + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); - this.manyArray.set('isLoaded', true); + if (!this.manyArray.get('isDestroyed')) { + this.manyArray.set('isLoaded', true); + } return this.manyArray; } }; diff --git a/packages/ember-data/tests/integration/relationships/many_to_many_test.js b/packages/ember-data/tests/integration/relationships/many_to_many_test.js index 430f92d8d2b..ca359724513 100644 --- a/packages/ember-data/tests/integration/relationships/many_to_many_test.js +++ b/packages/ember-data/tests/integration/relationships/many_to_many_test.js @@ -176,3 +176,27 @@ test("Deleting a record that has a hasMany relationship removes it from the othe equal(account.get('users.length'), 1, 'Users are still there'); equal(user.get('accounts.length'), 1, 'Account got rolledback correctly into the user'); }); + +test("Rollbacking a created record that has a ManyToMany relationship works correctly - async", function () { + var user = store.push('user', {id:1, name: 'Stanley'}); + var topic = store.createRecord('topic'); + user.get('topics').then(async(function(fetchedTopics) { + fetchedTopics.pushObject(topic); + topic.rollback(); + topic.get('users').then(async(function(fetchedUsers) { + equal(fetchedUsers.get('length'), 0, 'Users got removed'); + })); + user.get('topics').then(async(function(fetchedTopics) { + equal(fetchedTopics.get('length'), 0, 'Topics got removed'); + })); + })); +}); + +test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function () { + var account = store.push('account', {id:2 , state: 'lonely'}); + var user = store.createRecord('user'); + account.get('users').pushObject(user); + user.rollback(); + equal(account.get('users.length'), 0, 'Users got removed'); + equal(user.get('accounts.length'), undefined, 'Accounts got rolledback correctly'); +}); diff --git a/packages/ember-data/tests/integration/relationships/one_to_many_test.js b/packages/ember-data/tests/integration/relationships/one_to_many_test.js index bfcb398cfd0..a976d51e6e9 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_many_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_many_test.js @@ -383,4 +383,52 @@ test("Rollbacking a deleted record works correctly when the belongsTo side has b user.rollback(); equal(user.get('accounts.length'), 1, "User still has the accounts"); equal(account.get('user'), user, 'Account has the user again'); -}); \ No newline at end of file +}); + +/* +Rollback from created state +*/ + +test("Rollbacking a created record works correctly when the hasMany side has been created - async", function () { + var user = store.push('user', {id:1, name: 'Stanley'}); + var message = store.createRecord('message', {user: user}); + message.rollback(); + message.get('user').then(async(function(fetchedUser) { + equal(fetchedUser, null, 'Message does not have the user anymore'); + })); + user.get('messages').then(async(function(fetchedMessages) { + equal(fetchedMessages.get('length'), 0, message, 'User does not have the message anymore'); + })); +}); + +test("Rollbacking a created record works correctly when the hasMany side has been created - sync", function () { + var user = store.push('user', {id:1, name: 'Stanley'}); + var account = store.createRecord('account', {user: user}); + account.rollback(); + equal(user.get('accounts.length'), 0, "Accounts are rolled back"); + equal(account.get('user'), null, 'Account does not have the user anymore'); +}); + +test("Rollbacking a created record works correctly when the belongsTo side has been created - async", function () { + var message = store.push('message', {id: 2, title: 'EmberFest was great'}); + var user = store.createRecord('user'); + user.get('messages').then(async(function(messages) { + messages.pushObject(message); + user.rollback(); + message.get('user').then(async(function(fetchedUser) { + equal(fetchedUser, null, 'Message does not have the user anymore'); + })); + user.get('messages').then(async(function(fetchedMessages) { + equal(fetchedMessages.get('length'), 0, 'User does not have the message anymore'); + })); + })); +}); + +test("Rollbacking a created record works correctly when the belongsTo side has been created - sync", function () { + var account = store.push('account', {id:2 , state: 'lonely'}); + var user = store.createRecord('user'); + user.get('accounts').pushObject(account); + user.rollback(); + equal(user.get('accounts.length'), undefined, "User does not have the account anymore"); + equal(account.get('user'), null, 'Account does not have the user anymore'); +}); diff --git a/packages/ember-data/tests/integration/relationships/one_to_one_test.js b/packages/ember-data/tests/integration/relationships/one_to_one_test.js index d2e27a5f3ad..72b171c772d 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_one_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_one_test.js @@ -270,4 +270,24 @@ test("Rollbacking a deleted record restores the relationship on both sides - syn job.rollback(); equal(user.get('job'), job, 'Job got rollbacked correctly'); equal(job.get('user'), user, 'Job still has the user'); -}); \ No newline at end of file +}); + +test("Rollbacking a created record removes the relationship on both sides - async", function () { + var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + var stanley = store.createRecord('user', {bestFriend: stanleysFriend}); + stanley.rollback(); + stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { + equal(fetchedUser, null, 'Stanley got rollbacked correctly'); + })); + stanley.get('bestFriend').then(async(function(fetchedUser) { + equal(fetchedUser, null, 'Stanleys friend did got removed'); + })); +}); + +test("Rollbacking a created record removes the relationship on both sides - sync", function () { + var user = store.push('user', {id:1, name: 'Stanley'}); + var job = store.createRecord('job', {user: user}); + job.rollback(); + equal(user.get('job'), null, 'Job got rollbacked correctly'); + equal(job.get('user'), null, 'Job does not have user anymore'); +}); From bad2153ae8885a840c535f501fcea60c0bf69c80 Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 29 Oct 2014 08:09:03 +0200 Subject: [PATCH 0425/2527] Use the model rollback and not state machine for created records rollback --- packages/ember-data/lib/system/model/model.js | 4 ++++ packages/ember-data/lib/system/model/states.js | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 72ae90e8f96..3461bee980c 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -912,6 +912,10 @@ var Model = Ember.Object.extend(Ember.Evented, { this.reconnectRelationships(); } + if (get(this, 'isNew')) { + this.clearRelationships(); + } + if (!get(this, 'isValid')) { this._inFlightAttributes = {}; } diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index eb62dc217bc..a6389c824a2 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -397,7 +397,6 @@ var createdState = dirtyState({ }); createdState.uncommitted.rolledBack = function(record) { - record.clearRelationships(); record.transitionTo('deleted.saved'); }; From 2070b3a3e345e40e4d82d1a64082f492cdd7cfc0 Mon Sep 17 00:00:00 2001 From: Craig Teegarden Date: Wed, 29 Oct 2014 10:32:54 -0400 Subject: [PATCH 0426/2527] [DOCS] InvalidError docs missing quote --- packages/ember-data/lib/system/adapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 837b58055e6..6c8a9e5cbfa 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -51,7 +51,7 @@ var errorProps = [ ```javascript return new DS.InvalidError({ length: 'Must be less than 15', - name: 'Must not be blank + name: 'Must not be blank' }); ``` From bcfc1cb0f08c0e4af9fa38574d6d113c2c3791d3 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 29 Oct 2014 14:11:00 -0400 Subject: [PATCH 0427/2527] Ensure production builds do not use require internally. --- Brocfile.js | 22 ++++++++++++---------- package.json | 5 +++-- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Brocfile.js b/Brocfile.js index ba43ff851ff..2555a59e517 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -15,6 +15,7 @@ var version = require('git-repo-version')(10); var renderTemplate = require('broccoli-render-template'); var yuidoc = require('broccoli-yuidoc'); var replace = require('broccoli-string-replace'); +var derequire = require('broccoli-derequire'); function moveFromLibAndMainJS(packageName, vendored){ var root = vendored ? 'bower_components/' + packageName + "/packages/" + packageName + '/lib': @@ -175,24 +176,25 @@ configurationFiles = replace(configurationFiles, { } }); -var trees = merge([ +var trees = [ testFiles, - globalBuild, namedAMDBuild, testRunner, bower, configurationFiles -]); +]; if (env === 'production') { + globalBuild = derequire(globalBuild); + var minifiedAMD = minify(namedAMDBuild, 'ember-data.named-amd'); var minifiedGlobals = minify(globalBuild, 'ember-data'); - trees = merge([ - yuidocTree, - trees, - minifiedAMD, - minifiedGlobals - ]); + + trees.push(yuidocTree); + trees.push(minifiedAMD); + trees.push(minifiedGlobals); } -module.exports = trees; +trees.push(globalBuild); + +module.exports = merge(trees); diff --git a/package.json b/package.json index 44cd7a17d7a..c0375163cd6 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "broccoli-cli": "0.0.1", "broccoli-concat": "0.0.7", "broccoli-defeatureify": "^0.3.0", + "broccoli-derequire": "0.0.1", "broccoli-env": "0.0.1", "broccoli-es3-safe-recast": "0.0.8", "broccoli-es6-module-transpiler": "^0.1.1", @@ -48,8 +49,8 @@ "ejs": "^1.0.0", "ember-cli": "0.0.43", "ember-publisher": "0.0.6", + "git-repo-version": "0.0.2", "testem": "^0.6.19", - "yuidocjs": "~0.3.46", - "git-repo-version": "0.0.2" + "yuidocjs": "~0.3.46" } } From 927c8450e2368bd898105f737d97d47532909062 Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Thu, 30 Oct 2014 01:09:19 +0100 Subject: [PATCH 0428/2527] RestAdapter's buildUrl from delete can ask for record's relations. closes #534 --- .../tests/integration/adapter/rest_adapter_test.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 2456c1e0f64..0b9b136d694 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -1309,8 +1309,9 @@ test('buildURL - buildURL takes a record from update', function() { test('buildURL - buildURL takes a record from delete', function() { Comment.reopen({ post: DS.belongsTo('post') }); + Post.reopen({ comments: DS.hasMany('comment') }); adapter.buildURL = function(type, id, record) { - return '/comments/' + record.get('id'); + return 'posts/' + record.get('post.id') + '/comments/' + record.get('id'); }; ajaxResponse({ comments: [{ id: 1 }] }); @@ -1321,7 +1322,7 @@ test('buildURL - buildURL takes a record from delete', function() { comment.set('post', post); comment.deleteRecord(); comment.save().then(async(function(post) { - equal(passedUrl, "/comments/1"); + equal(passedUrl, "posts/2/comments/1"); })); }); From dcc908f1f201fabb39a0a8da1068fb442e2b538e Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Fri, 31 Oct 2014 16:25:31 +0100 Subject: [PATCH 0429/2527] update contributing links - Handlebars 2.0 with canary builds - Use the correct canary build URL --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8774703845b..e017efc82d4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,8 +27,8 @@ demo should be fully operational with the exception of the bug you want to demonstrate. The more pared down, the better. A preconfigured [JSBin][1] | [JSFiddle][2] with mocked requests is available. -[1]: http://emberjs.jsbin.com/butef/1/edit -[2]: http://jsfiddle.net/ty6xgfqc/ +[1]: http://emberjs.jsbin.com/qovara/1/edit?html,js,output +[2]: http://jsfiddle.net/842xesgc/ 4. If possible, submit a Pull Request with a failing test. Better yet, take a stab at fixing the bug yourself if you can! From 05dd58be5536f47a5b50ec4c50234363db715fa8 Mon Sep 17 00:00:00 2001 From: cohitre Date: Fri, 31 Oct 2014 16:44:52 -0700 Subject: [PATCH 0430/2527] Removing outdated example from DS.Store documentation. #2442 --- packages/ember-data/lib/system/store.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index e66784c992f..288ba023e9e 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -81,14 +81,6 @@ function coerceId(id) { }); ``` - If your application has multiple `DS.Store` instances (an unusual case), you can - specify which store should be used: - - ```javascript - store.find('person', 123).then(function (person) { - }); - ``` - By default, the store will talk to your backend using a standard REST mechanism. You can customize how the store talks to your backend by specifying a custom adapter: From 166f1cf62867d8beb1e1a9f1d945fbc79a19d148 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Tue, 28 Oct 2014 23:23:47 +0100 Subject: [PATCH 0431/2527] Warn when pushing unknown payload keys into the store --- packages/ember-data/lib/system/store.js | 9 +++++++++ packages/ember-data/tests/unit/store/push_test.js | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 288ba023e9e..7ba33e5f05d 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1298,6 +1298,15 @@ Store = Ember.Object.extend({ data = normalizeRelationships(this, type, data); + Ember.warn("The payload for '" + typeName + "' contains these unknown keys: " + + Ember.inspect(Ember.keys(data).filter(function(key) { + return !get(type, 'fields').has(key) && key !== 'id' && key !== 'links'; + })) + ". Make sure they've been defined in your model.", + Ember.keys(data).filter(function(key) { + return !get(type, 'fields').has(key) && key !== 'id' && key !== 'links'; + }).length === 0 + ); + // Actually load the record into the store. this._load(type, data, _partial); diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index e397e750611..56f38da2743 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -411,4 +411,15 @@ test('calling push with belongsTo relationship the value must not be an array', throws(function() { store.push('phone-number', { id: 1, person: [1] }); }, /must not be an array/); +}); + +test("Calling push with unknown keys in the provided payload should warn", function() { + warns(function() { + store.push('person', { + id: '1', + firstName: 'Tomster', + emailAddress: 'tomster@emberjs.com', + isMascot: true + }); + }, /The payload for 'person' contains these unknown keys: \[emailAddress,isMascot\]. Make sure they've been defined in your model./); }); \ No newline at end of file From 7049753fdf692fae598db5ad9fba4a65e7674682 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Mon, 3 Nov 2014 17:12:09 +0100 Subject: [PATCH 0432/2527] Clear inverseRecord for deleted belongsTo properly --- .../lib/system/relationships/relationship.js | 4 ++-- .../integration/relationships/one_to_one_test.js | 12 +++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index 4e7611524b3..0f52467e022 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -305,9 +305,9 @@ BelongsToRelationship.prototype.notifyRecordRelationshipRemoved = function(recor BelongsToRelationship.prototype._super$removeRecordFromOwn = Relationship.prototype.removeRecordFromOwn; BelongsToRelationship.prototype.removeRecordFromOwn = function(record) { - if (!this.members.has(record)){ return;} - this._super$removeRecordFromOwn(record); + if (!this.members.has(record)) { return; } this.inverseRecord = null; + this._super$removeRecordFromOwn(record); }; BelongsToRelationship.prototype.findRecord = function() { diff --git a/packages/ember-data/tests/integration/relationships/one_to_one_test.js b/packages/ember-data/tests/integration/relationships/one_to_one_test.js index 72b171c772d..46c377c7688 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_one_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_one_test.js @@ -227,8 +227,18 @@ Deleting tests */ test("When deleting a record that has a belongsTo relationship, the record is removed from the inverse but still has access to its own relationship - async", function () { - var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); + // This observer is here to make sure that inverseRecord gets cleared, when + // the record is deleted, before notifyRecordRelationshipRemoved() and in turn + // notifyPropertyChange() gets called. If not properly cleared observers will + // trigger with the old value of the relationship. + User.reopen({ + bestFriendObserver: Ember.observer('bestFriend', function () { + this.get('bestFriend'); + }) + }); + var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); stanley.deleteRecord(); stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { equal(fetchedUser, null, 'Stanley got removed'); From 05cc46453adac2d6118f30728eb757606cc3cbf6 Mon Sep 17 00:00:00 2001 From: Roy Liu Date: Mon, 3 Nov 2014 16:33:00 -0500 Subject: [PATCH 0433/2527] Expand the package configuration filename glob declaration in `Brocfile.js` into the affected filenames, as the `broccoli-string-replace` plugin doesn't support globbing This enables the package version to be properly injected. --- Brocfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Brocfile.js b/Brocfile.js index 2555a59e517..3c8d71d75b9 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -169,7 +169,7 @@ var configurationFiles = pickFiles('config/package_manager_files', { }); configurationFiles = replace(configurationFiles, { - files: [ '**/*' ], + files: [ 'bower.json', 'component.json', 'package.json' ], pattern: { match: /VERSION_STRING_PLACEHOLDER/g, replacement: version From 1ae0692d259f2fc96b79a6ef34929540305b1401 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 12 Nov 2014 13:04:13 -0600 Subject: [PATCH 0434/2527] handlebars 2.0 for beta --- tests/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/index.html b/tests/index.html index f190c624249..60374148911 100644 --- a/tests/index.html +++ b/tests/index.html @@ -34,7 +34,7 @@ - +
      From f382e24f16dec982c2b45f375663cee006ddb57c Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 29 Nov 2014 20:51:39 -0600 Subject: [PATCH 0478/2527] make sure production builds get es3Recasted! --- Brocfile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Brocfile.js b/Brocfile.js index 9a35dabe523..af68d7c82fc 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -2,7 +2,6 @@ var es6 = require('broccoli-es6-module-transpiler'); var PackageResolver = require('es6-module-transpiler-package-resolver'); -var compileModules = require('broccoli-compile-modules'); var concat = require('broccoli-concat'); var uglify = require('broccoli-uglify-js'); var es3SafeRecast = require('broccoli-es3-safe-recast'); @@ -154,10 +153,11 @@ var trees = [ ]; if (env === 'production') { + globalBuild = versionStamp(globalBuild); + globalBuild = es3SafeRecast(globalBuild); var minifiedGlobals = minify(globalBuild, 'ember-data'); trees.push(yuidocTree); trees.push(minifiedGlobals); - globalBuild = versionStamp(globalBuild); } trees.push(globalBuild); From 402acf05df1cdbc2c7eedc1e1361e35219be0ef4 Mon Sep 17 00:00:00 2001 From: bmac Date: Sat, 29 Nov 2014 22:20:00 -0500 Subject: [PATCH 0479/2527] Mention store.normalize in the store.push docs. --- packages/ember-data/lib/system/store.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index fe95973b45c..e98521456ab 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1304,9 +1304,15 @@ Store = Ember.Object.extend({ } ``` - If you're streaming data or implementing an adapter, - make sure that you have converted the incoming data - into this form. + If you're streaming data or implementing an adapter, make sure + that you have converted the incoming data into this form. The + store's [normalize](#method_normalize) method is a convenience + helper for converting a json payload into the form Ember Data + expects. + + ```js + store.push('person', store.normalize('person', data)); + ``` This method can be used both to push in brand new records, as well as to update existing records. From f89e94c33df9023d55a084c3848775e91efc8cef Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sun, 30 Nov 2014 14:39:06 -0600 Subject: [PATCH 0480/2527] add Ember.run to more code missing it --- .../tests/integration/filter_test.js | 17 +- .../tests/integration/records/save_test.js | 13 +- .../tests/integration/records/unload_test.js | 8 +- .../relationships/belongs_to_test.js | 4 +- .../relationships/has_many_test.js | 19 +- .../relationships/one_to_one_test.js | 256 +++++++---- .../embedded_records_mixin_test.js | 398 ++++++++++++------ .../serializers/json_serializer_test.js | 91 ++-- .../serializers/rest_serializer_test.js | 97 +++-- .../tests/integration/store_test.js | 74 ++-- .../tests/unit/adapters/rest_adapter/ajax.js | 18 +- packages/ember-data/tests/unit/debug_test.js | 12 +- .../unit/model/lifecycle_callbacks_test.js | 66 ++- .../ember-data/tests/unit/model/merge_test.js | 66 ++- .../tests/unit/model/relationships_test.js | 387 ++++++++++------- .../tests/unit/model/rollback_test.js | 164 +++++--- packages/ember-data/tests/unit/model_test.js | 349 ++++++++++----- .../tests/unit/record_array_test.js | 123 ++++-- .../tests/unit/store/adapter_interop_test.js | 216 ++++++---- .../tests/unit/store/create_record_test.js | 39 +- .../tests/unit/store/model_for_test.js | 8 +- .../ember-data/tests/unit/store/push_test.js | 346 ++++++++------- .../tests/unit/store/serializer_for_test.js | 7 +- .../tests/unit/store/unload_test.js | 116 ++--- 24 files changed, 1894 insertions(+), 1000 deletions(-) diff --git a/packages/ember-data/tests/integration/filter_test.js b/packages/ember-data/tests/integration/filter_test.js index 0cb99882991..f30d903f0cd 100644 --- a/packages/ember-data/tests/integration/filter_test.js +++ b/packages/ember-data/tests/integration/filter_test.js @@ -632,19 +632,26 @@ test("a Record Array can update its filter after server-side creates multiple re test("destroying filteredRecordArray unregisters models from being filtered", function() { var filterFn = tapFn( function(){ return true; } ); + var person; - var person = store.push('person', { - id: 1, - name: 'Tom Dale' + run(function(){ + person = store.push('person', { + id: 1, + name: 'Tom Dale' + }); }); - var recordArray = store.filter('person', filterFn); + var recordArray; + + run(function(){ + recordArray = store.filter('person', filterFn); + }); equal(filterFn.summary.called.length, 1); Ember.run(function(){ recordArray.then(function(array){ - array.destroy() + array.destroy(); }); }); clientEdits([1]); diff --git a/packages/ember-data/tests/integration/records/save_test.js b/packages/ember-data/tests/integration/records/save_test.js index dd257abb0bb..e8c66953398 100644 --- a/packages/ember-data/tests/integration/records/save_test.js +++ b/packages/ember-data/tests/integration/records/save_test.js @@ -75,18 +75,23 @@ test("Retry is allowed in a failure handler", function() { test("Repeated failed saves keeps the record in uncommited state", function() { expect(2); + var post; - var post = env.store.createRecord('post', {title: 'toto'}); + run(function(){ + post = env.store.createRecord('post', {title: 'toto'}); + }); env.adapter.createRecord = function(store, type, record) { return Ember.RSVP.reject(); }; - post.save().then(null, function() { - equal(post.get('currentState.stateName'), 'root.loaded.created.uncommitted'); - + run(function(){ post.save().then(null, function() { equal(post.get('currentState.stateName'), 'root.loaded.created.uncommitted'); + + post.save().then(null, function() { + equal(post.get('currentState.stateName'), 'root.loaded.created.uncommitted'); + }); }); }); }); diff --git a/packages/ember-data/tests/integration/records/unload_test.js b/packages/ember-data/tests/integration/records/unload_test.js index 5bc85d4f310..8680421e04e 100644 --- a/packages/ember-data/tests/integration/records/unload_test.js +++ b/packages/ember-data/tests/integration/records/unload_test.js @@ -93,7 +93,7 @@ test("unloading all records also updates record array from all()", function() { //TODO(Igor) think about how this works with ssot and unloading -test("unloading a record also clears it's relationship", function() { +test("unloading a record also clears its relationship", function() { var adam, bob; run(function(){ adam = env.store.push('person', { @@ -112,13 +112,13 @@ test("unloading a record also clears it's relationship", function() { }); }); - run(env.store, 'find', 'person', 1).then(function(person){ + run(env.store, 'find', 'person', 1).then(async(function(person){ equal(person.get('cars.length'), 1, 'aaaa'); - Ember.run(function(){ + run(function(){ person.unloadRecord(); }); equal(person.get('cars.length'), undefined); - }); + })); }); diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index b72e70e1316..cef64f905ca 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -263,7 +263,9 @@ test("A record with an async belongsTo relationship returning null should resolv env.container.register('model:group', Group); env.container.register('model:person', Person); - store.push('person', { id: 1, links: { group: '/people/1/group' } }); + run(function(){ + store.push('person', { id: 1, links: { group: '/people/1/group' } }); + }); env.adapter.find = function() { throw new Error("Adapter's find method should not be called"); diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index e958e8092d5..0734b3fc98c 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -408,16 +408,21 @@ test("PromiseArray proxies evented methods to its ManyArray", function() { { id: 2, body: "Second" } ]); }; + var post, comments; - var post = env.store.push('post', {id:1, links: {comments: 'someLink'}}); + run(function(){ + post = env.store.push('post', {id:1, links: {comments: 'someLink'}}); + comments = post.get('comments'); + }); - var comments = post.get('comments'); comments.on('on-event', function() { ok(true); }); - comments.trigger('on-event'); + run(function(){ + comments.trigger('on-event'); + }); equal(comments.has('on-event'), true); @@ -435,7 +440,9 @@ test("PromiseArray proxies evented methods to its ManyArray", function() { equal(comments.has('one-event'), true); - comments.trigger('one-event'); + run(function(){ + comments.trigger('one-event'); + }); equal(comments.has('one-event'), false); }); @@ -789,7 +796,7 @@ test("dual non-async HM <-> BT", function(){ return env.store.createRecord('comment', { post: post }).save(); - }).then(function(comment){ + }).then(async(function(comment){ var commentPost = comment.get('post'); var postComments = comment.get('post.comments'); var postCommentsLength = comment.get('post.comments.length'); @@ -799,7 +806,7 @@ test("dual non-async HM <-> BT", function(){ equal(postCommentsLength, 2, "comment's post should have a reference back to comment"); ok(postComments && postComments.indexOf(firstComment) !== -1, 'expect to contain first comment'); ok(postComments && postComments.indexOf(comment) !== -1, 'expected to contain the new comment'); - }); + })); }); test("When an unloaded record is added to the hasMany, it gets fetched once the hasMany is accessed even if the hasMany has been already fetched", function() { diff --git a/packages/ember-data/tests/integration/relationships/one_to_one_test.js b/packages/ember-data/tests/integration/relationships/one_to_one_test.js index 46c377c7688..7f0968c5263 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_one_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_one_test.js @@ -1,4 +1,5 @@ var env, store, User, Job; +var run = Ember.run; var attr = DS.attr, belongsTo = DS.belongsTo; @@ -30,7 +31,7 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', { }, teardown: function() { - env.container.destroy(); + run(env.container, 'destroy'); } }); @@ -39,42 +40,62 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', { */ test("Relationship is available from both sides even if only loaded from one side - async", function () { - var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend: 2}); - var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + var stanley, stanleysFriend; + run(function(){ + stanley = store.push('user', {id:1, name: 'Stanley', bestFriend: 2}); + stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + }); stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { equal(fetchedUser, stanley, 'User relationship was set up correctly'); })); }); test("Relationship is available from both sides even if only loaded from one side - sync", function () { - var job = store.push('job', {id:2 , isGood: true}); - var user = store.push('user', {id:1, name: 'Stanley', job:2 }); + var job, user; + run(function(){ + job = store.push('job', {id:2 , isGood: true}); + user = store.push('user', {id:1, name: 'Stanley', job:2 }); + }); equal(job.get('user'), user, 'User relationship was set up correctly'); }); test("Fetching a belongsTo that is set to null removes the record from a relationship - async", function () { - var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend: 1}); - store.push('user', {id:1, name: 'Stanley', bestFriend: null}); + var stanleysFriend; + run(function(){ + stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend: 1}); + store.push('user', {id:1, name: 'Stanley', bestFriend: null}); + }); stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { equal(fetchedUser, null, 'User relationship was removed correctly'); })); }); test("Fetching a belongsTo that is set to null removes the record from a relationship - sync", function () { - var job = store.push('job', {id:2 , isGood: true}); - store.push('user', {id:1, name: 'Stanley', job:2 }); - job = store.push('job', {id:2 , isGood: true, user:null}); + var job; + run(function(){ + job = store.push('job', {id:2 , isGood: true}); + store.push('user', {id:1, name: 'Stanley', job:2 }); + }); + run(function(){ + job = store.push('job', {id:2 , isGood: true, user:null}); + }); equal(job.get('user'), null, 'User relationship was removed correctly'); }); test("Fetching a belongsTo that is set to a different record, sets the old relationship to null - async", function () { expect(3); - var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend: 2}); - var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend: 1}); + var stanley, stanleysFriend; + run(function(){ + stanley = store.push('user', {id:1, name: 'Stanley', bestFriend: 2}); + stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend: 1}); + }); stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { equal(fetchedUser, stanley, 'User relationship was initally setup correctly'); - var stanleysNewFriend = store.push('user', {id:3, name: "Stanley's New friend", bestFriend: 1}); + var stanleysNewFriend + run(function(){ + stanleysNewFriend = store.push('user', {id:3, name: "Stanley's New friend", bestFriend: 1}); + }); stanley.get('bestFriend').then(async(function(fetchedNewFriend){ equal(fetchedNewFriend, stanleysNewFriend, 'User relationship was updated correctly'); @@ -87,10 +108,15 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat }); test("Fetching a belongsTo that is set to a different record, sets the old relationship to null - sync", function () { - var job = store.push('job', {id:2 , isGood: false}); - var user = store.push('user', {id:1, name: 'Stanley', job:2 }); + var job, user, newBetterJob; + run(function(){ + job = store.push('job', {id:2 , isGood: false}); + user = store.push('user', {id:1, name: 'Stanley', job:2 }); + }); equal(job.get('user'), user, 'Job and user initially setup correctly'); - var newBetterJob = store.push('job', {id:3, isGood: true, user:1 }); + run(function(){ + newBetterJob = store.push('job', {id:3, isGood: true, user:1 }); + }); equal(user.get('job'), newBetterJob, 'Job updated correctly'); equal(job.get('user'), null, 'Old relationship nulled out correctly'); @@ -102,26 +128,41 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat */ test("Setting a OneToOne relationship reflects correctly on the other side- async", function () { - var stanley = store.push('user', {id:1, name: 'Stanley'}); - var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); - stanley.set('bestFriend', stanleysFriend); + var stanley, stanleysFriend; + run(function(){ + stanley = store.push('user', {id:1, name: 'Stanley'}); + stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + }); + run(function(){ + stanley.set('bestFriend', stanleysFriend); + }); stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { equal(fetchedUser, stanley, 'User relationship was updated correctly'); })); }); test("Setting a OneToOne relationship reflects correctly on the other side- sync", function () { - var job = store.push('job', {id:2 , isGood: true}); - var user = store.push('user', {id:1, name: 'Stanley'}); - user.set('job', job); + var job, user; + run(function(){ + job = store.push('job', {id:2 , isGood: true}); + user = store.push('user', {id:1, name: 'Stanley'}); + }); + run(function(){ + user.set('job', job); + }); equal(job.get('user'), user, 'User relationship was set up correctly'); }); test("Setting a BelongsTo to a promise unwraps the promise before setting- async", function () { - var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); - var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); - var newFriend = store.push('user', {id:3, name: "New friend"}); - newFriend.set('bestFriend', stanleysFriend.get('bestFriend')); + var stanley, stanleysFriend, newFriend; + run(function(){ + stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); + stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + newFriend = store.push('user', {id:3, name: "New friend"}); + }); + run(function(){ + newFriend.set('bestFriend', stanleysFriend.get('bestFriend')); + }); stanley.get('bestFriend').then(async(function(fetchedUser) { equal(fetchedUser, newFriend, 'User relationship was updated correctly'); })); @@ -131,28 +172,41 @@ test("Setting a BelongsTo to a promise unwraps the promise before setting- async }); test("Setting a BelongsTo to a promise works when the promise returns null- async", function () { - store.push('user', {id:1, name: 'Stanley'}); - var igor = store.push('user', {id:2, name: "Igor"}); - var newFriend = store.push('user', {id:3, name: "New friend", bestFriend:1}); - newFriend.set('bestFriend', igor.get('bestFriend')); + var igor, newFriend; + run(function(){ + store.push('user', {id:1, name: 'Stanley'}); + igor = store.push('user', {id:2, name: "Igor"}); + newFriend = store.push('user', {id:3, name: "New friend", bestFriend:1}); + }); + run(function(){ + newFriend.set('bestFriend', igor.get('bestFriend')); + }); newFriend.get('bestFriend').then(async(function(fetchedUser) { equal(fetchedUser, null, 'User relationship was updated correctly'); })); }); test("Setting a BelongsTo to a promise that didn't come from a relationship errors out", function () { - var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); - var igor = store.push('user', {id:3, name: 'Igor'}); + var stanley, igor; + run(function(){ + stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); + igor = store.push('user', {id:3, name: 'Igor'}); + }); expectAssertion(function() { - stanley.set('bestFriend', Ember.RSVP.resolve(igor)); + run(function(){ + stanley.set('bestFriend', Ember.RSVP.resolve(igor)); + }); }, /You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call./); }); test("Setting a BelongsTo to a promise multiple times is resistant to race conditions- async", function () { expect(1); - var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); - var igor = store.push('user', {id:3, name: "Igor", bestFriend:5}); - var newFriend = store.push('user', {id:7, name: "New friend"}); + var stanley, igor, newFriend; + run(function(){ + stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); + igor = store.push('user', {id:3, name: "Igor", bestFriend:5}); + newFriend = store.push('user', {id:7, name: "New friend"}); + }); env.adapter.find = function(store, type, id) { if (id === '5') { return Ember.RSVP.resolve({id:5, name: "Igor's friend"}); @@ -167,38 +221,55 @@ test("Setting a BelongsTo to a promise multiple times is resistant to race condi } }; - newFriend.set('bestFriend', stanley.get('bestFriend')); - newFriend.set('bestFriend', igor.get('bestFriend')); - newFriend.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser.get('name'), "Igor's friend", 'User relationship was updated correctly'); - })); + run(function(){ + newFriend.set('bestFriend', stanley.get('bestFriend')); + newFriend.set('bestFriend', igor.get('bestFriend')); + newFriend.get('bestFriend').then(async(function(fetchedUser) { + equal(fetchedUser.get('name'), "Igor's friend", 'User relationship was updated correctly'); + })); + }); }); test("Setting a OneToOne relationship to null reflects correctly on the other side - async", function () { - var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); - var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend:1}); - stanley.set('bestFriend', null); // :( + var stanley, stanleysFriend; + run(function(){ + stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); + stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend:1}); + }); + run(function(){ + stanley.set('bestFriend', null); // :( + }); stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { equal(fetchedUser, null, 'User relationship was removed correctly'); })); }); test("Setting a OneToOne relationship to null reflects correctly on the other side - sync", function () { - var job = store.push('job', {id:2 , isGood: false, user:1}); - var user = store.push('user', {id:1, name: 'Stanley', job:2}); - user.set('job', null); + var job, user; + run(function(){ + job = store.push('job', {id:2 , isGood: false, user:1}); + user = store.push('user', {id:1, name: 'Stanley', job:2}); + }); + run(function(){ + user.set('job', null); + }); equal(job.get('user'), null, 'User relationship was removed correctly'); }); test("Setting a belongsTo to a different record, sets the old relationship to null - async", function () { expect(3); - var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend: 2}); - var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend: 1}); + var stanley, stanleysFriend; + run(function(){ + stanley = store.push('user', {id:1, name: 'Stanley', bestFriend: 2}); + stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend: 1}); + }); stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { equal(fetchedUser, stanley, 'User relationship was initally setup correctly'); var stanleysNewFriend = store.push('user', {id:3, name: "Stanley's New friend"}); - stanleysNewFriend.set('bestFriend', stanley); + run(function(){ + stanleysNewFriend.set('bestFriend', stanley); + }); stanley.get('bestFriend').then(async(function(fetchedNewFriend){ equal(fetchedNewFriend, stanleysNewFriend, 'User relationship was updated correctly'); @@ -211,11 +282,18 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu }); test("Setting a belongsTo to a different record, sets the old relationship to null - sync", function () { - var job = store.push('job', {id:2 , isGood: false}); - var user = store.push('user', {id:1, name: 'Stanley', job:2 }); + var job, user, newBetterJob; + run(function(){ + job = store.push('job', {id:2 , isGood: false}); + user = store.push('user', {id:1, name: 'Stanley', job:2 }); + }); + equal(job.get('user'), user, 'Job and user initially setup correctly'); - var newBetterJob = store.push('job', {id:3, isGood: true}); - newBetterJob.set('user', user); + + run(function(){ + newBetterJob = store.push('job', {id:3, isGood: true}); + newBetterJob.set('user', user); + }); equal(user.get('job'), newBetterJob, 'Job updated correctly'); equal(job.get('user'), null, 'Old relationship nulled out correctly'); @@ -236,10 +314,13 @@ test("When deleting a record that has a belongsTo relationship, the record is re this.get('bestFriend'); }) }); + var stanleysFriend, stanley; - var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); - var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); - stanley.deleteRecord(); + run(function(){ + stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); + }); + run(stanley, 'deleteRecord'); stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { equal(fetchedUser, null, 'Stanley got removed'); })); @@ -249,9 +330,14 @@ test("When deleting a record that has a belongsTo relationship, the record is re }); test("When deleting a record that has a belongsTo relationship, the record is removed from the inverse but still has access to its own relationship - sync", function () { - var job = store.push('job', {id:2 , isGood: true}); - var user = store.push('user', {id:1, name: 'Stanley', job:2 }); - job.deleteRecord(); + var job, user; + run(function(){ + job = store.push('job', {id:2 , isGood: true}); + user = store.push('user', {id:1, name: 'Stanley', job:2 }); + }); + run(function(){ + job.deleteRecord(); + }); equal(user.get('job'), null, 'Job got removed from the user'); equal(job.get('user'), user, 'Job still has the user'); }); @@ -261,10 +347,17 @@ Rollback tests */ test("Rollbacking a deleted record restores the relationship on both sides - async", function () { - var stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); - var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); - stanley.deleteRecord(); - stanley.rollback(); + var stanley, stanleysFriend; + run(function(){ + stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); + stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + }); + run(function(){ + stanley.deleteRecord(); + }); + run(function(){ + stanley.rollback(); + }); stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { equal(fetchedUser, stanley, 'Stanley got rollbacked correctly'); })); @@ -274,18 +367,28 @@ test("Rollbacking a deleted record restores the relationship on both sides - asy }); test("Rollbacking a deleted record restores the relationship on both sides - sync", function () { - var job = store.push('job', {id:2 , isGood: true}); - var user = store.push('user', {id:1, name: 'Stanley', job:2 }); - job.deleteRecord(); - job.rollback(); + var job, user; + run(function(){ + job = store.push('job', {id:2 , isGood: true}); + user = store.push('user', {id:1, name: 'Stanley', job:2 }); + }); + run(function(){ + job.deleteRecord(); + job.rollback(); + }); equal(user.get('job'), job, 'Job got rollbacked correctly'); equal(job.get('user'), user, 'Job still has the user'); }); test("Rollbacking a created record removes the relationship on both sides - async", function () { - var stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); - var stanley = store.createRecord('user', {bestFriend: stanleysFriend}); - stanley.rollback(); + var stanleysFriend, stanley; + run(function(){ + stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + stanley = store.createRecord('user', {bestFriend: stanleysFriend}); + }); + run(function(){ + stanley.rollback(); + }); stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { equal(fetchedUser, null, 'Stanley got rollbacked correctly'); })); @@ -295,9 +398,14 @@ test("Rollbacking a created record removes the relationship on both sides - asyn }); test("Rollbacking a created record removes the relationship on both sides - sync", function () { - var user = store.push('user', {id:1, name: 'Stanley'}); - var job = store.createRecord('job', {user: user}); - job.rollback(); + var user, job; + run(function(){ + user = store.push('user', {id:1, name: 'Stanley'}); + job = store.createRecord('job', {user: user}); + }); + run(function(){ + job.rollback(); + }); equal(user.get('job'), null, 'Job got rollbacked correctly'); equal(job.get('user'), null, 'Job does not have user anymore'); }); diff --git a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js index e4e88d0d4ee..ae46a71ae43 100644 --- a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js +++ b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js @@ -2,6 +2,7 @@ var get = Ember.get; var HomePlanet, SuperVillain, EvilMinion, SecretLab, SecretWeapon, Comment, league, superVillain, evilMinion, secretWeapon, homePlanet, secretLab, env; var indexOf = Ember.EnumerableUtils.indexOf; +var run = Ember.run; var LightSaber; module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { @@ -63,7 +64,7 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { }, teardown: function() { - env.store.destroy(); + run(env.store, 'destroy'); } }); @@ -87,8 +88,11 @@ test("extractSingle with embedded objects", function() { }] } }; + var json; - var json = serializer.extractSingle(env.store, HomePlanet, json_hash); + run(function(){ + json = serializer.extractSingle(env.store, HomePlanet, json_hash); + }); deepEqual(json, { id: "1", @@ -129,8 +133,11 @@ test("extractSingle with embedded objects inside embedded objects", function() { }] } }; + var json; - var json = serializer.extractSingle(env.store, HomePlanet, json_hash); + run(function(){ + json = serializer.extractSingle(env.store, HomePlanet, json_hash); + }); deepEqual(json, { id: "1", @@ -173,7 +180,10 @@ test("extractSingle with embedded objects of same type", function() { }] } }; - var json = serializer.extractSingle(env.store, Comment, json_hash); + var json; + run(function(){ + json = serializer.extractSingle(env.store, Comment, json_hash); + }); deepEqual(json, { id: "1", @@ -216,7 +226,10 @@ test("extractSingle with embedded objects inside embedded objects of same type", }] } }; - var json = serializer.extractSingle(env.store, Comment, json_hash); + var json; + run(function(){ + json = serializer.extractSingle(env.store, Comment, json_hash); + }); deepEqual(json, { id: "1", @@ -265,7 +278,10 @@ test("extractSingle with embedded objects of same type, but from separate attrib }] } }; - var json = serializer.extractSingle(env.store, HomePlanet, json_hash); + var json; + run(function(){ + json = serializer.extractSingle(env.store, HomePlanet, json_hash); + }); deepEqual(json, { id: "1", @@ -301,8 +317,11 @@ test("extractArray with embedded objects", function() { }] }] }; + var array; - var array = serializer.extractArray(env.store, HomePlanet, json_hash); + run(function(){ + array = serializer.extractArray(env.store, HomePlanet, json_hash); + }); deepEqual(array, [{ id: "1", @@ -340,8 +359,11 @@ test("extractArray with embedded objects with custom primary key", function() { }] }] }; + var array; - var array = serializer.extractArray(env.store, HomePlanet, json_hash); + run(function(){ + array = serializer.extractArray(env.store, HomePlanet, json_hash); + }); deepEqual(array, [{ id: "1", @@ -349,10 +371,11 @@ test("extractArray with embedded objects with custom primary key", function() { villains: ["1"] }]); - return env.store.find("superVillain", 1).then(function(minion){ - env.container.unregister('serializer:superVillain'); - equal(minion.get('firstName'), "Alex"); - + run(function(){ + return env.store.find("superVillain", 1).then(async(function(minion){ + env.container.unregister('serializer:superVillain'); + equal(minion.get('firstName'), "Alex"); + })); }); }); test("extractArray with embedded objects with identical relationship and attribute key ", function() { @@ -381,8 +404,11 @@ test("extractArray with embedded objects with identical relationship and attribu }] }] }; + var array; - var array = serializer.extractArray(env.store, HomePlanet, json_hash); + run(function(){ + array = serializer.extractArray(env.store, HomePlanet, json_hash); + }); deepEqual(array, [{ id: "1", @@ -390,9 +416,9 @@ test("extractArray with embedded objects with identical relationship and attribu villains: ["1"] }]); - return env.store.find("superVillain", 1).then(function(minion){ + return env.store.find("superVillain", 1).then(async(function(minion){ equal(minion.get('firstName'), "Alex"); - }); + })); }); test("extractArray with embedded objects of same type as primary type", function() { env.container.register('adapter:comment', DS.ActiveModelAdapter); @@ -421,8 +447,11 @@ test("extractArray with embedded objects of same type as primary type", function }] }] }; + var array; - var array = serializer.extractArray(env.store, Comment, json_hash); + run(function(){ + array = serializer.extractArray(env.store, Comment, json_hash); + }); deepEqual(array, [{ id: "1", @@ -486,7 +515,10 @@ test("extractArray with embedded objects of same type, but from separate attribu }] }] }; - var json = serializer.extractArray(env.store, HomePlanet, json_hash); + var json; + run(function(){ + json = serializer.extractArray(env.store, HomePlanet, json_hash); + }); deepEqual(json, [{ id: "1", @@ -509,15 +541,21 @@ test("extractArray with embedded objects of same type, but from separate attribu }); test("serialize supports serialize:false on non-relationship properties", function() { - var tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", id: '1' }); + var tom; + run(function(){ + tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", id: '1' }); + }); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { firstName: {serialize: false} } })); - var serializer = env.container.lookup("serializer:superVillain"); - var json = serializer.serialize(tom); + var serializer, json; + run(function(){ + serializer = env.container.lookup("serializer:superVillain"); + json = serializer.serialize(tom); + }); deepEqual(json, { last_name: "Dale", @@ -527,17 +565,24 @@ test("serialize supports serialize:false on non-relationship properties", functi }); test("serialize with embedded objects (hasMany relationship)", function() { - league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); - var tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); + var tom, league; + run(function(){ + league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); + tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); + }); env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: {embedded: 'always'} } })); - var serializer = env.container.lookup("serializer:homePlanet"); - var json = serializer.serialize(league); + var serializer, json; + run(function(){ + serializer = env.container.lookup("serializer:homePlanet"); + + json = serializer.serialize(league); + }); deepEqual(json, { name: "Villain League", @@ -552,17 +597,22 @@ test("serialize with embedded objects (hasMany relationship)", function() { }); test("serialize with embedded objects (hasMany relationship) supports serialize:false", function() { - league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); - env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); + run(function(){ + league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); + env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); + }); env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: {serialize: false} } })); - var serializer = env.container.lookup("serializer:homePlanet"); + var serializer, json; + run(function(){ + serializer = env.container.lookup("serializer:homePlanet"); - var json = serializer.serialize(league); + json = serializer.serialize(league); + }); deepEqual(json, { name: "Villain League" @@ -570,17 +620,22 @@ test("serialize with embedded objects (hasMany relationship) supports serialize: }); test("serialize with (new) embedded objects (hasMany relationship)", function() { - league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); - env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league }); + run(function(){ + league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); + env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league }); + }); env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: {embedded: 'always'} } })); - var serializer = env.container.lookup("serializer:homePlanet"); + var serializer, json; + run(function(){ + serializer = env.container.lookup("serializer:homePlanet"); - var json = serializer.serialize(league); + json = serializer.serialize(league); + }); deepEqual(json, { name: "Villain League", villains: [{ @@ -593,11 +648,13 @@ test("serialize with (new) embedded objects (hasMany relationship)", function() }); test("serialize with embedded objects (hasMany relationships, including related objects not embedded)", function() { - superVillain = env.store.createRecord(SuperVillain, { id: 1, firstName: "Super", lastName: "Villian" }); - evilMinion = env.store.createRecord(EvilMinion, { id: 1, name: "Evil Minion", superVillian: superVillain }); - secretWeapon = env.store.createRecord(SecretWeapon, { id: 1, name: "Secret Weapon", superVillain: superVillain }); - superVillain.get('evilMinions').pushObject(evilMinion); - superVillain.get('secretWeapons').pushObject(secretWeapon); + run(function(){ + superVillain = env.store.createRecord(SuperVillain, { id: 1, firstName: "Super", lastName: "Villian" }); + evilMinion = env.store.createRecord(EvilMinion, { id: 1, name: "Evil Minion", superVillian: superVillain }); + secretWeapon = env.store.createRecord(SecretWeapon, { id: 1, name: "Secret Weapon", superVillain: superVillain }); + superVillain.get('evilMinions').pushObject(evilMinion); + superVillain.get('secretWeapons').pushObject(secretWeapon); + }); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -605,9 +662,12 @@ test("serialize with embedded objects (hasMany relationships, including related secretWeapons: {serialize: 'ids'} } })); - var serializer = env.container.lookup("serializer:superVillain"); + var serializer, json; + run(function(){ + serializer = env.container.lookup("serializer:superVillain"); - var json = serializer.serialize(superVillain); + json = serializer.serialize(superVillain); + }); deepEqual(json, { first_name: get(superVillain, "firstName"), last_name: get(superVillain, "lastName"), @@ -648,8 +708,11 @@ test("extractSingle with embedded object (belongsTo relationship)", function() { secret_weapon_ids: [] } }; + var json; - var json = serializer.extractSingle(env.store, SuperVillain, json_hash); + run(function(){ + json = serializer.extractSingle(env.store, SuperVillain, json_hash); + }); deepEqual(json, { "id": "1", @@ -661,11 +724,13 @@ test("extractSingle with embedded object (belongsTo relationship)", function() { "secretWeapons": [] }); - env.store.find("secretLab", 101).then(async(function(secretLab) { - equal(secretLab.get('id'), '101'); - equal(secretLab.get('minionCapacity'), 5000); - equal(secretLab.get('vicinity'), 'California, USA'); - })); + run(function(){ + env.store.find("secretLab", 101).then(async(function(secretLab) { + equal(secretLab.get('id'), '101'); + equal(secretLab.get('minionCapacity'), 5000); + equal(secretLab.get('vicinity'), 'California, USA'); + })); + }); }); test("serialize with embedded object (belongsTo relationship)", function() { @@ -675,19 +740,25 @@ test("serialize with embedded object (belongsTo relationship)", function() { secretLab: {embedded: 'always'} } })); - var serializer = env.container.lookup("serializer:superVillain"); + var serializer, json, tom; + run(function(){ + serializer = env.container.lookup("serializer:superVillain"); - // records with an id, persisted + // records with an id, persisted - var tom = env.store.createRecord( - SuperVillain, - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) - } - ); + tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + }); + + run(function(){ + json = serializer.serialize(tom); + }); - var json = serializer.serialize(tom); deepEqual(json, { first_name: get(tom, "firstName"), last_name: get(tom, "lastName"), @@ -715,16 +786,22 @@ test("serialize with embedded object (belongsTo relationship) works with differe var serializer = env.container.lookup("serializer:superVillain"); // records with an id, persisted + var tom, json; + + run(function(){ + tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + }); - var tom = env.store.createRecord( - SuperVillain, - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) - } - ); + run(function(){ + json = serializer.serialize(tom); + }); - var json = serializer.serialize(tom); deepEqual(json, { first_name: get(tom, "firstName"), last_name: get(tom, "lastName"), @@ -748,16 +825,22 @@ test("serialize with embedded object (belongsTo relationship, new no id)", funct var serializer = env.container.lookup("serializer:superVillain"); // records without ids, new + var tom, json; + + run(function(){ + tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", + secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA" }), + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + }); - var tom = env.store.createRecord( - SuperVillain, - { firstName: "Tom", lastName: "Dale", - secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA" }), - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) - } - ); + run(function(){ + json = serializer.serialize(tom); + }); - var json = serializer.serialize(tom); deepEqual(json, { first_name: get(tom, "firstName"), last_name: get(tom, "lastName"), @@ -779,16 +862,22 @@ test("serialize with embedded object (belongsTo relationship) supports serialize var serializer = env.container.lookup("serializer:superVillain"); // records with an id, persisted + var tom, json; + + run(function(){ + tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + }); - var tom = env.store.createRecord( - SuperVillain, - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) - } - ); + run(function(){ + json = serializer.serialize(tom); + }); - var json = serializer.serialize(tom); deepEqual(json, { first_name: get(tom, "firstName"), last_name: get(tom, "lastName"), @@ -808,16 +897,22 @@ test("serialize with embedded object (belongsTo relationship) supports serialize var serializer = env.container.lookup("serializer:superVillain"); // records with an id, persisted + var tom, json; + + run(function(){ + tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + }); - var tom = env.store.createRecord( - SuperVillain, - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) - } - ); + run(function(){ + json = serializer.serialize(tom); + }); - var json = serializer.serialize(tom); deepEqual(json, { first_name: get(tom, "firstName"), last_name: get(tom, "lastName"), @@ -836,16 +931,21 @@ test("serialize with embedded object (belongsTo relationship) supports serialize var serializer = env.container.lookup("serializer:superVillain"); // records with an id, persisted + var tom, json; + run(function(){ + tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + }); - var tom = env.store.createRecord( - SuperVillain, - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) - } - ); + run(function(){ + json = serializer.serialize(tom); + }); - var json = serializer.serialize(tom); deepEqual(json, { first_name: get(tom, "firstName"), last_name: get(tom, "lastName"), @@ -860,15 +960,22 @@ test("serialize with embedded object (belongsTo relationship) serializes the id // records with an id, persisted - var tom = env.store.createRecord( - SuperVillain, - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) - } - ); + var tom, json; + + run(function(){ + tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + }); + + run(function(){ + json = serializer.serialize(tom); + }); - var json = serializer.serialize(tom); deepEqual(json, { first_name: get(tom, "firstName"), last_name: get(tom, "lastName"), @@ -885,15 +992,21 @@ test("when related record is not present, serialize embedded record (with a belo } })); var serializer = env.container.lookup("serializer:superVillain"); + var tom, json; - var tom = env.store.createRecord( - SuperVillain, - { firstName: "Tom", lastName: "Dale", id: "1", - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) - } - ); + run(function(){ + tom = env.store.createRecord( + SuperVillain, + { firstName: "Tom", lastName: "Dale", id: "1", + homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + } + ); + }); + + run(function(){ + json = serializer.serialize(tom); + }); - var json = serializer.serialize(tom); deepEqual(json, { first_name: get(tom, "firstName"), last_name: get(tom, "lastName"), @@ -933,7 +1046,11 @@ test("extractSingle with multiply-nested belongsTo", function() { } } }; - var json = serializer.extractSingle(env.store, EvilMinion, json_hash); + var json; + + run(function(){ + json = serializer.extractSingle(env.store, EvilMinion, json_hash); + }); deepEqual(json, { id: "1", @@ -978,8 +1095,11 @@ test("extractSingle with polymorphic hasMany", function() { ] } }; + var json; - var json = serializer.extractSingle(env.store, SuperVillain, json_hash); + run(function(){ + json = serializer.extractSingle(env.store, SuperVillain, json_hash); + }); deepEqual(json, { id: "1", @@ -998,15 +1118,17 @@ test("extractSingle with polymorphic hasMany", function() { }); test("Mixin can be used with RESTSerializer which does not define keyForAttribute", function() { - homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); - secretLab = env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); - superVillain = env.store.createRecord(SuperVillain, { - id: "1", firstName: "Super", lastName: "Villian", homePlanet: homePlanet, secretLab: secretLab + run(function(){ + homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); + secretLab = env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); + superVillain = env.store.createRecord(SuperVillain, { + id: "1", firstName: "Super", lastName: "Villian", homePlanet: homePlanet, secretLab: secretLab + }); + secretWeapon = env.store.createRecord(SecretWeapon, { id: "1", name: "Secret Weapon", superVillain: superVillain }); + superVillain.get('secretWeapons').pushObject(secretWeapon); + evilMinion = env.store.createRecord(EvilMinion, { id: "1", name: "Evil Minion", superVillian: superVillain }); + superVillain.get('evilMinions').pushObject(evilMinion); }); - secretWeapon = env.store.createRecord(SecretWeapon, { id: "1", name: "Secret Weapon", superVillain: superVillain }); - superVillain.get('secretWeapons').pushObject(secretWeapon); - evilMinion = env.store.createRecord(EvilMinion, { id: "1", name: "Evil Minion", superVillian: superVillain }); - superVillain.get('evilMinions').pushObject(evilMinion); env.container.register('serializer:evilMinion', DS.RESTSerializer); env.container.register('serializer:secretWeapon', DS.RESTSerializer); @@ -1016,8 +1138,12 @@ test("Mixin can be used with RESTSerializer which does not define keyForAttribut } })); var serializer = env.container.lookup("serializer:superVillain"); + var json; + + run(function(){ + json = serializer.serialize(superVillain); + }); - var json = serializer.serialize(superVillain); deepEqual(json, { firstName: get(superVillain, "firstName"), lastName: get(superVillain, "lastName"), @@ -1056,7 +1182,11 @@ test("normalize with custom belongsTo primary key", function() { } } }; - var json = serializer.extractSingle(env.store, EvilMinion, json_hash); + var json; + + run(function(){ + json = serializer.extractSingle(env.store, EvilMinion, json_hash); + }); deepEqual(json, { id: "1", @@ -1068,15 +1198,17 @@ test("normalize with custom belongsTo primary key", function() { }); test("serializing relationships with an embedded and without calls super when not attr not present", function() { - homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); - secretLab = env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); - superVillain = env.store.createRecord(SuperVillain, { - id: "1", firstName: "Super", lastName: "Villian", homePlanet: homePlanet, secretLab: secretLab + run(function(){ + homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); + secretLab = env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); + superVillain = env.store.createRecord(SuperVillain, { + id: "1", firstName: "Super", lastName: "Villian", homePlanet: homePlanet, secretLab: secretLab + }); + secretWeapon = env.store.createRecord(SecretWeapon, { id: "1", name: "Secret Weapon", superVillain: superVillain }); + superVillain.get('secretWeapons').pushObject(secretWeapon); + evilMinion = env.store.createRecord(EvilMinion, { id: "1", name: "Evil Minion", superVillian: superVillain }); + superVillain.get('evilMinions').pushObject(evilMinion); }); - secretWeapon = env.store.createRecord(SecretWeapon, { id: "1", name: "Secret Weapon", superVillain: superVillain }); - superVillain.get('secretWeapons').pushObject(secretWeapon); - evilMinion = env.store.createRecord(EvilMinion, { id: "1", name: "Evil Minion", superVillian: superVillain }); - superVillain.get('evilMinions').pushObject(evilMinion); var calledSerializeBelongsTo = false, calledSerializeHasMany = false; @@ -1108,7 +1240,11 @@ test("serializing relationships with an embedded and without calls super when no })); var serializer = env.container.lookup("serializer:superVillain"); - var json = serializer.serialize(superVillain); + var json; + run(function(){ + json = serializer.serialize(superVillain); + }); + deepEqual(json, { firstName: get(superVillain, "firstName"), lastName: get(superVillain, "lastName"), diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index 813b7291fa9..7a3c3fea290 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -1,5 +1,6 @@ var get = Ember.get; var Post, post, Comment, comment, env; +var run = Ember.run; module("integration/serializer/json - JSONSerializer", { setup: function() { @@ -20,12 +21,14 @@ module("integration/serializer/json - JSONSerializer", { }, teardown: function() { - env.store.destroy(); + run(env.store, 'destroy'); } }); test("serializeAttribute", function() { - post = env.store.createRecord("post", { title: "Rails is omakase"}); + run(function(){ + post = env.store.createRecord("post", { title: "Rails is omakase"}); + }); var json = {}; env.serializer.serializeAttribute(post, json, "title", {type: "string"}); @@ -42,7 +45,9 @@ test("serializeAttribute respects keyForAttribute", function() { } })); - post = env.store.createRecord("post", { title: "Rails is omakase"}); + run(function(){ + post = env.store.createRecord("post", { title: "Rails is omakase"}); + }); var json = {}; env.container.lookup("serializer:post").serializeAttribute(post, json, "title", {type: "string"}); @@ -54,8 +59,11 @@ test("serializeAttribute respects keyForAttribute", function() { }); test("serializeBelongsTo", function() { - post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1"}); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + run(function(){ + post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1"}); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + }); + var json = {}; env.serializer.serializeBelongsTo(comment, json, {key: "post", options: {}}); @@ -66,7 +74,9 @@ test("serializeBelongsTo", function() { }); test("serializeBelongsTo with null", function() { - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: null}); + run(function(){ + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: null}); + }); var json = {}; env.serializer.serializeBelongsTo(comment, json, {key: "post", options: {}}); @@ -80,7 +90,9 @@ test("async serializeBelongsTo with null", function() { Comment.reopen({ post: DS.belongsTo('post', {async:true}) }); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: null}); + run(function(){ + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: null}); + }); var json = {}; env.serializer.serializeBelongsTo(comment, json, {key: "post", options: {}}); @@ -96,8 +108,10 @@ test("serializeBelongsTo respects keyForRelationship", function() { return key.toUpperCase(); } })); - post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1"}); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + run(function(){ + post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1"}); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + }); var json = {}; env.container.lookup("serializer:post").serializeBelongsTo(comment, json, {key: "post", options: {}}); @@ -113,8 +127,12 @@ test("serializeHasMany respects keyForRelationship", function() { return key.toUpperCase(); } })); - post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1"}); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post, id: "1"}); + + run(function(){ + post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1"}); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post, id: "1"}); + }); + var json = {}; env.container.lookup("serializer:post").serializeHasMany(post, json, {key: "comments", options: {}}); @@ -125,7 +143,10 @@ test("serializeHasMany respects keyForRelationship", function() { }); test("serializeIntoHash", function() { - post = env.store.createRecord("post", { title: "Rails is omakase"}); + run(function(){ + post = env.store.createRecord("post", { title: "Rails is omakase"}); + }); + var json = {}; env.serializer.serializeIntoHash(json, Post, post); @@ -145,8 +166,11 @@ test("serializePolymorphicType", function() { } })); - post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1"}); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + run(function(){ + post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1"}); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + }); + var json = {}; env.container.lookup("serializer:comment").serializeBelongsTo(comment, json, {key: "post", options: { polymorphic: true}}); @@ -171,7 +195,9 @@ test("extractArray normalizes each record in the array", function() { } })); - env.container.lookup("serializer:post").extractArray(env.store, Post, posts); + run(function(){ + env.container.lookup("serializer:post").extractArray(env.store, Post, posts); + }); equal(postNormalizeCount, 2, "two posts are normalized"); }); @@ -204,9 +230,12 @@ test('Serializer should respect the attrs hash when serializing records', functi parentPost: {key: 'my_parent'} } })); + var parentPost; - var parentPost = env.store.push("post", { id:2, title: "Rails is omakase"}); - post = env.store.createRecord("post", { title: "Rails is omakase", parentPost: parentPost}); + run(function(){ + parentPost = env.store.push("post", { id:2, title: "Rails is omakase"}); + post = env.store.createRecord("post", { title: "Rails is omakase", parentPost: parentPost}); + }); var payload = env.container.lookup("serializer:post").serialize(post); @@ -222,7 +251,9 @@ test('Serializer respects `serialize: false` on the attrs hash', function(){ } })); - post = env.store.createRecord("post", { title: "Rails is omakase"}); + run(function(){ + post = env.store.createRecord("post", { title: "Rails is omakase"}); + }); var payload = env.container.lookup("serializer:post").serialize(post); @@ -238,8 +269,10 @@ test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` p } })); - post = env.store.createRecord("post", { title: "Rails is omakase"}); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + run(function(){ + post = env.store.createRecord("post", { title: "Rails is omakase"}); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + }); var serializer = env.container.lookup("serializer:post"); var serializedProperty = serializer.keyForRelationship('comments', 'hasMany'); @@ -256,8 +289,10 @@ test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` } })); - post = env.store.createRecord("post", { title: "Rails is omakase"}); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + run(function(){ + post = env.store.createRecord("post", { title: "Rails is omakase"}); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + }); var serializer = env.container.lookup("serializer:comment"); var serializedProperty = serializer.keyForRelationship('post', 'belongsTo'); @@ -273,7 +308,9 @@ test("Serializer should respect the primaryKey attribute when extracting records var jsonHash = { "_ID_": 1, title: "Rails is omakase"}; - post = env.container.lookup("serializer:post").extractSingle(env.store, Post, jsonHash); + run(function(){ + post = env.container.lookup("serializer:post").extractSingle(env.store, Post, jsonHash); + }); equal(post.id, "1"); equal(post.title, "Rails is omakase"); @@ -284,7 +321,9 @@ test("Serializer should respect the primaryKey attribute when serializing record primaryKey: '_ID_' })); - post = env.store.createRecord("post", { id: "1", title: "Rails is omakase"}); + run(function(){ + post = env.store.createRecord("post", { id: "1", title: "Rails is omakase"}); + }); var payload = env.container.lookup("serializer:post").serialize(post, {includeId: true}); @@ -334,7 +373,9 @@ test("normalizePayload is called during extractSingle", function() { } }; - post = env.container.lookup("serializer:post").extractSingle(env.store, Post, jsonHash); + run(function(){ + post = env.container.lookup("serializer:post").extractSingle(env.store, Post, jsonHash); + }); equal(post.id, "1"); equal(post.title, "Rails is omakase"); diff --git a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js index 398c3b6ef4a..05a795dacb7 100644 --- a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js @@ -45,7 +45,7 @@ module("integration/serializer/rest - RESTSerializer", { }, teardown: function() { - env.store.destroy(); + run(env.store,'destroy'); } }); @@ -67,8 +67,11 @@ test("extractArray with custom typeForRoot", function() { home_planets: [{id: "1", name: "Umber", superVillains: [1]}], super_villains: [{id: "1", firstName: "Tom", lastName: "Dale", homePlanet: "1"}] }; + var array; - var array = env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); + run(function(){ + array = env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); + }); deepEqual(array, [{ "id": "1", @@ -106,7 +109,9 @@ test("extractArray warning with custom typeForRoot", function() { }; noWarns(function(){ - homePlanets = Ember.A(env.restSerializer.extractArray(env.store, HomePlanet, jsonHash)); + run(function(){ + homePlanets = Ember.A(env.restSerializer.extractArray(env.store, HomePlanet, jsonHash)); + }); }); equal(get(homePlanets, "length"), 1); @@ -126,7 +131,9 @@ test("extractSingle warning with custom typeForRoot", function() { }; warns(Ember.run.bind(null, function(){ - env.restSerializer.extractSingle(env.store, HomePlanet, jsonHash); + run(function(){ + env.restSerializer.extractSingle(env.store, HomePlanet, jsonHash); + }); }), /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); // should not warn if a model is found. @@ -139,7 +146,9 @@ test("extractSingle warning with custom typeForRoot", function() { }; noWarns(function(){ - homePlanet = env.restSerializer.extractSingle(env.store, HomePlanet, jsonHash); + run(function(){ + homePlanet = env.restSerializer.extractSingle(env.store, HomePlanet, jsonHash); + }); }); equal(get(homePlanet, "name"), "Umber"); @@ -172,7 +181,9 @@ test("pushPayload - single record payload - warning with custom typeForRoot", fu }; warns(function(){ - env.store.pushPayload("homePlanet", jsonHash); + run(function(){ + env.store.pushPayload("homePlanet", jsonHash); + }); }, /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); @@ -200,8 +211,8 @@ test("pushPayload - single record payload - warning with custom typeForRoot", fu }; noWarns(function(){ - env.store.pushPayload("homePlanet", jsonHash); run(function(){ + env.store.pushPayload("homePlanet", jsonHash); homePlanet = env.store.getById("homePlanet", "1"); }); }); @@ -236,7 +247,9 @@ test("pushPayload - multiple record payload (extractArray) - warning with custom }; warns(function(){ - env.store.pushPayload("homePlanet", jsonHash); + run(function(){ + env.store.pushPayload("homePlanet", jsonHash); + }); }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); // assert non-warned records get pushed into store correctly @@ -263,8 +276,8 @@ test("pushPayload - multiple record payload (extractArray) - warning with custom }; noWarns(function(){ - env.store.pushPayload("homePlanet", jsonHash); run(function(){ + env.store.pushPayload("homePlanet", jsonHash); homePlanet = env.store.getById("homePlanet", "1"); }); }); @@ -274,8 +287,11 @@ test("pushPayload - multiple record payload (extractArray) - warning with custom }); test("serialize polymorphicType", function() { - var tom = env.store.createRecord(YellowMinion, {name: "Alex", id: "124"}); - var ray = env.store.createRecord(DoomsdayDevice, {evilMinion: tom, name: "DeathRay"}); + var tom, ray; + run(function(){ + tom = env.store.createRecord(YellowMinion, {name: "Alex", id: "124"}); + ray = env.store.createRecord(DoomsdayDevice, {evilMinion: tom, name: "DeathRay"}); + }); var json = env.restSerializer.serialize(ray); @@ -288,8 +304,11 @@ test("serialize polymorphicType", function() { test("serialize polymorphicType with decamelized typeKey", function() { YellowMinion.typeKey = 'yellow-minion'; - var tom = env.store.createRecord(YellowMinion, {name: "Alex", id: "124"}); - var ray = env.store.createRecord(DoomsdayDevice, {evilMinion: tom, name: "DeathRay"}); + var tom, ray; + run(function(){ + tom = env.store.createRecord(YellowMinion, {name: "Alex", id: "124"}); + ray = env.store.createRecord(DoomsdayDevice, {evilMinion: tom, name: "DeathRay"}); + }); var json = env.restSerializer.serialize(ray); @@ -309,13 +328,20 @@ test("normalizePayload is called during extractSingle", function() { } }; var applicationSerializer = env.container.lookup('serializer:application'); - var data = applicationSerializer.extractSingle(env.store, EvilMinion, jsonHash); + var data; + + run(function(){ + data = applicationSerializer.extractSingle(env.store, EvilMinion, jsonHash); + }); equal(data.name, jsonHash.response.evilMinion.name, "normalize reads off the response"); }); test("serialize polymorphic when associated object is null", function() { - var ray = env.store.createRecord(DoomsdayDevice, {name: "DeathRay"}); + var ray; + run(function(){ + ray = env.store.createRecord(DoomsdayDevice, {name: "DeathRay"}); + }); var json = env.restSerializer.serialize(ray); @@ -330,8 +356,11 @@ test("extractArray can load secondary records of the same type without affecting { id: "3", body: "Child Comment 2", root: false } ] }; + var array; - var array = env.restSerializer.extractArray(env.store, Comment, jsonHash); + run(function(){ + array = env.restSerializer.extractArray(env.store, Comment, jsonHash); + }); deepEqual(array, [{ "id": "1", @@ -361,7 +390,9 @@ test("extractSingle loads secondary records with correct serializer", function() superVillains: [{id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1"}] }; - env.restSerializer.extractSingle(env.store, EvilMinion, jsonHash); + run(function(){ + env.restSerializer.extractSingle(env.store, EvilMinion, jsonHash); + }); equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); }); @@ -372,8 +403,11 @@ test("extractSingle returns null if payload contains null", function() { var jsonHash = { evilMinion: null }; + var value; - var value = env.restSerializer.extractSingle(env.store, EvilMinion, jsonHash); + run(function(){ + value = env.restSerializer.extractSingle(env.store, EvilMinion, jsonHash); + }); equal(value, null, "returned value is null"); }); @@ -393,7 +427,9 @@ test("extractArray loads secondary records with correct serializer", function() superVillains: [{id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1"}] }; - env.restSerializer.extractArray(env.store, EvilMinion, jsonHash); + run(function(){ + env.restSerializer.extractArray(env.store, EvilMinion, jsonHash); + }); equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); }); @@ -410,8 +446,11 @@ test('normalizeHash normalizes specific parts of the payload', function(){ })); var jsonHash = { homePlanets: [{_id: "1", name: "Umber", superVillains: [1]}] }; + var array; - var array = env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); + run(function(){ + array = env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); + }); deepEqual(array, [{ "id": "1", @@ -453,8 +492,11 @@ test('normalizeHash works with transforms', function(){ var jsonHash = { evilMinions: [{id: "1", name: "Tom Dale", superVillain: 1, _condition: 1}] }; + var array; - var array = env.restSerializer.extractArray(env.store, EvilMinion, jsonHash); + run(function(){ + array = env.restSerializer.extractArray(env.store, EvilMinion, jsonHash); + }); equal(array[0].condition, "healing"); }); @@ -472,14 +514,19 @@ test('normalize should allow for different levels of normalization', function(){ var jsonHash = { evilMinions: [{id: "1", name: "Tom Dale", is_super_villain: 1}] }; + var array; - var array = env.restSerializer.extractArray(env.store, EvilMinion, jsonHash); + run(function(){ + array = env.restSerializer.extractArray(env.store, EvilMinion, jsonHash); + }); equal(array[0].superVillain, 1); }); test("serializeIntoHash", function() { - league = env.store.createRecord(HomePlanet, { name: "Umber", id: "123" }); + run(function(){ + league = env.store.createRecord(HomePlanet, { name: "Umber", id: "123" }); + }); var json = {}; env.restSerializer.serializeIntoHash(json, HomePlanet, league); @@ -493,7 +540,9 @@ test("serializeIntoHash", function() { test("serializeIntoHash with decamelized typeKey", function() { HomePlanet.typeKey = 'home-planet'; - league = env.store.createRecord(HomePlanet, { name: "Umber", id: "123" }); + run(function(){ + league = env.store.createRecord(HomePlanet, { name: "Umber", id: "123" }); + }); var json = {}; env.restSerializer.serializeIntoHash(json, HomePlanet, league); diff --git a/packages/ember-data/tests/integration/store_test.js b/packages/ember-data/tests/integration/store_test.js index 780134c8af3..d7322a03290 100644 --- a/packages/ember-data/tests/integration/store_test.js +++ b/packages/ember-data/tests/integration/store_test.js @@ -5,6 +5,8 @@ var Person = DS.Model.extend({ cars: DS.hasMany('car') }); +var run = Ember.run; + Person.toString = function() { return "Person"; }; var Car = DS.Model.extend({ @@ -71,7 +73,9 @@ asyncTest("destroying record during find doesn't cause error", function() { start(); } - store.find(type, id).then(done, done); + run(function(){ + store.find(type, id).then(done, done); + }); }); asyncTest("find calls do not resolve when the store is destroyed", function() { @@ -96,7 +100,9 @@ asyncTest("find calls do not resolve when the store is destroyed", function() { throw new Error("We shouldn't be pushing data into the store when it is destroyed"); }; - store.find(type, id); + run(function(){ + store.find(type, id); + }); setTimeout(function() { start(); @@ -105,17 +111,20 @@ asyncTest("find calls do not resolve when the store is destroyed", function() { test("destroying the store correctly cleans everything up", function() { - var car = store.push('car', { - id: 1, - make: 'BMC', - model: 'Mini', - person: 1 - }); + var car, person; + run(function(){ + car = store.push('car', { + id: 1, + make: 'BMC', + model: 'Mini', + person: 1 + }); - var person = store.push('person', { - id: 1, - name: 'Tom Dale', - cars: [1] + person = store.push('person', { + id: 1, + name: 'Tom Dale', + cars: [1] + }); }); var personWillDestroy = tap(person, 'willDestroy'); @@ -128,17 +137,24 @@ test("destroying the store correctly cleans everything up", function() { name: 'Yehuda' }]; }; + var adapterPopulatedPeople, filterdPeople; - var adapterPopulatedPeople = store.find('person', { - someCrazy: 'query' + run(function(){ + adapterPopulatedPeople = store.find('person', { + someCrazy: 'query' + }); }); - var filterdPeople = store.filter('person', function(){ return true; }); + run(function(){ + filterdPeople = store.filter('person', function(){ return true; }); + }); var filterdPeopleWillDestroy = tap(filterdPeople.content, 'willDestroy'); var adapterPopulatedPeopleWillDestroy = tap(adapterPopulatedPeople.content, 'willDestroy'); - store.find('person', 2); + run(function(){ + store.find('person', 2); + }); equal(personWillDestroy.called.length, 0, 'expected person.willDestroy to not have been called'); equal(carWillDestroy.called.length, 0, 'expected car.willDestroy to not have been called'); @@ -171,6 +187,7 @@ module("integration/store - fetch", { }); function ajaxResponse(value) { + var passedUrl, passedVerb, passedHash; env.adapter.ajax = function(url, verb, hash) { passedUrl = url; passedVerb = verb; @@ -182,13 +199,16 @@ function ajaxResponse(value) { test("Using store#fetch on existing record reloads it", function() { expect(2); + var car; - var car = store.push('car', { - id: 1, - make: 'BMC', - model: 'Mini' - }); + run(function(){ + car = store.push('car', { + id: 1, + make: 'BMC', + model: 'Mini' + }); + }); ajaxResponse({ cars: [{ id: 1, @@ -199,8 +219,10 @@ test("Using store#fetch on existing record reloads it", function() { equal(car.get('make'), 'BMC'); - store.fetch('car', 1).then(function (car) { - equal(car.get('make'), 'BMCW'); + run(function(){ + store.fetch('car', 1).then(async(function(car) { + equal(car.get('make'), 'BMCW'); + })); }); }); @@ -218,7 +240,9 @@ test("Using store#fetch on non existing record calls find", function() { var car = store.hasRecordForId('car', 20); ok(!car, 'Car with id=20 should not exist'); - store.fetch('car', 20).then(function (car) { - equal(car.get('make'), 'BMCW', 'Car with id=20 is now loaded'); + run(function(){ + store.fetch('car', 20).then(async(function (car) { + equal(car.get('make'), 'BMCW', 'Car with id=20 is now loaded'); + })); }); }); diff --git a/packages/ember-data/tests/unit/adapters/rest_adapter/ajax.js b/packages/ember-data/tests/unit/adapters/rest_adapter/ajax.js index 27ece8fc546..a1316933a86 100644 --- a/packages/ember-data/tests/unit/adapters/rest_adapter/ajax.js +++ b/packages/ember-data/tests/unit/adapters/rest_adapter/ajax.js @@ -1,4 +1,5 @@ var Person, Place, store, adapter, env; +var run = Ember.run; module("integration/adapter/ajax - building requests", { setup: function() { @@ -10,9 +11,10 @@ module("integration/adapter/ajax - building requests", { }, teardown: function() { - store.destroy(); - env.container.destroy(); - + run(function(){ + store.destroy(); + env.container.destroy(); + }); } }); @@ -25,8 +27,10 @@ test("When an id is searched, the correct url should be generated", function() { count++; return Ember.RSVP.resolve(); }; - adapter.find(store, Person, 1); - adapter.find(store, Place, 1); + run(function(){ + adapter.find(store, Person, 1); + adapter.find(store, Place, 1); + }); }); test("id's should be sanatized", function() { expect(1); @@ -34,5 +38,7 @@ test("id's should be sanatized", function() { equal(url, '/people/..%2Fplace%2F1', "should create the correct url"); return Ember.RSVP.resolve(); }; - adapter.find(store, Person, '../place/1'); + run(function(){ + adapter.find(store, Person, '../place/1'); + }); }); diff --git a/packages/ember-data/tests/unit/debug_test.js b/packages/ember-data/tests/unit/debug_test.js index 6df50a9844a..985fed020c0 100644 --- a/packages/ember-data/tests/unit/debug_test.js +++ b/packages/ember-data/tests/unit/debug_test.js @@ -1,4 +1,5 @@ var store; +var run = Ember.run; var TestAdapter = DS.Adapter.extend(); @@ -10,8 +11,10 @@ module("Debug", { }, teardown: function() { - store.destroy(); - store = null; + run(function(){ + store.destroy(); + store = null; + }); } }); @@ -30,8 +33,11 @@ test("_debugInfo groups the attributes and relationships correctly", function() maritalStatus: DS.belongsTo(MaritalStatus), posts: DS.hasMany(Post) }); + var record; - var record = store.createRecord(User); + run(function(){ + record = store.createRecord(User); + }); var propertyInfo = record._debugInfo().propertyInfo; diff --git a/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js b/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js index 62f695dc60a..bd7e1b3cab3 100644 --- a/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js +++ b/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js @@ -1,4 +1,5 @@ var get = Ember.get; +var run = Ember.run; module("unit/model/lifecycle_callbacks - Lifecycle Callbacks"); @@ -20,10 +21,12 @@ test("a record receives a didLoad callback when it has finished loading", functi adapter: adapter }); - store.find(Person, 1).then(async(function(person) { - equal(person.get('id'), "1", "The person's ID is available"); - equal(person.get('name'), "Foo", "The person's properties are available"); - })); + run(function(){ + store.find(Person, 1).then(async(function(person) { + equal(person.get('id'), "1", "The person's ID is available"); + equal(person.get('name'), "Foo", "The person's properties are available"); + })); + }); }); test("a record receives a didUpdate callback when it has finished updating", function() { @@ -54,13 +57,18 @@ test("a record receives a didUpdate callback when it has finished updating", fun var store = createStore({ adapter: adapter }); + var asyncPerson; - var asyncPerson = store.find(Person, 1); + run(function(){ + asyncPerson = store.find(Person, 1); + }); equal(callCount, 0, "precond - didUpdate callback was not called yet"); asyncPerson.then(async(function(person) { - person.set('bar', "Bar"); - return person.save(); + return run(function(){ + person.set('bar', "Bar"); + return person.save(); + }); })).then(async(function() { equal(callCount, 1, "didUpdate called after update"); })); @@ -90,12 +98,18 @@ test("a record receives a didCreate callback when it has finished updating", fun }); equal(callCount, 0, "precond - didCreate callback was not called yet"); + var person; - var person = store.createRecord(Person, { id: 69, name: "Newt Gingrich" }); + run(function(){ + person = store.createRecord(Person, { id: 69, name: "Newt Gingrich" }); + }); - person.save().then(async(function() { - equal(callCount, 1, "didCreate called after commit"); - })); + + run(function(){ + person.save().then(async(function() { + equal(callCount, 1, "didCreate called after commit"); + })); + }); }); test("a record receives a didDelete callback when it has finished deleting", function() { @@ -127,13 +141,19 @@ test("a record receives a didDelete callback when it has finished deleting", fun var store = createStore({ adapter: adapter }); + var asyncPerson; + + run(function(){ + asyncPerson = store.find(Person, 1); + }); - var asyncPerson = store.find(Person, 1); equal(callCount, 0, "precond - didDelete callback was not called yet"); asyncPerson.then(async(function(person) { - person.deleteRecord(); - return person.save(); + return run(function(){ + person.deleteRecord(); + return person.save(); + }); })).then(async(function() { equal(callCount, 1, "didDelete called after delete"); })); @@ -168,16 +188,21 @@ test("a record receives a becameInvalid callback when it became invalid", functi var store = createStore({ adapter: adapter }); + var asyncPerson; - var asyncPerson = store.find(Person, 1); + run(function(){ + asyncPerson = store.find(Person, 1); + }); equal(callCount, 0, "precond - becameInvalid callback was not called yet"); // Make sure that the error handler has a chance to attach before // save fails. - Ember.run(function() { + run(function() { asyncPerson.then(async(function(person) { - person.set('bar', "Bar"); - return person.save(); + return run(function(){ + person.set('bar', "Bar"); + return person.save(); + }); })).then(null, async(function() { equal(callCount, 1, "becameInvalid called after invalidating"); })); @@ -191,6 +216,9 @@ test("an ID of 0 is allowed", function() { name: DS.attr('string') }); - store.push(Person, { id: 0, name: "Tom Dale" }); + run(function(){ + store.push(Person, { id: 0, name: "Tom Dale" }); + }); + equal(store.all(Person).objectAt(0).get('name'), "Tom Dale", "found record with id 0"); }); diff --git a/packages/ember-data/tests/unit/model/merge_test.js b/packages/ember-data/tests/unit/model/merge_test.js index e52ee1c1290..ce68bae0a9d 100644 --- a/packages/ember-data/tests/unit/model/merge_test.js +++ b/packages/ember-data/tests/unit/model/merge_test.js @@ -1,4 +1,5 @@ var Person; +var run = Ember.run; module("unit/model/merge - Merging", { setup: function() { @@ -19,10 +20,13 @@ test("When a record is in flight, changes can be made", function() { return Ember.RSVP.resolve({ id: 1, name: "Tom Dale" }); } }); + var person; var store = createStore({ adapter: adapter }); - var person = store.createRecord(Person, { name: "Tom Dale" }); + run(function(){ + person = store.createRecord(Person, { name: "Tom Dale" }); + }); // Make sure saving isn't resolved synchronously Ember.run(function() { @@ -32,10 +36,10 @@ test("When a record is in flight, changes can be made", function() { person.set('name', "Thomas Dale"); - promise.then(function(person) { + promise.then(async(function(person) { equal(person.get('isDirty'), true, "The person is still dirty"); equal(person.get('name'), "Thomas Dale", "The changes made still apply"); - }); + })); }); }); @@ -47,9 +51,12 @@ test("When a record is in flight, pushes are applied underneath the in flight ch }); var store = createStore({ adapter: adapter }); + var person; - var person = store.push(Person, { id: 1, name: "Tom" }); - person.set('name', "Thomas Dale"); + run(function(){ + person = store.push(Person, { id: 1, name: "Tom" }); + person.set('name', "Thomas Dale"); + }); // Make sure saving isn't resolved synchronously Ember.run(function() { @@ -64,26 +71,30 @@ test("When a record is in flight, pushes are applied underneath the in flight ch equal(person.get('name'), "Tomasz Dale", "the local changes applied on top"); equal(person.get('city'), "PDX", "the pushed change is available"); - promise.then(function(person) { + promise.then(async(function(person) { equal(person.get('isDirty'), true, "The person is still dirty"); equal(person.get('name'), "Tomasz Dale", "The local changes apply"); equal(person.get('city'), "Portland", "The updates from the server apply on top of the previous pushes"); - }); + })); }); }); test("When a record is dirty, pushes are overridden by local changes", function() { var store = createStore({ adapter: DS.Adapter }); + var person; - var person = store.push(Person, { id: 1, name: "Tom Dale", city: "San Francisco" }); - - person.set('name', "Tomasz Dale"); + run(function(){ + person = store.push(Person, { id: 1, name: "Tom Dale", city: "San Francisco" }); + person.set('name', "Tomasz Dale"); + }); equal(person.get('isDirty'), true, "the person is currently dirty"); equal(person.get('name'), "Tomasz Dale", "the update was effective"); equal(person.get('city'), "San Francisco", "the original data applies"); - store.push(Person, { id: 1, name: "Thomas Dale", city: "Portland" }); + run(function(){ + store.push(Person, { id: 1, name: "Thomas Dale", city: "Portland" }); + }); equal(person.get('isDirty'), true, "the local changes are reapplied"); equal(person.get('name'), "Tomasz Dale", "the local changes are reapplied"); @@ -98,12 +109,17 @@ test("A record with no changes can still be saved", function() { }); var store = createStore({ adapter: adapter }); + var person; - var person = store.push(Person, { id: 1, name: "Tom Dale" }); + run(function(){ + person = store.push(Person, { id: 1, name: "Tom Dale" }); + }); - person.save().then(async(function() { - equal(person.get('name'), "Thomas Dale", "the updates occurred"); - })); + run(function(){ + person.save().then(async(function() { + equal(person.get('name'), "Thomas Dale", "the updates occurred"); + })); + }); }); test("A dirty record can be reloaded", function() { @@ -114,14 +130,18 @@ test("A dirty record can be reloaded", function() { }); var store = createStore({ adapter: adapter }); + var person; - var person = store.push(Person, { id: 1, name: "Tom Dale" }); - - person.set('name', "Tomasz Dale"); + run(function(){ + person = store.push(Person, { id: 1, name: "Tom Dale" }); + person.set('name', "Tomasz Dale"); + }); - person.reload().then(async(function() { - equal(person.get('isDirty'), true, "the person is dirty"); - equal(person.get('name'), "Tomasz Dale", "the local changes remain"); - equal(person.get('city'), "Portland", "the new changes apply"); - })); + run(function(){ + person.reload().then(async(function() { + equal(person.get('isDirty'), true, "the person is dirty"); + equal(person.get('name'), "Tomasz Dale", "the local changes remain"); + equal(person.get('city'), "Portland", "the new changes apply"); + })); + }); }); diff --git a/packages/ember-data/tests/unit/model/relationships_test.js b/packages/ember-data/tests/unit/model/relationships_test.js index d23b02477ed..aa1ff9672ab 100644 --- a/packages/ember-data/tests/unit/model/relationships_test.js +++ b/packages/ember-data/tests/unit/model/relationships_test.js @@ -1,4 +1,5 @@ var get = Ember.get, set = Ember.set; +var run = Ember.run; module("unit/model/relationships - DS.Model"); @@ -63,44 +64,57 @@ test("hasMany handles pre-loaded relationships", function() { var store = env.store; - store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); - store.pushMany('pet', [{ id: 4, name: "fluffy" }, { id: 7, name: "snowy" }, { id: 12, name: "cerberus" }]); - store.push('person', { id: 1, name: "Tom Dale", tags: [5] }); - store.push('person', { id: 2, name: "Yehuda Katz", tags: [12] }); + run(function(){ + store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); + store.pushMany('pet', [{ id: 4, name: "fluffy" }, { id: 7, name: "snowy" }, { id: 12, name: "cerberus" }]); + store.push('person', { id: 1, name: "Tom Dale", tags: [5] }); + store.push('person', { id: 2, name: "Yehuda Katz", tags: [12] }); + }); + + run(function(){ + store.find('person', 1).then(async(function(person) { + equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - store.find('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + var tags = get(person, 'tags'); + equal(get(tags, 'length'), 1, "the list of tags should have the correct length"); + equal(get(tags.objectAt(0), 'name'), "friendly", "the first tag should be a Tag"); - var tags = get(person, 'tags'); - equal(get(tags, 'length'), 1, "the list of tags should have the correct length"); - equal(get(tags.objectAt(0), 'name'), "friendly", "the first tag should be a Tag"); + run(function(){ + store.push('person', { id: 1, name: "Tom Dale", tags: [5, 2] }); + }); - store.push('person', { id: 1, name: "Tom Dale", tags: [5, 2] }); - equal(tags, get(person, 'tags'), "a relationship returns the same object every time"); - equal(get(get(person, 'tags'), 'length'), 2, "the length is updated after new data is loaded"); + equal(tags, get(person, 'tags'), "a relationship returns the same object every time"); + equal(get(get(person, 'tags'), 'length'), 2, "the length is updated after new data is loaded"); - strictEqual(get(person, 'tags').objectAt(0), get(person, 'tags').objectAt(0), "the returned object is always the same"); - asyncEqual(get(person, 'tags').objectAt(0), store.find(Tag, 5), "relationship objects are the same as objects retrieved directly"); + strictEqual(get(person, 'tags').objectAt(0), get(person, 'tags').objectAt(0), "the returned object is always the same"); + asyncEqual(get(person, 'tags').objectAt(0), store.find(Tag, 5), "relationship objects are the same as objects retrieved directly"); - store.push('person', { id: 3, name: "KSelden" }); + run(function(){ + store.push('person', { id: 3, name: "KSelden" }); + }); - return store.find('person', 3); - })).then(async(function(kselden) { - equal(get(get(kselden, 'tags'), 'length'), 0, "a relationship that has not been supplied returns an empty array"); + return store.find('person', 3); + })).then(async(function(kselden) { + equal(get(get(kselden, 'tags'), 'length'), 0, "a relationship that has not been supplied returns an empty array"); - store.push('person', { id: 4, name: "Cyvid Hamluck", pets: [4] }); - return store.find('person', 4); - })).then(async(function(cyvid) { - equal(get(cyvid, 'name'), "Cyvid Hamluck", "precond - retrieves person record from store"); + run(function(){ + store.push('person', { id: 4, name: "Cyvid Hamluck", pets: [4] }); + }); + return store.find('person', 4); + })).then(async(function(cyvid) { + equal(get(cyvid, 'name'), "Cyvid Hamluck", "precond - retrieves person record from store"); - var pets = get(cyvid, 'pets'); - equal(get(pets, 'length'), 1, "the list of pets should have the correct length"); - equal(get(pets.objectAt(0), 'name'), "fluffy", "the first pet should be correct"); + var pets = get(cyvid, 'pets'); + equal(get(pets, 'length'), 1, "the list of pets should have the correct length"); + equal(get(pets.objectAt(0), 'name'), "fluffy", "the first pet should be correct"); - store.push(Person, { id: 4, name: "Cyvid Hamluck", pets: [4, 12] }); - equal(pets, get(cyvid, 'pets'), "a relationship returns the same object every time"); - equal(get(get(cyvid, 'pets'), 'length'), 2, "the length is updated after new data is loaded"); - })); + run(function(){ + store.push(Person, { id: 4, name: "Cyvid Hamluck", pets: [4, 12] }); + }); + equal(pets, get(cyvid, 'pets'), "a relationship returns the same object every time"); + equal(get(get(cyvid, 'pets'), 'length'), 2, "the length is updated after new data is loaded"); + })); + }); }); test("hasMany lazily loads async relationships", function() { @@ -134,34 +148,43 @@ test("hasMany lazily loads async relationships", function() { var store = env.store; - store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); - store.pushMany('pet', [{ id: 4, name: "fluffy" }, { id: 7, name: "snowy" }, { id: 12, name: "cerberus" }]); - store.push('person', { id: 1, name: "Tom Dale", tags: [5] }); - store.push('person', { id: 2, name: "Yehuda Katz", tags: [12] }); + run(function(){ + store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); + store.pushMany('pet', [{ id: 4, name: "fluffy" }, { id: 7, name: "snowy" }, { id: 12, name: "cerberus" }]); + store.push('person', { id: 1, name: "Tom Dale", tags: [5] }); + store.push('person', { id: 2, name: "Yehuda Katz", tags: [12] }); + }); var wycats; - store.find('person', 2).then(async(function(person) { - wycats = person; - - equal(get(wycats, 'name'), "Yehuda Katz", "precond - retrieves person record from store"); - - return Ember.RSVP.hash({ - wycats: wycats, - tags: wycats.get('tags') - }); - })).then(async(function(records) { - equal(get(records.tags, 'length'), 1, "the list of tags should have the correct length"); - equal(get(records.tags.objectAt(0), 'name'), "oohlala", "the first tag should be a Tag"); - - strictEqual(records.tags.objectAt(0), records.tags.objectAt(0), "the returned object is always the same"); - asyncEqual(records.tags.objectAt(0), store.find(Tag, 12), "relationship objects are the same as objects retrieved directly"); - - return get(wycats, 'tags'); - })).then(async(function(tags) { - var newTag = store.createRecord(Tag); - tags.pushObject(newTag); - })); + run(function(){ + store.find('person', 2).then(async(function(person) { + wycats = person; + + equal(get(wycats, 'name'), "Yehuda Katz", "precond - retrieves person record from store"); + + return Ember.RSVP.hash({ + wycats: wycats, + tags: wycats.get('tags') + }); + })).then(async(function(records) { + equal(get(records.tags, 'length'), 1, "the list of tags should have the correct length"); + equal(get(records.tags.objectAt(0), 'name'), "oohlala", "the first tag should be a Tag"); + + strictEqual(records.tags.objectAt(0), records.tags.objectAt(0), "the returned object is always the same"); + asyncEqual(records.tags.objectAt(0), store.find(Tag, 12), "relationship objects are the same as objects retrieved directly"); + + return run(function(){ + return get(wycats, 'tags'); + }); + })).then(async(function(tags) { + var newTag; + run(function(){ + newTag = store.createRecord(Tag); + tags.pushObject(newTag); + }); + })); + }); }); test("should be able to retrieve the type for a hasMany relationship from its metadata", function() { @@ -248,13 +271,17 @@ test("relationships work when declared with a string path", function() { tag: Tag }); - env.store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); - env.store.push('person', { id: 1, name: "Tom Dale", tags: [5, 2] }); + run(function(){ + env.store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); + env.store.push('person', { id: 1, name: "Tom Dale", tags: [5, 2] }); + }); - env.store.find('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - equal(get(person, 'tags.length'), 2, "the list of tags should have the correct length"); - })); + run(function(){ + env.store.find('person', 1).then(async(function(person) { + equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + equal(get(person, 'tags.length'), 2, "the list of tags should have the correct length"); + })); + }); }); test("hasMany relationships work when the data hash has not been loaded", function() { @@ -290,15 +317,19 @@ test("hasMany relationships work when the data hash has not been loaded", functi return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", tags: [5, 2] }); }; - store.find('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "The person is now populated"); + run(function(){ + store.find('person', 1).then(async(function(person) { + equal(get(person, 'name'), "Tom Dale", "The person is now populated"); - return person.get('tags'); - })).then(async(function(tags) { - equal(get(tags, 'length'), 2, "the tags object still exists"); - equal(get(tags.objectAt(0), 'name'), "friendly", "Tom Dale is now friendly"); - equal(get(tags.objectAt(0), 'isLoaded'), true, "Tom Dale is now loaded"); - })); + return run(function(){ + return person.get('tags'); + }); + })).then(async(function(tags) { + equal(get(tags, 'length'), 2, "the tags object still exists"); + equal(get(tags.objectAt(0), 'name'), "friendly", "Tom Dale is now friendly"); + equal(get(tags.objectAt(0), 'isLoaded'), true, "Tom Dale is now loaded"); + })); + }); }); test("it is possible to add a new item to a relationship", function() { @@ -319,19 +350,25 @@ test("it is possible to add a new item to a relationship", function() { var store = env.store; - store.push('person', { id: 1, name: "Tom Dale", tags: [ 1 ] }); - store.push('tag', { id: 1, name: "ember" }); + run(function(){ + store.push('person', { id: 1, name: "Tom Dale", tags: [ 1 ] }); + store.push('tag', { id: 1, name: "ember" }); + }); - store.find(Person, 1).then(async(function(person) { - var tag = get(person, 'tags').objectAt(0); + run(function(){ + store.find(Person, 1).then(async(function(person) { + var tag = get(person, 'tags').objectAt(0); - equal(get(tag, 'name'), "ember", "precond - relationships work"); + equal(get(tag, 'name'), "ember", "precond - relationships work"); - tag = store.createRecord(Tag, { name: "js" }); - get(person, 'tags').pushObject(tag); + run(function(){ + tag = store.createRecord(Tag, { name: "js" }); + get(person, 'tags').pushObject(tag); + }); - equal(get(person, 'tags').objectAt(1), tag, "newly added relationship works"); - })); + equal(get(person, 'tags').objectAt(1), tag, "newly added relationship works"); + })); + }); }); test("possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)", function(){ @@ -384,18 +421,24 @@ test("it is possible to remove an item from a relationship", function() { var env = setupStore({ tag: Tag, person: Person }), store = env.store; - store.push('person', { id: 1, name: "Tom Dale", tags: [ 1 ] }); - store.push('tag', { id: 1, name: "ember" }); + run(function(){ + store.push('person', { id: 1, name: "Tom Dale", tags: [ 1 ] }); + store.push('tag', { id: 1, name: "ember" }); + }); - store.find('person', 1).then(async(function(person) { - var tag = get(person, 'tags').objectAt(0); + run(function(){ + store.find('person', 1).then(async(function(person) { + var tag = get(person, 'tags').objectAt(0); - equal(get(tag, 'name'), "ember", "precond - relationships work"); + equal(get(tag, 'name'), "ember", "precond - relationships work"); - get(person, 'tags').removeObject(tag); + run(function(){ + get(person, 'tags').removeObject(tag); + }); - equal(get(person, 'tags.length'), 0, "object is removed from the relationship"); - })); + equal(get(person, 'tags.length'), 0, "object is removed from the relationship"); + })); + }); }); test("it is possible to add an item to a relationship, remove it, then add it again", function() { @@ -414,21 +457,30 @@ test("it is possible to add an item to a relationship, remove it, then add it ag var env = setupStore({ tag: Tag, person: Person }), store = env.store; + var person, tag1, tag2, tag3; - var person = store.createRecord('person'); - var tag1 = store.createRecord('tag'); - var tag2 = store.createRecord('tag'); - var tag3 = store.createRecord('tag'); + run(function(){ + person = store.createRecord('person'); + tag1 = store.createRecord('tag'); + tag2 = store.createRecord('tag'); + tag3 = store.createRecord('tag'); + }); var tags = get(person, 'tags'); - tags.pushObjects([tag1, tag2, tag3]); - tags.removeObject(tag2); + run(function(){ + tags.pushObjects([tag1, tag2, tag3]); + tags.removeObject(tag2); + }); + equal(tags.objectAt(0), tag1); equal(tags.objectAt(1), tag3); equal(get(person, 'tags.length'), 2, "object is removed from the relationship"); - tags.insertAt(0, tag2); + run(function(){ + tags.insertAt(0, tag2); + }); + equal(get(person, 'tags.length'), 3, "object is added back to the relationship"); equal(tags.objectAt(0), tag2); equal(tags.objectAt(1), tag1); @@ -444,15 +496,20 @@ test("updating the content of a RecordArray updates its content", function() { var env = setupStore({ tag: Tag }), store = env.store; + var records, tags; - var records = store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); - - var tags = DS.RecordArray.create({ content: Ember.A(records.slice(0, 2)), store: store, type: Tag }); + run(function(){ + records = store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); + tags = DS.RecordArray.create({ content: Ember.A(records.slice(0, 2)), store: store, type: Tag }); + }); var tag = tags.objectAt(0); equal(get(tag, 'name'), "friendly", "precond - we're working with the right tags"); - set(tags, 'content', Ember.A(records.slice(1, 3))); + run(function(){ + set(tags, 'content', Ember.A(records.slice(1, 3))); + }); + tag = tags.objectAt(0); equal(get(tag, 'name'), "smarmy", "the lookup was updated"); }); @@ -471,15 +528,19 @@ test("can create child record from a hasMany relationship", function() { var env = setupStore({ tag: Tag, person: Person }), store = env.store; - store.push('person', { id: 1, name: "Tom Dale"}); + run(function(){ + store.push('person', { id: 1, name: "Tom Dale"}); + }); - store.find('person', 1).then(async(function(person) { - person.get("tags").createRecord({ name: "cool" }); + run(function(){ + store.find('person', 1).then(async(function(person) { + person.get("tags").createRecord({ name: "cool" }); - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - equal(get(person, 'tags.length'), 1, "tag is added to the parent record"); - equal(get(person, 'tags').objectAt(0).get("name"), "cool", "tag values are passed along"); - })); + equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + equal(get(person, 'tags.length'), 1, "tag is added to the parent record"); + equal(get(person, 'tags').objectAt(0).get("name"), "cool", "tag values are passed along"); + })); + }); }); module("unit/model/relationships - DS.belongsTo"); @@ -500,18 +561,22 @@ test("belongsTo lazily loads relationships as needed", function() { var env = setupStore({ tag: Tag, person: Person }), store = env.store; - store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); - store.push('person', { id: 1, name: "Tom Dale", tag: 5 }); + run(function(){ + store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); + store.push('person', { id: 1, name: "Tom Dale", tag: 5 }); + }); - store.find('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + run(function(){ + store.find('person', 1).then(async(function(person) { + equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); - equal(get(person, 'tag.name'), "friendly", "the tag shuld have name"); + equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); + equal(get(person, 'tag.name'), "friendly", "the tag shuld have name"); - strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); - asyncEqual(get(person, 'tag'), store.find('tag', 5), "relationship object is the same as object retrieved directly"); - })); + strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); + asyncEqual(get(person, 'tag'), store.find('tag', 5), "relationship object is the same as object retrieved directly"); + })); + }); }); test("async belongsTo relationships work when the data hash has not been loaded", function() { @@ -539,14 +604,18 @@ test("async belongsTo relationships work when the data hash has not been loaded" } }; - store.find('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "The person is now populated"); + run(function(){ + store.find('person', 1).then(async(function(person) { + equal(get(person, 'name'), "Tom Dale", "The person is now populated"); - return get(person, 'tag'); - })).then(async(function(tag) { - equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); - equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); - })); + return run(function(){ + return get(person, 'tag'); + }); + })).then(async(function(tag) { + equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); + equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); + })); + }); }); test("async belongsTo relationships work when the data hash has already been loaded", function() { @@ -562,16 +631,22 @@ test("async belongsTo relationships work when the data hash has already been loa var env = setupStore({ tag: Tag, person: Person }), store = env.store; + run(function(){ store.push('tag', { id: 2, name: "friendly"}); store.push('person', { id: 1, name: "Tom Dale", tag: 2}); + }); + run(function(){ store.find('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "The person is now populated"); + equal(get(person, 'name'), "Tom Dale", "The person is now populated"); + return run(function(){ return get(person, 'tag'); + }); })).then(async(function(tag) { - equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); - equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); - })); + equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); + equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); + })); + }); }); test("calling createRecord and passing in an undefined value for a relationship should be treated as if null", function () { @@ -588,11 +663,15 @@ test("calling createRecord and passing in an undefined value for a relationship var env = setupStore({ tag: Tag, person: Person }), store = env.store; - store.createRecord('person', {id: 1, tag: undefined}); + run(function(){ + store.createRecord('person', {id: 1, tag: undefined}); + }); - store.find(Person, 1).then(async(function(person) { - strictEqual(person.get('tag'), null, "undefined values should return null relationships"); - })); + run(function(){ + store.find(Person, 1).then(async(function(person) { + strictEqual(person.get('tag'), null, "undefined values should return null relationships"); + })); + }); }); test("When finding a hasMany relationship the inverse belongsTo relationship is available immediately", function() { @@ -620,19 +699,23 @@ test("When finding a hasMany relationship the inverse belongsTo relationship is env.adapter.coalesceFindRequests = true; - store.push('person', { id: 1, name: "Tom Dale", occupations: [5, 2] }); + run(function(){ + store.push('person', { id: 1, name: "Tom Dale", occupations: [5, 2] }); + }); - store.find('person', 1).then(async(function(person) { - equal(get(person, 'isLoaded'), true, "isLoaded should be true"); - equal(get(person, 'name'), "Tom Dale", "the person is still Tom Dale"); + run(function(){ + store.find('person', 1).then(async(function(person) { + equal(get(person, 'isLoaded'), true, "isLoaded should be true"); + equal(get(person, 'name'), "Tom Dale", "the person is still Tom Dale"); - return get(person, 'occupations'); - })).then(async(function(occupations) { - equal(get(occupations, 'length'), 2, "the list of occupations should have the correct length"); + return get(person, 'occupations'); + })).then(async(function(occupations) { + equal(get(occupations, 'length'), 2, "the list of occupations should have the correct length"); - equal(get(occupations.objectAt(0), 'description'), "fifth", "the occupation is the fifth"); - equal(get(occupations.objectAt(0), 'isLoaded'), true, "the occupation is now loaded"); - })); + equal(get(occupations.objectAt(0), 'description'), "fifth", "the occupation is the fifth"); + equal(get(occupations.objectAt(0), 'isLoaded'), true, "the occupation is now loaded"); + })); + }); }); test("When finding a belongsTo relationship the inverse belongsTo relationship is available immediately", function() { @@ -659,9 +742,13 @@ test("When finding a belongsTo relationship the inverse belongsTo relationship i return Ember.RSVP.resolve({ id: 5, description: "fifth" }); }; - store.push('person', { id: 1, name: "Tom Dale", occupation: 5 }); + run(function(){ + store.push('person', { id: 1, name: "Tom Dale", occupation: 5 }); + }); - store.getById('person', 1).get('occupation'); + run(function(){ + store.getById('person', 1).get('occupation'); + }); }); test("belongsTo supports relationships to models with id 0", function() { @@ -680,16 +767,20 @@ test("belongsTo supports relationships to models with id 0", function() { var env = setupStore({ tag: Tag, person: Person }), store = env.store; - store.pushMany('tag', [{ id: 0, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); - store.push('person', { id: 1, name: "Tom Dale", tag: 0 }); + run(function(){ + store.pushMany('tag', [{ id: 0, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); + store.push('person', { id: 1, name: "Tom Dale", tag: 0 }); + }); - store.find('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + run(function(){ + store.find('person', 1).then(async(function(person) { + equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); - equal(get(person, 'tag.name'), "friendly", "the tag should have name"); + equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); + equal(get(person, 'tag.name'), "friendly", "the tag should have name"); - strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); - asyncEqual(get(person, 'tag'), store.find(Tag, 0), "relationship object is the same as object retrieved directly"); - })); + strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); + asyncEqual(get(person, 'tag'), store.find(Tag, 0), "relationship object is the same as object retrieved directly"); + })); + }); }); diff --git a/packages/ember-data/tests/unit/model/rollback_test.js b/packages/ember-data/tests/unit/model/rollback_test.js index caf89ad528c..a098e3619e6 100644 --- a/packages/ember-data/tests/unit/model/rollback_test.js +++ b/packages/ember-data/tests/unit/model/rollback_test.js @@ -1,4 +1,5 @@ var env, store, Person, Dog; +var run = Ember.run; module("unit/model/rollback - model.rollback()", { setup: function() { @@ -13,13 +14,17 @@ module("unit/model/rollback - model.rollback()", { }); test("changes to attributes can be rolled back", function() { - var person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); - - person.set('firstName', "Thomas"); + var person; + run(function(){ + person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); + person.set('firstName', "Thomas"); + }); equal(person.get('firstName'), "Thomas"); - person.rollback(); + run(function(){ + person.rollback(); + }); equal(person.get('firstName'), "Tom"); equal(person.get('isDirty'), false); @@ -29,10 +34,12 @@ test("changes to attributes made after a record is in-flight only rolls back the env.adapter.updateRecord = function(store, type, record) { return Ember.RSVP.resolve(); }; + var person; - var person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); - - person.set('firstName', "Thomas"); + run(function(){ + person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); + person.set('firstName', "Thomas"); + }); // Make sure the save is async Ember.run(function() { @@ -60,22 +67,27 @@ test("a record's changes can be made if it fails to save", function() { env.adapter.updateRecord = function(store, type, record) { return Ember.RSVP.reject(); }; + var person; - var person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); + run(function(){ + person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); + person.set('firstName', "Thomas"); + }); - person.set('firstName', "Thomas"); deepEqual(person.changedAttributes(), {firstName: ["Tom", "Thomas"]}); - person.save().then(null, async(function() { - equal(person.get('isError'), true); - deepEqual(person.changedAttributes(), {firstName: ["Tom", "Thomas"]}); + run(function(){ + person.save().then(null, async(function() { + equal(person.get('isError'), true); + deepEqual(person.changedAttributes(), {firstName: ["Tom", "Thomas"]}); - person.rollback(); + person.rollback(); - equal(person.get('firstName'), "Tom"); - equal(person.get('isError'), false); - deepEqual(person.changedAttributes(), {}); - })); + equal(person.get('firstName'), "Tom"); + equal(person.get('isError'), false); + deepEqual(person.changedAttributes(), {}); + })); + }); }); test("a deleted record can be rollbacked if it fails to save, record arrays are updated accordingly", function() { @@ -83,25 +95,39 @@ test("a deleted record can be rollbacked if it fails to save, record arrays are env.adapter.deleteRecord = function(store, type, record) { return Ember.RSVP.reject(); }; + var person, people; - var person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); - var people = store.all('person'); - person.deleteRecord(); + run(function(){ + person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); + people = store.all('person'); + }); + + run(function(){ + person.deleteRecord(); + }); equal(people.get('length'), 0, "a deleted record does not appear in record array anymore"); - person.save().then(null, async(function() { - equal(person.get('isError'), true); - equal(person.get('isDeleted'), true); - person.rollback(); - equal(person.get('isDeleted'), false); - equal(person.get('isError'), false); - })).then(async(function() { - equal(people.get('length'), 1, "the underlying record array is updated accordingly in an asynchronous way"); - })); + run(function(){ + person.save().then(null, async(function() { + equal(person.get('isError'), true); + equal(person.get('isDeleted'), true); + run(function(){ + person.rollback(); + }); + equal(person.get('isDeleted'), false); + equal(person.get('isError'), false); + })).then(async(function() { + equal(people.get('length'), 1, "the underlying record array is updated accordingly in an asynchronous way"); + })); + }); }); test("new record can be rollbacked", function() { - var person = store.createRecord('person', { id: 1 }); + var person; + + run(function(){ + person = store.createRecord('person', { id: 1 }); + }); equal(person.get('isNew'), true, "must be new"); equal(person.get('isDirty'), true, "must be dirty"); @@ -114,15 +140,21 @@ test("new record can be rollbacked", function() { }); test("deleted record can be rollbacked", function() { - var person = store.push('person', { id: 1 }); - var people = store.all('person'); + var person, people; + + run(function(){ + person = store.push('person', { id: 1 }); + people = store.all('person'); + person.deleteRecord(); + }); - person.deleteRecord(); equal(people.get('length'), 0, "a deleted record does not appear in record array anymore"); equal(person.get('isDeleted'), true, "must be deleted"); - person.rollback(); + run(function(){ + person.rollback(); + }); equal(people.get('length'), 1, "the rollbacked record should appear again in the record array"); equal(person.get('isDeleted'), false, "must not be deleted"); equal(person.get('isDirty'), false, "must not be dirty"); @@ -156,16 +188,20 @@ test("invalid record can be rollbacked", function() { }); env = setupStore({ dog: Dog, adapter: adapter}); - var dog = env.store.push('dog', { id: 1, name: "Pluto" }); - - dog.set('name', "is a dwarf planet"); + var dog; + run(function(){ + dog = env.store.push('dog', { id: 1, name: "Pluto" }); + dog.set('name', "is a dwarf planet"); + }); - dog.save().then(null, async(function() { - dog.rollback(); + run(function(){ + dog.save().then(null, async(function() { + dog.rollback(); - equal(dog.get('name'), "Pluto"); - ok(dog.get('isValid')); - })); + equal(dog.get('name'), "Pluto"); + ok(dog.get('isValid')); + })); + }); }); test("invalid record is rolled back to correct state after set", function() { @@ -197,20 +233,32 @@ test("invalid record is rolled back to correct state after set", function() { }); env = setupStore({ dog: Dog, adapter: adapter}); - var dog = env.store.push('dog', { id: 1, name: "Pluto", breed: "Disney" }); - - dog.set('name', "is a dwarf planet"); - dog.set('breed', 'planet'); - - dog.save().then(null, async(function() { - equal(dog.get('name'), "is a dwarf planet"); - equal(dog.get('breed'), "planet"); - dog.set('name', 'Seymour Asses'); - equal(dog.get('name'), "Seymour Asses"); - equal(dog.get('breed'), "planet"); - dog.rollback(); - equal(dog.get('name'), "Pluto"); - equal(dog.get('breed'), "Disney"); - ok(dog.get('isValid')); - })); + var dog; + run(function(){ + dog = env.store.push('dog', { id: 1, name: "Pluto", breed: "Disney" }); + dog.set('name', "is a dwarf planet"); + dog.set('breed', 'planet'); + }); + + run(function(){ + dog.save().then(null, async(function() { + equal(dog.get('name'), "is a dwarf planet"); + equal(dog.get('breed'), "planet"); + + run(function(){ + dog.set('name', 'Seymour Asses'); + }); + + equal(dog.get('name'), "Seymour Asses"); + equal(dog.get('breed'), "planet"); + + run(function(){ + dog.rollback(); + }); + + equal(dog.get('name'), "Pluto"); + equal(dog.get('breed'), "Disney"); + ok(dog.get('isValid')); + })); + }); }); diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index e26da3b8f84..912c9997051 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -1,6 +1,7 @@ var get = Ember.get, set = Ember.set; var Person, store, array; +var run = Ember.run; module("unit/model - DS.Model", { setup: function() { @@ -13,53 +14,70 @@ module("unit/model - DS.Model", { }, teardown: function() { + run(function(){ + store.destroy(); + }); Person = null; store = null; } }); test("can have a property set on it", function() { - var record = store.createRecord(Person); - set(record, 'name', 'bar'); + var record; + run(function(){ + record = store.createRecord(Person); + set(record, 'name', 'bar'); + }); equal(get(record, 'name'), 'bar', "property was set on the record"); }); test("setting a property on a record that has not changed does not cause it to become dirty", function() { - store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); - store.find(Person, 1).then(async(function(person) { - equal(person.get('isDirty'), false, "precond - person record should not be dirty"); - person.set('name', "Peter"); - person.set('isDrugAddict', true); - equal(person.get('isDirty'), false, "record does not become dirty after setting property to old value"); - })); + run(function(){ + store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); + store.find(Person, 1).then(async(function(person) { + equal(person.get('isDirty'), false, "precond - person record should not be dirty"); + + run(function(){ + person.set('name', "Peter"); + person.set('isDrugAddict', true); + }); + + equal(person.get('isDirty'), false, "record does not become dirty after setting property to old value"); + })); + }); }); test("resetting a property on a record cause it to become clean again", function() { - store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); - store.find(Person, 1).then(async(function(person) { - equal(person.get('isDirty'), false, "precond - person record should not be dirty"); - person.set('isDrugAddict', false); - equal(person.get('isDirty'), true, "record becomes dirty after setting property to a new value"); - person.set('isDrugAddict', true); - equal(person.get('isDirty'), false, "record becomes clean after resetting property to the old value"); - })); + run(function(){ + store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); + store.find(Person, 1).then(async(function(person) { + equal(person.get('isDirty'), false, "precond - person record should not be dirty"); + person.set('isDrugAddict', false); + equal(person.get('isDirty'), true, "record becomes dirty after setting property to a new value"); + person.set('isDrugAddict', true); + equal(person.get('isDirty'), false, "record becomes clean after resetting property to the old value"); + })); + }); }); test("a record reports its unique id via the `id` property", function() { - store.push(Person, { id: 1 }); - - store.find(Person, 1).then(async(function(record) { - equal(get(record, 'id'), 1, "reports id as id by default"); - })); + run(function(){ + store.push(Person, { id: 1 }); + store.find(Person, 1).then(async(function(record) { + equal(get(record, 'id'), 1, "reports id as id by default"); + })); + }); }); test("a record's id is included in its toString representation", function() { - store.push(Person, { id: 1 }); + run(function(){ + store.push(Person, { id: 1 }); - store.find(Person, 1).then(async(function(record) { - equal(record.toString(), '<(subclass of DS.Model):'+Ember.guidFor(record)+':1>', "reports id in toString"); - })); + store.find(Person, 1).then(async(function(record) { + equal(record.toString(), '<(subclass of DS.Model):'+Ember.guidFor(record)+':1>', "reports id in toString"); + })); + }); }); test("trying to set an `id` attribute should raise", function() { @@ -69,8 +87,10 @@ test("trying to set an `id` attribute should raise", function() { }); expectAssertion(function() { - store.push(Person, { id: 1, name: "Scumdale" }); - store.find(Person, 1); + run(function(){ + store.push(Person, { id: 1, name: "Scumdale" }); + store.find(Person, 1); + }); }, /You may not set `id`/); }); @@ -80,10 +100,12 @@ test("a collision of a record's id with object function's name", function() { if (!hasWatchMethod) { Object.prototype.watch = function(){}; } - store.push(Person, { id: 'watch' }); - store.find(Person, 'watch').then(async(function(record) { - equal(get(record, 'id'), 'watch', "record is successfully created and could be found by its id"); - })); + run(function(){ + store.push(Person, { id: 'watch' }); + store.find(Person, 'watch').then(async(function(record) { + equal(get(record, 'id'), 'watch', "record is successfully created and could be found by its id"); + })); + }); } finally { if (!hasWatchMethod) { delete Object.prototype.watch; @@ -92,11 +114,13 @@ test("a collision of a record's id with object function's name", function() { }); test("it should use `_reference` and not `reference` to store its reference", function() { - store.push(Person, { id: 1 }); + run(function(){ + store.push(Person, { id: 1 }); - store.find(Person, 1).then(async(function(record) { - equal(record.get('reference'), undefined, "doesn't shadow reference key"); - })); + store.find(Person, 1).then(async(function(record) { + equal(record.get('reference'), undefined, "doesn't shadow reference key"); + })); + }); }); test("it should cache attributes", function() { @@ -109,13 +133,19 @@ test("it should cache attributes", function() { var dateString = "Sat, 31 Dec 2011 00:08:16 GMT"; var date = new Date(dateString); - store.push(Post, { id: 1 }); + run(function(){ + store.push(Post, { id: 1 }); + store.find(Post, 1).then(async(function(record) { + run(function(){ + record.set('updatedAt', date); + }); + deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); + strictEqual(get(record, 'updatedAt'), get(record, 'updatedAt'), "second get still returns the same object"); + })).finally(function(){ + run(store, 'destroy'); + }); + }); - store.find(Post, 1).then(async(function(record) { - record.set('updatedAt', date); - deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); - strictEqual(get(record, 'updatedAt'), get(record, 'updatedAt'), "second get still returns the same object"); - })); }); test("changedAttributes() return correct values", function() { @@ -126,15 +156,24 @@ test("changedAttributes() return correct values", function() { likes: DS.attr('string'), isMascot: DS.attr('boolean') }); + var mascot; - var mascot = store.push(Mascot, { id: 1, likes: 'JavaScript', isMascot: true }) + + run(function(){ + mascot = store.push(Mascot, { id: 1, likes: 'JavaScript', isMascot: true }); + }); deepEqual({}, mascot.changedAttributes(), 'there are no initial changes'); - mascot.set('name', 'Tomster'); // new value - mascot.set('likes', 'Ember.js'); // changed value - mascot.set('isMascot', true); // same value + run(function(){ + mascot.set('name', 'Tomster'); // new value + mascot.set('likes', 'Ember.js'); // changed value + mascot.set('isMascot', true); // same value + }); deepEqual({ name: [undefined, 'Tomster'], likes: ['JavaScript', 'Ember.js'] }, mascot.changedAttributes(), 'attributes has changed'); - mascot.rollback(); + + run(function(){ + mascot.rollback(); + }); deepEqual({}, mascot.changedAttributes(), 'after rollback there are no changes'); }); @@ -142,8 +181,11 @@ test("a DS.Model does not require an attribute type", function() { var Tag = DS.Model.extend({ name: DS.attr() }); + var tag; - var tag = store.createRecord(Tag, { name: "test" }); + run(function(){ + tag = store.createRecord(Tag, { name: "test" }); + }); equal(get(tag, 'name'), "test", "the value is persisted"); }); @@ -152,8 +194,11 @@ test("a DS.Model can have a defaultValue without an attribute type", function() var Tag = DS.Model.extend({ name: DS.attr({ defaultValue: "unknown" }) }); + var tag; - var tag = store.createRecord(Tag); + run(function(){ + tag = store.createRecord(Tag); + }); equal(get(tag, 'name'), "unknown", "the default value is found"); }); @@ -163,32 +208,46 @@ module("unit/model - DS.Model updating", { array = [{ id: 1, name: "Scumbag Dale" }, { id: 2, name: "Scumbag Katz" }, { id: 3, name: "Scumbag Bryn" }]; Person = DS.Model.extend({ name: DS.attr('string') }); store = createStore(); - store.pushMany(Person, array); + run(function(){ + store.pushMany(Person, array); + }); }, teardown: function() { - Person = null; - store = null; - array = null; + run(function(){ + store.destroy(); + Person = null; + store = null; + array = null; + }); } }); test("a DS.Model can update its attributes", function() { - store.find(Person, 2).then(async(function(person) { - set(person, 'name', "Brohuda Katz"); - equal(get(person, 'name'), "Brohuda Katz", "setting took hold"); - })); + run(function(){ + store.find(Person, 2).then(async(function(person) { + run(function(){ + set(person, 'name', "Brohuda Katz"); + }); + equal(get(person, 'name'), "Brohuda Katz", "setting took hold"); + })); + }); }); test("a DS.Model can have a defaultValue", function() { var Tag = DS.Model.extend({ name: DS.attr('string', { defaultValue: "unknown" }) }); + var tag; - var tag = store.createRecord(Tag); + run(function(){ + tag = store.createRecord(Tag); + }); equal(get(tag, 'name'), "unknown", "the default value is found"); - set(tag, 'name', null); + run(function(){ + set(tag, 'name', null); + }); equal(get(tag, 'name'), null, "null doesn't shadow defaultValue"); }); @@ -201,8 +260,11 @@ test("a defaultValue for an attribute can be a function", function() { } }) }); + var tag; - var tag = store.createRecord(Tag); + run(function(){ + tag = store.createRecord(Tag); + }); equal(get(tag, 'createdAt'), "le default value", "the defaultValue function is evaluated"); }); @@ -218,8 +280,12 @@ test("a defaultValue function gets the record, options, and key", function() { } }) }); + var tag; + + run(function(){ + tag = store.createRecord(Tag); + }); - var tag = store.createRecord(Tag); get(tag, 'createdAt'); }); @@ -227,15 +293,23 @@ test("setting a property to undefined on a newly created record should not impac var Tag = DS.Model.extend({ name: DS.attr('string') }); + var tag; - var tag = store.createRecord(Tag); - - set(tag, 'name', 'testing'); - set(tag, 'name', undefined); + run(function(){ + tag = store.createRecord(Tag); + }); + run(function(){ + set(tag, 'name', 'testing'); + }); + run(function(){ + set(tag, 'name', undefined); + }); equal(get(tag, 'currentState.stateName'), "root.loaded.created.uncommitted"); - tag = store.createRecord(Tag, {name: undefined}); + run(function(){ + tag = store.createRecord(Tag, {name: undefined}); + }); equal(get(tag, 'currentState.stateName'), "root.loaded.created.uncommitted"); }); @@ -243,17 +317,19 @@ test("setting a property to undefined on a newly created record should not impac // NOTE: this is a 'backdoor' test that ensures internal consistency, and should be // thrown out if/when the current `_attributes` hash logic is removed. test("setting a property back to its original value removes the property from the `_attributes` hash", function() { - store.find(Person, 1).then(async(function(person) { - equal(person._attributes.name, undefined, "the `_attributes` hash is clean"); + run(function(){ + store.find(Person, 1).then(async(function(person) { + equal(person._attributes.name, undefined, "the `_attributes` hash is clean"); - set(person, 'name', "Niceguy Dale"); + set(person, 'name', "Niceguy Dale"); - equal(person._attributes.name, "Niceguy Dale", "the `_attributes` hash contains the changed value"); + equal(person._attributes.name, "Niceguy Dale", "the `_attributes` hash contains the changed value"); - set(person, 'name', "Scumbag Dale"); + set(person, 'name', "Scumbag Dale"); - equal(person._attributes.name, undefined, "the `_attributes` hash is reset"); - })); + equal(person._attributes.name, undefined, "the `_attributes` hash is reset"); + })); + }); }); module("unit/model - with a simple Person model", { @@ -265,12 +341,17 @@ module("unit/model - with a simple Person model", { store = createStore({ person: Person }); - store.pushMany(Person, array); + run(function(){ + store.pushMany(Person, array); + }); }, teardown: function() { - Person = null; - store = null; - array = null; + run(function(){ + store.destroy(); + Person = null; + store = null; + array = null; + }); } }); @@ -284,14 +365,22 @@ test("can ask if record with a given id is loaded", function() { test("a listener can be added to a record", function() { var count = 0; var F = function() { count++; }; - var record = store.createRecord(Person); + var record; + + run(function(){ + record = store.createRecord(Person); + }); record.on('event!', F); - record.trigger('event!'); + run(function(){ + record.trigger('event!'); + }); equal(count, 1, "the event was triggered"); - record.trigger('event!'); + run(function(){ + record.trigger('event!'); + }); equal(count, 2, "the event was triggered"); }); @@ -299,11 +388,17 @@ test("a listener can be added to a record", function() { test("when an event is triggered on a record the method with the same name is invoked with arguments", function(){ var count = 0; var F = function() { count++; }; - var record = store.createRecord(Person); + var record; + + run(function(){ + record = store.createRecord(Person); + }); record.eventNamedMethod = F; - record.trigger('eventNamedMethod'); + run(function(){ + record.trigger('eventNamedMethod'); + }); equal(count, 1, "the corresponding method was called"); }); @@ -313,11 +408,17 @@ test("when a method is invoked from an event with the same name the arguments ar var F = function() { eventMethodArgs = arguments; }; - var record = store.createRecord(Person); + var record; + + run(function(){ + record = store.createRecord(Person); + }); record.eventThatTriggersMethod = F; - record.trigger('eventThatTriggersMethod', 1, 2); + run(function(){ + record.trigger('eventThatTriggersMethod', 1, 2); + }); equal( eventMethodArgs[0], 1); equal( eventMethodArgs[1], 2); @@ -333,12 +434,13 @@ var converts = function(type, provided, expected) { var testStore = createStore({model: Model}), serializer = DS.JSONSerializer.create({ store: testStore, container: container }); - testStore.push(Model, serializer.normalize(Model, { id: 1, name: provided })); - testStore.push(Model, serializer.normalize(Model, { id: 2 })); - - testStore.find('model', 1).then(async(function(record) { - deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); - })); + run(function(){ + testStore.push(Model, serializer.normalize(Model, { id: 1, name: provided })); + testStore.push(Model, serializer.normalize(Model, { id: 2 })); + testStore.find('model', 1).then(async(function(record) { + deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); + })); + }); // See: Github issue #421 // record = testStore.find(Model, 2); @@ -356,10 +458,12 @@ var convertsFromServer = function(type, provided, expected) { var testStore = createStore({model: Model}), serializer = DS.JSONSerializer.create({ store: testStore, container: container }); - testStore.push(Model, serializer.normalize(Model, { id: "1", name: provided })); - testStore.find('model', 1).then(async(function(record) { - deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); - })); + run(function(){ + testStore.push(Model, serializer.normalize(Model, { id: "1", name: provided })); + testStore.find('model', 1).then(async(function(record) { + deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); + })); + }); }; var convertsWhenSet = function(type, provided, expected) { @@ -369,11 +473,13 @@ var convertsWhenSet = function(type, provided, expected) { var testStore = createStore({model: Model}); - testStore.push(Model, { id: 2 }); - testStore.find('model', 2).then(async(function(record) { - set(record, 'name', provided); - deepEqual(record.serialize().name, expected, type + " saves " + provided + " as " + expected); - })); + run(function(){ + testStore.push(Model, { id: 2 }); + testStore.find('model', 2).then(async(function(record) { + set(record, 'name', provided); + deepEqual(record.serialize().name, expected, type + " saves " + provided + " as " + expected); + })); + }); }; test("a DS.Model can describe String attributes", function() { @@ -420,12 +526,15 @@ test("a DS.Model can describe Date attributes", function() { updatedAt: DS.attr('date') }); - store.push(Person, { id: 1 }); - store.find(Person, 1).then(async(function(record) { - record.set('updatedAt', date); - deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); - })); - + run(function(){ + store.push(Person, { id: 1 }); + store.find(Person, 1).then(async(function(record) { + run(function(){ + record.set('updatedAt', date); + }); + deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); + })); + }); convertsFromServer('date', dateString, date); convertsWhenSet('date', date, dateString); }); @@ -434,10 +543,16 @@ test("don't allow setting", function(){ var store = createStore(); var Person = DS.Model.extend(); - var record = store.createRecord(Person); + var record; + + run(function(){ + record = store.createRecord(Person); + }); raises(function(){ - record.set('isLoaded', true); + run(function(){ + record.set('isLoaded', true); + }); }, "raised error when trying to set an unsettable record"); }); @@ -450,10 +565,12 @@ test("ensure model exits loading state, materializes data and fulfills promise o }) }); - store.find(Person, 1).then(async(function(person) { - equal(get(person, 'currentState.stateName'), 'root.loaded.saved', 'model is in loaded state'); - equal(get(person, 'isLoaded'), true, 'model is loaded'); - })); + run(function(){ + store.find(Person, 1).then(async(function(person) { + equal(get(person, 'currentState.stateName'), 'root.loaded.saved', 'model is in loaded state'); + equal(get(person, 'isLoaded'), true, 'model is loaded'); + })); + }); }); test("A DS.Model can be JSONified", function() { @@ -462,7 +579,11 @@ test("A DS.Model can be JSONified", function() { }); var store = createStore({ person: Person }); - var record = store.createRecord('person', { name: "TomHuda" }); + var record; + + run(function(){ + record = store.createRecord('person', { name: "TomHuda" }); + }); deepEqual(record.toJSON(), { name: "TomHuda" }); }); @@ -474,6 +595,8 @@ test("A subclass of DS.Model can not use the `data` property", function() { var store = createStore({ person: Person }); expectAssertion(function() { - store.createRecord('person', { name: "TomHuda" }); + run(function(){ + store.createRecord('person', { name: "TomHuda" }); + }); }, /`data` is a reserved property name on DS.Model objects/); }); diff --git a/packages/ember-data/tests/unit/record_array_test.js b/packages/ember-data/tests/unit/record_array_test.js index afed88adf38..8335f294f1d 100644 --- a/packages/ember-data/tests/unit/record_array_test.js +++ b/packages/ember-data/tests/unit/record_array_test.js @@ -1,6 +1,7 @@ var get = Ember.get; var Person, array; +var run = Ember.run; module("unit/record_array - DS.RecordArray", { setup: function() { @@ -14,23 +15,31 @@ module("unit/record_array - DS.RecordArray", { test("a record array is backed by records", function() { var store = createStore(); - store.pushMany(Person, array); + run(function(){ + store.pushMany(Person, array); + }); - store.findByIds(Person, [1,2,3]).then(async(function(records) { - for (var i=0, l=get(array, 'length'); i Date: Mon, 1 Dec 2014 09:11:01 -0600 Subject: [PATCH 0481/2527] =?UTF-8?q?remove=20unnecessary=20=E2=80=9Casync?= =?UTF-8?q?=E2=80=9D=20helper=20calls?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../active_model_serializer_test.js | 12 +- .../integration/adapter/find_all_test.js | 42 +-- .../tests/integration/filter_test.js | 42 ++- .../records/collection_save_test.js | 4 +- .../tests/integration/records/reload_test.js | 38 +-- .../tests/integration/records/save_test.js | 26 +- .../tests/integration/records/unload_test.js | 16 +- .../relationships/belongs_to_test.js | 118 +++---- .../relationships/has_many_test.js | 299 +++++++++--------- .../relationships/one_to_many_test.js | 124 ++++---- .../relationships/one_to_one_test.js | 142 +++++---- .../embedded_records_mixin_test.js | 50 +-- .../serializers/rest_serializer_test.js | 8 +- .../tests/integration/store_test.js | 8 +- .../unit/model/lifecycle_callbacks_test.js | 46 +-- .../ember-data/tests/unit/model/merge_test.js | 18 +- .../tests/unit/model/relationships_test.js | 43 ++- .../tests/unit/model/rollback_test.js | 16 +- packages/ember-data/tests/unit/model_test.js | 70 ++-- .../tests/unit/record_array_test.js | 16 +- .../ember-data/tests/unit/store/push_test.js | 16 +- .../tests/unit/store/unload_test.js | 48 ++- tests/ember_configuration.js | 1 - 23 files changed, 626 insertions(+), 577 deletions(-) diff --git a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js index 9208bef70f6..af3cb08f0d3 100644 --- a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js +++ b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js @@ -156,9 +156,9 @@ test("extractSingle", function() { }); run(function(){ - env.store.find("superVillain", 1).then(async(function(minion){ + env.store.find("superVillain", 1).then(function(minion){ equal(minion.get('firstName'), "Tom"); - })); + }); }); }); @@ -181,9 +181,11 @@ test("extractArray", function() { "superVillains": [1] }]); - env.store.find("superVillain", 1).then(async(function(minion){ - equal(minion.get('firstName'), "Tom"); - })); + run(function(){ + env.store.find("superVillain", 1).then(function(minion){ + equal(minion.get('firstName'), "Tom"); + }); + }); }); test("serialize polymorphic", function() { diff --git a/packages/ember-data/tests/integration/adapter/find_all_test.js b/packages/ember-data/tests/integration/adapter/find_all_test.js index c41967895e8..695fb5638b6 100644 --- a/packages/ember-data/tests/integration/adapter/find_all_test.js +++ b/packages/ember-data/tests/integration/adapter/find_all_test.js @@ -37,16 +37,20 @@ test("When all records for a type are requested, the store should call the adapt var allRecords; - store.find(Person).then(async(function(all) { - allRecords = all; - equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); - equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); - })); - - store.find(Person).then(async(function(all) { - // Only one record array per type should ever be created (identity map) - strictEqual(allRecords, all, "the same record array is returned every time all records of a type are requested"); - })); + run(function(){ + store.find(Person).then(function(all) { + allRecords = all; + equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); + equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); + }); + }); + + run(function(){ + store.find(Person).then(function(all) { + // Only one record array per type should ever be created (identity map) + strictEqual(allRecords, all, "the same record array is returned every time all records of a type are requested"); + }); + }); }); test("When all records for a type are requested, a rejection should reject the promise", function() { @@ -69,14 +73,16 @@ test("When all records for a type are requested, a rejection should reject the p var allRecords; - store.find(Person).then(null, async(function() { - ok(true, "The rejection should get here"); - return store.find(Person); - })).then(async(function(all) { - allRecords = all; - equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); - equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); - })); + run(function(){ + store.find(Person).then(null, function() { + ok(true, "The rejection should get here"); + return store.find(Person); + }).then(function(all) { + allRecords = all; + equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); + equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); + }); + }); }); test("When all records for a type are requested, records that are already loaded should be returned immediately.", function() { diff --git a/packages/ember-data/tests/integration/filter_test.js b/packages/ember-data/tests/integration/filter_test.js index f30d903f0cd..0ef3572726b 100644 --- a/packages/ember-data/tests/integration/filter_test.js +++ b/packages/ember-data/tests/integration/filter_test.js @@ -430,7 +430,9 @@ test("it is possible to filter loaded records by dirtiness", function() { return !person.get('isDirty'); }); - store.push('person', { id: 1, name: "Tom Dale" }); + run(function(){ + store.push('person', { id: 1, name: "Tom Dale" }); + }); store.find('person', 1).then(async(function(person) { equal(filter.get('length'), 1, "the clean record is in the filter"); @@ -450,26 +452,38 @@ test("it is possible to filter loaded records by dirtiness", function() { }); test("it is possible to filter created records by dirtiness", function() { - set(store, 'adapter', DS.Adapter.extend({ - createRecord: function() { - return Ember.RSVP.resolve(); - } - })); + run(function(){ + set(store, 'adapter', DS.Adapter.extend({ + createRecord: function() { + return Ember.RSVP.resolve(); + } + })); + }); - var filter = store.filter('person', function(person) { - return !person.get('isDirty'); + var filter; + + run(function(){ + filter = store.filter('person', function(person) { + return !person.get('isDirty'); + }); }); - var person = store.createRecord('person', { - id: 1, - name: "Tom Dale" + var person; + + run(function(){ + person = store.createRecord('person', { + id: 1, + name: "Tom Dale" + }); }); equal(filter.get('length'), 0, "the dirty record is not in the filter"); - person.save().then(async(function(person) { - equal(filter.get('length'), 1, "the clean record is in the filter"); - })); + run(function(){ + person.save().then(function(person) { + equal(filter.get('length'), 1, "the clean record is in the filter"); + }); + }); }); test("it is possible to filter created records by isReloading", function() { diff --git a/packages/ember-data/tests/integration/records/collection_save_test.js b/packages/ember-data/tests/integration/records/collection_save_test.js index 41045feaa4c..90a5b88f91b 100644 --- a/packages/ember-data/tests/integration/records/collection_save_test.js +++ b/packages/ember-data/tests/integration/records/collection_save_test.js @@ -101,8 +101,8 @@ test("Collection will reject save on invalid", function() { }; Ember.run(function(){ - posts.save().then(function() {}, async(function() { + posts.save().then(function() {}, function() { ok(true, 'save operation was rejected'); - })); + }); }); }); diff --git a/packages/ember-data/tests/integration/records/reload_test.js b/packages/ember-data/tests/integration/records/reload_test.js index 60a0078f9b2..c85778f08db 100644 --- a/packages/ember-data/tests/integration/records/reload_test.js +++ b/packages/ember-data/tests/integration/records/reload_test.js @@ -38,16 +38,16 @@ test("When a single record is requested, the adapter's find method should be cal }; run(function(){ - env.store.find('person', 1).then(async(function(person) { + env.store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is loaded with the right name"); equal(get(person, 'isLoaded'), true, "The person is now loaded"); var promise = person.reload(); equal(get(person, 'isReloading'), true, "The person is now reloading"); return promise; - })).then(async(function(person) { + }).then(function(person) { equal(get(person, 'isReloading'), false, "The person is no longer reloading"); equal(get(person, 'name'), "Braaaahm Dale", "The person is now updated with the right name"); - })); + }); }); }); @@ -66,14 +66,16 @@ test("When a record is reloaded and fails, it can try again", function() { } }; - tom.reload().then(null, async(function() { - equal(tom.get('isError'), true, "Tom is now errored"); - return tom.reload(); - })).then(async(function(person) { - equal(person, tom, "The resolved value is the record"); - equal(tom.get('isError'), false, "Tom is no longer errored"); - equal(tom.get('name'), "Thomas Dale", "the updates apply"); - })); + run(function(){ + tom.reload().then(null, function() { + equal(tom.get('isError'), true, "Tom is now errored"); + return tom.reload(); + }).then(function(person) { + equal(person, tom, "The resolved value is the record"); + equal(tom.get('isError'), false, "Tom is no longer errored"); + equal(tom.get('name'), "Thomas Dale", "the updates apply"); + }); + }); }); test("When a record is loaded a second time, isLoaded stays true", function() { @@ -82,7 +84,7 @@ test("When a record is loaded a second time, isLoaded stays true", function() { }); run(function(){ - env.store.find('person', 1).then(async(function(person) { + env.store.find('person', 1).then(function(person) { equal(get(person, 'isLoaded'), true, "The person is loaded"); person.addObserver('isLoaded', isLoadedDidChange); @@ -91,7 +93,7 @@ test("When a record is loaded a second time, isLoaded stays true", function() { equal(get(person, 'isLoaded'), true, "The person is still loaded after load"); person.removeObserver('isLoaded', isLoadedDidChange); - })); + }); }); function isLoadedDidChange() { @@ -124,20 +126,20 @@ test("When a record is reloaded, its async hasMany relationships still work", fu var tom; run(function(){ - env.store.find('person', 1).then(async(function(person) { tom = person; + env.store.find('person', 1).then(function(person) { tom = person; equal(person.get('name'), "Tom", "precond"); return person.get('tags'); - })).then(async(function(tags) { + }).then(function(tags) { deepEqual(tags.mapBy('name'), [ 'hipster', 'hair' ]); return tom.reload(); - })).then(async(function(person) { + }).then(function(person) { equal(person.get('name'), "Tom", "precond"); return person.get('tags'); - })).then(async(function(tags) { + }).then(function(tags) { deepEqual(tags.mapBy('name'), [ 'hipster', 'hair' ], "The tags are still there"); - })); + }); }); }); diff --git a/packages/ember-data/tests/integration/records/save_test.js b/packages/ember-data/tests/integration/records/save_test.js index e8c66953398..c059ffccde3 100644 --- a/packages/ember-data/tests/integration/records/save_test.js +++ b/packages/ember-data/tests/integration/records/save_test.js @@ -28,9 +28,11 @@ test("Will resolve save on success", function() { return Ember.RSVP.resolve({ id: 123 }); }; - run(post, 'save').then(async(function() { - ok(true, 'save operation was resolved'); - })); + run(function(){ + post.save().then(function() { + ok(true, 'save operation was resolved'); + }); + }); }); test("Will reject save on error", function() { @@ -43,9 +45,11 @@ test("Will reject save on error", function() { return Ember.RSVP.reject(); }; - run(post, 'save').then(function() {}, async(function() { - ok(true, 'save operation was rejected'); - })); + run(function(){ + post.save().then(function() {}, function() { + ok(true, 'save operation was rejected'); + }); + }); }); test("Retry is allowed in a failure handler", function() { @@ -65,11 +69,11 @@ test("Retry is allowed in a failure handler", function() { }; run(function(){ - post.save().then(function() {}, async(function() { + post.save().then(function() {}, function() { return post.save(); - })).then(async(function(post) { + }).then(function(post) { equal(post.get('id'), '123', "The post ID made it through"); - })); + }); }); }); @@ -108,8 +112,8 @@ test("Will reject save on invalid", function() { }; run(function(){ - post.save().then(function() {}, async(function() { + post.save().then(function() {}, function() { ok(true, 'save operation was rejected'); - })); + }); }); }); diff --git a/packages/ember-data/tests/integration/records/unload_test.js b/packages/ember-data/tests/integration/records/unload_test.js index 8680421e04e..f379ef2750f 100644 --- a/packages/ember-data/tests/integration/records/unload_test.js +++ b/packages/ember-data/tests/integration/records/unload_test.js @@ -112,13 +112,15 @@ test("unloading a record also clears its relationship", function() { }); }); - run(env.store, 'find', 'person', 1).then(async(function(person){ - equal(person.get('cars.length'), 1, 'aaaa'); + run(function(){ + env.store.find('person', 1).then(function(person){ + equal(person.get('cars.length'), 1, 'aaaa'); - run(function(){ - person.unloadRecord(); - }); + run(function(){ + person.unloadRecord(); + }); - equal(person.get('cars.length'), undefined); - })); + equal(person.get('cars.length'), undefined); + }); + }); }); diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index cef64f905ca..0a0bb9fa7be 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -95,9 +95,9 @@ test("The store can materialize a non loaded monomorphic belongsTo association", }); run(function(){ - env.store.find('post', 1).then(async(function(post) { + env.store.find('post', 1).then(function(post) { post.get('user'); - })); + }); }); }); @@ -109,14 +109,16 @@ test("Only a record of the same type can be used with a monomorphic belongsTo re store.push('comment', { id: 2 }); }); - hash({ - post: store.find('post', 1), - comment: store.find('comment', 2) - }).then(async(function(records) { - expectAssertion(function() { - records.post.set('user', records.comment); - }, /You can only add a 'user' record to this relationship/); - })); + run(function(){ + hash({ + post: store.find('post', 1), + comment: store.find('comment', 2) + }).then(function(records) { + expectAssertion(function() { + records.post.set('user', records.comment); + }, /You can only add a 'user' record to this relationship/); + }); + }); }); test("Only a record of the same base type can be used with a polymorphic belongsTo relationship", function() { @@ -128,24 +130,26 @@ test("Only a record of the same base type can be used with a polymorphic belongs store.push('user', { id: 3 }); }); - var asyncRecords = hash({ - user: store.find('user', 3), - post: store.find('post', 1), - comment: store.find('comment', 1), - anotherComment: store.find('comment', 2) - }); + run(function(){ + var asyncRecords = hash({ + user: store.find('user', 3), + post: store.find('post', 1), + comment: store.find('comment', 1), + anotherComment: store.find('comment', 2) + }); - asyncRecords.then(async(function(records) { - var comment = records.comment; + asyncRecords.then(function(records) { + var comment = records.comment; - comment.set('message', records.anotherComment); - comment.set('message', records.post); - comment.set('message', null); + comment.set('message', records.anotherComment); + comment.set('message', records.post); + comment.set('message', null); - expectAssertion(function() { - comment.set('message', records.user); - }, /You can only add a 'message' record to this relationship/); - })); + expectAssertion(function() { + comment.set('message', records.user); + }, /You can only add a 'message' record to this relationship/); + }); + }); }); test("The store can load a polymorphic belongsTo association", function() { @@ -154,12 +158,14 @@ test("The store can load a polymorphic belongsTo association", function() { env.store.push('comment', { id: 2, message: 1, messageType: 'post' }); }); - hash({ - message: store.find('post', 1), - comment: store.find('comment', 2) - }).then(async(function(records) { - equal(records.comment.get('message'), records.message); - })); + run(function(){ + hash({ + message: store.find('post', 1), + comment: store.find('comment', 2) + }).then(function(records) { + equal(records.comment.get('message'), records.message); + }); + }); }); test("The store can serialize a polymorphic belongsTo association", function() { @@ -170,13 +176,13 @@ test("The store can serialize a polymorphic belongsTo association", function() { run(function(){ env.store.push('post', { id: 1 }); env.store.push('comment', { id: 2, message: 1, messageType: 'post' }); - }); - store.find('comment', 2).then(async(function(comment) { - var serialized = store.serialize(comment, { includeId: true }); - equal(serialized['message'], 1); - equal(serialized['message_type'], 'post'); - })); + store.find('comment', 2).then(function(comment) { + var serialized = store.serialize(comment, { includeId: true }); + equal(serialized['message'], 1); + equal(serialized['message_type'], 'post'); + }); + }); }); test("A serializer can materialize a belongsTo as a link that gets sent back to findBelongsTo", function() { @@ -207,12 +213,14 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to return Ember.RSVP.resolve({ id: 1, people: [1] }); }); - env.store.find('person', 1).then(async(function(person) { - return person.get('group'); - })).then(async(function(group) { - ok(group instanceof Group, "A group object is loaded"); - ok(group.get('id') === '1', 'It is the group we are expecting'); - })); + run(function(){ + env.store.find('person', 1).then(function(person) { + return person.get('group'); + }).then(function(group) { + ok(group instanceof Group, "A group object is loaded"); + ok(group.get('id') === '1', 'It is the group we are expecting'); + }); + }); }); test('A record with an async belongsTo relationship always returns a promise for that relationship', function () { @@ -239,14 +247,16 @@ test('A record with an async belongsTo relationship always returns a promise for return Ember.RSVP.resolve({ id: 1}); }); - env.store.find('person', 1).then(async(function(person) { - person.get('seat').then(async(function(seat) { - // this assertion fails too - // ok(seat.get('person') === person, 'parent relationship should be populated'); - seat.set('person', person); - ok(person.get('seat').then, 'seat should be a PromiseObject'); - })); - })); + run(function(){ + env.store.find('person', 1).then(function(person) { + person.get('seat').then(function(seat) { + // this assertion fails too + // ok(seat.get('person') === person, 'parent relationship should be populated'); + seat.set('person', person); + ok(person.get('seat').then, 'seat should be a PromiseObject'); + }); + }); + }); }); test("A record with an async belongsTo relationship returning null should resolve null", function() { @@ -460,10 +470,10 @@ test("Rollbacking a deleted record restores implicit relationship - async", func run(function(){ author.deleteRecord(); author.rollback(); + book.get('author').then(function(fetchedAuthor) { + equal(fetchedAuthor, author, 'Book has an author after rollback'); + }); }); - book.get('author').then(async(function(fetchedAuthor) { - equal(fetchedAuthor, author, 'Book has an author after rollback'); - })); }); test("Rollbacking a deleted record restores implicit relationship - sync", function () { diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 0734b3fc98c..3a07b60bc0e 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -94,11 +94,10 @@ test("When a hasMany relationship is accessed, the adapter's findMany method sho run(function(){ env.store.push('post', { id: 1, comments: [ 1 ] }); env.store.push('comment', { id: 1 }); + env.store.find('post', 1).then(function(post) { + return post.get('comments'); + }); }); - - env.store.find('post', 1).then(async(function(post) { - return post.get('comments'); - })); }); // This tests the case where a serializer materializes a has-many @@ -211,12 +210,14 @@ test("A hasMany backed by a link remains a promise after a record has been added post = env.store.push('post', { id: 1, links: {comments: '/posts/1/comments'}}); }); - run(post, 'get', 'comments').then(async(function() { - env.store.push('comment', { id:3, message: 1 }); - post.get('comments').then(async(function() { - ok(true, 'Promise was called'); - })); - })); + run(function(){ + post.get('comments').then(function() { + env.store.push('comment', { id:3, message: 1 }); + post.get('comments').then(function() { + ok(true, 'Promise was called'); + }); + }); + }); }); test("A hasMany relationship can be reloaded if it was fetched via a link", function() { @@ -242,28 +243,30 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func ]); }; - run(env.store, 'find', 'post', 1).then(async(function(post) { - return post.get('comments'); - })).then(async(function(comments) { - equal(comments.get('isLoaded'), true, "comments are loaded"); - equal(comments.get('length'), 2, "comments have 2 length"); - - env.adapter.findHasMany = function(store, record, link, relationship) { - equal(relationship.type, Comment, "findHasMany relationship type was Comment"); - equal(relationship.key, 'comments', "findHasMany relationship key was comments"); - equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); + run(function(){ + run(env.store, 'find', 'post', 1).then(function(post) { + return post.get('comments'); + }).then(function(comments) { + equal(comments.get('isLoaded'), true, "comments are loaded"); + equal(comments.get('length'), 2, "comments have 2 length"); - return Ember.RSVP.resolve([ - { id: 1, body: "First" }, - { id: 2, body: "Second" }, - { id: 3, body: "Thirds" } - ]); - }; + env.adapter.findHasMany = function(store, record, link, relationship) { + equal(relationship.type, Comment, "findHasMany relationship type was Comment"); + equal(relationship.key, 'comments', "findHasMany relationship key was comments"); + equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); - return comments.reload(); - })).then(async(function(newComments){ - equal(newComments.get('length'), 3, "reloaded comments have 3 length"); - })); + return Ember.RSVP.resolve([ + { id: 1, body: "First" }, + { id: 2, body: "Second" }, + { id: 3, body: "Thirds" } + ]); + }; + + return comments.reload(); + }).then(function(newComments){ + equal(newComments.get('length'), 3, "reloaded comments have 3 length"); + }); + }); }); test("A sync hasMany relationship can be reloaded if it was fetched via ids", function() { @@ -280,24 +283,24 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu run(function(){ env.store.pushMany('comment', [{ id: 1, body: "First" }, { id: 2, body: "Second" }]); - }); - run(env.store, 'find', 'post', 1).then(async(function(post) { - var comments = post.get('comments'); - equal(comments.get('isLoaded'), true, "comments are loaded"); - equal(comments.get('length'), 2, "comments have a length of 2"); + env.store.find('post', '1').then(function(post) { + var comments = post.get('comments'); + equal(comments.get('isLoaded'), true, "comments are loaded"); + equal(comments.get('length'), 2, "comments have a length of 2"); - env.adapter.findMany = function(store, type, ids, records) { - return Ember.RSVP.resolve([ - { id: 1, body: "FirstUpdated" }, - { id: 2, body: "Second" } - ]); - }; + env.adapter.findMany = function(store, type, ids, records) { + return Ember.RSVP.resolve([ + { id: 1, body: "FirstUpdated" }, + { id: 2, body: "Second" } + ]); + }; - return comments.reload(); - })).then(async(function(newComments){ - equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); - })); + return comments.reload(); + }).then(function(newComments){ + equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); + }); + }); }); test("A hasMany relationship can be reloaded if it was fetched via ids", function() { @@ -319,23 +322,25 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio ]); }; - run(env.store, 'find', 'post', 1).then(async(function(post) { - return post.get('comments'); - })).then(async(function(comments) { - equal(comments.get('isLoaded'), true, "comments are loaded"); - equal(comments.get('length'), 2, "comments have 2 length"); + run(function(){ + env.store.find('post', 1).then(function(post) { + return post.get('comments'); + }).then(function(comments) { + equal(comments.get('isLoaded'), true, "comments are loaded"); + equal(comments.get('length'), 2, "comments have 2 length"); - env.adapter.findMany = function(store, type, ids, records) { - return Ember.RSVP.resolve([ - { id: 1, body: "FirstUpdated" }, - { id: 2, body: "Second" } - ]); - }; + env.adapter.findMany = function(store, type, ids, records) { + return Ember.RSVP.resolve([ + { id: 1, body: "FirstUpdated" }, + { id: 2, body: "Second" } + ]); + }; - return comments.reload(); - })).then(async(function(newComments){ - equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); - })); + return comments.reload(); + }).then(function(newComments){ + equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); + }); + }); }); test("A hasMany relationship can be directly reloaded if it was fetched via ids", function() { @@ -357,13 +362,15 @@ test("A hasMany relationship can be directly reloaded if it was fetched via ids" ]); }; - run(env.store, 'find', 'post', 1).then(async(function(post) { - return post.get('comments').reload().then(async(function(comments) { - equal(comments.get('isLoaded'), true, "comments are loaded"); - equal(comments.get('length'), 2, "comments have 2 length"); - equal(comments.get('firstObject.body'), "FirstUpdated", "Record body was correctly updated"); - })); - })); + run(function(){ + env.store.find('post', 1).then(function(post) { + return post.get('comments').reload().then(function(comments) { + equal(comments.get('isLoaded'), true, "comments are loaded"); + equal(comments.get('length'), 2, "comments have 2 length"); + equal(comments.get('firstObject.body'), "FirstUpdated", "Record body was correctly updated"); + }); + }); + }); }); test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loaded", function() { @@ -385,14 +392,16 @@ test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loa post = env.store.push('post', {id:1, links: {comments: 'someLink'}}); }); - run(post, 'get', 'comments').then(async(function(comments) { - equal(comments.get('isLoaded'), true, "comments are loaded"); - equal(comments.get('length'), 2, "comments have 2 length"); + run(function(){ + post.get('comments').then(function(comments) { + equal(comments.get('isLoaded'), true, "comments are loaded"); + equal(comments.get('length'), 2, "comments have 2 length"); - var newComment = post.get('comments').createRecord({body: 'Third'}); - equal(newComment.get('body'), 'Third', "new comment is returned"); - equal(comments.get('length'), 3, "comments have 3 length, including new record"); - })); + var newComment = post.get('comments').createRecord({body: 'Third'}); + equal(newComment.get('body'), 'Third', "new comment is returned"); + equal(comments.get('length'), 3, "comments have 3 length, including new record"); + }); + }); }); test("PromiseArray proxies evented methods to its ManyArray", function() { @@ -475,17 +484,19 @@ test("An updated `links` value should invalidate a relationship cache", function post = env.store.push('post', {id:1, links: { comments: '/first' }}); }); - run(post, 'get', 'comments').then(async(function(comments) { - equal(comments.get('isLoaded'), true, "comments are loaded"); - equal(comments.get('length'), 2, "comments have 2 length"); - equal(comments.objectAt(0).get('body'), 'First', "comment 1 successfully loaded"); - env.store.push('post', {id:1, links: { comments: '/second' }}); - post.get('comments').then(async(function(newComments) { - equal(comments, newComments, "hasMany array was kept the same"); - equal(newComments.get('length'), 3, "comments updated successfully"); - equal(newComments.objectAt(0).get('body'), 'Third', "third comment loaded successfully"); - })); - })); + run(function(){ + post.get('comments').then(function(comments){ + equal(comments.get('isLoaded'), true, "comments are loaded"); + equal(comments.get('length'), 2, "comments have 2 length"); + equal(comments.objectAt(0).get('body'), 'First', "comment 1 successfully loaded"); + env.store.push('post', {id:1, links: { comments: '/second' }}); + post.get('comments').then(function(newComments) { + equal(comments, newComments, "hasMany array was kept the same"); + equal(newComments.get('length'), 3, "comments updated successfully"); + equal(newComments.objectAt(0).get('body'), 'Third', "third comment loaded successfully"); + }); + }); + }); }); test("When a polymorphic hasMany relationship is accessed, the adapter's findMany method should not be called if all the records in the relationship are already loaded", function() { @@ -502,10 +513,10 @@ test("When a polymorphic hasMany relationship is accessed, the adapter's findMan }); run(function(){ - env.store.find('user', 1).then(async(function(user) { + env.store.find('user', 1).then(function(user) { var messages = user.get('messages'); equal(messages.get('length'), 2, "The messages are correctly loaded"); - })); + }); }); }); @@ -527,11 +538,11 @@ test("When a polymorphic hasMany relationship is accessed, the store can call mu }); run(function(){ - env.store.find('user', 1).then(async(function(user) { + env.store.find('user', 1).then(function(user) { return user.get('messages'); - })).then(async(function(messages) { + }).then(function(messages) { equal(messages.get('length'), 2, "The messages are correctly loaded"); - })); + }); }); }); @@ -542,11 +553,11 @@ test("Type can be inferred from the key of a hasMany relationship", function() { env.store.push('contact', { id: 1 }); }); run(function(){ - env.store.find('user', 1).then(async(function(user) { + env.store.find('user', 1).then(function(user) { return user.get('contacts'); - })).then(async(function(contacts) { + }).then(function(contacts) { equal(contacts.get('length'), 1, "The contacts relationship is correctly set up"); - })); + }); }); }); @@ -561,11 +572,11 @@ test("Type can be inferred from the key of an async hasMany relationship", funct env.store.push('contact', { id: 1 }); }); run(function(){ - env.store.find('user', 1).then(async(function(user) { + env.store.find('user', 1).then(function(user) { return user.get('contacts'); - })).then(async(function(contacts) { + }).then(function(contacts) { equal(contacts.get('length'), 1, "The contacts relationship is correctly set up"); - })); + }); }); }); @@ -581,11 +592,11 @@ test("Polymorphic relationships work with a hasMany whose type is inferred", fun env.store.push('phone', { id: 2 }); }); run(function(){ - env.store.find('user', 1).then(async(function(user) { + env.store.find('user', 1).then(function(user) { return user.get('contacts'); - })).then(async(function(contacts) { + }).then(function(contacts) { equal(contacts.get('length'), 2, "The contacts relationship is correctly set up"); - })); + }); }); }); @@ -595,13 +606,13 @@ test("A record can't be created from a polymorphic hasMany relationship", functi }); run(function(){ - env.store.find('user', 1).then(async(function(user) { + env.store.find('user', 1).then(function(user) { return user.get('messages'); - })).then(async(function(messages) { + }).then(function(messages) { expectAssertion(function() { messages.createRecord(); }, /You cannot add 'message' records to this polymorphic relationship/); - })); + }); }); }); @@ -613,11 +624,11 @@ test("Only records of the same type can be added to a monomorphic hasMany relati }); run(function(){ - Ember.RSVP.all([ env.store.find('post', 1), env.store.find('post', 2) ]).then(async(function(records) { + Ember.RSVP.all([ env.store.find('post', 1), env.store.find('post', 2) ]).then(function(records) { expectAssertion(function() { records[0].get('comments').pushObject(records[1]); }, /You cannot add 'post' records to this relationship/); - })); + }); }); }); @@ -638,20 +649,20 @@ test("Only records of the same base type can be added to a polymorphic hasMany r post: env.store.find('post', 1), comment: env.store.find('comment', 3) }); - }); - asyncRecords.then(async(function(records) { - records.messages = records.user.get('messages'); - return Ember.RSVP.hash(records); - })).then(async(function(records) { - records.messages.pushObject(records.post); - records.messages.pushObject(records.comment); - equal(records.messages.get('length'), 2, "The messages are correctly added"); + asyncRecords.then(function(records) { + records.messages = records.user.get('messages'); + return Ember.RSVP.hash(records); + }).then(function(records) { + records.messages.pushObject(records.post); + records.messages.pushObject(records.comment); + equal(records.messages.get('length'), 2, "The messages are correctly added"); - expectAssertion(function() { - records.messages.pushObject(records.anotherUser); - }, /You cannot add 'user' records to this relationship/); - })); + expectAssertion(function() { + records.messages.pushObject(records.anotherUser); + }, /You cannot add 'user' records to this relationship/); + }); + }); }); test("A record can be removed from a polymorphic association", function() { @@ -668,19 +679,19 @@ test("A record can be removed from a polymorphic association", function() { user: env.store.find('user', 1), comment: env.store.find('comment', 3) }); - }); - asyncRecords.then(async(function(records) { - records.messages = records.user.get('messages'); - return Ember.RSVP.hash(records); - })).then(async(function(records) { - equal(records.messages.get('length'), 1, "The user has 1 message"); + asyncRecords.then(function(records) { + records.messages = records.user.get('messages'); + return Ember.RSVP.hash(records); + }).then(function(records) { + equal(records.messages.get('length'), 1, "The user has 1 message"); - var removedObject = records.messages.popObject(); + var removedObject = records.messages.popObject(); - equal(removedObject, records.comment, "The message is correctly removed"); - equal(records.messages.get('length'), 0, "The user does not have any messages"); - })); + equal(removedObject, records.comment, "The message is correctly removed"); + equal(records.messages.get('length'), 0, "The user does not have any messages"); + }); + }); }); test("When a record is created on the client, its hasMany arrays should be in a loaded state", function() { @@ -790,23 +801,21 @@ test("dual non-async HM <-> BT", function(){ run(function(){ post = env.store.push('post', { id: 1, comments: [ 1 ] }); firstComment = env.store.push('comment', { id: 1, post: 1 }); - }); - Ember.run(function(){ - return env.store.createRecord('comment', { + env.store.createRecord('comment', { post: post - }).save(); - }).then(async(function(comment){ - var commentPost = comment.get('post'); - var postComments = comment.get('post.comments'); - var postCommentsLength = comment.get('post.comments.length'); - - deepEqual(post, commentPost, 'expect the new comments post, to be the correct post'); - ok(postComments, "comments should exist"); - equal(postCommentsLength, 2, "comment's post should have a reference back to comment"); - ok(postComments && postComments.indexOf(firstComment) !== -1, 'expect to contain first comment'); - ok(postComments && postComments.indexOf(comment) !== -1, 'expected to contain the new comment'); - })); + }).save().then(function(comment){ + var commentPost = comment.get('post'); + var postComments = comment.get('post.comments'); + var postCommentsLength = comment.get('post.comments.length'); + + deepEqual(post, commentPost, 'expect the new comments post, to be the correct post'); + ok(postComments, "comments should exist"); + equal(postCommentsLength, 2, "comment's post should have a reference back to comment"); + ok(postComments && postComments.indexOf(firstComment) !== -1, 'expect to contain first comment'); + ok(postComments && postComments.indexOf(comment) !== -1, 'expected to contain the new comment'); + }); + }); }); test("When an unloaded record is added to the hasMany, it gets fetched once the hasMany is accessed even if the hasMany has been already fetched", function() { @@ -903,9 +912,9 @@ test("Rollbacking a deleted record restores implicit relationship correctly when chapter.rollback(); }); run(function(){ - book.get('chapters').then(async(function(fetchedChapters) { + book.get('chapters').then(function(fetchedChapters) { equal(fetchedChapters.objectAt(0), chapter, 'Book has a chapter after rollback'); - })); + }); }); }); @@ -938,9 +947,9 @@ test("Rollbacking a deleted record restores implicit relationship correctly when chapter.rollback(); }); run(function(){ - page.get('chapter').then(async(function(fetchedChapter) { + page.get('chapter').then(function(fetchedChapter) { equal(fetchedChapter, chapter, 'Page has a chapter after rollback'); - })); + }); }); }); diff --git a/packages/ember-data/tests/integration/relationships/one_to_many_test.js b/packages/ember-data/tests/integration/relationships/one_to_many_test.js index 8feca8e9ebe..0b68af6d461 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_many_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_many_test.js @@ -54,9 +54,9 @@ test("Relationship is available from the belongsTo side even if only loaded from message = store.push('message', {id: 2, title: 'EmberFest was great'}); }); run(function(){ - message.get('user').then(async(function(fetchedUser) { + message.get('user').then(function(fetchedUser) { equal(fetchedUser, user, 'User relationship was set up correctly'); - })); + }); }); }); @@ -76,9 +76,9 @@ test("Relationship is available from the hasMany side even if only loaded from t message = store.push('message', {id: 2, title: 'EmberFest was great', user:1}); }); run(function(){ - user.get('messages').then(async(function(fetchedMessages) { + user.get('messages').then(function(fetchedMessages) { equal(fetchedMessages.objectAt(0), message, 'Messages relationship was set up correctly'); - })); + }); }); }); @@ -101,9 +101,9 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio store.push('message', {id: 2, title: 'EmberConf will be better', user:null}); }); run(function(){ - user.get('messages').then(async(function(fetchedMessages) { + user.get('messages').then(function(fetchedMessages) { equal(get(fetchedMessages, 'length'), 1, 'Messages relationship was set up correctly'); - })); + }); }); }); @@ -127,9 +127,9 @@ test("Fetching a belongsTo that is not defined does not remove the record from a store.push('message', {id: 2, title: 'EmberConf will be better'}); }); run(function(){ - user.get('messages').then(async(function(fetchedMessages) { + user.get('messages').then(function(fetchedMessages) { equal(get(fetchedMessages, 'length'), 2, 'Messages relationship was set up correctly'); - })); + }); }); }); @@ -155,13 +155,13 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT }); run(function(){ - message.get('user').then(async(function(fetchedUser) { + message.get('user').then(function(fetchedUser) { equal(fetchedUser, null, 'User was removed correctly'); - })); + }); - message2.get('user').then(async(function(fetchedUser) { + message2.get('user').then(function(fetchedUser) { equal(fetchedUser, user, 'User was set on the second message'); - })); + }); }); }); @@ -186,9 +186,9 @@ test("Fetching the hasMany side where the hasMany is undefined does not change t }); run(function(){ - message.get('user').then(async(function(fetchedUser) { + message.get('user').then(function(fetchedUser) { equal(fetchedUser, user, 'User was not removed'); - })); + }); }); }); @@ -217,12 +217,12 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - async", }); run(function(){ - user.get('messages').then(async(function(fetchedMessages) { + user.get('messages').then(function(fetchedMessages) { fetchedMessages.pushObject(message2); - message2.get('user').then(async(function(fetchedUser) { + message2.get('user').then(function(fetchedUser) { equal(fetchedUser, user, "user got set correctly"); - })); - })); + }); + }); }); }); @@ -247,12 +247,12 @@ test("Removing from the hasMany side reflects the change on the belongsTo side - }); run(function(){ - user.get('messages').then(async(function(fetchedMessages) { + user.get('messages').then(function(fetchedMessages) { fetchedMessages.removeObject(message); - message.get('user').then(async(function(fetchedUser) { + message.get('user').then(function(fetchedUser) { equal(fetchedUser, null, "user got removed correctly"); - })); - })); + }); + }); }); }); @@ -279,17 +279,17 @@ test("Pushing to the hasMany side keeps the oneToMany invariant on the belongsTo }); run(function(){ - user2.get('messages').then(async(function(fetchedMessages) { + user2.get('messages').then(function(fetchedMessages) { fetchedMessages.pushObject(message); - message.get('user').then(async(function(fetchedUser) { + message.get('user').then(function(fetchedUser) { equal(fetchedUser, user2, "user got set correctly"); - })); + }); - user.get('messages').then(async(function(newFetchedMessages) { + user.get('messages').then(function(newFetchedMessages) { equal(get(newFetchedMessages, 'length'), 0, 'message got removed from the old messages hasMany'); - })); - })); + }); + }); }); }); @@ -318,14 +318,14 @@ test("Setting the belongsTo side keeps the oneToMany invariant on the hasMany- a }); run(function(){ - user.get('messages').then(async(function(fetchedMessages) { + user.get('messages').then(function(fetchedMessages) { equal(get(fetchedMessages, 'length'), 0, 'message got removed from the first user correctly'); - })); + }); }); run(function(){ - user2.get('messages').then(async(function(fetchedMessages) { + user2.get('messages').then(function(fetchedMessages) { equal(get(fetchedMessages, 'length'), 1, 'message got added to the second user correctly'); - })); + }); }); }); @@ -355,15 +355,15 @@ test("Setting the belongsTo side to null removes the record from the hasMany sid }); run(function(){ - user.get('messages').then(async(function(fetchedMessages) { + user.get('messages').then(function(fetchedMessages) { equal(get(fetchedMessages, 'length'), 0, 'message got removed from the user correctly'); - })); + }); }); run(function(){ - message.get('user').then(async(function(fetchedUser) { + message.get('user').then(function(fetchedUser) { equal(fetchedUser, null, 'user got set to null correctly'); - })); + }); }); }); @@ -392,12 +392,12 @@ test("When deleting a record that has a belongsTo it is removed from the hasMany }); run(message, 'deleteRecord'); run(function(){ - message.get('user').then(async(function(fetchedUser) { + message.get('user').then(function(fetchedUser) { equal(fetchedUser, user, 'Message still has the user'); - })); - user.get('messages').then(async(function(fetchedMessages) { + }); + user.get('messages').then(function(fetchedMessages) { equal(fetchedMessages.get('length'), 0, 'User was removed from the messages'); - })); + }); }); }); @@ -420,12 +420,12 @@ test("When deleting a record that has a hasMany it is removed from the belongsTo }); run(user, 'deleteRecord'); run(function(){ - message.get('user').then(async(function(fetchedUser) { + message.get('user').then(function(fetchedUser) { equal(fetchedUser, null, 'Message does not have the user anymore'); - })); - user.get('messages').then(async(function(fetchedMessages) { + }); + user.get('messages').then(function(fetchedMessages) { equal(fetchedMessages.get('length'), 1, 'User still has the messages'); - })); + }); }); }); @@ -457,12 +457,12 @@ test("Rollbacking a deleted record works correctly when the hasMany side has bee message.rollback(); }); run(function(){ - message.get('user').then(async(function(fetchedUser) { + message.get('user').then(function(fetchedUser) { equal(fetchedUser, user, 'Message still has the user'); - })); - user.get('messages').then(async(function(fetchedMessages) { + }); + user.get('messages').then(function(fetchedMessages) { equal(fetchedMessages.objectAt(0), message, 'User has the message'); - })); + }); }); }); @@ -491,12 +491,12 @@ test("Rollbacking a deleted record works correctly when the belongsTo side has b user.rollback(); }); run(function(){ - message.get('user').then(async(function(fetchedUser) { + message.get('user').then(function(fetchedUser) { equal(fetchedUser, user, 'Message has the user again'); - })); - user.get('messages').then(async(function(fetchedMessages) { + }); + user.get('messages').then(function(fetchedMessages) { equal(fetchedMessages.get('length'), 1, 'User still has the messages'); - })); + }); }); }); @@ -526,12 +526,12 @@ test("Rollbacking a created record works correctly when the hasMany side has bee }); run(message, 'rollback'); run(function(){ - message.get('user').then(async(function(fetchedUser) { + message.get('user').then(function(fetchedUser) { equal(fetchedUser, null, 'Message does not have the user anymore'); - })); - user.get('messages').then(async(function(fetchedMessages) { + }); + user.get('messages').then(function(fetchedMessages) { equal(fetchedMessages.get('length'), 0, message, 'User does not have the message anymore'); - })); + }); }); }); @@ -553,16 +553,16 @@ test("Rollbacking a created record works correctly when the belongsTo side has b user = store.createRecord('user'); }); run(function(){ - user.get('messages').then(async(function(messages) { + user.get('messages').then(function(messages) { messages.pushObject(message); user.rollback(); - message.get('user').then(async(function(fetchedUser) { + message.get('user').then(function(fetchedUser) { equal(fetchedUser, null, 'Message does not have the user anymore'); - })); - user.get('messages').then(async(function(fetchedMessages) { + }); + user.get('messages').then(function(fetchedMessages) { equal(fetchedMessages.get('length'), 0, 'User does not have the message anymore'); - })); - })); + }); + }); }); }); diff --git a/packages/ember-data/tests/integration/relationships/one_to_one_test.js b/packages/ember-data/tests/integration/relationships/one_to_one_test.js index 7f0968c5263..06e86d231e6 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_one_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_one_test.js @@ -44,10 +44,10 @@ test("Relationship is available from both sides even if only loaded from one sid run(function(){ stanley = store.push('user', {id:1, name: 'Stanley', bestFriend: 2}); stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + stanleysFriend.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, stanley, 'User relationship was set up correctly'); + }); }); - stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, stanley, 'User relationship was set up correctly'); - })); }); test("Relationship is available from both sides even if only loaded from one side - sync", function () { @@ -64,10 +64,10 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio run(function(){ stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend: 1}); store.push('user', {id:1, name: 'Stanley', bestFriend: null}); + stanleysFriend.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, null, 'User relationship was removed correctly'); + }); }); - stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, null, 'User relationship was removed correctly'); - })); }); test("Fetching a belongsTo that is set to null removes the record from a relationship - sync", function () { @@ -88,23 +88,23 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat run(function(){ stanley = store.push('user', {id:1, name: 'Stanley', bestFriend: 2}); stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend: 1}); - }); - stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, stanley, 'User relationship was initally setup correctly'); - var stanleysNewFriend - run(function(){ - stanleysNewFriend = store.push('user', {id:3, name: "Stanley's New friend", bestFriend: 1}); - }); + stanleysFriend.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, stanley, 'User relationship was initally setup correctly'); + var stanleysNewFriend; + run(function(){ + stanleysNewFriend = store.push('user', {id:3, name: "Stanley's New friend", bestFriend: 1}); + }); - stanley.get('bestFriend').then(async(function(fetchedNewFriend){ - equal(fetchedNewFriend, stanleysNewFriend, 'User relationship was updated correctly'); - })); + stanley.get('bestFriend').then(function(fetchedNewFriend){ + equal(fetchedNewFriend, stanleysNewFriend, 'User relationship was updated correctly'); + }); - stanleysFriend.get('bestFriend').then(async(function(fetchedOldFriend){ - equal(fetchedOldFriend, null, 'The old relationship was set to null correctly'); - })); - })); + stanleysFriend.get('bestFriend').then(function(fetchedOldFriend){ + equal(fetchedOldFriend, null, 'The old relationship was set to null correctly'); + }); + }); + }); }); test("Fetching a belongsTo that is set to a different record, sets the old relationship to null - sync", function () { @@ -135,10 +135,10 @@ test("Setting a OneToOne relationship reflects correctly on the other side- asyn }); run(function(){ stanley.set('bestFriend', stanleysFriend); + stanleysFriend.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, stanley, 'User relationship was updated correctly'); + }); }); - stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, stanley, 'User relationship was updated correctly'); - })); }); test("Setting a OneToOne relationship reflects correctly on the other side- sync", function () { @@ -162,13 +162,13 @@ test("Setting a BelongsTo to a promise unwraps the promise before setting- async }); run(function(){ newFriend.set('bestFriend', stanleysFriend.get('bestFriend')); + stanley.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, newFriend, 'User relationship was updated correctly'); + }); + newFriend.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, stanley, 'User relationship was updated correctly'); + }); }); - stanley.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, newFriend, 'User relationship was updated correctly'); - })); - newFriend.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, stanley, 'User relationship was updated correctly'); - })); }); test("Setting a BelongsTo to a promise works when the promise returns null- async", function () { @@ -180,10 +180,10 @@ test("Setting a BelongsTo to a promise works when the promise returns null- asyn }); run(function(){ newFriend.set('bestFriend', igor.get('bestFriend')); + newFriend.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, null, 'User relationship was updated correctly'); + }); }); - newFriend.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, null, 'User relationship was updated correctly'); - })); }); test("Setting a BelongsTo to a promise that didn't come from a relationship errors out", function () { @@ -224,9 +224,9 @@ test("Setting a BelongsTo to a promise multiple times is resistant to race condi run(function(){ newFriend.set('bestFriend', stanley.get('bestFriend')); newFriend.set('bestFriend', igor.get('bestFriend')); - newFriend.get('bestFriend').then(async(function(fetchedUser) { + newFriend.get('bestFriend').then(function(fetchedUser) { equal(fetchedUser.get('name'), "Igor's friend", 'User relationship was updated correctly'); - })); + }); }); }); @@ -238,10 +238,10 @@ test("Setting a OneToOne relationship to null reflects correctly on the other si }); run(function(){ stanley.set('bestFriend', null); // :( + stanleysFriend.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, null, 'User relationship was removed correctly'); + }); }); - stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, null, 'User relationship was removed correctly'); - })); }); test("Setting a OneToOne relationship to null reflects correctly on the other side - sync", function () { @@ -262,23 +262,23 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu run(function(){ stanley = store.push('user', {id:1, name: 'Stanley', bestFriend: 2}); stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend: 1}); - }); - stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, stanley, 'User relationship was initally setup correctly'); - var stanleysNewFriend = store.push('user', {id:3, name: "Stanley's New friend"}); - run(function(){ - stanleysNewFriend.set('bestFriend', stanley); - }); + stanleysFriend.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, stanley, 'User relationship was initally setup correctly'); + var stanleysNewFriend = store.push('user', {id:3, name: "Stanley's New friend"}); + run(function(){ + stanleysNewFriend.set('bestFriend', stanley); + }); - stanley.get('bestFriend').then(async(function(fetchedNewFriend){ - equal(fetchedNewFriend, stanleysNewFriend, 'User relationship was updated correctly'); - })); + stanley.get('bestFriend').then(function(fetchedNewFriend){ + equal(fetchedNewFriend, stanleysNewFriend, 'User relationship was updated correctly'); + }); - stanleysFriend.get('bestFriend').then(async(function(fetchedOldFriend){ - equal(fetchedOldFriend, null, 'The old relationship was set to null correctly'); - })); - })); + stanleysFriend.get('bestFriend').then(function(fetchedOldFriend){ + equal(fetchedOldFriend, null, 'The old relationship was set to null correctly'); + }); + }); + }); }); test("Setting a belongsTo to a different record, sets the old relationship to null - sync", function () { @@ -320,13 +320,15 @@ test("When deleting a record that has a belongsTo relationship, the record is re stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); }); - run(stanley, 'deleteRecord'); - stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, null, 'Stanley got removed'); - })); - stanley.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, stanleysFriend, 'Stanleys friend did not get removed'); - })); + run(function(){ + stanley.deleteRecord(); + stanleysFriend.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, null, 'Stanley got removed'); + }); + stanley.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, stanleysFriend, 'Stanleys friend did not get removed'); + }); + }); }); test("When deleting a record that has a belongsTo relationship, the record is removed from the inverse but still has access to its own relationship - sync", function () { @@ -357,13 +359,13 @@ test("Rollbacking a deleted record restores the relationship on both sides - asy }); run(function(){ stanley.rollback(); + stanleysFriend.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, stanley, 'Stanley got rollbacked correctly'); + }); + stanley.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, stanleysFriend, 'Stanleys friend did not get removed'); + }); }); - stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, stanley, 'Stanley got rollbacked correctly'); - })); - stanley.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, stanleysFriend, 'Stanleys friend did not get removed'); - })); }); test("Rollbacking a deleted record restores the relationship on both sides - sync", function () { @@ -388,13 +390,13 @@ test("Rollbacking a created record removes the relationship on both sides - asyn }); run(function(){ stanley.rollback(); + stanleysFriend.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, null, 'Stanley got rollbacked correctly'); + }); + stanley.get('bestFriend').then(function(fetchedUser) { + equal(fetchedUser, null, 'Stanleys friend did got removed'); + }); }); - stanleysFriend.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, null, 'Stanley got rollbacked correctly'); - })); - stanley.get('bestFriend').then(async(function(fetchedUser) { - equal(fetchedUser, null, 'Stanleys friend did got removed'); - })); }); test("Rollbacking a created record removes the relationship on both sides - sync", function () { diff --git a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js index ae46a71ae43..93820d99118 100644 --- a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js +++ b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js @@ -99,9 +99,11 @@ test("extractSingle with embedded objects", function() { name: "Umber", villains: ["1"] }); - env.store.find("superVillain", 1).then(async(function(minion) { - equal(minion.get('firstName'), "Tom"); - })); + run(function(){ + env.store.find("superVillain", 1).then(function(minion) { + equal(minion.get('firstName'), "Tom"); + }); + }); }); test("extractSingle with embedded objects inside embedded objects", function() { @@ -144,14 +146,16 @@ test("extractSingle with embedded objects inside embedded objects", function() { name: "Umber", villains: ["1"] }); - env.store.find("superVillain", 1).then(async(function(villain) { - equal(villain.get('firstName'), "Tom"); - equal(villain.get('evilMinions.length'), 1, "Should load the embedded child"); - equal(villain.get('evilMinions.firstObject.name'), "Alex", "Should load the embedded child"); - })); - env.store.find("evilMinion", 1).then(async(function(minion) { - equal(minion.get('name'), "Alex"); - })); + run(function(){ + env.store.find("superVillain", 1).then(function(villain) { + equal(villain.get('firstName'), "Tom"); + equal(villain.get('evilMinions.length'), 1, "Should load the embedded child"); + equal(villain.get('evilMinions.firstObject.name'), "Alex", "Should load the embedded child"); + }); + env.store.find("evilMinion", 1).then(function(minion) { + equal(minion.get('name'), "Alex"); + }); + }); }); test("extractSingle with embedded objects of same type", function() { @@ -329,9 +333,11 @@ test("extractArray with embedded objects", function() { villains: ["1"] }]); - env.store.find("superVillain", 1).then(async(function(minion){ - equal(minion.get('firstName'), "Tom"); - })); + run(function(){ + env.store.find("superVillain", 1).then(function(minion){ + equal(minion.get('firstName'), "Tom"); + }); + }); }); test("extractArray with embedded objects with custom primary key", function() { @@ -372,10 +378,10 @@ test("extractArray with embedded objects with custom primary key", function() { }]); run(function(){ - return env.store.find("superVillain", 1).then(async(function(minion){ + return env.store.find("superVillain", 1).then(function(minion){ env.container.unregister('serializer:superVillain'); equal(minion.get('firstName'), "Alex"); - })); + }); }); }); test("extractArray with embedded objects with identical relationship and attribute key ", function() { @@ -416,9 +422,11 @@ test("extractArray with embedded objects with identical relationship and attribu villains: ["1"] }]); - return env.store.find("superVillain", 1).then(async(function(minion){ - equal(minion.get('firstName'), "Alex"); - })); + run(function(){ + env.store.find("superVillain", 1).then(function(minion){ + equal(minion.get('firstName'), "Alex"); + }); + }); }); test("extractArray with embedded objects of same type as primary type", function() { env.container.register('adapter:comment', DS.ActiveModelAdapter); @@ -725,11 +733,11 @@ test("extractSingle with embedded object (belongsTo relationship)", function() { }); run(function(){ - env.store.find("secretLab", 101).then(async(function(secretLab) { + env.store.find("secretLab", 101).then(function(secretLab) { equal(secretLab.get('id'), '101'); equal(secretLab.get('minionCapacity'), 5000); equal(secretLab.get('vicinity'), 'California, USA'); - })); + }); }); }); diff --git a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js index 05a795dacb7..bd0b3c38f26 100644 --- a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js @@ -79,9 +79,11 @@ test("extractArray with custom typeForRoot", function() { "superVillains": [1] }]); - env.store.find("superVillain", 1).then(async(function(minion){ - equal(minion.get('firstName'), "Tom"); - })); + run(function(){ + env.store.find("superVillain", 1).then(function(minion){ + equal(minion.get('firstName'), "Tom"); + }); + }); }); test("extractArray warning with custom typeForRoot", function() { diff --git a/packages/ember-data/tests/integration/store_test.js b/packages/ember-data/tests/integration/store_test.js index d7322a03290..a4130615ba1 100644 --- a/packages/ember-data/tests/integration/store_test.js +++ b/packages/ember-data/tests/integration/store_test.js @@ -220,9 +220,9 @@ test("Using store#fetch on existing record reloads it", function() { equal(car.get('make'), 'BMC'); run(function(){ - store.fetch('car', 1).then(async(function(car) { + store.fetch('car', 1).then(function(car) { equal(car.get('make'), 'BMCW'); - })); + }); }); }); @@ -241,8 +241,8 @@ test("Using store#fetch on non existing record calls find", function() { ok(!car, 'Car with id=20 should not exist'); run(function(){ - store.fetch('car', 20).then(async(function (car) { + store.fetch('car', 20).then(function (car) { equal(car.get('make'), 'BMCW', 'Car with id=20 is now loaded'); - })); + }); }); }); diff --git a/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js b/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js index bd7e1b3cab3..af1146fa00c 100644 --- a/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js +++ b/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js @@ -22,10 +22,10 @@ test("a record receives a didLoad callback when it has finished loading", functi }); run(function(){ - store.find(Person, 1).then(async(function(person) { + store.find(Person, 1).then(function(person) { equal(person.get('id'), "1", "The person's ID is available"); equal(person.get('name'), "Foo", "The person's properties are available"); - })); + }); }); }); @@ -64,14 +64,16 @@ test("a record receives a didUpdate callback when it has finished updating", fun }); equal(callCount, 0, "precond - didUpdate callback was not called yet"); - asyncPerson.then(async(function(person) { - return run(function(){ - person.set('bar', "Bar"); - return person.save(); + run(function(){ + asyncPerson.then(function(person) { + return run(function(){ + person.set('bar', "Bar"); + return person.save(); + }); + }).then(function() { + equal(callCount, 1, "didUpdate called after update"); }); - })).then(async(function() { - equal(callCount, 1, "didUpdate called after update"); - })); + }); }); test("a record receives a didCreate callback when it has finished updating", function() { @@ -106,9 +108,9 @@ test("a record receives a didCreate callback when it has finished updating", fun run(function(){ - person.save().then(async(function() { + person.save().then(function() { equal(callCount, 1, "didCreate called after commit"); - })); + }); }); }); @@ -149,14 +151,16 @@ test("a record receives a didDelete callback when it has finished deleting", fun equal(callCount, 0, "precond - didDelete callback was not called yet"); - asyncPerson.then(async(function(person) { - return run(function(){ - person.deleteRecord(); - return person.save(); + run(function(){ + asyncPerson.then(function(person) { + return run(function(){ + person.deleteRecord(); + return person.save(); + }); + }).then(function() { + equal(callCount, 1, "didDelete called after delete"); }); - })).then(async(function() { - equal(callCount, 1, "didDelete called after delete"); - })); + }); }); test("a record receives a becameInvalid callback when it became invalid", function() { @@ -198,14 +202,14 @@ test("a record receives a becameInvalid callback when it became invalid", functi // Make sure that the error handler has a chance to attach before // save fails. run(function() { - asyncPerson.then(async(function(person) { + asyncPerson.then(function(person) { return run(function(){ person.set('bar', "Bar"); return person.save(); }); - })).then(null, async(function() { + }).then(null, function() { equal(callCount, 1, "becameInvalid called after invalidating"); - })); + }); }); }); diff --git a/packages/ember-data/tests/unit/model/merge_test.js b/packages/ember-data/tests/unit/model/merge_test.js index ce68bae0a9d..111f9665c8d 100644 --- a/packages/ember-data/tests/unit/model/merge_test.js +++ b/packages/ember-data/tests/unit/model/merge_test.js @@ -36,17 +36,20 @@ test("When a record is in flight, changes can be made", function() { person.set('name', "Thomas Dale"); - promise.then(async(function(person) { + promise.then(function(person) { equal(person.get('isDirty'), true, "The person is still dirty"); equal(person.get('name'), "Thomas Dale", "The changes made still apply"); - })); + }); }); }); test("When a record is in flight, pushes are applied underneath the in flight changes", function() { var adapter = DS.Adapter.extend({ updateRecord: function(store, type, record) { - return Ember.RSVP.resolve({ id: 1, name: "Senor Thomas Dale, Esq.", city: "Portland" }); + // Make sure saving isn't resolved synchronously + return new Ember.RSVP.Promise(function(resolve, reject){ + Ember.run.next(null, resolve, { id: 1, name: "Senor Thomas Dale, Esq.", city: "Portland" }); + }); } }); @@ -58,7 +61,6 @@ test("When a record is in flight, pushes are applied underneath the in flight ch person.set('name', "Thomas Dale"); }); - // Make sure saving isn't resolved synchronously Ember.run(function() { var promise = person.save(); @@ -116,9 +118,9 @@ test("A record with no changes can still be saved", function() { }); run(function(){ - person.save().then(async(function() { + person.save().then(function() { equal(person.get('name'), "Thomas Dale", "the updates occurred"); - })); + }); }); }); @@ -138,10 +140,10 @@ test("A dirty record can be reloaded", function() { }); run(function(){ - person.reload().then(async(function() { + person.reload().then(function() { equal(person.get('isDirty'), true, "the person is dirty"); equal(person.get('name'), "Tomasz Dale", "the local changes remain"); equal(person.get('city'), "Portland", "the new changes apply"); - })); + }); }); }); diff --git a/packages/ember-data/tests/unit/model/relationships_test.js b/packages/ember-data/tests/unit/model/relationships_test.js index aa1ff9672ab..a0bee24c5ca 100644 --- a/packages/ember-data/tests/unit/model/relationships_test.js +++ b/packages/ember-data/tests/unit/model/relationships_test.js @@ -72,7 +72,7 @@ test("hasMany handles pre-loaded relationships", function() { }); run(function(){ - store.find('person', 1).then(async(function(person) { + store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); var tags = get(person, 'tags'); @@ -94,26 +94,25 @@ test("hasMany handles pre-loaded relationships", function() { }); return store.find('person', 3); - })).then(async(function(kselden) { + }).then(function(kselden) { equal(get(get(kselden, 'tags'), 'length'), 0, "a relationship that has not been supplied returns an empty array"); run(function(){ store.push('person', { id: 4, name: "Cyvid Hamluck", pets: [4] }); }); return store.find('person', 4); - })).then(async(function(cyvid) { + }).then(function(cyvid) { equal(get(cyvid, 'name'), "Cyvid Hamluck", "precond - retrieves person record from store"); var pets = get(cyvid, 'pets'); equal(get(pets, 'length'), 1, "the list of pets should have the correct length"); equal(get(pets.objectAt(0), 'name'), "fluffy", "the first pet should be correct"); - run(function(){ store.push(Person, { id: 4, name: "Cyvid Hamluck", pets: [4, 12] }); - }); + equal(pets, get(cyvid, 'pets'), "a relationship returns the same object every time"); equal(get(get(cyvid, 'pets'), 'length'), 2, "the length is updated after new data is loaded"); - })); + }); }); }); @@ -158,7 +157,7 @@ test("hasMany lazily loads async relationships", function() { var wycats; run(function(){ - store.find('person', 2).then(async(function(person) { + store.find('person', 2).then(function(person) { wycats = person; equal(get(wycats, 'name'), "Yehuda Katz", "precond - retrieves person record from store"); @@ -167,23 +166,21 @@ test("hasMany lazily loads async relationships", function() { wycats: wycats, tags: wycats.get('tags') }); - })).then(async(function(records) { + }).then(function(records) { equal(get(records.tags, 'length'), 1, "the list of tags should have the correct length"); equal(get(records.tags.objectAt(0), 'name'), "oohlala", "the first tag should be a Tag"); strictEqual(records.tags.objectAt(0), records.tags.objectAt(0), "the returned object is always the same"); asyncEqual(records.tags.objectAt(0), store.find(Tag, 12), "relationship objects are the same as objects retrieved directly"); - return run(function(){ - return get(wycats, 'tags'); - }); - })).then(async(function(tags) { + return get(wycats, 'tags'); + }).then(function(tags) { var newTag; run(function(){ newTag = store.createRecord(Tag); tags.pushObject(newTag); }); - })); + }); }); }); @@ -277,10 +274,10 @@ test("relationships work when declared with a string path", function() { }); run(function(){ - env.store.find('person', 1).then(async(function(person) { + env.store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); equal(get(person, 'tags.length'), 2, "the list of tags should have the correct length"); - })); + }); }); }); @@ -318,17 +315,17 @@ test("hasMany relationships work when the data hash has not been loaded", functi }; run(function(){ - store.find('person', 1).then(async(function(person) { + store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return run(function(){ return person.get('tags'); }); - })).then(async(function(tags) { + }).then(function(tags) { equal(get(tags, 'length'), 2, "the tags object still exists"); equal(get(tags.objectAt(0), 'name'), "friendly", "Tom Dale is now friendly"); equal(get(tags.objectAt(0), 'isLoaded'), true, "Tom Dale is now loaded"); - })); + }); }); }); @@ -356,18 +353,16 @@ test("it is possible to add a new item to a relationship", function() { }); run(function(){ - store.find(Person, 1).then(async(function(person) { + store.find(Person, 1).then(function(person) { var tag = get(person, 'tags').objectAt(0); equal(get(tag, 'name'), "ember", "precond - relationships work"); - run(function(){ - tag = store.createRecord(Tag, { name: "js" }); - get(person, 'tags').pushObject(tag); - }); + tag = store.createRecord(Tag, { name: "js" }); + get(person, 'tags').pushObject(tag); equal(get(person, 'tags').objectAt(1), tag, "newly added relationship works"); - })); + }); }); }); diff --git a/packages/ember-data/tests/unit/model/rollback_test.js b/packages/ember-data/tests/unit/model/rollback_test.js index a098e3619e6..fde5628601c 100644 --- a/packages/ember-data/tests/unit/model/rollback_test.js +++ b/packages/ember-data/tests/unit/model/rollback_test.js @@ -32,7 +32,10 @@ test("changes to attributes can be rolled back", function() { test("changes to attributes made after a record is in-flight only rolls back the local changes", function() { env.adapter.updateRecord = function(store, type, record) { - return Ember.RSVP.resolve(); + // Make sure the save is async + return new Ember.RSVP.Promise(function(resolve, reject){ + Ember.run.later(null, resolve, 15); + }); }; var person; @@ -41,7 +44,6 @@ test("changes to attributes made after a record is in-flight only rolls back the person.set('firstName', "Thomas"); }); - // Make sure the save is async Ember.run(function() { var saving = person.save(); @@ -77,7 +79,7 @@ test("a record's changes can be made if it fails to save", function() { deepEqual(person.changedAttributes(), {firstName: ["Tom", "Thomas"]}); run(function(){ - person.save().then(null, async(function() { + person.save().then(null, function() { equal(person.get('isError'), true); deepEqual(person.changedAttributes(), {firstName: ["Tom", "Thomas"]}); @@ -86,7 +88,7 @@ test("a record's changes can be made if it fails to save", function() { equal(person.get('firstName'), "Tom"); equal(person.get('isError'), false); deepEqual(person.changedAttributes(), {}); - })); + }); }); }); @@ -108,7 +110,7 @@ test("a deleted record can be rollbacked if it fails to save, record arrays are equal(people.get('length'), 0, "a deleted record does not appear in record array anymore"); run(function(){ - person.save().then(null, async(function() { + person.save().then(null, function() { equal(person.get('isError'), true); equal(person.get('isDeleted'), true); run(function(){ @@ -116,9 +118,9 @@ test("a deleted record can be rollbacked if it fails to save, record arrays are }); equal(person.get('isDeleted'), false); equal(person.get('isError'), false); - })).then(async(function() { + }).then(function() { equal(people.get('length'), 1, "the underlying record array is updated accordingly in an asynchronous way"); - })); + }); }); }); diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index 912c9997051..ff2723f10ab 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -35,38 +35,36 @@ test("can have a property set on it", function() { test("setting a property on a record that has not changed does not cause it to become dirty", function() { run(function(){ store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); - store.find(Person, 1).then(async(function(person) { + store.find(Person, 1).then(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); - run(function(){ - person.set('name', "Peter"); - person.set('isDrugAddict', true); - }); + person.set('name', "Peter"); + person.set('isDrugAddict', true); equal(person.get('isDirty'), false, "record does not become dirty after setting property to old value"); - })); + }); }); }); test("resetting a property on a record cause it to become clean again", function() { run(function(){ store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); - store.find(Person, 1).then(async(function(person) { + store.find(Person, 1).then(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); person.set('isDrugAddict', false); equal(person.get('isDirty'), true, "record becomes dirty after setting property to a new value"); person.set('isDrugAddict', true); equal(person.get('isDirty'), false, "record becomes clean after resetting property to the old value"); - })); + }); }); }); test("a record reports its unique id via the `id` property", function() { run(function(){ store.push(Person, { id: 1 }); - store.find(Person, 1).then(async(function(record) { + store.find(Person, 1).then(function(record) { equal(get(record, 'id'), 1, "reports id as id by default"); - })); + }); }); }); @@ -74,9 +72,11 @@ test("a record's id is included in its toString representation", function() { run(function(){ store.push(Person, { id: 1 }); - store.find(Person, 1).then(async(function(record) { - equal(record.toString(), '<(subclass of DS.Model):'+Ember.guidFor(record)+':1>', "reports id in toString"); - })); + run(function(){ + store.find(Person, 1).then(function(record) { + equal(record.toString(), '<(subclass of DS.Model):'+Ember.guidFor(record)+':1>', "reports id in toString"); + }); + }); }); }); @@ -102,9 +102,9 @@ test("a collision of a record's id with object function's name", function() { } run(function(){ store.push(Person, { id: 'watch' }); - store.find(Person, 'watch').then(async(function(record) { + store.find(Person, 'watch').then(function(record) { equal(get(record, 'id'), 'watch', "record is successfully created and could be found by its id"); - })); + }); }); } finally { if (!hasWatchMethod) { @@ -117,9 +117,9 @@ test("it should use `_reference` and not `reference` to store its reference", fu run(function(){ store.push(Person, { id: 1 }); - store.find(Person, 1).then(async(function(record) { + store.find(Person, 1).then(function(record) { equal(record.get('reference'), undefined, "doesn't shadow reference key"); - })); + }); }); }); @@ -135,13 +135,13 @@ test("it should cache attributes", function() { run(function(){ store.push(Post, { id: 1 }); - store.find(Post, 1).then(async(function(record) { + store.find(Post, 1).then(function(record) { run(function(){ record.set('updatedAt', date); }); deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); strictEqual(get(record, 'updatedAt'), get(record, 'updatedAt'), "second get still returns the same object"); - })).finally(function(){ + }).finally(function(){ run(store, 'destroy'); }); }); @@ -224,12 +224,10 @@ module("unit/model - DS.Model updating", { test("a DS.Model can update its attributes", function() { run(function(){ - store.find(Person, 2).then(async(function(person) { - run(function(){ - set(person, 'name', "Brohuda Katz"); - }); + store.find(Person, 2).then(function(person) { + set(person, 'name', "Brohuda Katz"); equal(get(person, 'name'), "Brohuda Katz", "setting took hold"); - })); + }); }); }); @@ -318,7 +316,7 @@ test("setting a property to undefined on a newly created record should not impac // thrown out if/when the current `_attributes` hash logic is removed. test("setting a property back to its original value removes the property from the `_attributes` hash", function() { run(function(){ - store.find(Person, 1).then(async(function(person) { + store.find(Person, 1).then(function(person) { equal(person._attributes.name, undefined, "the `_attributes` hash is clean"); set(person, 'name', "Niceguy Dale"); @@ -328,7 +326,7 @@ test("setting a property back to its original value removes the property from th set(person, 'name', "Scumbag Dale"); equal(person._attributes.name, undefined, "the `_attributes` hash is reset"); - })); + }); }); }); @@ -437,9 +435,9 @@ var converts = function(type, provided, expected) { run(function(){ testStore.push(Model, serializer.normalize(Model, { id: 1, name: provided })); testStore.push(Model, serializer.normalize(Model, { id: 2 })); - testStore.find('model', 1).then(async(function(record) { + testStore.find('model', 1).then(function(record) { deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); - })); + }); }); // See: Github issue #421 @@ -460,9 +458,9 @@ var convertsFromServer = function(type, provided, expected) { run(function(){ testStore.push(Model, serializer.normalize(Model, { id: "1", name: provided })); - testStore.find('model', 1).then(async(function(record) { + testStore.find('model', 1).then(function(record) { deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); - })); + }); }); }; @@ -475,10 +473,10 @@ var convertsWhenSet = function(type, provided, expected) { run(function(){ testStore.push(Model, { id: 2 }); - testStore.find('model', 2).then(async(function(record) { + testStore.find('model', 2).then(function(record) { set(record, 'name', provided); deepEqual(record.serialize().name, expected, type + " saves " + provided + " as " + expected); - })); + }); }); }; @@ -528,12 +526,12 @@ test("a DS.Model can describe Date attributes", function() { run(function(){ store.push(Person, { id: 1 }); - store.find(Person, 1).then(async(function(record) { + store.find(Person, 1).then(function(record) { run(function(){ record.set('updatedAt', date); }); deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); - })); + }); }); convertsFromServer('date', dateString, date); convertsWhenSet('date', date, dateString); @@ -566,10 +564,10 @@ test("ensure model exits loading state, materializes data and fulfills promise o }); run(function(){ - store.find(Person, 1).then(async(function(person) { + store.find(Person, 1).then(function(person) { equal(get(person, 'currentState.stateName'), 'root.loaded.saved', 'model is in loaded state'); equal(get(person, 'isLoaded'), true, 'model is loaded'); - })); + }); }); }); diff --git a/packages/ember-data/tests/unit/record_array_test.js b/packages/ember-data/tests/unit/record_array_test.js index 8335f294f1d..3a860e97acc 100644 --- a/packages/ember-data/tests/unit/record_array_test.js +++ b/packages/ember-data/tests/unit/record_array_test.js @@ -20,11 +20,11 @@ test("a record array is backed by records", function() { }); run(function(){ - store.findByIds(Person, [1,2,3]).then(async(function(records) { + store.findByIds(Person, [1,2,3]).then(function(records) { for (var i=0, l=get(array, 'length'); i Date: Mon, 1 Dec 2014 11:49:01 -0600 Subject: [PATCH 0482/2527] fix testem running for file name change --- config/testem-beta.json | 2 +- config/testem-canary.json | 2 +- config/testem-stable.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/testem-beta.json b/config/testem-beta.json index 5c5232a3b65..86d96f4801c 100644 --- a/config/testem-beta.json +++ b/config/testem-beta.json @@ -9,6 +9,6 @@ ], "routes": { "/ember-data.js": "dist/ember-data.js", - "/tests/tests.js": "dist/tests.js" + "/tests/ember-data-tests.js": "dist/ember-data-tests.js" } } diff --git a/config/testem-canary.json b/config/testem-canary.json index 1fe5ad2d3fb..d9e6f97065f 100644 --- a/config/testem-canary.json +++ b/config/testem-canary.json @@ -9,6 +9,6 @@ ], "routes": { "/ember-data.js": "dist/ember-data.js", - "/tests/tests.js": "dist/tests.js" + "/tests/ember-data-tests.js": "dist/ember-data-tests.js" } } diff --git a/config/testem-stable.json b/config/testem-stable.json index ba21d9f305f..9b491b8f2bc 100644 --- a/config/testem-stable.json +++ b/config/testem-stable.json @@ -9,6 +9,6 @@ ], "routes": { "/ember-data.js": "dist/ember-data.js", - "/tests/tests.js": "dist/tests.js" + "/tests/ember-data-tests.js": "dist/ember-data-tests.js" } } From b0e3a26f24e40d60f22581ea4bf573934f5cc102 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Tue, 2 Dec 2014 00:27:38 +0100 Subject: [PATCH 0483/2527] Calling store.all() multiple times updates RecordArray immediately --- packages/ember-data/lib/system/store.js | 5 ++++- packages/ember-data/tests/integration/all_test.js | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 9dd50fadec5..2d112ded0a1 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -888,7 +888,10 @@ Store = Ember.Object.extend({ var typeMap = this.typeMapFor(type); var findAllCache = typeMap.findAllCache; - if (findAllCache) { return findAllCache; } + if (findAllCache) { + this.recordArrayManager.updateFilter(findAllCache, type); + return findAllCache; + } var array = this.recordArrayManager.createRecordArray(type); diff --git a/packages/ember-data/tests/integration/all_test.js b/packages/ember-data/tests/integration/all_test.js index 5a5963060f0..09c23bebbe4 100644 --- a/packages/ember-data/tests/integration/all_test.js +++ b/packages/ember-data/tests/integration/all_test.js @@ -32,3 +32,15 @@ test("store.all('person') should return all records and should update with new o equal(get(all, 'length'), 3); }); + +test("Calling store.all() multiple times should update immediately inside the runloop", function() { + expect(3); + + Ember.run(function() { + equal(get(store.all('person'), 'length'), 0, 'should initially be empty'); + store.createRecord('person', { name: "Tomster" }); + equal(get(store.all('person'), 'length'), 1, 'should contain one person'); + store.push('person', { id: 1, name: "Tomster's friend" }); + equal(get(store.all('person'), 'length'), 2, 'should contain two people'); + }); +}); From caa330185eba3ce4c367394e5ebaa97a7f5bfda1 Mon Sep 17 00:00:00 2001 From: IgorT Date: Mon, 1 Dec 2014 21:50:24 -0500 Subject: [PATCH 0484/2527] Additional store.all test --- packages/ember-data/tests/integration/all_test.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/ember-data/tests/integration/all_test.js b/packages/ember-data/tests/integration/all_test.js index 09c23bebbe4..e1495bc7535 100644 --- a/packages/ember-data/tests/integration/all_test.js +++ b/packages/ember-data/tests/integration/all_test.js @@ -44,3 +44,12 @@ test("Calling store.all() multiple times should update immediately inside the ru equal(get(store.all('person'), 'length'), 2, 'should contain two people'); }); }); + +test("Calling store.all() after creating a record should return correct data", function() { + expect(1); + + Ember.run(function() { + store.createRecord('person', { name: "Tomster" }); + equal(get(store.all('person'), 'length'), 1, 'should contain one person'); + }); +}); From 0d0eb7785b2a7d6ef12ccf758bf06b209b4fc899 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Thu, 27 Nov 2014 23:47:54 +0100 Subject: [PATCH 0485/2527] Assert model type is string in DS.belongsTo() and DS.hasMany() --- .../lib/system/relationships/belongs_to.js | 6 +-- .../lib/system/relationships/has_many.js | 4 +- .../relationships/belongs_to_test.js | 12 ++++++ .../relationships/has_many_test.js | 12 ++++++ .../inverse_relationships_test.js | 41 ++++++++++++------- packages/ember-data/tests/unit/debug_test.js | 26 +++++------- .../tests/unit/model/relationships_test.js | 31 +++++++++++--- .../tests/unit/store/unload_test.js | 28 +++++++------ 8 files changed, 109 insertions(+), 51 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index 3ea24a28c2b..e228a2e56c6 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -44,7 +44,7 @@ import { Model } from 'ember-data/system/model'; @namespace @method belongsTo @for DS - @param {String or DS.Model} type the model type of the relationship + @param {String} type the model type of the relationship @param {Object} options a hash of options @return {Ember.computed} relationship */ @@ -52,10 +52,10 @@ function belongsTo(type, options) { if (typeof type === 'object') { options = type; type = undefined; - } else { - Ember.assert("The first argument to DS.belongsTo must be a string representing a model type key, e.g. use DS.belongsTo('person') to define a relation to the App.Person model", !!type && (typeof type === 'string' || Model.detect(type))); } + Ember.assert("The first argument to DS.belongsTo must be a string representing a model type key, not an instance of " + Ember.inspect(type) + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", typeof type === 'string' || typeof type === 'undefined'); + options = options || {}; var meta = { diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index b3931a26348..8fa2bd161ca 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -78,7 +78,7 @@ import { Model } from "ember-data/system/model"; @namespace @method hasMany @for DS - @param {String or DS.Model} type the model type of the relationship + @param {String} type the model type of the relationship @param {Object} options a hash of options @return {Ember.computed} relationship */ @@ -88,6 +88,8 @@ function hasMany(type, options) { type = undefined; } + Ember.assert("The first argument to DS.hasMany must be a string representing a model type key, not an instance of " + Ember.inspect(type) + ". E.g., to define a relation to the Comment model, use DS.hasMany('comment')", typeof type === 'string' || typeof type === 'undefined'); + options = options || {}; // Metadata about relationships is stored on the meta of diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index 0a0bb9fa7be..657a6c9cdc9 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -488,3 +488,15 @@ test("Rollbacking a deleted record restores implicit relationship - sync", funct }); equal(book.get('author'), author, 'Book has an author after rollback'); }); + +test("Passing a model as type to belongsTo should not work", function () { + expect(1); + + expectAssertion(function() { + User = DS.Model.extend(); + + Contact = DS.Model.extend({ + user: belongsTo(User) + }); + }, /The first argument to DS.belongsTo must be a string/); +}); diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 3a07b60bc0e..df4c185c4e6 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -967,3 +967,15 @@ test("Rollbacking a deleted record restores implicit relationship correctly when equal(page.get('chapter'), chapter, "Page has a chapter after rollback"); }); }); + +test("Passing a model as type to hasMany should not work", function () { + expect(1); + + expectAssertion(function() { + User = DS.Model.extend(); + + Contact = DS.Model.extend({ + users: hasMany(User) + }); + }, /The first argument to DS.hasMany must be a string/); +}); diff --git a/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js b/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js index 090d57a1aeb..85babca5a0e 100644 --- a/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js +++ b/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js @@ -33,17 +33,28 @@ test("Inverse relationships can be explicitly nullable", function () { User = DS.Model.extend(); Post = DS.Model.extend({ - lastParticipant: DS.belongsTo(User, { inverse: null }), - participants: DS.hasMany(User, { inverse: 'posts' }) + lastParticipant: DS.belongsTo('user', { inverse: null }), + participants: DS.hasMany('user', { inverse: 'posts' }) }); User.reopen({ - posts: DS.hasMany(Post, { inverse: 'participants' }) + posts: DS.hasMany('post', { inverse: 'participants' }) }); - equal(User.inverseFor('posts').name, 'participants', 'User.posts inverse is Post.participants'); - equal(Post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); - equal(Post.inverseFor('participants').name, 'posts', 'Post.participants inverse is User.posts'); + var store = createStore({ + user: User, + post: Post + }); + var user, post; + + run(function() { + user = store.createRecord('user'); + post = store.createRecord('post'); + }); + + equal(user.inverseFor('posts').name, 'participants', 'User.posts inverse is Post.participants'); + equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); + equal(post.inverseFor('participants').name, 'posts', 'Post.participants inverse is User.posts'); }); test("When a record is added to a has-many relationship, the inverse belongsTo can be set explicitly", function() { @@ -162,9 +173,10 @@ test("When setting a belongsTo, the OneToOne invariant is transitive", function( post: DS.belongsTo('post') }); - var env = setupStore({ post: Post, comment: Comment }), - store = env.store; - var comment, post, post2; + var store = createStore({ + post: Post, + comment: Comment + }); run(function(){ comment = store.createRecord('comment'); @@ -198,9 +210,10 @@ test("When setting a belongsTo, the OneToOne invariant is commutative", function post: DS.belongsTo('post') }); - var env = setupStore({ post: Post, comment: Comment }), - store = env.store; - var comment, post, comment2; + var store = createStore({ + post: Post, + comment: Comment + }); run(function(){ comment = store.createRecord('comment'); @@ -406,7 +419,7 @@ test("Inverse relationships that don't exist throw a nice error for a hasMany", Comment = DS.Model.extend(); Post = DS.Model.extend({ - comments: DS.hasMany(Comment, { inverse: 'testPost' }) + comments: DS.hasMany('comment', { inverse: 'testPost' }) }); var env = setupStore({ post: Post, comment: Comment, user: User }); @@ -427,7 +440,7 @@ test("Inverse relationships that don't exist throw a nice error for a belongsTo" Comment = DS.Model.extend(); Post = DS.Model.extend({ - user: DS.belongsTo(User, { inverse: 'testPost' }) + user: DS.belongsTo('user', { inverse: 'testPost' }) }); var env = setupStore({ post: Post, comment: Comment, user: User }); diff --git a/packages/ember-data/tests/unit/debug_test.js b/packages/ember-data/tests/unit/debug_test.js index 985fed020c0..15fcf05d00b 100644 --- a/packages/ember-data/tests/unit/debug_test.js +++ b/packages/ember-data/tests/unit/debug_test.js @@ -3,20 +3,7 @@ var run = Ember.run; var TestAdapter = DS.Adapter.extend(); -module("Debug", { - setup: function() { - store = DS.Store.create({ - adapter: TestAdapter.extend() - }); - }, - - teardown: function() { - run(function(){ - store.destroy(); - store = null; - }); - } -}); +module("Debug"); test("_debugInfo groups the attributes and relationships correctly", function() { var MaritalStatus = DS.Model.extend({ @@ -30,8 +17,15 @@ test("_debugInfo groups the attributes and relationships correctly", function() var User = DS.Model.extend({ name: DS.attr('string'), isDrugAddict: DS.attr('boolean'), - maritalStatus: DS.belongsTo(MaritalStatus), - posts: DS.hasMany(Post) + maritalStatus: DS.belongsTo('maritalStatus'), + posts: DS.hasMany('post') + }); + + var store = createStore({ + adapter: TestAdapter.extend(), + maritalStatus: MaritalStatus, + post: Post, + user: User }); var record; diff --git a/packages/ember-data/tests/unit/model/relationships_test.js b/packages/ember-data/tests/unit/model/relationships_test.js index a0bee24c5ca..d2c07f78c94 100644 --- a/packages/ember-data/tests/unit/model/relationships_test.js +++ b/packages/ember-data/tests/unit/model/relationships_test.js @@ -7,12 +7,23 @@ test("exposes a hash of the relationships on a model", function() { var Occupation = DS.Model.extend(); var Person = DS.Model.extend({ - occupations: DS.hasMany(Occupation) + occupations: DS.hasMany('occupation') }); Person.reopen({ - people: DS.hasMany(Person), - parent: DS.belongsTo(Person) + people: DS.hasMany('person', { inverse: 'parent' }), + parent: DS.belongsTo('person') + }); + + var store = createStore({ + occupation: Occupation, + person: Person + }); + var person, occupation; + + run(function() { + person = store.createRecord('person'); + occupation = store.createRecord('occupation'); }); var relationships = get(Person, 'relationships'); @@ -20,7 +31,6 @@ test("exposes a hash of the relationships on a model", function() { { name: "people", kind: "hasMany" }, { name: "parent", kind: "belongsTo" } ]); - deepEqual(relationships.get(Occupation), [ { name: "occupations", kind: "hasMany" } ]); @@ -191,7 +201,18 @@ test("should be able to retrieve the type for a hasMany relationship from its me var Person = DS.Model.extend({ name: DS.attr('string'), - tags: DS.hasMany(Tag) + tags: DS.hasMany('tag') + }); + + var store = createStore({ + tag: Tag, + person: Person + }); + var tag, person; + + run(function() { + tag = store.createRecord('tag'); + person = store.createRecord('person'); }); equal(Person.typeForRelationship('tags'), Tag, "returns the relationship type"); diff --git a/packages/ember-data/tests/unit/store/unload_test.js b/packages/ember-data/tests/unit/store/unload_test.js index 26156599503..73740c87154 100644 --- a/packages/ember-data/tests/unit/store/unload_test.js +++ b/packages/ember-data/tests/unit/store/unload_test.js @@ -73,16 +73,6 @@ module("DS.Store - unload record with relationships"); test("can commit store after unload record with relationships", function() { - store = createStore({ adapter: DS.Adapter.extend({ - find: function() { - return Ember.RSVP.resolve({ id: 1, description: 'cuisinart', brand: 1 }); - }, - createRecord: function(store, type, record) { - return Ember.RSVP.resolve(); - } - }) - }); - var like, product; var Brand = DS.Model.extend({ @@ -91,11 +81,25 @@ test("can commit store after unload record with relationships", function() { var Product = DS.Model.extend({ description: DS.attr('string'), - brand: DS.belongsTo(Brand) + brand: DS.belongsTo('brand') }); var Like = DS.Model.extend({ - product: DS.belongsTo(Product) + product: DS.belongsTo('product') + }); + + var store = createStore({ + adapter: DS.Adapter.extend({ + find: function() { + return Ember.RSVP.resolve({ id: 1, description: 'cuisinart', brand: 1 }); + }, + createRecord: function(store, type, record) { + return Ember.RSVP.resolve(); + } + }), + brand: Brand, + product: Product, + like: Like }); var asyncRecords; From 0ecb2ad554ed79642ab487d55a80c95295f71eb5 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Sat, 6 Sep 2014 22:19:39 +0200 Subject: [PATCH 0486/2527] Added additional ajaxSuccess test --- .../integration/adapter/rest_adapter_test.js | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 7fa38a3e163..39852acc902 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -1687,3 +1687,30 @@ test('calls ajaxError with jqXHR, jqXHR.responseText', function(){ }); Ember.$.ajax = originalAjax; }); + +test("rejects promise if DS.InvalidError is returned from adapter.ajaxSuccess", function(){ + expect(3); + var originalAjax = Ember.$.ajax; + var jqXHR = {}; + var data = { + something: 'is invalid' + } + + Ember.$.ajax = function(hash) { + hash.success(data, 'ok', jqXHR); + }; + + adapter.ajaxSuccess = function(xhr, json) { + ok(true, 'ajaxSuccess should be called'); + return new DS.InvalidError(json); + }; + + Ember.run(function() { + store.find('post', '1').then(null, function(reason) { + ok(true, 'promise should be rejected'); + ok(reason instanceof DS.InvalidError, 'reason should be an instance of DS.InvalidError') + }); + }); + + Ember.$.ajax = originalAjax; +}); \ No newline at end of file From 0506f2e7d46246b3d5be8090e8aa097e458d3448 Mon Sep 17 00:00:00 2001 From: IgorT Date: Tue, 2 Dec 2014 04:03:40 -0500 Subject: [PATCH 0487/2527] Properly clean up destroyed record arrays This build upon #2361 which cleaned up filtered record arrays, but did not clean up record arrays coming from .all and .find --- .../lib/system/record_array_manager.js | 3 ++- .../record_arrays/filtered_record_array.js | 12 ---------- .../lib/system/record_arrays/record_array.js | 13 +++++++++++ .../tests/unit/record_array_test.js | 23 +++++++++++++++++++ 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index ca7de7f3abb..cba30d1c189 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -195,7 +195,8 @@ export default Ember.Object.extend({ type: type, content: Ember.A(), store: this.store, - isLoaded: true + isLoaded: true, + manager: this }); this.registerFilteredRecordArray(array, type); diff --git a/packages/ember-data/lib/system/record_arrays/filtered_record_array.js b/packages/ember-data/lib/system/record_arrays/filtered_record_array.js index 6f1d7032ea3..15b1bdb4634 100644 --- a/packages/ember-data/lib/system/record_arrays/filtered_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/filtered_record_array.js @@ -64,16 +64,4 @@ export default RecordArray.extend({ Ember.run.once(this, this._updateFilter); }, 'filterFunction'), - /** - @method _unregisterFromManager - @private - */ - _unregisterFromManager: function(){ - this.manager.unregisterFilteredRecordArray(this); - }, - - willDestroy: function(){ - this._unregisterFromManager(); - this._super(); - } }); diff --git a/packages/ember-data/lib/system/record_arrays/record_array.js b/packages/ember-data/lib/system/record_arrays/record_array.js index c724ccadbbd..4323ca94288 100644 --- a/packages/ember-data/lib/system/record_arrays/record_array.js +++ b/packages/ember-data/lib/system/record_arrays/record_array.js @@ -196,7 +196,20 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { }); }, + /** + @method _unregisterFromManager + @private + */ + _unregisterFromManager: function(){ + var manager = get(this, 'manager'); + //We will stop needing this stupid if statement soon, once manyArray are refactored to not be RecordArrays + if (manager) { + manager.unregisterFilteredRecordArray(this); + } + }, + willDestroy: function(){ + this._unregisterFromManager(); this._dissociateFromOwnRecords(); this._super(); } diff --git a/packages/ember-data/tests/unit/record_array_test.js b/packages/ember-data/tests/unit/record_array_test.js index 3a860e97acc..cd238243c5e 100644 --- a/packages/ember-data/tests/unit/record_array_test.js +++ b/packages/ember-data/tests/unit/record_array_test.js @@ -43,6 +43,29 @@ test("acts as a live query", function() { equal(get(recordArray, 'lastObject.name'), 'brohuda'); }); +test("stops updating when destroyed", function() { + expect(3); + var store = createStore(); + + var recordArray = store.all(Person); + run(function(){ + store.push(Person, { id: 1, name: 'wycats' }); + }); + + run(function() { + recordArray.destroy(); + }); + + run(function() { + equal(recordArray.get('length'), undefined, "Has no more records"); + store.push(Person, { id: 2, name: 'brohuda' }); + }); + + equal(recordArray.get('length'), undefined, "Has not been updated"); + equal(recordArray.get('content'), undefined, "Has not been updated"); +}); + + test("a loaded record is removed from a record array when it is deleted", function() { var Tag = DS.Model.extend({ people: DS.hasMany('person') From 885dc3996f3cc83e014c450cdff010ffedf6ec52 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Tue, 2 Dec 2014 10:18:26 +0100 Subject: [PATCH 0488/2527] Wrap ajax tests in try/finally to make sure we restore Ember.$.ajax --- .../integration/adapter/rest_adapter_test.js | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 7fa38a3e163..43385f7ba77 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -1657,10 +1657,13 @@ test("calls adapter.ajaxSuccess with the jqXHR and json", function(){ return json; }; - run(function(){ - store.find('post', '1'); - }); - Ember.$.ajax = originalAjax; + try { + run(function(){ + store.find('post', '1'); + }); + } finally { + Ember.$.ajax = originalAjax; + } }); test('calls ajaxError with jqXHR, jqXHR.responseText', function(){ @@ -1680,10 +1683,13 @@ test('calls ajaxError with jqXHR, jqXHR.responseText', function(){ return new Error('nope!'); }; - run(function(){ - store.find('post', '1').catch(function(err){ - ok(err, 'promise rejected'); + try { + run(function(){ + store.find('post', '1').catch(function(err){ + ok(err, 'promise rejected'); + }); }); - }); - Ember.$.ajax = originalAjax; + } finally { + Ember.$.ajax = originalAjax; + } }); From 5b705a7f8f6b7e768fcbe3561d1befb16274280b Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Thu, 13 Nov 2014 06:35:45 +0100 Subject: [PATCH 0489/2527] Deprecate store.update() - store.push() now handles partial updates - store.update() has been deprecated --- .../lib/serializers/json_serializer.js | 12 ++-- packages/ember-data/lib/system/model/model.js | 10 +--- packages/ember-data/lib/system/store.js | 55 ++++--------------- .../ember-data/tests/unit/store/push_test.js | 51 +++++++++++++++-- 4 files changed, 65 insertions(+), 63 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index ab479634332..8b00c0dace8 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -791,8 +791,8 @@ export default Ember.Object.extend({ /** `extractCreateRecord` is a hook into the extract method used when a - call is made to `DS.Store#createRecord`. By default this method is - alias for [extractSave](#method_extractSave). + call is made to `DS.Model#save` and the record is new. By default + this method is alias for [extractSave](#method_extractSave). @method extractCreateRecord @param {DS.Store} store @@ -807,8 +807,8 @@ export default Ember.Object.extend({ }, /** `extractUpdateRecord` is a hook into the extract method used when - a call is made to `DS.Store#update`. By default this method is alias - for [extractSave](#method_extractSave). + a call is made to `DS.Model#save` and the record has been updated. + By default this method is alias for [extractSave](#method_extractSave). @method extractUpdateRecord @param {DS.Store} store @@ -823,8 +823,8 @@ export default Ember.Object.extend({ }, /** `extractDeleteRecord` is a hook into the extract method used when - a call is made to `DS.Store#deleteRecord`. By default this method is - alias for [extractSave](#method_extractSave). + a call is made to `DS.Model#save` and the record has been deleted. + By default this method is alias for [extractSave](#method_extractSave). @method extractDeleteRecord @param {DS.Store} store diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 0bb8ad27d0e..1a039bd835c 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -866,17 +866,11 @@ var Model = Ember.Object.extend(Ember.Evented, { @method setupData @private @param {Object} data - @param {Boolean} partial the data should be merged into - the existing data, not replace it. */ - setupData: function(data, partial) { + setupData: function(data) { Ember.assert("Expected an object as `data` in `setupData`", Ember.typeOf(data) === 'object'); - if (partial) { - merge(this._data, data); - } else { - this._data = data; - } + Ember.merge(this._data, data); this.pushedData(); diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 06b72570650..12c548f5946 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -95,7 +95,7 @@ function coerceId(id) { You can learn more about writing a custom adapter by reading the `DS.Adapter` documentation. - ### Store createRecord() vs. push() vs. pushPayload() vs. update() + ### Store createRecord() vs. push() vs. pushPayload() The store provides multiple ways to create new record objects. They have some subtle differences in their use which are detailed below: @@ -108,7 +108,7 @@ function coerceId(id) { [push](#method_push) is used to notify Ember Data's store of new or updated records that exist in the backend. This will return a record in the `loaded.saved` state. The primary use-case for `store#push` is - to notify Ember Data about record updates that happen + to notify Ember Data about record updates (full or partial) that happen outside of the normal adapter methods (for example [SSE](http://dev.w3.org/html5/eventsource/) or [Web Sockets](http://www.w3.org/TR/2009/WD-websockets-20091222/)). @@ -117,10 +117,6 @@ function coerceId(id) { `store#push` that will deserialize payloads if the Serializer implements a `pushPayload` method. - [update](#method_update) works like `push`, except it can handle - partial attributes without overwriting the existing record - properties. - Note: When creating a new record using any of the above methods Ember Data will update `DS.RecordArray`s such as those returned by `store#all()`, `store#findAll()` or `store#filter()`. This means any @@ -1227,14 +1223,12 @@ Store = Ember.Object.extend({ @private @param {String or subclass of DS.Model} type @param {Object} data - @param {Boolean} partial the data should be merged into - the existing data, not replace it. */ - _load: function(type, data, partial) { + _load: function(type, data) { var id = coerceId(data.id); var record = this.recordForId(type, id); - record.setupData(data, partial); + record.setupData(data); this.recordArrayManager.recordDidChange(record); return record; @@ -1341,12 +1335,9 @@ Store = Ember.Object.extend({ @return {DS.Model} the record that was created or updated. */ - push: function(typeName, data, _partial) { - // _partial is an internal param used by `update`. - // If passed, it means that the data should be - // merged into the existing data, not replace it. - Ember.assert("Expected an object as `data` in a call to `push`/`update` for " + typeName + " , but was " + data, Ember.typeOf(data) === 'object'); - Ember.assert("You must include an `id` for " + typeName + " in an object passed to `push`/`update`", data.id != null && data.id !== ''); + push: function(typeName, data) { + Ember.assert("Expected an object as `data` in a call to `push` for " + typeName + " , but was " + data, Ember.typeOf(data) === 'object'); + Ember.assert("You must include an `id` for " + typeName + " in an object passed to `push`", data.id != null && data.id !== ''); var type = this.modelFor(typeName); var filter = Ember.EnumerableUtils.filter; @@ -1369,7 +1360,7 @@ Store = Ember.Object.extend({ // Actually load the record into the store. - this._load(type, data, _partial); + this._load(type, data); var record = this.recordForId(type, data.id); @@ -1465,39 +1456,15 @@ Store = Ember.Object.extend({ }, /** - Update existing records in the store. Unlike [push](#method_push), - update will merge the new data properties with the existing - properties. This makes it safe to use with a subset of record - attributes. This method expects normalized data. - - `update` is useful if your app broadcasts partial updates to - records. - - ```js - App.Person = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string') - }); - - store.get('person', 1).then(function(tom) { - tom.get('firstName'); // Tom - tom.get('lastName'); // Dale - - var updateEvent = {id: 1, firstName: "TomHuda"}; - store.update('person', updateEvent); - - tom.get('firstName'); // TomHuda - tom.get('lastName'); // Dale - }); - ``` - @method update @param {String} type @param {Object} data @return {DS.Model} the record that was updated. + @deprecated Use [push](#method_push) instead */ update: function(type, data) { - return this.push(type, data, true); + Ember.deprecate('Using store.update() has been deprecated since store.push() now handles partial updates. You should use store.push() instead.'); + return this.push(type, data); }, /** diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index feb550aa11c..dd4b50beedf 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -99,7 +99,15 @@ test("Calling push triggers `didLoad` even if the record hasn't been requested f }); }); -test("Calling update with partial records updates just those attributes", function() { +test("Calling update should be deprecated", function() { + expectDeprecation(function() { + run(function() { + store.update('person', { id: '1', name: 'Tomster' }); + }); + }); +}); + +test("Calling push with partial records updates just those attributes", function() { var person; run(function(){ person = store.push('person', { @@ -124,7 +132,7 @@ test("Calling update with partial records updates just those attributes", functi }); }); -test("Calling update on normalize allows partial updates with raw JSON", function () { +test("Calling push on normalize allows partial updates with raw JSON", function () { env.container.register('serializer:person', DS.RESTSerializer); var person; @@ -135,7 +143,7 @@ test("Calling update on normalize allows partial updates with raw JSON", functio lastName: "Jackson" }); - store.update('person', store.normalize('person', { + store.push('person', store.normalize('person', { id: '1', firstName: "Jacquie" })); @@ -145,7 +153,7 @@ test("Calling update on normalize allows partial updates with raw JSON", functio equal(person.get('lastName'), "Jackson", "existing fields are untouched"); }); -test("Calling update with partial records triggers observers for just those attributes", function() { +test("Calling push with partial records triggers observers for just those attributes", function() { expect(1); var person; @@ -166,7 +174,7 @@ test("Calling update with partial records triggers observers for just those attr }); run(function(){ - store.update('person', { + store.push('person', { id: 'wat', lastName: "Katz!" }); @@ -385,6 +393,39 @@ test("Calling pushPayload without a type should use a model's serializer when no equal(person.get('firstName'), "Yehuda", "you can push raw JSON into the store"); }); +test("Calling pushPayload allows partial updates with raw JSON", function () { + env.container.register('serializer:person', DS.RESTSerializer); + + var person; + + run(function() { + store.pushPayload('person', { + people: [{ + id: '1', + firstName: "Robert", + lastName: "Jackson" + }] + }); + }); + + var person = store.getById('person', 1); + + equal(person.get('firstName'), "Robert", "you can push raw JSON into the store"); + equal(person.get('lastName'), "Jackson", "you can push raw JSON into the store"); + + run(function() { + store.pushPayload('person', { + people: [{ + id: '1', + firstName: "Jacquie" + }] + }); + }); + + equal(person.get('firstName'), "Jacquie", "you can push raw JSON into the store"); + equal(person.get('lastName'), "Jackson", "existing fields are untouched"); +}); + test('calling push without data argument as an object raises an error', function(){ var invalidValues = [ undefined, From 8dcbe2c680e9fb57f59ff87e4ec1cb7d48f34f11 Mon Sep 17 00:00:00 2001 From: IgorT Date: Tue, 2 Dec 2014 05:51:09 -0500 Subject: [PATCH 0490/2527] Fix the build by wrapping the test in run --- .../relationships/has_many_test.js | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 297bbf44039..9c95d9f1960 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -220,7 +220,7 @@ test("A hasMany backed by a link remains a promise after a record has been added }); }); -asyncTest("A hasMany updated link should not remove new children", function() { +test("A hasMany updated link should not remove new children", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -241,22 +241,23 @@ asyncTest("A hasMany updated link should not remove new children", function() { }); }; - var post = env.store.createRecord('post', {}); - env.store.createRecord('comment', {message: post}); - - post.get('comments') - .then(function(comments) { - equal(comments.get('length'), 1); - - return post.save(); - }) - .then(function() { - return post.get('comments'); - }) - .then(function(comments) { - equal(comments.get('length'), 1); - start(); - }); + run(function() { + var post = env.store.createRecord('post', {}); + env.store.createRecord('comment', {message: post}); + + post.get('comments') + .then(function(comments) { + equal(comments.get('length'), 1); + + return post.save(); + }) + .then(function() { + return post.get('comments'); + }) + .then(function(comments) { + equal(comments.get('length'), 1); + }); + }); }); test("A hasMany relationship can be reloaded if it was fetched via a link", function() { From 7a608d467eb0bd6135164ceb84692f6d7d0c5bc7 Mon Sep 17 00:00:00 2001 From: IgorT Date: Thu, 27 Nov 2014 22:43:35 -0500 Subject: [PATCH 0491/2527] Cache relationships meta in production --- .../lib/system/relationships/ext.js | 135 ++++++++++-------- .../relationships/belongs_to_test.js | 53 ++++++- 2 files changed, 129 insertions(+), 59 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 7aedd73a4b6..997189395c6 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -11,6 +11,80 @@ import { var get = Ember.get; var filter = Ember.ArrayPolyfills.filter; +var relationshipsDescriptor = Ember.computed(function() { + if (Ember.testing === true && relationshipsDescriptor._cacheable === true) { + relationshipsDescriptor._cacheable = false; + } + + var map = new MapWithDefault({ + defaultValue: function() { return []; } + }); + + // Loop through each computed property on the class + this.eachComputedProperty(function(name, meta) { + // If the computed property is a relationship, add + // it to the map. + if (meta.isRelationship) { + meta.key = name; + var relationshipsForType = map.get(typeForRelationshipMeta(this.store, meta)); + + relationshipsForType.push({ + name: name, + kind: meta.kind + }); + } + }); + + return map; +}).readOnly(); + +var relatedTypesDescriptor = Ember.computed(function() { + if (Ember.testing === true && relatedTypesDescriptor._cacheable === true) { + relatedTypesDescriptor._cacheable = false; + } + + var type; + var types = Ember.A(); + + // Loop through each computed property on the class, + // and create an array of the unique types involved + // in relationships + this.eachComputedProperty(function(name, meta) { + if (meta.isRelationship) { + meta.key = name; + type = typeForRelationshipMeta(this.store, meta); + + Ember.assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", type); + + if (!types.contains(type)) { + Ember.assert("Trying to sideload " + name + " on " + this.toString() + " but the type doesn't exist.", !!type); + types.push(type); + } + } + }); + + return types; +}).readOnly(); + +var relationshipsByNameDescriptor = Ember.computed(function() { + if (Ember.testing === true && relationshipsByNameDescriptor._cacheable === true) { + relationshipsByNameDescriptor._cacheable = false; + } + + var map = Map.create(); + + this.eachComputedProperty(function(name, meta) { + if (meta.isRelationship) { + meta.key = name; + var relationship = relationshipFromMeta(this.store, meta); + relationship.type = typeForRelationshipMeta(this.store, meta); + map.set(name, relationship); + } + }); + + return map; +}).readOnly(); + /** @module ember-data */ @@ -266,28 +340,8 @@ Model.reopenClass({ @type Ember.Map @readOnly */ - relationships: Ember.computed(function() { - var map = new MapWithDefault({ - defaultValue: function() { return []; } - }); - // Loop through each computed property on the class - this.eachComputedProperty(function(name, meta) { - // If the computed property is a relationship, add - // it to the map. - if (meta.isRelationship) { - meta.key = name; - var relationshipsForType = map.get(typeForRelationshipMeta(this.store, meta)); - - relationshipsForType.push({ - name: name, - kind: meta.kind - }); - } - }); - - return map; - }).cacheable(false).readOnly(), + relationships: relationshipsDescriptor, /** A hash containing lists of the model's relationships, grouped @@ -361,29 +415,7 @@ Model.reopenClass({ @type Ember.Array @readOnly */ - relatedTypes: Ember.computed(function() { - var type; - var types = Ember.A(); - - // Loop through each computed property on the class, - // and create an array of the unique types involved - // in relationships - this.eachComputedProperty(function(name, meta) { - if (meta.isRelationship) { - meta.key = name; - type = typeForRelationshipMeta(this.store, meta); - - Ember.assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", type); - - if (!types.contains(type)) { - Ember.assert("Trying to sideload " + name + " on " + this.toString() + " but the type doesn't exist.", !!type); - types.push(type); - } - } - }); - - return types; - }).cacheable(false).readOnly(), + relatedTypes: relatedTypesDescriptor, /** A map whose keys are the relationships of a model and whose values are @@ -416,20 +448,7 @@ Model.reopenClass({ @type Ember.Map @readOnly */ - relationshipsByName: Ember.computed(function() { - var map = Map.create(); - - this.eachComputedProperty(function(name, meta) { - if (meta.isRelationship) { - meta.key = name; - var relationship = relationshipFromMeta(this.store, meta); - relationship.type = typeForRelationshipMeta(this.store, meta); - map.set(name, relationship); - } - }); - - return map; - }).cacheable(false).readOnly(), + relationshipsByName: relationshipsByNameDescriptor, /** A map whose keys are the fields of the model and whose values are strings diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index 657a6c9cdc9..12b10cba588 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -357,7 +357,58 @@ test("relationshipsByName does not cache a factory", function() { "model factory based on relationship type matches the model based on store.modelFor" ); }); -test("asdf", function() { +test("relationshipsByName is cached in production", function() { + var model = store.modelFor('user'); + var oldTesting = Ember.testing; + //We set the cacheable to true because that is the default state for any CP and then assert that it + //did not get dynamically changed when accessed + var oldCacheable = Ember.meta(model).descs.relationshipsByName._cacheable; + Ember.meta(model).descs.relationshipsByName._cacheable = true; + Ember.testing = false; + try { + equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached'); + equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached'); + } finally { + Ember.testing = oldTesting; + Ember.meta(model).descs.relationshipsByName._cacheable = oldCacheable; + } +}); + +test("relatedTypes is cached in production", function() { + var model = store.modelFor('user'); + var oldTesting = Ember.testing; + //We set the cacheable to true because that is the default state for any CP and then assert that it + //did not get dynamically changed when accessed + var oldCacheable = Ember.meta(model).descs.relatedTypes._cacheable; + Ember.meta(model).descs.relatedTypes._cacheable = true; + Ember.testing = false; + try { + equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached'); + equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached'); + } finally { + Ember.testing = oldTesting; + Ember.meta(model).descs.relatedTypes._cacheable = oldCacheable; + } +}); + +test("relationships is cached in production", function() { + var model = store.modelFor('user'); + var oldTesting = Ember.testing; + //We set the cacheable to true because that is the default state for any CP and then assert that it + //did not get dynamically changed when accessed + var oldCacheable = Ember.meta(model).descs.relatedTypes._cacheable; + Ember.meta(model).descs.relationships._cacheable = true; + Ember.testing = false; + try { + equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached'); + equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached'); + } finally { + Ember.testing = oldTesting; + Ember.meta(model).descs.relationships._cacheable = oldCacheable; + } +}); + +test("relationship changes shouldn’t cause async fetches", function() { expect(2); /* Scenario: From ef97c2dbab688fd40e603f2169d06f4038c6bdb6 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Fri, 5 Dec 2014 21:44:47 +0100 Subject: [PATCH 0492/2527] Include ember-data.js.map in S3 upload --- config/s3ProjectConfig.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/config/s3ProjectConfig.js b/config/s3ProjectConfig.js index 652ca09a1af..d655518a7a4 100644 --- a/config/s3ProjectConfig.js +++ b/config/s3ProjectConfig.js @@ -1,30 +1,30 @@ module.exports = function(revision, tag, date){ return { - 'ember-data.js': fileObject('ember-data', '.js', 'text/javascript', revision, tag, date), - 'ember-data.min.js': fileObject('ember-data.min', '.js', 'text/javascript', revision, tag, date), - 'ember-data.prod.js': fileObject('ember-data.prod', '.js', 'text/javascript', revision, tag, date) + 'ember-data.js': fileObject('ember-data.js', 'text/javascript', revision, tag, date), + 'ember-data.js.map': fileObject('ember-data.js.map', 'application/json', revision, tag, date), + 'ember-data.min.js': fileObject('ember-data.min.js', 'text/javascript', revision, tag, date), + 'ember-data.prod.js': fileObject('ember-data.prod.js', 'text/javascript', revision, tag, date) } } -function fileObject(baseName, extension, contentType, currentRevision, tag, date) { - var fullName = "/" + baseName + extension; +function fileObject(fileName, contentType, currentRevision, tag, date) { return { contentType: contentType, destinations: { canary: [ - 'canary' + fullName, - 'canary/daily/' + date + fullName, - 'canary/shas/' + currentRevision + fullName + 'canary' + fileName, + 'canary/daily/' + date + fileName, + 'canary/shas/' + currentRevision + fileName ], stable: [ - 'stable' + fullName, - 'stable/daily/' + date + fullName, - 'stable/shas/' + currentRevision + fullName + 'stable' + fileName, + 'stable/daily/' + date + fileName, + 'stable/shas/' + currentRevision + fileName ], beta: [ - 'beta' + fullName, - 'beta/daily/' + date + fullName, - 'beta/shas/' + currentRevision + fullName + 'beta' + fileName, + 'beta/daily/' + date + fileName, + 'beta/shas/' + currentRevision + fileName ] } } From 383166f0f67d88d8c37b5b44d043a903bc3f7b73 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 8 Dec 2014 13:43:32 -0500 Subject: [PATCH 0493/2527] [Feature thrownError] tag errorThrown from jQuery onto the jqXHR like ic-ajax does. fixes https://github.com/emberjs/ember.js/issues/9644 --- .../lib/system/active_model_adapter.js | 2 +- .../ember-data/lib/adapters/rest_adapter.js | 13 +++++-- .../integration/adapter/rest_adapter_test.js | 37 ++++++++++++++++++- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index 0046c5d197b..c212abf5c94 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -138,7 +138,7 @@ var ActiveModelAdapter = RESTAdapter.extend({ @return error */ ajaxError: function(jqXHR) { - var error = this._super(jqXHR); + var error = this._super.apply(this, arguments); if (jqXHR && jqXHR.status === 422) { return new InvalidError(Ember.$.parseJSON(jqXHR.responseText)); diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 9e1f8ea01c0..d3acd2b48b8 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -743,9 +743,14 @@ export default Adapter.extend({ @param {Object} responseText @return {Object} jqXHR */ - ajaxError: function(jqXHR, responseText) { - if (jqXHR && typeof jqXHR === 'object') { + ajaxError: function(jqXHR, responseText, errorThrown) { + var isObject = jqXHR !== null && typeof jqXHR === 'object'; + + if (isObject) { jqXHR.then = null; + if (!jqXHR.errorThrown) { + jqXHR.errorThrown = errorThrown; + } } return jqXHR; @@ -817,11 +822,11 @@ export default Adapter.extend({ }; hash.error = function(jqXHR, textStatus, errorThrown) { - Ember.run(null, reject, adapter.ajaxError(jqXHR, jqXHR.responseText)); + Ember.run(null, reject, adapter.ajaxError(jqXHR, jqXHR.responseText, errorThrown)); }; Ember.$.ajax(hash); - }, "DS: RESTAdapter#ajax " + type + " to " + url); + }, 'DS: RESTAdapter#ajax ' + type + ' to ' + url); }, /** diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 6988ff07536..b5c8c1d6355 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -1719,4 +1719,39 @@ test("rejects promise if DS.InvalidError is returned from adapter.ajaxSuccess", }); Ember.$.ajax = originalAjax; -}); \ No newline at end of file +}); + +test('ajaxError appends errorThrown for sanity', function() { + expect(6); + + var originalAjax = Ember.$.ajax; + var jqXHR = { + responseText: 'Nope lol' + }; + + var errorThrown = new Error('nope!'); + + Ember.$.ajax = function(hash) { + hash.error(jqXHR, jqXHR.responseText, errorThrown); + }; + + var originalAjaxError = adapter.ajaxError; + adapter.ajaxError = function(xhr, responseText, _errorThrown) { + deepEqual(_errorThrown, errorThrown); + ok(errorThrown); + deepEqual(xhr, jqXHR); + deepEqual(responseText, jqXHR.responseText); + return originalAjaxError.apply(adapter, arguments); + }; + + try { + run(function(){ + store.find('post', '1').catch(function(err){ + equal(err.errorThrown, errorThrown); + ok(err, 'promise rejected'); + }); + }); + } finally { + Ember.$.ajax = originalAjax; + } +}); From d3e8cbfd055d1d2a27ac09833b9b0a6f4aeb15d3 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 9 Dec 2014 12:42:48 -0500 Subject: [PATCH 0494/2527] [Bugfix] promiseHasMany.reload() should return another promiseHasMany --- .../lib/adapters/fixture_adapter.js | 1 - packages/ember-data/lib/main.js | 5 +++- .../ember-data/lib/system/promise_proxies.js | 4 ++- packages/ember-data/lib/system/store.js | 1 - .../tests/unit/promise_proxies_test.js | 25 +++++++++++++++++++ 5 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 packages/ember-data/tests/unit/promise_proxies_test.js diff --git a/packages/ember-data/lib/adapters/fixture_adapter.js b/packages/ember-data/lib/adapters/fixture_adapter.js index 4f44a4ac3a0..7e6b4f98c3c 100644 --- a/packages/ember-data/lib/adapters/fixture_adapter.js +++ b/packages/ember-data/lib/adapters/fixture_adapter.js @@ -1,7 +1,6 @@ /** @module ember-data */ - var get = Ember.get; var fmt = Ember.String.fmt; var indexOf = Ember.EnumerableUtils.indexOf; diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index 99476999a5e..2c99dc9466b 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -15,7 +15,8 @@ import "ember-inflector/main"; import { PromiseArray, - PromiseObject + PromiseObject, + PromiseManyArray } from "ember-data/system/promise_proxies"; import { Store @@ -70,6 +71,8 @@ DS.Store = Store; DS.PromiseArray = PromiseArray; DS.PromiseObject = PromiseObject; +DS.PromiseManyArray = PromiseManyArray; + DS.Model = Model; DS.RootState = RootState; DS.attr = attr; diff --git a/packages/ember-data/lib/system/promise_proxies.js b/packages/ember-data/lib/system/promise_proxies.js index ff9b8cde9b5..3015156b438 100644 --- a/packages/ember-data/lib/system/promise_proxies.js +++ b/packages/ember-data/lib/system/promise_proxies.js @@ -99,7 +99,9 @@ var PromiseManyArray = PromiseArray.extend({ reload: function() { //I don't think this should ever happen right now, but worth guarding if we refactor the async relationships Ember.assert('You are trying to reload an async manyArray before it has been created', get(this, 'content')); - return get(this, 'content').reload(); + return PromiseManyArray.create({ + promise: get(this, 'content').reload() + }); }, createRecord: proxyToContent('createRecord'), diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 06b72570650..3419597e8c2 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1000,7 +1000,6 @@ Store = Ember.Object.extend({ promise = promise || Promise.cast(array); - return promiseArray(promise.then(function() { return array; }, null, "DS: Store#filter of " + type)); diff --git a/packages/ember-data/tests/unit/promise_proxies_test.js b/packages/ember-data/tests/unit/promise_proxies_test.js new file mode 100644 index 00000000000..4c4f064e5a3 --- /dev/null +++ b/packages/ember-data/tests/unit/promise_proxies_test.js @@ -0,0 +1,25 @@ +module('PromiseManyArray'); + +test('.reload should NOT leak the internal promise, rather return another promiseArray', function() { + expect(2); + + var content = Ember.A(); + + content.reload = function() { + return Ember.RSVP.Promise.resolve(content); + }; + + var array = DS.PromiseManyArray.create({ + content: content + }); + + Ember.run(function() { + var reloaded = array.reload(); + + ok(reloaded instanceof DS.PromiseManyArray); + + reloaded.then(function(value) { + equal(content, value); + }); + }); +}); From 48d1fa28f5b6b7046ce01c9259f7eaf6bd369990 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Tue, 2 Dec 2014 21:51:21 +0100 Subject: [PATCH 0495/2527] Remove metaForType()/metadataFor() ambiguousness - Deprecated store.metaForType() - Added store.setMetadataFor() to set metadata for a specific type - Added tests --- .../lib/serializers/json_serializer.js | 4 +- packages/ember-data/lib/system/store.js | 30 +++++++++----- .../integration/adapter/rest_adapter_test.js | 2 +- .../tests/unit/store/metadata_for_test.js | 41 +++++++++++++++++++ 4 files changed, 64 insertions(+), 13 deletions(-) create mode 100644 packages/ember-data/tests/unit/store/metadata_for_test.js diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index ab479634332..01db48a67f9 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -961,7 +961,7 @@ export default Ember.Object.extend({ App.PostSerializer = DS.JSONSerializer.extend({ extractMeta: function(store, type, payload) { if (payload && payload._pagination) { - store.metaForType(type, payload._pagination); + store.setMetadataFor(type, payload._pagination); delete payload._pagination; } } @@ -975,7 +975,7 @@ export default Ember.Object.extend({ */ extractMeta: function(store, type, payload) { if (payload && payload.meta) { - store.metaForType(type, payload.meta); + store.setMetadataFor(type, payload.meta); delete payload.meta; } }, diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 3419597e8c2..c49811b55b7 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1033,14 +1033,27 @@ Store = Ember.Object.extend({ This method returns the metadata for a specific type. @method metadataFor - @param {String or subclass of DS.Model} type + @param {String or subclass of DS.Model} typeName @return {object} */ - metadataFor: function(type) { - type = this.modelFor(type); + metadataFor: function(typeName) { + var type = this.modelFor(typeName); return this.typeMapFor(type).metadata; }, + /** + This method sets the metadata for a specific type. + + @method setMetadataFor + @param {String or subclass of DS.Model} typeName + @param {Object} metadata metadata to set + @return {object} + */ + setMetadataFor: function(typeName, metadata) { + var type = this.modelFor(typeName); + Ember.merge(this.typeMapFor(type).metadata, metadata); + }, + // ............ // . UPDATING . // ............ @@ -1521,17 +1534,14 @@ Store = Ember.Object.extend({ }, /** - If you have some metadata to set for a type - you can call `metaForType`. - @method metaForType - @param {String or subclass of DS.Model} type + @param {String or subclass of DS.Model} typeName @param {Object} metadata + @deprecated Use [setMetadataFor](#method_setMetadataFor) instead */ metaForType: function(typeName, metadata) { - var type = this.modelFor(typeName); - - Ember.merge(this.typeMapFor(type).metadata, metadata); + Ember.deprecate('Using store.metaForType() has been deprecated. Use store.setMetadataFor() to set metadata for a specific type.'); + this.setMetadataFor(typeName, metadata); }, /** diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index b5c8c1d6355..ccfb5492e21 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -769,7 +769,7 @@ test("findAll - since token is passed to the adapter", function() { ] }); - store.metaForType('post', { since: 'now' }); + store.setMetadataFor('post', { since: 'now' }); store.findAll('post').then(async(function(posts) { equal(passedUrl, '/posts'); diff --git a/packages/ember-data/tests/unit/store/metadata_for_test.js b/packages/ember-data/tests/unit/store/metadata_for_test.js new file mode 100644 index 00000000000..0e84e365af3 --- /dev/null +++ b/packages/ember-data/tests/unit/store/metadata_for_test.js @@ -0,0 +1,41 @@ +var store; + +var run = Ember.run; + +module("unit/store/metadata_for - DS.Store#metadataFor", { + setup: function() { + store = createStore({ + post: DS.Model.extend(), + comment: DS.Model.extend() + }); + }, + + teardown: function() { + run(function(){ + store.destroy(); + }); + } +}); + +test("metaForType should be deprecated", function() { + expect(1); + + expectDeprecation(function() { + store.metaForType('post', { foo: 'bar' }); + }); +}); + +test("metadataFor and setMetadataFor should return and set correct metadata", function() { + expect(4); + + deepEqual(store.metadataFor('post'), {}, 'metadata for post is initially empty'); + + store.setMetadataFor('post', { foo: 'bar' }); + + deepEqual(store.metadataFor('post'), { foo: 'bar' }, 'metadata for post contains foo:bar'); + + store.setMetadataFor('post', { hello: 'world' }); + + deepEqual(store.metadataFor('post'), { foo: 'bar', hello: 'world' }, 'metadata for post contains both foo:bar and hello:world'); + deepEqual(store.metadataFor('comment'), {}, 'metadata for comment is empty'); +}); \ No newline at end of file From 2f964cab9627fa5a0d8a85a4f7396d81bac82666 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 11 Dec 2014 18:01:16 -0600 Subject: [PATCH 0496/2527] fix build step on CI --- bower.json | 4 ++-- config/testem-beta.json | 2 +- config/testem-canary.json | 2 +- config/testem-stable.json | 2 +- testem.json | 2 +- tests/index.html | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bower.json b/bower.json index 38c1afaf448..1d549892667 100644 --- a/bower.json +++ b/bower.json @@ -2,12 +2,12 @@ "name": "ember-data", "private": true, "dependencies": { - "ember": "~1.8.1" + "ember": "~1.9.0" }, "devDependencies": { "qunit": "~1.13.0", "jquery": "~1.10.x", - "handlebars": "~1.3.0", + "handlebars": "~2.0.0", "loader.js": "~1.0.0", "ember-inflector": "https://github.com/stefanpenner/ember-inflector.git#v1.2.0", "es5-shim": "~4.0.3" diff --git a/config/testem-beta.json b/config/testem-beta.json index 86d96f4801c..b0f802263f9 100644 --- a/config/testem-beta.json +++ b/config/testem-beta.json @@ -1,5 +1,5 @@ { - "test_page": "tests/index.html?emberchannel=beta&nojshint=true", + "test_page": "dist/index.html?emberchannel=beta&nojshint=true", "serve_files": [ "dist/**/*.js", "tests/**/*" diff --git a/config/testem-canary.json b/config/testem-canary.json index d9e6f97065f..94d7ac430ad 100644 --- a/config/testem-canary.json +++ b/config/testem-canary.json @@ -1,5 +1,5 @@ { - "test_page": "tests/index.html?emberchannel=canary&nojshint=true", + "test_page": "dist/index.html?emberchannel=canary&nojshint=true", "serve_files": [ "dist/**/*.js", "tests/**/*" diff --git a/config/testem-stable.json b/config/testem-stable.json index 9b491b8f2bc..a1460127be0 100644 --- a/config/testem-stable.json +++ b/config/testem-stable.json @@ -1,5 +1,5 @@ { - "test_page": "tests/index.html?emberchannel=stable&nojshint=true", + "test_page": "dist/index.html?emberchannel=stable&nojshint=true", "serve_files": [ "dist/**/*.js", "tests/**/*" diff --git a/testem.json b/testem.json index 0bc083fa12a..298efe31ceb 100644 --- a/testem.json +++ b/testem.json @@ -1,5 +1,5 @@ { - "test_page": "tests/index.html", + "test_page": "dist/index.html", "serve_files": [ "dist/**/*.js", "tests/**/*" diff --git a/tests/index.html b/tests/index.html index de75a8f103e..4fbc867f7e0 100644 --- a/tests/index.html +++ b/tests/index.html @@ -5,7 +5,6 @@ Ember Data - @@ -66,5 +65,6 @@
      + From 3b2a6917967434029d3bd1c1dbc0afb193de2859 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 11 Dec 2014 18:05:11 -0600 Subject: [PATCH 0497/2527] remove broccoli directly since ember-cli includes its own --- package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/package.json b/package.json index 50a6c9ed36c..ed214abadac 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,6 @@ "devDependencies": { "aws-sdk": "~2.0.0-rc8", "bower": "~1.3", - "broccoli": "^0.12.3", - "broccoli-cli": "0.0.1", "broccoli-compile-modules": "^1.1.0", "broccoli-concat": "0.0.12", "broccoli-defeatureify": "^0.3.0", From 5e99df4c34f09b810dd6756c2cb957f70c3a6122 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 11 Dec 2014 19:21:44 -0600 Subject: [PATCH 0498/2527] use nodejitsu while npm is down --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 0b39a33d1f1..e8c35b28c70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ install: - "bower install" - "npm run-script dist" script: + - npm config set registry http://registry.nodejitsu.com - npm run-script testem-stable - npm run-script testem-beta - npm run-script testem-canary From 8fd65d41362cdfb0d6549f2414fc52943d909701 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 11 Dec 2014 19:23:51 -0600 Subject: [PATCH 0499/2527] fix build order in travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e8c35b28c70..e5165b92007 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,11 +3,11 @@ language: node_js node_js: - "0.10" install: +- npm config set registry http://registry.nodejitsu.com - "npm install" - "bower install" - "npm run-script dist" script: - - npm config set registry http://registry.nodejitsu.com - npm run-script testem-stable - npm run-script testem-beta - npm run-script testem-canary From 8450896a872f29fd047a903d68874c9047f593e0 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 11 Dec 2014 19:36:29 -0600 Subject: [PATCH 0500/2527] use bower version of 1.9.0 until builds.emberjs.com gets back up to date --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e5165b92007..3e20001b1a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ install: - "bower install" - "npm run-script dist" script: - - npm run-script testem-stable + - npm run-script test - npm run-script testem-beta - npm run-script testem-canary after_success: From a82ce93d29810c0af8b8194b3c49bdf5b339ca44 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 11 Dec 2014 18:32:03 -0600 Subject: [PATCH 0501/2527] failing test for unloading a record before store.destroy --- .../relationships/has_many_test.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 9c95d9f1960..56e2fcb1d24 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -1019,3 +1019,37 @@ test("Passing a model as type to hasMany should not work", function () { }); }, /The first argument to DS.hasMany must be a string/); }); + +test('unloading a record with associated records does not prevent the store from tearing down', function(){ + var post; + + run(function(){ + post = env.store.push('post', { id: 2, title: 'Sailing the Seven Seas', comments: [1,2] }); + env.store.pushMany('comment', [ + { + id: 1, + post: 2 + }, + { + id: 2, + post: 2 + } + ]); + + // This line triggers the original bug that gets manifested + // in teardown for apps, e.g. store.destroy that is caused by + // App.destroy(). + // Relationship#clear uses Ember.Set#forEach, which does incorrect + // iteration when the set is being mutated (in our case, the index gets off + // because records are being removed) + env.store.unloadRecord(post); + }); + try { + run(function(){ + env.store.destroy(); + }); + ok(true, "store destroyed correctly"); + } catch (error) { + ok(false, "store prevented from being destroyed"); + } +}); From 0d946af646c5fa477aebc9325874d70e84acd22a Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 11 Dec 2014 19:08:45 -0600 Subject: [PATCH 0502/2527] fix Relationship.proto.clear bug --- .../lib/system/relationships/relationship.js | 8 +++-- .../relationships/has_many_test.js | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index 204c3e0a61d..b1dc87162f0 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -29,9 +29,13 @@ Relationship.prototype = { destroy: Ember.K, clear: function() { - this.members.forEach(function(member) { + var members = this.members.list; + var member; + + while (members.length > 0){ + member = members[0]; this.removeRecord(member); - }, this); + } }, disconnect: function(){ diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 56e2fcb1d24..081c5970176 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -1020,6 +1020,36 @@ test("Passing a model as type to hasMany should not work", function () { }, /The first argument to DS.hasMany must be a string/); }); +test("Relationship.clear removes all records correctly", function(){ + var post; + + run(function(){ + post = env.store.push('post', { id: 2, title: 'Sailing the Seven Seas', comments: [1,2] }); + env.store.pushMany('comment', [ + { + id: 1, + post: 2 + }, + { + id: 2, + post: 2 + }, + { + id: 3, + post: 2 + } + ]); + }); + + run(function(){ + post._relationships['comments'].clear(); + var comments = Em.A(env.store.all('comment')); + deepEqual(comments.mapBy('post'), [undefined, undefined, undefined]); + }); + +}); + + test('unloading a record with associated records does not prevent the store from tearing down', function(){ var post; From 4a4d8f073e21b78b600ca37e00ce0dfd69af9a85 Mon Sep 17 00:00:00 2001 From: Kevin Burke Date: Thu, 11 Dec 2014 22:44:14 -0800 Subject: [PATCH 0503/2527] Typo --- packages/ember-data/lib/adapters/rest_adapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index d3acd2b48b8..a6df6162e06 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -209,7 +209,7 @@ export default Adapter.extend({ will also send a request to: `GET /comments?ids[]=1&ids[]=2` Note: Requests coalescing rely on URL building strategy. So if you override `buildUrl` in your app - `groupRecordsForFindMany` more likely should be overriden as well in order for coalescing to work. + `groupRecordsForFindMany` more likely should be overridden as well in order for coalescing to work. @property coalesceFindRequests @type {boolean} From 921232735484080e19062bc6158c3e3b92ada946 Mon Sep 17 00:00:00 2001 From: Steven Lindberg Date: Thu, 11 Dec 2014 15:26:11 -0800 Subject: [PATCH 0504/2527] Removed unused notify on 'data' property --- packages/ember-data/lib/system/model/states.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index a07cb32211a..c3615644f3f 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -473,7 +473,6 @@ var RootState = { loadedData: function(record) { record.transitionTo('loaded.created.uncommitted'); - record.notifyPropertyChange('data'); }, pushedData: function(record) { From 45a9225769e2a0d11256429404ad611f3290db98 Mon Sep 17 00:00:00 2001 From: Philip Dudley Date: Wed, 10 Dec 2014 22:41:37 -0500 Subject: [PATCH 0505/2527] Warn when pushing in a relationship as a link and its not an async relationship --- .../lib/system/relationships/relationship.js | 1 + .../ember-data/tests/unit/store/push_test.js | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js index b1dc87162f0..273e863f671 100644 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ b/packages/ember-data/lib/system/relationships/relationship.js @@ -117,6 +117,7 @@ Relationship.prototype = { }, updateLink: function(link) { + Ember.warn("You have pushed a record of type '" + this.record.constructor.typeKey + "' with '" + this.key + "' as a link, but the association is not an aysnc relationship.", this.isAsync); Ember.assert("You have pushed a record of type '" + this.record.constructor.typeKey + "' with '" + this.key + "' as a link, but the value of that link is not a string.", typeof link === 'string' || link === null); if (link !== this.link) { this.link = link; diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index dd4b50beedf..efa7fc5432d 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -448,6 +448,23 @@ test('calling push without data argument as an object raises an error', function }); }); +test('Calling push with a link for a non async relationship should warn', function() { + Person.reopen({ + phoneNumbers: hasMany('phone-number', { async: false }) + }); + + warns(function() { + run(function(){ + store.push('person', { + id: '1', + links: { + phoneNumbers: '/api/people/1/phone-numbers' + } + }); + }); + }, /You have pushed a record of type 'person' with 'phoneNumbers' as a link, but the association is not an aysnc relationship./); +}); + test('Calling push with a link containing an object throws an assertion error', function() { expectAssertion(function() { run(function(){ From 4bd713fc0b83bec69945042f34b40c9c11d6ccdb Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Fri, 12 Dec 2014 23:13:22 +0100 Subject: [PATCH 0506/2527] fix s3 config --- config/s3ProjectConfig.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/config/s3ProjectConfig.js b/config/s3ProjectConfig.js index d655518a7a4..2f0d9a167cf 100644 --- a/config/s3ProjectConfig.js +++ b/config/s3ProjectConfig.js @@ -8,23 +8,24 @@ module.exports = function(revision, tag, date){ } function fileObject(fileName, contentType, currentRevision, tag, date) { + var filePath = '/' + fileName; return { contentType: contentType, destinations: { canary: [ - 'canary' + fileName, - 'canary/daily/' + date + fileName, - 'canary/shas/' + currentRevision + fileName + 'canary' + filePath, + 'canary/daily/' + date + filePath, + 'canary/shas/' + currentRevision + filePath ], stable: [ - 'stable' + fileName, - 'stable/daily/' + date + fileName, - 'stable/shas/' + currentRevision + fileName + 'stable' + filePath, + 'stable/daily/' + date + filePath, + 'stable/shas/' + currentRevision + filePath ], beta: [ - 'beta' + fileName, - 'beta/daily/' + date + fileName, - 'beta/shas/' + currentRevision + fileName + 'beta' + filePath, + 'beta/daily/' + date + filePath, + 'beta/shas/' + currentRevision + filePath ] } } From 0998a43ce8a13747decd9abae2be3c0d59d2789d Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Fri, 12 Dec 2014 14:59:03 -0800 Subject: [PATCH 0507/2527] Remove dead tests. --- .../relationships/belongs_to_test.js | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index 12b10cba588..a2510eb5f26 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -292,35 +292,6 @@ test("A record with an async belongsTo relationship returning null should resolv })); }); -test("TODO (embedded): The store can load an embedded polymorphic belongsTo association", function() { - expect(0); - //serializer.keyForEmbeddedType = function() { - //return 'embeddedType'; - //}; - - //adapter.load(store, App.User, { id: 2, favourite_message: { id: 1, embeddedType: 'comment'}}); - - //var user = store.find(App.User, 2), - //message = store.find(App.Comment, 1); - - //equal(user.get('favouriteMessage'), message); -}); - -test("TODO (embedded): The store can serialize an embedded polymorphic belongsTo association", function() { - expect(0); - //serializer.keyForEmbeddedType = function() { - //return 'embeddedType'; - //}; - //adapter.load(store, App.User, { id: 2, favourite_message: { id: 1, embeddedType: 'comment'}}); - - //var user = store.find(App.User, 2), - //serialized = store.serialize(user, {includeId: true}); - - //ok(serialized.hasOwnProperty('favourite_message')); - //equal(serialized.favourite_message.id, 1); - //equal(serialized.favourite_message.embeddedType, 'comment'); -}); - test("relationshipsByName does not cache a factory", function() { // The model is loaded up via a container. It has relationshipsByName From 501015170306a666ee3c76df5c8eefed66880905 Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Sat, 13 Dec 2014 17:14:33 +0100 Subject: [PATCH 0508/2527] Document and explicitely test specifying relationships type is optional --- .../lib/system/relationships/belongs_to.js | 15 ++++++-- .../lib/system/relationships/has_many.js | 15 ++++++-- .../tests/unit/model/relationships_test.js | 36 ++++++------------- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index e228a2e56c6..646c0b59598 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -41,11 +41,22 @@ import { Model } from 'ember-data/system/model'; }); ``` + You can avoid passing a string as the first parameter. In that case Ember Data + will infer the type from the key name. + + ```javascript + App.Comment = DS.Model.extend({ + post: DS.belongsTo() + }); + ``` + + will lookup for a Post type. + @namespace @method belongsTo @for DS - @param {String} type the model type of the relationship - @param {Object} options a hash of options + @param {String} type (optional) type of the relationship + @param {Object} options (optional) a hash of options @return {Ember.computed} relationship */ function belongsTo(type, options) { diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index 8fa2bd161ca..39973ff102a 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -42,6 +42,17 @@ import { Model } from "ember-data/system/model"; }); ``` + You can avoid passing a string as the first parameter. In that case Ember Data + will infer the type from the singularized key name. + + ```javascript + App.Post = DS.Model.extend({ + tags: DS.hasMany() + }); + ``` + + will lookup for a Tag type. + #### Explicit Inverses Ember Data will do its best to discover which relationships map to @@ -78,8 +89,8 @@ import { Model } from "ember-data/system/model"; @namespace @method hasMany @for DS - @param {String} type the model type of the relationship - @param {Object} options a hash of options + @param {String} type (optional) type of the relationship + @param {Object} options (optional) a hash of options @return {Ember.computed} relationship */ function hasMany(type, options) { diff --git a/packages/ember-data/tests/unit/model/relationships_test.js b/packages/ember-data/tests/unit/model/relationships_test.js index d2c07f78c94..910dfd0c69d 100644 --- a/packages/ember-data/tests/unit/model/relationships_test.js +++ b/packages/ember-data/tests/unit/model/relationships_test.js @@ -194,37 +194,25 @@ test("hasMany lazily loads async relationships", function() { }); }); -test("should be able to retrieve the type for a hasMany relationship from its metadata", function() { - var Tag = DS.Model.extend({ - name: DS.attr('string') - }); +test("should be able to retrieve the type for a hasMany relationship without specifying a type from its metadata", function() { + var Tag = DS.Model.extend({}); var Person = DS.Model.extend({ - name: DS.attr('string'), - tags: DS.hasMany('tag') + tags: DS.hasMany() }); - var store = createStore({ + var env = setupStore({ tag: Tag, person: Person }); - var tag, person; - - run(function() { - tag = store.createRecord('tag'); - person = store.createRecord('person'); - }); - equal(Person.typeForRelationship('tags'), Tag, "returns the relationship type"); + equal(env.store.modelFor('person').typeForRelationship('tags'), Tag, "returns the relationship type"); }); test("should be able to retrieve the type for a hasMany relationship specified using a string from its metadata", function() { - var Tag = DS.Model.extend({ - name: DS.attr('string') - }); + var Tag = DS.Model.extend({}); var Person = DS.Model.extend({ - name: DS.attr('string'), tags: DS.hasMany('tag') }); @@ -236,14 +224,11 @@ test("should be able to retrieve the type for a hasMany relationship specified u equal(env.store.modelFor('person').typeForRelationship('tags'), Tag, "returns the relationship type"); }); -test("should be able to retrieve the type for a belongsTo relationship from its metadata", function() { - var Tag = DS.Model.extend({ - name: DS.attr('string') - }); +test("should be able to retrieve the type for a belongsTo relationship without specifying a type from its metadata", function() { + var Tag = DS.Model.extend({}); var Person = DS.Model.extend({ - name: DS.attr('string'), - tags: DS.belongsTo('tag') + tag: DS.belongsTo() }); var env = setupStore({ @@ -251,7 +236,7 @@ test("should be able to retrieve the type for a belongsTo relationship from its person: Person }); - equal(env.store.modelFor('person').typeForRelationship('tags'), Tag, "returns the relationship type"); + equal(env.store.modelFor('person').typeForRelationship('tag'), Tag, "returns the relationship type"); }); test("should be able to retrieve the type for a belongsTo relationship specified using a string from its metadata", function() { @@ -260,7 +245,6 @@ test("should be able to retrieve the type for a belongsTo relationship specified }); var Person = DS.Model.extend({ - name: DS.attr('string'), tags: DS.belongsTo('tag') }); From 3c9cf71c56519f8e4b33b50b0cacd28661eba8af Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 11 Dec 2014 10:48:18 -0600 Subject: [PATCH 0509/2527] bring back AMD build for dev mode --- Brocfile.js | 21 +++++++++---- bower.json | 7 +++-- lib/amd-build.js | 55 +++++++++++++++++++++++++++++++++ package.json | 6 ++-- packages/ember-data/lib/main.js | 1 - 5 files changed, 78 insertions(+), 12 deletions(-) create mode 100644 lib/amd-build.js diff --git a/Brocfile.js b/Brocfile.js index af68d7c82fc..c4f02b70cf3 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -6,6 +6,7 @@ var concat = require('broccoli-concat'); var uglify = require('broccoli-uglify-js'); var es3SafeRecast = require('broccoli-es3-safe-recast'); var env = process.env.EMBER_ENV; +var amdBuild = require('./lib/amd-build'); var pickFiles = require('broccoli-static-compiler'); var merge = require('broccoli-merge-trees'); var moveFile = require('broccoli-file-mover'); @@ -91,12 +92,20 @@ var packages = merge([ package('activemodel-adapter') ]); -var globalBuild = es6(packages, { - inputFiles: ['ember-data'], - output: '/ember-data.js', - resolvers: [PackageResolver], - formatter: 'bundle' -}); +var globalBuild; + +// Bundle formatter for smaller payload +if (env === 'production') { + globalBuild = es6(packages, { + inputFiles: ['ember-data'], + output: '/ember-data.js', + resolvers: [PackageResolver], + formatter: 'bundle' + }); +} else { +// Use AMD for faster rebuilds in dev + globalBuild = amdBuild(packages); +} var testFiles = merge([ testTree('ember-data'), diff --git a/bower.json b/bower.json index 38c1afaf448..35214601c4f 100644 --- a/bower.json +++ b/bower.json @@ -2,14 +2,17 @@ "name": "ember-data", "private": true, "dependencies": { - "ember": "~1.8.1" + "ember": "~1.9.0" }, "devDependencies": { "qunit": "~1.13.0", "jquery": "~1.10.x", - "handlebars": "~1.3.0", + "handlebars": ">= 2.0.0 < 3.0.0", "loader.js": "~1.0.0", "ember-inflector": "https://github.com/stefanpenner/ember-inflector.git#v1.2.0", "es5-shim": "~4.0.3" + }, + "resolutions": { + "handlebars": ">= 2.0.0 < 3.0.0" } } diff --git a/lib/amd-build.js b/lib/amd-build.js new file mode 100644 index 00000000000..43fbc4e3f80 --- /dev/null +++ b/lib/amd-build.js @@ -0,0 +1,55 @@ +var pickFiles = require('broccoli-static-compiler'); +var concat = require('broccoli-concat'); +var es6 = require('broccoli-es6-module-transpiler'); +var merge = require('broccoli-merge-trees'); +var PackageResolver = require('es6-module-transpiler-package-resolver'); +var AMDFormatter = require('es6-module-transpiler-amd-formatter'); +var fileCreator = require('broccoli-file-creator'); +var merge = require('broccoli-merge-trees'); +var replace = require('broccoli-string-replace'); + +function amdES6Package(packages) { + var es6Build = es6(packages, { + inputFiles: ['ember-data'], + output: '/ember-data/', + resolvers: [PackageResolver], + formatter: new AMDFormatter(), + basePath: '/ember-data/', + sourceRoot: '/ember-data/' + }); + + var loaderJS = pickFiles('bower_components/loader.js', { + srcDir: '/', + files: ['loader.js'], + destDir: '/' + }); + + var bootFile = fileCreator('/boot.js', 'require("ember-data/lib/main");'); + + var amdBuild = merge([es6Build, loaderJS, bootFile]); + + amdBuild = concat(amdBuild, { + inputFiles: ['loader.js', 'ember-data/**/*.js', 'boot.js'], + outputFile: '/ember-data.js', + header: '(function(){', + footer: '})();' + }); + + amdBuild = merge([es6Build, amdBuild]); + + return replace(amdBuild, { + files: ['ember-data.js'], + patterns: [ + { + match: /\/lib/g, + replacement: '' + }, + { + match: /\/main/g, + replacement: '' + } + ] + }); +} + +module.exports = amdES6Package; diff --git a/package.json b/package.json index 50a6c9ed36c..2b1b97c0a0a 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,6 @@ "devDependencies": { "aws-sdk": "~2.0.0-rc8", "bower": "~1.3", - "broccoli": "^0.12.3", - "broccoli-cli": "0.0.1", "broccoli-compile-modules": "^1.1.0", "broccoli-concat": "0.0.12", "broccoli-defeatureify": "^0.3.0", @@ -36,6 +34,7 @@ "broccoli-es3-safe-recast": "0.0.8", "broccoli-es6-module-transpiler": "^0.5.0", "broccoli-es6-transpiler": "^0.1.0", + "broccoli-file-creator": "^0.1.0", "broccoli-file-mover": "~0.2.0", "broccoli-jshint": "^0.5.1", "broccoli-merge-trees": "^0.1.4", @@ -47,9 +46,10 @@ "broccoli-yuidoc": "^1.3.0", "defeatureify": "~0.1.4", "ejs": "^1.0.0", - "ember-cli": "^0.1.2", + "ember-cli": "^0.1.4", "ember-publisher": "0.0.6", "es6-module-transpiler": "^0.9.5", + "es6-module-transpiler-amd-formatter": "^0.2.4", "es6-module-transpiler-package-resolver": "^1.0.1", "git-repo-version": "0.0.2", "testem": "^0.6.19", diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index 2c99dc9466b..49a7a1c7367 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -11,7 +11,6 @@ Ember.RSVP.Promise.cast = Ember.RSVP.Promise.cast || Ember.RSVP.resolve; import "ember-data/system/create"; import DS from "ember-data/core"; import "ember-data/ext/date"; -import "ember-inflector/main"; import { PromiseArray, From 74cb6feb6bc56cb0e453500a05454e3d9d6b3b0b Mon Sep 17 00:00:00 2001 From: Miguel Camba Date: Sun, 14 Dec 2014 00:01:51 +0000 Subject: [PATCH 0510/2527] Clarify that `store.fetch` documentation. It was not clear that the returned promise when the record is already on the store will wait for the server to resolve. --- packages/ember-data/lib/system/store.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 0e2c15141c0..54d3a44b876 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -425,8 +425,10 @@ Store = Ember.Object.extend({ This method returns a fresh record for a given type and id combination. If a record is available for the given type/id combination, then - it will fetch this record from the store then reload it. If - there's no record corresponding in the store it will simply call + it will fetch this record from the store and call `reload()` on it. + That will fire a request to server and return a promise that will + resolve once the record has been reloaded. + If there's no record corresponding in the store it will simply call `store.find`. Example From 3a9db6ff514a3fbde8921a3d7cc24b73ae92450a Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Tue, 2 Dec 2014 16:49:28 +0100 Subject: [PATCH 0511/2527] Documented deprecation of store.update() and related breaking changes --- CHANGELOG.md | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f427e47540c..e86558eeb5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,84 @@ ### Master +#### Breaking Changes + +##### `store.update()` has been deprecated + +Calling `store.update()` has been deprecated in favor of `store.push()` now +handling partial payloads: + +```javascript +var post = store.push('post', { + id: 1, + title: 'Ember.js is fantastic', + author: 'Tomster' +}); + +post.get('title'); // => 'Ember.js is fantastic' +post.get('author'); // => 'Tomster' + +store.push('post', { id: 1, author: 'Tom Dale' }); + +post.get('title'); // => 'Ember.js is fantastic' +post.get('author'); // => 'Tom Dale' +``` + +This also mean that properties missing in the payload will no longer be reset, +but stay the same. + +If you need to reset values to null, you should have your server explicitly +send back null values in the payload: + +```javascript +{ + "person": { + "firstName": null, + "lastName": null + "role": "Computer Science Pioneer" + } +} +``` + +If you cannot change your API and you desire this behavior, you can create a +serializer and do the logic yourself: + +```javascript +// app/serializers/person.js +// or App.PersonSerializer if you aren't using Ember CLI +export default DS.RESTSerializer.extend({ + normalize: function(type, hash, prop) { + hash = this._super(type, hash, prop); + if (!hash.hasOwnProperty('firstName')){ + hash.firstName = null; + } + if (!hash.hasOwnProperty('lastName')){ + hash.lastName = null; + } + return hash; + } +}); +``` + +Or if you want to restore the old behavior for all of your models: + +```javascript +// app/serializers/application.js +// or App.ApplicationSerializer +export default DS.RESTSerializer.extend({ + normalize: function(type, hash, prop) { + hash = this._super(type, hash, prop); + type.eachAttribute(function(key) { + if (!hash.hasOwnProperty(key)) { + hash[key] = null; + } + }, this); + return hash; + } +}); +``` + + ### Ember Data 1.0.0-beta.12 (November 25, 2014) #### Breaking Changes From e7651925ca23d1e2a87d6a54fb15ff8353af83ca Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 16 Dec 2014 10:25:05 -0500 Subject: [PATCH 0512/2527] Include build instructions in the readme Closes #2597 --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index d6304cec71e..1730f0417ed 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,16 @@ For details on anticipated changes before the 1.0 release, see the blog post [The Road to Ember Data 1.0](http://emberjs.com/blog/2014/03/18/the-road-to-ember-data-1-0.html). +# Building Ember Data + +1. Ensure that [Node.js](http://nodejs.org/) is installed. +2. Run `npm install` to ensure the required dependencies are installed. +3. Run `npm run dist` to build Ember Data. The builds will be placed in the `dist/` directory. + +# Contribution + +See [CONTRIBUTING.md](https://github.com/emberjs/data/blob/master/CONTRIBUTING.md) + ## How to Run Unit Tests ### Setup From fa20f955792cf00cd0784ebd45b69e08341856d1 Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Wed, 17 Dec 2014 00:40:49 +0100 Subject: [PATCH 0513/2527] add test about model's attributes dirtiness --- packages/ember-data/tests/unit/model_test.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index ff2723f10ab..682972842ac 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -59,6 +59,23 @@ test("resetting a property on a record cause it to become clean again", function }); }); +test("a record becomes clean again only if all changed properties are reset", function() { + run(function(){ + store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); + store.find(Person, 1).then(function(person) { + equal(person.get('isDirty'), false, "precond - person record should not be dirty"); + person.set('isDrugAddict', false); + equal(person.get('isDirty'), true, "record becomes dirty after setting one property to a new value"); + person.set('name', 'Mark'); + equal(person.get('isDirty'), true, "record stays dirty after setting another property to a new value"); + person.set('isDrugAddict', true); + equal(person.get('isDirty'), true, "record stays dirty after resetting only one property to the old value"); + person.set('name', 'Peter'); + equal(person.get('isDirty'), false, "record becomes clean after resetting both properties to the old value"); + }); + }); +}); + test("a record reports its unique id via the `id` property", function() { run(function(){ store.push(Person, { id: 1 }); From 0dae4f0b973d00882bd063b1bd381dac42399482 Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Wed, 17 Dec 2014 01:20:58 +0100 Subject: [PATCH 0514/2527] test setting polymorphic belongsTo, opposite hasMany works --- .../relationships/has_many_test.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 081c5970176..88872a25a59 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -640,6 +640,28 @@ test("Polymorphic relationships work with a hasMany whose type is inferred", fun }); }); +test("Polymorphic relationships with a hasMany is set up correctly on both sides", function() { + expect(2); + + Contact.reopen({ + posts: DS.hasMany('post') + }); + + Post.reopen({ + contact: DS.belongsTo('contact', { polymorphic: true }) + }); + + Ember.run(function () { + email = env.store.createRecord('email'); + post = env.store.createRecord('post', { + contact: email + }); + }); + + equal(post.get('contact'), email, 'The polymorphic belongsTo is set up correctly'); + equal(get(email, 'posts.length'), 1, "The inverse has many is set up correctly on the email side."); +}); + test("A record can't be created from a polymorphic hasMany relationship", function() { run(function(){ env.store.push('user', { id: 1, messages: [] }); From f27cb1b71e111015ecac830f913af51360f56ec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Pa=C5=82ek?= Date: Wed, 17 Dec 2014 19:52:06 +0100 Subject: [PATCH 0515/2527] fix DS.Errors#errorsFor documentation --- packages/ember-data/lib/system/model/errors.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index 8e26ca78e4f..3ebf5c3ad3f 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -131,7 +131,8 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { email: 'invalidEmail' }); user.save().catch(function(){ - user.get('errors').errorsFor('email'); // ["Doesn't look like a valid email."] + user.get('errors').errorsFor('email'); // returns: + // [{attribute: "email", message: "Doesn't look like a valid email."}] }); ``` From 75dbd8ffb0101f82c0a84e44132fdda1661f2d2a Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 22 Oct 2014 20:35:52 +0300 Subject: [PATCH 0516/2527] Schedule relationship normalizaiton and split paths for canonical/client relationship updates This PR makes several changes to relationship handling: 1. It separates the path through which server side and client side updates happen, which lays the ground work for tracking relationship changes. 2. When pushing records into the store, it splits the push process into three phases using a custom runloop: a) Push primary key data and attribtues b) Turn foreign keys into records c) Update relationships The runloop changes have the effect of making pushing relationships at least 50% faster, more if you have more relationships. It also fixes bugs like #2210 --- .gitignore | 1 + packages/ember-data/lib/main.js | 2 +- packages/ember-data/lib/system/model/model.js | 2 +- .../lib/system/record_array_manager.js | 28 +- .../lib/system/record_arrays/many_array.js | 85 +++- .../lib/system/relationships/belongs_to.js | 6 +- .../lib/system/relationships/has_many.js | 13 +- .../lib/system/relationships/relationship.js | 394 ------------------ .../system/relationships/state/belongs_to.js | 133 ++++++ .../lib/system/relationships/state/create.js | 20 + .../system/relationships/state/has_many.js | 193 +++++++++ .../relationships/state/relationship.js | 223 ++++++++++ packages/ember-data/lib/system/store.js | 116 ++++-- .../integration/adapter/rest_adapter_test.js | 37 ++ .../tests/unit/model/relationships_test.js | 4 +- .../ember-data/tests/unit/store/push_test.js | 18 +- 16 files changed, 773 insertions(+), 502 deletions(-) delete mode 100644 packages/ember-data/lib/system/relationships/relationship.js create mode 100644 packages/ember-data/lib/system/relationships/state/belongs_to.js create mode 100644 packages/ember-data/lib/system/relationships/state/create.js create mode 100644 packages/ember-data/lib/system/relationships/state/has_many.js create mode 100644 packages/ember-data/lib/system/relationships/state/relationship.js diff --git a/.gitignore b/.gitignore index 0945db04706..15d57e983e9 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ docs/node_modules/ node_modules/ bower_components/ +.metadata_never_index diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index 49a7a1c7367..743774ec2c3 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -64,7 +64,7 @@ import "ember-data/ember-initializer"; import setupContainer from "ember-data/setup-container"; import ContainerProxy from "ember-data/system/container_proxy"; -import {Relationship} from "ember-data/system/relationships/relationship"; +import Relationship from "ember-data/system/relationships/state/relationship"; DS.Store = Store; DS.PromiseArray = PromiseArray; diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 1a039bd835c..e8b8f9478c6 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1,9 +1,9 @@ import RootState from "ember-data/system/model/states"; import Errors from "ember-data/system/model/errors"; import { PromiseObject } from "ember-data/system/promise_proxies"; -import { createRelationshipFor } from "ember-data/system/relationships/relationship"; import merge from "ember-data/system/merge"; import JSONSerializer from "ember-data/serializers/json_serializer"; +import createRelationshipFor from "ember-data/system/relationships/state/create"; /** @module ember-data diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index cba30d1c189..a8be3a6d69f 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -5,8 +5,7 @@ import { RecordArray, FilteredRecordArray, - AdapterPopulatedRecordArray, - ManyArray + AdapterPopulatedRecordArray } from "ember-data/system/record_arrays"; import { MapWithDefault, @@ -158,31 +157,6 @@ export default Ember.Object.extend({ } }, - /** - Create a `DS.ManyArray` for a type and list of record references, and index - the `ManyArray` under each reference. This allows us to efficiently remove - records from `ManyArray`s when they are deleted. - - @method createManyArray - @param {Class} type - @param {Array} references - @return {DS.ManyArray} - */ - createManyArray: function(type, records) { - var manyArray = ManyArray.create({ - type: type, - content: records, - store: this.store - }); - - forEach(records, function(record) { - var arrays = this.recordArraysForRecord(record); - arrays.add(manyArray); - }, this); - - return manyArray; - }, - /** Create a `DS.RecordArray` for a type and register it for updates. diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 91655a0ba7d..865cceb742f 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -1,5 +1,3 @@ -import RecordArray from "ember-data/system/record_arrays/record_array"; - /** @module ember-data */ @@ -42,11 +40,39 @@ var get = Ember.get, set = Ember.set; @namespace DS @extends DS.RecordArray */ -export default RecordArray.extend({ +export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { init: function() { - this._super.apply(this, arguments); + this.currentState = Ember.A([]); + this.diff = []; }, + record: null, + + canonicalState: null, + currentState: null, + + diff: null, + + length: 0, + + objectAt: function(index) { + if (this.currentState[index]) { + return this.currentState[index]; + } else { + return this.canonicalState[index]; + } + }, + + flushCanonical: function() { + //TODO make this smarter, currently its plenty stupid + this.arrayContentWillChange(0, this.length, this.length); + this.set('length', this.canonicalState.length); + this.currentState = this.canonicalState.slice(0); + this.arrayContentDidChange(0, this.length, this.length); + //TODO Figure out to notify only on additions and maybe only if unloaded + this.relationship.notifyHasManyChanged(); + this.record.updateRecordArrays(); + }, /** `true` if the relationship is polymorphic, `false` otherwise. @@ -70,7 +96,48 @@ export default RecordArray.extend({ */ relationship: null, + internalReplace: function(idx, amt, objects) { + if (!objects) { + objects = []; + } + this.arrayContentWillChange(idx, 0, objects.length); + this.currentState.splice.apply(this.currentState, [idx, amt].concat(objects)); + this.set('length', this.currentState.length); + this.arrayContentDidChange(idx, 0, objects.length); + if (objects){ + //TODO(Igor) probably needed only for unloaded records + this.relationship.notifyHasManyChanged(); + } + this.record.updateRecordArrays(); + }, + //TODO(Igor) optimize + internalRemoveRecords: function(records) { + var index; + for(var i=0; i < records.length; i++) { + index = this.currentState.indexOf(records[i]); + this.internalReplace(index, 1); + } + }, + + //TODO(Igor) optimize + internalAddRecords: function(records, idx) { + if (idx === undefined) { + idx = this.currentState.length; + } + this.internalReplace(idx, 0, records); + }, + + replace: function(idx, amt, objects) { + var records; + if (amt > 0){ + records = this.currentState.slice(idx, idx+amt); + this.get('relationship').removeRecords(records); + } + if (objects){ + this.get('relationship').addRecords(objects, idx); + } + }, /** Used for async `hasMany` arrays to keep track of when they will resolve. @@ -101,16 +168,6 @@ export default RecordArray.extend({ } }, - replaceContent: function(idx, amt, objects){ - var records; - if (amt > 0){ - records = get(this, 'content').slice(idx, idx+amt); - this.get('relationship').removeRecords(records); - } - if (objects){ - this.get('relationship').addRecords(objects, idx); - } - }, /** @method reload @public diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index 646c0b59598..cfcc259ed6d 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -101,11 +101,7 @@ function belongsTo(type, options) { @namespace DS */ Model.reopen({ - notifyBelongsToAdded: function(key, relationship) { - this.notifyPropertyChange(key); - }, - - notifyBelongsToRemoved: function(key) { + notifyBelongsToChanged: function(key) { this.notifyPropertyChange(key); } }); diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index 39973ff102a..7d34df375c1 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -122,21 +122,14 @@ function hasMany(type, options) { } Model.reopen({ - notifyHasManyAdded: function(key, record, idx) { - var relationship = this._relationships[key]; - var manyArray = relationship.manyArray; - manyArray.addRecord(record, idx); + notifyHasManyAdded: function(key) { //We need to notifyPropertyChange in the adding case because we need to make sure //we fetch the newly added record in case it is unloaded //TODO(Igor): Consider whether we could do this only if the record state is unloaded + + //Goes away once hasMany is double promisified this.notifyPropertyChange(key); }, - - notifyHasManyRemoved: function(key, record) { - var relationship = this._relationships[key]; - var manyArray = relationship.manyArray; - manyArray.removeRecord(record); - } }); diff --git a/packages/ember-data/lib/system/relationships/relationship.js b/packages/ember-data/lib/system/relationships/relationship.js deleted file mode 100644 index 273e863f671..00000000000 --- a/packages/ember-data/lib/system/relationships/relationship.js +++ /dev/null @@ -1,394 +0,0 @@ -import { - PromiseManyArray, - PromiseObject -} from "ember-data/system/promise_proxies"; -import { - OrderedSet -} from "ember-data/system/map"; - -var forEach = Ember.EnumerableUtils.forEach; - -var Relationship = function(store, record, inverseKey, relationshipMeta) { - this.members = new OrderedSet(); - this.store = store; - this.key = relationshipMeta.key; - this.inverseKey = inverseKey; - this.record = record; - this.isAsync = relationshipMeta.options.async; - this.relationshipMeta = relationshipMeta; - //This probably breaks for polymorphic relationship in complex scenarios, due to - //multiple possible typeKeys - this.inverseKeyForImplicit = this.store.modelFor(this.record.constructor).typeKey + this.key; - //Cached promise when fetching the relationship from a link - this.linkPromise = null; -}; - -Relationship.prototype = { - constructor: Relationship, - - destroy: Ember.K, - - clear: function() { - var members = this.members.list; - var member; - - while (members.length > 0){ - member = members[0]; - this.removeRecord(member); - } - }, - - disconnect: function(){ - this.members.forEach(function(member) { - this.removeRecordFromInverse(member); - }, this); - }, - - reconnect: function(){ - this.members.forEach(function(member) { - this.addRecordToInverse(member); - }, this); - }, - - removeRecords: function(records){ - var self = this; - forEach(records, function(record){ - self.removeRecord(record); - }); - }, - - addRecords: function(records, idx){ - var self = this; - forEach(records, function(record){ - self.addRecord(record, idx); - if (idx !== undefined) { - idx++; - } - }); - }, - - addRecord: function(record, idx) { - if (!this.members.has(record)) { - this.members.add(record); - this.notifyRecordRelationshipAdded(record, idx); - if (this.inverseKey) { - record._relationships[this.inverseKey].addRecord(this.record); - } else { - if (!record._implicitRelationships[this.inverseKeyForImplicit]) { - record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, {options:{}}); - } - record._implicitRelationships[this.inverseKeyForImplicit].addRecord(this.record); - } - this.record.updateRecordArrays(); - } - }, - - removeRecord: function(record) { - if (this.members.has(record)) { - this.removeRecordFromOwn(record); - if (this.inverseKey) { - this.removeRecordFromInverse(record); - } else { - if (record._implicitRelationships[this.inverseKeyForImplicit]) { - record._implicitRelationships[this.inverseKeyForImplicit].removeRecord(this.record); - } - } - } - }, - - addRecordToInverse: function(record) { - if (this.inverseKey) { - record._relationships[this.inverseKey].addRecord(this.record); - } - }, - - removeRecordFromInverse: function(record) { - var inverseRelationship = record._relationships[this.inverseKey]; - //Need to check for existence, as the record might unloading at the moment - if (inverseRelationship) { - inverseRelationship.removeRecordFromOwn(this.record); - } - }, - - removeRecordFromOwn: function(record) { - this.members.delete(record); - this.notifyRecordRelationshipRemoved(record); - this.record.updateRecordArrays(); - }, - - updateLink: function(link) { - Ember.warn("You have pushed a record of type '" + this.record.constructor.typeKey + "' with '" + this.key + "' as a link, but the association is not an aysnc relationship.", this.isAsync); - Ember.assert("You have pushed a record of type '" + this.record.constructor.typeKey + "' with '" + this.key + "' as a link, but the value of that link is not a string.", typeof link === 'string' || link === null); - if (link !== this.link) { - this.link = link; - this.linkPromise = null; - this.record.notifyPropertyChange(this.key); - } - }, - - findLink: function() { - if (this.linkPromise) { - return this.linkPromise; - } else { - var promise = this.fetchLink(); - this.linkPromise = promise; - return promise.then(function(result) { - return result; - }); - } - }, - - updateRecordsFromAdapter: function(records) { - //TODO Once we have adapter support, we need to handle updated and canonical changes - this.computeChanges(records); - }, - - notifyRecordRelationshipAdded: Ember.K, - notifyRecordRelationshipRemoved: Ember.K -}; - -var ManyRelationship = function(store, record, inverseKey, relationshipMeta) { - this._super$constructor(store, record, inverseKey, relationshipMeta); - this.belongsToType = relationshipMeta.type; - this.manyArray = store.recordArrayManager.createManyArray(this.belongsToType, Ember.A()); - this.manyArray.relationship = this; - this.isPolymorphic = relationshipMeta.options.polymorphic; - this.manyArray.isPolymorphic = this.isPolymorphic; -}; - -ManyRelationship.prototype = Ember.create(Relationship.prototype); -ManyRelationship.prototype.constructor = ManyRelationship; -ManyRelationship.prototype._super$constructor = Relationship; - -ManyRelationship.prototype.destroy = function() { - this.manyArray.destroy(); -}; - -ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) { - Ember.assert("You cannot add '" + record.constructor.typeKey + "' records to this relationship (only '" + this.belongsToType.typeKey + "' allowed)", !this.belongsToType || record instanceof this.belongsToType); - this.record.notifyHasManyAdded(this.key, record, idx); -}; - -ManyRelationship.prototype.notifyRecordRelationshipRemoved = function(record) { - this.record.notifyHasManyRemoved(this.key, record); -}; - -ManyRelationship.prototype.reload = function() { - var self = this; - if (this.link) { - return this.fetchLink(); - } else { - return this.store.scheduleFetchMany(this.manyArray.toArray()).then(function() { - //Goes away after the manyArray refactor - self.manyArray.set('isLoaded', true); - return self.manyArray; - }); - } -}; - -ManyRelationship.prototype.computeChanges = function(records) { - var members = this.members; - var recordsToRemove = []; - var length; - var record; - var i; - - records = setForArray(records); - - members.forEach(function(member) { - if (member.get('isNew') || records.has(member)) return; - - recordsToRemove.push(member); - }); - this.removeRecords(recordsToRemove); - - var hasManyArray = this.manyArray; - - // Using records.toArray() since currently using - // removeRecord can modify length, messing stuff up - // forEach since it directly looks at "length" each - // iteration - records = records.toArray(); - length = records.length; - for (i = 0; i < length; i++){ - record = records[i]; - //Need to preserve the order of incoming records - if (hasManyArray.objectAt(i) === record ) { - continue; - } - this.removeRecord(record); - this.addRecord(record, i); - } -}; - -ManyRelationship.prototype.fetchLink = function() { - var self = this; - return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function(records){ - self.updateRecordsFromAdapter(records); - return self.manyArray; - }); -}; - -ManyRelationship.prototype.findRecords = function() { - var manyArray = this.manyArray; - return this.store.findMany(manyArray.toArray()).then(function(){ - //Goes away after the manyArray refactor - manyArray.set('isLoaded', true); - return manyArray; - }); -}; - -ManyRelationship.prototype.getRecords = function() { - if (this.isAsync) { - var self = this; - var promise; - if (this.link) { - promise = this.findLink().then(function() { - return self.findRecords(); - }); - } else { - promise = this.findRecords(); - } - return PromiseManyArray.create({ - content: this.manyArray, - promise: promise - }); - } else { - Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.constructor.typeKey + "' with id " + this.record.get('id') + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); - - if (!this.manyArray.get('isDestroyed')) { - this.manyArray.set('isLoaded', true); - } - return this.manyArray; - } -}; - -var BelongsToRelationship = function(store, record, inverseKey, relationshipMeta) { - this._super$constructor(store, record, inverseKey, relationshipMeta); - this.record = record; - this.key = relationshipMeta.key; - this.inverseRecord = null; -}; - -BelongsToRelationship.prototype = Ember.create(Relationship.prototype); -BelongsToRelationship.prototype.constructor = BelongsToRelationship; -BelongsToRelationship.prototype._super$constructor = Relationship; - -BelongsToRelationship.prototype.setRecord = function(newRecord) { - if (newRecord) { - this.addRecord(newRecord); - } else if (this.inverseRecord) { - this.removeRecord(this.inverseRecord); - } -}; - -BelongsToRelationship.prototype._super$addRecord = Relationship.prototype.addRecord; -BelongsToRelationship.prototype.addRecord = function(newRecord) { - if (this.members.has(newRecord)){ return;} - var type = this.relationshipMeta.type; - Ember.assert("You can only add a '" + type.typeKey + "' record to this relationship", newRecord instanceof type); - - if (this.inverseRecord) { - this.removeRecord(this.inverseRecord); - } - - this.inverseRecord = newRecord; - this._super$addRecord(newRecord); -}; - -BelongsToRelationship.prototype.setRecordPromise = function(newPromise) { - var content = newPromise.get && newPromise.get('content'); - Ember.assert("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); - this.setRecord(content); -}; - -BelongsToRelationship.prototype.notifyRecordRelationshipAdded = function(newRecord) { - this.record.notifyBelongsToAdded(this.key, this); -}; - -BelongsToRelationship.prototype.notifyRecordRelationshipRemoved = function(record) { - this.record.notifyBelongsToRemoved(this.key, this); -}; - -BelongsToRelationship.prototype._super$removeRecordFromOwn = Relationship.prototype.removeRecordFromOwn; -BelongsToRelationship.prototype.removeRecordFromOwn = function(record) { - if (!this.members.has(record)) { return; } - this.inverseRecord = null; - this._super$removeRecordFromOwn(record); -}; - -BelongsToRelationship.prototype.findRecord = function() { - if (this.inverseRecord) { - return this.store._findByRecord(this.inverseRecord); - } else { - return Ember.RSVP.Promise.resolve(null); - } -}; - -BelongsToRelationship.prototype.fetchLink = function() { - var self = this; - return this.store.findBelongsTo(this.record, this.link, this.relationshipMeta).then(function(record){ - if (record) { - self.addRecord(record); - } - return record; - }); -}; - -BelongsToRelationship.prototype.getRecord = function() { - if (this.isAsync) { - var promise; - if (this.link){ - var self = this; - promise = this.findLink().then(function() { - return self.findRecord(); - }); - } else { - promise = this.findRecord(); - } - - return PromiseObject.create({ - promise: promise, - content: this.inverseRecord - }); - } else { - Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.constructor.typeKey + "' with id " + this.record.get('id') + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", this.inverseRecord === null || !this.inverseRecord.get('isEmpty')); - return this.inverseRecord; - } -}; - -function setForArray(array) { - var set = new OrderedSet(); - - if (array) { - for (var i=0, l=array.length; i -1) { + this.canonicalState.splice(i, 1); + } + this._super$removeCanonicalRecordFromOwn(record, idx); +}; + +ManyRelationship.prototype._super$flushCanonical = Relationship.prototype.flushCanonical; +ManyRelationship.prototype.flushCanonical = function() { + this.manyArray.flushCanonical(); + this._super$flushCanonical(); +}; + +ManyRelationship.prototype._super$removeRecordFromOwn = Relationship.prototype.removeRecordFromOwn; +ManyRelationship.prototype.removeRecordFromOwn = function(record, idx) { + if (!this.members.has(record)) { + return; + } + this._super$removeRecordFromOwn(record, idx); + if (idx !== undefined) { + //TODO(Igor) not used currently, fix + this.manyArray.currentState.removeAt(idx); + } else { + this.manyArray.internalRemoveRecords([record]); + } +}; + +ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) { + Ember.assert("You cannot add '" + record.constructor.typeKey + "' records to this relationship (only '" + this.belongsToType.typeKey + "' allowed)", !this.belongsToType || record instanceof this.belongsToType); + this.record.notifyHasManyAdded(this.key, record, idx); +}; + +ManyRelationship.prototype.reload = function() { + var self = this; + if (this.link) { + return this.fetchLink(); + } else { + return this.store.scheduleFetchMany(this.manyArray.toArray()).then(function() { + //Goes away after the manyArray refactor + self.manyArray.set('isLoaded', true); + return self.manyArray; + }); + } +}; + +ManyRelationship.prototype.computeChanges = function(records) { + var members = this.canonicalMembers; + var recordsToRemove = []; + var length; + var record; + var i; + + records = setForArray(records); + + members.forEach(function(member) { + if (records.has(member)) return; + + recordsToRemove.push(member); + }); + + this.removeCanonicalRecords(recordsToRemove); + + var hasManyArray = this.manyArray; + + // Using records.toArray() since currently using + // removeRecord can modify length, messing stuff up + // forEach since it directly looks at "length" each + // iteration + records = records.toArray(); + length = records.length; + for (i = 0; i < length; i++){ + record = records[i]; + //Need to preserve the order of incoming records + if (hasManyArray.objectAt(i) === record ) { + continue; + } + this.removeCanonicalRecord(record); + this.addCanonicalRecord(record, i); + } +}; + +ManyRelationship.prototype.fetchLink = function() { + var self = this; + return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function(records){ + self.updateRecordsFromAdapter(records); + return self.manyArray; + }); +}; + +ManyRelationship.prototype.findRecords = function() { + var manyArray = this.manyArray; + return this.store.findMany(manyArray.toArray()).then(function(){ + //Goes away after the manyArray refactor + manyArray.set('isLoaded', true); + return manyArray; + }); +}; +ManyRelationship.prototype.notifyHasManyChanged = function() { + this.record.notifyHasManyAdded(this.key); +}; + +ManyRelationship.prototype.getRecords = function() { + //TODO(Igor) sync server here, once our syncing is not stupid + if (this.isAsync) { + var self = this; + var promise; + if (this.link) { + promise = this.findLink().then(function() { + return self.findRecords(); + }); + } else { + promise = this.findRecords(); + } + return PromiseManyArray.create({ + content: this.manyArray, + promise: promise + }); + } else { + Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.constructor.typeKey + "' with id " + this.record.get('id') + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); + + //TODO(Igor) WTF DO I DO HERE? + if (!this.manyArray.get('isDestroyed')) { + this.manyArray.set('isLoaded', true); + } + return this.manyArray; + } +}; + +function setForArray(array) { + var set = new OrderedSet(); + + if (array) { + for (var i=0, l=array.length; i Date: Sat, 13 Dec 2014 22:03:28 -0500 Subject: [PATCH 0517/2527] backport a fix for #2510 --- .../lib/system/record_arrays/many_array.js | 11 ++++- .../system/relationships/state/belongs_to.js | 5 +++ .../relationships/state/relationship.js | 11 +++++ packages/ember-data/lib/system/store.js | 4 +- .../integration/adapter/rest_adapter_test.js | 9 ++-- .../relationships/has_many_test.js | 41 +++++++++++++++++++ 6 files changed, 74 insertions(+), 7 deletions(-) diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 865cceb742f..f6ad20c3231 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -65,9 +65,16 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { flushCanonical: function() { //TODO make this smarter, currently its plenty stupid + var toSet = this.canonicalState.slice(0); + //a hack for not removing new records + //TODO remove once we have proper diffing + var newRecords = this.currentState.filter(function(record) { + return record.get('isNew'); + }); + toSet = toSet.concat(newRecords); this.arrayContentWillChange(0, this.length, this.length); - this.set('length', this.canonicalState.length); - this.currentState = this.canonicalState.slice(0); + this.set('length', toSet.length); + this.currentState = toSet; this.arrayContentDidChange(0, this.length, this.length); //TODO Figure out to notify only on additions and maybe only if unloaded this.relationship.notifyHasManyChanged(); diff --git a/packages/ember-data/lib/system/relationships/state/belongs_to.js b/packages/ember-data/lib/system/relationships/state/belongs_to.js index 0954f12eb32..7e517a59cdd 100644 --- a/packages/ember-data/lib/system/relationships/state/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/state/belongs_to.js @@ -48,6 +48,11 @@ BelongsToRelationship.prototype.addCanonicalRecord = function(newRecord) { BelongsToRelationship.prototype._super$flushCanonical = Relationship.prototype.flushCanonical; BelongsToRelationship.prototype.flushCanonical = function() { + //temporary fix to not remove newly created records if server returned null. + //TODO remove once we have proper diffing + if (this.inverseRecord && this.inverseRecord.get('isNew') && !this.canonicalState) { + return; + } this.inverseRecord = this.canonicalState; this.record.notifyBelongsToChanged(this.key); this._super$flushCanonical(); diff --git a/packages/ember-data/lib/system/relationships/state/relationship.js b/packages/ember-data/lib/system/relationships/state/relationship.js index 4bf5e1da2a1..7ec95a63f63 100644 --- a/packages/ember-data/lib/system/relationships/state/relationship.js +++ b/packages/ember-data/lib/system/relationships/state/relationship.js @@ -170,8 +170,19 @@ Relationship.prototype = { flushCanonical: function() { this.willSync = false; + //a hack for not removing new records + //TODO remove once we have proper diffing + var newRecords = []; + for (var i=0; i Date: Wed, 17 Dec 2014 20:01:08 -0500 Subject: [PATCH 0518/2527] Backport relationship.proto.clear bugfix --- .../lib/system/relationships/state/relationship.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/state/relationship.js b/packages/ember-data/lib/system/relationships/state/relationship.js index 7ec95a63f63..818d902fae9 100644 --- a/packages/ember-data/lib/system/relationships/state/relationship.js +++ b/packages/ember-data/lib/system/relationships/state/relationship.js @@ -23,9 +23,13 @@ Relationship.prototype = { destroy: Ember.K, clear: function() { - this.members.forEach(function(member) { + var members = this.members.list; + var member; + + while (members.length > 0){ + member = members[0]; this.removeRecord(member); - }, this); + } }, disconnect: function(){ From 449bb192b0187770f5163350b1e92af383bf4768 Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 17 Dec 2014 20:07:41 -0500 Subject: [PATCH 0519/2527] Backport pushing non async relationship as a link --- .../ember-data/lib/system/relationships/state/relationship.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ember-data/lib/system/relationships/state/relationship.js b/packages/ember-data/lib/system/relationships/state/relationship.js index 818d902fae9..760ef782627 100644 --- a/packages/ember-data/lib/system/relationships/state/relationship.js +++ b/packages/ember-data/lib/system/relationships/state/relationship.js @@ -201,6 +201,7 @@ Relationship.prototype = { }, updateLink: function(link) { + Ember.warn("You have pushed a record of type '" + this.record.constructor.typeKey + "' with '" + this.key + "' as a link, but the association is not an aysnc relationship.", this.isAsync); Ember.assert("You have pushed a record of type '" + this.record.constructor.typeKey + "' with '" + this.key + "' as a link, but the value of that link is not a string.", typeof link === 'string' || link === null); if (link !== this.link) { this.link = link; From cde3f8c26cc56dc0bde5ce6604f7d3576f1f4e89 Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 17 Dec 2014 20:26:07 -0500 Subject: [PATCH 0520/2527] Use Ember.create and Ember.EnumerableUtils for relationships --- .../lib/system/relationships/state/belongs_to.js | 2 +- .../lib/system/relationships/state/has_many.js | 2 +- .../lib/system/relationships/state/relationship.js | 14 ++++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/state/belongs_to.js b/packages/ember-data/lib/system/relationships/state/belongs_to.js index 7e517a59cdd..4b41a4a03ad 100644 --- a/packages/ember-data/lib/system/relationships/state/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/state/belongs_to.js @@ -12,7 +12,7 @@ var BelongsToRelationship = function(store, record, inverseKey, relationshipMeta this.canonicalState = null; }; -BelongsToRelationship.prototype = Object.create(Relationship.prototype); +BelongsToRelationship.prototype = Ember.create(Relationship.prototype); BelongsToRelationship.prototype.constructor = BelongsToRelationship; BelongsToRelationship.prototype._super$constructor = Relationship; diff --git a/packages/ember-data/lib/system/relationships/state/has_many.js b/packages/ember-data/lib/system/relationships/state/has_many.js index ddd95fcca09..7d0f3adfdd0 100644 --- a/packages/ember-data/lib/system/relationships/state/has_many.js +++ b/packages/ember-data/lib/system/relationships/state/has_many.js @@ -12,7 +12,7 @@ var ManyRelationship = function(store, record, inverseKey, relationshipMeta) { this.manyArray.isPolymorphic = this.isPolymorphic; }; -ManyRelationship.prototype = Object.create(Relationship.prototype); +ManyRelationship.prototype = Ember.create(Relationship.prototype); ManyRelationship.prototype.constructor = ManyRelationship; ManyRelationship.prototype._super$constructor = Relationship; diff --git a/packages/ember-data/lib/system/relationships/state/relationship.js b/packages/ember-data/lib/system/relationships/state/relationship.js index 760ef782627..1884ca9921b 100644 --- a/packages/ember-data/lib/system/relationships/state/relationship.js +++ b/packages/ember-data/lib/system/relationships/state/relationship.js @@ -2,6 +2,8 @@ import { OrderedSet } from "ember-data/system/map"; +var forEach = Ember.EnumerableUtils.forEach; + var Relationship = function(store, record, inverseKey, relationshipMeta) { this.members = new OrderedSet(); this.canonicalMembers = new OrderedSet(); @@ -45,16 +47,16 @@ Relationship.prototype = { }, removeRecords: function(records){ - var that = this; - records.forEach(function(record){ - that.removeRecord(record); + var self = this; + forEach(records, function(record){ + self.removeRecord(record); }); }, addRecords: function(records, idx){ - var that = this; - records.forEach(function(record){ - that.addRecord(record, idx); + var self = this; + forEach(records, function(record){ + self.addRecord(record, idx); if (idx !== undefined) { idx++; } From b1fdb4b88a34832dfa6725db8e09cafdae75444c Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 17 Dec 2014 20:13:56 -0500 Subject: [PATCH 0521/2527] Make backburner import work with Ember.17 --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index a49f3fa5578..b2b36d736ec 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -23,7 +23,7 @@ import RecordArrayManager from "ember-data/system/record_array_manager"; import { Model } from "ember-data/system/model"; //Stanley told me to do this -var Backburner = Ember.__loader.require('backburner')['default']; +var Backburner = Ember.__loader.require('backburner')['default'] || Ember.__loader.require('backburner')['Backburner']; var get = Ember.get; From fdf1f0a6a4a227dd9d106c99e703efb292df6941 Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 17 Dec 2014 21:16:56 -0500 Subject: [PATCH 0522/2527] Shim backburner join until we are sure Ember has it --- packages/ember-data/lib/system/store.js | 40 +++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index b2b36d736ec..c5f8c2eb00f 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -25,6 +25,46 @@ import { Model } from "ember-data/system/model"; //Stanley told me to do this var Backburner = Ember.__loader.require('backburner')['default'] || Ember.__loader.require('backburner')['Backburner']; +//Shim Backburner.join +if (!Backburner.prototype.join) { + var isString = function(suspect) { + return typeof suspect === 'string'; + }; + + Backburner.prototype.join = function(/*target, method, args */) { + var method, target; + + if (this.currentInstance) { + var length = arguments.length; + if (length === 1) { + method = arguments[0]; + target = null; + } else { + target = arguments[0]; + method = arguments[1]; + } + + if (isString(method)) { + method = target[method]; + } + + if (length === 1) { + return method(); + } else if (length === 2) { + return method.call(target); + } else { + var args = new Array(length - 2); + for (var i =0, l = length - 2; i < l; i++) { + args[i] = arguments[i + 2]; + } + return method.apply(target, args); + } + } else { + return this.run.apply(this, arguments); + } + }; +} + var get = Ember.get; var set = Ember.set; From 43ced435a5a47e3de7fb2f1bb557cd615354cf5b Mon Sep 17 00:00:00 2001 From: IgorT Date: Thu, 18 Dec 2014 23:16:43 -0500 Subject: [PATCH 0523/2527] Fix array change notification in many arrays Fixes a bug introduced in 75dbd8ffb0101f82c0a84e44132fdda1661f2d2a where removals from a many array were not being notified correctly. --- .../lib/system/record_arrays/many_array.js | 4 +- .../relationships/has_many_test.js | 61 ++++++++++++++++++- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index f6ad20c3231..6797de9d7e9 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -107,10 +107,10 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { if (!objects) { objects = []; } - this.arrayContentWillChange(idx, 0, objects.length); + this.arrayContentWillChange(idx, amt, objects.length); this.currentState.splice.apply(this.currentState, [idx, amt].concat(objects)); this.set('length', this.currentState.length); - this.arrayContentDidChange(idx, 0, objects.length); + this.arrayContentDidChange(idx, amt, objects.length); if (objects){ //TODO(Igor) probably needed only for unloaded records this.relationship.notifyHasManyChanged(); diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 277e9267504..66c271e0ee2 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -55,7 +55,8 @@ module("integration/relationships/has_many - Has-Many Relationships", { Book.toString = stringify('Book'); Chapter = DS.Model.extend({ - title: attr() + title: attr(), + pages: hasMany('page') }); Chapter.toString = stringify('Chapter'); @@ -1071,6 +1072,64 @@ test("Rollbacking a deleted record restores implicit relationship correctly when }); }); +test("ManyArray notifies the array observers and flushes bindings when removing", function () { + expect(2); + var chapter, page, page2; + var observe = false; + var arr = Ember.A([1,2]); + run(function(){ + page = env.store.push('page', { id: 1, number: 1 }); + page2 = env.store.push('page', { id: 2, number: 2 }); + chapter = env.store.push('chapter', { id: 1, title: 'Sailing the Seven Seas', pages: [1, 2] }); + chapter.get('pages').addEnumerableObserver(this, { + willChange: function(pages, removing, addCount){ + if (observe) { + equal(removing[0], page2, 'page2 is passed to willChange'); + } + }, + didChange:function(pages, removeCount, adding){ + if (observe) { + equal(removeCount, 1, 'removeCount is correct'); + } + } + }); + }); + run(function(){ + observe = true; + page2.set('chapter', null); + observe = false; + }); +}); + +test("ManyArray notifies the array observers and flushes bindings when adding", function () { + expect(2); + var chapter, page, page2; + var observe = false; + var arr = Ember.A([1,2]); + run(function(){ + page = env.store.push('page', { id: 1, number: 1 }); + page2 = env.store.push('page', { id: 2, number: 2 }); + chapter = env.store.push('chapter', { id: 1, title: 'Sailing the Seven Seas', pages: [1] }); + chapter.get('pages').addEnumerableObserver(this, { + willChange: function(pages, removing, addCount){ + if (observe) { + equal(addCount, 1, 'addCount is correct'); + } + }, + didChange:function(pages, removeCount, adding){ + if (observe) { + equal(adding[0], page2, 'page2 is passed to didChange'); + } + } + }); + }); + run(function(){ + observe = true; + page2.set('chapter', chapter); + observe = false; + }); +}); + test("Passing a model as type to hasMany should not work", function () { expect(1); From fd6f86c980ae05f36ed218aa9a3afe713d779a65 Mon Sep 17 00:00:00 2001 From: gregmuck Date: Sun, 14 Dec 2014 11:54:26 -0500 Subject: [PATCH 0524/2527] Fixed model rollback in the case where an attribute is not assigned so that it rolls back to unassigned instead of cached value. Aadded a supporting unit test. --- packages/ember-data/lib/system/model/model.js | 13 ++++++++++++- .../tests/unit/model/rollback_test.js | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index e8b8f9478c6..6417d1345c7 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -907,6 +907,8 @@ var Model = Ember.Object.extend(Ember.Evented, { @method rollback */ rollback: function() { + var dirtyKeys = this.dirtyKeys(); + this._attributes = Ember.create(null); if (get(this, 'isError')) { @@ -931,8 +933,17 @@ var Model = Ember.Object.extend(Ember.Evented, { this.send('rolledBack'); - this._notifyProperties(Ember.keys(this._data)); + this._notifyProperties(dirtyKeys); + }, + + dirtyKeys: function() { + var keys = Ember.keys(this._attributes); + + if (get(this, 'isNew')) { + keys.concat(Ember.keys(this._data)); + } + return keys; }, toStringExtension: function() { diff --git a/packages/ember-data/tests/unit/model/rollback_test.js b/packages/ember-data/tests/unit/model/rollback_test.js index fde5628601c..158f614f6bc 100644 --- a/packages/ember-data/tests/unit/model/rollback_test.js +++ b/packages/ember-data/tests/unit/model/rollback_test.js @@ -30,6 +30,23 @@ test("changes to attributes can be rolled back", function() { equal(person.get('isDirty'), false); }); +test("changes to unassigned attributes can be rolled back", function() { + var person; + run(function(){ + person = store.push('person', { id: 1, lastName: "Dale" }); + person.set('firstName', "Thomas"); + }); + + equal(person.get('firstName'), "Thomas"); + + run(function(){ + person.rollback(); + }); + + equal(person.get('firstName'), undefined); + equal(person.get('isDirty'), false); +}); + test("changes to attributes made after a record is in-flight only rolls back the local changes", function() { env.adapter.updateRecord = function(store, type, record) { // Make sure the save is async From b6484aa00f8a18e32b8f91218364ac7562c082b1 Mon Sep 17 00:00:00 2001 From: IgorT Date: Fri, 19 Dec 2014 05:32:55 -0500 Subject: [PATCH 0525/2527] Cleanup new attributes saving PR #2594 --- .gitignore | 1 + packages/ember-data/lib/system/model/model.js | 12 +----------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 15d57e983e9..b756ef85947 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ dist/ .project .github-upload-token +*.swp tests/ember-data-tests.js *gem diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 6417d1345c7..b2cac36b436 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -907,7 +907,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @method rollback */ rollback: function() { - var dirtyKeys = this.dirtyKeys(); + var dirtyKeys = Ember.keys(this._attributes); this._attributes = Ember.create(null); @@ -936,16 +936,6 @@ var Model = Ember.Object.extend(Ember.Evented, { this._notifyProperties(dirtyKeys); }, - dirtyKeys: function() { - var keys = Ember.keys(this._attributes); - - if (get(this, 'isNew')) { - keys.concat(Ember.keys(this._data)); - } - - return keys; - }, - toStringExtension: function() { return get(this, 'id'); }, From 4396a707fee4c7120e446564b301e088e61d15d5 Mon Sep 17 00:00:00 2001 From: Luke Deniston Date: Thu, 20 Nov 2014 13:48:07 -0800 Subject: [PATCH 0526/2527] Add Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS option --- packages/ember-data/lib/system/store.js | 20 +++++++++++-------- .../ember-data/tests/unit/store/push_test.js | 18 +++++++++++++++++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index c5f8c2eb00f..12d7765c79c 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1400,14 +1400,18 @@ Store = Ember.Object.extend({ var type = this.modelFor(typeName); var filter = Ember.EnumerableUtils.filter; - Ember.warn("The payload for '" + type.typeKey + "' contains these unknown keys: " + - Ember.inspect(filter(Ember.keys(data), function(key) { - return !get(type, 'fields').has(key) && key !== 'id' && key !== 'links'; - })) + ". Make sure they've been defined in your model.", - filter(Ember.keys(data), function(key) { - return !get(type, 'fields').has(key) && key !== 'id' && key !== 'links'; - }).length === 0 - ); + // If the payload contains unused keys log a warning. + // Adding `Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS = true` will suppress the warning. + if (!Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS) { + Ember.warn("The payload for '" + type.typeKey + "' contains these unknown keys: " + + Ember.inspect(filter(Ember.keys(data), function(key) { + return !get(type, 'fields').has(key) && key !== 'id' && key !== 'links'; + })) + ". Make sure they've been defined in your model.", + filter(Ember.keys(data), function(key) { + return !get(type, 'fields').has(key) && key !== 'id' && key !== 'links'; + }).length === 0 + ); + } // Actually load the record into the store. diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index 5f4e304eaaa..b234cfd30a5 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -556,6 +556,24 @@ test('calling push with an embedded relationship throws a useful error', functio }, /If this is an embedded relationship/); }); +test("Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS suppresses unknown keys warning", function() { + Ember.run(function(){ + try { + Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS = true; + noWarns(function() { + store.push('person', { + id: '1', + firstName: 'Tomster', + emailAddress: 'tomster@emberjs.com', + isMascot: true + }); + }); + } finally { + Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS = null; + } + }); +}); + test("Calling push with unknown keys in the provided payload should warn", function() { warns(function() { run(function(){ From 915515c10a0124d5e58ac3706254959042dbe8f7 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Sun, 21 Dec 2014 03:40:18 +0900 Subject: [PATCH 0527/2527] [DOC] Fix markup for AcriveModelAdapter --- packages/activemodel-adapter/lib/system/active_model_adapter.js | 2 +- .../activemodel-adapter/lib/system/active_model_serializer.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index c212abf5c94..15f5d88cd93 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -13,7 +13,7 @@ var decamelize = Ember.String.decamelize, The ActiveModelAdapter is a subclass of the RESTAdapter designed to integrate with a JSON API that uses an underscored naming convention instead of camelCasing. It has been designed to work out of the box with the - [active_model_serializers](http://github.com/rails-api/active_model_serializers) + [active\_model\_serializers](http://github.com/rails-api/active_model_serializers) Ruby gem. This Adapter expects specific settings using ActiveModel::Serializers, `embed :ids, embed_in_root: true` which sideloads the records. diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index 6fdf40d848f..e57a1938747 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -14,7 +14,7 @@ var get = Ember.get, The ActiveModelSerializer is a subclass of the RESTSerializer designed to integrate with a JSON API that uses an underscored naming convention instead of camelCasing. It has been designed to work out of the box with the - [active_model_serializers](http://github.com/rails-api/active_model_serializers) + [active\_model\_serializers](http://github.com/rails-api/active_model_serializers) Ruby gem. This Serializer expects specific settings using ActiveModel::Serializers, `embed :ids, embed_in_root: true` which sideloads the records. From ce61491fd35b81dd63ab1950c95c932bccb4fae7 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Sun, 21 Dec 2014 03:49:57 +0900 Subject: [PATCH 0528/2527] [DOC] Add page for `DS.PromiseManyArray` --- .../ember-data/lib/system/promise_proxies.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/ember-data/lib/system/promise_proxies.js b/packages/ember-data/lib/system/promise_proxies.js index 3015156b438..ac53fb5b19a 100644 --- a/packages/ember-data/lib/system/promise_proxies.js +++ b/packages/ember-data/lib/system/promise_proxies.js @@ -79,13 +79,18 @@ var promiseArray = function(promise, label) { A PromiseManyArray is a PromiseArray that also proxies certain method calls to the underlying manyArray. Right now we proxy: - `reload()` - `createRecord()` - `on()` - `one()` - `trigger()` - `off()` - `has()` + + * `reload()` + * `createRecord()` + * `on()` + * `one()` + * `trigger()` + * `off()` + * `has()` + + @class PromiseManyArray + @namespace DS + @extends Ember.ArrayProxy */ function proxyToContent(method) { From ba2f46d85fc27bbf38bdce5e20288f6815e34591 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Fri, 12 Dec 2014 14:54:28 -0800 Subject: [PATCH 0529/2527] Work around type check issues with MODEL_FACTORY_INJECTIONS. The container subclasses types retrieved via `modelFor`, so that if A is a subtype of B, modelFor('model:A') will not be a subtype of modelFor('model:B'). This breaks the type check for polymorphic associations. This commit works around this issue by checking the superclass when doing its type checks, if MODEL_FACTORY_INJECTIONS is enabled. --- .../system/relationships/state/belongs_to.js | 10 ++++++- .../system/relationships/state/has_many.js | 12 ++++++++- .../relationships/belongs_to_test.js | 26 ++++++++++++++++--- .../relationships/has_many_test.js | 26 +++++++++++++++++-- 4 files changed, 67 insertions(+), 7 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/state/belongs_to.js b/packages/ember-data/lib/system/relationships/state/belongs_to.js index 4b41a4a03ad..9f5961c58c1 100644 --- a/packages/ember-data/lib/system/relationships/state/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/state/belongs_to.js @@ -62,7 +62,15 @@ BelongsToRelationship.prototype._super$addRecord = Relationship.prototype.addRec BelongsToRelationship.prototype.addRecord = function(newRecord) { if (this.members.has(newRecord)){ return;} var type = this.relationshipMeta.type; - Ember.assert("You can only add a '" + type.typeKey + "' record to this relationship", newRecord instanceof type); + Ember.assert("You can only add a '" + type.typeKey + "' record to this relationship", (function () { + if (newRecord instanceof type) { + return true; + } else if (Ember.MODEL_FACTORY_INJECTIONS) { + return newRecord instanceof type.superclass; + } + + return false; + })()); if (this.inverseRecord) { this.removeRecord(this.inverseRecord); diff --git a/packages/ember-data/lib/system/relationships/state/has_many.js b/packages/ember-data/lib/system/relationships/state/has_many.js index 7d0f3adfdd0..618164b40b5 100644 --- a/packages/ember-data/lib/system/relationships/state/has_many.js +++ b/packages/ember-data/lib/system/relationships/state/has_many.js @@ -78,7 +78,17 @@ ManyRelationship.prototype.removeRecordFromOwn = function(record, idx) { }; ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) { - Ember.assert("You cannot add '" + record.constructor.typeKey + "' records to this relationship (only '" + this.belongsToType.typeKey + "' allowed)", !this.belongsToType || record instanceof this.belongsToType); + var type = this.relationshipMeta.type; + Ember.assert("You cannot add '" + record.constructor.typeKey + "' records to the " + this.record.constructor.typeKey + "." + this.key + " relationship (only '" + this.belongsToType.typeKey + "' allowed)", (function () { + if (record instanceof type) { + return true; + } else if (Ember.MODEL_FACTORY_INJECTIONS) { + return record instanceof type.superclass; + } + + return false; + })()); + this.record.notifyHasManyAdded(this.key, record, idx); }; diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index a2510eb5f26..94d4517bb0a 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -13,13 +13,13 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { setup: function() { User = DS.Model.extend({ name: attr('string'), - messages: hasMany('message', {polymorphic: true}) - //favouriteMessage: belongsTo('message', {polymorphic: true}) + messages: hasMany('message', {polymorphic: true}), + favouriteMessage: belongsTo('message', {polymorphic: true, inverse: null}), }); User.toString = stringify('User'); Message = DS.Model.extend({ - user: belongsTo('user'), + user: belongsTo('user', { inverse: 'messages' }), created_at: attr('date') }); Message.toString = stringify('Message'); @@ -292,6 +292,26 @@ test("A record with an async belongsTo relationship returning null should resolv })); }); +test("polymorphic belongsTo type-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled", function() { + expect(1); + + var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; + Ember.MODEL_FACTORY_INJECTIONS = true; + + try { + run(function () { + var igor = env.store.createRecord('user', { name: 'Igor' }); + var post = env.store.createRecord('post', { title: "Igor's unimaginative blog post" }); + + igor.set('favouriteMessage', post); + + equal(igor.get('favouriteMessage.title'), "Igor's unimaginative blog post"); + }); + } finally { + Ember.MODEL_FACTORY_INJECTIONS = injectionValue; + } +}); + test("relationshipsByName does not cache a factory", function() { // The model is loaded up via a container. It has relationshipsByName diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 66c271e0ee2..16157581d1a 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -628,6 +628,28 @@ test("When a polymorphic hasMany relationship is accessed, the store can call mu }); }); +test("polymorphic hasMany type-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled", function() { + expect(1); + + var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; + Ember.MODEL_FACTORY_INJECTIONS = true; + + try { + run(function () { + var igor = env.store.createRecord('user', { name: 'Igor' }); + var comment = env.store.createRecord('comment', { body: "Well I thought the title was fine" }); + + igor.get('messages').addObject(comment); + + equal(igor.get('messages.firstObject.body'), "Well I thought the title was fine"); + }); + } finally { + Ember.MODEL_FACTORY_INJECTIONS = injectionValue; + } +}); + + + test("Type can be inferred from the key of a hasMany relationship", function() { expect(1); run(function(){ @@ -731,7 +753,7 @@ test("Only records of the same type can be added to a monomorphic hasMany relati Ember.RSVP.all([ env.store.find('post', 1), env.store.find('post', 2) ]).then(function(records) { expectAssertion(function() { records[0].get('comments').pushObject(records[1]); - }, /You cannot add 'post' records to this relationship/); + }, /You cannot add 'post' records to the post.comments relationship \(only 'comment' allowed\)/); }); }); }); @@ -764,7 +786,7 @@ test("Only records of the same base type can be added to a polymorphic hasMany r expectAssertion(function() { records.messages.pushObject(records.anotherUser); - }, /You cannot add 'user' records to this relationship/); + }, /You cannot add 'user' records to the user.messages relationship \(only 'message' allowed\)/); }); }); }); From 1e3e3bea1255d153d928ab88d150b4dd9d35ff7a Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 24 Dec 2014 00:55:02 +0100 Subject: [PATCH 0530/2527] Temporarily disable testem-canary --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3e20001b1a0..fbd11a05d31 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ install: script: - npm run-script test - npm run-script testem-beta - - npm run-script testem-canary +# - npm run-script testem-canary after_success: - npm run-script publish-build - "./bin/bower-ember-data-build" From 77e4f82b55930eb9fb2f13cbf58523d5a8971e6a Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Wed, 24 Dec 2014 12:24:16 +0900 Subject: [PATCH 0531/2527] [DOC] Stop using deprecated `each` helper syntax The `each` helper with context switching is deprecated in Ember.js 1.9. see: http://emberjs.com/guides/deprecations/#toc_more-consistent-handlebars-scope --- packages/ember-data/lib/system/model/errors.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index 3ebf5c3ad3f..ddbbbe9c827 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -54,23 +54,23 @@ import { or using the `messages` property to get an array of all errors. ```handlebars - {{#each errors.messages}} + {{#each message in errors.messages}}
      {{message}}
      {{/each}} - {{#each errors.username}} + {{#each error in errors.username}}
      - {{message}} + {{error.message}}
      {{/each}} - {{#each errors.email}} + {{#each error in errors.email}}
      - {{message}} + {{error.message}}
      {{/each}} ``` @@ -149,7 +149,7 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { record. This is useful for displaying all errors to the user. ```handlebars - {{#each errors.messages}} + {{#each message in errors.messages}}
      {{message}}
      From c2c61784ad977f2f347bfc3d3ac258e1e8de6a74 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 24 Dec 2014 13:41:38 -0700 Subject: [PATCH 0532/2527] update gitignore to ignore npm-debug.log --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b756ef85947..656b4ab8091 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ docs/node_modules/ node_modules/ bower_components/ .metadata_never_index +npm-debug.log From e358af16360182d5b6b38250152c0d469ed3fd56 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 24 Dec 2014 17:48:16 -0700 Subject: [PATCH 0533/2527] fix canary build for recent Ember.Container refactors refactors: https://github.com/emberjs/ember.js/pull/9981 --- .travis.yml | 2 +- .../tests/unit/store/create_record_test.js | 9 +++------ .../tests/unit/store/model_for_test.js | 12 ++++++------ tests/ember_configuration.js | 16 ++++++++++++++++ 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index fbd11a05d31..3e20001b1a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ install: script: - npm run-script test - npm run-script testem-beta -# - npm run-script testem-canary + - npm run-script testem-canary after_success: - npm run-script publish-build - "./bin/bower-ember-data-build" diff --git a/packages/ember-data/tests/unit/store/create_record_test.js b/packages/ember-data/tests/unit/store/create_record_test.js index a51b8d62a4c..a4bc2297175 100644 --- a/packages/ember-data/tests/unit/store/create_record_test.js +++ b/packages/ember-data/tests/unit/store/create_record_test.js @@ -28,12 +28,11 @@ module("unit/store/createRecord - Store with models by dash", { }); store = env.store; container = env.container; - container.normalize = function(key){ + env.replaceContainerNormalize(function(key){ return Ember.String.dasherize(key); - }; + }); } }); - test("creating a record by camel-case string finds the model", function(){ var attributes = { foo: 'bar' }; var record; @@ -65,9 +64,7 @@ module("unit/store/createRecord - Store with models by camelCase", { }); store = env.store; container = env.container; - container.normalize = function(key){ - return Ember.String.camelize(key); - }; + env.replaceContainerNormalize(Ember.String.camelize); } }); diff --git a/packages/ember-data/tests/unit/store/model_for_test.js b/packages/ember-data/tests/unit/store/model_for_test.js index 9f09e7fb53f..6a1d7bc1710 100644 --- a/packages/ember-data/tests/unit/store/model_for_test.js +++ b/packages/ember-data/tests/unit/store/model_for_test.js @@ -4,13 +4,15 @@ var camelize = Ember.String.camelize, dasherize = Ember.String.dasherize; var run = Ember.run; +var env; module("unit/store/model_for - DS.Store#modelFor", { setup: function() { - store = createStore({ + env = setupStore({ blogPost: DS.Model.extend(), "blog-post": DS.Model.extend() }); + store = env.store; container = store.container; }, @@ -23,18 +25,16 @@ module("unit/store/model_for - DS.Store#modelFor", { }); test("when fetching factory from string, sets a normalized key as typeKey", function() { - container.normalize = function(fullName){ - return camelize(fullName); - }; + env.replaceContainerNormalize(camelize); equal(container.normalize('some.post'), 'somePost', 'precond - container camelizes'); equal(store.modelFor("blog.post").typeKey, "blogPost", "typeKey is normalized to camelCase"); }); test("when fetching factory from string and dashing normalizer, sets a normalized key as typeKey", function() { - container.normalize = function(fullName){ + env.replaceContainerNormalize(function(fullName){ return dasherize(camelize(fullName)); - }; + }); equal(container.normalize('some.post'), 'some-post', 'precond - container dasherizes'); equal(store.modelFor("blog.post").typeKey, "blogPost", "typeKey is normalized to camelCase"); diff --git a/tests/ember_configuration.js b/tests/ember_configuration.js index 242c28ff55c..a5e962dd66e 100644 --- a/tests/ember_configuration.js +++ b/tests/ember_configuration.js @@ -52,6 +52,22 @@ var container = env.container = new Ember.Container(); + // We have to currently work around some container refactors until + // https://github.com/emberjs/ember.js/pull/9981 is on the stable release + // of ember + if (typeof Ember.Registry !== 'undefined') { + var registry = new Ember.Registry(); + container._registry = registry; + env.registry = registry; + } + env.replaceContainerNormalize = function replaceContainerNormalize(fn) { + if (env.registry) { + env.registry.normalize = fn; + } else { + env.container.normalize = fn; + } + } + var adapter = env.adapter = (options.adapter || DS.Adapter); delete options.adapter; From 28859c4b25a0bafcb061c1615b577850d4173c7f Mon Sep 17 00:00:00 2001 From: Dave Shifflett Date: Wed, 24 Dec 2014 21:49:06 -0600 Subject: [PATCH 0534/2527] Fix references to buildURL in documentation The correct naming for this is `buildURL` rather than `buildUrl`. --- CHANGELOG.md | 2 +- packages/ember-data/lib/adapters/rest_adapter.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e86558eeb5f..60cec69a968 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -150,7 +150,7 @@ var Post = DS.Model.extend({ * Expand the package configuration filename glob declaration in `Brocfile.js` into the affected filenames, as the `broccoli-string-replace` plugin doesn't support globbing * Clear inverseRecord for deleted belongsTo properly * Warn when pushing unknown payload keys into the store -* RestAdapter's buildUrl from delete can ask for record's relations. closes #534 +* RESTAdapter's buildURL from delete can ask for record's relations. closes #534 * Ensure production builds do not use require internally. * [DOCS] InvalidError docs missing quote * Use the model rollback and not state machine for created records rollback diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index a6df6162e06..27ce7492f7d 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -208,7 +208,7 @@ export default Adapter.extend({ will also send a request to: `GET /comments?ids[]=1&ids[]=2` - Note: Requests coalescing rely on URL building strategy. So if you override `buildUrl` in your app + Note: Requests coalescing rely on URL building strategy. So if you override `buildURL` in your app `groupRecordsForFindMany` more likely should be overridden as well in order for coalescing to work. @property coalesceFindRequests From 69a937f820326621a1f5fb90482d8f1fbdf99e84 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 25 Dec 2014 09:56:56 -0700 Subject: [PATCH 0535/2527] changelog prep for beta.13 --- CHANGELOG.md | 118 +++++++++++------- .../blueprints/ember-data/index.js | 2 +- 2 files changed, 74 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60cec69a968..94a3a0121a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Master +### Ember Data 1.0.0-beta.13 (December 25, 2014) + #### Breaking Changes ##### `store.update()` has been deprecated @@ -11,9 +13,9 @@ handling partial payloads: ```javascript var post = store.push('post', { - id: 1, - title: 'Ember.js is fantastic', - author: 'Tomster' +id: 1, +title: 'Ember.js is fantastic', +author: 'Tomster' }); post.get('title'); // => 'Ember.js is fantastic' @@ -33,11 +35,11 @@ send back null values in the payload: ```javascript { - "person": { - "firstName": null, - "lastName": null - "role": "Computer Science Pioneer" - } +"person": { +"firstName": null, +"lastName": null +"role": "Computer Science Pioneer" +} } ``` @@ -48,16 +50,16 @@ serializer and do the logic yourself: // app/serializers/person.js // or App.PersonSerializer if you aren't using Ember CLI export default DS.RESTSerializer.extend({ - normalize: function(type, hash, prop) { - hash = this._super(type, hash, prop); - if (!hash.hasOwnProperty('firstName')){ - hash.firstName = null; - } - if (!hash.hasOwnProperty('lastName')){ - hash.lastName = null; - } - return hash; - } +normalize: function(type, hash, prop) { +hash = this._super(type, hash, prop); +if (!hash.hasOwnProperty('firstName')){ +hash.firstName = null; +} +if (!hash.hasOwnProperty('lastName')){ +hash.lastName = null; +} +return hash; +} }); ``` @@ -67,22 +69,49 @@ Or if you want to restore the old behavior for all of your models: // app/serializers/application.js // or App.ApplicationSerializer export default DS.RESTSerializer.extend({ - normalize: function(type, hash, prop) { - hash = this._super(type, hash, prop); - type.eachAttribute(function(key) { - if (!hash.hasOwnProperty(key)) { - hash[key] = null; - } - }, this); - return hash; - } +normalize: function(type, hash, prop) { +hash = this._super(type, hash, prop); +type.eachAttribute(function(key) { +if (!hash.hasOwnProperty(key)) { +hash[key] = null; +} +}, this); +return hash; +} }); ``` +#### Changes + +* Fix references to buildURL in documentation +* fix canary build for recent Ember.Container refactors +* [DOC] Stop using deprecated `each` helper syntax +* Work around type check issues with MODEL_FACTORY_INJECTIONS. +* [DOC] Add page for `DS.PromiseManyArray` +* [DOC] Fix markup for AcriveModelAdapter +* Add Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS option +* Fixed model rollback in the case where an attribute is not assigned so that it rolls back to unassigned instead of cached value. Added a supporting unit test. +* Fix array change notification in many arrays +* Use Ember.create and Ember.EnumerableUtils for relationships +* Backport pushing non async relationship as a link +* Backport relationship.proto.clear bugfix +* Schedule relationship normalization and split paths for canonical/client relationship updates +* fix DS.Errors#errorsFor documentation +* add test about model's attributes dirtiness +* Include build instructions in the readme +* Clarify that `store.fetch` documentation. +* Document and explicitely test specifying relationships type is optional +* Warn when pushing in a relationship as a link and its not an async relationship +* Removed unused notify on 'data' property +* fix Relationship.proto.clear bug +* Remove metaForType()/metadataFor() ambiguousness +* [Bugfix] promiseHasMany.reload() should return another promiseHasMany +* [Feature thrownError] tag errorThrown from jQuery onto the jqXHR like ic-ajax does. +* Cache relationships meta in production +* Deprecate store.update() ### Ember Data 1.0.0-beta.12 (November 25, 2014) -#### Breaking Changes ##### Internet Explorer 8 Requires Ember 1.8 @@ -115,9 +144,9 @@ model's attributes. This means that the following code: ```javascript var Post = DS.Model.extend({ - doSomethingWhenDataChanges: function(){ - // do the work - }.property('data') +doSomethingWhenDataChanges: function(){ +// do the work +}.property('data') }); ``` @@ -126,11 +155,11 @@ would with any `Ember.Object`: ```javascript var Post = DS.Model.extend({ - name: DS.attr(), - date: DS.attr(), - doSomethingWhenDataChanges: function(){ - // do the work - }.property('name', 'date') +name: DS.attr(), +date: DS.attr(), +doSomethingWhenDataChanges: function(){ +// do the work +}.property('name', 'date') }); ``` @@ -436,7 +465,6 @@ correctly will need a shim for Object.create. * [BUGFIX] missing return statement in RecordArray#update * Fixes a small typo in DS.Store deleteRecord docs * Setting a property to undefined on a new record should not transition the record to root.deleted.saved -* Revert "Merge pull request #1652 from abuiles/camelize-in-pathForType" * Don't assume that factory.typeKey is always camelized. * Normalize typeNames when comparing against typeKey. * Force underscore after decamelizing typeKey. @@ -481,7 +509,7 @@ correctly will need a shim for Object.create. ### Ember Data 1.0.0-beta.3 _(September 28, 2013)_ * Add `normalizePayload` to `RESTAdapter` for payload normalization that is the same - across all requests. +across all requests. * Add `record.toJSON()` * Normalize relationships on payloads returned from saves. * Rename `rootForType` to `pathForType` in `RESTAdapter` @@ -490,14 +518,14 @@ correctly will need a shim for Object.create. * Add `typeFromRoot` * Allow retries of records that were not found * Add `pushPayload` for pushing out of band records that still go through the - appropriate normalization logic. +appropriate normalization logic. * Add an API for registering custom pluralization rules (see - 4df69d14ef2677977f520986070a2fdc45664008) +4df69d14ef2677977f520986070a2fdc45664008) * Add `unloadAll` on store * Infer the type of hasMany and belongsTo relationships by inflecting the key * Polymorphic relationship improvements * ActiveModel Adapter for working with Rails-like servers, not included by default - in the Ember Data build but available separately. +in the Ember Data build but available separately. * `store.metadataFor(type)` to get metadata provided by `findAll`. * `RecordArray#save` * `store.getById` returns null if a record isn't found @@ -506,7 +534,7 @@ correctly will need a shim for Object.create. * A number of `links`-related fixes * Ensure that `didLoad` fires when a record is created for the first time * Support primary and sideloaded data of the same type to be returned from array - lookups (via `posts` and `_posts`). +lookups (via `posts` and `_posts`). * IE8 fixes * Add `record.changedAttributes()` * Properly handle absolute and relative links in the `RESTAdapter` @@ -528,9 +556,9 @@ correctly will need a shim for Object.create. * RESTAdapter now has `rootForType` to convert a type into the root * `store.update` to update some, but not all attributes * Thanks to Paul Chavard, Toran Billups, Bradley Priest, Kasper Tidemann, Yann Mainier, - Dali Zheng, Jeremy Green, Robert Jackson, Joe Bartels, Alexandre de Oliveria, - Floren Jaby, Gordon Hempton, Ivan Vanderbyl, Johannes Würbach, Márcio Júnior, - Nick Ragaz, Ricardo Mendes, Ryunosuke SATO, Sylvain Mina, and ssured +Dali Zheng, Jeremy Green, Robert Jackson, Joe Bartels, Alexandre de Oliveria, +Floren Jaby, Gordon Hempton, Ivan Vanderbyl, Johannes Würbach, Márcio Júnior, +Nick Ragaz, Ricardo Mendes, Ryunosuke SATO, Sylvain Mina, and ssured ### Ember Data 1.0.0-beta.1 _(September 01, 2013)_ diff --git a/lib/ember-addon/blueprints/ember-data/index.js b/lib/ember-addon/blueprints/ember-data/index.js index 48eed22e1f8..0a5ed9f4539 100644 --- a/lib/ember-addon/blueprints/ember-data/index.js +++ b/lib/ember-addon/blueprints/ember-data/index.js @@ -8,6 +8,6 @@ module.exports = { }, afterInstall: function() { - return this.addBowerPackageToProject('ember-data', '1.0.0-beta.12'); + return this.addBowerPackageToProject('ember-data', '1.0.0-beta.13'); } }; From 40e26f69ad13090cd44b6d5f5e261de2a52bd6fb Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 25 Dec 2014 14:26:34 -0700 Subject: [PATCH 0536/2527] ie8 fixes --- bower.json | 2 +- .../lib/system/record_arrays/record_array.js | 5 ++-- .../tests/unit/store/metadata_for_test.js | 24 ++++++++++++++----- tests/index.html | 7 +----- tests/qunit_configuration.js | 2 +- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/bower.json b/bower.json index 35214601c4f..49726752b60 100644 --- a/bower.json +++ b/bower.json @@ -5,7 +5,7 @@ "ember": "~1.9.0" }, "devDependencies": { - "qunit": "~1.13.0", + "qunit": "~1.16.0", "jquery": "~1.10.x", "handlebars": ">= 2.0.0 < 3.0.0", "loader.js": "~1.0.0", diff --git a/packages/ember-data/lib/system/record_arrays/record_array.js b/packages/ember-data/lib/system/record_arrays/record_array.js index 4323ca94288..f34fd4e8a7e 100644 --- a/packages/ember-data/lib/system/record_arrays/record_array.js +++ b/packages/ember-data/lib/system/record_arrays/record_array.js @@ -4,6 +4,7 @@ import { PromiseArray } from "ember-data/system/promise_proxies"; var get = Ember.get; +var set = Ember.set; /** A record array is an array that contains records of a certain type. The record @@ -146,8 +147,6 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { pushRecord: function(record) { get(this, 'content').pushObject(record); }, - - /** Removes a record to the `RecordArray`. @@ -211,6 +210,8 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { willDestroy: function(){ this._unregisterFromManager(); this._dissociateFromOwnRecords(); + set(this, 'content', undefined); + delete this.content; this._super(); } }); diff --git a/packages/ember-data/tests/unit/store/metadata_for_test.js b/packages/ember-data/tests/unit/store/metadata_for_test.js index 0e84e365af3..01f993a3052 100644 --- a/packages/ember-data/tests/unit/store/metadata_for_test.js +++ b/packages/ember-data/tests/unit/store/metadata_for_test.js @@ -26,16 +26,28 @@ test("metaForType should be deprecated", function() { }); test("metadataFor and setMetadataFor should return and set correct metadata", function() { - expect(4); + expect(7); + var keys = Ember.keys; + function metadataKeys(type){ + return keys(store.metadataFor(type)); + } + + // Currently not using QUnit.deepEqual due to the way deepEqual + // comparing __proto__. In its check to see if an object has + // no proto, it checks strict equality on null instead of null or undefined. - deepEqual(store.metadataFor('post'), {}, 'metadata for post is initially empty'); + deepEqual(metadataKeys('post'), [], 'Metadata for post is initially empty'); store.setMetadataFor('post', { foo: 'bar' }); - deepEqual(store.metadataFor('post'), { foo: 'bar' }, 'metadata for post contains foo:bar'); + deepEqual(metadataKeys('post'), ['foo'], 'metadata for post contains foo:bar'); + equal(store.metadataFor('post').foo, 'bar'); store.setMetadataFor('post', { hello: 'world' }); - deepEqual(store.metadataFor('post'), { foo: 'bar', hello: 'world' }, 'metadata for post contains both foo:bar and hello:world'); - deepEqual(store.metadataFor('comment'), {}, 'metadata for comment is empty'); -}); \ No newline at end of file + deepEqual(metadataKeys('post'), ['foo', 'hello']); + equal(store.metadataFor('post').foo, 'bar', 'keeps original metadata'); + equal(store.metadataFor('post').hello, 'world', 'merges new metadata'); + + deepEqual(metadataKeys('comment'), [], 'metadata for comment is empty'); +}); diff --git a/tests/index.html b/tests/index.html index 4fbc867f7e0..10c4f50e3c7 100644 --- a/tests/index.html +++ b/tests/index.html @@ -43,12 +43,7 @@ diff --git a/tests/qunit_configuration.js b/tests/qunit_configuration.js index ff7c2f10f24..f0cfa53a705 100644 --- a/tests/qunit_configuration.js +++ b/tests/qunit_configuration.js @@ -95,7 +95,7 @@ // raises is deprecated, but we likely want to keep it around for our es3 // test runs. // taken from emberjs/ember-dev here: http://git.io/sQhl3A - QUnit.constructor.prototype.raises = QUnit['throws']; + QUnit.raises = QUnit['throws']; window.raises = QUnit['throws']; QUnit.jsDump.parsers.emberObject = function(obj) { From 26fa2476b5f65d63790a053e449c9ecfafd46131 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 25 Dec 2014 14:33:33 -0700 Subject: [PATCH 0537/2527] release v1.0.0-beta.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b1b97c0a0a..44b0e2cd63f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.13-canary", + "version": "1.0.0-beta.13", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", From 2a09bfaf8c379184d16bd4757c713d48ced3f364 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 25 Dec 2014 14:37:35 -0700 Subject: [PATCH 0538/2527] fix changelog indentation --- CHANGELOG.md | 54 ++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94a3a0121a4..1a318afd2e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,9 @@ handling partial payloads: ```javascript var post = store.push('post', { -id: 1, -title: 'Ember.js is fantastic', -author: 'Tomster' + id: 1, + title: 'Ember.js is fantastic', + author: 'Tomster' }); post.get('title'); // => 'Ember.js is fantastic' @@ -35,11 +35,11 @@ send back null values in the payload: ```javascript { -"person": { -"firstName": null, -"lastName": null -"role": "Computer Science Pioneer" -} + "person": { + "firstName": null, + "lastName": null + "role": "Computer Science Pioneer" + } } ``` @@ -50,16 +50,16 @@ serializer and do the logic yourself: // app/serializers/person.js // or App.PersonSerializer if you aren't using Ember CLI export default DS.RESTSerializer.extend({ -normalize: function(type, hash, prop) { -hash = this._super(type, hash, prop); -if (!hash.hasOwnProperty('firstName')){ -hash.firstName = null; -} -if (!hash.hasOwnProperty('lastName')){ -hash.lastName = null; -} -return hash; -} + normalize: function(type, hash, prop) { + hash = this._super(type, hash, prop); + if (!hash.hasOwnProperty('firstName')){ + hash.firstName = null; + } + if (!hash.hasOwnProperty('lastName')){ + hash.lastName = null; + } + return hash; + } }); ``` @@ -69,15 +69,15 @@ Or if you want to restore the old behavior for all of your models: // app/serializers/application.js // or App.ApplicationSerializer export default DS.RESTSerializer.extend({ -normalize: function(type, hash, prop) { -hash = this._super(type, hash, prop); -type.eachAttribute(function(key) { -if (!hash.hasOwnProperty(key)) { -hash[key] = null; -} -}, this); -return hash; -} + normalize: function(type, hash, prop) { + hash = this._super(type, hash, prop); + type.eachAttribute(function(key) { + if (!hash.hasOwnProperty(key)) { + hash[key] = null; + } + }, this); + return hash; + } }); ``` From 8f21c1a0e3a745c6685005006911982e24187b63 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 25 Dec 2014 14:40:27 -0700 Subject: [PATCH 0539/2527] MOAR indentation fixes --- CHANGELOG.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a318afd2e4..1e02afbcb02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,9 +36,9 @@ send back null values in the payload: ```javascript { "person": { - "firstName": null, - "lastName": null - "role": "Computer Science Pioneer" + "firstName": null, + "lastName": null + "role": "Computer Science Pioneer" } } ``` @@ -51,14 +51,14 @@ serializer and do the logic yourself: // or App.PersonSerializer if you aren't using Ember CLI export default DS.RESTSerializer.extend({ normalize: function(type, hash, prop) { - hash = this._super(type, hash, prop); - if (!hash.hasOwnProperty('firstName')){ - hash.firstName = null; - } - if (!hash.hasOwnProperty('lastName')){ - hash.lastName = null; - } - return hash; + hash = this._super(type, hash, prop); + if (!hash.hasOwnProperty('firstName')){ + hash.firstName = null; + } + if (!hash.hasOwnProperty('lastName')){ + hash.lastName = null; + } + return hash; } }); ``` @@ -70,13 +70,13 @@ Or if you want to restore the old behavior for all of your models: // or App.ApplicationSerializer export default DS.RESTSerializer.extend({ normalize: function(type, hash, prop) { - hash = this._super(type, hash, prop); - type.eachAttribute(function(key) { - if (!hash.hasOwnProperty(key)) { - hash[key] = null; - } - }, this); - return hash; + hash = this._super(type, hash, prop); + type.eachAttribute(function(key) { + if (!hash.hasOwnProperty(key)) { + hash[key] = null; + } + }, this); + return hash; } }); ``` From cf706ac96f68c80947894368d6c5487f1b54456f Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 25 Dec 2014 14:40:58 -0700 Subject: [PATCH 0540/2527] one more round of indentation fixes i am sorry :( --- CHANGELOG.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e02afbcb02..81973a2426b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -155,11 +155,11 @@ would with any `Ember.Object`: ```javascript var Post = DS.Model.extend({ -name: DS.attr(), -date: DS.attr(), -doSomethingWhenDataChanges: function(){ -// do the work -}.property('name', 'date') + name: DS.attr(), + date: DS.attr(), + doSomethingWhenDataChanges: function(){ + // do the work + }.property('name', 'date') }); ``` From 360df7c87d777fc67446829ff5ad0026aa8f8be6 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Thu, 25 Dec 2014 22:57:25 +0100 Subject: [PATCH 0541/2527] Minor CHANGELOG indentation fix --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81973a2426b..5b271d2ec70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -144,9 +144,9 @@ model's attributes. This means that the following code: ```javascript var Post = DS.Model.extend({ -doSomethingWhenDataChanges: function(){ -// do the work -}.property('data') + doSomethingWhenDataChanges: function(){ + // do the work + }.property('data') }); ``` @@ -158,7 +158,7 @@ var Post = DS.Model.extend({ name: DS.attr(), date: DS.attr(), doSomethingWhenDataChanges: function(){ - // do the work + // do the work }.property('name', 'date') }); ``` From db9d6d954f716f040aa909749d8fb19a33ccf4ad Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 25 Dec 2014 16:06:48 -0700 Subject: [PATCH 0542/2527] remove unnecessary delete statement --- packages/ember-data/lib/system/record_arrays/record_array.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ember-data/lib/system/record_arrays/record_array.js b/packages/ember-data/lib/system/record_arrays/record_array.js index f34fd4e8a7e..985379d0562 100644 --- a/packages/ember-data/lib/system/record_arrays/record_array.js +++ b/packages/ember-data/lib/system/record_arrays/record_array.js @@ -211,7 +211,6 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { this._unregisterFromManager(); this._dissociateFromOwnRecords(); set(this, 'content', undefined); - delete this.content; this._super(); } }); From 2b73a2b5239c25014ac0065aca020a51a2880a94 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 25 Dec 2014 16:09:05 -0700 Subject: [PATCH 0543/2527] release 0.3.14 due to npm constraints --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 44b0e2cd63f..dd63bbe1b1d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.13", + "version": "1.0.0-beta.14", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", From e7d30957a88f0c8a4ec9b0e5111791c4373f0df9 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 25 Dec 2014 16:09:28 -0700 Subject: [PATCH 0544/2527] prevent accidental publishes without built assets --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dd63bbe1b1d..b4f7321c981 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "lib/ember-addon" ], "scripts": { - "prepublish": "bower install", + "prepublish": "npm run-script dist", "start": "ember serve", "dist": "ember build --environment=production", "test": "testem -R dot ci", From 457f7cd828a7daa0bde1ecbf2f5e079ca9806a33 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 25 Dec 2014 16:10:45 -0700 Subject: [PATCH 0545/2527] fix blueprint for beta.14 --- lib/ember-addon/blueprints/ember-data/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ember-addon/blueprints/ember-data/index.js b/lib/ember-addon/blueprints/ember-data/index.js index 0a5ed9f4539..10eaa4953ac 100644 --- a/lib/ember-addon/blueprints/ember-data/index.js +++ b/lib/ember-addon/blueprints/ember-data/index.js @@ -8,6 +8,6 @@ module.exports = { }, afterInstall: function() { - return this.addBowerPackageToProject('ember-data', '1.0.0-beta.13'); + return this.addBowerPackageToProject('ember-data', '1.0.0-beta.14'); } }; From e9f89ef05cfdb6489f2fc5e5caf210d5ceb1fb29 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 25 Dec 2014 16:12:52 -0700 Subject: [PATCH 0546/2527] add bower install back to prepublish --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b4f7321c981..f969c234ea2 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "lib/ember-addon" ], "scripts": { - "prepublish": "npm run-script dist", + "prepublish": "bower install && npm run-script dist", "start": "ember serve", "dist": "ember build --environment=production", "test": "testem -R dot ci", From 4e50af719530446204e41cacce42f988ac088cd3 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 25 Dec 2014 16:28:28 -0700 Subject: [PATCH 0547/2527] post-release version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f969c234ea2..f133d3d7a71 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.14", + "version": "1.0.0-beta.15-canary", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", From 96a14bf5e75986299546ea8d3c36d11b07d9f5db Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Fri, 26 Dec 2014 11:54:05 +0900 Subject: [PATCH 0548/2527] Fix to replace DS.VERSION --- Brocfile.js | 6 +++--- generators/license.js | 2 +- lib/amd-build.js | 2 +- package.json | 2 +- packages/ember-data/lib/core.js | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Brocfile.js b/Brocfile.js index c4f02b70cf3..4a133477155 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -15,7 +15,7 @@ var jshint = require('broccoli-jshint'); var defeatureify = require('broccoli-defeatureify'); var version = require('git-repo-version')(10); var yuidoc = require('broccoli-yuidoc'); -var replace = require('broccoli-string-replace'); +var replace = require('broccoli-replace'); var path = require('path'); function minify(tree, name){ @@ -145,10 +145,10 @@ var configurationFiles = pickFiles('config/package_manager_files', { function versionStamp(tree){ return replace(tree, { files: ['**/*'], - pattern: { + patterns: [{ match: /VERSION_STRING_PLACEHOLDER/g, replacement: version - } + }] }); } diff --git a/generators/license.js b/generators/license.js index 8e4ea61b311..21dff7fa06c 100644 --- a/generators/license.js +++ b/generators/license.js @@ -3,5 +3,5 @@ * @copyright Copyright 2011-2014 Tilde Inc. and contributors. * Portions Copyright 2011 LivingSocial Inc. * @license Licensed under MIT license (see license.js) - * @version <%= versionStamp %> + * @version VERSION_STRING_PLACEHOLDER */ diff --git a/lib/amd-build.js b/lib/amd-build.js index 43fbc4e3f80..c8a06d50760 100644 --- a/lib/amd-build.js +++ b/lib/amd-build.js @@ -6,7 +6,7 @@ var PackageResolver = require('es6-module-transpiler-package-resolver'); var AMDFormatter = require('es6-module-transpiler-amd-formatter'); var fileCreator = require('broccoli-file-creator'); var merge = require('broccoli-merge-trees'); -var replace = require('broccoli-string-replace'); +var replace = require('broccoli-replace'); function amdES6Package(packages) { var es6Build = es6(packages, { diff --git a/package.json b/package.json index f133d3d7a71..1829897b2a9 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "broccoli-merge-trees": "^0.1.4", "broccoli-render-template": "0.0.3", "broccoli-static-compiler": "^0.2.1", - "broccoli-string-replace": "0.0.2", + "broccoli-replace": "~0.2.0", "broccoli-uglify-js": "^0.1.3", "broccoli-wrap": "0.0.2", "broccoli-yuidoc": "^1.3.0", diff --git a/packages/ember-data/lib/core.js b/packages/ember-data/lib/core.js index bf17945ff1b..027a4663ac9 100644 --- a/packages/ember-data/lib/core.js +++ b/packages/ember-data/lib/core.js @@ -12,12 +12,12 @@ /** @property VERSION @type String - @default '<%= versionStamp %>' + @default 'VERSION_STRING_PLACEHOLDER' @static */ /*jshint -W079 */ var DS = Ember.Namespace.create({ - VERSION: '<%= versionStamp %>' + VERSION: 'VERSION_STRING_PLACEHOLDER' }); if (Ember.libraries) { From b459f06961cd6953435dfb3f50149cd36e7ceeef Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Sun, 28 Dec 2014 22:54:52 +0100 Subject: [PATCH 0549/2527] Deprecate addRecord/removeRecord for ManyArray --- .../lib/system/record_arrays/many_array.js | 20 ++++++ .../ember-data/tests/unit/many_array_test.js | 68 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 packages/ember-data/tests/unit/many_array_test.js diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 6797de9d7e9..a77bb65af4b 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -202,5 +202,25 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { this.pushObject(record); return record; + }, + + /** + @method addRecord + @param {DS.Model} record + @deprecated Use `addObject()` instead + */ + addRecord: function(record) { + Ember.deprecate('Using manyArray.addRecord() has been deprecated. You should use manyArray.addObject() instead.'); + this.addObject(record); + }, + + /** + @method removeRecord + @param {DS.Model} record + @deprecated Use `removeObject()` instead + */ + removeRecord: function(record) { + Ember.deprecate('Using manyArray.removeRecord() has been deprecated. You should use manyArray.removeObject() instead.'); + this.removeObject(record); } }); diff --git a/packages/ember-data/tests/unit/many_array_test.js b/packages/ember-data/tests/unit/many_array_test.js new file mode 100644 index 00000000000..689e5819471 --- /dev/null +++ b/packages/ember-data/tests/unit/many_array_test.js @@ -0,0 +1,68 @@ +var env, store; +var attr = DS.attr; +var hasMany = DS.hasMany; +var belongsTo = DS.belongsTo; +var run = Ember.run; + +module("unit/many_array - DS.ManyArray", { + setup: function() { + var Post = DS.Model.extend({ + title: attr('string'), + tags: hasMany('tag') + }); + Post.toString = function() { + return 'Post'; + }; + + var Tag = DS.Model.extend({ + name: attr('string'), + post: belongsTo('post') + }); + Tag.toString = function() { + return 'Tag'; + }; + + env = setupStore({ + post: Post, + tag: Tag + }); + store = env.store; + }, + + teardown: function() { + run(function() { + store.destroy(); + }); + } +}); + +test("manyArray.addRecord() has been deprecated", function() { + expect(3); + + run(function() { + var tag = store.push('tag', { id: 1, name: 'Ember.js' }); + var post = store.push('post', { id: 2, title: 'A framework for creating ambitious web applications' }); + var tags = post.get('tags'); + + equal(tags.length, 0, 'there should not be any tags'); + expectDeprecation(function() { + tags.addRecord(tag); + }); + equal(tags.length, 1, 'there should be 1 tag'); + }); +}); + +test("manyArray.removeRecord() has been deprecated", function() { + expect(3); + run(function() { + var tag = store.push('tag', { id: 1, name: 'Ember.js' }); + var post = store.push('post', { id: 2, title: 'A framework for creating ambitious web applications', tags: [1] }); + var tags = post.get('tags'); + + equal(tags.length, 1, 'there should be 1 tag'); + expectDeprecation(function() { + tags.removeRecord(tag); + }); + equal(tags.length, 0, 'there should not be any tags'); + }); +}); From 55dabc53ddb113ddd635d20d8fc20b3160bfb50f Mon Sep 17 00:00:00 2001 From: thomassnielsen Date: Mon, 29 Dec 2014 11:54:03 +0100 Subject: [PATCH 0550/2527] Clarify store.find via findAll docs Clarification to fix the confusion in #2552. --- packages/ember-data/lib/system/store.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 12d7765c79c..20a51e1ffef 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -428,7 +428,8 @@ Store = Ember.Object.extend({ This will ask the adapter's `findAll` method to find the records for the given type, and return a promise that will be resolved once the server - returns the values. + returns the values. The promise will resolve into all records of this type + present in the store, even if the server only returns a subset of them. --- From 1868e5ae8f2b79fe5cdf889d1178a6be1963db4e Mon Sep 17 00:00:00 2001 From: Paul Sierks Date: Mon, 29 Dec 2014 09:58:28 -0600 Subject: [PATCH 0551/2527] generateIdForRecord gets type & object properties passed to it --- packages/ember-data/lib/system/store.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 12d7765c79c..ceeacb4253d 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -289,7 +289,7 @@ Store = Ember.Object.extend({ // to avoid conflicts. if (isNone(properties.id)) { - properties.id = this._generateId(type); + properties.id = this._generateId(type, properties); } // Coerce ID to a string @@ -314,13 +314,14 @@ Store = Ember.Object.extend({ @method _generateId @private @param {String} type + @param {Object} properties from the new record @return {String} if the adapter can generate one, an ID */ - _generateId: function(type) { + _generateId: function(type, properties) { var adapter = this.adapterFor(type); if (adapter && adapter.generateIdForRecord) { - return adapter.generateIdForRecord(this); + return adapter.generateIdForRecord(this, type, properties); } return null; From e664f4f40cca084eb275b4dab5d1ad2a52781b59 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 30 Dec 2014 19:38:22 -0600 Subject: [PATCH 0552/2527] fix version for dropped <= Ember 1.7 support --- config/package_manager_files/bower.json | 2 +- config/package_manager_files/component.json | 2 +- config/package_manager_files/composer.json | 2 +- config/package_manager_files/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/package_manager_files/bower.json b/config/package_manager_files/bower.json index f8e2930c85c..8e6b16ea519 100644 --- a/config/package_manager_files/bower.json +++ b/config/package_manager_files/bower.json @@ -3,7 +3,7 @@ "version": "VERSION_STRING_PLACEHOLDER", "main": "ember-data.js", "dependencies": { - "ember": ">= 1.0.0" + "ember": ">= 1.8.1 < 2.0.0" }, "ignore": [ "**/*_configuration.js", diff --git a/config/package_manager_files/component.json b/config/package_manager_files/component.json index cce479429d1..80b5c718477 100644 --- a/config/package_manager_files/component.json +++ b/config/package_manager_files/component.json @@ -10,7 +10,7 @@ "ember-data.prod.js" ], "dependencies": { - "components/ember": "~1.0" + "components/ember": ">= 1.8.1 < 2.0.0" }, "license": "MIT" } diff --git a/config/package_manager_files/composer.json b/config/package_manager_files/composer.json index 97e914b70ef..48978bdf3bc 100644 --- a/config/package_manager_files/composer.json +++ b/config/package_manager_files/composer.json @@ -4,7 +4,7 @@ "type": "component", "license": "MIT", "require": { - "components/ember": "1.*" + "components/ember": ">= 1.8.1 < 2.0.0" }, "extra": { "component": { diff --git a/config/package_manager_files/package.json b/config/package_manager_files/package.json index cddbc539fbc..4123b810594 100644 --- a/config/package_manager_files/package.json +++ b/config/package_manager_files/package.json @@ -7,6 +7,6 @@ ], "main": "./ember-data.js", "dependencies": { - "ember": "> 1.0.0" + "ember": ">= 1.8.1 < 2.0.0" } } From dd11c08cbd589487a37fc8548beedace8760ce6f Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 30 Dec 2014 19:40:06 -0600 Subject: [PATCH 0553/2527] fixes to load beta 14/14.1 sourcemaps in ember-cli --- lib/ember-addon/blueprints/ember-data/index.js | 2 +- lib/ember-addon/index.js | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/ember-addon/blueprints/ember-data/index.js b/lib/ember-addon/blueprints/ember-data/index.js index 10eaa4953ac..30ef0bebe13 100644 --- a/lib/ember-addon/blueprints/ember-data/index.js +++ b/lib/ember-addon/blueprints/ember-data/index.js @@ -8,6 +8,6 @@ module.exports = { }, afterInstall: function() { - return this.addBowerPackageToProject('ember-data', '1.0.0-beta.14'); + return this.addBowerPackageToProject('ember-data', '1.0.0-beta.14.1'); } }; diff --git a/lib/ember-addon/index.js b/lib/ember-addon/index.js index 9e15c8f3638..8aa40289352 100644 --- a/lib/ember-addon/index.js +++ b/lib/ember-addon/index.js @@ -1,3 +1,4 @@ +/* jshint node: true */ 'use strict'; var path = require('path'); @@ -22,5 +23,9 @@ module.exports = { development: app.bowerDirectory + '/ember-data/ember-data.js', production: app.bowerDirectory + '/ember-data/ember-data.prod.js' }, options); + // Source maps + this.app.import({ + development: app.bowerDirectory + '/ember-data/ember-data.js.map' + }, {destDir: 'assets'}); } -}; \ No newline at end of file +}; From a2c2e4a1b1cda4ca7f7fcb2062d895ab252bd80a Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 30 Dec 2014 20:00:26 -0600 Subject: [PATCH 0554/2527] assert version in dev mode --- config/package_manager_files/composer.json | 2 +- packages/ember-data/lib/main.js | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/config/package_manager_files/composer.json b/config/package_manager_files/composer.json index 48978bdf3bc..e91ef15a8a8 100644 --- a/config/package_manager_files/composer.json +++ b/config/package_manager_files/composer.json @@ -4,7 +4,7 @@ "type": "component", "license": "MIT", "require": { - "components/ember": ">= 1.8.1 < 2.0.0" + "components/ember": "~1.8.1", }, "extra": { "component": { diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index 743774ec2c3..a525c4e17e6 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -1,6 +1,5 @@ /** Ember Data - @module ember-data @main ember-data */ @@ -8,6 +7,14 @@ // support RSVP 2.x via resolve, but prefer RSVP 3.x's Promise.cast Ember.RSVP.Promise.cast = Ember.RSVP.Promise.cast || Ember.RSVP.resolve; +Ember.runInDebug(function(){ + if (Ember.VERSION.match(/1\.[0-7]\./)){ + throw new Ember.Error("Ember Data requires at least Ember 1.8.0, but you have " + + Ember.VERSION + + ". Please upgrade your version of Ember, then upgrade Ember Data"); + } +}); + import "ember-data/system/create"; import DS from "ember-data/core"; import "ember-data/ext/date"; From 24138f20f586abba23513b6d1b8b90aff6571985 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 31 Dec 2014 11:27:53 -0600 Subject: [PATCH 0555/2527] update gemspec to include sourcemap --- ember-data-source.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ember-data-source.gemspec b/ember-data-source.gemspec index 67ad870b5a4..1ace066d833 100644 --- a/ember-data-source.gemspec +++ b/ember-data-source.gemspec @@ -14,5 +14,5 @@ Gem::Specification.new do |gem| gem.add_dependency "ember-source" - gem.files = %w(package.json) + Dir['dist/ember-data*.js', 'lib/ember/data/*.rb'] + gem.files = %w(package.json) + Dir['dist/ember-data*.js', 'dist/ember-data.js.map', 'lib/ember/data/*.rb'] end From 8933ae7f8c7868afdaf9b10b6bc57bee0250ec75 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 31 Dec 2014 11:33:55 -0600 Subject: [PATCH 0556/2527] update changelog for beta14.1 --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b271d2ec70..9b3b84c8843 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,13 @@ ### Master -### Ember Data 1.0.0-beta.13 (December 25, 2014) +### Ember Data 1.0.0-beta.14.1 (December 31, 2014) + +* Replace `<%= versionStamp %>` with actual version stamp. Thanks + @tricknotes! +* Fix sourcemap loading in Ember CLI and Rails. + +### Ember Data 1.0.0-beta.14 (December 25, 2014) #### Breaking Changes From fbb2850068c96d2726514ddbe93cc31a43081575 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 31 Dec 2014 11:49:37 -0600 Subject: [PATCH 0557/2527] pin ember version in gemspec --- ember-data-source.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ember-data-source.gemspec b/ember-data-source.gemspec index 1ace066d833..8d254a6b576 100644 --- a/ember-data-source.gemspec +++ b/ember-data-source.gemspec @@ -12,7 +12,7 @@ Gem::Specification.new do |gem| gem.version = Ember::Data::VERSION gem.license = "MIT" - gem.add_dependency "ember-source" + gem.add_dependency "ember-source", "~> 1.8" gem.files = %w(package.json) + Dir['dist/ember-data*.js', 'dist/ember-data.js.map', 'lib/ember/data/*.rb'] end From 4de331554a02bd1a8f8c3f37cb78f2ea92f2467f Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 31 Dec 2014 17:06:47 -0500 Subject: [PATCH 0558/2527] Remove code that is no longer used from RecordArrayManager --- packages/ember-data/lib/system/model/model.js | 1 - .../lib/system/record_array_manager.js | 22 ------------------- 2 files changed, 23 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index b2cac36b436..b8632ae4ac2 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -46,7 +46,6 @@ function extractPivotName(name) { var Model = Ember.Object.extend(Ember.Evented, { _recordArrays: undefined, _relationships: undefined, - _loadingRecordArrays: undefined, /** If this property is `true` the record is in the `empty` state. Empty is the first state all records enter after they have diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index a8be3a6d69f..a13affd78b1 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -88,17 +88,6 @@ export default Ember.Object.extend({ this.updateRecordArray(array, filter, type, record); }, this); - // loop through all manyArrays containing an unloaded copy of this - // clientId and notify them that the record was loaded. - var manyArrays = record._loadingRecordArrays; - - if (manyArrays) { - for (var i=0, l=manyArrays.length; i Date: Wed, 31 Dec 2014 16:16:17 -0600 Subject: [PATCH 0559/2527] remove old polyfills for Ember <= 1.7.1 --- .jshintrc | 1 + packages/ember-data/lib/main.js | 1 - packages/ember-data/lib/system/create.js | 9 --- packages/ember-data/lib/system/map.js | 94 +++--------------------- 4 files changed, 11 insertions(+), 94 deletions(-) delete mode 100644 packages/ember-data/lib/system/create.js diff --git a/.jshintrc b/.jshintrc index c6ef978db67..716aa3cea24 100644 --- a/.jshintrc +++ b/.jshintrc @@ -3,6 +3,7 @@ "console", "requireModule", "-Promise", + "-Map", "Ember", "DS", "Handlebars", diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index a525c4e17e6..16647f47afe 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -15,7 +15,6 @@ Ember.runInDebug(function(){ } }); -import "ember-data/system/create"; import DS from "ember-data/core"; import "ember-data/ext/date"; diff --git a/packages/ember-data/lib/system/create.js b/packages/ember-data/lib/system/create.js deleted file mode 100644 index 5582b7f46be..00000000000 --- a/packages/ember-data/lib/system/create.js +++ /dev/null @@ -1,9 +0,0 @@ -/* - Detect if the user has a correct Object.create shim. - Ember has provided this for a long time but has had an incorrect shim before 1.8 - TODO: Remove for Ember Data 1.0. -*/ -var object = Ember.create(null); -if (object.toString !== undefined && Ember.keys(Ember.create({}))[0] === '__proto__'){ - throw new Error("Ember Data requires a correct Object.create shim. You should upgrade to Ember >= 1.8 which provides one for you. If you are using ES5-shim, you should try removing that after upgrading Ember."); -} diff --git a/packages/ember-data/lib/system/map.js b/packages/ember-data/lib/system/map.js index 7a86249e0dc..a73f90ee86f 100644 --- a/packages/ember-data/lib/system/map.js +++ b/packages/ember-data/lib/system/map.js @@ -1,88 +1,14 @@ -/** - * Polyfill Ember.Map behavior for Ember <= 1.7 - * This can probably be removed before 1.0 final +/* + The Map/MapWithDefault/OrderedSet code has been in flux as we try + to catch up with ES6. This is difficult as we support multiple + versions of Ember. + This file is currently here in case we have to polyfill ember's code + across a few releases. As ES6 comes to a close we should have a smaller + and smaller gap in implementations between Ember releases. */ -var mapForEach, deleteFn; - -function OrderedSet(){ - Ember.OrderedSet.apply(this, arguments); -} - -function Map() { - Ember.Map.apply(this, arguments); -} - -function MapWithDefault(){ - Ember.MapWithDefault.apply(this, arguments); -} - -var testMap = Ember.Map.create(); -testMap.set('key', 'value'); - -var usesOldBehavior = false; - -testMap.forEach(function(value, key){ - usesOldBehavior = value === 'key' && key === 'value'; -}); - -Map.prototype = Ember.create(Ember.Map.prototype); -MapWithDefault.prototype = Ember.create(Ember.MapWithDefault.prototype); -OrderedSet.prototype = Ember.create(Ember.OrderedSet.prototype); - -OrderedSet.create = function(){ - return new OrderedSet(); -}; - -/** - * returns a function that calls the original - * callback function in the correct order. - * if we are in pre-Ember.1.8 land, Map/MapWithDefault - * forEach calls with key, value, in that order. - * >= 1.8 forEach is called with the order value, key as per - * the ES6 spec. -*/ -function translate(valueKeyOrderedCallback){ - return function(key, value){ - valueKeyOrderedCallback.call(this, value, key); - }; -} - -// old, non ES6 compliant behavior -if (usesOldBehavior){ - mapForEach = function(callback, thisArg){ - this.__super$forEach(translate(callback), thisArg); - }; - - /* alias to remove */ - deleteFn = function(thing){ - this.remove(thing); - }; - - Map.prototype.__super$forEach = Ember.Map.prototype.forEach; - Map.prototype.forEach = mapForEach; - Map.prototype.delete = deleteFn; - - MapWithDefault.prototype.forEach = mapForEach; - MapWithDefault.prototype.__super$forEach = Ember.MapWithDefault.prototype.forEach; - MapWithDefault.prototype.delete = deleteFn; - - OrderedSet.prototype.delete = deleteFn; -} - -MapWithDefault.constructor = MapWithDefault; -Map.constructor = Map; - -MapWithDefault.create = function(options){ - if (options) { - return new MapWithDefault(options); - } else { - return new Map(); - } -}; - -Map.create = function(){ - return new this.constructor(); -}; +var Map = Ember.Map; +var MapWithDefault = Ember.MapWithDefault; +var OrderedSet = Ember.OrderedSet; export default Map; export {Map, MapWithDefault, OrderedSet}; From 7a6a38e7d934c1131663f007868dff5e81f291a0 Mon Sep 17 00:00:00 2001 From: IgorT Date: Thu, 23 Oct 2014 03:22:54 +0300 Subject: [PATCH 0560/2527] Don't refilter .all() and .find() if only properties changed --- packages/ember-data/lib/system/model/model.js | 9 ++++++ .../ember-data/lib/system/model/states.js | 7 +++++ .../lib/system/record_array_manager.js | 18 +++++++++-- .../relationships/state/relationship.js | 2 +- packages/ember-data/lib/system/store.js | 10 ++++-- .../integration/record_array_manager_test.js | 31 +++++++++++++++++-- .../integration/records/delete_record_test.js | 1 + 7 files changed, 69 insertions(+), 9 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index b8632ae4ac2..86a7aca45a2 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -377,6 +377,15 @@ var Model = Ember.Object.extend(Ember.Evented, { return serializer.serialize(this, options); }, + /** + Fired when the record is ready to be interacted with, + that is either loaded from the server or created locally. + + @event ready + */ + ready: function() { + this.store.recordArrayManager.recordWasLoaded(this); + }, /** Fired when the record is loaded from the server. diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index c3615644f3f..57a01a09d43 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -275,6 +275,7 @@ var DirtyState = { rollback: function(record) { record.rollback(); + record.triggerLater('ready'); } }, @@ -342,6 +343,7 @@ var DirtyState = { rolledBack: function(record) { get(record, 'errors').clear(); + record.triggerLater('ready'); }, becameValid: function(record) { @@ -473,11 +475,13 @@ var RootState = { loadedData: function(record) { record.transitionTo('loaded.created.uncommitted'); + record.triggerLater('ready'); }, pushedData: function(record) { record.transitionTo('loaded.saved'); record.triggerLater('didLoad'); + record.triggerLater('ready'); } }, @@ -499,6 +503,7 @@ var RootState = { pushedData: function(record) { record.transitionTo('loaded.saved'); record.triggerLater('didLoad'); + record.triggerLater('ready'); set(record, 'isError', false); }, @@ -618,6 +623,7 @@ var RootState = { rollback: function(record) { record.rollback(); + record.triggerLater('ready'); }, becomeDirty: Ember.K, @@ -625,6 +631,7 @@ var RootState = { rolledBack: function(record) { record.transitionTo('loaded.saved'); + record.triggerLater('ready'); } }, diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index a13affd78b1..1cd983e3b4f 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -78,6 +78,8 @@ export default Ember.Object.extend({ record._recordArrays = null; }, + + //Don't need to update non filtered arrays on simple changes _recordWasChanged: function (record) { var type = record.constructor; var recordArrays = this.filteredRecordArrays.get(type); @@ -85,11 +87,23 @@ export default Ember.Object.extend({ forEach(recordArrays, function(array) { filter = get(array, 'filterFunction'); - this.updateRecordArray(array, filter, type, record); + if (filter) { + this.updateRecordArray(array, filter, type, record); + } }, this); - }, + //Need to update live arrays on loading + recordWasLoaded: function(record) { + var type = record.constructor; + var recordArrays = this.filteredRecordArrays.get(type); + var filter; + + forEach(recordArrays, function(array) { + filter = get(array, 'filterFunction'); + this.updateRecordArray(array, filter, type, record); + }, this); + }, /** Update an individual filter. diff --git a/packages/ember-data/lib/system/relationships/state/relationship.js b/packages/ember-data/lib/system/relationships/state/relationship.js index 1884ca9921b..75a6a327847 100644 --- a/packages/ember-data/lib/system/relationships/state/relationship.js +++ b/packages/ember-data/lib/system/relationships/state/relationship.js @@ -124,7 +124,7 @@ Relationship.prototype = { } record._implicitRelationships[this.inverseKeyForImplicit].addRecord(this.record); } - this.record.updateRecordArrays(); + this.record.updateRecordArraysLater(); } }, diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 20a51e1ffef..cc826539054 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1102,9 +1102,8 @@ Store = Ember.Object.extend({ // ............ /** - If the adapter updates attributes or acknowledges creation - or deletion, the record will notify the store to update its - membership in any filters. + If the adapter updates attributes the record will notify + the store to update its membership in any filters. To avoid thrashing, this method is invoked only once per run loop per record. @@ -1614,6 +1613,11 @@ Store = Ember.Object.extend({ return record; }, + //Called by the state machine to notify the store that the record is ready to be interacted with + recordWasLoaded: function(record) { + this.recordArrayManager.recordWasLoaded(record); + }, + // ............... // . DESTRUCTION . // ............... diff --git a/packages/ember-data/tests/integration/record_array_manager_test.js b/packages/ember-data/tests/integration/record_array_manager_test.js index 77e63cb8779..bc08c6894a4 100644 --- a/packages/ember-data/tests/integration/record_array_manager_test.js +++ b/packages/ember-data/tests/integration/record_array_manager_test.js @@ -25,9 +25,7 @@ module("integration/record_array_manager- destroy", { }); store = env.store; - manager = DS.RecordArrayManager.create({ - store: store - }); + manager = store.recordArrayManager; env.container.register('model:car', Car); env.container.register('model:person', Person); @@ -103,3 +101,30 @@ test("destroying the store correctly cleans everything up", function() { equal(filterdSummary.called.length, 1); equal(adapterPopulatedSummary.called.length, 1); }); + + +test("Should not filter a stor.all() array when a record property is changed", function() { + var car; + + var filterdSummary = tap(store.recordArrayManager, 'updateRecordArray'); + + var allCars = store.all('car'); + + run(function(){ + car = store.push('car', { + id: 1, + make: 'BMC', + model: 'Mini Cooper', + person: 1 + }); + }); + + equal(filterdSummary.called.length, 1); + + run(function(){ + car.set('model', 'Mini'); + }); + + equal(filterdSummary.called.length, 1); + +}); diff --git a/packages/ember-data/tests/integration/records/delete_record_test.js b/packages/ember-data/tests/integration/records/delete_record_test.js index 06232075d61..c758c4ef2c9 100644 --- a/packages/ember-data/tests/integration/records/delete_record_test.js +++ b/packages/ember-data/tests/integration/records/delete_record_test.js @@ -58,6 +58,7 @@ test("when deleted records are rolled back, they are still in their previous rec equal(all.get('length'), 2, 'precond - we start with two people'); equal(filtered.get('length'), 2, 'precond - we start with two people'); + run(function(){ jaime.deleteRecord(); jaime.rollback(); From a46d91155b2aa95366bcaf4a2d5465cb6aceac05 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 31 Dec 2014 17:50:13 -0600 Subject: [PATCH 0561/2527] failing test for selective observers firing Test showing that observers fire for values that do not change. --- packages/ember-data/tests/unit/store/push_test.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index b234cfd30a5..449a6c3df65 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -153,7 +153,7 @@ test("Calling push on normalize allows partial updates with raw JSON", function equal(person.get('lastName'), "Jackson", "existing fields are untouched"); }); -test("Calling push with partial records triggers observers for just those attributes", function() { +test("Calling push with partial records triggers observers for just those attributes that changed", function() { expect(1); var person; @@ -176,7 +176,8 @@ test("Calling push with partial records triggers observers for just those attrib run(function(){ store.push('person', { id: 'wat', - lastName: "Katz!" + firstName: 'Yehuda', + lastName: 'Katz!' }); }); }); From 10077f492471fecf641d9055dcaf612d912d6d2d Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 31 Dec 2014 17:50:50 -0600 Subject: [PATCH 0562/2527] observers only fire for properties that changed This changes the previous behavior where attrs that didn't change on your model would have triggered an observer to fire, even though the property didn't actually change. --- packages/ember-data/lib/system/model/model.js | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 86a7aca45a2..1c1cd5cd454 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -34,6 +34,33 @@ function extractPivotName(name) { ); } +// Like Ember.merge, but instead returns a list of keys +// for values that fail a strict equality check +// instead of the original object. +function mergeAndReturnChangedKeys(original, updates) { + var changedKeys = []; + + if (!updates || typeof updates !== 'object') { + return changedKeys; + } + + var keys = Ember.keys(updates); + var length = keys.length; + var i, val, key; + + for (i = 0; i < length; i++) { + key = keys[i]; + val = updates[key]; + + if (original[key] !== val) { + changedKeys.push(key); + } + + original[key] = val; + } + return changedKeys; +} + /** The model class that all Ember Data records descend from. @@ -830,10 +857,11 @@ var Model = Ember.Object.extend(Ember.Evented, { @method adapterDidCommit */ adapterDidCommit: function(data) { + var changedKeys; set(this, 'isError', false); if (data) { - this._data = data; + changedKeys = mergeAndReturnChangedKeys(this._data, data); } else { merge(this._data, this._inFlightAttributes); } @@ -845,7 +873,7 @@ var Model = Ember.Object.extend(Ember.Evented, { if (!data) { return; } - this._notifyProperties(Ember.keys(data)); + this._notifyProperties(changedKeys); }, /** @@ -878,11 +906,11 @@ var Model = Ember.Object.extend(Ember.Evented, { setupData: function(data) { Ember.assert("Expected an object as `data` in `setupData`", Ember.typeOf(data) === 'object'); - Ember.merge(this._data, data); + var changedKeys = mergeAndReturnChangedKeys(this._data, data); this.pushedData(); - this._notifyProperties(Ember.keys(data)); + this._notifyProperties(changedKeys); }, materializeId: function(id) { From 0ca225ac4a5382f3bf31cd7a2655a54b806c0fbb Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Thu, 1 Jan 2015 18:33:42 +0900 Subject: [PATCH 0563/2527] Fix composer.json syntax --- config/package_manager_files/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/package_manager_files/composer.json b/config/package_manager_files/composer.json index e91ef15a8a8..cec1790ecbe 100644 --- a/config/package_manager_files/composer.json +++ b/config/package_manager_files/composer.json @@ -4,7 +4,7 @@ "type": "component", "license": "MIT", "require": { - "components/ember": "~1.8.1", + "components/ember": "~1.8.1" }, "extra": { "component": { From a4d6d371b2e77cd503e907b994e9c10af999db8a Mon Sep 17 00:00:00 2001 From: Jake Bixby Date: Wed, 3 Dec 2014 09:38:23 -0800 Subject: [PATCH 0564/2527] Removed es5-shim recommendation for IE8 support --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 60f6451aeb1..27edab720f8 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,7 @@ after [setup](#setup). You'll find ember-data.js in the `dist` directory. #### Internet Explorer 8 -If you need to support Internet Explorer, you will need to use es5-shim.js and -es5-sham.js from [es5-shim](https://github.com/es-shims/es5-shim). +Internet Explorer 8 support requires Ember 1.8.1 (which provides a polyfill for `Object.create`). ### Instantiating the Store From 542fd25f3818e3dc71e41a4b12872db9566a0b1b Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 5 Jan 2015 14:49:09 -0600 Subject: [PATCH 0565/2527] disable canary once again temporarily until we fix map --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3e20001b1a0..f2bddb6ba96 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ install: script: - npm run-script test - npm run-script testem-beta - - npm run-script testem-canary + # - npm run-script testem-canary after_success: - npm run-script publish-build - "./bin/bower-ember-data-build" From 2e57d18bd0a88f7be66b29863674a49887326428 Mon Sep 17 00:00:00 2001 From: mostafa Date: Tue, 6 Jan 2015 11:57:17 +0200 Subject: [PATCH 0566/2527] add note in change log for relationship changes --- .gitignore | 1 + CHANGELOG.md | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 656b4ab8091..7d3b8cb945f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ bundle tmp/ tests/source/ dist/ +.idea .DS_Store .project diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b3b84c8843..b1993756dcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -115,6 +115,7 @@ export default DS.RESTSerializer.extend({ * [Feature thrownError] tag errorThrown from jQuery onto the jqXHR like ic-ajax does. * Cache relationships meta in production * Deprecate store.update() +* Relationships are no long `ArrayProxy`, you can directly access them, so instead of relationship.get('content'). just use `relationship.toArray()`. ### Ember Data 1.0.0-beta.12 (November 25, 2014) From eef1e5b4adebd6adc644dedcb98d4bb794be7fb0 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 1 Jan 2015 21:13:12 -0500 Subject: [PATCH 0567/2527] build tool improvements * cleanup * windows via appveyor --- .travis.yml | 10 ++++++---- appveyor.yml | 40 ++++++++++++++++++++++++++++++++++++++++ package.json | 15 ++++++++------- 3 files changed, 54 insertions(+), 11 deletions(-) create mode 100644 appveyor.yml diff --git a/.travis.yml b/.travis.yml index f2bddb6ba96..0040ff9a1da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,15 +2,17 @@ language: node_js node_js: - "0.10" +before_install: + - "npm config set spin false" + - "npm install -g npm@^2" install: -- npm config set registry http://registry.nodejitsu.com - "npm install" - "bower install" -- "npm run-script dist" +- "npm run-script build:production" script: - npm run-script test - - npm run-script testem-beta - # - npm run-script testem-canary + - npm run-script test:beta +# - npm run-script test:canary after_success: - npm run-script publish-build - "./bin/bower-ember-data-build" diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000000..4aa36a9f3f1 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,40 @@ +# http://www.appveyor.com/docs/appveyor-yml + +# Fix line endings in Windows. (runs before repo cloning) +init: + - git config --global core.autocrlf true + +# Test against these versions of Node.js. +environment: + matrix: + - nodejs_version: "0.10" + +# Install scripts. (runs after repo cloning) +install: + # Get the latest stable version of Node 0.STABLE.latest + - ps: Install-Product node 0.10.30 x86 + # Install PhantomJS + - cinst PhantomJS + - set path=%path%;C:\tools\PhantomJS\ + - dir C:\tools\PhantomJS + # Typical npm stuff. + - md C:\nc + - npm install -g "npm@2.1.17" + - npm config set cache C:\nc + - npm version + - npm install + +# Post-install test scripts. +test_script: + # Output useful info for debugging. + - npm version + - npm run build + - cmd: npm run test + - cmd: npm run test:beta + - cmd: npm run test:canary + +# Don't actually build. +build: off + +# Set build version format here instead of in the admin panel. +version: "{build}" diff --git a/package.json b/package.json index 1829897b2a9..bce3d9a2493 100644 --- a/package.json +++ b/package.json @@ -14,15 +14,16 @@ "lib/ember-addon" ], "scripts": { - "prepublish": "bower install && npm run-script dist", + "build": "ember build", + "build:production": "ember build --environment=production", + "prepublish": "bower install && npm run-script build:production", "start": "ember serve", - "dist": "ember build --environment=production", "test": "testem -R dot ci", - "publish-build": "npm run dist && ./bin/publish_to_s3.js", - "testem-local": "testem -R dot ci", - "testem-beta": "testem -f config/testem-beta.json -R dot ci", - "testem-canary": "testem -f config/testem-canary.json -R dot ci", - "testem-stable": "testem -f config/testem-stable.json -R dot ci" + "publish-build": "npm run build:production && ./bin/publish_to_s3.js", + "test:local": "testem -R dot ci", + "test:beta": "testem -f config/testem-beta.json -R dot ci", + "test:canary": "testem -f config/testem-canary.json -R dot ci", + "test:stable": "testem -f config/testem-stable.json -R dot ci" }, "devDependencies": { "aws-sdk": "~2.0.0-rc8", From 9f0f002e1c49fced9c6843d3288d5e00968b5614 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Mon, 17 Nov 2014 18:58:57 +0100 Subject: [PATCH 0568/2527] Add support for embedded polymorphic belongsTo --- .../lib/serializers/embedded_records_mixin.js | 32 ++++++++-- packages/ember-data/lib/system/store.js | 2 +- .../embedded_records_mixin_test.js | 59 +++++++++++++++++-- 3 files changed, 83 insertions(+), 10 deletions(-) diff --git a/packages/ember-data/lib/serializers/embedded_records_mixin.js b/packages/ember-data/lib/serializers/embedded_records_mixin.js index 3b0d9633488..9d189f90ca5 100644 --- a/packages/ember-data/lib/serializers/embedded_records_mixin.js +++ b/packages/ember-data/lib/serializers/embedded_records_mixin.js @@ -29,7 +29,7 @@ var camelize = Ember.String.camelize; The `attrs` option for a resource `{ embedded: 'always' }` is shorthand for: ```js - { + { serialize: 'records', deserialize: 'records' } @@ -56,7 +56,7 @@ var camelize = Ember.String.camelize; If you do not overwrite `attrs` for a specific relationship, the `EmbeddedRecordsMixin` will behave in the following way: - BelongsTo: `{ serialize: 'id', deserialize: 'id' }` + BelongsTo: `{ serialize: 'id', deserialize: 'id' }` HasMany: `{ serialize: false, deserialize: 'ids' }` ### Model Relationships @@ -393,13 +393,16 @@ function extractEmbeddedRecords(serializer, store, type, partial) { if (relationship.kind === "hasMany") { if (relationship.options.polymorphic) { extractEmbeddedHasManyPolymorphic(store, key, partial); - } - else { + } else { extractEmbeddedHasMany(store, key, embeddedType, partial); } } if (relationship.kind === "belongsTo") { - extractEmbeddedBelongsTo(store, key, embeddedType, partial); + if (relationship.options.polymorphic) { + extractEmbeddedBelongsToPolymorphic(store, key, partial); + } else { + extractEmbeddedBelongsTo(store, key, embeddedType, partial); + } } } }); @@ -462,4 +465,23 @@ function extractEmbeddedBelongsTo(store, key, embeddedType, hash) { return hash; } +function extractEmbeddedBelongsToPolymorphic(store, key, hash) { + if (!hash[key]) { + return hash; + } + + var data = hash[key]; + var typeKey = data.type; + var embeddedSerializer = store.serializerFor(typeKey); + var embeddedType = store.modelFor(typeKey); + var primaryKey = get(embeddedSerializer, 'primaryKey'); + + var embeddedRecord = embeddedSerializer.normalize(embeddedType, data, null); + store.push(embeddedType, embeddedRecord); + + hash[key] = embeddedRecord[primaryKey]; + hash[key + 'Type'] = typeKey; + return hash; +} + export default EmbeddedRecordsMixin; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index cc826539054..4c3b12752d9 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1752,7 +1752,7 @@ function deserializeRecordId(store, data, key, relationship, id) { type = typeFor(relationship, key, data); data[key] = store.recordForId(type, id); } else if (typeof id === 'object') { - // polymorphic + // hasMany polymorphic Ember.assert('Ember Data expected a number or string to represent the record(s) in the `' + relationship.key + '` relationship instead it found an object. If this is a polymorphic relationship please specify a `type` key. If this is an embedded relationship please include the `DS.EmbeddedRecordsMixin` and specify the `' + relationship.key +'` property in your serializer\'s attrs hash.', id.type); data[key] = store.recordForId(id.type, id.id); } diff --git a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js index 93820d99118..0caf982616f 100644 --- a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js +++ b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js @@ -24,6 +24,9 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { vicinity: DS.attr('string'), superVillain: DS.belongsTo('superVillain') }); + BatCave = SecretLab.extend({ + infiltrated: DS.attr('boolean') + }); SecretWeapon = DS.Model.extend({ name: DS.attr('string'), superVillain: DS.belongsTo('superVillain') @@ -44,6 +47,7 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { superVillain: SuperVillain, homePlanet: HomePlanet, secretLab: SecretLab, + batCave: BatCave, secretWeapon: SecretWeapon, lightSaber: LightSaber, evilMinion: EvilMinion, @@ -52,6 +56,7 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { env.store.modelFor('superVillain'); env.store.modelFor('homePlanet'); env.store.modelFor('secretLab'); + env.store.modelFor('batCave'); env.store.modelFor('secretWeapon'); env.store.modelFor('lightSaber'); env.store.modelFor('evilMinion'); @@ -292,7 +297,7 @@ test("extractSingle with embedded objects of same type, but from separate attrib name: "Earth", villains: ["1", "3"], reformedVillains: ["2", "4"] - }, "Primary array was correct"); + }, "Primary hash was correct"); equal(env.store.recordForId("superVillain", "1").get("firstName"), "Tom", "Secondary records found in the store"); equal(env.store.recordForId("superVillain", "2").get("firstName"), "Alex", "Secondary records found in the store"); @@ -1064,7 +1069,7 @@ test("extractSingle with multiply-nested belongsTo", function() { id: "1", name: "Alex", superVillain: "1" - }, "Primary array was correct"); + }, "Primary hash was correct"); equal(env.store.recordForId("superVillain", "1").get("firstName"), "Tom", "Secondary record, Tom, found in the steore"); equal(env.store.recordForId("homePlanet", "1").get("name"), "Umber", "Nested Secondary record, Umber, found in the store"); @@ -1117,7 +1122,7 @@ test("extractSingle with polymorphic hasMany", function() { {id: "1", type: "lightSaber"}, {id: "1", type: "secretWeapon"} ] - }, "Primary array was correct"); + }, "Primary hash was correct"); equal(env.store.recordForId("secretWeapon", "1").get("name"), "The Death Star", "Embedded polymorphic SecretWeapon found"); equal(env.store.recordForId("lightSaber", "1").get("name"), "Tom's LightSaber", "Embedded polymorphic LightSaber found"); @@ -1125,6 +1130,52 @@ test("extractSingle with polymorphic hasMany", function() { }); +test("extractSingle with polymorphic belongsTo", function() { + expect(2); + + SuperVillain.reopen({ + secretLab: DS.belongsTo("secretLab", {polymorphic: true}), + }); + + env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: {embedded: 'always'} + } + })); + var serializer = env.container.lookup("serializer:superVillain"); + + var json_hash = { + super_villain: { + id: "1", + first_name: "Tom", + last_name: "Dale", + secret_lab: { + id: "1", + type: "BatCave", + infiltrated: true + } + } + }; + + var json; + + run(function() { + json = serializer.extractSingle(env.store, SuperVillain, json_hash); + }); + + deepEqual(json, { + id: "1", + firstName: "Tom", + lastName: "Dale", + secretLab: "1", + secretLabType: "batCave" + }, "Primary has was correct"); + + equal(env.store.recordForId("batCave", "1").get("infiltrated"), true, "Embedded polymorphic BatCave was found"); + +}); + test("Mixin can be used with RESTSerializer which does not define keyForAttribute", function() { run(function(){ homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); @@ -1200,7 +1251,7 @@ test("normalize with custom belongsTo primary key", function() { id: "1", name: "Alex", superVillain: "1" - }, "Primary array was correct"); + }, "Primary hash was correct"); equal(env.store.recordForId("superVillain", "1").get("firstName"), "Tom", "Secondary record, Tom, found in the steore"); }); From 143855c657218e4ddeea6d1e8ab461d4c6c8f757 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Tue, 6 Jan 2015 21:22:38 +0100 Subject: [PATCH 0569/2527] Add deprecation of store.metaForType to CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b3b84c8843..b086064b93a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,6 +87,12 @@ export default DS.RESTSerializer.extend({ }); ``` +##### `store.metaForType()` has been deprecated + +`store.metaForType()` has been deprecated because of it's ambiguous naming. +Please use `store.metadataFor()` to get metadata and `store.setMetadataFor()` +to set metadata. + #### Changes * Fix references to buildURL in documentation From 53d8bf9b78604da3e3b3ab5e35919514ca5b59dd Mon Sep 17 00:00:00 2001 From: Ryuta Oshikiri Date: Tue, 6 Jan 2015 13:47:46 -0800 Subject: [PATCH 0570/2527] remove type check for addCanonicalRecord in belongsto relationship --- .../system/relationships/state/belongs_to.js | 2 -- .../relationships/belongs_to_test.js | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/state/belongs_to.js b/packages/ember-data/lib/system/relationships/state/belongs_to.js index 9f5961c58c1..08e8e2d7de5 100644 --- a/packages/ember-data/lib/system/relationships/state/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/state/belongs_to.js @@ -35,8 +35,6 @@ BelongsToRelationship.prototype.setCanonicalRecord = function(newRecord) { BelongsToRelationship.prototype._super$addCanonicalRecord = Relationship.prototype.addCanonicalRecord; BelongsToRelationship.prototype.addCanonicalRecord = function(newRecord) { if (this.canonicalMembers.has(newRecord)){ return;} - var type = this.relationshipMeta.type; - Ember.assert("You can only add a '" + type.typeKey + "' record to this relationship", newRecord instanceof type); if (this.canonicalState) { this.removeCanonicalRecord(this.canonicalState); diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index 94d4517bb0a..752df083058 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -312,6 +312,24 @@ test("polymorphic belongsTo type-checks check the superclass when MODEL_FACTORY_ } }); +test("the subclass in a polymorphic belongsTo relationship is an instanceof its superclass", function() { + expect(1); + + var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; + Ember.MODEL_FACTORY_INJECTIONS = true; + + try { + run(function () { + var message = env.store.createRecord('message', { id: 1 }); + var comment = env.store.createRecord('comment', { id: 2, message: message }); + ok(comment instanceof Message, 'a comment is an instance of a message'); + }); + + } finally { + Ember.MODEL_FACTORY_INJECTIONS = injectionValue; + } +}); + test("relationshipsByName does not cache a factory", function() { // The model is loaded up via a container. It has relationshipsByName From 785bb284e42ba1603c2f7b6db951e0c316491054 Mon Sep 17 00:00:00 2001 From: Alex Speller Date: Thu, 29 May 2014 12:54:55 +0100 Subject: [PATCH 0571/2527] Allow errors on arbitrary properties, not just defined attributes or relationships --- packages/ember-data/lib/system/model/model.js | 10 +- .../integration/adapter/store_adapter_test.js | 91 +++++++++++++++++++ 2 files changed, 94 insertions(+), 7 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 1c1cd5cd454..04e00f5ad46 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1064,14 +1064,10 @@ var Model = Ember.Object.extend(Ember.Evented, { */ adapterDidInvalidate: function(errors) { var recordErrors = get(this, 'errors'); - function addError(name) { - if (errors[name]) { - recordErrors.add(name, errors[name]); - } + for (var key in errors) { + if (!errors.hasOwnProperty(key)) continue; + recordErrors.add(key, errors[key]); } - - this.eachAttribute(addError); - this.eachRelationship(addError); this._saveWasRejected(); }, diff --git a/packages/ember-data/tests/integration/adapter/store_adapter_test.js b/packages/ember-data/tests/integration/adapter/store_adapter_test.js index c923cf4939e..137c57a54cb 100644 --- a/packages/ember-data/tests/integration/adapter/store_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/store_adapter_test.js @@ -404,6 +404,48 @@ test("if a created record is marked as invalid by the server, it enters an error }); }); +test("allows errors on arbitrary properties on create", function() { + adapter.createRecord = function(store, type, record) { + if (get(record, 'name').indexOf('Bro') === -1) { + return Ember.RSVP.reject(new DS.InvalidError({ base: ['is a generally unsavoury character'] })); + } else { + return Ember.RSVP.resolve(); + } + }; + + var yehuda = run(function () { + return store.createRecord('person', { id: 1, name: "Yehuda Katz" }); + }); + + // Wrap this in an Ember.run so that all chained async behavior is set up + // before flushing any scheduled behavior. + run(function() { + yehuda.save().then(null, async(function(error) { + equal(get(yehuda, 'isValid'), false, "the record is invalid"); + ok(get(yehuda, 'errors.base'), "The errors.base property exists"); + deepEqual(get(yehuda, 'errors').errorsFor('base'), [{attribute: 'base', message: "is a generally unsavoury character"}]); + + set(yehuda, 'updatedAt', true); + equal(get(yehuda, 'isValid'), false, "the record is still invalid"); + + set(yehuda, 'name', "Brohuda Brokatz"); + + equal(get(yehuda, 'isValid'), false, "the record is still invalid as far as we know"); + equal(get(yehuda, 'isDirty'), true, "the record has outstanding changes"); + + equal(get(yehuda, 'isNew'), true, "precond - record is still new"); + + return yehuda.save(); + })).then(async(function(person) { + strictEqual(person, yehuda, "The promise resolves with the saved record"); + ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); + deepEqual(get(yehuda, 'errors').errorsFor('base'), []); + equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); + equal(get(yehuda, 'isNew'), false, "record is no longer new"); + })); + }); +}); + test("if a created record is marked as invalid by the server, you can attempt the save again", function() { var saveCount = 0; adapter.createRecord = function(store, type, record) { @@ -510,6 +552,55 @@ test("if an updated record is marked as invalid by the server, it enters an erro }); +test("records can have errors on arbitrary properties after update", function() { + adapter.updateRecord = function(store, type, record) { + if (get(record, 'name').indexOf('Bro') === -1) { + return Ember.RSVP.reject(new DS.InvalidError({ base: ['is a generally unsavoury character'] })); + } else { + return Ember.RSVP.resolve(); + } + }; + + var yehuda = run(function() { + return store.push('person', { id: 1, name: "Brohuda Brokatz" }); + }); + + run(function() { + store.find('person', 1).then(async(function(person) { + equal(person, yehuda, "The same object is passed through"); + + equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); + set(yehuda, 'name', "Yehuda Katz"); + equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); + + equal(get(yehuda, 'isDirty'), true, "the record is dirty"); + + return yehuda.save(); + })).then(null, async(function(reason) { + equal(get(yehuda, 'isDirty'), true, "the record is still dirty"); + equal(get(yehuda, 'isValid'), false, "the record is invalid"); + ok(get(yehuda, 'errors.base'), "The errors.base property exists"); + deepEqual(get(yehuda, 'errors').errorsFor('base'), [{attribute: 'base', message: "is a generally unsavoury character"}]); + + set(yehuda, 'updatedAt', true); + equal(get(yehuda, 'isValid'), false, "the record is still invalid"); + + set(yehuda, 'name', "Brohuda Brokatz"); + equal(get(yehuda, 'isValid'), false, "the record is still invalid after changing (only server can know if it's now valid)"); + equal(get(yehuda, 'isDirty'), true, "the record has outstanding changes"); + + return yehuda.save(); + })).then(async(function(yehuda) { + equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); + equal(get(yehuda, 'isDirty'), false, "record is no longer new"); + ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); + deepEqual(get(yehuda, 'errors').errorsFor('base'), []); + })); + }); +}); + + + test("if an updated record is marked as invalid by the server, you can attempt the save again", function() { var saveCount = 0; adapter.updateRecord = function(store, type, record) { From 6796d4c5d711462a02ddbeafd354777b6a31d03a Mon Sep 17 00:00:00 2001 From: Aaron Quamme Date: Tue, 6 Jan 2015 22:43:42 -0600 Subject: [PATCH 0572/2527] Remove workaround for Ember 1.5 --- packages/ember-data/tests/integration/debug_adapter_test.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/ember-data/tests/integration/debug_adapter_test.js b/packages/ember-data/tests/integration/debug_adapter_test.js index 54573fe97f9..9d2a6c0e5ce 100644 --- a/packages/ember-data/tests/integration/debug_adapter_test.js +++ b/packages/ember-data/tests/integration/debug_adapter_test.js @@ -22,11 +22,6 @@ module("DS.DebugAdapter", { debugAdapter.reopen({ getModelTypes: function() { - // Support Ember < 1.5. - // TODO: Remove this workaround (if statement) when Ember 1.5 is released. - if (!this.get('containerDebugAdapter')) { - return Ember.A([App.Post]); - } return Ember.A([{ klass: App.Post, name: 'App.Post' }]); } }); From 8f4bc3751b9ef71525899877f062b66d17aa6897 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 7 Jan 2015 09:50:37 +0100 Subject: [PATCH 0573/2527] Use store.push instead of store.update in test --- packages/ember-data/tests/unit/store/push_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index 449a6c3df65..c874995828e 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -116,7 +116,7 @@ test("Calling push with partial records updates just those attributes", function lastName: "Katz" }); - store.update('person', { + store.push('person', { id: 'wat', lastName: "Katz!" }); From feb9521f92b5a86874b61eb3b5b08a17bd9a17f2 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 7 Jan 2015 10:01:07 +0100 Subject: [PATCH 0574/2527] Remove yuidoc warning --- packages/ember-data/lib/adapters/rest_adapter.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 27ce7492f7d..4184d92c989 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -602,9 +602,7 @@ export default Adapter.extend({ return expandedURL.join('/'); }, - /** - http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers - */ + // http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers maxUrlLength: 2048, /** From abebddc7f4aa0b33f0c12a46478175472050c2e1 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Wed, 7 Jan 2015 14:46:20 -0500 Subject: [PATCH 0575/2527] Run Travis-CI with Docker / Cache http://docs.travis-ci.com/user/workers/container-based-infrastructure/ Running CI in docker container should be more performant. This is already being done in [ember/ember.js](https://github.com/emberjs/ember.js/blob/dca9c74de7136deff79b9cb2f2de4f6b6b8237c7/.travis.yml#L6-L10) --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0040ff9a1da..5c8eb2441e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,9 @@ --- language: node_js +sudo: false +cache: + directories: + - node_modules node_js: - "0.10" before_install: From 54c454af84607649fba177bb8d35009e72d13e57 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Wed, 7 Jan 2015 13:15:17 -0500 Subject: [PATCH 0576/2527] Add `expect` calls when async is involved `expect` calls within callbacks ensure that all expectations are invoked and passing. --- .../unit/model/lifecycle_callbacks_test.js | 10 ++++ .../ember-data/tests/unit/model/merge_test.js | 19 ++++--- .../tests/unit/model/relationships_test.js | 32 ++++++++++-- packages/ember-data/tests/unit/model_test.js | 52 ++++++++++++++----- .../tests/unit/record_array_test.js | 6 +++ .../tests/unit/store/adapter_interop_test.js | 46 ++++++++++++---- .../tests/unit/store/create_record_test.js | 2 +- .../tests/unit/store/metadata_for_test.js | 4 +- .../ember-data/tests/unit/store/push_test.js | 21 ++++++-- .../tests/unit/store/unload_test.js | 8 ++- 10 files changed, 158 insertions(+), 42 deletions(-) diff --git a/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js b/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js index af1146fa00c..1756fc97a43 100644 --- a/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js +++ b/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js @@ -4,6 +4,8 @@ var run = Ember.run; module("unit/model/lifecycle_callbacks - Lifecycle Callbacks"); test("a record receives a didLoad callback when it has finished loading", function() { + expect(3); + var Person = DS.Model.extend({ name: DS.attr(), didLoad: function() { @@ -30,6 +32,8 @@ test("a record receives a didLoad callback when it has finished loading", functi }); test("a record receives a didUpdate callback when it has finished updating", function() { + expect(5); + var callCount = 0; var Person = DS.Model.extend({ @@ -77,6 +81,8 @@ test("a record receives a didUpdate callback when it has finished updating", fun }); test("a record receives a didCreate callback when it has finished updating", function() { + expect(5); + var callCount = 0; var Person = DS.Model.extend({ @@ -115,6 +121,8 @@ test("a record receives a didCreate callback when it has finished updating", fun }); test("a record receives a didDelete callback when it has finished deleting", function() { + expect(5); + var callCount = 0; var Person = DS.Model.extend({ @@ -164,6 +172,8 @@ test("a record receives a didDelete callback when it has finished deleting", fun }); test("a record receives a becameInvalid callback when it became invalid", function() { + expect(5); + var callCount = 0; var Person = DS.Model.extend({ diff --git a/packages/ember-data/tests/unit/model/merge_test.js b/packages/ember-data/tests/unit/model/merge_test.js index 111f9665c8d..141488a8b92 100644 --- a/packages/ember-data/tests/unit/model/merge_test.js +++ b/packages/ember-data/tests/unit/model/merge_test.js @@ -7,21 +7,18 @@ module("unit/model/merge - Merging", { name: DS.attr(), city: DS.attr() }); - }, - - teardown: function() { - } }); test("When a record is in flight, changes can be made", function() { + expect(3); + var adapter = DS.Adapter.extend({ createRecord: function(store, type, record) { return Ember.RSVP.resolve({ id: 1, name: "Tom Dale" }); } }); var person; - var store = createStore({ adapter: adapter }); run(function(){ @@ -29,7 +26,7 @@ test("When a record is in flight, changes can be made", function() { }); // Make sure saving isn't resolved synchronously - Ember.run(function() { + run(function() { var promise = person.save(); equal(person.get('name'), "Tom Dale"); @@ -44,11 +41,13 @@ test("When a record is in flight, changes can be made", function() { }); test("When a record is in flight, pushes are applied underneath the in flight changes", function() { + expect(6); + var adapter = DS.Adapter.extend({ updateRecord: function(store, type, record) { // Make sure saving isn't resolved synchronously return new Ember.RSVP.Promise(function(resolve, reject){ - Ember.run.next(null, resolve, { id: 1, name: "Senor Thomas Dale, Esq.", city: "Portland" }); + run.next(null, resolve, { id: 1, name: "Senor Thomas Dale, Esq.", city: "Portland" }); }); } }); @@ -61,7 +60,7 @@ test("When a record is in flight, pushes are applied underneath the in flight ch person.set('name', "Thomas Dale"); }); - Ember.run(function() { + run(function() { var promise = person.save(); equal(person.get('name'), "Thomas Dale"); @@ -104,6 +103,8 @@ test("When a record is dirty, pushes are overridden by local changes", function( }); test("A record with no changes can still be saved", function() { + expect(1); + var adapter = DS.Adapter.extend({ updateRecord: function(store, type, record) { return Ember.RSVP.resolve({ id: 1, name: "Thomas Dale" }); @@ -125,6 +126,8 @@ test("A record with no changes can still be saved", function() { }); test("A dirty record can be reloaded", function() { + expect(3); + var adapter = DS.Adapter.extend({ find: function(store, type, id) { return Ember.RSVP.resolve({ id: 1, name: "Thomas Dale", city: "Portland" }); diff --git a/packages/ember-data/tests/unit/model/relationships_test.js b/packages/ember-data/tests/unit/model/relationships_test.js index 1405be73a35..52cf499ba15 100644 --- a/packages/ember-data/tests/unit/model/relationships_test.js +++ b/packages/ember-data/tests/unit/model/relationships_test.js @@ -44,6 +44,8 @@ module("unit/model/relationships - DS.hasMany", { }); test("hasMany handles pre-loaded relationships", function() { + expect(13); + var Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person') @@ -118,7 +120,7 @@ test("hasMany handles pre-loaded relationships", function() { equal(get(pets, 'length'), 1, "the list of pets should have the correct length"); equal(get(pets.objectAt(0), 'name'), "fluffy", "the first pet should be correct"); - Ember.run(function() { + run(function() { store.push(Person, { id: 4, name: "Cyvid Hamluck", pets: [4, 12] }); }); @@ -129,6 +131,8 @@ test("hasMany handles pre-loaded relationships", function() { }); test("hasMany lazily loads async relationships", function() { + expect(5); + var Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person') @@ -259,6 +263,8 @@ test("should be able to retrieve the type for a belongsTo relationship specified }); test("relationships work when declared with a string path", function() { + expect(2); + window.App = {}; var Person = DS.Model.extend({ @@ -289,6 +295,8 @@ test("relationships work when declared with a string path", function() { }); test("hasMany relationships work when the data hash has not been loaded", function() { + expect(8); + var Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person') @@ -337,6 +345,8 @@ test("hasMany relationships work when the data hash has not been loaded", functi }); test("it is possible to add a new item to a relationship", function() { + expect(2); + var Tag = DS.Model.extend({ name: DS.attr('string'), people: DS.belongsTo('person') @@ -374,6 +384,8 @@ test("it is possible to add a new item to a relationship", function() { }); test("possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)", function(){ + expect(2); + var Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person') @@ -386,9 +398,8 @@ test("possible to replace items in a relationship using setObjects w/ Ember Enum var env = setupStore({ tag: Tag, person: Person }); var store = env.store; - var run = Ember.run; - Ember.run(function(){ + run(function(){ store.push('person', { id: 1, name: "Tom Dale", tags: [ 1 ] }); store.push('person', { id: 2, name: "Sylvain Mina", tags: [ 2 ] }); store.push('tag', { id: 1, name: "ember" }); @@ -410,6 +421,8 @@ test("possible to replace items in a relationship using setObjects w/ Ember Enum }); test("it is possible to remove an item from a relationship", function() { + expect(2); + var Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person') @@ -517,6 +530,8 @@ test("updating the content of a RecordArray updates its content", function() { }); test("can create child record from a hasMany relationship", function() { + expect(3); + var Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person') @@ -548,6 +563,8 @@ test("can create child record from a hasMany relationship", function() { module("unit/model/relationships - DS.belongsTo"); test("belongsTo lazily loads relationships as needed", function() { + expect(5); + var Tag = DS.Model.extend({ name: DS.attr('string'), people: DS.hasMany('person') @@ -582,6 +599,8 @@ test("belongsTo lazily loads relationships as needed", function() { }); test("async belongsTo relationships work when the data hash has not been loaded", function() { + expect(5); + var Tag = DS.Model.extend({ name: DS.attr('string') }); @@ -621,6 +640,8 @@ test("async belongsTo relationships work when the data hash has not been loaded" }); test("async belongsTo relationships work when the data hash has already been loaded", function() { + expect(3); + var Tag = DS.Model.extend({ name: DS.attr('string') }); @@ -652,6 +673,8 @@ test("async belongsTo relationships work when the data hash has already been loa }); test("calling createRecord and passing in an undefined value for a relationship should be treated as if null", function () { + expect(1); + var Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person') @@ -722,6 +745,7 @@ test("When finding a hasMany relationship the inverse belongsTo relationship is test("When finding a belongsTo relationship the inverse belongsTo relationship is available immediately", function() { expect(1); + var Occupation = DS.Model.extend({ description: DS.attr('string'), person: DS.belongsTo('person') @@ -754,6 +778,8 @@ test("When finding a belongsTo relationship the inverse belongsTo relationship i }); test("belongsTo supports relationships to models with id 0", function() { + expect(5); + var Tag = DS.Model.extend({ name: DS.attr('string'), people: DS.hasMany('person') diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index 682972842ac..94d9c3c0638 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -1,7 +1,8 @@ -var get = Ember.get, set = Ember.set; +var get = Ember.get; +var set = Ember.set; +var run = Ember.run; var Person, store, array; -var run = Ember.run; module("unit/model - DS.Model", { setup: function() { @@ -33,6 +34,8 @@ test("can have a property set on it", function() { }); test("setting a property on a record that has not changed does not cause it to become dirty", function() { + expect(2); + run(function(){ store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); store.find(Person, 1).then(function(person) { @@ -47,6 +50,8 @@ test("setting a property on a record that has not changed does not cause it to b }); test("resetting a property on a record cause it to become clean again", function() { + expect(3); + run(function(){ store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); store.find(Person, 1).then(function(person) { @@ -60,6 +65,8 @@ test("resetting a property on a record cause it to become clean again", function }); test("a record becomes clean again only if all changed properties are reset", function() { + expect(5); + run(function(){ store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); store.find(Person, 1).then(function(person) { @@ -77,6 +84,8 @@ test("a record becomes clean again only if all changed properties are reset", fu }); test("a record reports its unique id via the `id` property", function() { + expect(1); + run(function(){ store.push(Person, { id: 1 }); store.find(Person, 1).then(function(record) { @@ -86,13 +95,12 @@ test("a record reports its unique id via the `id` property", function() { }); test("a record's id is included in its toString representation", function() { + expect(1); + run(function(){ store.push(Person, { id: 1 }); - - run(function(){ - store.find(Person, 1).then(function(record) { - equal(record.toString(), '<(subclass of DS.Model):'+Ember.guidFor(record)+':1>', "reports id in toString"); - }); + store.find(Person, 1).then(function(record) { + equal(record.toString(), '<(subclass of DS.Model):'+Ember.guidFor(record)+':1>', "reports id in toString"); }); }); }); @@ -112,6 +120,8 @@ test("trying to set an `id` attribute should raise", function() { }); test("a collision of a record's id with object function's name", function() { + expect(1); + var hasWatchMethod = Object.prototype.watch; try { if (!hasWatchMethod) { @@ -131,6 +141,8 @@ test("a collision of a record's id with object function's name", function() { }); test("it should use `_reference` and not `reference` to store its reference", function() { + expect(1); + run(function(){ store.push(Person, { id: 1 }); @@ -141,6 +153,8 @@ test("it should use `_reference` and not `reference` to store its reference", fu }); test("it should cache attributes", function() { + expect(2); + var store = createStore(); var Post = DS.Model.extend({ @@ -240,6 +254,8 @@ module("unit/model - DS.Model updating", { }); test("a DS.Model can update its attributes", function() { + expect(1); + run(function(){ store.find(Person, 2).then(function(person) { set(person, 'name', "Brohuda Katz"); @@ -312,11 +328,7 @@ test("setting a property to undefined on a newly created record should not impac run(function(){ tag = store.createRecord(Tag); - }); - run(function(){ set(tag, 'name', 'testing'); - }); - run(function(){ set(tag, 'name', undefined); }); @@ -332,6 +344,8 @@ test("setting a property to undefined on a newly created record should not impac // NOTE: this is a 'backdoor' test that ensures internal consistency, and should be // thrown out if/when the current `_attributes` hash logic is removed. test("setting a property back to its original value removes the property from the `_attributes` hash", function() { + expect(3); + run(function(){ store.find(Person, 1).then(function(person) { equal(person._attributes.name, undefined, "the `_attributes` hash is clean"); @@ -349,7 +363,11 @@ test("setting a property back to its original value removes the property from th module("unit/model - with a simple Person model", { setup: function() { - array = [{ id: 1, name: "Scumbag Dale" }, { id: 2, name: "Scumbag Katz" }, { id: 3, name: "Scumbag Bryn" }]; + array = [ + { id: 1, name: "Scumbag Dale" }, + { id: 2, name: "Scumbag Katz" }, + { id: 3, name: "Scumbag Bryn" } + ]; Person = DS.Model.extend({ name: DS.attr('string') }); @@ -498,6 +516,8 @@ var convertsWhenSet = function(type, provided, expected) { }; test("a DS.Model can describe String attributes", function() { + expect(6); + converts('string', "Scumbag Tom", "Scumbag Tom"); converts('string', 1, "1"); converts('string', "", ""); @@ -507,6 +527,8 @@ test("a DS.Model can describe String attributes", function() { }); test("a DS.Model can describe Number attributes", function() { + expect(9); + converts('number', "1", 1); converts('number', "0", 0); converts('number', 1, 1); @@ -519,6 +541,8 @@ test("a DS.Model can describe Number attributes", function() { }); test("a DS.Model can describe Boolean attributes", function() { + expect(7); + converts('boolean', "1", true); converts('boolean', "", false); converts('boolean', 1, true); @@ -529,6 +553,8 @@ test("a DS.Model can describe Boolean attributes", function() { }); test("a DS.Model can describe Date attributes", function() { + expect(5); + converts('date', null, null); converts('date', undefined, undefined); @@ -572,6 +598,8 @@ test("don't allow setting", function(){ }); test("ensure model exits loading state, materializes data and fulfills promise only after data is available", function () { + expect(2); + var store = createStore({ adapter: DS.Adapter.extend({ find: function(store, type, id) { diff --git a/packages/ember-data/tests/unit/record_array_test.js b/packages/ember-data/tests/unit/record_array_test.js index cd238243c5e..efaaf173b42 100644 --- a/packages/ember-data/tests/unit/record_array_test.js +++ b/packages/ember-data/tests/unit/record_array_test.js @@ -14,6 +14,8 @@ module("unit/record_array - DS.RecordArray", { }); test("a record array is backed by records", function() { + expect(3); + var store = createStore(); run(function(){ store.pushMany(Person, array); @@ -67,6 +69,8 @@ test("stops updating when destroyed", function() { test("a loaded record is removed from a record array when it is deleted", function() { + expect(4); + var Tag = DS.Model.extend({ people: DS.hasMany('person') }); @@ -223,6 +227,8 @@ test("a record array should be able to be enumerated in any order", function() { }); test("an AdapterPopulatedRecordArray knows if it's loaded or not", function() { + expect(1); + var env = setupStore({ person: Person }), store = env.store; diff --git a/packages/ember-data/tests/unit/store/adapter_interop_test.js b/packages/ember-data/tests/unit/store/adapter_interop_test.js index b000625d01f..75b4c0edde2 100644 --- a/packages/ember-data/tests/unit/store/adapter_interop_test.js +++ b/packages/ember-data/tests/unit/store/adapter_interop_test.js @@ -15,7 +15,7 @@ module("unit/store/adapter_interop - DS.Store working with a DS.Adapter", { }); test("Adapter can be set as a factory", function() { - store = createStore({adapter: TestAdapter}); + store = createStore({ adapter: TestAdapter }); ok(store.get('defaultAdapter') instanceof TestAdapter); }); @@ -27,6 +27,8 @@ test('Adapter can be set as a name', function() { }); test('Adapter can not be set as an instance', function() { + expect(5); + store = DS.Store.create({ adapter: DS.Adapter.create() }); @@ -79,13 +81,15 @@ test("Calling Store#findById multiple times coalesces the calls into a adapter#f var currentType = DS.Model.extend(); currentType.typeKey = "test"; stop(); - Ember.run(function(){ + run(function(){ currentStore.find(currentType, 1); currentStore.find(currentType, 2); }); }); test("Returning a promise from `find` asynchronously loads data", function() { + expect(1); + var adapter = TestAdapter.extend({ find: function(store, type, id) { return resolve({ id: 1, name: "Scumbag Dale" }); @@ -105,6 +109,8 @@ test("Returning a promise from `find` asynchronously loads data", function() { }); test("IDs provided as numbers are coerced to strings", function() { + expect(4); + var adapter = TestAdapter.extend({ find: function(store, type, id) { equal(typeof id, 'string', "id has been normalized to a string"); @@ -135,6 +141,8 @@ test("IDs provided as numbers are coerced to strings", function() { var array = [{ id: "1", name: "Scumbag Dale" }, { id: "2", name: "Scumbag Katz" }, { id: "3", name: "Scumbag Bryn" }]; test("can load data for the same record if it is not dirty", function() { + expect(3); + var store = createStore(); var Person = DS.Model.extend({ name: DS.attr('string') @@ -166,6 +174,8 @@ test("DS.Store loads individual records without explicit IDs with a custom prima */ test("pushMany extracts ids from an Array of hashes if no ids are specified", function() { + expect(1); + var store = createStore(); var Person = DS.Model.extend({ name: DS.attr('string') }); @@ -179,6 +189,8 @@ test("pushMany extracts ids from an Array of hashes if no ids are specified", fu }); test("loadMany takes an optional Object and passes it on to the Adapter", function() { + expect(2); + var passedQuery = { page: 1 }; var Person = DS.Model.extend({ @@ -323,6 +335,8 @@ test("an initial data hash can be provided via store.createRecord(type, hash)", }); test("if an id is supplied in the initial data hash, it can be looked up using `store.find`", function() { + expect(1); + var store = createStore(); var Person = DS.Model.extend({ name: DS.attr('string') @@ -338,6 +352,8 @@ test("if an id is supplied in the initial data hash, it can be looked up using ` }); test("initial values of attributes can be passed in as the third argument to find", function() { + expect(1); + var adapter = TestAdapter.extend({ find: function(store, type, query) { return Ember.RSVP.resolve({id: '1', name: 'Test'}); @@ -388,6 +404,7 @@ test("initial values of belongsTo can be passed in as the third argument to find test("initial values of belongsTo can be passed in as the third argument to find as ids", function() { expect(1); + var adapter = TestAdapter.extend({ find: function(store, type, id) { return Ember.RSVP.Promise.resolve({id: id}); @@ -470,6 +487,8 @@ test("initial values of hasMany can be passed in as the third argument to find a }); test("records should have their ids updated when the adapter returns the id data", function() { + expect(2); + var Person = DS.Model.extend(); var idCounter = 1; @@ -501,6 +520,8 @@ test("records should have their ids updated when the adapter returns the id data }); test("store.fetchMany should always return a promise", function() { + expect(3); + var Person = DS.Model.extend(); var store = createStore({ adapter: TestAdapter.extend() @@ -522,7 +543,9 @@ test("store.fetchMany should always return a promise", function() { })); }); -test("store.scheduleFetchMany should not resolve until all the records are resolve", function() { +test("store.scheduleFetchMany should not resolve until all the records are resolved", function() { + expect(1); + var Person = DS.Model.extend(); var Phone = DS.Model.extend(); @@ -533,7 +556,7 @@ test("store.scheduleFetchMany should not resolve until all the records are resol var record = { id: id }; return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.run.later(function() { + run.later(function() { resolve(record); }, wait); }); @@ -547,7 +570,7 @@ test("store.scheduleFetchMany should not resolve until all the records are resol }); return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.run.later(function() { + run.later(function() { resolve(records); }, wait); }); @@ -627,6 +650,7 @@ test("the store calls adapter.findMany according to groupings returned by adapte test("the promise returned by `scheduleFetch`, when it resolves, does not depend on the promises returned to other calls to `scheduleFetch` that are in the same run loop, but different groups", function() { expect(2); + var Person = DS.Model.extend(); var davidResolved = false; @@ -645,7 +669,7 @@ test("the promise returned by `scheduleFetch`, when it resolves, does not depend if (id === 'igor') { resolve(record); } else { - Ember.run.later(function () { + run.later(function () { davidResolved = true; resolve(record); }, 5); @@ -658,7 +682,7 @@ test("the promise returned by `scheduleFetch`, when it resolves, does not depend adapter: adapter }); - Ember.run(function () { + run(function () { var davidPromise = store.find(Person, 'david'); var igorPromise = store.find(Person, 'igor'); @@ -674,6 +698,7 @@ test("the promise returned by `scheduleFetch`, when it resolves, does not depend test("the promise returned by `scheduleFetch`, when it rejects, does not depend on the promises returned to other calls to `scheduleFetch` that are in the same run loop, but different groups", function() { expect(2); + var Person = DS.Model.extend(); var davidResolved = false; @@ -692,7 +717,7 @@ test("the promise returned by `scheduleFetch`, when it rejects, does not depend if (id === 'igor') { reject(record); } else { - Ember.run.later(function () { + run.later(function () { davidResolved = true; resolve(record); }, 5); @@ -705,7 +730,7 @@ test("the promise returned by `scheduleFetch`, when it rejects, does not depend adapter: adapter }); - Ember.run(function () { + run(function () { var davidPromise = store.find(Person, 'david'); var igorPromise = store.find(Person, 'igor'); @@ -721,6 +746,7 @@ test("the promise returned by `scheduleFetch`, when it rejects, does not depend test("store.fetchRecord reject records that were not found, even when those requests were coalesced with records that were found", function() { expect(2); + var Person = DS.Model.extend(); var adapter = TestAdapter.extend({ @@ -741,7 +767,7 @@ test("store.fetchRecord reject records that were not found, even when those requ adapter: adapter }); - Ember.run(function () { + run(function () { var davidPromise = store.find(Person, 'david'); var igorPromise = store.find(Person, 'igor'); diff --git a/packages/ember-data/tests/unit/store/create_record_test.js b/packages/ember-data/tests/unit/store/create_record_test.js index a4bc2297175..eff12ac6bf8 100644 --- a/packages/ember-data/tests/unit/store/create_record_test.js +++ b/packages/ember-data/tests/unit/store/create_record_test.js @@ -60,7 +60,7 @@ test("creating a record by dasherize string finds the model", function(){ module("unit/store/createRecord - Store with models by camelCase", { setup: function() { var env = setupStore({ - 'someThing': DS.Model.extend({ foo: DS.attr('string') }) + someThing: DS.Model.extend({ foo: DS.attr('string') }) }); store = env.store; container = env.container; diff --git a/packages/ember-data/tests/unit/store/metadata_for_test.js b/packages/ember-data/tests/unit/store/metadata_for_test.js index 01f993a3052..1a2daba2049 100644 --- a/packages/ember-data/tests/unit/store/metadata_for_test.js +++ b/packages/ember-data/tests/unit/store/metadata_for_test.js @@ -27,9 +27,9 @@ test("metaForType should be deprecated", function() { test("metadataFor and setMetadataFor should return and set correct metadata", function() { expect(7); - var keys = Ember.keys; + function metadataKeys(type){ - return keys(store.metadataFor(type)); + return Ember.keys(store.metadataFor(type)); } // Currently not using QUnit.deepEqual due to the way deepEqual diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index c874995828e..78425309eeb 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -1,5 +1,7 @@ var env, store, Person, PhoneNumber, Post; -var attr = DS.attr, hasMany = DS.hasMany, belongsTo = DS.belongsTo; +var attr = DS.attr; +var hasMany = DS.hasMany; +var belongsTo = DS.belongsTo; var run = Ember.run; module("unit/store/push - DS.Store#push", { @@ -38,13 +40,15 @@ module("unit/store/push - DS.Store#push", { }, teardown: function() { - Ember.run(function() { + run(function() { store.destroy(); }); } }); test("Calling push with a normalized hash returns a record", function() { + expect(2); + run(function(){ var person = store.push('person', { id: 'wat', @@ -63,6 +67,8 @@ test("Calling push with a normalized hash returns a record", function() { }); test("Supplying a model class for `push` is the same as supplying a string", function () { + expect(1); + var Programmer = Person.extend(); env.container.register('model:programmer', Programmer); @@ -84,6 +90,8 @@ test("Supplying a model class for `push` is the same as supplying a string", fun }); test("Calling push triggers `didLoad` even if the record hasn't been requested from the adapter", function() { + expect(1); + Person.reopen({ didLoad: async(function() { ok(true, "The didLoad callback was called"); @@ -108,9 +116,10 @@ test("Calling update should be deprecated", function() { }); test("Calling push with partial records updates just those attributes", function() { - var person; + expect(2); + run(function(){ - person = store.push('person', { + var person = store.push('person', { id: 'wat', firstName: "Yehuda", lastName: "Katz" @@ -210,6 +219,8 @@ test("Calling push with a normalized hash containing related records returns a r }); test("Calling push with a normalized hash containing IDs of related records returns a record", function() { + expect(1); + Person.reopen({ phoneNumbers: hasMany('phone-number', { async: true }) }); @@ -558,7 +569,7 @@ test('calling push with an embedded relationship throws a useful error', functio }); test("Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS suppresses unknown keys warning", function() { - Ember.run(function(){ + run(function(){ try { Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS = true; noWarns(function() { diff --git a/packages/ember-data/tests/unit/store/unload_test.js b/packages/ember-data/tests/unit/store/unload_test.js index 73740c87154..7d0156b0509 100644 --- a/packages/ember-data/tests/unit/store/unload_test.js +++ b/packages/ember-data/tests/unit/store/unload_test.js @@ -1,6 +1,6 @@ var get = Ember.get; -var store, tryToFind, Record; var run = Ember.run; +var store, tryToFind, Record; module("unit/store/unload - Store unloading records", { setup: function() { @@ -23,6 +23,8 @@ module("unit/store/unload - Store unloading records", { }); test("unload a dirty record", function() { + expect(2); + run(function(){ store.push(Record, { id: 1, @@ -48,6 +50,8 @@ test("unload a dirty record", function() { }); test("unload a record", function() { + expect(5); + run(function(){ store.push(Record, {id: 1, title: 'toto'}); store.find(Record, 1).then(function(record) { @@ -73,6 +77,8 @@ module("DS.Store - unload record with relationships"); test("can commit store after unload record with relationships", function() { + expect(1); + var like, product; var Brand = DS.Model.extend({ From a71d693f36ab5b24c5d464701c479a5fcdd86484 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Wed, 7 Jan 2015 18:40:12 -0500 Subject: [PATCH 0577/2527] Run JSHint on Test Suite Test suite should comply with JSHint standards and conventions --- Brocfile.js | 4 +- .../lib/system/relationships/belongs_to.js | 1 - .../integration/adapter/rest_adapter_test.js | 4 +- .../tests/integration/filter_test.js | 2 +- .../integration/record_array_manager_test.js | 3 +- .../relationships/belongs_to_test.js | 27 ++++-------- .../relationships/has_many_test.js | 44 +++++++------------ .../inverse_relationships_test.js | 6 +-- .../embedded_records_mixin_test.js | 2 +- packages/ember-data/tests/unit/debug_test.js | 1 - .../ember-data/tests/unit/store/push_test.js | 4 +- .../tests/unit/transform/number_test.js | 2 + 12 files changed, 38 insertions(+), 62 deletions(-) diff --git a/Brocfile.js b/Brocfile.js index 4a133477155..b421d0e3ca4 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -41,14 +41,14 @@ function testTree(packageName){ files: [ '**/*.js' ], destDir: '/' + packageName }); - var jshinted = jshint('packages/' + packageName + '/lib', { + var jshinted = jshint('packages/' + packageName + '/', { jshintrcPath: path.join(__dirname, '.jshintrc') }); jshinted = wrap(jshinted, { wrapper: [ "if (!QUnit.urlParams.nojshint) {\n", "\n}"], }); jshinted = pickFiles(jshinted, { - files: ['**/*.js'], + files: ['{lib,tests}/**/*.js'], srcDir: '/', destDir: '/' + packageName + '-jshint' }); diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index cfcc259ed6d..6bd9c181225 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -1,6 +1,5 @@ import { Model } from 'ember-data/system/model'; - /** `DS.belongsTo` is used to define One-To-One and One-To-Many relationships on a [DS.Model](/api/data/classes/DS.Model.html). diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index c9fefdadebc..8db9beec8a2 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -1738,7 +1738,7 @@ test("rejects promise if DS.InvalidError is returned from adapter.ajaxSuccess", var jqXHR = {}; var data = { something: 'is invalid' - } + }; Ember.$.ajax = function(hash) { hash.success(data, 'ok', jqXHR); @@ -1752,7 +1752,7 @@ test("rejects promise if DS.InvalidError is returned from adapter.ajaxSuccess", Ember.run(function() { store.find('post', '1').then(null, function(reason) { ok(true, 'promise should be rejected'); - ok(reason instanceof DS.InvalidError, 'reason should be an instance of DS.InvalidError') + ok(reason instanceof DS.InvalidError, 'reason should be an instance of DS.InvalidError'); }); }); diff --git a/packages/ember-data/tests/integration/filter_test.js b/packages/ember-data/tests/integration/filter_test.js index 0ef3572726b..ef222993538 100644 --- a/packages/ember-data/tests/integration/filter_test.js +++ b/packages/ember-data/tests/integration/filter_test.js @@ -34,7 +34,7 @@ function tapFn(fn, callback) { var new_fn = function() { var result = old_fn.apply(this, arguments); if (callback) { - callback.apply(obj, arguments); + callback.apply(fn, arguments); } new_fn.summary.called.push(arguments); return result; diff --git a/packages/ember-data/tests/integration/record_array_manager_test.js b/packages/ember-data/tests/integration/record_array_manager_test.js index bc08c6894a4..f8af1deda0c 100644 --- a/packages/ember-data/tests/integration/record_array_manager_test.js +++ b/packages/ember-data/tests/integration/record_array_manager_test.js @@ -105,10 +105,9 @@ test("destroying the store correctly cleans everything up", function() { test("Should not filter a stor.all() array when a record property is changed", function() { var car; - var filterdSummary = tap(store.recordArrayManager, 'updateRecordArray'); - var allCars = store.all('car'); + store.all('car'); run(function(){ car = store.push('car', { diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index 752df083058..90788c4201f 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -1,14 +1,12 @@ -var env, store, User, Message, Post, Comment, Book, Author, NewMessage; +var env, store, User, Message, Post, Contact, Comment, Book, Author, NewMessage; var get = Ember.get; var run = Ember.run; -var attr = DS.attr, hasMany = DS.hasMany, belongsTo = DS.belongsTo; +var attr = DS.attr; +var hasMany = DS.hasMany; +var belongsTo = DS.belongsTo; var hash = Ember.RSVP.hash; -function stringify(string) { - return function() { return string; }; -} - module("integration/relationship/belongs_to Belongs-To Relationships", { setup: function() { User = DS.Model.extend({ @@ -16,36 +14,30 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { messages: hasMany('message', {polymorphic: true}), favouriteMessage: belongsTo('message', {polymorphic: true, inverse: null}), }); - User.toString = stringify('User'); Message = DS.Model.extend({ user: belongsTo('user', { inverse: 'messages' }), created_at: attr('date') }); - Message.toString = stringify('Message'); Post = Message.extend({ title: attr('string'), comments: hasMany('comment') }); - Post.toString = stringify('Post'); Comment = Message.extend({ body: DS.attr('string'), message: DS.belongsTo('message', { polymorphic: true }) }); - Comment.toString = stringify('Comment'); Book = DS.Model.extend({ name: attr('string'), author: belongsTo('author') }); - Book.toString = stringify('Book'); Author = DS.Model.extend({ name: attr('string') }); - Author.toString = stringify('Author'); env = setupStore({ user: User, @@ -343,7 +335,6 @@ test("relationshipsByName does not cache a factory", function() { // A new model for a relationship is created. Note that this may happen // due to an extend call internal to MODEL_FACTORY_INJECTIONS. NewMessage = Message.extend(); - NewMessage.toString = stringify('Message'); // A new store is created. env = setupStore({ @@ -353,17 +344,17 @@ test("relationshipsByName does not cache a factory", function() { store = env.store; // relationshipsByName is called again. - var modelViaSecondFactory = store.modelFor('user'), - relationshipsByName = get(modelViaSecondFactory, 'relationshipsByName'), - messageType = relationshipsByName.get('messages').type; + var modelViaSecondFactory = store.modelFor('user'); + var relationshipsByName = get(modelViaSecondFactory, 'relationshipsByName'); + var messageType = relationshipsByName.get('messages').type; // A model is looked up in the store based on a string, via user input var messageModelFromStore = store.modelFor('message'); // And the model is lookup up internally via the relationship type var messageModelFromRelationType = store.modelFor(messageType); - equal( messageModelFromRelationType, messageModelFromStore, - "model factory based on relationship type matches the model based on store.modelFor" ); + equal(messageModelFromRelationType, messageModelFromStore, + "model factory based on relationship type matches the model based on store.modelFor"); }); test("relationshipsByName is cached in production", function() { diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 16157581d1a..d344bab2f1f 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -714,8 +714,9 @@ test("Polymorphic relationships with a hasMany is set up correctly on both sides Post.reopen({ contact: DS.belongsTo('contact', { polymorphic: true }) }); + var email, post; - Ember.run(function () { + run(function () { email = env.store.createRecord('email'); post = env.store.createRecord('post', { contact: email @@ -825,7 +826,7 @@ test("When a record is created on the client, its hasMany arrays should be in a var post; - Ember.run(function() { + run(function() { post = env.store.createRecord('post'); }); @@ -847,7 +848,7 @@ test("When a record is created on the client, its async hasMany arrays should be comments: DS.hasMany('comment', { async: true }) }); - var post = Ember.run(function() { + var post = run(function() { return env.store.createRecord('post'); }); @@ -864,7 +865,7 @@ test("When a record is created on the client, its async hasMany arrays should be test("a records SYNC HM relationship property is readOnly", function(){ expect(1); - var post = Ember.run(function() { + var post = run(function() { return env.store.createRecord('post'); }); @@ -880,7 +881,7 @@ test("a records ASYNC HM relationship property is readOnly", function(){ comments: DS.hasMany('comment', { async: true }) }); - var post = Ember.run(function() { + var post = run(function() { return env.store.createRecord('post'); }); @@ -898,7 +899,7 @@ test("When a record is saved, its unsaved hasMany records should be kept", funct return Ember.RSVP.resolve({ id: 1 }); }; - Ember.run(function () { + run(function () { post = env.store.createRecord('post'); comment = env.store.createRecord('comment'); post.get('comments').pushObject(comment); @@ -1098,7 +1099,7 @@ test("ManyArray notifies the array observers and flushes bindings when removing" expect(2); var chapter, page, page2; var observe = false; - var arr = Ember.A([1,2]); + run(function(){ page = env.store.push('page', { id: 1, number: 1 }); page2 = env.store.push('page', { id: 2, number: 2 }); @@ -1127,7 +1128,7 @@ test("ManyArray notifies the array observers and flushes bindings when adding", expect(2); var chapter, page, page2; var observe = false; - var arr = Ember.A([1,2]); + run(function(){ page = env.store.push('page', { id: 1, number: 1 }); page2 = env.store.push('page', { id: 2, number: 2 }); @@ -1170,24 +1171,15 @@ test("Relationship.clear removes all records correctly", function(){ run(function(){ post = env.store.push('post', { id: 2, title: 'Sailing the Seven Seas', comments: [1,2] }); env.store.pushMany('comment', [ - { - id: 1, - post: 2 - }, - { - id: 2, - post: 2 - }, - { - id: 3, - post: 2 - } + { id: 1, post: 2 }, + { id: 2, post: 2 }, + { id: 3, post: 2 } ]); }); run(function(){ post._relationships['comments'].clear(); - var comments = Em.A(env.store.all('comment')); + var comments = Ember.A(env.store.all('comment')); deepEqual(comments.mapBy('post'), [undefined, undefined, undefined]); }); @@ -1200,14 +1192,8 @@ test('unloading a record with associated records does not prevent the store from run(function(){ post = env.store.push('post', { id: 2, title: 'Sailing the Seven Seas', comments: [1,2] }); env.store.pushMany('comment', [ - { - id: 1, - post: 2 - }, - { - id: 2, - post: 2 - } + { id: 1, post: 2 }, + { id: 2, post: 2 } ]); // This line triggers the original bug that gets manifested diff --git a/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js b/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js index 85babca5a0e..acd59604d7e 100644 --- a/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js +++ b/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js @@ -177,6 +177,7 @@ test("When setting a belongsTo, the OneToOne invariant is transitive", function( post: Post, comment: Comment }); + var post, post2, comment; run(function(){ comment = store.createRecord('comment'); @@ -214,14 +215,13 @@ test("When setting a belongsTo, the OneToOne invariant is commutative", function post: Post, comment: Comment }); + var post, comment, comment2; run(function(){ - comment = store.createRecord('comment'); post = store.createRecord('post'); + comment = store.createRecord('comment'); comment2 = store.createRecord('comment'); - }); - run(function(){ comment.set('post', post); }); diff --git a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js index 0caf982616f..a8aee448763 100644 --- a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js +++ b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js @@ -1,5 +1,5 @@ var get = Ember.get; -var HomePlanet, SuperVillain, EvilMinion, SecretLab, SecretWeapon, Comment, +var HomePlanet, SuperVillain, EvilMinion, SecretLab, SecretWeapon, BatCave, Comment, league, superVillain, evilMinion, secretWeapon, homePlanet, secretLab, env; var indexOf = Ember.EnumerableUtils.indexOf; var run = Ember.run; diff --git a/packages/ember-data/tests/unit/debug_test.js b/packages/ember-data/tests/unit/debug_test.js index 15fcf05d00b..20c723a682b 100644 --- a/packages/ember-data/tests/unit/debug_test.js +++ b/packages/ember-data/tests/unit/debug_test.js @@ -1,4 +1,3 @@ -var store; var run = Ember.run; var TestAdapter = DS.Adapter.extend(); diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index 78425309eeb..1c464fe9e9f 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -192,7 +192,7 @@ test("Calling push with partial records triggers observers for just those attrib }); test("Calling push with a normalized hash containing related records returns a record", function() { - var number1, number, person; + var number1, number2, person; run(function(){ number1 = store.push('phone-number', { id: 1, @@ -420,7 +420,7 @@ test("Calling pushPayload allows partial updates with raw JSON", function () { }); }); - var person = store.getById('person', 1); + person = store.getById('person', 1); equal(person.get('firstName'), "Robert", "you can push raw JSON into the store"); equal(person.get('lastName'), "Jackson", "you can push raw JSON into the store"); diff --git a/packages/ember-data/tests/unit/transform/number_test.js b/packages/ember-data/tests/unit/transform/number_test.js index 0ad9843ccfd..81f880f41cb 100644 --- a/packages/ember-data/tests/unit/transform/number_test.js +++ b/packages/ember-data/tests/unit/transform/number_test.js @@ -1,3 +1,5 @@ +/* jshint -W053 */ + module("unit/transform - DS.NumberTransform"); test("#serialize", function() { From 8da74f3dffb956b4f2f09c6f70f334ad0e7767c2 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 7 Jan 2015 15:21:26 +0100 Subject: [PATCH 0578/2527] Disable unknown keys warning by default - Rename flag to DS_WARN_ON_UNKNOWN_KEYS, set to true to enable warnings - Don't warn for keys ending with "Type" --- packages/ember-data/lib/system/store.js | 10 +++++----- packages/ember-data/tests/unit/store/push_test.js | 13 +++++++------ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 4c3b12752d9..ec0f4f2d48d 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1400,15 +1400,15 @@ Store = Ember.Object.extend({ var type = this.modelFor(typeName); var filter = Ember.EnumerableUtils.filter; - // If the payload contains unused keys log a warning. - // Adding `Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS = true` will suppress the warning. - if (!Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS) { + // If Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload + // contains unknown keys, log a warning. + if (Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS) { Ember.warn("The payload for '" + type.typeKey + "' contains these unknown keys: " + Ember.inspect(filter(Ember.keys(data), function(key) { - return !get(type, 'fields').has(key) && key !== 'id' && key !== 'links'; + return !(key === 'id' || key === 'links' || get(type, 'fields').has(key) || key.match(/Type$/)); })) + ". Make sure they've been defined in your model.", filter(Ember.keys(data), function(key) { - return !get(type, 'fields').has(key) && key !== 'id' && key !== 'links'; + return !(key === 'id' || key === 'links' || get(type, 'fields').has(key) || key.match(/Type$/)); }).length === 0 ); } diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index 78425309eeb..355e52ce648 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -568,11 +568,12 @@ test('calling push with an embedded relationship throws a useful error', functio }, /If this is an embedded relationship/); }); -test("Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS suppresses unknown keys warning", function() { +test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown keys", function() { run(function(){ + var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; try { - Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS = true; - noWarns(function() { + Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; + warns(function() { store.push('person', { id: '1', firstName: 'Tomster', @@ -581,13 +582,13 @@ test("Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS suppresses unknown keys warning", func }); }); } finally { - Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS = null; + Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = originalFlagValue; } }); }); -test("Calling push with unknown keys in the provided payload should warn", function() { - warns(function() { +test("Calling push with unknown keys should not warn by default", function() { + noWarns(function() { run(function(){ store.push('person', { id: '1', From 1f9973e78d32c7dc2b739d2581186483424483ff Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 7 Jan 2015 15:31:56 +0100 Subject: [PATCH 0579/2527] Test warnings cleanup --- .../active_model_serializer_test.js | 9 +++------ .../relationships/has_many_test.js | 20 +++++++++++++++++-- .../embedded_records_mixin_test.js | 2 +- .../unit/model/lifecycle_callbacks_test.js | 3 +++ packages/ember-data/tests/unit/model_test.js | 7 ++++--- .../ember-data/tests/unit/store/push_test.js | 6 +++++- .../tests/unit/store/unload_test.js | 3 ++- 7 files changed, 36 insertions(+), 14 deletions(-) diff --git a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js index af3cb08f0d3..e5f2a3b54bb 100644 --- a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js +++ b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js @@ -233,8 +233,7 @@ test("extractPolymorphic hasMany", function() { YellowMinion.toString = function() { return "YellowMinion"; }; var json_hash = { - mediocre_villain: {id: 1, name: "Dr Horrible", evil_minions: [{ type: "yellow_minion", id: 12}] }, - evil_minions: [{id: 12, name: "Alex", doomsday_device_ids: [1] }] + mediocre_villain: { id: 1, name: "Dr Horrible", evil_minions: [{ type: "yellow_minion", id: 12 }] } }; var json; @@ -258,8 +257,7 @@ test("extractPolymorphic", function() { YellowMinion.toString = function() { return "YellowMinion"; }; var json_hash = { - doomsday_device: {id: 1, name: "DeathRay", evil_minion: { type: "yellow_minion", id: 12}}, - evil_minions: [{id: 12, name: "Alex", doomsday_device_ids: [1] }] + doomsday_device: { id: 1, name: "DeathRay", evil_minion: { type: "yellow_minion", id: 12 } } }; var json; @@ -279,8 +277,7 @@ test("extractPolymorphic", function() { test("extractPolymorphic when the related data is not specified", function() { var json = { - doomsday_device: {id: 1, name: "DeathRay"}, - evil_minions: [{id: 12, name: "Alex", doomsday_device_ids: [1] }] + doomsday_device: { id: 1, name: "DeathRay" } }; run(function(){ diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 16157581d1a..bfef7b88882 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -1167,8 +1167,16 @@ test("Passing a model as type to hasMany should not work", function () { test("Relationship.clear removes all records correctly", function(){ var post; + Comment.reopen({ + post: DS.belongsTo('post') + }); + + Post.reopen({ + comments: DS.hasMany('comment', { inverse: 'post' }) + }); + run(function(){ - post = env.store.push('post', { id: 2, title: 'Sailing the Seven Seas', comments: [1,2] }); + post = env.store.push('post', { id: 2, title: 'Sailing the Seven Seas', comments: [1, 2] }); env.store.pushMany('comment', [ { id: 1, @@ -1188,7 +1196,7 @@ test("Relationship.clear removes all records correctly", function(){ run(function(){ post._relationships['comments'].clear(); var comments = Em.A(env.store.all('comment')); - deepEqual(comments.mapBy('post'), [undefined, undefined, undefined]); + deepEqual(comments.mapBy('post'), [null, null, null]); }); }); @@ -1197,6 +1205,14 @@ test("Relationship.clear removes all records correctly", function(){ test('unloading a record with associated records does not prevent the store from tearing down', function(){ var post; + Comment.reopen({ + post: DS.belongsTo('post') + }); + + Post.reopen({ + comments: DS.hasMany('comment', { inverse: 'post' }) + }); + run(function(){ post = env.store.push('post', { id: 2, title: 'Sailing the Seven Seas', comments: [1,2] }); env.store.pushMany('comment', [ diff --git a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js index 0caf982616f..5d138dac790 100644 --- a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js +++ b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js @@ -1054,7 +1054,7 @@ test("extractSingle with multiply-nested belongsTo", function() { home_planet: { id: "1", name: "Umber", - super_villain_ids: ["1"] + villain_ids: ["1"] } } } diff --git a/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js b/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js index af1146fa00c..f0288a1e100 100644 --- a/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js +++ b/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js @@ -34,6 +34,7 @@ test("a record receives a didUpdate callback when it has finished updating", fun var Person = DS.Model.extend({ bar: DS.attr('string'), + name: DS.attr('string'), didUpdate: function() { callCount++; @@ -119,6 +120,7 @@ test("a record receives a didDelete callback when it has finished deleting", fun var Person = DS.Model.extend({ bar: DS.attr('string'), + name: DS.attr('string'), didDelete: function() { callCount++; @@ -168,6 +170,7 @@ test("a record receives a becameInvalid callback when it became invalid", functi var Person = DS.Model.extend({ bar: DS.attr('string'), + name: DS.attr('string'), becameInvalid: function() { callCount++; diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index 682972842ac..6a8185a87b5 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -100,7 +100,7 @@ test("a record's id is included in its toString representation", function() { test("trying to set an `id` attribute should raise", function() { Person = DS.Model.extend({ id: DS.attr('number'), - name: "Scumdale" + name: DS.attr('string'), }); expectAssertion(function() { @@ -575,7 +575,7 @@ test("ensure model exits loading state, materializes data and fulfills promise o var store = createStore({ adapter: DS.Adapter.extend({ find: function(store, type, id) { - return Ember.RSVP.resolve({ id: 1, name: "John", isDrugAddict: false }); + return Ember.RSVP.resolve({ id: 1, name: "John" }); } }) }); @@ -604,7 +604,8 @@ test("A DS.Model can be JSONified", function() { test("A subclass of DS.Model can not use the `data` property", function() { var Person = DS.Model.extend({ - data: DS.attr('string') + data: DS.attr('string'), + name: DS.attr('string') }); var store = createStore({ person: Person }); diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index c874995828e..9098452ed50 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -102,7 +102,7 @@ test("Calling push triggers `didLoad` even if the record hasn't been requested f test("Calling update should be deprecated", function() { expectDeprecation(function() { run(function() { - store.update('person', { id: '1', name: 'Tomster' }); + store.update('person', { id: '1', firstName: 'Yehuda', lastName: 'Katz' }); }); }); }); @@ -467,6 +467,10 @@ test('Calling push with a link for a non async relationship should warn', functi }); test('Calling push with a link containing an object throws an assertion error', function() { + Person.reopen({ + phoneNumbers: hasMany('phone-number', { async: true }) + }); + expectAssertion(function() { run(function(){ store.push('person', { diff --git a/packages/ember-data/tests/unit/store/unload_test.js b/packages/ember-data/tests/unit/store/unload_test.js index 73740c87154..220a77a0e99 100644 --- a/packages/ember-data/tests/unit/store/unload_test.js +++ b/packages/ember-data/tests/unit/store/unload_test.js @@ -13,7 +13,8 @@ module("unit/store/unload - Store unloading records", { }); Record = DS.Model.extend({ - title: DS.attr('string') + title: DS.attr('string'), + wasFetched: DS.attr('boolean') }); }, From 151739f0a8fd4a8e1a187f6679d1c09efb79b1f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kim=20R=C3=B8en?= Date: Sat, 10 Jan 2015 22:19:05 +0100 Subject: [PATCH 0580/2527] Use forEach instead of private api for accessing Map values --- .../ember-data/lib/system/record_array_manager.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index 1cd983e3b4f..b0a983a0682 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -261,22 +261,13 @@ export default Ember.Object.extend({ willDestroy: function(){ this._super(); - forEach(flatten(values(this.filteredRecordArrays.values)), destroy); + this.filteredRecordArrays.forEach(function(value) { + forEach(flatten(value), destroy); + }); forEach(this._adapterPopulatedRecordArrays, destroy); } }); -function values(obj) { - var result = []; - var keys = Ember.keys(obj); - - for (var i = 0; i < keys.length; i++) { - result.push(obj[keys[i]]); - } - - return result; -} - function destroy(entry) { entry.destroy(); } From 8f82335238c830775e5360925aab2bb2428b0826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kim=20R=C3=B8en?= Date: Sat, 10 Jan 2015 22:19:32 +0100 Subject: [PATCH 0581/2527] Re-enable canary tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5c8eb2441e9..09e6e42467c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ install: script: - npm run-script test - npm run-script test:beta -# - npm run-script test:canary + - npm run-script test:canary after_success: - npm run-script publish-build - "./bin/bower-ember-data-build" From 66f9ac189add12e4454d30efeda6f56c5ed60d3e Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 14 Jan 2015 12:03:38 -0500 Subject: [PATCH 0582/2527] Wrap the errorThrown in an Error object if it's a string. --- .../ember-data/lib/adapters/rest_adapter.js | 6 ++++- .../integration/adapter/rest_adapter_test.js | 27 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 4184d92c989..0a8020a385d 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -747,7 +747,11 @@ export default Adapter.extend({ if (isObject) { jqXHR.then = null; if (!jqXHR.errorThrown) { - jqXHR.errorThrown = errorThrown; + if (typeof errorThrown === 'string') { + jqXHR.errorThrown = new Error(errorThrown); + } else { + jqXHR.errorThrown = errorThrown; + } } } diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 8db9beec8a2..7012b448e00 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -1793,3 +1793,30 @@ test('ajaxError appends errorThrown for sanity', function() { Ember.$.ajax = originalAjax; } }); + + +test('ajaxError wraps the error string in an Error object', function() { + expect(2); + + var originalAjax = Ember.$.ajax; + var jqXHR = { + responseText: 'Nope lol' + }; + + var errorThrown = 'nope!'; + + Ember.$.ajax = function(hash) { + hash.error(jqXHR, jqXHR.responseText, errorThrown); + }; + + try { + run(function(){ + store.find('post', '1').catch(function(err){ + equal(err.errorThrown.message, errorThrown); + ok(err, 'promise rejected'); + }); + }); + } finally { + Ember.$.ajax = originalAjax; + } +}); From b36ca0e1df6aa5fe794ddec0b5b84dec5f6dd624 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Wed, 14 Jan 2015 12:05:25 -0500 Subject: [PATCH 0583/2527] Remove `package.json` files Package-specific `package.json` files are out of date and no longer necessary. --- packages/activemodel-adapter/package.json | 24 ------------------ packages/ember-data/package.json | 31 ----------------------- 2 files changed, 55 deletions(-) delete mode 100644 packages/activemodel-adapter/package.json delete mode 100644 packages/ember-data/package.json diff --git a/packages/activemodel-adapter/package.json b/packages/activemodel-adapter/package.json deleted file mode 100644 index 2144f351e92..00000000000 --- a/packages/activemodel-adapter/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "activemodel-adapter", - "summary": "ActiveModelAdapter for Ember Data", - "description": "", - "homepage": "http://github.com/emberjs/ember.js", - "author": ["Bradley Priest"], - "version": "1.0.0-beta.1", - - "directories":{ - "lib": "lib" - }, - - "dependencies": { - "ember-runtime": "1.0.0", - "ember-data": "1.0.0" - }, - - "bpm:build": { - "bpm_lib.js": { - "files": ["lib"], - "modes": "*" - } - } -} diff --git a/packages/ember-data/package.json b/packages/ember-data/package.json deleted file mode 100644 index fcb72f579e1..00000000000 --- a/packages/ember-data/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "ember-data", - "summary": "Short package description", - "description": "Ember Data is a library for loading records from a persistence layer (such as a JSON API), updating those records, then saving the changes. It provides many of the facilities you'd find in server-side ORMs like ActiveRecord, but is designed specifically for the unique environment of JavaScript in the browser.", - "homepage": "https://github.com/emberjs/data", - "author": "Tom Dale, Yehuda Katz, and contributors", - "version": "1.0.0-beta.2", - - "directories": { - "lib": "lib" - }, - - "dependencies": { - "spade": "~> 1.0", - "ember-runtime": "1.0.0", - "ember-inflector": "1.0.0" - }, - "dependencies:development": { - "spade-qunit": "~> 1.0.0" - }, - "bpm:build": { - "bpm_libs.js": { - "files": ["lib"], - "modes": "*" - }, - "ember-data/bpm_tests.js": { - "files": ["tests"], - "modes": ["debug"] - } - } -} From d888adf9262f51dad53a0368908c024f30a4a1e9 Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 15 Jan 2015 10:00:55 -0500 Subject: [PATCH 0584/2527] Display the correct doc block for the model header. --- packages/ember-data/lib/system/relationships/belongs_to.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index 6bd9c181225..e6281ce9917 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -92,12 +92,9 @@ function belongsTo(type, options) { }).meta(meta); } -/** +/* These observers observe all `belongsTo` relationships on the record. See `relationships/ext` to see how these observers get their dependencies. - - @class Model - @namespace DS */ Model.reopen({ notifyBelongsToChanged: function(key) { From f9994e81cb35c2f7ecf4f7a0b85bbd289b772af6 Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 15 Jan 2015 10:41:03 -0500 Subject: [PATCH 0585/2527] Document the signature of the callback that is passed into eachRelationship Closes #2616 --- .../lib/system/relationships/ext.js | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 997189395c6..f93b0ec005c 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -560,6 +560,47 @@ Model.reopen({ invoking the callback with the name of each relationship and its relationship descriptor. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(name, descriptor); + ``` + + - `name` the name of the current property in the iteration + - `descriptor` the meta object that describes this relationship + + The relationship descriptor argument is an object with the following properties. + + - **key** String the name of this relationship on the Model + - **kind** String "hasMany" or "belongsTo" + - **options** Object the original options hash passed when the relationship was declared + - **parentType** DS.Model the type of the Model that owns this relationship + - **type** DS.Model the type of the related Model + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. + + Example + + ```javascript + App.ApplicationSerializer = DS.JSONSerializer.extend({ + serialize: function(record, options) { + var json = {}; + + record.eachRelationship(function(name, descriptor) { + if (descriptor.kind === 'hasMany') { + var serializedHasManyName = name.toUpperCase() + '_IDS'; + json[name.toUpperCase()] = record.get(name).mapBy('id'); + } + }); + + return json; + } + }); + ``` + @method eachRelationship @param {Function} callback the callback to invoke @param {any} binding the value to which the callback's `this` should be bound From dcd52b3ee4c8aa928cf80e855be30fe9f117b1ff Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 15 Jan 2015 12:59:58 -0500 Subject: [PATCH 0586/2527] Favor `object` over `hash` in public documentation and assertions Closes #1892 --- packages/ember-data/lib/adapters/rest_adapter.js | 6 +++--- packages/ember-data/lib/system/model/model.js | 2 +- packages/ember-data/lib/system/store.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 4184d92c989..5bab142cc7c 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -801,7 +801,7 @@ export default Adapter.extend({ @private @param {String} url @param {String} type The request type GET, POST, PUT, DELETE etc. - @param {Object} hash + @param {Object} options @return {Promise} promise */ ajax: function(url, type, options) { @@ -832,8 +832,8 @@ export default Adapter.extend({ @private @param {String} url @param {String} type The request type GET, POST, PUT, DELETE etc. - @param {Object} hash - @return {Object} hash + @param {Object} options + @return {Object} */ ajaxOptions: function(url, type, options) { var hash = options || {}; diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 1c1cd5cd454..adedb98b0f6 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -918,7 +918,7 @@ var Model = Ember.Object.extend(Ember.Evented, { }, materializeAttributes: function(attributes) { - Ember.assert("Must pass a hash of attributes to materializeAttributes", !!attributes); + Ember.assert("Must pass an object to materializeAttributes", !!attributes); merge(this._data, attributes); }, diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index ec0f4f2d48d..af316537ccd 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1753,7 +1753,7 @@ function deserializeRecordId(store, data, key, relationship, id) { data[key] = store.recordForId(type, id); } else if (typeof id === 'object') { // hasMany polymorphic - Ember.assert('Ember Data expected a number or string to represent the record(s) in the `' + relationship.key + '` relationship instead it found an object. If this is a polymorphic relationship please specify a `type` key. If this is an embedded relationship please include the `DS.EmbeddedRecordsMixin` and specify the `' + relationship.key +'` property in your serializer\'s attrs hash.', id.type); + Ember.assert('Ember Data expected a number or string to represent the record(s) in the `' + relationship.key + '` relationship instead it found an object. If this is a polymorphic relationship please specify a `type` key. If this is an embedded relationship please include the `DS.EmbeddedRecordsMixin` and specify the `' + relationship.key +'` property in your serializer\'s attrs object.', id.type); data[key] = store.recordForId(id.type, id.id); } } From f31311ded19fc24c6fe45ea95df31ca7fd8d0d7d Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Thu, 15 Jan 2015 13:20:09 -0500 Subject: [PATCH 0587/2527] Update examples to use multi-var syntax Updating to use same style that Ember uses. --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 60f6451aeb1..adcf67ac725 100644 --- a/README.md +++ b/README.md @@ -57,9 +57,9 @@ Here's what your model definition would look like if you're using globals (that is, not something like Ember App Kit or ember-cli): ```js -var attr = DS.attr, - hasMany = DS.hasMany, - belongsTo = DS.belongsTo; +var attr = DS.attr; +var hasMany = DS.hasMany; +var belongsTo = DS.belongsTo; App.BlogPost = DS.Model.extend({ title: attr(), @@ -81,8 +81,8 @@ models would look like this: ```js // app/models/blog-post.js -var attr = DS.attr, - hasMany = DS.hasMany; +var attr = DS.attr; +var hasMany = DS.hasMany; export default DS.Model.extend({ title: attr(), @@ -92,8 +92,8 @@ export default DS.Model.extend({ }); // app/models/comment.js -var attr = DS.attr, - belongsTo = DS.belongsTo; +var attr = DS.attr; +var belongsTo = DS.belongsTo; export default DS.Model.extend({ body: attr(), From fca0dd43611b7ba3070b72db642df9b7a4a6b64a Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 15 Jan 2015 15:53:04 -0500 Subject: [PATCH 0588/2527] Document that ManyArrays are no longer RecordArrays in the changelog. Closes #2611 Closes #2665 --- CHANGELOG.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b086064b93a..640f6ec7ce4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -93,6 +93,27 @@ export default DS.RESTSerializer.extend({ Please use `store.metadataFor()` to get metadata and `store.setMetadataFor()` to set metadata. + +##### `ManyArray`s are no longer `RecordArray`s +[ManyArray](http://emberjs.com/api/data/classes/DS.ManyArray.html), +the object Ember Data uses to represent `DS.hasMany` relationships has +been changed so it no longer extends from `RecordArray`. This means if +you were relying on the RecordArray's `content` property to access the +underlying array you will now need to use the `.toArray()` method. + +```javascript +// Ember Data 1.0.0-beta.12 +record.get('myHasManyRelationship').get('content').map(...); + +// Ember Data 1.0.0-beta.14 +record.get('myHasManyRelationship').toArray().map(...); +``` + +Additionally if you were using the `RecordArray`'s `.addRecord()` and +`.removeRecord()` methods you will now need to use the `.addObject()` +/ `.removeObject()` array methods. + + #### Changes * Fix references to buildURL in documentation From 9800a92d1415352ce34854f8cb6e1d6cc98e0b3d Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 15 Jan 2015 17:25:13 -0500 Subject: [PATCH 0589/2527] Deprecate RecordArray.pushRecord() Closes #2612 --- packages/ember-data/lib/system/record_array_manager.js | 2 +- .../ember-data/lib/system/record_arrays/record_array.js | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index b0a983a0682..c84ea2f102a 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -126,7 +126,7 @@ export default Ember.Object.extend({ if (shouldBeInArray) { if (!recordArrays.has(array)) { - array.pushRecord(record); + array._pushRecord(record); recordArrays.add(array); } } else if (!shouldBeInArray) { diff --git a/packages/ember-data/lib/system/record_arrays/record_array.js b/packages/ember-data/lib/system/record_arrays/record_array.js index 985379d0562..5a6d3ebf366 100644 --- a/packages/ember-data/lib/system/record_arrays/record_array.js +++ b/packages/ember-data/lib/system/record_arrays/record_array.js @@ -137,15 +137,21 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { } }, + _pushRecord: function(record) { + get(this, 'content').pushObject(record); + }, + /** Adds a record to the `RecordArray`, but allows duplicates + @deprecated @method pushRecord @private @param {DS.Model} record */ pushRecord: function(record) { - get(this, 'content').pushObject(record); + Ember.deprecate('Usage of `recordArray.pushRecord` is deprecated, use `recordArray.addObject` instead'); + this._pushRecord(record); }, /** Removes a record to the `RecordArray`. From 4446853c8dedf25fed505c18b969f463fa924e4c Mon Sep 17 00:00:00 2001 From: "Andrey Mikhaylov (lolmaus)" Date: Mon, 19 Jan 2015 18:04:15 +0300 Subject: [PATCH 0590/2527] Fixed `@extends` and `@uses` for ManyArray doc @extends Ember.Object @uses Ember.MutableArray, Ember.Evented --- packages/ember-data/lib/system/record_arrays/many_array.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index a77bb65af4b..ff3e9a805fa 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -38,7 +38,8 @@ var get = Ember.get, set = Ember.set; @class ManyArray @namespace DS - @extends DS.RecordArray + @extends Ember.Object + @uses Ember.MutableArray, Ember.Evented */ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { init: function() { From 849934bb5052c30a96a58161af7e2c0ea4379cc5 Mon Sep 17 00:00:00 2001 From: Pepe Cano Date: Mon, 19 Jan 2015 16:40:23 +0100 Subject: [PATCH 0591/2527] Fix: root.deleted.invalid state --- .../ember-data/lib/system/model/states.js | 31 +++++++++++++ .../tests/unit/model/rollback_test.js | 46 +++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index 57a01a09d43..d29b8f5f090 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -658,6 +658,11 @@ var RootState = { becameError: function(record) { record.transitionTo('uncommitted'); record.triggerLater('becameError', record); + }, + + becameInvalid: function(record) { + record.transitionTo('invalid'); + record.triggerLater('becameInvalid', record); } }, @@ -681,6 +686,32 @@ var RootState = { willCommit: Ember.K, didCommit: Ember.K + }, + + invalid: { + isValid: false, + + didSetProperty: function(record, context) { + get(record, 'errors').remove(context.name); + + didSetProperty(record, context); + }, + + deleteRecord: Ember.K, + becomeDirty: Ember.K, + willCommit: Ember.K, + + + rolledBack: function(record) { + get(record, 'errors').clear(); + record.transitionTo('loaded.saved'); + record.triggerLater('ready'); + }, + + becameValid: function(record) { + record.transitionTo('uncommitted'); + } + } }, diff --git a/packages/ember-data/tests/unit/model/rollback_test.js b/packages/ember-data/tests/unit/model/rollback_test.js index 158f614f6bc..faa2aebcd78 100644 --- a/packages/ember-data/tests/unit/model/rollback_test.js +++ b/packages/ember-data/tests/unit/model/rollback_test.js @@ -281,3 +281,49 @@ test("invalid record is rolled back to correct state after set", function() { })); }); }); + +test("when destroying a record setup the record state to invalid, the record can be rollbacked", function() { + Dog = DS.Model.extend({ + name: DS.attr() + }); + + var adapter = DS.RESTAdapter.extend({ + ajax: function(url, type, hash) { + var adapter = this; + + return new Ember.RSVP.Promise(function(resolve, reject) { + Ember.run.next(function(){ + reject(adapter.ajaxError({name: 'is invalid'})); + }); + }); + }, + + ajaxError: function(jqXHR) { + return new DS.InvalidError(jqXHR); + } + }); + + env = setupStore({ dog: Dog, adapter: adapter}); + var dog; + run(function(){ + dog = env.store.push('dog', { id: 1, name: "Pluto" }); + }); + + run(function(){ + dog.destroyRecord().then(null, async(function() { + + + equal(dog.get('isError'), false, "must not be error"); + equal(dog.get('isDeleted'), true, "must be deleted"); + equal(dog.get('isValid'), false, "must not be valid"); + ok(dog.get('errors.length') > 0, "must have errors"); + + dog.rollback(); + + equal(dog.get('isError'), false, "must not be error after `rollback`"); + equal(dog.get('isDeleted'), false, "must not be deleted after `rollback`"); + equal(dog.get('isValid'), true, "must be valid after `rollback`"); + ok(dog.get('errors.length') === 0, "must not have errors"); + })); + }); +}); From 4d7a4ce323ac1f3975ed7350c6883da61a04f5b4 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Wed, 7 Jan 2015 19:21:07 -0500 Subject: [PATCH 0592/2527] Lint Code with JSCS * For now, copy `.jscsrc` from `emberjs/ember.js` * Integrate into `npm start` --- .jscsrc | 52 +++ Brocfile.js | 7 +- package.json | 5 +- .../lib/setup-container.js | 2 +- .../lib/system/active_model_serializer.js | 2 +- .../active_model_serializer_test.js | 71 +++-- .../lib/adapters/fixture_adapter.js | 6 +- .../ember-data/lib/adapters/rest_adapter.js | 10 +- packages/ember-data/lib/ext/date.js | 57 ++-- .../lib/initializers/data_adapter.js | 2 +- packages/ember-data/lib/initializers/store.js | 2 +- .../lib/initializers/store_injections.js | 2 +- .../ember-data/lib/initializers/transforms.js | 2 +- packages/ember-data/lib/main.js | 4 +- .../lib/serializers/embedded_records_mixin.js | 6 +- .../lib/serializers/json_serializer.js | 16 +- .../lib/serializers/rest_serializer.js | 8 +- packages/ember-data/lib/setup-container.js | 2 +- .../ember-data/lib/system/container_proxy.js | 14 +- .../lib/system/debug/debug_adapter.js | 6 +- packages/ember-data/lib/system/model/model.js | 22 +- .../lib/system/record_array_manager.js | 4 +- .../record_arrays/filtered_record_array.js | 3 +- .../lib/system/record_arrays/many_array.js | 8 +- .../lib/system/record_arrays/record_array.js | 12 +- .../lib/system/relationships/ext.js | 42 +-- .../lib/system/relationships/has_many.js | 2 +- .../system/relationships/state/belongs_to.js | 12 +- .../lib/system/relationships/state/create.js | 13 +- .../system/relationships/state/has_many.js | 20 +- .../relationships/state/relationship.js | 18 +- packages/ember-data/lib/system/store.js | 18 +- .../integration/adapter/find_all_test.js | 16 +- .../tests/integration/adapter/find_test.js | 16 +- .../adapter/fixture_adapter_test.js | 28 +- .../adapter/record_persistence_test.js | 20 +- .../integration/adapter/rest_adapter_test.js | 220 ++++++------- .../integration/adapter/store_adapter_test.js | 52 +-- .../ember-data/tests/integration/all_test.js | 4 +- .../tests/integration/application_test.js | 48 +-- .../integration/client_id_generation_test.js | 4 +- .../tests/integration/debug_adapter_test.js | 16 +- .../tests/integration/filter_test.js | 100 +++--- .../tests/integration/inverse_test.js | 32 +- .../tests/integration/lifecycle_hooks_test.js | 4 +- .../integration/record_array_manager_test.js | 14 +- .../records/collection_save_test.js | 32 +- .../integration/records/delete_record_test.js | 20 +- .../tests/integration/records/reload_test.js | 19 +- .../tests/integration/records/save_test.js | 30 +- .../tests/integration/records/unload_test.js | 50 +-- .../relationships/belongs_to_test.js | 56 ++-- .../relationships/has_many_test.js | 221 ++++++------- .../inverse_relationships_test.js | 68 ++-- .../relationships/many_to_many_test.js | 114 +++---- .../relationships/one_to_many_test.js | 300 +++++++++--------- .../relationships/one_to_one_test.js | 207 ++++++------ .../embedded_records_mixin_test.js | 192 +++++------ .../serializers/json_serializer_test.js | 134 ++++---- .../serializers/rest_serializer_test.js | 174 +++++----- .../tests/integration/setup-container-test.js | 10 +- .../tests/integration/store_test.js | 26 +- .../adapter_populated_record_array_test.js | 7 +- .../tests/unit/adapters/rest_adapter/ajax.js | 16 +- .../group_records_for_find_many_test.js | 28 +- packages/ember-data/tests/unit/debug_test.js | 2 +- .../tests/unit/model/errors_test.js | 2 +- .../unit/model/lifecycle_callbacks_test.js | 24 +- .../ember-data/tests/unit/model/merge_test.js | 18 +- .../tests/unit/model/relationships_test.js | 100 +++--- .../tests/unit/model/rollback_test.js | 58 ++-- packages/ember-data/tests/unit/model_test.js | 112 +++---- .../tests/unit/record_array_test.js | 52 +-- .../tests/unit/store/adapter_interop_test.js | 118 +++---- .../tests/unit/store/create_record_test.js | 24 +- .../tests/unit/store/metadata_for_test.js | 4 +- .../tests/unit/store/model_for_test.js | 8 +- .../ember-data/tests/unit/store/push_test.js | 133 ++++---- .../tests/unit/store/serializer_for_test.js | 4 +- .../tests/unit/store/unload_test.js | 14 +- 80 files changed, 1732 insertions(+), 1669 deletions(-) create mode 100644 .jscsrc diff --git a/.jscsrc b/.jscsrc new file mode 100644 index 00000000000..3463fb333df --- /dev/null +++ b/.jscsrc @@ -0,0 +1,52 @@ +{ + "esnext": true, + "excludeFiles": [], + "additionalRules": [], + "disallowSpacesInsideArrayBrackets": "all", + "requireSpaceBeforeObjectValues": true, + "requireCommaBeforeLineBreak": true, + "requireBlocksOnNewline": 1, + "disallowKeywordsOnNewLine": ["else"], + "disallowNewlineBeforeBlockStatements": true, + "requireSpacesInConditionalExpression": { + "afterTest": true, + "beforeConsequent": true, + "afterConsequent": true, + "beforeAlternate": true + }, + "disallowSpacesInCallExpression": true, + "disallowEmptyBlocks": true, + "requireSpacesInsideObjectBrackets": "all", + "requireCurlyBraces": [ + "if", + "else", + "for", + "while", + "do", + "try", + "catch" + ], + "requireLineFeedAtFileEnd": true, + "disallowTrailingWhitespace": true, + "disallowTrailingComma": true, + "requireSpaceBeforeBlockStatements": true, + "validateIndentation": 2, + "validateParameterSeparator": ", ", + "requireSpaceBeforeKeywords": [ + "else", + "while", + "catch" + ], + "requireSpaceAfterKeywords": [ + "do", + "for", + "if", + "else", + "switch", + "case", + "try", + "while", + "with", + "return" + ] +} diff --git a/Brocfile.js b/Brocfile.js index b421d0e3ca4..e574759ba69 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -17,6 +17,8 @@ var version = require('git-repo-version')(10); var yuidoc = require('broccoli-yuidoc'); var replace = require('broccoli-replace'); var path = require('path'); +var fs = require('fs'); +var jscsTree = require('broccoli-jscs'); function minify(tree, name){ var config = require('./config/ember-defeatureify'); @@ -154,11 +156,14 @@ function versionStamp(tree){ configurationFiles = versionStamp(configurationFiles); +var jscsFiles = jscsTree("packages"); + var trees = [ testFiles, testRunner, bower, - configurationFiles + configurationFiles, + jscsFiles ]; if (env === 'production') { diff --git a/package.json b/package.json index bce3d9a2493..e6d2d50a890 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "build:production": "ember build --environment=production", "prepublish": "bower install && npm run-script build:production", "start": "ember serve", - "test": "testem -R dot ci", + "test": "node_modules/broccoli-jscs/node_modules/jscs/bin/jscs packages && testem -R dot ci", "publish-build": "npm run build:production && ./bin/publish_to_s3.js", "test:local": "testem -R dot ci", "test:beta": "testem -f config/testem-beta.json -R dot ci", @@ -55,5 +55,8 @@ "git-repo-version": "0.0.2", "testem": "^0.6.19", "yuidocjs": "~0.3.46" + }, + "dependencies": { + "broccoli-jscs": "0.0.13" } } diff --git a/packages/activemodel-adapter/lib/setup-container.js b/packages/activemodel-adapter/lib/setup-container.js index 123c26e68ec..bf2ac985b2b 100644 --- a/packages/activemodel-adapter/lib/setup-container.js +++ b/packages/activemodel-adapter/lib/setup-container.js @@ -2,7 +2,7 @@ import ContainerProxy from "ember-data/system/container_proxy"; import ActiveModelSerializer from "activemodel-adapter/system/active_model_serializer"; import ActiveModelAdapter from "activemodel-adapter/system/active_model_adapter"; -export default function setupActiveModelAdapter(container, application){ +export default function setupActiveModelAdapter(container, application) { var proxy = new ContainerProxy(container); proxy.registerDeprecations([ { deprecated: 'serializer:_ams', valid: 'serializer:-active-model' }, diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index e57a1938747..3602bec6ae5 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -219,7 +219,7 @@ var ActiveModelSerializer = RESTSerializer.extend({ @param {Object} data */ - normalizeLinks: function(data){ + normalizeLinks: function(data) { if (data.links) { var links = data.links; diff --git a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js index e5f2a3b54bb..e7840993214 100644 --- a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js +++ b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js @@ -12,7 +12,7 @@ module("integration/active_model - ActiveModelSerializer", { }); HomePlanet = DS.Model.extend({ name: DS.attr('string'), - superVillains: DS.hasMany('superVillain', {async: true}) + superVillains: DS.hasMany('superVillain', { async: true }) }); EvilMinion = DS.Model.extend({ superVillain: DS.belongsTo('superVillain'), @@ -21,11 +21,11 @@ module("integration/active_model - ActiveModelSerializer", { YellowMinion = EvilMinion.extend(); DoomsdayDevice = DS.Model.extend({ name: DS.attr('string'), - evilMinion: DS.belongsTo('evilMinion', {polymorphic: true}) + evilMinion: DS.belongsTo('evilMinion', { polymorphic: true }) }); MediocreVillain = DS.Model.extend({ name: DS.attr('string'), - evilMinions: DS.hasMany('evilMinion', {polymorphic: true}) + evilMinions: DS.hasMany('evilMinion', { polymorphic: true }) }); env = setupStore({ superVillain: SuperVillain, @@ -55,7 +55,7 @@ module("integration/active_model - ActiveModelSerializer", { test("serialize", function() { var tom; - run(function(){ + run(function() { league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league }); }); @@ -70,7 +70,7 @@ test("serialize", function() { }); test("serializeIntoHash", function() { - run(function(){ + run(function() { league = env.store.createRecord(HomePlanet, { name: "Umber", id: "123" }); }); var json = {}; @@ -86,7 +86,7 @@ test("serializeIntoHash", function() { test("serializeIntoHash with decamelized types", function() { HomePlanet.typeKey = 'home-planet'; - run(function(){ + run(function() { league = env.store.createRecord(HomePlanet, { name: "Umber", id: "123" }); }); var json = {}; @@ -106,7 +106,7 @@ test("normalize", function() { yellowMinion: DS.belongsTo('yellowMinion') }); - var superVillain_hash = {first_name: "Tom", last_name: "Dale", home_planet_id: "123", evil_minion_ids: [1,2]}; + var superVillain_hash = { first_name: "Tom", last_name: "Dale", home_planet_id: "123", evil_minion_ids: [1,2] }; var json = env.amsSerializer.normalize(SuperVillain, superVillain_hash, "superVillain"); @@ -135,7 +135,7 @@ test("extractSingle", function() { env.container.register('adapter:superVillain', DS.ActiveModelAdapter); var json_hash = { - home_planet: {id: "1", name: "Umber", super_villain_ids: [1]}, + home_planet: { id: "1", name: "Umber", super_villain_ids: [1] }, super_villains: [{ id: "1", first_name: "Tom", @@ -145,7 +145,7 @@ test("extractSingle", function() { }; var json; - run(function(){ + run(function() { json = env.amsSerializer.extractSingle(env.store, HomePlanet, json_hash); }); @@ -155,8 +155,8 @@ test("extractSingle", function() { "superVillains": [1] }); - run(function(){ - env.store.find("superVillain", 1).then(function(minion){ + run(function() { + env.store.find("superVillain", 1).then(function(minion) { equal(minion.get('firstName'), "Tom"); }); }); @@ -167,11 +167,11 @@ test("extractArray", function() { var array; var json_hash = { - home_planets: [{id: "1", name: "Umber", super_villain_ids: [1]}], - super_villains: [{id: "1", first_name: "Tom", last_name: "Dale", home_planet_id: "1"}] + home_planets: [{ id: "1", name: "Umber", super_villain_ids: [1] }], + super_villains: [{ id: "1", first_name: "Tom", last_name: "Dale", home_planet_id: "1" }] }; - run(function(){ + run(function() { array = env.amsSerializer.extractArray(env.store, HomePlanet, json_hash); }); @@ -181,8 +181,8 @@ test("extractArray", function() { "superVillains": [1] }]); - run(function(){ - env.store.find("superVillain", 1).then(function(minion){ + run(function() { + env.store.find("superVillain", 1).then(function(minion) { equal(minion.get('firstName'), "Tom"); }); }); @@ -190,9 +190,9 @@ test("extractArray", function() { test("serialize polymorphic", function() { var tom, ray; - run(function(){ - tom = env.store.createRecord(YellowMinion, {name: "Alex", id: "124"}); - ray = env.store.createRecord(DoomsdayDevice, {evilMinion: tom, name: "DeathRay"}); + run(function() { + tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); + ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); }); var json = env.amsSerializer.serialize(ray); @@ -207,9 +207,9 @@ test("serialize polymorphic", function() { test("serialize polymorphic when type key is not camelized", function() { YellowMinion.typeKey = 'yellow-minion'; var tom, ray; - run(function(){ - tom = env.store.createRecord(YellowMinion, {name: "Alex", id: "124"}); - ray = env.store.createRecord(DoomsdayDevice, {evilMinion: tom, name: "DeathRay"}); + run(function() { + tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); + ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); }); var json = env.amsSerializer.serialize(ray); @@ -219,8 +219,8 @@ test("serialize polymorphic when type key is not camelized", function() { test("serialize polymorphic when associated object is null", function() { var ray, json; - run(function(){ - ray = env.store.createRecord(DoomsdayDevice, {name: "DeathRay"}); + run(function() { + ray = env.store.createRecord(DoomsdayDevice, { name: "DeathRay" }); json = env.amsSerializer.serialize(ray); }); @@ -233,11 +233,12 @@ test("extractPolymorphic hasMany", function() { YellowMinion.toString = function() { return "YellowMinion"; }; var json_hash = { - mediocre_villain: { id: 1, name: "Dr Horrible", evil_minions: [{ type: "yellow_minion", id: 12 }] } + mediocre_villain: { id: 1, name: "Dr Horrible", evil_minions: [{ type: "yellow_minion", id: 12 }] }, + evil_minions: [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] }; var json; - run(function(){ + run(function() { json = env.amsSerializer.extractSingle(env.store, MediocreVillain, json_hash); }); @@ -257,11 +258,12 @@ test("extractPolymorphic", function() { YellowMinion.toString = function() { return "YellowMinion"; }; var json_hash = { - doomsday_device: { id: 1, name: "DeathRay", evil_minion: { type: "yellow_minion", id: 12 } } + doomsday_device: { id: 1, name: "DeathRay", evil_minion: { type: "yellow_minion", id: 12 } }, + evil_minions: [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] }; var json; - run(function(){ + run(function() { json = env.amsSerializer.extractSingle(env.store, DoomsdayDevice, json_hash); }); @@ -277,10 +279,11 @@ test("extractPolymorphic", function() { test("extractPolymorphic when the related data is not specified", function() { var json = { - doomsday_device: { id: 1, name: "DeathRay" } + doomsday_device: { id: 1, name: "DeathRay" }, + evil_minions: [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] }; - run(function(){ + run(function() { json = env.amsSerializer.extractSingle(env.store, DoomsdayDevice, json); }); @@ -293,10 +296,10 @@ test("extractPolymorphic when the related data is not specified", function() { test("extractPolymorphic hasMany when the related data is not specified", function() { var json = { - mediocre_villain: {id: 1, name: "Dr Horrible"} + mediocre_villain: { id: 1, name: "Dr Horrible" } }; - run(function(){ + run(function() { json = env.amsSerializer.extractSingle(env.store, MediocreVillain, json); }); @@ -309,10 +312,10 @@ test("extractPolymorphic hasMany when the related data is not specified", functi test("extractPolymorphic does not break hasMany relationships", function() { var json = { - mediocre_villain: {id: 1, name: "Dr. Evil", evil_minions: []} + mediocre_villain: { id: 1, name: "Dr. Evil", evil_minions: [] } }; - run(function (){ + run(function () { json = env.amsSerializer.extractSingle(env.store, MediocreVillain, json); }); diff --git a/packages/ember-data/lib/adapters/fixture_adapter.js b/packages/ember-data/lib/adapters/fixture_adapter.js index 7e6b4f98c3c..bf88dea34ca 100644 --- a/packages/ember-data/lib/adapters/fixture_adapter.js +++ b/packages/ember-data/lib/adapters/fixture_adapter.js @@ -64,9 +64,9 @@ export default Adapter.extend({ fixturesForType: function(type) { if (type.FIXTURES) { var fixtures = Ember.A(type.FIXTURES); - return fixtures.map(function(fixture){ + return fixtures.map(function(fixture) { var fixtureIdType = typeof fixture.id; - if(fixtureIdType !== "number" && fixtureIdType !== "string"){ + if (fixtureIdType !== "number" && fixtureIdType !== "string") { throw new Error(fmt('the id property must be defined as a number or string for fixture %@', [fixture])); } fixture.id = fixture.id + ''; @@ -95,7 +95,7 @@ export default Adapter.extend({ @param {Array} fixture */ updateFixtures: function(type, fixture) { - if(!type.FIXTURES) { + if (!type.FIXTURES) { type.FIXTURES = []; } diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 8999db4d656..70cd10f89a0 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -594,7 +594,7 @@ export default Adapter.extend({ var id = record.get('id'); if (lastSegment === id) { expandedURL[expandedURL.length - 1] = ""; - } else if(endsWith(lastSegment, '?id=' + id)) { + } else if (endsWith(lastSegment, '?id=' + id)) { //Case when the url is of the format ...something?id=:id expandedURL[expandedURL.length - 1] = lastSegment.substring(0, lastSegment.length - id.length - 1); } @@ -628,11 +628,11 @@ export default Adapter.extend({ loaded separately by `findMany`. */ groupRecordsForFindMany: function (store, records) { - var groups = MapWithDefault.create({defaultValue: function(){return [];}}); + var groups = MapWithDefault.create({ defaultValue: function() { return []; } }); var adapter = this; var maxUrlLength = this.maxUrlLength; - forEach.call(records, function(record){ + forEach.call(records, function(record) { var baseUrl = adapter._stripIDFromURL(store, record); groups.get(baseUrl).push(record); }); @@ -659,7 +659,7 @@ export default Adapter.extend({ } var groupsArray = []; - groups.forEach(function(group, key){ + groups.forEach(function(group, key) { var paramNameLength = '&ids%5B%5D='.length; var splitGroups = splitGroupToFitInUrl(group, maxUrlLength, paramNameLength); @@ -865,7 +865,7 @@ export default Adapter.extend({ }); //From http://stackoverflow.com/questions/280634/endswith-in-javascript -function endsWith(string, suffix){ +function endsWith(string, suffix) { if (typeof String.prototype.endsWith !== 'function') { return string.indexOf(suffix, string.length - suffix.length) !== -1; } else { diff --git a/packages/ember-data/lib/ext/date.js b/packages/ember-data/lib/ext/date.js index ba35e0d72f7..c8f48afbed6 100644 --- a/packages/ember-data/lib/ext/date.js +++ b/packages/ember-data/lib/ext/date.js @@ -15,7 +15,7 @@ */ Ember.Date = Ember.Date || {}; -var origParse = Date.parse, numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ]; +var origParse = Date.parse, numericKeys = [1, 4, 5, 6, 7, 10, 11]; /** @method parse @@ -23,37 +23,36 @@ var origParse = Date.parse, numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ]; @return {Number} timestamp */ Ember.Date.parse = function (date) { - var timestamp, struct, minutesOffset = 0; - - // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string - // before falling back to any implementation-specific date parsing, so that’s what we do, even if native - // implementations could be faster - // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm - if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) { - // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC - for (var i = 0, k; (k = numericKeys[i]); ++i) { - struct[k] = +struct[k] || 0; - } - - // allow undefined days and months - struct[2] = (+struct[2] || 1) - 1; - struct[3] = +struct[3] || 1; - - if (struct[8] !== 'Z' && struct[9] !== undefined) { - minutesOffset = struct[10] * 60 + struct[11]; - - if (struct[9] === '+') { - minutesOffset = 0 - minutesOffset; - } - } - - timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]); + var timestamp, struct, minutesOffset = 0; + + // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string + // before falling back to any implementation-specific date parsing, so that’s what we do, even if native + // implementations could be faster + // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm + if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) { + // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC + for (var i = 0, k; (k = numericKeys[i]); ++i) { + struct[k] = +struct[k] || 0; } - else { - timestamp = origParse ? origParse(date) : NaN; + + // allow undefined days and months + struct[2] = (+struct[2] || 1) - 1; + struct[3] = +struct[3] || 1; + + if (struct[8] !== 'Z' && struct[9] !== undefined) { + minutesOffset = struct[10] * 60 + struct[11]; + + if (struct[9] === '+') { + minutesOffset = 0 - minutesOffset; + } } - return timestamp; + timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]); + } else { + timestamp = origParse ? origParse(date) : NaN; + } + + return timestamp; }; if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Date) { diff --git a/packages/ember-data/lib/initializers/data_adapter.js b/packages/ember-data/lib/initializers/data_adapter.js index 73326b97053..6f0b11b73df 100644 --- a/packages/ember-data/lib/initializers/data_adapter.js +++ b/packages/ember-data/lib/initializers/data_adapter.js @@ -7,6 +7,6 @@ import DebugAdapter from "ember-data/system/debug/debug_adapter"; @method initializeStoreInjections @param {Ember.Container} container */ -export default function initializeDebugAdapter(container){ +export default function initializeDebugAdapter(container) { container.register('data-adapter:main', DebugAdapter); } diff --git a/packages/ember-data/lib/initializers/store.js b/packages/ember-data/lib/initializers/store.js index b37a86b1455..4d20cacff61 100644 --- a/packages/ember-data/lib/initializers/store.js +++ b/packages/ember-data/lib/initializers/store.js @@ -11,7 +11,7 @@ import Store from "ember-data/system/store"; @param {Ember.Container} container @param {Object} [application] an application namespace */ -export default function initializeStore(container, application){ +export default function initializeStore(container, application) { Ember.deprecate('Specifying a custom Store for Ember Data on your global namespace as `App.Store` ' + 'has been deprecated. Please use `App.ApplicationStore` instead.', !(application && application.Store)); diff --git a/packages/ember-data/lib/initializers/store_injections.js b/packages/ember-data/lib/initializers/store_injections.js index 079f2ff2a76..3f193447985 100644 --- a/packages/ember-data/lib/initializers/store_injections.js +++ b/packages/ember-data/lib/initializers/store_injections.js @@ -5,7 +5,7 @@ @method initializeStoreInjections @param {Ember.Container} container */ -export default function initializeStoreInjections(container){ +export default function initializeStoreInjections(container) { container.injection('controller', 'store', 'store:main'); container.injection('route', 'store', 'store:main'); container.injection('serializer', 'store', 'store:main'); diff --git a/packages/ember-data/lib/initializers/transforms.js b/packages/ember-data/lib/initializers/transforms.js index 536f7f1ffd6..de067aaa39f 100644 --- a/packages/ember-data/lib/initializers/transforms.js +++ b/packages/ember-data/lib/initializers/transforms.js @@ -12,7 +12,7 @@ import { @method initializeTransforms @param {Ember.Container} container */ -export default function initializeTransforms(container){ +export default function initializeTransforms(container) { container.register('transform:boolean', BooleanTransform); container.register('transform:date', DateTransform); container.register('transform:number', NumberTransform); diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index 16647f47afe..f5195d3be18 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -7,8 +7,8 @@ // support RSVP 2.x via resolve, but prefer RSVP 3.x's Promise.cast Ember.RSVP.Promise.cast = Ember.RSVP.Promise.cast || Ember.RSVP.resolve; -Ember.runInDebug(function(){ - if (Ember.VERSION.match(/1\.[0-7]\./)){ +Ember.runInDebug(function() { + if (Ember.VERSION.match(/1\.[0-7]\./)) { throw new Ember.Error("Ember Data requires at least Ember 1.8.0, but you have " + Ember.VERSION + ". Please upgrade your version of Ember, then upgrade Ember Data"); diff --git a/packages/ember-data/lib/serializers/embedded_records_mixin.js b/packages/ember-data/lib/serializers/embedded_records_mixin.js index 9d189f90ca5..e7bbb9581f5 100644 --- a/packages/ember-data/lib/serializers/embedded_records_mixin.js +++ b/packages/ember-data/lib/serializers/embedded_records_mixin.js @@ -123,7 +123,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ return extractEmbeddedRecords(this, this.store, type, normalizedHash); }, - keyForRelationship: function(key, type){ + keyForRelationship: function(key, type) { if (this.hasDeserializeRecordsOption(key)) { return this.keyForAttribute(key); } else { @@ -202,7 +202,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ if (!embeddedRecord) { json[key] = null; } else { - json[key] = embeddedRecord.serialize({includeId: true}); + json[key] = embeddedRecord.serialize({ includeId: true }); this.removeEmbeddedForeignKey(record, embeddedRecord, relationship, json[key]); } } @@ -304,7 +304,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ } else if (includeRecords) { key = this.keyForAttribute(attr); json[key] = get(record, attr).map(function(embeddedRecord) { - var serializedEmbeddedRecord = embeddedRecord.serialize({includeId: true}); + var serializedEmbeddedRecord = embeddedRecord.serialize({ includeId: true }); this.removeEmbeddedForeignKey(record, embeddedRecord, relationship, serializedEmbeddedRecord); return serializedEmbeddedRecord; }, this); diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index c972519f7b0..87f9bdc1596 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -286,10 +286,10 @@ export default Ember.Object.extend({ mappedKey = attrs[key]; //We need to account for both the {title: 'post_title'} and //{title: {key: 'post_title'}} forms - if (mappedKey.key){ + if (mappedKey.key) { mappedKey = mappedKey.key; } - if (typeof mappedKey === 'string'){ + if (typeof mappedKey === 'string') { key = mappedKey; } } @@ -737,7 +737,7 @@ export default Ember.Object.extend({ @param {String} requestType @return {Array} array An array of deserialized objects */ - extractFindAll: function(store, type, payload, id, requestType){ + extractFindAll: function(store, type, payload, id, requestType) { return this.extractArray(store, type, payload, id, requestType); }, /** @@ -753,7 +753,7 @@ export default Ember.Object.extend({ @param {String} requestType @return {Array} array An array of deserialized objects */ - extractFindQuery: function(store, type, payload, id, requestType){ + extractFindQuery: function(store, type, payload, id, requestType) { return this.extractArray(store, type, payload, id, requestType); }, /** @@ -769,7 +769,7 @@ export default Ember.Object.extend({ @param {String} requestType @return {Array} array An array of deserialized objects */ - extractFindMany: function(store, type, payload, id, requestType){ + extractFindMany: function(store, type, payload, id, requestType) { return this.extractArray(store, type, payload, id, requestType); }, /** @@ -785,7 +785,7 @@ export default Ember.Object.extend({ @param {String} requestType @return {Array} array An array of deserialized objects */ - extractFindHasMany: function(store, type, payload, id, requestType){ + extractFindHasMany: function(store, type, payload, id, requestType) { return this.extractArray(store, type, payload, id, requestType); }, @@ -1033,7 +1033,7 @@ export default Ember.Object.extend({ @param {String} key @return {String} normalized key */ - keyForAttribute: function(key){ + keyForAttribute: function(key) { return key; }, @@ -1058,7 +1058,7 @@ export default Ember.Object.extend({ @return {String} normalized key */ - keyForRelationship: function(key, type){ + keyForRelationship: function(key, type) { return key; }, diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index e36b8cbc0f9..3a17e07e669 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -268,7 +268,7 @@ var RESTSerializer = JSONSerializer.extend({ for (var prop in payload) { var typeName = this.typeForRoot(prop); - if (!store.modelFactoryFor(typeName)){ + if (!store.modelFactoryFor(typeName)) { Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false); continue; } @@ -488,7 +488,7 @@ var RESTSerializer = JSONSerializer.extend({ for (var prop in payload) { var typeName = this.typeForRoot(prop); - if (!store.modelFactoryFor(typeName, prop)){ + if (!store.modelFactoryFor(typeName, prop)) { Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false); continue; } @@ -748,9 +748,9 @@ var RESTSerializer = JSONSerializer.extend({ } }); -Ember.runInDebug(function(){ +Ember.runInDebug(function() { RESTSerializer.reopen({ - warnMessageNoModelForKey: function(prop, typeKey){ + warnMessageNoModelForKey: function(prop, typeKey) { return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + typeKey + '" (resolved model name using ' + this.constructor.toString() + '.typeForRoot("' + prop + '"))'; } }); diff --git a/packages/ember-data/lib/setup-container.js b/packages/ember-data/lib/setup-container.js index 14675a41c82..9506120c3d9 100644 --- a/packages/ember-data/lib/setup-container.js +++ b/packages/ember-data/lib/setup-container.js @@ -4,7 +4,7 @@ import initializeStoreInjections from 'ember-data/initializers/store_injections' import initializeDataAdapter from 'ember-data/initializers/data_adapter'; import setupActiveModelContainer from 'activemodel-adapter/setup-container'; -export default function setupContainer(container, application){ +export default function setupContainer(container, application) { // application is not a required argument. This ensures // testing setups can setup a container without booting an // entire ember application. diff --git a/packages/ember-data/lib/system/container_proxy.js b/packages/ember-data/lib/system/container_proxy.js index 55a74da5a84..577126cea4e 100644 --- a/packages/ember-data/lib/system/container_proxy.js +++ b/packages/ember-data/lib/system/container_proxy.js @@ -6,18 +6,20 @@ @namespace DS @private */ -function ContainerProxy(container){ +function ContainerProxy(container) { this.container = container; } ContainerProxy.prototype.aliasedFactory = function(path, preLookup) { var _this = this; - return {create: function(){ - if (preLookup) { preLookup(); } + return { + create: function() { + if (preLookup) { preLookup(); } - return _this.container.lookup(path); - }}; + return _this.container.lookup(path); + } + }; }; ContainerProxy.prototype.registerAlias = function(source, dest, preLookup) { @@ -27,7 +29,7 @@ ContainerProxy.prototype.registerAlias = function(source, dest, preLookup) { }; ContainerProxy.prototype.registerDeprecation = function(deprecated, valid) { - var preLookupCallback = function(){ + var preLookupCallback = function() { Ember.deprecate("You tried to look up '" + deprecated + "', " + "but this has been deprecated in favor of '" + valid + "'.", false); }; diff --git a/packages/ember-data/lib/system/debug/debug_adapter.js b/packages/ember-data/lib/system/debug/debug_adapter.js index ac8f67b2343..b7be35bcd6e 100644 --- a/packages/ember-data/lib/system/debug/debug_adapter.js +++ b/packages/ember-data/lib/system/debug/debug_adapter.js @@ -35,9 +35,9 @@ export default Ember.DataAdapter.extend({ var count = 0; var self = this; get(type, 'attributes').forEach(function(meta, name) { - if (count++ > self.attributeLimit) { return false; } - var desc = capitalize(underscore(name).replace('_', ' ')); - columns.push({ name: name, desc: desc }); + if (count++ > self.attributeLimit) { return false; } + var desc = capitalize(underscore(name).replace('_', ' ')); + columns.push({ name: name, desc: desc }); }); return columns; }, diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index adedb98b0f6..e9ff97a41b0 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -503,7 +503,7 @@ var Model = Ember.Object.extend(Ember.Evented, { var model = this; //TODO Move into a getter for better perf this.constructor.eachRelationship(function(key, descriptor) { - model._relationships[key] = createRelationshipFor(model, descriptor, model.store); + model._relationships[key] = createRelationshipFor(model, descriptor, model.store); }); }, @@ -689,7 +689,7 @@ var Model = Ember.Object.extend(Ember.Evented, { clearRelationships: function() { this.eachRelationship(function(name, relationship) { var rel = this._relationships[name]; - if (rel){ + if (rel) { //TODO(Igor) figure out whether we want to clear or disconnect rel.clear(); rel.destroy(); @@ -759,7 +759,7 @@ var Model = Ember.Object.extend(Ember.Evented, { _preloadRelationship: function(key, preloadValue) { var relationshipMeta = this.constructor.metaForProperty(key); var type = relationshipMeta.type; - if (relationshipMeta.kind === 'hasMany'){ + if (relationshipMeta.kind === 'hasMany') { this._preloadHasMany(key, preloadValue, type); } else { this._preloadBelongsTo(key, preloadValue, type); @@ -778,7 +778,7 @@ var Model = Ember.Object.extend(Ember.Evented, { this._relationships[key].updateRecordsFromAdapter(recordsToSet); }, - _preloadBelongsTo: function(key, preloadValue, type){ + _preloadBelongsTo: function(key, preloadValue, type) { var recordToSet = this._convertStringOrNumberIntoRecord(preloadValue, type); //We use the pathway of setting the hasMany as if it came from the adapter @@ -787,7 +787,7 @@ var Model = Ember.Object.extend(Ember.Evented, { }, _convertStringOrNumberIntoRecord: function(value, type) { - if (Ember.typeOf(value) === 'string' || Ember.typeOf(value) === 'number'){ + if (Ember.typeOf(value) === 'string' || Ember.typeOf(value) === 'number') { return this.store.recordForId(type, value); } return value; @@ -800,7 +800,7 @@ var Model = Ember.Object.extend(Ember.Evented, { _notifyProperties: function(keys) { Ember.beginPropertyChanges(); var key; - for (var i = 0, length = keys.length; i < length; i++){ + for (var i = 0, length = keys.length; i < length; i++) { key = keys[i]; this.notifyPropertyChange(key); } @@ -984,7 +984,7 @@ var Model = Ember.Object.extend(Ember.Evented, { ```javascript record.set('name', 'Tomster'); - record.save().then(function(){ + record.save().then(function() { // Success callback }, function() { // Error callback @@ -1038,8 +1038,8 @@ var Model = Ember.Object.extend(Ember.Evented, { var record = this; var promiseLabel = "DS: Model#reload of " + this; - var promise = new Promise(function(resolve){ - record.send('reloadRecord', resolve); + var promise = new Promise(function(resolve) { + record.send('reloadRecord', resolve); }, promiseLabel).then(function() { record.set('isReloading', false); record.set('isError', false); @@ -1108,7 +1108,7 @@ var Model = Ember.Object.extend(Ember.Evented, { var args = new Array(length - 1); var name = arguments[0]; - for (var i = 1; i < length; i++ ){ + for (var i = 1; i < length; i++) { args[i - 1] = arguments[i]; } @@ -1120,7 +1120,7 @@ var Model = Ember.Object.extend(Ember.Evented, { var length = arguments.length; var args = new Array(length); - for (var i = 0; i < length; i++ ){ + for (var i = 0; i < length; i++) { args[i] = arguments[i]; } diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index c84ea2f102a..04ac22d7d32 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -71,7 +71,7 @@ export default Ember.Object.extend({ if (!recordArrays) { return; } - recordArrays.forEach(function(array){ + recordArrays.forEach(function(array) { array.removeRecord(record); }); @@ -258,7 +258,7 @@ export default Ember.Object.extend({ recordArrays.splice(index, 1); }, - willDestroy: function(){ + willDestroy: function() { this._super(); this.filteredRecordArrays.forEach(function(value) { diff --git a/packages/ember-data/lib/system/record_arrays/filtered_record_array.js b/packages/ember-data/lib/system/record_arrays/filtered_record_array.js index 15b1bdb4634..00c28161927 100644 --- a/packages/ember-data/lib/system/record_arrays/filtered_record_array.js +++ b/packages/ember-data/lib/system/record_arrays/filtered_record_array.js @@ -62,6 +62,5 @@ export default RecordArray.extend({ updateFilter: Ember.observer(function() { Ember.run.once(this, this._updateFilter); - }, 'filterFunction'), - + }, 'filterFunction') }); diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index ff3e9a805fa..1721dced928 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -112,7 +112,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { this.currentState.splice.apply(this.currentState, [idx, amt].concat(objects)); this.set('length', this.currentState.length); this.arrayContentDidChange(idx, amt, objects.length); - if (objects){ + if (objects) { //TODO(Igor) probably needed only for unloaded records this.relationship.notifyHasManyChanged(); } @@ -122,7 +122,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { //TODO(Igor) optimize internalRemoveRecords: function(records) { var index; - for(var i=0; i < records.length; i++) { + for (var i=0; i < records.length; i++) { index = this.currentState.indexOf(records[i]); this.internalReplace(index, 1); } @@ -138,11 +138,11 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { replace: function(idx, amt, objects) { var records; - if (amt > 0){ + if (amt > 0) { records = this.currentState.slice(idx, idx+amt); this.get('relationship').removeRecords(records); } - if (objects){ + if (objects) { this.get('relationship').addRecords(objects, idx); } }, diff --git a/packages/ember-data/lib/system/record_arrays/record_array.js b/packages/ember-data/lib/system/record_arrays/record_array.js index 5a6d3ebf366..0392bc5ae7d 100644 --- a/packages/ember-data/lib/system/record_arrays/record_array.js +++ b/packages/ember-data/lib/system/record_arrays/record_array.js @@ -130,10 +130,8 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { var content = get(this, 'content'); if (idx === undefined) { content.addObject(record); - } else { - if (!content.contains(record)) { - content.insertAt(idx, record); - } + } else if (!content.contains(record)) { + content.insertAt(idx, record); } }, @@ -192,7 +190,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { _dissociateFromOwnRecords: function() { var array = this; - this.forEach(function(record){ + this.forEach(function(record) { var recordArrays = record._recordArrays; if (recordArrays) { @@ -205,7 +203,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method _unregisterFromManager @private */ - _unregisterFromManager: function(){ + _unregisterFromManager: function() { var manager = get(this, 'manager'); //We will stop needing this stupid if statement soon, once manyArray are refactored to not be RecordArrays if (manager) { @@ -213,7 +211,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { } }, - willDestroy: function(){ + willDestroy: function() { this._unregisterFromManager(); this._dissociateFromOwnRecords(); set(this, 'content', undefined); diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 997189395c6..eb860318612 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -12,30 +12,30 @@ var get = Ember.get; var filter = Ember.ArrayPolyfills.filter; var relationshipsDescriptor = Ember.computed(function() { - if (Ember.testing === true && relationshipsDescriptor._cacheable === true) { - relationshipsDescriptor._cacheable = false; - } + if (Ember.testing === true && relationshipsDescriptor._cacheable === true) { + relationshipsDescriptor._cacheable = false; + } - var map = new MapWithDefault({ - defaultValue: function() { return []; } - }); + var map = new MapWithDefault({ + defaultValue: function() { return []; } + }); - // Loop through each computed property on the class - this.eachComputedProperty(function(name, meta) { - // If the computed property is a relationship, add - // it to the map. - if (meta.isRelationship) { - meta.key = name; - var relationshipsForType = map.get(typeForRelationshipMeta(this.store, meta)); + // Loop through each computed property on the class + this.eachComputedProperty(function(name, meta) { + // If the computed property is a relationship, add + // it to the map. + if (meta.isRelationship) { + meta.key = name; + var relationshipsForType = map.get(typeForRelationshipMeta(this.store, meta)); - relationshipsForType.push({ - name: name, - kind: meta.kind - }); - } - }); + relationshipsForType.push({ + name: name, + kind: meta.kind + }); + } + }); - return map; + return map; }).readOnly(); var relatedTypesDescriptor = Ember.computed(function() { @@ -281,7 +281,7 @@ Model.reopenClass({ relationships = filter.call(relationships, function(relationship) { var optionsForRelationship = inverseType.metaForProperty(relationship.name).options; - if (!optionsForRelationship.inverse){ + if (!optionsForRelationship.inverse) { return true; } diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index 7d34df375c1..e360e0a70ed 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -129,7 +129,7 @@ Model.reopen({ //Goes away once hasMany is double promisified this.notifyPropertyChange(key); - }, + } }); diff --git a/packages/ember-data/lib/system/relationships/state/belongs_to.js b/packages/ember-data/lib/system/relationships/state/belongs_to.js index 08e8e2d7de5..4d87e7dab3a 100644 --- a/packages/ember-data/lib/system/relationships/state/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/state/belongs_to.js @@ -34,7 +34,7 @@ BelongsToRelationship.prototype.setCanonicalRecord = function(newRecord) { BelongsToRelationship.prototype._super$addCanonicalRecord = Relationship.prototype.addCanonicalRecord; BelongsToRelationship.prototype.addCanonicalRecord = function(newRecord) { - if (this.canonicalMembers.has(newRecord)){ return;} + if (this.canonicalMembers.has(newRecord)) { return;} if (this.canonicalState) { this.removeCanonicalRecord(this.canonicalState); @@ -58,7 +58,7 @@ BelongsToRelationship.prototype.flushCanonical = function() { BelongsToRelationship.prototype._super$addRecord = Relationship.prototype.addRecord; BelongsToRelationship.prototype.addRecord = function(newRecord) { - if (this.members.has(newRecord)){ return;} + if (this.members.has(newRecord)) { return;} var type = this.relationshipMeta.type; Ember.assert("You can only add a '" + type.typeKey + "' record to this relationship", (function () { if (newRecord instanceof type) { @@ -87,7 +87,7 @@ BelongsToRelationship.prototype.setRecordPromise = function(newPromise) { BelongsToRelationship.prototype._super$removeRecordFromOwn = Relationship.prototype.removeRecordFromOwn; BelongsToRelationship.prototype.removeRecordFromOwn = function(record) { - if (!this.members.has(record)){ return;} + if (!this.members.has(record)) { return;} this.inverseRecord = null; this._super$removeRecordFromOwn(record); this.record.notifyBelongsToChanged(this.key); @@ -95,7 +95,7 @@ BelongsToRelationship.prototype.removeRecordFromOwn = function(record) { BelongsToRelationship.prototype._super$removeCanonicalRecordFromOwn = Relationship.prototype.removeCanonicalRecordFromOwn; BelongsToRelationship.prototype.removeCanonicalRecordFromOwn = function(record) { - if (!this.canonicalMembers.has(record)){ return;} + if (!this.canonicalMembers.has(record)) { return;} this.canonicalState = null; this._super$removeCanonicalRecordFromOwn(record); }; @@ -110,7 +110,7 @@ BelongsToRelationship.prototype.findRecord = function() { BelongsToRelationship.prototype.fetchLink = function() { var self = this; - return this.store.findBelongsTo(this.record, this.link, this.relationshipMeta).then(function(record){ + return this.store.findBelongsTo(this.record, this.link, this.relationshipMeta).then(function(record) { if (record) { self.addRecord(record); } @@ -122,7 +122,7 @@ BelongsToRelationship.prototype.getRecord = function() { //TODO(Igor) flushCanonical here once our syncing is not stupid if (this.isAsync) { var promise; - if (this.link){ + if (this.link) { var self = this; promise = this.findLink().then(function() { return self.findRecord(); diff --git a/packages/ember-data/lib/system/relationships/state/create.js b/packages/ember-data/lib/system/relationships/state/create.js index 88c4266f08f..fcf76998391 100644 --- a/packages/ember-data/lib/system/relationships/state/create.js +++ b/packages/ember-data/lib/system/relationships/state/create.js @@ -6,14 +6,13 @@ var createRelationshipFor = function(record, relationshipMeta, store) { var inverse = record.constructor.inverseFor(relationshipMeta.key); if (inverse) { - inverseKey = inverse.name; - } - - if (relationshipMeta.kind === 'hasMany'){ - return new ManyRelationship(store, record, inverseKey, relationshipMeta); + inverseKey = inverse.name; } - else { - return new BelongsToRelationship(store, record, inverseKey, relationshipMeta); + + if (relationshipMeta.kind === 'hasMany') { + return new ManyRelationship(store, record, inverseKey, relationshipMeta); + } else { + return new BelongsToRelationship(store, record, inverseKey, relationshipMeta); } }; diff --git a/packages/ember-data/lib/system/relationships/state/has_many.js b/packages/ember-data/lib/system/relationships/state/has_many.js index 618164b40b5..f04010fc924 100644 --- a/packages/ember-data/lib/system/relationships/state/has_many.js +++ b/packages/ember-data/lib/system/relationships/state/has_many.js @@ -7,7 +7,13 @@ var ManyRelationship = function(store, record, inverseKey, relationshipMeta) { this._super$constructor(store, record, inverseKey, relationshipMeta); this.belongsToType = relationshipMeta.type; this.canonicalState = []; - this.manyArray = ManyArray.create({ canonicalState:this.canonicalState, store:this.store, relationship:this, type:this.belongsToType, record:record}); + this.manyArray = ManyArray.create({ + canonicalState: this.canonicalState, + store: this.store, + relationship: this, + type: this.belongsToType, + record: record + }); this.isPolymorphic = relationshipMeta.options.polymorphic; this.manyArray.isPolymorphic = this.isPolymorphic; }; @@ -115,7 +121,7 @@ ManyRelationship.prototype.computeChanges = function(records) { records = setForArray(records); members.forEach(function(member) { - if (records.has(member)) return; + if (records.has(member)) { return; } recordsToRemove.push(member); }); @@ -130,7 +136,7 @@ ManyRelationship.prototype.computeChanges = function(records) { // iteration records = records.toArray(); length = records.length; - for (i = 0; i < length; i++){ + for (i = 0; i < length; i++) { record = records[i]; //Need to preserve the order of incoming records if (hasManyArray.objectAt(i) === record ) { @@ -143,7 +149,7 @@ ManyRelationship.prototype.computeChanges = function(records) { ManyRelationship.prototype.fetchLink = function() { var self = this; - return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function(records){ + return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function(records) { self.updateRecordsFromAdapter(records); return self.manyArray; }); @@ -151,7 +157,7 @@ ManyRelationship.prototype.fetchLink = function() { ManyRelationship.prototype.findRecords = function() { var manyArray = this.manyArray; - return this.store.findMany(manyArray.toArray()).then(function(){ + return this.store.findMany(manyArray.toArray()).then(function() { //Goes away after the manyArray refactor manyArray.set('isLoaded', true); return manyArray; @@ -178,14 +184,14 @@ ManyRelationship.prototype.getRecords = function() { promise: promise }); } else { - Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.constructor.typeKey + "' with id " + this.record.get('id') + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); + Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.constructor.typeKey + "' with id " + this.record.get('id') + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); //TODO(Igor) WTF DO I DO HERE? if (!this.manyArray.get('isDestroyed')) { this.manyArray.set('isLoaded', true); } return this.manyArray; - } + } }; function setForArray(array) { diff --git a/packages/ember-data/lib/system/relationships/state/relationship.js b/packages/ember-data/lib/system/relationships/state/relationship.js index 75a6a327847..1d4b5b0bcce 100644 --- a/packages/ember-data/lib/system/relationships/state/relationship.js +++ b/packages/ember-data/lib/system/relationships/state/relationship.js @@ -28,34 +28,34 @@ Relationship.prototype = { var members = this.members.list; var member; - while (members.length > 0){ + while (members.length > 0) { member = members[0]; this.removeRecord(member); } }, - disconnect: function(){ + disconnect: function() { this.members.forEach(function(member) { this.removeRecordFromInverse(member); }, this); }, - reconnect: function(){ + reconnect: function() { this.members.forEach(function(member) { this.addRecordToInverse(member); }, this); }, - removeRecords: function(records){ + removeRecords: function(records) { var self = this; - forEach(records, function(record){ + forEach(records, function(record) { self.removeRecord(record); }); }, - addRecords: function(records, idx){ + addRecords: function(records, idx) { var self = this; - forEach(records, function(record){ + forEach(records, function(record) { self.addRecord(record, idx); if (idx !== undefined) { idx++; @@ -80,7 +80,7 @@ Relationship.prototype = { record._relationships[this.inverseKey].addCanonicalRecord(this.record); } else { if (!record._implicitRelationships[this.inverseKeyForImplicit]) { - record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, {options:{}}); + record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, { options: {} }); } record._implicitRelationships[this.inverseKeyForImplicit].addCanonicalRecord(this.record); } @@ -120,7 +120,7 @@ Relationship.prototype = { record._relationships[this.inverseKey].addRecord(this.record); } else { if (!record._implicitRelationships[this.inverseKeyForImplicit]) { - record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, {options:{}}); + record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, { options: {} }); } record._implicitRelationships[this.inverseKeyForImplicit].addRecord(this.record); } diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index af316537ccd..89c5ea6c006 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -528,7 +528,7 @@ Store = Ember.Object.extend({ if (get(record, 'isEmpty')) { fetchedRecord = this.scheduleFetch(record); //TODO double check about reloading - } else if (get(record, 'isLoading')){ + } else if (get(record, 'isLoading')) { fetchedRecord = record._loadingPromise; } @@ -593,7 +593,7 @@ Store = Ember.Object.extend({ record.loadingData(promise); - if (!this._pendingFetch.get(type)){ + if (!this._pendingFetch.get(type)) { this._pendingFetch.set(type, [recordResolverPair]); } else { this._pendingFetch.get(type).push(recordResolverPair); @@ -603,7 +603,7 @@ Store = Ember.Object.extend({ return promise; }, - flushAllPendingFetches: function(){ + flushAllPendingFetches: function() { if (this.isDestroyed || this.isDestroying) { return; } @@ -623,9 +623,9 @@ Store = Ember.Object.extend({ } function resolveFoundRecords(records) { - forEach(records, function(record){ + forEach(records, function(record) { var pair = Ember.A(recordResolverPairs).findBy('record', record); - if (pair){ + if (pair) { var resolver = pair.resolver; resolver.resolve(record); } @@ -646,9 +646,9 @@ Store = Ember.Object.extend({ } function rejectRecords(records, error) { - forEach(records, function(record){ + forEach(records, function(record) { var pair = Ember.A(recordResolverPairs).findBy('record', record); - if (pair){ + if (pair) { var resolver = pair.resolver; resolver.reject(error); } @@ -1322,7 +1322,7 @@ Store = Ember.Object.extend({ return factory; }, - modelFactoryFor: function(key){ + modelFactoryFor: function(key) { return this.container.lookupFactory('model:' + key); }, @@ -2028,7 +2028,7 @@ function setupRelationships(store, record, data) { } relationship.setCanonicalRecord(value); } else if (kind === 'hasMany' && value) { - relationship.updateRecordsFromAdapter(value); + relationship.updateRecordsFromAdapter(value); } }); } diff --git a/packages/ember-data/tests/integration/adapter/find_all_test.js b/packages/ember-data/tests/integration/adapter/find_all_test.js index 695fb5638b6..2a6ea767c4d 100644 --- a/packages/ember-data/tests/integration/adapter/find_all_test.js +++ b/packages/ember-data/tests/integration/adapter/find_all_test.js @@ -15,7 +15,7 @@ module("integration/adapter/find_all - Finding All Records of a Type", { }, teardown: function() { - run(function(){ + run(function() { if (allRecords) { allRecords.destroy(); } store.destroy(); }); @@ -37,7 +37,7 @@ test("When all records for a type are requested, the store should call the adapt var allRecords; - run(function(){ + run(function() { store.find(Person).then(function(all) { allRecords = all; equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); @@ -45,7 +45,7 @@ test("When all records for a type are requested, the store should call the adapt }); }); - run(function(){ + run(function() { store.find(Person).then(function(all) { // Only one record array per type should ever be created (identity map) strictEqual(allRecords, all, "the same record array is returned every time all records of a type are requested"); @@ -73,7 +73,7 @@ test("When all records for a type are requested, a rejection should reject the p var allRecords; - run(function(){ + run(function() { store.find(Person).then(null, function() { ok(true, "The rejection should get here"); return store.find(Person); @@ -87,9 +87,9 @@ test("When all records for a type are requested, a rejection should reject the p test("When all records for a type are requested, records that are already loaded should be returned immediately.", function() { expect(3); - store = createStore({ adapter: DS.Adapter.extend()}); + store = createStore({ adapter: DS.Adapter.extend() }); - run(function(){ + run(function() { // Load a record from the server store.push(Person, { id: 1, name: "Jeremy Ashkenas" }); // Create a new, unsaved record in the store @@ -106,13 +106,13 @@ test("When all records for a type are requested, records that are already loaded test("When all records for a type are requested, records that are created on the client should be added to the record array.", function() { expect(3); - store = createStore({ adapter: DS.Adapter.extend()}); + store = createStore({ adapter: DS.Adapter.extend() }); allRecords = store.all(Person); equal(get(allRecords, 'length'), 0, "precond - the record array's length is zero before any records are loaded"); - run(function(){ + run(function() { store.createRecord(Person, { name: "Carsten Nielsen" }); }); diff --git a/packages/ember-data/tests/integration/adapter/find_test.js b/packages/ember-data/tests/integration/adapter/find_test.js index 57eaec5f9ed..caeb4ab857a 100644 --- a/packages/ember-data/tests/integration/adapter/find_test.js +++ b/packages/ember-data/tests/integration/adapter/find_test.js @@ -52,7 +52,7 @@ test("When a single record is requested, the adapter's find method should be cal }) }); - run(function(){ + run(function() { store.find(Person, 1); store.find(Person, 1); }); @@ -68,32 +68,32 @@ test("When a single record is requested multiple times, all .find() calls are re }) }); - run(function(){ + run(function() { store.find(Person, 1).then(async(function(person) { equal(person.get('id'), "1"); equal(person.get('name'), "Braaaahm Dale"); stop(); - deferred.promise.then(function(value){ + deferred.promise.then(function(value) { start(); ok(true, 'expected deferred.promise to fulfill'); - },function(reason){ + },function(reason) { start(); ok(false, 'expected deferred.promise to fulfill, but rejected'); }); })); }); - run(function(){ + run(function() { store.find(Person, 1).then(async(function(post) { equal(post.get('id'), "1"); equal(post.get('name'), "Braaaahm Dale"); stop(); - deferred.promise.then(function(value){ + deferred.promise.then(function(value) { start(); ok(true, 'expected deferred.promise to fulfill'); - }, function(reason){ + }, function(reason) { start(); ok(false, 'expected deferred.promise to fulfill, but rejected'); }); @@ -114,7 +114,7 @@ test("When a single record is requested, and the promise is rejected, .find() is }) }); - run(function(){ + run(function() { store.find(Person, 1).then(null, async(function(reason) { ok(true, "The rejection handler was called"); })); diff --git a/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js b/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js index 66fab080895..d5543f9b329 100644 --- a/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js @@ -14,7 +14,7 @@ module("integration/adapter/fixture_adapter - DS.FixtureAdapter", { }); Phone = DS.Model.extend({ - person: DS.belongsTo('person', { async: true}) + person: DS.belongsTo('person', { async: true }) }); env = setupStore({ person: Person, phone: Phone, adapter: DS.FixtureAdapter }); @@ -99,8 +99,8 @@ test("should create record asynchronously when it is committed", function() { var paul; equal(Person.FIXTURES.length, 0, "Fixtures is empty"); - run(function(){ - paul = env.store.createRecord('person', {firstName: 'Paul', lastName: 'Chavard', height: 70}); + run(function() { + paul = env.store.createRecord('person', { firstName: 'Paul', lastName: 'Chavard', height: 70 }); }); paul.on('didCreate', async(function() { @@ -124,7 +124,7 @@ test("should create record asynchronously when it is committed", function() { test("should update record asynchronously when it is committed", function() { equal(Person.FIXTURES.length, 0, "Fixtures is empty"); - var paul = env.store.push('person', { id: 1, firstName: 'Paul', lastName: 'Chavard', height: 70}); + var paul = env.store.push('person', { id: 1, firstName: 'Paul', lastName: 'Chavard', height: 70 }); paul.set('height', 80); @@ -156,7 +156,7 @@ test("should delete record asynchronously when it is committed", function() { var paul = env.store.push('person', { id: 'paul', firstName: 'Paul', lastName: 'Chavard', height: 70 }); - paul.save().then(function(){ + paul.save().then(function() { paul.deleteRecord(); paul.save(); }); @@ -253,8 +253,8 @@ test("should throw if ids are not defined in the FIXTURES", function() { height: 65 }]; - raises(function(){ - run(function(){ + raises(function() { + run(function() { env.store.find('person', 1); }); }, /the id property must be defined as a number or string for fixture/); @@ -282,22 +282,22 @@ asyncTest("copies fixtures instead of passing the direct reference", function() }]; var PersonAdapter = DS.FixtureAdapter.extend({ - find: function(store, type, id){ - return this._super(store, type, id).then(function(fixture){ + find: function(store, type, id) { + return this._super(store, type, id).then(function(fixture) { return returnedFixture = fixture; }); } }); - Ember.run(function(){ + Ember.run(function() { env.container.register('adapter:person', PersonAdapter); }); - env.store.find('person', 1).then(function(){ + env.store.find('person', 1).then(function() { start(); ok(Person.FIXTURES[0] !== returnedFixture, 'returnedFixture does not have object identity with defined fixture'); deepEqual(Person.FIXTURES[0], returnedFixture); - }, function(err){ + }, function(err) { ok(false, 'got error' + err); }); }); @@ -310,7 +310,7 @@ test("should save hasMany records", function() { Person.FIXTURES = [{ id: 'tomjerry', firstName: "Tom", lastName: "Jerry", height: 3 }]; createPhone = async(function(tom) { - env.store.createRecord('phone', {person: tom}); + env.store.createRecord('phone', { person: tom }); return tom.get('phones').then(async(function(p) { equal(p.get('length'), 1, "hasMany relationships are created in the store"); @@ -330,7 +330,7 @@ test("should save hasMany records", function() { })); }); - var ensureFixtureAdapterDoesNotLeak = async(function(){ + var ensureFixtureAdapterDoesNotLeak = async(function() { env.store.destroy(); env = setupStore({ person: Person, phone: Phone, adapter: DS.FixtureAdapter }); return env.store.find('phone').then(async(function(phones) { diff --git a/packages/ember-data/tests/integration/adapter/record_persistence_test.js b/packages/ember-data/tests/integration/adapter/record_persistence_test.js index b52a5dafd61..2e22fe5d7a7 100644 --- a/packages/ember-data/tests/integration/adapter/record_persistence_test.js +++ b/packages/ember-data/tests/integration/adapter/record_persistence_test.js @@ -41,7 +41,7 @@ test("When a store is committed, the adapter's `commit` method should be called return run(Ember.RSVP, 'resolve'); }; - run(function(){ + run(function() { env.store.push('person', { id: 1, name: "Braaaahm Dale" }); }); @@ -65,7 +65,7 @@ test("When a store is committed, the adapter's `commit` method should be called return Ember.RSVP.resolve({ id: 1, name: "Tom Dale" }); }; - run(function(){ + run(function() { tom = env.store.createRecord('person', { name: "Tom Dale" }); tom.save(); }); @@ -79,7 +79,7 @@ test("After a created record has been assigned an ID, finding a record by that I return Ember.RSVP.resolve({ id: 1, name: "Tom Dale" }); }; - run(function(){ + run(function() { tom = env.store.createRecord('person', { name: "Tom Dale" }); tom.save(); }); @@ -97,7 +97,7 @@ test("when a store is committed, the adapter's `commit` method should be called var tom; - run(function(){ + run(function() { env.store.push('person', { id: 1, name: "Tom Dale" }); }); env.store.find('person', 1).then(async(function(person) { @@ -118,12 +118,12 @@ test("An adapter can notify the store that records were updated by calling `didS return Ember.RSVP.resolve(); }; - run(function(){ + run(function() { env.store.push('person', { id: 1 }); env.store.push('person', { id: 2 }); }); - all([ env.store.find('person', 1), env.store.find('person', 2) ]) + all([env.store.find('person', 1), env.store.find('person', 2)]) .then(async(function(array) { tom = array[0]; yehuda = array[1]; @@ -153,7 +153,7 @@ test("An adapter can notify the store that records were updated and provide new } }; - run(function(){ + run(function() { env.store.push('person', { id: 1, name: "Braaaahm Dale" }); env.store.push('person', { id: 2, name: "Gentile Katz" }); }); @@ -176,7 +176,7 @@ test("An adapter can notify the store that a record was updated by calling `didS return Ember.RSVP.resolve(); }; - run(function(){ + run(function() { store.push('person', { id: 1 }); store.push('person', { id: 2 }); }); @@ -204,7 +204,7 @@ test("An adapter can notify the store that a record was updated and provide new } }; - run(function(){ + run(function() { env.store.push('person', { id: 1, name: "Braaaahm Dale" }); env.store.push('person', { id: 2, name: "Gentile Katz" }); }); @@ -228,7 +228,7 @@ test("An adapter can notify the store that records were deleted by calling `didS return Ember.RSVP.resolve(); }; - run(function(){ + run(function() { env.store.push('person', { id: 1, name: "Braaaahm Dale" }); env.store.push('person', { id: 2, name: "Gentile Katz" }); }); diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 7012b448e00..a40cc467a61 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -156,7 +156,7 @@ test("create - an empty payload is a basic success if an id was specified", func ajaxResponse(); var post; - run(function(){ + run(function() { post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); post.save().then(async(function(post) { equal(passedUrl, "/posts"); @@ -171,7 +171,7 @@ test("create - an empty payload is a basic success if an id was specified", func test("create - a payload with a new ID and data applies the updates", function() { ajaxResponse({ posts: [{ id: "1", name: "Dat Parley Letter" }] }); - run(function(){ + run(function() { var post = store.createRecord('post', { name: "The Parley Letter" }); post.save().then(async(function(post) { @@ -189,7 +189,7 @@ test("create - a payload with a new ID and data applies the updates", function() test("create - a payload with a new ID and data applies the updates (with legacy singular name)", function() { var post; ajaxResponse({ post: { id: "1", name: "Dat Parley Letter" } }); - run(function(){ + run(function() { post = store.createRecord('post', { name: "The Parley Letter" }); }); @@ -211,19 +211,19 @@ test("create - findMany doesn't overwrite owner", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); Comment.reopen({ post: DS.belongsTo('post') }); - run(function(){ + run(function() { store.push('post', { id: 1, name: "Rails is omakase", comments: [] }); }); var post = store.getById('post', 1); - run(function(){ + run(function() { comment = store.createRecord('comment', { name: "The Parley Letter" }); }); post.get('comments').pushObject(comment); equal(comment.get('post'), post, "the post has been set correctly"); - run(function(){ + run(function() { comment.save().then(async(function(comment) { equal(comment.get('isDirty'), false, "the post isn't dirty anymore"); equal(comment.get('name'), "Dat Parley Letter", "the post was updated"); @@ -244,7 +244,7 @@ test("create - a serializer's primary key and attributes are consulted when buil ajaxResponse(); - run(function(){ + run(function() { post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); }); @@ -265,7 +265,7 @@ test("create - a serializer's attributes are consulted when building the payload ajaxResponse(); - run(function(){ + run(function() { post = store.createRecord('post', { name: "The Parley Letter" }); post.save().then(async(function(post) { @@ -287,7 +287,7 @@ test("create - a serializer's attribute mapping takes precdence over keyForAttri ajaxResponse(); - run(function(){ + run(function() { var post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); post.save().then(async(function(post) { @@ -311,7 +311,7 @@ test("create - a serializer's attribute mapping takes precedence over keyForRela Comment.reopen({ post: DS.belongsTo('post') }); - run(function(){ + run(function() { var post = store.createRecord('post', { id: "a-post-id", name: "The Parley Letter" }); var comment = store.createRecord('comment', { id: "some-uuid", name: "Letters are fun", post: post }); @@ -336,13 +336,13 @@ test("create - a serializer's attribute mapping takes precedence over keyForRela Post.reopen({ comments: DS.hasMany('comment') }); - run(function(){ + run(function() { var comment = store.createRecord('comment', { id: "a-comment-id", name: "First!" }); var post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); post.get('comments').pushObject(comment); post.save().then(async(function(post) { - deepEqual(passedHash.data, { post: { opinions: [ "a-comment-id" ], id: "some-uuid", name: "The Parley Letter" } }); + deepEqual(passedHash.data, { post: { opinions: ["a-comment-id"], id: "some-uuid", name: "The Parley Letter" } }); })); }); }); @@ -377,7 +377,7 @@ test("create - a record on the many side of a hasMany relationship should update Post.reopen({ comments: DS.hasMany('comment') }); Comment.reopen({ post: DS.belongsTo('post') }); - run(function(){ + run(function() { store.push('post', { id: 1, name: "Rails is omakase", comments: [1] }); store.push('comment', { id: 1, name: "Dat Parlay Letter", post: 1 }); }); @@ -386,7 +386,7 @@ test("create - a record on the many side of a hasMany relationship should update var commentCount = post.get('comments.length'); equal(commentCount, 1, "the post starts life with a comment"); - run(function(){ + run(function() { var comment = store.createRecord('comment', { name: "Another Comment", post: post }); comment.save().then(async(function(comment) { @@ -406,7 +406,7 @@ test("create - sideloaded belongsTo relationships are both marked as loaded", fu Post.reopen({ comment: DS.belongsTo('comment') }); Comment.reopen({ post: DS.belongsTo('post') }); - run(function(){ + run(function() { post = store.createRecord('post', { name: "man" }); }); @@ -415,7 +415,7 @@ test("create - sideloaded belongsTo relationships are both marked as loaded", fu comments: [{ id: 1, post: 1, name: "Comcast is a bargain" }] }); - run(function(){ + run(function() { post.save().then(async(function(record) { equal(store.getById('post', 1).get('comment.isLoaded'), true, "post's comment isLoaded (via store)"); equal(store.getById('comment', 1).get('post.isLoaded'), true, "comment's post isLoaded (via store)"); @@ -455,7 +455,7 @@ test("create - response can contain relationships the client doesn't yet know ab equal(store.typeMapFor(Post).records.length, 1, "There should only be one post record in the store"); var postRecords = store.typeMapFor(Post).records; - for(var i = 0; i < postRecords.length; i++) { + for (var i = 0; i < postRecords.length; i++) { equal(post, postRecords[i], "The object in the identity map is the same"); } })); @@ -468,7 +468,7 @@ test("create - relationships are not duplicated", function() { Post.reopen({ comments: DS.hasMany('comment') }); Comment.reopen({ post: DS.belongsTo('post') }); - run(function(){ + run(function() { post = store.createRecord('post', { name: "Tomtomhuda" }); comment = store.createRecord('comment', { id: 2, name: "Comment title" }); }); @@ -487,12 +487,12 @@ test("create - relationships are not duplicated", function() { return post.save(); })).then(async(function(post) { - equal(post.get('comments.length'), 1, "post has 1 comment"); + equal(post.get('comments.length'), 1, "post has 1 comment"); })); }); test("update - an empty payload is a basic success", function() { - run(function(){ + run(function() { store.push('post', { id: 1, name: "Rails is omakase" }); }); @@ -512,7 +512,7 @@ test("update - an empty payload is a basic success", function() { }); test("update - a payload with updates applies the updates", function() { - run(function(){ + run(function() { store.push('post', { id: 1, name: "Rails is omakase" }); }); @@ -532,7 +532,7 @@ test("update - a payload with updates applies the updates", function() { }); test("update - a payload with updates applies the updates (with legacy singular name)", function() { - run(function(){ + run(function() { store.push('post', { id: 1, name: "Rails is omakase" }); }); @@ -557,7 +557,7 @@ test("update - a payload with sideloaded updates pushes the updates", function() posts: [{ id: 1, name: "Dat Parley Letter" }], comments: [{ id: 1, name: "FIRST" }] }); - run(function(){ + run(function() { post = store.createRecord('post', { name: "The Parley Letter" }); post.save().then(async(function(post) { equal(passedUrl, "/posts"); @@ -575,7 +575,7 @@ test("update - a payload with sideloaded updates pushes the updates", function() }); test("update - a payload with sideloaded updates pushes the updates", function() { - run(function(){ + run(function() { store.push('post', { id: 1, name: "Rails is omakase" }); }); @@ -609,7 +609,7 @@ test("update - a serializer's primary key and attributes are consulted when buil } })); - run(function(){ + run(function() { store.push('post', { id: 1, name: "Rails is omakase" }); }); ajaxResponse(); @@ -623,7 +623,7 @@ test("update - a serializer's primary key and attributes are consulted when buil }); test("delete - an empty payload is a basic success", function() { - run(function(){ + run(function() { store.push('post', { id: 1, name: "Rails is omakase" }); }); @@ -643,7 +643,7 @@ test("delete - an empty payload is a basic success", function() { }); test("delete - a payload with sideloaded updates pushes the updates", function() { - run(function(){ + run(function() { store.push('post', { id: 1, name: "Rails is omakase" }); }); @@ -666,12 +666,12 @@ test("delete - a payload with sideloaded updates pushes the updates", function() }); test("delete - a payload with sidloaded updates pushes the updates when the original record is omitted", function() { - run(function(){ + run(function() { store.push('post', { id: 1, name: "Rails is omakase" }); }); store.find('post', 1).then(async(function(post) { - ajaxResponse({ posts: [{ id: 2, name: "The Parley Letter" }] }); + ajaxResponse({ posts: [{ id: 2, name: "The Parley Letter" }] }); post.deleteRecord(); return post.save(); @@ -690,11 +690,11 @@ test("delete - a payload with sidloaded updates pushes the updates when the orig test("delete - deleting a newly created record should not throw an error", function() { var post; - run(function(){ + run(function() { post = store.createRecord('post'); }); - run(function(){ + run(function() { post.deleteRecord(); post.save().then(async(function(post) { equal(passedUrl, null, "There is no ajax call to delete a record that has never been saved."); @@ -739,7 +739,7 @@ test("findAll - returning an array populates the array", function() { equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); deepEqual( posts.toArray(), - [ post1, post2 ], + [post1, post2], "The correct records are in the array" ); })); @@ -792,7 +792,7 @@ test("findAll - data is normalized through custom serializers", function() { equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); deepEqual( posts.toArray(), - [ post1, post2 ], + [post1, post2], "The correct records are in the array" ); })); @@ -800,7 +800,7 @@ test("findAll - data is normalized through custom serializers", function() { test("findAll - since token is passed to the adapter", function() { ajaxResponse({ - meta: { since: 'later'}, + meta: { since: 'later' }, posts: [ { id: 1, name: "Rails is omakase" }, { id: 2, name: "The Parley Letter" } @@ -820,7 +820,7 @@ test("findAll - since token is passed to the adapter", function() { test("metadata is accessible", function() { ajaxResponse({ meta: { offset: 5 }, - posts: [{id: 1, name: "Rails is very expensive sushi"}] + posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); store.findAll('post').then(async(function(posts) { @@ -835,7 +835,7 @@ test("metadata is accessible", function() { test("findQuery - payload 'meta' is accessible on the record array", function() { ajaxResponse({ meta: { offset: 5 }, - posts: [{id: 1, name: "Rails is very expensive sushi"}] + posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); store.findQuery('post', { page: 2 }).then(async(function(posts) { @@ -850,7 +850,7 @@ test("findQuery - payload 'meta' is accessible on the record array", function() test("findQuery - each record array can have it's own meta object", function() { ajaxResponse({ meta: { offset: 5 }, - posts: [{id: 1, name: "Rails is very expensive sushi"}] + posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); store.findQuery('post', { page: 2 }).then(async(function(posts) { @@ -861,9 +861,9 @@ test("findQuery - each record array can have it's own meta object", function() { ); ajaxResponse({ meta: { offset: 1 }, - posts: [{id: 1, name: "Rails is very expensive sushi"}] + posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - store.findQuery('post', { page: 1}).then(async(function(newPosts){ + store.findQuery('post', { page: 1 }).then(async(function(newPosts) { equal(newPosts.get('meta.offset'), 1, 'new array has correct metadata'); equal(posts.get('meta.offset'), 5, 'metadata on the old array hasnt been clobbered'); })); @@ -901,7 +901,7 @@ test("findQuery - returning an array populates the array", function() { equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); deepEqual( posts.toArray(), - [ post1, post2 ], + [post1, post2], "The correct records are in the array" ); })); @@ -954,7 +954,7 @@ test("findQuery - data is normalized through custom serializers", function() { equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); deepEqual( posts.toArray(), - [ post1, post2 ], + [post1, post2], "The correct records are in the array" ); })); @@ -964,8 +964,8 @@ test("findMany - findMany uses a correct URL to access the records", function() Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; - run(function(){ - store.push('post', { id: 1, name: "Rails is omakase", comments: [ 1, 2, 3 ] }); + run(function() { + store.push('post', { id: 1, name: "Rails is omakase", comments: [1, 2, 3] }); }); var post = store.getById('post', 1); @@ -978,15 +978,15 @@ test("findMany - findMany uses a correct URL to access the records", function() }); run(post, 'get', 'comments').then(async(function(comments) { equal(passedUrl, "/comments"); - deepEqual(passedHash, {data: {ids: ["1", "2", "3"]}}); + deepEqual(passedHash, { data: { ids: ["1", "2", "3"] } }); })); }); test("findMany - findMany does not coalesce by default", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(function(){ - store.push('post', { id: 1, name: "Rails is omakase", comments: [ 1, 2, 3 ] }); + run(function() { + store.push('post', { id: 1, name: "Rails is omakase", comments: [1, 2, 3] }); }); var post = store.getById('post', 1); @@ -1008,8 +1008,8 @@ test("findMany - returning an array populates the array", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; - run(function(){ - store.push('post', { id: 1, name: "Rails is omakase", comments: [ 1, 2, 3 ] }); + run(function() { + store.push('post', { id: 1, name: "Rails is omakase", comments: [1, 2, 3] }); }); store.find('post', 1).then(async(function(post) { @@ -1021,7 +1021,7 @@ test("findMany - returning an array populates the array", function() { ] }); -return post.get('comments'); + return post.get('comments'); })).then(async(function(comments) { var comment1 = store.getById('comment', 1), comment2 = store.getById('comment', 2), @@ -1033,7 +1033,7 @@ return post.get('comments'); deepEqual( comments.toArray(), - [ comment1, comment2, comment3 ], + [comment1, comment2, comment3], "The correct records are in the array" ); })); @@ -1043,8 +1043,8 @@ test("findMany - returning sideloaded data loads the data", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; - run(function(){ - store.push('post', { id: 1, name: "Rails is omakase", comments: [ 1, 2, 3 ] }); + run(function() { + store.push('post', { id: 1, name: "Rails is omakase", comments: [1, 2, 3] }); }); store.find('post', 1).then(async(function(post) { @@ -1068,7 +1068,7 @@ test("findMany - returning sideloaded data loads the data", function() { deepEqual( comments.toArray(), - [ comment1, comment2, comment3 ], + [comment1, comment2, comment3], "The correct records are in the array" ); @@ -1091,8 +1091,8 @@ test("findMany - a custom serializer is used if present", function() { adapter.coalesceFindRequests = true; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(function(){ - store.push('post', { id: 1, name: "Rails is omakase", comments: [ 1, 2, 3 ] }); + run(function() { + store.push('post', { id: 1, name: "Rails is omakase", comments: [1, 2, 3] }); }); store.find('post', 1).then(async(function(post) { @@ -1113,14 +1113,14 @@ test("findMany - a custom serializer is used if present", function() { deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); - deepEqual(comments.toArray(), [ comment1, comment2, comment3 ], "The correct records are in the array"); + deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); })); }); test("findHasMany - returning an array populates the array", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(function(){ + run(function() { store.push( 'post', { @@ -1154,7 +1154,7 @@ test("findHasMany - returning an array populates the array", function() { deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); - deepEqual(comments.toArray(), [ comment1, comment2, comment3 ], "The correct records are in the array"); + deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); })); }); @@ -1162,7 +1162,7 @@ test("findMany - returning sideloaded data loads the data", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; - run(function(){ + run(function() { store.push( 'post', { @@ -1190,7 +1190,7 @@ test("findMany - returning sideloaded data loads the data", function() { comment3 = store.getById('comment', 3), post2 = store.getById('post', 2); - deepEqual(comments.toArray(), [ comment1, comment2, comment3 ], "The correct records are in the array"); + deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "The Parley Letter" }); })); @@ -1209,7 +1209,7 @@ test("findMany - a custom serializer is used if present", function() { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(function(){ + run(function() { store.push( 'post', { @@ -1238,12 +1238,12 @@ test("findMany - a custom serializer is used if present", function() { deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); - deepEqual(comments.toArray(), [ comment1, comment2, comment3 ], "The correct records are in the array"); + deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); })); }); test('buildURL - with host and namespace', function() { - run(function(){ + run(function() { adapter.setProperties({ host: 'http://example.com', namespace: 'api/v1' @@ -1258,7 +1258,7 @@ test('buildURL - with host and namespace', function() { }); test('buildURL - with relative paths in links', function() { - run(function(){ + run(function() { adapter.setProperties({ host: 'http://example.com', namespace: 'api/v1' @@ -1278,7 +1278,7 @@ test('buildURL - with relative paths in links', function() { }); test('buildURL - with absolute paths in links', function() { - run(function(){ + run(function() { adapter.setProperties({ host: 'http://example.com', namespace: 'api/v1' @@ -1313,7 +1313,7 @@ test('buildURL - with full URLs in links', function() { ] }); - run(function(){ + run(function() { store.find('post', 1).then(async(function(post) { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); @@ -1333,7 +1333,7 @@ test('buildURL - with camelized names', function() { ajaxResponse({ superUsers: [{ id: 1 }] }); - run(function(){ + run(function() { store.find('superUser', 1).then(async(function(post) { equal(passedUrl, "/super_users/1"); })); @@ -1349,12 +1349,12 @@ test('buildURL - buildURL takes a record from find', function() { ajaxResponse({ comments: [{ id: 1 }] }); var post; - run(function(){ + run(function() { post = store.push('post', { id: 2 }); }); - run(function(){ - store.find('comment', 1, {post: post}).then(async(function(post) { + run(function() { + store.find('comment', 1, { post: post }).then(async(function(post) { equal(passedUrl, "/posts/2/comments/1"); })); }); @@ -1362,17 +1362,17 @@ test('buildURL - buildURL takes a record from find', function() { test('buildURL - buildURL takes the records from findMany', function() { Comment.reopen({ post: DS.belongsTo('post') }); - Post.reopen({ comments: DS.hasMany('comment', {async: true}) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.buildURL = function(type, ids, records) { return "/posts/" + records.get('firstObject.post.id') + '/comments/'; }; adapter.coalesceFindRequests = true; - ajaxResponse({ comments: [{ id: 1 }, {id:2}, {id:3}] }); + ajaxResponse({ comments: [{ id: 1 }, { id: 2 }, { id: 3 }] }); var post; - run(function(){ + run(function() { post = store.push('post', { id: 2, comments: [1,2,3] }); post.get('comments').then(async(function(post) { equal(passedUrl, "/posts/2/comments/"); @@ -1388,7 +1388,7 @@ test('buildURL - buildURL takes a record from create', function() { ajaxResponse({ comments: [{ id: 1 }] }); - run(function(){ + run(function() { var post = store.push('post', { id: 2 }); var comment = store.createRecord('comment'); comment.set('post', post); @@ -1399,11 +1399,11 @@ test('buildURL - buildURL takes a record from create', function() { }); test('buildURL - buildURL takes a record from create to query a resolved async belongsTo relationship', function() { - Comment.reopen({ post: DS.belongsTo('post', {async: true}) }); + Comment.reopen({ post: DS.belongsTo('post', { async: true }) }); ajaxResponse({ posts: [{ id: 2 }] }); - run(function(){ + run(function() { store.find('post', 2).then(async(function(post) { equal(post.get('id'), 2); @@ -1432,12 +1432,12 @@ test('buildURL - buildURL takes a record from update', function() { ajaxResponse({ comments: [{ id: 1 }] }); var post, comment; - run(function(){ + run(function() { post = store.push('post', { id: 2 }); comment = store.push('comment', { id: 1 }); comment.set('post', post); }); - run(function(){ + run(function() { comment.save().then(async(function(post) { equal(passedUrl, "/posts/2/comments/1"); })); @@ -1454,14 +1454,14 @@ test('buildURL - buildURL takes a record from delete', function() { ajaxResponse({ comments: [{ id: 1 }] }); var post, comment; - run(function(){ + run(function() { post = store.push('post', { id: 2 }); comment = store.push('comment', { id: 1 }); comment.set('post', post); comment.deleteRecord(); }); - run(function(){ + run(function() { comment.save().then(async(function(post) { equal(passedUrl, "posts/2/comments/1"); })); @@ -1470,11 +1470,11 @@ test('buildURL - buildURL takes a record from delete', function() { test('groupRecordsForFindMany groups records based on their url', function() { Comment.reopen({ post: DS.belongsTo('post') }); - Post.reopen({ comments: DS.hasMany('comment', {async: true}) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; adapter.buildURL = function(type, id, record) { - if (id === '1'){ + if (id === '1') { return '/comments/1'; } else { return '/other_comments/' + id; @@ -1483,31 +1483,31 @@ test('groupRecordsForFindMany groups records based on their url', function() { adapter.find = function(store, type, id, record ) { equal(id, '1'); - return Ember.RSVP.resolve({comments: {id:1}}); + return Ember.RSVP.resolve({ comments: { id: 1 } }); }; adapter.findMany = function(store, type, ids, records ) { deepEqual(ids, ['2', '3']); - return Ember.RSVP.resolve({comments: [{id:2}, {id:3}]}); + return Ember.RSVP.resolve({ comments: [{ id: 2 }, { id: 3 }] }); }; var post; - run(function(){ + run(function() { post = store.push('post', { id: 2, comments: [1,2,3] }); }); - run(function(){ + run(function() { post.get('comments'); }); }); test('groupRecordsForFindMany groups records correctly when singular URLs are encoded as query params', function() { Comment.reopen({ post: DS.belongsTo('post') }); - Post.reopen({ comments: DS.hasMany('comment', {async: true}) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; adapter.buildURL = function(type, id, record) { - if (id === '1'){ + if (id === '1') { return '/comments?id=1'; } else { return '/other_comments?id=' + id; @@ -1516,20 +1516,20 @@ test('groupRecordsForFindMany groups records correctly when singular URLs are en adapter.find = function(store, type, id, record ) { equal(id, '1'); - return Ember.RSVP.resolve({comments: {id:1}}); + return Ember.RSVP.resolve({ comments: { id: 1 } }); }; adapter.findMany = function(store, type, ids, records ) { deepEqual(ids, ['2', '3']); - return Ember.RSVP.resolve({comments: [{id:2}, {id:3}]}); + return Ember.RSVP.resolve({ comments: [{ id: 2 }, { id: 3 }] }); }; var post; - run(function(){ + run(function() { post = store.push('post', { id: 2, comments: [1,2,3] }); }); - run(function(){ + run(function() { post.get('comments'); }); }); @@ -1576,7 +1576,7 @@ test('normalizeKey - to set up _ids and _id', function() { name: "Rails is omakase", author_name: "@d2h", author_id: "1", - comment_ids: [ "1", "2" ] + comment_ids: ["1", "2"] }], users: [{ @@ -1593,7 +1593,7 @@ test('normalizeKey - to set up _ids and _id', function() { }] }); - run(function(){ + run(function() { store.find('post', 1).then(async(function(post) { equal(post.get('authorName'), "@d2h"); equal(post.get('author.name'), "D2H"); @@ -1604,7 +1604,7 @@ test('normalizeKey - to set up _ids and _id', function() { test('groupRecordsForFindMany splits up calls for large ids', function() { Comment.reopen({ post: DS.belongsTo('post') }); - Post.reopen({ comments: DS.hasMany('comment', {async: true}) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); expect(2); @@ -1615,7 +1615,7 @@ test('groupRecordsForFindMany splits up calls for large ids', function() { var a2000 = repeatChar('a', 2000); var b2000 = repeatChar('b', 2000); var post; - run(function(){ + run(function() { post = store.push('post', { id: 1, comments: [a2000, b2000] }); }); @@ -1634,14 +1634,14 @@ test('groupRecordsForFindMany splits up calls for large ids', function() { return Ember.RSVP.reject(); }; - run(function(){ + run(function() { post.get('comments'); }); }); test('groupRecordsForFindMany groups calls for small ids', function() { Comment.reopen({ post: DS.belongsTo('post') }); - Post.reopen({ comments: DS.hasMany('comment', {async: true}) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); expect(1); @@ -1653,7 +1653,7 @@ test('groupRecordsForFindMany groups calls for small ids', function() { var b100 = repeatChar('b', 100); var post; - run(function(){ + run(function() { post = store.push('post', { id: 1, comments: [a100, b100] }); }); @@ -1669,12 +1669,12 @@ test('groupRecordsForFindMany groups calls for small ids', function() { return Ember.RSVP.resolve({ comments: { id: ids } }); }; - run(function(){ + run(function() { post.get('comments'); }); }); -test("calls adapter.ajaxSuccess with the jqXHR and json", function(){ +test("calls adapter.ajaxSuccess with the jqXHR and json", function() { expect(2); var originalAjax = Ember.$.ajax; var jqXHR = {}; @@ -1685,7 +1685,7 @@ test("calls adapter.ajaxSuccess with the jqXHR and json", function(){ } }; - Ember.$.ajax = function(hash){ + Ember.$.ajax = function(hash) { hash.success(data, 'ok', jqXHR); }; @@ -1696,7 +1696,7 @@ test("calls adapter.ajaxSuccess with the jqXHR and json", function(){ }; try { - run(function(){ + run(function() { store.find('post', '1'); }); } finally { @@ -1704,14 +1704,14 @@ test("calls adapter.ajaxSuccess with the jqXHR and json", function(){ } }); -test('calls ajaxError with jqXHR, jqXHR.responseText', function(){ +test('calls ajaxError with jqXHR, jqXHR.responseText', function() { expect(3); var originalAjax = Ember.$.ajax; var jqXHR = { responseText: 'Nope lol' }; - Ember.$.ajax = function(hash){ + Ember.$.ajax = function(hash) { hash.error(jqXHR, jqXHR.responseText); }; @@ -1722,8 +1722,8 @@ test('calls ajaxError with jqXHR, jqXHR.responseText', function(){ }; try { - run(function(){ - store.find('post', '1').catch(function(err){ + run(function() { + store.find('post', '1').catch(function(err) { ok(err, 'promise rejected'); }); }); @@ -1732,7 +1732,7 @@ test('calls ajaxError with jqXHR, jqXHR.responseText', function(){ } }); -test("rejects promise if DS.InvalidError is returned from adapter.ajaxSuccess", function(){ +test("rejects promise if DS.InvalidError is returned from adapter.ajaxSuccess", function() { expect(3); var originalAjax = Ember.$.ajax; var jqXHR = {}; @@ -1783,8 +1783,8 @@ test('ajaxError appends errorThrown for sanity', function() { }; try { - run(function(){ - store.find('post', '1').catch(function(err){ + run(function() { + store.find('post', '1').catch(function(err) { equal(err.errorThrown, errorThrown); ok(err, 'promise rejected'); }); diff --git a/packages/ember-data/tests/integration/adapter/store_adapter_test.js b/packages/ember-data/tests/integration/adapter/store_adapter_test.js index c923cf4939e..18816371a57 100644 --- a/packages/ember-data/tests/integration/adapter/store_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/store_adapter_test.js @@ -49,7 +49,7 @@ test("Records loaded multiple times and retrieved in recordArray are ready to se }]); }; - run(store, 'findQuery', 'person', {q: 'bla'}).then(async(function(people) { + run(store, 'findQuery', 'person', { q: 'bla' }).then(async(function(people) { var people2 = store.findQuery('person', { q: 'bla2' }); return Ember.RSVP.hash({ people: people, people2: people2 }); @@ -89,12 +89,12 @@ test("by default, createRecords calls createRecord once per record", function() }; var tom, yehuda; - run(function(){ + run(function() { tom = store.createRecord('person', { name: "Tom Dale" }); yehuda = store.createRecord('person', { name: "Yehuda Katz" }); }); - var promise = run(function(){ + var promise = run(function() { return Ember.RSVP.hash({ tom: tom.save(), yehuda: yehuda.save() @@ -132,12 +132,12 @@ test("by default, updateRecords calls updateRecord once per record", function() return Ember.RSVP.resolve(); }; - run(function(){ + run(function() { store.push('person', { id: 1, name: "Braaaahm Dale" }); store.push('person', { id: 2, name: "Brohuda Katz" }); }); - var promise = run(function(){ + var promise = run(function() { return Ember.RSVP.hash({ tom: store.find('person', 1), yehuda: store.find('person', 2) @@ -180,12 +180,12 @@ test("calling store.didSaveRecord can provide an optional hash", function() { } }; - run(function(){ + run(function() { store.push('person', { id: 1, name: "Braaaahm Dale" }); store.push('person', { id: 2, name: "Brohuda Katz" }); }); - var promise = run(function(){ + var promise = run(function() { return Ember.RSVP.hash({ tom: store.find('person', 1), yehuda: store.find('person', 2) @@ -230,12 +230,12 @@ test("by default, deleteRecord calls deleteRecord once per record", function() { return Ember.RSVP.resolve(); }; - run(function(){ + run(function() { store.push('person', { id: 1, name: "Tom Dale" }); store.push('person', { id: 2, name: "Yehuda Katz" }); }); - var promise = run(function(){ + var promise = run(function() { return Ember.RSVP.hash({ tom: store.find('person', 1), yehuda: store.find('person', 2) @@ -274,12 +274,12 @@ test("by default, destroyRecord calls deleteRecord once per record without requi return Ember.RSVP.resolve(); }; - run(function(){ + run(function() { store.push('person', { id: 1, name: "Tom Dale" }); store.push('person', { id: 2, name: "Yehuda Katz" }); }); - var promise = run(function(){ + var promise = run(function() { return Ember.RSVP.hash({ tom: store.find('person', 1), yehuda: store.find('person', 2) @@ -312,7 +312,7 @@ test("if an existing model is edited then deleted, deleteRecord is called on the }; // Load data for a record into the store. - run(function(){ + run(function() { store.push('person', { id: 'deleted-record', name: "Tom Dale" }); }); @@ -341,13 +341,13 @@ test("if a deleted record errors, it enters the error state", function() { } }; - run(function(){ + run(function() { store.push('person', { id: 'deleted-record', name: "Tom Dale" }); }); var tom; - run(function(){ + run(function() { store.find('person', 'deleted-record').then(async(function(person) { tom = person; person.deleteRecord(); @@ -374,7 +374,7 @@ test("if a created record is marked as invalid by the server, it enters an error } }; - var yehuda = run(function(){ + var yehuda = run(function() { return store.createRecord('person', { id: 1, name: "Yehuda Katz" }); }); // Wrap this in an Ember.run so that all chained async behavior is set up @@ -417,7 +417,7 @@ test("if a created record is marked as invalid by the server, you can attempt th } }; - var yehuda = run(function(){ + var yehuda = run(function() { return store.createRecord('person', { id: 1, name: "Yehuda Katz" }); }); @@ -475,7 +475,7 @@ test("if an updated record is marked as invalid by the server, it enters an erro } }; - var yehuda = run(function(){ + var yehuda = run(function() { return store.push('person', { id: 1, name: "Brohuda Brokatz" }); }); @@ -522,7 +522,7 @@ test("if an updated record is marked as invalid by the server, you can attempt t } }; - var yehuda = run(function(){ + var yehuda = run(function() { return store.push('person', { id: 1, name: "Brohuda Brokatz" }); }); @@ -565,7 +565,7 @@ test("if a updated record is marked as erred by the server, it enters an error s return Ember.RSVP.reject(); }; - var person = run(function(){ + var person = run(function() { return store.push(Person, { id: 1, name: "John Doe" }); }); @@ -586,7 +586,7 @@ test("can be created after the DS.Store", function() { return Ember.RSVP.resolve({ id: 1 }); }; - run(function(){ + run(function() { store.find('person', 1); }); }); @@ -610,7 +610,7 @@ test("the filter method can optionally take a server query as well", function() return store.find('person', 2); })).then(async(function(tom) { equal(get(loadedFilter, 'length'), 1, "The filter has an item in it"); - deepEqual(loadedFilter.toArray(), [ tom ], "The filter has a single entry in it"); + deepEqual(loadedFilter.toArray(), [tom], "The filter has a single entry in it"); })); }); @@ -619,7 +619,7 @@ test("relationships returned via `commit` do not trigger additional findManys", dogs: DS.hasMany() }); - run(function(){ + run(function() { store.push('dog', { id: 1, name: "Scruffy" }); }); @@ -639,7 +639,7 @@ test("relationships returned via `commit` do not trigger additional findManys", ok(false, "Should not get here"); }; - run(function(){ + run(function() { store.find('person', 1).then(async(function(person) { return Ember.RSVP.hash({ tom: person, dog: store.find('dog', 1) }); })).then(async(function(records) { @@ -664,7 +664,7 @@ test("relationships don't get reset if the links is the same", function() { return Ember.RSVP.resolve([{ id: 1, name: "Scruffy" }]); }; - run(function(){ + run(function() { store.push('person', { id: 1, name: "Tom Dale", links: { dogs: "/dogs" } }); }); @@ -697,13 +697,13 @@ test("async hasMany always returns a promise", function() { }; var tom; - run(function(){ + run(function() { tom = store.createRecord('person', { name: "Tom Dale" }); }); ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise before save"); - run(function(){ + run(function() { tom.save().then(async(function() { ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise after save"); })); diff --git a/packages/ember-data/tests/integration/all_test.js b/packages/ember-data/tests/integration/all_test.js index e1495bc7535..31dbdc9207a 100644 --- a/packages/ember-data/tests/integration/all_test.js +++ b/packages/ember-data/tests/integration/all_test.js @@ -19,14 +19,14 @@ module("integration/all - DS.Store#all()", { }); test("store.all('person') should return all records and should update with new ones", function() { - run(function(){ + run(function() { store.pushMany('person', array); }); var all = store.all('person'); equal(get(all, 'length'), 2); - run(function(){ + run(function() { store.pushMany('person', moreArray); }); diff --git a/packages/ember-data/tests/integration/application_test.js b/packages/ember-data/tests/integration/application_test.js index 745a9600ec3..82e195c6e22 100644 --- a/packages/ember-data/tests/integration/application_test.js +++ b/packages/ember-data/tests/integration/application_test.js @@ -12,11 +12,11 @@ var app, App, container; initialization and dependency injection APIs. */ -function getStore(){ +function getStore() { return lookup('store:main'); } -function lookup(thing){ +function lookup(thing) { return run(container, 'lookup', thing); } @@ -43,7 +43,7 @@ module("integration/application - Injecting a Custom Store", { }); test("If a Store property exists on an Ember.Application, it should be instantiated.", function() { - run(function(){ + run(function() { ok(getStore().get('isCustom'), "the custom store was instantiated"); }); }); @@ -54,10 +54,10 @@ test("If a store is instantiated, it should be made available to each controller ok(isCustom, "the custom store was injected"); }); -test("registering App.Store is deprecated but functional", function(){ +test("registering App.Store is deprecated but functional", function() { run(app, 'destroy'); - expectDeprecation(function(){ + expectDeprecation(function() { run(function() { app = Application.create({ Store: DS.Store.extend({ isCustomButDeprecated: true }), @@ -68,12 +68,12 @@ test("registering App.Store is deprecated but functional", function(){ }, 'Specifying a custom Store for Ember Data on your global namespace as `App.Store` ' + 'has been deprecated. Please use `App.ApplicationStore` instead.'); - run(function(){ + run(function() { ok(lookup('store:main').get('isCustomButDeprecated'), "the custom store was instantiated"); }); var fooController = lookup('controller:foo'); - run(function(){ + run(function() { ok(fooController.get('store.isCustomButDeprecated'), "the custom store was injected"); }); }); @@ -103,14 +103,14 @@ test("If a Store property exists on an Ember.Application, it should be instantia }); test("If a store is instantiated, it should be made available to each controller.", function() { - run(function(){ + run(function() { var fooController = lookup('controller:foo'); ok(fooController.get('store') instanceof DS.Store, "the store was injected"); }); }); test("the DS namespace should be accessible", function() { - run(function(){ + run(function() { ok(Namespace.byName('DS') instanceof Namespace, "the DS namespace is accessible"); }); }); @@ -128,75 +128,75 @@ module("integration/application - Attaching initializer", { } }); -test("ember-data initializer is run", function(){ +test("ember-data initializer is run", function() { var ran = false; App.initializer({ name: "after-ember-data", after: "ember-data", - initialize: function(){ ran = true; } + initialize: function() { ran = true; } }); - run(function(){ + run(function() { app = App.create(); }); ok(ran, 'ember-data initializer was found'); }); -test("store initializer is run (DEPRECATED)", function(){ +test("store initializer is run (DEPRECATED)", function() { var ran = false; App.initializer({ name: "after-store", after: 'store', - initialize: function(){ ran = true; } + initialize: function() { ran = true; } }); - run(function(){ + run(function() { app = App.create(); }); ok(ran, 'store initializer was found'); }); -test("injectStore initializer is run (DEPRECATED)", function(){ +test("injectStore initializer is run (DEPRECATED)", function() { var ran = false; App.initializer({ name: "after-store", after: 'injectStore', - initialize: function(){ ran = true; } + initialize: function() { ran = true; } }); - run(function(){ + run(function() { app = App.create(); }); ok(ran, 'injectStore initializer was found'); }); -test("transforms initializer is run (DEPRECATED)", function(){ +test("transforms initializer is run (DEPRECATED)", function() { var ran = false; App.initializer({ name: "after-store", after: 'transforms', - initialize: function(){ ran = true; } + initialize: function() { ran = true; } }); - run(function(){ + run(function() { app = App.create(); }); ok(ran, 'transforms initializer was found'); }); -test("activeModelAdapter initializer is run (DEPRECATED)", function(){ +test("activeModelAdapter initializer is run (DEPRECATED)", function() { var ran = false; App.initializer({ name: "after-store", after: 'activeModelAdapter', - initialize: function(){ ran = true; } + initialize: function() { ran = true; } }); - run(function(){ + run(function() { app = App.create(); }); diff --git a/packages/ember-data/tests/integration/client_id_generation_test.js b/packages/ember-data/tests/integration/client_id_generation_test.js index a794d8fe1a2..1b89b9e6cce 100644 --- a/packages/ember-data/tests/integration/client_id_generation_test.js +++ b/packages/ember-data/tests/integration/client_id_generation_test.js @@ -45,7 +45,7 @@ test("If an adapter implements the `generateIdForRecord` method, the store shoul }; var comment, post; - run(function(){ + run(function() { comment = env.store.createRecord('comment'); post = env.store.createRecord('post'); }); @@ -55,7 +55,7 @@ test("If an adapter implements the `generateIdForRecord` method, the store shoul // Despite client-generated IDs, calling commit() on the store should still // invoke the adapter's `createRecord` method. - run(function(){ + run(function() { comment.save(); post.save(); }); diff --git a/packages/ember-data/tests/integration/debug_adapter_test.js b/packages/ember-data/tests/integration/debug_adapter_test.js index 9d2a6c0e5ce..9599d60b12e 100644 --- a/packages/ember-data/tests/integration/debug_adapter_test.js +++ b/packages/ember-data/tests/integration/debug_adapter_test.js @@ -5,7 +5,7 @@ module("DS.DebugAdapter", { setup: function() { Ember.run(function() { App = Ember.Application.create(); - App.toString = function(){ return 'App'; }; + App.toString = function() { return 'App'; }; App.ApplicationStore = DS.Store.extend({ adapter: DS.Adapter.extend() @@ -47,8 +47,8 @@ test("Watching Model Types", function() { debugAdapter.watchModelTypes(added, updated); - run(function(){ - store.push('post', {id: 1, title: 'Post Title'}); + run(function() { + store.push('post', { id: 1, title: 'Post Title' }); }); }); @@ -56,7 +56,7 @@ test("Watching Records", function() { var post, args, record; Ember.run(function() { - store.push('post', { id: '1', title: 'Clean Post'}); + store.push('post', { id: '1', title: 'Clean Post' }); }); var callback = function() { @@ -67,7 +67,7 @@ test("Watching Records", function() { equal(get(args[0], 'length'), 1); record = args[0][0]; - deepEqual(record.columnValues, { id: '1', title: 'Clean Post'} ); + deepEqual(record.columnValues, { id: '1', title: 'Clean Post' } ); deepEqual(record.filterValues, { isNew: false, isModified: false, isClean: true } ); deepEqual(record.searchKeywords, ['1', 'Clean Post'] ); deepEqual(record.color, 'black' ); @@ -81,16 +81,16 @@ test("Watching Records", function() { }); record = args[0][0]; - deepEqual(record.columnValues, { id: '1', title: 'Modified Post'}); + deepEqual(record.columnValues, { id: '1', title: 'Modified Post' }); deepEqual(record.filterValues, { isNew: false, isModified: true, isClean: false }); deepEqual(record.searchKeywords, ['1', 'Modified Post'] ); deepEqual(record.color, 'blue' ); - run(function(){ + run(function() { post = store.createRecord('post', { id: '2', title: 'New Post' }); }); record = args[0][0]; - deepEqual(record.columnValues, { id: '2', title: 'New Post'}); + deepEqual(record.columnValues, { id: '2', title: 'New Post' }); deepEqual(record.filterValues, { isNew: true, isModified: false, isClean: false }); deepEqual(record.searchKeywords, ['2', 'New Post'] ); deepEqual(record.color, 'green' ); diff --git a/packages/ember-data/tests/integration/filter_test.js b/packages/ember-data/tests/integration/filter_test.js index ef222993538..5c468071554 100644 --- a/packages/ember-data/tests/integration/filter_test.js +++ b/packages/ember-data/tests/integration/filter_test.js @@ -46,18 +46,18 @@ function tapFn(fn, callback) { test("when a DS.Model updates its attributes, its changes affect its filtered Array membership", function() { - run(function(){ + run(function() { store.pushMany('person', array); }); var people; - run(function(){ + run(function() { people = store.filter('person', function(hash) { if (hash.get('name').match(/Katz$/)) { return true; } }); }); - run(function(){ + run(function() { equal(get(people, 'length'), 1, "precond - one item is in the RecordArray"); }); @@ -65,14 +65,14 @@ test("when a DS.Model updates its attributes, its changes affect its filtered Ar equal(get(person, 'name'), "Scumbag Katz", "precond - the item is correct"); - run(function(){ + run(function() { set(person, 'name', "Yehuda Katz"); }); equal(get(people, 'length'), 1, "there is still one item"); equal(get(person, 'name'), "Yehuda Katz", "it has the updated item"); - run(function(){ + run(function() { set(person, 'name', "Yehuda Katz-Foo"); }); @@ -81,18 +81,18 @@ test("when a DS.Model updates its attributes, its changes affect its filtered Ar }); test("when a DS.Model updates its relationships, its changes affect its filtered Array membership", function() { - run(function(){ + run(function() { store.pushMany('person', array); }); var people; - run(function(){ + run(function() { people = store.filter('person', function(person) { if (person.get('bestFriend') && person.get('bestFriend.name').match(/Katz$/)) { return true; } }); }); - run(function(){ + run(function() { equal(get(people, 'length'), 1, "precond - one item is in the RecordArray"); }); @@ -100,7 +100,7 @@ test("when a DS.Model updates its relationships, its changes affect its filtered equal(get(person, 'name'), "Scumbag Dale", "precond - the item is correct"); - run(function(){ + run(function() { set(person, 'bestFriend', null); }); @@ -108,7 +108,7 @@ test("when a DS.Model updates its relationships, its changes affect its filtered var erik = store.getById('person', 3); var yehuda = store.getById('person', 2); - run(function(){ + run(function() { erik.set('bestFriend', yehuda); }); @@ -119,12 +119,12 @@ test("when a DS.Model updates its relationships, its changes affect its filtered test("a record array can have a filter on it", function() { - run(function(){ + run(function() { store.pushMany('person', array); }); var recordArray; - run(function(){ + run(function() { recordArray = store.filter('person', function(hash) { if (hash.get('name').match(/Scumbag [KD]/)) { return true; } }); @@ -132,13 +132,13 @@ test("a record array can have a filter on it", function() { equal(get(recordArray, 'length'), 2, "The Record Array should have the filtered objects on it"); - run(function(){ + run(function() { store.push('person', { id: 4, name: "Scumbag Koz" }); }); equal(get(recordArray, 'length'), 3, "The Record Array should be updated as new items are added to the store"); - run(function(){ + run(function() { store.push('person', { id: 1, name: "Scumbag Tom" }); }); @@ -146,12 +146,12 @@ test("a record array can have a filter on it", function() { }); test("a filtered record array includes created elements", function() { - run(function(){ + run(function() { store.pushMany('person', array); }); var recordArray; - run(function(){ + run(function() { recordArray = store.filter('person', function(hash) { if (hash.get('name').match(/Scumbag [KD]/)) { return true; } }); @@ -159,7 +159,7 @@ test("a filtered record array includes created elements", function() { equal(get(recordArray, 'length'), 2, "precond - The Record Array should have the filtered objects on it"); - run(function(){ + run(function() { store.createRecord('person', { name: "Scumbag Koz" }); }); @@ -167,7 +167,7 @@ test("a filtered record array includes created elements", function() { }); test("a Record Array can update its filter", function() { - run(function(){ + run(function() { set(store, 'adapter', DS.Adapter.extend({ deleteRecord: function(store, type, record) { return Ember.RSVP.resolve(); @@ -175,18 +175,18 @@ test("a Record Array can update its filter", function() { })); }); - run(function(){ + run(function() { store.pushMany('person', array); }); - var dickens = run(function(){ + var dickens = run(function() { var record = store.createRecord('person', { id: 4, name: "Scumbag Dickens" }); record.deleteRecord(); return record; }); var asyncDale, asyncKatz, asyncBryn; - run(function(){ + run(function() { asyncDale = store.find('person', 1); asyncKatz = store.find('person', 2); asyncBryn = store.find('person', 3); @@ -226,7 +226,7 @@ test("a Record Array can update its filter", function() { }); test("a Record Array can update its filter and notify array observers", function() { - run(function(){ + run(function() { set(store, 'adapter', DS.Adapter.extend({ deleteRecord: function(store, type, record) { return Ember.RSVP.resolve(); @@ -234,19 +234,19 @@ test("a Record Array can update its filter and notify array observers", function })); }); - run(function(){ + run(function() { store.pushMany('person', array); }); var dickens; - run(function(){ + run(function() { dickens = store.createRecord('person', { id: 4, name: "Scumbag Dickens" }); dickens.deleteRecord(); }); var asyncDale, asyncKatz, asyncBryn; - run(function(){ + run(function() { asyncDale = store.find('person', 1); asyncKatz = store.find('person', 2); asyncBryn = store.find('person', 3); @@ -276,7 +276,7 @@ test("a Record Array can update its filter and notify array observers", function }); }); - Ember.RSVP.all([ asyncDale, asyncKatz, asyncBryn ]).then(async(function() { + Ember.RSVP.all([asyncDale, asyncKatz, asyncBryn]).then(async(function() { equal(didChangeRemoved, 1, "removed one item from array"); didChangeRemoved = 0; @@ -317,7 +317,7 @@ test("it is possible to filter by computed properties", function() { }); var filter; - run(function(){ + run(function() { filter = store.filter('person', function(person) { return person.get('upperName') === "TOM DALE"; }); @@ -325,7 +325,7 @@ test("it is possible to filter by computed properties", function() { equal(filter.get('length'), 0, "precond - the filter starts empty"); - run(function(){ + run(function() { store.push('person', { id: 1, name: "Tom Dale" }); }); @@ -348,12 +348,12 @@ test("a filter created after a record is already loaded works", function() { }).property('name') }); - run(function(){ + run(function() { store.push('person', { id: 1, name: "Tom Dale" }); }); var filter; - run(function(){ + run(function() { filter = store.filter('person', function(person) { return person.get('upperName') === "TOM DALE"; }); @@ -374,7 +374,7 @@ test("filter with query persists query on the resulting filteredRecordArray", fu })); var filter; - run(function(){ + run(function() { filter = store.filter(Person, { foo: 1 }, function(person) { return true; }); @@ -390,7 +390,7 @@ test("filter with query persists query on the resulting filteredRecordArray", fu test("it is possible to filter by state flags", function() { var filter; - run(function(){ + run(function() { set(store, 'adapter', DS.Adapter.extend({ find: function(store, type, id) { return Ember.RSVP.resolve({ id: id, name: "Tom Dale" }); @@ -430,7 +430,7 @@ test("it is possible to filter loaded records by dirtiness", function() { return !person.get('isDirty'); }); - run(function(){ + run(function() { store.push('person', { id: 1, name: "Tom Dale" }); }); @@ -452,7 +452,7 @@ test("it is possible to filter loaded records by dirtiness", function() { }); test("it is possible to filter created records by dirtiness", function() { - run(function(){ + run(function() { set(store, 'adapter', DS.Adapter.extend({ createRecord: function() { return Ember.RSVP.resolve(); @@ -462,7 +462,7 @@ test("it is possible to filter created records by dirtiness", function() { var filter; - run(function(){ + run(function() { filter = store.filter('person', function(person) { return !person.get('isDirty'); }); @@ -470,7 +470,7 @@ test("it is possible to filter created records by dirtiness", function() { var person; - run(function(){ + run(function() { person = store.createRecord('person', { id: 1, name: "Tom Dale" @@ -479,7 +479,7 @@ test("it is possible to filter created records by dirtiness", function() { equal(filter.get('length'), 0, "the dirty record is not in the filter"); - run(function(){ + run(function() { person.save().then(function(person) { equal(filter.get('length'), 1, "the clean record is in the filter"); }); @@ -541,12 +541,12 @@ var clientCreates = function(names) { }); }; -var serverResponds = function(){ +var serverResponds = function() { forEach(edited, function(person) { run(person, 'save'); }); }; var setup = function(serverCallbacks) { - run(function(){ + run(function() { set(store, 'adapter', DS.Adapter.extend(serverCallbacks)); store.pushMany('person', array); @@ -562,7 +562,7 @@ var setup = function(serverCallbacks) { test("a Record Array can update its filter after server-side updates one record", function() { setup({ updateRecord: function(store, type, record) { - return Ember.RSVP.resolve({id: 1, name: "Scumbag Server-side Dale"}); + return Ember.RSVP.resolve({ id: 1, name: "Scumbag Server-side Dale" }); } }); @@ -595,7 +595,7 @@ test("a Record Array can update its filter after server-side updates multiple re test("a Record Array can update its filter after server-side creates one record", function() { setup({ createRecord: function(store, type, record) { - return Ember.RSVP.resolve({id: 4, name: "Scumbag Server-side Tim"}); + return Ember.RSVP.resolve({ id: 4, name: "Scumbag Server-side Tim" }); } }); @@ -611,9 +611,9 @@ test("a Record Array can update its filter after server-side creates multiple re createRecord: function(store, type, record) { switch (record.get('name')) { case "Client-side Mike": - return Ember.RSVP.resolve({id: 4, name: "Scumbag Server-side Mike"}); + return Ember.RSVP.resolve({ id: 4, name: "Scumbag Server-side Mike" }); case "Client-side David": - return Ember.RSVP.resolve({id: 5, name: "Scumbag Server-side David"}); + return Ember.RSVP.resolve({ id: 5, name: "Scumbag Server-side David" }); } } }); @@ -630,9 +630,9 @@ test("a Record Array can update its filter after server-side creates multiple re createRecord: function(store, type, record) { switch (record.get('name')) { case "Client-side Mike": - return Ember.RSVP.resolve({id: 4, name: "Scumbag Server-side Mike"}); + return Ember.RSVP.resolve({ id: 4, name: "Scumbag Server-side Mike" }); case "Client-side David": - return Ember.RSVP.resolve({id: 5, name: "Scumbag Server-side David"}); + return Ember.RSVP.resolve({ id: 5, name: "Scumbag Server-side David" }); } } }); @@ -645,10 +645,10 @@ test("a Record Array can update its filter after server-side creates multiple re }); test("destroying filteredRecordArray unregisters models from being filtered", function() { - var filterFn = tapFn( function(){ return true; } ); + var filterFn = tapFn( function() { return true; } ); var person; - run(function(){ + run(function() { person = store.push('person', { id: 1, name: 'Tom Dale' @@ -657,14 +657,14 @@ test("destroying filteredRecordArray unregisters models from being filtered", fu var recordArray; - run(function(){ + run(function() { recordArray = store.filter('person', filterFn); }); equal(filterFn.summary.called.length, 1); - Ember.run(function(){ - recordArray.then(function(array){ + Ember.run(function() { + recordArray.then(function(array) { array.destroy(); }); }); diff --git a/packages/ember-data/tests/integration/inverse_test.js b/packages/ember-data/tests/integration/inverse_test.js index baabd6a16cc..7bf99b8de3b 100644 --- a/packages/ember-data/tests/integration/inverse_test.js +++ b/packages/ember-data/tests/integration/inverse_test.js @@ -11,7 +11,7 @@ module('integration/inverse_test - inverseFor', { setup: function() { User = DS.Model.extend({ name: attr('string'), - bestFriend: belongsTo('user', {async: true}), + bestFriend: belongsTo('user', { async: true }), job: belongsTo('job') }); @@ -39,7 +39,7 @@ module('integration/inverse_test - inverseFor', { test("Finds the inverse when there is only one possible available", function () { //Maybe store is evaluated lazily, so we need this :( - run(store, 'push', 'user', {id:1}); + run(store, 'push', 'user', { id: 1 }); deepEqual(Job.inverseFor('user'), { type: User, @@ -50,7 +50,7 @@ test("Finds the inverse when there is only one possible available", function () test("Finds the inverse when only one side has defined it manually", function () { Job.reopen({ - owner: belongsTo('user', {inverse: 'previousJob'}) + owner: belongsTo('user', { inverse: 'previousJob' }) }); User.reopen({ @@ -59,9 +59,9 @@ test("Finds the inverse when only one side has defined it manually", function () //Maybe store is evaluated lazily, so we need this :( var user, job; - run(function(){ - user = store.push('user', {id:1}); - job = store.push('user', {id:1}); + run(function() { + user = store.push('user', { id: 1 }); + job = store.push('user', { id: 1 }); }); deepEqual(Job.inverseFor('owner'), { @@ -79,7 +79,7 @@ test("Finds the inverse when only one side has defined it manually", function () test("Returns null if inverse relationship it is manually set with a different relationship key", function () { Job.reopen({ - user: belongsTo('user', {inverse: 'previousJob'}) + user: belongsTo('user', { inverse: 'previousJob' }) }); User.reopen({ @@ -87,8 +87,8 @@ test("Returns null if inverse relationship it is manually set with a different r }); //Maybe store is evaluated lazily, so we need this :( var user; - run(function(){ - user = store.push('user', {id:1}); + run(function() { + user = store.push('user', { id: 1 }); }); equal(User.inverseFor('job'), null, 'There is no inverse'); @@ -96,8 +96,8 @@ test("Returns null if inverse relationship it is manually set with a different r test("Errors out if you define 2 inverses to the same model", function () { Job.reopen({ - user: belongsTo('user', {inverse: 'job'}), - owner: belongsTo('user', {inverse: 'job'}) + user: belongsTo('user', { inverse: 'job' }), + owner: belongsTo('user', { inverse: 'job' }) }); User.reopen({ @@ -106,8 +106,8 @@ test("Errors out if you define 2 inverses to the same model", function () { //Maybe store is evaluated lazily, so we need this :( expectAssertion(function() { - run(function(){ - store.push('user', {id:1}); + run(function() { + store.push('user', { id: 1 }); }); User.inverseFor('job'); }, "You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses"); @@ -117,12 +117,12 @@ test("Errors out if you define 2 inverses to the same model", function () { test("Caches findInverseFor return value", function () { expect(1); //Maybe store is evaluated lazily, so we need this :( - run(function(){ - store.push('user', {id:1}); + run(function() { + store.push('user', { id: 1 }); }); var inverseForUser = Job.inverseFor('user'); - Job.findInverseFor = function(){ + Job.findInverseFor = function() { ok(false, 'Find is not called anymore'); }; diff --git a/packages/ember-data/tests/integration/lifecycle_hooks_test.js b/packages/ember-data/tests/integration/lifecycle_hooks_test.js index adc52906f43..61d78efdd4e 100644 --- a/packages/ember-data/tests/integration/lifecycle_hooks_test.js +++ b/packages/ember-data/tests/integration/lifecycle_hooks_test.js @@ -27,7 +27,7 @@ asyncTest("When the adapter acknowledges that a record has been created, a `didC }; var person; - run(function(){ + run(function() { person = env.store.createRecord(Person, { name: "Yehuda Katz" }); }); @@ -49,7 +49,7 @@ test("When the adapter acknowledges that a record has been created without a new }; var person; - run(function(){ + run(function() { person = env.store.createRecord(Person, { id: 99, name: "Yehuda Katz" }); }); diff --git a/packages/ember-data/tests/integration/record_array_manager_test.js b/packages/ember-data/tests/integration/record_array_manager_test.js index f8af1deda0c..e04f550fc09 100644 --- a/packages/ember-data/tests/integration/record_array_manager_test.js +++ b/packages/ember-data/tests/integration/record_array_manager_test.js @@ -19,7 +19,7 @@ Car.toString = function() { return "Car"; }; var manager; module("integration/record_array_manager- destroy", { - setup: function(){ + setup: function() { env = setupStore({ adapter: DS.FixtureAdapter.extend() }); @@ -53,7 +53,7 @@ test("destroying the store correctly cleans everything up", function() { var query = { }; var person; - run(function(){ + run(function() { store.push('car', { id: 1, make: 'BMC', @@ -62,7 +62,7 @@ test("destroying the store correctly cleans everything up", function() { }); }); - run(function(){ + run(function() { person = store.push('person', { id: 1, name: 'Tom Dale', @@ -70,8 +70,8 @@ test("destroying the store correctly cleans everything up", function() { }); }); - var filterd = manager.createFilteredRecordArray(Person, function(){ return true; }); - var filterd2 = manager.createFilteredRecordArray(Person, function(){ return true; }); + var filterd = manager.createFilteredRecordArray(Person, function() { return true; }); + var filterd2 = manager.createFilteredRecordArray(Person, function() { return true; }); var adapterPopulated = manager.createAdapterPopulatedRecordArray(Person, query); var filterdSummary = tap(filterd, 'willDestroy'); @@ -109,7 +109,7 @@ test("Should not filter a stor.all() array when a record property is changed", f store.all('car'); - run(function(){ + run(function() { car = store.push('car', { id: 1, make: 'BMC', @@ -120,7 +120,7 @@ test("Should not filter a stor.all() array when a record property is changed", f equal(filterdSummary.called.length, 1); - run(function(){ + run(function() { car.set('model', 'Mini'); }); diff --git a/packages/ember-data/tests/integration/records/collection_save_test.js b/packages/ember-data/tests/integration/records/collection_save_test.js index 90a5b88f91b..bc87f93aa77 100644 --- a/packages/ember-data/tests/integration/records/collection_save_test.js +++ b/packages/ember-data/tests/integration/records/collection_save_test.js @@ -19,9 +19,9 @@ module("integration/records/collection_save - Save Collection of Records", { test("Collection will resolve save on success", function() { expect(1); - run(function(){ - env.store.createRecord('post', {title: 'Hello'}); - env.store.createRecord('post', {title: 'World'}); + run(function() { + env.store.createRecord('post', { title: 'Hello' }); + env.store.createRecord('post', { title: 'World' }); }); var posts = env.store.all('post'); @@ -30,7 +30,7 @@ test("Collection will resolve save on success", function() { return Ember.RSVP.resolve({ id: 123 }); }; - run(function(){ + run(function() { posts.save().then(async(function() { ok(true, 'save operation was resolved'); })); @@ -38,9 +38,9 @@ test("Collection will resolve save on success", function() { }); test("Collection will reject save on error", function() { - run(function(){ - env.store.createRecord('post', {title: 'Hello'}); - env.store.createRecord('post', {title: 'World'}); + run(function() { + env.store.createRecord('post', { title: 'Hello' }); + env.store.createRecord('post', { title: 'World' }); }); var posts = env.store.all('post'); @@ -49,7 +49,7 @@ test("Collection will reject save on error", function() { return Ember.RSVP.reject(); }; - run(function(){ + run(function() { posts.save().then(function() {}, async(function() { ok(true, 'save operation was rejected'); })); @@ -57,9 +57,9 @@ test("Collection will reject save on error", function() { }); test("Retry is allowed in a failure handler", function() { - run(function(){ - env.store.createRecord('post', {title: 'Hello'}); - env.store.createRecord('post', {title: 'World'}); + run(function() { + env.store.createRecord('post', { title: 'Hello' }); + env.store.createRecord('post', { title: 'World' }); }); var posts = env.store.all('post'); @@ -78,7 +78,7 @@ test("Retry is allowed in a failure handler", function() { return Ember.RSVP.resolve({ id: 123 }); }; - run(function(){ + run(function() { posts.save().then(function() {}, async(function() { return posts.save(); })).then(async(function(post) { @@ -89,9 +89,9 @@ test("Retry is allowed in a failure handler", function() { test("Collection will reject save on invalid", function() { expect(1); - run(function(){ - env.store.createRecord('post', {title: 'Hello'}); - env.store.createRecord('post', {title: 'World'}); + run(function() { + env.store.createRecord('post', { title: 'Hello' }); + env.store.createRecord('post', { title: 'World' }); }); var posts = env.store.all('post'); @@ -100,7 +100,7 @@ test("Collection will reject save on invalid", function() { return Ember.RSVP.reject({ title: 'invalid' }); }; - Ember.run(function(){ + Ember.run(function() { posts.save().then(function() {}, function() { ok(true, 'save operation was rejected'); }); diff --git a/packages/ember-data/tests/integration/records/delete_record_test.js b/packages/ember-data/tests/integration/records/delete_record_test.js index c758c4ef2c9..f65f8a23af3 100644 --- a/packages/ember-data/tests/integration/records/delete_record_test.js +++ b/packages/ember-data/tests/integration/records/delete_record_test.js @@ -16,7 +16,7 @@ module("integration/deletedRecord - Deleting Records", { }, teardown: function() { - Ember.run(function(){ + Ember.run(function() { env.container.destroy(); }); } @@ -24,16 +24,16 @@ module("integration/deletedRecord - Deleting Records", { test("records can be deleted during record array enumeration", function () { var adam, dave; - run(function(){ - adam = env.store.push('person', {id: 1, name: "Adam Sunderland"}); - dave = env.store.push('person', {id: 2, name: "Dave Sunderland"}); + run(function() { + adam = env.store.push('person', { id: 1, name: "Adam Sunderland" }); + dave = env.store.push('person', { id: 2, name: "Dave Sunderland" }); }); var all = env.store.all('person'); // pre-condition equal(all.get('length'), 2, 'expected 2 records'); - Ember.run(function(){ + Ember.run(function() { all.forEach(function(record) { record.deleteRecord(); }); @@ -44,13 +44,13 @@ test("records can be deleted during record array enumeration", function () { test("when deleted records are rolled back, they are still in their previous record arrays", function () { var jaime, cersei; - run(function(){ - jaime = env.store.push('person', {id: 1, name: "Jaime Lannister"}); - cersei = env.store.push('person', {id: 2, name: "Cersei Lannister"}); + run(function() { + jaime = env.store.push('person', { id: 1, name: "Jaime Lannister" }); + cersei = env.store.push('person', { id: 2, name: "Cersei Lannister" }); }); var all = env.store.all('person'); var filtered; - run(function(){ + run(function() { filtered = env.store.filter('person', function () { return true; }); @@ -59,7 +59,7 @@ test("when deleted records are rolled back, they are still in their previous rec equal(all.get('length'), 2, 'precond - we start with two people'); equal(filtered.get('length'), 2, 'precond - we start with two people'); - run(function(){ + run(function() { jaime.deleteRecord(); jaime.rollback(); }); diff --git a/packages/ember-data/tests/integration/records/reload_test.js b/packages/ember-data/tests/integration/records/reload_test.js index c85778f08db..0dbca0c9b59 100644 --- a/packages/ember-data/tests/integration/records/reload_test.js +++ b/packages/ember-data/tests/integration/records/reload_test.js @@ -37,7 +37,7 @@ test("When a single record is requested, the adapter's find method should be cal } }; - run(function(){ + run(function() { env.store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is loaded with the right name"); equal(get(person, 'isLoaded'), true, "The person is now loaded"); @@ -53,7 +53,7 @@ test("When a single record is requested, the adapter's find method should be cal test("When a record is reloaded and fails, it can try again", function() { var tom; - run(function(){ + run(function() { tom = env.store.push('person', { id: 1, name: "Tom Dale" }); }); @@ -66,7 +66,7 @@ test("When a record is reloaded and fails, it can try again", function() { } }; - run(function(){ + run(function() { tom.reload().then(null, function() { equal(tom.get('isError'), true, "Tom is now errored"); return tom.reload(); @@ -79,11 +79,11 @@ test("When a record is reloaded and fails, it can try again", function() { }); test("When a record is loaded a second time, isLoaded stays true", function() { - run(function(){ + run(function() { env.store.push('person', { id: 1, name: "Tom Dale" }); }); - run(function(){ + run(function() { env.store.find('person', 1).then(function(person) { equal(get(person, 'isLoaded'), true, "The person is loaded"); person.addObserver('isLoaded', isLoadedDidChange); @@ -125,13 +125,14 @@ test("When a record is reloaded, its async hasMany relationships still work", fu var tom; - run(function(){ - env.store.find('person', 1).then(function(person) { tom = person; + run(function() { + env.store.find('person', 1).then(function(person) { + tom = person; equal(person.get('name'), "Tom", "precond"); return person.get('tags'); }).then(function(tags) { - deepEqual(tags.mapBy('name'), [ 'hipster', 'hair' ]); + deepEqual(tags.mapBy('name'), ['hipster', 'hair']); return tom.reload(); }).then(function(person) { @@ -139,7 +140,7 @@ test("When a record is reloaded, its async hasMany relationships still work", fu return person.get('tags'); }).then(function(tags) { - deepEqual(tags.mapBy('name'), [ 'hipster', 'hair' ], "The tags are still there"); + deepEqual(tags.mapBy('name'), ['hipster', 'hair'], "The tags are still there"); }); }); }); diff --git a/packages/ember-data/tests/integration/records/save_test.js b/packages/ember-data/tests/integration/records/save_test.js index c059ffccde3..bd0a3f61598 100644 --- a/packages/ember-data/tests/integration/records/save_test.js +++ b/packages/ember-data/tests/integration/records/save_test.js @@ -20,15 +20,15 @@ module("integration/records/save - Save Record", { test("Will resolve save on success", function() { expect(1); var post; - run(function(){ - post = env.store.createRecord('post', {title: 'toto'}); + run(function() { + post = env.store.createRecord('post', { title: 'toto' }); }); env.adapter.createRecord = function(store, type, record) { return Ember.RSVP.resolve({ id: 123 }); }; - run(function(){ + run(function() { post.save().then(function() { ok(true, 'save operation was resolved'); }); @@ -37,15 +37,15 @@ test("Will resolve save on success", function() { test("Will reject save on error", function() { var post; - run(function(){ - post = env.store.createRecord('post', {title: 'toto'}); + run(function() { + post = env.store.createRecord('post', { title: 'toto' }); }); env.adapter.createRecord = function(store, type, record) { return Ember.RSVP.reject(); }; - run(function(){ + run(function() { post.save().then(function() {}, function() { ok(true, 'save operation was rejected'); }); @@ -54,8 +54,8 @@ test("Will reject save on error", function() { test("Retry is allowed in a failure handler", function() { var post; - run(function(){ - post = env.store.createRecord('post', {title: 'toto'}); + run(function() { + post = env.store.createRecord('post', { title: 'toto' }); }); var count = 0; @@ -68,7 +68,7 @@ test("Retry is allowed in a failure handler", function() { } }; - run(function(){ + run(function() { post.save().then(function() {}, function() { return post.save(); }).then(function(post) { @@ -81,15 +81,15 @@ test("Repeated failed saves keeps the record in uncommited state", function() { expect(2); var post; - run(function(){ - post = env.store.createRecord('post', {title: 'toto'}); + run(function() { + post = env.store.createRecord('post', { title: 'toto' }); }); env.adapter.createRecord = function(store, type, record) { return Ember.RSVP.reject(); }; - run(function(){ + run(function() { post.save().then(null, function() { equal(post.get('currentState.stateName'), 'root.loaded.created.uncommitted'); @@ -103,15 +103,15 @@ test("Repeated failed saves keeps the record in uncommited state", function() { test("Will reject save on invalid", function() { expect(1); var post; - run(function(){ - post = env.store.createRecord('post', {title: 'toto'}); + run(function() { + post = env.store.createRecord('post', { title: 'toto' }); }); env.adapter.createRecord = function(store, type, record) { return Ember.RSVP.reject({ title: 'invalid' }); }; - run(function(){ + run(function() { post.save().then(function() {}, function() { ok(true, 'save operation was rejected'); }); diff --git a/packages/ember-data/tests/integration/records/unload_test.js b/packages/ember-data/tests/integration/records/unload_test.js index f379ef2750f..9ca738e3665 100644 --- a/packages/ember-data/tests/integration/records/unload_test.js +++ b/packages/ember-data/tests/integration/records/unload_test.js @@ -19,14 +19,14 @@ Person.toString = function() { return "Person"; }; module("integration/unload - Unloading Records", { setup: function() { - env = setupStore({ - person: Person, - car: Car - }); + env = setupStore({ + person: Person, + car: Car + }); }, teardown: function() { - Ember.run(function(){ + Ember.run(function() { env.container.destroy(); }); } @@ -34,11 +34,11 @@ module("integration/unload - Unloading Records", { test("can unload a single record", function () { var adam; - run(function(){ - adam = env.store.push('person', {id: 1, name: "Adam Sunderland"}); + run(function() { + adam = env.store.push('person', { id: 1, name: "Adam Sunderland" }); }); - Ember.run(function(){ + Ember.run(function() { adam.unloadRecord(); }); @@ -47,12 +47,12 @@ test("can unload a single record", function () { test("can unload all records for a given type", function () { var adam, bob; - run(function(){ - adam = env.store.push('person', {id: 1, name: "Adam Sunderland"}); - bob = env.store.push('person', {id: 2, name: "Bob Bobson"}); + run(function() { + adam = env.store.push('person', { id: 1, name: "Adam Sunderland" }); + bob = env.store.push('person', { id: 2, name: "Bob Bobson" }); }); - Ember.run(function(){ + Ember.run(function() { env.store.unloadAll('person'); }); @@ -61,12 +61,12 @@ test("can unload all records for a given type", function () { test("removes findAllCache after unloading all records", function () { var adam, bob; - run(function(){ - adam = env.store.push('person', {id: 1, name: "Adam Sunderland"}); - bob = env.store.push('person', {id: 2, name: "Bob Bobson"}); + run(function() { + adam = env.store.push('person', { id: 1, name: "Adam Sunderland" }); + bob = env.store.push('person', { id: 2, name: "Bob Bobson" }); }); - Ember.run(function(){ + Ember.run(function() { env.store.all('person'); env.store.unloadAll('person'); }); @@ -76,15 +76,15 @@ test("removes findAllCache after unloading all records", function () { test("unloading all records also updates record array from all()", function() { var adam, bob; - run(function(){ - adam = env.store.push('person', {id: 1, name: "Adam Sunderland"}); - bob = env.store.push('person', {id: 2, name: "Bob Bobson"}); + run(function() { + adam = env.store.push('person', { id: 1, name: "Adam Sunderland" }); + bob = env.store.push('person', { id: 2, name: "Bob Bobson" }); }); var all = env.store.all('person'); equal(all.get('length'), 2); - Ember.run(function(){ + Ember.run(function() { env.store.unloadAll('person'); }); @@ -95,7 +95,7 @@ test("unloading all records also updates record array from all()", function() { //TODO(Igor) think about how this works with ssot and unloading test("unloading a record also clears its relationship", function() { var adam, bob; - run(function(){ + run(function() { adam = env.store.push('person', { id: 1, name: "Adam Sunderland", @@ -103,7 +103,7 @@ test("unloading a record also clears its relationship", function() { }); }); - run(function(){ + run(function() { bob = env.store.push('car', { id: 1, make: "Lotus", @@ -112,11 +112,11 @@ test("unloading a record also clears its relationship", function() { }); }); - run(function(){ - env.store.find('person', 1).then(function(person){ + run(function() { + env.store.find('person', 1).then(function(person) { equal(person.get('cars.length'), 1, 'aaaa'); - run(function(){ + run(function() { person.unloadRecord(); }); diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index 90788c4201f..945379fc6e9 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -11,8 +11,8 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { setup: function() { User = DS.Model.extend({ name: attr('string'), - messages: hasMany('message', {polymorphic: true}), - favouriteMessage: belongsTo('message', {polymorphic: true, inverse: null}), + messages: hasMany('message', { polymorphic: true }), + favouriteMessage: belongsTo('message', { polymorphic: true, inverse: null }) }); Message = DS.Model.extend({ @@ -79,14 +79,14 @@ test("The store can materialize a non loaded monomorphic belongsTo association", }); }; - run(function(){ + run(function() { env.store.push('post', { id: 1, user: 2 }); }); - run(function(){ + run(function() { env.store.find('post', 1).then(function(post) { post.get('user'); }); @@ -96,12 +96,12 @@ test("The store can materialize a non loaded monomorphic belongsTo association", test("Only a record of the same type can be used with a monomorphic belongsTo relationship", function() { expect(1); - run(function(){ + run(function() { store.push('post', { id: 1 }); store.push('comment', { id: 2 }); }); - run(function(){ + run(function() { hash({ post: store.find('post', 1), comment: store.find('comment', 2) @@ -115,14 +115,14 @@ test("Only a record of the same type can be used with a monomorphic belongsTo re test("Only a record of the same base type can be used with a polymorphic belongsTo relationship", function() { expect(1); - run(function(){ + run(function() { store.push('comment', { id: 1 }); store.push('comment', { id: 2 }); store.push('post', { id: 1 }); store.push('user', { id: 3 }); }); - run(function(){ + run(function() { var asyncRecords = hash({ user: store.find('user', 3), post: store.find('post', 1), @@ -145,12 +145,12 @@ test("Only a record of the same base type can be used with a polymorphic belongs }); test("The store can load a polymorphic belongsTo association", function() { - run(function(){ + run(function() { env.store.push('post', { id: 1 }); env.store.push('comment', { id: 2, message: 1, messageType: 'post' }); }); - run(function(){ + run(function() { hash({ message: store.find('post', 1), comment: store.find('comment', 2) @@ -165,7 +165,7 @@ test("The store can serialize a polymorphic belongsTo association", function() { ok(true, "The serializer's serializePolymorphicType method should be called"); json["message_type"] = "post"; }; - run(function(){ + run(function() { env.store.push('post', { id: 1 }); env.store.push('comment', { id: 2, message: 1, messageType: 'post' }); @@ -189,7 +189,7 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to env.container.register('model:group', Group); env.container.register('model:person', Person); - run(function(){ + run(function() { store.push('person', { id: 1, links: { group: '/people/1/group' } }); }); @@ -205,7 +205,7 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to return Ember.RSVP.resolve({ id: 1, people: [1] }); }); - run(function(){ + run(function() { env.store.find('person', 1).then(function(person) { return person.get('group'); }).then(function(group) { @@ -227,7 +227,7 @@ test('A record with an async belongsTo relationship always returns a promise for env.container.register('model:seat', Seat); env.container.register('model:person', Person); - run(function(){ + run(function() { store.push('person', { id: 1, links: { seat: '/people/1/seat' } }); }); @@ -236,16 +236,16 @@ test('A record with an async belongsTo relationship always returns a promise for }; env.adapter.findBelongsTo = async(function(store, record, link, relationship) { - return Ember.RSVP.resolve({ id: 1}); + return Ember.RSVP.resolve({ id: 1 }); }); - run(function(){ + run(function() { env.store.find('person', 1).then(function(person) { person.get('seat').then(function(seat) { - // this assertion fails too - // ok(seat.get('person') === person, 'parent relationship should be populated'); - seat.set('person', person); - ok(person.get('seat').then, 'seat should be a PromiseObject'); + // this assertion fails too + // ok(seat.get('person') === person, 'parent relationship should be populated'); + seat.set('person', person); + ok(person.get('seat').then, 'seat should be a PromiseObject'); }); }); }); @@ -265,7 +265,7 @@ test("A record with an async belongsTo relationship returning null should resolv env.container.register('model:group', Group); env.container.register('model:person', Person); - run(function(){ + run(function() { store.push('person', { id: 1, links: { group: '/people/1/group' } }); }); @@ -436,7 +436,7 @@ test("relationship changes shouldn’t cause async fetches", function() { }) }); var post, comment; - run(function(){ + run(function() { post = env.store.push('post', { id: 1, comments: [1, 2, 3] @@ -478,7 +478,7 @@ test("Destroying a record with an unloaded aync belongsTo association does not f }) }); - run(function(){ + run(function() { post = env.store.push('post', { id: 1, user: 2 @@ -500,7 +500,7 @@ test("Destroying a record with an unloaded aync belongsTo association does not f test("A sync belongsTo errors out if the record is unlaoded", function() { var message; - run(function(){ + run(function() { message = env.store.push('message', { id: 1, user: 2 }); }); @@ -514,11 +514,11 @@ test("Rollbacking a deleted record restores implicit relationship - async", func author: DS.belongsTo('author', { async: true }) }); var book, author; - run(function(){ + run(function() { book = env.store.push('book', { id: 1, name: "Stanley's Amazing Adventures", author: 2 }); author = env.store.push('author', { id: 2, name: 'Stanley' }); }); - run(function(){ + run(function() { author.deleteRecord(); author.rollback(); book.get('author').then(function(fetchedAuthor) { @@ -529,11 +529,11 @@ test("Rollbacking a deleted record restores implicit relationship - async", func test("Rollbacking a deleted record restores implicit relationship - sync", function () { var book, author; - run(function(){ + run(function() { book = env.store.push('book', { id: 1, name: "Stanley's Amazing Adventures", author: 2 }); author = env.store.push('author', { id: 2, name: 'Stanley' }); }); - run(function(){ + run(function() { author.deleteRecord(); author.rollback(); }); diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 0fad354b6af..001ed3457fd 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -92,8 +92,8 @@ test("When a hasMany relationship is accessed, the adapter's findMany method sho ok(false, "The adapter's find method should not be called"); }; - run(function(){ - env.store.push('post', { id: 1, comments: [ 1 ] }); + run(function() { + env.store.push('post', { id: 1, comments: [1] }); env.store.push('comment', { id: 1 }); env.store.find('post', 1).then(function(post) { return post.get('comments'); @@ -133,7 +133,7 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi ]); }; - run(function(){ + run(function() { env.store.find('post', 1).then(async(function(post) { return post.get('comments'); })).then(async(function(comments) { @@ -156,8 +156,8 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ }); var post; - run(function(){ - post = env.store.push('post', { id: 1, links: {comments: '/posts/1/comments'}}); + run(function() { + post = env.store.push('post', { id: 1, links: { comments: '/posts/1/comments' } }); }); env.adapter.findHasMany = function(store, record, link, relationship) { @@ -166,7 +166,7 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ equal(count, 1, "findHasMany has only been called once"); stop(); return new Ember.RSVP.Promise(function(resolve, reject) { - setTimeout(function(){ + setTimeout(function() { var value = [ { id: 1, body: "First" }, { id: 2, body: "Second" } @@ -178,10 +178,10 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ stop(); var promise1, promise2; - run(function(){ + run(function() { promise1 = post.get('comments'); //Invalidate the post.comments CP - env.store.push('comment', { id:1, message: 1 }); + env.store.push('comment', { id: 1, message: 1 }); promise2 = post.get('comments'); }); Ember.RSVP.all([promise1, promise2]).then(function() { @@ -207,13 +207,13 @@ test("A hasMany backed by a link remains a promise after a record has been added ]); }; var post; - run(function(){ - post = env.store.push('post', { id: 1, links: {comments: '/posts/1/comments'}}); + run(function() { + post = env.store.push('post', { id: 1, links: { comments: '/posts/1/comments' } }); }); - run(function(){ + run(function() { post.get('comments').then(function() { - env.store.push('comment', { id:3, message: 1 }); + env.store.push('comment', { id: 3, message: 1 }); post.get('comments').then(function() { ok(true, 'Promise was called'); }); @@ -244,7 +244,7 @@ test("A hasMany updated link should not remove new children", function() { run(function() { var post = env.store.createRecord('post', {}); - env.store.createRecord('comment', {message: post}); + env.store.createRecord('comment', { message: post }); post.get('comments') .then(function(comments) { @@ -271,7 +271,7 @@ test("A hasMany updated link should not remove new children when the parent reco }); env.adapter.findHasMany = function(store, record, link, relationship) { - return Ember.RSVP.resolve([{id:5, body: 'hello'}]); + return Ember.RSVP.resolve([{ id: 5, body: 'hello' }]); }; env.adapter.createRecord = function(store, record, link, relationship) { @@ -284,7 +284,7 @@ test("A hasMany updated link should not remove new children when the parent reco run(function() { var post = env.store.createRecord('post', {}); - env.store.createRecord('comment', {message: post}); + env.store.createRecord('comment', { message: post }); post.get('comments') .then(function(comments) { @@ -325,7 +325,7 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func ]); }; - run(function(){ + run(function() { run(env.store, 'find', 'post', 1).then(function(post) { return post.get('comments'); }).then(function(comments) { @@ -345,7 +345,7 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func }; return comments.reload(); - }).then(function(newComments){ + }).then(function(newComments) { equal(newComments.get('length'), 3, "reloaded comments have 3 length"); }); }); @@ -360,10 +360,10 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu equal(type, Post, "find type was Post"); equal(id, "1", "find id was 1"); - return Ember.RSVP.resolve({ id: 1, comments: [ 1, 2 ] }); + return Ember.RSVP.resolve({ id: 1, comments: [1, 2] }); }; - run(function(){ + run(function() { env.store.pushMany('comment', [{ id: 1, body: "First" }, { id: 2, body: "Second" }]); env.store.find('post', '1').then(function(post) { @@ -379,7 +379,7 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu }; return comments.reload(); - }).then(function(newComments){ + }).then(function(newComments) { equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); }); }); @@ -404,7 +404,7 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio ]); }; - run(function(){ + run(function() { env.store.find('post', 1).then(function(post) { return post.get('comments'); }).then(function(comments) { @@ -419,7 +419,7 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio }; return comments.reload(); - }).then(function(newComments){ + }).then(function(newComments) { equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); }); }); @@ -444,7 +444,7 @@ test("A hasMany relationship can be directly reloaded if it was fetched via ids" ]); }; - run(function(){ + run(function() { env.store.find('post', 1).then(function(post) { return post.get('comments').reload().then(function(comments) { equal(comments.get('isLoaded'), true, "comments are loaded"); @@ -470,16 +470,16 @@ test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loa }; var post; - run(function(){ - post = env.store.push('post', {id:1, links: {comments: 'someLink'}}); + run(function() { + post = env.store.push('post', { id: 1, links: { comments: 'someLink' } }); }); - run(function(){ + run(function() { post.get('comments').then(function(comments) { equal(comments.get('isLoaded'), true, "comments are loaded"); equal(comments.get('length'), 2, "comments have 2 length"); - var newComment = post.get('comments').createRecord({body: 'Third'}); + var newComment = post.get('comments').createRecord({ body: 'Third' }); equal(newComment.get('body'), 'Third', "new comment is returned"); equal(comments.get('length'), 3, "comments have 3 length, including new record"); }); @@ -501,8 +501,8 @@ test("PromiseArray proxies evented methods to its ManyArray", function() { }; var post, comments; - run(function(){ - post = env.store.push('post', {id:1, links: {comments: 'someLink'}}); + run(function() { + post = env.store.push('post', { id: 1, links: { comments: 'someLink' } }); comments = post.get('comments'); }); @@ -511,7 +511,7 @@ test("PromiseArray proxies evented methods to its ManyArray", function() { ok(true); }); - run(function(){ + run(function() { comments.trigger('on-event'); }); @@ -531,7 +531,7 @@ test("PromiseArray proxies evented methods to its ManyArray", function() { equal(comments.has('one-event'), true); - run(function(){ + run(function() { comments.trigger('one-event'); }); @@ -562,16 +562,16 @@ test("An updated `links` value should invalidate a relationship cache", function }; var post; - run(function(){ - post = env.store.push('post', {id:1, links: { comments: '/first' }}); + run(function() { + post = env.store.push('post', { id: 1, links: { comments: '/first' } }); }); - run(function(){ - post.get('comments').then(function(comments){ + run(function() { + post.get('comments').then(function(comments) { equal(comments.get('isLoaded'), true, "comments are loaded"); equal(comments.get('length'), 2, "comments have 2 length"); equal(comments.objectAt(0).get('body'), 'First', "comment 1 successfully loaded"); - env.store.push('post', {id:1, links: { comments: '/second' }}); + env.store.push('post', { id: 1, links: { comments: '/second' } }); post.get('comments').then(function(newComments) { equal(comments, newComments, "hasMany array was kept the same"); equal(newComments.get('length'), 3, "comments updated successfully"); @@ -588,13 +588,13 @@ test("When a polymorphic hasMany relationship is accessed, the adapter's findMan ok(false, "The adapter's find method should not be called"); }; - run(function(){ - env.store.push('user', { id: 1, messages: [ {id: 1, type: 'post'}, {id: 3, type: 'comment'} ] }); + run(function() { + env.store.push('user', { id: 1, messages: [{ id: 1, type: 'post' }, { id: 3, type: 'comment' }] }); env.store.push('post', { id: 1 }); env.store.push('comment', { id: 3 }); }); - run(function(){ + run(function() { env.store.find('user', 1).then(function(user) { var messages = user.get('messages'); equal(messages.get('length'), 2, "The messages are correctly loaded"); @@ -615,11 +615,11 @@ test("When a polymorphic hasMany relationship is accessed, the store can call mu } }; - run(function(){ - env.store.push('user', { id: 1, messages: [ {id: 1, type: 'post'}, {id: 3, type: 'comment'} ] }); + run(function() { + env.store.push('user', { id: 1, messages: [{ id: 1, type: 'post' }, { id: 3, type: 'comment' }] }); }); - run(function(){ + run(function() { env.store.find('user', 1).then(function(user) { return user.get('messages'); }).then(function(messages) { @@ -652,11 +652,11 @@ test("polymorphic hasMany type-checks check the superclass when MODEL_FACTORY_IN test("Type can be inferred from the key of a hasMany relationship", function() { expect(1); - run(function(){ - env.store.push('user', { id: 1, contacts: [ 1 ] }); + run(function() { + env.store.push('user', { id: 1, contacts: [1] }); env.store.push('contact', { id: 1 }); }); - run(function(){ + run(function() { env.store.find('user', 1).then(function(user) { return user.get('contacts'); }).then(function(contacts) { @@ -671,11 +671,11 @@ test("Type can be inferred from the key of an async hasMany relationship", funct }); expect(1); - run(function(){ - env.store.push('user', { id: 1, contacts: [ 1 ] }); + run(function() { + env.store.push('user', { id: 1, contacts: [1] }); env.store.push('contact', { id: 1 }); }); - run(function(){ + run(function() { env.store.find('user', 1).then(function(user) { return user.get('contacts'); }).then(function(contacts) { @@ -690,12 +690,12 @@ test("Polymorphic relationships work with a hasMany whose type is inferred", fun }); expect(1); - run(function(){ - env.store.push('user', { id: 1, contacts: [ { id: 1, type: 'email' }, { id: 2, type: 'phone' } ] }); + run(function() { + env.store.push('user', { id: 1, contacts: [{ id: 1, type: 'email' }, { id: 2, type: 'phone' }] }); env.store.push('email', { id: 1 }); env.store.push('phone', { id: 2 }); }); - run(function(){ + run(function() { env.store.find('user', 1).then(function(user) { return user.get('contacts'); }).then(function(contacts) { @@ -728,11 +728,11 @@ test("Polymorphic relationships with a hasMany is set up correctly on both sides }); test("A record can't be created from a polymorphic hasMany relationship", function() { - run(function(){ + run(function() { env.store.push('user', { id: 1, messages: [] }); }); - run(function(){ + run(function() { env.store.find('user', 1).then(function(user) { return user.get('messages'); }).then(function(messages) { @@ -745,13 +745,16 @@ test("A record can't be created from a polymorphic hasMany relationship", functi test("Only records of the same type can be added to a monomorphic hasMany relationship", function() { expect(1); - run(function(){ + run(function() { env.store.push('post', { id: 1, comments: [] }); env.store.push('post', { id: 2 }); }); - run(function(){ - Ember.RSVP.all([ env.store.find('post', 1), env.store.find('post', 2) ]).then(function(records) { + run(function() { + Ember.RSVP.all([ + env.store.find('post', 1), + env.store.find('post', 2) + ]).then(function(records) { expectAssertion(function() { records[0].get('comments').pushObject(records[1]); }, /You cannot add 'post' records to the post.comments relationship \(only 'comment' allowed\)/); @@ -761,7 +764,7 @@ test("Only records of the same type can be added to a monomorphic hasMany relati test("Only records of the same base type can be added to a polymorphic hasMany relationship", function() { expect(2); - run(function(){ + run(function() { env.store.push('user', { id: 1, messages: [] }); env.store.push('user', { id: 2, messages: [] }); env.store.push('post', { id: 1, comments: [] }); @@ -769,7 +772,7 @@ test("Only records of the same base type can be added to a polymorphic hasMany r }); var asyncRecords; - run(function(){ + run(function() { asyncRecords = Ember.RSVP.hash({ user: env.store.find('user', 1), anotherUser: env.store.find('user', 2), @@ -795,13 +798,13 @@ test("Only records of the same base type can be added to a polymorphic hasMany r test("A record can be removed from a polymorphic association", function() { expect(3); - run(function(){ - env.store.push('user', { id: 1 , messages: [{id: 3, type: 'comment'}]}); + run(function() { + env.store.push('user', { id: 1 , messages: [{ id: 3, type: 'comment' }] }); env.store.push('comment', { id: 3 }); }); var asyncRecords; - run(function(){ + run(function() { asyncRecords = Ember.RSVP.hash({ user: env.store.find('user', 1), comment: env.store.find('comment', 3) @@ -832,7 +835,7 @@ test("When a record is created on the client, its hasMany arrays should be in a ok(get(post, 'isLoaded'), "The post should have isLoaded flag"); var comments; - run(function(){ + run(function() { comments = get(post, 'comments'); }); @@ -854,7 +857,7 @@ test("When a record is created on the client, its async hasMany arrays should be ok(get(post, 'isLoaded'), "The post should have isLoaded flag"); - run(function(){ + run(function() { get(post, 'comments').then(function(comments) { ok(true, "Comments array successfully resolves"); equal(get(comments, 'length'), 0, "The comments should be an empty array"); @@ -863,19 +866,19 @@ test("When a record is created on the client, its async hasMany arrays should be }); }); -test("a records SYNC HM relationship property is readOnly", function(){ +test("a records SYNC HM relationship property is readOnly", function() { expect(1); var post = run(function() { return env.store.createRecord('post'); }); - raises(function(){ + raises(function() { post.set('comments'); }, 'Cannot Set: comments on: ' + Ember.inspect(post)); }); -test("a records ASYNC HM relationship property is readOnly", function(){ +test("a records ASYNC HM relationship property is readOnly", function() { expect(1); Post.reopen({ comments: DS.hasMany('comment', { async: true }) @@ -885,7 +888,7 @@ test("a records ASYNC HM relationship property is readOnly", function(){ return env.store.createRecord('post'); }); - raises(function(){ + raises(function() { run(post, 'set', 'comments'); }, 'Cannot Set: comments on: ' + Ember.inspect(post)); }); @@ -909,7 +912,7 @@ test("When a record is saved, its unsaved hasMany records should be kept", funct equal(get(post, 'comments.length'), 1, "The unsaved comment should be in the post's comments array"); }); -test("dual non-async HM <-> BT", function(){ +test("dual non-async HM <-> BT", function() { Post.reopen({ comments: DS.hasMany('comment', { inverse: 'post' }) }); @@ -925,13 +928,13 @@ test("dual non-async HM <-> BT", function(){ }; var post, firstComment; - run(function(){ - post = env.store.push('post', { id: 1, comments: [ 1 ] }); + run(function() { + post = env.store.push('post', { id: 1, comments: [1] }); firstComment = env.store.push('comment', { id: 1, post: 1 }); env.store.createRecord('comment', { post: post - }).save().then(function(comment){ + }).save().then(function(comment) { var commentPost = comment.get('post'); var postComments = comment.get('post.comments'); var postCommentsLength = comment.get('post.comments.length'); @@ -951,19 +954,19 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the }); env.adapter.findMany = function() { - return resolve([{id:1, body: 'first'}, {id:2, body:'second'}]); + return resolve([{ id: 1, body: 'first' }, { id: 2, body: 'second' }]); }; env.adapter.find = function() { - return resolve({id:3, body: 'third'}); + return resolve({ id: 3, body: 'third' }); }; var post; - run(function(){ + run(function() { post = env.store.push('post', { id: 1, comments: [1, 2] }); }); - run(function(){ + run(function() { post.get('comments').then(async(function(fetchedComments) { equal(fetchedComments.get('length'), 2, 'comments fetched successfully'); equal(fetchedComments.objectAt(0).get('body'), 'first', 'first comment loaded successfully'); @@ -978,7 +981,7 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the test("A sync hasMany errors out if there are unlaoded records in it", function() { var post; - run(function(){ + run(function() { post = env.store.push('post', { id: 1, comments: [1, 2] }); }); @@ -990,39 +993,39 @@ test("A sync hasMany errors out if there are unlaoded records in it", function() test("If reordered hasMany data has been pushed to the store, the many array reflects the ordering change - sync", function() { var comment1, comment2, comment3, comment4; var post; - run(function(){ + run(function() { comment1 = env.store.push('comment', { id: 1 }); comment2 = env.store.push('comment', { id: 2 }); comment3 = env.store.push('comment', { id: 3 }); comment4 = env.store.push('comment', { id: 4 }); }); - run(function(){ + run(function() { post = env.store.push('post', { id: 1, comments: [1, 2] }); }); deepEqual(post.get('comments').toArray(), [comment1, comment2], 'Initial ordering is correct'); - run(function(){ + run(function() { env.store.push('post', { id: 1, comments: [2, 1] }); }); deepEqual(post.get('comments').toArray(), [comment2, comment1], 'Updated ordering is correct'); - run(function(){ + run(function() { env.store.push('post', { id: 1, comments: [2] }); }); deepEqual(post.get('comments').toArray(), [comment2], 'Updated ordering is correct'); - run(function(){ + run(function() { env.store.push('post', { id: 1, comments: [1,2,3,4] }); }); deepEqual(post.get('comments').toArray(), [comment1, comment2, comment3, comment4], 'Updated ordering is correct'); - run(function(){ + run(function() { env.store.push('post', { id: 1, comments: [4,3] }); }); deepEqual(post.get('comments').toArray(), [comment4, comment3], 'Updated ordering is correct'); - run(function(){ + run(function() { env.store.push('post', { id: 1, comments: [4,2,3,1] }); }); deepEqual(post.get('comments').toArray(), [comment4, comment2, comment3, comment1], 'Updated ordering is correct'); @@ -1030,15 +1033,15 @@ test("If reordered hasMany data has been pushed to the store, the many array ref test("Rollbacking a deleted record restores implicit relationship correctly when the hasMany side has been deleted - async", function () { var book, chapter; - run(function(){ + run(function() { book = env.store.push('book', { id: 1, title: "Stanley's Amazing Adventures", chapters: [2] }); chapter = env.store.push('chapter', { id: 2, title: 'Sailing the Seven Seas' }); }); - run(function(){ + run(function() { chapter.deleteRecord(); chapter.rollback(); }); - run(function(){ + run(function() { book.get('chapters').then(function(fetchedChapters) { equal(fetchedChapters.objectAt(0), chapter, 'Book has a chapter after rollback'); }); @@ -1047,15 +1050,15 @@ test("Rollbacking a deleted record restores implicit relationship correctly when test("Rollbacking a deleted record restores implicit relationship correctly when the hasMany side has been deleted - sync", function () { var book, chapter; - run(function(){ + run(function() { book = env.store.push('book', { id: 1, title: "Stanley's Amazing Adventures", chapters: [2] }); chapter = env.store.push('chapter', { id: 2, title: 'Sailing the Seven Seas' }); }); - run(function(){ + run(function() { chapter.deleteRecord(); chapter.rollback(); }); - run(function(){ + run(function() { equal(book.get('chapters.firstObject'), chapter, "Book has a chapter after rollback"); }); }); @@ -1065,15 +1068,15 @@ test("Rollbacking a deleted record restores implicit relationship correctly when chapter: DS.belongsTo('chapter', { async: true }) }); var chapter, page; - run(function(){ + run(function() { chapter = env.store.push('chapter', { id: 2, title: 'Sailing the Seven Seas' }); page = env.store.push('page', { id: 3, number: 1, chapter: 2 }); }); - run(function(){ + run(function() { chapter.deleteRecord(); chapter.rollback(); }); - run(function(){ + run(function() { page.get('chapter').then(function(fetchedChapter) { equal(fetchedChapter, chapter, 'Page has a chapter after rollback'); }); @@ -1082,15 +1085,15 @@ test("Rollbacking a deleted record restores implicit relationship correctly when test("Rollbacking a deleted record restores implicit relationship correctly when the belongsTo side has been deleted - sync", function () { var chapter, page; - run(function(){ + run(function() { chapter = env.store.push('chapter', { id: 2, title: 'Sailing the Seven Seas' }); page = env.store.push('page', { id: 3, number: 1, chapter: 2 }); }); - run(function(){ + run(function() { chapter.deleteRecord(); chapter.rollback(); }); - run(function(){ + run(function() { equal(page.get('chapter'), chapter, "Page has a chapter after rollback"); }); }); @@ -1100,24 +1103,24 @@ test("ManyArray notifies the array observers and flushes bindings when removing" var chapter, page, page2; var observe = false; - run(function(){ + run(function() { page = env.store.push('page', { id: 1, number: 1 }); page2 = env.store.push('page', { id: 2, number: 2 }); chapter = env.store.push('chapter', { id: 1, title: 'Sailing the Seven Seas', pages: [1, 2] }); chapter.get('pages').addEnumerableObserver(this, { - willChange: function(pages, removing, addCount){ + willChange: function(pages, removing, addCount) { if (observe) { equal(removing[0], page2, 'page2 is passed to willChange'); } }, - didChange:function(pages, removeCount, adding){ + didChange: function(pages, removeCount, adding) { if (observe) { equal(removeCount, 1, 'removeCount is correct'); } } }); }); - run(function(){ + run(function() { observe = true; page2.set('chapter', null); observe = false; @@ -1129,24 +1132,24 @@ test("ManyArray notifies the array observers and flushes bindings when adding", var chapter, page, page2; var observe = false; - run(function(){ + run(function() { page = env.store.push('page', { id: 1, number: 1 }); page2 = env.store.push('page', { id: 2, number: 2 }); chapter = env.store.push('chapter', { id: 1, title: 'Sailing the Seven Seas', pages: [1] }); chapter.get('pages').addEnumerableObserver(this, { - willChange: function(pages, removing, addCount){ + willChange: function(pages, removing, addCount) { if (observe) { equal(addCount, 1, 'addCount is correct'); } }, - didChange:function(pages, removeCount, adding){ + didChange: function(pages, removeCount, adding) { if (observe) { equal(adding[0], page2, 'page2 is passed to didChange'); } } }); }); - run(function(){ + run(function() { observe = true; page2.set('chapter', chapter); observe = false; @@ -1165,7 +1168,7 @@ test("Passing a model as type to hasMany should not work", function () { }, /The first argument to DS.hasMany must be a string/); }); -test("Relationship.clear removes all records correctly", function(){ +test("Relationship.clear removes all records correctly", function() { var post; Comment.reopen({ @@ -1176,7 +1179,7 @@ test("Relationship.clear removes all records correctly", function(){ comments: DS.hasMany('comment', { inverse: 'post' }) }); - run(function(){ + run(function() { post = env.store.push('post', { id: 2, title: 'Sailing the Seven Seas', comments: [1, 2] }); env.store.pushMany('comment', [ { id: 1, post: 2 }, @@ -1185,7 +1188,7 @@ test("Relationship.clear removes all records correctly", function(){ ]); }); - run(function(){ + run(function() { post._relationships['comments'].clear(); var comments = Ember.A(env.store.all('comment')); deepEqual(comments.mapBy('post'), [null, null, null]); @@ -1194,7 +1197,7 @@ test("Relationship.clear removes all records correctly", function(){ }); -test('unloading a record with associated records does not prevent the store from tearing down', function(){ +test('unloading a record with associated records does not prevent the store from tearing down', function() { var post; Comment.reopen({ @@ -1205,7 +1208,7 @@ test('unloading a record with associated records does not prevent the store from comments: DS.hasMany('comment', { inverse: 'post' }) }); - run(function(){ + run(function() { post = env.store.push('post', { id: 2, title: 'Sailing the Seven Seas', comments: [1,2] }); env.store.pushMany('comment', [ { id: 1, post: 2 }, @@ -1221,7 +1224,7 @@ test('unloading a record with associated records does not prevent the store from env.store.unloadRecord(post); }); try { - run(function(){ + run(function() { env.store.destroy(); }); ok(true, "store destroyed correctly"); diff --git a/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js b/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js index acd59604d7e..96a0baf4ecc 100644 --- a/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js +++ b/packages/ember-data/tests/integration/relationships/inverse_relationships_test.js @@ -16,14 +16,14 @@ test("When a record is added to a has-many relationship, the inverse belongsTo i store = env.store; var comment, post; - run(function(){ + run(function() { comment = store.createRecord('comment'); post = store.createRecord('post'); }); equal(comment.get('post'), null, "no post has been set on the comment"); - run(function(){ + run(function() { post.get('comments').pushObject(comment); }); equal(comment.get('post'), post, "post was set on the comment"); @@ -73,7 +73,7 @@ test("When a record is added to a has-many relationship, the inverse belongsTo c store = env.store; var comment, post; - run(function(){ + run(function() { comment = store.createRecord('comment'); post = store.createRecord('post'); }); @@ -83,7 +83,7 @@ test("When a record is added to a has-many relationship, the inverse belongsTo c equal(comment.get('redPost'), null, "redPost has not been set on the comment"); equal(comment.get('bluePost'), null, "bluePost has not been set on the comment"); - run(function(){ + run(function() { post.get('comments').pushObject(comment); }); @@ -108,7 +108,7 @@ test("When a record's belongsTo relationship is set, it can specify the inverse store = env.store; var comment, post; - run(function(){ + run(function() { comment = store.createRecord('comment'); post = store.createRecord('post'); }); @@ -117,7 +117,7 @@ test("When a record's belongsTo relationship is set, it can specify the inverse equal(post.get('youComments.length'), 0, "youComments has no posts"); equal(post.get('everyoneWeKnowComments.length'), 0, "everyoneWeKnowComments has no posts"); - run(function(){ + run(function() { comment.set('post', post); }); @@ -141,12 +141,12 @@ test("When setting a belongsTo, the OneToOne invariant is respected even when ot store = env.store; var comment, post, post2; - run(function(){ + run(function() { comment = store.createRecord('comment'); post = store.createRecord('post'); post2 = store.createRecord('post'); }); - run(function(){ + run(function() { comment.set('post', post); post2.set('bestComment', null); }); @@ -155,7 +155,7 @@ test("When setting a belongsTo, the OneToOne invariant is respected even when ot equal(post.get('bestComment'), comment); equal(post2.get('bestComment'), null); - run(function(){ + run(function() { comment.set('post', post2); }); @@ -179,13 +179,13 @@ test("When setting a belongsTo, the OneToOne invariant is transitive", function( }); var post, post2, comment; - run(function(){ + run(function() { comment = store.createRecord('comment'); post = store.createRecord('post'); post2 = store.createRecord('post'); }); - run(function(){ + run(function() { comment.set('post', post); }); @@ -193,7 +193,7 @@ test("When setting a belongsTo, the OneToOne invariant is transitive", function( equal(post.get('bestComment'), comment); equal(post2.get('bestComment'), null); - run(function(){ + run(function() { post2.set('bestComment', comment); }); @@ -217,7 +217,7 @@ test("When setting a belongsTo, the OneToOne invariant is commutative", function }); var post, comment, comment2; - run(function(){ + run(function() { post = store.createRecord('post'); comment = store.createRecord('comment'); comment2 = store.createRecord('comment'); @@ -229,7 +229,7 @@ test("When setting a belongsTo, the OneToOne invariant is commutative", function equal(post.get('bestComment'), comment); equal(comment2.get('post'), null); - run(function(){ + run(function() { post.set('bestComment', comment2); }); @@ -252,23 +252,23 @@ test("OneToNone relationship works", function() { store = env.store; var comment, post1, post2; - run(function(){ + run(function() { comment = store.createRecord('comment'); post1 = store.createRecord('post'); post2 = store.createRecord('post'); }); - run(function(){ + run(function() { comment.set('post', post1); }); equal(comment.get('post'), post1, 'the post is set to the first one'); - run(function(){ + run(function() { comment.set('post', post2); }); equal(comment.get('post'), post2, 'the post is set to the second one'); - run(function(){ + run(function() { comment.set('post', post1); }); equal(comment.get('post'), post1, 'the post is re-set to the first one'); @@ -296,7 +296,7 @@ test("When a record is added to or removed from a polymorphic has-many relations store = env.store; var post, user; - run(function(){ + run(function() { post = store.createRecord('post'); user = store.createRecord('user'); }); @@ -306,7 +306,7 @@ test("When a record is added to or removed from a polymorphic has-many relations equal(post.get('redUser'), null, "redUser has not been set on the user"); equal(post.get('blueUser'), null, "blueUser has not been set on the user"); - run(function(){ + run(function() { user.get('messages').pushObject(post); }); @@ -315,7 +315,7 @@ test("When a record is added to or removed from a polymorphic has-many relations equal(post.get('redUser'), user, "redUser has been set on the user"); equal(post.get('blueUser'), null, "blueUser has not been set on the user"); - run(function(){ + run(function() { user.get('messages').popObject(); }); @@ -342,7 +342,7 @@ test("When a record's belongsTo relationship is set, it can specify the inverse store = env.store; var user, post; - run(function(){ + run(function() { user = store.createRecord('user'); post = store.createRecord('post'); }); @@ -351,7 +351,7 @@ test("When a record's belongsTo relationship is set, it can specify the inverse equal(user.get('youMessages.length'), 0, "youMessages has no posts"); equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); - run(function(){ + run(function() { post.set('user', user); }); @@ -359,7 +359,7 @@ test("When a record's belongsTo relationship is set, it can specify the inverse equal(user.get('youMessages.length'), 1, "youMessages had the post added"); equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); - run(function(){ + run(function() { post.set('user', null); }); @@ -370,9 +370,9 @@ test("When a record's belongsTo relationship is set, it can specify the inverse test("When a record's polymorphic belongsTo relationship is set, it can specify the inverse hasMany to which the new child should be added", function() { Message = DS.Model.extend({ - meMessages: DS.hasMany('comment', {inverse: null}), - youMessages: DS.hasMany('comment', {inverse: 'message'}), - everyoneWeKnowMessages: DS.hasMany('comment', {inverse: null}) + meMessages: DS.hasMany('comment', { inverse: null }), + youMessages: DS.hasMany('comment', { inverse: 'message' }), + everyoneWeKnowMessages: DS.hasMany('comment', { inverse: null }) }); Post = Message.extend(); @@ -388,7 +388,7 @@ test("When a record's polymorphic belongsTo relationship is set, it can specify store = env.store; var comment, post; - run(function(){ + run(function() { comment = store.createRecord('comment'); post = store.createRecord('post'); }); @@ -397,7 +397,7 @@ test("When a record's polymorphic belongsTo relationship is set, it can specify equal(post.get('youMessages.length'), 0, "youMessages has no posts"); equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); - run(function(){ + run(function() { comment.set('message', post); }); @@ -405,7 +405,7 @@ test("When a record's polymorphic belongsTo relationship is set, it can specify equal(post.get('youMessages.length'), 1, "youMessages had the post added"); equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); - run(function(){ + run(function() { comment.set('message', null); }); @@ -424,12 +424,12 @@ test("Inverse relationships that don't exist throw a nice error for a hasMany", var env = setupStore({ post: Post, comment: Comment, user: User }); var comment; - run(function(){ + run(function() { comment = env.store.createRecord('comment'); }); expectAssertion(function() { - run(function(){ + run(function() { env.store.createRecord('post'); }); }, /We found no inverse relationships by the name of 'testPost' on the 'comment' model/); @@ -445,12 +445,12 @@ test("Inverse relationships that don't exist throw a nice error for a belongsTo" var env = setupStore({ post: Post, comment: Comment, user: User }); var user; - run(function(){ + run(function() { user = env.store.createRecord('user'); }); expectAssertion(function() { - run(function(){ + run(function() { env.store.createRecord('post'); }); }, /We found no inverse relationships by the name of 'testPost' on the 'user' model/); diff --git a/packages/ember-data/tests/integration/relationships/many_to_many_test.js b/packages/ember-data/tests/integration/relationships/many_to_many_test.js index 6b683aea626..3ce282f2459 100644 --- a/packages/ember-data/tests/integration/relationships/many_to_many_test.js +++ b/packages/ember-data/tests/integration/relationships/many_to_many_test.js @@ -11,7 +11,7 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships', setup: function() { User = DS.Model.extend({ name: attr('string'), - topics: hasMany('topic', {async: true}), + topics: hasMany('topic', { async: true }), accounts: hasMany('account') }); @@ -26,7 +26,7 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships', Topic = DS.Model.extend({ title: attr('string'), - users: hasMany('user', {async: true}) + users: hasMany('user', { async: true }) }); Topic.toString = stringify('Topic'); @@ -41,7 +41,7 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships', }, teardown: function() { - run(function(){ + run(function() { env.container.destroy(); }); } @@ -52,13 +52,13 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships', */ test("Loading from one hasMany side reflects on the other hasMany side - async", function () { - run(function(){ - store.push('user', {id:1, name: 'Stanley', topics: [2, 3]}); + run(function() { + store.push('user', { id: 1, name: 'Stanley', topics: [2, 3] }); }); - var topic = run(function(){ - return store.push('topic', {id: 2, title: 'EmberFest was great'}); + var topic = run(function() { + return store.push('topic', { id: 2, title: 'EmberFest was great' }); }); - run(function(){ + run(function() { topic.get('users').then(async(function(fetchedUsers) { equal(fetchedUsers.get('length'), 1, 'User relationship was set up correctly'); })); @@ -67,22 +67,22 @@ test("Loading from one hasMany side reflects on the other hasMany side - async", test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - sync", function () { var account; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); - store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); + store.push('user', { id: 1, name: 'Stanley', accounts: [2] }); }); - run(function(){ + run(function() { equal(account.get('users.length'), 1, 'User relationship was set up correctly'); }); }); test("Fetching a hasMany where a record was removed reflects on the other hasMany side - async", function () { var user, topic; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', topics: [2]}); - topic = store.push('topic', {id: 2, title: 'EmberFest was great', users:[]}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', topics: [2] }); + topic = store.push('topic', { id: 2, title: 'EmberFest was great', users: [] }); }); - run(function(){ + run(function() { user.get('topics').then(async(function(fetchedTopics) { equal(fetchedTopics.get('length'), 0, 'Topics were removed correctly'); topic.get('users').then(async(function(fetchedUsers) { @@ -94,10 +94,10 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan test("Fetching a hasMany where a record was removed reflects on the other hasMany side - async", function () { var account, user; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); - user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); - account = store.push('account', {id:2 , state: 'lonely', users: []}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); + user = store.push('user', { id: 1, name: 'Stanley', accounts: [2] }); + account = store.push('account', { id: 2 , state: 'lonely', users: [] }); }); equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); equal(account.get('users.length'), 0, 'Users were removed correctly'); @@ -111,11 +111,11 @@ test("Pushing to a hasMany reflects on the other hasMany side - async", function expect(1); var user, topic; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', topics: []}); - topic = store.push('topic', {id: 2, title: 'EmberFest was great'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', topics: [] }); + topic = store.push('topic', { id: 2, title: 'EmberFest was great' }); }); - run(function(){ + run(function() { topic.get('users').then(async(function(fetchedUsers) { fetchedUsers.pushObject(user); user.get('topics').then(async(function(fetchedTopics) { @@ -127,9 +127,9 @@ test("Pushing to a hasMany reflects on the other hasMany side - async", function test("Pushing to a hasMany reflects on the other hasMany side - sync", function () { var account, stanley; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); - stanley = store.push('user', {id:1, name: 'Stanley'}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); + stanley = store.push('user', { id: 1, name: 'Stanley' }); stanley.get('accounts').pushObject(account); }); equal(account.get('users.length'), 1, 'User relationship was set up correctly'); @@ -137,11 +137,11 @@ test("Pushing to a hasMany reflects on the other hasMany side - sync", function test("Removing a record from a hasMany reflects on the other hasMany side - async", function () { var user, topic; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', topics: [2]}); - topic = store.push('topic', {id: 2, title: 'EmberFest was great'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', topics: [2] }); + topic = store.push('topic', { id: 2, title: 'EmberFest was great' }); }); - run(function(){ + run(function() { user.get('topics').then(async(function(fetchedTopics) { equal(fetchedTopics.get('length'), 1, 'Topics were setup correctly'); fetchedTopics.removeObject(topic); @@ -154,12 +154,12 @@ test("Removing a record from a hasMany reflects on the other hasMany side - asyn test("Removing a record from a hasMany reflects on the other hasMany side - sync", function () { var account, user; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); - user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); + user = store.push('user', { id: 1, name: 'Stanley', accounts: [2] }); }); equal(account.get('users.length'), 1, 'Users were setup correctly'); - run(function(){ + run(function() { account.get('users').removeObject(user); }); equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); @@ -172,12 +172,12 @@ Deleting tests test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - async", function () { var user, topic; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', topics: [2]}); - topic = store.push('topic', {id: 2, title: 'EmberFest was great'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', topics: [2] }); + topic = store.push('topic', { id: 2, title: 'EmberFest was great' }); }); run(topic, 'deleteRecord'); - run(function(){ + run(function() { topic.get('users').then(async(function(fetchedUsers) { equal(fetchedUsers.get('length'), 1, 'Users are still there'); })); @@ -189,9 +189,9 @@ test("Deleting a record that has a hasMany relationship removes it from the othe test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function () { var account, user; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); - user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); + user = store.push('user', { id: 1, name: 'Stanley', accounts: [2] }); }); run(account, 'deleteRecord'); equal(account.get('users.length'), 1, 'Users are still there'); @@ -204,15 +204,15 @@ test("Deleting a record that has a hasMany relationship removes it from the othe test("Rollbacking a deleted record that has a ManyToMany relationship works correctly - async", function () { var user, topic; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', topics: [2]}); - topic = store.push('topic', {id: 2, title: 'EmberFest was great'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', topics: [2] }); + topic = store.push('topic', { id: 2, title: 'EmberFest was great' }); }); - run(function(){ + run(function() { topic.deleteRecord(); topic.rollback(); }); - run(function(){ + run(function() { topic.get('users').then(async(function(fetchedUsers) { equal(fetchedUsers.get('length'), 1, 'Users are still there'); })); @@ -224,11 +224,11 @@ test("Rollbacking a deleted record that has a ManyToMany relationship works corr test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function () { var account, user; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); - user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); + user = store.push('user', { id: 1, name: 'Stanley', accounts: [2] }); }); - run(function(){ + run(function() { account.deleteRecord(); account.rollback(); }); @@ -238,11 +238,11 @@ test("Deleting a record that has a hasMany relationship removes it from the othe test("Rollbacking a created record that has a ManyToMany relationship works correctly - async", function () { var user, topic; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley' }); topic = store.createRecord('topic'); }); - run(function(){ + run(function() { user.get('topics').then(async(function(fetchedTopics) { fetchedTopics.pushObject(topic); topic.rollback(); @@ -258,11 +258,11 @@ test("Rollbacking a created record that has a ManyToMany relationship works corr test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function () { var account, user; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); user = store.createRecord('user'); }); - run(function(){ + run(function() { account.get('users').pushObject(user); user.rollback(); }); diff --git a/packages/ember-data/tests/integration/relationships/one_to_many_test.js b/packages/ember-data/tests/integration/relationships/one_to_many_test.js index 0b68af6d461..857be567a1e 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_many_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_many_test.js @@ -12,7 +12,7 @@ module('integration/relationships/one_to_many_test - OneToMany relationships', { setup: function() { User = DS.Model.extend({ name: attr('string'), - messages: hasMany('message', {async: true}), + messages: hasMany('message', { async: true }), accounts: hasMany('account') }); User.toString = stringify('User'); @@ -25,7 +25,7 @@ module('integration/relationships/one_to_many_test - OneToMany relationships', { Message = DS.Model.extend({ title: attr('string'), - user: belongsTo('user', {async: true}) + user: belongsTo('user', { async: true }) }); Message.toString = stringify('Message'); @@ -49,11 +49,11 @@ module('integration/relationships/one_to_many_test - OneToMany relationships', { test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - async", function () { var user, message; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', messages: [2, 3]}); - message = store.push('message', {id: 2, title: 'EmberFest was great'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [2, 3] }); + message = store.push('message', { id: 2, title: 'EmberFest was great' }); }); - run(function(){ + run(function() { message.get('user').then(function(fetchedUser) { equal(fetchedUser, user, 'User relationship was set up correctly'); }); @@ -62,20 +62,20 @@ test("Relationship is available from the belongsTo side even if only loaded from test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - sync", function () { var account, user; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); - user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); + user = store.push('user', { id: 1, name: 'Stanley', accounts: [2] }); }); equal(account.get('user'), user, 'User relationship was set up correctly'); }); test("Relationship is available from the hasMany side even if only loaded from the belongsTo side - async", function () { var user, message; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley'}); - message = store.push('message', {id: 2, title: 'EmberFest was great', user:1}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley' }); + message = store.push('message', { id: 2, title: 'EmberFest was great', user: 1 }); }); - run(function(){ + run(function() { user.get('messages').then(function(fetchedMessages) { equal(fetchedMessages.objectAt(0), message, 'Messages relationship was set up correctly'); }); @@ -84,23 +84,23 @@ test("Relationship is available from the hasMany side even if only loaded from t test("Relationship is available from the hasMany side even if only loaded from the belongsTo side - sync", function () { var user, account; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley'}); - account = store.push('account', {id:2 , state: 'lonely', user:1}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley' }); + account = store.push('account', { id: 2 , state: 'lonely', user: 1 }); }); equal(user.get('accounts').objectAt(0), account, 'Accounts relationship was set up correctly'); }); test("Fetching a belongsTo that is set to null removes the record from a relationship - async", function () { var user; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', messages: [1,2]}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [1,2] }); }); - run(function(){ - store.push('message', {id: 1, title: 'EmberFest was great', user:1}); - store.push('message', {id: 2, title: 'EmberConf will be better', user:null}); + run(function() { + store.push('message', { id: 1, title: 'EmberFest was great', user: 1 }); + store.push('message', { id: 2, title: 'EmberConf will be better', user: null }); }); - run(function(){ + run(function() { user.get('messages').then(function(fetchedMessages) { equal(get(fetchedMessages, 'length'), 1, 'Messages relationship was set up correctly'); }); @@ -109,24 +109,24 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio test("Fetching a belongsTo that is set to null removes the record from a relationship - sync", function () { var account, user; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); - user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); - account = store.push('account', {id:2 , state: 'lonely', user:null}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); + user = store.push('user', { id: 1, name: 'Stanley', accounts: [2] }); + account = store.push('account', { id: 2 , state: 'lonely', user: null }); }); equal(user.get('accounts').objectAt(0), null, 'Account was sucesfully removed'); }); test("Fetching a belongsTo that is not defined does not remove the record from a relationship - async", function () { var user; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', messages: [1,2]}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [1,2] }); }); - run(function(){ - store.push('message', {id: 1, title: 'EmberFest was great', user:1}); - store.push('message', {id: 2, title: 'EmberConf will be better'}); + run(function() { + store.push('message', { id: 1, title: 'EmberFest was great', user: 1 }); + store.push('message', { id: 2, title: 'EmberConf will be better' }); }); - run(function(){ + run(function() { user.get('messages').then(function(fetchedMessages) { equal(get(fetchedMessages, 'length'), 2, 'Messages relationship was set up correctly'); }); @@ -135,26 +135,26 @@ test("Fetching a belongsTo that is not defined does not remove the record from a test("Fetching a belongsTo that is not defined does not remove the record from a relationship - sync", function () { var account, user; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); - user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); - account = store.push('account', {id:2 , state: 'lonely'}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); + user = store.push('user', { id: 1, name: 'Stanley', accounts: [2] }); + account = store.push('account', { id: 2 , state: 'lonely' }); }); equal(user.get('accounts').objectAt(0), account, 'Account was sucesfully removed'); }); test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsTo to null - async", function () { var user, message, message2; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', messages: [1]}); - message = store.push('message', {id: 1, title: 'EmberFest was great', user:1}); - message2 = store.push('message', {id: 2, title: 'EmberConf is gonna be better'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [1] }); + message = store.push('message', { id: 1, title: 'EmberFest was great', user: 1 }); + message2 = store.push('message', { id: 2, title: 'EmberConf is gonna be better' }); }); - run(function(){ - store.push('user', {id:1, name: 'Stanley', messages: [2]}); + run(function() { + store.push('user', { id: 1, name: 'Stanley', messages: [2] }); }); - run(function(){ + run(function() { message.get('user').then(function(fetchedUser) { equal(fetchedUser, null, 'User was removed correctly'); }); @@ -167,11 +167,11 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsTo to null - sync", function () { var account; - run(function(){ - store.push('user', {id:1, name: 'Stanley', accounts: [1]}); - account = store.push('account', {id: 1, state: 'great', user:1}); - store.push('account', {id: 2, state: 'awesome'}); - store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + run(function() { + store.push('user', { id: 1, name: 'Stanley', accounts: [1] }); + account = store.push('account', { id: 1, state: 'great', user: 1 }); + store.push('account', { id: 2, state: 'awesome' }); + store.push('user', { id: 1, name: 'Stanley', accounts: [2] }); }); equal(account.get('user'), null, 'User was removed correctly'); @@ -179,13 +179,13 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT test("Fetching the hasMany side where the hasMany is undefined does not change the belongsTo side - async", function () { var message, user; - run(function(){ - store.push('user', {id:1, name: 'Stanley', messages: [1]}); - message = store.push('message', {id: 1, title: 'EmberFest was great', user:1}); - user = store.push('user', {id:1, name: 'Stanley'}); + run(function() { + store.push('user', { id: 1, name: 'Stanley', messages: [1] }); + message = store.push('message', { id: 1, title: 'EmberFest was great', user: 1 }); + user = store.push('user', { id: 1, name: 'Stanley' }); }); - run(function(){ + run(function() { message.get('user').then(function(fetchedUser) { equal(fetchedUser, user, 'User was not removed'); }); @@ -194,11 +194,11 @@ test("Fetching the hasMany side where the hasMany is undefined does not change t test("Fetching the hasMany side where the hasMany is undefined does not change the belongsTo side - sync", function () { var account, user; - run(function(){ - store.push('user', {id:1, name: 'Stanley', accounts: [1]}); - account = store.push('account', {id: 1, state: 'great', user:1}); - store.push('account', {id: 2, state: 'awesome'}); - user = store.push('user', {id:1, name: 'Stanley'}); + run(function() { + store.push('user', { id: 1, name: 'Stanley', accounts: [1] }); + account = store.push('account', { id: 1, state: 'great', user: 1 }); + store.push('account', { id: 2, state: 'awesome' }); + user = store.push('user', { id: 1, name: 'Stanley' }); }); equal(account.get('user'), user, 'User was not removed'); @@ -210,13 +210,13 @@ test("Fetching the hasMany side where the hasMany is undefined does not change t test("Pushing to the hasMany reflects the change on the belongsTo side - async", function () { var user, message2; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', messages: [1]}); - store.push('message', {id: 1, title: 'EmberFest was great'}); - message2 = store.push('message', {id: 2, title: 'EmberFest was great'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [1] }); + store.push('message', { id: 1, title: 'EmberFest was great' }); + message2 = store.push('message', { id: 2, title: 'EmberFest was great' }); }); - run(function(){ + run(function() { user.get('messages').then(function(fetchedMessages) { fetchedMessages.pushObject(message2); message2.get('user').then(function(fetchedUser) { @@ -228,11 +228,11 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - async", test("Pushing to the hasMany reflects the change on the belongsTo side - sync", function () { var user, account2; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', accounts: [1]}); - store.push('account', {id: 1, state: 'great', user:1}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', accounts: [1] }); + store.push('account', { id: 1, state: 'great', user: 1 }); - account2 = store.push('account', {id: 2, state: 'awesome'}); + account2 = store.push('account', { id: 2, state: 'awesome' }); user.get('accounts').pushObject(account2); }); @@ -241,12 +241,12 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - sync", test("Removing from the hasMany side reflects the change on the belongsTo side - async", function () { var user, message; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', messages: [1]}); - message = store.push('message', {id: 1, title: 'EmberFest was great'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [1] }); + message = store.push('message', { id: 1, title: 'EmberFest was great' }); }); - run(function(){ + run(function() { user.get('messages').then(function(fetchedMessages) { fetchedMessages.removeObject(message); message.get('user').then(function(fetchedUser) { @@ -258,11 +258,11 @@ test("Removing from the hasMany side reflects the change on the belongsTo side - test("Removing from the hasMany side reflects the change on the belongsTo side - sync", function () { var user, account; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', accounts: [1]}); - account = store.push('account', {id: 1, state: 'great', user:1}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', accounts: [1] }); + account = store.push('account', { id: 1, state: 'great', user: 1 }); }); - run(function(){ + run(function() { user.get('accounts').removeObject(account); }); @@ -272,13 +272,13 @@ test("Removing from the hasMany side reflects the change on the belongsTo side - test("Pushing to the hasMany side keeps the oneToMany invariant on the belongsTo side - async", function () { expect(2); var user, user2, message; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', messages: [1]}); - user2 = store.push('user', {id:2, name: 'Tomhuda'}); - message = store.push('message', {id: 1, title: 'EmberFest was great'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [1] }); + user2 = store.push('user', { id: 2, name: 'Tomhuda' }); + message = store.push('message', { id: 1, title: 'EmberFest was great' }); }); - run(function(){ + run(function() { user2.get('messages').then(function(fetchedMessages) { fetchedMessages.pushObject(message); @@ -295,10 +295,10 @@ test("Pushing to the hasMany side keeps the oneToMany invariant on the belongsTo test("Pushing to the hasMany side keeps the oneToMany invariant - sync", function () { var user, user2, account; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', accounts: [1]}); - user2 = store.push('user', {id:2, name: 'Stanley'}); - account = store.push('account', {id: 1, state: 'great'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', accounts: [1] }); + user2 = store.push('user', { id: 2, name: 'Stanley' }); + account = store.push('account', { id: 1, state: 'great' }); user2.get('accounts').pushObject(account); }); @@ -310,19 +310,19 @@ test("Pushing to the hasMany side keeps the oneToMany invariant - sync", functio test("Setting the belongsTo side keeps the oneToMany invariant on the hasMany- async", function () { expect(2); var user, user2, message; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', messages: [1]}); - user2 = store.push('user', {id:2, name: 'Tomhuda'}); - message = store.push('message', {id: 1, title: 'EmberFest was great', user: 1}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [1] }); + user2 = store.push('user', { id: 2, name: 'Tomhuda' }); + message = store.push('message', { id: 1, title: 'EmberFest was great', user: 1 }); message.set('user', user2); }); - run(function(){ + run(function() { user.get('messages').then(function(fetchedMessages) { equal(get(fetchedMessages, 'length'), 0, 'message got removed from the first user correctly'); }); }); - run(function(){ + run(function() { user2.get('messages').then(function(fetchedMessages) { equal(get(fetchedMessages, 'length'), 1, 'message got added to the second user correctly'); }); @@ -331,10 +331,10 @@ test("Setting the belongsTo side keeps the oneToMany invariant on the hasMany- a test("Setting the belongsTo side keeps the oneToMany invariant on the hasMany- sync", function () { var user, user2, account; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', accounts: [1]}); - user2 = store.push('user', {id:2, name: 'Stanley'}); - account = store.push('account', {id: 1, state: 'great', user: 1}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', accounts: [1] }); + user2 = store.push('user', { id: 2, name: 'Stanley' }); + account = store.push('account', { id: 1, state: 'great', user: 1 }); account.set('user', user2); }); @@ -348,19 +348,19 @@ test("Setting the belongsTo side keeps the oneToMany invariant on the hasMany- s test("Setting the belongsTo side to null removes the record from the hasMany side - async", function () { expect(2); var user, message; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', messages: [1]}); - message = store.push('message', {id: 1, title: 'EmberFest was great', user: 1}); - message.set('user', null); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [1] }); + message = store.push('message', { id: 1, title: 'EmberFest was great', user: 1 }); + message.set('user', null); }); - run(function(){ + run(function() { user.get('messages').then(function(fetchedMessages) { equal(get(fetchedMessages, 'length'), 0, 'message got removed from the user correctly'); }); }); - run(function(){ + run(function() { message.get('user').then(function(fetchedUser) { equal(fetchedUser, null, 'user got set to null correctly'); }); @@ -369,9 +369,9 @@ test("Setting the belongsTo side to null removes the record from the hasMany sid test("Setting the belongsTo side to null removes the record from the hasMany side - sync", function () { var user, account; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', accounts: [1]}); - account = store.push('account', {id: 1, state: 'great', user: 1}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', accounts: [1] }); + account = store.push('account', { id: 1, state: 'great', user: 1 }); account.set('user', null); }); @@ -386,12 +386,12 @@ Deleting test("When deleting a record that has a belongsTo it is removed from the hasMany side but not the belongsTo side- async", function () { var user, message; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', messages: [2]}); - message = store.push('message', {id: 2, title: 'EmberFest was great'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [2] }); + message = store.push('message', { id: 2, title: 'EmberFest was great' }); }); run(message, 'deleteRecord'); - run(function(){ + run(function() { message.get('user').then(function(fetchedUser) { equal(fetchedUser, user, 'Message still has the user'); }); @@ -403,9 +403,9 @@ test("When deleting a record that has a belongsTo it is removed from the hasMany test("When deleting a record that has a belongsTo it is removed from the hasMany side but not the belongsTo side- sync", function () { var account, user; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); - user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); + user = store.push('user', { id: 1, name: 'Stanley', accounts: [2] }); account.deleteRecord(); }); equal(user.get('accounts.length'), 0, "User was removed from the accounts"); @@ -414,12 +414,12 @@ test("When deleting a record that has a belongsTo it is removed from the hasMany test("When deleting a record that has a hasMany it is removed from the belongsTo side but not the hasMany side- async", function () { var user, message; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', messages: [2]}); - message = store.push('message', {id: 2, title: 'EmberFest was great'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [2] }); + message = store.push('message', { id: 2, title: 'EmberFest was great' }); }); run(user, 'deleteRecord'); - run(function(){ + run(function() { message.get('user').then(function(fetchedUser) { equal(fetchedUser, null, 'Message does not have the user anymore'); }); @@ -431,11 +431,11 @@ test("When deleting a record that has a hasMany it is removed from the belongsTo test("When deleting a record that has a hasMany it is removed from the belongsTo side but not the hasMany side - sync", function () { var account, user; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); - user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); + user = store.push('user', { id: 1, name: 'Stanley', accounts: [2] }); }); - run(function(){ + run(function() { user.deleteRecord(); }); equal(user.get('accounts.length'), 1, "User still has the accounts"); @@ -448,15 +448,15 @@ Rollback from deleted state test("Rollbacking a deleted record works correctly when the hasMany side has been deleted - async", function () { var user, message; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', messages: [2]}); - message = store.push('message', {id: 2, title: 'EmberFest was great'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [2] }); + message = store.push('message', { id: 2, title: 'EmberFest was great' }); }); - run(function(){ + run(function() { message.deleteRecord(); message.rollback(); }); - run(function(){ + run(function() { message.get('user').then(function(fetchedUser) { equal(fetchedUser, user, 'Message still has the user'); }); @@ -468,11 +468,11 @@ test("Rollbacking a deleted record works correctly when the hasMany side has bee test("Rollbacking a deleted record works correctly when the hasMany side has been deleted - sync", function () { var account, user; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); - user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); + user = store.push('user', { id: 1, name: 'Stanley', accounts: [2] }); }); - run(function(){ + run(function() { account.deleteRecord(); account.rollback(); }); @@ -482,17 +482,17 @@ test("Rollbacking a deleted record works correctly when the hasMany side has bee test("Rollbacking a deleted record works correctly when the belongsTo side has been deleted - async", function () { var user, message; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley', messages: [2]}); - message = store.push('message', {id: 2, title: 'EmberFest was great'}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [2] }); + message = store.push('message', { id: 2, title: 'EmberFest was great' }); }); - run(function(){ + run(function() { user.deleteRecord(); user.rollback(); }); - run(function(){ + run(function() { message.get('user').then(function(fetchedUser) { - equal(fetchedUser, user, 'Message has the user again'); + equal(fetchedUser, user, 'Message has the user again'); }); user.get('messages').then(function(fetchedMessages) { equal(fetchedMessages.get('length'), 1, 'User still has the messages'); @@ -502,11 +502,11 @@ test("Rollbacking a deleted record works correctly when the belongsTo side has b test("Rollbacking a deleted record works correctly when the belongsTo side has been deleted - sync", function () { var account, user; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); - user = store.push('user', {id:1, name: 'Stanley', accounts: [2]}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); + user = store.push('user', { id: 1, name: 'Stanley', accounts: [2] }); }); - run(function(){ + run(function() { user.deleteRecord(); user.rollback(); }); @@ -520,12 +520,12 @@ Rollback from created state test("Rollbacking a created record works correctly when the hasMany side has been created - async", function () { var user, message; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley'}); - message = store.createRecord('message', {user: user}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley' }); + message = store.createRecord('message', { user: user }); }); run(message, 'rollback'); - run(function(){ + run(function() { message.get('user').then(function(fetchedUser) { equal(fetchedUser, null, 'Message does not have the user anymore'); }); @@ -537,9 +537,9 @@ test("Rollbacking a created record works correctly when the hasMany side has bee test("Rollbacking a created record works correctly when the hasMany side has been created - sync", function () { var user, account; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley'}); - account = store.createRecord('account', {user: user}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley' }); + account = store.createRecord('account', { user: user }); }); run(account, 'rollback'); equal(user.get('accounts.length'), 0, "Accounts are rolled back"); @@ -548,11 +548,11 @@ test("Rollbacking a created record works correctly when the hasMany side has bee test("Rollbacking a created record works correctly when the belongsTo side has been created - async", function () { var message, user; - run(function(){ - message = store.push('message', {id: 2, title: 'EmberFest was great'}); + run(function() { + message = store.push('message', { id: 2, title: 'EmberFest was great' }); user = store.createRecord('user'); }); - run(function(){ + run(function() { user.get('messages').then(function(messages) { messages.pushObject(message); user.rollback(); @@ -568,11 +568,11 @@ test("Rollbacking a created record works correctly when the belongsTo side has b test("Rollbacking a created record works correctly when the belongsTo side has been created - sync", function () { var account, user; - run(function(){ - account = store.push('account', {id:2 , state: 'lonely'}); + run(function() { + account = store.push('account', { id: 2 , state: 'lonely' }); user = store.createRecord('user'); }); - run(function(){ + run(function() { user.get('accounts').pushObject(account); }); run(user, 'rollback'); diff --git a/packages/ember-data/tests/integration/relationships/one_to_one_test.js b/packages/ember-data/tests/integration/relationships/one_to_one_test.js index 06e86d231e6..fa7bf991b0b 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_one_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_one_test.js @@ -11,7 +11,7 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', { setup: function() { User = DS.Model.extend({ name: attr('string'), - bestFriend: belongsTo('user', {async: true}), + bestFriend: belongsTo('user', { async: true }), job: belongsTo('job') }); User.toString = stringify('User'); @@ -41,9 +41,9 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', { test("Relationship is available from both sides even if only loaded from one side - async", function () { var stanley, stanleysFriend; - run(function(){ - stanley = store.push('user', {id:1, name: 'Stanley', bestFriend: 2}); - stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + run(function() { + stanley = store.push('user', { id: 1, name: 'Stanley', bestFriend: 2 }); + stanleysFriend = store.push('user', { id: 2, name: "Stanley's friend" }); stanleysFriend.get('bestFriend').then(function(fetchedUser) { equal(fetchedUser, stanley, 'User relationship was set up correctly'); }); @@ -52,18 +52,18 @@ test("Relationship is available from both sides even if only loaded from one sid test("Relationship is available from both sides even if only loaded from one side - sync", function () { var job, user; - run(function(){ - job = store.push('job', {id:2 , isGood: true}); - user = store.push('user', {id:1, name: 'Stanley', job:2 }); + run(function() { + job = store.push('job', { id: 2 , isGood: true }); + user = store.push('user', { id: 1, name: 'Stanley', job: 2 }); }); equal(job.get('user'), user, 'User relationship was set up correctly'); }); test("Fetching a belongsTo that is set to null removes the record from a relationship - async", function () { var stanleysFriend; - run(function(){ - stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend: 1}); - store.push('user', {id:1, name: 'Stanley', bestFriend: null}); + run(function() { + stanleysFriend = store.push('user', { id: 2, name: "Stanley's friend", bestFriend: 1 }); + store.push('user', { id: 1, name: 'Stanley', bestFriend: null }); stanleysFriend.get('bestFriend').then(function(fetchedUser) { equal(fetchedUser, null, 'User relationship was removed correctly'); }); @@ -72,12 +72,12 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio test("Fetching a belongsTo that is set to null removes the record from a relationship - sync", function () { var job; - run(function(){ - job = store.push('job', {id:2 , isGood: true}); - store.push('user', {id:1, name: 'Stanley', job:2 }); + run(function() { + job = store.push('job', { id: 2 , isGood: true }); + store.push('user', { id: 1, name: 'Stanley', job: 2 }); }); - run(function(){ - job = store.push('job', {id:2 , isGood: true, user:null}); + run(function() { + job = store.push('job', { id: 2 , isGood: true, user: null }); }); equal(job.get('user'), null, 'User relationship was removed correctly'); }); @@ -85,22 +85,22 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio test("Fetching a belongsTo that is set to a different record, sets the old relationship to null - async", function () { expect(3); var stanley, stanleysFriend; - run(function(){ - stanley = store.push('user', {id:1, name: 'Stanley', bestFriend: 2}); - stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend: 1}); + run(function() { + stanley = store.push('user', { id: 1, name: 'Stanley', bestFriend: 2 }); + stanleysFriend = store.push('user', { id: 2, name: "Stanley's friend", bestFriend: 1 }); stanleysFriend.get('bestFriend').then(function(fetchedUser) { equal(fetchedUser, stanley, 'User relationship was initally setup correctly'); var stanleysNewFriend; - run(function(){ - stanleysNewFriend = store.push('user', {id:3, name: "Stanley's New friend", bestFriend: 1}); + run(function() { + stanleysNewFriend = store.push('user', { id: 3, name: "Stanley's New friend", bestFriend: 1 }); }); - stanley.get('bestFriend').then(function(fetchedNewFriend){ + stanley.get('bestFriend').then(function(fetchedNewFriend) { equal(fetchedNewFriend, stanleysNewFriend, 'User relationship was updated correctly'); }); - stanleysFriend.get('bestFriend').then(function(fetchedOldFriend){ + stanleysFriend.get('bestFriend').then(function(fetchedOldFriend) { equal(fetchedOldFriend, null, 'The old relationship was set to null correctly'); }); }); @@ -109,13 +109,13 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat test("Fetching a belongsTo that is set to a different record, sets the old relationship to null - sync", function () { var job, user, newBetterJob; - run(function(){ - job = store.push('job', {id:2 , isGood: false}); - user = store.push('user', {id:1, name: 'Stanley', job:2 }); + run(function() { + job = store.push('job', { id: 2 , isGood: false }); + user = store.push('user', { id: 1, name: 'Stanley', job: 2 }); }); equal(job.get('user'), user, 'Job and user initially setup correctly'); - run(function(){ - newBetterJob = store.push('job', {id:3, isGood: true, user:1 }); + run(function() { + newBetterJob = store.push('job', { id: 3, isGood: true, user: 1 }); }); equal(user.get('job'), newBetterJob, 'Job updated correctly'); @@ -129,11 +129,11 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat test("Setting a OneToOne relationship reflects correctly on the other side- async", function () { var stanley, stanleysFriend; - run(function(){ - stanley = store.push('user', {id:1, name: 'Stanley'}); - stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + run(function() { + stanley = store.push('user', { id: 1, name: 'Stanley' }); + stanleysFriend = store.push('user', { id: 2, name: "Stanley's friend" }); }); - run(function(){ + run(function() { stanley.set('bestFriend', stanleysFriend); stanleysFriend.get('bestFriend').then(function(fetchedUser) { equal(fetchedUser, stanley, 'User relationship was updated correctly'); @@ -143,11 +143,11 @@ test("Setting a OneToOne relationship reflects correctly on the other side- asyn test("Setting a OneToOne relationship reflects correctly on the other side- sync", function () { var job, user; - run(function(){ - job = store.push('job', {id:2 , isGood: true}); - user = store.push('user', {id:1, name: 'Stanley'}); + run(function() { + job = store.push('job', { id: 2 , isGood: true }); + user = store.push('user', { id: 1, name: 'Stanley' }); }); - run(function(){ + run(function() { user.set('job', job); }); equal(job.get('user'), user, 'User relationship was set up correctly'); @@ -155,12 +155,12 @@ test("Setting a OneToOne relationship reflects correctly on the other side- sync test("Setting a BelongsTo to a promise unwraps the promise before setting- async", function () { var stanley, stanleysFriend, newFriend; - run(function(){ - stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); - stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); - newFriend = store.push('user', {id:3, name: "New friend"}); + run(function() { + stanley = store.push('user', { id: 1, name: 'Stanley', bestFriend: 2 }); + stanleysFriend = store.push('user', { id: 2, name: "Stanley's friend" }); + newFriend = store.push('user', { id: 3, name: "New friend" }); }); - run(function(){ + run(function() { newFriend.set('bestFriend', stanleysFriend.get('bestFriend')); stanley.get('bestFriend').then(function(fetchedUser) { equal(fetchedUser, newFriend, 'User relationship was updated correctly'); @@ -173,12 +173,12 @@ test("Setting a BelongsTo to a promise unwraps the promise before setting- async test("Setting a BelongsTo to a promise works when the promise returns null- async", function () { var igor, newFriend; - run(function(){ - store.push('user', {id:1, name: 'Stanley'}); - igor = store.push('user', {id:2, name: "Igor"}); - newFriend = store.push('user', {id:3, name: "New friend", bestFriend:1}); + run(function() { + store.push('user', { id: 1, name: 'Stanley' }); + igor = store.push('user', { id: 2, name: "Igor" }); + newFriend = store.push('user', { id: 3, name: "New friend", bestFriend: 1 }); }); - run(function(){ + run(function() { newFriend.set('bestFriend', igor.get('bestFriend')); newFriend.get('bestFriend').then(function(fetchedUser) { equal(fetchedUser, null, 'User relationship was updated correctly'); @@ -188,12 +188,12 @@ test("Setting a BelongsTo to a promise works when the promise returns null- asyn test("Setting a BelongsTo to a promise that didn't come from a relationship errors out", function () { var stanley, igor; - run(function(){ - stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); - igor = store.push('user', {id:3, name: 'Igor'}); + run(function() { + stanley = store.push('user', { id: 1, name: 'Stanley', bestFriend: 2 }); + igor = store.push('user', { id: 3, name: 'Igor' }); }); expectAssertion(function() { - run(function(){ + run(function() { stanley.set('bestFriend', Ember.RSVP.resolve(igor)); }); }, /You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call./); @@ -202,26 +202,26 @@ test("Setting a BelongsTo to a promise that didn't come from a relationship erro test("Setting a BelongsTo to a promise multiple times is resistant to race conditions- async", function () { expect(1); var stanley, igor, newFriend; - run(function(){ - stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); - igor = store.push('user', {id:3, name: "Igor", bestFriend:5}); - newFriend = store.push('user', {id:7, name: "New friend"}); + run(function() { + stanley = store.push('user', { id: 1, name: 'Stanley', bestFriend: 2 }); + igor = store.push('user', { id: 3, name: "Igor", bestFriend: 5 }); + newFriend = store.push('user', { id: 7, name: "New friend" }); }); env.adapter.find = function(store, type, id) { if (id === '5') { - return Ember.RSVP.resolve({id:5, name: "Igor's friend"}); + return Ember.RSVP.resolve({ id: 5, name: "Igor's friend" }); } else if (id === '2') { stop(); return new Ember.RSVP.Promise(function(resolve, reject) { - setTimeout(function(){ + setTimeout(function() { start(); - resolve({id:2, name:"Stanley's friend"}); + resolve({ id: 2, name: "Stanley's friend" }); }, 1); }); } }; - run(function(){ + run(function() { newFriend.set('bestFriend', stanley.get('bestFriend')); newFriend.set('bestFriend', igor.get('bestFriend')); newFriend.get('bestFriend').then(function(fetchedUser) { @@ -232,11 +232,11 @@ test("Setting a BelongsTo to a promise multiple times is resistant to race condi test("Setting a OneToOne relationship to null reflects correctly on the other side - async", function () { var stanley, stanleysFriend; - run(function(){ - stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); - stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend:1}); + run(function() { + stanley = store.push('user', { id: 1, name: 'Stanley', bestFriend: 2 }); + stanleysFriend = store.push('user', { id: 2, name: "Stanley's friend", bestFriend: 1 }); }); - run(function(){ + run(function() { stanley.set('bestFriend', null); // :( stanleysFriend.get('bestFriend').then(function(fetchedUser) { equal(fetchedUser, null, 'User relationship was removed correctly'); @@ -246,11 +246,11 @@ test("Setting a OneToOne relationship to null reflects correctly on the other si test("Setting a OneToOne relationship to null reflects correctly on the other side - sync", function () { var job, user; - run(function(){ - job = store.push('job', {id:2 , isGood: false, user:1}); - user = store.push('user', {id:1, name: 'Stanley', job:2}); + run(function() { + job = store.push('job', { id: 2 , isGood: false, user: 1 }); + user = store.push('user', { id: 1, name: 'Stanley', job: 2 }); }); - run(function(){ + run(function() { user.set('job', null); }); equal(job.get('user'), null, 'User relationship was removed correctly'); @@ -258,23 +258,24 @@ test("Setting a OneToOne relationship to null reflects correctly on the other si test("Setting a belongsTo to a different record, sets the old relationship to null - async", function () { expect(3); + var stanley, stanleysFriend; - run(function(){ - stanley = store.push('user', {id:1, name: 'Stanley', bestFriend: 2}); - stanleysFriend = store.push('user', {id:2, name: "Stanley's friend", bestFriend: 1}); + run(function() { + stanley = store.push('user', { id: 1, name: 'Stanley', bestFriend: 2 }); + stanleysFriend = store.push('user', { id: 2, name: "Stanley's friend", bestFriend: 1 }); stanleysFriend.get('bestFriend').then(function(fetchedUser) { equal(fetchedUser, stanley, 'User relationship was initally setup correctly'); - var stanleysNewFriend = store.push('user', {id:3, name: "Stanley's New friend"}); - run(function(){ + var stanleysNewFriend = store.push('user', { id: 3, name: "Stanley's New friend" }); + run(function() { stanleysNewFriend.set('bestFriend', stanley); }); - stanley.get('bestFriend').then(function(fetchedNewFriend){ + stanley.get('bestFriend').then(function(fetchedNewFriend) { equal(fetchedNewFriend, stanleysNewFriend, 'User relationship was updated correctly'); }); - stanleysFriend.get('bestFriend').then(function(fetchedOldFriend){ + stanleysFriend.get('bestFriend').then(function(fetchedOldFriend) { equal(fetchedOldFriend, null, 'The old relationship was set to null correctly'); }); }); @@ -283,15 +284,15 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu test("Setting a belongsTo to a different record, sets the old relationship to null - sync", function () { var job, user, newBetterJob; - run(function(){ - job = store.push('job', {id:2 , isGood: false}); - user = store.push('user', {id:1, name: 'Stanley', job:2 }); + run(function() { + job = store.push('job', { id: 2 , isGood: false }); + user = store.push('user', { id: 1, name: 'Stanley', job: 2 }); }); equal(job.get('user'), user, 'Job and user initially setup correctly'); - run(function(){ - newBetterJob = store.push('job', {id:3, isGood: true}); + run(function() { + newBetterJob = store.push('job', { id: 3, isGood: true }); newBetterJob.set('user', user); }); @@ -310,17 +311,17 @@ test("When deleting a record that has a belongsTo relationship, the record is re // notifyPropertyChange() gets called. If not properly cleared observers will // trigger with the old value of the relationship. User.reopen({ - bestFriendObserver: Ember.observer('bestFriend', function () { + bestFriendObserver: Ember.observer('bestFriend', function() { this.get('bestFriend'); }) }); var stanleysFriend, stanley; - run(function(){ - stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); - stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); + run(function() { + stanleysFriend = store.push('user', { id: 2, name: "Stanley's friend" }); + stanley = store.push('user', { id: 1, name: 'Stanley', bestFriend: 2 }); }); - run(function(){ + run(function() { stanley.deleteRecord(); stanleysFriend.get('bestFriend').then(function(fetchedUser) { equal(fetchedUser, null, 'Stanley got removed'); @@ -333,11 +334,11 @@ test("When deleting a record that has a belongsTo relationship, the record is re test("When deleting a record that has a belongsTo relationship, the record is removed from the inverse but still has access to its own relationship - sync", function () { var job, user; - run(function(){ - job = store.push('job', {id:2 , isGood: true}); - user = store.push('user', {id:1, name: 'Stanley', job:2 }); + run(function() { + job = store.push('job', { id: 2 , isGood: true }); + user = store.push('user', { id: 1, name: 'Stanley', job: 2 }); }); - run(function(){ + run(function() { job.deleteRecord(); }); equal(user.get('job'), null, 'Job got removed from the user'); @@ -350,14 +351,14 @@ Rollback tests test("Rollbacking a deleted record restores the relationship on both sides - async", function () { var stanley, stanleysFriend; - run(function(){ - stanley = store.push('user', {id:1, name: 'Stanley', bestFriend:2}); - stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); + run(function() { + stanley = store.push('user', { id: 1, name: 'Stanley', bestFriend: 2 }); + stanleysFriend = store.push('user', { id: 2, name: "Stanley's friend" }); }); - run(function(){ + run(function() { stanley.deleteRecord(); }); - run(function(){ + run(function() { stanley.rollback(); stanleysFriend.get('bestFriend').then(function(fetchedUser) { equal(fetchedUser, stanley, 'Stanley got rollbacked correctly'); @@ -370,11 +371,11 @@ test("Rollbacking a deleted record restores the relationship on both sides - asy test("Rollbacking a deleted record restores the relationship on both sides - sync", function () { var job, user; - run(function(){ - job = store.push('job', {id:2 , isGood: true}); - user = store.push('user', {id:1, name: 'Stanley', job:2 }); + run(function() { + job = store.push('job', { id: 2 , isGood: true }); + user = store.push('user', { id: 1, name: 'Stanley', job: 2 }); }); - run(function(){ + run(function() { job.deleteRecord(); job.rollback(); }); @@ -384,11 +385,11 @@ test("Rollbacking a deleted record restores the relationship on both sides - syn test("Rollbacking a created record removes the relationship on both sides - async", function () { var stanleysFriend, stanley; - run(function(){ - stanleysFriend = store.push('user', {id:2, name: "Stanley's friend"}); - stanley = store.createRecord('user', {bestFriend: stanleysFriend}); + run(function() { + stanleysFriend = store.push('user', { id: 2, name: "Stanley's friend" }); + stanley = store.createRecord('user', { bestFriend: stanleysFriend }); }); - run(function(){ + run(function() { stanley.rollback(); stanleysFriend.get('bestFriend').then(function(fetchedUser) { equal(fetchedUser, null, 'Stanley got rollbacked correctly'); @@ -401,11 +402,11 @@ test("Rollbacking a created record removes the relationship on both sides - asyn test("Rollbacking a created record removes the relationship on both sides - sync", function () { var user, job; - run(function(){ - user = store.push('user', {id:1, name: 'Stanley'}); - job = store.createRecord('job', {user: user}); + run(function() { + user = store.push('user', { id: 1, name: 'Stanley' }); + job = store.createRecord('job', { user: user }); }); - run(function(){ + run(function() { job.rollback(); }); equal(user.get('job'), null, 'Job got rollbacked correctly'); diff --git a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js index 027e5a10132..70ab2920842 100644 --- a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js +++ b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js @@ -10,14 +10,14 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { SuperVillain = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), - homePlanet: DS.belongsTo("homePlanet", {inverse: 'villains'}), + homePlanet: DS.belongsTo("homePlanet", { inverse: 'villains' }), secretLab: DS.belongsTo("secretLab"), secretWeapons: DS.hasMany("secretWeapon"), evilMinions: DS.hasMany("evilMinion") }); HomePlanet = DS.Model.extend({ name: DS.attr('string'), - villains: DS.hasMany('superVillain', {inverse: 'homePlanet'}) + villains: DS.hasMany('superVillain', { inverse: 'homePlanet' }) }); SecretLab = DS.Model.extend({ minionCapacity: DS.attr('number'), @@ -77,7 +77,7 @@ test("extractSingle with embedded objects", function() { env.container.register('adapter:superVillain', DS.ActiveModelAdapter); env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - villains: {embedded: 'always'} + villains: { embedded: 'always' } } })); @@ -95,7 +95,7 @@ test("extractSingle with embedded objects", function() { }; var json; - run(function(){ + run(function() { json = serializer.extractSingle(env.store, HomePlanet, json_hash); }); @@ -104,7 +104,7 @@ test("extractSingle with embedded objects", function() { name: "Umber", villains: ["1"] }); - run(function(){ + run(function() { env.store.find("superVillain", 1).then(function(minion) { equal(minion.get('firstName'), "Tom"); }); @@ -115,12 +115,12 @@ test("extractSingle with embedded objects inside embedded objects", function() { env.container.register('adapter:superVillain', DS.ActiveModelAdapter); env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - villains: {embedded: 'always'} + villains: { embedded: 'always' } } })); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - evilMinions: {embedded: 'always'} + evilMinions: { embedded: 'always' } } })); @@ -142,7 +142,7 @@ test("extractSingle with embedded objects inside embedded objects", function() { }; var json; - run(function(){ + run(function() { json = serializer.extractSingle(env.store, HomePlanet, json_hash); }); @@ -151,7 +151,7 @@ test("extractSingle with embedded objects inside embedded objects", function() { name: "Umber", villains: ["1"] }); - run(function(){ + run(function() { env.store.find("superVillain", 1).then(function(villain) { equal(villain.get('firstName'), "Tom"); equal(villain.get('evilMinions.length'), 1, "Should load the embedded child"); @@ -167,7 +167,7 @@ test("extractSingle with embedded objects of same type", function() { env.container.register('adapter:comment', DS.ActiveModelAdapter); env.container.register('serializer:comment', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - children: {embedded: 'always'} + children: { embedded: 'always' } } })); @@ -190,7 +190,7 @@ test("extractSingle with embedded objects of same type", function() { } }; var json; - run(function(){ + run(function() { json = serializer.extractSingle(env.store, Comment, json_hash); }); @@ -208,7 +208,7 @@ test("extractSingle with embedded objects inside embedded objects of same type", env.container.register('adapter:comment', DS.ActiveModelAdapter); env.container.register('serializer:comment', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - children: {embedded: 'always'} + children: { embedded: 'always' } } })); @@ -236,7 +236,7 @@ test("extractSingle with embedded objects inside embedded objects of same type", } }; var json; - run(function(){ + run(function() { json = serializer.extractSingle(env.store, Comment, json_hash); }); @@ -255,14 +255,14 @@ test("extractSingle with embedded objects inside embedded objects of same type", test("extractSingle with embedded objects of same type, but from separate attributes", function() { HomePlanet.reopen({ - reformedVillains: DS.hasMany('superVillain', {inverse: null}) + reformedVillains: DS.hasMany('superVillain', { inverse: null }) }); env.container.register('adapter:home_planet', DS.ActiveModelAdapter); env.container.register('serializer:home_planet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - villains: {embedded: 'always'}, - reformedVillains: {embedded: 'always'} + villains: { embedded: 'always' }, + reformedVillains: { embedded: 'always' } } })); @@ -288,7 +288,7 @@ test("extractSingle with embedded objects of same type, but from separate attrib } }; var json; - run(function(){ + run(function() { json = serializer.extractSingle(env.store, HomePlanet, json_hash); }); @@ -309,7 +309,7 @@ test("extractArray with embedded objects", function() { env.container.register('adapter:superVillain', DS.ActiveModelAdapter); env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - villains: {embedded: 'always'} + villains: { embedded: 'always' } } })); @@ -328,7 +328,7 @@ test("extractArray with embedded objects", function() { }; var array; - run(function(){ + run(function() { array = serializer.extractArray(env.store, HomePlanet, json_hash); }); @@ -338,8 +338,8 @@ test("extractArray with embedded objects", function() { villains: ["1"] }]); - run(function(){ - env.store.find("superVillain", 1).then(function(minion){ + run(function() { + env.store.find("superVillain", 1).then(function(minion) { equal(minion.get('firstName'), "Tom"); }); }); @@ -353,7 +353,7 @@ test("extractArray with embedded objects with custom primary key", function() { })); env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - villains: {embedded: 'always'} + villains: { embedded: 'always' } } })); @@ -372,7 +372,7 @@ test("extractArray with embedded objects with custom primary key", function() { }; var array; - run(function(){ + run(function() { array = serializer.extractArray(env.store, HomePlanet, json_hash); }); @@ -382,8 +382,8 @@ test("extractArray with embedded objects with custom primary key", function() { villains: ["1"] }]); - run(function(){ - return env.store.find("superVillain", 1).then(function(minion){ + run(function() { + return env.store.find("superVillain", 1).then(function(minion) { env.container.unregister('serializer:superVillain'); equal(minion.get('firstName'), "Alex"); }); @@ -394,7 +394,7 @@ test("extractArray with embedded objects with identical relationship and attribu env.container.register('adapter:superVillain', DS.ActiveModelAdapter); env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - villains: {embedded: 'always'} + villains: { embedded: 'always' } }, //Makes the keyForRelationship and keyForAttribute collide. keyForRelationship: function(key, type) { @@ -417,7 +417,7 @@ test("extractArray with embedded objects with identical relationship and attribu }; var array; - run(function(){ + run(function() { array = serializer.extractArray(env.store, HomePlanet, json_hash); }); @@ -427,8 +427,8 @@ test("extractArray with embedded objects with identical relationship and attribu villains: ["1"] }]); - run(function(){ - env.store.find("superVillain", 1).then(function(minion){ + run(function() { + env.store.find("superVillain", 1).then(function(minion) { equal(minion.get('firstName'), "Alex"); }); }); @@ -437,7 +437,7 @@ test("extractArray with embedded objects of same type as primary type", function env.container.register('adapter:comment', DS.ActiveModelAdapter); env.container.register('serializer:comment', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - children: {embedded: 'always'} + children: { embedded: 'always' } } })); @@ -462,7 +462,7 @@ test("extractArray with embedded objects of same type as primary type", function }; var array; - run(function(){ + run(function() { array = serializer.extractArray(env.store, Comment, json_hash); }); @@ -485,8 +485,8 @@ test("extractArray with embedded objects of same type, but from separate attribu env.container.register('adapter:homePlanet', DS.ActiveModelAdapter); env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - villains: {embedded: 'always'}, - reformedVillains: {embedded: 'always'} + villains: { embedded: 'always' }, + reformedVillains: { embedded: 'always' } } })); @@ -529,7 +529,7 @@ test("extractArray with embedded objects of same type, but from separate attribu }] }; var json; - run(function(){ + run(function() { json = serializer.extractArray(env.store, HomePlanet, json_hash); }); @@ -555,17 +555,17 @@ test("extractArray with embedded objects of same type, but from separate attribu test("serialize supports serialize:false on non-relationship properties", function() { var tom; - run(function(){ + run(function() { tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", id: '1' }); }); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - firstName: {serialize: false} + firstName: { serialize: false } } })); var serializer, json; - run(function(){ + run(function() { serializer = env.container.lookup("serializer:superVillain"); json = serializer.serialize(tom); }); @@ -579,19 +579,19 @@ test("serialize supports serialize:false on non-relationship properties", functi test("serialize with embedded objects (hasMany relationship)", function() { var tom, league; - run(function(){ + run(function() { league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); }); env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - villains: {embedded: 'always'} + villains: { embedded: 'always' } } })); var serializer, json; - run(function(){ + run(function() { serializer = env.container.lookup("serializer:homePlanet"); json = serializer.serialize(league); @@ -610,18 +610,18 @@ test("serialize with embedded objects (hasMany relationship)", function() { }); test("serialize with embedded objects (hasMany relationship) supports serialize:false", function() { - run(function(){ + run(function() { league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); }); env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - villains: {serialize: false} + villains: { serialize: false } } })); var serializer, json; - run(function(){ + run(function() { serializer = env.container.lookup("serializer:homePlanet"); json = serializer.serialize(league); @@ -633,18 +633,18 @@ test("serialize with embedded objects (hasMany relationship) supports serialize: }); test("serialize with (new) embedded objects (hasMany relationship)", function() { - run(function(){ + run(function() { league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league }); }); env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - villains: {embedded: 'always'} + villains: { embedded: 'always' } } })); var serializer, json; - run(function(){ + run(function() { serializer = env.container.lookup("serializer:homePlanet"); json = serializer.serialize(league); @@ -661,7 +661,7 @@ test("serialize with (new) embedded objects (hasMany relationship)", function() }); test("serialize with embedded objects (hasMany relationships, including related objects not embedded)", function() { - run(function(){ + run(function() { superVillain = env.store.createRecord(SuperVillain, { id: 1, firstName: "Super", lastName: "Villian" }); evilMinion = env.store.createRecord(EvilMinion, { id: 1, name: "Evil Minion", superVillian: superVillain }); secretWeapon = env.store.createRecord(SecretWeapon, { id: 1, name: "Secret Weapon", superVillain: superVillain }); @@ -671,12 +671,12 @@ test("serialize with embedded objects (hasMany relationships, including related env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - evilMinions: {serialize: 'records', deserialize: 'records'}, - secretWeapons: {serialize: 'ids'} + evilMinions: { serialize: 'records', deserialize: 'records' }, + secretWeapons: { serialize: 'ids' } } })); var serializer, json; - run(function(){ + run(function() { serializer = env.container.lookup("serializer:superVillain"); json = serializer.serialize(superVillain); @@ -691,7 +691,7 @@ test("serialize with embedded objects (hasMany relationships, including related super_villain_id: "1" }], secret_lab_id: null, - secret_weapon_ids: [ "1" ] + secret_weapon_ids: ["1"] }); }); @@ -700,7 +700,7 @@ test("extractSingle with embedded object (belongsTo relationship)", function() { env.container.register('adapter:superVillain', DS.ActiveModelAdapter); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - secretLab: {embedded: 'always'} + secretLab: { embedded: 'always' } } })); @@ -723,7 +723,7 @@ test("extractSingle with embedded object (belongsTo relationship)", function() { }; var json; - run(function(){ + run(function() { json = serializer.extractSingle(env.store, SuperVillain, json_hash); }); @@ -737,7 +737,7 @@ test("extractSingle with embedded object (belongsTo relationship)", function() { "secretWeapons": [] }); - run(function(){ + run(function() { env.store.find("secretLab", 101).then(function(secretLab) { equal(secretLab.get('id'), '101'); equal(secretLab.get('minionCapacity'), 5000); @@ -750,11 +750,11 @@ test("serialize with embedded object (belongsTo relationship)", function() { env.container.register('adapter:superVillain', DS.ActiveModelAdapter); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - secretLab: {embedded: 'always'} + secretLab: { embedded: 'always' } } })); var serializer, json, tom; - run(function(){ + run(function() { serializer = env.container.lookup("serializer:superVillain"); // records with an id, persisted @@ -768,7 +768,7 @@ test("serialize with embedded object (belongsTo relationship)", function() { ); }); - run(function(){ + run(function() { json = serializer.serialize(tom); }); @@ -789,7 +789,7 @@ test("serialize with embedded object (belongsTo relationship) works with differe env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { primaryKey: '_id', attrs: { - secretLab: {embedded: 'always'} + secretLab: { embedded: 'always' } } })); env.container.register('serializer:secretLab', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { @@ -801,7 +801,7 @@ test("serialize with embedded object (belongsTo relationship) works with differe // records with an id, persisted var tom, json; - run(function(){ + run(function() { tom = env.store.createRecord( SuperVillain, { firstName: "Tom", lastName: "Dale", id: "1", @@ -811,7 +811,7 @@ test("serialize with embedded object (belongsTo relationship) works with differe ); }); - run(function(){ + run(function() { json = serializer.serialize(tom); }); @@ -831,7 +831,7 @@ test("serialize with embedded object (belongsTo relationship, new no id)", funct env.container.register('adapter:superVillain', DS.ActiveModelAdapter); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - secretLab: {embedded: 'always'} + secretLab: { embedded: 'always' } } })); @@ -840,7 +840,7 @@ test("serialize with embedded object (belongsTo relationship, new no id)", funct // records without ids, new var tom, json; - run(function(){ + run(function() { tom = env.store.createRecord( SuperVillain, { firstName: "Tom", lastName: "Dale", @@ -850,7 +850,7 @@ test("serialize with embedded object (belongsTo relationship, new no id)", funct ); }); - run(function(){ + run(function() { json = serializer.serialize(tom); }); @@ -869,7 +869,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize env.container.register('adapter:superVillain', DS.ActiveModelAdapter); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - secretLab: {serialize: 'ids'} + secretLab: { serialize: 'ids' } } })); var serializer = env.container.lookup("serializer:superVillain"); @@ -877,7 +877,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize // records with an id, persisted var tom, json; - run(function(){ + run(function() { tom = env.store.createRecord( SuperVillain, { firstName: "Tom", lastName: "Dale", id: "1", @@ -887,7 +887,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize ); }); - run(function(){ + run(function() { json = serializer.serialize(tom); }); @@ -903,7 +903,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize env.container.register('adapter:superVillain', DS.ActiveModelAdapter); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - secretLab: {serialize: 'id'} + secretLab: { serialize: 'id' } } })); @@ -912,7 +912,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize // records with an id, persisted var tom, json; - run(function(){ + run(function() { tom = env.store.createRecord( SuperVillain, { firstName: "Tom", lastName: "Dale", id: "1", @@ -922,7 +922,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize ); }); - run(function(){ + run(function() { json = serializer.serialize(tom); }); @@ -938,14 +938,14 @@ test("serialize with embedded object (belongsTo relationship) supports serialize env.container.register('adapter:superVillain', DS.ActiveModelAdapter); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - secretLab: {serialize: false} + secretLab: { serialize: false } } })); var serializer = env.container.lookup("serializer:superVillain"); // records with an id, persisted var tom, json; - run(function(){ + run(function() { tom = env.store.createRecord( SuperVillain, { firstName: "Tom", lastName: "Dale", id: "1", @@ -955,7 +955,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize ); }); - run(function(){ + run(function() { json = serializer.serialize(tom); }); @@ -975,7 +975,7 @@ test("serialize with embedded object (belongsTo relationship) serializes the id var tom, json; - run(function(){ + run(function() { tom = env.store.createRecord( SuperVillain, { firstName: "Tom", lastName: "Dale", id: "1", @@ -985,7 +985,7 @@ test("serialize with embedded object (belongsTo relationship) serializes the id ); }); - run(function(){ + run(function() { json = serializer.serialize(tom); }); @@ -1001,13 +1001,13 @@ test("when related record is not present, serialize embedded record (with a belo env.container.register('adapter:superVillain', DS.ActiveModelAdapter); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - secretLab: {embedded: 'always'} + secretLab: { embedded: 'always' } } })); var serializer = env.container.lookup("serializer:superVillain"); var tom, json; - run(function(){ + run(function() { tom = env.store.createRecord( SuperVillain, { firstName: "Tom", lastName: "Dale", id: "1", @@ -1016,7 +1016,7 @@ test("when related record is not present, serialize embedded record (with a belo ); }); - run(function(){ + run(function() { json = serializer.serialize(tom); }); @@ -1032,12 +1032,12 @@ test("extractSingle with multiply-nested belongsTo", function() { env.container.register('adapter:evilMinion', DS.ActiveModelAdapter); env.container.register('serializer:evilMinion', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - superVillain: {embedded: 'always'} + superVillain: { embedded: 'always' } } })); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - homePlanet: {embedded: 'always'} + homePlanet: { embedded: 'always' } } })); @@ -1061,7 +1061,7 @@ test("extractSingle with multiply-nested belongsTo", function() { }; var json; - run(function(){ + run(function() { json = serializer.extractSingle(env.store, EvilMinion, json_hash); }); @@ -1077,13 +1077,13 @@ test("extractSingle with multiply-nested belongsTo", function() { test("extractSingle with polymorphic hasMany", function() { SuperVillain.reopen({ - secretWeapons: DS.hasMany("secretWeapon", {polymorphic: true}) + secretWeapons: DS.hasMany("secretWeapon", { polymorphic: true }) }); env.container.register('adapter:superVillain', DS.ActiveModelAdapter); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - secretWeapons: {embedded: 'always'} + secretWeapons: { embedded: 'always' } } })); var serializer = env.container.lookup("serializer:superVillain"); @@ -1110,7 +1110,7 @@ test("extractSingle with polymorphic hasMany", function() { }; var json; - run(function(){ + run(function() { json = serializer.extractSingle(env.store, SuperVillain, json_hash); }); @@ -1119,8 +1119,8 @@ test("extractSingle with polymorphic hasMany", function() { firstName: "Tom", lastName: "Dale", secretWeapons: [ - {id: "1", type: "lightSaber"}, - {id: "1", type: "secretWeapon"} + { id: "1", type: "lightSaber" }, + { id: "1", type: "secretWeapon" } ] }, "Primary hash was correct"); @@ -1134,13 +1134,13 @@ test("extractSingle with polymorphic belongsTo", function() { expect(2); SuperVillain.reopen({ - secretLab: DS.belongsTo("secretLab", {polymorphic: true}), + secretLab: DS.belongsTo("secretLab", { polymorphic: true }) }); env.container.register('adapter:superVillain', DS.ActiveModelAdapter); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - secretLab: {embedded: 'always'} + secretLab: { embedded: 'always' } } })); var serializer = env.container.lookup("serializer:superVillain"); @@ -1177,7 +1177,7 @@ test("extractSingle with polymorphic belongsTo", function() { }); test("Mixin can be used with RESTSerializer which does not define keyForAttribute", function() { - run(function(){ + run(function() { homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); secretLab = env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); superVillain = env.store.createRecord(SuperVillain, { @@ -1193,13 +1193,13 @@ test("Mixin can be used with RESTSerializer which does not define keyForAttribut env.container.register('serializer:secretWeapon', DS.RESTSerializer); env.container.register('serializer:superVillain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - evilMinions: {serialize: 'records', deserialize: 'records'} + evilMinions: { serialize: 'records', deserialize: 'records' } } })); var serializer = env.container.lookup("serializer:superVillain"); var json; - run(function(){ + run(function() { json = serializer.serialize(superVillain); }); @@ -1222,7 +1222,7 @@ test("normalize with custom belongsTo primary key", function() { env.container.register('adapter:evilMinion', DS.ActiveModelAdapter); env.container.register('serializer:evilMinion', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - superVillain: {embedded: 'always'} + superVillain: { embedded: 'always' } } })); env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend({ @@ -1243,7 +1243,7 @@ test("normalize with custom belongsTo primary key", function() { }; var json; - run(function(){ + run(function() { json = serializer.extractSingle(env.store, EvilMinion, json_hash); }); @@ -1257,7 +1257,7 @@ test("normalize with custom belongsTo primary key", function() { }); test("serializing relationships with an embedded and without calls super when not attr not present", function() { - run(function(){ + run(function() { homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); secretLab = env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); superVillain = env.store.createRecord(SuperVillain, { @@ -1292,15 +1292,15 @@ test("serializing relationships with an embedded and without calls super when no env.container.register('serializer:secretWeapon', Serializer); env.container.register('serializer:superVillain', Serializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - evilMinions: {serialize: 'records', deserialize: 'records'} + evilMinions: { serialize: 'records', deserialize: 'records' } // some relationships are not listed here, so super should be called on those - // e.g. secretWeapons: {serialize: 'ids'} + // e.g. secretWeapons: { serialize: 'ids' } } })); var serializer = env.container.lookup("serializer:superVillain"); var json; - run(function(){ + run(function() { json = serializer.serialize(superVillain); }); diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index 7a3c3fea290..97b029b5428 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -6,7 +6,7 @@ module("integration/serializer/json - JSONSerializer", { setup: function() { Post = DS.Model.extend({ title: DS.attr('string'), - comments: DS.hasMany('comment', {inverse:null}) + comments: DS.hasMany('comment', { inverse: null }) }); Comment = DS.Model.extend({ body: DS.attr('string'), @@ -26,12 +26,12 @@ module("integration/serializer/json - JSONSerializer", { }); test("serializeAttribute", function() { - run(function(){ - post = env.store.createRecord("post", { title: "Rails is omakase"}); + run(function() { + post = env.store.createRecord("post", { title: "Rails is omakase" }); }); var json = {}; - env.serializer.serializeAttribute(post, json, "title", {type: "string"}); + env.serializer.serializeAttribute(post, json, "title", { type: "string" }); deepEqual(json, { title: "Rails is omakase" @@ -45,41 +45,37 @@ test("serializeAttribute respects keyForAttribute", function() { } })); - run(function(){ - post = env.store.createRecord("post", { title: "Rails is omakase"}); + run(function() { + post = env.store.createRecord("post", { title: "Rails is omakase" }); }); var json = {}; - env.container.lookup("serializer:post").serializeAttribute(post, json, "title", {type: "string"}); + env.container.lookup("serializer:post").serializeAttribute(post, json, "title", { type: "string" }); - deepEqual(json, { - TITLE: "Rails is omakase" - }); + deepEqual(json, { TITLE: "Rails is omakase" }); }); test("serializeBelongsTo", function() { - run(function(){ - post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1"}); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + run(function() { + post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1" }); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post }); }); var json = {}; - env.serializer.serializeBelongsTo(comment, json, {key: "post", options: {}}); + env.serializer.serializeBelongsTo(comment, json, { key: "post", options: {} }); - deepEqual(json, { - post: "1" - }); + deepEqual(json, { post: "1" }); }); test("serializeBelongsTo with null", function() { - run(function(){ - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: null}); + run(function() { + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: null }); }); var json = {}; - env.serializer.serializeBelongsTo(comment, json, {key: "post", options: {}}); + env.serializer.serializeBelongsTo(comment, json, { key: "post", options: {} }); deepEqual(json, { post: null @@ -88,14 +84,14 @@ test("serializeBelongsTo with null", function() { test("async serializeBelongsTo with null", function() { Comment.reopen({ - post: DS.belongsTo('post', {async:true}) + post: DS.belongsTo('post', { async: true }) }); - run(function(){ - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: null}); + run(function() { + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: null }); }); var json = {}; - env.serializer.serializeBelongsTo(comment, json, {key: "post", options: {}}); + env.serializer.serializeBelongsTo(comment, json, { key: "post", options: {} }); deepEqual(json, { post: null @@ -108,13 +104,13 @@ test("serializeBelongsTo respects keyForRelationship", function() { return key.toUpperCase(); } })); - run(function(){ - post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1"}); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + run(function() { + post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1" }); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post }); }); var json = {}; - env.container.lookup("serializer:post").serializeBelongsTo(comment, json, {key: "post", options: {}}); + env.container.lookup("serializer:post").serializeBelongsTo(comment, json, { key: "post", options: {} }); deepEqual(json, { POST: "1" @@ -128,14 +124,14 @@ test("serializeHasMany respects keyForRelationship", function() { } })); - run(function(){ - post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1"}); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post, id: "1"}); + run(function() { + post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1" }); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post, id: "1" }); }); var json = {}; - env.container.lookup("serializer:post").serializeHasMany(post, json, {key: "comments", options: {}}); + env.container.lookup("serializer:post").serializeHasMany(post, json, { key: "comments", options: {} }); deepEqual(json, { COMMENTS: ["1"] @@ -143,8 +139,8 @@ test("serializeHasMany respects keyForRelationship", function() { }); test("serializeIntoHash", function() { - run(function(){ - post = env.store.createRecord("post", { title: "Rails is omakase"}); + run(function() { + post = env.store.createRecord("post", { title: "Rails is omakase" }); }); var json = {}; @@ -166,14 +162,14 @@ test("serializePolymorphicType", function() { } })); - run(function(){ - post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1"}); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + run(function() { + post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1" }); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post }); }); var json = {}; - env.container.lookup("serializer:comment").serializeBelongsTo(comment, json, {key: "post", options: { polymorphic: true}}); + env.container.lookup("serializer:comment").serializeBelongsTo(comment, json, { key: "post", options: { polymorphic: true } }); deepEqual(json, { post: "1", @@ -184,8 +180,8 @@ test("serializePolymorphicType", function() { test("extractArray normalizes each record in the array", function() { var postNormalizeCount = 0; var posts = [ - { title: "Rails is omakase"}, - { title: "Another Post"} + { title: "Rails is omakase" }, + { title: "Another Post" } ]; env.container.register('serializer:post', DS.JSONSerializer.extend({ @@ -195,13 +191,13 @@ test("extractArray normalizes each record in the array", function() { } })); - run(function(){ + run(function() { env.container.lookup("serializer:post").extractArray(env.store, Post, posts); }); equal(postNormalizeCount, 2, "two posts are normalized"); }); -test('Serializer should respect the attrs hash when extracting records', function(){ +test('Serializer should respect the attrs hash when extracting records', function() { env.container.register("serializer:post", DS.JSONSerializer.extend({ attrs: { title: "title_payload_key", @@ -220,21 +216,21 @@ test('Serializer should respect the attrs hash when extracting records', functio deepEqual(post.comments, [1,2]); }); -test('Serializer should respect the attrs hash when serializing records', function(){ +test('Serializer should respect the attrs hash when serializing records', function() { Post.reopen({ parentPost: DS.belongsTo('post') }); env.container.register("serializer:post", DS.JSONSerializer.extend({ attrs: { title: "title_payload_key", - parentPost: {key: 'my_parent'} + parentPost: { key: "my_parent" } } })); var parentPost; - run(function(){ - parentPost = env.store.push("post", { id:2, title: "Rails is omakase"}); - post = env.store.createRecord("post", { title: "Rails is omakase", parentPost: parentPost}); + run(function() { + parentPost = env.store.push("post", { id: 2, title: "Rails is omakase" }); + post = env.store.createRecord("post", { title: "Rails is omakase", parentPost: parentPost }); }); var payload = env.container.lookup("serializer:post").serialize(post); @@ -243,16 +239,16 @@ test('Serializer should respect the attrs hash when serializing records', functi equal(payload.my_parent, '2'); }); -test('Serializer respects `serialize: false` on the attrs hash', function(){ +test('Serializer respects `serialize: false` on the attrs hash', function() { expect(2); env.container.register("serializer:post", DS.JSONSerializer.extend({ attrs: { - title: {serialize: false} + title: { serialize: false } } })); - run(function(){ - post = env.store.createRecord("post", { title: "Rails is omakase"}); + run(function() { + post = env.store.createRecord("post", { title: "Rails is omakase" }); }); var payload = env.container.lookup("serializer:post").serialize(post); @@ -261,17 +257,17 @@ test('Serializer respects `serialize: false` on the attrs hash', function(){ ok(!payload.hasOwnProperty('[object Object]'),"Does not add some random key like [object Object]"); }); -test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` property', function(){ +test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` property', function() { expect(1); env.container.register("serializer:post", DS.JSONSerializer.extend({ attrs: { - comments: {serialize: false} + comments: { serialize: false } } })); - run(function(){ - post = env.store.createRecord("post", { title: "Rails is omakase"}); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + run(function() { + post = env.store.createRecord("post", { title: "Rails is omakase" }); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post }); }); var serializer = env.container.lookup("serializer:post"); @@ -281,17 +277,17 @@ test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` p ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); }); -test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` property', function(){ +test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` property', function() { expect(1); env.container.register("serializer:comment", DS.JSONSerializer.extend({ attrs: { - post: {serialize: false} + post: { serialize: false } } })); - run(function(){ - post = env.store.createRecord("post", { title: "Rails is omakase"}); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post}); + run(function() { + post = env.store.createRecord("post", { title: "Rails is omakase" }); + comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post }); }); var serializer = env.container.lookup("serializer:comment"); @@ -306,9 +302,9 @@ test("Serializer should respect the primaryKey attribute when extracting records primaryKey: '_ID_' })); - var jsonHash = { "_ID_": 1, title: "Rails is omakase"}; + var jsonHash = { "_ID_": 1, title: "Rails is omakase" }; - run(function(){ + run(function() { post = env.container.lookup("serializer:post").extractSingle(env.store, Post, jsonHash); }); @@ -321,11 +317,11 @@ test("Serializer should respect the primaryKey attribute when serializing record primaryKey: '_ID_' })); - run(function(){ - post = env.store.createRecord("post", { id: "1", title: "Rails is omakase"}); + run(function() { + post = env.store.createRecord("post", { id: "1", title: "Rails is omakase" }); }); - var payload = env.container.lookup("serializer:post").serialize(post, {includeId: true}); + var payload = env.container.lookup("serializer:post").serialize(post, { includeId: true }); equal(payload._ID_, "1"); }); @@ -337,7 +333,7 @@ test("Serializer should respect keyForAttribute when extracting records", functi } })); - var jsonHash = {id: 1, TITLE: 'Rails is omakase'}; + var jsonHash = { id: 1, TITLE: 'Rails is omakase' }; post = env.container.lookup("serializer:post").normalize(Post, jsonHash); @@ -352,7 +348,7 @@ test("Serializer should respect keyForRelationship when extracting records", fun } })); - var jsonHash = {id: 1, title: 'Rails is omakase', COMMENTS: ['1']}; + var jsonHash = { id: 1, title: 'Rails is omakase', COMMENTS: ['1'] }; post = env.container.lookup("serializer:post").normalize(Post, jsonHash); @@ -373,7 +369,7 @@ test("normalizePayload is called during extractSingle", function() { } }; - run(function(){ + run(function() { post = env.container.lookup("serializer:post").extractSingle(env.store, Post, jsonHash); }); diff --git a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js index bd0b3c38f26..e713f8a0500 100644 --- a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js @@ -21,7 +21,7 @@ module("integration/serializer/rest - RESTSerializer", { YellowMinion = EvilMinion.extend(); DoomsdayDevice = DS.Model.extend({ name: DS.attr('string'), - evilMinion: DS.belongsTo('evilMinion', {polymorphic: true}) + evilMinion: DS.belongsTo('evilMinion', { polymorphic: true }) }); Comment = DS.Model.extend({ body: DS.attr('string'), @@ -64,23 +64,23 @@ test("extractArray with custom typeForRoot", function() { }; var jsonHash = { - home_planets: [{id: "1", name: "Umber", superVillains: [1]}], - super_villains: [{id: "1", firstName: "Tom", lastName: "Dale", homePlanet: "1"}] + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], + super_villains: [{ id: "1", firstName: "Tom", lastName: "Dale", homePlanet: "1" }] }; var array; - run(function(){ + run(function() { array = env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); }); deepEqual(array, [{ - "id": "1", - "name": "Umber", - "superVillains": [1] + id: "1", + name: "Umber", + superVillains: [1] }]); - run(function(){ - env.store.find("superVillain", 1).then(function(minion){ + run(function() { + env.store.find("superVillain", 1).then(function(minion) { equal(minion.get('firstName'), "Tom"); }); }); @@ -94,24 +94,24 @@ test("extractArray warning with custom typeForRoot", function() { }; var jsonHash = { - home_planets: [{id: "1", name: "Umber", superVillains: [1]}] + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] }; - warns(function(){ + warns(function() { env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); // should not warn if a model is found. - env.restSerializer.typeForRoot = function(root){ + env.restSerializer.typeForRoot = function(root) { return Ember.String.camelize(Ember.String.singularize(root)); }; jsonHash = { - home_planets: [{id: "1", name: "Umber", superVillains: [1]}] + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] }; - noWarns(function(){ - run(function(){ + noWarns(function() { + run(function() { homePlanets = Ember.A(env.restSerializer.extractArray(env.store, HomePlanet, jsonHash)); }); }); @@ -129,26 +129,26 @@ test("extractSingle warning with custom typeForRoot", function() { }; var jsonHash = { - home_planet: {id: "1", name: "Umber", superVillains: [1]} + home_planet: { id: "1", name: "Umber", superVillains: [1] } }; - warns(Ember.run.bind(null, function(){ - run(function(){ + warns(Ember.run.bind(null, function() { + run(function() { env.restSerializer.extractSingle(env.store, HomePlanet, jsonHash); }); }), /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); // should not warn if a model is found. - env.restSerializer.typeForRoot = function(root){ + env.restSerializer.typeForRoot = function(root) { return Ember.String.camelize(Ember.String.singularize(root)); }; jsonHash = { - home_planet: {id: "1", name: "Umber", superVillains: [1]} + home_planet: { id: "1", name: "Umber", superVillains: [1] } }; - noWarns(function(){ - run(function(){ + noWarns(function() { + run(function() { homePlanet = env.restSerializer.extractSingle(env.store, HomePlanet, jsonHash); }); }); @@ -160,7 +160,7 @@ test("extractSingle warning with custom typeForRoot", function() { test("pushPayload - single record payload - warning with custom typeForRoot", function() { var homePlanet; var HomePlanetRestSerializer = DS.RESTSerializer.extend({ - typeForRoot: function(root){ + typeForRoot: function(root) { //return some garbage that won"t resolve in the container if (root === "home_planet") { return "garbage"; @@ -173,17 +173,12 @@ test("pushPayload - single record payload - warning with custom typeForRoot", fu env.container.register("serializer:homePlanet", HomePlanetRestSerializer); var jsonHash = { - home_planet: {id: "1", name: "Umber", superVillains: [1]}, - super_villains: [ - { - "id": "1", - "firstName": "Stanley" - } - ] + home_planet: { id: "1", name: "Umber", superVillains: [1] }, + super_villains: [{ id: "1", firstName: "Stanley" }] }; - warns(function(){ - run(function(){ + warns(function() { + run(function() { env.store.pushPayload("homePlanet", jsonHash); }); }, /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); @@ -196,24 +191,19 @@ test("pushPayload - single record payload - warning with custom typeForRoot", fu // Serializers are singletons, so that"s why we use the store which // looks at the container to look it up env.store.serializerFor("homePlanet").reopen({ - typeForRoot: function(root){ + typeForRoot: function(root) { // should not warn if a model is found. return Ember.String.camelize(Ember.String.singularize(root)); } }); jsonHash = { - home_planet: {id: "1", name: "Umber", superVillains: [1]}, - super_villains: [ - { - "id": "1", - "firstName": "Stanley" - } - ] + home_planet: { id: "1", name: "Umber", superVillains: [1] }, + super_villains: [{ id: "1", firstName: "Stanley" }] }; - noWarns(function(){ - run(function(){ + noWarns(function() { + run(function() { env.store.pushPayload("homePlanet", jsonHash); homePlanet = env.store.getById("homePlanet", "1"); }); @@ -226,7 +216,7 @@ test("pushPayload - single record payload - warning with custom typeForRoot", fu test("pushPayload - multiple record payload (extractArray) - warning with custom typeForRoot", function() { var homePlanet; var HomePlanetRestSerializer = DS.RESTSerializer.extend({ - typeForRoot: function(root){ + typeForRoot: function(root) { //return some garbage that won"t resolve in the container if (root === "home_planets") { return "garbage"; @@ -239,17 +229,12 @@ test("pushPayload - multiple record payload (extractArray) - warning with custom env.container.register("serializer:homePlanet", HomePlanetRestSerializer); var jsonHash = { - home_planets: [{id: "1", name: "Umber", superVillains: [1]}], - super_villains: [ - { - "id": "1", - "firstName": "Stanley" - } - ] + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], + super_villains: [{ id: "1", firstName: "Stanley" }] }; - warns(function(){ - run(function(){ + warns(function() { + run(function() { env.store.pushPayload("homePlanet", jsonHash); }); }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); @@ -261,24 +246,19 @@ test("pushPayload - multiple record payload (extractArray) - warning with custom // Serializers are singletons, so that"s why we use the store which // looks at the container to look it up env.store.serializerFor("homePlanet").reopen({ - typeForRoot: function(root){ + typeForRoot: function(root) { // should not warn if a model is found. return Ember.String.camelize(Ember.String.singularize(root)); } }); jsonHash = { - home_planets: [{id: "1", name: "Umber", superVillains: [1]}], - super_villains: [ - { - "id": "1", - "firstName": "Stanley" - } - ] + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], + super_villains: [{ id: "1", firstName: "Stanley" }] }; - noWarns(function(){ - run(function(){ + noWarns(function() { + run(function() { env.store.pushPayload("homePlanet", jsonHash); homePlanet = env.store.getById("homePlanet", "1"); }); @@ -290,9 +270,9 @@ test("pushPayload - multiple record payload (extractArray) - warning with custom test("serialize polymorphicType", function() { var tom, ray; - run(function(){ - tom = env.store.createRecord(YellowMinion, {name: "Alex", id: "124"}); - ray = env.store.createRecord(DoomsdayDevice, {evilMinion: tom, name: "DeathRay"}); + run(function() { + tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); + ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); }); var json = env.restSerializer.serialize(ray); @@ -307,9 +287,9 @@ test("serialize polymorphicType", function() { test("serialize polymorphicType with decamelized typeKey", function() { YellowMinion.typeKey = 'yellow-minion'; var tom, ray; - run(function(){ - tom = env.store.createRecord(YellowMinion, {name: "Alex", id: "124"}); - ray = env.store.createRecord(DoomsdayDevice, {evilMinion: tom, name: "DeathRay"}); + run(function() { + tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); + ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); }); var json = env.restSerializer.serialize(ray); @@ -324,15 +304,17 @@ test("normalizePayload is called during extractSingle", function() { } })); - var jsonHash = { response: { - evilMinion: {id: "1", name: "Tom Dale", superVillain: 1}, - superVillains: [{id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1"}] - } }; + var jsonHash = { + response: { + evilMinion: { id: "1", name: "Tom Dale", superVillain: 1 }, + superVillains: [{ id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1" }] + } + }; var applicationSerializer = env.container.lookup('serializer:application'); var data; - run(function(){ + run(function() { data = applicationSerializer.extractSingle(env.store, EvilMinion, jsonHash); }); @@ -341,8 +323,8 @@ test("normalizePayload is called during extractSingle", function() { }); test("serialize polymorphic when associated object is null", function() { var ray; - run(function(){ - ray = env.store.createRecord(DoomsdayDevice, {name: "DeathRay"}); + run(function() { + ray = env.store.createRecord(DoomsdayDevice, { name: "DeathRay" }); }); var json = env.restSerializer.serialize(ray); @@ -352,7 +334,7 @@ test("serialize polymorphic when associated object is null", function() { test("extractArray can load secondary records of the same type without affecting the query count", function() { var jsonHash = { - comments: [{id: "1", body: "Parent Comment", root: true, children: [2, 3]}], + comments: [{ id: "1", body: "Parent Comment", root: true, children: [2, 3] }], _comments: [ { id: "2", body: "Child Comment 1", root: false }, { id: "3", body: "Child Comment 2", root: false } @@ -360,7 +342,7 @@ test("extractArray can load secondary records of the same type without affecting }; var array; - run(function(){ + run(function() { array = env.restSerializer.extractArray(env.store, Comment, jsonHash); }); @@ -388,11 +370,11 @@ test("extractSingle loads secondary records with correct serializer", function() })); var jsonHash = { - evilMinion: {id: "1", name: "Tom Dale", superVillain: 1}, - superVillains: [{id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1"}] + evilMinion: { id: "1", name: "Tom Dale", superVillain: 1 }, + superVillains: [{ id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1" }] }; - run(function(){ + run(function() { env.restSerializer.extractSingle(env.store, EvilMinion, jsonHash); }); @@ -407,7 +389,7 @@ test("extractSingle returns null if payload contains null", function() { }; var value; - run(function(){ + run(function() { value = env.restSerializer.extractSingle(env.store, EvilMinion, jsonHash); }); @@ -425,18 +407,18 @@ test("extractArray loads secondary records with correct serializer", function() })); var jsonHash = { - evilMinions: [{id: "1", name: "Tom Dale", superVillain: 1}], - superVillains: [{id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1"}] + evilMinions: [{ id: "1", name: "Tom Dale", superVillain: 1 }], + superVillains: [{ id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1" }] }; - run(function(){ + run(function() { env.restSerializer.extractArray(env.store, EvilMinion, jsonHash); }); equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); }); -test('normalizeHash normalizes specific parts of the payload', function(){ +test('normalizeHash normalizes specific parts of the payload', function() { env.container.register('serializer:application', DS.RESTSerializer.extend({ normalizeHash: { homePlanets: function(hash) { @@ -447,10 +429,12 @@ test('normalizeHash normalizes specific parts of the payload', function(){ } })); - var jsonHash = { homePlanets: [{_id: "1", name: "Umber", superVillains: [1]}] }; + var jsonHash = { + homePlanets: [{ _id: "1", name: "Umber", superVillains: [1] }] + }; var array; - run(function(){ + run(function() { array = env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); }); @@ -461,7 +445,7 @@ test('normalizeHash normalizes specific parts of the payload', function(){ }]); }); -test('normalizeHash works with transforms', function(){ +test('normalizeHash works with transforms', function() { env.container.register('serializer:application', DS.RESTSerializer.extend({ normalizeHash: { evilMinions: function(hash) { @@ -492,18 +476,18 @@ test('normalizeHash works with transforms', function(){ EvilMinion.reopen({ condition: DS.attr('condition') }); var jsonHash = { - evilMinions: [{id: "1", name: "Tom Dale", superVillain: 1, _condition: 1}] + evilMinions: [{ id: "1", name: "Tom Dale", superVillain: 1, _condition: 1 }] }; var array; - run(function(){ + run(function() { array = env.restSerializer.extractArray(env.store, EvilMinion, jsonHash); }); equal(array[0].condition, "healing"); }); -test('normalize should allow for different levels of normalization', function(){ +test('normalize should allow for different levels of normalization', function() { env.container.register('serializer:application', DS.RESTSerializer.extend({ attrs: { superVillain: 'is_super_villain' @@ -514,11 +498,11 @@ test('normalize should allow for different levels of normalization', function(){ })); var jsonHash = { - evilMinions: [{id: "1", name: "Tom Dale", is_super_villain: 1}] + evilMinions: [{ id: "1", name: "Tom Dale", is_super_villain: 1 }] }; var array; - run(function(){ + run(function() { array = env.restSerializer.extractArray(env.store, EvilMinion, jsonHash); }); @@ -526,7 +510,7 @@ test('normalize should allow for different levels of normalization', function(){ }); test("serializeIntoHash", function() { - run(function(){ + run(function() { league = env.store.createRecord(HomePlanet, { name: "Umber", id: "123" }); }); var json = {}; @@ -542,7 +526,7 @@ test("serializeIntoHash", function() { test("serializeIntoHash with decamelized typeKey", function() { HomePlanet.typeKey = 'home-planet'; - run(function(){ + run(function() { league = env.store.createRecord(HomePlanet, { name: "Umber", id: "123" }); }); var json = {}; diff --git a/packages/ember-data/tests/integration/setup-container-test.js b/packages/ember-data/tests/integration/setup-container-test.js index aa8269eba50..91b30d6f7cb 100644 --- a/packages/ember-data/tests/integration/setup-container-test.js +++ b/packages/ember-data/tests/integration/setup-container-test.js @@ -32,7 +32,7 @@ test("If a store is instantiated, it should be made available to each controller ok(fooController.get('store') instanceof Store, "the store was injected"); }); -test("the deprecated serializer:_default is resolved as serializer:default", function(){ +test("the deprecated serializer:_default is resolved as serializer:default", function() { var deprecated, valid = container.lookup('serializer:-default'); expectDeprecation(function() { deprecated = container.lookup('serializer:_default'); @@ -41,7 +41,7 @@ test("the deprecated serializer:_default is resolved as serializer:default", fun ok(deprecated === valid, "they should resolve to the same thing"); }); -test("the deprecated serializer:_rest is resolved as serializer:rest", function(){ +test("the deprecated serializer:_rest is resolved as serializer:rest", function() { var deprecated, valid = container.lookup('serializer:-rest'); expectDeprecation(function() { deprecated = container.lookup('serializer:_rest'); @@ -50,7 +50,7 @@ test("the deprecated serializer:_rest is resolved as serializer:rest", function( ok(deprecated === valid, "they should resolve to the same thing"); }); -test("the deprecated adapter:_rest is resolved as adapter:rest", function(){ +test("the deprecated adapter:_rest is resolved as adapter:rest", function() { var deprecated, valid = container.lookup('adapter:-rest'); expectDeprecation(function() { deprecated = container.lookup('adapter:_rest'); @@ -59,8 +59,8 @@ test("the deprecated adapter:_rest is resolved as adapter:rest", function(){ ok(deprecated === valid, "they should resolve to the same thing"); }); -test("a deprecation is made when looking up adapter:_rest", function(){ - expectDeprecation(function(){ +test("a deprecation is made when looking up adapter:_rest", function() { + expectDeprecation(function() { container.lookup('serializer:_default'); },"You tried to look up 'serializer:_default', but this has been deprecated in favor of 'serializer:-default'."); }); diff --git a/packages/ember-data/tests/integration/store_test.js b/packages/ember-data/tests/integration/store_test.js index a4130615ba1..7d43331fbe9 100644 --- a/packages/ember-data/tests/integration/store_test.js +++ b/packages/ember-data/tests/integration/store_test.js @@ -28,7 +28,7 @@ function initializeStore(adapter) { } module("integration/store - destroy", { - setup: function(){ + setup: function() { initializeStore(DS.FixtureAdapter.extend()); } }); @@ -69,11 +69,11 @@ asyncTest("destroying record during find doesn't cause error", function() { var type = "car"; var id = 1; - function done(){ + function done() { start(); } - run(function(){ + run(function() { store.find(type, id).then(done, done); }); }); @@ -100,7 +100,7 @@ asyncTest("find calls do not resolve when the store is destroyed", function() { throw new Error("We shouldn't be pushing data into the store when it is destroyed"); }; - run(function(){ + run(function() { store.find(type, id); }); @@ -112,7 +112,7 @@ asyncTest("find calls do not resolve when the store is destroyed", function() { test("destroying the store correctly cleans everything up", function() { var car, person; - run(function(){ + run(function() { car = store.push('car', { id: 1, make: 'BMC', @@ -139,20 +139,20 @@ test("destroying the store correctly cleans everything up", function() { }; var adapterPopulatedPeople, filterdPeople; - run(function(){ + run(function() { adapterPopulatedPeople = store.find('person', { someCrazy: 'query' }); }); - run(function(){ - filterdPeople = store.filter('person', function(){ return true; }); + run(function() { + filterdPeople = store.filter('person', function() { return true; }); }); var filterdPeopleWillDestroy = tap(filterdPeople.content, 'willDestroy'); var adapterPopulatedPeopleWillDestroy = tap(adapterPopulatedPeople.content, 'willDestroy'); - run(function(){ + run(function() { store.find('person', 2); }); @@ -181,7 +181,7 @@ test("destroying the store correctly cleans everything up", function() { }); module("integration/store - fetch", { - setup: function(){ + setup: function() { initializeStore(DS.RESTAdapter.extend()); } }); @@ -201,7 +201,7 @@ test("Using store#fetch on existing record reloads it", function() { expect(2); var car; - run(function(){ + run(function() { car = store.push('car', { id: 1, make: 'BMC', @@ -219,7 +219,7 @@ test("Using store#fetch on existing record reloads it", function() { equal(car.get('make'), 'BMC'); - run(function(){ + run(function() { store.fetch('car', 1).then(function(car) { equal(car.get('make'), 'BMCW'); }); @@ -240,7 +240,7 @@ test("Using store#fetch on non existing record calls find", function() { var car = store.hasRecordForId('car', 20); ok(!car, 'Car with id=20 should not exist'); - run(function(){ + run(function() { store.fetch('car', 20).then(function (car) { equal(car.get('make'), 'BMCW', 'Car with id=20 is now loaded'); }); diff --git a/packages/ember-data/tests/unit/adapter_populated_record_array_test.js b/packages/ember-data/tests/unit/adapter_populated_record_array_test.js index 4cd075d122f..9de3a89ea5b 100644 --- a/packages/ember-data/tests/unit/adapter_populated_record_array_test.js +++ b/packages/ember-data/tests/unit/adapter_populated_record_array_test.js @@ -1,7 +1,8 @@ var Person, array, store; +var run = Ember.run; var adapter = DS.Adapter.extend({ - deleteRecord: function(){ + deleteRecord: function() { return Ember.RSVP.Promise.resolve(); } }); @@ -27,13 +28,13 @@ test("when a record is deleted in an adapter populated record array, it should b var recordArray = store.recordArrayManager .createAdapterPopulatedRecordArray(Person, null); - Ember.run(function(){ + run(function() { recordArray.load(array); }); equal(recordArray.get('length'), 3, "expected recordArray to contain exactly 3 records"); - Ember.run(function(){ + run(function() { recordArray.get('firstObject').destroyRecord(); }); diff --git a/packages/ember-data/tests/unit/adapters/rest_adapter/ajax.js b/packages/ember-data/tests/unit/adapters/rest_adapter/ajax.js index a1316933a86..05ee98d5343 100644 --- a/packages/ember-data/tests/unit/adapters/rest_adapter/ajax.js +++ b/packages/ember-data/tests/unit/adapters/rest_adapter/ajax.js @@ -3,15 +3,15 @@ var run = Ember.run; module("integration/adapter/ajax - building requests", { setup: function() { - Person = {typeKey: 'person'}; - Place = {typeKey: 'place'}; - env = setupStore({adapter: DS.RESTAdapter, person: Person, place: Place }); + Person = { typeKey: 'person' }; + Place = { typeKey: 'place' }; + env = setupStore({ adapter: DS.RESTAdapter, person: Person, place: Place }); store = env.store; adapter = env.adapter; }, teardown: function() { - run(function(){ + run(function() { store.destroy(); env.container.destroy(); }); @@ -22,12 +22,12 @@ test("When an id is searched, the correct url should be generated", function() { expect(2); var count = 0; adapter.ajax = function(url, method) { - if (count === 0) {equal(url, '/people/1', "should create the correct url");} - if (count === 1) {equal(url, '/places/1', "should create the correct url");} + if (count === 0) { equal(url, '/people/1', "should create the correct url"); } + if (count === 1) { equal(url, '/places/1', "should create the correct url"); } count++; return Ember.RSVP.resolve(); }; - run(function(){ + run(function() { adapter.find(store, Person, 1); adapter.find(store, Place, 1); }); @@ -38,7 +38,7 @@ test("id's should be sanatized", function() { equal(url, '/people/..%2Fplace%2F1', "should create the correct url"); return Ember.RSVP.resolve(); }; - run(function(){ + run(function() { adapter.find(store, Person, '../place/1'); }); }); diff --git a/packages/ember-data/tests/unit/adapters/rest_adapter/group_records_for_find_many_test.js b/packages/ember-data/tests/unit/adapters/rest_adapter/group_records_for_find_many_test.js index ae00a4c61e3..fdf8813b054 100644 --- a/packages/ember-data/tests/unit/adapters/rest_adapter/group_records_for_find_many_test.js +++ b/packages/ember-data/tests/unit/adapters/rest_adapter/group_records_for_find_many_test.js @@ -33,17 +33,17 @@ module("unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda } }); - -test('groupRecordsForFindMany - findMany', function() { - - Ember.run(function() { - for(var i = 1; i <= 1024; i++) { - Store.find('testRecord', i); - } - }); - - ok(lengths.every(function(len) { - return len <= maxLength; - }), "Some URLs are longer than " + maxLength + " chars"); - -}); + +test('groupRecordsForFindMany - findMany', function() { + + Ember.run(function() { + for (var i = 1; i <= 1024; i++) { + Store.find('testRecord', i); + } + }); + + ok(lengths.every(function(len) { + return len <= maxLength; + }), "Some URLs are longer than " + maxLength + " chars"); + +}); diff --git a/packages/ember-data/tests/unit/debug_test.js b/packages/ember-data/tests/unit/debug_test.js index 20c723a682b..f4906b99460 100644 --- a/packages/ember-data/tests/unit/debug_test.js +++ b/packages/ember-data/tests/unit/debug_test.js @@ -28,7 +28,7 @@ test("_debugInfo groups the attributes and relationships correctly", function() }); var record; - run(function(){ + run(function() { record = store.createRecord(User); }); diff --git a/packages/ember-data/tests/unit/model/errors_test.js b/packages/ember-data/tests/unit/model/errors_test.js index 15ad7b1f355..4d41a309e82 100644 --- a/packages/ember-data/tests/unit/model/errors_test.js +++ b/packages/ember-data/tests/unit/model/errors_test.js @@ -51,7 +51,7 @@ test("get error", function() { errors.add('firstName', 'error'); errors.trigger = unexpectedSend; ok(errors.get('firstName').length === 1, 'returns errors'); - deepEqual(errors.get('firstObject'), {attribute: 'firstName', message: 'error'}); + deepEqual(errors.get('firstObject'), { attribute: 'firstName', message: 'error' }); errors.add('firstName', 'error2'); ok(errors.get('firstName').length === 2, 'returns errors'); errors.add('lastName', 'error3'); diff --git a/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js b/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js index 45a9a72df05..f92eff986fc 100644 --- a/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js +++ b/packages/ember-data/tests/unit/model/lifecycle_callbacks_test.js @@ -23,7 +23,7 @@ test("a record receives a didLoad callback when it has finished loading", functi adapter: adapter }); - run(function(){ + run(function() { store.find(Person, 1).then(function(person) { equal(person.get('id'), "1", "The person's ID is available"); equal(person.get('name'), "Foo", "The person's properties are available"); @@ -64,14 +64,14 @@ test("a record receives a didUpdate callback when it has finished updating", fun }); var asyncPerson; - run(function(){ + run(function() { asyncPerson = store.find(Person, 1); }); equal(callCount, 0, "precond - didUpdate callback was not called yet"); - run(function(){ + run(function() { asyncPerson.then(function(person) { - return run(function(){ + return run(function() { person.set('bar', "Bar"); return person.save(); }); @@ -109,12 +109,12 @@ test("a record receives a didCreate callback when it has finished updating", fun equal(callCount, 0, "precond - didCreate callback was not called yet"); var person; - run(function(){ + run(function() { person = store.createRecord(Person, { id: 69, name: "Newt Gingrich" }); }); - run(function(){ + run(function() { person.save().then(function() { equal(callCount, 1, "didCreate called after commit"); }); @@ -155,15 +155,15 @@ test("a record receives a didDelete callback when it has finished deleting", fun }); var asyncPerson; - run(function(){ + run(function() { asyncPerson = store.find(Person, 1); }); equal(callCount, 0, "precond - didDelete callback was not called yet"); - run(function(){ + run(function() { asyncPerson.then(function(person) { - return run(function(){ + return run(function() { person.deleteRecord(); return person.save(); }); @@ -207,7 +207,7 @@ test("a record receives a becameInvalid callback when it became invalid", functi }); var asyncPerson; - run(function(){ + run(function() { asyncPerson = store.find(Person, 1); }); equal(callCount, 0, "precond - becameInvalid callback was not called yet"); @@ -216,7 +216,7 @@ test("a record receives a becameInvalid callback when it became invalid", functi // save fails. run(function() { asyncPerson.then(function(person) { - return run(function(){ + return run(function() { person.set('bar', "Bar"); return person.save(); }); @@ -233,7 +233,7 @@ test("an ID of 0 is allowed", function() { name: DS.attr('string') }); - run(function(){ + run(function() { store.push(Person, { id: 0, name: "Tom Dale" }); }); diff --git a/packages/ember-data/tests/unit/model/merge_test.js b/packages/ember-data/tests/unit/model/merge_test.js index 141488a8b92..00aafcb5586 100644 --- a/packages/ember-data/tests/unit/model/merge_test.js +++ b/packages/ember-data/tests/unit/model/merge_test.js @@ -21,7 +21,7 @@ test("When a record is in flight, changes can be made", function() { var person; var store = createStore({ adapter: adapter }); - run(function(){ + run(function() { person = store.createRecord(Person, { name: "Tom Dale" }); }); @@ -46,7 +46,7 @@ test("When a record is in flight, pushes are applied underneath the in flight ch var adapter = DS.Adapter.extend({ updateRecord: function(store, type, record) { // Make sure saving isn't resolved synchronously - return new Ember.RSVP.Promise(function(resolve, reject){ + return new Ember.RSVP.Promise(function(resolve, reject) { run.next(null, resolve, { id: 1, name: "Senor Thomas Dale, Esq.", city: "Portland" }); }); } @@ -55,7 +55,7 @@ test("When a record is in flight, pushes are applied underneath the in flight ch var store = createStore({ adapter: adapter }); var person; - run(function(){ + run(function() { person = store.push(Person, { id: 1, name: "Tom" }); person.set('name', "Thomas Dale"); }); @@ -84,7 +84,7 @@ test("When a record is dirty, pushes are overridden by local changes", function( var store = createStore({ adapter: DS.Adapter }); var person; - run(function(){ + run(function() { person = store.push(Person, { id: 1, name: "Tom Dale", city: "San Francisco" }); person.set('name', "Tomasz Dale"); }); @@ -93,7 +93,7 @@ test("When a record is dirty, pushes are overridden by local changes", function( equal(person.get('name'), "Tomasz Dale", "the update was effective"); equal(person.get('city'), "San Francisco", "the original data applies"); - run(function(){ + run(function() { store.push(Person, { id: 1, name: "Thomas Dale", city: "Portland" }); }); @@ -114,11 +114,11 @@ test("A record with no changes can still be saved", function() { var store = createStore({ adapter: adapter }); var person; - run(function(){ + run(function() { person = store.push(Person, { id: 1, name: "Tom Dale" }); }); - run(function(){ + run(function() { person.save().then(function() { equal(person.get('name'), "Thomas Dale", "the updates occurred"); }); @@ -137,12 +137,12 @@ test("A dirty record can be reloaded", function() { var store = createStore({ adapter: adapter }); var person; - run(function(){ + run(function() { person = store.push(Person, { id: 1, name: "Tom Dale" }); person.set('name', "Tomasz Dale"); }); - run(function(){ + run(function() { person.reload().then(function() { equal(person.get('isDirty'), true, "the person is dirty"); equal(person.get('name'), "Tomasz Dale", "the local changes remain"); diff --git a/packages/ember-data/tests/unit/model/relationships_test.js b/packages/ember-data/tests/unit/model/relationships_test.js index 52cf499ba15..1e8a2165114 100644 --- a/packages/ember-data/tests/unit/model/relationships_test.js +++ b/packages/ember-data/tests/unit/model/relationships_test.js @@ -76,14 +76,14 @@ test("hasMany handles pre-loaded relationships", function() { var store = env.store; - run(function(){ + run(function() { store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); store.pushMany('pet', [{ id: 4, name: "fluffy" }, { id: 7, name: "snowy" }, { id: 12, name: "cerberus" }]); store.push('person', { id: 1, name: "Tom Dale", tags: [5] }); store.push('person', { id: 2, name: "Yehuda Katz", tags: [12] }); }); - run(function(){ + run(function() { store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); @@ -91,7 +91,7 @@ test("hasMany handles pre-loaded relationships", function() { equal(get(tags, 'length'), 1, "the list of tags should have the correct length"); equal(get(tags.objectAt(0), 'name'), "friendly", "the first tag should be a Tag"); - run(function(){ + run(function() { store.push('person', { id: 1, name: "Tom Dale", tags: [5, 2] }); }); @@ -101,7 +101,7 @@ test("hasMany handles pre-loaded relationships", function() { strictEqual(get(person, 'tags').objectAt(0), get(person, 'tags').objectAt(0), "the returned object is always the same"); asyncEqual(get(person, 'tags').objectAt(0), store.find(Tag, 5), "relationship objects are the same as objects retrieved directly"); - run(function(){ + run(function() { store.push('person', { id: 3, name: "KSelden" }); }); @@ -109,7 +109,7 @@ test("hasMany handles pre-loaded relationships", function() { }).then(function(kselden) { equal(get(get(kselden, 'tags'), 'length'), 0, "a relationship that has not been supplied returns an empty array"); - run(function(){ + run(function() { store.push('person', { id: 4, name: "Cyvid Hamluck", pets: [4] }); }); return store.find('person', 4); @@ -163,7 +163,7 @@ test("hasMany lazily loads async relationships", function() { var store = env.store; - run(function(){ + run(function() { store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); store.pushMany('pet', [{ id: 4, name: "fluffy" }, { id: 7, name: "snowy" }, { id: 12, name: "cerberus" }]); store.push('person', { id: 1, name: "Tom Dale", tags: [5] }); @@ -172,7 +172,7 @@ test("hasMany lazily loads async relationships", function() { var wycats; - run(function(){ + run(function() { store.find('person', 2).then(function(person) { wycats = person; @@ -192,7 +192,7 @@ test("hasMany lazily loads async relationships", function() { return get(wycats, 'tags'); }).then(function(tags) { var newTag; - run(function(){ + run(function() { newTag = store.createRecord(Tag); tags.pushObject(newTag); }); @@ -281,12 +281,12 @@ test("relationships work when declared with a string path", function() { tag: Tag }); - run(function(){ + run(function() { env.store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); env.store.push('person', { id: 1, name: "Tom Dale", tags: [5, 2] }); }); - run(function(){ + run(function() { env.store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); equal(get(person, 'tags.length'), 2, "the list of tags should have the correct length"); @@ -329,11 +329,11 @@ test("hasMany relationships work when the data hash has not been loaded", functi return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", tags: [5, 2] }); }; - run(function(){ + run(function() { store.find('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); - return run(function(){ + return run(function() { return person.get('tags'); }); }).then(function(tags) { @@ -364,12 +364,12 @@ test("it is possible to add a new item to a relationship", function() { var store = env.store; - run(function(){ - store.push('person', { id: 1, name: "Tom Dale", tags: [ 1 ] }); + run(function() { + store.push('person', { id: 1, name: "Tom Dale", tags: [1] }); store.push('tag', { id: 1, name: "ember" }); }); - run(function(){ + run(function() { store.find(Person, 1).then(function(person) { var tag = get(person, 'tags').objectAt(0); @@ -383,7 +383,7 @@ test("it is possible to add a new item to a relationship", function() { }); }); -test("possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)", function(){ +test("possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)", function() { expect(2); var Tag = DS.Model.extend({ @@ -399,16 +399,16 @@ test("possible to replace items in a relationship using setObjects w/ Ember Enum var env = setupStore({ tag: Tag, person: Person }); var store = env.store; - run(function(){ - store.push('person', { id: 1, name: "Tom Dale", tags: [ 1 ] }); - store.push('person', { id: 2, name: "Sylvain Mina", tags: [ 2 ] }); + run(function() { + store.push('person', { id: 1, name: "Tom Dale", tags: [1] }); + store.push('person', { id: 2, name: "Sylvain Mina", tags: [2] }); store.push('tag', { id: 1, name: "ember" }); store.push('tag', { id: 2, name: "ember-data" }); }); var tom, sylvain; - run(function(){ + run(function() { tom = store.getById('person', '1'); sylvain = store.getById('person', '2'); // Test that since sylvain.get('tags') instanceof DS.ManyArray, @@ -436,18 +436,18 @@ test("it is possible to remove an item from a relationship", function() { var env = setupStore({ tag: Tag, person: Person }), store = env.store; - run(function(){ - store.push('person', { id: 1, name: "Tom Dale", tags: [ 1 ] }); + run(function() { + store.push('person', { id: 1, name: "Tom Dale", tags: [1] }); store.push('tag', { id: 1, name: "ember" }); }); - run(function(){ + run(function() { store.find('person', 1).then(async(function(person) { var tag = get(person, 'tags').objectAt(0); equal(get(tag, 'name'), "ember", "precond - relationships work"); - run(function(){ + run(function() { get(person, 'tags').removeObject(tag); }); @@ -474,7 +474,7 @@ test("it is possible to add an item to a relationship, remove it, then add it ag store = env.store; var person, tag1, tag2, tag3; - run(function(){ + run(function() { person = store.createRecord('person'); tag1 = store.createRecord('tag'); tag2 = store.createRecord('tag'); @@ -483,7 +483,7 @@ test("it is possible to add an item to a relationship, remove it, then add it ag var tags = get(person, 'tags'); - run(function(){ + run(function() { tags.pushObjects([tag1, tag2, tag3]); tags.removeObject(tag2); }); @@ -492,7 +492,7 @@ test("it is possible to add an item to a relationship, remove it, then add it ag equal(tags.objectAt(1), tag3); equal(get(person, 'tags.length'), 2, "object is removed from the relationship"); - run(function(){ + run(function() { tags.insertAt(0, tag2); }); @@ -513,7 +513,7 @@ test("updating the content of a RecordArray updates its content", function() { store = env.store; var records, tags; - run(function(){ + run(function() { records = store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); tags = DS.RecordArray.create({ content: Ember.A(records.slice(0, 2)), store: store, type: Tag }); }); @@ -521,7 +521,7 @@ test("updating the content of a RecordArray updates its content", function() { var tag = tags.objectAt(0); equal(get(tag, 'name'), "friendly", "precond - we're working with the right tags"); - run(function(){ + run(function() { set(tags, 'content', Ember.A(records.slice(1, 3))); }); @@ -545,11 +545,11 @@ test("can create child record from a hasMany relationship", function() { var env = setupStore({ tag: Tag, person: Person }), store = env.store; - run(function(){ - store.push('person', { id: 1, name: "Tom Dale"}); + run(function() { + store.push('person', { id: 1, name: "Tom Dale" }); }); - run(function(){ + run(function() { store.find('person', 1).then(async(function(person) { person.get("tags").createRecord({ name: "cool" }); @@ -580,12 +580,12 @@ test("belongsTo lazily loads relationships as needed", function() { var env = setupStore({ tag: Tag, person: Person }), store = env.store; - run(function(){ + run(function() { store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); store.push('person', { id: 1, name: "Tom Dale", tag: 5 }); }); - run(function(){ + run(function() { store.find('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); @@ -625,11 +625,11 @@ test("async belongsTo relationships work when the data hash has not been loaded" } }; - run(function(){ + run(function() { store.find('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); - return run(function(){ + return run(function() { return get(person, 'tag'); }); })).then(async(function(tag) { @@ -654,15 +654,15 @@ test("async belongsTo relationships work when the data hash has already been loa var env = setupStore({ tag: Tag, person: Person }), store = env.store; - run(function(){ - store.push('tag', { id: 2, name: "friendly"}); - store.push('person', { id: 1, name: "Tom Dale", tag: 2}); + run(function() { + store.push('tag', { id: 2, name: "friendly" }); + store.push('person', { id: 1, name: "Tom Dale", tag: 2 }); }); - run(function(){ + run(function() { store.find('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); - return run(function(){ + return run(function() { return get(person, 'tag'); }); })).then(async(function(tag) { @@ -688,11 +688,11 @@ test("calling createRecord and passing in an undefined value for a relationship var env = setupStore({ tag: Tag, person: Person }), store = env.store; - run(function(){ - store.createRecord('person', {id: 1, tag: undefined}); + run(function() { + store.createRecord('person', { id: 1, tag: undefined }); }); - run(function(){ + run(function() { store.find(Person, 1).then(async(function(person) { strictEqual(person.get('tag'), null, "undefined values should return null relationships"); })); @@ -724,11 +724,11 @@ test("When finding a hasMany relationship the inverse belongsTo relationship is env.adapter.coalesceFindRequests = true; - run(function(){ + run(function() { store.push('person', { id: 1, name: "Tom Dale", occupations: [5, 2] }); }); - run(function(){ + run(function() { store.find('person', 1).then(async(function(person) { equal(get(person, 'isLoaded'), true, "isLoaded should be true"); equal(get(person, 'name'), "Tom Dale", "the person is still Tom Dale"); @@ -768,11 +768,11 @@ test("When finding a belongsTo relationship the inverse belongsTo relationship i return Ember.RSVP.resolve({ id: 5, description: "fifth" }); }; - run(function(){ + run(function() { store.push('person', { id: 1, name: "Tom Dale", occupation: 5 }); }); - run(function(){ + run(function() { store.getById('person', 1).get('occupation'); }); }); @@ -795,12 +795,12 @@ test("belongsTo supports relationships to models with id 0", function() { var env = setupStore({ tag: Tag, person: Person }), store = env.store; - run(function(){ + run(function() { store.pushMany('tag', [{ id: 0, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); store.push('person', { id: 1, name: "Tom Dale", tag: 0 }); }); - run(function(){ + run(function() { store.find('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); diff --git a/packages/ember-data/tests/unit/model/rollback_test.js b/packages/ember-data/tests/unit/model/rollback_test.js index 158f614f6bc..691cf4b03e2 100644 --- a/packages/ember-data/tests/unit/model/rollback_test.js +++ b/packages/ember-data/tests/unit/model/rollback_test.js @@ -15,14 +15,14 @@ module("unit/model/rollback - model.rollback()", { test("changes to attributes can be rolled back", function() { var person; - run(function(){ + run(function() { person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); person.set('firstName', "Thomas"); }); equal(person.get('firstName'), "Thomas"); - run(function(){ + run(function() { person.rollback(); }); @@ -32,14 +32,14 @@ test("changes to attributes can be rolled back", function() { test("changes to unassigned attributes can be rolled back", function() { var person; - run(function(){ + run(function() { person = store.push('person', { id: 1, lastName: "Dale" }); person.set('firstName', "Thomas"); }); equal(person.get('firstName'), "Thomas"); - run(function(){ + run(function() { person.rollback(); }); @@ -50,13 +50,13 @@ test("changes to unassigned attributes can be rolled back", function() { test("changes to attributes made after a record is in-flight only rolls back the local changes", function() { env.adapter.updateRecord = function(store, type, record) { // Make sure the save is async - return new Ember.RSVP.Promise(function(resolve, reject){ + return new Ember.RSVP.Promise(function(resolve, reject) { Ember.run.later(null, resolve, 15); }); }; var person; - run(function(){ + run(function() { person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); person.set('firstName', "Thomas"); }); @@ -88,17 +88,17 @@ test("a record's changes can be made if it fails to save", function() { }; var person; - run(function(){ + run(function() { person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); person.set('firstName', "Thomas"); }); - deepEqual(person.changedAttributes(), {firstName: ["Tom", "Thomas"]}); + deepEqual(person.changedAttributes(), { firstName: ["Tom", "Thomas"] }); - run(function(){ + run(function() { person.save().then(null, function() { equal(person.get('isError'), true); - deepEqual(person.changedAttributes(), {firstName: ["Tom", "Thomas"]}); + deepEqual(person.changedAttributes(), { firstName: ["Tom", "Thomas"] }); person.rollback(); @@ -116,21 +116,21 @@ test("a deleted record can be rollbacked if it fails to save, record arrays are }; var person, people; - run(function(){ + run(function() { person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); people = store.all('person'); }); - run(function(){ + run(function() { person.deleteRecord(); }); equal(people.get('length'), 0, "a deleted record does not appear in record array anymore"); - run(function(){ + run(function() { person.save().then(null, function() { equal(person.get('isError'), true); equal(person.get('isDeleted'), true); - run(function(){ + run(function() { person.rollback(); }); equal(person.get('isDeleted'), false); @@ -144,7 +144,7 @@ test("a deleted record can be rollbacked if it fails to save, record arrays are test("new record can be rollbacked", function() { var person; - run(function(){ + run(function() { person = store.createRecord('person', { id: 1 }); }); @@ -161,7 +161,7 @@ test("new record can be rollbacked", function() { test("deleted record can be rollbacked", function() { var person, people; - run(function(){ + run(function() { person = store.push('person', { id: 1 }); people = store.all('person'); person.deleteRecord(); @@ -171,7 +171,7 @@ test("deleted record can be rollbacked", function() { equal(person.get('isDeleted'), true, "must be deleted"); - run(function(){ + run(function() { person.rollback(); }); equal(people.get('length'), 1, "the rollbacked record should appear again in the record array"); @@ -195,8 +195,8 @@ test("invalid record can be rollbacked", function() { So wrapping the reject in an Ember.run.next makes it so save completes without failure and the failure hits the failure route of the promise instead of crashing the save. */ - Ember.run.next(function(){ - reject(adapter.ajaxError({name: 'is invalid'})); + Ember.run.next(function() { + reject(adapter.ajaxError({ name: 'is invalid' })); }); }); }, @@ -206,14 +206,14 @@ test("invalid record can be rollbacked", function() { } }); - env = setupStore({ dog: Dog, adapter: adapter}); + env = setupStore({ dog: Dog, adapter: adapter }); var dog; - run(function(){ + run(function() { dog = env.store.push('dog', { id: 1, name: "Pluto" }); dog.set('name', "is a dwarf planet"); }); - run(function(){ + run(function() { dog.save().then(null, async(function() { dog.rollback(); @@ -240,8 +240,8 @@ test("invalid record is rolled back to correct state after set", function() { So wrapping the reject in an Ember.run.next makes it so save completes without failure and the failure hits the failure route of the promise instead of crashing the save. */ - Ember.run.next(function(){ - reject(adapter.ajaxError({name: 'is invalid'})); + Ember.run.next(function() { + reject(adapter.ajaxError({ name: 'is invalid' })); }); }); }, @@ -251,27 +251,27 @@ test("invalid record is rolled back to correct state after set", function() { } }); - env = setupStore({ dog: Dog, adapter: adapter}); + env = setupStore({ dog: Dog, adapter: adapter }); var dog; - run(function(){ + run(function() { dog = env.store.push('dog', { id: 1, name: "Pluto", breed: "Disney" }); dog.set('name', "is a dwarf planet"); dog.set('breed', 'planet'); }); - run(function(){ + run(function() { dog.save().then(null, async(function() { equal(dog.get('name'), "is a dwarf planet"); equal(dog.get('breed'), "planet"); - run(function(){ + run(function() { dog.set('name', 'Seymour Asses'); }); equal(dog.get('name'), "Seymour Asses"); equal(dog.get('breed'), "planet"); - run(function(){ + run(function() { dog.rollback(); }); diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index d19a6e83e54..628498f442e 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -15,7 +15,7 @@ module("unit/model - DS.Model", { }, teardown: function() { - run(function(){ + run(function() { store.destroy(); }); Person = null; @@ -25,7 +25,7 @@ module("unit/model - DS.Model", { test("can have a property set on it", function() { var record; - run(function(){ + run(function() { record = store.createRecord(Person); set(record, 'name', 'bar'); }); @@ -36,7 +36,7 @@ test("can have a property set on it", function() { test("setting a property on a record that has not changed does not cause it to become dirty", function() { expect(2); - run(function(){ + run(function() { store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); store.find(Person, 1).then(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); @@ -52,7 +52,7 @@ test("setting a property on a record that has not changed does not cause it to b test("resetting a property on a record cause it to become clean again", function() { expect(3); - run(function(){ + run(function() { store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); store.find(Person, 1).then(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); @@ -67,7 +67,7 @@ test("resetting a property on a record cause it to become clean again", function test("a record becomes clean again only if all changed properties are reset", function() { expect(5); - run(function(){ + run(function() { store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); store.find(Person, 1).then(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); @@ -86,7 +86,7 @@ test("a record becomes clean again only if all changed properties are reset", fu test("a record reports its unique id via the `id` property", function() { expect(1); - run(function(){ + run(function() { store.push(Person, { id: 1 }); store.find(Person, 1).then(function(record) { equal(get(record, 'id'), 1, "reports id as id by default"); @@ -97,7 +97,7 @@ test("a record reports its unique id via the `id` property", function() { test("a record's id is included in its toString representation", function() { expect(1); - run(function(){ + run(function() { store.push(Person, { id: 1 }); store.find(Person, 1).then(function(record) { equal(record.toString(), '<(subclass of DS.Model):'+Ember.guidFor(record)+':1>', "reports id in toString"); @@ -112,7 +112,7 @@ test("trying to set an `id` attribute should raise", function() { }); expectAssertion(function() { - run(function(){ + run(function() { store.push(Person, { id: 1, name: "Scumdale" }); store.find(Person, 1); }); @@ -125,9 +125,9 @@ test("a collision of a record's id with object function's name", function() { var hasWatchMethod = Object.prototype.watch; try { if (!hasWatchMethod) { - Object.prototype.watch = function(){}; + Object.prototype.watch = function() {}; } - run(function(){ + run(function() { store.push(Person, { id: 'watch' }); store.find(Person, 'watch').then(function(record) { equal(get(record, 'id'), 'watch', "record is successfully created and could be found by its id"); @@ -143,7 +143,7 @@ test("a collision of a record's id with object function's name", function() { test("it should use `_reference` and not `reference` to store its reference", function() { expect(1); - run(function(){ + run(function() { store.push(Person, { id: 1 }); store.find(Person, 1).then(function(record) { @@ -164,15 +164,15 @@ test("it should cache attributes", function() { var dateString = "Sat, 31 Dec 2011 00:08:16 GMT"; var date = new Date(dateString); - run(function(){ + run(function() { store.push(Post, { id: 1 }); store.find(Post, 1).then(function(record) { - run(function(){ + run(function() { record.set('updatedAt', date); }); deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); strictEqual(get(record, 'updatedAt'), get(record, 'updatedAt'), "second get still returns the same object"); - }).finally(function(){ + }).finally(function() { run(store, 'destroy'); }); }); @@ -190,19 +190,19 @@ test("changedAttributes() return correct values", function() { var mascot; - run(function(){ + run(function() { mascot = store.push(Mascot, { id: 1, likes: 'JavaScript', isMascot: true }); }); deepEqual({}, mascot.changedAttributes(), 'there are no initial changes'); - run(function(){ + run(function() { mascot.set('name', 'Tomster'); // new value mascot.set('likes', 'Ember.js'); // changed value mascot.set('isMascot', true); // same value }); deepEqual({ name: [undefined, 'Tomster'], likes: ['JavaScript', 'Ember.js'] }, mascot.changedAttributes(), 'attributes has changed'); - run(function(){ + run(function() { mascot.rollback(); }); deepEqual({}, mascot.changedAttributes(), 'after rollback there are no changes'); @@ -214,7 +214,7 @@ test("a DS.Model does not require an attribute type", function() { }); var tag; - run(function(){ + run(function() { tag = store.createRecord(Tag, { name: "test" }); }); @@ -227,7 +227,7 @@ test("a DS.Model can have a defaultValue without an attribute type", function() }); var tag; - run(function(){ + run(function() { tag = store.createRecord(Tag); }); @@ -239,12 +239,12 @@ module("unit/model - DS.Model updating", { array = [{ id: 1, name: "Scumbag Dale" }, { id: 2, name: "Scumbag Katz" }, { id: 3, name: "Scumbag Bryn" }]; Person = DS.Model.extend({ name: DS.attr('string') }); store = createStore(); - run(function(){ + run(function() { store.pushMany(Person, array); }); }, teardown: function() { - run(function(){ + run(function() { store.destroy(); Person = null; store = null; @@ -256,7 +256,7 @@ module("unit/model - DS.Model updating", { test("a DS.Model can update its attributes", function() { expect(1); - run(function(){ + run(function() { store.find(Person, 2).then(function(person) { set(person, 'name', "Brohuda Katz"); equal(get(person, 'name'), "Brohuda Katz", "setting took hold"); @@ -270,13 +270,13 @@ test("a DS.Model can have a defaultValue", function() { }); var tag; - run(function(){ + run(function() { tag = store.createRecord(Tag); }); equal(get(tag, 'name'), "unknown", "the default value is found"); - run(function(){ + run(function() { set(tag, 'name', null); }); @@ -293,7 +293,7 @@ test("a defaultValue for an attribute can be a function", function() { }); var tag; - run(function(){ + run(function() { tag = store.createRecord(Tag); }); equal(get(tag, 'createdAt'), "le default value", "the defaultValue function is evaluated"); @@ -313,7 +313,7 @@ test("a defaultValue function gets the record, options, and key", function() { }); var tag; - run(function(){ + run(function() { tag = store.createRecord(Tag); }); @@ -326,7 +326,7 @@ test("setting a property to undefined on a newly created record should not impac }); var tag; - run(function(){ + run(function() { tag = store.createRecord(Tag); set(tag, 'name', 'testing'); set(tag, 'name', undefined); @@ -334,8 +334,8 @@ test("setting a property to undefined on a newly created record should not impac equal(get(tag, 'currentState.stateName'), "root.loaded.created.uncommitted"); - run(function(){ - tag = store.createRecord(Tag, {name: undefined}); + run(function() { + tag = store.createRecord(Tag, { name: undefined }); }); equal(get(tag, 'currentState.stateName'), "root.loaded.created.uncommitted"); @@ -346,7 +346,7 @@ test("setting a property to undefined on a newly created record should not impac test("setting a property back to its original value removes the property from the `_attributes` hash", function() { expect(3); - run(function(){ + run(function() { store.find(Person, 1).then(function(person) { equal(person._attributes.name, undefined, "the `_attributes` hash is clean"); @@ -374,12 +374,12 @@ module("unit/model - with a simple Person model", { store = createStore({ person: Person }); - run(function(){ + run(function() { store.pushMany(Person, array); }); }, teardown: function() { - run(function(){ + run(function() { store.destroy(); Person = null; store = null; @@ -400,56 +400,56 @@ test("a listener can be added to a record", function() { var F = function() { count++; }; var record; - run(function(){ + run(function() { record = store.createRecord(Person); }); record.on('event!', F); - run(function(){ + run(function() { record.trigger('event!'); }); equal(count, 1, "the event was triggered"); - run(function(){ + run(function() { record.trigger('event!'); }); equal(count, 2, "the event was triggered"); }); -test("when an event is triggered on a record the method with the same name is invoked with arguments", function(){ +test("when an event is triggered on a record the method with the same name is invoked with arguments", function() { var count = 0; var F = function() { count++; }; var record; - run(function(){ + run(function() { record = store.createRecord(Person); }); record.eventNamedMethod = F; - run(function(){ + run(function() { record.trigger('eventNamedMethod'); }); equal(count, 1, "the corresponding method was called"); }); -test("when a method is invoked from an event with the same name the arguments are passed through", function(){ +test("when a method is invoked from an event with the same name the arguments are passed through", function() { var eventMethodArgs = null; var F = function() { eventMethodArgs = arguments; }; var record; - run(function(){ + run(function() { record = store.createRecord(Person); }); record.eventThatTriggersMethod = F; - run(function(){ + run(function() { record.trigger('eventThatTriggersMethod', 1, 2); }); @@ -464,10 +464,10 @@ var converts = function(type, provided, expected) { var container = new Ember.Container(); - var testStore = createStore({model: Model}), + var testStore = createStore({ model: Model }), serializer = DS.JSONSerializer.create({ store: testStore, container: container }); - run(function(){ + run(function() { testStore.push(Model, serializer.normalize(Model, { id: 1, name: provided })); testStore.push(Model, serializer.normalize(Model, { id: 2 })); testStore.find('model', 1).then(function(record) { @@ -488,10 +488,10 @@ var convertsFromServer = function(type, provided, expected) { var container = new Ember.Container(); - var testStore = createStore({model: Model}), + var testStore = createStore({ model: Model }), serializer = DS.JSONSerializer.create({ store: testStore, container: container }); - run(function(){ + run(function() { testStore.push(Model, serializer.normalize(Model, { id: "1", name: provided })); testStore.find('model', 1).then(function(record) { deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); @@ -504,9 +504,9 @@ var convertsWhenSet = function(type, provided, expected) { name: DS.attr(type) }); - var testStore = createStore({model: Model}); + var testStore = createStore({ model: Model }); - run(function(){ + run(function() { testStore.push(Model, { id: 2 }); testStore.find('model', 2).then(function(record) { set(record, 'name', provided); @@ -567,10 +567,10 @@ test("a DS.Model can describe Date attributes", function() { updatedAt: DS.attr('date') }); - run(function(){ + run(function() { store.push(Person, { id: 1 }); store.find(Person, 1).then(function(record) { - run(function(){ + run(function() { record.set('updatedAt', date); }); deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); @@ -580,18 +580,18 @@ test("a DS.Model can describe Date attributes", function() { convertsWhenSet('date', date, dateString); }); -test("don't allow setting", function(){ +test("don't allow setting", function() { var store = createStore(); var Person = DS.Model.extend(); var record; - run(function(){ + run(function() { record = store.createRecord(Person); }); - raises(function(){ - run(function(){ + raises(function() { + run(function() { record.set('isLoaded', true); }); }, "raised error when trying to set an unsettable record"); @@ -608,7 +608,7 @@ test("ensure model exits loading state, materializes data and fulfills promise o }) }); - run(function(){ + run(function() { store.find(Person, 1).then(function(person) { equal(get(person, 'currentState.stateName'), 'root.loaded.saved', 'model is in loaded state'); equal(get(person, 'isLoaded'), true, 'model is loaded'); @@ -624,7 +624,7 @@ test("A DS.Model can be JSONified", function() { var store = createStore({ person: Person }); var record; - run(function(){ + run(function() { record = store.createRecord('person', { name: "TomHuda" }); }); deepEqual(record.toJSON(), { name: "TomHuda" }); @@ -639,7 +639,7 @@ test("A subclass of DS.Model can not use the `data` property", function() { var store = createStore({ person: Person }); expectAssertion(function() { - run(function(){ + run(function() { store.createRecord('person', { name: "TomHuda" }); }); }, /`data` is a reserved property name on DS.Model objects/); diff --git a/packages/ember-data/tests/unit/record_array_test.js b/packages/ember-data/tests/unit/record_array_test.js index efaaf173b42..e701cba0fb3 100644 --- a/packages/ember-data/tests/unit/record_array_test.js +++ b/packages/ember-data/tests/unit/record_array_test.js @@ -17,11 +17,11 @@ test("a record array is backed by records", function() { expect(3); var store = createStore(); - run(function(){ + run(function() { store.pushMany(Person, array); }); - run(function(){ + run(function() { store.findByIds(Person, [1,2,3]).then(function(records) { for (var i=0, l=get(array, 'length'); i Date: Thu, 8 Jan 2015 10:22:52 -0500 Subject: [PATCH 0593/2527] Copy from `emberjs/ember.js/lib/jscs-rules` * Adds additional rules from main project. * Ideally, this project would reference the main project's: * .jshintrc * .jscsrc * lib/jscs-rules * STYLEGUIDE.md --- .jscsrc | 13 ++- ...allow-multiple-var-decl-with-assignment.js | 39 +++++++++ .../disallow-space-before-semicolon.js | 29 +++++++ ...-inside-round-braces-in-call-expression.js | 76 ++++++++++++++++++ ...ing-parenthesis-in-function-declaration.js | 79 +++++++++++++++++++ package.json | 2 +- .../lib/system/active_model_adapter.js | 4 +- .../lib/system/active_model_serializer.js | 14 ++-- .../ember-data/lib/adapters/rest_adapter.js | 8 +- packages/ember-data/lib/ext/date.js | 6 +- .../lib/serializers/json_serializer.js | 3 +- .../lib/system/debug/debug_adapter.js | 6 +- .../ember-data/lib/system/debug/debug_info.js | 6 +- packages/ember-data/lib/system/model/model.js | 4 +- .../ember-data/lib/system/model/states.js | 3 +- .../lib/system/record_array_manager.js | 5 +- .../lib/system/record_arrays/many_array.js | 3 +- packages/ember-data/lib/system/store.js | 6 +- packages/ember-data/lib/transforms/date.js | 10 +-- .../tests/integration/adapter/find_test.js | 2 +- .../adapter/record_persistence_test.js | 7 +- .../integration/adapter/rest_adapter_test.js | 62 +++++++-------- .../integration/adapter/store_adapter_test.js | 27 ++++--- .../tests/integration/application_test.js | 12 +-- .../tests/integration/debug_adapter_test.js | 19 ++--- .../tests/integration/filter_test.js | 13 +-- .../tests/integration/inverse_test.js | 3 +- .../relationships/belongs_to_test.js | 2 +- .../relationships/has_many_test.js | 4 +- .../inverse_relationships_test.js | 32 ++++---- .../relationships/many_to_many_test.js | 3 +- .../relationships/one_to_many_test.js | 4 +- .../relationships/one_to_one_test.js | 3 +- .../embedded_records_mixin_test.js | 3 +- .../serializers/json_serializer_test.js | 4 +- .../tests/integration/setup-container-test.js | 19 +++-- .../tests/unit/model/relationships_test.js | 56 +++++++------ packages/ember-data/tests/unit/model_test.js | 22 +++--- .../tests/unit/record_array_test.js | 32 ++++---- .../tests/unit/store/adapter_interop_test.js | 3 +- .../tests/unit/store/model_for_test.js | 4 +- .../ember-data/tests/unit/store/push_test.js | 13 ++- 42 files changed, 467 insertions(+), 198 deletions(-) create mode 100644 lib/jscs-rules/disallow-multiple-var-decl-with-assignment.js create mode 100644 lib/jscs-rules/disallow-space-before-semicolon.js create mode 100644 lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js create mode 100644 lib/jscs-rules/require-spaces-after-closing-parenthesis-in-function-declaration.js diff --git a/.jscsrc b/.jscsrc index 3463fb333df..a60b40bc2c3 100644 --- a/.jscsrc +++ b/.jscsrc @@ -1,12 +1,13 @@ { "esnext": true, - "excludeFiles": [], - "additionalRules": [], + "additionalRules": [ "lib/jscs-rules/*.js" ], "disallowSpacesInsideArrayBrackets": "all", + "disallowMultipleVarDeclWithAssignment": true, "requireSpaceBeforeObjectValues": true, "requireCommaBeforeLineBreak": true, "requireBlocksOnNewline": 1, "disallowKeywordsOnNewLine": ["else"], + "disallowSpacesBeforeSemicolons": true, "disallowNewlineBeforeBlockStatements": true, "requireSpacesInConditionalExpression": { "afterTest": true, @@ -15,6 +16,7 @@ "beforeAlternate": true }, "disallowSpacesInCallExpression": true, + "disallowSpacesInsideRoundBracesInCallExpression": true, "disallowEmptyBlocks": true, "requireSpacesInsideObjectBrackets": "all", "requireCurlyBraces": [ @@ -48,5 +50,10 @@ "while", "with", "return" - ] + ], + "requireSpaceBetweenArguments": true, + "requireSpacesAfterClosingParenthesisInFunctionDeclaration": { + "beforeOpeningRoundBrace": false, + "beforeOpeningCurlyBrace": true + } } diff --git a/lib/jscs-rules/disallow-multiple-var-decl-with-assignment.js b/lib/jscs-rules/disallow-multiple-var-decl-with-assignment.js new file mode 100644 index 00000000000..838e3e18f3f --- /dev/null +++ b/lib/jscs-rules/disallow-multiple-var-decl-with-assignment.js @@ -0,0 +1,39 @@ +var assert = require('assert'); + +module.exports = function() {}; + +module.exports.prototype = { + configure: function(disallowMultipleVarDeclWithAssignment) { + assert( + typeof disallowMultipleVarDeclWithAssignment === 'boolean', + 'disallowMultipleVarDeclWithAssignment option requires boolean value' + ); + assert( + disallowMultipleVarDeclWithAssignment === true, + 'disallowMultipleVarDeclWithAssignment option requires true value or should be removed' + ); + }, + + getOptionName: function() { + return 'disallowMultipleVarDeclWithAssignment'; + }, + + check: function(file, errors) { + file.iterateNodesByType('VariableDeclaration', function(node) { + // allow multiple var declarations in for statement + // for (var i = 0, j = myArray.length; i < j; i++) {} + if (node.parentNode.type === 'ForStatement') { return; } + + var hasAssignment = false; + var multiDeclaration = node.declarations.length > 1; + + node.declarations.forEach(function(declaration) { + if (declaration.init) { hasAssignment = true; } + }); + + if (hasAssignment && multiDeclaration) { + errors.add('Multiple assigning variable declarations', node.loc.start); + } + }); + } +}; diff --git a/lib/jscs-rules/disallow-space-before-semicolon.js b/lib/jscs-rules/disallow-space-before-semicolon.js new file mode 100644 index 00000000000..85554a87f22 --- /dev/null +++ b/lib/jscs-rules/disallow-space-before-semicolon.js @@ -0,0 +1,29 @@ +var assert = require('assert'); + +module.exports = function() {}; + +module.exports.prototype = { + configure: function(disallowSpacesBeforeSemicolons) { + assert( + typeof disallowSpacesBeforeSemicolons === 'boolean', + 'disallowSpacesBeforeSemicolons option requires boolean value' + ); + assert( + disallowSpacesBeforeSemicolons === true, + 'disallowSpacesBeforeSemicolons option requires true value or should be removed' + ); + }, + + getOptionName: function() { + return 'disallowSpacesBeforeSemicolons'; + }, + + check: function(file, errors) { + var lines = file.getLines(); + for (var i = 0, l = lines.length; i < l; i++) { + if (lines[i].match(/\s+;$/)) { + errors.add('Spaces are disallowed before semicolons.', i + 1, lines[i].length - 2); + } + } + } +}; diff --git a/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js b/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js new file mode 100644 index 00000000000..3685932f017 --- /dev/null +++ b/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js @@ -0,0 +1,76 @@ +var assert = require('assert'); + +function spaceAfterBrace(arg, braceToken) { + if (arg) { + var supportedArgs = arg.type !== 'UnaryExpression' && arg.type !== 'BinaryExpression'; + + return supportedArgs && braceToken.value === '(' && braceToken.range[1] + 1 === arg.range[0]; + } + + return false; +} + +function spaceBeforeBrace(arg, braceToken) { + if (arg) { + var supportedArgs = arg.type !== 'UnaryExpression' && arg.type !== 'BinaryExpression'; + + return supportedArgs && braceToken.value === ')' && braceToken.range[0] === arg.range[1] + 1; + } + + return false; +} + +module.exports = function() {}; + +module.exports.prototype = { + configure: function(requireSpacesInsideRoundBracesInCallExpression) { + assert( + requireSpacesInsideRoundBracesInCallExpression === true, + 'disallowSpacesInsideRoundBracesInCallExpression option requires true value or should be removed' + ); + }, + + getOptionName: function() { + return 'disallowSpacesInsideRoundBracesInCallExpression'; + }, + + check: function(file, errors) { + var tokens = file.getTokens(); + + file.iterateNodesByType('CallExpression', function(node) { + var nodeBeforeRoundBrace = node; + + if (node.callee) { + nodeBeforeRoundBrace = node.callee; + } + + var roundBraceTokenStart = file.getTokenByRangeStart(nodeBeforeRoundBrace.range[0]); + var roundBraceTokenEnd = file.getTokenByRangeStart(nodeBeforeRoundBrace.range[0]); + + do { + roundBraceTokenStart = file.findNextToken(roundBraceTokenStart, 'Punctuator', '('); + roundBraceTokenEnd = file.findNextToken(roundBraceTokenEnd, 'Punctuator', ')'); + } while (roundBraceTokenStart.range[0] < nodeBeforeRoundBrace.range[1]); + + var firstArg = nodeBeforeRoundBrace.parentNode.arguments[0]; + var lastArg = nodeBeforeRoundBrace.parentNode.arguments[nodeBeforeRoundBrace.parentNode.arguments.length - 1]; + + var spaceAfterOpeningRoundBraceExists = spaceAfterBrace(firstArg, roundBraceTokenStart); + var spaceBeforeClosingRoundBraceExists = spaceBeforeBrace(lastArg, roundBraceTokenEnd); + + if (spaceAfterOpeningRoundBraceExists) { + errors.add( + 'Illegal space after opening round brace', + roundBraceTokenStart.loc.start + ); + } + + if (spaceBeforeClosingRoundBraceExists) { + errors.add( + 'Illegal space before closing round brace', + roundBraceTokenEnd.loc.start + ); + } + }); + } +}; diff --git a/lib/jscs-rules/require-spaces-after-closing-parenthesis-in-function-declaration.js b/lib/jscs-rules/require-spaces-after-closing-parenthesis-in-function-declaration.js new file mode 100644 index 00000000000..8ead028da71 --- /dev/null +++ b/lib/jscs-rules/require-spaces-after-closing-parenthesis-in-function-declaration.js @@ -0,0 +1,79 @@ +var assert = require('assert'); + +module.exports = function() {}; + +module.exports.prototype = { + configure: function(options) { + assert( + typeof options === 'object', + 'requireSpacesAfterClosingParenthesisInFunctionDeclaration option must be the object' + ); + + assert( + options.beforeOpeningCurlyBrace || options.beforeOpeningRoundBrace, + 'requireSpacesAfterClosingParenthesisInFunctionDeclaration must have beforeOpeningCurlyBrace or beforeOpeningRoundBrace property' + ); + + this._beforeOpeningRoundBrace = Boolean(options.beforeOpeningRoundBrace); + this._beforeOpeningCurlyBrace = Boolean(options.beforeOpeningCurlyBrace); + }, + + getOptionName: function() { + return 'requireSpacesAfterClosingParenthesisInFunctionDeclaration'; + }, + + check: function(file, errors) { + var beforeOpeningRoundBrace = this._beforeOpeningRoundBrace; + var beforeOpeningCurlyBrace = this._beforeOpeningCurlyBrace; + var tokens = file.getTokens(); + + file.iterateNodesByType(['FunctionDeclaration'], function(node) { + var nodeBeforeRoundBrace = node; + // named function + if (node.id) { + nodeBeforeRoundBrace = node.id; + } + + var functionTokenPos = file.getTokenPosByRangeStart(nodeBeforeRoundBrace.range[0]); + var functionToken = tokens[functionTokenPos]; + + var nextTokenPos = file.getTokenPosByRangeStart(functionToken.range[1]); + var nextToken = tokens[nextTokenPos]; + + if (beforeOpeningRoundBrace) { + if (nextToken) { + errors.add( + 'Missing space before opening round brace', + nextToken.loc.start + ); + } + } else { + if (!nextToken) { + errors.add( + 'Illegal space before opening round brace', + functionToken.loc.end + ); + } + } + + var tokenBeforeBodyPos = file.getTokenPosByRangeStart(node.body.range[0] - 1); + var tokenBeforeBody = tokens[tokenBeforeBodyPos]; + + if (beforeOpeningCurlyBrace) { + if (tokenBeforeBody) { + errors.add( + 'Missing space before opening curly brace', + tokenBeforeBody.loc.start + ); + } + } else { + if (!tokenBeforeBody) { + errors.add( + 'Illegal space before opening curly brace', + node.body.loc.end + ); + } + } + }); + } +}; diff --git a/package.json b/package.json index e6d2d50a890..3430a92353d 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,6 @@ "yuidocjs": "~0.3.46" }, "dependencies": { - "broccoli-jscs": "0.0.13" + "broccoli-jscs": "0.0.12" } } diff --git a/packages/activemodel-adapter/lib/system/active_model_adapter.js b/packages/activemodel-adapter/lib/system/active_model_adapter.js index 15f5d88cd93..cc7360d735a 100644 --- a/packages/activemodel-adapter/lib/system/active_model_adapter.js +++ b/packages/activemodel-adapter/lib/system/active_model_adapter.js @@ -6,8 +6,8 @@ import {pluralize} from "ember-inflector"; @module ember-data */ -var decamelize = Ember.String.decamelize, - underscore = Ember.String.underscore; +var decamelize = Ember.String.decamelize; +var underscore = Ember.String.underscore; /** The ActiveModelAdapter is a subclass of the RESTAdapter designed to integrate diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index 3602bec6ae5..bee4f5b6644 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -1,15 +1,15 @@ -import {singularize} from "ember-inflector"; +import { singularize } from "ember-inflector"; import RESTSerializer from "ember-data/serializers/rest_serializer"; /** @module ember-data */ -var get = Ember.get, - forEach = Ember.EnumerableUtils.forEach, - camelize = Ember.String.camelize, - capitalize = Ember.String.capitalize, - decamelize = Ember.String.decamelize, - underscore = Ember.String.underscore; +var get = Ember.get; +var forEach = Ember.EnumerableUtils.forEach; +var camelize = Ember.String.camelize; +var capitalize = Ember.String.capitalize; +var decamelize = Ember.String.decamelize; +var underscore = Ember.String.underscore; /** The ActiveModelSerializer is a subclass of the RESTSerializer designed to integrate with a JSON API that uses an underscored naming convention instead of camelCasing. diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 70cd10f89a0..b920c00e1d0 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -530,9 +530,9 @@ export default Adapter.extend({ @return {String} url */ buildURL: function(type, id, record) { - var url = [], - host = get(this, 'host'), - prefix = this.urlPrefix(); + var url = []; + var host = get(this, 'host'); + var prefix = this.urlPrefix(); if (type) { url.push(this.pathForType(type)); } @@ -590,7 +590,7 @@ export default Adapter.extend({ var expandedURL = url.split('/'); //Case when the url is of the format ...something/:id - var lastSegment = expandedURL[ expandedURL.length - 1 ]; + var lastSegment = expandedURL[expandedURL.length - 1]; var id = record.get('id'); if (lastSegment === id) { expandedURL[expandedURL.length - 1] = ""; diff --git a/packages/ember-data/lib/ext/date.js b/packages/ember-data/lib/ext/date.js index c8f48afbed6..05475976adc 100644 --- a/packages/ember-data/lib/ext/date.js +++ b/packages/ember-data/lib/ext/date.js @@ -15,7 +15,8 @@ */ Ember.Date = Ember.Date || {}; -var origParse = Date.parse, numericKeys = [1, 4, 5, 6, 7, 10, 11]; +var origParse = Date.parse; +var numericKeys = [1, 4, 5, 6, 7, 10, 11]; /** @method parse @@ -23,7 +24,8 @@ var origParse = Date.parse, numericKeys = [1, 4, 5, 6, 7, 10, 11]; @return {Number} timestamp */ Ember.Date.parse = function (date) { - var timestamp, struct, minutesOffset = 0; + var timestamp, struct; + var minutesOffset = 0; // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string // before falling back to any implementation-specific date parsing, so that’s what we do, even if native diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 87f9bdc1596..56dbccfcc9a 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -232,7 +232,8 @@ export default Ember.Object.extend({ @private */ normalizeUsingDeclaredMapping: function(type, hash) { - var attrs = get(this, 'attrs'), payloadKey, key; + var attrs = get(this, 'attrs'); + var payloadKey, key; if (attrs) { for (key in attrs) { diff --git a/packages/ember-data/lib/system/debug/debug_adapter.js b/packages/ember-data/lib/system/debug/debug_adapter.js index b7be35bcd6e..5c8acb10efa 100644 --- a/packages/ember-data/lib/system/debug/debug_adapter.js +++ b/packages/ember-data/lib/system/debug/debug_adapter.js @@ -47,7 +47,8 @@ export default Ember.DataAdapter.extend({ }, getRecordColumnValues: function(record) { - var self = this, count = 0; + var self = this; + var count = 0; var columnValues = { id: get(record, 'id') }; record.eachAttribute(function(key) { @@ -91,7 +92,8 @@ export default Ember.DataAdapter.extend({ }, observeRecord: function(record, recordUpdated) { - var releaseMethods = Ember.A(), self = this; + var releaseMethods = Ember.A(); + var self = this; var keysToObserve = Ember.A(['id', 'isNew', 'isDirty']); record.eachAttribute(function(key) { diff --git a/packages/ember-data/lib/system/debug/debug_info.js b/packages/ember-data/lib/system/debug/debug_info.js index f1699eca5a3..98163f919b1 100644 --- a/packages/ember-data/lib/system/debug/debug_info.js +++ b/packages/ember-data/lib/system/debug/debug_info.js @@ -19,9 +19,9 @@ Model.reopen({ @private */ _debugInfo: function() { - var attributes = ['id'], - relationships = { belongsTo: [], hasMany: [] }, - expensiveProperties = []; + var attributes = ['id']; + var relationships = { belongsTo: [], hasMany: [] }; + var expensiveProperties = []; this.eachAttribute(function(name, meta) { attributes.push(name); diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index e9ff97a41b0..450eafe8c1a 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -543,7 +543,9 @@ var Model = Ember.Object.extend(Ember.Evented, { } while (!state.hasOwnProperty(pivotName)); var path = splitOnDot(name); - var setups = [], enters = [], i, l; + var setups = []; + var enters = []; + var i, l; for (i=0, l=path.length; i Date: Fri, 23 Jan 2015 00:44:14 +0100 Subject: [PATCH 0594/2527] Update JSBin link - Version 1 was missing ember-template-compiler.js which caused it to error out - Link to the latest version --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e017efc82d4..21e9ef13ae2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,7 @@ demo should be fully operational with the exception of the bug you want to demonstrate. The more pared down, the better. A preconfigured [JSBin][1] | [JSFiddle][2] with mocked requests is available. -[1]: http://emberjs.jsbin.com/qovara/1/edit?html,js,output +[1]: http://emberjs.jsbin.com/qovara/edit?html,js,output [2]: http://jsfiddle.net/842xesgc/ 4. If possible, submit a Pull Request with a failing test. Better yet, take From 76845d331e313fa0863340169682d3b788f654bd Mon Sep 17 00:00:00 2001 From: bmac Date: Sat, 24 Jan 2015 12:30:03 -0500 Subject: [PATCH 0595/2527] Improve error docs based on feedback in issue #2028 --- packages/ember-data/lib/system/adapter.js | 8 ++--- .../ember-data/lib/system/model/errors.js | 33 +++++++++++-------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 6c8a9e5cbfa..d725668131b 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -45,13 +45,13 @@ var errorProps = [ ``` The `DS.InvalidError` must be constructed with a single object whose - keys are the invalid model properties, and whose values are the - corresponding error messages. For example: + keys are the invalid model properties, and whose values contain + arrays of the corresponding error messages. For example: ```javascript return new DS.InvalidError({ - length: 'Must be less than 15', - name: 'Must not be blank' + length: ['Must be less than 15'], + name: ['Must not be blank'] }); ``` diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index ddbbbe9c827..e39527e6bc9 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -43,34 +43,41 @@ import { ```javascript { - "errors": { - "username": ["This username is already taken!"], - "email": ["Doesn't look like a valid email."] - } + "username": ["This username is already taken!"], + "email": ["Doesn't look like a valid email."] } ``` Errors can be displayed to the user by accessing their property name - or using the `messages` property to get an array of all errors. + to get an array of all the error objects for that property. Each + error object is a JavaScript object with two keys: + + - `message` A string containing the error message from the backend + - `attribute` The name of the property associated with this error message ```handlebars - {{#each message in errors.messages}} + + {{#each error in model.errors.username}}
      - {{message}} + {{error.message}}
      {{/each}} - - {{#each error in errors.username}} + + {{#each error in model.errors.email}}
      {{error.message}}
      {{/each}} + ``` - - {{#each error in errors.email}} + You can also access the special `messages` property on the error + object to get an array of all the error strings. + + ```handlebars + {{#each message in model.errors.messages}}
      - {{error.message}} + {{message}}
      {{/each}} ``` @@ -149,7 +156,7 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { record. This is useful for displaying all errors to the user. ```handlebars - {{#each message in errors.messages}} + {{#each message in model.errors.messages}}
      {{message}}
      From 4acb9a606c0018e64f45da8806c4d5554318256a Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 20 Jan 2015 15:47:32 -0500 Subject: [PATCH 0596/2527] Do not double include the host when it uses a protocol relative url. Closes #2714 --- .../ember-data/lib/adapters/rest_adapter.js | 10 +++++++-- .../integration/adapter/rest_adapter_test.js | 21 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index b920c00e1d0..807839c64f0 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -562,8 +562,15 @@ export default Adapter.extend({ var url = []; if (path) { + // Protocol relative url + //jscs:disable disallowEmptyBlocks + if (/^\/\//.test(path)) { + // Do nothing, the full host is already included. This branch + // avoids the absolute path logic and the relative path logic. + // Absolute path - if (path.charAt(0) === '/') { + } else if (path.charAt(0) === '/') { + //jscs:enable disallowEmptyBlocks if (host) { path = path.slice(1); url.push(host); @@ -872,4 +879,3 @@ function endsWith(string, suffix) { return string.endsWith(suffix); } } - diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 877aeb5d314..4982f64f9a1 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -1297,6 +1297,27 @@ test('buildURL - with absolute paths in links', function() { })); }); + +test('buildURL - with absolute paths in links and protocol relative host', function() { + run(function() { + adapter.setProperties({ + host: '//example.com', + namespace: 'api/v1' + }); + }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + Comment.reopen({ post: DS.belongsTo('post') }); + + ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); + + run(store, 'find', 'post', 1).then(async(function(post) { + ajaxResponse({ comments: [{ id: 1 }] }); + return post.get('comments'); + })).then(async(function (comments) { + equal(passedUrl, "//example.com/api/v1/posts/1/comments"); + })); +}); + test('buildURL - with full URLs in links', function() { adapter.setProperties({ host: 'http://example.com', From 3e54958366deee242e1bcb7737fe177ad062a564 Mon Sep 17 00:00:00 2001 From: Omar Ismail Date: Sat, 24 Jan 2015 08:50:47 -0500 Subject: [PATCH 0597/2527] add documentation for the Store's find method --- packages/ember-data/lib/system/store.js | 34 ++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 2c8ada606a9..ab296dbd306 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -440,9 +440,37 @@ Store = Ember.Object.extend({ store.find('person', { page: 1 }); ``` - This will ask the adapter's `findQuery` method to find the records for - the query, and return a promise that will be resolved once the server - responds. + By passing an object `{page: 1}` as an argument to the find method, it + delegates to the adapter's findQuery method. The adapter then makes + a call to the server, transforming the object `{page: 1}` as parameters + that are sent along, and will return a RecordArray when the promise + resolves. + + Exposing queries this way seems preferable to creating an abstract query + language for all server-side queries, and then require all adapters to + implement them. + + The call made to the server, using a Rails backend, will look something like this: + + ``` + Started GET "/api/v1/person?page=1" + Processing by Api::V1::PersonsController#index as HTML + Parameters: {"page"=>"1"} + ``` + + If you do something like this: + + ```javascript + store.find('person', {ids: [1, 2, 3]}); + ``` + + The call to the server, using a Rails backend, will look something like this: + + ``` + Started GET "/api/v1/person?ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3" + Processing by Api::V1::PersonsController#index as HTML + Parameters: {"ids"=>["1", "2", "3"]} + ``` @method find @param {String or subclass of DS.Model} type From 81282f7c76b10877f03f35ab2caa595ea868df5f Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 25 Jan 2015 12:43:42 +0100 Subject: [PATCH 0598/2527] [DOCS]Update about defining application's store Previously, when you've defined store, like outdated documentation suggested: ~~~~ MyApp.Store = DS.Store.extend(); ~~~~ It raised deprecation warning: ~~~~ DEPRECATION: Specifying a custom Store for Ember Data on your global namespace as `App.Store` has been deprecated. Please use `App.ApplicationStore` instead. at ember$data$lib$initializers$store$$initializeStore (http://builds.emberjs.com/canary/ember-data.js:10308:13) at ember$data$lib$setup$container$$setupContainer (http://builds.emberjs.com/canary/ember-data.js:10621:7) at http://builds.emberjs.com/tags/v1.9.1/ember.js:3079:11 at visit (http://builds.emberjs.com/tags/v1.9.1/ember.js:2002:7) at visit (http://builds.emberjs.com/tags/v1.9.1/ember.js:2000:9) at DAG.topsort (http://builds.emberjs.com/tags/v1.9.1/ember.js:2114:11) at Namespace.extend.runInitializers (http://builds.emberjs.com/tags/v1.9.1/ember.js:3076:15) at Namespace.extend._initialize (http://builds.emberjs.com/tags/v1.9.1/ember.js:2961:14) at Object.Backburner.run (http://builds.emberjs.com/tags/v1.9.1/ember.js:194:27) ~~~~ This is the correct way: ~~~~ MyApp.ApplicationStore = DS.Store.extend(); ~~~~ And this should be in docs. --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index ab296dbd306..0e22f3780d1 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -113,7 +113,7 @@ function coerceId(id) { Define your application's store like this: ```javascript - MyApp.Store = DS.Store.extend(); + MyApp.ApplicationStore = DS.Store.extend(); ``` Most Ember.js applications will only have a single `DS.Store` that is From b07770f5a445894d67121585f49bbc0464da2dc2 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Mon, 26 Jan 2015 11:06:57 -0500 Subject: [PATCH 0599/2527] Split Relationship Tests into Separate Files Multiple `Qunit.modules` lacking shared setup should live in separate files. --- .../model/relationships/belongs_to_test.js | 255 ++++++ .../unit/model/relationships/has_many_test.js | 468 +++++++++++ .../model/relationships/record_array_test.js | 62 ++ .../tests/unit/model/relationships_test.js | 775 ------------------ 4 files changed, 785 insertions(+), 775 deletions(-) create mode 100644 packages/ember-data/tests/unit/model/relationships/belongs_to_test.js create mode 100644 packages/ember-data/tests/unit/model/relationships/has_many_test.js create mode 100644 packages/ember-data/tests/unit/model/relationships/record_array_test.js diff --git a/packages/ember-data/tests/unit/model/relationships/belongs_to_test.js b/packages/ember-data/tests/unit/model/relationships/belongs_to_test.js new file mode 100644 index 00000000000..3fe81534a09 --- /dev/null +++ b/packages/ember-data/tests/unit/model/relationships/belongs_to_test.js @@ -0,0 +1,255 @@ +var get = Ember.get; +var run = Ember.run; + +module("unit/model/relationships - DS.belongsTo"); + +test("belongsTo lazily loads relationships as needed", function() { + expect(5); + + var Tag = DS.Model.extend({ + name: DS.attr('string'), + people: DS.hasMany('person') + }); + Tag.toString = function() { return "Tag"; }; + + var Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag') + }); + Person.toString = function() { return "Person"; }; + + var env = setupStore({ tag: Tag, person: Person }); + var store = env.store; + + run(function() { + store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); + store.push('person', { id: 1, name: "Tom Dale", tag: 5 }); + }); + + run(function() { + store.find('person', 1).then(async(function(person) { + equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + + equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); + equal(get(person, 'tag.name'), "friendly", "the tag shuld have name"); + + strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); + asyncEqual(get(person, 'tag'), store.find('tag', 5), "relationship object is the same as object retrieved directly"); + })); + }); +}); + +test("async belongsTo relationships work when the data hash has not been loaded", function() { + expect(5); + + var Tag = DS.Model.extend({ + name: DS.attr('string') + }); + + var Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: true }) + }); + + var env = setupStore({ tag: Tag, person: Person }); + var store = env.store; + + env.adapter.find = function(store, type, id) { + if (type === Person) { + equal(id, 1, "id should be 1"); + + return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", tag: 2 }); + } else if (type === Tag) { + equal(id, 2, "id should be 2"); + + return Ember.RSVP.resolve({ id: 2, name: "friendly" }); + } + }; + + run(function() { + store.find('person', 1).then(async(function(person) { + equal(get(person, 'name'), "Tom Dale", "The person is now populated"); + + return run(function() { + return get(person, 'tag'); + }); + })).then(async(function(tag) { + equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); + equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); + })); + }); +}); + +test("async belongsTo relationships work when the data hash has already been loaded", function() { + expect(3); + + var Tag = DS.Model.extend({ + name: DS.attr('string') + }); + + var Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: true }) + }); + + var env = setupStore({ tag: Tag, person: Person }); + var store = env.store; + + run(function() { + store.push('tag', { id: 2, name: "friendly" }); + store.push('person', { id: 1, name: "Tom Dale", tag: 2 }); + }); + + run(function() { + store.find('person', 1).then(async(function(person) { + equal(get(person, 'name'), "Tom Dale", "The person is now populated"); + return run(function() { + return get(person, 'tag'); + }); + })).then(async(function(tag) { + equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); + equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); + })); + }); +}); + +test("calling createRecord and passing in an undefined value for a relationship should be treated as if null", function () { + expect(1); + + var Tag = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person') + }); + + var Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag') + }); + + var env = setupStore({ tag: Tag, person: Person }); + var store = env.store; + + run(function() { + store.createRecord('person', { id: 1, tag: undefined }); + }); + + run(function() { + store.find(Person, 1).then(async(function(person) { + strictEqual(person.get('tag'), null, "undefined values should return null relationships"); + })); + }); +}); + +test("When finding a hasMany relationship the inverse belongsTo relationship is available immediately", function() { + var Occupation = DS.Model.extend({ + description: DS.attr('string'), + person: DS.belongsTo('person') + }); + + Occupation.toString = function() { return "Occupation"; }; + + var Person = DS.Model.extend({ + name: DS.attr('string'), + occupations: DS.hasMany('occupation', { async: true }) + }); + + Person.toString = function() { return "Person"; }; + + var env = setupStore({ occupation: Occupation, person: Person }); + var store = env.store; + + env.adapter.findMany = function(store, type, ids, records) { + equal(records[0].get('person.id'), '1'); + return Ember.RSVP.resolve([{ id: 5, description: "fifth" }, { id: 2, description: "second" }]); + }; + + env.adapter.coalesceFindRequests = true; + + run(function() { + store.push('person', { id: 1, name: "Tom Dale", occupations: [5, 2] }); + }); + + run(function() { + store.find('person', 1).then(async(function(person) { + equal(get(person, 'isLoaded'), true, "isLoaded should be true"); + equal(get(person, 'name'), "Tom Dale", "the person is still Tom Dale"); + + return get(person, 'occupations'); + })).then(async(function(occupations) { + equal(get(occupations, 'length'), 2, "the list of occupations should have the correct length"); + + equal(get(occupations.objectAt(0), 'description'), "fifth", "the occupation is the fifth"); + equal(get(occupations.objectAt(0), 'isLoaded'), true, "the occupation is now loaded"); + })); + }); +}); + +test("When finding a belongsTo relationship the inverse belongsTo relationship is available immediately", function() { + expect(1); + + var Occupation = DS.Model.extend({ + description: DS.attr('string'), + person: DS.belongsTo('person') + }); + + Occupation.toString = function() { return "Occupation"; }; + + var Person = DS.Model.extend({ + name: DS.attr('string'), + occupation: DS.belongsTo('occupation', { async: true }) + }); + + Person.toString = function() { return "Person"; }; + + var env = setupStore({ occupation: Occupation, person: Person }); + var store = env.store; + + env.adapter.find = function(store, type, id, record) { + equal(record.get('person.id'), '1'); + return Ember.RSVP.resolve({ id: 5, description: "fifth" }); + }; + + run(function() { + store.push('person', { id: 1, name: "Tom Dale", occupation: 5 }); + }); + + run(function() { + store.getById('person', 1).get('occupation'); + }); +}); + +test("belongsTo supports relationships to models with id 0", function() { + expect(5); + + var Tag = DS.Model.extend({ + name: DS.attr('string'), + people: DS.hasMany('person') + }); + Tag.toString = function() { return "Tag"; }; + + var Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag') + }); + Person.toString = function() { return "Person"; }; + + var env = setupStore({ tag: Tag, person: Person }); + var store = env.store; + + run(function() { + store.pushMany('tag', [{ id: 0, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); + store.push('person', { id: 1, name: "Tom Dale", tag: 0 }); + }); + + run(function() { + store.find('person', 1).then(async(function(person) { + equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + + equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); + equal(get(person, 'tag.name'), "friendly", "the tag should have name"); + + strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); + asyncEqual(get(person, 'tag'), store.find(Tag, 0), "relationship object is the same as object retrieved directly"); + })); + }); +}); diff --git a/packages/ember-data/tests/unit/model/relationships/has_many_test.js b/packages/ember-data/tests/unit/model/relationships/has_many_test.js new file mode 100644 index 00000000000..ab5e02fb788 --- /dev/null +++ b/packages/ember-data/tests/unit/model/relationships/has_many_test.js @@ -0,0 +1,468 @@ +var get = Ember.get; +var run = Ember.run; +var env; + +module("unit/model/relationships - DS.hasMany", { + setup: function() { + env = setupStore(); + } +}); + +test("hasMany handles pre-loaded relationships", function() { + expect(13); + + var Tag = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person') + }); + + var Pet = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person') + }); + + var Person = DS.Model.extend({ + name: DS.attr('string'), + tags: DS.hasMany('tag'), + pets: DS.hasMany('pet') + }); + + env.container.register('model:tag', Tag); + env.container.register('model:pet', Pet); + env.container.register('model:person', Person); + + env.adapter.find = function(store, type, id) { + if (type === Tag && id === '12') { + return Ember.RSVP.resolve({ id: 12, name: "oohlala" }); + } else { + ok(false, "find() should not be called with these values"); + } + }; + + var store = env.store; + + run(function() { + store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); + store.pushMany('pet', [{ id: 4, name: "fluffy" }, { id: 7, name: "snowy" }, { id: 12, name: "cerberus" }]); + store.push('person', { id: 1, name: "Tom Dale", tags: [5] }); + store.push('person', { id: 2, name: "Yehuda Katz", tags: [12] }); + }); + + run(function() { + store.find('person', 1).then(function(person) { + equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + + var tags = get(person, 'tags'); + equal(get(tags, 'length'), 1, "the list of tags should have the correct length"); + equal(get(tags.objectAt(0), 'name'), "friendly", "the first tag should be a Tag"); + + run(function() { + store.push('person', { id: 1, name: "Tom Dale", tags: [5, 2] }); + }); + + equal(tags, get(person, 'tags'), "a relationship returns the same object every time"); + equal(get(get(person, 'tags'), 'length'), 2, "the length is updated after new data is loaded"); + + strictEqual(get(person, 'tags').objectAt(0), get(person, 'tags').objectAt(0), "the returned object is always the same"); + asyncEqual(get(person, 'tags').objectAt(0), store.find(Tag, 5), "relationship objects are the same as objects retrieved directly"); + + run(function() { + store.push('person', { id: 3, name: "KSelden" }); + }); + + return store.find('person', 3); + }).then(function(kselden) { + equal(get(get(kselden, 'tags'), 'length'), 0, "a relationship that has not been supplied returns an empty array"); + + run(function() { + store.push('person', { id: 4, name: "Cyvid Hamluck", pets: [4] }); + }); + return store.find('person', 4); + }).then(function(cyvid) { + equal(get(cyvid, 'name'), "Cyvid Hamluck", "precond - retrieves person record from store"); + + var pets = get(cyvid, 'pets'); + equal(get(pets, 'length'), 1, "the list of pets should have the correct length"); + equal(get(pets.objectAt(0), 'name'), "fluffy", "the first pet should be correct"); + + run(function() { + store.push(Person, { id: 4, name: "Cyvid Hamluck", pets: [4, 12] }); + }); + + equal(pets, get(cyvid, 'pets'), "a relationship returns the same object every time"); + equal(get(get(cyvid, 'pets'), 'length'), 2, "the length is updated after new data is loaded"); + }); + }); +}); + +test("hasMany lazily loads async relationships", function() { + expect(5); + + var Tag = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person') + }); + + var Pet = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person') + }); + + var Person = DS.Model.extend({ + name: DS.attr('string'), + tags: DS.hasMany('tag', { async: true }), + pets: DS.hasMany('pet') + }); + + env.container.register('model:tag', Tag); + env.container.register('model:pet', Pet); + env.container.register('model:person', Person); + + env.adapter.find = function(store, type, id) { + if (type === Tag && id === '12') { + return Ember.RSVP.resolve({ id: 12, name: "oohlala" }); + } else { + ok(false, "find() should not be called with these values"); + } + }; + + var store = env.store; + + run(function() { + store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); + store.pushMany('pet', [{ id: 4, name: "fluffy" }, { id: 7, name: "snowy" }, { id: 12, name: "cerberus" }]); + store.push('person', { id: 1, name: "Tom Dale", tags: [5] }); + store.push('person', { id: 2, name: "Yehuda Katz", tags: [12] }); + }); + + var wycats; + + run(function() { + store.find('person', 2).then(function(person) { + wycats = person; + + equal(get(wycats, 'name'), "Yehuda Katz", "precond - retrieves person record from store"); + + return Ember.RSVP.hash({ + wycats: wycats, + tags: wycats.get('tags') + }); + }).then(function(records) { + equal(get(records.tags, 'length'), 1, "the list of tags should have the correct length"); + equal(get(records.tags.objectAt(0), 'name'), "oohlala", "the first tag should be a Tag"); + + strictEqual(records.tags.objectAt(0), records.tags.objectAt(0), "the returned object is always the same"); + asyncEqual(records.tags.objectAt(0), store.find(Tag, 12), "relationship objects are the same as objects retrieved directly"); + + return get(wycats, 'tags'); + }).then(function(tags) { + var newTag; + run(function() { + newTag = store.createRecord(Tag); + tags.pushObject(newTag); + }); + }); + }); +}); + +test("should be able to retrieve the type for a hasMany relationship without specifying a type from its metadata", function() { + var Tag = DS.Model.extend({}); + + var Person = DS.Model.extend({ + tags: DS.hasMany() + }); + + var env = setupStore({ + tag: Tag, + person: Person + }); + + equal(env.store.modelFor('person').typeForRelationship('tags'), Tag, "returns the relationship type"); +}); + +test("should be able to retrieve the type for a hasMany relationship specified using a string from its metadata", function() { + var Tag = DS.Model.extend({}); + + var Person = DS.Model.extend({ + tags: DS.hasMany('tag') + }); + + var env = setupStore({ + tag: Tag, + person: Person + }); + + equal(env.store.modelFor('person').typeForRelationship('tags'), Tag, "returns the relationship type"); +}); + +test("should be able to retrieve the type for a belongsTo relationship without specifying a type from its metadata", function() { + var Tag = DS.Model.extend({}); + + var Person = DS.Model.extend({ + tag: DS.belongsTo() + }); + + var env = setupStore({ + tag: Tag, + person: Person + }); + + equal(env.store.modelFor('person').typeForRelationship('tag'), Tag, "returns the relationship type"); +}); + +test("should be able to retrieve the type for a belongsTo relationship specified using a string from its metadata", function() { + var Tag = DS.Model.extend({ + name: DS.attr('string') + }); + + var Person = DS.Model.extend({ + tags: DS.belongsTo('tag') + }); + + var env = setupStore({ + tag: Tag, + person: Person + }); + + equal(env.store.modelFor('person').typeForRelationship('tags'), Tag, "returns the relationship type"); +}); + +test("relationships work when declared with a string path", function() { + expect(2); + + window.App = {}; + + var Person = DS.Model.extend({ + name: DS.attr('string'), + tags: DS.hasMany('tag') + }); + + var Tag = DS.Model.extend({ + name: DS.attr('string') + }); + + var env = setupStore({ + person: Person, + tag: Tag + }); + + run(function() { + env.store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); + env.store.push('person', { id: 1, name: "Tom Dale", tags: [5, 2] }); + }); + + run(function() { + env.store.find('person', 1).then(function(person) { + equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + equal(get(person, 'tags.length'), 2, "the list of tags should have the correct length"); + }); + }); +}); + +test("hasMany relationships work when the data hash has not been loaded", function() { + expect(8); + + var Tag = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person') + }); + + Tag.toString = function() { return "Tag"; }; + + var Person = DS.Model.extend({ + name: DS.attr('string'), + tags: DS.hasMany('tag', { async: true }) + }); + + Person.toString = function() { return "Person"; }; + + var env = setupStore({ tag: Tag, person: Person }); + var store = env.store; + + env.adapter.coalesceFindRequests = true; + env.adapter.findMany = function(store, type, ids) { + equal(type, Tag, "type should be Tag"); + deepEqual(ids, ['5', '2'], "ids should be 5 and 2"); + + return Ember.RSVP.resolve([{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); + }; + + env.adapter.find = function(store, type, id) { + equal(type, Person, "type should be Person"); + equal(id, 1, "id should be 1"); + + return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", tags: [5, 2] }); + }; + + run(function() { + store.find('person', 1).then(function(person) { + equal(get(person, 'name'), "Tom Dale", "The person is now populated"); + + return run(function() { + return person.get('tags'); + }); + }).then(function(tags) { + equal(get(tags, 'length'), 2, "the tags object still exists"); + equal(get(tags.objectAt(0), 'name'), "friendly", "Tom Dale is now friendly"); + equal(get(tags.objectAt(0), 'isLoaded'), true, "Tom Dale is now loaded"); + }); + }); +}); + +test("it is possible to add a new item to a relationship", function() { + expect(2); + + var Tag = DS.Model.extend({ + name: DS.attr('string'), + people: DS.belongsTo('person') + }); + + var Person = DS.Model.extend({ + name: DS.attr('string'), + tags: DS.hasMany('tag') + }); + + var env = setupStore({ + tag: Tag, + person: Person + }); + + var store = env.store; + + run(function() { + store.push('person', { id: 1, name: "Tom Dale", tags: [1] }); + store.push('tag', { id: 1, name: "ember" }); + }); + + run(function() { + store.find(Person, 1).then(function(person) { + var tag = get(person, 'tags').objectAt(0); + + equal(get(tag, 'name'), "ember", "precond - relationships work"); + + tag = store.createRecord(Tag, { name: "js" }); + get(person, 'tags').pushObject(tag); + + equal(get(person, 'tags').objectAt(1), tag, "newly added relationship works"); + }); + }); +}); + +test("possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)", function() { + expect(2); + + var Tag = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person') + }); + + var Person = DS.Model.extend({ + name: DS.attr('string'), + tags: DS.hasMany('tag') + }); + + var env = setupStore({ tag: Tag, person: Person }); + var store = env.store; + + run(function() { + store.push('person', { id: 1, name: "Tom Dale", tags: [1] }); + store.push('person', { id: 2, name: "Sylvain Mina", tags: [2] }); + store.push('tag', { id: 1, name: "ember" }); + store.push('tag', { id: 2, name: "ember-data" }); + }); + + var tom, sylvain; + + run(function() { + tom = store.getById('person', '1'); + sylvain = store.getById('person', '2'); + // Test that since sylvain.get('tags') instanceof DS.ManyArray, + // addRecords on Relationship iterates correctly. + tom.get('tags').setObjects(sylvain.get('tags')); + }); + + equal(tom.get('tags.length'), 1); + equal(tom.get('tags.firstObject'), store.getById('tag', 2)); +}); + +test("it is possible to remove an item from a relationship", function() { + expect(2); + + var Tag = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person') + }); + + var Person = DS.Model.extend({ + name: DS.attr('string'), + tags: DS.hasMany('tag') + }); + + var env = setupStore({ tag: Tag, person: Person }); + var store = env.store; + + run(function() { + store.push('person', { id: 1, name: "Tom Dale", tags: [1] }); + store.push('tag', { id: 1, name: "ember" }); + }); + + run(function() { + store.find('person', 1).then(async(function(person) { + var tag = get(person, 'tags').objectAt(0); + + equal(get(tag, 'name'), "ember", "precond - relationships work"); + + run(function() { + get(person, 'tags').removeObject(tag); + }); + + equal(get(person, 'tags.length'), 0, "object is removed from the relationship"); + })); + }); +}); + +test("it is possible to add an item to a relationship, remove it, then add it again", function() { + var Tag = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person') + }); + + var Person = DS.Model.extend({ + name: DS.attr('string'), + tags: DS.hasMany('tag') + }); + + Tag.toString = function() { return "Tag"; }; + Person.toString = function() { return "Person"; }; + + var env = setupStore({ tag: Tag, person: Person }); + var store = env.store; + var person, tag1, tag2, tag3; + + run(function() { + person = store.createRecord('person'); + tag1 = store.createRecord('tag'); + tag2 = store.createRecord('tag'); + tag3 = store.createRecord('tag'); + }); + + var tags = get(person, 'tags'); + + run(function() { + tags.pushObjects([tag1, tag2, tag3]); + tags.removeObject(tag2); + }); + + equal(tags.objectAt(0), tag1); + equal(tags.objectAt(1), tag3); + equal(get(person, 'tags.length'), 2, "object is removed from the relationship"); + + run(function() { + tags.insertAt(0, tag2); + }); + + equal(get(person, 'tags.length'), 3, "object is added back to the relationship"); + equal(tags.objectAt(0), tag2); + equal(tags.objectAt(1), tag1); + equal(tags.objectAt(2), tag3); +}); diff --git a/packages/ember-data/tests/unit/model/relationships/record_array_test.js b/packages/ember-data/tests/unit/model/relationships/record_array_test.js new file mode 100644 index 00000000000..76809505d26 --- /dev/null +++ b/packages/ember-data/tests/unit/model/relationships/record_array_test.js @@ -0,0 +1,62 @@ +var get = Ember.get; +var set = Ember.set; +var run = Ember.run; + +module("unit/model/relationships - RecordArray"); + +test("updating the content of a RecordArray updates its content", function() { + var Tag = DS.Model.extend({ + name: DS.attr('string') + }); + + var env = setupStore({ tag: Tag }); + var store = env.store; + var records, tags; + + run(function() { + records = store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); + tags = DS.RecordArray.create({ content: Ember.A(records.slice(0, 2)), store: store, type: Tag }); + }); + + var tag = tags.objectAt(0); + equal(get(tag, 'name'), "friendly", "precond - we're working with the right tags"); + + run(function() { + set(tags, 'content', Ember.A(records.slice(1, 3))); + }); + + tag = tags.objectAt(0); + equal(get(tag, 'name'), "smarmy", "the lookup was updated"); +}); + +test("can create child record from a hasMany relationship", function() { + expect(3); + + var Tag = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person') + }); + + var Person = DS.Model.extend({ + name: DS.attr('string'), + tags: DS.hasMany('tag') + }); + + var env = setupStore({ tag: Tag, person: Person }); + var store = env.store; + + run(function() { + store.push('person', { id: 1, name: "Tom Dale" }); + }); + + run(function() { + store.find('person', 1).then(async(function(person) { + person.get("tags").createRecord({ name: "cool" }); + + equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + equal(get(person, 'tags.length'), 1, "tag is added to the parent record"); + equal(get(person, 'tags').objectAt(0).get("name"), "cool", "tag values are passed along"); + })); + }); +}); + diff --git a/packages/ember-data/tests/unit/model/relationships_test.js b/packages/ember-data/tests/unit/model/relationships_test.js index e1d470fb684..8166e97097a 100644 --- a/packages/ember-data/tests/unit/model/relationships_test.js +++ b/packages/ember-data/tests/unit/model/relationships_test.js @@ -1,5 +1,4 @@ var get = Ember.get; -var set = Ember.set; var run = Ember.run; module("unit/model/relationships - DS.Model"); @@ -36,777 +35,3 @@ test("exposes a hash of the relationships on a model", function() { { name: "occupations", kind: "hasMany" } ]); }); - -var env; -module("unit/model/relationships - DS.hasMany", { - setup: function() { - env = setupStore(); - } -}); - -test("hasMany handles pre-loaded relationships", function() { - expect(13); - - var Tag = DS.Model.extend({ - name: DS.attr('string'), - person: DS.belongsTo('person') - }); - - var Pet = DS.Model.extend({ - name: DS.attr('string'), - person: DS.belongsTo('person') - }); - - var Person = DS.Model.extend({ - name: DS.attr('string'), - tags: DS.hasMany('tag'), - pets: DS.hasMany('pet') - }); - - env.container.register('model:tag', Tag); - env.container.register('model:pet', Pet); - env.container.register('model:person', Person); - - env.adapter.find = function(store, type, id) { - if (type === Tag && id === '12') { - return Ember.RSVP.resolve({ id: 12, name: "oohlala" }); - } else { - ok(false, "find() should not be called with these values"); - } - }; - - var store = env.store; - - run(function() { - store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); - store.pushMany('pet', [{ id: 4, name: "fluffy" }, { id: 7, name: "snowy" }, { id: 12, name: "cerberus" }]); - store.push('person', { id: 1, name: "Tom Dale", tags: [5] }); - store.push('person', { id: 2, name: "Yehuda Katz", tags: [12] }); - }); - - run(function() { - store.find('person', 1).then(function(person) { - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - - var tags = get(person, 'tags'); - equal(get(tags, 'length'), 1, "the list of tags should have the correct length"); - equal(get(tags.objectAt(0), 'name'), "friendly", "the first tag should be a Tag"); - - run(function() { - store.push('person', { id: 1, name: "Tom Dale", tags: [5, 2] }); - }); - - equal(tags, get(person, 'tags'), "a relationship returns the same object every time"); - equal(get(get(person, 'tags'), 'length'), 2, "the length is updated after new data is loaded"); - - strictEqual(get(person, 'tags').objectAt(0), get(person, 'tags').objectAt(0), "the returned object is always the same"); - asyncEqual(get(person, 'tags').objectAt(0), store.find(Tag, 5), "relationship objects are the same as objects retrieved directly"); - - run(function() { - store.push('person', { id: 3, name: "KSelden" }); - }); - - return store.find('person', 3); - }).then(function(kselden) { - equal(get(get(kselden, 'tags'), 'length'), 0, "a relationship that has not been supplied returns an empty array"); - - run(function() { - store.push('person', { id: 4, name: "Cyvid Hamluck", pets: [4] }); - }); - return store.find('person', 4); - }).then(function(cyvid) { - equal(get(cyvid, 'name'), "Cyvid Hamluck", "precond - retrieves person record from store"); - - var pets = get(cyvid, 'pets'); - equal(get(pets, 'length'), 1, "the list of pets should have the correct length"); - equal(get(pets.objectAt(0), 'name'), "fluffy", "the first pet should be correct"); - - run(function() { - store.push(Person, { id: 4, name: "Cyvid Hamluck", pets: [4, 12] }); - }); - - equal(pets, get(cyvid, 'pets'), "a relationship returns the same object every time"); - equal(get(get(cyvid, 'pets'), 'length'), 2, "the length is updated after new data is loaded"); - }); - }); -}); - -test("hasMany lazily loads async relationships", function() { - expect(5); - - var Tag = DS.Model.extend({ - name: DS.attr('string'), - person: DS.belongsTo('person') - }); - - var Pet = DS.Model.extend({ - name: DS.attr('string'), - person: DS.belongsTo('person') - }); - - var Person = DS.Model.extend({ - name: DS.attr('string'), - tags: DS.hasMany('tag', { async: true }), - pets: DS.hasMany('pet') - }); - - env.container.register('model:tag', Tag); - env.container.register('model:pet', Pet); - env.container.register('model:person', Person); - - env.adapter.find = function(store, type, id) { - if (type === Tag && id === '12') { - return Ember.RSVP.resolve({ id: 12, name: "oohlala" }); - } else { - ok(false, "find() should not be called with these values"); - } - }; - - var store = env.store; - - run(function() { - store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); - store.pushMany('pet', [{ id: 4, name: "fluffy" }, { id: 7, name: "snowy" }, { id: 12, name: "cerberus" }]); - store.push('person', { id: 1, name: "Tom Dale", tags: [5] }); - store.push('person', { id: 2, name: "Yehuda Katz", tags: [12] }); - }); - - var wycats; - - run(function() { - store.find('person', 2).then(function(person) { - wycats = person; - - equal(get(wycats, 'name'), "Yehuda Katz", "precond - retrieves person record from store"); - - return Ember.RSVP.hash({ - wycats: wycats, - tags: wycats.get('tags') - }); - }).then(function(records) { - equal(get(records.tags, 'length'), 1, "the list of tags should have the correct length"); - equal(get(records.tags.objectAt(0), 'name'), "oohlala", "the first tag should be a Tag"); - - strictEqual(records.tags.objectAt(0), records.tags.objectAt(0), "the returned object is always the same"); - asyncEqual(records.tags.objectAt(0), store.find(Tag, 12), "relationship objects are the same as objects retrieved directly"); - - return get(wycats, 'tags'); - }).then(function(tags) { - var newTag; - run(function() { - newTag = store.createRecord(Tag); - tags.pushObject(newTag); - }); - }); - }); -}); - -test("should be able to retrieve the type for a hasMany relationship without specifying a type from its metadata", function() { - var Tag = DS.Model.extend({}); - - var Person = DS.Model.extend({ - tags: DS.hasMany() - }); - - var env = setupStore({ - tag: Tag, - person: Person - }); - - equal(env.store.modelFor('person').typeForRelationship('tags'), Tag, "returns the relationship type"); -}); - -test("should be able to retrieve the type for a hasMany relationship specified using a string from its metadata", function() { - var Tag = DS.Model.extend({}); - - var Person = DS.Model.extend({ - tags: DS.hasMany('tag') - }); - - var env = setupStore({ - tag: Tag, - person: Person - }); - - equal(env.store.modelFor('person').typeForRelationship('tags'), Tag, "returns the relationship type"); -}); - -test("should be able to retrieve the type for a belongsTo relationship without specifying a type from its metadata", function() { - var Tag = DS.Model.extend({}); - - var Person = DS.Model.extend({ - tag: DS.belongsTo() - }); - - var env = setupStore({ - tag: Tag, - person: Person - }); - - equal(env.store.modelFor('person').typeForRelationship('tag'), Tag, "returns the relationship type"); -}); - -test("should be able to retrieve the type for a belongsTo relationship specified using a string from its metadata", function() { - var Tag = DS.Model.extend({ - name: DS.attr('string') - }); - - var Person = DS.Model.extend({ - tags: DS.belongsTo('tag') - }); - - var env = setupStore({ - tag: Tag, - person: Person - }); - - equal(env.store.modelFor('person').typeForRelationship('tags'), Tag, "returns the relationship type"); -}); - -test("relationships work when declared with a string path", function() { - expect(2); - - window.App = {}; - - var Person = DS.Model.extend({ - name: DS.attr('string'), - tags: DS.hasMany('tag') - }); - - var Tag = DS.Model.extend({ - name: DS.attr('string') - }); - - var env = setupStore({ - person: Person, - tag: Tag - }); - - run(function() { - env.store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); - env.store.push('person', { id: 1, name: "Tom Dale", tags: [5, 2] }); - }); - - run(function() { - env.store.find('person', 1).then(function(person) { - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - equal(get(person, 'tags.length'), 2, "the list of tags should have the correct length"); - }); - }); -}); - -test("hasMany relationships work when the data hash has not been loaded", function() { - expect(8); - - var Tag = DS.Model.extend({ - name: DS.attr('string'), - person: DS.belongsTo('person') - }); - Tag.toString = function() { return "Tag"; }; - - var Person = DS.Model.extend({ - name: DS.attr('string'), - tags: DS.hasMany('tag', { async: true }) - }); - Person.toString = function() { return "Person"; }; - - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; - - env.adapter.coalesceFindRequests = true; - env.adapter.findMany = function(store, type, ids) { - equal(type, Tag, "type should be Tag"); - deepEqual(ids, ['5', '2'], "ids should be 5 and 2"); - - return Ember.RSVP.resolve([{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); - }; - - env.adapter.find = function(store, type, id) { - equal(type, Person, "type should be Person"); - equal(id, 1, "id should be 1"); - - return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", tags: [5, 2] }); - }; - - run(function() { - store.find('person', 1).then(function(person) { - equal(get(person, 'name'), "Tom Dale", "The person is now populated"); - - return run(function() { - return person.get('tags'); - }); - }).then(function(tags) { - equal(get(tags, 'length'), 2, "the tags object still exists"); - equal(get(tags.objectAt(0), 'name'), "friendly", "Tom Dale is now friendly"); - equal(get(tags.objectAt(0), 'isLoaded'), true, "Tom Dale is now loaded"); - }); - }); -}); - -test("it is possible to add a new item to a relationship", function() { - expect(2); - - var Tag = DS.Model.extend({ - name: DS.attr('string'), - people: DS.belongsTo('person') - }); - - var Person = DS.Model.extend({ - name: DS.attr('string'), - tags: DS.hasMany('tag') - }); - - var env = setupStore({ - tag: Tag, - person: Person - }); - - var store = env.store; - - run(function() { - store.push('person', { id: 1, name: "Tom Dale", tags: [1] }); - store.push('tag', { id: 1, name: "ember" }); - }); - - run(function() { - store.find(Person, 1).then(function(person) { - var tag = get(person, 'tags').objectAt(0); - - equal(get(tag, 'name'), "ember", "precond - relationships work"); - - tag = store.createRecord(Tag, { name: "js" }); - get(person, 'tags').pushObject(tag); - - equal(get(person, 'tags').objectAt(1), tag, "newly added relationship works"); - }); - }); -}); - -test("possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)", function() { - expect(2); - - var Tag = DS.Model.extend({ - name: DS.attr('string'), - person: DS.belongsTo('person') - }); - - var Person = DS.Model.extend({ - name: DS.attr('string'), - tags: DS.hasMany('tag') - }); - - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; - - run(function() { - store.push('person', { id: 1, name: "Tom Dale", tags: [1] }); - store.push('person', { id: 2, name: "Sylvain Mina", tags: [2] }); - store.push('tag', { id: 1, name: "ember" }); - store.push('tag', { id: 2, name: "ember-data" }); - }); - - var tom, sylvain; - - run(function() { - tom = store.getById('person', '1'); - sylvain = store.getById('person', '2'); - // Test that since sylvain.get('tags') instanceof DS.ManyArray, - // addRecords on Relationship iterates correctly. - tom.get('tags').setObjects(sylvain.get('tags')); - }); - - equal(tom.get('tags.length'), 1); - equal(tom.get('tags.firstObject'), store.getById('tag', 2)); -}); - -test("it is possible to remove an item from a relationship", function() { - expect(2); - - var Tag = DS.Model.extend({ - name: DS.attr('string'), - person: DS.belongsTo('person') - }); - - var Person = DS.Model.extend({ - name: DS.attr('string'), - tags: DS.hasMany('tag') - }); - - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; - - run(function() { - store.push('person', { id: 1, name: "Tom Dale", tags: [1] }); - store.push('tag', { id: 1, name: "ember" }); - }); - - run(function() { - store.find('person', 1).then(async(function(person) { - var tag = get(person, 'tags').objectAt(0); - - equal(get(tag, 'name'), "ember", "precond - relationships work"); - - run(function() { - get(person, 'tags').removeObject(tag); - }); - - equal(get(person, 'tags.length'), 0, "object is removed from the relationship"); - })); - }); -}); - -test("it is possible to add an item to a relationship, remove it, then add it again", function() { - var Tag = DS.Model.extend({ - name: DS.attr('string'), - person: DS.belongsTo('person') - }); - Tag.toString = function() { return "Tag"; }; - - var Person = DS.Model.extend({ - name: DS.attr('string'), - tags: DS.hasMany('tag') - }); - Person.toString = function() { return "Person"; }; - - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; - var person, tag1, tag2, tag3; - - run(function() { - person = store.createRecord('person'); - tag1 = store.createRecord('tag'); - tag2 = store.createRecord('tag'); - tag3 = store.createRecord('tag'); - }); - - var tags = get(person, 'tags'); - - run(function() { - tags.pushObjects([tag1, tag2, tag3]); - tags.removeObject(tag2); - }); - - equal(tags.objectAt(0), tag1); - equal(tags.objectAt(1), tag3); - equal(get(person, 'tags.length'), 2, "object is removed from the relationship"); - - run(function() { - tags.insertAt(0, tag2); - }); - - equal(get(person, 'tags.length'), 3, "object is added back to the relationship"); - equal(tags.objectAt(0), tag2); - equal(tags.objectAt(1), tag1); - equal(tags.objectAt(2), tag3); -}); - -module("unit/model/relationships - RecordArray"); - -test("updating the content of a RecordArray updates its content", function() { - var Tag = DS.Model.extend({ - name: DS.attr('string') - }); - - var env = setupStore({ tag: Tag }); - var store = env.store; - var records, tags; - - run(function() { - records = store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); - tags = DS.RecordArray.create({ content: Ember.A(records.slice(0, 2)), store: store, type: Tag }); - }); - - var tag = tags.objectAt(0); - equal(get(tag, 'name'), "friendly", "precond - we're working with the right tags"); - - run(function() { - set(tags, 'content', Ember.A(records.slice(1, 3))); - }); - - tag = tags.objectAt(0); - equal(get(tag, 'name'), "smarmy", "the lookup was updated"); -}); - -test("can create child record from a hasMany relationship", function() { - expect(3); - - var Tag = DS.Model.extend({ - name: DS.attr('string'), - person: DS.belongsTo('person') - }); - - var Person = DS.Model.extend({ - name: DS.attr('string'), - tags: DS.hasMany('tag') - }); - - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; - - run(function() { - store.push('person', { id: 1, name: "Tom Dale" }); - }); - - run(function() { - store.find('person', 1).then(async(function(person) { - person.get("tags").createRecord({ name: "cool" }); - - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - equal(get(person, 'tags.length'), 1, "tag is added to the parent record"); - equal(get(person, 'tags').objectAt(0).get("name"), "cool", "tag values are passed along"); - })); - }); -}); - -module("unit/model/relationships - DS.belongsTo"); - -test("belongsTo lazily loads relationships as needed", function() { - expect(5); - - var Tag = DS.Model.extend({ - name: DS.attr('string'), - people: DS.hasMany('person') - }); - Tag.toString = function() { return "Tag"; }; - - var Person = DS.Model.extend({ - name: DS.attr('string'), - tag: DS.belongsTo('tag') - }); - Person.toString = function() { return "Person"; }; - - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; - - run(function() { - store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); - store.push('person', { id: 1, name: "Tom Dale", tag: 5 }); - }); - - run(function() { - store.find('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - - equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); - equal(get(person, 'tag.name'), "friendly", "the tag shuld have name"); - - strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); - asyncEqual(get(person, 'tag'), store.find('tag', 5), "relationship object is the same as object retrieved directly"); - })); - }); -}); - -test("async belongsTo relationships work when the data hash has not been loaded", function() { - expect(5); - - var Tag = DS.Model.extend({ - name: DS.attr('string') - }); - - var Person = DS.Model.extend({ - name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: true }) - }); - - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; - - env.adapter.find = function(store, type, id) { - if (type === Person) { - equal(id, 1, "id should be 1"); - - return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", tag: 2 }); - } else if (type === Tag) { - equal(id, 2, "id should be 2"); - - return Ember.RSVP.resolve({ id: 2, name: "friendly" }); - } - }; - - run(function() { - store.find('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "The person is now populated"); - - return run(function() { - return get(person, 'tag'); - }); - })).then(async(function(tag) { - equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); - equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); - })); - }); -}); - -test("async belongsTo relationships work when the data hash has already been loaded", function() { - expect(3); - - var Tag = DS.Model.extend({ - name: DS.attr('string') - }); - - var Person = DS.Model.extend({ - name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: true }) - }); - - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; - - run(function() { - store.push('tag', { id: 2, name: "friendly" }); - store.push('person', { id: 1, name: "Tom Dale", tag: 2 }); - }); - - run(function() { - store.find('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "The person is now populated"); - return run(function() { - return get(person, 'tag'); - }); - })).then(async(function(tag) { - equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); - equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); - })); - }); -}); - -test("calling createRecord and passing in an undefined value for a relationship should be treated as if null", function () { - expect(1); - - var Tag = DS.Model.extend({ - name: DS.attr('string'), - person: DS.belongsTo('person') - }); - - var Person = DS.Model.extend({ - name: DS.attr('string'), - tag: DS.belongsTo('tag') - }); - - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; - - run(function() { - store.createRecord('person', { id: 1, tag: undefined }); - }); - - run(function() { - store.find(Person, 1).then(async(function(person) { - strictEqual(person.get('tag'), null, "undefined values should return null relationships"); - })); - }); -}); - -test("When finding a hasMany relationship the inverse belongsTo relationship is available immediately", function() { - var Occupation = DS.Model.extend({ - description: DS.attr('string'), - person: DS.belongsTo('person') - }); - - Occupation.toString = function() { return "Occupation"; }; - - var Person = DS.Model.extend({ - name: DS.attr('string'), - occupations: DS.hasMany('occupation', { async: true }) - }); - - Person.toString = function() { return "Person"; }; - - var env = setupStore({ occupation: Occupation, person: Person }); - var store = env.store; - - env.adapter.findMany = function(store, type, ids, records) { - equal(records[0].get('person.id'), '1'); - return Ember.RSVP.resolve([{ id: 5, description: "fifth" }, { id: 2, description: "second" }]); - }; - - env.adapter.coalesceFindRequests = true; - - run(function() { - store.push('person', { id: 1, name: "Tom Dale", occupations: [5, 2] }); - }); - - run(function() { - store.find('person', 1).then(async(function(person) { - equal(get(person, 'isLoaded'), true, "isLoaded should be true"); - equal(get(person, 'name'), "Tom Dale", "the person is still Tom Dale"); - - return get(person, 'occupations'); - })).then(async(function(occupations) { - equal(get(occupations, 'length'), 2, "the list of occupations should have the correct length"); - - equal(get(occupations.objectAt(0), 'description'), "fifth", "the occupation is the fifth"); - equal(get(occupations.objectAt(0), 'isLoaded'), true, "the occupation is now loaded"); - })); - }); -}); - -test("When finding a belongsTo relationship the inverse belongsTo relationship is available immediately", function() { - expect(1); - - var Occupation = DS.Model.extend({ - description: DS.attr('string'), - person: DS.belongsTo('person') - }); - - Occupation.toString = function() { return "Occupation"; }; - - var Person = DS.Model.extend({ - name: DS.attr('string'), - occupation: DS.belongsTo('occupation', { async: true }) - }); - - Person.toString = function() { return "Person"; }; - - var env = setupStore({ occupation: Occupation, person: Person }); - var store = env.store; - - env.adapter.find = function(store, type, id, record) { - equal(record.get('person.id'), '1'); - return Ember.RSVP.resolve({ id: 5, description: "fifth" }); - }; - - run(function() { - store.push('person', { id: 1, name: "Tom Dale", occupation: 5 }); - }); - - run(function() { - store.getById('person', 1).get('occupation'); - }); -}); - -test("belongsTo supports relationships to models with id 0", function() { - expect(5); - - var Tag = DS.Model.extend({ - name: DS.attr('string'), - people: DS.hasMany('person') - }); - Tag.toString = function() { return "Tag"; }; - - var Person = DS.Model.extend({ - name: DS.attr('string'), - tag: DS.belongsTo('tag') - }); - Person.toString = function() { return "Person"; }; - - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; - - run(function() { - store.pushMany('tag', [{ id: 0, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); - store.push('person', { id: 1, name: "Tom Dale", tag: 0 }); - }); - - run(function() { - store.find('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - - equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); - equal(get(person, 'tag.name'), "friendly", "the tag should have name"); - - strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); - asyncEqual(get(person, 'tag'), store.find(Tag, 0), "relationship object is the same as object retrieved directly"); - })); - }); -}); From 763791eac5fbe9585da96d7a16a77533d78d1279 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Mon, 26 Jan 2015 11:14:19 -0500 Subject: [PATCH 0600/2527] Cleanup JSONSerializer#extract example --- .../ember-data/lib/serializers/json_serializer.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 56dbccfcc9a..3bbb2394981 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -696,17 +696,20 @@ export default Ember.Object.extend({ This method delegates to a more specific extract method based on the `requestType`. - Example + To override this method with a custom one, make sure to call + `this._super(store, type, payload, id, requestType)` with your + pre-processed data. + + Here's an example of using `extract` manually: ```javascript - var get = Ember.get; socket.on('message', function(message) { - var modelName = message.model; var data = message.data; - var type = store.modelFor(modelName); + var type = store.modelFor(message.modelName); var serializer = store.serializerFor(type.typeKey); - var record = serializer.extract(store, type, data, get(data, 'id'), 'single'); - store.push(modelName, record); + var record = serializer.extract(store, type, data, data.id, 'single'); + + store.push(message.modelName, record); }); ``` From 3b42a16921bfb3a86430e61d90272c708bfc73fb Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 28 Jan 2015 20:58:06 +0100 Subject: [PATCH 0601/2527] Remove non-breaking spaces --- packages/ember-data/lib/system/relationships/belongs_to.js | 2 +- packages/ember-data/lib/system/relationships/has_many.js | 2 +- packages/ember-data/lib/system/store.js | 4 ++-- .../tests/integration/relationships/has_many_test.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/belongs_to.js b/packages/ember-data/lib/system/relationships/belongs_to.js index 6bd9c181225..13481e5d4ca 100644 --- a/packages/ember-data/lib/system/relationships/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/belongs_to.js @@ -64,7 +64,7 @@ function belongsTo(type, options) { type = undefined; } - Ember.assert("The first argument to DS.belongsTo must be a string representing a model type key, not an instance of " + Ember.inspect(type) + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", typeof type === 'string' || typeof type === 'undefined'); + Ember.assert("The first argument to DS.belongsTo must be a string representing a model type key, not an instance of " + Ember.inspect(type) + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", typeof type === 'string' || typeof type === 'undefined'); options = options || {}; diff --git a/packages/ember-data/lib/system/relationships/has_many.js b/packages/ember-data/lib/system/relationships/has_many.js index e360e0a70ed..9f3af4132da 100644 --- a/packages/ember-data/lib/system/relationships/has_many.js +++ b/packages/ember-data/lib/system/relationships/has_many.js @@ -99,7 +99,7 @@ function hasMany(type, options) { type = undefined; } - Ember.assert("The first argument to DS.hasMany must be a string representing a model type key, not an instance of " + Ember.inspect(type) + ". E.g., to define a relation to the Comment model, use DS.hasMany('comment')", typeof type === 'string' || typeof type === 'undefined'); + Ember.assert("The first argument to DS.hasMany must be a string representing a model type key, not an instance of " + Ember.inspect(type) + ". E.g., to define a relation to the Comment model, use DS.hasMany('comment')", typeof type === 'string' || typeof type === 'undefined'); options = options || {}; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 0e22f3780d1..9d1a37f4956 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1434,10 +1434,10 @@ Store = Ember.Object.extend({ if (Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS) { Ember.warn("The payload for '" + type.typeKey + "' contains these unknown keys: " + Ember.inspect(filter(Ember.keys(data), function(key) { - return !(key === 'id' || key === 'links' || get(type, 'fields').has(key) || key.match(/Type$/)); + return !(key === 'id' || key === 'links' || get(type, 'fields').has(key) || key.match(/Type$/)); })) + ". Make sure they've been defined in your model.", filter(Ember.keys(data), function(key) { - return !(key === 'id' || key === 'links' || get(type, 'fields').has(key) || key.match(/Type$/)); + return !(key === 'id' || key === 'links' || get(type, 'fields').has(key) || key.match(/Type$/)); }).length === 0 ); } diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index 6865b1e8470..fd33231e490 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -895,7 +895,7 @@ test("a records ASYNC HM relationship property is readOnly", function() { }, 'Cannot Set: comments on: ' + Ember.inspect(post)); }); -test("When a record is saved, its unsaved hasMany records should be kept", function () { +test("When a record is saved, its unsaved hasMany records should be kept", function () { expect(1); var post, comment; From d0a3e5fb8514603c827c057649f6b49dedfecd9d Mon Sep 17 00:00:00 2001 From: Miguel Camba Date: Mon, 12 Jan 2015 18:06:05 +0000 Subject: [PATCH 0602/2527] Sort query params in ajax calls. When developing APIs, is pretty common to place a high level caching mechanism, like Varnish, to cache requests to public API endpoints, and those tools use the URL string to determine if they have a cached response. As an example, if one user requests `/posts?sort=price&category=pets` and another requests `/posts?category=pets&sort=price`, the cached request won't be used in the second call. Varnish by example has some modules to sort query parameters when caching, but it's not the default behavior and requires custom config. Although the URL specification does not say that the order of the query parameters is meaningless, in the bast mayority (read: all) of the APIs I've seen, 2 requests are considered identical regardless of the the order. Because of that, sorting the query params consistenlty is considered a good practice, so this PR introduces a `sortQueryParams` key in the RESTAdapter class, that defaults to a function to sort query params alphabetically. In case you don't want this behavior, setting that property to a falsey value in the ApplicationAdapter will respect the original order. In case you want a different order, you can pass a function that does the sorting your way. As other customization in ED, this can be customized on a per resource level, in case the order matters in only a few endpoints. --- .../ember-data/lib/adapters/rest_adapter.js | 57 +++++++++++++++++ .../integration/adapter/rest_adapter_test.js | 61 +++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index b920c00e1d0..e654a57aee1 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -170,6 +170,60 @@ var forEach = Ember.ArrayPolyfills.forEach; export default Adapter.extend({ defaultSerializer: '-rest', + /** + By default, the RESTAdapter will send the query params sorted alphabetically to the + server. + + For example: + + ```js + store.find('posts', {sort: 'price', category: 'pets'}); + ``` + + will generate a requests like this `/posts?category=pets&sort=price`, even if the + parameters were specified in a different order. + + That way the generated URL will be deterministic and that simplifies caching mechanisms + in the backend. + + Setting `sortQueryParams` to a falsey value will respect the original order. + + In case you want to sort the query parameters with a different criteria, set + `sortQueryParams` to your custom sort function. + + ```js + export default DS.RESTAdapter.extend({ + sortQueryParams: function(params) { + var sortedKeys = Object.keys(params).sort().reverse(); + var len = sortedKeys.length, newParams = {}; + + for (var i = 0; i < len; i++) { + newParams[sortedKeys[i]] = params[sortedKeys[i]]; + } + return newParams; + } + }); + ``` + + @method sortQueryParams + @param {Object} obj + @return {Object} + */ + sortQueryParams: function(obj) { + var keys = Ember.keys(obj); + var len = keys.length; + if (len < 2) { + return obj; + } + var newQueryParams = {}; + var sortedKeys = keys.sort(); + + for (var i = 0; i < len; i++) { + newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]]; + } + return newQueryParams; + }, + /** By default the RESTAdapter will send each find request coming from a `store.find` or from accessing a relationship separately to the server. If your server supports passing @@ -329,6 +383,9 @@ export default Adapter.extend({ @return {Promise} promise */ findQuery: function(store, type, query) { + if (this.sortQueryParams) { + query = this.sortQueryParams(query); + } return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query }); }, diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 877aeb5d314..427b2c1bae1 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -832,6 +832,67 @@ test("metadata is accessible", function() { })); }); +test("findQuery - if `sortQueryParams` option is not provided, query params are sorted alphabetically", function() { + adapter.ajax = function(url, verb, hash) { + passedUrl = url; + passedVerb = verb; + passedHash = hash; + + deepEqual(Object.keys(hash.data), ["in", "order", "params", "wrong"], 'query params are received in alphabetical order'); + + return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); + }; + + store.findQuery('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { + // Noop + })); +}); + +test("findQuery - if `sortQueryParams` is falsey, query params are not sorted at all", function() { + adapter.ajax = function(url, verb, hash) { + passedUrl = url; + passedVerb = verb; + passedHash = hash; + + deepEqual(Object.keys(hash.data), ["params", "in", "wrong", "order"], 'query params are received in their original order'); + + return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); + }; + + adapter.sortQueryParams = null; + + store.findQuery('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { + // Noop + })); +}); + +test("findQuery - if `sortQueryParams` is a custom function, query params passed through that function", function() { + adapter.ajax = function(url, verb, hash) { + passedUrl = url; + passedVerb = verb; + passedHash = hash; + + deepEqual(Object.keys(hash.data), ["wrong", "params", "order", "in"], 'query params are received in reverse alphabetical order'); + + return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); + }; + + adapter.sortQueryParams = function(obj) { + var sortedKeys = Object.keys(obj).sort().reverse(); + var len = sortedKeys.length; + var newQueryParams = {}; + + for (var i = 0; i < len; i++) { + newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]]; + } + return newQueryParams; + }; + + store.findQuery('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { + // Noop + })); +}); + test("findQuery - payload 'meta' is accessible on the record array", function() { ajaxResponse({ meta: { offset: 5 }, From cf0ba5b3a9e39d6f7bb66c74a1f1cc3510a87cfb Mon Sep 17 00:00:00 2001 From: Adolfo Builes Date: Wed, 28 Jan 2015 17:27:01 -0500 Subject: [PATCH 0603/2527] Fix typo. --- .../ember-data/lib/system/relationships/state/relationship.js | 2 +- packages/ember-data/tests/unit/store/push_test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/state/relationship.js b/packages/ember-data/lib/system/relationships/state/relationship.js index 1d4b5b0bcce..acd00075319 100644 --- a/packages/ember-data/lib/system/relationships/state/relationship.js +++ b/packages/ember-data/lib/system/relationships/state/relationship.js @@ -203,7 +203,7 @@ Relationship.prototype = { }, updateLink: function(link) { - Ember.warn("You have pushed a record of type '" + this.record.constructor.typeKey + "' with '" + this.key + "' as a link, but the association is not an aysnc relationship.", this.isAsync); + Ember.warn("You have pushed a record of type '" + this.record.constructor.typeKey + "' with '" + this.key + "' as a link, but the association is not an async relationship.", this.isAsync); Ember.assert("You have pushed a record of type '" + this.record.constructor.typeKey + "' with '" + this.key + "' as a link, but the value of that link is not a string.", typeof link === 'string' || link === null); if (link !== this.link) { this.link = link; diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index fcdffd97238..f6045294b01 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -483,7 +483,7 @@ test('Calling push with a link for a non async relationship should warn', functi } }); }); - }, /You have pushed a record of type 'person' with 'phoneNumbers' as a link, but the association is not an aysnc relationship./); + }, /You have pushed a record of type 'person' with 'phoneNumbers' as a link, but the association is not an async relationship./); }); test('Calling push with a link containing an object throws an assertion error', function() { From 04bf5146b3676dd6174187f76e1daf2df540d548 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 28 Jan 2015 18:57:51 -0500 Subject: [PATCH 0604/2527] Update the generateIdForRecord docs to show it gets passed an Object not a record instance. --- packages/ember-data/lib/system/adapter.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index d725668131b..d12b69fed9f 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -261,7 +261,7 @@ var Adapter = Ember.Object.extend({ the first parameter and the newly created record as the second parameter: ```javascript - generateIdForRecord: function(store, record) { + generateIdForRecord: function(store, inputProperties) { var uuid = App.generateUUIDWithStatisticallyLowOddsOfCollision(); return uuid; } @@ -269,7 +269,8 @@ var Adapter = Ember.Object.extend({ @method generateIdForRecord @param {DS.Store} store - @param {DS.Model} record + @param {Object} inputProperties a hash of properties to set on the + newly created record. @return {String|Number} id */ generateIdForRecord: null, From d0a2cfa68b57d723e8696181e3603db97cb301fc Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 28 Jan 2015 23:16:41 -0500 Subject: [PATCH 0605/2527] Fix to stop phantomjs from crashing with the Ember beta travis tests --- packages/ember-data/tests/unit/model/rollback_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/tests/unit/model/rollback_test.js b/packages/ember-data/tests/unit/model/rollback_test.js index 691cf4b03e2..16bc8202efb 100644 --- a/packages/ember-data/tests/unit/model/rollback_test.js +++ b/packages/ember-data/tests/unit/model/rollback_test.js @@ -247,7 +247,7 @@ test("invalid record is rolled back to correct state after set", function() { }, ajaxError: function(jqXHR) { - return new DS.InvalidError(jqXHR); + return new Error(jqXHR); } }); From 2d1a5abdd2faafdabcf3f30a279618be1328f7e0 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Thu, 29 Jan 2015 09:20:11 +0100 Subject: [PATCH 0606/2527] Enable 'nonbsp' JSHint option --- .jshintrc | 1 + 1 file changed, 1 insertion(+) diff --git a/.jshintrc b/.jshintrc index 716aa3cea24..d906d053597 100644 --- a/.jshintrc +++ b/.jshintrc @@ -53,6 +53,7 @@ "newcap": true, "noarg": true, "noempty": false, + "nonbsp": true, "nonew": false, "nomen": false, "onevar": false, From 674678c000aa64bfbad287d02590996544199d52 Mon Sep 17 00:00:00 2001 From: Miguel Camba Date: Fri, 2 Jan 2015 01:00:19 +0000 Subject: [PATCH 0607/2527] Created `store.fetchById` and `store.fetchAll`. * `store.fetchById` behaves like `store.fetch` used to. * `store.fetchAll` behaves like `store.find` called with only a type. * `store.fetch` is aliased to `store.fetchById` and deprecated. --- packages/ember-data/lib/system/store.js | 39 ++++- .../tests/integration/store_test.js | 139 +++++++++++++++++- 2 files changed, 163 insertions(+), 15 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index e99098870f6..008e2d856e9 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -515,13 +515,13 @@ Store = Ember.Object.extend({ }); ``` - @method fetch + @method fetchById @param {String or subclass of DS.Model} type @param {String|Integer} id @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models @return {Promise} promise */ - fetch: function(type, id, preload) { + fetchById: function(type, id, preload) { if (this.hasRecordForId(type, id)) { return this.getById(type, id).reload(); } else { @@ -529,6 +529,33 @@ Store = Ember.Object.extend({ } }, + /** + This method returns a fresh collection from the server, regardless of if there is already records + in the store or not. + + @method fetchAll + @param {String or subclass of DS.Model} type + @return {Promise} promise + */ + fetchAll: function(type) { + type = this.modelFor(type); + + return this._fetchAll(type, this.all(type)); + }, + + /** + @method fetch + @param {String or subclass of DS.Model} type + @param {String|Integer} id + @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models + @return {Promise} promise + @deprecated Use [fetchById](#method_fetchById) instead + */ + fetch: function(type, id, preload) { + Ember.deprecate('Using store.fetch() has been deprecated. Use store.fetchById for fetching individual records or store.fetchAll for collections'); + return this.fetchById(type, id, preload); + }, + /** This method returns a record for a given type and id combination. @@ -899,19 +926,17 @@ Store = Ember.Object.extend({ @return {DS.AdapterPopulatedRecordArray} */ findAll: function(typeName) { - var type = this.modelFor(typeName); - - return this.fetchAll(type, this.all(type)); + return this.fetchAll(typeName); }, /** - @method fetchAll + @method _fetchAll @private @param {DS.Model} type @param {DS.RecordArray} array @return {Promise} promise */ - fetchAll: function(type, array) { + _fetchAll: function(type, array) { var adapter = this.adapterFor(type); var sinceToken = this.typeMapFor(type).metadata.since; diff --git a/packages/ember-data/tests/integration/store_test.js b/packages/ember-data/tests/integration/store_test.js index 7d43331fbe9..62ce788222f 100644 --- a/packages/ember-data/tests/integration/store_test.js +++ b/packages/ember-data/tests/integration/store_test.js @@ -197,7 +197,51 @@ function ajaxResponse(value) { }; } -test("Using store#fetch on existing record reloads it", function() { +test("Using store#fetch is deprecated", function() { + ajaxResponse({ + cars: [ + { id: 1, make: 'BMW', model: 'Mini' } + ] + }); + + expectDeprecation( + function() { + run(function() { + store.fetch('car', 1); + }); + }, + 'Using store.fetch() has been deprecated. Use store.fetchById for fetching individual records or store.fetchAll for collections' + ); +}); + +module("integration/store - fetchById", { + setup: function() { + initializeStore(DS.RESTAdapter.extend()); + } +}); + +test("Using store#fetchById on non existing record fetches it from the server", function() { + expect(2); + + ajaxResponse({ + cars: [{ + id: 20, + make: 'BMCW', + model: 'Mini' + }] + }); + + var car = store.hasRecordForId('car', 20); + ok(!car, 'Car with id=20 should not exist'); + + run(function() { + store.fetchById('car', 20).then(function (car) { + equal(car.get('make'), 'BMCW', 'Car with id=20 is now loaded'); + }); + }); +}); + +test("Using store#fetchById on existing record reloads it", function() { expect(2); var car; @@ -220,29 +264,108 @@ test("Using store#fetch on existing record reloads it", function() { equal(car.get('make'), 'BMC'); run(function() { - store.fetch('car', 1).then(function(car) { + store.fetchById('car', 1).then(function(car) { equal(car.get('make'), 'BMCW'); }); }); }); -test("Using store#fetch on non existing record calls find", function() { +module("integration/store - fetchAll", { + setup: function() { + initializeStore(DS.RESTAdapter.extend()); + } +}); + +test("Using store#fetchAll with no records triggers a query", function() { expect(2); ajaxResponse({ cars: [{ - id: 20, + id: 1, + make: 'BMC', + model: 'Mini' + }, + { + id: 2, make: 'BMCW', + model: 'Isetta' + }] + }); + + var cars = store.all('car'); + ok(!cars.get('length'), 'There is no cars in the store'); + + run(function() { + store.fetchAll('car').then(function(cars) { + equal(cars.get('length'), 2, 'Two car were fetched'); + }); + }); +}); + +test("Using store#fetchAll with existing records performs a query, updating existing records and returning new ones", function() { + expect(3); + + run(function() { + store.push('car', { + id: 1, + make: 'BMC', model: 'Mini' + }); + }); + + ajaxResponse({ + cars: [{ + id: 1, + make: 'BMC', + model: 'New Mini' + }, + { + id: 2, + make: 'BMCW', + model: 'Isetta' }] }); - var car = store.hasRecordForId('car', 20); - ok(!car, 'Car with id=20 should not exist'); + var cars = store.all('car'); + equal(cars.get('length'), 1, 'There is one car in the store'); run(function() { - store.fetch('car', 20).then(function (car) { - equal(car.get('make'), 'BMCW', 'Car with id=20 is now loaded'); + store.fetchAll('car').then(function(cars) { + equal(cars.get('length'), 2, 'There is 2 cars in the store now'); + var mini = cars.findBy('id', '1'); + equal(mini.get('model'), 'New Mini', 'Existing records have been updated'); }); }); }); + +test("When is used store#fetchAll with existing, and the response doesn't contain some of those records, WHAT DO WE DO?!?!?!", function() { + expect(4); + + run(function() { + store.push('car', { id: 1, make: 'BMC', model: 'Mini' }); + store.push('car', { id: 2, make: 'BMCW', model: 'Isetta' }); + }); + + ajaxResponse({ + cars: [{ + id: 1, + make: 'BMC', + model: 'New Mini' + }] + }); + + var cars = store.all('car'); + equal(cars.get('length'), 2, 'There is two cars in the store'); + + run(function() { + store.fetchAll('car').then(function(cars) { + equal(cars.get('length'), 2, 'It returns 1 car'); + var mini = cars.findBy('id', '1'); + equal(mini.get('model'), 'New Mini', 'Existing records have been updated'); + + var carsInStore = store.all('car'); + equal(carsInStore.get('length'), 2, 'There is 2 cars in the store'); + }); + }); + +}); From 9df59fb64d043eb4e5d442178a38ca90c108e78e Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 30 Jan 2015 21:29:46 -0500 Subject: [PATCH 0608/2527] idiomatic super usage. --- packages/ember-data/lib/system/model/model.js | 4 ++-- packages/ember-data/lib/system/record_array_manager.js | 2 +- packages/ember-data/lib/system/record_arrays/record_array.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 450eafe8c1a..40703767b69 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -468,7 +468,7 @@ var Model = Ember.Object.extend(Ember.Evented, { _data: null, init: function() { - this._super(); + this._super.apply(this, arguments); this._setup(); }, @@ -1141,7 +1141,7 @@ var Model = Ember.Object.extend(Ember.Evented, { }, willDestroy: function() { - this._super(); + this._super.apply(this, arguments); this.clearRelationships(); }, diff --git a/packages/ember-data/lib/system/record_array_manager.js b/packages/ember-data/lib/system/record_array_manager.js index 703943141e6..8914ef27e61 100644 --- a/packages/ember-data/lib/system/record_array_manager.js +++ b/packages/ember-data/lib/system/record_array_manager.js @@ -260,7 +260,7 @@ export default Ember.Object.extend({ }, willDestroy: function() { - this._super(); + this._super.apply(this, arguments); this.filteredRecordArrays.forEach(function(value) { forEach(flatten(value), destroy); diff --git a/packages/ember-data/lib/system/record_arrays/record_array.js b/packages/ember-data/lib/system/record_arrays/record_array.js index 0392bc5ae7d..2f5789cb243 100644 --- a/packages/ember-data/lib/system/record_arrays/record_array.js +++ b/packages/ember-data/lib/system/record_arrays/record_array.js @@ -215,6 +215,6 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { this._unregisterFromManager(); this._dissociateFromOwnRecords(); set(this, 'content', undefined); - this._super(); + this._super.apply(this, arguments); } }); From b29c8bdb919311ed39353dfac4bb3fd1eafce65c Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 4 Feb 2015 21:57:36 +0100 Subject: [PATCH 0609/2527] Fix JS code block for coalesceFindRequests --- packages/ember-data/lib/adapters/rest_adapter.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 807839c64f0..31506ff6020 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -176,11 +176,14 @@ export default Adapter.extend({ ids as a query string, you can set coalesceFindRequests to true to coalesce all find requests within a single runloop. - For example, if you have an initial payload of + For example, if you have an initial payload of: + ```javascript - post: { - id:1, - comments: [1,2] + { + post: { + id: 1, + comments: [1, 2] + } } ``` From ac765a5f5e69454d239c0b3f96ba52b78a3da9ab Mon Sep 17 00:00:00 2001 From: Steven Lindberg Date: Thu, 5 Feb 2015 16:54:19 -0800 Subject: [PATCH 0610/2527] Added failing test for hasMany add/remove bug --- .../integration/adapter/rest_adapter_test.js | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 4982f64f9a1..4096172170e 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -622,6 +622,37 @@ test("update - a serializer's primary key and attributes are consulted when buil })); }); +test("update - hasMany relationships faithfully reflect simultaneous adds and removes", function() { + Post.reopen({ comments: DS.hasMany('comment') }); + Comment.reopen({ post: DS.belongsTo('post') }); + + run(function() { + store.push('post', { id: 1, name: "Not everyone uses Rails", comments: [1] }); + store.push('comment', { id: 1, name: "Rails is omakase" }); + store.push('comment', { id: 2, name: "Yes. Yes it is." }); + }); + + ajaxResponse({ + posts: { id: 1, name: "Not everyone uses Rails", comments: [2] } + }); + + store.find('comment', 2).then(async(function() { + return store.find('post', 1); + })).then(async(function(post) { + var newComment = store.getById('comment', 2); + var comments = post.get('comments'); + + // Replace the comment with a new one + comments.popObject(); + comments.pushObject(newComment); + + return post.save(); + })).then(async(function(post) { + equal(post.get('comments.length'), 1, "the post has the correct number of comments"); + equal(post.get('comments.firstObject.name'), "Yes. Yes it is.", "the post has the correct comment"); + })); +}); + test("delete - an empty payload is a basic success", function() { run(function() { store.push('post', { id: 1, name: "Rails is omakase" }); From 9bd98f7806acdae19b5ec1bab3aed98681f4b539 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Fri, 6 Feb 2015 16:46:54 +0100 Subject: [PATCH 0611/2527] CHANGELOG spelling --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7eb46ca8ca..faf6884c215 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,7 +121,7 @@ to set metadata. * [Feature thrownError] tag errorThrown from jQuery onto the jqXHR like ic-ajax does. * Cache relationships meta in production * Deprecate store.update() -* Relationships are no long `ArrayProxy`, you can directly access them, so instead of relationship.get('content'). just use `relationship.toArray()`. +* hasMany relationships are no longer `RecordArray`, but `ManyArray`. To access the underlying array use `relationship.toArray()` instead of `relationship.get('content')`. ### Ember Data 1.0.0-beta.12 (November 25, 2014) From 131fe2b24540ff41b9c7554301f83ec3732bbdd4 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 4 Feb 2015 23:11:31 -0500 Subject: [PATCH 0612/2527] Fix tests on canary. They broke when Ember.js removed the meta.descs property. See https://github.com/emberjs/ember.js/pull/10323 --- .../relationships/belongs_to_test.js | 45 ++++++++++++++----- .../tests/integration/store_test.js | 1 - .../tests/unit/record_array_test.js | 9 +++- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index 1de4864bee6..29f3fc87e40 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -7,6 +7,21 @@ var hasMany = DS.hasMany; var belongsTo = DS.belongsTo; var hash = Ember.RSVP.hash; +// Before https://github.com/emberjs/ember.js/pull/10323 the computed +// property descriptor was stored on the ember meta object. After that +// pr it was moved to the ember object. This code normalized that +// lookup because the Ember Data ci tests run against diferent version +// of Ember. Once that code reaches the release branch this code can +// be removed. +function getComputedPropertyDesc(model, key) { + if (Ember.meta(model).descs) { + return Ember.meta(model).descs[key]; + } + var possibleDesc = model[key]; + var desc = (possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor) ? possibleDesc : undefined; + return desc; +} + module("integration/relationship/belongs_to Belongs-To Relationships", { setup: function() { User = DS.Model.extend({ @@ -362,15 +377,16 @@ test("relationshipsByName is cached in production", function() { var oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it //did not get dynamically changed when accessed - var oldCacheable = Ember.meta(model).descs.relationshipsByName._cacheable; - Ember.meta(model).descs.relationshipsByName._cacheable = true; + var relationshipsByName = getComputedPropertyDesc(model, 'relationshipsByName'); + var oldCacheable = relationshipsByName._cacheable; + relationshipsByName._cacheable = true; Ember.testing = false; try { equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached'); equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached'); } finally { Ember.testing = oldTesting; - Ember.meta(model).descs.relationshipsByName._cacheable = oldCacheable; + relationshipsByName._cacheable = oldCacheable; } }); @@ -379,15 +395,16 @@ test("relatedTypes is cached in production", function() { var oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it //did not get dynamically changed when accessed - var oldCacheable = Ember.meta(model).descs.relatedTypes._cacheable; - Ember.meta(model).descs.relatedTypes._cacheable = true; + var relatedTypes = getComputedPropertyDesc(model, 'relatedTypes'); + var oldCacheable = relatedTypes._cacheable; + relatedTypes._cacheable = true; Ember.testing = false; try { equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached'); equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached'); } finally { Ember.testing = oldTesting; - Ember.meta(model).descs.relatedTypes._cacheable = oldCacheable; + relatedTypes._cacheable = oldCacheable; } }); @@ -396,15 +413,16 @@ test("relationships is cached in production", function() { var oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it //did not get dynamically changed when accessed - var oldCacheable = Ember.meta(model).descs.relatedTypes._cacheable; - Ember.meta(model).descs.relationships._cacheable = true; + var relationships = getComputedPropertyDesc(model, 'relationships'); + var oldCacheable = relationships._cacheable; + relationships._cacheable = true; Ember.testing = false; try { equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached'); equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached'); } finally { Ember.testing = oldTesting; - Ember.meta(model).descs.relationships._cacheable = oldCacheable; + relationships._cacheable = oldCacheable; } }); @@ -451,7 +469,7 @@ test("relationship changes shouldn’t cause async fetches", function() { env.adapter.deleteRecord = function(store, type, record) { ok(record instanceof type); equal(record.id, 1, 'should first comment'); - return record; + return record.toJSON({ includeId: true }); }; env.adapter.findMany = function(store, type, ids, records) { @@ -492,7 +510,12 @@ test("Destroying a record with an unloaded aync belongsTo association does not f env.adapter.deleteRecord = function(store, type, record) { ok(record instanceof type); equal(record.id, 1, 'should first post'); - return record; + return { + id: "1", + title: null, + created_at: null, + user: "2" + }; }; run(post, 'destroyRecord'); diff --git a/packages/ember-data/tests/integration/store_test.js b/packages/ember-data/tests/integration/store_test.js index 62ce788222f..794eaf4a89d 100644 --- a/packages/ember-data/tests/integration/store_test.js +++ b/packages/ember-data/tests/integration/store_test.js @@ -171,7 +171,6 @@ test("destroying the store correctly cleans everything up", function() { Ember.run(store, 'destroy'); equal(car.get('person'), null, "expected car.person to no longer be present"); - equal(person.get('cars'), undefined, "expected person.cars to be empty"); equal(personWillDestroy.called.length, 1, 'expected person to have recieved willDestroy once'); equal(carWillDestroy.called.length, 1, 'expected car to recieve willDestroy once'); diff --git a/packages/ember-data/tests/unit/record_array_test.js b/packages/ember-data/tests/unit/record_array_test.js index 6942317c566..8f59201e64d 100644 --- a/packages/ember-data/tests/unit/record_array_test.js +++ b/packages/ember-data/tests/unit/record_array_test.js @@ -49,6 +49,11 @@ test("stops updating when destroyed", function() { expect(3); var store = createStore(); + // TODO remove once + // https://github.com/emberjs/ember.js/commit/c3f13e85a62069295965dd49ca487fe6ddba1188 + // is on the release branch + var emptyLength = Ember.meta(store).descs ? undefined : 0; + var recordArray = store.all(Person); run(function() { store.push(Person, { id: 1, name: 'wycats' }); @@ -59,11 +64,11 @@ test("stops updating when destroyed", function() { }); run(function() { - equal(recordArray.get('length'), undefined, "Has no more records"); + equal(recordArray.get('length'), emptyLength, "Has no more records"); store.push(Person, { id: 2, name: 'brohuda' }); }); - equal(recordArray.get('length'), undefined, "Has not been updated"); + equal(recordArray.get('length'), emptyLength, "Has not been updated"); equal(recordArray.get('content'), undefined, "Has not been updated"); }); From 54286d5d015829675ca64a0fb660728828fa95dc Mon Sep 17 00:00:00 2001 From: bmac Date: Sat, 7 Feb 2015 19:40:46 -0500 Subject: [PATCH 0613/2527] Fix jscs spacing violations revealed by the latest version of jscs --- .../active_model_serializer_test.js | 6 +-- .../lib/initializers/store_injections.js | 6 +-- .../ember-data/lib/initializers/transforms.js | 6 +-- .../lib/system/relationships/ext.js | 2 +- .../tests/integration/adapter/find_test.js | 2 +- .../tests/integration/inverse_test.js | 2 +- .../embedded_records_mixin_test.js | 4 +- .../serializers/json_serializer_test.js | 2 +- .../serializers/rest_serializer_test.js | 6 +-- .../tests/integration/setup-container-test.js | 2 +- .../tests/unit/store/adapter_interop_test.js | 6 +-- .../ember-data/tests/unit/store/push_test.js | 4 +- .../tests/unit/transform/boolean_test.js | 38 +++++++++---------- .../tests/unit/transform/date_test.js | 12 +++--- .../tests/unit/transform/number_test.js | 28 +++++++------- .../tests/unit/transform/string_test.js | 12 +++--- 16 files changed, 69 insertions(+), 69 deletions(-) diff --git a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js index e7840993214..18394f56596 100644 --- a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js +++ b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js @@ -128,7 +128,7 @@ test("normalize links", function() { var json = env.amsSerializer.normalize(HomePlanet, home_planet, "homePlanet"); - equal(json.links.superVillains, "/api/super_villians/1", "normalize links"); + equal(json.links.superVillains, "/api/super_villians/1", "normalize links"); }); test("extractSingle", function() { @@ -191,7 +191,7 @@ test("extractArray", function() { test("serialize polymorphic", function() { var tom, ray; run(function() { - tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); + tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); }); @@ -208,7 +208,7 @@ test("serialize polymorphic when type key is not camelized", function() { YellowMinion.typeKey = 'yellow-minion'; var tom, ray; run(function() { - tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); + tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); }); diff --git a/packages/ember-data/lib/initializers/store_injections.js b/packages/ember-data/lib/initializers/store_injections.js index 3f193447985..266c7424fd4 100644 --- a/packages/ember-data/lib/initializers/store_injections.js +++ b/packages/ember-data/lib/initializers/store_injections.js @@ -6,8 +6,8 @@ @param {Ember.Container} container */ export default function initializeStoreInjections(container) { - container.injection('controller', 'store', 'store:main'); - container.injection('route', 'store', 'store:main'); - container.injection('serializer', 'store', 'store:main'); + container.injection('controller', 'store', 'store:main'); + container.injection('route', 'store', 'store:main'); + container.injection('serializer', 'store', 'store:main'); container.injection('data-adapter', 'store', 'store:main'); } diff --git a/packages/ember-data/lib/initializers/transforms.js b/packages/ember-data/lib/initializers/transforms.js index de067aaa39f..e289648a688 100644 --- a/packages/ember-data/lib/initializers/transforms.js +++ b/packages/ember-data/lib/initializers/transforms.js @@ -14,7 +14,7 @@ import { */ export default function initializeTransforms(container) { container.register('transform:boolean', BooleanTransform); - container.register('transform:date', DateTransform); - container.register('transform:number', NumberTransform); - container.register('transform:string', StringTransform); + container.register('transform:date', DateTransform); + container.register('transform:number', NumberTransform); + container.register('transform:string', StringTransform); } diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index d22892575c4..70c619c21a1 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -54,7 +54,7 @@ var relatedTypesDescriptor = Ember.computed(function() { meta.key = name; type = typeForRelationshipMeta(this.store, meta); - Ember.assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", type); + Ember.assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", type); if (!types.contains(type)) { Ember.assert("Trying to sideload " + name + " on " + this.toString() + " but the type doesn't exist.", !!type); diff --git a/packages/ember-data/tests/integration/adapter/find_test.js b/packages/ember-data/tests/integration/adapter/find_test.js index c84ac3a65fc..bed21e7bbd8 100644 --- a/packages/ember-data/tests/integration/adapter/find_test.js +++ b/packages/ember-data/tests/integration/adapter/find_test.js @@ -77,7 +77,7 @@ test("When a single record is requested multiple times, all .find() calls are re deferred.promise.then(function(value) { start(); ok(true, 'expected deferred.promise to fulfill'); - },function(reason) { + }, function(reason) { start(); ok(false, 'expected deferred.promise to fulfill, but rejected'); }); diff --git a/packages/ember-data/tests/integration/inverse_test.js b/packages/ember-data/tests/integration/inverse_test.js index da8d5347a43..4950dfa0e6e 100644 --- a/packages/ember-data/tests/integration/inverse_test.js +++ b/packages/ember-data/tests/integration/inverse_test.js @@ -111,7 +111,7 @@ test("Errors out if you define 2 inverses to the same model", function () { store.push('user', { id: 1 }); }); User.inverseFor('job'); - }, "You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses"); + }, "You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses"); }); diff --git a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js index 2b20f7cb5de..e27ac9bdda0 100644 --- a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js +++ b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js @@ -62,8 +62,8 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { env.store.modelFor('evilMinion'); env.store.modelFor('comment'); env.container.register('serializer:application', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); - env.container.register('serializer:-active-model', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); - env.container.register('adapter:-active-model', DS.ActiveModelAdapter); + env.container.register('serializer:-active-model', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); + env.container.register('adapter:-active-model', DS.ActiveModelAdapter); env.amsSerializer = env.container.lookup("serializer:-active-model"); env.amsAdapter = env.container.lookup("adapter:-active-model"); }, diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index d85bf9fe34d..119bef9a5f0 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -254,7 +254,7 @@ test('Serializer respects `serialize: false` on the attrs hash', function() { var payload = env.container.lookup("serializer:post").serialize(post); ok(!payload.hasOwnProperty('title'), "Does not add the key to instance"); - ok(!payload.hasOwnProperty('[object Object]'),"Does not add some random key like [object Object]"); + ok(!payload.hasOwnProperty('[object Object]'), "Does not add some random key like [object Object]"); }); test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` property', function() { diff --git a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js index e713f8a0500..70ad75e93b8 100644 --- a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js @@ -45,7 +45,7 @@ module("integration/serializer/rest - RESTSerializer", { }, teardown: function() { - run(env.store,'destroy'); + run(env.store, 'destroy'); } }); @@ -271,7 +271,7 @@ test("pushPayload - multiple record payload (extractArray) - warning with custom test("serialize polymorphicType", function() { var tom, ray; run(function() { - tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); + tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); }); @@ -288,7 +288,7 @@ test("serialize polymorphicType with decamelized typeKey", function() { YellowMinion.typeKey = 'yellow-minion'; var tom, ray; run(function() { - tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); + tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); }); diff --git a/packages/ember-data/tests/integration/setup-container-test.js b/packages/ember-data/tests/integration/setup-container-test.js index ccf613342d0..21447b31044 100644 --- a/packages/ember-data/tests/integration/setup-container-test.js +++ b/packages/ember-data/tests/integration/setup-container-test.js @@ -65,5 +65,5 @@ test("the deprecated adapter:_rest is resolved as adapter:rest", function() { test("a deprecation is made when looking up adapter:_rest", function() { expectDeprecation(function() { container.lookup('serializer:_default'); - },"You tried to look up 'serializer:_default', but this has been deprecated in favor of 'serializer:-default'."); + }, "You tried to look up 'serializer:_default', but this has been deprecated in favor of 'serializer:-default'."); }); diff --git a/packages/ember-data/tests/unit/store/adapter_interop_test.js b/packages/ember-data/tests/unit/store/adapter_interop_test.js index dd2cc4473ac..82c946c1de1 100644 --- a/packages/ember-data/tests/unit/store/adapter_interop_test.js +++ b/packages/ember-data/tests/unit/store/adapter_interop_test.js @@ -46,9 +46,9 @@ test("Calling Store#find invokes its adapter#find", function() { find: function(store, type, id, record) { ok(true, "Adapter#find was called"); equal(store, currentStore, "Adapter#find was called with the right store"); - equal(type, currentType, "Adapter#find was called with the type passed into Store#find"); - equal(id, 1, "Adapter#find was called with the id passed into Store#find"); - equal(record.get('id'), '1', "Adapter#find was called with the record created from Store#find"); + equal(type, currentType, "Adapter#find was called with the type passed into Store#find"); + equal(id, 1, "Adapter#find was called with the id passed into Store#find"); + equal(record.get('id'), '1', "Adapter#find was called with the record created from Store#find"); return Ember.RSVP.resolve({ id: 1 }); } diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index f6045294b01..10c8ebd1fa4 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -483,7 +483,7 @@ test('Calling push with a link for a non async relationship should warn', functi } }); }); - }, /You have pushed a record of type 'person' with 'phoneNumbers' as a link, but the association is not an async relationship./); + }, /You have pushed a record of type 'person' with 'phoneNumbers' as a link, but the association is not an async relationship./); }); test('Calling push with a link containing an object throws an assertion error', function() { @@ -502,7 +502,7 @@ test('Calling push with a link containing an object throws an assertion error', } }); }); - }, "You have pushed a record of type 'person' with 'phoneNumbers' as a link, but the value of that link is not a string."); + }, "You have pushed a record of type 'person' with 'phoneNumbers' as a link, but the value of that link is not a string."); }); test('Calling push with a link containing the value null', function() { diff --git a/packages/ember-data/tests/unit/transform/boolean_test.js b/packages/ember-data/tests/unit/transform/boolean_test.js index dd2ac139a43..ec1b563a92c 100644 --- a/packages/ember-data/tests/unit/transform/boolean_test.js +++ b/packages/ember-data/tests/unit/transform/boolean_test.js @@ -3,36 +3,36 @@ module("unit/transform - DS.BooleanTransform"); test("#serialize", function() { var transform = new DS.BooleanTransform(); - equal(transform.serialize(null), false); + equal(transform.serialize(null), false); equal(transform.serialize(undefined), false); - equal(transform.serialize(true), true); - equal(transform.serialize(false), false); + equal(transform.serialize(true), true); + equal(transform.serialize(false), false); }); test("#deserialize", function() { var transform = new DS.BooleanTransform(); - equal(transform.deserialize(null), false); + equal(transform.deserialize(null), false); equal(transform.deserialize(undefined), false); - equal(transform.deserialize(true), true); - equal(transform.deserialize(false), false); + equal(transform.deserialize(true), true); + equal(transform.deserialize(false), false); - equal(transform.deserialize("true"), true); - equal(transform.deserialize("TRUE"), true); - equal(transform.deserialize("false"), false); - equal(transform.deserialize("FALSE"), false); + equal(transform.deserialize("true"), true); + equal(transform.deserialize("TRUE"), true); + equal(transform.deserialize("false"), false); + equal(transform.deserialize("FALSE"), false); - equal(transform.deserialize("t"), true); - equal(transform.deserialize("T"), true); - equal(transform.deserialize("f"), false); - equal(transform.deserialize("F"), false); + equal(transform.deserialize("t"), true); + equal(transform.deserialize("T"), true); + equal(transform.deserialize("f"), false); + equal(transform.deserialize("F"), false); - equal(transform.deserialize("1"), true); - equal(transform.deserialize("0"), false); + equal(transform.deserialize("1"), true); + equal(transform.deserialize("0"), false); - equal(transform.deserialize(1), true); - equal(transform.deserialize(2), false); - equal(transform.deserialize(0), false); + equal(transform.deserialize(1), true); + equal(transform.deserialize(2), false); + equal(transform.deserialize(0), false); }); diff --git a/packages/ember-data/tests/unit/transform/date_test.js b/packages/ember-data/tests/unit/transform/date_test.js index dfa465c6838..ce20af6f7c2 100644 --- a/packages/ember-data/tests/unit/transform/date_test.js +++ b/packages/ember-data/tests/unit/transform/date_test.js @@ -7,7 +7,7 @@ var date = new Date(dateInMillis); test("#serialize", function() { var transform = new DS.DateTransform(); - equal(transform.serialize(null), null); + equal(transform.serialize(null), null); equal(transform.serialize(undefined), null); equal(transform.serialize(date), dateString); @@ -17,15 +17,15 @@ test("#deserialize", function() { var transform = new DS.DateTransform(); // from String - equal(transform.deserialize(dateString).toISOString(), dateString); + equal(transform.deserialize(dateString).toISOString(), dateString); // from Number - equal(transform.deserialize(dateInMillis).valueOf(), dateInMillis); + equal(transform.deserialize(dateInMillis).valueOf(), dateInMillis); // from other - equal(transform.deserialize({}), null); + equal(transform.deserialize({}), null); // from none - equal(transform.deserialize(null), null); - equal(transform.deserialize(undefined), null); + equal(transform.deserialize(null), null); + equal(transform.deserialize(undefined), null); }); diff --git a/packages/ember-data/tests/unit/transform/number_test.js b/packages/ember-data/tests/unit/transform/number_test.js index 81f880f41cb..909d71c1b65 100644 --- a/packages/ember-data/tests/unit/transform/number_test.js +++ b/packages/ember-data/tests/unit/transform/number_test.js @@ -5,25 +5,25 @@ module("unit/transform - DS.NumberTransform"); test("#serialize", function() { var transform = new DS.NumberTransform(); - equal(transform.serialize(null), null); - equal(transform.serialize(undefined), null); - equal(transform.serialize("1.1"), 1.1); - equal(transform.serialize(1.1), 1.1); + equal(transform.serialize(null), null); + equal(transform.serialize(undefined), null); + equal(transform.serialize("1.1"), 1.1); + equal(transform.serialize(1.1), 1.1); equal(transform.serialize(new Number(1.1)), 1.1); - equal(transform.serialize(NaN), null); - equal(transform.serialize(Infinity), null); - equal(transform.serialize(-Infinity), null); + equal(transform.serialize(NaN), null); + equal(transform.serialize(Infinity), null); + equal(transform.serialize(-Infinity), null); }); test("#deserialize", function() { var transform = new DS.NumberTransform(); - equal(transform.deserialize(null), null); - equal(transform.deserialize(undefined), null); - equal(transform.deserialize("1.1"), 1.1); - equal(transform.deserialize(1.1), 1.1); + equal(transform.deserialize(null), null); + equal(transform.deserialize(undefined), null); + equal(transform.deserialize("1.1"), 1.1); + equal(transform.deserialize(1.1), 1.1); equal(transform.deserialize(new Number(1.1)), 1.1); - equal(transform.deserialize(NaN), null); - equal(transform.deserialize(Infinity), null); - equal(transform.deserialize(-Infinity), null); + equal(transform.deserialize(NaN), null); + equal(transform.deserialize(Infinity), null); + equal(transform.deserialize(-Infinity), null); }); diff --git a/packages/ember-data/tests/unit/transform/string_test.js b/packages/ember-data/tests/unit/transform/string_test.js index 2334f7edc4a..80a7d84f39d 100644 --- a/packages/ember-data/tests/unit/transform/string_test.js +++ b/packages/ember-data/tests/unit/transform/string_test.js @@ -3,19 +3,19 @@ module("unit/transform - DS.StringTransform"); test("#serialize", function() { var transform = new DS.StringTransform(); - equal(transform.serialize(null), null); + equal(transform.serialize(null), null); equal(transform.serialize(undefined), null); - equal(transform.serialize("foo"), "foo"); - equal(transform.serialize(1), "1"); + equal(transform.serialize("foo"), "foo"); + equal(transform.serialize(1), "1"); }); test("#deserialize", function() { var transform = new DS.StringTransform(); - equal(transform.deserialize(null), null); + equal(transform.deserialize(null), null); equal(transform.deserialize(undefined), null); - equal(transform.deserialize("foo"), "foo"); - equal(transform.deserialize(1), "1"); + equal(transform.deserialize("foo"), "foo"); + equal(transform.deserialize(1), "1"); }); From 868a62561a00a0b5481333d91996677044ab6f27 Mon Sep 17 00:00:00 2001 From: johanneswuerbach Date: Sat, 7 Feb 2015 22:03:56 +0100 Subject: [PATCH 0614/2527] Fixed appveyor Install latest npm 2 Use files to filter (inputFiles was not used) Bundle jscs (to avoid windows path errors) Moved broccoli-jscs to devDependencies --- Brocfile.js | 3 +-- appveyor.yml | 2 +- package.json | 9 ++++----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Brocfile.js b/Brocfile.js index e574759ba69..b7a243ddfdb 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -128,13 +128,12 @@ testFiles = concat(testFiles, { var testRunner = pickFiles('tests', { srcDir: '/', - inputFiles: [ '**/*' ], + files: [ '**/*' ], destDir: '/' }); var bower = pickFiles('bower_components', { srcDir: '/', - inputFiles: [ '**/*' ], destDir: '/bower_components' }); diff --git a/appveyor.yml b/appveyor.yml index 4aa36a9f3f1..a4d5e80208b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,7 +19,7 @@ install: - dir C:\tools\PhantomJS # Typical npm stuff. - md C:\nc - - npm install -g "npm@2.1.17" + - npm install -g npm@^2 - npm config set cache C:\nc - npm version - npm install diff --git a/package.json b/package.json index 3430a92353d..2ee39547110 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "build:production": "ember build --environment=production", "prepublish": "bower install && npm run-script build:production", "start": "ember serve", - "test": "node_modules/broccoli-jscs/node_modules/jscs/bin/jscs packages && testem -R dot ci", + "test": "jscs packages && testem -R dot ci", "publish-build": "npm run build:production && ./bin/publish_to_s3.js", "test:local": "testem -R dot ci", "test:beta": "testem -f config/testem-beta.json -R dot ci", @@ -37,11 +37,12 @@ "broccoli-es6-transpiler": "^0.1.0", "broccoli-file-creator": "^0.1.0", "broccoli-file-mover": "~0.2.0", + "broccoli-jscs": "0.0.14", "broccoli-jshint": "^0.5.1", "broccoli-merge-trees": "^0.1.4", "broccoli-render-template": "0.0.3", - "broccoli-static-compiler": "^0.2.1", "broccoli-replace": "~0.2.0", + "broccoli-static-compiler": "^0.2.1", "broccoli-uglify-js": "^0.1.3", "broccoli-wrap": "0.0.2", "broccoli-yuidoc": "^1.3.0", @@ -53,10 +54,8 @@ "es6-module-transpiler-amd-formatter": "^0.2.4", "es6-module-transpiler-package-resolver": "^1.0.1", "git-repo-version": "0.0.2", + "jscs": "^1.11.0", "testem": "^0.6.19", "yuidocjs": "~0.3.46" - }, - "dependencies": { - "broccoli-jscs": "0.0.12" } } From 3db20e8d12dca2c4eddf71906fdcf62cdd27a563 Mon Sep 17 00:00:00 2001 From: johanneswuerbach Date: Sun, 8 Feb 2015 10:30:34 +0100 Subject: [PATCH 0615/2527] Removed unnecessary commands from travis The npm install prepublish hook is already doing bower install and a production build --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 09e6e42467c..e36b3fef12f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,6 @@ before_install: - "npm install -g npm@^2" install: - "npm install" -- "bower install" -- "npm run-script build:production" script: - npm run-script test - npm run-script test:beta From bba27cccd5d333afb4be0d7b83d7018550306471 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 28 Jan 2015 23:17:39 +0100 Subject: [PATCH 0616/2527] Added save() to ManyArray --- .../lib/system/record_arrays/many_array.js | 29 +++++++++++++++++++ .../ember-data/tests/unit/many_array_test.js | 27 +++++++++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 41d5ce8a979..c30de30470e 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -1,6 +1,7 @@ /** @module ember-data */ +import { PromiseArray } from "ember-data/system/promise_proxies"; var get = Ember.get; var set = Ember.set; @@ -185,6 +186,34 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { return this.relationship.reload(); }, + /** + Saves all of the records in the `ManyArray`. + + Example + + ```javascript + store.find('inbox', 1).then(function(inbox) { + inbox.get('messages').then(function(messages) { + messages.forEach(function(message) { + message.set('isRead', true); + }); + messages.save() + }); + }); + ``` + + @method save + @return {DS.PromiseArray} promise + */ + save: function() { + var promiseLabel = "DS: ManyArray#save " + get(this, 'type'); + var promise = Ember.RSVP.all(this.invoke("save"), promiseLabel).then(function(array) { + return Ember.A(array); + }, null, "DS: ManyArray#save apply Ember.NativeArray"); + + return PromiseArray.create({ promise: promise }); + }, + /** Create a child record within the owner diff --git a/packages/ember-data/tests/unit/many_array_test.js b/packages/ember-data/tests/unit/many_array_test.js index 689e5819471..ee91b2151e6 100644 --- a/packages/ember-data/tests/unit/many_array_test.js +++ b/packages/ember-data/tests/unit/many_array_test.js @@ -4,9 +4,11 @@ var hasMany = DS.hasMany; var belongsTo = DS.belongsTo; var run = Ember.run; +var Post, Tag; + module("unit/many_array - DS.ManyArray", { setup: function() { - var Post = DS.Model.extend({ + Post = DS.Model.extend({ title: attr('string'), tags: hasMany('tag') }); @@ -14,7 +16,7 @@ module("unit/many_array - DS.ManyArray", { return 'Post'; }; - var Tag = DS.Model.extend({ + Tag = DS.Model.extend({ name: attr('string'), post: belongsTo('post') }); @@ -36,6 +38,27 @@ module("unit/many_array - DS.ManyArray", { } }); +test("manyArray.save() calls save() on all records", function() { + expect(3); + + run(function() { + Tag.reopen({ + save: function() { + ok(true, 'record.save() was called'); + return Ember.RSVP.resolve(); + } + }); + + store.push('tag', { id: 1, name: 'Ember.js' }); + store.push('tag', { id: 2, name: 'Tomster' }); + + var post = store.push('post', { id: 3, title: 'A framework for creating ambitious web applications', tags: [1, 2] }); + post.get('tags').save().then(function() { + ok(true, 'manyArray.save() promise resolved'); + }); + }); +}); + test("manyArray.addRecord() has been deprecated", function() { expect(3); From 75f790ca32e49d66eb69f60eee130b3687c9e8cb Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Thu, 29 Jan 2015 15:02:28 +0100 Subject: [PATCH 0617/2527] Make ManyArray.save() and RecordArray.save() return themselves --- packages/ember-data/lib/system/record_arrays/many_array.js | 5 +++-- packages/ember-data/lib/system/record_arrays/record_array.js | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index c30de30470e..fa25c4e3be5 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -206,10 +206,11 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { @return {DS.PromiseArray} promise */ save: function() { + var manyArray = this; var promiseLabel = "DS: ManyArray#save " + get(this, 'type'); var promise = Ember.RSVP.all(this.invoke("save"), promiseLabel).then(function(array) { - return Ember.A(array); - }, null, "DS: ManyArray#save apply Ember.NativeArray"); + return manyArray; + }, null, "DS: ManyArray#save return ManyArray"); return PromiseArray.create({ promise: promise }); }, diff --git a/packages/ember-data/lib/system/record_arrays/record_array.js b/packages/ember-data/lib/system/record_arrays/record_array.js index 2f5789cb243..84c2d2a1109 100644 --- a/packages/ember-data/lib/system/record_arrays/record_array.js +++ b/packages/ember-data/lib/system/record_arrays/record_array.js @@ -179,10 +179,11 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @return {DS.PromiseArray} promise */ save: function() { + var recordArray = this; var promiseLabel = "DS: RecordArray#save " + get(this, 'type'); var promise = Ember.RSVP.all(this.invoke("save"), promiseLabel).then(function(array) { - return Ember.A(array); - }, null, "DS: RecordArray#save apply Ember.NativeArray"); + return recordArray; + }, null, "DS: RecordArray#save return RecordArray"); return PromiseArray.create({ promise: promise }); }, From 732a751e517698008a7a27dacc923c15c8fefe9f Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Fri, 23 Jan 2015 00:06:07 +0100 Subject: [PATCH 0618/2527] Add a Serializer base class --- packages/ember-data/lib/main.js | 3 + .../lib/serializers/json_serializer.js | 5 +- packages/ember-data/lib/system/serializer.js | 74 +++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 packages/ember-data/lib/system/serializer.js diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index f5195d3be18..1d5300d1c8d 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -36,6 +36,7 @@ import { InvalidError, Adapter } from "ember-data/system/adapter"; +import Serializer from "ember-data/system/serializer"; import DebugAdapter from "ember-data/system/debug"; import { RecordArray, @@ -86,6 +87,8 @@ DS.Errors = Errors; DS.Adapter = Adapter; DS.InvalidError = InvalidError; +DS.Serializer = Serializer; + DS.DebugAdapter = DebugAdapter; DS.RecordArray = RecordArray; diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 3bbb2394981..6fb82aba34c 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -1,3 +1,5 @@ +import Serializer from "ember-data/system/serializer"; + var get = Ember.get; var isNone = Ember.isNone; var map = Ember.ArrayPolyfills.map; @@ -17,8 +19,9 @@ var merge = Ember.merge; @class JSONSerializer @namespace DS + @extends DS.Serializer */ -export default Ember.Object.extend({ +export default Serializer.extend({ /** The primaryKey is used when serializing and deserializing data. Ember Data always uses the `id` property to store the id of diff --git a/packages/ember-data/lib/system/serializer.js b/packages/ember-data/lib/system/serializer.js new file mode 100644 index 00000000000..5bf571c15d6 --- /dev/null +++ b/packages/ember-data/lib/system/serializer.js @@ -0,0 +1,74 @@ +/** + @module ember-data +*/ + +/** + `DS.Serializer` is an abstract base class that you should override in your + application to customize it for your backend. The minimum set of methods + that you should implement is: + + * `extract()` + * `serialize()` + + And you can optionally override the following methods: + + * `normalize()` + + For an example implementation, see + [DS.JSONSerializer](DS.JSONSerializer.html), the included JSON serializer. + + @class Serializer + @namespace DS + @extends Ember.Object +*/ + +var Serializer = Ember.Object.extend({ + + /** + The `extract` method is used to deserialize the payload received from your + data source into the form that Ember Data expects. + + @method extract + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} + */ + extract: Ember.required(Function), + + /** + The `serialize` method is used when a record is saved in order to convert + the record into the form that your external data source expects. + + `serialize` takes an optional `options` hash with a single option: + + - `includeId`: If this is `true`, `serialize` should include the ID + in the serialized object it builds. + + @method serialize + @param {subclass of DS.Model} record + @param {Object} [options] + @return {Object} + */ + serialize: Ember.required(Function), + + /** + The `normalize` method is used to convert a payload received from your + external data source into the normalized form `store.push()` expects. You + should override this method, munge the hash and return the normalized + payload. + + @method normalize + @param {subclass of DS.Model} type + @param {Object} hash + @return {Object} + */ + normalize: function(type, hash) { + return hash; + } + +}); + +export default Serializer; From 644e118f34afc982361e6c74b257e3b11d6e5479 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 12 Nov 2014 20:34:48 +0100 Subject: [PATCH 0619/2527] Dematerialize rejected _find() if record isEmpty --- packages/ember-data/lib/system/store.js | 3 +++ .../tests/integration/adapter/find_test.js | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 008e2d856e9..78bc1911968 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1911,6 +1911,9 @@ function _find(adapter, store, type, id, record) { var record = store.getById(type, id); if (record) { record.notFound(); + if (get(record, 'isEmpty')) { + store.dematerializeRecord(record); + } } throw error; }, "DS: Extract payload of '" + type + "'"); diff --git a/packages/ember-data/tests/integration/adapter/find_test.js b/packages/ember-data/tests/integration/adapter/find_test.js index bed21e7bbd8..716b4b37493 100644 --- a/packages/ember-data/tests/integration/adapter/find_test.js +++ b/packages/ember-data/tests/integration/adapter/find_test.js @@ -120,3 +120,22 @@ test("When a single record is requested, and the promise is rejected, .find() is })); }); }); + +test("When a single record is requested, and the promise is rejected, the record should be dematerialized.", function() { + expect(2); + + store = createStore({ adapter: DS.Adapter.extend({ + find: function(store, type, id) { + return Ember.RSVP.reject(); + } + }) + }); + + run(function() { + store.find(Person, 1).then(null, async(function(reason) { + ok(true, "The rejection handler was called"); + })); + }); + + ok(!store.hasRecordForId(Person, 1), "The record has been dematerialized"); +}); From ad1db92c76874dd9d325fb89f077a4588ed10395 Mon Sep 17 00:00:00 2001 From: johanneswuerbach Date: Mon, 9 Feb 2015 13:04:50 +0100 Subject: [PATCH 0620/2527] Use latest node 0.10 release Use node version specified in environment Use upgraded npm --- appveyor.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index a4d5e80208b..cd7a9d90a11 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,7 +12,7 @@ environment: # Install scripts. (runs after repo cloning) install: # Get the latest stable version of Node 0.STABLE.latest - - ps: Install-Product node 0.10.30 x86 + - ps: Install-Product node $env:nodejs_version # Install PhantomJS - cinst PhantomJS - set path=%path%;C:\tools\PhantomJS\ @@ -20,6 +20,8 @@ install: # Typical npm stuff. - md C:\nc - npm install -g npm@^2 + # Workaround https://github.com/npm/npm/wiki/Troubleshooting#upgrading-on-windows + - set PATH=%APPDATA%\npm;%PATH% - npm config set cache C:\nc - npm version - npm install From 1ee712bd932c11e89a9ad419bfd4715ca6329655 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Tue, 10 Feb 2015 16:33:22 -0500 Subject: [PATCH 0621/2527] Replace calls to `container` with `registry` `Ember.Registry` has not yet landed on `stable`, but floods the console with deprecation warnings for `beta` and `canary`. This PR replaces all calls of `env.container.register` with `env.registry.register` throughout the test suite. When the Registry is available, it will handle registration. Otherwise, it will defer to the Container. --- .../active_model_serializer_test.js | 14 +- .../adapter/fixture_adapter_test.js | 2 +- .../integration/adapter/rest_adapter_test.js | 36 ++--- .../integration/record_array_manager_test.js | 4 +- .../tests/integration/records/reload_test.js | 4 +- .../relationships/belongs_to_test.js | 14 +- .../embedded_records_mixin_test.js | 130 +++++++++--------- .../serializers/json_serializer_test.js | 34 ++--- .../serializers/rest_serializer_test.js | 18 +-- .../unit/model/relationships/has_many_test.js | 12 +- .../ember-data/tests/unit/store/push_test.js | 18 +-- tests/ember_configuration.js | 30 ++-- 12 files changed, 158 insertions(+), 158 deletions(-) diff --git a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js index 18394f56596..6aeef0cfac1 100644 --- a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js +++ b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js @@ -41,9 +41,9 @@ module("integration/active_model - ActiveModelSerializer", { env.store.modelFor('yellowMinion'); env.store.modelFor('doomsdayDevice'); env.store.modelFor('mediocreVillain'); - env.container.register('serializer:application', DS.ActiveModelSerializer); - env.container.register('serializer:-active-model', DS.ActiveModelSerializer); - env.container.register('adapter:-active-model', DS.ActiveModelAdapter); + env.registry.register('serializer:application', DS.ActiveModelSerializer); + env.registry.register('serializer:-active-model', DS.ActiveModelSerializer); + env.registry.register('adapter:-active-model', DS.ActiveModelAdapter); env.amsSerializer = env.container.lookup("serializer:-active-model"); env.amsAdapter = env.container.lookup("adapter:-active-model"); }, @@ -132,7 +132,7 @@ test("normalize links", function() { }); test("extractSingle", function() { - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); var json_hash = { home_planet: { id: "1", name: "Umber", super_villain_ids: [1] }, @@ -163,7 +163,7 @@ test("extractSingle", function() { }); test("extractArray", function() { - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); var array; var json_hash = { @@ -228,7 +228,7 @@ test("serialize polymorphic when associated object is null", function() { }); test("extractPolymorphic hasMany", function() { - env.container.register('adapter:yellowMinion', DS.ActiveModelAdapter); + env.registry.register('adapter:yellowMinion', DS.ActiveModelAdapter); MediocreVillain.toString = function() { return "MediocreVillain"; }; YellowMinion.toString = function() { return "YellowMinion"; }; @@ -253,7 +253,7 @@ test("extractPolymorphic hasMany", function() { }); test("extractPolymorphic", function() { - env.container.register('adapter:yellowMinion', DS.ActiveModelAdapter); + env.registry.register('adapter:yellowMinion', DS.ActiveModelAdapter); EvilMinion.toString = function() { return "EvilMinion"; }; YellowMinion.toString = function() { return "YellowMinion"; }; diff --git a/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js b/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js index d5543f9b329..185766c8566 100644 --- a/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/fixture_adapter_test.js @@ -290,7 +290,7 @@ asyncTest("copies fixtures instead of passing the direct reference", function() }); Ember.run(function() { - env.container.register('adapter:person', PersonAdapter); + env.registry.register('adapter:person', PersonAdapter); }); env.store.find('person', 1).then(function() { diff --git a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js index 430424718e9..d8ea749e65c 100644 --- a/packages/ember-data/tests/integration/adapter/rest_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/rest_adapter_test.js @@ -111,7 +111,7 @@ test("find - payload with sideloaded records of a different type", function() { test("find - payload with an serializer-specified primary key", function() { - env.container.register('serializer:post', DS.RESTSerializer.extend({ + env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_' })); @@ -128,7 +128,7 @@ test("find - payload with an serializer-specified primary key", function() { }); test("find - payload with a serializer-specified attribute mapping", function() { - env.container.register('serializer:post', DS.RESTSerializer.extend({ + env.registry.register('serializer:post', DS.RESTSerializer.extend({ attrs: { 'name': '_NAME_', 'createdAt': { key: '_CREATED_AT_', someOtherOption: 'option' } @@ -234,7 +234,7 @@ test("create - findMany doesn't overwrite owner", function() { test("create - a serializer's primary key and attributes are consulted when building the payload", function() { var post; - env.container.register('serializer:post', DS.RESTSerializer.extend({ + env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_id_', attrs: { @@ -255,7 +255,7 @@ test("create - a serializer's primary key and attributes are consulted when buil test("create - a serializer's attributes are consulted when building the payload if no id is pre-defined", function() { var post; - env.container.register('serializer:post', DS.RESTSerializer.extend({ + env.registry.register('serializer:post', DS.RESTSerializer.extend({ primarykey: '_id_', attrs: { @@ -275,7 +275,7 @@ test("create - a serializer's attributes are consulted when building the payload }); test("create - a serializer's attribute mapping takes precdence over keyForAttribute when building the payload", function() { - env.container.register('serializer:post', DS.RESTSerializer.extend({ + env.registry.register('serializer:post', DS.RESTSerializer.extend({ attrs: { name: 'given_name' }, @@ -297,7 +297,7 @@ test("create - a serializer's attribute mapping takes precdence over keyForAttri }); test("create - a serializer's attribute mapping takes precedence over keyForRelationship (belongsTo) when building the payload", function() { - env.container.register('serializer:comment', DS.RESTSerializer.extend({ + env.registry.register('serializer:comment', DS.RESTSerializer.extend({ attrs: { post: 'article' }, @@ -322,7 +322,7 @@ test("create - a serializer's attribute mapping takes precedence over keyForRela }); test("create - a serializer's attribute mapping takes precedence over keyForRelationship (hasMany) when building the payload", function() { - env.container.register('serializer:post', DS.RESTSerializer.extend({ + env.registry.register('serializer:post', DS.RESTSerializer.extend({ attrs: { comments: 'opinions' }, @@ -601,7 +601,7 @@ test("update - a payload with sideloaded updates pushes the updates", function() }); test("update - a serializer's primary key and attributes are consulted when building the payload", function() { - env.container.register('serializer:post', DS.RESTSerializer.extend({ + env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_id_', attrs: { @@ -761,7 +761,7 @@ test("findAll - returning sideloaded data loads the data", function() { }); test("findAll - data is normalized through custom serializers", function() { - env.container.register('serializer:post', DS.RESTSerializer.extend({ + env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', attrs: { name: '_NAME_' } })); @@ -985,7 +985,7 @@ test("findQuery - returning sideloaded data loads the data", function() { }); test("findQuery - data is normalized through custom serializers", function() { - env.container.register('serializer:post', DS.RESTSerializer.extend({ + env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', attrs: { name: '_NAME_' } })); @@ -1139,12 +1139,12 @@ test("findMany - returning sideloaded data loads the data", function() { }); test("findMany - a custom serializer is used if present", function() { - env.container.register('serializer:post', DS.RESTSerializer.extend({ + env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', attrs: { name: '_NAME_' } })); - env.container.register('serializer:comment', DS.RESTSerializer.extend({ + env.registry.register('serializer:comment', DS.RESTSerializer.extend({ primaryKey: '_ID_', attrs: { name: '_NAME_' } })); @@ -1258,12 +1258,12 @@ test("findMany - returning sideloaded data loads the data", function() { }); test("findMany - a custom serializer is used if present", function() { - env.container.register('serializer:post', DS.RESTSerializer.extend({ + env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', attrs: { name: '_NAME_' } })); - env.container.register('serializer:comment', DS.RESTSerializer.extend({ + env.registry.register('serializer:comment', DS.RESTSerializer.extend({ primaryKey: '_ID_', attrs: { name: '_NAME_' } })); @@ -1617,7 +1617,7 @@ test('groupRecordsForFindMany groups records correctly when singular URLs are en }); test('normalizeKey - to set up _ids and _id', function() { - env.container.register('serializer:application', DS.RESTSerializer.extend({ + env.registry.register('serializer:application', DS.RESTSerializer.extend({ keyForAttribute: function(attr) { return Ember.String.underscore(attr); }, @@ -1636,19 +1636,19 @@ test('normalizeKey - to set up _ids and _id', function() { } })); - env.container.register('model:post', DS.Model.extend({ + env.registry.register('model:post', DS.Model.extend({ name: DS.attr(), authorName: DS.attr(), author: DS.belongsTo('user'), comments: DS.hasMany('comment') })); - env.container.register('model:user', DS.Model.extend({ + env.registry.register('model:user', DS.Model.extend({ createdAt: DS.attr(), name: DS.attr() })); - env.container.register('model:comment', DS.Model.extend({ + env.registry.register('model:comment', DS.Model.extend({ body: DS.attr() })); diff --git a/packages/ember-data/tests/integration/record_array_manager_test.js b/packages/ember-data/tests/integration/record_array_manager_test.js index e04f550fc09..b58f002f78a 100644 --- a/packages/ember-data/tests/integration/record_array_manager_test.js +++ b/packages/ember-data/tests/integration/record_array_manager_test.js @@ -27,8 +27,8 @@ module("integration/record_array_manager- destroy", { manager = store.recordArrayManager; - env.container.register('model:car', Car); - env.container.register('model:person', Person); + env.registry.register('model:car', Car); + env.registry.register('model:person', Person); } }); diff --git a/packages/ember-data/tests/integration/records/reload_test.js b/packages/ember-data/tests/integration/records/reload_test.js index 0dbca0c9b59..625d1ec1633 100644 --- a/packages/ember-data/tests/integration/records/reload_test.js +++ b/packages/ember-data/tests/integration/records/reload_test.js @@ -103,12 +103,12 @@ test("When a record is loaded a second time, isLoaded stays true", function() { }); test("When a record is reloaded, its async hasMany relationships still work", function() { - env.container.register('model:person', DS.Model.extend({ + env.registry.register('model:person', DS.Model.extend({ name: DS.attr(), tags: DS.hasMany('tag', { async: true }) })); - env.container.register('model:tag', DS.Model.extend({ + env.registry.register('model:tag', DS.Model.extend({ name: DS.attr() })); diff --git a/packages/ember-data/tests/integration/relationships/belongs_to_test.js b/packages/ember-data/tests/integration/relationships/belongs_to_test.js index 29f3fc87e40..ff2319b0358 100644 --- a/packages/ember-data/tests/integration/relationships/belongs_to_test.js +++ b/packages/ember-data/tests/integration/relationships/belongs_to_test.js @@ -63,7 +63,7 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { author: Author }); - env.container.register('serializer:user', DS.JSONSerializer.extend({ + env.registry.register('serializer:user', DS.JSONSerializer.extend({ attrs: { favouriteMessage: { embedded: 'always' } } @@ -201,8 +201,8 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to group: DS.belongsTo({ async: true }) }); - env.container.register('model:group', Group); - env.container.register('model:person', Person); + env.registry.register('model:group', Group); + env.registry.register('model:person', Person); run(function() { store.push('person', { id: 1, links: { group: '/people/1/group' } }); @@ -239,8 +239,8 @@ test('A record with an async belongsTo relationship always returns a promise for seat: DS.belongsTo('seat', { async: true }) }); - env.container.register('model:seat', Seat); - env.container.register('model:person', Person); + env.registry.register('model:seat', Seat); + env.registry.register('model:person', Person); run(function() { store.push('person', { id: 1, links: { seat: '/people/1/seat' } }); @@ -277,8 +277,8 @@ test("A record with an async belongsTo relationship returning null should resolv group: DS.belongsTo({ async: true }) }); - env.container.register('model:group', Group); - env.container.register('model:person', Person); + env.registry.register('model:group', Group); + env.registry.register('model:person', Person); run(function() { store.push('person', { id: 1, links: { group: '/people/1/group' } }); diff --git a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js index e27ac9bdda0..b0979009712 100644 --- a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js +++ b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js @@ -61,9 +61,9 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { env.store.modelFor('lightSaber'); env.store.modelFor('evilMinion'); env.store.modelFor('comment'); - env.container.register('serializer:application', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); - env.container.register('serializer:-active-model', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); - env.container.register('adapter:-active-model', DS.ActiveModelAdapter); + env.registry.register('serializer:application', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); + env.registry.register('serializer:-active-model', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); + env.registry.register('adapter:-active-model', DS.ActiveModelAdapter); env.amsSerializer = env.container.lookup("serializer:-active-model"); env.amsAdapter = env.container.lookup("adapter:-active-model"); }, @@ -74,8 +74,8 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { }); test("extractSingle with embedded objects", function() { - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' } } @@ -112,13 +112,13 @@ test("extractSingle with embedded objects", function() { }); test("extractSingle with embedded objects inside embedded objects", function() { - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' } } })); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { evilMinions: { embedded: 'always' } } @@ -164,8 +164,8 @@ test("extractSingle with embedded objects inside embedded objects", function() { }); test("extractSingle with embedded objects of same type", function() { - env.container.register('adapter:comment', DS.ActiveModelAdapter); - env.container.register('serializer:comment', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:comment', DS.ActiveModelAdapter); + env.registry.register('serializer:comment', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { children: { embedded: 'always' } } @@ -205,8 +205,8 @@ test("extractSingle with embedded objects of same type", function() { }); test("extractSingle with embedded objects inside embedded objects of same type", function() { - env.container.register('adapter:comment', DS.ActiveModelAdapter); - env.container.register('serializer:comment', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:comment', DS.ActiveModelAdapter); + env.registry.register('serializer:comment', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { children: { embedded: 'always' } } @@ -258,8 +258,8 @@ test("extractSingle with embedded objects of same type, but from separate attrib reformedVillains: DS.hasMany('superVillain', { inverse: null }) }); - env.container.register('adapter:home_planet', DS.ActiveModelAdapter); - env.container.register('serializer:home_planet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:home_planet', DS.ActiveModelAdapter); + env.registry.register('serializer:home_planet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' }, reformedVillains: { embedded: 'always' } @@ -306,8 +306,8 @@ test("extractSingle with embedded objects of same type, but from separate attrib }); test("extractArray with embedded objects", function() { - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' } } @@ -347,11 +347,11 @@ test("extractArray with embedded objects", function() { test("extractArray with embedded objects with custom primary key", function() { expect(2); - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend({ + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend({ primaryKey: 'villain_id' })); - env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' } } @@ -391,8 +391,8 @@ test("extractArray with embedded objects with custom primary key", function() { }); test("extractArray with embedded objects with identical relationship and attribute key ", function() { expect(2); - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' } }, @@ -434,8 +434,8 @@ test("extractArray with embedded objects with identical relationship and attribu }); }); test("extractArray with embedded objects of same type as primary type", function() { - env.container.register('adapter:comment', DS.ActiveModelAdapter); - env.container.register('serializer:comment', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:comment', DS.ActiveModelAdapter); + env.registry.register('serializer:comment', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { children: { embedded: 'always' } } @@ -482,8 +482,8 @@ test("extractArray with embedded objects of same type, but from separate attribu reformedVillains: DS.hasMany('superVillain') }); - env.container.register('adapter:homePlanet', DS.ActiveModelAdapter); - env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:homePlanet', DS.ActiveModelAdapter); + env.registry.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' }, reformedVillains: { embedded: 'always' } @@ -559,7 +559,7 @@ test("serialize supports serialize:false on non-relationship properties", functi tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", id: '1' }); }); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { firstName: { serialize: false } } @@ -584,7 +584,7 @@ test("serialize with embedded objects (hasMany relationship)", function() { tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); }); - env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' } } @@ -615,7 +615,7 @@ test("serialize with embedded objects (hasMany relationship) supports serialize: env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); }); - env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { serialize: false } } @@ -638,7 +638,7 @@ test("serialize with (new) embedded objects (hasMany relationship)", function() env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league }); }); - env.container.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('serializer:homePlanet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' } } @@ -669,7 +669,7 @@ test("serialize with embedded objects (hasMany relationships, including related superVillain.get('secretWeapons').pushObject(secretWeapon); }); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { evilMinions: { serialize: 'records', deserialize: 'records' }, secretWeapons: { serialize: 'ids' } @@ -697,8 +697,8 @@ test("serialize with embedded objects (hasMany relationships, including related test("extractSingle with embedded object (belongsTo relationship)", function() { expect(4); - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { embedded: 'always' } } @@ -747,8 +747,8 @@ test("extractSingle with embedded object (belongsTo relationship)", function() { }); test("serialize with embedded object (belongsTo relationship)", function() { - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { embedded: 'always' } } @@ -785,14 +785,14 @@ test("serialize with embedded object (belongsTo relationship)", function() { }); test("serialize with embedded object (belongsTo relationship) works with different primaryKeys", function() { - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { primaryKey: '_id', attrs: { secretLab: { embedded: 'always' } } })); - env.container.register('serializer:secretLab', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('serializer:secretLab', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { primaryKey: 'crazy_id' })); @@ -828,8 +828,8 @@ test("serialize with embedded object (belongsTo relationship) works with differe }); test("serialize with embedded object (belongsTo relationship, new no id)", function() { - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { embedded: 'always' } } @@ -866,8 +866,8 @@ test("serialize with embedded object (belongsTo relationship, new no id)", funct }); test("serialize with embedded object (belongsTo relationship) supports serialize:ids", function() { - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { serialize: 'ids' } } @@ -900,8 +900,8 @@ test("serialize with embedded object (belongsTo relationship) supports serialize }); test("serialize with embedded object (belongsTo relationship) supports serialize:id", function() { - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { serialize: 'id' } } @@ -935,8 +935,8 @@ test("serialize with embedded object (belongsTo relationship) supports serialize }); test("serialize with embedded object (belongsTo relationship) supports serialize:false", function() { - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { serialize: false } } @@ -967,8 +967,8 @@ test("serialize with embedded object (belongsTo relationship) supports serialize }); test("serialize with embedded object (belongsTo relationship) serializes the id by default if no option specified", function() { - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); var serializer = env.container.lookup("serializer:superVillain"); // records with an id, persisted @@ -998,8 +998,8 @@ test("serialize with embedded object (belongsTo relationship) serializes the id }); test("when related record is not present, serialize embedded record (with a belongsTo relationship) as null", function() { - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { embedded: 'always' } } @@ -1029,13 +1029,13 @@ test("when related record is not present, serialize embedded record (with a belo }); test("extractSingle with multiply-nested belongsTo", function() { - env.container.register('adapter:evilMinion', DS.ActiveModelAdapter); - env.container.register('serializer:evilMinion', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:evilMinion', DS.ActiveModelAdapter); + env.registry.register('serializer:evilMinion', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { superVillain: { embedded: 'always' } } })); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { homePlanet: { embedded: 'always' } } @@ -1080,8 +1080,8 @@ test("extractSingle with polymorphic hasMany", function() { secretWeapons: DS.hasMany("secretWeapon", { polymorphic: true }) }); - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretWeapons: { embedded: 'always' } } @@ -1137,8 +1137,8 @@ test("extractSingle with polymorphic belongsTo", function() { secretLab: DS.belongsTo("secretLab", { polymorphic: true }) }); - env.container.register('adapter:superVillain', DS.ActiveModelAdapter); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { embedded: 'always' } } @@ -1189,9 +1189,9 @@ test("Mixin can be used with RESTSerializer which does not define keyForAttribut superVillain.get('evilMinions').pushObject(evilMinion); }); - env.container.register('serializer:evilMinion', DS.RESTSerializer); - env.container.register('serializer:secretWeapon', DS.RESTSerializer); - env.container.register('serializer:superVillain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('serializer:evilMinion', DS.RESTSerializer); + env.registry.register('serializer:secretWeapon', DS.RESTSerializer); + env.registry.register('serializer:superVillain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { evilMinions: { serialize: 'records', deserialize: 'records' } } @@ -1219,13 +1219,13 @@ test("Mixin can be used with RESTSerializer which does not define keyForAttribut }); test("normalize with custom belongsTo primary key", function() { - env.container.register('adapter:evilMinion', DS.ActiveModelAdapter); - env.container.register('serializer:evilMinion', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('adapter:evilMinion', DS.ActiveModelAdapter); + env.registry.register('serializer:evilMinion', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { superVillain: { embedded: 'always' } } })); - env.container.register('serializer:superVillain', DS.ActiveModelSerializer.extend({ + env.registry.register('serializer:superVillain', DS.ActiveModelSerializer.extend({ primaryKey: 'custom' })); @@ -1289,9 +1289,9 @@ test("serializing relationships with an embedded and without calls super when no } } }); - env.container.register('serializer:evilMinion', Serializer); - env.container.register('serializer:secretWeapon', Serializer); - env.container.register('serializer:superVillain', Serializer.extend(DS.EmbeddedRecordsMixin, { + env.registry.register('serializer:evilMinion', Serializer); + env.registry.register('serializer:secretWeapon', Serializer); + env.registry.register('serializer:superVillain', Serializer.extend(DS.EmbeddedRecordsMixin, { attrs: { evilMinions: { serialize: 'records', deserialize: 'records' } // some relationships are not listed here, so super should be called on those diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index 119bef9a5f0..90b1601358c 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -39,7 +39,7 @@ test("serializeAttribute", function() { }); test("serializeAttribute respects keyForAttribute", function() { - env.container.register('serializer:post', DS.JSONSerializer.extend({ + env.registry.register('serializer:post', DS.JSONSerializer.extend({ keyForAttribute: function(key) { return key.toUpperCase(); } @@ -99,7 +99,7 @@ test("async serializeBelongsTo with null", function() { }); test("serializeBelongsTo respects keyForRelationship", function() { - env.container.register('serializer:post', DS.JSONSerializer.extend({ + env.registry.register('serializer:post', DS.JSONSerializer.extend({ keyForRelationship: function(key, type) { return key.toUpperCase(); } @@ -118,7 +118,7 @@ test("serializeBelongsTo respects keyForRelationship", function() { }); test("serializeHasMany respects keyForRelationship", function() { - env.container.register('serializer:post', DS.JSONSerializer.extend({ + env.registry.register('serializer:post', DS.JSONSerializer.extend({ keyForRelationship: function(key, type) { return key.toUpperCase(); } @@ -154,7 +154,7 @@ test("serializeIntoHash", function() { }); test("serializePolymorphicType", function() { - env.container.register('serializer:comment', DS.JSONSerializer.extend({ + env.registry.register('serializer:comment', DS.JSONSerializer.extend({ serializePolymorphicType: function(record, json, relationship) { var key = relationship.key; var belongsTo = get(record, key); @@ -184,7 +184,7 @@ test("extractArray normalizes each record in the array", function() { { title: "Another Post" } ]; - env.container.register('serializer:post', DS.JSONSerializer.extend({ + env.registry.register('serializer:post', DS.JSONSerializer.extend({ normalize: function () { postNormalizeCount++; return this._super.apply(this, arguments); @@ -198,7 +198,7 @@ test("extractArray normalizes each record in the array", function() { }); test('Serializer should respect the attrs hash when extracting records', function() { - env.container.register("serializer:post", DS.JSONSerializer.extend({ + env.registry.register("serializer:post", DS.JSONSerializer.extend({ attrs: { title: "title_payload_key", comments: { key: 'my_comments' } @@ -220,7 +220,7 @@ test('Serializer should respect the attrs hash when serializing records', functi Post.reopen({ parentPost: DS.belongsTo('post') }); - env.container.register("serializer:post", DS.JSONSerializer.extend({ + env.registry.register("serializer:post", DS.JSONSerializer.extend({ attrs: { title: "title_payload_key", parentPost: { key: "my_parent" } @@ -241,7 +241,7 @@ test('Serializer should respect the attrs hash when serializing records', functi test('Serializer respects `serialize: false` on the attrs hash', function() { expect(2); - env.container.register("serializer:post", DS.JSONSerializer.extend({ + env.registry.register("serializer:post", DS.JSONSerializer.extend({ attrs: { title: { serialize: false } } @@ -259,7 +259,7 @@ test('Serializer respects `serialize: false` on the attrs hash', function() { test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` property', function() { expect(1); - env.container.register("serializer:post", DS.JSONSerializer.extend({ + env.registry.register("serializer:post", DS.JSONSerializer.extend({ attrs: { comments: { serialize: false } } @@ -279,7 +279,7 @@ test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` p test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` property', function() { expect(1); - env.container.register("serializer:comment", DS.JSONSerializer.extend({ + env.registry.register("serializer:comment", DS.JSONSerializer.extend({ attrs: { post: { serialize: false } } @@ -298,7 +298,7 @@ test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` }); test("Serializer should respect the primaryKey attribute when extracting records", function() { - env.container.register('serializer:post', DS.JSONSerializer.extend({ + env.registry.register('serializer:post', DS.JSONSerializer.extend({ primaryKey: '_ID_' })); @@ -313,7 +313,7 @@ test("Serializer should respect the primaryKey attribute when extracting records }); test("Serializer should respect the primaryKey attribute when serializing records", function() { - env.container.register('serializer:post', DS.JSONSerializer.extend({ + env.registry.register('serializer:post', DS.JSONSerializer.extend({ primaryKey: '_ID_' })); @@ -327,7 +327,7 @@ test("Serializer should respect the primaryKey attribute when serializing record }); test("Serializer should respect keyForAttribute when extracting records", function() { - env.container.register('serializer:post', DS.JSONSerializer.extend({ + env.registry.register('serializer:post', DS.JSONSerializer.extend({ keyForAttribute: function(key) { return key.toUpperCase(); } @@ -342,7 +342,7 @@ test("Serializer should respect keyForAttribute when extracting records", functi }); test("Serializer should respect keyForRelationship when extracting records", function() { - env.container.register('serializer:post', DS.JSONSerializer.extend({ + env.registry.register('serializer:post', DS.JSONSerializer.extend({ keyForRelationship: function(key, type) { return key.toUpperCase(); } @@ -356,7 +356,7 @@ test("Serializer should respect keyForRelationship when extracting records", fun }); test("normalizePayload is called during extractSingle", function() { - env.container.register('serializer:post', DS.JSONSerializer.extend({ + env.registry.register('serializer:post', DS.JSONSerializer.extend({ normalizePayload: function(payload) { return payload.response; } @@ -382,14 +382,14 @@ test("Calling normalize should normalize the payload (only the passed keys)", fu var Person = DS.Model.extend({ posts: DS.hasMany('post') }); - env.container.register('serializer:post', DS.JSONSerializer.extend({ + env.registry.register('serializer:post', DS.JSONSerializer.extend({ attrs: { notInHash: 'aCustomAttrNotInHash', inHash: 'aCustomAttrInHash' } })); - env.container.register('model:person', Person); + env.registry.register('model:person', Person); Post.reopen({ content: DS.attr('string'), diff --git a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js index 70ad75e93b8..c0d77fdedc8 100644 --- a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js @@ -170,7 +170,7 @@ test("pushPayload - single record payload - warning with custom typeForRoot", fu } }); - env.container.register("serializer:homePlanet", HomePlanetRestSerializer); + env.registry.register("serializer:homePlanet", HomePlanetRestSerializer); var jsonHash = { home_planet: { id: "1", name: "Umber", superVillains: [1] }, @@ -226,7 +226,7 @@ test("pushPayload - multiple record payload (extractArray) - warning with custom } }); - env.container.register("serializer:homePlanet", HomePlanetRestSerializer); + env.registry.register("serializer:homePlanet", HomePlanetRestSerializer); var jsonHash = { home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], @@ -298,7 +298,7 @@ test("serialize polymorphicType with decamelized typeKey", function() { }); test("normalizePayload is called during extractSingle", function() { - env.container.register('serializer:application', DS.RESTSerializer.extend({ + env.registry.register('serializer:application', DS.RESTSerializer.extend({ normalizePayload: function(payload) { return payload.response; } @@ -362,7 +362,7 @@ test("extractArray can load secondary records of the same type without affecting test("extractSingle loads secondary records with correct serializer", function() { var superVillainNormalizeCount = 0; - env.container.register('serializer:superVillain', DS.RESTSerializer.extend({ + env.registry.register('serializer:superVillain', DS.RESTSerializer.extend({ normalize: function() { superVillainNormalizeCount++; return this._super.apply(this, arguments); @@ -399,7 +399,7 @@ test("extractSingle returns null if payload contains null", function() { test("extractArray loads secondary records with correct serializer", function() { var superVillainNormalizeCount = 0; - env.container.register('serializer:superVillain', DS.RESTSerializer.extend({ + env.registry.register('serializer:superVillain', DS.RESTSerializer.extend({ normalize: function() { superVillainNormalizeCount++; return this._super.apply(this, arguments); @@ -419,7 +419,7 @@ test("extractArray loads secondary records with correct serializer", function() }); test('normalizeHash normalizes specific parts of the payload', function() { - env.container.register('serializer:application', DS.RESTSerializer.extend({ + env.registry.register('serializer:application', DS.RESTSerializer.extend({ normalizeHash: { homePlanets: function(hash) { hash.id = hash._id; @@ -446,7 +446,7 @@ test('normalizeHash normalizes specific parts of the payload', function() { }); test('normalizeHash works with transforms', function() { - env.container.register('serializer:application', DS.RESTSerializer.extend({ + env.registry.register('serializer:application', DS.RESTSerializer.extend({ normalizeHash: { evilMinions: function(hash) { hash.condition = hash._condition; @@ -456,7 +456,7 @@ test('normalizeHash works with transforms', function() { } })); - env.container.register('transform:condition', DS.Transform.extend({ + env.registry.register('transform:condition', DS.Transform.extend({ deserialize: function(serialized) { if (serialized === 1) { return "healing"; @@ -488,7 +488,7 @@ test('normalizeHash works with transforms', function() { }); test('normalize should allow for different levels of normalization', function() { - env.container.register('serializer:application', DS.RESTSerializer.extend({ + env.registry.register('serializer:application', DS.RESTSerializer.extend({ attrs: { superVillain: 'is_super_villain' }, diff --git a/packages/ember-data/tests/unit/model/relationships/has_many_test.js b/packages/ember-data/tests/unit/model/relationships/has_many_test.js index ab5e02fb788..609ee787176 100644 --- a/packages/ember-data/tests/unit/model/relationships/has_many_test.js +++ b/packages/ember-data/tests/unit/model/relationships/has_many_test.js @@ -27,9 +27,9 @@ test("hasMany handles pre-loaded relationships", function() { pets: DS.hasMany('pet') }); - env.container.register('model:tag', Tag); - env.container.register('model:pet', Pet); - env.container.register('model:person', Person); + env.registry.register('model:tag', Tag); + env.registry.register('model:pet', Pet); + env.registry.register('model:person', Person); env.adapter.find = function(store, type, id) { if (type === Tag && id === '12') { @@ -114,9 +114,9 @@ test("hasMany lazily loads async relationships", function() { pets: DS.hasMany('pet') }); - env.container.register('model:tag', Tag); - env.container.register('model:pet', Pet); - env.container.register('model:person', Person); + env.registry.register('model:tag', Tag); + env.registry.register('model:pet', Pet); + env.registry.register('model:person', Person); env.adapter.find = function(store, type, id) { if (type === Tag && id === '12') { diff --git a/packages/ember-data/tests/unit/store/push_test.js b/packages/ember-data/tests/unit/store/push_test.js index 10c8ebd1fa4..2202c1ac379 100644 --- a/packages/ember-data/tests/unit/store/push_test.js +++ b/packages/ember-data/tests/unit/store/push_test.js @@ -38,7 +38,7 @@ module("unit/store/push - DS.Store#push", { store = env.store; - env.container.register('serializer:post', DS.ActiveModelSerializer); + env.registry.register('serializer:post', DS.ActiveModelSerializer); }, teardown: function() { @@ -72,7 +72,7 @@ test("Supplying a model class for `push` is the same as supplying a string", fun expect(1); var Programmer = Person.extend(); - env.container.register('model:programmer', Programmer); + env.registry.register('model:programmer', Programmer); run(function() { store.push(Programmer, { @@ -144,7 +144,7 @@ test("Calling push with partial records updates just those attributes", function }); test("Calling push on normalize allows partial updates with raw JSON", function () { - env.container.register('serializer:person', DS.RESTSerializer); + env.registry.register('serializer:person', DS.RESTSerializer); var person; run(function() { @@ -323,13 +323,13 @@ test("Calling pushPayload allows pushing singular payload properties", function test("Calling pushPayload should use the type's serializer for normalizing", function () { expect(4); - env.container.register('serializer:post', DS.RESTSerializer.extend({ + env.registry.register('serializer:post', DS.RESTSerializer.extend({ normalize: function(store, payload) { ok(true, "normalized is called on Post serializer"); return this._super(store, payload); } })); - env.container.register('serializer:person', DS.RESTSerializer.extend({ + env.registry.register('serializer:person', DS.RESTSerializer.extend({ normalize: function(store, payload) { ok(true, "normalized is called on Person serializer"); return this._super(store, payload); @@ -361,7 +361,7 @@ test("Calling pushPayload should use the type's serializer for normalizing", fun test("Calling pushPayload without a type uses application serializer's pushPayload method", function () { expect(1); - env.container.register('serializer:application', DS.RESTSerializer.extend({ + env.registry.register('serializer:application', DS.RESTSerializer.extend({ pushPayload: function(store, payload) { ok(true, "pushPayload is called on Application serializer"); return this._super(store, payload); @@ -378,14 +378,14 @@ test("Calling pushPayload without a type uses application serializer's pushPaylo test("Calling pushPayload without a type should use a model's serializer when normalizing", function () { expect(4); - env.container.register('serializer:post', DS.RESTSerializer.extend({ + env.registry.register('serializer:post', DS.RESTSerializer.extend({ normalize: function(store, payload) { ok(true, "normalized is called on Post serializer"); return this._super(store, payload); } })); - env.container.register('serializer:application', DS.RESTSerializer.extend({ + env.registry.register('serializer:application', DS.RESTSerializer.extend({ normalize: function(store, payload) { ok(true, "normalized is called on Application serializer"); return this._super(store, payload); @@ -415,7 +415,7 @@ test("Calling pushPayload without a type should use a model's serializer when no }); test("Calling pushPayload allows partial updates with raw JSON", function () { - env.container.register('serializer:person', DS.RESTSerializer); + env.registry.register('serializer:person', DS.RESTSerializer); var person; diff --git a/tests/ember_configuration.js b/tests/ember_configuration.js index a5e962dd66e..2235b8c2486 100644 --- a/tests/ember_configuration.js +++ b/tests/ember_configuration.js @@ -47,19 +47,19 @@ }; window.setupStore = function(options) { + var container, registry; + var emberChannel = QUnit.urlParams.emberchannel || "release"; var env = {}; options = options || {}; - var container = env.container = new Ember.Container(); - - // We have to currently work around some container refactors until - // https://github.com/emberjs/ember.js/pull/9981 is on the stable release - // of ember - if (typeof Ember.Registry !== 'undefined') { - var registry = new Ember.Registry(); - container._registry = registry; - env.registry = registry; + if (emberChannel.match(/^beta|canary$/i)) { + registry = env.registry = new Ember.Registry(); + container = env.container = registry.container(); + } else { + container = env.container = new Ember.Container(); + registry = env.registry = container; } + env.replaceContainerNormalize = function replaceContainerNormalize(fn) { if (env.registry) { env.registry.normalize = fn; @@ -72,18 +72,18 @@ delete options.adapter; for (var prop in options) { - container.register('model:' + prop, options[prop]); + registry.register('model:' + prop, options[prop]); } - container.register('store:main', DS.Store.extend({ + registry.register('store:main', DS.Store.extend({ adapter: adapter })); - container.register('serializer:-default', DS.JSONSerializer); - container.register('serializer:-rest', DS.RESTSerializer); - container.register('adapter:-rest', DS.RESTAdapter); + registry.register('serializer:-default', DS.JSONSerializer); + registry.register('serializer:-rest', DS.RESTSerializer); + registry.register('adapter:-rest', DS.RESTAdapter); - container.injection('serializer', 'store', 'store:main'); + registry.injection('serializer', 'store', 'store:main'); env.serializer = container.lookup('serializer:-default'); env.restSerializer = container.lookup('serializer:-rest'); From edb755fbee8ae47ada648874da78a5ee18095384 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 11 Feb 2015 07:58:54 +0100 Subject: [PATCH 0622/2527] Add adapter.hasMany unique IDs test --- .../relationships/has_many_test.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index fd33231e490..a6f11926784 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -103,6 +103,27 @@ test("When a hasMany relationship is accessed, the adapter's findMany method sho }); }); +test("adapter.findMany only gets unique IDs even if duplicate IDs are present in the hasMany relationship", function() { + expect(2); + + env.adapter.findMany = function(store, type, ids, records) { + equal(type, Chapter, 'type passed to adapter.findMany is correct'); + deepEqual(ids, ['2', '3'], 'ids passed to adapter.findMany are unique'); + + return Ember.RSVP.resolve([ + { id: 2, title: 'Chapter One' }, + { id: 3, title: 'Chapter Two' } + ]); + }; + + run(function() { + env.store.push('book', { id: 1, chapters: [2, 3, 3] }); + env.store.find('book', 1).then(function(book) { + return book.get('chapters'); + }); + }); +}); + // This tests the case where a serializer materializes a has-many // relationship as a reference that it can fetch lazily. The most // common use case of this is to provide a URL to a collection that From 51b7e0c54a4ddeb6ffe61828007a7b428c0e7be3 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 11 Feb 2015 07:26:49 -0500 Subject: [PATCH 0623/2527] upgrade qunit (now we can filter tests/modules) --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 49726752b60..5a9f9f7ed67 100644 --- a/bower.json +++ b/bower.json @@ -5,7 +5,7 @@ "ember": "~1.9.0" }, "devDependencies": { - "qunit": "~1.16.0", + "qunit": "~1.17.0", "jquery": "~1.10.x", "handlebars": ">= 2.0.0 < 3.0.0", "loader.js": "~1.0.0", From f33498fbadc6f5019760a41f3609a4527a81d255 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 11 Feb 2015 17:27:02 -0600 Subject: [PATCH 0624/2527] bump ember-inflector dependency for HTMLBars compat --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 5a9f9f7ed67..d947597b298 100644 --- a/bower.json +++ b/bower.json @@ -9,7 +9,7 @@ "jquery": "~1.10.x", "handlebars": ">= 2.0.0 < 3.0.0", "loader.js": "~1.0.0", - "ember-inflector": "https://github.com/stefanpenner/ember-inflector.git#v1.2.0", + "ember-inflector": "https://github.com/stefanpenner/ember-inflector.git#v1.4.0", "es5-shim": "~4.0.3" }, "resolutions": { From 82ff318eb962f7088df4449930d8b1c252015a63 Mon Sep 17 00:00:00 2001 From: Chester Law Date: Wed, 11 Feb 2015 17:46:28 -0800 Subject: [PATCH 0625/2527] Add missing backquote --- packages/ember-data/lib/serializers/json_serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 3bbb2394981..68e6ded18a8 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -986,7 +986,7 @@ export default Ember.Object.extend({ /** `extractErrors` is used to extract model errors when a call is made - to `DS.Model#save` which fails with an InvalidError`. By default + to `DS.Model#save` which fails with an `InvalidError`. By default Ember Data expects error information to be located on the `errors` property of the payload object. From cf2dcd8e0b559687863d3e205c1a263c3b3891ac Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 19 Jan 2015 16:39:01 -0500 Subject: [PATCH 0626/2527] Warn if the user specifies a reflexive relationship without explicitly defining the inverse --- .../lib/system/relationships/ext.js | 5 +++- .../tests/integration/filter_test.js | 2 +- .../tests/integration/inverse_test.js | 24 ++++++++++++++++--- .../relationships/has_many_test.js | 2 +- .../relationships/one_to_one_test.js | 2 +- .../embedded_records_mixin_test.js | 2 +- .../serializers/json_serializer_test.js | 2 +- .../serializers/rest_serializer_test.js | 2 +- .../tests/unit/model/relationships_test.js | 2 +- .../tests/unit/store/adapter_interop_test.js | 8 +++---- 10 files changed, 36 insertions(+), 15 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 70c619c21a1..9b02eeddc7c 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -228,12 +228,15 @@ Model.reopenClass({ return null; } + var propertyMeta = this.metaForProperty(name); //If inverse is manually specified to be null, like `comments: DS.hasMany('message', {inverse: null})` - var options = this.metaForProperty(name).options; + var options = propertyMeta.options; if (options.inverse === null) { return null; } var inverseName, inverseKind, inverse; + Ember.warn("Detected a reflexive relationship by the name of '" + name + "' without an inverse option. Look at http://emberjs.com/guides/models/defining-models/#toc_reflexive-relation for how to explicitly specify inverses.", options.inverse || propertyMeta.type !== propertyMeta.parentType.typeKey); + //If inverse is specified manually, return the inverse if (options.inverse) { inverseName = options.inverse; diff --git a/packages/ember-data/tests/integration/filter_test.js b/packages/ember-data/tests/integration/filter_test.js index eb6b2aea9bb..85716709621 100644 --- a/packages/ember-data/tests/integration/filter_test.js +++ b/packages/ember-data/tests/integration/filter_test.js @@ -17,7 +17,7 @@ var shouldNotContain = function(array, item) { module("integration/filter - DS.Model updating", { setup: function() { array = [{ id: 1, name: "Scumbag Dale", bestFriend: 2 }, { id: 2, name: "Scumbag Katz" }, { id: 3, name: "Scumbag Bryn" }]; - Person = DS.Model.extend({ name: DS.attr('string'), bestFriend: DS.belongsTo('person') }); + Person = DS.Model.extend({ name: DS.attr('string'), bestFriend: DS.belongsTo('person', { inverse: null }) }); env = setupStore({ person: Person }); store = env.store; diff --git a/packages/ember-data/tests/integration/inverse_test.js b/packages/ember-data/tests/integration/inverse_test.js index 4950dfa0e6e..107adffc71c 100644 --- a/packages/ember-data/tests/integration/inverse_test.js +++ b/packages/ember-data/tests/integration/inverse_test.js @@ -1,4 +1,4 @@ -var env, store, User, Job; +var env, store, User, Job, ReflexiveModel; var attr = DS.attr; var belongsTo = DS.belongsTo; @@ -12,7 +12,7 @@ module('integration/inverse_test - inverseFor', { setup: function() { User = DS.Model.extend({ name: attr('string'), - bestFriend: belongsTo('user', { async: true }), + bestFriend: belongsTo('user', { async: true, inverse: null }), job: belongsTo('job') }); @@ -25,9 +25,16 @@ module('integration/inverse_test - inverseFor', { Job.toString = stringify('job'); + ReflexiveModel = DS.Model.extend({ + reflexiveProp: belongsTo('reflexiveModel') + }); + + ReflexiveModel.toString = stringify('reflexiveModel'); + env = setupStore({ user: User, - job: Job + job: Job, + reflexiveModel: ReflexiveModel }); store = env.store; @@ -129,3 +136,14 @@ test("Caches findInverseFor return value", function () { equal(inverseForUser, Job.inverseFor('user'), 'Inverse cached succesfully'); }); + +test("Errors out if you do not define an inverse for a reflexive relationship", function () { + + //Maybe store is evaluated lazily, so we need this :( + warns(function() { + var reflexiveModel; + run(function() { + reflexiveModel = store.push('reflexiveModel', { id: 1 }); + }); + }, /Detected a reflexive relationship by the name of 'reflexiveProp'/); +}); diff --git a/packages/ember-data/tests/integration/relationships/has_many_test.js b/packages/ember-data/tests/integration/relationships/has_many_test.js index fd33231e490..ec59e8689ac 100644 --- a/packages/ember-data/tests/integration/relationships/has_many_test.js +++ b/packages/ember-data/tests/integration/relationships/has_many_test.js @@ -17,7 +17,7 @@ module("integration/relationships/has_many - Has-Many Relationships", { User = DS.Model.extend({ name: attr('string'), messages: hasMany('message', { polymorphic: true }), - contacts: hasMany() + contacts: hasMany('user', { inverse: null }) }); Contact = DS.Model.extend({ diff --git a/packages/ember-data/tests/integration/relationships/one_to_one_test.js b/packages/ember-data/tests/integration/relationships/one_to_one_test.js index a267c45d23c..93388845ffa 100644 --- a/packages/ember-data/tests/integration/relationships/one_to_one_test.js +++ b/packages/ember-data/tests/integration/relationships/one_to_one_test.js @@ -12,7 +12,7 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', { setup: function() { User = DS.Model.extend({ name: attr('string'), - bestFriend: belongsTo('user', { async: true }), + bestFriend: belongsTo('user', { async: true, inverse: 'bestFriend' }), job: belongsTo('job') }); User.toString = stringify('User'); diff --git a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js index e27ac9bdda0..1d34dc64f76 100644 --- a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js +++ b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js @@ -41,7 +41,7 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { Comment = DS.Model.extend({ body: DS.attr('string'), root: DS.attr('boolean'), - children: DS.hasMany('comment') + children: DS.hasMany('comment', { inverse: null }) }); env = setupStore({ superVillain: SuperVillain, diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index 119bef9a5f0..2e3b508257e 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -218,7 +218,7 @@ test('Serializer should respect the attrs hash when extracting records', functio test('Serializer should respect the attrs hash when serializing records', function() { Post.reopen({ - parentPost: DS.belongsTo('post') + parentPost: DS.belongsTo('post', { inverse: null }) }); env.container.register("serializer:post", DS.JSONSerializer.extend({ attrs: { diff --git a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js index 70ad75e93b8..9bac5d5a008 100644 --- a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js @@ -26,7 +26,7 @@ module("integration/serializer/rest - RESTSerializer", { Comment = DS.Model.extend({ body: DS.attr('string'), root: DS.attr('boolean'), - children: DS.hasMany('comment') + children: DS.hasMany('comment', { inverse: null }) }); env = setupStore({ superVillain: SuperVillain, diff --git a/packages/ember-data/tests/unit/model/relationships_test.js b/packages/ember-data/tests/unit/model/relationships_test.js index 8166e97097a..f110aefd703 100644 --- a/packages/ember-data/tests/unit/model/relationships_test.js +++ b/packages/ember-data/tests/unit/model/relationships_test.js @@ -12,7 +12,7 @@ test("exposes a hash of the relationships on a model", function() { Person.reopen({ people: DS.hasMany('person', { inverse: 'parent' }), - parent: DS.belongsTo('person') + parent: DS.belongsTo('person', { inverse: 'people' }) }); var store = createStore({ diff --git a/packages/ember-data/tests/unit/store/adapter_interop_test.js b/packages/ember-data/tests/unit/store/adapter_interop_test.js index 82c946c1de1..b221c75b0bd 100644 --- a/packages/ember-data/tests/unit/store/adapter_interop_test.js +++ b/packages/ember-data/tests/unit/store/adapter_interop_test.js @@ -389,7 +389,7 @@ test("initial values of belongsTo can be passed in as the third argument to find var Person = DS.Model.extend({ name: DS.attr('string'), - friend: DS.belongsTo('person') + friend: DS.belongsTo('person', { inverse: null }) }); store.container.register('model:person', Person); @@ -418,7 +418,7 @@ test("initial values of belongsTo can be passed in as the third argument to find var Person = DS.Model.extend({ name: DS.attr('string'), - friend: DS.belongsTo('person', { async: true }) + friend: DS.belongsTo('person', { async: true, inverse: null }) }); store.container.register('model:person', Person); @@ -445,7 +445,7 @@ test("initial values of hasMany can be passed in as the third argument to find a var Person = DS.Model.extend({ name: DS.attr('string'), - friends: DS.hasMany('person') + friends: DS.hasMany('person', { inverse: null }) }); store.container.register('model:person', Person); @@ -474,7 +474,7 @@ test("initial values of hasMany can be passed in as the third argument to find a var Person = DS.Model.extend({ name: DS.attr('string'), - friends: DS.hasMany('person', { async: true }) + friends: DS.hasMany('person', { async: true, inverse: null }) }); store.container.register('model:person', Person); From e60be25f7cd28a9453fd20f2a748e9ca92c11e91 Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 12 Feb 2015 18:16:08 -0500 Subject: [PATCH 0627/2527] Correctly trigger arrayContentDidChange when updating hasMany relationships Closes #2713 --- .../lib/system/record_arrays/many_array.js | 5 +-- .../ember-data/tests/unit/many_array_test.js | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 41d5ce8a979..431e4b0da94 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -74,10 +74,11 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { return record.get('isNew'); }); toSet = toSet.concat(newRecords); - this.arrayContentWillChange(0, this.length, this.length); + var oldLength = this.length; + this.arrayContentWillChange(0, this.length, toSet.length); this.set('length', toSet.length); this.currentState = toSet; - this.arrayContentDidChange(0, this.length, this.length); + this.arrayContentDidChange(0, oldLength, this.length); //TODO Figure out to notify only on additions and maybe only if unloaded this.relationship.notifyHasManyChanged(); this.record.updateRecordArrays(); diff --git a/packages/ember-data/tests/unit/many_array_test.js b/packages/ember-data/tests/unit/many_array_test.js index 689e5819471..73bc80eee19 100644 --- a/packages/ember-data/tests/unit/many_array_test.js +++ b/packages/ember-data/tests/unit/many_array_test.js @@ -66,3 +66,37 @@ test("manyArray.removeRecord() has been deprecated", function() { equal(tags.length, 0, 'there should not be any tags'); }); }); + + +test("manyArray trigger arrayContentChange functions with the correct values", function() { + expect(12); + var willChangeStartIdx; + var willChangeRemoveAmt; + var willChangeAddAmt; + var originalArrayContentWillChange = DS.ManyArray.prototype.arrayContentWillChange; + var originalArrayContentDidChange = DS.ManyArray.prototype.arrayContentDidChange; + DS.ManyArray.reopen({ + arrayContentWillChange: function(startIdx, removeAmt, addAmt) { + willChangeStartIdx = startIdx; + willChangeRemoveAmt = removeAmt; + willChangeAddAmt = addAmt; + return this._super.apply(arguments); + }, + arrayContentDidChange: function(startIdx, removeAmt, addAmt) { + equal(startIdx, willChangeStartIdx, 'WillChange and DidChange startIdx should match'); + equal(removeAmt, willChangeRemoveAmt, 'WillChange and DidChange removeAmt should match'); + equal(addAmt, willChangeAddAmt, 'WillChange and DidChange addAmt should match'); + return this._super.apply(arguments); + } + }); + run(function() { + store.push('tag', { id: 1, name: 'Ember.js' }); + store.push('tag', { id: 2, name: 'Ember Data' }); + var post = store.push('post', { id: 2, title: 'A framework for creating ambitious web applications', tags: [1] }); + post = store.push('post', { id: 2, title: 'A framework for creating ambitious web applications', tags: [1, 2] }); + }); + DS.ManyArray.reopen({ + arrayContentWillChange: originalArrayContentWillChange, + arrayContentDidChange: originalArrayContentDidChange + }); +}); From 8ef9eb2c79b7e3b4a3995c2d89a8cd21c1d819d2 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Thu, 12 Feb 2015 23:26:55 +0100 Subject: [PATCH 0628/2527] Use store.unloadRecord() in favor of store.dematerializeRecord() --- packages/ember-data/lib/system/store.js | 2 +- packages/ember-data/tests/integration/adapter/find_test.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 78bc1911968..fa2c1628602 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1912,7 +1912,7 @@ function _find(adapter, store, type, id, record) { if (record) { record.notFound(); if (get(record, 'isEmpty')) { - store.dematerializeRecord(record); + store.unloadRecord(record); } } throw error; diff --git a/packages/ember-data/tests/integration/adapter/find_test.js b/packages/ember-data/tests/integration/adapter/find_test.js index 716b4b37493..ab9f02e369f 100644 --- a/packages/ember-data/tests/integration/adapter/find_test.js +++ b/packages/ember-data/tests/integration/adapter/find_test.js @@ -121,7 +121,7 @@ test("When a single record is requested, and the promise is rejected, .find() is }); }); -test("When a single record is requested, and the promise is rejected, the record should be dematerialized.", function() { +test("When a single record is requested, and the promise is rejected, the record should be unloaded.", function() { expect(2); store = createStore({ adapter: DS.Adapter.extend({ @@ -137,5 +137,5 @@ test("When a single record is requested, and the promise is rejected, the record })); }); - ok(!store.hasRecordForId(Person, 1), "The record has been dematerialized"); + ok(!store.hasRecordForId(Person, 1), "The record has been unloaded"); }); From 5b149eb4e468295f492d65b6d4126d9ebda10f16 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Thu, 12 Feb 2015 23:26:32 +0100 Subject: [PATCH 0629/2527] Deprecate store.dematerializeRecord() --- packages/ember-data/lib/system/model/states.js | 2 +- packages/ember-data/lib/system/store.js | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index 34909c26f46..b7dcd672875 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -671,7 +671,7 @@ var RootState = { setup: function(record) { var store = get(record, 'store'); - store.dematerializeRecord(record); + store._dematerializeRecord(record); }, invokeLifecycleCallbacks: function(record) { diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index fa2c1628602..cf4700fb18c 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1677,15 +1677,26 @@ Store = Ember.Object.extend({ // . DESTRUCTION . // ............... + /** + @method dematerializeRecord + @private + @param {DS.Model} record + @deprecated Use [unloadRecord](#method_unloadRecord) instead + */ + dematerializeRecord: function(record) { + Ember.deprecate('Using store.dematerializeRecord() has been deprecated since it was intended for private use only. You should use store.unloadRecord() instead.'); + this._dematerializeRecord(record); + }, + /** When a record is destroyed, this un-indexes it and removes it from any record arrays so it can be GCed. - @method dematerializeRecord + @method _dematerializeRecord @private @param {DS.Model} record */ - dematerializeRecord: function(record) { + _dematerializeRecord: function(record) { var type = record.constructor; var typeMap = this.typeMapFor(type); var id = get(record, 'id'); From 718f1ca3e41d876939ecfb30f3d038972083e11d Mon Sep 17 00:00:00 2001 From: Tony Schneider Date: Fri, 13 Feb 2015 10:59:19 -0500 Subject: [PATCH 0630/2527] remove unused code. * ManyArray doesn't appear to use the diff array --- packages/ember-data/lib/system/record_arrays/many_array.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 41d5ce8a979..c89d5bdb552 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -45,7 +45,6 @@ var set = Ember.set; export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { init: function() { this.currentState = Ember.A([]); - this.diff = []; }, record: null, @@ -53,8 +52,6 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { canonicalState: null, currentState: null, - diff: null, - length: 0, objectAt: function(index) { From cf2d8acce98890fb87bf2df0bfb43f06ae35b418 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 10 Feb 2015 15:11:01 -0500 Subject: [PATCH 0631/2527] Fix bug preventing hasMany relationships from correctly tracking simultaneous adds and removes. --- packages/ember-data/lib/system/model/states.js | 5 +++++ .../lib/system/relationships/state/has_many.js | 6 ------ .../relationships/many_to_many_test.js | 14 ++++++++++++++ packages/ember-data/tests/unit/model_test.js | 16 ++++++++++++++++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index 34909c26f46..e75f432b3ce 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -417,6 +417,11 @@ createdState.uncommitted.rollback = function(record) { record.transitionTo('deleted.saved'); }; +createdState.uncommitted.pushedData = function(record) { + record.transitionTo('loaded.updated.uncommitted'); + record.triggerLater('didLoad'); +}; + createdState.uncommitted.propertyWasReset = Ember.K; function assertAgainstUnloadRecord(record) { diff --git a/packages/ember-data/lib/system/relationships/state/has_many.js b/packages/ember-data/lib/system/relationships/state/has_many.js index f04010fc924..a8fedf4a6c5 100644 --- a/packages/ember-data/lib/system/relationships/state/has_many.js +++ b/packages/ember-data/lib/system/relationships/state/has_many.js @@ -128,8 +128,6 @@ ManyRelationship.prototype.computeChanges = function(records) { this.removeCanonicalRecords(recordsToRemove); - var hasManyArray = this.manyArray; - // Using records.toArray() since currently using // removeRecord can modify length, messing stuff up // forEach since it directly looks at "length" each @@ -138,10 +136,6 @@ ManyRelationship.prototype.computeChanges = function(records) { length = records.length; for (i = 0; i < length; i++) { record = records[i]; - //Need to preserve the order of incoming records - if (hasManyArray.objectAt(i) === record ) { - continue; - } this.removeCanonicalRecord(record); this.addCanonicalRecord(record, i); } diff --git a/packages/ember-data/tests/integration/relationships/many_to_many_test.js b/packages/ember-data/tests/integration/relationships/many_to_many_test.js index 496435cea05..94f0a22b6b1 100644 --- a/packages/ember-data/tests/integration/relationships/many_to_many_test.js +++ b/packages/ember-data/tests/integration/relationships/many_to_many_test.js @@ -270,3 +270,17 @@ test("Deleting a record that has a hasMany relationship removes it from the othe equal(account.get('users.length'), 0, 'Users got removed'); equal(user.get('accounts.length'), undefined, 'Accounts got rolledback correctly'); }); + + +test("Re-loading a removed record should re add it to the relationship when the removed record is the last one in the relationship", function () { + var account, ada, byron; + run(function() { + account = store.push('account', { id: 2 , state: 'account 1' }); + ada = store.push('user', { id: 1, name: 'Ada Lovelace', accounts: [2] }); + byron = store.push('user', { id: 2, name: 'Lord Byron', accounts: [2] }); + account.get('users').removeObject(byron); + account = store.push('account', { id: 2 , state: 'account 1', users: [1, 2] }); + }); + + equal(account.get('users.length'), 2, 'Accounts were updated correctly'); +}); diff --git a/packages/ember-data/tests/unit/model_test.js b/packages/ember-data/tests/unit/model_test.js index 4497aec35ba..5f542bacf60 100644 --- a/packages/ember-data/tests/unit/model_test.js +++ b/packages/ember-data/tests/unit/model_test.js @@ -648,3 +648,19 @@ test("A subclass of DS.Model can not use the `data` property", function() { }); }, /`data` is a reserved property name on DS.Model objects/); }); + + +test("Pushing a record into the store should transition it to the loaded state", function() { + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var store = createStore({ person: Person }); + + run(function() { + var person = store.createRecord('person', { id: 1, name: 'TomHuda' }); + equal(person.get('isNew'), true, 'createRecord should put records into the new state'); + store.push('person', { id: 1, name: 'TomHuda' }); + equal(person.get('isNew'), false, 'push should put records into the loaded state'); + }); +}); From a837175dd46d8e925ebfd92d164bdc2815c3a3ec Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 13 Feb 2015 13:10:07 -0600 Subject: [PATCH 0632/2527] Revert "Allow errors on arbitrary properties, not just defined attributes or relationships" This reverts commit 785bb284e42ba1603c2f7b6db951e0c316491054. --- packages/ember-data/lib/system/model/model.js | 10 +- .../integration/adapter/store_adapter_test.js | 91 ------------------- 2 files changed, 7 insertions(+), 94 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index cfcc3183317..40703767b69 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1066,10 +1066,14 @@ var Model = Ember.Object.extend(Ember.Evented, { */ adapterDidInvalidate: function(errors) { var recordErrors = get(this, 'errors'); - for (var key in errors) { - if (!errors.hasOwnProperty(key)) continue; - recordErrors.add(key, errors[key]); + function addError(name) { + if (errors[name]) { + recordErrors.add(name, errors[name]); + } } + + this.eachAttribute(addError); + this.eachRelationship(addError); this._saveWasRejected(); }, diff --git a/packages/ember-data/tests/integration/adapter/store_adapter_test.js b/packages/ember-data/tests/integration/adapter/store_adapter_test.js index 77f03042ef1..ea13105a8c9 100644 --- a/packages/ember-data/tests/integration/adapter/store_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/store_adapter_test.js @@ -411,48 +411,6 @@ test("if a created record is marked as invalid by the server, it enters an error }); }); -test("allows errors on arbitrary properties on create", function() { - adapter.createRecord = function(store, type, record) { - if (get(record, 'name').indexOf('Bro') === -1) { - return Ember.RSVP.reject(new DS.InvalidError({ base: ['is a generally unsavoury character'] })); - } else { - return Ember.RSVP.resolve(); - } - }; - - var yehuda = run(function () { - return store.createRecord('person', { id: 1, name: "Yehuda Katz" }); - }); - - // Wrap this in an Ember.run so that all chained async behavior is set up - // before flushing any scheduled behavior. - run(function() { - yehuda.save().then(null, async(function(error) { - equal(get(yehuda, 'isValid'), false, "the record is invalid"); - ok(get(yehuda, 'errors.base'), "The errors.base property exists"); - deepEqual(get(yehuda, 'errors').errorsFor('base'), [{attribute: 'base', message: "is a generally unsavoury character"}]); - - set(yehuda, 'updatedAt', true); - equal(get(yehuda, 'isValid'), false, "the record is still invalid"); - - set(yehuda, 'name', "Brohuda Brokatz"); - - equal(get(yehuda, 'isValid'), false, "the record is still invalid as far as we know"); - equal(get(yehuda, 'isDirty'), true, "the record has outstanding changes"); - - equal(get(yehuda, 'isNew'), true, "precond - record is still new"); - - return yehuda.save(); - })).then(async(function(person) { - strictEqual(person, yehuda, "The promise resolves with the saved record"); - ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); - deepEqual(get(yehuda, 'errors').errorsFor('base'), []); - equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); - equal(get(yehuda, 'isNew'), false, "record is no longer new"); - })); - }); -}); - test("if a created record is marked as invalid by the server, you can attempt the save again", function() { var saveCount = 0; adapter.createRecord = function(store, type, record) { @@ -559,55 +517,6 @@ test("if an updated record is marked as invalid by the server, it enters an erro }); -test("records can have errors on arbitrary properties after update", function() { - adapter.updateRecord = function(store, type, record) { - if (get(record, 'name').indexOf('Bro') === -1) { - return Ember.RSVP.reject(new DS.InvalidError({ base: ['is a generally unsavoury character'] })); - } else { - return Ember.RSVP.resolve(); - } - }; - - var yehuda = run(function() { - return store.push('person', { id: 1, name: "Brohuda Brokatz" }); - }); - - run(function() { - store.find('person', 1).then(async(function(person) { - equal(person, yehuda, "The same object is passed through"); - - equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); - set(yehuda, 'name', "Yehuda Katz"); - equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); - - equal(get(yehuda, 'isDirty'), true, "the record is dirty"); - - return yehuda.save(); - })).then(null, async(function(reason) { - equal(get(yehuda, 'isDirty'), true, "the record is still dirty"); - equal(get(yehuda, 'isValid'), false, "the record is invalid"); - ok(get(yehuda, 'errors.base'), "The errors.base property exists"); - deepEqual(get(yehuda, 'errors').errorsFor('base'), [{attribute: 'base', message: "is a generally unsavoury character"}]); - - set(yehuda, 'updatedAt', true); - equal(get(yehuda, 'isValid'), false, "the record is still invalid"); - - set(yehuda, 'name', "Brohuda Brokatz"); - equal(get(yehuda, 'isValid'), false, "the record is still invalid after changing (only server can know if it's now valid)"); - equal(get(yehuda, 'isDirty'), true, "the record has outstanding changes"); - - return yehuda.save(); - })).then(async(function(yehuda) { - equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); - equal(get(yehuda, 'isDirty'), false, "record is no longer new"); - ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); - deepEqual(get(yehuda, 'errors').errorsFor('base'), []); - })); - }); -}); - - - test("if an updated record is marked as invalid by the server, you can attempt the save again", function() { var saveCount = 0; adapter.updateRecord = function(store, type, record) { From cf077422d6d8cfd4dda38c8a597fee441823746a Mon Sep 17 00:00:00 2001 From: Alex Speller Date: Thu, 29 May 2014 12:54:55 +0100 Subject: [PATCH 0633/2527] Allow errors on arbitrary properties, not just defined attributes or relationships --- packages/ember-data/lib/system/model/model.js | 10 +- .../integration/adapter/store_adapter_test.js | 91 +++++++++++++++++++ 2 files changed, 95 insertions(+), 6 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 40703767b69..77241c312d2 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1066,14 +1066,12 @@ var Model = Ember.Object.extend(Ember.Evented, { */ adapterDidInvalidate: function(errors) { var recordErrors = get(this, 'errors'); - function addError(name) { - if (errors[name]) { - recordErrors.add(name, errors[name]); + for (var key in errors) { + if (!errors.hasOwnProperty(key)) { + continue; } + recordErrors.add(key, errors[key]); } - - this.eachAttribute(addError); - this.eachRelationship(addError); this._saveWasRejected(); }, diff --git a/packages/ember-data/tests/integration/adapter/store_adapter_test.js b/packages/ember-data/tests/integration/adapter/store_adapter_test.js index ea13105a8c9..46072ad5032 100644 --- a/packages/ember-data/tests/integration/adapter/store_adapter_test.js +++ b/packages/ember-data/tests/integration/adapter/store_adapter_test.js @@ -411,6 +411,48 @@ test("if a created record is marked as invalid by the server, it enters an error }); }); +test("allows errors on arbitrary properties on create", function() { + adapter.createRecord = function(store, type, record) { + if (get(record, 'name').indexOf('Bro') === -1) { + return Ember.RSVP.reject(new DS.InvalidError({ base: ['is a generally unsavoury character'] })); + } else { + return Ember.RSVP.resolve(); + } + }; + + var yehuda = run(function () { + return store.createRecord('person', { id: 1, name: "Yehuda Katz" }); + }); + + // Wrap this in an Ember.run so that all chained async behavior is set up + // before flushing any scheduled behavior. + run(function() { + yehuda.save().then(null, async(function(error) { + equal(get(yehuda, 'isValid'), false, "the record is invalid"); + ok(get(yehuda, 'errors.base'), "The errors.base property exists"); + deepEqual(get(yehuda, 'errors').errorsFor('base'), [{ attribute: 'base', message: "is a generally unsavoury character" }]); + + set(yehuda, 'updatedAt', true); + equal(get(yehuda, 'isValid'), false, "the record is still invalid"); + + set(yehuda, 'name', "Brohuda Brokatz"); + + equal(get(yehuda, 'isValid'), false, "the record is still invalid as far as we know"); + equal(get(yehuda, 'isDirty'), true, "the record has outstanding changes"); + + equal(get(yehuda, 'isNew'), true, "precond - record is still new"); + + return yehuda.save(); + })).then(async(function(person) { + strictEqual(person, yehuda, "The promise resolves with the saved record"); + ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); + deepEqual(get(yehuda, 'errors').errorsFor('base'), []); + equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); + equal(get(yehuda, 'isNew'), false, "record is no longer new"); + })); + }); +}); + test("if a created record is marked as invalid by the server, you can attempt the save again", function() { var saveCount = 0; adapter.createRecord = function(store, type, record) { @@ -517,6 +559,55 @@ test("if an updated record is marked as invalid by the server, it enters an erro }); +test("records can have errors on arbitrary properties after update", function() { + adapter.updateRecord = function(store, type, record) { + if (get(record, 'name').indexOf('Bro') === -1) { + return Ember.RSVP.reject(new DS.InvalidError({ base: ['is a generally unsavoury character'] })); + } else { + return Ember.RSVP.resolve(); + } + }; + + var yehuda = run(function() { + return store.push('person', { id: 1, name: "Brohuda Brokatz" }); + }); + + run(function() { + store.find('person', 1).then(async(function(person) { + equal(person, yehuda, "The same object is passed through"); + + equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); + set(yehuda, 'name', "Yehuda Katz"); + equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); + + equal(get(yehuda, 'isDirty'), true, "the record is dirty"); + + return yehuda.save(); + })).then(null, async(function(reason) { + equal(get(yehuda, 'isDirty'), true, "the record is still dirty"); + equal(get(yehuda, 'isValid'), false, "the record is invalid"); + ok(get(yehuda, 'errors.base'), "The errors.base property exists"); + deepEqual(get(yehuda, 'errors').errorsFor('base'), [{ attribute: 'base', message: "is a generally unsavoury character" }]); + + set(yehuda, 'updatedAt', true); + equal(get(yehuda, 'isValid'), false, "the record is still invalid"); + + set(yehuda, 'name', "Brohuda Brokatz"); + equal(get(yehuda, 'isValid'), false, "the record is still invalid after changing (only server can know if it's now valid)"); + equal(get(yehuda, 'isDirty'), true, "the record has outstanding changes"); + + return yehuda.save(); + })).then(async(function(yehuda) { + equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); + equal(get(yehuda, 'isDirty'), false, "record is no longer new"); + ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); + deepEqual(get(yehuda, 'errors').errorsFor('base'), []); + })); + }); +}); + + + test("if an updated record is marked as invalid by the server, you can attempt the save again", function() { var saveCount = 0; adapter.updateRecord = function(store, type, record) { From 212bd20ecd7a416252b7dfb805a438ab24c701aa Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Fri, 12 Dec 2014 00:05:19 +0100 Subject: [PATCH 0634/2527] Initial implementation of the Snapshot API --- .../lib/system/active_model_serializer.js | 16 +- .../active_model_serializer_test.js | 12 +- .../lib/adapters/fixture_adapter.js | 4 +- .../ember-data/lib/adapters/rest_adapter.js | 6 +- packages/ember-data/lib/main.js | 3 + .../lib/serializers/embedded_records_mixin.js | 44 +-- .../lib/serializers/json_serializer.js | 96 ++--- .../lib/serializers/rest_serializer.js | 46 +-- packages/ember-data/lib/system/adapter.js | 3 +- packages/ember-data/lib/system/model/model.js | 13 +- packages/ember-data/lib/system/snapshot.js | 361 ++++++++++++++++++ packages/ember-data/lib/system/store.js | 3 +- .../embedded_records_mixin_test.js | 40 +- .../serializers/json_serializer_test.js | 65 ++-- .../serializers/rest_serializer_test.js | 10 +- .../tests/integration/snapshot_test.js | 340 +++++++++++++++++ 16 files changed, 900 insertions(+), 162 deletions(-) create mode 100644 packages/ember-data/lib/system/snapshot.js create mode 100644 packages/ember-data/tests/integration/snapshot_test.js diff --git a/packages/activemodel-adapter/lib/system/active_model_serializer.js b/packages/activemodel-adapter/lib/system/active_model_serializer.js index bee4f5b6644..2f2affb70a5 100644 --- a/packages/activemodel-adapter/lib/system/active_model_serializer.js +++ b/packages/activemodel-adapter/lib/system/active_model_serializer.js @@ -4,12 +4,12 @@ import RESTSerializer from "ember-data/serializers/rest_serializer"; @module ember-data */ -var get = Ember.get; var forEach = Ember.EnumerableUtils.forEach; var camelize = Ember.String.camelize; var capitalize = Ember.String.capitalize; var decamelize = Ember.String.decamelize; var underscore = Ember.String.underscore; + /** The ActiveModelSerializer is a subclass of the RESTSerializer designed to integrate with a JSON API that uses an underscored naming convention instead of camelCasing. @@ -142,31 +142,31 @@ var ActiveModelSerializer = RESTSerializer.extend({ @method serializeIntoHash @param {Object} hash @param {subclass of DS.Model} type - @param {DS.Model} record + @param {DS.Snapshot} snapshot @param {Object} options */ - serializeIntoHash: function(data, type, record, options) { + serializeIntoHash: function(data, type, snapshot, options) { var root = underscore(decamelize(type.typeKey)); - data[root] = this.serialize(record, options); + data[root] = this.serialize(snapshot, options); }, /** Serializes a polymorphic type as a fully capitalized model name. @method serializePolymorphicType - @param {DS.Model} record + @param {DS.Snapshot} snapshot @param {Object} json @param {Object} relationship */ - serializePolymorphicType: function(record, json, relationship) { + serializePolymorphicType: function(snapshot, json, relationship) { var key = relationship.key; - var belongsTo = get(record, key); + var belongsTo = snapshot.belongsTo(key); var jsonKey = underscore(key + "_type"); if (Ember.isNone(belongsTo)) { json[jsonKey] = null; } else { - json[jsonKey] = capitalize(camelize(belongsTo.constructor.typeKey)); + json[jsonKey] = capitalize(camelize(belongsTo.typeKey)); } }, diff --git a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js index 6aeef0cfac1..07e9f27d35f 100644 --- a/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js +++ b/packages/activemodel-adapter/tests/integration/active_model_serializer_test.js @@ -60,7 +60,7 @@ test("serialize", function() { tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league }); }); - var json = env.amsSerializer.serialize(tom); + var json = env.amsSerializer.serialize(tom._createSnapshot()); deepEqual(json, { first_name: "Tom", @@ -75,7 +75,7 @@ test("serializeIntoHash", function() { }); var json = {}; - env.amsSerializer.serializeIntoHash(json, HomePlanet, league); + env.amsSerializer.serializeIntoHash(json, HomePlanet, league._createSnapshot()); deepEqual(json, { home_planet: { @@ -91,7 +91,7 @@ test("serializeIntoHash with decamelized types", function() { }); var json = {}; - env.amsSerializer.serializeIntoHash(json, HomePlanet, league); + env.amsSerializer.serializeIntoHash(json, HomePlanet, league._createSnapshot()); deepEqual(json, { home_planet: { @@ -195,7 +195,7 @@ test("serialize polymorphic", function() { ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); }); - var json = env.amsSerializer.serialize(ray); + var json = env.amsSerializer.serialize(ray._createSnapshot()); deepEqual(json, { name: "DeathRay", @@ -212,7 +212,7 @@ test("serialize polymorphic when type key is not camelized", function() { ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); }); - var json = env.amsSerializer.serialize(ray); + var json = env.amsSerializer.serialize(ray._createSnapshot()); deepEqual(json["evil_minion_type"], "YellowMinion"); }); @@ -221,7 +221,7 @@ test("serialize polymorphic when associated object is null", function() { var ray, json; run(function() { ray = env.store.createRecord(DoomsdayDevice, { name: "DeathRay" }); - json = env.amsSerializer.serialize(ray); + json = env.amsSerializer.serialize(ray._createSnapshot()); }); deepEqual(json["evil_minion_type"], null); diff --git a/packages/ember-data/lib/adapters/fixture_adapter.js b/packages/ember-data/lib/adapters/fixture_adapter.js index bf88dea34ca..eabaee11ed7 100644 --- a/packages/ember-data/lib/adapters/fixture_adapter.js +++ b/packages/ember-data/lib/adapters/fixture_adapter.js @@ -110,11 +110,13 @@ export default Adapter.extend({ Implement this method in order to provide json for CRUD methods @method mockJSON + @param {DS.Store} store @param {Subclass of DS.Model} type @param {DS.Model} record */ mockJSON: function(store, type, record) { - return store.serializerFor(type).serialize(record, { includeId: true }); + var snapshot = record._createSnapshot(); + return store.serializerFor(snapshot.typeKey).serialize(snapshot, { includeId: true }); }, /** diff --git a/packages/ember-data/lib/adapters/rest_adapter.js b/packages/ember-data/lib/adapters/rest_adapter.js index 2b990132c4f..eef2133552b 100644 --- a/packages/ember-data/lib/adapters/rest_adapter.js +++ b/packages/ember-data/lib/adapters/rest_adapter.js @@ -524,7 +524,8 @@ export default Adapter.extend({ var data = {}; var serializer = store.serializerFor(type.typeKey); - serializer.serializeIntoHash(data, type, record, { includeId: true }); + var snapshot = record._createSnapshot(); + serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); return this.ajax(this.buildURL(type.typeKey, null, record), "POST", { data: data }); }, @@ -549,7 +550,8 @@ export default Adapter.extend({ var data = {}; var serializer = store.serializerFor(type.typeKey); - serializer.serializeIntoHash(data, type, record); + var snapshot = record._createSnapshot(); + serializer.serializeIntoHash(data, type, snapshot); var id = get(record, 'id'); diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index f5195d3be18..32d57a5f388 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -32,6 +32,7 @@ import { RootState, attr } from "ember-data/system/model"; +import Snapshot from "ember-data/system/snapshot"; import { InvalidError, Adapter @@ -83,6 +84,8 @@ DS.RootState = RootState; DS.attr = attr; DS.Errors = Errors; +DS.Snapshot = Snapshot; + DS.Adapter = Adapter; DS.InvalidError = InvalidError; diff --git a/packages/ember-data/lib/serializers/embedded_records_mixin.js b/packages/ember-data/lib/serializers/embedded_records_mixin.js index e7bbb9581f5..dcd095a53ed 100644 --- a/packages/ember-data/lib/serializers/embedded_records_mixin.js +++ b/packages/ember-data/lib/serializers/embedded_records_mixin.js @@ -176,34 +176,34 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ ``` @method serializeBelongsTo - @param {DS.Model} record + @param {DS.Snapshot} snapshot @param {Object} json @param {Object} relationship */ - serializeBelongsTo: function(record, json, relationship) { + serializeBelongsTo: function(snapshot, json, relationship) { var attr = relationship.key; if (this.noSerializeOptionSpecified(attr)) { - this._super(record, json, relationship); + this._super(snapshot, json, relationship); return; } var includeIds = this.hasSerializeIdsOption(attr); var includeRecords = this.hasSerializeRecordsOption(attr); - var embeddedRecord = record.get(attr); + var embeddedSnapshot = snapshot.belongsTo(attr); var key; if (includeIds) { key = this.keyForRelationship(attr, relationship.kind); - if (!embeddedRecord) { + if (!embeddedSnapshot) { json[key] = null; } else { - json[key] = get(embeddedRecord, 'id'); + json[key] = embeddedSnapshot.id; } } else if (includeRecords) { key = this.keyForAttribute(attr); - if (!embeddedRecord) { + if (!embeddedSnapshot) { json[key] = null; } else { - json[key] = embeddedRecord.serialize({ includeId: true }); - this.removeEmbeddedForeignKey(record, embeddedRecord, relationship, json[key]); + json[key] = embeddedSnapshot.record.serialize({ includeId: true }); + this.removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, json[key]); } } }, @@ -285,14 +285,14 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ ``` @method serializeHasMany - @param {DS.Model} record + @param {DS.Snapshot} snapshot @param {Object} json @param {Object} relationship */ - serializeHasMany: function(record, json, relationship) { + serializeHasMany: function(snapshot, json, relationship) { var attr = relationship.key; if (this.noSerializeOptionSpecified(attr)) { - this._super(record, json, relationship); + this._super(snapshot, json, relationship); return; } var includeIds = this.hasSerializeIdsOption(attr); @@ -300,13 +300,13 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ var key; if (includeIds) { key = this.keyForRelationship(attr, relationship.kind); - json[key] = get(record, attr).mapBy('id'); + json[key] = snapshot.hasMany(attr, { ids: true }); } else if (includeRecords) { key = this.keyForAttribute(attr); - json[key] = get(record, attr).map(function(embeddedRecord) { - var serializedEmbeddedRecord = embeddedRecord.serialize({ includeId: true }); - this.removeEmbeddedForeignKey(record, embeddedRecord, relationship, serializedEmbeddedRecord); - return serializedEmbeddedRecord; + json[key] = snapshot.hasMany(attr).map(function(embeddedSnapshot) { + var embeddedJson = embeddedSnapshot.record.serialize({ includeId: true }); + this.removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, embeddedJson); + return embeddedJson; }, this); } }, @@ -322,19 +322,19 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ the parent record. @method removeEmbeddedForeignKey - @param {DS.Model} record - @param {DS.Model} embeddedRecord + @param {DS.Snapshot} snapshot + @param {DS.Snapshot} embeddedSnapshot @param {Object} relationship @param {Object} json */ - removeEmbeddedForeignKey: function (record, embeddedRecord, relationship, json) { + removeEmbeddedForeignKey: function (snapshot, embeddedSnapshot, relationship, json) { if (relationship.kind === 'hasMany') { return; } else if (relationship.kind === 'belongsTo') { - var parentRecord = record.constructor.inverseFor(relationship.key); + var parentRecord = snapshot.type.inverseFor(relationship.key); if (parentRecord) { var name = parentRecord.name; - var embeddedSerializer = this.store.serializerFor(embeddedRecord.constructor); + var embeddedSerializer = this.store.serializerFor(embeddedSnapshot.type); var parentKey = embeddedSerializer.keyForRelationship(name, parentRecord.kind); if (parentKey) { delete json[parentKey]; diff --git a/packages/ember-data/lib/serializers/json_serializer.js b/packages/ember-data/lib/serializers/json_serializer.js index 68e6ded18a8..919c2541d32 100644 --- a/packages/ember-data/lib/serializers/json_serializer.js +++ b/packages/ember-data/lib/serializers/json_serializer.js @@ -369,15 +369,15 @@ export default Ember.Object.extend({ ```javascript App.PostSerializer = DS.JSONSerializer.extend({ - serialize: function(post, options) { + serialize: function(snapshot, options) { var json = { - POST_TTL: post.get('title'), - POST_BDY: post.get('body'), - POST_CMS: post.get('comments').mapBy('id') + POST_TTL: snapshot.attr('title'), + POST_BDY: snapshot.attr('body'), + POST_CMS: snapshot.hasMany('comments', { ids: true }) } if (options.includeId) { - json.POST_ID_ = post.get('id'); + json.POST_ID_ = snapshot.id; } return json; @@ -393,21 +393,21 @@ export default Ember.Object.extend({ ```javascript App.ApplicationSerializer = DS.JSONSerializer.extend({ - serialize: function(record, options) { + serialize: function(snapshot, options) { var json = {}; - record.eachAttribute(function(name) { - json[serverAttributeName(name)] = record.get(name); + snapshot.eachAttribute(function(name) { + json[serverAttributeName(name)] = snapshot.attr(name); }) - record.eachRelationship(function(name, relationship) { + snapshot.eachRelationship(function(name, relationship) { if (relationship.kind === 'hasMany') { - json[serverHasManyName(name)] = record.get(name).mapBy('id'); + json[serverHasManyName(name)] = snapshot.hasMany(name, { ids: true }); } }); if (options.includeId) { - json.ID_ = record.get('id'); + json.ID_ = snapshot.id; } return json; @@ -441,7 +441,7 @@ export default Ember.Object.extend({ ```javascript App.PostSerializer = DS.JSONSerializer.extend({ - serialize: function(record, options) { + serialize: function(snapshot, options) { var json = this._super.apply(this, arguments); json.subject = json.title; @@ -453,30 +453,30 @@ export default Ember.Object.extend({ ``` @method serialize - @param {subclass of DS.Model} record + @param {DS.Snapshot} snapshot @param {Object} options @return {Object} json */ - serialize: function(record, options) { + serialize: function(snapshot, options) { var json = {}; if (options && options.includeId) { - var id = get(record, 'id'); + var id = snapshot.id; if (id) { json[get(this, 'primaryKey')] = id; } } - record.eachAttribute(function(key, attribute) { - this.serializeAttribute(record, json, key, attribute); + snapshot.eachAttribute(function(key, attribute) { + this.serializeAttribute(snapshot, json, key, attribute); }, this); - record.eachRelationship(function(key, relationship) { + snapshot.eachRelationship(function(key, relationship) { if (relationship.kind === 'belongsTo') { - this.serializeBelongsTo(record, json, relationship); + this.serializeBelongsTo(snapshot, json, relationship); } else if (relationship.kind === 'hasMany') { - this.serializeHasMany(record, json, relationship); + this.serializeHasMany(snapshot, json, relationship); } }, this); @@ -494,9 +494,9 @@ export default Ember.Object.extend({ ```js App.ApplicationSerializer = DS.RESTSerializer.extend({ - serializeIntoHash: function(data, type, record, options) { + serializeIntoHash: function(data, type, snapshot, options) { var root = Ember.String.decamelize(type.typeKey); - data[root] = this.serialize(record, options); + data[root] = this.serialize(snapshot, options); } }); ``` @@ -504,11 +504,11 @@ export default Ember.Object.extend({ @method serializeIntoHash @param {Object} hash @param {subclass of DS.Model} type - @param {DS.Model} record + @param {DS.Snapshot} snapshot @param {Object} options */ - serializeIntoHash: function(hash, type, record, options) { - merge(hash, this.serialize(record, options)); + serializeIntoHash: function(hash, type, snapshot, options) { + merge(hash, this.serialize(snapshot, options)); }, /** @@ -521,24 +521,24 @@ export default Ember.Object.extend({ ```javascript App.ApplicationSerializer = DS.JSONSerializer.extend({ - serializeAttribute: function(record, json, key, attributes) { + serializeAttribute: function(snapshot, json, key, attributes) { json.attributes = json.attributes || {}; - this._super(record, json.attributes, key, attributes); + this._super(snapshot, json.attributes, key, attributes); } }); ``` @method serializeAttribute - @param {DS.Model} record + @param {DS.Snapshot} snapshot @param {Object} json @param {String} key @param {Object} attribute */ - serializeAttribute: function(record, json, key, attribute) { + serializeAttribute: function(snapshot, json, key, attribute) { var type = attribute.type; if (this._canSerialize(key)) { - var value = get(record, key); + var value = snapshot.attr(key); if (type) { var transform = this.transformFor(type); value = transform.serialize(value); @@ -564,28 +564,28 @@ export default Ember.Object.extend({ ```javascript App.PostSerializer = DS.JSONSerializer.extend({ - serializeBelongsTo: function(record, json, relationship) { + serializeBelongsTo: function(snapshot, json, relationship) { var key = relationship.key; - var belongsTo = get(record, key); + var belongsTo = snapshot.belongsTo(key); key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo") : key; - json[key] = Ember.isNone(belongsTo) ? belongsTo : belongsTo.toJSON(); + json[key] = Ember.isNone(belongsTo) ? belongsTo : belongsTo.record.toJSON(); } }); ``` @method serializeBelongsTo - @param {DS.Model} record + @param {DS.Snapshot} snapshot @param {Object} json @param {Object} relationship */ - serializeBelongsTo: function(record, json, relationship) { + serializeBelongsTo: function(snapshot, json, relationship) { var key = relationship.key; if (this._canSerialize(key)) { - var belongsTo = get(record, key); + var belongsToId = snapshot.belongsTo(key, { id: true }); // if provided, use the mapping provided by `attrs` in // the serializer @@ -595,14 +595,14 @@ export default Ember.Object.extend({ } //Need to check whether the id is there for new&async records - if (isNone(belongsTo) || isNone(get(belongsTo, 'id'))) { + if (isNone(belongsToId)) { json[payloadKey] = null; } else { - json[payloadKey] = get(belongsTo, 'id'); + json[payloadKey] = belongsToId; } if (relationship.options.polymorphic) { - this.serializePolymorphicType(record, json, relationship); + this.serializePolymorphicType(snapshot, json, relationship); } } }, @@ -615,7 +615,7 @@ export default Ember.Object.extend({ ```javascript App.PostSerializer = DS.JSONSerializer.extend({ - serializeHasMany: function(record, json, relationship) { + serializeHasMany: function(snapshot, json, relationship) { var key = relationship.key; if (key === 'comments') { return; @@ -627,11 +627,11 @@ export default Ember.Object.extend({ ``` @method serializeHasMany - @param {DS.Model} record + @param {DS.Snapshot} snapshot @param {Object} json @param {Object} relationship */ - serializeHasMany: function(record, json, relationship) { + serializeHasMany: function(snapshot, json, relationship) { var key = relationship.key; if (this._canSerialize(key)) { @@ -644,10 +644,10 @@ export default Ember.Object.extend({ payloadKey = this.keyForRelationship(key, "hasMany"); } - var relationshipType = record.constructor.determineRelationshipType(relationship); + var relationshipType = snapshot.type.determineRelationshipType(relationship); if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') { - json[payloadKey] = get(record, key).mapBy('id'); + json[payloadKey] = snapshot.hasMany(key, { ids: true }); // TODO support for polymorphic manyToNone and manyToMany relationships } } @@ -663,22 +663,22 @@ export default Ember.Object.extend({ ```javascript App.CommentSerializer = DS.JSONSerializer.extend({ - serializePolymorphicType: function(record, json, relationship) { + serializePolymorphicType: function(snapshot, json, relationship) { var key = relationship.key, - belongsTo = get(record, key); + belongsTo = snapshot.belongsTo(key); key = this.keyForAttribute ? this.keyForAttribute(key) : key; if (Ember.isNone(belongsTo)) { json[key + "_type"] = null; } else { - json[key + "_type"] = belongsTo.constructor.typeKey; + json[key + "_type"] = belongsTo.typeKey; } } }); ``` @method serializePolymorphicType - @param {DS.Model} record + @param {DS.Snapshot} snapshot @param {Object} json @param {Object} relationship */ diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index 3a17e07e669..1d3722b7e93 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -3,7 +3,7 @@ */ import JSONSerializer from "ember-data/serializers/json_serializer"; -var get = Ember.get; + var forEach = Ember.ArrayPolyfills.forEach; var map = Ember.ArrayPolyfills.map; var camelize = Ember.String.camelize; @@ -608,15 +608,15 @@ var RESTSerializer = JSONSerializer.extend({ ```js App.PostSerializer = DS.RESTSerializer.extend({ - serialize: function(post, options) { + serialize: function(snapshot, options) { var json = { - POST_TTL: post.get('title'), - POST_BDY: post.get('body'), - POST_CMS: post.get('comments').mapBy('id') + POST_TTL: snapshot.attr('title'), + POST_BDY: snapshot.attr('body'), + POST_CMS: snapshot.hasMany('comments', { ids: true }) } if (options.includeId) { - json.POST_ID_ = post.get('id'); + json.POST_ID_ = snapshot.id; } return json; @@ -632,21 +632,21 @@ var RESTSerializer = JSONSerializer.extend({ ```js App.ApplicationSerializer = DS.RESTSerializer.extend({ - serialize: function(record, options) { + serialize: function(snapshot, options) { var json = {}; - record.eachAttribute(function(name) { - json[serverAttributeName(name)] = record.get(name); + snapshot.eachAttribute(function(name) { + json[serverAttributeName(name)] = snapshot.attr(name); }) - record.eachRelationship(function(name, relationship) { + snapshot.eachRelationship(function(name, relationship) { if (relationship.kind === 'hasMany') { - json[serverHasManyName(name)] = record.get(name).mapBy('id'); + json[serverHasManyName(name)] = snapshot.hasMany(name, { ids: true }); } }); if (options.includeId) { - json.ID_ = record.get('id'); + json.ID_ = snapshot.id; } return json; @@ -680,8 +680,8 @@ var RESTSerializer = JSONSerializer.extend({ ```js App.PostSerializer = DS.RESTSerializer.extend({ - serialize: function(record, options) { - var json = this._super(record, options); + serialize: function(snapshot, options) { + var json = this._super(snapshot, options); json.subject = json.title; delete json.title; @@ -692,11 +692,11 @@ var RESTSerializer = JSONSerializer.extend({ ``` @method serialize - @param {subclass of DS.Model} record + @param {DS.Snapshot} snapshot @param {Object} options @return {Object} json */ - serialize: function(record, options) { + serialize: function(snapshot, options) { return this._super.apply(this, arguments); }, @@ -719,11 +719,11 @@ var RESTSerializer = JSONSerializer.extend({ @method serializeIntoHash @param {Object} hash @param {subclass of DS.Model} type - @param {DS.Model} record + @param {DS.Snapshot} snapshot @param {Object} options */ - serializeIntoHash: function(hash, type, record, options) { - hash[type.typeKey] = this.serialize(record, options); + serializeIntoHash: function(hash, type, snapshot, options) { + hash[type.typeKey] = this.serialize(snapshot, options); }, /** @@ -732,18 +732,18 @@ var RESTSerializer = JSONSerializer.extend({ the attribute and value from the model's camelcased model name. @method serializePolymorphicType - @param {DS.Model} record + @param {DS.Snapshot} snapshot @param {Object} json @param {Object} relationship */ - serializePolymorphicType: function(record, json, relationship) { + serializePolymorphicType: function(snapshot, json, relationship) { var key = relationship.key; - var belongsTo = get(record, key); + var belongsTo = snapshot.belongsTo(key); key = this.keyForAttribute ? this.keyForAttribute(key) : key; if (Ember.isNone(belongsTo)) { json[key + "Type"] = null; } else { - json[key + "Type"] = Ember.String.camelize(belongsTo.constructor.typeKey); + json[key + "Type"] = Ember.String.camelize(belongsTo.typeKey); } } }); diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index d12b69fed9f..414c5263c6b 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -297,7 +297,8 @@ var Adapter = Ember.Object.extend({ @return {Object} serialized record */ serialize: function(record, options) { - return get(record, 'store').serializerFor(record.constructor.typeKey).serialize(record, options); + var snapshot = record._createSnapshot(); + return get(record, 'store').serializerFor(snapshot.typeKey).serialize(snapshot, options); }, /** diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 40703767b69..b20cfaf3984 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -4,6 +4,7 @@ import { PromiseObject } from "ember-data/system/promise_proxies"; import merge from "ember-data/system/merge"; import JSONSerializer from "ember-data/serializers/json_serializer"; import createRelationshipFor from "ember-data/system/relationships/state/create"; +import Snapshot from "ember-data/system/snapshot"; /** @module ember-data @@ -401,7 +402,9 @@ var Model = Ember.Object.extend(Ember.Evented, { toJSON: function(options) { // container is for lazy transform lookups var serializer = JSONSerializer.create({ container: this.container }); - return serializer.serialize(this, options); + var snapshot = this._createSnapshot(); + + return serializer.serialize(snapshot, options); }, /** @@ -974,6 +977,14 @@ var Model = Ember.Object.extend(Ember.Evented, { this._notifyProperties(dirtyKeys); }, + /** + @method _createSnapshot + @private + */ + _createSnapshot: function() { + return new Snapshot(this); + }, + toStringExtension: function() { return get(this, 'id'); }, diff --git a/packages/ember-data/lib/system/snapshot.js b/packages/ember-data/lib/system/snapshot.js new file mode 100644 index 00000000000..3c59731740f --- /dev/null +++ b/packages/ember-data/lib/system/snapshot.js @@ -0,0 +1,361 @@ +/** + @module ember-data +*/ + +var get = Ember.get; + +/** + @class Snapshot + @namespace DS + @private + @constructor + @param {DS.Model} record The record to create a snapshot from +*/ +function Snapshot(record) { + this._attributes = Ember.create(null); + this._belongsToRelationships = Ember.create(null); + this._belongsToIds = Ember.create(null); + this._hasManyRelationships = Ember.create(null); + this._hasManyIds = Ember.create(null); + + record.eachAttribute(function(keyName) { + this._attributes[keyName] = get(record, keyName); + }, this); + + this.id = get(record, 'id'); + this.record = record; + this.type = record.constructor; + this.typeKey = record.constructor.typeKey; + + // The following code is here to keep backwards compatibility when accessing + // `constructor` directly. + // + // With snapshots you should use `type` instead of `constructor`. + // + // Remove for Ember Data 1.0. + if (Ember.platform.hasPropertyAccessors) { + var callDeprecate = true; + + Ember.defineProperty(this, 'constructor', { + get: function() { + // Ugly hack since accessing error.stack (done in `Ember.deprecate()`) + // causes the internals of Chrome to access the constructor, which then + // causes an infinite loop if accessed and calls `Ember.deprecate()` + // again. + if (callDeprecate) { + callDeprecate = false; + Ember.deprecate('Usage of `snapshot.constructor` is deprecated, use `snapshot.type` instead.'); + callDeprecate = true; + } + + return this.type; + } + }); + } else { + this.constructor = this.type; + } +} + +Snapshot.prototype = { + constructor: Snapshot, + + /** + The id of the snapshot's underlying record + + Example + + ```javascript + var post = store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + var snapshot = post._createSnapshot(); + + snapshot.id; // => '1' + ``` + + @property id + @type {String} + */ + id: null, + + /** + The underlying record for this snapshot. Can be used to access methods and + properties defined on the record. + + Example + + ```javascript + var json = snapshot.record.toJSON(); + ``` + + @property record + @type {DS.Model} + */ + record: null, + + /** + The type of the underlying record for this snapshot, as a subclass of DS.Model. + + @property type + @type {subclass of DS.Model} + */ + type: null, + + /** + The name of the type of the underlying record for this snapshot, as a string. + + @property typeKey + @type {String} + */ + typeKey: null, + + /** + Returns the value of an attribute. + + Example + + ```javascript + var post = store.createRecord('post', { author: 'Tomster', title: 'Ember.js rocks' }); + var snapshot = post._createSnapshot(); + + snapshot.attr('author'); // => 'Tomster' + snapshot.attr('title'); // => 'Ember.js rocks' + ``` + + Note: Values are loaded eagerly and cached when the snapshot is created. + + @method attr + @param {String} keyName + @return {Object} The attribute value or undefined + */ + attr: function(keyName) { + if (keyName in this._attributes) { + return this._attributes[keyName]; + } + throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no attribute named '" + keyName + "' defined."); + }, + + /** + Returns all attributes and their corresponding values. + + Example + + ```javascript + var post = store.createRecord('post', { author: 'Tomster', title: 'Ember.js rocks' }); + var snapshot = post._createSnapshot(); + + snapshot.attributes(); // => { author: 'Tomster', title: 'Ember.js rocks' } + ``` + + @method attributes + @return {Array} All attributes for the current snapshot + */ + attributes: function() { + return Ember.copy(this._attributes); + }, + + /** + Returns the current value of a belongsTo relationship. + + `belongsTo` takes an optional hash of options as a second parameter, + currently supported options are: + + - `id`: set to `true` if you only want the ID of the related record to be + returned. + + Example + + ```javascript + var post = store.push('post', { id: 1, title: 'Hello World' }); + var comment = store.createRecord('comment', { body: 'Lorem ipsum', post: post }); + var snapshot = comment._createSnapshot(); + + snapshot.belongsTo('post'); // => DS.Snapshot of post + snapshot.belongsTo('post', { id: true }); // => '1' + ``` + + Calling `belongsTo` will return a new Snapshot as long as there's any + data available, such as an ID. If there's no data available `belongsTo` will + return undefined. + + Note: Relationships are loaded lazily and cached upon first access. + + @method belongsTo + @param {String} keyName + @param {Object} [options] + @return {DS.Snapshot|String|undefined} A snapshot or ID of a belongsTo relationship, or undefined + */ + belongsTo: function(keyName, options) { + var id = options && options.id; + var result; + var relationship, inverseRecord; + + if (id && keyName in this._belongsToIds) { + return this._belongsToIds[keyName]; + } + + if (!id && keyName in this._belongsToRelationships) { + return this._belongsToRelationships[keyName]; + } + + relationship = this.record._relationships[keyName]; + if (!(relationship && relationship.relationshipMeta.kind === 'belongsTo')) { + throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined."); + } + + inverseRecord = get(relationship, 'inverseRecord'); + if (id) { + if (inverseRecord) { + result = get(inverseRecord, 'id'); + } + this._belongsToIds[keyName] = result; + } else { + if (inverseRecord) { + result = inverseRecord._createSnapshot(); + } + this._belongsToRelationships[keyName] = result; + } + + return result; + }, + + /** + Returns the current value of a hasMany relationship. + + `hasMany` takes an optional hash of options as a second parameter, + currently supported options are: + + - `ids`: set to `true` if you only want the IDs of the related records to be + returned. + + Example + + ```javascript + var post = store.createRecord('post', { title: 'Hello World', comments: [2, 3] }); + var snapshot = post._createSnapshot(); + + snapshot.hasMany('comments'); // => [DS.Snapshot, DS.Snapshot] + snapshot.hasMany('comments', { ids: true }); // => ['2', '3'] + ``` + + Note: Relationships are loaded lazily and cached upon first access. + + @method hasMany + @param {String} keyName + @param {Object} [options] + @return {Array} An array of snapshots or IDs of a hasMany relationship + */ + hasMany: function(keyName, options) { + var ids = options && options.ids; + var results = []; + var relationship, members; + + if (ids && keyName in this._hasManyIds) { + return this._hasManyIds[keyName]; + } + + if (!ids && keyName in this._hasManyRelationships) { + return this._hasManyRelationships[keyName]; + } + + relationship = this.record._relationships[keyName]; + if (!(relationship && relationship.relationshipMeta.kind === 'hasMany')) { + throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined."); + } + + members = get(relationship, 'members'); + + if (ids) { + members.forEach(function(member) { + results.push(get(member, 'id')); + }); + this._hasManyIds[keyName] = results; + } else { + members.forEach(function(member) { + results.push(member._createSnapshot()); + }); + this._hasManyRelationships[keyName] = results; + } + + return results; + }, + + /** + Iterates through all the attributes of the model, calling the passed + function on each attribute. + + Example + + ```javascript + snapshot.eachAttribute(function(name, meta) { + // ... + }); + ``` + + @method eachAttribute + @param {Function} callback the callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + */ + eachAttribute: function(callback, binding) { + this.record.eachAttribute(callback, binding); + }, + + /** + Iterates through all the relationships of the model, calling the passed + function on each relationship. + + Example + + ```javascript + snapshot.eachRelationship(function(name, relationship) { + // ... + }); + ``` + + @method eachRelationship + @param {Function} callback the callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + */ + eachRelationship: function(callback, binding) { + this.record.eachRelationship(callback, binding); + }, + + /** + @method get + @param {String} keyName + @return {Object} The property value + @deprecated Use [attr](#method_attr), [belongsTo](#method_belongsTo) or [hasMany](#method_hasMany) instead + */ + get: function(keyName) { + Ember.deprecate('Using DS.Snapshot.get() is deprecated. Use .attr(), .belongsTo() or .hasMany() instead.'); + + if (keyName === 'id') { + return this.id; + } + + if (keyName in this._attributes) { + return this.attr(keyName); + } + + var relationship = this.record._relationships[keyName]; + + if (relationship && relationship.relationshipMeta.kind === 'belongsTo') { + return this.belongsTo(keyName); + } + if (relationship && relationship.relationshipMeta.kind === 'hasMany') { + return this.hasMany(keyName); + } + + return get(this.record, keyName); + }, + + /** + @method unknownProperty + @param {String} keyName + @return {Object} The property value + @deprecated Use [attr](#method_attr), [belongsTo](#method_belongsTo) or [hasMany](#method_hasMany) instead + */ + unknownProperty: function(keyName) { + return this.get(keyName); + } +}; + +export default Snapshot; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 78bc1911968..ed1ee142b85 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -221,7 +221,8 @@ Store = Ember.Object.extend({ @param {Object} options an options hash */ serialize: function(record, options) { - return this.serializerFor(record.constructor.typeKey).serialize(record, options); + var snapshot = record._createSnapshot(); + return this.serializerFor(snapshot.typeKey).serialize(snapshot, options); }, /** diff --git a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js index bd835be6e02..5a4ff4595b1 100644 --- a/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js +++ b/packages/ember-data/tests/integration/serializers/embedded_records_mixin_test.js @@ -567,7 +567,7 @@ test("serialize supports serialize:false on non-relationship properties", functi var serializer, json; run(function() { serializer = env.container.lookup("serializer:superVillain"); - json = serializer.serialize(tom); + json = serializer.serialize(tom._createSnapshot()); }); deepEqual(json, { @@ -594,7 +594,7 @@ test("serialize with embedded objects (hasMany relationship)", function() { run(function() { serializer = env.container.lookup("serializer:homePlanet"); - json = serializer.serialize(league); + json = serializer.serialize(league._createSnapshot()); }); deepEqual(json, { @@ -624,7 +624,7 @@ test("serialize with embedded objects (hasMany relationship) supports serialize: run(function() { serializer = env.container.lookup("serializer:homePlanet"); - json = serializer.serialize(league); + json = serializer.serialize(league._createSnapshot()); }); deepEqual(json, { @@ -647,7 +647,7 @@ test("serialize with (new) embedded objects (hasMany relationship)", function() run(function() { serializer = env.container.lookup("serializer:homePlanet"); - json = serializer.serialize(league); + json = serializer.serialize(league._createSnapshot()); }); deepEqual(json, { name: "Villain League", @@ -679,7 +679,7 @@ test("serialize with embedded objects (hasMany relationships, including related run(function() { serializer = env.container.lookup("serializer:superVillain"); - json = serializer.serialize(superVillain); + json = serializer.serialize(superVillain._createSnapshot()); }); deepEqual(json, { first_name: get(superVillain, "firstName"), @@ -769,7 +769,7 @@ test("serialize with embedded object (belongsTo relationship)", function() { }); run(function() { - json = serializer.serialize(tom); + json = serializer.serialize(tom._createSnapshot()); }); deepEqual(json, { @@ -812,7 +812,7 @@ test("serialize with embedded object (belongsTo relationship) works with differe }); run(function() { - json = serializer.serialize(tom); + json = serializer.serialize(tom._createSnapshot()); }); deepEqual(json, { @@ -851,7 +851,7 @@ test("serialize with embedded object (belongsTo relationship, new no id)", funct }); run(function() { - json = serializer.serialize(tom); + json = serializer.serialize(tom._createSnapshot()); }); deepEqual(json, { @@ -888,7 +888,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize }); run(function() { - json = serializer.serialize(tom); + json = serializer.serialize(tom._createSnapshot()); }); deepEqual(json, { @@ -923,7 +923,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize }); run(function() { - json = serializer.serialize(tom); + json = serializer.serialize(tom._createSnapshot()); }); deepEqual(json, { @@ -956,7 +956,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize }); run(function() { - json = serializer.serialize(tom); + json = serializer.serialize(tom._createSnapshot()); }); deepEqual(json, { @@ -986,7 +986,7 @@ test("serialize with embedded object (belongsTo relationship) serializes the id }); run(function() { - json = serializer.serialize(tom); + json = serializer.serialize(tom._createSnapshot()); }); deepEqual(json, { @@ -1017,7 +1017,7 @@ test("when related record is not present, serialize embedded record (with a belo }); run(function() { - json = serializer.serialize(tom); + json = serializer.serialize(tom._createSnapshot()); }); deepEqual(json, { @@ -1200,7 +1200,7 @@ test("Mixin can be used with RESTSerializer which does not define keyForAttribut var json; run(function() { - json = serializer.serialize(superVillain); + json = serializer.serialize(superVillain._createSnapshot()); }); deepEqual(json, { @@ -1273,19 +1273,19 @@ test("serializing relationships with an embedded and without calls super when no var calledSerializeHasMany = false; var Serializer = DS.RESTSerializer.extend({ - serializeBelongsTo: function(record, json, relationship) { + serializeBelongsTo: function(snapshot, json, relationship) { calledSerializeBelongsTo = true; - return this._super(record, json, relationship); + return this._super(snapshot, json, relationship); }, - serializeHasMany: function(record, json, relationship) { + serializeHasMany: function(snapshot, json, relationship) { calledSerializeHasMany = true; var key = relationship.key; var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, "hasMany") : key; - var relationshipType = record.constructor.determineRelationshipType(relationship); + var relationshipType = snapshot.type.determineRelationshipType(relationship); // "manyToOne" not supported in DS.RESTSerializer.prototype.serializeHasMany var relationshipTypes = Ember.String.w('manyToNone manyToMany manyToOne'); if (indexOf(relationshipTypes, relationshipType) > -1) { - json[payloadKey] = get(record, key).mapBy('id'); + json[payloadKey] = snapshot.hasMany(key, { ids: true }); } } }); @@ -1302,7 +1302,7 @@ test("serializing relationships with an embedded and without calls super when no var json; run(function() { - json = serializer.serialize(superVillain); + json = serializer.serialize(superVillain._createSnapshot()); }); deepEqual(json, { diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index c55df4b03d2..111055b3ad6 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -31,7 +31,7 @@ test("serializeAttribute", function() { }); var json = {}; - env.serializer.serializeAttribute(post, json, "title", { type: "string" }); + env.serializer.serializeAttribute(post._createSnapshot(), json, "title", { type: "string" }); deepEqual(json, { title: "Rails is omakase" @@ -50,8 +50,7 @@ test("serializeAttribute respects keyForAttribute", function() { }); var json = {}; - env.container.lookup("serializer:post").serializeAttribute(post, json, "title", { type: "string" }); - + env.container.lookup("serializer:post").serializeAttribute(post._createSnapshot(), json, "title", { type: "string" }); deepEqual(json, { TITLE: "Rails is omakase" }); }); @@ -64,7 +63,7 @@ test("serializeBelongsTo", function() { var json = {}; - env.serializer.serializeBelongsTo(comment, json, { key: "post", options: {} }); + env.serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); deepEqual(json, { post: "1" }); }); @@ -75,7 +74,7 @@ test("serializeBelongsTo with null", function() { }); var json = {}; - env.serializer.serializeBelongsTo(comment, json, { key: "post", options: {} }); + env.serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); deepEqual(json, { post: null @@ -91,7 +90,7 @@ test("async serializeBelongsTo with null", function() { }); var json = {}; - env.serializer.serializeBelongsTo(comment, json, { key: "post", options: {} }); + env.serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); deepEqual(json, { post: null @@ -110,7 +109,7 @@ test("serializeBelongsTo respects keyForRelationship", function() { }); var json = {}; - env.container.lookup("serializer:post").serializeBelongsTo(comment, json, { key: "post", options: {} }); + env.container.lookup("serializer:post").serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); deepEqual(json, { POST: "1" @@ -131,7 +130,7 @@ test("serializeHasMany respects keyForRelationship", function() { var json = {}; - env.container.lookup("serializer:post").serializeHasMany(post, json, { key: "comments", options: {} }); + env.container.lookup("serializer:post").serializeHasMany(post._createSnapshot(), json, { key: "comments", options: {} }); deepEqual(json, { COMMENTS: ["1"] @@ -145,7 +144,7 @@ test("serializeIntoHash", function() { var json = {}; - env.serializer.serializeIntoHash(json, Post, post); + env.serializer.serializeIntoHash(json, Post, post._createSnapshot()); deepEqual(json, { title: "Rails is omakase", @@ -153,28 +152,46 @@ test("serializeIntoHash", function() { }); }); -test("serializePolymorphicType", function() { +test("serializePolymorphicType sync", function() { + expect(1); + env.registry.register('serializer:comment', DS.JSONSerializer.extend({ serializePolymorphicType: function(record, json, relationship) { var key = relationship.key; - var belongsTo = get(record, key); - json[relationship.key + "TYPE"] = belongsTo.constructor.typeKey; + var belongsTo = record.belongsTo(key); + json[relationship.key + "TYPE"] = belongsTo.typeKey; + + ok(true, 'serializePolymorphicType is called when serialize a polymorphic belongsTo'); } })); run(function() { - post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1" }); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post }); + post = env.store.createRecord('post', { title: 'Rails is omakase', id: 1 }); + comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); }); - var json = {}; + env.container.lookup('serializer:comment').serializeBelongsTo(comment._createSnapshot(), {}, { key: 'post', options: { polymorphic: true } }); +}); - env.container.lookup("serializer:comment").serializeBelongsTo(comment, json, { key: "post", options: { polymorphic: true } }); +test("serializePolymorphicType async", function() { + expect(1); - deepEqual(json, { - post: "1", - postTYPE: "post" + Comment.reopen({ + post: DS.belongsTo('post', { async: true }) + }); + + env.container.register('serializer:comment', DS.JSONSerializer.extend({ + serializePolymorphicType: function(record, json, relationship) { + ok(true, 'serializePolymorphicType is called when serialize a polymorphic belongsTo'); + } + })); + + run(function() { + post = env.store.createRecord(Post, { title: 'Rails is omakase', id: 1 }); + comment = env.store.createRecord(Comment, { body: 'Omakase is delicious', post: post }); }); + + env.container.lookup('serializer:comment').serializeBelongsTo(comment._createSnapshot(), {}, { key: 'post', options: { async: true, polymorphic: true } }); }); test("extractArray normalizes each record in the array", function() { @@ -233,7 +250,7 @@ test('Serializer should respect the attrs hash when serializing records', functi post = env.store.createRecord("post", { title: "Rails is omakase", parentPost: parentPost }); }); - var payload = env.container.lookup("serializer:post").serialize(post); + var payload = env.container.lookup("serializer:post").serialize(post._createSnapshot()); equal(payload.title_payload_key, "Rails is omakase"); equal(payload.my_parent, '2'); @@ -251,7 +268,7 @@ test('Serializer respects `serialize: false` on the attrs hash', function() { post = env.store.createRecord("post", { title: "Rails is omakase" }); }); - var payload = env.container.lookup("serializer:post").serialize(post); + var payload = env.container.lookup("serializer:post").serialize(post._createSnapshot()); ok(!payload.hasOwnProperty('title'), "Does not add the key to instance"); ok(!payload.hasOwnProperty('[object Object]'), "Does not add some random key like [object Object]"); @@ -273,7 +290,7 @@ test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` p var serializer = env.container.lookup("serializer:post"); var serializedProperty = serializer.keyForRelationship('comments', 'hasMany'); - var payload = serializer.serialize(post); + var payload = serializer.serialize(post._createSnapshot()); ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); }); @@ -293,7 +310,7 @@ test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` var serializer = env.container.lookup("serializer:comment"); var serializedProperty = serializer.keyForRelationship('post', 'belongsTo'); - var payload = serializer.serialize(comment); + var payload = serializer.serialize(comment._createSnapshot()); ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); }); @@ -321,7 +338,7 @@ test("Serializer should respect the primaryKey attribute when serializing record post = env.store.createRecord("post", { id: "1", title: "Rails is omakase" }); }); - var payload = env.container.lookup("serializer:post").serialize(post, { includeId: true }); + var payload = env.container.lookup("serializer:post").serialize(post._createSnapshot(), { includeId: true }); equal(payload._ID_, "1"); }); diff --git a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js index d61b9173437..2f472c5ff73 100644 --- a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js @@ -275,7 +275,7 @@ test("serialize polymorphicType", function() { ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); }); - var json = env.restSerializer.serialize(ray); + var json = env.restSerializer.serialize(ray._createSnapshot()); deepEqual(json, { name: "DeathRay", @@ -292,7 +292,7 @@ test("serialize polymorphicType with decamelized typeKey", function() { ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); }); - var json = env.restSerializer.serialize(ray); + var json = env.restSerializer.serialize(ray._createSnapshot()); deepEqual(json["evilMinionType"], "yellowMinion"); }); @@ -327,7 +327,7 @@ test("serialize polymorphic when associated object is null", function() { ray = env.store.createRecord(DoomsdayDevice, { name: "DeathRay" }); }); - var json = env.restSerializer.serialize(ray); + var json = env.restSerializer.serialize(ray._createSnapshot()); deepEqual(json["evilMinionType"], null); }); @@ -515,7 +515,7 @@ test("serializeIntoHash", function() { }); var json = {}; - env.restSerializer.serializeIntoHash(json, HomePlanet, league); + env.restSerializer.serializeIntoHash(json, HomePlanet, league._createSnapshot()); deepEqual(json, { homePlanet: { @@ -531,7 +531,7 @@ test("serializeIntoHash with decamelized typeKey", function() { }); var json = {}; - env.restSerializer.serializeIntoHash(json, HomePlanet, league); + env.restSerializer.serializeIntoHash(json, HomePlanet, league._createSnapshot()); deepEqual(json, { homePlanet: { diff --git a/packages/ember-data/tests/integration/snapshot_test.js b/packages/ember-data/tests/integration/snapshot_test.js new file mode 100644 index 00000000000..4eb91d0cbdd --- /dev/null +++ b/packages/ember-data/tests/integration/snapshot_test.js @@ -0,0 +1,340 @@ +var run = Ember.run; +var env, Post, Comment; + +module("integration/snapshot - DS.Snapshot", { + setup: function() { + Post = DS.Model.extend({ + author: DS.attr(), + title: DS.attr(), + comments: DS.hasMany({ async: true }) + }); + Comment = DS.Model.extend({ + body: DS.attr(), + post: DS.belongsTo({ async: true }) + }); + + env = setupStore({ + post: Post, + comment: Comment + }); + }, + + teardown: function() { + run(function() { + env.store.destroy(); + }); + } +}); + +test("record._createSnapshot() returns a snapshot", function() { + expect(1); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); + + ok(snapshot instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); + }); +}); + +test("snapshot.id, snapshot.type and snapshot.typeKey returns correctly", function() { + expect(3); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); + + equal(snapshot.id, '1', 'id is correct'); + ok(DS.Model.detect(snapshot.type), 'type is correct'); + equal(snapshot.typeKey, 'post', 'typeKey is correct'); + }); +}); + +test("snapshot.constructor is unique and deprecated", function() { + expect(4); + + run(function() { + var comment = env.store.push('comment', { id: 1, body: 'This is comment' }); + var post = env.store.push('post', { id: 2, title: 'Hello World' }); + var commentSnapshot = comment._createSnapshot(); + var postSnapshot = post._createSnapshot(); + + expectDeprecation(function() { + equal(commentSnapshot.constructor.typeKey, 'comment', 'constructor.typeKey is unique per type'); + }); + + expectDeprecation(function() { + equal(postSnapshot.constructor.typeKey, 'post', 'constructor.typeKey is unique per type'); + }); + }); +}); + +test("snapshot.attr() does not change when record changes", function() { + expect(2); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); + + equal(snapshot.attr('title'), 'Hello World', 'snapshot title is correct'); + post.set('title', 'Tomster'); + equal(snapshot.attr('title'), 'Hello World', 'snapshot title is still correct'); + }); +}); + +test("snapshot.attributes() returns a copy of all attributes for the current snapshot", function() { + expect(1); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); + + var attributes = snapshot.attributes(); + + deepEqual(attributes, { author: undefined, title: 'Hello World' }, 'attributes are returned correctly'); + }); +}); + +test("snapshot.belongsTo() returns undefined if relationship is undefined", function() { + expect(1); + + run(function() { + var comment = env.store.push('comment', { id: 1, body: 'This is comment' }); + var snapshot = comment._createSnapshot(); + var relationship = snapshot.belongsTo('post'); + + equal(relationship, undefined, 'relationship is undefined'); + }); +}); + +test("snapshot.belongsTo() returns a snapshot if relationship is set", function() { + expect(3); + + run(function() { + env.store.push('post', { id: 1, title: 'Hello World' }); + var comment = env.store.push('comment', { id: 2, body: 'This is comment', post: 1 }); + var snapshot = comment._createSnapshot(); + var relationship = snapshot.belongsTo('post'); + + ok(relationship instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); + equal(relationship.id, '1', 'post id is correct'); + equal(relationship.attr('title'), 'Hello World', 'post title is correct'); + }); +}); + +test("snapshot.hasMany() returns ID if option.id is set", function() { + expect(1); + + run(function() { + env.store.push('post', { id: 1, title: 'Hello World' }); + var comment = env.store.push('comment', { id: 2, body: 'This is comment', post: 1 }); + var snapshot = comment._createSnapshot(); + var relationship = snapshot.belongsTo('post', { id: true }); + + equal(relationship, '1', 'relationship ID correctly returned'); + }); +}); + +test("snapshot.hasMany() returns empty array if relationship is undefined", function() { + expect(2); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); + var relationship = snapshot.hasMany('comments'); + + ok(relationship instanceof Array, 'relationship is an instance of Array'); + equal(relationship.length, 0, 'relationship is empty'); + }); +}); + +test("snapshot.hasMany() returns array of snapshots if relationship is set", function() { + expect(5); + + run(function() { + env.store.push('comment', { id: 1, body: 'This is the first comment' }); + env.store.push('comment', { id: 2, body: 'This is the second comment' }); + var post = env.store.push('post', { id: 3, title: 'Hello World', comments: [1, 2] }); + var snapshot = post._createSnapshot(); + var relationship = snapshot.hasMany('comments'); + + ok(relationship instanceof Array, 'relationship is an instance of Array'); + equal(relationship.length, 2, 'relationship has two items'); + + var relationship1 = relationship[0]; + + ok(relationship1 instanceof DS.Snapshot, 'relationship item is an instance of DS.Snapshot'); + + equal(relationship1.id, '1', 'relationship item id is correct'); + equal(relationship1.attr('body'), 'This is the first comment', 'relationship item body is correct'); + }); +}); + +test("snapshot.hasMany() returns array of IDs if option.ids is set", function() { + expect(1); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World', comments: [2, 3] }); + var snapshot = post._createSnapshot(); + var relationship = snapshot.hasMany('comments', { ids: true }); + + deepEqual(relationship, ['2', '3'], 'relationship IDs correctly returned'); + }); +}); + +test("snapshot.eachAttribute() proxies to record", function() { + expect(1); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); + + var attributes = []; + snapshot.eachAttribute(function(name) { + attributes.push(name); + }); + deepEqual(attributes, ['author', 'title'], 'attributes are iterated correctly'); + }); +}); + +test("snapshot.eachRelationship() proxies to record", function() { + expect(2); + + var getRelationships = function(snapshot) { + var relationships = []; + snapshot.eachRelationship(function(name) { + relationships.push(name); + }); + return relationships; + }; + + run(function() { + var comment = env.store.push('comment', { id: 1, body: 'This is the first comment' }); + var post = env.store.push('post', { id: 2, title: 'Hello World' }); + var snapshot; + + snapshot = comment._createSnapshot(); + deepEqual(getRelationships(snapshot), ['post'], 'relationships are iterated correctly'); + + snapshot = post._createSnapshot(); + deepEqual(getRelationships(snapshot), ['comments'], 'relationships are iterated correctly'); + }); +}); + +test("snapshot.belongsTo() does not trigger a call to store.scheduleFetch", function() { + expect(0); + + env.store.scheduleFetch = function() { + ok(false, 'store.scheduleFetch should not be called'); + }; + + run(function() { + var comment = env.store.push('comment', { id: 2, body: 'This is comment', post: 1 }); + var snapshot = comment._createSnapshot(); + + snapshot.belongsTo('post'); + }); +}); + +test("snapshot.hasMany() does not trigger a call to store.scheduleFetch", function() { + expect(0); + + env.store.scheduleFetch = function() { + ok(false, 'store.scheduleFetch should not be called'); + }; + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World', comments: [2, 3] }); + var snapshot = post._createSnapshot(); + + snapshot.hasMany('comments'); + }); +}); + +test("snapshot.get() is deprecated", function() { + expect(1); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); + + expectDeprecation(function() { + snapshot.get('title'); + }, 'Using DS.Snapshot.get() is deprecated. Use .attr(), .belongsTo() or .hasMany() instead.'); + }); +}); + +test("snapshot.get() returns id", function() { + expect(2); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); + + expectDeprecation(function() { + equal(snapshot.get('id'), '1', 'snapshot id is correct'); + }); + }); +}); + +test("snapshot.get() returns attribute", function() { + expect(2); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); + + expectDeprecation(function() { + equal(snapshot.get('title'), 'Hello World', 'snapshot title is correct'); + }); + }); +}); + +test("snapshot.get() returns belongsTo", function() { + expect(3); + + run(function() { + var comment = env.store.push('comment', { id: 1, body: 'This is a comment', post: 2 }); + var snapshot = comment._createSnapshot(); + var relationship; + + expectDeprecation(function() { + relationship = snapshot.get('post'); + }); + + ok(relationship instanceof DS.Snapshot, 'relationship is an instance of DS.Snapshot'); + equal(relationship.id, '2', 'relationship id is correct'); + }); +}); + +test("snapshot.get() returns hasMany", function() { + expect(3); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World', comments: [2, 3] }); + var snapshot = post._createSnapshot(); + var relationship; + + expectDeprecation(function() { + relationship = snapshot.get('comments'); + }); + + ok(relationship instanceof Array, 'relationship is an instance of Array'); + equal(relationship.length, 2, 'relationship has two items'); + }); +}); + +test("snapshot.get() proxies property to record unless identified as id, attribute or relationship", function() { + expect(2); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); + + post.set('category', 'Ember.js'); // category is not defined as an DS.attr() + + expectDeprecation(function() { + equal(snapshot.get('category'), 'Ember.js', 'snapshot proxies unknown property correctly'); + }); + }); +}); From 4bf6a8eed89f440cc2fe25713cf7a2649dc4d70f Mon Sep 17 00:00:00 2001 From: James Herdman Date: Tue, 2 Dec 2014 23:11:25 -0500 Subject: [PATCH 0635/2527] Belongs To Polymorphic Async Bug Failing Test --- .../serializers/json_serializer_test.js | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index 111055b3ad6..4ef9a73724d 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -1,5 +1,5 @@ var get = Ember.get; -var Post, post, Comment, comment, env; +var Post, post, Comment, comment, Favorite, favorite, env; var run = Ember.run; module("integration/serializer/json - JSONSerializer", { @@ -12,12 +12,17 @@ module("integration/serializer/json - JSONSerializer", { body: DS.attr('string'), post: DS.belongsTo('post') }); + Favorite = DS.Model.extend({ + post: DS.belongsTo('post', { async: true, polymorphic: true }) + }); env = setupStore({ post: Post, - comment: Comment + comment: Comment, + favorite: Favorite }); env.store.modelFor('post'); env.store.modelFor('comment'); + env.store.modelFor('favorite'); }, teardown: function() { @@ -429,3 +434,28 @@ test("Calling normalize should normalize the payload (only the passed keys)", fu inHash: 'blah' }); }); + +test('serializeBelongsTo with async polymorphic', function() { + var json = {}, + expectedJSON = { post: '1', postTYPE: 'post' }; + + env.container.register('serializer:favorite', DS.JSONSerializer.extend({ + serializePolymorphicType: function(record, json, relationship) { + var key = relationship.key; + json[relationship.key + 'TYPE'] = record.constructor.typeKey; + } + })); + + run(function() { + post = env.store.createRecord(Post, { title: 'Kitties are omakase', id: '1' }); + favorite = env.store.createRecord(Favorite, { post: post, id: '3' }); + }); + + env.container.lookup('serializer:favorite').serializeBelongsTo(favorite, json, { key: 'post', options: { polymorphic: true, async: true } }); + + deepEqual( + json, + expectedJSON, + 'Expected: ' + JSON.stringify(expectedJSON) + ', Got: ' + JSON.stringify(json) + ); +}); From 83e9cc8134cad1cff98be87edb2a394f4a146f13 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 7 Jan 2015 21:33:40 +0100 Subject: [PATCH 0636/2527] Added serializeBelongsTo with async polymorphic test for RESTSerializer --- .../serializers/json_serializer_test.js | 17 +++++++---------- .../serializers/rest_serializer_test.js | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index 4ef9a73724d..18a8f77d0b9 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -436,13 +436,14 @@ test("Calling normalize should normalize the payload (only the passed keys)", fu }); test('serializeBelongsTo with async polymorphic', function() { - var json = {}, - expectedJSON = { post: '1', postTYPE: 'post' }; + var post, favorite; + var json = {}; + var expected = { post: '1', postTYPE: 'post' }; env.container.register('serializer:favorite', DS.JSONSerializer.extend({ - serializePolymorphicType: function(record, json, relationship) { + serializePolymorphicType: function(snapshot, json, relationship) { var key = relationship.key; - json[relationship.key + 'TYPE'] = record.constructor.typeKey; + json[key + 'TYPE'] = snapshot.belongsTo(key).typeKey; } })); @@ -451,11 +452,7 @@ test('serializeBelongsTo with async polymorphic', function() { favorite = env.store.createRecord(Favorite, { post: post, id: '3' }); }); - env.container.lookup('serializer:favorite').serializeBelongsTo(favorite, json, { key: 'post', options: { polymorphic: true, async: true } }); + env.container.lookup('serializer:favorite').serializeBelongsTo(favorite._createSnapshot(), json, { key: 'post', options: { polymorphic: true, async: true } }); - deepEqual( - json, - expectedJSON, - 'Expected: ' + JSON.stringify(expectedJSON) + ', Got: ' + JSON.stringify(json) - ); + deepEqual(json, expected, 'returned JSON is correct'); }); diff --git a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js index 2f472c5ff73..ed3b5ec8013 100644 --- a/packages/ember-data/tests/integration/serializers/rest_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/rest_serializer_test.js @@ -539,3 +539,18 @@ test("serializeIntoHash with decamelized typeKey", function() { } }); }); + +test('serializeBelongsTo with async polymorphic', function() { + var evilMinion, doomsdayDevice; + var json = {}; + var expected = { evilMinion: '1', evilMinionType: 'evilMinion' }; + + run(function() { + evilMinion = env.store.createRecord('evilMinion', { id: 1, name: 'Tomster' }); + doomsdayDevice = env.store.createRecord('doomsdayDevice', { id: 2, name: 'Yehuda', evilMinion: evilMinion }); + }); + + env.restSerializer.serializeBelongsTo(doomsdayDevice._createSnapshot(), json, { key: 'evilMinion', options: { polymorphic: true, async: true } }); + + deepEqual(json, expected, 'returned JSON is correct'); +}); From b5f86f36cf2ba36d078ee14a880a0c4724bee639 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Sat, 10 Jan 2015 02:09:01 +0100 Subject: [PATCH 0637/2527] Pass JSHint --- .../tests/integration/serializers/json_serializer_test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/ember-data/tests/integration/serializers/json_serializer_test.js b/packages/ember-data/tests/integration/serializers/json_serializer_test.js index 18a8f77d0b9..4351956f77b 100644 --- a/packages/ember-data/tests/integration/serializers/json_serializer_test.js +++ b/packages/ember-data/tests/integration/serializers/json_serializer_test.js @@ -1,4 +1,3 @@ -var get = Ember.get; var Post, post, Comment, comment, Favorite, favorite, env; var run = Ember.run; @@ -436,7 +435,6 @@ test("Calling normalize should normalize the payload (only the passed keys)", fu }); test('serializeBelongsTo with async polymorphic', function() { - var post, favorite; var json = {}; var expected = { post: '1', postTYPE: 'post' }; From 7a653bc78faea813edf4f5f5331af6b54a61dc8f Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 14 Feb 2015 15:15:54 -0600 Subject: [PATCH 0638/2527] use package.json for ember addon We should migrate Ember Data to an ember addon soon. Until then, we remove a step that could be automated in the release pipeline by using the version in package.json --- lib/ember-addon/blueprints/ember-data/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/ember-addon/blueprints/ember-data/index.js b/lib/ember-addon/blueprints/ember-data/index.js index 30ef0bebe13..289382d65be 100644 --- a/lib/ember-addon/blueprints/ember-data/index.js +++ b/lib/ember-addon/blueprints/ember-data/index.js @@ -8,6 +8,7 @@ module.exports = { }, afterInstall: function() { - return this.addBowerPackageToProject('ember-data', '1.0.0-beta.14.1'); + var json = require('../../../../package.json'); + return this.addBowerPackageToProject('ember-data', json.version); } }; From dde7957c319e26f25f7d45db123cad58600edc00 Mon Sep 17 00:00:00 2001 From: bmac Date: Sat, 14 Feb 2015 16:24:24 -0500 Subject: [PATCH 0639/2527] Release 1.0.0-beta.15 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2ee39547110..0b100974aaa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.15-canary", + "version": "1.0.0-beta.15", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", From eaca9848e88180a051aff20620a299e735bb552e Mon Sep 17 00:00:00 2001 From: bmac Date: Sat, 14 Feb 2015 17:14:26 -0500 Subject: [PATCH 0640/2527] Update changelog for 1.0.0-beta.15 release --- CHANGELOG.md | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cc824363bc..3aa63a21024 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,91 @@ ### Master +#### serializer.serialize() now receives a Snapshot instead of a record instance +A snapshot represents the frozen state of a record at a particular +moment in time. Its initial purpose is to be passed to serializers +instead of the real record. This allows the serializer to examine the +current state of that record in the moment without triggering +side-effects, like loading relationships. + +The serializer has a different API from a record for accessing +properties so you will know you are working with a snapshot. Using +`snapshot.get` is still supported for compatibility however it will +log a deprecated warning to encourage you to use the new apis. + +To access attributes you should now use the `attr` function. + +```js +// Ember Data 1.0.0-beta.14.1 +post.get('title'); +// Ember Data 1.0.0-beta.15 +postSnapshot.attr('title'); +``` + +To access a belongsTo relationship you should use `.belongsTo()` method. + +```js +// Ember Data 1.0.0-beta.14.1 +post.get('author'); +// Ember Data 1.0.0-beta.15 +postSnapshot.belongsTo('author'); +``` + +To access a hasMany relationship you should use `.hasMany()` method. + +```js +// Ember Data 1.0.0-beta.14.1 +post.get('comments'); +// Ember Data 1.0.0-beta.15 +postSnapshot.hasMany('comments'); +``` + +#### RecordArray.pushRecord and ManyArray.addRecord/removeRecord are deprecated + +If you would like to add a new record to a `RecordArray` or a +`ManyArray` you should now use the `addObject` and `removeObject` +methods. + +### Release 1.0.0-beta.15 (February 14, 2015) + * use package.json for ember addon + * Initial implementation of the Snapshot API + * Allow errors on arbitrary properties, not just defined attributes or relationships + * Fix bug preventing hasMany relationships from correctly tracking simultaneous adds and removes. + * remove unused code. + * Deprecate store.dematerializeRecord() + * Use store.unloadRecord() in favor of store.dematerializeRecord() + * Correctly trigger arrayContentDidChange when updating hasMany relationships + * Warn if the user specifies a reflexive relationship without explicitly defining the inverse + * bump ember-inflector dependency for HTMLBars compat + * Add adapter.hasMany unique IDs test + * Replace calls to `container` with `registry` + * Dematerialize rejected _find() if record isEmpty + * Add a Serializer base class + * Make ManyArray.save() and RecordArray.save() return themselves + * Added save() to ManyArray + * idiomatic super usage. + * Created `store.fetchById` and `store.fetchAll`. + * Update the generateIdForRecord docs to show it gets passed an Object not a record instance. + * Sort query params in ajax calls. + * Cleanup JSONSerializer#extract example + * Split Relationship Tests into Separate Files + * [DOCS]Update about defining application's store + * add documentation for the Store's find method + * Do not double include the host when it uses a protocol relative url. + * Deprecate RecordArray.pushRecord() + * Wrap the errorThrown in an Error object if it's a string. + * Use forEach instead of private api for accessing Map values + * Disable unknown keys warning by default + * remove type check for addCanonicalRecord in belongsto relationship + * Add support for embedded polymorphic belongsTo + * observers only fire for properties that changed + * Don't refilter .all() and .find() if only properties changed + * fixes to load beta 14/14.1 sourcemaps in ember-cli + * fix version for dropped <= Ember 1.7 support + * generateIdForRecord gets type & object properties passed to it + * Clarify store.find via findAll docs + * Deprecate addRecord/removeRecord for ManyArray + ### Ember Data 1.0.0-beta.14.1 (December 31, 2014) * Replace `<%= versionStamp %>` with actual version stamp. Thanks From f1be2af71d7402d034bc034d9502733647cad295 Mon Sep 17 00:00:00 2001 From: bmac Date: Sat, 14 Feb 2015 17:23:57 -0500 Subject: [PATCH 0641/2527] Bump the version to 1.0.0-beta.16+canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0b100974aaa..67cb8ecccbe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.15", + "version": "1.0.0-beta.16+canary", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", From 9fbac10d47a2ceb79924c5ad3137f482a40ec0ee Mon Sep 17 00:00:00 2001 From: "Andrey Mikhaylov (lolmaus)" Date: Sun, 15 Feb 2015 22:35:40 +0300 Subject: [PATCH 0642/2527] (Docs) ManyArray is no longer a RecordArray Further docs refining may be needed --- packages/ember-data/lib/system/record_arrays/many_array.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/record_arrays/many_array.js b/packages/ember-data/lib/system/record_arrays/many_array.js index 54dd44c3545..8d7a98fecd4 100644 --- a/packages/ember-data/lib/system/record_arrays/many_array.js +++ b/packages/ember-data/lib/system/record_arrays/many_array.js @@ -7,7 +7,7 @@ var get = Ember.get; var set = Ember.set; /** - A `ManyArray` is a `RecordArray` that represents the contents of a has-many + A `ManyArray` is a `MutableArray` that represents the contents of a has-many relationship. The `ManyArray` is instantiated lazily the first time the relationship is From 4ddf56cb093fa66bc5eefc0f0ffa62f9edd24d96 Mon Sep 17 00:00:00 2001 From: Joe Ruello Date: Tue, 17 Feb 2015 10:44:58 +1100 Subject: [PATCH 0643/2527] [DOC]: Clarify when didCreate is fired Previous doc was ambiguous and could be interpreted to mean when the record is created using createRecord(). Clarifies that the event is fired when a new record is saved. --- packages/ember-data/lib/system/model/model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 9562ddb9389..a1feba5f339 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -431,7 +431,7 @@ var Model = Ember.Object.extend(Ember.Evented, { didUpdate: Ember.K, /** - Fired when the record is created. + Fired when a new record is commited to the server. @event didCreate */ From e23ca8790d8e56faf816621ce55f9ca09c9fb90e Mon Sep 17 00:00:00 2001 From: IgorT Date: Wed, 11 Feb 2015 11:25:40 +0100 Subject: [PATCH 0644/2527] Adds support for using mixins in polymorphic relationships Now it's possible to reference mixins in polymorphic relationships. For example: ``` var Comment = DS.Model.extend({ owner: belongsTo('commentable'. { polymorphic: true }) }); var Commentable = Ember.Mixin.create({ comments: hasMany('comment') }); ``` --- .../system/relationships/state/belongs_to.js | 12 +- .../system/relationships/state/has_many.js | 12 +- packages/ember-data/lib/system/store.js | 39 ++++- .../polymorphic_mixins_belongs_to_test.js | 149 +++++++++++++++++ .../polymorphic_mixins_has_many_test.js | 157 ++++++++++++++++++ tests/index.html | 7 +- 6 files changed, 361 insertions(+), 15 deletions(-) create mode 100644 packages/ember-data/tests/integration/relationships/polymorphic_mixins_belongs_to_test.js create mode 100644 packages/ember-data/tests/integration/relationships/polymorphic_mixins_has_many_test.js diff --git a/packages/ember-data/lib/system/relationships/state/belongs_to.js b/packages/ember-data/lib/system/relationships/state/belongs_to.js index 4d87e7dab3a..d8c07242f9d 100644 --- a/packages/ember-data/lib/system/relationships/state/belongs_to.js +++ b/packages/ember-data/lib/system/relationships/state/belongs_to.js @@ -61,13 +61,13 @@ BelongsToRelationship.prototype.addRecord = function(newRecord) { if (this.members.has(newRecord)) { return;} var type = this.relationshipMeta.type; Ember.assert("You can only add a '" + type.typeKey + "' record to this relationship", (function () { - if (newRecord instanceof type) { - return true; - } else if (Ember.MODEL_FACTORY_INJECTIONS) { - return newRecord instanceof type.superclass; + if (type.__isMixin) { + return type.__mixin.detect(newRecord); } - - return false; + if (Ember.MODEL_FACTORY_INJECTIONS) { + type = type.superclass; + } + return newRecord instanceof type; })()); if (this.inverseRecord) { diff --git a/packages/ember-data/lib/system/relationships/state/has_many.js b/packages/ember-data/lib/system/relationships/state/has_many.js index a8fedf4a6c5..ab7cabb36ef 100644 --- a/packages/ember-data/lib/system/relationships/state/has_many.js +++ b/packages/ember-data/lib/system/relationships/state/has_many.js @@ -86,13 +86,13 @@ ManyRelationship.prototype.removeRecordFromOwn = function(record, idx) { ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) { var type = this.relationshipMeta.type; Ember.assert("You cannot add '" + record.constructor.typeKey + "' records to the " + this.record.constructor.typeKey + "." + this.key + " relationship (only '" + this.belongsToType.typeKey + "' allowed)", (function () { - if (record instanceof type) { - return true; - } else if (Ember.MODEL_FACTORY_INJECTIONS) { - return record instanceof type.superclass; + if (type.__isMixin) { + return type.__mixin.detect(record); } - - return false; + if (Ember.MODEL_FACTORY_INJECTIONS) { + type = type.superclass; + } + return record instanceof type; })()); this.record.notifyHasManyAdded(this.key, record, idx); diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 5a928f8b7fa..6100249c84e 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1348,6 +1348,35 @@ Store = Ember.Object.extend({ return record; }, + /* + In case someone defined a relationship to a mixin, for example: + ``` + var Comment = DS.Model.extend({ + owner: belongsTo('commentable'. { polymorphic: true}) + }); + var Commentable = Ember.Mixin.create({ + comments: hasMany('comment') + }); + ``` + we want to look up a Commentable class which has all the necessary + relationship metadata. Thus, we look up the mixin and create a mock + DS.Model, so we can access the relationship CPs of the mixin (`comments`) + in this case + */ + + _modelForMixin: function(key) { + var mixin = this.container.resolve('mixin:' + key); + if (mixin) { + //Cache the class as a model + this.container.register('model:' + key, DS.Model.extend(mixin)); + } + var factory = this.modelFactoryFor(key); + factory.__isMixin = true; + factory.__mixin = mixin; + + return factory; + }, + /** Returns a model class for a particular key. Used by methods that take a type key (like `find`, `createRecord`, @@ -1362,6 +1391,10 @@ Store = Ember.Object.extend({ if (typeof key === 'string') { factory = this.modelFactoryFor(key); + if (!factory) { + //Support looking up mixins as base types for polymorphic relationships + factory = this._modelForMixin(key); + } if (!factory) { throw new Ember.Error("No model was found for '" + key + "'"); } @@ -1379,7 +1412,11 @@ Store = Ember.Object.extend({ }, modelFactoryFor: function(key) { - return this.container.lookupFactory('model:' + key); + if (this.container.has('model:' + key)) { + return this.container.lookupFactory('model:' + key); + } else { + return null; + } }, /** diff --git a/packages/ember-data/tests/integration/relationships/polymorphic_mixins_belongs_to_test.js b/packages/ember-data/tests/integration/relationships/polymorphic_mixins_belongs_to_test.js new file mode 100644 index 00000000000..830b138d768 --- /dev/null +++ b/packages/ember-data/tests/integration/relationships/polymorphic_mixins_belongs_to_test.js @@ -0,0 +1,149 @@ +var env, store, User, Message, Video, NotMessage; +var run = Ember.run; + +var attr = DS.attr; +var belongsTo = DS.belongsTo; + +function stringify(string) { + return function() { return string; }; +} + +module('integration/relationships/polymorphic_mixins_belongs_to_test - Polymorphic belongsTo relationships with mixins', { + setup: function() { + User = DS.Model.extend({ + name: attr('string'), + bestMessage: belongsTo('message', { async: true, polymorphic: true }) + }); + User.toString = stringify('User'); + + Message = Ember.Mixin.create({ + title: attr('string'), + user: belongsTo('user', { async: true }) + }); + Message.toString = stringify('Message'); + + NotMessage = DS.Model.extend({ + video: attr() + }); + + Video = DS.Model.extend(Message, { + video: attr() + }); + + env = setupStore({ + user: User, + video: Video, + notMessage: NotMessage + }); + + env.container.register('mixin:message', Message); + store = env.store; + }, + + teardown: function() { + run(env.container, 'destroy'); + } +}); + +/* + Server loading tests +*/ + +test("Relationship is available from the belongsTo side even if only loaded from the inverse side - async", function () { + var user, video; + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', bestMessage: 2, bestMessageType: 'video' }); + video = store.push('video', { id: 2, video: 'Here comes Youtube' }); + }); + run(function() { + user.get('bestMessage').then(function(message) { + equal(message, video, 'The message was loaded correctly'); + message.get('user').then(function(fetchedUser) { + equal(fetchedUser, user, 'The inverse was setup correctly'); + }); + }); + }); +}); + +/* + Local edits +*/ +test("Setting the polymorphic belongsTo gets propagated to the inverse side - async", function () { + var user, video; + run(function() { + user = store.push('user', { id: 1, name: 'Stanley' }); + video = store.push('video', { id: 2, video: 'Here comes Youtube' }); + }); + + run(function() { + user.set('bestMessage', video); + video.get('user').then(function(fetchedUser) { + equal(fetchedUser, user, "user got set correctly"); + }); + user.get('bestMessage').then(function(message) { + equal(message, video, 'The message was set correctly'); + }); + }); +}); + +test("Setting the polymorphic belongsTo with an object that does not implement the mixin errors out", function () { + var user, video; + run(function() { + user = store.push('user', { id: 1, name: 'Stanley' }); + video = store.push('notMessage', { id: 2, video: 'Here comes Youtube' }); + }); + + run(function() { + expectAssertion(function() { + user.set('bestMessage', video); + }, /You can only add a 'message' record to this relationship/); + }); +}); + + +test("Setting the polymorphic belongsTo gets propagated to the inverse side - model injections true", function () { + expect(2); + var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; + Ember.MODEL_FACTORY_INJECTIONS = true; + + try { + var user, video; + run(function() { + user = store.push('user', { id: 1, name: 'Stanley' }); + video = store.push('video', { id: 2, video: 'Here comes Youtube' }); + }); + + run(function() { + user.set('bestMessage', video); + video.get('user').then(function(fetchedUser) { + equal(fetchedUser, user, "user got set correctly"); + }); + user.get('bestMessage').then(function(message) { + equal(message, video, 'The message was set correctly'); + }); + }); + } finally { + Ember.MODEL_FACTORY_INJECTIONS = injectionValue; + } +}); + +test("Setting the polymorphic belongsTo with an object that does not implement the mixin errors out - model injections true", function () { + var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; + Ember.MODEL_FACTORY_INJECTIONS = true; + + try { + var user, video; + run(function() { + user = store.push('user', { id: 1, name: 'Stanley' }); + video = store.push('notMessage', { id: 2, video: 'Here comes Youtube' }); + }); + + run(function() { + expectAssertion(function() { + user.set('bestMessage', video); + }, /You can only add a 'message' record to this relationship/); + }); + } finally { + Ember.MODEL_FACTORY_INJECTIONS = injectionValue; + } +}); diff --git a/packages/ember-data/tests/integration/relationships/polymorphic_mixins_has_many_test.js b/packages/ember-data/tests/integration/relationships/polymorphic_mixins_has_many_test.js new file mode 100644 index 00000000000..26b723c6cdc --- /dev/null +++ b/packages/ember-data/tests/integration/relationships/polymorphic_mixins_has_many_test.js @@ -0,0 +1,157 @@ +var env, store, User, Message, NotMessage, Video; +var run = Ember.run; + +var attr = DS.attr; +var hasMany = DS.hasMany; +var belongsTo = DS.belongsTo; + +function stringify(string) { + return function() { return string; }; +} + +module('integration/relationships/polymorphic_mixins_has_many_test - Polymorphic hasMany relationships with mixins', { + setup: function() { + User = DS.Model.extend({ + name: attr('string'), + messages: hasMany('message', { async: true, polymorphic: true }) + }); + User.toString = stringify('User'); + + Message = Ember.Mixin.create({ + title: attr('string'), + user: belongsTo('user', { async: true }) + }); + Message.toString = stringify('Message'); + + Video = DS.Model.extend(Message, { + video: attr() + }); + + NotMessage = DS.Model.extend({ + video: attr() + }); + + env = setupStore({ + user: User, + video: Video, + notMessage: NotMessage + }); + + env.container.register('mixin:message', Message); + store = env.store; + }, + + teardown: function() { + run(env.container, 'destroy'); + } +}); + +/* + Server loading tests +*/ + +test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - async", function () { + var user, video; + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [{ id: 2, type: 'video' }] }); + video = store.push('video', { id: 2, video: 'Here comes Youtube' }); + }); + run(function() { + user.get('messages').then(function(messages) { + equal(messages.objectAt(0), video, 'The hasMany has loaded correctly'); + messages.objectAt(0).get('user').then(function(fetchedUser) { + equal(fetchedUser, user, 'The inverse was setup correctly'); + }); + }); + }); +}); + +/* + Local edits +*/ +test("Pushing to the hasMany reflects the change on the belongsTo side - async", function () { + var user, video; + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [] }); + video = store.push('video', { id: 2, video: 'Here comes Youtube' }); + }); + + run(function() { + user.get('messages').then(function(fetchedMessages) { + fetchedMessages.pushObject(video); + video.get('user').then(function(fetchedUser) { + equal(fetchedUser, user, "user got set correctly"); + }); + }); + }); +}); + +/* + Local edits +*/ +test("Pushing a an object that does not implement the mixin to the mixin accepting array errors out", function () { + var user,notMessage; + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [] }); + notMessage = store.push('notMessage', { id: 2, video: 'Here comes Youtube' }); + }); + + run(function() { + user.get('messages').then(function(fetchedMessages) { + expectAssertion(function() { + fetchedMessages.pushObject(notMessage); + }, /You cannot add 'notMessage' records to the user\.messages relationship \(only 'message' allowed\)/); + }); + }); +}); + +test("Pushing to the hasMany reflects the change on the belongsTo side - model injections true", function () { + var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; + Ember.MODEL_FACTORY_INJECTIONS = true; + + try { + var user, video; + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [] }); + video = store.push('video', { id: 2, video: 'Here comes Youtube' }); + }); + + run(function() { + user.get('messages').then(function(fetchedMessages) { + fetchedMessages.pushObject(video); + video.get('user').then(function(fetchedUser) { + equal(fetchedUser, user, "user got set correctly"); + }); + }); + }); + } finally { + Ember.MODEL_FACTORY_INJECTIONS = injectionValue; + } +}); + +/* + Local edits +*/ +test("Pushing a an object that does not implement the mixin to the mixin accepting array errors out - model injections true", function () { + var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; + Ember.MODEL_FACTORY_INJECTIONS = true; + + try { + var user,notMessage; + run(function() { + user = store.push('user', { id: 1, name: 'Stanley', messages: [] }); + notMessage = store.push('notMessage', { id: 2, video: 'Here comes Youtube' }); + }); + + run(function() { + user.get('messages').then(function(fetchedMessages) { + expectAssertion(function() { + fetchedMessages.pushObject(notMessage); + }, /You cannot add 'notMessage' records to the user\.messages relationship \(only 'message' allowed\)/); + }); + }); + } finally { + Ember.MODEL_FACTORY_INJECTIONS = injectionValue; + } +}); + diff --git a/tests/index.html b/tests/index.html index 10c4f50e3c7..e5a0b0e078a 100644 --- a/tests/index.html +++ b/tests/index.html @@ -43,8 +43,11 @@ - + + +
      From 82c1ce44aafa33e12fa56e3719fa53a0c13be8ff Mon Sep 17 00:00:00 2001 From: Sergio Arbeo Date: Tue, 26 May 2015 14:06:10 +0200 Subject: [PATCH 0797/2527] Fix warning message after typeForRoot renaming. --- packages/ember-data/lib/serializers/rest_serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/rest_serializer.js b/packages/ember-data/lib/serializers/rest_serializer.js index 1d3722b7e93..96471585413 100644 --- a/packages/ember-data/lib/serializers/rest_serializer.js +++ b/packages/ember-data/lib/serializers/rest_serializer.js @@ -751,7 +751,7 @@ var RESTSerializer = JSONSerializer.extend({ Ember.runInDebug(function() { RESTSerializer.reopen({ warnMessageNoModelForKey: function(prop, typeKey) { - return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + typeKey + '" (resolved model name using ' + this.constructor.toString() + '.typeForRoot("' + prop + '"))'; + return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + typeKey + '" (resolved model name using ' + this.constructor.toString() + '.modelNameFromPayloadKey("' + prop + '"))'; } }); }); From 55a03019e15d673c85e46fcc79120d86bc7e53f6 Mon Sep 17 00:00:00 2001 From: Sergio Arbeo Date: Tue, 26 May 2015 14:06:10 +0200 Subject: [PATCH 0798/2527] Fix warning message after typeForRoot renaming. --- packages/ember-data/lib/serializers/rest-serializer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index df84c921e97..6acdfecd9e4 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -827,8 +827,8 @@ var RESTSerializer = JSONSerializer.extend({ Ember.runInDebug(function() { RESTSerializer.reopen({ - warnMessageNoModelForKey: function(prop, modelName) { - return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + modelName + '" (resolved model name using ' + this.constructor.toString() + '.typeForRoot("' + prop + '"))'; + warnMessageNoModelForKey: function(prop, typeKey) { + return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + typeKey + '" (resolved model name using ' + this.constructor.toString() + '.modelNameFromPayloadKey("' + prop + '"))'; } }); }); From 75d7d8d63d3a6ac883a6b44f2dde42cce1a102f5 Mon Sep 17 00:00:00 2001 From: Tony Schneider Date: Tue, 26 May 2015 16:11:17 -0400 Subject: [PATCH 0799/2527] Cleanup unused 'materialize' records in model --- packages/ember-data/lib/system/model/model.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 6de8fd51257..85f9caf5f7e 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -971,19 +971,6 @@ var Model = Ember.Object.extend(Ember.Evented, { this._notifyProperties(changedKeys); }, - materializeId: function(id) { - set(this, 'id', id); - }, - - materializeAttributes: function(attributes) { - Ember.assert("Must pass an object to materializeAttributes", !!attributes); - merge(this._data, attributes); - }, - - materializeAttribute: function(name, value) { - this._data[name] = value; - }, - /** If the model `isDirty` this function will discard any unsaved changes. If the model `isNew` it will be removed from the store. From 911519dee51916f55fdea49677f7486f953e9953 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 28 May 2015 13:46:47 -0500 Subject: [PATCH 0800/2527] Revert "transform tests through the module compiler" This reverts commit 37f78e38e4dd2c3c871f6eb329c8678246464fca. --- Brocfile.js | 75 +++++++++++++++++++++++++++++------------------- lib/amd-build.js | 26 ++++++++++++++--- lib/lib-tree.js | 9 ------ lib/test-tree.js | 40 -------------------------- package.json | 6 ++-- tests/index.html | 25 +--------------- 6 files changed, 71 insertions(+), 110 deletions(-) delete mode 100644 lib/lib-tree.js delete mode 100644 lib/test-tree.js diff --git a/Brocfile.js b/Brocfile.js index c095e88fda6..a69bbe62f8d 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -7,11 +7,11 @@ var uglify = require('broccoli-uglify-js'); var es3SafeRecast = require('broccoli-es3-safe-recast'); var env = process.env.EMBER_ENV; var amdBuild = require('./lib/amd-build'); -var testTree = require('./lib/test-tree'); -var libTree = require('./lib/lib-tree'); var pickFiles = require('broccoli-static-compiler'); var merge = require('broccoli-merge-trees'); var moveFile = require('broccoli-file-mover'); +var wrap = require('broccoli-wrap'); +var jshint = require('broccoli-jshint'); var defeatureify = require('broccoli-defeatureify'); var version = require('git-repo-version')(10); var yuidoc = require('broccoli-yuidoc'); @@ -19,10 +19,9 @@ var replace = require('broccoli-replace'); var stew = require('broccoli-stew'); var path = require('path'); var fs = require('fs'); +var jscsTree = require('broccoli-jscs'); var babel = require('broccoli-babel-transpiler'); var babelOptions = require('./config/babel'); -var fileCreator = require('broccoli-file-creator'); -var jscs = require('broccoli-jscs'); function minify(tree, name){ var config = require('./config/ember-defeatureify'); @@ -34,11 +33,6 @@ function minify(tree, name){ srcFile: name + '.js', destFile: '/' + name + '.prod.js' }); - tree = pickFiles(tree, { - srcDir: '/', - destDir: '/', - files: [ name + '.prod.js' ] - }); tree = removeSourceMappingURL(tree); var uglified = moveFile(uglify(tree, {mangle: true}),{ srcFile: name + '.prod.js', @@ -47,6 +41,26 @@ function minify(tree, name){ return merge([uglified, tree], {overwrite: true}); } +function testTree(packageName){ + var test = pickFiles('packages/' + packageName + '/tests', { + srcDir: '/', + files: [ '**/*.js' ], + destDir: '/' + packageName + }); + var jshinted = jshint('packages/' + packageName + '/', { + jshintrcPath: path.join(__dirname, '.jshintrc') + }); + jshinted = wrap(jshinted, { + wrapper: [ "if (!QUnit.urlParams.nojshint) {\n", "\n}"], + }); + jshinted = pickFiles(jshinted, { + files: ['{lib,tests}/**/*.js'], + srcDir: '/', + destDir: '/' + packageName + '-jshint' + }); + return merge([jshinted, test]); +} + var yuidocTree = yuidoc('packages', { srcDir: '/', destDir: 'docs', @@ -72,7 +86,7 @@ var yuidocTree = yuidoc('packages', { function package(packagePath, vendorPath) { vendorPath = vendorPath || 'packages/'; return pickFiles(vendorPath + packagePath, { - files: [ '**/*.js' ], + files: [ 'lib/**/*.js' ], srcDir: '/', destDir: '/' + packagePath }); @@ -99,34 +113,34 @@ packages = babel(packages, babelOptions); // Bundle formatter for smaller payload if (env === 'production') { - globalBuild = es6(libTree(packages), { + globalBuild = es6(packages, { inputFiles: ['ember-data'], output: '/ember-data.js', resolvers: [PackageResolver], formatter: 'bundle' }); - - var tests = testTree(packages, amdBuild(packages)); - globalBuild = merge([globalBuild, tests]); } else { // Use AMD for faster rebuilds in dev - var bootFile = fileCreator('/boot.js', 'require("ember-data");'); - - var compiled = amdBuild(packages); - var libFiles = libTree(compiled); - - var emberData = merge([bootFile, libFiles]); + globalBuild = amdBuild(packages); +} - var emberData = concat(emberData, { - inputFiles: ['ember-data/**/*.js', 'boot.js'], - outputFile: '/ember-data.js', - wrapInEval: false, - wrapInFunction: false - }); +var testFiles = merge([ + testTree('ember-data'), + testTree('activemodel-adapter') +]); - globalBuild = merge([emberData, testTree(packages, compiled)]); +if (env === 'production'){ + testFiles = es3SafeRecast(testFiles); } +testFiles = concat(testFiles, { + inputFiles: ['**/*.js'], + separator: '\n', + wrapInEval: true, + wrapInFunction: true, + outputFile: '/ember-data-tests.js' +}); + var testRunner = pickFiles('tests', { srcDir: '/', files: [ '**/*' ], @@ -166,13 +180,14 @@ function removeSourceMappingURL(tree) { configurationFiles = versionStamp(configurationFiles); -var jscsTree = jscs('packages'); +var jscsFiles = jscsTree("packages"); var trees = [ - jscsTree, + testFiles, testRunner, bower, - configurationFiles + configurationFiles, + jscsFiles ]; if (env === 'production') { diff --git a/lib/amd-build.js b/lib/amd-build.js index f9cc7a467ab..c8a06d50760 100644 --- a/lib/amd-build.js +++ b/lib/amd-build.js @@ -8,8 +8,7 @@ var fileCreator = require('broccoli-file-creator'); var merge = require('broccoli-merge-trees'); var replace = require('broccoli-replace'); -function amdES6Package(packages, root, outfile) { - +function amdES6Package(packages) { var es6Build = es6(packages, { inputFiles: ['ember-data'], output: '/ember-data/', @@ -19,8 +18,27 @@ function amdES6Package(packages, root, outfile) { sourceRoot: '/ember-data/' }); - return replace(es6Build, { - files: ['**/*.js'], + var loaderJS = pickFiles('bower_components/loader.js', { + srcDir: '/', + files: ['loader.js'], + destDir: '/' + }); + + var bootFile = fileCreator('/boot.js', 'require("ember-data/lib/main");'); + + var amdBuild = merge([es6Build, loaderJS, bootFile]); + + amdBuild = concat(amdBuild, { + inputFiles: ['loader.js', 'ember-data/**/*.js', 'boot.js'], + outputFile: '/ember-data.js', + header: '(function(){', + footer: '})();' + }); + + amdBuild = merge([es6Build, amdBuild]); + + return replace(amdBuild, { + files: ['ember-data.js'], patterns: [ { match: /\/lib/g, diff --git a/lib/lib-tree.js b/lib/lib-tree.js deleted file mode 100644 index c13805b93e5..00000000000 --- a/lib/lib-tree.js +++ /dev/null @@ -1,9 +0,0 @@ -var pickFiles = require('broccoli-static-compiler'); - -module.exports = function libTree(tree) { - return pickFiles(tree, { - files: ['**/*/lib/**/*.js'], - srcDir: '/', - destDir: '/' - }); -} diff --git a/lib/test-tree.js b/lib/test-tree.js deleted file mode 100644 index 0a23ff8ff62..00000000000 --- a/lib/test-tree.js +++ /dev/null @@ -1,40 +0,0 @@ -var concat = require('broccoli-concat'); -var pickFiles = require('broccoli-static-compiler'); -var jshint = require('broccoli-jshint'); -var path = require('path'); -var wrap = require('broccoli-wrap'); -var merge = require('broccoli-merge-trees'); -var amdBuild = require('./amd-build'); - -module.exports = function testTree(sourceTree, compiled) { - var emberDataFiles = pickFiles(sourceTree, { - files: ['**/{ember-data,activemodel-adapter}/**/*.js'], - srcDir: '/', - destDir: '/' - }); - - var hinted = hint(emberDataFiles); - var testFiles = pickFiles(compiled, { - srcDir: '/', - destDir: '/', - files: ['**/*/tests/**/*.js'] - }); - - var allTestFiles = merge([hinted, testFiles]); - - return concat(allTestFiles, { - inputFiles: ['**/*.js'], - outputFile: '/ember-data-tests.js', - wrapInEval: true, - wrapInFunction: false - }); -}; - -function hint(tree){ - var jshinted = jshint(tree, { - jshintrcPath: path.join(__dirname, '..', '.jshintrc') - }); - return wrap(jshinted, { - wrapper: [ "if (!QUnit.urlParams.nojshint) {\n", "\n}"], - }); -} diff --git a/package.json b/package.json index 4ec57a55b28..9823493ef16 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ "devDependencies": { "aws-sdk": "~2.0.0-rc8", "bower": "~1.3", - "broccoli-babel-transpiler": "^5.0.0", "broccoli-compile-modules": "^1.1.0", "broccoli-concat": "0.0.12", "broccoli-defeatureify": "^0.3.0", @@ -39,7 +38,7 @@ "broccoli-es6-transpiler": "^0.1.0", "broccoli-file-creator": "^0.1.0", "broccoli-file-mover": "~0.2.0", - "broccoli-jscs": "0.0.22", + "broccoli-jscs": "0.0.14", "broccoli-jshint": "^0.5.1", "broccoli-merge-trees": "^0.1.4", "broccoli-render-template": "0.0.3", @@ -58,12 +57,13 @@ "es6-module-transpiler-amd-formatter": "^0.2.4", "es6-module-transpiler-package-resolver": "^1.0.1", "git-repo-version": "0.0.2", - "github": "^0.2.4", "jscs": "^1.12.0", "testem": "^0.6.19", "yuidocjs": "~0.3.46" }, "dependencies": { + "broccoli-babel-transpiler": "^5.0.0", + "github": "^0.2.4", "rsvp": "^3.0.18" } } diff --git a/tests/index.html b/tests/index.html index e245e4d6f95..d0ea9e15809 100644 --- a/tests/index.html +++ b/tests/index.html @@ -55,33 +55,10 @@ - + - -
      From a14dd62517b8442b27b9744ae35922be14373f56 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Fri, 8 May 2015 18:27:57 +0200 Subject: [PATCH 0801/2527] Update tests to always pass strings to store methods --- .../integration/adapter/find-all-test.js | 38 +++++---- .../tests/integration/adapter/find-test.js | 46 ++++++----- .../tests/integration/filter-test.js | 4 +- packages/ember-data/tests/unit/model-test.js | 5 +- .../unit/model/lifecycle-callbacks-test.js | 20 +++-- .../ember-data/tests/unit/model/merge-test.js | 4 +- .../tests/unit/record-array-test.js | 2 +- .../tests/unit/store/adapter-interop-test.js | 78 ++++++++++--------- .../tests/unit/store/unload-test.js | 23 +++--- 9 files changed, 127 insertions(+), 93 deletions(-) diff --git a/packages/ember-data/tests/integration/adapter/find-all-test.js b/packages/ember-data/tests/integration/adapter/find-all-test.js index b870cd536e1..ced7ffa3fd8 100644 --- a/packages/ember-data/tests/integration/adapter/find-all-test.js +++ b/packages/ember-data/tests/integration/adapter/find-all-test.js @@ -25,20 +25,21 @@ module("integration/adapter/find_all - Finding All Records of a Type", { test("When all records for a type are requested, the store should call the adapter's `findAll` method.", function() { expect(5); - store = createStore({ adapter: DS.Adapter.extend({ + store = createStore({ + adapter: DS.Adapter.extend({ findAll: function(store, type, since) { // this will get called twice ok(true, "the adapter's findAll method should be invoked"); - return Ember.RSVP.resolve([{ id: 1, name: "Braaaahm Dale" }]); } - }) + }), + person: Person }); var allRecords; run(function() { - store.find(Person).then(function(all) { + store.find('person').then(function(all) { allRecords = all; equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); @@ -46,7 +47,7 @@ test("When all records for a type are requested, the store should call the adapt }); run(function() { - store.find(Person).then(function(all) { + store.find('person').then(function(all) { // Only one record array per type should ever be created (identity map) strictEqual(allRecords, all, "the same record array is returned every time all records of a type are requested"); }); @@ -69,15 +70,16 @@ test("When all records for a type are requested, a rejection should reject the p return Ember.RSVP.resolve([{ id: 1, name: "Braaaahm Dale" }]); } } - }) + }), + person: Person }); var allRecords; run(function() { - store.find(Person).then(null, function() { + store.find('person').then(null, function() { ok(true, "The rejection should get here"); - return store.find(Person); + return store.find('person'); }).then(function(all) { allRecords = all; equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); @@ -88,16 +90,19 @@ test("When all records for a type are requested, a rejection should reject the p test("When all records for a type are requested, records that are already loaded should be returned immediately.", function() { expect(3); - store = createStore({ adapter: DS.Adapter.extend() }); + store = createStore({ + adapter: DS.Adapter.extend(), + person: Person + }); run(function() { // Load a record from the server - store.push(Person, { id: 1, name: "Jeremy Ashkenas" }); + store.push('person', { id: 1, name: "Jeremy Ashkenas" }); // Create a new, unsaved record in the store - store.createRecord(Person, { name: "Alex MacCaw" }); + store.createRecord('person', { name: "Alex MacCaw" }); }); - allRecords = store.all(Person); + allRecords = store.all('person'); equal(get(allRecords, 'length'), 2, "the record array's length is 2"); equal(allRecords.objectAt(0).get('name'), "Jeremy Ashkenas", "the first item in the record array is Jeremy Ashkenas"); @@ -107,14 +112,17 @@ test("When all records for a type are requested, records that are already loaded test("When all records for a type are requested, records that are created on the client should be added to the record array.", function() { expect(3); - store = createStore({ adapter: DS.Adapter.extend() }); + store = createStore({ + adapter: DS.Adapter.extend(), + person: Person + }); - allRecords = store.all(Person); + allRecords = store.all('person'); equal(get(allRecords, 'length'), 0, "precond - the record array's length is zero before any records are loaded"); run(function() { - store.createRecord(Person, { name: "Carsten Nielsen" }); + store.createRecord('person', { name: "Carsten Nielsen" }); }); equal(get(allRecords, 'length'), 1, "the record array's length is 1"); diff --git a/packages/ember-data/tests/integration/adapter/find-test.js b/packages/ember-data/tests/integration/adapter/find-test.js index 8d76e27f496..8e9975de42f 100644 --- a/packages/ember-data/tests/integration/adapter/find-test.js +++ b/packages/ember-data/tests/integration/adapter/find-test.js @@ -25,14 +25,16 @@ test("It raises an assertion when no type is passed", function() { }); test("It raises an assertion when `undefined` is passed as id (#1705)", function() { - store = createStore(); + store = createStore({ + person: Person + }); expectAssertion(function() { - store.find(Person, undefined); + store.find('person', undefined); }, "You may not pass `undefined` as id to the store's find method"); expectAssertion(function() { - store.find(Person, null); + store.find('person', null); }, "You may not pass `null` as id to the store's find method"); }); @@ -41,7 +43,8 @@ test("When a single record is requested, the adapter's find method should be cal var count = 0; - store = createStore({ adapter: DS.Adapter.extend({ + store = createStore({ + adapter: DS.Adapter.extend({ find: function(store, type, id, snapshot) { equal(type, Person, "the find method is called with the correct type"); equal(count, 0, "the find method is only called once"); @@ -49,27 +52,30 @@ test("When a single record is requested, the adapter's find method should be cal count++; return { id: 1, name: "Braaaahm Dale" }; } - }) + }), + person: Person }); run(function() { - store.find(Person, 1); - store.find(Person, 1); + store.find('person', 1); + store.find('person', 1); }); }); test("When a single record is requested multiple times, all .find() calls are resolved after the promise is resolved", function() { var deferred = Ember.RSVP.defer(); - store = createStore({ adapter: DS.Adapter.extend({ + store = createStore({ + adapter: DS.Adapter.extend({ find: function(store, type, id, snapshot) { return deferred.promise; } - }) + }), + person: Person }); run(function() { - store.find(Person, 1).then(async(function(person) { + store.find('person', 1).then(async(function(person) { equal(person.get('id'), "1"); equal(person.get('name'), "Braaaahm Dale"); @@ -85,7 +91,7 @@ test("When a single record is requested multiple times, all .find() calls are re }); run(function() { - store.find(Person, 1).then(async(function(post) { + store.find('person', 1).then(async(function(post) { equal(post.get('id'), "1"); equal(post.get('name'), "Braaaahm Dale"); @@ -107,15 +113,17 @@ test("When a single record is requested multiple times, all .find() calls are re }); test("When a single record is requested, and the promise is rejected, .find() is rejected.", function() { - store = createStore({ adapter: DS.Adapter.extend({ + store = createStore({ + adapter: DS.Adapter.extend({ find: function(store, type, id, snapshot) { return Ember.RSVP.reject(); } - }) + }), + person: Person }); run(function() { - store.find(Person, 1).then(null, async(function(reason) { + store.find('person', 1).then(null, async(function(reason) { ok(true, "The rejection handler was called"); })); }); @@ -124,18 +132,20 @@ test("When a single record is requested, and the promise is rejected, .find() is test("When a single record is requested, and the promise is rejected, the record should be unloaded.", function() { expect(2); - store = createStore({ adapter: DS.Adapter.extend({ + store = createStore({ + adapter: DS.Adapter.extend({ find: function(store, type, id, snapshot) { return Ember.RSVP.reject(); } - }) + }), + person: Person }); run(function() { - store.find(Person, 1).then(null, async(function(reason) { + store.find('person', 1).then(null, async(function(reason) { ok(true, "The rejection handler was called"); })); }); - ok(!store.hasRecordForId(Person, 1), "The record has been unloaded"); + ok(!store.hasRecordForId('person', 1), "The record has been unloaded"); }); diff --git a/packages/ember-data/tests/integration/filter-test.js b/packages/ember-data/tests/integration/filter-test.js index 8196c4ff526..6652842525a 100644 --- a/packages/ember-data/tests/integration/filter-test.js +++ b/packages/ember-data/tests/integration/filter-test.js @@ -378,7 +378,7 @@ test("filter with query persists query on the resulting filteredRecordArray", fu var filter; run(function() { - filter = store.filter(Person, { foo: 1 }, function(person) { + filter = store.filter('person', { foo: 1 }, function(person) { return true; }); }); @@ -400,7 +400,7 @@ test("it is possible to filter by state flags", function() { } })); - filter = store.filter(Person, function(person) { + filter = store.filter('person', function(person) { return person.get('isLoaded'); }); }); diff --git a/packages/ember-data/tests/unit/model-test.js b/packages/ember-data/tests/unit/model-test.js index d6b76fa0ccf..38818481bd2 100644 --- a/packages/ember-data/tests/unit/model-test.js +++ b/packages/ember-data/tests/unit/model-test.js @@ -682,11 +682,12 @@ test("ensure model exits loading state, materializes data and fulfills promise o find: function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "John" }); } - }) + }), + person: Person }); run(function() { - store.find(Person, 1).then(function(person) { + store.find('person', 1).then(function(person) { equal(get(person, 'currentState.stateName'), 'root.loaded.saved', 'model is in loaded state'); equal(get(person, 'isLoaded'), true, 'model is loaded'); }); diff --git a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js index 219f5998716..4855eb1f245 100644 --- a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js +++ b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js @@ -20,11 +20,12 @@ test("a record receives a didLoad callback when it has finished loading", functi }); var store = createStore({ - adapter: adapter + adapter: adapter, + person: Person }); run(function() { - store.find(Person, 1).then(function(person) { + store.find('person', 1).then(function(person) { equal(person.get('id'), "1", "The person's ID is available"); equal(person.get('name'), "Foo", "The person's properties are available"); }); @@ -60,12 +61,13 @@ test("a record receives a didUpdate callback when it has finished updating", fun }); var store = createStore({ - adapter: adapter + adapter: adapter, + person: Person }); var asyncPerson; run(function() { - asyncPerson = store.find(Person, 1); + asyncPerson = store.find('person', 1); }); equal(callCount, 0, "precond - didUpdate callback was not called yet"); @@ -151,12 +153,13 @@ test("a record receives a didDelete callback when it has finished deleting", fun }); var store = createStore({ - adapter: adapter + adapter: adapter, + person: Person }); var asyncPerson; run(function() { - asyncPerson = store.find(Person, 1); + asyncPerson = store.find('person', 1); }); equal(callCount, 0, "precond - didDelete callback was not called yet"); @@ -237,12 +240,13 @@ test("a record receives a becameInvalid callback when it became invalid", functi }); var store = createStore({ - adapter: adapter + adapter: adapter, + person: Person }); var asyncPerson; run(function() { - asyncPerson = store.find(Person, 1); + asyncPerson = store.find('person', 1); }); equal(callCount, 0, "precond - becameInvalid callback was not called yet"); diff --git a/packages/ember-data/tests/unit/model/merge-test.js b/packages/ember-data/tests/unit/model/merge-test.js index bd84896158b..17361afb106 100644 --- a/packages/ember-data/tests/unit/model/merge-test.js +++ b/packages/ember-data/tests/unit/model/merge-test.js @@ -134,11 +134,11 @@ test("A dirty record can be reloaded", function() { } }); - var store = createStore({ adapter: adapter }); + var store = createStore({ adapter: adapter, person: Person }); var person; run(function() { - person = store.push(Person, { id: 1, name: "Tom Dale" }); + person = store.push('person', { id: 1, name: "Tom Dale" }); person.set('name', "Tomasz Dale"); }); diff --git a/packages/ember-data/tests/unit/record-array-test.js b/packages/ember-data/tests/unit/record-array-test.js index 8f59201e64d..69f4ac6f1b7 100644 --- a/packages/ember-data/tests/unit/record-array-test.js +++ b/packages/ember-data/tests/unit/record-array-test.js @@ -256,7 +256,7 @@ test("a record array should return a promise when updating", function() { return Ember.RSVP.resolve(array); }; - recordArray = store.all(Person); + recordArray = store.all('person'); run(function() { promise = recordArray.update(); }); diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index 7b0e56e86ee..6e26dc22fb4 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -54,11 +54,12 @@ test("Calling Store#find invokes its adapter#find", function() { } }); - var currentStore = createStore({ adapter: adapter }); var currentType = DS.Model.extend(); + var currentStore = createStore({ adapter: adapter, test: currentType }); + run(function() { - currentStore.find(currentType, 1); + currentStore.find('test', 1); }); }); @@ -78,13 +79,13 @@ test("Calling Store#findById multiple times coalesces the calls into a adapter#f coalesceFindRequests: true }); - var currentStore = createStore({ adapter: adapter }); var currentType = DS.Model.extend(); - currentType.modelName = "test"; + var currentStore = createStore({ adapter: adapter, test: currentType }); + stop(); run(function() { - currentStore.find(currentType, 1); - currentStore.find(currentType, 2); + currentStore.find('test', 1); + currentStore.find('test', 2); }); }); @@ -97,13 +98,13 @@ test("Returning a promise from `find` asynchronously loads data", function() { } }); - var currentStore = createStore({ adapter: adapter }); var currentType = DS.Model.extend({ name: DS.attr('string') }); + var currentStore = createStore({ adapter: adapter, test: currentType }); run(function() { - currentStore.find(currentType, 1).then(async(function(object) { + currentStore.find('test', 1).then(async(function(object) { strictEqual(get(object, 'name'), "Scumbag Dale", "the data was pushed"); })); }); @@ -119,18 +120,18 @@ test("IDs provided as numbers are coerced to strings", function() { } }); - var currentStore = createStore({ adapter: adapter }); var currentType = DS.Model.extend({ name: DS.attr('string') }); + var currentStore = createStore({ adapter: adapter, test: currentType }); run(function() { - currentStore.find(currentType, 1).then(async(function(object) { + currentStore.find('test', 1).then(async(function(object) { equal(typeof object.get('id'), 'string', "id was coerced to a string"); run(function() { - currentStore.push(currentType, { id: 2, name: "Scumbag Sam Saffron" }); + currentStore.push('test', { id: 2, name: "Scumbag Sam Saffron" }); }); - return currentStore.find(currentType, 2); + return currentStore.find('test', 2); })).then(async(function(object) { ok(object, "object was found"); equal(typeof object.get('id'), 'string', "id is a string despite being supplied and searched for as a number"); @@ -363,16 +364,17 @@ test("initial values of attributes can be passed in as the third argument to fin } }); - var store = createStore({ - adapter: adapter - }); - var Person = DS.Model.extend({ name: DS.attr('string') }); + var store = createStore({ + adapter: adapter, + test: Person + }); + run(function() { - store.find(Person, 1, { name: 'Test' }); + store.find('test', 1, { name: 'Test' }); }); }); @@ -583,17 +585,19 @@ test("store.scheduleFetchMany should not resolve until all the records are resol }); var store = createStore({ - adapter: adapter + adapter: adapter, + test: Person, + phone: Phone }); run(function() { - store.createRecord(Person); + store.createRecord('test'); }); var records = Ember.A([ - store.recordForId(Person, 10), - store.recordForId(Phone, 20), - store.recordForId(Phone, 21) + store.recordForId('test', 10), + store.recordForId('phone', 20), + store.recordForId('phone', 21) ]); run(function() { @@ -636,13 +640,14 @@ test("the store calls adapter.findMany according to groupings returned by adapte }); var store = createStore({ - adapter: adapter + adapter: adapter, + test: Person }); var records = Ember.A([ - store.recordForId(Person, 10), - store.recordForId(Person, 20), - store.recordForId(Person, 21) + store.recordForId('test', 10), + store.recordForId('test', 20), + store.recordForId('test', 21) ]); run(function() { @@ -684,12 +689,13 @@ test("the promise returned by `scheduleFetch`, when it resolves, does not depend }); var store = createStore({ - adapter: adapter + adapter: adapter, + test: Person }); run(function () { - var davidPromise = store.find(Person, 'david'); - var igorPromise = store.find(Person, 'igor'); + var davidPromise = store.find('test', 'david'); + var igorPromise = store.find('test', 'igor'); igorPromise.then(async(function () { equal(davidResolved, false, "Igor did not need to wait for David"); @@ -732,12 +738,13 @@ test("the promise returned by `scheduleFetch`, when it rejects, does not depend }); var store = createStore({ - adapter: adapter + adapter: adapter, + test: Person }); run(function () { - var davidPromise = store.find(Person, 'david'); - var igorPromise = store.find(Person, 'igor'); + var davidPromise = store.find('test', 'david'); + var igorPromise = store.find('test', 'igor'); igorPromise.then(null, async(function () { equal(davidResolved, false, "Igor did not need to wait for David"); @@ -769,13 +776,14 @@ test("store.fetchRecord reject records that were not found, even when those requ }); var store = createStore({ - adapter: adapter + adapter: adapter, + test: Person }); warns(function() { run(function () { - var davidPromise = store.find(Person, 'david'); - var igorPromise = store.find(Person, 'igor'); + var davidPromise = store.find('test', 'david'); + var igorPromise = store.find('test', 'igor'); davidPromise.then(async(function () { ok(true, "David resolved"); diff --git a/packages/ember-data/tests/unit/store/unload-test.js b/packages/ember-data/tests/unit/store/unload-test.js index dac00f1154d..5816b16943c 100644 --- a/packages/ember-data/tests/unit/store/unload-test.js +++ b/packages/ember-data/tests/unit/store/unload-test.js @@ -4,18 +4,21 @@ var store, tryToFind, Record; module("unit/store/unload - Store unloading records", { setup: function() { - store = createStore({ adapter: DS.Adapter.extend({ - find: function(store, type, id, snapshot) { - tryToFind = true; - return Ember.RSVP.resolve({ id: id, wasFetched: true }); - } - }) - }); Record = DS.Model.extend({ title: DS.attr('string'), wasFetched: DS.attr('boolean') }); + + store = createStore({ + adapter: DS.Adapter.extend({ + find: function(store, type, id, snapshot) { + tryToFind = true; + return Ember.RSVP.resolve({ id: id, wasFetched: true }); + } + }), + record: Record + }); }, teardown: function() { @@ -54,8 +57,8 @@ test("unload a record", function() { expect(5); run(function() { - store.push(Record, { id: 1, title: 'toto' }); - store.find(Record, 1).then(function(record) { + store.push('record', { id: 1, title: 'toto' }); + store.find('record', 1).then(function(record) { equal(get(record, 'id'), 1, "found record with id 1"); equal(get(record, 'isDirty'), false, "record is not dirty"); @@ -67,7 +70,7 @@ test("unload a record", function() { equal(get(record, 'isDeleted'), true, "record is deleted"); tryToFind = false; - return store.find(Record, 1).then(function() { + return store.find('record', 1).then(function() { equal(tryToFind, true, "not found record with id 1"); }); }); From 6bc4f0e9969e6e24a9c20d3ff6cee4692c04045a Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Thu, 28 May 2015 21:30:29 +0200 Subject: [PATCH 0802/2527] Fix docparser warnings, @returns => @return --- .../activemodel-adapter/lib/system/active-model-serializer.js | 2 +- packages/ember-data/lib/serializers/rest-serializer.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/active-model-serializer.js b/packages/activemodel-adapter/lib/system/active-model-serializer.js index 9ba54166f00..adbacd106a4 100644 --- a/packages/activemodel-adapter/lib/system/active-model-serializer.js +++ b/packages/activemodel-adapter/lib/system/active-model-serializer.js @@ -142,7 +142,7 @@ var ActiveModelSerializer = RESTSerializer.extend({ @method payloadKeyFromModelName @param {String} modelName - @returns {String} + @return {String} */ payloadKeyFromModelName: function(modelName) { return underscore(decamelize(modelName)); diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index 6acdfecd9e4..3431246c4b4 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -784,7 +784,7 @@ var RESTSerializer = JSONSerializer.extend({ @method payloadKeyFromModelName @param {String} modelName - @returns {String} + @return {String} */ payloadKeyFromModelName: function(modelName) { return camelize(modelName); @@ -795,7 +795,7 @@ var RESTSerializer = JSONSerializer.extend({ @method typeForRoot @param {String} modelName - @returns {String} + @return {String} @deprecated */ typeForRoot: function(modelName) { From e5e4c186d3b1449ef732d8dc9b096f39626c3cde Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 29 May 2015 11:21:58 -0500 Subject: [PATCH 0803/2527] Revert "Revert "transform tests through the module compiler"" This reverts commit 911519dee51916f55fdea49677f7486f953e9953. --- Brocfile.js | 75 +++++++++++++++++++----------------------------- lib/amd-build.js | 26 +++-------------- lib/lib-tree.js | 9 ++++++ lib/test-tree.js | 40 ++++++++++++++++++++++++++ package.json | 6 ++-- tests/index.html | 25 +++++++++++++++- 6 files changed, 110 insertions(+), 71 deletions(-) create mode 100644 lib/lib-tree.js create mode 100644 lib/test-tree.js diff --git a/Brocfile.js b/Brocfile.js index a69bbe62f8d..c095e88fda6 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -7,11 +7,11 @@ var uglify = require('broccoli-uglify-js'); var es3SafeRecast = require('broccoli-es3-safe-recast'); var env = process.env.EMBER_ENV; var amdBuild = require('./lib/amd-build'); +var testTree = require('./lib/test-tree'); +var libTree = require('./lib/lib-tree'); var pickFiles = require('broccoli-static-compiler'); var merge = require('broccoli-merge-trees'); var moveFile = require('broccoli-file-mover'); -var wrap = require('broccoli-wrap'); -var jshint = require('broccoli-jshint'); var defeatureify = require('broccoli-defeatureify'); var version = require('git-repo-version')(10); var yuidoc = require('broccoli-yuidoc'); @@ -19,9 +19,10 @@ var replace = require('broccoli-replace'); var stew = require('broccoli-stew'); var path = require('path'); var fs = require('fs'); -var jscsTree = require('broccoli-jscs'); var babel = require('broccoli-babel-transpiler'); var babelOptions = require('./config/babel'); +var fileCreator = require('broccoli-file-creator'); +var jscs = require('broccoli-jscs'); function minify(tree, name){ var config = require('./config/ember-defeatureify'); @@ -33,6 +34,11 @@ function minify(tree, name){ srcFile: name + '.js', destFile: '/' + name + '.prod.js' }); + tree = pickFiles(tree, { + srcDir: '/', + destDir: '/', + files: [ name + '.prod.js' ] + }); tree = removeSourceMappingURL(tree); var uglified = moveFile(uglify(tree, {mangle: true}),{ srcFile: name + '.prod.js', @@ -41,26 +47,6 @@ function minify(tree, name){ return merge([uglified, tree], {overwrite: true}); } -function testTree(packageName){ - var test = pickFiles('packages/' + packageName + '/tests', { - srcDir: '/', - files: [ '**/*.js' ], - destDir: '/' + packageName - }); - var jshinted = jshint('packages/' + packageName + '/', { - jshintrcPath: path.join(__dirname, '.jshintrc') - }); - jshinted = wrap(jshinted, { - wrapper: [ "if (!QUnit.urlParams.nojshint) {\n", "\n}"], - }); - jshinted = pickFiles(jshinted, { - files: ['{lib,tests}/**/*.js'], - srcDir: '/', - destDir: '/' + packageName + '-jshint' - }); - return merge([jshinted, test]); -} - var yuidocTree = yuidoc('packages', { srcDir: '/', destDir: 'docs', @@ -86,7 +72,7 @@ var yuidocTree = yuidoc('packages', { function package(packagePath, vendorPath) { vendorPath = vendorPath || 'packages/'; return pickFiles(vendorPath + packagePath, { - files: [ 'lib/**/*.js' ], + files: [ '**/*.js' ], srcDir: '/', destDir: '/' + packagePath }); @@ -113,33 +99,33 @@ packages = babel(packages, babelOptions); // Bundle formatter for smaller payload if (env === 'production') { - globalBuild = es6(packages, { + globalBuild = es6(libTree(packages), { inputFiles: ['ember-data'], output: '/ember-data.js', resolvers: [PackageResolver], formatter: 'bundle' }); + + var tests = testTree(packages, amdBuild(packages)); + globalBuild = merge([globalBuild, tests]); } else { // Use AMD for faster rebuilds in dev - globalBuild = amdBuild(packages); -} + var bootFile = fileCreator('/boot.js', 'require("ember-data");'); -var testFiles = merge([ - testTree('ember-data'), - testTree('activemodel-adapter') -]); + var compiled = amdBuild(packages); + var libFiles = libTree(compiled); -if (env === 'production'){ - testFiles = es3SafeRecast(testFiles); -} + var emberData = merge([bootFile, libFiles]); -testFiles = concat(testFiles, { - inputFiles: ['**/*.js'], - separator: '\n', - wrapInEval: true, - wrapInFunction: true, - outputFile: '/ember-data-tests.js' -}); + var emberData = concat(emberData, { + inputFiles: ['ember-data/**/*.js', 'boot.js'], + outputFile: '/ember-data.js', + wrapInEval: false, + wrapInFunction: false + }); + + globalBuild = merge([emberData, testTree(packages, compiled)]); +} var testRunner = pickFiles('tests', { srcDir: '/', @@ -180,14 +166,13 @@ function removeSourceMappingURL(tree) { configurationFiles = versionStamp(configurationFiles); -var jscsFiles = jscsTree("packages"); +var jscsTree = jscs('packages'); var trees = [ - testFiles, + jscsTree, testRunner, bower, - configurationFiles, - jscsFiles + configurationFiles ]; if (env === 'production') { diff --git a/lib/amd-build.js b/lib/amd-build.js index c8a06d50760..f9cc7a467ab 100644 --- a/lib/amd-build.js +++ b/lib/amd-build.js @@ -8,7 +8,8 @@ var fileCreator = require('broccoli-file-creator'); var merge = require('broccoli-merge-trees'); var replace = require('broccoli-replace'); -function amdES6Package(packages) { +function amdES6Package(packages, root, outfile) { + var es6Build = es6(packages, { inputFiles: ['ember-data'], output: '/ember-data/', @@ -18,27 +19,8 @@ function amdES6Package(packages) { sourceRoot: '/ember-data/' }); - var loaderJS = pickFiles('bower_components/loader.js', { - srcDir: '/', - files: ['loader.js'], - destDir: '/' - }); - - var bootFile = fileCreator('/boot.js', 'require("ember-data/lib/main");'); - - var amdBuild = merge([es6Build, loaderJS, bootFile]); - - amdBuild = concat(amdBuild, { - inputFiles: ['loader.js', 'ember-data/**/*.js', 'boot.js'], - outputFile: '/ember-data.js', - header: '(function(){', - footer: '})();' - }); - - amdBuild = merge([es6Build, amdBuild]); - - return replace(amdBuild, { - files: ['ember-data.js'], + return replace(es6Build, { + files: ['**/*.js'], patterns: [ { match: /\/lib/g, diff --git a/lib/lib-tree.js b/lib/lib-tree.js new file mode 100644 index 00000000000..c13805b93e5 --- /dev/null +++ b/lib/lib-tree.js @@ -0,0 +1,9 @@ +var pickFiles = require('broccoli-static-compiler'); + +module.exports = function libTree(tree) { + return pickFiles(tree, { + files: ['**/*/lib/**/*.js'], + srcDir: '/', + destDir: '/' + }); +} diff --git a/lib/test-tree.js b/lib/test-tree.js new file mode 100644 index 00000000000..0a23ff8ff62 --- /dev/null +++ b/lib/test-tree.js @@ -0,0 +1,40 @@ +var concat = require('broccoli-concat'); +var pickFiles = require('broccoli-static-compiler'); +var jshint = require('broccoli-jshint'); +var path = require('path'); +var wrap = require('broccoli-wrap'); +var merge = require('broccoli-merge-trees'); +var amdBuild = require('./amd-build'); + +module.exports = function testTree(sourceTree, compiled) { + var emberDataFiles = pickFiles(sourceTree, { + files: ['**/{ember-data,activemodel-adapter}/**/*.js'], + srcDir: '/', + destDir: '/' + }); + + var hinted = hint(emberDataFiles); + var testFiles = pickFiles(compiled, { + srcDir: '/', + destDir: '/', + files: ['**/*/tests/**/*.js'] + }); + + var allTestFiles = merge([hinted, testFiles]); + + return concat(allTestFiles, { + inputFiles: ['**/*.js'], + outputFile: '/ember-data-tests.js', + wrapInEval: true, + wrapInFunction: false + }); +}; + +function hint(tree){ + var jshinted = jshint(tree, { + jshintrcPath: path.join(__dirname, '..', '.jshintrc') + }); + return wrap(jshinted, { + wrapper: [ "if (!QUnit.urlParams.nojshint) {\n", "\n}"], + }); +} diff --git a/package.json b/package.json index 9823493ef16..4ec57a55b28 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "devDependencies": { "aws-sdk": "~2.0.0-rc8", "bower": "~1.3", + "broccoli-babel-transpiler": "^5.0.0", "broccoli-compile-modules": "^1.1.0", "broccoli-concat": "0.0.12", "broccoli-defeatureify": "^0.3.0", @@ -38,7 +39,7 @@ "broccoli-es6-transpiler": "^0.1.0", "broccoli-file-creator": "^0.1.0", "broccoli-file-mover": "~0.2.0", - "broccoli-jscs": "0.0.14", + "broccoli-jscs": "0.0.22", "broccoli-jshint": "^0.5.1", "broccoli-merge-trees": "^0.1.4", "broccoli-render-template": "0.0.3", @@ -57,13 +58,12 @@ "es6-module-transpiler-amd-formatter": "^0.2.4", "es6-module-transpiler-package-resolver": "^1.0.1", "git-repo-version": "0.0.2", + "github": "^0.2.4", "jscs": "^1.12.0", "testem": "^0.6.19", "yuidocjs": "~0.3.46" }, "dependencies": { - "broccoli-babel-transpiler": "^5.0.0", - "github": "^0.2.4", "rsvp": "^3.0.18" } } diff --git a/tests/index.html b/tests/index.html index d0ea9e15809..e245e4d6f95 100644 --- a/tests/index.html +++ b/tests/index.html @@ -55,10 +55,33 @@ - + + +
      From b0f616577c3a6f74c4995b43f7f360b93a1f10c2 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 29 May 2015 11:53:17 -0500 Subject: [PATCH 0804/2527] defeatureify updates This restores ES6 build output for tests. We let the assertion for Ember.VERSION run in production builds due to a weird bug with defeautreify where it removes one too many characters in the case of Ember.runInDebug. --- Brocfile.js | 76 +++++++++++++++++++-------------- config/ember-defeatureify.js | 11 +---- package.json | 3 +- packages/ember-data/lib/main.js | 13 +++--- 4 files changed, 55 insertions(+), 48 deletions(-) diff --git a/Brocfile.js b/Brocfile.js index c095e88fda6..416ba4abb0b 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -7,11 +7,11 @@ var uglify = require('broccoli-uglify-js'); var es3SafeRecast = require('broccoli-es3-safe-recast'); var env = process.env.EMBER_ENV; var amdBuild = require('./lib/amd-build'); -var testTree = require('./lib/test-tree'); -var libTree = require('./lib/lib-tree'); var pickFiles = require('broccoli-static-compiler'); var merge = require('broccoli-merge-trees'); var moveFile = require('broccoli-file-mover'); +var wrap = require('broccoli-wrap'); +var jshint = require('broccoli-jshint'); var defeatureify = require('broccoli-defeatureify'); var version = require('git-repo-version')(10); var yuidoc = require('broccoli-yuidoc'); @@ -19,26 +19,21 @@ var replace = require('broccoli-replace'); var stew = require('broccoli-stew'); var path = require('path'); var fs = require('fs'); +var jscsTree = require('broccoli-jscs'); var babel = require('broccoli-babel-transpiler'); var babelOptions = require('./config/babel'); -var fileCreator = require('broccoli-file-creator'); -var jscs = require('broccoli-jscs'); +var sourcemapConcat = require('broccoli-sourcemap-concat'); function minify(tree, name){ var config = require('./config/ember-defeatureify'); tree = defeatureify(tree, { debugStatements: config.options.debugStatements, - enableStripDebug: config.stripDebug + enableStripDebug: config.enableStripDebug }); tree = moveFile(tree, { srcFile: name + '.js', destFile: '/' + name + '.prod.js' }); - tree = pickFiles(tree, { - srcDir: '/', - destDir: '/', - files: [ name + '.prod.js' ] - }); tree = removeSourceMappingURL(tree); var uglified = moveFile(uglify(tree, {mangle: true}),{ srcFile: name + '.prod.js', @@ -47,6 +42,27 @@ function minify(tree, name){ return merge([uglified, tree], {overwrite: true}); } +function testTree(packageName){ + var test = pickFiles('packages/' + packageName + '/tests', { + srcDir: '/', + files: [ '**/*.js' ], + destDir: '/' + packageName + }); + test = babel(test, babelOptions); + var jshinted = jshint('packages/' + packageName + '/', { + jshintrcPath: path.join(__dirname, '.jshintrc') + }); + jshinted = wrap(jshinted, { + wrapper: [ "if (!QUnit.urlParams.nojshint) {\n", "\n}"], + }); + jshinted = pickFiles(jshinted, { + files: ['{lib,tests}/**/*.js'], + srcDir: '/', + destDir: '/' + packageName + '-jshint' + }); + return merge([jshinted, test]); +} + var yuidocTree = yuidoc('packages', { srcDir: '/', destDir: 'docs', @@ -72,7 +88,7 @@ var yuidocTree = yuidoc('packages', { function package(packagePath, vendorPath) { vendorPath = vendorPath || 'packages/'; return pickFiles(vendorPath + packagePath, { - files: [ '**/*.js' ], + files: [ 'lib/**/*.js' ], srcDir: '/', destDir: '/' + packagePath }); @@ -99,34 +115,31 @@ packages = babel(packages, babelOptions); // Bundle formatter for smaller payload if (env === 'production') { - globalBuild = es6(libTree(packages), { + globalBuild = es6(packages, { inputFiles: ['ember-data'], output: '/ember-data.js', resolvers: [PackageResolver], formatter: 'bundle' }); - - var tests = testTree(packages, amdBuild(packages)); - globalBuild = merge([globalBuild, tests]); } else { // Use AMD for faster rebuilds in dev - var bootFile = fileCreator('/boot.js', 'require("ember-data");'); - - var compiled = amdBuild(packages); - var libFiles = libTree(compiled); - - var emberData = merge([bootFile, libFiles]); + globalBuild = amdBuild(packages); +} - var emberData = concat(emberData, { - inputFiles: ['ember-data/**/*.js', 'boot.js'], - outputFile: '/ember-data.js', - wrapInEval: false, - wrapInFunction: false - }); +var testFiles = merge([ + testTree('ember-data'), + testTree('activemodel-adapter') +]); - globalBuild = merge([emberData, testTree(packages, compiled)]); +if (env === 'production'){ + testFiles = es3SafeRecast(testFiles); } +testFiles = sourcemapConcat(testFiles, { + inputFiles: ['**/*.js'], + outputFile: '/ember-data-tests.js' +}); + var testRunner = pickFiles('tests', { srcDir: '/', files: [ '**/*' ], @@ -166,13 +179,14 @@ function removeSourceMappingURL(tree) { configurationFiles = versionStamp(configurationFiles); -var jscsTree = jscs('packages'); +var jscsFiles = jscsTree("packages"); var trees = [ - jscsTree, + testFiles, testRunner, bower, - configurationFiles + configurationFiles, + jscsFiles ]; if (env === 'production') { diff --git a/config/ember-defeatureify.js b/config/ember-defeatureify.js index 67c344ce9a3..25b3f8baa66 100644 --- a/config/ember-defeatureify.js +++ b/config/ember-defeatureify.js @@ -10,15 +10,8 @@ module.exports = { "Ember.debug", "emberDebug", "Ember.Logger.info", - "Ember.runInDebug", - "runInDebug" + "Ember.runInDebug" ] }, - stripDebug: { - options: { - enableStripDebug: true - }, - src: 'dist/ember-data.js', - dest: 'dist/ember-data.prod.js' - } + enableStripDebug: true }; diff --git a/package.json b/package.json index 4ec57a55b28..4ac7770ab30 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "broccoli-babel-transpiler": "^5.0.0", "broccoli-compile-modules": "^1.1.0", "broccoli-concat": "0.0.12", - "broccoli-defeatureify": "^0.3.0", + "broccoli-defeatureify": "^1.0.0", "broccoli-env": "0.0.1", "broccoli-es3-safe-recast": "0.0.8", "broccoli-es6-module-transpiler": "^0.5.0", @@ -44,6 +44,7 @@ "broccoli-merge-trees": "^0.1.4", "broccoli-render-template": "0.0.3", "broccoli-replace": "~0.2.0", + "broccoli-sourcemap-concat": "^0.4.4", "broccoli-static-compiler": "^0.2.1", "broccoli-stew": "^0.2.1", "broccoli-uglify-js": "^0.1.3", diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index 1f7f54327df..1def75f8607 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -4,16 +4,15 @@ @main ember-data */ +if (Ember.VERSION.match(/^1\.[0-7]\./)) { + throw new Ember.Error("Ember Data requires at least Ember 1.8.0, but you have " + + Ember.VERSION + + ". Please upgrade your version of Ember, then upgrade Ember Data"); +} + // support RSVP 2.x via resolve, but prefer RSVP 3.x's Promise.cast Ember.RSVP.Promise.cast = Ember.RSVP.Promise.cast || Ember.RSVP.resolve; -Ember.runInDebug(function() { - if (Ember.VERSION.match(/^1\.[0-7]\./)) { - throw new Ember.Error("Ember Data requires at least Ember 1.8.0, but you have " + - Ember.VERSION + - ". Please upgrade your version of Ember, then upgrade Ember Data"); - } -}); import DS from "ember-data/core"; import "ember-data/ext/date"; From 2b968e4e9d5b8f1f09b64d73fc91780c71278442 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 29 May 2015 12:27:06 -0500 Subject: [PATCH 0805/2527] include sourcemaps in 'between' broccoli trees --- Brocfile.js | 74 +++++++++++++++++++----------------------------- lib/lib-tree.js | 2 +- lib/test-tree.js | 10 +++---- 3 files changed, 34 insertions(+), 52 deletions(-) diff --git a/Brocfile.js b/Brocfile.js index 416ba4abb0b..92116e9158f 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -2,16 +2,16 @@ var es6 = require('broccoli-es6-module-transpiler'); var PackageResolver = require('es6-module-transpiler-package-resolver'); -var concat = require('broccoli-concat'); +var concat = require('broccoli-sourcemap-concat'); var uglify = require('broccoli-uglify-js'); var es3SafeRecast = require('broccoli-es3-safe-recast'); var env = process.env.EMBER_ENV; var amdBuild = require('./lib/amd-build'); +var testTree = require('./lib/test-tree'); +var libTree = require('./lib/lib-tree'); var pickFiles = require('broccoli-static-compiler'); var merge = require('broccoli-merge-trees'); var moveFile = require('broccoli-file-mover'); -var wrap = require('broccoli-wrap'); -var jshint = require('broccoli-jshint'); var defeatureify = require('broccoli-defeatureify'); var version = require('git-repo-version')(10); var yuidoc = require('broccoli-yuidoc'); @@ -19,10 +19,10 @@ var replace = require('broccoli-replace'); var stew = require('broccoli-stew'); var path = require('path'); var fs = require('fs'); -var jscsTree = require('broccoli-jscs'); var babel = require('broccoli-babel-transpiler'); var babelOptions = require('./config/babel'); -var sourcemapConcat = require('broccoli-sourcemap-concat'); +var fileCreator = require('broccoli-file-creator'); +var jscs = require('broccoli-jscs'); function minify(tree, name){ var config = require('./config/ember-defeatureify'); @@ -34,6 +34,11 @@ function minify(tree, name){ srcFile: name + '.js', destFile: '/' + name + '.prod.js' }); + tree = pickFiles(tree, { + srcDir: '/', + destDir: '/', + files: [ name + '.prod.js' ] + }); tree = removeSourceMappingURL(tree); var uglified = moveFile(uglify(tree, {mangle: true}),{ srcFile: name + '.prod.js', @@ -42,27 +47,6 @@ function minify(tree, name){ return merge([uglified, tree], {overwrite: true}); } -function testTree(packageName){ - var test = pickFiles('packages/' + packageName + '/tests', { - srcDir: '/', - files: [ '**/*.js' ], - destDir: '/' + packageName - }); - test = babel(test, babelOptions); - var jshinted = jshint('packages/' + packageName + '/', { - jshintrcPath: path.join(__dirname, '.jshintrc') - }); - jshinted = wrap(jshinted, { - wrapper: [ "if (!QUnit.urlParams.nojshint) {\n", "\n}"], - }); - jshinted = pickFiles(jshinted, { - files: ['{lib,tests}/**/*.js'], - srcDir: '/', - destDir: '/' + packageName + '-jshint' - }); - return merge([jshinted, test]); -} - var yuidocTree = yuidoc('packages', { srcDir: '/', destDir: 'docs', @@ -88,7 +72,7 @@ var yuidocTree = yuidoc('packages', { function package(packagePath, vendorPath) { vendorPath = vendorPath || 'packages/'; return pickFiles(vendorPath + packagePath, { - files: [ 'lib/**/*.js' ], + files: [ '**/*.js' ], srcDir: '/', destDir: '/' + packagePath }); @@ -115,30 +99,31 @@ packages = babel(packages, babelOptions); // Bundle formatter for smaller payload if (env === 'production') { - globalBuild = es6(packages, { + globalBuild = es6(libTree(packages), { inputFiles: ['ember-data'], output: '/ember-data.js', resolvers: [PackageResolver], formatter: 'bundle' }); + + var tests = testTree(packages, amdBuild(packages)); + globalBuild = merge([globalBuild, tests]); } else { // Use AMD for faster rebuilds in dev - globalBuild = amdBuild(packages); -} + var bootFile = fileCreator('/boot.js', 'require("ember-data");'); -var testFiles = merge([ - testTree('ember-data'), - testTree('activemodel-adapter') -]); + var compiled = amdBuild(packages); + var libFiles = libTree(compiled); -if (env === 'production'){ - testFiles = es3SafeRecast(testFiles); -} + var emberData = merge([bootFile, libFiles]); -testFiles = sourcemapConcat(testFiles, { - inputFiles: ['**/*.js'], - outputFile: '/ember-data-tests.js' -}); + var emberData = concat(emberData, { + inputFiles: ['ember-data/**/*.js', 'boot.js'], + outputFile: '/ember-data.js' + }); + + globalBuild = merge([emberData, testTree(packages, compiled)]); +} var testRunner = pickFiles('tests', { srcDir: '/', @@ -179,14 +164,13 @@ function removeSourceMappingURL(tree) { configurationFiles = versionStamp(configurationFiles); -var jscsFiles = jscsTree("packages"); +var jscsTree = jscs('packages'); var trees = [ - testFiles, + jscsTree, testRunner, bower, - configurationFiles, - jscsFiles + configurationFiles ]; if (env === 'production') { diff --git a/lib/lib-tree.js b/lib/lib-tree.js index c13805b93e5..3122aa868af 100644 --- a/lib/lib-tree.js +++ b/lib/lib-tree.js @@ -2,7 +2,7 @@ var pickFiles = require('broccoli-static-compiler'); module.exports = function libTree(tree) { return pickFiles(tree, { - files: ['**/*/lib/**/*.js'], + files: ['**/*/lib/**/*.{js,map}'], srcDir: '/', destDir: '/' }); diff --git a/lib/test-tree.js b/lib/test-tree.js index 0a23ff8ff62..e48710e848a 100644 --- a/lib/test-tree.js +++ b/lib/test-tree.js @@ -1,4 +1,4 @@ -var concat = require('broccoli-concat'); +var concat = require('broccoli-sourcemap-concat'); var pickFiles = require('broccoli-static-compiler'); var jshint = require('broccoli-jshint'); var path = require('path'); @@ -8,7 +8,7 @@ var amdBuild = require('./amd-build'); module.exports = function testTree(sourceTree, compiled) { var emberDataFiles = pickFiles(sourceTree, { - files: ['**/{ember-data,activemodel-adapter}/**/*.js'], + files: ['**/{ember-data,activemodel-adapter}/**/*.{js,map}'], srcDir: '/', destDir: '/' }); @@ -17,16 +17,14 @@ module.exports = function testTree(sourceTree, compiled) { var testFiles = pickFiles(compiled, { srcDir: '/', destDir: '/', - files: ['**/*/tests/**/*.js'] + files: ['**/*/tests/**/*.{js,map}'] }); var allTestFiles = merge([hinted, testFiles]); return concat(allTestFiles, { inputFiles: ['**/*.js'], - outputFile: '/ember-data-tests.js', - wrapInEval: true, - wrapInFunction: false + outputFile: '/ember-data-tests.js' }); }; From 6243347687da16b1700a02a28d7c3f48281e6580 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 16 May 2015 13:18:31 -0500 Subject: [PATCH 0806/2527] remove passing factories to store methods Previously, we allowed users to either pass factories (subclasses of DS.Model), or a string to store methods. For more consistency in the container-based world where things are looked up through strings, support for looking up via passing a factory has been removed. This is part of a refactor that will remove state (like the store) from Ember Data's factories in order to remove Ember.MODEL_FACTORY_INJECTIONS. --- .../lib/system/active-model-serializer.js | 6 +- ...el-serializer-namespaced-modelname-test.js | 29 +-- .../active-model-serializer-test.js | 48 ++-- .../lib/serializers/embedded-records-mixin.js | 10 +- .../lib/serializers/json-serializer.js | 2 +- .../lib/serializers/rest-serializer.js | 25 +- .../lib/system/debug/debug-adapter.js | 6 +- packages/ember-data/lib/system/many-array.js | 2 +- packages/ember-data/lib/system/model/model.js | 4 +- .../adapter-populated-record-array.js | 5 +- .../lib/system/record-arrays/record-array.js | 4 +- .../relationships/state/relationship.js | 6 +- packages/ember-data/lib/system/store.js | 231 ++++++++++-------- .../ember-data/lib/system/store/finders.js | 30 ++- .../adapter/build-url-mixin-test.js | 6 +- .../integration/adapter/find-all-test.js | 66 ++--- .../tests/integration/adapter/find-test.js | 77 +++--- .../integration/adapter/store-adapter-test.js | 2 +- .../tests/integration/debug-adapter-test.js | 9 +- .../tests/integration/filter-test.js | 8 +- .../tests/integration/inverse-test.js | 4 +- .../tests/integration/lifecycle-hooks-test.js | 4 +- .../tests/integration/multiple_stores_test.js | 26 +- .../tests/integration/records/load-test.js | 4 +- .../relationships/belongs-to-test.js | 2 +- .../polymorphic-mixins-belongs-to-test.js | 4 +- .../polymorphic-mixins-has-many-test.js | 4 +- .../embedded-records-mixin-test.js | 196 +++++++-------- .../serializers/json-serializer-test.js | 46 ++-- .../serializers/rest-serializer-test.js | 66 ++--- .../tests/integration/store-test.js | 2 +- .../adapter-populated-record-array-test.js | 12 +- packages/ember-data/tests/unit/debug-test.js | 4 +- packages/ember-data/tests/unit/model-test.js | 171 ++++++++----- .../unit/model/lifecycle-callbacks-test.js | 39 +-- .../ember-data/tests/unit/model/merge-test.js | 39 ++- .../model/relationships/belongs-to-test.js | 4 +- .../unit/model/relationships/has-many-test.js | 12 +- .../tests/unit/record-array-test.js | 76 ++++-- .../tests/unit/store/adapter-interop-test.js | 206 +++++++++------- .../tests/unit/store/create-record-test.js | 9 +- .../unit/store/has_record_for_id_test.js | 8 +- .../tests/unit/store/model-for-test.js | 10 - .../ember-data/tests/unit/store/push-test.js | 2 +- .../tests/unit/store/unload-test.js | 38 +-- 45 files changed, 868 insertions(+), 696 deletions(-) diff --git a/packages/activemodel-adapter/lib/system/active-model-serializer.js b/packages/activemodel-adapter/lib/system/active-model-serializer.js index adbacd106a4..366d28882db 100644 --- a/packages/activemodel-adapter/lib/system/active-model-serializer.js +++ b/packages/activemodel-adapter/lib/system/active-model-serializer.js @@ -117,12 +117,12 @@ var ActiveModelSerializer = RESTSerializer.extend({ relationship keys. @method keyForRelationship - @param {String} relationshipTypeKey + @param {String} relationshipModelName @param {String} kind @return String */ - keyForRelationship: function(relationshipTypeKey, kind) { - var key = decamelize(relationshipTypeKey); + keyForRelationship: function(relationshipModelName, kind) { + var key = decamelize(relationshipModelName); if (kind === "belongsTo") { return key + "_id"; } else if (kind === "hasMany") { diff --git a/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-modelname-test.js b/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-modelname-test.js index 27fa5b5cb5c..958281d5ac3 100644 --- a/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-modelname-test.js +++ b/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-modelname-test.js @@ -6,34 +6,35 @@ module("integration/active_model - AMS-namespaced-model-names", { SuperVillain = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), - evilMinions: DS.hasMany("evilMinion") + evilMinions: DS.hasMany('evil-minion') }); EvilMinion = DS.Model.extend({ - superVillain: DS.belongsTo('superVillain'), + superVillain: DS.belongsTo('super-villain'), name: DS.attr('string') }); YellowMinion = EvilMinion.extend(); DoomsdayDevice = DS.Model.extend({ name: DS.attr('string'), - evilMinion: DS.belongsTo('evilMinion', { polymorphic: true }) + evilMinion: DS.belongsTo('evil-minion', { polymorphic: true }) }); MediocreVillain = DS.Model.extend({ name: DS.attr('string'), - evilMinions: DS.hasMany('evilMinion', { polymorphic: true }) + evilMinions: DS.hasMany('evil-minion', { polymorphic: true }) }); env = setupStore({ superVillain: SuperVillain, evilMinion: EvilMinion, 'evilMinions/yellowMinion': YellowMinion, doomsdayDevice: DoomsdayDevice, - mediocreVillain: MediocreVillain + mediocreVillain: MediocreVillain, + yellowMinion: YellowMinion }); - env.store.modelFor('superVillain'); - env.store.modelFor('evilMinion'); - env.store.modelFor('evilMinions/yellowMinion'); - env.store.modelFor('doomsdayDevice'); - env.store.modelFor('mediocreVillain'); + env.store.modelFor('super-villain'); + env.store.modelFor('evil-minion'); + env.store.modelFor('evil-minions/yellow-minion'); + env.store.modelFor('doomsday-device'); + env.store.modelFor('mediocre-villain'); env.registry.register('serializer:application', DS.ActiveModelSerializer); env.registry.register('serializer:-active-model', DS.ActiveModelSerializer); env.registry.register('adapter:-active-model', DS.ActiveModelAdapter); @@ -49,8 +50,8 @@ module("integration/active_model - AMS-namespaced-model-names", { test("serialize polymorphic", function() { var tom, ray; run(function() { - tom = env.store.createRecord('evilMinions/yellowMinion', { name: "Alex", id: "124" }); - ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); + tom = env.store.createRecord('evil-minions/yellow-minion', { name: "Alex", id: "124" }); + ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: "DeathRay" }); }); var json = env.amsSerializer.serialize(ray._createSnapshot()); @@ -66,8 +67,8 @@ test("serialize polymorphic when type key is not camelized", function() { YellowMinion.modelName = 'evil-minions/yellow-minion'; var tom, ray; run(function() { - tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); - ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); + tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); + ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: "DeathRay" }); }); var json = env.amsSerializer.serialize(ray._createSnapshot()); diff --git a/packages/activemodel-adapter/tests/integration/active-model-serializer-test.js b/packages/activemodel-adapter/tests/integration/active-model-serializer-test.js index e0a56034a1b..a259615348a 100644 --- a/packages/activemodel-adapter/tests/integration/active-model-serializer-test.js +++ b/packages/activemodel-adapter/tests/integration/active-model-serializer-test.js @@ -7,25 +7,25 @@ module("integration/active_model - ActiveModelSerializer", { SuperVillain = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), - homePlanet: DS.belongsTo("homePlanet"), - evilMinions: DS.hasMany("evilMinion") + homePlanet: DS.belongsTo('home-planet'), + evilMinions: DS.hasMany('evil-minion') }); HomePlanet = DS.Model.extend({ name: DS.attr('string'), - superVillains: DS.hasMany('superVillain', { async: true }) + superVillains: DS.hasMany('super-villain', { async: true }) }); EvilMinion = DS.Model.extend({ - superVillain: DS.belongsTo('superVillain'), + superVillain: DS.belongsTo('super-villain'), name: DS.attr('string') }); YellowMinion = EvilMinion.extend(); DoomsdayDevice = DS.Model.extend({ name: DS.attr('string'), - evilMinion: DS.belongsTo('evilMinion', { polymorphic: true }) + evilMinion: DS.belongsTo('evil-minion', { polymorphic: true }) }); MediocreVillain = DS.Model.extend({ name: DS.attr('string'), - evilMinions: DS.hasMany('evilMinion', { polymorphic: true }) + evilMinions: DS.hasMany('evil-minion', { polymorphic: true }) }); env = setupStore({ superVillain: SuperVillain, @@ -35,12 +35,12 @@ module("integration/active_model - ActiveModelSerializer", { doomsdayDevice: DoomsdayDevice, mediocreVillain: MediocreVillain }); - env.store.modelFor('superVillain'); - env.store.modelFor('homePlanet'); - env.store.modelFor('evilMinion'); - env.store.modelFor('yellowMinion'); - env.store.modelFor('doomsdayDevice'); - env.store.modelFor('mediocreVillain'); + env.store.modelFor('super-villain'); + env.store.modelFor('home-planet'); + env.store.modelFor('evil-minion'); + env.store.modelFor('yellow-minion'); + env.store.modelFor('doomsday-device'); + env.store.modelFor('mediocre-villain'); env.registry.register('serializer:application', DS.ActiveModelSerializer); env.registry.register('serializer:-active-model', DS.ActiveModelSerializer); env.registry.register('adapter:-active-model', DS.ActiveModelAdapter); @@ -56,8 +56,8 @@ module("integration/active_model - ActiveModelSerializer", { test("serialize", function() { var tom; run(function() { - league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); - tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league }); + league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); + tom = env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league }); }); var json = env.amsSerializer.serialize(tom._createSnapshot()); @@ -71,7 +71,7 @@ test("serialize", function() { test("serializeIntoHash", function() { run(function() { - league = env.store.createRecord(HomePlanet, { name: "Umber", id: "123" }); + league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); }); var json = {}; @@ -87,7 +87,7 @@ test("serializeIntoHash", function() { test("serializeIntoHash with decamelized types", function() { HomePlanet.modelName = 'home-planet'; run(function() { - league = env.store.createRecord(HomePlanet, { name: "Umber", id: "123" }); + league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); }); var json = {}; @@ -103,7 +103,7 @@ test("serializeIntoHash with decamelized types", function() { test("normalize", function() { SuperVillain.reopen({ - yellowMinion: DS.belongsTo('yellowMinion') + yellowMinion: DS.belongsTo('yellow-minion') }); var superVillain_hash = { first_name: "Tom", last_name: "Dale", home_planet_id: "123", evil_minion_ids: [1,2] }; @@ -156,7 +156,7 @@ test("extractSingle", function() { }); run(function() { - env.store.find("superVillain", 1).then(function(minion) { + env.store.find('super-villain', 1).then(function(minion) { equal(minion.get('firstName'), "Tom"); }); }); @@ -182,7 +182,7 @@ test("extractArray", function() { }]); run(function() { - env.store.find("superVillain", 1).then(function(minion) { + env.store.find('super-villain', 1).then(function(minion) { equal(minion.get('firstName'), "Tom"); }); }); @@ -191,8 +191,8 @@ test("extractArray", function() { test("serialize polymorphic", function() { var tom, ray; run(function() { - tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); - ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); + tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); + ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: "DeathRay" }); }); var json = env.amsSerializer.serialize(ray._createSnapshot()); @@ -208,8 +208,8 @@ test("serialize polymorphic when type key is not camelized", function() { YellowMinion.modelName = 'yellow-minion'; var tom, ray; run(function() { - tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); - ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); + tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); + ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: "DeathRay" }); }); var json = env.amsSerializer.serialize(ray._createSnapshot()); @@ -220,7 +220,7 @@ test("serialize polymorphic when type key is not camelized", function() { test("serialize polymorphic when associated object is null", function() { var ray, json; run(function() { - ray = env.store.createRecord(DoomsdayDevice, { name: "DeathRay" }); + ray = env.store.createRecord('doomsday-device', { name: "DeathRay" }); json = env.amsSerializer.serialize(ray._createSnapshot()); }); diff --git a/packages/ember-data/lib/serializers/embedded-records-mixin.js b/packages/ember-data/lib/serializers/embedded-records-mixin.js index d0c2be79e37..adc0ddcbc99 100644 --- a/packages/ember-data/lib/serializers/embedded-records-mixin.js +++ b/packages/ember-data/lib/serializers/embedded-records-mixin.js @@ -336,7 +336,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ var parentRecord = snapshot.type.inverseFor(relationship.key); if (parentRecord) { var name = parentRecord.name; - var embeddedSerializer = this.store.serializerFor(embeddedSnapshot.type); + var embeddedSerializer = this.store.serializerFor(embeddedSnapshot.modelName); var parentKey = embeddedSerializer.keyForRelationship(name, parentRecord.kind, 'deserialize'); if (parentKey) { delete json[parentKey]; @@ -423,7 +423,7 @@ function extractEmbeddedHasMany(store, key, embeddedTypeClass, hash) { var embeddedSerializer = store.serializerFor(embeddedTypeClass.modelName); forEach(hash[key], function(data) { var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null); - store.push(embeddedTypeClass, embeddedRecord); + store.push(embeddedTypeClass.modelName, embeddedRecord); ids.push(embeddedRecord.id); }); @@ -445,7 +445,7 @@ function extractEmbeddedHasManyPolymorphic(store, key, hash) { var primaryKey = get(embeddedSerializer, 'primaryKey'); var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null); - store.push(embeddedTypeClass, embeddedRecord); + store.push(embeddedTypeClass.modelName, embeddedRecord); ids.push({ id: embeddedRecord[primaryKey], type: modelName }); }); @@ -460,7 +460,7 @@ function extractEmbeddedBelongsTo(store, key, embeddedTypeClass, hash) { var embeddedSerializer = store.serializerFor(embeddedTypeClass.modelName); var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, hash[key], null); - store.push(embeddedTypeClass, embeddedRecord); + store.push(embeddedTypeClass.modelName, embeddedRecord); hash[key] = embeddedRecord.id; //TODO Need to add a reference to the parent later so relationship works between both `belongsTo` records @@ -479,7 +479,7 @@ function extractEmbeddedBelongsToPolymorphic(store, key, hash) { var primaryKey = get(embeddedSerializer, 'primaryKey'); var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null); - store.push(embeddedTypeClass, embeddedRecord); + store.push(embeddedTypeClass.modelName, embeddedRecord); hash[key] = embeddedRecord[primaryKey]; hash[key + 'Type'] = modelName; diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index 7a03adaa7d4..e81133c090b 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -729,7 +729,7 @@ export default Serializer.extend({ @return {Object} json The deserialized payload */ extract: function(store, typeClass, payload, id, requestType) { - this.extractMeta(store, typeClass, payload); + this.extractMeta(store, typeClass.modelName, payload); var specificExtract = "extract" + requestType.charAt(0).toUpperCase() + requestType.substr(1); return this[specificExtract](store, typeClass, payload, id, requestType); diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index 3431246c4b4..2a96622ac68 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -267,14 +267,14 @@ var RESTSerializer = JSONSerializer.extend({ var primaryRecord; for (var prop in payload) { - var typeName = this.modelNameFromPayloadKey(prop); + var modelName = this.modelNameFromPayloadKey(prop); - if (!store.modelFactoryFor(typeName)) { - Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false); + if (!store.modelFactoryFor(modelName)) { + Ember.warn(this.warnMessageNoModelForKey(prop, modelName), false); continue; } - var type = store.modelFor(typeName); - var isPrimary = type.modelName === primaryTypeClassName; + var typeClass = store.modelFor(modelName); + var isPrimary = typeClass.modelName === primaryTypeClassName; var value = payload[prop]; if (value === null) { @@ -290,10 +290,9 @@ var RESTSerializer = JSONSerializer.extend({ /*jshint loopfunc:true*/ forEach.call(value, function(hash) { var typeName = this.modelNameFromPayloadKey(prop); - var type = store.modelFor(typeName); - var typeSerializer = store.serializerFor(type); + var typeSerializer = store.serializerFor(typeName); - hash = typeSerializer.normalize(type, hash, prop); + hash = typeSerializer.normalize(typeClass, hash, prop); var isFirstCreatedRecord = isPrimary && !recordId && !primaryRecord; var isUpdatedRecord = isPrimary && coerceId(hash.id) === recordId; @@ -307,7 +306,7 @@ var RESTSerializer = JSONSerializer.extend({ if (isFirstCreatedRecord || isUpdatedRecord) { primaryRecord = hash; } else { - store.push(typeName, hash); + store.push(modelName, hash); } }, this); } @@ -435,7 +434,7 @@ var RESTSerializer = JSONSerializer.extend({ continue; } var type = store.modelFor(typeName); - var typeSerializer = store.serializerFor(type); + var typeSerializer = store.serializerFor(typeName); var isPrimary = (!forcedSecondary && (type.modelName === primaryTypeClassName)); /*jshint loopfunc:true*/ @@ -493,12 +492,12 @@ var RESTSerializer = JSONSerializer.extend({ Ember.warn(this.warnMessageNoModelForKey(prop, modelName), false); continue; } - var type = store.modelFor(modelName); - var typeSerializer = store.serializerFor(type); + var typeClass = store.modelFor(modelName); + var typeSerializer = store.serializerFor(modelName); /*jshint loopfunc:true*/ var normalizedArray = map.call(Ember.makeArray(payload[prop]), function(hash) { - return typeSerializer.normalize(type, hash, prop); + return typeSerializer.normalize(typeClass, hash, prop); }, this); store.pushMany(modelName, normalizedArray); diff --git a/packages/ember-data/lib/system/debug/debug-adapter.js b/packages/ember-data/lib/system/debug/debug-adapter.js index 3b7681466c7..fb81957483a 100644 --- a/packages/ember-data/lib/system/debug/debug-adapter.js +++ b/packages/ember-data/lib/system/debug/debug-adapter.js @@ -42,7 +42,11 @@ export default Ember.DataAdapter.extend({ return columns; }, - getRecords: function(modelName) { + getRecords: function(modelNameOrFactory) { + // TODO: Ask Teddy what we should do here. + // Ideally this should always get passed a string. + + var modelName = typeof modelNameOrFactory === 'string' ? modelNameOrFactory : modelNameOrFactory.modelName; return this.get('store').all(modelName); }, diff --git a/packages/ember-data/lib/system/many-array.js b/packages/ember-data/lib/system/many-array.js index be0ff78d696..e4b3bbf15cc 100644 --- a/packages/ember-data/lib/system/many-array.js +++ b/packages/ember-data/lib/system/many-array.js @@ -228,7 +228,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { Ember.assert("You cannot add '" + type.modelName + "' records to this polymorphic relationship.", !get(this, 'isPolymorphic')); - record = store.createRecord(type, hash); + record = store.createRecord(type.modelName, hash); this.pushObject(record); return record; diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 85f9caf5f7e..fbdbe98011f 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -29,13 +29,13 @@ var _splitOnDotCache = Ember.create(null); function splitOnDot(name) { return _splitOnDotCache[name] || ( - _splitOnDotCache[name] = name.split('.') + (_splitOnDotCache[name] = name.split('.')) ); } function extractPivotName(name) { return _extractPivotNameCache[name] || ( - _extractPivotNameCache[name] = splitOnDot(name)[0] + (_extractPivotNameCache[name] = splitOnDot(name)[0]) ); } diff --git a/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js b/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js index 5712a5a142a..1d7a24f00e7 100644 --- a/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js +++ b/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js @@ -39,8 +39,9 @@ export default RecordArray.extend({ load: function(data) { var store = get(this, 'store'); var type = get(this, 'type'); - var records = store.pushMany(type, data); - var meta = store.metadataFor(type); + var modelName = type.modelName; + var records = store.pushMany(modelName, data); + var meta = store.metadataFor(modelName); this.setProperties({ content: Ember.A(records), diff --git a/packages/ember-data/lib/system/record-arrays/record-array.js b/packages/ember-data/lib/system/record-arrays/record-array.js index da3a0409618..a1c98541f6d 100644 --- a/packages/ember-data/lib/system/record-arrays/record-array.js +++ b/packages/ember-data/lib/system/record-arrays/record-array.js @@ -113,9 +113,9 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { if (get(this, 'isUpdating')) { return; } var store = get(this, 'store'); - var type = get(this, 'type'); + var modelName = get(this, 'type.modelName'); - return store.fetchAll(type, this); + return store.fetchAll(modelName, this); }, /** diff --git a/packages/ember-data/lib/system/relationships/state/relationship.js b/packages/ember-data/lib/system/relationships/state/relationship.js index f17715dc7fb..4dffdee23f1 100644 --- a/packages/ember-data/lib/system/relationships/state/relationship.js +++ b/packages/ember-data/lib/system/relationships/state/relationship.js @@ -2,7 +2,7 @@ import OrderedSet from "ember-data/system/ordered-set"; var forEach = Ember.EnumerableUtils.forEach; -var Relationship = function(store, record, inverseKey, relationshipMeta) { +function Relationship(store, record, inverseKey, relationshipMeta) { this.members = new OrderedSet(); this.canonicalMembers = new OrderedSet(); this.store = store; @@ -13,10 +13,10 @@ var Relationship = function(store, record, inverseKey, relationshipMeta) { this.relationshipMeta = relationshipMeta; //This probably breaks for polymorphic relationship in complex scenarios, due to //multiple possible modelNames - this.inverseKeyForImplicit = this.store.modelFor(this.record.constructor).modelName + this.key; + this.inverseKeyForImplicit = this.record.constructor.modelName + this.key; this.linkPromise = null; this.hasData = false; -}; +} Relationship.prototype = { constructor: Relationship, diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 3a21b1d43f3..bc84050d148 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -41,9 +41,7 @@ import { import RecordArrayManager from "ember-data/system/record-array-manager"; import Model from "ember-data/system/model"; - -//Stanley told me to do this -var Backburner = Ember.__loader.require('backburner')['default'] || Ember.__loader.require('backburner')['Backburner']; +var Backburner = Ember.Backburner || Ember.__loader.require('backburner')['default'] || Ember.__loader.require('backburner')['Backburner']; //Shim Backburner.join if (!Backburner.prototype.join) { @@ -306,6 +304,7 @@ Store = Service.extend({ @return {DS.Model} record */ createRecord: function(modelName, inputProperties) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var properties = copy(inputProperties) || {}; @@ -315,7 +314,7 @@ Store = Service.extend({ // to avoid conflicts. if (isNone(properties.id)) { - properties.id = this._generateId(typeClass, properties); + properties.id = this._generateId(modelName, properties); } // Coerce ID to a string @@ -512,6 +511,7 @@ Store = Service.extend({ find: function(modelName, id, preload) { Ember.assert("You need to pass a type to the store's find method", arguments.length >= 1); Ember.assert("You may not pass `" + id + "` as id to the store's find method", arguments.length === 1 || !Ember.isNone(id)); + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); if (arguments.length === 1) { return this.findAll(modelName); @@ -552,6 +552,7 @@ Store = Service.extend({ @return {Promise} promise */ fetchById: function(modelName, id, preload) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); if (this.hasRecordForId(modelName, id)) { return this.getById(modelName, id).reload(); } else { @@ -568,6 +569,7 @@ Store = Service.extend({ @return {Promise} promise */ fetchAll: function(modelName) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); return this._fetchAll(typeClass, this.all(modelName)); @@ -582,6 +584,7 @@ Store = Service.extend({ @deprecated Use [fetchById](#method_fetchById) instead */ fetch: function(modelName, id, preload) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); Ember.deprecate('Using store.fetch() has been deprecated. Use store.fetchById for fetching individual records or store.fetchAll for collections'); return this.fetchById(modelName, id, preload); }, @@ -597,9 +600,9 @@ Store = Service.extend({ @return {Promise} promise */ findById: function(modelName, id, preload) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - var typeClass = this.modelFor(modelName); - var record = this.recordForId(typeClass, id); + var record = this.recordForId(modelName, id); return this._findByRecord(record, preload); }, @@ -632,6 +635,7 @@ Store = Service.extend({ @return {Promise} promise */ findByIds: function(modelName, ids) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var store = this; return promiseArray(Ember.RSVP.all(map(ids, function(id) { @@ -652,7 +656,7 @@ Store = Service.extend({ fetchRecord: function(record) { var typeClass = record.constructor; var id = get(record, 'id'); - var adapter = this.adapterFor(typeClass); + var adapter = this.adapterFor(typeClass.modelName); Ember.assert("You tried to find a record but you have no adapter (for " + typeClass + ")", adapter); Ember.assert("You tried to find a record but your adapter (for " + typeClass + ") does not implement 'find'", typeof adapter.find === 'function'); @@ -700,7 +704,7 @@ Store = Service.extend({ _flushPendingFetchForType: function (recordResolverPairs, typeClass) { var store = this; - var adapter = store.adapterFor(typeClass); + var adapter = store.adapterFor(typeClass.modelName); var shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; var records = Ember.A(recordResolverPairs).mapBy('record'); @@ -802,13 +806,14 @@ Store = Service.extend({ ``` @method getById - @param {String or subclass of DS.Model} type + @param {String} modelName @param {String|Integer} id @return {DS.Model|null} record */ - getById: function(type, id) { - if (this.hasRecordForId(type, id)) { - return this.recordForId(type, id); + getById: function(modelName, id) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + if (this.hasRecordForId(modelName, id)) { + return this.recordForId(modelName, id); } else { return null; } @@ -828,7 +833,7 @@ Store = Service.extend({ */ reloadRecord: function(record) { var type = record.constructor; - var adapter = this.adapterFor(type); + var adapter = this.adapterFor(type.modelName); var id = get(record, 'id'); Ember.assert("You cannot reload a record without an ID", id); @@ -847,6 +852,7 @@ Store = Service.extend({ @return {Boolean} */ hasRecordForId: function(modelName, inputId) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var id = coerceId(inputId); var record = this.typeMapFor(typeClass).idToRecord[id]; @@ -864,6 +870,7 @@ Store = Service.extend({ @return {DS.Model} record */ recordForId: function(modelName, inputId) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var id = coerceId(inputId); var idToRecord = this.typeMapFor(typeClass).idToRecord; @@ -912,7 +919,7 @@ Store = Service.extend({ @return {Promise} promise */ findHasMany: function(owner, link, type) { - var adapter = this.adapterFor(owner.constructor); + var adapter = this.adapterFor(owner.constructor.modelName); Ember.assert("You tried to load a hasMany relationship but you have no adapter (for " + owner.constructor + ")", adapter); Ember.assert("You tried to load a hasMany relationship from a specified `link` in the original payload but your adapter does not implement `findHasMany`", typeof adapter.findHasMany === 'function'); @@ -929,7 +936,7 @@ Store = Service.extend({ @return {Promise} promise */ findBelongsTo: function(owner, link, relationship) { - var adapter = this.adapterFor(owner.constructor); + var adapter = this.adapterFor(owner.constructor.modelName); Ember.assert("You tried to load a belongsTo relationship but you have no adapter (for " + owner.constructor + ")", adapter); Ember.assert("You tried to load a belongsTo relationship from a specified `link` in the original payload but your adapter does not implement `findBelongsTo`", typeof adapter.findBelongsTo === 'function'); @@ -950,21 +957,22 @@ Store = Service.extend({ @method findQuery @private - @param {String or subclass of DS.Model} type + @param {String} modelName @param {any} query an opaque query to be used by the adapter @return {Promise} promise */ - findQuery: function(typeName, query) { - var type = this.modelFor(typeName); + findQuery: function(modelName, query) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + var typeClass = this.modelFor(modelName); var array = this.recordArrayManager - .createAdapterPopulatedRecordArray(type, query); + .createAdapterPopulatedRecordArray(typeClass, query); - var adapter = this.adapterFor(type); + var adapter = this.adapterFor(modelName); - Ember.assert("You tried to load a query but you have no adapter (for " + type + ")", adapter); + Ember.assert("You tried to load a query but you have no adapter (for " + typeClass + ")", adapter); Ember.assert("You tried to load a query but your adapter does not implement `findQuery`", typeof adapter.findQuery === 'function'); - return promiseArray(_findQuery(adapter, this, type, query, array)); + return promiseArray(_findQuery(adapter, this, typeClass, query, array)); }, /** @@ -978,6 +986,7 @@ Store = Service.extend({ @return {DS.AdapterPopulatedRecordArray} */ findAll: function(modelName) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); return this.fetchAll(modelName); }, @@ -989,7 +998,7 @@ Store = Service.extend({ @return {Promise} promise */ _fetchAll: function(typeClass, array) { - var adapter = this.adapterFor(typeClass); + var adapter = this.adapterFor(typeClass.modelName); var sinceToken = this.typeMapFor(typeClass).metadata.since; set(array, 'isUpdating', true); @@ -1003,6 +1012,7 @@ Store = Service.extend({ /** @method didUpdateAll @param {DS.Model} typeClass + @private */ didUpdateAll: function(typeClass) { var findAllCache = this.typeMapFor(typeClass).findAllCache; @@ -1033,6 +1043,7 @@ Store = Service.extend({ @return {DS.RecordArray} */ all: function(modelName) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var typeMap = this.typeMapFor(typeClass); var findAllCache = typeMap.findAllCache; @@ -1062,6 +1073,7 @@ Store = Service.extend({ @param {String} optional modelName */ unloadAll: function(modelName) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), !modelName || typeof modelName === 'string'); if (arguments.length === 0) { var typeMaps = this.typeMaps; var keys = Ember.keys(typeMaps); @@ -1086,7 +1098,7 @@ Store = Service.extend({ } function byType(entry) { - return typeMaps[entry]['type']; + return typeMaps[entry]['type'].modelName; } }, @@ -1137,12 +1149,13 @@ Store = Service.extend({ ``` @method filter - @param {String or subclass of DS.Model} type + @param {String} modelName @param {Object} query optional query @param {Function} filter @return {DS.PromiseArray} */ - filter: function(type, query, filter) { + filter: function(modelName, query, filter) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var promise; var length = arguments.length; var array; @@ -1150,24 +1163,24 @@ Store = Service.extend({ // allow an optional server query if (hasQuery) { - promise = this.findQuery(type, query); + promise = this.findQuery(modelName, query); } else if (arguments.length === 2) { filter = query; } - type = this.modelFor(type); + modelName = this.modelFor(modelName); if (hasQuery) { - array = this.recordArrayManager.createFilteredRecordArray(type, filter, query); + array = this.recordArrayManager.createFilteredRecordArray(modelName, filter, query); } else { - array = this.recordArrayManager.createFilteredRecordArray(type, filter); + array = this.recordArrayManager.createFilteredRecordArray(modelName, filter); } promise = promise || Promise.cast(array); return promiseArray(promise.then(function() { return array; - }, null, "DS: Store#filter of " + type)); + }, null, "DS: Store#filter of " + modelName)); }, /** @@ -1185,24 +1198,26 @@ Store = Service.extend({ ``` @method recordIsLoaded - @param {String or subclass of DS.Model} type + @param {String} modelName @param {string} id @return {boolean} */ - recordIsLoaded: function(type, id) { - if (!this.hasRecordForId(type, id)) { return false; } - return !get(this.recordForId(type, id), 'isEmpty'); + recordIsLoaded: function(modelName, id) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + if (!this.hasRecordForId(modelName, id)) { return false; } + return !get(this.recordForId(modelName, id), 'isEmpty'); }, /** This method returns the metadata for a specific type. @method metadataFor - @param {String or subclass of DS.Model} typeName + @param {String or subclass of DS.Model} modelName @return {object} */ - metadataFor: function(typeName) { - var typeClass = this.modelFor(typeName); + metadataFor: function(modelName) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + var typeClass = this.modelFor(modelName); return this.typeMapFor(typeClass).metadata; }, @@ -1210,12 +1225,13 @@ Store = Service.extend({ This method sets the metadata for a specific type. @method setMetadataFor - @param {String or subclass of DS.Model} typeName + @param {String} modelName @param {Object} metadata metadata to set @return {object} */ - setMetadataFor: function(typeName, metadata) { - var typeClass = this.modelFor(typeName); + setMetadataFor: function(modelName, metadata) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + var typeClass = this.modelFor(modelName); Ember.merge(this.typeMapFor(typeClass).metadata, metadata); }, @@ -1273,7 +1289,7 @@ Store = Service.extend({ forEach(pending, function(tuple) { var record = tuple[0]; var resolver = tuple[1]; - var adapter = this.adapterFor(record.constructor); + var adapter = this.adapterFor(record.constructor.modelName); var operation; if (get(record, 'currentState.stateName') === 'root.deleted.saved') { @@ -1429,14 +1445,14 @@ Store = Service.extend({ */ _modelForMixin: function(modelName) { - var normalizedTypeKey = normalizeModelName(modelName); + var normalizedModelName = normalizeModelName(modelName); var registry = this.container._registry ? this.container._registry : this.container; - var mixin = registry.resolve('mixin:' + normalizedTypeKey); + var mixin = registry.resolve('mixin:' + normalizedModelName); if (mixin) { //Cache the class as a model - registry.register('model:' + normalizedTypeKey, DS.Model.extend(mixin)); + registry.register('model:' + normalizedModelName, DS.Model.extend(mixin)); } - var factory = this.modelFactoryFor(normalizedTypeKey); + var factory = this.modelFactoryFor(normalizedModelName); if (factory) { factory.__isMixin = true; factory.__mixin = mixin; @@ -1451,29 +1467,21 @@ Store = Service.extend({ etc.) @method modelFor - @param {String or subclass of DS.Model} key + @param {String} modelName @return {subclass of DS.Model} */ - modelFor: function(key) { - var factory; - - if (typeof key === 'string') { - factory = this.modelFactoryFor(key); - if (!factory) { - //Support looking up mixins as base types for polymorphic relationships - factory = this._modelForMixin(key); - } - if (!factory) { - throw new Ember.Error("No model was found for '" + key + "'"); - } - factory.modelName = factory.modelName || normalizeModelName(key); - } else { - // A factory already supplied. Ensure it has a normalized key. - factory = key; - if (factory.modelName) { - factory.modelName = normalizeModelName(factory.modelName); - } + modelFor: function(modelName) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + + var factory = this.modelFactoryFor(modelName); + if (!factory) { + //Support looking up mixins as base types for polymorphic relationships + factory = this._modelForMixin(modelName); } + if (!factory) { + throw new Ember.Error("No model was found for '" + modelName + "'"); + } + factory.modelName = factory.modelName || normalizeModelName(modelName); // deprecate typeKey if (!('typeKey' in factory)) { @@ -1494,8 +1502,9 @@ Store = Service.extend({ return factory; }, - modelFactoryFor: function(key) { - var normalizedKey = normalizeModelName(key); + modelFactoryFor: function(modelName) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + var normalizedKey = normalizeModelName(modelName); return this.container.lookupFactory('model:' + normalizedKey); }, @@ -1561,12 +1570,13 @@ Store = Service.extend({ records, as well as to update existing records. @method push - @param {String or subclass of DS.Model} modelName + @param {String} modelName @param {Object} data @return {DS.Model} the record that was created or updated. */ push: function(modelName, data) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); Ember.assert("Expected an object as `data` in a call to `push` for " + modelName + " , but was " + data, Ember.typeOf(data) === 'object'); Ember.assert("You must include an `id` for " + modelName + " in an object passed to `push`", data.id != null && data.id !== ''); @@ -1588,9 +1598,9 @@ Store = Service.extend({ // Actually load the record into the store. - this._load(type, data); + this._load(modelName, data); - var record = this.recordForId(type, data.id); + var record = this.recordForId(modelName, data.id); var store = this; this._backburner.join(function() { @@ -1656,19 +1666,20 @@ Store = Service.extend({ ``` @method pushPayload - @param {String} type Optionally, a model used to determine which serializer will be used + @param {String} modelName Optionally, a model type used to determine which serializer will be used @param {Object} payload */ - pushPayload: function (type, inputPayload) { + pushPayload: function (modelName, inputPayload) { var serializer; var payload; if (!inputPayload) { - payload = type; + payload = modelName; serializer = defaultSerializer(this.container); - Ember.assert("You cannot use `store#pushPayload` without a type unless your default serializer defines `pushPayload`", typeof serializer.pushPayload === 'function'); + Ember.assert("You cannot use `store#pushPayload` without a modelName unless your default serializer defines `pushPayload`", typeof serializer.pushPayload === 'function'); } else { payload = inputPayload; - serializer = this.serializerFor(type); + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + serializer = this.serializerFor(modelName); } var store = this; this._adapterRun(function() { @@ -1691,26 +1702,28 @@ Store = Service.extend({ ``` @method normalize - @param {String} type The name of the model type for this payload + @param {String} modelName The name of the model type for this payload @param {Object} payload @return {Object} The normalized payload */ - normalize: function (type, payload) { - var serializer = this.serializerFor(type); - var model = this.modelFor(type); + normalize: function (modelName, payload) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + var serializer = this.serializerFor(modelName); + var model = this.modelFor(modelName); return serializer.normalize(model, payload); }, /** @method update - @param {String} type + @param {String} modelName @param {Object} data @return {DS.Model} the record that was updated. @deprecated Use [push](#method_push) instead */ - update: function(type, data) { + update: function(modelName, data) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); Ember.deprecate('Using store.update() has been deprecated since store.push() now handles partial updates. You should use store.push() instead.'); - return this.push(type, data); + return this.push(modelName, data); }, /** @@ -1719,16 +1732,17 @@ Store = Service.extend({ call `push` repeatedly for you. @method pushMany - @param {String or subclass of DS.Model} type + @param {String} modelName @param {Array} datas @return {Array} */ - pushMany: function(type, datas) { + pushMany: function(modelName, datas) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var length = datas.length; var result = new Array(length); for (var i = 0; i < length; i++) { - result[i] = this.push(type, datas[i]); + result[i] = this.push(modelName, datas[i]); } return result; @@ -1736,13 +1750,14 @@ Store = Service.extend({ /** @method metaForType - @param {String or subclass of DS.Model} typeName + @param {String or subclass of DS.Model} modelName @param {Object} metadata @deprecated Use [setMetadataFor](#method_setMetadataFor) instead */ - metaForType: function(typeName, metadata) { + metaForType: function(modelName, metadata) { + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); Ember.deprecate('Using store.metaForType() has been deprecated. Use store.setMetadataFor() to set metadata for a specific type.'); - this.setMetadataFor(typeName, metadata); + this.setMetadataFor(modelName, metadata); }, /** @@ -1847,15 +1862,21 @@ Store = Service.extend({ @method adapterFor @private - @param {String or subclass of DS.Model} type + @param {String} modelName @return DS.Adapter */ - adapterFor: function(type) { - if (type !== 'application') { - type = this.modelFor(type); + adapterFor: function(modelOrClass) { + var modelName; + + Ember.deprecate('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelOrClass === 'string'); + + if (typeof modelOrClass !== 'string') { + modelName = modelOrClass.modelName; + } else { + modelName = modelOrClass; } - var adapter = this.lookupAdapter(type.modelName) || this.lookupAdapter('application'); + var adapter = this.lookupAdapter(modelName) || this.lookupAdapter('application'); return adapter || get(this, 'defaultAdapter'); }, @@ -1886,18 +1907,23 @@ Store = Service.extend({ @method serializerFor @private - @param {String or subclass of DS.Model} type the record to serialize + @param {String} modelName the record to serialize @return {DS.Serializer} */ - serializerFor: function(type) { - if (type !== 'application') { - type = this.modelFor(type); + serializerFor: function(modelOrClass) { + var modelName; + + Ember.deprecate('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelOrClass === 'string'); + if (typeof modelOrClass !== 'string') { + modelName = modelOrClass.modelName; + } else { + modelName = modelOrClass; } - var serializer = this.lookupSerializer(type.modelName) || this.lookupSerializer('application'); + var serializer = this.lookupSerializer(modelName) || this.lookupSerializer('application'); if (!serializer) { - var adapter = this.adapterFor(type); + var adapter = this.adapterFor(modelName); serializer = this.lookupSerializer(get(adapter, 'defaultSerializer')); } @@ -1986,7 +2012,7 @@ function deserializeRecordId(store, data, key, relationship, id) { if (typeof id === 'number' || typeof id === 'string') { type = typeFor(relationship, key, data); - data[key] = store.recordForId(type, id); + data[key] = store.recordForId(typeof type === 'string' ? type : type.modelName, id); } else if (typeof id === 'object') { // hasMany polymorphic Ember.assert('Ember Data expected a number or string to represent the record(s) in the `' + relationship.key + '` relationship instead it found an object. If this is a polymorphic relationship please specify a `type` key. If this is an embedded relationship please include the `DS.EmbeddedRecordsMixin` and specify the `' + relationship.key +'` property in your serializer\'s attrs object.', id.type); @@ -2024,9 +2050,10 @@ function defaultSerializer(container) { function _commit(adapter, store, operation, record) { var type = record.constructor; + var modelName = type.modelName; var snapshot = record._createSnapshot(); var promise = adapter[operation](store, type, snapshot); - var serializer = serializerForAdapter(store, adapter, type); + var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Extract and notify about " + operation + " completion of " + record; Ember.assert("Your adapter's '" + operation + "' method must return a value, but it returned `undefined", promise !==undefined); diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index 4697be92462..c633f5f3252 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -13,9 +13,10 @@ var get = Ember.get; var Promise = Ember.RSVP.Promise; export function _find(adapter, store, typeClass, id, record) { + var modelName = typeClass.modelName; var snapshot = record._createSnapshot(); var promise = adapter.find(store, typeClass, id, snapshot); - var serializer = serializerForAdapter(store, adapter, typeClass); + var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Handle Adapter#find of " + typeClass + " with id: " + id; promise = Promise.cast(promise, label); @@ -26,7 +27,7 @@ export function _find(adapter, store, typeClass, id, record) { return store._adapterRun(function() { var payload = serializer.extract(store, typeClass, adapterPayload, id, 'find'); - return store.push(typeClass, payload); + return store.push(modelName, payload); }); }, function(error) { record.notFound(); @@ -40,9 +41,10 @@ export function _find(adapter, store, typeClass, id, record) { export function _findMany(adapter, store, typeClass, ids, records) { + var modelName = typeClass.modelName; var snapshots = Ember.A(records).invoke('_createSnapshot'); var promise = adapter.findMany(store, typeClass, ids, snapshots); - var serializer = serializerForAdapter(store, adapter, typeClass); + var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Handle Adapter#findMany of " + typeClass; if (promise === undefined) { @@ -58,15 +60,16 @@ export function _findMany(adapter, store, typeClass, ids, records) { Ember.assert("The response from a findMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); - return store.pushMany(typeClass, payload); + return store.pushMany(modelName, payload); }); }, null, "DS: Extract payload of " + typeClass); } export function _findHasMany(adapter, store, record, link, relationship) { var snapshot = record._createSnapshot(); + var modelName = relationship.type.modelName; var promise = adapter.findHasMany(store, snapshot, link, relationship); - var serializer = serializerForAdapter(store, adapter, relationship.type); + var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type; promise = Promise.cast(promise, label); @@ -79,16 +82,17 @@ export function _findHasMany(adapter, store, record, link, relationship) { Ember.assert("The response from a findHasMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); - var records = store.pushMany(relationship.type, payload); + var records = store.pushMany(modelName, payload); return records; }); }, null, "DS: Extract payload of " + record + " : hasMany " + relationship.type); } export function _findBelongsTo(adapter, store, record, link, relationship) { + var modelName = relationship.type.modelName; var snapshot = record._createSnapshot(); var promise = adapter.findBelongsTo(store, snapshot, link, relationship); - var serializer = serializerForAdapter(store, adapter, relationship.type); + var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type; promise = Promise.cast(promise, label); @@ -103,7 +107,7 @@ export function _findBelongsTo(adapter, store, record, link, relationship) { return null; } - var record = store.push(relationship.type, payload); + var record = store.push(modelName, payload); return record; }); }, null, "DS: Extract payload of " + record + " : " + relationship.type); @@ -111,7 +115,8 @@ export function _findBelongsTo(adapter, store, record, link, relationship) { export function _findAll(adapter, store, typeClass, sinceToken) { var promise = adapter.findAll(store, typeClass, sinceToken); - var serializer = serializerForAdapter(store, adapter, typeClass); + var modelName = typeClass.modelName; + var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Handle Adapter#findAll of " + typeClass; promise = Promise.cast(promise, label); @@ -123,17 +128,18 @@ export function _findAll(adapter, store, typeClass, sinceToken) { Ember.assert("The response from a findAll must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); - store.pushMany(typeClass, payload); + store.pushMany(modelName, payload); }); store.didUpdateAll(typeClass); - return store.all(typeClass); + return store.all(modelName); }, null, "DS: Extract payload of findAll " + typeClass); } export function _findQuery(adapter, store, typeClass, query, recordArray) { + var modelName = typeClass.modelName; var promise = adapter.findQuery(store, typeClass, query, recordArray); - var serializer = serializerForAdapter(store, adapter, typeClass); + var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Handle Adapter#findQuery of " + typeClass; promise = Promise.cast(promise, label); diff --git a/packages/ember-data/tests/integration/adapter/build-url-mixin-test.js b/packages/ember-data/tests/integration/adapter/build-url-mixin-test.js index fa5ea293f03..cdc8008f614 100644 --- a/packages/ember-data/tests/integration/adapter/build-url-mixin-test.js +++ b/packages/ember-data/tests/integration/adapter/build-url-mixin-test.js @@ -28,6 +28,10 @@ module("integration/adapter/build-url-mixin - BuildURLMixin with RESTAdapter", { store = env.store; adapter = env.adapter; + Post = store.modelFor('post'); + Comment = store.modelFor('comment'); + SuperUser = store.modelFor('super-user'); + passedUrl = null; } }); @@ -154,7 +158,7 @@ test('buildURL - with camelized names', function() { ajaxResponse({ superUsers: [{ id: 1 }] }); run(function() { - store.find('superUser', 1).then(async(function(post) { + store.find('super-user', 1).then(async(function(post) { equal(passedUrl, "/super_users/1"); })); }); diff --git a/packages/ember-data/tests/integration/adapter/find-all-test.js b/packages/ember-data/tests/integration/adapter/find-all-test.js index b870cd536e1..a0541631765 100644 --- a/packages/ember-data/tests/integration/adapter/find-all-test.js +++ b/packages/ember-data/tests/integration/adapter/find-all-test.js @@ -1,6 +1,7 @@ var get = Ember.get; var Person, store, allRecords; var run = Ember.run; +var env; module("integration/adapter/find_all - Finding All Records of a Type", { setup: function() { @@ -12,6 +13,11 @@ module("integration/adapter/find_all - Finding All Records of a Type", { }); allRecords = null; + + env = setupStore({ + person: Person + }); + store = env.store; }, teardown: function() { @@ -25,20 +31,19 @@ module("integration/adapter/find_all - Finding All Records of a Type", { test("When all records for a type are requested, the store should call the adapter's `findAll` method.", function() { expect(5); - store = createStore({ adapter: DS.Adapter.extend({ - findAll: function(store, type, since) { - // this will get called twice - ok(true, "the adapter's findAll method should be invoked"); + env.registry.register('adapter:person', DS.Adapter.extend({ + findAll: function(store, type, since) { + // this will get called twice + ok(true, "the adapter's findAll method should be invoked"); - return Ember.RSVP.resolve([{ id: 1, name: "Braaaahm Dale" }]); - } - }) - }); + return Ember.RSVP.resolve([{ id: 1, name: "Braaaahm Dale" }]); + } + })); var allRecords; run(function() { - store.find(Person).then(function(all) { + store.find('person').then(function(all) { allRecords = all; equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); @@ -46,7 +51,7 @@ test("When all records for a type are requested, the store should call the adapt }); run(function() { - store.find(Person).then(function(all) { + store.find('person').then(function(all) { // Only one record array per type should ever be created (identity map) strictEqual(allRecords, all, "the same record array is returned every time all records of a type are requested"); }); @@ -57,27 +62,25 @@ test("When all records for a type are requested, a rejection should reject the p expect(5); var count = 0; - store = createStore({ - adapter: DS.Adapter.extend({ - findAll: function(store, type, since) { - // this will get called twice - ok(true, "the adapter's findAll method should be invoked"); - - if (count++ === 0) { - return Ember.RSVP.reject(); - } else { - return Ember.RSVP.resolve([{ id: 1, name: "Braaaahm Dale" }]); - } + env.registry.register('adapter:person', DS.Adapter.extend({ + findAll: function(store, type, since) { + // this will get called twice + ok(true, "the adapter's findAll method should be invoked"); + + if (count++ === 0) { + return Ember.RSVP.reject(); + } else { + return Ember.RSVP.resolve([{ id: 1, name: "Braaaahm Dale" }]); } - }) - }); + } + })); var allRecords; run(function() { - store.find(Person).then(null, function() { + store.find('person').then(null, function() { ok(true, "The rejection should get here"); - return store.find(Person); + return store.find('person'); }).then(function(all) { allRecords = all; equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); @@ -88,16 +91,15 @@ test("When all records for a type are requested, a rejection should reject the p test("When all records for a type are requested, records that are already loaded should be returned immediately.", function() { expect(3); - store = createStore({ adapter: DS.Adapter.extend() }); run(function() { // Load a record from the server - store.push(Person, { id: 1, name: "Jeremy Ashkenas" }); + store.push('person', { id: 1, name: "Jeremy Ashkenas" }); // Create a new, unsaved record in the store - store.createRecord(Person, { name: "Alex MacCaw" }); + store.createRecord('person', { name: "Alex MacCaw" }); }); - allRecords = store.all(Person); + allRecords = store.all('person'); equal(get(allRecords, 'length'), 2, "the record array's length is 2"); equal(allRecords.objectAt(0).get('name'), "Jeremy Ashkenas", "the first item in the record array is Jeremy Ashkenas"); @@ -107,14 +109,12 @@ test("When all records for a type are requested, records that are already loaded test("When all records for a type are requested, records that are created on the client should be added to the record array.", function() { expect(3); - store = createStore({ adapter: DS.Adapter.extend() }); - - allRecords = store.all(Person); + allRecords = store.all('person'); equal(get(allRecords, 'length'), 0, "precond - the record array's length is zero before any records are loaded"); run(function() { - store.createRecord(Person, { name: "Carsten Nielsen" }); + store.createRecord('person', { name: "Carsten Nielsen" }); }); equal(get(allRecords, 'length'), 1, "the record array's length is 1"); diff --git a/packages/ember-data/tests/integration/adapter/find-test.js b/packages/ember-data/tests/integration/adapter/find-test.js index 8d76e27f496..d07614e0ed4 100644 --- a/packages/ember-data/tests/integration/adapter/find-test.js +++ b/packages/ember-data/tests/integration/adapter/find-test.js @@ -1,4 +1,4 @@ -var Person, store; +var Person, store, env; var run = Ember.run; module("integration/adapter/find - Finding Records", { @@ -9,6 +9,11 @@ module("integration/adapter/find - Finding Records", { firstName: DS.attr('string'), lastName: DS.attr('string') }); + + env = setupStore({ + person: Person + }); + store = env.store; }, teardown: function() { @@ -17,7 +22,6 @@ module("integration/adapter/find - Finding Records", { }); test("It raises an assertion when no type is passed", function() { - store = createStore(); expectAssertion(function() { store.find(); @@ -25,14 +29,13 @@ test("It raises an assertion when no type is passed", function() { }); test("It raises an assertion when `undefined` is passed as id (#1705)", function() { - store = createStore(); expectAssertion(function() { - store.find(Person, undefined); + store.find('person', undefined); }, "You may not pass `undefined` as id to the store's find method"); expectAssertion(function() { - store.find(Person, null); + store.find('person', null); }, "You may not pass `null` as id to the store's find method"); }); @@ -41,35 +44,33 @@ test("When a single record is requested, the adapter's find method should be cal var count = 0; - store = createStore({ adapter: DS.Adapter.extend({ - find: function(store, type, id, snapshot) { - equal(type, Person, "the find method is called with the correct type"); - equal(count, 0, "the find method is only called once"); + env.registry.register('adapter:person', DS.Adapter.extend({ + find: function(store, type, id, snapshot) { + equal(type, Person, "the find method is called with the correct type"); + equal(count, 0, "the find method is only called once"); - count++; - return { id: 1, name: "Braaaahm Dale" }; - } - }) - }); + count++; + return { id: 1, name: "Braaaahm Dale" }; + } + })); run(function() { - store.find(Person, 1); - store.find(Person, 1); + store.find('person', 1); + store.find('person', 1); }); }); test("When a single record is requested multiple times, all .find() calls are resolved after the promise is resolved", function() { var deferred = Ember.RSVP.defer(); - store = createStore({ adapter: DS.Adapter.extend({ - find: function(store, type, id, snapshot) { - return deferred.promise; - } - }) - }); + env.registry.register('adapter:person', DS.Adapter.extend({ + find: function(store, type, id, snapshot) { + return deferred.promise; + } + })); run(function() { - store.find(Person, 1).then(async(function(person) { + store.find('person', 1).then(async(function(person) { equal(person.get('id'), "1"); equal(person.get('name'), "Braaaahm Dale"); @@ -85,7 +86,7 @@ test("When a single record is requested multiple times, all .find() calls are re }); run(function() { - store.find(Person, 1).then(async(function(post) { + store.find('person', 1).then(async(function(post) { equal(post.get('id'), "1"); equal(post.get('name'), "Braaaahm Dale"); @@ -107,15 +108,14 @@ test("When a single record is requested multiple times, all .find() calls are re }); test("When a single record is requested, and the promise is rejected, .find() is rejected.", function() { - store = createStore({ adapter: DS.Adapter.extend({ - find: function(store, type, id, snapshot) { - return Ember.RSVP.reject(); - } - }) - }); + env.registry.register('adapter:person', DS.Adapter.extend({ + find: function(store, type, id, snapshot) { + return Ember.RSVP.reject(); + } + })); run(function() { - store.find(Person, 1).then(null, async(function(reason) { + store.find('person', 1).then(null, async(function(reason) { ok(true, "The rejection handler was called"); })); }); @@ -124,18 +124,17 @@ test("When a single record is requested, and the promise is rejected, .find() is test("When a single record is requested, and the promise is rejected, the record should be unloaded.", function() { expect(2); - store = createStore({ adapter: DS.Adapter.extend({ - find: function(store, type, id, snapshot) { - return Ember.RSVP.reject(); - } - }) - }); + env.registry.register('adapter:person', DS.Adapter.extend({ + find: function(store, type, id, snapshot) { + return Ember.RSVP.reject(); + } + })); run(function() { - store.find(Person, 1).then(null, async(function(reason) { + store.find('person', 1).then(null, async(function(reason) { ok(true, "The rejection handler was called"); })); }); - ok(!store.hasRecordForId(Person, 1), "The record has been unloaded"); + ok(!store.hasRecordForId('person', 1), "The record has been unloaded"); }); diff --git a/packages/ember-data/tests/integration/adapter/store-adapter-test.js b/packages/ember-data/tests/integration/adapter/store-adapter-test.js index 50e854e3eb1..605b13c9f1a 100644 --- a/packages/ember-data/tests/integration/adapter/store-adapter-test.js +++ b/packages/ember-data/tests/integration/adapter/store-adapter-test.js @@ -664,7 +664,7 @@ test("if a updated record is marked as erred by the server, it enters an error s }; var person = run(function() { - return store.push(Person, { id: 1, name: "John Doe" }); + return store.push('person', { id: 1, name: "John Doe" }); }); run(store, 'find', 'person', 1).then(async(function(record) { diff --git a/packages/ember-data/tests/integration/debug-adapter-test.js b/packages/ember-data/tests/integration/debug-adapter-test.js index 3471c665065..53ec9a313ab 100644 --- a/packages/ember-data/tests/integration/debug-adapter-test.js +++ b/packages/ember-data/tests/integration/debug-adapter-test.js @@ -15,6 +15,9 @@ module("DS.DebugAdapter", { App.Post = DS.Model.extend({ title: DS.attr('string') }); + App.Post.reopenClass({ + modelName: 'post' + }); }); @@ -23,7 +26,7 @@ module("DS.DebugAdapter", { debugAdapter.reopen({ getModelTypes: function() { - return Ember.A([{ klass: App.Post, name: 'App.Post' }]); + return Ember.A([{ klass: App.__container__.lookupFactory('model:post'), name: 'App.Post' }]); } }); }, @@ -39,7 +42,7 @@ test("Watching Model Types", function() { equal(types.length, 1); equal(types[0].name, 'App.Post'); equal(types[0].count, 0); - strictEqual(types[0].object, App.Post); + strictEqual(types[0].object, store.modelFor('post')); }; var updated = function(types) { @@ -71,7 +74,7 @@ test("Watching Records", function() { removedCount = count; }; - debugAdapter.watchRecords(App.Post, recordsAdded, recordsUpdated, recordsRemoved); + debugAdapter.watchRecords(App.__container__.lookupFactory('model:post'), recordsAdded, recordsUpdated, recordsRemoved); equal(get(addedRecords, 'length'), 1); record = addedRecords[0]; diff --git a/packages/ember-data/tests/integration/filter-test.js b/packages/ember-data/tests/integration/filter-test.js index 8196c4ff526..e59721e90ee 100644 --- a/packages/ember-data/tests/integration/filter-test.js +++ b/packages/ember-data/tests/integration/filter-test.js @@ -193,7 +193,7 @@ test("a Record Array can update its filter", function() { asyncBryn = store.find('person', 3); }); - store.filter(Person, function(hash) { + store.filter('person', function(hash) { if (hash.get('name').match(/Scumbag [KD]/)) { return true; } }).then(async(function(recordArray) { @@ -253,7 +253,7 @@ test("a Record Array can update its filter and notify array observers", function asyncBryn = store.find('person', 3); }); - store.filter(Person, function(hash) { + store.filter('person', function(hash) { if (hash.get('name').match(/Scumbag [KD]/)) { return true; } }).then(async(function(recordArray) { @@ -378,7 +378,7 @@ test("filter with query persists query on the resulting filteredRecordArray", fu var filter; run(function() { - filter = store.filter(Person, { foo: 1 }, function(person) { + filter = store.filter('person', { foo: 1 }, function(person) { return true; }); }); @@ -400,7 +400,7 @@ test("it is possible to filter by state flags", function() { } })); - filter = store.filter(Person, function(person) { + filter = store.filter('person', function(person) { return person.get('isLoaded'); }); }); diff --git a/packages/ember-data/tests/integration/inverse-test.js b/packages/ember-data/tests/integration/inverse-test.js index 107adffc71c..e55f15ec4b9 100644 --- a/packages/ember-data/tests/integration/inverse-test.js +++ b/packages/ember-data/tests/integration/inverse-test.js @@ -26,7 +26,7 @@ module('integration/inverse_test - inverseFor', { Job.toString = stringify('job'); ReflexiveModel = DS.Model.extend({ - reflexiveProp: belongsTo('reflexiveModel') + reflexiveProp: belongsTo('reflexive-model') }); ReflexiveModel.toString = stringify('reflexiveModel'); @@ -143,7 +143,7 @@ test("Errors out if you do not define an inverse for a reflexive relationship", warns(function() { var reflexiveModel; run(function() { - reflexiveModel = store.push('reflexiveModel', { id: 1 }); + reflexiveModel = store.push('reflexive-model', { id: 1 }); }); }, /Detected a reflexive relationship by the name of 'reflexiveProp'/); }); diff --git a/packages/ember-data/tests/integration/lifecycle-hooks-test.js b/packages/ember-data/tests/integration/lifecycle-hooks-test.js index dab3da4c7a6..3625e35c9e0 100644 --- a/packages/ember-data/tests/integration/lifecycle-hooks-test.js +++ b/packages/ember-data/tests/integration/lifecycle-hooks-test.js @@ -28,7 +28,7 @@ asyncTest("When the adapter acknowledges that a record has been created, a `didC var person; run(function() { - person = env.store.createRecord(Person, { name: "Yehuda Katz" }); + person = env.store.createRecord('person', { name: "Yehuda Katz" }); }); person.on('didCreate', function() { @@ -50,7 +50,7 @@ test("When the adapter acknowledges that a record has been created without a new var person; run(function() { - person = env.store.createRecord(Person, { id: 99, name: "Yehuda Katz" }); + person = env.store.createRecord('person', { id: 99, name: "Yehuda Katz" }); }); person.on('didCreate', function() { diff --git a/packages/ember-data/tests/integration/multiple_stores_test.js b/packages/ember-data/tests/integration/multiple_stores_test.js index 09210a6db6b..badc61087e4 100644 --- a/packages/ember-data/tests/integration/multiple_stores_test.js +++ b/packages/ember-data/tests/integration/multiple_stores_test.js @@ -7,15 +7,15 @@ module("integration/multiple_stores - Multiple Stores Tests", { SuperVillain = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), - homePlanet: DS.belongsTo("homePlanet", { inverse: 'villains' }), - evilMinions: DS.hasMany("evilMinion") + homePlanet: DS.belongsTo('home-planet', { inverse: 'villains' }), + evilMinions: DS.hasMany('evil-minion') }); HomePlanet = DS.Model.extend({ name: DS.attr('string'), - villains: DS.hasMany('superVillain', { inverse: 'homePlanet' }) + villains: DS.hasMany('super-villain', { inverse: 'homePlanet' }) }); EvilMinion = DS.Model.extend({ - superVillain: DS.belongsTo('superVillain'), + superVillain: DS.belongsTo('super-villain'), name: DS.attr('string') }); @@ -77,9 +77,9 @@ test("embedded records should be created in multiple stores", function() { } })); - var serializer_main = env.store.serializerFor("homePlanet"); - var serializer_a = env.store_a.serializerFor("homePlanet"); - var serializer_b = env.store_b.serializerFor("homePlanet"); + var serializer_main = env.store.serializerFor('home-planet'); + var serializer_a = env.store_a.serializerFor('home-planet'); + var serializer_b = env.store_b.serializerFor('home-planet'); var json_hash_main = { home_planet: { @@ -117,18 +117,18 @@ test("embedded records should be created in multiple stores", function() { var json_main, json_a, json_b; run(function() { - json_main = serializer_main.extractSingle(env.store, HomePlanet, json_hash_main); - equal(env.store.hasRecordForId("superVillain", "1"), true, "superVillain should exist in store:main"); + json_main = serializer_main.extractSingle(env.store, env.store.modelFor('home-planet'), json_hash_main); + equal(env.store.hasRecordForId('super-villain', "1"), true, "superVillain should exist in store:main"); }); run(function() { - json_a = serializer_a.extractSingle(env.store_a, HomePlanet, json_hash_a); - equal(env.store_a.hasRecordForId("superVillain", "1"), true, "superVillain should exist in store:store-a"); + json_a = serializer_a.extractSingle(env.store_a, env.store_a.modelFor('home-planet'), json_hash_a); + equal(env.store_a.hasRecordForId("super-villain", "1"), true, "superVillain should exist in store:store-a"); }); run(function() { - json_b = serializer_b.extractSingle(env.store_b, HomePlanet, json_hash_b); - equal(env.store_b.hasRecordForId("superVillain", "1"), true, "superVillain should exist in store:store-b"); + json_b = serializer_b.extractSingle(env.store_b, env.store_a.modelFor('home-planet'), json_hash_b); + equal(env.store_b.hasRecordForId("super-villain", "1"), true, "superVillain should exist in store:store-b"); }); }); diff --git a/packages/ember-data/tests/integration/records/load-test.js b/packages/ember-data/tests/integration/records/load-test.js index 368e4641ff4..b13d373b196 100644 --- a/packages/ember-data/tests/integration/records/load-test.js +++ b/packages/ember-data/tests/integration/records/load-test.js @@ -27,13 +27,13 @@ test("When loading a record fails, the isLoading is set to false", function() { }; run(function() { - env.store.find('post', 1).then(null, function() { + env.store.find('post', 1).then(null, async(function() { // store.recordForId is private, but there is currently no other way to // get the specific record instance, since it is not passed to this // rejection handler var post = env.store.recordForId('post', 1); equal(post.get("isLoading"), false, "post is not loading anymore"); - }); + })); }); }); diff --git a/packages/ember-data/tests/integration/relationships/belongs-to-test.js b/packages/ember-data/tests/integration/relationships/belongs-to-test.js index a906968a355..9679be315a2 100644 --- a/packages/ember-data/tests/integration/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/integration/relationships/belongs-to-test.js @@ -380,7 +380,7 @@ test("relationshipsByName does not cache a factory", function() { // A model is looked up in the store based on a string, via user input var messageModelFromStore = store.modelFor('message'); // And the model is lookup up internally via the relationship type - var messageModelFromRelationType = store.modelFor(messageType); + var messageModelFromRelationType = store.modelFor(messageType.modelName); equal(messageModelFromRelationType, messageModelFromStore, "model factory based on relationship type matches the model based on store.modelFor"); diff --git a/packages/ember-data/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/packages/ember-data/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index 261517873e2..f3977b596b2 100644 --- a/packages/ember-data/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/packages/ember-data/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -90,7 +90,7 @@ test("Setting the polymorphic belongsTo with an object that does not implement t var user, video; run(function() { user = store.push('user', { id: 1, name: 'Stanley' }); - video = store.push('notMessage', { id: 2, video: 'Here comes Youtube' }); + video = store.push('not-message', { id: 2, video: 'Here comes Youtube' }); }); run(function() { @@ -135,7 +135,7 @@ test("Setting the polymorphic belongsTo with an object that does not implement t var user, video; run(function() { user = store.push('user', { id: 1, name: 'Stanley' }); - video = store.push('notMessage', { id: 2, video: 'Here comes Youtube' }); + video = store.push('not-message', { id: 2, video: 'Here comes Youtube' }); }); run(function() { diff --git a/packages/ember-data/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/packages/ember-data/tests/integration/relationships/polymorphic-mixins-has-many-test.js index 3d84bb2f642..5cd8d528b60 100644 --- a/packages/ember-data/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -93,7 +93,7 @@ test("Pushing a an object that does not implement the mixin to the mixin accepti var user,notMessage; run(function() { user = store.push('user', { id: 1, name: 'Stanley', messages: [] }); - notMessage = store.push('notMessage', { id: 2, video: 'Here comes Youtube' }); + notMessage = store.push('not-message', { id: 2, video: 'Here comes Youtube' }); }); run(function() { @@ -140,7 +140,7 @@ test("Pushing a an object that does not implement the mixin to the mixin accepti var user,notMessage; run(function() { user = store.push('user', { id: 1, name: 'Stanley', messages: [] }); - notMessage = store.push('notMessage', { id: 2, video: 'Here comes Youtube' }); + notMessage = store.push('not-message', { id: 2, video: 'Here comes Youtube' }); }); run(function() { diff --git a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js index 8606df6b8a8..0c4f1e99a71 100644 --- a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js +++ b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js @@ -10,32 +10,32 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { SuperVillain = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), - homePlanet: DS.belongsTo("homePlanet", { inverse: 'villains' }), - secretLab: DS.belongsTo("secretLab"), - secretWeapons: DS.hasMany("secretWeapon"), - evilMinions: DS.hasMany("evilMinion") + homePlanet: DS.belongsTo('home-planet', { inverse: 'villains' }), + secretLab: DS.belongsTo('secret-lab'), + secretWeapons: DS.hasMany('secret-weapon'), + evilMinions: DS.hasMany('evil-minion') }); HomePlanet = DS.Model.extend({ name: DS.attr('string'), - villains: DS.hasMany('superVillain', { inverse: 'homePlanet' }) + villains: DS.hasMany('super-villain', { inverse: 'homePlanet' }) }); SecretLab = DS.Model.extend({ minionCapacity: DS.attr('number'), vicinity: DS.attr('string'), - superVillain: DS.belongsTo('superVillain') + superVillain: DS.belongsTo('super-villain') }); BatCave = SecretLab.extend({ infiltrated: DS.attr('boolean') }); SecretWeapon = DS.Model.extend({ name: DS.attr('string'), - superVillain: DS.belongsTo('superVillain') + superVillain: DS.belongsTo('super-villain') }); LightSaber = SecretWeapon.extend({ color: DS.attr('string') }); EvilMinion = DS.Model.extend({ - superVillain: DS.belongsTo('superVillain'), + superVillain: DS.belongsTo('super-villain'), name: DS.attr('string') }); Comment = DS.Model.extend({ @@ -53,13 +53,13 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { evilMinion: EvilMinion, comment: Comment }); - env.store.modelFor('superVillain'); - env.store.modelFor('homePlanet'); - env.store.modelFor('secretLab'); - env.store.modelFor('batCave'); - env.store.modelFor('secretWeapon'); - env.store.modelFor('lightSaber'); - env.store.modelFor('evilMinion'); + env.store.modelFor('super-villain'); + env.store.modelFor('home-planet'); + env.store.modelFor('secret-lab'); + env.store.modelFor('bat-cave'); + env.store.modelFor('secret-weapon'); + env.store.modelFor('light-saber'); + env.store.modelFor('evil-minion'); env.store.modelFor('comment'); env.registry.register('serializer:application', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); env.registry.register('serializer:-active-model', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin)); @@ -105,7 +105,7 @@ test("extractSingle with embedded objects", function() { villains: ["1"] }); run(function() { - env.store.find("superVillain", 1).then(function(minion) { + env.store.find('super-villain', 1).then(function(minion) { equal(minion.get('firstName'), "Tom"); }); }); @@ -152,14 +152,14 @@ test("extractSingle with embedded objects inside embedded objects", function() { villains: ["1"] }); run(function() { - env.store.find("superVillain", 1).then(async(function(villain) { + env.store.find('super-villain', 1).then(function(villain) { equal(villain.get('firstName'), "Tom"); equal(villain.get('evilMinions.length'), 1, "Should load the embedded child"); equal(villain.get('evilMinions.firstObject.name'), "Alex", "Should load the embedded child"); - })); - env.store.find("evilMinion", 1).then(async(function(minion) { + }); + env.store.find('evil-minion', 1).then(function(minion) { equal(minion.get('name'), "Alex"); - })); + }); }); }); @@ -200,8 +200,8 @@ test("extractSingle with embedded objects of same type", function() { root: true, children: ["2", "3"] }, "Primary record was correct"); - equal(env.store.recordForId("comment", "2").get("body"), "World", "Secondary records found in the store"); - equal(env.store.recordForId("comment", "3").get("body"), "Foo", "Secondary records found in the store"); + equal(env.store.recordForId('comment', "2").get("body"), "World", "Secondary records found in the store"); + equal(env.store.recordForId('comment', "3").get("body"), "Foo", "Secondary records found in the store"); }); test("extractSingle with embedded objects inside embedded objects of same type", function() { @@ -246,16 +246,16 @@ test("extractSingle with embedded objects inside embedded objects of same type", root: true, children: ["2", "3"] }, "Primary record was correct"); - equal(env.store.recordForId("comment", "2").get("body"), "World", "Secondary records found in the store"); - equal(env.store.recordForId("comment", "3").get("body"), "Foo", "Secondary records found in the store"); - equal(env.store.recordForId("comment", "4").get("body"), "Another", "Secondary records found in the store"); - equal(env.store.recordForId("comment", "2").get("children.length"), 1, "Should have one embedded record"); - equal(env.store.recordForId("comment", "2").get("children.firstObject.body"), "Another", "Should have one embedded record"); + equal(env.store.recordForId('comment', "2").get("body"), "World", "Secondary records found in the store"); + equal(env.store.recordForId('comment', "3").get("body"), "Foo", "Secondary records found in the store"); + equal(env.store.recordForId('comment', "4").get("body"), "Another", "Secondary records found in the store"); + equal(env.store.recordForId('comment', "2").get("children.length"), 1, "Should have one embedded record"); + equal(env.store.recordForId('comment', "2").get("children.firstObject.body"), "Another", "Should have one embedded record"); }); test("extractSingle with embedded objects of same type, but from separate attributes", function() { HomePlanet.reopen({ - reformedVillains: DS.hasMany('superVillain', { inverse: null }) + reformedVillains: DS.hasMany('super-villain', { inverse: null }) }); env.registry.register('adapter:home-planet', DS.ActiveModelAdapter); @@ -299,10 +299,10 @@ test("extractSingle with embedded objects of same type, but from separate attrib reformedVillains: ["2", "4"] }, "Primary hash was correct"); - equal(env.store.recordForId("superVillain", "1").get("firstName"), "Tom", "Secondary records found in the store"); - equal(env.store.recordForId("superVillain", "2").get("firstName"), "Alex", "Secondary records found in the store"); - equal(env.store.recordForId("superVillain", "3").get("firstName"), "Yehuda", "Secondary records found in the store"); - equal(env.store.recordForId("superVillain", "4").get("firstName"), "Erik", "Secondary records found in the store"); + equal(env.store.recordForId('super-villain', "1").get("firstName"), "Tom", "Secondary records found in the store"); + equal(env.store.recordForId('super-villain', "2").get("firstName"), "Alex", "Secondary records found in the store"); + equal(env.store.recordForId('super-villain', "3").get("firstName"), "Yehuda", "Secondary records found in the store"); + equal(env.store.recordForId('super-villain', "4").get("firstName"), "Erik", "Secondary records found in the store"); }); test("extractArray with embedded objects", function() { @@ -339,7 +339,7 @@ test("extractArray with embedded objects", function() { }]); run(function() { - env.store.find("superVillain", 1).then(function(minion) { + env.store.find('super-villain', 1).then(function(minion) { equal(minion.get('firstName'), "Tom"); }); }); @@ -383,8 +383,8 @@ test("extractArray with embedded objects with custom primary key", function() { }]); run(function() { - return env.store.find("superVillain", 1).then(function(minion) { - env.registry.unregister('serializer:super-villain'); + return env.store.find('super-villain', 1).then(function(minion) { + env.registry.unregister('serializer:superVillain'); equal(minion.get('firstName'), "Alex"); }); }); @@ -428,7 +428,7 @@ test("extractArray with embedded objects with identical relationship and attribu }]); run(function() { - env.store.find("superVillain", 1).then(function(minion) { + env.store.find('super-villain', 1).then(function(minion) { equal(minion.get('firstName'), "Alex"); }); }); @@ -473,13 +473,13 @@ test("extractArray with embedded objects of same type as primary type", function children: ["2", "3"] }], "Primary array is correct"); - equal(env.store.recordForId("comment", "2").get("body"), "World", "Secondary record found in the store"); - equal(env.store.recordForId("comment", "3").get("body"), "Foo", "Secondary record found in the store"); + equal(env.store.recordForId('comment', "2").get("body"), "World", "Secondary record found in the store"); + equal(env.store.recordForId('comment', "3").get("body"), "Foo", "Secondary record found in the store"); }); test("extractArray with embedded objects of same type, but from separate attributes", function() { HomePlanet.reopen({ - reformedVillains: DS.hasMany('superVillain') + reformedVillains: DS.hasMany('super-villain') }); env.registry.register('adapter:home-planet', DS.ActiveModelAdapter); @@ -545,18 +545,18 @@ test("extractArray with embedded objects of same type, but from separate attribu reformedVillains: ["5", "6"] }], "Primary array was correct"); - equal(env.store.recordForId("superVillain", "1").get("firstName"), "Tom", "Secondary records found in the store"); - equal(env.store.recordForId("superVillain", "2").get("firstName"), "Alex", "Secondary records found in the store"); - equal(env.store.recordForId("superVillain", "3").get("firstName"), "Yehuda", "Secondary records found in the store"); - equal(env.store.recordForId("superVillain", "4").get("firstName"), "Erik", "Secondary records found in the store"); - equal(env.store.recordForId("superVillain", "5").get("firstName"), "Peter", "Secondary records found in the store"); - equal(env.store.recordForId("superVillain", "6").get("firstName"), "Trek", "Secondary records found in the store"); + equal(env.store.recordForId('super-villain', "1").get("firstName"), "Tom", "Secondary records found in the store"); + equal(env.store.recordForId('super-villain', "2").get("firstName"), "Alex", "Secondary records found in the store"); + equal(env.store.recordForId('super-villain', "3").get("firstName"), "Yehuda", "Secondary records found in the store"); + equal(env.store.recordForId('super-villain', "4").get("firstName"), "Erik", "Secondary records found in the store"); + equal(env.store.recordForId('super-villain', "5").get("firstName"), "Peter", "Secondary records found in the store"); + equal(env.store.recordForId('super-villain', "6").get("firstName"), "Trek", "Secondary records found in the store"); }); test("serialize supports serialize:false on non-relationship properties", function() { var tom; run(function() { - tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", id: '1' }); + tom = env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", id: '1' }); }); env.registry.register('serializer:super-villain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { @@ -580,8 +580,8 @@ test("serialize supports serialize:false on non-relationship properties", functi test("serialize with embedded objects (hasMany relationship)", function() { var tom, league; run(function() { - league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); - tom = env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); + league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); + tom = env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); }); env.registry.register('serializer:home-planet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { @@ -611,8 +611,8 @@ test("serialize with embedded objects (hasMany relationship)", function() { test("serialize with embedded objects (hasMany relationship) supports serialize:false", function() { run(function() { - league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); - env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); + league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); + env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); }); env.registry.register('serializer:home-planet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { @@ -634,8 +634,8 @@ test("serialize with embedded objects (hasMany relationship) supports serialize: test("serialize with (new) embedded objects (hasMany relationship)", function() { run(function() { - league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); - env.store.createRecord(SuperVillain, { firstName: "Tom", lastName: "Dale", homePlanet: league }); + league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); + env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league }); }); env.registry.register('serializer:home-planet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { @@ -662,9 +662,9 @@ test("serialize with (new) embedded objects (hasMany relationship)", function() test("serialize with embedded objects (hasMany relationships, including related objects not embedded)", function() { run(function() { - superVillain = env.store.createRecord(SuperVillain, { id: 1, firstName: "Super", lastName: "Villian" }); - evilMinion = env.store.createRecord(EvilMinion, { id: 1, name: "Evil Minion", superVillian: superVillain }); - secretWeapon = env.store.createRecord(SecretWeapon, { id: 1, name: "Secret Weapon", superVillain: superVillain }); + superVillain = env.store.createRecord('super-villain', { id: 1, firstName: "Super", lastName: "Villian" }); + evilMinion = env.store.createRecord('evil-minion', { id: 1, name: "Evil Minion", superVillian: superVillain }); + secretWeapon = env.store.createRecord('secret-weapon', { id: 1, name: "Secret Weapon", superVillain: superVillain }); superVillain.get('evilMinions').pushObject(evilMinion); superVillain.get('secretWeapons').pushObject(secretWeapon); }); @@ -738,7 +738,7 @@ test("extractSingle with embedded object (belongsTo relationship)", function() { }); run(function() { - env.store.find("secretLab", 101).then(function(secretLab) { + env.store.find('secret-lab', 101).then(function(secretLab) { equal(secretLab.get('id'), '101'); equal(secretLab.get('minionCapacity'), 5000); equal(secretLab.get('vicinity'), 'California, USA'); @@ -760,10 +760,10 @@ test("serialize with embedded object (belongsTo relationship)", function() { // records with an id, persisted tom = env.store.createRecord( - SuperVillain, + 'super-villain', { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) } ); }); @@ -803,7 +803,7 @@ test("serialize with embedded object (belongsTo relationship) works with differe run(function() { tom = env.store.createRecord( - SuperVillain, + 'super-villain', { firstName: "Tom", lastName: "Dale", id: "1", secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) @@ -842,10 +842,10 @@ test("serialize with embedded object (belongsTo relationship, new no id)", funct run(function() { tom = env.store.createRecord( - SuperVillain, + 'super-villain', { firstName: "Tom", lastName: "Dale", - secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA" }), - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) } ); }); @@ -879,10 +879,10 @@ test("serialize with embedded object (belongsTo relationship) supports serialize run(function() { tom = env.store.createRecord( - SuperVillain, + 'super-villain', { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) } ); }); @@ -914,10 +914,10 @@ test("serialize with embedded object (belongsTo relationship) supports serialize run(function() { tom = env.store.createRecord( - SuperVillain, + 'super-villain', { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) } ); }); @@ -949,10 +949,10 @@ test("serialize with embedded object (belongsTo relationship) supports serialize run(function() { tom = env.store.createRecord( - SuperVillain, + 'super-villain', { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secretLab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('homePlanet', { name: "Villain League", id: "123" }) + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) } ); }); @@ -982,10 +982,10 @@ test("serialize with embedded object (belongsTo relationship) supports serialize var tom, json; run(function() { tom = env.store.createRecord( - SuperVillain, + 'super-villain', { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) } ); }); @@ -1012,10 +1012,10 @@ test("serialize with embedded object (belongsTo relationship) serializes the id run(function() { tom = env.store.createRecord( - SuperVillain, + 'super-villain', { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) } ); }); @@ -1044,9 +1044,9 @@ test("when related record is not present, serialize embedded record (with a belo run(function() { tom = env.store.createRecord( - SuperVillain, + 'super-villain', { firstName: "Tom", lastName: "Dale", id: "1", - homePlanet: env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }) + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) } ); }); @@ -1106,13 +1106,13 @@ test("extractSingle with multiply-nested belongsTo", function() { superVillain: "1" }, "Primary hash was correct"); - equal(env.store.recordForId("superVillain", "1").get("firstName"), "Tom", "Secondary record, Tom, found in the steore"); - equal(env.store.recordForId("homePlanet", "1").get("name"), "Umber", "Nested Secondary record, Umber, found in the store"); + equal(env.store.recordForId('super-villain', "1").get("firstName"), "Tom", "Secondary record, Tom, found in the steore"); + equal(env.store.recordForId('home-planet', "1").get("name"), "Umber", "Nested Secondary record, Umber, found in the store"); }); test("extractSingle with polymorphic hasMany", function() { SuperVillain.reopen({ - secretWeapons: DS.hasMany("secretWeapon", { polymorphic: true }) + secretWeapons: DS.hasMany('secret-weapon', { polymorphic: true }) }); env.registry.register('adapter:super-villain', DS.ActiveModelAdapter); @@ -1159,8 +1159,8 @@ test("extractSingle with polymorphic hasMany", function() { ] }, "Primary hash was correct"); - equal(env.store.recordForId("secretWeapon", "1").get("name"), "The Death Star", "Embedded polymorphic SecretWeapon found"); - equal(env.store.recordForId("lightSaber", "1").get("name"), "Tom's LightSaber", "Embedded polymorphic LightSaber found"); + equal(env.store.recordForId('secret-weapon', "1").get("name"), "The Death Star", "Embedded polymorphic SecretWeapon found"); + equal(env.store.recordForId('light-saber', "1").get("name"), "Tom's LightSaber", "Embedded polymorphic LightSaber found"); }); @@ -1169,7 +1169,7 @@ test("extractSingle with polymorphic belongsTo", function() { expect(2); SuperVillain.reopen({ - secretLab: DS.belongsTo("secretLab", { polymorphic: true }) + secretLab: DS.belongsTo('secret-lab', { polymorphic: true }) }); env.registry.register('adapter:super-villain', DS.ActiveModelAdapter); @@ -1207,20 +1207,20 @@ test("extractSingle with polymorphic belongsTo", function() { secretLabType: "bat-cave" }, "Primary has was correct"); - equal(env.store.recordForId("batCave", "1").get("infiltrated"), true, "Embedded polymorphic BatCave was found"); + equal(env.store.recordForId('bat-cave', "1").get("infiltrated"), true, "Embedded polymorphic BatCave was found"); }); test("Mixin can be used with RESTSerializer which does not define keyForAttribute", function() { run(function() { - homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); - secretLab = env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); - superVillain = env.store.createRecord(SuperVillain, { + homePlanet = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); + secretLab = env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); + superVillain = env.store.createRecord('super-villain', { id: "1", firstName: "Super", lastName: "Villian", homePlanet: homePlanet, secretLab: secretLab }); - secretWeapon = env.store.createRecord(SecretWeapon, { id: "1", name: "Secret Weapon", superVillain: superVillain }); + secretWeapon = env.store.createRecord('secret-weapon', { id: "1", name: "Secret Weapon", superVillain: superVillain }); superVillain.get('secretWeapons').pushObject(secretWeapon); - evilMinion = env.store.createRecord(EvilMinion, { id: "1", name: "Evil Minion", superVillian: superVillain }); + evilMinion = env.store.createRecord('evil-minion', { id: "1", name: "Evil Minion", superVillian: superVillain }); superVillain.get('evilMinions').pushObject(evilMinion); }); @@ -1288,19 +1288,19 @@ test("normalize with custom belongsTo primary key", function() { superVillain: "1" }, "Primary hash was correct"); - equal(env.store.recordForId("superVillain", "1").get("firstName"), "Tom", "Secondary record, Tom, found in the steore"); + equal(env.store.recordForId('super-villain', "1").get("firstName"), "Tom", "Secondary record, Tom, found in the steore"); }); test("serializing relationships with an embedded and without calls super when not attr not present", function() { run(function() { - homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); - secretLab = env.store.createRecord(SecretLab, { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); - superVillain = env.store.createRecord(SuperVillain, { + homePlanet = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); + secretLab = env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); + superVillain = env.store.createRecord('super-villain', { id: "1", firstName: "Super", lastName: "Villian", homePlanet: homePlanet, secretLab: secretLab }); - secretWeapon = env.store.createRecord(SecretWeapon, { id: "1", name: "Secret Weapon", superVillain: superVillain }); + secretWeapon = env.store.createRecord('secret-weapon', { id: "1", name: "Secret Weapon", superVillain: superVillain }); superVillain.get('secretWeapons').pushObject(secretWeapon); - evilMinion = env.store.createRecord(EvilMinion, { id: "1", name: "Evil Minion", superVillian: superVillain }); + evilMinion = env.store.createRecord('evil-minion', { id: "1", name: "Evil Minion", superVillian: superVillain }); superVillain.get('evilMinions').pushObject(evilMinion); }); diff --git a/packages/ember-data/tests/integration/serializers/json-serializer-test.js b/packages/ember-data/tests/integration/serializers/json-serializer-test.js index d9be2147f05..be5c04ee057 100644 --- a/packages/ember-data/tests/integration/serializers/json-serializer-test.js +++ b/packages/ember-data/tests/integration/serializers/json-serializer-test.js @@ -31,7 +31,7 @@ module("integration/serializer/json - JSONSerializer", { test("serializeAttribute", function() { run(function() { - post = env.store.createRecord("post", { title: "Rails is omakase" }); + post = env.store.createRecord('post', { title: "Rails is omakase" }); }); var json = {}; @@ -50,7 +50,7 @@ test("serializeAttribute respects keyForAttribute", function() { })); run(function() { - post = env.store.createRecord("post", { title: "Rails is omakase" }); + post = env.store.createRecord('post', { title: "Rails is omakase" }); }); var json = {}; @@ -61,8 +61,8 @@ test("serializeAttribute respects keyForAttribute", function() { test("serializeBelongsTo", function() { run(function() { - post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1" }); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post }); + post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); + comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); }); var json = {}; @@ -74,7 +74,7 @@ test("serializeBelongsTo", function() { test("serializeBelongsTo with null", function() { run(function() { - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: null }); + comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: null }); }); var json = {}; @@ -90,7 +90,7 @@ test("async serializeBelongsTo with null", function() { post: DS.belongsTo('post', { async: true }) }); run(function() { - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: null }); + comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: null }); }); var json = {}; @@ -108,8 +108,8 @@ test("serializeBelongsTo respects keyForRelationship", function() { } })); run(function() { - post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1" }); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post }); + post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); + comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); }); var json = {}; @@ -128,8 +128,8 @@ test("serializeHasMany respects keyForRelationship", function() { })); run(function() { - post = env.store.createRecord(Post, { title: "Rails is omakase", id: "1" }); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post, id: "1" }); + post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); + comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post, id: "1" }); }); var json = {}; @@ -143,7 +143,7 @@ test("serializeHasMany respects keyForRelationship", function() { test("serializeIntoHash", function() { run(function() { - post = env.store.createRecord("post", { title: "Rails is omakase" }); + post = env.store.createRecord('post', { title: "Rails is omakase" }); }); var json = {}; @@ -191,8 +191,8 @@ test("serializePolymorphicType async", function() { })); run(function() { - post = env.store.createRecord(Post, { title: 'Rails is omakase', id: 1 }); - comment = env.store.createRecord(Comment, { body: 'Omakase is delicious', post: post }); + post = env.store.createRecord('post', { title: 'Rails is omakase', id: 1 }); + comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); }); env.container.lookup('serializer:comment').serializeBelongsTo(comment._createSnapshot(), {}, { key: 'post', options: { async: true, polymorphic: true } }); @@ -250,8 +250,8 @@ test('Serializer should respect the attrs hash when serializing records', functi var parentPost; run(function() { - parentPost = env.store.push("post", { id: 2, title: "Rails is omakase" }); - post = env.store.createRecord("post", { title: "Rails is omakase", parentPost: parentPost }); + parentPost = env.store.push('post', { id: 2, title: "Rails is omakase" }); + post = env.store.createRecord('post', { title: "Rails is omakase", parentPost: parentPost }); }); var payload = env.container.lookup("serializer:post").serialize(post._createSnapshot()); @@ -269,7 +269,7 @@ test('Serializer respects `serialize: false` on the attrs hash', function() { })); run(function() { - post = env.store.createRecord("post", { title: "Rails is omakase" }); + post = env.store.createRecord('post', { title: "Rails is omakase" }); }); var payload = env.container.lookup("serializer:post").serialize(post._createSnapshot()); @@ -287,8 +287,8 @@ test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` p })); run(function() { - post = env.store.createRecord("post", { title: "Rails is omakase" }); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post }); + post = env.store.createRecord('post', { title: "Rails is omakase" }); + comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); }); var serializer = env.container.lookup("serializer:post"); @@ -307,8 +307,8 @@ test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` })); run(function() { - post = env.store.createRecord("post", { title: "Rails is omakase" }); - comment = env.store.createRecord(Comment, { body: "Omakase is delicious", post: post }); + post = env.store.createRecord('post', { title: "Rails is omakase" }); + comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); }); var serializer = env.container.lookup("serializer:comment"); @@ -370,7 +370,7 @@ test("Serializer should respect the primaryKey attribute when serializing record })); run(function() { - post = env.store.createRecord("post", { id: "1", title: "Rails is omakase" }); + post = env.store.createRecord('post', { id: "1", title: "Rails is omakase" }); }); var payload = env.container.lookup("serializer:post").serialize(post._createSnapshot(), { includeId: true }); @@ -477,8 +477,8 @@ test('serializeBelongsTo with async polymorphic', function() { })); run(function() { - post = env.store.createRecord(Post, { title: 'Kitties are omakase', id: '1' }); - favorite = env.store.createRecord(Favorite, { post: post, id: '3' }); + post = env.store.createRecord('post', { title: 'Kitties are omakase', id: '1' }); + favorite = env.store.createRecord('favorite', { post: post, id: '3' }); }); env.container.lookup('serializer:favorite').serializeBelongsTo(favorite._createSnapshot(), json, { key: 'post', options: { polymorphic: true, async: true } }); diff --git a/packages/ember-data/tests/integration/serializers/rest-serializer-test.js b/packages/ember-data/tests/integration/serializers/rest-serializer-test.js index 7efe5f88a2a..c2e1f746a79 100644 --- a/packages/ember-data/tests/integration/serializers/rest-serializer-test.js +++ b/packages/ember-data/tests/integration/serializers/rest-serializer-test.js @@ -6,22 +6,22 @@ module("integration/serializer/rest - RESTSerializer", { setup: function() { HomePlanet = DS.Model.extend({ name: DS.attr('string'), - superVillains: DS.hasMany('superVillain') + superVillains: DS.hasMany('super-villain') }); SuperVillain = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), - homePlanet: DS.belongsTo("homePlanet"), - evilMinions: DS.hasMany("evilMinion") + homePlanet: DS.belongsTo('home-planet'), + evilMinions: DS.hasMany('evil-minion') }); EvilMinion = DS.Model.extend({ - superVillain: DS.belongsTo('superVillain'), + superVillain: DS.belongsTo('super-villain'), name: DS.attr('string') }); YellowMinion = EvilMinion.extend(); DoomsdayDevice = DS.Model.extend({ name: DS.attr('string'), - evilMinion: DS.belongsTo('evilMinion', { polymorphic: true }) + evilMinion: DS.belongsTo('evil-minion', { polymorphic: true }) }); Comment = DS.Model.extend({ body: DS.attr('string'), @@ -36,11 +36,11 @@ module("integration/serializer/rest - RESTSerializer", { doomsdayDevice: DoomsdayDevice, comment: Comment }); - env.store.modelFor('superVillain'); - env.store.modelFor('homePlanet'); - env.store.modelFor('evilMinion'); - env.store.modelFor('yellowMinion'); - env.store.modelFor('doomsdayDevice'); + env.store.modelFor('super-villain'); + env.store.modelFor('home-planet'); + env.store.modelFor('evil-minion'); + env.store.modelFor('yellow-minion'); + env.store.modelFor('doomsday-device'); env.store.modelFor('comment'); }, @@ -80,7 +80,7 @@ test("extractArray with custom modelNameFromPayloadKey", function() { }]); run(function() { - env.store.find("superVillain", 1).then(function(minion) { + env.store.find('super-villain', 1).then(function(minion) { equal(minion.get('firstName'), "Tom"); }); }); @@ -179,18 +179,18 @@ test("pushPayload - single record payload - warning with custom modelNameFromPay warns(function() { run(function() { - env.store.pushPayload("homePlanet", jsonHash); + env.store.pushPayload('home-planet', jsonHash); }); }, /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); // assert non-warned records get pushed into store correctly - var superVillain = env.store.getById("superVillain", "1"); + var superVillain = env.store.getById('super-villain', "1"); equal(get(superVillain, "firstName"), "Stanley"); // Serializers are singletons, so that"s why we use the store which // looks at the container to look it up - env.store.serializerFor("homePlanet").reopen({ + env.store.serializerFor('home-planet').reopen({ modelNameFromPayloadKey: function(root) { // should not warn if a model is found. return Ember.String.camelize(Ember.String.singularize(root)); @@ -204,8 +204,8 @@ test("pushPayload - single record payload - warning with custom modelNameFromPay noWarns(function() { run(function() { - env.store.pushPayload("homePlanet", jsonHash); - homePlanet = env.store.getById("homePlanet", "1"); + env.store.pushPayload('home-planet', jsonHash); + homePlanet = env.store.getById('home-planet', "1"); }); }); @@ -235,17 +235,17 @@ test("pushPayload - multiple record payload (extractArray) - warning with custom warns(function() { run(function() { - env.store.pushPayload("homePlanet", jsonHash); + env.store.pushPayload('home-planet', jsonHash); }); }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); // assert non-warned records get pushed into store correctly - var superVillain = env.store.getById("superVillain", "1"); + var superVillain = env.store.getById('super-villain', "1"); equal(get(superVillain, "firstName"), "Stanley"); // Serializers are singletons, so that"s why we use the store which // looks at the container to look it up - env.store.serializerFor("homePlanet").reopen({ + env.store.serializerFor('home-planet').reopen({ modelNameFromPayloadKey: function(root) { // should not warn if a model is found. return Ember.String.camelize(Ember.String.singularize(root)); @@ -259,8 +259,8 @@ test("pushPayload - multiple record payload (extractArray) - warning with custom noWarns(function() { run(function() { - env.store.pushPayload("homePlanet", jsonHash); - homePlanet = env.store.getById("homePlanet", "1"); + env.store.pushPayload('home-planet', jsonHash); + homePlanet = env.store.getById('home-planet', "1"); }); }); @@ -271,8 +271,8 @@ test("pushPayload - multiple record payload (extractArray) - warning with custom test("serialize polymorphicType", function() { var tom, ray; run(function() { - tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); - ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); + tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); + ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: "DeathRay" }); }); var json = env.restSerializer.serialize(ray._createSnapshot()); @@ -288,8 +288,8 @@ test("serialize polymorphicType with decamelized modelName", function() { YellowMinion.modelName = 'yellow-minion'; var tom, ray; run(function() { - tom = env.store.createRecord(YellowMinion, { name: "Alex", id: "124" }); - ray = env.store.createRecord(DoomsdayDevice, { evilMinion: tom, name: "DeathRay" }); + tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); + ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: "DeathRay" }); }); var json = env.restSerializer.serialize(ray._createSnapshot()); @@ -324,7 +324,7 @@ test("normalizePayload is called during extractSingle", function() { test("serialize polymorphic when associated object is null", function() { var ray; run(function() { - ray = env.store.createRecord(DoomsdayDevice, { name: "DeathRay" }); + ray = env.store.createRecord('doomsday-device', { name: "DeathRay" }); }); var json = env.restSerializer.serialize(ray._createSnapshot()); @@ -355,8 +355,8 @@ test("extractArray can load secondary records of the same type without affecting equal(array.length, 1, "The query count is unaffected"); - equal(env.store.recordForId("comment", "2").get("body"), "Child Comment 1", "Secondary records are in the store"); - equal(env.store.recordForId("comment", "3").get("body"), "Child Comment 2", "Secondary records are in the store"); + equal(env.store.recordForId('comment', "2").get("body"), "Child Comment 1", "Secondary records are in the store"); + equal(env.store.recordForId('comment', "3").get("body"), "Child Comment 2", "Secondary records are in the store"); }); test("extractSingle loads secondary records with correct serializer", function() { @@ -511,7 +511,7 @@ test('normalize should allow for different levels of normalization', function() test("serializeIntoHash", function() { run(function() { - league = env.store.createRecord(HomePlanet, { name: "Umber", id: "123" }); + league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); }); var json = {}; @@ -527,7 +527,7 @@ test("serializeIntoHash", function() { test("serializeIntoHash with decamelized modelName", function() { HomePlanet.modelName = 'home-planet'; run(function() { - league = env.store.createRecord(HomePlanet, { name: "Umber", id: "123" }); + league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); }); var json = {}; @@ -546,8 +546,8 @@ test('serializeBelongsTo with async polymorphic', function() { var expected = { evilMinion: '1', evilMinionType: 'evilMinion' }; run(function() { - evilMinion = env.store.createRecord('evilMinion', { id: 1, name: 'Tomster' }); - doomsdayDevice = env.store.createRecord('doomsdayDevice', { id: 2, name: 'Yehuda', evilMinion: evilMinion }); + evilMinion = env.store.createRecord('evil-minion', { id: 1, name: 'Tomster' }); + doomsdayDevice = env.store.createRecord('doomsday-device', { id: 2, name: 'Yehuda', evilMinion: evilMinion }); }); env.restSerializer.serializeBelongsTo(doomsdayDevice._createSnapshot(), json, { key: 'evilMinion', options: { polymorphic: true, async: true } }); @@ -557,7 +557,7 @@ test('serializeBelongsTo with async polymorphic', function() { test('serializeIntoHash uses payloadKeyFromModelName to normalize the payload root key', function() { run(function() { - league = env.store.createRecord(HomePlanet, { name: "Umber", id: "123" }); + league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); }); var json = {}; env.registry.register('serializer:home-planet', DS.RESTSerializer.extend({ diff --git a/packages/ember-data/tests/integration/store-test.js b/packages/ember-data/tests/integration/store-test.js index 854f2939afa..708a25b9c1c 100644 --- a/packages/ember-data/tests/integration/store-test.js +++ b/packages/ember-data/tests/integration/store-test.js @@ -57,7 +57,7 @@ asyncTest("destroying record during find doesn't cause error", function() { find: function(store, type, id, snapshot) { return new Ember.RSVP.Promise(function(resolve, reject) { Ember.run.next(function() { - store.unloadAll(type); + store.unloadAll(type.modelName); reject(); }); }); diff --git a/packages/ember-data/tests/unit/adapter-populated-record-array-test.js b/packages/ember-data/tests/unit/adapter-populated-record-array-test.js index 9de3a89ea5b..74a1a9c6652 100644 --- a/packages/ember-data/tests/unit/adapter-populated-record-array-test.js +++ b/packages/ember-data/tests/unit/adapter-populated-record-array-test.js @@ -9,24 +9,24 @@ var adapter = DS.Adapter.extend({ module("unit/adapter_populated_record_array - DS.AdapterPopulatedRecordArray", { setup: function() { + Person = DS.Model.extend({ + name: DS.attr('string') + }); store = createStore({ - adapter: adapter + adapter: adapter, + person: Person }); - array = [{ id: '1', name: "Scumbag Dale" }, { id: '2', name: "Scumbag Katz" }, { id: '3', name: "Scumbag Bryn" }]; - Person = DS.Model.extend({ - name: DS.attr('string') - }); } }); test("when a record is deleted in an adapter populated record array, it should be removed", function() { var recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray(Person, null); + .createAdapterPopulatedRecordArray(store.modelFor('person'), null); run(function() { recordArray.load(array); diff --git a/packages/ember-data/tests/unit/debug-test.js b/packages/ember-data/tests/unit/debug-test.js index f4906b99460..95589a6d696 100644 --- a/packages/ember-data/tests/unit/debug-test.js +++ b/packages/ember-data/tests/unit/debug-test.js @@ -16,7 +16,7 @@ test("_debugInfo groups the attributes and relationships correctly", function() var User = DS.Model.extend({ name: DS.attr('string'), isDrugAddict: DS.attr('boolean'), - maritalStatus: DS.belongsTo('maritalStatus'), + maritalStatus: DS.belongsTo('marital-status'), posts: DS.hasMany('post') }); @@ -29,7 +29,7 @@ test("_debugInfo groups the attributes and relationships correctly", function() var record; run(function() { - record = store.createRecord(User); + record = store.createRecord('user'); }); var propertyInfo = record._debugInfo().propertyInfo; diff --git a/packages/ember-data/tests/unit/model-test.js b/packages/ember-data/tests/unit/model-test.js index d6b76fa0ccf..8063ea1dde8 100644 --- a/packages/ember-data/tests/unit/model-test.js +++ b/packages/ember-data/tests/unit/model-test.js @@ -2,16 +2,19 @@ var get = Ember.get; var set = Ember.set; var run = Ember.run; -var Person, store, array; +var Person, store, array, env; module("unit/model - DS.Model", { setup: function() { - store = createStore(); - Person = DS.Model.extend({ name: DS.attr('string'), isDrugAddict: DS.attr('boolean') }); + + env = setupStore({ + person: Person + }); + store = env.store; }, teardown: function() { @@ -26,7 +29,7 @@ module("unit/model - DS.Model", { test("can have a property set on it", function() { var record; run(function() { - record = store.createRecord(Person); + record = store.createRecord('person'); set(record, 'name', 'bar'); }); @@ -37,8 +40,8 @@ test("setting a property on a record that has not changed does not cause it to b expect(2); run(function() { - store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); - store.find(Person, 1).then(function(person) { + store.push('person', { id: 1, name: "Peter", isDrugAddict: true }); + store.find('person', 1).then(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); person.set('name', "Peter"); @@ -53,8 +56,8 @@ test("resetting a property on a record cause it to become clean again", function expect(3); run(function() { - store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); - store.find(Person, 1).then(function(person) { + store.push('person', { id: 1, name: "Peter", isDrugAddict: true }); + store.find('person', 1).then(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); person.set('isDrugAddict', false); equal(person.get('isDirty'), true, "record becomes dirty after setting property to a new value"); @@ -68,8 +71,8 @@ test("a record becomes clean again only if all changed properties are reset", fu expect(5); run(function() { - store.push(Person, { id: 1, name: "Peter", isDrugAddict: true }); - store.find(Person, 1).then(function(person) { + store.push('person', { id: 1, name: "Peter", isDrugAddict: true }); + store.find('person', 1).then(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); person.set('isDrugAddict', false); equal(person.get('isDirty'), true, "record becomes dirty after setting one property to a new value"); @@ -87,8 +90,8 @@ test("a record reports its unique id via the `id` property", function() { expect(1); run(function() { - store.push(Person, { id: 1 }); - store.find(Person, 1).then(function(record) { + store.push('person', { id: 1 }); + store.find('person', 1).then(function(record) { equal(get(record, 'id'), 1, "reports id as id by default"); }); }); @@ -98,8 +101,8 @@ test("a record's id is included in its toString representation", function() { expect(1); run(function() { - store.push(Person, { id: 1 }); - store.find(Person, 1).then(function(record) { + store.push('person', { id: 1 }); + store.find('person', 1).then(function(record) { equal(record.toString(), '<(subclass of DS.Model):'+Ember.guidFor(record)+':1>', "reports id in toString"); }); }); @@ -111,10 +114,14 @@ test("trying to set an `id` attribute should raise", function() { name: DS.attr('string') }); + var store = createStore({ + person: Person + }); + expectAssertion(function() { run(function() { - store.push(Person, { id: 1, name: "Scumdale" }); - store.find(Person, 1); + store.push('person', { id: 1, name: "Scumdale" }); + store.find('person', 1); }); }, /You may not set `id`/); }); @@ -128,8 +135,8 @@ test("a collision of a record's id with object function's name", function() { Object.prototype.watch = function() {}; } run(function() { - store.push(Person, { id: 'watch' }); - store.find(Person, 'watch').then(function(record) { + store.push('person', { id: 'watch' }); + store.find('person', 'watch').then(function(record) { equal(get(record, 'id'), 'watch', "record is successfully created and could be found by its id"); }); }); @@ -144,9 +151,9 @@ test("it should use `_reference` and not `reference` to store its reference", fu expect(1); run(function() { - store.push(Person, { id: 1 }); + store.push('person', { id: 1 }); - store.find(Person, 1).then(function(record) { + store.find('person', 1).then(function(record) { equal(record.get('reference'), undefined, "doesn't shadow reference key"); }); }); @@ -155,18 +162,20 @@ test("it should use `_reference` and not `reference` to store its reference", fu test("it should cache attributes", function() { expect(2); - var store = createStore(); - var Post = DS.Model.extend({ updatedAt: DS.attr('string') }); + var store = createStore({ + post: Post + }); + var dateString = "Sat, 31 Dec 2011 00:08:16 GMT"; var date = new Date(dateString); run(function() { - store.push(Post, { id: 1 }); - store.find(Post, 1).then(function(record) { + store.push('post', { id: 1 }); + store.find('post', 1).then(function(record) { run(function() { record.set('updatedAt', date); }); @@ -187,11 +196,16 @@ test("changedAttributes() return correct values", function() { likes: DS.attr('string'), isMascot: DS.attr('boolean') }); + + var store = createStore({ + mascot: Mascot + }); + var mascot; run(function() { - mascot = store.push(Mascot, { id: 1, likes: 'JavaScript', isMascot: true }); + mascot = store.push('mascot', { id: 1, likes: 'JavaScript', isMascot: true }); }); deepEqual({}, mascot.changedAttributes(), 'there are no initial changes'); @@ -212,10 +226,15 @@ test("a DS.Model does not require an attribute type", function() { var Tag = DS.Model.extend({ name: DS.attr() }); + + var store = createStore({ + tag: Tag + }); + var tag; run(function() { - tag = store.createRecord(Tag, { name: "test" }); + tag = store.createRecord('tag', { name: "test" }); }); equal(get(tag, 'name'), "test", "the value is persisted"); @@ -225,10 +244,14 @@ test("a DS.Model can have a defaultValue without an attribute type", function() var Tag = DS.Model.extend({ name: DS.attr({ defaultValue: "unknown" }) }); + + var store = createStore({ + tag: Tag + }); var tag; run(function() { - tag = store.createRecord(Tag); + tag = store.createRecord('tag'); }); equal(get(tag, 'name'), "unknown", "the default value is found"); @@ -241,7 +264,9 @@ test("Calling attr(), belongsTo() or hasMany() throws a warning", function() { name: DS.attr('string') }); - var store = createStore({ person: Person }); + var store = createStore({ + person: Person + }); run(function() { var person = store.createRecord('person', { id: 1, name: 'TomHuda' }); @@ -264,9 +289,9 @@ test("supports pushedData in root.deleted.uncommitted", function() { var record; var hash = { id: 1 }; run(function() { - record = store.push(Person, hash); + record = store.push('person', hash); record.deleteRecord(); - store.push(Person, hash); + store.push('person', hash); equal(get(record, 'currentState.stateName'), 'root.deleted.uncommitted', 'record accepts pushedData is in root.deleted.uncommitted state'); }); @@ -277,9 +302,12 @@ module("unit/model - DS.Model updating", { setup: function() { array = [{ id: 1, name: "Scumbag Dale" }, { id: 2, name: "Scumbag Katz" }, { id: 3, name: "Scumbag Bryn" }]; Person = DS.Model.extend({ name: DS.attr('string') }); - store = createStore(); + env = setupStore({ + person: Person + }); + store = env.store; run(function() { - store.pushMany(Person, array); + store.pushMany('person', array); }); }, teardown: function() { @@ -296,7 +324,7 @@ test("a DS.Model can update its attributes", function() { expect(1); run(function() { - store.find(Person, 2).then(function(person) { + store.find('person', 2).then(function(person) { set(person, 'name', "Brohuda Katz"); equal(get(person, 'name'), "Brohuda Katz", "setting took hold"); }); @@ -309,8 +337,12 @@ test("a DS.Model can have a defaultValue", function() { }); var tag; + var store = createStore({ + tag: Tag + }); + run(function() { - tag = store.createRecord(Tag); + tag = store.createRecord('tag'); }); equal(get(tag, 'name'), "unknown", "the default value is found"); @@ -334,8 +366,12 @@ test("a DS.model can define 'setUnknownProperty'", function() { } }); + var store = createStore({ + tag: Tag + }); + run(function() { - tag = store.createRecord(Tag, { name: "old" }); + tag = store.createRecord('tag', { name: "old" }); set(tag, "title", "new"); }); @@ -352,8 +388,12 @@ test("a defaultValue for an attribute can be a function", function() { }); var tag; + var store = createStore({ + tag: Tag + }); + run(function() { - tag = store.createRecord(Tag); + tag = store.createRecord('tag'); }); equal(get(tag, 'createdAt'), "le default value", "the defaultValue function is evaluated"); }); @@ -370,10 +410,14 @@ test("a defaultValue function gets the record, options, and key", function() { } }) }); + + var store = createStore({ + tag: Tag + }); var tag; run(function() { - tag = store.createRecord(Tag); + tag = store.createRecord('tag'); }); get(tag, 'createdAt'); @@ -383,10 +427,15 @@ test("setting a property to undefined on a newly created record should not impac var Tag = DS.Model.extend({ name: DS.attr('string') }); + + var store = createStore({ + tag: Tag + }); + var tag; run(function() { - tag = store.createRecord(Tag); + tag = store.createRecord('tag'); set(tag, 'name', 'testing'); set(tag, 'name', undefined); }); @@ -394,7 +443,7 @@ test("setting a property to undefined on a newly created record should not impac equal(get(tag, 'currentState.stateName'), "root.loaded.created.uncommitted"); run(function() { - tag = store.createRecord(Tag, { name: undefined }); + tag = store.createRecord('tag', { name: undefined }); }); equal(get(tag, 'currentState.stateName'), "root.loaded.created.uncommitted"); @@ -406,7 +455,7 @@ test("setting a property back to its original value removes the property from th expect(3); run(function() { - store.find(Person, 1).then(function(person) { + store.find('person', 1).then(function(person) { equal(person._attributes.name, undefined, "the `_attributes` hash is clean"); set(person, 'name', "Niceguy Dale"); @@ -434,7 +483,7 @@ module("unit/model - with a simple Person model", { person: Person }); run(function() { - store.pushMany(Person, array); + store.pushMany('person', array); }); }, teardown: function() { @@ -448,9 +497,9 @@ module("unit/model - with a simple Person model", { }); test("can ask if record with a given id is loaded", function() { - equal(store.recordIsLoaded(Person, 1), true, 'should have person with id 1'); equal(store.recordIsLoaded('person', 1), true, 'should have person with id 1'); - equal(store.recordIsLoaded(Person, 4), false, 'should not have person with id 4'); + equal(store.recordIsLoaded('person', 1), true, 'should have person with id 1'); + equal(store.recordIsLoaded('person', 4), false, 'should not have person with id 4'); equal(store.recordIsLoaded('person', 4), false, 'should not have person with id 4'); }); @@ -460,7 +509,7 @@ test("a listener can be added to a record", function() { var record; run(function() { - record = store.createRecord(Person); + record = store.createRecord('person'); }); record.on('event!', F); @@ -483,7 +532,7 @@ test("when an event is triggered on a record the method with the same name is in var record; run(function() { - record = store.createRecord(Person); + record = store.createRecord('person'); }); record.eventNamedMethod = F; @@ -503,7 +552,7 @@ test("when a method is invoked from an event with the same name the arguments ar var record; run(function() { - record = store.createRecord(Person); + record = store.createRecord('person'); }); record.eventThatTriggersMethod = F; @@ -536,8 +585,8 @@ var converts = function(type, provided, expected) { }); run(function() { - testStore.push(Model, serializer.normalize(Model, { id: 1, name: provided })); - testStore.push(Model, serializer.normalize(Model, { id: 2 })); + testStore.push('model', serializer.normalize(Model, { id: 1, name: provided })); + testStore.push('model', serializer.normalize(Model, { id: 2 })); testStore.find('model', 1).then(function(record) { deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); }); @@ -569,7 +618,7 @@ var convertsFromServer = function(type, provided, expected) { }); run(function() { - testStore.push(Model, serializer.normalize(Model, { id: "1", name: provided })); + testStore.push('model', serializer.normalize(Model, { id: "1", name: provided })); testStore.find('model', 1).then(function(record) { deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); }); @@ -584,7 +633,7 @@ var convertsWhenSet = function(type, provided, expected) { var testStore = createStore({ model: Model }); run(function() { - testStore.push(Model, { id: 2 }); + testStore.push('model', { id: 2 }); testStore.find('model', 2).then(function(record) { set(record, 'name', provided); deepEqual(record.serialize().name, expected, type + " saves " + provided + " as " + expected); @@ -638,15 +687,18 @@ test("a DS.Model can describe Date attributes", function() { var dateString = "2011-12-31T00:08:16.000Z"; var date = new Date(Ember.Date.parse(dateString)); - var store = createStore(); var Person = DS.Model.extend({ updatedAt: DS.attr('date') }); + var store = createStore({ + person: Person + }); + run(function() { - store.push(Person, { id: 1 }); - store.find(Person, 1).then(function(record) { + store.push('person', { id: 1 }); + store.find('person', 1).then(function(record) { run(function() { record.set('updatedAt', date); }); @@ -658,13 +710,15 @@ test("a DS.Model can describe Date attributes", function() { }); test("don't allow setting", function() { - var store = createStore(); - var Person = DS.Model.extend(); var record; + var store = createStore({ + person: Person + }); + run(function() { - record = store.createRecord(Person); + record = store.createRecord('person'); }); raises(function() { @@ -682,11 +736,12 @@ test("ensure model exits loading state, materializes data and fulfills promise o find: function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "John" }); } - }) + }), + person: Person }); run(function() { - store.find(Person, 1).then(function(person) { + store.find('person', 1).then(function(person) { equal(get(person, 'currentState.stateName'), 'root.loaded.saved', 'model is in loaded state'); equal(get(person, 'isLoaded'), true, 'model is loaded'); }); diff --git a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js index 219f5998716..45cbd32c730 100644 --- a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js +++ b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js @@ -20,11 +20,12 @@ test("a record receives a didLoad callback when it has finished loading", functi }); var store = createStore({ - adapter: adapter + adapter: adapter, + person: Person }); run(function() { - store.find(Person, 1).then(function(person) { + store.find('person', 1).then(function(person) { equal(person.get('id'), "1", "The person's ID is available"); equal(person.get('name'), "Foo", "The person's properties are available"); }); @@ -60,12 +61,13 @@ test("a record receives a didUpdate callback when it has finished updating", fun }); var store = createStore({ - adapter: adapter + adapter: adapter, + person: Person }); var asyncPerson; run(function() { - asyncPerson = store.find(Person, 1); + asyncPerson = store.find('person', 1); }); equal(callCount, 0, "precond - didUpdate callback was not called yet"); @@ -103,14 +105,15 @@ test("a record receives a didCreate callback when it has finished updating", fun }); var store = createStore({ - adapter: adapter + adapter: adapter, + person: Person }); equal(callCount, 0, "precond - didCreate callback was not called yet"); var person; run(function() { - person = store.createRecord(Person, { id: 69, name: "Newt Gingrich" }); + person = store.createRecord('person', { id: 69, name: "Newt Gingrich" }); }); @@ -151,12 +154,13 @@ test("a record receives a didDelete callback when it has finished deleting", fun }); var store = createStore({ - adapter: adapter + adapter: adapter, + person: Person }); var asyncPerson; run(function() { - asyncPerson = store.find(Person, 1); + asyncPerson = store.find('person', 1); }); equal(callCount, 0, "precond - didDelete callback was not called yet"); @@ -190,12 +194,13 @@ test("an uncommited record also receives a didDelete callback when it is deleted }); var store = createStore({ - adapter: DS.Adapter.extend() + adapter: DS.Adapter.extend(), + person: Person }); var person; run(function() { - person = store.createRecord(Person, { name: 'Tomster' }); + person = store.createRecord('person', { name: 'Tomster' }); }); equal(callCount, 0, "precond - didDelete callback was not called yet"); @@ -237,12 +242,13 @@ test("a record receives a becameInvalid callback when it became invalid", functi }); var store = createStore({ - adapter: adapter + adapter: adapter, + person: Person }); var asyncPerson; run(function() { - asyncPerson = store.find(Person, 1); + asyncPerson = store.find('person', 1); }); equal(callCount, 0, "precond - becameInvalid callback was not called yet"); @@ -261,15 +267,18 @@ test("a record receives a becameInvalid callback when it became invalid", functi }); test("an ID of 0 is allowed", function() { - var store = createStore(); var Person = DS.Model.extend({ name: DS.attr('string') }); + var store = createStore({ + person: Person + }); + run(function() { - store.push(Person, { id: 0, name: "Tom Dale" }); + store.push('person', { id: 0, name: "Tom Dale" }); }); - equal(store.all(Person).objectAt(0).get('name'), "Tom Dale", "found record with id 0"); + equal(store.all('person').objectAt(0).get('name'), "Tom Dale", "found record with id 0"); }); diff --git a/packages/ember-data/tests/unit/model/merge-test.js b/packages/ember-data/tests/unit/model/merge-test.js index bd84896158b..353099942a3 100644 --- a/packages/ember-data/tests/unit/model/merge-test.js +++ b/packages/ember-data/tests/unit/model/merge-test.js @@ -19,10 +19,13 @@ test("When a record is in flight, changes can be made", function() { } }); var person; - var store = createStore({ adapter: adapter }); + var store = createStore({ + adapter: adapter, + person: Person + }); run(function() { - person = store.createRecord(Person, { name: "Tom Dale" }); + person = store.createRecord('person', { name: "Tom Dale" }); }); // Make sure saving isn't resolved synchronously @@ -52,11 +55,14 @@ test("When a record is in flight, pushes are applied underneath the in flight ch } }); - var store = createStore({ adapter: adapter }); + var store = createStore({ + adapter: adapter, + person: Person + }); var person; run(function() { - person = store.push(Person, { id: 1, name: "Tom" }); + person = store.push('person', { id: 1, name: "Tom" }); person.set('name', "Thomas Dale"); }); @@ -67,7 +73,7 @@ test("When a record is in flight, pushes are applied underneath the in flight ch person.set('name', "Tomasz Dale"); - store.push(Person, { id: 1, name: "Tommy Dale", city: "PDX" }); + store.push('person', { id: 1, name: "Tommy Dale", city: "PDX" }); equal(person.get('name'), "Tomasz Dale", "the local changes applied on top"); equal(person.get('city'), "PDX", "the pushed change is available"); @@ -81,11 +87,14 @@ test("When a record is in flight, pushes are applied underneath the in flight ch }); test("When a record is dirty, pushes are overridden by local changes", function() { - var store = createStore({ adapter: DS.Adapter }); + var store = createStore({ + adapter: DS.Adapter, + person: Person + }); var person; run(function() { - person = store.push(Person, { id: 1, name: "Tom Dale", city: "San Francisco" }); + person = store.push('person', { id: 1, name: "Tom Dale", city: "San Francisco" }); person.set('name', "Tomasz Dale"); }); @@ -94,7 +103,7 @@ test("When a record is dirty, pushes are overridden by local changes", function( equal(person.get('city'), "San Francisco", "the original data applies"); run(function() { - store.push(Person, { id: 1, name: "Thomas Dale", city: "Portland" }); + store.push('person', { id: 1, name: "Thomas Dale", city: "Portland" }); }); equal(person.get('isDirty'), true, "the local changes are reapplied"); @@ -111,11 +120,14 @@ test("A record with no changes can still be saved", function() { } }); - var store = createStore({ adapter: adapter }); + var store = createStore({ + adapter: adapter, + person: Person + }); var person; run(function() { - person = store.push(Person, { id: 1, name: "Tom Dale" }); + person = store.push('person', { id: 1, name: "Tom Dale" }); }); run(function() { @@ -134,11 +146,14 @@ test("A dirty record can be reloaded", function() { } }); - var store = createStore({ adapter: adapter }); + var store = createStore({ + adapter: adapter, + person: Person + }); var person; run(function() { - person = store.push(Person, { id: 1, name: "Tom Dale" }); + person = store.push('person', { id: 1, name: "Tom Dale" }); person.set('name', "Tomasz Dale"); }); diff --git a/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js b/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js index 0b788e23ff0..65e5cdc2c44 100644 --- a/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js @@ -134,7 +134,7 @@ test("calling createRecord and passing in an undefined value for a relationship }); run(function() { - store.find(Person, 1).then(async(function(person) { + store.find('person', 1).then(async(function(person) { strictEqual(person.get('tag'), null, "undefined values should return null relationships"); })); }); @@ -249,7 +249,7 @@ test("belongsTo supports relationships to models with id 0", function() { equal(get(person, 'tag.name'), "friendly", "the tag should have name"); strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); - asyncEqual(get(person, 'tag'), store.find(Tag, 0), "relationship object is the same as object retrieved directly"); + asyncEqual(get(person, 'tag'), store.find('tag', 0), "relationship object is the same as object retrieved directly"); })); }); }); diff --git a/packages/ember-data/tests/unit/model/relationships/has-many-test.js b/packages/ember-data/tests/unit/model/relationships/has-many-test.js index dad161ea1b3..a637bcab2f9 100644 --- a/packages/ember-data/tests/unit/model/relationships/has-many-test.js +++ b/packages/ember-data/tests/unit/model/relationships/has-many-test.js @@ -64,7 +64,7 @@ test("hasMany handles pre-loaded relationships", function() { equal(get(get(person, 'tags'), 'length'), 2, "the length is updated after new data is loaded"); strictEqual(get(person, 'tags').objectAt(0), get(person, 'tags').objectAt(0), "the returned object is always the same"); - asyncEqual(get(person, 'tags').objectAt(0), store.find(Tag, 5), "relationship objects are the same as objects retrieved directly"); + asyncEqual(get(person, 'tags').objectAt(0), store.find('tag', 5), "relationship objects are the same as objects retrieved directly"); run(function() { store.push('person', { id: 3, name: "KSelden" }); @@ -86,7 +86,7 @@ test("hasMany handles pre-loaded relationships", function() { equal(get(pets.objectAt(0), 'name'), "fluffy", "the first pet should be correct"); run(function() { - store.push(Person, { id: 4, name: "Cyvid Hamluck", pets: [4, 12] }); + store.push('person', { id: 4, name: "Cyvid Hamluck", pets: [4, 12] }); }); equal(pets, get(cyvid, 'pets'), "a relationship returns the same object every time"); @@ -152,13 +152,13 @@ test("hasMany lazily loads async relationships", function() { equal(get(records.tags.objectAt(0), 'name'), "oohlala", "the first tag should be a Tag"); strictEqual(records.tags.objectAt(0), records.tags.objectAt(0), "the returned object is always the same"); - asyncEqual(records.tags.objectAt(0), store.find(Tag, 12), "relationship objects are the same as objects retrieved directly"); + asyncEqual(records.tags.objectAt(0), store.find('tag', 12), "relationship objects are the same as objects retrieved directly"); return get(wycats, 'tags'); }).then(function(tags) { var newTag; run(function() { - newTag = store.createRecord(Tag); + newTag = store.createRecord('tag'); tags.pushObject(newTag); }); }); @@ -335,12 +335,12 @@ test("it is possible to add a new item to a relationship", function() { }); run(function() { - store.find(Person, 1).then(function(person) { + store.find('person', 1).then(function(person) { var tag = get(person, 'tags').objectAt(0); equal(get(tag, 'name'), "ember", "precond - relationships work"); - tag = store.createRecord(Tag, { name: "js" }); + tag = store.createRecord('tag', { name: "js" }); get(person, 'tags').pushObject(tag); equal(get(person, 'tags').objectAt(1), tag, "newly added relationship works"); diff --git a/packages/ember-data/tests/unit/record-array-test.js b/packages/ember-data/tests/unit/record-array-test.js index 8f59201e64d..2992d8b98a9 100644 --- a/packages/ember-data/tests/unit/record-array-test.js +++ b/packages/ember-data/tests/unit/record-array-test.js @@ -16,13 +16,15 @@ module("unit/record_array - DS.RecordArray", { test("a record array is backed by records", function() { expect(3); - var store = createStore(); + var store = createStore({ + person: Person + }); run(function() { - store.pushMany(Person, array); + store.pushMany('person', array); }); run(function() { - store.findByIds(Person, [1,2,3]).then(function(records) { + store.findByIds('person', [1,2,3]).then(function(records) { for (var i=0, l=get(array, 'length'); i Date: Sat, 16 May 2015 19:07:52 -0500 Subject: [PATCH 0807/2527] remove instances of DS.Store from factories When using multiple stores with Ember Data, we want to avoid storing the state on the factory itself. Because multiple stores currently share the same factory, this means that the first store to look up the factory will store itself as the `store` on that factory. That means that any stores thereafter will receive factories whose `store` property references the first store, not their own. --- .../lib/serializers/embedded-records-mixin.js | 2 +- .../lib/serializers/json-serializer.js | 2 +- .../lib/system/relationship-meta.js | 20 ++++-------- .../lib/system/relationships/ext.js | 31 ++++++++++--------- .../system/relationships/state/belongs-to.js | 12 +++---- .../lib/system/relationships/state/create.js | 2 +- .../system/relationships/state/has-many.js | 14 ++++----- packages/ember-data/lib/system/store.js | 1 - .../ember-data/lib/system/store/finders.js | 10 +++--- .../tests/integration/inverse-test.js | 18 ++++++----- .../relationships/belongs-to-test.js | 13 ++++++-- .../relationships/has-many-test.js | 8 ++--- .../tests/unit/model/relationships-test.js | 4 +-- .../unit/model/relationships/has-many-test.js | 8 ++--- .../tests/unit/store/create-record-test.js | 4 +-- 15 files changed, 77 insertions(+), 72 deletions(-) diff --git a/packages/ember-data/lib/serializers/embedded-records-mixin.js b/packages/ember-data/lib/serializers/embedded-records-mixin.js index adc0ddcbc99..0e4a105755b 100644 --- a/packages/ember-data/lib/serializers/embedded-records-mixin.js +++ b/packages/ember-data/lib/serializers/embedded-records-mixin.js @@ -391,7 +391,7 @@ function extractEmbeddedRecords(serializer, store, typeClass, partial) { typeClass.eachRelationship(function(key, relationship) { if (serializer.hasDeserializeRecordsOption(key)) { - var embeddedTypeClass = store.modelFor(relationship.type.modelName); + var embeddedTypeClass = store.modelFor(relationship.type); if (relationship.kind === "hasMany") { if (relationship.options.polymorphic) { extractEmbeddedHasManyPolymorphic(store, key, partial); diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index e81133c090b..533b6822c6d 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -651,7 +651,7 @@ export default Serializer.extend({ payloadKey = this.keyForRelationship(key, "hasMany", "serialize"); } - var relationshipType = snapshot.type.determineRelationshipType(relationship); + var relationshipType = snapshot.type.determineRelationshipType(relationship, this.store); if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') { json[payloadKey] = snapshot.hasMany(key, { ids: true }); diff --git a/packages/ember-data/lib/system/relationship-meta.js b/packages/ember-data/lib/system/relationship-meta.js index 42244245a85..3ec11c098f8 100644 --- a/packages/ember-data/lib/system/relationship-meta.js +++ b/packages/ember-data/lib/system/relationship-meta.js @@ -1,26 +1,18 @@ import {singularize} from 'ember-inflector/lib/system/string'; +import normalizeModelName from 'ember-data/system/normalize-model-name'; -export function typeForRelationshipMeta(store, meta) { - var modelName, typeClass; +export function typeForRelationshipMeta(meta) { + var modelName; modelName = meta.type || meta.key; - if (typeof modelName === 'string') { - if (meta.kind === 'hasMany') { - modelName = singularize(modelName); - } - typeClass = store.modelFor(modelName); - } else { - typeClass = meta.type; - } - - return typeClass; + return singularize(normalizeModelName(modelName)); } -export function relationshipFromMeta(store, meta) { +export function relationshipFromMeta(meta) { return { key: meta.key, kind: meta.kind, - type: typeForRelationshipMeta(store, meta), + type: typeForRelationshipMeta(meta), options: meta.options, parentType: meta.parentType, isRelationship: true diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index a610e220203..7c89de481de 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -26,7 +26,7 @@ var relationshipsDescriptor = Ember.computed(function() { // it to the map. if (meta.isRelationship) { meta.key = name; - var relationshipsForType = map.get(typeForRelationshipMeta(this.store, meta)); + var relationshipsForType = map.get(typeForRelationshipMeta(meta)); relationshipsForType.push({ name: name, @@ -52,7 +52,7 @@ var relatedTypesDescriptor = Ember.computed(function() { this.eachComputedProperty(function(name, meta) { if (meta.isRelationship) { meta.key = name; - modelName = typeForRelationshipMeta(this.store, meta); + modelName = typeForRelationshipMeta(meta); Ember.assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", modelName); @@ -76,8 +76,8 @@ var relationshipsByNameDescriptor = Ember.computed(function() { this.eachComputedProperty(function(name, meta) { if (meta.isRelationship) { meta.key = name; - var relationship = relationshipFromMeta(this.store, meta); - relationship.type = typeForRelationshipMeta(this.store, meta); + var relationship = relationshipFromMeta(meta); + relationship.type = typeForRelationshipMeta(meta); map.set(name, relationship); } }); @@ -175,11 +175,12 @@ Model.reopenClass({ @method typeForRelationship @static @param {String} name the name of the relationship + @param {store} store an instance of DS.Store @return {subclass of DS.Model} the type of the relationship, or undefined */ - typeForRelationship: function(name) { + typeForRelationship: function(name, store) { var relationship = get(this, 'relationshipsByName').get(name); - return relationship && relationship.type; + return relationship && store.modelFor(relationship.type); }, inverseMap: Ember.computed(function() { @@ -209,21 +210,21 @@ Model.reopenClass({ @param {String} name the name of the relationship @return {Object} the inverse relationship, or null */ - inverseFor: function(name) { + inverseFor: function(name, store) { var inverseMap = get(this, 'inverseMap'); if (inverseMap[name]) { return inverseMap[name]; } else { - var inverse = this._findInverseFor(name); + var inverse = this._findInverseFor(name, store); inverseMap[name] = inverse; return inverse; } }, //Calculate the inverse, ignoring the cache - _findInverseFor: function(name) { + _findInverseFor: function(name, store) { - var inverseType = this.typeForRelationship(name); + var inverseType = this.typeForRelationship(name, store); if (!inverseType) { return null; } @@ -277,9 +278,9 @@ Model.reopenClass({ var possibleRelationships = relationshipsSoFar || []; var relationshipMap = get(inverseType, 'relationships'); - if (!relationshipMap) { return; } + if (!relationshipMap) { return possibleRelationships; } - var relationships = relationshipMap.get(type); + var relationships = relationshipMap.get(type.modelName); relationships = filter.call(relationships, function(relationship) { var optionsForRelationship = inverseType.metaForProperty(relationship.name).options; @@ -535,10 +536,10 @@ Model.reopenClass({ }); }, - determineRelationshipType: function(knownSide) { + determineRelationshipType: function(knownSide, store) { var knownKey = knownSide.key; var knownKind = knownSide.kind; - var inverse = this.inverseFor(knownKey); + var inverse = this.inverseFor(knownKey, store); var key, otherKind; if (!inverse) { @@ -617,7 +618,7 @@ Model.reopen({ }, inverseFor: function(key) { - return this.constructor.inverseFor(key); + return this.constructor.inverseFor(key, this.store); } }); diff --git a/packages/ember-data/lib/system/relationships/state/belongs-to.js b/packages/ember-data/lib/system/relationships/state/belongs-to.js index a515aa6aa57..b658ca20cdf 100644 --- a/packages/ember-data/lib/system/relationships/state/belongs-to.js +++ b/packages/ember-data/lib/system/relationships/state/belongs-to.js @@ -61,15 +61,15 @@ BelongsToRelationship.prototype.flushCanonical = function() { BelongsToRelationship.prototype._super$addRecord = Relationship.prototype.addRecord; BelongsToRelationship.prototype.addRecord = function(newRecord) { if (this.members.has(newRecord)) { return;} - var type = this.relationshipMeta.type; - Ember.assert("You cannot add a '" + newRecord.constructor.modelName + "' record to the '" + this.record.constructor.modelName + "." + this.key +"'. " + "You can only add a '" + type.modelName + "' record to this relationship.", (function () { - if (type.__isMixin) { - return type.__mixin.detect(newRecord); + var typeClass = this.store.modelFor(this.relationshipMeta.type); + Ember.assert("You cannot add a '" + newRecord.constructor.modelName + "' record to the '" + this.record.constructor.modelName + "." + this.key +"'. " + "You can only add a '" + typeClass.modelName + "' record to this relationship.", (function () { + if (typeClass.__isMixin) { + return typeClass.__mixin.detect(newRecord); } if (Ember.MODEL_FACTORY_INJECTIONS) { - type = type.superclass; + typeClass = typeClass.superclass; } - return newRecord instanceof type; + return newRecord instanceof typeClass; })()); if (this.inverseRecord) { diff --git a/packages/ember-data/lib/system/relationships/state/create.js b/packages/ember-data/lib/system/relationships/state/create.js index 9d4bd93ae4c..778d5d44087 100644 --- a/packages/ember-data/lib/system/relationships/state/create.js +++ b/packages/ember-data/lib/system/relationships/state/create.js @@ -3,7 +3,7 @@ import BelongsToRelationship from "ember-data/system/relationships/state/belongs var createRelationshipFor = function(record, relationshipMeta, store) { var inverseKey; - var inverse = record.constructor.inverseFor(relationshipMeta.key); + var inverse = record.constructor.inverseFor(relationshipMeta.key, store); if (inverse) { inverseKey = inverse.name; diff --git a/packages/ember-data/lib/system/relationships/state/has-many.js b/packages/ember-data/lib/system/relationships/state/has-many.js index 0c774db41ec..775f47a08a7 100644 --- a/packages/ember-data/lib/system/relationships/state/has-many.js +++ b/packages/ember-data/lib/system/relationships/state/has-many.js @@ -11,7 +11,7 @@ var ManyRelationship = function(store, record, inverseKey, relationshipMeta) { canonicalState: this.canonicalState, store: this.store, relationship: this, - type: this.belongsToType, + type: this.store.modelFor(this.belongsToType), record: record }); this.isPolymorphic = relationshipMeta.options.polymorphic; @@ -84,15 +84,15 @@ ManyRelationship.prototype.removeRecordFromOwn = function(record, idx) { }; ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) { - var type = this.relationshipMeta.type; - Ember.assert("You cannot add '" + record.constructor.modelName + "' records to the " + this.record.constructor.modelName + "." + this.key + " relationship (only '" + this.belongsToType.modelName + "' allowed)", (function () { - if (type.__isMixin) { - return type.__mixin.detect(record); + var typeClass = this.store.modelFor(this.relationshipMeta.type); + Ember.assert("You cannot add '" + record.constructor.modelName + "' records to the " + this.record.constructor.modelName + "." + this.key + " relationship (only '" + typeClass.modelName + "' allowed)", (function () { + if (typeClass.__isMixin) { + return typeClass.__mixin.detect(record); } if (Ember.MODEL_FACTORY_INJECTIONS) { - type = type.superclass; + typeClass = typeClass.superclass; } - return record instanceof type; + return record instanceof typeClass; })()); this.record.notifyHasManyAdded(this.key, record, idx); diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index bc84050d148..4777fc8d4f6 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1498,7 +1498,6 @@ Store = Service.extend({ }); } - factory.store = this; return factory; }, diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index c633f5f3252..0296ef02fc1 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -67,7 +67,8 @@ export function _findMany(adapter, store, typeClass, ids, records) { export function _findHasMany(adapter, store, record, link, relationship) { var snapshot = record._createSnapshot(); - var modelName = relationship.type.modelName; + var modelName = relationship.type; + var typeClass = store.modelFor(modelName); var promise = adapter.findHasMany(store, snapshot, link, relationship); var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type; @@ -78,7 +79,7 @@ export function _findHasMany(adapter, store, record, link, relationship) { return promise.then(function(adapterPayload) { return store._adapterRun(function() { - var payload = serializer.extract(store, relationship.type, adapterPayload, null, 'findHasMany'); + var payload = serializer.extract(store, typeClass, adapterPayload, null, 'findHasMany'); Ember.assert("The response from a findHasMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -89,7 +90,8 @@ export function _findHasMany(adapter, store, record, link, relationship) { } export function _findBelongsTo(adapter, store, record, link, relationship) { - var modelName = relationship.type.modelName; + var modelName = relationship.type; + var typeClass = store.modelFor(modelName); var snapshot = record._createSnapshot(); var promise = adapter.findBelongsTo(store, snapshot, link, relationship); var serializer = serializerForAdapter(store, adapter, modelName); @@ -101,7 +103,7 @@ export function _findBelongsTo(adapter, store, record, link, relationship) { return promise.then(function(adapterPayload) { return store._adapterRun(function() { - var payload = serializer.extract(store, relationship.type, adapterPayload, null, 'findBelongsTo'); + var payload = serializer.extract(store, typeClass, adapterPayload, null, 'findBelongsTo'); if (!payload) { return null; diff --git a/packages/ember-data/tests/integration/inverse-test.js b/packages/ember-data/tests/integration/inverse-test.js index e55f15ec4b9..d0861e54ae4 100644 --- a/packages/ember-data/tests/integration/inverse-test.js +++ b/packages/ember-data/tests/integration/inverse-test.js @@ -38,6 +38,10 @@ module('integration/inverse_test - inverseFor', { }); store = env.store; + + Job = store.modelFor('job'); + User = store.modelFor('user'); + ReflexiveModel = store.modelFor('reflexive-model'); }, teardown: function() { @@ -49,7 +53,7 @@ test("Finds the inverse when there is only one possible available", function () //Maybe store is evaluated lazily, so we need this :( run(store, 'push', 'user', { id: 1 }); - deepEqual(Job.inverseFor('user'), { + deepEqual(Job.inverseFor('user', store), { type: User, name: 'job', kind: 'belongsTo' @@ -72,13 +76,13 @@ test("Finds the inverse when only one side has defined it manually", function () job = store.push('user', { id: 1 }); }); - deepEqual(Job.inverseFor('owner'), { + deepEqual(Job.inverseFor('owner', store), { type: User, //the model's type name: 'previousJob', //the models relationship key kind: 'belongsTo' }, 'Gets correct type, name and kind'); - deepEqual(User.inverseFor('previousJob'), { + deepEqual(User.inverseFor('previousJob', store), { type: Job, //the model's type name: 'owner', //the models relationship key kind: 'belongsTo' @@ -99,7 +103,7 @@ test("Returns null if inverse relationship it is manually set with a different r user = store.push('user', { id: 1 }); }); - equal(User.inverseFor('job'), null, 'There is no inverse'); + equal(User.inverseFor('job', store), null, 'There is no inverse'); }); test("Errors out if you define 2 inverses to the same model", function () { @@ -117,7 +121,7 @@ test("Errors out if you define 2 inverses to the same model", function () { run(function() { store.push('user', { id: 1 }); }); - User.inverseFor('job'); + User.inverseFor('job', store); }, "You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses"); }); @@ -129,12 +133,12 @@ test("Caches findInverseFor return value", function () { store.push('user', { id: 1 }); }); - var inverseForUser = Job.inverseFor('user'); + var inverseForUser = Job.inverseFor('user', store); Job.findInverseFor = function() { ok(false, 'Find is not called anymore'); }; - equal(inverseForUser, Job.inverseFor('user'), 'Inverse cached succesfully'); + equal(inverseForUser, Job.inverseFor('user', store), 'Inverse cached succesfully'); }); test("Errors out if you do not define an inverse for a reflexive relationship", function () { diff --git a/packages/ember-data/tests/integration/relationships/belongs-to-test.js b/packages/ember-data/tests/integration/relationships/belongs-to-test.js index 9679be315a2..db4ba5d33e7 100644 --- a/packages/ember-data/tests/integration/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/integration/relationships/belongs-to-test.js @@ -71,7 +71,6 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { author: Author }); - env.registry.optionsForType('serializer', { singleton: false }); env.registry.optionsForType('adapter', { singleton: false }); @@ -82,6 +81,14 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { })); store = env.store; + + User = store.modelFor('user'); + Post = store.modelFor('post'); + Comment = store.modelFor('comment'); + Message = store.modelFor('message'); + Book = store.modelFor('book'); + Chapter = store.modelFor('chapter'); + Author = store.modelFor('author'); }, teardown: function() { @@ -227,7 +234,7 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to }; env.adapter.findBelongsTo = async(function(store, snapshot, link, relationship) { - equal(relationship.type, Group); + equal(relationship.type, 'group'); equal(relationship.key, 'group'); equal(link, "/people/1/group"); @@ -380,7 +387,7 @@ test("relationshipsByName does not cache a factory", function() { // A model is looked up in the store based on a string, via user input var messageModelFromStore = store.modelFor('message'); // And the model is lookup up internally via the relationship type - var messageModelFromRelationType = store.modelFor(messageType.modelName); + var messageModelFromRelationType = store.modelFor(messageType); equal(messageModelFromRelationType, messageModelFromStore, "model factory based on relationship type matches the model based on store.modelFor"); diff --git a/packages/ember-data/tests/integration/relationships/has-many-test.js b/packages/ember-data/tests/integration/relationships/has-many-test.js index ad4981cfa39..42584542cd7 100644 --- a/packages/ember-data/tests/integration/relationships/has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/has-many-test.js @@ -150,7 +150,7 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi env.adapter.findHasMany = function(store, snapshot, link, relationship) { equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); - equal(relationship.type.modelName, "comment", "relationship was passed correctly"); + equal(relationship.type, "comment", "relationship was passed correctly"); return Ember.RSVP.resolve([ { id: 1, body: "First" }, @@ -340,7 +340,7 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func }; env.adapter.findHasMany = function(store, snapshot, link, relationship) { - equal(relationship.type, Comment, "findHasMany relationship type was Comment"); + equal(relationship.type, 'comment', "findHasMany relationship type was Comment"); equal(relationship.key, 'comments', "findHasMany relationship key was comments"); equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); @@ -358,7 +358,7 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func equal(comments.get('length'), 2, "comments have 2 length"); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - equal(relationship.type, Comment, "findHasMany relationship type was Comment"); + equal(relationship.type, 'comment', "findHasMany relationship type was Comment"); equal(relationship.key, 'comments', "findHasMany relationship key was comments"); equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); @@ -570,7 +570,7 @@ test("An updated `links` value should invalidate a relationship cache", function }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - equal(relationship.type.modelName, "comment", "relationship was passed correctly"); + equal(relationship.type, "comment", "relationship was passed correctly"); if (link === '/first') { return Ember.RSVP.resolve([ diff --git a/packages/ember-data/tests/unit/model/relationships-test.js b/packages/ember-data/tests/unit/model/relationships-test.js index f110aefd703..30dd0ec96e3 100644 --- a/packages/ember-data/tests/unit/model/relationships-test.js +++ b/packages/ember-data/tests/unit/model/relationships-test.js @@ -27,11 +27,11 @@ test("exposes a hash of the relationships on a model", function() { }); var relationships = get(Person, 'relationships'); - deepEqual(relationships.get(Person), [ + deepEqual(relationships.get('person'), [ { name: "people", kind: "hasMany" }, { name: "parent", kind: "belongsTo" } ]); - deepEqual(relationships.get(Occupation), [ + deepEqual(relationships.get('occupation'), [ { name: "occupations", kind: "hasMany" } ]); }); diff --git a/packages/ember-data/tests/unit/model/relationships/has-many-test.js b/packages/ember-data/tests/unit/model/relationships/has-many-test.js index a637bcab2f9..beb12f47d68 100644 --- a/packages/ember-data/tests/unit/model/relationships/has-many-test.js +++ b/packages/ember-data/tests/unit/model/relationships/has-many-test.js @@ -177,7 +177,7 @@ test("should be able to retrieve the type for a hasMany relationship without spe person: Person }); - equal(env.store.modelFor('person').typeForRelationship('tags'), Tag, "returns the relationship type"); + equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, "returns the relationship type"); }); test("should be able to retrieve the type for a hasMany relationship specified using a string from its metadata", function() { @@ -192,7 +192,7 @@ test("should be able to retrieve the type for a hasMany relationship specified u person: Person }); - equal(env.store.modelFor('person').typeForRelationship('tags'), Tag, "returns the relationship type"); + equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, "returns the relationship type"); }); test("should be able to retrieve the type for a belongsTo relationship without specifying a type from its metadata", function() { @@ -207,7 +207,7 @@ test("should be able to retrieve the type for a belongsTo relationship without s person: Person }); - equal(env.store.modelFor('person').typeForRelationship('tag'), Tag, "returns the relationship type"); + equal(env.store.modelFor('person').typeForRelationship('tag', env.store), Tag, "returns the relationship type"); }); test("should be able to retrieve the type for a belongsTo relationship specified using a string from its metadata", function() { @@ -224,7 +224,7 @@ test("should be able to retrieve the type for a belongsTo relationship specified person: Person }); - equal(env.store.modelFor('person').typeForRelationship('tags'), Tag, "returns the relationship type"); + equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, "returns the relationship type"); }); test("relationships work when declared with a string path", function() { diff --git a/packages/ember-data/tests/unit/store/create-record-test.js b/packages/ember-data/tests/unit/store/create-record-test.js index 1e555d6ac1a..9620ef2a1db 100644 --- a/packages/ember-data/tests/unit/store/create-record-test.js +++ b/packages/ember-data/tests/unit/store/create-record-test.js @@ -33,8 +33,8 @@ test("doesn't modify passed in properties hash", function() { test("allow passing relationships as well as attributes", function() { var records, storage; run(function() { - records = store.pushMany(Record, [{ id: 1, title: "it's a beautiful day" }, { id: 2, title: "it's a beautiful day" }]); - storage = store.createRecord(Storage, { name: 'Great store', records: records }); + records = store.pushMany('record', [{ id: 1, title: "it's a beautiful day" }, { id: 2, title: "it's a beautiful day" }]); + storage = store.createRecord('storage', { name: 'Great store', records: records }); }); equal(storage.get('name'), 'Great store', "The attribute is well defined"); From f89a83a6d953b22ef66b0891b369640f53af7781 Mon Sep 17 00:00:00 2001 From: Tony Schneider Date: Sat, 30 May 2015 12:14:30 -0400 Subject: [PATCH 0808/2527] Cleanup unneeded if after ManyArray refactor --- packages/ember-data/lib/system/record-arrays/record-array.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/record-arrays/record-array.js b/packages/ember-data/lib/system/record-arrays/record-array.js index da3a0409618..ddac3b34fd0 100644 --- a/packages/ember-data/lib/system/record-arrays/record-array.js +++ b/packages/ember-data/lib/system/record-arrays/record-array.js @@ -206,10 +206,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { */ _unregisterFromManager: function() { var manager = get(this, 'manager'); - //We will stop needing this stupid if statement soon, once manyArray are refactored to not be RecordArrays - if (manager) { - manager.unregisterFilteredRecordArray(this); - } + manager.unregisterFilteredRecordArray(this); }, willDestroy: function() { From 76cb9ac43bfcebc5820aa46db523c5397d971741 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 1 Jun 2015 06:28:27 -0400 Subject: [PATCH 0809/2527] Remove ember.debug warning from the browser console when running tests --- tests/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/index.html b/tests/index.html index e245e4d6f95..0a02c96ba86 100644 --- a/tests/index.html +++ b/tests/index.html @@ -44,9 +44,9 @@ From 3830984944b84af4bfe443d0952f7688d4d75516 Mon Sep 17 00:00:00 2001 From: tchak Date: Mon, 1 Jun 2015 11:24:04 +0300 Subject: [PATCH 0810/2527] Create snapshots on save not on flush alows us to have access to changed attributes in snapshot --- packages/ember-data/lib/system/model/model.js | 10 +++++-- packages/ember-data/lib/system/snapshot.js | 29 ++++++++++++++++++- packages/ember-data/lib/system/store.js | 18 +++++++----- .../tests/integration/snapshot-test.js | 14 +++++++++ 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 85f9caf5f7e..e435865e9af 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -889,7 +889,7 @@ var Model = Ember.Object.extend(Ember.Evented, { changedAttributes: function() { var oldData = get(this, '_data'); var newData = get(this, '_attributes'); - var diffData = {}; + var diffData = Ember.create(null); var prop; for (prop in newData) { @@ -899,11 +899,17 @@ var Model = Ember.Object.extend(Ember.Evented, { return diffData; }, + flushChangedAttributes: function() { + this._inFlightAttributes = this._attributes; + this._attributes = Ember.create(null); + }, + /** @method adapterWillCommit @private */ adapterWillCommit: function() { + this.flushChangedAttributes(); this.send('willCommit'); }, @@ -1052,8 +1058,6 @@ var Model = Ember.Object.extend(Ember.Evented, { var resolver = Ember.RSVP.defer(promiseLabel); this.store.scheduleSave(this, resolver); - this._inFlightAttributes = this._attributes; - this._attributes = Ember.create(null); return PromiseObject.create({ promise: resolver.promise diff --git a/packages/ember-data/lib/system/snapshot.js b/packages/ember-data/lib/system/snapshot.js index d14fc0d4a0c..2129e47f1ab 100644 --- a/packages/ember-data/lib/system/snapshot.js +++ b/packages/ember-data/lib/system/snapshot.js @@ -27,6 +27,8 @@ function Snapshot(record) { this.type = record.constructor; this.modelName = record.constructor.modelName; + this._changedAttributes = record.changedAttributes(); + // The following code is here to keep backwards compatibility when accessing // `constructor` directly. // @@ -135,7 +137,7 @@ Snapshot.prototype = { Example ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Hello World' }); + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); postSnapshot.attributes(); // => { author: 'Tomster', title: 'Ember.js rocks' } ``` @@ -146,6 +148,31 @@ Snapshot.prototype = { return Ember.copy(this._attributes); }, + /** + Returns all changed attributes and their old and new values. + + Example + + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postModel.set('title', 'Ember.js rocks!'); + postSnapshot.changedAttributes(); // => { title: ['Ember.js rocks', 'Ember.js rocks!'] } + ``` + + @method changedAttributes + @return {Object} All changed attributes of the current snapshot + */ + changedAttributes: function() { + var prop; + var changedAttributes = Ember.create(null); + + for (prop in this._changedAttributes) { + changedAttributes[prop] = Ember.copy(this._changedAttributes[prop]); + } + + return changedAttributes; + }, + /** Returns the current value of a belongsTo relationship. diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 3a21b1d43f3..350d2fa36cb 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1254,8 +1254,9 @@ Store = Service.extend({ @param {Resolver} resolver */ scheduleSave: function(record, resolver) { + var snapshot = record._createSnapshot(); record.adapterWillCommit(); - this._pendingSave.push([record, resolver]); + this._pendingSave.push([snapshot, resolver]); once(this, 'flushPendingSave'); }, @@ -1271,8 +1272,9 @@ Store = Service.extend({ this._pendingSave = []; forEach(pending, function(tuple) { - var record = tuple[0]; + var snapshot = tuple[0]; var resolver = tuple[1]; + var record = snapshot.record; var adapter = this.adapterFor(record.constructor); var operation; @@ -1286,7 +1288,7 @@ Store = Service.extend({ operation = 'updateRecord'; } - resolver.resolve(_commit(adapter, this, operation, record)); + resolver.resolve(_commit(adapter, this, operation, snapshot)); }, this); }, @@ -2022,9 +2024,9 @@ function defaultSerializer(container) { container.lookup('serializer:-default'); } -function _commit(adapter, store, operation, record) { - var type = record.constructor; - var snapshot = record._createSnapshot(); +function _commit(adapter, store, operation, snapshot) { + var record = snapshot.record; + var type = snapshot.type; var promise = adapter[operation](store, type, snapshot); var serializer = serializerForAdapter(store, adapter, type); var label = "DS: Extract and notify about " + operation + " completion of " + record; @@ -2040,7 +2042,7 @@ function _commit(adapter, store, operation, record) { store._adapterRun(function() { if (adapterPayload) { - payload = serializer.extract(store, type, adapterPayload, get(record, 'id'), operation); + payload = serializer.extract(store, type, adapterPayload, get(snapshot, 'id'), operation); } store.didSaveRecord(record, payload); }); @@ -2048,7 +2050,7 @@ function _commit(adapter, store, operation, record) { return record; }, function(reason) { if (reason instanceof InvalidError) { - var errors = serializer.extractErrors(store, type, reason.errors, get(record, 'id')); + var errors = serializer.extractErrors(store, type, reason.errors, get(snapshot, 'id')); store.recordWasInvalid(record, errors); reason = new InvalidError(errors); } else { diff --git a/packages/ember-data/tests/integration/snapshot-test.js b/packages/ember-data/tests/integration/snapshot-test.js index 0c71dffd273..8b85621cab2 100644 --- a/packages/ember-data/tests/integration/snapshot-test.js +++ b/packages/ember-data/tests/integration/snapshot-test.js @@ -112,6 +112,20 @@ test("snapshot.attributes() returns a copy of all attributes for the current sna }); }); +test("snapshot.changedAttributes() returns a copy of all changed attributes for the current snapshot", function() { + expect(1); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + post.set('title', 'Hello World!'); + var snapshot = post._createSnapshot(); + + var changes = snapshot.changedAttributes(); + + deepEqual(changes, { title: ['Hello World', 'Hello World!'] }, 'changed attributes are returned correctly'); + }); +}); + test("snapshot.belongsTo() returns undefined if relationship is undefined", function() { expect(1); From 98d1b178e23eabfd53f3e648dca3a907f0036aad Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Fri, 29 May 2015 00:06:46 +0200 Subject: [PATCH 0811/2527] Break out commonalities from extractArray/extractSingle --- .../lib/serializers/rest-serializer.js | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index 3431246c4b4..965214578ec 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -263,7 +263,6 @@ var RESTSerializer = JSONSerializer.extend({ */ extractSingle: function(store, primaryTypeClass, rawPayload, recordId) { var payload = this.normalizePayload(rawPayload); - var primaryTypeClassName = primaryTypeClass.modelName; var primaryRecord; for (var prop in payload) { @@ -273,8 +272,7 @@ var RESTSerializer = JSONSerializer.extend({ Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false); continue; } - var type = store.modelFor(typeName); - var isPrimary = type.modelName === primaryTypeClassName; + var isPrimary = this.isPrimaryType(store, typeName, primaryTypeClass); var value = payload[prop]; if (value === null) { @@ -287,14 +285,10 @@ var RESTSerializer = JSONSerializer.extend({ continue; } - /*jshint loopfunc:true*/ - forEach.call(value, function(hash) { - var typeName = this.modelNameFromPayloadKey(prop); - var type = store.modelFor(typeName); - var typeSerializer = store.serializerFor(type); - - hash = typeSerializer.normalize(type, hash, prop); + var normalizedArray = this.normalizeArray(store, typeName, value, prop); + /*jshint loopfunc:true*/ + forEach.call(normalizedArray, function(hash) { var isFirstCreatedRecord = isPrimary && !recordId && !primaryRecord; var isUpdatedRecord = isPrimary && coerceId(hash.id) === recordId; @@ -417,7 +411,6 @@ var RESTSerializer = JSONSerializer.extend({ */ extractArray: function(store, primaryTypeClass, rawPayload) { var payload = this.normalizePayload(rawPayload); - var primaryTypeClassName = primaryTypeClass.modelName; var primaryArray; for (var prop in payload) { @@ -434,14 +427,9 @@ var RESTSerializer = JSONSerializer.extend({ Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false); continue; } - var type = store.modelFor(typeName); - var typeSerializer = store.serializerFor(type); - var isPrimary = (!forcedSecondary && (type.modelName === primaryTypeClassName)); - /*jshint loopfunc:true*/ - var normalizedArray = map.call(payload[prop], function(hash) { - return typeSerializer.normalize(type, hash, prop); - }, this); + var normalizedArray = this.normalizeArray(store, typeName, payload[prop], prop); + var isPrimary = (!forcedSecondary && this.isPrimaryType(store, typeName, primaryTypeClass)); if (isPrimary) { primaryArray = normalizedArray; @@ -453,6 +441,21 @@ var RESTSerializer = JSONSerializer.extend({ return primaryArray; }, + normalizeArray: function(store, typeName, arrayHash, prop) { + var typeClass = store.modelFor(typeName); + var typeSerializer = store.serializerFor(typeClass); + + /*jshint loopfunc:true*/ + return map.call(arrayHash, function(hash) { + return typeSerializer.normalize(typeClass, hash, prop); + }, this); + }, + + isPrimaryType: function(store, typeName, primaryTypeClass) { + var typeClass = store.modelFor(typeName); + return typeClass.modelName === primaryTypeClass.modelName; + }, + /** This method allows you to push a payload containing top-level collections of records organized per type. From db8cbe6d235c7bb19c30b73349f1c46b320be113 Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 1 Jun 2015 20:01:44 +0200 Subject: [PATCH 0812/2527] Custom primaryKey for embedded polymorphic relations work Since the hashs of the polymorphic embedded records are normalized, the - possible - customized primaryKey can be accessed via the `id` property. --- .../lib/serializers/embedded-records-mixin.js | 7 +- .../embedded-records-mixin-test.js | 106 ++++++++++++++++++ 2 files changed, 108 insertions(+), 5 deletions(-) diff --git a/packages/ember-data/lib/serializers/embedded-records-mixin.js b/packages/ember-data/lib/serializers/embedded-records-mixin.js index d0c2be79e37..3997ffbbbdd 100644 --- a/packages/ember-data/lib/serializers/embedded-records-mixin.js +++ b/packages/ember-data/lib/serializers/embedded-records-mixin.js @@ -1,4 +1,3 @@ -var get = Ember.get; var forEach = Ember.EnumerableUtils.forEach; var camelize = Ember.String.camelize; @@ -442,11 +441,10 @@ function extractEmbeddedHasManyPolymorphic(store, key, hash) { var modelName = data.type; var embeddedSerializer = store.serializerFor(modelName); var embeddedTypeClass = store.modelFor(modelName); - var primaryKey = get(embeddedSerializer, 'primaryKey'); var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null); store.push(embeddedTypeClass, embeddedRecord); - ids.push({ id: embeddedRecord[primaryKey], type: modelName }); + ids.push({ id: embeddedRecord.id, type: modelName }); }); hash[key] = ids; @@ -476,12 +474,11 @@ function extractEmbeddedBelongsToPolymorphic(store, key, hash) { var modelName = data.type; var embeddedSerializer = store.serializerFor(modelName); var embeddedTypeClass = store.modelFor(modelName); - var primaryKey = get(embeddedSerializer, 'primaryKey'); var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null); store.push(embeddedTypeClass, embeddedRecord); - hash[key] = embeddedRecord[primaryKey]; + hash[key] = embeddedRecord.id; hash[key + 'Type'] = modelName; return hash; } diff --git a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js index 8606df6b8a8..8ae3c9eef34 100644 --- a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js +++ b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js @@ -1165,6 +1165,63 @@ test("extractSingle with polymorphic hasMany", function() { }); +test("extractSingle with polymorphic hasMany and custom primary key", function() { + SuperVillain.reopen({ + secretWeapons: DS.hasMany("secretWeapon", { polymorphic: true }) + }); + + env.registry.register('adapter:super-villain', DS.ActiveModelAdapter); + env.registry.register('serializer:light-saber', DS.ActiveModelSerializer.extend({ + primaryKey: 'custom' + })); + env.registry.register('serializer:super-villain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretWeapons: { embedded: 'always' } + } + })); + var serializer = env.container.lookup("serializer:super-villain"); + + var json_hash = { + super_villain: { + id: "1", + first_name: "Tom", + last_name: "Dale", + secret_weapons: [ + { + custom: "1", + type: "LightSaber", + name: "Tom's LightSaber", + color: "Red" + }, + { + id: "1", + type: "SecretWeapon", + name: "The Death Star" + } + ] + } + }; + var json; + + run(function() { + json = serializer.extractSingle(env.store, SuperVillain, json_hash); + }); + + deepEqual(json, { + id: "1", + firstName: "Tom", + lastName: "Dale", + secretWeapons: [ + { id: "1", type: "light-saber" }, + { id: "1", type: "secret-weapon" } + ] + }, "Custom primary key of embedded hasMany is correctly normalized"); + + equal(env.store.recordForId("lightSaber", "1").get("name"), "Tom's LightSaber", "Embedded polymorphic LightSaber with custom primary key is found"); + equal(env.store.recordForId("secretWeapon", "1").get("name"), "The Death Star", "Embedded polymorphic SecretWeapon found"); + +}); + test("extractSingle with polymorphic belongsTo", function() { expect(2); @@ -1211,6 +1268,55 @@ test("extractSingle with polymorphic belongsTo", function() { }); +test("extractSingle with polymorphic belongsTo and custom primary key", function() { + expect(2); + + SuperVillain.reopen({ + secretLab: DS.belongsTo("secretLab", { polymorphic: true }) + }); + + env.registry.register('adapter:super-villain', DS.ActiveModelAdapter); + env.registry.register('serializer:super-villain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' } + } + })); + env.registry.register('serializer:bat-cave', DS.ActiveModelSerializer.extend({ + primaryKey: 'custom' + })); + var serializer = env.container.lookup("serializer:super-villain"); + + var json_hash = { + super_villain: { + id: "1", + first_name: "Tom", + last_name: "Dale", + secret_lab: { + custom: "1", + type: "bat-cave", + infiltrated: true + } + } + }; + + var json; + + run(function() { + json = serializer.extractSingle(env.store, SuperVillain, json_hash); + }); + + deepEqual(json, { + id: "1", + firstName: "Tom", + lastName: "Dale", + secretLab: "1", + secretLabType: "bat-cave" + }, "Custom primary key is correctly normalized"); + + equal(env.store.recordForId("batCave", "1").get("infiltrated"), true, "Embedded polymorphic BatCave with custom primary key is found"); + +}); + test("Mixin can be used with RESTSerializer which does not define keyForAttribute", function() { run(function() { homePlanet = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); From 90619b8c3b048a136bff3de00b00ebea49b1a1a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Grosjean?= Date: Tue, 2 Jun 2015 01:24:21 +0300 Subject: [PATCH 0813/2527] Extend adapter instead of reopening it --- packages/ember-data/lib/adapters/rest-adapter.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest-adapter.js b/packages/ember-data/lib/adapters/rest-adapter.js index 0d0e70b88c6..f6ee3f00e11 100644 --- a/packages/ember-data/lib/adapters/rest-adapter.js +++ b/packages/ember-data/lib/adapters/rest-adapter.js @@ -99,7 +99,7 @@ import BuildURLMixin from "ember-data/adapters/build-url-mixin"; property on the adapter: ```js - DS.RESTAdapter.reopen({ + App.ApplicationAdapter = DS.RESTAdapter.extend({ namespace: 'api/1' }); ``` @@ -110,7 +110,7 @@ import BuildURLMixin from "ember-data/adapters/build-url-mixin"; An adapter can target other hosts by setting the `host` property. ```js - DS.RESTAdapter.reopen({ + App.ApplicationAdapter = DS.RESTAdapter.extend({ host: 'https://api.example.com' }); ``` @@ -281,7 +281,7 @@ export default Adapter.extend(BuildURLMixin, { property on the adapter: ```javascript - DS.RESTAdapter.reopen({ + App.ApplicationAdapter = DS.RESTAdapter.extend({ namespace: 'api/1' }); ``` @@ -296,7 +296,7 @@ export default Adapter.extend(BuildURLMixin, { An adapter can target other hosts by setting the `host` property. ```javascript - DS.RESTAdapter.reopen({ + App.ApplicationAdapter = DS.RESTAdapter.extend({ host: 'https://api.example.com' }); ``` From 065eef91caf7fced779a5a10fd6378a487cc9091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Grosjean?= Date: Tue, 2 Jun 2015 02:51:50 +0300 Subject: [PATCH 0814/2527] Fix doc for typeForRoot, should recommend modelNameFromPayloadKey. --- packages/ember-data/lib/serializers/rest-serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index 3431246c4b4..b5d501875d7 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -791,7 +791,7 @@ var RESTSerializer = JSONSerializer.extend({ }, /** - Deprecated. Use payloadKeyFromModelName instead + Deprecated. Use modelNameFromPayloadKey instead @method typeForRoot @param {String} modelName From 4a0447427c7b02806520b256aca210eefbb30ae1 Mon Sep 17 00:00:00 2001 From: IgorT Date: Sun, 12 Apr 2015 12:50:02 +0200 Subject: [PATCH 0815/2527] Refactor internals to use Javascript objects for internals instead of DS.Model This commit adds an `InternalModel` class that is now used everywhere inside ED to represent models. This class is a fast Javascript object that contains all the data that we know for a particular record. At the ED/App code boundaries, such as responses to `find`, models being set/pushed to `belongsTo`/`hasMany` we convert between internalModels and DS.Models. This should be a huge performance win, because we now lazily create DS.Models which are pretty slow to instantiate. We need to wait for the new serializer/push refactor in order to use a `push` that does not immediately materialize a record to get further perf gains. For now most of perf gains if for foreign keys. --- packages/ember-data/lib/main.js | 3 + packages/ember-data/lib/system/many-array.js | 17 +- .../ember-data/lib/system/model/attributes.js | 14 +- .../lib/system/model/internal-model.js | 694 ++++++++++++++++++ packages/ember-data/lib/system/model/model.js | 537 +------------- .../ember-data/lib/system/model/states.js | 20 +- .../lib/system/record-array-manager.js | 10 +- .../adapter-populated-record-array.js | 6 +- .../lib/system/record-arrays/record-array.js | 6 +- .../lib/system/relationships/belongs-to.js | 10 +- .../lib/system/relationships/has-many.js | 7 +- .../system/relationships/state/belongs-to.js | 20 +- .../lib/system/relationships/state/create.js | 2 +- .../system/relationships/state/has-many.js | 15 +- .../relationships/state/relationship.js | 6 +- packages/ember-data/lib/system/snapshot.js | 18 +- packages/ember-data/lib/system/store.js | 181 +++-- .../ember-data/lib/system/store/finders.js | 20 +- .../integration/adapter/rest-adapter-test.js | 2 +- .../integration/adapter/store-adapter-test.js | 2 +- .../tests/integration/lifecycle-hooks-test.js | 4 +- .../integration/record-array-manager-test.js | 6 +- .../tests/integration/records/save-test.js | 15 +- .../relationships/belongs-to-test.js | 12 +- .../relationships/has-many-test.js | 18 +- packages/ember-data/tests/unit/model-test.js | 12 +- .../tests/unit/model/internal-model-test.js | 19 + .../unit/model/lifecycle-callbacks-test.js | 26 + .../model/relationships/record-array-test.js | 7 +- .../tests/unit/store/unload-test.js | 4 +- 30 files changed, 1027 insertions(+), 686 deletions(-) create mode 100644 packages/ember-data/lib/system/model/internal-model.js create mode 100644 packages/ember-data/tests/unit/model/internal-model-test.js diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index 1def75f8607..d5a28b47a5a 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -19,6 +19,8 @@ import "ember-data/ext/date"; import normalizeModelName from "ember-data/system/normalize-model-name"; +import InternalModel from "ember-data/system/model/internal-model"; + import { PromiseArray, PromiseObject, @@ -85,6 +87,7 @@ DS.RootState = RootState; DS.attr = attr; DS.Errors = Errors; +DS.InternalModel = InternalModel; DS.Snapshot = Snapshot; DS.Adapter = Adapter; diff --git a/packages/ember-data/lib/system/many-array.js b/packages/ember-data/lib/system/many-array.js index be0ff78d696..23d614679bf 100644 --- a/packages/ember-data/lib/system/many-array.js +++ b/packages/ember-data/lib/system/many-array.js @@ -6,6 +6,7 @@ import { PromiseArray } from "ember-data/system/promise-proxies"; var get = Ember.get; var set = Ember.set; var filter = Ember.ArrayPolyfills.filter; +var map = Ember.EnumerableUtils.map; /** A `ManyArray` is a `MutableArray` that represents the contents of a has-many @@ -57,19 +58,23 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { length: 0, objectAt: function(index) { - return this.currentState[index]; + //Ember observers such as 'firstObject', 'lastObject' might do out of bounds accesses + if (!this.currentState[index]) { + return undefined; + } + return this.currentState[index].getRecord(); }, flushCanonical: function() { //TODO make this smarter, currently its plenty stupid - var toSet = filter.call(this.canonicalState, function(record) { - return !record.get('isDeleted'); + var toSet = filter.call(this.canonicalState, function(internalModel) { + return !internalModel.isDeleted(); }); //a hack for not removing new records //TODO remove once we have proper diffing - var newRecords = this.currentState.filter(function(record) { - return record.get('isNew'); + var newRecords = this.currentState.filter(function(internalModel) { + return internalModel.isNew(); }); toSet = toSet.concat(newRecords); var oldLength = this.length; @@ -143,7 +148,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { this.get('relationship').removeRecords(records); } if (objects) { - this.get('relationship').addRecords(objects, idx); + this.get('relationship').addRecords(map(objects, function(obj) { return obj._internalModel; }), idx); } }, /** diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 505d4bd38bd..ff232ffce6e 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -300,25 +300,27 @@ export default function attr(type, options) { return computedPolyfill({ get: function(key) { - if (hasValue(this, key)) { - return getValue(this, key); + var internalModel = this._internalModel; + if (hasValue(internalModel, key)) { + return getValue(internalModel, key); } else { return getDefaultValue(this, options, key); } }, set: function(key, value) { Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.constructor.toString(), key !== 'id'); - var oldValue = getValue(this, key); + var internalModel = this._internalModel; + var oldValue = getValue(internalModel, key); if (value !== oldValue) { // Add the new value to the changed attributes hash; it will get deleted by // the 'didSetProperty' handler if it is no different from the original value - this._attributes[key] = value; + internalModel._attributes[key] = value; - this.send('didSetProperty', { + this._internalModel.send('didSetProperty', { name: key, oldValue: oldValue, - originalValue: this._data[key], + originalValue: internalModel._data[key], value: value }); } diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js new file mode 100644 index 00000000000..c28de2fac09 --- /dev/null +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -0,0 +1,694 @@ +import merge from "ember-data/system/merge"; +import RootState from "ember-data/system/model/states"; +import createRelationshipFor from "ember-data/system/relationships/state/create"; +import Snapshot from "ember-data/system/snapshot"; +import Errors from "ember-data/system/model/errors"; + +var Promise = Ember.RSVP.Promise; +var get = Ember.get; +var set = Ember.set; +var forEach = Ember.ArrayPolyfills.forEach; +var map = Ember.ArrayPolyfills.map; + +var _extractPivotNameCache = Ember.create(null); +var _splitOnDotCache = Ember.create(null); + +function splitOnDot(name) { + return _splitOnDotCache[name] || ( + _splitOnDotCache[name] = name.split('.') + ); +} + +function extractPivotName(name) { + return _extractPivotNameCache[name] || ( + _extractPivotNameCache[name] = splitOnDot(name)[0] + ); +} + +function retrieveFromCurrentState(key) { + return function() { + return get(this.currentState, key); + }; +} + +/** + `InternalModel` is the Model class that we use internally inside Ember Data to represent models. + Internal ED methods should only deal with `InternalModel` objects. It is a fast, plain Javascript class. + + We expose `DS.Model` to application code, by materializing a `DS.Model` from `InternalModel` lazily, as + a performance optimization. + + `InternalModel` should never be exposed to application code. At the boundaries of the system, in places + like `find`, `push`, etc. we convert between Models and InternalModels. + + We need to make sure that the properties from `InternalModel` are correctly exposed/proxied on `Model` + if they are needed. + + @class InternalModel +*/ + +var InternalModel = function InternalModel(type, id, store, container, data) { + this.type = type; + this.id = id; + this.store = store; + this.container = container; + this._data = data || {}; + this.modelName = type.modelName; + this.errors = null; + this.dataHasInitialized = false; + //Look into making this lazy + this._deferredTriggers = []; + this._data = {}; + this._attributes = Ember.create(null); + this._inFlightAttributes = Ember.create(null); + this._relationships = {}; + this.currentState = RootState.empty; + this.isReloading = false; + /* + implicit relationships are relationship which have not been declared but the inverse side exists on + another record somewhere + For example if there was + ``` + App.Comment = DS.Model.extend({ + name: DS.attr() + }) + ``` + but there is also + ``` + App.Post = DS.Model.extend({ + name: DS.attr(), + comments: DS.hasMany('comment') + }) + ``` + + would have a implicit post relationship in order to be do things like remove ourselves from the post + when we are deleted + */ + this._implicitRelationships = Ember.create(null); + var model = this; + //TODO Move into a getter for better perf + this.eachRelationship(function(key, descriptor) { + model._relationships[key] = createRelationshipFor(model, descriptor, model.store); + }); +}; + +InternalModel.prototype = { + isEmpty: retrieveFromCurrentState('isEmpty'), + isLoading: retrieveFromCurrentState('isLoading'), + isLoaded: retrieveFromCurrentState('isLoaded'), + isDirty: retrieveFromCurrentState('isDirty'), + isSaving: retrieveFromCurrentState('isSaving'), + isDeleted: retrieveFromCurrentState('isDeleted'), + isNew: retrieveFromCurrentState('isNew'), + isValid: retrieveFromCurrentState('isValid'), + dirtyType: retrieveFromCurrentState('dirtyType'), + + constructor: InternalModel, + materializeRecord: function() { + Ember.assert("Materialized " + this.modelName + " record with id:" + this.id + "more than once", this.record === null || this.record === undefined); + // lookupFactory should really return an object that creates + // instances with the injections applied + this.record = this.type._create({ + id: this.id, + store: this.store, + container: this.container + }); + this.record._internalModel = this; + this._triggerDeferredTriggers(); + }, + + recordObjectWillDestroy: function() { + this.record = null; + }, + + deleteRecord: function() { + this.send('deleteRecord'); + }, + + save: function() { + var promiseLabel = "DS: Model#save " + this; + var resolver = Ember.RSVP.defer(promiseLabel); + + this.store.scheduleSave(this, resolver); + return resolver.promise; + }, + + startedReloading: function() { + this.isReloading = true; + if (this.record) { + set(this.record, 'isReloading', true); + } + }, + + finishedReloading: function() { + this.isReloading = false; + if (this.record) { + set(this.record, 'isReloading', false); + } + }, + + reload: function() { + this.startedReloading(); + var record = this; + var promiseLabel = "DS: Model#reload of " + this; + return new Promise(function(resolve) { + record.send('reloadRecord', resolve); + }, promiseLabel).then(function() { + record.didCleanError(); + return record; + }, function(reason) { + record.didError(); + throw reason; + }, "DS: Model#reload complete, update flags").finally(function () { + record.finishedReloading(); + record.updateRecordArrays(); + }); + }, + + getRecord: function() { + if (!this.record) { + this.materializeRecord(); + } + return this.record; + }, + + unloadRecord: function() { + this.send('unloadRecord'); + }, + + eachRelationship: function(callback, binding) { + return this.type.eachRelationship(callback, binding); + }, + + eachAttribute: function(callback, binding) { + return this.type.eachAttribute(callback, binding); + }, + + inverseFor: function(key) { + return this.type.inverseFor(key); + }, + + setupData: function(data) { + var changedKeys = mergeAndReturnChangedKeys(this._data, data); + this.pushedData(); + if (this.record) { + this.record._notifyProperties(changedKeys); + } + this.didInitalizeData(); + }, + + becameReady: function() { + Ember.run.schedule('actions', this.store.recordArrayManager, this.store.recordArrayManager.recordWasLoaded, this); + }, + + didInitalizeData: function() { + if (!this.dataHasInitialized) { + this.becameReady(); + this.dataHasInitialized = true; + } + }, + + destroy: function() { + if (this.record) { + return this.record.destroy(); + } + }, + + /** + @method _createSnapshot + @private + */ + _createSnapshot: function() { + return new Snapshot(this); + }, + + /** + @method loadingData + @private + @param {Promise} promise + */ + loadingData: function(promise) { + this.send('loadingData', promise); + }, + + /** + @method loadedData + @private + */ + loadedData: function() { + this.send('loadedData'); + this.didInitalizeData(); + }, + + /** + @method notFound + @private + */ + notFound: function() { + this.send('notFound'); + }, + + /** + @method pushedData + @private + */ + pushedData: function() { + this.send('pushedData'); + }, + + flushChangedAttributes: function() { + this._inFlightAttributes = this._attributes; + this._attributes = Ember.create(null); + }, + + /** + @method adapterWillCommit + @private + */ + adapterWillCommit: function() { + this.flushChangedAttributes(); + this.send('willCommit'); + }, + + /** + @method adapterDidDirty + @private + */ + adapterDidDirty: function() { + this.send('becomeDirty'); + this.updateRecordArraysLater(); + }, + + /** + @method send + @private + @param {String} name + @param {Object} context + */ + send: function(name, context) { + var currentState = get(this, 'currentState'); + + if (!currentState[name]) { + this._unhandledEvent(currentState, name, context); + } + + return currentState[name](this, context); + }, + + notifyHasManyAdded: function(key, record, idx) { + if (this.record) { + this.record.notifyHasManyAdded(key, record, idx); + } + }, + + notifyHasManyRemoved: function(key, record, idx) { + if (this.record) { + this.record.notifyHasManyRemoved(key, record, idx); + } + }, + + notifyBelongsToChanged: function(key, record) { + if (this.record) { + this.record.notifyBelongsToChanged(key, record); + } + }, + + notifyPropertyChange: function(key) { + if (this.record) { + this.record.notifyPropertyChange(key); + } + }, + + rollback: function() { + var dirtyKeys = Ember.keys(this._attributes); + + this._attributes = Ember.create(null); + + if (get(this, 'isError')) { + this._inFlightAttributes = Ember.create(null); + this.didCleanError(); + } + + //Eventually rollback will always work for relationships + //For now we support it only out of deleted state, because we + //have an explicit way of knowing when the server acked the relationship change + if (this.isDeleted()) { + //TODO: Should probably move this to the state machine somehow + this.becameReady(); + this.reconnectRelationships(); + } + + if (this.isNew()) { + this.clearRelationships(); + } + + if (this.isValid()) { + this._inFlightAttributes = Ember.create(null); + } + + this.send('rolledBack'); + + this.record._notifyProperties(dirtyKeys); + + }, + /** + @method transitionTo + @private + @param {String} name + */ + transitionTo: function(name) { + // POSSIBLE TODO: Remove this code and replace with + // always having direct reference to state objects + + var pivotName = extractPivotName(name); + var currentState = get(this, 'currentState'); + var state = currentState; + + do { + if (state.exit) { state.exit(this); } + state = state.parentState; + } while (!state.hasOwnProperty(pivotName)); + + var path = splitOnDot(name); + var setups = []; + var enters = []; + var i, l; + + for (i=0, l=path.length; i { + recordErrors.add(key, errors[key]); + }); + this._saveWasRejected(); + }, + + /** + @method adapterDidError + @private + */ + adapterDidError: function() { + this.send('becameError'); + this.didError(); + this._saveWasRejected(); + }, + + _saveWasRejected: function() { + var keys = Ember.keys(this._inFlightAttributes); + for (var i=0; i < keys.length; i++) { + if (this._attributes[keys[i]] === undefined) { + this._attributes[keys[i]] = this._inFlightAttributes[keys[i]]; + } + } + this._inFlightAttributes = Ember.create(null); + } +}; + +// Like Ember.merge, but instead returns a list of keys +// for values that fail a strict equality check +// instead of the original object. +function mergeAndReturnChangedKeys(original, updates) { + var changedKeys = []; + + if (!updates || typeof updates !== 'object') { + return changedKeys; + } + + var keys = Ember.keys(updates); + var length = keys.length; + var i, val, key; + + for (i = 0; i < length; i++) { + key = keys[i]; + val = updates[key]; + + if (original[key] !== val) { + changedKeys.push(key); + } + + original[key] = val; + } + return changedKeys; +} + +export default InternalModel; diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index e435865e9af..bdd8cd975a9 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1,74 +1,28 @@ -import RootState from "ember-data/system/model/states"; -import Errors from "ember-data/system/model/errors"; import { PromiseObject } from "ember-data/system/promise-proxies"; -import merge from "ember-data/system/merge"; import JSONSerializer from "ember-data/serializers/json-serializer"; -import createRelationshipFor from "ember-data/system/relationships/state/create"; -import Snapshot from "ember-data/system/snapshot"; /** @module ember-data */ var get = Ember.get; -var set = Ember.set; -var Promise = Ember.RSVP.Promise; -var forEach = Ember.ArrayPolyfills.forEach; -var map = Ember.ArrayPolyfills.map; var intersection = Ember.EnumerableUtils.intersection; var RESERVED_MODEL_PROPS = [ 'currentState', 'data', 'store' ]; var retrieveFromCurrentState = Ember.computed('currentState', function(key) { - return get(get(this, 'currentState'), key); + return get(this._internalModel.currentState, key); }).readOnly(); -var _extractPivotNameCache = Ember.create(null); -var _splitOnDotCache = Ember.create(null); - -function splitOnDot(name) { - return _splitOnDotCache[name] || ( - _splitOnDotCache[name] = name.split('.') - ); -} - -function extractPivotName(name) { - return _extractPivotNameCache[name] || ( - _extractPivotNameCache[name] = splitOnDot(name)[0] - ); -} - -// Like Ember.merge, but instead returns a list of keys -// for values that fail a strict equality check -// instead of the original object. -function mergeAndReturnChangedKeys(original, updates) { - var changedKeys = []; - - if (!updates || typeof updates !== 'object') { - return changedKeys; - } - - var keys = Ember.keys(updates); - var length = keys.length; - var i, val, key; - - for (i = 0; i < length; i++) { - key = keys[i]; - val = updates[key]; - - if (original[key] !== val) { - changedKeys.push(key); - } - - original[key] = val; - } - return changedKeys; -} /** The model class that all Ember Data records descend from. + This is the public API of Ember Data models. If you are using Ember Data + in your application, this is the class you should use. + If you are working on Ember Data internals, you most likely want to be dealing + with `InternalModel` @class Model @namespace DS @@ -288,6 +242,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @readOnly */ isError: false, + /** If `true` the store is attempting to reload the record form the adapter. @@ -305,17 +260,6 @@ var Model = Ember.Object.extend(Ember.Evented, { */ isReloading: false, - /** - The `clientId` property is a transient numerical identifier - generated at runtime by the data store. It is important - primarily because newly created objects may not yet have an - externally generated id. - - @property clientId - @private - @type {Number|String} - */ - clientId: null, /** All ember models have an id property. This is an identifier managed by an external source. These are always coerced to be @@ -342,7 +286,6 @@ var Model = Ember.Object.extend(Ember.Evented, { @private @type {Object} */ - currentState: RootState.empty, /** When the record is in the `invalid` state this object will contain @@ -396,15 +339,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @type {DS.Errors} */ errors: Ember.computed(function() { - var errors = Errors.create(); - - errors.registerHandlers(this, function() { - this.send('becameInvalid'); - }, function() { - this.send('becameValid'); - }); - - return errors; + return this._internalModel.getErrors(); }).readOnly(), /** @@ -453,9 +388,8 @@ var Model = Ember.Object.extend(Ember.Evented, { @event ready */ - ready: function() { - this.store.recordArrayManager.recordWasLoaded(this); - }, + ready: Ember.K, + /** Fired when the record is loaded from the server. @@ -515,49 +449,8 @@ var Model = Ember.Object.extend(Ember.Evented, { return this._data; }).readOnly(), - _data: null, - - init: function() { - this._super.apply(this, arguments); - this._setup(); - }, - - _setup: function() { - this._changesToSync = {}; - this._deferredTriggers = []; - this._data = {}; - this._attributes = Ember.create(null); - this._inFlightAttributes = Ember.create(null); - this._relationships = {}; - /* - implicit relationships are relationship which have not been declared but the inverse side exists on - another record somewhere - For example if there was - ``` - App.Comment = DS.Model.extend({ - name: DS.attr() - }) - ``` - but there is also - ``` - App.Post = DS.Model.extend({ - name: DS.attr(), - comments: DS.hasMany('comment') - }) - ``` - - would have a implicit post relationship in order to be do things like remove ourselves from the post - when we are deleted - */ - this._implicitRelationships = Ember.create(null); - var model = this; - //TODO Move into a getter for better perf - this.constructor.eachRelationship(function(key, descriptor) { - model._relationships[key] = createRelationshipFor(model, descriptor, model.store); - }); - - }, + //TODO Do we want to deprecate these? /** @method send @private @@ -565,13 +458,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @param {Object} context */ send: function(name, context) { - var currentState = get(this, 'currentState'); - - if (!currentState[name]) { - this._unhandledEvent(currentState, name, context); - } - - return currentState[name](this, context); + return this._internalModel.send(name, context); }, /** @@ -580,92 +467,9 @@ var Model = Ember.Object.extend(Ember.Evented, { @param {String} name */ transitionTo: function(name) { - // POSSIBLE TODO: Remove this code and replace with - // always having direct references to state objects - - var pivotName = extractPivotName(name); - var currentState = get(this, 'currentState'); - var state = currentState; - - do { - if (state.exit) { state.exit(this); } - state = state.parentState; - } while (!state.hasOwnProperty(pivotName)); - - var path = splitOnDot(name); - var setups = []; - var enters = []; - var i, l; - - for (i=0, l=path.length; i model.getRecord()); + } + return promiseObject(toReturn, label); +} + var get = Ember.get; var set = Ember.set; var once = Ember.run.once; @@ -113,7 +129,7 @@ if (!Service) { // * +clientId+ means a transient numerical identifier generated at runtime by // the data store. It is important primarily because newly created objects may // not yet have an externally generated id. -// * +reference+ means a record reference object, which holds metadata about a +// * +internalModel+ means a record internalModel object, which holds metadata about a // record, even if it has not yet been fully materialized. // * +type+ means a subclass of DS.Model. @@ -321,17 +337,18 @@ Store = Service.extend({ // Coerce ID to a string properties.id = coerceId(properties.id); - var record = this.buildRecord(typeClass, properties.id); + var internalModel = this.buildInternalModel(typeClass, properties.id); + var record = internalModel.getRecord(); // Move the record out of its initial `empty` state into // the `loaded` state. - record.loadedData(); + internalModel.loadedData(); // Set the properties specified on the record. record.setProperties(properties); - record.eachRelationship(function(key, descriptor) { - record._relationships[key].setHasData(true); + internalModel.eachRelationship(function(key, descriptor) { + internalModel._relationships[key].setHasData(true); }); return record; @@ -598,29 +615,28 @@ Store = Service.extend({ */ findById: function(modelName, id, preload) { - var typeClass = this.modelFor(modelName); - var record = this.recordForId(typeClass, id); + var type = this.modelFor(modelName); + var internalModel = this._internalModelForId(type, id); - return this._findByRecord(record, preload); + return this._findByInternalModel(internalModel, preload); }, - _findByRecord: function(record, preload) { - var fetchedRecord; + _findByInternalModel: function(internalModel, preload) { + var fetchedInternalModel; if (preload) { - record._preloadData(preload); + internalModel._preloadData(preload); } - if (get(record, 'isEmpty')) { - fetchedRecord = this.scheduleFetch(record); + if (internalModel.isEmpty()) { + fetchedInternalModel = this.scheduleFetch(internalModel); //TODO double check about reloading - } else if (get(record, 'isLoading')) { - fetchedRecord = record._loadingPromise; + } else if (internalModel.isLoading()) { + fetchedInternalModel = internalModel._loadingPromise; } - return promiseObject(fetchedRecord || record, "DS: Store#findByRecord " + record.modelName + " with id: " + get(record, 'id')); + return promiseRecord(fetchedInternalModel || internalModel, "DS: Store#findByRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id')); }, - /** This method makes a series of requests to the adapter's `find` method and returns a promise that resolves once they are all loaded. @@ -650,7 +666,7 @@ Store = Service.extend({ @return {Promise} promise */ fetchRecord: function(record) { - var typeClass = record.constructor; + var typeClass = record.type; var id = get(record, 'id'); var adapter = this.adapterFor(typeClass); @@ -662,15 +678,17 @@ Store = Service.extend({ }, scheduleFetchMany: function(records) { - return Promise.all(map(records, this.scheduleFetch, this)); + var internalModel = map(records, function(record) { return record._internalModel; }); + return Promise.all(map(internalModel, this.scheduleFetch, this)); }, scheduleFetch: function(record) { - var typeClass = record.constructor; + var typeClass = record.type; + if (isNone(record)) { return null; } if (record._loadingPromise) { return record._loadingPromise; } - var resolver = Ember.RSVP.defer('Fetching ' + typeClass + 'with id: ' + record.get('id')); + var resolver = Ember.RSVP.defer('Fetching ' + typeClass + 'with id: ' + record.id); var recordResolverPair = { record: record, resolver: resolver @@ -766,7 +784,7 @@ Store = Service.extend({ var snapshots = Ember.A(records).invoke('_createSnapshot'); var groups = adapter.groupRecordsForFindMany(this, snapshots); forEach(groups, function (groupOfSnapshots) { - var groupOfRecords = Ember.A(groupOfSnapshots).mapBy('record'); + var groupOfRecords = Ember.A(groupOfSnapshots).mapBy('record._internalModel'); var requestedRecords = Ember.A(groupOfRecords); var ids = requestedRecords.mapBy('id'); if (ids.length > 1) { @@ -808,7 +826,7 @@ Store = Service.extend({ */ getById: function(type, id) { if (this.hasRecordForId(type, id)) { - return this.recordForId(type, id); + return this._internalModelForId(type, id).getRecord(); } else { return null; } @@ -850,7 +868,7 @@ Store = Service.extend({ var typeClass = this.modelFor(modelName); var id = coerceId(inputId); var record = this.typeMapFor(typeClass).idToRecord[id]; - return !!record && get(record, 'isLoaded'); + return !!record && record.isLoaded(); }, /** @@ -863,32 +881,35 @@ Store = Service.extend({ @param {String|Integer} id @return {DS.Model} record */ - recordForId: function(modelName, inputId) { - var typeClass = this.modelFor(modelName); + recordForId: function(modelName, id) { + return this._internalModelForId(modelName, id).getRecord(); + }, + + _internalModelForId: function(typeName, inputId) { + var typeClass = this.modelFor(typeName); var id = coerceId(inputId); var idToRecord = this.typeMapFor(typeClass).idToRecord; var record = idToRecord[id]; if (!record || !idToRecord[id]) { - record = this.buildRecord(typeClass, id); + record = this.buildInternalModel(typeClass, id); } return record; }, + + /** @method findMany @private - @param {DS.Model} owner - @param {Array} records - @param {String or subclass of DS.Model} type - @param {Resolver} resolver + @param {Array} internalModels @return {Promise} promise */ - findMany: function(records) { + findMany: function(internalModels) { var store = this; - return Promise.all(map(records, function(record) { - return store._findByRecord(record); + return Promise.all(map(internalModels, function(internalModel) { + return store._findByInternalModel(internalModel); })); }, @@ -912,9 +933,9 @@ Store = Service.extend({ @return {Promise} promise */ findHasMany: function(owner, link, type) { - var adapter = this.adapterFor(owner.constructor); + var adapter = this.adapterFor(owner.type); - Ember.assert("You tried to load a hasMany relationship but you have no adapter (for " + owner.constructor + ")", adapter); + Ember.assert("You tried to load a hasMany relationship but you have no adapter (for " + owner.type + ")", adapter); Ember.assert("You tried to load a hasMany relationship from a specified `link` in the original payload but your adapter does not implement `findHasMany`", typeof adapter.findHasMany === 'function'); return _findHasMany(adapter, this, owner, link, type); @@ -929,9 +950,9 @@ Store = Service.extend({ @return {Promise} promise */ findBelongsTo: function(owner, link, relationship) { - var adapter = this.adapterFor(owner.constructor); + var adapter = this.adapterFor(owner.type); - Ember.assert("You tried to load a belongsTo relationship but you have no adapter (for " + owner.constructor + ")", adapter); + Ember.assert("You tried to load a belongsTo relationship but you have no adapter (for " + owner.type + ")", adapter); Ember.assert("You tried to load a belongsTo relationship from a specified `link` in the original payload but your adapter does not implement `findBelongsTo`", typeof adapter.findBelongsTo === 'function'); return _findBelongsTo(adapter, this, owner, link, relationship); @@ -1190,8 +1211,7 @@ Store = Service.extend({ @return {boolean} */ recordIsLoaded: function(type, id) { - if (!this.hasRecordForId(type, id)) { return false; } - return !get(this.recordForId(type, id), 'isEmpty'); + return this.hasRecordForId(type, id); }, /** @@ -1274,15 +1294,15 @@ Store = Service.extend({ forEach(pending, function(tuple) { var snapshot = tuple[0]; var resolver = tuple[1]; - var record = snapshot.record; - var adapter = this.adapterFor(record.constructor); + var record = snapshot._internalModel; + var adapter = this.adapterFor(record.type); var operation; if (get(record, 'currentState.stateName') === 'root.deleted.saved') { - return resolver.resolve(record); - } else if (get(record, 'isNew')) { + return resolver.resolve(); + } else if (record.isNew()) { operation = 'createRecord'; - } else if (get(record, 'isDeleted')) { + } else if (record.isDeleted()) { operation = 'deleteRecord'; } else { operation = 'updateRecord'; @@ -1308,7 +1328,7 @@ Store = Service.extend({ didSaveRecord: function(record, data) { if (data) { // normalize relationship IDs into records - this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', record, record.constructor, data); + this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', record, record.type, data); this.updateId(record, data); } @@ -1360,9 +1380,9 @@ Store = Service.extend({ Ember.assert("An adapter cannot assign a new id to a record that already has an id. " + record + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId); - this.typeMapFor(record.constructor).idToRecord[id] = record; + this.typeMapFor(record.type).idToRecord[id] = record; - set(record, 'id', id); + record.setId(id); }, /** @@ -1406,12 +1426,13 @@ Store = Service.extend({ */ _load: function(type, data) { var id = coerceId(data.id); - var record = this.recordForId(type, id); + var internalModel = this._internalModelForId(type, id); - record.setupData(data); - this.recordArrayManager.recordDidChange(record); + internalModel.setupData(data); - return record; + this.recordArrayManager.recordDidChange(internalModel); + + return internalModel; }, /* @@ -1484,7 +1505,11 @@ Store = Service.extend({ configurable: false, get: function() { Ember.deprecate('Usage of `typeKey` has been deprecated and will be removed in Ember Data 1.0. It has been replaced by `modelName` on the model class.'); - return Ember.String.camelize(this.modelName); + var typeKey = this.modelName; + if (typeKey) { + typeKey = Ember.String.camelize(this.modelName); + } + return typeKey; }, set: function() { Ember.assert('Setting typeKey is not supported. In addition, typeKey has also been deprecated in favor of modelName. Setting modelName is also not supported.'); @@ -1569,6 +1594,11 @@ Store = Service.extend({ updated. */ push: function(modelName, data) { + var internalModel = this._pushInternalModel(modelName, data); + return internalModel.getRecord(); + }, + + _pushInternalModel: function(modelName, data) { Ember.assert("Expected an object as `data` in a call to `push` for " + modelName + " , but was " + data, Ember.typeOf(data) === 'object'); Ember.assert("You must include an `id` for " + modelName + " in an object passed to `push`", data.id != null && data.id !== ''); @@ -1589,17 +1619,15 @@ Store = Service.extend({ } // Actually load the record into the store. + var internalModel = this._load(type, data); - this._load(type, data); - - var record = this.recordForId(type, data.id); var store = this; this._backburner.join(function() { - store._backburner.schedule('normalizeRelationships', store, '_setupRelationships', record, type, data); + store._backburner.schedule('normalizeRelationships', store, '_setupRelationships', internalModel, type, data); }); - return record; + return internalModel; }, _setupRelationships: function(record, type, data) { @@ -1758,7 +1786,7 @@ Store = Service.extend({ @param {Object} data @return {DS.Model} record */ - buildRecord: function(type, id, data) { + buildInternalModel: function(type, id, data) { var typeMap = this.typeMapFor(type); var idToRecord = typeMap.idToRecord; @@ -1767,25 +1795,17 @@ Store = Service.extend({ // lookupFactory should really return an object that creates // instances with the injections applied - var record = type._create({ - id: id, - store: this, - container: this.container - }); - - if (data) { - record.setupData(data); - } + var internalModel = new InternalModel(type, id, this, this.container, data); // if we're creating an item, this process will be done // later, once the object has been persisted. if (id) { - idToRecord[id] = record; + idToRecord[id] = internalModel; } - typeMap.records.push(record); + typeMap.records.push(internalModel); - return record; + return internalModel; }, //Called by the state machine to notify the store that the record is ready to be interacted with @@ -1817,7 +1837,7 @@ Store = Service.extend({ @param {DS.Model} record */ _dematerializeRecord: function(record) { - var type = record.constructor; + var type = record.type; var typeMap = this.typeMapFor(type); var id = get(record, 'id'); @@ -1979,20 +1999,27 @@ function normalizeRelationships(store, type, data, record) { } function deserializeRecordId(store, data, key, relationship, id) { - if (isNone(id) || id instanceof Model) { + if (isNone(id)) { return; } + + //If record objects were given to push directly, uncommon, not sure whether we should actually support + if (id instanceof Model) { + data[key] = id._internalModel; + return; + } + Ember.assert("A " + relationship.parentType + " record was pushed into the store with the value of " + key + " being " + Ember.inspect(id) + ", but " + key + " is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.", !Ember.isArray(id)); var type; if (typeof id === 'number' || typeof id === 'string') { type = typeFor(relationship, key, data); - data[key] = store.recordForId(type, id); + data[key] = store._internalModelForId(type, id); } else if (typeof id === 'object') { // hasMany polymorphic Ember.assert('Ember Data expected a number or string to represent the record(s) in the `' + relationship.key + '` relationship instead it found an object. If this is a polymorphic relationship please specify a `type` key. If this is an embedded relationship please include the `DS.EmbeddedRecordsMixin` and specify the `' + relationship.key +'` property in your serializer\'s attrs object.', id.type); - data[key] = store.recordForId(id.type, id.id); + data[key] = store._internalModelForId(id.type, id.id); } } @@ -2025,7 +2052,7 @@ function defaultSerializer(container) { } function _commit(adapter, store, operation, snapshot) { - var record = snapshot.record; + var record = snapshot._internalModel; var type = snapshot.type; var promise = adapter[operation](store, type, snapshot); var serializer = serializerForAdapter(store, adapter, type); @@ -2062,7 +2089,7 @@ function _commit(adapter, store, operation, snapshot) { } function setupRelationships(store, record, data) { - var typeClass = record.constructor; + var typeClass = record.type; typeClass.eachRelationship(function(key, descriptor) { var kind = descriptor.kind; diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index 4697be92462..27b5707e3bb 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -9,8 +9,8 @@ import { } from "ember-data/system/store/serializers"; -var get = Ember.get; var Promise = Ember.RSVP.Promise; +var map = Ember.EnumerableUtils.map; export function _find(adapter, store, typeClass, id, record) { var snapshot = record._createSnapshot(); @@ -26,12 +26,14 @@ export function _find(adapter, store, typeClass, id, record) { return store._adapterRun(function() { var payload = serializer.extract(store, typeClass, adapterPayload, id, 'find'); - return store.push(typeClass, payload); + //TODO Optimize + var record = store.push(typeClass, payload); + return record._internalModel; }); }, function(error) { record.notFound(); - if (get(record, 'isEmpty')) { - store.unloadRecord(record); + if (record.isEmpty()) { + record.unloadRecord(); } throw error; @@ -58,7 +60,9 @@ export function _findMany(adapter, store, typeClass, ids, records) { Ember.assert("The response from a findMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); - return store.pushMany(typeClass, payload); + //TODO Optimize, no need to materialize here + var records = store.pushMany(typeClass, payload); + return map(records, function(record) { return record._internalModel; }); }); }, null, "DS: Extract payload of " + typeClass); } @@ -79,8 +83,9 @@ export function _findHasMany(adapter, store, record, link, relationship) { Ember.assert("The response from a findHasMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); + //TODO Use a non record creating push var records = store.pushMany(relationship.type, payload); - return records; + return map(records, function(record) { return record._internalModel; }); }); }, null, "DS: Extract payload of " + record + " : hasMany " + relationship.type); } @@ -104,7 +109,8 @@ export function _findBelongsTo(adapter, store, record, link, relationship) { } var record = store.push(relationship.type, payload); - return record; + //TODO Optimize + return record._internalModel; }); }, null, "DS: Extract payload of " + record + " : " + relationship.type); } diff --git a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js b/packages/ember-data/tests/integration/adapter/rest-adapter-test.js index 7098801ca74..5b2e2218b02 100644 --- a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js +++ b/packages/ember-data/tests/integration/adapter/rest-adapter-test.js @@ -486,7 +486,7 @@ test("create - response can contain relationships the client doesn't yet know ab var postRecords = store.typeMapFor(Post).records; for (var i = 0; i < postRecords.length; i++) { - equal(post, postRecords[i], "The object in the identity map is the same"); + equal(post, postRecords[i].getRecord(), "The object in the identity map is the same"); } })); }); diff --git a/packages/ember-data/tests/integration/adapter/store-adapter-test.js b/packages/ember-data/tests/integration/adapter/store-adapter-test.js index 50e854e3eb1..605b13c9f1a 100644 --- a/packages/ember-data/tests/integration/adapter/store-adapter-test.js +++ b/packages/ember-data/tests/integration/adapter/store-adapter-test.js @@ -664,7 +664,7 @@ test("if a updated record is marked as erred by the server, it enters an error s }; var person = run(function() { - return store.push(Person, { id: 1, name: "John Doe" }); + return store.push('person', { id: 1, name: "John Doe" }); }); run(store, 'find', 'person', 1).then(async(function(record) { diff --git a/packages/ember-data/tests/integration/lifecycle-hooks-test.js b/packages/ember-data/tests/integration/lifecycle-hooks-test.js index dab3da4c7a6..3625e35c9e0 100644 --- a/packages/ember-data/tests/integration/lifecycle-hooks-test.js +++ b/packages/ember-data/tests/integration/lifecycle-hooks-test.js @@ -28,7 +28,7 @@ asyncTest("When the adapter acknowledges that a record has been created, a `didC var person; run(function() { - person = env.store.createRecord(Person, { name: "Yehuda Katz" }); + person = env.store.createRecord('person', { name: "Yehuda Katz" }); }); person.on('didCreate', function() { @@ -50,7 +50,7 @@ test("When the adapter acknowledges that a record has been created without a new var person; run(function() { - person = env.store.createRecord(Person, { id: 99, name: "Yehuda Katz" }); + person = env.store.createRecord('person', { id: 99, name: "Yehuda Katz" }); }); person.on('didCreate', function() { diff --git a/packages/ember-data/tests/integration/record-array-manager-test.js b/packages/ember-data/tests/integration/record-array-manager-test.js index fbef834d1b8..f059fff3787 100644 --- a/packages/ember-data/tests/integration/record-array-manager-test.js +++ b/packages/ember-data/tests/integration/record-array-manager-test.js @@ -84,17 +84,17 @@ test("destroying the store correctly cleans everything up", function() { equal(filterd2Summary.called.length, 0); - equal(person._recordArrays.list.length, 2, 'expected the person to be a member of 2 recordArrays'); + equal(person._internalModel._recordArrays.list.length, 2, 'expected the person to be a member of 2 recordArrays'); Ember.run(filterd2, filterd2.destroy); - equal(person._recordArrays.list.length, 1, 'expected the person to be a member of 1 recordArrays'); + equal(person._internalModel._recordArrays.list.length, 1, 'expected the person to be a member of 1 recordArrays'); equal(filterd2Summary.called.length, 1); Ember.run(manager, manager.destroy); - equal(person._recordArrays.list.length, 0, 'expected the person to be a member of no recordArrays'); + equal(person._internalModel._recordArrays.list.length, 0, 'expected the person to be a member of no recordArrays'); equal(filterd2Summary.called.length, 1); diff --git a/packages/ember-data/tests/integration/records/save-test.js b/packages/ember-data/tests/integration/records/save-test.js index cc432f3169d..10fc17fbd50 100644 --- a/packages/ember-data/tests/integration/records/save-test.js +++ b/packages/ember-data/tests/integration/records/save-test.js @@ -18,19 +18,28 @@ module("integration/records/save - Save Record", { }); test("Will resolve save on success", function() { - expect(1); + expect(4); var post; run(function() { post = env.store.createRecord('post', { title: 'toto' }); }); + var deferred = Ember.RSVP.defer(); env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ id: 123 }); + return deferred.promise; }; run(function() { - post.save().then(function() { + var saved = post.save(); + + // `save` returns a PromiseObject which allows to call get on it + equal(saved.get('id'), undefined); + + deferred.resolve({ id: 123 }); + saved.then(function(model) { ok(true, 'save operation was resolved'); + equal(saved.get('id'), 123); + equal(model, post, "resolves with the model"); }); }); }); diff --git a/packages/ember-data/tests/integration/relationships/belongs-to-test.js b/packages/ember-data/tests/integration/relationships/belongs-to-test.js index a906968a355..8a38c9006a9 100644 --- a/packages/ember-data/tests/integration/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/integration/relationships/belongs-to-test.js @@ -602,7 +602,7 @@ test("belongsTo hasData async loaded", function () { run(function() { store.find('book', 1).then(function(book) { - var relationship = book._relationships['author']; + var relationship = book._internalModel._relationships['author']; equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -617,7 +617,7 @@ test("belongsTo hasData sync loaded", function () { run(function() { store.find('book', 1).then(function(book) { - var relationship = book._relationships['author']; + var relationship = book._internalModel._relationships['author']; equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -636,7 +636,7 @@ test("belongsTo hasData async not loaded", function () { run(function() { store.find('book', 1).then(function(book) { - var relationship = book._relationships['author']; + var relationship = book._internalModel._relationships['author']; equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -651,7 +651,7 @@ test("belongsTo hasData sync not loaded", function () { run(function() { store.find('book', 1).then(function(book) { - var relationship = book._relationships['author']; + var relationship = book._internalModel._relationships['author']; equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -666,7 +666,7 @@ test("belongsTo hasData async created", function () { run(function() { var book = store.createRecord('book', { name: 'The Greatest Book' }); - var relationship = book._relationships['author']; + var relationship = book._internalModel._relationships['author']; equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -676,7 +676,7 @@ test("belongsTo hasData sync created", function () { run(function() { var book = store.createRecord('book', { name: 'The Greatest Book' }); - var relationship = book._relationships['author']; + var relationship = book._internalModel._relationships['author']; equal(relationship.hasData, true, 'relationship has data'); }); }); diff --git a/packages/ember-data/tests/integration/relationships/has-many-test.js b/packages/ember-data/tests/integration/relationships/has-many-test.js index ad4981cfa39..fc029cb7628 100644 --- a/packages/ember-data/tests/integration/relationships/has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/has-many-test.js @@ -127,7 +127,7 @@ test("adapter.findMany only gets unique IDs even if duplicate IDs are present in }); // This tests the case where a serializer materializes a has-many -// relationship as a reference that it can fetch lazily. The most +// relationship as a internalModel that it can fetch lazily. The most // common use case of this is to provide a URL to a collection that // is loaded later. test("A serializer can materialize a hasMany as an opaque token that can be lazily fetched via the adapter's findHasMany hook", function() { @@ -970,7 +970,7 @@ test("dual non-async HM <-> BT", function() { deepEqual(post, commentPost, 'expect the new comments post, to be the correct post'); ok(postComments, "comments should exist"); - equal(postCommentsLength, 2, "comment's post should have a reference back to comment"); + equal(postCommentsLength, 2, "comment's post should have a internalModel back to comment"); ok(postComments && postComments.indexOf(firstComment) !== -1, 'expect to contain first comment'); ok(postComments && postComments.indexOf(comment) !== -1, 'expected to contain the new comment'); }); @@ -1218,7 +1218,7 @@ test("Relationship.clear removes all records correctly", function() { }); run(function() { - post._relationships['comments'].clear(); + post._internalModel._relationships['comments'].clear(); var comments = Ember.A(env.store.all('comment')); deepEqual(comments.mapBy('post'), [null, null, null]); }); @@ -1350,7 +1350,7 @@ test("hasMany hasData async loaded", function () { run(function() { store.find('chapter', 1).then(function(chapter) { - var relationship = chapter._relationships['pages']; + var relationship = chapter._internalModel._relationships['pages']; equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -1365,7 +1365,7 @@ test("hasMany hasData sync loaded", function () { run(function() { store.find('chapter', 1).then(function(chapter) { - var relationship = chapter._relationships['pages']; + var relationship = chapter._internalModel._relationships['pages']; equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -1384,7 +1384,7 @@ test("hasMany hasData async not loaded", function () { run(function() { store.find('chapter', 1).then(function(chapter) { - var relationship = chapter._relationships['pages']; + var relationship = chapter._internalModel._relationships['pages']; equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -1399,7 +1399,7 @@ test("hasMany hasData sync not loaded", function () { run(function() { store.find('chapter', 1).then(function(chapter) { - var relationship = chapter._relationships['pages']; + var relationship = chapter._internalModel._relationships['pages']; equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -1414,7 +1414,7 @@ test("hasMany hasData async created", function () { run(function() { var chapter = store.createRecord('chapter', { title: 'The Story Begins' }); - var relationship = chapter._relationships['pages']; + var relationship = chapter._internalModel._relationships['pages']; equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -1424,7 +1424,7 @@ test("hasMany hasData sync created", function () { run(function() { var chapter = store.createRecord('chapter', { title: 'The Story Begins' }); - var relationship = chapter._relationships['pages']; + var relationship = chapter._internalModel._relationships['pages']; equal(relationship.hasData, true, 'relationship has data'); }); }); diff --git a/packages/ember-data/tests/unit/model-test.js b/packages/ember-data/tests/unit/model-test.js index 38818481bd2..c5a9866104d 100644 --- a/packages/ember-data/tests/unit/model-test.js +++ b/packages/ember-data/tests/unit/model-test.js @@ -140,17 +140,19 @@ test("a collision of a record's id with object function's name", function() { } }); -test("it should use `_reference` and not `reference` to store its reference", function() { +/* +test("it should use `_internalModel` and not `internalModel` to store its internalModel", function() { expect(1); run(function() { store.push(Person, { id: 1 }); store.find(Person, 1).then(function(record) { - equal(record.get('reference'), undefined, "doesn't shadow reference key"); + equal(record.get('_internalModel'), undefined, "doesn't shadow internalModel key"); }); }); }); +*/ test("it should cache attributes", function() { expect(2); @@ -407,15 +409,15 @@ test("setting a property back to its original value removes the property from th run(function() { store.find(Person, 1).then(function(person) { - equal(person._attributes.name, undefined, "the `_attributes` hash is clean"); + equal(person._internalModel._attributes.name, undefined, "the `_attributes` hash is clean"); set(person, 'name', "Niceguy Dale"); - equal(person._attributes.name, "Niceguy Dale", "the `_attributes` hash contains the changed value"); + equal(person._internalModel._attributes.name, "Niceguy Dale", "the `_attributes` hash contains the changed value"); set(person, 'name', "Scumbag Dale"); - equal(person._attributes.name, undefined, "the `_attributes` hash is reset"); + equal(person._internalModel._attributes.name, undefined, "the `_attributes` hash is reset"); }); }); }); diff --git a/packages/ember-data/tests/unit/model/internal-model-test.js b/packages/ember-data/tests/unit/model/internal-model-test.js new file mode 100644 index 00000000000..5e81ff5ab17 --- /dev/null +++ b/packages/ember-data/tests/unit/model/internal-model-test.js @@ -0,0 +1,19 @@ +module("unit/model/internal-model - Internal Model"); + +var mockModelFactory = { + _create: function() { + return { trigger: function() {} }; + }, + + eachRelationship: function() { + } +}; +test("Materializing a model twice errors out", function() { + expect(1); + var internalModel = new DS.InternalModel(mockModelFactory, null, null, null); + + internalModel.materializeRecord(); + expectAssertion(function() { + internalModel.materializeRecord(); + }, /more than once/); +}); diff --git a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js index 4855eb1f245..b7598ee3a79 100644 --- a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js +++ b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js @@ -32,6 +32,32 @@ test("a record receives a didLoad callback when it has finished loading", functi }); }); +test("TEMPORARY: a record receives a didLoad callback once it materializes if it wasn't materialized when loaded", function() { + expect(2); + var didLoadCalled = 0; + var Person = DS.Model.extend({ + name: DS.attr(), + didLoad: function() { + didLoadCalled++; + } + }); + + var store = createStore({ + person: Person + }); + + run(function() { + store._pushInternalModel('person', { id: 1 }); + equal(didLoadCalled, 0, "didLoad was not called"); + }); + run(function() { + store.getById('person', 1); + }); + run(function() { + equal(didLoadCalled, 1, "didLoad was called"); + }); +}); + test("a record receives a didUpdate callback when it has finished updating", function() { expect(5); diff --git a/packages/ember-data/tests/unit/model/relationships/record-array-test.js b/packages/ember-data/tests/unit/model/relationships/record-array-test.js index 76809505d26..be273c2a158 100644 --- a/packages/ember-data/tests/unit/model/relationships/record-array-test.js +++ b/packages/ember-data/tests/unit/model/relationships/record-array-test.js @@ -11,18 +11,19 @@ test("updating the content of a RecordArray updates its content", function() { var env = setupStore({ tag: Tag }); var store = env.store; - var records, tags; + var records, tags, internalModel; run(function() { records = store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); - tags = DS.RecordArray.create({ content: Ember.A(records.slice(0, 2)), store: store, type: Tag }); + internalModel = Ember.A(records).mapBy('_internalModel'); + tags = DS.RecordArray.create({ content: Ember.A(internalModel.slice(0, 2)), store: store, type: Tag }); }); var tag = tags.objectAt(0); equal(get(tag, 'name'), "friendly", "precond - we're working with the right tags"); run(function() { - set(tags, 'content', Ember.A(records.slice(1, 3))); + set(tags, 'content', Ember.A(internalModel.slice(1, 3))); }); tag = tags.objectAt(0); diff --git a/packages/ember-data/tests/unit/store/unload-test.js b/packages/ember-data/tests/unit/store/unload-test.js index 5816b16943c..8791b87b12b 100644 --- a/packages/ember-data/tests/unit/store/unload-test.js +++ b/packages/ember-data/tests/unit/store/unload-test.js @@ -37,7 +37,7 @@ test("unload a dirty record", function() { store.find(Record, 1).then(function(record) { record.set('title', 'toto2'); - record.send('willCommit'); + record._internalModel.send('willCommit'); equal(get(record, 'isDirty'), true, "record is dirty"); @@ -47,7 +47,7 @@ test("unload a dirty record", function() { // force back into safe to unload mode. run(function() { - record.transitionTo('deleted.saved'); + record._internalModel.transitionTo('deleted.saved'); }); }); }); From d92c6edc7a2a6e23e99fe875d61a838660b5dafd Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Sun, 31 May 2015 14:06:12 +0300 Subject: [PATCH 0816/2527] Guard for embedded unknown hasMany relationship --- .../lib/serializers/embedded-records-mixin.js | 8 ++++-- .../embedded-records-mixin-test.js | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/serializers/embedded-records-mixin.js b/packages/ember-data/lib/serializers/embedded-records-mixin.js index 3997ffbbbdd..f093f75ab98 100644 --- a/packages/ember-data/lib/serializers/embedded-records-mixin.js +++ b/packages/ember-data/lib/serializers/embedded-records-mixin.js @@ -298,13 +298,17 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ } var includeIds = this.hasSerializeIdsOption(attr); var includeRecords = this.hasSerializeRecordsOption(attr); - var key; + var key, hasMany; if (includeIds) { key = this.keyForRelationship(attr, relationship.kind, 'serialize'); json[key] = snapshot.hasMany(attr, { ids: true }); } else if (includeRecords) { key = this.keyForAttribute(attr, 'serialize'); - json[key] = snapshot.hasMany(attr).map(function(embeddedSnapshot) { + hasMany = snapshot.hasMany(attr); + + Ember.warn("The embedded relationship '" + key + "' is undefined for '" + snapshot.modelName + "' with id '" + snapshot.id + "'. Please include it in your original payload.", Ember.typeOf(hasMany) !== 'undefined'); + + json[key] = Ember.A(hasMany).map(function(embeddedSnapshot) { var embeddedJson = embeddedSnapshot.record.serialize({ includeId: true }); this.removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, embeddedJson); return embeddedJson; diff --git a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js index 8ae3c9eef34..13a663411b8 100644 --- a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js +++ b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js @@ -609,6 +609,32 @@ test("serialize with embedded objects (hasMany relationship)", function() { }); }); +test("serialize with embedded objects (unknown hasMany relationship)", function() { + var league; + run(function() { + league = env.store.push(HomePlanet, { name: "Villain League", id: "123" }); + }); + + env.registry.register('serializer:home-planet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' } + } + })); + + var serializer, json; + warns(function() { + run(function() { + serializer = env.container.lookup("serializer:home-planet"); + json = serializer.serialize(league._createSnapshot()); + }); + }, /The embedded relationship 'villains' is undefined for 'home-planet' with id '123'. Please include it in your original payload./); + + deepEqual(json, { + name: "Villain League", + villains: [] + }); +}); + test("serialize with embedded objects (hasMany relationship) supports serialize:false", function() { run(function() { league = env.store.createRecord(HomePlanet, { name: "Villain League", id: "123" }); From 690af896c060d1a9852b873cf0babab7a4a88e9f Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Tue, 2 Jun 2015 12:43:18 +0300 Subject: [PATCH 0817/2527] Move coerceId to a separate file --- .../ember-data/lib/serializers/rest-serializer.js | 5 +---- packages/ember-data/lib/system/coerce-id.js | 9 +++++++++ packages/ember-data/lib/system/store.js | 12 ++---------- 3 files changed, 12 insertions(+), 14 deletions(-) create mode 100644 packages/ember-data/lib/system/coerce-id.js diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index 712a27c6159..f6ae93de964 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -5,15 +5,12 @@ import JSONSerializer from "ember-data/serializers/json-serializer"; import normalizeModelName from "ember-data/system/normalize-model-name"; import {singularize} from "ember-inflector/lib/system/string"; +import coerceId from "ember-data/system/coerce-id"; var forEach = Ember.ArrayPolyfills.forEach; var map = Ember.ArrayPolyfills.map; var camelize = Ember.String.camelize; -function coerceId(id) { - return id == null ? null : id + ''; -} - /** Normally, applications will use the `RESTSerializer` by implementing the `normalize` method and individual normalizations under diff --git a/packages/ember-data/lib/system/coerce-id.js b/packages/ember-data/lib/system/coerce-id.js new file mode 100644 index 00000000000..62acf96bb14 --- /dev/null +++ b/packages/ember-data/lib/system/coerce-id.js @@ -0,0 +1,9 @@ +// Used by the store to normalize IDs entering the store. Despite the fact +// that developers may provide IDs as numbers (e.g., `store.find(Person, 1)`), +// it is important that internally we use strings, since IDs may be serialized +// and lose type information. For example, Ember's router may put a record's +// ID into the URL, and if we later try to deserialize that URL and find the +// corresponding record, we will not know if it is a string or a number. +export default function coerceId(id) { + return id == null ? null : id+''; +} diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 376e9e5a4b3..1a129489fe0 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -38,6 +38,8 @@ import { _findQuery } from "ember-data/system/store/finders"; +import coerceId from "ember-data/system/coerce-id"; + import RecordArrayManager from "ember-data/system/record-array-manager"; import InternalModel from "ember-data/system/model/internal-model"; @@ -133,16 +135,6 @@ if (!Service) { // record, even if it has not yet been fully materialized. // * +type+ means a subclass of DS.Model. -// Used by the store to normalize IDs entering the store. Despite the fact -// that developers may provide IDs as numbers (e.g., `store.find(Person, 1)`), -// it is important that internally we use strings, since IDs may be serialized -// and lose type information. For example, Ember's router may put a record's -// ID into the URL, and if we later try to deserialize that URL and find the -// corresponding record, we will not know if it is a string or a number. -function coerceId(id) { - return id == null ? null : id+''; -} - /** The store contains all of the data for records loaded from the server. It is also responsible for creating instances of `DS.Model` that wrap From c1324d7de18e6c46684987c8587a342bb8eddea1 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 1 Jun 2015 12:13:30 -0400 Subject: [PATCH 0818/2527] Lookup the store using store:application instead of application:main This simplifes the process of registering the store when a user creates a custom one. This change also fixes deprecations warning introduces in Ember 1.12. The store service is now injected as a instanceInitializer. --- bower.json | 2 +- packages/ember-data/lib/ember-initializer.js | 20 +++++++++++--- .../lib/initializers/store-injections.js | 6 ++--- packages/ember-data/lib/initializers/store.js | 10 +++---- .../initialize-store-service.js | 26 +++++++++++++++++++ packages/ember-data/lib/setup-container.js | 19 +++++++++----- .../tests/integration/application-test.js | 4 +-- .../non-dasherized-lookups.js | 4 +-- .../tests/integration/debug-adapter-test.js | 2 +- .../tests/integration/multiple_stores_test.js | 2 +- .../tests/integration/setup-container-test.js | 13 +++++++++- 11 files changed, 81 insertions(+), 27 deletions(-) create mode 100644 packages/ember-data/lib/instance-initializers/initialize-store-service.js diff --git a/bower.json b/bower.json index 1dc4ca9ce93..b1d345e8de6 100644 --- a/bower.json +++ b/bower.json @@ -2,7 +2,7 @@ "name": "ember-data", "private": true, "dependencies": { - "ember": "~1.11.1" + "ember": "~1.12.1" }, "devDependencies": { "qunit": "~1.17.0", diff --git a/packages/ember-data/lib/ember-initializer.js b/packages/ember-data/lib/ember-initializer.js index a42031bc254..f102f729df3 100644 --- a/packages/ember-data/lib/ember-initializer.js +++ b/packages/ember-data/lib/ember-initializer.js @@ -1,4 +1,6 @@ -import setupContainer from 'ember-data/setup-container'; +import { initializeInjects } from 'ember-data/setup-container'; +import initializeStoreService from 'ember-data/instance-initializers/initialize-store-service'; + var K = Ember.K; @@ -42,11 +44,23 @@ Ember.onLoad('Ember.Application', function(Application) { Application.initializer({ name: "ember-data", - initialize: setupContainer + initialize: initializeInjects }); - // Deprecated initializers to satisfy old code that depended on them + if (Application.instanceInitializer) { + Application.instanceInitializer({ + name: "ember-data", + initialize: initializeStoreService + }); + } else { + Ember.initializer({ + name: "ember-data-store-service", + after: "ember-data", + initialize: initializeStoreService + }); + } + // Deprecated initializers to satisfy old code that depended on them Application.initializer({ name: "store", after: "ember-data", diff --git a/packages/ember-data/lib/initializers/store-injections.js b/packages/ember-data/lib/initializers/store-injections.js index 16dca7f409b..af907d0bd33 100644 --- a/packages/ember-data/lib/initializers/store-injections.js +++ b/packages/ember-data/lib/initializers/store-injections.js @@ -6,7 +6,7 @@ @param {Ember.Registry} registry */ export default function initializeStoreInjections(registry) { - registry.injection('controller', 'store', 'store:main'); - registry.injection('route', 'store', 'store:main'); - registry.injection('data-adapter', 'store', 'store:main'); + registry.injection('controller', 'store', 'store:application'); + registry.injection('route', 'store', 'store:application'); + registry.injection('data-adapter', 'store', 'store:application'); } diff --git a/packages/ember-data/lib/initializers/store.js b/packages/ember-data/lib/initializers/store.js index b7470688b24..e86832289b2 100644 --- a/packages/ember-data/lib/initializers/store.js +++ b/packages/ember-data/lib/initializers/store.js @@ -18,7 +18,7 @@ export default function initializeStore(registry, application) { registry.optionsForType('serializer', { singleton: false }); registry.optionsForType('adapter', { singleton: false }); - registry.register('store:main', registry.lookupFactory('store:application') || (application && application.Store) || Store); + registry.register('store:application', application && application.Store || Store); // allow older names to be looked up @@ -26,16 +26,12 @@ export default function initializeStore(registry, application) { proxy.registerDeprecations([ { deprecated: 'serializer:_default', valid: 'serializer:-default' }, { deprecated: 'serializer:_rest', valid: 'serializer:-rest' }, - { deprecated: 'adapter:_rest', valid: 'adapter:-rest' } + { deprecated: 'adapter:_rest', valid: 'adapter:-rest' }, + { deprecated: 'store:main', valid: 'store:application' } ]); // new go forward paths registry.register('serializer:-default', JSONSerializer); registry.register('serializer:-rest', RESTSerializer); registry.register('adapter:-rest', RESTAdapter); - - // Eagerly generate the store so defaultStore is populated. - // TODO: Do this in a finisher hook - var store = registry.lookup('store:main'); - registry.register('service:store', store, { instantiate: false }); } diff --git a/packages/ember-data/lib/instance-initializers/initialize-store-service.js b/packages/ember-data/lib/instance-initializers/initialize-store-service.js new file mode 100644 index 00000000000..e685bfcca3e --- /dev/null +++ b/packages/ember-data/lib/instance-initializers/initialize-store-service.js @@ -0,0 +1,26 @@ +/** + Configures a registry for use with an Ember-Data + store. + + @method initializeStore + @param {Ember.ApplicationInstance} applicationOrRegistry + */ +export default function initializeStoreService(applicationOrRegistry) { + var registry, container; + if (applicationOrRegistry.registry && applicationOrRegistry.container) { + // initializeStoreService was registered with an + // instanceInitializer. The first argument is the application + // instance. + registry = applicationOrRegistry.registry; + container = applicationOrRegistry.container; + } else { + // initializeStoreService was called by an initializer instead of + // an instanceInitializer. The first argument is a registy. This + // case allows ED to support Ember pre 1.12 + registry = applicationOrRegistry; + container = registry.container(); + } + // Eagerly generate the store so defaultStore is populated. + var store = container.lookup('store:application'); + registry.register('service:store', store, { instantiate: false }); +} diff --git a/packages/ember-data/lib/setup-container.js b/packages/ember-data/lib/setup-container.js index 7542c4fcf60..359d1bd6e7d 100644 --- a/packages/ember-data/lib/setup-container.js +++ b/packages/ember-data/lib/setup-container.js @@ -3,15 +3,22 @@ import initializeTransforms from 'ember-data/initializers/transforms'; import initializeStoreInjections from 'ember-data/initializers/store-injections'; import initializeDataAdapter from 'ember-data/initializers/data-adapter'; import setupActiveModelContainer from 'activemodel-adapter/setup-container'; +import initializeStoreService from 'ember-data/instance-initializers/initialize-store-service'; -export default function setupContainer(container, application) { +export default function setupContainer(registry, application) { // application is not a required argument. This ensures // testing setups can setup a container without booting an // entire ember application. - initializeDataAdapter(container, application); - initializeTransforms(container, application); - initializeStoreInjections(container, application); - initializeStore(container, application); - setupActiveModelContainer(container, application); + initializeInjects(registry, application); + initializeStoreService(registry); +} + + +export function initializeInjects(registry, application) { + initializeDataAdapter(registry, application); + initializeTransforms(registry, application); + initializeStoreInjections(registry, application); + setupActiveModelContainer(registry, application); + initializeStore(registry, application); } diff --git a/packages/ember-data/tests/integration/application-test.js b/packages/ember-data/tests/integration/application-test.js index 31ffb01e93b..1c523737724 100644 --- a/packages/ember-data/tests/integration/application-test.js +++ b/packages/ember-data/tests/integration/application-test.js @@ -13,7 +13,7 @@ var app, App, container; */ function getStore() { - return lookup('store:main'); + return lookup('store:application'); } function lookup(thing) { @@ -69,7 +69,7 @@ test("registering App.Store is deprecated but functional", function() { 'has been deprecated. Please use `App.ApplicationStore` instead.'); run(function() { - ok(lookup('store:main').get('isCustomButDeprecated'), "the custom store was instantiated"); + ok(lookup('store:application').get('isCustomButDeprecated'), "the custom store was instantiated"); }); var fooController = lookup('controller:foo'); diff --git a/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js b/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js index d7ece25d65b..e72eacff39c 100644 --- a/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js +++ b/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js @@ -9,7 +9,7 @@ module('integration/backwards-compat/non-dasherized-lookups - non dasherized loo name: DS.attr() }); }); - store = App.__container__.lookup('store:main'); + store = App.__container__.lookup('store:application'); }, teardown: function() { run(App, 'destroy'); @@ -67,7 +67,7 @@ module('integration/backwards-compat/non-dasherized-lookups - non dasherized loo postNotes: DS.hasMany('post_note') }); }); - store = App.__container__.lookup('store:main'); + store = App.__container__.lookup('store:application'); }, teardown: function() { diff --git a/packages/ember-data/tests/integration/debug-adapter-test.js b/packages/ember-data/tests/integration/debug-adapter-test.js index 3471c665065..dd7596a2af6 100644 --- a/packages/ember-data/tests/integration/debug-adapter-test.js +++ b/packages/ember-data/tests/integration/debug-adapter-test.js @@ -18,7 +18,7 @@ module("DS.DebugAdapter", { }); - store = App.__container__.lookup('store:main'); + store = App.__container__.lookup('store:application'); debugAdapter = App.__container__.lookup('data-adapter:main'); debugAdapter.reopen({ diff --git a/packages/ember-data/tests/integration/multiple_stores_test.js b/packages/ember-data/tests/integration/multiple_stores_test.js index 09210a6db6b..f66bc86bee5 100644 --- a/packages/ember-data/tests/integration/multiple_stores_test.js +++ b/packages/ember-data/tests/integration/multiple_stores_test.js @@ -118,7 +118,7 @@ test("embedded records should be created in multiple stores", function() { run(function() { json_main = serializer_main.extractSingle(env.store, HomePlanet, json_hash_main); - equal(env.store.hasRecordForId("superVillain", "1"), true, "superVillain should exist in store:main"); + equal(env.store.hasRecordForId("superVillain", "1"), true, "superVillain should exist in store:application"); }); run(function() { diff --git a/packages/ember-data/tests/integration/setup-container-test.js b/packages/ember-data/tests/integration/setup-container-test.js index 724f6537bcc..e8c85d2ea8c 100644 --- a/packages/ember-data/tests/integration/setup-container-test.js +++ b/packages/ember-data/tests/integration/setup-container-test.js @@ -30,7 +30,7 @@ module("integration/setup-container - Setting up a container", { }); test("The store should be registered into a container.", function() { - ok(container.lookup('store:main') instanceof Store, "the custom store is instantiated"); + ok(container.lookup('store:application') instanceof Store, "the custom store is instantiated"); }); test("The store should be registered into the container as a service.", function() { @@ -86,6 +86,17 @@ test("serializers are not returned as singletons - each lookup should return a d notEqual(serializer1, serializer2); }); +test("the deprecated store:main is resolved as store:application", function() { + var deprecated; + var valid = container.lookup('store:application'); + expectDeprecation(function() { + deprecated = container.lookup('store:main'); + }); + + ok(deprecated.constructor === valid.constructor, "they should resolve to the same thing"); +}); + + test("adapters are not returned as singletons - each lookup should return a different instance", function() { var adapter1, adapter2; adapter1 = container.lookup('adapter:-rest'); From b3e7d1853c48f7307947614f696827aa68b935bf Mon Sep 17 00:00:00 2001 From: IgorT Date: Tue, 2 Jun 2015 15:24:19 +0300 Subject: [PATCH 0819/2527] Add codeclimate yml --- .codeclimate.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .codeclimate.yml diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 00000000000..05f8fac2da5 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,7 @@ +# Save as .codeclimate.yml (note leading .) in project root directory +languages: + JavaScript: true + exclude_paths: + - "packages/activemodel-adapter/tests/*" + - "packages/ember/tests/*" + - "packages/ember-data/tests/*" From a818fd79e3aa1d355c7a5d958b799f072d4c2bb5 Mon Sep 17 00:00:00 2001 From: tchak Date: Mon, 1 Jun 2015 20:11:48 +0300 Subject: [PATCH 0820/2527] minor adjustments and tests for snapshot creation refactor --- .../lib/system/model/internal-model.js | 1 - packages/ember-data/lib/system/store.js | 13 +++---- .../ember-data/tests/unit/model/merge-test.js | 35 +++++++++++++++++++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js index c28de2fac09..b5114a97227 100644 --- a/packages/ember-data/lib/system/model/internal-model.js +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -266,7 +266,6 @@ InternalModel.prototype = { @private */ adapterWillCommit: function() { - this.flushChangedAttributes(); this.send('willCommit'); }, diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 1a129489fe0..bb4db7cb798 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1262,12 +1262,13 @@ Store = Service.extend({ @method scheduleSave @private - @param {DS.Model} record + @param {InternalModel} record @param {Resolver} resolver */ - scheduleSave: function(record, resolver) { - var snapshot = record._createSnapshot(); - record.adapterWillCommit(); + scheduleSave: function(internalModel, resolver) { + var snapshot = internalModel._createSnapshot(); + internalModel.flushChangedAttributes(); + internalModel.adapterWillCommit(); this._pendingSave.push([snapshot, resolver]); once(this, 'flushPendingSave'); }, @@ -2061,7 +2062,7 @@ function _commit(adapter, store, operation, snapshot) { store._adapterRun(function() { if (adapterPayload) { - payload = serializer.extract(store, type, adapterPayload, get(snapshot, 'id'), operation); + payload = serializer.extract(store, type, adapterPayload, snapshot.id, operation); } store.didSaveRecord(record, payload); }); @@ -2069,7 +2070,7 @@ function _commit(adapter, store, operation, snapshot) { return record; }, function(reason) { if (reason instanceof InvalidError) { - var errors = serializer.extractErrors(store, type, reason.errors, get(snapshot, 'id')); + var errors = serializer.extractErrors(store, type, reason.errors, snapshot.id); store.recordWasInvalid(record, errors); reason = new InvalidError(errors); } else { diff --git a/packages/ember-data/tests/unit/model/merge-test.js b/packages/ember-data/tests/unit/model/merge-test.js index 17361afb106..2c7a2866773 100644 --- a/packages/ember-data/tests/unit/model/merge-test.js +++ b/packages/ember-data/tests/unit/model/merge-test.js @@ -40,6 +40,41 @@ test("When a record is in flight, changes can be made", function() { }); }); +test("Make sure snapshot is created at save time not at flush time", function() { + expect(5); + + var adapter = DS.Adapter.extend({ + updateRecord: function(store, type, snapshot) { + equal(snapshot.attr('name'), 'Thomas Dale'); + + return Ember.RSVP.resolve(); + } + }); + + var store = createStore({ adapter: adapter }); + var person; + + run(function() { + person = store.push(Person, { id: 1, name: "Tom" }); + person.set('name', "Thomas Dale"); + }); + + run(function() { + var promise = person.save(); + + equal(person.get('name'), "Thomas Dale"); + + person.set('name', "Tomasz Dale"); + + equal(person.get('name'), "Tomasz Dale", "the local changes applied on top"); + + promise.then(async(function(person) { + equal(person.get('isDirty'), true, "The person is still dirty"); + equal(person.get('name'), "Tomasz Dale", "The local changes apply"); + })); + }); +}); + test("When a record is in flight, pushes are applied underneath the in flight changes", function() { expect(6); From 6626d76c649baaf514a65734cce968dd8df542fe Mon Sep 17 00:00:00 2001 From: tchak Date: Tue, 2 Jun 2015 10:46:44 +0300 Subject: [PATCH 0821/2527] more consistent use of internalModel vs record and some documentation fixes --- packages/ember-data/lib/system/store.js | 58 ++++++++++++------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index bb4db7cb798..b9ec3557340 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -859,8 +859,8 @@ Store = Service.extend({ hasRecordForId: function(modelName, inputId) { var typeClass = this.modelFor(modelName); var id = coerceId(inputId); - var record = this.typeMapFor(typeClass).idToRecord[id]; - return !!record && record.isLoaded(); + var internalModel = this.typeMapFor(typeClass).idToRecord[id]; + return !!internalModel && internalModel.isLoaded(); }, /** @@ -1244,10 +1244,10 @@ Store = Service.extend({ @method dataWasUpdated @private @param {Class} type - @param {DS.Model} record + @param {InternalModel} record */ - dataWasUpdated: function(type, record) { - this.recordArrayManager.recordDidChange(record); + dataWasUpdated: function(type, internalModel) { + this.recordArrayManager.recordDidChange(internalModel); }, // .............. @@ -1315,19 +1315,19 @@ Store = Service.extend({ @method didSaveRecord @private - @param {DS.Model} record the in-flight record + @param {InternalModel} record the in-flight record @param {Object} data optional data (see above) */ - didSaveRecord: function(record, data) { + didSaveRecord: function(internalModel, data) { if (data) { // normalize relationship IDs into records - this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', record, record.type, data); - this.updateId(record, data); + this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, internalModel.type, data); + this.updateId(internalModel, data); } //We first make sure the primary data has been updated //TODO try to move notification to the user to the end of the runloop - record.adapterDidCommit(data); + internalModel.adapterDidCommit(data); }, /** @@ -1337,11 +1337,11 @@ Store = Service.extend({ @method recordWasInvalid @private - @param {DS.Model} record + @param {InternalModel} record @param {Object} errors */ - recordWasInvalid: function(record, errors) { - record.adapterDidInvalidate(errors); + recordWasInvalid: function(internalModel, errors) { + internalModel.adapterDidInvalidate(errors); }, /** @@ -1351,10 +1351,10 @@ Store = Service.extend({ @method recordWasError @private - @param {DS.Model} record + @param {InternalModel} record */ - recordWasError: function(record) { - record.adapterDidError(); + recordWasError: function(internalModel) { + internalModel.adapterDidError(); }, /** @@ -1364,18 +1364,18 @@ Store = Service.extend({ @method updateId @private - @param {DS.Model} record + @param {InternalModel} record @param {Object} data */ - updateId: function(record, data) { - var oldId = get(record, 'id'); + updateId: function(internalModel, data) { + var oldId = internalModel.id; var id = coerceId(data.id); - Ember.assert("An adapter cannot assign a new id to a record that already has an id. " + record + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId); + Ember.assert("An adapter cannot assign a new id to a record that already has an id. " + internalModel + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId); - this.typeMapFor(record.type).idToRecord[id] = record; + this.typeMapFor(internalModel.type).idToRecord[id] = internalModel; - record.setId(id); + internalModel.setId(id); }, /** @@ -1777,7 +1777,7 @@ Store = Service.extend({ @param {subclass of DS.Model} type @param {String} id @param {Object} data - @return {DS.Model} record + @return {InternalModel} record */ buildInternalModel: function(type, id, data) { var typeMap = this.typeMapFor(type); @@ -1827,20 +1827,20 @@ Store = Service.extend({ @method _dematerializeRecord @private - @param {DS.Model} record + @param {InternalModel} record */ - _dematerializeRecord: function(record) { - var type = record.type; + _dematerializeRecord: function(internalModel) { + var type = internalModel.type; var typeMap = this.typeMapFor(type); - var id = get(record, 'id'); + var id = internalModel.id; - record.updateRecordArrays(); + internalModel.updateRecordArrays(); if (id) { delete typeMap.idToRecord[id]; } - var loc = indexOf(typeMap.records, record); + var loc = indexOf(typeMap.records, internalModel); typeMap.records.splice(loc, 1); }, From 30062d11e30d2d757e74652ed5748acdc3ac481c Mon Sep 17 00:00:00 2001 From: Greg Funtusov Date: Tue, 2 Jun 2015 18:59:02 +0300 Subject: [PATCH 0822/2527] Fix codeclimate styling complaints --- Brocfile.js | 2 - bin/publish-to-s3.js | 4 +- config/s3ProjectConfig.js | 2 +- lib/amd-build.js | 4 - .../blueprints/ember-data/index.js | 1 + ...-inside-round-braces-in-call-expression.js | 2 - lib/lib-tree.js | 2 +- lib/test-tree.js | 4 +- tests/ember-configuration.js | 2 +- tests/ember-data-setup.js | 2 - tests/qunit-configuration.js | 135 +++++++++--------- 11 files changed, 77 insertions(+), 83 deletions(-) diff --git a/Brocfile.js b/Brocfile.js index 92116e9158f..ad0c470a5b5 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -17,8 +17,6 @@ var version = require('git-repo-version')(10); var yuidoc = require('broccoli-yuidoc'); var replace = require('broccoli-replace'); var stew = require('broccoli-stew'); -var path = require('path'); -var fs = require('fs'); var babel = require('broccoli-babel-transpiler'); var babelOptions = require('./config/babel'); var fileCreator = require('broccoli-file-creator'); diff --git a/bin/publish-to-s3.js b/bin/publish-to-s3.js index bc1c9c0e0ce..7cda3058eb2 100755 --- a/bin/publish-to-s3.js +++ b/bin/publish-to-s3.js @@ -15,6 +15,6 @@ // ./bin/publish_to_s3.js // ``` var S3Publisher = require('ember-publisher'); -var configPath = require('path').join(__dirname, '../config/s3ProjectConfig.js') -publisher = new S3Publisher({projectConfigPath: configPath}); +var configPath = require('path').join(__dirname, '../config/s3ProjectConfig.js'); +var publisher = new S3Publisher({projectConfigPath: configPath}); publisher.publish(); diff --git a/config/s3ProjectConfig.js b/config/s3ProjectConfig.js index fa8c7239b24..e24fafd558c 100644 --- a/config/s3ProjectConfig.js +++ b/config/s3ProjectConfig.js @@ -6,7 +6,7 @@ function fileMap(revision,tag,date) { 'ember-data.prod.js': fileObject('ember-data.prod', '.js', 'text/javascript', revision, tag, date), 'docs/data.json': fileObject('ember-data-docs', '.json', 'application/json', revision, tag, date) }; -}; +} function fileObject(baseName, extension, contentType, currentRevision, tag, date){ var fullName = '/' + baseName + extension; diff --git a/lib/amd-build.js b/lib/amd-build.js index f9cc7a467ab..0fc58f3ae25 100644 --- a/lib/amd-build.js +++ b/lib/amd-build.js @@ -1,11 +1,7 @@ -var pickFiles = require('broccoli-static-compiler'); -var concat = require('broccoli-concat'); var es6 = require('broccoli-es6-module-transpiler'); var merge = require('broccoli-merge-trees'); var PackageResolver = require('es6-module-transpiler-package-resolver'); var AMDFormatter = require('es6-module-transpiler-amd-formatter'); -var fileCreator = require('broccoli-file-creator'); -var merge = require('broccoli-merge-trees'); var replace = require('broccoli-replace'); function amdES6Package(packages, root, outfile) { diff --git a/lib/ember-addon/blueprints/ember-data/index.js b/lib/ember-addon/blueprints/ember-data/index.js index 289382d65be..0de95eb439c 100644 --- a/lib/ember-addon/blueprints/ember-data/index.js +++ b/lib/ember-addon/blueprints/ember-data/index.js @@ -1,3 +1,4 @@ +/* jshint node: true */ 'use strict'; module.exports = { diff --git a/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js b/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js index 3685932f017..1245ee81680 100644 --- a/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js +++ b/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js @@ -35,8 +35,6 @@ module.exports.prototype = { }, check: function(file, errors) { - var tokens = file.getTokens(); - file.iterateNodesByType('CallExpression', function(node) { var nodeBeforeRoundBrace = node; diff --git a/lib/lib-tree.js b/lib/lib-tree.js index 3122aa868af..b140ea93168 100644 --- a/lib/lib-tree.js +++ b/lib/lib-tree.js @@ -6,4 +6,4 @@ module.exports = function libTree(tree) { srcDir: '/', destDir: '/' }); -} +}; diff --git a/lib/test-tree.js b/lib/test-tree.js index e48710e848a..eff7cfc54e4 100644 --- a/lib/test-tree.js +++ b/lib/test-tree.js @@ -4,7 +4,6 @@ var jshint = require('broccoli-jshint'); var path = require('path'); var wrap = require('broccoli-wrap'); var merge = require('broccoli-merge-trees'); -var amdBuild = require('./amd-build'); module.exports = function testTree(sourceTree, compiled) { var emberDataFiles = pickFiles(sourceTree, { @@ -29,8 +28,9 @@ module.exports = function testTree(sourceTree, compiled) { }; function hint(tree){ + var dirname = __dirname || path.resolve(path.dirname()); var jshinted = jshint(tree, { - jshintrcPath: path.join(__dirname, '..', '.jshintrc') + jshintrcPath: path.join(dirname, '..', '.jshintrc') }); return wrap(jshinted, { wrapper: [ "if (!QUnit.urlParams.nojshint) {\n", "\n}"], diff --git a/tests/ember-configuration.js b/tests/ember-configuration.js index 9c9faf4eb29..b0582a9eb85 100644 --- a/tests/ember-configuration.js +++ b/tests/ember-configuration.js @@ -65,7 +65,7 @@ } else { env.container.normalize = fn; } - } + }; var adapter = env.adapter = (options.adapter || DS.Adapter); delete options.adapter; diff --git a/tests/ember-data-setup.js b/tests/ember-data-setup.js index 7f57db55d0a..ce0686fb355 100644 --- a/tests/ember-data-setup.js +++ b/tests/ember-data-setup.js @@ -1,5 +1,3 @@ -/* globals syncForTest */ - ;(function(){ Ember.RSVP.configure('onerror', function(reason) { diff --git a/tests/qunit-configuration.js b/tests/qunit-configuration.js index f0cfa53a705..fec07e42416 100644 --- a/tests/qunit-configuration.js +++ b/tests/qunit-configuration.js @@ -1,85 +1,87 @@ (function() { + /*global namespace: true */ + window.EmberDev = window.EmberDev || {}; EmberDev.afterEach = function() { - if (Ember && Ember.View) { - var viewIds = [], id; - for (id in Ember.View.views) { - if (Ember.View.views[id] != null) { - viewIds.push(id); - } + if (Ember && Ember.View) { + var viewIds = [], id; + for (id in Ember.View.views) { + if (Ember.View.views[id] != null) { + viewIds.push(id); } + } - if (viewIds.length > 0) { - deepEqual(viewIds, [], "Ember.View.views should be empty"); - Ember.View.views = []; - } + if (viewIds.length > 0) { + deepEqual(viewIds, [], "Ember.View.views should be empty"); + Ember.View.views = []; } + } - if (Ember && Ember.TEMPLATES) { - var templateNames = [], name; - for (name in Ember.TEMPLATES) { - if (Ember.TEMPLATES[name] != null) { - templateNames.push(name); - } + if (Ember && Ember.TEMPLATES) { + var templateNames = [], name; + for (name in Ember.TEMPLATES) { + if (Ember.TEMPLATES[name] != null) { + templateNames.push(name); } + } - if (templateNames.length > 0) { - deepEqual(templateNames, [], "Ember.TEMPLATES should be empty"); - Ember.TEMPLATES = {}; - } + if (templateNames.length > 0) { + deepEqual(templateNames, [], "Ember.TEMPLATES should be empty"); + Ember.TEMPLATES = {}; } - }; + } + }; - window.globalFailedTests = []; - window.globalTestResults = null; - window.lastAssertionTime = new Date().getTime(); + window.globalFailedTests = []; + window.globalTestResults = null; + window.lastAssertionTime = new Date().getTime(); - var currentTest, assertCount; + var currentTest, assertCount; - QUnit.testStart(function(data) { - // Reset the assertion count - assertCount = 0; + QUnit.testStart(function(data) { + // Reset the assertion count + assertCount = 0; - currentTest = { - name: data.name, - failedAssertions: [], - total: 0, - passed: 0, - failed: 0, - start: new Date(), - time: 0 - }; + currentTest = { + name: data.name, + failedAssertions: [], + total: 0, + passed: 0, + failed: 0, + start: new Date(), + time: 0 + }; - }) + }); - QUnit.log(function(data) { - assertCount++; - lastAssertionTime = new Date().getTime(); + QUnit.log(function(data) { + assertCount++; + lastAssertionTime = new Date().getTime(); - // Ignore passing assertions - if (!data.result) { - currentTest.failedAssertions.push(data); - } - }); + // Ignore passing assertions + if (!data.result) { + currentTest.failedAssertions.push(data); + } + }); - QUnit.testDone(function(data) { - currentTest.time = (new Date()).getTime() - currentTest.start.getTime(); // ms - currentTest.total = data.total; - currentTest.passed = data.passed; - currentTest.failed = data.failed; + QUnit.testDone(function(data) { + currentTest.time = (new Date()).getTime() - currentTest.start.getTime(); // ms + currentTest.total = data.total; + currentTest.passed = data.passed; + currentTest.failed = data.failed; - if (currentTest.failed > 0) - window.globalFailedTests.push(currentTest) + if (currentTest.failed > 0) + window.globalFailedTests.push(currentTest); - currentTest = null; - }); + currentTest = null; + }); - QUnit.done(function( details ) { - details.failedTests = globalFailedTests; + QUnit.done(function( details ) { + details.failedTests = globalFailedTests; - window.globalTestResults = details; - }); + window.globalTestResults = details; + }); // hack qunit to not suck for Ember objects var originalTypeof = QUnit.jsDump.typeOf; @@ -174,7 +176,7 @@ function MethodCallExpectation(target, property){ this.target = target; this.property = property; - }; + } MethodCallExpectation.prototype = { handleCall: function(){ @@ -208,7 +210,8 @@ function AssertExpectation(message){ MethodCallExpectation.call(this, Ember, 'assert'); this.expectedMessage = message; - }; + } + AssertExpectation.Error = function(){}; AssertExpectation.prototype = o_create(MethodCallExpectation.prototype); AssertExpectation.prototype.handleCall = function(message, test){ @@ -281,7 +284,7 @@ // Ember.deprecate("Old And Busted"); // window.expectNoDeprecation = function(message) { - if (typeof EmberDev.deprecations.expecteds === 'array') { + if (Ember.isArray(EmberDev.deprecations.expecteds)) { throw("No deprecation was expected after expectDeprecation was called!"); } EmberDev.deprecations.stubEmber(); @@ -344,15 +347,15 @@ if (expecteds === EmberDev.deprecations.NONE) { var actualMessages = []; - for (var actual in actuals) { - actualMessages.push(actual[0]); + for (var _actual in actuals) { + actualMessages.push(_actual[0]); } ok(actuals.length === 0, "Expected no deprecation call, got: "+actualMessages.join(', ')); } else { for (var o=0;o < expecteds.length; o++) { - var expected = expecteds[o], match; + var expected = expecteds[o], match, actual; for (var i=0;i < actuals.length; i++) { - var actual = actuals[i]; + actual = actuals[i]; if (!actual[1]) { if (expected instanceof RegExp) { if (expected.test(actual[0])) { From e5de2c5798da3311e2226289a9a274daf1fdc539 Mon Sep 17 00:00:00 2001 From: tchak Date: Tue, 2 Jun 2015 17:35:22 +0300 Subject: [PATCH 0823/2527] more cleanup on internalModel vs record --- .../ember-data/lib/system/model/attributes.js | 2 +- .../lib/system/model/internal-model.js | 17 +- packages/ember-data/lib/system/model/model.js | 11 +- .../ember-data/lib/system/model/states.js | 286 +++++++++--------- packages/ember-data/lib/system/snapshot.js | 6 +- packages/ember-data/lib/system/store.js | 62 ++-- .../ember-data/lib/system/store/finders.js | 34 +-- 7 files changed, 209 insertions(+), 209 deletions(-) diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index ff232ffce6e..a92615da32f 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -220,7 +220,7 @@ function getDefaultValue(record, options, key) { function hasValue(record, key) { return key in record._attributes || key in record._inFlightAttributes || - record._data.hasOwnProperty(key); + key in record._data; } function getValue(record, key) { diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js index b5114a97227..8305d3da021 100644 --- a/packages/ember-data/lib/system/model/internal-model.js +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -52,16 +52,15 @@ var InternalModel = function InternalModel(type, id, store, container, data) { this.id = id; this.store = store; this.container = container; - this._data = data || {}; + this._data = data || Ember.create(null); this.modelName = type.modelName; this.errors = null; this.dataHasInitialized = false; //Look into making this lazy this._deferredTriggers = []; - this._data = {}; this._attributes = Ember.create(null); this._inFlightAttributes = Ember.create(null); - this._relationships = {}; + this._relationships = Ember.create(null); this.currentState = RootState.empty; this.isReloading = false; /* @@ -215,10 +214,10 @@ InternalModel.prototype = { }, /** - @method _createSnapshot + @method createSnapshot @private */ - _createSnapshot: function() { + createSnapshot: function() { return new Snapshot(this); }, @@ -660,6 +659,14 @@ InternalModel.prototype = { } } this._inFlightAttributes = Ember.create(null); + }, + + toString: function() { + if (this.record) { + return this.record.toString(); + } else { + return `<${this.modelName}:${this.id}>`; + } } }; diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index bdd8cd975a9..3259db1b786 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -377,7 +377,7 @@ var Model = Ember.Object.extend(Ember.Evented, { toJSON: function(options) { // container is for lazy transform lookups var serializer = JSONSerializer.create({ container: this.container }); - var snapshot = this._createSnapshot(); + var snapshot = this._internalModel.createSnapshot(); return serializer.serialize(snapshot, options); }, @@ -444,11 +444,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @private @type {Object} */ - data: Ember.computed(function() { - this._data = this._data || {}; - return this._data; - }).readOnly(), - + data: Ember.computed.readOnly('_internalModel._data'), //TODO Do we want to deprecate these? /** @@ -624,13 +620,12 @@ var Model = Ember.Object.extend(Ember.Evented, { this._internalModel.rollback(); }, - /* @method _createSnapshot @private */ _createSnapshot: function() { - return this._internalModel._createSnapshot(); + return this._internalModel.createSnapshot(); }, toStringExtension: function() { diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index effa630c431..f6b32e73391 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -172,15 +172,15 @@ var get = Ember.get; @class RootState */ -function didSetProperty(record, context) { +function didSetProperty(internalModel, context) { if (context.value === context.originalValue) { - delete record._attributes[context.name]; - record.send('propertyWasReset', context.name); + delete internalModel._attributes[context.name]; + internalModel.send('propertyWasReset', context.name); } else if (context.value !== context.oldValue) { - record.send('becomeDirty'); + internalModel.send('becomeDirty'); } - record.updateRecordArraysLater(); + internalModel.updateRecordArraysLater(); } // Implementation notes: @@ -245,36 +245,36 @@ var DirtyState = { //loadingData event, though it seems fine? loadingData: Ember.K, - propertyWasReset: function(record, name) { - var length = Ember.keys(record._attributes).length; + propertyWasReset: function(internalModel, name) { + var length = Ember.keys(internalModel._attributes).length; var stillDirty = length > 0; - if (!stillDirty) { record.send('rolledBack'); } + if (!stillDirty) { internalModel.send('rolledBack'); } }, pushedData: Ember.K, becomeDirty: Ember.K, - willCommit: function(record) { - record.transitionTo('inFlight'); + willCommit: function(internalModel) { + internalModel.transitionTo('inFlight'); }, - reloadRecord: function(record, resolve) { - resolve(get(record, 'store').reloadRecord(record)); + reloadRecord: function(internalModel, resolve) { + resolve(internalModel.store.reloadRecord(internalModel)); }, - rolledBack: function(record) { - record.transitionTo('loaded.saved'); + rolledBack: function(internalModel) { + internalModel.transitionTo('loaded.saved'); }, - becameInvalid: function(record) { - record.transitionTo('invalid'); + becameInvalid: function(internalModel) { + internalModel.transitionTo('invalid'); }, - rollback: function(record) { - record.rollback(); - record.triggerLater('ready'); + rollback: function(internalModel) { + internalModel.rollback(); + internalModel.triggerLater('ready'); } }, @@ -295,21 +295,21 @@ var DirtyState = { // TODO: More robust semantics around save-while-in-flight willCommit: Ember.K, - didCommit: function(record) { + didCommit: function(internalModel) { var dirtyType = get(this, 'dirtyType'); - record.transitionTo('saved'); - record.send('invokeLifecycleCallbacks', dirtyType); + internalModel.transitionTo('saved'); + internalModel.send('invokeLifecycleCallbacks', dirtyType); }, - becameInvalid: function(record) { - record.transitionTo('invalid'); - record.send('invokeLifecycleCallbacks'); + becameInvalid: function(internalModel) { + internalModel.transitionTo('invalid'); + internalModel.send('invokeLifecycleCallbacks'); }, - becameError: function(record) { - record.transitionTo('uncommitted'); - record.triggerLater('becameError', record); + becameError: function(internalModel) { + internalModel.transitionTo('uncommitted'); + internalModel.triggerLater('becameError', internalModel); } }, @@ -320,39 +320,39 @@ var DirtyState = { isValid: false, // EVENTS - deleteRecord: function(record) { - record.transitionTo('deleted.uncommitted'); - record.disconnectRelationships(); + deleteRecord: function(internalModel) { + internalModel.transitionTo('deleted.uncommitted'); + internalModel.disconnectRelationships(); }, - didSetProperty: function(record, context) { - record.getErrors().remove(context.name); + didSetProperty: function(internalModel, context) { + internalModel.getErrors().remove(context.name); - didSetProperty(record, context); + didSetProperty(internalModel, context); }, becomeDirty: Ember.K, - willCommit: function(record) { - record.getErrors().clear(); - record.transitionTo('inFlight'); + willCommit: function(internalModel) { + internalModel.getErrors().clear(); + internalModel.transitionTo('inFlight'); }, - rolledBack: function(record) { - record.getErrors().clear(); - record.triggerLater('ready'); + rolledBack: function(internalModel) { + internalModel.getErrors().clear(); + internalModel.triggerLater('ready'); }, - becameValid: function(record) { - record.transitionTo('uncommitted'); + becameValid: function(internalModel) { + internalModel.transitionTo('uncommitted'); }, - invokeLifecycleCallbacks: function(record) { - record.triggerLater('becameInvalid', record); + invokeLifecycleCallbacks: function(internalModel) { + internalModel.triggerLater('becameInvalid', internalModel); }, - exit: function(record) { - record._inFlightAttributes = {}; + exit: function(internalModel) { + internalModel._inFlightAttributes = Ember.create(null); } } }; @@ -396,44 +396,44 @@ var createdState = dirtyState({ isNew: true }); -createdState.invalid.rolledBack = function(record) { - record.transitionTo('deleted.saved'); +createdState.invalid.rolledBack = function(internalModel) { + internalModel.transitionTo('deleted.saved'); }; -createdState.uncommitted.rolledBack = function(record) { - record.transitionTo('deleted.saved'); +createdState.uncommitted.rolledBack = function(internalModel) { + internalModel.transitionTo('deleted.saved'); }; var updatedState = dirtyState({ dirtyType: 'updated' }); -createdState.uncommitted.deleteRecord = function(record) { - record.disconnectRelationships(); - record.transitionTo('deleted.saved'); - record.send('invokeLifecycleCallbacks'); +createdState.uncommitted.deleteRecord = function(internalModel) { + internalModel.disconnectRelationships(); + internalModel.transitionTo('deleted.saved'); + internalModel.send('invokeLifecycleCallbacks'); }; -createdState.uncommitted.rollback = function(record) { +createdState.uncommitted.rollback = function(internalModel) { DirtyState.uncommitted.rollback.apply(this, arguments); - record.transitionTo('deleted.saved'); + internalModel.transitionTo('deleted.saved'); }; -createdState.uncommitted.pushedData = function(record) { - record.transitionTo('loaded.updated.uncommitted'); - record.triggerLater('didLoad'); +createdState.uncommitted.pushedData = function(internalModel) { + internalModel.transitionTo('loaded.updated.uncommitted'); + internalModel.triggerLater('didLoad'); }; createdState.uncommitted.propertyWasReset = Ember.K; -function assertAgainstUnloadRecord(record) { - Ember.assert("You can only unload a record which is not inFlight. `" + Ember.inspect(record.record) + "`", false); +function assertAgainstUnloadRecord(internalModel) { + Ember.assert("You can only unload a record which is not inFlight. `" + internalModel + "`", false); } updatedState.inFlight.unloadRecord = assertAgainstUnloadRecord; -updatedState.uncommitted.deleteRecord = function(record) { - record.transitionTo('deleted.uncommitted'); - record.disconnectRelationships(); +updatedState.uncommitted.deleteRecord = function(internalModel) { + internalModel.transitionTo('deleted.uncommitted'); + internalModel.disconnectRelationships(); }; var RootState = { @@ -454,11 +454,11 @@ var RootState = { // in-flight state, rolling back the record doesn't move // you out of the in-flight state. rolledBack: Ember.K, - unloadRecord: function(record) { + unloadRecord: function(internalModel) { // clear relationships before moving to deleted state // otherwise it fails - record.clearRelationships(); - record.transitionTo('deleted.saved'); + internalModel.clearRelationships(); + internalModel.transitionTo('deleted.saved'); }, @@ -475,20 +475,20 @@ var RootState = { isEmpty: true, // EVENTS - loadingData: function(record, promise) { - record._loadingPromise = promise; - record.transitionTo('loading'); + loadingData: function(internalModel, promise) { + internalModel._loadingPromise = promise; + internalModel.transitionTo('loading'); }, - loadedData: function(record) { - record.transitionTo('loaded.created.uncommitted'); - record.triggerLater('ready'); + loadedData: function(internalModel) { + internalModel.transitionTo('loaded.created.uncommitted'); + internalModel.triggerLater('ready'); }, - pushedData: function(record) { - record.transitionTo('loaded.saved'); - record.triggerLater('didLoad'); - record.triggerLater('ready'); + pushedData: function(internalModel) { + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('didLoad'); + internalModel.triggerLater('ready'); } }, @@ -502,25 +502,25 @@ var RootState = { // FLAGS isLoading: true, - exit: function(record) { - record._loadingPromise = null; + exit: function(internalModel) { + internalModel._loadingPromise = null; }, // EVENTS - pushedData: function(record) { - record.transitionTo('loaded.saved'); - record.triggerLater('didLoad'); - record.triggerLater('ready'); + pushedData: function(internalModel) { + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('didLoad'); + internalModel.triggerLater('ready'); //TODO this seems out of place here - record.didCleanError(); + internalModel.didCleanError(); }, - becameError: function(record) { - record.triggerLater('becameError', record); + becameError: function(internalModel) { + internalModel.triggerLater('becameError', internalModel); }, - notFound: function(record) { - record.transitionTo('empty'); + notFound: function(internalModel) { + internalModel.transitionTo('empty'); } }, @@ -542,12 +542,12 @@ var RootState = { // If there are no local changes to a record, it remains // in the `saved` state. saved: { - setup: function(record) { - var attrs = record._attributes; + setup: function(internalModel) { + var attrs = internalModel._attributes; var isDirty = Ember.keys(attrs).length > 0; if (isDirty) { - record.adapterDidDirty(); + internalModel.adapterDidDirty(); } }, @@ -556,32 +556,32 @@ var RootState = { pushedData: Ember.K, - becomeDirty: function(record) { - record.transitionTo('updated.uncommitted'); + becomeDirty: function(internalModel) { + internalModel.transitionTo('updated.uncommitted'); }, - willCommit: function(record) { - record.transitionTo('updated.inFlight'); + willCommit: function(internalModel) { + internalModel.transitionTo('updated.inFlight'); }, - reloadRecord: function(record, resolve) { - resolve(get(record, 'store').reloadRecord(record)); + reloadRecord: function(internalModel, resolve) { + resolve(internalModel.store.reloadRecord(internalModel)); }, - deleteRecord: function(record) { - record.transitionTo('deleted.uncommitted'); - record.disconnectRelationships(); + deleteRecord: function(internalModel) { + internalModel.transitionTo('deleted.uncommitted'); + internalModel.disconnectRelationships(); }, - unloadRecord: function(record) { + unloadRecord: function(internalModel) { // clear relationships before moving to deleted state // otherwise it fails - record.clearRelationships(); - record.transitionTo('deleted.saved'); + internalModel.clearRelationships(); + internalModel.transitionTo('deleted.saved'); }, - didCommit: function(record) { - record.send('invokeLifecycleCallbacks', get(record, 'lastDirtyType')); + didCommit: function(internalModel) { + internalModel.send('invokeLifecycleCallbacks', get(internalModel, 'lastDirtyType')); }, // loaded.saved.notFound would be triggered by a failed @@ -612,8 +612,8 @@ var RootState = { isDirty: true, // TRANSITIONS - setup: function(record) { - record.updateRecordArrays(); + setup: function(internalModel) { + internalModel.updateRecordArrays(); }, // SUBSTATES @@ -625,22 +625,22 @@ var RootState = { // EVENTS - willCommit: function(record) { - record.transitionTo('inFlight'); + willCommit: function(internalModel) { + internalModel.transitionTo('inFlight'); }, - rollback: function(record) { - record.rollback(); - record.triggerLater('ready'); + rollback: function(internalModel) { + internalModel.rollback(); + internalModel.triggerLater('ready'); }, pushedData: Ember.K, becomeDirty: Ember.K, deleteRecord: Ember.K, - rolledBack: function(record) { - record.transitionTo('loaded.saved'); - record.triggerLater('ready'); + rolledBack: function(internalModel) { + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('ready'); } }, @@ -658,20 +658,20 @@ var RootState = { // TODO: More robust semantics around save-while-in-flight willCommit: Ember.K, - didCommit: function(record) { - record.transitionTo('saved'); + didCommit: function(internalModel) { + internalModel.transitionTo('saved'); - record.send('invokeLifecycleCallbacks'); + internalModel.send('invokeLifecycleCallbacks'); }, - becameError: function(record) { - record.transitionTo('uncommitted'); - record.triggerLater('becameError', record); + becameError: function(internalModel) { + internalModel.transitionTo('uncommitted'); + internalModel.triggerLater('becameError', internalModel); }, - becameInvalid: function(record) { - record.transitionTo('invalid'); - record.triggerLater('becameInvalid', record); + becameInvalid: function(internalModel) { + internalModel.transitionTo('invalid'); + internalModel.triggerLater('becameInvalid', internalModel); } }, @@ -682,14 +682,14 @@ var RootState = { // FLAGS isDirty: false, - setup: function(record) { - var store = get(record, 'store'); - store._dematerializeRecord(record); + setup: function(internalModel) { + var store = internalModel.store; + store._dematerializeRecord(internalModel); }, - invokeLifecycleCallbacks: function(record) { - record.triggerLater('didDelete', record); - record.triggerLater('didCommit', record); + invokeLifecycleCallbacks: function(internalModel) { + internalModel.triggerLater('didDelete', internalModel); + internalModel.triggerLater('didCommit', internalModel); }, willCommit: Ember.K, @@ -700,10 +700,10 @@ var RootState = { invalid: { isValid: false, - didSetProperty: function(record, context) { - record.getErrors().remove(context.name); + didSetProperty: function(internalModel, context) { + internalModel.getErrors().remove(context.name); - didSetProperty(record, context); + didSetProperty(internalModel, context); }, deleteRecord: Ember.K, @@ -711,27 +711,27 @@ var RootState = { willCommit: Ember.K, - rolledBack: function(record) { - record.getErrors().clear(); - record.transitionTo('loaded.saved'); - record.triggerLater('ready'); + rolledBack: function(internalModel) { + internalModel.getErrors().clear(); + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('ready'); }, - becameValid: function(record) { - record.transitionTo('uncommitted'); + becameValid: function(internalModel) { + internalModel.transitionTo('uncommitted'); } } }, - invokeLifecycleCallbacks: function(record, dirtyType) { + invokeLifecycleCallbacks: function(internalModel, dirtyType) { if (dirtyType === 'created') { - record.triggerLater('didCreate', record); + internalModel.triggerLater('didCreate', internalModel); } else { - record.triggerLater('didUpdate', record); + internalModel.triggerLater('didUpdate', internalModel); } - record.triggerLater('didCommit', record); + internalModel.triggerLater('didCommit', internalModel); } }; diff --git a/packages/ember-data/lib/system/snapshot.js b/packages/ember-data/lib/system/snapshot.js index 7bcfe4274f2..7a3d5a615eb 100644 --- a/packages/ember-data/lib/system/snapshot.js +++ b/packages/ember-data/lib/system/snapshot.js @@ -236,7 +236,7 @@ Snapshot.prototype = { if (id) { result = get(inverseRecord, 'id'); } else { - result = inverseRecord._createSnapshot(); + result = inverseRecord.createSnapshot(); } } else { result = null; @@ -306,9 +306,9 @@ Snapshot.prototype = { results = []; members.forEach(function(member) { if (ids) { - results.push(get(member, 'id')); + results.push(member.id); } else { - results.push(member._createSnapshot()); + results.push(member.createSnapshot()); } }); } diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index b9ec3557340..6bb6895f638 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -253,7 +253,7 @@ Store = Service.extend({ @param {Object} options an options hash */ serialize: function(record, options) { - var snapshot = record._createSnapshot(); + var snapshot = record._internalModel.createSnapshot(); return this.serializerFor(snapshot.modelName).serialize(snapshot, options); }, @@ -315,7 +315,7 @@ Store = Service.extend({ */ createRecord: function(modelName, inputProperties) { var typeClass = this.modelFor(modelName); - var properties = copy(inputProperties) || {}; + var properties = copy(inputProperties) || Ember.create(null); // If the passed properties do not include a primary key, // give the adapter an opportunity to generate one. Typically, @@ -606,7 +606,6 @@ Store = Service.extend({ @return {Promise} promise */ findById: function(modelName, id, preload) { - var type = this.modelFor(modelName); var internalModel = this._internalModelForId(type, id); @@ -654,40 +653,39 @@ Store = Service.extend({ @method fetchRecord @private - @param {DS.Model} record + @param {InternalModel} internal model @return {Promise} promise */ - fetchRecord: function(record) { - var typeClass = record.type; - var id = get(record, 'id'); + fetchRecord: function(internalModel) { + var typeClass = internalModel.type; + var id = internalModel.id; var adapter = this.adapterFor(typeClass); Ember.assert("You tried to find a record but you have no adapter (for " + typeClass + ")", adapter); Ember.assert("You tried to find a record but your adapter (for " + typeClass + ") does not implement 'find'", typeof adapter.find === 'function'); - var promise = _find(adapter, this, typeClass, id, record); + var promise = _find(adapter, this, typeClass, id, internalModel); return promise; }, scheduleFetchMany: function(records) { - var internalModel = map(records, function(record) { return record._internalModel; }); - return Promise.all(map(internalModel, this.scheduleFetch, this)); + var internalModels = map(records, function(record) { return record._internalModel; }); + return Promise.all(map(internalModels, this.scheduleFetch, this)); }, - scheduleFetch: function(record) { - var typeClass = record.type; + scheduleFetch: function(internalModel) { + var typeClass = internalModel.type; - if (isNone(record)) { return null; } - if (record._loadingPromise) { return record._loadingPromise; } + if (internalModel._loadingPromise) { return internalModel._loadingPromise; } - var resolver = Ember.RSVP.defer('Fetching ' + typeClass + 'with id: ' + record.id); + var resolver = Ember.RSVP.defer('Fetching ' + typeClass + 'with id: ' + internalModel.id); var recordResolverPair = { - record: record, + record: internalModel, resolver: resolver }; var promise = resolver.promise; - record.loadingData(promise); + internalModel.loadingData(promise); if (!this._pendingFetch.get(typeClass)) { this._pendingFetch.set(typeClass, [recordResolverPair]); @@ -773,10 +771,10 @@ Store = Service.extend({ // records from the grouped snapshots even though the _findMany() finder // will once again convert the records to snapshots for adapter.findMany() - var snapshots = Ember.A(records).invoke('_createSnapshot'); + var snapshots = Ember.A(records).invoke('createSnapshot'); var groups = adapter.groupRecordsForFindMany(this, snapshots); forEach(groups, function (groupOfSnapshots) { - var groupOfRecords = Ember.A(groupOfSnapshots).mapBy('record._internalModel'); + var groupOfRecords = Ember.A(groupOfSnapshots).mapBy('_internalModel'); var requestedRecords = Ember.A(groupOfRecords); var ids = requestedRecords.mapBy('id'); if (ids.length > 1) { @@ -836,16 +834,16 @@ Store = Service.extend({ @param {DS.Model} record @return {Promise} promise */ - reloadRecord: function(record) { - var type = record.constructor; + reloadRecord: function(internalModel) { + var type = internalModel.type; var adapter = this.adapterFor(type); - var id = get(record, 'id'); + var id = internalModel.id; Ember.assert("You cannot reload a record without an ID", id); Ember.assert("You tried to reload a record but you have no adapter (for " + type + ")", adapter); Ember.assert("You tried to reload a record but your adapter does not implement `find`", typeof adapter.find === 'function'); - return this.scheduleFetch(record); + return this.scheduleFetch(internalModel); }, /** @@ -1244,7 +1242,7 @@ Store = Service.extend({ @method dataWasUpdated @private @param {Class} type - @param {InternalModel} record + @param {InternalModel} internal model */ dataWasUpdated: function(type, internalModel) { this.recordArrayManager.recordDidChange(internalModel); @@ -1262,11 +1260,11 @@ Store = Service.extend({ @method scheduleSave @private - @param {InternalModel} record + @param {InternalModel} internal model @param {Resolver} resolver */ scheduleSave: function(internalModel, resolver) { - var snapshot = internalModel._createSnapshot(); + var snapshot = internalModel.createSnapshot(); internalModel.flushChangedAttributes(); internalModel.adapterWillCommit(); this._pendingSave.push([snapshot, resolver]); @@ -1315,7 +1313,7 @@ Store = Service.extend({ @method didSaveRecord @private - @param {InternalModel} record the in-flight record + @param {InternalModel} internal model the in-flight internal model @param {Object} data optional data (see above) */ didSaveRecord: function(internalModel, data) { @@ -1337,7 +1335,7 @@ Store = Service.extend({ @method recordWasInvalid @private - @param {InternalModel} record + @param {InternalModel} internal model @param {Object} errors */ recordWasInvalid: function(internalModel, errors) { @@ -1351,7 +1349,7 @@ Store = Service.extend({ @method recordWasError @private - @param {InternalModel} record + @param {InternalModel} internal model */ recordWasError: function(internalModel) { internalModel.adapterDidError(); @@ -1364,7 +1362,7 @@ Store = Service.extend({ @method updateId @private - @param {InternalModel} record + @param {InternalModel} internal model @param {Object} data */ updateId: function(internalModel, data) { @@ -1777,7 +1775,7 @@ Store = Service.extend({ @param {subclass of DS.Model} type @param {String} id @param {Object} data - @return {InternalModel} record + @return {InternalModel} internal model */ buildInternalModel: function(type, id, data) { var typeMap = this.typeMapFor(type); @@ -1827,7 +1825,7 @@ Store = Service.extend({ @method _dematerializeRecord @private - @param {InternalModel} record + @param {InternalModel} internal model */ _dematerializeRecord: function(internalModel) { var type = internalModel.type; diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index 27b5707e3bb..bc6143160c2 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -12,8 +12,8 @@ import { var Promise = Ember.RSVP.Promise; var map = Ember.EnumerableUtils.map; -export function _find(adapter, store, typeClass, id, record) { - var snapshot = record._createSnapshot(); +export function _find(adapter, store, typeClass, id, internalModel) { + var snapshot = internalModel.createSnapshot(); var promise = adapter.find(store, typeClass, id, snapshot); var serializer = serializerForAdapter(store, adapter, typeClass); var label = "DS: Handle Adapter#find of " + typeClass + " with id: " + id; @@ -31,9 +31,9 @@ export function _find(adapter, store, typeClass, id, record) { return record._internalModel; }); }, function(error) { - record.notFound(); - if (record.isEmpty()) { - record.unloadRecord(); + internalModel.notFound(); + if (internalModel.isEmpty()) { + internalModel.unloadRecord(); } throw error; @@ -41,8 +41,8 @@ export function _find(adapter, store, typeClass, id, record) { } -export function _findMany(adapter, store, typeClass, ids, records) { - var snapshots = Ember.A(records).invoke('_createSnapshot'); +export function _findMany(adapter, store, typeClass, ids, internalModels) { + var snapshots = Ember.A(internalModels).invoke('createSnapshot'); var promise = adapter.findMany(store, typeClass, ids, snapshots); var serializer = serializerForAdapter(store, adapter, typeClass); var label = "DS: Handle Adapter#findMany of " + typeClass; @@ -67,15 +67,15 @@ export function _findMany(adapter, store, typeClass, ids, records) { }, null, "DS: Extract payload of " + typeClass); } -export function _findHasMany(adapter, store, record, link, relationship) { - var snapshot = record._createSnapshot(); +export function _findHasMany(adapter, store, internalModel, link, relationship) { + var snapshot = internalModel.createSnapshot(); var promise = adapter.findHasMany(store, snapshot, link, relationship); var serializer = serializerForAdapter(store, adapter, relationship.type); - var label = "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type; + var label = "DS: Handle Adapter#findHasMany of " + internalModel + " : " + relationship.type; promise = Promise.cast(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); - promise = _guard(promise, _bind(_objectIsAlive, record)); + promise = _guard(promise, _bind(_objectIsAlive, internalModel)); return promise.then(function(adapterPayload) { return store._adapterRun(function() { @@ -87,18 +87,18 @@ export function _findHasMany(adapter, store, record, link, relationship) { var records = store.pushMany(relationship.type, payload); return map(records, function(record) { return record._internalModel; }); }); - }, null, "DS: Extract payload of " + record + " : hasMany " + relationship.type); + }, null, "DS: Extract payload of " + internalModel + " : hasMany " + relationship.type); } -export function _findBelongsTo(adapter, store, record, link, relationship) { - var snapshot = record._createSnapshot(); +export function _findBelongsTo(adapter, store, internalModel, link, relationship) { + var snapshot = internalModel.createSnapshot(); var promise = adapter.findBelongsTo(store, snapshot, link, relationship); var serializer = serializerForAdapter(store, adapter, relationship.type); - var label = "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type; + var label = "DS: Handle Adapter#findBelongsTo of " + internalModel + " : " + relationship.type; promise = Promise.cast(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); - promise = _guard(promise, _bind(_objectIsAlive, record)); + promise = _guard(promise, _bind(_objectIsAlive, internalModel)); return promise.then(function(adapterPayload) { return store._adapterRun(function() { @@ -112,7 +112,7 @@ export function _findBelongsTo(adapter, store, record, link, relationship) { //TODO Optimize return record._internalModel; }); - }, null, "DS: Extract payload of " + record + " : " + relationship.type); + }, null, "DS: Extract payload of " + internalModel + " : " + relationship.type); } export function _findAll(adapter, store, typeClass, sinceToken) { From 89a518960f96e8afd2068990a24962e2091d2497 Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Tue, 2 Jun 2015 22:26:09 +0200 Subject: [PATCH 0824/2527] remove deprecated RecordArray#pushRecord --- .../lib/system/record-array-manager.js | 2 +- .../lib/system/record-arrays/record-array.js | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/packages/ember-data/lib/system/record-array-manager.js b/packages/ember-data/lib/system/record-array-manager.js index 43cd8bec4ca..609e90c7275 100644 --- a/packages/ember-data/lib/system/record-array-manager.js +++ b/packages/ember-data/lib/system/record-array-manager.js @@ -124,7 +124,7 @@ export default Ember.Object.extend({ if (shouldBeInArray) { if (!recordArrays.has(array)) { - array._pushRecord(record); + array.addRecord(record); recordArrays.add(array); } } else if (!shouldBeInArray) { diff --git a/packages/ember-data/lib/system/record-arrays/record-array.js b/packages/ember-data/lib/system/record-arrays/record-array.js index 6a67743f05a..24ee764eac0 100644 --- a/packages/ember-data/lib/system/record-arrays/record-array.js +++ b/packages/ember-data/lib/system/record-arrays/record-array.js @@ -135,22 +135,6 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { } }, - _pushRecord: function(record) { - get(this, 'content').pushObject(record); - }, - - /** - Adds a record to the `RecordArray`, but allows duplicates - - @deprecated - @method pushRecord - @private - @param {DS.Model} record - */ - pushRecord: function(record) { - Ember.deprecate('Usage of `recordArray.pushRecord` is deprecated, use `recordArray.addObject` instead'); - this._pushRecord(record); - }, /** Removes a record to the `RecordArray`. From f2e4033cb8b833be73ed28f2dfcc36856e557a29 Mon Sep 17 00:00:00 2001 From: Mike Hollis Date: Tue, 2 Jun 2015 16:53:22 -0400 Subject: [PATCH 0825/2527] Add test for error on model.create() --- packages/ember-data/tests/unit/model-test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/ember-data/tests/unit/model-test.js b/packages/ember-data/tests/unit/model-test.js index c5a9866104d..7a03835b9e6 100644 --- a/packages/ember-data/tests/unit/model-test.js +++ b/packages/ember-data/tests/unit/model-test.js @@ -773,3 +773,9 @@ test("Pushing a record into the store should transition it to the loaded state", equal(person.get('isNew'), false, 'push should put records into the loaded state'); }); }); + +test("A subclass of DS.Model throws an error when calling create() directly", function() { + throws(function() { + Person.create(); + }, /You should not call `create` on a model/, "Throws an error when calling create() on model"); +}); From 6d888b013737fa831a071f7201b1f8fed13cc53a Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Tue, 2 Jun 2015 23:02:35 +0200 Subject: [PATCH 0826/2527] add test for Store#getById --- .../tests/unit/store/get-by-id-test.js | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 packages/ember-data/tests/unit/store/get-by-id-test.js diff --git a/packages/ember-data/tests/unit/store/get-by-id-test.js b/packages/ember-data/tests/unit/store/get-by-id-test.js new file mode 100644 index 00000000000..440101867a8 --- /dev/null +++ b/packages/ember-data/tests/unit/store/get-by-id-test.js @@ -0,0 +1,35 @@ +var env, store, Person; +var run = Ember.run; + +module("unit/store/getById - Store getById", { + setup: function() { + + Person = DS.Model.extend(); + Person.toString = function() { + return 'Person'; + }; + + env = setupStore({ + person: Person + }); + store = env.store; + }, + + teardown: function() { + Ember.run(store, 'destroy'); + } +}); + +test("getById should return the record if it is in the store ", function() { + + run(function() { + var person = store.push('person', { id: 1 }); + equal(person, store.getById('person', 1), 'getById only return the corresponding record in the store'); + }); +}); + +test("getById should return null if the record is not in the store ", function() { + run(function() { + equal(null, store.getById('person', 1), 'getById returns null if the corresponding record is not in the store'); + }); +}); From e424f6783610567d74ab0993072f22f5a68f8430 Mon Sep 17 00:00:00 2001 From: Sergio Arbeo Date: Tue, 2 Jun 2015 23:30:19 +0200 Subject: [PATCH 0827/2527] Add test for store#deleteRecord. Fix 3160. --- .../tests/integration/store-test.js | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/packages/ember-data/tests/integration/store-test.js b/packages/ember-data/tests/integration/store-test.js index 854f2939afa..b57ce7552be 100644 --- a/packages/ember-data/tests/integration/store-test.js +++ b/packages/ember-data/tests/integration/store-test.js @@ -415,3 +415,32 @@ test("Using store#serializerFor should not throw an error when looking up the ap ok(applicationSerializer); }); }); + +module("integration/store - deleteRecord", { + setup: function() { + initializeStore(DS.RESTAdapter.extend()); + } +}); + +test("Using store#deleteRecord should mark the model for removal", function() { + expect(3); + var person; + + run(function() { + person = store.push('person', { + id: 1, + name: 'Tom Dale' + }); + }); + + ok(store.hasRecordForId('person', 1), 'expected the record to be in the store'); + + var personDeleteRecord = tap(person, 'deleteRecord'); + + run(function() { + store.deleteRecord(person); + }); + + equal(personDeleteRecord.called.length, 1, 'expected person.deleteRecord to have been called'); + ok(person.get('isDeleted'), 'expect person to be isDeleted'); +}); From bcefa52774af9cbf8d9a7821664bde6452414628 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 28 May 2015 18:23:17 -0500 Subject: [PATCH 0828/2527] avoid unnecessary singularization for belongsTo relationships --- packages/ember-data/lib/system/relationship-meta.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/relationship-meta.js b/packages/ember-data/lib/system/relationship-meta.js index 3ec11c098f8..e2265acc260 100644 --- a/packages/ember-data/lib/system/relationship-meta.js +++ b/packages/ember-data/lib/system/relationship-meta.js @@ -5,7 +5,10 @@ export function typeForRelationshipMeta(meta) { var modelName; modelName = meta.type || meta.key; - return singularize(normalizeModelName(modelName)); + if (meta.kind === 'hasMany') { + modelName = singularize(normalizeModelName(modelName)); + } + return modelName; } export function relationshipFromMeta(meta) { From 0c5100931510caf005951ba5dc261ae8322dd549 Mon Sep 17 00:00:00 2001 From: Ian Storz Date: Tue, 2 Jun 2015 19:21:33 -0600 Subject: [PATCH 0829/2527] Ensure snapshot.belongsTo() and hasMany() do not return deleted records Even though we remove records from their opposite relationships once they are deleted, this commit places this functionality under test and ensures that only non deleted records are returned from snapshot.belongsTo() and snapshot.hasMany(). Closes #3081 --- packages/ember-data/lib/system/snapshot.js | 12 ++-- .../tests/integration/snapshot-test.js | 72 ++++++++++++++++++- 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/packages/ember-data/lib/system/snapshot.js b/packages/ember-data/lib/system/snapshot.js index 7a3d5a615eb..6dab199c066 100644 --- a/packages/ember-data/lib/system/snapshot.js +++ b/packages/ember-data/lib/system/snapshot.js @@ -232,7 +232,7 @@ Snapshot.prototype = { inverseRecord = get(relationship, 'inverseRecord'); if (hasData) { - if (inverseRecord) { + if (inverseRecord && !inverseRecord.isDeleted()) { if (id) { result = get(inverseRecord, 'id'); } else { @@ -305,10 +305,12 @@ Snapshot.prototype = { if (hasData) { results = []; members.forEach(function(member) { - if (ids) { - results.push(member.id); - } else { - results.push(member.createSnapshot()); + if (!member.isDeleted()) { + if (ids) { + results.push(member.id); + } else { + results.push(member.createSnapshot()); + } } }); } diff --git a/packages/ember-data/tests/integration/snapshot-test.js b/packages/ember-data/tests/integration/snapshot-test.js index 8b85621cab2..b00a58a850c 100644 --- a/packages/ember-data/tests/integration/snapshot-test.js +++ b/packages/ember-data/tests/integration/snapshot-test.js @@ -166,6 +166,22 @@ test("snapshot.belongsTo() returns a snapshot if relationship is set", function( }); }); +test("snapshot.belongsTo() returns null if relationship is deleted", function() { + expect(1); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var comment = env.store.push('comment', { id: 2, body: 'This is comment', post: 1 }); + + post.deleteRecord(); + + var snapshot = comment._createSnapshot(); + var relationship = snapshot.belongsTo('post'); + + equal(relationship, null, 'relationship unset after deleted'); + }); +}); + test("snapshot.belongsTo() returns undefined if relationship is a link", function() { expect(1); @@ -246,7 +262,7 @@ test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when setting }); }); -test("snapshot.hasMany() returns ID if option.id is set", function() { +test("snapshot.belongsTo() returns ID if option.id is set", function() { expect(1); run(function() { @@ -259,6 +275,22 @@ test("snapshot.hasMany() returns ID if option.id is set", function() { }); }); +test("snapshot.belongsTo() returns null if option.id is set but relationship was deleted", function() { + expect(1); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var comment = env.store.push('comment', { id: 2, body: 'This is comment', post: 1 }); + + post.deleteRecord(); + + var snapshot = comment._createSnapshot(); + var relationship = snapshot.belongsTo('post', { id: true }); + + equal(relationship, null, 'relationship unset after deleted'); + }); +}); + test("snapshot.hasMany() returns undefined if relationship is undefined", function() { expect(1); @@ -306,6 +338,25 @@ test("snapshot.hasMany() returns array of snapshots if relationship is set", fun }); }); +test("snapshot.hasMany() returns empty array if relationship records are deleted", function() { + expect(2); + + run(function() { + var comment1 = env.store.push('comment', { id: 1, body: 'This is the first comment' }); + var comment2 = env.store.push('comment', { id: 2, body: 'This is the second comment' }); + var post = env.store.push('post', { id: 3, title: 'Hello World', comments: [1, 2] }); + + comment1.deleteRecord(); + comment2.deleteRecord(); + + var snapshot = post._createSnapshot(); + var relationship = snapshot.hasMany('comments'); + + ok(relationship instanceof Array, 'relationship is an instance of Array'); + equal(relationship.length, 0, 'relationship is empty'); + }); +}); + test("snapshot.hasMany() returns array of IDs if option.ids is set", function() { expect(1); @@ -318,6 +369,25 @@ test("snapshot.hasMany() returns array of IDs if option.ids is set", function() }); }); +test("snapshot.hasMany() returns empty array of IDs if option.ids is set but relationship records were deleted", function() { + expect(2); + + run(function() { + var comment1 = env.store.push('comment', { id: 1, body: 'This is the first comment' }); + var comment2 = env.store.push('comment', { id: 2, body: 'This is the second comment' }); + var post = env.store.push('post', { id: 3, title: 'Hello World', comments: [1, 1] }); + + comment1.deleteRecord(); + comment2.deleteRecord(); + + var snapshot = post._createSnapshot(); + var relationship = snapshot.hasMany('comments', { ids: true }); + + ok(relationship instanceof Array, 'relationship is an instance of Array'); + equal(relationship.length, 0, 'relationship is empty'); + }); +}); + test("snapshot.hasMany() returns undefined if relationship is a link", function() { expect(1); From e074ce006c1ba0079493f1f7a220f3405b0820ff Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 2 Jun 2015 19:32:47 -0500 Subject: [PATCH 0830/2527] Merge branch 'master' of github.com:emberjs/data into remove-passing-factories-to-store-methods --- .codeclimate.yml | 7 + Brocfile.js | 2 - bin/publish-to-s3.js | 4 +- config/s3ProjectConfig.js | 2 +- lib/amd-build.js | 4 - .../blueprints/ember-data/index.js | 1 + ...-inside-round-braces-in-call-expression.js | 2 - lib/lib-tree.js | 2 +- lib/test-tree.js | 4 +- .../ember-data/lib/adapters/rest-adapter.js | 8 +- packages/ember-data/lib/main.js | 3 + .../lib/serializers/embedded-records-mixin.js | 16 +- .../lib/serializers/rest-serializer.js | 46 +- packages/ember-data/lib/system/coerce-id.js | 9 + packages/ember-data/lib/system/many-array.js | 17 +- .../ember-data/lib/system/model/attributes.js | 16 +- .../lib/system/model/internal-model.js | 700 ++++++++++++++++++ packages/ember-data/lib/system/model/model.js | 543 +------------- .../ember-data/lib/system/model/states.js | 291 ++++---- .../lib/system/record-array-manager.js | 12 +- .../adapter-populated-record-array.js | 6 +- .../lib/system/record-arrays/record-array.js | 27 +- .../lib/system/relationships/belongs-to.js | 10 +- .../lib/system/relationships/has-many.js | 7 +- .../system/relationships/state/belongs-to.js | 20 +- .../lib/system/relationships/state/create.js | 2 +- .../system/relationships/state/has-many.js | 13 +- .../relationships/state/relationship.js | 6 +- packages/ember-data/lib/system/snapshot.js | 53 +- packages/ember-data/lib/system/store.js | 298 ++++---- .../ember-data/lib/system/store/finders.js | 70 +- .../integration/adapter/find-all-test.js | 4 + .../integration/adapter/rest-adapter-test.js | 2 +- .../integration/record-array-manager-test.js | 6 +- .../tests/integration/records/save-test.js | 15 +- .../relationships/belongs-to-test.js | 12 +- .../relationships/has-many-test.js | 18 +- .../embedded-records-mixin-test.js | 132 ++++ .../tests/integration/snapshot-test.js | 14 + packages/ember-data/tests/unit/model-test.js | 20 +- .../tests/unit/model/internal-model-test.js | 19 + .../unit/model/lifecycle-callbacks-test.js | 26 + .../ember-data/tests/unit/model/merge-test.js | 35 + .../model/relationships/record-array-test.js | 7 +- .../tests/unit/model/rollback-test.js | 45 ++ .../tests/unit/store/adapter-interop-test.js | 73 +- .../tests/unit/store/get-by-id-test.js | 35 + .../tests/unit/store/unload-test.js | 4 +- tests/ember-configuration.js | 2 +- tests/ember-data-setup.js | 2 - tests/index.html | 4 +- tests/qunit-configuration.js | 135 ++-- 52 files changed, 1717 insertions(+), 1094 deletions(-) create mode 100644 .codeclimate.yml create mode 100644 packages/ember-data/lib/system/coerce-id.js create mode 100644 packages/ember-data/lib/system/model/internal-model.js create mode 100644 packages/ember-data/tests/unit/model/internal-model-test.js create mode 100644 packages/ember-data/tests/unit/store/get-by-id-test.js diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 00000000000..05f8fac2da5 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,7 @@ +# Save as .codeclimate.yml (note leading .) in project root directory +languages: + JavaScript: true + exclude_paths: + - "packages/activemodel-adapter/tests/*" + - "packages/ember/tests/*" + - "packages/ember-data/tests/*" diff --git a/Brocfile.js b/Brocfile.js index 92116e9158f..ad0c470a5b5 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -17,8 +17,6 @@ var version = require('git-repo-version')(10); var yuidoc = require('broccoli-yuidoc'); var replace = require('broccoli-replace'); var stew = require('broccoli-stew'); -var path = require('path'); -var fs = require('fs'); var babel = require('broccoli-babel-transpiler'); var babelOptions = require('./config/babel'); var fileCreator = require('broccoli-file-creator'); diff --git a/bin/publish-to-s3.js b/bin/publish-to-s3.js index bc1c9c0e0ce..7cda3058eb2 100755 --- a/bin/publish-to-s3.js +++ b/bin/publish-to-s3.js @@ -15,6 +15,6 @@ // ./bin/publish_to_s3.js // ``` var S3Publisher = require('ember-publisher'); -var configPath = require('path').join(__dirname, '../config/s3ProjectConfig.js') -publisher = new S3Publisher({projectConfigPath: configPath}); +var configPath = require('path').join(__dirname, '../config/s3ProjectConfig.js'); +var publisher = new S3Publisher({projectConfigPath: configPath}); publisher.publish(); diff --git a/config/s3ProjectConfig.js b/config/s3ProjectConfig.js index fa8c7239b24..e24fafd558c 100644 --- a/config/s3ProjectConfig.js +++ b/config/s3ProjectConfig.js @@ -6,7 +6,7 @@ function fileMap(revision,tag,date) { 'ember-data.prod.js': fileObject('ember-data.prod', '.js', 'text/javascript', revision, tag, date), 'docs/data.json': fileObject('ember-data-docs', '.json', 'application/json', revision, tag, date) }; -}; +} function fileObject(baseName, extension, contentType, currentRevision, tag, date){ var fullName = '/' + baseName + extension; diff --git a/lib/amd-build.js b/lib/amd-build.js index f9cc7a467ab..0fc58f3ae25 100644 --- a/lib/amd-build.js +++ b/lib/amd-build.js @@ -1,11 +1,7 @@ -var pickFiles = require('broccoli-static-compiler'); -var concat = require('broccoli-concat'); var es6 = require('broccoli-es6-module-transpiler'); var merge = require('broccoli-merge-trees'); var PackageResolver = require('es6-module-transpiler-package-resolver'); var AMDFormatter = require('es6-module-transpiler-amd-formatter'); -var fileCreator = require('broccoli-file-creator'); -var merge = require('broccoli-merge-trees'); var replace = require('broccoli-replace'); function amdES6Package(packages, root, outfile) { diff --git a/lib/ember-addon/blueprints/ember-data/index.js b/lib/ember-addon/blueprints/ember-data/index.js index 289382d65be..0de95eb439c 100644 --- a/lib/ember-addon/blueprints/ember-data/index.js +++ b/lib/ember-addon/blueprints/ember-data/index.js @@ -1,3 +1,4 @@ +/* jshint node: true */ 'use strict'; module.exports = { diff --git a/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js b/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js index 3685932f017..1245ee81680 100644 --- a/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js +++ b/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js @@ -35,8 +35,6 @@ module.exports.prototype = { }, check: function(file, errors) { - var tokens = file.getTokens(); - file.iterateNodesByType('CallExpression', function(node) { var nodeBeforeRoundBrace = node; diff --git a/lib/lib-tree.js b/lib/lib-tree.js index 3122aa868af..b140ea93168 100644 --- a/lib/lib-tree.js +++ b/lib/lib-tree.js @@ -6,4 +6,4 @@ module.exports = function libTree(tree) { srcDir: '/', destDir: '/' }); -} +}; diff --git a/lib/test-tree.js b/lib/test-tree.js index e48710e848a..eff7cfc54e4 100644 --- a/lib/test-tree.js +++ b/lib/test-tree.js @@ -4,7 +4,6 @@ var jshint = require('broccoli-jshint'); var path = require('path'); var wrap = require('broccoli-wrap'); var merge = require('broccoli-merge-trees'); -var amdBuild = require('./amd-build'); module.exports = function testTree(sourceTree, compiled) { var emberDataFiles = pickFiles(sourceTree, { @@ -29,8 +28,9 @@ module.exports = function testTree(sourceTree, compiled) { }; function hint(tree){ + var dirname = __dirname || path.resolve(path.dirname()); var jshinted = jshint(tree, { - jshintrcPath: path.join(__dirname, '..', '.jshintrc') + jshintrcPath: path.join(dirname, '..', '.jshintrc') }); return wrap(jshinted, { wrapper: [ "if (!QUnit.urlParams.nojshint) {\n", "\n}"], diff --git a/packages/ember-data/lib/adapters/rest-adapter.js b/packages/ember-data/lib/adapters/rest-adapter.js index 0d0e70b88c6..f6ee3f00e11 100644 --- a/packages/ember-data/lib/adapters/rest-adapter.js +++ b/packages/ember-data/lib/adapters/rest-adapter.js @@ -99,7 +99,7 @@ import BuildURLMixin from "ember-data/adapters/build-url-mixin"; property on the adapter: ```js - DS.RESTAdapter.reopen({ + App.ApplicationAdapter = DS.RESTAdapter.extend({ namespace: 'api/1' }); ``` @@ -110,7 +110,7 @@ import BuildURLMixin from "ember-data/adapters/build-url-mixin"; An adapter can target other hosts by setting the `host` property. ```js - DS.RESTAdapter.reopen({ + App.ApplicationAdapter = DS.RESTAdapter.extend({ host: 'https://api.example.com' }); ``` @@ -281,7 +281,7 @@ export default Adapter.extend(BuildURLMixin, { property on the adapter: ```javascript - DS.RESTAdapter.reopen({ + App.ApplicationAdapter = DS.RESTAdapter.extend({ namespace: 'api/1' }); ``` @@ -296,7 +296,7 @@ export default Adapter.extend(BuildURLMixin, { An adapter can target other hosts by setting the `host` property. ```javascript - DS.RESTAdapter.reopen({ + App.ApplicationAdapter = DS.RESTAdapter.extend({ host: 'https://api.example.com' }); ``` diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index 1def75f8607..d5a28b47a5a 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -19,6 +19,8 @@ import "ember-data/ext/date"; import normalizeModelName from "ember-data/system/normalize-model-name"; +import InternalModel from "ember-data/system/model/internal-model"; + import { PromiseArray, PromiseObject, @@ -85,6 +87,7 @@ DS.RootState = RootState; DS.attr = attr; DS.Errors = Errors; +DS.InternalModel = InternalModel; DS.Snapshot = Snapshot; DS.Adapter = Adapter; diff --git a/packages/ember-data/lib/serializers/embedded-records-mixin.js b/packages/ember-data/lib/serializers/embedded-records-mixin.js index 0e4a105755b..61789365942 100644 --- a/packages/ember-data/lib/serializers/embedded-records-mixin.js +++ b/packages/ember-data/lib/serializers/embedded-records-mixin.js @@ -1,4 +1,3 @@ -var get = Ember.get; var forEach = Ember.EnumerableUtils.forEach; var camelize = Ember.String.camelize; @@ -299,13 +298,17 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ } var includeIds = this.hasSerializeIdsOption(attr); var includeRecords = this.hasSerializeRecordsOption(attr); - var key; + var key, hasMany; if (includeIds) { key = this.keyForRelationship(attr, relationship.kind, 'serialize'); json[key] = snapshot.hasMany(attr, { ids: true }); } else if (includeRecords) { key = this.keyForAttribute(attr, 'serialize'); - json[key] = snapshot.hasMany(attr).map(function(embeddedSnapshot) { + hasMany = snapshot.hasMany(attr); + + Ember.warn("The embedded relationship '" + key + "' is undefined for '" + snapshot.modelName + "' with id '" + snapshot.id + "'. Please include it in your original payload.", Ember.typeOf(hasMany) !== 'undefined'); + + json[key] = Ember.A(hasMany).map(function(embeddedSnapshot) { var embeddedJson = embeddedSnapshot.record.serialize({ includeId: true }); this.removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, embeddedJson); return embeddedJson; @@ -442,11 +445,11 @@ function extractEmbeddedHasManyPolymorphic(store, key, hash) { var modelName = data.type; var embeddedSerializer = store.serializerFor(modelName); var embeddedTypeClass = store.modelFor(modelName); - var primaryKey = get(embeddedSerializer, 'primaryKey'); + // var primaryKey = embeddedSerializer.get('primaryKey'); var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null); store.push(embeddedTypeClass.modelName, embeddedRecord); - ids.push({ id: embeddedRecord[primaryKey], type: modelName }); + ids.push({ id: embeddedRecord.id, type: modelName }); }); hash[key] = ids; @@ -476,12 +479,11 @@ function extractEmbeddedBelongsToPolymorphic(store, key, hash) { var modelName = data.type; var embeddedSerializer = store.serializerFor(modelName); var embeddedTypeClass = store.modelFor(modelName); - var primaryKey = get(embeddedSerializer, 'primaryKey'); var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null); store.push(embeddedTypeClass.modelName, embeddedRecord); - hash[key] = embeddedRecord[primaryKey]; + hash[key] = embeddedRecord.id; hash[key + 'Type'] = modelName; return hash; } diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index 2a96622ac68..6743061b50e 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -5,15 +5,12 @@ import JSONSerializer from "ember-data/serializers/json-serializer"; import normalizeModelName from "ember-data/system/normalize-model-name"; import {singularize} from "ember-inflector/lib/system/string"; +import coerceId from "ember-data/system/coerce-id"; var forEach = Ember.ArrayPolyfills.forEach; var map = Ember.ArrayPolyfills.map; var camelize = Ember.String.camelize; -function coerceId(id) { - return id == null ? null : id + ''; -} - /** Normally, applications will use the `RESTSerializer` by implementing the `normalize` method and individual normalizations under @@ -263,7 +260,6 @@ var RESTSerializer = JSONSerializer.extend({ */ extractSingle: function(store, primaryTypeClass, rawPayload, recordId) { var payload = this.normalizePayload(rawPayload); - var primaryTypeClassName = primaryTypeClass.modelName; var primaryRecord; for (var prop in payload) { @@ -273,8 +269,8 @@ var RESTSerializer = JSONSerializer.extend({ Ember.warn(this.warnMessageNoModelForKey(prop, modelName), false); continue; } - var typeClass = store.modelFor(modelName); - var isPrimary = typeClass.modelName === primaryTypeClassName; + + var isPrimary = this.isPrimaryType(store, modelName, primaryTypeClass); var value = payload[prop]; if (value === null) { @@ -287,13 +283,10 @@ var RESTSerializer = JSONSerializer.extend({ continue; } - /*jshint loopfunc:true*/ - forEach.call(value, function(hash) { - var typeName = this.modelNameFromPayloadKey(prop); - var typeSerializer = store.serializerFor(typeName); - - hash = typeSerializer.normalize(typeClass, hash, prop); + var normalizedArray = this.normalizeArray(store, modelName, value, prop); + /*jshint loopfunc:true*/ + forEach.call(normalizedArray, function(hash) { var isFirstCreatedRecord = isPrimary && !recordId && !primaryRecord; var isUpdatedRecord = isPrimary && coerceId(hash.id) === recordId; @@ -416,7 +409,6 @@ var RESTSerializer = JSONSerializer.extend({ */ extractArray: function(store, primaryTypeClass, rawPayload) { var payload = this.normalizePayload(rawPayload); - var primaryTypeClassName = primaryTypeClass.modelName; var primaryArray; for (var prop in payload) { @@ -433,14 +425,9 @@ var RESTSerializer = JSONSerializer.extend({ Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false); continue; } - var type = store.modelFor(typeName); - var typeSerializer = store.serializerFor(typeName); - var isPrimary = (!forcedSecondary && (type.modelName === primaryTypeClassName)); - /*jshint loopfunc:true*/ - var normalizedArray = map.call(payload[prop], function(hash) { - return typeSerializer.normalize(type, hash, prop); - }, this); + var normalizedArray = this.normalizeArray(store, typeName, payload[prop], prop); + var isPrimary = (!forcedSecondary && this.isPrimaryType(store, typeName, primaryTypeClass)); if (isPrimary) { primaryArray = normalizedArray; @@ -452,6 +439,21 @@ var RESTSerializer = JSONSerializer.extend({ return primaryArray; }, + normalizeArray: function(store, typeName, arrayHash, prop) { + var typeClass = store.modelFor(typeName); + var typeSerializer = store.serializerFor(typeName); + + /*jshint loopfunc:true*/ + return map.call(arrayHash, function(hash) { + return typeSerializer.normalize(typeClass, hash, prop); + }, this); + }, + + isPrimaryType: function(store, typeName, primaryTypeClass) { + var typeClass = store.modelFor(typeName); + return typeClass.modelName === primaryTypeClass.modelName; + }, + /** This method allows you to push a payload containing top-level collections of records organized per type. @@ -790,7 +792,7 @@ var RESTSerializer = JSONSerializer.extend({ }, /** - Deprecated. Use payloadKeyFromModelName instead + Deprecated. Use modelNameFromPayloadKey instead @method typeForRoot @param {String} modelName diff --git a/packages/ember-data/lib/system/coerce-id.js b/packages/ember-data/lib/system/coerce-id.js new file mode 100644 index 00000000000..62acf96bb14 --- /dev/null +++ b/packages/ember-data/lib/system/coerce-id.js @@ -0,0 +1,9 @@ +// Used by the store to normalize IDs entering the store. Despite the fact +// that developers may provide IDs as numbers (e.g., `store.find(Person, 1)`), +// it is important that internally we use strings, since IDs may be serialized +// and lose type information. For example, Ember's router may put a record's +// ID into the URL, and if we later try to deserialize that URL and find the +// corresponding record, we will not know if it is a string or a number. +export default function coerceId(id) { + return id == null ? null : id+''; +} diff --git a/packages/ember-data/lib/system/many-array.js b/packages/ember-data/lib/system/many-array.js index e4b3bbf15cc..9ac12443f91 100644 --- a/packages/ember-data/lib/system/many-array.js +++ b/packages/ember-data/lib/system/many-array.js @@ -6,6 +6,7 @@ import { PromiseArray } from "ember-data/system/promise-proxies"; var get = Ember.get; var set = Ember.set; var filter = Ember.ArrayPolyfills.filter; +var map = Ember.EnumerableUtils.map; /** A `ManyArray` is a `MutableArray` that represents the contents of a has-many @@ -57,19 +58,23 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { length: 0, objectAt: function(index) { - return this.currentState[index]; + //Ember observers such as 'firstObject', 'lastObject' might do out of bounds accesses + if (!this.currentState[index]) { + return undefined; + } + return this.currentState[index].getRecord(); }, flushCanonical: function() { //TODO make this smarter, currently its plenty stupid - var toSet = filter.call(this.canonicalState, function(record) { - return !record.get('isDeleted'); + var toSet = filter.call(this.canonicalState, function(internalModel) { + return !internalModel.isDeleted(); }); //a hack for not removing new records //TODO remove once we have proper diffing - var newRecords = this.currentState.filter(function(record) { - return record.get('isNew'); + var newRecords = this.currentState.filter(function(internalModel) { + return internalModel.isNew(); }); toSet = toSet.concat(newRecords); var oldLength = this.length; @@ -143,7 +148,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { this.get('relationship').removeRecords(records); } if (objects) { - this.get('relationship').addRecords(objects, idx); + this.get('relationship').addRecords(map(objects, function(obj) { return obj._internalModel; }), idx); } }, /** diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 505d4bd38bd..a92615da32f 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -220,7 +220,7 @@ function getDefaultValue(record, options, key) { function hasValue(record, key) { return key in record._attributes || key in record._inFlightAttributes || - record._data.hasOwnProperty(key); + key in record._data; } function getValue(record, key) { @@ -300,25 +300,27 @@ export default function attr(type, options) { return computedPolyfill({ get: function(key) { - if (hasValue(this, key)) { - return getValue(this, key); + var internalModel = this._internalModel; + if (hasValue(internalModel, key)) { + return getValue(internalModel, key); } else { return getDefaultValue(this, options, key); } }, set: function(key, value) { Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.constructor.toString(), key !== 'id'); - var oldValue = getValue(this, key); + var internalModel = this._internalModel; + var oldValue = getValue(internalModel, key); if (value !== oldValue) { // Add the new value to the changed attributes hash; it will get deleted by // the 'didSetProperty' handler if it is no different from the original value - this._attributes[key] = value; + internalModel._attributes[key] = value; - this.send('didSetProperty', { + this._internalModel.send('didSetProperty', { name: key, oldValue: oldValue, - originalValue: this._data[key], + originalValue: internalModel._data[key], value: value }); } diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js new file mode 100644 index 00000000000..8305d3da021 --- /dev/null +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -0,0 +1,700 @@ +import merge from "ember-data/system/merge"; +import RootState from "ember-data/system/model/states"; +import createRelationshipFor from "ember-data/system/relationships/state/create"; +import Snapshot from "ember-data/system/snapshot"; +import Errors from "ember-data/system/model/errors"; + +var Promise = Ember.RSVP.Promise; +var get = Ember.get; +var set = Ember.set; +var forEach = Ember.ArrayPolyfills.forEach; +var map = Ember.ArrayPolyfills.map; + +var _extractPivotNameCache = Ember.create(null); +var _splitOnDotCache = Ember.create(null); + +function splitOnDot(name) { + return _splitOnDotCache[name] || ( + _splitOnDotCache[name] = name.split('.') + ); +} + +function extractPivotName(name) { + return _extractPivotNameCache[name] || ( + _extractPivotNameCache[name] = splitOnDot(name)[0] + ); +} + +function retrieveFromCurrentState(key) { + return function() { + return get(this.currentState, key); + }; +} + +/** + `InternalModel` is the Model class that we use internally inside Ember Data to represent models. + Internal ED methods should only deal with `InternalModel` objects. It is a fast, plain Javascript class. + + We expose `DS.Model` to application code, by materializing a `DS.Model` from `InternalModel` lazily, as + a performance optimization. + + `InternalModel` should never be exposed to application code. At the boundaries of the system, in places + like `find`, `push`, etc. we convert between Models and InternalModels. + + We need to make sure that the properties from `InternalModel` are correctly exposed/proxied on `Model` + if they are needed. + + @class InternalModel +*/ + +var InternalModel = function InternalModel(type, id, store, container, data) { + this.type = type; + this.id = id; + this.store = store; + this.container = container; + this._data = data || Ember.create(null); + this.modelName = type.modelName; + this.errors = null; + this.dataHasInitialized = false; + //Look into making this lazy + this._deferredTriggers = []; + this._attributes = Ember.create(null); + this._inFlightAttributes = Ember.create(null); + this._relationships = Ember.create(null); + this.currentState = RootState.empty; + this.isReloading = false; + /* + implicit relationships are relationship which have not been declared but the inverse side exists on + another record somewhere + For example if there was + ``` + App.Comment = DS.Model.extend({ + name: DS.attr() + }) + ``` + but there is also + ``` + App.Post = DS.Model.extend({ + name: DS.attr(), + comments: DS.hasMany('comment') + }) + ``` + + would have a implicit post relationship in order to be do things like remove ourselves from the post + when we are deleted + */ + this._implicitRelationships = Ember.create(null); + var model = this; + //TODO Move into a getter for better perf + this.eachRelationship(function(key, descriptor) { + model._relationships[key] = createRelationshipFor(model, descriptor, model.store); + }); +}; + +InternalModel.prototype = { + isEmpty: retrieveFromCurrentState('isEmpty'), + isLoading: retrieveFromCurrentState('isLoading'), + isLoaded: retrieveFromCurrentState('isLoaded'), + isDirty: retrieveFromCurrentState('isDirty'), + isSaving: retrieveFromCurrentState('isSaving'), + isDeleted: retrieveFromCurrentState('isDeleted'), + isNew: retrieveFromCurrentState('isNew'), + isValid: retrieveFromCurrentState('isValid'), + dirtyType: retrieveFromCurrentState('dirtyType'), + + constructor: InternalModel, + materializeRecord: function() { + Ember.assert("Materialized " + this.modelName + " record with id:" + this.id + "more than once", this.record === null || this.record === undefined); + // lookupFactory should really return an object that creates + // instances with the injections applied + this.record = this.type._create({ + id: this.id, + store: this.store, + container: this.container + }); + this.record._internalModel = this; + this._triggerDeferredTriggers(); + }, + + recordObjectWillDestroy: function() { + this.record = null; + }, + + deleteRecord: function() { + this.send('deleteRecord'); + }, + + save: function() { + var promiseLabel = "DS: Model#save " + this; + var resolver = Ember.RSVP.defer(promiseLabel); + + this.store.scheduleSave(this, resolver); + return resolver.promise; + }, + + startedReloading: function() { + this.isReloading = true; + if (this.record) { + set(this.record, 'isReloading', true); + } + }, + + finishedReloading: function() { + this.isReloading = false; + if (this.record) { + set(this.record, 'isReloading', false); + } + }, + + reload: function() { + this.startedReloading(); + var record = this; + var promiseLabel = "DS: Model#reload of " + this; + return new Promise(function(resolve) { + record.send('reloadRecord', resolve); + }, promiseLabel).then(function() { + record.didCleanError(); + return record; + }, function(reason) { + record.didError(); + throw reason; + }, "DS: Model#reload complete, update flags").finally(function () { + record.finishedReloading(); + record.updateRecordArrays(); + }); + }, + + getRecord: function() { + if (!this.record) { + this.materializeRecord(); + } + return this.record; + }, + + unloadRecord: function() { + this.send('unloadRecord'); + }, + + eachRelationship: function(callback, binding) { + return this.type.eachRelationship(callback, binding); + }, + + eachAttribute: function(callback, binding) { + return this.type.eachAttribute(callback, binding); + }, + + inverseFor: function(key) { + return this.type.inverseFor(key); + }, + + setupData: function(data) { + var changedKeys = mergeAndReturnChangedKeys(this._data, data); + this.pushedData(); + if (this.record) { + this.record._notifyProperties(changedKeys); + } + this.didInitalizeData(); + }, + + becameReady: function() { + Ember.run.schedule('actions', this.store.recordArrayManager, this.store.recordArrayManager.recordWasLoaded, this); + }, + + didInitalizeData: function() { + if (!this.dataHasInitialized) { + this.becameReady(); + this.dataHasInitialized = true; + } + }, + + destroy: function() { + if (this.record) { + return this.record.destroy(); + } + }, + + /** + @method createSnapshot + @private + */ + createSnapshot: function() { + return new Snapshot(this); + }, + + /** + @method loadingData + @private + @param {Promise} promise + */ + loadingData: function(promise) { + this.send('loadingData', promise); + }, + + /** + @method loadedData + @private + */ + loadedData: function() { + this.send('loadedData'); + this.didInitalizeData(); + }, + + /** + @method notFound + @private + */ + notFound: function() { + this.send('notFound'); + }, + + /** + @method pushedData + @private + */ + pushedData: function() { + this.send('pushedData'); + }, + + flushChangedAttributes: function() { + this._inFlightAttributes = this._attributes; + this._attributes = Ember.create(null); + }, + + /** + @method adapterWillCommit + @private + */ + adapterWillCommit: function() { + this.send('willCommit'); + }, + + /** + @method adapterDidDirty + @private + */ + adapterDidDirty: function() { + this.send('becomeDirty'); + this.updateRecordArraysLater(); + }, + + /** + @method send + @private + @param {String} name + @param {Object} context + */ + send: function(name, context) { + var currentState = get(this, 'currentState'); + + if (!currentState[name]) { + this._unhandledEvent(currentState, name, context); + } + + return currentState[name](this, context); + }, + + notifyHasManyAdded: function(key, record, idx) { + if (this.record) { + this.record.notifyHasManyAdded(key, record, idx); + } + }, + + notifyHasManyRemoved: function(key, record, idx) { + if (this.record) { + this.record.notifyHasManyRemoved(key, record, idx); + } + }, + + notifyBelongsToChanged: function(key, record) { + if (this.record) { + this.record.notifyBelongsToChanged(key, record); + } + }, + + notifyPropertyChange: function(key) { + if (this.record) { + this.record.notifyPropertyChange(key); + } + }, + + rollback: function() { + var dirtyKeys = Ember.keys(this._attributes); + + this._attributes = Ember.create(null); + + if (get(this, 'isError')) { + this._inFlightAttributes = Ember.create(null); + this.didCleanError(); + } + + //Eventually rollback will always work for relationships + //For now we support it only out of deleted state, because we + //have an explicit way of knowing when the server acked the relationship change + if (this.isDeleted()) { + //TODO: Should probably move this to the state machine somehow + this.becameReady(); + this.reconnectRelationships(); + } + + if (this.isNew()) { + this.clearRelationships(); + } + + if (this.isValid()) { + this._inFlightAttributes = Ember.create(null); + } + + this.send('rolledBack'); + + this.record._notifyProperties(dirtyKeys); + + }, + /** + @method transitionTo + @private + @param {String} name + */ + transitionTo: function(name) { + // POSSIBLE TODO: Remove this code and replace with + // always having direct reference to state objects + + var pivotName = extractPivotName(name); + var currentState = get(this, 'currentState'); + var state = currentState; + + do { + if (state.exit) { state.exit(this); } + state = state.parentState; + } while (!state.hasOwnProperty(pivotName)); + + var path = splitOnDot(name); + var setups = []; + var enters = []; + var i, l; + + for (i=0, l=path.length; i { + recordErrors.add(key, errors[key]); + }); + this._saveWasRejected(); + }, + + /** + @method adapterDidError + @private + */ + adapterDidError: function() { + this.send('becameError'); + this.didError(); + this._saveWasRejected(); + }, + + _saveWasRejected: function() { + var keys = Ember.keys(this._inFlightAttributes); + for (var i=0; i < keys.length; i++) { + if (this._attributes[keys[i]] === undefined) { + this._attributes[keys[i]] = this._inFlightAttributes[keys[i]]; + } + } + this._inFlightAttributes = Ember.create(null); + }, + + toString: function() { + if (this.record) { + return this.record.toString(); + } else { + return `<${this.modelName}:${this.id}>`; + } + } +}; + +// Like Ember.merge, but instead returns a list of keys +// for values that fail a strict equality check +// instead of the original object. +function mergeAndReturnChangedKeys(original, updates) { + var changedKeys = []; + + if (!updates || typeof updates !== 'object') { + return changedKeys; + } + + var keys = Ember.keys(updates); + var length = keys.length; + var i, val, key; + + for (i = 0; i < length; i++) { + key = keys[i]; + val = updates[key]; + + if (original[key] !== val) { + changedKeys.push(key); + } + + original[key] = val; + } + return changedKeys; +} + +export default InternalModel; diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index fbdbe98011f..60380426283 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1,74 +1,27 @@ -import RootState from "ember-data/system/model/states"; -import Errors from "ember-data/system/model/errors"; import { PromiseObject } from "ember-data/system/promise-proxies"; -import merge from "ember-data/system/merge"; import JSONSerializer from "ember-data/serializers/json-serializer"; -import createRelationshipFor from "ember-data/system/relationships/state/create"; -import Snapshot from "ember-data/system/snapshot"; /** @module ember-data */ var get = Ember.get; -var set = Ember.set; -var Promise = Ember.RSVP.Promise; -var forEach = Ember.ArrayPolyfills.forEach; -var map = Ember.ArrayPolyfills.map; var intersection = Ember.EnumerableUtils.intersection; var RESERVED_MODEL_PROPS = [ 'currentState', 'data', 'store' ]; var retrieveFromCurrentState = Ember.computed('currentState', function(key) { - return get(get(this, 'currentState'), key); + return get(this._internalModel.currentState, key); }).readOnly(); -var _extractPivotNameCache = Ember.create(null); -var _splitOnDotCache = Ember.create(null); - -function splitOnDot(name) { - return _splitOnDotCache[name] || ( - (_splitOnDotCache[name] = name.split('.')) - ); -} - -function extractPivotName(name) { - return _extractPivotNameCache[name] || ( - (_extractPivotNameCache[name] = splitOnDot(name)[0]) - ); -} - -// Like Ember.merge, but instead returns a list of keys -// for values that fail a strict equality check -// instead of the original object. -function mergeAndReturnChangedKeys(original, updates) { - var changedKeys = []; - - if (!updates || typeof updates !== 'object') { - return changedKeys; - } - - var keys = Ember.keys(updates); - var length = keys.length; - var i, val, key; - - for (i = 0; i < length; i++) { - key = keys[i]; - val = updates[key]; - - if (original[key] !== val) { - changedKeys.push(key); - } - - original[key] = val; - } - return changedKeys; -} - /** The model class that all Ember Data records descend from. + This is the public API of Ember Data models. If you are using Ember Data + in your application, this is the class you should use. + If you are working on Ember Data internals, you most likely want to be dealing + with `InternalModel` @class Model @namespace DS @@ -288,6 +241,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @readOnly */ isError: false, + /** If `true` the store is attempting to reload the record form the adapter. @@ -305,17 +259,6 @@ var Model = Ember.Object.extend(Ember.Evented, { */ isReloading: false, - /** - The `clientId` property is a transient numerical identifier - generated at runtime by the data store. It is important - primarily because newly created objects may not yet have an - externally generated id. - - @property clientId - @private - @type {Number|String} - */ - clientId: null, /** All ember models have an id property. This is an identifier managed by an external source. These are always coerced to be @@ -342,7 +285,6 @@ var Model = Ember.Object.extend(Ember.Evented, { @private @type {Object} */ - currentState: RootState.empty, /** When the record is in the `invalid` state this object will contain @@ -396,15 +338,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @type {DS.Errors} */ errors: Ember.computed(function() { - var errors = Errors.create(); - - errors.registerHandlers(this, function() { - this.send('becameInvalid'); - }, function() { - this.send('becameValid'); - }); - - return errors; + return this._internalModel.getErrors(); }).readOnly(), /** @@ -442,7 +376,7 @@ var Model = Ember.Object.extend(Ember.Evented, { toJSON: function(options) { // container is for lazy transform lookups var serializer = JSONSerializer.create({ container: this.container }); - var snapshot = this._createSnapshot(); + var snapshot = this._internalModel.createSnapshot(); return serializer.serialize(snapshot, options); }, @@ -453,9 +387,8 @@ var Model = Ember.Object.extend(Ember.Evented, { @event ready */ - ready: function() { - this.store.recordArrayManager.recordWasLoaded(this); - }, + ready: Ember.K, + /** Fired when the record is loaded from the server. @@ -510,54 +443,9 @@ var Model = Ember.Object.extend(Ember.Evented, { @private @type {Object} */ - data: Ember.computed(function() { - this._data = this._data || {}; - return this._data; - }).readOnly(), - - _data: null, - - init: function() { - this._super.apply(this, arguments); - this._setup(); - }, - - _setup: function() { - this._changesToSync = {}; - this._deferredTriggers = []; - this._data = {}; - this._attributes = Ember.create(null); - this._inFlightAttributes = Ember.create(null); - this._relationships = {}; - /* - implicit relationships are relationship which have not been declared but the inverse side exists on - another record somewhere - For example if there was - ``` - App.Comment = DS.Model.extend({ - name: DS.attr() - }) - ``` - but there is also - ``` - App.Post = DS.Model.extend({ - name: DS.attr(), - comments: DS.hasMany('comment') - }) - ``` - - would have a implicit post relationship in order to be do things like remove ourselves from the post - when we are deleted - */ - this._implicitRelationships = Ember.create(null); - var model = this; - //TODO Move into a getter for better perf - this.constructor.eachRelationship(function(key, descriptor) { - model._relationships[key] = createRelationshipFor(model, descriptor, model.store); - }); - - }, + data: Ember.computed.readOnly('_internalModel._data'), + //TODO Do we want to deprecate these? /** @method send @private @@ -565,13 +453,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @param {Object} context */ send: function(name, context) { - var currentState = get(this, 'currentState'); - - if (!currentState[name]) { - this._unhandledEvent(currentState, name, context); - } - - return currentState[name](this, context); + return this._internalModel.send(name, context); }, /** @@ -580,92 +462,9 @@ var Model = Ember.Object.extend(Ember.Evented, { @param {String} name */ transitionTo: function(name) { - // POSSIBLE TODO: Remove this code and replace with - // always having direct references to state objects - - var pivotName = extractPivotName(name); - var currentState = get(this, 'currentState'); - var state = currentState; - - do { - if (state.exit) { state.exit(this); } - state = state.parentState; - } while (!state.hasOwnProperty(pivotName)); - - var path = splitOnDot(name); - var setups = []; - var enters = []; - var i, l; - - for (i=0, l=path.length; i 0; - if (!stillDirty) { record.send('rolledBack'); } + if (!stillDirty) { internalModel.send('rolledBack'); } }, pushedData: Ember.K, becomeDirty: Ember.K, - willCommit: function(record) { - record.transitionTo('inFlight'); + willCommit: function(internalModel) { + internalModel.transitionTo('inFlight'); }, - reloadRecord: function(record, resolve) { - resolve(get(record, 'store').reloadRecord(record)); + reloadRecord: function(internalModel, resolve) { + resolve(internalModel.store.reloadRecord(internalModel)); }, - rolledBack: function(record) { - record.transitionTo('loaded.saved'); + rolledBack: function(internalModel) { + internalModel.transitionTo('loaded.saved'); }, - becameInvalid: function(record) { - record.transitionTo('invalid'); + becameInvalid: function(internalModel) { + internalModel.transitionTo('invalid'); }, - rollback: function(record) { - record.rollback(); - record.triggerLater('ready'); + rollback: function(internalModel) { + internalModel.rollback(); + internalModel.triggerLater('ready'); } }, @@ -291,28 +290,26 @@ var DirtyState = { becomeDirty: Ember.K, pushedData: Ember.K, - unloadRecord: function(record) { - Ember.assert("You can only unload a record which is not inFlight. `" + Ember.inspect(record) + " `", false); - }, + unloadRecord: assertAgainstUnloadRecord, // TODO: More robust semantics around save-while-in-flight willCommit: Ember.K, - didCommit: function(record) { + didCommit: function(internalModel) { var dirtyType = get(this, 'dirtyType'); - record.transitionTo('saved'); - record.send('invokeLifecycleCallbacks', dirtyType); + internalModel.transitionTo('saved'); + internalModel.send('invokeLifecycleCallbacks', dirtyType); }, - becameInvalid: function(record) { - record.transitionTo('invalid'); - record.send('invokeLifecycleCallbacks'); + becameInvalid: function(internalModel) { + internalModel.transitionTo('invalid'); + internalModel.send('invokeLifecycleCallbacks'); }, - becameError: function(record) { - record.transitionTo('uncommitted'); - record.triggerLater('becameError', record); + becameError: function(internalModel) { + internalModel.transitionTo('uncommitted'); + internalModel.triggerLater('becameError', internalModel); } }, @@ -323,39 +320,39 @@ var DirtyState = { isValid: false, // EVENTS - deleteRecord: function(record) { - record.transitionTo('deleted.uncommitted'); - record.disconnectRelationships(); + deleteRecord: function(internalModel) { + internalModel.transitionTo('deleted.uncommitted'); + internalModel.disconnectRelationships(); }, - didSetProperty: function(record, context) { - get(record, 'errors').remove(context.name); + didSetProperty: function(internalModel, context) { + internalModel.getErrors().remove(context.name); - didSetProperty(record, context); + didSetProperty(internalModel, context); }, becomeDirty: Ember.K, - willCommit: function(record) { - get(record, 'errors').clear(); - record.transitionTo('inFlight'); + willCommit: function(internalModel) { + internalModel.getErrors().clear(); + internalModel.transitionTo('inFlight'); }, - rolledBack: function(record) { - get(record, 'errors').clear(); - record.triggerLater('ready'); + rolledBack: function(internalModel) { + internalModel.getErrors().clear(); + internalModel.triggerLater('ready'); }, - becameValid: function(record) { - record.transitionTo('uncommitted'); + becameValid: function(internalModel) { + internalModel.transitionTo('uncommitted'); }, - invokeLifecycleCallbacks: function(record) { - record.triggerLater('becameInvalid', record); + invokeLifecycleCallbacks: function(internalModel) { + internalModel.triggerLater('becameInvalid', internalModel); }, - exit: function(record) { - record._inFlightAttributes = {}; + exit: function(internalModel) { + internalModel._inFlightAttributes = Ember.create(null); } } }; @@ -399,41 +396,44 @@ var createdState = dirtyState({ isNew: true }); -createdState.uncommitted.rolledBack = function(record) { - record.transitionTo('deleted.saved'); +createdState.invalid.rolledBack = function(internalModel) { + internalModel.transitionTo('deleted.saved'); +}; +createdState.uncommitted.rolledBack = function(internalModel) { + internalModel.transitionTo('deleted.saved'); }; var updatedState = dirtyState({ dirtyType: 'updated' }); -createdState.uncommitted.deleteRecord = function(record) { - record.disconnectRelationships(); - record.transitionTo('deleted.saved'); - record.send('invokeLifecycleCallbacks'); +createdState.uncommitted.deleteRecord = function(internalModel) { + internalModel.disconnectRelationships(); + internalModel.transitionTo('deleted.saved'); + internalModel.send('invokeLifecycleCallbacks'); }; -createdState.uncommitted.rollback = function(record) { +createdState.uncommitted.rollback = function(internalModel) { DirtyState.uncommitted.rollback.apply(this, arguments); - record.transitionTo('deleted.saved'); + internalModel.transitionTo('deleted.saved'); }; -createdState.uncommitted.pushedData = function(record) { - record.transitionTo('loaded.updated.uncommitted'); - record.triggerLater('didLoad'); +createdState.uncommitted.pushedData = function(internalModel) { + internalModel.transitionTo('loaded.updated.uncommitted'); + internalModel.triggerLater('didLoad'); }; createdState.uncommitted.propertyWasReset = Ember.K; -function assertAgainstUnloadRecord(record) { - Ember.assert("You can only unload a record which is not inFlight. `" + Ember.inspect(record) + "`", false); +function assertAgainstUnloadRecord(internalModel) { + Ember.assert("You can only unload a record which is not inFlight. `" + internalModel + "`", false); } updatedState.inFlight.unloadRecord = assertAgainstUnloadRecord; -updatedState.uncommitted.deleteRecord = function(record) { - record.transitionTo('deleted.uncommitted'); - record.disconnectRelationships(); +updatedState.uncommitted.deleteRecord = function(internalModel) { + internalModel.transitionTo('deleted.uncommitted'); + internalModel.disconnectRelationships(); }; var RootState = { @@ -454,11 +454,11 @@ var RootState = { // in-flight state, rolling back the record doesn't move // you out of the in-flight state. rolledBack: Ember.K, - unloadRecord: function(record) { + unloadRecord: function(internalModel) { // clear relationships before moving to deleted state // otherwise it fails - record.clearRelationships(); - record.transitionTo('deleted.saved'); + internalModel.clearRelationships(); + internalModel.transitionTo('deleted.saved'); }, @@ -475,20 +475,20 @@ var RootState = { isEmpty: true, // EVENTS - loadingData: function(record, promise) { - record._loadingPromise = promise; - record.transitionTo('loading'); + loadingData: function(internalModel, promise) { + internalModel._loadingPromise = promise; + internalModel.transitionTo('loading'); }, - loadedData: function(record) { - record.transitionTo('loaded.created.uncommitted'); - record.triggerLater('ready'); + loadedData: function(internalModel) { + internalModel.transitionTo('loaded.created.uncommitted'); + internalModel.triggerLater('ready'); }, - pushedData: function(record) { - record.transitionTo('loaded.saved'); - record.triggerLater('didLoad'); - record.triggerLater('ready'); + pushedData: function(internalModel) { + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('didLoad'); + internalModel.triggerLater('ready'); } }, @@ -502,24 +502,25 @@ var RootState = { // FLAGS isLoading: true, - exit: function(record) { - record._loadingPromise = null; + exit: function(internalModel) { + internalModel._loadingPromise = null; }, // EVENTS - pushedData: function(record) { - record.transitionTo('loaded.saved'); - record.triggerLater('didLoad'); - record.triggerLater('ready'); - set(record, 'isError', false); + pushedData: function(internalModel) { + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('didLoad'); + internalModel.triggerLater('ready'); + //TODO this seems out of place here + internalModel.didCleanError(); }, - becameError: function(record) { - record.triggerLater('becameError', record); + becameError: function(internalModel) { + internalModel.triggerLater('becameError', internalModel); }, - notFound: function(record) { - record.transitionTo('empty'); + notFound: function(internalModel) { + internalModel.transitionTo('empty'); } }, @@ -541,12 +542,12 @@ var RootState = { // If there are no local changes to a record, it remains // in the `saved` state. saved: { - setup: function(record) { - var attrs = record._attributes; + setup: function(internalModel) { + var attrs = internalModel._attributes; var isDirty = Ember.keys(attrs).length > 0; if (isDirty) { - record.adapterDidDirty(); + internalModel.adapterDidDirty(); } }, @@ -555,32 +556,32 @@ var RootState = { pushedData: Ember.K, - becomeDirty: function(record) { - record.transitionTo('updated.uncommitted'); + becomeDirty: function(internalModel) { + internalModel.transitionTo('updated.uncommitted'); }, - willCommit: function(record) { - record.transitionTo('updated.inFlight'); + willCommit: function(internalModel) { + internalModel.transitionTo('updated.inFlight'); }, - reloadRecord: function(record, resolve) { - resolve(get(record, 'store').reloadRecord(record)); + reloadRecord: function(internalModel, resolve) { + resolve(internalModel.store.reloadRecord(internalModel)); }, - deleteRecord: function(record) { - record.transitionTo('deleted.uncommitted'); - record.disconnectRelationships(); + deleteRecord: function(internalModel) { + internalModel.transitionTo('deleted.uncommitted'); + internalModel.disconnectRelationships(); }, - unloadRecord: function(record) { + unloadRecord: function(internalModel) { // clear relationships before moving to deleted state // otherwise it fails - record.clearRelationships(); - record.transitionTo('deleted.saved'); + internalModel.clearRelationships(); + internalModel.transitionTo('deleted.saved'); }, - didCommit: function(record) { - record.send('invokeLifecycleCallbacks', get(record, 'lastDirtyType')); + didCommit: function(internalModel) { + internalModel.send('invokeLifecycleCallbacks', get(internalModel, 'lastDirtyType')); }, // loaded.saved.notFound would be triggered by a failed @@ -611,8 +612,8 @@ var RootState = { isDirty: true, // TRANSITIONS - setup: function(record) { - record.updateRecordArrays(); + setup: function(internalModel) { + internalModel.updateRecordArrays(); }, // SUBSTATES @@ -624,22 +625,22 @@ var RootState = { // EVENTS - willCommit: function(record) { - record.transitionTo('inFlight'); + willCommit: function(internalModel) { + internalModel.transitionTo('inFlight'); }, - rollback: function(record) { - record.rollback(); - record.triggerLater('ready'); + rollback: function(internalModel) { + internalModel.rollback(); + internalModel.triggerLater('ready'); }, pushedData: Ember.K, becomeDirty: Ember.K, deleteRecord: Ember.K, - rolledBack: function(record) { - record.transitionTo('loaded.saved'); - record.triggerLater('ready'); + rolledBack: function(internalModel) { + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('ready'); } }, @@ -657,20 +658,20 @@ var RootState = { // TODO: More robust semantics around save-while-in-flight willCommit: Ember.K, - didCommit: function(record) { - record.transitionTo('saved'); + didCommit: function(internalModel) { + internalModel.transitionTo('saved'); - record.send('invokeLifecycleCallbacks'); + internalModel.send('invokeLifecycleCallbacks'); }, - becameError: function(record) { - record.transitionTo('uncommitted'); - record.triggerLater('becameError', record); + becameError: function(internalModel) { + internalModel.transitionTo('uncommitted'); + internalModel.triggerLater('becameError', internalModel); }, - becameInvalid: function(record) { - record.transitionTo('invalid'); - record.triggerLater('becameInvalid', record); + becameInvalid: function(internalModel) { + internalModel.transitionTo('invalid'); + internalModel.triggerLater('becameInvalid', internalModel); } }, @@ -681,14 +682,14 @@ var RootState = { // FLAGS isDirty: false, - setup: function(record) { - var store = get(record, 'store'); - store._dematerializeRecord(record); + setup: function(internalModel) { + var store = internalModel.store; + store._dematerializeRecord(internalModel); }, - invokeLifecycleCallbacks: function(record) { - record.triggerLater('didDelete', record); - record.triggerLater('didCommit', record); + invokeLifecycleCallbacks: function(internalModel) { + internalModel.triggerLater('didDelete', internalModel); + internalModel.triggerLater('didCommit', internalModel); }, willCommit: Ember.K, @@ -699,10 +700,10 @@ var RootState = { invalid: { isValid: false, - didSetProperty: function(record, context) { - get(record, 'errors').remove(context.name); + didSetProperty: function(internalModel, context) { + internalModel.getErrors().remove(context.name); - didSetProperty(record, context); + didSetProperty(internalModel, context); }, deleteRecord: Ember.K, @@ -710,27 +711,27 @@ var RootState = { willCommit: Ember.K, - rolledBack: function(record) { - get(record, 'errors').clear(); - record.transitionTo('loaded.saved'); - record.triggerLater('ready'); + rolledBack: function(internalModel) { + internalModel.getErrors().clear(); + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('ready'); }, - becameValid: function(record) { - record.transitionTo('uncommitted'); + becameValid: function(internalModel) { + internalModel.transitionTo('uncommitted'); } } }, - invokeLifecycleCallbacks: function(record, dirtyType) { + invokeLifecycleCallbacks: function(internalModel, dirtyType) { if (dirtyType === 'created') { - record.triggerLater('didCreate', record); + internalModel.triggerLater('didCreate', internalModel); } else { - record.triggerLater('didUpdate', record); + internalModel.triggerLater('didUpdate', internalModel); } - record.triggerLater('didCommit', record); + internalModel.triggerLater('didCommit', internalModel); } }; diff --git a/packages/ember-data/lib/system/record-array-manager.js b/packages/ember-data/lib/system/record-array-manager.js index 5fb9cb88303..609e90c7275 100644 --- a/packages/ember-data/lib/system/record-array-manager.js +++ b/packages/ember-data/lib/system/record-array-manager.js @@ -54,7 +54,7 @@ export default Ember.Object.extend({ */ updateRecordArrays: function() { forEach(this.changedRecords, function(record) { - if (get(record, 'isDeleted')) { + if (record.isDeleted()) { this._recordWasDeleted(record); } else { this._recordWasChanged(record); @@ -79,7 +79,7 @@ export default Ember.Object.extend({ //Don't need to update non filtered arrays on simple changes _recordWasChanged: function (record) { - var typeClass = record.constructor; + var typeClass = record.type; var recordArrays = this.filteredRecordArrays.get(typeClass); var filter; @@ -93,7 +93,7 @@ export default Ember.Object.extend({ //Need to update live arrays on loading recordWasLoaded: function(record) { - var typeClass = record.constructor; + var typeClass = record.type; var recordArrays = this.filteredRecordArrays.get(typeClass); var filter; @@ -117,14 +117,14 @@ export default Ember.Object.extend({ if (!filter) { shouldBeInArray = true; } else { - shouldBeInArray = filter(record); + shouldBeInArray = filter(record.getRecord()); } var recordArrays = this.recordArraysForRecord(record); if (shouldBeInArray) { if (!recordArrays.has(array)) { - array._pushRecord(record); + array.addRecord(record); recordArrays.add(array); } } else if (!shouldBeInArray) { @@ -153,7 +153,7 @@ export default Ember.Object.extend({ for (var i = 0, l = records.length; i < l; i++) { record = records[i]; - if (!get(record, 'isDeleted') && !get(record, 'isEmpty')) { + if (!record.isDeleted() && !record.isEmpty()) { this.updateRecordArray(array, filter, modelName, record); } } diff --git a/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js b/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js index 1d7a24f00e7..65670d58b90 100644 --- a/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js +++ b/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js @@ -43,13 +43,15 @@ export default RecordArray.extend({ var records = store.pushMany(modelName, data); var meta = store.metadataFor(modelName); + //TODO Optimize + var internalModels = Ember.A(records).mapBy('_internalModel'); this.setProperties({ - content: Ember.A(records), + content: Ember.A(internalModels), isLoaded: true, meta: cloneNull(meta) }); - records.forEach(function(record) { + internalModels.forEach(function(record) { this.manager.recordArraysForRecord(record).add(this); }, this); diff --git a/packages/ember-data/lib/system/record-arrays/record-array.js b/packages/ember-data/lib/system/record-arrays/record-array.js index a1c98541f6d..180bf51ff2c 100644 --- a/packages/ember-data/lib/system/record-arrays/record-array.js +++ b/packages/ember-data/lib/system/record-arrays/record-array.js @@ -90,8 +90,8 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { */ objectAtContent: function(index) { var content = get(this, 'content'); - - return content.objectAt(index); + var internalModel = content.objectAt(index); + return internalModel && internalModel.getRecord(); }, /** @@ -135,22 +135,6 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { } }, - _pushRecord: function(record) { - get(this, 'content').pushObject(record); - }, - - /** - Adds a record to the `RecordArray`, but allows duplicates - - @deprecated - @method pushRecord - @private - @param {DS.Model} record - */ - pushRecord: function(record) { - Ember.deprecate('Usage of `recordArray.pushRecord` is deprecated, use `recordArray.addObject` instead'); - this._pushRecord(record); - }, /** Removes a record to the `RecordArray`. @@ -191,7 +175,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { _dissociateFromOwnRecords: function() { var array = this; - this.forEach(function(record) { + this.get('content').forEach(function(record) { var recordArrays = record._recordArrays; if (recordArrays) { @@ -206,10 +190,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { */ _unregisterFromManager: function() { var manager = get(this, 'manager'); - //We will stop needing this stupid if statement soon, once manyArray are refactored to not be RecordArrays - if (manager) { - manager.unregisterFilteredRecordArray(this); - } + manager.unregisterFilteredRecordArray(this); }, willDestroy: function() { diff --git a/packages/ember-data/lib/system/relationships/belongs-to.js b/packages/ember-data/lib/system/relationships/belongs-to.js index 85ec51d3837..63a0d14d786 100644 --- a/packages/ember-data/lib/system/relationships/belongs-to.js +++ b/packages/ember-data/lib/system/relationships/belongs-to.js @@ -89,19 +89,21 @@ function belongsTo(modelName, options) { return computedPolyfill({ get: function(key) { - return this._relationships[key].getRecord(); + return this._internalModel._relationships[key].getRecord(); }, set: function(key, value) { if (value === undefined) { value = null; } if (value && value.then) { - this._relationships[key].setRecordPromise(value); + this._internalModel._relationships[key].setRecordPromise(value); + } else if (value) { + this._internalModel._relationships[key].setRecord(value._internalModel); } else { - this._relationships[key].setRecord(value); + this._internalModel._relationships[key].setRecord(value); } - return this._relationships[key].getRecord(); + return this._internalModel._relationships[key].getRecord(); } }).meta(meta); } diff --git a/packages/ember-data/lib/system/relationships/has-many.js b/packages/ember-data/lib/system/relationships/has-many.js index e7baf49141c..06a5144d647 100644 --- a/packages/ember-data/lib/system/relationships/has-many.js +++ b/packages/ember-data/lib/system/relationships/has-many.js @@ -123,13 +123,14 @@ function hasMany(type, options) { return computedPolyfill({ get: function(key) { - var relationship = this._relationships[key]; + var relationship = this._internalModel._relationships[key]; return relationship.getRecords(); }, set: function(key, records) { - var relationship = this._relationships[key]; + var relationship = this._internalModel._relationships[key]; relationship.clear(); - relationship.addRecords(records); + Ember.assert("You must pass an array of records to set a hasMany relationship", Ember.isArray(records)); + relationship.addRecords(Ember.A(records).mapBy('_internalModel')); return relationship.getRecords(); } }).meta(meta); diff --git a/packages/ember-data/lib/system/relationships/state/belongs-to.js b/packages/ember-data/lib/system/relationships/state/belongs-to.js index b658ca20cdf..7409bd77925 100644 --- a/packages/ember-data/lib/system/relationships/state/belongs-to.js +++ b/packages/ember-data/lib/system/relationships/state/belongs-to.js @@ -50,7 +50,7 @@ BelongsToRelationship.prototype._super$flushCanonical = Relationship.prototype.f BelongsToRelationship.prototype.flushCanonical = function() { //temporary fix to not remove newly created records if server returned null. //TODO remove once we have proper diffing - if (this.inverseRecord && this.inverseRecord.get('isNew') && !this.canonicalState) { + if (this.inverseRecord && this.inverseRecord.isNew() && !this.canonicalState) { return; } this.inverseRecord = this.canonicalState; @@ -62,14 +62,16 @@ BelongsToRelationship.prototype._super$addRecord = Relationship.prototype.addRec BelongsToRelationship.prototype.addRecord = function(newRecord) { if (this.members.has(newRecord)) { return;} var typeClass = this.store.modelFor(this.relationshipMeta.type); - Ember.assert("You cannot add a '" + newRecord.constructor.modelName + "' record to the '" + this.record.constructor.modelName + "." + this.key +"'. " + "You can only add a '" + typeClass.modelName + "' record to this relationship.", (function () { + Ember.assert("You cannot add a '" + newRecord.type.modelName + "' record to the '" + this.record.type.modelName + "." + this.key +"'. " + "You can only add a '" + typeClass.modelName + "' record to this relationship.", (function () { if (typeClass.__isMixin) { - return typeClass.__mixin.detect(newRecord); + //TODO Need to do this in order to support mixins, should convert to public api + //once it exists in Ember + return typeClass.__mixin.detect(newRecord.type.PrototypeMixin); } if (Ember.MODEL_FACTORY_INJECTIONS) { typeClass = typeClass.superclass; } - return newRecord instanceof typeClass; + return typeClass.detect(newRecord.type); })()); if (this.inverseRecord) { @@ -104,7 +106,7 @@ BelongsToRelationship.prototype.removeCanonicalRecordFromOwn = function(record) BelongsToRelationship.prototype.findRecord = function() { if (this.inverseRecord) { - return this.store._findByRecord(this.inverseRecord); + return this.store._findByInternalModel(this.inverseRecord); } else { return Ember.RSVP.Promise.resolve(null); } @@ -138,8 +140,12 @@ BelongsToRelationship.prototype.getRecord = function() { content: this.inverseRecord }); } else { - Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.constructor.modelName + "' with id " + this.record.get('id') + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", this.inverseRecord === null || !this.inverseRecord.get('isEmpty')); - return this.inverseRecord; + if (this.inverseRecord === null) { + return null; + } + var toReturn = this.inverseRecord.getRecord(); + Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); + return toReturn; } }; diff --git a/packages/ember-data/lib/system/relationships/state/create.js b/packages/ember-data/lib/system/relationships/state/create.js index 778d5d44087..2519241ee44 100644 --- a/packages/ember-data/lib/system/relationships/state/create.js +++ b/packages/ember-data/lib/system/relationships/state/create.js @@ -3,7 +3,7 @@ import BelongsToRelationship from "ember-data/system/relationships/state/belongs var createRelationshipFor = function(record, relationshipMeta, store) { var inverseKey; - var inverse = record.constructor.inverseFor(relationshipMeta.key, store); + var inverse = record.type.inverseFor(relationshipMeta.key, store); if (inverse) { inverseKey = inverse.name; diff --git a/packages/ember-data/lib/system/relationships/state/has-many.js b/packages/ember-data/lib/system/relationships/state/has-many.js index 775f47a08a7..4e9e03f95ad 100644 --- a/packages/ember-data/lib/system/relationships/state/has-many.js +++ b/packages/ember-data/lib/system/relationships/state/has-many.js @@ -3,6 +3,8 @@ import Relationship from "ember-data/system/relationships/state/relationship"; import OrderedSet from "ember-data/system/ordered-set"; import ManyArray from "ember-data/system/many-array"; +var map = Ember.EnumerableUtils.map; + var ManyRelationship = function(store, record, inverseKey, relationshipMeta) { this._super$constructor(store, record, inverseKey, relationshipMeta); this.belongsToType = relationshipMeta.type; @@ -85,14 +87,14 @@ ManyRelationship.prototype.removeRecordFromOwn = function(record, idx) { ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) { var typeClass = this.store.modelFor(this.relationshipMeta.type); - Ember.assert("You cannot add '" + record.constructor.modelName + "' records to the " + this.record.constructor.modelName + "." + this.key + " relationship (only '" + typeClass.modelName + "' allowed)", (function () { + Ember.assert("You cannot add '" + record.type.modelName + "' records to the " + this.record.type.modelName + "." + this.key + " relationship (only '" + typeClass.modelName + "' allowed)", (function () { if (typeClass.__isMixin) { - return typeClass.__mixin.detect(record); + return typeClass.__mixin.detect(record.type.PrototypeMixin); } if (Ember.MODEL_FACTORY_INJECTIONS) { typeClass = typeClass.superclass; } - return record instanceof typeClass; + return typeClass.detect(record.type); })()); this.record.notifyHasManyAdded(this.key, record, idx); @@ -153,7 +155,8 @@ ManyRelationship.prototype.fetchLink = function() { ManyRelationship.prototype.findRecords = function() { var manyArray = this.manyArray; - return this.store.findMany(manyArray.toArray()).then(function() { + //TODO CLEANUP + return this.store.findMany(map(manyArray.toArray(), function(rec) { return rec._internalModel; })).then(function() { //Goes away after the manyArray refactor manyArray.set('isLoaded', true); return manyArray; @@ -180,7 +183,7 @@ ManyRelationship.prototype.getRecords = function() { promise: promise }); } else { - Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.constructor.modelName + "' with id " + this.record.get('id') + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); + Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); //TODO(Igor) WTF DO I DO HERE? if (!this.manyArray.get('isDestroyed')) { diff --git a/packages/ember-data/lib/system/relationships/state/relationship.js b/packages/ember-data/lib/system/relationships/state/relationship.js index 4dffdee23f1..e587ef5e380 100644 --- a/packages/ember-data/lib/system/relationships/state/relationship.js +++ b/packages/ember-data/lib/system/relationships/state/relationship.js @@ -181,7 +181,7 @@ Relationship.prototype = { //TODO remove once we have proper diffing var newRecords = []; for (var i=0; i { author: 'Tomster', title: 'Ember.js rocks' } ``` @@ -146,6 +150,31 @@ Snapshot.prototype = { return Ember.copy(this._attributes); }, + /** + Returns all changed attributes and their old and new values. + + Example + + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postModel.set('title', 'Ember.js rocks!'); + postSnapshot.changedAttributes(); // => { title: ['Ember.js rocks', 'Ember.js rocks!'] } + ``` + + @method changedAttributes + @return {Object} All changed attributes of the current snapshot + */ + changedAttributes: function() { + var prop; + var changedAttributes = Ember.create(null); + + for (prop in this._changedAttributes) { + changedAttributes[prop] = Ember.copy(this._changedAttributes[prop]); + } + + return changedAttributes; + }, + /** Returns the current value of a belongsTo relationship. @@ -194,7 +223,7 @@ Snapshot.prototype = { return this._belongsToRelationships[keyName]; } - relationship = this.record._relationships[keyName]; + relationship = this._internalModel._relationships[keyName]; if (!(relationship && relationship.relationshipMeta.kind === 'belongsTo')) { throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined."); } @@ -207,7 +236,7 @@ Snapshot.prototype = { if (id) { result = get(inverseRecord, 'id'); } else { - result = inverseRecord._createSnapshot(); + result = inverseRecord.createSnapshot(); } } else { result = null; @@ -265,7 +294,7 @@ Snapshot.prototype = { return this._hasManyRelationships[keyName]; } - relationship = this.record._relationships[keyName]; + relationship = this._internalModel._relationships[keyName]; if (!(relationship && relationship.relationshipMeta.kind === 'hasMany')) { throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined."); } @@ -277,9 +306,9 @@ Snapshot.prototype = { results = []; members.forEach(function(member) { if (ids) { - results.push(get(member, 'id')); + results.push(member.id); } else { - results.push(member._createSnapshot()); + results.push(member.createSnapshot()); } }); } @@ -350,7 +379,7 @@ Snapshot.prototype = { return this.attr(keyName); } - var relationship = this.record._relationships[keyName]; + var relationship = this._internalModel._relationships[keyName]; if (relationship && relationship.relationshipMeta.kind === 'belongsTo') { return this.belongsTo(keyName); diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 4777fc8d4f6..1f3d758e07b 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -38,8 +38,12 @@ import { _findQuery } from "ember-data/system/store/finders"; +import coerceId from "ember-data/system/coerce-id"; + import RecordArrayManager from "ember-data/system/record-array-manager"; +import InternalModel from "ember-data/system/model/internal-model"; + import Model from "ember-data/system/model"; var Backburner = Ember.Backburner || Ember.__loader.require('backburner')['default'] || Ember.__loader.require('backburner')['Backburner']; @@ -84,6 +88,20 @@ if (!Backburner.prototype.join) { } +//Get the materialized model from the internalModel/promise that returns +//an internal model and return it in a promiseObject. Useful for returning +//from find methods +function promiseRecord(internalModel, label) { + //TODO cleanup + var toReturn = internalModel; + if (!internalModel.then) { + toReturn = internalModel.getRecord(); + } else { + toReturn = internalModel.then((model) => model.getRecord()); + } + return promiseObject(toReturn, label); +} + var get = Ember.get; var set = Ember.set; var once = Ember.run.once; @@ -111,20 +129,10 @@ if (!Service) { // * +clientId+ means a transient numerical identifier generated at runtime by // the data store. It is important primarily because newly created objects may // not yet have an externally generated id. -// * +reference+ means a record reference object, which holds metadata about a +// * +internalModel+ means a record internalModel object, which holds metadata about a // record, even if it has not yet been fully materialized. // * +type+ means a subclass of DS.Model. -// Used by the store to normalize IDs entering the store. Despite the fact -// that developers may provide IDs as numbers (e.g., `store.find(Person, 1)`), -// it is important that internally we use strings, since IDs may be serialized -// and lose type information. For example, Ember's router may put a record's -// ID into the URL, and if we later try to deserialize that URL and find the -// corresponding record, we will not know if it is a string or a number. -function coerceId(id) { - return id == null ? null : id+''; -} - /** The store contains all of the data for records loaded from the server. It is also responsible for creating instances of `DS.Model` that wrap @@ -243,7 +251,7 @@ Store = Service.extend({ @param {Object} options an options hash */ serialize: function(record, options) { - var snapshot = record._createSnapshot(); + var snapshot = record._internalModel.createSnapshot(); return this.serializerFor(snapshot.modelName).serialize(snapshot, options); }, @@ -306,7 +314,7 @@ Store = Service.extend({ createRecord: function(modelName, inputProperties) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); - var properties = copy(inputProperties) || {}; + var properties = copy(inputProperties) || Ember.create(null); // If the passed properties do not include a primary key, // give the adapter an opportunity to generate one. Typically, @@ -320,17 +328,18 @@ Store = Service.extend({ // Coerce ID to a string properties.id = coerceId(properties.id); - var record = this.buildRecord(typeClass, properties.id); + var internalModel = this.buildInternalModel(typeClass, properties.id); + var record = internalModel.getRecord(); // Move the record out of its initial `empty` state into // the `loaded` state. - record.loadedData(); + internalModel.loadedData(); // Set the properties specified on the record. record.setProperties(properties); - record.eachRelationship(function(key, descriptor) { - record._relationships[key].setHasData(true); + internalModel.eachRelationship(function(key, descriptor) { + internalModel._relationships[key].setHasData(true); }); return record; @@ -601,29 +610,27 @@ Store = Service.extend({ */ findById: function(modelName, id, preload) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + var internalModel = this._internalModelForId(modelName, id); - var record = this.recordForId(modelName, id); - - return this._findByRecord(record, preload); + return this._findByInternalModel(internalModel, preload); }, - _findByRecord: function(record, preload) { - var fetchedRecord; + _findByInternalModel: function(internalModel, preload) { + var fetchedInternalModel; if (preload) { - record._preloadData(preload); + internalModel._preloadData(preload); } - if (get(record, 'isEmpty')) { - fetchedRecord = this.scheduleFetch(record); + if (internalModel.isEmpty()) { + fetchedInternalModel = this.scheduleFetch(internalModel); //TODO double check about reloading - } else if (get(record, 'isLoading')) { - fetchedRecord = record._loadingPromise; + } else if (internalModel.isLoading()) { + fetchedInternalModel = internalModel._loadingPromise; } - return promiseObject(fetchedRecord || record, "DS: Store#findByRecord " + record.modelName + " with id: " + get(record, 'id')); + return promiseRecord(fetchedInternalModel || internalModel, "DS: Store#findByRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id')); }, - /** This method makes a series of requests to the adapter's `find` method and returns a promise that resolves once they are all loaded. @@ -650,38 +657,39 @@ Store = Service.extend({ @method fetchRecord @private - @param {DS.Model} record + @param {InternalModel} internal model @return {Promise} promise */ - fetchRecord: function(record) { - var typeClass = record.constructor; - var id = get(record, 'id'); + fetchRecord: function(internalModel) { + var typeClass = internalModel.type; + var id = internalModel.id; var adapter = this.adapterFor(typeClass.modelName); Ember.assert("You tried to find a record but you have no adapter (for " + typeClass + ")", adapter); Ember.assert("You tried to find a record but your adapter (for " + typeClass + ") does not implement 'find'", typeof adapter.find === 'function'); - var promise = _find(adapter, this, typeClass, id, record); + var promise = _find(adapter, this, typeClass, id, internalModel); return promise; }, scheduleFetchMany: function(records) { - return Promise.all(map(records, this.scheduleFetch, this)); + var internalModels = map(records, function(record) { return record._internalModel; }); + return Promise.all(map(internalModels, this.scheduleFetch, this)); }, - scheduleFetch: function(record) { - var typeClass = record.constructor; - if (isNone(record)) { return null; } - if (record._loadingPromise) { return record._loadingPromise; } + scheduleFetch: function(internalModel) { + var typeClass = internalModel.type; - var resolver = Ember.RSVP.defer('Fetching ' + typeClass + 'with id: ' + record.get('id')); + if (internalModel._loadingPromise) { return internalModel._loadingPromise; } + + var resolver = Ember.RSVP.defer('Fetching ' + typeClass + 'with id: ' + internalModel.id); var recordResolverPair = { - record: record, + record: internalModel, resolver: resolver }; var promise = resolver.promise; - record.loadingData(promise); + internalModel.loadingData(promise); if (!this._pendingFetch.get(typeClass)) { this._pendingFetch.set(typeClass, [recordResolverPair]); @@ -767,10 +775,10 @@ Store = Service.extend({ // records from the grouped snapshots even though the _findMany() finder // will once again convert the records to snapshots for adapter.findMany() - var snapshots = Ember.A(records).invoke('_createSnapshot'); + var snapshots = Ember.A(records).invoke('createSnapshot'); var groups = adapter.groupRecordsForFindMany(this, snapshots); forEach(groups, function (groupOfSnapshots) { - var groupOfRecords = Ember.A(groupOfSnapshots).mapBy('record'); + var groupOfRecords = Ember.A(groupOfSnapshots).mapBy('_internalModel'); var requestedRecords = Ember.A(groupOfRecords); var ids = requestedRecords.mapBy('id'); if (ids.length > 1) { @@ -813,7 +821,7 @@ Store = Service.extend({ getById: function(modelName, id) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); if (this.hasRecordForId(modelName, id)) { - return this.recordForId(modelName, id); + return this._internalModelForId(modelName, id).getRecord(); } else { return null; } @@ -831,16 +839,16 @@ Store = Service.extend({ @param {DS.Model} record @return {Promise} promise */ - reloadRecord: function(record) { - var type = record.constructor; - var adapter = this.adapterFor(type.modelName); - var id = get(record, 'id'); + reloadRecord: function(internalModel) { + var modelName = internalModel.type.modelName; + var adapter = this.adapterFor(modelName); + var id = internalModel.id; Ember.assert("You cannot reload a record without an ID", id); - Ember.assert("You tried to reload a record but you have no adapter (for " + type + ")", adapter); + Ember.assert("You tried to reload a record but you have no adapter (for " + modelName + ")", adapter); Ember.assert("You tried to reload a record but your adapter does not implement `find`", typeof adapter.find === 'function'); - return this.scheduleFetch(record); + return this.scheduleFetch(internalModel); }, /** @@ -855,8 +863,8 @@ Store = Service.extend({ Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var id = coerceId(inputId); - var record = this.typeMapFor(typeClass).idToRecord[id]; - return !!record && get(record, 'isLoaded'); + var internalModel = this.typeMapFor(typeClass).idToRecord[id]; + return !!internalModel && internalModel.isLoaded(); }, /** @@ -869,33 +877,36 @@ Store = Service.extend({ @param {String|Integer} id @return {DS.Model} record */ - recordForId: function(modelName, inputId) { + recordForId: function(modelName, id) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - var typeClass = this.modelFor(modelName); + return this._internalModelForId(modelName, id).getRecord(); + }, + + _internalModelForId: function(typeName, inputId) { + var typeClass = this.modelFor(typeName); var id = coerceId(inputId); var idToRecord = this.typeMapFor(typeClass).idToRecord; var record = idToRecord[id]; if (!record || !idToRecord[id]) { - record = this.buildRecord(typeClass, id); + record = this.buildInternalModel(typeClass, id); } return record; }, + + /** @method findMany @private - @param {DS.Model} owner - @param {Array} records - @param {String or subclass of DS.Model} type - @param {Resolver} resolver + @param {Array} internalModels @return {Promise} promise */ - findMany: function(records) { + findMany: function(internalModels) { var store = this; - return Promise.all(map(records, function(record) { - return store._findByRecord(record); + return Promise.all(map(internalModels, function(internalModel) { + return store._findByInternalModel(internalModel); })); }, @@ -919,9 +930,9 @@ Store = Service.extend({ @return {Promise} promise */ findHasMany: function(owner, link, type) { - var adapter = this.adapterFor(owner.constructor.modelName); + var adapter = this.adapterFor(owner.type.modelName); - Ember.assert("You tried to load a hasMany relationship but you have no adapter (for " + owner.constructor + ")", adapter); + Ember.assert("You tried to load a hasMany relationship but you have no adapter (for " + owner.type + ")", adapter); Ember.assert("You tried to load a hasMany relationship from a specified `link` in the original payload but your adapter does not implement `findHasMany`", typeof adapter.findHasMany === 'function'); return _findHasMany(adapter, this, owner, link, type); @@ -936,9 +947,9 @@ Store = Service.extend({ @return {Promise} promise */ findBelongsTo: function(owner, link, relationship) { - var adapter = this.adapterFor(owner.constructor.modelName); + var adapter = this.adapterFor(owner.type.modelName); - Ember.assert("You tried to load a belongsTo relationship but you have no adapter (for " + owner.constructor + ")", adapter); + Ember.assert("You tried to load a belongsTo relationship but you have no adapter (for " + owner.type + ")", adapter); Ember.assert("You tried to load a belongsTo relationship from a specified `link` in the original payload but your adapter does not implement `findBelongsTo`", typeof adapter.findBelongsTo === 'function'); return _findBelongsTo(adapter, this, owner, link, relationship); @@ -1204,8 +1215,7 @@ Store = Service.extend({ */ recordIsLoaded: function(modelName, id) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - if (!this.hasRecordForId(modelName, id)) { return false; } - return !get(this.recordForId(modelName, id), 'isEmpty'); + return this.hasRecordForId(modelName, id); }, /** @@ -1248,10 +1258,10 @@ Store = Service.extend({ @method dataWasUpdated @private @param {Class} type - @param {DS.Model} record + @param {InternalModel} internal model */ - dataWasUpdated: function(type, record) { - this.recordArrayManager.recordDidChange(record); + dataWasUpdated: function(type, internalModel) { + this.recordArrayManager.recordDidChange(internalModel); }, // .............. @@ -1266,12 +1276,14 @@ Store = Service.extend({ @method scheduleSave @private - @param {DS.Model} record + @param {InternalModel} internal model @param {Resolver} resolver */ - scheduleSave: function(record, resolver) { - record.adapterWillCommit(); - this._pendingSave.push([record, resolver]); + scheduleSave: function(internalModel, resolver) { + var snapshot = internalModel.createSnapshot(); + internalModel.flushChangedAttributes(); + internalModel.adapterWillCommit(); + this._pendingSave.push([snapshot, resolver]); once(this, 'flushPendingSave'); }, @@ -1287,22 +1299,23 @@ Store = Service.extend({ this._pendingSave = []; forEach(pending, function(tuple) { - var record = tuple[0]; + var snapshot = tuple[0]; var resolver = tuple[1]; - var adapter = this.adapterFor(record.constructor.modelName); + var record = snapshot._internalModel; + var adapter = this.adapterFor(record.type.modelName); var operation; if (get(record, 'currentState.stateName') === 'root.deleted.saved') { - return resolver.resolve(record); - } else if (get(record, 'isNew')) { + return resolver.resolve(); + } else if (record.isNew()) { operation = 'createRecord'; - } else if (get(record, 'isDeleted')) { + } else if (record.isDeleted()) { operation = 'deleteRecord'; } else { operation = 'updateRecord'; } - resolver.resolve(_commit(adapter, this, operation, record)); + resolver.resolve(_commit(adapter, this, operation, snapshot)); }, this); }, @@ -1316,19 +1329,19 @@ Store = Service.extend({ @method didSaveRecord @private - @param {DS.Model} record the in-flight record + @param {InternalModel} internal model the in-flight internal model @param {Object} data optional data (see above) */ - didSaveRecord: function(record, data) { + didSaveRecord: function(internalModel, data) { if (data) { // normalize relationship IDs into records - this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', record, record.constructor, data); - this.updateId(record, data); + this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, internalModel.type, data); + this.updateId(internalModel, data); } //We first make sure the primary data has been updated //TODO try to move notification to the user to the end of the runloop - record.adapterDidCommit(data); + internalModel.adapterDidCommit(data); }, /** @@ -1338,11 +1351,11 @@ Store = Service.extend({ @method recordWasInvalid @private - @param {DS.Model} record + @param {InternalModel} internal model @param {Object} errors */ - recordWasInvalid: function(record, errors) { - record.adapterDidInvalidate(errors); + recordWasInvalid: function(internalModel, errors) { + internalModel.adapterDidInvalidate(errors); }, /** @@ -1352,10 +1365,10 @@ Store = Service.extend({ @method recordWasError @private - @param {DS.Model} record + @param {InternalModel} internal model */ - recordWasError: function(record) { - record.adapterDidError(); + recordWasError: function(internalModel) { + internalModel.adapterDidError(); }, /** @@ -1365,18 +1378,18 @@ Store = Service.extend({ @method updateId @private - @param {DS.Model} record + @param {InternalModel} internal model @param {Object} data */ - updateId: function(record, data) { - var oldId = get(record, 'id'); + updateId: function(internalModel, data) { + var oldId = internalModel.id; var id = coerceId(data.id); - Ember.assert("An adapter cannot assign a new id to a record that already has an id. " + record + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId); + Ember.assert("An adapter cannot assign a new id to a record that already has an id. " + internalModel + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId); - this.typeMapFor(record.constructor).idToRecord[id] = record; + this.typeMapFor(internalModel.type).idToRecord[id] = internalModel; - set(record, 'id', id); + internalModel.setId(id); }, /** @@ -1420,12 +1433,13 @@ Store = Service.extend({ */ _load: function(type, data) { var id = coerceId(data.id); - var record = this.recordForId(type, id); + var internalModel = this._internalModelForId(type, id); - record.setupData(data); - this.recordArrayManager.recordDidChange(record); + internalModel.setupData(data); - return record; + this.recordArrayManager.recordDidChange(internalModel); + + return internalModel; }, /* @@ -1490,7 +1504,11 @@ Store = Service.extend({ configurable: false, get: function() { Ember.deprecate('Usage of `typeKey` has been deprecated and will be removed in Ember Data 1.0. It has been replaced by `modelName` on the model class.'); - return Ember.String.camelize(this.modelName); + var typeKey = this.modelName; + if (typeKey) { + typeKey = Ember.String.camelize(this.modelName); + } + return typeKey; }, set: function() { Ember.assert('Setting typeKey is not supported. In addition, typeKey has also been deprecated in favor of modelName. Setting modelName is also not supported.'); @@ -1576,6 +1594,11 @@ Store = Service.extend({ */ push: function(modelName, data) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + var internalModel = this._pushInternalModel(modelName, data); + return internalModel.getRecord(); + }, + + _pushInternalModel: function(modelName, data) { Ember.assert("Expected an object as `data` in a call to `push` for " + modelName + " , but was " + data, Ember.typeOf(data) === 'object'); Ember.assert("You must include an `id` for " + modelName + " in an object passed to `push`", data.id != null && data.id !== ''); @@ -1596,17 +1619,15 @@ Store = Service.extend({ } // Actually load the record into the store. + var internalModel = this._load(modelName, data); - this._load(modelName, data); - - var record = this.recordForId(modelName, data.id); var store = this; this._backburner.join(function() { - store._backburner.schedule('normalizeRelationships', store, '_setupRelationships', record, type, data); + store._backburner.schedule('normalizeRelationships', store, '_setupRelationships', internalModel, type, data); }); - return record; + return internalModel; }, _setupRelationships: function(record, type, data) { @@ -1768,9 +1789,9 @@ Store = Service.extend({ @param {subclass of DS.Model} type @param {String} id @param {Object} data - @return {DS.Model} record + @return {InternalModel} internal model */ - buildRecord: function(type, id, data) { + buildInternalModel: function(type, id, data) { var typeMap = this.typeMapFor(type); var idToRecord = typeMap.idToRecord; @@ -1779,25 +1800,17 @@ Store = Service.extend({ // lookupFactory should really return an object that creates // instances with the injections applied - var record = type._create({ - id: id, - store: this, - container: this.container - }); - - if (data) { - record.setupData(data); - } + var internalModel = new InternalModel(type, id, this, this.container, data); // if we're creating an item, this process will be done // later, once the object has been persisted. if (id) { - idToRecord[id] = record; + idToRecord[id] = internalModel; } - typeMap.records.push(record); + typeMap.records.push(internalModel); - return record; + return internalModel; }, //Called by the state machine to notify the store that the record is ready to be interacted with @@ -1826,20 +1839,20 @@ Store = Service.extend({ @method _dematerializeRecord @private - @param {DS.Model} record + @param {InternalModel} internal model */ - _dematerializeRecord: function(record) { - var type = record.constructor; + _dematerializeRecord: function(internalModel) { + var type = internalModel.type; var typeMap = this.typeMapFor(type); - var id = get(record, 'id'); + var id = internalModel.id; - record.updateRecordArrays(); + internalModel.updateRecordArrays(); if (id) { delete typeMap.idToRecord[id]; } - var loc = indexOf(typeMap.records, record); + var loc = indexOf(typeMap.records, internalModel); typeMap.records.splice(loc, 1); }, @@ -2002,20 +2015,27 @@ function normalizeRelationships(store, type, data, record) { } function deserializeRecordId(store, data, key, relationship, id) { - if (isNone(id) || id instanceof Model) { + if (isNone(id)) { return; } + + //If record objects were given to push directly, uncommon, not sure whether we should actually support + if (id instanceof Model) { + data[key] = id._internalModel; + return; + } + Ember.assert("A " + relationship.parentType + " record was pushed into the store with the value of " + key + " being " + Ember.inspect(id) + ", but " + key + " is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.", !Ember.isArray(id)); var type; if (typeof id === 'number' || typeof id === 'string') { type = typeFor(relationship, key, data); - data[key] = store.recordForId(typeof type === 'string' ? type : type.modelName, id); + data[key] = store._internalModelForId(type, id); } else if (typeof id === 'object') { // hasMany polymorphic Ember.assert('Ember Data expected a number or string to represent the record(s) in the `' + relationship.key + '` relationship instead it found an object. If this is a polymorphic relationship please specify a `type` key. If this is an embedded relationship please include the `DS.EmbeddedRecordsMixin` and specify the `' + relationship.key +'` property in your serializer\'s attrs object.', id.type); - data[key] = store.recordForId(id.type, id.id); + data[key] = store._internalModelForId(id.type, id.id); } } @@ -2047,10 +2067,10 @@ function defaultSerializer(container) { container.lookup('serializer:-default'); } -function _commit(adapter, store, operation, record) { - var type = record.constructor; - var modelName = type.modelName; - var snapshot = record._createSnapshot(); +function _commit(adapter, store, operation, snapshot) { + var record = snapshot._internalModel; + var modelName = snapshot.modelName; + var type = store.modelFor(modelName); var promise = adapter[operation](store, type, snapshot); var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Extract and notify about " + operation + " completion of " + record; @@ -2066,7 +2086,7 @@ function _commit(adapter, store, operation, record) { store._adapterRun(function() { if (adapterPayload) { - payload = serializer.extract(store, type, adapterPayload, get(record, 'id'), operation); + payload = serializer.extract(store, type, adapterPayload, snapshot.id, operation); } store.didSaveRecord(record, payload); }); @@ -2074,7 +2094,7 @@ function _commit(adapter, store, operation, record) { return record; }, function(reason) { if (reason instanceof InvalidError) { - var errors = serializer.extractErrors(store, type, reason.errors, get(record, 'id')); + var errors = serializer.extractErrors(store, type, reason.errors, snapshot.id); store.recordWasInvalid(record, errors); reason = new InvalidError(errors); } else { @@ -2086,7 +2106,7 @@ function _commit(adapter, store, operation, record) { } function setupRelationships(store, record, data) { - var typeClass = record.constructor; + var typeClass = record.type; typeClass.eachRelationship(function(key, descriptor) { var kind = descriptor.kind; diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index 0296ef02fc1..dbb6be5fbb6 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -9,14 +9,13 @@ import { } from "ember-data/system/store/serializers"; -var get = Ember.get; var Promise = Ember.RSVP.Promise; +var map = Ember.EnumerableUtils.map; -export function _find(adapter, store, typeClass, id, record) { - var modelName = typeClass.modelName; - var snapshot = record._createSnapshot(); +export function _find(adapter, store, typeClass, id, internalModel) { + var snapshot = internalModel.createSnapshot(); var promise = adapter.find(store, typeClass, id, snapshot); - var serializer = serializerForAdapter(store, adapter, modelName); + var serializer = serializerForAdapter(store, adapter, internalModel.type.modelName); var label = "DS: Handle Adapter#find of " + typeClass + " with id: " + id; promise = Promise.cast(promise, label); @@ -27,12 +26,14 @@ export function _find(adapter, store, typeClass, id, record) { return store._adapterRun(function() { var payload = serializer.extract(store, typeClass, adapterPayload, id, 'find'); - return store.push(modelName, payload); + //TODO Optimize + var record = store.push(typeClass.modelName, payload); + return record._internalModel; }); }, function(error) { - record.notFound(); - if (get(record, 'isEmpty')) { - store.unloadRecord(record); + internalModel.notFound(); + if (internalModel.isEmpty()) { + internalModel.unloadRecord(); } throw error; @@ -40,11 +41,10 @@ export function _find(adapter, store, typeClass, id, record) { } -export function _findMany(adapter, store, typeClass, ids, records) { - var modelName = typeClass.modelName; - var snapshots = Ember.A(records).invoke('_createSnapshot'); +export function _findMany(adapter, store, typeClass, ids, internalModels) { + var snapshots = Ember.A(internalModels).invoke('createSnapshot'); var promise = adapter.findMany(store, typeClass, ids, snapshots); - var serializer = serializerForAdapter(store, adapter, modelName); + var serializer = serializerForAdapter(store, adapter, typeClass.modelName); var label = "DS: Handle Adapter#findMany of " + typeClass; if (promise === undefined) { @@ -60,22 +60,23 @@ export function _findMany(adapter, store, typeClass, ids, records) { Ember.assert("The response from a findMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); - return store.pushMany(modelName, payload); + //TODO Optimize, no need to materialize here + var records = store.pushMany(typeClass.modelName, payload); + return map(records, function(record) { return record._internalModel; }); }); }, null, "DS: Extract payload of " + typeClass); } -export function _findHasMany(adapter, store, record, link, relationship) { - var snapshot = record._createSnapshot(); - var modelName = relationship.type; - var typeClass = store.modelFor(modelName); +export function _findHasMany(adapter, store, internalModel, link, relationship) { + var snapshot = internalModel.createSnapshot(); + var typeClass = store.modelFor(relationship.type); var promise = adapter.findHasMany(store, snapshot, link, relationship); - var serializer = serializerForAdapter(store, adapter, modelName); - var label = "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type; + var serializer = serializerForAdapter(store, adapter, relationship.type); + var label = "DS: Handle Adapter#findHasMany of " + internalModel + " : " + relationship.type; promise = Promise.cast(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); - promise = _guard(promise, _bind(_objectIsAlive, record)); + promise = _guard(promise, _bind(_objectIsAlive, internalModel)); return promise.then(function(adapterPayload) { return store._adapterRun(function() { @@ -83,23 +84,23 @@ export function _findHasMany(adapter, store, record, link, relationship) { Ember.assert("The response from a findHasMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); - var records = store.pushMany(modelName, payload); - return records; + //TODO Use a non record creating push + var records = store.pushMany(relationship.type, payload); + return map(records, function(record) { return record._internalModel; }); }); - }, null, "DS: Extract payload of " + record + " : hasMany " + relationship.type); + }, null, "DS: Extract payload of " + internalModel + " : hasMany " + relationship.type); } -export function _findBelongsTo(adapter, store, record, link, relationship) { - var modelName = relationship.type; - var typeClass = store.modelFor(modelName); - var snapshot = record._createSnapshot(); +export function _findBelongsTo(adapter, store, internalModel, link, relationship) { + var snapshot = internalModel.createSnapshot(); + var typeClass = store.modelFor(relationship.type); var promise = adapter.findBelongsTo(store, snapshot, link, relationship); - var serializer = serializerForAdapter(store, adapter, modelName); - var label = "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type; + var serializer = serializerForAdapter(store, adapter, relationship.type); + var label = "DS: Handle Adapter#findBelongsTo of " + internalModel + " : " + relationship.type; promise = Promise.cast(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); - promise = _guard(promise, _bind(_objectIsAlive, record)); + promise = _guard(promise, _bind(_objectIsAlive, internalModel)); return promise.then(function(adapterPayload) { return store._adapterRun(function() { @@ -109,10 +110,11 @@ export function _findBelongsTo(adapter, store, record, link, relationship) { return null; } - var record = store.push(modelName, payload); - return record; + var record = store.push(relationship.type, payload); + //TODO Optimize + return record._internalModel; }); - }, null, "DS: Extract payload of " + record + " : " + relationship.type); + }, null, "DS: Extract payload of " + internalModel + " : " + relationship.type); } export function _findAll(adapter, store, typeClass, sinceToken) { diff --git a/packages/ember-data/tests/integration/adapter/find-all-test.js b/packages/ember-data/tests/integration/adapter/find-all-test.js index a0541631765..50854511e44 100644 --- a/packages/ember-data/tests/integration/adapter/find-all-test.js +++ b/packages/ember-data/tests/integration/adapter/find-all-test.js @@ -91,6 +91,10 @@ test("When all records for a type are requested, a rejection should reject the p test("When all records for a type are requested, records that are already loaded should be returned immediately.", function() { expect(3); + store = createStore({ + adapter: DS.Adapter.extend(), + person: Person + }); run(function() { // Load a record from the server diff --git a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js b/packages/ember-data/tests/integration/adapter/rest-adapter-test.js index 7098801ca74..5b2e2218b02 100644 --- a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js +++ b/packages/ember-data/tests/integration/adapter/rest-adapter-test.js @@ -486,7 +486,7 @@ test("create - response can contain relationships the client doesn't yet know ab var postRecords = store.typeMapFor(Post).records; for (var i = 0; i < postRecords.length; i++) { - equal(post, postRecords[i], "The object in the identity map is the same"); + equal(post, postRecords[i].getRecord(), "The object in the identity map is the same"); } })); }); diff --git a/packages/ember-data/tests/integration/record-array-manager-test.js b/packages/ember-data/tests/integration/record-array-manager-test.js index fbef834d1b8..f059fff3787 100644 --- a/packages/ember-data/tests/integration/record-array-manager-test.js +++ b/packages/ember-data/tests/integration/record-array-manager-test.js @@ -84,17 +84,17 @@ test("destroying the store correctly cleans everything up", function() { equal(filterd2Summary.called.length, 0); - equal(person._recordArrays.list.length, 2, 'expected the person to be a member of 2 recordArrays'); + equal(person._internalModel._recordArrays.list.length, 2, 'expected the person to be a member of 2 recordArrays'); Ember.run(filterd2, filterd2.destroy); - equal(person._recordArrays.list.length, 1, 'expected the person to be a member of 1 recordArrays'); + equal(person._internalModel._recordArrays.list.length, 1, 'expected the person to be a member of 1 recordArrays'); equal(filterd2Summary.called.length, 1); Ember.run(manager, manager.destroy); - equal(person._recordArrays.list.length, 0, 'expected the person to be a member of no recordArrays'); + equal(person._internalModel._recordArrays.list.length, 0, 'expected the person to be a member of no recordArrays'); equal(filterd2Summary.called.length, 1); diff --git a/packages/ember-data/tests/integration/records/save-test.js b/packages/ember-data/tests/integration/records/save-test.js index cc432f3169d..10fc17fbd50 100644 --- a/packages/ember-data/tests/integration/records/save-test.js +++ b/packages/ember-data/tests/integration/records/save-test.js @@ -18,19 +18,28 @@ module("integration/records/save - Save Record", { }); test("Will resolve save on success", function() { - expect(1); + expect(4); var post; run(function() { post = env.store.createRecord('post', { title: 'toto' }); }); + var deferred = Ember.RSVP.defer(); env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ id: 123 }); + return deferred.promise; }; run(function() { - post.save().then(function() { + var saved = post.save(); + + // `save` returns a PromiseObject which allows to call get on it + equal(saved.get('id'), undefined); + + deferred.resolve({ id: 123 }); + saved.then(function(model) { ok(true, 'save operation was resolved'); + equal(saved.get('id'), 123); + equal(model, post, "resolves with the model"); }); }); }); diff --git a/packages/ember-data/tests/integration/relationships/belongs-to-test.js b/packages/ember-data/tests/integration/relationships/belongs-to-test.js index db4ba5d33e7..5c3a5399989 100644 --- a/packages/ember-data/tests/integration/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/integration/relationships/belongs-to-test.js @@ -609,7 +609,7 @@ test("belongsTo hasData async loaded", function () { run(function() { store.find('book', 1).then(function(book) { - var relationship = book._relationships['author']; + var relationship = book._internalModel._relationships['author']; equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -624,7 +624,7 @@ test("belongsTo hasData sync loaded", function () { run(function() { store.find('book', 1).then(function(book) { - var relationship = book._relationships['author']; + var relationship = book._internalModel._relationships['author']; equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -643,7 +643,7 @@ test("belongsTo hasData async not loaded", function () { run(function() { store.find('book', 1).then(function(book) { - var relationship = book._relationships['author']; + var relationship = book._internalModel._relationships['author']; equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -658,7 +658,7 @@ test("belongsTo hasData sync not loaded", function () { run(function() { store.find('book', 1).then(function(book) { - var relationship = book._relationships['author']; + var relationship = book._internalModel._relationships['author']; equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -673,7 +673,7 @@ test("belongsTo hasData async created", function () { run(function() { var book = store.createRecord('book', { name: 'The Greatest Book' }); - var relationship = book._relationships['author']; + var relationship = book._internalModel._relationships['author']; equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -683,7 +683,7 @@ test("belongsTo hasData sync created", function () { run(function() { var book = store.createRecord('book', { name: 'The Greatest Book' }); - var relationship = book._relationships['author']; + var relationship = book._internalModel._relationships['author']; equal(relationship.hasData, true, 'relationship has data'); }); }); diff --git a/packages/ember-data/tests/integration/relationships/has-many-test.js b/packages/ember-data/tests/integration/relationships/has-many-test.js index 42584542cd7..780fa5feadd 100644 --- a/packages/ember-data/tests/integration/relationships/has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/has-many-test.js @@ -127,7 +127,7 @@ test("adapter.findMany only gets unique IDs even if duplicate IDs are present in }); // This tests the case where a serializer materializes a has-many -// relationship as a reference that it can fetch lazily. The most +// relationship as a internalModel that it can fetch lazily. The most // common use case of this is to provide a URL to a collection that // is loaded later. test("A serializer can materialize a hasMany as an opaque token that can be lazily fetched via the adapter's findHasMany hook", function() { @@ -970,7 +970,7 @@ test("dual non-async HM <-> BT", function() { deepEqual(post, commentPost, 'expect the new comments post, to be the correct post'); ok(postComments, "comments should exist"); - equal(postCommentsLength, 2, "comment's post should have a reference back to comment"); + equal(postCommentsLength, 2, "comment's post should have a internalModel back to comment"); ok(postComments && postComments.indexOf(firstComment) !== -1, 'expect to contain first comment'); ok(postComments && postComments.indexOf(comment) !== -1, 'expected to contain the new comment'); }); @@ -1218,7 +1218,7 @@ test("Relationship.clear removes all records correctly", function() { }); run(function() { - post._relationships['comments'].clear(); + post._internalModel._relationships['comments'].clear(); var comments = Ember.A(env.store.all('comment')); deepEqual(comments.mapBy('post'), [null, null, null]); }); @@ -1350,7 +1350,7 @@ test("hasMany hasData async loaded", function () { run(function() { store.find('chapter', 1).then(function(chapter) { - var relationship = chapter._relationships['pages']; + var relationship = chapter._internalModel._relationships['pages']; equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -1365,7 +1365,7 @@ test("hasMany hasData sync loaded", function () { run(function() { store.find('chapter', 1).then(function(chapter) { - var relationship = chapter._relationships['pages']; + var relationship = chapter._internalModel._relationships['pages']; equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -1384,7 +1384,7 @@ test("hasMany hasData async not loaded", function () { run(function() { store.find('chapter', 1).then(function(chapter) { - var relationship = chapter._relationships['pages']; + var relationship = chapter._internalModel._relationships['pages']; equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -1399,7 +1399,7 @@ test("hasMany hasData sync not loaded", function () { run(function() { store.find('chapter', 1).then(function(chapter) { - var relationship = chapter._relationships['pages']; + var relationship = chapter._internalModel._relationships['pages']; equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -1414,7 +1414,7 @@ test("hasMany hasData async created", function () { run(function() { var chapter = store.createRecord('chapter', { title: 'The Story Begins' }); - var relationship = chapter._relationships['pages']; + var relationship = chapter._internalModel._relationships['pages']; equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -1424,7 +1424,7 @@ test("hasMany hasData sync created", function () { run(function() { var chapter = store.createRecord('chapter', { title: 'The Story Begins' }); - var relationship = chapter._relationships['pages']; + var relationship = chapter._internalModel._relationships['pages']; equal(relationship.hasData, true, 'relationship has data'); }); }); diff --git a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js index 0c4f1e99a71..b2e4db91a08 100644 --- a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js +++ b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js @@ -609,6 +609,32 @@ test("serialize with embedded objects (hasMany relationship)", function() { }); }); +test("serialize with embedded objects (unknown hasMany relationship)", function() { + var league; + run(function() { + league = env.store.push('home-planet', { name: "Villain League", id: "123" }); + }); + + env.registry.register('serializer:home-planet', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' } + } + })); + + var serializer, json; + warns(function() { + run(function() { + serializer = env.container.lookup("serializer:home-planet"); + json = serializer.serialize(league._createSnapshot()); + }); + }, /The embedded relationship 'villains' is undefined for 'home-planet' with id '123'. Please include it in your original payload./); + + deepEqual(json, { + name: "Villain League", + villains: [] + }); +}); + test("serialize with embedded objects (hasMany relationship) supports serialize:false", function() { run(function() { league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); @@ -1165,6 +1191,63 @@ test("extractSingle with polymorphic hasMany", function() { }); +test("extractSingle with polymorphic hasMany and custom primary key", function() { + SuperVillain.reopen({ + secretWeapons: DS.hasMany("secretWeapon", { polymorphic: true }) + }); + + env.registry.register('adapter:super-villain', DS.ActiveModelAdapter); + env.registry.register('serializer:light-saber', DS.ActiveModelSerializer.extend({ + primaryKey: 'custom' + })); + env.registry.register('serializer:super-villain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretWeapons: { embedded: 'always' } + } + })); + var serializer = env.container.lookup("serializer:super-villain"); + + var json_hash = { + super_villain: { + id: "1", + first_name: "Tom", + last_name: "Dale", + secret_weapons: [ + { + custom: "1", + type: "LightSaber", + name: "Tom's LightSaber", + color: "Red" + }, + { + id: "1", + type: "SecretWeapon", + name: "The Death Star" + } + ] + } + }; + var json; + + run(function() { + json = serializer.extractSingle(env.store, SuperVillain, json_hash); + }); + + deepEqual(json, { + id: "1", + firstName: "Tom", + lastName: "Dale", + secretWeapons: [ + { id: "1", type: "light-saber" }, + { id: "1", type: "secret-weapon" } + ] + }, "Custom primary key of embedded hasMany is correctly normalized"); + + equal(env.store.recordForId("lightSaber", "1").get("name"), "Tom's LightSaber", "Embedded polymorphic LightSaber with custom primary key is found"); + equal(env.store.recordForId("secretWeapon", "1").get("name"), "The Death Star", "Embedded polymorphic SecretWeapon found"); + +}); + test("extractSingle with polymorphic belongsTo", function() { expect(2); @@ -1211,6 +1294,55 @@ test("extractSingle with polymorphic belongsTo", function() { }); +test("extractSingle with polymorphic belongsTo and custom primary key", function() { + expect(2); + + SuperVillain.reopen({ + secretLab: DS.belongsTo("secretLab", { polymorphic: true }) + }); + + env.registry.register('adapter:super-villain', DS.ActiveModelAdapter); + env.registry.register('serializer:super-villain', DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' } + } + })); + env.registry.register('serializer:bat-cave', DS.ActiveModelSerializer.extend({ + primaryKey: 'custom' + })); + var serializer = env.container.lookup("serializer:super-villain"); + + var json_hash = { + super_villain: { + id: "1", + first_name: "Tom", + last_name: "Dale", + secret_lab: { + custom: "1", + type: "bat-cave", + infiltrated: true + } + } + }; + + var json; + + run(function() { + json = serializer.extractSingle(env.store, SuperVillain, json_hash); + }); + + deepEqual(json, { + id: "1", + firstName: "Tom", + lastName: "Dale", + secretLab: "1", + secretLabType: "bat-cave" + }, "Custom primary key is correctly normalized"); + + equal(env.store.recordForId("batCave", "1").get("infiltrated"), true, "Embedded polymorphic BatCave with custom primary key is found"); + +}); + test("Mixin can be used with RESTSerializer which does not define keyForAttribute", function() { run(function() { homePlanet = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); diff --git a/packages/ember-data/tests/integration/snapshot-test.js b/packages/ember-data/tests/integration/snapshot-test.js index 0c71dffd273..8b85621cab2 100644 --- a/packages/ember-data/tests/integration/snapshot-test.js +++ b/packages/ember-data/tests/integration/snapshot-test.js @@ -112,6 +112,20 @@ test("snapshot.attributes() returns a copy of all attributes for the current sna }); }); +test("snapshot.changedAttributes() returns a copy of all changed attributes for the current snapshot", function() { + expect(1); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + post.set('title', 'Hello World!'); + var snapshot = post._createSnapshot(); + + var changes = snapshot.changedAttributes(); + + deepEqual(changes, { title: ['Hello World', 'Hello World!'] }, 'changed attributes are returned correctly'); + }); +}); + test("snapshot.belongsTo() returns undefined if relationship is undefined", function() { expect(1); diff --git a/packages/ember-data/tests/unit/model-test.js b/packages/ember-data/tests/unit/model-test.js index 8063ea1dde8..e41eb4a38fc 100644 --- a/packages/ember-data/tests/unit/model-test.js +++ b/packages/ember-data/tests/unit/model-test.js @@ -147,17 +147,19 @@ test("a collision of a record's id with object function's name", function() { } }); -test("it should use `_reference` and not `reference` to store its reference", function() { +/* +test("it should use `_internalModel` and not `internalModel` to store its internalModel", function() { expect(1); run(function() { store.push('person', { id: 1 }); - store.find('person', 1).then(function(record) { - equal(record.get('reference'), undefined, "doesn't shadow reference key"); + store.find(Person, 1).then(function(record) { + equal(record.get('_internalModel'), undefined, "doesn't shadow internalModel key"); }); }); }); +*/ test("it should cache attributes", function() { expect(2); @@ -456,15 +458,15 @@ test("setting a property back to its original value removes the property from th run(function() { store.find('person', 1).then(function(person) { - equal(person._attributes.name, undefined, "the `_attributes` hash is clean"); + equal(person._internalModel._attributes.name, undefined, "the `_attributes` hash is clean"); set(person, 'name', "Niceguy Dale"); - equal(person._attributes.name, "Niceguy Dale", "the `_attributes` hash contains the changed value"); + equal(person._internalModel._attributes.name, "Niceguy Dale", "the `_attributes` hash contains the changed value"); set(person, 'name', "Scumbag Dale"); - equal(person._attributes.name, undefined, "the `_attributes` hash is reset"); + equal(person._internalModel._attributes.name, undefined, "the `_attributes` hash is reset"); }); }); }); @@ -825,3 +827,9 @@ test("Pushing a record into the store should transition it to the loaded state", equal(person.get('isNew'), false, 'push should put records into the loaded state'); }); }); + +test("A subclass of DS.Model throws an error when calling create() directly", function() { + throws(function() { + Person.create(); + }, /You should not call `create` on a model/, "Throws an error when calling create() on model"); +}); diff --git a/packages/ember-data/tests/unit/model/internal-model-test.js b/packages/ember-data/tests/unit/model/internal-model-test.js new file mode 100644 index 00000000000..5e81ff5ab17 --- /dev/null +++ b/packages/ember-data/tests/unit/model/internal-model-test.js @@ -0,0 +1,19 @@ +module("unit/model/internal-model - Internal Model"); + +var mockModelFactory = { + _create: function() { + return { trigger: function() {} }; + }, + + eachRelationship: function() { + } +}; +test("Materializing a model twice errors out", function() { + expect(1); + var internalModel = new DS.InternalModel(mockModelFactory, null, null, null); + + internalModel.materializeRecord(); + expectAssertion(function() { + internalModel.materializeRecord(); + }, /more than once/); +}); diff --git a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js index 45cbd32c730..accac509a36 100644 --- a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js +++ b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js @@ -32,6 +32,32 @@ test("a record receives a didLoad callback when it has finished loading", functi }); }); +test("TEMPORARY: a record receives a didLoad callback once it materializes if it wasn't materialized when loaded", function() { + expect(2); + var didLoadCalled = 0; + var Person = DS.Model.extend({ + name: DS.attr(), + didLoad: function() { + didLoadCalled++; + } + }); + + var store = createStore({ + person: Person + }); + + run(function() { + store._pushInternalModel('person', { id: 1 }); + equal(didLoadCalled, 0, "didLoad was not called"); + }); + run(function() { + store.getById('person', 1); + }); + run(function() { + equal(didLoadCalled, 1, "didLoad was called"); + }); +}); + test("a record receives a didUpdate callback when it has finished updating", function() { expect(5); diff --git a/packages/ember-data/tests/unit/model/merge-test.js b/packages/ember-data/tests/unit/model/merge-test.js index 353099942a3..df3bfee770c 100644 --- a/packages/ember-data/tests/unit/model/merge-test.js +++ b/packages/ember-data/tests/unit/model/merge-test.js @@ -43,6 +43,41 @@ test("When a record is in flight, changes can be made", function() { }); }); +test("Make sure snapshot is created at save time not at flush time", function() { + expect(5); + + var adapter = DS.Adapter.extend({ + updateRecord: function(store, type, snapshot) { + equal(snapshot.attr('name'), 'Thomas Dale'); + + return Ember.RSVP.resolve(); + } + }); + + var store = createStore({ adapter: adapter, person: Person }); + var person; + + run(function() { + person = store.push('person', { id: 1, name: "Tom" }); + person.set('name', "Thomas Dale"); + }); + + run(function() { + var promise = person.save(); + + equal(person.get('name'), "Thomas Dale"); + + person.set('name', "Tomasz Dale"); + + equal(person.get('name'), "Tomasz Dale", "the local changes applied on top"); + + promise.then(async(function(person) { + equal(person.get('isDirty'), true, "The person is still dirty"); + equal(person.get('name'), "Tomasz Dale", "The local changes apply"); + })); + }); +}); + test("When a record is in flight, pushes are applied underneath the in flight changes", function() { expect(6); diff --git a/packages/ember-data/tests/unit/model/relationships/record-array-test.js b/packages/ember-data/tests/unit/model/relationships/record-array-test.js index 76809505d26..be273c2a158 100644 --- a/packages/ember-data/tests/unit/model/relationships/record-array-test.js +++ b/packages/ember-data/tests/unit/model/relationships/record-array-test.js @@ -11,18 +11,19 @@ test("updating the content of a RecordArray updates its content", function() { var env = setupStore({ tag: Tag }); var store = env.store; - var records, tags; + var records, tags, internalModel; run(function() { records = store.pushMany('tag', [{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }, { id: 12, name: "oohlala" }]); - tags = DS.RecordArray.create({ content: Ember.A(records.slice(0, 2)), store: store, type: Tag }); + internalModel = Ember.A(records).mapBy('_internalModel'); + tags = DS.RecordArray.create({ content: Ember.A(internalModel.slice(0, 2)), store: store, type: Tag }); }); var tag = tags.objectAt(0); equal(get(tag, 'name'), "friendly", "precond - we're working with the right tags"); run(function() { - set(tags, 'content', Ember.A(records.slice(1, 3))); + set(tags, 'content', Ember.A(internalModel.slice(1, 3))); }); tag = tags.objectAt(0); diff --git a/packages/ember-data/tests/unit/model/rollback-test.js b/packages/ember-data/tests/unit/model/rollback-test.js index a7f795b0d44..6db9b6eb832 100644 --- a/packages/ember-data/tests/unit/model/rollback-test.js +++ b/packages/ember-data/tests/unit/model/rollback-test.js @@ -159,6 +159,51 @@ test("new record can be rollbacked", function() { equal(person.get('isDeleted'), true, "must be deleted"); }); +test("invalid new record can be rollbacked", function() { + var person; + var adapter = DS.RESTAdapter.extend({ + ajax: function(url, type, hash) { + var adapter = this; + + return new Ember.RSVP.Promise(function(resolve, reject) { + /* If InvalidError is passed back in the reject it will throw the + exception which will bubble up the call stack (crashing the test) + instead of hitting the failure route of the promise. + So wrapping the reject in an Ember.run.next makes it so save + completes without failure and the failure hits the failure route + of the promise instead of crashing the save. */ + Ember.run.next(function() { + reject(adapter.ajaxError({ name: 'is invalid' })); + }); + }); + }, + + ajaxError: function(jqXHR) { + return new DS.InvalidError(jqXHR); + } + }); + + env = setupStore({ person: Person, adapter: adapter }); + + run(function() { + person = env.store.createRecord('person', { id: 1 }); + }); + + equal(person.get('isNew'), true, "must be new"); + equal(person.get('isDirty'), true, "must be dirty"); + + run(function() { + person.save().then(null, async(function() { + equal(person.get('isValid'), false); + person.rollback(); + + equal(person.get('isNew'), false, "must not be new"); + equal(person.get('isDirty'), false, "must not be dirty"); + equal(person.get('isDeleted'), true, "must be deleted"); + })); + }); +}); + test("deleted record can be rollbacked", function() { var person, people; diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index 69f642600c5..55cd298e46b 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -46,7 +46,7 @@ test("Calling Store#find invokes its adapter#find", function() { find: function(store, type, id, snapshot) { ok(true, "Adapter#find was called"); equal(store, currentStore, "Adapter#find was called with the right store"); - equal(type, store.modelFor('type'), "Adapter#find was called with the type passed into Store#find"); + equal(type, store.modelFor('test'), "Adapter#find was called with the type passed into Store#find"); equal(id, 1, "Adapter#find was called with the id passed into Store#find"); equal(snapshot.id, '1', "Adapter#find was called with the record created from Store#find"); @@ -54,13 +54,12 @@ test("Calling Store#find invokes its adapter#find", function() { } }); - var currentStore = createStore({ - adapter: adapter, - type: DS.Model.extend() - }); + var currentType = DS.Model.extend(); + var currentStore = createStore({ adapter: adapter, test: currentType }); + run(function() { - currentStore.find('type', 1); + currentStore.find('test', 1); }); }); @@ -100,15 +99,13 @@ test("Returning a promise from `find` asynchronously loads data", function() { } }); - var currentStore = createStore({ - adapter: adapter, - type: DS.Model.extend({ - name: DS.attr('string') - }) + var currentType = DS.Model.extend({ + name: DS.attr('string') }); + var currentStore = createStore({ adapter: adapter, test: currentType }); run(function() { - currentStore.find('type', 1).then(async(function(object) { + currentStore.find('test', 1).then(async(function(object) { strictEqual(get(object, 'name'), "Scumbag Dale", "the data was pushed"); })); }); @@ -124,20 +121,18 @@ test("IDs provided as numbers are coerced to strings", function() { } }); - var currentStore = createStore({ - adapter: adapter, - type: DS.Model.extend({ - name: DS.attr('string') - }) + var currentType = DS.Model.extend({ + name: DS.attr('string') }); + var currentStore = createStore({ adapter: adapter, test: currentType }); run(function() { - currentStore.find('type', 1).then(async(function(object) { + currentStore.find('test', 1).then(async(function(object) { equal(typeof object.get('id'), 'string', "id was coerced to a string"); run(function() { - currentStore.push('type', { id: 2, name: "Scumbag Sam Saffron" }); + currentStore.push('test', { id: 2, name: "Scumbag Sam Saffron" }); }); - return currentStore.find('type', 2); + return currentStore.find('test', 2); })).then(async(function(object) { ok(object, "object was found"); equal(typeof object.get('id'), 'string', "id is a string despite being supplied and searched for as a number"); @@ -395,12 +390,12 @@ test("initial values of attributes can be passed in as the third argument to fin }); var store = createStore({ - person: Person, - adapter: adapter + adapter: adapter, + test: Person }); run(function() { - store.find('person', 1, { name: 'Test' }); + store.find('test', 1, { name: 'Test' }); }); }); @@ -614,16 +609,16 @@ test("store.scheduleFetchMany should not resolve until all the records are resol var store = createStore({ adapter: adapter, - person: Person, + test: Person, phone: Phone }); run(function() { - store.createRecord('person'); + store.createRecord('test'); }); var records = Ember.A([ - store.recordForId('person', 10), + store.recordForId('test', 10), store.recordForId('phone', 20), store.recordForId('phone', 21) ]); @@ -669,13 +664,13 @@ test("the store calls adapter.findMany according to groupings returned by adapte var store = createStore({ adapter: adapter, - person: Person + test: Person }); var records = Ember.A([ - store.recordForId('person', 10), - store.recordForId('person', 20), - store.recordForId('person', 21) + store.recordForId('test', 10), + store.recordForId('test', 20), + store.recordForId('test', 21) ]); run(function() { @@ -718,12 +713,12 @@ test("the promise returned by `scheduleFetch`, when it resolves, does not depend var store = createStore({ adapter: adapter, - person: Person + test: Person }); run(function () { - var davidPromise = store.find('person', 'david'); - var igorPromise = store.find('person', 'igor'); + var davidPromise = store.find('test', 'david'); + var igorPromise = store.find('test', 'igor'); igorPromise.then(async(function () { equal(davidResolved, false, "Igor did not need to wait for David"); @@ -767,12 +762,12 @@ test("the promise returned by `scheduleFetch`, when it rejects, does not depend var store = createStore({ adapter: adapter, - person: Person + test: Person }); run(function () { - var davidPromise = store.find('person', 'david'); - var igorPromise = store.find('person', 'igor'); + var davidPromise = store.find('test', 'david'); + var igorPromise = store.find('test', 'igor'); igorPromise.then(null, async(function () { equal(davidResolved, false, "Igor did not need to wait for David"); @@ -805,13 +800,13 @@ test("store.fetchRecord reject records that were not found, even when those requ var store = createStore({ adapter: adapter, - person: Person + test: Person }); warns(function() { run(function () { - var davidPromise = store.find('person', 'david'); - var igorPromise = store.find('person', 'igor'); + var davidPromise = store.find('test', 'david'); + var igorPromise = store.find('test', 'igor'); davidPromise.then(async(function () { ok(true, "David resolved"); diff --git a/packages/ember-data/tests/unit/store/get-by-id-test.js b/packages/ember-data/tests/unit/store/get-by-id-test.js new file mode 100644 index 00000000000..440101867a8 --- /dev/null +++ b/packages/ember-data/tests/unit/store/get-by-id-test.js @@ -0,0 +1,35 @@ +var env, store, Person; +var run = Ember.run; + +module("unit/store/getById - Store getById", { + setup: function() { + + Person = DS.Model.extend(); + Person.toString = function() { + return 'Person'; + }; + + env = setupStore({ + person: Person + }); + store = env.store; + }, + + teardown: function() { + Ember.run(store, 'destroy'); + } +}); + +test("getById should return the record if it is in the store ", function() { + + run(function() { + var person = store.push('person', { id: 1 }); + equal(person, store.getById('person', 1), 'getById only return the corresponding record in the store'); + }); +}); + +test("getById should return null if the record is not in the store ", function() { + run(function() { + equal(null, store.getById('person', 1), 'getById returns null if the corresponding record is not in the store'); + }); +}); diff --git a/packages/ember-data/tests/unit/store/unload-test.js b/packages/ember-data/tests/unit/store/unload-test.js index 96343773427..a3c95a2ff8b 100644 --- a/packages/ember-data/tests/unit/store/unload-test.js +++ b/packages/ember-data/tests/unit/store/unload-test.js @@ -36,7 +36,7 @@ test("unload a dirty record", function() { store.find('record', 1).then(function(record) { record.set('title', 'toto2'); - record.send('willCommit'); + record._internalModel.send('willCommit'); equal(get(record, 'isDirty'), true, "record is dirty"); @@ -46,7 +46,7 @@ test("unload a dirty record", function() { // force back into safe to unload mode. run(function() { - record.transitionTo('deleted.saved'); + record._internalModel.transitionTo('deleted.saved'); }); }); }); diff --git a/tests/ember-configuration.js b/tests/ember-configuration.js index 9c9faf4eb29..b0582a9eb85 100644 --- a/tests/ember-configuration.js +++ b/tests/ember-configuration.js @@ -65,7 +65,7 @@ } else { env.container.normalize = fn; } - } + }; var adapter = env.adapter = (options.adapter || DS.Adapter); delete options.adapter; diff --git a/tests/ember-data-setup.js b/tests/ember-data-setup.js index 7f57db55d0a..ce0686fb355 100644 --- a/tests/ember-data-setup.js +++ b/tests/ember-data-setup.js @@ -1,5 +1,3 @@ -/* globals syncForTest */ - ;(function(){ Ember.RSVP.configure('onerror', function(reason) { diff --git a/tests/index.html b/tests/index.html index e245e4d6f95..0a02c96ba86 100644 --- a/tests/index.html +++ b/tests/index.html @@ -44,9 +44,9 @@ diff --git a/tests/qunit-configuration.js b/tests/qunit-configuration.js index f0cfa53a705..fec07e42416 100644 --- a/tests/qunit-configuration.js +++ b/tests/qunit-configuration.js @@ -1,85 +1,87 @@ (function() { + /*global namespace: true */ + window.EmberDev = window.EmberDev || {}; EmberDev.afterEach = function() { - if (Ember && Ember.View) { - var viewIds = [], id; - for (id in Ember.View.views) { - if (Ember.View.views[id] != null) { - viewIds.push(id); - } + if (Ember && Ember.View) { + var viewIds = [], id; + for (id in Ember.View.views) { + if (Ember.View.views[id] != null) { + viewIds.push(id); } + } - if (viewIds.length > 0) { - deepEqual(viewIds, [], "Ember.View.views should be empty"); - Ember.View.views = []; - } + if (viewIds.length > 0) { + deepEqual(viewIds, [], "Ember.View.views should be empty"); + Ember.View.views = []; } + } - if (Ember && Ember.TEMPLATES) { - var templateNames = [], name; - for (name in Ember.TEMPLATES) { - if (Ember.TEMPLATES[name] != null) { - templateNames.push(name); - } + if (Ember && Ember.TEMPLATES) { + var templateNames = [], name; + for (name in Ember.TEMPLATES) { + if (Ember.TEMPLATES[name] != null) { + templateNames.push(name); } + } - if (templateNames.length > 0) { - deepEqual(templateNames, [], "Ember.TEMPLATES should be empty"); - Ember.TEMPLATES = {}; - } + if (templateNames.length > 0) { + deepEqual(templateNames, [], "Ember.TEMPLATES should be empty"); + Ember.TEMPLATES = {}; } - }; + } + }; - window.globalFailedTests = []; - window.globalTestResults = null; - window.lastAssertionTime = new Date().getTime(); + window.globalFailedTests = []; + window.globalTestResults = null; + window.lastAssertionTime = new Date().getTime(); - var currentTest, assertCount; + var currentTest, assertCount; - QUnit.testStart(function(data) { - // Reset the assertion count - assertCount = 0; + QUnit.testStart(function(data) { + // Reset the assertion count + assertCount = 0; - currentTest = { - name: data.name, - failedAssertions: [], - total: 0, - passed: 0, - failed: 0, - start: new Date(), - time: 0 - }; + currentTest = { + name: data.name, + failedAssertions: [], + total: 0, + passed: 0, + failed: 0, + start: new Date(), + time: 0 + }; - }) + }); - QUnit.log(function(data) { - assertCount++; - lastAssertionTime = new Date().getTime(); + QUnit.log(function(data) { + assertCount++; + lastAssertionTime = new Date().getTime(); - // Ignore passing assertions - if (!data.result) { - currentTest.failedAssertions.push(data); - } - }); + // Ignore passing assertions + if (!data.result) { + currentTest.failedAssertions.push(data); + } + }); - QUnit.testDone(function(data) { - currentTest.time = (new Date()).getTime() - currentTest.start.getTime(); // ms - currentTest.total = data.total; - currentTest.passed = data.passed; - currentTest.failed = data.failed; + QUnit.testDone(function(data) { + currentTest.time = (new Date()).getTime() - currentTest.start.getTime(); // ms + currentTest.total = data.total; + currentTest.passed = data.passed; + currentTest.failed = data.failed; - if (currentTest.failed > 0) - window.globalFailedTests.push(currentTest) + if (currentTest.failed > 0) + window.globalFailedTests.push(currentTest); - currentTest = null; - }); + currentTest = null; + }); - QUnit.done(function( details ) { - details.failedTests = globalFailedTests; + QUnit.done(function( details ) { + details.failedTests = globalFailedTests; - window.globalTestResults = details; - }); + window.globalTestResults = details; + }); // hack qunit to not suck for Ember objects var originalTypeof = QUnit.jsDump.typeOf; @@ -174,7 +176,7 @@ function MethodCallExpectation(target, property){ this.target = target; this.property = property; - }; + } MethodCallExpectation.prototype = { handleCall: function(){ @@ -208,7 +210,8 @@ function AssertExpectation(message){ MethodCallExpectation.call(this, Ember, 'assert'); this.expectedMessage = message; - }; + } + AssertExpectation.Error = function(){}; AssertExpectation.prototype = o_create(MethodCallExpectation.prototype); AssertExpectation.prototype.handleCall = function(message, test){ @@ -281,7 +284,7 @@ // Ember.deprecate("Old And Busted"); // window.expectNoDeprecation = function(message) { - if (typeof EmberDev.deprecations.expecteds === 'array') { + if (Ember.isArray(EmberDev.deprecations.expecteds)) { throw("No deprecation was expected after expectDeprecation was called!"); } EmberDev.deprecations.stubEmber(); @@ -344,15 +347,15 @@ if (expecteds === EmberDev.deprecations.NONE) { var actualMessages = []; - for (var actual in actuals) { - actualMessages.push(actual[0]); + for (var _actual in actuals) { + actualMessages.push(_actual[0]); } ok(actuals.length === 0, "Expected no deprecation call, got: "+actualMessages.join(', ')); } else { for (var o=0;o < expecteds.length; o++) { - var expected = expecteds[o], match; + var expected = expecteds[o], match, actual; for (var i=0;i < actuals.length; i++) { - var actual = actuals[i]; + actual = actuals[i]; if (!actual[1]) { if (expected instanceof RegExp) { if (expected.test(actual[0])) { From 50c4195b1d7fc5cdee9e2defeb6c945db53d05e3 Mon Sep 17 00:00:00 2001 From: yratanov Date: Tue, 2 Jun 2015 22:10:59 +0700 Subject: [PATCH 0831/2527] add Snapshot#serialize method * fixes #3144 use Snapshot#serialize in Store#serialize --- packages/ember-data/lib/system/snapshot.js | 9 +++++++++ packages/ember-data/lib/system/store.js | 2 +- .../ember-data/tests/integration/snapshot-test.js | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/snapshot.js b/packages/ember-data/lib/system/snapshot.js index 6dab199c066..fe099ac6324 100644 --- a/packages/ember-data/lib/system/snapshot.js +++ b/packages/ember-data/lib/system/snapshot.js @@ -393,6 +393,15 @@ Snapshot.prototype = { return get(this.record, keyName); }, + /** + @method serialize + @param {Object} options + @return {Object} an object whose values are primitive JSON values only + */ + serialize: function(options) { + return this.record.store.serializerFor(this.modelName).serialize(this, options); + }, + /** @method unknownProperty @param {String} keyName diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 6bb6895f638..2436cf02002 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -254,7 +254,7 @@ Store = Service.extend({ */ serialize: function(record, options) { var snapshot = record._internalModel.createSnapshot(); - return this.serializerFor(snapshot.modelName).serialize(snapshot, options); + return snapshot.serialize(options); }, /** diff --git a/packages/ember-data/tests/integration/snapshot-test.js b/packages/ember-data/tests/integration/snapshot-test.js index b00a58a850c..0fa3417be54 100644 --- a/packages/ember-data/tests/integration/snapshot-test.js +++ b/packages/ember-data/tests/integration/snapshot-test.js @@ -598,6 +598,20 @@ test("snapshot.get() proxies property to record unless identified as id, attribu }); }); +test("snapshot.serialize() serializes itself", function() { + expect(2); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); + + post.set('title', 'New Title'); + + deepEqual(snapshot.serialize(), { author: undefined, title: 'Hello World' }, 'shapshot serializes correctly'); + deepEqual(snapshot.serialize({ includeId: true }), { id: "1", author: undefined, title: 'Hello World' }, 'serialize takes options') + }); +}); + test('snapshot.typeKey is deprecated', function() { expect(1); From 23908d129e20903a184c0dbaacae516668c119fd Mon Sep 17 00:00:00 2001 From: yratanov Date: Wed, 3 Jun 2015 14:51:03 +0700 Subject: [PATCH 0832/2527] add tests for error conditions in snapshot methods * snapshot.attr() * snapshot.belongsTo() * snapshot.hasMany() --- .../tests/integration/snapshot-test.js | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/packages/ember-data/tests/integration/snapshot-test.js b/packages/ember-data/tests/integration/snapshot-test.js index b00a58a850c..0276b8092f9 100644 --- a/packages/ember-data/tests/integration/snapshot-test.js +++ b/packages/ember-data/tests/integration/snapshot-test.js @@ -99,6 +99,19 @@ test("snapshot.attr() does not change when record changes", function() { }); }); +test("snapshot.attr() throws an error attribute not found", function() { + expect(1); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); + + throws(function() { + snapshot.attr('unknown'); + }, /has no attribute named 'unknown' defined/, 'attr throws error'); + }); +}); + test("snapshot.attributes() returns a copy of all attributes for the current snapshot", function() { expect(1); @@ -194,6 +207,19 @@ test("snapshot.belongsTo() returns undefined if relationship is a link", functio }); }); +test("snapshot.belongsTo() throws error if relation doesn't exist", function() { + expect(1); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); + + throws(function() { + snapshot.belongsTo('unknown'); + }, /has no belongsTo relationship named 'unknown'/, 'throws error') + }); +}); + test("snapshot.belongsTo() returns a snapshot if relationship link has been fetched", function() { expect(2); @@ -420,6 +446,19 @@ test("snapshot.hasMany() returns array of snapshots if relationship link has bee }); }); +test("snapshot.hasMany() throws error if relation doesn't exist", function() { + expect(1); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); + + throws(function() { + snapshot.hasMany('unknown'); + }, /has no hasMany relationship named 'unknown'/, 'throws error') + }); +}); + test("snapshot.hasMany() respects the order of items in the relationship", function() { expect(3); From 4741717e3dd314222aeb3bc582372936ccc41bb5 Mon Sep 17 00:00:00 2001 From: yratanov Date: Wed, 3 Jun 2015 16:00:39 +0700 Subject: [PATCH 0833/2527] add missing tests for record arrays --- .../unit/adapter-populated-record-array-test.js | 9 +++++++++ .../record-arrays/filtered-record-array-test.js | 13 +++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 packages/ember-data/tests/unit/record-arrays/filtered-record-array-test.js diff --git a/packages/ember-data/tests/unit/adapter-populated-record-array-test.js b/packages/ember-data/tests/unit/adapter-populated-record-array-test.js index 9de3a89ea5b..0addd5933c4 100644 --- a/packages/ember-data/tests/unit/adapter-populated-record-array-test.js +++ b/packages/ember-data/tests/unit/adapter-populated-record-array-test.js @@ -40,3 +40,12 @@ test("when a record is deleted in an adapter populated record array, it should b equal(recordArray.get('length'), 2, "expected recordArray to contain exactly 2 records"); }); + +test('recordArray.replace() throws error', function() { + var recordArray = store.recordArrayManager + .createAdapterPopulatedRecordArray(Person, null); + + throws(function() { + recordArray.replace(); + }, Error("The result of a server query (on (subclass of DS.Model)) is immutable."), 'throws error') +}); diff --git a/packages/ember-data/tests/unit/record-arrays/filtered-record-array-test.js b/packages/ember-data/tests/unit/record-arrays/filtered-record-array-test.js new file mode 100644 index 00000000000..cd706d21c6b --- /dev/null +++ b/packages/ember-data/tests/unit/record-arrays/filtered-record-array-test.js @@ -0,0 +1,13 @@ +var filteredArray; + +module("unit/record-arrays/filtered-record-array - DS.FilteredRecordArray", { + setup: function() { + filteredArray = DS.FilteredRecordArray.create({ type: 'recordType' }) + } +}); + +test('recordArray.replace() throws error', function() { + throws(function() { + filteredArray.replace(); + }, Error("The result of a client-side filter (on recordType) is immutable."), 'throws error') +}); From 2a471f7799440479219b5f1a2762b17feba0f4c7 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 3 Jun 2015 11:12:57 +0200 Subject: [PATCH 0834/2527] Fix broken JSDoc references --- .../lib/adapters/build-url-mixin.js | 4 +-- .../lib/adapters/fixture-adapter.js | 8 ++--- .../lib/serializers/embedded-records-mixin.js | 2 +- .../lib/serializers/json-serializer.js | 8 ++--- .../lib/serializers/rest-serializer.js | 6 ++-- .../lib/system/normalize-model-name.js | 2 +- .../lib/system/record-arrays/record-array.js | 2 +- packages/ember-data/lib/system/snapshot.js | 2 +- packages/ember-data/lib/system/store.js | 34 +++++++++---------- 9 files changed, 33 insertions(+), 35 deletions(-) diff --git a/packages/ember-data/lib/adapters/build-url-mixin.js b/packages/ember-data/lib/adapters/build-url-mixin.js index 58316d9e9cc..77487674247 100644 --- a/packages/ember-data/lib/adapters/build-url-mixin.js +++ b/packages/ember-data/lib/adapters/build-url-mixin.js @@ -136,7 +136,7 @@ export default Ember.Mixin.create({ /** * @method urlForFindMany * @param {Array} ids - * @param {String} type + * @param {String} modelName * @param {Array} snapshots * @return {String} url */ @@ -200,7 +200,7 @@ export default Ember.Mixin.create({ @method urlPrefix @private @param {String} path - @param {String} parentUrl + @param {String} parentURL @return {String} urlPrefix */ urlPrefix: function(path, parentURL) { diff --git a/packages/ember-data/lib/adapters/fixture-adapter.js b/packages/ember-data/lib/adapters/fixture-adapter.js index 25e917c8404..459f7f959e2 100644 --- a/packages/ember-data/lib/adapters/fixture-adapter.js +++ b/packages/ember-data/lib/adapters/fixture-adapter.js @@ -82,7 +82,7 @@ export default Adapter.extend({ Implement this method in order to query fixtures data @method queryFixtures - @param {Array} fixture + @param {Array} fixtures @param {Object} query @param {Subclass of DS.Model} typeClass @return {Promise|Array} @@ -123,7 +123,6 @@ export default Adapter.extend({ /** @method generateIdForRecord @param {DS.Store} store - @param {DS.Model} record @return {String} id */ generateIdForRecord: function(store) { @@ -186,7 +185,6 @@ export default Adapter.extend({ @method findAll @param {DS.Store} store @param {subclass of DS.Model} typeClass - @param {String} sinceToken @return {Promise} promise */ findAll: function(store, typeClass) { @@ -205,7 +203,7 @@ export default Adapter.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} query - @param {DS.AdapterPopulatedRecordArray} recordArray + @param {DS.AdapterPopulatedRecordArray} array @return {Promise} promise */ findQuery: function(store, typeClass, query, array) { @@ -242,7 +240,7 @@ export default Adapter.extend({ /** @method updateRecord @param {DS.Store} store - @param {subclass of DS.Model} type + @param {subclass of DS.Model} typeClass @param {DS.Snapshot} snapshot @return {Promise} promise */ diff --git a/packages/ember-data/lib/serializers/embedded-records-mixin.js b/packages/ember-data/lib/serializers/embedded-records-mixin.js index f093f75ab98..dd2754e823f 100644 --- a/packages/ember-data/lib/serializers/embedded-records-mixin.js +++ b/packages/ember-data/lib/serializers/embedded-records-mixin.js @@ -115,7 +115,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ @method normalize @param {subclass of DS.Model} typeClass @param {Object} hash to be normalized - @param {String} key the hash has been referenced by + @param {String} prop the hash has been referenced by @return {Object} the normalized hash **/ normalize: function(typeClass, hash, prop) { diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index 7a03adaa7d4..e49b07890fd 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -758,7 +758,7 @@ export default Serializer.extend({ @method extractFindQuery @param {DS.Store} store - @param {subclass of DS.Model} type + @param {subclass of DS.Model} typeClass @param {Object} payload @param {String or Number} id @param {String} requestType @@ -888,7 +888,7 @@ export default Serializer.extend({ @method extractSave @param {DS.Store} store - @param {subclass of DS.Model} type + @param {subclass of DS.Model} typeClass @param {Object} payload @param {String or Number} id @param {String} requestType @@ -947,7 +947,7 @@ export default Serializer.extend({ @method extractArray @param {DS.Store} store @param {subclass of DS.Model} typeClass - @param {Object} payload + @param {Object} arrayPayload @param {String or Number} id @param {String} requestType @return {Array} array An array of deserialized objects @@ -1066,7 +1066,7 @@ export default Serializer.extend({ @method keyForRelationship @param {String} key - @param {String} relationship typeClass + @param {String} typeClass @param {String} method @return {String} normalized key */ diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index f6ae93de964..5540698039a 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -254,7 +254,7 @@ var RESTSerializer = JSONSerializer.extend({ @method extractSingle @param {DS.Store} store @param {subclass of DS.Model} primaryTypeClass - @param {Object} payload + @param {Object} rawPayload @param {String} recordId @return {Object} the primary response to the original request */ @@ -402,7 +402,7 @@ var RESTSerializer = JSONSerializer.extend({ @method extractArray @param {DS.Store} store @param {subclass of DS.Model} primaryTypeClass - @param {Object} payload + @param {Object} rawPayload @return {Array} The primary array that was returned in response to the original query. */ @@ -482,7 +482,7 @@ var RESTSerializer = JSONSerializer.extend({ @method pushPayload @param {DS.Store} store - @param {Object} payload + @param {Object} rawPayload */ pushPayload: function(store, rawPayload) { var payload = this.normalizePayload(rawPayload); diff --git a/packages/ember-data/lib/system/normalize-model-name.js b/packages/ember-data/lib/system/normalize-model-name.js index c836dddb8b8..813ef9b3727 100644 --- a/packages/ember-data/lib/system/normalize-model-name.js +++ b/packages/ember-data/lib/system/normalize-model-name.js @@ -3,7 +3,7 @@ require changes to other normalization hooks (such as typeForRoot). @method normalizeModelName @public - @param {String} type + @param {String} modelName @return {String} if the adapter can generate one, an ID @for DS */ diff --git a/packages/ember-data/lib/system/record-arrays/record-array.js b/packages/ember-data/lib/system/record-arrays/record-array.js index 24ee764eac0..1a1a8ccab0e 100644 --- a/packages/ember-data/lib/system/record-arrays/record-array.js +++ b/packages/ember-data/lib/system/record-arrays/record-array.js @@ -124,7 +124,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method addRecord @private @param {DS.Model} record - @param {DS.Model} an optional index to insert at + @param {DS.Model} idx an optional index to insert at */ addRecord: function(record, idx) { var content = get(this, 'content'); diff --git a/packages/ember-data/lib/system/snapshot.js b/packages/ember-data/lib/system/snapshot.js index 6dab199c066..423b7845d81 100644 --- a/packages/ember-data/lib/system/snapshot.js +++ b/packages/ember-data/lib/system/snapshot.js @@ -9,7 +9,7 @@ var get = Ember.get; @namespace DS @private @constructor - @param {DS.Model} record The record to create a snapshot from + @param {DS.Model} internalModel The model to create a snapshot from */ function Snapshot(internalModel) { this._attributes = Ember.create(null); diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 6bb6895f638..94037effdc3 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -309,7 +309,7 @@ Store = Service.extend({ @method createRecord @param {String} modelName - @param {Object} properties a hash of properties to set on the + @param {Object} inputProperties a hash of properties to set on the newly created record. @return {DS.Model} record */ @@ -653,7 +653,7 @@ Store = Service.extend({ @method fetchRecord @private - @param {InternalModel} internal model + @param {InternalModel} internalModel model @return {Promise} promise */ fetchRecord: function(internalModel) { @@ -831,7 +831,7 @@ Store = Service.extend({ @method reloadRecord @private - @param {DS.Model} record + @param {DS.Model} internalModel @return {Promise} promise */ reloadRecord: function(internalModel) { @@ -850,8 +850,8 @@ Store = Service.extend({ Returns true if a record for a given type and ID is already loaded. @method hasRecordForId - @param {String or subclass of DS.Model} type - @param {String|Integer} id + @param {String or subclass of DS.Model} modelName + @param {String|Integer} inputId @return {Boolean} */ hasRecordForId: function(modelName, inputId) { @@ -961,7 +961,7 @@ Store = Service.extend({ @method findQuery @private - @param {String or subclass of DS.Model} type + @param {String or subclass of DS.Model} typeName @param {any} query an opaque query to be used by the adapter @return {Promise} promise */ @@ -1070,7 +1070,7 @@ Store = Service.extend({ ``` @method unloadAll - @param {String} optional modelName + @param {String=} modelName */ unloadAll: function(modelName) { if (arguments.length === 0) { @@ -1242,7 +1242,7 @@ Store = Service.extend({ @method dataWasUpdated @private @param {Class} type - @param {InternalModel} internal model + @param {InternalModel} internalModel */ dataWasUpdated: function(type, internalModel) { this.recordArrayManager.recordDidChange(internalModel); @@ -1260,7 +1260,7 @@ Store = Service.extend({ @method scheduleSave @private - @param {InternalModel} internal model + @param {InternalModel} internalModel @param {Resolver} resolver */ scheduleSave: function(internalModel, resolver) { @@ -1313,7 +1313,7 @@ Store = Service.extend({ @method didSaveRecord @private - @param {InternalModel} internal model the in-flight internal model + @param {InternalModel} internalModel the in-flight internal model @param {Object} data optional data (see above) */ didSaveRecord: function(internalModel, data) { @@ -1335,7 +1335,7 @@ Store = Service.extend({ @method recordWasInvalid @private - @param {InternalModel} internal model + @param {InternalModel} internalModel @param {Object} errors */ recordWasInvalid: function(internalModel, errors) { @@ -1349,7 +1349,7 @@ Store = Service.extend({ @method recordWasError @private - @param {InternalModel} internal model + @param {InternalModel} internalModel */ recordWasError: function(internalModel) { internalModel.adapterDidError(); @@ -1362,7 +1362,7 @@ Store = Service.extend({ @method updateId @private - @param {InternalModel} internal model + @param {InternalModel} internalModel @param {Object} data */ updateId: function(internalModel, data) { @@ -1678,7 +1678,7 @@ Store = Service.extend({ @method pushPayload @param {String} type Optionally, a model used to determine which serializer will be used - @param {Object} payload + @param {Object} inputPayload */ pushPayload: function (type, inputPayload) { var serializer; @@ -1825,7 +1825,7 @@ Store = Service.extend({ @method _dematerializeRecord @private - @param {InternalModel} internal model + @param {InternalModel} internalModel */ _dematerializeRecord: function(internalModel) { var type = internalModel.type; @@ -1931,8 +1931,8 @@ Store = Service.extend({ @method retrieveManagedInstance @private - @param {String} type the object modelName - @param {String} type the object name + @param {String} modelName the object modelName + @param {String} name the object name @return {Ember.Object} */ retrieveManagedInstance: function(modelName, name) { From 9f2d8da1b137af246a6442ba443290c7b8d55ff9 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 3 Jun 2015 11:18:08 +0200 Subject: [PATCH 0835/2527] Remove "mixed" type annotation "mixed" is not a valid JSDoc type. It's better to not use any type annotation in this case. --- packages/ember-data/lib/transforms/base.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/transforms/base.js b/packages/ember-data/lib/transforms/base.js index 11019d80e39..e275f8d71d3 100644 --- a/packages/ember-data/lib/transforms/base.js +++ b/packages/ember-data/lib/transforms/base.js @@ -46,8 +46,8 @@ export default Ember.Object.extend({ ``` @method serialize - @param {mixed} deserialized The deserialized value - @return {mixed} The serialized value + @param deserialized The deserialized value + @return The serialized value */ serialize: null, @@ -64,8 +64,8 @@ export default Ember.Object.extend({ ``` @method deserialize - @param {mixed} serialized The serialized value - @return {mixed} The deserialized value + @param serialized The serialized value + @return The deserialized value */ deserialize: null }); From 545d973a12e25ace6b34e3b6c53cd0c73781b5cf Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 3 Jun 2015 11:20:14 +0200 Subject: [PATCH 0836/2527] Replace "String or Number" with valid JSDoc type annotation see http://usejsdoc.org/tags-type.html --- .../lib/serializers/json-serializer.js | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index e49b07890fd..54505281d18 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -724,7 +724,7 @@ export default Serializer.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} payload - @param {String or Number} id + @param {(String|Number)} id @param {String} requestType @return {Object} json The deserialized payload */ @@ -744,7 +744,7 @@ export default Serializer.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} payload - @param {String or Number} id + @param {(String|Number)} id @param {String} requestType @return {Array} array An array of deserialized objects */ @@ -760,7 +760,7 @@ export default Serializer.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} payload - @param {String or Number} id + @param {(String|Number)} id @param {String} requestType @return {Array} array An array of deserialized objects */ @@ -776,7 +776,7 @@ export default Serializer.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} payload - @param {String or Number} id + @param {(String|Number)} id @param {String} requestType @return {Array} array An array of deserialized objects */ @@ -792,7 +792,7 @@ export default Serializer.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} payload - @param {String or Number} id + @param {(String|Number)} id @param {String} requestType @return {Array} array An array of deserialized objects */ @@ -809,7 +809,7 @@ export default Serializer.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} payload - @param {String or Number} id + @param {(String|Number)} id @param {String} requestType @return {Object} json The deserialized payload */ @@ -825,7 +825,7 @@ export default Serializer.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} payload - @param {String or Number} id + @param {(String|Number)} id @param {String} requestType @return {Object} json The deserialized payload */ @@ -841,7 +841,7 @@ export default Serializer.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} payload - @param {String or Number} id + @param {(String|Number)} id @param {String} requestType @return {Object} json The deserialized payload */ @@ -858,7 +858,7 @@ export default Serializer.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} payload - @param {String or Number} id + @param {(String|Number)} id @param {String} requestType @return {Object} json The deserialized payload */ @@ -874,7 +874,7 @@ export default Serializer.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} payload - @param {String or Number} id + @param {(String|Number)} id @param {String} requestType @return {Object} json The deserialized payload */ @@ -890,7 +890,7 @@ export default Serializer.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} payload - @param {String or Number} id + @param {(String|Number)} id @param {String} requestType @return {Object} json The deserialized payload */ @@ -919,7 +919,7 @@ export default Serializer.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} payload - @param {String or Number} id + @param {(String|Number)} id @param {String} requestType @return {Object} json The deserialized payload */ @@ -948,7 +948,7 @@ export default Serializer.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} arrayPayload - @param {String or Number} id + @param {(String|Number)} id @param {String} requestType @return {Array} array An array of deserialized objects */ @@ -1015,7 +1015,7 @@ export default Serializer.extend({ @param {DS.Store} store @param {subclass of DS.Model} typeClass @param {Object} payload - @param {String or Number} id + @param {(String|Number)} id @return {Object} json The deserialized errors */ extractErrors: function(store, typeClass, payload, id) { From 07d59cd4413a04aa6f36007cf6a7d92ccda9a226 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 3 Jun 2015 11:29:32 +0200 Subject: [PATCH 0837/2527] Replace "subclass of DS.Model" with valid "DS.Model" type annotation --- .../lib/adapters/fixture-adapter.js | 22 +++++------ .../ember-data/lib/adapters/rest-adapter.js | 14 +++---- .../lib/serializers/embedded-records-mixin.js | 2 +- .../lib/serializers/json-serializer.js | 36 +++++++++--------- .../lib/serializers/rest-serializer.js | 8 ++-- packages/ember-data/lib/system/adapter.js | 16 ++++---- .../lib/system/record-array-manager.js | 8 ++-- .../lib/system/relationships/ext.js | 2 +- packages/ember-data/lib/system/serializer.js | 6 +-- packages/ember-data/lib/system/snapshot.js | 4 +- packages/ember-data/lib/system/store.js | 38 +++++++++---------- 11 files changed, 78 insertions(+), 78 deletions(-) diff --git a/packages/ember-data/lib/adapters/fixture-adapter.js b/packages/ember-data/lib/adapters/fixture-adapter.js index 459f7f959e2..b95165953a8 100644 --- a/packages/ember-data/lib/adapters/fixture-adapter.js +++ b/packages/ember-data/lib/adapters/fixture-adapter.js @@ -60,7 +60,7 @@ export default Adapter.extend({ Implement this method in order to provide data associated with a type @method fixturesForType - @param {Subclass of DS.Model} typeClass + @param {DS.Model} typeClass @return {Array} */ fixturesForType: function(typeClass) { @@ -84,7 +84,7 @@ export default Adapter.extend({ @method queryFixtures @param {Array} fixtures @param {Object} query - @param {Subclass of DS.Model} typeClass + @param {DS.Model} typeClass @return {Promise|Array} */ queryFixtures: function(fixtures, query, typeClass) { @@ -93,7 +93,7 @@ export default Adapter.extend({ /** @method updateFixtures - @param {Subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Array} fixture */ updateFixtures: function(typeClass, fixture) { @@ -113,7 +113,7 @@ export default Adapter.extend({ @method mockJSON @param {DS.Store} store - @param {Subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {DS.Snapshot} snapshot */ mockJSON: function(store, typeClass, snapshot) { @@ -132,7 +132,7 @@ export default Adapter.extend({ /** @method find @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {String} id @param {DS.Snapshot} snapshot @return {Promise} promise @@ -157,7 +157,7 @@ export default Adapter.extend({ /** @method findMany @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Array} ids @param {Array} snapshots @return {Promise} promise @@ -184,7 +184,7 @@ export default Adapter.extend({ @private @method findAll @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @return {Promise} promise */ findAll: function(store, typeClass) { @@ -201,7 +201,7 @@ export default Adapter.extend({ @private @method findQuery @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} query @param {DS.AdapterPopulatedRecordArray} array @return {Promise} promise @@ -223,7 +223,7 @@ export default Adapter.extend({ /** @method createRecord @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {DS.Snapshot} snapshot @return {Promise} promise */ @@ -240,7 +240,7 @@ export default Adapter.extend({ /** @method updateRecord @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {DS.Snapshot} snapshot @return {Promise} promise */ @@ -257,7 +257,7 @@ export default Adapter.extend({ /** @method deleteRecord @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {DS.Snapshot} snapshot @return {Promise} promise */ diff --git a/packages/ember-data/lib/adapters/rest-adapter.js b/packages/ember-data/lib/adapters/rest-adapter.js index f6ee3f00e11..85e4e074f1c 100644 --- a/packages/ember-data/lib/adapters/rest-adapter.js +++ b/packages/ember-data/lib/adapters/rest-adapter.js @@ -338,7 +338,7 @@ export default Adapter.extend(BuildURLMixin, { @method find @param {DS.Store} store - @param {subclass of DS.Model} type + @param {DS.Model} type @param {String} id @param {DS.Snapshot} snapshot @return {Promise} promise @@ -357,7 +357,7 @@ export default Adapter.extend(BuildURLMixin, { @private @method findAll @param {DS.Store} store - @param {subclass of DS.Model} type + @param {DS.Model} type @param {String} sinceToken @return {Promise} promise */ @@ -386,7 +386,7 @@ export default Adapter.extend(BuildURLMixin, { @private @method findQuery @param {DS.Store} store - @param {subclass of DS.Model} type + @param {DS.Model} type @param {Object} query @return {Promise} promise */ @@ -428,7 +428,7 @@ export default Adapter.extend(BuildURLMixin, { @method findMany @param {DS.Store} store - @param {subclass of DS.Model} type + @param {DS.Model} type @param {Array} ids @param {Array} snapshots @return {Promise} promise @@ -521,7 +521,7 @@ export default Adapter.extend(BuildURLMixin, { @method createRecord @param {DS.Store} store - @param {subclass of DS.Model} type + @param {DS.Model} type @param {DS.Snapshot} snapshot @return {Promise} promise */ @@ -547,7 +547,7 @@ export default Adapter.extend(BuildURLMixin, { @method updateRecord @param {DS.Store} store - @param {subclass of DS.Model} type + @param {DS.Model} type @param {DS.Snapshot} snapshot @return {Promise} promise */ @@ -570,7 +570,7 @@ export default Adapter.extend(BuildURLMixin, { @method deleteRecord @param {DS.Store} store - @param {subclass of DS.Model} type + @param {DS.Model} type @param {DS.Snapshot} snapshot @return {Promise} promise */ diff --git a/packages/ember-data/lib/serializers/embedded-records-mixin.js b/packages/ember-data/lib/serializers/embedded-records-mixin.js index dd2754e823f..8dd454b866b 100644 --- a/packages/ember-data/lib/serializers/embedded-records-mixin.js +++ b/packages/ember-data/lib/serializers/embedded-records-mixin.js @@ -113,7 +113,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ } ``` @method normalize - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} hash to be normalized @param {String} prop the hash has been referenced by @return {Object} the normalized hash diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index 54505281d18..690410c9f0a 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -109,7 +109,7 @@ export default Serializer.extend({ @method applyTransforms @private - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} data The data to transform @return {Object} data The transformed data object */ @@ -155,7 +155,7 @@ export default Serializer.extend({ ``` @method normalize - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} hash @return {Object} */ @@ -510,7 +510,7 @@ export default Serializer.extend({ @method serializeIntoHash @param {Object} hash - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {DS.Snapshot} snapshot @param {Object} options */ @@ -722,7 +722,7 @@ export default Serializer.extend({ @method extract @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload @param {(String|Number)} id @param {String} requestType @@ -742,7 +742,7 @@ export default Serializer.extend({ @method extractFindAll @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload @param {(String|Number)} id @param {String} requestType @@ -758,7 +758,7 @@ export default Serializer.extend({ @method extractFindQuery @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload @param {(String|Number)} id @param {String} requestType @@ -774,7 +774,7 @@ export default Serializer.extend({ @method extractFindMany @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload @param {(String|Number)} id @param {String} requestType @@ -790,7 +790,7 @@ export default Serializer.extend({ @method extractFindHasMany @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload @param {(String|Number)} id @param {String} requestType @@ -807,7 +807,7 @@ export default Serializer.extend({ @method extractCreateRecord @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload @param {(String|Number)} id @param {String} requestType @@ -823,7 +823,7 @@ export default Serializer.extend({ @method extractUpdateRecord @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload @param {(String|Number)} id @param {String} requestType @@ -839,7 +839,7 @@ export default Serializer.extend({ @method extractDeleteRecord @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload @param {(String|Number)} id @param {String} requestType @@ -856,7 +856,7 @@ export default Serializer.extend({ @method extractFind @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload @param {(String|Number)} id @param {String} requestType @@ -872,7 +872,7 @@ export default Serializer.extend({ @method extractFindBelongsTo @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload @param {(String|Number)} id @param {String} requestType @@ -888,7 +888,7 @@ export default Serializer.extend({ @method extractSave @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload @param {(String|Number)} id @param {String} requestType @@ -917,7 +917,7 @@ export default Serializer.extend({ @method extractSingle @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload @param {(String|Number)} id @param {String} requestType @@ -946,7 +946,7 @@ export default Serializer.extend({ @method extractArray @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} arrayPayload @param {(String|Number)} id @param {String} requestType @@ -981,7 +981,7 @@ export default Serializer.extend({ @method extractMeta @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload */ extractMeta: function(store, typeClass, payload) { @@ -1013,7 +1013,7 @@ export default Serializer.extend({ @method extractErrors @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload @param {(String|Number)} id @return {Object} json The deserialized errors diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index 5540698039a..5e47bf6f747 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -161,7 +161,7 @@ var RESTSerializer = JSONSerializer.extend({ payload. @method normalize - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} hash @param {String} prop @return {Object} @@ -253,7 +253,7 @@ var RESTSerializer = JSONSerializer.extend({ @method extractSingle @param {DS.Store} store - @param {subclass of DS.Model} primaryTypeClass + @param {DS.Model} primaryTypeClass @param {Object} rawPayload @param {String} recordId @return {Object} the primary response to the original request @@ -401,7 +401,7 @@ var RESTSerializer = JSONSerializer.extend({ @method extractArray @param {DS.Store} store - @param {subclass of DS.Model} primaryTypeClass + @param {DS.Model} primaryTypeClass @param {Object} rawPayload @return {Array} The primary array that was returned in response to the original query. @@ -734,7 +734,7 @@ var RESTSerializer = JSONSerializer.extend({ @method serializeIntoHash @param {Object} hash - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {DS.Snapshot} snapshot @param {Object} options */ diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 430338168c1..bfbd0a3155a 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -112,7 +112,7 @@ var Adapter = Ember.Object.extend({ @method find @param {DS.Store} store - @param {subclass of DS.Model} type + @param {DS.Model} type @param {String} id @param {DS.Snapshot} snapshot @return {Promise} promise @@ -145,7 +145,7 @@ var Adapter = Ember.Object.extend({ @private @method findAll @param {DS.Store} store - @param {subclass of DS.Model} type + @param {DS.Model} type @param {String} sinceToken @return {Promise} promise */ @@ -177,7 +177,7 @@ var Adapter = Ember.Object.extend({ @private @method findQuery @param {DS.Store} store - @param {subclass of DS.Model} type + @param {DS.Model} type @param {Object} query @param {DS.AdapterPopulatedRecordArray} recordArray @return {Promise} promise @@ -207,7 +207,7 @@ var Adapter = Ember.Object.extend({ @method generateIdForRecord @param {DS.Store} store - @param {subclass of DS.Model} type the DS.Model class of the record + @param {DS.Model} type the DS.Model class of the record @param {Object} inputProperties a hash of properties to set on the newly created record. @return {String|Number} id @@ -272,7 +272,7 @@ var Adapter = Ember.Object.extend({ @method createRecord @param {DS.Store} store - @param {subclass of DS.Model} type the DS.Model class of the record + @param {DS.Model} type the DS.Model class of the record @param {DS.Snapshot} snapshot @return {Promise} promise */ @@ -312,7 +312,7 @@ var Adapter = Ember.Object.extend({ @method updateRecord @param {DS.Store} store - @param {subclass of DS.Model} type the DS.Model class of the record + @param {DS.Model} type the DS.Model class of the record @param {DS.Snapshot} snapshot @return {Promise} promise */ @@ -352,7 +352,7 @@ var Adapter = Ember.Object.extend({ @method deleteRecord @param {DS.Store} store - @param {subclass of DS.Model} type the DS.Model class of the record + @param {DS.Model} type the DS.Model class of the record @param {DS.Snapshot} snapshot @return {Promise} promise */ @@ -374,7 +374,7 @@ var Adapter = Ember.Object.extend({ @method findMany @param {DS.Store} store - @param {subclass of DS.Model} type the DS.Model class of the records + @param {DS.Model} type the DS.Model class of the records @param {Array} ids @param {Array} snapshots @return {Promise} promise diff --git a/packages/ember-data/lib/system/record-array-manager.js b/packages/ember-data/lib/system/record-array-manager.js index 609e90c7275..169cc06e082 100644 --- a/packages/ember-data/lib/system/record-array-manager.js +++ b/packages/ember-data/lib/system/record-array-manager.js @@ -108,7 +108,7 @@ export default Ember.Object.extend({ @method updateRecordArray @param {DS.FilteredRecordArray} array @param {Function} filter - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Number|String} clientId */ updateRecordArray: function(array, filter, typeClass, record) { @@ -184,7 +184,7 @@ export default Ember.Object.extend({ Create a `DS.FilteredRecordArray` for a type and register it for updates. @method createFilteredRecordArray - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Function} filter @param {Object} query (optional @return {DS.FilteredRecordArray} @@ -208,7 +208,7 @@ export default Ember.Object.extend({ Create a `DS.AdapterPopulatedRecordArray` for a type with given query. @method createAdapterPopulatedRecordArray - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} query @return {DS.AdapterPopulatedRecordArray} */ @@ -234,7 +234,7 @@ export default Ember.Object.extend({ @method registerFilteredRecordArray @param {DS.RecordArray} array - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Function} filter */ registerFilteredRecordArray: function(array, typeClass, filter) { diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index a610e220203..7b8eadcfaa7 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -175,7 +175,7 @@ Model.reopenClass({ @method typeForRelationship @static @param {String} name the name of the relationship - @return {subclass of DS.Model} the type of the relationship, or undefined + @return {DS.Model} the type of the relationship, or undefined */ typeForRelationship: function(name) { var relationship = get(this, 'relationshipsByName').get(name); diff --git a/packages/ember-data/lib/system/serializer.js b/packages/ember-data/lib/system/serializer.js index 8f77e4d30dd..aff222c1de6 100644 --- a/packages/ember-data/lib/system/serializer.js +++ b/packages/ember-data/lib/system/serializer.js @@ -40,7 +40,7 @@ var Serializer = Ember.Object.extend({ @method extract @param {DS.Store} store - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} payload @param {String|Number} id @param {String} requestType @@ -58,7 +58,7 @@ var Serializer = Ember.Object.extend({ in the serialized object it builds. @method serialize - @param {subclass of DS.Model} record + @param {DS.Model} record @param {Object} [options] @return {Object} */ @@ -71,7 +71,7 @@ var Serializer = Ember.Object.extend({ payload. @method normalize - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @param {Object} hash @return {Object} */ diff --git a/packages/ember-data/lib/system/snapshot.js b/packages/ember-data/lib/system/snapshot.js index 423b7845d81..39f4f74b4f8 100644 --- a/packages/ember-data/lib/system/snapshot.js +++ b/packages/ember-data/lib/system/snapshot.js @@ -94,10 +94,10 @@ Snapshot.prototype = { record: null, /** - The type of the underlying record for this snapshot, as a subclass of DS.Model. + The type of the underlying record for this snapshot, as a DS.Model. @property type - @type {subclass of DS.Model} + @type {DS.Model} */ type: null, diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 94037effdc3..ab449a8d410 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -133,7 +133,7 @@ if (!Service) { // not yet have an externally generated id. // * +internalModel+ means a record internalModel object, which holds metadata about a // record, even if it has not yet been fully materialized. -// * +type+ means a subclass of DS.Model. +// * +type+ means a DS.Model. /** The store contains all of the data for records loaded from the server. @@ -810,7 +810,7 @@ Store = Service.extend({ ``` @method getById - @param {String or subclass of DS.Model} type + @param {String or DS.Model} type @param {String|Integer} id @return {DS.Model|null} record */ @@ -850,7 +850,7 @@ Store = Service.extend({ Returns true if a record for a given type and ID is already loaded. @method hasRecordForId - @param {String or subclass of DS.Model} modelName + @param {String or DS.Model} modelName @param {String|Integer} inputId @return {Boolean} */ @@ -919,7 +919,7 @@ Store = Service.extend({ @private @param {DS.Model} owner @param {any} link - @param {String or subclass of DS.Model} type + @param {String or DS.Model} type @return {Promise} promise */ findHasMany: function(owner, link, type) { @@ -961,7 +961,7 @@ Store = Service.extend({ @method findQuery @private - @param {String or subclass of DS.Model} typeName + @param {String or DS.Model} typeName @param {any} query an opaque query to be used by the adapter @return {Promise} promise */ @@ -1148,7 +1148,7 @@ Store = Service.extend({ ``` @method filter - @param {String or subclass of DS.Model} type + @param {String or DS.Model} type @param {Object} query optional query @param {Function} filter @return {DS.PromiseArray} @@ -1196,7 +1196,7 @@ Store = Service.extend({ ``` @method recordIsLoaded - @param {String or subclass of DS.Model} type + @param {String or DS.Model} type @param {string} id @return {boolean} */ @@ -1208,7 +1208,7 @@ Store = Service.extend({ This method returns the metadata for a specific type. @method metadataFor - @param {String or subclass of DS.Model} typeName + @param {String or DS.Model} typeName @return {object} */ metadataFor: function(typeName) { @@ -1220,7 +1220,7 @@ Store = Service.extend({ This method sets the metadata for a specific type. @method setMetadataFor - @param {String or subclass of DS.Model} typeName + @param {String or DS.Model} typeName @param {Object} metadata metadata to set @return {object} */ @@ -1381,7 +1381,7 @@ Store = Service.extend({ @method typeMapFor @private - @param {subclass of DS.Model} typeClass + @param {DS.Model} typeClass @return {Object} typeMap */ typeMapFor: function(typeClass) { @@ -1412,7 +1412,7 @@ Store = Service.extend({ @method _load @private - @param {String or subclass of DS.Model} type + @param {String or DS.Model} type @param {Object} data */ _load: function(type, data) { @@ -1465,8 +1465,8 @@ Store = Service.extend({ etc.) @method modelFor - @param {String or subclass of DS.Model} key - @return {subclass of DS.Model} + @param {String or DS.Model} key + @return {DS.Model} */ modelFor: function(key) { var factory; @@ -1579,7 +1579,7 @@ Store = Service.extend({ records, as well as to update existing records. @method push - @param {String or subclass of DS.Model} modelName + @param {String or DS.Model} modelName @param {Object} data @return {DS.Model} the record that was created or updated. @@ -1740,7 +1740,7 @@ Store = Service.extend({ call `push` repeatedly for you. @method pushMany - @param {String or subclass of DS.Model} type + @param {String or DS.Model} type @param {Array} datas @return {Array} */ @@ -1757,7 +1757,7 @@ Store = Service.extend({ /** @method metaForType - @param {String or subclass of DS.Model} typeName + @param {String or DS.Model} typeName @param {Object} metadata @deprecated Use [setMetadataFor](#method_setMetadataFor) instead */ @@ -1772,7 +1772,7 @@ Store = Service.extend({ @method buildRecord @private - @param {subclass of DS.Model} type + @param {DS.Model} type @param {String} id @param {Object} data @return {InternalModel} internal model @@ -1860,7 +1860,7 @@ Store = Service.extend({ @method adapterFor @private - @param {String or subclass of DS.Model} type + @param {String or DS.Model} type @return DS.Adapter */ adapterFor: function(type) { @@ -1899,7 +1899,7 @@ Store = Service.extend({ @method serializerFor @private - @param {String or subclass of DS.Model} type the record to serialize + @param {String or DS.Model} type the record to serialize @return {DS.Serializer} */ serializerFor: function(type) { From 58998147dba1003ebb10803007c03990231886a5 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 3 Jun 2015 11:30:52 +0200 Subject: [PATCH 0838/2527] Replace "String or DS.Model" with valid JSDoc type annotation see http://usejsdoc.org/tags-type.html --- packages/ember-data/lib/system/store.js | 30 ++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index ab449a8d410..85ae8684088 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -810,7 +810,7 @@ Store = Service.extend({ ``` @method getById - @param {String or DS.Model} type + @param {(String|DS.Model)} type @param {String|Integer} id @return {DS.Model|null} record */ @@ -850,7 +850,7 @@ Store = Service.extend({ Returns true if a record for a given type and ID is already loaded. @method hasRecordForId - @param {String or DS.Model} modelName + @param {(String|DS.Model)} modelName @param {String|Integer} inputId @return {Boolean} */ @@ -919,7 +919,7 @@ Store = Service.extend({ @private @param {DS.Model} owner @param {any} link - @param {String or DS.Model} type + @param {(String|DS.Model)} type @return {Promise} promise */ findHasMany: function(owner, link, type) { @@ -961,7 +961,7 @@ Store = Service.extend({ @method findQuery @private - @param {String or DS.Model} typeName + @param {(String|DS.Model)} typeName @param {any} query an opaque query to be used by the adapter @return {Promise} promise */ @@ -1148,7 +1148,7 @@ Store = Service.extend({ ``` @method filter - @param {String or DS.Model} type + @param {(String|DS.Model)} type @param {Object} query optional query @param {Function} filter @return {DS.PromiseArray} @@ -1196,7 +1196,7 @@ Store = Service.extend({ ``` @method recordIsLoaded - @param {String or DS.Model} type + @param {(String|DS.Model)} type @param {string} id @return {boolean} */ @@ -1208,7 +1208,7 @@ Store = Service.extend({ This method returns the metadata for a specific type. @method metadataFor - @param {String or DS.Model} typeName + @param {(String|DS.Model)} typeName @return {object} */ metadataFor: function(typeName) { @@ -1220,7 +1220,7 @@ Store = Service.extend({ This method sets the metadata for a specific type. @method setMetadataFor - @param {String or DS.Model} typeName + @param {(String|DS.Model)} typeName @param {Object} metadata metadata to set @return {object} */ @@ -1412,7 +1412,7 @@ Store = Service.extend({ @method _load @private - @param {String or DS.Model} type + @param {(String|DS.Model)} type @param {Object} data */ _load: function(type, data) { @@ -1465,7 +1465,7 @@ Store = Service.extend({ etc.) @method modelFor - @param {String or DS.Model} key + @param {(String|DS.Model)} key @return {DS.Model} */ modelFor: function(key) { @@ -1579,7 +1579,7 @@ Store = Service.extend({ records, as well as to update existing records. @method push - @param {String or DS.Model} modelName + @param {(String|DS.Model)} modelName @param {Object} data @return {DS.Model} the record that was created or updated. @@ -1740,7 +1740,7 @@ Store = Service.extend({ call `push` repeatedly for you. @method pushMany - @param {String or DS.Model} type + @param {(String|DS.Model)} type @param {Array} datas @return {Array} */ @@ -1757,7 +1757,7 @@ Store = Service.extend({ /** @method metaForType - @param {String or DS.Model} typeName + @param {(String|DS.Model)} typeName @param {Object} metadata @deprecated Use [setMetadataFor](#method_setMetadataFor) instead */ @@ -1860,7 +1860,7 @@ Store = Service.extend({ @method adapterFor @private - @param {String or DS.Model} type + @param {(String|DS.Model)} type @return DS.Adapter */ adapterFor: function(type) { @@ -1899,7 +1899,7 @@ Store = Service.extend({ @method serializerFor @private - @param {String or DS.Model} type the record to serialize + @param {(String|DS.Model)} type the record to serialize @return {DS.Serializer} */ serializerFor: function(type) { From c1e65285c8b73d966e0f8ad8f3188f719b08c10d Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 3 Jun 2015 11:34:27 +0200 Subject: [PATCH 0839/2527] Wrap JSDoc type unions in parantheses --- .../ember-data/lib/adapters/build-url-mixin.js | 4 ++-- .../ember-data/lib/adapters/fixture-adapter.js | 2 +- packages/ember-data/lib/system/adapter.js | 2 +- packages/ember-data/lib/system/model/errors.js | 2 +- .../lib/system/record-array-manager.js | 2 +- packages/ember-data/lib/system/serializer.js | 2 +- packages/ember-data/lib/system/snapshot.js | 4 ++-- packages/ember-data/lib/system/store.js | 18 +++++++++--------- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/ember-data/lib/adapters/build-url-mixin.js b/packages/ember-data/lib/adapters/build-url-mixin.js index 77487674247..c8f556617b1 100644 --- a/packages/ember-data/lib/adapters/build-url-mixin.js +++ b/packages/ember-data/lib/adapters/build-url-mixin.js @@ -43,8 +43,8 @@ export default Ember.Mixin.create({ @method buildURL @param {String} modelName - @param {String|Array|Object} id single id or array of ids or query - @param {DS.Snapshot|Array} snapshot single snapshot or array of snapshots + @param {(String|Array|Object)} id single id or array of ids or query + @param {(DS.Snapshot|Array)} snapshot single snapshot or array of snapshots @param {String} requestType @param {Object} query object of query parameters to send for findQuery requests. @return {String} url diff --git a/packages/ember-data/lib/adapters/fixture-adapter.js b/packages/ember-data/lib/adapters/fixture-adapter.js index b95165953a8..805c86f284c 100644 --- a/packages/ember-data/lib/adapters/fixture-adapter.js +++ b/packages/ember-data/lib/adapters/fixture-adapter.js @@ -85,7 +85,7 @@ export default Adapter.extend({ @param {Array} fixtures @param {Object} query @param {DS.Model} typeClass - @return {Promise|Array} + @return {(Promise|Array)} */ queryFixtures: function(fixtures, query, typeClass) { Ember.assert('Not implemented: You must override the DS.FixtureAdapter::queryFixtures method to support querying the fixture store.'); diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index bfbd0a3155a..cc9295ca0f9 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -210,7 +210,7 @@ var Adapter = Ember.Object.extend({ @param {DS.Model} type the DS.Model class of the record @param {Object} inputProperties a hash of properties to set on the newly created record. - @return {String|Number} id + @return {(String|Number)} id */ generateIdForRecord: null, diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index 458e1443f2c..6cbb3c11f78 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -225,7 +225,7 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { @method add @param {String} attribute - @param {Array|String} messages + @param {(Array|String)} messages */ add: function(attribute, messages) { var wasEmpty = get(this, 'isEmpty'); diff --git a/packages/ember-data/lib/system/record-array-manager.js b/packages/ember-data/lib/system/record-array-manager.js index 169cc06e082..4c768781f03 100644 --- a/packages/ember-data/lib/system/record-array-manager.js +++ b/packages/ember-data/lib/system/record-array-manager.js @@ -109,7 +109,7 @@ export default Ember.Object.extend({ @param {DS.FilteredRecordArray} array @param {Function} filter @param {DS.Model} typeClass - @param {Number|String} clientId + @param {(Number|String)} clientId */ updateRecordArray: function(array, filter, typeClass, record) { var shouldBeInArray; diff --git a/packages/ember-data/lib/system/serializer.js b/packages/ember-data/lib/system/serializer.js index aff222c1de6..cd78055fc52 100644 --- a/packages/ember-data/lib/system/serializer.js +++ b/packages/ember-data/lib/system/serializer.js @@ -42,7 +42,7 @@ var Serializer = Ember.Object.extend({ @param {DS.Store} store @param {DS.Model} typeClass @param {Object} payload - @param {String|Number} id + @param {(String|Number)} id @param {String} requestType @return {Object} */ diff --git a/packages/ember-data/lib/system/snapshot.js b/packages/ember-data/lib/system/snapshot.js index 39f4f74b4f8..ab5346a17dd 100644 --- a/packages/ember-data/lib/system/snapshot.js +++ b/packages/ember-data/lib/system/snapshot.js @@ -206,7 +206,7 @@ Snapshot.prototype = { @method belongsTo @param {String} keyName @param {Object} [options] - @return {DS.Snapshot|String|null|undefined} A snapshot or ID of a known + @return {(DS.Snapshot|String|null|undefined)} A snapshot or ID of a known relationship or null if the relationship is known but unset. undefined will be returned if the contents of the relationship is unknown. */ @@ -277,7 +277,7 @@ Snapshot.prototype = { @method hasMany @param {String} keyName @param {Object} [options] - @return {Array|undefined} An array of snapshots or IDs of a known + @return {(Array|undefined)} An array of snapshots or IDs of a known relationship or an empty array if the relationship is known but unset. undefined will be returned if the contents of the relationship is unknown. */ diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 85ae8684088..eed8dd4000f 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -234,7 +234,7 @@ Store = Service.extend({ @property adapter @default DS.RESTAdapter - @type {DS.Adapter|String} + @type {(DS.Adapter|String)} */ adapter: '-rest', @@ -514,7 +514,7 @@ Store = Service.extend({ @method find @param {String} modelName - @param {Object|String|Integer|null} id + @param {(Object|String|Integer|null)} id @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models @return {Promise} promise */ @@ -556,7 +556,7 @@ Store = Service.extend({ @method fetchById @param {String} modelName - @param {String|Integer} id + @param {(String|Integer)} id @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models @return {Promise} promise */ @@ -585,7 +585,7 @@ Store = Service.extend({ /** @method fetch @param {String} modelName - @param {String|Integer} id + @param {(String|Integer)} id @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models @return {Promise} promise @deprecated Use [fetchById](#method_fetchById) instead @@ -601,7 +601,7 @@ Store = Service.extend({ @method findById @private @param {String} modelName - @param {String|Integer} id + @param {(String|Integer)} id @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models @return {Promise} promise */ @@ -811,8 +811,8 @@ Store = Service.extend({ @method getById @param {(String|DS.Model)} type - @param {String|Integer} id - @return {DS.Model|null} record + @param {(String|Integer)} id + @return {(DS.Model|null)} record */ getById: function(type, id) { if (this.hasRecordForId(type, id)) { @@ -851,7 +851,7 @@ Store = Service.extend({ @method hasRecordForId @param {(String|DS.Model)} modelName - @param {String|Integer} inputId + @param {(String|Integer)} inputId @return {Boolean} */ hasRecordForId: function(modelName, inputId) { @@ -868,7 +868,7 @@ Store = Service.extend({ @method recordForId @private @param {String} modelName - @param {String|Integer} id + @param {(String|Integer)} id @return {DS.Model} record */ recordForId: function(modelName, id) { From 2246cfd500a9ef7e3935f2de95de2d709c6a30f7 Mon Sep 17 00:00:00 2001 From: yratanov Date: Wed, 3 Jun 2015 16:55:16 +0700 Subject: [PATCH 0840/2527] add missing tests DS.Model * eachRelatedType() * relationshipNames --- .../tests/unit/model/relationships-test.js | 47 +++++++++++++------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/packages/ember-data/tests/unit/model/relationships-test.js b/packages/ember-data/tests/unit/model/relationships-test.js index f110aefd703..6555d7a23a0 100644 --- a/packages/ember-data/tests/unit/model/relationships-test.js +++ b/packages/ember-data/tests/unit/model/relationships-test.js @@ -1,24 +1,28 @@ var get = Ember.get; +var set = Ember.set; var run = Ember.run; +var Occupation, Person, store; -module("unit/model/relationships - DS.Model"); +module("unit/model/relationships - DS.Model", { + setup: function() { + Occupation = DS.Model.extend(); -test("exposes a hash of the relationships on a model", function() { - var Occupation = DS.Model.extend(); + Person = DS.Model.extend({ + occupations: DS.hasMany('occupation'), + people: DS.hasMany('person', { inverse: 'parent' }), + parent: DS.belongsTo('person', { inverse: 'people' }) + }); - var Person = DS.Model.extend({ - occupations: DS.hasMany('occupation') - }); + store = createStore({ + occupation: Occupation, + person: Person + }); - Person.reopen({ - people: DS.hasMany('person', { inverse: 'parent' }), - parent: DS.belongsTo('person', { inverse: 'people' }) - }); + set(Person, 'store', store); + } +}); - var store = createStore({ - occupation: Occupation, - person: Person - }); +test("exposes a hash of the relationships on a model", function() { var person, occupation; run(function() { @@ -35,3 +39,18 @@ test("exposes a hash of the relationships on a model", function() { { name: "occupations", kind: "hasMany" } ]); }); + +test("relationshipNames a hash of the relationships on a model with type as a key", function() { + deepEqual(get(Person, 'relationshipNames'), + { hasMany: ['occupations', 'people'], belongsTo: ["parent"] }); +}); + +test("eachRelatedType() iterates over relations without duplication", function() { + var relations = []; + + Person.eachRelatedType(function(typeClass) { + relations.push(typeClass.modelName); + }); + + deepEqual(relations, ['occupation', 'person']); +}); From f2a5c7304255d1edbdaff5433dc35dce9117c761 Mon Sep 17 00:00:00 2001 From: Mikhail Topolskiy Date: Wed, 3 Jun 2015 01:45:48 +0300 Subject: [PATCH 0841/2527] Add a test for DS.Adapter#serialize --- .../integration/adapter/serialize-test.js | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 packages/ember-data/tests/integration/adapter/serialize-test.js diff --git a/packages/ember-data/tests/integration/adapter/serialize-test.js b/packages/ember-data/tests/integration/adapter/serialize-test.js new file mode 100644 index 00000000000..889993f5c69 --- /dev/null +++ b/packages/ember-data/tests/integration/adapter/serialize-test.js @@ -0,0 +1,32 @@ +var run = Ember.run; +var env, store, adapter, serializer; + +module("integration/adapter/serialize - DS.Adapter integration test", { + setup: function() { + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + env = setupStore({ person: Person }); + store = env.store; + adapter = env.adapter; + serializer = store.serializerFor('person'); + }, + + teardown: function() { + run(env.container, 'destroy'); + } +}); + +test("serialize() is delegated to the serializer", function() { + expect(1); + + serializer.serialize = function(snapshot, options) { + deepEqual(options, { foo: 'bar' }); + }; + + run(function() { + var person = store.createRecord('person'); + adapter.serialize(person._createSnapshot(), { foo: 'bar' }); + }); +}); From 2c425d498e4a22568e13a8c1ca2a259bbf4c56d9 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 3 Jun 2015 13:12:54 +0200 Subject: [PATCH 0842/2527] system/model/attributes: Fix JSDoc annotations for "binding" parameters --- packages/ember-data/lib/system/model/attributes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index a92615da32f..fcbd7ce8006 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -144,7 +144,7 @@ Model.reopenClass({ @method eachAttribute @param {Function} callback The callback to execute - @param {Object} [target] The target object to use + @param {Object} [binding] the value to which the callback's `this` should be bound @static */ eachAttribute: function(callback, binding) { @@ -192,7 +192,7 @@ Model.reopenClass({ @method eachTransformedAttribute @param {Function} callback The callback to execute - @param {Object} [target] The target object to use + @param {Object} [binding] the value to which the callback's `this` should be bound @static */ eachTransformedAttribute: function(callback, binding) { From 998dae31fb4415302b2941b23437dca8432dfe93 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 3 Jun 2015 13:20:11 +0200 Subject: [PATCH 0843/2527] system/record-array-manager: Fix JSDoc annotation for updateRecordArray() --- packages/ember-data/lib/system/record-array-manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/record-array-manager.js b/packages/ember-data/lib/system/record-array-manager.js index 4c768781f03..2ff49e2f03b 100644 --- a/packages/ember-data/lib/system/record-array-manager.js +++ b/packages/ember-data/lib/system/record-array-manager.js @@ -109,7 +109,7 @@ export default Ember.Object.extend({ @param {DS.FilteredRecordArray} array @param {Function} filter @param {DS.Model} typeClass - @param {(Number|String)} clientId + @param {InternalModel} record */ updateRecordArray: function(array, filter, typeClass, record) { var shouldBeInArray; From 1db6615623e064a94e46ab4dc00cdcee3b580dcc Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 3 Jun 2015 13:28:28 +0200 Subject: [PATCH 0844/2527] system/model: Add missing "name" parameter to trigger() method The JSDoc declared the parameter but it was missing from the method definition --- packages/ember-data/lib/system/model/model.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 3259db1b786..e2a15d04e48 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -703,10 +703,9 @@ var Model = Ember.Object.extend(Ember.Evented, { @private @param {String} name */ - trigger: function() { + trigger: function(name) { var length = arguments.length; var args = new Array(length - 1); - var name = arguments[0]; for (var i = 1; i < length; i++) { args[i - 1] = arguments[i]; From e90e2f7b179cc22e1a57b6c6fafaa5b3c917a713 Mon Sep 17 00:00:00 2001 From: yratanov Date: Wed, 3 Jun 2015 19:36:59 +0700 Subject: [PATCH 0845/2527] add tests for restAdapter#ajaxOptions method * rename adapters/rest-adapter/ajax to ajax-test. QUnit didn't run this file before. * fixes #3151 --- .../unit/adapters/rest-adapter/ajax-test.js | 104 ++++++++++++++++++ .../tests/unit/adapters/rest-adapter/ajax.js | 44 -------- 2 files changed, 104 insertions(+), 44 deletions(-) create mode 100644 packages/ember-data/tests/unit/adapters/rest-adapter/ajax-test.js delete mode 100644 packages/ember-data/tests/unit/adapters/rest-adapter/ajax.js diff --git a/packages/ember-data/tests/unit/adapters/rest-adapter/ajax-test.js b/packages/ember-data/tests/unit/adapters/rest-adapter/ajax-test.js new file mode 100644 index 00000000000..78d83a2a1a7 --- /dev/null +++ b/packages/ember-data/tests/unit/adapters/rest-adapter/ajax-test.js @@ -0,0 +1,104 @@ +var Person, Place, store, adapter, env; +var run = Ember.run; + +module("unit/adapters/rest-adapter/ajax - building requests", { + setup: function() { + Person = { modelName: 'person' }; + Place = { modelName: 'place' }; + env = setupStore({ adapter: DS.RESTAdapter, person: Person, place: Place }); + store = env.store; + adapter = env.adapter; + }, + + teardown: function() { + run(function() { + store.destroy(); + env.container.destroy(); + }); + } +}); + +test("When an id is searched, the correct url should be generated", function() { + expect(2); + var count = 0; + adapter.ajax = function(url, method) { + if (count === 0) { equal(url, '/people/1', "should create the correct url"); } + if (count === 1) { equal(url, '/places/1', "should create the correct url"); } + count++; + return Ember.RSVP.resolve(); + }; + run(function() { + adapter.find(store, Person, 1); + adapter.find(store, Place, 1); + }); +}); + +test("id's should be sanatized", function() { + expect(1); + adapter.ajax = function(url, method) { + equal(url, '/people/..%2Fplace%2F1', "should create the correct url"); + return Ember.RSVP.resolve(); + }; + run(function() { + adapter.find(store, Person, '../place/1'); + }); +}); + +test("ajaxOptions() headers are set", function() { + adapter.headers = { 'Content-Type': 'application/json', 'Other-key': 'Other Value' }; + var url = 'example.com'; + var type = 'GET'; + var ajaxOptions = adapter.ajaxOptions(url, type, {}); + var receivedHeaders = []; + var fakeXHR = { + setRequestHeader: function(key, value) { + receivedHeaders.push([key, value]) + } + }; + ajaxOptions.beforeSend(fakeXHR); + deepEqual(receivedHeaders, [['Content-Type', 'application/json'], ['Other-key', 'Other Value']], 'headers assigned'); +}); + +test("ajaxOptions() do not serializes data when GET", function() { + var url = 'example.com'; + var type = 'GET'; + var ajaxOptions = adapter.ajaxOptions(url, type, { data: { key: 'value' } }); + + deepEqual(ajaxOptions, { + context: adapter, + data: { + key: 'value' + }, + dataType: 'json', + type: 'GET', + url: 'example.com' + }); +}); + +test("ajaxOptions() serializes data when not GET", function() { + var url = 'example.com'; + var type = 'POST'; + var ajaxOptions = adapter.ajaxOptions(url, type, { data: { key: 'value' } }); + + deepEqual(ajaxOptions, { + contentType: "application/json; charset=utf-8", + context: adapter, + data: '{"key":"value"}', + dataType: 'json', + type: 'POST', + url: 'example.com' + }); +}); + +test("ajaxOptions() empty data", function() { + var url = 'example.com'; + var type = 'POST'; + var ajaxOptions = adapter.ajaxOptions(url, type, {}); + + deepEqual(ajaxOptions, { + context: adapter, + dataType: 'json', + type: 'POST', + url: 'example.com' + }); +}); diff --git a/packages/ember-data/tests/unit/adapters/rest-adapter/ajax.js b/packages/ember-data/tests/unit/adapters/rest-adapter/ajax.js deleted file mode 100644 index 83a11297ec1..00000000000 --- a/packages/ember-data/tests/unit/adapters/rest-adapter/ajax.js +++ /dev/null @@ -1,44 +0,0 @@ -var Person, Place, store, adapter, env; -var run = Ember.run; - -module("integration/adapter/ajax - building requests", { - setup: function() { - Person = { modelName: 'person' }; - Place = { modelName: 'place' }; - env = setupStore({ adapter: DS.RESTAdapter, person: Person, place: Place }); - store = env.store; - adapter = env.adapter; - }, - - teardown: function() { - run(function() { - store.destroy(); - env.container.destroy(); - }); - } -}); - -test("When an id is searched, the correct url should be generated", function() { - expect(2); - var count = 0; - adapter.ajax = function(url, method) { - if (count === 0) { equal(url, '/people/1', "should create the correct url"); } - if (count === 1) { equal(url, '/places/1', "should create the correct url"); } - count++; - return Ember.RSVP.resolve(); - }; - run(function() { - adapter.find(store, Person, 1); - adapter.find(store, Place, 1); - }); -}); -test("id's should be sanatized", function() { - expect(1); - adapter.ajax= function(url, method) { - equal(url, '/people/..%2Fplace%2F1', "should create the correct url"); - return Ember.RSVP.resolve(); - }; - run(function() { - adapter.find(store, Person, '../place/1'); - }); -}); From 946115840748b1af867dcc681d7536f4df89e262 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 3 Jun 2015 10:46:55 -0400 Subject: [PATCH 0846/2527] initialize lives on the application instance not the Ember namespace --- packages/ember-data/lib/ember-initializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/ember-initializer.js b/packages/ember-data/lib/ember-initializer.js index f102f729df3..f5782a05614 100644 --- a/packages/ember-data/lib/ember-initializer.js +++ b/packages/ember-data/lib/ember-initializer.js @@ -53,7 +53,7 @@ Ember.onLoad('Ember.Application', function(Application) { initialize: initializeStoreService }); } else { - Ember.initializer({ + Application.initializer({ name: "ember-data-store-service", after: "ember-data", initialize: initializeStoreService From 11f66261a88fb22fe12d6bed2f88780461b08961 Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Wed, 3 Jun 2015 00:53:41 +0200 Subject: [PATCH 0847/2527] rename add/removeRecord to add/removeInternalModel in record array --- .../lib/system/record-array-manager.js | 6 ++--- .../lib/system/record-arrays/record-array.js | 26 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/ember-data/lib/system/record-array-manager.js b/packages/ember-data/lib/system/record-array-manager.js index 2ff49e2f03b..897838645a2 100644 --- a/packages/ember-data/lib/system/record-array-manager.js +++ b/packages/ember-data/lib/system/record-array-manager.js @@ -70,7 +70,7 @@ export default Ember.Object.extend({ if (!recordArrays) { return; } recordArrays.forEach(function(array) { - array.removeRecord(record); + array.removeInternalModel(record); }); record._recordArrays = null; @@ -124,12 +124,12 @@ export default Ember.Object.extend({ if (shouldBeInArray) { if (!recordArrays.has(array)) { - array.addRecord(record); + array.addInternalModel(record); recordArrays.add(array); } } else if (!shouldBeInArray) { recordArrays.delete(array); - array.removeRecord(record); + array.removeInternalModel(record); } }, diff --git a/packages/ember-data/lib/system/record-arrays/record-array.js b/packages/ember-data/lib/system/record-arrays/record-array.js index 1a1a8ccab0e..e0c37dbf734 100644 --- a/packages/ember-data/lib/system/record-arrays/record-array.js +++ b/packages/ember-data/lib/system/record-arrays/record-array.js @@ -119,31 +119,31 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { }, /** - Adds a record to the `RecordArray` without duplicates + Adds an internal model to the `RecordArray` without duplicates - @method addRecord + @method addInternalModel @private - @param {DS.Model} record - @param {DS.Model} idx an optional index to insert at + @param {InternalModel} internalModel + @param {number} an optional index to insert at */ - addRecord: function(record, idx) { + addInternalModel: function(internalModel, idx) { var content = get(this, 'content'); if (idx === undefined) { - content.addObject(record); - } else if (!content.contains(record)) { - content.insertAt(idx, record); + content.addObject(internalModel); + } else if (!content.contains(internalModel)) { + content.insertAt(idx, internalModel); } }, /** - Removes a record to the `RecordArray`. + Removes an internalModel to the `RecordArray`. - @method removeRecord + @method removeInternalModel @private - @param {DS.Model} record + @param {InternalModel} internalModel */ - removeRecord: function(record) { - get(this, 'content').removeObject(record); + removeInternalModel: function(internalModel) { + get(this, 'content').removeObject(internalModel); }, /** From 1371034ea1d08562c2f4de6f4f073045d866db7a Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 3 Jun 2015 11:00:24 -0500 Subject: [PATCH 0848/2527] stop rebuilding production after successful test runs The production build is already built at the start of the build due to the `prepublish` hooks that runs after `npm install`. --- .travis.yml | 4 ++-- package.json | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e36b3fef12f..74e0f5c9526 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,8 +16,8 @@ script: - npm run-script test:beta - npm run-script test:canary after_success: -- npm run-script publish-build -- "./bin/bower-ember-data-build" + - npm run-script publish-build:prebuilt + - "./bin/bower-ember-data-build" env: global: - BROCCOLI_ENV="production" diff --git a/package.json b/package.json index 4ac7770ab30..24b6d5c440c 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "start": "ember serve", "test": "jscs packages && testem -R dot ci", "publish-build": "npm run build:production && ./bin/publish-to-s3.js", + "publish-build:prebuilt": "./bin/publish-to-s3.js", "test:local": "testem -R dot ci", "test:beta": "testem -f config/testem-beta.json -R dot ci", "test:canary": "testem -f config/testem-canary.json -R dot ci", From b61576539d0b293a0e5d4420441aa03ade69bae1 Mon Sep 17 00:00:00 2001 From: Sylvain MINA Date: Wed, 3 Jun 2015 16:58:42 +0200 Subject: [PATCH 0849/2527] fix belongs-to when set with a resolved promise --- .../system/relationships/state/belongs-to.js | 4 +-- .../relationships/belongs-to-test.js | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/state/belongs-to.js b/packages/ember-data/lib/system/relationships/state/belongs-to.js index a4a30a894ff..d47c76ab32f 100644 --- a/packages/ember-data/lib/system/relationships/state/belongs-to.js +++ b/packages/ember-data/lib/system/relationships/state/belongs-to.js @@ -86,7 +86,7 @@ BelongsToRelationship.prototype.addRecord = function(newRecord) { BelongsToRelationship.prototype.setRecordPromise = function(newPromise) { var content = newPromise.get && newPromise.get('content'); Ember.assert("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); - this.setRecord(content); + this.setRecord(content ? content._internalModel : content); }; BelongsToRelationship.prototype._super$removeRecordFromOwn = Relationship.prototype.removeRecordFromOwn; @@ -137,7 +137,7 @@ BelongsToRelationship.prototype.getRecord = function() { return PromiseObject.create({ promise: promise, - content: this.inverseRecord + content: this.inverseRecord ? this.inverseRecord.getRecord() : null }); } else { if (this.inverseRecord === null) { diff --git a/packages/ember-data/tests/integration/relationships/belongs-to-test.js b/packages/ember-data/tests/integration/relationships/belongs-to-test.js index 8a38c9006a9..26b2b62af0d 100644 --- a/packages/ember-data/tests/integration/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/integration/relationships/belongs-to-test.js @@ -313,6 +313,34 @@ test("A record with an async belongsTo relationship returning null should resolv })); }); +test("A record can be created with a resolved belongsTo promise", function() { + expect(1); + + var Group = DS.Model.extend({ + people: DS.hasMany() + }); + + var Person = DS.Model.extend({ + group: DS.belongsTo({ async: true }) + }); + + env.registry.register('model:group', Group); + env.registry.register('model:person', Person); + + var group; + run(function() { + group = store.push('group', { id: 1 }); + }); + + var groupPromise = store.find('group', 1); + groupPromise.then(async(function(group) { + var person = env.store.createRecord('person', { + group: groupPromise + }); + equal(person.get('group.content'), group); + })); +}); + test("polymorphic belongsTo type-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled", function() { expect(1); From e520a21a84999764eadc273d382c738ca6275464 Mon Sep 17 00:00:00 2001 From: Andrew Fan Date: Mon, 16 Mar 2015 13:23:15 +0300 Subject: [PATCH 0850/2527] update relationships getters in snapshot --- .../lib/system/model/internal-model.js | 21 ++++------ .../lib/system/relationships/belongs-to.js | 10 ++--- .../lib/system/relationships/has-many.js | 4 +- .../lib/system/relationships/state/create.js | 22 ++++++++++- .../relationships/state/relationship.js | 10 ++--- packages/ember-data/lib/system/snapshot.js | 6 +-- packages/ember-data/lib/system/store.js | 5 ++- .../tests/integration/inverse-test.js | 1 + .../relationships/belongs-to-test.js | 39 +++++++++++++++++++ .../relationships/has-many-test.js | 19 ++++++++- .../inverse-relationships-test.js | 10 +++-- 11 files changed, 112 insertions(+), 35 deletions(-) diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js index 8305d3da021..2687c55ce0b 100644 --- a/packages/ember-data/lib/system/model/internal-model.js +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -1,6 +1,6 @@ import merge from "ember-data/system/merge"; import RootState from "ember-data/system/model/states"; -import createRelationshipFor from "ember-data/system/relationships/state/create"; +import Relationships from "ember-data/system/relationships/state/create"; import Snapshot from "ember-data/system/snapshot"; import Errors from "ember-data/system/model/errors"; @@ -60,7 +60,7 @@ var InternalModel = function InternalModel(type, id, store, container, data) { this._deferredTriggers = []; this._attributes = Ember.create(null); this._inFlightAttributes = Ember.create(null); - this._relationships = Ember.create(null); + this._relationships = new Relationships(this); this.currentState = RootState.empty; this.isReloading = false; /* @@ -84,11 +84,6 @@ var InternalModel = function InternalModel(type, id, store, container, data) { when we are deleted */ this._implicitRelationships = Ember.create(null); - var model = this; - //TODO Move into a getter for better perf - this.eachRelationship(function(key, descriptor) { - model._relationships[key] = createRelationshipFor(model, descriptor, model.store); - }); }; InternalModel.prototype = { @@ -441,8 +436,8 @@ InternalModel.prototype = { */ clearRelationships: function() { this.eachRelationship(function(name, relationship) { - var rel = this._relationships[name]; - if (rel) { + if (this._relationships.has(name)) { + var rel = this._relationships.get(name); //TODO(Igor) figure out whether we want to clear or disconnect rel.clear(); rel.destroy(); @@ -457,7 +452,7 @@ InternalModel.prototype = { disconnectRelationships: function() { this.eachRelationship(function(name, relationship) { - this._relationships[name].disconnect(); + this._relationships.get(name).disconnect(); }, this); var model = this; forEach.call(Ember.keys(this._implicitRelationships), function(key) { @@ -467,7 +462,7 @@ InternalModel.prototype = { reconnectRelationships: function() { this.eachRelationship(function(name, relationship) { - this._relationships[name].reconnect(); + this._relationships.get(name).reconnect(); }, this); var model = this; forEach.call(Ember.keys(this._implicitRelationships), function(key) { @@ -524,7 +519,7 @@ InternalModel.prototype = { }); //We use the pathway of setting the hasMany as if it came from the adapter //because the user told us that they know this relationships exists already - this._relationships[key].updateRecordsFromAdapter(recordsToSet); + this._relationships.get(key).updateRecordsFromAdapter(recordsToSet); }, _preloadBelongsTo: function(key, preloadValue, type) { @@ -532,7 +527,7 @@ InternalModel.prototype = { //We use the pathway of setting the hasMany as if it came from the adapter //because the user told us that they know this relationships exists already - this._relationships[key].setRecord(recordToSet); + this._relationships.get(key).setRecord(recordToSet); }, _convertStringOrNumberIntoInternalModel: function(value, type) { diff --git a/packages/ember-data/lib/system/relationships/belongs-to.js b/packages/ember-data/lib/system/relationships/belongs-to.js index 63a0d14d786..c1d60c3058a 100644 --- a/packages/ember-data/lib/system/relationships/belongs-to.js +++ b/packages/ember-data/lib/system/relationships/belongs-to.js @@ -89,21 +89,21 @@ function belongsTo(modelName, options) { return computedPolyfill({ get: function(key) { - return this._internalModel._relationships[key].getRecord(); + return this._internalModel._relationships.get(key).getRecord(); }, set: function(key, value) { if (value === undefined) { value = null; } if (value && value.then) { - this._internalModel._relationships[key].setRecordPromise(value); + this._internalModel._relationships.get(key).setRecordPromise(value); } else if (value) { - this._internalModel._relationships[key].setRecord(value._internalModel); + this._internalModel._relationships.get(key).setRecord(value._internalModel); } else { - this._internalModel._relationships[key].setRecord(value); + this._internalModel._relationships.get(key).setRecord(value); } - return this._internalModel._relationships[key].getRecord(); + return this._internalModel._relationships.get(key).getRecord(); } }).meta(meta); } diff --git a/packages/ember-data/lib/system/relationships/has-many.js b/packages/ember-data/lib/system/relationships/has-many.js index 06a5144d647..96d5fb01daa 100644 --- a/packages/ember-data/lib/system/relationships/has-many.js +++ b/packages/ember-data/lib/system/relationships/has-many.js @@ -123,11 +123,11 @@ function hasMany(type, options) { return computedPolyfill({ get: function(key) { - var relationship = this._internalModel._relationships[key]; + var relationship = this._internalModel._relationships.get(key); return relationship.getRecords(); }, set: function(key, records) { - var relationship = this._internalModel._relationships[key]; + var relationship = this._internalModel._relationships.get(key); relationship.clear(); Ember.assert("You must pass an array of records to set a hasMany relationship", Ember.isArray(records)); relationship.addRecords(Ember.A(records).mapBy('_internalModel')); diff --git a/packages/ember-data/lib/system/relationships/state/create.js b/packages/ember-data/lib/system/relationships/state/create.js index 2519241ee44..41ffdd65ed3 100644 --- a/packages/ember-data/lib/system/relationships/state/create.js +++ b/packages/ember-data/lib/system/relationships/state/create.js @@ -1,6 +1,8 @@ import ManyRelationship from "ember-data/system/relationships/state/has-many"; import BelongsToRelationship from "ember-data/system/relationships/state/belongs-to"; +var get = Ember.get; + var createRelationshipFor = function(record, relationshipMeta, store) { var inverseKey; var inverse = record.type.inverseFor(relationshipMeta.key, store); @@ -16,4 +18,22 @@ var createRelationshipFor = function(record, relationshipMeta, store) { } }; -export default createRelationshipFor; +var Relationships = function(record) { + this.record = record; + this.initializedRelationships = Ember.create(null); +}; + +Relationships.prototype.has = function(key) { + return !!this.initializedRelationships[key]; +}; + +Relationships.prototype.get = function(key) { + var relationships = this.initializedRelationships; + var relationshipsByName = get(this.record.constructor, 'relationshipsByName'); + if (!relationships[key] && relationshipsByName.get(key)) { + relationships[key] = createRelationshipFor(this.record, relationshipsByName.get(key), this.record.store); + } + return relationships[key]; +}; + +export default Relationships; diff --git a/packages/ember-data/lib/system/relationships/state/relationship.js b/packages/ember-data/lib/system/relationships/state/relationship.js index e587ef5e380..adc2889bd4f 100644 --- a/packages/ember-data/lib/system/relationships/state/relationship.js +++ b/packages/ember-data/lib/system/relationships/state/relationship.js @@ -76,7 +76,7 @@ Relationship.prototype = { if (!this.canonicalMembers.has(record)) { this.canonicalMembers.add(record); if (this.inverseKey) { - record._relationships[this.inverseKey].addCanonicalRecord(this.record); + record._relationships.get(this.inverseKey).addCanonicalRecord(this.record); } else { if (!record._implicitRelationships[this.inverseKeyForImplicit]) { record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, { options: {} }); @@ -117,7 +117,7 @@ Relationship.prototype = { this.members.addWithIndex(record, idx); this.notifyRecordRelationshipAdded(record, idx); if (this.inverseKey) { - record._relationships[this.inverseKey].addRecord(this.record); + record._relationships.get(this.inverseKey).addRecord(this.record); } else { if (!record._implicitRelationships[this.inverseKeyForImplicit]) { record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, { options: {} }); @@ -144,12 +144,12 @@ Relationship.prototype = { addRecordToInverse: function(record) { if (this.inverseKey) { - record._relationships[this.inverseKey].addRecord(this.record); + record._relationships.get(this.inverseKey).addRecord(this.record); } }, removeRecordFromInverse: function(record) { - var inverseRelationship = record._relationships[this.inverseKey]; + var inverseRelationship = record._relationships.get(this.inverseKey); //Need to check for existence, as the record might unloading at the moment if (inverseRelationship) { inverseRelationship.removeRecordFromOwn(this.record); @@ -163,7 +163,7 @@ Relationship.prototype = { }, removeCanonicalRecordFromInverse: function(record) { - var inverseRelationship = record._relationships[this.inverseKey]; + var inverseRelationship = record._relationships.get(this.inverseKey); //Need to check for existence, as the record might unloading at the moment if (inverseRelationship) { inverseRelationship.removeCanonicalRecordFromOwn(this.record); diff --git a/packages/ember-data/lib/system/snapshot.js b/packages/ember-data/lib/system/snapshot.js index f1cc25aab7d..ece20c8d3c1 100644 --- a/packages/ember-data/lib/system/snapshot.js +++ b/packages/ember-data/lib/system/snapshot.js @@ -223,7 +223,7 @@ Snapshot.prototype = { return this._belongsToRelationships[keyName]; } - relationship = this._internalModel._relationships[keyName]; + relationship = this._internalModel._relationships.get(keyName); if (!(relationship && relationship.relationshipMeta.kind === 'belongsTo')) { throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined."); } @@ -294,7 +294,7 @@ Snapshot.prototype = { return this._hasManyRelationships[keyName]; } - relationship = this._internalModel._relationships[keyName]; + relationship = this._internalModel._relationships.get(keyName); if (!(relationship && relationship.relationshipMeta.kind === 'hasMany')) { throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined."); } @@ -381,7 +381,7 @@ Snapshot.prototype = { return this.attr(keyName); } - var relationship = this._internalModel._relationships[keyName]; + var relationship = this._internalModel._relationships.get(keyName); if (relationship && relationship.relationshipMeta.kind === 'belongsTo') { return this.belongsTo(keyName); diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 782a3eb84d6..52f868e9999 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -2111,16 +2111,19 @@ function setupRelationships(store, record, data) { typeClass.eachRelationship(function(key, descriptor) { var kind = descriptor.kind; var value = data[key]; - var relationship = record._relationships[key]; + var relationship; if (data.links && data.links[key]) { + relationship = record._relationships.get(key); relationship.updateLink(data.links[key]); } if (value !== undefined) { if (kind === 'belongsTo') { + relationship = record._relationships.get(key); relationship.setCanonicalRecord(value); } else if (kind === 'hasMany') { + relationship = record._relationships.get(key); relationship.updateRecordsFromAdapter(value); } } diff --git a/packages/ember-data/tests/integration/inverse-test.js b/packages/ember-data/tests/integration/inverse-test.js index d0861e54ae4..974dd0ed31b 100644 --- a/packages/ember-data/tests/integration/inverse-test.js +++ b/packages/ember-data/tests/integration/inverse-test.js @@ -148,6 +148,7 @@ test("Errors out if you do not define an inverse for a reflexive relationship", var reflexiveModel; run(function() { reflexiveModel = store.push('reflexive-model', { id: 1 }); + reflexiveModel.get('reflexiveProp'); }); }, /Detected a reflexive relationship by the name of 'reflexiveProp'/); }); diff --git a/packages/ember-data/tests/integration/relationships/belongs-to-test.js b/packages/ember-data/tests/integration/relationships/belongs-to-test.js index 5c3a5399989..614d34fd344 100644 --- a/packages/ember-data/tests/integration/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/integration/relationships/belongs-to-test.js @@ -687,3 +687,42 @@ test("belongsTo hasData sync created", function () { equal(relationship.hasData, true, 'relationship has data'); }); }); + +test("Model's belongsTo relationship should not be created during model creation", function () { + var user; + run(function () { + user = env.store.createRecord('user'); + ok(!user._relationships.has('favouriteMessage'), 'Newly created record should not have relationships'); + }); +}); + +test("Model's belongsTo relationship should be created during model creation if relationship passed in constructor", function () { + var user, message; + run(function () { + message = env.store.createRecord('message'); + user = env.store.createRecord('user', { + name: 'John Doe', + favouriteMessage: message + }); + ok(user._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); + }); +}); + +test("Model's belongsTo relationship should be created during 'set' method", function () { + var user, message; + run(function () { + message = env.store.createRecord('message'); + user = env.store.createRecord('user'); + user.set('favouriteMessage', message); + ok(user._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); + }); +}); + +test("Model's belongsTo relationship should be created during 'get' method", function () { + var user; + run(function () { + user = env.store.createRecord('user'); + user.get('favouriteMessage'); + ok(user._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); + }); +}); diff --git a/packages/ember-data/tests/integration/relationships/has-many-test.js b/packages/ember-data/tests/integration/relationships/has-many-test.js index 780fa5feadd..5f0bd64b780 100644 --- a/packages/ember-data/tests/integration/relationships/has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/has-many-test.js @@ -1218,7 +1218,7 @@ test("Relationship.clear removes all records correctly", function() { }); run(function() { - post._internalModel._relationships['comments'].clear(); + post._internalModel._relationships.get('comments').clear(); var comments = Ember.A(env.store.all('comment')); deepEqual(comments.mapBy('post'), [null, null, null]); }); @@ -1428,3 +1428,20 @@ test("hasMany hasData sync created", function () { equal(relationship.hasData, true, 'relationship has data'); }); }); + +test("Model's hasMany relationship should not be created during model creation", function () { + var user; + run(function () { + user = env.store.createRecord('user'); + ok(!user._relationships.has('messages'), 'Newly created record should not have relationships'); + }); +}); + +test("Model's belongsTo relationship should be created during 'get' method", function () { + var user; + run(function () { + user = env.store.createRecord('user'); + user.get('messages'); + ok(user._relationships.has('messages'), "Newly created record with relationships in params passed in its constructor should have relationships"); + }); +}); diff --git a/packages/ember-data/tests/integration/relationships/inverse-relationships-test.js b/packages/ember-data/tests/integration/relationships/inverse-relationships-test.js index beedbe6c3f3..89977f0c7e3 100644 --- a/packages/ember-data/tests/integration/relationships/inverse-relationships-test.js +++ b/packages/ember-data/tests/integration/relationships/inverse-relationships-test.js @@ -423,14 +423,15 @@ test("Inverse relationships that don't exist throw a nice error for a hasMany", }); var env = setupStore({ post: Post, comment: Comment, user: User }); - var comment; + var comment, post; run(function() { comment = env.store.createRecord('comment'); }); expectAssertion(function() { run(function() { - env.store.createRecord('post'); + post = env.store.createRecord('post'); + post.get('comments'); }); }, /We found no inverse relationships by the name of 'testPost' on the 'comment' model/); }); @@ -444,14 +445,15 @@ test("Inverse relationships that don't exist throw a nice error for a belongsTo" }); var env = setupStore({ post: Post, comment: Comment, user: User }); - var user; + var user, post; run(function() { user = env.store.createRecord('user'); }); expectAssertion(function() { run(function() { - env.store.createRecord('post'); + post = env.store.createRecord('post'); + post.get('user'); }); }, /We found no inverse relationships by the name of 'testPost' on the 'user' model/); }); From 69892b416728bafa177c6aaf633c100f3ad4cd81 Mon Sep 17 00:00:00 2001 From: Mikhail Topolskiy Date: Wed, 3 Jun 2015 23:26:56 +0300 Subject: [PATCH 0851/2527] Rebased pr #2741 --- .../lib/system/relationships/state/create.js | 2 +- packages/ember-data/lib/system/store.js | 2 +- .../relationships/belongs-to-test.js | 22 +++++++++---------- .../relationships/has-many-test.js | 18 +++++++-------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/state/create.js b/packages/ember-data/lib/system/relationships/state/create.js index 41ffdd65ed3..0dece8f563a 100644 --- a/packages/ember-data/lib/system/relationships/state/create.js +++ b/packages/ember-data/lib/system/relationships/state/create.js @@ -29,7 +29,7 @@ Relationships.prototype.has = function(key) { Relationships.prototype.get = function(key) { var relationships = this.initializedRelationships; - var relationshipsByName = get(this.record.constructor, 'relationshipsByName'); + var relationshipsByName = get(this.record.type, 'relationshipsByName'); if (!relationships[key] && relationshipsByName.get(key)) { relationships[key] = createRelationshipFor(this.record, relationshipsByName.get(key), this.record.store); } diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 52f868e9999..2f385b029c9 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -339,7 +339,7 @@ Store = Service.extend({ record.setProperties(properties); internalModel.eachRelationship(function(key, descriptor) { - internalModel._relationships[key].setHasData(true); + internalModel._relationships.get(key).setHasData(true); }); return record; diff --git a/packages/ember-data/tests/integration/relationships/belongs-to-test.js b/packages/ember-data/tests/integration/relationships/belongs-to-test.js index 614d34fd344..fbc45db9d52 100644 --- a/packages/ember-data/tests/integration/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/integration/relationships/belongs-to-test.js @@ -609,7 +609,7 @@ test("belongsTo hasData async loaded", function () { run(function() { store.find('book', 1).then(function(book) { - var relationship = book._internalModel._relationships['author']; + var relationship = book._internalModel._relationships.get('author'); equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -624,7 +624,7 @@ test("belongsTo hasData sync loaded", function () { run(function() { store.find('book', 1).then(function(book) { - var relationship = book._internalModel._relationships['author']; + var relationship = book._internalModel._relationships.get('author'); equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -643,7 +643,7 @@ test("belongsTo hasData async not loaded", function () { run(function() { store.find('book', 1).then(function(book) { - var relationship = book._internalModel._relationships['author']; + var relationship = book._internalModel._relationships.get('author'); equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -658,7 +658,7 @@ test("belongsTo hasData sync not loaded", function () { run(function() { store.find('book', 1).then(function(book) { - var relationship = book._internalModel._relationships['author']; + var relationship = book._internalModel._relationships.get('author'); equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -673,7 +673,7 @@ test("belongsTo hasData async created", function () { run(function() { var book = store.createRecord('book', { name: 'The Greatest Book' }); - var relationship = book._internalModel._relationships['author']; + var relationship = book._internalModel._relationships.get('author'); equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -683,7 +683,7 @@ test("belongsTo hasData sync created", function () { run(function() { var book = store.createRecord('book', { name: 'The Greatest Book' }); - var relationship = book._internalModel._relationships['author']; + var relationship = book._internalModel._relationships.get('author'); equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -691,8 +691,8 @@ test("belongsTo hasData sync created", function () { test("Model's belongsTo relationship should not be created during model creation", function () { var user; run(function () { - user = env.store.createRecord('user'); - ok(!user._relationships.has('favouriteMessage'), 'Newly created record should not have relationships'); + user = env.store.push('user', { id: 1 }); + ok(!user._internalModel._relationships.has('favouriteMessage'), 'Newly created record should not have relationships'); }); }); @@ -704,7 +704,7 @@ test("Model's belongsTo relationship should be created during model creation if name: 'John Doe', favouriteMessage: message }); - ok(user._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); + ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); }); }); @@ -714,7 +714,7 @@ test("Model's belongsTo relationship should be created during 'set' method", fun message = env.store.createRecord('message'); user = env.store.createRecord('user'); user.set('favouriteMessage', message); - ok(user._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); + ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); }); }); @@ -723,6 +723,6 @@ test("Model's belongsTo relationship should be created during 'get' method", fun run(function () { user = env.store.createRecord('user'); user.get('favouriteMessage'); - ok(user._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); + ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); }); }); diff --git a/packages/ember-data/tests/integration/relationships/has-many-test.js b/packages/ember-data/tests/integration/relationships/has-many-test.js index 5f0bd64b780..67bb165c30a 100644 --- a/packages/ember-data/tests/integration/relationships/has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/has-many-test.js @@ -1350,7 +1350,7 @@ test("hasMany hasData async loaded", function () { run(function() { store.find('chapter', 1).then(function(chapter) { - var relationship = chapter._internalModel._relationships['pages']; + var relationship = chapter._internalModel._relationships.get('pages'); equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -1365,7 +1365,7 @@ test("hasMany hasData sync loaded", function () { run(function() { store.find('chapter', 1).then(function(chapter) { - var relationship = chapter._internalModel._relationships['pages']; + var relationship = chapter._internalModel._relationships.get('pages'); equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -1384,7 +1384,7 @@ test("hasMany hasData async not loaded", function () { run(function() { store.find('chapter', 1).then(function(chapter) { - var relationship = chapter._internalModel._relationships['pages']; + var relationship = chapter._internalModel._relationships.get('pages'); equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -1399,7 +1399,7 @@ test("hasMany hasData sync not loaded", function () { run(function() { store.find('chapter', 1).then(function(chapter) { - var relationship = chapter._internalModel._relationships['pages']; + var relationship = chapter._internalModel._relationships.get('pages'); equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -1414,7 +1414,7 @@ test("hasMany hasData async created", function () { run(function() { var chapter = store.createRecord('chapter', { title: 'The Story Begins' }); - var relationship = chapter._internalModel._relationships['pages']; + var relationship = chapter._internalModel._relationships.get('pages'); equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -1424,7 +1424,7 @@ test("hasMany hasData sync created", function () { run(function() { var chapter = store.createRecord('chapter', { title: 'The Story Begins' }); - var relationship = chapter._internalModel._relationships['pages']; + var relationship = chapter._internalModel._relationships.get('pages'); equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -1432,8 +1432,8 @@ test("hasMany hasData sync created", function () { test("Model's hasMany relationship should not be created during model creation", function () { var user; run(function () { - user = env.store.createRecord('user'); - ok(!user._relationships.has('messages'), 'Newly created record should not have relationships'); + user = env.store.push('user', { id: 1 }); + ok(!user._internalModel._relationships.has('messages'), 'Newly created record should not have relationships'); }); }); @@ -1442,6 +1442,6 @@ test("Model's belongsTo relationship should be created during 'get' method", fun run(function () { user = env.store.createRecord('user'); user.get('messages'); - ok(user._relationships.has('messages'), "Newly created record with relationships in params passed in its constructor should have relationships"); + ok(user._internalModel._relationships.has('messages'), "Newly created record with relationships in params passed in its constructor should have relationships"); }); }); From 2a4f7c756c1f995582c14105b633a9924defee6f Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 3 Jun 2015 21:37:37 -0500 Subject: [PATCH 0852/2527] fix jshint line numbers It was getting the babel transpiled output, which made it pretty much impossible to see where the actual lint warnings were coming from. --- Brocfile.js | 8 ++++---- packages/ember-data/tests/integration/snapshot-test.js | 6 +++--- .../tests/unit/adapter-populated-record-array-test.js | 2 +- .../tests/unit/adapters/rest-adapter/ajax-test.js | 2 +- .../unit/record-arrays/filtered-record-array-test.js | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Brocfile.js b/Brocfile.js index ad0c470a5b5..1dc789a054a 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -93,24 +93,24 @@ var packages = merge([ var globalBuild; -packages = babel(packages, babelOptions); +var transpiledPackages = babel(packages, babelOptions); // Bundle formatter for smaller payload if (env === 'production') { - globalBuild = es6(libTree(packages), { + globalBuild = es6(libTree(transpiledPackages), { inputFiles: ['ember-data'], output: '/ember-data.js', resolvers: [PackageResolver], formatter: 'bundle' }); - var tests = testTree(packages, amdBuild(packages)); + var tests = testTree(packages, amdBuild(transpiledPackages)); globalBuild = merge([globalBuild, tests]); } else { // Use AMD for faster rebuilds in dev var bootFile = fileCreator('/boot.js', 'require("ember-data");'); - var compiled = amdBuild(packages); + var compiled = amdBuild(transpiledPackages); var libFiles = libTree(compiled); var emberData = merge([bootFile, libFiles]); diff --git a/packages/ember-data/tests/integration/snapshot-test.js b/packages/ember-data/tests/integration/snapshot-test.js index 3c90ea4558f..b8c0fe5f45b 100644 --- a/packages/ember-data/tests/integration/snapshot-test.js +++ b/packages/ember-data/tests/integration/snapshot-test.js @@ -216,7 +216,7 @@ test("snapshot.belongsTo() throws error if relation doesn't exist", function() { throws(function() { snapshot.belongsTo('unknown'); - }, /has no belongsTo relationship named 'unknown'/, 'throws error') + }, /has no belongsTo relationship named 'unknown'/, 'throws error'); }); }); @@ -455,7 +455,7 @@ test("snapshot.hasMany() throws error if relation doesn't exist", function() { throws(function() { snapshot.hasMany('unknown'); - }, /has no hasMany relationship named 'unknown'/, 'throws error') + }, /has no hasMany relationship named 'unknown'/, 'throws error'); }); }); @@ -647,7 +647,7 @@ test("snapshot.serialize() serializes itself", function() { post.set('title', 'New Title'); deepEqual(snapshot.serialize(), { author: undefined, title: 'Hello World' }, 'shapshot serializes correctly'); - deepEqual(snapshot.serialize({ includeId: true }), { id: "1", author: undefined, title: 'Hello World' }, 'serialize takes options') + deepEqual(snapshot.serialize({ includeId: true }), { id: "1", author: undefined, title: 'Hello World' }, 'serialize takes options'); }); }); diff --git a/packages/ember-data/tests/unit/adapter-populated-record-array-test.js b/packages/ember-data/tests/unit/adapter-populated-record-array-test.js index b5903f643b6..6b881395c33 100644 --- a/packages/ember-data/tests/unit/adapter-populated-record-array-test.js +++ b/packages/ember-data/tests/unit/adapter-populated-record-array-test.js @@ -47,5 +47,5 @@ test('recordArray.replace() throws error', function() { throws(function() { recordArray.replace(); - }, Error("The result of a server query (on (subclass of DS.Model)) is immutable."), 'throws error') + }, Error("The result of a server query (on (subclass of DS.Model)) is immutable."), 'throws error'); }); diff --git a/packages/ember-data/tests/unit/adapters/rest-adapter/ajax-test.js b/packages/ember-data/tests/unit/adapters/rest-adapter/ajax-test.js index 78d83a2a1a7..f19931bd944 100644 --- a/packages/ember-data/tests/unit/adapters/rest-adapter/ajax-test.js +++ b/packages/ember-data/tests/unit/adapters/rest-adapter/ajax-test.js @@ -52,7 +52,7 @@ test("ajaxOptions() headers are set", function() { var receivedHeaders = []; var fakeXHR = { setRequestHeader: function(key, value) { - receivedHeaders.push([key, value]) + receivedHeaders.push([key, value]); } }; ajaxOptions.beforeSend(fakeXHR); diff --git a/packages/ember-data/tests/unit/record-arrays/filtered-record-array-test.js b/packages/ember-data/tests/unit/record-arrays/filtered-record-array-test.js index cd706d21c6b..baa0448efef 100644 --- a/packages/ember-data/tests/unit/record-arrays/filtered-record-array-test.js +++ b/packages/ember-data/tests/unit/record-arrays/filtered-record-array-test.js @@ -2,12 +2,12 @@ var filteredArray; module("unit/record-arrays/filtered-record-array - DS.FilteredRecordArray", { setup: function() { - filteredArray = DS.FilteredRecordArray.create({ type: 'recordType' }) + filteredArray = DS.FilteredRecordArray.create({ type: 'recordType' }); } }); test('recordArray.replace() throws error', function() { throws(function() { filteredArray.replace(); - }, Error("The result of a client-side filter (on recordType) is immutable."), 'throws error') + }, Error("The result of a client-side filter (on recordType) is immutable."), 'throws error'); }); From a080db4593cfb35efaff333ddf18575c575bc4a3 Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 4 Jun 2015 09:38:54 -0400 Subject: [PATCH 0853/2527] Update comment to make its intention clear Closes #2726 --- packages/ember-data/lib/transforms/date.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/transforms/date.js b/packages/ember-data/lib/transforms/date.js index 62092b0f165..a3d64b196b0 100644 --- a/packages/ember-data/lib/transforms/date.js +++ b/packages/ember-data/lib/transforms/date.js @@ -54,8 +54,8 @@ export default Transform.extend({ } else if (type === "number") { return new Date(serialized); } else if (serialized === null || serialized === undefined) { - // if the value is not present in the data, - // return undefined, not null. + // if the value is null return null + // if the value is not present in the data return undefined return serialized; } else { return null; From 00a17f0fedae62d0bc4c4b858dcee07dce27b73d Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 4 Jun 2015 09:36:35 -0500 Subject: [PATCH 0854/2527] add feature flags to the build process --- .travis.yml | 1 + Brocfile.js | 7 +++++-- FEATURES.md | 13 +++++++++++++ bin/lint-features | 16 ++++++++++++++++ config/features.json | 2 ++ lib/feature-flags.js | 23 +++++++++++++++++++++++ packages/ember-data/lib/core.js | 4 ++++ 7 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 FEATURES.md create mode 100755 bin/lint-features create mode 100644 config/features.json create mode 100644 lib/feature-flags.js diff --git a/.travis.yml b/.travis.yml index 74e0f5c9526..8c8284b9de3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ before_install: install: - "npm install" script: + - ./bin/lint-features - npm run-script test - npm run-script test:beta - npm run-script test:canary diff --git a/Brocfile.js b/Brocfile.js index 1dc789a054a..f5bcd6f4294 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -21,12 +21,14 @@ var babel = require('broccoli-babel-transpiler'); var babelOptions = require('./config/babel'); var fileCreator = require('broccoli-file-creator'); var jscs = require('broccoli-jscs'); +var features = require('./lib/feature-flags'); function minify(tree, name){ var config = require('./config/ember-defeatureify'); tree = defeatureify(tree, { debugStatements: config.options.debugStatements, - enableStripDebug: config.enableStripDebug + enableStripDebug: config.enableStripDebug, + features: require('./config/features') }); tree = moveFile(tree, { srcFile: name + '.js', @@ -93,7 +95,8 @@ var packages = merge([ var globalBuild; -var transpiledPackages = babel(packages, babelOptions); +var withFeatures = features(packages); +var transpiledPackages = babel(withFeatures, babelOptions); // Bundle formatter for smaller payload if (env === 'production') { diff --git a/FEATURES.md b/FEATURES.md new file mode 100644 index 00000000000..d866f00ae24 --- /dev/null +++ b/FEATURES.md @@ -0,0 +1,13 @@ +## About Features + +Please read the [Feature Flag Guide](http://emberjs.com/guides/configuring-ember/feature-flags/) +for a detailed explanation. + +To add a new feature flag or change an existing one, you can add an +entry in `config/features.json`. + +**Ember Data features flags must begin with `ds-`, such as +`ds-new-coalescing`.** + +## Feature Flags + diff --git a/bin/lint-features b/bin/lint-features new file mode 100755 index 00000000000..3eb65b78f14 --- /dev/null +++ b/bin/lint-features @@ -0,0 +1,16 @@ +#!/usr/bin/env node + +var features = require('../config/features'); + +var beginsWithDS = /^ds-/; + +var violations = Object.keys(features).filter(function(feature){ + return !beginsWithDS.exec(feature); +}); + +if (violations.length) { + console.log('Features in features.json MUST begin with `ds-`! These features do not:', violations.join(' ')); + process.exit(1); +} else { + console.log('Features passed linting!'); +} diff --git a/config/features.json b/config/features.json new file mode 100644 index 00000000000..2c63c085104 --- /dev/null +++ b/config/features.json @@ -0,0 +1,2 @@ +{ +} diff --git a/lib/feature-flags.js b/lib/feature-flags.js new file mode 100644 index 00000000000..add23037452 --- /dev/null +++ b/lib/feature-flags.js @@ -0,0 +1,23 @@ +'use strict'; + +var replace = require('broccoli-replace'); +var pickFiles = require('broccoli-static-compiler'); +var merge = require('broccoli-merge-trees'); + +module.exports = function(tree){ + var features = require('../config/features'); + var core = pickFiles(tree, { + srcDir: '/', + destDir: '/', + files: ['**/*/core.js'] + }); + var replaced = replace(tree, { + files: ['**/*.js'], + patterns: [{ + match: /EMBER_DATA_FEATURES_PLACEHOLDER/g, + replacement: JSON.stringify(features, null, 2) + }] + }); + return merge([tree, replaced], {overwrite: true}); +}; + diff --git a/packages/ember-data/lib/core.js b/packages/ember-data/lib/core.js index 027a4663ac9..b1da96fd589 100644 --- a/packages/ember-data/lib/core.js +++ b/packages/ember-data/lib/core.js @@ -24,4 +24,8 @@ if (Ember.libraries) { Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); } +var EMBER_DATA_FEATURES = EMBER_DATA_FEATURES_PLACEHOLDER; //jshint ignore: line + +Ember.merge(Ember.FEATURES, EMBER_DATA_FEATURES); + export default DS; From ee9776056922ff33661cb60f775519c4902c4657 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 29 May 2015 11:20:32 -0500 Subject: [PATCH 0855/2527] refactor store managed instances In this commit, we refactor store managed instance lookups to have its own class that takes the store's container. This moves a large portion of code out of the store and instead uses delegation. There's also a performance benefit: If you look up `adapter:post` and fallback to `adapter:application`, this lookup is cached. So, if you look up `adapter:post` again, that instance will actually be cached. Previously, we did the lookup for `adapter:post` every time. This also removes passing factories as the `adapter` property to DS.Store. closes #3050 --- packages/ember-data/lib/system/adapter.js | 1 + packages/ember-data/lib/system/store.js | 69 ++++----- .../system/store/container-instance-cache.js | 86 +++++++++++ .../tests/helpers/custom-adapter.js | 10 ++ .../tests/integration/filter-test.js | 50 +++---- .../tests/unit/store/adapter-interop-test.js | 7 +- .../tests/unit/store/lookup-test.js | 135 ++++++++++++++++++ tests/ember-configuration.js | 10 +- 8 files changed, 294 insertions(+), 74 deletions(-) create mode 100644 packages/ember-data/lib/system/store/container-instance-cache.js create mode 100644 packages/ember-data/tests/helpers/custom-adapter.js create mode 100644 packages/ember-data/tests/unit/store/lookup-test.js diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index cc9295ca0f9..68274a76d79 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -83,6 +83,7 @@ var Adapter = Ember.Object.extend({ @property defaultSerializer @type {String} */ + defaultSerializer: '-default', /** The `find()` method is invoked when the store is asked for a record that diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 2f385b029c9..53c19974ae1 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -7,8 +7,7 @@ import normalizeModelName from "ember-data/system/normalize-model-name"; import { - InvalidError, - Adapter + InvalidError } from "ember-data/system/adapter"; import { Map @@ -41,6 +40,7 @@ import { import coerceId from "ember-data/system/coerce-id"; import RecordArrayManager from "ember-data/system/record-array-manager"; +import ContainerInstanceCache from 'ember-data/system/store/container-instance-cache'; import InternalModel from "ember-data/system/model/internal-model"; import Model from "ember-data/system/model"; @@ -214,7 +214,7 @@ Store = Service.extend({ store: this }); this._pendingSave = []; - this._containerCache = Ember.create(null); + this._instanceCache = new ContainerInstanceCache(this.container); //Used to keep track of all the find requests that need to be coalesced this._pendingFetch = Map.create(); }, @@ -273,18 +273,9 @@ Store = Service.extend({ defaultAdapter: Ember.computed('adapter', function() { var adapter = get(this, 'adapter'); - Ember.assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name or a factory', !(adapter instanceof Adapter)); + Ember.assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name', typeof adapter === 'string'); - if (typeof adapter === 'string') { - adapter = this.container.lookup('adapter:' + adapter) || this.container.lookup('adapter:application') || this.container.lookup('adapter:-rest'); - } - - if (DS.Adapter.detect(adapter)) { - adapter = adapter.create({ - container: this.container, - store: this - }); - } + adapter = this.retrieveManagedInstance('adapter', adapter); return adapter; }), @@ -1888,9 +1879,7 @@ Store = Service.extend({ modelName = modelOrClass; } - var adapter = this.lookupAdapter(modelName) || this.lookupAdapter('application'); - - return adapter || get(this, 'defaultAdapter'); + return this.lookupAdapter(modelName); }, _adapterRun: function (fn) { @@ -1932,17 +1921,13 @@ Store = Service.extend({ modelName = modelOrClass; } - var serializer = this.lookupSerializer(modelName) || this.lookupSerializer('application'); - - if (!serializer) { - var adapter = this.adapterFor(modelName); - serializer = this.lookupSerializer(get(adapter, 'defaultSerializer')); - } - - if (!serializer) { - serializer = this.lookupSerializer('-default'); - } + var fallbacks = [ + 'application', + this.adapterFor(modelName).get('defaultSerializer'), + '-default' + ]; + var serializer = this.lookupSerializer(modelName, fallbacks); return serializer; }, @@ -1958,30 +1943,28 @@ Store = Service.extend({ @private @param {String} modelName the object modelName @param {String} name the object name + @param {Array} fallbacks the fallback objects to lookup if the lookup for modelName or 'application' fails @return {Ember.Object} */ - retrieveManagedInstance: function(modelName, name) { - var normalizedTypeKey = normalizeModelName(modelName); - var key = normalizedTypeKey + ":" +name; - - if (!this._containerCache[key]) { - var instance = this.container.lookup(key); - - if (instance) { - set(instance, 'store', this); - this._containerCache[key] = instance; - } - } + retrieveManagedInstance: function(type, modelName, fallbacks) { + var normalizedModelName = normalizeModelName(modelName); - return this._containerCache[key]; + var instance = this._instanceCache.get(type, normalizedModelName, fallbacks); + set(instance, 'store', this); + return instance; }, lookupAdapter: function(name) { - return this.retrieveManagedInstance('adapter', name); + return this.retrieveManagedInstance('adapter', name, this.get('_adapterFallbacks')); }, - lookupSerializer: function(name) { - return this.retrieveManagedInstance('serializer', name); + _adapterFallbacks: Ember.computed('adapter', function() { + var adapter = this.get('adapter'); + return ['application', adapter, '-rest']; + }), + + lookupSerializer: function(name, fallbacks) { + return this.retrieveManagedInstance('serializer', name, fallbacks); }, willDestroy: function() { diff --git a/packages/ember-data/lib/system/store/container-instance-cache.js b/packages/ember-data/lib/system/store/container-instance-cache.js new file mode 100644 index 00000000000..cc86980874d --- /dev/null +++ b/packages/ember-data/lib/system/store/container-instance-cache.js @@ -0,0 +1,86 @@ +import Ember from 'ember'; + +/** + * The `ContainerInstanceCache` serves as a lazy cache for looking up + * instances of serializers and adapters. It has some additional logic for + * finding the 'fallback' adapter or serializer. + * + * The 'fallback' adapter or serializer is an adapter or serializer that is looked up + * when the preferred lookup fails. For example, say you try to look up `adapter:post`, + * but there is no entry (app/adapters/post.js in EmberCLI) for `adapter:post` in the registry. + * + * The `fallbacks` array passed will then be used; the first entry in the fallbacks array + * that exists in the container will then be cached for `adapter:post`. So, the next time you + * look up `adapter:post`, you'll get the `adapter:application` instance (or whatever the fallback + * was if `adapter:application` doesn't exist). + * + * @private + * @class ContainerInstanceCache + * +*/ +function ContainerInstanceCache(container) { + this._container = container; + this._cache = Ember.create(null); +} + +ContainerInstanceCache.prototype = Ember.create(null); + +Ember.merge(ContainerInstanceCache.prototype, { + get: function(type, preferredKey, fallbacks) { + let cache = this._cache; + let preferredLookupKey = `${type}:${preferredKey}`; + + if (!(preferredLookupKey in cache)) { + let instance = this.instanceFor(preferredLookupKey) || this._findInstance(type, fallbacks); + if (instance) { + cache[preferredLookupKey] = instance; + } + } + return cache[preferredLookupKey]; + }, + + _findInstance: function(type, fallbacks) { + for (let i = 0, length = fallbacks.length; i < length; i++) { + let fallback = fallbacks[i]; + let lookupKey = `${type}:${fallback}`; + let instance = this.instanceFor(lookupKey); + + if (instance) { + return instance; + } + } + }, + + instanceFor: function(key) { + let cache = this._cache; + if (!cache[key]) { + let instance = this._container.lookup(key); + if (instance) { + cache[key] = instance; + } + } + return cache[key]; + }, + + destroy: function() { + let cache = this._cache; + let cacheEntries = Ember.keys(cache); + + for (let i = 0, length = cacheEntries.length; i < length; i++) { + let cacheKey = cacheEntries[i]; + let cacheEntry = cache[cacheKey]; + if (cacheEntry) { + cacheEntry.destroy(); + } + } + this._container = null; + }, + + constructor: ContainerInstanceCache, + + toString: function() { + return 'ContainerInstanceCache'; + } +}); + +export default ContainerInstanceCache; diff --git a/packages/ember-data/tests/helpers/custom-adapter.js b/packages/ember-data/tests/helpers/custom-adapter.js new file mode 100644 index 00000000000..3cead14285f --- /dev/null +++ b/packages/ember-data/tests/helpers/custom-adapter.js @@ -0,0 +1,10 @@ + +export default function(env, adapterDefinition) { + var adapter = adapterDefinition; + if (!DS.Adapter.detect(adapterDefinition)) { + adapter = DS.Adapter.extend(adapterDefinition); + } + var store = env.store; + env.registry.register('adapter:-custom', adapter); + Ember.run(() => store.set('adapter', '-custom')); +} diff --git a/packages/ember-data/tests/integration/filter-test.js b/packages/ember-data/tests/integration/filter-test.js index e59721e90ee..9d6503a4f6b 100644 --- a/packages/ember-data/tests/integration/filter-test.js +++ b/packages/ember-data/tests/integration/filter-test.js @@ -1,3 +1,5 @@ +import customAdapter from 'ember-data/tests/helpers/custom-adapter'; + var get = Ember.get; var set = Ember.set; var forEach = Ember.EnumerableUtils.forEach; @@ -168,13 +170,11 @@ test("a filtered record array includes created elements", function() { }); test("a Record Array can update its filter", function() { - run(function() { - set(store, 'adapter', DS.Adapter.extend({ - deleteRecord: function(store, type, snapshot) { - return Ember.RSVP.resolve(); - } - })); - }); + customAdapter(env, DS.Adapter.extend({ + deleteRecord: function(store, type, snapshot) { + return Ember.RSVP.resolve(); + } + })); run(function() { store.pushMany('person', array); @@ -227,13 +227,11 @@ test("a Record Array can update its filter", function() { }); test("a Record Array can update its filter and notify array observers", function() { - run(function() { - set(store, 'adapter', DS.Adapter.extend({ - deleteRecord: function(store, type, snapshot) { - return Ember.RSVP.resolve(); - } - })); - }); + customAdapter(env, DS.Adapter.extend({ + deleteRecord: function(store, type, snapshot) { + return Ember.RSVP.resolve(); + } + })); run(function() { store.pushMany('person', array); @@ -367,7 +365,7 @@ test("a filter created after a record is already loaded works", function() { }); test("filter with query persists query on the resulting filteredRecordArray", function() { - set(store, 'adapter', DS.Adapter.extend({ + customAdapter(env, DS.Adapter.extend({ findQuery: function(store, type, id) { return Ember.RSVP.resolve([{ id: id, @@ -375,6 +373,7 @@ test("filter with query persists query on the resulting filteredRecordArray", fu }]); } })); + var filter; run(function() { @@ -393,13 +392,14 @@ test("filter with query persists query on the resulting filteredRecordArray", fu test("it is possible to filter by state flags", function() { var filter; - run(function() { - set(store, 'adapter', DS.Adapter.extend({ - find: function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: id, name: "Tom Dale" }); - } - })); + customAdapter(env, DS.Adapter.extend({ + find: function(store, type, id, snapshot) { + return Ember.RSVP.resolve({ id: id, name: "Tom Dale" }); + } + })); + + run(function() { filter = store.filter('person', function(person) { return person.get('isLoaded'); }); @@ -423,7 +423,7 @@ test("it is possible to filter by state flags", function() { }); test("it is possible to filter loaded records by dirtiness", function() { - set(store, 'adapter', DS.Adapter.extend({ + customAdapter(env, DS.Adapter.extend({ updateRecord: function() { return Ember.RSVP.resolve(); } @@ -456,7 +456,7 @@ test("it is possible to filter loaded records by dirtiness", function() { test("it is possible to filter created records by dirtiness", function() { run(function() { - set(store, 'adapter', DS.Adapter.extend({ + customAdapter(env, DS.Adapter.extend({ createRecord: function() { return Ember.RSVP.resolve(); } @@ -490,7 +490,7 @@ test("it is possible to filter created records by dirtiness", function() { }); test("it is possible to filter created records by isReloading", function() { - set(store, 'adapter', DS.Adapter.extend({ + customAdapter(env, DS.Adapter.extend({ find: function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, @@ -550,7 +550,7 @@ var serverResponds = function() { var setup = function(serverCallbacks) { run(function() { - set(store, 'adapter', DS.Adapter.extend(serverCallbacks)); + customAdapter(env, DS.Adapter.extend(serverCallbacks)); store.pushMany('person', array); diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index 7bf95b7164e..1b1a803c6b7 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -28,15 +28,12 @@ test('Adapter can be set as a name', function() { }); test('Adapter can not be set as an instance', function() { - expect(5); + expect(1); store = DS.Store.create({ adapter: DS.Adapter.create() }); - var assert = Ember.assert; - Ember.assert = function() { ok(true, "raises an error when passing in an instance"); }; - store.get('defaultAdapter'); - Ember.assert = assert; + expectAssertion(() => store.get('defaultAdapter')); }); test("Calling Store#find invokes its adapter#find", function() { diff --git a/packages/ember-data/tests/unit/store/lookup-test.js b/packages/ember-data/tests/unit/store/lookup-test.js new file mode 100644 index 00000000000..6e942aefdc7 --- /dev/null +++ b/packages/ember-data/tests/unit/store/lookup-test.js @@ -0,0 +1,135 @@ +var store, env, applicationAdapter, applicationSerializer, Person; +const run = Ember.run; + +function resetStore() { + if (store) { + run(store, 'destroy'); + } + env = setupStore({ + adapter: '-rest', + person: Person + }); + + env.registry.unregister('adapter:application'); + env.registry.unregister('serializer:application'); + + env.registry.optionsForType('serializer', { singleton: true }); + env.registry.optionsForType('adapter', { singleton: true }); + + store = env.store; +} + +function lookupAdapter(adapterName) { + return run(store, 'adapterFor', adapterName); +} + +function lookupSerializer(serializerName) { + return run(store, 'serializerFor', serializerName); +} + +function registerAdapter(adapterName, adapter) { + env.registry.register(`adapter:${adapterName}`, adapter); +} + +function registerSerializer(serializerName, serializer) { + env.registry.register(`serializer:${serializerName}`, serializer); +} + +module('unit/store/lookup - Managed Instance lookups', { + setup() { + Person = DS.Model.extend(); + resetStore(); + env.registry.register('adapter:application', DS.Adapter.extend()); + env.registry.register('adapter:serializer', DS.Adapter.extend()); + + applicationAdapter = run(store, 'adapterFor', 'application'); + applicationSerializer = run(store, 'serializerFor', 'application'); + }, + + teardown() { + run(store, 'destroy'); + } +}); + +test('when the adapter does not exist for a type, the fallback is returned', () => { + let personAdapter = lookupAdapter('person'); + + strictEqual(personAdapter, applicationAdapter); +}); + +test('when the adapter for a type exists, returns that instead of the fallback', () => { + registerAdapter('person', DS.Adapter.extend()); + let personAdapter = lookupAdapter('person'); + + ok(personAdapter !== applicationAdapter); +}); + +test('when the serializer does not exist for a type, the fallback is returned', () => { + let personSerializer = lookupSerializer('person'); + + strictEqual(personSerializer, applicationSerializer); +}); + +test('when the serializer does exist for a type, the serializer is returned', () => { + registerSerializer('person', DS.Serializer.extend()); + + let personSerializer = lookupSerializer('person'); + + ok(personSerializer !== applicationSerializer); +}); + +test('adapter lookup order', () => { + expect(3); + + resetStore(); + + let personAdapter = lookupAdapter('person'); + + strictEqual(personAdapter, lookupAdapter('-rest'), 'looks up the RESTAdapter first'); + resetStore(); + + registerAdapter('application', DS.ActiveModelSerializer.extend()); + personAdapter = lookupAdapter('person'); + + strictEqual(personAdapter, lookupAdapter('application'), 'looks up application adapter before RESTAdapter if it exists'); + + resetStore(); + + registerAdapter('application', DS.ActiveModelSerializer.extend()); + registerAdapter('person', DS.ActiveModelSerializer.extend({ customThingy: true })); + + ok(lookupAdapter('person').get('customThingy'), 'looks up type serializer before application'); +}); + +test('serializer lookup order', () => { + resetStore(); + + let personSerializer = lookupSerializer('person'); + + strictEqual(personSerializer, lookupSerializer('-rest')); + + resetStore(); + + registerSerializer('application', DS.ActiveModelSerializer.extend()); + personSerializer = lookupSerializer('person'); + strictEqual(personSerializer, lookupSerializer('application'), 'looks up application before default'); + + resetStore(); + registerAdapter('person', DS.Adapter.extend({ + defaultSerializer: '-active-model' + })); + personSerializer = lookupSerializer('person'); + + strictEqual(personSerializer, lookupSerializer('-active-model'), 'uses defaultSerializer on adapterFor("model") if application not defined'); + + resetStore(); + registerAdapter('person', DS.Adapter.extend({ + defaultSerializer: '-active-model' + })); + registerSerializer('application', DS.ActiveModelSerializer.extend()); + registerSerializer('person', DS.JSONSerializer.extend({ customThingy: true })); + personSerializer = lookupSerializer('person'); + + ok(personSerializer.get('customThingy'), 'uses the person serializer before any fallbacks if it is defined'); +}); + diff --git a/tests/ember-configuration.js b/tests/ember-configuration.js index b0582a9eb85..1a71c4afc9a 100644 --- a/tests/ember-configuration.js +++ b/tests/ember-configuration.js @@ -67,9 +67,14 @@ } }; - var adapter = env.adapter = (options.adapter || DS.Adapter); + var adapter = env.adapter = (options.adapter || '-default'); delete options.adapter; + if (typeof adapter !== 'string') { + env.registry.register('adapter:-ember-data-test-custom', adapter); + adapter = '-ember-data-test-custom'; + } + for (var prop in options) { registry.register('model:' + Ember.String.dasherize(prop), options[prop]); } @@ -80,9 +85,12 @@ registry.optionsForType('serializer', { singleton: false }); registry.optionsForType('adapter', { singleton: false }); + registry.register('adapter:-default', DS.Adapter); registry.register('serializer:-default', DS.JSONSerializer); registry.register('serializer:-rest', DS.RESTSerializer); + registry.register('adapter:-active-model', DS.ActiveModelAdapter); + registry.register('serializer:-active-model', DS.ActiveModelSerializer); registry.register('adapter:-rest', DS.RESTAdapter); registry.injection('serializer', 'store', 'store:main'); From b795f71c87be22da3892c6cc9eca607b229c66bf Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 4 Jun 2015 12:36:40 -0400 Subject: [PATCH 0856/2527] Support for Ember 1.9's container API after `store:application` refactor. --- .../lib/instance-initializers/initialize-store-service.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/instance-initializers/initialize-store-service.js b/packages/ember-data/lib/instance-initializers/initialize-store-service.js index e685bfcca3e..638b2ed3939 100644 --- a/packages/ember-data/lib/instance-initializers/initialize-store-service.js +++ b/packages/ember-data/lib/instance-initializers/initialize-store-service.js @@ -18,7 +18,11 @@ export default function initializeStoreService(applicationOrRegistry) { // an instanceInitializer. The first argument is a registy. This // case allows ED to support Ember pre 1.12 registry = applicationOrRegistry; - container = registry.container(); + if (registry.container) { // Support Ember 1.10 - 1.11 + container = registry.container(); + } else { // Support Ember 1.9 + container = registry; + } } // Eagerly generate the store so defaultStore is populated. var store = container.lookup('store:application'); From b86afd71d2a82ca532ef66665c183ccc3a8b8ca5 Mon Sep 17 00:00:00 2001 From: Sylvain MINA Date: Thu, 28 May 2015 11:59:53 +0200 Subject: [PATCH 0857/2527] maxUrlLength -> maxURLLength --- .../ember-data/lib/adapters/rest-adapter.js | 30 +++++++++++++++---- .../group-records-for-find-many-test.js | 2 +- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest-adapter.js b/packages/ember-data/lib/adapters/rest-adapter.js index 85e4e074f1c..482e1491929 100644 --- a/packages/ember-data/lib/adapters/rest-adapter.js +++ b/packages/ember-data/lib/adapters/rest-adapter.js @@ -10,6 +10,7 @@ import { MapWithDefault } from "ember-data/system/map"; var get = Ember.get; +var set = Ember.set; var forEach = Ember.ArrayPolyfills.forEach; import BuildURLMixin from "ember-data/adapters/build-url-mixin"; @@ -170,7 +171,7 @@ import BuildURLMixin from "ember-data/adapters/build-url-mixin"; @extends DS.Adapter @uses DS.BuildURLMixin */ -export default Adapter.extend(BuildURLMixin, { +var RestAdapter = Adapter.extend(BuildURLMixin, { defaultSerializer: '-rest', /** @@ -598,7 +599,7 @@ export default Adapter.extend(BuildURLMixin, { }, // http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers - maxUrlLength: 2048, + maxURLLength: 2048, /** Organize records into groups, each of which is to be passed to separate @@ -625,21 +626,21 @@ export default Adapter.extend(BuildURLMixin, { groupRecordsForFindMany: function (store, snapshots) { var groups = MapWithDefault.create({ defaultValue: function() { return []; } }); var adapter = this; - var maxUrlLength = this.maxUrlLength; + var maxURLLength = this.maxURLLength; forEach.call(snapshots, function(snapshot) { var baseUrl = adapter._stripIDFromURL(store, snapshot); groups.get(baseUrl).push(snapshot); }); - function splitGroupToFitInUrl(group, maxUrlLength, paramNameLength) { + function splitGroupToFitInUrl(group, maxURLLength, paramNameLength) { var baseUrl = adapter._stripIDFromURL(store, group[0]); var idsSize = 0; var splitGroups = [[]]; forEach.call(group, function(snapshot) { var additionalLength = encodeURIComponent(snapshot.id).length + paramNameLength; - if (baseUrl.length + idsSize + additionalLength >= maxUrlLength) { + if (baseUrl.length + idsSize + additionalLength >= maxURLLength) { idsSize = 0; splitGroups.push([]); } @@ -656,7 +657,7 @@ export default Adapter.extend(BuildURLMixin, { var groupsArray = []; groups.forEach(function(group, key) { var paramNameLength = '&ids%5B%5D='.length; - var splitGroups = splitGroupToFitInUrl(group, maxUrlLength, paramNameLength); + var splitGroups = splitGroupToFitInUrl(group, maxURLLength, paramNameLength); forEach.call(splitGroups, function(splitGroup) { groupsArray.push(splitGroup); @@ -838,3 +839,20 @@ function endsWith(string, suffix) { return string.endsWith(suffix); } } + +if (Ember.platform.hasPropertyAccessors) { + Ember.defineProperty(RestAdapter.prototype, 'maxUrlLength', { + enumerable: false, + get: function() { + Ember.deprecate('maxUrlLength has been deprecated (wrong casing). You should use maxURLLength instead.'); + return this.maxURLLength; + }, + + set: function(value) { + Ember.deprecate('maxUrlLength has been deprecated (wrong casing). You should use maxURLLength instead.'); + set(this, 'maxURLLength', value); + } + }); +} + +export default RestAdapter; diff --git a/packages/ember-data/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/packages/ember-data/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 2de89a7561c..d59b6cb0361 100644 --- a/packages/ember-data/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/packages/ember-data/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -18,7 +18,7 @@ module("unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda }).join('&'); var fullUrl = url + '?' + queryString; - maxLength = this.get('maxUrlLength'); + maxLength = this.get('maxURLLength'); lengths.push(fullUrl.length); var testRecords = options.data.ids.map(function(id) { From d3a226f52df3e33f59b5f559f5aa0bbaae0b8afd Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 4 Jun 2015 20:54:41 -0400 Subject: [PATCH 0858/2527] Add ability to toggle feature flags to test suite. --- tests/ember-configuration.js | 3 +++ tests/qunit-configuration.js | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/ember-configuration.js b/tests/ember-configuration.js index 1a71c4afc9a..0828e61da90 100644 --- a/tests/ember-configuration.js +++ b/tests/ember-configuration.js @@ -12,6 +12,9 @@ var extendPrototypes = QUnit.urlParams.extendprototypes; ENV['EXTEND_PROTOTYPES'] = !!extendPrototypes; + // Handle testing feature flags + ENV['ENABLE_OPTIONAL_FEATURES'] = !!QUnit.urlParams.enableoptionalfeatures; + window.async = function(callback, timeout) { var timer; stop(); diff --git a/tests/qunit-configuration.js b/tests/qunit-configuration.js index fec07e42416..77aa757a5a4 100644 --- a/tests/qunit-configuration.js +++ b/tests/qunit-configuration.js @@ -1,6 +1,6 @@ (function() { /*global namespace: true */ - + window.EmberDev = window.EmberDev || {}; EmberDev.afterEach = function() { @@ -171,6 +171,9 @@ }; }()); + // Handle testing feature flags + QUnit.config.urlConfig.push({ id: 'enableoptionalfeatures', label: "Enable Opt Features"}); + // A light class for stubbing // function MethodCallExpectation(target, property){ From d7d3a887c84a46ff1ebd0b320cfeeb34eb8cc428 Mon Sep 17 00:00:00 2001 From: Teddy Zeenny Date: Thu, 4 Jun 2015 19:46:29 +0300 Subject: [PATCH 0859/2527] Use string model names in debug adapter --- .../lib/system/debug/debug-adapter.js | 18 +++++++++++++----- .../tests/integration/debug-adapter-test.js | 16 ++++++++++++---- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/packages/ember-data/lib/system/debug/debug-adapter.js b/packages/ember-data/lib/system/debug/debug-adapter.js index fb81957483a..ee2ed753f23 100644 --- a/packages/ember-data/lib/system/debug/debug-adapter.js +++ b/packages/ember-data/lib/system/debug/debug-adapter.js @@ -5,6 +5,7 @@ import Model from "ember-data/system/model"; var get = Ember.get; var capitalize = Ember.String.capitalize; var underscore = Ember.String.underscore; +const { assert } = Ember; /** Extend `Ember.DataAdapter` with ED specific code. @@ -42,11 +43,18 @@ export default Ember.DataAdapter.extend({ return columns; }, - getRecords: function(modelNameOrFactory) { - // TODO: Ask Teddy what we should do here. - // Ideally this should always get passed a string. - - var modelName = typeof modelNameOrFactory === 'string' ? modelNameOrFactory : modelNameOrFactory.modelName; + getRecords: function(modelClass, modelName) { + if (arguments.length < 2) { + // Legacy Ember.js < 1.13 support + let containerKey = modelClass._debugContainerKey; + if (containerKey) { + let match = containerKey.match(/model:(.*)/); + if (match) { + modelName = match[1]; + } + } + } + assert("Cannot find model name. Please upgrade to Ember.js >= 1.13 for Ember Inspector support", !!modelName); return this.get('store').all(modelName); }, diff --git a/packages/ember-data/tests/integration/debug-adapter-test.js b/packages/ember-data/tests/integration/debug-adapter-test.js index 1bada903bd8..34f7356628f 100644 --- a/packages/ember-data/tests/integration/debug-adapter-test.js +++ b/packages/ember-data/tests/integration/debug-adapter-test.js @@ -15,8 +15,10 @@ module("DS.DebugAdapter", { App.Post = DS.Model.extend({ title: DS.attr('string') }); + + // TODO: Remove this when Ember is upgraded to >= 1.13 App.Post.reopenClass({ - modelName: 'post' + _debugContainerKey: 'model:post' }); }); @@ -26,7 +28,7 @@ module("DS.DebugAdapter", { debugAdapter.reopen({ getModelTypes: function() { - return Ember.A([{ klass: App.__container__.lookupFactory('model:post'), name: 'App.Post' }]); + return Ember.A([{ klass: App.__container__.lookupFactory('model:post'), name: 'post' }]); } }); }, @@ -40,7 +42,7 @@ test("Watching Model Types", function() { var added = function(types) { equal(types.length, 1); - equal(types[0].name, 'App.Post'); + equal(types[0].name, 'post'); equal(types[0].count, 0); strictEqual(types[0].object, store.modelFor('post')); }; @@ -74,7 +76,13 @@ test("Watching Records", function() { removedCount = count; }; - debugAdapter.watchRecords(App.__container__.lookupFactory('model:post'), recordsAdded, recordsUpdated, recordsRemoved); + let modelClassOrName; + if (debugAdapter.get('acceptsModelName')) { + modelClassOrName = 'post'; + } else { + modelClassOrName = App.__container__.lookupFactory('model:post'); + } + debugAdapter.watchRecords(modelClassOrName, recordsAdded, recordsUpdated, recordsRemoved); equal(get(addedRecords, 'length'), 1); record = addedRecords[0]; From a5e4df6d5fe272664a2353cdb28a66110df2fd75 Mon Sep 17 00:00:00 2001 From: Marek Fajkus Date: Fri, 27 Mar 2015 13:17:24 +0100 Subject: [PATCH 0860/2527] handle pushes on invalid record --- .../ember-data/lib/system/model/states.js | 2 ++ .../ember-data/tests/unit/model/merge-test.js | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index f6b32e73391..36379760528 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -333,6 +333,8 @@ var DirtyState = { becomeDirty: Ember.K, + pushedData: Ember.K, + willCommit: function(internalModel) { internalModel.getErrors().clear(); internalModel.transitionTo('inFlight'); diff --git a/packages/ember-data/tests/unit/model/merge-test.js b/packages/ember-data/tests/unit/model/merge-test.js index df3bfee770c..b768d54c3ca 100644 --- a/packages/ember-data/tests/unit/model/merge-test.js +++ b/packages/ember-data/tests/unit/model/merge-test.js @@ -146,6 +146,34 @@ test("When a record is dirty, pushes are overridden by local changes", function( equal(person.get('city'), "Portland", "if there are no local changes, the new data applied"); }); +test("When a record is invalid, pushes are overridden by local changes", function() { + var store = createStore({ + adapter: DS.Adapter, + person: Person + }); + var person; + + run(function() { + person = store.push('person', { id: 1, name: "Brendan McLoughlin", city: "Boston" }); + person.set('name', "Brondan McLoughlin"); + person.send('becameInvalid'); + }); + + equal(person.get('isDirty'), true, "the person is currently dirty"); + equal(person.get('isValid'), false, "the person is currently invalid"); + equal(person.get('name'), "Brondan McLoughlin", "the update was effective"); + equal(person.get('city'), "Boston", "the original data applies"); + + run(function() { + store.push('person', { id: 1, name: "bmac", city: "Prague" }); + }); + + equal(person.get('isDirty'), true, "the local changes are reapplied"); + equal(person.get('isValid'), false, "record is still invalid"); + equal(person.get('name'), "Brondan McLoughlin", "the local changes are reapplied"); + equal(person.get('city'), "Prague", "if there are no local changes, the new data applied"); +}); + test("A record with no changes can still be saved", function() { expect(1); From 81061075d43d35c75a789818ec482048fa13b2bd Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 4 Jun 2015 22:04:28 -0500 Subject: [PATCH 0861/2527] lookup JSONSerializer instance through store instead of manual instantiation --- packages/ember-data/lib/system/model/model.js | 3 +- packages/ember-data/tests/unit/model-test.js | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 7879b8f74fb..65dcf173154 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -1,5 +1,4 @@ import { PromiseObject } from "ember-data/system/promise-proxies"; -import JSONSerializer from "ember-data/serializers/json-serializer"; /** @module ember-data @@ -375,7 +374,7 @@ var Model = Ember.Object.extend(Ember.Evented, { */ toJSON: function(options) { // container is for lazy transform lookups - var serializer = JSONSerializer.create({ container: this.container }); + var serializer = this.store.serializerFor('-default'); var snapshot = this._internalModel.createSnapshot(); return serializer.serialize(snapshot, options); diff --git a/packages/ember-data/tests/unit/model-test.js b/packages/ember-data/tests/unit/model-test.js index e41eb4a38fc..4e0b70f672c 100644 --- a/packages/ember-data/tests/unit/model-test.js +++ b/packages/ember-data/tests/unit/model-test.js @@ -833,3 +833,39 @@ test("A subclass of DS.Model throws an error when calling create() directly", fu Person.create(); }, /You should not call `create` on a model/, "Throws an error when calling create() on model"); }); + +test('toJSON looks up the JSONSerializer using the store instead of using JSONSerializer.create', function() { + var Person = DS.Model.extend({ + posts: DS.hasMany('post') + }); + var Post = DS.Model.extend({ + person: DS.belongsTo('person') + }); + + var env = setupStore({ + person: Person, + post: Post + }); + var store = env.store; + + var person, json; + // Loading the person without explicitly + // loading its relationships seems to trigger the + // original bug where `this.store` was not + // present on the serializer due to using .create + // instead of `store.serializerFor`. + run(() => { + person = store.push('person', { + id: 1 + }); + }); + var errorThrown = false; + try { + json = run(person, 'toJSON'); + } catch (e) { + errorThrown = true; + } + + ok(!errorThrown, 'error not thrown due to missing store'); + deepEqual(json, {}); +}); From 87e4767d085f2587b7a4ef0b108b786c681e0cfc Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 3 Jun 2015 10:06:10 +0200 Subject: [PATCH 0862/2527] transforms: Adjust code samples to ember-cli --- packages/ember-data/lib/transforms/base.js | 17 ++++++++++------- packages/ember-data/lib/transforms/boolean.js | 13 +++++++------ packages/ember-data/lib/transforms/date.js | 11 ++++++----- packages/ember-data/lib/transforms/number.js | 11 ++++++----- packages/ember-data/lib/transforms/string.js | 13 +++++++------ 5 files changed, 36 insertions(+), 29 deletions(-) diff --git a/packages/ember-data/lib/transforms/base.js b/packages/ember-data/lib/transforms/base.js index e275f8d71d3..252c35519b9 100644 --- a/packages/ember-data/lib/transforms/base.js +++ b/packages/ember-data/lib/transforms/base.js @@ -7,9 +7,11 @@ Example - ```javascript + ```app/transforms/temperature.js + import DS from 'ember-data'; + // Converts centigrade in the JSON to fahrenheit in the app - App.TemperatureTransform = DS.Transform.extend({ + export default DS.Transform.extend({ deserialize: function(serialized) { return (serialized * 1.8) + 32; }, @@ -21,11 +23,12 @@ Usage - ```javascript - var attr = DS.attr; - App.Requirement = DS.Model.extend({ - name: attr('string'), - temperature: attr('temperature') + ```app/models/requirement.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + name: DS.attr('string'), + temperature: DS.attr('temperature') }); ``` diff --git a/packages/ember-data/lib/transforms/boolean.js b/packages/ember-data/lib/transforms/boolean.js index 69f72819f2a..c054f395d9c 100644 --- a/packages/ember-data/lib/transforms/boolean.js +++ b/packages/ember-data/lib/transforms/boolean.js @@ -8,12 +8,13 @@ import Transform from "ember-data/transforms/base"; Usage - ```javascript - var attr = DS.attr; - App.User = DS.Model.extend({ - isAdmin: attr('boolean'), - name: attr('string'), - email: attr('string') + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + isAdmin: DS.attr('boolean'), + name: DS.attr('string'), + email: DS.attr('string') }); ``` diff --git a/packages/ember-data/lib/transforms/date.js b/packages/ember-data/lib/transforms/date.js index a3d64b196b0..e674e389ebc 100644 --- a/packages/ember-data/lib/transforms/date.js +++ b/packages/ember-data/lib/transforms/date.js @@ -4,12 +4,13 @@ when `date` is passed as the type parameter to the [DS.attr](../../data#method_attr) function. - ```javascript - var attr = DS.attr; - App.Score = DS.Model.extend({ - value: attr('number'), + ```app/models/score.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + value: DS.attr('number'), player: DS.belongsTo('player'), - date: attr('date') + date: DS.attr('date') }); ``` diff --git a/packages/ember-data/lib/transforms/number.js b/packages/ember-data/lib/transforms/number.js index 118a26d2613..6463756fc1f 100644 --- a/packages/ember-data/lib/transforms/number.js +++ b/packages/ember-data/lib/transforms/number.js @@ -14,12 +14,13 @@ function isNumber(value) { Usage - ```javascript - var attr = DS.attr; - App.Score = DS.Model.extend({ - value: attr('number'), + ```app/models/score.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + value: DS.attr('number'), player: DS.belongsTo('player'), - date: attr('date') + date: DS.attr('date') }); ``` diff --git a/packages/ember-data/lib/transforms/string.js b/packages/ember-data/lib/transforms/string.js index 180a1973590..edce67db6a7 100644 --- a/packages/ember-data/lib/transforms/string.js +++ b/packages/ember-data/lib/transforms/string.js @@ -9,12 +9,13 @@ var none = Ember.isNone; Usage - ```javascript - var attr = DS.attr; - App.User = DS.Model.extend({ - isAdmin: attr('boolean'), - name: attr('string'), - email: attr('string') + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + isAdmin: DS.attr('boolean'), + name: DS.attr('string'), + email: DS.attr('string') }); ``` From 2b796c7ff705f35629e3959a3f786a6372815a66 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 3 Jun 2015 10:31:07 +0200 Subject: [PATCH 0863/2527] serializers: Adjust code samples to ember-cli --- .../lib/serializers/embedded-records-mixin.js | 24 ++-- .../lib/serializers/json-serializer.js | 128 ++++++++++++------ .../lib/serializers/rest-serializer.js | 76 +++++++---- 3 files changed, 151 insertions(+), 77 deletions(-) diff --git a/packages/ember-data/lib/serializers/embedded-records-mixin.js b/packages/ember-data/lib/serializers/embedded-records-mixin.js index 1fe96c6c068..d61102408ae 100644 --- a/packages/ember-data/lib/serializers/embedded-records-mixin.js +++ b/packages/ember-data/lib/serializers/embedded-records-mixin.js @@ -11,8 +11,10 @@ var camelize = Ember.String.camelize; Below is an example of a per-type serializer ('post' type). - ```js - App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { author: { embedded: 'always' }, comments: { serialize: 'ids' } @@ -152,8 +154,10 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ Use a custom (type) serializer for the post model to configure embedded author - ```js - App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + ```app/serializers/post.js + import DS from 'ember-data; + + export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { author: {embedded: 'always'} } @@ -229,8 +233,10 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ Use a custom (type) serializer for the post model to configure embedded comments - ```js - App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + ```app/serializers/post.js + import DS from 'ember-data; + + export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { comments: {embedded: 'always'} } @@ -266,8 +272,10 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ To embed the `ids` for a related object (using a hasMany relationship): - ```js - App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + ```app/serializers/post.js + import DS from 'ember-data; + + export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { comments: {serialize: 'ids', deserialize: 'records'} } diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index 8e39c68cf09..ee50f533d8c 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -32,8 +32,10 @@ export default Serializer.extend({ Example - ```javascript - App.ApplicationSerializer = DS.JSONSerializer.extend({ + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ primaryKey: '_id' }); ``` @@ -53,15 +55,21 @@ export default Serializer.extend({ Example - ```javascript - App.Person = DS.Model.extend({ + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), occupation: DS.attr('string'), admin: DS.attr('boolean') }); + ``` - App.PersonSerializer = DS.JSONSerializer.extend({ + ```app/serializers/person.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ attrs: { admin: 'is_admin', occupation: {key: 'career'} @@ -74,8 +82,10 @@ export default Serializer.extend({ Example - ```javascript - App.PersonSerializer = DS.JSONSerializer.extend({ + ```app/serializers/person.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ attrs: { admin: {serialize: false}, occupation: {key: 'career'} @@ -138,8 +148,10 @@ export default Serializer.extend({ Example - ```javascript - App.ApplicationSerializer = DS.JSONSerializer.extend({ + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ normalize: function(typeClass, hash) { var fields = Ember.get(typeClass, 'fields'); fields.forEach(function(field) { @@ -177,8 +189,10 @@ export default Serializer.extend({ For example, you might want to remove some extraneous data from the payload: - ```js - App.ApplicationSerializer = DS.JSONSerializer.extend({ + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ normalizePayload: function(payload) { delete payload.version; delete payload.status; @@ -330,8 +344,10 @@ export default Serializer.extend({ For example, consider this model: - ```javascript - App.Comment = DS.Model.extend({ + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ title: DS.attr(), body: DS.attr(), @@ -374,8 +390,10 @@ export default Serializer.extend({ In that case, you can implement `serialize` yourself and return a JSON hash of your choosing. - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ serialize: function(snapshot, options) { var json = { POST_TTL: snapshot.attr('title'), @@ -398,8 +416,10 @@ export default Serializer.extend({ application, you'll probably want to use `eachAttribute` and `eachRelationship` on the record. - ```javascript - App.ApplicationSerializer = DS.JSONSerializer.extend({ + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ serialize: function(snapshot, options) { var json = {}; @@ -446,8 +466,10 @@ export default Serializer.extend({ you can call super first and make the tweaks on the returned JSON. - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ serialize: function(snapshot, options) { var json = this._super.apply(this, arguments); @@ -499,8 +521,10 @@ export default Serializer.extend({ For example, your server may expect underscored root objects. - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ serializeIntoHash: function(data, type, snapshot, options) { var root = Ember.String.decamelize(type.modelName); data[root] = this.serialize(snapshot, options); @@ -526,8 +550,10 @@ export default Serializer.extend({ serialized as properties on an `attributes` object you could write: - ```javascript - App.ApplicationSerializer = DS.JSONSerializer.extend({ + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ serializeAttribute: function(snapshot, json, key, attributes) { json.attributes = json.attributes || {}; this._super(snapshot, json.attributes, key, attributes); @@ -569,8 +595,10 @@ export default Serializer.extend({ Example - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ serializeBelongsTo: function(snapshot, json, relationship) { var key = relationship.key; @@ -620,8 +648,10 @@ export default Serializer.extend({ Example - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ serializeHasMany: function(snapshot, json, relationship) { var key = relationship.key; if (key === 'comments') { @@ -668,8 +698,10 @@ export default Serializer.extend({ Example - ```javascript - App.CommentSerializer = DS.JSONSerializer.extend({ + ```app/serializers/comment.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ serializePolymorphicType: function(snapshot, json, relationship) { var key = relationship.key, belongsTo = snapshot.belongsTo(key); @@ -682,7 +714,7 @@ export default Serializer.extend({ } } }); - ``` + ``` @method serializePolymorphicType @param {DS.Snapshot} snapshot @@ -904,8 +936,10 @@ export default Serializer.extend({ Example - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ extractSingle: function(store, typeClass, payload) { payload.comments = payload._embedded.comment; delete payload._embedded; @@ -934,8 +968,10 @@ export default Serializer.extend({ Example - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ extractArray: function(store, typeClass, payload) { return payload.map(function(json) { return this.extractSingle(store, typeClass, json); @@ -968,8 +1004,10 @@ export default Serializer.extend({ Example - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ extractMeta: function(store, typeClass, payload) { if (payload && payload._pagination) { store.setMetadataFor(typeClass, payload._pagination); @@ -999,8 +1037,10 @@ export default Serializer.extend({ Example - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ extractErrors: function(store, typeClass, payload, id) { if (payload && typeof payload === 'object' && payload._problems) { payload = payload._problems; @@ -1032,8 +1072,10 @@ export default Serializer.extend({ Example - ```javascript - App.ApplicationSerializer = DS.RESTSerializer.extend({ + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ keyForAttribute: function(attr, method) { return Ember.String.underscore(attr).toUpperCase(); } @@ -1056,8 +1098,10 @@ export default Serializer.extend({ Example - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ keyForRelationship: function(key, relationship, method) { return 'rel_' + Ember.String.underscore(key); } diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index ddf2902549f..8f084246e37 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -35,8 +35,10 @@ var camelize = Ember.String.camelize; can implement across-the-board rules for how to convert an attribute name in your model to a key in your JSON. - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ keyForAttribute: function(attr, method) { return Ember.String.underscore(attr).toUpperCase(); } @@ -79,8 +81,10 @@ var RESTSerializer = JSONSerializer.extend({ You use `normalizeHash` to normalize just the comments: - ```javascript - App.PostSerializer = DS.RESTSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ normalizeHash: { comments: function(hash) { hash.id = hash._id; @@ -145,8 +149,10 @@ var RESTSerializer = JSONSerializer.extend({ For example, if the `IDs` under `"comments"` are provided as `_id` instead of `id`, you can specify how to normalize just the comments: - ```js - App.PostSerializer = DS.RESTSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ normalizeHash: { comments: function(hash) { hash.id = hash._id; @@ -215,8 +221,10 @@ var RESTSerializer = JSONSerializer.extend({ You could implement a serializer that looks like this to get your payload into shape: - ```js - App.PostSerializer = DS.RESTSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ // First, restructure the top-level so it's organized by type extractSingle: function(store, typeClass, payload, id) { var comments = payload._embedded.comment; @@ -345,8 +353,10 @@ var RESTSerializer = JSONSerializer.extend({ You could implement a serializer that looks like this to get your payload into shape: - ```js - App.PostSerializer = DS.RESTSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ // First, restructure the top-level so it's organized by type // and the comments are listed under a post's `comments` key. extractArray: function(store, type, payload) { @@ -514,10 +524,11 @@ var RESTSerializer = JSONSerializer.extend({ the name of the model in your app. Let's take a look at an example model, and an example payload: - ```javascript - // Located in the file app/models/post.js + ```app/models/post.js import DS from 'ember-data'; - export default var Post = DS.Model.extend(); + + export default DS.Model.extend({ + }); ``` ```javascript @@ -536,8 +547,7 @@ var RESTSerializer = JSONSerializer.extend({ Since we want to remove this namespace, we can define a serializer for the application that will remove "blog/" from the payload key whenver it's encountered by Ember Data: - ```javascript - // located in app/serializers/application.js + ```app/serializers/application.js import DS from 'ember-data'; export default DS.RESTSerializer.extend({ @@ -578,8 +588,10 @@ var RESTSerializer = JSONSerializer.extend({ For example, consider this model: - ```js - App.Comment = DS.Model.extend({ + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ title: DS.attr(), body: DS.attr(), @@ -622,8 +634,10 @@ var RESTSerializer = JSONSerializer.extend({ In that case, you can implement `serialize` yourself and return a JSON hash of your choosing. - ```js - App.PostSerializer = DS.RESTSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ serialize: function(snapshot, options) { var json = { POST_TTL: snapshot.attr('title'), @@ -646,8 +660,10 @@ var RESTSerializer = JSONSerializer.extend({ application, you'll probably want to use `eachAttribute` and `eachRelationship` on the record. - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ serialize: function(snapshot, options) { var json = {}; @@ -694,8 +710,10 @@ var RESTSerializer = JSONSerializer.extend({ you can call super first and make the tweaks on the returned JSON. - ```js - App.PostSerializer = DS.RESTSerializer.extend({ + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ serialize: function(snapshot, options) { var json = this._super(snapshot, options); @@ -723,8 +741,10 @@ var RESTSerializer = JSONSerializer.extend({ For example, your server may expect underscored root objects. - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ serializeIntoHash: function(data, type, record, options) { var root = Ember.String.decamelize(type.modelName); data[root] = this.serialize(record, options); @@ -762,8 +782,10 @@ var RESTSerializer = JSONSerializer.extend({ For example, your server may expect dasherized root objects: - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ payloadKeyFromModelName: function(modelName) { return Ember.String.dasherize(modelName); } From b2833406af80396cdd52406c1aa46aff93dffb07 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 3 Jun 2015 10:47:12 +0200 Subject: [PATCH 0864/2527] adapters: Adjust code samples to ember-cli --- .../lib/adapters/build-url-mixin.js | 6 +- .../ember-data/lib/adapters/rest-adapter.js | 64 +++++++++++++------ 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/packages/ember-data/lib/adapters/build-url-mixin.js b/packages/ember-data/lib/adapters/build-url-mixin.js index c8f556617b1..667bb925afc 100644 --- a/packages/ember-data/lib/adapters/build-url-mixin.js +++ b/packages/ember-data/lib/adapters/build-url-mixin.js @@ -250,8 +250,10 @@ export default Ember.Mixin.create({ For example if you have an object LineItem with an endpoint of "/line_items/". - ```js - App.ApplicationAdapter = DS.RESTAdapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ pathForType: function(modelName) { var decamelized = Ember.String.decamelize(modelName); return Ember.String.pluralize(decamelized); diff --git a/packages/ember-data/lib/adapters/rest-adapter.js b/packages/ember-data/lib/adapters/rest-adapter.js index 482e1491929..12722f2ea67 100644 --- a/packages/ember-data/lib/adapters/rest-adapter.js +++ b/packages/ember-data/lib/adapters/rest-adapter.js @@ -71,8 +71,10 @@ import BuildURLMixin from "ember-data/adapters/build-url-mixin"; For example, if you have a `Person` model: - ```js - App.Person = DS.Model.extend({ + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), occupation: DS.attr('string') @@ -99,8 +101,10 @@ import BuildURLMixin from "ember-data/adapters/build-url-mixin"; Endpoint paths can be prefixed with a `namespace` by setting the namespace property on the adapter: - ```js - App.ApplicationAdapter = DS.RESTAdapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ namespace: 'api/1' }); ``` @@ -110,8 +114,10 @@ import BuildURLMixin from "ember-data/adapters/build-url-mixin"; An adapter can target other hosts by setting the `host` property. - ```js - App.ApplicationAdapter = DS.RESTAdapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ host: 'https://api.example.com' }); ``` @@ -123,8 +129,10 @@ import BuildURLMixin from "ember-data/adapters/build-url-mixin"; object and Ember Data will send them along with each ajax request. - ```js - App.ApplicationAdapter = DS.RESTAdapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ headers: { "API_KEY": "secret key", "ANOTHER_HEADER": "Some header value" @@ -136,8 +144,10 @@ import BuildURLMixin from "ember-data/adapters/build-url-mixin"; headers. In the example below, the `session` object has been injected into an adapter by Ember's container. - ```js - App.ApplicationAdapter = DS.RESTAdapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ headers: function() { return { "API_KEY": this.get("session.authToken"), @@ -154,8 +164,10 @@ import BuildURLMixin from "ember-data/adapters/build-url-mixin"; function to set the property into a non-cached mode causing the headers to be recomputed with every request. - ```js - App.ApplicationAdapter = DS.RESTAdapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ headers: function() { return { "API_KEY": Ember.get(document.cookie.match(/apiKey\=([^;]*)/), "1"), @@ -195,7 +207,9 @@ var RestAdapter = Adapter.extend(BuildURLMixin, { In case you want to sort the query parameters with a different criteria, set `sortQueryParams` to your custom sort function. - ```js + ```app/adapters/application.js + import DS from 'ember-data'; + export default DS.RESTAdapter.extend({ sortQueryParams: function(params) { var sortedKeys = Object.keys(params).sort().reverse(); @@ -281,8 +295,10 @@ var RestAdapter = Adapter.extend(BuildURLMixin, { Endpoint paths can be prefixed with a `namespace` by setting the namespace property on the adapter: - ```javascript - App.ApplicationAdapter = DS.RESTAdapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ namespace: 'api/1' }); ``` @@ -296,8 +312,10 @@ var RestAdapter = Adapter.extend(BuildURLMixin, { /** An adapter can target other hosts by setting the `host` property. - ```javascript - App.ApplicationAdapter = DS.RESTAdapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ host: 'https://api.example.com' }); ``` @@ -315,8 +333,10 @@ var RestAdapter = Adapter.extend(BuildURLMixin, { along with each ajax request. For dynamic headers see [headers customization](/api/data/classes/DS.RESTAdapter.html#toc_headers-customization). - ```javascript - App.ApplicationAdapter = DS.RESTAdapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ headers: { "API_KEY": "secret key", "ANOTHER_HEADER": "Some header value" @@ -680,8 +700,10 @@ var RestAdapter = Adapter.extend(BuildURLMixin, { Example - ```javascript - App.ApplicationAdapter = DS.RESTAdapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ ajaxError: function(jqXHR) { var error = this._super(jqXHR); From 09b20c78427bd1d3f97978efd2de82960a55aadb Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 3 Jun 2015 10:53:32 +0200 Subject: [PATCH 0865/2527] system/adapter: Adjust code samples to ember-cli --- packages/ember-data/lib/system/adapter.js | 71 ++++++++++++++--------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 68274a76d79..4c4149e7b63 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -16,26 +16,25 @@ var get = Ember.get; ### Creating an Adapter - Create a new subclass of `DS.Adapter`, then assign - it to the `ApplicationAdapter` property of the application. + Create a new subclass of `DS.Adapter` in the `app/adapters` folder: - ```javascript - var MyAdapter = DS.Adapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ // ...your code here }); - - App.ApplicationAdapter = MyAdapter; ``` - Model-specific adapters can be created by assigning your adapter - class to the `ModelName` + `Adapter` property of the application. + Model-specific adapters can be created by putting your adapter + class in an `app/adapters/` + `model-name` + `.js` file of the application. + + ```app/adapters/post.js + import DS from 'ember-data'; - ```javascript - var MyPostAdapter = DS.Adapter.extend({ + export default DS.Adapter.extend({ // ...Post-specific adapter code goes here }); - - App.PostAdapter = MyPostAdapter; ``` `DS.Adapter` is an abstract base class that you should override in your @@ -74,8 +73,10 @@ var Adapter = Ember.Object.extend({ a model specific serializer (i.e. `PostSerializer`) or the `application` serializer. - ```javascript - var DjangoAdapter = DS.Adapter.extend({ + ```app/adapters/django.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ defaultSerializer: 'django' }); ``` @@ -94,8 +95,10 @@ var Adapter = Ember.Object.extend({ Here is an example `find` implementation: - ```javascript - App.ApplicationAdapter = DS.Adapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ find: function(store, type, id, snapshot) { var url = [type.modelName, id].join('/'); @@ -126,8 +129,10 @@ var Adapter = Ember.Object.extend({ Example - ```javascript - App.ApplicationAdapter = DS.Adapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ findAll: function(store, type, sinceToken) { var url = type; var query = { since: sinceToken }; @@ -159,8 +164,10 @@ var Adapter = Ember.Object.extend({ Example - ```javascript - App.ApplicationAdapter = DS.Adapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ findQuery: function(store, type, query) { var url = type; return new Ember.RSVP.Promise(function(resolve, reject) { @@ -220,8 +227,10 @@ var Adapter = Ember.Object.extend({ Example - ```javascript - App.ApplicationAdapter = DS.Adapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ createRecord: function(store, type, snapshot) { var data = this.serialize(snapshot, { includeId: true }); var url = type; @@ -248,8 +257,10 @@ var Adapter = Ember.Object.extend({ Example - ```javascript - App.ApplicationAdapter = DS.Adapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ createRecord: function(store, type, snapshot) { var data = this.serialize(snapshot, { includeId: true }); var url = type; @@ -287,8 +298,10 @@ var Adapter = Ember.Object.extend({ Example - ```javascript - App.ApplicationAdapter = DS.Adapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ updateRecord: function(store, type, snapshot) { var data = this.serialize(snapshot, { includeId: true }); var id = snapshot.id; @@ -327,8 +340,10 @@ var Adapter = Ember.Object.extend({ Example - ```javascript - App.ApplicationAdapter = DS.Adapter.extend({ + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ deleteRecord: function(store, type, snapshot) { var data = this.serialize(snapshot, { includeId: true }); var id = snapshot.id; From 36ee20c5525f4c712e4da9b0b967c486dddcee14 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 3 Jun 2015 10:59:19 +0200 Subject: [PATCH 0866/2527] system/many-array: Adjust code samples to ember-cli --- packages/ember-data/lib/system/many-array.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/many-array.js b/packages/ember-data/lib/system/many-array.js index 9ac12443f91..9ebd8a7503c 100644 --- a/packages/ember-data/lib/system/many-array.js +++ b/packages/ember-data/lib/system/many-array.js @@ -21,12 +21,18 @@ var map = Ember.EnumerableUtils.map; an inverse. For example, imagine the following models are defined: - ```javascript - App.Post = DS.Model.extend({ + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ comments: DS.hasMany('comment') }); + ``` + + ```app/models/comment.js + import DS from 'ember-data'; - App.Comment = DS.Model.extend({ + export default DS.Model.extend({ post: DS.belongsTo('post') }); ``` From 92401c8b3692c22dc6d37f29525389ca959e6ff5 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 5 Jun 2015 09:45:13 +0200 Subject: [PATCH 0867/2527] system/store: Adjust code samples to ember-cli --- packages/ember-data/lib/system/store.js | 54 ++++++++++++++++++------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 53c19974ae1..3ad0739a28e 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -141,8 +141,11 @@ if (!Service) { Define your application's store like this: - ```javascript - MyApp.ApplicationStore = DS.Store.extend(); + ```app/stores/application.js + import DS from 'ember-data'; + + export default DS.Store.extend({ + }); ``` Most Ember.js applications will only have a single `DS.Store` that is @@ -160,8 +163,11 @@ if (!Service) { REST mechanism. You can customize how the store talks to your backend by specifying a custom adapter: - ```javascript - MyApp.ApplicationAdapter = MyApp.CustomAdapter + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + }); ``` You can learn more about writing a custom adapter by reading the `DS.Adapter` @@ -224,7 +230,7 @@ Store = Service.extend({ This can be specified as an instance, class, or string. - If you want to specify `App.CustomAdapter` as a string, do: + If you want to specify `app/adapters/custom.js` as a string, do: ```js adapter: 'custom' @@ -537,8 +543,10 @@ Store = Service.extend({ Example - ```javascript - App.PostRoute = Ember.Route.extend({ + ```app/routes/post.js + import Ember from 'ember'; + + export default Ember.Route.extend({ model: function(params) { return this.store.fetchById('post', params.post_id); } @@ -1531,8 +1539,10 @@ Store = Service.extend({ For this model: - ```js - App.Person = DS.Model.extend({ + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ firstName: DS.attr(), lastName: DS.attr(), @@ -1645,9 +1655,13 @@ Store = Service.extend({ All objects should be in the format expected by the serializer. - ```js - App.ApplicationSerializer = DS.ActiveModelSerializer; + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.ActiveModelSerializer; + ``` + ```js var pushData = { posts: [ {id: 1, post_title: "Great post", comment_ids: [2]} @@ -1669,11 +1683,21 @@ Store = Service.extend({ `normalizePayload`) will not know which model it is deserializing. + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.ActiveModelSerializer; + ``` + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer; + ``` + ```js - App.ApplicationSerializer = DS.ActiveModelSerializer; - App.PostSerializer = DS.JSONSerializer; - store.pushPayload('comment', pushData); // Will use the ApplicationSerializer - store.pushPayload('post', pushData); // Will use the PostSerializer + store.pushPayload('comment', pushData); // Will use the application serializer + store.pushPayload('post', pushData); // Will use the post serializer ``` @method pushPayload From 97f39acbe5b67157a3077e4ed124290625f00576 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 5 Jun 2015 09:55:52 +0200 Subject: [PATCH 0868/2527] system/model: Adjust code samples to ember-cli --- .../ember-data/lib/system/model/attributes.js | 55 ++++++++++++------- .../ember-data/lib/system/model/errors.js | 30 +++++++--- .../lib/system/model/errors/invalid.js | 20 +++++-- .../lib/system/model/internal-model.js | 25 ++++++--- packages/ember-data/lib/system/model/model.js | 27 ++++++--- 5 files changed, 105 insertions(+), 52 deletions(-) diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index fcbd7ce8006..1e46603be47 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -23,15 +23,21 @@ Model.reopenClass({ Example - ```javascript + ```app/models/person.js + import DS from 'ember-data'; - App.Person = DS.Model.extend({ + export default DS.Model.extend({ firstName: attr('string'), lastName: attr('string'), birthday: attr('date') }); + ``` + + ```javascript + import Ember from 'ember'; + import Person from 'app/models/person'; - var attributes = Ember.get(App.Person, 'attributes') + var attributes = Ember.get(Person, 'attributes') attributes.forEach(function(name, meta) { console.log(name, meta); @@ -71,14 +77,21 @@ Model.reopenClass({ Example - ```javascript - App.Person = DS.Model.extend({ + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ firstName: attr(), lastName: attr('string'), birthday: attr('date') }); + ``` - var transformedAttributes = Ember.get(App.Person, 'transformedAttributes') + ```javascript + import Ember from 'ember'; + import Person from 'app/models/person'; + + var transformedAttributes = Ember.get(Person, 'transformedAttributes') transformedAttributes.forEach(function(field, type) { console.log(field, type); @@ -126,13 +139,15 @@ Model.reopenClass({ Example ```javascript - App.Person = DS.Model.extend({ + import DS from 'ember-data'; + + var Person = DS.Model.extend({ firstName: attr('string'), lastName: attr('string'), birthday: attr('date') }); - App.Person.eachAttribute(function(name, meta) { + Person.eachAttribute(function(name, meta) { console.log(name, meta); }); @@ -175,13 +190,15 @@ Model.reopenClass({ Example ```javascript - App.Person = DS.Model.extend({ + import DS from 'ember-data'; + + var Person = DS.Model.extend({ firstName: attr(), lastName: attr('string'), birthday: attr('date') }); - App.Person.eachTransformedAttribute(function(name, type) { + Person.eachTransformedAttribute(function(name, type) { console.log(name, type); }); @@ -251,23 +268,23 @@ function getValue(record, key) { Example - ```javascript - var attr = DS.attr; + ```app/models/user.js + import DS from 'ember-data'; - App.User = DS.Model.extend({ - username: attr('string'), - email: attr('string'), - verified: attr('boolean', {defaultValue: false}) + export default DS.Model.extend({ + username: DS.attr('string'), + email: DS.attr('string'), + verified: DS.attr('boolean', {defaultValue: false}) }); ``` Default value can also be a function. This is useful it you want to return a new object for each attribute. - ```javascript - var attr = DS.attr; + ```app/models/user.js + import DS from 'ember-data'; - App.User = DS.Model.extend({ + export default DS.Model.extend({ username: attr('string'), email: attr('string'), settings: attr({defaultValue: function() { diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index 6cbb3c11f78..80818a19090 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -22,8 +22,10 @@ import { For Example, if you had an `User` model that looked like this: - ```javascript - App.User = DS.Model.extend({ + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ username: attr('string'), email: attr('string') }); @@ -262,14 +264,20 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { Example: - ```javascript - App.User = DS.Model.extend({ + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ email: DS.attr('string'), twoFactorAuth: DS.attr('boolean'), phone: DS.attr('string') }); + ``` - App.UserEditRoute = Ember.Route.extend({ + ```app/routes/user/edit.js + import Ember from 'ember'; + + export default Ember.Route.extend({ actions: { save: function(user) { if (!user.get('twoFactorAuth')) { @@ -304,8 +312,10 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { Example: - ```javascript - App.UserEditRoute = Ember.Route.extend({ + ```app/routes/user/edit.js + import Ember from 'ember'; + + export default Ember.Route.extend({ actions: { retrySave: function(user) { user.get('errors').clear(); @@ -329,8 +339,10 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { /** Checks if there is error messages for the given attribute. - ```javascript - App.UserEditRoute = Ember.Route.extend({ + ```app/routes/user/edit.js + import Ember from 'ember'; + + export default Ember.Route.extend({ actions: { save: function(user) { if (user.get('errors').has('email')) { diff --git a/packages/ember-data/lib/system/model/errors/invalid.js b/packages/ember-data/lib/system/model/errors/invalid.js index a4389007be9..17de54872ed 100644 --- a/packages/ember-data/lib/system/model/errors/invalid.js +++ b/packages/ember-data/lib/system/model/errors/invalid.js @@ -15,8 +15,10 @@ var EmberError = Ember.Error; namespaced under a key that matches the property name. For example if you had a Post model that looked like this. - ```js - App.Post = DS.Model.extend({ + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ title: DS.attr('string'), content: DS.attr('string') }); @@ -26,8 +28,11 @@ var EmberError = Ember.Error; `content` properties your adapter could return a promise that rejects with a `DS.InvalidError` object that looks like this: - ```js - App.PostAdapter = DS.RESTAdapter.extend({ + ```app/adapters/post.js + import Ember from 'ember'; + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ updateRecord: function() { // Fictional adapter that always rejects return Ember.RSVP.reject(new DS.InvalidError({ @@ -46,8 +51,11 @@ var EmberError = Ember.Error; Example - ```javascript - App.ApplicationAdapter = DS.RESTAdapter.extend({ + ```app/adapters/application.js + import Ember from 'ember'; + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ ajaxError: function(jqXHR) { var error = this._super(jqXHR); diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js index 2687c55ce0b..a304982b89b 100644 --- a/packages/ember-data/lib/system/model/internal-model.js +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -67,17 +67,24 @@ var InternalModel = function InternalModel(type, id, store, container, data) { implicit relationships are relationship which have not been declared but the inverse side exists on another record somewhere For example if there was + + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + name: DS.attr() + }) ``` - App.Comment = DS.Model.extend({ - name: DS.attr() - }) - ``` + but there is also - ``` - App.Post = DS.Model.extend({ - name: DS.attr(), - comments: DS.hasMany('comment') - }) + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + name: DS.attr(), + comments: DS.hasMany('comment') + }) ``` would have a implicit post relationship in order to be do things like remove ourselves from the post diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 65dcf173154..fa1332b7d94 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -473,8 +473,10 @@ var Model = Ember.Object.extend(Ember.Evented, { Example - ```javascript - App.ModelDeleteRoute = Ember.Route.extend({ + ```app/routes/model/delete.js + import Ember from 'ember'; + + export default Ember.Route.extend({ actions: { softDelete: function() { this.controller.get('model').deleteRecord(); @@ -500,8 +502,10 @@ var Model = Ember.Object.extend(Ember.Evented, { Example - ```javascript - App.ModelDeleteRoute = Ember.Route.extend({ + ```app/routes/model/delete.js + import Ember from 'ember'; + + export default Ember.Route.extend({ actions: { delete: function() { var controller = this.controller; @@ -551,12 +555,15 @@ var Model = Ember.Object.extend(Ember.Evented, { Example - ```javascript - var attr = DS.attr; - App.Mascot = DS.Model.extend({ + ```app/models/mascot.js + import DS from 'ember-data'; + + export default DS.Model.extend({ name: attr('string') }); + ``` + ```javascript var mascot = store.createRecord('mascot'); mascot.changedAttributes(); // {} mascot.set('name', 'Tomster'); @@ -666,8 +673,10 @@ var Model = Ember.Object.extend(Ember.Evented, { Example - ```javascript - App.ModelViewRoute = Ember.Route.extend({ + ```app/routes/model/view.js + import Ember from 'ember'; + + export default Ember.Route.extend({ actions: { reload: function() { this.controller.get('model').reload().then(function(model) { From 0aabfd7ea9c47b96562ab3f40fb4c1035c6d8330 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 5 Jun 2015 10:07:38 +0200 Subject: [PATCH 0869/2527] system/relationships: Adjust code samples to ember-cli --- .../lib/system/relationships/belongs-to.js | 30 +++++-- .../lib/system/relationships/ext.js | 88 +++++++++++++------ .../lib/system/relationships/has-many.js | 53 +++++++---- 3 files changed, 119 insertions(+), 52 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/belongs-to.js b/packages/ember-data/lib/system/relationships/belongs-to.js index c1d60c3058a..d40fba39435 100644 --- a/packages/ember-data/lib/system/relationships/belongs-to.js +++ b/packages/ember-data/lib/system/relationships/belongs-to.js @@ -19,12 +19,18 @@ import normalizeModelName from "ember-data/system/normalize-model-name"; To declare a one-to-one relationship between two models, use `DS.belongsTo`: - ```javascript - App.User = DS.Model.extend({ + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ profile: DS.belongsTo('profile') }); + ``` - App.Profile = DS.Model.extend({ + ```app/models/profile.js + import DS from 'ember-data'; + + export default DS.Model.extend({ user: DS.belongsTo('user') }); ``` @@ -33,12 +39,18 @@ import normalizeModelName from "ember-data/system/normalize-model-name"; To declare a one-to-many relationship between two models, use `DS.belongsTo` in combination with `DS.hasMany`, like this: - ```javascript - App.Post = DS.Model.extend({ + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ comments: DS.hasMany('comment') }); + ``` + + ```app/models/comment.js + import DS from 'ember-data'; - App.Comment = DS.Model.extend({ + export default DS.Model.extend({ post: DS.belongsTo('post') }); ``` @@ -46,8 +58,10 @@ import normalizeModelName from "ember-data/system/normalize-model-name"; You can avoid passing a string as the first parameter. In that case Ember Data will infer the type from the key name. - ```javascript - App.Comment = DS.Model.extend({ + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ post: DS.belongsTo() }); ``` diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 98b0415ca12..25c94aa3932 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -164,8 +164,10 @@ Model.reopenClass({ For example, if you define a model like this: - ```javascript - App.Post = DS.Model.extend({ + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ comments: DS.hasMany('comment') }); ``` @@ -192,14 +194,20 @@ Model.reopenClass({ For example, if you define models like this: - ```javascript - App.Post = DS.Model.extend({ - comments: DS.hasMany('message') - }); + ```app/models/post.js + import DS from 'ember-data'; - App.Message = DS.Model.extend({ - owner: DS.belongsTo('post') - }); + export default DS.Model.extend({ + comments: DS.hasMany('message') + }); + ``` + + ```app/models/message.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + owner: DS.belongsTo('post') + }); ``` App.Post.inverseFor('comments') -> {type: App.Message, name:'owner', kind:'belongsTo'} @@ -319,8 +327,10 @@ Model.reopenClass({ For example, given the following model definition: - ```javascript - App.Blog = DS.Model.extend({ + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ users: DS.hasMany('user'), owner: DS.belongsTo('user'), posts: DS.hasMany('post') @@ -331,7 +341,10 @@ Model.reopenClass({ relationships, like this: ```javascript - var relationships = Ember.get(App.Blog, 'relationships'); + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + var relationships = Ember.get(Blog, 'relationships'); relationships.get(App.User); //=> [ { name: 'users', kind: 'hasMany' }, // { name: 'owner', kind: 'belongsTo' } ] @@ -352,8 +365,10 @@ Model.reopenClass({ by the relationship kind. For example, given a model with this definition: - ```javascript - App.Blog = DS.Model.extend({ + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ users: DS.hasMany('user'), owner: DS.belongsTo('user'), @@ -364,7 +379,10 @@ Model.reopenClass({ This property would contain the following: ```javascript - var relationshipNames = Ember.get(App.Blog, 'relationshipNames'); + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + var relationshipNames = Ember.get(Blog, 'relationshipNames'); relationshipNames.hasMany; //=> ['users', 'posts'] relationshipNames.belongsTo; @@ -398,8 +416,10 @@ Model.reopenClass({ For example, given a model with this definition: - ```javascript - App.Blog = DS.Model.extend({ + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ users: DS.hasMany('user'), owner: DS.belongsTo('user'), @@ -410,7 +430,10 @@ Model.reopenClass({ This property would contain the following: ```javascript - var relatedTypes = Ember.get(App.Blog, 'relatedTypes'); + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + var relatedTypes = Ember.get(Blog, 'relatedTypes'); //=> [ App.User, App.Post ] ``` @@ -428,8 +451,10 @@ Model.reopenClass({ For example, given a model with this definition: - ```javascript - App.Blog = DS.Model.extend({ + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ users: DS.hasMany('user'), owner: DS.belongsTo('user'), @@ -440,7 +465,10 @@ Model.reopenClass({ This property would contain the following: ```javascript - var relationshipsByName = Ember.get(App.Blog, 'relationshipsByName'); + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + var relationshipsByName = Ember.get(Blog, 'relationshipsByName'); relationshipsByName.get('users'); //=> { key: 'users', kind: 'hasMany', type: App.User } relationshipsByName.get('owner'); @@ -461,9 +489,10 @@ Model.reopenClass({ For example: - ```javascript + ```app/models/blog.js + import DS from 'ember-data'; - App.Blog = DS.Model.extend({ + export default DS.Model.extend({ users: DS.hasMany('user'), owner: DS.belongsTo('user'), @@ -471,8 +500,13 @@ Model.reopenClass({ title: DS.attr('string') }); + ``` - var fields = Ember.get(App.Blog, 'fields'); + ```js + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + var fields = Ember.get(Blog, 'fields'); fields.forEach(function(kind, field) { console.log(field, kind); }); @@ -588,8 +622,10 @@ Model.reopen({ Example - ```javascript - App.ApplicationSerializer = DS.JSONSerializer.extend({ + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ serialize: function(record, options) { var json = {}; diff --git a/packages/ember-data/lib/system/relationships/has-many.js b/packages/ember-data/lib/system/relationships/has-many.js index 96d5fb01daa..13fb142ab88 100644 --- a/packages/ember-data/lib/system/relationships/has-many.js +++ b/packages/ember-data/lib/system/relationships/has-many.js @@ -20,12 +20,18 @@ import normalizeModelName from "ember-data/system/normalize-model-name"; To declare a one-to-many relationship between two models, use `DS.belongsTo` in combination with `DS.hasMany`, like this: - ```javascript - App.Post = DS.Model.extend({ + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ comments: DS.hasMany('comment') }); + ``` + + ```app/models/comment.js + import DS from 'ember-data'; - App.Comment = DS.Model.extend({ + export default DS.Model.extend({ post: DS.belongsTo('post') }); ``` @@ -34,12 +40,18 @@ import normalizeModelName from "ember-data/system/normalize-model-name"; To declare a many-to-many relationship between two models, use `DS.hasMany`: - ```javascript - App.Post = DS.Model.extend({ + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ tags: DS.hasMany('tag') }); + ``` - App.Tag = DS.Model.extend({ + ```app/models/tag.js + import DS from 'ember-data'; + + export default DS.Model.extend({ posts: DS.hasMany('post') }); ``` @@ -47,8 +59,10 @@ import normalizeModelName from "ember-data/system/normalize-model-name"; You can avoid passing a string as the first parameter. In that case Ember Data will infer the type from the singularized key name. - ```javascript - App.Post = DS.Model.extend({ + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ tags: DS.hasMany() }); ``` @@ -67,19 +81,22 @@ import normalizeModelName from "ember-data/system/normalize-model-name"; same type. You can specify which property on the related model is the inverse using `DS.hasMany`'s `inverse` option: - ```javascript - var belongsTo = DS.belongsTo, - hasMany = DS.hasMany; + ```app/models/comment.js + import DS from 'ember-data'; - App.Comment = DS.Model.extend({ - onePost: belongsTo('post'), - twoPost: belongsTo('post'), - redPost: belongsTo('post'), - bluePost: belongsTo('post') + export default DS.Model.extend({ + onePost: DS.belongsTo('post'), + twoPost: DS.belongsTo('post'), + redPost: DS.belongsTo('post'), + bluePost: DS.belongsTo('post') }); + ``` + + ```app/models/post.js + import DS from 'ember-data'; - App.Post = DS.Model.extend({ - comments: hasMany('comment', { + export default DS.Model.extend({ + comments: DS.hasMany('comment', { inverse: 'redPost' }) }); From d963e374110843062efeaf7dc81397c6fcf378f5 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 5 Jun 2015 10:31:55 +0200 Subject: [PATCH 0870/2527] README: Adjust code samples to ember-cli --- README.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 3a849b673a5..015caa7e67b 100644 --- a/README.md +++ b/README.md @@ -80,25 +80,23 @@ models would look like this: ```js // app/models/blog-post.js -var attr = DS.attr; -var hasMany = DS.hasMany; +import DS from 'ember-data'; export default DS.Model.extend({ - title: attr(), - createdAt: attr('date'), + title: DS.attr(), + createdAt: DS.attr('date'), - comments: hasMany('comment') + comments: DS.hasMany('comment') }); // app/models/comment.js -var attr = DS.attr; -var belongsTo = DS.belongsTo; +import DS from 'ember-data'; export default DS.Model.extend({ - body: attr(), - username: attr(), + body: DS.attr(), + username: DS.attr(), - post: belongsTo('blogPost') + post: DS.belongsTo('blogPost') }); ``` From 08bb942a1a170f94048a516a1e2758e04e11dbb7 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 5 Jun 2015 10:34:54 +0200 Subject: [PATCH 0871/2527] README: Move ember-cli example above globals ember-cli is the recommended way of doing things now and should have priority --- README.md | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 015caa7e67b..ca2c00fae90 100644 --- a/README.md +++ b/README.md @@ -52,31 +52,9 @@ controllers in your app. First thing's first: tell Ember Data about the models in your application. For example, imagine we're writing a blog reader app. -Here's what your model definition would look like if you're using -globals (that is, not something like or ember-cli): - -```js -var attr = DS.attr; -var hasMany = DS.hasMany; -var belongsTo = DS.belongsTo; -App.BlogPost = DS.Model.extend({ - title: attr(), - createdAt: attr('date'), - - comments: hasMany('comment') -}); - -App.Comment = DS.Model.extend({ - body: attr(), - username: attr(), - - post: belongsTo('blogPost') -}); -``` - -If you're using ES6 modules (via ember-cli), your -models would look like this: +Here's what your model definition would look like if you're using +ES6 modules (via ember-cli): ```js // app/models/blog-post.js @@ -100,6 +78,29 @@ export default DS.Model.extend({ }); ``` +If you're using globals (that is, not something like or ember-cli), your +models would look like this: + +```js +var attr = DS.attr; +var hasMany = DS.hasMany; +var belongsTo = DS.belongsTo; + +App.BlogPost = DS.Model.extend({ + title: attr(), + createdAt: attr('date'), + + comments: hasMany('comment') +}); + +App.Comment = DS.Model.extend({ + body: attr(), + username: attr(), + + post: belongsTo('blogPost') +}); +``` + ### A Brief Note on Adapters Without immediately diving in to the depths of the architecture, one From f79a68495e57b5cf3ec0a33f366d63921e935de9 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 5 Jun 2015 11:06:13 +0200 Subject: [PATCH 0872/2527] Brocfile: Fix JSCS issues --- Brocfile.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Brocfile.js b/Brocfile.js index f5bcd6f4294..41219d529c5 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -23,7 +23,7 @@ var fileCreator = require('broccoli-file-creator'); var jscs = require('broccoli-jscs'); var features = require('./lib/feature-flags'); -function minify(tree, name){ +function minify(tree, name) { var config = require('./config/ember-defeatureify'); tree = defeatureify(tree, { debugStatements: config.options.debugStatements, @@ -37,14 +37,14 @@ function minify(tree, name){ tree = pickFiles(tree, { srcDir: '/', destDir: '/', - files: [ name + '.prod.js' ] + files: [name + '.prod.js'] }); tree = removeSourceMappingURL(tree); - var uglified = moveFile(uglify(tree, {mangle: true}),{ + var uglified = moveFile(uglify(tree, { mangle: true }), { srcFile: name + '.prod.js', destFile: '/' + name + '.min.js' }); - return merge([uglified, tree], {overwrite: true}); + return merge([uglified, tree], { overwrite: true }); } var yuidocTree = yuidoc('packages', { @@ -72,7 +72,7 @@ var yuidocTree = yuidoc('packages', { function package(packagePath, vendorPath) { vendorPath = vendorPath || 'packages/'; return pickFiles(vendorPath + packagePath, { - files: [ '**/*.js' ], + files: ['**/*.js'], srcDir: '/', destDir: '/' + packagePath }); @@ -80,7 +80,7 @@ function package(packagePath, vendorPath) { function packageAddon(packagePath, vendorPath) { return stew.rename(pickFiles(vendorPath + packagePath, { - files: [ '**/*.js' ], + files: ['**/*.js'], srcDir: '/addon', destDir: '/' + packagePath + '/lib' }), 'index.js', 'main.js'); @@ -110,7 +110,7 @@ if (env === 'production') { var tests = testTree(packages, amdBuild(transpiledPackages)); globalBuild = merge([globalBuild, tests]); } else { -// Use AMD for faster rebuilds in dev + // Use AMD for faster rebuilds in dev var bootFile = fileCreator('/boot.js', 'require("ember-data");'); var compiled = amdBuild(transpiledPackages); @@ -118,7 +118,7 @@ if (env === 'production') { var emberData = merge([bootFile, libFiles]); - var emberData = concat(emberData, { + emberData = concat(emberData, { inputFiles: ['ember-data/**/*.js', 'boot.js'], outputFile: '/ember-data.js' }); @@ -128,7 +128,7 @@ if (env === 'production') { var testRunner = pickFiles('tests', { srcDir: '/', - files: [ '**/*' ], + files: ['**/*'], destDir: '/' }); @@ -140,7 +140,7 @@ var bower = pickFiles('bower_components', { var configurationFiles = pickFiles('config/package-manager-files', { srcDir: '/', destDir: '/', - files: [ '**/*.json' ] + files: ['**/*.json'] }); function versionStamp(tree) { @@ -184,4 +184,4 @@ if (env === 'production') { trees.push(globalBuild); -module.exports = merge(trees, {overwrite: true}); +module.exports = merge(trees, { overwrite: true }); From 49625c5a13bf10b5b50b8724cf95ad5b4457e4c0 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 5 Jun 2015 11:12:35 +0200 Subject: [PATCH 0873/2527] tests: Fix JSCS issues --- tests/ember-configuration.js | 14 +++--- tests/ember-data-setup.js | 2 +- tests/qunit-configuration.js | 84 +++++++++++++++++++----------------- 3 files changed, 52 insertions(+), 48 deletions(-) diff --git a/tests/ember-configuration.js b/tests/ember-configuration.js index 0828e61da90..12108ded4f7 100644 --- a/tests/ember-configuration.js +++ b/tests/ember-configuration.js @@ -1,6 +1,6 @@ /* globals ENV, QUnit */ -(function (){ +(function () { window.Ember = window.Ember || {}; Ember.config = {}; @@ -37,7 +37,7 @@ }; window.asyncEqual = function(a, b, message) { - Ember.RSVP.all([ Ember.RSVP.resolve(a), Ember.RSVP.resolve(b) ]).then(async(function(array) { + Ember.RSVP.all([Ember.RSVP.resolve(a), Ember.RSVP.resolve(b)]).then(async(function(array) { /*globals QUnit*/ QUnit.push(array[0] === array[1], array[0], array[1], message); })); @@ -110,7 +110,7 @@ return setupStore(options).store; }; - QUnit.begin(function(){ + QUnit.begin(function() { Ember.RSVP.configure('onerror', function(reason) { // only print error messages if they're exceptions; // otherwise, let a future turn of the event loop @@ -141,10 +141,10 @@ // to make the QUnit global check run clean jQuery(window).data('testing', true); - window.warns = function(callback, regex){ + window.warns = function(callback, regex) { var warnWasCalled = false; var oldWarn = Ember.warn; - Ember.warn = function Ember_assertWarning(message, test){ + Ember.warn = function Ember_assertWarning(message, test) { if (!test) { warnWasCalled = true; if (regex) { @@ -160,10 +160,10 @@ } }; - window.noWarns = function(callback){ + window.noWarns = function(callback) { var oldWarn = Ember.warn; var warnWasCalled = false; - Ember.warn = function Ember_noWarn(message, test){ + Ember.warn = function Ember_noWarn(message, test) { warnWasCalled = !test; }; try { diff --git a/tests/ember-data-setup.js b/tests/ember-data-setup.js index ce0686fb355..bbe39109a2c 100644 --- a/tests/ember-data-setup.js +++ b/tests/ember-data-setup.js @@ -1,4 +1,4 @@ -;(function(){ +;(function() { Ember.RSVP.configure('onerror', function(reason) { // only print error messages if they're exceptions; diff --git a/tests/qunit-configuration.js b/tests/qunit-configuration.js index 77aa757a5a4..51d6872a6f5 100644 --- a/tests/qunit-configuration.js +++ b/tests/qunit-configuration.js @@ -5,8 +5,8 @@ EmberDev.afterEach = function() { if (Ember && Ember.View) { - var viewIds = [], id; - for (id in Ember.View.views) { + var viewIds = []; + for (var id in Ember.View.views) { if (Ember.View.views[id] != null) { viewIds.push(id); } @@ -19,8 +19,8 @@ } if (Ember && Ember.TEMPLATES) { - var templateNames = [], name; - for (name in Ember.TEMPLATES) { + var templateNames = []; + for (var name in Ember.TEMPLATES) { if (Ember.TEMPLATES[name] != null) { templateNames.push(name); } @@ -71,8 +71,9 @@ currentTest.passed = data.passed; currentTest.failed = data.failed; - if (currentTest.failed > 0) + if (currentTest.failed > 0) { window.globalFailedTests.push(currentTest); + } currentTest = null; }); @@ -144,9 +145,9 @@ EmberDev.jsHintReporter = function (file, errors) { if (!errors) { return ''; } - var len = errors.length, - str = '', - error, idx; + var len = errors.length; + var str = ''; + var error, idx; if (len === 0) { return ''; } @@ -159,8 +160,8 @@ return str + "\n" + len + ' error' + ((len === 1) ? '' : 's'); }; - var o_create = Object.create || (function(){ - function F(){} + var o_create = Object.create || (function() { + function F() {} return function(o) { if (arguments.length !== 1) { @@ -172,31 +173,31 @@ }()); // Handle testing feature flags - QUnit.config.urlConfig.push({ id: 'enableoptionalfeatures', label: "Enable Opt Features"}); + QUnit.config.urlConfig.push({ id: 'enableoptionalfeatures', label: "Enable Opt Features" }); // A light class for stubbing // - function MethodCallExpectation(target, property){ + function MethodCallExpectation(target, property) { this.target = target; this.property = property; } MethodCallExpectation.prototype = { - handleCall: function(){ + handleCall: function() { this.sawCall = true; return this.originalMethod.apply(this.target, arguments); }, - stubMethod: function(fn){ + stubMethod: function(fn) { var context = this; this.originalMethod = this.target[this.property]; - this.target[this.property] = function(){ + this.target[this.property] = function() { return context.handleCall.apply(context, arguments); }; }, - restoreMethod: function(){ + restoreMethod: function() { this.target[this.property] = this.originalMethod; }, - runWithStub: function(fn){ + runWithStub: function(fn) { try { this.stubMethod(); fn(); @@ -210,26 +211,27 @@ } }; - function AssertExpectation(message){ + function AssertExpectation(message) { MethodCallExpectation.call(this, Ember, 'assert'); this.expectedMessage = message; } - AssertExpectation.Error = function(){}; + AssertExpectation.Error = function() {}; AssertExpectation.prototype = o_create(MethodCallExpectation.prototype); - AssertExpectation.prototype.handleCall = function(message, test){ + AssertExpectation.prototype.handleCall = function(message, test) { this.sawCall = true; - if (test) return; // Only get message for failures + if (test) { return; } // Only get message for failures this.actualMessage = message; // Halt execution throw new AssertExpectation.Error(); }; - AssertExpectation.prototype.assert = function(fn){ + AssertExpectation.prototype.assert = function(fn) { try { this.runWithStub(fn); } catch (e) { - if (!(e instanceof AssertExpectation.Error)) + if (!(e instanceof AssertExpectation.Error)) { throw e; + } } // Run assertions in an order that is useful when debugging a test failure. @@ -258,7 +260,7 @@ // Ember.assert("Homie don't roll like that"); // } /* , optionalMessageStringOrRegex */); // - window.expectAssertion = function expectAssertion(fn, message){ + window.expectAssertion = function expectAssertion(fn, message) { (new AssertExpectation(message)).assert(fn); }; @@ -266,7 +268,7 @@ NONE: 99, // 99 problems and a deprecation ain't one expecteds: null, actuals: null, - stubEmber: function(){ + stubEmber: function() { if (!EmberDev.deprecations.originalEmberDeprecate && Ember.deprecate !== EmberDev.deprecations.originalEmberDeprecate) { EmberDev.deprecations.originalEmberDeprecate = Ember.deprecate; } @@ -275,7 +277,7 @@ EmberDev.deprecations.actuals.push([msg, test]); }; }, - restoreEmber: function(){ + restoreEmber: function() { Ember.deprecate = EmberDev.deprecations.originalEmberDeprecate; } }; @@ -337,8 +339,8 @@ // without explicit asserts. // window.assertDeprecation = function() { - var expecteds = EmberDev.deprecations.expecteds, - actuals = EmberDev.deprecations.actuals || []; + var expecteds = EmberDev.deprecations.expecteds; + var actuals = EmberDev.deprecations.actuals || []; if (!expecteds) { EmberDev.deprecations.actuals = null; return; @@ -356,8 +358,9 @@ ok(actuals.length === 0, "Expected no deprecation call, got: "+actualMessages.join(', ')); } else { for (var o=0;o < expecteds.length; o++) { - var expected = expecteds[o], match, actual; - for (var i=0;i < actuals.length; i++) { + var expected = expecteds[o]; + var match, actual; + for (var i = 0; i < actuals.length; i++) { actual = actuals[i]; if (!actual[1]) { if (expected instanceof RegExp) { @@ -374,16 +377,17 @@ } } - if (!actual) - ok(false, "Recieved no deprecate calls at all, expecting: "+expected); - else if (match && !match[1]) - ok(true, "Recieved failing deprecation with message: "+match[0]); - else if (match && match[1]) - ok(false, "Expected failing deprecation, got succeeding with message: "+match[0]); - else if (actual[1]) - ok(false, "Did not receive failing deprecation matching '"+expected+"', last was success with '"+actual[0]+"'"); - else if (!actual[1]) - ok(false, "Did not receive failing deprecation matching '"+expected+"', last was failure with '"+actual[0]+"'"); + if (!actual) { + ok(false, "Recieved no deprecate calls at all, expecting: " + expected); + } else if (match && !match[1]) { + ok(true, "Recieved failing deprecation with message: " + match[0]); + } else if (match && match[1]) { + ok(false, "Expected failing deprecation, got succeeding with message: " + match[0]); + } else if (actual[1]) { + ok(false, "Did not receive failing deprecation matching '" + expected + "', last was success with '" + actual[0] + "'"); + } else if (!actual[1]) { + ok(false, "Did not receive failing deprecation matching '" + expected + "', last was failure with '" + actual[0] + "'"); + } } } }; From 3576aa4d3318af4c034d7fbedf14e16f13a02490 Mon Sep 17 00:00:00 2001 From: Satoshi Korin Date: Fri, 5 Jun 2015 18:39:19 +0900 Subject: [PATCH 0874/2527] Fix doc for Store#findHasMany. Its 3rd argument is a relationship object. --- packages/ember-data/lib/system/store.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 2f385b029c9..c95a31ef26b 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -926,16 +926,16 @@ Store = Service.extend({ @private @param {DS.Model} owner @param {any} link - @param {(String|DS.Model)} type + @param {(Relationship)} relationship @return {Promise} promise */ - findHasMany: function(owner, link, type) { + findHasMany: function(owner, link, relationship) { var adapter = this.adapterFor(owner.type.modelName); Ember.assert("You tried to load a hasMany relationship but you have no adapter (for " + owner.type + ")", adapter); Ember.assert("You tried to load a hasMany relationship from a specified `link` in the original payload but your adapter does not implement `findHasMany`", typeof adapter.findHasMany === 'function'); - return _findHasMany(adapter, this, owner, link, type); + return _findHasMany(adapter, this, owner, link, relationship); }, /** From 8fc8a51f992d692558bbd0d1114f16c4f058185e Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Fri, 5 Jun 2015 17:09:58 +0300 Subject: [PATCH 0875/2527] Revert breaking out commonalities to normalizeArray --- .../lib/serializers/rest-serializer.js | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index 8f084246e37..71ad7926941 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -290,10 +290,14 @@ var RESTSerializer = JSONSerializer.extend({ continue; } - var normalizedArray = this.normalizeArray(store, modelName, value, prop); - /*jshint loopfunc:true*/ - forEach.call(normalizedArray, function(hash) { + forEach.call(value, function(hash) { + var typeName = this.modelNameFromPayloadKey(prop); + var type = store.modelFor(typeName); + var typeSerializer = store.serializerFor(type); + + hash = typeSerializer.normalize(type, hash, prop); + var isFirstCreatedRecord = isPrimary && !recordId && !primaryRecord; var isUpdatedRecord = isPrimary && coerceId(hash.id) === recordId; @@ -434,10 +438,15 @@ var RESTSerializer = JSONSerializer.extend({ Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false); continue; } - - var normalizedArray = this.normalizeArray(store, typeName, payload[prop], prop); + var type = store.modelFor(typeName); + var typeSerializer = store.serializerFor(type); var isPrimary = (!forcedSecondary && this.isPrimaryType(store, typeName, primaryTypeClass)); + /*jshint loopfunc:true*/ + var normalizedArray = map.call(payload[prop], function(hash) { + return typeSerializer.normalize(type, hash, prop); + }, this); + if (isPrimary) { primaryArray = normalizedArray; } else { @@ -448,16 +457,6 @@ var RESTSerializer = JSONSerializer.extend({ return primaryArray; }, - normalizeArray: function(store, typeName, arrayHash, prop) { - var typeClass = store.modelFor(typeName); - var typeSerializer = store.serializerFor(typeName); - - /*jshint loopfunc:true*/ - return map.call(arrayHash, function(hash) { - return typeSerializer.normalize(typeClass, hash, prop); - }, this); - }, - isPrimaryType: function(store, typeName, primaryTypeClass) { var typeClass = store.modelFor(typeName); return typeClass.modelName === primaryTypeClass.modelName; From df8f14a7f75b9ac44609a487f679993ae10ebdbc Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Mon, 13 Apr 2015 20:16:45 +0200 Subject: [PATCH 0876/2527] Improve property change notifications for records --- .../lib/system/model/internal-model.js | 62 +++++----- .../records/property-changes-test.js | 115 ++++++++++++++++++ .../ember-data/tests/unit/store/push-test.js | 29 ----- 3 files changed, 148 insertions(+), 58 deletions(-) create mode 100644 packages/ember-data/tests/integration/records/property-changes-test.js diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js index a304982b89b..9711f724cef 100644 --- a/packages/ember-data/lib/system/model/internal-model.js +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -190,7 +190,8 @@ InternalModel.prototype = { }, setupData: function(data) { - var changedKeys = mergeAndReturnChangedKeys(this._data, data); + var changedKeys = this._changedKeys(data); + merge(this._data, data); this.pushedData(); if (this.record) { this.record._notifyProperties(changedKeys); @@ -584,11 +585,11 @@ InternalModel.prototype = { @method adapterDidCommit */ adapterDidCommit: function(data) { - var changedKeys; this.didCleanError(); + var changedKeys = this._changedKeys(data); if (data) { - changedKeys = mergeAndReturnChangedKeys(this._data, data); + merge(this._data, data); } else { merge(this._data, this._inFlightAttributes); } @@ -663,6 +664,35 @@ InternalModel.prototype = { this._inFlightAttributes = Ember.create(null); }, + /** + @method _changedKeys + @private + */ + _changedKeys: function(updates) { + var changedKeys = []; + + if (updates && typeof updates === 'object') { + var original, i, value, key; + var keys = Ember.keys(updates); + var length = keys.length; + + original = merge({}, this._data); + original = merge(original, this._attributes); + original = merge(original, this._inFlightAttributes); + + for (i = 0; i < length; i++) { + key = keys[i]; + value = updates[key]; + + if (original[key] !== value) { + changedKeys.push(key); + } + } + } + + return changedKeys; + }, + toString: function() { if (this.record) { return this.record.toString(); @@ -672,31 +702,5 @@ InternalModel.prototype = { } }; -// Like Ember.merge, but instead returns a list of keys -// for values that fail a strict equality check -// instead of the original object. -function mergeAndReturnChangedKeys(original, updates) { - var changedKeys = []; - - if (!updates || typeof updates !== 'object') { - return changedKeys; - } - - var keys = Ember.keys(updates); - var length = keys.length; - var i, val, key; - - for (i = 0; i < length; i++) { - key = keys[i]; - val = updates[key]; - - if (original[key] !== val) { - changedKeys.push(key); - } - - original[key] = val; - } - return changedKeys; -} export default InternalModel; diff --git a/packages/ember-data/tests/integration/records/property-changes-test.js b/packages/ember-data/tests/integration/records/property-changes-test.js new file mode 100644 index 00000000000..c7e816d84f2 --- /dev/null +++ b/packages/ember-data/tests/integration/records/property-changes-test.js @@ -0,0 +1,115 @@ +var env, store, Person; +var attr = DS.attr; +var run = Ember.run; + +module('integration/records/property-changes - Property changes', { + setup: function() { + Person = DS.Model.extend({ + firstName: attr('string'), + lastName: attr('string') + }); + Person.toString = function() { return 'Person'; }; + + env = setupStore({ + person: Person + }); + store = env.store; + }, + + teardown: function() { + Ember.run(function() { + env.container.destroy(); + }); + } +}); + +test('Calling push with partial records trigger observers for just those attributes that changed', function() { + expect(1); + var person; + + run(function() { + person = store.push('person', { + id: 'wat', + firstName: 'Yehuda', + lastName: 'Katz' + }); + }); + + person.addObserver('firstName', function() { + ok(false, 'firstName observer should not be triggered'); + }); + + person.addObserver('lastName', function() { + ok(true, 'lastName observer should be triggered'); + }); + + run(function() { + store.push('person', { + id: 'wat', + firstName: 'Yehuda', + lastName: 'Katz!' + }); + }); +}); + +test('Calling push does not trigger observers for locally changed attributes with the same value', function() { + expect(0); + var person; + + run(function() { + person = store.push('person', { + id: 'wat', + firstName: 'Yehuda', + lastName: 'Katz' + }); + + person.set('lastName', 'Katz!'); + }); + + person.addObserver('firstName', function() { + ok(false, 'firstName observer should not be triggered'); + }); + + person.addObserver('lastName', function() { + ok(false, 'lastName observer should not be triggered'); + }); + + run(function() { + store.push('person', { + id: 'wat', + firstName: 'Yehuda', + lastName: 'Katz!' + }); + }); +}); + +test('Saving a record trigger observers for locally changed attributes with the same canonical value', function() { + expect(1); + var person; + + env.adapter.updateRecord = function(store, type, snapshot) { + return Ember.RSVP.resolve({ id: 'wat', lastName: 'Katz' }); + }; + + run(function() { + person = store.push('person', { + id: 'wat', + firstName: 'Yehuda', + lastName: 'Katz' + }); + + person.set('lastName', 'Katz!'); + }); + + person.addObserver('firstName', function() { + ok(false, 'firstName observer should not be triggered'); + }); + + person.addObserver('lastName', function() { + ok(true, 'lastName observer should be triggered'); + }); + + run(function() { + person.save(); + }); +}); diff --git a/packages/ember-data/tests/unit/store/push-test.js b/packages/ember-data/tests/unit/store/push-test.js index fc2f436c384..f1a30aa2469 100644 --- a/packages/ember-data/tests/unit/store/push-test.js +++ b/packages/ember-data/tests/unit/store/push-test.js @@ -164,35 +164,6 @@ test("Calling push on normalize allows partial updates with raw JSON", function equal(person.get('lastName'), "Jackson", "existing fields are untouched"); }); -test("Calling push with partial records triggers observers for just those attributes that changed", function() { - expect(1); - var person; - - run(function() { - person = store.push('person', { - id: 'wat', - firstName: "Yehuda", - lastName: "Katz" - }); - }); - - person.addObserver('firstName', function() { - ok(false, 'firstName observer should not be triggered'); - }); - - person.addObserver('lastName', function() { - ok(true, 'lastName observer should be triggered'); - }); - - run(function() { - store.push('person', { - id: 'wat', - firstName: 'Yehuda', - lastName: 'Katz!' - }); - }); -}); - test("Calling push with a normalized hash containing related records returns a record", function() { var number1, number2, person; run(function() { From 6c1946e1e815b9a4ef9c8a15ea68431d5d374c85 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 5 Jun 2015 10:09:40 -0500 Subject: [PATCH 0877/2527] release v1.0.0-beta.19 --- CHANGELOG.md | 31 +++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87ec5f9cf04..39e82049844 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,40 @@ ### Master +### Release 1.0.0-beta.19 (June 5, 2015) + - Removed support for DS.FixtureAdapter. You can use it as an addon, or build it using [Ember Giftwrap](https://github.com/ef4/ember-giftwrap). https://github.com/emberjs/ember-data-fixture-adapter/tree/master +- Removed support for passing factories to store methods. An example + would be `store.find(App.Post, '1')`. Use the string form instead: + `post` instead of `App.Post`. You can also use this [Ember Watson + command](https://github.com/abuiles/ember-watson#ember-watsonconvert-ember-data-model-lookups) +- [#3074](https://github.com/emberjs/data/pull/3074) remove passing factories to store methods [@fivetanley](https://github.com/fivetanley) +- [#3083](https://github.com/emberjs/data/pull/3083) A new record which is marked as invalid can be rollbacked [@pangratz](https://github.com/pangratz) +- [#3102](https://github.com/emberjs/data/pull/3102) Updated copyright year [@perlun](https://github.com/perlun) +- [#3091](https://github.com/emberjs/data/pull/3091) deprecate support for DS.FixtureAdapter [@emberjs](https://github.com/emberjs) +- [#3097](https://github.com/emberjs/data/pull/3097) fix bower publishing [@emberjs](https://github.com/emberjs) +- [#3094](https://github.com/emberjs/data/pull/3094) Lazily materialize DS.Models for app code, use InternalModel inside ED otherwise [@emberjs](https://github.com/emberjs) +- [#3119](https://github.com/emberjs/data/pull/3119) maxUrlLength -> maxURLLength [@sly7-7](https://github.com/sly7-7) +- [#3110](https://github.com/emberjs/data/pull/3110) Cleanup unused 'materialize' records in model [@tonywok](https://github.com/tonywok) +- [#3182](https://github.com/emberjs/data/pull/3182) initialize lives on the application instance not the Ember namespace [@bmac](https://github.com/bmac) +- [#3126](https://github.com/emberjs/data/pull/3126) Guard for embedded unknown hasMany relationship [@wecc](https://github.com/wecc) +- [#3133](https://github.com/emberjs/data/pull/3133) Create snapshots on save not on flush [@tchak](https://github.com/tchak) +- [#3136](https://github.com/emberjs/data/pull/3136) Lookup the store using store:application instead of store:main [@bmac](https://github.com/bmac) +- [#3139](https://github.com/emberjs/data/pull/3139) Extend adapter instead of reopening it [@BookingSync](https://github.com/BookingSync) +- [#3138](https://github.com/emberjs/data/pull/3138) Custom primaryKey for embedded polymorphic relations work [@pangratz](https://github.com/pangratz) +- [#3174](https://github.com/emberjs/data/pull/3174) Adjust code samples to ember-cli [@Turbo87](https://github.com/Turbo87) +- [#3148](https://github.com/emberjs/data/pull/3148) add Snapshot#serialize method [@yratanov/feature](https://github.com/yratanov/feature) +- [#3170](https://github.com/emberjs/data/pull/3170) Ensure snapshot.belongsTo() and hasMany() do not return deleted records [@ianstarz](https://github.com/ianstarz) +- [#3156](https://github.com/emberjs/data/pull/3156) Remove deprecated push record [@sly7-7](https://github.com/sly7-7) +- [#3169](https://github.com/emberjs/data/pull/3169) rename add/removeRecord to add/removeInternalModel in record array [@sly7-7](https://github.com/sly7-7) +- [#3183](https://github.com/emberjs/data/pull/3183) fix belongs-to when set with a resolved promise [@sly7-7](https://github.com/sly7-7) +- [#3195](https://github.com/emberjs/data/pull/3195) Update comment to make its intention clearer [@bmac](https://github.com/bmac) +- [#3191](https://github.com/emberjs/data/pull/3191) refactor store managed instances [@fivetanley](https://github.com/fivetanley) +- [#3203](https://github.com/emberjs/data/pull/3203) Use string model names in debug adapter [@teddyzeenny](https://github.com/teddyzeenny) +- [#3208](https://github.com/emberjs/data/pull/3208) DirtyState.invalid handle pushedData event [@bmac](https://github.com/bmac) +- [#3211](https://github.com/emberjs/data/pull/3211) lookup JSONSerializer instance through store instead of manual instan… [@emberjs](https://github.com/emberjs) ### Release 1.0.0-beta.18 (May 18, 2015) diff --git a/package.json b/package.json index 24b6d5c440c..fe82b58c875 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.19+canary", + "version": "1.0.0-beta.19", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", From 8b69971e4cd11c0cd223a01233a8793fbb60a643 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 5 Jun 2015 10:10:44 -0500 Subject: [PATCH 0878/2527] post-release version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fe82b58c875..0c6eed0686c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "1.0.0-beta.19", + "version": "1.0.0-beta.20+canary", "namespace": "DS", "repository": "git://github.com/emberjs/data.git", "license": "MIT", From 4adcc1813ab0b7b1992d4c29148a459af7789750 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Fri, 8 May 2015 18:27:35 +0200 Subject: [PATCH 0879/2527] Refactor the Serializer API --- FEATURES.md | 3 + config/features.json | 1 + .../adapter-populated-record-array.js | 13 + packages/ember-data/lib/system/serializer.js | 31 +++ packages/ember-data/lib/system/store.js | 26 +- .../system/store/container-instance-cache.js | 3 + .../ember-data/lib/system/store/finders.js | 49 ++-- .../lib/system/store/serializer-response.js | 240 ++++++++++++++++++ 8 files changed, 333 insertions(+), 33 deletions(-) create mode 100644 packages/ember-data/lib/system/store/serializer-response.js diff --git a/FEATURES.md b/FEATURES.md index d866f00ae24..7c720870a27 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -11,3 +11,6 @@ entry in `config/features.json`. ## Feature Flags +* `ds-new-serializer-api` + + Activates the new Serializer API for default serializers. diff --git a/config/features.json b/config/features.json index 2c63c085104..9e71e4691c1 100644 --- a/config/features.json +++ b/config/features.json @@ -1,2 +1,3 @@ { + "ds-new-serializer-api": null } diff --git a/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js b/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js index 65670d58b90..d0a93c80207 100644 --- a/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js +++ b/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js @@ -41,6 +41,19 @@ export default RecordArray.extend({ var type = get(this, 'type'); var modelName = type.modelName; var records = store.pushMany(modelName, data); + + this.loadRecords(records); + }, + + /** + @method loadRecords + @param {Array} records + @private + */ + loadRecords: function(records) { + var store = get(this, 'store'); + var type = get(this, 'type'); + var modelName = type.modelName; var meta = store.metadataFor(modelName); //TODO Optimize diff --git a/packages/ember-data/lib/system/serializer.js b/packages/ember-data/lib/system/serializer.js index cd78055fc52..06cc95e2942 100644 --- a/packages/ember-data/lib/system/serializer.js +++ b/packages/ember-data/lib/system/serializer.js @@ -23,6 +23,37 @@ */ var Serializer = Ember.Object.extend({ + + /* + This is only to be used temporarily during the transition from the old + serializer API to the new one. + + To activate the new Serializer API you need to enable the feature flag + `ds-new-serializer-api`. + + http://guides.emberjs.com/v1.12.0/configuring-ember/feature-flags/ + + This makes the store and the built-in serializers use the new Serializer API. + + + ## Custom Serializers + + If you have custom serializers you need to do the following: + + 1. Opt-in to the new Serializer API by setting `isNewSerializerAPI` to `true` + when extending one of the built-in serializers. This indicates that the + store should call `normalizeResponse` instead of `extract` and to expect + a JSON-API Document back. + 2. If you have a custom `extract` hooks you need to refactor it to the new + `normalizeResponse` hooks and make sure it returns a JSON-API Document. + 3. If you have a custom `normalize` method you need to make sure it also + returns a JSON-API Document with the record in question as the primary + data. + + @property isNewSerializerAPI + */ + isNewSerializerAPI: false, + /** The `store` property is the application's `store` that contains all records. It's injected as a service. diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 17cdc59208f..2159b60e1e7 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -24,6 +24,12 @@ import { _objectIsAlive } from "ember-data/system/store/common"; +import { + convertResourceObject, + normalizeResponseHelper, + pushPayload +} from "ember-data/system/store/serializer-response"; + import { serializerForAdapter } from "ember-data/system/store/serializers"; @@ -1590,17 +1596,25 @@ Store = Service.extend({ @method push @param {String} modelName @param {Object} data - @return {DS.Model} the record that was created or + @return {DS.Model|Array} the record(s) that was created or updated. */ push: function(modelName, data) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var internalModel = this._pushInternalModel(modelName, data); + if (Ember.isArray(internalModel)) { + return map(internalModel, (item) => { + return item.getRecord(); + }); + } return internalModel.getRecord(); }, _pushInternalModel: function(modelName, data) { - Ember.assert("Expected an object as `data` in a call to `push` for " + modelName + " , but was " + data, Ember.typeOf(data) === 'object'); + if (Ember.typeOf(modelName) === 'object' && Ember.typeOf(data) === 'undefined') { + return pushPayload(this, modelName); + } + Ember.assert("Expected an object as `data` in a call to `push` for " + modelName + " , but was " + Ember.typeOf(data), Ember.typeOf(data) === 'object'); Ember.assert("You must include an `id` for " + modelName + " in an object passed to `push`", data.id != null && data.id !== ''); var type = this.modelFor(modelName); @@ -2089,13 +2103,13 @@ function _commit(adapter, store, operation, snapshot) { promise = _guard(promise, _bind(_objectIsAlive, record)); return promise.then(function(adapterPayload) { - var payload; - store._adapterRun(function() { + var payload, data; if (adapterPayload) { - payload = serializer.extract(store, type, adapterPayload, snapshot.id, operation); + payload = normalizeResponseHelper(serializer, store, type, adapterPayload, snapshot.id, operation); + data = convertResourceObject(payload.data); } - store.didSaveRecord(record, payload); + store.didSaveRecord(record, data); }); return record; diff --git a/packages/ember-data/lib/system/store/container-instance-cache.js b/packages/ember-data/lib/system/store/container-instance-cache.js index cc86980874d..e9f81501885 100644 --- a/packages/ember-data/lib/system/store/container-instance-cache.js +++ b/packages/ember-data/lib/system/store/container-instance-cache.js @@ -46,6 +46,9 @@ Ember.merge(ContainerInstanceCache.prototype, { let instance = this.instanceFor(lookupKey); if (instance) { + if (fallback === '-default') { + instance.set('isNewSerializerAPI', true); + } return instance; } } diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index dbb6be5fbb6..5f96c371810 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -4,11 +4,15 @@ import { _objectIsAlive } from "ember-data/system/store/common"; +import { + normalizeResponseHelper, + pushPayload +} from "ember-data/system/store/serializer-response"; + import { serializerForAdapter } from "ember-data/system/store/serializers"; - var Promise = Ember.RSVP.Promise; var map = Ember.EnumerableUtils.map; @@ -24,10 +28,9 @@ export function _find(adapter, store, typeClass, id, internalModel) { return promise.then(function(adapterPayload) { Ember.assert("You made a request for a " + typeClass.typeClassKey + " with id " + id + ", but the adapter's response did not have any data", adapterPayload); return store._adapterRun(function() { - var payload = serializer.extract(store, typeClass, adapterPayload, id, 'find'); - + var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, id, 'find'); //TODO Optimize - var record = store.push(typeClass.modelName, payload); + var record = pushPayload(store, payload); return record._internalModel; }); }, function(error) { @@ -56,12 +59,9 @@ export function _findMany(adapter, store, typeClass, ids, internalModels) { return promise.then(function(adapterPayload) { return store._adapterRun(function() { - var payload = serializer.extract(store, typeClass, adapterPayload, null, 'findMany'); - - Ember.assert("The response from a findMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); - + var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findMany'); //TODO Optimize, no need to materialize here - var records = store.pushMany(typeClass.modelName, payload); + var records = pushPayload(store, payload); return map(records, function(record) { return record._internalModel; }); }); }, null, "DS: Extract payload of " + typeClass); @@ -80,12 +80,9 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) return promise.then(function(adapterPayload) { return store._adapterRun(function() { - var payload = serializer.extract(store, typeClass, adapterPayload, null, 'findHasMany'); - - Ember.assert("The response from a findHasMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); - + var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findHasMany'); //TODO Use a non record creating push - var records = store.pushMany(relationship.type, payload); + var records = pushPayload(store, payload); return map(records, function(record) { return record._internalModel; }); }); }, null, "DS: Extract payload of " + internalModel + " : hasMany " + relationship.type); @@ -104,14 +101,14 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship return promise.then(function(adapterPayload) { return store._adapterRun(function() { - var payload = serializer.extract(store, typeClass, adapterPayload, null, 'findBelongsTo'); + var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findBelongsTo'); - if (!payload) { + if (!payload.data) { return null; } - var record = store.push(relationship.type, payload); //TODO Optimize + var record = pushPayload(store, payload); return record._internalModel; }); }, null, "DS: Extract payload of " + internalModel + " : " + relationship.type); @@ -128,11 +125,9 @@ export function _findAll(adapter, store, typeClass, sinceToken) { return promise.then(function(adapterPayload) { store._adapterRun(function() { - var payload = serializer.extract(store, typeClass, adapterPayload, null, 'findAll'); - - Ember.assert("The response from a findAll must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); - - store.pushMany(modelName, payload); + var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findAll'); + //TODO Optimize + pushPayload(store, payload); }); store.didUpdateAll(typeClass); @@ -150,14 +145,14 @@ export function _findQuery(adapter, store, typeClass, query, recordArray) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - var payload; + var records; store._adapterRun(function() { - payload = serializer.extract(store, typeClass, adapterPayload, null, 'findQuery'); - - Ember.assert("The response from a findQuery must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); + var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findQuery'); + //TODO Optimize + records = pushPayload(store, payload); }); - recordArray.load(payload); + recordArray.loadRecords(records); return recordArray; }, null, "DS: Extract payload of findQuery " + typeClass); diff --git a/packages/ember-data/lib/system/store/serializer-response.js b/packages/ember-data/lib/system/store/serializer-response.js new file mode 100644 index 00000000000..36de338dcbd --- /dev/null +++ b/packages/ember-data/lib/system/store/serializer-response.js @@ -0,0 +1,240 @@ +var forEach = Ember.EnumerableUtils.forEach; +var map = Ember.EnumerableUtils.map; + +/** + This is a helper method that always returns a JSON-API Document. + + If the feature flag `ds-new-serializer-api` is enabled and the current serializer + has `isNewSerializerAPI` set to `true` this helper calls `normalizeResponse` + instead of `extract`. + + All the built-in serializers get `isNewSerializerAPI` set to `true` automatically + if the feature flag is enabled. + + @method normalizeResponseHelper + @param {DS.Serializer} serializer + @param {DS.Store} store + @param {subclass of DS.Model} modelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document +*/ +export function normalizeResponseHelper(serializer, store, modelClass, payload, id, requestType) { + if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && serializer.get('isNewSerializerAPI')) { + return serializer.normalizeResponse(store, modelClass, payload, id, requestType); + } else { + if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { + Ember.deprecate('Your custom serializer uses the old version of the Serializer API, with `extract` hooks. Please upgrade your serializers to the new Serializer API using `normalizeResponse` hooks instead.'); + } + let serializerPayload = serializer.extract(store, modelClass, payload, id, requestType); + return _normalizeSerializerPayload(modelClass, serializerPayload); + } +} + +/** + Convert the payload from `serializer.extract` to a JSON-API Document. + + @method _normalizeSerializerPayload + @private + @param {subclass of DS.Model} modelClass + @param {Object} payload + @return {Object} JSON-API Document +*/ +export function _normalizeSerializerPayload(modelClass, payload) { + let data = null; + + if (payload) { + if (Ember.isArray(payload)) { + data = map(payload, (payload) => { + return _normalizeSerializerPayloadItem(modelClass, payload); + }); + } else { + data = _normalizeSerializerPayloadItem(modelClass, payload); + } + } + + return { data }; +} + +/** + Convert the payload representing a single record from `serializer.extract` to + a JSON-API Resource Object. + + @method _normalizeSerializerPayloadItem + @private + @param {subclass of DS.Model} modelClass + @param {Object} payload + @return {Object} JSON-API Resource Object +*/ +export function _normalizeSerializerPayloadItem(modelClass, itemPayload) { + var item = {}; + + item.id = '' + itemPayload.id; + item.type = modelClass.modelName; + item.attributes = {}; + item.relationships = {}; + + modelClass.eachAttribute(function(name) { + if (itemPayload.hasOwnProperty(name)) { + item.attributes[name] = itemPayload[name]; + } + }); + + modelClass.eachRelationship(function(key, relationshipMeta) { + var relationship, value; + + if (itemPayload.hasOwnProperty(key)) { + relationship = {}; + value = itemPayload[key]; + + let normalizeRelationshipData = function(value, relationshipMeta) { + if (Ember.isNone(value)) { + return null; + } + if (Ember.typeOf(value) === 'object') { + if (value.id) { + value.id = `${value.id}`; + } + return value; + } + return { id: `${value}`, type: relationshipMeta.type }; + }; + + if (relationshipMeta.kind === 'belongsTo') { + relationship.data = normalizeRelationshipData(value, relationshipMeta); + } else if (relationshipMeta.kind === 'hasMany') { + relationship.data = map(Ember.A(value), function(item) { + return normalizeRelationshipData(item, relationshipMeta); + }); + } + } + + if (itemPayload.links && itemPayload.links.hasOwnProperty(key)) { + relationship = relationship || {}; + value = itemPayload.links[key]; + + relationship.links = { + related: value + }; + } + + if (relationship) { + item.relationships[key] = relationship; + } + }); + + return item; +} + +/** + Push a JSON-API Document to the store. + + This will push both primary data located in `data` and secondary data located + in `included` (if present). + + @method pushPayload + @param {DS.Store} store + @param {Object} payload + @return {DS.Model|Array} one or multiple records from `data` +*/ +export function pushPayload(store, payload) { + var result = pushPayloadData(store, payload); + pushPayloadIncluded(store, payload); + return result; +} + +/** + Push the primary data of a JSON-API Document to the store. + + This method only pushes the primary data located in `data`. + + @method pushPayloadData + @param {DS.Store} store + @param {Object} payload + @return {DS.Model|Array} one or multiple records from `data` +*/ +export function pushPayloadData(store, payload) { + var result; + if (payload && payload.data) { + if (Ember.isArray(payload.data)) { + result = map(payload.data, (item) => { + return _pushResourceObject(store, item); + }); + } else { + result = _pushResourceObject(store, payload.data); + } + } + return result; +} + +/** + Push the secondary data of a JSON-API Document to the store. + + This method only pushes the secondary data located in `included`. + + @method pushPayloadIncluded + @param {DS.Store} store + @param {Object} payload + @return {Array} an array containing zero or more records from `included` +*/ +export function pushPayloadIncluded(store, payload) { + var result; + if (payload && payload.included && Ember.isArray(payload.included)) { + result = map(payload.included, (item) => { + return _pushResourceObject(store, item); + }); + } + return result; +} + +/** + Push a single JSON-API Resource Object to the store. + + @method _pushResourceObject + @private + @param {Object} resourceObject + @return {DS.Model} a record +*/ +export function _pushResourceObject(store, resourceObject) { + return store.push(resourceObject.type, convertResourceObject(resourceObject)); +} + +/** + This method converts a JSON-API Resource Object to a format that DS.Store + understands. + + TODO: This method works as an interim until DS.Store understands JSON-API. + + @method convertResourceObject + @param {Object} payload + @return {Object} an object formatted the way DS.Store understands +*/ +export function convertResourceObject(payload) { + if (!payload) { + return payload; + } + + var data = { + id: payload.id, + type: payload.type, + links: {} + }; + + var attributeKeys = Ember.keys(payload.attributes); + forEach(attributeKeys, function(key) { + var attribute = payload.attributes[key]; + data[key] = attribute; + }); + + var relationshipKeys = Ember.keys(payload.relationships); + forEach(relationshipKeys, function(key) { + var relationship = payload.relationships[key]; + if (relationship.hasOwnProperty('data')) { + data[key] = relationship.data; + } else if (relationship.links && relationship.links.related) { + data.links[key] = relationship.links.related; + } + }); + return data; +} From 994c705895a36e5a5cca0074e98156539befd212 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 3 Jun 2015 00:35:32 +0300 Subject: [PATCH 0880/2527] Make JSONSerializer work with the new Serializer API --- .../lib/serializers/json-serializer.js | 460 +++++++++++++++++- .../serializers/json-serializer-new-test.js | 194 ++++++++ 2 files changed, 653 insertions(+), 1 deletion(-) create mode 100644 packages/ember-data/tests/integration/serializers/json-serializer-new-test.js diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index ee50f533d8c..655fb65af2d 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -1,10 +1,70 @@ import Serializer from "ember-data/system/serializer"; +import coerceId from "ember-data/system/coerce-id"; var get = Ember.get; var isNone = Ember.isNone; var map = Ember.ArrayPolyfills.map; var merge = Ember.merge; +/* + Ember Data 2.0 Serializer: + + In Ember Data a Serializer is used to serialize and deserialize + records when they are transferred in and out of an external source. + This process involves normalizing property names, transforming + attribute values and serializing relationships. + + By default Ember Data recommends using the JSONApiSerializer. + + `JSONSerializer` is useful for simpler or legacy backends that may + not support the http://jsonapi.org/ spec. + + `JSONSerializer` normalizes a JSON payload that looks like: + + ```js + App.User = DS.Model.extend({ + name: DS.attr(), + friends: DS.hasMany('user'), + house: DS.belongsTo('location'), + }); + ``` + ```js + { id: 1, + name: 'Sebastian', + friends: [3, 4], + links: { + house: '/houses/lefkada' + } + } + ``` + to JSONApi format that the Ember Data store expects. + + You can customize how JSONSerializer processes it's payload by passing options in + the attrs hash or by subclassing the JSONSerializer and overriding hooks: + + -To customize how a single record is normalized, use the `normalize` hook + -To customize how JSONSerializer normalizes the whole server response, use the + normalizeResponse hook + -To customize how JSONSerializer normalizes a specific response from the server, + use one of the many specific normalizeResponse hooks + -To customize how JSONSerializer normalizes your attributes or relationships, + use the extractAttributes and extractRelationships hooks. + + JSONSerializer normalization process follows these steps: + - `normalizeResponse` - entry method to the Serializer + - `normalizeCreateRecordResponse` - a normalizeResponse for a specific operation is called + - `normalizeSingleResponse`|`normalizeArrayResponse` - for methods like `createRecord` we expect + a single record back, while for methods like `findAll` we expect multiple methods back + - `normalize` - normalizeArray iterates and calls normalize for each of it's records while normalizeSingle + calls it once. This is the method you most likely want to subclass + - `extractId` | `extractAttributes` | `extractRelationships` - normalize delegates to these methods to + turn the record payload into the JSONApi format + + @class JSONSerializer + @namespace DS + @extends DS.Serializer +*/ + /** In Ember Data a Serializer is used to serialize and deserialize records when they are transferred in and out of an external source. @@ -22,6 +82,7 @@ var merge = Ember.merge; @extends DS.Serializer */ export default Serializer.extend({ + /** The primaryKey is used when serializing and deserializing data. Ember Data always uses the `id` property to store the id of @@ -134,6 +195,252 @@ export default Serializer.extend({ return data; }, + /* + The `normalizeResponse` method is used to normalize a payload from the + server to a JSON-API Document. + + http://jsonapi.org/format/#document-structure + + This method delegates to a more specific normalize method based on + the `requestType`. + + To override this method with a custom one, make sure to call + `return this._super(store, primaryModelClass, payload, id, requestType)` with your + pre-processed data. + + Here's an example of using `normalizeResponse` manually: + + ```javascript + socket.on('message', function(message) { + var data = message.data; + var modelClass = store.modelFor(data.modelName); + var serializer = store.serializerFor(data.modelName); + var json = serializer.normalizeSingleResponse(store, modelClass, data, data.id); + + store.push(normalized); + }); + ``` + + @method normalizeResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeResponse: function(store, primaryModelClass, payload, id, requestType) { + switch (requestType) { + case 'find': + return this.normalizeFindResponse(...arguments); + case 'findAll': + return this.normalizeFindAllResponse(...arguments); + case 'findBelongsTo': + return this.normalizeFindBelongsToResponse(...arguments); + case 'findHasMany': + return this.normalizeFindHasManyResponse(...arguments); + case 'findMany': + return this.normalizeFindManyResponse(...arguments); + case 'findQuery': + return this.normalizeFindQueryResponse(...arguments); + case 'createRecord': + return this.normalizeCreateRecordResponse(...arguments); + case 'deleteRecord': + return this.normalizeDeleteRecordResponse(...arguments); + case 'updateRecord': + return this.normalizeUpdateRecordResponse(...arguments); + } + }, + + /* + @method normalizeFindResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeFindResponse: function(store, primaryModelClass, payload, id, requestType) { + return this.normalizeSingleResponse(...arguments); + }, + + /* + @method normalizeFindAllResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeFindAllResponse: function(store, primaryModelClass, payload, id, requestType) { + return this.normalizeArrayResponse(...arguments); + }, + + /* + @method normalizeFindBelongsToResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeFindBelongsToResponse: function(store, primaryModelClass, payload, id, requestType) { + return this.normalizeSingleResponse(...arguments); + }, + + /* + @method normalizeFindHasManyResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeFindHasManyResponse: function(store, primaryModelClass, payload, id, requestType) { + return this.normalizeArrayResponse(...arguments); + }, + + /* + @method normalizeFindManyResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeFindManyResponse: function(store, primaryModelClass, payload, id, requestType) { + return this.normalizeArrayResponse(...arguments); + }, + + /* + @method normalizeFindQueryResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeFindQueryResponse: function(store, primaryModelClass, payload, id, requestType) { + return this.normalizeArrayResponse(...arguments); + }, + + /* + @method normalizeCreateRecordResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeCreateRecordResponse: function(store, primaryModelClass, payload, id, requestType) { + return this.normalizeSaveResponse(...arguments); + }, + + /* + @method normalizeDeleteRecordResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeDeleteRecordResponse: function(store, primaryModelClass, payload, id, requestType) { + return this.normalizeSaveResponse(...arguments); + }, + + /* + @method normalizeUpdateRecordResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeUpdateRecordResponse: function(store, primaryModelClass, payload, id, requestType) { + return this.normalizeSaveResponse(...arguments); + }, + + /* + @method normalizeSaveResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeSaveResponse: function(store, primaryModelClass, payload, id, requestType) { + return this.normalizeSingleResponse(...arguments); + }, + + /* + @method normalizeSingleResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeSingleResponse: function(store, primaryModelClass, payload, id, requestType) { + return this._normalizeResponse(store, primaryModelClass, payload, id, requestType, true); + }, + + /* + @method normalizeArrayResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeArrayResponse: function(store, primaryModelClass, payload, id, requestType) { + return this._normalizeResponse(store, primaryModelClass, payload, id, requestType, false); + }, + + /* + @method _normalizeResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @param {Boolean} isSingle + @return {Object} JSON-API Document + @private + */ + _normalizeResponse: function(store, primaryModelClass, payload, id, requestType, isSingle) { + let documentHash = { + data: null, + included: [] + }; + + payload = this.normalizePayload(payload); + + if (isSingle) { + let { data } = this.normalize(primaryModelClass, payload); + documentHash.data = data; + } else { + documentHash.data = payload.map((item) => { + let { data } = this.normalize(primaryModelClass, item); + return data; + }); + } + + return documentHash; + }, + + /** Normalizes a part of the JSON payload returned by the server. You should override this method, munge the hash @@ -172,6 +479,10 @@ export default Serializer.extend({ @return {Object} */ normalize: function(typeClass, hash) { + if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) { + return _newNormalize.apply(this, arguments); + } + if (!hash) { return hash; } this.normalizeId(hash); @@ -183,6 +494,115 @@ export default Serializer.extend({ return hash; }, + /* + Returns the resource's ID. + + @method extractId + @param {Object} resourceHash + @return {String} + */ + extractId: function(resourceHash) { + var primaryKey = get(this, 'primaryKey'); + var id = resourceHash[primaryKey]; + return coerceId(id); + }, + + /* + Returns the resource's attributes formatted as a JSON-API "attributes object". + + http://jsonapi.org/format/#document-resource-object-attributes + + @method extractId + @param {Object} resourceHash + @return {Object} + */ + extractAttributes: function(modelClass, resourceHash) { + var attributeKey; + var attributes = {}; + + modelClass.eachAttribute(function(key) { + attributeKey = this.keyForAttribute(key, 'deserialize'); + if (resourceHash.hasOwnProperty(attributeKey)) { + attributes[key] = resourceHash[attributeKey]; + } + }, this); + + return attributes; + }, + + /* + Returns a relationship formatted as a JSON-API "relationship object". + + http://jsonapi.org/format/#document-resource-object-relationships + + @method extractRelationship + @param {Object} relationshipModelName + @param {Object} relationshipHash + @return {Object} + */ + extractRelationship: function(relationshipModelName, relationshipHash) { + if (Ember.isNone(relationshipHash)) { return null; } + /* + When `relationshipHash` is an object it usually means that the relationship + is polymorphic. It could however also be embedded resources that the + EmbeddedRecordsMixin has be able to process. + */ + if (Ember.typeOf(relationshipHash) === 'object') { + if (relationshipHash.id) { + relationshipHash.id = coerceId(relationshipHash.id); + } + if (relationshipHash.type) { + relationshipHash.type = this.modelNameFromPayloadKey(relationshipHash.type); + } + return relationshipHash; + } + return { id: coerceId(relationshipHash), type: relationshipModelName }; + }, + + /* + Returns the resource's relationships formatted as a JSON-API "relationships object". + + http://jsonapi.org/format/#document-resource-object-relationships + + @method extractRelationships + @param {Object} modelClass + @param {Object} resourceHash + @return {Object} + */ + extractRelationships: function(modelClass, resourceHash) { + let relationships = {}; + + modelClass.eachRelationship(function(key, relationshipMeta) { + let relationship = null; + let relationshipKey = this.keyForRelationship(key, relationshipMeta.kind, 'deserialize'); + if (resourceHash.hasOwnProperty(relationshipKey)) { + let data = null; + let relationshipHash = resourceHash[relationshipKey]; + if (relationshipMeta.kind === 'belongsTo') { + data = this.extractRelationship(relationshipMeta.type, relationshipHash); + } else if (relationshipMeta.kind === 'hasMany') { + data = Ember.A(relationshipHash).map(function(item) { + return this.extractRelationship(relationshipMeta.type, item); + }, this); + } + relationship = { data }; + } + + let linkKey = this.keyForLink(key, relationshipMeta.kind); + if (resourceHash.links && resourceHash.links.hasOwnProperty(linkKey)) { + let related = resourceHash.links[linkKey]; + relationship = relationship || {}; + relationship.links = { related }; + } + + if (relationship) { + relationships[key] = relationship; + } + }, this); + + return relationships; + }, + /** You can use this method to normalize all payloads, regardless of whether they represent single records or an array. @@ -1114,11 +1534,23 @@ export default Serializer.extend({ @param {String} method @return {String} normalized key */ - keyForRelationship: function(key, typeClass, method) { return key; }, + /** + `keyForLink` can be used to define a custom key when deserializing link + properties. + + @method keyForLink + @param {String} key + @param {String} kind `belongsTo` or `hasMany` + @return {String} normalized key + */ + keyForLink: function(key, kind) { + return key; + }, + // HELPERS /** @@ -1134,3 +1566,29 @@ export default Serializer.extend({ return transform; } }); + +/* + @method _newNormalize + @param {DS.Model} modelClass + @param {Object} resourceHash + @return {Object} + @private +*/ +function _newNormalize(modelClass, resourceHash) { + let data = null; + + if (resourceHash) { + this.normalizeUsingDeclaredMapping(modelClass, resourceHash); + + data = { + id: this.extractId(resourceHash), + type: modelClass.modelName, + attributes: this.extractAttributes(modelClass, resourceHash), + relationships: this.extractRelationships(modelClass, resourceHash) + }; + + this.applyTransforms(modelClass, data.attributes); + } + + return { data }; +} diff --git a/packages/ember-data/tests/integration/serializers/json-serializer-new-test.js b/packages/ember-data/tests/integration/serializers/json-serializer-new-test.js new file mode 100644 index 00000000000..0e0b2caa58f --- /dev/null +++ b/packages/ember-data/tests/integration/serializers/json-serializer-new-test.js @@ -0,0 +1,194 @@ +var Post, post, Comment, Favorite, TestSerializer, env; +var run = Ember.run; + +module("integration/serializer/json - JSONSerializer (new API)", { + setup: function() { + Post = DS.Model.extend({ + title: DS.attr('string'), + comments: DS.hasMany('comment', { inverse: null }) + }); + Comment = DS.Model.extend({ + body: DS.attr('string'), + post: DS.belongsTo('post') + }); + Favorite = DS.Model.extend({ + post: DS.belongsTo('post', { async: true, polymorphic: true }) + }); + TestSerializer = DS.JSONSerializer.extend({ + isNewSerializerAPI: true + }); + env = setupStore({ + post: Post, + comment: Comment, + favorite: Favorite + }); + env.store.modelFor('post'); + env.store.modelFor('comment'); + env.store.modelFor('favorite'); + + env.registry.register('serializer:application', TestSerializer); + }, + + teardown: function() { + run(env.store, 'destroy'); + } +}); + +if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { + + test("normalizeArrayResponse normalizes each record in the array", function() { + var postNormalizeCount = 0; + var posts = [ + { id: "1", title: "Rails is omakase" }, + { id: "2", title: "Another Post" } + ]; + + env.registry.register('serializer:post', TestSerializer.extend({ + normalize: function () { + postNormalizeCount++; + return this._super.apply(this, arguments); + } + })); + + run(function() { + env.container.lookup("serializer:post").normalizeArrayResponse(env.store, Post, posts, null, 'findAll'); + }); + equal(postNormalizeCount, 2, "two posts are normalized"); + }); + + test('Serializer should respect the attrs hash when extracting records', function() { + env.registry.register("serializer:post", TestSerializer.extend({ + attrs: { + title: "title_payload_key", + comments: { key: 'my_comments' } + } + })); + + var jsonHash = { + id: "1", + title_payload_key: "Rails is omakase", + my_comments: [1, 2] + }; + + var post = env.container.lookup("serializer:post").normalizeSingleResponse(env.store, Post, jsonHash, '1', 'find'); + + equal(post.data.attributes.title, "Rails is omakase"); + deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }, { id: "2", type: "comment" }]); + }); + + test("Serializer should respect the primaryKey attribute when extracting records", function() { + env.registry.register('serializer:post', TestSerializer.extend({ + primaryKey: '_ID_' + })); + + var jsonHash = { "_ID_": 1, title: "Rails is omakase" }; + + run(function() { + post = env.container.lookup("serializer:post").normalizeSingleResponse(env.store, Post, jsonHash, '1', 'find'); + }); + + equal(post.data.id, "1"); + equal(post.data.attributes.title, "Rails is omakase"); + }); + + test("Serializer should respect keyForAttribute when extracting records", function() { + env.registry.register('serializer:post', TestSerializer.extend({ + keyForAttribute: function(key) { + return key.toUpperCase(); + } + })); + + var jsonHash = { id: 1, TITLE: 'Rails is omakase' }; + + post = env.container.lookup("serializer:post").normalize(Post, jsonHash); + + equal(post.data.id, "1"); + equal(post.data.attributes.title, "Rails is omakase"); + }); + + test("Serializer should respect keyForRelationship when extracting records", function() { + env.registry.register('serializer:post', TestSerializer.extend({ + keyForRelationship: function(key, type) { + return key.toUpperCase(); + } + })); + + var jsonHash = { id: 1, title: 'Rails is omakase', COMMENTS: ['1'] }; + + post = env.container.lookup("serializer:post").normalize(Post, jsonHash); + + deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }]); + }); + + test("normalizePayload is called during normalizeSingleResponse", function() { + var counter = 0; + + env.registry.register('serializer:post', TestSerializer.extend({ + normalizePayload: function(payload) { + counter++; + return payload.response; + } + })); + + var jsonHash = { + response: { + id: 1, + title: "Rails is omakase" + } + }; + + run(function() { + post = env.container.lookup("serializer:post").normalizeSingleResponse(env.store, Post, jsonHash, '1', 'find'); + }); + + equal(counter, 1); + equal(post.data.id, "1"); + equal(post.data.attributes.title, "Rails is omakase"); + }); + + test("Calling normalize should normalize the payload (only the passed keys)", function () { + expect(1); + var Person = DS.Model.extend({ + posts: DS.hasMany('post') + }); + env.registry.register('serializer:post', TestSerializer.extend({ + attrs: { + notInHash: 'aCustomAttrNotInHash', + inHash: 'aCustomAttrInHash' + } + })); + + env.registry.register('model:person', Person); + + Post.reopen({ + content: DS.attr('string'), + author: DS.belongsTo('person'), + notInHash: DS.attr('string'), + inHash: DS.attr('string') + }); + + var normalizedPayload = env.container.lookup("serializer:post").normalize(Post, { + id: '1', + title: 'Ember rocks', + author: 1, + aCustomAttrInHash: 'blah' + }); + + deepEqual(normalizedPayload, { + "data": { + "id": "1", + "type": "post", + "attributes": { + "inHash": "blah", + "title": "Ember rocks" + }, + "relationships": { + "author": { + "data": { "id": "1", "type": "person" } + } + } + } + }); + }); + +} From 2ba2d588d2a4b0b7ab7630851dd8b072dc41acf2 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Sun, 31 May 2015 12:27:10 +0200 Subject: [PATCH 0881/2527] Make RESTSerializer work with the new Serializer API --- .../lib/serializers/rest-serializer.js | 202 +++++++++ .../serializers/rest-serializer-new-test.js | 395 ++++++++++++++++++ .../serializers/rest-serializer-test.js | 338 +++++++-------- tests/ember-configuration.js | 4 + 4 files changed, 775 insertions(+), 164 deletions(-) create mode 100644 packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index 71ad7926941..da97a9d4350 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -6,6 +6,7 @@ import JSONSerializer from "ember-data/serializers/json-serializer"; import normalizeModelName from "ember-data/system/normalize-model-name"; import {singularize} from "ember-inflector/lib/system/string"; import coerceId from "ember-data/system/coerce-id"; +import { pushPayload } from "ember-data/system/store/serializer-response"; var forEach = Ember.ArrayPolyfills.forEach; var map = Ember.ArrayPolyfills.map; @@ -55,6 +56,7 @@ var camelize = Ember.String.camelize; @extends DS.JSONSerializer */ var RESTSerializer = JSONSerializer.extend({ + /** If you want to do normalizations specific to some part of the payload, you can specify those under `normalizeHash`. @@ -173,6 +175,11 @@ var RESTSerializer = JSONSerializer.extend({ @return {Object} */ normalize: function(typeClass, hash, prop) { + if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) { + _newNormalize.apply(this, arguments); + return this._super(...arguments); + } + this.normalizeId(hash); this.normalizeAttributes(typeClass, hash); this.normalizeRelationships(typeClass, hash); @@ -187,6 +194,150 @@ var RESTSerializer = JSONSerializer.extend({ return hash; }, + /* + Normalizes an array of resource payloads and returns a JSON-API Document + with primary data and, if any, included data as `{ data, included }`. + + @method normalizeArray + @param {DS.Store} store + @param {String} modelName + @param {Object} arrayHash + @param {String} prop + @return {Object} + */ + normalizeArray: function(store, modelName, arrayHash, prop) { + let documentHash = { + data: [], + included: [] + }; + + let modelClass = store.modelFor(modelName); + let serializer = store.serializerFor(modelName); + + /*jshint loopfunc:true*/ + forEach.call(arrayHash, (hash) => { + let { data, included } = serializer.normalize(modelClass, hash, prop); + documentHash.data.push(data); + documentHash.included.push(...included); + }, this); + + return documentHash; + }, + + /* + @method _normalizeResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @param {Boolean} isSingle + @return {Object} JSON-API Document + @private + */ + _normalizeResponse: function(store, primaryModelClass, payload, id, requestType, isSingle) { + var document = { + data: null, + included: [] + }; + + Ember.keys(payload).forEach((prop) => { + var modelName = prop; + var forcedSecondary = false; + + /* + If you want to provide sideloaded records of the same type that the + primary data you can do that by prefixing the key with `_`. + + Example + + ``` + { + users: [ + { id: 1, title: 'Tom', manager: 3 }, + { id: 2, title: 'Yehuda', manager: 3 } + ], + _users: [ + { id: 3, title: 'Tomster' } + ] + } + ``` + + This forces `_users` to be added to `included` instead of `data`. + */ + if (prop.charAt(0) === '_') { + forcedSecondary = true; + modelName = prop.substr(1); + } + + var typeName = this.modelNameFromPayloadKey(modelName); + if (!store.modelFactoryFor(typeName)) { + Ember.warn(this.warnMessageNoModelForKey(modelName, typeName), false); + return; + } + + var isPrimary = (!forcedSecondary && this.isPrimaryType(store, typeName, primaryModelClass)); + var value = payload[prop]; + + if (value === null) { + return; + } + + /* + Support primary data as an object instead of an array. + + Example + + ``` + { + user: { id: 1, title: 'Tom', manager: 3 } + } + ``` + */ + if (isPrimary && Ember.typeOf(value) !== 'array') { + let { data, included } = this.normalize(primaryModelClass, value, prop); + document.data = data; + document.included.push(...included); + return; + } + + let { data, included } = this.normalizeArray(store, typeName, value, prop); + + document.included.push(...included); + + if (isSingle) { + /*jshint loopfunc:true*/ + forEach.call(data, function(resource) { + + /* + Figures out if this is the primary record or not. + + It's either: + + 1. The record with the same ID as the original request + 2. If it's a newly created record without an ID, the first record + in the array + */ + var isUpdatedRecord = isPrimary && coerceId(resource.id) === id; + var isFirstCreatedRecord = isPrimary && !id && !document.data; + + if (isFirstCreatedRecord || isUpdatedRecord) { + document.data = resource; + } else { + document.included.push(resource); + } + }); + } else { + if (isPrimary) { + document.data = data; + } else { + document.included.push(...data); + } + } + }); + + return document; + }, /** Called when the server has returned a payload representing @@ -494,6 +645,11 @@ var RESTSerializer = JSONSerializer.extend({ @param {Object} rawPayload */ pushPayload: function(store, rawPayload) { + if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) { + _newPushPayload.apply(this, arguments); + return; + } + var payload = this.normalizePayload(rawPayload); for (var prop in payload) { @@ -855,3 +1011,49 @@ Ember.runInDebug(function() { }); export default RESTSerializer; + +/* + @method _newNormalize + @param {DS.Model} modelClass + @param {Object} resourceHash + @param {String} prop + @return {Object} + @private +*/ +function _newNormalize(modelClass, resourceHash, prop) { + if (this.normalizeHash && this.normalizeHash[prop]) { + this.normalizeHash[prop](resourceHash); + } +} + +/* + @method _newPushPayload + @param {DS.Store} store + @param {Object} rawPayload +*/ +function _newPushPayload(store, rawPayload) { + let documentHash = { + data: [], + included: [] + }; + let payload = this.normalizePayload(rawPayload); + + for (var prop in payload) { + var modelName = this.modelNameFromPayloadKey(prop); + if (!store.modelFactoryFor(modelName)) { + Ember.warn(this.warnMessageNoModelForKey(prop, modelName), false); + continue; + } + var type = store.modelFor(modelName); + var typeSerializer = store.serializerFor(type); + + /*jshint loopfunc:true*/ + forEach.call(Ember.makeArray(payload[prop]), (hash) => { + let { data, included } = typeSerializer.normalize(type, hash, prop); + documentHash.data.push(data); + documentHash.included.push(...included); + }, this); + } + + pushPayload(store, documentHash); +} diff --git a/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js b/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js new file mode 100644 index 00000000000..ca85ab4c304 --- /dev/null +++ b/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js @@ -0,0 +1,395 @@ +var HomePlanet, SuperVillain, EvilMinion, YellowMinion, DoomsdayDevice, Comment, TestSerializer, env; +var run = Ember.run; + +module("integration/serializer/rest - RESTSerializer (new API)", { + setup: function() { + HomePlanet = DS.Model.extend({ + name: DS.attr('string'), + superVillains: DS.hasMany('superVillain') + }); + SuperVillain = DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + homePlanet: DS.belongsTo("homePlanet"), + evilMinions: DS.hasMany("evilMinion") + }); + EvilMinion = DS.Model.extend({ + superVillain: DS.belongsTo('superVillain'), + name: DS.attr('string') + }); + YellowMinion = EvilMinion.extend(); + DoomsdayDevice = DS.Model.extend({ + name: DS.attr('string'), + evilMinion: DS.belongsTo('evilMinion', { polymorphic: true }) + }); + Comment = DS.Model.extend({ + body: DS.attr('string'), + root: DS.attr('boolean'), + children: DS.hasMany('comment', { inverse: null }) + }); + TestSerializer = DS.RESTSerializer.extend({ + isNewSerializerAPI: true + }); + env = setupStore({ + superVillain: SuperVillain, + homePlanet: HomePlanet, + evilMinion: EvilMinion, + yellowMinion: YellowMinion, + doomsdayDevice: DoomsdayDevice, + comment: Comment + }); + + //env.registry.register('serializer:application', TestSerializer.extend()); + + env.store.modelFor('superVillain'); + env.store.modelFor('homePlanet'); + env.store.modelFor('evilMinion'); + env.store.modelFor('yellowMinion'); + env.store.modelFor('doomsdayDevice'); + env.store.modelFor('comment'); + + env.registry.register('serializer:application', TestSerializer); + }, + + teardown: function() { + run(env.store, 'destroy'); + } +}); + +if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { + + test("normalizeSingleResponse with custom modelNameFromPayloadKey", function() { + expect(1); + + env.restNewSerializer.modelNameFromPayloadKey = function(root) { + var camelized = Ember.String.camelize(root); + return Ember.String.singularize(camelized); + }; + + var jsonHash = { + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], + super_villains: [{ id: "1", firstName: "Tom", lastName: "Dale", homePlanet: "1" }] + }; + var array; + + run(function() { + array = env.container.lookup("serializer:application").normalizeSingleResponse(env.store, HomePlanet, jsonHash, '1', 'find'); + }); + + deepEqual(array, { + data: { + id: '1', + type: 'home-planet', + attributes: { + name: 'Umber' + }, + relationships: { + superVillains: { + data: [{ id: '1', type: 'super-villain' }] + } + } + }, + included: [{ + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale' + }, + relationships: { + homePlanet: { + data: { id: '1', type: 'home-planet' } + } + } + }] + }); + }); + + test("normalizeArrayResponse warning with custom modelNameFromPayloadKey", function() { + var homePlanets; + env.restNewSerializer.modelNameFromPayloadKey = function(root) { + //return some garbage that won"t resolve in the container + return "garbage"; + }; + + var jsonHash = { + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] + }; + + warns(function() { + env.restNewSerializer.normalizeArrayResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); + }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); + + // should not warn if a model is found. + env.restNewSerializer.modelNameFromPayloadKey = function(root) { + return Ember.String.camelize(Ember.String.singularize(root)); + }; + + jsonHash = { + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] + }; + + noWarns(function() { + run(function() { + homePlanets = env.restNewSerializer.normalizeArrayResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); + }); + }); + + equal(homePlanets.data.length, 1); + equal(homePlanets.data[0].attributes.name, "Umber"); + deepEqual(homePlanets.data[0].relationships.superVillains.data, [{ id: '1', type: 'super-villain' }]); + }); + + test("normalizeSingleResponse warning with custom modelNameFromPayloadKey", function() { + var homePlanet; + var oldModelNameFromPayloadKey = env.restNewSerializer.modelNameFromPayloadKey; + env.restNewSerializer.modelNameFromPayloadKey = function(root) { + //return some garbage that won"t resolve in the container + return "garbage"; + }; + + var jsonHash = { + home_planet: { id: "1", name: "Umber", superVillains: [1] } + }; + + warns(Ember.run.bind(null, function() { + run(function() { + env.restNewSerializer.normalizeSingleResponse(env.store, HomePlanet, jsonHash, '1', 'find'); + }); + }), /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); + + // should not warn if a model is found. + env.restNewSerializer.modelNameFromPayloadKey = oldModelNameFromPayloadKey; + jsonHash = { + home_planet: { id: "1", name: "Umber", superVillains: [1] } + }; + + noWarns(function() { + run(function() { + homePlanet = env.restNewSerializer.normalizeSingleResponse(env.store, HomePlanet, jsonHash, 1, 'find'); + }); + }); + + equal(homePlanet.data.attributes.name, "Umber"); + deepEqual(homePlanet.data.relationships.superVillains.data, [{ id: '1', type: 'super-villain' }]); + }); + + test("normalizeResponse can load secondary records of the same type without affecting the query count", function() { + var jsonHash = { + comments: [{ id: "1", body: "Parent Comment", root: true, children: [2, 3] }], + _comments: [ + { id: "2", body: "Child Comment 1", root: false }, + { id: "3", body: "Child Comment 2", root: false } + ] + }; + var array; + + run(function() { + array = env.restNewSerializer.normalizeResponse(env.store, Comment, jsonHash, '1', 'find'); + }); + + deepEqual(array, { + "data": { + "id": "1", + "type": "comment", + "attributes": { + "body": "Parent Comment", + "root": true + }, + "relationships": { + "children": { + "data": [ + { "id": "2", "type": "comment" }, + { "id": "3", "type": "comment" } + ] + } + } + }, + "included": [{ + "id": "2", + "type": "comment", + "attributes": { + "body": "Child Comment 1", + "root": false + }, + "relationships": {} + }, { + "id": "3", + "type": "comment", + "attributes": { + "body": "Child Comment 2", + "root": false + }, + "relationships": {} + }] + }); + + // normalizeResponse does not push records to the store + //equal(env.store.recordForId("comment", "2").get("body"), "Child Comment 1", "Secondary records are in the store"); + //equal(env.store.recordForId("comment", "3").get("body"), "Child Comment 2", "Secondary records are in the store"); + }); + + test("normalizeSingleResponse loads secondary records with correct serializer", function() { + var superVillainNormalizeCount = 0; + + env.registry.register('serializer:super-villain', TestSerializer.extend({ + normalize: function() { + superVillainNormalizeCount++; + return this._super.apply(this, arguments); + } + })); + + var jsonHash = { + evilMinion: { id: "1", name: "Tom Dale", superVillain: 1 }, + superVillains: [{ id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1" }] + }; + + run(function() { + env.restNewSerializer.normalizeSingleResponse(env.store, EvilMinion, jsonHash, '1', 'find'); + }); + + equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); + }); + + test("normalizeSingleResponse returns null if payload contains null", function() { + expect(1); + + var jsonHash = { + evilMinion: null + }; + var value; + + run(function() { + value = env.restNewSerializer.normalizeSingleResponse(env.store, EvilMinion, jsonHash, null, 'find'); + }); + + deepEqual(value, { data: null, included: [] }, "returned value is null"); + }); + + test("normalizeArrayResponse loads secondary records with correct serializer", function() { + var superVillainNormalizeCount = 0; + + env.registry.register('serializer:super-villain', TestSerializer.extend({ + normalize: function() { + superVillainNormalizeCount++; + return this._super.apply(this, arguments); + } + })); + + var jsonHash = { + evilMinions: [{ id: "1", name: "Tom Dale", superVillain: 1 }], + superVillains: [{ id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1" }] + }; + + run(function() { + env.restNewSerializer.normalizeArrayResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); + }); + + equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); + }); + + test('normalizeHash normalizes specific parts of the payload', function() { + env.registry.register('serializer:application', TestSerializer.extend({ + normalizeHash: { + homePlanets: function(hash) { + hash.id = hash._id; + delete hash._id; + return hash; + } + } + })); + + var jsonHash = { + homePlanets: [{ _id: "1", name: "Umber", superVillains: [1] }] + }; + var array; + + run(function() { + array = env.restNewSerializer.normalizeArrayResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); + }); + + deepEqual(array, { + "data": [{ + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "superVillains": { + "data": [ + { "id": "1", "type": "super-villain" } + ] + } + } + }], + "included": [] + }); + + }); + + test('normalizeHash works with transforms', function() { + env.registry.register('serializer:application', TestSerializer.extend({ + normalizeHash: { + evilMinions: function(hash) { + hash.condition = hash._condition; + delete hash._condition; + return hash; + } + } + })); + + env.registry.register('transform:condition', DS.Transform.extend({ + deserialize: function(serialized) { + if (serialized === 1) { + return "healing"; + } else { + return "unknown"; + } + }, + serialize: function(deserialized) { + if (deserialized === "healing") { + return 1; + } else { + return 2; + } + } + })); + + EvilMinion.reopen({ condition: DS.attr('condition') }); + + var jsonHash = { + evilMinions: [{ id: "1", name: "Tom Dale", superVillain: 1, _condition: 1 }] + }; + var array; + + run(function() { + array = env.restNewSerializer.normalizeArrayResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); + }); + + equal(array.data[0].attributes.condition, "healing"); + }); + + test('normalize should allow for different levels of normalization', function() { + env.registry.register('serializer:application', TestSerializer.extend({ + attrs: { + superVillain: 'is_super_villain' + }, + keyForAttribute: function(attr) { + return Ember.String.decamelize(attr); + } + })); + + var jsonHash = { + evilMinions: [{ id: "1", name: "Tom Dale", is_super_villain: 1 }] + }; + var array; + + run(function() { + array = env.restNewSerializer.normalizeArrayResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); + }); + + equal(array.data[0].relationships.superVillain.data.id, 1); + }); + +} diff --git a/packages/ember-data/tests/integration/serializers/rest-serializer-test.js b/packages/ember-data/tests/integration/serializers/rest-serializer-test.js index c2e1f746a79..9dc79a01c6f 100644 --- a/packages/ember-data/tests/integration/serializers/rest-serializer-test.js +++ b/packages/ember-data/tests/integration/serializers/rest-serializer-test.js @@ -57,69 +57,73 @@ test("modelNameFromPayloadKey returns always same modelName even for uncountable equal(env.restSerializer.modelNameFromPayloadKey('multi-words'), expectedModelName); }); -test("extractArray with custom modelNameFromPayloadKey", function() { - env.restSerializer.modelNameFromPayloadKey = function(root) { - var camelized = Ember.String.camelize(root); - return Ember.String.singularize(camelized); - }; - - var jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], - super_villains: [{ id: "1", firstName: "Tom", lastName: "Dale", homePlanet: "1" }] - }; - var array; +if (!Ember.FEATURES.isEnabled('ds-new-serializer-api')) { + test("extractArray with custom modelNameFromPayloadKey", function() { + env.restSerializer.modelNameFromPayloadKey = function(root) { + var camelized = Ember.String.camelize(root); + return Ember.String.singularize(camelized); + }; + + var jsonHash = { + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], + super_villains: [{ id: "1", firstName: "Tom", lastName: "Dale", homePlanet: "1" }] + }; + var array; - run(function() { - array = env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); - }); + run(function() { + array = env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); + }); - deepEqual(array, [{ - id: "1", - name: "Umber", - superVillains: [1] - }]); + deepEqual(array, [{ + id: "1", + name: "Umber", + superVillains: [1] + }]); - run(function() { - env.store.find('super-villain', 1).then(function(minion) { - equal(minion.get('firstName'), "Tom"); + run(function() { + env.store.find('super-villain', 1).then(function(minion) { + equal(minion.get('firstName'), "Tom"); + }); }); }); -}); +} -test("extractArray warning with custom modelNameFromPayloadKey", function() { - var homePlanets; - env.restSerializer.modelNameFromPayloadKey = function(root) { - //return some garbage that won"t resolve in the container - return "garbage"; - }; +if (!Ember.FEATURES.isEnabled('ds-new-serializer-api')) { + test("extractArray warning with custom modelNameFromPayloadKey", function() { + var homePlanets; + env.restSerializer.modelNameFromPayloadKey = function(root) { + //return some garbage that won"t resolve in the container + return "garbage"; + }; - var jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] - }; + var jsonHash = { + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] + }; - warns(function() { - env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); - }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); + warns(function() { + env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); + }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); - // should not warn if a model is found. - env.restSerializer.modelNameFromPayloadKey = function(root) { - return Ember.String.camelize(Ember.String.singularize(root)); - }; + // should not warn if a model is found. + env.restSerializer.modelNameFromPayloadKey = function(root) { + return Ember.String.camelize(Ember.String.singularize(root)); + }; - jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] - }; + jsonHash = { + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] + }; - noWarns(function() { - run(function() { - homePlanets = Ember.A(env.restSerializer.extractArray(env.store, HomePlanet, jsonHash)); + noWarns(function() { + run(function() { + homePlanets = Ember.A(env.restSerializer.extractArray(env.store, HomePlanet, jsonHash)); + }); }); - }); - equal(get(homePlanets, "length"), 1); - equal(get(homePlanets, "firstObject.name"), "Umber"); - deepEqual(get(homePlanets, "firstObject.superVillains"), [1]); -}); + equal(get(homePlanets, "length"), 1); + equal(get(homePlanets, "firstObject.name"), "Umber"); + deepEqual(get(homePlanets, "firstObject.superVillains"), [1]); + }); +} test("extractSingle warning with custom modelNameFromPayloadKey", function() { var homePlanet; @@ -157,116 +161,120 @@ test("extractSingle warning with custom modelNameFromPayloadKey", function() { deepEqual(get(homePlanet, "superVillains"), [1]); }); -test("pushPayload - single record payload - warning with custom modelNameFromPayloadKey", function() { - var homePlanet; - var HomePlanetRestSerializer = DS.RESTSerializer.extend({ - modelNameFromPayloadKey: function(root) { - //return some garbage that won"t resolve in the container - if (root === "home_planet") { - return "garbage"; - } else { - return Ember.String.singularize(Ember.String.camelize(root)); +if (!Ember.FEATURES.isEnabled('ds-new-serializer-api')) { + test("pushPayload - single record payload - warning with custom modelNameFromPayloadKey", function() { + var homePlanet; + var HomePlanetRestSerializer = DS.RESTSerializer.extend({ + modelNameFromPayloadKey: function(root) { + //return some garbage that won"t resolve in the container + if (root === "home_planet") { + return "garbage"; + } else { + return Ember.String.singularize(Ember.String.camelize(root)); + } } - } - }); - - env.registry.register("serializer:home-planet", HomePlanetRestSerializer); - - var jsonHash = { - home_planet: { id: "1", name: "Umber", superVillains: [1] }, - super_villains: [{ id: "1", firstName: "Stanley" }] - }; - - warns(function() { - run(function() { - env.store.pushPayload('home-planet', jsonHash); }); - }, /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); - - // assert non-warned records get pushed into store correctly - var superVillain = env.store.getById('super-villain', "1"); - equal(get(superVillain, "firstName"), "Stanley"); + env.registry.register("serializer:home-planet", HomePlanetRestSerializer); - // Serializers are singletons, so that"s why we use the store which - // looks at the container to look it up - env.store.serializerFor('home-planet').reopen({ - modelNameFromPayloadKey: function(root) { - // should not warn if a model is found. - return Ember.String.camelize(Ember.String.singularize(root)); - } - }); + var jsonHash = { + home_planet: { id: "1", name: "Umber", superVillains: [1] }, + super_villains: [{ id: "1", firstName: "Stanley" }] + }; - jsonHash = { - home_planet: { id: "1", name: "Umber", superVillains: [1] }, - super_villains: [{ id: "1", firstName: "Stanley" }] - }; + warns(function() { + run(function() { + env.store.pushPayload('home-planet', jsonHash); + }); + }, /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); - noWarns(function() { - run(function() { - env.store.pushPayload('home-planet', jsonHash); - homePlanet = env.store.getById('home-planet', "1"); - }); - }); - equal(get(homePlanet, "name"), "Umber"); - deepEqual(get(homePlanet, "superVillains.firstObject.firstName"), "Stanley"); -}); + // assert non-warned records get pushed into store correctly + var superVillain = env.store.getById('super-villain', "1"); + equal(get(superVillain, "firstName"), "Stanley"); -test("pushPayload - multiple record payload (extractArray) - warning with custom modelNameFromPayloadKey", function() { - var homePlanet; - var HomePlanetRestSerializer = DS.RESTSerializer.extend({ - modelNameFromPayloadKey: function(root) { - //return some garbage that won"t resolve in the container - if (root === "home_planets") { - return "garbage"; - } else { - return Ember.String.singularize(Ember.String.camelize(root)); + // Serializers are singletons, so that"s why we use the store which + // looks at the container to look it up + env.store.serializerFor('home-planet').reopen({ + modelNameFromPayloadKey: function(root) { + // should not warn if a model is found. + return Ember.String.camelize(Ember.String.singularize(root)); } - } - }); - - env.registry.register("serializer:home-planet", HomePlanetRestSerializer); + }); - var jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], - super_villains: [{ id: "1", firstName: "Stanley" }] - }; + jsonHash = { + home_planet: { id: "1", name: "Umber", superVillains: [1] }, + super_villains: [{ id: "1", firstName: "Stanley" }] + }; - warns(function() { - run(function() { - env.store.pushPayload('home-planet', jsonHash); + noWarns(function() { + run(function() { + env.store.pushPayload('home-planet', jsonHash); + homePlanet = env.store.getById('home-planet', "1"); + }); }); - }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); - - // assert non-warned records get pushed into store correctly - var superVillain = env.store.getById('super-villain', "1"); - equal(get(superVillain, "firstName"), "Stanley"); - // Serializers are singletons, so that"s why we use the store which - // looks at the container to look it up - env.store.serializerFor('home-planet').reopen({ - modelNameFromPayloadKey: function(root) { - // should not warn if a model is found. - return Ember.String.camelize(Ember.String.singularize(root)); - } + equal(get(homePlanet, "name"), "Umber"); + deepEqual(get(homePlanet, "superVillains.firstObject.firstName"), "Stanley"); }); +} + +if (!Ember.FEATURES.isEnabled('ds-new-serializer-api')) { + test("pushPayload - multiple record payload (extractArray) - warning with custom modelNameFromPayloadKey", function() { + var homePlanet; + var HomePlanetRestSerializer = DS.RESTSerializer.extend({ + modelNameFromPayloadKey: function(root) { + //return some garbage that won"t resolve in the container + if (root === "home_planets") { + return "garbage"; + } else { + return Ember.String.singularize(Ember.String.camelize(root)); + } + } + }); - jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], - super_villains: [{ id: "1", firstName: "Stanley" }] - }; + env.registry.register("serializer:home-planet", HomePlanetRestSerializer); + + var jsonHash = { + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], + super_villains: [{ id: "1", firstName: "Stanley" }] + }; + + warns(function() { + run(function() { + env.store.pushPayload('home-planet', jsonHash); + }); + }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); + + // assert non-warned records get pushed into store correctly + var superVillain = env.store.getById('super-villain', "1"); + equal(get(superVillain, "firstName"), "Stanley"); + + // Serializers are singletons, so that"s why we use the store which + // looks at the container to look it up + env.store.serializerFor('home-planet').reopen({ + modelNameFromPayloadKey: function(root) { + // should not warn if a model is found. + return Ember.String.camelize(Ember.String.singularize(root)); + } + }); - noWarns(function() { - run(function() { - env.store.pushPayload('home-planet', jsonHash); - homePlanet = env.store.getById('home-planet', "1"); + jsonHash = { + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], + super_villains: [{ id: "1", firstName: "Stanley" }] + }; + + noWarns(function() { + run(function() { + env.store.pushPayload('home-planet', jsonHash); + homePlanet = env.store.getById('home-planet', "1"); + }); }); - }); - equal(get(homePlanet, "name"), "Umber"); - deepEqual(get(homePlanet, "superVillains.firstObject.firstName"), "Stanley"); -}); + equal(get(homePlanet, "name"), "Umber"); + deepEqual(get(homePlanet, "superVillains.firstObject.firstName"), "Stanley"); + }); +} test("serialize polymorphicType", function() { var tom, ray; @@ -332,32 +340,34 @@ test("serialize polymorphic when associated object is null", function() { deepEqual(json["evilMinionType"], null); }); -test("extractArray can load secondary records of the same type without affecting the query count", function() { - var jsonHash = { - comments: [{ id: "1", body: "Parent Comment", root: true, children: [2, 3] }], - _comments: [ - { id: "2", body: "Child Comment 1", root: false }, - { id: "3", body: "Child Comment 2", root: false } - ] - }; - var array; +if (!Ember.FEATURES.isEnabled('ds-new-serializer-api')) { + test("extractArray can load secondary records of the same type without affecting the query count", function() { + var jsonHash = { + comments: [{ id: "1", body: "Parent Comment", root: true, children: [2, 3] }], + _comments: [ + { id: "2", body: "Child Comment 1", root: false }, + { id: "3", body: "Child Comment 2", root: false } + ] + }; + var array; - run(function() { - array = env.restSerializer.extractArray(env.store, Comment, jsonHash); - }); + run(function() { + array = env.restSerializer.extractArray(env.store, Comment, jsonHash); + }); - deepEqual(array, [{ - "id": "1", - "body": "Parent Comment", - "root": true, - "children": [2, 3] - }]); + deepEqual(array, [{ + "id": "1", + "body": "Parent Comment", + "root": true, + "children": [2, 3] + }]); - equal(array.length, 1, "The query count is unaffected"); + equal(array.length, 1, "The query count is unaffected"); - equal(env.store.recordForId('comment', "2").get("body"), "Child Comment 1", "Secondary records are in the store"); - equal(env.store.recordForId('comment', "3").get("body"), "Child Comment 2", "Secondary records are in the store"); -}); + equal(env.store.recordForId('comment', "2").get("body"), "Child Comment 1", "Secondary records are in the store"); + equal(env.store.recordForId('comment', "3").get("body"), "Child Comment 2", "Secondary records are in the store"); + }); +} test("extractSingle loads secondary records with correct serializer", function() { var superVillainNormalizeCount = 0; diff --git a/tests/ember-configuration.js b/tests/ember-configuration.js index 12108ded4f7..3d0c7a4f754 100644 --- a/tests/ember-configuration.js +++ b/tests/ember-configuration.js @@ -92,14 +92,18 @@ registry.register('serializer:-default', DS.JSONSerializer); registry.register('serializer:-rest', DS.RESTSerializer); + registry.register('serializer:-rest-new', DS.RESTSerializer.extend({ isNewSerializerAPI: true })); + registry.register('adapter:-active-model', DS.ActiveModelAdapter); registry.register('serializer:-active-model', DS.ActiveModelSerializer); + registry.register('adapter:-rest', DS.RESTAdapter); registry.injection('serializer', 'store', 'store:main'); env.serializer = container.lookup('serializer:-default'); env.restSerializer = container.lookup('serializer:-rest'); + env.restNewSerializer = container.lookup('serializer:-rest-new'); env.store = container.lookup('store:main'); env.adapter = env.store.get('defaultAdapter'); From 7931842f0d65ad70104d86c65bb25430c3a3d1ae Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Tue, 2 Jun 2015 15:50:19 +0300 Subject: [PATCH 0882/2527] Make ActiveModelSerializer work with the new Serializer API --- .../lib/system/active-model-serializer.js | 15 +- ...rializer-namespaced-model-name-new-test.js | 126 ++++++ ...-serializer-namespaced-model-name-test.js} | 0 .../active-model-serializer-new-test.js | 361 ++++++++++++++++++ 4 files changed, 500 insertions(+), 2 deletions(-) create mode 100644 packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-model-name-new-test.js rename packages/activemodel-adapter/tests/integration/{active-model-serializer-namespaced-modelname-test.js => active-model-serializer-namespaced-model-name-test.js} (100%) create mode 100644 packages/activemodel-adapter/tests/integration/active-model-serializer-new-test.js diff --git a/packages/activemodel-adapter/lib/system/active-model-serializer.js b/packages/activemodel-adapter/lib/system/active-model-serializer.js index 366d28882db..21dc587cf19 100644 --- a/packages/activemodel-adapter/lib/system/active-model-serializer.js +++ b/packages/activemodel-adapter/lib/system/active-model-serializer.js @@ -132,6 +132,19 @@ var ActiveModelSerializer = RESTSerializer.extend({ } }, + /** + `keyForLink` can be used to define a custom key when deserializing link + properties. The `ActiveModelSerializer` camelizes link keys by default. + + @method keyForLink + @param {String} key + @param {String} kind `belongsTo` or `hasMany` + @return {String} normalized key + */ + keyForLink: function(key, relationshipKind) { + return camelize(key); + }, + /* Does not serialize hasMany relationships by default. */ @@ -205,10 +218,8 @@ var ActiveModelSerializer = RESTSerializer.extend({ @param {String} prop @return Object */ - normalize: function(typeClass, hash, prop) { this.normalizeLinks(hash); - return this._super(typeClass, hash, prop); }, diff --git a/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-model-name-new-test.js b/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-model-name-new-test.js new file mode 100644 index 00000000000..f4464c1162c --- /dev/null +++ b/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-model-name-new-test.js @@ -0,0 +1,126 @@ +var SuperVillain, EvilMinion, YellowMinion, DoomsdayDevice, MediocreVillain, TestSerializer, env; +var run = Ember.run; + +module("integration/active_model - AMS-namespaced-model-names (new API)", { + setup: function() { + SuperVillain = DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + evilMinions: DS.hasMany("evilMinion") + }); + + EvilMinion = DS.Model.extend({ + superVillain: DS.belongsTo('superVillain'), + name: DS.attr('string') + }); + YellowMinion = EvilMinion.extend(); + DoomsdayDevice = DS.Model.extend({ + name: DS.attr('string'), + evilMinion: DS.belongsTo('evilMinion', { polymorphic: true }) + }); + MediocreVillain = DS.Model.extend({ + name: DS.attr('string'), + evilMinions: DS.hasMany('evilMinion', { polymorphic: true }) + }); + TestSerializer = DS.ActiveModelSerializer.extend({ + isNewSerializerAPI: true + }); + env = setupStore({ + superVillain: SuperVillain, + evilMinion: EvilMinion, + 'evilMinions/yellowMinion': YellowMinion, + doomsdayDevice: DoomsdayDevice, + mediocreVillain: MediocreVillain + }); + env.store.modelFor('superVillain'); + env.store.modelFor('evilMinion'); + env.store.modelFor('evilMinions/yellowMinion'); + env.store.modelFor('doomsdayDevice'); + env.store.modelFor('mediocreVillain'); + env.registry.register('serializer:application', TestSerializer); + env.registry.register('serializer:-active-model', TestSerializer); + env.registry.register('adapter:-active-model', TestSerializer); + env.amsSerializer = env.container.lookup("serializer:-active-model"); + env.amsAdapter = env.container.lookup("adapter:-active-model"); + }, + + teardown: function() { + run(env.store, 'destroy'); + } +}); + +if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { + + test("extractPolymorphic hasMany", function() { + var json_hash = { + mediocre_villain: { id: 1, name: "Dr Horrible", evil_minion_ids: [{ type: "EvilMinions::YellowMinion", id: 12 }] }, + "evil-minions/yellow-minion": [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] + }; + var json; + + run(function() { + json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "mediocre-villain", + "attributes": { + "name": "Dr Horrible" + }, + "relationships": { + "evilMinions": { + "data": [ + { "id": "12", "type": "evil-minions/yellow-minion" } + ] + } + } + }, + "included": [{ + "id": "12", + "type": "evil-minions/yellow-minion", + "attributes": { + "name": "Alex" + }, + "relationships": {} + }] + }); + }); + + test("extractPolymorphic belongsTo", function() { + var json_hash = { + doomsday_device: { id: 1, name: "DeathRay", evil_minion_id: { type: "EvilMinions::YellowMinion", id: 12 } }, + "evil-minions/yellow-minion": [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] + }; + var json; + + run(function() { + json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "doomsday-device", + "attributes": { + "name": "DeathRay" + }, + "relationships": { + "evilMinion": { + "data": { "id": "12", "type": "evil-minions/yellow-minion" } + } + } + }, + "included": [{ + "id": "12", + "type": "evil-minions/yellow-minion", + "attributes": { + "name": "Alex" + }, + "relationships": {} + }] + }); + }); + +} diff --git a/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-modelname-test.js b/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-model-name-test.js similarity index 100% rename from packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-modelname-test.js rename to packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-model-name-test.js diff --git a/packages/activemodel-adapter/tests/integration/active-model-serializer-new-test.js b/packages/activemodel-adapter/tests/integration/active-model-serializer-new-test.js new file mode 100644 index 00000000000..fcfba817517 --- /dev/null +++ b/packages/activemodel-adapter/tests/integration/active-model-serializer-new-test.js @@ -0,0 +1,361 @@ +var HomePlanet, SuperVillain, EvilMinion, YellowMinion, DoomsdayDevice, MediocreVillain, TestSerializer, env; +var run = Ember.run; + +module("integration/active_model - ActiveModelSerializer (new API)", { + setup: function() { + SuperVillain = DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + homePlanet: DS.belongsTo("homePlanet"), + evilMinions: DS.hasMany("evilMinion") + }); + HomePlanet = DS.Model.extend({ + name: DS.attr('string'), + superVillains: DS.hasMany('superVillain', { async: true }) + }); + EvilMinion = DS.Model.extend({ + superVillain: DS.belongsTo('superVillain'), + name: DS.attr('string') + }); + YellowMinion = EvilMinion.extend(); + DoomsdayDevice = DS.Model.extend({ + name: DS.attr('string'), + evilMinion: DS.belongsTo('evilMinion', { polymorphic: true }) + }); + MediocreVillain = DS.Model.extend({ + name: DS.attr('string'), + evilMinions: DS.hasMany('evilMinion', { polymorphic: true }) + }); + TestSerializer = DS.ActiveModelSerializer.extend({ + isNewSerializerAPI: true + }); + env = setupStore({ + superVillain: SuperVillain, + homePlanet: HomePlanet, + evilMinion: EvilMinion, + yellowMinion: YellowMinion, + doomsdayDevice: DoomsdayDevice, + mediocreVillain: MediocreVillain + }); + env.store.modelFor('superVillain'); + env.store.modelFor('homePlanet'); + env.store.modelFor('evilMinion'); + env.store.modelFor('yellowMinion'); + env.store.modelFor('doomsdayDevice'); + env.store.modelFor('mediocreVillain'); + env.registry.register('serializer:application', TestSerializer); + env.registry.register('serializer:-active-model', TestSerializer); + env.registry.register('adapter:-active-model', DS.ActiveModelAdapter); + env.amsSerializer = env.container.lookup("serializer:-active-model"); + env.amsAdapter = env.container.lookup("adapter:-active-model"); + }, + + teardown: function() { + run(env.store, 'destroy'); + } +}); + +if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { + + test("normalize", function() { + SuperVillain.reopen({ + yellowMinion: DS.belongsTo('yellowMinion') + }); + + var superVillain_hash = { + id: "1", + first_name: "Tom", + last_name: "Dale", + home_planet_id: "123", + evil_minion_ids: [1, 2] + }; + + var json = env.amsSerializer.normalize(SuperVillain, superVillain_hash, "superVillain"); + + deepEqual(json, { + "data": { + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": { + "evilMinions": { + "data": [ + { "id": "1", "type": "evil-minion" }, + { "id": "2", "type": "evil-minion" } + ] + }, + "homePlanet": { + "data": { "id": "123", "type": "home-planet" } + } + } + } + }); + }); + + test("normalize links", function() { + var home_planet = { + id: "1", + name: "Umber", + links: { super_villains: "/api/super_villians/1" } + }; + + var json = env.amsSerializer.normalize(HomePlanet, home_planet, "homePlanet"); + + equal(json.data.relationships.superVillains.links.related, "/api/super_villians/1", "normalize links"); + }); + + test("normalizeSingleResponse", function() { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + + var json_hash = { + home_planet: { id: "1", name: "Umber", super_villain_ids: [1] }, + super_villains: [{ + id: "1", + first_name: "Tom", + last_name: "Dale", + home_planet_id: "1" + }] + }; + + var json; + run(function() { + json = env.amsSerializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "superVillains": { + "data": [ + { "id": "1", "type": "super-villain" } + ] + } + } + }, + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": { + "homePlanet": { + "data": { "id": "1", "type": "home-planet" } + } + } + }] + }); + }); + + test("normalizeArrayResponse", function() { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + var array; + + var json_hash = { + home_planets: [{ id: "1", name: "Umber", super_villain_ids: [1] }], + super_villains: [{ id: "1", first_name: "Tom", last_name: "Dale", home_planet_id: "1" }] + }; + + run(function() { + array = env.amsSerializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); + }); + + deepEqual(array, { + "data": [{ + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "superVillains": { + "data": [ + { "id": "1", "type": "super-villain" } + ] + } + } + }], + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": { + "homePlanet": { + "data": { "id": "1", "type": "home-planet" } + } + } + }] + }); + }); + + test("extractPolymorphic hasMany", function() { + env.registry.register('adapter:yellowMinion', DS.ActiveModelAdapter); + MediocreVillain.toString = function() { return "MediocreVillain"; }; + YellowMinion.toString = function() { return "YellowMinion"; }; + + var json_hash = { + mediocre_villain: { id: 1, name: "Dr Horrible", evil_minion_ids: [{ type: "yellow_minion", id: 12 }] }, + yellow_minions: [{ id: 12, name: "Alex" }] + }; + var json; + + run(function() { + json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "mediocre-villain", + "attributes": { + "name": "Dr Horrible" + }, + "relationships": { + "evilMinions": { + "data": [ + { "id": "12", "type": "yellow-minion" } + ] + } + } + }, + "included": [{ + "id": "12", + "type": "yellow-minion", + "attributes": { + "name": "Alex" + }, + "relationships": {} + }] + }); + }); + + test("extractPolymorphic belongsTo", function() { + env.registry.register('adapter:yellowMinion', DS.ActiveModelAdapter); + EvilMinion.toString = function() { return "EvilMinion"; }; + YellowMinion.toString = function() { return "YellowMinion"; }; + + var json_hash = { + doomsday_device: { id: 1, name: "DeathRay", evil_minion_id: { type: "yellow_minion", id: 12 } }, + yellow_minions: [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] + }; + var json; + + run(function() { + json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "doomsday-device", + "attributes": { + "name": "DeathRay" + }, + "relationships": { + "evilMinion": { + "data": { "id": "12", "type": "yellow-minion" } + } + } + }, + "included": [{ + "id": "12", + "type": "yellow-minion", + "attributes": { + "name": "Alex" + }, + "relationships": {} + }] + }); + }); + + test("extractPolymorphic when the related data is not specified", function() { + var json = { + doomsday_device: { id: 1, name: "DeathRay" }, + evil_minions: [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] + }; + + run(function() { + json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "doomsday-device", + "attributes": { + "name": "DeathRay" + }, + "relationships": {} + }, + "included": [{ + "id": "12", + "type": "evil-minion", + "attributes": { + "name": "Alex" + }, + "relationships": {} + }] + }); + }); + + test("extractPolymorphic hasMany when the related data is not specified", function() { + var json = { + mediocre_villain: { id: 1, name: "Dr Horrible" } + }; + + run(function() { + json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "mediocre-villain", + "attributes": { + "name": "Dr Horrible" + }, + "relationships": {} + }, + "included": [] + }); + }); + + test("extractPolymorphic does not break hasMany relationships", function() { + var json = { + mediocre_villain: { id: 1, name: "Dr. Evil", evil_minion_ids: [] } + }; + + run(function () { + json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "mediocre-villain", + "attributes": { + "name": "Dr. Evil" + }, + "relationships": { + "evilMinions": { + "data": [] + } + } + }, + "included": [] + }); + }); + +} From 3313864ebbeedd5955a45af5e15ba3abe494feba Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Tue, 2 Jun 2015 03:06:47 +0300 Subject: [PATCH 0883/2527] Make EmbeddedRecordsMixin work with the new Serializer API --- .../lib/serializers/embedded-records-mixin.js | 246 +++- .../embedded-records-mixin-new-test.js | 1200 +++++++++++++++++ 2 files changed, 1377 insertions(+), 69 deletions(-) create mode 100644 packages/ember-data/tests/integration/serializers/embedded-records-mixin-new-test.js diff --git a/packages/ember-data/lib/serializers/embedded-records-mixin.js b/packages/ember-data/lib/serializers/embedded-records-mixin.js index d61102408ae..f600c5fdc5c 100644 --- a/packages/ember-data/lib/serializers/embedded-records-mixin.js +++ b/packages/ember-data/lib/serializers/embedded-records-mixin.js @@ -1,3 +1,5 @@ +var get = Ember.get; +var set = Ember.set; var forEach = Ember.EnumerableUtils.forEach; var camelize = Ember.String.camelize; @@ -122,7 +124,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ **/ normalize: function(typeClass, hash, prop) { var normalizedHash = this._super(typeClass, hash, prop); - return extractEmbeddedRecords(this, this.store, typeClass, normalizedHash); + return this._extractEmbeddedRecords(this, this.store, typeClass, normalizedHash); }, keyForRelationship: function(key, typeClass, method) { @@ -393,63 +395,123 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ attrsOption: function(attr) { var attrs = this.get('attrs'); return attrs && (attrs[camelize(attr)] || attrs[attr]); - } -}); + }, -// chooses a relationship kind to branch which function is used to update payload -// does not change payload if attr is not embedded -function extractEmbeddedRecords(serializer, store, typeClass, partial) { + /** + @method _extractEmbeddedRecords + @private + */ + _extractEmbeddedRecords: function(serializer, store, typeClass, partial) { + if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) { + return _newExtractEmbeddedRecords.apply(this, arguments); + } - typeClass.eachRelationship(function(key, relationship) { - if (serializer.hasDeserializeRecordsOption(key)) { - var embeddedTypeClass = store.modelFor(relationship.type); - if (relationship.kind === "hasMany") { - if (relationship.options.polymorphic) { - extractEmbeddedHasManyPolymorphic(store, key, partial); - } else { - extractEmbeddedHasMany(store, key, embeddedTypeClass, partial); + typeClass.eachRelationship(function(key, relationship) { + if (serializer.hasDeserializeRecordsOption(key)) { + var embeddedTypeClass = store.modelFor(relationship.type); + if (relationship.kind === "hasMany") { + if (relationship.options.polymorphic) { + this._extractEmbeddedHasManyPolymorphic(store, key, partial); + } else { + this._extractEmbeddedHasMany(store, key, embeddedTypeClass, partial); + } } - } - if (relationship.kind === "belongsTo") { - if (relationship.options.polymorphic) { - extractEmbeddedBelongsToPolymorphic(store, key, partial); - } else { - extractEmbeddedBelongsTo(store, key, embeddedTypeClass, partial); + if (relationship.kind === "belongsTo") { + if (relationship.options.polymorphic) { + this._extractEmbeddedBelongsToPolymorphic(store, key, partial); + } else { + this._extractEmbeddedBelongsTo(store, key, embeddedTypeClass, partial); + } } } + }, this); + + return partial; + }, + + /** + @method _extractEmbeddedHasMany + @private + */ + _extractEmbeddedHasMany: function(store, key, embeddedTypeClass, hash) { + if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) { + return _newExtractEmbeddedHasMany.apply(this, arguments); } - }); - return partial; -} + if (!hash[key]) { + return hash; + } + + var ids = []; -// handles embedding for `hasMany` relationship -function extractEmbeddedHasMany(store, key, embeddedTypeClass, hash) { - if (!hash[key]) { + var embeddedSerializer = store.serializerFor(embeddedTypeClass.modelName); + forEach(hash[key], function(data) { + var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null); + store.push(embeddedTypeClass.modelName, embeddedRecord); + ids.push(embeddedRecord.id); + }); + + hash[key] = ids; return hash; - } + }, - var ids = []; + /** + @method _extractEmbeddedHasManyPolymorphic + @private + */ + _extractEmbeddedHasManyPolymorphic: function(store, key, hash) { + if (!hash[key]) { + return hash; + } - var embeddedSerializer = store.serializerFor(embeddedTypeClass.modelName); - forEach(hash[key], function(data) { - var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null); - store.push(embeddedTypeClass.modelName, embeddedRecord); - ids.push(embeddedRecord.id); - }); + var ids = []; - hash[key] = ids; - return hash; -} + forEach(hash[key], function(data) { + var modelName = data.type; + var embeddedSerializer = store.serializerFor(modelName); + var embeddedTypeClass = store.modelFor(modelName); + // var primaryKey = embeddedSerializer.get('primaryKey'); + + var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null); + store.push(embeddedTypeClass.modelName, embeddedRecord); + ids.push({ id: embeddedRecord.id, type: modelName }); + }); -function extractEmbeddedHasManyPolymorphic(store, key, hash) { - if (!hash[key]) { + hash[key] = ids; return hash; - } + }, - var ids = []; + /** + @method _extractEmbeddedBelongsTo + @private + */ + _extractEmbeddedBelongsTo: function(store, key, embeddedTypeClass, hash) { + if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) { + return _newExtractEmbeddedBelongsTo.apply(this, arguments); + } + + if (!hash[key]) { + return hash; + } - forEach(hash[key], function(data) { + var embeddedSerializer = store.serializerFor(embeddedTypeClass.modelName); + var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, hash[key], null); + store.push(embeddedTypeClass.modelName, embeddedRecord); + + hash[key] = embeddedRecord.id; + return hash; + }, + + /** + @method _extractEmbeddedBelongsToPolymorphic + @private + */ + _extractEmbeddedBelongsToPolymorphic: function(store, key, hash) { + if (!hash[key]) { + return hash; + } + + var data = hash[key]; var modelName = data.type; var embeddedSerializer = store.serializerFor(modelName); var embeddedTypeClass = store.modelFor(modelName); @@ -457,43 +519,89 @@ function extractEmbeddedHasManyPolymorphic(store, key, hash) { var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null); store.push(embeddedTypeClass.modelName, embeddedRecord); - ids.push({ id: embeddedRecord.id, type: modelName }); - }); - hash[key] = ids; - return hash; -} - -function extractEmbeddedBelongsTo(store, key, embeddedTypeClass, hash) { - if (!hash[key]) { + hash[key] = embeddedRecord.id; + hash[key + 'Type'] = modelName; return hash; + }, + + /** + @method _normalizeEmbeddedRelationship + @private + */ + _normalizeEmbeddedRelationship: function(store, relationshipMeta, relationshipHash) { + let modelName = relationshipMeta.type; + if (relationshipMeta.options.polymorphic) { + modelName = relationshipHash.type; + } + let modelClass = store.modelFor(modelName); + let serializer = store.serializerFor(modelName); + + return serializer.normalize(modelClass, relationshipHash, null); } - var embeddedSerializer = store.serializerFor(embeddedTypeClass.modelName); - var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, hash[key], null); - store.push(embeddedTypeClass.modelName, embeddedRecord); +}); - hash[key] = embeddedRecord.id; - //TODO Need to add a reference to the parent later so relationship works between both `belongsTo` records - return hash; +export default EmbeddedRecordsMixin; + +/* + @method _newExtractEmbeddedRecords + @private +*/ +function _newExtractEmbeddedRecords(serializer, store, typeClass, partial) { + typeClass.eachRelationship((key, relationship) => { + if (serializer.hasDeserializeRecordsOption(key)) { + if (relationship.kind === "hasMany") { + this._extractEmbeddedHasMany(store, key, partial, relationship); + } + if (relationship.kind === "belongsTo") { + this._extractEmbeddedBelongsTo(store, key, partial, relationship); + } + } + }, this); + return partial; } -function extractEmbeddedBelongsToPolymorphic(store, key, hash) { - if (!hash[key]) { - return hash; +/* + @method _newExtractEmbeddedHasMany + @private +*/ +function _newExtractEmbeddedHasMany(store, key, hash, relationshipMeta) { + let relationshipHash = get(hash, `data.relationships.${key}.data`); + if (!relationshipHash) { + return; } - var data = hash[key]; - var modelName = data.type; - var embeddedSerializer = store.serializerFor(modelName); - var embeddedTypeClass = store.modelFor(modelName); + let hasMany = relationshipHash.map(item => { + let { data, included } = this._normalizeEmbeddedRelationship(store, relationshipMeta, item); + hash.included = hash.included || []; + hash.included.push(data); + hash.included.push(...included); - var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null); - store.push(embeddedTypeClass.modelName, embeddedRecord); + return { id: data.id, type: data.type }; + }); - hash[key] = embeddedRecord.id; - hash[key + 'Type'] = modelName; - return hash; + let relationship = { data: hasMany }; + set(hash, `data.relationships.${key}`, relationship); } -export default EmbeddedRecordsMixin; +/* + @method _newExtractEmbeddedBelongsTo + @private +*/ +function _newExtractEmbeddedBelongsTo(store, key, hash, relationshipMeta) { + let relationshipHash = get(hash, `data.relationships.${key}.data`); + if (!relationshipHash) { + return; + } + + let { data, included } = this._normalizeEmbeddedRelationship(store, relationshipMeta, relationshipHash); + hash.included = hash.included || []; + hash.included.push(data); + hash.included.push(...included); + + let belongsTo = { id: data.id, type: data.type }; + let relationship = { data: belongsTo }; + + set(hash, `data.relationships.${key}`, relationship); +} diff --git a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-new-test.js b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-new-test.js new file mode 100644 index 00000000000..b1224e40dd3 --- /dev/null +++ b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-new-test.js @@ -0,0 +1,1200 @@ +var HomePlanet, SuperVillain, EvilMinion, SecretLab, SecretWeapon, BatCave, Comment, env; +var run = Ember.run; +var LightSaber; +var TestSerializer; + +module("integration/embedded_records_mixin - EmbeddedRecordsMixin (new API)", { + setup: function() { + SuperVillain = DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + homePlanet: DS.belongsTo("homePlanet", { inverse: 'villains' }), + secretLab: DS.belongsTo("secretLab"), + secretWeapons: DS.hasMany("secretWeapon"), + evilMinions: DS.hasMany("evilMinion") + }); + HomePlanet = DS.Model.extend({ + name: DS.attr('string'), + villains: DS.hasMany('superVillain', { inverse: 'homePlanet' }) + }); + SecretLab = DS.Model.extend({ + minionCapacity: DS.attr('number'), + vicinity: DS.attr('string'), + superVillain: DS.belongsTo('superVillain') + }); + BatCave = SecretLab.extend({ + infiltrated: DS.attr('boolean') + }); + SecretWeapon = DS.Model.extend({ + name: DS.attr('string'), + superVillain: DS.belongsTo('superVillain') + }); + LightSaber = SecretWeapon.extend({ + color: DS.attr('string') + }); + EvilMinion = DS.Model.extend({ + superVillain: DS.belongsTo('superVillain'), + name: DS.attr('string') + }); + Comment = DS.Model.extend({ + body: DS.attr('string'), + root: DS.attr('boolean'), + children: DS.hasMany('comment', { inverse: null }) + }); + TestSerializer = DS.RESTSerializer.extend({ + isNewSerializerAPI: true + }); + env = setupStore({ + superVillain: SuperVillain, + homePlanet: HomePlanet, + secretLab: SecretLab, + batCave: BatCave, + secretWeapon: SecretWeapon, + lightSaber: LightSaber, + evilMinion: EvilMinion, + comment: Comment + }); + env.store.modelFor('superVillain'); + env.store.modelFor('homePlanet'); + env.store.modelFor('secretLab'); + env.store.modelFor('batCave'); + env.store.modelFor('secretWeapon'); + env.store.modelFor('lightSaber'); + env.store.modelFor('evilMinion'); + env.store.modelFor('comment'); + + env.registry.register('serializer:application', TestSerializer.extend(DS.EmbeddedRecordsMixin)); + }, + + teardown: function() { + run(env.store, 'destroy'); + } +}); + +if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { + + test("normalizeSingleResponse with embedded objects", function() { + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:super-villain', TestSerializer.extend()); + env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' } + } + })); + + var serializer = env.container.lookup("serializer:home-planet"); + var json_hash = { + homePlanet: { + id: "1", + name: "Umber", + villains: [{ + id: "2", + firstName: "Tom", + lastName: "Dale" + }] + } + }; + var json; + + run(function() { + json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "villains": { + "data": [ + { "id": "2", "type": "super-villain" } + ] + } + } + }, + "included": [ + { + "id": "2", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": {} + } + ] + }); + }); + + test("normalizeSingleResponse with embedded objects inside embedded objects", function() { + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' } + } + })); + env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + evilMinions: { embedded: 'always' } + } + })); + env.registry.register('serializer:evil-minion', TestSerializer); + + var serializer = env.container.lookup("serializer:home-planet"); + var json_hash = { + homePlanet: { + id: "1", + name: "Umber", + villains: [{ + id: "2", + firstName: "Tom", + lastName: "Dale", + evilMinions: [{ + id: "3", + name: "Alex" + }] + }] + } + }; + var json; + + run(function() { + json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "villains": { + "data": [ + { "id": "2", "type": "super-villain" } + ] + } + } + }, + "included": [{ + "id": "2", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": { + "evilMinions": { + "data": [ + { "id": "3", "type": "evil-minion" } + ] + } + } + }, { + "id": "3", + "type": "evil-minion", + "attributes": { + "name": "Alex" + }, + "relationships": {} + }] + }); + }); + + test("normalizeSingleResponse with embedded objects of same type", function() { + env.registry.register('adapter:comment', DS.RESTAdapter); + env.registry.register('serializer:comment', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + children: { embedded: 'always' } + } + })); + + var serializer = env.container.lookup("serializer:comment"); + var json_hash = { + comment: { + id: "1", + body: "Hello", + root: true, + children: [{ + id: "2", + body: "World", + root: false + }, + { + id: "3", + body: "Foo", + root: false + }] + } + }; + var json; + run(function() { + json = serializer.normalizeSingleResponse(env.store, Comment, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "comment", + "attributes": { + "body": "Hello", + "root": true + }, + "relationships": { + "children": { + "data": [ + { "id": "2", "type": "comment" }, + { "id": "3", "type": "comment" } + ] + } + } + }, + "included": [{ + "id": "2", + "type": "comment", + "attributes": { + "body": "World", + "root": false + }, + "relationships": {} + }, { + "id": "3", + "type": "comment", + "attributes": { + "body": "Foo", + "root": false + }, + "relationships": {} + }] + }, "Primary record was correct"); + }); + + test("normalizeSingleResponse with embedded objects inside embedded objects of same type", function() { + env.registry.register('adapter:comment', DS.RESTAdapter); + env.registry.register('serializer:comment', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + children: { embedded: 'always' } + } + })); + + var serializer = env.container.lookup("serializer:comment"); + var json_hash = { + comment: { + id: "1", + body: "Hello", + root: true, + children: [{ + id: "2", + body: "World", + root: false, + children: [{ + id: "4", + body: "Another", + root: false + }] + }, + { + id: "3", + body: "Foo", + root: false + }] + } + }; + var json; + run(function() { + json = serializer.normalizeSingleResponse(env.store, Comment, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "comment", + "attributes": { + "body": "Hello", + "root": true + }, + "relationships": { + "children": { + "data": [ + { "id": "2", "type": "comment" }, + { "id": "3", "type": "comment" } + ] + } + } + }, + "included": [{ + "id": "2", + "type": "comment", + "attributes": { + "body": "World", + "root": false + }, + "relationships": { + "children": { + "data": [ + { "id": "4", "type": "comment" } + ] + } + } + }, { + "id": "4", + "type": "comment", + "attributes": { + "body": "Another", + "root": false + }, + "relationships": {} + }, { + "id": "3", + "type": "comment", + "attributes": { + "body": "Foo", + "root": false + }, + "relationships": {} + }] + }, "Primary record was correct"); + }); + + test("normalizeSingleResponse with embedded objects of same type, but from separate attributes", function() { + HomePlanet.reopen({ + reformedVillains: DS.hasMany('superVillain', { inverse: null }) + }); + + env.registry.register('adapter:home-planet', DS.RESTAdapter); + env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + reformedVillains: { embedded: 'always' } + } + })); + env.registry.register('serializer:super-villain', TestSerializer); + + var serializer = env.container.lookup("serializer:home-planet"); + var json_hash = { + homePlanet: { + id: "1", + name: "Earth", + villains: [{ + id: "1", + firstName: "Tom" + }, { + id: "3", + firstName: "Yehuda" + }], + reformedVillains: [{ + id: "2", + firstName: "Alex" + },{ + id: "4", + firstName: "Erik" + }] + } + }; + var json; + run(function() { + json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Earth" + }, + "relationships": { + "villains": { + "data": [ + { "id": "1", "type": "super-villain" }, + { "id": "3", "type": "super-villain" } + ] + }, + "reformedVillains": { + "data": [ + { "id": "2", "type": "super-villain" }, + { "id": "4", "type": "super-villain" } + ] + } + } + }, + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom" + }, + "relationships": {} + }, { + "id": "3", + "type": "super-villain", + "attributes": { + "firstName": "Yehuda" + }, + "relationships": {} + }, { + "id": "2", + "type": "super-villain", + "attributes": { + "firstName": "Alex" + }, + "relationships": {} + }, { + "id": "4", + "type": "super-villain", + "attributes": { + "firstName": "Erik" + }, + "relationships": {} + }] + }, "Primary hash was correct"); + }); + + test("normalizeArrayResponse with embedded objects", function() { + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' } + } + })); + env.registry.register('serializer:super-villain', TestSerializer); + + var serializer = env.container.lookup("serializer:home-planet"); + + var json_hash = { + homePlanets: [{ + id: "1", + name: "Umber", + villains: [{ + id: "1", + firstName: "Tom", + lastName: "Dale" + }] + }] + }; + var array; + + run(function() { + array = serializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); + }); + + deepEqual(array, { + "data": [{ + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "villains": { + "data": [ + { "id": "1", "type": "super-villain" } + ] + } + } + }], + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": {} + }] + }); + }); + + test("normalizeArrayResponse with embedded objects with custom primary key", function() { + expect(1); + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:super-villain', TestSerializer.extend({ + primaryKey: 'villain_id' + })); + env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' } + } + })); + + var serializer = env.container.lookup("serializer:home-planet"); + + var json_hash = { + homePlanets: [{ + id: "1", + name: "Umber", + villains: [{ + villain_id: "2", + firstName: "Alex", + lastName: "Baizeau" + }] + }] + }; + var array; + + run(function() { + array = serializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); + }); + + deepEqual(array, { + "data": [{ + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "villains": { + "data": [ + { "id": "2", "type": "super-villain" } + ] + } + } + }], + "included": [{ + "id": "2", + "type": "super-villain", + "attributes": { + "firstName": "Alex", + "lastName": "Baizeau" + }, + "relationships": {} + }] + }); + }); + + test("normalizeArrayResponse with embedded objects with identical relationship and attribute key ", function() { + expect(1); + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' } + }, + //Makes the keyForRelationship and keyForAttribute collide. + keyForRelationship: function(key, type) { + return this.keyForAttribute(key, type); + } + })); + env.registry.register('serializer:super-villain', TestSerializer); + + var serializer = env.container.lookup("serializer:home-planet"); + + var json_hash = { + homePlanets: [{ + id: "1", + name: "Umber", + villains: [{ + id: "1", + firstName: "Alex", + lastName: "Baizeau" + }] + }] + }; + var array; + + run(function() { + array = serializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); + }); + + deepEqual(array, { + "data": [{ + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "villains": { + "data": [ + { "id": "1", "type": "super-villain" } + ] + } + } + }], + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Alex", + "lastName": "Baizeau" + }, + "relationships": {} + }] + }); + }); + test("normalizeArrayResponse with embedded objects of same type as primary type", function() { + env.registry.register('adapter:comment', DS.RESTAdapter); + env.registry.register('serializer:comment', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + children: { embedded: 'always' } + } + })); + + var serializer = env.container.lookup("serializer:comment"); + + var json_hash = { + comments: [{ + id: "1", + body: "Hello", + root: true, + children: [{ + id: "2", + body: "World", + root: false + }, + { + id: "3", + body: "Foo", + root: false + }] + }] + }; + var array; + + run(function() { + array = serializer.normalizeArrayResponse(env.store, Comment, json_hash, null, 'findAll'); + }); + + deepEqual(array, { + "data": [{ + "id": "1", + "type": "comment", + "attributes": { + "body": "Hello", + "root": true + }, + "relationships": { + "children": { + "data": [ + { "id": "2", "type": "comment" }, + { "id": "3", "type": "comment" } + ] + } + } + }], + "included": [{ + "id": "2", + "type": "comment", + "attributes": { + "body": "World", + "root": false + }, + "relationships": {} + }, { + "id": "3", + "type": "comment", + "attributes": { + "body": "Foo", + "root": false + }, + "relationships": {} + }] + }, "Primary array is correct"); + }); + + test("normalizeArrayResponse with embedded objects of same type, but from separate attributes", function() { + HomePlanet.reopen({ + reformedVillains: DS.hasMany('superVillain') + }); + + env.registry.register('adapter:home-planet', DS.RESTAdapter); + env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + reformedVillains: { embedded: 'always' } + } + })); + env.registry.register('serializer:super-villain', TestSerializer); + + var serializer = env.container.lookup("serializer:home-planet"); + var json_hash = { + homePlanets: [{ + id: "1", + name: "Earth", + villains: [{ + id: "1", + firstName: "Tom" + },{ + id: "3", + firstName: "Yehuda" + }], + reformedVillains: [{ + id: "2", + firstName: "Alex" + },{ + id: "4", + firstName: "Erik" + }] + },{ + id: "2", + name: "Mars", + villains: [{ + id: "1", + firstName: "Tom" + },{ + id: "3", + firstName: "Yehuda" + }], + reformedVillains: [{ + id: "5", + firstName: "Peter" + },{ + id: "6", + firstName: "Trek" + }] + }] + }; + + var json; + run(function() { + json = serializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); + }); + + deepEqual(json, { + "data": [{ + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Earth" + }, + "relationships": { + "reformedVillains": { + "data": [ + { "id": "2", "type": "super-villain" }, + { "id": "4", "type": "super-villain" } + ] + }, + "villains": { + "data": [ + { "id": "1", "type": "super-villain" }, + { "id": "3", "type": "super-villain" } + ] + } + } + }, { + "id": "2", + "type": "home-planet", + "attributes": { + "name": "Mars" + }, + "relationships": { + "reformedVillains": { + "data": [ + { "id": "5", "type": "super-villain" }, + { "id": "6", "type": "super-villain" } + ] + }, + "villains": { + "data": [ + { "id": "1", "type": "super-villain" }, + { "id": "3", "type": "super-villain" } + ] + } + } + }], + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom" + }, + "relationships": {} + }, { + "id": "3", + "type": "super-villain", + "attributes": { + "firstName": "Yehuda" + }, + "relationships": {} + }, { + "id": "2", + "type": "super-villain", + "attributes": { + "firstName": "Alex" + }, + "relationships": {} + }, { + "id": "4", + "type": "super-villain", + "attributes": { + "firstName": "Erik" + }, + "relationships": {} + }, { + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom" + }, + "relationships": {} + }, { + "id": "3", + "type": "super-villain", + "attributes": { + "firstName": "Yehuda" + }, + "relationships": {} + }, { + "id": "5", + "type": "super-villain", + "attributes": { + "firstName": "Peter" + }, + "relationships": {} + }, { + "id": "6", + "type": "super-villain", + "attributes": { + "firstName": "Trek" + }, + "relationships": {} + }] + }, "Primary array was correct"); + }); + + test("normalizeSingleResponse with embedded object (belongsTo relationship)", function() { + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' } + } + })); + //env.registry.register('serializer:secret-lab', TestSerializer); + + var serializer = env.container.lookup("serializer:super-villain"); + + var json_hash = { + superVillain: { + id: "1", + firstName: "Tom", + lastName: "Dale", + homePlanet: "123", + evilMinions: ["1", "2", "3"], + secretLab: { + minionCapacity: 5000, + vicinity: "California, USA", + id: "101" + }, + secretWeapons: [] + } + }; + var json; + + run(function() { + json = serializer.normalizeSingleResponse(env.store, SuperVillain, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": { + "evilMinions": { + "data": [ + { "id": "1", "type": "evil-minion" }, + { "id": "2", "type": "evil-minion" }, + { "id": "3", "type": "evil-minion" } + ] + }, + "homePlanet": { + "data": { "id": "123", "type": "home-planet" } + }, + "secretLab": { + "data": { "id": "101", "type": "secret-lab" } + }, + "secretWeapons": { + "data": [] + } + } + }, + "included": [{ + "id": "101", + "type": "secret-lab", + "attributes": { + "minionCapacity": 5000, + "vicinity": "California, USA" + }, + "relationships": {} + }] + }); + }); + + test("normalizeSingleResponse with multiply-nested belongsTo", function() { + env.registry.register('adapter:evil-minion', DS.RESTAdapter); + env.registry.register('serializer:evil-minion', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + superVillain: { embedded: 'always' } + } + })); + env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + homePlanet: { embedded: 'always' } + } + })); + + var serializer = env.container.lookup("serializer:evil-minion"); + var json_hash = { + evilMinion: { + id: "1", + name: "Alex", + superVillain: { + id: "1", + firstName: "Tom", + lastName: "Dale", + evilMinions: ["1"], + homePlanet: { + id: "1", + name: "Umber", + villains: ["1"] + } + } + } + }; + var json; + + run(function() { + json = serializer.normalizeSingleResponse(env.store, EvilMinion, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "evil-minion", + "attributes": { + "name": "Alex" + }, + "relationships": { + "superVillain": { + "data": { "id": "1", "type": "super-villain" } + } + } + }, + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": { + "evilMinions": { + "data": [ + { "id": "1", "type": "evil-minion" } + ] + }, + "homePlanet": { + "data": { "id": "1", "type": "home-planet" } + } + } + }, { + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "villains": { + "data": [ + { "id": "1", "type": "super-villain" } + ] + } + } + }] + }, "Primary hash was correct"); + }); + + test("normalizeSingleResponse with polymorphic hasMany", function() { + SuperVillain.reopen({ + secretWeapons: DS.hasMany("secretWeapon", { polymorphic: true }) + }); + + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretWeapons: { embedded: 'always' } + } + })); + var serializer = env.container.lookup("serializer:super-villain"); + + var json_hash = { + superVillain: { + id: "1", + firstName: "Tom", + lastName: "Dale", + secretWeapons: [ + { + id: "1", + type: "LightSaber", + name: "Tom's LightSaber", + color: "Red" + }, + { + id: "1", + type: "SecretWeapon", + name: "The Death Star" + } + ] + } + }; + var json; + + run(function() { + json = serializer.normalizeSingleResponse(env.store, SuperVillain, json_hash, '1', 'findAll'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": { + "secretWeapons": { + "data": [ + { "id": "1", "type": "light-saber" }, + { "id": "1", "type": "secret-weapon" } + ] + } + } + }, + "included": [{ + "id": "1", + "type": "light-saber", + "attributes": { + "color": "Red", + "name": "Tom's LightSaber" + }, + "relationships": {} + }, { + "id": "1", + "type": "secret-weapon", + "attributes": { + "name": "The Death Star" + }, + "relationships": {} + }] + }, "Primary hash was correct"); + }); + + test("normalizeSingleResponse with polymorphic belongsTo", function() { + SuperVillain.reopen({ + secretLab: DS.belongsTo("secretLab", { polymorphic: true }) + }); + + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' } + } + })); + var serializer = env.container.lookup("serializer:super-villain"); + + var json_hash = { + superVillain: { + id: "1", + firstName: "Tom", + lastName: "Dale", + secretLab: { + id: "1", + type: "bat-cave", + infiltrated: true + } + } + }; + + var json; + + run(function() { + json = serializer.normalizeSingleResponse(env.store, SuperVillain, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": { + "secretLab": { + "data": { "id": "1", "type": "bat-cave" } + } + } + }, + "included": [{ + "id": "1", + "type": "bat-cave", + "attributes": { + "infiltrated": true + }, + "relationships": {} + }] + }, "Primary has was correct"); + }); + + test("normalize with custom belongsTo primary key", function() { + env.registry.register('adapter:evil-minion', DS.RESTAdapter); + env.registry.register('serializer:evil-minion', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + superVillain: { embedded: 'always' } + } + })); + env.registry.register('serializer:super-villain', TestSerializer.extend({ + primaryKey: 'custom' + })); + + var serializer = env.container.lookup("serializer:evil-minion"); + var json_hash = { + evil_minion: { + id: "1", + name: "Alex", + superVillain: { + custom: "1", + firstName: "Tom", + lastName: "Dale" + } + } + }; + var json; + + run(function() { + json = serializer.normalizeResponse(env.store, EvilMinion, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "evil-minion", + "attributes": { + "name": "Alex" + }, + "relationships": { + "superVillain": { + "data": { "id": "1", "type": "super-villain" } + } + } + }, + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": {} + }] + }, "Primary hash was correct"); + }); + +} From b7a19f912f94e638806eaf39c42f3bedd123dbc9 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Sat, 6 Jun 2015 01:00:10 +0300 Subject: [PATCH 0884/2527] Implement extractMeta for new Serializer API --- .../lib/serializers/json-serializer.js | 26 +++++++++- .../lib/serializers/rest-serializer.js | 26 ++++++---- .../serializers/json-serializer-new-test.js | 49 +++++++++---------- .../serializers/rest-serializer-new-test.js | 19 +++++++ 4 files changed, 83 insertions(+), 37 deletions(-) diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index 655fb65af2d..6a205e7e319 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -425,7 +425,11 @@ export default Serializer.extend({ included: [] }; - payload = this.normalizePayload(payload); + let meta = this.extractMeta(store, primaryModelClass, payload); + if (meta) { + Ember.assert('The `meta` returned from `extractMeta` has to be an object, not "' + Ember.typeOf(meta) + '".', Ember.typeOf(meta) === 'object'); + documentHash.meta = meta; + } if (isSingle) { let { data } = this.normalize(primaryModelClass, payload); @@ -1443,6 +1447,10 @@ export default Serializer.extend({ @param {Object} payload */ extractMeta: function(store, typeClass, payload) { + if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) { + return _newExtractMeta.apply(this, arguments); + } + if (payload && payload.meta) { store.setMetadataFor(typeClass, payload.meta); delete payload.meta; @@ -1592,3 +1600,19 @@ function _newNormalize(modelClass, resourceHash) { return { data }; } + +/* + @method _newExtractMeta + @param {DS.Store} store + @param {DS.Model} modelClass + @param {Object} payload + @return {Object} + @private +*/ +function _newExtractMeta(store, modelClass, payload) { + if (payload && payload.hasOwnProperty('meta')) { + let meta = payload.meta; + delete payload.meta; + return meta; + } +} diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index da97a9d4350..70136a19770 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -236,11 +236,17 @@ var RESTSerializer = JSONSerializer.extend({ @private */ _normalizeResponse: function(store, primaryModelClass, payload, id, requestType, isSingle) { - var document = { + let documentHash = { data: null, included: [] }; + let meta = this.extractMeta(store, primaryModelClass, payload); + if (meta) { + Ember.assert('The `meta` returned from `extractMeta` has to be an object, not "' + Ember.typeOf(meta) + '".', Ember.typeOf(meta) === 'object'); + documentHash.meta = meta; + } + Ember.keys(payload).forEach((prop) => { var modelName = prop; var forcedSecondary = false; @@ -296,14 +302,14 @@ var RESTSerializer = JSONSerializer.extend({ */ if (isPrimary && Ember.typeOf(value) !== 'array') { let { data, included } = this.normalize(primaryModelClass, value, prop); - document.data = data; - document.included.push(...included); + documentHash.data = data; + documentHash.included.push(...included); return; } let { data, included } = this.normalizeArray(store, typeName, value, prop); - document.included.push(...included); + documentHash.included.push(...included); if (isSingle) { /*jshint loopfunc:true*/ @@ -319,24 +325,24 @@ var RESTSerializer = JSONSerializer.extend({ in the array */ var isUpdatedRecord = isPrimary && coerceId(resource.id) === id; - var isFirstCreatedRecord = isPrimary && !id && !document.data; + var isFirstCreatedRecord = isPrimary && !id && !documentHash.data; if (isFirstCreatedRecord || isUpdatedRecord) { - document.data = resource; + documentHash.data = resource; } else { - document.included.push(resource); + documentHash.included.push(resource); } }); } else { if (isPrimary) { - document.data = data; + documentHash.data = data; } else { - document.included.push(...data); + documentHash.included.push(...data); } } }); - return document; + return documentHash; }, /** diff --git a/packages/ember-data/tests/integration/serializers/json-serializer-new-test.js b/packages/ember-data/tests/integration/serializers/json-serializer-new-test.js index 0e0b2caa58f..23411fbd046 100644 --- a/packages/ember-data/tests/integration/serializers/json-serializer-new-test.js +++ b/packages/ember-data/tests/integration/serializers/json-serializer-new-test.js @@ -76,6 +76,29 @@ if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }, { id: "2", type: "comment" }]); }); + test('normalizeSingleResponse should extract meta using extractMeta', function() { + env.registry.register("serializer:post", TestSerializer.extend({ + extractMeta: function(store, modelClass, payload) { + let meta = this._super(...arguments); + meta.authors.push('Tomhuda'); + return meta; + } + })); + + var jsonHash = { + id: "1", + title_payload_key: "Rails is omakase", + my_comments: [1, 2], + meta: { + authors: ['Tomster'] + } + }; + + var post = env.container.lookup("serializer:post").normalizeSingleResponse(env.store, Post, jsonHash, '1', 'find'); + + deepEqual(post.meta.authors, ['Tomster', 'Tomhuda']); + }); + test("Serializer should respect the primaryKey attribute when extracting records", function() { env.registry.register('serializer:post', TestSerializer.extend({ primaryKey: '_ID_' @@ -120,32 +143,6 @@ if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }]); }); - test("normalizePayload is called during normalizeSingleResponse", function() { - var counter = 0; - - env.registry.register('serializer:post', TestSerializer.extend({ - normalizePayload: function(payload) { - counter++; - return payload.response; - } - })); - - var jsonHash = { - response: { - id: 1, - title: "Rails is omakase" - } - }; - - run(function() { - post = env.container.lookup("serializer:post").normalizeSingleResponse(env.store, Post, jsonHash, '1', 'find'); - }); - - equal(counter, 1); - equal(post.data.id, "1"); - equal(post.data.attributes.title, "Rails is omakase"); - }); - test("Calling normalize should normalize the payload (only the passed keys)", function () { expect(1); var Person = DS.Model.extend({ diff --git a/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js b/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js index ca85ab4c304..866322b4c25 100644 --- a/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js +++ b/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js @@ -105,6 +105,25 @@ if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { }); }); + test('normalizeArrayResponse should extract meta using extractMeta', function() { + env.registry.register("serializer:home-planet", TestSerializer.extend({ + extractMeta: function(store, modelClass, payload) { + let meta = this._super(...arguments); + meta.authors.push('Tomhuda'); + return meta; + } + })); + + var jsonHash = { + meta: { authors: ['Tomster'] }, + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] + }; + + var json = env.container.lookup("serializer:home-planet").normalizeArrayResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); + + deepEqual(json.meta.authors, ['Tomster', 'Tomhuda']); + }); + test("normalizeArrayResponse warning with custom modelNameFromPayloadKey", function() { var homePlanets; env.restNewSerializer.modelNameFromPayloadKey = function(root) { From 4e45a8a82a38169f63a0b91749d504c06467f72e Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Sat, 14 Mar 2015 13:10:05 +0100 Subject: [PATCH 0885/2527] Move cloneNull to a separate module --- packages/ember-data/lib/system/clone-null.js | 7 +++++++ .../record-arrays/adapter-populated-record-array.js | 10 ++-------- 2 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 packages/ember-data/lib/system/clone-null.js diff --git a/packages/ember-data/lib/system/clone-null.js b/packages/ember-data/lib/system/clone-null.js new file mode 100644 index 00000000000..bf73dc73633 --- /dev/null +++ b/packages/ember-data/lib/system/clone-null.js @@ -0,0 +1,7 @@ +export default function cloneNull(source) { + var clone = Ember.create(null); + for (var key in source) { + clone[key] = source[key]; + } + return clone; +} diff --git a/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js b/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js index d0a93c80207..6e0ddb4b172 100644 --- a/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js +++ b/packages/ember-data/lib/system/record-arrays/adapter-populated-record-array.js @@ -1,18 +1,12 @@ import RecordArray from "ember-data/system/record-arrays/record-array"; +import cloneNull from "ember-data/system/clone-null"; + /** @module ember-data */ var get = Ember.get; -function cloneNull(source) { - var clone = Ember.create(null); - for (var key in source) { - clone[key] = source[key]; - } - return clone; -} - /** Represents an ordered list of records whose order and membership is determined by the adapter. For example, a query sent to the adapter From 3eb4c293904dc0966784eaed3680760876c220de Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Sat, 14 Mar 2015 13:11:12 +0100 Subject: [PATCH 0886/2527] Implement ManyArray.meta --- packages/ember-data/lib/system/many-array.js | 40 +++++++++++++++++++ .../system/relationships/state/has-many.js | 4 ++ .../relationships/has-many-test.js | 28 +++++++++++++ 3 files changed, 72 insertions(+) diff --git a/packages/ember-data/lib/system/many-array.js b/packages/ember-data/lib/system/many-array.js index 9ebd8a7503c..f4f10778f3d 100644 --- a/packages/ember-data/lib/system/many-array.js +++ b/packages/ember-data/lib/system/many-array.js @@ -115,6 +115,46 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { */ relationship: null, + /** + Metadata associated with the request for async hasMany relationships. + + Example + + Given that the server returns the following JSON payload when fetching a + hasMany relationship: + + ```js + { + "comments": [{ + "id": 1, + "comment": "This is the first comment", + }, { + // ... + }], + + "meta": { + "page": 1, + "total": 5 + } + } + ``` + + You can then access the metadata via the `meta` property: + + ```js + post.get('comments').then(function(comments) { + var meta = comments.get('meta'); + + // meta.page => 1 + // meta.total => 5 + }); + ``` + + @property {Object} meta + @public + */ + meta: null, + internalReplace: function(idx, amt, objects) { if (!objects) { objects = []; diff --git a/packages/ember-data/lib/system/relationships/state/has-many.js b/packages/ember-data/lib/system/relationships/state/has-many.js index 4e9e03f95ad..1767f8665a9 100644 --- a/packages/ember-data/lib/system/relationships/state/has-many.js +++ b/packages/ember-data/lib/system/relationships/state/has-many.js @@ -2,6 +2,7 @@ import { PromiseManyArray } from "ember-data/system/promise-proxies"; import Relationship from "ember-data/system/relationships/state/relationship"; import OrderedSet from "ember-data/system/ordered-set"; import ManyArray from "ember-data/system/many-array"; +import cloneNull from "ember-data/system/clone-null"; var map = Ember.EnumerableUtils.map; @@ -146,6 +147,9 @@ ManyRelationship.prototype.computeChanges = function(records) { ManyRelationship.prototype.fetchLink = function() { var self = this; return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function(records) { + var meta = self.store.metadataFor(self.relationshipMeta.type); + self.manyArray.set('meta', cloneNull(meta)); + self.store._backburner.join(function() { self.updateRecordsFromAdapter(records); }); diff --git a/packages/ember-data/tests/integration/relationships/has-many-test.js b/packages/ember-data/tests/integration/relationships/has-many-test.js index 67bb165c30a..1ec8960bb54 100644 --- a/packages/ember-data/tests/integration/relationships/has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/has-many-test.js @@ -1443,5 +1443,33 @@ test("Model's belongsTo relationship should be created during 'get' method", fun user = env.store.createRecord('user'); user.get('messages'); ok(user._internalModel._relationships.has('messages'), "Newly created record with relationships in params passed in its constructor should have relationships"); +}); + +test("metadata is accessible", function() { + expect(1); + + env.adapter.findHasMany = function() { + return resolve({ + meta: { + foo: 'bar' + }, + chapters: [ + { id: '2' }, + { id: '3' } + ] + }); + }; + + var book; + + run(function() { + book = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', links: { chapters: '/chapters' } }); + }); + + run(function() { + book.get('chapters').then(function(chapters) { + var meta = chapters.get('meta'); + equal(get(meta, 'foo'), 'bar', 'metadata is available'); + }); }); }); From 12f0cb183092e6a74238d70cce0e29ea592b1215 Mon Sep 17 00:00:00 2001 From: IgorT Date: Sat, 6 Jun 2015 05:45:44 +0300 Subject: [PATCH 0887/2527] Add meta for hasMany relationships Rebased #2878 and added a test from #2996 Added metadata support behind a feature flag, for hasMany relationships. For now, until we refactor the internals, the store internally pushes hasMany metadata around in the `meta` key next to `links` and `data`. This might lead to overriding meta attribtues with meta relationships, but will be solved by the upcoming change of the internals to JSONAPI format --- .../system/relationships/state/has-many.js | 22 ++-- .../relationships/state/relationship.js | 5 + packages/ember-data/lib/system/store.js | 5 + .../ember-data/lib/system/store/finders.js | 6 +- .../relationships/has-many-test.js | 107 ++++++++++++++---- 5 files changed, 115 insertions(+), 30 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/state/has-many.js b/packages/ember-data/lib/system/relationships/state/has-many.js index 1767f8665a9..3f98b3ed502 100644 --- a/packages/ember-data/lib/system/relationships/state/has-many.js +++ b/packages/ember-data/lib/system/relationships/state/has-many.js @@ -2,7 +2,6 @@ import { PromiseManyArray } from "ember-data/system/promise-proxies"; import Relationship from "ember-data/system/relationships/state/relationship"; import OrderedSet from "ember-data/system/ordered-set"; import ManyArray from "ember-data/system/many-array"; -import cloneNull from "ember-data/system/clone-null"; var map = Ember.EnumerableUtils.map; @@ -29,6 +28,12 @@ ManyRelationship.prototype.destroy = function() { this.manyArray.destroy(); }; +ManyRelationship.prototype._super$updateMeta = Relationship.prototype.updateMeta; +ManyRelationship.prototype.updateMeta = function(meta) { + this._super$updateMeta(meta); + this.manyArray.set('meta', meta); +}; + ManyRelationship.prototype._super$addCanonicalRecord = Relationship.prototype.addCanonicalRecord; ManyRelationship.prototype.addCanonicalRecord = function(record, idx) { if (this.canonicalMembers.has(record)) { @@ -145,15 +150,14 @@ ManyRelationship.prototype.computeChanges = function(records) { }; ManyRelationship.prototype.fetchLink = function() { - var self = this; - return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function(records) { - var meta = self.store.metadataFor(self.relationshipMeta.type); - self.manyArray.set('meta', cloneNull(meta)); - - self.store._backburner.join(function() { - self.updateRecordsFromAdapter(records); + return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then((records) => { + if (records.hasOwnProperty('meta')) { + this.updateMeta(records.meta); + } + this.store._backburner.join(() => { + this.updateRecordsFromAdapter(records); }); - return self.manyArray; + return this.manyArray; }); }; diff --git a/packages/ember-data/lib/system/relationships/state/relationship.js b/packages/ember-data/lib/system/relationships/state/relationship.js index adc2889bd4f..a7cdc146047 100644 --- a/packages/ember-data/lib/system/relationships/state/relationship.js +++ b/packages/ember-data/lib/system/relationships/state/relationship.js @@ -15,6 +15,7 @@ function Relationship(store, record, inverseKey, relationshipMeta) { //multiple possible modelNames this.inverseKeyForImplicit = this.record.constructor.modelName + this.key; this.linkPromise = null; + this.meta = null; this.hasData = false; } @@ -23,6 +24,10 @@ Relationship.prototype = { destroy: Ember.K, + updateMeta: function(meta) { + this.meta = meta; + }, + clear: function() { var members = this.members.list; var member; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 2159b60e1e7..ac52efc9323 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -2139,6 +2139,11 @@ function setupRelationships(store, record, data) { relationship.updateLink(data.links[key]); } + if (data.meta && data.meta.hasOwnProperty(key)) { + relationship = record._relationships.get(key); + relationship.updateMeta(data.meta[key]); + } + if (value !== undefined) { if (kind === 'belongsTo') { relationship = record._relationships.get(key); diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index 5f96c371810..c69a8dcba42 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -83,7 +83,11 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findHasMany'); //TODO Use a non record creating push var records = pushPayload(store, payload); - return map(records, function(record) { return record._internalModel; }); + var recordArray = map(records, function(record) { return record._internalModel; }); + if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && serializer.get('isNewSerializerAPI')) { + recordArray.meta = payload.meta; + } + return recordArray; }); }, null, "DS: Extract payload of " + internalModel + " : hasMany " + relationship.type); } diff --git a/packages/ember-data/tests/integration/relationships/has-many-test.js b/packages/ember-data/tests/integration/relationships/has-many-test.js index 1ec8960bb54..f9cf9b97c70 100644 --- a/packages/ember-data/tests/integration/relationships/has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/has-many-test.js @@ -1443,33 +1443,100 @@ test("Model's belongsTo relationship should be created during 'get' method", fun user = env.store.createRecord('user'); user.get('messages'); ok(user._internalModel._relationships.has('messages'), "Newly created record with relationships in params passed in its constructor should have relationships"); + }); }); -test("metadata is accessible", function() { - expect(1); +if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { - env.adapter.findHasMany = function() { - return resolve({ - meta: { - foo: 'bar' - }, - chapters: [ - { id: '2' }, - { id: '3' } - ] + test("metadata is accessible when pushed as a meta property for a relationship", function() { + expect(1); + var book; + env.adapter.findHasMany = function() { + return resolve({}); + }; + + run(function() { + book = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', meta: { chapters: 'the lefkada sea' }, links: { chapters: '/chapters' } }); }); - }; - var book; + run(function() { + equal(book._internalModel._relationships.get('chapters').meta, 'the lefkada sea', 'meta is there'); + }); + }); - run(function() { - book = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', links: { chapters: '/chapters' } }); + test("metadata is accessible when return from a fetchLink", function() { + expect(1); + env.registry.register('serializer:application', DS.RESTSerializer.extend({ isNewSerializerAPI: true })); + + env.adapter.findHasMany = function() { + return resolve({ + meta: { + foo: 'bar' + }, + chapters: [ + { id: '2' }, + { id: '3' } + ] + }); + }; + + var book; + + run(function() { + book = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', links: { chapters: '/chapters' } }); + }); + + run(function() { + book.get('chapters').then(function(chapters) { + var meta = chapters.get('meta'); + equal(get(meta, 'foo'), 'bar', 'metadata is available'); + }); + }); }); - run(function() { - book.get('chapters').then(function(chapters) { - var meta = chapters.get('meta'); - equal(get(meta, 'foo'), 'bar', 'metadata is available'); + test("metadata should be reset between requests", function() { + var counter = 0; + env.registry.register('serializer:application', DS.RESTSerializer.extend({ isNewSerializerAPI: true })); + + env.adapter.findHasMany = function() { + var data = { + meta: { + foo: 'bar' + }, + chapters: [ + { id: '2' }, + { id: '3' } + ] + }; + + ok(true, 'findHasMany should be called twice'); + + if (counter === 1) { + delete data.meta; + } + + counter++; + + return resolve(data); + }; + + var book1, book2; + + run(function() { + book1 = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', links: { chapters: 'chapters' } }); + book2 = env.store.push('book', { id: 2, title: 'Another book title', links: { chapters: 'chapters' } }); + }); + + run(function() { + book1.get('chapters').then(function(chapters) { + var meta = chapters.get('meta'); + equal(get(meta, 'foo'), 'bar', 'metadata should available'); + + book2.get('chapters').then(function(chapters) { + var meta = chapters.get('meta'); + equal(meta, undefined, 'metadata should not be available'); + }); + }); }); }); -}); +} From b9044fd978c2ff4fc6e6acda1800c57e59351454 Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 2 Jun 2015 23:31:58 +0200 Subject: [PATCH 0888/2527] `store.all()` is not treated as a FilteredRecordArray This refactors the handling of the record array returned by `store.all()`. Previously it has been treated as a FilteredRecordArray without a filter function which resulted in awkward code paths. Now there is a list of liveRecordArrays which contains the RecordArrays which hold all records for a type. --- .../lib/system/record-array-manager.js | 97 +++++++++++++------ .../lib/system/record-arrays/record-array.js | 2 +- packages/ember-data/lib/system/store.js | 18 +--- .../integration/record-array-manager-test.js | 38 +++++--- 4 files changed, 98 insertions(+), 57 deletions(-) diff --git a/packages/ember-data/lib/system/record-array-manager.js b/packages/ember-data/lib/system/record-array-manager.js index 897838645a2..5243bc92e4f 100644 --- a/packages/ember-data/lib/system/record-array-manager.js +++ b/packages/ember-data/lib/system/record-array-manager.js @@ -27,6 +27,12 @@ export default Ember.Object.extend({ defaultValue: function() { return []; } }); + this.liveRecordArrays = MapWithDefault.create({ + defaultValue: (typeClass) => { + return this.createRecordArray(typeClass); + } + }); + this.changedRecords = []; this._adapterPopulatedRecordArrays = []; }, @@ -77,7 +83,6 @@ export default Ember.Object.extend({ }, - //Don't need to update non filtered arrays on simple changes _recordWasChanged: function (record) { var typeClass = record.type; var recordArrays = this.filteredRecordArrays.get(typeClass); @@ -85,9 +90,7 @@ export default Ember.Object.extend({ forEach(recordArrays, function(array) { filter = get(array, 'filterFunction'); - if (filter) { - this.updateRecordArray(array, filter, typeClass, record); - } + this.updateFilterRecordArray(array, filter, typeClass, record); }, this); }, @@ -99,37 +102,54 @@ export default Ember.Object.extend({ forEach(recordArrays, function(array) { filter = get(array, 'filterFunction'); - this.updateRecordArray(array, filter, typeClass, record); + this.updateFilterRecordArray(array, filter, typeClass, record); }, this); + + if (this.liveRecordArrays.has(typeClass)) { + var liveRecordArray = this.liveRecordArrays.get(typeClass); + this._addRecordToRecordArray(liveRecordArray, record); + } }, /** Update an individual filter. - @method updateRecordArray + @method updateFilterRecordArray @param {DS.FilteredRecordArray} array @param {Function} filter @param {DS.Model} typeClass @param {InternalModel} record */ - updateRecordArray: function(array, filter, typeClass, record) { - var shouldBeInArray; + updateFilterRecordArray: function(array, filter, typeClass, record) { + var shouldBeInArray = filter(record.getRecord()); + var recordArrays = this.recordArraysForRecord(record); - if (!filter) { - shouldBeInArray = true; + if (shouldBeInArray) { + this._addRecordToRecordArray(array, record); } else { - shouldBeInArray = filter(record.getRecord()); + recordArrays.delete(array); + array.removeInternalModel(record); } + }, + _addRecordToRecordArray: function(array, record) { var recordArrays = this.recordArraysForRecord(record); + if (!recordArrays.has(array)) { + array.addInternalModel(record); + recordArrays.add(array); + } + }, - if (shouldBeInArray) { - if (!recordArrays.has(array)) { - array.addInternalModel(record); - recordArrays.add(array); + populateLiveRecordArray: function(array, modelName) { + var typeMap = this.store.typeMapFor(modelName); + var records = typeMap.records; + var record; + + for (var i = 0, l = records.length; i < l; i++) { + record = records[i]; + + if (!record.isDeleted() && !record.isEmpty()) { + this._addRecordToRecordArray(array, record); } - } else if (!shouldBeInArray) { - recordArrays.delete(array); - array.removeInternalModel(record); } }, @@ -154,13 +174,25 @@ export default Ember.Object.extend({ record = records[i]; if (!record.isDeleted() && !record.isEmpty()) { - this.updateRecordArray(array, filter, modelName, record); + this.updateFilterRecordArray(array, filter, modelName, record); } } }, /** - Create a `DS.RecordArray` for a type and register it for updates. + Get the `DS.RecordArray` for a type, which contains all loaded records of + given type. + + @method liveRecordArrayFor + @param {Class} typeClass + @return {DS.RecordArray} + */ + liveRecordArrayFor: function(typeClass) { + return this.liveRecordArrays.get(typeClass); + }, + + /** + Create a `DS.RecordArray` for a type. @method createRecordArray @param {Class} typeClass @@ -175,8 +207,6 @@ export default Ember.Object.extend({ manager: this }); - this.registerFilteredRecordArray(array, typeClass); - return array; }, @@ -245,16 +275,28 @@ export default Ember.Object.extend({ }, /** - Unregister a FilteredRecordArray. + Unregister a RecordArray. So manager will not update this array. - @method unregisterFilteredRecordArray + @method unregisterRecordArray @param {DS.RecordArray} array */ - unregisterFilteredRecordArray: function(array) { - var recordArrays = this.filteredRecordArrays.get(array.type); + unregisterRecordArray: function(array) { + var typeClass = array.type; + + // unregister filtered record array + var recordArrays = this.filteredRecordArrays.get(typeClass); var index = indexOf(recordArrays, array); - recordArrays.splice(index, 1); + if (index !== -1) { + recordArrays.splice(index, 1); + + // unregister live record array + } else if (this.liveRecordArrays.has(typeClass)) { + var liveRecordArrayForType = this.liveRecordArrayFor(typeClass); + if (array === liveRecordArrayForType) { + this.liveRecordArrays.remove(typeClass); + } + } }, willDestroy: function() { @@ -263,6 +305,7 @@ export default Ember.Object.extend({ this.filteredRecordArrays.forEach(function(value) { forEach(flatten(value), destroy); }); + forEach(this.liveRecordArrays, destroy); forEach(this._adapterPopulatedRecordArrays, destroy); } }); diff --git a/packages/ember-data/lib/system/record-arrays/record-array.js b/packages/ember-data/lib/system/record-arrays/record-array.js index 2a4a4267918..1ffbdde67e5 100644 --- a/packages/ember-data/lib/system/record-arrays/record-array.js +++ b/packages/ember-data/lib/system/record-arrays/record-array.js @@ -190,7 +190,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { */ _unregisterFromManager: function() { var manager = get(this, 'manager'); - manager.unregisterFilteredRecordArray(this); + manager.unregisterRecordArray(this); }, willDestroy: function() { diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 2159b60e1e7..c4d09d51daa 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1031,8 +1031,8 @@ Store = Service.extend({ @private */ didUpdateAll: function(typeClass) { - var findAllCache = this.typeMapFor(typeClass).findAllCache; - set(findAllCache, 'isUpdating', false); + var liveRecordArray = this.recordArrayManager.liveRecordArrayFor(typeClass); + set(liveRecordArray, 'isUpdating', false); }, /** @@ -1061,18 +1061,11 @@ Store = Service.extend({ all: function(modelName) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); - var typeMap = this.typeMapFor(typeClass); - var findAllCache = typeMap.findAllCache; - if (findAllCache) { - this.recordArrayManager.updateFilter(findAllCache, typeClass); - return findAllCache; - } - - var array = this.recordArrayManager.createRecordArray(typeClass); + var liveRecordArray = this.recordArrayManager.liveRecordArrayFor(typeClass); + this.recordArrayManager.populateLiveRecordArray(liveRecordArray, typeClass); - typeMap.findAllCache = array; - return array; + return liveRecordArray; }, /** @@ -1109,7 +1102,6 @@ Store = Service.extend({ record.destroy(); // maybe within unloadRecord } - typeMap.findAllCache = null; typeMap.metadata = Ember.create(null); } diff --git a/packages/ember-data/tests/integration/record-array-manager-test.js b/packages/ember-data/tests/integration/record-array-manager-test.js index f059fff3787..66d6d80f619 100644 --- a/packages/ember-data/tests/integration/record-array-manager-test.js +++ b/packages/ember-data/tests/integration/record-array-manager-test.js @@ -18,7 +18,7 @@ Car.toString = function() { return "Car"; }; var manager; -module("integration/record_array_manager- destroy", { +module("integration/record_array_manager", { setup: function() { env = setupStore({ adapter: DS.RESTAdapter.extend() @@ -72,40 +72,44 @@ test("destroying the store correctly cleans everything up", function() { var filterd = manager.createFilteredRecordArray(Person, function() { return true; }); var filterd2 = manager.createFilteredRecordArray(Person, function() { return true; }); + var all = store.all('person'); var adapterPopulated = manager.createAdapterPopulatedRecordArray(Person, query); var filterdSummary = tap(filterd, 'willDestroy'); var filterd2Summary = tap(filterd2, 'willDestroy'); - + var allSummary = tap(all, 'willDestroy'); var adapterPopulatedSummary = tap(adapterPopulated, 'willDestroy'); equal(filterdSummary.called.length, 0); - equal(adapterPopulatedSummary.called.length, 0); - equal(filterd2Summary.called.length, 0); + equal(allSummary.called.length, 0); + equal(adapterPopulatedSummary.called.length, 0); - equal(person._internalModel._recordArrays.list.length, 2, 'expected the person to be a member of 2 recordArrays'); + equal(person._internalModel._recordArrays.list.length, 3, 'expected the person to be a member of 3 recordArrays'); Ember.run(filterd2, filterd2.destroy); + equal(person._internalModel._recordArrays.list.length, 2, 'expected the person to be a member of 2 recordArrays'); + equal(filterd2Summary.called.length, 1); + equal(manager.liveRecordArrays.has(all.type), true); + Ember.run(all, all.destroy); equal(person._internalModel._recordArrays.list.length, 1, 'expected the person to be a member of 1 recordArrays'); - - equal(filterd2Summary.called.length, 1); + equal(allSummary.called.length, 1); + equal(manager.liveRecordArrays.has(all.type), false); Ember.run(manager, manager.destroy); - equal(person._internalModel._recordArrays.list.length, 0, 'expected the person to be a member of no recordArrays'); - - equal(filterd2Summary.called.length, 1); - equal(filterdSummary.called.length, 1); + equal(filterd2Summary.called.length, 1); + equal(allSummary.called.length, 1); equal(adapterPopulatedSummary.called.length, 1); }); - -test("Should not filter a stor.all() array when a record property is changed", function() { +test("Should not filter a store.all() array when a record property is changed", function() { var car; - var filterdSummary = tap(store.recordArrayManager, 'updateRecordArray'); + + var populateLiveRecordArray = tap(store.recordArrayManager, 'populateLiveRecordArray'); + var updateFilterRecordArray = tap(store.recordArrayManager, 'updateFilterRecordArray'); store.all('car'); @@ -118,12 +122,14 @@ test("Should not filter a stor.all() array when a record property is changed", f }); }); - equal(filterdSummary.called.length, 1); + equal(populateLiveRecordArray.called.length, 1); + equal(updateFilterRecordArray.called.length, 0); run(function() { car.set('model', 'Mini'); }); - equal(filterdSummary.called.length, 1); + equal(populateLiveRecordArray.called.length, 1); + equal(updateFilterRecordArray.called.length, 0); }); From 570a948441b7b6b5f4b088cfd41decfc27802e89 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 6 Jun 2015 14:44:43 -0500 Subject: [PATCH 0889/2527] run optional feature tests on TravisCI --- .travis.yml | 1 + config/testem-optional-features.json | 14 ++++++++++++++ package.json | 3 ++- 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 config/testem-optional-features.json diff --git a/.travis.yml b/.travis.yml index 8c8284b9de3..dc1d375ff33 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,7 @@ script: - npm run-script test - npm run-script test:beta - npm run-script test:canary + - npm run-script test:optional-features after_success: - npm run-script publish-build:prebuilt - "./bin/bower-ember-data-build" diff --git a/config/testem-optional-features.json b/config/testem-optional-features.json new file mode 100644 index 00000000000..ee0c0b90e2b --- /dev/null +++ b/config/testem-optional-features.json @@ -0,0 +1,14 @@ +{ + "test_page": "dist/index.html?nojshint=true&enableoptionalfeatures=true", + "serve_files": [ + "dist/**/*.js", + "tests/**/*" + ], + "launch_in_ci": [ + "PhantomJS" + ], + "routes": { + "/ember-data.js": "dist/ember-data.js", + "/tests/ember-data-tests.js": "dist/ember-data-tests.js" + } +} diff --git a/package.json b/package.json index 0c6eed0686c..d7fd1e3ced4 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "test:local": "testem -R dot ci", "test:beta": "testem -f config/testem-beta.json -R dot ci", "test:canary": "testem -f config/testem-canary.json -R dot ci", - "test:stable": "testem -f config/testem-stable.json -R dot ci" + "test:stable": "testem -f config/testem-stable.json -R dot ci", + "test:optional-features": "testem -f config/testem-optional-features.json -R dot ci" }, "devDependencies": { "aws-sdk": "~2.0.0-rc8", From a669aa383ab3c0ffcde7d6a5c1748649f6a44c3e Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Sat, 6 Jun 2015 16:37:54 -0400 Subject: [PATCH 0890/2527] Add findByRecord and deprecate findById --- packages/ember-data/lib/system/store.js | 21 ++++++++++++++++--- .../tests/integration/store-test.js | 18 ++++++++++++++++ .../tests/unit/store/adapter-interop-test.js | 2 +- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 2159b60e1e7..c497dd9ae33 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -534,7 +534,7 @@ Store = Service.extend({ return this.findQuery(modelName, id); } - return this.findById(modelName, coerceId(id), preload); + return this.findByRecord(modelName, coerceId(id), preload); }, /** @@ -614,6 +614,21 @@ Store = Service.extend({ @return {Promise} promise */ findById: function(modelName, id, preload) { + Ember.deprecate('Using store.findById() has been deprecated. Use store.findByRecord() to return a record for a given type and id combination.'); + return this.findByRecord(modelName, id, preload); + }, + + /** + This method returns a record for a given type and id combination. + + @method findByRecord + @private + @param {String} modelName + @param {(String|Integer)} id + @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models + @return {Promise} promise + */ + findByRecord: function(modelName, id, preload) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var internalModel = this._internalModelForId(modelName, id); @@ -651,12 +666,12 @@ Store = Service.extend({ var store = this; return promiseArray(Ember.RSVP.all(map(ids, function(id) { - return store.findById(modelName, id); + return store.findByRecord(modelName, id); })).then(Ember.A, null, "DS: Store#findByIds of " + modelName + " complete")); }, /** - This method is called by `findById` if it discovers that a particular + This method is called by `findByRecord` if it discovers that a particular type/id pair hasn't been loaded yet to kick off a request to the adapter. diff --git a/packages/ember-data/tests/integration/store-test.js b/packages/ember-data/tests/integration/store-test.js index 7bc52661dd0..74ef12dcb0d 100644 --- a/packages/ember-data/tests/integration/store-test.js +++ b/packages/ember-data/tests/integration/store-test.js @@ -179,6 +179,24 @@ test("destroying the store correctly cleans everything up", function() { equal(filterdPeopleWillDestroy.called.length, 1, 'expected filterdPeople.willDestroy to have been called once'); }); +module("integration/store - findById() [deprecated]", { + setup: function() { + initializeStore(DS.RESTAdapter.extend()); + } +}); + +test("store.findById() is deprecated", function() { + expectDeprecation( + function() { + run(function() { + store.push('person', { id: 1, name: "Tomster" }); + store.findById('person', 1); + }); + }, + 'Using store.findById() has been deprecated. Use store.findByRecord() to return a record for a given type and id combination.' + ); +}); + module("integration/store - fetch", { setup: function() { initializeStore(DS.RESTAdapter.extend()); diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index 1b1a803c6b7..7ef9c372b5f 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -60,7 +60,7 @@ test("Calling Store#find invokes its adapter#find", function() { }); }); -test("Calling Store#findById multiple times coalesces the calls into a adapter#findMany call", function() { +test("Calling Store#findByRecord multiple times coalesces the calls into a adapter#findMany call", function() { expect(2); var adapter = TestAdapter.extend({ From 1a57000301e03e618f70812dda3d67934f2acc8c Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Sat, 6 Jun 2015 18:07:04 -0400 Subject: [PATCH 0891/2527] Deprecate store.find(type) in favor of store.findAll(type) --- README.md | 2 +- TRANSITION.md | 18 +++++++++--------- packages/ember-data/lib/system/adapter.js | 4 +--- packages/ember-data/lib/system/store.js | 6 +++--- .../integration/adapter/find-all-test.js | 8 ++++---- .../tests/integration/adapter/find-test.js | 19 +++++++++++++++++-- 6 files changed, 35 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index ca2c00fae90..1854cf27007 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Server](http://emberjs.com/guides/models/connecting-to-an-http-server/). From your route or controller: ```js -this.store.find('blogPost'); +this.store.findAll('blogPost'); ``` This returns a promise that resolves to the collection of records. diff --git a/TRANSITION.md b/TRANSITION.md index b088a762659..77320bc870f 100644 --- a/TRANSITION.md +++ b/TRANSITION.md @@ -28,7 +28,7 @@ Ember Data 1.0.beta.1: ```js App.PostsRoute = Ember.Route.extend({ model: function() { - return this.store.find('post'); + return this.store.findAll('post'); } }); @@ -180,7 +180,7 @@ App.NewPostRoute = Ember.Route.extend({ }); ``` -You also no longer need transactions to save relationships independently +You also no longer need transactions to save relationships independently of the model it belongs to, e.g. comments of a post. Ember Data 0.13: @@ -295,7 +295,7 @@ function retry(promise, retryCallback, nTimes) { }); } -// try to save the person up to 5 times +// try to save the person up to 5 times retry(person.save(), function() { return person.save(); }, 5); @@ -305,7 +305,7 @@ Because all async operations in Ember Data 1.0.beta.1 are promises, you can combine them together using normal promise primitives. ```js -this.store.find('person').then(function(people) { +this.store.findAll('person').then(function(people) { people.forEach(function(person) { person.set('isPaidUp', true); }); @@ -533,7 +533,7 @@ App.PostSerializer = DS.RESTSerializer.extend({ }); post.comments = commentIds; - + var post_payload = { post: post, comments: comments }; return this._super(store, type, post_payload, id); @@ -559,7 +559,7 @@ App.PostSerializer = DS.RESTSerializer.extend({ // below in `normalizeHash` var comments = payload._embedded.comments; post.comments = comments.mapBy('ID_'); - + var post_payload = { post: post, comments: comments }; return this._super(store, type, post_payload, id); @@ -620,7 +620,7 @@ App.PostSerializer = DS.RESTSerializer.extend({ // normalize the underscored properties for (var prop in hash) { - json[prop.camelize()] = hash[prop]; + json[prop.camelize()] = hash[prop]; } // delegate to any type-specific normalizations @@ -648,14 +648,14 @@ In 0.13, the REST Adapter automatically camelized incoming keys for you. It also expected `belongsTo` relationships to be listed under `name_id` and `hasMany` relationships to be listed under `name_ids`. -If your application returns json with underscored attributes and `_id` or `_ids` +If your application returns json with underscored attributes and `_id` or `_ids` for relation, you can extend `ActiveModelSerializer` and all will work out of the box. ```js App.ApplicationSerializer = DS.ActiveModelSerializer.extend({}); ``` -Note: DS.ActiveModelSerializer is not to be confused with the ActiveModelSerializer gem +Note: DS.ActiveModelSerializer is not to be confused with the ActiveModelSerializer gem that is part of Rails API project. A conventional Rails API project with produce underscored output and the `DS.ActiveModelSerializer` will perform the expected normalization behavior such as camelizing property keys in your JSON. diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 4c4149e7b63..3af7cd8f4e1 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -124,8 +124,7 @@ var Adapter = Ember.Object.extend({ find: null, /** - The `findAll()` method is called when you call `find` on the store - without an ID (i.e. `store.find('post')`). + The `findAll()` method is used to retrieve all records for a given type. Example @@ -148,7 +147,6 @@ var Adapter = Ember.Object.extend({ }); ``` - @private @method findAll @param {DS.Store} store @param {DS.Model} type diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 2159b60e1e7..8bd47325bd9 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -462,10 +462,10 @@ Store = Service.extend({ --- - To find all records for a type, call `find` with no additional parameters: + To find all records for a type, call `findAll`: ```javascript - store.find('person'); + store.findAll('person'); ``` This will ask the adapter's `findAll` method to find the records for the @@ -526,6 +526,7 @@ Store = Service.extend({ Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); if (arguments.length === 1) { + Ember.deprecate('Using store.find(type) has been deprecated. Use store.findAll(type) to retrieve all records for a given type.'); return this.findAll(modelName); } @@ -997,7 +998,6 @@ Store = Service.extend({ the array with records of that type. @method findAll - @private @param {String} modelName @return {DS.AdapterPopulatedRecordArray} */ diff --git a/packages/ember-data/tests/integration/adapter/find-all-test.js b/packages/ember-data/tests/integration/adapter/find-all-test.js index 1f4bfc6b727..846dcc58cd9 100644 --- a/packages/ember-data/tests/integration/adapter/find-all-test.js +++ b/packages/ember-data/tests/integration/adapter/find-all-test.js @@ -43,7 +43,7 @@ test("When all records for a type are requested, the store should call the adapt var allRecords; run(function() { - store.find('person').then(function(all) { + store.findAll('person').then(function(all) { allRecords = all; equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); @@ -51,7 +51,7 @@ test("When all records for a type are requested, the store should call the adapt }); run(function() { - store.find('person').then(function(all) { + store.findAll('person').then(function(all) { // Only one record array per type should ever be created (identity map) strictEqual(allRecords, all, "the same record array is returned every time all records of a type are requested"); }); @@ -78,9 +78,9 @@ test("When all records for a type are requested, a rejection should reject the p var allRecords; run(function() { - store.find('person').then(null, function() { + store.findAll('person').then(null, function() { ok(true, "The rejection should get here"); - return store.find('person'); + return store.findAll('person'); }).then(function(all) { allRecords = all; equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); diff --git a/packages/ember-data/tests/integration/adapter/find-test.js b/packages/ember-data/tests/integration/adapter/find-test.js index d07614e0ed4..e91de0e63b4 100644 --- a/packages/ember-data/tests/integration/adapter/find-test.js +++ b/packages/ember-data/tests/integration/adapter/find-test.js @@ -22,14 +22,12 @@ module("integration/adapter/find - Finding Records", { }); test("It raises an assertion when no type is passed", function() { - expectAssertion(function() { store.find(); }, "You need to pass a type to the store's find method"); }); test("It raises an assertion when `undefined` is passed as id (#1705)", function() { - expectAssertion(function() { store.find('person', undefined); }, "You may not pass `undefined` as id to the store's find method"); @@ -39,6 +37,23 @@ test("It raises an assertion when `undefined` is passed as id (#1705)", function }, "You may not pass `null` as id to the store's find method"); }); +test("store.find(type) is deprecated", function() { + env.registry.register('adapter:person', DS.Adapter.extend({ + findAll: function(store, typeClass) { + return []; + } + })); + + expectDeprecation( + function() { + run(function() { + store.find('person'); + }); + }, + 'Using store.find(type) has been deprecated. Use store.findAll(type) to retrieve all records for a given type.' + ); +}); + test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function() { expect(2); From 0aa0c8da839aa58cbef1b772ba4271de0be8200d Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Sat, 6 Jun 2015 20:49:34 -0400 Subject: [PATCH 0892/2527] Use dasherized modelName to fetch serializer --- packages/ember-data/lib/serializers/rest-serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index 70136a19770..8670cee973c 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -451,7 +451,7 @@ var RESTSerializer = JSONSerializer.extend({ forEach.call(value, function(hash) { var typeName = this.modelNameFromPayloadKey(prop); var type = store.modelFor(typeName); - var typeSerializer = store.serializerFor(type); + var typeSerializer = store.serializerFor(type.modelName); hash = typeSerializer.normalize(type, hash, prop); From 34bc7792a0c808793d54c83d05c51a506a505d3e Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Sat, 6 Jun 2015 21:05:45 -0400 Subject: [PATCH 0893/2527] Use Map.prototype.delete instead of Map.prototype.remove --- packages/ember-data/lib/system/record-array-manager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/record-array-manager.js b/packages/ember-data/lib/system/record-array-manager.js index 5243bc92e4f..c9ecf97a0b8 100644 --- a/packages/ember-data/lib/system/record-array-manager.js +++ b/packages/ember-data/lib/system/record-array-manager.js @@ -294,7 +294,7 @@ export default Ember.Object.extend({ } else if (this.liveRecordArrays.has(typeClass)) { var liveRecordArrayForType = this.liveRecordArrayFor(typeClass); if (array === liveRecordArrayForType) { - this.liveRecordArrays.remove(typeClass); + this.liveRecordArrays.delete(typeClass); } } }, From 2ee14f97c3027664ec5e0f0d90c2d56024966b7a Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 6 Jun 2015 21:50:47 -0500 Subject: [PATCH 0894/2527] add test asserting findAll resolves with DS.Models http://stackoverflow.com/questions/30680516/ember-data-1-0-0-beta-19-store-find-returns-ds-internalmodel-instances --- .../integration/adapter/rest-adapter-test.js | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js b/packages/ember-data/tests/integration/adapter/rest-adapter-test.js index 5b2e2218b02..563d182acdd 100644 --- a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js +++ b/packages/ember-data/tests/integration/adapter/rest-adapter-test.js @@ -1,6 +1,7 @@ var env, store, adapter, Post, Comment, SuperUser; var passedUrl, passedVerb, passedHash; var run = Ember.run; +var get = Ember.get; module("integration/adapter/rest_adapter - REST Adapter", { setup: function() { @@ -1888,3 +1889,32 @@ test('ajaxError wraps the error string in an Error object', function() { Ember.$.ajax = originalAjax; } }); + +test('findAll resolves with a collection of DS.Models, not DS.InternalModels', () => { + expect(4); + + ajaxResponse({ + posts: [ + { + id: 1, + name: 'dhh lol' + }, + { + id: 2, + name: 'james mickens is rad' + }, + { + id: 3, + name: 'in the name of love' + } + ] + }); + + run(() => { + store.findAll('post').then(async((posts) => { + equal(get(posts, 'length'), 3); + posts.forEach((post) => ok(post instanceof DS.Model)); + })); + }); + +}); From a9a11e10331a85de590298286ddda541f76c4b8f Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Sun, 7 Jun 2015 10:02:41 -0400 Subject: [PATCH 0895/2527] Rename findByRecord to findRecord --- packages/ember-data/lib/system/store.js | 17 ++++++++--------- .../ember-data/tests/integration/store-test.js | 2 +- .../tests/unit/store/adapter-interop-test.js | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index bb6e2ffd5d3..481be950b6c 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -534,7 +534,7 @@ Store = Service.extend({ return this.findQuery(modelName, id); } - return this.findByRecord(modelName, coerceId(id), preload); + return this.findRecord(modelName, coerceId(id), preload); }, /** @@ -614,21 +614,20 @@ Store = Service.extend({ @return {Promise} promise */ findById: function(modelName, id, preload) { - Ember.deprecate('Using store.findById() has been deprecated. Use store.findByRecord() to return a record for a given type and id combination.'); - return this.findByRecord(modelName, id, preload); + Ember.deprecate('Using store.findById() has been deprecated. Use store.findRecord() to return a record for a given type and id combination.'); + return this.findRecord(modelName, id, preload); }, /** This method returns a record for a given type and id combination. - @method findByRecord - @private + @method findRecord @param {String} modelName @param {(String|Integer)} id @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models @return {Promise} promise */ - findByRecord: function(modelName, id, preload) { + findRecord: function(modelName, id, preload) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var internalModel = this._internalModelForId(modelName, id); @@ -649,7 +648,7 @@ Store = Service.extend({ fetchedInternalModel = internalModel._loadingPromise; } - return promiseRecord(fetchedInternalModel || internalModel, "DS: Store#findByRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id')); + return promiseRecord(fetchedInternalModel || internalModel, "DS: Store#findRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id')); }, /** This method makes a series of requests to the adapter's `find` method @@ -666,12 +665,12 @@ Store = Service.extend({ var store = this; return promiseArray(Ember.RSVP.all(map(ids, function(id) { - return store.findByRecord(modelName, id); + return store.findRecord(modelName, id); })).then(Ember.A, null, "DS: Store#findByIds of " + modelName + " complete")); }, /** - This method is called by `findByRecord` if it discovers that a particular + This method is called by `findRecord` if it discovers that a particular type/id pair hasn't been loaded yet to kick off a request to the adapter. diff --git a/packages/ember-data/tests/integration/store-test.js b/packages/ember-data/tests/integration/store-test.js index 74ef12dcb0d..2bc98e84f73 100644 --- a/packages/ember-data/tests/integration/store-test.js +++ b/packages/ember-data/tests/integration/store-test.js @@ -193,7 +193,7 @@ test("store.findById() is deprecated", function() { store.findById('person', 1); }); }, - 'Using store.findById() has been deprecated. Use store.findByRecord() to return a record for a given type and id combination.' + 'Using store.findById() has been deprecated. Use store.findRecord() to return a record for a given type and id combination.' ); }); diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index 7ef9c372b5f..725c9c5fd69 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -60,7 +60,7 @@ test("Calling Store#find invokes its adapter#find", function() { }); }); -test("Calling Store#findByRecord multiple times coalesces the calls into a adapter#findMany call", function() { +test("Calling Store#findRecord multiple times coalesces the calls into a adapter#findMany call", function() { expect(2); var adapter = TestAdapter.extend({ From a631f01bc43ad9e7e87e7152ab963c544f794b81 Mon Sep 17 00:00:00 2001 From: Christopher Santero Date: Sun, 7 Jun 2015 10:08:33 -0400 Subject: [PATCH 0896/2527] rename store.findQuery to store.query --- .../ember-data/lib/adapters/rest-adapter.js | 2 +- packages/ember-data/lib/system/adapter.js | 4 +- packages/ember-data/lib/system/store.js | 99 ++++++++++--------- .../ember-data/lib/system/store/finders.js | 2 +- .../tests/integration/adapter/queries-test.js | 2 +- .../integration/adapter/rest-adapter-test.js | 20 ++-- .../integration/adapter/store-adapter-test.js | 4 +- .../tests/integration/store-test.js | 2 +- .../tests/unit/record-array-test.js | 2 +- .../tests/unit/store/adapter-interop-test.js | 4 +- 10 files changed, 71 insertions(+), 70 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest-adapter.js b/packages/ember-data/lib/adapters/rest-adapter.js index 12722f2ea67..28bc7f3c087 100644 --- a/packages/ember-data/lib/adapters/rest-adapter.js +++ b/packages/ember-data/lib/adapters/rest-adapter.js @@ -193,7 +193,7 @@ var RestAdapter = Adapter.extend(BuildURLMixin, { For example: ```js - store.find('posts', {sort: 'price', category: 'pets'}); + store.query('posts', {sort: 'price', category: 'pets'}); ``` will generate a requests like this `/posts?category=pets&sort=price`, even if the diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 4c4149e7b63..59865d54749 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -158,9 +158,7 @@ var Adapter = Ember.Object.extend({ findAll: null, /** - This method is called when you call `find` on the store with a - query object as the second parameter (i.e. `store.find('person', { - page: 1 })`). + This method is called when you call `query` on the store. Example diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index bb6e2ffd5d3..3dd3f5f47bb 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -40,7 +40,7 @@ import { _findHasMany, _findBelongsTo, _findAll, - _findQuery + _query } from "ember-data/system/store/finders"; import coerceId from "ember-data/system/coerce-id"; @@ -473,47 +473,6 @@ Store = Service.extend({ returns the values. The promise will resolve into all records of this type present in the store, even if the server only returns a subset of them. - --- - - To find a record by a query, call `find` with a hash as the second - parameter: - - ```javascript - store.find('person', { page: 1 }); - ``` - - By passing an object `{page: 1}` as an argument to the find method, it - delegates to the adapter's findQuery method. The adapter then makes - a call to the server, transforming the object `{page: 1}` as parameters - that are sent along, and will return a RecordArray when the promise - resolves. - - Exposing queries this way seems preferable to creating an abstract query - language for all server-side queries, and then require all adapters to - implement them. - - The call made to the server, using a Rails backend, will look something like this: - - ``` - Started GET "/api/v1/person?page=1" - Processing by Api::V1::PersonsController#index as HTML - Parameters: {"page"=>"1"} - ``` - - If you do something like this: - - ```javascript - store.find('person', {ids: [1, 2, 3]}); - ``` - - The call to the server, using a Rails backend, will look something like this: - - ``` - Started GET "/api/v1/person?ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3" - Processing by Api::V1::PersonsController#index as HTML - Parameters: {"ids"=>["1", "2", "3"]} - ``` - @method find @param {String} modelName @param {(Object|String|Integer|null)} id @@ -531,7 +490,8 @@ Store = Service.extend({ // We are passed a query instead of an id. if (Ember.typeOf(id) === 'object') { - return this.findQuery(modelName, id); + Ember.deprecate('Calling store.find() with a query object is deprecated. Use store.query() instead.'); + return this.query(modelName, id); } return this.findByRecord(modelName, coerceId(id), preload); @@ -983,16 +943,37 @@ Store = Service.extend({ language for all server-side queries, and then require all adapters to implement them. + The call made to the server, using a Rails backend, will look something like this: + + ``` + Started GET "/api/v1/person?page=1" + Processing by Api::V1::PersonsController#index as HTML + Parameters: {"page"=>"1"} + ``` + + If you do something like this: + + ```javascript + store.query('person', {ids: [1, 2, 3]}); + ``` + + The call to the server, using a Rails backend, will look something like this: + + ``` + Started GET "/api/v1/person?ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3" + Processing by Api::V1::PersonsController#index as HTML + Parameters: {"ids"=>["1", "2", "3"]} + ``` + This method returns a promise, which is resolved with a `RecordArray` once the server returns. - @method findQuery - @private + @method query @param {String} modelName @param {any} query an opaque query to be used by the adapter @return {Promise} promise */ - findQuery: function(modelName, query) { + query: function(modelName, query) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var array = this.recordArrayManager @@ -1003,7 +984,29 @@ Store = Service.extend({ Ember.assert("You tried to load a query but you have no adapter (for " + typeClass + ")", adapter); Ember.assert("You tried to load a query but your adapter does not implement `findQuery`", typeof adapter.findQuery === 'function'); - return promiseArray(_findQuery(adapter, this, typeClass, query, array)); + return promiseArray(_query(adapter, this, typeClass, query, array)); + }, + + /** + This method delegates a query to the adapter. This is the one place where + adapter-level semantics are exposed to the application. + + Exposing queries this way seems preferable to creating an abstract query + language for all server-side queries, and then require all adapters to + implement them. + + This method returns a promise, which is resolved with a `RecordArray` + once the server returns. + + @method query + @param {String} modelName + @param {any} query an opaque query to be used by the adapter + @return {Promise} promise + @deprecated Use `store.query instead` + */ + findQuery: function(modelName, query) { + Ember.deprecate('store#findQuery is deprecated. You should use store#query instead.'); + return this.query(modelName, query); }, /** @@ -1186,7 +1189,7 @@ Store = Service.extend({ // allow an optional server query if (hasQuery) { - promise = this.findQuery(modelName, query); + promise = this.query(modelName, query); } else if (arguments.length === 2) { filter = query; } diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index 5f96c371810..cf62337031c 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -135,7 +135,7 @@ export function _findAll(adapter, store, typeClass, sinceToken) { }, null, "DS: Extract payload of findAll " + typeClass); } -export function _findQuery(adapter, store, typeClass, query, recordArray) { +export function _query(adapter, store, typeClass, query, recordArray) { var modelName = typeClass.modelName; var promise = adapter.findQuery(store, typeClass, query, recordArray); var serializer = serializerForAdapter(store, adapter, modelName); diff --git a/packages/ember-data/tests/integration/adapter/queries-test.js b/packages/ember-data/tests/integration/adapter/queries-test.js index 6976be91fbe..fbd4520bdef 100644 --- a/packages/ember-data/tests/integration/adapter/queries-test.js +++ b/packages/ember-data/tests/integration/adapter/queries-test.js @@ -28,7 +28,7 @@ test("When a query is made, the adapter should receive a record array it can pop return Ember.RSVP.resolve([{ id: 1, name: "Peter Wagenet" }, { id: 2, name: "Brohuda Katz" }]); }; - store.find('person', { page: 1 }).then(async(function(queryResults) { + store.query('person', { page: 1 }).then(async(function(queryResults) { equal(get(queryResults, 'length'), 2, "the record array has a length of 2 after the results are loaded"); equal(get(queryResults, 'isLoaded'), true, "the record array's `isLoaded` property should be true"); diff --git a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js b/packages/ember-data/tests/integration/adapter/rest-adapter-test.js index 5b2e2218b02..c167f23a7de 100644 --- a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js +++ b/packages/ember-data/tests/integration/adapter/rest-adapter-test.js @@ -960,7 +960,7 @@ test("findQuery - if `sortQueryParams` option is not provided, query params are return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); }; - store.findQuery('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { + store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { // Noop })); }); @@ -976,7 +976,7 @@ test("findQuery - passes buildURL the requestType", function() { return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); }; - store.findQuery('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { + store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { // NOOP })); }); @@ -994,7 +994,7 @@ test("findQuery - if `sortQueryParams` is falsey, query params are not sorted at adapter.sortQueryParams = null; - store.findQuery('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { + store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { // Noop })); }); @@ -1021,7 +1021,7 @@ test("findQuery - if `sortQueryParams` is a custom function, query params passed return newQueryParams; }; - store.findQuery('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { + store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { // Noop })); }); @@ -1032,7 +1032,7 @@ test("findQuery - payload 'meta' is accessible on the record array", function() posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - store.findQuery('post', { page: 2 }).then(async(function(posts) { + store.query('post', { page: 2 }).then(async(function(posts) { equal( posts.get('meta.offset'), 5, @@ -1047,7 +1047,7 @@ test("findQuery - each record array can have it's own meta object", function() { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - store.findQuery('post', { page: 2 }).then(async(function(posts) { + store.query('post', { page: 2 }).then(async(function(posts) { equal( posts.get('meta.offset'), 5, @@ -1057,7 +1057,7 @@ test("findQuery - each record array can have it's own meta object", function() { meta: { offset: 1 }, posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - store.findQuery('post', { page: 1 }).then(async(function(newPosts) { + store.query('post', { page: 1 }).then(async(function(newPosts) { equal(newPosts.get('meta.offset'), 1, 'new array has correct metadata'); equal(posts.get('meta.offset'), 5, 'metadata on the old array hasnt been clobbered'); })); @@ -1072,7 +1072,7 @@ test("findQuery - returning an array populates the array", function() { { id: 2, name: "The Parley Letter" }] }); - store.findQuery('post', { page: 1 }).then(async(function(posts) { + store.query('post', { page: 1 }).then(async(function(posts) { equal(passedUrl, '/posts'); equal(passedVerb, 'GET'); deepEqual(passedHash.data, { page: 1 }); @@ -1110,7 +1110,7 @@ test("findQuery - returning sideloaded data loads the data", function() { comments: [{ id: 1, name: "FIRST" }] }); - store.findQuery('post', { page: 1 }).then(async(function(posts) { + store.query('post', { page: 1 }).then(async(function(posts) { var comment = store.getById('comment', 1); deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); @@ -1128,7 +1128,7 @@ test("findQuery - data is normalized through custom serializers", function() { { _ID_: 2, _NAME_: "The Parley Letter" }] }); - store.findQuery('post', { page: 1 }).then(async(function(posts) { + store.query('post', { page: 1 }).then(async(function(posts) { var post1 = store.getById('post', 1); var post2 = store.getById('post', 2); diff --git a/packages/ember-data/tests/integration/adapter/store-adapter-test.js b/packages/ember-data/tests/integration/adapter/store-adapter-test.js index 605b13c9f1a..06ab28ce357 100644 --- a/packages/ember-data/tests/integration/adapter/store-adapter-test.js +++ b/packages/ember-data/tests/integration/adapter/store-adapter-test.js @@ -50,8 +50,8 @@ test("Records loaded multiple times and retrieved in recordArray are ready to se }]); }; - run(store, 'findQuery', 'person', { q: 'bla' }).then(async(function(people) { - var people2 = store.findQuery('person', { q: 'bla2' }); + run(store, 'query', 'person', { q: 'bla' }).then(async(function(people) { + var people2 = store.query('person', { q: 'bla2' }); return Ember.RSVP.hash({ people: people, people2: people2 }); })).then(async(function(results) { diff --git a/packages/ember-data/tests/integration/store-test.js b/packages/ember-data/tests/integration/store-test.js index 74ef12dcb0d..0dd6ab68e4b 100644 --- a/packages/ember-data/tests/integration/store-test.js +++ b/packages/ember-data/tests/integration/store-test.js @@ -140,7 +140,7 @@ test("destroying the store correctly cleans everything up", function() { var adapterPopulatedPeople, filterdPeople; run(function() { - adapterPopulatedPeople = store.find('person', { + adapterPopulatedPeople = store.query('person', { someCrazy: 'query' }); }); diff --git a/packages/ember-data/tests/unit/record-array-test.js b/packages/ember-data/tests/unit/record-array-test.js index 2992d8b98a9..fdd61e72d6c 100644 --- a/packages/ember-data/tests/unit/record-array-test.js +++ b/packages/ember-data/tests/unit/record-array-test.js @@ -263,7 +263,7 @@ test("an AdapterPopulatedRecordArray knows if it's loaded or not", function() { }; run(function() { - store.find('person', { page: 1 }).then(function(people) { + store.query('person', { page: 1 }).then(function(people) { equal(get(people, 'isLoaded'), true, "The array is now loaded"); }); }); diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index 7ef9c372b5f..5799645b97e 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -215,7 +215,7 @@ test("loadMany takes an optional Object and passes it on to the Adapter", functi }); run(function() { - store.find('person', passedQuery); + store.query('person', passedQuery); }); }); @@ -250,7 +250,7 @@ test("Find with query calls the correct extract", function() { env.registry.register('serializer:application', ApplicationSerializer); run(function() { - store.find('person', passedQuery); + store.query('person', passedQuery); }); equal(callCount, 1, 'extractFindQuery was called'); }); From 339a7d203291570409f7b30103d6d4fb8d7e488d Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Sun, 7 Jun 2015 10:41:18 -0400 Subject: [PATCH 0897/2527] Always use dasherized modelName to fetch serializer --- packages/ember-data/lib/serializers/rest-serializer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index 8670cee973c..085ad39b534 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -596,7 +596,7 @@ var RESTSerializer = JSONSerializer.extend({ continue; } var type = store.modelFor(typeName); - var typeSerializer = store.serializerFor(type); + var typeSerializer = store.serializerFor(type.modelName); var isPrimary = (!forcedSecondary && this.isPrimaryType(store, typeName, primaryTypeClass)); /*jshint loopfunc:true*/ @@ -1051,7 +1051,7 @@ function _newPushPayload(store, rawPayload) { continue; } var type = store.modelFor(modelName); - var typeSerializer = store.serializerFor(type); + var typeSerializer = store.serializerFor(type.modelName); /*jshint loopfunc:true*/ forEach.call(Ember.makeArray(payload[prop]), (hash) => { From 9804a2146f1b6be8bd927adf18bc7d3ce23d7799 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 7 Jun 2015 11:59:52 -0700 Subject: [PATCH 0898/2527] Use Ember._Backburner if present instead of Ember.Backburner. --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 3dd3f5f47bb..fa3cb2cf4e5 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -51,7 +51,7 @@ import ContainerInstanceCache from 'ember-data/system/store/container-instance-c import InternalModel from "ember-data/system/model/internal-model"; import Model from "ember-data/system/model"; -var Backburner = Ember.Backburner || Ember.__loader.require('backburner')['default'] || Ember.__loader.require('backburner')['Backburner']; +var Backburner = Ember._Backburner || Ember.Backburner || Ember.__loader.require('backburner')['default'] || Ember.__loader.require('backburner')['Backburner']; //Shim Backburner.join if (!Backburner.prototype.join) { From ac8ee7e4979552fe879384cde45387ad6711ec6b Mon Sep 17 00:00:00 2001 From: Miguel Camba Date: Fri, 8 May 2015 09:59:54 +0100 Subject: [PATCH 0899/2527] Use ember-new-computed instead of local polyfill --- Brocfile.js | 1 + package.json | 1 + .../ember-data/lib/system/model/attributes.js | 2 +- .../lib/system/relationships/belongs-to.js | 3 +- .../lib/system/relationships/has-many.js | 2 +- .../ember-data/lib/utils/computed-polyfill.js | 35 ------------------- .../utils/supports-computed-getter-setter.js | 13 ------- 7 files changed, 5 insertions(+), 52 deletions(-) delete mode 100644 packages/ember-data/lib/utils/computed-polyfill.js delete mode 100644 packages/ember-data/lib/utils/supports-computed-getter-setter.js diff --git a/Brocfile.js b/Brocfile.js index 41219d529c5..1f4c83a2b6a 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -88,6 +88,7 @@ function packageAddon(packagePath, vendorPath) { var packages = merge([ packageAddon('ember-inflector', 'node_modules/'), + packageAddon('ember-new-computed', 'node_modules/'), package('ember-data'), package('activemodel-adapter'), package('ember') diff --git a/package.json b/package.json index d7fd1e3ced4..1667ee5541f 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "defeatureify": "~0.1.4", "ejs": "^1.0.0", "ember-cli": "^0.1.15", + "ember-new-computed": "1.0.1", "ember-inflector": "^1.5.0", "ember-publisher": "0.0.7", "es6-module-transpiler": "^0.9.5", diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 1e46603be47..8e74e0638dd 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -3,7 +3,7 @@ import { Map } from "ember-data/system/map"; -import computedPolyfill from "ember-data/utils/computed-polyfill"; +import computedPolyfill from "ember-new-computed"; /** @module ember-data diff --git a/packages/ember-data/lib/system/relationships/belongs-to.js b/packages/ember-data/lib/system/relationships/belongs-to.js index d40fba39435..9ed0700fe56 100644 --- a/packages/ember-data/lib/system/relationships/belongs-to.js +++ b/packages/ember-data/lib/system/relationships/belongs-to.js @@ -1,6 +1,5 @@ import Model from 'ember-data/system/model'; - -import computedPolyfill from "ember-data/utils/computed-polyfill"; +import computedPolyfill from "ember-new-computed"; import normalizeModelName from "ember-data/system/normalize-model-name"; /** diff --git a/packages/ember-data/lib/system/relationships/has-many.js b/packages/ember-data/lib/system/relationships/has-many.js index 13fb142ab88..73b3d5db0a8 100644 --- a/packages/ember-data/lib/system/relationships/has-many.js +++ b/packages/ember-data/lib/system/relationships/has-many.js @@ -2,7 +2,7 @@ @module ember-data */ -import computedPolyfill from "ember-data/utils/computed-polyfill"; +import computedPolyfill from "ember-new-computed"; import Model from "ember-data/system/model"; import normalizeModelName from "ember-data/system/normalize-model-name"; diff --git a/packages/ember-data/lib/utils/computed-polyfill.js b/packages/ember-data/lib/utils/computed-polyfill.js deleted file mode 100644 index 5384ae7022d..00000000000 --- a/packages/ember-data/lib/utils/computed-polyfill.js +++ /dev/null @@ -1,35 +0,0 @@ -import supportsComputedGetterSetter from './supports-computed-getter-setter'; - -var computed = Ember.computed; - -export default function() { - var polyfillArguments = []; - var config = arguments[arguments.length - 1]; - - if (typeof config === 'function' || supportsComputedGetterSetter) { - return computed.apply(null, arguments); - } - - for (var i = 0, l = arguments.length - 1; i < l; i++) { - polyfillArguments.push(arguments[i]); - } - - var func; - if (config.set) { - func = function(key, value) { - if (arguments.length > 1) { - return config.set.call(this, key, value); - } else { - return config.get.call(this, key); - } - }; - } else { - func = function(key) { - return config.get.call(this, key); - }; - } - - polyfillArguments.push(func); - - return computed.apply(null, polyfillArguments); -} diff --git a/packages/ember-data/lib/utils/supports-computed-getter-setter.js b/packages/ember-data/lib/utils/supports-computed-getter-setter.js deleted file mode 100644 index 19f290a4027..00000000000 --- a/packages/ember-data/lib/utils/supports-computed-getter-setter.js +++ /dev/null @@ -1,13 +0,0 @@ -var supportsComputedGetterSetter; - -try { - Ember.computed({ - get: function() { }, - set: function() { } - }); - supportsComputedGetterSetter = true; -} catch(e) { - supportsComputedGetterSetter = false; -} - -export default supportsComputedGetterSetter; From 54e6c3d998dd6a1b0802d6cb110104e1bef69bd9 Mon Sep 17 00:00:00 2001 From: Calvin Metcalf Date: Mon, 6 Oct 2014 12:30:41 -0400 Subject: [PATCH 0900/2527] Treat empty strings in ids the same as null or undefined --- packages/ember-data/lib/system/coerce-id.js | 2 +- .../integration/client-id-generation-test.js | 41 ++++++++++++++++++- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/lib/system/coerce-id.js b/packages/ember-data/lib/system/coerce-id.js index 62acf96bb14..f325671ce05 100644 --- a/packages/ember-data/lib/system/coerce-id.js +++ b/packages/ember-data/lib/system/coerce-id.js @@ -5,5 +5,5 @@ // ID into the URL, and if we later try to deserialize that URL and find the // corresponding record, we will not know if it is a string or a number. export default function coerceId(id) { - return id == null ? null : id+''; + return id == null || id === '' ? null : id+''; } diff --git a/packages/ember-data/tests/integration/client-id-generation-test.js b/packages/ember-data/tests/integration/client-id-generation-test.js index 1bf6b79c289..ddbe46500e7 100644 --- a/packages/ember-data/tests/integration/client-id-generation-test.js +++ b/packages/ember-data/tests/integration/client-id-generation-test.js @@ -1,5 +1,5 @@ var get = Ember.get; -var Post, Comment, env; +var Post, Comment, Misc, env; var run = Ember.run; module("integration/client_id_generation - Client-side ID Generation", { @@ -12,9 +12,14 @@ module("integration/client_id_generation - Client-side ID Generation", { comments: DS.hasMany('comment') }); + Misc = DS.Model.extend({ + foo: DS.attr('string') + }); + env = setupStore({ post: Post, - comment: Comment + comment: Comment, + misc: Misc }); }, @@ -60,3 +65,35 @@ test("If an adapter implements the `generateIdForRecord` method, the store shoul post.save(); }); }); + +test("empty string and undefined ids should coerce to null", function() { + expect(6); + var comment, post; + var idCount = 0; + var ids = [undefined, '']; + env.adapter.generateIdForRecord = function(passedStore, record) { + equal(env.store, passedStore, "store is the first parameter"); + + return ids[idCount++]; + }; + + env.adapter.createRecord = function(store, type, record) { + equal(typeof get(record, 'id'), 'object', 'correct type'); + return Ember.RSVP.resolve(); + }; + + run(function() { + comment = env.store.createRecord('misc'); + post = env.store.createRecord('misc'); + }); + + equal(get(comment, 'id'), null, "comment is assigned id 'null'"); + equal(get(post, 'id'), null, "post is assigned id 'null'"); + + // Despite client-generated IDs, calling commit() on the store should still + // invoke the adapter's `createRecord` method. + run(function() { + comment.save(); + post.save(); + }); +}); From 7f036db93886bbe3d0a16c95738034b47062e6fa Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Mon, 8 Jun 2015 10:34:38 -0400 Subject: [PATCH 0901/2527] Update changelog to mention new Instance Initializer --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39e82049844..12b5806dca7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ ### Release 1.0.0-beta.19 (June 5, 2015) +#### Breaking Changes + +##### Store Service moved to an Instance Initializer + +In order to fix deprecations warning induced by Ember 1.12, the store service +is now injected as an instanceInitializer. As a consequence, if you had initializers +depending on the store, you should move them to an instance initializer as well, +and mark it as after: 'ember-data'. + - Removed support for DS.FixtureAdapter. You can use it as an addon, or build it using [Ember Giftwrap](https://github.com/ef4/ember-giftwrap). https://github.com/emberjs/ember-data-fixture-adapter/tree/master From de360871ea7b1be1376c303ffb260bed60582d77 Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Sat, 6 Jun 2015 18:35:43 -0400 Subject: [PATCH 0902/2527] Deprecate store.fetchAll in favor of store.findAll --- packages/ember-data/lib/system/store.js | 10 +++---- .../tests/integration/store-test.js | 29 ++++++++++++++----- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 8bd47325bd9..a3b6011c907 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -584,10 +584,8 @@ Store = Service.extend({ @return {Promise} promise */ fetchAll: function(modelName) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - var typeClass = this.modelFor(modelName); - - return this._fetchAll(typeClass, this.all(modelName)); + Ember.deprecate('Using store.fetchAll(type) has been deprecated. Use store.findAll(type) to retrieve all records for a given type.'); + return this.findAll(modelName); }, /** @@ -1003,7 +1001,9 @@ Store = Service.extend({ */ findAll: function(modelName) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - return this.fetchAll(modelName); + var typeClass = this.modelFor(modelName); + + return this._fetchAll(typeClass, this.all(modelName)); }, /** diff --git a/packages/ember-data/tests/integration/store-test.js b/packages/ember-data/tests/integration/store-test.js index 7bc52661dd0..e34625f2615 100644 --- a/packages/ember-data/tests/integration/store-test.js +++ b/packages/ember-data/tests/integration/store-test.js @@ -269,13 +269,28 @@ test("Using store#fetchById on existing record reloads it", function() { }); }); -module("integration/store - fetchAll", { +module("integration/store - findAll", { setup: function() { initializeStore(DS.RESTAdapter.extend()); } }); -test("Using store#fetchAll with no records triggers a query", function() { +test("store#fetchAll() is deprecated", function() { + ajaxResponse({ + cars: [] + }); + + expectDeprecation( + function() { + run(function() { + store.fetchAll('car'); + }); + }, + 'Using store.fetchAll(type) has been deprecated. Use store.findAll(type) to retrieve all records for a given type.' + ); +}); + +test("Using store#findAll with no records triggers a query", function() { expect(2); ajaxResponse({ @@ -295,13 +310,13 @@ test("Using store#fetchAll with no records triggers a query", function() { ok(!cars.get('length'), 'There is no cars in the store'); run(function() { - store.fetchAll('car').then(function(cars) { + store.findAll('car').then(function(cars) { equal(cars.get('length'), 2, 'Two car were fetched'); }); }); }); -test("Using store#fetchAll with existing records performs a query, updating existing records and returning new ones", function() { +test("Using store#findAll with existing records performs a query, updating existing records and returning new ones", function() { expect(3); run(function() { @@ -329,7 +344,7 @@ test("Using store#fetchAll with existing records performs a query, updating exis equal(cars.get('length'), 1, 'There is one car in the store'); run(function() { - store.fetchAll('car').then(function(cars) { + store.findAll('car').then(function(cars) { equal(cars.get('length'), 2, 'There is 2 cars in the store now'); var mini = cars.findBy('id', '1'); equal(mini.get('model'), 'New Mini', 'Existing records have been updated'); @@ -337,7 +352,7 @@ test("Using store#fetchAll with existing records performs a query, updating exis }); }); -test("store#fetchAll should return all known records even if they are not in the adapter response", function() { +test("store#findAll should return all known records even if they are not in the adapter response", function() { expect(4); run(function() { @@ -357,7 +372,7 @@ test("store#fetchAll should return all known records even if they are not in the equal(cars.get('length'), 2, 'There is two cars in the store'); run(function() { - store.fetchAll('car').then(function(cars) { + store.findAll('car').then(function(cars) { equal(cars.get('length'), 2, 'It returns all cars'); var mini = cars.findBy('id', '1'); equal(mini.get('model'), 'New Mini', 'Existing records have been updated'); From cd43c952d4ff7cc8d6fa5f70e42840fe7330ddcd Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 5 Jun 2015 10:44:23 -0400 Subject: [PATCH 0903/2527] Update Wecc's property change notification pr based on pr feedback --- .../lib/system/model/internal-model.js | 58 ++++++++++++++++--- .../records/property-changes-test.js | 31 ++++++++++ 2 files changed, 82 insertions(+), 7 deletions(-) diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js index 9711f724cef..843de1f75fa 100644 --- a/packages/ember-data/lib/system/model/internal-model.js +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -588,10 +588,9 @@ InternalModel.prototype = { this.didCleanError(); var changedKeys = this._changedKeys(data); + merge(this._data, this._inFlightAttributes); if (data) { merge(this._data, data); - } else { - merge(this._data, this._inFlightAttributes); } this._inFlightAttributes = Ember.create(null); @@ -664,27 +663,72 @@ InternalModel.prototype = { this._inFlightAttributes = Ember.create(null); }, - /** + /** @method _changedKeys + + Ember Data has 3 buckets for storing the value of an attribute on an internalModel. + + `_data` holds all of the attributes that have been acknowledged by + a backend via the adapter. When rollback is called on a model all + attributes will revert to the record's state in `_data`. + + `_attributes` holds any change the user has made to an attribute + that has not been acknowledged by the adapter. Any values in + `_attributes` are have priority over values in `_data`. + + `_inFlightAttributes`. When a record is being synced with the + backend the values in `_attributes` are copied to + `_inFlightAttributes`. This way if the backend acknowledges the + save but does not return the new state Ember Data can copy the + values from `_inFlightAttributes` to `_data`. Without having to + worry about changes made to `_attributes` while the save was + happenign. + + + Changed keys builds a list of all of the values that may have been + changed by the backend after a successful save. + + It does this by iterating over each key, value pair in the payload + returned from the server after a save. If the `key` is found in + `_attributes` then the user has a local changed to the attribute + that has not been synced with the server and the key is not + included in the list of changed keys. + + + + If the value, for a key differs from the value in what Ember Data + believes to be the truth about the backend state (A merger of the + `_data` and `_inFlightAttributes` objects where + `_inFlightAttributes` has priority) then that means the backend + has updated the value and the key is added to the list of changed + keys. + @private */ _changedKeys: function(updates) { var changedKeys = []; - if (updates && typeof updates === 'object') { + if (updates) { var original, i, value, key; var keys = Ember.keys(updates); var length = keys.length; - original = merge({}, this._data); - original = merge(original, this._attributes); + original = merge(Ember.create(null), this._data); original = merge(original, this._inFlightAttributes); for (i = 0; i < length; i++) { key = keys[i]; value = updates[key]; - if (original[key] !== value) { + // A value in _attributes means the user has a local change to + // this attributes. We never override this value when merging + // updates from the backend so we should not sent a change + // notification if the server value differs from the original. + if (this._attributes[key] !== undefined) { + continue; + } + + if (!Ember.isEqual(original[key], value)) { changedKeys.push(key); } } diff --git a/packages/ember-data/tests/integration/records/property-changes-test.js b/packages/ember-data/tests/integration/records/property-changes-test.js index c7e816d84f2..228f1ae3fdf 100644 --- a/packages/ember-data/tests/integration/records/property-changes-test.js +++ b/packages/ember-data/tests/integration/records/property-changes-test.js @@ -113,3 +113,34 @@ test('Saving a record trigger observers for locally changed attributes with the person.save(); }); }); + +test('store.push should not override a modified attribute', function() { + expect(1); + var person; + + run(function() { + person = store.push('person', { + id: 'wat', + firstName: 'Yehuda', + lastName: 'Katz' + }); + + person.set('lastName', 'Katz!'); + }); + + person.addObserver('firstName', function() { + ok(true, 'firstName observer should be triggered'); + }); + + person.addObserver('lastName', function() { + ok(false, 'lastName observer should not be triggered'); + }); + + run(function() { + person = store.push('person', { + id: 'wat', + firstName: 'Tom', + lastName: 'Dale' + }); + }); +}); From 7bd5993beaf8998338fc2b61e4acfe1261a49cd6 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 8 Jun 2015 15:38:38 -0400 Subject: [PATCH 0904/2527] Pass _internalModel into a record when it is created --- .../lib/system/model/internal-model.js | 4 ++-- packages/ember-data/lib/system/model/model.js | 1 + packages/ember-data/tests/unit/model-test.js | 20 +++++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js index a304982b89b..8e1ade5fad0 100644 --- a/packages/ember-data/lib/system/model/internal-model.js +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -112,9 +112,9 @@ InternalModel.prototype = { this.record = this.type._create({ id: this.id, store: this.store, - container: this.container + container: this.container, + _internalModel: this }); - this.record._internalModel = this; this._triggerDeferredTriggers(); }, diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index fa1332b7d94..f85b93320d3 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -30,6 +30,7 @@ var retrieveFromCurrentState = Ember.computed('currentState', function(key) { var Model = Ember.Object.extend(Ember.Evented, { _recordArrays: undefined, _relationships: undefined, + _internalModel: null, store: null, diff --git a/packages/ember-data/tests/unit/model-test.js b/packages/ember-data/tests/unit/model-test.js index 4e0b70f672c..e2ec4999241 100644 --- a/packages/ember-data/tests/unit/model-test.js +++ b/packages/ember-data/tests/unit/model-test.js @@ -869,3 +869,23 @@ test('toJSON looks up the JSONSerializer using the store instead of using JSONSe ok(!errorThrown, 'error not thrown due to missing store'); deepEqual(json, {}); }); + + +test('accessing attributes in the initializer should not throw an error', function() { + expect(1); + var Person = DS.Model.extend({ + name: DS.attr('string'), + + init: function() { + this._super.apply(this, arguments); + ok(!this.get('name')); + } + }); + + var env = setupStore({ + person: Person + }); + var store = env.store; + + run(_ => store.createRecord('person')); +}); From 78878c1b805be098b8432d7a06ed19afcdf2ea65 Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Mon, 8 Jun 2015 23:57:12 -0400 Subject: [PATCH 0905/2527] Pad single-line objects with white-space --- packages/ember-data/lib/adapters/rest-adapter.js | 2 +- .../lib/serializers/embedded-records-mixin.js | 8 ++++---- packages/ember-data/lib/serializers/json-serializer.js | 10 +++++----- packages/ember-data/lib/system/model/attributes.js | 2 +- packages/ember-data/lib/system/relationships/ext.js | 6 +++--- packages/ember-data/lib/system/store.js | 6 +++--- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/ember-data/lib/adapters/rest-adapter.js b/packages/ember-data/lib/adapters/rest-adapter.js index 28bc7f3c087..caf968b9ddd 100644 --- a/packages/ember-data/lib/adapters/rest-adapter.js +++ b/packages/ember-data/lib/adapters/rest-adapter.js @@ -193,7 +193,7 @@ var RestAdapter = Adapter.extend(BuildURLMixin, { For example: ```js - store.query('posts', {sort: 'price', category: 'pets'}); + store.query('posts', { sort: 'price', category: 'pets' }); ``` will generate a requests like this `/posts?category=pets&sort=price`, even if the diff --git a/packages/ember-data/lib/serializers/embedded-records-mixin.js b/packages/ember-data/lib/serializers/embedded-records-mixin.js index f600c5fdc5c..bb97a86cbeb 100644 --- a/packages/ember-data/lib/serializers/embedded-records-mixin.js +++ b/packages/ember-data/lib/serializers/embedded-records-mixin.js @@ -161,7 +161,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - author: {embedded: 'always'} + author: { embedded: 'always' } } }) ``` @@ -269,8 +269,8 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ serializing. When serializing, an option to embed `ids` or `records` can be set. When extracting the only option is `records`. - So `{embedded: 'always'}` is shorthand for: - `{serialize: 'records', deserialize: 'records'}` + So `{ embedded: 'always' }` is shorthand for: + `{ serialize: 'records', deserialize: 'records' }` To embed the `ids` for a related object (using a hasMany relationship): @@ -279,7 +279,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { - comments: {serialize: 'ids', deserialize: 'records'} + comments: { serialize: 'ids', deserialize: 'records' } } }) ``` diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index 6a205e7e319..4d7020c6bc1 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -133,7 +133,7 @@ export default Serializer.extend({ export default DS.JSONSerializer.extend({ attrs: { admin: 'is_admin', - occupation: {key: 'career'} + occupation: { key: 'career' } } }); ``` @@ -149,7 +149,7 @@ export default Serializer.extend({ export default DS.JSONSerializer.extend({ attrs: { admin: {serialize: false}, - occupation: {key: 'career'} + occupation: { key: 'career' } } }); ``` @@ -730,8 +730,8 @@ export default Serializer.extend({ var mappedKey; if (attrs && attrs[key]) { mappedKey = attrs[key]; - //We need to account for both the {title: 'post_title'} and - //{title: {key: 'post_title'}} forms + //We need to account for both the { title: 'post_title' } and + //{ title: { key: 'post_title' }} forms if (mappedKey.key) { mappedKey = mappedKey.key; } @@ -1117,7 +1117,7 @@ export default Serializer.extend({ /** You can use this method to customize how polymorphic objects are serialized. Objects are considered to be polymorphic if - `{polymorphic: true}` is pass as the second argument to the + `{ polymorphic: true }` is pass as the second argument to the `DS.belongsTo` function. Example diff --git a/packages/ember-data/lib/system/model/attributes.js b/packages/ember-data/lib/system/model/attributes.js index 8e74e0638dd..c0c80deb46b 100644 --- a/packages/ember-data/lib/system/model/attributes.js +++ b/packages/ember-data/lib/system/model/attributes.js @@ -274,7 +274,7 @@ function getValue(record, key) { export default DS.Model.extend({ username: DS.attr('string'), email: DS.attr('string'), - verified: DS.attr('boolean', {defaultValue: false}) + verified: DS.attr('boolean', { defaultValue: false }) }); ``` diff --git a/packages/ember-data/lib/system/relationships/ext.js b/packages/ember-data/lib/system/relationships/ext.js index 25c94aa3932..5eb4845f216 100644 --- a/packages/ember-data/lib/system/relationships/ext.js +++ b/packages/ember-data/lib/system/relationships/ext.js @@ -210,8 +210,8 @@ Model.reopenClass({ }); ``` - App.Post.inverseFor('comments') -> {type: App.Message, name:'owner', kind:'belongsTo'} - App.Message.inverseFor('owner') -> {type: App.Post, name:'comments', kind:'hasMany'} + App.Post.inverseFor('comments') -> { type: App.Message, name: 'owner', kind: 'belongsTo' } + App.Message.inverseFor('owner') -> { type: App.Post, name: 'comments', kind: 'hasMany' } @method inverseFor @static @@ -238,7 +238,7 @@ Model.reopenClass({ } var propertyMeta = this.metaForProperty(name); - //If inverse is manually specified to be null, like `comments: DS.hasMany('message', {inverse: null})` + //If inverse is manually specified to be null, like `comments: DS.hasMany('message', { inverse: null })` var options = propertyMeta.options; if (options.inverse === null) { return null; } diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 7c325cc53d5..0cf38b773f3 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -445,7 +445,7 @@ Store = Service.extend({ without fetching the post you can pass in the post to the `find` call: ```javascript - store.find('comment', 2, {post: 1}); + store.find('comment', 2, { post: 1 }); ``` If you have access to the post model you can also pass the model itself: @@ -1687,10 +1687,10 @@ Store = Service.extend({ ```js var pushData = { posts: [ - {id: 1, post_title: "Great post", comment_ids: [2]} + { id: 1, post_title: "Great post", comment_ids: [2] } ], comments: [ - {id: 2, comment_body: "Insightful comment"} + { id: 2, comment_body: "Insightful comment" } ] } From 9a00fac84f06545f3ccea2cca88c3644531b6476 Mon Sep 17 00:00:00 2001 From: IgorT Date: Tue, 9 Jun 2015 08:12:10 +0300 Subject: [PATCH 0906/2527] Fix for passing json api objects into push --- packages/ember-data/lib/system/store.js | 9 ++++- .../lib/system/store/serializer-response.js | 33 ++++++++++--------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 787815896c9..a1a58dc7786 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1621,7 +1621,14 @@ Store = Service.extend({ _pushInternalModel: function(modelName, data) { if (Ember.typeOf(modelName) === 'object' && Ember.typeOf(data) === 'undefined') { - return pushPayload(this, modelName); + //TODO Remove once the transition is complete + var result = pushPayload(this, modelName); + if (Ember.isArray(result)) { + return map(result, (item) => { + return item._internalModel; + }); + } + return result._internalModel; } Ember.assert("Expected an object as `data` in a call to `push` for " + modelName + " , but was " + Ember.typeOf(data), Ember.typeOf(data) === 'object'); Ember.assert("You must include an `id` for " + modelName + " in an object passed to `push`", data.id != null && data.id !== ''); diff --git a/packages/ember-data/lib/system/store/serializer-response.js b/packages/ember-data/lib/system/store/serializer-response.js index 36de338dcbd..d1aba0fd0d0 100644 --- a/packages/ember-data/lib/system/store/serializer-response.js +++ b/packages/ember-data/lib/system/store/serializer-response.js @@ -221,20 +221,23 @@ export function convertResourceObject(payload) { links: {} }; - var attributeKeys = Ember.keys(payload.attributes); - forEach(attributeKeys, function(key) { - var attribute = payload.attributes[key]; - data[key] = attribute; - }); - - var relationshipKeys = Ember.keys(payload.relationships); - forEach(relationshipKeys, function(key) { - var relationship = payload.relationships[key]; - if (relationship.hasOwnProperty('data')) { - data[key] = relationship.data; - } else if (relationship.links && relationship.links.related) { - data.links[key] = relationship.links.related; - } - }); + if (payload.attributes) { + var attributeKeys = Ember.keys(payload.attributes); + forEach(attributeKeys, function(key) { + var attribute = payload.attributes[key]; + data[key] = attribute; + }); + } + if (payload.relationships) { + var relationshipKeys = Ember.keys(payload.relationships); + forEach(relationshipKeys, function(key) { + var relationship = payload.relationships[key]; + if (relationship.hasOwnProperty('data')) { + data[key] = relationship.data; + } else if (relationship.links && relationship.links.related) { + data.links[key] = relationship.links.related; + } + }); + } return data; } From 8a99a3c09d7aca29bb3392b18e7f0cfe327b1c7e Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 9 Jun 2015 07:16:47 +0200 Subject: [PATCH 0907/2527] Fix JSHint: '_' is defined but never used. --- packages/ember-data/tests/unit/model-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/tests/unit/model-test.js b/packages/ember-data/tests/unit/model-test.js index e2ec4999241..58aa5d8a949 100644 --- a/packages/ember-data/tests/unit/model-test.js +++ b/packages/ember-data/tests/unit/model-test.js @@ -887,5 +887,5 @@ test('accessing attributes in the initializer should not throw an error', functi }); var store = env.store; - run(_ => store.createRecord('person')); + run(() => store.createRecord('person')); }); From e01fb1681e8154157ca574f1534eb84ede8a8b77 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Tue, 9 Jun 2015 10:10:47 +0200 Subject: [PATCH 0908/2527] Pass store to inverseFor in removeEmbeddedForeignKey --- .../lib/serializers/embedded-records-mixin.js | 2 +- .../embedded-records-mixin-test.js | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/embedded-records-mixin.js b/packages/ember-data/lib/serializers/embedded-records-mixin.js index bb97a86cbeb..15d1764839f 100644 --- a/packages/ember-data/lib/serializers/embedded-records-mixin.js +++ b/packages/ember-data/lib/serializers/embedded-records-mixin.js @@ -346,7 +346,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ if (relationship.kind === 'hasMany') { return; } else if (relationship.kind === 'belongsTo') { - var parentRecord = snapshot.type.inverseFor(relationship.key); + var parentRecord = snapshot.type.inverseFor(relationship.key, this.store); if (parentRecord) { var name = parentRecord.name; var embeddedSerializer = this.store.serializerFor(embeddedSnapshot.modelName); diff --git a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js index df1c945db8f..d11686c3e5d 100644 --- a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js +++ b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js @@ -1537,3 +1537,38 @@ test("serializing relationships with an embedded and without calls super when no ok(calledSerializeBelongsTo); ok(calledSerializeHasMany); }); + +test("serializing belongsTo correctly removes embedded foreign key", function() { + SecretWeapon.reopen({ + superVillain: null + }); + EvilMinion.reopen({ + secretWeapon: DS.belongsTo('secret-weapon'), + superVillain: null + }); + + run(function() { + secretWeapon = env.store.createRecord('secret-weapon', { name: "Secret Weapon" }); + evilMinion = env.store.createRecord('evil-minion', { name: "Evil Minion", secretWeapon: secretWeapon }); + }); + + env.registry.register('serializer:evil-minion', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretWeapon: { embedded: 'always' } + } + })); + + var serializer = env.container.lookup("serializer:evil-minion"); + var json; + + run(function() { + json = serializer.serialize(evilMinion._createSnapshot()); + }); + + deepEqual(json, { + name: "Evil Minion", + secretWeapon: { + name: "Secret Weapon" + } + }); +}); From 2aa1f27e237e270fc024d22b615416cf48cdd8ea Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 8 Jun 2015 17:07:43 -0400 Subject: [PATCH 0909/2527] Deprecate the preload argument to `find`/`fetchById` and move in into the `preload` key on the options argument. --- packages/ember-data/lib/system/store.js | 53 ++++++++++---- .../adapter/build-url-mixin-test.js | 2 +- .../tests/unit/store/adapter-interop-test.js | 73 +++++++++++++++++-- 3 files changed, 108 insertions(+), 20 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index a1a58dc7786..9ae07dd64aa 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -445,7 +445,7 @@ Store = Service.extend({ without fetching the post you can pass in the post to the `find` call: ```javascript - store.find('comment', 2, { post: 1 }); + store.find('comment', 2, { preload: { post: 1 } }); ``` If you have access to the post model you can also pass the model itself: @@ -476,7 +476,7 @@ Store = Service.extend({ @method find @param {String} modelName @param {(Object|String|Integer|null)} id - @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models + @param {Object} options @return {Promise} promise */ find: function(modelName, id, preload) { @@ -494,8 +494,8 @@ Store = Service.extend({ Ember.deprecate('Calling store.find() with a query object is deprecated. Use store.query() instead.'); return this.query(modelName, id); } - - return this.findRecord(modelName, coerceId(id), preload); + var options = deprecatePreload(preload, this.modelFor(modelName), 'find'); + return this.findRecord(modelName, coerceId(id), options); }, /** @@ -523,15 +523,16 @@ Store = Service.extend({ @method fetchById @param {String} modelName @param {(String|Integer)} id - @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models + @param {Object} options @return {Promise} promise */ fetchById: function(modelName, id, preload) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + var options = deprecatePreload(preload, this.modelFor(modelName), 'fetchById'); if (this.hasRecordForId(modelName, id)) { return this.getById(modelName, id).reload(); } else { - return this.find(modelName, id, preload); + return this.findRecord(modelName, id, options); } }, @@ -569,12 +570,13 @@ Store = Service.extend({ @private @param {String} modelName @param {(String|Integer)} id - @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models + @param {Object} options @return {Promise} promise */ findById: function(modelName, id, preload) { Ember.deprecate('Using store.findById() has been deprecated. Use store.findRecord() to return a record for a given type and id combination.'); - return this.findRecord(modelName, id, preload); + var options = deprecatePreload(preload, this.modelFor(modelName), 'findById'); + return this.findRecord(modelName, id, options); }, /** @@ -583,21 +585,23 @@ Store = Service.extend({ @method findRecord @param {String} modelName @param {(String|Integer)} id - @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models + @param {Object} options @return {Promise} promise */ - findRecord: function(modelName, id, preload) { + findRecord: function(modelName, id, options) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var internalModel = this._internalModelForId(modelName, id); - return this._findByInternalModel(internalModel, preload); + return this._findByInternalModel(internalModel, options); }, - _findByInternalModel: function(internalModel, preload) { + _findByInternalModel: function(internalModel, options) { var fetchedInternalModel; + options = options || {}; + - if (preload) { - internalModel._preloadData(preload); + if (options.preload) { + internalModel._preloadData(options.preload); } if (internalModel.isEmpty()) { @@ -2172,5 +2176,26 @@ function setupRelationships(store, record, data) { }); } +function deprecatePreload(preloadOrOptions, type, methodName) { + if (preloadOrOptions) { + var modelProperties = []; + var fields = Ember.get(type, 'fields'); + fields.forEach(function(fieldType, key) { + modelProperties.push(key); + }); + var preloadDetected = modelProperties.reduce(function(memo, key) { + return typeof preloadOrOptions[key] !== 'undefined' || memo; + }, false); + if (preloadDetected) { + Ember.deprecate(`Passing a preload argument to \`store.${methodName}\` is deprecated. Please move it to the preload key on the ${methodName} \`options\` argument.`); + var preload = preloadOrOptions; + return { + preload: preload + }; + } + } + return preloadOrOptions; +} + export { Store }; export default Store; diff --git a/packages/ember-data/tests/integration/adapter/build-url-mixin-test.js b/packages/ember-data/tests/integration/adapter/build-url-mixin-test.js index cdc8008f614..dc2a1b75619 100644 --- a/packages/ember-data/tests/integration/adapter/build-url-mixin-test.js +++ b/packages/ember-data/tests/integration/adapter/build-url-mixin-test.js @@ -178,7 +178,7 @@ test('buildURL - buildURL takes a record from find', function() { }); run(function() { - store.find('comment', 1, { post: post }).then(async(function(post) { + store.find('comment', 1, { preload: { post: post } }).then(async(function(post) { equal(passedUrl, "/posts/2/comments/1"); })); }); diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index 2747cd1f1e4..d6585e92867 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -391,7 +391,7 @@ test("initial values of attributes can be passed in as the third argument to fin }); run(function() { - store.find('test', 1, { name: 'Test' }); + store.find('test', 1, { preload: { name: 'Test' } }); }); }); @@ -419,7 +419,7 @@ test("initial values of belongsTo can be passed in as the third argument to find run(function() { tom = store.push('person', { id: 2, name: 'Tom' }); - store.find('person', 1, { friend: tom }); + store.find('person', 1, { preload: { friend: tom } }); }); }); @@ -445,7 +445,7 @@ test("initial values of belongsTo can be passed in as the third argument to find env.registry.register('model:person', Person); run(function() { - store.find('person', 1, { friend: 2 }).then(async(function() { + store.find('person', 1, { preload: { friend: 2 } }).then(async(function() { store.getById('person', 1).get('friend').then(async(function(friend) { equal(friend.get('id'), '2', 'Preloaded belongsTo set'); })); @@ -477,7 +477,7 @@ test("initial values of hasMany can be passed in as the third argument to find a run(function() { tom = store.push('person', { id: 2, name: 'Tom' }); - store.find('person', 1, { friends: [tom] }); + store.find('person', 1, { preload: { friends: [tom] } }); }); }); @@ -504,7 +504,7 @@ test("initial values of hasMany can be passed in as the third argument to find a env.registry.register('model:person', Person); run(function() { - store.find('person', 1, { friends: [2] }); + store.find('person', 1, { preload: { friends: [2] } }); }); }); @@ -814,3 +814,66 @@ test("store.fetchRecord reject records that were not found, even when those requ }); }, /expected to find records with the following ids in the adapter response but they were missing/); }); + +module("unit/store/adapter_interop - find preload deprecations", { + setup: function() { + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var TestAdapter = DS.Adapter.extend({ + find: function(store, type, id, snapshot) { + equal(snapshot.attr('name'), 'Tom'); + return Ember.RSVP.resolve({ id: id }); + } + }); + store = createStore({ + adapter: TestAdapter, + person: Person + }); + }, + teardown: function() { + run(function() { + if (store) { store.destroy(); } + }); + } +}); + +test("Using store#find with preload is deprecated", function() { + expect(2); + + expectDeprecation( + function() { + run(function() { + store.find('person', 1, { name: 'Tom' }); + }); + }, + /Passing a preload argument to `store.find` is deprecated./ + ); +}); + +test("Using store#fetchById with preload is deprecated", function() { + expect(2); + + expectDeprecation( + function() { + run(function() { + store.fetchById('person', 1, { name: 'Tom' }); + }); + }, + /Passing a preload argument to `store.fetchById` is deprecated./ + ); +}); + +test("Using store#findById with preload is deprecated", function() { + expect(2); + + expectDeprecation( + function() { + run(function() { + store.findById('person', 1, { name: 'Tom' }); + }); + }, + /Passing a preload argument to `store.findById` is deprecated/ + ); +}); From 885e28ef633d4827635de83e7ed51e631cb98f09 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 9 Jun 2015 09:24:19 -0500 Subject: [PATCH 0910/2527] beta 19.1 changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12b5806dca7..c46983ceaf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ### Master +### Release 1.0.0-beta.19.1 (June 9, 2015) + +- Fix a regression where a `DS.Model`'s `InternalModel` would not be set + on init - @bmac https://github.com/emberjs/data/pull/3262 + ### Release 1.0.0-beta.19 (June 5, 2015) #### Breaking Changes From 60c01a3f305b2b580c03b7f32712a43a2de30440 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 9 Jun 2015 09:29:06 -0500 Subject: [PATCH 0911/2527] add another changelog entry for beta.19.1 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c46983ceaf9..4c3f887ba0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - Fix a regression where a `DS.Model`'s `InternalModel` would not be set on init - @bmac https://github.com/emberjs/data/pull/3262 +- Pass store to inverseFor in removeEmbeddedForeignKey #3270 - @wecc + https://github.com/emberjs/data/pull/3270 ### Release 1.0.0-beta.19 (June 5, 2015) From bbbbb6310a235ecf3a704e5f88bdb8c0eac23087 Mon Sep 17 00:00:00 2001 From: "Joel A. Villarreal Bertoldi" Date: Tue, 9 Jun 2015 22:39:37 -0300 Subject: [PATCH 0912/2527] Deprecation if id is Model in deserializeRecordId --- packages/ember-data/lib/system/store.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index a1a58dc7786..4a4eb95efb4 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -2058,6 +2058,7 @@ function deserializeRecordId(store, data, key, relationship, id) { //If record objects were given to push directly, uncommon, not sure whether we should actually support if (id instanceof Model) { + Ember.deprecate("Passing a record object to push directly into the store has been deprecated. Pass a number or string as a value to represent the record."); data[key] = id._internalModel; return; } From 45662c52bca07d3f9277f489eb3938fb41621cb6 Mon Sep 17 00:00:00 2001 From: "Joel A. Villarreal Bertoldi" Date: Tue, 9 Jun 2015 22:57:41 -0300 Subject: [PATCH 0913/2527] Better deprecation message in deserializeRecordId --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 4a4eb95efb4..aa536ff460a 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -2058,7 +2058,7 @@ function deserializeRecordId(store, data, key, relationship, id) { //If record objects were given to push directly, uncommon, not sure whether we should actually support if (id instanceof Model) { - Ember.deprecate("Passing a record object to push directly into the store has been deprecated. Pass a number or string as a value to represent the record."); + Ember.deprecate("You tried to push a record '" + relationship.parentType + "'' with id '" + Ember.inspect(id) + "' and passed a DS.Model instance as a value for the relationship '" + key + "'. You should instead pass a numerical or string id to represent the record."); data[key] = id._internalModel; return; } From f6d6263b848866e0f86e87275b22f2f121917cfb Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Tue, 9 Jun 2015 23:34:58 -0400 Subject: [PATCH 0914/2527] Add test for deprecated find with preload --- .../tests/unit/store/adapter-interop-test.js | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index d6585e92867..2a3892b5444 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -827,6 +827,7 @@ module("unit/store/adapter_interop - find preload deprecations", { return Ember.RSVP.resolve({ id: id }); } }); + store = createStore({ adapter: TestAdapter, person: Person @@ -839,6 +840,28 @@ module("unit/store/adapter_interop - find preload deprecations", { } }); +test("store#find with deprecated preload passes correct options to store#findRecord", function() { + expect(2); + + var expectedOptions = { preload: { name: 'Tom' } }; + + store.reopen({ + findRecord: function(modelName, id, options) { + deepEqual(options, expectedOptions, + 'deprecated preload transformed to new options store#findRecord'); + } + }); + + expectDeprecation( + function() { + run(function() { + store.find('person', 1, { name: 'Tom' }); + }); + }, + /Passing a preload argument to `store.find` is deprecated./ + ); +}); + test("Using store#find with preload is deprecated", function() { expect(2); From 8021db7f0fa643dd683800d66fe84bbfe7641479 Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Thu, 4 Jun 2015 21:21:20 -0400 Subject: [PATCH 0915/2527] Rename & deprecate store.getById for store.peekRecord --- packages/ember-data/lib/system/store.js | 27 +++++- .../integration/adapter/rest-adapter-test.js | 90 +++++++++---------- .../non-dasherized-lookups.js | 4 +- .../tests/integration/filter-test.js | 4 +- .../tests/integration/records/unload-test.js | 2 +- .../serializers/rest-serializer-test.js | 9 +- .../unit/model/lifecycle-callbacks-test.js | 2 +- .../model/relationships/belongs-to-test.js | 2 +- .../unit/model/relationships/has-many-test.js | 6 +- .../tests/unit/store/adapter-interop-test.js | 2 +- .../tests/unit/store/get-by-id-test.js | 35 -------- .../tests/unit/store/peek-by-id-test.js | 46 ++++++++++ .../ember-data/tests/unit/store/push-test.js | 16 ++-- 13 files changed, 140 insertions(+), 105 deletions(-) delete mode 100644 packages/ember-data/tests/unit/store/get-by-id-test.js create mode 100644 packages/ember-data/tests/unit/store/peek-by-id-test.js diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 9ae07dd64aa..f14081beb5e 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -530,7 +530,7 @@ Store = Service.extend({ Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var options = deprecatePreload(preload, this.modelFor(modelName), 'fetchById'); if (this.hasRecordForId(modelName, id)) { - return this.getById(modelName, id).reload(); + return this.peekRecord(modelName, id).reload(); } else { return this.findRecord(modelName, id, options); } @@ -801,6 +801,31 @@ Store = Service.extend({ @return {DS.Model|null} record */ getById: function(modelName, id) { + Ember.deprecate('Using store.getById() has been deprecated. Use store.peekRecord to get a record by a given type and ID without triggering a fetch.'); + return this.peekRecord(modelName, id); + }, + + /** + Get a record by a given type and ID without triggering a fetch. + + This method will synchronously return the record if it is available in the store, + otherwise it will return `null`. A record is available if it has been fetched earlier, or + pushed manually into the store. + + _Note: This is an synchronous method and does not return a promise._ + + ```js + var post = store.peekRecord('post', 1); + + post.get('id'); // 1 + ``` + + @method peekRecord + @param {String} modelName + @param {String|Integer} id + @return {DS.Model|null} record + */ + peekRecord: function(modelName, id) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); if (this.hasRecordForId(modelName, id)) { return this._internalModelForId(modelName, id).getRecord(); diff --git a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js b/packages/ember-data/tests/integration/adapter/rest-adapter-test.js index b9810dbfce3..f80aa3978e4 100644 --- a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js +++ b/packages/ember-data/tests/integration/adapter/rest-adapter-test.js @@ -99,7 +99,7 @@ test("find - payload with sideloaded records of the same type", function() { equal(post.get('id'), "1"); equal(post.get('name'), "Rails is omakase"); - var post2 = store.getById('post', 2); + var post2 = store.peekRecord('post', 2); equal(post2.get('id'), "2"); equal(post2.get('name'), "The Parley Letter"); })); @@ -119,7 +119,7 @@ test("find - payload with sideloaded records of a different type", function() { equal(post.get('id'), "1"); equal(post.get('name'), "Rails is omakase"); - var comment = store.getById('comment', 1); + var comment = store.peekRecord('comment', 1); equal(comment.get('id'), "1"); equal(comment.get('name'), "FIRST"); })); @@ -246,7 +246,7 @@ test("create - findMany doesn't overwrite owner", function() { run(function() { store.push('post', { id: 1, name: "Rails is omakase", comments: [] }); }); - var post = store.getById('post', 1); + var post = store.peekRecord('post', 1); run(function() { comment = store.createRecord('comment', { name: "The Parley Letter" }); @@ -413,7 +413,7 @@ test("create - a record on the many side of a hasMany relationship should update store.push('comment', { id: 1, name: "Dat Parlay Letter", post: 1 }); }); - var post = store.getById('post', 1); + var post = store.peekRecord('post', 1); var commentCount = post.get('comments.length'); equal(commentCount, 1, "the post starts life with a comment"); @@ -448,8 +448,8 @@ test("create - sideloaded belongsTo relationships are both marked as loaded", fu run(function() { post.save().then(async(function(record) { - equal(store.getById('post', 1).get('comment.isLoaded'), true, "post's comment isLoaded (via store)"); - equal(store.getById('comment', 1).get('post.isLoaded'), true, "comment's post isLoaded (via store)"); + equal(store.peekRecord('post', 1).get('comment.isLoaded'), true, "post's comment isLoaded (via store)"); + equal(store.peekRecord('comment', 1).get('post.isLoaded'), true, "comment's post isLoaded (via store)"); equal(record.get('comment.isLoaded'), true, "post's comment isLoaded (via record)"); equal(record.get('comment.post.isLoaded'), true, "post's comment's post isLoaded (via record)"); })); @@ -618,7 +618,7 @@ test("update - a payload with sideloaded updates pushes the updates", function() equal(post.get('isDirty'), false, "the post isn't dirty anymore"); equal(post.get('name'), "Dat Parley Letter", "the post was updated"); - var comment = store.getById('comment', 1); + var comment = store.peekRecord('comment', 1); equal(comment.get('name'), "FIRST", "The comment was sideloaded"); })); }); @@ -645,7 +645,7 @@ test("update - a payload with sideloaded updates pushes the updates", function() equal(post.get('isDirty'), false, "the post isn't dirty anymore"); equal(post.get('name'), "Dat Parley Letter", "the post was updated"); - var comment = store.getById('comment', 1); + var comment = store.peekRecord('comment', 1); equal(comment.get('name'), "FIRST", "The comment was sideloaded"); })); }); @@ -689,7 +689,7 @@ test("update - hasMany relationships faithfully reflect simultaneous adds and re store.find('comment', 2).then(async(function() { return store.find('post', 1); })).then(async(function(post) { - var newComment = store.getById('comment', 2); + var newComment = store.peekRecord('comment', 2); var comments = post.get('comments'); // Replace the comment with a new one @@ -760,7 +760,7 @@ test("delete - a payload with sideloaded updates pushes the updates", function() equal(post.get('isDirty'), false, "the post isn't dirty anymore"); equal(post.get('isDeleted'), true, "the post is now deleted"); - var comment = store.getById('comment', 1); + var comment = store.peekRecord('comment', 1); equal(comment.get('name'), "FIRST", "The comment was sideloaded"); })); }); @@ -783,7 +783,7 @@ test("delete - a payload with sidloaded updates pushes the updates when the orig equal(post.get('isDirty'), false, "the original post isn't dirty anymore"); equal(post.get('isDeleted'), true, "the original post is now deleted"); - var newPost = store.getById('post', 2); + var newPost = store.peekRecord('post', 2); equal(newPost.get('name'), "The Parley Letter", "The new post was added to the store"); })); }); @@ -820,8 +820,8 @@ test("findAll - returning an array populates the array", function() { equal(passedVerb, "GET"); equal(passedHash.data, undefined); - var post1 = store.getById('post', 1); - var post2 = store.getById('post', 2); + var post1 = store.peekRecord('post', 1); + var post2 = store.peekRecord('post', 2); deepEqual( post1.getProperties('id', 'name'), @@ -872,7 +872,7 @@ test("findAll - returning sideloaded data loads the data", function() { comments: [{ id: 1, name: "FIRST" }] }); store.findAll('post').then(async(function(posts) { - var comment = store.getById('comment', 1); + var comment = store.peekRecord('comment', 1); deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); })); @@ -892,8 +892,8 @@ test("findAll - data is normalized through custom serializers", function() { }); store.findAll('post').then(async(function(posts) { - var post1 = store.getById('post', 1); - var post2 = store.getById('post', 2); + var post1 = store.peekRecord('post', 1); + var post2 = store.peekRecord('post', 2); deepEqual( post1.getProperties('id', 'name'), @@ -1078,8 +1078,8 @@ test("findQuery - returning an array populates the array", function() { equal(passedVerb, 'GET'); deepEqual(passedHash.data, { page: 1 }); - var post1 = store.getById('post', 1); - var post2 = store.getById('post', 2); + var post1 = store.peekRecord('post', 1); + var post2 = store.peekRecord('post', 2); deepEqual( post1.getProperties('id', 'name'), @@ -1112,7 +1112,7 @@ test("findQuery - returning sideloaded data loads the data", function() { }); store.query('post', { page: 1 }).then(async(function(posts) { - var comment = store.getById('comment', 1); + var comment = store.peekRecord('comment', 1); deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); })); @@ -1130,8 +1130,8 @@ test("findQuery - data is normalized through custom serializers", function() { }); store.query('post', { page: 1 }).then(async(function(posts) { - var post1 = store.getById('post', 1); - var post2 = store.getById('post', 2); + var post1 = store.peekRecord('post', 1); + var post2 = store.peekRecord('post', 2); deepEqual( post1.getProperties('id', 'name'), @@ -1163,7 +1163,7 @@ test("findMany - findMany uses a correct URL to access the records", function() store.push('post', { id: 1, name: "Rails is omakase", comments: [1, 2, 3] }); }); - var post = store.getById('post', 1); + var post = store.peekRecord('post', 1); ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1189,7 +1189,7 @@ test("findMany - passes buildURL the requestType", function() { store.push('post', { id: 1, name: "Rails is omakase", comments: [1, 2, 3] }); }); - var post = store.getById('post', 1); + var post = store.peekRecord('post', 1); ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1209,7 +1209,7 @@ test("findMany - findMany does not coalesce by default", function() { store.push('post', { id: 1, name: "Rails is omakase", comments: [1, 2, 3] }); }); - var post = store.getById('post', 1); + var post = store.peekRecord('post', 1); //It's still ok to return this even without coalescing because RESTSerializer supports sideloading ajaxResponse({ comments: [ @@ -1243,9 +1243,9 @@ test("findMany - returning an array populates the array", function() { return post.get('comments'); })).then(async(function(comments) { - var comment1 = store.getById('comment', 1); - var comment2 = store.getById('comment', 2); - var comment3 = store.getById('comment', 3); + var comment1 = store.peekRecord('comment', 1); + var comment2 = store.peekRecord('comment', 2); + var comment3 = store.peekRecord('comment', 3); deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); @@ -1280,11 +1280,11 @@ test("findMany - returning sideloaded data loads the data", function() { return post.get('comments'); })).then(async(function(comments) { - var comment1 = store.getById('comment', 1); - var comment2 = store.getById('comment', 2); - var comment3 = store.getById('comment', 3); - var comment4 = store.getById('comment', 4); - var post2 = store.getById('post', 2); + var comment1 = store.peekRecord('comment', 1); + var comment2 = store.peekRecord('comment', 2); + var comment3 = store.peekRecord('comment', 3); + var comment4 = store.peekRecord('comment', 4); + var post2 = store.peekRecord('post', 2); deepEqual( comments.toArray(), @@ -1325,9 +1325,9 @@ test("findMany - a custom serializer is used if present", function() { return post.get('comments'); })).then(async(function(comments) { - var comment1 = store.getById('comment', 1); - var comment2 = store.getById('comment', 2); - var comment3 = store.getById('comment', 3); + var comment1 = store.peekRecord('comment', 1); + var comment2 = store.peekRecord('comment', 2); + var comment3 = store.peekRecord('comment', 3); deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); @@ -1366,9 +1366,9 @@ test("findHasMany - returning an array populates the array", function() { equal(passedVerb, 'GET'); equal(passedHash, undefined); - var comment1 = store.getById('comment', 1); - var comment2 = store.getById('comment', 2); - var comment3 = store.getById('comment', 3); + var comment1 = store.peekRecord('comment', 1); + var comment2 = store.peekRecord('comment', 2); + var comment3 = store.peekRecord('comment', 3); deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); @@ -1440,10 +1440,10 @@ test("findMany - returning sideloaded data loads the data", function() { return post.get('comments'); })).then(async(function(comments) { - var comment1 = store.getById('comment', 1); - var comment2 = store.getById('comment', 2); - var comment3 = store.getById('comment', 3); - var post2 = store.getById('post', 2); + var comment1 = store.peekRecord('comment', 1); + var comment2 = store.peekRecord('comment', 2); + var comment3 = store.peekRecord('comment', 3); + var post2 = store.peekRecord('post', 2); deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); @@ -1485,9 +1485,9 @@ test("findMany - a custom serializer is used if present", function() { }); return post.get('comments'); })).then(async(function(comments) { - var comment1 = store.getById('comment', 1); - var comment2 = store.getById('comment', 2); - var comment3 = store.getById('comment', 3); + var comment1 = store.peekRecord('comment', 1); + var comment2 = store.peekRecord('comment', 2); + var comment3 = store.peekRecord('comment', 3); deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); diff --git a/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js b/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js index e72eacff39c..e026bea16d5 100644 --- a/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js +++ b/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js @@ -92,7 +92,7 @@ test('looks up using camelCase string', function() { run(function() { store.find('postNote', 1).then(function(postNote) { - equal(postNote.get('notePost'), store.getById('notePost', 1)); + equal(postNote.get('notePost'), store.peekRecord('notePost', 1)); }); }); }); @@ -114,7 +114,7 @@ test('looks up using under_score string', function() { run(function() { store.find('long_model_name', 1).then(function(longModelName) { - deepEqual(longModelName.get('postNotes').toArray(), [store.getById('postNote', 1)]); + deepEqual(longModelName.get('postNotes').toArray(), [store.peekRecord('postNote', 1)]); }); }); diff --git a/packages/ember-data/tests/integration/filter-test.js b/packages/ember-data/tests/integration/filter-test.js index 9d6503a4f6b..3102b0593be 100644 --- a/packages/ember-data/tests/integration/filter-test.js +++ b/packages/ember-data/tests/integration/filter-test.js @@ -109,8 +109,8 @@ test("when a DS.Model updates its relationships, its changes affect its filtered equal(get(people, 'length'), 0, "there are now 0 items"); - var erik = store.getById('person', 3); - var yehuda = store.getById('person', 2); + var erik = store.peekRecord('person', 3); + var yehuda = store.peekRecord('person', 2); run(function() { erik.set('bestFriend', yehuda); }); diff --git a/packages/ember-data/tests/integration/records/unload-test.js b/packages/ember-data/tests/integration/records/unload-test.js index 0e5008cfb39..2095819e0c9 100644 --- a/packages/ember-data/tests/integration/records/unload-test.js +++ b/packages/ember-data/tests/integration/records/unload-test.js @@ -204,7 +204,7 @@ test("unloading a record also clears the implicit inverse relationships", functi run(function() { env.store.find('group', 1).then(function(group) { equal(group.get('people.length'), 1, 'The inital length of people is correct'); - var person = env.store.getById('person', 1); + var person = env.store.peekRecord('person', 1); run(function() { person.unloadRecord(); }); diff --git a/packages/ember-data/tests/integration/serializers/rest-serializer-test.js b/packages/ember-data/tests/integration/serializers/rest-serializer-test.js index 9dc79a01c6f..0870b6514ae 100644 --- a/packages/ember-data/tests/integration/serializers/rest-serializer-test.js +++ b/packages/ember-data/tests/integration/serializers/rest-serializer-test.js @@ -188,9 +188,8 @@ if (!Ember.FEATURES.isEnabled('ds-new-serializer-api')) { }); }, /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); - // assert non-warned records get pushed into store correctly - var superVillain = env.store.getById('super-villain', "1"); + var superVillain = env.store.peekRecord('super-villain', "1"); equal(get(superVillain, "firstName"), "Stanley"); // Serializers are singletons, so that"s why we use the store which @@ -210,7 +209,7 @@ if (!Ember.FEATURES.isEnabled('ds-new-serializer-api')) { noWarns(function() { run(function() { env.store.pushPayload('home-planet', jsonHash); - homePlanet = env.store.getById('home-planet', "1"); + homePlanet = env.store.peekRecord('home-planet', "1"); }); }); @@ -247,7 +246,7 @@ if (!Ember.FEATURES.isEnabled('ds-new-serializer-api')) { }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); // assert non-warned records get pushed into store correctly - var superVillain = env.store.getById('super-villain', "1"); + var superVillain = env.store.peekRecord('super-villain', "1"); equal(get(superVillain, "firstName"), "Stanley"); // Serializers are singletons, so that"s why we use the store which @@ -267,7 +266,7 @@ if (!Ember.FEATURES.isEnabled('ds-new-serializer-api')) { noWarns(function() { run(function() { env.store.pushPayload('home-planet', jsonHash); - homePlanet = env.store.getById('home-planet', "1"); + homePlanet = env.store.peekRecord('home-planet', "1"); }); }); diff --git a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js index accac509a36..b1b6ab1be88 100644 --- a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js +++ b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js @@ -51,7 +51,7 @@ test("TEMPORARY: a record receives a didLoad callback once it materializes if it equal(didLoadCalled, 0, "didLoad was not called"); }); run(function() { - store.getById('person', 1); + store.peekRecord('person', 1); }); run(function() { equal(didLoadCalled, 1, "didLoad was called"); diff --git a/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js b/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js index 65e5cdc2c44..463a987fd27 100644 --- a/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js @@ -214,7 +214,7 @@ test("When finding a belongsTo relationship the inverse belongsTo relationship i }); run(function() { - store.getById('person', 1).get('occupation'); + store.peekRecord('person', 1).get('occupation'); }); }); diff --git a/packages/ember-data/tests/unit/model/relationships/has-many-test.js b/packages/ember-data/tests/unit/model/relationships/has-many-test.js index beb12f47d68..be32afe7331 100644 --- a/packages/ember-data/tests/unit/model/relationships/has-many-test.js +++ b/packages/ember-data/tests/unit/model/relationships/has-many-test.js @@ -374,15 +374,15 @@ test("possible to replace items in a relationship using setObjects w/ Ember Enum var tom, sylvain; run(function() { - tom = store.getById('person', '1'); - sylvain = store.getById('person', '2'); + tom = store.peekRecord('person', '1'); + sylvain = store.peekRecord('person', '2'); // Test that since sylvain.get('tags') instanceof DS.ManyArray, // addRecords on Relationship iterates correctly. tom.get('tags').setObjects(sylvain.get('tags')); }); equal(tom.get('tags.length'), 1); - equal(tom.get('tags.firstObject'), store.getById('tag', 2)); + equal(tom.get('tags.firstObject'), store.peekRecord('tag', 2)); }); test("it is possible to remove an item from a relationship", function() { diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index 2a3892b5444..cdf7d17c8d5 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -446,7 +446,7 @@ test("initial values of belongsTo can be passed in as the third argument to find run(function() { store.find('person', 1, { preload: { friend: 2 } }).then(async(function() { - store.getById('person', 1).get('friend').then(async(function(friend) { + store.peekRecord('person', 1).get('friend').then(async(function(friend) { equal(friend.get('id'), '2', 'Preloaded belongsTo set'); })); })); diff --git a/packages/ember-data/tests/unit/store/get-by-id-test.js b/packages/ember-data/tests/unit/store/get-by-id-test.js deleted file mode 100644 index 440101867a8..00000000000 --- a/packages/ember-data/tests/unit/store/get-by-id-test.js +++ /dev/null @@ -1,35 +0,0 @@ -var env, store, Person; -var run = Ember.run; - -module("unit/store/getById - Store getById", { - setup: function() { - - Person = DS.Model.extend(); - Person.toString = function() { - return 'Person'; - }; - - env = setupStore({ - person: Person - }); - store = env.store; - }, - - teardown: function() { - Ember.run(store, 'destroy'); - } -}); - -test("getById should return the record if it is in the store ", function() { - - run(function() { - var person = store.push('person', { id: 1 }); - equal(person, store.getById('person', 1), 'getById only return the corresponding record in the store'); - }); -}); - -test("getById should return null if the record is not in the store ", function() { - run(function() { - equal(null, store.getById('person', 1), 'getById returns null if the corresponding record is not in the store'); - }); -}); diff --git a/packages/ember-data/tests/unit/store/peek-by-id-test.js b/packages/ember-data/tests/unit/store/peek-by-id-test.js new file mode 100644 index 00000000000..ad8d8db3122 --- /dev/null +++ b/packages/ember-data/tests/unit/store/peek-by-id-test.js @@ -0,0 +1,46 @@ +var env, store, Person; +var run = Ember.run; + +module("unit/store/peekRecord - Store peekRecord", { + setup: function() { + + Person = DS.Model.extend(); + Person.toString = function() { + return 'Person'; + }; + + env = setupStore({ + person: Person + }); + store = env.store; + }, + + teardown: function() { + Ember.run(store, 'destroy'); + } +}); + +test("peekRecord should return the record if it is in the store ", function() { + run(function() { + var person = store.push('person', { id: 1 }); + equal(person, store.peekRecord('person', 1), 'peekRecord only return the corresponding record in the store'); + }); +}); + +test("peekRecord should return null if the record is not in the store ", function() { + run(function() { + equal(null, store.peekRecord('person', 1), 'peekRecord returns null if the corresponding record is not in the store'); + }); +}); + +test("getById is deprecated", function() { + expectDeprecation( + function() { + run(function() { + store.push('person', { id: 1 }); + store.getById('person', 1); + }); + }, + 'Using store.getById() has been deprecated. Use store.peekRecord to get a record by a given type and ID without triggering a fetch.' + ); +}); diff --git a/packages/ember-data/tests/unit/store/push-test.js b/packages/ember-data/tests/unit/store/push-test.js index f1a30aa2469..e4f9bcf5387 100644 --- a/packages/ember-data/tests/unit/store/push-test.js +++ b/packages/ember-data/tests/unit/store/push-test.js @@ -250,7 +250,7 @@ test("Calling pushPayload allows pushing raw JSON", function () { }); }); - var post = store.getById('post', 1); + var post = store.peekRecord('post', 1); equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); @@ -276,7 +276,7 @@ test("Calling pushPayload allows pushing singular payload properties", function }); }); - var post = store.getById('post', 1); + var post = store.peekRecord('post', 1); equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); @@ -320,11 +320,11 @@ test("Calling pushPayload should use the type's serializer for normalizing", fun }); }); - var post = store.getById('post', 1); + var post = store.peekRecord('post', 1); equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); - var person = store.getById('person', 2); + var person = store.peekRecord('person', 2); equal(person.get('firstName'), "Yehuda", "you can push raw JSON into the store"); }); @@ -376,11 +376,11 @@ test("Calling pushPayload without a type should use a model's serializer when no }); }); - var post = store.getById('post', 1); + var post = store.peekRecord('post', 1); equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); - var person = store.getById('person', 2); + var person = store.peekRecord('person', 2); equal(person.get('firstName'), "Yehuda", "you can push raw JSON into the store"); }); @@ -400,7 +400,7 @@ test("Calling pushPayload allows partial updates with raw JSON", function () { }); }); - person = store.getById('person', 1); + person = store.peekRecord('person', 1); equal(person.get('firstName'), "Robert", "you can push raw JSON into the store"); equal(person.get('lastName'), "Jackson", "you can push raw JSON into the store"); @@ -487,7 +487,7 @@ test('Calling push with a link containing the value null', function() { }); }); - var person = store.getById('person', 1); + var person = store.peekRecord('person', 1); equal(person.get('firstName'), "Tan", "you can use links that contain null as a value"); }); From 3f9b4b6c858a38139daa25c818e3d1f101bd3446 Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Thu, 4 Jun 2015 22:20:48 -0400 Subject: [PATCH 0916/2527] Rename & deprecate store.all for store.peekAll --- .../lib/system/debug/debug-adapter.js | 2 +- .../record-arrays/filtered-record-array.js | 2 +- .../lib/system/record-arrays/record-array.js | 8 +-- packages/ember-data/lib/system/store.js | 32 ++++++++- .../ember-data/lib/system/store/finders.js | 2 +- .../integration/adapter/find-all-test.js | 4 +- .../ember-data/tests/integration/all-test.js | 55 ---------------- .../tests/integration/peek-all-test.js | 66 +++++++++++++++++++ .../integration/record-array-manager-test.js | 4 +- .../records/collection-save-test.js | 8 +-- .../integration/records/delete-record-test.js | 4 +- .../tests/integration/records/unload-test.js | 18 ++--- .../relationships/has-many-test.js | 2 +- .../tests/integration/store-test.js | 8 +-- .../unit/model/lifecycle-callbacks-test.js | 2 +- .../tests/unit/model/rollback-test.js | 4 +- .../tests/unit/record-array-test.js | 12 ++-- .../tests/unit/store/adapter-interop-test.js | 8 +-- 18 files changed, 140 insertions(+), 101 deletions(-) delete mode 100644 packages/ember-data/tests/integration/all-test.js create mode 100644 packages/ember-data/tests/integration/peek-all-test.js diff --git a/packages/ember-data/lib/system/debug/debug-adapter.js b/packages/ember-data/lib/system/debug/debug-adapter.js index ee2ed753f23..ae5e01a022a 100644 --- a/packages/ember-data/lib/system/debug/debug-adapter.js +++ b/packages/ember-data/lib/system/debug/debug-adapter.js @@ -55,7 +55,7 @@ export default Ember.DataAdapter.extend({ } } assert("Cannot find model name. Please upgrade to Ember.js >= 1.13 for Ember Inspector support", !!modelName); - return this.get('store').all(modelName); + return this.get('store').peekAll(modelName); }, getRecordColumnValues: function(record) { diff --git a/packages/ember-data/lib/system/record-arrays/filtered-record-array.js b/packages/ember-data/lib/system/record-arrays/filtered-record-array.js index b03841d4731..9344294c2a7 100644 --- a/packages/ember-data/lib/system/record-arrays/filtered-record-array.js +++ b/packages/ember-data/lib/system/record-arrays/filtered-record-array.js @@ -24,7 +24,7 @@ export default RecordArray.extend({ Example ```javascript - var allPeople = store.all('person'); + var allPeople = store.peekAll('person'); allPeople.mapBy('name'); // ["Tom Dale", "Yehuda Katz", "Trek Glowacki"] var people = store.filter('person', function(person) { diff --git a/packages/ember-data/lib/system/record-arrays/record-array.js b/packages/ember-data/lib/system/record-arrays/record-array.js index 1ffbdde67e5..0a16d65f1ca 100644 --- a/packages/ember-data/lib/system/record-arrays/record-array.js +++ b/packages/ember-data/lib/system/record-arrays/record-array.js @@ -46,7 +46,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { Example ```javascript - var people = store.all('person'); + var people = store.peekAll('person'); people.get('isLoaded'); // true ``` @@ -60,7 +60,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { Example ```javascript - var people = store.all('person'); + var people = store.peekAll('person'); people.get('isUpdating'); // false people.update(); people.get('isUpdating'); // true @@ -101,7 +101,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { Example ```javascript - var people = store.all('person'); + var people = store.peekAll('person'); people.get('isUpdating'); // false people.update(); people.get('isUpdating'); // true @@ -152,7 +152,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { Example ```javascript - var messages = store.all('message'); + var messages = store.peekAll('message'); messages.forEach(function(message) { message.set('hasBeenSeen', true); }); diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index f14081beb5e..4fef2f0f077 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -203,7 +203,7 @@ if (!Service) { Note: When creating a new record using any of the above methods Ember Data will update `DS.RecordArray`s such as those returned by - `store#all()`, `store#findAll()` or `store#filter()`. This means any + `store#peekAll()`, `store#findAll()` or `store#filter()`. This means any data bindings or computed properties that depend on the RecordArray will automatically be synced to include the new or updated record values. @@ -1049,7 +1049,7 @@ Store = Service.extend({ Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); - return this._fetchAll(typeClass, this.all(modelName)); + return this._fetchAll(typeClass, this.peekAll(modelName)); }, /** @@ -1105,6 +1105,34 @@ Store = Service.extend({ @return {DS.RecordArray} */ all: function(modelName) { + Ember.deprecate('Using store.all() has been deprecated. Use store.peekAll() to get all records by a given type without triggering a fetch.'); + return this.peekAll(modelName); + }, + + /** + This method returns a filtered array that contains all of the + known records for a given type in the store. + + Note that because it's just a filter, the result will contain any + locally created records of the type, however, it will not make a + request to the backend to retrieve additional records. If you + would like to request all the records from the backend please use + [store.find](#method_find). + + Also note that multiple calls to `peekAll` for a given type will always + return the same `RecordArray`. + + Example + + ```javascript + var localPosts = store.peekAll('post'); + ``` + + @method peekAll + @param {String} modelName + @return {DS.RecordArray} + */ + peekAll: function(modelName) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index ed43cb7643a..2d156f476b4 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -135,7 +135,7 @@ export function _findAll(adapter, store, typeClass, sinceToken) { }); store.didUpdateAll(typeClass); - return store.all(modelName); + return store.peekAll(modelName); }, null, "DS: Extract payload of findAll " + typeClass); } diff --git a/packages/ember-data/tests/integration/adapter/find-all-test.js b/packages/ember-data/tests/integration/adapter/find-all-test.js index 846dcc58cd9..958b11860f1 100644 --- a/packages/ember-data/tests/integration/adapter/find-all-test.js +++ b/packages/ember-data/tests/integration/adapter/find-all-test.js @@ -103,7 +103,7 @@ test("When all records for a type are requested, records that are already loaded store.createRecord('person', { name: "Alex MacCaw" }); }); - allRecords = store.all('person'); + allRecords = store.peekAll('person'); equal(get(allRecords, 'length'), 2, "the record array's length is 2"); equal(allRecords.objectAt(0).get('name'), "Jeremy Ashkenas", "the first item in the record array is Jeremy Ashkenas"); @@ -118,7 +118,7 @@ test("When all records for a type are requested, records that are created on the person: Person }); - allRecords = store.all('person'); + allRecords = store.peekAll('person'); equal(get(allRecords, 'length'), 0, "precond - the record array's length is zero before any records are loaded"); diff --git a/packages/ember-data/tests/integration/all-test.js b/packages/ember-data/tests/integration/all-test.js deleted file mode 100644 index 31dbdc9207a..00000000000 --- a/packages/ember-data/tests/integration/all-test.js +++ /dev/null @@ -1,55 +0,0 @@ -var get = Ember.get; -var run = Ember.run; - -var Person, store, array, moreArray; - -module("integration/all - DS.Store#all()", { - setup: function() { - array = [{ id: 1, name: "Scumbag Dale" }, { id: 2, name: "Scumbag Katz" }]; - moreArray = [{ id: 3, name: "Scumbag Bryn" }]; - Person = DS.Model.extend({ name: DS.attr('string') }); - - store = createStore({ person: Person }); - }, - teardown: function() { - run(store, 'destroy'); - Person = null; - array = null; - } -}); - -test("store.all('person') should return all records and should update with new ones", function() { - run(function() { - store.pushMany('person', array); - }); - - var all = store.all('person'); - equal(get(all, 'length'), 2); - - run(function() { - store.pushMany('person', moreArray); - }); - - equal(get(all, 'length'), 3); -}); - -test("Calling store.all() multiple times should update immediately inside the runloop", function() { - expect(3); - - Ember.run(function() { - equal(get(store.all('person'), 'length'), 0, 'should initially be empty'); - store.createRecord('person', { name: "Tomster" }); - equal(get(store.all('person'), 'length'), 1, 'should contain one person'); - store.push('person', { id: 1, name: "Tomster's friend" }); - equal(get(store.all('person'), 'length'), 2, 'should contain two people'); - }); -}); - -test("Calling store.all() after creating a record should return correct data", function() { - expect(1); - - Ember.run(function() { - store.createRecord('person', { name: "Tomster" }); - equal(get(store.all('person'), 'length'), 1, 'should contain one person'); - }); -}); diff --git a/packages/ember-data/tests/integration/peek-all-test.js b/packages/ember-data/tests/integration/peek-all-test.js new file mode 100644 index 00000000000..51788dc7df5 --- /dev/null +++ b/packages/ember-data/tests/integration/peek-all-test.js @@ -0,0 +1,66 @@ +var get = Ember.get; +var run = Ember.run; + +var Person, store, array, moreArray; + +module("integration/peek_all - DS.Store#peekAll()", { + setup: function() { + array = [{ id: 1, name: "Scumbag Dale" }, { id: 2, name: "Scumbag Katz" }]; + moreArray = [{ id: 3, name: "Scumbag Bryn" }]; + Person = DS.Model.extend({ name: DS.attr('string') }); + + store = createStore({ person: Person }); + }, + teardown: function() { + run(store, 'destroy'); + Person = null; + array = null; + } +}); + +test("store.peekAll('person') should return all records and should update with new ones", function() { + run(function() { + store.pushMany('person', array); + }); + + var all = store.peekAll('person'); + equal(get(all, 'length'), 2); + + run(function() { + store.pushMany('person', moreArray); + }); + + equal(get(all, 'length'), 3); +}); + +test("Calling store.peekAll() multiple times should update immediately inside the runloop", function() { + expect(3); + + Ember.run(function() { + equal(get(store.peekAll('person'), 'length'), 0, 'should initially be empty'); + store.createRecord('person', { name: "Tomster" }); + equal(get(store.peekAll('person'), 'length'), 1, 'should contain one person'); + store.push('person', { id: 1, name: "Tomster's friend" }); + equal(get(store.peekAll('person'), 'length'), 2, 'should contain two people'); + }); +}); + +test("Calling store.peekAll() after creating a record should return correct data", function() { + expect(1); + + Ember.run(function() { + store.createRecord('person', { name: "Tomster" }); + equal(get(store.peekAll('person'), 'length'), 1, 'should contain one person'); + }); +}); + +test("store.all() is deprecated", function() { + expectDeprecation( + function() { + run(function() { + store.all('person'); + }); + }, + 'Using store.all() has been deprecated. Use store.peekAll() to get all records by a given type without triggering a fetch.' + ); +}); diff --git a/packages/ember-data/tests/integration/record-array-manager-test.js b/packages/ember-data/tests/integration/record-array-manager-test.js index 66d6d80f619..9893609404a 100644 --- a/packages/ember-data/tests/integration/record-array-manager-test.js +++ b/packages/ember-data/tests/integration/record-array-manager-test.js @@ -105,13 +105,13 @@ test("destroying the store correctly cleans everything up", function() { equal(adapterPopulatedSummary.called.length, 1); }); -test("Should not filter a store.all() array when a record property is changed", function() { +test("Should not filter a store.peekAll() array when a record property is changed", function() { var car; var populateLiveRecordArray = tap(store.recordArrayManager, 'populateLiveRecordArray'); var updateFilterRecordArray = tap(store.recordArrayManager, 'updateFilterRecordArray'); - store.all('car'); + store.peekAll('car'); run(function() { car = store.push('car', { diff --git a/packages/ember-data/tests/integration/records/collection-save-test.js b/packages/ember-data/tests/integration/records/collection-save-test.js index e64f38091fc..a18282c3508 100644 --- a/packages/ember-data/tests/integration/records/collection-save-test.js +++ b/packages/ember-data/tests/integration/records/collection-save-test.js @@ -24,7 +24,7 @@ test("Collection will resolve save on success", function() { env.store.createRecord('post', { title: 'World' }); }); - var posts = env.store.all('post'); + var posts = env.store.peekAll('post'); env.adapter.createRecord = function(store, type, snapshot) { return Ember.RSVP.resolve({ id: 123 }); @@ -43,7 +43,7 @@ test("Collection will reject save on error", function() { env.store.createRecord('post', { title: 'World' }); }); - var posts = env.store.all('post'); + var posts = env.store.peekAll('post'); env.adapter.createRecord = function(store, type, snapshot) { return Ember.RSVP.reject(); @@ -62,7 +62,7 @@ test("Retry is allowed in a failure handler", function() { env.store.createRecord('post', { title: 'World' }); }); - var posts = env.store.all('post'); + var posts = env.store.peekAll('post'); var count = 0; @@ -94,7 +94,7 @@ test("Collection will reject save on invalid", function() { env.store.createRecord('post', { title: 'World' }); }); - var posts = env.store.all('post'); + var posts = env.store.peekAll('post'); env.adapter.createRecord = function(store, type, snapshot) { return Ember.RSVP.reject({ title: 'invalid' }); diff --git a/packages/ember-data/tests/integration/records/delete-record-test.js b/packages/ember-data/tests/integration/records/delete-record-test.js index ad31e24beb6..66bf4cd4434 100644 --- a/packages/ember-data/tests/integration/records/delete-record-test.js +++ b/packages/ember-data/tests/integration/records/delete-record-test.js @@ -28,7 +28,7 @@ test("records can be deleted during record array enumeration", function () { adam = env.store.push('person', { id: 1, name: "Adam Sunderland" }); dave = env.store.push('person', { id: 2, name: "Dave Sunderland" }); }); - var all = env.store.all('person'); + var all = env.store.peekAll('person'); // pre-condition equal(all.get('length'), 2, 'expected 2 records'); @@ -49,7 +49,7 @@ test("when deleted records are rolled back, they are still in their previous rec jaime = env.store.push('person', { id: 1, name: "Jaime Lannister" }); cersei = env.store.push('person', { id: 2, name: "Cersei Lannister" }); }); - var all = env.store.all('person'); + var all = env.store.peekAll('person'); var filtered; run(function() { filtered = env.store.filter('person', function () { diff --git a/packages/ember-data/tests/integration/records/unload-test.js b/packages/ember-data/tests/integration/records/unload-test.js index 2095819e0c9..e7b1de0f238 100644 --- a/packages/ember-data/tests/integration/records/unload-test.js +++ b/packages/ember-data/tests/integration/records/unload-test.js @@ -51,7 +51,7 @@ test("can unload a single record", function () { adam.unloadRecord(); }); - equal(env.store.all('person').get('length'), 0); + equal(env.store.peekAll('person').get('length'), 0); }); test("can unload all records for a given type", function () { @@ -74,8 +74,8 @@ test("can unload all records for a given type", function () { env.store.unloadAll('person'); }); - equal(env.store.all('person').get('length'), 0); - equal(env.store.all('car').get('length'), 1); + equal(env.store.peekAll('person').get('length'), 0); + equal(env.store.peekAll('car').get('length'), 1); }); test("can unload all records", function () { @@ -98,8 +98,8 @@ test("can unload all records", function () { env.store.unloadAll(); }); - equal(env.store.all('person').get('length'), 0); - equal(env.store.all('car').get('length'), 0); + equal(env.store.peekAll('person').get('length'), 0); + equal(env.store.peekAll('car').get('length'), 0); }); test("Unloading all records for a given type clears saved meta data.", function () { @@ -128,20 +128,20 @@ test("removes findAllCache after unloading all records", function () { }); Ember.run(function() { - env.store.all('person'); + env.store.peekAll('person'); env.store.unloadAll('person'); }); - equal(env.store.all('person').get('length'), 0); + equal(env.store.peekAll('person').get('length'), 0); }); -test("unloading all records also updates record array from all()", function() { +test("unloading all records also updates record array from peekAll()", function() { var adam, bob; run(function() { adam = env.store.push('person', { id: 1, name: "Adam Sunderland" }); bob = env.store.push('person', { id: 2, name: "Bob Bobson" }); }); - var all = env.store.all('person'); + var all = env.store.peekAll('person'); equal(all.get('length'), 2); diff --git a/packages/ember-data/tests/integration/relationships/has-many-test.js b/packages/ember-data/tests/integration/relationships/has-many-test.js index f9cf9b97c70..2339ed9a438 100644 --- a/packages/ember-data/tests/integration/relationships/has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/has-many-test.js @@ -1219,7 +1219,7 @@ test("Relationship.clear removes all records correctly", function() { run(function() { post._internalModel._relationships.get('comments').clear(); - var comments = Ember.A(env.store.all('comment')); + var comments = Ember.A(env.store.peekAll('comment')); deepEqual(comments.mapBy('post'), [null, null, null]); }); diff --git a/packages/ember-data/tests/integration/store-test.js b/packages/ember-data/tests/integration/store-test.js index 53c2d6623b3..2977ad108d2 100644 --- a/packages/ember-data/tests/integration/store-test.js +++ b/packages/ember-data/tests/integration/store-test.js @@ -324,7 +324,7 @@ test("Using store#findAll with no records triggers a query", function() { }] }); - var cars = store.all('car'); + var cars = store.peekAll('car'); ok(!cars.get('length'), 'There is no cars in the store'); run(function() { @@ -358,7 +358,7 @@ test("Using store#findAll with existing records performs a query, updating exist }] }); - var cars = store.all('car'); + var cars = store.peekAll('car'); equal(cars.get('length'), 1, 'There is one car in the store'); run(function() { @@ -386,7 +386,7 @@ test("store#findAll should return all known records even if they are not in the }] }); - var cars = store.all('car'); + var cars = store.peekAll('car'); equal(cars.get('length'), 2, 'There is two cars in the store'); run(function() { @@ -395,7 +395,7 @@ test("store#findAll should return all known records even if they are not in the var mini = cars.findBy('id', '1'); equal(mini.get('model'), 'New Mini', 'Existing records have been updated'); - var carsInStore = store.all('car'); + var carsInStore = store.peekAll('car'); equal(carsInStore.get('length'), 2, 'There is 2 cars in the store'); }); }); diff --git a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js index b1b6ab1be88..b8c3f08ab30 100644 --- a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js +++ b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js @@ -306,5 +306,5 @@ test("an ID of 0 is allowed", function() { store.push('person', { id: 0, name: "Tom Dale" }); }); - equal(store.all('person').objectAt(0).get('name'), "Tom Dale", "found record with id 0"); + equal(store.peekAll('person').objectAt(0).get('name'), "Tom Dale", "found record with id 0"); }); diff --git a/packages/ember-data/tests/unit/model/rollback-test.js b/packages/ember-data/tests/unit/model/rollback-test.js index 6db9b6eb832..0095245e347 100644 --- a/packages/ember-data/tests/unit/model/rollback-test.js +++ b/packages/ember-data/tests/unit/model/rollback-test.js @@ -118,7 +118,7 @@ test("a deleted record can be rollbacked if it fails to save, record arrays are run(function() { person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); - people = store.all('person'); + people = store.peekAll('person'); }); run(function() { @@ -209,7 +209,7 @@ test("deleted record can be rollbacked", function() { run(function() { person = store.push('person', { id: 1 }); - people = store.all('person'); + people = store.peekAll('person'); person.deleteRecord(); }); diff --git a/packages/ember-data/tests/unit/record-array-test.js b/packages/ember-data/tests/unit/record-array-test.js index fdd61e72d6c..05f3fe5c1de 100644 --- a/packages/ember-data/tests/unit/record-array-test.js +++ b/packages/ember-data/tests/unit/record-array-test.js @@ -37,7 +37,7 @@ test("acts as a live query", function() { var store = createStore({ person: Person }); - var recordArray = store.all('person'); + var recordArray = store.peekAll('person'); run(function() { store.push('person', { id: 1, name: 'wycats' }); }); @@ -60,7 +60,7 @@ test("stops updating when destroyed", function() { // is on the release branch var emptyLength = Ember.meta(store).descs ? undefined : 0; - var recordArray = store.all('person'); + var recordArray = store.peekAll('person'); run(function() { store.push('person', { id: 1, name: 'wycats' }); }); @@ -188,7 +188,7 @@ test("a newly created record is removed from a record array when it is deleted", var store = createStore({ person: Person }); - var recordArray = store.all('person'); + var recordArray = store.peekAll('person'); var scumbag; run(function() { @@ -231,7 +231,7 @@ test("a record array returns undefined when asking for a member outside of its c store.pushMany('person', array); }); - var recordArray = store.all('person'); + var recordArray = store.peekAll('person'); strictEqual(recordArray.objectAt(20), undefined, "objects outside of the range just return undefined"); }); @@ -245,7 +245,7 @@ test("a record array should be able to be enumerated in any order", function() { store.pushMany('person', array); }); - var recordArray = store.all('person'); + var recordArray = store.peekAll('person'); equal(get(recordArray.objectAt(2), 'id'), 3, "should retrieve correct record at index 2"); equal(get(recordArray.objectAt(1), 'id'), 2, "should retrieve correct record at index 1"); @@ -278,7 +278,7 @@ test("a record array should return a promise when updating", function() { return Ember.RSVP.resolve(array); }; - recordArray = store.all('person'); + recordArray = store.peekAll('person'); run(function() { promise = recordArray.update(); }); diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index cdf7d17c8d5..244befa8091 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -255,7 +255,7 @@ test("Find with query calls the correct extract", function() { equal(callCount, 1, 'extractFindQuery was called'); }); -test("all(type) returns a record array of all records of a specific type", function() { +test("peekAll(type) returns a record array of all records of a specific type", function() { var Person = DS.Model.extend({ name: DS.attr('string') }); @@ -268,7 +268,7 @@ test("all(type) returns a record array of all records of a specific type", funct store.push('person', { id: 1, name: "Tom Dale" }); }); - var results = store.all('person'); + var results = store.peekAll('person'); equal(get(results, 'length'), 1, "record array should have the original object"); equal(get(results.objectAt(0), 'name'), "Tom Dale", "record has the correct information"); @@ -278,7 +278,7 @@ test("all(type) returns a record array of all records of a specific type", funct equal(get(results, 'length'), 2, "record array should have the new object"); equal(get(results.objectAt(1), 'name'), "Yehuda Katz", "record has the correct information"); - strictEqual(results, store.all('person'), "subsequent calls to all return the same recordArray)"); + strictEqual(results, store.peekAll('person'), "subsequent calls to peekAll return the same recordArray)"); }); test("a new record of a particular type is created via store.createRecord(type)", function() { @@ -527,7 +527,7 @@ test("records should have their ids updated when the adapter returns the id data person: Person }); - var people = store.all('person'); + var people = store.peekAll('person'); var tom, yehuda; run(function() { From db82aebda4ff6803dfb9bb197d32210f32a471ba Mon Sep 17 00:00:00 2001 From: Sylvain MINA Date: Fri, 5 Jun 2015 15:34:09 +0200 Subject: [PATCH 0917/2527] serialize:true takes priority over the OneToMany check for relationships --- .../lib/serializers/json-serializer.js | 46 +++++++++-- .../serializers/json-serializer-test.js | 80 +++++++++++++++++++ 2 files changed, 118 insertions(+), 8 deletions(-) diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index 4d7020c6bc1..ae5f3d7d29b 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -758,6 +758,41 @@ export default Serializer.extend({ return !attrs || !attrs[key] || attrs[key].serialize !== false; }, + /** + When attrs.key.serialize is set to true then + it takes priority over the other checks and the related + attribute/relationship will be serialized + + @method _mustSerialize + @private + @param {String} key + @return {boolean} true if the key must be serialized + */ + _mustSerialize: function(key) { + var attrs = get(this, 'attrs'); + + return attrs && attrs[key] && attrs[key].serialize === true; + }, + + /** + Check if the given hasMany relationship should be serialized + + @method _shouldSerializeHasMany + @private + @param {DS.Snapshot} snapshot + @param {String} key + @param {String} relationshipType + @return {boolean} true if the hasMany relationship should be serialized + */ + _shouldSerializeHasMany: function (snapshot, key, relationship) { + var relationshipType = snapshot.type.determineRelationshipType(relationship, this.store); + if (this._mustSerialize(key)) { + return true; + } + return this._canSerialize(key) && (relationshipType === 'manyToNone' || relationshipType === 'manyToMany'); + }, + + // SERIALIZE /** Called when a record is saved in order to convert the @@ -1095,7 +1130,7 @@ export default Serializer.extend({ serializeHasMany: function(snapshot, json, relationship) { var key = relationship.key; - if (this._canSerialize(key)) { + if (this._shouldSerializeHasMany(snapshot, key, relationship)) { var payloadKey; // if provided, use the mapping provided by `attrs` in @@ -1104,13 +1139,8 @@ export default Serializer.extend({ if (payloadKey === key && this.keyForRelationship) { payloadKey = this.keyForRelationship(key, "hasMany", "serialize"); } - - var relationshipType = snapshot.type.determineRelationshipType(relationship, this.store); - - if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') { - json[payloadKey] = snapshot.hasMany(key, { ids: true }); - // TODO support for polymorphic manyToNone and manyToMany relationships - } + json[payloadKey] = snapshot.hasMany(key, { ids: true }); + // TODO support for polymorphic manyToNone and manyToMany relationships } }, diff --git a/packages/ember-data/tests/integration/serializers/json-serializer-test.js b/packages/ember-data/tests/integration/serializers/json-serializer-test.js index be5c04ee057..02c9d3d5f5d 100644 --- a/packages/ember-data/tests/integration/serializers/json-serializer-test.js +++ b/packages/ember-data/tests/integration/serializers/json-serializer-test.js @@ -318,6 +318,86 @@ test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); }); +test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` property', function() { + expect(1); + env.registry.register("serializer:post", DS.JSONSerializer.extend({ + attrs: { + comments: { serialize: false } + } + })); + + run(function() { + post = env.store.createRecord('post', { title: "Rails is omakase" }); + comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + }); + + var serializer = env.container.lookup("serializer:post"); + var serializedProperty = serializer.keyForRelationship('comments', 'hasMany'); + + var payload = serializer.serialize(post._createSnapshot()); + ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); +}); + +test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` property', function() { + expect(1); + env.registry.register("serializer:comment", DS.JSONSerializer.extend({ + attrs: { + post: { serialize: false } + } + })); + + run(function() { + post = env.store.createRecord('post', { title: "Rails is omakase" }); + comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + }); + + var serializer = env.container.lookup("serializer:comment"); + var serializedProperty = serializer.keyForRelationship('post', 'belongsTo'); + + var payload = serializer.serialize(comment._createSnapshot()); + ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); +}); + +test('Serializer respects `serialize: true` on the attrs hash for a `hasMany` property', function() { + expect(1); + env.registry.register("serializer:post", DS.JSONSerializer.extend({ + attrs: { + comments: { serialize: true } + } + })); + + run(function() { + post = env.store.createRecord('post', { title: "Rails is omakase" }); + comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + }); + + var serializer = env.container.lookup("serializer:post"); + var serializedProperty = serializer.keyForRelationship('comments', 'hasMany'); + + var payload = serializer.serialize(post._createSnapshot()); + ok(payload.hasOwnProperty(serializedProperty), "Add the key to instance"); +}); + +test('Serializer respects `serialize: true` on the attrs hash for a `belongsTo` property', function() { + expect(1); + env.registry.register("serializer:comment", DS.JSONSerializer.extend({ + attrs: { + post: { serialize: true } + } + })); + + run(function() { + post = env.store.createRecord('post', { title: "Rails is omakase" }); + comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + }); + + var serializer = env.container.lookup("serializer:comment"); + var serializedProperty = serializer.keyForRelationship('post', 'belongsTo'); + + var payload = serializer.serialize(comment._createSnapshot()); + ok(payload.hasOwnProperty(serializedProperty), "Add the key to instance"); +}); + test("Serializer should merge attrs from superclasses", function() { expect(4); Post.reopen({ From 5dc004a60b19fe2ac66ec27b029347dba3d48aea Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 10 Jun 2015 12:48:56 -0400 Subject: [PATCH 0918/2527] Fix deprecation warning in tests --- packages/ember-data/lib/system/record-arrays/record-array.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/record-arrays/record-array.js b/packages/ember-data/lib/system/record-arrays/record-array.js index 1ffbdde67e5..62eff479ee4 100644 --- a/packages/ember-data/lib/system/record-arrays/record-array.js +++ b/packages/ember-data/lib/system/record-arrays/record-array.js @@ -115,7 +115,8 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { var store = get(this, 'store'); var modelName = get(this, 'type.modelName'); - return store.fetchAll(modelName, this); + // TODO change this to store.findAll(modelName, { reload: true }); + return store.findAll(modelName); }, /** From 61f9f52438f0700498d7161f71ed4d4b17423b02 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 10 Jun 2015 13:02:05 -0400 Subject: [PATCH 0919/2527] Rename `all` to `peekAll` in a test to fix a deprecation warning. --- .../ember-data/tests/integration/record-array-manager-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/tests/integration/record-array-manager-test.js b/packages/ember-data/tests/integration/record-array-manager-test.js index 9893609404a..d5a0d4c6008 100644 --- a/packages/ember-data/tests/integration/record-array-manager-test.js +++ b/packages/ember-data/tests/integration/record-array-manager-test.js @@ -72,7 +72,7 @@ test("destroying the store correctly cleans everything up", function() { var filterd = manager.createFilteredRecordArray(Person, function() { return true; }); var filterd2 = manager.createFilteredRecordArray(Person, function() { return true; }); - var all = store.all('person'); + var all = store.peekAll('person'); var adapterPopulated = manager.createAdapterPopulatedRecordArray(Person, query); var filterdSummary = tap(filterd, 'willDestroy'); From 7cab3e3c45d38f5df923b4a70fe603c2ed5010a5 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 10 Jun 2015 21:31:21 +0200 Subject: [PATCH 0920/2527] Allow for store.push(object) --- packages/ember-data/lib/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 4fef2f0f077..41460c9748a 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1666,7 +1666,7 @@ Store = Service.extend({ updated. */ push: function(modelName, data) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string' || typeof data === 'undefined'); var internalModel = this._pushInternalModel(modelName, data); if (Ember.isArray(internalModel)) { return map(internalModel, (item) => { From bdffdcd897f8b4bae0672acf9e7eef5c2592fbb0 Mon Sep 17 00:00:00 2001 From: Zoee Silcock Date: Sat, 6 Jun 2015 11:13:51 +0200 Subject: [PATCH 0921/2527] Warnings for incorrect options in belongsTo, resolves #3187 --- .../lib/system/relationships/belongs-to.js | 3 + .../model/relationships/belongs-to-test.js | 58 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/packages/ember-data/lib/system/relationships/belongs-to.js b/packages/ember-data/lib/system/relationships/belongs-to.js index 9ed0700fe56..51dc79398a6 100644 --- a/packages/ember-data/lib/system/relationships/belongs-to.js +++ b/packages/ember-data/lib/system/relationships/belongs-to.js @@ -102,6 +102,9 @@ function belongsTo(modelName, options) { return computedPolyfill({ get: function(key) { + Ember.warn('You provided a serialize option on the "' + key + '" property in the "' + this._internalModel.modelName + '" class, this belongs in the serializer. See DS.Serializer and it\'s implementations http://emberjs.com/api/data/classes/DS.Serializer.html', !opts.hasOwnProperty('serialize')); + Ember.warn('You provided an embedded option on the "' + key + '" property in the "' + this._internalModel.modelName + '" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html', !opts.hasOwnProperty('embedded')); + return this._internalModel._relationships.get(key).getRecord(); }, set: function(key, value) { diff --git a/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js b/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js index 463a987fd27..ebdfb7810b7 100644 --- a/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js @@ -253,3 +253,61 @@ test("belongsTo supports relationships to models with id 0", function() { })); }); }); + +test("belongsTo gives a warning when provided with a serialize option", function() { + var Hobby = DS.Model.extend({ + name: DS.attr('string') + }); + Hobby.toString = function() { return "Hobby"; }; + + var Person = DS.Model.extend({ + name: DS.attr('string'), + hobby: DS.belongsTo('hobby', { serialize: true }) + }); + Person.toString = function() { return "Person"; }; + + var env = setupStore({ hobby: Hobby, person: Person }); + var store = env.store; + + run(function() { + store.pushMany('hobby', [{ id: 1, name: "fishing" }, { id: 1, name: "coding" }]); + store.push('person', { id: 1, name: "Tom Dale", hobby: 1 }); + }); + + warns(function() { + run(function() { + store.find('person', 1).then(async(function(person) { + get(person, 'hobby'); + })); + }); + }, /You provided a serialize option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.Serializer and it's implementations/); +}); + +test("belongsTo gives a warning when provided with an embedded option", function() { + var Hobby = DS.Model.extend({ + name: DS.attr('string') + }); + Hobby.toString = function() { return "Hobby"; }; + + var Person = DS.Model.extend({ + name: DS.attr('string'), + hobby: DS.belongsTo('hobby', { embedded: true }) + }); + Person.toString = function() { return "Person"; }; + + var env = setupStore({ hobby: Hobby, person: Person }); + var store = env.store; + + run(function() { + store.pushMany('hobby', [{ id: 1, name: "fishing" }, { id: 1, name: "coding" }]); + store.push('person', { id: 1, name: "Tom Dale", hobby: 1 }); + }); + + warns(function() { + run(function() { + store.find('person', 1).then(async(function(person) { + get(person, 'hobby'); + })); + }); + }, /You provided an embedded option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin/); +}); From e2cbb8241f9b8721a73a313cf2b3a66c38e0dac6 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 11 Jun 2015 17:27:04 +0200 Subject: [PATCH 0922/2527] Fix relationship being named `belongsTo` instead of `book` --- .../tests/integration/relationships/belongs-to-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/tests/integration/relationships/belongs-to-test.js b/packages/ember-data/tests/integration/relationships/belongs-to-test.js index 82619eadb82..ae9e41fcdc2 100644 --- a/packages/ember-data/tests/integration/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/integration/relationships/belongs-to-test.js @@ -53,7 +53,7 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { Chapter = DS.Model.extend({ title: attr('string'), - belongsTo: belongsTo('book') + book: belongsTo('book') }); Author = DS.Model.extend({ From a99dfa98ff9776c67fd7fc8fd7ac1c32c752f6c9 Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 11 Jun 2015 16:27:30 -0400 Subject: [PATCH 0923/2527] Set the currentState when a record is created, not only when the state changes --- packages/ember-data/lib/system/model/internal-model.js | 3 ++- packages/ember-data/tests/unit/model-test.js | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js index dc6276c879d..94329d08f41 100644 --- a/packages/ember-data/lib/system/model/internal-model.js +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -113,7 +113,8 @@ InternalModel.prototype = { id: this.id, store: this.store, container: this.container, - _internalModel: this + _internalModel: this, + currentState: get(this, 'currentState') }); this._triggerDeferredTriggers(); }, diff --git a/packages/ember-data/tests/unit/model-test.js b/packages/ember-data/tests/unit/model-test.js index 58aa5d8a949..48890115191 100644 --- a/packages/ember-data/tests/unit/model-test.js +++ b/packages/ember-data/tests/unit/model-test.js @@ -299,6 +299,16 @@ test("supports pushedData in root.deleted.uncommitted", function() { }); }); +test("currentState is accessible when the record is created", function() { + var record; + var hash = { id: 1 }; + run(function() { + record = store.push('person', hash); + equal(get(record, 'currentState.stateName'), 'root.loaded.saved', + 'records pushed into the store start in the loaded state'); + }); +}); + module("unit/model - DS.Model updating", { setup: function() { From cfb9cf71dab21a0b5d431f533710fc0e039c6700 Mon Sep 17 00:00:00 2001 From: Zeke Sikelianos Date: Thu, 11 Jun 2015 17:57:18 -0700 Subject: [PATCH 0924/2527] fix typo in README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1854cf27007..331b5a28f6d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ember.js applications. Ember Data is designed to be agnostic to the underlying persistence mechanism, so it works just as well with JSON APIs over HTTP as it does with streaming WebSockets or local IndexedDB storage. - +n It provides many of the facilities you'd find in server-side ORMs like ActiveRecord, but is designed specifically for the unique environment of JavaScript in the browser. @@ -78,7 +78,7 @@ export default DS.Model.extend({ }); ``` -If you're using globals (that is, not something like or ember-cli), your +If you're using globals (that is, not something like ember-cli), your models would look like this: ```js From f69a9ebdccb2c72905ac5ae6794b199ee2433509 Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Thu, 11 Jun 2015 09:25:53 -0400 Subject: [PATCH 0925/2527] Rename rollback() to rollbackAttributes() for Model and InternalModel --- .../lib/system/model/internal-model.js | 4 +- packages/ember-data/lib/system/model/model.js | 30 +- .../ember-data/lib/system/model/states.js | 4 +- .../integration/records/delete-record-test.js | 2 +- .../relationships/belongs-to-test.js | 12 +- .../relationships/has-many-test.js | 24 +- .../relationships/many-to-many-test.js | 14 +- .../relationships/one-to-many-test.js | 36 +- .../relationships/one-to-one-test.js | 18 +- packages/ember-data/tests/unit/model-test.js | 4 +- .../unit/model/rollback-attributes-test.js | 376 ++++++++++++++++++ .../tests/unit/model/rollback-test.js | 364 +---------------- 12 files changed, 473 insertions(+), 415 deletions(-) create mode 100644 packages/ember-data/tests/unit/model/rollback-attributes-test.js diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js index dc6276c879d..61bae6ee90f 100644 --- a/packages/ember-data/lib/system/model/internal-model.js +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -320,7 +320,7 @@ InternalModel.prototype = { } }, - rollback: function() { + rollbackAttributes: function() { var dirtyKeys = Ember.keys(this._attributes); this._attributes = Ember.create(null); @@ -669,7 +669,7 @@ InternalModel.prototype = { Ember Data has 3 buckets for storing the value of an attribute on an internalModel. `_data` holds all of the attributes that have been acknowledged by - a backend via the adapter. When rollback is called on a model all + a backend via the adapter. When rollbackAttributes is called on a model all attributes will revert to the record's state in `_data`. `_attributes` holds any change the user has made to an attribute diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index f85b93320d3..2f04fa8d913 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -469,8 +469,8 @@ var Model = Ember.Object.extend(Ember.Evented, { /** Marks the record as deleted but does not save it. You must call `save` afterwards if you want to persist it. You might use this - method if you want to allow the user to still `rollback()` a - delete after it was made. + method if you want to allow the user to still `rollbackAttributes()` + after a delete it was made. Example @@ -486,7 +486,7 @@ var Model = Ember.Object.extend(Ember.Evented, { this.controller.get('model').save(); }, undo: function() { - this.controller.get('model').rollback(); + this.controller.get('model').rollbackAttributes(); } } }); @@ -621,9 +621,31 @@ var Model = Ember.Object.extend(Ember.Evented, { ``` @method rollback + @deprecated Use `addAttributes()` instead */ rollback: function() { - this._internalModel.rollback(); + Ember.deprecate('Using model.rollback() has been deprecated. Use model.rollbackAttributes() to discard any unsaved changes to a model.'); + this.rollbackAttributes(); + }, + + /** + If the model `isDirty` this function will discard any unsaved + changes. If the model `isNew` it will be removed from the store. + + Example + + ```javascript + record.get('name'); // 'Untitled Document' + record.set('name', 'Doc 1'); + record.get('name'); // 'Doc 1' + record.rollbackAttributes(); + record.get('name'); // 'Untitled Document' + ``` + + @method rollbackAttributes + */ + rollbackAttributes: function() { + this._internalModel.rollbackAttributes(); }, /* diff --git a/packages/ember-data/lib/system/model/states.js b/packages/ember-data/lib/system/model/states.js index 36379760528..60b71c0908b 100644 --- a/packages/ember-data/lib/system/model/states.js +++ b/packages/ember-data/lib/system/model/states.js @@ -273,7 +273,7 @@ var DirtyState = { }, rollback: function(internalModel) { - internalModel.rollback(); + internalModel.rollbackAttributes(); internalModel.triggerLater('ready'); } }, @@ -632,7 +632,7 @@ var RootState = { }, rollback: function(internalModel) { - internalModel.rollback(); + internalModel.rollbackAttributes(); internalModel.triggerLater('ready'); }, diff --git a/packages/ember-data/tests/integration/records/delete-record-test.js b/packages/ember-data/tests/integration/records/delete-record-test.js index 66bf4cd4434..2d62d77270f 100644 --- a/packages/ember-data/tests/integration/records/delete-record-test.js +++ b/packages/ember-data/tests/integration/records/delete-record-test.js @@ -62,7 +62,7 @@ test("when deleted records are rolled back, they are still in their previous rec run(function() { jaime.deleteRecord(); - jaime.rollback(); + jaime.rollbackAttributes(); }); equal(all.get('length'), 2, 'record was not removed'); equal(filtered.get('length'), 2, 'record was not removed'); diff --git a/packages/ember-data/tests/integration/relationships/belongs-to-test.js b/packages/ember-data/tests/integration/relationships/belongs-to-test.js index 82619eadb82..9b23e2f5b1d 100644 --- a/packages/ember-data/tests/integration/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/integration/relationships/belongs-to-test.js @@ -581,7 +581,7 @@ test("A sync belongsTo errors out if the record is unlaoded", function() { }, /You looked up the 'user' relationship on a 'message' with id 1 but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async \(`DS.belongsTo\({ async: true }\)`\)/); }); -test("Rollbacking a deleted record restores implicit relationship - async", function () { +test("Rollbacking attributes for a deleted record restores implicit relationship - async", function () { Book.reopen({ author: DS.belongsTo('author', { async: true }) }); @@ -592,14 +592,14 @@ test("Rollbacking a deleted record restores implicit relationship - async", func }); run(function() { author.deleteRecord(); - author.rollback(); + author.rollbackAttributes(); book.get('author').then(function(fetchedAuthor) { - equal(fetchedAuthor, author, 'Book has an author after rollback'); + equal(fetchedAuthor, author, 'Book has an author after rollback attributes'); }); }); }); -test("Rollbacking a deleted record restores implicit relationship - sync", function () { +test("Rollbacking attributes for a deleted record restores implicit relationship - sync", function () { var book, author; run(function() { book = env.store.push('book', { id: 1, name: "Stanley's Amazing Adventures", author: 2 }); @@ -607,9 +607,9 @@ test("Rollbacking a deleted record restores implicit relationship - sync", funct }); run(function() { author.deleteRecord(); - author.rollback(); + author.rollbackAttributes(); }); - equal(book.get('author'), author, 'Book has an author after rollback'); + equal(book.get('author'), author, 'Book has an author after rollback attributes'); }); test("Passing a model as type to belongsTo should not work", function () { diff --git a/packages/ember-data/tests/integration/relationships/has-many-test.js b/packages/ember-data/tests/integration/relationships/has-many-test.js index 2339ed9a438..38ad0ca5d1e 100644 --- a/packages/ember-data/tests/integration/relationships/has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/has-many-test.js @@ -1060,7 +1060,7 @@ test("If reordered hasMany data has been pushed to the store, the many array ref deepEqual(post.get('comments').toArray(), [comment4, comment2, comment3, comment1], 'Updated ordering is correct'); }); -test("Rollbacking a deleted record restores implicit relationship correctly when the hasMany side has been deleted - async", function () { +test("Rollbacking attributes for deleted record restores implicit relationship correctly when the hasMany side has been deleted - async", function () { var book, chapter; run(function() { book = env.store.push('book', { id: 1, title: "Stanley's Amazing Adventures", chapters: [2] }); @@ -1068,16 +1068,16 @@ test("Rollbacking a deleted record restores implicit relationship correctly when }); run(function() { chapter.deleteRecord(); - chapter.rollback(); + chapter.rollbackAttributes(); }); run(function() { book.get('chapters').then(function(fetchedChapters) { - equal(fetchedChapters.objectAt(0), chapter, 'Book has a chapter after rollback'); + equal(fetchedChapters.objectAt(0), chapter, 'Book has a chapter after rollback attributes'); }); }); }); -test("Rollbacking a deleted record restores implicit relationship correctly when the hasMany side has been deleted - sync", function () { +test("Rollbacking attributes for deleted record restores implicit relationship correctly when the hasMany side has been deleted - sync", function () { var book, chapter; run(function() { book = env.store.push('book', { id: 1, title: "Stanley's Amazing Adventures", chapters: [2] }); @@ -1085,14 +1085,14 @@ test("Rollbacking a deleted record restores implicit relationship correctly when }); run(function() { chapter.deleteRecord(); - chapter.rollback(); + chapter.rollbackAttributes(); }); run(function() { - equal(book.get('chapters.firstObject'), chapter, "Book has a chapter after rollback"); + equal(book.get('chapters.firstObject'), chapter, "Book has a chapter after rollback attributes"); }); }); -test("Rollbacking a deleted record restores implicit relationship correctly when the belongsTo side has been deleted - async", function () { +test("Rollbacking attributes for deleted record restores implicit relationship correctly when the belongsTo side has been deleted - async", function () { Page.reopen({ chapter: DS.belongsTo('chapter', { async: true }) }); @@ -1103,16 +1103,16 @@ test("Rollbacking a deleted record restores implicit relationship correctly when }); run(function() { chapter.deleteRecord(); - chapter.rollback(); + chapter.rollbackAttributes(); }); run(function() { page.get('chapter').then(function(fetchedChapter) { - equal(fetchedChapter, chapter, 'Page has a chapter after rollback'); + equal(fetchedChapter, chapter, 'Page has a chapter after rollback attributes'); }); }); }); -test("Rollbacking a deleted record restores implicit relationship correctly when the belongsTo side has been deleted - sync", function () { +test("Rollbacking attributes for deleted record restores implicit relationship correctly when the belongsTo side has been deleted - sync", function () { var chapter, page; run(function() { chapter = env.store.push('chapter', { id: 2, title: 'Sailing the Seven Seas' }); @@ -1120,10 +1120,10 @@ test("Rollbacking a deleted record restores implicit relationship correctly when }); run(function() { chapter.deleteRecord(); - chapter.rollback(); + chapter.rollbackAttributes(); }); run(function() { - equal(page.get('chapter'), chapter, "Page has a chapter after rollback"); + equal(page.get('chapter'), chapter, "Page has a chapter after rollback attributes"); }); }); diff --git a/packages/ember-data/tests/integration/relationships/many-to-many-test.js b/packages/ember-data/tests/integration/relationships/many-to-many-test.js index 21778c3631e..916b19d764a 100644 --- a/packages/ember-data/tests/integration/relationships/many-to-many-test.js +++ b/packages/ember-data/tests/integration/relationships/many-to-many-test.js @@ -204,10 +204,10 @@ test("Deleting a record that has a hasMany relationship removes it from the othe }); /* - Rollback tests + Rollback Attributes tests */ -test("Rollbacking a deleted record that has a ManyToMany relationship works correctly - async", function () { +test("Rollbacking attributes for a deleted record that has a ManyToMany relationship works correctly - async", function () { var user, topic; run(function() { user = store.push('user', { id: 1, name: 'Stanley', topics: [2] }); @@ -215,7 +215,7 @@ test("Rollbacking a deleted record that has a ManyToMany relationship works corr }); run(function() { topic.deleteRecord(); - topic.rollback(); + topic.rollbackAttributes(); }); run(function() { topic.get('users').then(async(function(fetchedUsers) { @@ -235,13 +235,13 @@ test("Deleting a record that has a hasMany relationship removes it from the othe }); run(function() { account.deleteRecord(); - account.rollback(); + account.rollbackAttributes(); }); equal(account.get('users.length'), 1, 'Users are still there'); equal(user.get('accounts.length'), 1, 'Account got rolledback correctly into the user'); }); -test("Rollbacking a created record that has a ManyToMany relationship works correctly - async", function () { +test("Rollbacking attributes for a created record that has a ManyToMany relationship works correctly - async", function () { var user, topic; run(function() { user = store.push('user', { id: 1, name: 'Stanley' }); @@ -250,7 +250,7 @@ test("Rollbacking a created record that has a ManyToMany relationship works corr run(function() { user.get('topics').then(async(function(fetchedTopics) { fetchedTopics.pushObject(topic); - topic.rollback(); + topic.rollbackAttributes(); topic.get('users').then(async(function(fetchedUsers) { equal(fetchedUsers.get('length'), 0, 'Users got removed'); equal(fetchedUsers.objectAt(0), null, "User can't be fetched"); @@ -271,7 +271,7 @@ test("Deleting a record that has a hasMany relationship removes it from the othe }); run(function() { account.get('users').pushObject(user); - user.rollback(); + user.rollbackAttributes(); }); equal(account.get('users.length'), 0, 'Users got removed'); equal(user.get('accounts.length'), undefined, 'Accounts got rolledback correctly'); diff --git a/packages/ember-data/tests/integration/relationships/one-to-many-test.js b/packages/ember-data/tests/integration/relationships/one-to-many-test.js index 82622f61fd5..83ec15159c5 100644 --- a/packages/ember-data/tests/integration/relationships/one-to-many-test.js +++ b/packages/ember-data/tests/integration/relationships/one-to-many-test.js @@ -446,10 +446,10 @@ test("When deleting a record that has a hasMany it is removed from the belongsTo }); /* -Rollback from deleted state +Rollback attributes from deleted state */ -test("Rollbacking a deleted record works correctly when the hasMany side has been deleted - async", function () { +test("Rollbacking attributes of a deleted record works correctly when the hasMany side has been deleted - async", function () { var user, message; run(function() { user = store.push('user', { id: 1, name: 'Stanley', messages: [2] }); @@ -457,7 +457,7 @@ test("Rollbacking a deleted record works correctly when the hasMany side has bee }); run(function() { message.deleteRecord(); - message.rollback(); + message.rollbackAttributes(); }); run(function() { message.get('user').then(function(fetchedUser) { @@ -469,7 +469,7 @@ test("Rollbacking a deleted record works correctly when the hasMany side has bee }); }); -test("Rollbacking a deleted record works correctly when the hasMany side has been deleted - sync", function () { +test("Rollbacking attributes of a deleted record works correctly when the hasMany side has been deleted - sync", function () { var account, user; run(function() { account = store.push('account', { id: 2 , state: 'lonely' }); @@ -477,13 +477,13 @@ test("Rollbacking a deleted record works correctly when the hasMany side has bee }); run(function() { account.deleteRecord(); - account.rollback(); + account.rollbackAttributes(); }); equal(user.get('accounts.length'), 1, "Accounts are rolled back"); equal(account.get('user'), user, 'Account still has the user'); }); -test("Rollbacking a deleted record works correctly when the belongsTo side has been deleted - async", function () { +test("Rollbacking attributes of deleted record works correctly when the belongsTo side has been deleted - async", function () { var user, message; run(function() { user = store.push('user', { id: 1, name: 'Stanley', messages: [2] }); @@ -491,7 +491,7 @@ test("Rollbacking a deleted record works correctly when the belongsTo side has b }); run(function() { user.deleteRecord(); - user.rollback(); + user.rollbackAttributes(); }); run(function() { message.get('user').then(function(fetchedUser) { @@ -503,7 +503,7 @@ test("Rollbacking a deleted record works correctly when the belongsTo side has b }); }); -test("Rollbacking a deleted record works correctly when the belongsTo side has been deleted - sync", function () { +test("Rollbacking attributes of a deleted record works correctly when the belongsTo side has been deleted - sync", function () { var account, user; run(function() { account = store.push('account', { id: 2 , state: 'lonely' }); @@ -511,23 +511,23 @@ test("Rollbacking a deleted record works correctly when the belongsTo side has b }); run(function() { user.deleteRecord(); - user.rollback(); + user.rollbackAttributes(); }); equal(user.get('accounts.length'), 1, "User still has the accounts"); equal(account.get('user'), user, 'Account has the user again'); }); /* -Rollback from created state +Rollback attributes from created state */ -test("Rollbacking a created record works correctly when the hasMany side has been created - async", function () { +test("Rollbacking attributes of a created record works correctly when the hasMany side has been created - async", function () { var user, message; run(function() { user = store.push('user', { id: 1, name: 'Stanley' }); message = store.createRecord('message', { user: user }); }); - run(message, 'rollback'); + run(message, 'rollbackAttributes'); run(function() { message.get('user').then(function(fetchedUser) { equal(fetchedUser, null, 'Message does not have the user anymore'); @@ -539,18 +539,18 @@ test("Rollbacking a created record works correctly when the hasMany side has bee }); }); -test("Rollbacking a created record works correctly when the hasMany side has been created - sync", function () { +test("Rollbacking attributes of a created record works correctly when the hasMany side has been created - sync", function () { var user, account; run(function() { user = store.push('user', { id: 1, name: 'Stanley' }); account = store.createRecord('account', { user: user }); }); - run(account, 'rollback'); + run(account, 'rollbackAttributes'); equal(user.get('accounts.length'), 0, "Accounts are rolled back"); equal(account.get('user'), null, 'Account does not have the user anymore'); }); -test("Rollbacking a created record works correctly when the belongsTo side has been created - async", function () { +test("Rollbacking attributes of a created record works correctly when the belongsTo side has been created - async", function () { var message, user; run(function() { message = store.push('message', { id: 2, title: 'EmberFest was great' }); @@ -559,7 +559,7 @@ test("Rollbacking a created record works correctly when the belongsTo side has b run(function() { user.get('messages').then(function(messages) { messages.pushObject(message); - user.rollback(); + user.rollbackAttributes(); message.get('user').then(function(fetchedUser) { equal(fetchedUser, null, 'Message does not have the user anymore'); }); @@ -571,7 +571,7 @@ test("Rollbacking a created record works correctly when the belongsTo side has b }); }); -test("Rollbacking a created record works correctly when the belongsTo side has been created - sync", function () { +test("Rollbacking attributes of a created record works correctly when the belongsTo side has been created - sync", function () { var account, user; run(function() { account = store.push('account', { id: 2 , state: 'lonely' }); @@ -580,7 +580,7 @@ test("Rollbacking a created record works correctly when the belongsTo side has b run(function() { user.get('accounts').pushObject(account); }); - run(user, 'rollback'); + run(user, 'rollbackAttributes'); equal(user.get('accounts.length'), undefined, "User does not have the account anymore"); equal(account.get('user'), null, 'Account does not have the user anymore'); }); diff --git a/packages/ember-data/tests/integration/relationships/one-to-one-test.js b/packages/ember-data/tests/integration/relationships/one-to-one-test.js index 74648cada5b..57df05c02c0 100644 --- a/packages/ember-data/tests/integration/relationships/one-to-one-test.js +++ b/packages/ember-data/tests/integration/relationships/one-to-one-test.js @@ -347,10 +347,10 @@ test("When deleting a record that has a belongsTo relationship, the record is re }); /* -Rollback tests +Rollback attributes tests */ -test("Rollbacking a deleted record restores the relationship on both sides - async", function () { +test("Rollbacking attributes of deleted record restores the relationship on both sides - async", function () { var stanley, stanleysFriend; run(function() { stanley = store.push('user', { id: 1, name: 'Stanley', bestFriend: 2 }); @@ -360,7 +360,7 @@ test("Rollbacking a deleted record restores the relationship on both sides - asy stanley.deleteRecord(); }); run(function() { - stanley.rollback(); + stanley.rollbackAttributes(); stanleysFriend.get('bestFriend').then(function(fetchedUser) { equal(fetchedUser, stanley, 'Stanley got rollbacked correctly'); }); @@ -370,7 +370,7 @@ test("Rollbacking a deleted record restores the relationship on both sides - asy }); }); -test("Rollbacking a deleted record restores the relationship on both sides - sync", function () { +test("Rollbacking attributes of deleted record restores the relationship on both sides - sync", function () { var job, user; run(function() { job = store.push('job', { id: 2 , isGood: true }); @@ -378,20 +378,20 @@ test("Rollbacking a deleted record restores the relationship on both sides - syn }); run(function() { job.deleteRecord(); - job.rollback(); + job.rollbackAttributes(); }); equal(user.get('job'), job, 'Job got rollbacked correctly'); equal(job.get('user'), user, 'Job still has the user'); }); -test("Rollbacking a created record removes the relationship on both sides - async", function () { +test("Rollbacking attributes of created record removes the relationship on both sides - async", function () { var stanleysFriend, stanley; run(function() { stanleysFriend = store.push('user', { id: 2, name: "Stanley's friend" }); stanley = store.createRecord('user', { bestFriend: stanleysFriend }); }); run(function() { - stanley.rollback(); + stanley.rollbackAttributes(); stanleysFriend.get('bestFriend').then(function(fetchedUser) { equal(fetchedUser, null, 'Stanley got rollbacked correctly'); }); @@ -401,14 +401,14 @@ test("Rollbacking a created record removes the relationship on both sides - asyn }); }); -test("Rollbacking a created record removes the relationship on both sides - sync", function () { +test("Rollbacking attributes of created record removes the relationship on both sides - sync", function () { var user, job; run(function() { user = store.push('user', { id: 1, name: 'Stanley' }); job = store.createRecord('job', { user: user }); }); run(function() { - job.rollback(); + job.rollbackAttributes(); }); equal(user.get('job'), null, 'Job got rollbacked correctly'); equal(job.get('user'), null, 'Job does not have user anymore'); diff --git a/packages/ember-data/tests/unit/model-test.js b/packages/ember-data/tests/unit/model-test.js index 58aa5d8a949..a4dce35c43a 100644 --- a/packages/ember-data/tests/unit/model-test.js +++ b/packages/ember-data/tests/unit/model-test.js @@ -219,9 +219,9 @@ test("changedAttributes() return correct values", function() { deepEqual({ name: [undefined, 'Tomster'], likes: ['JavaScript', 'Ember.js'] }, mascot.changedAttributes(), 'attributes has changed'); run(function() { - mascot.rollback(); + mascot.rollbackAttributes(); }); - deepEqual({}, mascot.changedAttributes(), 'after rollback there are no changes'); + deepEqual({}, mascot.changedAttributes(), 'after rollback attributes there are no changes'); }); test("a DS.Model does not require an attribute type", function() { diff --git a/packages/ember-data/tests/unit/model/rollback-attributes-test.js b/packages/ember-data/tests/unit/model/rollback-attributes-test.js new file mode 100644 index 00000000000..408305f306d --- /dev/null +++ b/packages/ember-data/tests/unit/model/rollback-attributes-test.js @@ -0,0 +1,376 @@ +var env, store, Person, Dog; +var run = Ember.run; + +module("unit/model/rollbackAttributes - model.rollbackAttributes()", { + setup: function() { + Person = DS.Model.extend({ + firstName: DS.attr(), + lastName: DS.attr() + }); + + env = setupStore({ person: Person }); + store = env.store; + } +}); + +test("changes to attributes can be rolled back", function() { + var person; + run(function() { + person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); + person.set('firstName', "Thomas"); + }); + + equal(person.get('firstName'), "Thomas"); + + run(function() { + person.rollbackAttributes(); + }); + + equal(person.get('firstName'), "Tom"); + equal(person.get('isDirty'), false); +}); + +test("changes to unassigned attributes can be rolled back", function() { + var person; + run(function() { + person = store.push('person', { id: 1, lastName: "Dale" }); + person.set('firstName', "Thomas"); + }); + + equal(person.get('firstName'), "Thomas"); + + run(function() { + person.rollbackAttributes(); + }); + + equal(person.get('firstName'), undefined); + equal(person.get('isDirty'), false); +}); + +test("changes to attributes made after a record is in-flight only rolls back the local changes", function() { + env.adapter.updateRecord = function(store, type, snapshot) { + // Make sure the save is async + return new Ember.RSVP.Promise(function(resolve, reject) { + Ember.run.later(null, resolve, 15); + }); + }; + var person; + + run(function() { + person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); + person.set('firstName', "Thomas"); + }); + + Ember.run(function() { + var saving = person.save(); + + equal(person.get('firstName'), "Thomas"); + + person.set('lastName', "Dolly"); + + equal(person.get('lastName'), "Dolly"); + + person.rollbackAttributes(); + + equal(person.get('firstName'), "Thomas"); + equal(person.get('lastName'), "Dale"); + equal(person.get('isSaving'), true); + + saving.then(async(function() { + equal(person.get('isDirty'), false, "The person is now clean"); + })); + }); +}); + +test("a record's changes can be made if it fails to save", function() { + env.adapter.updateRecord = function(store, type, snapshot) { + return Ember.RSVP.reject(); + }; + var person; + + run(function() { + person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); + person.set('firstName', "Thomas"); + }); + + deepEqual(person.changedAttributes(), { firstName: ["Tom", "Thomas"] }); + + run(function() { + person.save().then(null, function() { + equal(person.get('isError'), true); + deepEqual(person.changedAttributes(), { firstName: ["Tom", "Thomas"] }); + + person.rollbackAttributes(); + + equal(person.get('firstName'), "Tom"); + equal(person.get('isError'), false); + deepEqual(person.changedAttributes(), {}); + }); + }); +}); + +test("a deleted record's attributes can be rollbacked if it fails to save, record arrays are updated accordingly", function() { + expect(7); + env.adapter.deleteRecord = function(store, type, snapshot) { + return Ember.RSVP.reject(); + }; + var person, people; + + run(function() { + person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); + people = store.peekAll('person'); + }); + + run(function() { + person.deleteRecord(); + }); + equal(people.get('length'), 0, "a deleted record does not appear in record array anymore"); + equal(people.objectAt(0), null, "a deleted record does not appear in record array anymore"); + + run(function() { + person.save().then(null, function() { + equal(person.get('isError'), true); + equal(person.get('isDeleted'), true); + run(function() { + person.rollbackAttributes(); + }); + equal(person.get('isDeleted'), false); + equal(person.get('isError'), false); + }).then(function() { + equal(people.get('length'), 1, "the underlying record array is updated accordingly in an asynchronous way"); + }); + }); +}); + +test("new record's attributes can be rollbacked", function() { + var person; + + run(function() { + person = store.createRecord('person', { id: 1 }); + }); + + equal(person.get('isNew'), true, "must be new"); + equal(person.get('isDirty'), true, "must be dirty"); + + Ember.run(person, 'rollbackAttributes'); + + equal(person.get('isNew'), false, "must not be new"); + equal(person.get('isDirty'), false, "must not be dirty"); + equal(person.get('isDeleted'), true, "must be deleted"); +}); + +test("invalid new record's attributes can be rollbacked", function() { + var person; + var adapter = DS.RESTAdapter.extend({ + ajax: function(url, type, hash) { + var adapter = this; + + return new Ember.RSVP.Promise(function(resolve, reject) { + /* If InvalidError is passed back in the reject it will throw the + exception which will bubble up the call stack (crashing the test) + instead of hitting the failure route of the promise. + So wrapping the reject in an Ember.run.next makes it so save + completes without failure and the failure hits the failure route + of the promise instead of crashing the save. */ + Ember.run.next(function() { + reject(adapter.ajaxError({ name: 'is invalid' })); + }); + }); + }, + + ajaxError: function(jqXHR) { + return new DS.InvalidError(jqXHR); + } + }); + + env = setupStore({ person: Person, adapter: adapter }); + + run(function() { + person = env.store.createRecord('person', { id: 1 }); + }); + + equal(person.get('isNew'), true, "must be new"); + equal(person.get('isDirty'), true, "must be dirty"); + + run(function() { + person.save().then(null, async(function() { + equal(person.get('isValid'), false); + person.rollbackAttributes(); + + equal(person.get('isNew'), false, "must not be new"); + equal(person.get('isDirty'), false, "must not be dirty"); + equal(person.get('isDeleted'), true, "must be deleted"); + })); + }); +}); + +test("deleted record's attributes can be rollbacked", function() { + var person, people; + + run(function() { + person = store.push('person', { id: 1 }); + people = store.peekAll('person'); + person.deleteRecord(); + }); + + equal(people.get('length'), 0, "a deleted record does not appear in record array anymore"); + equal(people.objectAt(0), null, "a deleted record does not appear in record array anymore"); + + equal(person.get('isDeleted'), true, "must be deleted"); + + run(function() { + person.rollbackAttributes(); + }); + equal(people.get('length'), 1, "the rollbacked record should appear again in the record array"); + equal(person.get('isDeleted'), false, "must not be deleted"); + equal(person.get('isDirty'), false, "must not be dirty"); +}); + +test("invalid record's attributes can be rollbacked", function() { + Dog = DS.Model.extend({ + name: DS.attr() + }); + + var adapter = DS.RESTAdapter.extend({ + ajax: function(url, type, hash) { + var adapter = this; + + return new Ember.RSVP.Promise(function(resolve, reject) { + /* If InvalidError is passed back in the reject it will throw the + exception which will bubble up the call stack (crashing the test) + instead of hitting the failure route of the promise. + So wrapping the reject in an Ember.run.next makes it so save + completes without failure and the failure hits the failure route + of the promise instead of crashing the save. */ + Ember.run.next(function() { + reject(adapter.ajaxError({ name: 'is invalid' })); + }); + }); + }, + + ajaxError: function(jqXHR) { + return new DS.InvalidError(jqXHR); + } + }); + + env = setupStore({ dog: Dog, adapter: adapter }); + var dog; + run(function() { + dog = env.store.push('dog', { id: 1, name: "Pluto" }); + dog.set('name', "is a dwarf planet"); + }); + + run(function() { + dog.save().then(null, async(function() { + dog.rollbackAttributes(); + + equal(dog.get('name'), "Pluto"); + ok(dog.get('isValid')); + })); + }); +}); + +test("invalid record's attributes rolled back to correct state after set", function() { + Dog = DS.Model.extend({ + name: DS.attr(), + breed: DS.attr() + }); + + var adapter = DS.RESTAdapter.extend({ + ajax: function(url, type, hash) { + var adapter = this; + + return new Ember.RSVP.Promise(function(resolve, reject) { + /* If InvalidError is passed back in the reject it will throw the + exception which will bubble up the call stack (crashing the test) + instead of hitting the failure route of the promise. + So wrapping the reject in an Ember.run.next makes it so save + completes without failure and the failure hits the failure route + of the promise instead of crashing the save. */ + Ember.run.next(function() { + reject(adapter.ajaxError({ name: 'is invalid' })); + }); + }); + }, + + ajaxError: function(jqXHR) { + return new Error(jqXHR); + } + }); + + env = setupStore({ dog: Dog, adapter: adapter }); + var dog; + run(function() { + dog = env.store.push('dog', { id: 1, name: "Pluto", breed: "Disney" }); + dog.set('name', "is a dwarf planet"); + dog.set('breed', 'planet'); + }); + + run(function() { + dog.save().then(null, async(function() { + equal(dog.get('name'), "is a dwarf planet"); + equal(dog.get('breed'), "planet"); + + run(function() { + dog.set('name', 'Seymour Asses'); + }); + + equal(dog.get('name'), "Seymour Asses"); + equal(dog.get('breed'), "planet"); + + run(function() { + dog.rollbackAttributes(); + }); + + equal(dog.get('name'), "Pluto"); + equal(dog.get('breed'), "Disney"); + ok(dog.get('isValid')); + })); + }); +}); + +test("when destroying a record setup the record state to invalid, the record's attributes can be rollbacked", function() { + Dog = DS.Model.extend({ + name: DS.attr() + }); + + var adapter = DS.RESTAdapter.extend({ + ajax: function(url, type, hash) { + var adapter = this; + + return new Ember.RSVP.Promise(function(resolve, reject) { + Ember.run.next(function() { + reject(adapter.ajaxError({ name: 'is invalid' })); + }); + }); + }, + + ajaxError: function(jqXHR) { + return new DS.InvalidError(jqXHR); + } + }); + + env = setupStore({ dog: Dog, adapter: adapter }); + var dog; + run(function() { + dog = env.store.push('dog', { id: 1, name: "Pluto" }); + }); + + run(function() { + dog.destroyRecord().then(null, async(function() { + + + equal(dog.get('isError'), false, "must not be error"); + equal(dog.get('isDeleted'), true, "must be deleted"); + equal(dog.get('isValid'), false, "must not be valid"); + ok(dog.get('errors.length') > 0, "must have errors"); + + dog.rollbackAttributes(); + + equal(dog.get('isError'), false, "must not be error after `rollbackAttributes`"); + equal(dog.get('isDeleted'), false, "must not be deleted after `rollbackAttributes`"); + equal(dog.get('isValid'), true, "must be valid after `rollbackAttributes`"); + ok(dog.get('errors.length') === 0, "must not have errors"); + })); + }); +}); diff --git a/packages/ember-data/tests/unit/model/rollback-test.js b/packages/ember-data/tests/unit/model/rollback-test.js index 0095245e347..8e1b98ec73e 100644 --- a/packages/ember-data/tests/unit/model/rollback-test.js +++ b/packages/ember-data/tests/unit/model/rollback-test.js @@ -1,7 +1,7 @@ -var env, store, Person, Dog; +var env, store, Person; var run = Ember.run; -module("unit/model/rollback - model.rollback()", { +module("unit/model/rollback - model.rollback() - deprecated", { setup: function() { Person = DS.Model.extend({ firstName: DS.attr(), @@ -13,364 +13,24 @@ module("unit/model/rollback - model.rollback()", { } }); -test("changes to attributes can be rolled back", function() { +test("changes to attributes can be rolled back - deprecated", function() { var person; run(function() { - person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); - person.set('firstName', "Thomas"); + person = store.push('person', { id: 1, firstName: 'Tom', lastName: 'Dale' }); + person.set('firstName', 'Thomas'); }); - equal(person.get('firstName'), "Thomas"); + equal(person.get('firstName'), 'Thomas'); - run(function() { - person.rollback(); - }); - - equal(person.get('firstName'), "Tom"); - equal(person.get('isDirty'), false); -}); - -test("changes to unassigned attributes can be rolled back", function() { - var person; - run(function() { - person = store.push('person', { id: 1, lastName: "Dale" }); - person.set('firstName', "Thomas"); - }); - - equal(person.get('firstName'), "Thomas"); - - run(function() { - person.rollback(); - }); - - equal(person.get('firstName'), undefined); - equal(person.get('isDirty'), false); -}); - -test("changes to attributes made after a record is in-flight only rolls back the local changes", function() { - env.adapter.updateRecord = function(store, type, snapshot) { - // Make sure the save is async - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.run.later(null, resolve, 15); - }); - }; - var person; - - run(function() { - person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); - person.set('firstName', "Thomas"); - }); - - Ember.run(function() { - var saving = person.save(); - - equal(person.get('firstName'), "Thomas"); - - person.set('lastName', "Dolly"); - - equal(person.get('lastName'), "Dolly"); - - person.rollback(); - - equal(person.get('firstName'), "Thomas"); - equal(person.get('lastName'), "Dale"); - equal(person.get('isSaving'), true); - - saving.then(async(function() { - equal(person.get('isDirty'), false, "The person is now clean"); - })); - }); -}); - -test("a record's changes can be made if it fails to save", function() { - env.adapter.updateRecord = function(store, type, snapshot) { - return Ember.RSVP.reject(); - }; - var person; - - run(function() { - person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); - person.set('firstName', "Thomas"); - }); - - deepEqual(person.changedAttributes(), { firstName: ["Tom", "Thomas"] }); - - run(function() { - person.save().then(null, function() { - equal(person.get('isError'), true); - deepEqual(person.changedAttributes(), { firstName: ["Tom", "Thomas"] }); - - person.rollback(); - - equal(person.get('firstName'), "Tom"); - equal(person.get('isError'), false); - deepEqual(person.changedAttributes(), {}); - }); - }); -}); - -test("a deleted record can be rollbacked if it fails to save, record arrays are updated accordingly", function() { - expect(7); - env.adapter.deleteRecord = function(store, type, snapshot) { - return Ember.RSVP.reject(); - }; - var person, people; - - run(function() { - person = store.push('person', { id: 1, firstName: "Tom", lastName: "Dale" }); - people = store.peekAll('person'); - }); - - run(function() { - person.deleteRecord(); - }); - equal(people.get('length'), 0, "a deleted record does not appear in record array anymore"); - equal(people.objectAt(0), null, "a deleted record does not appear in record array anymore"); - - run(function() { - person.save().then(null, function() { - equal(person.get('isError'), true); - equal(person.get('isDeleted'), true); + expectDeprecation( + function() { run(function() { person.rollback(); }); - equal(person.get('isDeleted'), false); - equal(person.get('isError'), false); - }).then(function() { - equal(people.get('length'), 1, "the underlying record array is updated accordingly in an asynchronous way"); - }); - }); -}); - -test("new record can be rollbacked", function() { - var person; - - run(function() { - person = store.createRecord('person', { id: 1 }); - }); - - equal(person.get('isNew'), true, "must be new"); - equal(person.get('isDirty'), true, "must be dirty"); - - Ember.run(person, 'rollback'); - - equal(person.get('isNew'), false, "must not be new"); - equal(person.get('isDirty'), false, "must not be dirty"); - equal(person.get('isDeleted'), true, "must be deleted"); -}); - -test("invalid new record can be rollbacked", function() { - var person; - var adapter = DS.RESTAdapter.extend({ - ajax: function(url, type, hash) { - var adapter = this; - - return new Ember.RSVP.Promise(function(resolve, reject) { - /* If InvalidError is passed back in the reject it will throw the - exception which will bubble up the call stack (crashing the test) - instead of hitting the failure route of the promise. - So wrapping the reject in an Ember.run.next makes it so save - completes without failure and the failure hits the failure route - of the promise instead of crashing the save. */ - Ember.run.next(function() { - reject(adapter.ajaxError({ name: 'is invalid' })); - }); - }); - }, - - ajaxError: function(jqXHR) { - return new DS.InvalidError(jqXHR); - } - }); - - env = setupStore({ person: Person, adapter: adapter }); - - run(function() { - person = env.store.createRecord('person', { id: 1 }); - }); - - equal(person.get('isNew'), true, "must be new"); - equal(person.get('isDirty'), true, "must be dirty"); - - run(function() { - person.save().then(null, async(function() { - equal(person.get('isValid'), false); - person.rollback(); - - equal(person.get('isNew'), false, "must not be new"); - equal(person.get('isDirty'), false, "must not be dirty"); - equal(person.get('isDeleted'), true, "must be deleted"); - })); - }); -}); - -test("deleted record can be rollbacked", function() { - var person, people; - - run(function() { - person = store.push('person', { id: 1 }); - people = store.peekAll('person'); - person.deleteRecord(); - }); - - equal(people.get('length'), 0, "a deleted record does not appear in record array anymore"); - equal(people.objectAt(0), null, "a deleted record does not appear in record array anymore"); - - equal(person.get('isDeleted'), true, "must be deleted"); - - run(function() { - person.rollback(); - }); - equal(people.get('length'), 1, "the rollbacked record should appear again in the record array"); - equal(person.get('isDeleted'), false, "must not be deleted"); - equal(person.get('isDirty'), false, "must not be dirty"); -}); - -test("invalid record can be rollbacked", function() { - Dog = DS.Model.extend({ - name: DS.attr() - }); - - var adapter = DS.RESTAdapter.extend({ - ajax: function(url, type, hash) { - var adapter = this; - - return new Ember.RSVP.Promise(function(resolve, reject) { - /* If InvalidError is passed back in the reject it will throw the - exception which will bubble up the call stack (crashing the test) - instead of hitting the failure route of the promise. - So wrapping the reject in an Ember.run.next makes it so save - completes without failure and the failure hits the failure route - of the promise instead of crashing the save. */ - Ember.run.next(function() { - reject(adapter.ajaxError({ name: 'is invalid' })); - }); - }); - }, - - ajaxError: function(jqXHR) { - return new DS.InvalidError(jqXHR); - } - }); - - env = setupStore({ dog: Dog, adapter: adapter }); - var dog; - run(function() { - dog = env.store.push('dog', { id: 1, name: "Pluto" }); - dog.set('name', "is a dwarf planet"); - }); - - run(function() { - dog.save().then(null, async(function() { - dog.rollback(); - - equal(dog.get('name'), "Pluto"); - ok(dog.get('isValid')); - })); - }); -}); - -test("invalid record is rolled back to correct state after set", function() { - Dog = DS.Model.extend({ - name: DS.attr(), - breed: DS.attr() - }); - - var adapter = DS.RESTAdapter.extend({ - ajax: function(url, type, hash) { - var adapter = this; - - return new Ember.RSVP.Promise(function(resolve, reject) { - /* If InvalidError is passed back in the reject it will throw the - exception which will bubble up the call stack (crashing the test) - instead of hitting the failure route of the promise. - So wrapping the reject in an Ember.run.next makes it so save - completes without failure and the failure hits the failure route - of the promise instead of crashing the save. */ - Ember.run.next(function() { - reject(adapter.ajaxError({ name: 'is invalid' })); - }); - }); }, + 'Using model.rollback() has been deprecated. Use model.rollbackAttributes() to discard any unsaved changes to a model.' + ); - ajaxError: function(jqXHR) { - return new Error(jqXHR); - } - }); - - env = setupStore({ dog: Dog, adapter: adapter }); - var dog; - run(function() { - dog = env.store.push('dog', { id: 1, name: "Pluto", breed: "Disney" }); - dog.set('name', "is a dwarf planet"); - dog.set('breed', 'planet'); - }); - - run(function() { - dog.save().then(null, async(function() { - equal(dog.get('name'), "is a dwarf planet"); - equal(dog.get('breed'), "planet"); - - run(function() { - dog.set('name', 'Seymour Asses'); - }); - - equal(dog.get('name'), "Seymour Asses"); - equal(dog.get('breed'), "planet"); - - run(function() { - dog.rollback(); - }); - - equal(dog.get('name'), "Pluto"); - equal(dog.get('breed'), "Disney"); - ok(dog.get('isValid')); - })); - }); -}); - -test("when destroying a record setup the record state to invalid, the record can be rollbacked", function() { - Dog = DS.Model.extend({ - name: DS.attr() - }); - - var adapter = DS.RESTAdapter.extend({ - ajax: function(url, type, hash) { - var adapter = this; - - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.run.next(function() { - reject(adapter.ajaxError({ name: 'is invalid' })); - }); - }); - }, - - ajaxError: function(jqXHR) { - return new DS.InvalidError(jqXHR); - } - }); - - env = setupStore({ dog: Dog, adapter: adapter }); - var dog; - run(function() { - dog = env.store.push('dog', { id: 1, name: "Pluto" }); - }); - - run(function() { - dog.destroyRecord().then(null, async(function() { - - - equal(dog.get('isError'), false, "must not be error"); - equal(dog.get('isDeleted'), true, "must be deleted"); - equal(dog.get('isValid'), false, "must not be valid"); - ok(dog.get('errors.length') > 0, "must have errors"); - - dog.rollback(); - - equal(dog.get('isError'), false, "must not be error after `rollback`"); - equal(dog.get('isDeleted'), false, "must not be deleted after `rollback`"); - equal(dog.get('isValid'), true, "must be valid after `rollback`"); - ok(dog.get('errors.length') === 0, "must not have errors"); - })); - }); + equal(person.get('firstName'), 'Tom'); + equal(person.get('isDirty'), false); }); From c061ad4a24ea4f7dfbd23e44cc14cf185b214760 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 12 Jun 2015 14:50:23 -0400 Subject: [PATCH 0926/2527] Support custom stores defined on the container as --- .../ember-data/lib/initializers/store-injections.js | 6 +++--- packages/ember-data/lib/initializers/store.js | 8 ++++---- .../initialize-store-service.js | 10 +++++++++- packages/ember-data/lib/main.js | 4 ++++ .../tests/integration/application-test.js | 4 ++-- .../backwards-compat/non-dasherized-lookups.js | 4 ++-- .../tests/integration/debug-adapter-test.js | 2 +- .../tests/integration/multiple_stores_test.js | 2 +- .../tests/integration/setup-container-test.js | 13 +------------ 9 files changed, 27 insertions(+), 26 deletions(-) diff --git a/packages/ember-data/lib/initializers/store-injections.js b/packages/ember-data/lib/initializers/store-injections.js index af907d0bd33..16dca7f409b 100644 --- a/packages/ember-data/lib/initializers/store-injections.js +++ b/packages/ember-data/lib/initializers/store-injections.js @@ -6,7 +6,7 @@ @param {Ember.Registry} registry */ export default function initializeStoreInjections(registry) { - registry.injection('controller', 'store', 'store:application'); - registry.injection('route', 'store', 'store:application'); - registry.injection('data-adapter', 'store', 'store:application'); + registry.injection('controller', 'store', 'store:main'); + registry.injection('route', 'store', 'store:main'); + registry.injection('data-adapter', 'store', 'store:main'); } diff --git a/packages/ember-data/lib/initializers/store.js b/packages/ember-data/lib/initializers/store.js index e86832289b2..327ca307f40 100644 --- a/packages/ember-data/lib/initializers/store.js +++ b/packages/ember-data/lib/initializers/store.js @@ -1,7 +1,6 @@ import {JSONSerializer, RESTSerializer} from "ember-data/serializers"; import {RESTAdapter} from "ember-data/adapters"; import ContainerProxy from "ember-data/system/container-proxy"; -import Store from "ember-data/system/store"; /** Configures a registry for use with an Ember-Data @@ -18,7 +17,9 @@ export default function initializeStore(registry, application) { registry.optionsForType('serializer', { singleton: false }); registry.optionsForType('adapter', { singleton: false }); - registry.register('store:application', application && application.Store || Store); + if (application && application.Store) { + registry.register('store:application', application.Store); + } // allow older names to be looked up @@ -26,8 +27,7 @@ export default function initializeStore(registry, application) { proxy.registerDeprecations([ { deprecated: 'serializer:_default', valid: 'serializer:-default' }, { deprecated: 'serializer:_rest', valid: 'serializer:-rest' }, - { deprecated: 'adapter:_rest', valid: 'adapter:-rest' }, - { deprecated: 'store:main', valid: 'store:application' } + { deprecated: 'adapter:_rest', valid: 'adapter:-rest' } ]); // new go forward paths diff --git a/packages/ember-data/lib/instance-initializers/initialize-store-service.js b/packages/ember-data/lib/instance-initializers/initialize-store-service.js index 638b2ed3939..54f6b962519 100644 --- a/packages/ember-data/lib/instance-initializers/initialize-store-service.js +++ b/packages/ember-data/lib/instance-initializers/initialize-store-service.js @@ -1,3 +1,4 @@ +import Store from "ember-data/system/store"; /** Configures a registry for use with an Ember-Data store. @@ -24,7 +25,14 @@ export default function initializeStoreService(applicationOrRegistry) { container = registry; } } + if (registry.has('store:application')) { + var customStoreFactory = container.lookupFactory('store:application'); + registry.register('store:main', customStoreFactory); + } else { + registry.register('store:main', Store); + } + // Eagerly generate the store so defaultStore is populated. - var store = container.lookup('store:application'); + var store = container.lookup('store:main'); registry.register('service:store', store, { instantiate: false }); } diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index d5a28b47a5a..09a6a1ae872 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -10,6 +10,10 @@ if (Ember.VERSION.match(/^1\.[0-7]\./)) { ". Please upgrade your version of Ember, then upgrade Ember Data"); } +if (Ember.VERSION.match(/^1\.12\.0/)) { + throw new Ember.Error("Ember Data does not work with Ember 1.12.0. Please upgrade to Ember 1.12.1 or higher."); +} + // support RSVP 2.x via resolve, but prefer RSVP 3.x's Promise.cast Ember.RSVP.Promise.cast = Ember.RSVP.Promise.cast || Ember.RSVP.resolve; diff --git a/packages/ember-data/tests/integration/application-test.js b/packages/ember-data/tests/integration/application-test.js index 1c523737724..31ffb01e93b 100644 --- a/packages/ember-data/tests/integration/application-test.js +++ b/packages/ember-data/tests/integration/application-test.js @@ -13,7 +13,7 @@ var app, App, container; */ function getStore() { - return lookup('store:application'); + return lookup('store:main'); } function lookup(thing) { @@ -69,7 +69,7 @@ test("registering App.Store is deprecated but functional", function() { 'has been deprecated. Please use `App.ApplicationStore` instead.'); run(function() { - ok(lookup('store:application').get('isCustomButDeprecated'), "the custom store was instantiated"); + ok(lookup('store:main').get('isCustomButDeprecated'), "the custom store was instantiated"); }); var fooController = lookup('controller:foo'); diff --git a/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js b/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js index e026bea16d5..531f35da9e2 100644 --- a/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js +++ b/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js @@ -9,7 +9,7 @@ module('integration/backwards-compat/non-dasherized-lookups - non dasherized loo name: DS.attr() }); }); - store = App.__container__.lookup('store:application'); + store = App.__container__.lookup('store:main'); }, teardown: function() { run(App, 'destroy'); @@ -67,7 +67,7 @@ module('integration/backwards-compat/non-dasherized-lookups - non dasherized loo postNotes: DS.hasMany('post_note') }); }); - store = App.__container__.lookup('store:application'); + store = App.__container__.lookup('store:main'); }, teardown: function() { diff --git a/packages/ember-data/tests/integration/debug-adapter-test.js b/packages/ember-data/tests/integration/debug-adapter-test.js index 34f7356628f..7ea659afc43 100644 --- a/packages/ember-data/tests/integration/debug-adapter-test.js +++ b/packages/ember-data/tests/integration/debug-adapter-test.js @@ -23,7 +23,7 @@ module("DS.DebugAdapter", { }); - store = App.__container__.lookup('store:application'); + store = App.__container__.lookup('store:main'); debugAdapter = App.__container__.lookup('data-adapter:main'); debugAdapter.reopen({ diff --git a/packages/ember-data/tests/integration/multiple_stores_test.js b/packages/ember-data/tests/integration/multiple_stores_test.js index 1156cae6e96..badc61087e4 100644 --- a/packages/ember-data/tests/integration/multiple_stores_test.js +++ b/packages/ember-data/tests/integration/multiple_stores_test.js @@ -118,7 +118,7 @@ test("embedded records should be created in multiple stores", function() { run(function() { json_main = serializer_main.extractSingle(env.store, env.store.modelFor('home-planet'), json_hash_main); - equal(env.store.hasRecordForId('super-villain', "1"), true, "superVillain should exist in store:application"); + equal(env.store.hasRecordForId('super-villain', "1"), true, "superVillain should exist in store:main"); }); run(function() { diff --git a/packages/ember-data/tests/integration/setup-container-test.js b/packages/ember-data/tests/integration/setup-container-test.js index e8c85d2ea8c..724f6537bcc 100644 --- a/packages/ember-data/tests/integration/setup-container-test.js +++ b/packages/ember-data/tests/integration/setup-container-test.js @@ -30,7 +30,7 @@ module("integration/setup-container - Setting up a container", { }); test("The store should be registered into a container.", function() { - ok(container.lookup('store:application') instanceof Store, "the custom store is instantiated"); + ok(container.lookup('store:main') instanceof Store, "the custom store is instantiated"); }); test("The store should be registered into the container as a service.", function() { @@ -86,17 +86,6 @@ test("serializers are not returned as singletons - each lookup should return a d notEqual(serializer1, serializer2); }); -test("the deprecated store:main is resolved as store:application", function() { - var deprecated; - var valid = container.lookup('store:application'); - expectDeprecation(function() { - deprecated = container.lookup('store:main'); - }); - - ok(deprecated.constructor === valid.constructor, "they should resolve to the same thing"); -}); - - test("adapters are not returned as singletons - each lookup should return a different instance", function() { var adapter1, adapter2; adapter1 = container.lookup('adapter:-rest'); From 88ed8394bff3f5e96dcc9802917b88e601ee15a4 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 12 Jun 2015 16:32:26 -0400 Subject: [PATCH 0927/2527] Update changelog for beta-19.2 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c3f887ba0e..a1e4ba0aa0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ### Master +### Release 1.0.0-beta.19.2 (June 12, 2015) + +- Fix a regression with Ember CLI users who have defined a custom + store in `app/store.js` - https://github.com/emberjs/data/pull/3316 +- Fix a regression where `currentState` was not defined on a record + until the record a state change occured. https://github.com/emberjs/data/pull/3311 + ### Release 1.0.0-beta.19.1 (June 9, 2015) - Fix a regression where a `DS.Model`'s `InternalModel` would not be set From 8e13f16e365a7e579e9aa45f389adb348df5b6df Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 11 Jun 2015 23:48:54 +0200 Subject: [PATCH 0928/2527] Add `assertPolymorphicType` utility This function checks if a records which should be added/set on a relationship is a valid, meaning that it is a valid polymorphic type. --- packages/ember-data/lib/utils.js | 46 ++++++++ packages/ember-data/tests/unit/utils-test.js | 107 +++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 packages/ember-data/lib/utils.js create mode 100644 packages/ember-data/tests/unit/utils-test.js diff --git a/packages/ember-data/lib/utils.js b/packages/ember-data/lib/utils.js new file mode 100644 index 00000000000..14d767fc6ee --- /dev/null +++ b/packages/ember-data/lib/utils.js @@ -0,0 +1,46 @@ +import Ember from 'ember'; + +/** + Assert that `addedRecord` has a valid type so it can be added to the + relationship of the `record`. + + The assert basically checks if the `addedRecord` can be added to the + relationship (specified via `relationshipMeta`) of the `record`. + + This utility should only be used internally, as both record parameters must + be an InternalModel and the `relationshipMeta` needs to be the meta + information about the relationship, retrieved via + `record.relationshipFor(key)`. + + @param {InternalModel} record + @param {RelationshipMeta} relationshipMeta retrieved via + `record.relationshipFor(key)` + @param {InternalModel} addedRecord record which + should be added/set for the relationship +*/ +var assertPolymorphicType = function(record, relationshipMeta, addedRecord) { + var addedType = addedRecord.type.modelName; + var recordType = record.type.modelName; + var key = relationshipMeta.key; + var typeClass = record.store.modelFor(relationshipMeta.type); + + var assertionMessage = `You cannot add a record of type '${addedType}' to the '${recordType}.${key}' relationship (only '${typeClass.modelName}' allowed)`; + + Ember.assert(assertionMessage, checkPolymorphic(typeClass, addedRecord)); +}; + +function checkPolymorphic(typeClass, addedRecord) { + if (typeClass.__isMixin) { + //TODO Need to do this in order to support mixins, should convert to public api + //once it exists in Ember + return typeClass.__mixin.detect(addedRecord.type.PrototypeMixin); + } + if (Ember.MODEL_FACTORY_INJECTIONS) { + typeClass = typeClass.superclass; + } + return typeClass.detect(addedRecord.type); +} + +export { + assertPolymorphicType +}; diff --git a/packages/ember-data/tests/unit/utils-test.js b/packages/ember-data/tests/unit/utils-test.js new file mode 100644 index 00000000000..6e9e1a0f4e0 --- /dev/null +++ b/packages/ember-data/tests/unit/utils-test.js @@ -0,0 +1,107 @@ +// TODO enable import once this is possible +// import { assertPolymorphicType } from "ember-data/utils"; + +var env, User, Message, Post, Person, Video, Medium; + +module("unit/utils", { + setup() { + Person = DS.Model.extend(); + User = DS.Model.extend({ + messages: DS.hasMany('message') + }); + + Message = DS.Model.extend(); + Post = Message.extend({ + medias: DS.hasMany('medium') + }); + + Medium = Ember.Mixin.create(); + Video = DS.Model.extend(Medium); + + env = setupStore({ + user: User, + person: Person, + message: Message, + post: Post, + video: Video + }); + + env.registry.register('mixin:medium', Medium); + }, + + teardown() { + Ember.run(env.container, 'destroy'); + } +}); + +test("assertPolymorphicType works for subclasses", function() { + var user, post, person; + + Ember.run(function() { + user = env.store.push('user', { id: 1, messages: [] }); + post = env.store.push('post', { id: 1 }); + person = env.store.push('person', { id: 1 }); + }); + + // TODO un-comment once we test the assertPolymorphicType directly + // var relationship = user.relationshipFor('messages'); + // user = user._internalModel; + // post = post._internalModel; + // person = person._internalModel; + + try { + Ember.run(function() { + user.get('messages').addObject(post); + }); + + // TODO enable once we can do "import { assertPolymorphicType } from "ember-data/utils" + // assertPolymorphicType(user, relationship, post); + } catch (e) { + ok(false, "should not throw an error"); + } + + expectAssertion(function() { + Ember.run(function() { + user.get('messages').addObject(person); + }); + + // TODO enable once we can do "import { assertPolymorphicType } from "ember-data/utils" + // assertPolymorphicType(user, relationship, person); + }, "You cannot add a record of type 'person' to the 'user.messages' relationship (only 'message' allowed)"); +}); + +test("assertPolymorphicType works for mixins", function() { + var post, video, person; + + Ember.run(function() { + post = env.store.push('post', { id: 1 }); + video = env.store.push('video', { id: 1 }); + person = env.store.push('person', { id: 1 }); + }); + + // TODO un-comment once we test the assertPolymorphicType directly + // var relationship = post.relationshipFor('medias'); + // post = post._internalModel; + // video = video._internalModel; + // person = person._internalModel; + + try { + Ember.run(function() { + post.get('medias').addObject(video); + }); + + // TODO enable once we can do "import { assertPolymorphicType } from "ember-data/utils" + // assertPolymorphicType(post, relationship, video); + } catch (e) { + ok(false, "should not throw an error"); + } + + expectAssertion(function() { + Ember.run(function() { + post.get('medias').addObject(person); + }); + + // TODO enable once we can do "import { assertPolymorphicType } from "ember-data/utils" + // assertPolymorphicType(post, relationship, person); + }, "You cannot add a record of type 'person' to the 'post.medias' relationship (only 'medium' allowed)"); +}); From 72991b8747d868f50cff9ec4a887c27a9baaa607 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 11 Jun 2015 23:57:31 +0200 Subject: [PATCH 0929/2527] Use assertPolymorphicType in belongs-to/has-many relationship states This also unifies the assertion messages, so the assertions for adding a (polymorphic) record to the belongs-to and has-many relationship is the same for both cases. --- .../lib/system/relationships/state/belongs-to.js | 16 ++++------------ .../lib/system/relationships/state/has-many.js | 13 +++---------- .../integration/relationships/belongs-to-test.js | 4 ++-- .../integration/relationships/has-many-test.js | 4 ++-- .../polymorphic-mixins-belongs-to-test.js | 4 ++-- .../polymorphic-mixins-has-many-test.js | 4 ++-- 6 files changed, 15 insertions(+), 30 deletions(-) diff --git a/packages/ember-data/lib/system/relationships/state/belongs-to.js b/packages/ember-data/lib/system/relationships/state/belongs-to.js index 8714d545024..0e2eb995c0d 100644 --- a/packages/ember-data/lib/system/relationships/state/belongs-to.js +++ b/packages/ember-data/lib/system/relationships/state/belongs-to.js @@ -2,6 +2,8 @@ import { PromiseObject } from "ember-data/system/promise-proxies"; +import { assertPolymorphicType } from "ember-data/utils"; + import Relationship from "ember-data/system/relationships/state/relationship"; var BelongsToRelationship = function(store, record, inverseKey, relationshipMeta) { @@ -61,18 +63,8 @@ BelongsToRelationship.prototype.flushCanonical = function() { BelongsToRelationship.prototype._super$addRecord = Relationship.prototype.addRecord; BelongsToRelationship.prototype.addRecord = function(newRecord) { if (this.members.has(newRecord)) { return;} - var typeClass = this.store.modelFor(this.relationshipMeta.type); - Ember.assert("You cannot add a '" + newRecord.type.modelName + "' record to the '" + this.record.type.modelName + "." + this.key +"'. " + "You can only add a '" + typeClass.modelName + "' record to this relationship.", (function () { - if (typeClass.__isMixin) { - //TODO Need to do this in order to support mixins, should convert to public api - //once it exists in Ember - return typeClass.__mixin.detect(newRecord.type.PrototypeMixin); - } - if (Ember.MODEL_FACTORY_INJECTIONS) { - typeClass = typeClass.superclass; - } - return typeClass.detect(newRecord.type); - })()); + + assertPolymorphicType(this.record, this.relationshipMeta, newRecord); if (this.inverseRecord) { this.removeRecord(this.inverseRecord); diff --git a/packages/ember-data/lib/system/relationships/state/has-many.js b/packages/ember-data/lib/system/relationships/state/has-many.js index 3f98b3ed502..14be1d10aeb 100644 --- a/packages/ember-data/lib/system/relationships/state/has-many.js +++ b/packages/ember-data/lib/system/relationships/state/has-many.js @@ -3,6 +3,8 @@ import Relationship from "ember-data/system/relationships/state/relationship"; import OrderedSet from "ember-data/system/ordered-set"; import ManyArray from "ember-data/system/many-array"; +import { assertPolymorphicType } from "ember-data/utils"; + var map = Ember.EnumerableUtils.map; var ManyRelationship = function(store, record, inverseKey, relationshipMeta) { @@ -92,16 +94,7 @@ ManyRelationship.prototype.removeRecordFromOwn = function(record, idx) { }; ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) { - var typeClass = this.store.modelFor(this.relationshipMeta.type); - Ember.assert("You cannot add '" + record.type.modelName + "' records to the " + this.record.type.modelName + "." + this.key + " relationship (only '" + typeClass.modelName + "' allowed)", (function () { - if (typeClass.__isMixin) { - return typeClass.__mixin.detect(record.type.PrototypeMixin); - } - if (Ember.MODEL_FACTORY_INJECTIONS) { - typeClass = typeClass.superclass; - } - return typeClass.detect(record.type); - })()); + assertPolymorphicType(this.record, this.relationshipMeta, record); this.record.notifyHasManyAdded(this.key, record, idx); }; diff --git a/packages/ember-data/tests/integration/relationships/belongs-to-test.js b/packages/ember-data/tests/integration/relationships/belongs-to-test.js index c021f5f1df2..e3621acc3bf 100644 --- a/packages/ember-data/tests/integration/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/integration/relationships/belongs-to-test.js @@ -142,7 +142,7 @@ test("Only a record of the same type can be used with a monomorphic belongsTo re }).then(function(records) { expectAssertion(function() { records.post.set('user', records.comment); - }, /You can only add a 'user' record to this relationship/); + }, /You cannot add a record of type 'comment' to the 'post.user' relationship/); }); }); }); @@ -173,7 +173,7 @@ test("Only a record of the same base type can be used with a polymorphic belongs expectAssertion(function() { comment.set('message', records.user); - }, /You cannot add a 'user' record to the 'comment.message'. You can only add a 'message' record to this relationship./); + }, /You cannot add a record of type 'user' to the 'comment.message' relationship \(only 'message' allowed\)/); }); }); }); diff --git a/packages/ember-data/tests/integration/relationships/has-many-test.js b/packages/ember-data/tests/integration/relationships/has-many-test.js index 38ad0ca5d1e..8c9fd1a6c68 100644 --- a/packages/ember-data/tests/integration/relationships/has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/has-many-test.js @@ -782,7 +782,7 @@ test("Only records of the same type can be added to a monomorphic hasMany relati ]).then(function(records) { expectAssertion(function() { records[0].get('comments').pushObject(records[1]); - }, /You cannot add 'post' records to the post.comments relationship \(only 'comment' allowed\)/); + }, /You cannot add a record of type 'post' to the 'post.comments' relationship \(only 'comment' allowed\)/); }); }); }); @@ -815,7 +815,7 @@ test("Only records of the same base type can be added to a polymorphic hasMany r expectAssertion(function() { records.messages.pushObject(records.anotherUser); - }, /You cannot add 'user' records to the user.messages relationship \(only 'message' allowed\)/); + }, /You cannot add a record of type 'user' to the 'user.messages' relationship \(only 'message' allowed\)/); }); }); }); diff --git a/packages/ember-data/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/packages/ember-data/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index f3977b596b2..d9b7fcb0657 100644 --- a/packages/ember-data/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/packages/ember-data/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -96,7 +96,7 @@ test("Setting the polymorphic belongsTo with an object that does not implement t run(function() { expectAssertion(function() { user.set('bestMessage', video); - }, /You can only add a 'message' record to this relationship/); + }, /You cannot add a record of type 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); }); }); @@ -141,7 +141,7 @@ test("Setting the polymorphic belongsTo with an object that does not implement t run(function() { expectAssertion(function() { user.set('bestMessage', video); - }, /You can only add a 'message' record to this relationship/); + }, /You cannot add a record of type 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); }); } finally { Ember.MODEL_FACTORY_INJECTIONS = injectionValue; diff --git a/packages/ember-data/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/packages/ember-data/tests/integration/relationships/polymorphic-mixins-has-many-test.js index 5cd8d528b60..b9a5602650a 100644 --- a/packages/ember-data/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -100,7 +100,7 @@ test("Pushing a an object that does not implement the mixin to the mixin accepti user.get('messages').then(function(fetchedMessages) { expectAssertion(function() { fetchedMessages.pushObject(notMessage); - }, /You cannot add 'not-message' records to the user\.messages relationship \(only 'message' allowed\)/); + }, /You cannot add a record of type 'not-message' to the 'user.messages' relationship \(only 'message' allowed\)/); }); }); }); @@ -147,7 +147,7 @@ test("Pushing a an object that does not implement the mixin to the mixin accepti user.get('messages').then(function(fetchedMessages) { expectAssertion(function() { fetchedMessages.pushObject(notMessage); - }, /You cannot add 'not-message' records to the user\.messages relationship \(only 'message' allowed\)/); + }, /You cannot add a record of type 'not-message' to the 'user.messages' relationship \(only 'message' allowed\)/); }); }); } finally { From 8437ce5f2635ab0f9848c1cacc449317695e4b91 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 12 Jun 2015 18:42:23 -0500 Subject: [PATCH 0930/2527] fix tests for IE8 --- packages/ember-data/lib/system/model/model.js | 8 +-- packages/ember-data/lib/system/snapshot.js | 9 ++-- .../deprecate-type-key-test.js | 18 ++++--- .../tests/integration/snapshot-test.js | 50 ++++++++++--------- packages/ember-data/tests/unit/model-test.js | 10 ++-- .../unit/model/rollback-attributes-test.js | 6 +-- 6 files changed, 56 insertions(+), 45 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 2f04fa8d913..ee2cac7819a 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -579,10 +579,12 @@ var Model = Ember.Object.extend(Ember.Evented, { var oldData = get(this._internalModel, '_data'); var newData = get(this._internalModel, '_attributes'); var diffData = Ember.create(null); - var prop; - for (prop in newData) { - diffData[prop] = [oldData[prop], newData[prop]]; + var newDataKeys = Ember.keys(newData); + + for (let i = 0, length = newDataKeys.length; i < length; i++) { + let key = newDataKeys[i]; + diffData[key] = [oldData[key], newData[key]]; } return diffData; diff --git a/packages/ember-data/lib/system/snapshot.js b/packages/ember-data/lib/system/snapshot.js index ece20c8d3c1..5018a7fa837 100644 --- a/packages/ember-data/lib/system/snapshot.js +++ b/packages/ember-data/lib/system/snapshot.js @@ -165,11 +165,12 @@ Snapshot.prototype = { @return {Object} All changed attributes of the current snapshot */ changedAttributes: function() { - var prop; - var changedAttributes = Ember.create(null); + let changedAttributes = Ember.create(null); + let changedAttributeKeys = Ember.keys(this._changedAttributes); - for (prop in this._changedAttributes) { - changedAttributes[prop] = Ember.copy(this._changedAttributes[prop]); + for (let i=0, length = changedAttributeKeys.length; i < length; i++) { + let key = changedAttributeKeys[i]; + changedAttributes[key] = Ember.copy(this._changedAttributes[key]); } return changedAttributes; diff --git a/packages/ember-data/tests/integration/backwards-compat/deprecate-type-key-test.js b/packages/ember-data/tests/integration/backwards-compat/deprecate-type-key-test.js index aa9db8dad1a..9341f9a5b00 100644 --- a/packages/ember-data/tests/integration/backwards-compat/deprecate-type-key-test.js +++ b/packages/ember-data/tests/integration/backwards-compat/deprecate-type-key-test.js @@ -11,14 +11,16 @@ module('integration/backwards-compat/deprecate-type-key', { } }); -test('typeKey is deprecated', function() { - expectDeprecation(function() { - return Post.typeKey; +if (Ember.platform.hasPropertyAccessors) { + test('typeKey is deprecated', function() { + expectDeprecation(function() { + return Post.typeKey; + }); }); -}); -test('setting typeKey is not allowed', function() { - throws(function() { - Post.typeKey = 'hello'; + test('setting typeKey is not allowed', function() { + throws(function() { + Post.typeKey = 'hello'; + }); }); -}); +} diff --git a/packages/ember-data/tests/integration/snapshot-test.js b/packages/ember-data/tests/integration/snapshot-test.js index b8c0fe5f45b..0f076532c74 100644 --- a/packages/ember-data/tests/integration/snapshot-test.js +++ b/packages/ember-data/tests/integration/snapshot-test.js @@ -67,24 +67,26 @@ test("snapshot.id, snapshot.type and snapshot.modelName returns correctly", func }); }); -test("snapshot.constructor is unique and deprecated", function() { - expect(4); +if (Ember.platform.hasPropertyAccessors) { + test("snapshot.constructor is unique and deprecated", function() { + expect(4); - run(function() { - var comment = env.store.push('comment', { id: 1, body: 'This is comment' }); - var post = env.store.push('post', { id: 2, title: 'Hello World' }); - var commentSnapshot = comment._createSnapshot(); - var postSnapshot = post._createSnapshot(); + run(function() { + var comment = env.store.push('comment', { id: 1, body: 'This is comment' }); + var post = env.store.push('post', { id: 2, title: 'Hello World' }); + var commentSnapshot = comment._createSnapshot(); + var postSnapshot = post._createSnapshot(); - expectDeprecation(function() { - equal(commentSnapshot.constructor.modelName, 'comment', 'constructor.modelName is unique per type'); - }); + expectDeprecation(function() { + equal(commentSnapshot.constructor.modelName, 'comment', 'constructor.modelName is unique per type'); + }); - expectDeprecation(function() { - equal(postSnapshot.constructor.modelName, 'post', 'constructor.modelName is unique per type'); + expectDeprecation(function() { + equal(postSnapshot.constructor.modelName, 'post', 'constructor.modelName is unique per type'); + }); }); }); -}); +} test("snapshot.attr() does not change when record changes", function() { expect(2); @@ -135,7 +137,7 @@ test("snapshot.changedAttributes() returns a copy of all changed attributes for var changes = snapshot.changedAttributes(); - deepEqual(changes, { title: ['Hello World', 'Hello World!'] }, 'changed attributes are returned correctly'); + deepEqual(changes.title, ['Hello World', 'Hello World!'], 'changed attributes are returned correctly'); }); }); @@ -651,16 +653,18 @@ test("snapshot.serialize() serializes itself", function() { }); }); -test('snapshot.typeKey is deprecated', function() { - expect(1); +if (Ember.platform.hasPropertyAccessors) { + test('snapshot.typeKey is deprecated', function() { + expect(1); - run(function() { - var post = env.store.push('post', { id: 1, title: 'Hello World' }); - var snapshot = post._createSnapshot(); + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + var snapshot = post._createSnapshot(); - expectDeprecation(function() { - return snapshot.typeKey; + expectDeprecation(function() { + return snapshot.typeKey; + }); }); - }); -}); + }); +} diff --git a/packages/ember-data/tests/unit/model-test.js b/packages/ember-data/tests/unit/model-test.js index 29f20990bee..a1dfba3ac4b 100644 --- a/packages/ember-data/tests/unit/model-test.js +++ b/packages/ember-data/tests/unit/model-test.js @@ -191,7 +191,7 @@ test("it should cache attributes", function() { }); test("changedAttributes() return correct values", function() { - expect(3); + expect(4); var Mascot = DS.Model.extend({ name: DS.attr('string'), @@ -210,18 +210,20 @@ test("changedAttributes() return correct values", function() { mascot = store.push('mascot', { id: 1, likes: 'JavaScript', isMascot: true }); }); - deepEqual({}, mascot.changedAttributes(), 'there are no initial changes'); + equal(Ember.keys(mascot.changedAttributes()).length, 0, 'there are no initial changes'); run(function() { mascot.set('name', 'Tomster'); // new value mascot.set('likes', 'Ember.js'); // changed value mascot.set('isMascot', true); // same value }); - deepEqual({ name: [undefined, 'Tomster'], likes: ['JavaScript', 'Ember.js'] }, mascot.changedAttributes(), 'attributes has changed'); + var changedAttributes = mascot.changedAttributes(); + deepEqual(changedAttributes.name, [undefined, 'Tomster']); + deepEqual(changedAttributes.likes, ['JavaScript', 'Ember.js']); run(function() { mascot.rollbackAttributes(); }); - deepEqual({}, mascot.changedAttributes(), 'after rollback attributes there are no changes'); + equal(Ember.keys(mascot.changedAttributes()).length, 0, 'after rollback attributes there are no changes'); }); test("a DS.Model does not require an attribute type", function() { diff --git a/packages/ember-data/tests/unit/model/rollback-attributes-test.js b/packages/ember-data/tests/unit/model/rollback-attributes-test.js index 408305f306d..4f979dc28be 100644 --- a/packages/ember-data/tests/unit/model/rollback-attributes-test.js +++ b/packages/ember-data/tests/unit/model/rollback-attributes-test.js @@ -93,18 +93,18 @@ test("a record's changes can be made if it fails to save", function() { person.set('firstName', "Thomas"); }); - deepEqual(person.changedAttributes(), { firstName: ["Tom", "Thomas"] }); + deepEqual(person.changedAttributes().firstName, ["Tom", "Thomas"]); run(function() { person.save().then(null, function() { equal(person.get('isError'), true); - deepEqual(person.changedAttributes(), { firstName: ["Tom", "Thomas"] }); + deepEqual(person.changedAttributes().firstName, ["Tom", "Thomas"]); person.rollbackAttributes(); equal(person.get('firstName'), "Tom"); equal(person.get('isError'), false); - deepEqual(person.changedAttributes(), {}); + equal(Ember.keys(person.changedAttributes()).length, 0); }); }); }); From db928c7fca36138e6cb9ed4de4e7a713e3c1da36 Mon Sep 17 00:00:00 2001 From: Mikhail Topolskiy Date: Sat, 13 Jun 2015 12:57:24 +0300 Subject: [PATCH 0931/2527] Fix a typo in `rollback()` documentation --- packages/ember-data/lib/system/model/model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index ee2cac7819a..eb9f949223a 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -623,7 +623,7 @@ var Model = Ember.Object.extend(Ember.Evented, { ``` @method rollback - @deprecated Use `addAttributes()` instead + @deprecated Use `rollbackAttributes()` instead */ rollback: function() { Ember.deprecate('Using model.rollback() has been deprecated. Use model.rollbackAttributes() to discard any unsaved changes to a model.'); From f536223411c13b41aa7dc39a6247a2824f479a8e Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Mon, 22 Dec 2014 16:22:22 -0500 Subject: [PATCH 0932/2527] Add options hash to model.save --- packages/ember-data/lib/system/adapter.js | 3 +++ packages/ember-data/lib/system/model/model.js | 5 +++-- packages/ember-data/lib/system/store.js | 22 ++++++++++++------- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 33f2610067c..850eb00f3e7 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -282,6 +282,7 @@ var Adapter = Ember.Object.extend({ @param {DS.Store} store @param {DS.Model} type the DS.Model class of the record @param {DS.Snapshot} snapshot + @param {Object} options @return {Promise} promise */ createRecord: null, @@ -324,6 +325,7 @@ var Adapter = Ember.Object.extend({ @param {DS.Store} store @param {DS.Model} type the DS.Model class of the record @param {DS.Snapshot} snapshot + @param {Object} options @return {Promise} promise */ updateRecord: null, @@ -366,6 +368,7 @@ var Adapter = Ember.Object.extend({ @param {DS.Store} store @param {DS.Model} type the DS.Model class of the record @param {DS.Snapshot} snapshot + @param {Object} options @return {Promise} promise */ deleteRecord: null, diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index eb9f949223a..004f984f8cc 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -677,13 +677,14 @@ var Model = Ember.Object.extend(Ember.Evented, { }); ``` @method save + @param {Object} options a hash specifying save options sent to the server. @return {Promise} a promise that will be resolved when the adapter returns successfully or rejected if the adapter returns with an error. */ - save: function() { + save: function(options) { var model = this; return PromiseObject.create({ - promise: this._internalModel.save().then(function() { + promise: this._internalModel.save(options).then(function() { return model; }) }); diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 41460c9748a..fdbfdddd0da 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1349,12 +1349,17 @@ Store = Service.extend({ @private @param {InternalModel} internalModel @param {Resolver} resolver + @param {Object} options */ - scheduleSave: function(internalModel, resolver) { + scheduleSave: function(internalModel, resolver, options) { var snapshot = internalModel.createSnapshot(); internalModel.flushChangedAttributes(); internalModel.adapterWillCommit(); - this._pendingSave.push([snapshot, resolver]); + this._pendingSave.push({ + snapshot: snapshot, + response: resolver, + options: options + }); once(this, 'flushPendingSave'); }, @@ -1369,9 +1374,10 @@ Store = Service.extend({ var pending = this._pendingSave.slice(); this._pendingSave = []; - forEach(pending, function(tuple) { - var snapshot = tuple[0]; - var resolver = tuple[1]; + forEach(pending, function(pendingItem) { + var snapshot = pendingItem.snapshot; + var resolver = pendingItem.resolver; + var options = pendingItem.options; var record = snapshot._internalModel; var adapter = this.adapterFor(record.type.modelName); var operation; @@ -1386,7 +1392,7 @@ Store = Service.extend({ operation = 'updateRecord'; } - resolver.resolve(_commit(adapter, this, operation, snapshot)); + resolver.resolve(_commit(adapter, this, operation, snapshot, options)); }, this); }, @@ -2161,11 +2167,11 @@ function defaultSerializer(container) { container.lookup('serializer:-default'); } -function _commit(adapter, store, operation, snapshot) { +function _commit(adapter, store, operation, snapshot, options) { var record = snapshot._internalModel; var modelName = snapshot.modelName; var type = store.modelFor(modelName); - var promise = adapter[operation](store, type, snapshot); + var promise = adapter[operation](store, type, snapshot, options); // TODO check this out var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Extract and notify about " + operation + " completion of " + record; From aaa16d2bb46e8cc9e8cd55897259f1cb317de397 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 9 Jun 2015 17:42:37 -0400 Subject: [PATCH 0933/2527] Deprecate store:main and store:application and recommend users always use service:store`app/services/store.js` to prevent duplicate stores. --- packages/ember-data/lib/ember-initializer.js | 4 +-- .../lib/initializers/store-injections.js | 6 ++-- packages/ember-data/lib/initializers/store.js | 3 ++ .../initialize-store-service.js | 32 +++++++++++++++---- .../tests/integration/application-test.js | 4 +-- .../non-dasherized-lookups.js | 4 +-- .../tests/integration/debug-adapter-test.js | 2 +- .../tests/integration/multiple_stores_test.js | 2 +- .../tests/integration/setup-container-test.js | 22 ++++++++++++- 9 files changed, 61 insertions(+), 18 deletions(-) diff --git a/packages/ember-data/lib/ember-initializer.js b/packages/ember-data/lib/ember-initializer.js index f5782a05614..5520b118aa3 100644 --- a/packages/ember-data/lib/ember-initializer.js +++ b/packages/ember-data/lib/ember-initializer.js @@ -13,7 +13,7 @@ var K = Ember.K; This code initializes Ember-Data onto an Ember application. If an Ember.js developer defines a subclass of DS.Store on their application, - as `App.ApplicationStore` (or via a module system that resolves to `store:application`) + as `App.StoreService` (or via a module system that resolves to `service:store`) this code will automatically instantiate it and make it available on the router. @@ -22,7 +22,7 @@ var K = Ember.K; For example, imagine an Ember.js application with the following classes: - App.ApplicationStore = DS.Store.extend({ + App.StoreService = DS.Store.extend({ adapter: 'custom' }); diff --git a/packages/ember-data/lib/initializers/store-injections.js b/packages/ember-data/lib/initializers/store-injections.js index 16dca7f409b..7be3af772a6 100644 --- a/packages/ember-data/lib/initializers/store-injections.js +++ b/packages/ember-data/lib/initializers/store-injections.js @@ -6,7 +6,7 @@ @param {Ember.Registry} registry */ export default function initializeStoreInjections(registry) { - registry.injection('controller', 'store', 'store:main'); - registry.injection('route', 'store', 'store:main'); - registry.injection('data-adapter', 'store', 'store:main'); + registry.injection('controller', 'store', 'service:store'); + registry.injection('route', 'store', 'service:store'); + registry.injection('data-adapter', 'store', 'service:store'); } diff --git a/packages/ember-data/lib/initializers/store.js b/packages/ember-data/lib/initializers/store.js index 327ca307f40..654af83bb34 100644 --- a/packages/ember-data/lib/initializers/store.js +++ b/packages/ember-data/lib/initializers/store.js @@ -17,6 +17,9 @@ export default function initializeStore(registry, application) { registry.optionsForType('serializer', { singleton: false }); registry.optionsForType('adapter', { singleton: false }); + // This will get deprecated later in the instace + // initializer. However we register it here so we have access to + // application.Store in the instance initializer. if (application && application.Store) { registry.register('store:application', application.Store); } diff --git a/packages/ember-data/lib/instance-initializers/initialize-store-service.js b/packages/ember-data/lib/instance-initializers/initialize-store-service.js index 54f6b962519..a74bf77cb1a 100644 --- a/packages/ember-data/lib/instance-initializers/initialize-store-service.js +++ b/packages/ember-data/lib/instance-initializers/initialize-store-service.js @@ -1,4 +1,6 @@ import Store from "ember-data/system/store"; +import ContainerProxy from "ember-data/system/container-proxy"; + /** Configures a registry for use with an Ember-Data store. @@ -25,14 +27,32 @@ export default function initializeStoreService(applicationOrRegistry) { container = registry; } } + + // Eagerly generate the store so defaultStore is populated. + var store; + if (registry.has('store:main')) { + Ember.deprecate('Registering a custom store as `store:main` or defining a store in app/store.js has been deprecated. Please move you store to `service:store` or define your custom store in `app/services/store.js`'); + store = container.lookup('store:main'); + } else { + var storeMainProxy = new ContainerProxy(registry); + storeMainProxy.registerDeprecations([ + { deprecated: 'store:main', valid: 'service:store' } + ]); + } + if (registry.has('store:application')) { - var customStoreFactory = container.lookupFactory('store:application'); - registry.register('store:main', customStoreFactory); + Ember.deprecate('Registering a custom store as `store:application` or defining a store in app/stores/application.js has been deprecated. Please move you store to `service:store` or define your custom store in `app/services/store.js`'); + store = container.lookup('store:application'); } else { - registry.register('store:main', Store); + var storeApplicationProxy = new ContainerProxy(registry); + storeApplicationProxy.registerDeprecations([ + { deprecated: 'store:application', valid: 'service:store' } + ]); } - // Eagerly generate the store so defaultStore is populated. - var store = container.lookup('store:main'); - registry.register('service:store', store, { instantiate: false }); + if (store) { + registry.register('service:store', store, { instantiate: false }); + } else { + registry.register('service:store', Store); + } } diff --git a/packages/ember-data/tests/integration/application-test.js b/packages/ember-data/tests/integration/application-test.js index 31ffb01e93b..3e08370ecfc 100644 --- a/packages/ember-data/tests/integration/application-test.js +++ b/packages/ember-data/tests/integration/application-test.js @@ -13,7 +13,7 @@ var app, App, container; */ function getStore() { - return lookup('store:main'); + return lookup('service:store'); } function lookup(thing) { @@ -69,7 +69,7 @@ test("registering App.Store is deprecated but functional", function() { 'has been deprecated. Please use `App.ApplicationStore` instead.'); run(function() { - ok(lookup('store:main').get('isCustomButDeprecated'), "the custom store was instantiated"); + ok(lookup('service:store').get('isCustomButDeprecated'), "the custom store was instantiated"); }); var fooController = lookup('controller:foo'); diff --git a/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js b/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js index 531f35da9e2..964a22dc18c 100644 --- a/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js +++ b/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups.js @@ -9,7 +9,7 @@ module('integration/backwards-compat/non-dasherized-lookups - non dasherized loo name: DS.attr() }); }); - store = App.__container__.lookup('store:main'); + store = App.__container__.lookup('service:store'); }, teardown: function() { run(App, 'destroy'); @@ -67,7 +67,7 @@ module('integration/backwards-compat/non-dasherized-lookups - non dasherized loo postNotes: DS.hasMany('post_note') }); }); - store = App.__container__.lookup('store:main'); + store = App.__container__.lookup('service:store'); }, teardown: function() { diff --git a/packages/ember-data/tests/integration/debug-adapter-test.js b/packages/ember-data/tests/integration/debug-adapter-test.js index 7ea659afc43..17322cc66cf 100644 --- a/packages/ember-data/tests/integration/debug-adapter-test.js +++ b/packages/ember-data/tests/integration/debug-adapter-test.js @@ -23,7 +23,7 @@ module("DS.DebugAdapter", { }); - store = App.__container__.lookup('store:main'); + store = App.__container__.lookup('service:store'); debugAdapter = App.__container__.lookup('data-adapter:main'); debugAdapter.reopen({ diff --git a/packages/ember-data/tests/integration/multiple_stores_test.js b/packages/ember-data/tests/integration/multiple_stores_test.js index badc61087e4..af39000faf3 100644 --- a/packages/ember-data/tests/integration/multiple_stores_test.js +++ b/packages/ember-data/tests/integration/multiple_stores_test.js @@ -118,7 +118,7 @@ test("embedded records should be created in multiple stores", function() { run(function() { json_main = serializer_main.extractSingle(env.store, env.store.modelFor('home-planet'), json_hash_main); - equal(env.store.hasRecordForId('super-villain', "1"), true, "superVillain should exist in store:main"); + equal(env.store.hasRecordForId('super-villain', "1"), true, "superVillain should exist in service:store"); }); run(function() { diff --git a/packages/ember-data/tests/integration/setup-container-test.js b/packages/ember-data/tests/integration/setup-container-test.js index 724f6537bcc..12506357a32 100644 --- a/packages/ember-data/tests/integration/setup-container-test.js +++ b/packages/ember-data/tests/integration/setup-container-test.js @@ -30,7 +30,7 @@ module("integration/setup-container - Setting up a container", { }); test("The store should be registered into a container.", function() { - ok(container.lookup('store:main') instanceof Store, "the custom store is instantiated"); + ok(container.lookup('service:store') instanceof Store, "the custom store is instantiated"); }); test("The store should be registered into the container as a service.", function() { @@ -86,6 +86,26 @@ test("serializers are not returned as singletons - each lookup should return a d notEqual(serializer1, serializer2); }); +test("the deprecated store:main is resolved as service:store", function() { + var deprecated; + var valid = container.lookup('service:store'); + expectDeprecation(function() { + deprecated = container.lookup('store:main'); + }); + + ok(deprecated.constructor === valid.constructor, "they should resolve to the same thing"); +}); + +test("the deprecated store:application is resolved as service:store", function() { + var deprecated; + var valid = container.lookup('service:store'); + expectDeprecation(function() { + deprecated = container.lookup('store:application'); + }); + + ok(deprecated.constructor === valid.constructor, "they should resolve to the same thing"); +}); + test("adapters are not returned as singletons - each lookup should return a different instance", function() { var adapter1, adapter2; adapter1 = container.lookup('adapter:-rest'); From 059ec88cbc3a71a698f7a8952e2e8022d927c36e Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 9 Jun 2015 14:33:57 -0400 Subject: [PATCH 0934/2527] Allow the store to pass options to the adapter via a snapshot Add a SnapshotRecordArray object used for passing snapshots, meta and adapterOptions to the adapter. --- packages/ember-data/lib/system/adapter.js | 4 +- .../lib/system/model/internal-model.js | 11 +-- packages/ember-data/lib/system/model/model.js | 7 +- .../lib/system/snapshot-record-array.js | 44 ++++++++++++ packages/ember-data/lib/system/store.js | 59 +++++++-------- .../ember-data/lib/system/store/finders.js | 12 ++-- .../integration/adapter/store-adapter-test.js | 71 +++++++++++++++++++ 7 files changed, 165 insertions(+), 43 deletions(-) create mode 100644 packages/ember-data/lib/system/snapshot-record-array.js diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 850eb00f3e7..1ee98a0c2ba 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -151,6 +151,7 @@ var Adapter = Ember.Object.extend({ @param {DS.Store} store @param {DS.Model} type @param {String} sinceToken + @param {DS.SnapshotRecordArray} snapshotRecordArray @return {Promise} promise */ findAll: null, @@ -282,7 +283,6 @@ var Adapter = Ember.Object.extend({ @param {DS.Store} store @param {DS.Model} type the DS.Model class of the record @param {DS.Snapshot} snapshot - @param {Object} options @return {Promise} promise */ createRecord: null, @@ -325,7 +325,6 @@ var Adapter = Ember.Object.extend({ @param {DS.Store} store @param {DS.Model} type the DS.Model class of the record @param {DS.Snapshot} snapshot - @param {Object} options @return {Promise} promise */ updateRecord: null, @@ -368,7 +367,6 @@ var Adapter = Ember.Object.extend({ @param {DS.Store} store @param {DS.Model} type the DS.Model class of the record @param {DS.Snapshot} snapshot - @param {Object} options @return {Promise} promise */ deleteRecord: null, diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js index 14d782019ef..0f33c5c2187 100644 --- a/packages/ember-data/lib/system/model/internal-model.js +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -127,11 +127,11 @@ InternalModel.prototype = { this.send('deleteRecord'); }, - save: function() { + save: function(options) { var promiseLabel = "DS: Model#save " + this; var resolver = Ember.RSVP.defer(promiseLabel); - this.store.scheduleSave(this, resolver); + this.store.scheduleSave(this, resolver, options); return resolver.promise; }, @@ -221,8 +221,11 @@ InternalModel.prototype = { @method createSnapshot @private */ - createSnapshot: function() { - return new Snapshot(this); + createSnapshot: function(options) { + var adapterOptions = options && options.adapterOptions; + var snapshot = new Snapshot(this); + snapshot.adapterOptions = adapterOptions; + return snapshot; }, /** diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 004f984f8cc..99f8cb1423c 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -519,12 +519,13 @@ var Model = Ember.Object.extend(Ember.Evented, { ``` @method destroyRecord + @param {Object} options @return {Promise} a promise that will be resolved when the adapter returns successfully or rejected if the adapter returns with an error. */ - destroyRecord: function() { + destroyRecord: function(options) { this.deleteRecord(); - return this.save(); + return this.save(options); }, /** @@ -677,7 +678,7 @@ var Model = Ember.Object.extend(Ember.Evented, { }); ``` @method save - @param {Object} options a hash specifying save options sent to the server. + @param {Object} options @return {Promise} a promise that will be resolved when the adapter returns successfully or rejected if the adapter returns with an error. */ diff --git a/packages/ember-data/lib/system/snapshot-record-array.js b/packages/ember-data/lib/system/snapshot-record-array.js new file mode 100644 index 00000000000..e84aba68aad --- /dev/null +++ b/packages/ember-data/lib/system/snapshot-record-array.js @@ -0,0 +1,44 @@ +/** + @module ember-data +*/ + +/** + @class SnapshotRecordArray + @namespace DS + @private + @constructor + @param {Array} snapshots An array of snapshots + @param {Object} meta +*/ +function SnapshotRecordArray(recordArray, meta, adapterOptions) { + this._snapshots = null; + this._recordArray = recordArray; + this.length = recordArray.get('length'); + this.meta = meta; + this.adapterOptions = adapterOptions; +} + +/** + @method fromRecordArray + @private + @static + @param {DS.RecordArray} recordArray + @param {Object} adapterOptions + @return SnapshotRecordArray +*/ +SnapshotRecordArray.fromRecordArray = function(recordArray, adapterOptions) { + var meta = recordArray.get('meta'); + return new SnapshotRecordArray(recordArray, meta, adapterOptions); +}; + +SnapshotRecordArray.prototype.snapshots = function() { + if (this._snapshots) { + return this._snapshots; + } + var recordArray = this._recordArray; + this._snapshots = recordArray.invoke('createSnapshot'); + + return this._snapshots; +}; + +export default SnapshotRecordArray; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index fdbfdddd0da..3b746779f8c 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -605,7 +605,7 @@ Store = Service.extend({ } if (internalModel.isEmpty()) { - fetchedInternalModel = this.scheduleFetch(internalModel); + fetchedInternalModel = this.scheduleFetch(internalModel, options); //TODO double check about reloading } else if (internalModel.isLoading()) { fetchedInternalModel = internalModel._loadingPromise; @@ -641,8 +641,9 @@ Store = Service.extend({ @private @param {InternalModel} internalModel model @return {Promise} promise - */ - fetchRecord: function(internalModel) { + */ + // TODO rename this to have an underscore + fetchRecord: function(internalModel, options) { var typeClass = internalModel.type; var id = internalModel.id; var adapter = this.adapterFor(typeClass.modelName); @@ -650,7 +651,7 @@ Store = Service.extend({ Ember.assert("You tried to find a record but you have no adapter (for " + typeClass + ")", adapter); Ember.assert("You tried to find a record but your adapter (for " + typeClass + ") does not implement 'find'", typeof adapter.find === 'function'); - var promise = _find(adapter, this, typeClass, id, internalModel); + var promise = _find(adapter, this, typeClass, id, internalModel, options); return promise; }, @@ -659,24 +660,25 @@ Store = Service.extend({ return Promise.all(map(internalModels, this.scheduleFetch, this)); }, - scheduleFetch: function(internalModel) { + scheduleFetch: function(internalModel, options) { var typeClass = internalModel.type; if (internalModel._loadingPromise) { return internalModel._loadingPromise; } var resolver = Ember.RSVP.defer('Fetching ' + typeClass + 'with id: ' + internalModel.id); - var recordResolverPair = { + var pendingFetchItem = { record: internalModel, - resolver: resolver + resolver: resolver, + options: options }; var promise = resolver.promise; internalModel.loadingData(promise); if (!this._pendingFetch.get(typeClass)) { - this._pendingFetch.set(typeClass, [recordResolverPair]); + this._pendingFetch.set(typeClass, [pendingFetchItem]); } else { - this._pendingFetch.get(typeClass).push(recordResolverPair); + this._pendingFetch.get(typeClass).push(pendingFetchItem); } Ember.run.scheduleOnce('afterRender', this, this.flushAllPendingFetches); @@ -692,19 +694,19 @@ Store = Service.extend({ this._pendingFetch = Map.create(); }, - _flushPendingFetchForType: function (recordResolverPairs, typeClass) { + _flushPendingFetchForType: function (pendingFetchItems, typeClass) { var store = this; var adapter = store.adapterFor(typeClass.modelName); var shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; - var records = Ember.A(recordResolverPairs).mapBy('record'); + var records = Ember.A(pendingFetchItems).mapBy('record'); function _fetchRecord(recordResolverPair) { - recordResolverPair.resolver.resolve(store.fetchRecord(recordResolverPair.record)); + recordResolverPair.resolver.resolve(store.fetchRecord(recordResolverPair.record, recordResolverPair.options)); // TODO adapter options } function resolveFoundRecords(records) { forEach(records, function(record) { - var pair = Ember.A(recordResolverPairs).findBy('record', record); + var pair = Ember.A(pendingFetchItems).findBy('record', record); if (pair) { var resolver = pair.resolver; resolver.resolve(record); @@ -734,7 +736,7 @@ Store = Service.extend({ function rejectRecords(records, error) { forEach(records, function(record) { - var pair = Ember.A(recordResolverPairs).findBy('record', record); + var pair = Ember.A(pendingFetchItems).findBy('record', record); if (pair) { var resolver = pair.resolver; resolver.reject(error); @@ -742,8 +744,8 @@ Store = Service.extend({ }); } - if (recordResolverPairs.length === 1) { - _fetchRecord(recordResolverPairs[0]); + if (pendingFetchItems.length === 1) { + _fetchRecord(pendingFetchItems[0]); } else if (shouldCoalesce) { // TODO: Improve records => snapshots => records => snapshots @@ -769,14 +771,14 @@ Store = Service.extend({ then(makeMissingRecordsRejector(requestedRecords)). then(null, makeRecordsRejector(requestedRecords)); } else if (ids.length === 1) { - var pair = Ember.A(recordResolverPairs).findBy('record', groupOfRecords[0]); + var pair = Ember.A(pendingFetchItems).findBy('record', groupOfRecords[0]); _fetchRecord(pair); } else { Ember.assert("You cannot return an empty array from adapter's method groupRecordsForFindMany", false); } }); } else { - forEach(recordResolverPairs, _fetchRecord); + forEach(pendingFetchItems, _fetchRecord); } }, @@ -1043,13 +1045,14 @@ Store = Service.extend({ @method findAll @param {String} modelName + @param {Object} options @return {DS.AdapterPopulatedRecordArray} */ - findAll: function(modelName) { + findAll: function(modelName, options) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); - return this._fetchAll(typeClass, this.peekAll(modelName)); + return this._fetchAll(typeClass, this.peekAll(modelName), options); }, /** @@ -1059,7 +1062,7 @@ Store = Service.extend({ @param {DS.RecordArray} array @return {Promise} promise */ - _fetchAll: function(typeClass, array) { + _fetchAll: function(typeClass, array, options) { var adapter = this.adapterFor(typeClass.modelName); var sinceToken = this.typeMapFor(typeClass).metadata.since; @@ -1068,7 +1071,7 @@ Store = Service.extend({ Ember.assert("You tried to load all records but you have no adapter (for " + typeClass + ")", adapter); Ember.assert("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function'); - return promiseArray(_findAll(adapter, this, typeClass, sinceToken)); + return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); }, /** @@ -1352,13 +1355,12 @@ Store = Service.extend({ @param {Object} options */ scheduleSave: function(internalModel, resolver, options) { - var snapshot = internalModel.createSnapshot(); + var snapshot = internalModel.createSnapshot(options); internalModel.flushChangedAttributes(); internalModel.adapterWillCommit(); this._pendingSave.push({ snapshot: snapshot, - response: resolver, - options: options + resolver: resolver }); once(this, 'flushPendingSave'); }, @@ -1377,7 +1379,6 @@ Store = Service.extend({ forEach(pending, function(pendingItem) { var snapshot = pendingItem.snapshot; var resolver = pendingItem.resolver; - var options = pendingItem.options; var record = snapshot._internalModel; var adapter = this.adapterFor(record.type.modelName); var operation; @@ -1392,7 +1393,7 @@ Store = Service.extend({ operation = 'updateRecord'; } - resolver.resolve(_commit(adapter, this, operation, snapshot, options)); + resolver.resolve(_commit(adapter, this, operation, snapshot)); }, this); }, @@ -2167,11 +2168,11 @@ function defaultSerializer(container) { container.lookup('serializer:-default'); } -function _commit(adapter, store, operation, snapshot, options) { +function _commit(adapter, store, operation, snapshot) { var record = snapshot._internalModel; var modelName = snapshot.modelName; var type = store.modelFor(modelName); - var promise = adapter[operation](store, type, snapshot, options); // TODO check this out + var promise = adapter[operation](store, type, snapshot); var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Extract and notify about " + operation + " completion of " + record; diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index 2d156f476b4..8e57bf31c6c 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -13,11 +13,13 @@ import { serializerForAdapter } from "ember-data/system/store/serializers"; +import SnapshotRecordArray from "ember-data/system/snapshot-record-array"; + var Promise = Ember.RSVP.Promise; var map = Ember.EnumerableUtils.map; -export function _find(adapter, store, typeClass, id, internalModel) { - var snapshot = internalModel.createSnapshot(); +export function _find(adapter, store, typeClass, id, internalModel, options) { + var snapshot = internalModel.createSnapshot(options); var promise = adapter.find(store, typeClass, id, snapshot); var serializer = serializerForAdapter(store, adapter, internalModel.type.modelName); var label = "DS: Handle Adapter#find of " + typeClass + " with id: " + id; @@ -118,9 +120,11 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship }, null, "DS: Extract payload of " + internalModel + " : " + relationship.type); } -export function _findAll(adapter, store, typeClass, sinceToken) { - var promise = adapter.findAll(store, typeClass, sinceToken); +export function _findAll(adapter, store, typeClass, sinceToken, options) { + var adapterOptions = options && options.adapterOptions; var modelName = typeClass.modelName; + var snapshotArray = SnapshotRecordArray.fromRecordArray(store.peekAll(modelName), adapterOptions); + var promise = adapter.findAll(store, typeClass, sinceToken, snapshotArray); var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Handle Adapter#findAll of " + typeClass; diff --git a/packages/ember-data/tests/integration/adapter/store-adapter-test.js b/packages/ember-data/tests/integration/adapter/store-adapter-test.js index 06ab28ce357..8bb2bcd604e 100644 --- a/packages/ember-data/tests/integration/adapter/store-adapter-test.js +++ b/packages/ember-data/tests/integration/adapter/store-adapter-test.js @@ -947,3 +947,74 @@ test("findBelongsTo receives a snapshot", function() { person.get('dog'); }); }); + +test("record.save should pass adapterOptions to the updateRecord method", function() { + expect(1); + + env.adapter.updateRecord = async(function(store, type, snapshot) { + deepEqual(snapshot.adapterOptions, { subscribe: true }); + return Ember.RSVP.resolve({ id: 1 }); + }); + + run(function() { + var person = store.push('person', { id: 1, name: 'Tom' }); + person.save({ adapterOptions: { subscribe: true } }); + }); +}); + +test("record.save should pass adapterOptions to the createRecord method", function() { + expect(1); + + env.adapter.createRecord = async(function(store, type, snapshot) { + deepEqual(snapshot.adapterOptions, { subscribe: true }); + return Ember.RSVP.resolve({ id: 1 }); + }); + + run(function() { + var person = store.createRecord('person', { name: 'Tom' }); + person.save({ adapterOptions: { subscribe: true } }); + }); +}); + +test("record.save should pass adapterOptions to the deleteRecord method", function() { + expect(1); + + env.adapter.deleteRecord = async(function(store, type, snapshot) { + deepEqual(snapshot.adapterOptions, { subscribe: true }); + return Ember.RSVP.resolve({ id: 1 }); + }); + + run(function() { + var person = store.push('person', { id: 1, name: 'Tom' }); + person.destroyRecord({ adapterOptions: { subscribe: true } }); + }); +}); + + +test("findRecord should pass adapterOptions to the find method", function() { + expect(1); + + env.adapter.find = async(function(store, type, id, snapshot) { + deepEqual(snapshot.adapterOptions, { query: { embed: true } }); + return Ember.RSVP.resolve({ id: 1 }); + }); + + run(function() { + store.findRecord('person', 1, { adapterOptions: { query: { embed: true } } }); + }); +}); + + +test("findAll should pass adapterOptions to the findAll method", function() { + expect(1); + + env.adapter.findAll = async(function(store, type, sinceToken, arraySnapshot) { + var adapterOptions = arraySnapshot.adapterOptions; + deepEqual(adapterOptions, { query: { embed: true } }); + return Ember.RSVP.resolve([{ id: 1 }]); + }); + + run(function() { + store.findAll('person', { adapterOptions: { query: { embed: true } } }); + }); +}); From c332708d46af30101ce120ed8d4f2455af169068 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Sat, 13 Jun 2015 18:00:49 +0900 Subject: [PATCH 0935/2527] Allow ember-source 2.x Close https://github.com/emberjs/data/issues/3252 --- ember-data-source.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ember-data-source.gemspec b/ember-data-source.gemspec index 8d254a6b576..59eec65e4eb 100644 --- a/ember-data-source.gemspec +++ b/ember-data-source.gemspec @@ -12,7 +12,7 @@ Gem::Specification.new do |gem| gem.version = Ember::Data::VERSION gem.license = "MIT" - gem.add_dependency "ember-source", "~> 1.8" + gem.add_dependency "ember-source", ">= 1.8", "< 3.0" gem.files = %w(package.json) + Dir['dist/ember-data*.js', 'dist/ember-data.js.map', 'lib/ember/data/*.rb'] end From bf57ab44a513378183c130ac2b470e7e059dcf3f Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 10 Jun 2015 13:56:23 -0400 Subject: [PATCH 0936/2527] Deprecate the store.fetch APIs and replace them will an reload option on `store.find`/`store.findAll`. Conflicts: packages/ember-data/lib/system/record-arrays/record-array.js --- .../lib/system/record-arrays/record-array.js | 3 +- packages/ember-data/lib/system/store.js | 88 +++++++++++++------ .../tests/integration/store-test.js | 16 ++-- 3 files changed, 70 insertions(+), 37 deletions(-) diff --git a/packages/ember-data/lib/system/record-arrays/record-array.js b/packages/ember-data/lib/system/record-arrays/record-array.js index 1cacadb1cee..abd8d79b6b5 100644 --- a/packages/ember-data/lib/system/record-arrays/record-array.js +++ b/packages/ember-data/lib/system/record-arrays/record-array.js @@ -115,8 +115,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { var store = get(this, 'store'); var modelName = get(this, 'type.modelName'); - // TODO change this to store.findAll(modelName, { reload: true }); - return store.findAll(modelName); + return store.findAll(modelName, { reload: true }); }, /** diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 3b746779f8c..24693bbff89 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -501,26 +501,8 @@ Store = Service.extend({ /** This method returns a fresh record for a given type and id combination. - If a record is available for the given type/id combination, then - it will fetch this record from the store and call `reload()` on it. - That will fire a request to server and return a promise that will - resolve once the record has been reloaded. - If there's no record corresponding in the store it will simply call - `store.find`. - - Example - - ```app/routes/post.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - model: function(params) { - return this.store.fetchById('post', params.post_id); - } - }); - ``` - @method fetchById + @deprecated Use [findRecord](#method_findRecord) instead @param {String} modelName @param {(String|Integer)} id @param {Object} options @@ -529,6 +511,7 @@ Store = Service.extend({ fetchById: function(modelName, id, preload) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var options = deprecatePreload(preload, this.modelFor(modelName), 'fetchById'); + Ember.deprecate('Using store.fetchById(type, id) has been deprecated. Use store.findRecord(type, id, { reload: true }) to reload a record for a given type.'); if (this.hasRecordForId(modelName, id)) { return this.peekRecord(modelName, id).reload(); } else { @@ -541,12 +524,13 @@ Store = Service.extend({ in the store or not. @method fetchAll + @deprecated Use [findAll](#method_findAll) instead @param {String} modelName @return {Promise} promise */ fetchAll: function(modelName) { - Ember.deprecate('Using store.fetchAll(type) has been deprecated. Use store.findAll(type) to retrieve all records for a given type.'); - return this.findAll(modelName); + Ember.deprecate('Using store.fetchAll(type) has been deprecated. Use store.findAll(type, { reload: true }) to retrieve all records for a given type.'); + return this.findAll(modelName, { reload: true }); }, /** @@ -555,12 +539,12 @@ Store = Service.extend({ @param {(String|Integer)} id @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models @return {Promise} promise - @deprecated Use [fetchById](#method_fetchById) instead + @deprecated Use [findRecord](#method_findRecord) instead */ fetch: function(modelName, id, preload) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - Ember.deprecate('Using store.fetch() has been deprecated. Use store.fetchById for fetching individual records or store.fetchAll for collections'); - return this.fetchById(modelName, id, preload); + Ember.deprecate('Using store.fetch() has been deprecated. Use store.findRecord for fetching individual records or store.fetchAll for collections'); + return this.findRecord(modelName, id, { reload: true, preload: preload }); }, /** @@ -582,6 +566,40 @@ Store = Service.extend({ /** This method returns a record for a given type and id combination. + The `find` method will always return a **promise** that will be + resolved with the record. If the record was already in the store, + the promise will be resolved immediately. Otherwise, the store + will ask the adapter's `find` method to find the necessary data. + + The `find` method will always resolve its promise with the same + object for a given type and `id`. + + Example + + ```app/routes/post.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model: function(params) { + return this.store.findRecord('post', params.post_id); + } + }); + ``` + + If you would like to force the record to reload, instead of + loading it from the cache when present you can set `reload: true` + in the options object for `findRecord`. + + ```app/routes/post/edit.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model: function(params) { + return this.store.findRecord('post', params.post_id, { reload: true }); + } + }); + ``` + @method findRecord @param {String} modelName @param {(String|Integer)} id @@ -591,7 +609,11 @@ Store = Service.extend({ findRecord: function(modelName, id, options) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var internalModel = this._internalModelForId(modelName, id); + options = options || {}; + if (options.reload && this.hasRecordForId(modelName, id)) { + return this.peekRecord(modelName, id).reload(); + } return this._findByInternalModel(internalModel, options); }, @@ -1039,9 +1061,21 @@ Store = Service.extend({ }, /** - This method returns an array of all records adapter can find. - It triggers the adapter's `findAll` method to give it an opportunity to populate - the array with records of that type. + `findAll` ask the adapter's `findAll` method to find the records + for the given type, and return a promise that will be resolved + once the server returns the values. The promise will resolve into + all records of this type present in the store, even if the server + only returns a subset of them. + + ```app/routes/authors.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model: function(params) { + return this.store.findAll('author'); + } + }); + ``` @method findAll @param {String} modelName diff --git a/packages/ember-data/tests/integration/store-test.js b/packages/ember-data/tests/integration/store-test.js index 2977ad108d2..f4cc532b531 100644 --- a/packages/ember-data/tests/integration/store-test.js +++ b/packages/ember-data/tests/integration/store-test.js @@ -227,17 +227,17 @@ test("Using store#fetch is deprecated", function() { store.fetch('car', 1); }); }, - 'Using store.fetch() has been deprecated. Use store.fetchById for fetching individual records or store.fetchAll for collections' + 'Using store.fetch() has been deprecated. Use store.findRecord for fetching individual records or store.fetchAll for collections' ); }); -module("integration/store - fetchById", { +module("integration/store - findRecord { reload: true }", { setup: function() { initializeStore(DS.RESTAdapter.extend()); } }); -test("Using store#fetchById on non existing record fetches it from the server", function() { +test("Using store#findRecord on non existing record fetches it from the server", function() { expect(2); ajaxResponse({ @@ -252,13 +252,13 @@ test("Using store#fetchById on non existing record fetches it from the server", ok(!car, 'Car with id=20 should not exist'); run(function() { - store.fetchById('car', 20).then(function (car) { + store.findRecord('car', 20, { reload: true }).then(function (car) { equal(car.get('make'), 'BMCW', 'Car with id=20 is now loaded'); }); }); }); -test("Using store#fetchById on existing record reloads it", function() { +test("Using store#findRecord on existing record reloads it", function() { expect(2); var car; @@ -281,7 +281,7 @@ test("Using store#fetchById on existing record reloads it", function() { equal(car.get('make'), 'BMC'); run(function() { - store.fetchById('car', 1).then(function(car) { + store.findRecord('car', 1, { reload: true }).then(function(car) { equal(car.get('make'), 'BMCW'); }); }); @@ -304,7 +304,7 @@ test("store#fetchAll() is deprecated", function() { store.fetchAll('car'); }); }, - 'Using store.fetchAll(type) has been deprecated. Use store.findAll(type) to retrieve all records for a given type.' + 'Using store.fetchAll(type) has been deprecated. Use store.findAll(type, { reload: true }) to retrieve all records for a given type.' ); }); @@ -424,7 +424,7 @@ test("Using store#fetch on an empty record calls find", function() { ok(car.get('isEmpty'), 'Car with id=20 should be empty'); run(function() { - store.fetchById('car', 20).then(function (car) { + store.findRecord('car', 20, { reload: true }).then(function (car) { equal(car.get('make'), 'BMCW', 'Car with id=20 is now loaded'); }); }); From 2ded4211fdb30c4cc85fe0e3ac7da56baa389943 Mon Sep 17 00:00:00 2001 From: Mike Hollis Date: Sat, 13 Jun 2015 14:23:14 -0400 Subject: [PATCH 0937/2527] Deprecate store.pushMany in favor of store.push --- packages/ember-data/lib/system/store.js | 1 + packages/ember-data/tests/unit/store/push-test.js | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 24693bbff89..0cb9fafb315 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1901,6 +1901,7 @@ Store = Service.extend({ */ pushMany: function(modelName, datas) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + Ember.deprecate('Using store.pushMany() has been deprecated since store.push() now handles multiple items. You should use store.push() instead.'); var length = datas.length; var result = new Array(length); diff --git a/packages/ember-data/tests/unit/store/push-test.js b/packages/ember-data/tests/unit/store/push-test.js index e4f9bcf5387..9f107182c43 100644 --- a/packages/ember-data/tests/unit/store/push-test.js +++ b/packages/ember-data/tests/unit/store/push-test.js @@ -584,3 +584,15 @@ test("Calling push with unknown keys should not warn by default", function() { }); }, /The payload for 'person' contains these unknown keys: \[emailAddress,isMascot\]. Make sure they've been defined in your model./); }); + +test("Calling pushMany is deprecated", function() { + var person1, person2; + expectDeprecation(function() { + run(function() { + person1 = { id: 1, firstName: 'John', lastName: 'Smith' }; + person2 = { id: 2, firstName: 'Suzie', lastName: 'Q' }; + + store.pushMany('person', [person1, person2]); + }); + }, 'Using store.pushMany() has been deprecated since store.push() now handles multiple items. You should use store.push() instead.'); +}); From 5e39cbc4f23623e0bcf36e55c11a228476c99997 Mon Sep 17 00:00:00 2001 From: Tom Coquereau Date: Thu, 11 Dec 2014 00:04:13 +0100 Subject: [PATCH 0938/2527] Implement queryRecord method on the store --- .../lib/serializers/json-serializer.js | 18 ++++++ packages/ember-data/lib/system/adapter.js | 38 +++++++++++ packages/ember-data/lib/system/store.js | 33 +++++++++- .../ember-data/lib/system/store/finders.js | 22 +++++++ .../integration/store/query-record-test.js | 63 +++++++++++++++++++ 5 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 packages/ember-data/tests/integration/store/query-record-test.js diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index ae5f3d7d29b..2ead6b69954 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -1253,6 +1253,24 @@ export default Serializer.extend({ extractFindQuery: function(store, typeClass, payload, id, requestType) { return this.extractArray(store, typeClass, payload, id, requestType); }, + /** + TODO: remove this in a couple of days + + `extractQueryRecord` is a hook into the extract method used when a + call is made to `DS.Store#queryRecord`. By default this method is an + alias for [extractSingle](#method_extractSingle). + + @method extractQueryRecord + @param {DS.Store} store + @param {DS.Model} typeClass + @param {Object} payload + @param {(String|Number)} id + @param {String} requestType + @return {Object} object A hash of deserialized object + */ + extractQueryRecord: function(store, typeClass, payload, id, requestType) { + return this.extractSingle(store, typeClass, payload, id, requestType); + }, /** `extractFindMany` is a hook into the extract method used when a call is made to `DS.Store#findMany`. By default this method is diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 1ee98a0c2ba..6c9fb5bbf1f 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -189,6 +189,44 @@ var Adapter = Ember.Object.extend({ */ findQuery: null, + /** + The `queryRecord()` method is invoked when the store is asked for a single + record through a query object. + + In response to `queryRecord()` being called, you should always fetch fresh + data. Once found, you can asynchronously call the store's `push()` method + to push the record into the store. + + Here is an example `queryRecord` implementation: + + Example + + ```javascript + App.ApplicationAdapter = DS.Adapter.extend({ + queryRecord: function(store, typeClass, query) { + var url = [type.typeKey, id].join('/'); + + return new Ember.RSVP.Promise(function(resolve, reject) { + jQuery.getJSON(url, query).then(function(data) { + Ember.run(null, resolve, data); + }, function(jqXHR) { + jqXHR.then = null; // tame jQuery's ill mannered promises + Ember.run(null, reject, jqXHR); + }); + }); + } + }); + ``` + + @method queryRecord + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} query + @param {String} id + @return {Promise} promise + */ + queryRecord: null, + /** If the globally unique IDs for your records should be generated on the client, implement the `generateIdForRecord()` method. This method will be invoked diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 24693bbff89..0bf2fecc5a2 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -40,7 +40,8 @@ import { _findHasMany, _findBelongsTo, _findAll, - _query + _query, + _queryRecord } from "ember-data/system/store/finders"; import coerceId from "ember-data/system/coerce-id"; @@ -1038,6 +1039,36 @@ Store = Service.extend({ return promiseArray(_query(adapter, this, typeClass, query, array)); }, + /** + This method delegates a query to the adapter. This is the one place where + adapter-level semantics are exposed to the application. + + Exposing queries this way seems preferable to creating an abstract query + language for all server-side queries, and then require all adapters to + implement them. + + This method returns a promise, which is resolved with a `RecordObject` + once the server returns. + + @method queryRecord + @param {String or subclass of DS.Model} type + @param {any} query an opaque query to be used by the adapter + @return {Promise} promise + */ + queryRecord: function(modelName, query) { + Ember.assert("You need to pass a type to the store's queryRecord method", modelName); + Ember.assert("You need to pass a query hash to the store's queryRecord method", query); + Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + + var typeClass = this.modelFor(modelName); + var adapter = this.adapterFor(modelName); + + Ember.assert("You tried to make a query but you have no adapter (for " + typeClass + ")", adapter); + Ember.assert("You tried to make a query but your adapter does not implement `queryRecord`", typeof adapter.queryRecord === 'function'); + + return promiseObject(_queryRecord(adapter, this, typeClass, query)); + }, + /** This method delegates a query to the adapter. This is the one place where adapter-level semantics are exposed to the application. diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index 8e57bf31c6c..ad4c0779728 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -165,3 +165,25 @@ export function _query(adapter, store, typeClass, query, recordArray) { }, null, "DS: Extract payload of findQuery " + typeClass); } + +export function _queryRecord(adapter, store, typeClass, query) { + var modelName = typeClass.modelName; + var promise = adapter.queryRecord(store, typeClass, query); + var serializer = serializerForAdapter(store, adapter, modelName); + var label = "DS: Handle Adapter#queryRecord of " + typeClass; + + promise = Promise.cast(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + + return promise.then(function(adapterPayload) { + var record; + store._adapterRun(function() { + var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'queryRecord'); + //TODO Optimize + record = pushPayload(store, payload); + }); + + return record; + + }, null, "DS: Extract payload of queryRecord " + typeClass); +} diff --git a/packages/ember-data/tests/integration/store/query-record-test.js b/packages/ember-data/tests/integration/store/query-record-test.js new file mode 100644 index 00000000000..e1eb5792db7 --- /dev/null +++ b/packages/ember-data/tests/integration/store/query-record-test.js @@ -0,0 +1,63 @@ +var Person, store, env; +var run = Ember.run; + +module("integration/store/query-record - Query one record with a query hash", { + setup: function() { + Person = DS.Model.extend({ + updatedAt: DS.attr('string'), + name: DS.attr('string'), + firstName: DS.attr('string'), + lastName: DS.attr('string') + }); + + env = setupStore({ + person: Person + }); + store = env.store; + }, + + teardown: function() { + run(store, 'destroy'); + } +}); + +test("It raises an assertion when no type is passed", function() { + expectAssertion(function() { + store.queryRecord(); + }, "You need to pass a type to the store's queryRecord method"); +}); + +test("It raises an assertion when no query hash is passed", function() { + expectAssertion(function() { + store.queryRecord('person'); + }, "You need to pass a query hash to the store's queryRecord method"); +}); + +test("When a record is requested, the adapter's queryRecord method should be called.", function() { + expect(1); + + env.registry.register('adapter:person', DS.Adapter.extend({ + queryRecord: function(store, type, query) { + equal(type, Person, "the query method is called with the correct type"); + return Ember.RSVP.resolve({ id: 1, name: "Peter Wagenet" }); + } + })); + + run(function() { + store.queryRecord('person', { related: 'posts' }); + }); +}); + +test("When a record is requested, and the promise is rejected, .queryRecord() is rejected.", function() { + env.registry.register('adapter:person', DS.Adapter.extend({ + queryRecord: function(store, type, query) { + return Ember.RSVP.reject(); + } + })); + + run(function() { + store.queryRecord('person', {}).then(null, async(function(reason) { + ok(true, "The rejection handler was called"); + })); + }); +}); From 21114f195e48d0c134cc2be27f67e8d61d46239c Mon Sep 17 00:00:00 2001 From: Grzesiek Pluta Date: Sat, 13 Jun 2015 22:51:52 +0200 Subject: [PATCH 0939/2527] Fixed a small typo in readme.md Removed a lonely 'n' char from the first paragraph. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 331b5a28f6d..51fca5efa98 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Ember.js applications. Ember Data is designed to be agnostic to the underlying persistence mechanism, so it works just as well with JSON APIs over HTTP as it does with streaming WebSockets or local IndexedDB storage. -n + It provides many of the facilities you'd find in server-side ORMs like ActiveRecord, but is designed specifically for the unique environment of JavaScript in the browser. From 71fecd2ef7240301a2eb61f376d646f8c957e0e7 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sat, 13 Jun 2015 22:30:00 +0200 Subject: [PATCH 0940/2527] Refactor `Errors#errorsByAttributeName` to not use Ember.reduceComputed --- .../ember-data/lib/system/model/errors.js | 29 ++++++------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index 80818a19090..5f0e175f422 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -109,26 +109,12 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { @type {Ember.MapWithDefault} @private */ - errorsByAttributeName: Ember.reduceComputed("content", { - initialValue: function() { - return MapWithDefault.create({ - defaultValue: function() { - return Ember.A(); - } - }); - }, - - addedItem: function(errors, error) { - errors.get(error.attribute).pushObject(error); - - return errors; - }, - - removedItem: function(errors, error) { - errors.get(error.attribute).removeObject(error); - - return errors; - } + errorsByAttributeName: Ember.computed(function() { + return MapWithDefault.create({ + defaultValue: function() { + return Ember.A(); + } + }); }), /** @@ -234,6 +220,7 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { messages = this._findOrCreateMessages(attribute, messages); get(this, 'content').addObjects(messages); + get(this, 'errorsByAttributeName').get(attribute).addObjects(messages); this.notifyPropertyChange(attribute); this.enumerableContentDidChange(); @@ -297,6 +284,7 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { var content = get(this, 'content').rejectBy('attribute', attribute); get(this, 'content').setObjects(content); + get(this, 'errorsByAttributeName').delete(attribute); this.notifyPropertyChange(attribute); this.enumerableContentDidChange(); @@ -331,6 +319,7 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { if (get(this, 'isEmpty')) { return; } get(this, 'content').clear(); + get(this, 'errorsByAttributeName').clear(); this.enumerableContentDidChange(); this.trigger('becameValid'); From 5326f1f2d394586459d69b86558334f00f3bc9fb Mon Sep 17 00:00:00 2001 From: pangratz Date: Sun, 14 Jun 2015 13:57:17 +0200 Subject: [PATCH 0941/2527] Update Ember.js to v1.13 --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index b1d345e8de6..a55a26f3c8b 100644 --- a/bower.json +++ b/bower.json @@ -2,7 +2,7 @@ "name": "ember-data", "private": true, "dependencies": { - "ember": "~1.12.1" + "ember": "~1.13" }, "devDependencies": { "qunit": "~1.17.0", From bb11d583c163a6b4d47d94326026bdc0a46e8af2 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sun, 14 Jun 2015 12:34:46 -0500 Subject: [PATCH 0942/2527] deprecate ActiveModelAdapter being bundled with core --- packages/ember-data/lib/main.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index 09a6a1ae872..d8b90b474ec 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -120,8 +120,27 @@ DS.StringTransform = StringTransform; DS.NumberTransform = NumberTransform; DS.BooleanTransform = BooleanTransform; -DS.ActiveModelAdapter = ActiveModelAdapter; -DS.ActiveModelSerializer = ActiveModelSerializer; +if (Ember.platform.hasPropertyAccessors) { + Ember.defineProperty(DS, 'ActiveModelAdapter', { + get: function() { + Ember.deprecate('The ActiveModelAdapter has been moved into a plugin. It will not be bundled with Ember Data in 2.0', false, { + url: 'https://github.com/ember-data/active-model-adapter' + }); + return ActiveModelAdapter; + } + }); + Ember.defineProperty(DS, 'ActiveModelSerializer', { + get: function() { + Ember.deprecate('The ActiveModelSerializer has been moved into a plugin. It will not be bundled with Ember Data in 2.0', false, { + url: 'https://github.com/ember-data/active-model-adapter' + }); + return ActiveModelSerializer; + } + }); +} else { + DS.ActiveModelAdapter = ActiveModelAdapter; + DS.ActiveModelSerializer = ActiveModelSerializer; +} DS.EmbeddedRecordsMixin = EmbeddedRecordsMixin; DS.belongsTo = belongsTo; From 4779a101d63b8d812c819a3e6c186ec1e55f6301 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Mon, 15 Jun 2015 02:42:07 +0200 Subject: [PATCH 0943/2527] Fix docparser warning --- packages/ember-data/lib/utils.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ember-data/lib/utils.js b/packages/ember-data/lib/utils.js index 14d767fc6ee..103160c2b7f 100644 --- a/packages/ember-data/lib/utils.js +++ b/packages/ember-data/lib/utils.js @@ -12,6 +12,7 @@ import Ember from 'ember'; information about the relationship, retrieved via `record.relationshipFor(key)`. + @method assertPolymorphicType @param {InternalModel} record @param {RelationshipMeta} relationshipMeta retrieved via `record.relationshipFor(key)` From 3ebfec4c9924064df9bd7e0075ba3dc000e30be4 Mon Sep 17 00:00:00 2001 From: Sylvain MINA Date: Mon, 15 Jun 2015 09:47:00 +0200 Subject: [PATCH 0944/2527] Use 'findRecord' instead of 'find' in doc cc/ @bmac, I think it was a small bad copy paste in https://github.com/emberjs/data/pull/3312/files#diff-1636bea36bbe333a834ea11fbfbde48dR569 --- packages/ember-data/lib/system/store.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index f44a8496b8e..d4bbb93794f 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -567,12 +567,12 @@ Store = Service.extend({ /** This method returns a record for a given type and id combination. - The `find` method will always return a **promise** that will be + The `findRecord` method will always return a **promise** that will be resolved with the record. If the record was already in the store, the promise will be resolved immediately. Otherwise, the store will ask the adapter's `find` method to find the necessary data. - The `find` method will always resolve its promise with the same + The `findRecord` method will always resolve its promise with the same object for a given type and `id`. Example From 20a4c5446cf34bc47d529b165ffe74ee70f0494b Mon Sep 17 00:00:00 2001 From: Sylvain MINA Date: Mon, 15 Jun 2015 10:02:36 +0200 Subject: [PATCH 0945/2527] fix deprecation warning for store.fetch --- packages/ember-data/lib/system/store.js | 2 +- packages/ember-data/tests/integration/store-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index f44a8496b8e..f080f5e9a83 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -544,7 +544,7 @@ Store = Service.extend({ */ fetch: function(modelName, id, preload) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - Ember.deprecate('Using store.fetch() has been deprecated. Use store.findRecord for fetching individual records or store.fetchAll for collections'); + Ember.deprecate('Using store.fetch() has been deprecated. Use store.findRecord for fetching individual records or store.findAll for collections'); return this.findRecord(modelName, id, { reload: true, preload: preload }); }, diff --git a/packages/ember-data/tests/integration/store-test.js b/packages/ember-data/tests/integration/store-test.js index f4cc532b531..739086339ac 100644 --- a/packages/ember-data/tests/integration/store-test.js +++ b/packages/ember-data/tests/integration/store-test.js @@ -227,7 +227,7 @@ test("Using store#fetch is deprecated", function() { store.fetch('car', 1); }); }, - 'Using store.fetch() has been deprecated. Use store.findRecord for fetching individual records or store.fetchAll for collections' + 'Using store.fetch() has been deprecated. Use store.findRecord for fetching individual records or store.findAll for collections' ); }); From 2cc186c613e934285be007e72bb631a14473a751 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 15 Jun 2015 11:10:47 -0400 Subject: [PATCH 0946/2527] Disable beta and canary tests so we can ship Ember Data 1.13 that still works with IE8 --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index dc1d375ff33..04da648ebb1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,8 @@ install: script: - ./bin/lint-features - npm run-script test - - npm run-script test:beta - - npm run-script test:canary +# - npm run-script test:beta +# - npm run-script test:canary - npm run-script test:optional-features after_success: - npm run-script publish-build:prebuilt From b8cd771fc6a9cddf3390d2b44475a10391b434a5 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 15 Jun 2015 13:54:51 -0400 Subject: [PATCH 0947/2527] Remove the JSONAPI serializer refactor feature flag --- FEATURES.md | 2 - config/features.json | 2 +- .../lib/serializers/embedded-records-mixin.js | 6 +- .../lib/serializers/json-serializer.js | 4 +- .../lib/serializers/rest-serializer.js | 4 +- packages/ember-data/lib/system/serializer.js | 5 - .../ember-data/lib/system/store/finders.js | 2 +- .../lib/system/store/serializer-response.js | 11 +- .../relationships/has-many-test.js | 139 +- .../embedded-records-mixin-new-test.js | 2014 ++++++++--------- .../serializers/json-serializer-new-test.js | 256 ++- .../serializers/rest-serializer-new-test.js | 594 +++-- .../serializers/rest-serializer-test.js | 211 -- 13 files changed, 1507 insertions(+), 1743 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 7c720870a27..92cc95cdb0b 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -11,6 +11,4 @@ entry in `config/features.json`. ## Feature Flags -* `ds-new-serializer-api` - Activates the new Serializer API for default serializers. diff --git a/config/features.json b/config/features.json index 9e71e4691c1..0db3279e44b 100644 --- a/config/features.json +++ b/config/features.json @@ -1,3 +1,3 @@ { - "ds-new-serializer-api": null + } diff --git a/packages/ember-data/lib/serializers/embedded-records-mixin.js b/packages/ember-data/lib/serializers/embedded-records-mixin.js index 15d1764839f..b593cf10c76 100644 --- a/packages/ember-data/lib/serializers/embedded-records-mixin.js +++ b/packages/ember-data/lib/serializers/embedded-records-mixin.js @@ -402,7 +402,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ @private */ _extractEmbeddedRecords: function(serializer, store, typeClass, partial) { - if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) { + if (this.get('isNewSerializerAPI')) { return _newExtractEmbeddedRecords.apply(this, arguments); } @@ -434,7 +434,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ @private */ _extractEmbeddedHasMany: function(store, key, embeddedTypeClass, hash) { - if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) { + if (this.get('isNewSerializerAPI')) { return _newExtractEmbeddedHasMany.apply(this, arguments); } @@ -486,7 +486,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ @private */ _extractEmbeddedBelongsTo: function(store, key, embeddedTypeClass, hash) { - if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) { + if (this.get('isNewSerializerAPI')) { return _newExtractEmbeddedBelongsTo.apply(this, arguments); } diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index 2ead6b69954..1d3dd6a49fb 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -483,7 +483,7 @@ export default Serializer.extend({ @return {Object} */ normalize: function(typeClass, hash) { - if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) { + if (this.get('isNewSerializerAPI')) { return _newNormalize.apply(this, arguments); } @@ -1495,7 +1495,7 @@ export default Serializer.extend({ @param {Object} payload */ extractMeta: function(store, typeClass, payload) { - if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) { + if (this.get('isNewSerializerAPI')) { return _newExtractMeta.apply(this, arguments); } diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index 085ad39b534..713f721137b 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -175,7 +175,7 @@ var RESTSerializer = JSONSerializer.extend({ @return {Object} */ normalize: function(typeClass, hash, prop) { - if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) { + if (this.get('isNewSerializerAPI')) { _newNormalize.apply(this, arguments); return this._super(...arguments); } @@ -651,7 +651,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {Object} rawPayload */ pushPayload: function(store, rawPayload) { - if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && this.get('isNewSerializerAPI')) { + if (this.get('isNewSerializerAPI')) { _newPushPayload.apply(this, arguments); return; } diff --git a/packages/ember-data/lib/system/serializer.js b/packages/ember-data/lib/system/serializer.js index 06cc95e2942..de9d23c5fe4 100644 --- a/packages/ember-data/lib/system/serializer.js +++ b/packages/ember-data/lib/system/serializer.js @@ -28,11 +28,6 @@ var Serializer = Ember.Object.extend({ This is only to be used temporarily during the transition from the old serializer API to the new one. - To activate the new Serializer API you need to enable the feature flag - `ds-new-serializer-api`. - - http://guides.emberjs.com/v1.12.0/configuring-ember/feature-flags/ - This makes the store and the built-in serializers use the new Serializer API. diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index ad4c0779728..e9d9e4412ac 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -86,7 +86,7 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) //TODO Use a non record creating push var records = pushPayload(store, payload); var recordArray = map(records, function(record) { return record._internalModel; }); - if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && serializer.get('isNewSerializerAPI')) { + if (serializer.get('isNewSerializerAPI')) { recordArray.meta = payload.meta; } return recordArray; diff --git a/packages/ember-data/lib/system/store/serializer-response.js b/packages/ember-data/lib/system/store/serializer-response.js index d1aba0fd0d0..c416813a298 100644 --- a/packages/ember-data/lib/system/store/serializer-response.js +++ b/packages/ember-data/lib/system/store/serializer-response.js @@ -4,9 +4,8 @@ var map = Ember.EnumerableUtils.map; /** This is a helper method that always returns a JSON-API Document. - If the feature flag `ds-new-serializer-api` is enabled and the current serializer - has `isNewSerializerAPI` set to `true` this helper calls `normalizeResponse` - instead of `extract`. + If the current serializer has `isNewSerializerAPI` set to `true` + this helper calls `normalizeResponse` instead of `extract`. All the built-in serializers get `isNewSerializerAPI` set to `true` automatically if the feature flag is enabled. @@ -21,12 +20,10 @@ var map = Ember.EnumerableUtils.map; @return {Object} JSON-API Document */ export function normalizeResponseHelper(serializer, store, modelClass, payload, id, requestType) { - if (Ember.FEATURES.isEnabled('ds-new-serializer-api') && serializer.get('isNewSerializerAPI')) { + if (serializer.get('isNewSerializerAPI')) { return serializer.normalizeResponse(store, modelClass, payload, id, requestType); } else { - if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { - Ember.deprecate('Your custom serializer uses the old version of the Serializer API, with `extract` hooks. Please upgrade your serializers to the new Serializer API using `normalizeResponse` hooks instead.'); - } + Ember.deprecate('Your custom serializer uses the old version of the Serializer API, with `extract` hooks. Please upgrade your serializers to the new Serializer API using `normalizeResponse` hooks instead.'); let serializerPayload = serializer.extract(store, modelClass, payload, id, requestType); return _normalizeSerializerPayload(modelClass, serializerPayload); } diff --git a/packages/ember-data/tests/integration/relationships/has-many-test.js b/packages/ember-data/tests/integration/relationships/has-many-test.js index 8c9fd1a6c68..4bd0482eeae 100644 --- a/packages/ember-data/tests/integration/relationships/has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/has-many-test.js @@ -1446,97 +1446,94 @@ test("Model's belongsTo relationship should be created during 'get' method", fun }); }); -if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { - - test("metadata is accessible when pushed as a meta property for a relationship", function() { - expect(1); - var book; - env.adapter.findHasMany = function() { - return resolve({}); - }; +test("metadata is accessible when pushed as a meta property for a relationship", function() { + expect(1); + var book; + env.adapter.findHasMany = function() { + return resolve({}); + }; - run(function() { - book = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', meta: { chapters: 'the lefkada sea' }, links: { chapters: '/chapters' } }); - }); + run(function() { + book = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', meta: { chapters: 'the lefkada sea' }, links: { chapters: '/chapters' } }); + }); - run(function() { - equal(book._internalModel._relationships.get('chapters').meta, 'the lefkada sea', 'meta is there'); - }); + run(function() { + equal(book._internalModel._relationships.get('chapters').meta, 'the lefkada sea', 'meta is there'); }); +}); - test("metadata is accessible when return from a fetchLink", function() { - expect(1); - env.registry.register('serializer:application', DS.RESTSerializer.extend({ isNewSerializerAPI: true })); +test("metadata is accessible when return from a fetchLink", function() { + expect(1); + env.registry.register('serializer:application', DS.RESTSerializer.extend({ isNewSerializerAPI: true })); - env.adapter.findHasMany = function() { - return resolve({ - meta: { - foo: 'bar' - }, - chapters: [ - { id: '2' }, - { id: '3' } - ] - }); - }; + env.adapter.findHasMany = function() { + return resolve({ + meta: { + foo: 'bar' + }, + chapters: [ + { id: '2' }, + { id: '3' } + ] + }); + }; - var book; + var book; - run(function() { - book = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', links: { chapters: '/chapters' } }); - }); + run(function() { + book = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', links: { chapters: '/chapters' } }); + }); - run(function() { - book.get('chapters').then(function(chapters) { - var meta = chapters.get('meta'); - equal(get(meta, 'foo'), 'bar', 'metadata is available'); - }); + run(function() { + book.get('chapters').then(function(chapters) { + var meta = chapters.get('meta'); + equal(get(meta, 'foo'), 'bar', 'metadata is available'); }); }); +}); - test("metadata should be reset between requests", function() { - var counter = 0; - env.registry.register('serializer:application', DS.RESTSerializer.extend({ isNewSerializerAPI: true })); +test("metadata should be reset between requests", function() { + var counter = 0; + env.registry.register('serializer:application', DS.RESTSerializer.extend({ isNewSerializerAPI: true })); - env.adapter.findHasMany = function() { - var data = { - meta: { - foo: 'bar' - }, - chapters: [ - { id: '2' }, - { id: '3' } - ] - }; + env.adapter.findHasMany = function() { + var data = { + meta: { + foo: 'bar' + }, + chapters: [ + { id: '2' }, + { id: '3' } + ] + }; - ok(true, 'findHasMany should be called twice'); + ok(true, 'findHasMany should be called twice'); - if (counter === 1) { - delete data.meta; - } + if (counter === 1) { + delete data.meta; + } - counter++; + counter++; - return resolve(data); - }; + return resolve(data); + }; - var book1, book2; + var book1, book2; - run(function() { - book1 = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', links: { chapters: 'chapters' } }); - book2 = env.store.push('book', { id: 2, title: 'Another book title', links: { chapters: 'chapters' } }); - }); + run(function() { + book1 = env.store.push('book', { id: 1, title: 'Sailing the Seven Seas', links: { chapters: 'chapters' } }); + book2 = env.store.push('book', { id: 2, title: 'Another book title', links: { chapters: 'chapters' } }); + }); - run(function() { - book1.get('chapters').then(function(chapters) { - var meta = chapters.get('meta'); - equal(get(meta, 'foo'), 'bar', 'metadata should available'); + run(function() { + book1.get('chapters').then(function(chapters) { + var meta = chapters.get('meta'); + equal(get(meta, 'foo'), 'bar', 'metadata should available'); - book2.get('chapters').then(function(chapters) { - var meta = chapters.get('meta'); - equal(meta, undefined, 'metadata should not be available'); - }); + book2.get('chapters').then(function(chapters) { + var meta = chapters.get('meta'); + equal(meta, undefined, 'metadata should not be available'); }); }); }); -} +}); diff --git a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-new-test.js b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-new-test.js index b1224e40dd3..741183b12f9 100644 --- a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-new-test.js +++ b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-new-test.js @@ -71,1130 +71,1126 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin (new API)", { } }); -if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { - - test("normalizeSingleResponse with embedded objects", function() { - env.registry.register('adapter:super-villain', DS.RESTAdapter); - env.registry.register('serializer:super-villain', TestSerializer.extend()); - env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' } - } - })); - - var serializer = env.container.lookup("serializer:home-planet"); - var json_hash = { - homePlanet: { - id: "1", - name: "Umber", - villains: [{ - id: "2", - firstName: "Tom", - lastName: "Dale" - }] - } - }; - var json; +test("normalizeSingleResponse with embedded objects", function() { + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:super-villain', TestSerializer.extend()); + env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' } + } + })); + + var serializer = env.container.lookup("serializer:home-planet"); + var json_hash = { + homePlanet: { + id: "1", + name: "Umber", + villains: [{ + id: "2", + firstName: "Tom", + lastName: "Dale" + }] + } + }; + var json; - run(function() { - json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); - }); + run(function() { + json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); + }); - deepEqual(json, { - "data": { - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "villains": { - "data": [ - { "id": "2", "type": "super-villain" } - ] - } - } + deepEqual(json, { + "data": { + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" }, - "included": [ - { - "id": "2", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": {} + "relationships": { + "villains": { + "data": [ + { "id": "2", "type": "super-villain" } + ] } - ] - }); - }); - - test("normalizeSingleResponse with embedded objects inside embedded objects", function() { - env.registry.register('adapter:super-villain', DS.RESTAdapter); - env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' } - } - })); - env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - evilMinions: { embedded: 'always' } - } - })); - env.registry.register('serializer:evil-minion', TestSerializer); - - var serializer = env.container.lookup("serializer:home-planet"); - var json_hash = { - homePlanet: { - id: "1", - name: "Umber", - villains: [{ - id: "2", - firstName: "Tom", - lastName: "Dale", - evilMinions: [{ - id: "3", - name: "Alex" - }] - }] } - }; - var json; - - run(function() { - json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); - }); - - deepEqual(json, { - "data": { - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "villains": { - "data": [ - { "id": "2", "type": "super-villain" } - ] - } - } - }, - "included": [{ + }, + "included": [ + { "id": "2", "type": "super-villain", "attributes": { "firstName": "Tom", "lastName": "Dale" }, - "relationships": { - "evilMinions": { - "data": [ - { "id": "3", "type": "evil-minion" } - ] - } - } - }, { - "id": "3", - "type": "evil-minion", - "attributes": { - "name": "Alex" - }, "relationships": {} - }] - }); - }); - - test("normalizeSingleResponse with embedded objects of same type", function() { - env.registry.register('adapter:comment', DS.RESTAdapter); - env.registry.register('serializer:comment', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - children: { embedded: 'always' } } - })); + ] + }); +}); - var serializer = env.container.lookup("serializer:comment"); - var json_hash = { - comment: { - id: "1", - body: "Hello", - root: true, - children: [{ - id: "2", - body: "World", - root: false - }, - { +test("normalizeSingleResponse with embedded objects inside embedded objects", function() { + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' } + } + })); + env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + evilMinions: { embedded: 'always' } + } + })); + env.registry.register('serializer:evil-minion', TestSerializer); + + var serializer = env.container.lookup("serializer:home-planet"); + var json_hash = { + homePlanet: { + id: "1", + name: "Umber", + villains: [{ + id: "2", + firstName: "Tom", + lastName: "Dale", + evilMinions: [{ id: "3", - body: "Foo", - root: false + name: "Alex" }] - } - }; - var json; - run(function() { - json = serializer.normalizeSingleResponse(env.store, Comment, json_hash, '1', 'find'); - }); - - deepEqual(json, { - "data": { - "id": "1", - "type": "comment", - "attributes": { - "body": "Hello", - "root": true - }, - "relationships": { - "children": { - "data": [ - { "id": "2", "type": "comment" }, - { "id": "3", "type": "comment" } - ] - } - } - }, - "included": [{ - "id": "2", - "type": "comment", - "attributes": { - "body": "World", - "root": false - }, - "relationships": {} - }, { - "id": "3", - "type": "comment", - "attributes": { - "body": "Foo", - "root": false - }, - "relationships": {} }] - }, "Primary record was correct"); - }); + } + }; + var json; - test("normalizeSingleResponse with embedded objects inside embedded objects of same type", function() { - env.registry.register('adapter:comment', DS.RESTAdapter); - env.registry.register('serializer:comment', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - children: { embedded: 'always' } - } - })); - - var serializer = env.container.lookup("serializer:comment"); - var json_hash = { - comment: { - id: "1", - body: "Hello", - root: true, - children: [{ - id: "2", - body: "World", - root: false, - children: [{ - id: "4", - body: "Another", - root: false - }] - }, - { - id: "3", - body: "Foo", - root: false - }] - } - }; - var json; - run(function() { - json = serializer.normalizeSingleResponse(env.store, Comment, json_hash, '1', 'find'); - }); + run(function() { + json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); + }); - deepEqual(json, { - "data": { - "id": "1", - "type": "comment", - "attributes": { - "body": "Hello", - "root": true - }, - "relationships": { - "children": { - "data": [ - { "id": "2", "type": "comment" }, - { "id": "3", "type": "comment" } - ] - } + deepEqual(json, { + "data": { + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "villains": { + "data": [ + { "id": "2", "type": "super-villain" } + ] } + } + }, + "included": [{ + "id": "2", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" }, - "included": [{ - "id": "2", - "type": "comment", - "attributes": { - "body": "World", - "root": false - }, - "relationships": { - "children": { - "data": [ - { "id": "4", "type": "comment" } - ] - } + "relationships": { + "evilMinions": { + "data": [ + { "id": "3", "type": "evil-minion" } + ] } - }, { - "id": "4", - "type": "comment", - "attributes": { - "body": "Another", - "root": false - }, - "relationships": {} - }, { - "id": "3", - "type": "comment", - "attributes": { - "body": "Foo", - "root": false - }, - "relationships": {} - }] - }, "Primary record was correct"); + } + }, { + "id": "3", + "type": "evil-minion", + "attributes": { + "name": "Alex" + }, + "relationships": {} + }] }); +}); - test("normalizeSingleResponse with embedded objects of same type, but from separate attributes", function() { - HomePlanet.reopen({ - reformedVillains: DS.hasMany('superVillain', { inverse: null }) - }); +test("normalizeSingleResponse with embedded objects of same type", function() { + env.registry.register('adapter:comment', DS.RESTAdapter); + env.registry.register('serializer:comment', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + children: { embedded: 'always' } + } + })); + + var serializer = env.container.lookup("serializer:comment"); + var json_hash = { + comment: { + id: "1", + body: "Hello", + root: true, + children: [{ + id: "2", + body: "World", + root: false + }, + { + id: "3", + body: "Foo", + root: false + }] + } + }; + var json; + run(function() { + json = serializer.normalizeSingleResponse(env.store, Comment, json_hash, '1', 'find'); + }); - env.registry.register('adapter:home-planet', DS.RESTAdapter); - env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' }, - reformedVillains: { embedded: 'always' } + deepEqual(json, { + "data": { + "id": "1", + "type": "comment", + "attributes": { + "body": "Hello", + "root": true + }, + "relationships": { + "children": { + "data": [ + { "id": "2", "type": "comment" }, + { "id": "3", "type": "comment" } + ] + } } - })); - env.registry.register('serializer:super-villain', TestSerializer); + }, + "included": [{ + "id": "2", + "type": "comment", + "attributes": { + "body": "World", + "root": false + }, + "relationships": {} + }, { + "id": "3", + "type": "comment", + "attributes": { + "body": "Foo", + "root": false + }, + "relationships": {} + }] + }, "Primary record was correct"); +}); - var serializer = env.container.lookup("serializer:home-planet"); - var json_hash = { - homePlanet: { - id: "1", - name: "Earth", - villains: [{ - id: "1", - firstName: "Tom" - }, { - id: "3", - firstName: "Yehuda" - }], - reformedVillains: [{ - id: "2", - firstName: "Alex" - },{ +test("normalizeSingleResponse with embedded objects inside embedded objects of same type", function() { + env.registry.register('adapter:comment', DS.RESTAdapter); + env.registry.register('serializer:comment', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + children: { embedded: 'always' } + } + })); + + var serializer = env.container.lookup("serializer:comment"); + var json_hash = { + comment: { + id: "1", + body: "Hello", + root: true, + children: [{ + id: "2", + body: "World", + root: false, + children: [{ id: "4", - firstName: "Erik" + body: "Another", + root: false }] - } - }; - var json; - run(function() { - json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); - }); - - deepEqual(json, { - "data": { - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Earth" - }, - "relationships": { - "villains": { - "data": [ - { "id": "1", "type": "super-villain" }, - { "id": "3", "type": "super-villain" } - ] - }, - "reformedVillains": { - "data": [ - { "id": "2", "type": "super-villain" }, - { "id": "4", "type": "super-villain" } - ] - } - } }, - "included": [{ - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom" - }, - "relationships": {} - }, { - "id": "3", - "type": "super-villain", - "attributes": { - "firstName": "Yehuda" - }, - "relationships": {} - }, { - "id": "2", - "type": "super-villain", - "attributes": { - "firstName": "Alex" - }, - "relationships": {} - }, { - "id": "4", - "type": "super-villain", - "attributes": { - "firstName": "Erik" - }, - "relationships": {} - }] - }, "Primary hash was correct"); + { + id: "3", + body: "Foo", + root: false + }] + } + }; + var json; + run(function() { + json = serializer.normalizeSingleResponse(env.store, Comment, json_hash, '1', 'find'); }); - test("normalizeArrayResponse with embedded objects", function() { - env.registry.register('adapter:super-villain', DS.RESTAdapter); - env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' } + deepEqual(json, { + "data": { + "id": "1", + "type": "comment", + "attributes": { + "body": "Hello", + "root": true + }, + "relationships": { + "children": { + "data": [ + { "id": "2", "type": "comment" }, + { "id": "3", "type": "comment" } + ] + } + } + }, + "included": [{ + "id": "2", + "type": "comment", + "attributes": { + "body": "World", + "root": false + }, + "relationships": { + "children": { + "data": [ + { "id": "4", "type": "comment" } + ] + } } - })); - env.registry.register('serializer:super-villain', TestSerializer); + }, { + "id": "4", + "type": "comment", + "attributes": { + "body": "Another", + "root": false + }, + "relationships": {} + }, { + "id": "3", + "type": "comment", + "attributes": { + "body": "Foo", + "root": false + }, + "relationships": {} + }] + }, "Primary record was correct"); +}); - var serializer = env.container.lookup("serializer:home-planet"); +test("normalizeSingleResponse with embedded objects of same type, but from separate attributes", function() { + HomePlanet.reopen({ + reformedVillains: DS.hasMany('superVillain', { inverse: null }) + }); - var json_hash = { - homePlanets: [{ + env.registry.register('adapter:home-planet', DS.RESTAdapter); + env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + reformedVillains: { embedded: 'always' } + } + })); + env.registry.register('serializer:super-villain', TestSerializer); + + var serializer = env.container.lookup("serializer:home-planet"); + var json_hash = { + homePlanet: { + id: "1", + name: "Earth", + villains: [{ id: "1", - name: "Umber", - villains: [{ - id: "1", - firstName: "Tom", - lastName: "Dale" - }] - }] - }; - var array; - - run(function() { - array = serializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); - }); - - deepEqual(array, { - "data": [{ - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "villains": { - "data": [ - { "id": "1", "type": "super-villain" } - ] - } - } + firstName: "Tom" + }, { + id: "3", + firstName: "Yehuda" }], - "included": [{ - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": {} + reformedVillains: [{ + id: "2", + firstName: "Alex" + },{ + id: "4", + firstName: "Erik" }] - }); + } + }; + var json; + run(function() { + json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); }); - test("normalizeArrayResponse with embedded objects with custom primary key", function() { - expect(1); - env.registry.register('adapter:super-villain', DS.RESTAdapter); - env.registry.register('serializer:super-villain', TestSerializer.extend({ - primaryKey: 'villain_id' - })); - env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' } + deepEqual(json, { + "data": { + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Earth" + }, + "relationships": { + "villains": { + "data": [ + { "id": "1", "type": "super-villain" }, + { "id": "3", "type": "super-villain" } + ] + }, + "reformedVillains": { + "data": [ + { "id": "2", "type": "super-villain" }, + { "id": "4", "type": "super-villain" } + ] + } } - })); - - var serializer = env.container.lookup("serializer:home-planet"); + }, + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom" + }, + "relationships": {} + }, { + "id": "3", + "type": "super-villain", + "attributes": { + "firstName": "Yehuda" + }, + "relationships": {} + }, { + "id": "2", + "type": "super-villain", + "attributes": { + "firstName": "Alex" + }, + "relationships": {} + }, { + "id": "4", + "type": "super-villain", + "attributes": { + "firstName": "Erik" + }, + "relationships": {} + }] + }, "Primary hash was correct"); +}); - var json_hash = { - homePlanets: [{ +test("normalizeArrayResponse with embedded objects", function() { + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' } + } + })); + env.registry.register('serializer:super-villain', TestSerializer); + + var serializer = env.container.lookup("serializer:home-planet"); + + var json_hash = { + homePlanets: [{ + id: "1", + name: "Umber", + villains: [{ id: "1", - name: "Umber", - villains: [{ - villain_id: "2", - firstName: "Alex", - lastName: "Baizeau" - }] + firstName: "Tom", + lastName: "Dale" }] - }; - var array; - - run(function() { - array = serializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); - }); + }] + }; + var array; - deepEqual(array, { - "data": [{ - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "villains": { - "data": [ - { "id": "2", "type": "super-villain" } - ] - } - } - }], - "included": [{ - "id": "2", - "type": "super-villain", - "attributes": { - "firstName": "Alex", - "lastName": "Baizeau" - }, - "relationships": {} - }] - }); + run(function() { + array = serializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); }); - test("normalizeArrayResponse with embedded objects with identical relationship and attribute key ", function() { - expect(1); - env.registry.register('adapter:super-villain', DS.RESTAdapter); - env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' } + deepEqual(array, { + "data": [{ + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" }, - //Makes the keyForRelationship and keyForAttribute collide. - keyForRelationship: function(key, type) { - return this.keyForAttribute(key, type); + "relationships": { + "villains": { + "data": [ + { "id": "1", "type": "super-villain" } + ] + } } - })); - env.registry.register('serializer:super-villain', TestSerializer); - - var serializer = env.container.lookup("serializer:home-planet"); + }], + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": {} + }] + }); +}); - var json_hash = { - homePlanets: [{ - id: "1", - name: "Umber", - villains: [{ - id: "1", - firstName: "Alex", - lastName: "Baizeau" - }] +test("normalizeArrayResponse with embedded objects with custom primary key", function() { + expect(1); + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:super-villain', TestSerializer.extend({ + primaryKey: 'villain_id' + })); + env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' } + } + })); + + var serializer = env.container.lookup("serializer:home-planet"); + + var json_hash = { + homePlanets: [{ + id: "1", + name: "Umber", + villains: [{ + villain_id: "2", + firstName: "Alex", + lastName: "Baizeau" }] - }; - var array; + }] + }; + var array; - run(function() { - array = serializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); - }); + run(function() { + array = serializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); + }); - deepEqual(array, { - "data": [{ - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "villains": { - "data": [ - { "id": "1", "type": "super-villain" } - ] - } + deepEqual(array, { + "data": [{ + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "villains": { + "data": [ + { "id": "2", "type": "super-villain" } + ] } - }], - "included": [{ - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Alex", - "lastName": "Baizeau" - }, - "relationships": {} - }] - }); - }); - test("normalizeArrayResponse with embedded objects of same type as primary type", function() { - env.registry.register('adapter:comment', DS.RESTAdapter); - env.registry.register('serializer:comment', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - children: { embedded: 'always' } } - })); - - var serializer = env.container.lookup("serializer:comment"); + }], + "included": [{ + "id": "2", + "type": "super-villain", + "attributes": { + "firstName": "Alex", + "lastName": "Baizeau" + }, + "relationships": {} + }] + }); +}); - var json_hash = { - comments: [{ +test("normalizeArrayResponse with embedded objects with identical relationship and attribute key ", function() { + expect(1); + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' } + }, + //Makes the keyForRelationship and keyForAttribute collide. + keyForRelationship: function(key, type) { + return this.keyForAttribute(key, type); + } + })); + env.registry.register('serializer:super-villain', TestSerializer); + + var serializer = env.container.lookup("serializer:home-planet"); + + var json_hash = { + homePlanets: [{ + id: "1", + name: "Umber", + villains: [{ id: "1", - body: "Hello", - root: true, - children: [{ - id: "2", - body: "World", - root: false - }, - { - id: "3", - body: "Foo", - root: false - }] + firstName: "Alex", + lastName: "Baizeau" }] - }; - var array; + }] + }; + var array; - run(function() { - array = serializer.normalizeArrayResponse(env.store, Comment, json_hash, null, 'findAll'); - }); + run(function() { + array = serializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); + }); - deepEqual(array, { - "data": [{ - "id": "1", - "type": "comment", - "attributes": { - "body": "Hello", - "root": true - }, - "relationships": { - "children": { - "data": [ - { "id": "2", "type": "comment" }, - { "id": "3", "type": "comment" } - ] - } + deepEqual(array, { + "data": [{ + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "villains": { + "data": [ + { "id": "1", "type": "super-villain" } + ] } - }], - "included": [{ - "id": "2", - "type": "comment", - "attributes": { - "body": "World", - "root": false - }, - "relationships": {} - }, { - "id": "3", - "type": "comment", - "attributes": { - "body": "Foo", - "root": false - }, - "relationships": {} - }] - }, "Primary array is correct"); + } + }], + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Alex", + "lastName": "Baizeau" + }, + "relationships": {} + }] + }); +}); +test("normalizeArrayResponse with embedded objects of same type as primary type", function() { + env.registry.register('adapter:comment', DS.RESTAdapter); + env.registry.register('serializer:comment', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + children: { embedded: 'always' } + } + })); + + var serializer = env.container.lookup("serializer:comment"); + + var json_hash = { + comments: [{ + id: "1", + body: "Hello", + root: true, + children: [{ + id: "2", + body: "World", + root: false + }, + { + id: "3", + body: "Foo", + root: false + }] + }] + }; + var array; + + run(function() { + array = serializer.normalizeArrayResponse(env.store, Comment, json_hash, null, 'findAll'); }); - test("normalizeArrayResponse with embedded objects of same type, but from separate attributes", function() { - HomePlanet.reopen({ - reformedVillains: DS.hasMany('superVillain') - }); - - env.registry.register('adapter:home-planet', DS.RESTAdapter); - env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' }, - reformedVillains: { embedded: 'always' } + deepEqual(array, { + "data": [{ + "id": "1", + "type": "comment", + "attributes": { + "body": "Hello", + "root": true + }, + "relationships": { + "children": { + "data": [ + { "id": "2", "type": "comment" }, + { "id": "3", "type": "comment" } + ] + } } - })); - env.registry.register('serializer:super-villain', TestSerializer); + }], + "included": [{ + "id": "2", + "type": "comment", + "attributes": { + "body": "World", + "root": false + }, + "relationships": {} + }, { + "id": "3", + "type": "comment", + "attributes": { + "body": "Foo", + "root": false + }, + "relationships": {} + }] + }, "Primary array is correct"); +}); + +test("normalizeArrayResponse with embedded objects of same type, but from separate attributes", function() { + HomePlanet.reopen({ + reformedVillains: DS.hasMany('superVillain') + }); - var serializer = env.container.lookup("serializer:home-planet"); - var json_hash = { - homePlanets: [{ + env.registry.register('adapter:home-planet', DS.RESTAdapter); + env.registry.register('serializer:home-planet', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + reformedVillains: { embedded: 'always' } + } + })); + env.registry.register('serializer:super-villain', TestSerializer); + + var serializer = env.container.lookup("serializer:home-planet"); + var json_hash = { + homePlanets: [{ + id: "1", + name: "Earth", + villains: [{ id: "1", - name: "Earth", - villains: [{ - id: "1", - firstName: "Tom" - },{ - id: "3", - firstName: "Yehuda" - }], - reformedVillains: [{ - id: "2", - firstName: "Alex" - },{ - id: "4", - firstName: "Erik" - }] + firstName: "Tom" },{ + id: "3", + firstName: "Yehuda" + }], + reformedVillains: [{ id: "2", - name: "Mars", - villains: [{ - id: "1", - firstName: "Tom" - },{ - id: "3", - firstName: "Yehuda" - }], - reformedVillains: [{ - id: "5", - firstName: "Peter" - },{ - id: "6", - firstName: "Trek" - }] + firstName: "Alex" + },{ + id: "4", + firstName: "Erik" + }] + },{ + id: "2", + name: "Mars", + villains: [{ + id: "1", + firstName: "Tom" + },{ + id: "3", + firstName: "Yehuda" + }], + reformedVillains: [{ + id: "5", + firstName: "Peter" + },{ + id: "6", + firstName: "Trek" }] - }; + }] + }; - var json; - run(function() { - json = serializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); - }); + var json; + run(function() { + json = serializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); + }); - deepEqual(json, { - "data": [{ - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Earth" + deepEqual(json, { + "data": [{ + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Earth" + }, + "relationships": { + "reformedVillains": { + "data": [ + { "id": "2", "type": "super-villain" }, + { "id": "4", "type": "super-villain" } + ] }, - "relationships": { - "reformedVillains": { - "data": [ - { "id": "2", "type": "super-villain" }, - { "id": "4", "type": "super-villain" } - ] - }, - "villains": { - "data": [ - { "id": "1", "type": "super-villain" }, - { "id": "3", "type": "super-villain" } - ] - } + "villains": { + "data": [ + { "id": "1", "type": "super-villain" }, + { "id": "3", "type": "super-villain" } + ] } - }, { - "id": "2", - "type": "home-planet", - "attributes": { - "name": "Mars" + } + }, { + "id": "2", + "type": "home-planet", + "attributes": { + "name": "Mars" + }, + "relationships": { + "reformedVillains": { + "data": [ + { "id": "5", "type": "super-villain" }, + { "id": "6", "type": "super-villain" } + ] }, - "relationships": { - "reformedVillains": { - "data": [ - { "id": "5", "type": "super-villain" }, - { "id": "6", "type": "super-villain" } - ] - }, - "villains": { - "data": [ - { "id": "1", "type": "super-villain" }, - { "id": "3", "type": "super-villain" } - ] - } + "villains": { + "data": [ + { "id": "1", "type": "super-villain" }, + { "id": "3", "type": "super-villain" } + ] } - }], - "included": [{ - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom" - }, - "relationships": {} - }, { - "id": "3", - "type": "super-villain", - "attributes": { - "firstName": "Yehuda" - }, - "relationships": {} - }, { - "id": "2", - "type": "super-villain", - "attributes": { - "firstName": "Alex" - }, - "relationships": {} - }, { - "id": "4", - "type": "super-villain", - "attributes": { - "firstName": "Erik" - }, - "relationships": {} - }, { - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom" - }, - "relationships": {} - }, { - "id": "3", - "type": "super-villain", - "attributes": { - "firstName": "Yehuda" + } + }], + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom" + }, + "relationships": {} + }, { + "id": "3", + "type": "super-villain", + "attributes": { + "firstName": "Yehuda" + }, + "relationships": {} + }, { + "id": "2", + "type": "super-villain", + "attributes": { + "firstName": "Alex" + }, + "relationships": {} + }, { + "id": "4", + "type": "super-villain", + "attributes": { + "firstName": "Erik" + }, + "relationships": {} + }, { + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom" + }, + "relationships": {} + }, { + "id": "3", + "type": "super-villain", + "attributes": { + "firstName": "Yehuda" + }, + "relationships": {} + }, { + "id": "5", + "type": "super-villain", + "attributes": { + "firstName": "Peter" + }, + "relationships": {} + }, { + "id": "6", + "type": "super-villain", + "attributes": { + "firstName": "Trek" + }, + "relationships": {} + }] + }, "Primary array was correct"); +}); + +test("normalizeSingleResponse with embedded object (belongsTo relationship)", function() { + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' } + } + })); + //env.registry.register('serializer:secret-lab', TestSerializer); + + var serializer = env.container.lookup("serializer:super-villain"); + + var json_hash = { + superVillain: { + id: "1", + firstName: "Tom", + lastName: "Dale", + homePlanet: "123", + evilMinions: ["1", "2", "3"], + secretLab: { + minionCapacity: 5000, + vicinity: "California, USA", + id: "101" + }, + secretWeapons: [] + } + }; + var json; + + run(function() { + json = serializer.normalizeSingleResponse(env.store, SuperVillain, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": { + "evilMinions": { + "data": [ + { "id": "1", "type": "evil-minion" }, + { "id": "2", "type": "evil-minion" }, + { "id": "3", "type": "evil-minion" } + ] }, - "relationships": {} - }, { - "id": "5", - "type": "super-villain", - "attributes": { - "firstName": "Peter" + "homePlanet": { + "data": { "id": "123", "type": "home-planet" } }, - "relationships": {} - }, { - "id": "6", - "type": "super-villain", - "attributes": { - "firstName": "Trek" + "secretLab": { + "data": { "id": "101", "type": "secret-lab" } }, - "relationships": {} - }] - }, "Primary array was correct"); - }); - - test("normalizeSingleResponse with embedded object (belongsTo relationship)", function() { - env.registry.register('adapter:super-villain', DS.RESTAdapter); - env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' } + "secretWeapons": { + "data": [] + } } - })); - //env.registry.register('serializer:secret-lab', TestSerializer); - - var serializer = env.container.lookup("serializer:super-villain"); + }, + "included": [{ + "id": "101", + "type": "secret-lab", + "attributes": { + "minionCapacity": 5000, + "vicinity": "California, USA" + }, + "relationships": {} + }] + }); +}); - var json_hash = { +test("normalizeSingleResponse with multiply-nested belongsTo", function() { + env.registry.register('adapter:evil-minion', DS.RESTAdapter); + env.registry.register('serializer:evil-minion', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + superVillain: { embedded: 'always' } + } + })); + env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + homePlanet: { embedded: 'always' } + } + })); + + var serializer = env.container.lookup("serializer:evil-minion"); + var json_hash = { + evilMinion: { + id: "1", + name: "Alex", superVillain: { id: "1", firstName: "Tom", lastName: "Dale", - homePlanet: "123", - evilMinions: ["1", "2", "3"], - secretLab: { - minionCapacity: 5000, - vicinity: "California, USA", - id: "101" - }, - secretWeapons: [] + evilMinions: ["1"], + homePlanet: { + id: "1", + name: "Umber", + villains: ["1"] + } } - }; - var json; + } + }; + var json; - run(function() { - json = serializer.normalizeSingleResponse(env.store, SuperVillain, json_hash, '1', 'find'); - }); + run(function() { + json = serializer.normalizeSingleResponse(env.store, EvilMinion, json_hash, '1', 'find'); + }); - deepEqual(json, { - "data": { - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": { - "evilMinions": { - "data": [ - { "id": "1", "type": "evil-minion" }, - { "id": "2", "type": "evil-minion" }, - { "id": "3", "type": "evil-minion" } - ] - }, - "homePlanet": { - "data": { "id": "123", "type": "home-planet" } - }, - "secretLab": { - "data": { "id": "101", "type": "secret-lab" } - }, - "secretWeapons": { - "data": [] - } + deepEqual(json, { + "data": { + "id": "1", + "type": "evil-minion", + "attributes": { + "name": "Alex" + }, + "relationships": { + "superVillain": { + "data": { "id": "1", "type": "super-villain" } } + } + }, + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" }, - "included": [{ - "id": "101", - "type": "secret-lab", - "attributes": { - "minionCapacity": 5000, - "vicinity": "California, USA" + "relationships": { + "evilMinions": { + "data": [ + { "id": "1", "type": "evil-minion" } + ] }, - "relationships": {} - }] - }); - }); - - test("normalizeSingleResponse with multiply-nested belongsTo", function() { - env.registry.register('adapter:evil-minion', DS.RESTAdapter); - env.registry.register('serializer:evil-minion', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - superVillain: { embedded: 'always' } - } - })); - env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - homePlanet: { embedded: 'always' } + "homePlanet": { + "data": { "id": "1", "type": "home-planet" } + } } - })); - - var serializer = env.container.lookup("serializer:evil-minion"); - var json_hash = { - evilMinion: { - id: "1", - name: "Alex", - superVillain: { - id: "1", - firstName: "Tom", - lastName: "Dale", - evilMinions: ["1"], - homePlanet: { - id: "1", - name: "Umber", - villains: ["1"] - } + }, { + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "villains": { + "data": [ + { "id": "1", "type": "super-villain" } + ] } } - }; - var json; + }] + }, "Primary hash was correct"); +}); - run(function() { - json = serializer.normalizeSingleResponse(env.store, EvilMinion, json_hash, '1', 'find'); - }); +test("normalizeSingleResponse with polymorphic hasMany", function() { + SuperVillain.reopen({ + secretWeapons: DS.hasMany("secretWeapon", { polymorphic: true }) + }); - deepEqual(json, { - "data": { - "id": "1", - "type": "evil-minion", - "attributes": { - "name": "Alex" - }, - "relationships": { - "superVillain": { - "data": { "id": "1", "type": "super-villain" } - } - } - }, - "included": [{ - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": { - "evilMinions": { - "data": [ - { "id": "1", "type": "evil-minion" } - ] - }, - "homePlanet": { - "data": { "id": "1", "type": "home-planet" } - } - } - }, { - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretWeapons: { embedded: 'always' } + } + })); + var serializer = env.container.lookup("serializer:super-villain"); + + var json_hash = { + superVillain: { + id: "1", + firstName: "Tom", + lastName: "Dale", + secretWeapons: [ + { + id: "1", + type: "LightSaber", + name: "Tom's LightSaber", + color: "Red" }, - "relationships": { - "villains": { - "data": [ - { "id": "1", "type": "super-villain" } - ] - } + { + id: "1", + type: "SecretWeapon", + name: "The Death Star" } - }] - }, "Primary hash was correct"); - }); + ] + } + }; + var json; - test("normalizeSingleResponse with polymorphic hasMany", function() { - SuperVillain.reopen({ - secretWeapons: DS.hasMany("secretWeapon", { polymorphic: true }) - }); + run(function() { + json = serializer.normalizeSingleResponse(env.store, SuperVillain, json_hash, '1', 'findAll'); + }); - env.registry.register('adapter:super-villain', DS.RESTAdapter); - env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretWeapons: { embedded: 'always' } + deepEqual(json, { + "data": { + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": { + "secretWeapons": { + "data": [ + { "id": "1", "type": "light-saber" }, + { "id": "1", "type": "secret-weapon" } + ] + } } - })); - var serializer = env.container.lookup("serializer:super-villain"); + }, + "included": [{ + "id": "1", + "type": "light-saber", + "attributes": { + "color": "Red", + "name": "Tom's LightSaber" + }, + "relationships": {} + }, { + "id": "1", + "type": "secret-weapon", + "attributes": { + "name": "The Death Star" + }, + "relationships": {} + }] + }, "Primary hash was correct"); +}); - var json_hash = { - superVillain: { +test("normalizeSingleResponse with polymorphic belongsTo", function() { + SuperVillain.reopen({ + secretLab: DS.belongsTo("secretLab", { polymorphic: true }) + }); + + env.registry.register('adapter:super-villain', DS.RESTAdapter); + env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' } + } + })); + var serializer = env.container.lookup("serializer:super-villain"); + + var json_hash = { + superVillain: { + id: "1", + firstName: "Tom", + lastName: "Dale", + secretLab: { id: "1", - firstName: "Tom", - lastName: "Dale", - secretWeapons: [ - { - id: "1", - type: "LightSaber", - name: "Tom's LightSaber", - color: "Red" - }, - { - id: "1", - type: "SecretWeapon", - name: "The Death Star" - } - ] + type: "bat-cave", + infiltrated: true } - }; - var json; + } + }; - run(function() { - json = serializer.normalizeSingleResponse(env.store, SuperVillain, json_hash, '1', 'findAll'); - }); + var json; - deepEqual(json, { - "data": { - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": { - "secretWeapons": { - "data": [ - { "id": "1", "type": "light-saber" }, - { "id": "1", "type": "secret-weapon" } - ] - } - } - }, - "included": [{ - "id": "1", - "type": "light-saber", - "attributes": { - "color": "Red", - "name": "Tom's LightSaber" - }, - "relationships": {} - }, { - "id": "1", - "type": "secret-weapon", - "attributes": { - "name": "The Death Star" - }, - "relationships": {} - }] - }, "Primary hash was correct"); + run(function() { + json = serializer.normalizeSingleResponse(env.store, SuperVillain, json_hash, '1', 'find'); }); - test("normalizeSingleResponse with polymorphic belongsTo", function() { - SuperVillain.reopen({ - secretLab: DS.belongsTo("secretLab", { polymorphic: true }) - }); - - env.registry.register('adapter:super-villain', DS.RESTAdapter); - env.registry.register('serializer:super-villain', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' } + deepEqual(json, { + "data": { + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": { + "secretLab": { + "data": { "id": "1", "type": "bat-cave" } + } } - })); - var serializer = env.container.lookup("serializer:super-villain"); + }, + "included": [{ + "id": "1", + "type": "bat-cave", + "attributes": { + "infiltrated": true + }, + "relationships": {} + }] + }, "Primary has was correct"); +}); - var json_hash = { +test("normalize with custom belongsTo primary key", function() { + env.registry.register('adapter:evil-minion', DS.RESTAdapter); + env.registry.register('serializer:evil-minion', TestSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + superVillain: { embedded: 'always' } + } + })); + env.registry.register('serializer:super-villain', TestSerializer.extend({ + primaryKey: 'custom' + })); + + var serializer = env.container.lookup("serializer:evil-minion"); + var json_hash = { + evil_minion: { + id: "1", + name: "Alex", superVillain: { - id: "1", + custom: "1", firstName: "Tom", - lastName: "Dale", - secretLab: { - id: "1", - type: "bat-cave", - infiltrated: true - } + lastName: "Dale" } - }; + } + }; + var json; - var json; - - run(function() { - json = serializer.normalizeSingleResponse(env.store, SuperVillain, json_hash, '1', 'find'); - }); - - deepEqual(json, { - "data": { - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": { - "secretLab": { - "data": { "id": "1", "type": "bat-cave" } - } - } - }, - "included": [{ - "id": "1", - "type": "bat-cave", - "attributes": { - "infiltrated": true - }, - "relationships": {} - }] - }, "Primary has was correct"); + run(function() { + json = serializer.normalizeResponse(env.store, EvilMinion, json_hash, '1', 'find'); }); - test("normalize with custom belongsTo primary key", function() { - env.registry.register('adapter:evil-minion', DS.RESTAdapter); - env.registry.register('serializer:evil-minion', TestSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - superVillain: { embedded: 'always' } - } - })); - env.registry.register('serializer:super-villain', TestSerializer.extend({ - primaryKey: 'custom' - })); - - var serializer = env.container.lookup("serializer:evil-minion"); - var json_hash = { - evil_minion: { - id: "1", - name: "Alex", - superVillain: { - custom: "1", - firstName: "Tom", - lastName: "Dale" + deepEqual(json, { + "data": { + "id": "1", + "type": "evil-minion", + "attributes": { + "name": "Alex" + }, + "relationships": { + "superVillain": { + "data": { "id": "1", "type": "super-villain" } } } - }; - var json; - - run(function() { - json = serializer.normalizeResponse(env.store, EvilMinion, json_hash, '1', 'find'); - }); - - deepEqual(json, { - "data": { - "id": "1", - "type": "evil-minion", - "attributes": { - "name": "Alex" - }, - "relationships": { - "superVillain": { - "data": { "id": "1", "type": "super-villain" } - } - } + }, + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" }, - "included": [{ - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": {} - }] - }, "Primary hash was correct"); - }); - -} + "relationships": {} + }] + }, "Primary hash was correct"); +}); diff --git a/packages/ember-data/tests/integration/serializers/json-serializer-new-test.js b/packages/ember-data/tests/integration/serializers/json-serializer-new-test.js index 23411fbd046..aaee993ef4e 100644 --- a/packages/ember-data/tests/integration/serializers/json-serializer-new-test.js +++ b/packages/ember-data/tests/integration/serializers/json-serializer-new-test.js @@ -34,158 +34,154 @@ module("integration/serializer/json - JSONSerializer (new API)", { } }); -if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { - - test("normalizeArrayResponse normalizes each record in the array", function() { - var postNormalizeCount = 0; - var posts = [ - { id: "1", title: "Rails is omakase" }, - { id: "2", title: "Another Post" } - ]; - - env.registry.register('serializer:post', TestSerializer.extend({ - normalize: function () { - postNormalizeCount++; - return this._super.apply(this, arguments); - } - })); - - run(function() { - env.container.lookup("serializer:post").normalizeArrayResponse(env.store, Post, posts, null, 'findAll'); - }); - equal(postNormalizeCount, 2, "two posts are normalized"); +test("normalizeArrayResponse normalizes each record in the array", function() { + var postNormalizeCount = 0; + var posts = [ + { id: "1", title: "Rails is omakase" }, + { id: "2", title: "Another Post" } + ]; + + env.registry.register('serializer:post', TestSerializer.extend({ + normalize: function () { + postNormalizeCount++; + return this._super.apply(this, arguments); + } + })); + + run(function() { + env.container.lookup("serializer:post").normalizeArrayResponse(env.store, Post, posts, null, 'findAll'); }); + equal(postNormalizeCount, 2, "two posts are normalized"); +}); - test('Serializer should respect the attrs hash when extracting records', function() { - env.registry.register("serializer:post", TestSerializer.extend({ - attrs: { - title: "title_payload_key", - comments: { key: 'my_comments' } - } - })); - - var jsonHash = { - id: "1", - title_payload_key: "Rails is omakase", - my_comments: [1, 2] - }; +test('Serializer should respect the attrs hash when extracting records', function() { + env.registry.register("serializer:post", TestSerializer.extend({ + attrs: { + title: "title_payload_key", + comments: { key: 'my_comments' } + } + })); - var post = env.container.lookup("serializer:post").normalizeSingleResponse(env.store, Post, jsonHash, '1', 'find'); + var jsonHash = { + id: "1", + title_payload_key: "Rails is omakase", + my_comments: [1, 2] + }; - equal(post.data.attributes.title, "Rails is omakase"); - deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }, { id: "2", type: "comment" }]); - }); + var post = env.container.lookup("serializer:post").normalizeSingleResponse(env.store, Post, jsonHash, '1', 'find'); - test('normalizeSingleResponse should extract meta using extractMeta', function() { - env.registry.register("serializer:post", TestSerializer.extend({ - extractMeta: function(store, modelClass, payload) { - let meta = this._super(...arguments); - meta.authors.push('Tomhuda'); - return meta; - } - })); - - var jsonHash = { - id: "1", - title_payload_key: "Rails is omakase", - my_comments: [1, 2], - meta: { - authors: ['Tomster'] - } - }; - - var post = env.container.lookup("serializer:post").normalizeSingleResponse(env.store, Post, jsonHash, '1', 'find'); - - deepEqual(post.meta.authors, ['Tomster', 'Tomhuda']); - }); + equal(post.data.attributes.title, "Rails is omakase"); + deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }, { id: "2", type: "comment" }]); +}); - test("Serializer should respect the primaryKey attribute when extracting records", function() { - env.registry.register('serializer:post', TestSerializer.extend({ - primaryKey: '_ID_' - })); +test('normalizeSingleResponse should extract meta using extractMeta', function() { + env.registry.register("serializer:post", TestSerializer.extend({ + extractMeta: function(store, modelClass, payload) { + let meta = this._super(...arguments); + meta.authors.push('Tomhuda'); + return meta; + } + })); + + var jsonHash = { + id: "1", + title_payload_key: "Rails is omakase", + my_comments: [1, 2], + meta: { + authors: ['Tomster'] + } + }; + + var post = env.container.lookup("serializer:post").normalizeSingleResponse(env.store, Post, jsonHash, '1', 'find'); + + deepEqual(post.meta.authors, ['Tomster', 'Tomhuda']); +}); - var jsonHash = { "_ID_": 1, title: "Rails is omakase" }; +test("Serializer should respect the primaryKey attribute when extracting records", function() { + env.registry.register('serializer:post', TestSerializer.extend({ + primaryKey: '_ID_' + })); - run(function() { - post = env.container.lookup("serializer:post").normalizeSingleResponse(env.store, Post, jsonHash, '1', 'find'); - }); + var jsonHash = { "_ID_": 1, title: "Rails is omakase" }; - equal(post.data.id, "1"); - equal(post.data.attributes.title, "Rails is omakase"); + run(function() { + post = env.container.lookup("serializer:post").normalizeSingleResponse(env.store, Post, jsonHash, '1', 'find'); }); - test("Serializer should respect keyForAttribute when extracting records", function() { - env.registry.register('serializer:post', TestSerializer.extend({ - keyForAttribute: function(key) { - return key.toUpperCase(); - } - })); - - var jsonHash = { id: 1, TITLE: 'Rails is omakase' }; + equal(post.data.id, "1"); + equal(post.data.attributes.title, "Rails is omakase"); +}); - post = env.container.lookup("serializer:post").normalize(Post, jsonHash); +test("Serializer should respect keyForAttribute when extracting records", function() { + env.registry.register('serializer:post', TestSerializer.extend({ + keyForAttribute: function(key) { + return key.toUpperCase(); + } + })); - equal(post.data.id, "1"); - equal(post.data.attributes.title, "Rails is omakase"); - }); + var jsonHash = { id: 1, TITLE: 'Rails is omakase' }; - test("Serializer should respect keyForRelationship when extracting records", function() { - env.registry.register('serializer:post', TestSerializer.extend({ - keyForRelationship: function(key, type) { - return key.toUpperCase(); - } - })); + post = env.container.lookup("serializer:post").normalize(Post, jsonHash); - var jsonHash = { id: 1, title: 'Rails is omakase', COMMENTS: ['1'] }; + equal(post.data.id, "1"); + equal(post.data.attributes.title, "Rails is omakase"); +}); - post = env.container.lookup("serializer:post").normalize(Post, jsonHash); +test("Serializer should respect keyForRelationship when extracting records", function() { + env.registry.register('serializer:post', TestSerializer.extend({ + keyForRelationship: function(key, type) { + return key.toUpperCase(); + } + })); - deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }]); - }); + var jsonHash = { id: 1, title: 'Rails is omakase', COMMENTS: ['1'] }; - test("Calling normalize should normalize the payload (only the passed keys)", function () { - expect(1); - var Person = DS.Model.extend({ - posts: DS.hasMany('post') - }); - env.registry.register('serializer:post', TestSerializer.extend({ - attrs: { - notInHash: 'aCustomAttrNotInHash', - inHash: 'aCustomAttrInHash' - } - })); + post = env.container.lookup("serializer:post").normalize(Post, jsonHash); - env.registry.register('model:person', Person); + deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }]); +}); - Post.reopen({ - content: DS.attr('string'), - author: DS.belongsTo('person'), - notInHash: DS.attr('string'), - inHash: DS.attr('string') - }); +test("Calling normalize should normalize the payload (only the passed keys)", function () { + expect(1); + var Person = DS.Model.extend({ + posts: DS.hasMany('post') + }); + env.registry.register('serializer:post', TestSerializer.extend({ + attrs: { + notInHash: 'aCustomAttrNotInHash', + inHash: 'aCustomAttrInHash' + } + })); + + env.registry.register('model:person', Person); + + Post.reopen({ + content: DS.attr('string'), + author: DS.belongsTo('person'), + notInHash: DS.attr('string'), + inHash: DS.attr('string') + }); - var normalizedPayload = env.container.lookup("serializer:post").normalize(Post, { - id: '1', - title: 'Ember rocks', - author: 1, - aCustomAttrInHash: 'blah' - }); + var normalizedPayload = env.container.lookup("serializer:post").normalize(Post, { + id: '1', + title: 'Ember rocks', + author: 1, + aCustomAttrInHash: 'blah' + }); - deepEqual(normalizedPayload, { - "data": { - "id": "1", - "type": "post", - "attributes": { - "inHash": "blah", - "title": "Ember rocks" - }, - "relationships": { - "author": { - "data": { "id": "1", "type": "person" } - } + deepEqual(normalizedPayload, { + "data": { + "id": "1", + "type": "post", + "attributes": { + "inHash": "blah", + "title": "Ember rocks" + }, + "relationships": { + "author": { + "data": { "id": "1", "type": "person" } } } - }); + } }); - -} +}); diff --git a/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js b/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js index 866322b4c25..6c38fb5e8b1 100644 --- a/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js +++ b/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js @@ -56,359 +56,355 @@ module("integration/serializer/rest - RESTSerializer (new API)", { } }); -if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { - - test("normalizeSingleResponse with custom modelNameFromPayloadKey", function() { - expect(1); - - env.restNewSerializer.modelNameFromPayloadKey = function(root) { - var camelized = Ember.String.camelize(root); - return Ember.String.singularize(camelized); - }; - - var jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], - super_villains: [{ id: "1", firstName: "Tom", lastName: "Dale", homePlanet: "1" }] - }; - var array; - - run(function() { - array = env.container.lookup("serializer:application").normalizeSingleResponse(env.store, HomePlanet, jsonHash, '1', 'find'); - }); +test("normalizeSingleResponse with custom modelNameFromPayloadKey", function() { + expect(1); + + env.restNewSerializer.modelNameFromPayloadKey = function(root) { + var camelized = Ember.String.camelize(root); + return Ember.String.singularize(camelized); + }; + + var jsonHash = { + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], + super_villains: [{ id: "1", firstName: "Tom", lastName: "Dale", homePlanet: "1" }] + }; + var array; + + run(function() { + array = env.container.lookup("serializer:application").normalizeSingleResponse(env.store, HomePlanet, jsonHash, '1', 'find'); + }); - deepEqual(array, { - data: { - id: '1', - type: 'home-planet', - attributes: { - name: 'Umber' - }, - relationships: { - superVillains: { - data: [{ id: '1', type: 'super-villain' }] - } + deepEqual(array, { + data: { + id: '1', + type: 'home-planet', + attributes: { + name: 'Umber' + }, + relationships: { + superVillains: { + data: [{ id: '1', type: 'super-villain' }] } + } + }, + included: [{ + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale' }, - included: [{ - id: '1', - type: 'super-villain', - attributes: { - firstName: 'Tom', - lastName: 'Dale' - }, - relationships: { - homePlanet: { - data: { id: '1', type: 'home-planet' } - } + relationships: { + homePlanet: { + data: { id: '1', type: 'home-planet' } } - }] - }); + } + }] }); +}); - test('normalizeArrayResponse should extract meta using extractMeta', function() { - env.registry.register("serializer:home-planet", TestSerializer.extend({ - extractMeta: function(store, modelClass, payload) { - let meta = this._super(...arguments); - meta.authors.push('Tomhuda'); - return meta; - } - })); +test('normalizeArrayResponse should extract meta using extractMeta', function() { + env.registry.register("serializer:home-planet", TestSerializer.extend({ + extractMeta: function(store, modelClass, payload) { + let meta = this._super(...arguments); + meta.authors.push('Tomhuda'); + return meta; + } + })); - var jsonHash = { - meta: { authors: ['Tomster'] }, - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] - }; + var jsonHash = { + meta: { authors: ['Tomster'] }, + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] + }; - var json = env.container.lookup("serializer:home-planet").normalizeArrayResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); + var json = env.container.lookup("serializer:home-planet").normalizeArrayResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); - deepEqual(json.meta.authors, ['Tomster', 'Tomhuda']); - }); + deepEqual(json.meta.authors, ['Tomster', 'Tomhuda']); +}); - test("normalizeArrayResponse warning with custom modelNameFromPayloadKey", function() { - var homePlanets; - env.restNewSerializer.modelNameFromPayloadKey = function(root) { - //return some garbage that won"t resolve in the container - return "garbage"; - }; - - var jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] - }; - - warns(function() { - env.restNewSerializer.normalizeArrayResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); - }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); - - // should not warn if a model is found. - env.restNewSerializer.modelNameFromPayloadKey = function(root) { - return Ember.String.camelize(Ember.String.singularize(root)); - }; - - jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] - }; - - noWarns(function() { - run(function() { - homePlanets = env.restNewSerializer.normalizeArrayResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); - }); - }); +test("normalizeArrayResponse warning with custom modelNameFromPayloadKey", function() { + var homePlanets; + env.restNewSerializer.modelNameFromPayloadKey = function(root) { + //return some garbage that won"t resolve in the container + return "garbage"; + }; - equal(homePlanets.data.length, 1); - equal(homePlanets.data[0].attributes.name, "Umber"); - deepEqual(homePlanets.data[0].relationships.superVillains.data, [{ id: '1', type: 'super-villain' }]); - }); + var jsonHash = { + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] + }; - test("normalizeSingleResponse warning with custom modelNameFromPayloadKey", function() { - var homePlanet; - var oldModelNameFromPayloadKey = env.restNewSerializer.modelNameFromPayloadKey; - env.restNewSerializer.modelNameFromPayloadKey = function(root) { - //return some garbage that won"t resolve in the container - return "garbage"; - }; - - var jsonHash = { - home_planet: { id: "1", name: "Umber", superVillains: [1] } - }; - - warns(Ember.run.bind(null, function() { - run(function() { - env.restNewSerializer.normalizeSingleResponse(env.store, HomePlanet, jsonHash, '1', 'find'); - }); - }), /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); - - // should not warn if a model is found. - env.restNewSerializer.modelNameFromPayloadKey = oldModelNameFromPayloadKey; - jsonHash = { - home_planet: { id: "1", name: "Umber", superVillains: [1] } - }; - - noWarns(function() { - run(function() { - homePlanet = env.restNewSerializer.normalizeSingleResponse(env.store, HomePlanet, jsonHash, 1, 'find'); - }); - }); + warns(function() { + env.restNewSerializer.normalizeArrayResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); + }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); - equal(homePlanet.data.attributes.name, "Umber"); - deepEqual(homePlanet.data.relationships.superVillains.data, [{ id: '1', type: 'super-villain' }]); - }); + // should not warn if a model is found. + env.restNewSerializer.modelNameFromPayloadKey = function(root) { + return Ember.String.camelize(Ember.String.singularize(root)); + }; - test("normalizeResponse can load secondary records of the same type without affecting the query count", function() { - var jsonHash = { - comments: [{ id: "1", body: "Parent Comment", root: true, children: [2, 3] }], - _comments: [ - { id: "2", body: "Child Comment 1", root: false }, - { id: "3", body: "Child Comment 2", root: false } - ] - }; - var array; + jsonHash = { + home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] + }; + noWarns(function() { run(function() { - array = env.restNewSerializer.normalizeResponse(env.store, Comment, jsonHash, '1', 'find'); + homePlanets = env.restNewSerializer.normalizeArrayResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); }); + }); - deepEqual(array, { - "data": { - "id": "1", - "type": "comment", - "attributes": { - "body": "Parent Comment", - "root": true - }, - "relationships": { - "children": { - "data": [ - { "id": "2", "type": "comment" }, - { "id": "3", "type": "comment" } - ] - } - } - }, - "included": [{ - "id": "2", - "type": "comment", - "attributes": { - "body": "Child Comment 1", - "root": false - }, - "relationships": {} - }, { - "id": "3", - "type": "comment", - "attributes": { - "body": "Child Comment 2", - "root": false - }, - "relationships": {} - }] - }); + equal(homePlanets.data.length, 1); + equal(homePlanets.data[0].attributes.name, "Umber"); + deepEqual(homePlanets.data[0].relationships.superVillains.data, [{ id: '1', type: 'super-villain' }]); +}); - // normalizeResponse does not push records to the store - //equal(env.store.recordForId("comment", "2").get("body"), "Child Comment 1", "Secondary records are in the store"); - //equal(env.store.recordForId("comment", "3").get("body"), "Child Comment 2", "Secondary records are in the store"); - }); +test("normalizeSingleResponse warning with custom modelNameFromPayloadKey", function() { + var homePlanet; + var oldModelNameFromPayloadKey = env.restNewSerializer.modelNameFromPayloadKey; + env.restNewSerializer.modelNameFromPayloadKey = function(root) { + //return some garbage that won"t resolve in the container + return "garbage"; + }; - test("normalizeSingleResponse loads secondary records with correct serializer", function() { - var superVillainNormalizeCount = 0; + var jsonHash = { + home_planet: { id: "1", name: "Umber", superVillains: [1] } + }; - env.registry.register('serializer:super-villain', TestSerializer.extend({ - normalize: function() { - superVillainNormalizeCount++; - return this._super.apply(this, arguments); - } - })); + warns(Ember.run.bind(null, function() { + run(function() { + env.restNewSerializer.normalizeSingleResponse(env.store, HomePlanet, jsonHash, '1', 'find'); + }); + }), /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); - var jsonHash = { - evilMinion: { id: "1", name: "Tom Dale", superVillain: 1 }, - superVillains: [{ id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1" }] - }; + // should not warn if a model is found. + env.restNewSerializer.modelNameFromPayloadKey = oldModelNameFromPayloadKey; + jsonHash = { + home_planet: { id: "1", name: "Umber", superVillains: [1] } + }; + noWarns(function() { run(function() { - env.restNewSerializer.normalizeSingleResponse(env.store, EvilMinion, jsonHash, '1', 'find'); + homePlanet = env.restNewSerializer.normalizeSingleResponse(env.store, HomePlanet, jsonHash, 1, 'find'); }); + }); - equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); + equal(homePlanet.data.attributes.name, "Umber"); + deepEqual(homePlanet.data.relationships.superVillains.data, [{ id: '1', type: 'super-villain' }]); +}); + +test("normalizeResponse can load secondary records of the same type without affecting the query count", function() { + var jsonHash = { + comments: [{ id: "1", body: "Parent Comment", root: true, children: [2, 3] }], + _comments: [ + { id: "2", body: "Child Comment 1", root: false }, + { id: "3", body: "Child Comment 2", root: false } + ] + }; + var array; + + run(function() { + array = env.restNewSerializer.normalizeResponse(env.store, Comment, jsonHash, '1', 'find'); }); - test("normalizeSingleResponse returns null if payload contains null", function() { - expect(1); + deepEqual(array, { + "data": { + "id": "1", + "type": "comment", + "attributes": { + "body": "Parent Comment", + "root": true + }, + "relationships": { + "children": { + "data": [ + { "id": "2", "type": "comment" }, + { "id": "3", "type": "comment" } + ] + } + } + }, + "included": [{ + "id": "2", + "type": "comment", + "attributes": { + "body": "Child Comment 1", + "root": false + }, + "relationships": {} + }, { + "id": "3", + "type": "comment", + "attributes": { + "body": "Child Comment 2", + "root": false + }, + "relationships": {} + }] + }); - var jsonHash = { - evilMinion: null - }; - var value; + // normalizeResponse does not push records to the store + //equal(env.store.recordForId("comment", "2").get("body"), "Child Comment 1", "Secondary records are in the store"); + //equal(env.store.recordForId("comment", "3").get("body"), "Child Comment 2", "Secondary records are in the store"); +}); - run(function() { - value = env.restNewSerializer.normalizeSingleResponse(env.store, EvilMinion, jsonHash, null, 'find'); - }); +test("normalizeSingleResponse loads secondary records with correct serializer", function() { + var superVillainNormalizeCount = 0; - deepEqual(value, { data: null, included: [] }, "returned value is null"); - }); + env.registry.register('serializer:super-villain', TestSerializer.extend({ + normalize: function() { + superVillainNormalizeCount++; + return this._super.apply(this, arguments); + } + })); - test("normalizeArrayResponse loads secondary records with correct serializer", function() { - var superVillainNormalizeCount = 0; + var jsonHash = { + evilMinion: { id: "1", name: "Tom Dale", superVillain: 1 }, + superVillains: [{ id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1" }] + }; - env.registry.register('serializer:super-villain', TestSerializer.extend({ - normalize: function() { - superVillainNormalizeCount++; - return this._super.apply(this, arguments); - } - })); + run(function() { + env.restNewSerializer.normalizeSingleResponse(env.store, EvilMinion, jsonHash, '1', 'find'); + }); + + equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); +}); - var jsonHash = { - evilMinions: [{ id: "1", name: "Tom Dale", superVillain: 1 }], - superVillains: [{ id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1" }] - }; +test("normalizeSingleResponse returns null if payload contains null", function() { + expect(1); - run(function() { - env.restNewSerializer.normalizeArrayResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); - }); + var jsonHash = { + evilMinion: null + }; + var value; - equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); + run(function() { + value = env.restNewSerializer.normalizeSingleResponse(env.store, EvilMinion, jsonHash, null, 'find'); }); - test('normalizeHash normalizes specific parts of the payload', function() { - env.registry.register('serializer:application', TestSerializer.extend({ - normalizeHash: { - homePlanets: function(hash) { - hash.id = hash._id; - delete hash._id; - return hash; - } - } - })); + deepEqual(value, { data: null, included: [] }, "returned value is null"); +}); - var jsonHash = { - homePlanets: [{ _id: "1", name: "Umber", superVillains: [1] }] - }; - var array; +test("normalizeArrayResponse loads secondary records with correct serializer", function() { + var superVillainNormalizeCount = 0; - run(function() { - array = env.restNewSerializer.normalizeArrayResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); - }); + env.registry.register('serializer:super-villain', TestSerializer.extend({ + normalize: function() { + superVillainNormalizeCount++; + return this._super.apply(this, arguments); + } + })); - deepEqual(array, { - "data": [{ - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "superVillains": { - "data": [ - { "id": "1", "type": "super-villain" } - ] - } - } - }], - "included": [] - }); + var jsonHash = { + evilMinions: [{ id: "1", name: "Tom Dale", superVillain: 1 }], + superVillains: [{ id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1" }] + }; + run(function() { + env.restNewSerializer.normalizeArrayResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); }); - test('normalizeHash works with transforms', function() { - env.registry.register('serializer:application', TestSerializer.extend({ - normalizeHash: { - evilMinions: function(hash) { - hash.condition = hash._condition; - delete hash._condition; - return hash; - } + equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); +}); + +test('normalizeHash normalizes specific parts of the payload', function() { + env.registry.register('serializer:application', TestSerializer.extend({ + normalizeHash: { + homePlanets: function(hash) { + hash.id = hash._id; + delete hash._id; + return hash; } - })); - - env.registry.register('transform:condition', DS.Transform.extend({ - deserialize: function(serialized) { - if (serialized === 1) { - return "healing"; - } else { - return "unknown"; - } + } + })); + + var jsonHash = { + homePlanets: [{ _id: "1", name: "Umber", superVillains: [1] }] + }; + var array; + + run(function() { + array = env.restNewSerializer.normalizeArrayResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); + }); + + deepEqual(array, { + "data": [{ + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" }, - serialize: function(deserialized) { - if (deserialized === "healing") { - return 1; - } else { - return 2; + "relationships": { + "superVillains": { + "data": [ + { "id": "1", "type": "super-villain" } + ] } } - })); - - EvilMinion.reopen({ condition: DS.attr('condition') }); + }], + "included": [] + }); - var jsonHash = { - evilMinions: [{ id: "1", name: "Tom Dale", superVillain: 1, _condition: 1 }] - }; - var array; +}); - run(function() { - array = env.restNewSerializer.normalizeArrayResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); - }); +test('normalizeHash works with transforms', function() { + env.registry.register('serializer:application', TestSerializer.extend({ + normalizeHash: { + evilMinions: function(hash) { + hash.condition = hash._condition; + delete hash._condition; + return hash; + } + } + })); + + env.registry.register('transform:condition', DS.Transform.extend({ + deserialize: function(serialized) { + if (serialized === 1) { + return "healing"; + } else { + return "unknown"; + } + }, + serialize: function(deserialized) { + if (deserialized === "healing") { + return 1; + } else { + return 2; + } + } + })); - equal(array.data[0].attributes.condition, "healing"); - }); + EvilMinion.reopen({ condition: DS.attr('condition') }); - test('normalize should allow for different levels of normalization', function() { - env.registry.register('serializer:application', TestSerializer.extend({ - attrs: { - superVillain: 'is_super_villain' - }, - keyForAttribute: function(attr) { - return Ember.String.decamelize(attr); - } - })); + var jsonHash = { + evilMinions: [{ id: "1", name: "Tom Dale", superVillain: 1, _condition: 1 }] + }; + var array; - var jsonHash = { - evilMinions: [{ id: "1", name: "Tom Dale", is_super_villain: 1 }] - }; - var array; + run(function() { + array = env.restNewSerializer.normalizeArrayResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); + }); - run(function() { - array = env.restNewSerializer.normalizeArrayResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); - }); + equal(array.data[0].attributes.condition, "healing"); +}); - equal(array.data[0].relationships.superVillain.data.id, 1); +test('normalize should allow for different levels of normalization', function() { + env.registry.register('serializer:application', TestSerializer.extend({ + attrs: { + superVillain: 'is_super_villain' + }, + keyForAttribute: function(attr) { + return Ember.String.decamelize(attr); + } + })); + + var jsonHash = { + evilMinions: [{ id: "1", name: "Tom Dale", is_super_villain: 1 }] + }; + var array; + + run(function() { + array = env.restNewSerializer.normalizeArrayResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); }); -} + equal(array.data[0].relationships.superVillain.data.id, 1); +}); diff --git a/packages/ember-data/tests/integration/serializers/rest-serializer-test.js b/packages/ember-data/tests/integration/serializers/rest-serializer-test.js index 0870b6514ae..595ae16b625 100644 --- a/packages/ember-data/tests/integration/serializers/rest-serializer-test.js +++ b/packages/ember-data/tests/integration/serializers/rest-serializer-test.js @@ -57,74 +57,6 @@ test("modelNameFromPayloadKey returns always same modelName even for uncountable equal(env.restSerializer.modelNameFromPayloadKey('multi-words'), expectedModelName); }); -if (!Ember.FEATURES.isEnabled('ds-new-serializer-api')) { - test("extractArray with custom modelNameFromPayloadKey", function() { - env.restSerializer.modelNameFromPayloadKey = function(root) { - var camelized = Ember.String.camelize(root); - return Ember.String.singularize(camelized); - }; - - var jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], - super_villains: [{ id: "1", firstName: "Tom", lastName: "Dale", homePlanet: "1" }] - }; - var array; - - run(function() { - array = env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); - }); - - deepEqual(array, [{ - id: "1", - name: "Umber", - superVillains: [1] - }]); - - run(function() { - env.store.find('super-villain', 1).then(function(minion) { - equal(minion.get('firstName'), "Tom"); - }); - }); - }); -} - -if (!Ember.FEATURES.isEnabled('ds-new-serializer-api')) { - test("extractArray warning with custom modelNameFromPayloadKey", function() { - var homePlanets; - env.restSerializer.modelNameFromPayloadKey = function(root) { - //return some garbage that won"t resolve in the container - return "garbage"; - }; - - var jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] - }; - - warns(function() { - env.restSerializer.extractArray(env.store, HomePlanet, jsonHash); - }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); - - // should not warn if a model is found. - env.restSerializer.modelNameFromPayloadKey = function(root) { - return Ember.String.camelize(Ember.String.singularize(root)); - }; - - jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] - }; - - noWarns(function() { - run(function() { - homePlanets = Ember.A(env.restSerializer.extractArray(env.store, HomePlanet, jsonHash)); - }); - }); - - equal(get(homePlanets, "length"), 1); - equal(get(homePlanets, "firstObject.name"), "Umber"); - deepEqual(get(homePlanets, "firstObject.superVillains"), [1]); - }); -} - test("extractSingle warning with custom modelNameFromPayloadKey", function() { var homePlanet; env.restSerializer.modelNameFromPayloadKey = function(root) { @@ -161,120 +93,6 @@ test("extractSingle warning with custom modelNameFromPayloadKey", function() { deepEqual(get(homePlanet, "superVillains"), [1]); }); -if (!Ember.FEATURES.isEnabled('ds-new-serializer-api')) { - test("pushPayload - single record payload - warning with custom modelNameFromPayloadKey", function() { - var homePlanet; - var HomePlanetRestSerializer = DS.RESTSerializer.extend({ - modelNameFromPayloadKey: function(root) { - //return some garbage that won"t resolve in the container - if (root === "home_planet") { - return "garbage"; - } else { - return Ember.String.singularize(Ember.String.camelize(root)); - } - } - }); - - env.registry.register("serializer:home-planet", HomePlanetRestSerializer); - - var jsonHash = { - home_planet: { id: "1", name: "Umber", superVillains: [1] }, - super_villains: [{ id: "1", firstName: "Stanley" }] - }; - - warns(function() { - run(function() { - env.store.pushPayload('home-planet', jsonHash); - }); - }, /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); - - // assert non-warned records get pushed into store correctly - var superVillain = env.store.peekRecord('super-villain', "1"); - equal(get(superVillain, "firstName"), "Stanley"); - - // Serializers are singletons, so that"s why we use the store which - // looks at the container to look it up - env.store.serializerFor('home-planet').reopen({ - modelNameFromPayloadKey: function(root) { - // should not warn if a model is found. - return Ember.String.camelize(Ember.String.singularize(root)); - } - }); - - jsonHash = { - home_planet: { id: "1", name: "Umber", superVillains: [1] }, - super_villains: [{ id: "1", firstName: "Stanley" }] - }; - - noWarns(function() { - run(function() { - env.store.pushPayload('home-planet', jsonHash); - homePlanet = env.store.peekRecord('home-planet', "1"); - }); - }); - - equal(get(homePlanet, "name"), "Umber"); - deepEqual(get(homePlanet, "superVillains.firstObject.firstName"), "Stanley"); - }); -} - -if (!Ember.FEATURES.isEnabled('ds-new-serializer-api')) { - test("pushPayload - multiple record payload (extractArray) - warning with custom modelNameFromPayloadKey", function() { - var homePlanet; - var HomePlanetRestSerializer = DS.RESTSerializer.extend({ - modelNameFromPayloadKey: function(root) { - //return some garbage that won"t resolve in the container - if (root === "home_planets") { - return "garbage"; - } else { - return Ember.String.singularize(Ember.String.camelize(root)); - } - } - }); - - env.registry.register("serializer:home-planet", HomePlanetRestSerializer); - - var jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], - super_villains: [{ id: "1", firstName: "Stanley" }] - }; - - warns(function() { - run(function() { - env.store.pushPayload('home-planet', jsonHash); - }); - }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); - - // assert non-warned records get pushed into store correctly - var superVillain = env.store.peekRecord('super-villain', "1"); - equal(get(superVillain, "firstName"), "Stanley"); - - // Serializers are singletons, so that"s why we use the store which - // looks at the container to look it up - env.store.serializerFor('home-planet').reopen({ - modelNameFromPayloadKey: function(root) { - // should not warn if a model is found. - return Ember.String.camelize(Ember.String.singularize(root)); - } - }); - - jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], - super_villains: [{ id: "1", firstName: "Stanley" }] - }; - - noWarns(function() { - run(function() { - env.store.pushPayload('home-planet', jsonHash); - homePlanet = env.store.peekRecord('home-planet', "1"); - }); - }); - - equal(get(homePlanet, "name"), "Umber"); - deepEqual(get(homePlanet, "superVillains.firstObject.firstName"), "Stanley"); - }); -} - test("serialize polymorphicType", function() { var tom, ray; run(function() { @@ -339,35 +157,6 @@ test("serialize polymorphic when associated object is null", function() { deepEqual(json["evilMinionType"], null); }); -if (!Ember.FEATURES.isEnabled('ds-new-serializer-api')) { - test("extractArray can load secondary records of the same type without affecting the query count", function() { - var jsonHash = { - comments: [{ id: "1", body: "Parent Comment", root: true, children: [2, 3] }], - _comments: [ - { id: "2", body: "Child Comment 1", root: false }, - { id: "3", body: "Child Comment 2", root: false } - ] - }; - var array; - - run(function() { - array = env.restSerializer.extractArray(env.store, Comment, jsonHash); - }); - - deepEqual(array, [{ - "id": "1", - "body": "Parent Comment", - "root": true, - "children": [2, 3] - }]); - - equal(array.length, 1, "The query count is unaffected"); - - equal(env.store.recordForId('comment', "2").get("body"), "Child Comment 1", "Secondary records are in the store"); - equal(env.store.recordForId('comment', "3").get("body"), "Child Comment 2", "Secondary records are in the store"); - }); -} - test("extractSingle loads secondary records with correct serializer", function() { var superVillainNormalizeCount = 0; From 76cf421556c80cff61462c49cd70cc193bdca9c5 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Wed, 10 Jun 2015 22:45:39 +0200 Subject: [PATCH 0948/2527] Initial JSON-API Adapter/Serializer --- packages/ember-data/lib/adapters.js | 6 +- .../lib/adapters/json-api-adapter.js | 84 ++ packages/ember-data/lib/initializers/store.js | 7 +- packages/ember-data/lib/main.js | 15 +- packages/ember-data/lib/serializers.js | 6 + .../lib/serializers/json-api-serializer.js | 310 +++++++ .../adapter/json-api-adapter-test.js | 800 ++++++++++++++++++ .../serializers/json-api-serializer-test.js | 17 + .../adapters/json-api-adapter/ajax-test.js | 65 ++ tests/ember-configuration.js | 3 + 10 files changed, 1305 insertions(+), 8 deletions(-) create mode 100644 packages/ember-data/lib/adapters/json-api-adapter.js create mode 100644 packages/ember-data/lib/serializers/json-api-serializer.js create mode 100644 packages/ember-data/tests/integration/adapter/json-api-adapter-test.js create mode 100644 packages/ember-data/tests/integration/serializers/json-api-serializer-test.js create mode 100644 packages/ember-data/tests/unit/adapters/json-api-adapter/ajax-test.js diff --git a/packages/ember-data/lib/adapters.js b/packages/ember-data/lib/adapters.js index 3fa577e3e66..4ad9bb43a6a 100644 --- a/packages/ember-data/lib/adapters.js +++ b/packages/ember-data/lib/adapters.js @@ -3,9 +3,11 @@ */ import FixtureAdapter from "ember-data/adapters/fixture-adapter"; +import JSONAPIAdapter from "ember-data/adapters/json-api-adapter"; import RESTAdapter from "ember-data/adapters/rest-adapter"; export { - RESTAdapter, - FixtureAdapter + FixtureAdapter, + JSONAPIAdapter, + RESTAdapter }; diff --git a/packages/ember-data/lib/adapters/json-api-adapter.js b/packages/ember-data/lib/adapters/json-api-adapter.js new file mode 100644 index 00000000000..e23582bbb04 --- /dev/null +++ b/packages/ember-data/lib/adapters/json-api-adapter.js @@ -0,0 +1,84 @@ +/** + @module ember-data +*/ + +import RESTAdapter from "ember-data/adapters/rest-adapter"; + +/** + @class JSONAPIAdapter + @constructor + @namespace DS + @extends DS.RESTAdapter +*/ +export default RESTAdapter.extend({ + defaultSerializer: '-json-api', + + /** + @method ajaxOptions + @private + @param {String} url + @param {String} type The request type GET, POST, PUT, DELETE etc. + @param {Object} options + @return {Object} + */ + ajaxOptions: function(url, type, options) { + let hash = this._super(...arguments); + + if (hash.contentType) { + hash.contentType = 'application/vnd.api+json'; + } + + let beforeSend = hash.beforeSend; + hash.beforeSend = function(xhr) { + xhr.setRequestHeader('Accept', 'application/vnd.api+json'); + if (beforeSend) { + beforeSend(xhr); + } + }; + + return hash; + }, + + /** + @method findMany + @param {DS.Store} store + @param {DS.Model} type + @param {Array} ids + @param {Array} snapshots + @return {Promise} promise + */ + findMany: function(store, type, ids, snapshots) { + var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); + return this.ajax(url, 'GET', { data: { filter: { id: ids.join(',') } } }); + }, + + /** + @method pathForType + @param {String} modelName + @return {String} path + **/ + pathForType: function(modelName) { + var dasherized = Ember.String.dasherize(modelName); + return Ember.String.pluralize(dasherized); + }, + + // TODO: Remove this once we have a better way to override HTTP verbs. + /** + @method updateRecord + @param {DS.Store} store + @param {DS.Model} type + @param {DS.Snapshot} snapshot + @return {Promise} promise + */ + updateRecord: function(store, type, snapshot) { + var data = {}; + var serializer = store.serializerFor(type.modelName); + + serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); + + var id = snapshot.id; + var url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); + + return this.ajax(url, 'PATCH', { data: data }); + } +}); diff --git a/packages/ember-data/lib/initializers/store.js b/packages/ember-data/lib/initializers/store.js index 654af83bb34..cfe36b195dc 100644 --- a/packages/ember-data/lib/initializers/store.js +++ b/packages/ember-data/lib/initializers/store.js @@ -1,5 +1,5 @@ -import {JSONSerializer, RESTSerializer} from "ember-data/serializers"; -import {RESTAdapter} from "ember-data/adapters"; +import { JSONAPISerializer, JSONSerializer, RESTSerializer } from "ember-data/serializers"; +import { JSONAPIAdapter, RESTAdapter } from "ember-data/adapters"; import ContainerProxy from "ember-data/system/container-proxy"; /** @@ -37,4 +37,7 @@ export default function initializeStore(registry, application) { registry.register('serializer:-default', JSONSerializer); registry.register('serializer:-rest', RESTSerializer); registry.register('adapter:-rest', RESTAdapter); + + registry.register('adapter:-json-api', JSONAPIAdapter); + registry.register('serializer:-json-api', JSONAPISerializer); } diff --git a/packages/ember-data/lib/main.js b/packages/ember-data/lib/main.js index d8b90b474ec..72fd8476170 100644 --- a/packages/ember-data/lib/main.js +++ b/packages/ember-data/lib/main.js @@ -51,12 +51,16 @@ import { import ManyArray from "ember-data/system/many-array"; import RecordArrayManager from "ember-data/system/record-array-manager"; import { - RESTAdapter, - FixtureAdapter + FixtureAdapter, + JSONAPIAdapter, + RESTAdapter } from "ember-data/adapters"; import BuildURLMixin from "ember-data/adapters/build-url-mixin"; -import JSONSerializer from "ember-data/serializers/json-serializer"; -import RESTSerializer from "ember-data/serializers/rest-serializer"; +import { + JSONAPISerializer, + JSONSerializer, + RESTSerializer +} from "ember-data/serializers"; import "ember-inflector"; import EmbeddedRecordsMixin from "ember-data/serializers/embedded-records-mixin"; import { @@ -114,6 +118,9 @@ DS.BuildURLMixin = BuildURLMixin; DS.RESTSerializer = RESTSerializer; DS.JSONSerializer = JSONSerializer; +DS.JSONAPIAdapter = JSONAPIAdapter; +DS.JSONAPISerializer = JSONAPISerializer; + DS.Transform = Transform; DS.DateTransform = DateTransform; DS.StringTransform = StringTransform; diff --git a/packages/ember-data/lib/serializers.js b/packages/ember-data/lib/serializers.js index 5d163be2984..f423d5300e8 100644 --- a/packages/ember-data/lib/serializers.js +++ b/packages/ember-data/lib/serializers.js @@ -1,7 +1,13 @@ +/** + @module ember-data +*/ + +import JSONAPISerializer from "ember-data/serializers/json-api-serializer"; import JSONSerializer from "ember-data/serializers/json-serializer"; import RESTSerializer from "ember-data/serializers/rest-serializer"; export { + JSONAPISerializer, JSONSerializer, RESTSerializer }; diff --git a/packages/ember-data/lib/serializers/json-api-serializer.js b/packages/ember-data/lib/serializers/json-api-serializer.js new file mode 100644 index 00000000000..f125816bf39 --- /dev/null +++ b/packages/ember-data/lib/serializers/json-api-serializer.js @@ -0,0 +1,310 @@ +/** + @module ember-data +*/ + +import JSONSerializer from 'ember-data/serializers/json-serializer'; +import normalizeModelName from 'ember-data/system/normalize-model-name'; +import { pluralize, singularize } from 'ember-inflector/lib/system/string'; + +var dasherize = Ember.String.dasherize; +var map = Ember.EnumerableUtils.map; + +/** + @class JSONAPISerializer + @namespace DS + @extends DS.JSONSerializer +*/ +export default JSONSerializer.extend({ + + /* + @method _normalizeRelationshipDataHelper + @param {Object} relationshipDataHash + @return {Object} + @private + */ + _normalizeRelationshipDataHelper: function(relationshipDataHash) { + let type = this.modelNameFromPayloadKey(relationshipDataHash.type); + relationshipDataHash.type = type; + return relationshipDataHash; + }, + + /* + @method _normalizeResourceHelper + @param {Object} resourceHash + @return {Object} + @private + */ + _normalizeResourceHelper: function(resourceHash) { + let modelName = this.modelNameFromPayloadKey(resourceHash.type); + let modelClass = this.store.modelFor(modelName); + let serializer = this.store.serializerFor(modelName); + let { data } = serializer.normalize(modelClass, resourceHash); + return data; + }, + + /** + @method _normalizeResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @param {Boolean} isSingle + @return {Object} JSON-API Document + @private + */ + _normalizeResponse: function(store, primaryModelClass, payload, id, requestType, isSingle) { + + if (Ember.typeOf(payload.data) === 'object') { + payload.data = this._normalizeResourceHelper(payload.data); + } else { + payload.data = map(payload.data, this._normalizeResourceHelper, this); + } + + if (Ember.typeOf(payload.included) === 'array') { + payload.included = map(payload.included, this._normalizeResourceHelper, this); + } + + return payload; + }, + + /* + @method extractAttributes + @param {DS.Model} modelClass + @param {Object} resourceHash + @return {Object} + */ + extractAttributes: function(modelClass, resourceHash) { + var attributes = {}; + + if (resourceHash.attributes) { + modelClass.eachAttribute((key) => { + let attributeKey = this.keyForAttribute(key, 'deserialize'); + if (resourceHash.attributes.hasOwnProperty(attributeKey)) { + attributes[key] = resourceHash.attributes[attributeKey]; + } + }); + } + + return attributes; + }, + + /* + @method extractRelationship + @param {Object} relationshipHash + @return {Object} + */ + extractRelationship: function(relationshipHash) { + + if (Ember.typeOf(relationshipHash.data) === 'object') { + relationshipHash.data = this._normalizeRelationshipDataHelper(relationshipHash.data); + } + + if (Ember.typeOf(relationshipHash.data) === 'array') { + relationshipHash.data = map(relationshipHash.data, this._normalizeRelationshipDataHelper, this); + } + + return relationshipHash; + }, + + /* + @method extractRelationships + @param {Object} modelClass + @param {Object} resourceHash + @return {Object} + */ + extractRelationships: function(modelClass, resourceHash) { + let relationships = {}; + + if (resourceHash.relationships) { + modelClass.eachRelationship((key, relationshipMeta) => { + let relationshipKey = this.keyForRelationship(key, relationshipMeta.kind, 'deserialize'); + if (resourceHash.relationships.hasOwnProperty(relationshipKey)) { + + let relationshipHash = resourceHash.relationships[relationshipKey]; + relationships[key] = this.extractRelationship(relationshipHash); + + } + }); + } + + return relationships; + }, + + /* + @method extractType + @param {DS.Model} modelClass + @param {Object} resourceHash + @return {String} + @private + */ + _extractType: function(modelClass, resourceHash) { + return this.modelNameFromPayloadKey(resourceHash.type); + }, + + /** + @method modelNameFromPayloadKey + @param {String} key + @return {String} the model's modelName + */ + modelNameFromPayloadKey: function(key) { + return singularize(normalizeModelName(key)); + }, + + /** + @method payloadKeyFromModelName + @param {String} modelName + @return {String} + */ + payloadKeyFromModelName: function(modelName) { + return pluralize(modelName); + }, + + /* + @method normalize + @param {DS.Model} modelClass + @param {Object} resourceHash + @return {String} + */ + normalize: function(modelClass, resourceHash) { + this.normalizeUsingDeclaredMapping(modelClass, resourceHash); + + let data = { + id: this.extractId(resourceHash), + type: this._extractType(modelClass, resourceHash), + attributes: this.extractAttributes(modelClass, resourceHash), + relationships: this.extractRelationships(modelClass, resourceHash) + }; + + this.applyTransforms(modelClass, data.attributes); + + return { data }; + }, + + /** + @method keyForAttribute + @param {String} key + @param {String} method + @return {String} normalized key + */ + keyForAttribute: function(key, method) { + return dasherize(key); + }, + + /** + @method keyForRelationship + @param {String} key + @param {String} typeClass + @param {String} method + @return {String} normalized key + */ + keyForRelationship: function(key, typeClass, method) { + return dasherize(key); + }, + + /** + @method serialize + @param {DS.Snapshot} snapshot + @param {Object} options + @return {Object} json + */ + serialize: function(snapshot, options) { + let data = this._super(...arguments); + data.type = this.payloadKeyFromModelName(snapshot.modelName); + return { data }; + }, + + /** + @method serializeAttribute + @param {DS.Snapshot} snapshot + @param {Object} json + @param {String} key + @param {Object} attribute + */ + serializeAttribute: function(snapshot, json, key, attribute) { + var type = attribute.type; + + if (this._canSerialize(key)) { + json.attributes = json.attributes || {}; + + var value = snapshot.attr(key); + if (type) { + var transform = this.transformFor(type); + value = transform.serialize(value); + } + + var payloadKey = this._getMappedKey(key); + if (payloadKey === key) { + payloadKey = this.keyForAttribute(key, 'serialize'); + } + + json.attributes[payloadKey] = value; + } + }, + + /** + @method serializeBelongsTo + @param {DS.Snapshot} snapshot + @param {Object} json + @param {Object} relationship + */ + serializeBelongsTo: function(snapshot, json, relationship) { + var key = relationship.key; + + if (this._canSerialize(key)) { + var belongsTo = snapshot.belongsTo(key); + if (belongsTo !== undefined) { + + json.relationships = json.relationships || {}; + + var payloadKey = this._getMappedKey(key); + if (payloadKey === key) { + payloadKey = this.keyForRelationship(key, 'belongsTo', 'serialize'); + } + + let data = null; + if (belongsTo) { + data = { + type: this.payloadKeyFromModelName(belongsTo.modelName), + id: belongsTo.id + }; + } + + json.relationships[payloadKey] = { data }; + } + } + }, + + /** + @method serializeHasMany + @param {DS.Snapshot} snapshot + @param {Object} json + @param {Object} relationship + */ + serializeHasMany: function(snapshot, json, relationship) { + var key = relationship.key; + + if (this._shouldSerializeHasMany(snapshot, key, relationship)) { + var hasMany = snapshot.hasMany(key); + if (hasMany !== undefined) { + + json.relationships = json.relationships || {}; + + var payloadKey = this._getMappedKey(key); + if (payloadKey === key && this.keyForRelationship) { + payloadKey = this.keyForRelationship(key, 'hasMany', 'serialize'); + } + + let data = map(hasMany, (item) => { + return { + type: item.modelName, + id: item.id + }; + }); + + json.relationships[payloadKey] = { data }; + } + } + } +}); + diff --git a/packages/ember-data/tests/integration/adapter/json-api-adapter-test.js b/packages/ember-data/tests/integration/adapter/json-api-adapter-test.js new file mode 100644 index 00000000000..fe5be31df96 --- /dev/null +++ b/packages/ember-data/tests/integration/adapter/json-api-adapter-test.js @@ -0,0 +1,800 @@ +var env, store, adapter; +var passedUrl, passedVerb, passedHash; + +var run = Ember.run; + +var User, Post, Comment, Handle, GithubHandle, TwitterHandle, Company, DevelopmentShop, DesignStudio; + +module('integration/adapter/json-api-adapter - JSONAPIAdapter', { + setup: function() { + User = DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + posts: DS.hasMany('post', { async: true }), + handles: DS.hasMany('handle', { async: true, polymorphic: true }), + company: DS.belongsTo('company', { async: true, polymorphic: true }) + }); + + Post = DS.Model.extend({ + title: DS.attr('string'), + author: DS.belongsTo('user', { async: true }), + comments: DS.hasMany('comment', { async: true }) + }); + + Comment = DS.Model.extend({ + text: DS.attr('string'), + post: DS.belongsTo('post', { async: true }) + }); + + Handle = DS.Model.extend({ + user: DS.belongsTo('user', { async: true }) + }); + + GithubHandle = Handle.extend({ + username: DS.attr('string') + }); + + TwitterHandle = Handle.extend({ + nickname: DS.attr('string') + }); + + Company = DS.Model.extend({ + name: DS.attr('string'), + employees: DS.hasMany('user', { async: true }) + }); + + DevelopmentShop = Company.extend({ + coffee: DS.attr('boolean') + }); + + DesignStudio = Company.extend({ + hipsters: DS.attr('number') + }); + + env = setupStore({ + adapter: DS.JSONAPIAdapter, + + 'user': User, + 'post': Post, + 'comment': Comment, + 'handle': Handle, + 'github-handle': GithubHandle, + 'twitter-handle': TwitterHandle, + 'company': Company, + 'development-shop': DevelopmentShop, + 'design-studio': DesignStudio + }); + + store = env.store; + adapter = env.adapter; + }, + + teardown: function() { + run(env.store, 'destroy'); + } +}); + +function ajaxResponse(responses) { + var counter = 0; + var index; + + passedUrl = []; + passedVerb = []; + passedHash = []; + + adapter.ajax = function(url, verb, hash) { + index = counter++; + + passedUrl[index] = url; + passedVerb[index] = verb; + passedHash[index] = hash; + + return run(Ember.RSVP, 'resolve', responses[index]); + }; +} + +test('find a single record', function() { + expect(3); + + ajaxResponse([{ + data: { + type: 'post', + id: '1', + attributes: { + title: 'Ember.js rocks' + } + } + }]); + + run(function() { + store.find('post', 1).then(function(post) { + equal(passedUrl[0], '/posts/1'); + + equal(post.get('id'), '1'); + equal(post.get('title'), 'Ember.js rocks'); + }); + }); +}); + +test('find all records with sideloaded relationships', function() { + expect(9); + + ajaxResponse([{ + data: [{ + type: 'posts', + id: '1', + attributes: { + title: 'Ember.js rocks' + }, + relationships: { + author: { + data: { type: 'users', id: '3' } + } + } + }, { + type: 'posts', + id: '2', + attributes: { + title: 'Tomster rules' + }, + relationships: { + author: { + data: { type: 'users', id: '3' } + }, + comments: { + data: [ + { type: 'comments', id: '4' }, + { type: 'comments', id: '5' } + ] + } + } + }], + included: [{ + type: 'users', + id: '3', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz' + } + }, { + type: 'comments', + id: '4', + attributes: { + text: 'This is the first comment' + } + }, { + type: 'comments', + id: '5', + attributes: { + text: 'This is the second comment' + } + }] + }]); + + run(function() { + store.findAll('post').then(function(posts) { + equal(passedUrl[0], '/posts'); + + equal(posts.get('length'), '2'); + equal(posts.get('firstObject.title'), 'Ember.js rocks'); + equal(posts.get('lastObject.title'), 'Tomster rules'); + + equal(posts.get('firstObject.author.firstName'), 'Yehuda'); + equal(posts.get('lastObject.author.lastName'), 'Katz'); + + equal(posts.get('firstObject.comments.length'), 0); + + equal(posts.get('lastObject.comments.firstObject.text'), 'This is the first comment'); + equal(posts.get('lastObject.comments.lastObject.text'), 'This is the second comment'); + }); + }); +}); + +test('find many records', function() { + expect(4); + + ajaxResponse([{ + data: [{ + type: 'posts', + id: '1', + attributes: { + title: 'Ember.js rocks' + } + }] + }]); + + run(function() { + store.find('post', { filter: { id: 1 } }).then(function(posts) { + equal(passedUrl[0], '/posts'); + deepEqual(passedHash[0], { data: { filter: { id: 1 } } }); + + equal(posts.get('length'), '1'); + equal(posts.get('firstObject.title'), 'Ember.js rocks'); + }); + }); +}); + +test('find a single record with belongsTo link as object { related }', function() { + expect(7); + + ajaxResponse([{ + data: { + type: 'posts', + id: '1', + attributes: { + title: 'Ember.js rocks' + }, + relationships: { + author: { + links: { + related: 'http://example.com/user/2' + } + } + } + } + }, { + data: { + type: 'users', + id: '2', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz' + } + } + }]); + + run(function() { + store.find('post', 1).then(function(post) { + equal(passedUrl[0], '/posts/1'); + + equal(post.get('id'), '1'); + equal(post.get('title'), 'Ember.js rocks'); + + post.get('author').then(function(author) { + equal(passedUrl[1], 'http://example.com/user/2'); + + equal(author.get('id'), '2'); + equal(author.get('firstName'), 'Yehuda'); + equal(author.get('lastName'), 'Katz'); + }); + }); + }); +}); + +test('find a single record with belongsTo link as object { data }', function() { + expect(7); + + ajaxResponse([{ + data: { + type: 'posts', + id: '1', + attributes: { + title: 'Ember.js rocks' + }, + relationships: { + author: { + data: { type: 'users', id: '2' } + } + } + } + }, { + data: { + type: 'users', + id: '2', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz' + } + } + }]); + + run(function() { + store.find('post', 1).then(function(post) { + equal(passedUrl[0], '/posts/1'); + + equal(post.get('id'), '1'); + equal(post.get('title'), 'Ember.js rocks'); + + post.get('author').then(function(author) { + equal(passedUrl[1], '/users/2'); + + equal(author.get('id'), '2'); + equal(author.get('firstName'), 'Yehuda'); + equal(author.get('lastName'), 'Katz'); + }); + }); + }); +}); + +test('find a single record with belongsTo link as object { data } (polymorphic)', function() { + expect(8); + + ajaxResponse([{ + data: { + type: 'users', + id: '1', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz' + }, + relationships: { + company: { + data: { type: 'development-shops', id: '2' } + } + } + } + }, { + data: { + type: 'development-shop', + id: '2', + attributes: { + name: 'Tilde', + coffee: true + } + } + }]); + + run(function() { + store.find('user', 1).then(function(user) { + equal(passedUrl[0], '/users/1'); + + equal(user.get('id'), '1'); + equal(user.get('firstName'), 'Yehuda'); + equal(user.get('lastName'), 'Katz'); + + user.get('company').then(function(company) { + equal(passedUrl[1], '/development-shops/2'); + + equal(company.get('id'), '2'); + equal(company.get('name'), 'Tilde'); + equal(company.get('coffee'), true); + }); + }); + }); +}); + +test('find a single record with sideloaded belongsTo link as object { data }', function() { + expect(7); + + ajaxResponse([{ + data: { + type: 'post', + id: '1', + attributes: { + title: 'Ember.js rocks' + }, + relationships: { + author: { + data: { type: 'user', id: '2' } + } + } + }, + included: [{ + type: 'user', + id: '2', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz' + } + }] + }]); + + run(function() { + + store.find('post', 1).then(function(post) { + equal(passedUrl[0], '/posts/1'); + + equal(post.get('id'), '1'); + equal(post.get('title'), 'Ember.js rocks'); + + post.get('author').then(function(author) { + equal(passedUrl.length, 1); + + equal(author.get('id'), '2'); + equal(author.get('firstName'), 'Yehuda'); + equal(author.get('lastName'), 'Katz'); + }); + }); + }); +}); + +test('find a single record with hasMany link as object { related }', function() { + expect(7); + + ajaxResponse([{ + data: { + type: 'post', + id: '1', + attributes: { + title: 'Ember.js rocks' + }, + relationships: { + comments: { + links: { + related: 'http://example.com/post/1/comments' + } + } + } + } + }, { + data: [{ + type: 'comment', + id: '2', + attributes: { + text: 'This is the first comment' + } + }, { + type: 'comment', + id: '3', + attributes: { + text: 'This is the second comment' + } + }] + }]); + + run(function() { + store.find('post', 1).then(function(post) { + equal(passedUrl[0], '/posts/1'); + + equal(post.get('id'), '1'); + equal(post.get('title'), 'Ember.js rocks'); + + post.get('comments').then(function(comments) { + equal(passedUrl[1], 'http://example.com/post/1/comments'); + + equal(comments.get('length'), 2); + equal(comments.get('firstObject.text'), 'This is the first comment'); + equal(comments.get('lastObject.text'), 'This is the second comment'); + }); + }); + }); +}); + +test('find a single record with hasMany link as object { data }', function() { + expect(8); + + ajaxResponse([{ + data: { + type: 'post', + id: '1', + attributes: { + title: 'Ember.js rocks' + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' } + ] + } + } + } + }, { + data: { + type: 'comment', + id: '2', + attributes: { + text: 'This is the first comment' + } + } + }, { + data: { + type: 'comment', + id: '3', + attributes: { + text: 'This is the second comment' + } + } + }]); + + run(function() { + store.find('post', 1).then(function(post) { + equal(passedUrl[0], '/posts/1'); + + equal(post.get('id'), '1'); + equal(post.get('title'), 'Ember.js rocks'); + + post.get('comments').then(function(comments) { + equal(passedUrl[1], '/comments/2'); + equal(passedUrl[2], '/comments/3'); + + equal(comments.get('length'), 2); + equal(comments.get('firstObject.text'), 'This is the first comment'); + equal(comments.get('lastObject.text'), 'This is the second comment'); + }); + }); + }); +}); + +test('find a single record with hasMany link as object { data } (polymorphic)', function() { + expect(9); + + ajaxResponse([{ + data: { + type: 'user', + id: '1', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz' + }, + relationships: { + handles: { + data: [ + { type: 'github-handle', id: '2' }, + { type: 'twitter-handle', id: '3' } + ] + } + } + } + }, { + data: { + type: 'github-handle', + id: '2', + attributes: { + username: 'wycats' + } + } + }, { + data: { + type: 'twitter-handle', + id: '3', + attributes: { + nickname: '@wycats' + } + } + }]); + + run(function() { + store.find('user', 1).then(function(user) { + equal(passedUrl[0], '/users/1'); + + equal(user.get('id'), '1'); + equal(user.get('firstName'), 'Yehuda'); + equal(user.get('lastName'), 'Katz'); + + user.get('handles').then(function(handles) { + equal(passedUrl[1], '/github-handles/2'); + equal(passedUrl[2], '/twitter-handles/3'); + + equal(handles.get('length'), 2); + equal(handles.get('firstObject.username'), 'wycats'); + equal(handles.get('lastObject.nickname'), '@wycats'); + }); + }); + }); +}); + +test('find a single record with sideloaded hasMany link as object { data }', function() { + expect(7); + + ajaxResponse([{ + data: { + type: 'post', + id: '1', + attributes: { + title: 'Ember.js rocks' + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' } + ] + } + } + }, + included: [{ + type: 'comment', + id: '2', + attributes: { + text: 'This is the first comment' + } + }, { + type: 'comment', + id: '3', + attributes: { + text: 'This is the second comment' + } + }] + }]); + + run(function() { + store.find('post', 1).then(function(post) { + equal(passedUrl[0], '/posts/1'); + + equal(post.get('id'), '1'); + equal(post.get('title'), 'Ember.js rocks'); + + post.get('comments').then(function(comments) { + equal(passedUrl.length, 1); + + equal(comments.get('length'), 2); + equal(comments.get('firstObject.text'), 'This is the first comment'); + equal(comments.get('lastObject.text'), 'This is the second comment'); + }); + }); + }); +}); + +test('find a single record with sideloaded hasMany link as object { data } (polymorphic)', function() { + expect(8); + + ajaxResponse([{ + data: { + type: 'user', + id: '1', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz' + }, + relationships: { + handles: { + data: [ + { type: 'github-handle', id: '2' }, + { type: 'twitter-handle', id: '3' } + ] + } + } + }, + included: [{ + type: 'github-handle', + id: '2', + attributes: { + username: 'wycats' + } + }, { + type: 'twitter-handle', + id: '3', + attributes: { + nickname: '@wycats' + } + }] + }]); + + run(function() { + store.find('user', 1).then(function(user) { + equal(passedUrl[0], '/users/1'); + + equal(user.get('id'), '1'); + equal(user.get('firstName'), 'Yehuda'); + equal(user.get('lastName'), 'Katz'); + + user.get('handles').then(function(handles) { + equal(passedUrl.length, 1); + + equal(handles.get('length'), 2); + equal(handles.get('firstObject.username'), 'wycats'); + equal(handles.get('lastObject.nickname'), '@wycats'); + }); + }); + }); +}); + +test('create record', function() { + expect(3); + + ajaxResponse([{ + data: { + type: 'users', + id: '3' + } + }]); + + run(function() { + + var company = store.push({ data: { + type: 'company', + id: '1', + attributes: { + name: 'Tilde Inc.' + } + } }); + + var githubHandle = store.push({ data: { + type: 'github-handle', + id: '2', + attributes: { + username: 'wycats' + } + } }); + + var user = store.createRecord('user', { + firstName: 'Yehuda', + lastName: 'Katz', + company: company + }); + + user.get('handles').then(function(handles) { + handles.addObject(githubHandle); + + user.save().then(function() { + equal(passedUrl[0], '/users'); + equal(passedVerb[0], 'POST'); + deepEqual(passedHash[0], { + data: { + data : { + type: 'users', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz' + }, + relationships: { + company: { + data: { type: 'companies', id: '1' } + } + } + } + } + }); + }); + }); + }); +}); + +test('update record', function() { + expect(3); + + ajaxResponse([{ + data: { + type: 'users', + id: '1' + } + }]); + + run(function() { + var user = store.push({ data: { + type: 'user', + id: '1', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + } + } }); + + var company = store.push({ data: { + type: 'company', + id: '2', + attributes: { + name: 'Tilde Inc.' + } + } }); + + var githubHandle = store.push({ data: { + type: 'github-handle', + id: '3', + attributes: { + username: 'wycats' + } + } }); + + user.set('firstName', 'Yehuda!'); + user.set('company', company); + + user.get('handles').then(function(handles) { + handles.addObject(githubHandle); + + user.save().then(function() { + equal(passedUrl[0], '/users/1'); + equal(passedVerb[0], 'PATCH'); + deepEqual(passedHash[0], { + data: { + data : { + type: 'users', + id: '1', + attributes: { + 'first-name': 'Yehuda!', + 'last-name': 'Katz' + }, + relationships: { + company: { + data: { type: 'companies', id: '2' } + } + } + } + } + }); + }); + + }); + }); +}); diff --git a/packages/ember-data/tests/integration/serializers/json-api-serializer-test.js b/packages/ember-data/tests/integration/serializers/json-api-serializer-test.js new file mode 100644 index 00000000000..d31ce1e8d64 --- /dev/null +++ b/packages/ember-data/tests/integration/serializers/json-api-serializer-test.js @@ -0,0 +1,17 @@ +var env; +var run = Ember.run; + +module('integration/serializers/json-api-serializer - JSONAPISerializer', { + setup: function() { + env = setupStore({ + }); + }, + + teardown: function() { + run(env.store, 'destroy'); + } +}); + +/*test('...', function() { + +});*/ diff --git a/packages/ember-data/tests/unit/adapters/json-api-adapter/ajax-test.js b/packages/ember-data/tests/unit/adapters/json-api-adapter/ajax-test.js new file mode 100644 index 00000000000..c88fb4e08d3 --- /dev/null +++ b/packages/ember-data/tests/unit/adapters/json-api-adapter/ajax-test.js @@ -0,0 +1,65 @@ +var Person, Place, store, adapter, env; +var run = Ember.run; + +module("unit/adapters/json-api-adapter/ajax - building requests", { + setup: function() { + Person = { modelName: 'person' }; + Place = { modelName: 'place' }; + env = setupStore({ adapter: DS.JSONAPIAdapter, person: Person, place: Place }); + store = env.store; + adapter = env.adapter; + }, + + teardown: function() { + run(function() { + store.destroy(); + env.container.destroy(); + }); + } +}); + +test("ajaxOptions() adds Accept when no other headers exist", function() { + var url = 'example.com'; + var type = 'GET'; + var ajaxOptions = adapter.ajaxOptions(url, type, {}); + var receivedHeaders = []; + var fakeXHR = { + setRequestHeader: function(key, value) { + receivedHeaders.push([key, value]); + } + }; + ajaxOptions.beforeSend(fakeXHR); + deepEqual(receivedHeaders, [['Accept', 'application/vnd.api+json']], 'headers assigned'); +}); + +test("ajaxOptions() adds Accept header to existing headers", function() { + adapter.headers = { 'Other-key': 'Other Value' }; + var url = 'example.com'; + var type = 'GET'; + var ajaxOptions = adapter.ajaxOptions(url, type, {}); + var receivedHeaders = []; + var fakeXHR = { + setRequestHeader: function(key, value) { + receivedHeaders.push([key, value]); + } + }; + ajaxOptions.beforeSend(fakeXHR); + deepEqual(receivedHeaders, [['Accept', 'application/vnd.api+json'], ['Other-key', 'Other Value']], 'headers assigned'); +}); + +test("ajaxOptions() adds Accept header to existing computed properties headers", function() { + adapter.headers = Ember.computed(function() { + return { 'Other-key': 'Other Value' }; + }); + var url = 'example.com'; + var type = 'GET'; + var ajaxOptions = adapter.ajaxOptions(url, type, {}); + var receivedHeaders = []; + var fakeXHR = { + setRequestHeader: function(key, value) { + receivedHeaders.push([key, value]); + } + }; + ajaxOptions.beforeSend(fakeXHR); + deepEqual(receivedHeaders, [['Accept', 'application/vnd.api+json'], ['Other-key', 'Other Value']], 'headers assigned'); +}); diff --git a/tests/ember-configuration.js b/tests/ember-configuration.js index 3d0c7a4f754..36d44fe7c7e 100644 --- a/tests/ember-configuration.js +++ b/tests/ember-configuration.js @@ -99,6 +99,9 @@ registry.register('adapter:-rest', DS.RESTAdapter); + registry.register('adapter:-json-api', DS.JSONAPIAdapter); + registry.register('serializer:-json-api', DS.JSONAPISerializer.extend({ isNewSerializerAPI: true })); + registry.injection('serializer', 'store', 'store:main'); env.serializer = container.lookup('serializer:-default'); From c6f990877cf164eab7d611aa7bf421498187e921 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 12 Jun 2015 11:38:58 -0400 Subject: [PATCH 0949/2527] Implement Adapter#shouldReloadRecord and Adapter#shouldBackgroundReloadRecord Implement Adapter#shouldReloadAll and Adapter#shouldBackgroundReloadAll --- packages/ember-data/lib/system/adapter.js | 79 ++++ .../lib/system/record-arrays/record-array.js | 8 + .../lib/system/snapshot-record-array.js | 13 - packages/ember-data/lib/system/store.js | 71 +++- .../ember-data/lib/system/store/finders.js | 6 +- .../tests/unit/store/adapter-interop-test.js | 383 ++++++++++++++++++ 6 files changed, 524 insertions(+), 36 deletions(-) diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 6c9fb5bbf1f..587610b9aca 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -448,6 +448,85 @@ var Adapter = Ember.Object.extend({ */ groupRecordsForFindMany: function(store, snapshots) { return [snapshots]; + }, + + + /** + This method is used by the store to determine if the store should + reload a record from the adapter when a record is requested by + `store.findRecord`. + + If this method returns true the store will re fetch a record form + the adapter. If is method returns false the store will resolve + immediately using the cached record. + + @method shouldReloadRecord + @param {DS.Store} store + @param {DS.Snapshot} snapshot + @return {Boolean} + */ + shouldReloadRecord: function(store, snapshot) { + return false; + }, + + /** + This method is used by the store to determine if the store should + reload all records from the adapter when records are requested by + `store.findAll`. + + If this method returns true the store will re fetch all records form + the adapter. If is method returns false the store will resolve + immediately using the cached record. + + @method shouldReloadRecord + @param {DS.Store} store + @param {DS.SnapshotRecordArray} snapshotRecordArray + @return {Boolean} + */ + shouldReloadAll: function(store, snapshotRecordArray) { + Ember.deprecate('The default behavior of `shouldBackgroundReloadAll` will change in Ember Data 2.0 to always return false. If you would like to preserve the current behavior please override `shouldReloadAll` in you adapter:application and return true.'); + return true; + }, + + /** + This method is used by the store to determine if the store should + reload a record after the `store.findRecord` method resolves a + chached record. + + This method is *only* checked by the store when the store is + returning a cached record. + + If this method returns true the store will re-fetch a record form + the adapter. + + @method shouldBackgroundReloadRecord + @param {DS.Store} store + @param {DS.Snapshot} snapshot + @return {Boolean} + */ + shouldBackgroundReloadRecord: function(store, snapshot) { + Ember.deprecate('The default behavior of `shouldBackgroundReloadRecord` will change in Ember Data 2.0 to always return true. If you would like to preserve the current behavior please override `shouldBackgroundReloadRecord` in you adapter:application and return false.'); + return false; + }, + + /** + This method is used by the store to determine if the store should + reload a record array after the `store.findAll` method resolves + with a chached record array. + + This method is *only* checked by the store when the store is + returning a cached record array. + + If this method returns true the store will re-fetch all records + form the adapter. + + @method shouldBackgroundReloadAll + @param {DS.Store} store + @param {DS.SnapshotRecordArray} snapshotRecordArray + @return {Boolean} + */ + shouldBackgroundReloadAll: function(store, snapshotRecordArray) { + return true; } }); diff --git a/packages/ember-data/lib/system/record-arrays/record-array.js b/packages/ember-data/lib/system/record-arrays/record-array.js index abd8d79b6b5..221a434111a 100644 --- a/packages/ember-data/lib/system/record-arrays/record-array.js +++ b/packages/ember-data/lib/system/record-arrays/record-array.js @@ -3,6 +3,8 @@ */ import { PromiseArray } from "ember-data/system/promise-proxies"; +import SnapshotRecordArray from "ember-data/system/snapshot-record-array"; + var get = Ember.get; var set = Ember.set; @@ -198,5 +200,11 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { this._dissociateFromOwnRecords(); set(this, 'content', undefined); this._super.apply(this, arguments); + }, + + createSnapshot(options) { + var adapterOptions = options && options.adapterOptions; + var meta = this.get('meta'); + return new SnapshotRecordArray(this, meta, adapterOptions); } }); diff --git a/packages/ember-data/lib/system/snapshot-record-array.js b/packages/ember-data/lib/system/snapshot-record-array.js index e84aba68aad..f5ad544f936 100644 --- a/packages/ember-data/lib/system/snapshot-record-array.js +++ b/packages/ember-data/lib/system/snapshot-record-array.js @@ -18,19 +18,6 @@ function SnapshotRecordArray(recordArray, meta, adapterOptions) { this.adapterOptions = adapterOptions; } -/** - @method fromRecordArray - @private - @static - @param {DS.RecordArray} recordArray - @param {Object} adapterOptions - @return SnapshotRecordArray -*/ -SnapshotRecordArray.fromRecordArray = function(recordArray, adapterOptions) { - var meta = recordArray.get('meta'); - return new SnapshotRecordArray(recordArray, meta, adapterOptions); -}; - SnapshotRecordArray.prototype.snapshots = function() { if (this._snapshots) { return this._snapshots; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index f44a8496b8e..dc1330f701f 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -99,13 +99,7 @@ if (!Backburner.prototype.join) { //an internal model and return it in a promiseObject. Useful for returning //from find methods function promiseRecord(internalModel, label) { - //TODO cleanup - var toReturn = internalModel; - if (!internalModel.then) { - toReturn = internalModel.getRecord(); - } else { - toReturn = internalModel.then((model) => model.getRecord()); - } + var toReturn = internalModel.then((model) => model.getRecord()); return promiseObject(toReturn, label); } @@ -612,29 +606,53 @@ Store = Service.extend({ var internalModel = this._internalModelForId(modelName, id); options = options || {}; - if (options.reload && this.hasRecordForId(modelName, id)) { - return this.peekRecord(modelName, id).reload(); - } return this._findByInternalModel(internalModel, options); }, _findByInternalModel: function(internalModel, options) { - var fetchedInternalModel; options = options || {}; - if (options.preload) { internalModel._preloadData(options.preload); } + var fetchedInternalModel = this._fetchOrResolveInternalModel(internalModel, options); + + return promiseRecord(fetchedInternalModel, "DS: Store#findRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id')); + }, + + _fetchOrResolveInternalModel: function(internalModel, options) { + var typeClass = internalModel.type; + var adapter = this.adapterFor(typeClass.modelName); + // Always fetch the model if it is not loaded if (internalModel.isEmpty()) { - fetchedInternalModel = this.scheduleFetch(internalModel, options); - //TODO double check about reloading - } else if (internalModel.isLoading()) { - fetchedInternalModel = internalModel._loadingPromise; + return this.scheduleFetch(internalModel, options); + } + + //TODO double check about reloading + if (internalModel.isLoading()) { + return internalModel._loadingPromise; } - return promiseRecord(fetchedInternalModel || internalModel, "DS: Store#findRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id')); + // Refetch if the reload option is passed + if (options.reload) { + return this.scheduleFetch(internalModel, options); + } + + // Refetch the record if the adapter thinks the record is stale + var snapshot = internalModel.createSnapshot(); + snapshot.adapterOptions = options && options.adapterOptions; + if (adapter.shouldReloadRecord(this, snapshot)) { + return this.scheduleFetch(internalModel, options); + } + + // Trigger the background refetch if all the previous checks fail + if (adapter.shouldBackgroundReloadRecord(this, snapshot)) { + this.scheduleFetch(internalModel, options); + } + + // Return the cached record + return Promise.resolve(internalModel); }, /** This method makes a series of requests to the adapter's `find` method @@ -1128,6 +1146,7 @@ Store = Service.extend({ @return {Promise} promise */ _fetchAll: function(typeClass, array, options) { + options = options || {}; var adapter = this.adapterFor(typeClass.modelName); var sinceToken = this.typeMapFor(typeClass).metadata.since; @@ -1135,8 +1154,22 @@ Store = Service.extend({ Ember.assert("You tried to load all records but you have no adapter (for " + typeClass + ")", adapter); Ember.assert("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function'); - - return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); + if (!get(array, '__isLoaded')) { + var arrayPromise = promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); + arrayPromise.then(() => set(array, '__isLoaded', true)); + return arrayPromise; + } + if (options.reload) { + return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); + } + var snapshotArray = array.createSnapshot(options); + if (adapter.shouldReloadAll(this, snapshotArray)) { + return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); + } + if (adapter.shouldBackgroundReloadAll(this, snapshotArray)) { + promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); + } + return promiseArray(Promise.resolve(array)); }, /** diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index ad4c0779728..6505c3c3140 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -13,8 +13,6 @@ import { serializerForAdapter } from "ember-data/system/store/serializers"; -import SnapshotRecordArray from "ember-data/system/snapshot-record-array"; - var Promise = Ember.RSVP.Promise; var map = Ember.EnumerableUtils.map; @@ -121,9 +119,9 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship } export function _findAll(adapter, store, typeClass, sinceToken, options) { - var adapterOptions = options && options.adapterOptions; var modelName = typeClass.modelName; - var snapshotArray = SnapshotRecordArray.fromRecordArray(store.peekAll(modelName), adapterOptions); + var recordArray = store.peekAll(modelName); + var snapshotArray = recordArray.createSnapshot(options); var promise = adapter.findAll(store, typeClass, sinceToken, snapshotArray); var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Handle Adapter#findAll of " + typeClass; diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index 244befa8091..dee040455cd 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -815,6 +815,389 @@ test("store.fetchRecord reject records that were not found, even when those requ }, /expected to find records with the following ids in the adapter response but they were missing/); }); +test("store should not call shouldReloadRecord when the record is not in the store", function() { + expect(1); + + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var TestAdapter = DS.Adapter.extend({ + shouldReloadRecord: function(store, type, id, snapshot) { + ok(false, 'shouldReloadRecord should not be called when the record is not loaded'); + return false; + }, + find: function() { + ok(true, 'find is always called when the record is not in the store'); + return { id: 1 }; + } + }); + + store = createStore({ + adapter: TestAdapter, + person: Person + }); + + run(function() { + store.findRecord('person', 1); + }); +}); + +test("store should not reload record when shouldReloadRecord returns false", function() { + expect(1); + + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var TestAdapter = DS.Adapter.extend({ + shouldReloadRecord: function(store, type, id, snapshot) { + ok(true, 'shouldReloadRecord should be called when the record is in the store'); + return false; + }, + find: function() { + ok(false, 'find should not be called when shouldReloadRecord returns false'); + } + }); + + store = createStore({ + adapter: TestAdapter, + person: Person + }); + + run(function() { + store.push('person', { id: 1 }); + store.findRecord('person', 1); + }); +}); + +test("store should reload record when shouldReloadRecord returns true", function() { + expect(3); + + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var TestAdapter = DS.Adapter.extend({ + shouldReloadRecord: function(store, type, id, snapshot) { + ok(true, 'shouldReloadRecord should be called when the record is in the store'); + return true; + }, + find: function() { + ok(true, 'find should not be called when shouldReloadRecord returns false'); + return { id: 1, name: 'Tom' }; + } + }); + + store = createStore({ + adapter: TestAdapter, + person: Person + }); + + run(function() { + store.push('person', { id: 1 }); + store.findRecord('person', 1).then(function(record) { + equal(record.get('name'), 'Tom'); + }); + }); +}); + +test("store should not call shouldBackgroundReloadRecord when the store is already loading the record", function() { + expect(2); + + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var TestAdapter = DS.Adapter.extend({ + shouldReloadRecord: function(store, type, id, snapshot) { + return true; + }, + shouldBackgroundReloadRecord: function(store, type, id, snapshot) { + ok(false, 'shouldBackgroundReloadRecord is not called when shouldReloadRecord returns true'); + }, + find: function() { + ok(true, 'find should be called'); + return { id: 1, name: 'Tom' }; + } + }); + + store = createStore({ + adapter: TestAdapter, + person: Person + }); + + run(function() { + store.push('person', { id: 1 }); + store.findRecord('person', 1).then(function(record) { + equal(record.get('name'), 'Tom'); + }); + }); +}); + +test("store should not reload a record when `shouldBackgroundReloadRecord` is false", function() { + expect(2); + + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var TestAdapter = DS.Adapter.extend({ + shouldBackgroundReloadRecord: function(store, type, id, snapshot) { + ok(true, 'shouldBackgroundReloadRecord is called when record is loaded form the cache'); + return false; + }, + find: function() { + ok(false, 'find should not be called'); + return { id: 1, name: 'Tom' }; + } + }); + + store = createStore({ + adapter: TestAdapter, + person: Person + }); + + run(function() { + store.push('person', { id: 1 }); + store.findRecord('person', 1).then(function(record) { + equal(record.get('name'), undefined); + }); + }); +}); + + +test("store should reload the record in the background when `shouldBackgroundReloadRecord` is true", function() { + expect(4); + + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var TestAdapter = DS.Adapter.extend({ + shouldBackgroundReloadRecord: function(store, type, id, snapshot) { + ok(true, 'shouldBackgroundReloadRecord is called when record is loaded form the cache'); + return true; + }, + find: function() { + ok(true, 'find should not be called'); + return { id: 1, name: 'Tom' }; + } + }); + + store = createStore({ + adapter: TestAdapter, + person: Person + }); + + run(function() { + store.push('person', { id: 1 }); + store.findRecord('person', 1).then(function(record) { + equal(record.get('name'), undefined); + }); + }); + + equal(store.peekRecord('person', 1).get('name'), 'Tom'); +}); + + +test("store should not call shouldReloadAll when the recordArary is not loaded", function() { + expect(1); + + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var TestAdapter = DS.Adapter.extend({ + shouldReloadAll: function(store, type, id, snapshot) { + ok(false, 'shouldReloadRecord should not be called when the record is not loaded'); + return false; + }, + findAll: function() { + ok(true, 'find is always called when the record is not in the store'); + return [{ id: 1 }]; + } + }); + + store = createStore({ + adapter: TestAdapter, + person: Person + }); + + run(function() { + store.findAll('person'); + }); +}); + +test("store should not reload record array when shouldReloadAll returns false", function() { + expect(1); + + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var TestAdapter = DS.Adapter.extend({ + shouldReloadAll: function(store, snapshot) { + ok(true, 'shouldReloadAll should be called when the record is in the store'); + return false; + }, + shouldBackgroundReloadAll: function(store, snapshot) { + return false; + }, + findAll: function() { + ok(false, 'findAll should not be called when shouldReloadAll returns false'); + } + }); + + store = createStore({ + adapter: TestAdapter, + person: Person + }); + + run(function() { + store.peekAll('person').set('__isLoaded', true); + store.find('person'); + }); +}); + +test("store should reload all records when shouldReloadAll returns true", function() { + expect(3); + + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var TestAdapter = DS.Adapter.extend({ + shouldReloadAll: function(store, type, id, snapshot) { + ok(true, 'shouldReloadAll should be called when the record is in the store'); + return true; + }, + findAll: function() { + ok(true, 'findAll should be called when shouldReloadAll returns true'); + return [{ id: 1, name: 'Tom' }]; + } + }); + + store = createStore({ + adapter: TestAdapter, + person: Person + }); + + run(function() { + store.peekAll('person').set('__isLoaded', true); + store.findAll('person').then(function(records) { + equal(records.get('firstObject.name'), 'Tom'); + }); + }); +}); + +test("store should not call shouldBackgroundReloadAll when the store is already loading all records", function() { + expect(2); + + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var TestAdapter = DS.Adapter.extend({ + shouldReloadAll: function(store, type, id, snapshot) { + return true; + }, + shouldBackgroundReloadAll: function(store, type, id, snapshot) { + ok(false, 'shouldBackgroundReloadRecord is not called when shouldReloadRecord returns true'); + }, + findAll: function() { + ok(true, 'find should be called'); + return [{ id: 1, name: 'Tom' }]; + } + }); + + store = createStore({ + adapter: TestAdapter, + person: Person + }); + + run(function() { + store.peekAll('person').set('__isLoaded', true); + store.findAll('person').then(function(records) { + equal(records.get('firstObject.name'), 'Tom'); + }); + }); +}); + +test("store should not reload all records when `shouldBackgroundReloadAll` is false", function() { + expect(3); + + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var TestAdapter = DS.Adapter.extend({ + shouldReloadAll: function(store, type, id, snapshot) { + ok(true, 'shouldReloadAll is called when record is loaded form the cache'); + return false; + }, + shouldBackgroundReloadAll: function(store, type, id, snapshot) { + ok(true, 'shouldBackgroundReloadAll is called when record is loaded form the cache'); + return false; + }, + findAll: function() { + ok(false, 'findAll should not be called'); + return [{ id: 1, name: 'Tom' }]; + } + }); + + store = createStore({ + adapter: TestAdapter, + person: Person + }); + + run(function() { + store.peekAll('person').set('__isLoaded', true); + store.findAll('person').then(function(records) { + equal(records.get('firstObject'), undefined); + }); + }); +}); + + +test("store should reload all records in the background when `shouldBackgroundReloadAll` is true", function() { + expect(5); + + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var TestAdapter = DS.Adapter.extend({ + shouldReloadAll: function() { + ok(true, 'shouldReloadAll is called'); + return false; + }, + shouldBackgroundReloadAll: function(store, snapshot) { + ok(true, 'shouldBackgroundReloadAll is called when record is loaded form the cache'); + return true; + }, + findAll: function() { + ok(true, 'find should not be called'); + return [{ id: 1, name: 'Tom' }]; + } + }); + + store = createStore({ + adapter: TestAdapter, + person: Person + }); + + run(function() { + store.peekAll('person').set('__isLoaded', true); + store.findAll('person').then(function(records) { + equal(records.get('firstObject.name'), undefined); + }); + }); + + equal(store.peekRecord('person', 1).get('name'), 'Tom'); +}); + + module("unit/store/adapter_interop - find preload deprecations", { setup: function() { var Person = DS.Model.extend({ From 83994f8308e5f6bda9baa76a3f186b1cad19afb2 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Mon, 15 Jun 2015 22:33:14 +0200 Subject: [PATCH 0950/2527] Implement modelNameFromPayloadKey in JSONSerializer --- .../ember-data/lib/serializers/json-serializer.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index 1d3dd6a49fb..8277fa3e444 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -1,5 +1,6 @@ import Serializer from "ember-data/system/serializer"; import coerceId from "ember-data/system/coerce-id"; +import normalizeModelName from "ember-data/system/normalize-model-name"; var get = Ember.get; var isNone = Ember.isNone; @@ -607,6 +608,16 @@ export default Serializer.extend({ return relationships; }, + /** + @method modelNameFromPayloadKey + @param {String} key + @return {String} the model's modelName + */ + modelNameFromPayloadKey: function(key) { + return normalizeModelName(key); + }, + + /** You can use this method to normalize all payloads, regardless of whether they represent single records or an array. From daf892fdbae331bcd08d6d490fa23ece3e48f3d9 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Mon, 15 Jun 2015 22:36:22 +0200 Subject: [PATCH 0951/2527] Remove ds-new-serializer-api from ActiveModel tests --- ...rializer-namespaced-model-name-new-test.js | 124 +++-- .../active-model-serializer-new-test.js | 504 +++++++++--------- 2 files changed, 310 insertions(+), 318 deletions(-) diff --git a/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-model-name-new-test.js b/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-model-name-new-test.js index f4464c1162c..7e7fbd1e89b 100644 --- a/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-model-name-new-test.js +++ b/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-model-name-new-test.js @@ -49,78 +49,74 @@ module("integration/active_model - AMS-namespaced-model-names (new API)", { } }); -if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { +test("extractPolymorphic hasMany", function() { + var json_hash = { + mediocre_villain: { id: 1, name: "Dr Horrible", evil_minion_ids: [{ type: "EvilMinions::YellowMinion", id: 12 }] }, + "evil-minions/yellow-minion": [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] + }; + var json; - test("extractPolymorphic hasMany", function() { - var json_hash = { - mediocre_villain: { id: 1, name: "Dr Horrible", evil_minion_ids: [{ type: "EvilMinions::YellowMinion", id: 12 }] }, - "evil-minions/yellow-minion": [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] - }; - var json; - - run(function() { - json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json_hash, '1', 'find'); - }); + run(function() { + json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json_hash, '1', 'find'); + }); - deepEqual(json, { - "data": { - "id": "1", - "type": "mediocre-villain", - "attributes": { - "name": "Dr Horrible" - }, - "relationships": { - "evilMinions": { - "data": [ - { "id": "12", "type": "evil-minions/yellow-minion" } - ] - } + deepEqual(json, { + "data": { + "id": "1", + "type": "mediocre-villain", + "attributes": { + "name": "Dr Horrible" + }, + "relationships": { + "evilMinions": { + "data": [ + { "id": "12", "type": "evil-minions/yellow-minion" } + ] } + } + }, + "included": [{ + "id": "12", + "type": "evil-minions/yellow-minion", + "attributes": { + "name": "Alex" }, - "included": [{ - "id": "12", - "type": "evil-minions/yellow-minion", - "attributes": { - "name": "Alex" - }, - "relationships": {} - }] - }); + "relationships": {} + }] }); +}); - test("extractPolymorphic belongsTo", function() { - var json_hash = { - doomsday_device: { id: 1, name: "DeathRay", evil_minion_id: { type: "EvilMinions::YellowMinion", id: 12 } }, - "evil-minions/yellow-minion": [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] - }; - var json; +test("extractPolymorphic belongsTo", function() { + var json_hash = { + doomsday_device: { id: 1, name: "DeathRay", evil_minion_id: { type: "EvilMinions::YellowMinion", id: 12 } }, + "evil-minions/yellow-minion": [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] + }; + var json; - run(function() { - json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json_hash, '1', 'find'); - }); + run(function() { + json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json_hash, '1', 'find'); + }); - deepEqual(json, { - "data": { - "id": "1", - "type": "doomsday-device", - "attributes": { - "name": "DeathRay" - }, - "relationships": { - "evilMinion": { - "data": { "id": "12", "type": "evil-minions/yellow-minion" } - } + deepEqual(json, { + "data": { + "id": "1", + "type": "doomsday-device", + "attributes": { + "name": "DeathRay" + }, + "relationships": { + "evilMinion": { + "data": { "id": "12", "type": "evil-minions/yellow-minion" } } + } + }, + "included": [{ + "id": "12", + "type": "evil-minions/yellow-minion", + "attributes": { + "name": "Alex" }, - "included": [{ - "id": "12", - "type": "evil-minions/yellow-minion", - "attributes": { - "name": "Alex" - }, - "relationships": {} - }] - }); + "relationships": {} + }] }); - -} +}); diff --git a/packages/activemodel-adapter/tests/integration/active-model-serializer-new-test.js b/packages/activemodel-adapter/tests/integration/active-model-serializer-new-test.js index fcfba817517..31382e60bd3 100644 --- a/packages/activemodel-adapter/tests/integration/active-model-serializer-new-test.js +++ b/packages/activemodel-adapter/tests/integration/active-model-serializer-new-test.js @@ -55,307 +55,303 @@ module("integration/active_model - ActiveModelSerializer (new API)", { } }); -if (Ember.FEATURES.isEnabled('ds-new-serializer-api')) { - - test("normalize", function() { - SuperVillain.reopen({ - yellowMinion: DS.belongsTo('yellowMinion') - }); +test("normalize", function() { + SuperVillain.reopen({ + yellowMinion: DS.belongsTo('yellowMinion') + }); - var superVillain_hash = { - id: "1", - first_name: "Tom", - last_name: "Dale", - home_planet_id: "123", - evil_minion_ids: [1, 2] - }; - - var json = env.amsSerializer.normalize(SuperVillain, superVillain_hash, "superVillain"); - - deepEqual(json, { - "data": { - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" + var superVillain_hash = { + id: "1", + first_name: "Tom", + last_name: "Dale", + home_planet_id: "123", + evil_minion_ids: [1, 2] + }; + + var json = env.amsSerializer.normalize(SuperVillain, superVillain_hash, "superVillain"); + + deepEqual(json, { + "data": { + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": { + "evilMinions": { + "data": [ + { "id": "1", "type": "evil-minion" }, + { "id": "2", "type": "evil-minion" } + ] }, - "relationships": { - "evilMinions": { - "data": [ - { "id": "1", "type": "evil-minion" }, - { "id": "2", "type": "evil-minion" } - ] - }, - "homePlanet": { - "data": { "id": "123", "type": "home-planet" } - } + "homePlanet": { + "data": { "id": "123", "type": "home-planet" } } } - }); + } }); +}); - test("normalize links", function() { - var home_planet = { - id: "1", - name: "Umber", - links: { super_villains: "/api/super_villians/1" } - }; +test("normalize links", function() { + var home_planet = { + id: "1", + name: "Umber", + links: { super_villains: "/api/super_villians/1" } + }; - var json = env.amsSerializer.normalize(HomePlanet, home_planet, "homePlanet"); + var json = env.amsSerializer.normalize(HomePlanet, home_planet, "homePlanet"); - equal(json.data.relationships.superVillains.links.related, "/api/super_villians/1", "normalize links"); - }); + equal(json.data.relationships.superVillains.links.related, "/api/super_villians/1", "normalize links"); +}); - test("normalizeSingleResponse", function() { - env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); - - var json_hash = { - home_planet: { id: "1", name: "Umber", super_villain_ids: [1] }, - super_villains: [{ - id: "1", - first_name: "Tom", - last_name: "Dale", - home_planet_id: "1" - }] - }; - - var json; - run(function() { - json = env.amsSerializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); - }); +test("normalizeSingleResponse", function() { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); - deepEqual(json, { - "data": { - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "superVillains": { - "data": [ - { "id": "1", "type": "super-villain" } - ] - } + var json_hash = { + home_planet: { id: "1", name: "Umber", super_villain_ids: [1] }, + super_villains: [{ + id: "1", + first_name: "Tom", + last_name: "Dale", + home_planet_id: "1" + }] + }; + + var json; + run(function() { + json = env.amsSerializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); + }); + + deepEqual(json, { + "data": { + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "superVillains": { + "data": [ + { "id": "1", "type": "super-villain" } + ] } + } + }, + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" }, - "included": [{ - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": { - "homePlanet": { - "data": { "id": "1", "type": "home-planet" } - } + "relationships": { + "homePlanet": { + "data": { "id": "1", "type": "home-planet" } } - }] - }); + } + }] }); +}); - test("normalizeArrayResponse", function() { - env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); - var array; +test("normalizeArrayResponse", function() { + env.registry.register('adapter:superVillain', DS.ActiveModelAdapter); + var array; - var json_hash = { - home_planets: [{ id: "1", name: "Umber", super_villain_ids: [1] }], - super_villains: [{ id: "1", first_name: "Tom", last_name: "Dale", home_planet_id: "1" }] - }; + var json_hash = { + home_planets: [{ id: "1", name: "Umber", super_villain_ids: [1] }], + super_villains: [{ id: "1", first_name: "Tom", last_name: "Dale", home_planet_id: "1" }] + }; - run(function() { - array = env.amsSerializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); - }); + run(function() { + array = env.amsSerializer.normalizeArrayResponse(env.store, HomePlanet, json_hash, null, 'findAll'); + }); - deepEqual(array, { - "data": [{ - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "superVillains": { - "data": [ - { "id": "1", "type": "super-villain" } - ] - } + deepEqual(array, { + "data": [{ + "id": "1", + "type": "home-planet", + "attributes": { + "name": "Umber" + }, + "relationships": { + "superVillains": { + "data": [ + { "id": "1", "type": "super-villain" } + ] } - }], - "included": [{ - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": { - "homePlanet": { - "data": { "id": "1", "type": "home-planet" } - } + } + }], + "included": [{ + "id": "1", + "type": "super-villain", + "attributes": { + "firstName": "Tom", + "lastName": "Dale" + }, + "relationships": { + "homePlanet": { + "data": { "id": "1", "type": "home-planet" } } - }] - }); + } + }] }); +}); - test("extractPolymorphic hasMany", function() { - env.registry.register('adapter:yellowMinion', DS.ActiveModelAdapter); - MediocreVillain.toString = function() { return "MediocreVillain"; }; - YellowMinion.toString = function() { return "YellowMinion"; }; +test("extractPolymorphic hasMany", function() { + env.registry.register('adapter:yellowMinion', DS.ActiveModelAdapter); + MediocreVillain.toString = function() { return "MediocreVillain"; }; + YellowMinion.toString = function() { return "YellowMinion"; }; - var json_hash = { - mediocre_villain: { id: 1, name: "Dr Horrible", evil_minion_ids: [{ type: "yellow_minion", id: 12 }] }, - yellow_minions: [{ id: 12, name: "Alex" }] - }; - var json; + var json_hash = { + mediocre_villain: { id: 1, name: "Dr Horrible", evil_minion_ids: [{ type: "yellow_minion", id: 12 }] }, + yellow_minions: [{ id: 12, name: "Alex" }] + }; + var json; - run(function() { - json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json_hash, '1', 'find'); - }); + run(function() { + json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json_hash, '1', 'find'); + }); - deepEqual(json, { - "data": { - "id": "1", - "type": "mediocre-villain", - "attributes": { - "name": "Dr Horrible" - }, - "relationships": { - "evilMinions": { - "data": [ - { "id": "12", "type": "yellow-minion" } - ] - } + deepEqual(json, { + "data": { + "id": "1", + "type": "mediocre-villain", + "attributes": { + "name": "Dr Horrible" + }, + "relationships": { + "evilMinions": { + "data": [ + { "id": "12", "type": "yellow-minion" } + ] } + } + }, + "included": [{ + "id": "12", + "type": "yellow-minion", + "attributes": { + "name": "Alex" }, - "included": [{ - "id": "12", - "type": "yellow-minion", - "attributes": { - "name": "Alex" - }, - "relationships": {} - }] - }); + "relationships": {} + }] }); +}); - test("extractPolymorphic belongsTo", function() { - env.registry.register('adapter:yellowMinion', DS.ActiveModelAdapter); - EvilMinion.toString = function() { return "EvilMinion"; }; - YellowMinion.toString = function() { return "YellowMinion"; }; +test("extractPolymorphic belongsTo", function() { + env.registry.register('adapter:yellowMinion', DS.ActiveModelAdapter); + EvilMinion.toString = function() { return "EvilMinion"; }; + YellowMinion.toString = function() { return "YellowMinion"; }; - var json_hash = { - doomsday_device: { id: 1, name: "DeathRay", evil_minion_id: { type: "yellow_minion", id: 12 } }, - yellow_minions: [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] - }; - var json; + var json_hash = { + doomsday_device: { id: 1, name: "DeathRay", evil_minion_id: { type: "yellow_minion", id: 12 } }, + yellow_minions: [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] + }; + var json; - run(function() { - json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json_hash, '1', 'find'); - }); + run(function() { + json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json_hash, '1', 'find'); + }); - deepEqual(json, { - "data": { - "id": "1", - "type": "doomsday-device", - "attributes": { - "name": "DeathRay" - }, - "relationships": { - "evilMinion": { - "data": { "id": "12", "type": "yellow-minion" } - } + deepEqual(json, { + "data": { + "id": "1", + "type": "doomsday-device", + "attributes": { + "name": "DeathRay" + }, + "relationships": { + "evilMinion": { + "data": { "id": "12", "type": "yellow-minion" } } + } + }, + "included": [{ + "id": "12", + "type": "yellow-minion", + "attributes": { + "name": "Alex" }, - "included": [{ - "id": "12", - "type": "yellow-minion", - "attributes": { - "name": "Alex" - }, - "relationships": {} - }] - }); + "relationships": {} + }] }); +}); - test("extractPolymorphic when the related data is not specified", function() { - var json = { - doomsday_device: { id: 1, name: "DeathRay" }, - evil_minions: [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] - }; +test("extractPolymorphic when the related data is not specified", function() { + var json = { + doomsday_device: { id: 1, name: "DeathRay" }, + evil_minions: [{ id: 12, name: "Alex", doomsday_device_ids: [1] }] + }; - run(function() { - json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json, '1', 'find'); - }); + run(function() { + json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json, '1', 'find'); + }); - deepEqual(json, { - "data": { - "id": "1", - "type": "doomsday-device", - "attributes": { - "name": "DeathRay" - }, - "relationships": {} + deepEqual(json, { + "data": { + "id": "1", + "type": "doomsday-device", + "attributes": { + "name": "DeathRay" }, - "included": [{ - "id": "12", - "type": "evil-minion", - "attributes": { - "name": "Alex" - }, - "relationships": {} - }] - }); + "relationships": {} + }, + "included": [{ + "id": "12", + "type": "evil-minion", + "attributes": { + "name": "Alex" + }, + "relationships": {} + }] }); +}); - test("extractPolymorphic hasMany when the related data is not specified", function() { - var json = { - mediocre_villain: { id: 1, name: "Dr Horrible" } - }; +test("extractPolymorphic hasMany when the related data is not specified", function() { + var json = { + mediocre_villain: { id: 1, name: "Dr Horrible" } + }; - run(function() { - json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json, '1', 'find'); - }); + run(function() { + json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json, '1', 'find'); + }); - deepEqual(json, { - "data": { - "id": "1", - "type": "mediocre-villain", - "attributes": { - "name": "Dr Horrible" - }, - "relationships": {} + deepEqual(json, { + "data": { + "id": "1", + "type": "mediocre-villain", + "attributes": { + "name": "Dr Horrible" }, - "included": [] - }); + "relationships": {} + }, + "included": [] }); +}); - test("extractPolymorphic does not break hasMany relationships", function() { - var json = { - mediocre_villain: { id: 1, name: "Dr. Evil", evil_minion_ids: [] } - }; +test("extractPolymorphic does not break hasMany relationships", function() { + var json = { + mediocre_villain: { id: 1, name: "Dr. Evil", evil_minion_ids: [] } + }; - run(function () { - json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json, '1', 'find'); - }); + run(function () { + json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json, '1', 'find'); + }); - deepEqual(json, { - "data": { - "id": "1", - "type": "mediocre-villain", - "attributes": { - "name": "Dr. Evil" - }, - "relationships": { - "evilMinions": { - "data": [] - } - } + deepEqual(json, { + "data": { + "id": "1", + "type": "mediocre-villain", + "attributes": { + "name": "Dr. Evil" }, - "included": [] - }); + "relationships": { + "evilMinions": { + "data": [] + } + } + }, + "included": [] }); - -} +}); From 1a4cac06f751c358dc745a3ab49b3f856ecda75c Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 15 Jun 2015 16:54:35 -0400 Subject: [PATCH 0952/2527] Register service:store in an initializer instead of an instanceInitializer --- packages/ember-data/lib/initializers/store.js | 37 +++++++++++++++---- .../initialize-store-service.js | 30 +-------------- 2 files changed, 30 insertions(+), 37 deletions(-) diff --git a/packages/ember-data/lib/initializers/store.js b/packages/ember-data/lib/initializers/store.js index cfe36b195dc..e18b523e40e 100644 --- a/packages/ember-data/lib/initializers/store.js +++ b/packages/ember-data/lib/initializers/store.js @@ -1,3 +1,4 @@ +import Store from "ember-data/system/store"; import { JSONAPISerializer, JSONSerializer, RESTSerializer } from "ember-data/serializers"; import { JSONAPIAdapter, RESTAdapter } from "ember-data/adapters"; import ContainerProxy from "ember-data/system/container-proxy"; @@ -17,15 +18,7 @@ export default function initializeStore(registry, application) { registry.optionsForType('serializer', { singleton: false }); registry.optionsForType('adapter', { singleton: false }); - // This will get deprecated later in the instace - // initializer. However we register it here so we have access to - // application.Store in the instance initializer. - if (application && application.Store) { - registry.register('store:application', application.Store); - } - // allow older names to be looked up - var proxy = new ContainerProxy(registry); proxy.registerDeprecations([ { deprecated: 'serializer:_default', valid: 'serializer:-default' }, @@ -40,4 +33,32 @@ export default function initializeStore(registry, application) { registry.register('adapter:-json-api', JSONAPIAdapter); registry.register('serializer:-json-api', JSONAPISerializer); + + + var store; + if (registry.has('store:main')) { + Ember.deprecate('Registering a custom store as `store:main` or defining a store in app/store.js has been deprecated. Please move you store to `service:store` or define your custom store in `app/services/store.js`'); + store = registry.lookup('store:main'); + } else { + var storeMainProxy = new ContainerProxy(registry); + storeMainProxy.registerDeprecations([ + { deprecated: 'store:main', valid: 'service:store' } + ]); + } + + if (registry.has('store:application')) { + Ember.deprecate('Registering a custom store as `store:application` or defining a store in app/stores/application.js has been deprecated. Please move you store to `service:store` or define your custom store in `app/services/store.js`'); + store = registry.lookup('store:application'); + } else { + var storeApplicationProxy = new ContainerProxy(registry); + storeApplicationProxy.registerDeprecations([ + { deprecated: 'store:application', valid: 'service:store' } + ]); + } + + if (store) { + registry.register('service:store', store, { instantiate: false }); + } else { + registry.register('service:store', application && application.Store || Store); + } } diff --git a/packages/ember-data/lib/instance-initializers/initialize-store-service.js b/packages/ember-data/lib/instance-initializers/initialize-store-service.js index a74bf77cb1a..2d6488f611d 100644 --- a/packages/ember-data/lib/instance-initializers/initialize-store-service.js +++ b/packages/ember-data/lib/instance-initializers/initialize-store-service.js @@ -1,6 +1,3 @@ -import Store from "ember-data/system/store"; -import ContainerProxy from "ember-data/system/container-proxy"; - /** Configures a registry for use with an Ember-Data store. @@ -29,30 +26,5 @@ export default function initializeStoreService(applicationOrRegistry) { } // Eagerly generate the store so defaultStore is populated. - var store; - if (registry.has('store:main')) { - Ember.deprecate('Registering a custom store as `store:main` or defining a store in app/store.js has been deprecated. Please move you store to `service:store` or define your custom store in `app/services/store.js`'); - store = container.lookup('store:main'); - } else { - var storeMainProxy = new ContainerProxy(registry); - storeMainProxy.registerDeprecations([ - { deprecated: 'store:main', valid: 'service:store' } - ]); - } - - if (registry.has('store:application')) { - Ember.deprecate('Registering a custom store as `store:application` or defining a store in app/stores/application.js has been deprecated. Please move you store to `service:store` or define your custom store in `app/services/store.js`'); - store = container.lookup('store:application'); - } else { - var storeApplicationProxy = new ContainerProxy(registry); - storeApplicationProxy.registerDeprecations([ - { deprecated: 'store:application', valid: 'service:store' } - ]); - } - - if (store) { - registry.register('service:store', store, { instantiate: false }); - } else { - registry.register('service:store', Store); - } + container.lookup('service:store'); } From fd3d5dd1a3de415e36051c44ed389339a62c46a7 Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 11 Jun 2015 10:14:55 -0400 Subject: [PATCH 0953/2527] Rename adapter and serializer methods to match the new store methods Adapter#find -> Adapter#findRecord and Adapter#findQuery -> Adapter#query BuildURLMixin#urlForFind -> BuildURLMixin#urlForFindRecord and BuildURLMixin#urlForFindQuery -> BuildURLMixin#urlForQuery Serializer#extractFind -> Serializer#extractFindRecord and Serializer#findQuery -> Serializer#extractQuery --- ...rializer-namespaced-model-name-new-test.js | 4 +- .../active-model-serializer-new-test.js | 12 +-- .../active-model-serializer-test.js | 4 +- .../lib/adapters/build-url-mixin.js | 57 +++++++++++-- .../ember-data/lib/adapters/rest-adapter.js | 68 ++++++++++++++-- .../lib/serializers/json-serializer.js | 21 ++--- packages/ember-data/lib/system/adapter.js | 22 ++--- packages/ember-data/lib/system/store.js | 6 +- .../ember-data/lib/system/store/finders.js | 25 +++++- .../adapter/build-url-mixin-test.js | 48 ++++++++--- .../tests/integration/adapter/find-test.js | 20 ++--- .../tests/integration/adapter/queries-test.js | 2 +- .../integration/adapter/rest-adapter-test.js | 16 ++-- .../integration/adapter/store-adapter-test.js | 54 ++++++------- .../tests/integration/filter-test.js | 30 +++---- .../tests/integration/records/load-test.js | 4 +- .../tests/integration/records/reload-test.js | 12 +-- .../relationships/belongs-to-test.js | 54 ++++++------- .../relationships/has-many-test.js | 74 ++++++++--------- .../relationships/one-to-one-test.js | 2 +- .../embedded-records-mixin-new-test.js | 18 ++--- .../serializers/rest-serializer-new-test.js | 13 +-- .../tests/integration/store-test.js | 12 +-- .../build-url-mixin/path-for-type-test.js | 16 ++-- .../unit/adapters/rest-adapter/ajax-test.js | 6 +- .../deprecated-adapter-methods.js | 35 ++++++++ packages/ember-data/tests/unit/model-test.js | 34 ++++---- .../unit/model/lifecycle-callbacks-test.js | 16 ++-- .../ember-data/tests/unit/model/merge-test.js | 2 +- .../model/relationships/belongs-to-test.js | 20 ++--- .../unit/model/relationships/has-many-test.js | 30 +++---- .../model/relationships/record-array-test.js | 2 +- .../tests/unit/record-array-test.js | 6 +- .../tests/unit/store/adapter-interop-test.js | 80 +++++++++---------- .../ember-data/tests/unit/store/push-test.js | 12 +-- .../tests/unit/store/unload-test.js | 18 ++--- 36 files changed, 520 insertions(+), 335 deletions(-) create mode 100644 packages/ember-data/tests/unit/adapters/rest-adapter/deprecated-adapter-methods.js diff --git a/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-model-name-new-test.js b/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-model-name-new-test.js index 7e7fbd1e89b..915ffec6bf1 100644 --- a/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-model-name-new-test.js +++ b/packages/activemodel-adapter/tests/integration/active-model-serializer-namespaced-model-name-new-test.js @@ -57,7 +57,7 @@ test("extractPolymorphic hasMany", function() { var json; run(function() { - json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json_hash, '1', 'find'); + json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json_hash, '1', 'findRecord'); }); deepEqual(json, { @@ -94,7 +94,7 @@ test("extractPolymorphic belongsTo", function() { var json; run(function() { - json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json_hash, '1', 'find'); + json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json_hash, '1', 'findRecord'); }); deepEqual(json, { diff --git a/packages/activemodel-adapter/tests/integration/active-model-serializer-new-test.js b/packages/activemodel-adapter/tests/integration/active-model-serializer-new-test.js index 31382e60bd3..68ffb2d67db 100644 --- a/packages/activemodel-adapter/tests/integration/active-model-serializer-new-test.js +++ b/packages/activemodel-adapter/tests/integration/active-model-serializer-new-test.js @@ -120,7 +120,7 @@ test("normalizeSingleResponse", function() { var json; run(function() { - json = env.amsSerializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); + json = env.amsSerializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'findRecord'); }); deepEqual(json, { @@ -210,7 +210,7 @@ test("extractPolymorphic hasMany", function() { var json; run(function() { - json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json_hash, '1', 'find'); + json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json_hash, '1', 'findRecord'); }); deepEqual(json, { @@ -251,7 +251,7 @@ test("extractPolymorphic belongsTo", function() { var json; run(function() { - json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json_hash, '1', 'find'); + json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json_hash, '1', 'findRecord'); }); deepEqual(json, { @@ -285,7 +285,7 @@ test("extractPolymorphic when the related data is not specified", function() { }; run(function() { - json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json, '1', 'find'); + json = env.amsSerializer.normalizeResponse(env.store, DoomsdayDevice, json, '1', 'findRecord'); }); deepEqual(json, { @@ -314,7 +314,7 @@ test("extractPolymorphic hasMany when the related data is not specified", functi }; run(function() { - json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json, '1', 'find'); + json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json, '1', 'findRecord'); }); deepEqual(json, { @@ -336,7 +336,7 @@ test("extractPolymorphic does not break hasMany relationships", function() { }; run(function () { - json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json, '1', 'find'); + json = env.amsSerializer.normalizeResponse(env.store, MediocreVillain, json, '1', 'findRecord'); }); deepEqual(json, { diff --git a/packages/activemodel-adapter/tests/integration/active-model-serializer-test.js b/packages/activemodel-adapter/tests/integration/active-model-serializer-test.js index a259615348a..914a68b7723 100644 --- a/packages/activemodel-adapter/tests/integration/active-model-serializer-test.js +++ b/packages/activemodel-adapter/tests/integration/active-model-serializer-test.js @@ -156,7 +156,7 @@ test("extractSingle", function() { }); run(function() { - env.store.find('super-villain', 1).then(function(minion) { + env.store.findRecord('super-villain', 1).then(function(minion) { equal(minion.get('firstName'), "Tom"); }); }); @@ -182,7 +182,7 @@ test("extractArray", function() { }]); run(function() { - env.store.find('super-villain', 1).then(function(minion) { + env.store.findRecord('super-villain', 1).then(function(minion) { equal(minion.get('firstName'), "Tom"); }); }); diff --git a/packages/ember-data/lib/adapters/build-url-mixin.js b/packages/ember-data/lib/adapters/build-url-mixin.js index 667bb925afc..328c224030b 100644 --- a/packages/ember-data/lib/adapters/build-url-mixin.js +++ b/packages/ember-data/lib/adapters/build-url-mixin.js @@ -13,8 +13,8 @@ var get = Ember.get; ```javascript export default DS.Adapter.extend(BuildURLMixin, { - find: function(store, type, id, snapshot) { - var url = this.buildURL(type.modelName, id, snapshot, 'find'); + findRecord: function(store, type, id, snapshot) { + var url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); return this.ajax(url, 'GET'); } }); @@ -27,7 +27,7 @@ var get = Ember.get; @class BuildURLMixin @namespace DS */ -export default Ember.Mixin.create({ +var BuildURLMixin = Ember.Mixin.create({ /** Builds a URL for a given type and optional ID. @@ -46,17 +46,23 @@ export default Ember.Mixin.create({ @param {(String|Array|Object)} id single id or array of ids or query @param {(DS.Snapshot|Array)} snapshot single snapshot or array of snapshots @param {String} requestType - @param {Object} query object of query parameters to send for findQuery requests. + @param {Object} query object of query parameters to send for query requests. @return {String} url */ buildURL: function(modelName, id, snapshot, requestType, query) { switch (requestType) { case 'find': + // The `find` case is deprecated return this.urlForFind(id, modelName, snapshot); + case 'findRecord': + return this.urlForFindRecord(id, modelName, snapshot); case 'findAll': return this.urlForFindAll(modelName); case 'findQuery': + // The `findQuery` case is deprecated return this.urlForFindQuery(query, modelName); + case 'query': + return this.urlForQuery(query, modelName); case 'findMany': return this.urlForFindMany(id, modelName, snapshot); case 'findHasMany': @@ -109,8 +115,22 @@ export default Ember.Mixin.create({ * @param {String} modelName * @param {DS.Snapshot} snapshot * @return {String} url + * @deprecated Use [urlForFindRecord](#method_urlForFindRecord) instead */ - urlForFind: function(id, modelName, snapshot) { + urlForFind: urlForFind, + + /** + * @method urlForFind + * @param {String} id + * @param {String} modelName + * @param {DS.Snapshot} snapshot + * @return {String} url + */ + urlForFindRecord: function(id, modelName, snapshot) { + if (this.urlForFind !== urlForFind) { + Ember.deprecate('BuildURLMixin#urlForFind has been deprecated and renamed to `urlForFindRecord`.'); + return this.urlForFind(id, modelName, snapshot); + } return this._buildURL(modelName, id); }, @@ -128,8 +148,21 @@ export default Ember.Mixin.create({ * @param {Object} query * @param {String} modelName * @return {String} url + * @deprecated Use [urlForQuery](#method_urlForQuery) instead */ - urlForFindQuery: function(query, modelName) { + urlForFindQuery: urlForFindQuery, + + /** + * @method urlForQuery + * @param {Object} query + * @param {String} modelName + * @return {String} url + */ + urlForQuery: function(query, modelName) { + if (this.urlForFindQuery !== urlForFindQuery) { + Ember.deprecate('BuildURLMixin#urlForFindQuery has been deprecated and renamed to `urlForQuery`.'); + return this.urlForFindQuery(query, modelName); + } return this._buildURL(modelName); }, @@ -270,3 +303,15 @@ export default Ember.Mixin.create({ return Ember.String.pluralize(camelized); } }); + +function urlForFind(id, modelName, snapshot) { + Ember.deprecate('BuildURLMixin#urlForFind has been deprecated and renamed to `urlForFindRecord`.'); + return this._buildURL(modelName, id); +} + +function urlForFindQuery(query, modelName) { + Ember.deprecate('BuildURLMixin#urlForFindQuery has been deprecated and renamed to `urlForQuery`.'); + return this._buildURL(modelName); +} + +export default BuildURLMixin; diff --git a/packages/ember-data/lib/adapters/rest-adapter.js b/packages/ember-data/lib/adapters/rest-adapter.js index caf968b9ddd..f161f286b1e 100644 --- a/packages/ember-data/lib/adapters/rest-adapter.js +++ b/packages/ember-data/lib/adapters/rest-adapter.js @@ -277,8 +277,8 @@ var RestAdapter = Adapter.extend(BuildURLMixin, { relationships accessed within the same runloop. If you set `coalesceFindRequests: true` ```javascript - store.find('comment', 1); - store.find('comment', 2); + store.findRecord('comment', 1); + store.findRecord('comment', 2); ``` will also send a request to: `GET /comments?ids[]=1&ids[]=2` @@ -346,26 +346,45 @@ var RestAdapter = Adapter.extend(BuildURLMixin, { @property headers @type {Object} + */ + + /** + @method find + @param {DS.Store} store + @param {DS.Model} type + @param {String} id + @param {DS.Snapshot} snapshot + @return {Promise} promise + @deprecated Use [findRecord](#method_findRecord) instead */ + find: function(store, type, id, snapshot) { + Ember.deprecate('RestAdapter#find has been deprecated and renamed to `findRecord`.'); + return this.ajax(this.buildURL(type.modelName, id, snapshot, 'find'), 'GET'); + }, /** Called by the store in order to fetch the JSON for a given type and ID. - The `find` method makes an Ajax request to a URL computed by `buildURL`, and returns a - promise for the resulting payload. + The `findRecord` method makes an Ajax request to a URL computed by + `buildURL`, and returns a promise for the resulting payload. This method performs an HTTP `GET` request with the id provided as part of the query string. - @method find + @method findRecord @param {DS.Store} store @param {DS.Model} type @param {String} id @param {DS.Snapshot} snapshot @return {Promise} promise */ - find: function(store, type, id, snapshot) { - return this.ajax(this.buildURL(type.modelName, id, snapshot, 'find'), 'GET'); + findRecord: function(store, type, id, snapshot) { + var find = RestAdapter.prototype.find; + if (find !== this.find) { + Ember.deprecate('RestAdapter#find has been deprecated and renamed to `findRecord`.'); + return this.find(store, type, id, snapshot); + } + return this.ajax(this.buildURL(type.modelName, id, snapshot, 'findRecord'), 'GET'); }, /** @@ -410,8 +429,10 @@ var RestAdapter = Adapter.extend(BuildURLMixin, { @param {DS.Model} type @param {Object} query @return {Promise} promise + @deprecated Use [query](#method_query) instead */ findQuery: function(store, type, query) { + Ember.deprecate('RestAdapter#findQuery has been deprecated and renamed to `query`.'); var url = this.buildURL(type.modelName, null, null, 'findQuery', query); if (this.sortQueryParams) { @@ -421,6 +442,39 @@ var RestAdapter = Adapter.extend(BuildURLMixin, { return this.ajax(url, 'GET', { data: query }); }, + /** + Called by the store in order to fetch a JSON array for + the records that match a particular query. + + The `findQuery` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a + promise for the resulting payload. + + The `query` argument is a simple JavaScript object that will be passed directly + to the server as parameters. + + @private + @method query + @param {DS.Store} store + @param {DS.Model} type + @param {Object} query + @return {Promise} promise + */ + query: function(store, type, query) { + var findQuery = RestAdapter.prototype.findQuery; + if (findQuery !== this.findQuery) { + Ember.deprecate('RestAdapter#findQuery has been deprecated and renamed to `query`.'); + return this.findQuery(store, type, query); + } + + var url = this.buildURL(type.modelName, null, null, 'query', query); + + if (this.sortQueryParams) { + query = this.sortQueryParams(query); + } + + return this.ajax(url, 'GET', { data: query }); + }, + /** Called by the store in order to fetch several records together if `coalesceFindRequests` is true diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index 1d3dd6a49fb..cecde55c1d9 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -81,7 +81,7 @@ var merge = Ember.merge; @namespace DS @extends DS.Serializer */ -export default Serializer.extend({ +var JSONSerializer = Serializer.extend({ /** The primaryKey is used when serializing and deserializing @@ -231,8 +231,8 @@ export default Serializer.extend({ */ normalizeResponse: function(store, primaryModelClass, payload, id, requestType) { switch (requestType) { - case 'find': - return this.normalizeFindResponse(...arguments); + case 'findRecord': + return this.normalizeFindRecordResponse(...arguments); case 'findAll': return this.normalizeFindAllResponse(...arguments); case 'findBelongsTo': @@ -241,8 +241,8 @@ export default Serializer.extend({ return this.normalizeFindHasManyResponse(...arguments); case 'findMany': return this.normalizeFindManyResponse(...arguments); - case 'findQuery': - return this.normalizeFindQueryResponse(...arguments); + case 'query': + return this.normalizeQueryResponse(...arguments); case 'createRecord': return this.normalizeCreateRecordResponse(...arguments); case 'deleteRecord': @@ -253,7 +253,7 @@ export default Serializer.extend({ }, /* - @method normalizeFindResponse + @method normalizeFindRecordResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @param {Object} payload @@ -261,7 +261,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeFindResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeFindRecordResponse: function(store, primaryModelClass, payload, id, requestType) { return this.normalizeSingleResponse(...arguments); }, @@ -318,7 +318,7 @@ export default Serializer.extend({ }, /* - @method normalizeFindQueryResponse + @method normalizeQueryResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @param {Object} payload @@ -326,7 +326,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeFindQueryResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeQueryResponse: function(store, primaryModelClass, payload, id, requestType) { return this.normalizeArrayResponse(...arguments); }, @@ -1369,6 +1369,7 @@ export default Serializer.extend({ extractFind: function(store, typeClass, payload, id, requestType) { return this.extractSingle(store, typeClass, payload, id, requestType); }, + /** `extractFindBelongsTo` is a hook into the extract method used when a call is made to `DS.Store#findBelongsTo`. By default this method is @@ -1664,3 +1665,5 @@ function _newExtractMeta(store, modelClass, payload) { return meta; } } + +export default JSONSerializer; diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 587610b9aca..9e23956cc8b 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -41,12 +41,12 @@ var get = Ember.get; application to customize it for your backend. The minimum set of methods that you should implement is: - * `find()` + * `findRecord()` * `createRecord()` * `updateRecord()` * `deleteRecord()` * `findAll()` - * `findQuery()` + * `query()` To improve the network performance of your application, you can optimize your adapter by overriding these lower-level methods: @@ -87,19 +87,19 @@ var Adapter = Ember.Object.extend({ defaultSerializer: '-default', /** - The `find()` method is invoked when the store is asked for a record that - has not previously been loaded. In response to `find()` being called, you + The `findRecord()` method is invoked when the store is asked for a record that + has not previously been loaded. In response to `findRecord()` being called, you should query your persistence layer for a record with the given ID. Once found, you can asynchronously call the store's `push()` method to push the record into the store. - Here is an example `find` implementation: + Here is an example `findRecord` implementation: ```app/adapters/application.js import DS from 'ember-data'; export default DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { var url = [type.modelName, id].join('/'); return new Ember.RSVP.Promise(function(resolve, reject) { @@ -114,14 +114,14 @@ var Adapter = Ember.Object.extend({ }); ``` - @method find + @method findRecord @param {DS.Store} store @param {DS.Model} type @param {String} id @param {DS.Snapshot} snapshot @return {Promise} promise */ - find: null, + findRecord: null, /** The `findAll()` method is used to retrieve all records for a given type. @@ -165,7 +165,7 @@ var Adapter = Ember.Object.extend({ import DS from 'ember-data'; export default DS.Adapter.extend({ - findQuery: function(store, type, query) { + query: function(store, type, query) { var url = type; return new Ember.RSVP.Promise(function(resolve, reject) { jQuery.getJSON(url, query).then(function(data) { @@ -180,14 +180,14 @@ var Adapter = Ember.Object.extend({ ``` @private - @method findQuery + @method query @param {DS.Store} store @param {DS.Model} type @param {Object} query @param {DS.AdapterPopulatedRecordArray} recordArray @return {Promise} promise */ - findQuery: null, + query: null, /** The `queryRecord()` method is invoked when the store is asked for a single diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 3d1a577a8c3..72abc47ce0c 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -690,7 +690,7 @@ Store = Service.extend({ var adapter = this.adapterFor(typeClass.modelName); Ember.assert("You tried to find a record but you have no adapter (for " + typeClass + ")", adapter); - Ember.assert("You tried to find a record but your adapter (for " + typeClass + ") does not implement 'find'", typeof adapter.find === 'function'); + Ember.assert("You tried to find a record but your adapter (for " + typeClass + ") does not implement 'findRecord'", typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); var promise = _find(adapter, this, typeClass, id, internalModel, options); return promise; @@ -896,7 +896,7 @@ Store = Service.extend({ Ember.assert("You cannot reload a record without an ID", id); Ember.assert("You tried to reload a record but you have no adapter (for " + modelName + ")", adapter); - Ember.assert("You tried to reload a record but your adapter does not implement `find`", typeof adapter.find === 'function'); + Ember.assert("You tried to reload a record but your adapter does not implement `findRecord`", typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); return this.scheduleFetch(internalModel); }, @@ -1052,7 +1052,7 @@ Store = Service.extend({ var adapter = this.adapterFor(modelName); Ember.assert("You tried to load a query but you have no adapter (for " + typeClass + ")", adapter); - Ember.assert("You tried to load a query but your adapter does not implement `findQuery`", typeof adapter.findQuery === 'function'); + Ember.assert("You tried to load a query but your adapter does not implement `query`", typeof adapter.query === 'function' || typeof adapter.findQuery === 'function'); return promiseArray(_query(adapter, this, typeClass, query, array)); }, diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index d99fb20f71c..1be56f395a3 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -15,10 +15,17 @@ import { var Promise = Ember.RSVP.Promise; var map = Ember.EnumerableUtils.map; +var get = Ember.get; export function _find(adapter, store, typeClass, id, internalModel, options) { var snapshot = internalModel.createSnapshot(options); - var promise = adapter.find(store, typeClass, id, snapshot); + var promise; + if (!adapter.findRecord) { + Ember.deprecate('Adapter#find has been deprecated and renamed to `findRecord`.'); + promise = adapter.find(store, typeClass, id, snapshot); + } else { + promise = adapter.findRecord(store, typeClass, id, snapshot); + } var serializer = serializerForAdapter(store, adapter, internalModel.type.modelName); var label = "DS: Handle Adapter#find of " + typeClass + " with id: " + id; @@ -28,7 +35,8 @@ export function _find(adapter, store, typeClass, id, internalModel, options) { return promise.then(function(adapterPayload) { Ember.assert("You made a request for a " + typeClass.typeClassKey + " with id " + id + ", but the adapter's response did not have any data", adapterPayload); return store._adapterRun(function() { - var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, id, 'find'); + var requestType = get(serializer, 'isNewSerializerAPI') ? 'findRecord' : 'find'; + var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, id, requestType); //TODO Optimize var record = pushPayload(store, payload); return record._internalModel; @@ -143,7 +151,15 @@ export function _findAll(adapter, store, typeClass, sinceToken, options) { export function _query(adapter, store, typeClass, query, recordArray) { var modelName = typeClass.modelName; - var promise = adapter.findQuery(store, typeClass, query, recordArray); + var promise; + + if (!adapter.query) { + Ember.deprecate('Adapter#findQuery has been deprecated and renamed to `query`.'); + promise = adapter.findQuery(store, typeClass, query, recordArray); + } else { + promise = adapter.query(store, typeClass, query, recordArray); + } + var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Handle Adapter#findQuery of " + typeClass; @@ -153,7 +169,8 @@ export function _query(adapter, store, typeClass, query, recordArray) { return promise.then(function(adapterPayload) { var records; store._adapterRun(function() { - var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findQuery'); + var requestType = get(serializer, 'isNewSerializerAPI') ? 'query' : 'findQuery'; + var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, requestType); //TODO Optimize records = pushPayload(store, payload); }); diff --git a/packages/ember-data/tests/integration/adapter/build-url-mixin-test.js b/packages/ember-data/tests/integration/adapter/build-url-mixin-test.js index dc2a1b75619..3ed2e523e23 100644 --- a/packages/ember-data/tests/integration/adapter/build-url-mixin-test.js +++ b/packages/ember-data/tests/integration/adapter/build-url-mixin-test.js @@ -55,7 +55,7 @@ test('buildURL - with host and namespace', function() { ajaxResponse({ posts: [{ id: 1 }] }); - run(store, 'find', 'post', 1).then(async(function(post) { + run(store, 'findRecord', 'post', 1).then(async(function(post) { equal(passedUrl, "http://example.com/api/v1/posts/1"); })); }); @@ -72,7 +72,7 @@ test('buildURL - with relative paths in links', function() { ajaxResponse({ posts: [{ id: 1, links: { comments: 'comments' } }] }); - run(store, 'find', 'post', '1').then(async(function(post) { + run(store, 'findRecord', 'post', '1').then(async(function(post) { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); })).then(async(function (comments) { @@ -92,7 +92,7 @@ test('buildURL - with absolute paths in links', function() { ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - run(store, 'find', 'post', 1).then(async(function(post) { + run(store, 'findRecord', 'post', 1).then(async(function(post) { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); })).then(async(function (comments) { @@ -113,7 +113,7 @@ test('buildURL - with absolute paths in links and protocol relative host', funct ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - run(store, 'find', 'post', 1).then(async(function(post) { + run(store, 'findRecord', 'post', 1).then(async(function(post) { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); })).then(async(function (comments) { @@ -138,7 +138,7 @@ test('buildURL - with full URLs in links', function() { }); run(function() { - store.find('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(async(function(post) { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); })).then(async(function (comments) { @@ -158,7 +158,7 @@ test('buildURL - with camelized names', function() { ajaxResponse({ superUsers: [{ id: 1 }] }); run(function() { - store.find('super-user', 1).then(async(function(post) { + store.findRecord('super-user', 1).then(async(function(post) { equal(passedUrl, "/super_users/1"); })); }); @@ -178,7 +178,7 @@ test('buildURL - buildURL takes a record from find', function() { }); run(function() { - store.find('comment', 1, { preload: { post: post } }).then(async(function(post) { + store.findRecord('comment', 1, { preload: { post: post } }).then(async(function(post) { equal(passedUrl, "/posts/2/comments/1"); })); }); @@ -231,7 +231,7 @@ test('buildURL - buildURL takes a record from create to query a resolved async b ajaxResponse({ posts: [{ id: 2 }] }); run(function() { - store.find('post', 2).then(async(function(post) { + store.findRecord('post', 2).then(async(function(post) { equal(post.get('id'), 2); adapter.buildURL = function(type, id, snapshot) { @@ -304,7 +304,37 @@ test('buildURL - with absolute namespace', function() { ajaxResponse({ posts: [{ id: 1 }] }); - run(store, 'find', 'post', 1).then(async(function(post) { + run(store, 'findRecord', 'post', 1).then(async(function(post) { equal(passedUrl, "/api/v1/posts/1"); })); }); + + +test('buildURL - urlForFindRecord calls deprecated urlForFind', function() { + expect(2); + + var adapter = DS.RESTAdapter.extend({ + urlForFind: function() { + ok(true, 'urlForFind should be called'); + } + }).create(); + + expectDeprecation(function() { + adapter.buildURL('post', 1, {}, 'findRecord'); + }, /urlForFindRecord/); +}); + + +test('buildURL - urlForQuery calls deprecated urlForFindQuery', function() { + expect(2); + + var adapter = DS.RESTAdapter.extend({ + urlForFindQuery: function() { + ok(true, 'urlForFindQuery should be called'); + } + }).create(); + + expectDeprecation(function() { + adapter.buildURL('post', 1, {}, 'query'); + }, /urlForQuery/); +}); diff --git a/packages/ember-data/tests/integration/adapter/find-test.js b/packages/ember-data/tests/integration/adapter/find-test.js index e91de0e63b4..8e573b11ea9 100644 --- a/packages/ember-data/tests/integration/adapter/find-test.js +++ b/packages/ember-data/tests/integration/adapter/find-test.js @@ -60,7 +60,7 @@ test("When a single record is requested, the adapter's find method should be cal var count = 0; env.registry.register('adapter:person', DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { equal(type, Person, "the find method is called with the correct type"); equal(count, 0, "the find method is only called once"); @@ -70,8 +70,8 @@ test("When a single record is requested, the adapter's find method should be cal })); run(function() { - store.find('person', 1); - store.find('person', 1); + store.findRecord('person', 1); + store.findRecord('person', 1); }); }); @@ -79,13 +79,13 @@ test("When a single record is requested multiple times, all .find() calls are re var deferred = Ember.RSVP.defer(); env.registry.register('adapter:person', DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return deferred.promise; } })); run(function() { - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { equal(person.get('id'), "1"); equal(person.get('name'), "Braaaahm Dale"); @@ -101,7 +101,7 @@ test("When a single record is requested multiple times, all .find() calls are re }); run(function() { - store.find('person', 1).then(async(function(post) { + store.findRecord('person', 1).then(async(function(post) { equal(post.get('id'), "1"); equal(post.get('name'), "Braaaahm Dale"); @@ -124,13 +124,13 @@ test("When a single record is requested multiple times, all .find() calls are re test("When a single record is requested, and the promise is rejected, .find() is rejected.", function() { env.registry.register('adapter:person', DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return Ember.RSVP.reject(); } })); run(function() { - store.find('person', 1).then(null, async(function(reason) { + store.findRecord('person', 1).then(null, async(function(reason) { ok(true, "The rejection handler was called"); })); }); @@ -140,13 +140,13 @@ test("When a single record is requested, and the promise is rejected, the record expect(2); env.registry.register('adapter:person', DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return Ember.RSVP.reject(); } })); run(function() { - store.find('person', 1).then(null, async(function(reason) { + store.findRecord('person', 1).then(null, async(function(reason) { ok(true, "The rejection handler was called"); })); }); diff --git a/packages/ember-data/tests/integration/adapter/queries-test.js b/packages/ember-data/tests/integration/adapter/queries-test.js index fbd4520bdef..70ecd6b204b 100644 --- a/packages/ember-data/tests/integration/adapter/queries-test.js +++ b/packages/ember-data/tests/integration/adapter/queries-test.js @@ -22,7 +22,7 @@ module("integration/adapter/queries - Queries", { }); test("When a query is made, the adapter should receive a record array it can populate with the results of the query.", function() { - adapter.findQuery = function(store, type, query, recordArray) { + adapter.query = function(store, type, query, recordArray) { equal(type, Person, "the find method is called with the correct type"); return Ember.RSVP.resolve([{ id: 1, name: "Peter Wagenet" }, { id: 2, name: "Brohuda Katz" }]); diff --git a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js b/packages/ember-data/tests/integration/adapter/rest-adapter-test.js index f80aa3978e4..664f97fe314 100644 --- a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js +++ b/packages/ember-data/tests/integration/adapter/rest-adapter-test.js @@ -57,7 +57,7 @@ test("find - basic payload", function() { }); -test("find - passes buildURL a requestType", function() { +test("findRecord - passes buildURL a requestType", function() { adapter.buildURL = function(type, id, snapshot, requestType) { return "/" + requestType + "/post/" + id; }; @@ -65,8 +65,8 @@ test("find - passes buildURL a requestType", function() { ajaxResponse({ posts: [{ id: 1, name: "Rails is omakase" }] }); - run(store, 'find', 'post', 1).then(async(function(post) { - equal(passedUrl, "/find/post/1"); + run(store, 'findRecord', 'post', 1).then(async(function(post) { + equal(passedUrl, "/findRecord/post/1"); })); }); @@ -972,7 +972,7 @@ test("findQuery - passes buildURL the requestType", function() { }; adapter.ajax = function(url, verb, hash) { - equal(url, '/findQuery/posts'); + equal(url, '/query/posts'); return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); }; @@ -1549,7 +1549,7 @@ test('groupRecordsForFindMany groups records based on their url', function() { } }; - adapter.find = function(store, type, id, snapshot) { + adapter.findRecord = function(store, type, id, snapshot) { equal(id, '1'); return Ember.RSVP.resolve({ comments: { id: 1 } }); }; @@ -1582,7 +1582,7 @@ test('groupRecordsForFindMany groups records correctly when singular URLs are en } }; - adapter.find = function(store, type, id, snapshot) { + adapter.findRecord = function(store, type, id, snapshot) { equal(id, '1'); return Ember.RSVP.resolve({ comments: { id: 1 } }); }; @@ -1689,7 +1689,7 @@ test('groupRecordsForFindMany splits up calls for large ids', function() { adapter.coalesceFindRequests = true; - adapter.find = function(store, type, id, snapshot) { + adapter.findRecord = function(store, type, id, snapshot) { if (id === a2000 || id === b2000) { ok(true, "Found " + id); } @@ -1727,7 +1727,7 @@ test('groupRecordsForFindMany groups calls for small ids', function() { adapter.coalesceFindRequests = true; - adapter.find = function(store, type, id, snapshot) { + adapter.findRecord = function(store, type, id, snapshot) { ok(false, "find should not be called - we expect 1 call to findMany for a100 and b100"); return Ember.RSVP.reject(); }; diff --git a/packages/ember-data/tests/integration/adapter/store-adapter-test.js b/packages/ember-data/tests/integration/adapter/store-adapter-test.js index 8bb2bcd604e..8af0faba42c 100644 --- a/packages/ember-data/tests/integration/adapter/store-adapter-test.js +++ b/packages/ember-data/tests/integration/adapter/store-adapter-test.js @@ -40,7 +40,7 @@ module("integration/adapter/store_adapter - DS.Store and DS.Adapter integration }); test("Records loaded multiple times and retrieved in recordArray are ready to send state events", function() { - adapter.findQuery = function(store, type, query, recordArray) { + adapter.query = function(store, type, query, recordArray) { return Ember.RSVP.resolve([{ id: 1, name: "Mickael Ramírez" @@ -105,8 +105,8 @@ test("by default, createRecords calls createRecord once per record", function() tom = records.tom; yehuda = records.yehuda; - asyncEqual(tom, store.find('person', 1), "Once an ID is in, find returns the same object"); - asyncEqual(yehuda, store.find('person', 2), "Once an ID is in, find returns the same object"); + asyncEqual(tom, store.findRecord('person', 1), "Once an ID is in, find returns the same object"); + asyncEqual(yehuda, store.findRecord('person', 2), "Once an ID is in, find returns the same object"); equal(get(tom, 'updatedAt'), "now", "The new information is received"); equal(get(yehuda, 'updatedAt'), "now", "The new information is received"); })); @@ -140,8 +140,8 @@ test("by default, updateRecords calls updateRecord once per record", function() var promise = run(function() { return Ember.RSVP.hash({ - tom: store.find('person', 1), - yehuda: store.find('person', 2) + tom: store.findRecord('person', 1), + yehuda: store.findRecord('person', 2) }); }); @@ -190,8 +190,8 @@ test("calling store.didSaveRecord can provide an optional hash", function() { var promise = run(function() { return Ember.RSVP.hash({ - tom: store.find('person', 1), - yehuda: store.find('person', 2) + tom: store.findRecord('person', 1), + yehuda: store.findRecord('person', 2) }); }); promise.then(async(function(records) { @@ -242,8 +242,8 @@ test("by default, deleteRecord calls deleteRecord once per record", function() { var promise = run(function() { return Ember.RSVP.hash({ - tom: store.find('person', 1), - yehuda: store.find('person', 2) + tom: store.findRecord('person', 1), + yehuda: store.findRecord('person', 2) }); }); @@ -287,8 +287,8 @@ test("by default, destroyRecord calls deleteRecord once per record without requi var promise = run(function() { return Ember.RSVP.hash({ - tom: store.find('person', 1), - yehuda: store.find('person', 2) + tom: store.findRecord('person', 1), + yehuda: store.findRecord('person', 2) }); }); @@ -324,7 +324,7 @@ test("if an existing model is edited then deleted, deleteRecord is called on the }); // Retrieve that loaded record and edit it so it becomes dirty - run(store, 'find', 'person', 'deleted-record').then(async(function(tom) { + run(store, 'findRecord', 'person', 'deleted-record').then(async(function(tom) { tom.set('name', "Tom Mothereffin' Dale"); equal(get(tom, 'isDirty'), true, "precond - record should be dirty after editing"); @@ -355,7 +355,7 @@ test("if a deleted record errors, it enters the error state", function() { var tom; run(function() { - store.find('person', 'deleted-record').then(async(function(person) { + store.findRecord('person', 'deleted-record').then(async(function(person) { tom = person; person.deleteRecord(); return person.save(); @@ -529,7 +529,7 @@ test("if an updated record is marked as invalid by the server, it enters an erro }); Ember.run(function() { - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { equal(person, yehuda, "The same object is passed through"); equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); @@ -573,7 +573,7 @@ test("records can have errors on arbitrary properties after update", function() }); run(function() { - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { equal(person, yehuda, "The same object is passed through"); equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); @@ -625,7 +625,7 @@ test("if an updated record is marked as invalid by the server, you can attempt t }); Ember.run(function() { - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { equal(person, yehuda, "The same object is passed through"); equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); @@ -667,7 +667,7 @@ test("if a updated record is marked as erred by the server, it enters an error s return store.push('person', { id: 1, name: "John Doe" }); }); - run(store, 'find', 'person', 1).then(async(function(record) { + run(store, 'findRecord', 'person', 1).then(async(function(record) { equal(record, person, "The person was resolved"); person.set('name', "Jonathan Doe"); return person.save(); @@ -679,18 +679,18 @@ test("if a updated record is marked as erred by the server, it enters an error s test("can be created after the DS.Store", function() { expect(1); - adapter.find = function(store, type, id, snapshot) { + adapter.findRecord = function(store, type, id, snapshot) { equal(type, Person, "the type is correct"); return Ember.RSVP.resolve({ id: 1 }); }; run(function() { - store.find('person', 1); + store.findRecord('person', 1); }); }); test("the filter method can optionally take a server query as well", function() { - adapter.findQuery = function(store, type, query, array) { + adapter.query = function(store, type, query, array) { return Ember.RSVP.resolve([ { id: 1, name: "Yehuda Katz" }, { id: 2, name: "Tom Dale" } @@ -705,7 +705,7 @@ test("the filter method can optionally take a server query as well", function() asyncFilter.then(async(function(filter) { loadedFilter = filter; - return store.find('person', 2); + return store.findRecord('person', 2); })).then(async(function(tom) { equal(get(loadedFilter, 'length'), 1, "The filter has an item in it"); deepEqual(loadedFilter.toArray(), [tom], "The filter has a single entry in it"); @@ -721,7 +721,7 @@ test("relationships returned via `commit` do not trigger additional findManys", store.push('dog', { id: 1, name: "Scruffy" }); }); - adapter.find = function(store, type, id, snapshot) { + adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", dogs: [1] }); }; @@ -738,8 +738,8 @@ test("relationships returned via `commit` do not trigger additional findManys", }; run(function() { - store.find('person', 1).then(async(function(person) { - return Ember.RSVP.hash({ tom: person, dog: store.find('dog', 1) }); + store.findRecord('person', 1).then(async(function(person) { + return Ember.RSVP.hash({ tom: person, dog: store.findRecord('dog', 1) }); })).then(async(function(records) { records.tom.get('dogs'); return records.dog.save(); @@ -768,7 +768,7 @@ test("relationships don't get reset if the links is the same", function() { var tom, dogs; - run(store, 'find', 'person', 1).then(async(function(person) { + run(store, 'findRecord', 'person', 1).then(async(function(person) { tom = person; dogs = tom.get('dogs'); return dogs; @@ -867,13 +867,13 @@ test("deleteRecord receives a snapshot", function() { test("find receives a snapshot", function() { expect(1); - adapter.find = function(store, type, id, snapshot) { + adapter.findRecord = function(store, type, id, snapshot) { ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); return Ember.RSVP.resolve({ id: 1 }); }; run(function() { - store.find('person', 1); + store.findRecord('person', 1); }); }); diff --git a/packages/ember-data/tests/integration/filter-test.js b/packages/ember-data/tests/integration/filter-test.js index 3102b0593be..2ab10cf9a47 100644 --- a/packages/ember-data/tests/integration/filter-test.js +++ b/packages/ember-data/tests/integration/filter-test.js @@ -188,9 +188,9 @@ test("a Record Array can update its filter", function() { var asyncDale, asyncKatz, asyncBryn; run(function() { - asyncDale = store.find('person', 1); - asyncKatz = store.find('person', 2); - asyncBryn = store.find('person', 3); + asyncDale = store.findRecord('person', 1); + asyncKatz = store.findRecord('person', 2); + asyncBryn = store.findRecord('person', 3); }); store.filter('person', function(hash) { @@ -246,9 +246,9 @@ test("a Record Array can update its filter and notify array observers", function var asyncDale, asyncKatz, asyncBryn; run(function() { - asyncDale = store.find('person', 1); - asyncKatz = store.find('person', 2); - asyncBryn = store.find('person', 3); + asyncDale = store.findRecord('person', 1); + asyncKatz = store.findRecord('person', 2); + asyncBryn = store.findRecord('person', 3); }); store.filter('person', function(hash) { @@ -332,7 +332,7 @@ test("it is possible to filter by computed properties", function() { equal(filter.get('length'), 1, "the filter now has a record in it"); - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { Ember.run(function() { person.set('name', "Yehuda Katz"); }); @@ -361,12 +361,12 @@ test("a filter created after a record is already loaded works", function() { }); equal(filter.get('length'), 1, "the filter now has a record in it"); - asyncEqual(filter.objectAt(0), store.find('person', 1)); + asyncEqual(filter.objectAt(0), store.findRecord('person', 1)); }); test("filter with query persists query on the resulting filteredRecordArray", function() { customAdapter(env, DS.Adapter.extend({ - findQuery: function(store, type, id) { + query: function(store, type, id) { return Ember.RSVP.resolve([{ id: id, name: "Tom Dale" @@ -394,7 +394,7 @@ test("it is possible to filter by state flags", function() { var filter; customAdapter(env, DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: id, name: "Tom Dale" }); } })); @@ -408,7 +408,7 @@ test("it is possible to filter by state flags", function() { equal(filter.get('length'), 0, "precond - there are no records yet"); Ember.run(function() { - var asyncPerson = store.find('person', 1); + var asyncPerson = store.findRecord('person', 1); // Ember.run will block `find` from being synchronously // resolved in test mode @@ -417,7 +417,7 @@ test("it is possible to filter by state flags", function() { asyncPerson.then(async(function(person) { equal(filter.get('length'), 1, "the now-loaded record is in the filter"); - asyncEqual(filter.objectAt(0), store.find('person', 1)); + asyncEqual(filter.objectAt(0), store.findRecord('person', 1)); })); }); }); @@ -437,7 +437,7 @@ test("it is possible to filter loaded records by dirtiness", function() { store.push('person', { id: 1, name: "Tom Dale" }); }); - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { equal(filter.get('length'), 1, "the clean record is in the filter"); // Force synchronous update of the filter, even though @@ -491,7 +491,7 @@ test("it is possible to filter created records by dirtiness", function() { test("it is possible to filter created records by isReloading", function() { customAdapter(env, DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Tom Dalle" @@ -524,7 +524,7 @@ var clientEdits = function(ids) { // wrap in an Ember.run to guarantee coalescence of the // iterated `set` calls and promise resolution. Ember.run(function() { - store.find('person', id).then(function(person) { + store.findRecord('person', id).then(function(person) { edited.push(person); person.set('name', 'Client-side ' + id ); }); diff --git a/packages/ember-data/tests/integration/records/load-test.js b/packages/ember-data/tests/integration/records/load-test.js index b13d373b196..3c68ce619cb 100644 --- a/packages/ember-data/tests/integration/records/load-test.js +++ b/packages/ember-data/tests/integration/records/load-test.js @@ -22,12 +22,12 @@ module("integration/load - Loading Records", { }); test("When loading a record fails, the isLoading is set to false", function() { - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.reject(); }; run(function() { - env.store.find('post', 1).then(null, async(function() { + env.store.findRecord('post', 1).then(null, async(function() { // store.recordForId is private, but there is currently no other way to // get the specific record instance, since it is not passed to this // rejection handler diff --git a/packages/ember-data/tests/integration/records/reload-test.js b/packages/ember-data/tests/integration/records/reload-test.js index edc2d487a97..a4600eed35a 100644 --- a/packages/ember-data/tests/integration/records/reload-test.js +++ b/packages/ember-data/tests/integration/records/reload-test.js @@ -25,7 +25,7 @@ module("integration/reload - Reloading Records", { test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function() { var count = 0; - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { if (count === 0) { count++; return Ember.RSVP.resolve({ id: id, name: "Tom Dale" }); @@ -38,7 +38,7 @@ test("When a single record is requested, the adapter's find method should be cal }; run(function() { - env.store.find('person', 1).then(function(person) { + env.store.findRecord('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is loaded with the right name"); equal(get(person, 'isLoaded'), true, "The person is now loaded"); var promise = person.reload(); @@ -58,7 +58,7 @@ test("When a record is reloaded and fails, it can try again", function() { }); var count = 0; - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { equal(tom.get('isReloading'), true, "Tom is reloading"); if (count++ === 0) { return Ember.RSVP.reject(); @@ -87,7 +87,7 @@ test("When a record is loaded a second time, isLoaded stays true", function() { }); run(function() { - env.store.find('person', 1).then(function(person) { + env.store.findRecord('person', 1).then(function(person) { equal(get(person, 'isLoaded'), true, "The person is loaded"); person.addObserver('isLoaded', isLoadedDidChange); @@ -117,7 +117,7 @@ test("When a record is reloaded, its async hasMany relationships still work", fu var tags = { 1: "hipster", 2: "hair" }; - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { switch (type.modelName) { case 'person': return Ember.RSVP.resolve({ id: 1, name: "Tom", tags: [1, 2] }); @@ -129,7 +129,7 @@ test("When a record is reloaded, its async hasMany relationships still work", fu var tom; run(function() { - env.store.find('person', 1).then(function(person) { + env.store.findRecord('person', 1).then(function(person) { tom = person; equal(person.get('name'), "Tom", "precond"); diff --git a/packages/ember-data/tests/integration/relationships/belongs-to-test.js b/packages/ember-data/tests/integration/relationships/belongs-to-test.js index e3621acc3bf..967d303af48 100644 --- a/packages/ember-data/tests/integration/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/integration/relationships/belongs-to-test.js @@ -106,7 +106,7 @@ test("The store can materialize a non loaded monomorphic belongsTo association", }) }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { ok(true, "The adapter's find method should be called"); return Ember.RSVP.resolve({ id: 1 @@ -121,7 +121,7 @@ test("The store can materialize a non loaded monomorphic belongsTo association", }); run(function() { - env.store.find('post', 1).then(function(post) { + env.store.findRecord('post', 1).then(function(post) { post.get('user'); }); }); @@ -137,8 +137,8 @@ test("Only a record of the same type can be used with a monomorphic belongsTo re run(function() { hash({ - post: store.find('post', 1), - comment: store.find('comment', 2) + post: store.findRecord('post', 1), + comment: store.findRecord('comment', 2) }).then(function(records) { expectAssertion(function() { records.post.set('user', records.comment); @@ -158,10 +158,10 @@ test("Only a record of the same base type can be used with a polymorphic belongs run(function() { var asyncRecords = hash({ - user: store.find('user', 3), - post: store.find('post', 1), - comment: store.find('comment', 1), - anotherComment: store.find('comment', 2) + user: store.findRecord('user', 3), + post: store.findRecord('post', 1), + comment: store.findRecord('comment', 1), + anotherComment: store.findRecord('comment', 2) }); asyncRecords.then(function(records) { @@ -186,8 +186,8 @@ test("The store can load a polymorphic belongsTo association", function() { run(function() { hash({ - message: store.find('post', 1), - comment: store.find('comment', 2) + message: store.findRecord('post', 1), + comment: store.findRecord('comment', 2) }).then(function(records) { equal(records.comment.get('message'), records.message); }); @@ -205,7 +205,7 @@ test("The store can serialize a polymorphic belongsTo association", function() { env.store.push('post', { id: 1 }); env.store.push('comment', { id: 2, message: 1, messageType: 'post' }); - store.find('comment', 2).then(function(comment) { + store.findRecord('comment', 2).then(function(comment) { var serialized = store.serialize(comment, { includeId: true }); equal(serialized['message'], 1); equal(serialized['message_type'], 'post'); @@ -229,7 +229,7 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to store.push('person', { id: 1, links: { group: '/people/1/group' } }); }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { throw new Error("Adapter's find method should not be called"); }; @@ -242,7 +242,7 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to }); run(function() { - env.store.find('person', 1).then(function(person) { + env.store.findRecord('person', 1).then(function(person) { return person.get('group'); }).then(function(group) { ok(group instanceof Group, "A group object is loaded"); @@ -267,7 +267,7 @@ test('A record with an async belongsTo relationship always returns a promise for store.push('person', { id: 1, links: { seat: '/people/1/seat' } }); }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { throw new Error("Adapter's find method should not be called"); }; @@ -276,7 +276,7 @@ test('A record with an async belongsTo relationship always returns a promise for }); run(function() { - env.store.find('person', 1).then(function(person) { + env.store.findRecord('person', 1).then(function(person) { person.get('seat').then(function(seat) { // this assertion fails too // ok(seat.get('person') === person, 'parent relationship should be populated'); @@ -305,7 +305,7 @@ test("A record with an async belongsTo relationship returning null should resolv store.push('person', { id: 1, links: { group: '/people/1/group' } }); }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { throw new Error("Adapter's find method should not be called"); }; @@ -313,7 +313,7 @@ test("A record with an async belongsTo relationship returning null should resolv return Ember.RSVP.resolve(null); }); - env.store.find('person', 1).then(async(function(person) { + env.store.findRecord('person', 1).then(async(function(person) { return person.get('group'); })).then(async(function(group) { ok(group === null, "group should be null"); @@ -339,7 +339,7 @@ test("A record can be created with a resolved belongsTo promise", function() { group = store.push('group', { id: 1 }); }); - var groupPromise = store.find('group', 1); + var groupPromise = store.findRecord('group', 1); groupPromise.then(async(function(group) { var person = env.store.createRecord('person', { group: groupPromise @@ -552,7 +552,7 @@ test("Destroying a record with an unloaded aync belongsTo association does not f }); }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { throw new Error("Adapter's find method should not be called"); }; @@ -631,12 +631,12 @@ test("belongsTo hasData async loaded", function () { author: belongsTo('author', { async: true }) }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: 'The Greatest Book', author: 2 }); }; run(function() { - store.find('book', 1).then(function(book) { + store.findRecord('book', 1).then(function(book) { var relationship = book._internalModel._relationships.get('author'); equal(relationship.hasData, true, 'relationship has data'); }); @@ -646,12 +646,12 @@ test("belongsTo hasData async loaded", function () { test("belongsTo hasData sync loaded", function () { expect(1); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: 'The Greatest Book', author: 2 }); }; run(function() { - store.find('book', 1).then(function(book) { + store.findRecord('book', 1).then(function(book) { var relationship = book._internalModel._relationships.get('author'); equal(relationship.hasData, true, 'relationship has data'); }); @@ -665,12 +665,12 @@ test("belongsTo hasData async not loaded", function () { author: belongsTo('author', { async: true }) }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: 'The Greatest Book', links: { author: 'author' } }); }; run(function() { - store.find('book', 1).then(function(book) { + store.findRecord('book', 1).then(function(book) { var relationship = book._internalModel._relationships.get('author'); equal(relationship.hasData, false, 'relationship does not have data'); }); @@ -680,12 +680,12 @@ test("belongsTo hasData async not loaded", function () { test("belongsTo hasData sync not loaded", function () { expect(1); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: 'The Greatest Book' }); }; run(function() { - store.find('book', 1).then(function(book) { + store.findRecord('book', 1).then(function(book) { var relationship = book._internalModel._relationships.get('author'); equal(relationship.hasData, false, 'relationship does not have data'); }); diff --git a/packages/ember-data/tests/integration/relationships/has-many-test.js b/packages/ember-data/tests/integration/relationships/has-many-test.js index 4bd0482eeae..ee93c485375 100644 --- a/packages/ember-data/tests/integration/relationships/has-many-test.js +++ b/packages/ember-data/tests/integration/relationships/has-many-test.js @@ -99,7 +99,7 @@ test("When a hasMany relationship is accessed, the adapter's findMany method sho run(function() { env.store.push('post', { id: 1, comments: [1] }); env.store.push('comment', { id: 1 }); - env.store.find('post', 1).then(function(post) { + env.store.findRecord('post', 1).then(function(post) { return post.get('comments'); }); }); @@ -120,7 +120,7 @@ test("adapter.findMany only gets unique IDs even if duplicate IDs are present in run(function() { env.store.push('book', { id: 1, chapters: [2, 3, 3] }); - env.store.find('book', 1).then(function(book) { + env.store.findRecord('book', 1).then(function(book) { return book.get('chapters'); }); }); @@ -137,7 +137,7 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi // When the store asks the adapter for the record with ID 1, // provide some fake data. - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { equal(type, Post, "find type was Post"); equal(id, "1", "find id was 1"); @@ -159,7 +159,7 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi }; run(function() { - env.store.find('post', 1).then(async(function(post) { + env.store.findRecord('post', 1).then(async(function(post) { return post.get('comments'); })).then(async(function(comments) { equal(comments.get('isLoaded'), true, "comments are loaded"); @@ -332,7 +332,7 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func comments: DS.hasMany('comment', { async: true }) }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { equal(type, Post, "find type was Post"); equal(id, "1", "find id was 1"); @@ -351,7 +351,7 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func }; run(function() { - run(env.store, 'find', 'post', 1).then(function(post) { + run(env.store, 'findRecord', 'post', 1).then(function(post) { return post.get('comments'); }).then(function(comments) { equal(comments.get('isLoaded'), true, "comments are loaded"); @@ -381,7 +381,7 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu comments: DS.hasMany('comment') }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { equal(type, Post, "find type was Post"); equal(id, "1", "find id was 1"); @@ -391,7 +391,7 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu run(function() { env.store.pushMany('comment', [{ id: 1, body: "First" }, { id: 2, body: "Second" }]); - env.store.find('post', '1').then(function(post) { + env.store.findRecord('post', '1').then(function(post) { var comments = post.get('comments'); equal(comments.get('isLoaded'), true, "comments are loaded"); equal(comments.get('length'), 2, "comments have a length of 2"); @@ -415,7 +415,7 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio comments: DS.hasMany('comment', { async: true }) }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { equal(type, Post, "find type was Post"); equal(id, "1", "find id was 1"); @@ -430,7 +430,7 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio }; run(function() { - env.store.find('post', 1).then(function(post) { + env.store.findRecord('post', 1).then(function(post) { return post.get('comments'); }).then(function(comments) { equal(comments.get('isLoaded'), true, "comments are loaded"); @@ -455,7 +455,7 @@ test("A hasMany relationship can be directly reloaded if it was fetched via ids" comments: DS.hasMany('comment', { async: true }) }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { equal(type, Post, "find type was Post"); equal(id, "1", "find id was 1"); @@ -470,7 +470,7 @@ test("A hasMany relationship can be directly reloaded if it was fetched via ids" }; run(function() { - env.store.find('post', 1).then(function(post) { + env.store.findRecord('post', 1).then(function(post) { return post.get('comments').reload().then(function(comments) { equal(comments.get('isLoaded'), true, "comments are loaded"); equal(comments.get('length'), 2, "comments have 2 length"); @@ -620,7 +620,7 @@ test("When a polymorphic hasMany relationship is accessed, the adapter's findMan }); run(function() { - env.store.find('user', 1).then(function(user) { + env.store.findRecord('user', 1).then(function(user) { var messages = user.get('messages'); equal(messages.get('length'), 2, "The messages are correctly loaded"); }); @@ -632,7 +632,7 @@ test("When a polymorphic hasMany relationship is accessed, the store can call mu messages: hasMany('message', { polymorphic: true, async: true }) }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { if (type === Post) { return Ember.RSVP.resolve({ id: 1 }); } else if (type === Comment) { @@ -645,7 +645,7 @@ test("When a polymorphic hasMany relationship is accessed, the store can call mu }); run(function() { - env.store.find('user', 1).then(function(user) { + env.store.findRecord('user', 1).then(function(user) { return user.get('messages'); }).then(function(messages) { equal(messages.get('length'), 2, "The messages are correctly loaded"); @@ -682,7 +682,7 @@ test("Type can be inferred from the key of a hasMany relationship", function() { env.store.push('contact', { id: 1 }); }); run(function() { - env.store.find('user', 1).then(function(user) { + env.store.findRecord('user', 1).then(function(user) { return user.get('contacts'); }).then(function(contacts) { equal(contacts.get('length'), 1, "The contacts relationship is correctly set up"); @@ -701,7 +701,7 @@ test("Type can be inferred from the key of an async hasMany relationship", funct env.store.push('contact', { id: 1 }); }); run(function() { - env.store.find('user', 1).then(function(user) { + env.store.findRecord('user', 1).then(function(user) { return user.get('contacts'); }).then(function(contacts) { equal(contacts.get('length'), 1, "The contacts relationship is correctly set up"); @@ -721,7 +721,7 @@ test("Polymorphic relationships work with a hasMany whose type is inferred", fun env.store.push('phone', { id: 2 }); }); run(function() { - env.store.find('user', 1).then(function(user) { + env.store.findRecord('user', 1).then(function(user) { return user.get('contacts'); }).then(function(contacts) { equal(contacts.get('length'), 2, "The contacts relationship is correctly set up"); @@ -758,7 +758,7 @@ test("A record can't be created from a polymorphic hasMany relationship", functi }); run(function() { - env.store.find('user', 1).then(function(user) { + env.store.findRecord('user', 1).then(function(user) { return user.get('messages'); }).then(function(messages) { expectAssertion(function() { @@ -777,8 +777,8 @@ test("Only records of the same type can be added to a monomorphic hasMany relati run(function() { Ember.RSVP.all([ - env.store.find('post', 1), - env.store.find('post', 2) + env.store.findRecord('post', 1), + env.store.findRecord('post', 2) ]).then(function(records) { expectAssertion(function() { records[0].get('comments').pushObject(records[1]); @@ -799,10 +799,10 @@ test("Only records of the same base type can be added to a polymorphic hasMany r run(function() { asyncRecords = Ember.RSVP.hash({ - user: env.store.find('user', 1), - anotherUser: env.store.find('user', 2), - post: env.store.find('post', 1), - comment: env.store.find('comment', 3) + user: env.store.findRecord('user', 1), + anotherUser: env.store.findRecord('user', 2), + post: env.store.findRecord('post', 1), + comment: env.store.findRecord('comment', 3) }); asyncRecords.then(function(records) { @@ -831,8 +831,8 @@ test("A record can be removed from a polymorphic association", function() { run(function() { asyncRecords = Ember.RSVP.hash({ - user: env.store.find('user', 1), - comment: env.store.find('comment', 3) + user: env.store.findRecord('user', 1), + comment: env.store.findRecord('comment', 3) }); asyncRecords.then(function(records) { @@ -986,7 +986,7 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the return resolve([{ id: 1, body: 'first' }, { id: 2, body: 'second' }]); }; - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { return resolve({ id: 3, body: 'third' }); }; var post; @@ -1307,7 +1307,7 @@ test("adding and removing records from hasMany relationship #2666", function() { run(function() { stop(); - env.store.find('post', 1).then(function (post) { + env.store.findRecord('post', 1).then(function (post) { var comments = post.get('comments'); equal(comments.get('length'), 3, "Initial comments count"); @@ -1344,12 +1344,12 @@ test("hasMany hasData async loaded", function () { pages: hasMany('pages', { async: true }) }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, title: 'The Story Begins', pages: [2, 3] }); }; run(function() { - store.find('chapter', 1).then(function(chapter) { + store.findRecord('chapter', 1).then(function(chapter) { var relationship = chapter._internalModel._relationships.get('pages'); equal(relationship.hasData, true, 'relationship has data'); }); @@ -1359,12 +1359,12 @@ test("hasMany hasData async loaded", function () { test("hasMany hasData sync loaded", function () { expect(1); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, title: 'The Story Begins', pages: [2, 3] }); }; run(function() { - store.find('chapter', 1).then(function(chapter) { + store.findRecord('chapter', 1).then(function(chapter) { var relationship = chapter._internalModel._relationships.get('pages'); equal(relationship.hasData, true, 'relationship has data'); }); @@ -1378,12 +1378,12 @@ test("hasMany hasData async not loaded", function () { pages: hasMany('pages', { async: true }) }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, title: 'The Story Begins', links: { pages: 'pages' } }); }; run(function() { - store.find('chapter', 1).then(function(chapter) { + store.findRecord('chapter', 1).then(function(chapter) { var relationship = chapter._internalModel._relationships.get('pages'); equal(relationship.hasData, false, 'relationship does not have data'); }); @@ -1393,12 +1393,12 @@ test("hasMany hasData async not loaded", function () { test("hasMany hasData sync not loaded", function () { expect(1); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, title: 'The Story Begins' }); }; run(function() { - store.find('chapter', 1).then(function(chapter) { + store.findRecord('chapter', 1).then(function(chapter) { var relationship = chapter._internalModel._relationships.get('pages'); equal(relationship.hasData, false, 'relationship does not have data'); }); diff --git a/packages/ember-data/tests/integration/relationships/one-to-one-test.js b/packages/ember-data/tests/integration/relationships/one-to-one-test.js index 57df05c02c0..9e0a0d41173 100644 --- a/packages/ember-data/tests/integration/relationships/one-to-one-test.js +++ b/packages/ember-data/tests/integration/relationships/one-to-one-test.js @@ -208,7 +208,7 @@ test("Setting a BelongsTo to a promise multiple times is resistant to race condi igor = store.push('user', { id: 3, name: "Igor", bestFriend: 5 }); newFriend = store.push('user', { id: 7, name: "New friend" }); }); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { if (id === '5') { return Ember.RSVP.resolve({ id: 5, name: "Igor's friend" }); } else if (id === '2') { diff --git a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-new-test.js b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-new-test.js index 741183b12f9..016fcb4030c 100644 --- a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-new-test.js +++ b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-new-test.js @@ -95,7 +95,7 @@ test("normalizeSingleResponse with embedded objects", function() { var json; run(function() { - json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); + json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'findRecord'); }); deepEqual(json, { @@ -160,7 +160,7 @@ test("normalizeSingleResponse with embedded objects inside embedded objects", fu var json; run(function() { - json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); + json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'findRecord'); }); deepEqual(json, { @@ -231,7 +231,7 @@ test("normalizeSingleResponse with embedded objects of same type", function() { }; var json; run(function() { - json = serializer.normalizeSingleResponse(env.store, Comment, json_hash, '1', 'find'); + json = serializer.normalizeSingleResponse(env.store, Comment, json_hash, '1', 'findRecord'); }); deepEqual(json, { @@ -304,7 +304,7 @@ test("normalizeSingleResponse with embedded objects inside embedded objects of s }; var json; run(function() { - json = serializer.normalizeSingleResponse(env.store, Comment, json_hash, '1', 'find'); + json = serializer.normalizeSingleResponse(env.store, Comment, json_hash, '1', 'findRecord'); }); deepEqual(json, { @@ -395,7 +395,7 @@ test("normalizeSingleResponse with embedded objects of same type, but from separ }; var json; run(function() { - json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'find'); + json = serializer.normalizeSingleResponse(env.store, HomePlanet, json_hash, '1', 'findRecord'); }); deepEqual(json, { @@ -883,7 +883,7 @@ test("normalizeSingleResponse with embedded object (belongsTo relationship)", fu var json; run(function() { - json = serializer.normalizeSingleResponse(env.store, SuperVillain, json_hash, '1', 'find'); + json = serializer.normalizeSingleResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); }); deepEqual(json, { @@ -959,7 +959,7 @@ test("normalizeSingleResponse with multiply-nested belongsTo", function() { var json; run(function() { - json = serializer.normalizeSingleResponse(env.store, EvilMinion, json_hash, '1', 'find'); + json = serializer.normalizeSingleResponse(env.store, EvilMinion, json_hash, '1', 'findRecord'); }); deepEqual(json, { @@ -1113,7 +1113,7 @@ test("normalizeSingleResponse with polymorphic belongsTo", function() { var json; run(function() { - json = serializer.normalizeSingleResponse(env.store, SuperVillain, json_hash, '1', 'find'); + json = serializer.normalizeSingleResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); }); deepEqual(json, { @@ -1167,7 +1167,7 @@ test("normalize with custom belongsTo primary key", function() { var json; run(function() { - json = serializer.normalizeResponse(env.store, EvilMinion, json_hash, '1', 'find'); + json = serializer.normalizeResponse(env.store, EvilMinion, json_hash, '1', 'findRecord'); }); deepEqual(json, { diff --git a/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js b/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js index 6c38fb5e8b1..1306dba9c7a 100644 --- a/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js +++ b/packages/ember-data/tests/integration/serializers/rest-serializer-new-test.js @@ -71,7 +71,7 @@ test("normalizeSingleResponse with custom modelNameFromPayloadKey", function() { var array; run(function() { - array = env.container.lookup("serializer:application").normalizeSingleResponse(env.store, HomePlanet, jsonHash, '1', 'find'); + array = env.container.lookup("serializer:application").normalizeSingleResponse(env.store, HomePlanet, jsonHash, '1', 'findRecord'); }); deepEqual(array, { @@ -171,7 +171,7 @@ test("normalizeSingleResponse warning with custom modelNameFromPayloadKey", func warns(Ember.run.bind(null, function() { run(function() { - env.restNewSerializer.normalizeSingleResponse(env.store, HomePlanet, jsonHash, '1', 'find'); + env.restNewSerializer.normalizeSingleResponse(env.store, HomePlanet, jsonHash, '1', 'findRecord'); }); }), /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); @@ -183,7 +183,8 @@ test("normalizeSingleResponse warning with custom modelNameFromPayloadKey", func noWarns(function() { run(function() { - homePlanet = env.restNewSerializer.normalizeSingleResponse(env.store, HomePlanet, jsonHash, 1, 'find'); + + homePlanet = env.restNewSerializer.normalizeSingleResponse(env.store, HomePlanet, jsonHash, 1, 'findRecord'); }); }); @@ -202,7 +203,7 @@ test("normalizeResponse can load secondary records of the same type without affe var array; run(function() { - array = env.restNewSerializer.normalizeResponse(env.store, Comment, jsonHash, '1', 'find'); + array = env.restNewSerializer.normalizeResponse(env.store, Comment, jsonHash, '1', 'findRecord'); }); deepEqual(array, { @@ -262,7 +263,7 @@ test("normalizeSingleResponse loads secondary records with correct serializer", }; run(function() { - env.restNewSerializer.normalizeSingleResponse(env.store, EvilMinion, jsonHash, '1', 'find'); + env.restNewSerializer.normalizeSingleResponse(env.store, EvilMinion, jsonHash, '1', 'findRecord'); }); equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); @@ -277,7 +278,7 @@ test("normalizeSingleResponse returns null if payload contains null", function() var value; run(function() { - value = env.restNewSerializer.normalizeSingleResponse(env.store, EvilMinion, jsonHash, null, 'find'); + value = env.restNewSerializer.normalizeSingleResponse(env.store, EvilMinion, jsonHash, null, 'findRecord'); }); deepEqual(value, { data: null, included: [] }, "returned value is null"); diff --git a/packages/ember-data/tests/integration/store-test.js b/packages/ember-data/tests/integration/store-test.js index 739086339ac..a42baae233e 100644 --- a/packages/ember-data/tests/integration/store-test.js +++ b/packages/ember-data/tests/integration/store-test.js @@ -54,7 +54,7 @@ asyncTest("destroying record during find doesn't cause error", function() { expect(0); var TestAdapter = DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return new Ember.RSVP.Promise(function(resolve, reject) { Ember.run.next(function() { store.unloadAll(type.modelName); @@ -74,7 +74,7 @@ asyncTest("destroying record during find doesn't cause error", function() { } run(function() { - store.find(type, id).then(done, done); + store.findRecord(type, id).then(done, done); }); }); @@ -82,7 +82,7 @@ asyncTest("find calls do not resolve when the store is destroyed", function() { expect(0); var TestAdapter = DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { store.destroy(); Ember.RSVP.resolve(null); } @@ -101,7 +101,7 @@ asyncTest("find calls do not resolve when the store is destroyed", function() { }; run(function() { - store.find(type, id); + store.findRecord(type, id); }); setTimeout(function() { @@ -131,7 +131,7 @@ test("destroying the store correctly cleans everything up", function() { var carWillDestroy = tap(car, 'willDestroy'); var carsWillDestroy = tap(car.get('person.cars'), 'willDestroy'); - env.adapter.findQuery = function() { + env.adapter.query = function() { return [{ id: 2, name: 'Yehuda' @@ -153,7 +153,7 @@ test("destroying the store correctly cleans everything up", function() { var adapterPopulatedPeopleWillDestroy = tap(adapterPopulatedPeople.content, 'willDestroy'); run(function() { - store.find('person', 2); + store.findRecord('person', 2); }); equal(personWillDestroy.called.length, 0, 'expected person.willDestroy to not have been called'); diff --git a/packages/ember-data/tests/unit/adapters/build-url-mixin/path-for-type-test.js b/packages/ember-data/tests/unit/adapters/build-url-mixin/path-for-type-test.js index 38ba5d212d4..a9f26119464 100644 --- a/packages/ember-data/tests/unit/adapters/build-url-mixin/path-for-type-test.js +++ b/packages/ember-data/tests/unit/adapters/build-url-mixin/path-for-type-test.js @@ -37,17 +37,17 @@ test('buildURL - works with empty paths', function() { equal(adapter.buildURL('rootModel', 1), "/1"); }); -test('buildURL - find requestType delegates to urlForFind', function() { +test('buildURL - find requestType delegates to urlForFindRecord', function() { expect(4); var snapshotStub = { snapshot: true }; - var originalMethod = adapter.urlForFind; - adapter.urlForFind = function(id, type, snapshot) { + var originalMethod = adapter.urlForFindRecord; + adapter.urlForFindRecord = function(id, type, snapshot) { equal(id, 1); equal(type, 'super-user'); equal(snapshot, snapshotStub); return originalMethod.apply(this, arguments); }; - equal(adapter.buildURL('super-user', 1, snapshotStub, 'find'), '/superUsers/1'); + equal(adapter.buildURL('super-user', 1, snapshotStub, 'findRecord'), '/superUsers/1'); }); test('buildURL - findAll requestType delegates to urlForFindAll', function() { @@ -60,16 +60,16 @@ test('buildURL - findAll requestType delegates to urlForFindAll', function() { equal(adapter.buildURL('super-user', null, null, 'findAll'), '/superUsers'); }); -test('buildURL - findQuery requestType delegates to urlForFindQuery', function() { +test('buildURL - query requestType delegates to urlForQuery', function() { expect(3); - var originalMethod = adapter.urlForFindQuery; + var originalMethod = adapter.urlForQuery; var queryStub = { limit: 10 }; - adapter.urlForFindQuery = function(query, type) { + adapter.urlForQuery = function(query, type) { equal(query, queryStub); equal(type, 'super-user'); return originalMethod.apply(this, arguments); }; - equal(adapter.buildURL('super-user', null, null, 'findQuery', queryStub), '/superUsers'); + equal(adapter.buildURL('super-user', null, null, 'query', queryStub), '/superUsers'); }); test('buildURL - findMany requestType delegates to urlForFindMany', function() { diff --git a/packages/ember-data/tests/unit/adapters/rest-adapter/ajax-test.js b/packages/ember-data/tests/unit/adapters/rest-adapter/ajax-test.js index f19931bd944..0cd1afeb1ac 100644 --- a/packages/ember-data/tests/unit/adapters/rest-adapter/ajax-test.js +++ b/packages/ember-data/tests/unit/adapters/rest-adapter/ajax-test.js @@ -28,8 +28,8 @@ test("When an id is searched, the correct url should be generated", function() { return Ember.RSVP.resolve(); }; run(function() { - adapter.find(store, Person, 1); - adapter.find(store, Place, 1); + adapter.findRecord(store, Person, 1); + adapter.findRecord(store, Place, 1); }); }); @@ -40,7 +40,7 @@ test("id's should be sanatized", function() { return Ember.RSVP.resolve(); }; run(function() { - adapter.find(store, Person, '../place/1'); + adapter.findRecord(store, Person, '../place/1'); }); }); diff --git a/packages/ember-data/tests/unit/adapters/rest-adapter/deprecated-adapter-methods.js b/packages/ember-data/tests/unit/adapters/rest-adapter/deprecated-adapter-methods.js new file mode 100644 index 00000000000..90f55bf98ae --- /dev/null +++ b/packages/ember-data/tests/unit/adapters/rest-adapter/deprecated-adapter-methods.js @@ -0,0 +1,35 @@ +var store = {}; +var type = 'post'; +var id = 1; +var snapshot = {}; + +module("unit/adapters/rest-adapter/deprecated-adapter-methods - "); + +test("`findRecord` delegates to deprecated find method if it is supplied", function() { + expect(2); + + var adapter = DS.RESTAdapter.extend({ + find: function() { + ok(true, 'overridden `find` method should be called'); + } + }).create(); + + expectDeprecation(function() { + adapter.findRecord(store, type, id, snapshot); + }, /RestAdapter#find has been deprecated and renamed to `findRecord`./); +}); + + +test("`query` delegates to deprecated findQuery method if it is supplied", function() { + expect(2); + + var adapter = DS.RESTAdapter.extend({ + findQuery: function() { + ok(true, 'overridden `findQuery` method should be called'); + } + }).create(); + + expectDeprecation(function() { + adapter.query(store, type, id, snapshot); + }, /RestAdapter#findQuery has been deprecated and renamed to `query`./); +}); diff --git a/packages/ember-data/tests/unit/model-test.js b/packages/ember-data/tests/unit/model-test.js index a1dfba3ac4b..766a0ad75fc 100644 --- a/packages/ember-data/tests/unit/model-test.js +++ b/packages/ember-data/tests/unit/model-test.js @@ -41,7 +41,7 @@ test("setting a property on a record that has not changed does not cause it to b run(function() { store.push('person', { id: 1, name: "Peter", isDrugAddict: true }); - store.find('person', 1).then(function(person) { + store.findRecord('person', 1).then(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); person.set('name', "Peter"); @@ -57,7 +57,7 @@ test("resetting a property on a record cause it to become clean again", function run(function() { store.push('person', { id: 1, name: "Peter", isDrugAddict: true }); - store.find('person', 1).then(function(person) { + store.findRecord('person', 1).then(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); person.set('isDrugAddict', false); equal(person.get('isDirty'), true, "record becomes dirty after setting property to a new value"); @@ -72,7 +72,7 @@ test("a record becomes clean again only if all changed properties are reset", fu run(function() { store.push('person', { id: 1, name: "Peter", isDrugAddict: true }); - store.find('person', 1).then(function(person) { + store.findRecord('person', 1).then(function(person) { equal(person.get('isDirty'), false, "precond - person record should not be dirty"); person.set('isDrugAddict', false); equal(person.get('isDirty'), true, "record becomes dirty after setting one property to a new value"); @@ -91,7 +91,7 @@ test("a record reports its unique id via the `id` property", function() { run(function() { store.push('person', { id: 1 }); - store.find('person', 1).then(function(record) { + store.findRecord('person', 1).then(function(record) { equal(get(record, 'id'), 1, "reports id as id by default"); }); }); @@ -102,7 +102,7 @@ test("a record's id is included in its toString representation", function() { run(function() { store.push('person', { id: 1 }); - store.find('person', 1).then(function(record) { + store.findRecord('person', 1).then(function(record) { equal(record.toString(), '<(subclass of DS.Model):'+Ember.guidFor(record)+':1>', "reports id in toString"); }); }); @@ -121,7 +121,7 @@ test("trying to set an `id` attribute should raise", function() { expectAssertion(function() { run(function() { store.push('person', { id: 1, name: "Scumdale" }); - store.find('person', 1); + store.findRecord('person', 1); }); }, /You may not set `id`/); }); @@ -136,7 +136,7 @@ test("a collision of a record's id with object function's name", function() { } run(function() { store.push('person', { id: 'watch' }); - store.find('person', 'watch').then(function(record) { + store.findRecord('person', 'watch').then(function(record) { equal(get(record, 'id'), 'watch', "record is successfully created and could be found by its id"); }); }); @@ -154,7 +154,7 @@ test("it should use `_internalModel` and not `internalModel` to store its intern run(function() { store.push('person', { id: 1 }); - store.find(Person, 1).then(function(record) { + store.findRecord(Person, 1).then(function(record) { equal(record.get('_internalModel'), undefined, "doesn't shadow internalModel key"); }); }); @@ -177,7 +177,7 @@ test("it should cache attributes", function() { run(function() { store.push('post', { id: 1 }); - store.find('post', 1).then(function(record) { + store.findRecord('post', 1).then(function(record) { run(function() { record.set('updatedAt', date); }); @@ -338,7 +338,7 @@ test("a DS.Model can update its attributes", function() { expect(1); run(function() { - store.find('person', 2).then(function(person) { + store.findRecord('person', 2).then(function(person) { set(person, 'name', "Brohuda Katz"); equal(get(person, 'name'), "Brohuda Katz", "setting took hold"); }); @@ -469,7 +469,7 @@ test("setting a property back to its original value removes the property from th expect(3); run(function() { - store.find('person', 1).then(function(person) { + store.findRecord('person', 1).then(function(person) { equal(person._internalModel._attributes.name, undefined, "the `_attributes` hash is clean"); set(person, 'name', "Niceguy Dale"); @@ -601,7 +601,7 @@ var converts = function(type, provided, expected) { run(function() { testStore.push('model', serializer.normalize(Model, { id: 1, name: provided })); testStore.push('model', serializer.normalize(Model, { id: 2 })); - testStore.find('model', 1).then(function(record) { + testStore.findRecord('model', 1).then(function(record) { deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); }); }); @@ -633,7 +633,7 @@ var convertsFromServer = function(type, provided, expected) { run(function() { testStore.push('model', serializer.normalize(Model, { id: "1", name: provided })); - testStore.find('model', 1).then(function(record) { + testStore.findRecord('model', 1).then(function(record) { deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); }); }); @@ -648,7 +648,7 @@ var convertsWhenSet = function(type, provided, expected) { run(function() { testStore.push('model', { id: 2 }); - testStore.find('model', 2).then(function(record) { + testStore.findRecord('model', 2).then(function(record) { set(record, 'name', provided); deepEqual(record.serialize().name, expected, type + " saves " + provided + " as " + expected); }); @@ -712,7 +712,7 @@ test("a DS.Model can describe Date attributes", function() { run(function() { store.push('person', { id: 1 }); - store.find('person', 1).then(function(record) { + store.findRecord('person', 1).then(function(record) { run(function() { record.set('updatedAt', date); }); @@ -747,7 +747,7 @@ test("ensure model exits loading state, materializes data and fulfills promise o var store = createStore({ adapter: DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "John" }); } }), @@ -755,7 +755,7 @@ test("ensure model exits loading state, materializes data and fulfills promise o }); run(function() { - store.find('person', 1).then(function(person) { + store.findRecord('person', 1).then(function(person) { equal(get(person, 'currentState.stateName'), 'root.loaded.saved', 'model is in loaded state'); equal(get(person, 'isLoaded'), true, 'model is loaded'); }); diff --git a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js index b8c3f08ab30..b747a14a5ae 100644 --- a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js +++ b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js @@ -14,7 +14,7 @@ test("a record receives a didLoad callback when it has finished loading", functi }); var adapter = DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Foo" }); } }); @@ -25,7 +25,7 @@ test("a record receives a didLoad callback when it has finished loading", functi }); run(function() { - store.find('person', 1).then(function(person) { + store.findRecord('person', 1).then(function(person) { equal(person.get('id'), "1", "The person's ID is available"); equal(person.get('name'), "Foo", "The person's properties are available"); }); @@ -75,7 +75,7 @@ test("a record receives a didUpdate callback when it has finished updating", fun }); var adapter = DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Foo" }); }, @@ -93,7 +93,7 @@ test("a record receives a didUpdate callback when it has finished updating", fun var asyncPerson; run(function() { - asyncPerson = store.find('person', 1); + asyncPerson = store.findRecord('person', 1); }); equal(callCount, 0, "precond - didUpdate callback was not called yet"); @@ -168,7 +168,7 @@ test("a record receives a didDelete callback when it has finished deleting", fun }); var adapter = DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Foo" }); }, @@ -186,7 +186,7 @@ test("a record receives a didDelete callback when it has finished deleting", fun var asyncPerson; run(function() { - asyncPerson = store.find('person', 1); + asyncPerson = store.findRecord('person', 1); }); equal(callCount, 0, "precond - didDelete callback was not called yet"); @@ -256,7 +256,7 @@ test("a record receives a becameInvalid callback when it became invalid", functi }); var adapter = DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Foo" }); }, @@ -274,7 +274,7 @@ test("a record receives a becameInvalid callback when it became invalid", functi var asyncPerson; run(function() { - asyncPerson = store.find('person', 1); + asyncPerson = store.findRecord('person', 1); }); equal(callCount, 0, "precond - becameInvalid callback was not called yet"); diff --git a/packages/ember-data/tests/unit/model/merge-test.js b/packages/ember-data/tests/unit/model/merge-test.js index b768d54c3ca..89e89640874 100644 --- a/packages/ember-data/tests/unit/model/merge-test.js +++ b/packages/ember-data/tests/unit/model/merge-test.js @@ -204,7 +204,7 @@ test("A dirty record can be reloaded", function() { expect(3); var adapter = DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Thomas Dale", city: "Portland" }); } }); diff --git a/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js b/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js index ebdfb7810b7..ebbef9fd9ac 100644 --- a/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js +++ b/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js @@ -27,14 +27,14 @@ test("belongsTo lazily loads relationships as needed", function() { }); run(function() { - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); equal(get(person, 'tag.name'), "friendly", "the tag shuld have name"); strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); - asyncEqual(get(person, 'tag'), store.find('tag', 5), "relationship object is the same as object retrieved directly"); + asyncEqual(get(person, 'tag'), store.findRecord('tag', 5), "relationship object is the same as object retrieved directly"); })); }); }); @@ -54,7 +54,7 @@ test("async belongsTo relationships work when the data hash has not been loaded" var env = setupStore({ tag: Tag, person: Person }); var store = env.store; - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { if (type === Person) { equal(id, 1, "id should be 1"); @@ -67,7 +67,7 @@ test("async belongsTo relationships work when the data hash has not been loaded" }; run(function() { - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return run(function() { @@ -101,7 +101,7 @@ test("async belongsTo relationships work when the data hash has already been loa }); run(function() { - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return run(function() { return get(person, 'tag'); @@ -134,7 +134,7 @@ test("calling createRecord and passing in an undefined value for a relationship }); run(function() { - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { strictEqual(person.get('tag'), null, "undefined values should return null relationships"); })); }); @@ -170,7 +170,7 @@ test("When finding a hasMany relationship the inverse belongsTo relationship is }); run(function() { - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { equal(get(person, 'isLoaded'), true, "isLoaded should be true"); equal(get(person, 'name'), "Tom Dale", "the person is still Tom Dale"); @@ -204,7 +204,7 @@ test("When finding a belongsTo relationship the inverse belongsTo relationship i var env = setupStore({ occupation: Occupation, person: Person }); var store = env.store; - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { equal(snapshot.belongsTo('person').id, '1'); return Ember.RSVP.resolve({ id: 5, description: "fifth" }); }; @@ -242,14 +242,14 @@ test("belongsTo supports relationships to models with id 0", function() { }); run(function() { - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); equal(get(person, 'tag.name'), "friendly", "the tag should have name"); strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); - asyncEqual(get(person, 'tag'), store.find('tag', 0), "relationship object is the same as object retrieved directly"); + asyncEqual(get(person, 'tag'), store.findRecord('tag', 0), "relationship object is the same as object retrieved directly"); })); }); }); diff --git a/packages/ember-data/tests/unit/model/relationships/has-many-test.js b/packages/ember-data/tests/unit/model/relationships/has-many-test.js index be32afe7331..2fd01eff317 100644 --- a/packages/ember-data/tests/unit/model/relationships/has-many-test.js +++ b/packages/ember-data/tests/unit/model/relationships/has-many-test.js @@ -31,11 +31,11 @@ test("hasMany handles pre-loaded relationships", function() { env.registry.register('model:pet', Pet); env.registry.register('model:person', Person); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { if (type === Tag && id === '12') { return Ember.RSVP.resolve({ id: 12, name: "oohlala" }); } else { - ok(false, "find() should not be called with these values"); + ok(false, "findRecord() should not be called with these values"); } }; @@ -49,7 +49,7 @@ test("hasMany handles pre-loaded relationships", function() { }); run(function() { - store.find('person', 1).then(function(person) { + store.findRecord('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); var tags = get(person, 'tags'); @@ -64,20 +64,20 @@ test("hasMany handles pre-loaded relationships", function() { equal(get(get(person, 'tags'), 'length'), 2, "the length is updated after new data is loaded"); strictEqual(get(person, 'tags').objectAt(0), get(person, 'tags').objectAt(0), "the returned object is always the same"); - asyncEqual(get(person, 'tags').objectAt(0), store.find('tag', 5), "relationship objects are the same as objects retrieved directly"); + asyncEqual(get(person, 'tags').objectAt(0), store.findRecord('tag', 5), "relationship objects are the same as objects retrieved directly"); run(function() { store.push('person', { id: 3, name: "KSelden" }); }); - return store.find('person', 3); + return store.findRecord('person', 3); }).then(function(kselden) { equal(get(get(kselden, 'tags'), 'length'), 0, "a relationship that has not been supplied returns an empty array"); run(function() { store.push('person', { id: 4, name: "Cyvid Hamluck", pets: [4] }); }); - return store.find('person', 4); + return store.findRecord('person', 4); }).then(function(cyvid) { equal(get(cyvid, 'name'), "Cyvid Hamluck", "precond - retrieves person record from store"); @@ -118,11 +118,11 @@ test("hasMany lazily loads async relationships", function() { env.registry.register('model:pet', Pet); env.registry.register('model:person', Person); - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { if (type === Tag && id === '12') { return Ember.RSVP.resolve({ id: 12, name: "oohlala" }); } else { - ok(false, "find() should not be called with these values"); + ok(false, "findRecord() should not be called with these values"); } }; @@ -138,7 +138,7 @@ test("hasMany lazily loads async relationships", function() { var wycats; run(function() { - store.find('person', 2).then(function(person) { + store.findRecord('person', 2).then(function(person) { wycats = person; equal(get(wycats, 'name'), "Yehuda Katz", "precond - retrieves person record from store"); @@ -152,7 +152,7 @@ test("hasMany lazily loads async relationships", function() { equal(get(records.tags.objectAt(0), 'name'), "oohlala", "the first tag should be a Tag"); strictEqual(records.tags.objectAt(0), records.tags.objectAt(0), "the returned object is always the same"); - asyncEqual(records.tags.objectAt(0), store.find('tag', 12), "relationship objects are the same as objects retrieved directly"); + asyncEqual(records.tags.objectAt(0), store.findRecord('tag', 12), "relationship objects are the same as objects retrieved directly"); return get(wycats, 'tags'); }).then(function(tags) { @@ -252,7 +252,7 @@ test("relationships work when declared with a string path", function() { }); run(function() { - env.store.find('person', 1).then(function(person) { + env.store.findRecord('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); equal(get(person, 'tags.length'), 2, "the list of tags should have the correct length"); }); @@ -287,7 +287,7 @@ test("hasMany relationships work when the data hash has not been loaded", functi return Ember.RSVP.resolve([{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); }; - env.adapter.find = function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { equal(type, Person, "type should be Person"); equal(id, 1, "id should be 1"); @@ -295,7 +295,7 @@ test("hasMany relationships work when the data hash has not been loaded", functi }; run(function() { - store.find('person', 1).then(function(person) { + store.findRecord('person', 1).then(function(person) { equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return run(function() { @@ -335,7 +335,7 @@ test("it is possible to add a new item to a relationship", function() { }); run(function() { - store.find('person', 1).then(function(person) { + store.findRecord('person', 1).then(function(person) { var tag = get(person, 'tags').objectAt(0); equal(get(tag, 'name'), "ember", "precond - relationships work"); @@ -407,7 +407,7 @@ test("it is possible to remove an item from a relationship", function() { }); run(function() { - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { var tag = get(person, 'tags').objectAt(0); equal(get(tag, 'name'), "ember", "precond - relationships work"); diff --git a/packages/ember-data/tests/unit/model/relationships/record-array-test.js b/packages/ember-data/tests/unit/model/relationships/record-array-test.js index be273c2a158..334b8e17244 100644 --- a/packages/ember-data/tests/unit/model/relationships/record-array-test.js +++ b/packages/ember-data/tests/unit/model/relationships/record-array-test.js @@ -51,7 +51,7 @@ test("can create child record from a hasMany relationship", function() { }); run(function() { - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { person.get("tags").createRecord({ name: "cool" }); equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); diff --git a/packages/ember-data/tests/unit/record-array-test.js b/packages/ember-data/tests/unit/record-array-test.js index 05f3fe5c1de..a75c0688cbd 100644 --- a/packages/ember-data/tests/unit/record-array-test.js +++ b/packages/ember-data/tests/unit/record-array-test.js @@ -103,8 +103,8 @@ test("a loaded record is removed from a record array when it is deleted", functi run(function() { var asyncRecords = Ember.RSVP.hash({ - scumbag: store.find('person', 1), - tag: store.find('tag', 1) + scumbag: store.findRecord('person', 1), + tag: store.findRecord('tag', 1) }); asyncRecords.then(function(records) { @@ -258,7 +258,7 @@ test("an AdapterPopulatedRecordArray knows if it's loaded or not", function() { var env = setupStore({ person: Person }); var store = env.store; - env.adapter.findQuery = function(store, type, query, recordArray) { + env.adapter.query = function(store, type, query, recordArray) { return Ember.RSVP.resolve(array); }; diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index dee040455cd..582eaabc560 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -40,7 +40,7 @@ test("Calling Store#find invokes its adapter#find", function() { expect(5); var adapter = TestAdapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { ok(true, "Adapter#find was called"); equal(store, currentStore, "Adapter#find was called with the right store"); equal(type, store.modelFor('test'), "Adapter#find was called with the type passed into Store#find"); @@ -56,7 +56,7 @@ test("Calling Store#find invokes its adapter#find", function() { run(function() { - currentStore.find('test', 1); + currentStore.findRecord('test', 1); }); }); @@ -64,8 +64,8 @@ test("Calling Store#findRecord multiple times coalesces the calls into a adapter expect(2); var adapter = TestAdapter.extend({ - find: function(store, type, id, snapshot) { - ok(false, "Adapter#find was not called"); + findRecord: function(store, type, id, snapshot) { + ok(false, "Adapter#findRecord was not called"); }, findMany: function(store, type, ids, snapshots) { start(); @@ -81,16 +81,16 @@ test("Calling Store#findRecord multiple times coalesces the calls into a adapter stop(); run(function() { - currentStore.find('test', 1); - currentStore.find('test', 2); + currentStore.findRecord('test', 1); + currentStore.findRecord('test', 2); }); }); -test("Returning a promise from `find` asynchronously loads data", function() { +test("Returning a promise from `findRecord` asynchronously loads data", function() { expect(1); var adapter = TestAdapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return resolve({ id: 1, name: "Scumbag Dale" }); } }); @@ -101,7 +101,7 @@ test("Returning a promise from `find` asynchronously loads data", function() { var currentStore = createStore({ adapter: adapter, test: currentType }); run(function() { - currentStore.find('test', 1).then(async(function(object) { + currentStore.findRecord('test', 1).then(async(function(object) { strictEqual(get(object, 'name'), "Scumbag Dale", "the data was pushed"); })); }); @@ -111,7 +111,7 @@ test("IDs provided as numbers are coerced to strings", function() { expect(4); var adapter = TestAdapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { equal(typeof id, 'string', "id has been normalized to a string"); return resolve({ id: 1, name: "Scumbag Sylvain" }); } @@ -123,12 +123,12 @@ test("IDs provided as numbers are coerced to strings", function() { var currentStore = createStore({ adapter: adapter, test: currentType }); run(function() { - currentStore.find('test', 1).then(async(function(object) { + currentStore.findRecord('test', 1).then(async(function(object) { equal(typeof object.get('id'), 'string', "id was coerced to a string"); run(function() { currentStore.push('test', { id: 2, name: "Scumbag Sam Saffron" }); }); - return currentStore.find('test', 2); + return currentStore.findRecord('test', 2); })).then(async(function(object) { ok(object, "object was found"); equal(typeof object.get('id'), 'string', "id is a string despite being supplied and searched for as a number"); @@ -153,7 +153,7 @@ test("can load data for the same record if it is not dirty", function() { run(function() { store.push('person', { id: 1, name: "Tom Dale" }); - store.find('person', 1).then(async(function(tom) { + store.findRecord('person', 1).then(async(function(tom) { equal(get(tom, 'isDirty'), false, "precond - record is not dirty"); equal(get(tom, 'name'), "Tom Dale", "returns the correct name"); @@ -170,7 +170,7 @@ test("DS.Store loads individual records without explicit IDs with a custom prima store.load(Person, { key: 1, name: "Tom Dale" }); - var tom = store.find(Person, 1); + var tom = store.findRecord(Person, 1); equal(get(tom, 'name'), "Tom Dale", "the person was successfully loaded for the given ID"); }); */ @@ -186,7 +186,7 @@ test("pushMany extracts ids from an Array of hashes if no ids are specified", fu run(function() { store.pushMany('person', array); - store.find('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(async(function(person) { equal(get(person, 'name'), "Scumbag Dale", "correctly extracted id for loaded data"); })); }); @@ -202,7 +202,7 @@ test("loadMany takes an optional Object and passes it on to the Adapter", functi }); var adapter = TestAdapter.extend({ - findQuery: function(store, type, query) { + query: function(store, type, query) { equal(type, store.modelFor('person'), 'The type was Person'); equal(query, passedQuery, "The query was passed in"); return Ember.RSVP.resolve([]); @@ -227,7 +227,7 @@ test("Find with query calls the correct extract", function() { }); var adapter = TestAdapter.extend({ - findQuery: function(store, type, query) { + query: function(store, type, query) { return Ember.RSVP.resolve([]); } }); @@ -252,7 +252,7 @@ test("Find with query calls the correct extract", function() { run(function() { store.query('person', passedQuery); }); - equal(callCount, 1, 'extractFindQuery was called'); + equal(callCount, 1, 'extractQuery was called'); }); test("peekAll(type) returns a record array of all records of a specific type", function() { @@ -365,7 +365,7 @@ test("if an id is supplied in the initial data hash, it can be looked up using ` run(function() { person = store.createRecord('person', { id: 1, name: "Brohuda Katz" }); - store.find('person', 1).then(async(function(again) { + store.findRecord('person', 1).then(async(function(again) { strictEqual(person, again, "the store returns the loaded object"); })); }); @@ -375,7 +375,7 @@ test("initial values of attributes can be passed in as the third argument to fin expect(1); var adapter = TestAdapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { equal(snapshot.attr('name'), 'Test', 'Preloaded attribtue set'); return Ember.RSVP.resolve({ id: '1', name: 'Test' }); } @@ -391,14 +391,14 @@ test("initial values of attributes can be passed in as the third argument to fin }); run(function() { - store.find('test', 1, { preload: { name: 'Test' } }); + store.findRecord('test', 1, { preload: { name: 'Test' } }); }); }); test("initial values of belongsTo can be passed in as the third argument to find as records", function() { expect(1); var adapter = TestAdapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { equal(snapshot.belongsTo('friend').attr('name'), 'Tom', 'Preloaded belongsTo set'); return new Ember.RSVP.Promise(function() {}); } @@ -419,7 +419,7 @@ test("initial values of belongsTo can be passed in as the third argument to find run(function() { tom = store.push('person', { id: 2, name: 'Tom' }); - store.find('person', 1, { preload: { friend: tom } }); + store.findRecord('person', 1, { preload: { friend: tom } }); }); }); @@ -427,7 +427,7 @@ test("initial values of belongsTo can be passed in as the third argument to find expect(1); var adapter = TestAdapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return Ember.RSVP.Promise.resolve({ id: id }); } }); @@ -445,7 +445,7 @@ test("initial values of belongsTo can be passed in as the third argument to find env.registry.register('model:person', Person); run(function() { - store.find('person', 1, { preload: { friend: 2 } }).then(async(function() { + store.findRecord('person', 1, { preload: { friend: 2 } }).then(async(function() { store.peekRecord('person', 1).get('friend').then(async(function(friend) { equal(friend.get('id'), '2', 'Preloaded belongsTo set'); })); @@ -456,7 +456,7 @@ test("initial values of belongsTo can be passed in as the third argument to find test("initial values of hasMany can be passed in as the third argument to find as records", function() { expect(1); var adapter = TestAdapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { equal(snapshot.hasMany('friends')[0].attr('name'), 'Tom', 'Preloaded hasMany set'); return new Ember.RSVP.Promise(function() {}); } @@ -477,7 +477,7 @@ test("initial values of hasMany can be passed in as the third argument to find a run(function() { tom = store.push('person', { id: 2, name: 'Tom' }); - store.find('person', 1, { preload: { friends: [tom] } }); + store.findRecord('person', 1, { preload: { friends: [tom] } }); }); }); @@ -485,7 +485,7 @@ test("initial values of hasMany can be passed in as the third argument to find a expect(1); var adapter = TestAdapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { equal(snapshot.hasMany('friends')[0].id, '2', 'Preloaded hasMany set'); return Ember.RSVP.resolve({ id: id }); } @@ -504,7 +504,7 @@ test("initial values of hasMany can be passed in as the third argument to find a env.registry.register('model:person', Person); run(function() { - store.find('person', 1, { preload: { friends: [2] } }); + store.findRecord('person', 1, { preload: { friends: [2] } }); }); }); @@ -576,7 +576,7 @@ test("store.scheduleFetchMany should not resolve until all the records are resol var Phone = DS.Model.extend(); var adapter = TestAdapter.extend({ - find: function (store, type, id, snapshot) { + findRecord: function (store, type, id, snapshot) { var wait = 5; var record = { id: id }; @@ -640,7 +640,7 @@ test("the store calls adapter.findMany according to groupings returned by adapte ]; }, - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { equal(id, "10", "The first group is passed to find"); return Ember.RSVP.resolve({ id: id }); }, @@ -691,7 +691,7 @@ test("the promise returned by `scheduleFetch`, when it resolves, does not depend ]; }, - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { var record = { id: id }; return new Ember.RSVP.Promise(function(resolve, reject) { @@ -713,8 +713,8 @@ test("the promise returned by `scheduleFetch`, when it resolves, does not depend }); run(function () { - var davidPromise = store.find('test', 'david'); - var igorPromise = store.find('test', 'igor'); + var davidPromise = store.findRecord('test', 'david'); + var igorPromise = store.findRecord('test', 'igor'); igorPromise.then(async(function () { equal(davidResolved, false, "Igor did not need to wait for David"); @@ -740,7 +740,7 @@ test("the promise returned by `scheduleFetch`, when it rejects, does not depend ]; }, - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { var record = { id: id }; return new Ember.RSVP.Promise(function(resolve, reject) { @@ -762,8 +762,8 @@ test("the promise returned by `scheduleFetch`, when it rejects, does not depend }); run(function () { - var davidPromise = store.find('test', 'david'); - var igorPromise = store.find('test', 'igor'); + var davidPromise = store.findRecord('test', 'david'); + var igorPromise = store.findRecord('test', 'igor'); igorPromise.then(null, async(function () { equal(davidResolved, false, "Igor did not need to wait for David"); @@ -801,8 +801,8 @@ test("store.fetchRecord reject records that were not found, even when those requ warns(function() { run(function () { - var davidPromise = store.find('test', 'david'); - var igorPromise = store.find('test', 'igor'); + var davidPromise = store.findRecord('test', 'david'); + var igorPromise = store.findRecord('test', 'igor'); davidPromise.then(async(function () { ok(true, "David resolved"); @@ -1205,7 +1205,7 @@ module("unit/store/adapter_interop - find preload deprecations", { }); var TestAdapter = DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { equal(snapshot.attr('name'), 'Tom'); return Ember.RSVP.resolve({ id: id }); } diff --git a/packages/ember-data/tests/unit/store/push-test.js b/packages/ember-data/tests/unit/store/push-test.js index 9f107182c43..e430681ab74 100644 --- a/packages/ember-data/tests/unit/store/push-test.js +++ b/packages/ember-data/tests/unit/store/push-test.js @@ -57,8 +57,8 @@ test("Calling push with a normalized hash returns a record", function() { firstName: "Yehuda", lastName: "Katz" }); - store.find('person', 'wat').then(function(foundPerson) { - equal(foundPerson, person, "record returned via load() is the same as the record returned from find()"); + store.findRecord('person', 'wat').then(function(foundPerson) { + equal(foundPerson, person, "record returned via load() is the same as the record returned from findRecord()"); deepEqual(foundPerson.getProperties('id', 'firstName', 'lastName'), { id: 'wat', firstName: "Yehuda", @@ -81,7 +81,7 @@ test("Supplying a model class for `push` is the same as supplying a string", fun lastName: "Katz" }); - store.find('programmer', 'wat').then(function(foundProgrammer) { + store.findRecord('programmer', 'wat').then(function(foundProgrammer) { deepEqual(foundProgrammer.getProperties('id', 'firstName', 'lastName'), { id: 'wat', firstName: "Yehuda", @@ -132,8 +132,8 @@ test("Calling push with partial records updates just those attributes", function lastName: "Katz!" }); - store.find('person', 'wat').then(function(foundPerson) { - equal(foundPerson, person, "record returned via load() is the same as the record returned from find()"); + store.findRecord('person', 'wat').then(function(foundPerson) { + equal(foundPerson, person, "record returned via load() is the same as the record returned from findRecord()"); deepEqual(foundPerson.getProperties('id', 'firstName', 'lastName'), { id: 'wat', firstName: "Yehuda", @@ -198,7 +198,7 @@ test("Calling push with a normalized hash containing IDs of related records retu phoneNumbers: hasMany('phone-number', { async: true }) }); - env.adapter.find = function(store, type, id) { + env.adapter.findRecord = function(store, type, id) { if (id === "1") { return Ember.RSVP.resolve({ id: 1, diff --git a/packages/ember-data/tests/unit/store/unload-test.js b/packages/ember-data/tests/unit/store/unload-test.js index a3c95a2ff8b..56ba2a3e456 100644 --- a/packages/ember-data/tests/unit/store/unload-test.js +++ b/packages/ember-data/tests/unit/store/unload-test.js @@ -11,7 +11,7 @@ module("unit/store/unload - Store unloading records", { }); store = createStore({ adapter: DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { tryToFind = true; return Ember.RSVP.resolve({ id: id, wasFetched: true }); } @@ -34,7 +34,7 @@ test("unload a dirty record", function() { title: 'toto' }); - store.find('record', 1).then(function(record) { + store.findRecord('record', 1).then(function(record) { record.set('title', 'toto2'); record._internalModel.send('willCommit'); @@ -57,7 +57,7 @@ test("unload a record", function() { run(function() { store.push('record', { id: 1, title: 'toto' }); - store.find('record', 1).then(function(record) { + store.findRecord('record', 1).then(function(record) { equal(get(record, 'id'), 1, "found record with id 1"); equal(get(record, 'isDirty'), false, "record is not dirty"); @@ -69,7 +69,7 @@ test("unload a record", function() { equal(get(record, 'isDeleted'), true, "record is deleted"); tryToFind = false; - return store.find('record', 1).then(function() { + return store.findRecord('record', 1).then(function() { equal(tryToFind, true, "not found record with id 1"); }); }); @@ -99,7 +99,7 @@ test("can commit store after unload record with relationships", function() { var store = createStore({ adapter: DS.Adapter.extend({ - find: function(store, type, id, snapshot) { + findRecord: function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, description: 'cuisinart', brand: 1 }); }, createRecord: function(store, type, snapshot) { @@ -116,8 +116,8 @@ test("can commit store after unload record with relationships", function() { store.push('brand', { id: 1, name: 'EmberJS' }); store.push('product', { id: 1, description: 'toto', brand: 1 }); asyncRecords = Ember.RSVP.hash({ - brand: store.find('brand', 1), - product: store.find('product', 1) + brand: store.findRecord('brand', 1), + product: store.findRecord('product', 1) }); asyncRecords.then(function(records) { like = store.createRecord('like', { id: 1, product: product }); @@ -125,9 +125,9 @@ test("can commit store after unload record with relationships", function() { return Ember.RSVP.hash(records); }).then(function(records) { store.unloadRecord(records.product); - return store.find('product', 1); + return store.findRecord('product', 1); }).then(function(product) { - equal(product.get('description'), 'cuisinart', "The record was unloaded and the adapter's `find` was called"); + equal(product.get('description'), 'cuisinart', "The record was unloaded and the adapter's `findRecord` was called"); store.destroy(); }); }); From a2c264eaf9d9f225d58e2eb524147bcfe1ef6eec Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 15 Jun 2015 17:28:23 -0400 Subject: [PATCH 0954/2527] Deprecate store.push(type, data) --- packages/ember-data/lib/system/store.js | 1 + packages/ember-data/tests/unit/store/push-test.js | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 3d1a577a8c3..26287f87a14 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1794,6 +1794,7 @@ Store = Service.extend({ } Ember.assert("Expected an object as `data` in a call to `push` for " + modelName + " , but was " + Ember.typeOf(data), Ember.typeOf(data) === 'object'); Ember.assert("You must include an `id` for " + modelName + " in an object passed to `push`", data.id != null && data.id !== ''); + Ember.deprecate('store.push(type, data) has been deprecated. Please provide a JSON-API document object as the first and only argument to store.push.'); var type = this.modelFor(modelName); var filter = Ember.EnumerableUtils.filter; diff --git a/packages/ember-data/tests/unit/store/push-test.js b/packages/ember-data/tests/unit/store/push-test.js index 9f107182c43..15292822ef1 100644 --- a/packages/ember-data/tests/unit/store/push-test.js +++ b/packages/ember-data/tests/unit/store/push-test.js @@ -596,3 +596,15 @@ test("Calling pushMany is deprecated", function() { }); }, 'Using store.pushMany() has been deprecated since store.push() now handles multiple items. You should use store.push() instead.'); }); + + +test("Calling push(type, data) is deprecated", function() { + var person1; + expectDeprecation(function() { + run(function() { + person1 = { id: 1, firstName: 'John', lastName: 'Smith' }; + + store.push('person', person1); + }); + }, /store.push\(type, data\) has been deprecated/); +}); From 5493b0d366170cf8db6dd7415de3485af977c2fd Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 15 Jun 2015 18:27:25 -0400 Subject: [PATCH 0955/2527] Deprecate isDirty in favor of Model#hasDirtyAttributes --- .../lib/system/debug/debug-adapter.js | 8 ++-- .../ember-data/lib/system/debug/debug-info.js | 2 +- .../lib/system/model/internal-model.js | 2 +- packages/ember-data/lib/system/model/model.js | 32 +++++++++++++- .../adapter/record-persistence-test.js | 10 ++--- .../integration/adapter/rest-adapter-test.js | 24 +++++------ .../integration/adapter/store-adapter-test.js | 42 +++++++++---------- .../tests/integration/filter-test.js | 4 +- packages/ember-data/tests/unit/model-test.js | 40 +++++++++++++----- .../unit/model/lifecycle-callbacks-test.js | 10 ++--- .../ember-data/tests/unit/model/merge-test.js | 16 +++---- .../unit/model/rollback-attributes-test.js | 16 +++---- .../tests/unit/model/rollback-test.js | 2 +- .../tests/unit/store/adapter-interop-test.js | 6 +-- .../tests/unit/store/unload-test.js | 6 +-- 15 files changed, 135 insertions(+), 85 deletions(-) diff --git a/packages/ember-data/lib/system/debug/debug-adapter.js b/packages/ember-data/lib/system/debug/debug-adapter.js index ae5e01a022a..5f6661cd5e0 100644 --- a/packages/ember-data/lib/system/debug/debug-adapter.js +++ b/packages/ember-data/lib/system/debug/debug-adapter.js @@ -88,8 +88,8 @@ export default Ember.DataAdapter.extend({ getRecordFilterValues: function(record) { return { isNew: record.get('isNew'), - isModified: record.get('isDirty') && !record.get('isNew'), - isClean: !record.get('isDirty') + isModified: record.get('hasDirtyAttributes') && !record.get('isNew'), + isClean: !record.get('hasDirtyAttributes') }; }, @@ -97,7 +97,7 @@ export default Ember.DataAdapter.extend({ var color = 'black'; if (record.get('isNew')) { color = 'green'; - } else if (record.get('isDirty')) { + } else if (record.get('hasDirtyAttributes')) { color = 'blue'; } return color; @@ -106,7 +106,7 @@ export default Ember.DataAdapter.extend({ observeRecord: function(record, recordUpdated) { var releaseMethods = Ember.A(); var self = this; - var keysToObserve = Ember.A(['id', 'isNew', 'isDirty']); + var keysToObserve = Ember.A(['id', 'isNew', 'hasDirtyAttributes']); record.eachAttribute(function(key) { keysToObserve.push(key); diff --git a/packages/ember-data/lib/system/debug/debug-info.js b/packages/ember-data/lib/system/debug/debug-info.js index 9c55026896b..a5bf7533050 100644 --- a/packages/ember-data/lib/system/debug/debug-info.js +++ b/packages/ember-data/lib/system/debug/debug-info.js @@ -50,7 +50,7 @@ Model.reopen({ }, { name: 'Flags', - properties: ['isLoaded', 'isDirty', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'] + properties: ['isLoaded', 'hasDirtyAttributes', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'] } ]; diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js index 0f33c5c2187..7ce82189d3f 100644 --- a/packages/ember-data/lib/system/model/internal-model.js +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -97,7 +97,7 @@ InternalModel.prototype = { isEmpty: retrieveFromCurrentState('isEmpty'), isLoading: retrieveFromCurrentState('isLoading'), isLoaded: retrieveFromCurrentState('isLoaded'), - isDirty: retrieveFromCurrentState('isDirty'), + hasDirtyAttributes: retrieveFromCurrentState('hasDirtyAttributes'), isSaving: retrieveFromCurrentState('isSaving'), isDeleted: retrieveFromCurrentState('isDeleted'), isNew: retrieveFromCurrentState('isNew'), diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 99f8cb1423c..7eb14548f2d 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -103,8 +103,38 @@ var Model = Ember.Object.extend(Ember.Evented, { @property isDirty @type {Boolean} @readOnly + @deprecated */ - isDirty: retrieveFromCurrentState, + isDirty: Ember.computed('currentState.isDirty', function() { + Ember.deprecate('DS.Model#isDirty has been deprecated please use hasDirtyAttributes instead'); + return this.get('currentState.isDirty'); + }), + /** + If this property is `true` the record is in the `dirty` state. The + record has local changes that have not yet been saved by the + adapter. This includes records that have been created (but not yet + saved) or deleted. + + Example + + ```javascript + var record = store.createRecord('model'); + record.get('hasDirtyAttributes'); // true + + store.find('model', 1).then(function(model) { + model.get('hasDirtyAttributes'); // false + model.set('foo', 'some value'); + model.get('hasDirtyAttributes'); // true + }); + ``` + + @property hasDirtyAttributes + @type {Boolean} + @readOnly + */ + hasDirtyAttributes: Ember.computed('currentState.isDirty', function() { + return this.get('currentState.isDirty'); + }), /** If this property is `true` the record is in the `saving` state. A record enters the saving state when `save` is called, but the diff --git a/packages/ember-data/tests/integration/adapter/record-persistence-test.js b/packages/ember-data/tests/integration/adapter/record-persistence-test.js index eb72ce7c515..d9a18ce30cf 100644 --- a/packages/ember-data/tests/integration/adapter/record-persistence-test.js +++ b/packages/ember-data/tests/integration/adapter/record-persistence-test.js @@ -9,7 +9,7 @@ var hash = Ember.RSVP.hash; function assertClean(promise) { return promise.then(async(function(record) { - equal(record.get('isDirty'), false, "The record is now clean"); + equal(record.get('hasDirtyAttributes'), false, "The record is now clean"); return record; })); } @@ -134,8 +134,8 @@ test("An adapter can notify the store that records were updated by calling `didS tom.set('name', "Michael Phelps"); yehuda.set('name', "Usain Bolt"); - ok(tom.get('isDirty'), "tom is dirty"); - ok(yehuda.get('isDirty'), "yehuda is dirty"); + ok(tom.get('hasDirtyAttributes'), "tom is dirty"); + ok(yehuda.get('hasDirtyAttributes'), "yehuda is dirty"); assertClean(tom.save()).then(async(function(record) { equal(record, tom, "The record is correct"); @@ -188,8 +188,8 @@ test("An adapter can notify the store that a record was updated by calling `didS people.tom.set('name', "Tom Dale"); people.yehuda.set('name', "Yehuda Katz"); - ok(people.tom.get('isDirty'), "tom is dirty"); - ok(people.yehuda.get('isDirty'), "yehuda is dirty"); + ok(people.tom.get('hasDirtyAttributes'), "tom is dirty"); + ok(people.yehuda.get('hasDirtyAttributes'), "yehuda is dirty"); assertClean(people.tom.save()); assertClean(people.yehuda.save()); diff --git a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js b/packages/ember-data/tests/integration/adapter/rest-adapter-test.js index 664f97fe314..a2fc39db53a 100644 --- a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js +++ b/packages/ember-data/tests/integration/adapter/rest-adapter-test.js @@ -179,7 +179,7 @@ test("create - an empty payload is a basic success if an id was specified", func equal(passedVerb, "POST"); deepEqual(passedHash.data, { post: { id: "some-uuid", name: "The Parley Letter" } }); - equal(post.get('isDirty'), false, "the post isn't dirty anymore"); + equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); equal(post.get('name'), "The Parley Letter", "the post was updated"); })); }); @@ -212,7 +212,7 @@ test("create - a payload with a new ID and data applies the updates", function() deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); equal(post.get('id'), "1", "the post has the updated ID"); - equal(post.get('isDirty'), false, "the post isn't dirty anymore"); + equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); equal(post.get('name'), "Dat Parley Letter", "the post was updated"); })); }); @@ -231,7 +231,7 @@ test("create - a payload with a new ID and data applies the updates (with legacy deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); equal(post.get('id'), "1", "the post has the updated ID"); - equal(post.get('isDirty'), false, "the post isn't dirty anymore"); + equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); equal(post.get('name'), "Dat Parley Letter", "the post was updated"); })); }); @@ -257,7 +257,7 @@ test("create - findMany doesn't overwrite owner", function() { run(function() { comment.save().then(async(function(comment) { - equal(comment.get('isDirty'), false, "the post isn't dirty anymore"); + equal(comment.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); equal(comment.get('name'), "Dat Parley Letter", "the post was updated"); equal(comment.get('post'), post, "the post is still set"); })); @@ -537,7 +537,7 @@ test("update - an empty payload is a basic success", function() { equal(passedVerb, "PUT"); deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); - equal(post.get('isDirty'), false, "the post isn't dirty anymore"); + equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); equal(post.get('name'), "The Parley Letter", "the post was updated"); })); }); @@ -576,7 +576,7 @@ test("update - a payload with updates applies the updates", function() { equal(passedVerb, "PUT"); deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); - equal(post.get('isDirty'), false, "the post isn't dirty anymore"); + equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); equal(post.get('name'), "Dat Parley Letter", "the post was updated"); })); }); @@ -596,7 +596,7 @@ test("update - a payload with updates applies the updates (with legacy singular equal(passedVerb, "PUT"); deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); - equal(post.get('isDirty'), false, "the post isn't dirty anymore"); + equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); equal(post.get('name'), "Dat Parley Letter", "the post was updated"); })); }); @@ -615,7 +615,7 @@ test("update - a payload with sideloaded updates pushes the updates", function() deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); equal(post.get('id'), "1", "the post has the updated ID"); - equal(post.get('isDirty'), false, "the post isn't dirty anymore"); + equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); equal(post.get('name'), "Dat Parley Letter", "the post was updated"); var comment = store.peekRecord('comment', 1); @@ -642,7 +642,7 @@ test("update - a payload with sideloaded updates pushes the updates", function() equal(passedVerb, "PUT"); deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); - equal(post.get('isDirty'), false, "the post isn't dirty anymore"); + equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); equal(post.get('name'), "Dat Parley Letter", "the post was updated"); var comment = store.peekRecord('comment', 1); @@ -718,7 +718,7 @@ test("delete - an empty payload is a basic success", function() { equal(passedVerb, "DELETE"); equal(passedHash, undefined); - equal(post.get('isDirty'), false, "the post isn't dirty anymore"); + equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); equal(post.get('isDeleted'), true, "the post is now deleted"); })); }); @@ -757,7 +757,7 @@ test("delete - a payload with sideloaded updates pushes the updates", function() equal(passedVerb, "DELETE"); equal(passedHash, undefined); - equal(post.get('isDirty'), false, "the post isn't dirty anymore"); + equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); equal(post.get('isDeleted'), true, "the post is now deleted"); var comment = store.peekRecord('comment', 1); @@ -780,7 +780,7 @@ test("delete - a payload with sidloaded updates pushes the updates when the orig equal(passedVerb, "DELETE"); equal(passedHash, undefined); - equal(post.get('isDirty'), false, "the original post isn't dirty anymore"); + equal(post.get('hasDirtyAttributes'), false, "the original post isn't dirty anymore"); equal(post.get('isDeleted'), true, "the original post is now deleted"); var newPost = store.peekRecord('post', 2); diff --git a/packages/ember-data/tests/integration/adapter/store-adapter-test.js b/packages/ember-data/tests/integration/adapter/store-adapter-test.js index 8af0faba42c..442c5e6f741 100644 --- a/packages/ember-data/tests/integration/adapter/store-adapter-test.js +++ b/packages/ember-data/tests/integration/adapter/store-adapter-test.js @@ -206,10 +206,10 @@ test("calling store.didSaveRecord can provide an optional hash", function() { var tom = records.tom; var yehuda = records.yehuda; - equal(get(tom, 'isDirty'), false, "the record should not be dirty"); + equal(get(tom, 'hasDirtyAttributes'), false, "the record should not be dirty"); equal(get(tom, 'updatedAt'), "now", "the hash was updated"); - equal(get(yehuda, 'isDirty'), false, "the record should not be dirty"); + equal(get(yehuda, 'hasDirtyAttributes'), false, "the record should not be dirty"); equal(get(yehuda, 'updatedAt'), "now!", "the hash was updated"); })); }); @@ -327,12 +327,12 @@ test("if an existing model is edited then deleted, deleteRecord is called on the run(store, 'findRecord', 'person', 'deleted-record').then(async(function(tom) { tom.set('name', "Tom Mothereffin' Dale"); - equal(get(tom, 'isDirty'), true, "precond - record should be dirty after editing"); + equal(get(tom, 'hasDirtyAttributes'), true, "precond - record should be dirty after editing"); tom.deleteRecord(); return tom.save(); })).then(async(function(tom) { - equal(get(tom, 'isDirty'), false, "record should not be dirty"); + equal(get(tom, 'hasDirtyAttributes'), false, "record should not be dirty"); equal(get(tom, 'isDeleted'), true, "record should be considered deleted"); })); }); @@ -397,7 +397,7 @@ test("if a created record is marked as invalid by the server, it enters an error set(yehuda, 'name', "Brohuda Brokatz"); equal(get(yehuda, 'isValid'), true, "the record is no longer invalid after changing"); - equal(get(yehuda, 'isDirty'), true, "the record has outstanding changes"); + equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); equal(get(yehuda, 'isNew'), true, "precond - record is still new"); @@ -438,7 +438,7 @@ test("allows errors on arbitrary properties on create", function() { set(yehuda, 'name', "Brohuda Brokatz"); equal(get(yehuda, 'isValid'), false, "the record is still invalid as far as we know"); - equal(get(yehuda, 'isDirty'), true, "the record has outstanding changes"); + equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); equal(get(yehuda, 'isNew'), true, "precond - record is still new"); @@ -477,7 +477,7 @@ test("if a created record is marked as invalid by the server, you can attempt th equal(saveCount, 1, "The record has been saved once"); ok(reason.message.match("The backend rejected the commit because it was invalid"), "It should fail due to being invalid"); equal(get(yehuda, 'isValid'), false, "the record is invalid"); - equal(get(yehuda, 'isDirty'), true, "the record has outstanding changes"); + equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); ok(get(yehuda, 'errors.name'), "The errors.name property exists"); equal(get(yehuda, 'isNew'), true, "precond - record is still new"); return yehuda.save(); @@ -485,7 +485,7 @@ test("if a created record is marked as invalid by the server, you can attempt th equal(saveCount, 2, "The record has been saved twice"); ok(reason.message.match("The backend rejected the commit because it was invalid"), "It should fail due to being invalid"); equal(get(yehuda, 'isValid'), false, "the record is still invalid"); - equal(get(yehuda, 'isDirty'), true, "the record has outstanding changes"); + equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); ok(get(yehuda, 'errors.name'), "The errors.name property exists"); equal(get(yehuda, 'isNew'), true, "precond - record is still new"); set(yehuda, 'name', 'Brohuda Brokatz'); @@ -493,7 +493,7 @@ test("if a created record is marked as invalid by the server, you can attempt th })).then(async(function(person) { equal(saveCount, 3, "The record has been saved thrice"); equal(get(yehuda, 'isValid'), true, "record is valid"); - equal(get(yehuda, 'isDirty'), false, "record is not dirty"); + equal(get(yehuda, 'hasDirtyAttributes'), false, "record is not dirty"); equal(get(yehuda, 'errors.isEmpty'), true, "record has no errors"); })); }); @@ -536,11 +536,11 @@ test("if an updated record is marked as invalid by the server, it enters an erro set(yehuda, 'name', "Yehuda Katz"); equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); - equal(get(yehuda, 'isDirty'), true, "the record is dirty"); + equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); return yehuda.save(); })).then(null, async(function(reason) { - equal(get(yehuda, 'isDirty'), true, "the record is still dirty"); + equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); equal(get(yehuda, 'isValid'), false, "the record is invalid"); set(yehuda, 'updatedAt', true); @@ -548,12 +548,12 @@ test("if an updated record is marked as invalid by the server, it enters an erro set(yehuda, 'name', "Brohuda Brokatz"); equal(get(yehuda, 'isValid'), true, "the record is no longer invalid after changing"); - equal(get(yehuda, 'isDirty'), true, "the record has outstanding changes"); + equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); return yehuda.save(); })).then(async(function(yehuda) { equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); - equal(get(yehuda, 'isDirty'), false, "record is no longer new"); + equal(get(yehuda, 'hasDirtyAttributes'), false, "record is no longer new"); })); }); }); @@ -580,11 +580,11 @@ test("records can have errors on arbitrary properties after update", function() set(yehuda, 'name', "Yehuda Katz"); equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); - equal(get(yehuda, 'isDirty'), true, "the record is dirty"); + equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); return yehuda.save(); })).then(null, async(function(reason) { - equal(get(yehuda, 'isDirty'), true, "the record is still dirty"); + equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); equal(get(yehuda, 'isValid'), false, "the record is invalid"); ok(get(yehuda, 'errors.base'), "The errors.base property exists"); deepEqual(get(yehuda, 'errors').errorsFor('base'), [{ attribute: 'base', message: "is a generally unsavoury character" }]); @@ -594,12 +594,12 @@ test("records can have errors on arbitrary properties after update", function() set(yehuda, 'name', "Brohuda Brokatz"); equal(get(yehuda, 'isValid'), false, "the record is still invalid after changing (only server can know if it's now valid)"); - equal(get(yehuda, 'isDirty'), true, "the record has outstanding changes"); + equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); return yehuda.save(); })).then(async(function(yehuda) { equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); - equal(get(yehuda, 'isDirty'), false, "record is no longer new"); + equal(get(yehuda, 'hasDirtyAttributes'), false, "record is no longer new"); ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); deepEqual(get(yehuda, 'errors').errorsFor('base'), []); })); @@ -632,26 +632,26 @@ test("if an updated record is marked as invalid by the server, you can attempt t set(yehuda, 'name', "Yehuda Katz"); equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); - equal(get(yehuda, 'isDirty'), true, "the record is dirty"); + equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); return yehuda.save(); })).then(null, async(function(reason) { equal(saveCount, 1, "The record has been saved once"); ok(reason.message.match("The backend rejected the commit because it was invalid"), "It should fail due to being invalid"); - equal(get(yehuda, 'isDirty'), true, "the record is still dirty"); + equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); equal(get(yehuda, 'isValid'), false, "the record is invalid"); return yehuda.save(); })).then(null, async(function(reason) { equal(saveCount, 2, "The record has been saved twice"); ok(reason.message.match("The backend rejected the commit because it was invalid"), "It should fail due to being invalid"); equal(get(yehuda, 'isValid'), false, "record is still invalid"); - equal(get(yehuda, 'isDirty'), true, "record is still dirty"); + equal(get(yehuda, 'hasDirtyAttributes'), true, "record is still dirty"); set(yehuda, 'name', 'Brohuda Brokatz'); return yehuda.save(); })).then(async(function(person) { equal(saveCount, 3, "The record has been saved thrice"); equal(get(yehuda, 'isValid'), true, "record is valid"); - equal(get(yehuda, 'isDirty'), false, "record is not dirty"); + equal(get(yehuda, 'hasDirtyAttributes'), false, "record is not dirty"); equal(get(yehuda, 'errors.isEmpty'), true, "record has no errors"); })); }); diff --git a/packages/ember-data/tests/integration/filter-test.js b/packages/ember-data/tests/integration/filter-test.js index 2ab10cf9a47..8f7c9bbc2b0 100644 --- a/packages/ember-data/tests/integration/filter-test.js +++ b/packages/ember-data/tests/integration/filter-test.js @@ -430,7 +430,7 @@ test("it is possible to filter loaded records by dirtiness", function() { })); var filter = store.filter('person', function(person) { - return !person.get('isDirty'); + return !person.get('hasDirtyAttributes'); }); run(function() { @@ -467,7 +467,7 @@ test("it is possible to filter created records by dirtiness", function() { run(function() { filter = store.filter('person', function(person) { - return !person.get('isDirty'); + return !person.get('hasDirtyAttributes'); }); }); diff --git a/packages/ember-data/tests/unit/model-test.js b/packages/ember-data/tests/unit/model-test.js index 766a0ad75fc..e0dc55a1d17 100644 --- a/packages/ember-data/tests/unit/model-test.js +++ b/packages/ember-data/tests/unit/model-test.js @@ -42,12 +42,12 @@ test("setting a property on a record that has not changed does not cause it to b run(function() { store.push('person', { id: 1, name: "Peter", isDrugAddict: true }); store.findRecord('person', 1).then(function(person) { - equal(person.get('isDirty'), false, "precond - person record should not be dirty"); + equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); person.set('name', "Peter"); person.set('isDrugAddict', true); - equal(person.get('isDirty'), false, "record does not become dirty after setting property to old value"); + equal(person.get('hasDirtyAttributes'), false, "record does not become dirty after setting property to old value"); }); }); }); @@ -58,11 +58,11 @@ test("resetting a property on a record cause it to become clean again", function run(function() { store.push('person', { id: 1, name: "Peter", isDrugAddict: true }); store.findRecord('person', 1).then(function(person) { - equal(person.get('isDirty'), false, "precond - person record should not be dirty"); + equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); person.set('isDrugAddict', false); - equal(person.get('isDirty'), true, "record becomes dirty after setting property to a new value"); + equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting property to a new value"); person.set('isDrugAddict', true); - equal(person.get('isDirty'), false, "record becomes clean after resetting property to the old value"); + equal(person.get('hasDirtyAttributes'), false, "record becomes clean after resetting property to the old value"); }); }); }); @@ -73,15 +73,15 @@ test("a record becomes clean again only if all changed properties are reset", fu run(function() { store.push('person', { id: 1, name: "Peter", isDrugAddict: true }); store.findRecord('person', 1).then(function(person) { - equal(person.get('isDirty'), false, "precond - person record should not be dirty"); + equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); person.set('isDrugAddict', false); - equal(person.get('isDirty'), true, "record becomes dirty after setting one property to a new value"); + equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting one property to a new value"); person.set('name', 'Mark'); - equal(person.get('isDirty'), true, "record stays dirty after setting another property to a new value"); + equal(person.get('hasDirtyAttributes'), true, "record stays dirty after setting another property to a new value"); person.set('isDrugAddict', true); - equal(person.get('isDirty'), true, "record stays dirty after resetting only one property to the old value"); + equal(person.get('hasDirtyAttributes'), true, "record stays dirty after resetting only one property to the old value"); person.set('name', 'Peter'); - equal(person.get('isDirty'), false, "record becomes clean after resetting both properties to the old value"); + equal(person.get('hasDirtyAttributes'), false, "record becomes clean after resetting both properties to the old value"); }); }); }); @@ -901,3 +901,23 @@ test('accessing attributes in the initializer should not throw an error', functi run(() => store.createRecord('person')); }); + + +test('isDirty should log a deprecation warning', function() { + expect(1); + var Person = DS.Model.extend({ + name: DS.attr('string') + }); + + var env = setupStore({ + person: Person + }); + var store = env.store; + + run(function() { + var person = store.createRecord('person'); + expectDeprecation(function() { + person.get('isDirty'); + }, /DS.Model#isDirty has been deprecated/); + }); +}); diff --git a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js index b747a14a5ae..5620b6f7e53 100644 --- a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js +++ b/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js @@ -70,7 +70,7 @@ test("a record receives a didUpdate callback when it has finished updating", fun didUpdate: function() { callCount++; equal(get(this, 'isSaving'), false, "record should be saving"); - equal(get(this, 'isDirty'), false, "record should not be dirty"); + equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); } }); @@ -118,7 +118,7 @@ test("a record receives a didCreate callback when it has finished updating", fun didCreate: function() { callCount++; equal(get(this, 'isSaving'), false, "record should not be saving"); - equal(get(this, 'isDirty'), false, "record should not be dirty"); + equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); } }); @@ -163,7 +163,7 @@ test("a record receives a didDelete callback when it has finished deleting", fun callCount++; equal(get(this, 'isSaving'), false, "record should not be saving"); - equal(get(this, 'isDirty'), false, "record should not be dirty"); + equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); } }); @@ -215,7 +215,7 @@ test("an uncommited record also receives a didDelete callback when it is deleted didDelete: function() { callCount++; equal(get(this, 'isSaving'), false, "record should not be saving"); - equal(get(this, 'isDirty'), false, "record should not be dirty"); + equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); } }); @@ -251,7 +251,7 @@ test("a record receives a becameInvalid callback when it became invalid", functi callCount++; equal(get(this, 'isSaving'), false, "record should not be saving"); - equal(get(this, 'isDirty'), true, "record should be dirty"); + equal(get(this, 'hasDirtyAttributes'), true, "record should be dirty"); } }); diff --git a/packages/ember-data/tests/unit/model/merge-test.js b/packages/ember-data/tests/unit/model/merge-test.js index 89e89640874..e5b9b4d35f4 100644 --- a/packages/ember-data/tests/unit/model/merge-test.js +++ b/packages/ember-data/tests/unit/model/merge-test.js @@ -37,7 +37,7 @@ test("When a record is in flight, changes can be made", function() { person.set('name', "Thomas Dale"); promise.then(function(person) { - equal(person.get('isDirty'), true, "The person is still dirty"); + equal(person.get('hasDirtyAttributes'), true, "The person is still dirty"); equal(person.get('name'), "Thomas Dale", "The changes made still apply"); }); }); @@ -72,7 +72,7 @@ test("Make sure snapshot is created at save time not at flush time", function() equal(person.get('name'), "Tomasz Dale", "the local changes applied on top"); promise.then(async(function(person) { - equal(person.get('isDirty'), true, "The person is still dirty"); + equal(person.get('hasDirtyAttributes'), true, "The person is still dirty"); equal(person.get('name'), "Tomasz Dale", "The local changes apply"); })); }); @@ -114,7 +114,7 @@ test("When a record is in flight, pushes are applied underneath the in flight ch equal(person.get('city'), "PDX", "the pushed change is available"); promise.then(async(function(person) { - equal(person.get('isDirty'), true, "The person is still dirty"); + equal(person.get('hasDirtyAttributes'), true, "The person is still dirty"); equal(person.get('name'), "Tomasz Dale", "The local changes apply"); equal(person.get('city'), "Portland", "The updates from the server apply on top of the previous pushes"); })); @@ -133,7 +133,7 @@ test("When a record is dirty, pushes are overridden by local changes", function( person.set('name', "Tomasz Dale"); }); - equal(person.get('isDirty'), true, "the person is currently dirty"); + equal(person.get('hasDirtyAttributes'), true, "the person is currently dirty"); equal(person.get('name'), "Tomasz Dale", "the update was effective"); equal(person.get('city'), "San Francisco", "the original data applies"); @@ -141,7 +141,7 @@ test("When a record is dirty, pushes are overridden by local changes", function( store.push('person', { id: 1, name: "Thomas Dale", city: "Portland" }); }); - equal(person.get('isDirty'), true, "the local changes are reapplied"); + equal(person.get('hasDirtyAttributes'), true, "the local changes are reapplied"); equal(person.get('name'), "Tomasz Dale", "the local changes are reapplied"); equal(person.get('city'), "Portland", "if there are no local changes, the new data applied"); }); @@ -159,7 +159,7 @@ test("When a record is invalid, pushes are overridden by local changes", functio person.send('becameInvalid'); }); - equal(person.get('isDirty'), true, "the person is currently dirty"); + equal(person.get('hasDirtyAttributes'), true, "the person is currently dirty"); equal(person.get('isValid'), false, "the person is currently invalid"); equal(person.get('name'), "Brondan McLoughlin", "the update was effective"); equal(person.get('city'), "Boston", "the original data applies"); @@ -168,7 +168,7 @@ test("When a record is invalid, pushes are overridden by local changes", functio store.push('person', { id: 1, name: "bmac", city: "Prague" }); }); - equal(person.get('isDirty'), true, "the local changes are reapplied"); + equal(person.get('hasDirtyAttributes'), true, "the local changes are reapplied"); equal(person.get('isValid'), false, "record is still invalid"); equal(person.get('name'), "Brondan McLoughlin", "the local changes are reapplied"); equal(person.get('city'), "Prague", "if there are no local changes, the new data applied"); @@ -222,7 +222,7 @@ test("A dirty record can be reloaded", function() { run(function() { person.reload().then(function() { - equal(person.get('isDirty'), true, "the person is dirty"); + equal(person.get('hasDirtyAttributes'), true, "the person is dirty"); equal(person.get('name'), "Tomasz Dale", "the local changes remain"); equal(person.get('city'), "Portland", "the new changes apply"); }); diff --git a/packages/ember-data/tests/unit/model/rollback-attributes-test.js b/packages/ember-data/tests/unit/model/rollback-attributes-test.js index 4f979dc28be..461b915befc 100644 --- a/packages/ember-data/tests/unit/model/rollback-attributes-test.js +++ b/packages/ember-data/tests/unit/model/rollback-attributes-test.js @@ -27,7 +27,7 @@ test("changes to attributes can be rolled back", function() { }); equal(person.get('firstName'), "Tom"); - equal(person.get('isDirty'), false); + equal(person.get('hasDirtyAttributes'), false); }); test("changes to unassigned attributes can be rolled back", function() { @@ -44,7 +44,7 @@ test("changes to unassigned attributes can be rolled back", function() { }); equal(person.get('firstName'), undefined); - equal(person.get('isDirty'), false); + equal(person.get('hasDirtyAttributes'), false); }); test("changes to attributes made after a record is in-flight only rolls back the local changes", function() { @@ -77,7 +77,7 @@ test("changes to attributes made after a record is in-flight only rolls back the equal(person.get('isSaving'), true); saving.then(async(function() { - equal(person.get('isDirty'), false, "The person is now clean"); + equal(person.get('hasDirtyAttributes'), false, "The person is now clean"); })); }); }); @@ -150,12 +150,12 @@ test("new record's attributes can be rollbacked", function() { }); equal(person.get('isNew'), true, "must be new"); - equal(person.get('isDirty'), true, "must be dirty"); + equal(person.get('hasDirtyAttributes'), true, "must be dirty"); Ember.run(person, 'rollbackAttributes'); equal(person.get('isNew'), false, "must not be new"); - equal(person.get('isDirty'), false, "must not be dirty"); + equal(person.get('hasDirtyAttributes'), false, "must not be dirty"); equal(person.get('isDeleted'), true, "must be deleted"); }); @@ -190,7 +190,7 @@ test("invalid new record's attributes can be rollbacked", function() { }); equal(person.get('isNew'), true, "must be new"); - equal(person.get('isDirty'), true, "must be dirty"); + equal(person.get('hasDirtyAttributes'), true, "must be dirty"); run(function() { person.save().then(null, async(function() { @@ -198,7 +198,7 @@ test("invalid new record's attributes can be rollbacked", function() { person.rollbackAttributes(); equal(person.get('isNew'), false, "must not be new"); - equal(person.get('isDirty'), false, "must not be dirty"); + equal(person.get('hasDirtyAttributes'), false, "must not be dirty"); equal(person.get('isDeleted'), true, "must be deleted"); })); }); @@ -223,7 +223,7 @@ test("deleted record's attributes can be rollbacked", function() { }); equal(people.get('length'), 1, "the rollbacked record should appear again in the record array"); equal(person.get('isDeleted'), false, "must not be deleted"); - equal(person.get('isDirty'), false, "must not be dirty"); + equal(person.get('hasDirtyAttributes'), false, "must not be dirty"); }); test("invalid record's attributes can be rollbacked", function() { diff --git a/packages/ember-data/tests/unit/model/rollback-test.js b/packages/ember-data/tests/unit/model/rollback-test.js index 8e1b98ec73e..0514539d925 100644 --- a/packages/ember-data/tests/unit/model/rollback-test.js +++ b/packages/ember-data/tests/unit/model/rollback-test.js @@ -32,5 +32,5 @@ test("changes to attributes can be rolled back - deprecated", function() { ); equal(person.get('firstName'), 'Tom'); - equal(person.get('isDirty'), false); + equal(person.get('hasDirtyAttributes'), false); }); diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index 582eaabc560..f7a132c55cb 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -154,7 +154,7 @@ test("can load data for the same record if it is not dirty", function() { store.push('person', { id: 1, name: "Tom Dale" }); store.findRecord('person', 1).then(async(function(tom) { - equal(get(tom, 'isDirty'), false, "precond - record is not dirty"); + equal(get(tom, 'hasDirtyAttributes'), false, "precond - record is not dirty"); equal(get(tom, 'name'), "Tom Dale", "returns the correct name"); store.push('person', { id: 1, name: "Captain Underpants" }); @@ -297,7 +297,7 @@ test("a new record of a particular type is created via store.createRecord(type)" equal(get(person, 'isLoaded'), true, "A newly created record is loaded"); equal(get(person, 'isNew'), true, "A newly created record is new"); - equal(get(person, 'isDirty'), true, "A newly created record is dirty"); + equal(get(person, 'hasDirtyAttributes'), true, "A newly created record is dirty"); run(function() { set(person, 'name', "Braaahm Dale"); @@ -347,7 +347,7 @@ test("an initial data hash can be provided via store.createRecord(type, hash)", equal(get(person, 'isLoaded'), true, "A newly created record is loaded"); equal(get(person, 'isNew'), true, "A newly created record is new"); - equal(get(person, 'isDirty'), true, "A newly created record is dirty"); + equal(get(person, 'hasDirtyAttributes'), true, "A newly created record is dirty"); equal(get(person, 'name'), "Brohuda Katz", "The initial data hash is provided"); }); diff --git a/packages/ember-data/tests/unit/store/unload-test.js b/packages/ember-data/tests/unit/store/unload-test.js index 56ba2a3e456..e2e3444d7d8 100644 --- a/packages/ember-data/tests/unit/store/unload-test.js +++ b/packages/ember-data/tests/unit/store/unload-test.js @@ -38,7 +38,7 @@ test("unload a dirty record", function() { record.set('title', 'toto2'); record._internalModel.send('willCommit'); - equal(get(record, 'isDirty'), true, "record is dirty"); + equal(get(record, 'hasDirtyAttributes'), true, "record is dirty"); expectAssertion(function() { record.unloadRecord(); @@ -59,13 +59,13 @@ test("unload a record", function() { store.push('record', { id: 1, title: 'toto' }); store.findRecord('record', 1).then(function(record) { equal(get(record, 'id'), 1, "found record with id 1"); - equal(get(record, 'isDirty'), false, "record is not dirty"); + equal(get(record, 'hasDirtyAttributes'), false, "record is not dirty"); run(function() { store.unloadRecord(record); }); - equal(get(record, 'isDirty'), false, "record is not dirty"); + equal(get(record, 'hasDirtyAttributes'), false, "record is not dirty"); equal(get(record, 'isDeleted'), true, "record is deleted"); tryToFind = false; From a458ebcf1e8e41e2a922d5716e0bc7d8188e8c8f Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 15 Jun 2015 18:39:48 -0400 Subject: [PATCH 0956/2527] Remove the logic to always fetch all the records the first time. This will be moved into `shouldReloadAll` in Ember Data 2.0 --- packages/ember-data/lib/system/adapter.js | 3 +- .../lib/system/snapshot-record-array.js | 1 + packages/ember-data/lib/system/store.js | 5 --- .../tests/unit/store/adapter-interop-test.js | 34 ------------------- 4 files changed, 3 insertions(+), 40 deletions(-) diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 9e23956cc8b..c17b1d29b9a 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -484,7 +484,8 @@ var Adapter = Ember.Object.extend({ @return {Boolean} */ shouldReloadAll: function(store, snapshotRecordArray) { - Ember.deprecate('The default behavior of `shouldBackgroundReloadAll` will change in Ember Data 2.0 to always return false. If you would like to preserve the current behavior please override `shouldReloadAll` in you adapter:application and return true.'); + var modelName = snapshotRecordArray.type.modelName; + Ember.deprecate(`The default behavior of shouldBackgroundReloadAll will change in Ember Data 2.0 to always return false when there is at least one "${modelName}" record in the store. If you would like to preserve the current behavior please override shouldReloadAll in you adapter:application and return true.`); return true; }, diff --git a/packages/ember-data/lib/system/snapshot-record-array.js b/packages/ember-data/lib/system/snapshot-record-array.js index f5ad544f936..071f2d53a38 100644 --- a/packages/ember-data/lib/system/snapshot-record-array.js +++ b/packages/ember-data/lib/system/snapshot-record-array.js @@ -14,6 +14,7 @@ function SnapshotRecordArray(recordArray, meta, adapterOptions) { this._snapshots = null; this._recordArray = recordArray; this.length = recordArray.get('length'); + this.type = recordArray.get('type'); this.meta = meta; this.adapterOptions = adapterOptions; } diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 72abc47ce0c..46edeca0010 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1154,11 +1154,6 @@ Store = Service.extend({ Ember.assert("You tried to load all records but you have no adapter (for " + typeClass + ")", adapter); Ember.assert("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function'); - if (!get(array, '__isLoaded')) { - var arrayPromise = promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); - arrayPromise.then(() => set(array, '__isLoaded', true)); - return arrayPromise; - } if (options.reload) { return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); } diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index 582eaabc560..1a94d8205ee 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -1000,35 +1000,6 @@ test("store should reload the record in the background when `shouldBackgroundRel equal(store.peekRecord('person', 1).get('name'), 'Tom'); }); - -test("store should not call shouldReloadAll when the recordArary is not loaded", function() { - expect(1); - - var Person = DS.Model.extend({ - name: DS.attr('string') - }); - - var TestAdapter = DS.Adapter.extend({ - shouldReloadAll: function(store, type, id, snapshot) { - ok(false, 'shouldReloadRecord should not be called when the record is not loaded'); - return false; - }, - findAll: function() { - ok(true, 'find is always called when the record is not in the store'); - return [{ id: 1 }]; - } - }); - - store = createStore({ - adapter: TestAdapter, - person: Person - }); - - run(function() { - store.findAll('person'); - }); -}); - test("store should not reload record array when shouldReloadAll returns false", function() { expect(1); @@ -1055,7 +1026,6 @@ test("store should not reload record array when shouldReloadAll returns false", }); run(function() { - store.peekAll('person').set('__isLoaded', true); store.find('person'); }); }); @@ -1084,7 +1054,6 @@ test("store should reload all records when shouldReloadAll returns true", functi }); run(function() { - store.peekAll('person').set('__isLoaded', true); store.findAll('person').then(function(records) { equal(records.get('firstObject.name'), 'Tom'); }); @@ -1117,7 +1086,6 @@ test("store should not call shouldBackgroundReloadAll when the store is already }); run(function() { - store.peekAll('person').set('__isLoaded', true); store.findAll('person').then(function(records) { equal(records.get('firstObject.name'), 'Tom'); }); @@ -1152,7 +1120,6 @@ test("store should not reload all records when `shouldBackgroundReloadAll` is fa }); run(function() { - store.peekAll('person').set('__isLoaded', true); store.findAll('person').then(function(records) { equal(records.get('firstObject'), undefined); }); @@ -1188,7 +1155,6 @@ test("store should reload all records in the background when `shouldBackgroundRe }); run(function() { - store.peekAll('person').set('__isLoaded', true); store.findAll('person').then(function(records) { equal(records.get('firstObject.name'), undefined); }); From 07cf7a9a19a0e72309b176027bc02ef288733785 Mon Sep 17 00:00:00 2001 From: Tom Coquereau Date: Sun, 14 Jun 2015 23:33:27 +0200 Subject: [PATCH 0957/2527] Add new normalizeQueryRecordResponse --- .../lib/serializers/json-serializer.js | 15 ++++++++ .../integration/store/query-record-test.js | 35 ++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index cecde55c1d9..25662860605 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -233,6 +233,8 @@ var JSONSerializer = Serializer.extend({ switch (requestType) { case 'findRecord': return this.normalizeFindRecordResponse(...arguments); + case 'queryRecord': + return this.normalizeQueryRecordResponse(...arguments); case 'findAll': return this.normalizeFindAllResponse(...arguments); case 'findBelongsTo': @@ -265,6 +267,19 @@ var JSONSerializer = Serializer.extend({ return this.normalizeSingleResponse(...arguments); }, + /* + @method normalizeQueryRecordResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeQueryRecordResponse: function(store, primaryModelClass, payload, id, requestType) { + return this.normalizeSingleResponse(...arguments); + }, + /* @method normalizeFindAllResponse @param {DS.Store} store diff --git a/packages/ember-data/tests/integration/store/query-record-test.js b/packages/ember-data/tests/integration/store/query-record-test.js index e1eb5792db7..1baea0255e6 100644 --- a/packages/ember-data/tests/integration/store/query-record-test.js +++ b/packages/ember-data/tests/integration/store/query-record-test.js @@ -1,4 +1,4 @@ -var Person, store, env; +var Person, store, env, TestSerializer; var run = Ember.run; module("integration/store/query-record - Query one record with a query hash", { @@ -14,6 +14,10 @@ module("integration/store/query-record - Query one record with a query hash", { person: Person }); store = env.store; + + TestSerializer = DS.JSONAPISerializer.extend({ + isNewSerializerAPI: true + }); }, teardown: function() { @@ -61,3 +65,32 @@ test("When a record is requested, and the promise is rejected, .queryRecord() is })); }); }); + +test("When a record is requested, the serializer's normalizeQueryRecordResponse method should be called.", function() { + expect(1); + + env.registry.register('serializer:person', TestSerializer.extend({ + normalizeQueryRecordResponse: function(store, primaryModelClass, payload, id, requestType) { + equal(payload.data.id , '1', "the normalizeQueryRecordResponse method was called with the right payload"); + return this._super(...arguments); + } + })); + + env.registry.register('adapter:person', DS.Adapter.extend({ + queryRecord: function(store, type, query) { + return Ember.RSVP.resolve({ + data: { + id: '1', + type: 'person', + attributes: { + name: "Peter Wagenet" + } + } + }); + } + })); + + run(function() { + store.queryRecord('person', { related: 'posts' }); + }); +}); From 8ecb37b18813463318b8c8a83b22908b6982b8c6 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Tue, 16 Jun 2015 01:08:17 +0200 Subject: [PATCH 0958/2527] Add deprecation for default RESTAdapter --- .../lib/system/store/container-instance-cache.js | 4 ++++ .../ember-data/tests/unit/store/adapter-interop-test.js | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/packages/ember-data/lib/system/store/container-instance-cache.js b/packages/ember-data/lib/system/store/container-instance-cache.js index e9f81501885..5fbb9c90be6 100644 --- a/packages/ember-data/lib/system/store/container-instance-cache.js +++ b/packages/ember-data/lib/system/store/container-instance-cache.js @@ -55,6 +55,10 @@ Ember.merge(ContainerInstanceCache.prototype, { }, instanceFor: function(key) { + if (key === 'adapter:-rest') { + Ember.deprecate('You are currently using the default DS.RESTAdapter adapter. For Ember 2.0 the default adapter will be DS.JSONAPIAdapter. If you would like to continue using DS.RESTAdapter please create an application adapter that extends DS.RESTAdapter.'); + } + let cache = this._cache; if (!cache[key]) { let instance = this._container.lookup(key); diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/packages/ember-data/tests/unit/store/adapter-interop-test.js index 244befa8091..be0f794054f 100644 --- a/packages/ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/ember-data/tests/unit/store/adapter-interop-test.js @@ -27,6 +27,14 @@ test('Adapter can be set as a name', function() { ok(store.get('defaultAdapter') instanceof DS.RESTAdapter); }); +test('Default RESTAdapter has been deprecated', function() { + expectDeprecation(function() { + run(function() { + store = createStore({ adapter: '-rest' }); + }); + }, /You are currently using the default DS.RESTAdapter adapter. For Ember 2.0 the default adapter will be DS.JSONAPIAdapter. If you would like to continue using DS.RESTAdapter please create an application adapter that extends DS.RESTAdapter./); +}); + test('Adapter can not be set as an instance', function() { expect(1); From 67d0b12536e083054507733b69a6fc98bace77d6 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 15 Jun 2015 12:54:14 -0400 Subject: [PATCH 0959/2527] Replace Ember.EnumerableUtils with Ember.ArrayPollyfills. Ember.EnumerableUtils is deprecated. Ember.ArrayPollyfills is private. They are both going away in Ember 2.0 but Ember.ArrayPollyfills doesn't introduce console noise in user's code --- .../lib/adapters/fixture-adapter.js | 6 +-- .../lib/serializers/embedded-records-mixin.js | 6 +-- packages/ember-data/lib/system/many-array.js | 4 +- .../ember-data/lib/system/model/errors.js | 4 +- packages/ember-data/lib/system/model/model.js | 15 ++++++- .../lib/system/record-array-manager.js | 20 +++++----- .../system/relationships/state/has-many.js | 5 ++- .../relationships/state/relationship.js | 6 +-- packages/ember-data/lib/system/store.js | 40 +++++++++---------- .../ember-data/lib/system/store/finders.js | 6 +-- .../lib/system/store/serializer-response.js | 16 ++++---- .../tests/integration/filter-test.js | 14 +++---- .../embedded-records-mixin-test.js | 4 +- .../ember-data/tests/unit/store/push-test.js | 7 ++-- 14 files changed, 83 insertions(+), 70 deletions(-) diff --git a/packages/ember-data/lib/adapters/fixture-adapter.js b/packages/ember-data/lib/adapters/fixture-adapter.js index 805c86f284c..14f81ace904 100644 --- a/packages/ember-data/lib/adapters/fixture-adapter.js +++ b/packages/ember-data/lib/adapters/fixture-adapter.js @@ -3,7 +3,7 @@ */ var get = Ember.get; var fmt = Ember.String.fmt; -var indexOf = Ember.EnumerableUtils.indexOf; +var indexOf = Ember.ArrayPolyfills.indexOf; var counter = 0; @@ -169,7 +169,7 @@ export default Adapter.extend({ if (fixtures) { fixtures = fixtures.filter(function(item) { - return indexOf(ids, item.id) !== -1; + return indexOf.call(ids, item.id) !== -1; }); } @@ -280,7 +280,7 @@ export default Adapter.extend({ var existingFixture = this.findExistingFixture(typeClass, snapshot); if (existingFixture) { - var index = indexOf(typeClass.FIXTURES, existingFixture); + var index = indexOf.call(typeClass.FIXTURES, existingFixture); typeClass.FIXTURES.splice(index, 1); return true; } diff --git a/packages/ember-data/lib/serializers/embedded-records-mixin.js b/packages/ember-data/lib/serializers/embedded-records-mixin.js index b593cf10c76..531b869aacc 100644 --- a/packages/ember-data/lib/serializers/embedded-records-mixin.js +++ b/packages/ember-data/lib/serializers/embedded-records-mixin.js @@ -1,6 +1,6 @@ var get = Ember.get; var set = Ember.set; -var forEach = Ember.EnumerableUtils.forEach; +var forEach = Ember.ArrayPolyfills.forEach; var camelize = Ember.String.camelize; /** @@ -445,7 +445,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ var ids = []; var embeddedSerializer = store.serializerFor(embeddedTypeClass.modelName); - forEach(hash[key], function(data) { + forEach.call(hash[key], function(data) { var embeddedRecord = embeddedSerializer.normalize(embeddedTypeClass, data, null); store.push(embeddedTypeClass.modelName, embeddedRecord); ids.push(embeddedRecord.id); @@ -466,7 +466,7 @@ var EmbeddedRecordsMixin = Ember.Mixin.create({ var ids = []; - forEach(hash[key], function(data) { + forEach.call(hash[key], function(data) { var modelName = data.type; var embeddedSerializer = store.serializerFor(modelName); var embeddedTypeClass = store.modelFor(modelName); diff --git a/packages/ember-data/lib/system/many-array.js b/packages/ember-data/lib/system/many-array.js index f4f10778f3d..1a6f71da618 100644 --- a/packages/ember-data/lib/system/many-array.js +++ b/packages/ember-data/lib/system/many-array.js @@ -6,7 +6,6 @@ import { PromiseArray } from "ember-data/system/promise-proxies"; var get = Ember.get; var set = Ember.set; var filter = Ember.ArrayPolyfills.filter; -var map = Ember.EnumerableUtils.map; /** A `ManyArray` is a `MutableArray` that represents the contents of a has-many @@ -193,8 +192,9 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { records = this.currentState.slice(idx, idx+amt); this.get('relationship').removeRecords(records); } + var map = objects.map || Ember.ArrayPolyfills.map; if (objects) { - this.get('relationship').addRecords(map(objects, function(obj) { return obj._internalModel; }), idx); + this.get('relationship').addRecords(map.call(objects, function(obj) { return obj._internalModel; }), idx); } }, /** diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index 5f0e175f422..f41c28611f9 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -1,6 +1,6 @@ var get = Ember.get; var isEmpty = Ember.isEmpty; -var map = Ember.EnumerableUtils.map; +var map = Ember.ArrayPolyfills.map; import { MapWithDefault @@ -237,7 +237,7 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { _findOrCreateMessages: function(attribute, messages) { var errors = this.errorsFor(attribute); - return map(Ember.makeArray(messages), function(message) { + return map.call(Ember.makeArray(messages), function(message) { return errors.findBy('message', message) || { attribute: attribute, message: message diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 99f8cb1423c..832021674c2 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -5,7 +5,20 @@ import { PromiseObject } from "ember-data/system/promise-proxies"; */ var get = Ember.get; -var intersection = Ember.EnumerableUtils.intersection; +var forEach = Ember.ArrayPolyfills.forEach; +var indexOf = Ember.ArrayPolyfills.indexOf; + +function intersection (array1, array2) { + var result = []; + forEach.call(array1, (element) => { + if (indexOf.call(array2, element) >= 0) { + result.push(element); + } + }); + + return result; +} + var RESERVED_MODEL_PROPS = [ 'currentState', 'data', 'store' ]; diff --git a/packages/ember-data/lib/system/record-array-manager.js b/packages/ember-data/lib/system/record-array-manager.js index c9ecf97a0b8..5f8a81698e3 100644 --- a/packages/ember-data/lib/system/record-array-manager.js +++ b/packages/ember-data/lib/system/record-array-manager.js @@ -12,8 +12,8 @@ import { } from "ember-data/system/map"; import OrderedSet from "ember-data/system/ordered-set"; var get = Ember.get; -var forEach = Ember.EnumerableUtils.forEach; -var indexOf = Ember.EnumerableUtils.indexOf; +var forEach = Ember.ArrayPolyfills.forEach; +var indexOf = Ember.ArrayPolyfills.indexOf; /** @class RecordArrayManager @@ -59,7 +59,7 @@ export default Ember.Object.extend({ @method updateRecordArrays */ updateRecordArrays: function() { - forEach(this.changedRecords, function(record) { + forEach.call(this.changedRecords, function(record) { if (record.isDeleted()) { this._recordWasDeleted(record); } else { @@ -87,8 +87,7 @@ export default Ember.Object.extend({ var typeClass = record.type; var recordArrays = this.filteredRecordArrays.get(typeClass); var filter; - - forEach(recordArrays, function(array) { + forEach.call(recordArrays, function(array) { filter = get(array, 'filterFunction'); this.updateFilterRecordArray(array, filter, typeClass, record); }, this); @@ -100,7 +99,7 @@ export default Ember.Object.extend({ var recordArrays = this.filteredRecordArrays.get(typeClass); var filter; - forEach(recordArrays, function(array) { + forEach.call(recordArrays, function(array) { filter = get(array, 'filterFunction'); this.updateFilterRecordArray(array, filter, typeClass, record); }, this); @@ -122,7 +121,6 @@ export default Ember.Object.extend({ updateFilterRecordArray: function(array, filter, typeClass, record) { var shouldBeInArray = filter(record.getRecord()); var recordArrays = this.recordArraysForRecord(record); - if (shouldBeInArray) { this._addRecordToRecordArray(array, record); } else { @@ -286,7 +284,7 @@ export default Ember.Object.extend({ // unregister filtered record array var recordArrays = this.filteredRecordArrays.get(typeClass); - var index = indexOf(recordArrays, array); + var index = indexOf.call(recordArrays, array); if (index !== -1) { recordArrays.splice(index, 1); @@ -303,10 +301,10 @@ export default Ember.Object.extend({ this._super.apply(this, arguments); this.filteredRecordArrays.forEach(function(value) { - forEach(flatten(value), destroy); + forEach.call(flatten(value), destroy); }); - forEach(this.liveRecordArrays, destroy); - forEach(this._adapterPopulatedRecordArrays, destroy); + forEach.call(this.liveRecordArrays, destroy); + forEach.call(this._adapterPopulatedRecordArrays, destroy); } }); diff --git a/packages/ember-data/lib/system/relationships/state/has-many.js b/packages/ember-data/lib/system/relationships/state/has-many.js index 14be1d10aeb..608a95a5bd1 100644 --- a/packages/ember-data/lib/system/relationships/state/has-many.js +++ b/packages/ember-data/lib/system/relationships/state/has-many.js @@ -5,7 +5,8 @@ import ManyArray from "ember-data/system/many-array"; import { assertPolymorphicType } from "ember-data/utils"; -var map = Ember.EnumerableUtils.map; +var map = Ember.ArrayPolyfills.map; + var ManyRelationship = function(store, record, inverseKey, relationshipMeta) { this._super$constructor(store, record, inverseKey, relationshipMeta); @@ -157,7 +158,7 @@ ManyRelationship.prototype.fetchLink = function() { ManyRelationship.prototype.findRecords = function() { var manyArray = this.manyArray; //TODO CLEANUP - return this.store.findMany(map(manyArray.toArray(), function(rec) { return rec._internalModel; })).then(function() { + return this.store.findMany(map.call(manyArray.toArray(), function(rec) { return rec._internalModel; })).then(function() { //Goes away after the manyArray refactor manyArray.set('isLoaded', true); return manyArray; diff --git a/packages/ember-data/lib/system/relationships/state/relationship.js b/packages/ember-data/lib/system/relationships/state/relationship.js index a7cdc146047..20fcd352485 100644 --- a/packages/ember-data/lib/system/relationships/state/relationship.js +++ b/packages/ember-data/lib/system/relationships/state/relationship.js @@ -1,6 +1,6 @@ import OrderedSet from "ember-data/system/ordered-set"; -var forEach = Ember.EnumerableUtils.forEach; +var forEach = Ember.ArrayPolyfills.forEach; function Relationship(store, record, inverseKey, relationshipMeta) { this.members = new OrderedSet(); @@ -52,14 +52,14 @@ Relationship.prototype = { removeRecords: function(records) { var self = this; - forEach(records, function(record) { + forEach.call(records, function(record) { self.removeRecord(record); }); }, addRecords: function(records, idx) { var self = this; - forEach(records, function(record) { + forEach.call(records, function(record) { self.addRecord(record, idx); if (idx !== undefined) { idx++; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index fd6b75cda3b..9e28bf97b1e 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -107,9 +107,9 @@ var get = Ember.get; var set = Ember.set; var once = Ember.run.once; var isNone = Ember.isNone; -var forEach = Ember.EnumerableUtils.forEach; -var indexOf = Ember.EnumerableUtils.indexOf; -var map = Ember.EnumerableUtils.map; +var forEach = Ember.ArrayPolyfills.forEach; +var indexOf = Ember.ArrayPolyfills.indexOf; +var map = Ember.ArrayPolyfills.map; var Promise = Ember.RSVP.Promise; var copy = Ember.copy; var Store; @@ -668,7 +668,7 @@ Store = Service.extend({ Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var store = this; - return promiseArray(Ember.RSVP.all(map(ids, function(id) { + return promiseArray(Ember.RSVP.all(map.call(ids, function(id) { return store.findRecord(modelName, id); })).then(Ember.A, null, "DS: Store#findByIds of " + modelName + " complete")); }, @@ -697,8 +697,8 @@ Store = Service.extend({ }, scheduleFetchMany: function(records) { - var internalModels = map(records, function(record) { return record._internalModel; }); - return Promise.all(map(internalModels, this.scheduleFetch, this)); + var internalModels = map.call(records, function(record) { return record._internalModel; }); + return Promise.all(map.call(internalModels, this.scheduleFetch, this)); }, scheduleFetch: function(internalModel, options) { @@ -746,7 +746,7 @@ Store = Service.extend({ } function resolveFoundRecords(records) { - forEach(records, function(record) { + forEach.call(records, function(record) { var pair = Ember.A(pendingFetchItems).findBy('record', record); if (pair) { var resolver = pair.resolver; @@ -776,7 +776,7 @@ Store = Service.extend({ } function rejectRecords(records, error) { - forEach(records, function(record) { + forEach.call(records, function(record) { var pair = Ember.A(pendingFetchItems).findBy('record', record); if (pair) { var resolver = pair.resolver; @@ -802,7 +802,7 @@ Store = Service.extend({ var snapshots = Ember.A(records).invoke('createSnapshot'); var groups = adapter.groupRecordsForFindMany(this, snapshots); - forEach(groups, function (groupOfSnapshots) { + forEach.call(groups, function (groupOfSnapshots) { var groupOfRecords = Ember.A(groupOfSnapshots).mapBy('_internalModel'); var requestedRecords = Ember.A(groupOfRecords); var ids = requestedRecords.mapBy('id'); @@ -819,7 +819,7 @@ Store = Service.extend({ } }); } else { - forEach(pendingFetchItems, _fetchRecord); + forEach.call(pendingFetchItems, _fetchRecord); } }, @@ -955,7 +955,7 @@ Store = Service.extend({ */ findMany: function(internalModels) { var store = this; - return Promise.all(map(internalModels, function(internalModel) { + return Promise.all(map.call(internalModels, function(internalModel) { return store._findByInternalModel(internalModel); })); }, @@ -1262,9 +1262,9 @@ Store = Service.extend({ var typeMaps = this.typeMaps; var keys = Ember.keys(typeMaps); - var types = map(keys, byType); + var types = map.call(keys, byType); - forEach(types, this.unloadAll, this); + forEach.call(types, this.unloadAll, this); } else { var typeClass = this.modelFor(modelName); var typeMap = this.typeMapFor(typeClass); @@ -1474,7 +1474,7 @@ Store = Service.extend({ var pending = this._pendingSave.slice(); this._pendingSave = []; - forEach(pending, function(pendingItem) { + forEach.call(pending, function(pendingItem) { var snapshot = pendingItem.snapshot; var resolver = pendingItem.resolver; var record = snapshot._internalModel; @@ -1774,7 +1774,7 @@ Store = Service.extend({ Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string' || typeof data === 'undefined'); var internalModel = this._pushInternalModel(modelName, data); if (Ember.isArray(internalModel)) { - return map(internalModel, (item) => { + return map.call(internalModel, (item) => { return item.getRecord(); }); } @@ -1786,7 +1786,7 @@ Store = Service.extend({ //TODO Remove once the transition is complete var result = pushPayload(this, modelName); if (Ember.isArray(result)) { - return map(result, (item) => { + return map.call(result, (item) => { return item._internalModel; }); } @@ -1797,16 +1797,16 @@ Store = Service.extend({ Ember.deprecate('store.push(type, data) has been deprecated. Please provide a JSON-API document object as the first and only argument to store.push.'); var type = this.modelFor(modelName); - var filter = Ember.EnumerableUtils.filter; + var filter = Ember.ArrayPolyfills.filter; // If Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload // contains unknown keys, log a warning. if (Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS) { Ember.warn("The payload for '" + type.modelName + "' contains these unknown keys: " + - Ember.inspect(filter(Ember.keys(data), function(key) { + Ember.inspect(filter.call(Ember.keys(data), function(key) { return !(key === 'id' || key === 'links' || get(type, 'fields').has(key) || key.match(/Type$/)); })) + ". Make sure they've been defined in your model.", - filter(Ember.keys(data), function(key) { + filter.call(Ember.keys(data), function(key) { return !(key === 'id' || key === 'links' || get(type, 'fields').has(key) || key.match(/Type$/)); }).length === 0 ); @@ -2061,7 +2061,7 @@ Store = Service.extend({ delete typeMap.idToRecord[id]; } - var loc = indexOf(typeMap.records, internalModel); + var loc = indexOf.call(typeMap.records, internalModel); typeMap.records.splice(loc, 1); }, diff --git a/packages/ember-data/lib/system/store/finders.js b/packages/ember-data/lib/system/store/finders.js index 1be56f395a3..104d88e127e 100644 --- a/packages/ember-data/lib/system/store/finders.js +++ b/packages/ember-data/lib/system/store/finders.js @@ -14,7 +14,7 @@ import { } from "ember-data/system/store/serializers"; var Promise = Ember.RSVP.Promise; -var map = Ember.EnumerableUtils.map; +var map = Ember.ArrayPolyfills.map; var get = Ember.get; export function _find(adapter, store, typeClass, id, internalModel, options) { @@ -70,7 +70,7 @@ export function _findMany(adapter, store, typeClass, ids, internalModels) { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findMany'); //TODO Optimize, no need to materialize here var records = pushPayload(store, payload); - return map(records, function(record) { return record._internalModel; }); + return map.call(records, function(record) { return record._internalModel; }); }); }, null, "DS: Extract payload of " + typeClass); } @@ -91,7 +91,7 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findHasMany'); //TODO Use a non record creating push var records = pushPayload(store, payload); - var recordArray = map(records, function(record) { return record._internalModel; }); + var recordArray = map.call(records, function(record) { return record._internalModel; }); if (serializer.get('isNewSerializerAPI')) { recordArray.meta = payload.meta; } diff --git a/packages/ember-data/lib/system/store/serializer-response.js b/packages/ember-data/lib/system/store/serializer-response.js index c416813a298..02e2f723e17 100644 --- a/packages/ember-data/lib/system/store/serializer-response.js +++ b/packages/ember-data/lib/system/store/serializer-response.js @@ -1,5 +1,5 @@ -var forEach = Ember.EnumerableUtils.forEach; -var map = Ember.EnumerableUtils.map; +var forEach = Ember.ArrayPolyfills.forEach; +var map = Ember.ArrayPolyfills.map; /** This is a helper method that always returns a JSON-API Document. @@ -43,7 +43,7 @@ export function _normalizeSerializerPayload(modelClass, payload) { if (payload) { if (Ember.isArray(payload)) { - data = map(payload, (payload) => { + data = map.call(payload, (payload) => { return _normalizeSerializerPayloadItem(modelClass, payload); }); } else { @@ -101,7 +101,7 @@ export function _normalizeSerializerPayloadItem(modelClass, itemPayload) { if (relationshipMeta.kind === 'belongsTo') { relationship.data = normalizeRelationshipData(value, relationshipMeta); } else if (relationshipMeta.kind === 'hasMany') { - relationship.data = map(Ember.A(value), function(item) { + relationship.data = map.call(Ember.A(value), function(item) { return normalizeRelationshipData(item, relationshipMeta); }); } @@ -155,7 +155,7 @@ export function pushPayloadData(store, payload) { var result; if (payload && payload.data) { if (Ember.isArray(payload.data)) { - result = map(payload.data, (item) => { + result = map.call(payload.data, (item) => { return _pushResourceObject(store, item); }); } else { @@ -178,7 +178,7 @@ export function pushPayloadData(store, payload) { export function pushPayloadIncluded(store, payload) { var result; if (payload && payload.included && Ember.isArray(payload.included)) { - result = map(payload.included, (item) => { + result = map.call(payload.included, (item) => { return _pushResourceObject(store, item); }); } @@ -220,14 +220,14 @@ export function convertResourceObject(payload) { if (payload.attributes) { var attributeKeys = Ember.keys(payload.attributes); - forEach(attributeKeys, function(key) { + forEach.call(attributeKeys, function(key) { var attribute = payload.attributes[key]; data[key] = attribute; }); } if (payload.relationships) { var relationshipKeys = Ember.keys(payload.relationships); - forEach(relationshipKeys, function(key) { + forEach.call(relationshipKeys, function(key) { var relationship = payload.relationships[key]; if (relationship.hasOwnProperty('data')) { data[key] = relationship.data; diff --git a/packages/ember-data/tests/integration/filter-test.js b/packages/ember-data/tests/integration/filter-test.js index 2ab10cf9a47..c2a2994a15e 100644 --- a/packages/ember-data/tests/integration/filter-test.js +++ b/packages/ember-data/tests/integration/filter-test.js @@ -2,18 +2,18 @@ import customAdapter from 'ember-data/tests/helpers/custom-adapter'; var get = Ember.get; var set = Ember.set; -var forEach = Ember.EnumerableUtils.forEach; -var indexOf = Ember.EnumerableUtils.indexOf; +var forEach = Ember.ArrayPolyfills.forEach; +var indexOf = Ember.ArrayPolyfills.indexOf; var run = Ember.run; var Person, store, env, array, recordArray; var shouldContain = function(array, item) { - ok(indexOf(array, item) !== -1, "array should contain "+item.get('name')); + ok(array.indexOf(item) !== -1, "array should contain "+item.get('name')); }; var shouldNotContain = function(array, item) { - ok(indexOf(array, item) === -1, "array should not contain "+item.get('name')); + ok(indexOf.call(array, item) === -1, "array should not contain "+item.get('name')); }; module("integration/filter - DS.Model updating", { @@ -520,7 +520,7 @@ var edited; var clientEdits = function(ids) { edited = []; - forEach(ids, function(id) { + forEach.call(ids, function(id) { // wrap in an Ember.run to guarantee coalescence of the // iterated `set` calls and promise resolution. Ember.run(function() { @@ -538,14 +538,14 @@ var clientCreates = function(names) { // wrap in an Ember.run to guarantee coalescence of the // iterated `set` calls. Ember.run(function() { - forEach(names, function(name) { + forEach.call(names, function(name) { edited.push(store.createRecord('person', { name: 'Client-side ' + name })); }); }); }; var serverResponds = function() { - forEach(edited, function(person) { run(person, 'save'); }); + forEach.call(edited, function(person) { run(person, 'save'); }); }; var setup = function(serverCallbacks) { diff --git a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js index d11686c3e5d..e8d3cd5850b 100644 --- a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js +++ b/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js @@ -1,7 +1,7 @@ var get = Ember.get; var HomePlanet, SuperVillain, EvilMinion, SecretLab, SecretWeapon, BatCave, Comment, league, superVillain, evilMinion, secretWeapon, homePlanet, secretLab, env; -var indexOf = Ember.EnumerableUtils.indexOf; +var indexOf = Ember.ArrayPolyfills.indexOf; var run = Ember.run; var LightSaber; @@ -1500,7 +1500,7 @@ test("serializing relationships with an embedded and without calls super when no var relationshipType = snapshot.type.determineRelationshipType(relationship); // "manyToOne" not supported in DS.RESTSerializer.prototype.serializeHasMany var relationshipTypes = Ember.String.w('manyToNone manyToMany manyToOne'); - if (indexOf(relationshipTypes, relationshipType) > -1) { + if (indexOf.call(relationshipTypes, relationshipType) > -1) { json[payloadKey] = snapshot.hasMany(key, { ids: true }); } } diff --git a/packages/ember-data/tests/unit/store/push-test.js b/packages/ember-data/tests/unit/store/push-test.js index 54d36cd25e3..543dc6eb173 100644 --- a/packages/ember-data/tests/unit/store/push-test.js +++ b/packages/ember-data/tests/unit/store/push-test.js @@ -3,6 +3,7 @@ var attr = DS.attr; var hasMany = DS.hasMany; var belongsTo = DS.belongsTo; var run = Ember.run; +var forEach = Ember.ArrayPolyfills.forEach; module("unit/store/push - DS.Store#push", { setup: function() { @@ -431,7 +432,7 @@ test('calling push without data argument as an object raises an error', function expect(invalidValues.length); - Ember.EnumerableUtils.forEach(invalidValues, function(invalidValue) { + forEach.call(invalidValues, function(invalidValue) { throws(function() { run(function() { store.push('person', invalidValue); @@ -503,7 +504,7 @@ test('calling push with hasMany relationship the value must be an array', functi expect(invalidValues.length); - Ember.EnumerableUtils.forEach(invalidValues, function(invalidValue) { + forEach.call(invalidValues, function(invalidValue) { throws(function() { run(function() { store.push('person', { id: 1, phoneNumbers: invalidValue }); @@ -521,7 +522,7 @@ test('calling push with missing or invalid `id` throws assertion error', functio expect(invalidValues.length); - Ember.EnumerableUtils.forEach(invalidValues, function(invalidValue) { + forEach.call(invalidValues, function(invalidValue) { throws(function() { run(function() { store.push('person', invalidValue); From 7879ee7364d9051ce8ccd4da719a4d85a2c3b37c Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 15 Jun 2015 20:21:36 -0400 Subject: [PATCH 0960/2527] Do not register DS.ActiveModelAdapter for all tests. This change removes about 2000 deprecation warnings from the console when the tests are run. --- packages/ember-data/tests/unit/store/lookup-test.js | 2 ++ tests/ember-configuration.js | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/ember-data/tests/unit/store/lookup-test.js b/packages/ember-data/tests/unit/store/lookup-test.js index 6e942aefdc7..c586b204e30 100644 --- a/packages/ember-data/tests/unit/store/lookup-test.js +++ b/packages/ember-data/tests/unit/store/lookup-test.js @@ -13,6 +13,8 @@ function resetStore() { env.registry.unregister('adapter:application'); env.registry.unregister('serializer:application'); + env.registry.register('serializer:-active-model', DS.ActiveModelSerializer); + env.registry.optionsForType('serializer', { singleton: true }); env.registry.optionsForType('adapter', { singleton: true }); diff --git a/tests/ember-configuration.js b/tests/ember-configuration.js index 36d44fe7c7e..6278c32855f 100644 --- a/tests/ember-configuration.js +++ b/tests/ember-configuration.js @@ -94,9 +94,6 @@ registry.register('serializer:-rest', DS.RESTSerializer); registry.register('serializer:-rest-new', DS.RESTSerializer.extend({ isNewSerializerAPI: true })); - registry.register('adapter:-active-model', DS.ActiveModelAdapter); - registry.register('serializer:-active-model', DS.ActiveModelSerializer); - registry.register('adapter:-rest', DS.RESTAdapter); registry.register('adapter:-json-api', DS.JSONAPIAdapter); From 2f97f684bb647a932846f052a311f59f2105c981 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 15 Jun 2015 20:23:45 -0400 Subject: [PATCH 0961/2527] Remove handlebars from the test file since it is no longer a dependecy of ember and is not installed by bower. --- tests/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/index.html b/tests/index.html index 0a02c96ba86..05cefb0407b 100644 --- a/tests/index.html +++ b/tests/index.html @@ -6,7 +6,6 @@ - - - + + + {{content-for 'body-footer'}} + + diff --git a/tests/dummy/app/models/.gitkeep b/tests/dummy/app/models/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js new file mode 100644 index 00000000000..cef554b3d9e --- /dev/null +++ b/tests/dummy/app/router.js @@ -0,0 +1,11 @@ +import Ember from 'ember'; +import config from './config/environment'; + +var Router = Ember.Router.extend({ + location: config.locationType +}); + +Router.map(function() { +}); + +export default Router; diff --git a/tests/dummy/app/routes/.gitkeep b/tests/dummy/app/routes/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/dummy/app/styles/app.css b/tests/dummy/app/styles/app.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/dummy/app/templates/application.hbs b/tests/dummy/app/templates/application.hbs new file mode 100644 index 00000000000..f8bc38e7b6a --- /dev/null +++ b/tests/dummy/app/templates/application.hbs @@ -0,0 +1,3 @@ +

      Welcome to Ember

      + +{{outlet}} diff --git a/tests/dummy/app/templates/components/.gitkeep b/tests/dummy/app/templates/components/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js new file mode 100644 index 00000000000..c59bcd538ea --- /dev/null +++ b/tests/dummy/config/environment.js @@ -0,0 +1,47 @@ +/* jshint node: true */ + +module.exports = function(environment) { + var ENV = { + modulePrefix: 'dummy', + environment: environment, + baseURL: '/', + locationType: 'auto', + EmberENV: { + FEATURES: { + // Here you can enable experimental features on an ember canary build + // e.g. 'with-controller': true + } + }, + + APP: { + // Here you can pass flags/options to your application instance + // when it is created + } + }; + + if (environment === 'development') { + // ENV.APP.LOG_RESOLVER = true; + // ENV.APP.LOG_ACTIVE_GENERATION = true; + // ENV.APP.LOG_TRANSITIONS = true; + // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; + // ENV.APP.LOG_VIEW_LOOKUPS = true; + } + + if (environment === 'test') { + // Testem prefers this... + ENV.baseURL = '/'; + ENV.locationType = 'none'; + + // keep test console output quieter + ENV.APP.LOG_ACTIVE_GENERATION = false; + ENV.APP.LOG_VIEW_LOOKUPS = false; + + ENV.APP.rootElement = '#ember-testing'; + } + + if (environment === 'production') { + + } + + return ENV; +}; diff --git a/tests/dummy/public/crossdomain.xml b/tests/dummy/public/crossdomain.xml new file mode 100644 index 00000000000..0c16a7a07b3 --- /dev/null +++ b/tests/dummy/public/crossdomain.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/tests/dummy/public/robots.txt b/tests/dummy/public/robots.txt new file mode 100644 index 00000000000..f5916452e5f --- /dev/null +++ b/tests/dummy/public/robots.txt @@ -0,0 +1,3 @@ +# http://www.robotstxt.org +User-agent: * +Disallow: diff --git a/packages/ember-data/tests/helpers/custom-adapter.js b/tests/helpers/custom-adapter.js similarity index 100% rename from packages/ember-data/tests/helpers/custom-adapter.js rename to tests/helpers/custom-adapter.js diff --git a/tests/helpers/resolver.js b/tests/helpers/resolver.js new file mode 100644 index 00000000000..28f4ece46a0 --- /dev/null +++ b/tests/helpers/resolver.js @@ -0,0 +1,11 @@ +import Resolver from 'ember/resolver'; +import config from '../../config/environment'; + +var resolver = Resolver.create(); + +resolver.namespace = { + modulePrefix: config.modulePrefix, + podModulePrefix: config.podModulePrefix +}; + +export default resolver; diff --git a/tests/helpers/start-app.js b/tests/helpers/start-app.js new file mode 100644 index 00000000000..0f7aab1afb5 --- /dev/null +++ b/tests/helpers/start-app.js @@ -0,0 +1,18 @@ +import Ember from 'ember'; +import Application from '../../app'; +import config from '../../config/environment'; + +export default function startApp(attrs) { + var application; + + var attributes = Ember.merge({}, config.APP); + attributes = Ember.merge(attributes, attrs); // use defaults, but you can override; + + Ember.run(function() { + application = Application.create(attributes); + application.setupForTesting(); + application.injectTestHelpers(); + }); + + return application; +} diff --git a/tests/index.html b/tests/index.html index 848cfed509b..8fea6fe700b 100644 --- a/tests/index.html +++ b/tests/index.html @@ -1,82 +1,33 @@ - + - Ember Data - - - + + Dummy Tests + + - + {{content-for 'head'}} + {{content-for 'test-head'}} - + + + - - - - - - - - - - - - - + {{content-for 'head-footer'}} + {{content-for 'test-head-footer'}} - -
      -
      - - + + + {{content-for 'body'}} + {{content-for 'test-body'}} + + + + + + + {{content-for 'body-footer'}} + {{content-for 'test-body-footer'}} + diff --git a/packages/ember-data/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js similarity index 100% rename from packages/ember-data/tests/integration/adapter/build-url-mixin-test.js rename to tests/integration/adapter/build-url-mixin-test.js diff --git a/packages/ember-data/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js similarity index 100% rename from packages/ember-data/tests/integration/adapter/find-all-test.js rename to tests/integration/adapter/find-all-test.js diff --git a/packages/ember-data/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js similarity index 100% rename from packages/ember-data/tests/integration/adapter/find-test.js rename to tests/integration/adapter/find-test.js diff --git a/packages/ember-data/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js similarity index 100% rename from packages/ember-data/tests/integration/adapter/json-api-adapter-test.js rename to tests/integration/adapter/json-api-adapter-test.js diff --git a/packages/ember-data/tests/integration/adapter/queries-test.js b/tests/integration/adapter/queries-test.js similarity index 100% rename from packages/ember-data/tests/integration/adapter/queries-test.js rename to tests/integration/adapter/queries-test.js diff --git a/packages/ember-data/tests/integration/adapter/record-persistence-test.js b/tests/integration/adapter/record-persistence-test.js similarity index 100% rename from packages/ember-data/tests/integration/adapter/record-persistence-test.js rename to tests/integration/adapter/record-persistence-test.js diff --git a/packages/ember-data/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js similarity index 100% rename from packages/ember-data/tests/integration/adapter/rest-adapter-test.js rename to tests/integration/adapter/rest-adapter-test.js diff --git a/packages/ember-data/tests/integration/adapter/serialize-test.js b/tests/integration/adapter/serialize-test.js similarity index 100% rename from packages/ember-data/tests/integration/adapter/serialize-test.js rename to tests/integration/adapter/serialize-test.js diff --git a/packages/ember-data/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js similarity index 100% rename from packages/ember-data/tests/integration/adapter/store-adapter-test.js rename to tests/integration/adapter/store-adapter-test.js diff --git a/packages/ember-data/tests/integration/application-test.js b/tests/integration/application-test.js similarity index 100% rename from packages/ember-data/tests/integration/application-test.js rename to tests/integration/application-test.js diff --git a/packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups-test.js b/tests/integration/backwards-compat/non-dasherized-lookups-test.js similarity index 100% rename from packages/ember-data/tests/integration/backwards-compat/non-dasherized-lookups-test.js rename to tests/integration/backwards-compat/non-dasherized-lookups-test.js diff --git a/packages/ember-data/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js similarity index 100% rename from packages/ember-data/tests/integration/client-id-generation-test.js rename to tests/integration/client-id-generation-test.js diff --git a/packages/ember-data/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js similarity index 100% rename from packages/ember-data/tests/integration/debug-adapter-test.js rename to tests/integration/debug-adapter-test.js diff --git a/packages/ember-data/tests/integration/filter-test.js b/tests/integration/filter-test.js similarity index 100% rename from packages/ember-data/tests/integration/filter-test.js rename to tests/integration/filter-test.js diff --git a/packages/ember-data/tests/integration/inverse-test.js b/tests/integration/inverse-test.js similarity index 100% rename from packages/ember-data/tests/integration/inverse-test.js rename to tests/integration/inverse-test.js diff --git a/packages/ember-data/tests/integration/lifecycle-hooks-test.js b/tests/integration/lifecycle-hooks-test.js similarity index 100% rename from packages/ember-data/tests/integration/lifecycle-hooks-test.js rename to tests/integration/lifecycle-hooks-test.js diff --git a/packages/ember-data/tests/integration/multiple_stores_test.js b/tests/integration/multiple_stores_test.js similarity index 100% rename from packages/ember-data/tests/integration/multiple_stores_test.js rename to tests/integration/multiple_stores_test.js diff --git a/packages/ember-data/tests/integration/peek-all-test.js b/tests/integration/peek-all-test.js similarity index 100% rename from packages/ember-data/tests/integration/peek-all-test.js rename to tests/integration/peek-all-test.js diff --git a/packages/ember-data/tests/integration/polymorphic-belongs-to-test.js b/tests/integration/polymorphic-belongs-to-test.js similarity index 100% rename from packages/ember-data/tests/integration/polymorphic-belongs-to-test.js rename to tests/integration/polymorphic-belongs-to-test.js diff --git a/packages/ember-data/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js similarity index 100% rename from packages/ember-data/tests/integration/record-array-manager-test.js rename to tests/integration/record-array-manager-test.js diff --git a/packages/ember-data/tests/integration/records/collection-save-test.js b/tests/integration/records/collection-save-test.js similarity index 100% rename from packages/ember-data/tests/integration/records/collection-save-test.js rename to tests/integration/records/collection-save-test.js diff --git a/packages/ember-data/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js similarity index 100% rename from packages/ember-data/tests/integration/records/delete-record-test.js rename to tests/integration/records/delete-record-test.js diff --git a/packages/ember-data/tests/integration/records/load-test.js b/tests/integration/records/load-test.js similarity index 100% rename from packages/ember-data/tests/integration/records/load-test.js rename to tests/integration/records/load-test.js diff --git a/packages/ember-data/tests/integration/records/property-changes-test.js b/tests/integration/records/property-changes-test.js similarity index 100% rename from packages/ember-data/tests/integration/records/property-changes-test.js rename to tests/integration/records/property-changes-test.js diff --git a/packages/ember-data/tests/integration/records/reload-test.js b/tests/integration/records/reload-test.js similarity index 100% rename from packages/ember-data/tests/integration/records/reload-test.js rename to tests/integration/records/reload-test.js diff --git a/packages/ember-data/tests/integration/records/save-test.js b/tests/integration/records/save-test.js similarity index 100% rename from packages/ember-data/tests/integration/records/save-test.js rename to tests/integration/records/save-test.js diff --git a/packages/ember-data/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js similarity index 100% rename from packages/ember-data/tests/integration/records/unload-test.js rename to tests/integration/records/unload-test.js diff --git a/packages/ember-data/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js similarity index 100% rename from packages/ember-data/tests/integration/relationships/belongs-to-test.js rename to tests/integration/relationships/belongs-to-test.js diff --git a/packages/ember-data/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js similarity index 100% rename from packages/ember-data/tests/integration/relationships/has-many-test.js rename to tests/integration/relationships/has-many-test.js diff --git a/packages/ember-data/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js similarity index 100% rename from packages/ember-data/tests/integration/relationships/inverse-relationships-test.js rename to tests/integration/relationships/inverse-relationships-test.js diff --git a/packages/ember-data/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js similarity index 100% rename from packages/ember-data/tests/integration/relationships/many-to-many-test.js rename to tests/integration/relationships/many-to-many-test.js diff --git a/packages/ember-data/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js similarity index 100% rename from packages/ember-data/tests/integration/relationships/one-to-many-test.js rename to tests/integration/relationships/one-to-many-test.js diff --git a/packages/ember-data/tests/integration/relationships/one-to-one-test.js b/tests/integration/relationships/one-to-one-test.js similarity index 100% rename from packages/ember-data/tests/integration/relationships/one-to-one-test.js rename to tests/integration/relationships/one-to-one-test.js diff --git a/packages/ember-data/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js similarity index 100% rename from packages/ember-data/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js rename to tests/integration/relationships/polymorphic-mixins-belongs-to-test.js diff --git a/packages/ember-data/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js similarity index 100% rename from packages/ember-data/tests/integration/relationships/polymorphic-mixins-has-many-test.js rename to tests/integration/relationships/polymorphic-mixins-has-many-test.js diff --git a/packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js similarity index 100% rename from packages/ember-data/tests/integration/serializers/embedded-records-mixin-test.js rename to tests/integration/serializers/embedded-records-mixin-test.js diff --git a/packages/ember-data/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js similarity index 100% rename from packages/ember-data/tests/integration/serializers/json-api-serializer-test.js rename to tests/integration/serializers/json-api-serializer-test.js diff --git a/packages/ember-data/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js similarity index 100% rename from packages/ember-data/tests/integration/serializers/json-serializer-test.js rename to tests/integration/serializers/json-serializer-test.js diff --git a/packages/ember-data/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js similarity index 100% rename from packages/ember-data/tests/integration/serializers/rest-serializer-test.js rename to tests/integration/serializers/rest-serializer-test.js diff --git a/packages/ember-data/tests/integration/setup-container-test.js b/tests/integration/setup-container-test.js similarity index 100% rename from packages/ember-data/tests/integration/setup-container-test.js rename to tests/integration/setup-container-test.js diff --git a/packages/ember-data/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js similarity index 100% rename from packages/ember-data/tests/integration/snapshot-test.js rename to tests/integration/snapshot-test.js diff --git a/packages/ember-data/tests/integration/store-test.js b/tests/integration/store-test.js similarity index 100% rename from packages/ember-data/tests/integration/store-test.js rename to tests/integration/store-test.js diff --git a/packages/ember-data/tests/integration/store/json-api-validation-test.js b/tests/integration/store/json-api-validation-test.js similarity index 100% rename from packages/ember-data/tests/integration/store/json-api-validation-test.js rename to tests/integration/store/json-api-validation-test.js diff --git a/packages/ember-data/tests/integration/store/query-record-test.js b/tests/integration/store/query-record-test.js similarity index 100% rename from packages/ember-data/tests/integration/store/query-record-test.js rename to tests/integration/store/query-record-test.js diff --git a/tests/test-helper.js b/tests/test-helper.js new file mode 100644 index 00000000000..e6cfb70fe80 --- /dev/null +++ b/tests/test-helper.js @@ -0,0 +1,6 @@ +import resolver from './helpers/resolver'; +import { + setResolver +} from 'ember-qunit'; + +setResolver(resolver); diff --git a/tests/unit/.gitkeep b/tests/unit/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/ember-data/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js similarity index 100% rename from packages/ember-data/tests/unit/adapter-errors-test.js rename to tests/unit/adapter-errors-test.js diff --git a/packages/ember-data/tests/unit/adapter-populated-record-array-test.js b/tests/unit/adapter-populated-record-array-test.js similarity index 100% rename from packages/ember-data/tests/unit/adapter-populated-record-array-test.js rename to tests/unit/adapter-populated-record-array-test.js diff --git a/packages/ember-data/tests/unit/adapters/build-url-mixin/path-for-type-test.js b/tests/unit/adapters/build-url-mixin/path-for-type-test.js similarity index 100% rename from packages/ember-data/tests/unit/adapters/build-url-mixin/path-for-type-test.js rename to tests/unit/adapters/build-url-mixin/path-for-type-test.js diff --git a/packages/ember-data/tests/unit/adapters/json-api-adapter/ajax-test.js b/tests/unit/adapters/json-api-adapter/ajax-test.js similarity index 100% rename from packages/ember-data/tests/unit/adapters/json-api-adapter/ajax-test.js rename to tests/unit/adapters/json-api-adapter/ajax-test.js diff --git a/packages/ember-data/tests/unit/adapters/rest-adapter/ajax-test.js b/tests/unit/adapters/rest-adapter/ajax-test.js similarity index 100% rename from packages/ember-data/tests/unit/adapters/rest-adapter/ajax-test.js rename to tests/unit/adapters/rest-adapter/ajax-test.js diff --git a/packages/ember-data/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js similarity index 100% rename from packages/ember-data/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js rename to tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js diff --git a/packages/ember-data/tests/unit/debug-test.js b/tests/unit/debug-test.js similarity index 100% rename from packages/ember-data/tests/unit/debug-test.js rename to tests/unit/debug-test.js diff --git a/packages/ember-data/tests/unit/many-array-test.js b/tests/unit/many-array-test.js similarity index 100% rename from packages/ember-data/tests/unit/many-array-test.js rename to tests/unit/many-array-test.js diff --git a/packages/ember-data/tests/unit/model-test.js b/tests/unit/model-test.js similarity index 100% rename from packages/ember-data/tests/unit/model-test.js rename to tests/unit/model-test.js diff --git a/packages/ember-data/tests/unit/model/errors-test.js b/tests/unit/model/errors-test.js similarity index 100% rename from packages/ember-data/tests/unit/model/errors-test.js rename to tests/unit/model/errors-test.js diff --git a/packages/ember-data/tests/unit/model/internal-model-test.js b/tests/unit/model/internal-model-test.js similarity index 100% rename from packages/ember-data/tests/unit/model/internal-model-test.js rename to tests/unit/model/internal-model-test.js diff --git a/packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js similarity index 100% rename from packages/ember-data/tests/unit/model/lifecycle-callbacks-test.js rename to tests/unit/model/lifecycle-callbacks-test.js diff --git a/packages/ember-data/tests/unit/model/merge-test.js b/tests/unit/model/merge-test.js similarity index 100% rename from packages/ember-data/tests/unit/model/merge-test.js rename to tests/unit/model/merge-test.js diff --git a/packages/ember-data/tests/unit/model/relationships-test.js b/tests/unit/model/relationships-test.js similarity index 100% rename from packages/ember-data/tests/unit/model/relationships-test.js rename to tests/unit/model/relationships-test.js diff --git a/packages/ember-data/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js similarity index 100% rename from packages/ember-data/tests/unit/model/relationships/belongs-to-test.js rename to tests/unit/model/relationships/belongs-to-test.js diff --git a/packages/ember-data/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js similarity index 100% rename from packages/ember-data/tests/unit/model/relationships/has-many-test.js rename to tests/unit/model/relationships/has-many-test.js diff --git a/packages/ember-data/tests/unit/model/relationships/record-array-test.js b/tests/unit/model/relationships/record-array-test.js similarity index 100% rename from packages/ember-data/tests/unit/model/relationships/record-array-test.js rename to tests/unit/model/relationships/record-array-test.js diff --git a/packages/ember-data/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js similarity index 100% rename from packages/ember-data/tests/unit/model/rollback-attributes-test.js rename to tests/unit/model/rollback-attributes-test.js diff --git a/packages/ember-data/tests/unit/promise-proxies-test.js b/tests/unit/promise-proxies-test.js similarity index 100% rename from packages/ember-data/tests/unit/promise-proxies-test.js rename to tests/unit/promise-proxies-test.js diff --git a/packages/ember-data/tests/unit/record-array-test.js b/tests/unit/record-array-test.js similarity index 100% rename from packages/ember-data/tests/unit/record-array-test.js rename to tests/unit/record-array-test.js diff --git a/packages/ember-data/tests/unit/record-arrays/filtered-record-array-test.js b/tests/unit/record-arrays/filtered-record-array-test.js similarity index 100% rename from packages/ember-data/tests/unit/record-arrays/filtered-record-array-test.js rename to tests/unit/record-arrays/filtered-record-array-test.js diff --git a/packages/ember-data/tests/unit/states-test.js b/tests/unit/states-test.js similarity index 100% rename from packages/ember-data/tests/unit/states-test.js rename to tests/unit/states-test.js diff --git a/packages/ember-data/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js similarity index 100% rename from packages/ember-data/tests/unit/store/adapter-interop-test.js rename to tests/unit/store/adapter-interop-test.js diff --git a/packages/ember-data/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js similarity index 100% rename from packages/ember-data/tests/unit/store/create-record-test.js rename to tests/unit/store/create-record-test.js diff --git a/packages/ember-data/tests/unit/store/has-record-for-id-test.js b/tests/unit/store/has-record-for-id-test.js similarity index 100% rename from packages/ember-data/tests/unit/store/has-record-for-id-test.js rename to tests/unit/store/has-record-for-id-test.js diff --git a/packages/ember-data/tests/unit/store/lookup-test.js b/tests/unit/store/lookup-test.js similarity index 100% rename from packages/ember-data/tests/unit/store/lookup-test.js rename to tests/unit/store/lookup-test.js diff --git a/packages/ember-data/tests/unit/store/model-for-test.js b/tests/unit/store/model-for-test.js similarity index 100% rename from packages/ember-data/tests/unit/store/model-for-test.js rename to tests/unit/store/model-for-test.js diff --git a/packages/ember-data/tests/unit/store/peek-record-test.js b/tests/unit/store/peek-record-test.js similarity index 100% rename from packages/ember-data/tests/unit/store/peek-record-test.js rename to tests/unit/store/peek-record-test.js diff --git a/packages/ember-data/tests/unit/store/push-test.js b/tests/unit/store/push-test.js similarity index 100% rename from packages/ember-data/tests/unit/store/push-test.js rename to tests/unit/store/push-test.js diff --git a/packages/ember-data/tests/unit/store/serializer-for-test.js b/tests/unit/store/serializer-for-test.js similarity index 100% rename from packages/ember-data/tests/unit/store/serializer-for-test.js rename to tests/unit/store/serializer-for-test.js diff --git a/packages/ember-data/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js similarity index 100% rename from packages/ember-data/tests/unit/store/unload-test.js rename to tests/unit/store/unload-test.js diff --git a/packages/ember-data/tests/unit/transform/boolean-test.js b/tests/unit/transform/boolean-test.js similarity index 100% rename from packages/ember-data/tests/unit/transform/boolean-test.js rename to tests/unit/transform/boolean-test.js diff --git a/packages/ember-data/tests/unit/transform/date-test.js b/tests/unit/transform/date-test.js similarity index 100% rename from packages/ember-data/tests/unit/transform/date-test.js rename to tests/unit/transform/date-test.js diff --git a/packages/ember-data/tests/unit/transform/number-test.js b/tests/unit/transform/number-test.js similarity index 100% rename from packages/ember-data/tests/unit/transform/number-test.js rename to tests/unit/transform/number-test.js diff --git a/packages/ember-data/tests/unit/transform/string-test.js b/tests/unit/transform/string-test.js similarity index 100% rename from packages/ember-data/tests/unit/transform/string-test.js rename to tests/unit/transform/string-test.js diff --git a/packages/ember-data/tests/unit/utils-test.js b/tests/unit/utils-test.js similarity index 100% rename from packages/ember-data/tests/unit/utils-test.js rename to tests/unit/utils-test.js From 82e46c4274dc53a360bf1186047a21a1134c7e0f Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 4 Nov 2015 20:11:50 -0600 Subject: [PATCH 1193/2527] pull over more configuration from generated addon scaffold --- addon/{main.js => index.js} | 0 bower.json | 19 ++-- config/ember-try.js | 35 +++++++ config/environment.js | 5 + index.js | 6 ++ package.json | 97 +++++++------------ testem.json | 15 ++- .../adapter/build-url-mixin-test.js | 2 + 8 files changed, 101 insertions(+), 78 deletions(-) rename addon/{main.js => index.js} (100%) create mode 100644 config/ember-try.js create mode 100644 config/environment.js create mode 100644 index.js diff --git a/addon/main.js b/addon/index.js similarity index 100% rename from addon/main.js rename to addon/index.js diff --git a/bower.json b/bower.json index 0d941b22d38..b635590fe44 100644 --- a/bower.json +++ b/bower.json @@ -1,13 +1,16 @@ { "name": "ember-data", - "private": true, "dependencies": { - "ember": "^2.0.0" - }, - "devDependencies": { - "qunit": "~1.17.0", - "jquery": "~1.10.x", - "loader.js": "~1.0.0", - "es5-shim": "~4.0.3" + "ember": "1.13.7", + "ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3", + "ember-cli-test-loader": "ember-cli-test-loader#0.1.3", + "ember-data": "1.13.8", + "ember-load-initializers": "ember-cli/ember-load-initializers#0.1.5", + "ember-qunit": "0.4.9", + "ember-qunit-notifications": "0.0.7", + "ember-resolver": "~0.1.18", + "jquery": "^1.11.3", + "loader.js": "ember-cli/loader.js#3.2.1", + "qunit": "~1.18.0" } } diff --git a/config/ember-try.js b/config/ember-try.js new file mode 100644 index 00000000000..83dab0f1846 --- /dev/null +++ b/config/ember-try.js @@ -0,0 +1,35 @@ +module.exports = { + scenarios: [ + { + name: 'default', + dependencies: { } + }, + { + name: 'ember-release', + dependencies: { + 'ember': 'components/ember#release' + }, + resolutions: { + 'ember': 'release' + } + }, + { + name: 'ember-beta', + dependencies: { + 'ember': 'components/ember#beta' + }, + resolutions: { + 'ember': 'beta' + } + }, + { + name: 'ember-canary', + dependencies: { + 'ember': 'components/ember#canary' + }, + resolutions: { + 'ember': 'canary' + } + } + ] +}; diff --git a/config/environment.js b/config/environment.js new file mode 100644 index 00000000000..0dfaed4728b --- /dev/null +++ b/config/environment.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = function(/* environment, appConfig */) { + return { }; +}; diff --git a/index.js b/index.js new file mode 100644 index 00000000000..3ad252c0448 --- /dev/null +++ b/index.js @@ -0,0 +1,6 @@ +/* jshint node: true */ +'use strict'; + +module.exports = { + name: 'ember-data' +}; diff --git a/package.json b/package.json index 9e4337cec12..5c8e376ef15 100644 --- a/package.json +++ b/package.json @@ -1,73 +1,48 @@ { "name": "ember-data", - "version": "2.3.0-canary", - "namespace": "DS", - "repository": "git://github.com/emberjs/data.git", - "license": "MIT", - "keywords": [ - "ember-addon" - ], - "main": "lib/ember-addon/index.js", - "ember-addon": { - "main": "lib/ember-addon/index.js" + "version": "0.0.0", + "description": "The default blueprint for ember-cli addons.", + "directories": { + "doc": "doc", + "test": "tests" }, - "files": [ - "lib/ember-addon" - ], "scripts": { "build": "ember build", - "build:production": "ember build --environment=production", - "prepublish": "bower install && npm run-script build:production", - "start": "ember serve", - "test": "jscs packages && testem -R dot ci", - "publish-build": "npm run build:production && ./bin/publish-to-s3.js", - "publish-build:prebuilt": "./bin/publish-to-s3.js", - "test:local": "testem -R dot ci", - "test:beta": "testem -f config/testem-beta.json -R dot ci", - "test:canary": "testem -f config/testem-canary.json -R dot ci", - "test:stable": "testem -f config/testem-stable.json -R dot ci", - "test:optional-features": "testem -f config/testem-optional-features.json -R dot ci" + "start": "ember server", + "test": "ember try:testall" + }, + "repository": "", + "engines": { + "node": ">= 0.10.0" }, + "author": "", + "license": "MIT", "devDependencies": { - "aws-sdk": "~2.0.0-rc8", - "bower": "~1.3", - "broccoli-babel-transpiler": "5.1.1", - "broccoli-compile-modules": "^1.1.0", - "broccoli-concat": "0.0.12", - "broccoli-defeatureify": "^1.0.0", - "broccoli-env": "0.0.1", - "broccoli-es3-safe-recast": "2.0.0", - "broccoli-es6-module-transpiler": "^0.5.0", - "broccoli-es6-transpiler": "^0.1.0", - "broccoli-file-creator": "^0.1.0", - "broccoli-file-mover": "~0.2.0", - "broccoli-jscs": "0.0.22", - "broccoli-jshint": "^0.5.6", - "broccoli-merge-trees": "^0.1.4", - "broccoli-render-template": "0.0.3", - "broccoli-replace": "~0.2.0", - "broccoli-sourcemap-concat": "^0.4.4", - "broccoli-static-compiler": "^0.2.1", - "broccoli-stew": "^0.2.1", - "broccoli-uglify-js": "^0.1.3", - "broccoli-wrap": "0.0.2", - "broccoli-yuidoc": "^1.3.0", - "defeatureify": "~0.1.4", - "ejs": "^1.0.0", - "ember-cli": "^1.13.8", + "broccoli-asset-rev": "^2.1.2", + "ember-cli": "1.13.8", + "ember-cli-app-version": "0.5.0", + "ember-cli-content-security-policy": "0.4.0", "ember-cli-dependency-checker": "^1.0.1", - "ember-inflector": "^1.9.3", - "ember-publisher": "0.0.7", - "es6-module-transpiler": "^0.9.5", - "es6-module-transpiler-amd-formatter": "^0.2.4", - "es6-module-transpiler-package-resolver": "^1.0.1", - "git-repo-version": "0.0.2", - "github": "^0.2.4", - "jscs": "^1.12.0", - "testem": "^0.6.19", - "yuidocjs": "~0.3.46" + "ember-cli-htmlbars": "0.7.9", + "ember-cli-htmlbars-inline-precompile": "^0.2.0", + "ember-cli-ic-ajax": "0.2.1", + "ember-cli-inject-live-reload": "^1.3.1", + "ember-cli-qunit": "^1.0.0", + "ember-cli-release": "0.2.3", + "ember-cli-sri": "^1.0.3", + "ember-cli-uglify": "^1.2.0", + "ember-disable-proxy-controllers": "^1.0.0", + "ember-export-application-global": "^1.0.3", + "ember-disable-prototype-extensions": "^1.0.0", + "ember-try": "0.0.6" }, + "keywords": [ + "ember-addon" + ], "dependencies": { - "rsvp": "^3.0.18" + "ember-cli-babel": "^5.1.3" + }, + "ember-addon": { + "configPath": "tests/dummy/config" } } diff --git a/testem.json b/testem.json index 298efe31ceb..71b50baf873 100644 --- a/testem.json +++ b/testem.json @@ -1,14 +1,11 @@ { - "test_page": "dist/index.html", - "serve_files": [ - "dist/**/*.js", - "tests/**/*" - ], - "routes": { - "/ember-data.js": "dist/ember-data.js", - "/tests/tests.js": "dist/tests.js" - }, + "framework": "qunit", + "test_page": "tests/index.html?hidepassed", + "disable_watching": true, "launch_in_ci": [ "PhantomJS" + ], + "launch_in_dev": [ + "Chrome" ] } diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index 63851a77619..730a10406a1 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, adapter, Post, Comment, SuperUser; var passedUrl; var run = Ember.run; From 24d4e17c47d66c9d8b7a9c083a5f86108ec4d83f Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 4 Nov 2015 20:14:59 -0600 Subject: [PATCH 1194/2527] add import for ember data in tests --- tests/ember-configuration.js | 2 ++ tests/ember-data-setup.js | 2 ++ tests/helpers/custom-adapter.js | 2 ++ tests/integration/adapter/find-all-test.js | 2 ++ tests/integration/adapter/find-test.js | 2 ++ tests/integration/adapter/json-api-adapter-test.js | 2 ++ tests/integration/adapter/queries-test.js | 2 ++ tests/integration/adapter/record-persistence-test.js | 2 ++ tests/integration/adapter/rest-adapter-test.js | 2 ++ tests/integration/adapter/serialize-test.js | 2 ++ tests/integration/adapter/store-adapter-test.js | 2 ++ tests/integration/application-test.js | 2 ++ .../integration/backwards-compat/non-dasherized-lookups-test.js | 2 ++ tests/integration/client-id-generation-test.js | 2 ++ tests/integration/debug-adapter-test.js | 2 ++ tests/integration/filter-test.js | 2 ++ tests/integration/inverse-test.js | 2 ++ tests/integration/lifecycle-hooks-test.js | 2 ++ tests/integration/multiple_stores_test.js | 2 ++ tests/integration/peek-all-test.js | 2 ++ tests/integration/polymorphic-belongs-to-test.js | 2 ++ tests/integration/record-array-manager-test.js | 2 ++ tests/integration/records/collection-save-test.js | 2 ++ tests/integration/records/delete-record-test.js | 2 ++ tests/integration/records/load-test.js | 2 ++ tests/integration/records/property-changes-test.js | 2 ++ tests/integration/records/reload-test.js | 2 ++ tests/integration/records/save-test.js | 2 ++ tests/integration/records/unload-test.js | 2 ++ tests/integration/relationships/belongs-to-test.js | 2 ++ tests/integration/relationships/has-many-test.js | 2 ++ tests/integration/relationships/inverse-relationships-test.js | 2 ++ tests/integration/relationships/many-to-many-test.js | 2 ++ tests/integration/relationships/one-to-many-test.js | 2 ++ tests/integration/relationships/one-to-one-test.js | 2 ++ .../relationships/polymorphic-mixins-belongs-to-test.js | 2 ++ .../relationships/polymorphic-mixins-has-many-test.js | 2 ++ tests/integration/serializers/embedded-records-mixin-test.js | 2 ++ tests/integration/serializers/json-api-serializer-test.js | 2 ++ tests/integration/serializers/json-serializer-test.js | 2 ++ tests/integration/serializers/rest-serializer-test.js | 2 ++ tests/integration/setup-container-test.js | 2 ++ tests/integration/snapshot-test.js | 2 ++ tests/integration/store-test.js | 2 ++ tests/integration/store/json-api-validation-test.js | 2 ++ tests/integration/store/query-record-test.js | 2 ++ tests/unit/adapter-errors-test.js | 2 ++ tests/unit/adapter-populated-record-array-test.js | 2 ++ tests/unit/adapters/build-url-mixin/path-for-type-test.js | 2 ++ tests/unit/adapters/json-api-adapter/ajax-test.js | 2 ++ tests/unit/adapters/rest-adapter/ajax-test.js | 2 ++ .../adapters/rest-adapter/group-records-for-find-many-test.js | 2 ++ tests/unit/debug-test.js | 2 ++ tests/unit/many-array-test.js | 2 ++ tests/unit/model-test.js | 2 ++ tests/unit/model/errors-test.js | 2 ++ tests/unit/model/internal-model-test.js | 2 ++ tests/unit/model/lifecycle-callbacks-test.js | 2 ++ tests/unit/model/merge-test.js | 2 ++ tests/unit/model/relationships-test.js | 2 ++ tests/unit/model/relationships/belongs-to-test.js | 2 ++ tests/unit/model/relationships/has-many-test.js | 2 ++ tests/unit/model/relationships/record-array-test.js | 2 ++ tests/unit/model/rollback-attributes-test.js | 2 ++ tests/unit/promise-proxies-test.js | 2 ++ tests/unit/record-array-test.js | 2 ++ tests/unit/record-arrays/filtered-record-array-test.js | 2 ++ tests/unit/states-test.js | 2 ++ tests/unit/store/adapter-interop-test.js | 2 ++ tests/unit/store/create-record-test.js | 2 ++ tests/unit/store/has-record-for-id-test.js | 2 ++ tests/unit/store/lookup-test.js | 2 ++ tests/unit/store/model-for-test.js | 2 ++ tests/unit/store/peek-record-test.js | 2 ++ tests/unit/store/push-test.js | 2 ++ tests/unit/store/serializer-for-test.js | 2 ++ tests/unit/store/unload-test.js | 2 ++ tests/unit/transform/boolean-test.js | 2 ++ tests/unit/transform/date-test.js | 2 ++ tests/unit/transform/number-test.js | 2 ++ tests/unit/transform/string-test.js | 2 ++ tests/unit/utils-test.js | 2 ++ 82 files changed, 164 insertions(+) diff --git a/tests/ember-configuration.js b/tests/ember-configuration.js index ad317c1bcdf..9c20aef4fdc 100644 --- a/tests/ember-configuration.js +++ b/tests/ember-configuration.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + /* globals ENV, QUnit */ (function () { diff --git a/tests/ember-data-setup.js b/tests/ember-data-setup.js index bbe39109a2c..a25bf257041 100644 --- a/tests/ember-data-setup.js +++ b/tests/ember-data-setup.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + ;(function() { Ember.RSVP.configure('onerror', function(reason) { diff --git a/tests/helpers/custom-adapter.js b/tests/helpers/custom-adapter.js index 3cead14285f..050bc3c7929 100644 --- a/tests/helpers/custom-adapter.js +++ b/tests/helpers/custom-adapter.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + export default function(env, adapterDefinition) { var adapter = adapterDefinition; diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index 2357c776b9a..6f289a6802b 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var Person, store, allRecords; var run = Ember.run; diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 7774125a85c..87f1272ef6b 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var Person, store, env; var run = Ember.run; diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index d607549fa33..63e6e16614c 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, adapter; var passedUrl, passedVerb, passedHash; diff --git a/tests/integration/adapter/queries-test.js b/tests/integration/adapter/queries-test.js index a8f5143642b..6e0771b21fc 100644 --- a/tests/integration/adapter/queries-test.js +++ b/tests/integration/adapter/queries-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var Person, env, store, adapter; var run = Ember.run; diff --git a/tests/integration/adapter/record-persistence-test.js b/tests/integration/adapter/record-persistence-test.js index 96f263399b9..f2cb5056229 100644 --- a/tests/integration/adapter/record-persistence-test.js +++ b/tests/integration/adapter/record-persistence-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var set = Ember.set; var attr = DS.attr; diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 10da5cf9fd2..1d4de9a3644 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, adapter, Post, Comment, SuperUser; var passedUrl, passedVerb, passedHash; var run = Ember.run; diff --git a/tests/integration/adapter/serialize-test.js b/tests/integration/adapter/serialize-test.js index 889993f5c69..279df6958e8 100644 --- a/tests/integration/adapter/serialize-test.js +++ b/tests/integration/adapter/serialize-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var run = Ember.run; var env, store, adapter, serializer; diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 240a16241c0..cecafc13309 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + /* This is an integration test that tests the communication between a store and its adapter. diff --git a/tests/integration/application-test.js b/tests/integration/application-test.js index 873408bebc6..9e2e619069c 100644 --- a/tests/integration/application-test.js +++ b/tests/integration/application-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var run = Ember.run; var Application = Ember.Application; var Controller = Ember.Controller; diff --git a/tests/integration/backwards-compat/non-dasherized-lookups-test.js b/tests/integration/backwards-compat/non-dasherized-lookups-test.js index 6bbb2d8f476..3f4dd19b6e0 100644 --- a/tests/integration/backwards-compat/non-dasherized-lookups-test.js +++ b/tests/integration/backwards-compat/non-dasherized-lookups-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + const get = Ember.get; const { run } = Ember; diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index 5e50d51d871..768703d222e 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var Post, Comment, Misc, env; var run = Ember.run; diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index 29465089cdd..2b1ad368639 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var App, store, debugAdapter; var get = Ember.get; var run = Ember.run; diff --git a/tests/integration/filter-test.js b/tests/integration/filter-test.js index a9e8cf0b0d1..fd13cd5dd68 100644 --- a/tests/integration/filter-test.js +++ b/tests/integration/filter-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + import customAdapter from 'ember-data/tests/helpers/custom-adapter'; var get = Ember.get; diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index 9a08dd476b4..dae6735ba61 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, User, Job, ReflexiveModel; var attr = DS.attr; diff --git a/tests/integration/lifecycle-hooks-test.js b/tests/integration/lifecycle-hooks-test.js index 3625e35c9e0..c858941bdb2 100644 --- a/tests/integration/lifecycle-hooks-test.js +++ b/tests/integration/lifecycle-hooks-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var Person, env; var attr = DS.attr; var resolve = Ember.RSVP.resolve; diff --git a/tests/integration/multiple_stores_test.js b/tests/integration/multiple_stores_test.js index 0b9898d8f38..b286ae9978a 100644 --- a/tests/integration/multiple_stores_test.js +++ b/tests/integration/multiple_stores_test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env; var SuperVillain, HomePlanet, EvilMinion; var run = Ember.run; diff --git a/tests/integration/peek-all-test.js b/tests/integration/peek-all-test.js index 996e61d1bc8..cfedf7a0686 100644 --- a/tests/integration/peek-all-test.js +++ b/tests/integration/peek-all-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var run = Ember.run; diff --git a/tests/integration/polymorphic-belongs-to-test.js b/tests/integration/polymorphic-belongs-to-test.js index 3a5026a76cd..8ee053c9ab3 100644 --- a/tests/integration/polymorphic-belongs-to-test.js +++ b/tests/integration/polymorphic-belongs-to-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + const {attr, belongsTo} = DS; const {run} = Ember; diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index d7674f4775f..2ed69e08f24 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var store, env; var run = Ember.run; diff --git a/tests/integration/records/collection-save-test.js b/tests/integration/records/collection-save-test.js index a18282c3508..8c547ddb711 100644 --- a/tests/integration/records/collection-save-test.js +++ b/tests/integration/records/collection-save-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var Post, env; var run = Ember.run; diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index 7a7930ac8b7..a5681a220bf 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var attr = DS.attr; var Person, env; var run = Ember.run; diff --git a/tests/integration/records/load-test.js b/tests/integration/records/load-test.js index 3c68ce619cb..68b1f54a0a4 100644 --- a/tests/integration/records/load-test.js +++ b/tests/integration/records/load-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var hasMany = DS.hasMany; var Post, Comment, env; var run = Ember.run; diff --git a/tests/integration/records/property-changes-test.js b/tests/integration/records/property-changes-test.js index f3789725be0..97c344b6cc1 100644 --- a/tests/integration/records/property-changes-test.js +++ b/tests/integration/records/property-changes-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, Person; var attr = DS.attr; var run = Ember.run; diff --git a/tests/integration/records/reload-test.js b/tests/integration/records/reload-test.js index 2fa27105a5b..1186a991086 100644 --- a/tests/integration/records/reload-test.js +++ b/tests/integration/records/reload-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var attr = DS.attr; var Person, env; diff --git a/tests/integration/records/save-test.js b/tests/integration/records/save-test.js index 46bab32edf5..d09fd668a65 100644 --- a/tests/integration/records/save-test.js +++ b/tests/integration/records/save-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var Post, env; var run = Ember.run; diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 786d23fbb00..07235dc479c 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var attr = DS.attr; var belongsTo = DS.belongsTo; var hasMany = DS.hasMany; diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 7f51329614d..d2906789010 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, User, Message, Post, Contact, Comment, Book, Chapter, Author, NewMessage; var get = Ember.get; var run = Ember.run; diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 522a5cb1b76..52fcd6716c6 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, User, Contact, Email, Phone, Message, Post, Comment; var Book, Chapter, Page; var get = Ember.get; diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index 1eecf948789..afca1c137b9 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var Post, Comment, Message, User; var run = Ember.run; diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index d7e5a7afa29..98b8b0f36f4 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var Account, Topic, User, store, env; var run = Ember.run; diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index e406309ae13..222001933ae 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, User, Message, Account; var get = Ember.get; var run = Ember.run; diff --git a/tests/integration/relationships/one-to-one-test.js b/tests/integration/relationships/one-to-one-test.js index cf903f4ac11..8026c156a4e 100644 --- a/tests/integration/relationships/one-to-one-test.js +++ b/tests/integration/relationships/one-to-one-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, User, Job; var run = Ember.run; diff --git a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index 0060b0a769e..194154e2307 100644 --- a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, User, Message, Video, NotMessage; var run = Ember.run; diff --git a/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js index e0470db7e7a..a7e38229a07 100644 --- a/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, User, Message, NotMessage, Video; var run = Ember.run; diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index 82073b45080..9d7dfb5c7eb 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var HomePlanet, SuperVillain, EvilMinion, SecretLab, SecretWeapon, BatCave, Comment, league, superVillain, evilMinion, secretWeapon, homePlanet, secretLab, env; diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 29df8d57943..68d3fa2babc 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, serializer; var get = Ember.get; diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 79fd398d4ab..c891ab72389 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var Post, post, Comment, comment, Favorite, favorite, env; var run = Ember.run; diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 95ae9a9ca14..274acbe9cdc 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var HomePlanet, league, SuperVillain, EvilMinion, YellowMinion, DoomsdayDevice, Comment, Basket, Container, env; var run = Ember.run; diff --git a/tests/integration/setup-container-test.js b/tests/integration/setup-container-test.js index d970bd53e9c..c4a1d2f06b3 100644 --- a/tests/integration/setup-container-test.js +++ b/tests/integration/setup-container-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var run = Ember.run; var Store = DS.Store; var EmberObject = Ember.Object; diff --git a/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js index 355f4634f88..71ba3aacbf7 100644 --- a/tests/integration/snapshot-test.js +++ b/tests/integration/snapshot-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var run = Ember.run; var env, Post, Comment; diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index cafb160efe7..c8e6174e3b7 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var store, env; var Person = DS.Model.extend({ diff --git a/tests/integration/store/json-api-validation-test.js b/tests/integration/store/json-api-validation-test.js index b65808622b7..789d2b1669a 100644 --- a/tests/integration/store/json-api-validation-test.js +++ b/tests/integration/store/json-api-validation-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var Person, store, env; var run = Ember.run; diff --git a/tests/integration/store/query-record-test.js b/tests/integration/store/query-record-test.js index 87c26a518bd..0a01da7973b 100644 --- a/tests/integration/store/query-record-test.js +++ b/tests/integration/store/query-record-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var Person, store, env; var run = Ember.run; diff --git a/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js index 2b4c0e3bdca..cf8f596b822 100644 --- a/tests/unit/adapter-errors-test.js +++ b/tests/unit/adapter-errors-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + module("unit/adapter-errors - DS.AdapterError"); test("DS.AdapterError", function() { diff --git a/tests/unit/adapter-populated-record-array-test.js b/tests/unit/adapter-populated-record-array-test.js index 3b5cc2b2d3a..ba6d859aab1 100644 --- a/tests/unit/adapter-populated-record-array-test.js +++ b/tests/unit/adapter-populated-record-array-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var Person, store; var run = Ember.run; diff --git a/tests/unit/adapters/build-url-mixin/path-for-type-test.js b/tests/unit/adapters/build-url-mixin/path-for-type-test.js index 6ce9e2150d9..79dcd0d9e3d 100644 --- a/tests/unit/adapters/build-url-mixin/path-for-type-test.js +++ b/tests/unit/adapters/build-url-mixin/path-for-type-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, adapter; module("unit/adapters/build-url-mixin/path-for-type - DS.BuildURLMixin#pathForType", { diff --git a/tests/unit/adapters/json-api-adapter/ajax-test.js b/tests/unit/adapters/json-api-adapter/ajax-test.js index c88fb4e08d3..c4be843178a 100644 --- a/tests/unit/adapters/json-api-adapter/ajax-test.js +++ b/tests/unit/adapters/json-api-adapter/ajax-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var Person, Place, store, adapter, env; var run = Ember.run; diff --git a/tests/unit/adapters/rest-adapter/ajax-test.js b/tests/unit/adapters/rest-adapter/ajax-test.js index 0cd1afeb1ac..bbbf3df1dac 100644 --- a/tests/unit/adapters/rest-adapter/ajax-test.js +++ b/tests/unit/adapters/rest-adapter/ajax-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var Person, Place, store, adapter, env; var run = Ember.run; diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 2573ceddf0e..59d1f4498da 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var GroupsAdapter, Store; var maxLength = -1; var lengths = Ember.A([]); diff --git a/tests/unit/debug-test.js b/tests/unit/debug-test.js index 88121e4ce2d..d19d10c81fd 100644 --- a/tests/unit/debug-test.js +++ b/tests/unit/debug-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var run = Ember.run; var TestAdapter = DS.Adapter.extend(); diff --git a/tests/unit/many-array-test.js b/tests/unit/many-array-test.js index e1c800aa2ba..6ad19dd9673 100644 --- a/tests/unit/many-array-test.js +++ b/tests/unit/many-array-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store; var attr = DS.attr; var hasMany = DS.hasMany; diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index b9c7f1c3b99..3510876d69f 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var set = Ember.set; var run = Ember.run; diff --git a/tests/unit/model/errors-test.js b/tests/unit/model/errors-test.js index 4d41a309e82..6037b9927ae 100644 --- a/tests/unit/model/errors-test.js +++ b/tests/unit/model/errors-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var errors; module("unit/model/errors", { diff --git a/tests/unit/model/internal-model-test.js b/tests/unit/model/internal-model-test.js index 5e81ff5ab17..ca3f098ca87 100644 --- a/tests/unit/model/internal-model-test.js +++ b/tests/unit/model/internal-model-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + module("unit/model/internal-model - Internal Model"); var mockModelFactory = { diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index 9f5573e08d4..e4b5a15730c 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var run = Ember.run; diff --git a/tests/unit/model/merge-test.js b/tests/unit/model/merge-test.js index 917f04d0585..d3af592c07e 100644 --- a/tests/unit/model/merge-test.js +++ b/tests/unit/model/merge-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var Person; var run = Ember.run; diff --git a/tests/unit/model/relationships-test.js b/tests/unit/model/relationships-test.js index 41b32ebb933..fc62d3a9026 100644 --- a/tests/unit/model/relationships-test.js +++ b/tests/unit/model/relationships-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var run = Ember.run; var Occupation, Person, store; diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index d5c0daf7f03..e3af69c9a8c 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var run = Ember.run; diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index beeef51b733..4763d62422a 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var run = Ember.run; var env; diff --git a/tests/unit/model/relationships/record-array-test.js b/tests/unit/model/relationships/record-array-test.js index bbe730f8f67..ca72f642f5e 100644 --- a/tests/unit/model/relationships/record-array-test.js +++ b/tests/unit/model/relationships/record-array-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var set = Ember.set; var run = Ember.run; diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index c658693a836..1d1ea24d668 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, Person, Dog; var run = Ember.run; diff --git a/tests/unit/promise-proxies-test.js b/tests/unit/promise-proxies-test.js index 4c4f064e5a3..9a5f150b8f3 100644 --- a/tests/unit/promise-proxies-test.js +++ b/tests/unit/promise-proxies-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + module('PromiseManyArray'); test('.reload should NOT leak the internal promise, rather return another promiseArray', function() { diff --git a/tests/unit/record-array-test.js b/tests/unit/record-array-test.js index 45069ff45c2..e976ba9b99c 100644 --- a/tests/unit/record-array-test.js +++ b/tests/unit/record-array-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var Person, array; diff --git a/tests/unit/record-arrays/filtered-record-array-test.js b/tests/unit/record-arrays/filtered-record-array-test.js index baa0448efef..ea7bfdc5677 100644 --- a/tests/unit/record-arrays/filtered-record-array-test.js +++ b/tests/unit/record-arrays/filtered-record-array-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var filteredArray; module("unit/record-arrays/filtered-record-array - DS.FilteredRecordArray", { diff --git a/tests/unit/states-test.js b/tests/unit/states-test.js index 1d2f05fc870..7e700cec57d 100644 --- a/tests/unit/states-test.js +++ b/tests/unit/states-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var rootState, stateName; diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index c5094e6f8b3..872d1b63d2f 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var set = Ember.set; var resolve = Ember.RSVP.resolve; diff --git a/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js index 8f37f1684b7..1e6e18e2658 100644 --- a/tests/unit/store/create-record-test.js +++ b/tests/unit/store/create-record-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var store, container, Record, Storage; var run = Ember.run; diff --git a/tests/unit/store/has-record-for-id-test.js b/tests/unit/store/has-record-for-id-test.js index 8289a2bda9d..ee241abc2f7 100644 --- a/tests/unit/store/has-record-for-id-test.js +++ b/tests/unit/store/has-record-for-id-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, Person, PhoneNumber; var attr = DS.attr; var hasMany = DS.hasMany; diff --git a/tests/unit/store/lookup-test.js b/tests/unit/store/lookup-test.js index 3a5426ea7b8..b9dea9a3c79 100644 --- a/tests/unit/store/lookup-test.js +++ b/tests/unit/store/lookup-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var store, env, applicationAdapter, applicationSerializer, Person; const run = Ember.run; diff --git a/tests/unit/store/model-for-test.js b/tests/unit/store/model-for-test.js index c2c117fba91..3a38f444d93 100644 --- a/tests/unit/store/model-for-test.js +++ b/tests/unit/store/model-for-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var container, store, registry; var camelize = Ember.String.camelize; diff --git a/tests/unit/store/peek-record-test.js b/tests/unit/store/peek-record-test.js index b3e8754d6b1..e404f309739 100644 --- a/tests/unit/store/peek-record-test.js +++ b/tests/unit/store/peek-record-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, Person; var run = Ember.run; diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index f9df4d438eb..af659ea1f22 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var env, store, Person, PhoneNumber, Post; var attr = DS.attr; var hasMany = DS.hasMany; diff --git a/tests/unit/store/serializer-for-test.js b/tests/unit/store/serializer-for-test.js index c525782cd00..1dca0299759 100644 --- a/tests/unit/store/serializer-for-test.js +++ b/tests/unit/store/serializer-for-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var container, store, registry, Person; var run = Ember.run; diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index 17749433328..8c79750a276 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + var get = Ember.get; var run = Ember.run; var store, tryToFind, Record; diff --git a/tests/unit/transform/boolean-test.js b/tests/unit/transform/boolean-test.js index ec1b563a92c..be454239176 100644 --- a/tests/unit/transform/boolean-test.js +++ b/tests/unit/transform/boolean-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + module("unit/transform - DS.BooleanTransform"); test("#serialize", function() { diff --git a/tests/unit/transform/date-test.js b/tests/unit/transform/date-test.js index ce20af6f7c2..5fa25156cc5 100644 --- a/tests/unit/transform/date-test.js +++ b/tests/unit/transform/date-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + module("unit/transform - DS.DateTransform"); var dateString = "2015-01-01T00:00:00.000Z"; diff --git a/tests/unit/transform/number-test.js b/tests/unit/transform/number-test.js index 909d71c1b65..48d1d95bb52 100644 --- a/tests/unit/transform/number-test.js +++ b/tests/unit/transform/number-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + /* jshint -W053 */ module("unit/transform - DS.NumberTransform"); diff --git a/tests/unit/transform/string-test.js b/tests/unit/transform/string-test.js index 80a7d84f39d..386e4706179 100644 --- a/tests/unit/transform/string-test.js +++ b/tests/unit/transform/string-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + module("unit/transform - DS.StringTransform"); test("#serialize", function() { diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index 94053ba4801..52eb013672a 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -1,3 +1,5 @@ +import DS from 'ember-data'; + // TODO enable import once this is possible // import { assertPolymorphicType } from "ember-data/utils"; // import { modelHasAttributeOrRelationshipNamedType } from "ember-data/utils"; From 86e1faf9805c4f1d8944dc5bfdda1981da65b276 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 4 Nov 2015 20:17:25 -0600 Subject: [PATCH 1195/2527] disable FEATURES for now --- addon/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/core.js b/addon/core.js index b1da96fd589..007dfc70ba9 100644 --- a/addon/core.js +++ b/addon/core.js @@ -24,7 +24,7 @@ if (Ember.libraries) { Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); } -var EMBER_DATA_FEATURES = EMBER_DATA_FEATURES_PLACEHOLDER; //jshint ignore: line +// var EMBER_DATA_FEATURES = EMBER_DATA_FEATURES_PLACEHOLDER; //jshint ignore: line Ember.merge(Ember.FEATURES, EMBER_DATA_FEATURES); From bab3c45c943c8eb6d2796e65ed54e6e251174cbe Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 4 Nov 2015 20:25:09 -0600 Subject: [PATCH 1196/2527] add missing import Ember statements --- addon/core.js | 2 +- tests/ember-configuration.js | 2 -- tests/ember-data-setup.js | 2 ++ tests/helpers/custom-adapter.js | 2 ++ tests/integration/adapter/build-url-mixin-test.js | 2 ++ tests/integration/adapter/find-all-test.js | 2 ++ tests/integration/adapter/find-test.js | 2 ++ tests/integration/adapter/json-api-adapter-test.js | 2 ++ tests/integration/adapter/queries-test.js | 2 ++ tests/integration/adapter/record-persistence-test.js | 2 ++ tests/integration/adapter/rest-adapter-test.js | 2 ++ tests/integration/adapter/serialize-test.js | 2 ++ tests/integration/adapter/store-adapter-test.js | 2 ++ tests/integration/application-test.js | 2 ++ .../integration/backwards-compat/non-dasherized-lookups-test.js | 2 ++ tests/integration/client-id-generation-test.js | 2 ++ tests/integration/debug-adapter-test.js | 2 ++ tests/integration/filter-test.js | 2 ++ tests/integration/inverse-test.js | 2 ++ tests/integration/lifecycle-hooks-test.js | 2 ++ tests/integration/multiple_stores_test.js | 2 ++ tests/integration/peek-all-test.js | 2 ++ tests/integration/polymorphic-belongs-to-test.js | 2 ++ tests/integration/record-array-manager-test.js | 2 ++ tests/integration/records/collection-save-test.js | 2 ++ tests/integration/records/delete-record-test.js | 2 ++ tests/integration/records/load-test.js | 2 ++ tests/integration/records/property-changes-test.js | 2 ++ tests/integration/records/reload-test.js | 2 ++ tests/integration/records/save-test.js | 2 ++ tests/integration/records/unload-test.js | 2 ++ tests/integration/relationships/belongs-to-test.js | 2 ++ tests/integration/relationships/has-many-test.js | 2 ++ tests/integration/relationships/inverse-relationships-test.js | 2 ++ tests/integration/relationships/many-to-many-test.js | 2 ++ tests/integration/relationships/one-to-many-test.js | 2 ++ tests/integration/relationships/one-to-one-test.js | 2 ++ .../relationships/polymorphic-mixins-belongs-to-test.js | 2 ++ .../relationships/polymorphic-mixins-has-many-test.js | 2 ++ tests/integration/serializers/embedded-records-mixin-test.js | 2 ++ tests/integration/serializers/json-api-serializer-test.js | 2 ++ tests/integration/serializers/json-serializer-test.js | 2 ++ tests/integration/serializers/rest-serializer-test.js | 2 ++ tests/integration/setup-container-test.js | 2 ++ tests/integration/snapshot-test.js | 2 ++ tests/integration/store-test.js | 2 ++ tests/integration/store/json-api-validation-test.js | 2 ++ tests/integration/store/query-record-test.js | 2 ++ tests/qunit-configuration.js | 2 ++ tests/unit/adapter-errors-test.js | 2 ++ tests/unit/adapter-populated-record-array-test.js | 2 ++ tests/unit/adapters/json-api-adapter/ajax-test.js | 2 ++ tests/unit/adapters/rest-adapter/ajax-test.js | 2 ++ .../adapters/rest-adapter/group-records-for-find-many-test.js | 2 ++ tests/unit/debug-test.js | 2 ++ tests/unit/many-array-test.js | 2 ++ tests/unit/model-test.js | 2 ++ tests/unit/model/lifecycle-callbacks-test.js | 2 ++ tests/unit/model/merge-test.js | 2 ++ tests/unit/model/relationships-test.js | 2 ++ tests/unit/model/relationships/belongs-to-test.js | 2 ++ tests/unit/model/relationships/has-many-test.js | 2 ++ tests/unit/model/relationships/record-array-test.js | 2 ++ tests/unit/model/rollback-attributes-test.js | 2 ++ tests/unit/promise-proxies-test.js | 2 ++ tests/unit/record-array-test.js | 2 ++ tests/unit/states-test.js | 2 ++ tests/unit/store/adapter-interop-test.js | 2 ++ tests/unit/store/create-record-test.js | 2 ++ tests/unit/store/has-record-for-id-test.js | 2 ++ tests/unit/store/lookup-test.js | 2 ++ tests/unit/store/model-for-test.js | 2 ++ tests/unit/store/peek-record-test.js | 2 ++ tests/unit/store/push-test.js | 2 ++ tests/unit/store/serializer-for-test.js | 2 ++ tests/unit/store/unload-test.js | 2 ++ tests/unit/transform/date-test.js | 2 ++ tests/unit/utils-test.js | 2 ++ 78 files changed, 153 insertions(+), 3 deletions(-) diff --git a/addon/core.js b/addon/core.js index 007dfc70ba9..539965386cd 100644 --- a/addon/core.js +++ b/addon/core.js @@ -26,6 +26,6 @@ if (Ember.libraries) { // var EMBER_DATA_FEATURES = EMBER_DATA_FEATURES_PLACEHOLDER; //jshint ignore: line -Ember.merge(Ember.FEATURES, EMBER_DATA_FEATURES); +// Ember.merge(Ember.FEATURES, EMBER_DATA_FEATURES); export default DS; diff --git a/tests/ember-configuration.js b/tests/ember-configuration.js index 9c20aef4fdc..ad317c1bcdf 100644 --- a/tests/ember-configuration.js +++ b/tests/ember-configuration.js @@ -1,5 +1,3 @@ -import DS from 'ember-data'; - /* globals ENV, QUnit */ (function () { diff --git a/tests/ember-data-setup.js b/tests/ember-data-setup.js index a25bf257041..154ff38a8a5 100644 --- a/tests/ember-data-setup.js +++ b/tests/ember-data-setup.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; ;(function() { diff --git a/tests/helpers/custom-adapter.js b/tests/helpers/custom-adapter.js index 050bc3c7929..9272e8d1bbe 100644 --- a/tests/helpers/custom-adapter.js +++ b/tests/helpers/custom-adapter.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index 730a10406a1..9de16b69d17 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, adapter, Post, Comment, SuperUser; diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index 6f289a6802b..0ff433f3520 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 87f1272ef6b..c621ce8354e 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var Person, store, env; diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index 63e6e16614c..f04dd2e2937 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, adapter; diff --git a/tests/integration/adapter/queries-test.js b/tests/integration/adapter/queries-test.js index 6e0771b21fc..86ef97d5a33 100644 --- a/tests/integration/adapter/queries-test.js +++ b/tests/integration/adapter/queries-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/integration/adapter/record-persistence-test.js b/tests/integration/adapter/record-persistence-test.js index f2cb5056229..2e30707faa4 100644 --- a/tests/integration/adapter/record-persistence-test.js +++ b/tests/integration/adapter/record-persistence-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 1d4de9a3644..3689590d413 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, adapter, Post, Comment, SuperUser; diff --git a/tests/integration/adapter/serialize-test.js b/tests/integration/adapter/serialize-test.js index 279df6958e8..e543e5dcfd4 100644 --- a/tests/integration/adapter/serialize-test.js +++ b/tests/integration/adapter/serialize-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var run = Ember.run; diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index cecafc13309..016a76240e9 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; /* diff --git a/tests/integration/application-test.js b/tests/integration/application-test.js index 9e2e619069c..61c99a9651a 100644 --- a/tests/integration/application-test.js +++ b/tests/integration/application-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var run = Ember.run; diff --git a/tests/integration/backwards-compat/non-dasherized-lookups-test.js b/tests/integration/backwards-compat/non-dasherized-lookups-test.js index 3f4dd19b6e0..362a7a20fdb 100644 --- a/tests/integration/backwards-compat/non-dasherized-lookups-test.js +++ b/tests/integration/backwards-compat/non-dasherized-lookups-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; const get = Ember.get; diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index 768703d222e..8cc33184e99 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index 2b1ad368639..68d509db463 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var App, store, debugAdapter; diff --git a/tests/integration/filter-test.js b/tests/integration/filter-test.js index fd13cd5dd68..10c6f62eb72 100644 --- a/tests/integration/filter-test.js +++ b/tests/integration/filter-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; import customAdapter from 'ember-data/tests/helpers/custom-adapter'; diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index dae6735ba61..990db17f4bc 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, User, Job, ReflexiveModel; diff --git a/tests/integration/lifecycle-hooks-test.js b/tests/integration/lifecycle-hooks-test.js index c858941bdb2..5ca507c4afa 100644 --- a/tests/integration/lifecycle-hooks-test.js +++ b/tests/integration/lifecycle-hooks-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var Person, env; diff --git a/tests/integration/multiple_stores_test.js b/tests/integration/multiple_stores_test.js index b286ae9978a..e26e030f952 100644 --- a/tests/integration/multiple_stores_test.js +++ b/tests/integration/multiple_stores_test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env; diff --git a/tests/integration/peek-all-test.js b/tests/integration/peek-all-test.js index cfedf7a0686..fa0fe205778 100644 --- a/tests/integration/peek-all-test.js +++ b/tests/integration/peek-all-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/integration/polymorphic-belongs-to-test.js b/tests/integration/polymorphic-belongs-to-test.js index 8ee053c9ab3..97c0ced2537 100644 --- a/tests/integration/polymorphic-belongs-to-test.js +++ b/tests/integration/polymorphic-belongs-to-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; const {attr, belongsTo} = DS; diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index 2ed69e08f24..a1d322a8247 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var store, env; diff --git a/tests/integration/records/collection-save-test.js b/tests/integration/records/collection-save-test.js index 8c547ddb711..64e9375206a 100644 --- a/tests/integration/records/collection-save-test.js +++ b/tests/integration/records/collection-save-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var Post, env; diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index a5681a220bf..4aed2a16021 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var attr = DS.attr; diff --git a/tests/integration/records/load-test.js b/tests/integration/records/load-test.js index 68b1f54a0a4..1085d935a27 100644 --- a/tests/integration/records/load-test.js +++ b/tests/integration/records/load-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var hasMany = DS.hasMany; diff --git a/tests/integration/records/property-changes-test.js b/tests/integration/records/property-changes-test.js index 97c344b6cc1..4b961ef2a84 100644 --- a/tests/integration/records/property-changes-test.js +++ b/tests/integration/records/property-changes-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, Person; diff --git a/tests/integration/records/reload-test.js b/tests/integration/records/reload-test.js index 1186a991086..c769a177fde 100644 --- a/tests/integration/records/reload-test.js +++ b/tests/integration/records/reload-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/integration/records/save-test.js b/tests/integration/records/save-test.js index d09fd668a65..aac9e9ce51a 100644 --- a/tests/integration/records/save-test.js +++ b/tests/integration/records/save-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var Post, env; diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 07235dc479c..ebdb1176f65 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var attr = DS.attr; diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index d2906789010..d6084666494 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, User, Message, Post, Contact, Comment, Book, Chapter, Author, NewMessage; diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 52fcd6716c6..a8cda0451f1 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, User, Contact, Email, Phone, Message, Post, Comment; diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index afca1c137b9..c32bdaf7d4a 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var Post, Comment, Message, User; diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index 98b8b0f36f4..ad25817e272 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var Account, Topic, User, store, env; diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index 222001933ae..6d9d6412ae7 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, User, Message, Account; diff --git a/tests/integration/relationships/one-to-one-test.js b/tests/integration/relationships/one-to-one-test.js index 8026c156a4e..4f9ca56d74e 100644 --- a/tests/integration/relationships/one-to-one-test.js +++ b/tests/integration/relationships/one-to-one-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, User, Job; diff --git a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index 194154e2307..061629789b6 100644 --- a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, User, Message, Video, NotMessage; diff --git a/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js index a7e38229a07..a4a770e9ef0 100644 --- a/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, User, Message, NotMessage, Video; diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index 9d7dfb5c7eb..8236836c441 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 68d3fa2babc..a99d1712c40 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, serializer; diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index c891ab72389..85512cc415a 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var Post, post, Comment, comment, Favorite, favorite, env; diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 274acbe9cdc..7fb87ffdbbb 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var HomePlanet, league, SuperVillain, EvilMinion, YellowMinion, DoomsdayDevice, Comment, Basket, Container, env; diff --git a/tests/integration/setup-container-test.js b/tests/integration/setup-container-test.js index c4a1d2f06b3..9ef73823df7 100644 --- a/tests/integration/setup-container-test.js +++ b/tests/integration/setup-container-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var run = Ember.run; diff --git a/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js index 71ba3aacbf7..55e39e37087 100644 --- a/tests/integration/snapshot-test.js +++ b/tests/integration/snapshot-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var run = Ember.run; diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index c8e6174e3b7..c113564e8e1 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var store, env; diff --git a/tests/integration/store/json-api-validation-test.js b/tests/integration/store/json-api-validation-test.js index 789d2b1669a..6a405432858 100644 --- a/tests/integration/store/json-api-validation-test.js +++ b/tests/integration/store/json-api-validation-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var Person, store, env; diff --git a/tests/integration/store/query-record-test.js b/tests/integration/store/query-record-test.js index 0a01da7973b..d7f022f0708 100644 --- a/tests/integration/store/query-record-test.js +++ b/tests/integration/store/query-record-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var Person, store, env; diff --git a/tests/qunit-configuration.js b/tests/qunit-configuration.js index 7d6df605fce..1f62492f8e7 100644 --- a/tests/qunit-configuration.js +++ b/tests/qunit-configuration.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + (function() { /*global namespace: true */ diff --git a/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js index cf8f596b822..f443672c1db 100644 --- a/tests/unit/adapter-errors-test.js +++ b/tests/unit/adapter-errors-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; module("unit/adapter-errors - DS.AdapterError"); diff --git a/tests/unit/adapter-populated-record-array-test.js b/tests/unit/adapter-populated-record-array-test.js index ba6d859aab1..76195eca3da 100644 --- a/tests/unit/adapter-populated-record-array-test.js +++ b/tests/unit/adapter-populated-record-array-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var Person, store; diff --git a/tests/unit/adapters/json-api-adapter/ajax-test.js b/tests/unit/adapters/json-api-adapter/ajax-test.js index c4be843178a..5a05c4d0eb2 100644 --- a/tests/unit/adapters/json-api-adapter/ajax-test.js +++ b/tests/unit/adapters/json-api-adapter/ajax-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var Person, Place, store, adapter, env; diff --git a/tests/unit/adapters/rest-adapter/ajax-test.js b/tests/unit/adapters/rest-adapter/ajax-test.js index bbbf3df1dac..b11c9b4a68c 100644 --- a/tests/unit/adapters/rest-adapter/ajax-test.js +++ b/tests/unit/adapters/rest-adapter/ajax-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var Person, Place, store, adapter, env; diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 59d1f4498da..4c6f105f001 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var GroupsAdapter, Store; diff --git a/tests/unit/debug-test.js b/tests/unit/debug-test.js index d19d10c81fd..fada4dff728 100644 --- a/tests/unit/debug-test.js +++ b/tests/unit/debug-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var run = Ember.run; diff --git a/tests/unit/many-array-test.js b/tests/unit/many-array-test.js index 6ad19dd9673..3d13084be21 100644 --- a/tests/unit/many-array-test.js +++ b/tests/unit/many-array-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store; diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 3510876d69f..39762ca084f 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index e4b5a15730c..a399586b212 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/unit/model/merge-test.js b/tests/unit/model/merge-test.js index d3af592c07e..31b0dfb6002 100644 --- a/tests/unit/model/merge-test.js +++ b/tests/unit/model/merge-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var Person; diff --git a/tests/unit/model/relationships-test.js b/tests/unit/model/relationships-test.js index fc62d3a9026..1e6fc089682 100644 --- a/tests/unit/model/relationships-test.js +++ b/tests/unit/model/relationships-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index e3af69c9a8c..12eacfdbd20 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 4763d62422a..ac92ceb8874 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/unit/model/relationships/record-array-test.js b/tests/unit/model/relationships/record-array-test.js index ca72f642f5e..f22c0390a8d 100644 --- a/tests/unit/model/relationships/record-array-test.js +++ b/tests/unit/model/relationships/record-array-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index 1d1ea24d668..64067ce3f37 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, Person, Dog; diff --git a/tests/unit/promise-proxies-test.js b/tests/unit/promise-proxies-test.js index 9a5f150b8f3..a393a56e4e6 100644 --- a/tests/unit/promise-proxies-test.js +++ b/tests/unit/promise-proxies-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; module('PromiseManyArray'); diff --git a/tests/unit/record-array-test.js b/tests/unit/record-array-test.js index e976ba9b99c..64331cbad42 100644 --- a/tests/unit/record-array-test.js +++ b/tests/unit/record-array-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/unit/states-test.js b/tests/unit/states-test.js index 7e700cec57d..9b9ade11f48 100644 --- a/tests/unit/states-test.js +++ b/tests/unit/states-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index 872d1b63d2f..f855c3adaa3 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js index 1e6e18e2658..1b906374062 100644 --- a/tests/unit/store/create-record-test.js +++ b/tests/unit/store/create-record-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var store, container, Record, Storage; diff --git a/tests/unit/store/has-record-for-id-test.js b/tests/unit/store/has-record-for-id-test.js index ee241abc2f7..11e025e3d6d 100644 --- a/tests/unit/store/has-record-for-id-test.js +++ b/tests/unit/store/has-record-for-id-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, Person, PhoneNumber; diff --git a/tests/unit/store/lookup-test.js b/tests/unit/store/lookup-test.js index b9dea9a3c79..9284f76f95e 100644 --- a/tests/unit/store/lookup-test.js +++ b/tests/unit/store/lookup-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var store, env, applicationAdapter, applicationSerializer, Person; diff --git a/tests/unit/store/model-for-test.js b/tests/unit/store/model-for-test.js index 3a38f444d93..6b7ecdda20a 100644 --- a/tests/unit/store/model-for-test.js +++ b/tests/unit/store/model-for-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var container, store, registry; diff --git a/tests/unit/store/peek-record-test.js b/tests/unit/store/peek-record-test.js index e404f309739..ab9dd43085f 100644 --- a/tests/unit/store/peek-record-test.js +++ b/tests/unit/store/peek-record-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, Person; diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index af659ea1f22..60de010d15e 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var env, store, Person, PhoneNumber, Post; diff --git a/tests/unit/store/serializer-for-test.js b/tests/unit/store/serializer-for-test.js index 1dca0299759..87a8e3faf4f 100644 --- a/tests/unit/store/serializer-for-test.js +++ b/tests/unit/store/serializer-for-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var container, store, registry, Person; diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index 8c79750a276..f285975e95a 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; var get = Ember.get; diff --git a/tests/unit/transform/date-test.js b/tests/unit/transform/date-test.js index 5fa25156cc5..27ac00ea516 100644 --- a/tests/unit/transform/date-test.js +++ b/tests/unit/transform/date-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; module("unit/transform - DS.DateTransform"); diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index 52eb013672a..8fe478142e5 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + import DS from 'ember-data'; // TODO enable import once this is possible From 4e4c63bbeebd29c7a7e8eb1447b3259878b1a301 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 4 Nov 2015 20:26:22 -0600 Subject: [PATCH 1197/2527] upgrade qunit tests to use ember-qunit/ES6 --- package.json | 5 +- .../adapter/build-url-mixin-test.js | 58 +- tests/integration/adapter/find-all-test.js | 50 +- tests/integration/adapter/find-test.js | 46 +- .../adapter/json-api-adapter-test.js | 262 +++---- tests/integration/adapter/queries-test.js | 22 +- .../adapter/record-persistence-test.js | 76 ++- .../integration/adapter/rest-adapter-test.js | 638 +++++++++--------- tests/integration/adapter/serialize-test.js | 12 +- .../integration/adapter/store-adapter-test.js | 422 ++++++------ tests/integration/application-test.js | 66 +- .../non-dasherized-lookups-test.js | 34 +- .../integration/client-id-generation-test.js | 32 +- tests/integration/debug-adapter-test.js | 56 +- tests/integration/filter-test.js | 154 ++--- tests/integration/inverse-test.js | 32 +- tests/integration/lifecycle-hooks-test.js | 24 +- tests/integration/peek-all-test.js | 28 +- .../polymorphic-belongs-to-test.js | 14 +- .../integration/record-array-manager-test.js | 48 +- .../records/collection-save-test.js | 26 +- .../integration/records/delete-record-test.js | 32 +- tests/integration/records/load-test.js | 10 +- .../records/property-changes-test.js | 38 +- tests/integration/records/reload-test.js | 54 +- tests/integration/records/save-test.js | 60 +- tests/integration/records/unload-test.js | 48 +- .../relationships/belongs-to-test.js | 208 +++--- .../relationships/has-many-test.js | 468 ++++++------- .../inverse-relationships-test.js | 172 ++--- .../relationships/many-to-many-test.js | 88 +-- .../relationships/one-to-many-test.js | 170 ++--- .../relationships/one-to-one-test.js | 120 ++-- .../polymorphic-mixins-belongs-to-test.js | 30 +- .../polymorphic-mixins-has-many-test.js | 24 +- .../embedded-records-mixin-test.js | 160 ++--- .../serializers/json-api-serializer-test.js | 32 +- .../serializers/json-serializer-test.js | 204 +++--- .../serializers/rest-serializer-test.js | 154 ++--- tests/integration/setup-container-test.js | 26 +- tests/integration/snapshot-test.js | 246 +++---- tests/integration/store-test.js | 136 ++-- .../store/json-api-validation-test.js | 36 +- tests/integration/store/query-record-test.js | 26 +- tests/unit/adapter-errors-test.js | 40 +- .../adapter-populated-record-array-test.js | 14 +- .../build-url-mixin/path-for-type-test.js | 130 ++-- .../adapters/json-api-adapter/ajax-test.js | 18 +- tests/unit/adapters/rest-adapter/ajax-test.js | 36 +- .../group-records-for-find-many-test.js | 8 +- tests/unit/debug-test.js | 12 +- tests/unit/many-array-test.js | 24 +- tests/unit/model-test.js | 296 ++++---- tests/unit/model/errors-test.js | 78 +-- tests/unit/model/internal-model-test.js | 6 +- tests/unit/model/lifecycle-callbacks-test.js | 92 +-- tests/unit/model/merge-test.js | 92 +-- tests/unit/model/relationships-test.js | 18 +- .../model/relationships/belongs-to-test.js | 84 +-- .../unit/model/relationships/has-many-test.js | 140 ++-- .../model/relationships/record-array-test.js | 18 +- tests/unit/model/rollback-attributes-test.js | 184 ++--- tests/unit/promise-proxies-test.js | 10 +- tests/unit/record-array-test.js | 88 +-- .../filtered-record-array-test.js | 8 +- tests/unit/states-test.js | 24 +- tests/unit/store/adapter-interop-test.js | 326 ++++----- tests/unit/store/create-record-test.js | 30 +- tests/unit/store/has-record-for-id-test.js | 14 +- tests/unit/store/lookup-test.js | 30 +- tests/unit/store/model-for-test.js | 22 +- tests/unit/store/peek-record-test.js | 14 +- tests/unit/store/push-test.js | 156 ++--- tests/unit/store/serializer-for-test.js | 20 +- tests/unit/store/unload-test.js | 32 +- tests/unit/transform/boolean-test.js | 48 +- tests/unit/transform/date-test.js | 22 +- tests/unit/transform/number-test.js | 38 +- tests/unit/transform/string-test.js | 22 +- tests/unit/utils-test.js | 51 +- 80 files changed, 3525 insertions(+), 3367 deletions(-) diff --git a/package.json b/package.json index 5c8e376ef15..93bfcd190de 100644 --- a/package.json +++ b/package.json @@ -31,10 +31,11 @@ "ember-cli-release": "0.2.3", "ember-cli-sri": "^1.0.3", "ember-cli-uglify": "^1.2.0", + "ember-disable-prototype-extensions": "^1.0.0", "ember-disable-proxy-controllers": "^1.0.0", "ember-export-application-global": "^1.0.3", - "ember-disable-prototype-extensions": "^1.0.0", - "ember-try": "0.0.6" + "ember-try": "0.0.6", + "ember-watson": "^0.7.0" }, "keywords": [ "ember-addon" diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index 9de16b69d17..fb37baf242a 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, adapter, Post, Comment, SuperUser; @@ -7,7 +9,7 @@ var passedUrl; var run = Ember.run; module("integration/adapter/build-url-mixin - BuildURLMixin with RESTAdapter", { - setup: function() { + beforeEach: function() { Post = DS.Model.extend({ name: DS.attr("string") }); @@ -49,7 +51,7 @@ function ajaxResponse(value) { } -test('buildURL - with host and namespace', function() { +test('buildURL - with host and namespace', function(assert) { run(function() { adapter.setProperties({ host: 'http://example.com', @@ -60,11 +62,11 @@ test('buildURL - with host and namespace', function() { ajaxResponse({ posts: [{ id: 1 }] }); run(store, 'findRecord', 'post', 1).then(async(function(post) { - equal(passedUrl, "http://example.com/api/v1/posts/1"); + assert.equal(passedUrl, "http://example.com/api/v1/posts/1"); })); }); -test('buildURL - with relative paths in links', function() { +test('buildURL - with relative paths in links', function(assert) { run(function() { adapter.setProperties({ host: 'http://example.com', @@ -80,11 +82,11 @@ test('buildURL - with relative paths in links', function() { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); })).then(async(function (comments) { - equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); + assert.equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); })); }); -test('buildURL - with absolute paths in links', function() { +test('buildURL - with absolute paths in links', function(assert) { run(function() { adapter.setProperties({ host: 'http://example.com', @@ -100,12 +102,12 @@ test('buildURL - with absolute paths in links', function() { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); })).then(async(function (comments) { - equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); + assert.equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); })); }); -test('buildURL - with absolute paths in links and protocol relative host', function() { +test('buildURL - with absolute paths in links and protocol relative host', function(assert) { run(function() { adapter.setProperties({ host: '//example.com', @@ -121,11 +123,11 @@ test('buildURL - with absolute paths in links and protocol relative host', funct ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); })).then(async(function (comments) { - equal(passedUrl, "//example.com/api/v1/posts/1/comments"); + assert.equal(passedUrl, "//example.com/api/v1/posts/1/comments"); })); }); -test('buildURL - with full URLs in links', function() { +test('buildURL - with full URLs in links', function(assert) { adapter.setProperties({ host: 'http://example.com', namespace: 'api/v1' @@ -146,12 +148,12 @@ test('buildURL - with full URLs in links', function() { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); })).then(async(function (comments) { - equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); + assert.equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); })); }); }); -test('buildURL - with camelized names', function() { +test('buildURL - with camelized names', function(assert) { adapter.setProperties({ pathForType: function(type) { var decamelized = Ember.String.decamelize(type); @@ -163,12 +165,12 @@ test('buildURL - with camelized names', function() { run(function() { store.findRecord('super-user', 1).then(async(function(post) { - equal(passedUrl, "/super_users/1"); + assert.equal(passedUrl, "/super_users/1"); })); }); }); -test('buildURL - buildURL takes a record from find', function() { +test('buildURL - buildURL takes a record from find', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); adapter.buildURL = function(type, id, snapshot) { return "/posts/" + snapshot.belongsTo('post', { id: true }) + '/comments/' + snapshot.id; @@ -188,12 +190,12 @@ test('buildURL - buildURL takes a record from find', function() { run(function() { store.findRecord('comment', 1, { preload: { post: post } }).then(async(function(post) { - equal(passedUrl, "/posts/2/comments/1"); + assert.equal(passedUrl, "/posts/2/comments/1"); })); }); }); -test('buildURL - buildURL takes the records from findMany', function() { +test('buildURL - buildURL takes the records from findMany', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -225,12 +227,12 @@ test('buildURL - buildURL takes the records from findMany', function() { } }); post.get('comments').then(async(function(post) { - equal(passedUrl, "/posts/2/comments/"); + assert.equal(passedUrl, "/posts/2/comments/"); })); }); }); -test('buildURL - buildURL takes a record from create', function() { +test('buildURL - buildURL takes a record from create', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); adapter.buildURL = function(type, id, snapshot) { return "/posts/" + snapshot.belongsTo('post', { id: true }) + '/comments/'; @@ -248,19 +250,19 @@ test('buildURL - buildURL takes a record from create', function() { var comment = store.createRecord('comment'); comment.set('post', post); comment.save().then(async(function(post) { - equal(passedUrl, "/posts/2/comments/"); + assert.equal(passedUrl, "/posts/2/comments/"); })); }); }); -test('buildURL - buildURL takes a record from create to query a resolved async belongsTo relationship', function() { +test('buildURL - buildURL takes a record from create to query a resolved async belongsTo relationship', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: true }) }); ajaxResponse({ posts: [{ id: 2 }] }); run(function() { store.findRecord('post', 2).then(async(function(post) { - equal(post.get('id'), 2); + assert.equal(post.get('id'), 2); adapter.buildURL = function(type, id, snapshot) { return "/posts/" + snapshot.belongsTo('post', { id: true }) + '/comments/'; @@ -271,14 +273,14 @@ test('buildURL - buildURL takes a record from create to query a resolved async b var comment = store.createRecord('comment'); comment.set('post', post); comment.save().then(async(function(post) { - equal(passedUrl, "/posts/2/comments/"); + assert.equal(passedUrl, "/posts/2/comments/"); })); })); }); }); -test('buildURL - buildURL takes a record from update', function() { +test('buildURL - buildURL takes a record from update', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); adapter.buildURL = function(type, id, snapshot) { return "/posts/" + snapshot.belongsTo('post', { id: true }) + '/comments/' + snapshot.id; @@ -304,12 +306,12 @@ test('buildURL - buildURL takes a record from update', function() { }); run(function() { comment.save().then(async(function(post) { - equal(passedUrl, "/posts/2/comments/1"); + assert.equal(passedUrl, "/posts/2/comments/1"); })); }); }); -test('buildURL - buildURL takes a record from delete', function() { +test('buildURL - buildURL takes a record from delete', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); adapter.buildURL = function(type, id, snapshot) { @@ -338,12 +340,12 @@ test('buildURL - buildURL takes a record from delete', function() { }); run(function() { comment.save().then(async(function(post) { - equal(passedUrl, "posts/2/comments/1"); + assert.equal(passedUrl, "posts/2/comments/1"); })); }); }); -test('buildURL - with absolute namespace', function() { +test('buildURL - with absolute namespace', function(assert) { run(function() { adapter.setProperties({ namespace: '/api/v1' @@ -353,6 +355,6 @@ test('buildURL - with absolute namespace', function() { ajaxResponse({ posts: [{ id: 1 }] }); run(store, 'findRecord', 'post', 1).then(async(function(post) { - equal(passedUrl, "/api/v1/posts/1"); + assert.equal(passedUrl, "/api/v1/posts/1"); })); }); diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index 0ff433f3520..001267b6cdc 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -8,7 +10,7 @@ var run = Ember.run; var env; module("integration/adapter/find_all - Finding All Records of a Type", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ updatedAt: DS.attr('string'), name: DS.attr('string'), @@ -24,7 +26,7 @@ module("integration/adapter/find_all - Finding All Records of a Type", { store = env.store; }, - teardown: function() { + afterEach: function() { run(function() { if (allRecords) { allRecords.destroy(); } store.destroy(); @@ -32,13 +34,13 @@ module("integration/adapter/find_all - Finding All Records of a Type", { } }); -test("When all records for a type are requested, the store should call the adapter's `findAll` method.", function() { - expect(5); +test("When all records for a type are requested, the store should call the adapter's `findAll` method.", function(assert) { + assert.expect(5); env.registry.register('adapter:person', DS.Adapter.extend({ findAll: function(store, type, since) { // this will get called twice - ok(true, "the adapter's findAll method should be invoked"); + assert.ok(true, "the adapter's findAll method should be invoked"); return Ember.RSVP.resolve([{ id: 1, name: "Braaaahm Dale" }]); } @@ -49,27 +51,27 @@ test("When all records for a type are requested, the store should call the adapt run(function() { store.findAll('person').then(function(all) { allRecords = all; - equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); - equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); + assert.equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); + assert.equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); }); }); run(function() { store.findAll('person').then(function(all) { // Only one record array per type should ever be created (identity map) - strictEqual(allRecords, all, "the same record array is returned every time all records of a type are requested"); + assert.strictEqual(allRecords, all, "the same record array is returned every time all records of a type are requested"); }); }); }); -test("When all records for a type are requested, a rejection should reject the promise", function() { - expect(5); +test("When all records for a type are requested, a rejection should reject the promise", function(assert) { + assert.expect(5); var count = 0; env.registry.register('adapter:person', DS.Adapter.extend({ findAll: function(store, type, since) { // this will get called twice - ok(true, "the adapter's findAll method should be invoked"); + assert.ok(true, "the adapter's findAll method should be invoked"); if (count++ === 0) { return Ember.RSVP.reject(); @@ -83,18 +85,18 @@ test("When all records for a type are requested, a rejection should reject the p run(function() { store.findAll('person').then(null, function() { - ok(true, "The rejection should get here"); + assert.ok(true, "The rejection should get here"); return store.findAll('person'); }).then(function(all) { allRecords = all; - equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); - equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); + assert.equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); + assert.equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); }); }); }); -test("When all records for a type are requested, records that are already loaded should be returned immediately.", function() { - expect(3); +test("When all records for a type are requested, records that are already loaded should be returned immediately.", function(assert) { + assert.expect(3); store = createStore({ adapter: DS.Adapter.extend(), person: Person @@ -117,13 +119,13 @@ test("When all records for a type are requested, records that are already loaded allRecords = store.peekAll('person'); - equal(get(allRecords, 'length'), 2, "the record array's length is 2"); - equal(allRecords.objectAt(0).get('name'), "Jeremy Ashkenas", "the first item in the record array is Jeremy Ashkenas"); - equal(allRecords.objectAt(1).get('name'), "Alex MacCaw", "the second item in the record array is Alex MacCaw"); + assert.equal(get(allRecords, 'length'), 2, "the record array's length is 2"); + assert.equal(allRecords.objectAt(0).get('name'), "Jeremy Ashkenas", "the first item in the record array is Jeremy Ashkenas"); + assert.equal(allRecords.objectAt(1).get('name'), "Alex MacCaw", "the second item in the record array is Alex MacCaw"); }); -test("When all records for a type are requested, records that are created on the client should be added to the record array.", function() { - expect(3); +test("When all records for a type are requested, records that are created on the client should be added to the record array.", function(assert) { + assert.expect(3); store = createStore({ adapter: DS.Adapter.extend(), @@ -132,12 +134,12 @@ test("When all records for a type are requested, records that are created on the allRecords = store.peekAll('person'); - equal(get(allRecords, 'length'), 0, "precond - the record array's length is zero before any records are loaded"); + assert.equal(get(allRecords, 'length'), 0, "precond - the record array's length is zero before any records are loaded"); run(function() { store.createRecord('person', { name: "Carsten Nielsen" }); }); - equal(get(allRecords, 'length'), 1, "the record array's length is 1"); - equal(allRecords.objectAt(0).get('name'), "Carsten Nielsen", "the first item in the record array is Carsten Nielsen"); + assert.equal(get(allRecords, 'length'), 1, "the record array's length is 1"); + assert.equal(allRecords.objectAt(0).get('name'), "Carsten Nielsen", "the first item in the record array is Carsten Nielsen"); }); diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index c621ce8354e..009adad24fc 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var Person, store, env; var run = Ember.run; module("integration/adapter/find - Finding Records", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ updatedAt: DS.attr('string'), name: DS.attr('string'), @@ -20,12 +22,12 @@ module("integration/adapter/find - Finding Records", { store = env.store; }, - teardown: function() { + afterEach: function() { run(store, 'destroy'); } }); -test("It raises an assertion when `undefined` is passed as id (#1705)", function() { +test("It raises an assertion when `undefined` is passed as id (#1705)", function(assert) { expectAssertion(function() { store.find('person', undefined); }, "You cannot pass `undefined` as id to the store's find method"); @@ -35,15 +37,15 @@ test("It raises an assertion when `undefined` is passed as id (#1705)", function }, "You cannot pass `null` as id to the store's find method"); }); -test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function() { - expect(2); +test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function(assert) { + assert.expect(2); var count = 0; env.registry.register('adapter:person', DS.Adapter.extend({ findRecord: function(store, type, id, snapshot) { - equal(type, Person, "the find method is called with the correct type"); - equal(count, 0, "the find method is only called once"); + assert.equal(type, Person, "the find method is called with the correct type"); + assert.equal(count, 0, "the find method is only called once"); count++; return { id: 1, name: "Braaaahm Dale" }; @@ -56,7 +58,7 @@ test("When a single record is requested, the adapter's find method should be cal }); }); -test("When a single record is requested multiple times, all .find() calls are resolved after the promise is resolved", function() { +test("When a single record is requested multiple times, all .find() calls are resolved after the promise is resolved", function(assert) { var deferred = Ember.RSVP.defer(); env.registry.register('adapter:person', DS.Adapter.extend({ @@ -67,32 +69,32 @@ test("When a single record is requested multiple times, all .find() calls are re run(function() { store.findRecord('person', 1).then(async(function(person) { - equal(person.get('id'), "1"); - equal(person.get('name'), "Braaaahm Dale"); + assert.equal(person.get('id'), "1"); + assert.equal(person.get('name'), "Braaaahm Dale"); stop(); deferred.promise.then(function(value) { start(); - ok(true, 'expected deferred.promise to fulfill'); + assert.ok(true, 'expected deferred.promise to fulfill'); }, function(reason) { start(); - ok(false, 'expected deferred.promise to fulfill, but rejected'); + assert.ok(false, 'expected deferred.promise to fulfill, but rejected'); }); })); }); run(function() { store.findRecord('person', 1).then(async(function(post) { - equal(post.get('id'), "1"); - equal(post.get('name'), "Braaaahm Dale"); + assert.equal(post.get('id'), "1"); + assert.equal(post.get('name'), "Braaaahm Dale"); stop(); deferred.promise.then(function(value) { start(); - ok(true, 'expected deferred.promise to fulfill'); + assert.ok(true, 'expected deferred.promise to fulfill'); }, function(reason) { start(); - ok(false, 'expected deferred.promise to fulfill, but rejected'); + assert.ok(false, 'expected deferred.promise to fulfill, but rejected'); }); })); @@ -103,7 +105,7 @@ test("When a single record is requested multiple times, all .find() calls are re }); }); -test("When a single record is requested, and the promise is rejected, .find() is rejected.", function() { +test("When a single record is requested, and the promise is rejected, .find() is rejected.", function(assert) { env.registry.register('adapter:person', DS.Adapter.extend({ findRecord: function(store, type, id, snapshot) { return Ember.RSVP.reject(); @@ -112,13 +114,13 @@ test("When a single record is requested, and the promise is rejected, .find() is run(function() { store.findRecord('person', 1).then(null, async(function(reason) { - ok(true, "The rejection handler was called"); + assert.ok(true, "The rejection handler was called"); })); }); }); -test("When a single record is requested, and the promise is rejected, the record should be unloaded.", function() { - expect(2); +test("When a single record is requested, and the promise is rejected, the record should be unloaded.", function(assert) { + assert.expect(2); env.registry.register('adapter:person', DS.Adapter.extend({ findRecord: function(store, type, id, snapshot) { @@ -128,9 +130,9 @@ test("When a single record is requested, and the promise is rejected, the record run(function() { store.findRecord('person', 1).then(null, async(function(reason) { - ok(true, "The rejection handler was called"); + assert.ok(true, "The rejection handler was called"); })); }); - ok(!store.hasRecordForId('person', 1), "The record has been unloaded"); + assert.ok(!store.hasRecordForId('person', 1), "The record has been unloaded"); }); diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index f04dd2e2937..b6e772a2092 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, adapter; @@ -10,7 +12,7 @@ var run = Ember.run; var User, Post, Comment, Handle, GithubHandle, TwitterHandle, Company, DevelopmentShop, DesignStudio; module('integration/adapter/json-api-adapter - JSONAPIAdapter', { - setup: function() { + beforeEach: function() { User = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), @@ -73,7 +75,7 @@ module('integration/adapter/json-api-adapter - JSONAPIAdapter', { adapter = env.adapter; }, - teardown: function() { + afterEach: function() { run(env.store, 'destroy'); } }); @@ -97,8 +99,8 @@ function ajaxResponse(responses) { }; } -test('find a single record', function() { - expect(3); +test('find a single record', function(assert) { + assert.expect(3); ajaxResponse([{ data: { @@ -112,16 +114,16 @@ test('find a single record', function() { run(function() { store.find('post', 1).then(function(post) { - equal(passedUrl[0], '/posts/1'); + assert.equal(passedUrl[0], '/posts/1'); - equal(post.get('id'), '1'); - equal(post.get('title'), 'Ember.js rocks'); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('title'), 'Ember.js rocks'); }); }); }); -test('find all records with sideloaded relationships', function() { - expect(9); +test('find all records with sideloaded relationships', function(assert) { + assert.expect(9); ajaxResponse([{ data: [{ @@ -177,25 +179,25 @@ test('find all records with sideloaded relationships', function() { run(function() { store.findAll('post').then(function(posts) { - equal(passedUrl[0], '/posts'); + assert.equal(passedUrl[0], '/posts'); - equal(posts.get('length'), '2'); - equal(posts.get('firstObject.title'), 'Ember.js rocks'); - equal(posts.get('lastObject.title'), 'Tomster rules'); + assert.equal(posts.get('length'), '2'); + assert.equal(posts.get('firstObject.title'), 'Ember.js rocks'); + assert.equal(posts.get('lastObject.title'), 'Tomster rules'); - equal(posts.get('firstObject.author.firstName'), 'Yehuda'); - equal(posts.get('lastObject.author.lastName'), 'Katz'); + assert.equal(posts.get('firstObject.author.firstName'), 'Yehuda'); + assert.equal(posts.get('lastObject.author.lastName'), 'Katz'); - equal(posts.get('firstObject.comments.length'), 0); + assert.equal(posts.get('firstObject.comments.length'), 0); - equal(posts.get('lastObject.comments.firstObject.text'), 'This is the first comment'); - equal(posts.get('lastObject.comments.lastObject.text'), 'This is the second comment'); + assert.equal(posts.get('lastObject.comments.firstObject.text'), 'This is the first comment'); + assert.equal(posts.get('lastObject.comments.lastObject.text'), 'This is the second comment'); }); }); }); -test('find many records', function() { - expect(4); +test('find many records', function(assert) { + assert.expect(4); ajaxResponse([{ data: [{ @@ -209,17 +211,17 @@ test('find many records', function() { run(function() { store.query('post', { filter: { id: 1 } }).then(function(posts) { - equal(passedUrl[0], '/posts'); - deepEqual(passedHash[0], { data: { filter: { id: 1 } } }); + assert.equal(passedUrl[0], '/posts'); + assert.deepEqual(passedHash[0], { data: { filter: { id: 1 } } }); - equal(posts.get('length'), '1'); - equal(posts.get('firstObject.title'), 'Ember.js rocks'); + assert.equal(posts.get('length'), '1'); + assert.equal(posts.get('firstObject.title'), 'Ember.js rocks'); }); }); }); -test('find a single record with belongsTo link as object { related }', function() { - expect(7); +test('find a single record with belongsTo link as object { related }', function(assert) { + assert.expect(7); ajaxResponse([{ data: { @@ -249,24 +251,24 @@ test('find a single record with belongsTo link as object { related }', function( run(function() { store.find('post', 1).then(function(post) { - equal(passedUrl[0], '/posts/1'); + assert.equal(passedUrl[0], '/posts/1'); - equal(post.get('id'), '1'); - equal(post.get('title'), 'Ember.js rocks'); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('title'), 'Ember.js rocks'); post.get('author').then(function(author) { - equal(passedUrl[1], 'http://example.com/user/2'); + assert.equal(passedUrl[1], 'http://example.com/user/2'); - equal(author.get('id'), '2'); - equal(author.get('firstName'), 'Yehuda'); - equal(author.get('lastName'), 'Katz'); + assert.equal(author.get('id'), '2'); + assert.equal(author.get('firstName'), 'Yehuda'); + assert.equal(author.get('lastName'), 'Katz'); }); }); }); }); -test('find a single record with belongsTo link as object { data }', function() { - expect(7); +test('find a single record with belongsTo link as object { data }', function(assert) { + assert.expect(7); ajaxResponse([{ data: { @@ -294,24 +296,24 @@ test('find a single record with belongsTo link as object { data }', function() { run(function() { store.find('post', 1).then(function(post) { - equal(passedUrl[0], '/posts/1'); + assert.equal(passedUrl[0], '/posts/1'); - equal(post.get('id'), '1'); - equal(post.get('title'), 'Ember.js rocks'); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('title'), 'Ember.js rocks'); post.get('author').then(function(author) { - equal(passedUrl[1], '/users/2'); + assert.equal(passedUrl[1], '/users/2'); - equal(author.get('id'), '2'); - equal(author.get('firstName'), 'Yehuda'); - equal(author.get('lastName'), 'Katz'); + assert.equal(author.get('id'), '2'); + assert.equal(author.get('firstName'), 'Yehuda'); + assert.equal(author.get('lastName'), 'Katz'); }); }); }); }); -test('find a single record with belongsTo link as object { data } (polymorphic)', function() { - expect(8); +test('find a single record with belongsTo link as object { data } (polymorphic)', function(assert) { + assert.expect(8); ajaxResponse([{ data: { @@ -340,25 +342,25 @@ test('find a single record with belongsTo link as object { data } (polymorphic)' run(function() { store.find('user', 1).then(function(user) { - equal(passedUrl[0], '/users/1'); + assert.equal(passedUrl[0], '/users/1'); - equal(user.get('id'), '1'); - equal(user.get('firstName'), 'Yehuda'); - equal(user.get('lastName'), 'Katz'); + assert.equal(user.get('id'), '1'); + assert.equal(user.get('firstName'), 'Yehuda'); + assert.equal(user.get('lastName'), 'Katz'); user.get('company').then(function(company) { - equal(passedUrl[1], '/development-shops/2'); + assert.equal(passedUrl[1], '/development-shops/2'); - equal(company.get('id'), '2'); - equal(company.get('name'), 'Tilde'); - equal(company.get('coffee'), true); + assert.equal(company.get('id'), '2'); + assert.equal(company.get('name'), 'Tilde'); + assert.equal(company.get('coffee'), true); }); }); }); }); -test('find a single record with sideloaded belongsTo link as object { data }', function() { - expect(7); +test('find a single record with sideloaded belongsTo link as object { data }', function(assert) { + assert.expect(7); ajaxResponse([{ data: { @@ -386,24 +388,24 @@ test('find a single record with sideloaded belongsTo link as object { data }', f run(function() { store.find('post', 1).then(function(post) { - equal(passedUrl[0], '/posts/1'); + assert.equal(passedUrl[0], '/posts/1'); - equal(post.get('id'), '1'); - equal(post.get('title'), 'Ember.js rocks'); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('title'), 'Ember.js rocks'); post.get('author').then(function(author) { - equal(passedUrl.length, 1); + assert.equal(passedUrl.length, 1); - equal(author.get('id'), '2'); - equal(author.get('firstName'), 'Yehuda'); - equal(author.get('lastName'), 'Katz'); + assert.equal(author.get('id'), '2'); + assert.equal(author.get('firstName'), 'Yehuda'); + assert.equal(author.get('lastName'), 'Katz'); }); }); }); }); -test('find a single record with hasMany link as object { related }', function() { - expect(7); +test('find a single record with hasMany link as object { related }', function(assert) { + assert.expect(7); ajaxResponse([{ data: { @@ -438,24 +440,24 @@ test('find a single record with hasMany link as object { related }', function() run(function() { store.find('post', 1).then(function(post) { - equal(passedUrl[0], '/posts/1'); + assert.equal(passedUrl[0], '/posts/1'); - equal(post.get('id'), '1'); - equal(post.get('title'), 'Ember.js rocks'); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('title'), 'Ember.js rocks'); post.get('comments').then(function(comments) { - equal(passedUrl[1], 'http://example.com/post/1/comments'); + assert.equal(passedUrl[1], 'http://example.com/post/1/comments'); - equal(comments.get('length'), 2); - equal(comments.get('firstObject.text'), 'This is the first comment'); - equal(comments.get('lastObject.text'), 'This is the second comment'); + assert.equal(comments.get('length'), 2); + assert.equal(comments.get('firstObject.text'), 'This is the first comment'); + assert.equal(comments.get('lastObject.text'), 'This is the second comment'); }); }); }); }); -test('find a single record with hasMany link as object { data }', function() { - expect(8); +test('find a single record with hasMany link as object { data }', function(assert) { + assert.expect(8); ajaxResponse([{ data: { @@ -493,25 +495,25 @@ test('find a single record with hasMany link as object { data }', function() { run(function() { store.find('post', 1).then(function(post) { - equal(passedUrl[0], '/posts/1'); + assert.equal(passedUrl[0], '/posts/1'); - equal(post.get('id'), '1'); - equal(post.get('title'), 'Ember.js rocks'); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('title'), 'Ember.js rocks'); post.get('comments').then(function(comments) { - equal(passedUrl[1], '/comments/2'); - equal(passedUrl[2], '/comments/3'); + assert.equal(passedUrl[1], '/comments/2'); + assert.equal(passedUrl[2], '/comments/3'); - equal(comments.get('length'), 2); - equal(comments.get('firstObject.text'), 'This is the first comment'); - equal(comments.get('lastObject.text'), 'This is the second comment'); + assert.equal(comments.get('length'), 2); + assert.equal(comments.get('firstObject.text'), 'This is the first comment'); + assert.equal(comments.get('lastObject.text'), 'This is the second comment'); }); }); }); }); -test('find a single record with hasMany link as object { data } (polymorphic)', function() { - expect(9); +test('find a single record with hasMany link as object { data } (polymorphic)', function(assert) { + assert.expect(9); ajaxResponse([{ data: { @@ -550,26 +552,26 @@ test('find a single record with hasMany link as object { data } (polymorphic)', run(function() { store.find('user', 1).then(function(user) { - equal(passedUrl[0], '/users/1'); + assert.equal(passedUrl[0], '/users/1'); - equal(user.get('id'), '1'); - equal(user.get('firstName'), 'Yehuda'); - equal(user.get('lastName'), 'Katz'); + assert.equal(user.get('id'), '1'); + assert.equal(user.get('firstName'), 'Yehuda'); + assert.equal(user.get('lastName'), 'Katz'); user.get('handles').then(function(handles) { - equal(passedUrl[1], '/github-handles/2'); - equal(passedUrl[2], '/twitter-handles/3'); + assert.equal(passedUrl[1], '/github-handles/2'); + assert.equal(passedUrl[2], '/twitter-handles/3'); - equal(handles.get('length'), 2); - equal(handles.get('firstObject.username'), 'wycats'); - equal(handles.get('lastObject.nickname'), '@wycats'); + assert.equal(handles.get('length'), 2); + assert.equal(handles.get('firstObject.username'), 'wycats'); + assert.equal(handles.get('lastObject.nickname'), '@wycats'); }); }); }); }); -test('find a single record with sideloaded hasMany link as object { data }', function() { - expect(7); +test('find a single record with sideloaded hasMany link as object { data }', function(assert) { + assert.expect(7); ajaxResponse([{ data: { @@ -604,24 +606,24 @@ test('find a single record with sideloaded hasMany link as object { data }', fun run(function() { store.find('post', 1).then(function(post) { - equal(passedUrl[0], '/posts/1'); + assert.equal(passedUrl[0], '/posts/1'); - equal(post.get('id'), '1'); - equal(post.get('title'), 'Ember.js rocks'); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('title'), 'Ember.js rocks'); post.get('comments').then(function(comments) { - equal(passedUrl.length, 1); + assert.equal(passedUrl.length, 1); - equal(comments.get('length'), 2); - equal(comments.get('firstObject.text'), 'This is the first comment'); - equal(comments.get('lastObject.text'), 'This is the second comment'); + assert.equal(comments.get('length'), 2); + assert.equal(comments.get('firstObject.text'), 'This is the first comment'); + assert.equal(comments.get('lastObject.text'), 'This is the second comment'); }); }); }); }); -test('find a single record with sideloaded hasMany link as object { data } (polymorphic)', function() { - expect(8); +test('find a single record with sideloaded hasMany link as object { data } (polymorphic)', function(assert) { + assert.expect(8); ajaxResponse([{ data: { @@ -657,25 +659,25 @@ test('find a single record with sideloaded hasMany link as object { data } (poly run(function() { store.find('user', 1).then(function(user) { - equal(passedUrl[0], '/users/1'); + assert.equal(passedUrl[0], '/users/1'); - equal(user.get('id'), '1'); - equal(user.get('firstName'), 'Yehuda'); - equal(user.get('lastName'), 'Katz'); + assert.equal(user.get('id'), '1'); + assert.equal(user.get('firstName'), 'Yehuda'); + assert.equal(user.get('lastName'), 'Katz'); user.get('handles').then(function(handles) { - equal(passedUrl.length, 1); + assert.equal(passedUrl.length, 1); - equal(handles.get('length'), 2); - equal(handles.get('firstObject.username'), 'wycats'); - equal(handles.get('lastObject.nickname'), '@wycats'); + assert.equal(handles.get('length'), 2); + assert.equal(handles.get('firstObject.username'), 'wycats'); + assert.equal(handles.get('lastObject.nickname'), '@wycats'); }); }); }); }); -test('create record', function() { - expect(3); +test('create record', function(assert) { + assert.expect(3); ajaxResponse([{ data: { @@ -712,9 +714,9 @@ test('create record', function() { handles.addObject(githubHandle); user.save().then(function() { - equal(passedUrl[0], '/users'); - equal(passedVerb[0], 'POST'); - deepEqual(passedHash[0], { + assert.equal(passedUrl[0], '/users'); + assert.equal(passedVerb[0], 'POST'); + assert.deepEqual(passedHash[0], { data: { data : { type: 'users', @@ -735,8 +737,8 @@ test('create record', function() { }); }); -test('update record', function() { - expect(3); +test('update record', function(assert) { + assert.expect(3); ajaxResponse([{ data: { @@ -778,9 +780,9 @@ test('update record', function() { handles.addObject(githubHandle); user.save().then(function() { - equal(passedUrl[0], '/users/1'); - equal(passedVerb[0], 'PATCH'); - deepEqual(passedHash[0], { + assert.equal(passedUrl[0], '/users/1'); + assert.equal(passedVerb[0], 'PATCH'); + assert.deepEqual(passedHash[0], { data: { data : { type: 'users', @@ -803,8 +805,8 @@ test('update record', function() { }); }); -test('update record - serialize hasMany', function() { - expect(3); +test('update record - serialize hasMany', function(assert) { + assert.expect(3); ajaxResponse([{ data: { @@ -852,9 +854,9 @@ test('update record - serialize hasMany', function() { handles.addObject(twitterHandle); user.save().then(function() { - equal(passedUrl[0], '/users/1'); - equal(passedVerb[0], 'PATCH'); - deepEqual(passedHash[0], { + assert.equal(passedUrl[0], '/users/1'); + assert.equal(passedVerb[0], 'PATCH'); + assert.deepEqual(passedHash[0], { data: { data : { type: 'users', @@ -880,8 +882,8 @@ test('update record - serialize hasMany', function() { }); }); -test('fetching a belongsTo relationship link that returns null', function() { - expect(3); +test('fetching a belongsTo relationship link that returns null', function(assert) { + assert.expect(3); ajaxResponse([{ data: { @@ -904,12 +906,12 @@ test('fetching a belongsTo relationship link that returns null', function() { run(function() { store.find('post', 1).then(function(post) { - equal(passedUrl[0], '/posts/1'); + assert.equal(passedUrl[0], '/posts/1'); return post.get('author'); }).then(function(author) { - equal(passedUrl[1], 'http://example.com/post/1/author'); - equal(author, null); + assert.equal(passedUrl[1], 'http://example.com/post/1/author'); + assert.equal(author, null); }); }); }); diff --git a/tests/integration/adapter/queries-test.js b/tests/integration/adapter/queries-test.js index 86ef97d5a33..a1db29e4f7f 100644 --- a/tests/integration/adapter/queries-test.js +++ b/tests/integration/adapter/queries-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -7,7 +9,7 @@ var Person, env, store, adapter; var run = Ember.run; module("integration/adapter/queries - Queries", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ updatedAt: DS.attr('string'), name: DS.attr('string'), @@ -20,34 +22,34 @@ module("integration/adapter/queries - Queries", { adapter = env.adapter; }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); -test("When a query is made, the adapter should receive a record array it can populate with the results of the query.", function() { +test("When a query is made, the adapter should receive a record array it can populate with the results of the query.", function(assert) { adapter.query = function(store, type, query, recordArray) { - equal(type, Person, "the query method is called with the correct type"); + assert.equal(type, Person, "the query method is called with the correct type"); return Ember.RSVP.resolve([{ id: 1, name: "Peter Wagenet" }, { id: 2, name: "Brohuda Katz" }]); }; store.query('person', { page: 1 }).then(async(function(queryResults) { - equal(get(queryResults, 'length'), 2, "the record array has a length of 2 after the results are loaded"); - equal(get(queryResults, 'isLoaded'), true, "the record array's `isLoaded` property should be true"); + assert.equal(get(queryResults, 'length'), 2, "the record array has a length of 2 after the results are loaded"); + assert.equal(get(queryResults, 'isLoaded'), true, "the record array's `isLoaded` property should be true"); - equal(queryResults.objectAt(0).get('name'), "Peter Wagenet", "the first record is 'Peter Wagenet'"); - equal(queryResults.objectAt(1).get('name'), "Brohuda Katz", "the second record is 'Brohuda Katz'"); + assert.equal(queryResults.objectAt(0).get('name'), "Peter Wagenet", "the first record is 'Peter Wagenet'"); + assert.equal(queryResults.objectAt(1).get('name'), "Brohuda Katz", "the second record is 'Brohuda Katz'"); })); }); -test("The store asserts when query is made and the adapter responses with a single record.", function() { +test("The store asserts when query is made and the adapter responses with a single record.", function(assert) { env = setupStore({ person: Person, adapter: DS.RESTAdapter }); store = env.store; adapter = env.adapter; adapter.query = function(store, type, query, recordArray) { - equal(type, Person, "the query method is called with the correct type"); + assert.equal(type, Person, "the query method is called with the correct type"); return Ember.RSVP.resolve({ people: { id: 1, name: "Peter Wagenet" } }); }; diff --git a/tests/integration/adapter/record-persistence-test.js b/tests/integration/adapter/record-persistence-test.js index 2e30707faa4..1795f414aea 100644 --- a/tests/integration/adapter/record-persistence-test.js +++ b/tests/integration/adapter/record-persistence-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -13,14 +15,14 @@ var hash = Ember.RSVP.hash; function assertClean(promise) { return promise.then(async(function(record) { - equal(record.get('hasDirtyAttributes'), false, "The record is now clean"); + assert.equal(record.get('hasDirtyAttributes'), false, "The record is now clean"); return record; })); } module("integration/adapter/record_persistence - Persisting Records", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ updatedAt: attr('string'), name: attr('string'), @@ -38,17 +40,17 @@ module("integration/adapter/record_persistence - Persisting Records", { store = env.store; }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); -test("When a store is committed, the adapter's `commit` method should be called with records that have been changed.", function() { - expect(2); +test("When a store is committed, the adapter's `commit` method should be called with records that have been changed.", function(assert) { + assert.expect(2); env.adapter.updateRecord = function(store, type, snapshot) { - equal(type, Person, "the type is correct"); - equal(snapshot.record, tom, "the record is correct"); + assert.equal(type, Person, "the type is correct"); + assert.equal(snapshot.record, tom, "the record is correct"); return run(Ember.RSVP, 'resolve'); }; @@ -76,13 +78,13 @@ test("When a store is committed, the adapter's `commit` method should be called }); }); -test("When a store is committed, the adapter's `commit` method should be called with records that have been created.", function() { - expect(2); +test("When a store is committed, the adapter's `commit` method should be called with records that have been created.", function(assert) { + assert.expect(2); var tom; env.adapter.createRecord = function(store, type, snapshot) { - equal(type, Person, "the type is correct"); - equal(snapshot.record, tom, "the record is correct"); + assert.equal(type, Person, "the type is correct"); + assert.equal(snapshot.record, tom, "the record is correct"); return Ember.RSVP.resolve({ id: 1, name: "Tom Dale" }); }; @@ -93,8 +95,8 @@ test("When a store is committed, the adapter's `commit` method should be called }); }); -test("After a created record has been assigned an ID, finding a record by that ID returns the original record.", function() { - expect(1); +test("After a created record has been assigned an ID, finding a record by that ID returns the original record.", function(assert) { + assert.expect(1); var tom; env.adapter.createRecord = function(store, type, snapshot) { @@ -109,10 +111,10 @@ test("After a created record has been assigned an ID, finding a record by that I asyncEqual(tom, env.store.find('person', 1), "the retrieved record is the same as the created record"); }); -test("when a store is committed, the adapter's `commit` method should be called with records that have been deleted.", function() { +test("when a store is committed, the adapter's `commit` method should be called with records that have been deleted.", function(assert) { env.adapter.deleteRecord = function(store, type, snapshot) { - equal(type, Person, "the type is correct"); - equal(snapshot.record, tom, "the record is correct"); + assert.equal(type, Person, "the type is correct"); + assert.equal(snapshot.record, tom, "the record is correct"); return run(Ember.RSVP, 'resolve'); }; @@ -135,12 +137,12 @@ test("when a store is committed, the adapter's `commit` method should be called tom.deleteRecord(); return tom.save(); })).then(async(function(tom) { - equal(get(tom, 'isDeleted'), true, "record is marked as deleted"); + assert.equal(get(tom, 'isDeleted'), true, "record is marked as deleted"); })); }); -test("An adapter can notify the store that records were updated by calling `didSaveRecords`.", function() { - expect(6); +test("An adapter can notify the store that records were updated by calling `didSaveRecords`.", function(assert) { + assert.expect(6); var tom, yehuda; @@ -168,20 +170,20 @@ test("An adapter can notify the store that records were updated by calling `didS tom.set('name', "Michael Phelps"); yehuda.set('name', "Usain Bolt"); - ok(tom.get('hasDirtyAttributes'), "tom is dirty"); - ok(yehuda.get('hasDirtyAttributes'), "yehuda is dirty"); + assert.ok(tom.get('hasDirtyAttributes'), "tom is dirty"); + assert.ok(yehuda.get('hasDirtyAttributes'), "yehuda is dirty"); assertClean(tom.save()).then(async(function(record) { - equal(record, tom, "The record is correct"); + assert.equal(record, tom, "The record is correct"); })); assertClean(yehuda.save()).then(async(function(record) { - equal(record, yehuda, "The record is correct"); + assert.equal(record, yehuda, "The record is correct"); })); })); }); -test("An adapter can notify the store that records were updated and provide new data by calling `didSaveRecords`.", function() { +test("An adapter can notify the store that records were updated and provide new data by calling `didSaveRecords`.", function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { if (snapshot.id === "1") { return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", updatedAt: "now" }); @@ -214,14 +216,14 @@ test("An adapter can notify the store that records were updated and provide new return hash({ tom: people.tom.save(), yehuda: people.yehuda.save() }); })).then(async(function(people) { - equal(people.tom.get('name'), "Tom Dale", "name attribute should reflect value of hash passed to didSaveRecords"); - equal(people.tom.get('updatedAt'), "now", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); - equal(people.yehuda.get('name'), "Yehuda Katz", "name attribute should reflect value of hash passed to didSaveRecords"); - equal(people.yehuda.get('updatedAt'), "now!", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); + assert.equal(people.tom.get('name'), "Tom Dale", "name attribute should reflect value of hash passed to didSaveRecords"); + assert.equal(people.tom.get('updatedAt'), "now", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); + assert.equal(people.yehuda.get('name'), "Yehuda Katz", "name attribute should reflect value of hash passed to didSaveRecords"); + assert.equal(people.yehuda.get('updatedAt'), "now!", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); })); }); -test("An adapter can notify the store that a record was updated by calling `didSaveRecord`.", function() { +test("An adapter can notify the store that a record was updated by calling `didSaveRecord`.", function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { return Ember.RSVP.resolve(); }; @@ -242,8 +244,8 @@ test("An adapter can notify the store that a record was updated by calling `didS people.tom.set('name', "Tom Dale"); people.yehuda.set('name', "Yehuda Katz"); - ok(people.tom.get('hasDirtyAttributes'), "tom is dirty"); - ok(people.yehuda.get('hasDirtyAttributes'), "yehuda is dirty"); + assert.ok(people.tom.get('hasDirtyAttributes'), "tom is dirty"); + assert.ok(people.yehuda.get('hasDirtyAttributes'), "yehuda is dirty"); assertClean(people.tom.save()); assertClean(people.yehuda.save()); @@ -251,7 +253,7 @@ test("An adapter can notify the store that a record was updated by calling `didS }); -test("An adapter can notify the store that a record was updated and provide new data by calling `didSaveRecord`.", function() { +test("An adapter can notify the store that a record was updated and provide new data by calling `didSaveRecord`.", function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { switch (snapshot.id) { case "1": @@ -285,15 +287,15 @@ test("An adapter can notify the store that a record was updated and provide new return hash({ tom: people.tom.save(), yehuda: people.yehuda.save() }); })).then(async(function(people) { - equal(people.tom.get('name'), "Tom Dale", "name attribute should reflect value of hash passed to didSaveRecords"); - equal(people.tom.get('updatedAt'), "now", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); - equal(people.yehuda.get('name'), "Yehuda Katz", "name attribute should reflect value of hash passed to didSaveRecords"); - equal(people.yehuda.get('updatedAt'), "now!", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); + assert.equal(people.tom.get('name'), "Tom Dale", "name attribute should reflect value of hash passed to didSaveRecords"); + assert.equal(people.tom.get('updatedAt'), "now", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); + assert.equal(people.yehuda.get('name'), "Yehuda Katz", "name attribute should reflect value of hash passed to didSaveRecords"); + assert.equal(people.yehuda.get('updatedAt'), "now!", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); })); }); -test("An adapter can notify the store that records were deleted by calling `didSaveRecords`.", function() { +test("An adapter can notify the store that records were deleted by calling `didSaveRecords`.", function(assert) { env.adapter.deleteRecord = function(store, type, snapshot) { return Ember.RSVP.resolve(); }; diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 3689590d413..81b7ef4221a 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, adapter, Post, Comment, SuperUser; @@ -8,7 +10,7 @@ var run = Ember.run; var get = Ember.get; module("integration/adapter/rest_adapter - REST Adapter", { - setup: function() { + beforeEach: function() { Post = DS.Model.extend({ name: DS.attr("string") }); @@ -47,21 +49,21 @@ function ajaxResponse(value) { }; } -test("find - basic payload", function() { +test("find - basic payload", function(assert) { ajaxResponse({ posts: [{ id: 1, name: "Rails is omakase" }] }); run(store, 'find', 'post', 1).then(async(function(post) { - equal(passedUrl, "/posts/1"); - equal(passedVerb, "GET"); - equal(passedHash, undefined); + assert.equal(passedUrl, "/posts/1"); + assert.equal(passedVerb, "GET"); + assert.equal(passedHash, undefined); - equal(post.get('id'), "1"); - equal(post.get('name'), "Rails is omakase"); + assert.equal(post.get('id'), "1"); + assert.equal(post.get('name'), "Rails is omakase"); })); }); -test("findRecord - passes buildURL a requestType", function() { +test("findRecord - passes buildURL a requestType", function(assert) { adapter.buildURL = function(type, id, snapshot, requestType) { return "/" + requestType + "/post/" + id; }; @@ -70,24 +72,24 @@ test("findRecord - passes buildURL a requestType", function() { run(store, 'findRecord', 'post', 1).then(async(function(post) { - equal(passedUrl, "/findRecord/post/1"); + assert.equal(passedUrl, "/findRecord/post/1"); })); }); -test("find - basic payload (with legacy singular name)", function() { +test("find - basic payload (with legacy singular name)", function(assert) { ajaxResponse({ post: { id: 1, name: "Rails is omakase" } }); run(store, 'find', 'post', 1).then(async(function(post) { - equal(passedUrl, "/posts/1"); - equal(passedVerb, "GET"); - equal(passedHash, undefined); + assert.equal(passedUrl, "/posts/1"); + assert.equal(passedVerb, "GET"); + assert.equal(passedHash, undefined); - equal(post.get('id'), "1"); - equal(post.get('name'), "Rails is omakase"); + assert.equal(post.get('id'), "1"); + assert.equal(post.get('name'), "Rails is omakase"); })); }); -test("find - payload with sideloaded records of the same type", function() { +test("find - payload with sideloaded records of the same type", function(assert) { ajaxResponse({ posts: [ { id: 1, name: "Rails is omakase" }, @@ -96,41 +98,41 @@ test("find - payload with sideloaded records of the same type", function() { }); run(store, 'find', 'post', 1).then(async(function(post) { - equal(passedUrl, "/posts/1"); - equal(passedVerb, "GET"); - equal(passedHash, undefined); + assert.equal(passedUrl, "/posts/1"); + assert.equal(passedVerb, "GET"); + assert.equal(passedHash, undefined); - equal(post.get('id'), "1"); - equal(post.get('name'), "Rails is omakase"); + assert.equal(post.get('id'), "1"); + assert.equal(post.get('name'), "Rails is omakase"); var post2 = store.peekRecord('post', 2); - equal(post2.get('id'), "2"); - equal(post2.get('name'), "The Parley Letter"); + assert.equal(post2.get('id'), "2"); + assert.equal(post2.get('name'), "The Parley Letter"); })); }); -test("find - payload with sideloaded records of a different type", function() { +test("find - payload with sideloaded records of a different type", function(assert) { ajaxResponse({ posts: [{ id: 1, name: "Rails is omakase" }], comments: [{ id: 1, name: "FIRST" }] }); run(store, 'find', 'post', 1).then(async(function(post) { - equal(passedUrl, "/posts/1"); - equal(passedVerb, "GET"); - equal(passedHash, undefined); + assert.equal(passedUrl, "/posts/1"); + assert.equal(passedVerb, "GET"); + assert.equal(passedHash, undefined); - equal(post.get('id'), "1"); - equal(post.get('name'), "Rails is omakase"); + assert.equal(post.get('id'), "1"); + assert.equal(post.get('name'), "Rails is omakase"); var comment = store.peekRecord('comment', 1); - equal(comment.get('id'), "1"); - equal(comment.get('name'), "FIRST"); + assert.equal(comment.get('id'), "1"); + assert.equal(comment.get('name'), "FIRST"); })); }); -test("find - payload with an serializer-specified primary key", function() { +test("find - payload with an serializer-specified primary key", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_' })); @@ -138,16 +140,16 @@ test("find - payload with an serializer-specified primary key", function() { ajaxResponse({ posts: [{ "_ID_": 1, name: "Rails is omakase" }] }); run(store, 'find', 'post', 1).then(async(function(post) { - equal(passedUrl, "/posts/1"); - equal(passedVerb, "GET"); - equal(passedHash, undefined); + assert.equal(passedUrl, "/posts/1"); + assert.equal(passedVerb, "GET"); + assert.equal(passedHash, undefined); - equal(post.get('id'), "1"); - equal(post.get('name'), "Rails is omakase"); + assert.equal(post.get('id'), "1"); + assert.equal(post.get('name'), "Rails is omakase"); })); }); -test("find - payload with a serializer-specified attribute mapping", function() { +test("find - payload with a serializer-specified attribute mapping", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ attrs: { 'name': '_NAME_', @@ -162,34 +164,34 @@ test("find - payload with a serializer-specified attribute mapping", function() ajaxResponse({ posts: [{ id: 1, _NAME_: "Rails is omakase", _CREATED_AT_: 2013 }] }); run(store, 'find', 'post', 1).then(async(function(post) { - equal(passedUrl, "/posts/1"); - equal(passedVerb, "GET"); - equal(passedHash, undefined); + assert.equal(passedUrl, "/posts/1"); + assert.equal(passedVerb, "GET"); + assert.equal(passedHash, undefined); - equal(post.get('id'), "1"); - equal(post.get('name'), "Rails is omakase"); - equal(post.get('createdAt'), 2013); + assert.equal(post.get('id'), "1"); + assert.equal(post.get('name'), "Rails is omakase"); + assert.equal(post.get('createdAt'), 2013); })); }); -test("create - an empty payload is a basic success if an id was specified", function() { +test("create - an empty payload is a basic success if an id was specified", function(assert) { ajaxResponse(); var post; run(function() { post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); post.save().then(async(function(post) { - equal(passedUrl, "/posts"); - equal(passedVerb, "POST"); - deepEqual(passedHash.data, { post: { id: "some-uuid", name: "The Parley Letter" } }); + assert.equal(passedUrl, "/posts"); + assert.equal(passedVerb, "POST"); + assert.deepEqual(passedHash.data, { post: { id: "some-uuid", name: "The Parley Letter" } }); - equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - equal(post.get('name'), "The Parley Letter", "the post was updated"); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), "The Parley Letter", "the post was updated"); })); }); }); -test("create - passes buildURL the requestType", function() { +test("create - passes buildURL the requestType", function(assert) { adapter.buildURL = function(type, id, snapshot, requestType) { return "/post/" + requestType; }; @@ -200,29 +202,29 @@ test("create - passes buildURL the requestType", function() { run(function() { post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); post.save().then(async(function(post) { - equal(passedUrl, "/post/createRecord"); + assert.equal(passedUrl, "/post/createRecord"); })); }); }); -test("create - a payload with a new ID and data applies the updates", function() { +test("create - a payload with a new ID and data applies the updates", function(assert) { ajaxResponse({ posts: [{ id: "1", name: "Dat Parley Letter" }] }); run(function() { var post = store.createRecord('post', { name: "The Parley Letter" }); post.save().then(async(function(post) { - equal(passedUrl, "/posts"); - equal(passedVerb, "POST"); - deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); + assert.equal(passedUrl, "/posts"); + assert.equal(passedVerb, "POST"); + assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); - equal(post.get('id'), "1", "the post has the updated ID"); - equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - equal(post.get('name'), "Dat Parley Letter", "the post was updated"); + assert.equal(post.get('id'), "1", "the post has the updated ID"); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); })); }); }); -test("create - a payload with a new ID and data applies the updates (with legacy singular name)", function() { +test("create - a payload with a new ID and data applies the updates (with legacy singular name)", function(assert) { var post; ajaxResponse({ post: { id: "1", name: "Dat Parley Letter" } }); run(function() { @@ -230,17 +232,17 @@ test("create - a payload with a new ID and data applies the updates (with legacy }); run(post, 'save').then(async(function(post) { - equal(passedUrl, "/posts"); - equal(passedVerb, "POST"); - deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); + assert.equal(passedUrl, "/posts"); + assert.equal(passedVerb, "POST"); + assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); - equal(post.get('id'), "1", "the post has the updated ID"); - equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - equal(post.get('name'), "Dat Parley Letter", "the post was updated"); + assert.equal(post.get('id'), "1", "the post has the updated ID"); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); })); }); -test("create - findMany doesn't overwrite owner", function() { +test("create - findMany doesn't overwrite owner", function(assert) { ajaxResponse({ comment: { id: "1", name: "Dat Parley Letter", post: 1 } }); var comment; @@ -270,18 +272,18 @@ test("create - findMany doesn't overwrite owner", function() { }); post.get('comments').pushObject(comment); - equal(comment.get('post'), post, "the post has been set correctly"); + assert.equal(comment.get('post'), post, "the post has been set correctly"); run(function() { comment.save().then(async(function(comment) { - equal(comment.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - equal(comment.get('name'), "Dat Parley Letter", "the post was updated"); - equal(comment.get('post'), post, "the post is still set"); + assert.equal(comment.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(comment.get('name'), "Dat Parley Letter", "the post was updated"); + assert.equal(comment.get('post'), post, "the post is still set"); })); }); }); -test("create - a serializer's primary key and attributes are consulted when building the payload", function() { +test("create - a serializer's primary key and attributes are consulted when building the payload", function(assert) { var post; env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_id_', @@ -298,11 +300,11 @@ test("create - a serializer's primary key and attributes are consulted when buil }); run(post, 'save').then(async(function(post) { - deepEqual(passedHash.data, { post: { _id_: 'some-uuid', '_name_': "The Parley Letter" } }); + assert.deepEqual(passedHash.data, { post: { _id_: 'some-uuid', '_name_': "The Parley Letter" } }); })); }); -test("create - a serializer's attributes are consulted when building the payload if no id is pre-defined", function() { +test("create - a serializer's attributes are consulted when building the payload if no id is pre-defined", function(assert) { var post; env.registry.register('serializer:post', DS.RESTSerializer.extend({ primarykey: '_id_', @@ -318,12 +320,12 @@ test("create - a serializer's attributes are consulted when building the payload post = store.createRecord('post', { name: "The Parley Letter" }); post.save().then(async(function(post) { - deepEqual(passedHash.data, { post: { '_name_': "The Parley Letter" } }); + assert.deepEqual(passedHash.data, { post: { '_name_': "The Parley Letter" } }); })); }); }); -test("create - a serializer's attribute mapping takes precdence over keyForAttribute when building the payload", function() { +test("create - a serializer's attribute mapping takes precdence over keyForAttribute when building the payload", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ attrs: { name: 'given_name' @@ -340,12 +342,12 @@ test("create - a serializer's attribute mapping takes precdence over keyForAttri var post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); post.save().then(async(function(post) { - deepEqual(passedHash.data, { post: { 'given_name': "The Parley Letter", id: "some-uuid" } }); + assert.deepEqual(passedHash.data, { post: { 'given_name': "The Parley Letter", id: "some-uuid" } }); })); }); }); -test("create - a serializer's attribute mapping takes precedence over keyForRelationship (belongsTo) when building the payload", function() { +test("create - a serializer's attribute mapping takes precedence over keyForRelationship (belongsTo) when building the payload", function(assert) { env.registry.register('serializer:comment', DS.RESTSerializer.extend({ attrs: { post: 'article' @@ -365,12 +367,12 @@ test("create - a serializer's attribute mapping takes precedence over keyForRela var comment = store.createRecord('comment', { id: "some-uuid", name: "Letters are fun", post: post }); comment.save().then(async(function(post) { - deepEqual(passedHash.data, { comment: { article: "a-post-id", id: "some-uuid", name: "Letters are fun" } }); + assert.deepEqual(passedHash.data, { comment: { article: "a-post-id", id: "some-uuid", name: "Letters are fun" } }); })); }); }); -test("create - a serializer's attribute mapping takes precedence over keyForRelationship (hasMany) when building the payload", function() { +test("create - a serializer's attribute mapping takes precedence over keyForRelationship (hasMany) when building the payload", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ attrs: { comments: 'opinions' @@ -390,13 +392,13 @@ test("create - a serializer's attribute mapping takes precedence over keyForRela var post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter", comments: [comment] }); post.save().then(async(function(post) { - deepEqual(passedHash.data, { post: { opinions: ["a-comment-id"], id: "some-uuid", name: "The Parley Letter" } }); + assert.deepEqual(passedHash.data, { post: { opinions: ["a-comment-id"], id: "some-uuid", name: "The Parley Letter" } }); })); }); }); -test("create - a record on the many side of a hasMany relationship should update relationships when data is sideloaded", function() { - expect(3); +test("create - a record on the many side of a hasMany relationship should update relationships when data is sideloaded", function(assert) { + assert.expect(3); ajaxResponse({ posts: [{ @@ -460,23 +462,23 @@ test("create - a record on the many side of a hasMany relationship should update var post = store.peekRecord('post', 1); var commentCount = post.get('comments.length'); - equal(commentCount, 1, "the post starts life with a comment"); + assert.equal(commentCount, 1, "the post starts life with a comment"); run(function() { var comment = store.createRecord('comment', { name: "Another Comment", post: post }); comment.save().then(async(function(comment) { - equal(comment.get('post'), post, "the comment is related to the post"); + assert.equal(comment.get('post'), post, "the comment is related to the post"); })); post.reload().then(async(function(post) { - equal(post.get('comments.length'), 2, "Post comment count has been updated"); + assert.equal(post.get('comments.length'), 2, "Post comment count has been updated"); })); }); }); -test("create - sideloaded belongsTo relationships are both marked as loaded", function () { - expect(4); +test("create - sideloaded belongsTo relationships are both marked as loaded", function(assert) { + assert.expect(4); var post; Post.reopen({ comment: DS.belongsTo('comment', { async: false }) }); @@ -493,16 +495,16 @@ test("create - sideloaded belongsTo relationships are both marked as loaded", fu run(function() { post.save().then(async(function(record) { - equal(store.peekRecord('post', 1).get('comment.isLoaded'), true, "post's comment isLoaded (via store)"); - equal(store.peekRecord('comment', 1).get('post.isLoaded'), true, "comment's post isLoaded (via store)"); - equal(record.get('comment.isLoaded'), true, "post's comment isLoaded (via record)"); - equal(record.get('comment.post.isLoaded'), true, "post's comment's post isLoaded (via record)"); + assert.equal(store.peekRecord('post', 1).get('comment.isLoaded'), true, "post's comment isLoaded (via store)"); + assert.equal(store.peekRecord('comment', 1).get('post.isLoaded'), true, "comment's post isLoaded (via store)"); + assert.equal(record.get('comment.isLoaded'), true, "post's comment isLoaded (via record)"); + assert.equal(record.get('comment.post.isLoaded'), true, "post's comment's post isLoaded (via record)"); })); }); }); -test("create - response can contain relationships the client doesn't yet know about", function() { - expect(3); // while records.length is 2, we are getting 4 assertions +test("create - response can contain relationships the client doesn't yet know about", function(assert) { + assert.expect(3); // while records.length is 2, we are getting 4 assertions ajaxResponse({ posts: [{ @@ -527,18 +529,18 @@ test("create - response can contain relationships the client doesn't yet know ab run(function() { post.save().then(async(function(post) { - equal(post.get('comments.firstObject.post'), post, "the comments are related to the correct post model"); - equal(store.typeMapFor(Post).records.length, 1, "There should only be one post record in the store"); + assert.equal(post.get('comments.firstObject.post'), post, "the comments are related to the correct post model"); + assert.equal(store.typeMapFor(Post).records.length, 1, "There should only be one post record in the store"); var postRecords = store.typeMapFor(Post).records; for (var i = 0; i < postRecords.length; i++) { - equal(post, postRecords[i].getRecord(), "The object in the identity map is the same"); + assert.equal(post, postRecords[i].getRecord(), "The object in the identity map is the same"); } })); }); }); -test("create - relationships are not duplicated", function() { +test("create - relationships are not duplicated", function(assert) { var post, comment; Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); @@ -552,9 +554,9 @@ test("create - relationships are not duplicated", function() { ajaxResponse({ post: [{ id: 1, name: "Rails is omakase", comments: [] }] }); run(post, 'save').then(async(function(post) { - equal(post.get('comments.length'), 0, "post has 0 comments"); + assert.equal(post.get('comments.length'), 0, "post has 0 comments"); post.get('comments').pushObject(comment); - equal(post.get('comments.length'), 1, "post has 1 comment"); + assert.equal(post.get('comments.length'), 1, "post has 1 comment"); ajaxResponse({ post: [{ id: 1, name: "Rails is omakase", comments: [2] }], @@ -563,11 +565,11 @@ test("create - relationships are not duplicated", function() { return post.save(); })).then(async(function(post) { - equal(post.get('comments.length'), 1, "post has 1 comment"); + assert.equal(post.get('comments.length'), 1, "post has 1 comment"); })); }); -test("update - an empty payload is a basic success", function() { +test("update - an empty payload is a basic success", function(assert) { run(function() { store.push({ data: { @@ -586,17 +588,17 @@ test("update - an empty payload is a basic success", function() { post.set('name', "The Parley Letter"); post.save().then(async(function(post) { - equal(passedUrl, "/posts/1"); - equal(passedVerb, "PUT"); - deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); + assert.equal(passedUrl, "/posts/1"); + assert.equal(passedVerb, "PUT"); + assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); - equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - equal(post.get('name'), "The Parley Letter", "the post was updated"); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), "The Parley Letter", "the post was updated"); })); }); }); -test("update - passes the requestType to buildURL", function() { +test("update - passes the requestType to buildURL", function(assert) { adapter.buildURL = function(type, id, snapshot, requestType) { return "/posts/" + id + "/" + requestType; }; @@ -621,12 +623,12 @@ test("update - passes the requestType to buildURL", function() { post.set('name', "The Parley Letter"); return post.save(); })).then(async(function(post) { - equal(passedUrl, "/posts/1/updateRecord"); + assert.equal(passedUrl, "/posts/1/updateRecord"); })); }); }); -test("update - a payload with updates applies the updates", function() { +test("update - a payload with updates applies the updates", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.push({ @@ -646,16 +648,16 @@ test("update - a payload with updates applies the updates", function() { post.set('name', "The Parley Letter"); return post.save(); })).then(async(function(post) { - equal(passedUrl, "/posts/1"); - equal(passedVerb, "PUT"); - deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); + assert.equal(passedUrl, "/posts/1"); + assert.equal(passedVerb, "PUT"); + assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); - equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - equal(post.get('name'), "Dat Parley Letter", "the post was updated"); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); })); }); -test("update - a payload with updates applies the updates (with legacy singular name)", function() { +test("update - a payload with updates applies the updates (with legacy singular name)", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.push({ @@ -675,16 +677,16 @@ test("update - a payload with updates applies the updates (with legacy singular post.set('name', "The Parley Letter"); return post.save(); })).then(async(function(post) { - equal(passedUrl, "/posts/1"); - equal(passedVerb, "PUT"); - deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); + assert.equal(passedUrl, "/posts/1"); + assert.equal(passedVerb, "PUT"); + assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); - equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - equal(post.get('name'), "Dat Parley Letter", "the post was updated"); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); })); }); -test("update - a payload with sideloaded updates pushes the updates", function() { +test("update - a payload with sideloaded updates pushes the updates", function(assert) { var post; ajaxResponse({ posts: [{ id: 1, name: "Dat Parley Letter" }], @@ -693,21 +695,21 @@ test("update - a payload with sideloaded updates pushes the updates", function() run(function() { post = store.createRecord('post', { name: "The Parley Letter" }); post.save().then(async(function(post) { - equal(passedUrl, "/posts"); - equal(passedVerb, "POST"); - deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); + assert.equal(passedUrl, "/posts"); + assert.equal(passedVerb, "POST"); + assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); - equal(post.get('id'), "1", "the post has the updated ID"); - equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - equal(post.get('name'), "Dat Parley Letter", "the post was updated"); + assert.equal(post.get('id'), "1", "the post has the updated ID"); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); var comment = store.peekRecord('comment', 1); - equal(comment.get('name'), "FIRST", "The comment was sideloaded"); + assert.equal(comment.get('name'), "FIRST", "The comment was sideloaded"); })); }); }); -test("update - a payload with sideloaded updates pushes the updates", function() { +test("update - a payload with sideloaded updates pushes the updates", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.push({ @@ -730,19 +732,19 @@ test("update - a payload with sideloaded updates pushes the updates", function() post.set('name', "The Parley Letter"); return post.save(); })).then(async(function(post) { - equal(passedUrl, "/posts/1"); - equal(passedVerb, "PUT"); - deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); + assert.equal(passedUrl, "/posts/1"); + assert.equal(passedVerb, "PUT"); + assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); - equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - equal(post.get('name'), "Dat Parley Letter", "the post was updated"); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); var comment = store.peekRecord('comment', 1); - equal(comment.get('name'), "FIRST", "The comment was sideloaded"); + assert.equal(comment.get('name'), "FIRST", "The comment was sideloaded"); })); }); -test("update - a serializer's primary key and attributes are consulted when building the payload", function() { +test("update - a serializer's primary key and attributes are consulted when building the payload", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_id_', @@ -767,11 +769,11 @@ test("update - a serializer's primary key and attributes are consulted when buil post.set('name', "The Parley Letter"); return post.save(); })).then(async(function(post) { - deepEqual(passedHash.data, { post: { '_name_': "The Parley Letter" } }); + assert.deepEqual(passedHash.data, { post: { '_name_': "The Parley Letter" } }); })); }); -test("update - hasMany relationships faithfully reflect simultaneous adds and removes", function() { +test("update - hasMany relationships faithfully reflect simultaneous adds and removes", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); adapter.shouldBackgroundReloadRecord = () => false; @@ -824,12 +826,12 @@ test("update - hasMany relationships faithfully reflect simultaneous adds and re return post.save(); })).then(async(function(post) { - equal(post.get('comments.length'), 1, "the post has the correct number of comments"); - equal(post.get('comments.firstObject.name'), "Yes. Yes it is.", "the post has the correct comment"); + assert.equal(post.get('comments.length'), 1, "the post has the correct number of comments"); + assert.equal(post.get('comments.firstObject.name'), "Yes. Yes it is.", "the post has the correct comment"); })); }); -test("delete - an empty payload is a basic success", function() { +test("delete - an empty payload is a basic success", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.push({ @@ -849,16 +851,16 @@ test("delete - an empty payload is a basic success", function() { post.deleteRecord(); return post.save(); })).then(async(function(post) { - equal(passedUrl, "/posts/1"); - equal(passedVerb, "DELETE"); - equal(passedHash, undefined); + assert.equal(passedUrl, "/posts/1"); + assert.equal(passedVerb, "DELETE"); + assert.equal(passedHash, undefined); - equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - equal(post.get('isDeleted'), true, "the post is now deleted"); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('isDeleted'), true, "the post is now deleted"); })); }); -test("delete - passes the requestType to buildURL", function() { +test("delete - passes the requestType to buildURL", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.buildURL = function(type, id, snapshot, requestType) { return "/posts/" + id + "/" + requestType; @@ -882,11 +884,11 @@ test("delete - passes the requestType to buildURL", function() { post.deleteRecord(); return post.save(); })).then(async(function(post) { - equal(passedUrl, "/posts/1/deleteRecord"); + assert.equal(passedUrl, "/posts/1/deleteRecord"); })); }); -test("delete - a payload with sideloaded updates pushes the updates", function() { +test("delete - a payload with sideloaded updates pushes the updates", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.push({ @@ -906,19 +908,19 @@ test("delete - a payload with sideloaded updates pushes the updates", function() post.deleteRecord(); return post.save(); })).then(async(function(post) { - equal(passedUrl, "/posts/1"); - equal(passedVerb, "DELETE"); - equal(passedHash, undefined); + assert.equal(passedUrl, "/posts/1"); + assert.equal(passedVerb, "DELETE"); + assert.equal(passedHash, undefined); - equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - equal(post.get('isDeleted'), true, "the post is now deleted"); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('isDeleted'), true, "the post is now deleted"); var comment = store.peekRecord('comment', 1); - equal(comment.get('name'), "FIRST", "The comment was sideloaded"); + assert.equal(comment.get('name'), "FIRST", "The comment was sideloaded"); })); }); -test("delete - a payload with sidloaded updates pushes the updates when the original record is omitted", function() { +test("delete - a payload with sidloaded updates pushes the updates when the original record is omitted", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.push({ @@ -938,19 +940,19 @@ test("delete - a payload with sidloaded updates pushes the updates when the orig post.deleteRecord(); return post.save(); })).then(async(function(post) { - equal(passedUrl, "/posts/1"); - equal(passedVerb, "DELETE"); - equal(passedHash, undefined); + assert.equal(passedUrl, "/posts/1"); + assert.equal(passedVerb, "DELETE"); + assert.equal(passedHash, undefined); - equal(post.get('hasDirtyAttributes'), false, "the original post isn't dirty anymore"); - equal(post.get('isDeleted'), true, "the original post is now deleted"); + assert.equal(post.get('hasDirtyAttributes'), false, "the original post isn't dirty anymore"); + assert.equal(post.get('isDeleted'), true, "the original post is now deleted"); var newPost = store.peekRecord('post', 2); - equal(newPost.get('name'), "The Parley Letter", "The new post was added to the store"); + assert.equal(newPost.get('name'), "The Parley Letter", "The new post was added to the store"); })); }); -test("delete - deleting a newly created record should not throw an error", function() { +test("delete - deleting a newly created record should not throw an error", function(assert) { var post; run(function() { post = store.createRecord('post'); @@ -959,17 +961,17 @@ test("delete - deleting a newly created record should not throw an error", funct run(function() { post.deleteRecord(); post.save().then(async(function(post) { - equal(passedUrl, null, "There is no ajax call to delete a record that has never been saved."); - equal(passedVerb, null, "There is no ajax call to delete a record that has never been saved."); - equal(passedHash, null, "There is no ajax call to delete a record that has never been saved."); + assert.equal(passedUrl, null, "There is no ajax call to delete a record that has never been saved."); + assert.equal(passedVerb, null, "There is no ajax call to delete a record that has never been saved."); + assert.equal(passedHash, null, "There is no ajax call to delete a record that has never been saved."); - equal(post.get('isDeleted'), true, "the post is now deleted"); - equal(post.get('isError'), false, "the post is not an error"); + assert.equal(post.get('isDeleted'), true, "the post is now deleted"); + assert.equal(post.get('isError'), false, "the post is not an error"); })); }); }); -test("findAll - returning an array populates the array", function() { +test("findAll - returning an array populates the array", function(assert) { ajaxResponse({ posts: [ { id: 1, name: "Rails is omakase" }, @@ -978,28 +980,28 @@ test("findAll - returning an array populates the array", function() { }); store.findAll('post').then(async(function(posts) { - equal(passedUrl, "/posts"); - equal(passedVerb, "GET"); - equal(passedHash.data, undefined); + assert.equal(passedUrl, "/posts"); + assert.equal(passedVerb, "GET"); + assert.equal(passedHash.data, undefined); var post1 = store.peekRecord('post', 1); var post2 = store.peekRecord('post', 2); - deepEqual( + assert.deepEqual( post1.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }, "Post 1 is loaded" ); - deepEqual( + assert.deepEqual( post2.getProperties('id', 'name'), { id: "2", name: "The Parley Letter" }, "Post 2 is loaded" ); - equal(posts.get('length'), 2, "The posts are in the array"); - equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); - deepEqual( + assert.equal(posts.get('length'), 2, "The posts are in the array"); + assert.equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); + assert.deepEqual( posts.toArray(), [post1, post2], "The correct records are in the array" @@ -1008,7 +1010,7 @@ test("findAll - returning an array populates the array", function() { }); -test("findAll - passes buildURL the requestType", function() { +test("findAll - passes buildURL the requestType", function(assert) { adapter.buildURL = function(type, id, snapshot, requestType) { return "/" + requestType + "/posts"; }; @@ -1021,11 +1023,11 @@ test("findAll - passes buildURL the requestType", function() { }); store.findAll('post').then(async(function(posts) { - equal(passedUrl, "/findAll/posts"); + assert.equal(passedUrl, "/findAll/posts"); })); }); -test("findAll - returning sideloaded data loads the data", function() { +test("findAll - returning sideloaded data loads the data", function(assert) { ajaxResponse({ posts: [ { id: 1, name: "Rails is omakase" }, @@ -1036,11 +1038,11 @@ test("findAll - returning sideloaded data loads the data", function() { store.findAll('post').then(async(function(posts) { var comment = store.peekRecord('comment', 1); - deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); + assert.deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); })); }); -test("findAll - data is normalized through custom serializers", function() { +test("findAll - data is normalized through custom serializers", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', attrs: { name: '_NAME_' } @@ -1057,20 +1059,20 @@ test("findAll - data is normalized through custom serializers", function() { var post1 = store.peekRecord('post', 1); var post2 = store.peekRecord('post', 2); - deepEqual( + assert.deepEqual( post1.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }, "Post 1 is loaded" ); - deepEqual( + assert.deepEqual( post2.getProperties('id', 'name'), { id: "2", name: "The Parley Letter" }, "Post 2 is loaded" ); - equal(posts.get('length'), 2, "The posts are in the array"); - equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); - deepEqual( + assert.equal(posts.get('length'), 2, "The posts are in the array"); + assert.equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); + assert.deepEqual( posts.toArray(), [post1, post2], "The correct records are in the array" @@ -1078,13 +1080,13 @@ test("findAll - data is normalized through custom serializers", function() { })); }); -test("query - if `sortQueryParams` option is not provided, query params are sorted alphabetically", function() { +test("query - if `sortQueryParams` option is not provided, query params are sorted alphabetically", function(assert) { adapter.ajax = function(url, verb, hash) { passedUrl = url; passedVerb = verb; passedHash = hash; - deepEqual(Object.keys(hash.data), ["in", "order", "params", "wrong"], 'query params are received in alphabetical order'); + assert.deepEqual(Object.keys(hash.data), ["in", "order", "params", "wrong"], 'query params are received in alphabetical order'); return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); }; @@ -1094,13 +1096,13 @@ test("query - if `sortQueryParams` option is not provided, query params are sort })); }); -test("query - passes buildURL the requestType", function() { +test("query - passes buildURL the requestType", function(assert) { adapter.buildURL = function(type, id, snapshot, requestType) { return "/" + requestType + "/posts"; }; adapter.ajax = function(url, verb, hash) { - equal(url, '/query/posts'); + assert.equal(url, '/query/posts'); return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); }; @@ -1110,13 +1112,13 @@ test("query - passes buildURL the requestType", function() { })); }); -test("query - if `sortQueryParams` is falsey, query params are not sorted at all", function() { +test("query - if `sortQueryParams` is falsey, query params are not sorted at all", function(assert) { adapter.ajax = function(url, verb, hash) { passedUrl = url; passedVerb = verb; passedHash = hash; - deepEqual(Object.keys(hash.data), ["params", "in", "wrong", "order"], 'query params are received in their original order'); + assert.deepEqual(Object.keys(hash.data), ["params", "in", "wrong", "order"], 'query params are received in their original order'); return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); }; @@ -1128,13 +1130,13 @@ test("query - if `sortQueryParams` is falsey, query params are not sorted at all })); }); -test("query - if `sortQueryParams` is a custom function, query params passed through that function", function() { +test("query - if `sortQueryParams` is a custom function, query params passed through that function", function(assert) { adapter.ajax = function(url, verb, hash) { passedUrl = url; passedVerb = verb; passedHash = hash; - deepEqual(Object.keys(hash.data), ["wrong", "params", "order", "in"], 'query params are received in reverse alphabetical order'); + assert.deepEqual(Object.keys(hash.data), ["wrong", "params", "order", "in"], 'query params are received in reverse alphabetical order'); return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); }; @@ -1155,14 +1157,14 @@ test("query - if `sortQueryParams` is a custom function, query params passed thr })); }); -test("query - payload 'meta' is accessible on the record array", function() { +test("query - payload 'meta' is accessible on the record array", function(assert) { ajaxResponse({ meta: { offset: 5 }, posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); store.query('post', { page: 2 }).then(async(function(posts) { - equal( + assert.equal( posts.get('meta.offset'), 5, "Reponse metadata can be accessed with recordArray.meta" @@ -1170,14 +1172,14 @@ test("query - payload 'meta' is accessible on the record array", function() { })); }); -test("query - each record array can have it's own meta object", function() { +test("query - each record array can have it's own meta object", function(assert) { ajaxResponse({ meta: { offset: 5 }, posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); store.query('post', { page: 2 }).then(async(function(posts) { - equal( + assert.equal( posts.get('meta.offset'), 5, "Reponse metadata can be accessed with recordArray.meta" @@ -1187,14 +1189,14 @@ test("query - each record array can have it's own meta object", function() { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); store.query('post', { page: 1 }).then(async(function(newPosts) { - equal(newPosts.get('meta.offset'), 1, 'new array has correct metadata'); - equal(posts.get('meta.offset'), 5, 'metadata on the old array hasnt been clobbered'); + assert.equal(newPosts.get('meta.offset'), 1, 'new array has correct metadata'); + assert.equal(posts.get('meta.offset'), 5, 'metadata on the old array hasnt been clobbered'); })); })); }); -test("query - returning an array populates the array", function() { +test("query - returning an array populates the array", function(assert) { ajaxResponse({ posts: [ { id: 1, name: "Rails is omakase" }, @@ -1202,27 +1204,27 @@ test("query - returning an array populates the array", function() { }); store.query('post', { page: 1 }).then(async(function(posts) { - equal(passedUrl, '/posts'); - equal(passedVerb, 'GET'); - deepEqual(passedHash.data, { page: 1 }); + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, { page: 1 }); var post1 = store.peekRecord('post', 1); var post2 = store.peekRecord('post', 2); - deepEqual( + assert.deepEqual( post1.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }, "Post 1 is loaded" ); - deepEqual( + assert.deepEqual( post2.getProperties('id', 'name'), { id: "2", name: "The Parley Letter" }, "Post 2 is loaded" ); - equal(posts.get('length'), 2, "The posts are in the array"); - equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); - deepEqual( + assert.equal(posts.get('length'), 2, "The posts are in the array"); + assert.equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); + assert.deepEqual( posts.toArray(), [post1, post2], "The correct records are in the array" @@ -1230,7 +1232,7 @@ test("query - returning an array populates the array", function() { })); }); -test("query - returning sideloaded data loads the data", function() { +test("query - returning sideloaded data loads the data", function(assert) { ajaxResponse({ posts: [ { id: 1, name: "Rails is omakase" }, @@ -1242,11 +1244,11 @@ test("query - returning sideloaded data loads the data", function() { store.query('post', { page: 1 }).then(async(function(posts) { var comment = store.peekRecord('comment', 1); - deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); + assert.deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); })); }); -test("query - data is normalized through custom serializers", function() { +test("query - data is normalized through custom serializers", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', attrs: { name: '_NAME_' } @@ -1261,21 +1263,21 @@ test("query - data is normalized through custom serializers", function() { var post1 = store.peekRecord('post', 1); var post2 = store.peekRecord('post', 2); - deepEqual( + assert.deepEqual( post1.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }, "Post 1 is loaded" ); - deepEqual( + assert.deepEqual( post2.getProperties('id', 'name'), { id: "2", name: "The Parley Letter" }, "Post 2 is loaded" ); - equal(posts.get('length'), 2, "The posts are in the array"); - equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); - deepEqual( + assert.equal(posts.get('length'), 2, "The posts are in the array"); + assert.equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); + assert.deepEqual( posts.toArray(), [post1, post2], "The correct records are in the array" @@ -1283,7 +1285,7 @@ test("query - data is normalized through custom serializers", function() { })); }); -test("queryRecord - returns a single record in an object", function() { +test("queryRecord - returns a single record in an object", function(assert) { ajaxResponse({ post: { id: '1', @@ -1292,11 +1294,11 @@ test("queryRecord - returns a single record in an object", function() { }); store.queryRecord('post', { slug: 'ember-js-rocks' }).then(async(function(post) { - deepEqual(post.get('name'), "Ember.js rocks"); + assert.deepEqual(post.get('name'), "Ember.js rocks"); })); }); -test("queryRecord - returning sideloaded data loads the data", function() { +test("queryRecord - returning sideloaded data loads the data", function(assert) { ajaxResponse({ post: { id: 1, name: "Rails is omakase" }, comments: [{ id: 1, name: "FIRST" }] @@ -1305,11 +1307,11 @@ test("queryRecord - returning sideloaded data loads the data", function() { store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(async(function(post) { var comment = store.peekRecord('comment', 1); - deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); + assert.deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); })); }); -test("queryRecord - returning an array picks the first one but saves all records to the store", function() { +test("queryRecord - returning an array picks the first one but saves all records to the store", function(assert) { ajaxResponse({ post: [{ id: 1, name: "Rails is omakase" }, { id: 2, name: "Ember is js" }] }); @@ -1317,12 +1319,12 @@ test("queryRecord - returning an array picks the first one but saves all records store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(async(function(post) { var post2 = store.peekRecord('post', 2); - deepEqual(post.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }); - deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "Ember is js" }); + assert.deepEqual(post.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }); + assert.deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "Ember is js" }); })); }); -test("queryRecord - data is normalized through custom serializers", function() { +test("queryRecord - data is normalized through custom serializers", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', attrs: { name: '_NAME_' } @@ -1334,7 +1336,7 @@ test("queryRecord - data is normalized through custom serializers", function() { store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(async(function(post) { - deepEqual( + assert.deepEqual( post.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }, "Post 1 is loaded with correct data" @@ -1342,7 +1344,7 @@ test("queryRecord - data is normalized through custom serializers", function() { })); }); -test("findMany - findMany uses a correct URL to access the records", function() { +test("findMany - findMany uses a correct URL to access the records", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; @@ -1376,12 +1378,12 @@ test("findMany - findMany uses a correct URL to access the records", function() ] }); run(post, 'get', 'comments').then(async(function(comments) { - equal(passedUrl, "/comments"); - deepEqual(passedHash, { data: { ids: ["1", "2", "3"] } }); + assert.equal(passedUrl, "/comments"); + assert.deepEqual(passedHash, { data: { ids: ["1", "2", "3"] } }); })); }); -test("findMany - passes buildURL the requestType", function() { +test("findMany - passes buildURL the requestType", function(assert) { adapter.buildURL = function(type, id, snapshot, requestType) { return "/" + requestType + "/" + type; }; @@ -1419,11 +1421,11 @@ test("findMany - passes buildURL the requestType", function() { ] }); run(post, 'get', 'comments').then(async(function(comments) { - equal(passedUrl, "/findMany/comment"); + assert.equal(passedUrl, "/findMany/comment"); })); }); -test("findMany - findMany does not coalesce by default", function() { +test("findMany - findMany does not coalesce by default", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); run(function() { @@ -1457,12 +1459,12 @@ test("findMany - findMany does not coalesce by default", function() { ] }); run(post, 'get', 'comments').then(async(function(comments) { - equal(passedUrl, "/comments/3"); - equal(passedHash, null); + assert.equal(passedUrl, "/comments/3"); + assert.equal(passedHash, null); })); }); -test("findMany - returning an array populates the array", function() { +test("findMany - returning an array populates the array", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; @@ -1503,11 +1505,11 @@ test("findMany - returning an array populates the array", function() { var comment2 = store.peekRecord('comment', 2); var comment3 = store.peekRecord('comment', 3); - deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); - deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); - deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); + assert.deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); + assert.deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); + assert.deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); - deepEqual( + assert.deepEqual( comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array" @@ -1515,7 +1517,7 @@ test("findMany - returning an array populates the array", function() { })); }); -test("findMany - returning sideloaded data loads the data", function() { +test("findMany - returning sideloaded data loads the data", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; @@ -1560,18 +1562,18 @@ test("findMany - returning sideloaded data loads the data", function() { var comment4 = store.peekRecord('comment', 4); var post2 = store.peekRecord('post', 2); - deepEqual( + assert.deepEqual( comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array" ); - deepEqual(comment4.getProperties('id', 'name'), { id: "4", name: "Unrelated comment" }); - deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "The Parley Letter" }); + assert.deepEqual(comment4.getProperties('id', 'name'), { id: "4", name: "Unrelated comment" }); + assert.deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "The Parley Letter" }); })); }); -test("findMany - a custom serializer is used if present", function() { +test("findMany - a custom serializer is used if present", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', @@ -1621,15 +1623,15 @@ test("findMany - a custom serializer is used if present", function() { var comment2 = store.peekRecord('comment', 2); var comment3 = store.peekRecord('comment', 3); - deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); - deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); - deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); + assert.deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); + assert.deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); + assert.deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); - deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); + assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); })); }); -test("findHasMany - returning an array populates the array", function() { +test("findHasMany - returning an array populates the array", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -1663,26 +1665,26 @@ test("findHasMany - returning an array populates the array", function() { return post.get('comments'); })).then(async(function(comments) { - equal(passedUrl, '/posts/1/comments'); - equal(passedVerb, 'GET'); - equal(passedHash, undefined); + assert.equal(passedUrl, '/posts/1/comments'); + assert.equal(passedVerb, 'GET'); + assert.equal(passedHash, undefined); var comment1 = store.peekRecord('comment', 1); var comment2 = store.peekRecord('comment', 2); var comment3 = store.peekRecord('comment', 3); - deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); - deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); - deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); + assert.deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); + assert.deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); + assert.deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); - deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); + assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); })); }); -test("findHasMany - passes buildURL the requestType", function() { +test("findHasMany - passes buildURL the requestType", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.buildURL = function(type, id, snapshot, requestType) { - equal(requestType, 'findHasMany'); + assert.equal(requestType, 'findHasMany'); }; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -1723,7 +1725,7 @@ test("findHasMany - passes buildURL the requestType", function() { -test("findMany - returning sideloaded data loads the data", function() { +test("findMany - returning sideloaded data loads the data", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; @@ -1764,13 +1766,13 @@ test("findMany - returning sideloaded data loads the data", function() { var comment3 = store.peekRecord('comment', 3); var post2 = store.peekRecord('post', 2); - deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); + assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); - deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "The Parley Letter" }); + assert.deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "The Parley Letter" }); })); }); -test("findMany - a custom serializer is used if present", function() { +test("findMany - a custom serializer is used if present", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', @@ -1817,18 +1819,18 @@ test("findMany - a custom serializer is used if present", function() { var comment2 = store.peekRecord('comment', 2); var comment3 = store.peekRecord('comment', 3); - deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); - deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); - deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); + assert.deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); + assert.deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); + assert.deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); - deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); + assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); })); }); -test('findBelongsTo - passes buildURL the requestType', function() { +test('findBelongsTo - passes buildURL the requestType', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.buildURL = function(type, id, snapshot, requestType) { - equal(requestType, 'findBelongsTo'); + assert.equal(requestType, 'findBelongsTo'); }; Comment.reopen({ post: DS.belongsTo('post', { async: true }) }); @@ -1860,7 +1862,7 @@ test('findBelongsTo - passes buildURL the requestType', function() { })); }); -test('coalesceFindRequests warns if the expected records are not returned in the coalesced request', function() { +test('coalesceFindRequests warns if the expected records are not returned in the coalesced request', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -1893,7 +1895,7 @@ test('coalesceFindRequests warns if the expected records are not returned in the }, /expected to find records with the following ids in the adapter response but they were missing: \[2,3\]/); }); -test('groupRecordsForFindMany groups records based on their url', function() { +test('groupRecordsForFindMany groups records based on their url', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; @@ -1907,12 +1909,12 @@ test('groupRecordsForFindMany groups records based on their url', function() { }; adapter.findRecord = function(store, type, id, snapshot) { - equal(id, '1'); + assert.equal(id, '1'); return Ember.RSVP.resolve({ comments: { id: 1 } }); }; adapter.findMany = function(store, type, ids, snapshots) { - deepEqual(ids, ['2', '3']); + assert.deepEqual(ids, ['2', '3']); return Ember.RSVP.resolve({ comments: [{ id: 2 }, { id: 3 }] }); }; @@ -1941,7 +1943,7 @@ test('groupRecordsForFindMany groups records based on their url', function() { }); }); -test('groupRecordsForFindMany groups records correctly when singular URLs are encoded as query params', function() { +test('groupRecordsForFindMany groups records correctly when singular URLs are encoded as query params', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; @@ -1955,12 +1957,12 @@ test('groupRecordsForFindMany groups records correctly when singular URLs are en }; adapter.findRecord = function(store, type, id, snapshot) { - equal(id, '1'); + assert.equal(id, '1'); return Ember.RSVP.resolve({ comments: { id: 1 } }); }; adapter.findMany = function(store, type, ids, snapshots) { - deepEqual(ids, ['2', '3']); + assert.deepEqual(ids, ['2', '3']); return Ember.RSVP.resolve({ comments: [{ id: 2 }, { id: 3 }] }); }; var post; @@ -1989,7 +1991,7 @@ test('groupRecordsForFindMany groups records correctly when singular URLs are en }); }); -test('normalizeKey - to set up _ids and _id', function() { +test('normalizeKey - to set up _ids and _id', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ keyForAttribute: function(attr) { return Ember.String.underscore(attr); @@ -2050,18 +2052,18 @@ test('normalizeKey - to set up _ids and _id', function() { run(function() { store.find('post', 1).then(async(function(post) { - equal(post.get('authorName'), "@d2h"); - equal(post.get('author.name'), "D2H"); - deepEqual(post.get('comments').mapBy('body'), ["Rails is unagi", "What is omakase?"]); + assert.equal(post.get('authorName'), "@d2h"); + assert.equal(post.get('author.name'), "D2H"); + assert.deepEqual(post.get('comments').mapBy('body'), ["Rails is unagi", "What is omakase?"]); })); }); }); -test('groupRecordsForFindMany splits up calls for large ids', function() { +test('groupRecordsForFindMany splits up calls for large ids', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - expect(2); + assert.expect(2); function repeatChar(character, n) { return new Array(n+1).join(character); @@ -2092,14 +2094,14 @@ test('groupRecordsForFindMany splits up calls for large ids', function() { adapter.findRecord = function(store, type, id, snapshot) { if (id === a2000 || id === b2000) { - ok(true, "Found " + id); + assert.ok(true, "Found " + id); } return Ember.RSVP.resolve({ comments: { id: id } }); }; adapter.findMany = function(store, type, ids, snapshots) { - ok(false, "findMany should not be called - we expect 2 calls to find for a2000 and b2000"); + assert.ok(false, "findMany should not be called - we expect 2 calls to find for a2000 and b2000"); return Ember.RSVP.reject(); }; @@ -2108,11 +2110,11 @@ test('groupRecordsForFindMany splits up calls for large ids', function() { }); }); -test('groupRecordsForFindMany groups calls for small ids', function() { +test('groupRecordsForFindMany groups calls for small ids', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - expect(1); + assert.expect(1); function repeatChar(character, n) { return new Array(n+1).join(character); @@ -2143,12 +2145,12 @@ test('groupRecordsForFindMany groups calls for small ids', function() { adapter.coalesceFindRequests = true; adapter.findRecord = function(store, type, id, snapshot) { - ok(false, "find should not be called - we expect 1 call to findMany for a100 and b100"); + assert.ok(false, "find should not be called - we expect 1 call to findMany for a100 and b100"); return Ember.RSVP.reject(); }; adapter.findMany = function(store, type, ids, snapshots) { - deepEqual(ids, [a100, b100]); + assert.deepEqual(ids, [a100, b100]); return Ember.RSVP.resolve({ comments: [{ id: a100 }, { id: b100 }] }); }; @@ -2158,8 +2160,8 @@ test('groupRecordsForFindMany groups calls for small ids', function() { }); -test("calls adapter.handleResponse with the jqXHR and json", function() { - expect(2); +test("calls adapter.handleResponse with the jqXHR and json", function(assert) { + assert.expect(2); var originalAjax = Ember.$.ajax; var jqXHR = { status: 200, @@ -2177,8 +2179,8 @@ test("calls adapter.handleResponse with the jqXHR and json", function() { }; adapter.handleResponse = function(status, headers, json) { - deepEqual(status, 200); - deepEqual(json, data); + assert.deepEqual(status, 200); + assert.deepEqual(json, data); return json; }; @@ -2191,8 +2193,8 @@ test("calls adapter.handleResponse with the jqXHR and json", function() { } }); -test('calls handleResponse with jqXHR, jqXHR.responseText', function() { - expect(3); +test('calls handleResponse with jqXHR, jqXHR.responseText', function(assert) { + assert.expect(3); var originalAjax = Ember.$.ajax; var jqXHR = { status: 400, @@ -2205,15 +2207,15 @@ test('calls handleResponse with jqXHR, jqXHR.responseText', function() { }; adapter.handleResponse = function(status, headers, json) { - deepEqual(status, 400); - deepEqual(json, jqXHR.responseText); + assert.deepEqual(status, 400); + assert.deepEqual(json, jqXHR.responseText); return new DS.AdapterError('nope!'); }; try { run(function() { store.find('post', '1').catch(function(err) { - ok(err, 'promise rejected'); + assert.ok(err, 'promise rejected'); }); }); } finally { @@ -2221,8 +2223,8 @@ test('calls handleResponse with jqXHR, jqXHR.responseText', function() { } }); -test("rejects promise if DS.AdapterError is returned from adapter.handleResponse", function() { - expect(3); +test("rejects promise if DS.AdapterError is returned from adapter.handleResponse", function(assert) { + assert.expect(3); var originalAjax = Ember.$.ajax; var jqXHR = { getAllResponseHeaders: function() { return ''; } @@ -2236,22 +2238,22 @@ test("rejects promise if DS.AdapterError is returned from adapter.handleResponse }; adapter.handleResponse = function(status, headers, json) { - ok(true, 'handleResponse should be called'); + assert.ok(true, 'handleResponse should be called'); return new DS.AdapterError(json); }; Ember.run(function() { store.find('post', '1').then(null, function(reason) { - ok(true, 'promise should be rejected'); - ok(reason instanceof DS.AdapterError, 'reason should be an instance of DS.AdapterError'); + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.AdapterError, 'reason should be an instance of DS.AdapterError'); }); }); Ember.$.ajax = originalAjax; }); -test('on error appends errorThrown for sanity', function() { - expect(2); +test('on error appends errorThrown for sanity', function(assert) { + assert.expect(2); var originalAjax = Ember.$.ajax; var jqXHR = { @@ -2266,14 +2268,14 @@ test('on error appends errorThrown for sanity', function() { }; adapter.handleResponse = function(status, headers, payload) { - ok(false); + assert.ok(false); }; try { run(function() { store.find('post', '1').catch(function(err) { - equal(err, errorThrown); - ok(err, 'promise rejected'); + assert.equal(err, errorThrown); + assert.ok(err, 'promise rejected'); }); }); } finally { @@ -2282,8 +2284,8 @@ test('on error appends errorThrown for sanity', function() { }); -test('on error wraps the error string in an DS.AdapterError object', function() { - expect(2); +test('on error wraps the error string in an DS.AdapterError object', function(assert) { + assert.expect(2); var originalAjax = Ember.$.ajax; var jqXHR = { @@ -2300,8 +2302,8 @@ test('on error wraps the error string in an DS.AdapterError object', function() try { run(function() { store.find('post', '1').catch(function(err) { - equal(err.errors[0].detail, errorThrown); - ok(err, 'promise rejected'); + assert.equal(err.errors[0].detail, errorThrown); + assert.ok(err, 'promise rejected'); }); }); } finally { @@ -2310,7 +2312,7 @@ test('on error wraps the error string in an DS.AdapterError object', function() }); test('findAll resolves with a collection of DS.Models, not DS.InternalModels', () => { - expect(4); + assert.expect(4); ajaxResponse({ posts: [ @@ -2331,14 +2333,14 @@ test('findAll resolves with a collection of DS.Models, not DS.InternalModels', ( run(() => { store.findAll('post').then(async((posts) => { - equal(get(posts, 'length'), 3); + assert.equal(get(posts, 'length'), 3); posts.forEach((post) => ok(post instanceof DS.Model)); })); }); }); -test("create - sideloaded records are pushed to the store", function() { +test("create - sideloaded records are pushed to the store", function(assert) { Post.reopen({ comments: DS.hasMany('comment') }); @@ -2364,9 +2366,9 @@ test("create - sideloaded records are pushed to the store", function() { post.save().then(function(post) { var comments = store.peekAll('comment'); - equal(get(comments, 'length'), 2, 'comments.length is correct'); - equal(get(comments, 'firstObject.name'), 'First comment', 'comments.firstObject.name is correct'); - equal(get(comments, 'lastObject.name'), 'Second comment', 'comments.lastObject.name is correct'); + assert.equal(get(comments, 'length'), 2, 'comments.length is correct'); + assert.equal(get(comments, 'firstObject.name'), 'First comment', 'comments.firstObject.name is correct'); + assert.equal(get(comments, 'lastObject.name'), 'Second comment', 'comments.lastObject.name is correct'); }); }); }); diff --git a/tests/integration/adapter/serialize-test.js b/tests/integration/adapter/serialize-test.js index e543e5dcfd4..348edeb6c0d 100644 --- a/tests/integration/adapter/serialize-test.js +++ b/tests/integration/adapter/serialize-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var run = Ember.run; var env, store, adapter, serializer; module("integration/adapter/serialize - DS.Adapter integration test", { - setup: function() { + beforeEach: function() { var Person = DS.Model.extend({ name: DS.attr('string') }); @@ -17,16 +19,16 @@ module("integration/adapter/serialize - DS.Adapter integration test", { serializer = store.serializerFor('person'); }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); -test("serialize() is delegated to the serializer", function() { - expect(1); +test("serialize() is delegated to the serializer", function(assert) { + assert.expect(1); serializer.serialize = function(snapshot, options) { - deepEqual(options, { foo: 'bar' }); + assert.deepEqual(options, { foo: 'bar' }); }; run(function() { diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 016a76240e9..0fc2f21120d 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; /* @@ -21,7 +23,7 @@ var run = Ember.run; var Person, Dog, env, store, adapter; module("integration/adapter/store-adapter - DS.Store and DS.Adapter integration test", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ updatedAt: DS.attr('string'), name: DS.attr('string'), @@ -38,12 +40,12 @@ module("integration/adapter/store-adapter - DS.Store and DS.Adapter integration adapter = env.adapter; }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); -test("Records loaded multiple times and retrieved in recordArray are ready to send state events", function() { +test("Records loaded multiple times and retrieved in recordArray are ready to send state events", function(assert) { adapter.query = function(store, type, query, recordArray) { return Ember.RSVP.resolve([{ id: 1, @@ -59,11 +61,11 @@ test("Records loaded multiple times and retrieved in recordArray are ready to se return Ember.RSVP.hash({ people: people, people2: people2 }); })).then(async(function(results) { - equal(results.people2.get('length'), 2, 'return the elements'); - ok(results.people2.get('isLoaded'), 'array is loaded'); + assert.equal(results.people2.get('length'), 2, 'return the elements'); + assert.ok(results.people2.get('isLoaded'), 'array is loaded'); var person = results.people.objectAt(0); - ok(person.get('isLoaded'), 'record is loaded'); + assert.ok(person.get('isLoaded'), 'record is loaded'); // delete record will not throw exception person.deleteRecord(); @@ -71,18 +73,18 @@ test("Records loaded multiple times and retrieved in recordArray are ready to se }); -test("by default, createRecords calls createRecord once per record", function() { +test("by default, createRecords calls createRecord once per record", function(assert) { var count = 1; adapter.shouldBackgroundReloadRecord = () => false; adapter.createRecord = function(store, type, snapshot) { - equal(type, Person, "the type is correct"); + assert.equal(type, Person, "the type is correct"); if (count === 1) { - equal(snapshot.attr('name'), "Tom Dale"); + assert.equal(snapshot.attr('name'), "Tom Dale"); } else if (count === 2) { - equal(snapshot.attr('name'), "Yehuda Katz"); + assert.equal(snapshot.attr('name'), "Yehuda Katz"); } else { - ok(false, "should not have invoked more than 2 times"); + assert.ok(false, "should not have invoked more than 2 times"); } var hash = snapshot.attributes(); @@ -111,28 +113,28 @@ test("by default, createRecords calls createRecord once per record", function() asyncEqual(tom, store.findRecord('person', 1), "Once an ID is in, find returns the same object"); asyncEqual(yehuda, store.findRecord('person', 2), "Once an ID is in, find returns the same object"); - equal(get(tom, 'updatedAt'), "now", "The new information is received"); - equal(get(yehuda, 'updatedAt'), "now", "The new information is received"); + assert.equal(get(tom, 'updatedAt'), "now", "The new information is received"); + assert.equal(get(yehuda, 'updatedAt'), "now", "The new information is received"); })); }); -test("by default, updateRecords calls updateRecord once per record", function() { +test("by default, updateRecords calls updateRecord once per record", function(assert) { var count = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { - equal(type, Person, "the type is correct"); + assert.equal(type, Person, "the type is correct"); if (count === 0) { - equal(snapshot.attr('name'), "Tom Dale"); + assert.equal(snapshot.attr('name'), "Tom Dale"); } else if (count === 1) { - equal(snapshot.attr('name'), "Yehuda Katz"); + assert.equal(snapshot.attr('name'), "Yehuda Katz"); } else { - ok(false, "should not get here"); + assert.ok(false, "should not get here"); } count++; - equal(snapshot.record.get('isSaving'), true, "record is saving"); + assert.equal(snapshot.record.get('isSaving'), true, "record is saving"); return Ember.RSVP.resolve(); }; @@ -174,29 +176,29 @@ test("by default, updateRecords calls updateRecord once per record", function() var tom = records.tom; var yehuda = records.yehuda; - equal(tom.get('isSaving'), false, "record is no longer saving"); - equal(tom.get('isLoaded'), true, "record is loaded"); + assert.equal(tom.get('isSaving'), false, "record is no longer saving"); + assert.equal(tom.get('isLoaded'), true, "record is loaded"); - equal(yehuda.get('isSaving'), false, "record is no longer saving"); - equal(yehuda.get('isLoaded'), true, "record is loaded"); + assert.equal(yehuda.get('isSaving'), false, "record is no longer saving"); + assert.equal(yehuda.get('isLoaded'), true, "record is loaded"); })); }); -test("calling store.didSaveRecord can provide an optional hash", function() { +test("calling store.didSaveRecord can provide an optional hash", function(assert) { var count = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { - equal(type, Person, "the type is correct"); + assert.equal(type, Person, "the type is correct"); count++; if (count === 1) { - equal(snapshot.attr('name'), "Tom Dale"); + assert.equal(snapshot.attr('name'), "Tom Dale"); return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", updatedAt: "now" }); } else if (count === 2) { - equal(snapshot.attr('name'), "Yehuda Katz"); + assert.equal(snapshot.attr('name'), "Yehuda Katz"); return Ember.RSVP.resolve({ id: 2, name: "Yehuda Katz", updatedAt: "now!" }); } else { - ok(false, "should not get here"); + assert.ok(false, "should not get here"); } }; @@ -236,28 +238,28 @@ test("calling store.didSaveRecord can provide an optional hash", function() { var tom = records.tom; var yehuda = records.yehuda; - equal(get(tom, 'hasDirtyAttributes'), false, "the record should not be dirty"); - equal(get(tom, 'updatedAt'), "now", "the hash was updated"); + assert.equal(get(tom, 'hasDirtyAttributes'), false, "the record should not be dirty"); + assert.equal(get(tom, 'updatedAt'), "now", "the hash was updated"); - equal(get(yehuda, 'hasDirtyAttributes'), false, "the record should not be dirty"); - equal(get(yehuda, 'updatedAt'), "now!", "the hash was updated"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "the record should not be dirty"); + assert.equal(get(yehuda, 'updatedAt'), "now!", "the hash was updated"); })); }); -test("by default, deleteRecord calls deleteRecord once per record", function() { - expect(4); +test("by default, deleteRecord calls deleteRecord once per record", function(assert) { + assert.expect(4); var count = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.deleteRecord = function(store, type, snapshot) { - equal(type, Person, "the type is correct"); + assert.equal(type, Person, "the type is correct"); if (count === 0) { - equal(snapshot.attr('name'), "Tom Dale"); + assert.equal(snapshot.attr('name'), "Tom Dale"); } else if (count === 1) { - equal(snapshot.attr('name'), "Yehuda Katz"); + assert.equal(snapshot.attr('name'), "Yehuda Katz"); } else { - ok(false, "should not get here"); + assert.ok(false, "should not get here"); } count++; @@ -302,20 +304,20 @@ test("by default, deleteRecord calls deleteRecord once per record", function() { })); }); -test("by default, destroyRecord calls deleteRecord once per record without requiring .save", function() { - expect(4); +test("by default, destroyRecord calls deleteRecord once per record without requiring .save", function(assert) { + assert.expect(4); var count = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.deleteRecord = function(store, type, snapshot) { - equal(type, Person, "the type is correct"); + assert.equal(type, Person, "the type is correct"); if (count === 0) { - equal(snapshot.attr('name'), "Tom Dale"); + assert.equal(snapshot.attr('name'), "Tom Dale"); } else if (count === 1) { - equal(snapshot.attr('name'), "Yehuda Katz"); + assert.equal(snapshot.attr('name'), "Yehuda Katz"); } else { - ok(false, "should not get here"); + assert.ok(false, "should not get here"); } count++; @@ -357,21 +359,21 @@ test("by default, destroyRecord calls deleteRecord once per record without requi })); }); -test("if an existing model is edited then deleted, deleteRecord is called on the adapter", function() { - expect(5); +test("if an existing model is edited then deleted, deleteRecord is called on the adapter", function(assert) { + assert.expect(5); var count = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.deleteRecord = function(store, type, snapshot) { count++; - equal(snapshot.id, 'deleted-record', "should pass correct record to deleteRecord"); - equal(count, 1, "should only call deleteRecord method of adapter once"); + assert.equal(snapshot.id, 'deleted-record', "should pass correct record to deleteRecord"); + assert.equal(count, 1, "should only call deleteRecord method of adapter once"); return Ember.RSVP.resolve(); }; adapter.updateRecord = function() { - ok(false, "should not have called updateRecord method of adapter"); + assert.ok(false, "should not have called updateRecord method of adapter"); }; // Load data for a record into the store. @@ -391,17 +393,17 @@ test("if an existing model is edited then deleted, deleteRecord is called on the run(store, 'findRecord', 'person', 'deleted-record').then(async(function(tom) { tom.set('name', "Tom Mothereffin' Dale"); - equal(get(tom, 'hasDirtyAttributes'), true, "precond - record should be dirty after editing"); + assert.equal(get(tom, 'hasDirtyAttributes'), true, "precond - record should be dirty after editing"); tom.deleteRecord(); return tom.save(); })).then(async(function(tom) { - equal(get(tom, 'hasDirtyAttributes'), false, "record should not be dirty"); - equal(get(tom, 'isDeleted'), true, "record should be considered deleted"); + assert.equal(get(tom, 'hasDirtyAttributes'), false, "record should not be dirty"); + assert.equal(get(tom, 'isDeleted'), true, "record should be considered deleted"); })); }); -test("if a deleted record errors, it enters the error state", function() { +test("if a deleted record errors, it enters the error state", function(assert) { var count = 0; var error = new DS.AdapterError(); @@ -434,21 +436,21 @@ test("if a deleted record errors, it enters the error state", function() { person.deleteRecord(); return person.save(); })).then(null, async(function() { - equal(tom.get('isError'), true, "Tom is now errored"); - equal(tom.get('adapterError'), error, "error object is exposed"); + assert.equal(tom.get('isError'), true, "Tom is now errored"); + assert.equal(tom.get('adapterError'), error, "error object is exposed"); // this time it succeeds return tom.save(); })).then(async(function() { - equal(tom.get('isError'), false, "Tom is not errored anymore"); - equal(tom.get('adapterError'), null, "error object is discarded"); + assert.equal(tom.get('isError'), false, "Tom is not errored anymore"); + assert.equal(tom.get('adapterError'), null, "error object is discarded"); })); }); }); -test("if a created record is marked as invalid by the server, it enters an error state", function() { +test("if a created record is marked as invalid by the server, it enters an error state", function(assert) { adapter.createRecord = function(store, type, snapshot) { - equal(type, Person, "the type is correct"); + assert.equal(type, Person, "the type is correct"); if (snapshot.attr('name').indexOf('Bro') === -1) { return Ember.RSVP.reject(new DS.InvalidError([ @@ -472,30 +474,30 @@ test("if a created record is marked as invalid by the server, it enters an error // before flushing any scheduled behavior. Ember.run(function() { yehuda.save().then(null, async(function(error) { - equal(get(yehuda, 'isValid'), false, "the record is invalid"); - ok(get(yehuda, 'errors.name'), "The errors.name property exists"); + assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); + assert.ok(get(yehuda, 'errors.name'), "The errors.name property exists"); set(yehuda, 'updatedAt', true); - equal(get(yehuda, 'isValid'), false, "the record is still invalid"); + assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid"); set(yehuda, 'name', "Brohuda Brokatz"); - equal(get(yehuda, 'isValid'), true, "the record is no longer invalid after changing"); - equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); + assert.equal(get(yehuda, 'isValid'), true, "the record is no longer invalid after changing"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); - equal(get(yehuda, 'isNew'), true, "precond - record is still new"); + assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); return yehuda.save(); })).then(async(function(person) { - strictEqual(person, yehuda, "The promise resolves with the saved record"); + assert.strictEqual(person, yehuda, "The promise resolves with the saved record"); - equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); - equal(get(yehuda, 'isNew'), false, "record is no longer new"); + assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); + assert.equal(get(yehuda, 'isNew'), false, "record is no longer new"); })); }); }); -test("allows errors on arbitrary properties on create", function() { +test("allows errors on arbitrary properties on create", function(assert) { adapter.createRecord = function(store, type, snapshot) { if (snapshot.attr('name').indexOf('Bro') === -1) { return Ember.RSVP.reject(new DS.InvalidError([ @@ -520,35 +522,35 @@ test("allows errors on arbitrary properties on create", function() { // before flushing any scheduled behavior. run(function() { yehuda.save().then(null, async(function(error) { - equal(get(yehuda, 'isValid'), false, "the record is invalid"); - ok(get(yehuda, 'errors.base'), "The errors.base property exists"); - deepEqual(get(yehuda, 'errors').errorsFor('base'), [{ attribute: 'base', message: "is a generally unsavoury character" }]); + assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); + assert.ok(get(yehuda, 'errors.base'), "The errors.base property exists"); + assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), [{ attribute: 'base', message: "is a generally unsavoury character" }]); set(yehuda, 'updatedAt', true); - equal(get(yehuda, 'isValid'), false, "the record is still invalid"); + assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid"); set(yehuda, 'name', "Brohuda Brokatz"); - equal(get(yehuda, 'isValid'), false, "the record is still invalid as far as we know"); - equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); + assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid as far as we know"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); - equal(get(yehuda, 'isNew'), true, "precond - record is still new"); + assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); return yehuda.save(); })).then(async(function(person) { - strictEqual(person, yehuda, "The promise resolves with the saved record"); - ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); - deepEqual(get(yehuda, 'errors').errorsFor('base'), []); - equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); - equal(get(yehuda, 'isNew'), false, "record is no longer new"); + assert.strictEqual(person, yehuda, "The promise resolves with the saved record"); + assert.ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); + assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), []); + assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); + assert.equal(get(yehuda, 'isNew'), false, "record is no longer new"); })); }); }); -test("if a created record is marked as invalid by the server, you can attempt the save again", function() { +test("if a created record is marked as invalid by the server, you can attempt the save again", function(assert) { var saveCount = 0; adapter.createRecord = function(store, type, snapshot) { - equal(type, Person, "the type is correct"); + assert.equal(type, Person, "the type is correct"); saveCount++; if (snapshot.attr('name').indexOf('Bro') === -1) { @@ -574,32 +576,32 @@ test("if a created record is marked as invalid by the server, you can attempt th // before flushing any scheduled behavior. Ember.run(function() { yehuda.save().then(null, async(function(reason) { - equal(saveCount, 1, "The record has been saved once"); - ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); - equal(get(yehuda, 'isValid'), false, "the record is invalid"); - equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); - ok(get(yehuda, 'errors.name'), "The errors.name property exists"); - equal(get(yehuda, 'isNew'), true, "precond - record is still new"); + assert.equal(saveCount, 1, "The record has been saved once"); + assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); + assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); + assert.ok(get(yehuda, 'errors.name'), "The errors.name property exists"); + assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); return yehuda.save(); })).then(null, async(function(reason) { - equal(saveCount, 2, "The record has been saved twice"); - ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); - equal(get(yehuda, 'isValid'), false, "the record is still invalid"); - equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); - ok(get(yehuda, 'errors.name'), "The errors.name property exists"); - equal(get(yehuda, 'isNew'), true, "precond - record is still new"); + assert.equal(saveCount, 2, "The record has been saved twice"); + assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); + assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); + assert.ok(get(yehuda, 'errors.name'), "The errors.name property exists"); + assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); set(yehuda, 'name', 'Brohuda Brokatz'); return yehuda.save(); })).then(async(function(person) { - equal(saveCount, 3, "The record has been saved thrice"); - equal(get(yehuda, 'isValid'), true, "record is valid"); - equal(get(yehuda, 'hasDirtyAttributes'), false, "record is not dirty"); - equal(get(yehuda, 'errors.isEmpty'), true, "record has no errors"); + assert.equal(saveCount, 3, "The record has been saved thrice"); + assert.equal(get(yehuda, 'isValid'), true, "record is valid"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is not dirty"); + assert.equal(get(yehuda, 'errors.isEmpty'), true, "record has no errors"); })); }); }); -test("if a created record is marked as erred by the server, it enters an error state", function() { +test("if a created record is marked as erred by the server, it enters an error state", function(assert) { var error = new DS.AdapterError(); adapter.createRecord = function(store, type, snapshot) { @@ -610,16 +612,16 @@ test("if a created record is marked as erred by the server, it enters an error s var person = store.createRecord('person', { id: 1, name: "John Doe" }); person.save().then(null, async(function() { - ok(get(person, 'isError'), "the record is in the error state"); - equal(get(person, 'adapterError'), error, "error object is exposed"); + assert.ok(get(person, 'isError'), "the record is in the error state"); + assert.equal(get(person, 'adapterError'), error, "error object is exposed"); })); }); }); -test("if an updated record is marked as invalid by the server, it enters an error state", function() { +test("if an updated record is marked as invalid by the server, it enters an error state", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { - equal(type, Person, "the type is correct"); + assert.equal(type, Person, "the type is correct"); if (snapshot.attr('name').indexOf('Bro') === -1) { return Ember.RSVP.reject(new DS.InvalidError([ @@ -651,36 +653,36 @@ test("if an updated record is marked as invalid by the server, it enters an erro Ember.run(function() { store.findRecord('person', 1).then(async(function(person) { - equal(person, yehuda, "The same object is passed through"); + assert.equal(person, yehuda, "The same object is passed through"); - equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); + assert.equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); set(yehuda, 'name', "Yehuda Katz"); - equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); + assert.equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); - equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); return yehuda.save(); })).then(null, async(function(reason) { - equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); - equal(get(yehuda, 'isValid'), false, "the record is invalid"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); + assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); set(yehuda, 'updatedAt', true); - equal(get(yehuda, 'isValid'), false, "the record is still invalid"); + assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid"); set(yehuda, 'name', "Brohuda Brokatz"); - equal(get(yehuda, 'isValid'), true, "the record is no longer invalid after changing"); - equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); + assert.equal(get(yehuda, 'isValid'), true, "the record is no longer invalid after changing"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); return yehuda.save(); })).then(async(function(yehuda) { - equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); - equal(get(yehuda, 'hasDirtyAttributes'), false, "record is no longer new"); + assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is no longer new"); })); }); }); -test("records can have errors on arbitrary properties after update", function() { +test("records can have errors on arbitrary properties after update", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { if (snapshot.attr('name').indexOf('Bro') === -1) { @@ -713,45 +715,45 @@ test("records can have errors on arbitrary properties after update", function() run(function() { store.findRecord('person', 1).then(async(function(person) { - equal(person, yehuda, "The same object is passed through"); + assert.equal(person, yehuda, "The same object is passed through"); - equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); + assert.equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); set(yehuda, 'name', "Yehuda Katz"); - equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); + assert.equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); - equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); return yehuda.save(); })).then(null, async(function(reason) { - equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); - equal(get(yehuda, 'isValid'), false, "the record is invalid"); - ok(get(yehuda, 'errors.base'), "The errors.base property exists"); - deepEqual(get(yehuda, 'errors').errorsFor('base'), [{ attribute: 'base', message: "is a generally unsavoury character" }]); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); + assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); + assert.ok(get(yehuda, 'errors.base'), "The errors.base property exists"); + assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), [{ attribute: 'base', message: "is a generally unsavoury character" }]); set(yehuda, 'updatedAt', true); - equal(get(yehuda, 'isValid'), false, "the record is still invalid"); + assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid"); set(yehuda, 'name', "Brohuda Brokatz"); - equal(get(yehuda, 'isValid'), false, "the record is still invalid after changing (only server can know if it's now valid)"); - equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); + assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid after changing (only server can know if it's now valid)"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); return yehuda.save(); })).then(async(function(yehuda) { - equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); - equal(get(yehuda, 'hasDirtyAttributes'), false, "record is no longer new"); - ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); - deepEqual(get(yehuda, 'errors').errorsFor('base'), []); + assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is no longer new"); + assert.ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); + assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), []); })); }); }); -test("if an updated record is marked as invalid by the server, you can attempt the save again", function() { +test("if an updated record is marked as invalid by the server, you can attempt the save again", function(assert) { var saveCount = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { - equal(type, Person, "the type is correct"); + assert.equal(type, Person, "the type is correct"); saveCount++; if (snapshot.attr('name').indexOf('Bro') === -1) { return Ember.RSVP.reject(new DS.InvalidError([ @@ -783,39 +785,39 @@ test("if an updated record is marked as invalid by the server, you can attempt t Ember.run(function() { store.findRecord('person', 1).then(async(function(person) { - equal(person, yehuda, "The same object is passed through"); + assert.equal(person, yehuda, "The same object is passed through"); - equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); + assert.equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); set(yehuda, 'name', "Yehuda Katz"); - equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); + assert.equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); - equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); return yehuda.save(); })).then(null, async(function(reason) { - equal(saveCount, 1, "The record has been saved once"); - ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); - equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); - equal(get(yehuda, 'isValid'), false, "the record is invalid"); + assert.equal(saveCount, 1, "The record has been saved once"); + assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); + assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); return yehuda.save(); })).then(null, async(function(reason) { - equal(saveCount, 2, "The record has been saved twice"); - ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); - equal(get(yehuda, 'isValid'), false, "record is still invalid"); - equal(get(yehuda, 'hasDirtyAttributes'), true, "record is still dirty"); + assert.equal(saveCount, 2, "The record has been saved twice"); + assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); + assert.equal(get(yehuda, 'isValid'), false, "record is still invalid"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "record is still dirty"); set(yehuda, 'name', 'Brohuda Brokatz'); return yehuda.save(); })).then(async(function(person) { - equal(saveCount, 3, "The record has been saved thrice"); - equal(get(yehuda, 'isValid'), true, "record is valid"); - equal(get(yehuda, 'hasDirtyAttributes'), false, "record is not dirty"); - equal(get(yehuda, 'errors.isEmpty'), true, "record has no errors"); + assert.equal(saveCount, 3, "The record has been saved thrice"); + assert.equal(get(yehuda, 'isValid'), true, "record is valid"); + assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is not dirty"); + assert.equal(get(yehuda, 'errors.isEmpty'), true, "record has no errors"); })); }); }); -test("if a updated record is marked as erred by the server, it enters an error state", function() { +test("if a updated record is marked as erred by the server, it enters an error state", function(assert) { var error = new DS.AdapterError(); adapter.shouldBackgroundReloadRecord = () => false; @@ -837,20 +839,20 @@ test("if a updated record is marked as erred by the server, it enters an error s }); run(store, 'findRecord', 'person', 1).then(async(function(record) { - equal(record, person, "The person was resolved"); + assert.equal(record, person, "The person was resolved"); person.set('name', "Jonathan Doe"); return person.save(); })).then(null, async(function(reason) { - ok(get(person, 'isError'), "the record is in the error state"); - equal(get(person, 'adapterError'), error, "error object is exposed"); + assert.ok(get(person, 'isError'), "the record is in the error state"); + assert.equal(get(person, 'adapterError'), error, "error object is exposed"); })); }); -test("can be created after the DS.Store", function() { - expect(1); +test("can be created after the DS.Store", function(assert) { + assert.expect(1); adapter.findRecord = function(store, type, id, snapshot) { - equal(type, Person, "the type is correct"); + assert.equal(type, Person, "the type is correct"); return Ember.RSVP.resolve({ id: 1 }); }; @@ -859,7 +861,7 @@ test("can be created after the DS.Store", function() { }); }); -test("the filter method can optionally take a server query as well", function() { +test("the filter method can optionally take a server query as well", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.query = function(store, type, query, array) { return Ember.RSVP.resolve([ @@ -878,12 +880,12 @@ test("the filter method can optionally take a server query as well", function() loadedFilter = filter; return store.findRecord('person', 2); })).then(async(function(tom) { - equal(get(loadedFilter, 'length'), 1, "The filter has an item in it"); - deepEqual(loadedFilter.toArray(), [tom], "The filter has a single entry in it"); + assert.equal(get(loadedFilter, 'length'), 1, "The filter has an item in it"); + assert.deepEqual(loadedFilter.toArray(), [tom], "The filter has a single entry in it"); })); }); -test("relationships returned via `commit` do not trigger additional findManys", function() { +test("relationships returned via `commit` do not trigger additional findManys", function(assert) { Person.reopen({ dogs: DS.hasMany('dog', { async: false }) }); @@ -936,7 +938,7 @@ test("relationships returned via `commit` do not trigger additional findManys", }; adapter.findMany = function(store, type, ids, snapshots) { - ok(false, "Should not get here"); + assert.ok(false, "Should not get here"); }; run(function() { @@ -946,12 +948,12 @@ test("relationships returned via `commit` do not trigger additional findManys", records.tom.get('dogs'); return records.dog.save(); })).then(async(function(tom) { - ok(true, "Tom was saved"); + assert.ok(true, "Tom was saved"); })); }); }); -test("relationships don't get reset if the links is the same", function() { +test("relationships don't get reset if the links is the same", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; Person.reopen({ dogs: DS.hasMany({ async: true }) @@ -960,7 +962,7 @@ test("relationships don't get reset if the links is the same", function() { var count = 0; adapter.findHasMany = function(store, snapshot, link, relationship) { - ok(count++ === 0, "findHasMany is only called once"); + assert.ok(count++ === 0, "findHasMany is only called once"); return Ember.RSVP.resolve([{ id: 1, name: "Scruffy" }]); }; @@ -991,7 +993,7 @@ test("relationships don't get reset if the links is the same", function() { dogs = tom.get('dogs'); return dogs; })).then(async(function(dogs) { - equal(dogs.get('length'), 1, "The dogs are loaded"); + assert.equal(dogs.get('length'), 1, "The dogs are loaded"); store.push({ data: { type: 'person', @@ -1008,14 +1010,14 @@ test("relationships don't get reset if the links is the same", function() { } } }); - ok(tom.get('dogs') instanceof DS.PromiseArray, 'dogs is a promise'); + assert.ok(tom.get('dogs') instanceof DS.PromiseArray, 'dogs is a promise'); return tom.get('dogs'); })).then(async(function(dogs) { - equal(dogs.get('length'), 1, "The same dogs are loaded"); + assert.equal(dogs.get('length'), 1, "The same dogs are loaded"); })); }); -test("async hasMany always returns a promise", function() { +test("async hasMany always returns a promise", function(assert) { Person.reopen({ dogs: DS.hasMany({ async: true }) }); @@ -1032,20 +1034,20 @@ test("async hasMany always returns a promise", function() { tom = store.createRecord('person', { name: "Tom Dale" }); }); - ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise before save"); + assert.ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise before save"); run(function() { tom.save().then(async(function() { - ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise after save"); + assert.ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise after save"); })); }); }); -test("createRecord receives a snapshot", function() { - expect(1); +test("createRecord receives a snapshot", function(assert) { + assert.expect(1); adapter.createRecord = function(store, type, snapshot) { - ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); + assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); return Ember.RSVP.resolve(); }; @@ -1057,11 +1059,11 @@ test("createRecord receives a snapshot", function() { }); }); -test("updateRecord receives a snapshot", function() { - expect(1); +test("updateRecord receives a snapshot", function(assert) { + assert.expect(1); adapter.updateRecord = function(store, type, snapshot) { - ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); + assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); return Ember.RSVP.resolve(); }; @@ -1086,11 +1088,11 @@ test("updateRecord receives a snapshot", function() { }); }); -test("deleteRecord receives a snapshot", function() { - expect(1); +test("deleteRecord receives a snapshot", function(assert) { + assert.expect(1); adapter.deleteRecord = function(store, type, snapshot) { - ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); + assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); return Ember.RSVP.resolve(); }; @@ -1115,11 +1117,11 @@ test("deleteRecord receives a snapshot", function() { }); }); -test("find receives a snapshot", function() { - expect(1); +test("find receives a snapshot", function(assert) { + assert.expect(1); adapter.findRecord = function(store, type, id, snapshot) { - ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); + assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); return Ember.RSVP.resolve({ id: 1 }); }; @@ -1128,8 +1130,8 @@ test("find receives a snapshot", function() { }); }); -test("findMany receives an array of snapshots", function() { - expect(2); +test("findMany receives an array of snapshots", function(assert) { + assert.expect(2); Person.reopen({ dogs: DS.hasMany({ async: true }) @@ -1137,8 +1139,8 @@ test("findMany receives an array of snapshots", function() { adapter.coalesceFindRequests = true; adapter.findMany = function(store, type, ids, snapshots) { - ok(snapshots[0] instanceof DS.Snapshot, "snapshots[0] is an instance of DS.Snapshot"); - ok(snapshots[1] instanceof DS.Snapshot, "snapshots[1] is an instance of DS.Snapshot"); + assert.ok(snapshots[0] instanceof DS.Snapshot, "snapshots[0] is an instance of DS.Snapshot"); + assert.ok(snapshots[1] instanceof DS.Snapshot, "snapshots[1] is an instance of DS.Snapshot"); return Ember.RSVP.resolve([{ id: 2 }, { id: 3 }]); }; @@ -1167,15 +1169,15 @@ test("findMany receives an array of snapshots", function() { }); }); -test("findHasMany receives a snapshot", function() { - expect(1); +test("findHasMany receives a snapshot", function(assert) { + assert.expect(1); Person.reopen({ dogs: DS.hasMany({ async: true }) }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); + assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); return Ember.RSVP.resolve([{ id: 2 }, { id: 3 }]); }; @@ -1203,15 +1205,15 @@ test("findHasMany receives a snapshot", function() { }); }); -test("findBelongsTo receives a snapshot", function() { - expect(1); +test("findBelongsTo receives a snapshot", function(assert) { + assert.expect(1); Person.reopen({ dog: DS.belongsTo({ async: true }) }); env.adapter.findBelongsTo = async(function(store, snapshot, link, relationship) { - ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); + assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); return Ember.RSVP.resolve({ id: 2 }); }); @@ -1239,11 +1241,11 @@ test("findBelongsTo receives a snapshot", function() { }); }); -test("record.save should pass adapterOptions to the updateRecord method", function() { - expect(1); +test("record.save should pass adapterOptions to the updateRecord method", function(assert) { + assert.expect(1); env.adapter.updateRecord = async(function(store, type, snapshot) { - deepEqual(snapshot.adapterOptions, { subscribe: true }); + assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); return Ember.RSVP.resolve({ id: 1 }); }); @@ -1262,11 +1264,11 @@ test("record.save should pass adapterOptions to the updateRecord method", functi }); }); -test("record.save should pass adapterOptions to the createRecord method", function() { - expect(1); +test("record.save should pass adapterOptions to the createRecord method", function(assert) { + assert.expect(1); env.adapter.createRecord = async(function(store, type, snapshot) { - deepEqual(snapshot.adapterOptions, { subscribe: true }); + assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); return Ember.RSVP.resolve({ id: 1 }); }); @@ -1276,11 +1278,11 @@ test("record.save should pass adapterOptions to the createRecord method", functi }); }); -test("record.save should pass adapterOptions to the deleteRecord method", function() { - expect(1); +test("record.save should pass adapterOptions to the deleteRecord method", function(assert) { + assert.expect(1); env.adapter.deleteRecord = async(function(store, type, snapshot) { - deepEqual(snapshot.adapterOptions, { subscribe: true }); + assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); return Ember.RSVP.resolve({ id: 1 }); }); @@ -1300,11 +1302,11 @@ test("record.save should pass adapterOptions to the deleteRecord method", functi }); -test("findRecord should pass adapterOptions to the find method", function() { - expect(1); +test("findRecord should pass adapterOptions to the find method", function(assert) { + assert.expect(1); env.adapter.findRecord = async(function(store, type, id, snapshot) { - deepEqual(snapshot.adapterOptions, { query: { embed: true } }); + assert.deepEqual(snapshot.adapterOptions, { query: { embed: true } }); return Ember.RSVP.resolve({ id: 1 }); }); @@ -1314,12 +1316,12 @@ test("findRecord should pass adapterOptions to the find method", function() { }); -test("findAll should pass adapterOptions to the findAll method", function() { - expect(1); +test("findAll should pass adapterOptions to the findAll method", function(assert) { + assert.expect(1); env.adapter.findAll = async(function(store, type, sinceToken, arraySnapshot) { var adapterOptions = arraySnapshot.adapterOptions; - deepEqual(adapterOptions, { query: { embed: true } }); + assert.deepEqual(adapterOptions, { query: { embed: true } }); return Ember.RSVP.resolve([{ id: 1 }]); }); @@ -1329,7 +1331,7 @@ test("findAll should pass adapterOptions to the findAll method", function() { }); -test("An async hasMany relationship with links should not trigger shouldBackgroundReloadRecord", function() { +test("An async hasMany relationship with links should not trigger shouldBackgroundReloadRecord", function(assert) { var Post = DS.Model.extend({ name: DS.attr("string"), comments: DS.hasMany('comment', { async: true }) @@ -1362,7 +1364,7 @@ test("An async hasMany relationship with links should not trigger shouldBackgrou }); }, shouldBackgroundReloadRecord: function() { - ok(false, 'shouldBackgroundReloadRecord should not be called'); + assert.ok(false, 'shouldBackgroundReloadRecord should not be called'); } }) }); @@ -1372,6 +1374,6 @@ test("An async hasMany relationship with links should not trigger shouldBackgrou run(store, 'find', 'post', '1').then(async(function(post) { return post.get('comments'); })).then(async(function(comments) { - equal(comments.get('length'), 3); + assert.equal(comments.get('length'), 3); })); }); diff --git a/tests/integration/application-test.js b/tests/integration/application-test.js index 61c99a9651a..ca8a01fd5a5 100644 --- a/tests/integration/application-test.js +++ b/tests/integration/application-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var run = Ember.run; @@ -24,7 +26,7 @@ function lookup(thing) { } module("integration/application - Injecting a Custom Store", { - setup: function() { + beforeEach: function() { run(function() { app = Application.create({ StoreService: Store.extend({ isCustom: true }), @@ -38,36 +40,36 @@ module("integration/application - Injecting a Custom Store", { container = app.__container__; }, - teardown: function() { + afterEach: function() { run(app, app.destroy); Ember.BOOTED = false; } }); -test("If a Store property exists on an Ember.Application, it should be instantiated.", function() { +test("If a Store property exists on an Ember.Application, it should be instantiated.", function(assert) { run(function() { - ok(getStore().get('isCustom'), "the custom store was instantiated"); + assert.ok(getStore().get('isCustom'), "the custom store was instantiated"); }); }); -test("If a store is instantiated, it should be made available to each controller.", function() { +test("If a store is instantiated, it should be made available to each controller.", function(assert) { var fooController = lookup('controller:foo'); var isCustom = run(fooController, 'get', 'store.isCustom'); - ok(isCustom, "the custom store was injected"); + assert.ok(isCustom, "the custom store was injected"); }); -test("The JSONAPIAdapter is the default adapter when no custom adapter is provided", function() { +test("The JSONAPIAdapter is the default adapter when no custom adapter is provided", function(assert) { run(function() { var store = getStore(); var adapter = store.adapterFor('application'); - ok(adapter instanceof DS.JSONAPIAdapter, 'default adapter should be the JSONAPIAdapter'); + assert.ok(adapter instanceof DS.JSONAPIAdapter, 'default adapter should be the JSONAPIAdapter'); }); }); module("integration/application - Injecting the Default Store", { - setup: function() { + beforeEach: function() { run(function() { app = Application.create({ FooController: Controller.extend(), @@ -79,32 +81,32 @@ module("integration/application - Injecting the Default Store", { container = app.__container__; }, - teardown: function() { + afterEach: function() { run(app, 'destroy'); Ember.BOOTED = false; } }); -test("If a Store property exists on an Ember.Application, it should be instantiated.", function() { - ok(getStore() instanceof DS.Store, "the store was instantiated"); +test("If a Store property exists on an Ember.Application, it should be instantiated.", function(assert) { + assert.ok(getStore() instanceof DS.Store, "the store was instantiated"); }); -test("If a store is instantiated, it should be made available to each controller.", function() { +test("If a store is instantiated, it should be made available to each controller.", function(assert) { run(function() { var fooController = lookup('controller:foo'); - ok(fooController.get('store') instanceof DS.Store, "the store was injected"); + assert.ok(fooController.get('store') instanceof DS.Store, "the store was injected"); }); }); -test("the DS namespace should be accessible", function() { +test("the DS namespace should be accessible", function(assert) { run(function() { - ok(Namespace.byName('DS') instanceof Namespace, "the DS namespace is accessible"); + assert.ok(Namespace.byName('DS') instanceof Namespace, "the DS namespace is accessible"); }); }); if (Ember.inject && Ember.inject.service) { module("integration/application - Using the store as a service", { - setup: function() { + beforeEach: function() { run(function() { app = Application.create({ DoodleService: Ember.Service.extend({ store: Ember.inject.service() }) @@ -114,26 +116,26 @@ if (Ember.inject && Ember.inject.service) { container = app.__container__; }, - teardown: function() { + afterEach: function() { run(app, 'destroy'); Ember.BOOTED = false; } }); - test("The store can be injected as a service", function() { + test("The store can be injected as a service", function(assert) { run(function() { var doodleService = lookup('service:doodle'); - ok(doodleService.get('store') instanceof Store, "the store can be used as a service"); + assert.ok(doodleService.get('store') instanceof Store, "the store can be used as a service"); }); }); } module("integration/application - Attaching initializer", { - setup: function() { + beforeEach: function() { App = Application.extend(); }, - teardown: function() { + afterEach: function() { if (app) { run(app, app.destroy); } @@ -141,7 +143,7 @@ module("integration/application - Attaching initializer", { } }); -test("ember-data initializer is run", function() { +test("ember-data initializer is run", function(assert) { var ran = false; App.initializer({ name: "after-ember-data", @@ -153,10 +155,10 @@ test("ember-data initializer is run", function() { app = App.create(); }); - ok(ran, 'ember-data initializer was found'); + assert.ok(ran, 'ember-data initializer was found'); }); -test("ember-data initializer does not register the store service when it was already registered", function() { +test("ember-data initializer does not register the store service when it was already registered", function(assert) { var AppStore = Store.extend({ isCustomStore: true @@ -176,11 +178,11 @@ test("ember-data initializer does not register the store service when it was alr }); var store = getStore(); - ok(store && store.get('isCustomStore'), 'ember-data initializer does not overwrite the previous registered service store'); + assert.ok(store && store.get('isCustomStore'), 'ember-data initializer does not overwrite the previous registered service store'); }); -test("store initializer is run (DEPRECATED)", function() { +test("store initializer is run (DEPRECATED)", function(assert) { var ran = false; App.initializer({ name: "after-store", @@ -192,10 +194,10 @@ test("store initializer is run (DEPRECATED)", function() { app = App.create(); }); - ok(ran, 'store initializer was found'); + assert.ok(ran, 'store initializer was found'); }); -test("injectStore initializer is run (DEPRECATED)", function() { +test("injectStore initializer is run (DEPRECATED)", function(assert) { var ran = false; App.initializer({ name: "after-store", @@ -207,10 +209,10 @@ test("injectStore initializer is run (DEPRECATED)", function() { app = App.create(); }); - ok(ran, 'injectStore initializer was found'); + assert.ok(ran, 'injectStore initializer was found'); }); -test("transforms initializer is run (DEPRECATED)", function() { +test("transforms initializer is run (DEPRECATED)", function(assert) { var ran = false; App.initializer({ name: "after-store", @@ -222,5 +224,5 @@ test("transforms initializer is run (DEPRECATED)", function() { app = App.create(); }); - ok(ran, 'transforms initializer was found'); + assert.ok(ran, 'transforms initializer was found'); }); diff --git a/tests/integration/backwards-compat/non-dasherized-lookups-test.js b/tests/integration/backwards-compat/non-dasherized-lookups-test.js index 362a7a20fdb..28475fe6ea2 100644 --- a/tests/integration/backwards-compat/non-dasherized-lookups-test.js +++ b/tests/integration/backwards-compat/non-dasherized-lookups-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; const get = Ember.get; @@ -17,7 +19,7 @@ const { let store; module('integration/backwards-compat/non-dasherized-lookups - non dasherized lookups in application code finders', { - setup: function() { + beforeEach: function() { const PostNote = Model.extend({ name: attr('string') }); @@ -36,13 +38,13 @@ module('integration/backwards-compat/non-dasherized-lookups - non dasherized loo store = env.store; }, - teardown: function() { + afterEach: function() { run(store, 'destroy'); } }); -test('can lookup records using camelCase strings', function() { - expect(1); +test('can lookup records using camelCase strings', function(assert) { + assert.expect(1); run(() => { store.pushPayload('post-note', { @@ -58,13 +60,13 @@ test('can lookup records using camelCase strings', function() { run(() => { store.findRecord('postNote', 1).then((postNote) => { - equal(get(postNote, 'name'), 'Ember Data', 'record found'); + assert.equal(get(postNote, 'name'), 'Ember Data', 'record found'); }); }); }); -test('can lookup records using under_scored strings', function() { - expect(1); +test('can lookup records using under_scored strings', function(assert) { + assert.expect(1); run(() => { store.pushPayload('post-note', { @@ -80,13 +82,13 @@ test('can lookup records using under_scored strings', function() { run(() => { store.findRecord('post_note', 1).then((postNote) => { - equal(get(postNote, 'name'), 'Ember Data', 'record found'); + assert.equal(get(postNote, 'name'), 'Ember Data', 'record found'); }); }); }); module('integration/backwards-compat/non-dasherized-lookups - non dasherized lookups in application code relationship macros', { - setup: function() { + beforeEach: function() { const PostNote = Model.extend({ notePost: belongsTo('note-post', { async: false }), @@ -119,13 +121,13 @@ module('integration/backwards-compat/non-dasherized-lookups - non dasherized loo store = env.store; }, - teardown: function() { + afterEach: function() { run(store, 'destroy'); } }); -test('looks up belongsTo using camelCase strings', function() { - expect(1); +test('looks up belongsTo using camelCase strings', function(assert) { + assert.expect(1); run(() => { store.pushPayload('post-note', { @@ -155,13 +157,13 @@ test('looks up belongsTo using camelCase strings', function() { run(() => { store.findRecord('post-note', 1).then((postNote) => { - equal(get(postNote, 'notePost.name'), 'Inverse', 'inverse record found'); + assert.equal(get(postNote, 'notePost.name'), 'Inverse', 'inverse record found'); }); }); }); -test('looks up belongsTo using under_scored strings', function() { - expect(1); +test('looks up belongsTo using under_scored strings', function(assert) { + assert.expect(1); run(() => { store.pushPayload('long_model_name', { @@ -193,7 +195,7 @@ test('looks up belongsTo using under_scored strings', function() { store.findRecord('long_model_name', 1).then((longModelName) => { const postNotes = get(longModelName, 'postNotes').toArray(); - deepEqual(postNotes, [store.peekRecord('postNote', 1)], + assert.deepEqual(postNotes, [store.peekRecord('postNote', 1)], 'inverse records found'); }); }); diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index 8cc33184e99..4a7ed51736c 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -7,7 +9,7 @@ var Post, Comment, Misc, env; var run = Ember.run; module("integration/client_id_generation - Client-side ID Generation", { - setup: function() { + beforeEach: function() { Comment = DS.Model.extend({ post: DS.belongsTo('post', { async: false }) }); @@ -27,28 +29,28 @@ module("integration/client_id_generation - Client-side ID Generation", { }); }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); -test("If an adapter implements the `generateIdForRecord` method, the store should be able to assign IDs without saving to the persistence layer.", function() { - expect(6); +test("If an adapter implements the `generateIdForRecord` method, the store should be able to assign IDs without saving to the persistence layer.", function(assert) { + assert.expect(6); var idCount = 1; env.adapter.generateIdForRecord = function(passedStore, record) { - equal(env.store, passedStore, "store is the first parameter"); + assert.equal(env.store, passedStore, "store is the first parameter"); return "id-" + idCount++; }; env.adapter.createRecord = function(store, type, snapshot) { if (type === Comment) { - equal(snapshot.id, 'id-1', "Comment passed to `createRecord` has 'id-1' assigned"); + assert.equal(snapshot.id, 'id-1', "Comment passed to `createRecord` has 'id-1' assigned"); return Ember.RSVP.resolve(); } else { - equal(snapshot.id, 'id-2', "Post passed to `createRecord` has 'id-2' assigned"); + assert.equal(snapshot.id, 'id-2', "Post passed to `createRecord` has 'id-2' assigned"); return Ember.RSVP.resolve(); } }; @@ -59,8 +61,8 @@ test("If an adapter implements the `generateIdForRecord` method, the store shoul post = env.store.createRecord('post'); }); - equal(get(comment, 'id'), 'id-1', "comment is assigned id 'id-1'"); - equal(get(post, 'id'), 'id-2', "post is assigned id 'id-2'"); + assert.equal(get(comment, 'id'), 'id-1', "comment is assigned id 'id-1'"); + assert.equal(get(post, 'id'), 'id-2', "post is assigned id 'id-2'"); // Despite client-generated IDs, calling commit() on the store should still // invoke the adapter's `createRecord` method. @@ -70,19 +72,19 @@ test("If an adapter implements the `generateIdForRecord` method, the store shoul }); }); -test("empty string and undefined ids should coerce to null", function() { - expect(6); +test("empty string and undefined ids should coerce to null", function(assert) { + assert.expect(6); var comment, post; var idCount = 0; var ids = [undefined, '']; env.adapter.generateIdForRecord = function(passedStore, record) { - equal(env.store, passedStore, "store is the first parameter"); + assert.equal(env.store, passedStore, "store is the first parameter"); return ids[idCount++]; }; env.adapter.createRecord = function(store, type, record) { - equal(typeof get(record, 'id'), 'object', 'correct type'); + assert.equal(typeof get(record, 'id'), 'object', 'correct type'); return Ember.RSVP.resolve(); }; @@ -91,8 +93,8 @@ test("empty string and undefined ids should coerce to null", function() { post = env.store.createRecord('misc'); }); - equal(get(comment, 'id'), null, "comment is assigned id 'null'"); - equal(get(post, 'id'), null, "post is assigned id 'null'"); + assert.equal(get(comment, 'id'), null, "comment is assigned id 'null'"); + assert.equal(get(post, 'id'), null, "post is assigned id 'null'"); // Despite client-generated IDs, calling commit() on the store should still // invoke the adapter's `createRecord` method. diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index 68d509db463..4b08bce091f 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var App, store, debugAdapter; @@ -7,7 +9,7 @@ var get = Ember.get; var run = Ember.run; module("DS.DebugAdapter", { - setup: function() { + beforeEach: function() { Ember.run(function() { App = Ember.Application.create(); App.toString = function() { return 'App'; }; @@ -38,23 +40,23 @@ module("DS.DebugAdapter", { } }); }, - teardown: function() { + afterEach: function() { run(App, App.destroy); } }); -test("Watching Model Types", function() { - expect(5); +test("Watching Model Types", function(assert) { + assert.expect(5); var added = function(types) { - equal(types.length, 1); - equal(types[0].name, 'post'); - equal(types[0].count, 0); - strictEqual(types[0].object, store.modelFor('post')); + assert.equal(types.length, 1); + assert.equal(types[0].name, 'post'); + assert.equal(types[0].count, 0); + assert.strictEqual(types[0].object, store.modelFor('post')); }; var updated = function(types) { - equal(types[0].count, 1); + assert.equal(types[0].count, 1); }; debugAdapter.watchModelTypes(added, updated); @@ -72,7 +74,7 @@ test("Watching Model Types", function() { }); }); -test("Watching Records", function() { +test("Watching Records", function(assert) { var post, record, addedRecords, updatedRecords, removedIndex, removedCount; Ember.run(function() { @@ -106,12 +108,12 @@ test("Watching Records", function() { } debugAdapter.watchRecords(modelClassOrName, recordsAdded, recordsUpdated, recordsRemoved); - equal(get(addedRecords, 'length'), 1); + assert.equal(get(addedRecords, 'length'), 1); record = addedRecords[0]; - deepEqual(record.columnValues, { id: '1', title: 'Clean Post' }); - deepEqual(record.filterValues, { isNew: false, isModified: false, isClean: true }); - deepEqual(record.searchKeywords, ['1', 'Clean Post']); - deepEqual(record.color, 'black'); + assert.deepEqual(record.columnValues, { id: '1', title: 'Clean Post' }); + assert.deepEqual(record.filterValues, { isNew: false, isModified: false, isClean: true }); + assert.deepEqual(record.searchKeywords, ['1', 'Clean Post']); + assert.deepEqual(record.color, 'black'); Ember.run(function() { post = store.find('post', 1); @@ -121,25 +123,25 @@ test("Watching Records", function() { post.set('title', 'Modified Post'); }); - equal(get(updatedRecords, 'length'), 1); + assert.equal(get(updatedRecords, 'length'), 1); record = updatedRecords[0]; - deepEqual(record.columnValues, { id: '1', title: 'Modified Post' }); - deepEqual(record.filterValues, { isNew: false, isModified: true, isClean: false }); - deepEqual(record.searchKeywords, ['1', 'Modified Post']); - deepEqual(record.color, 'blue'); + assert.deepEqual(record.columnValues, { id: '1', title: 'Modified Post' }); + assert.deepEqual(record.filterValues, { isNew: false, isModified: true, isClean: false }); + assert.deepEqual(record.searchKeywords, ['1', 'Modified Post']); + assert.deepEqual(record.color, 'blue'); run(function() { post = store.createRecord('post', { id: '2', title: 'New Post' }); }); - equal(get(addedRecords, 'length'), 1); + assert.equal(get(addedRecords, 'length'), 1); record = addedRecords[0]; - deepEqual(record.columnValues, { id: '2', title: 'New Post' }); - deepEqual(record.filterValues, { isNew: true, isModified: false, isClean: false }); - deepEqual(record.searchKeywords, ['2', 'New Post']); - deepEqual(record.color, 'green'); + assert.deepEqual(record.columnValues, { id: '2', title: 'New Post' }); + assert.deepEqual(record.filterValues, { isNew: true, isModified: false, isClean: false }); + assert.deepEqual(record.searchKeywords, ['2', 'New Post']); + assert.deepEqual(record.color, 'green'); Ember.run(post, 'unloadRecord'); - equal(removedIndex, 1); - equal(removedCount, 1); + assert.equal(removedIndex, 1); + assert.equal(removedCount, 1); }); diff --git a/tests/integration/filter-test.js b/tests/integration/filter-test.js index 10c6f62eb72..e715a8e8515 100644 --- a/tests/integration/filter-test.js +++ b/tests/integration/filter-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; import customAdapter from 'ember-data/tests/helpers/custom-adapter'; @@ -11,15 +13,15 @@ var run = Ember.run; var Person, store, env, array, recordArray; var shouldContain = function(array, item) { - ok(array.indexOf(item) !== -1, "array should contain "+item.get('name')); + assert.ok(array.indexOf(item) !== -1, "array should contain "+item.get('name')); }; var shouldNotContain = function(array, item) { - ok(array.indexOf(item) === -1, "array should not contain "+item.get('name')); + assert.ok(array.indexOf(item) === -1, "array should not contain "+item.get('name')); }; module("integration/filter - DS.Model updating", { - setup: function() { + beforeEach: function() { array = [{ id: '1', type: 'person', @@ -52,7 +54,7 @@ module("integration/filter - DS.Model updating", { env = setupStore({ person: Person }); store = env.store; }, - teardown: function() { + afterEach: function() { run(store, 'destroy'); Person = null; array = null; @@ -76,7 +78,7 @@ function tapFn(fn, callback) { } -test("when a DS.Model updates its attributes, its changes affect its filtered Array membership", function() { +test("when a DS.Model updates its attributes, its changes affect its filtered Array membership", function(assert) { run(function() { store.push({ data: array }); }); @@ -89,29 +91,29 @@ test("when a DS.Model updates its attributes, its changes affect its filtered Ar }); run(function() { - equal(get(people, 'length'), 1, "precond - one item is in the RecordArray"); + assert.equal(get(people, 'length'), 1, "precond - one item is in the RecordArray"); }); var person = people.objectAt(0); - equal(get(person, 'name'), "Scumbag Katz", "precond - the item is correct"); + assert.equal(get(person, 'name'), "Scumbag Katz", "precond - the item is correct"); run(function() { set(person, 'name', "Yehuda Katz"); }); - equal(get(people, 'length'), 1, "there is still one item"); - equal(get(person, 'name'), "Yehuda Katz", "it has the updated item"); + assert.equal(get(people, 'length'), 1, "there is still one item"); + assert.equal(get(person, 'name'), "Yehuda Katz", "it has the updated item"); run(function() { set(person, 'name', "Yehuda Katz-Foo"); }); - equal(get(people, 'query'), null, 'expected no query object set'); - equal(get(people, 'length'), 0, "there are now no items"); + assert.equal(get(people, 'query'), null, 'expected no query object set'); + assert.equal(get(people, 'length'), 0, "there are now no items"); }); -test("when a DS.Model updates its relationships, its changes affect its filtered Array membership", function() { +test("when a DS.Model updates its relationships, its changes affect its filtered Array membership", function(assert) { run(function() { store.push({ data: array }); }); @@ -124,18 +126,18 @@ test("when a DS.Model updates its relationships, its changes affect its filtered }); run(function() { - equal(get(people, 'length'), 1, "precond - one item is in the RecordArray"); + assert.equal(get(people, 'length'), 1, "precond - one item is in the RecordArray"); }); var person = people.objectAt(0); - equal(get(person, 'name'), "Scumbag Dale", "precond - the item is correct"); + assert.equal(get(person, 'name'), "Scumbag Dale", "precond - the item is correct"); run(function() { set(person, 'bestFriend', null); }); - equal(get(people, 'length'), 0, "there are now 0 items"); + assert.equal(get(people, 'length'), 0, "there are now 0 items"); var erik = store.peekRecord('person', 3); var yehuda = store.peekRecord('person', 2); @@ -144,12 +146,12 @@ test("when a DS.Model updates its relationships, its changes affect its filtered }); person = people.objectAt(0); - equal(get(people, 'length'), 1, "there is now 1 item"); - equal(get(person, 'name'), "Scumbag Bryn", "precond - the item is correct"); + assert.equal(get(people, 'length'), 1, "there is now 1 item"); + assert.equal(get(person, 'name'), "Scumbag Bryn", "precond - the item is correct"); }); -test("a record array can have a filter on it", function() { +test("a record array can have a filter on it", function(assert) { run(function() { store.push({ data: array }); }); @@ -161,7 +163,7 @@ test("a record array can have a filter on it", function() { }); }); - equal(get(recordArray, 'length'), 2, "The Record Array should have the filtered objects on it"); + assert.equal(get(recordArray, 'length'), 2, "The Record Array should have the filtered objects on it"); run(function () { store.push({ @@ -175,7 +177,7 @@ test("a record array can have a filter on it", function() { }); }); - equal(get(recordArray, 'length'), 3, "The Record Array should be updated as new items are added to the store"); + assert.equal(get(recordArray, 'length'), 3, "The Record Array should be updated as new items are added to the store"); run(function () { store.push({ @@ -189,10 +191,10 @@ test("a record array can have a filter on it", function() { }); }); - equal(get(recordArray, 'length'), 2, "The Record Array should be updated as existing members are updated"); + assert.equal(get(recordArray, 'length'), 2, "The Record Array should be updated as existing members are updated"); }); -test("a filtered record array includes created elements", function() { +test("a filtered record array includes created elements", function(assert) { run(function() { store.push({ data: array }); }); @@ -204,16 +206,16 @@ test("a filtered record array includes created elements", function() { }); }); - equal(get(recordArray, 'length'), 2, "precond - The Record Array should have the filtered objects on it"); + assert.equal(get(recordArray, 'length'), 2, "precond - The Record Array should have the filtered objects on it"); run(function() { store.createRecord('person', { name: "Scumbag Koz" }); }); - equal(get(recordArray, 'length'), 3, "The record array has the new object on it"); + assert.equal(get(recordArray, 'length'), 3, "The record array has the new object on it"); }); -test("a Record Array can update its filter", function() { +test("a Record Array can update its filter", function(assert) { customAdapter(env, DS.Adapter.extend({ deleteRecord: function(store, type, snapshot) { return Ember.RSVP.resolve(); @@ -254,7 +256,7 @@ test("a Record Array can update its filter", function() { }); }); - equal(get(recordArray, 'length'), 1, "The Record Array should have one object on it"); + assert.equal(get(recordArray, 'length'), 1, "The Record Array should have one object on it"); Ember.run(function () { store.push({ @@ -268,7 +270,7 @@ test("a Record Array can update its filter", function() { }); }); - equal(get(recordArray, 'length'), 2, "The Record Array now has the new object matching the filter"); + assert.equal(get(recordArray, 'length'), 2, "The Record Array now has the new object matching the filter"); Ember.run(function () { store.push({ @@ -282,12 +284,12 @@ test("a Record Array can update its filter", function() { }); }); - equal(get(recordArray, 'length'), 2, "The Record Array doesn't have objects matching the old filter"); + assert.equal(get(recordArray, 'length'), 2, "The Record Array doesn't have objects matching the old filter"); })); })); }); -test("a Record Array can update its filter and notify array observers", function() { +test("a Record Array can update its filter and notify array observers", function(assert) { customAdapter(env, DS.Adapter.extend({ deleteRecord: function(store, type, snapshot) { return Ember.RSVP.resolve(); @@ -340,7 +342,7 @@ test("a Record Array can update its filter and notify array observers", function }); Ember.RSVP.all([asyncDale, asyncKatz, asyncBryn]).then(async(function() { - equal(didChangeRemoved, 1, "removed one item from array"); + assert.equal(didChangeRemoved, 1, "removed one item from array"); didChangeRemoved = 0; Ember.run(function () { @@ -355,10 +357,10 @@ test("a Record Array can update its filter and notify array observers", function }); }); - equal(didChangeAdded, 1, "one item was added"); + assert.equal(didChangeAdded, 1, "one item was added"); didChangeAdded = 0; - equal(recordArray.objectAt(didChangeIdx).get('name'), "Other Katz"); + assert.equal(recordArray.objectAt(didChangeIdx).get('name'), "Other Katz"); Ember.run(function () { store.push({ @@ -372,7 +374,7 @@ test("a Record Array can update its filter and notify array observers", function }); }); - equal(didChangeAdded, 0, "did not get called when an object that doesn't match is added"); + assert.equal(didChangeAdded, 0, "did not get called when an object that doesn't match is added"); Ember.run(function() { recordArray.set('filterFunction', function(hash) { @@ -380,14 +382,14 @@ test("a Record Array can update its filter and notify array observers", function }); }); - equal(didChangeAdded, 2, "one item is added when going back"); - equal(recordArray.objectAt(didChangeIdx).get('name'), "Scumbag Demon"); - equal(recordArray.objectAt(didChangeIdx-1).get('name'), "Scumbag Dale"); + assert.equal(didChangeAdded, 2, "one item is added when going back"); + assert.equal(recordArray.objectAt(didChangeIdx).get('name'), "Scumbag Demon"); + assert.equal(recordArray.objectAt(didChangeIdx-1).get('name'), "Scumbag Dale"); })); })); }); -test("it is possible to filter by computed properties", function() { +test("it is possible to filter by computed properties", function(assert) { customAdapter(env, DS.Adapter.extend({ shouldBackgroundReloadRecord: () => false })); @@ -405,7 +407,7 @@ test("it is possible to filter by computed properties", function() { }); }); - equal(filter.get('length'), 0, "precond - the filter starts empty"); + assert.equal(filter.get('length'), 0, "precond - the filter starts empty"); run(function () { store.push({ @@ -419,18 +421,18 @@ test("it is possible to filter by computed properties", function() { }); }); - equal(filter.get('length'), 1, "the filter now has a record in it"); + assert.equal(filter.get('length'), 1, "the filter now has a record in it"); store.findRecord('person', 1).then(async(function(person) { Ember.run(function() { person.set('name', "Yehuda Katz"); }); - equal(filter.get('length'), 0, "the filter is empty again"); + assert.equal(filter.get('length'), 0, "the filter is empty again"); })); }); -test("a filter created after a record is already loaded works", function() { +test("a filter created after a record is already loaded works", function(assert) { customAdapter(env, DS.Adapter.extend({ shouldBackgroundReloadRecord: () => false })); @@ -460,11 +462,11 @@ test("a filter created after a record is already loaded works", function() { }); }); - equal(filter.get('length'), 1, "the filter now has a record in it"); + assert.equal(filter.get('length'), 1, "the filter now has a record in it"); asyncEqual(filter.objectAt(0), store.findRecord('person', 1)); }); -test("filter with query persists query on the resulting filteredRecordArray", function() { +test("filter with query persists query on the resulting filteredRecordArray", function(assert) { customAdapter(env, DS.Adapter.extend({ query: function(store, type, id) { return Ember.RSVP.resolve([{ @@ -484,13 +486,13 @@ test("filter with query persists query on the resulting filteredRecordArray", fu Ember.run(function() { filter.then(function(array) { - deepEqual(get(array, 'query'), { foo: 1 }, 'has expected query'); + assert.deepEqual(get(array, 'query'), { foo: 1 }, 'has expected query'); }); }); }); -test("it is possible to filter by state flags", function() { +test("it is possible to filter by state flags", function(assert) { var filter; customAdapter(env, DS.Adapter.extend({ @@ -505,7 +507,7 @@ test("it is possible to filter by state flags", function() { }); }); - equal(filter.get('length'), 0, "precond - there are no records yet"); + assert.equal(filter.get('length'), 0, "precond - there are no records yet"); Ember.run(function() { var asyncPerson = store.findRecord('person', 1); @@ -513,16 +515,16 @@ test("it is possible to filter by state flags", function() { // Ember.run will block `find` from being synchronously // resolved in test mode - equal(filter.get('length'), 0, "the unloaded record isn't in the filter"); + assert.equal(filter.get('length'), 0, "the unloaded record isn't in the filter"); asyncPerson.then(async(function(person) { - equal(filter.get('length'), 1, "the now-loaded record is in the filter"); + assert.equal(filter.get('length'), 1, "the now-loaded record is in the filter"); asyncEqual(filter.objectAt(0), store.findRecord('person', 1)); })); }); }); -test("it is possible to filter loaded records by dirtiness", function() { +test("it is possible to filter loaded records by dirtiness", function(assert) { customAdapter(env, DS.Adapter.extend({ updateRecord: function() { return Ember.RSVP.resolve(); @@ -547,7 +549,7 @@ test("it is possible to filter loaded records by dirtiness", function() { }); store.findRecord('person', 1).then(async(function(person) { - equal(filter.get('length'), 1, "the clean record is in the filter"); + assert.equal(filter.get('length'), 1, "the clean record is in the filter"); // Force synchronous update of the filter, even though // we're already inside a run loop @@ -555,15 +557,15 @@ test("it is possible to filter loaded records by dirtiness", function() { person.set('name', "Yehuda Katz"); }); - equal(filter.get('length'), 0, "the now-dirty record is not in the filter"); + assert.equal(filter.get('length'), 0, "the now-dirty record is not in the filter"); return person.save(); })).then(async(function(person) { - equal(filter.get('length'), 1, "the clean record is back in the filter"); + assert.equal(filter.get('length'), 1, "the clean record is back in the filter"); })); }); -test("it is possible to filter created records by dirtiness", function() { +test("it is possible to filter created records by dirtiness", function(assert) { run(function() { customAdapter(env, DS.Adapter.extend({ createRecord: function() { @@ -590,16 +592,16 @@ test("it is possible to filter created records by dirtiness", function() { }); }); - equal(filter.get('length'), 0, "the dirty record is not in the filter"); + assert.equal(filter.get('length'), 0, "the dirty record is not in the filter"); run(function() { person.save().then(function(person) { - equal(filter.get('length'), 1, "the clean record is in the filter"); + assert.equal(filter.get('length'), 1, "the clean record is in the filter"); }); }); }); -test("it is possible to filter created records by isReloading", function() { +test("it is possible to filter created records by isReloading", function(assert) { customAdapter(env, DS.Adapter.extend({ findRecord: function(store, type, id, snapshot) { return Ember.RSVP.resolve({ @@ -619,7 +621,7 @@ test("it is possible to filter created records by isReloading", function() { }); person.reload().then(async(function(person) { - equal(filter.get('length'), 1, "the filter correctly returned a reloaded object"); + assert.equal(filter.get('length'), 1, "the filter correctly returned a reloaded object"); })); }); @@ -669,10 +671,10 @@ var setup = function(serverCallbacks) { }); }); - equal(get(recordArray, 'length'), 3, "The filter function should work"); + assert.equal(get(recordArray, 'length'), 3, "The filter function should work"); }; -test("a Record Array can update its filter after server-side updates one record", function() { +test("a Record Array can update its filter after server-side updates one record", function(assert) { setup({ updateRecord: function(store, type, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Scumbag Server-side Dale" }); @@ -681,13 +683,13 @@ test("a Record Array can update its filter after server-side updates one record" }); clientEdits([1]); - equal(get(recordArray, 'length'), 2, "The record array updates when the client changes records"); + assert.equal(get(recordArray, 'length'), 2, "The record array updates when the client changes records"); serverResponds(); - equal(get(recordArray, 'length'), 3, "The record array updates when the server changes one record"); + assert.equal(get(recordArray, 'length'), 3, "The record array updates when the server changes one record"); }); -test("a Record Array can update its filter after server-side updates multiple records", function() { +test("a Record Array can update its filter after server-side updates multiple records", function(assert) { setup({ updateRecord: function(store, type, snapshot) { switch (snapshot.id) { @@ -701,13 +703,13 @@ test("a Record Array can update its filter after server-side updates multiple re }); clientEdits([1,2]); - equal(get(recordArray, 'length'), 1, "The record array updates when the client changes records"); + assert.equal(get(recordArray, 'length'), 1, "The record array updates when the client changes records"); serverResponds(); - equal(get(recordArray, 'length'), 3, "The record array updates when the server changes multiple records"); + assert.equal(get(recordArray, 'length'), 3, "The record array updates when the server changes multiple records"); }); -test("a Record Array can update its filter after server-side creates one record", function() { +test("a Record Array can update its filter after server-side creates one record", function(assert) { setup({ createRecord: function(store, type, snapshot) { return Ember.RSVP.resolve({ id: 4, name: "Scumbag Server-side Tim" }); @@ -715,13 +717,13 @@ test("a Record Array can update its filter after server-side creates one record" }); clientCreates(["Tim"]); - equal(get(recordArray, 'length'), 3, "The record array does not include non-matching records"); + assert.equal(get(recordArray, 'length'), 3, "The record array does not include non-matching records"); serverResponds(); - equal(get(recordArray, 'length'), 4, "The record array updates when the server creates a record"); + assert.equal(get(recordArray, 'length'), 4, "The record array updates when the server creates a record"); }); -test("a Record Array can update its filter after server-side creates multiple records", function() { +test("a Record Array can update its filter after server-side creates multiple records", function(assert) { setup({ createRecord: function(store, type, snapshot) { switch (snapshot.attr('name')) { @@ -734,13 +736,13 @@ test("a Record Array can update its filter after server-side creates multiple re }); clientCreates(["Mike", "David"]); - equal(get(recordArray, 'length'), 3, "The record array does not include non-matching records"); + assert.equal(get(recordArray, 'length'), 3, "The record array does not include non-matching records"); serverResponds(); - equal(get(recordArray, 'length'), 5, "The record array updates when the server creates multiple records"); + assert.equal(get(recordArray, 'length'), 5, "The record array updates when the server creates multiple records"); }); -test("a Record Array can update its filter after server-side creates multiple records", function() { +test("a Record Array can update its filter after server-side creates multiple records", function(assert) { setup({ createRecord: function(store, type, snapshot) { switch (snapshot.attr('name')) { @@ -753,13 +755,13 @@ test("a Record Array can update its filter after server-side creates multiple re }); clientCreates(["Mike", "David"]); - equal(get(recordArray, 'length'), 3, "The record array does not include non-matching records"); + assert.equal(get(recordArray, 'length'), 3, "The record array does not include non-matching records"); serverResponds(); - equal(get(recordArray, 'length'), 5, "The record array updates when the server creates multiple records"); + assert.equal(get(recordArray, 'length'), 5, "The record array updates when the server creates multiple records"); }); -test("destroying filteredRecordArray unregisters models from being filtered", function() { +test("destroying filteredRecordArray unregisters models from being filtered", function(assert) { var filterFn = tapFn(function() { return true; }); customAdapter(env, DS.Adapter.extend({ shouldBackgroundReloadRecord: () => false @@ -782,7 +784,7 @@ test("destroying filteredRecordArray unregisters models from being filtered", fu recordArray = store.filter('person', filterFn); }); - equal(filterFn.summary.called.length, 1); + assert.equal(filterFn.summary.called.length, 1); Ember.run(function() { recordArray.then(function(array) { @@ -791,5 +793,5 @@ test("destroying filteredRecordArray unregisters models from being filtered", fu }); clientEdits([1]); - equal(filterFn.summary.called.length, 1, 'expected the filter function not being called anymore'); + assert.equal(filterFn.summary.called.length, 1, 'expected the filter function not being called anymore'); }); diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index 990db17f4bc..d60d4367289 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, User, Job, ReflexiveModel; @@ -13,7 +15,7 @@ function stringify(string) { } module('integration/inverse_test - inverseFor', { - setup: function() { + beforeEach: function() { User = DS.Model.extend({ name: attr('string'), bestFriend: belongsTo('user', { async: true, inverse: null }), @@ -48,20 +50,20 @@ module('integration/inverse_test - inverseFor', { ReflexiveModel = store.modelFor('reflexive-model'); }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); -test("Finds the inverse when there is only one possible available", function () { - deepEqual(Job.inverseFor('user', store), { +test("Finds the inverse when there is only one possible available", function(assert) { + assert.deepEqual(Job.inverseFor('user', store), { type: User, name: 'job', kind: 'belongsTo' }, 'Gets correct type, name and kind'); }); -test("Finds the inverse when only one side has defined it manually", function () { +test("Finds the inverse when only one side has defined it manually", function(assert) { Job.reopen({ owner: belongsTo('user', { inverse: 'previousJob', async: false }) }); @@ -70,20 +72,20 @@ test("Finds the inverse when only one side has defined it manually", function () previousJob: belongsTo('job', { async: false }) }); - deepEqual(Job.inverseFor('owner', store), { + assert.deepEqual(Job.inverseFor('owner', store), { type: User, //the model's type name: 'previousJob', //the models relationship key kind: 'belongsTo' }, 'Gets correct type, name and kind'); - deepEqual(User.inverseFor('previousJob', store), { + assert.deepEqual(User.inverseFor('previousJob', store), { type: Job, //the model's type name: 'owner', //the models relationship key kind: 'belongsTo' }, 'Gets correct type, name and kind'); }); -test("Returns null if inverse relationship it is manually set with a different relationship key", function () { +test("Returns null if inverse relationship it is manually set with a different relationship key", function(assert) { Job.reopen({ user: belongsTo('user', { inverse: 'previousJob', async: false }) }); @@ -92,10 +94,10 @@ test("Returns null if inverse relationship it is manually set with a different r job: belongsTo('job', { async: false }) }); - equal(User.inverseFor('job', store), null, 'There is no inverse'); + assert.equal(User.inverseFor('job', store), null, 'There is no inverse'); }); -test("Errors out if you define 2 inverses to the same model", function () { +test("Errors out if you define 2 inverses to the same model", function(assert) { Job.reopen({ user: belongsTo('user', { inverse: 'job', async: false }), owner: belongsTo('user', { inverse: 'job', async: false }) @@ -111,18 +113,18 @@ test("Errors out if you define 2 inverses to the same model", function () { }); -test("Caches findInverseFor return value", function () { - expect(1); +test("Caches findInverseFor return value", function(assert) { + assert.expect(1); var inverseForUser = Job.inverseFor('user', store); Job.findInverseFor = function() { - ok(false, 'Find is not called anymore'); + assert.ok(false, 'Find is not called anymore'); }; - equal(inverseForUser, Job.inverseFor('user', store), 'Inverse cached succesfully'); + assert.equal(inverseForUser, Job.inverseFor('user', store), 'Inverse cached succesfully'); }); -test("Errors out if you do not define an inverse for a reflexive relationship", function () { +test("Errors out if you do not define an inverse for a reflexive relationship", function(assert) { //Maybe store is evaluated lazily, so we need this :( warns(function() { diff --git a/tests/integration/lifecycle-hooks-test.js b/tests/integration/lifecycle-hooks-test.js index 5ca507c4afa..62c3698f942 100644 --- a/tests/integration/lifecycle-hooks-test.js +++ b/tests/integration/lifecycle-hooks-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var Person, env; @@ -8,7 +10,7 @@ var resolve = Ember.RSVP.resolve; var run = Ember.run; module("integration/lifecycle_hooks - Lifecycle Hooks", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ name: attr('string') }); @@ -18,13 +20,13 @@ module("integration/lifecycle_hooks - Lifecycle Hooks", { }); }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); asyncTest("When the adapter acknowledges that a record has been created, a `didCreate` event is triggered.", function() { - expect(3); + assert.expect(3); env.adapter.createRecord = function(store, type, snapshot) { return resolve({ id: 99, name: "Yehuda Katz" }); @@ -36,17 +38,17 @@ asyncTest("When the adapter acknowledges that a record has been created, a `didC }); person.on('didCreate', function() { - equal(this, person, "this is bound to the record"); - equal(this.get('id'), "99", "the ID has been assigned"); - equal(this.get('name'), "Yehuda Katz", "the attribute has been assigned"); + assert.equal(this, person, "this is bound to the record"); + assert.equal(this.get('id'), "99", "the ID has been assigned"); + assert.equal(this.get('name'), "Yehuda Katz", "the attribute has been assigned"); start(); }); run(person, 'save'); }); -test("When the adapter acknowledges that a record has been created without a new data payload, a `didCreate` event is triggered.", function() { - expect(3); +test("When the adapter acknowledges that a record has been created without a new data payload, a `didCreate` event is triggered.", function(assert) { + assert.expect(3); env.adapter.createRecord = function(store, type, snapshot) { return Ember.RSVP.resolve(); @@ -58,9 +60,9 @@ test("When the adapter acknowledges that a record has been created without a new }); person.on('didCreate', function() { - equal(this, person, "this is bound to the record"); - equal(this.get('id'), "99", "the ID has been assigned"); - equal(this.get('name'), "Yehuda Katz", "the attribute has been assigned"); + assert.equal(this, person, "this is bound to the record"); + assert.equal(this.get('id'), "99", "the ID has been assigned"); + assert.equal(this.get('name'), "Yehuda Katz", "the attribute has been assigned"); }); run(person, 'save'); diff --git a/tests/integration/peek-all-test.js b/tests/integration/peek-all-test.js index fa0fe205778..126f60e9458 100644 --- a/tests/integration/peek-all-test.js +++ b/tests/integration/peek-all-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -8,7 +10,7 @@ var run = Ember.run; var Person, store, array, moreArray; module("integration/peek-all - DS.Store#peekAll()", { - setup: function() { + beforeEach: function() { array = { data: [{ type: 'person', @@ -38,35 +40,35 @@ module("integration/peek-all - DS.Store#peekAll()", { store = createStore({ person: Person }); }, - teardown: function() { + afterEach: function() { run(store, 'destroy'); Person = null; array = null; } }); -test("store.peekAll('person') should return all records and should update with new ones", function() { +test("store.peekAll('person') should return all records and should update with new ones", function(assert) { run(function() { store.push(array); }); var all = store.peekAll('person'); - equal(get(all, 'length'), 2); + assert.equal(get(all, 'length'), 2); run(function() { store.push(moreArray); }); - equal(get(all, 'length'), 3); + assert.equal(get(all, 'length'), 3); }); -test("Calling store.peekAll() multiple times should update immediately inside the runloop", function() { - expect(3); +test("Calling store.peekAll() multiple times should update immediately inside the runloop", function(assert) { + assert.expect(3); Ember.run(function() { - equal(get(store.peekAll('person'), 'length'), 0, 'should initially be empty'); + assert.equal(get(store.peekAll('person'), 'length'), 0, 'should initially be empty'); store.createRecord('person', { name: "Tomster" }); - equal(get(store.peekAll('person'), 'length'), 1, 'should contain one person'); + assert.equal(get(store.peekAll('person'), 'length'), 1, 'should contain one person'); store.push({ data: { type: 'person', @@ -76,15 +78,15 @@ test("Calling store.peekAll() multiple times should update immediately inside th } } }); - equal(get(store.peekAll('person'), 'length'), 2, 'should contain two people'); + assert.equal(get(store.peekAll('person'), 'length'), 2, 'should contain two people'); }); }); -test("Calling store.peekAll() after creating a record should return correct data", function() { - expect(1); +test("Calling store.peekAll() after creating a record should return correct data", function(assert) { + assert.expect(1); Ember.run(function() { store.createRecord('person', { name: "Tomster" }); - equal(get(store.peekAll('person'), 'length'), 1, 'should contain one person'); + assert.equal(get(store.peekAll('person'), 'length'), 1, 'should contain one person'); }); }); diff --git a/tests/integration/polymorphic-belongs-to-test.js b/tests/integration/polymorphic-belongs-to-test.js index 97c0ced2537..8c64116b51b 100644 --- a/tests/integration/polymorphic-belongs-to-test.js +++ b/tests/integration/polymorphic-belongs-to-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; const {attr, belongsTo} = DS; @@ -21,7 +23,7 @@ const AsyncBook = DS.Model.extend({ }); module('integration/polymorphic-belongs-to - Polymorphic BelongsTo', { - setup() { + beforeEach() { let env = setupStore({ book: Book, author: Author, @@ -31,7 +33,7 @@ module('integration/polymorphic-belongs-to - Polymorphic BelongsTo', { store = env.store; }, - teardown() { + afterEach() { run(store, 'destroy'); } }); @@ -66,7 +68,7 @@ test('using store.push with a null value for a payload in relationships sets the return store.peekRecord('book', 1); }); - equal(book.get('author.id'), 1); + assert.equal(book.get('author.id'), 1); let payloadThatResetsBelongToRelationship = { data: { @@ -82,7 +84,7 @@ test('using store.push with a null value for a payload in relationships sets the }; run(() => store.push(payloadThatResetsBelongToRelationship)); - equal(book.get('author'), null); + assert.equal(book.get('author'), null); }); test('using store.push with a null value for a payload in relationships sets the Models relationship to null - async relationship', () => { @@ -129,11 +131,11 @@ test('using store.push with a null value for a payload in relationships sets the stop(); book.get('author').then((author) => { - equal(author.get('id'), 1); + assert.equal(author.get('id'), 1); run(() => store.push(payloadThatResetsBelongToRelationship)); return book.get('author'); }).then((author) => { start(); - equal(author, null); + assert.equal(author, null); }); }); diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index a1d322a8247..a046a911906 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var store, env; @@ -23,7 +25,7 @@ Car.toString = function() { return "Car"; }; var manager; module("integration/record_array_manager", { - setup: function() { + beforeEach: function() { env = setupStore({ adapter: DS.RESTAdapter.extend() }); @@ -53,7 +55,7 @@ function tap(obj, methodName, callback) { return summary; } -test("destroying the store correctly cleans everything up", function() { +test("destroying the store correctly cleans everything up", function(assert) { var query = { }; var person; @@ -105,32 +107,32 @@ test("destroying the store correctly cleans everything up", function() { var allSummary = tap(all, 'willDestroy'); var adapterPopulatedSummary = tap(adapterPopulated, 'willDestroy'); - equal(filterdSummary.called.length, 0); - equal(filterd2Summary.called.length, 0); - equal(allSummary.called.length, 0); - equal(adapterPopulatedSummary.called.length, 0); + assert.equal(filterdSummary.called.length, 0); + assert.equal(filterd2Summary.called.length, 0); + assert.equal(allSummary.called.length, 0); + assert.equal(adapterPopulatedSummary.called.length, 0); - equal(person._internalModel._recordArrays.list.length, 3, 'expected the person to be a member of 3 recordArrays'); + assert.equal(person._internalModel._recordArrays.list.length, 3, 'expected the person to be a member of 3 recordArrays'); Ember.run(filterd2, filterd2.destroy); - equal(person._internalModel._recordArrays.list.length, 2, 'expected the person to be a member of 2 recordArrays'); - equal(filterd2Summary.called.length, 1); + assert.equal(person._internalModel._recordArrays.list.length, 2, 'expected the person to be a member of 2 recordArrays'); + assert.equal(filterd2Summary.called.length, 1); - equal(manager.liveRecordArrays.has(all.type), true); + assert.equal(manager.liveRecordArrays.has(all.type), true); Ember.run(all, all.destroy); - equal(person._internalModel._recordArrays.list.length, 1, 'expected the person to be a member of 1 recordArrays'); - equal(allSummary.called.length, 1); - equal(manager.liveRecordArrays.has(all.type), false); + assert.equal(person._internalModel._recordArrays.list.length, 1, 'expected the person to be a member of 1 recordArrays'); + assert.equal(allSummary.called.length, 1); + assert.equal(manager.liveRecordArrays.has(all.type), false); Ember.run(manager, manager.destroy); - equal(person._internalModel._recordArrays.list.length, 0, 'expected the person to be a member of no recordArrays'); - equal(filterdSummary.called.length, 1); - equal(filterd2Summary.called.length, 1); - equal(allSummary.called.length, 1); - equal(adapterPopulatedSummary.called.length, 1); + assert.equal(person._internalModel._recordArrays.list.length, 0, 'expected the person to be a member of no recordArrays'); + assert.equal(filterdSummary.called.length, 1); + assert.equal(filterd2Summary.called.length, 1); + assert.equal(allSummary.called.length, 1); + assert.equal(adapterPopulatedSummary.called.length, 1); }); -test("Should not filter a store.peekAll() array when a record property is changed", function() { +test("Should not filter a store.peekAll() array when a record property is changed", function(assert) { var car; var populateLiveRecordArray = tap(store.recordArrayManager, 'populateLiveRecordArray'); @@ -157,14 +159,14 @@ test("Should not filter a store.peekAll() array when a record property is change car = store.peekRecord('car', 1); }); - equal(populateLiveRecordArray.called.length, 1); - equal(updateFilterRecordArray.called.length, 0); + assert.equal(populateLiveRecordArray.called.length, 1); + assert.equal(updateFilterRecordArray.called.length, 0); run(function() { car.set('model', 'Mini'); }); - equal(populateLiveRecordArray.called.length, 1); - equal(updateFilterRecordArray.called.length, 0); + assert.equal(populateLiveRecordArray.called.length, 1); + assert.equal(updateFilterRecordArray.called.length, 0); }); diff --git a/tests/integration/records/collection-save-test.js b/tests/integration/records/collection-save-test.js index 64e9375206a..778dbe7eb24 100644 --- a/tests/integration/records/collection-save-test.js +++ b/tests/integration/records/collection-save-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var Post, env; var run = Ember.run; module("integration/records/collection_save - Save Collection of Records", { - setup: function() { + beforeEach: function() { Post = DS.Model.extend({ title: DS.attr('string') }); @@ -16,13 +18,13 @@ module("integration/records/collection_save - Save Collection of Records", { env = setupStore({ post: Post }); }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); -test("Collection will resolve save on success", function() { - expect(1); +test("Collection will resolve save on success", function(assert) { + assert.expect(1); run(function() { env.store.createRecord('post', { title: 'Hello' }); env.store.createRecord('post', { title: 'World' }); @@ -36,12 +38,12 @@ test("Collection will resolve save on success", function() { run(function() { posts.save().then(async(function() { - ok(true, 'save operation was resolved'); + assert.ok(true, 'save operation was resolved'); })); }); }); -test("Collection will reject save on error", function() { +test("Collection will reject save on error", function(assert) { run(function() { env.store.createRecord('post', { title: 'Hello' }); env.store.createRecord('post', { title: 'World' }); @@ -55,12 +57,12 @@ test("Collection will reject save on error", function() { run(function() { posts.save().then(function() {}, async(function() { - ok(true, 'save operation was rejected'); + assert.ok(true, 'save operation was rejected'); })); }); }); -test("Retry is allowed in a failure handler", function() { +test("Retry is allowed in a failure handler", function(assert) { run(function() { env.store.createRecord('post', { title: 'Hello' }); env.store.createRecord('post', { title: 'World' }); @@ -86,13 +88,13 @@ test("Retry is allowed in a failure handler", function() { posts.save().then(function() {}, async(function() { return posts.save(); })).then(async(function(post) { - equal(posts.get('firstObject.id'), '123', "The post ID made it through"); + assert.equal(posts.get('firstObject.id'), '123', "The post ID made it through"); })); }); }); -test("Collection will reject save on invalid", function() { - expect(1); +test("Collection will reject save on invalid", function(assert) { + assert.expect(1); run(function() { env.store.createRecord('post', { title: 'Hello' }); env.store.createRecord('post', { title: 'World' }); @@ -106,7 +108,7 @@ test("Collection will reject save on invalid", function() { Ember.run(function() { posts.save().then(function() {}, function() { - ok(true, 'save operation was rejected'); + assert.ok(true, 'save operation was rejected'); }); }); }); diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index 4aed2a16021..0ccb876d245 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var attr = DS.attr; @@ -7,7 +9,7 @@ var Person, env; var run = Ember.run; module("integration/deletedRecord - Deleting Records", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ name: attr('string') }); @@ -19,14 +21,14 @@ module("integration/deletedRecord - Deleting Records", { }); }, - teardown: function() { + afterEach: function() { Ember.run(function() { env.container.destroy(); }); } }); -test("records should not be removed from record arrays just after deleting, but only after commiting them", function () { +test("records should not be removed from record arrays just after deleting, but only after commiting them", function(assert) { var adam, dave; env.adapter.deleteRecord = function() { @@ -57,18 +59,18 @@ test("records should not be removed from record arrays just after deleting, but // pre-condition - equal(all.get('length'), 2, 'pre-condition: 2 records in array'); + assert.equal(all.get('length'), 2, 'pre-condition: 2 records in array'); Ember.run(adam, 'deleteRecord'); - equal(all.get('length'), 2, '2 records in array after deleteRecord'); + assert.equal(all.get('length'), 2, '2 records in array after deleteRecord'); Ember.run(adam, 'save'); - equal(all.get('length'), 1, '1 record in array after deleteRecord and save'); + assert.equal(all.get('length'), 1, '1 record in array after deleteRecord and save'); }); -test("records can be deleted during record array enumeration", function () { +test("records can be deleted during record array enumeration", function(assert) { var adam, dave; env.adapter.deleteRecord = function() { @@ -97,7 +99,7 @@ test("records can be deleted during record array enumeration", function () { var all = env.store.peekAll('person'); // pre-condition - equal(all.get('length'), 2, 'expected 2 records'); + assert.equal(all.get('length'), 2, 'expected 2 records'); Ember.run(function() { all.forEach(function(record) { @@ -105,11 +107,11 @@ test("records can be deleted during record array enumeration", function () { }); }); - equal(all.get('length'), 0, 'expected 0 records'); - equal(all.objectAt(0), null, "can't get any records"); + assert.equal(all.get('length'), 0, 'expected 0 records'); + assert.equal(all.objectAt(0), null, "can't get any records"); }); -test("when deleted records are rolled back, they are still in their previous record arrays", function () { +test("when deleted records are rolled back, they are still in their previous record arrays", function(assert) { var jaime, cersei; run(function() { env.store.push({ @@ -138,13 +140,13 @@ test("when deleted records are rolled back, they are still in their previous rec }); }); - equal(all.get('length'), 2, 'precond - we start with two people'); - equal(filtered.get('length'), 2, 'precond - we start with two people'); + assert.equal(all.get('length'), 2, 'precond - we start with two people'); + assert.equal(filtered.get('length'), 2, 'precond - we start with two people'); run(function() { jaime.deleteRecord(); jaime.rollbackAttributes(); }); - equal(all.get('length'), 2, 'record was not removed'); - equal(filtered.get('length'), 2, 'record was not removed'); + assert.equal(all.get('length'), 2, 'record was not removed'); + assert.equal(filtered.get('length'), 2, 'record was not removed'); }); diff --git a/tests/integration/records/load-test.js b/tests/integration/records/load-test.js index 1085d935a27..91d61056732 100644 --- a/tests/integration/records/load-test.js +++ b/tests/integration/records/load-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var hasMany = DS.hasMany; @@ -7,7 +9,7 @@ var Post, Comment, env; var run = Ember.run; module("integration/load - Loading Records", { - setup: function() { + beforeEach: function() { Post = DS.Model.extend({ comments: hasMany({ async: true }) }); @@ -20,12 +22,12 @@ module("integration/load - Loading Records", { env = setupStore({ post: Post, comment: Comment }); }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); -test("When loading a record fails, the isLoading is set to false", function() { +test("When loading a record fails, the isLoading is set to false", function(assert) { env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.reject(); }; @@ -37,7 +39,7 @@ test("When loading a record fails, the isLoading is set to false", function() { // rejection handler var post = env.store.recordForId('post', 1); - equal(post.get("isLoading"), false, "post is not loading anymore"); + assert.equal(post.get("isLoading"), false, "post is not loading anymore"); })); }); }); diff --git a/tests/integration/records/property-changes-test.js b/tests/integration/records/property-changes-test.js index 4b961ef2a84..eec961c7c49 100644 --- a/tests/integration/records/property-changes-test.js +++ b/tests/integration/records/property-changes-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, Person; @@ -7,7 +9,7 @@ var attr = DS.attr; var run = Ember.run; module('integration/records/property-changes - Property changes', { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ firstName: attr('string'), lastName: attr('string') @@ -20,15 +22,15 @@ module('integration/records/property-changes - Property changes', { store = env.store; }, - teardown: function() { + afterEach: function() { Ember.run(function() { env.container.destroy(); }); } }); -test('Calling push with partial records trigger observers for just those attributes that changed', function() { - expect(1); +test('Calling push with partial records trigger observers for just those attributes that changed', function(assert) { + assert.expect(1); var person; run(function() { @@ -46,11 +48,11 @@ test('Calling push with partial records trigger observers for just those attribu }); person.addObserver('firstName', function() { - ok(false, 'firstName observer should not be triggered'); + assert.ok(false, 'firstName observer should not be triggered'); }); person.addObserver('lastName', function() { - ok(true, 'lastName observer should be triggered'); + assert.ok(true, 'lastName observer should be triggered'); }); run(function() { @@ -67,8 +69,8 @@ test('Calling push with partial records trigger observers for just those attribu }); }); -test('Calling push does not trigger observers for locally changed attributes with the same value', function() { - expect(0); +test('Calling push does not trigger observers for locally changed attributes with the same value', function(assert) { + assert.expect(0); var person; run(function() { @@ -87,11 +89,11 @@ test('Calling push does not trigger observers for locally changed attributes wit }); person.addObserver('firstName', function() { - ok(false, 'firstName observer should not be triggered'); + assert.ok(false, 'firstName observer should not be triggered'); }); person.addObserver('lastName', function() { - ok(false, 'lastName observer should not be triggered'); + assert.ok(false, 'lastName observer should not be triggered'); }); run(function() { @@ -108,8 +110,8 @@ test('Calling push does not trigger observers for locally changed attributes wit }); }); -test('Saving a record trigger observers for locally changed attributes with the same canonical value', function() { - expect(1); +test('Saving a record trigger observers for locally changed attributes with the same canonical value', function(assert) { + assert.expect(1); var person; env.adapter.updateRecord = function(store, type, snapshot) { @@ -132,11 +134,11 @@ test('Saving a record trigger observers for locally changed attributes with the }); person.addObserver('firstName', function() { - ok(false, 'firstName observer should not be triggered'); + assert.ok(false, 'firstName observer should not be triggered'); }); person.addObserver('lastName', function() { - ok(true, 'lastName observer should be triggered'); + assert.ok(true, 'lastName observer should be triggered'); }); run(function() { @@ -144,8 +146,8 @@ test('Saving a record trigger observers for locally changed attributes with the }); }); -test('store.push should not override a modified attribute', function() { - expect(1); +test('store.push should not override a modified attribute', function(assert) { + assert.expect(1); var person; run(function() { @@ -164,11 +166,11 @@ test('store.push should not override a modified attribute', function() { }); person.addObserver('firstName', function() { - ok(true, 'firstName observer should be triggered'); + assert.ok(true, 'firstName observer should be triggered'); }); person.addObserver('lastName', function() { - ok(false, 'lastName observer should not be triggered'); + assert.ok(false, 'lastName observer should not be triggered'); }); run(function() { diff --git a/tests/integration/records/reload-test.js b/tests/integration/records/reload-test.js index c769a177fde..cea6be8c3a0 100644 --- a/tests/integration/records/reload-test.js +++ b/tests/integration/records/reload-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -8,7 +10,7 @@ var Person, env; var run = Ember.run; module("integration/reload - Reloading Records", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ updatedAt: attr('string'), name: attr('string'), @@ -21,12 +23,12 @@ module("integration/reload - Reloading Records", { env = setupStore({ person: Person }); }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); -test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function() { +test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function(assert) { var count = 0; env.adapter.findRecord = function(store, type, id, snapshot) { @@ -37,25 +39,25 @@ test("When a single record is requested, the adapter's find method should be cal count++; return Ember.RSVP.resolve({ id: id, name: "Braaaahm Dale" }); } else { - ok(false, "Should not get here"); + assert.ok(false, "Should not get here"); } }; run(function() { env.store.findRecord('person', 1).then(function(person) { - equal(get(person, 'name'), "Tom Dale", "The person is loaded with the right name"); - equal(get(person, 'isLoaded'), true, "The person is now loaded"); + assert.equal(get(person, 'name'), "Tom Dale", "The person is loaded with the right name"); + assert.equal(get(person, 'isLoaded'), true, "The person is now loaded"); var promise = person.reload(); - equal(get(person, 'isReloading'), true, "The person is now reloading"); + assert.equal(get(person, 'isReloading'), true, "The person is now reloading"); return promise; }).then(function(person) { - equal(get(person, 'isReloading'), false, "The person is no longer reloading"); - equal(get(person, 'name'), "Braaaahm Dale", "The person is now updated with the right name"); + assert.equal(get(person, 'isReloading'), false, "The person is no longer reloading"); + assert.equal(get(person, 'name'), "Braaaahm Dale", "The person is now updated with the right name"); }); }); }); -test("When a record is reloaded and fails, it can try again", function() { +test("When a record is reloaded and fails, it can try again", function(assert) { var tom; run(function() { env.store.push({ @@ -72,7 +74,7 @@ test("When a record is reloaded and fails, it can try again", function() { var count = 0; env.adapter.findRecord = function(store, type, id, snapshot) { - equal(tom.get('isReloading'), true, "Tom is reloading"); + assert.equal(tom.get('isReloading'), true, "Tom is reloading"); if (count++ === 0) { return Ember.RSVP.reject(); } else { @@ -82,19 +84,19 @@ test("When a record is reloaded and fails, it can try again", function() { run(function() { tom.reload().then(null, function() { - equal(tom.get('isError'), true, "Tom is now errored"); - equal(tom.get('isReloading'), false, "Tom is no longer reloading"); + assert.equal(tom.get('isError'), true, "Tom is now errored"); + assert.equal(tom.get('isReloading'), false, "Tom is no longer reloading"); return tom.reload(); }).then(function(person) { - equal(person, tom, "The resolved value is the record"); - equal(tom.get('isError'), false, "Tom is no longer errored"); - equal(tom.get('isReloading'), false, "Tom is no longer reloading"); - equal(tom.get('name'), "Thomas Dale", "the updates apply"); + assert.equal(person, tom, "The resolved value is the record"); + assert.equal(tom.get('isError'), false, "Tom is no longer errored"); + assert.equal(tom.get('isReloading'), false, "Tom is no longer reloading"); + assert.equal(tom.get('name'), "Thomas Dale", "the updates apply"); }); }); }); -test("When a record is loaded a second time, isLoaded stays true", function() { +test("When a record is loaded a second time, isLoaded stays true", function(assert) { env.adapter.findRecord = function(store, type, id, snapshot) { return { id: 1, name: "Tom Dale" }; }; @@ -112,7 +114,7 @@ test("When a record is loaded a second time, isLoaded stays true", function() { run(function() { env.store.findRecord('person', 1).then(function(person) { - equal(get(person, 'isLoaded'), true, "The person is loaded"); + assert.equal(get(person, 'isLoaded'), true, "The person is loaded"); person.addObserver('isLoaded', isLoadedDidChange); // Reload the record @@ -126,7 +128,7 @@ test("When a record is loaded a second time, isLoaded stays true", function() { } }); - equal(get(person, 'isLoaded'), true, "The person is still loaded after load"); + assert.equal(get(person, 'isLoaded'), true, "The person is still loaded after load"); person.removeObserver('isLoaded', isLoadedDidChange); }); @@ -134,11 +136,11 @@ test("When a record is loaded a second time, isLoaded stays true", function() { function isLoadedDidChange() { // This shouldn't be hit - equal(get(this, 'isLoaded'), true, "The person is still loaded after change"); + assert.equal(get(this, 'isLoaded'), true, "The person is still loaded after change"); } }); -test("When a record is reloaded, its async hasMany relationships still work", function() { +test("When a record is reloaded, its async hasMany relationships still work", function(assert) { env.registry.register('model:person', DS.Model.extend({ name: DS.attr(), tags: DS.hasMany('tag', { async: true }) @@ -164,19 +166,19 @@ test("When a record is reloaded, its async hasMany relationships still work", fu run(function() { env.store.findRecord('person', 1).then(function(person) { tom = person; - equal(person.get('name'), "Tom", "precond"); + assert.equal(person.get('name'), "Tom", "precond"); return person.get('tags'); }).then(function(tags) { - deepEqual(tags.mapBy('name'), ['hipster', 'hair']); + assert.deepEqual(tags.mapBy('name'), ['hipster', 'hair']); return tom.reload(); }).then(function(person) { - equal(person.get('name'), "Tom", "precond"); + assert.equal(person.get('name'), "Tom", "precond"); return person.get('tags'); }).then(function(tags) { - deepEqual(tags.mapBy('name'), ['hipster', 'hair'], "The tags are still there"); + assert.deepEqual(tags.mapBy('name'), ['hipster', 'hair'], "The tags are still there"); }); }); }); diff --git a/tests/integration/records/save-test.js b/tests/integration/records/save-test.js index aac9e9ce51a..f6b4e588f0b 100644 --- a/tests/integration/records/save-test.js +++ b/tests/integration/records/save-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var Post, env; var run = Ember.run; module("integration/records/save - Save Record", { - setup: function() { + beforeEach: function() { Post = DS.Model.extend({ title: DS.attr('string') }); @@ -16,13 +18,13 @@ module("integration/records/save - Save Record", { env = setupStore({ post: Post }); }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); -test("Will resolve save on success", function() { - expect(4); +test("Will resolve save on success", function(assert) { + assert.expect(4); var post; run(function() { post = env.store.createRecord('post', { title: 'toto' }); @@ -37,18 +39,18 @@ test("Will resolve save on success", function() { var saved = post.save(); // `save` returns a PromiseObject which allows to call get on it - equal(saved.get('id'), undefined); + assert.equal(saved.get('id'), undefined); deferred.resolve({ id: 123 }); saved.then(function(model) { - ok(true, 'save operation was resolved'); - equal(saved.get('id'), 123); - equal(model, post, "resolves with the model"); + assert.ok(true, 'save operation was resolved'); + assert.equal(saved.get('id'), 123); + assert.equal(model, post, "resolves with the model"); }); }); }); -test("Will reject save on error", function() { +test("Will reject save on error", function(assert) { var post; run(function() { post = env.store.createRecord('post', { title: 'toto' }); @@ -60,12 +62,12 @@ test("Will reject save on error", function() { run(function() { post.save().then(function() {}, function() { - ok(true, 'save operation was rejected'); + assert.ok(true, 'save operation was rejected'); }); }); }); -test("Retry is allowed in a failure handler", function() { +test("Retry is allowed in a failure handler", function(assert) { var post; run(function() { post = env.store.createRecord('post', { title: 'toto' }); @@ -85,13 +87,13 @@ test("Retry is allowed in a failure handler", function() { post.save().then(function() {}, function() { return post.save(); }).then(function(post) { - equal(post.get('id'), '123', "The post ID made it through"); + assert.equal(post.get('id'), '123', "The post ID made it through"); }); }); }); -test("Repeated failed saves keeps the record in uncommited state", function() { - expect(4); +test("Repeated failed saves keeps the record in uncommited state", function(assert) { + assert.expect(4); var post; run(function() { @@ -104,19 +106,19 @@ test("Repeated failed saves keeps the record in uncommited state", function() { run(function() { post.save().then(null, function() { - ok(post.get('isError')); - equal(post.get('currentState.stateName'), 'root.loaded.created.uncommitted'); + assert.ok(post.get('isError')); + assert.equal(post.get('currentState.stateName'), 'root.loaded.created.uncommitted'); post.save().then(null, function() { - ok(post.get('isError')); - equal(post.get('currentState.stateName'), 'root.loaded.created.uncommitted'); + assert.ok(post.get('isError')); + assert.equal(post.get('currentState.stateName'), 'root.loaded.created.uncommitted'); }); }); }); }); -test("Repeated failed saves with invalid error marks the record as invalid", function() { - expect(2); +test("Repeated failed saves with invalid error marks the record as invalid", function(assert) { + assert.expect(2); var post; run(function() { @@ -136,17 +138,17 @@ test("Repeated failed saves with invalid error marks the record as invalid", fun run(function() { post.save().then(null, function() { - equal(post.get('isValid'), false); + assert.equal(post.get('isValid'), false); post.save().then(null, function() { - equal(post.get('isValid'), false); + assert.equal(post.get('isValid'), false); }); }); }); }); -test("Repeated failed saves with invalid error without payload marks the record as invalid", function() { - expect(2); +test("Repeated failed saves with invalid error without payload marks the record as invalid", function(assert) { + assert.expect(2); var post; run(function() { @@ -161,17 +163,17 @@ test("Repeated failed saves with invalid error without payload marks the record run(function() { post.save().then(null, function() { - equal(post.get('isValid'), false); + assert.equal(post.get('isValid'), false); post.save().then(null, function() { - equal(post.get('isValid'), false); + assert.equal(post.get('isValid'), false); }); }); }); }); -test("Will reject save on invalid", function() { - expect(1); +test("Will reject save on invalid", function(assert) { + assert.expect(1); var post; run(function() { post = env.store.createRecord('post', { title: 'toto' }); @@ -183,7 +185,7 @@ test("Will reject save on invalid", function() { run(function() { post.save().then(function() {}, function() { - ok(true, 'save operation was rejected'); + assert.ok(true, 'save operation was rejected'); }); }); }); diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index ebdb1176f65..3556d30dbc9 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var attr = DS.attr; @@ -30,7 +32,7 @@ var Car = DS.Model.extend({ Car.toString = function() { return "Car"; }; module("integration/unload - Unloading Records", { - setup: function() { + beforeEach: function() { env = setupStore({ person: Person, car: Car, @@ -38,14 +40,14 @@ module("integration/unload - Unloading Records", { }); }, - teardown: function() { + afterEach: function() { Ember.run(function() { env.container.destroy(); }); } }); -test("can unload a single record", function () { +test("can unload a single record", function(assert) { var adam; run(function() { env.store.push({ @@ -64,11 +66,11 @@ test("can unload a single record", function () { adam.unloadRecord(); }); - equal(env.store.peekAll('person').get('length'), 0); + assert.equal(env.store.peekAll('person').get('length'), 0); }); -test("can unload all records for a given type", function () { - expect(2); +test("can unload all records for a given type", function(assert) { + assert.expect(2); var adam, bob, dudu; run(function() { @@ -112,12 +114,12 @@ test("can unload all records for a given type", function () { env.store.unloadAll('person'); }); - equal(env.store.peekAll('person').get('length'), 0); - equal(env.store.peekAll('car').get('length'), 1); + assert.equal(env.store.peekAll('person').get('length'), 0); + assert.equal(env.store.peekAll('car').get('length'), 1); }); -test("can unload all records", function () { - expect(2); +test("can unload all records", function(assert) { + assert.expect(2); var adam, bob, dudu; run(function() { @@ -161,11 +163,11 @@ test("can unload all records", function () { env.store.unloadAll(); }); - equal(env.store.peekAll('person').get('length'), 0); - equal(env.store.peekAll('car').get('length'), 0); + assert.equal(env.store.peekAll('person').get('length'), 0); + assert.equal(env.store.peekAll('car').get('length'), 0); }); -test("removes findAllCache after unloading all records", function () { +test("removes findAllCache after unloading all records", function(assert) { var adam, bob; run(function() { env.store.push({ @@ -192,10 +194,10 @@ test("removes findAllCache after unloading all records", function () { env.store.unloadAll('person'); }); - equal(env.store.peekAll('person').get('length'), 0); + assert.equal(env.store.peekAll('person').get('length'), 0); }); -test("unloading all records also updates record array from peekAll()", function() { +test("unloading all records also updates record array from peekAll()", function(assert) { var adam, bob; run(function() { env.store.push({ @@ -218,17 +220,17 @@ test("unloading all records also updates record array from peekAll()", function( }); var all = env.store.peekAll('person'); - equal(all.get('length'), 2); + assert.equal(all.get('length'), 2); Ember.run(function() { env.store.unloadAll('person'); }); - equal(all.get('length'), 0); + assert.equal(all.get('length'), 0); }); -test("unloading a record also clears its relationship", function() { +test("unloading a record also clears its relationship", function(assert) { var adam, bob; // disable background reloading so we do not re-create the relationship. @@ -275,18 +277,18 @@ test("unloading a record also clears its relationship", function() { run(function() { env.store.findRecord('person', 1).then(function(person) { - equal(person.get('cars.length'), 1, 'The inital length of cars is correct'); + assert.equal(person.get('cars.length'), 1, 'The inital length of cars is correct'); run(function() { person.unloadRecord(); }); - equal(person.get('cars.length'), undefined); + assert.equal(person.get('cars.length'), undefined); }); }); }); -test("unloading a record also clears the implicit inverse relationships", function() { +test("unloading a record also clears the implicit inverse relationships", function(assert) { var adam, bob; // disable background reloading so we do not re-create the relationship. env.adapter.shouldBackgroundReloadRecord = () => false; @@ -323,13 +325,13 @@ test("unloading a record also clears the implicit inverse relationships", functi run(function() { env.store.findRecord('group', 1).then(function(group) { - equal(group.get('people.length'), 1, 'The inital length of people is correct'); + assert.equal(group.get('people.length'), 1, 'The inital length of people is correct'); var person = env.store.peekRecord('person', 1); run(function() { person.unloadRecord(); }); - equal(group.get('people.length'), 0, 'Person was removed from the people array'); + assert.equal(group.get('people.length'), 0, 'Person was removed from the people array'); }); }); }); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index d6084666494..c1f53293e2d 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, User, Message, Post, Contact, Comment, Book, Chapter, Author, NewMessage; @@ -27,7 +29,7 @@ function getComputedPropertyDesc(model, key) { } module("integration/relationship/belongs_to Belongs-To Relationships", { - setup: function() { + beforeEach: function() { User = DS.Model.extend({ name: attr('string'), messages: hasMany('message', { polymorphic: true, async: false }), @@ -95,13 +97,13 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { Author = store.modelFor('author'); }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); -test("The store can materialize a non loaded monomorphic belongsTo association", function() { - expect(1); +test("The store can materialize a non loaded monomorphic belongsTo association", function(assert) { + assert.expect(1); env.store.modelFor('post').reopen({ user: DS.belongsTo('user', { @@ -111,7 +113,7 @@ test("The store can materialize a non loaded monomorphic belongsTo association", }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.findRecord = function(store, type, id, snapshot) { - ok(true, "The adapter's find method should be called"); + assert.ok(true, "The adapter's find method should be called"); return Ember.RSVP.resolve({ id: 1 }); @@ -141,8 +143,8 @@ test("The store can materialize a non loaded monomorphic belongsTo association", }); }); -test("Only a record of the same type can be used with a monomorphic belongsTo relationship", function() { - expect(1); +test("Only a record of the same type can be used with a monomorphic belongsTo relationship", function(assert) { + assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.push({ @@ -172,9 +174,9 @@ test("Only a record of the same type can be used with a monomorphic belongsTo re }); }); -test("Only a record of the same base type can be used with a polymorphic belongsTo relationship", function() { +test("Only a record of the same base type can be used with a polymorphic belongsTo relationship", function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; - expect(1); + assert.expect(1); run(function() { store.push({ data: [{ @@ -223,7 +225,7 @@ test("Only a record of the same base type can be used with a polymorphic belongs }); }); -test("The store can load a polymorphic belongsTo association", function() { +test("The store can load a polymorphic belongsTo association", function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { env.store.push({ @@ -254,17 +256,17 @@ test("The store can load a polymorphic belongsTo association", function() { message: store.findRecord('post', 1), comment: store.findRecord('comment', 2) }).then(function(records) { - equal(records.comment.get('message'), records.message); + assert.equal(records.comment.get('message'), records.message); }); }); }); -test("The store can serialize a polymorphic belongsTo association", function() { +test("The store can serialize a polymorphic belongsTo association", function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; var serializerInstance = store.serializerFor('comment'); serializerInstance.serializePolymorphicType = function(record, json, relationship) { - ok(true, "The serializer's serializePolymorphicType method should be called"); + assert.ok(true, "The serializer's serializePolymorphicType method should be called"); json["message_type"] = "post"; }; run(function() { @@ -291,13 +293,13 @@ test("The store can serialize a polymorphic belongsTo association", function() { store.findRecord('comment', 2).then(function(comment) { var serialized = store.serialize(comment, { includeId: true }); - equal(serialized['message'], 1); - equal(serialized['message_type'], 'post'); + assert.equal(serialized['message'], 1); + assert.equal(serialized['message_type'], 'post'); }); }); }); -test("A serializer can materialize a belongsTo as a link that gets sent back to findBelongsTo", function() { +test("A serializer can materialize a belongsTo as a link that gets sent back to findBelongsTo", function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; var Group = DS.Model.extend({ people: DS.hasMany('person', { async: false }) @@ -331,9 +333,9 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to }; env.adapter.findBelongsTo = async(function(store, snapshot, link, relationship) { - equal(relationship.type, 'group'); - equal(relationship.key, 'group'); - equal(link, "/people/1/group"); + assert.equal(relationship.type, 'group'); + assert.equal(relationship.key, 'group'); + assert.equal(link, "/people/1/group"); return Ember.RSVP.resolve({ id: 1, people: [1] }); }); @@ -342,13 +344,13 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to env.store.findRecord('person', 1).then(function(person) { return person.get('group'); }).then(function(group) { - ok(group instanceof Group, "A group object is loaded"); - ok(group.get('id') === '1', 'It is the group we are expecting'); + assert.ok(group instanceof Group, "A group object is loaded"); + assert.ok(group.get('id') === '1', 'It is the group we are expecting'); }); }); }); -test('A record with an async belongsTo relationship always returns a promise for that relationship', function () { +test('A record with an async belongsTo relationship always returns a promise for that relationship', function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; var Seat = DS.Model.extend({ person: DS.belongsTo('person', { async: false }) @@ -391,14 +393,14 @@ test('A record with an async belongsTo relationship always returns a promise for // this assertion fails too // ok(seat.get('person') === person, 'parent relationship should be populated'); seat.set('person', person); - ok(person.get('seat').then, 'seat should be a PromiseObject'); + assert.ok(person.get('seat').then, 'seat should be a PromiseObject'); }); }); }); }); -test("A record with an async belongsTo relationship returning null should resolve null", function() { - expect(1); +test("A record with an async belongsTo relationship returning null should resolve null", function(assert) { + assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; var Group = DS.Model.extend({ @@ -439,12 +441,12 @@ test("A record with an async belongsTo relationship returning null should resolv env.store.findRecord('person', '1').then(async(function(person) { return person.get('group'); })).then(async(function(group) { - ok(group === null, "group should be null"); + assert.ok(group === null, "group should be null"); })); }); -test("A record can be created with a resolved belongsTo promise", function() { - expect(1); +test("A record can be created with a resolved belongsTo promise", function(assert) { + assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; var Group = DS.Model.extend({ @@ -473,12 +475,12 @@ test("A record can be created with a resolved belongsTo promise", function() { var person = env.store.createRecord('person', { group: groupPromise }); - equal(person.get('group.content'), group); + assert.equal(person.get('group.content'), group); })); }); -test("polymorphic belongsTo type-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled", function() { - expect(1); +test("polymorphic belongsTo type-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled", function(assert) { + assert.expect(1); var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; Ember.MODEL_FACTORY_INJECTIONS = true; @@ -490,15 +492,15 @@ test("polymorphic belongsTo type-checks check the superclass when MODEL_FACTORY_ igor.set('favouriteMessage', post); - equal(igor.get('favouriteMessage.title'), "Igor's unimaginative blog post"); + assert.equal(igor.get('favouriteMessage.title'), "Igor's unimaginative blog post"); }); } finally { Ember.MODEL_FACTORY_INJECTIONS = injectionValue; } }); -test("the subclass in a polymorphic belongsTo relationship is an instanceof its superclass", function() { - expect(1); +test("the subclass in a polymorphic belongsTo relationship is an instanceof its superclass", function(assert) { + assert.expect(1); var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; Ember.MODEL_FACTORY_INJECTIONS = true; @@ -507,7 +509,7 @@ test("the subclass in a polymorphic belongsTo relationship is an instanceof its run(function () { var message = env.store.createRecord('message', { id: 1 }); var comment = env.store.createRecord('comment', { id: 2, message: message }); - ok(comment instanceof Message, 'a comment is an instance of a message'); + assert.ok(comment instanceof Message, 'a comment is an instance of a message'); }); } finally { @@ -515,7 +517,7 @@ test("the subclass in a polymorphic belongsTo relationship is an instanceof its } }); -test("relationshipsByName does not cache a factory", function() { +test("relationshipsByName does not cache a factory", function(assert) { // The model is loaded up via a container. It has relationshipsByName // called on it. @@ -546,11 +548,11 @@ test("relationshipsByName does not cache a factory", function() { // And the model is lookup up internally via the relationship type var messageModelFromRelationType = store.modelFor(messageType); - equal(messageModelFromRelationType, messageModelFromStore, + assert.equal(messageModelFromRelationType, messageModelFromStore, "model factory based on relationship type matches the model based on store.modelFor"); }); -test("relationshipsByName is cached in production", function() { +test("relationshipsByName is cached in production", function(assert) { var model = store.modelFor('user'); var oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it @@ -560,15 +562,15 @@ test("relationshipsByName is cached in production", function() { relationshipsByName._cacheable = true; Ember.testing = false; try { - equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached'); - equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached'); + assert.equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached'); + assert.equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached'); } finally { Ember.testing = oldTesting; relationshipsByName._cacheable = oldCacheable; } }); -test("relatedTypes is cached in production", function() { +test("relatedTypes is cached in production", function(assert) { var model = store.modelFor('user'); var oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it @@ -578,15 +580,15 @@ test("relatedTypes is cached in production", function() { relatedTypes._cacheable = true; Ember.testing = false; try { - equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached'); - equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached'); + assert.equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached'); + assert.equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached'); } finally { Ember.testing = oldTesting; relatedTypes._cacheable = oldCacheable; } }); -test("relationships is cached in production", function() { +test("relationships is cached in production", function(assert) { var model = store.modelFor('user'); var oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it @@ -596,16 +598,16 @@ test("relationships is cached in production", function() { relationships._cacheable = true; Ember.testing = false; try { - equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached'); - equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached'); + assert.equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached'); + assert.equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached'); } finally { Ember.testing = oldTesting; relationships._cacheable = oldCacheable; } }); -test("relationship changes shouldn’t cause async fetches", function() { - expect(2); +test("relationship changes shouldn’t cause async fetches", function(assert) { + assert.expect(2); /* Scenario: * --------- @@ -670,20 +672,20 @@ test("relationship changes shouldn’t cause async fetches", function() { }); env.adapter.deleteRecord = function(store, type, snapshot) { - ok(snapshot.record instanceof type); - equal(snapshot.id, 1, 'should first comment'); + assert.ok(snapshot.record instanceof type); + assert.equal(snapshot.id, 1, 'should first comment'); return snapshot.record.toJSON({ includeId: true }); }; env.adapter.findMany = function(store, type, ids, snapshots) { - ok(false, 'should not need to findMay more comments, but attempted to anyways'); + assert.ok(false, 'should not need to findMay more comments, but attempted to anyways'); }; run(comment, 'destroyRecord'); }); -test("Destroying a record with an unloaded aync belongsTo association does not fetch the record", function() { - expect(2); +test("Destroying a record with an unloaded aync belongsTo association does not fetch the record", function(assert) { + assert.expect(2); var post; env.store.modelFor('message').reopen({ @@ -721,8 +723,8 @@ test("Destroying a record with an unloaded aync belongsTo association does not f }; env.adapter.deleteRecord = function(store, type, snapshot) { - ok(snapshot.record instanceof type); - equal(snapshot.id, 1, 'should first post'); + assert.ok(snapshot.record instanceof type); + assert.equal(snapshot.id, 1, 'should first post'); return { id: '1', title: null, @@ -734,7 +736,7 @@ test("Destroying a record with an unloaded aync belongsTo association does not f run(post, 'destroyRecord'); }); -test("A sync belongsTo errors out if the record is unlaoded", function() { +test("A sync belongsTo errors out if the record is unlaoded", function(assert) { var message; run(function() { message = env.store.push({ @@ -759,7 +761,7 @@ test("A sync belongsTo errors out if the record is unlaoded", function() { }, /You looked up the 'user' relationship on a 'message' with id 1 but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async \(`DS.belongsTo\({ async: true }\)`\)/); }); -test("Rollbacking attributes for a deleted record restores implicit relationship - async", function () { +test("Rollbacking attributes for a deleted record restores implicit relationship - async", function(assert) { Book.reopen({ author: DS.belongsTo('author', { async: true }) }); @@ -797,12 +799,12 @@ test("Rollbacking attributes for a deleted record restores implicit relationship author.deleteRecord(); author.rollbackAttributes(); book.get('author').then(function(fetchedAuthor) { - equal(fetchedAuthor, author, 'Book has an author after rollback attributes'); + assert.equal(fetchedAuthor, author, 'Book has an author after rollback attributes'); }); }); }); -test("Rollbacking attributes for a deleted record restores implicit relationship - sync", function () { +test("Rollbacking attributes for a deleted record restores implicit relationship - sync", function(assert) { var book, author; run(function() { book = env.store.push({ @@ -837,11 +839,11 @@ test("Rollbacking attributes for a deleted record restores implicit relationship author.deleteRecord(); author.rollbackAttributes(); }); - equal(book.get('author'), author, 'Book has an author after rollback attributes'); + assert.equal(book.get('author'), author, 'Book has an author after rollback attributes'); }); -test("Passing a model as type to belongsTo should not work", function () { - expect(1); +test("Passing a model as type to belongsTo should not work", function(assert) { + assert.expect(1); expectAssertion(function() { User = DS.Model.extend(); @@ -852,8 +854,8 @@ test("Passing a model as type to belongsTo should not work", function () { }, /The first argument to DS.belongsTo must be a string/); }); -test("belongsTo hasData async loaded", function () { - expect(1); +test("belongsTo hasData async loaded", function(assert) { + assert.expect(1); Book.reopen({ author: belongsTo('author', { async: true }) @@ -866,13 +868,13 @@ test("belongsTo hasData async loaded", function () { run(function() { store.findRecord('book', 1).then(function(book) { var relationship = book._internalModel._relationships.get('author'); - equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasData, true, 'relationship has data'); }); }); }); -test("belongsTo hasData sync loaded", function () { - expect(1); +test("belongsTo hasData sync loaded", function(assert) { + assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: 'The Greatest Book', author: 2 }); @@ -881,13 +883,13 @@ test("belongsTo hasData sync loaded", function () { run(function() { store.findRecord('book', 1).then(function(book) { var relationship = book._internalModel._relationships.get('author'); - equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasData, true, 'relationship has data'); }); }); }); -test("belongsTo hasData async not loaded", function () { - expect(1); +test("belongsTo hasData async not loaded", function(assert) { + assert.expect(1); Book.reopen({ author: belongsTo('author', { async: true }) @@ -900,13 +902,13 @@ test("belongsTo hasData async not loaded", function () { run(function() { store.findRecord('book', 1).then(function(book) { var relationship = book._internalModel._relationships.get('author'); - equal(relationship.hasData, false, 'relationship does not have data'); + assert.equal(relationship.hasData, false, 'relationship does not have data'); }); }); }); -test("belongsTo hasData sync not loaded", function () { - expect(1); +test("belongsTo hasData sync not loaded", function(assert) { + assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: 'The Greatest Book' }); @@ -915,13 +917,13 @@ test("belongsTo hasData sync not loaded", function () { run(function() { store.findRecord('book', 1).then(function(book) { var relationship = book._internalModel._relationships.get('author'); - equal(relationship.hasData, false, 'relationship does not have data'); + assert.equal(relationship.hasData, false, 'relationship does not have data'); }); }); }); -test("belongsTo hasData async created", function () { - expect(1); +test("belongsTo hasData async created", function(assert) { + assert.expect(1); Book.reopen({ author: belongsTo('author', { async: true }) @@ -930,21 +932,21 @@ test("belongsTo hasData async created", function () { run(function() { var book = store.createRecord('book', { name: 'The Greatest Book' }); var relationship = book._internalModel._relationships.get('author'); - equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasData, true, 'relationship has data'); }); }); -test("belongsTo hasData sync created", function () { - expect(1); +test("belongsTo hasData sync created", function(assert) { + assert.expect(1); run(function() { var book = store.createRecord('book', { name: 'The Greatest Book' }); var relationship = book._internalModel._relationships.get('author'); - equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasData, true, 'relationship has data'); }); }); -test("Model's belongsTo relationship should not be created during model creation", function () { +test("Model's belongsTo relationship should not be created during model creation", function(assert) { var user; run(function () { user = env.store.push({ @@ -954,11 +956,11 @@ test("Model's belongsTo relationship should not be created during model creation } }); - ok(!user._internalModel._relationships.has('favouriteMessage'), 'Newly created record should not have relationships'); + assert.ok(!user._internalModel._relationships.has('favouriteMessage'), 'Newly created record should not have relationships'); }); }); -test("Model's belongsTo relationship should be created during model creation if relationship passed in constructor", function () { +test("Model's belongsTo relationship should be created during model creation if relationship passed in constructor", function(assert) { var user, message; run(function () { message = env.store.createRecord('message'); @@ -966,39 +968,39 @@ test("Model's belongsTo relationship should be created during model creation if name: 'John Doe', favouriteMessage: message }); - ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); + assert.ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); }); }); -test("Model's belongsTo relationship should be created during 'set' method", function () { +test("Model's belongsTo relationship should be created during 'set' method", function(assert) { var user, message; run(function () { message = env.store.createRecord('message'); user = env.store.createRecord('user'); user.set('favouriteMessage', message); - ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); + assert.ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); }); }); -test("Model's belongsTo relationship should be created during 'get' method", function () { +test("Model's belongsTo relationship should be created during 'get' method", function(assert) { var user; run(function () { user = env.store.createRecord('user'); user.get('favouriteMessage'); - ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); + assert.ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); }); }); -test("Related link should be fetched when no local data is present", function() { - expect(3); +test("Related link should be fetched when no local data is present", function(assert) { + assert.expect(3); Book.reopen({ author: DS.belongsTo('author', { async: true }) }); env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { - equal(url, 'author', 'url is correct'); - ok(true, "The adapter's findBelongsTo method should be called"); + assert.equal(url, 'author', 'url is correct'); + assert.ok(true, "The adapter's findBelongsTo method should be called"); return Ember.RSVP.resolve( { id: 1, name: 'This is author' } ); @@ -1019,20 +1021,20 @@ test("Related link should be fetched when no local data is present", function() } }); book.get('author').then((author) => { - equal(author.get('name'), 'This is author', 'author name is correct'); + assert.equal(author.get('name'), 'This is author', 'author name is correct'); }); }); }); -test("Local data should take precedence over related link", function() { - expect(1); +test("Local data should take precedence over related link", function(assert) { + assert.expect(1); Book.reopen({ author: DS.belongsTo('author', { async: true }) }); env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { - ok(false, "The adapter's findBelongsTo method should not be called"); + assert.ok(false, "The adapter's findBelongsTo method should not be called"); }; env.adapter.findRecord = function(store, type, id, snapshot) { @@ -1055,28 +1057,28 @@ test("Local data should take precedence over related link", function() { } }); book.get('author').then((author) => { - equal(author.get('name'), 'This is author', 'author name is correct'); + assert.equal(author.get('name'), 'This is author', 'author name is correct'); }); }); }); -test("Updated related link should take precedence over local data", function() { - expect(3); +test("Updated related link should take precedence over local data", function(assert) { + assert.expect(3); Book.reopen({ author: DS.belongsTo('author', { async: true }) }); env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { - equal(url, 'author-updated-link', 'url is correct'); - ok(true, "The adapter's findBelongsTo method should be called"); + assert.equal(url, 'author-updated-link', 'url is correct'); + assert.ok(true, "The adapter's findBelongsTo method should be called"); return Ember.RSVP.resolve( { id: 1, name: 'This is author' } ); }; env.adapter.findRecord = function(store, type, id, snapshot) { - ok(false, "The adapter's findRecord method should not be called"); + assert.ok(false, "The adapter's findRecord method should not be called"); }; run(function() { @@ -1110,7 +1112,7 @@ test("Updated related link should take precedence over local data", function() { }); book.get('author').then((author) => { - equal(author.get('name'), 'This is author', 'author name is correct'); + assert.equal(author.get('name'), 'This is author', 'author name is correct'); }); }); }); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index a8cda0451f1..0df146558de 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, User, Contact, Email, Phone, Message, Post, Comment; @@ -17,7 +19,7 @@ function stringify(string) { } module("integration/relationships/has_many - Has-Many Relationships", { - setup: function() { + beforeEach: function() { User = DS.Model.extend({ name: attr('string'), messages: hasMany('message', { polymorphic: true, async: false }), @@ -88,16 +90,16 @@ module("integration/relationships/has_many - Has-Many Relationships", { store = env.store; }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); -test("When a hasMany relationship is accessed, the adapter's findMany method should not be called if all the records in the relationship are already loaded", function() { - expect(0); +test("When a hasMany relationship is accessed, the adapter's findMany method should not be called if all the records in the relationship are already loaded", function(assert) { + assert.expect(0); env.adapter.findMany = function(store, type, ids, snapshots) { - ok(false, "The adapter's find method should not be called"); + assert.ok(false, "The adapter's find method should not be called"); }; env.adapter.findRecord = function(store, type, ids, snapshots) { @@ -128,12 +130,12 @@ test("When a hasMany relationship is accessed, the adapter's findMany method sho }); }); -test("adapter.findMany only gets unique IDs even if duplicate IDs are present in the hasMany relationship", function() { - expect(2); +test("adapter.findMany only gets unique IDs even if duplicate IDs are present in the hasMany relationship", function(assert) { + assert.expect(2); env.adapter.findMany = function(store, type, ids, snapshots) { - equal(type, Chapter, 'type passed to adapter.findMany is correct'); - deepEqual(ids, ['2', '3'], 'ids passed to adapter.findMany are unique'); + assert.equal(type, Chapter, 'type passed to adapter.findMany is correct'); + assert.deepEqual(ids, ['2', '3'], 'ids passed to adapter.findMany are unique'); return Ember.RSVP.resolve([ { id: 2, title: 'Chapter One' }, @@ -171,7 +173,7 @@ test("adapter.findMany only gets unique IDs even if duplicate IDs are present in // relationship as a internalModel that it can fetch lazily. The most // common use case of this is to provide a URL to a collection that // is loaded later. -test("A serializer can materialize a hasMany as an opaque token that can be lazily fetched via the adapter's findHasMany hook", function() { +test("A serializer can materialize a hasMany as an opaque token that can be lazily fetched via the adapter's findHasMany hook", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -179,8 +181,8 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi // When the store asks the adapter for the record with ID 1, // provide some fake data. env.adapter.findRecord = function(store, type, id, snapshot) { - equal(type, Post, "find type was Post"); - equal(id, "1", "find id was 1"); + assert.equal(type, Post, "find type was Post"); + assert.equal(id, "1", "find id was 1"); return Ember.RSVP.resolve({ id: 1, links: { comments: "/posts/1/comments" } }); }; @@ -190,8 +192,8 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi }; env.adapter.findHasMany = function(store, snapshot, link, relationship) { - equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); - equal(relationship.type, "comment", "relationship was passed correctly"); + assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); + assert.equal(relationship.type, "comment", "relationship was passed correctly"); return Ember.RSVP.resolve([ { id: 1, body: "First" }, @@ -203,15 +205,15 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi env.store.findRecord('post', 1).then(async(function(post) { return post.get('comments'); })).then(async(function(comments) { - equal(comments.get('isLoaded'), true, "comments are loaded"); - equal(comments.get('length'), 2, "comments have 2 length"); - equal(comments.objectAt(0).get('body'), 'First', "comment loaded successfully"); + assert.equal(comments.get('isLoaded'), true, "comments are loaded"); + assert.equal(comments.get('length'), 2, "comments have 2 length"); + assert.equal(comments.objectAt(0).get('body'), 'First', "comment loaded successfully"); })); }); }); -test("Accessing a hasMany backed by a link multiple times triggers only one request", function() { - expect(2); +test("Accessing a hasMany backed by a link multiple times triggers only one request", function(assert) { + assert.expect(2); var count = 0; Post.reopen({ comments: DS.hasMany('comment', { async: true }) @@ -242,7 +244,7 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ env.adapter.findHasMany = function(store, snapshot, link, relationship) { start(); count++; - equal(count, 1, "findHasMany has only been called once"); + assert.equal(count, 1, "findHasMany has only been called once"); stop(); return new Ember.RSVP.Promise(function(resolve, reject) { setTimeout(function() { @@ -276,11 +278,11 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ Ember.RSVP.all([promise1, promise2]).then(function() { start(); }); - equal(promise1.promise, promise2.promise, "Same promise is returned both times"); + assert.equal(promise1.promise, promise2.promise, "Same promise is returned both times"); }); -test("A hasMany backed by a link remains a promise after a record has been added to it", function() { - expect(1); +test("A hasMany backed by a link remains a promise after a record has been added to it", function(assert) { + assert.expect(1); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -327,13 +329,13 @@ test("A hasMany backed by a link remains a promise after a record has been added } }); post.get('comments').then(function() { - ok(true, 'Promise was called'); + assert.ok(true, 'Promise was called'); }); }); }); }); -test("A hasMany updated link should not remove new children", function() { +test("A hasMany updated link should not remove new children", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -360,7 +362,7 @@ test("A hasMany updated link should not remove new children", function() { post.get('comments') .then(function(comments) { - equal(comments.get('length'), 1); + assert.equal(comments.get('length'), 1); return post.save(); }) @@ -368,12 +370,12 @@ test("A hasMany updated link should not remove new children", function() { return post.get('comments'); }) .then(function(comments) { - equal(comments.get('length'), 1); + assert.equal(comments.get('length'), 1); }); }); }); -test("A hasMany updated link should not remove new children when the parent record has children already", function() { +test("A hasMany updated link should not remove new children when the parent record has children already", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -400,7 +402,7 @@ test("A hasMany updated link should not remove new children when the parent reco post.get('comments') .then(function(comments) { - equal(comments.get('length'), 1); + assert.equal(comments.get('length'), 1); return post.save(); }) @@ -408,28 +410,28 @@ test("A hasMany updated link should not remove new children when the parent reco return post.get('comments'); }) .then(function(comments) { - equal(comments.get('length'), 2); + assert.equal(comments.get('length'), 2); }); }); }); -test("A hasMany relationship can be reloaded if it was fetched via a link", function() { +test("A hasMany relationship can be reloaded if it was fetched via a link", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); env.adapter.findRecord = function(store, type, id, snapshot) { - equal(type, Post, "find type was Post"); - equal(id, "1", "find id was 1"); + assert.equal(type, Post, "find type was Post"); + assert.equal(id, "1", "find id was 1"); return Ember.RSVP.resolve({ id: 1, links: { comments: "/posts/1/comments" } }); }; env.adapter.findHasMany = function(store, snapshot, link, relationship) { - equal(relationship.type, 'comment', "findHasMany relationship type was Comment"); - equal(relationship.key, 'comments', "findHasMany relationship key was comments"); - equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); + assert.equal(relationship.type, 'comment', "findHasMany relationship type was Comment"); + assert.equal(relationship.key, 'comments', "findHasMany relationship key was comments"); + assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); return Ember.RSVP.resolve([ { id: 1, body: "First" }, @@ -441,13 +443,13 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func run(env.store, 'findRecord', 'post', 1).then(function(post) { return post.get('comments'); }).then(function(comments) { - equal(comments.get('isLoaded'), true, "comments are loaded"); - equal(comments.get('length'), 2, "comments have 2 length"); + assert.equal(comments.get('isLoaded'), true, "comments are loaded"); + assert.equal(comments.get('length'), 2, "comments have 2 length"); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - equal(relationship.type, 'comment', "findHasMany relationship type was Comment"); - equal(relationship.key, 'comments', "findHasMany relationship key was comments"); - equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); + assert.equal(relationship.type, 'comment', "findHasMany relationship type was Comment"); + assert.equal(relationship.key, 'comments', "findHasMany relationship key was comments"); + assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); return Ember.RSVP.resolve([ { id: 1, body: "First" }, @@ -458,19 +460,19 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func return comments.reload(); }).then(function(newComments) { - equal(newComments.get('length'), 3, "reloaded comments have 3 length"); + assert.equal(newComments.get('length'), 3, "reloaded comments have 3 length"); }); }); }); -test("A sync hasMany relationship can be reloaded if it was fetched via ids", function() { +test("A sync hasMany relationship can be reloaded if it was fetched via ids", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); env.adapter.findRecord = function(store, type, id, snapshot) { - equal(type, Post, "find type was Post"); - equal(id, "1", "find id was 1"); + assert.equal(type, Post, "find type was Post"); + assert.equal(id, "1", "find id was 1"); return Ember.RSVP.resolve({ id: 1, comments: [1, 2] }); }; @@ -494,8 +496,8 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu env.store.findRecord('post', '1').then(function(post) { var comments = post.get('comments'); - equal(comments.get('isLoaded'), true, "comments are loaded"); - equal(comments.get('length'), 2, "comments have a length of 2"); + assert.equal(comments.get('isLoaded'), true, "comments are loaded"); + assert.equal(comments.get('length'), 2, "comments have a length of 2"); env.adapter.findMany = function(store, type, ids, snapshots) { return Ember.RSVP.resolve([ @@ -506,19 +508,19 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu return comments.reload(); }).then(function(newComments) { - equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); + assert.equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); }); }); }); -test("A hasMany relationship can be reloaded if it was fetched via ids", function() { +test("A hasMany relationship can be reloaded if it was fetched via ids", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); env.adapter.findRecord = function(store, type, id, snapshot) { - equal(type, Post, "find type was Post"); - equal(id, "1", "find id was 1"); + assert.equal(type, Post, "find type was Post"); + assert.equal(id, "1", "find id was 1"); return Ember.RSVP.resolve({ id: 1, comments: [1,2] }); }; @@ -534,8 +536,8 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio env.store.findRecord('post', 1).then(function(post) { return post.get('comments'); }).then(function(comments) { - equal(comments.get('isLoaded'), true, "comments are loaded"); - equal(comments.get('length'), 2, "comments have 2 length"); + assert.equal(comments.get('isLoaded'), true, "comments are loaded"); + assert.equal(comments.get('length'), 2, "comments have 2 length"); env.adapter.findMany = function(store, type, ids, snapshots) { return Ember.RSVP.resolve([ @@ -546,19 +548,19 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio return comments.reload(); }).then(function(newComments) { - equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); + assert.equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); }); }); }); -test("A hasMany relationship can be directly reloaded if it was fetched via ids", function() { +test("A hasMany relationship can be directly reloaded if it was fetched via ids", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); env.adapter.findRecord = function(store, type, id, snapshot) { - equal(type, Post, "find type was Post"); - equal(id, "1", "find id was 1"); + assert.equal(type, Post, "find type was Post"); + assert.equal(id, "1", "find id was 1"); return Ember.RSVP.resolve({ id: 1, comments: [1,2] }); }; @@ -573,16 +575,16 @@ test("A hasMany relationship can be directly reloaded if it was fetched via ids" run(function() { env.store.findRecord('post', 1).then(function(post) { return post.get('comments').reload().then(function(comments) { - equal(comments.get('isLoaded'), true, "comments are loaded"); - equal(comments.get('length'), 2, "comments have 2 length"); - equal(comments.get('firstObject.body'), "FirstUpdated", "Record body was correctly updated"); + assert.equal(comments.get('isLoaded'), true, "comments are loaded"); + assert.equal(comments.get('length'), 2, "comments have 2 length"); + assert.equal(comments.get('firstObject.body'), "FirstUpdated", "Record body was correctly updated"); }); }); }); }); -test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loaded", function() { - expect(4); +test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loaded", function(assert) { + assert.expect(4); Post.reopen({ comments: DS.hasMany('comment', { async: true }) @@ -615,18 +617,18 @@ test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loa run(function() { post.get('comments').then(function(comments) { - equal(comments.get('isLoaded'), true, "comments are loaded"); - equal(comments.get('length'), 2, "comments have 2 length"); + assert.equal(comments.get('isLoaded'), true, "comments are loaded"); + assert.equal(comments.get('length'), 2, "comments have 2 length"); var newComment = post.get('comments').createRecord({ body: 'Third' }); - equal(newComment.get('body'), 'Third', "new comment is returned"); - equal(comments.get('length'), 3, "comments have 3 length, including new record"); + assert.equal(newComment.get('body'), 'Third', "new comment is returned"); + assert.equal(comments.get('length'), 3, "comments have 3 length, including new record"); }); }); }); -test("PromiseArray proxies evented methods to its ManyArray", function() { - expect(6); +test("PromiseArray proxies evented methods to its ManyArray", function(assert) { + assert.expect(6); Post.reopen({ comments: DS.hasMany('comment', { async: true }) @@ -660,44 +662,44 @@ test("PromiseArray proxies evented methods to its ManyArray", function() { comments.on('on-event', function() { - ok(true); + assert.ok(true); }); run(function() { comments.trigger('on-event'); }); - equal(comments.has('on-event'), true); + assert.equal(comments.has('on-event'), true); comments.on('off-event', function() { - ok(false); + assert.ok(false); }); comments.off('off-event'); - equal(comments.has('off-event'), false); + assert.equal(comments.has('off-event'), false); comments.one('one-event', function() { - ok(true); + assert.ok(true); }); - equal(comments.has('one-event'), true); + assert.equal(comments.has('one-event'), true); run(function() { comments.trigger('one-event'); }); - equal(comments.has('one-event'), false); + assert.equal(comments.has('one-event'), false); }); -test("An updated `links` value should invalidate a relationship cache", function() { - expect(8); +test("An updated `links` value should invalidate a relationship cache", function(assert) { + assert.expect(8); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - equal(relationship.type, "comment", "relationship was passed correctly"); + assert.equal(relationship.type, "comment", "relationship was passed correctly"); if (link === '/first') { return Ember.RSVP.resolve([ @@ -733,9 +735,9 @@ test("An updated `links` value should invalidate a relationship cache", function run(function() { post.get('comments').then(function(comments) { - equal(comments.get('isLoaded'), true, "comments are loaded"); - equal(comments.get('length'), 2, "comments have 2 length"); - equal(comments.objectAt(0).get('body'), 'First', "comment 1 successfully loaded"); + assert.equal(comments.get('isLoaded'), true, "comments are loaded"); + assert.equal(comments.get('length'), 2, "comments have 2 length"); + assert.equal(comments.objectAt(0).get('body'), 'First', "comment 1 successfully loaded"); env.store.push({ data: { type: 'post', @@ -750,19 +752,19 @@ test("An updated `links` value should invalidate a relationship cache", function } }); post.get('comments').then(function(newComments) { - equal(comments, newComments, "hasMany array was kept the same"); - equal(newComments.get('length'), 3, "comments updated successfully"); - equal(newComments.objectAt(0).get('body'), 'Third', "third comment loaded successfully"); + assert.equal(comments, newComments, "hasMany array was kept the same"); + assert.equal(newComments.get('length'), 3, "comments updated successfully"); + assert.equal(newComments.objectAt(0).get('body'), 'Third', "third comment loaded successfully"); }); }); }); }); -test("When a polymorphic hasMany relationship is accessed, the adapter's findMany method should not be called if all the records in the relationship are already loaded", function() { - expect(1); +test("When a polymorphic hasMany relationship is accessed, the adapter's findMany method should not be called if all the records in the relationship are already loaded", function(assert) { + assert.expect(1); env.adapter.findMany = function(store, type, ids, snapshots) { - ok(false, "The adapter's find method should not be called"); + assert.ok(false, "The adapter's find method should not be called"); }; env.adapter.findRecord = function(store, type, ids, snapshots) { @@ -796,12 +798,12 @@ test("When a polymorphic hasMany relationship is accessed, the adapter's findMan run(function() { env.store.findRecord('user', 1).then(function(user) { var messages = user.get('messages'); - equal(messages.get('length'), 2, "The messages are correctly loaded"); + assert.equal(messages.get('length'), 2, "The messages are correctly loaded"); }); }); }); -test("When a polymorphic hasMany relationship is accessed, the store can call multiple adapters' findMany or find methods if the records are not loaded", function() { +test("When a polymorphic hasMany relationship is accessed, the store can call multiple adapters' findMany or find methods if the records are not loaded", function(assert) { User.reopen({ messages: hasMany('message', { polymorphic: true, async: true }) }); @@ -835,13 +837,13 @@ test("When a polymorphic hasMany relationship is accessed, the store can call mu env.store.findRecord('user', 1).then(function(user) { return user.get('messages'); }).then(function(messages) { - equal(messages.get('length'), 2, "The messages are correctly loaded"); + assert.equal(messages.get('length'), 2, "The messages are correctly loaded"); }); }); }); -test("polymorphic hasMany type-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled", function() { - expect(1); +test("polymorphic hasMany type-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled", function(assert) { + assert.expect(1); var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; Ember.MODEL_FACTORY_INJECTIONS = true; @@ -853,7 +855,7 @@ test("polymorphic hasMany type-checks check the superclass when MODEL_FACTORY_IN igor.get('messages').addObject(comment); - equal(igor.get('messages.firstObject.body'), "Well I thought the title was fine"); + assert.equal(igor.get('messages.firstObject.body'), "Well I thought the title was fine"); }); } finally { Ember.MODEL_FACTORY_INJECTIONS = injectionValue; @@ -862,8 +864,8 @@ test("polymorphic hasMany type-checks check the superclass when MODEL_FACTORY_IN -test("Type can be inferred from the key of a hasMany relationship", function() { - expect(1); +test("Type can be inferred from the key of a hasMany relationship", function(assert) { + assert.expect(1); env.adapter.findRecord = function(store, type, ids, snapshots) { return { id: 1, contacts: [1] }; @@ -892,13 +894,13 @@ test("Type can be inferred from the key of a hasMany relationship", function() { env.store.findRecord('user', 1).then(function(user) { return user.get('contacts'); }).then(function(contacts) { - equal(contacts.get('length'), 1, "The contacts relationship is correctly set up"); + assert.equal(contacts.get('length'), 1, "The contacts relationship is correctly set up"); }); }); }); -test("Type can be inferred from the key of an async hasMany relationship", function() { - expect(1); +test("Type can be inferred from the key of an async hasMany relationship", function(assert) { + assert.expect(1); User.reopen({ contacts: DS.hasMany({ async: true }) @@ -931,12 +933,12 @@ test("Type can be inferred from the key of an async hasMany relationship", funct env.store.findRecord('user', 1).then(function(user) { return user.get('contacts'); }).then(function(contacts) { - equal(contacts.get('length'), 1, "The contacts relationship is correctly set up"); + assert.equal(contacts.get('length'), 1, "The contacts relationship is correctly set up"); }); }); }); -test("Polymorphic relationships work with a hasMany whose type is inferred", function() { +test("Polymorphic relationships work with a hasMany whose type is inferred", function(assert) { User.reopen({ contacts: DS.hasMany({ polymorphic: true, async: false }) }); @@ -945,7 +947,7 @@ test("Polymorphic relationships work with a hasMany whose type is inferred", fun return { id: 1 }; }; - expect(1); + assert.expect(1); run(function() { env.store.push({ data: { @@ -973,13 +975,13 @@ test("Polymorphic relationships work with a hasMany whose type is inferred", fun env.store.findRecord('user', 1).then(function(user) { return user.get('contacts'); }).then(function(contacts) { - equal(contacts.get('length'), 2, "The contacts relationship is correctly set up"); + assert.equal(contacts.get('length'), 2, "The contacts relationship is correctly set up"); }); }); }); -test("Polymorphic relationships with a hasMany is set up correctly on both sides", function() { - expect(2); +test("Polymorphic relationships with a hasMany is set up correctly on both sides", function(assert) { + assert.expect(2); Contact.reopen({ posts: DS.hasMany('post', { async: false }) @@ -997,11 +999,11 @@ test("Polymorphic relationships with a hasMany is set up correctly on both sides }); }); - equal(post.get('contact'), email, 'The polymorphic belongsTo is set up correctly'); - equal(get(email, 'posts.length'), 1, "The inverse has many is set up correctly on the email side."); + assert.equal(post.get('contact'), email, 'The polymorphic belongsTo is set up correctly'); + assert.equal(get(email, 'posts.length'), 1, "The inverse has many is set up correctly on the email side."); }); -test("A record can't be created from a polymorphic hasMany relationship", function() { +test("A record can't be created from a polymorphic hasMany relationship", function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { env.store.push({ @@ -1028,8 +1030,8 @@ test("A record can't be created from a polymorphic hasMany relationship", functi }); }); -test("Only records of the same type can be added to a monomorphic hasMany relationship", function() { - expect(1); +test("Only records of the same type can be added to a monomorphic hasMany relationship", function(assert) { + assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { env.store.push({ @@ -1060,8 +1062,8 @@ test("Only records of the same type can be added to a monomorphic hasMany relati }); }); -test("Only records of the same base type can be added to a polymorphic hasMany relationship", function() { - expect(2); +test("Only records of the same base type can be added to a polymorphic hasMany relationship", function(assert) { + assert.expect(2); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { env.store.push({ @@ -1112,7 +1114,7 @@ test("Only records of the same base type can be added to a polymorphic hasMany r }).then(function(records) { records.messages.pushObject(records.post); records.messages.pushObject(records.comment); - equal(records.messages.get('length'), 2, "The messages are correctly added"); + assert.equal(records.messages.get('length'), 2, "The messages are correctly added"); expectAssertion(function() { records.messages.pushObject(records.anotherUser); @@ -1121,8 +1123,8 @@ test("Only records of the same base type can be added to a polymorphic hasMany r }); }); -test("A record can be removed from a polymorphic association", function() { - expect(4); +test("A record can be removed from a polymorphic association", function(assert) { + assert.expect(4); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { env.store.push({ @@ -1155,19 +1157,19 @@ test("A record can be removed from a polymorphic association", function() { records.messages = records.user.get('messages'); return Ember.RSVP.hash(records); }).then(function(records) { - equal(records.messages.get('length'), 1, "The user has 1 message"); + assert.equal(records.messages.get('length'), 1, "The user has 1 message"); var removedObject = records.messages.popObject(); - equal(removedObject, records.comment, "The message is correctly removed"); - equal(records.messages.get('length'), 0, "The user does not have any messages"); - equal(records.messages.objectAt(0), null, "No messages can't be fetched"); + assert.equal(removedObject, records.comment, "The message is correctly removed"); + assert.equal(records.messages.get('length'), 0, "The user does not have any messages"); + assert.equal(records.messages.objectAt(0), null, "No messages can't be fetched"); }); }); }); -test("When a record is created on the client, its hasMany arrays should be in a loaded state", function() { - expect(3); +test("When a record is created on the client, its hasMany arrays should be in a loaded state", function(assert) { + assert.expect(3); var post; @@ -1175,19 +1177,19 @@ test("When a record is created on the client, its hasMany arrays should be in a post = env.store.createRecord('post'); }); - ok(get(post, 'isLoaded'), "The post should have isLoaded flag"); + assert.ok(get(post, 'isLoaded'), "The post should have isLoaded flag"); var comments; run(function() { comments = get(post, 'comments'); }); - equal(get(comments, 'length'), 0, "The comments should be an empty array"); + assert.equal(get(comments, 'length'), 0, "The comments should be an empty array"); - ok(get(comments, 'isLoaded'), "The comments should have isLoaded flag"); + assert.ok(get(comments, 'isLoaded'), "The comments should have isLoaded flag"); }); -test("When a record is created on the client, its async hasMany arrays should be in a loaded state", function() { - expect(4); +test("When a record is created on the client, its async hasMany arrays should be in a loaded state", function(assert) { + assert.expect(4); Post.reopen({ comments: DS.hasMany('comment', { async: true }) @@ -1197,19 +1199,19 @@ test("When a record is created on the client, its async hasMany arrays should be return env.store.createRecord('post'); }); - ok(get(post, 'isLoaded'), "The post should have isLoaded flag"); + assert.ok(get(post, 'isLoaded'), "The post should have isLoaded flag"); run(function() { get(post, 'comments').then(function(comments) { - ok(true, "Comments array successfully resolves"); - equal(get(comments, 'length'), 0, "The comments should be an empty array"); - ok(get(comments, 'isLoaded'), "The comments should have isLoaded flag"); + assert.ok(true, "Comments array successfully resolves"); + assert.equal(get(comments, 'length'), 0, "The comments should be an empty array"); + assert.ok(get(comments, 'isLoaded'), "The comments should have isLoaded flag"); }); }); }); -test("we can set records SYNC HM relationship", function() { - expect(1); +test("we can set records SYNC HM relationship", function(assert) { + assert.expect(1); var post = run(function() { return env.store.createRecord('post'); }); @@ -1231,12 +1233,12 @@ test("we can set records SYNC HM relationship", function() { }); post.set('comments', env.store.peekAll('comment')); }); - equal(get(post, 'comments.length'), 2, "we can set HM relationship"); + assert.equal(get(post, 'comments.length'), 2, "we can set HM relationship"); }); -test("We can set records ASYNC HM relationship", function() { - expect(1); +test("We can set records ASYNC HM relationship", function(assert) { + assert.expect(1); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -1264,12 +1266,12 @@ test("We can set records ASYNC HM relationship", function() { }); post.get('comments').then(async(function(comments) { - equal(comments.get('length') , 2, "we can set async HM relationship"); + assert.equal(comments.get('length') , 2, "we can set async HM relationship"); })); }); -test("When a record is saved, its unsaved hasMany records should be kept", function () { - expect(1); +test("When a record is saved, its unsaved hasMany records should be kept", function(assert) { + assert.expect(1); var post, comment; @@ -1284,10 +1286,10 @@ test("When a record is saved, its unsaved hasMany records should be kept", funct post.save(); }); - equal(get(post, 'comments.length'), 1, "The unsaved comment should be in the post's comments array"); + assert.equal(get(post, 'comments.length'), 1, "The unsaved comment should be in the post's comments array"); }); -test("dual non-async HM <-> BT", function() { +test("dual non-async HM <-> BT", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { inverse: 'post', async: false }) }); @@ -1338,16 +1340,16 @@ test("dual non-async HM <-> BT", function() { var postComments = comment.get('post.comments'); var postCommentsLength = comment.get('post.comments.length'); - deepEqual(post, commentPost, 'expect the new comments post, to be the correct post'); - ok(postComments, "comments should exist"); - equal(postCommentsLength, 2, "comment's post should have a internalModel back to comment"); - ok(postComments && postComments.indexOf(firstComment) !== -1, 'expect to contain first comment'); - ok(postComments && postComments.indexOf(comment) !== -1, 'expected to contain the new comment'); + assert.deepEqual(post, commentPost, 'expect the new comments post, to be the correct post'); + assert.ok(postComments, "comments should exist"); + assert.equal(postCommentsLength, 2, "comment's post should have a internalModel back to comment"); + assert.ok(postComments && postComments.indexOf(firstComment) !== -1, 'expect to contain first comment'); + assert.ok(postComments && postComments.indexOf(comment) !== -1, 'expected to contain the new comment'); }); }); }); -test("When an unloaded record is added to the hasMany, it gets fetched once the hasMany is accessed even if the hasMany has been already fetched", function() { +test("When an unloaded record is added to the hasMany, it gets fetched once the hasMany is accessed even if the hasMany has been already fetched", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -1381,8 +1383,8 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the run(function() { post.get('comments').then(async(function(fetchedComments) { - equal(fetchedComments.get('length'), 2, 'comments fetched successfully'); - equal(fetchedComments.objectAt(0).get('body'), 'first', 'first comment loaded successfully'); + assert.equal(fetchedComments.get('length'), 2, 'comments fetched successfully'); + assert.equal(fetchedComments.objectAt(0).get('body'), 'first', 'first comment loaded successfully'); env.store.push({ data: { type: 'post', @@ -1399,14 +1401,14 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the } }); post.get('comments').then(async(function(newlyFetchedComments) { - equal(newlyFetchedComments.get('length'), 3, 'all three comments fetched successfully'); - equal(newlyFetchedComments.objectAt(2).get('body'), 'third', 'third comment loaded successfully'); + assert.equal(newlyFetchedComments.get('length'), 3, 'all three comments fetched successfully'); + assert.equal(newlyFetchedComments.objectAt(2).get('body'), 'third', 'third comment loaded successfully'); })); })); }); }); -test("A sync hasMany errors out if there are unlaoded records in it", function() { +test("A sync hasMany errors out if there are unlaoded records in it", function(assert) { var post; run(function() { env.store.push({ @@ -1431,7 +1433,7 @@ test("A sync hasMany errors out if there are unlaoded records in it", function() }, /You looked up the 'comments' relationship on a 'post' with id 1 but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async \(`DS.hasMany\({ async: true }\)`\)/); }); -test("If reordered hasMany data has been pushed to the store, the many array reflects the ordering change - sync", function() { +test("If reordered hasMany data has been pushed to the store, the many array reflects the ordering change - sync", function(assert) { var comment1, comment2, comment3, comment4; var post; run(function() { @@ -1474,7 +1476,7 @@ test("If reordered hasMany data has been pushed to the store, the many array ref }); post = env.store.peekRecord('post', 1); }); - deepEqual(post.get('comments').toArray(), [comment1, comment2], 'Initial ordering is correct'); + assert.deepEqual(post.get('comments').toArray(), [comment1, comment2], 'Initial ordering is correct'); run(function() { env.store.push({ @@ -1492,7 +1494,7 @@ test("If reordered hasMany data has been pushed to the store, the many array ref } }); }); - deepEqual(post.get('comments').toArray(), [comment2, comment1], 'Updated ordering is correct'); + assert.deepEqual(post.get('comments').toArray(), [comment2, comment1], 'Updated ordering is correct'); run(function() { env.store.push({ @@ -1509,7 +1511,7 @@ test("If reordered hasMany data has been pushed to the store, the many array ref } }); }); - deepEqual(post.get('comments').toArray(), [comment2], 'Updated ordering is correct'); + assert.deepEqual(post.get('comments').toArray(), [comment2], 'Updated ordering is correct'); run(function() { env.store.push({ @@ -1529,7 +1531,7 @@ test("If reordered hasMany data has been pushed to the store, the many array ref } }); }); - deepEqual(post.get('comments').toArray(), [comment1, comment2, comment3, comment4], 'Updated ordering is correct'); + assert.deepEqual(post.get('comments').toArray(), [comment1, comment2, comment3, comment4], 'Updated ordering is correct'); run(function() { env.store.push({ @@ -1547,7 +1549,7 @@ test("If reordered hasMany data has been pushed to the store, the many array ref } }); }); - deepEqual(post.get('comments').toArray(), [comment4, comment3], 'Updated ordering is correct'); + assert.deepEqual(post.get('comments').toArray(), [comment4, comment3], 'Updated ordering is correct'); run(function() { env.store.push({ @@ -1567,10 +1569,10 @@ test("If reordered hasMany data has been pushed to the store, the many array ref } }); }); - deepEqual(post.get('comments').toArray(), [comment4, comment2, comment3, comment1], 'Updated ordering is correct'); + assert.deepEqual(post.get('comments').toArray(), [comment4, comment2, comment3, comment1], 'Updated ordering is correct'); }); -test("Rollbacking attributes for deleted record restores implicit relationship correctly when the hasMany side has been deleted - async", function () { +test("Rollbacking attributes for deleted record restores implicit relationship correctly when the hasMany side has been deleted - async", function(assert) { var book, chapter; run(function() { env.store.push({ @@ -1605,12 +1607,12 @@ test("Rollbacking attributes for deleted record restores implicit relationship c }); run(function() { book.get('chapters').then(function(fetchedChapters) { - equal(fetchedChapters.objectAt(0), chapter, 'Book has a chapter after rollback attributes'); + assert.equal(fetchedChapters.objectAt(0), chapter, 'Book has a chapter after rollback attributes'); }); }); }); -test("Rollbacking attributes for deleted record restores implicit relationship correctly when the hasMany side has been deleted - sync", function () { +test("Rollbacking attributes for deleted record restores implicit relationship correctly when the hasMany side has been deleted - sync", function(assert) { var book, chapter; run(function() { env.store.push({ @@ -1644,11 +1646,11 @@ test("Rollbacking attributes for deleted record restores implicit relationship c chapter.rollbackAttributes(); }); run(function() { - equal(book.get('chapters.firstObject'), chapter, "Book has a chapter after rollback attributes"); + assert.equal(book.get('chapters.firstObject'), chapter, "Book has a chapter after rollback attributes"); }); }); -test("Rollbacking attributes for deleted record restores implicit relationship correctly when the belongsTo side has been deleted - async", function () { +test("Rollbacking attributes for deleted record restores implicit relationship correctly when the belongsTo side has been deleted - async", function(assert) { Page.reopen({ chapter: DS.belongsTo('chapter', { async: true }) }); @@ -1684,12 +1686,12 @@ test("Rollbacking attributes for deleted record restores implicit relationship c }); run(function() { page.get('chapter').then(function(fetchedChapter) { - equal(fetchedChapter, chapter, 'Page has a chapter after rollback attributes'); + assert.equal(fetchedChapter, chapter, 'Page has a chapter after rollback attributes'); }); }); }); -test("Rollbacking attributes for deleted record restores implicit relationship correctly when the belongsTo side has been deleted - sync", function () { +test("Rollbacking attributes for deleted record restores implicit relationship correctly when the belongsTo side has been deleted - sync", function(assert) { var chapter, page; run(function() { env.store.push({ @@ -1721,12 +1723,12 @@ test("Rollbacking attributes for deleted record restores implicit relationship c chapter.rollbackAttributes(); }); run(function() { - equal(page.get('chapter'), chapter, "Page has a chapter after rollback attributes"); + assert.equal(page.get('chapter'), chapter, "Page has a chapter after rollback attributes"); }); }); -test("ManyArray notifies the array observers and flushes bindings when removing", function () { - expect(2); +test("ManyArray notifies the array observers and flushes bindings when removing", function(assert) { + assert.expect(2); var chapter, page, page2; var observe = false; @@ -1767,12 +1769,12 @@ test("ManyArray notifies the array observers and flushes bindings when removing" chapter.get('pages').addEnumerableObserver(this, { willChange: function(pages, removing, addCount) { if (observe) { - equal(removing[0], page2, 'page2 is passed to willChange'); + assert.equal(removing[0], page2, 'page2 is passed to willChange'); } }, didChange: function(pages, removeCount, adding) { if (observe) { - equal(removeCount, 1, 'removeCount is correct'); + assert.equal(removeCount, 1, 'removeCount is correct'); } } }); @@ -1784,8 +1786,8 @@ test("ManyArray notifies the array observers and flushes bindings when removing" }); }); -test("ManyArray notifies the array observers and flushes bindings when adding", function () { - expect(2); +test("ManyArray notifies the array observers and flushes bindings when adding", function(assert) { + assert.expect(2); var chapter, page, page2; var observe = false; @@ -1825,12 +1827,12 @@ test("ManyArray notifies the array observers and flushes bindings when adding", chapter.get('pages').addEnumerableObserver(this, { willChange: function(pages, removing, addCount) { if (observe) { - equal(addCount, 1, 'addCount is correct'); + assert.equal(addCount, 1, 'addCount is correct'); } }, didChange: function(pages, removeCount, adding) { if (observe) { - equal(adding[0], page2, 'page2 is passed to didChange'); + assert.equal(adding[0], page2, 'page2 is passed to didChange'); } } }); @@ -1842,8 +1844,8 @@ test("ManyArray notifies the array observers and flushes bindings when adding", }); }); -test("Passing a model as type to hasMany should not work", function () { - expect(1); +test("Passing a model as type to hasMany should not work", function(assert) { + assert.expect(1); expectAssertion(function() { User = DS.Model.extend(); @@ -1854,7 +1856,7 @@ test("Passing a model as type to hasMany should not work", function () { }, /The first argument to DS.hasMany must be a string/); }); -test("Relationship.clear removes all records correctly", function() { +test("Relationship.clear removes all records correctly", function(assert) { var post; Comment.reopen({ @@ -1913,13 +1915,13 @@ test("Relationship.clear removes all records correctly", function() { run(function() { post._internalModel._relationships.get('comments').clear(); var comments = Ember.A(env.store.peekAll('comment')); - deepEqual(comments.mapBy('post'), [null, null, null]); + assert.deepEqual(comments.mapBy('post'), [null, null, null]); }); }); -test('unloading a record with associated records does not prevent the store from tearing down', function() { +test('unloading a record with associated records does not prevent the store from tearing down', function(assert) { var post; Comment.reopen({ @@ -1978,14 +1980,14 @@ test('unloading a record with associated records does not prevent the store from run(function() { env.store.destroy(); }); - ok(true, "store destroyed correctly"); + assert.ok(true, "store destroyed correctly"); } catch (error) { - ok(false, "store prevented from being destroyed"); + assert.ok(false, "store prevented from being destroyed"); } }); -test("adding and removing records from hasMany relationship #2666", function() { - expect(4); +test("adding and removing records from hasMany relationship #2666", function(assert) { + assert.expect(4); var Post = DS.Model.extend({ comments: DS.hasMany('comment', { async: true }) @@ -2046,20 +2048,20 @@ test("adding and removing records from hasMany relationship #2666", function() { stop(); env.store.findRecord('post', 1).then(function (post) { var comments = post.get('comments'); - equal(comments.get('length'), 3, "Initial comments count"); + assert.equal(comments.get('length'), 3, "Initial comments count"); // Add comment #4 var comment = env.store.createRecord('comment'); comments.addObject(comment); return comment.save().then(function() { var comments = post.get('comments'); - equal(comments.get('length'), 4, "Comments count after first add"); + assert.equal(comments.get('length'), 4, "Comments count after first add"); // Delete comment #4 return comments.get('lastObject').destroyRecord(); }).then(function() { var comments = post.get('comments'); - equal(comments.get('length'), 3, "Comments count after destroy"); + assert.equal(comments.get('length'), 3, "Comments count after destroy"); // Add another comment #4 var comment = env.store.createRecord('comment'); @@ -2067,15 +2069,15 @@ test("adding and removing records from hasMany relationship #2666", function() { return comment.save(); }).then(function() { var comments = post.get('comments'); - equal(comments.get('length'), 4, "Comments count after second add"); + assert.equal(comments.get('length'), 4, "Comments count after second add"); start(); }); }); }); }); -test("hasMany hasData async loaded", function () { - expect(1); +test("hasMany hasData async loaded", function(assert) { + assert.expect(1); Chapter.reopen({ pages: hasMany('pages', { async: true }) @@ -2088,13 +2090,13 @@ test("hasMany hasData async loaded", function () { run(function() { store.findRecord('chapter', 1).then(function(chapter) { var relationship = chapter._internalModel._relationships.get('pages'); - equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasData, true, 'relationship has data'); }); }); }); -test("hasMany hasData sync loaded", function () { - expect(1); +test("hasMany hasData sync loaded", function(assert) { + assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, title: 'The Story Begins', pages: [2, 3] }); @@ -2103,13 +2105,13 @@ test("hasMany hasData sync loaded", function () { run(function() { store.findRecord('chapter', 1).then(function(chapter) { var relationship = chapter._internalModel._relationships.get('pages'); - equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasData, true, 'relationship has data'); }); }); }); -test("hasMany hasData async not loaded", function () { - expect(1); +test("hasMany hasData async not loaded", function(assert) { + assert.expect(1); Chapter.reopen({ pages: hasMany('pages', { async: true }) @@ -2122,13 +2124,13 @@ test("hasMany hasData async not loaded", function () { run(function() { store.findRecord('chapter', 1).then(function(chapter) { var relationship = chapter._internalModel._relationships.get('pages'); - equal(relationship.hasData, false, 'relationship does not have data'); + assert.equal(relationship.hasData, false, 'relationship does not have data'); }); }); }); -test("hasMany hasData sync not loaded", function () { - expect(1); +test("hasMany hasData sync not loaded", function(assert) { + assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, title: 'The Story Begins' }); @@ -2137,13 +2139,13 @@ test("hasMany hasData sync not loaded", function () { run(function() { store.findRecord('chapter', 1).then(function(chapter) { var relationship = chapter._internalModel._relationships.get('pages'); - equal(relationship.hasData, false, 'relationship does not have data'); + assert.equal(relationship.hasData, false, 'relationship does not have data'); }); }); }); -test("hasMany hasData async created", function () { - expect(1); +test("hasMany hasData async created", function(assert) { + assert.expect(1); Chapter.reopen({ pages: hasMany('pages', { async: true }) @@ -2152,21 +2154,21 @@ test("hasMany hasData async created", function () { run(function() { var chapter = store.createRecord('chapter', { title: 'The Story Begins' }); var relationship = chapter._internalModel._relationships.get('pages'); - equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasData, true, 'relationship has data'); }); }); -test("hasMany hasData sync created", function () { - expect(1); +test("hasMany hasData sync created", function(assert) { + assert.expect(1); run(function() { var chapter = store.createRecord('chapter', { title: 'The Story Begins' }); var relationship = chapter._internalModel._relationships.get('pages'); - equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasData, true, 'relationship has data'); }); }); -test("Model's hasMany relationship should not be created during model creation", function () { +test("Model's hasMany relationship should not be created during model creation", function(assert) { var user; run(function () { env.store.push({ @@ -2176,21 +2178,21 @@ test("Model's hasMany relationship should not be created during model creation", } }); user = env.store.peekRecord('user', 1); - ok(!user._internalModel._relationships.has('messages'), 'Newly created record should not have relationships'); + assert.ok(!user._internalModel._relationships.has('messages'), 'Newly created record should not have relationships'); }); }); -test("Model's belongsTo relationship should be created during 'get' method", function () { +test("Model's belongsTo relationship should be created during 'get' method", function(assert) { var user; run(function () { user = env.store.createRecord('user'); user.get('messages'); - ok(user._internalModel._relationships.has('messages'), "Newly created record with relationships in params passed in its constructor should have relationships"); + assert.ok(user._internalModel._relationships.has('messages'), "Newly created record with relationships in params passed in its constructor should have relationships"); }); }); -test("metadata is accessible when pushed as a meta property for a relationship", function() { - expect(1); +test("metadata is accessible when pushed as a meta property for a relationship", function(assert) { + assert.expect(1); var book; env.adapter.findHasMany = function() { return resolve({}); @@ -2220,12 +2222,12 @@ test("metadata is accessible when pushed as a meta property for a relationship", }); run(function() { - equal(book._internalModel._relationships.get('chapters').meta.where, 'the lefkada sea', 'meta is there'); + assert.equal(book._internalModel._relationships.get('chapters').meta.where, 'the lefkada sea', 'meta is there'); }); }); -test("metadata is accessible when return from a fetchLink", function() { - expect(1); +test("metadata is accessible when return from a fetchLink", function(assert) { + assert.expect(1); env.registry.register('serializer:application', DS.RESTSerializer); env.adapter.findHasMany = function() { @@ -2265,12 +2267,12 @@ test("metadata is accessible when return from a fetchLink", function() { run(function() { book.get('chapters').then(function(chapters) { var meta = chapters.get('meta'); - equal(get(meta, 'foo'), 'bar', 'metadata is available'); + assert.equal(get(meta, 'foo'), 'bar', 'metadata is available'); }); }); }); -test("metadata should be reset between requests", function() { +test("metadata should be reset between requests", function(assert) { var counter = 0; env.registry.register('serializer:application', DS.RESTSerializer); @@ -2285,7 +2287,7 @@ test("metadata should be reset between requests", function() { ] }; - ok(true, 'findHasMany should be called twice'); + assert.ok(true, 'findHasMany should be called twice'); if (counter === 1) { delete data.meta; @@ -2335,26 +2337,26 @@ test("metadata should be reset between requests", function() { run(function() { book1.get('chapters').then(function(chapters) { var meta = chapters.get('meta'); - equal(get(meta, 'foo'), 'bar', 'metadata should available'); + assert.equal(get(meta, 'foo'), 'bar', 'metadata should available'); book2.get('chapters').then(function(chapters) { var meta = chapters.get('meta'); - equal(meta, undefined, 'metadata should not be available'); + assert.equal(meta, undefined, 'metadata should not be available'); }); }); }); }); -test("Related link should be fetched when no local data is present", function() { - expect(3); +test("Related link should be fetched when no local data is present", function(assert) { + assert.expect(3); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); env.adapter.findHasMany = function(store, snapshot, url, relationship) { - equal(url, 'comments', 'url is correct'); - ok(true, "The adapter's findHasMany method should be called"); + assert.equal(url, 'comments', 'url is correct'); + assert.ok(true, "The adapter's findHasMany method should be called"); return Ember.RSVP.resolve([ { id: 1, body: 'This is comment' } ]); @@ -2375,20 +2377,20 @@ test("Related link should be fetched when no local data is present", function() } }); post.get('comments').then((comments) => { - equal(comments.get('firstObject.body'), 'This is comment', 'comment body is correct'); + assert.equal(comments.get('firstObject.body'), 'This is comment', 'comment body is correct'); }); }); }); -test("Local data should take precedence over related link", function() { - expect(1); +test("Local data should take precedence over related link", function(assert) { + assert.expect(1); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); env.adapter.findHasMany = function(store, snapshot, url, relationship) { - ok(false, "The adapter's findHasMany method should not be called"); + assert.ok(false, "The adapter's findHasMany method should not be called"); }; env.adapter.findRecord = function(store, type, id, snapshot) { @@ -2413,28 +2415,28 @@ test("Local data should take precedence over related link", function() { } }); post.get('comments').then((comments) => { - equal(comments.get('firstObject.body'), 'This is comment', 'comment body is correct'); + assert.equal(comments.get('firstObject.body'), 'This is comment', 'comment body is correct'); }); }); }); -test("Updated related link should take precedence over local data", function() { - expect(3); +test("Updated related link should take precedence over local data", function(assert) { + assert.expect(3); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); env.adapter.findHasMany = function(store, snapshot, url, relationship) { - equal(url, 'comments-updated-link', 'url is correct'); - ok(true, "The adapter's findHasMany method should be called"); + assert.equal(url, 'comments-updated-link', 'url is correct'); + assert.ok(true, "The adapter's findHasMany method should be called"); return Ember.RSVP.resolve([ { id: 1, body: 'This is comment' } ]); }; env.adapter.findRecord = function(store, type, id, snapshot) { - ok(false, "The adapter's findRecord method should not be called"); + assert.ok(false, "The adapter's findRecord method should not be called"); }; run(function() { @@ -2470,7 +2472,7 @@ test("Updated related link should take precedence over local data", function() { }); post.get('comments').then((comments) => { - equal(comments.get('firstObject.body'), 'This is comment', 'comment body is correct'); + assert.equal(comments.get('firstObject.body'), 'This is comment', 'comment body is correct'); }); }); }); diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index c32bdaf7d4a..d17dee2f354 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var Post, Comment, Message, User; @@ -7,7 +9,7 @@ var run = Ember.run; module('integration/relationships/inverse_relationships - Inverse Relationships'); -test("When a record is added to a has-many relationship, the inverse belongsTo is determined automatically", function() { +test("When a record is added to a has-many relationship, the inverse belongsTo is determined automatically", function(assert) { Post = DS.Model.extend({ comments: DS.hasMany('comment', { async: false }) }); @@ -25,15 +27,15 @@ test("When a record is added to a has-many relationship, the inverse belongsTo i post = store.createRecord('post'); }); - equal(comment.get('post'), null, "no post has been set on the comment"); + assert.equal(comment.get('post'), null, "no post has been set on the comment"); run(function() { post.get('comments').pushObject(comment); }); - equal(comment.get('post'), post, "post was set on the comment"); + assert.equal(comment.get('post'), post, "post was set on the comment"); }); -test("Inverse relationships can be explicitly nullable", function () { +test("Inverse relationships can be explicitly nullable", function(assert) { User = DS.Model.extend(); Post = DS.Model.extend({ @@ -56,12 +58,12 @@ test("Inverse relationships can be explicitly nullable", function () { post = store.createRecord('post'); }); - equal(user.inverseFor('posts').name, 'participants', 'User.posts inverse is Post.participants'); - equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); - equal(post.inverseFor('participants').name, 'posts', 'Post.participants inverse is User.posts'); + assert.equal(user.inverseFor('posts').name, 'participants', 'User.posts inverse is Post.participants'); + assert.equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); + assert.equal(post.inverseFor('participants').name, 'posts', 'Post.participants inverse is User.posts'); }); -test("When a record is added to a has-many relationship, the inverse belongsTo can be set explicitly", function() { +test("When a record is added to a has-many relationship, the inverse belongsTo can be set explicitly", function(assert) { Post = DS.Model.extend({ comments: DS.hasMany('comment', { inverse: 'redPost', async: false }) }); @@ -82,22 +84,22 @@ test("When a record is added to a has-many relationship, the inverse belongsTo c post = store.createRecord('post'); }); - equal(comment.get('onePost'), null, "onePost has not been set on the comment"); - equal(comment.get('twoPost'), null, "twoPost has not been set on the comment"); - equal(comment.get('redPost'), null, "redPost has not been set on the comment"); - equal(comment.get('bluePost'), null, "bluePost has not been set on the comment"); + assert.equal(comment.get('onePost'), null, "onePost has not been set on the comment"); + assert.equal(comment.get('twoPost'), null, "twoPost has not been set on the comment"); + assert.equal(comment.get('redPost'), null, "redPost has not been set on the comment"); + assert.equal(comment.get('bluePost'), null, "bluePost has not been set on the comment"); run(function() { post.get('comments').pushObject(comment); }); - equal(comment.get('onePost'), null, "onePost has not been set on the comment"); - equal(comment.get('twoPost'), null, "twoPost has not been set on the comment"); - equal(comment.get('redPost'), post, "redPost has been set on the comment"); - equal(comment.get('bluePost'), null, "bluePost has not been set on the comment"); + assert.equal(comment.get('onePost'), null, "onePost has not been set on the comment"); + assert.equal(comment.get('twoPost'), null, "twoPost has not been set on the comment"); + assert.equal(comment.get('redPost'), post, "redPost has been set on the comment"); + assert.equal(comment.get('bluePost'), null, "bluePost has not been set on the comment"); }); -test("When a record's belongsTo relationship is set, it can specify the inverse hasMany to which the new child should be added", function() { +test("When a record's belongsTo relationship is set, it can specify the inverse hasMany to which the new child should be added", function(assert) { Post = DS.Model.extend({ meComments: DS.hasMany('comment', { async: false }), youComments: DS.hasMany('comment', { async: false }), @@ -117,22 +119,22 @@ test("When a record's belongsTo relationship is set, it can specify the inverse post = store.createRecord('post'); }); - equal(post.get('meComments.length'), 0, "meComments has no posts"); - equal(post.get('youComments.length'), 0, "youComments has no posts"); - equal(post.get('everyoneWeKnowComments.length'), 0, "everyoneWeKnowComments has no posts"); + assert.equal(post.get('meComments.length'), 0, "meComments has no posts"); + assert.equal(post.get('youComments.length'), 0, "youComments has no posts"); + assert.equal(post.get('everyoneWeKnowComments.length'), 0, "everyoneWeKnowComments has no posts"); run(function() { comment.set('post', post); }); - equal(comment.get('post'), post, 'The post that was set can be retrieved'); + assert.equal(comment.get('post'), post, 'The post that was set can be retrieved'); - equal(post.get('meComments.length'), 0, "meComments has no posts"); - equal(post.get('youComments.length'), 1, "youComments had the post added"); - equal(post.get('everyoneWeKnowComments.length'), 0, "everyoneWeKnowComments has no posts"); + assert.equal(post.get('meComments.length'), 0, "meComments has no posts"); + assert.equal(post.get('youComments.length'), 1, "youComments had the post added"); + assert.equal(post.get('everyoneWeKnowComments.length'), 0, "everyoneWeKnowComments has no posts"); }); -test("When setting a belongsTo, the OneToOne invariant is respected even when other records have been previously used", function() { +test("When setting a belongsTo, the OneToOne invariant is respected even when other records have been previously used", function(assert) { Post = DS.Model.extend({ bestComment: DS.belongsTo('comment', { async: false }) }); @@ -155,20 +157,20 @@ test("When setting a belongsTo, the OneToOne invariant is respected even when ot post2.set('bestComment', null); }); - equal(comment.get('post'), post); - equal(post.get('bestComment'), comment); - equal(post2.get('bestComment'), null); + assert.equal(comment.get('post'), post); + assert.equal(post.get('bestComment'), comment); + assert.equal(post2.get('bestComment'), null); run(function() { comment.set('post', post2); }); - equal(comment.get('post'), post2); - equal(post.get('bestComment'), null); - equal(post2.get('bestComment'), comment); + assert.equal(comment.get('post'), post2); + assert.equal(post.get('bestComment'), null); + assert.equal(post2.get('bestComment'), comment); }); -test("When setting a belongsTo, the OneToOne invariant is transitive", function() { +test("When setting a belongsTo, the OneToOne invariant is transitive", function(assert) { Post = DS.Model.extend({ bestComment: DS.belongsTo('comment', { async: false }) }); @@ -193,20 +195,20 @@ test("When setting a belongsTo, the OneToOne invariant is transitive", function( comment.set('post', post); }); - equal(comment.get('post'), post); - equal(post.get('bestComment'), comment); - equal(post2.get('bestComment'), null); + assert.equal(comment.get('post'), post); + assert.equal(post.get('bestComment'), comment); + assert.equal(post2.get('bestComment'), null); run(function() { post2.set('bestComment', comment); }); - equal(comment.get('post'), post2); - equal(post.get('bestComment'), null); - equal(post2.get('bestComment'), comment); + assert.equal(comment.get('post'), post2); + assert.equal(post.get('bestComment'), null); + assert.equal(post2.get('bestComment'), comment); }); -test("When setting a belongsTo, the OneToOne invariant is commutative", function() { +test("When setting a belongsTo, the OneToOne invariant is commutative", function(assert) { Post = DS.Model.extend({ bestComment: DS.belongsTo('comment', { async: false }) }); @@ -229,21 +231,21 @@ test("When setting a belongsTo, the OneToOne invariant is commutative", function comment.set('post', post); }); - equal(comment.get('post'), post); - equal(post.get('bestComment'), comment); - equal(comment2.get('post'), null); + assert.equal(comment.get('post'), post); + assert.equal(post.get('bestComment'), comment); + assert.equal(comment2.get('post'), null); run(function() { post.set('bestComment', comment2); }); - equal(comment.get('post'), null); - equal(post.get('bestComment'), comment2); - equal(comment2.get('post'), post); + assert.equal(comment.get('post'), null); + assert.equal(post.get('bestComment'), comment2); + assert.equal(comment2.get('post'), post); }); -test("OneToNone relationship works", function() { - expect(3); +test("OneToNone relationship works", function(assert) { + assert.expect(3); Post = DS.Model.extend({ name: DS.attr('string') }); @@ -265,21 +267,21 @@ test("OneToNone relationship works", function() { run(function() { comment.set('post', post1); }); - equal(comment.get('post'), post1, 'the post is set to the first one'); + assert.equal(comment.get('post'), post1, 'the post is set to the first one'); run(function() { comment.set('post', post2); }); - equal(comment.get('post'), post2, 'the post is set to the second one'); + assert.equal(comment.get('post'), post2, 'the post is set to the second one'); run(function() { comment.set('post', post1); }); - equal(comment.get('post'), post1, 'the post is re-set to the first one'); + assert.equal(comment.get('post'), post1, 'the post is re-set to the first one'); }); -test("When a record is added to or removed from a polymorphic has-many relationship, the inverse belongsTo can be set explicitly", function() { +test("When a record is added to or removed from a polymorphic has-many relationship, the inverse belongsTo can be set explicitly", function(assert) { User = DS.Model.extend({ messages: DS.hasMany('message', { async: false, @@ -306,31 +308,31 @@ test("When a record is added to or removed from a polymorphic has-many relations user = store.createRecord('user'); }); - equal(post.get('oneUser'), null, "oneUser has not been set on the user"); - equal(post.get('twoUser'), null, "twoUser has not been set on the user"); - equal(post.get('redUser'), null, "redUser has not been set on the user"); - equal(post.get('blueUser'), null, "blueUser has not been set on the user"); + assert.equal(post.get('oneUser'), null, "oneUser has not been set on the user"); + assert.equal(post.get('twoUser'), null, "twoUser has not been set on the user"); + assert.equal(post.get('redUser'), null, "redUser has not been set on the user"); + assert.equal(post.get('blueUser'), null, "blueUser has not been set on the user"); run(function() { user.get('messages').pushObject(post); }); - equal(post.get('oneUser'), null, "oneUser has not been set on the user"); - equal(post.get('twoUser'), null, "twoUser has not been set on the user"); - equal(post.get('redUser'), user, "redUser has been set on the user"); - equal(post.get('blueUser'), null, "blueUser has not been set on the user"); + assert.equal(post.get('oneUser'), null, "oneUser has not been set on the user"); + assert.equal(post.get('twoUser'), null, "twoUser has not been set on the user"); + assert.equal(post.get('redUser'), user, "redUser has been set on the user"); + assert.equal(post.get('blueUser'), null, "blueUser has not been set on the user"); run(function() { user.get('messages').popObject(); }); - equal(post.get('oneUser'), null, "oneUser has not been set on the user"); - equal(post.get('twoUser'), null, "twoUser has not been set on the user"); - equal(post.get('redUser'), null, "redUser has bot been set on the user"); - equal(post.get('blueUser'), null, "blueUser has not been set on the user"); + assert.equal(post.get('oneUser'), null, "oneUser has not been set on the user"); + assert.equal(post.get('twoUser'), null, "twoUser has not been set on the user"); + assert.equal(post.get('redUser'), null, "redUser has bot been set on the user"); + assert.equal(post.get('blueUser'), null, "blueUser has not been set on the user"); }); -test("When a record's belongsTo relationship is set, it can specify the inverse polymorphic hasMany to which the new child should be added or removed", function() { +test("When a record's belongsTo relationship is set, it can specify the inverse polymorphic hasMany to which the new child should be added or removed", function(assert) { User = DS.Model.extend({ meMessages: DS.hasMany('message', { polymorphic: true, async: false }), youMessages: DS.hasMany('message', { polymorphic: true, async: false }), @@ -352,28 +354,28 @@ test("When a record's belongsTo relationship is set, it can specify the inverse post = store.createRecord('post'); }); - equal(user.get('meMessages.length'), 0, "meMessages has no posts"); - equal(user.get('youMessages.length'), 0, "youMessages has no posts"); - equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(user.get('meMessages.length'), 0, "meMessages has no posts"); + assert.equal(user.get('youMessages.length'), 0, "youMessages has no posts"); + assert.equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); run(function() { post.set('user', user); }); - equal(user.get('meMessages.length'), 0, "meMessages has no posts"); - equal(user.get('youMessages.length'), 1, "youMessages had the post added"); - equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(user.get('meMessages.length'), 0, "meMessages has no posts"); + assert.equal(user.get('youMessages.length'), 1, "youMessages had the post added"); + assert.equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); run(function() { post.set('user', null); }); - equal(user.get('meMessages.length'), 0, "meMessages has no posts"); - equal(user.get('youMessages.length'), 0, "youMessages has no posts"); - equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(user.get('meMessages.length'), 0, "meMessages has no posts"); + assert.equal(user.get('youMessages.length'), 0, "youMessages has no posts"); + assert.equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); }); -test("When a record's polymorphic belongsTo relationship is set, it can specify the inverse hasMany to which the new child should be added", function() { +test("When a record's polymorphic belongsTo relationship is set, it can specify the inverse hasMany to which the new child should be added", function(assert) { Message = DS.Model.extend({ meMessages: DS.hasMany('comment', { inverse: null, async: false }), youMessages: DS.hasMany('comment', { inverse: 'message', async: false }), @@ -399,28 +401,28 @@ test("When a record's polymorphic belongsTo relationship is set, it can specify post = store.createRecord('post'); }); - equal(post.get('meMessages.length'), 0, "meMessages has no posts"); - equal(post.get('youMessages.length'), 0, "youMessages has no posts"); - equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(post.get('meMessages.length'), 0, "meMessages has no posts"); + assert.equal(post.get('youMessages.length'), 0, "youMessages has no posts"); + assert.equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); run(function() { comment.set('message', post); }); - equal(post.get('meMessages.length'), 0, "meMessages has no posts"); - equal(post.get('youMessages.length'), 1, "youMessages had the post added"); - equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(post.get('meMessages.length'), 0, "meMessages has no posts"); + assert.equal(post.get('youMessages.length'), 1, "youMessages had the post added"); + assert.equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); run(function() { comment.set('message', null); }); - equal(post.get('meMessages.length'), 0, "meMessages has no posts"); - equal(post.get('youMessages.length'), 0, "youMessages has no posts"); - equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(post.get('meMessages.length'), 0, "meMessages has no posts"); + assert.equal(post.get('youMessages.length'), 0, "youMessages has no posts"); + assert.equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); }); -test("Inverse relationships that don't exist throw a nice error for a hasMany", function () { +test("Inverse relationships that don't exist throw a nice error for a hasMany", function(assert) { User = DS.Model.extend(); Comment = DS.Model.extend(); @@ -442,7 +444,7 @@ test("Inverse relationships that don't exist throw a nice error for a hasMany", }, /We found no inverse relationships by the name of 'testPost' on the 'comment' model/); }); -test("Inverse relationships that don't exist throw a nice error for a belongsTo", function () { +test("Inverse relationships that don't exist throw a nice error for a belongsTo", function(assert) { User = DS.Model.extend(); Comment = DS.Model.extend(); diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index ad25817e272..8edba4925e4 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var Account, Topic, User, store, env; @@ -13,7 +15,7 @@ function stringify(string) { } module('integration/relationships/many_to_many_test - ManyToMany relationships', { - setup: function() { + beforeEach: function() { User = DS.Model.extend({ name: attr('string'), topics: hasMany('topic', { async: true }), @@ -48,7 +50,7 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships', store = env.store; }, - teardown: function() { + afterEach: function() { run(function() { env.container.destroy(); }); @@ -59,7 +61,7 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships', Server loading tests */ -test("Loading from one hasMany side reflects on the other hasMany side - async", function () { +test("Loading from one hasMany side reflects on the other hasMany side - async", function(assert) { run(function() { store.push({ data: { @@ -97,12 +99,12 @@ test("Loading from one hasMany side reflects on the other hasMany side - async", run(function() { topic.get('users').then(async(function(fetchedUsers) { - equal(fetchedUsers.get('length'), 1, 'User relationship was set up correctly'); + assert.equal(fetchedUsers.get('length'), 1, 'User relationship was set up correctly'); })); }); }); -test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - sync", function () { +test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - sync", function(assert) { var account; run(function() { account = store.push({ @@ -134,11 +136,11 @@ test("Relationship is available from the belongsTo side even if only loaded from }); run(function() { - equal(account.get('users.length'), 1, 'User relationship was set up correctly'); + assert.equal(account.get('users.length'), 1, 'User relationship was set up correctly'); }); }); -test("Fetching a hasMany where a record was removed reflects on the other hasMany side - async", function () { +test("Fetching a hasMany where a record was removed reflects on the other hasMany side - async", function(assert) { var user, topic; run(function() { user = store.push({ @@ -175,17 +177,17 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan }); run(function() { user.get('topics').then(async(function(fetchedTopics) { - equal(fetchedTopics.get('length'), 0, 'Topics were removed correctly'); - equal(fetchedTopics.objectAt(0), null, "Topics can't be fetched"); + assert.equal(fetchedTopics.get('length'), 0, 'Topics were removed correctly'); + assert.equal(fetchedTopics.objectAt(0), null, "Topics can't be fetched"); topic.get('users').then(async(function(fetchedUsers) { - equal(fetchedUsers.get('length'), 0, 'Users were removed correctly'); - equal(fetchedUsers.objectAt(0), null, "User can't be fetched"); + assert.equal(fetchedUsers.get('length'), 0, 'Users were removed correctly'); + assert.equal(fetchedUsers.objectAt(0), null, "User can't be fetched"); })); })); }); }); -test("Fetching a hasMany where a record was removed reflects on the other hasMany side - async", function () { +test("Fetching a hasMany where a record was removed reflects on the other hasMany side - async", function(assert) { var account, user; run(function() { account = store.push({ @@ -230,16 +232,16 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan }); }); - equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); - equal(account.get('users.length'), 0, 'Users were removed correctly'); + assert.equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); + assert.equal(account.get('users.length'), 0, 'Users were removed correctly'); }); /* Local edits */ -test("Pushing to a hasMany reflects on the other hasMany side - async", function () { - expect(1); +test("Pushing to a hasMany reflects on the other hasMany side - async", function(assert) { + assert.expect(1); var user, topic; run(function() { @@ -272,13 +274,13 @@ test("Pushing to a hasMany reflects on the other hasMany side - async", function topic.get('users').then(async(function(fetchedUsers) { fetchedUsers.pushObject(user); user.get('topics').then(async(function(fetchedTopics) { - equal(fetchedTopics.get('length'), 1, 'User relationship was set up correctly'); + assert.equal(fetchedTopics.get('length'), 1, 'User relationship was set up correctly'); })); })); }); }); -test("Pushing to a hasMany reflects on the other hasMany side - sync", function () { +test("Pushing to a hasMany reflects on the other hasMany side - sync", function(assert) { var account, stanley; run(function() { account = store.push({ @@ -302,10 +304,10 @@ test("Pushing to a hasMany reflects on the other hasMany side - sync", function stanley.get('accounts').pushObject(account); }); - equal(account.get('users.length'), 1, 'User relationship was set up correctly'); + assert.equal(account.get('users.length'), 1, 'User relationship was set up correctly'); }); -test("Removing a record from a hasMany reflects on the other hasMany side - async", function () { +test("Removing a record from a hasMany reflects on the other hasMany side - async", function(assert) { var user, topic; run(function() { user = store.push({ @@ -338,17 +340,17 @@ test("Removing a record from a hasMany reflects on the other hasMany side - asyn run(function() { user.get('topics').then(async(function(fetchedTopics) { - equal(fetchedTopics.get('length'), 1, 'Topics were setup correctly'); + assert.equal(fetchedTopics.get('length'), 1, 'Topics were setup correctly'); fetchedTopics.removeObject(topic); topic.get('users').then(async(function(fetchedUsers) { - equal(fetchedUsers.get('length'), 0, 'Users were removed correctly'); - equal(fetchedUsers.objectAt(0), null, "User can't be fetched"); + assert.equal(fetchedUsers.get('length'), 0, 'Users were removed correctly'); + assert.equal(fetchedUsers.objectAt(0), null, "User can't be fetched"); })); })); }); }); -test("Removing a record from a hasMany reflects on the other hasMany side - sync", function () { +test("Removing a record from a hasMany reflects on the other hasMany side - sync", function(assert) { var account, user; run(function() { account = store.push({ @@ -379,19 +381,19 @@ test("Removing a record from a hasMany reflects on the other hasMany side - sync }); }); - equal(account.get('users.length'), 1, 'Users were setup correctly'); + assert.equal(account.get('users.length'), 1, 'Users were setup correctly'); run(function() { account.get('users').removeObject(user); }); - equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); - equal(account.get('users.length'), 0, 'Users were removed correctly'); + assert.equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); + assert.equal(account.get('users.length'), 0, 'Users were removed correctly'); }); /* Rollback Attributes tests */ -test("Rollbacking attributes for a deleted record that has a ManyToMany relationship works correctly - async", function () { +test("Rollbacking attributes for a deleted record that has a ManyToMany relationship works correctly - async", function(assert) { var user, topic; run(function() { user = store.push({ @@ -428,15 +430,15 @@ test("Rollbacking attributes for a deleted record that has a ManyToMany relation }); run(function() { topic.get('users').then(async(function(fetchedUsers) { - equal(fetchedUsers.get('length'), 1, 'Users are still there'); + assert.equal(fetchedUsers.get('length'), 1, 'Users are still there'); })); user.get('topics').then(async(function(fetchedTopics) { - equal(fetchedTopics.get('length'), 1, 'Topic got rollbacked into the user'); + assert.equal(fetchedTopics.get('length'), 1, 'Topic got rollbacked into the user'); })); }); }); -test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function () { +test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function(assert) { var account, user; run(function() { account = store.push({ @@ -471,11 +473,11 @@ test("Deleting a record that has a hasMany relationship removes it from the othe account.deleteRecord(); account.rollbackAttributes(); }); - equal(account.get('users.length'), 1, 'Users are still there'); - equal(user.get('accounts.length'), 1, 'Account got rolledback correctly into the user'); + assert.equal(account.get('users.length'), 1, 'Users are still there'); + assert.equal(user.get('accounts.length'), 1, 'Account got rolledback correctly into the user'); }); -test("Rollbacking attributes for a created record that has a ManyToMany relationship works correctly - async", function () { +test("Rollbacking attributes for a created record that has a ManyToMany relationship works correctly - async", function(assert) { var user, topic; run(function() { user = store.push({ @@ -495,18 +497,18 @@ test("Rollbacking attributes for a created record that has a ManyToMany relation fetchedTopics.pushObject(topic); topic.rollbackAttributes(); topic.get('users').then(async(function(fetchedUsers) { - equal(fetchedUsers.get('length'), 0, 'Users got removed'); - equal(fetchedUsers.objectAt(0), null, "User can't be fetched"); + assert.equal(fetchedUsers.get('length'), 0, 'Users got removed'); + assert.equal(fetchedUsers.objectAt(0), null, "User can't be fetched"); })); user.get('topics').then(async(function(fetchedTopics) { - equal(fetchedTopics.get('length'), 0, 'Topics got removed'); - equal(fetchedTopics.objectAt(0), null, "Topic can't be fetched"); + assert.equal(fetchedTopics.get('length'), 0, 'Topics got removed'); + assert.equal(fetchedTopics.objectAt(0), null, "Topic can't be fetched"); })); })); }); }); -test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function () { +test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function(assert) { var account, user; run(function() { account = store.push({ @@ -525,12 +527,12 @@ test("Deleting a record that has a hasMany relationship removes it from the othe account.get('users').pushObject(user); user.rollbackAttributes(); }); - equal(account.get('users.length'), 0, 'Users got removed'); - equal(user.get('accounts.length'), undefined, 'Accounts got rolledback correctly'); + assert.equal(account.get('users.length'), 0, 'Users got removed'); + assert.equal(user.get('accounts.length'), undefined, 'Accounts got rolledback correctly'); }); -test("Re-loading a removed record should re add it to the relationship when the removed record is the last one in the relationship", function () { +test("Re-loading a removed record should re add it to the relationship when the removed record is the last one in the relationship", function(assert) { var account, ada, byron; run(function() { account = store.push({ @@ -600,5 +602,5 @@ test("Re-loading a removed record should re add it to the relationship when the }); - equal(account.get('users.length'), 2, 'Accounts were updated correctly'); + assert.equal(account.get('users.length'), 2, 'Accounts were updated correctly'); }); diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index 6d9d6412ae7..cb1ae282aae 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, User, Message, Account; @@ -15,7 +17,7 @@ function stringify(string) { } module('integration/relationships/one_to_many_test - OneToMany relationships', { - setup: function() { + beforeEach: function() { User = DS.Model.extend({ name: attr('string'), messages: hasMany('message', { async: true }), @@ -47,7 +49,7 @@ module('integration/relationships/one_to_many_test - OneToMany relationships', { store = env.store; }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); @@ -56,7 +58,7 @@ module('integration/relationships/one_to_many_test - OneToMany relationships', { Server loading tests */ -test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - async", function () { +test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - async", function(assert) { var user, message; run(function () { user = store.push({ @@ -88,12 +90,12 @@ test("Relationship is available from the belongsTo side even if only loaded from }); run(function() { message.get('user').then(function(fetchedUser) { - equal(fetchedUser, user, 'User relationship was set up correctly'); + assert.equal(fetchedUser, user, 'User relationship was set up correctly'); }); }); }); -test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - sync", function () { +test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - sync", function(assert) { var account, user; run(function () { account = store.push({ @@ -123,10 +125,10 @@ test("Relationship is available from the belongsTo side even if only loaded from } }); }); - equal(account.get('user'), user, 'User relationship was set up correctly'); + assert.equal(account.get('user'), user, 'User relationship was set up correctly'); }); -test("Relationship is available from the hasMany side even if only loaded from the belongsTo side - async", function () { +test("Relationship is available from the hasMany side even if only loaded from the belongsTo side - async", function(assert) { var user, message; run(function () { user = store.push({ @@ -158,12 +160,12 @@ test("Relationship is available from the hasMany side even if only loaded from t }); run(function() { user.get('messages').then(function(fetchedMessages) { - equal(fetchedMessages.objectAt(0), message, 'Messages relationship was set up correctly'); + assert.equal(fetchedMessages.objectAt(0), message, 'Messages relationship was set up correctly'); }); }); }); -test("Relationship is available from the hasMany side even if only loaded from the belongsTo side - sync", function () { +test("Relationship is available from the hasMany side even if only loaded from the belongsTo side - sync", function(assert) { var user, account; run(function () { user = store.push({ @@ -193,10 +195,10 @@ test("Relationship is available from the hasMany side even if only loaded from t } }); }); - equal(user.get('accounts').objectAt(0), account, 'Accounts relationship was set up correctly'); + assert.equal(user.get('accounts').objectAt(0), account, 'Accounts relationship was set up correctly'); }); -test("Fetching a belongsTo that is set to null removes the record from a relationship - async", function () { +test("Fetching a belongsTo that is set to null removes the record from a relationship - async", function(assert) { var user; run(function () { user = store.push({ @@ -253,12 +255,12 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio }); run(function() { user.get('messages').then(function(fetchedMessages) { - equal(get(fetchedMessages, 'length'), 1, 'Messages relationship was set up correctly'); + assert.equal(get(fetchedMessages, 'length'), 1, 'Messages relationship was set up correctly'); }); }); }); -test("Fetching a belongsTo that is set to null removes the record from a relationship - sync", function () { +test("Fetching a belongsTo that is set to null removes the record from a relationship - sync", function(assert) { var account, user; run(function () { account = store.push({ @@ -302,10 +304,10 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio } }); }); - equal(user.get('accounts').objectAt(0), null, 'Account was sucesfully removed'); + assert.equal(user.get('accounts').objectAt(0), null, 'Account was sucesfully removed'); }); -test("Fetching a belongsTo that is not defined does not remove the record from a relationship - async", function () { +test("Fetching a belongsTo that is not defined does not remove the record from a relationship - async", function(assert) { var user; run(function () { user = store.push({ @@ -356,12 +358,12 @@ test("Fetching a belongsTo that is not defined does not remove the record from a }); run(function() { user.get('messages').then(function(fetchedMessages) { - equal(get(fetchedMessages, 'length'), 2, 'Messages relationship was set up correctly'); + assert.equal(get(fetchedMessages, 'length'), 2, 'Messages relationship was set up correctly'); }); }); }); -test("Fetching a belongsTo that is not defined does not remove the record from a relationship - sync", function () { +test("Fetching a belongsTo that is not defined does not remove the record from a relationship - sync", function(assert) { var account, user; run(function () { account = store.push({ @@ -400,10 +402,10 @@ test("Fetching a belongsTo that is not defined does not remove the record from a } }); }); - equal(user.get('accounts').objectAt(0), account, 'Account was sucesfully removed'); + assert.equal(user.get('accounts').objectAt(0), account, 'Account was sucesfully removed'); }); -test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsTo to null - async", function () { +test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsTo to null - async", function(assert) { var user, message, message2; run(function () { user = store.push({ @@ -471,16 +473,16 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT }); run(function() { message.get('user').then(function(fetchedUser) { - equal(fetchedUser, null, 'User was removed correctly'); + assert.equal(fetchedUser, null, 'User was removed correctly'); }); message2.get('user').then(function(fetchedUser) { - equal(fetchedUser, user, 'User was set on the second message'); + assert.equal(fetchedUser, user, 'User was set on the second message'); }); }); }); -test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsTo to null - sync", function () { +test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsTo to null - sync", function(assert) { var account; run(function () { store.push({ @@ -544,10 +546,10 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT } }); }); - equal(account.get('user'), null, 'User was removed correctly'); + assert.equal(account.get('user'), null, 'User was removed correctly'); }); -test("Fetching the hasMany side where the hasMany is undefined does not change the belongsTo side - async", function () { +test("Fetching the hasMany side where the hasMany is undefined does not change the belongsTo side - async", function(assert) { var message, user; run(function () { store.push({ @@ -597,12 +599,12 @@ test("Fetching the hasMany side where the hasMany is undefined does not change t run(function() { message.get('user').then(function(fetchedUser) { - equal(fetchedUser, user, 'User was not removed'); + assert.equal(fetchedUser, user, 'User was not removed'); }); }); }); -test("Fetching the hasMany side where the hasMany is undefined does not change the belongsTo side - sync", function () { +test("Fetching the hasMany side where the hasMany is undefined does not change the belongsTo side - sync", function(assert) { var account, user; run(function () { store.push({ @@ -659,14 +661,14 @@ test("Fetching the hasMany side where the hasMany is undefined does not change t }); }); - equal(account.get('user'), user, 'User was not removed'); + assert.equal(account.get('user'), user, 'User was not removed'); }); /* Local edits */ -test("Pushing to the hasMany reflects the change on the belongsTo side - async", function () { +test("Pushing to the hasMany reflects the change on the belongsTo side - async", function(assert) { var user, message2; run(function () { user = store.push({ @@ -710,13 +712,13 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - async", user.get('messages').then(function(fetchedMessages) { fetchedMessages.pushObject(message2); message2.get('user').then(function(fetchedUser) { - equal(fetchedUser, user, "user got set correctly"); + assert.equal(fetchedUser, user, "user got set correctly"); }); }); }); }); -test("Pushing to the hasMany reflects the change on the belongsTo side - sync", function () { +test("Pushing to the hasMany reflects the change on the belongsTo side - sync", function(assert) { var user, account2; run(function () { user = store.push({ @@ -766,10 +768,10 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - sync", user.get('accounts').pushObject(account2); }); - equal(account2.get('user'), user, 'user got set correctly'); + assert.equal(account2.get('user'), user, 'user got set correctly'); }); -test("Removing from the hasMany side reflects the change on the belongsTo side - async", function () { +test("Removing from the hasMany side reflects the change on the belongsTo side - async", function(assert) { var user, message; run(function () { user = store.push({ @@ -804,13 +806,13 @@ test("Removing from the hasMany side reflects the change on the belongsTo side - user.get('messages').then(function(fetchedMessages) { fetchedMessages.removeObject(message); message.get('user').then(function(fetchedUser) { - equal(fetchedUser, null, "user got removed correctly"); + assert.equal(fetchedUser, null, "user got removed correctly"); }); }); }); }); -test("Removing from the hasMany side reflects the change on the belongsTo side - sync", function () { +test("Removing from the hasMany side reflects the change on the belongsTo side - sync", function(assert) { var user, account; run(function () { user = store.push({ @@ -852,11 +854,11 @@ test("Removing from the hasMany side reflects the change on the belongsTo side - user.get('accounts').removeObject(account); }); - equal(account.get('user'), null, 'user got removed correctly'); + assert.equal(account.get('user'), null, 'user got removed correctly'); }); -test("Pushing to the hasMany side keeps the oneToMany invariant on the belongsTo side - async", function () { - expect(2); +test("Pushing to the hasMany side keeps the oneToMany invariant on the belongsTo side - async", function(assert) { + assert.expect(2); var user, user2, message; run(function () { user = store.push({ @@ -901,17 +903,17 @@ test("Pushing to the hasMany side keeps the oneToMany invariant on the belongsTo fetchedMessages.pushObject(message); message.get('user').then(function(fetchedUser) { - equal(fetchedUser, user2, "user got set correctly"); + assert.equal(fetchedUser, user2, "user got set correctly"); }); user.get('messages').then(function(newFetchedMessages) { - equal(get(newFetchedMessages, 'length'), 0, 'message got removed from the old messages hasMany'); + assert.equal(get(newFetchedMessages, 'length'), 0, 'message got removed from the old messages hasMany'); }); }); }); }); -test("Pushing to the hasMany side keeps the oneToMany invariant - sync", function () { +test("Pushing to the hasMany side keeps the oneToMany invariant - sync", function(assert) { var user, user2, account; run(function () { user = store.push({ @@ -951,13 +953,13 @@ test("Pushing to the hasMany side keeps the oneToMany invariant - sync", functio }); user2.get('accounts').pushObject(account); }); - equal(account.get('user'), user2, 'user got set correctly'); - equal(user.get('accounts.length'), 0, 'the account got removed correctly'); - equal(user2.get('accounts.length'), 1, 'the account got pushed correctly'); + assert.equal(account.get('user'), user2, 'user got set correctly'); + assert.equal(user.get('accounts.length'), 0, 'the account got removed correctly'); + assert.equal(user2.get('accounts.length'), 1, 'the account got pushed correctly'); }); -test("Setting the belongsTo side keeps the oneToMany invariant on the hasMany- async", function () { - expect(2); +test("Setting the belongsTo side keeps the oneToMany invariant on the hasMany- async", function(assert) { + assert.expect(2); var user, user2, message; run(function () { user = store.push({ @@ -1008,17 +1010,17 @@ test("Setting the belongsTo side keeps the oneToMany invariant on the hasMany- a run(function() { user.get('messages').then(function(fetchedMessages) { - equal(get(fetchedMessages, 'length'), 0, 'message got removed from the first user correctly'); + assert.equal(get(fetchedMessages, 'length'), 0, 'message got removed from the first user correctly'); }); }); run(function() { user2.get('messages').then(function(fetchedMessages) { - equal(get(fetchedMessages, 'length'), 1, 'message got added to the second user correctly'); + assert.equal(get(fetchedMessages, 'length'), 1, 'message got added to the second user correctly'); }); }); }); -test("Setting the belongsTo side keeps the oneToMany invariant on the hasMany- sync", function () { +test("Setting the belongsTo side keeps the oneToMany invariant on the hasMany- sync", function(assert) { var user, user2, account; run(function () { user = store.push({ @@ -1066,14 +1068,14 @@ test("Setting the belongsTo side keeps the oneToMany invariant on the hasMany- s }); account.set('user', user2); }); - equal(account.get('user'), user2, 'user got set correctly'); - equal(user.get('accounts.length'), 0, 'the account got removed correctly'); - equal(user2.get('accounts.length'), 1, 'the account got pushed correctly'); + assert.equal(account.get('user'), user2, 'user got set correctly'); + assert.equal(user.get('accounts.length'), 0, 'the account got removed correctly'); + assert.equal(user2.get('accounts.length'), 1, 'the account got pushed correctly'); }); -test("Setting the belongsTo side to null removes the record from the hasMany side - async", function () { - expect(2); +test("Setting the belongsTo side to null removes the record from the hasMany side - async", function(assert) { + assert.expect(2); var user, message; run(function () { user = store.push({ @@ -1114,18 +1116,18 @@ test("Setting the belongsTo side to null removes the record from the hasMany sid }); run(function() { user.get('messages').then(function(fetchedMessages) { - equal(get(fetchedMessages, 'length'), 0, 'message got removed from the user correctly'); + assert.equal(get(fetchedMessages, 'length'), 0, 'message got removed from the user correctly'); }); }); run(function() { message.get('user').then(function(fetchedUser) { - equal(fetchedUser, null, 'user got set to null correctly'); + assert.equal(fetchedUser, null, 'user got set to null correctly'); }); }); }); -test("Setting the belongsTo side to null removes the record from the hasMany side - sync", function () { +test("Setting the belongsTo side to null removes the record from the hasMany side - sync", function(assert) { var user, account; run(function () { user = store.push({ @@ -1165,16 +1167,16 @@ test("Setting the belongsTo side to null removes the record from the hasMany sid account.set('user', null); }); - equal(account.get('user'), null, 'user got set to null correctly'); + assert.equal(account.get('user'), null, 'user got set to null correctly'); - equal(user.get('accounts.length'), 0, 'the account got removed correctly'); + assert.equal(user.get('accounts.length'), 0, 'the account got removed correctly'); }); /* Rollback attributes from deleted state */ -test("Rollbacking attributes of a deleted record works correctly when the hasMany side has been deleted - async", function () { +test("Rollbacking attributes of a deleted record works correctly when the hasMany side has been deleted - async", function(assert) { var user, message; run(function () { user = store.push({ @@ -1210,15 +1212,15 @@ test("Rollbacking attributes of a deleted record works correctly when the hasMan }); run(function() { message.get('user').then(function(fetchedUser) { - equal(fetchedUser, user, 'Message still has the user'); + assert.equal(fetchedUser, user, 'Message still has the user'); }); user.get('messages').then(function(fetchedMessages) { - equal(fetchedMessages.objectAt(0), message, 'User has the message'); + assert.equal(fetchedMessages.objectAt(0), message, 'User has the message'); }); }); }); -test("Rollbacking attributes of a deleted record works correctly when the hasMany side has been deleted - sync", function () { +test("Rollbacking attributes of a deleted record works correctly when the hasMany side has been deleted - sync", function(assert) { var account, user; run(function () { account = store.push({ @@ -1252,11 +1254,11 @@ test("Rollbacking attributes of a deleted record works correctly when the hasMan account.deleteRecord(); account.rollbackAttributes(); }); - equal(user.get('accounts.length'), 1, "Accounts are rolled back"); - equal(account.get('user'), user, 'Account still has the user'); + assert.equal(user.get('accounts.length'), 1, "Accounts are rolled back"); + assert.equal(account.get('user'), user, 'Account still has the user'); }); -test("Rollbacking attributes of deleted record works correctly when the belongsTo side has been deleted - async", function () { +test("Rollbacking attributes of deleted record works correctly when the belongsTo side has been deleted - async", function(assert) { var user, message; run(function () { user = store.push({ @@ -1292,15 +1294,15 @@ test("Rollbacking attributes of deleted record works correctly when the belongsT }); run(function() { message.get('user').then(function(fetchedUser) { - equal(fetchedUser, user, 'Message has the user again'); + assert.equal(fetchedUser, user, 'Message has the user again'); }); user.get('messages').then(function(fetchedMessages) { - equal(fetchedMessages.get('length'), 1, 'User still has the messages'); + assert.equal(fetchedMessages.get('length'), 1, 'User still has the messages'); }); }); }); -test("Rollbacking attributes of a deleted record works correctly when the belongsTo side has been deleted - sync", function () { +test("Rollbacking attributes of a deleted record works correctly when the belongsTo side has been deleted - sync", function(assert) { var account, user; run(function () { account = store.push({ @@ -1334,15 +1336,15 @@ test("Rollbacking attributes of a deleted record works correctly when the belong user.deleteRecord(); user.rollbackAttributes(); }); - equal(user.get('accounts.length'), 1, "User still has the accounts"); - equal(account.get('user'), user, 'Account has the user again'); + assert.equal(user.get('accounts.length'), 1, "User still has the accounts"); + assert.equal(account.get('user'), user, 'Account has the user again'); }); /* Rollback attributes from created state */ -test("Rollbacking attributes of a created record works correctly when the hasMany side has been created - async", function () { +test("Rollbacking attributes of a created record works correctly when the hasMany side has been created - async", function(assert) { var user, message; run(function () { user = store.push({ @@ -1361,16 +1363,16 @@ test("Rollbacking attributes of a created record works correctly when the hasMan run(message, 'rollbackAttributes'); run(function() { message.get('user').then(function(fetchedUser) { - equal(fetchedUser, null, 'Message does not have the user anymore'); + assert.equal(fetchedUser, null, 'Message does not have the user anymore'); }); user.get('messages').then(function(fetchedMessages) { - equal(fetchedMessages.get('length'), 0, message, 'User does not have the message anymore'); - equal(fetchedMessages.get('firstObject'), null, "User message can't be accessed"); + assert.equal(fetchedMessages.get('length'), 0, message, 'User does not have the message anymore'); + assert.equal(fetchedMessages.get('firstObject'), null, "User message can't be accessed"); }); }); }); -test("Rollbacking attributes of a created record works correctly when the hasMany side has been created - sync", function () { +test("Rollbacking attributes of a created record works correctly when the hasMany side has been created - sync", function(assert) { var user, account; run(function () { user = store.push({ @@ -1387,11 +1389,11 @@ test("Rollbacking attributes of a created record works correctly when the hasMan }); }); run(account, 'rollbackAttributes'); - equal(user.get('accounts.length'), 0, "Accounts are rolled back"); - equal(account.get('user'), null, 'Account does not have the user anymore'); + assert.equal(user.get('accounts.length'), 0, "Accounts are rolled back"); + assert.equal(account.get('user'), null, 'Account does not have the user anymore'); }); -test("Rollbacking attributes of a created record works correctly when the belongsTo side has been created - async", function () { +test("Rollbacking attributes of a created record works correctly when the belongsTo side has been created - async", function(assert) { var message, user; run(function () { message = store.push({ @@ -1410,17 +1412,17 @@ test("Rollbacking attributes of a created record works correctly when the belong messages.pushObject(message); user.rollbackAttributes(); message.get('user').then(function(fetchedUser) { - equal(fetchedUser, null, 'Message does not have the user anymore'); + assert.equal(fetchedUser, null, 'Message does not have the user anymore'); }); user.get('messages').then(function(fetchedMessages) { - equal(fetchedMessages.get('length'), 0, 'User does not have the message anymore'); - equal(fetchedMessages.get('firstObject'), null, "User message can't be accessed"); + assert.equal(fetchedMessages.get('length'), 0, 'User does not have the message anymore'); + assert.equal(fetchedMessages.get('firstObject'), null, "User message can't be accessed"); }); }); }); }); -test("Rollbacking attributes of a created record works correctly when the belongsTo side has been created - sync", function () { +test("Rollbacking attributes of a created record works correctly when the belongsTo side has been created - sync", function(assert) { var account, user; run(function () { account = store.push({ @@ -1438,6 +1440,6 @@ test("Rollbacking attributes of a created record works correctly when the belong user.get('accounts').pushObject(account); }); run(user, 'rollbackAttributes'); - equal(user.get('accounts.length'), undefined, "User does not have the account anymore"); - equal(account.get('user'), null, 'Account does not have the user anymore'); + assert.equal(user.get('accounts.length'), undefined, "User does not have the account anymore"); + assert.equal(account.get('user'), null, 'Account does not have the user anymore'); }); diff --git a/tests/integration/relationships/one-to-one-test.js b/tests/integration/relationships/one-to-one-test.js index 4f9ca56d74e..f775709d324 100644 --- a/tests/integration/relationships/one-to-one-test.js +++ b/tests/integration/relationships/one-to-one-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, User, Job; @@ -13,7 +15,7 @@ function stringify(string) { } module('integration/relationships/one_to_one_test - OneToOne relationships', { - setup: function() { + beforeEach: function() { User = DS.Model.extend({ name: attr('string'), bestFriend: belongsTo('user', { async: true, inverse: 'bestFriend' }), @@ -38,7 +40,7 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', { store = env.store; }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); @@ -47,7 +49,7 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', { Server loading tests */ -test("Relationship is available from both sides even if only loaded from one side - async", function() { +test("Relationship is available from both sides even if only loaded from one side - async", function(assert) { var stanley, stanleysFriend; run(function() { stanley = store.push({ @@ -78,13 +80,13 @@ test("Relationship is available from both sides even if only loaded from one sid }); stanleysFriend.get('bestFriend').then(function(fetchedUser) { - equal(fetchedUser, stanley, 'User relationship was set up correctly'); + assert.equal(fetchedUser, stanley, 'User relationship was set up correctly'); }); }); }); -test("Relationship is available from both sides even if only loaded from one side - sync", function() { +test("Relationship is available from both sides even if only loaded from one side - sync", function(assert) { var job, user; run(function() { job = store.push({ @@ -114,10 +116,10 @@ test("Relationship is available from both sides even if only loaded from one sid } }); }); - equal(job.get('user'), user, 'User relationship was set up correctly'); + assert.equal(job.get('user'), user, 'User relationship was set up correctly'); }); -test("Fetching a belongsTo that is set to null removes the record from a relationship - async", function() { +test("Fetching a belongsTo that is set to null removes the record from a relationship - async", function(assert) { var stanleysFriend; run(function() { stanleysFriend = store.push({ @@ -152,13 +154,13 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio } }); stanleysFriend.get('bestFriend').then(function(fetchedUser) { - equal(fetchedUser, null, 'User relationship was removed correctly'); + assert.equal(fetchedUser, null, 'User relationship was removed correctly'); }); }); }); -test("Fetching a belongsTo that is set to null removes the record from a relationship - sync", function() { +test("Fetching a belongsTo that is set to null removes the record from a relationship - sync", function(assert) { var job; run(function() { job = store.push({ @@ -204,12 +206,12 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio } }); }); - equal(job.get('user'), null, 'User relationship was removed correctly'); + assert.equal(job.get('user'), null, 'User relationship was removed correctly'); }); -test("Fetching a belongsTo that is set to a different record, sets the old relationship to null - async", function() { - expect(3); +test("Fetching a belongsTo that is set to a different record, sets the old relationship to null - async", function(assert) { + assert.expect(3); var stanley, stanleysFriend; run(function() { stanley = store.push({ @@ -248,7 +250,7 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat }); stanleysFriend.get('bestFriend').then(function(fetchedUser) { - equal(fetchedUser, stanley, 'User relationship was initally setup correctly'); + assert.equal(fetchedUser, stanley, 'User relationship was initally setup correctly'); var stanleysNewFriend; run(function() { stanleysNewFriend = store.push({ @@ -271,18 +273,18 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat }); stanley.get('bestFriend').then(function(fetchedNewFriend) { - equal(fetchedNewFriend, stanleysNewFriend, 'User relationship was updated correctly'); + assert.equal(fetchedNewFriend, stanleysNewFriend, 'User relationship was updated correctly'); }); stanleysFriend.get('bestFriend').then(function(fetchedOldFriend) { - equal(fetchedOldFriend, null, 'The old relationship was set to null correctly'); + assert.equal(fetchedOldFriend, null, 'The old relationship was set to null correctly'); }); }); }); }); -test("Fetching a belongsTo that is set to a different record, sets the old relationship to null - sync", function() { +test("Fetching a belongsTo that is set to a different record, sets the old relationship to null - sync", function(assert) { var job, user, newBetterJob; run(function() { job = store.push({ @@ -312,7 +314,7 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat } }); }); - equal(job.get('user'), user, 'Job and user initially setup correctly'); + assert.equal(job.get('user'), user, 'Job and user initially setup correctly'); run(function() { newBetterJob = store.push({ data: { @@ -333,16 +335,16 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat }); }); - equal(user.get('job'), newBetterJob, 'Job updated correctly'); - equal(job.get('user'), null, 'Old relationship nulled out correctly'); - equal(newBetterJob.get('user'), user, 'New job setup correctly'); + assert.equal(user.get('job'), newBetterJob, 'Job updated correctly'); + assert.equal(job.get('user'), null, 'Old relationship nulled out correctly'); + assert.equal(newBetterJob.get('user'), user, 'New job setup correctly'); }); /* Local edits */ -test("Setting a OneToOne relationship reflects correctly on the other side- async", function() { +test("Setting a OneToOne relationship reflects correctly on the other side- async", function(assert) { var stanley, stanleysFriend; run(function() { stanley = store.push({ @@ -367,13 +369,13 @@ test("Setting a OneToOne relationship reflects correctly on the other side- asyn run(function() { stanley.set('bestFriend', stanleysFriend); stanleysFriend.get('bestFriend').then(function(fetchedUser) { - equal(fetchedUser, stanley, 'User relationship was updated correctly'); + assert.equal(fetchedUser, stanley, 'User relationship was updated correctly'); }); }); }); -test("Setting a OneToOne relationship reflects correctly on the other side- sync", function() { +test("Setting a OneToOne relationship reflects correctly on the other side- sync", function(assert) { var job, user; run(function() { job = store.push({ @@ -398,11 +400,11 @@ test("Setting a OneToOne relationship reflects correctly on the other side- sync run(function() { user.set('job', job); }); - equal(job.get('user'), user, 'User relationship was set up correctly'); + assert.equal(job.get('user'), user, 'User relationship was set up correctly'); }); -test("Setting a BelongsTo to a promise unwraps the promise before setting- async", function() { +test("Setting a BelongsTo to a promise unwraps the promise before setting- async", function(assert) { var stanley, stanleysFriend, newFriend; run(function() { stanley = store.push({ @@ -444,16 +446,16 @@ test("Setting a BelongsTo to a promise unwraps the promise before setting- async run(function() { newFriend.set('bestFriend', stanleysFriend.get('bestFriend')); stanley.get('bestFriend').then(function(fetchedUser) { - equal(fetchedUser, newFriend, 'User relationship was updated correctly'); + assert.equal(fetchedUser, newFriend, 'User relationship was updated correctly'); }); newFriend.get('bestFriend').then(function(fetchedUser) { - equal(fetchedUser, stanley, 'User relationship was updated correctly'); + assert.equal(fetchedUser, stanley, 'User relationship was updated correctly'); }); }); }); -test("Setting a BelongsTo to a promise works when the promise returns null- async", function() { +test("Setting a BelongsTo to a promise works when the promise returns null- async", function(assert) { var igor, newFriend; run(function() { store.push({ @@ -495,13 +497,13 @@ test("Setting a BelongsTo to a promise works when the promise returns null- asyn run(function() { newFriend.set('bestFriend', igor.get('bestFriend')); newFriend.get('bestFriend').then(function(fetchedUser) { - equal(fetchedUser, null, 'User relationship was updated correctly'); + assert.equal(fetchedUser, null, 'User relationship was updated correctly'); }); }); }); -test("Setting a BelongsTo to a promise that didn't come from a relationship errors out", function () { +test("Setting a BelongsTo to a promise that didn't come from a relationship errors out", function(assert) { var stanley, igor; run(function() { stanley = store.push({ @@ -539,8 +541,8 @@ test("Setting a BelongsTo to a promise that didn't come from a relationship erro }, /You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call./); }); -test("Setting a BelongsTo to a promise multiple times is resistant to race conditions- async", function () { - expect(1); +test("Setting a BelongsTo to a promise multiple times is resistant to race conditions- async", function(assert) { + assert.expect(1); var stanley, igor, newFriend; run(function() { stanley = store.push({ @@ -606,12 +608,12 @@ test("Setting a BelongsTo to a promise multiple times is resistant to race condi newFriend.set('bestFriend', stanley.get('bestFriend')); newFriend.set('bestFriend', igor.get('bestFriend')); newFriend.get('bestFriend').then(function(fetchedUser) { - equal(fetchedUser.get('name'), "Igor's friend", 'User relationship was updated correctly'); + assert.equal(fetchedUser.get('name'), "Igor's friend", 'User relationship was updated correctly'); }); }); }); -test("Setting a OneToOne relationship to null reflects correctly on the other side - async", function () { +test("Setting a OneToOne relationship to null reflects correctly on the other side - async", function(assert) { var stanley, stanleysFriend; run(function() { stanley = store.push({ @@ -653,12 +655,12 @@ test("Setting a OneToOne relationship to null reflects correctly on the other si run(function() { stanley.set('bestFriend', null); // :( stanleysFriend.get('bestFriend').then(function(fetchedUser) { - equal(fetchedUser, null, 'User relationship was removed correctly'); + assert.equal(fetchedUser, null, 'User relationship was removed correctly'); }); }); }); -test("Setting a OneToOne relationship to null reflects correctly on the other side - sync", function () { +test("Setting a OneToOne relationship to null reflects correctly on the other side - sync", function(assert) { var job, user; run(function() { job = store.push({ @@ -700,11 +702,11 @@ test("Setting a OneToOne relationship to null reflects correctly on the other si run(function() { user.set('job', null); }); - equal(job.get('user'), null, 'User relationship was removed correctly'); + assert.equal(job.get('user'), null, 'User relationship was removed correctly'); }); -test("Setting a belongsTo to a different record, sets the old relationship to null - async", function () { - expect(3); +test("Setting a belongsTo to a different record, sets the old relationship to null - async", function(assert) { + assert.expect(3); var stanley, stanleysFriend; run(function() { @@ -745,7 +747,7 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu stanleysFriend.get('bestFriend').then(function(fetchedUser) { - equal(fetchedUser, stanley, 'User relationship was initally setup correctly'); + assert.equal(fetchedUser, stanley, 'User relationship was initally setup correctly'); var stanleysNewFriend = store.push({ data: { id: 3, @@ -761,17 +763,17 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu }); stanley.get('bestFriend').then(function(fetchedNewFriend) { - equal(fetchedNewFriend, stanleysNewFriend, 'User relationship was updated correctly'); + assert.equal(fetchedNewFriend, stanleysNewFriend, 'User relationship was updated correctly'); }); stanleysFriend.get('bestFriend').then(function(fetchedOldFriend) { - equal(fetchedOldFriend, null, 'The old relationship was set to null correctly'); + assert.equal(fetchedOldFriend, null, 'The old relationship was set to null correctly'); }); }); }); }); -test("Setting a belongsTo to a different record, sets the old relationship to null - sync", function () { +test("Setting a belongsTo to a different record, sets the old relationship to null - sync", function(assert) { var job, user, newBetterJob; run(function() { job = store.push({ @@ -802,7 +804,7 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu }); }); - equal(job.get('user'), user, 'Job and user initially setup correctly'); + assert.equal(job.get('user'), user, 'Job and user initially setup correctly'); run(function() { newBetterJob = store.push({ @@ -818,16 +820,16 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu newBetterJob.set('user', user); }); - equal(user.get('job'), newBetterJob, 'Job updated correctly'); - equal(job.get('user'), null, 'Old relationship nulled out correctly'); - equal(newBetterJob.get('user'), user, 'New job setup correctly'); + assert.equal(user.get('job'), newBetterJob, 'Job updated correctly'); + assert.equal(job.get('user'), null, 'Old relationship nulled out correctly'); + assert.equal(newBetterJob.get('user'), user, 'New job setup correctly'); }); /* Rollback attributes tests */ -test("Rollbacking attributes of deleted record restores the relationship on both sides - async", function () { +test("Rollbacking attributes of deleted record restores the relationship on both sides - async", function(assert) { var stanley, stanleysFriend; run(function() { stanley = store.push({ @@ -864,15 +866,15 @@ test("Rollbacking attributes of deleted record restores the relationship on both run(function() { stanley.rollbackAttributes(); stanleysFriend.get('bestFriend').then(function(fetchedUser) { - equal(fetchedUser, stanley, 'Stanley got rollbacked correctly'); + assert.equal(fetchedUser, stanley, 'Stanley got rollbacked correctly'); }); stanley.get('bestFriend').then(function(fetchedUser) { - equal(fetchedUser, stanleysFriend, 'Stanleys friend did not get removed'); + assert.equal(fetchedUser, stanleysFriend, 'Stanleys friend did not get removed'); }); }); }); -test("Rollbacking attributes of deleted record restores the relationship on both sides - sync", function () { +test("Rollbacking attributes of deleted record restores the relationship on both sides - sync", function(assert) { var job, user; run(function() { job = store.push({ @@ -906,11 +908,11 @@ test("Rollbacking attributes of deleted record restores the relationship on both job.deleteRecord(); job.rollbackAttributes(); }); - equal(user.get('job'), job, 'Job got rollbacked correctly'); - equal(job.get('user'), user, 'Job still has the user'); + assert.equal(user.get('job'), job, 'Job got rollbacked correctly'); + assert.equal(job.get('user'), user, 'Job still has the user'); }); -test("Rollbacking attributes of created record removes the relationship on both sides - async", function () { +test("Rollbacking attributes of created record removes the relationship on both sides - async", function(assert) { var stanleysFriend, stanley; run(function() { stanleysFriend = store.push({ @@ -928,15 +930,15 @@ test("Rollbacking attributes of created record removes the relationship on both run(function() { stanley.rollbackAttributes(); stanleysFriend.get('bestFriend').then(function(fetchedUser) { - equal(fetchedUser, null, 'Stanley got rollbacked correctly'); + assert.equal(fetchedUser, null, 'Stanley got rollbacked correctly'); }); stanley.get('bestFriend').then(function(fetchedUser) { - equal(fetchedUser, null, 'Stanleys friend did got removed'); + assert.equal(fetchedUser, null, 'Stanleys friend did got removed'); }); }); }); -test("Rollbacking attributes of created record removes the relationship on both sides - sync", function () { +test("Rollbacking attributes of created record removes the relationship on both sides - sync", function(assert) { var user, job; run(function() { user = store.push({ @@ -954,6 +956,6 @@ test("Rollbacking attributes of created record removes the relationship on both run(function() { job.rollbackAttributes(); }); - equal(user.get('job'), null, 'Job got rollbacked correctly'); - equal(job.get('user'), null, 'Job does not have user anymore'); + assert.equal(user.get('job'), null, 'Job got rollbacked correctly'); + assert.equal(job.get('user'), null, 'Job does not have user anymore'); }); diff --git a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index 061629789b6..62572080df0 100644 --- a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, User, Message, Video, NotMessage; @@ -13,7 +15,7 @@ function stringify(string) { } module('integration/relationships/polymorphic_mixins_belongs_to_test - Polymorphic belongsTo relationships with mixins', { - setup: function() { + beforeEach: function() { User = DS.Model.extend({ name: attr('string'), bestMessage: belongsTo('message', { async: true, polymorphic: true }) @@ -44,7 +46,7 @@ module('integration/relationships/polymorphic_mixins_belongs_to_test - Polymorph store = env.store; }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); @@ -53,7 +55,7 @@ module('integration/relationships/polymorphic_mixins_belongs_to_test - Polymorph Server loading tests */ -test("Relationship is available from the belongsTo side even if only loaded from the inverse side - async", function () { +test("Relationship is available from the belongsTo side even if only loaded from the inverse side - async", function(assert) { var user, video; run(function() { store.push({ @@ -81,9 +83,9 @@ test("Relationship is available from the belongsTo side even if only loaded from }); run(function() { user.get('bestMessage').then(function(message) { - equal(message, video, 'The message was loaded correctly'); + assert.equal(message, video, 'The message was loaded correctly'); message.get('user').then(function(fetchedUser) { - equal(fetchedUser, user, 'The inverse was setup correctly'); + assert.equal(fetchedUser, user, 'The inverse was setup correctly'); }); }); }); @@ -92,7 +94,7 @@ test("Relationship is available from the belongsTo side even if only loaded from /* Local edits */ -test("Setting the polymorphic belongsTo gets propagated to the inverse side - async", function () { +test("Setting the polymorphic belongsTo gets propagated to the inverse side - async", function(assert) { var user, video; run(function() { store.push({ @@ -117,15 +119,15 @@ test("Setting the polymorphic belongsTo gets propagated to the inverse side - as run(function() { user.set('bestMessage', video); video.get('user').then(function(fetchedUser) { - equal(fetchedUser, user, "user got set correctly"); + assert.equal(fetchedUser, user, "user got set correctly"); }); user.get('bestMessage').then(function(message) { - equal(message, video, 'The message was set correctly'); + assert.equal(message, video, 'The message was set correctly'); }); }); }); -test("Setting the polymorphic belongsTo with an object that does not implement the mixin errors out", function () { +test("Setting the polymorphic belongsTo with an object that does not implement the mixin errors out", function(assert) { var user, video; run(function() { store.push({ @@ -155,8 +157,8 @@ test("Setting the polymorphic belongsTo with an object that does not implement t }); -test("Setting the polymorphic belongsTo gets propagated to the inverse side - model injections true", function () { - expect(2); +test("Setting the polymorphic belongsTo gets propagated to the inverse side - model injections true", function(assert) { + assert.expect(2); var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; Ember.MODEL_FACTORY_INJECTIONS = true; @@ -185,10 +187,10 @@ test("Setting the polymorphic belongsTo gets propagated to the inverse side - mo run(function() { user.set('bestMessage', video); video.get('user').then(function(fetchedUser) { - equal(fetchedUser, user, "user got set correctly"); + assert.equal(fetchedUser, user, "user got set correctly"); }); user.get('bestMessage').then(function(message) { - equal(message, video, 'The message was set correctly'); + assert.equal(message, video, 'The message was set correctly'); }); }); } finally { @@ -196,7 +198,7 @@ test("Setting the polymorphic belongsTo gets propagated to the inverse side - mo } }); -test("Setting the polymorphic belongsTo with an object that does not implement the mixin errors out - model injections true", function () { +test("Setting the polymorphic belongsTo with an object that does not implement the mixin errors out - model injections true", function(assert) { var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; Ember.MODEL_FACTORY_INJECTIONS = true; diff --git a/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js index a4a770e9ef0..1caa333a387 100644 --- a/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, User, Message, NotMessage, Video; @@ -14,7 +16,7 @@ function stringify(string) { } module('integration/relationships/polymorphic_mixins_has_many_test - Polymorphic hasMany relationships with mixins', { - setup: function() { + beforeEach: function() { User = DS.Model.extend({ name: attr('string'), messages: hasMany('message', { async: true, polymorphic: true }) @@ -45,7 +47,7 @@ module('integration/relationships/polymorphic_mixins_has_many_test - Polymorphic store = env.store; }, - teardown: function() { + afterEach: function() { run(env.container, 'destroy'); } }); @@ -54,7 +56,7 @@ module('integration/relationships/polymorphic_mixins_has_many_test - Polymorphic Server loading tests */ -test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - async", function () { +test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - async", function(assert) { var user, video; run(function() { store.push({ @@ -84,9 +86,9 @@ test("Relationship is available from the belongsTo side even if only loaded from }); run(function() { user.get('messages').then(function(messages) { - equal(messages.objectAt(0), video, 'The hasMany has loaded correctly'); + assert.equal(messages.objectAt(0), video, 'The hasMany has loaded correctly'); messages.objectAt(0).get('user').then(function(fetchedUser) { - equal(fetchedUser, user, 'The inverse was setup correctly'); + assert.equal(fetchedUser, user, 'The inverse was setup correctly'); }); }); }); @@ -95,7 +97,7 @@ test("Relationship is available from the belongsTo side even if only loaded from /* Local edits */ -test("Pushing to the hasMany reflects the change on the belongsTo side - async", function () { +test("Pushing to the hasMany reflects the change on the belongsTo side - async", function(assert) { var user, video; run(function() { store.push({ @@ -126,7 +128,7 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - async", user.get('messages').then(function(fetchedMessages) { fetchedMessages.pushObject(video); video.get('user').then(function(fetchedUser) { - equal(fetchedUser, user, "user got set correctly"); + assert.equal(fetchedUser, user, "user got set correctly"); }); }); }); @@ -135,7 +137,7 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - async", /* Local edits */ -test("Pushing a an object that does not implement the mixin to the mixin accepting array errors out", function () { +test("Pushing a an object that does not implement the mixin to the mixin accepting array errors out", function(assert) { var user,notMessage; run(function() { store.push({ @@ -171,7 +173,7 @@ test("Pushing a an object that does not implement the mixin to the mixin accepti }); }); -test("Pushing to the hasMany reflects the change on the belongsTo side - model injections true", function () { +test("Pushing to the hasMany reflects the change on the belongsTo side - model injections true", function(assert) { var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; Ember.MODEL_FACTORY_INJECTIONS = true; @@ -206,7 +208,7 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - model i user.get('messages').then(function(fetchedMessages) { fetchedMessages.pushObject(video); video.get('user').then(function(fetchedUser) { - equal(fetchedUser, user, "user got set correctly"); + assert.equal(fetchedUser, user, "user got set correctly"); }); }); }); @@ -218,7 +220,7 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - model i /* Local edits */ -test("Pushing a an object that does not implement the mixin to the mixin accepting array errors out - model injections true", function () { +test("Pushing a an object that does not implement the mixin to the mixin accepting array errors out - model injections true", function(assert) { var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; Ember.MODEL_FACTORY_INJECTIONS = true; diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index 8236836c441..7291ec2883e 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -9,7 +11,7 @@ var run = Ember.run; var LightSaber; module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { - setup: function() { + beforeEach: function() { SuperVillain = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), @@ -72,12 +74,12 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { //env.amsAdapter = env.container.lookup("adapter:-active-model"); }, - teardown: function() { + afterEach: function() { run(env.store, 'destroy'); } }); -test("normalizeResponse with embedded objects", function() { +test("normalizeResponse with embedded objects", function(assert) { env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' } @@ -102,7 +104,7 @@ test("normalizeResponse with embedded objects", function() { json = serializer.normalizeResponse(env.store, HomePlanet, json_hash, '1', 'findRecord'); }); - deepEqual(json, { + assert.deepEqual(json, { "data": { "id": "1", "type": "home-planet", @@ -131,7 +133,7 @@ test("normalizeResponse with embedded objects", function() { }); }); -test("normalizeResponse with embedded objects inside embedded objects", function() { +test("normalizeResponse with embedded objects inside embedded objects", function(assert) { env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' } @@ -165,7 +167,7 @@ test("normalizeResponse with embedded objects inside embedded objects", function json = serializer.normalizeResponse(env.store, HomePlanet, json_hash, '1', 'findRecord'); }); - deepEqual(json, { + assert.deepEqual(json, { "data": { "id": "1", "type": "home-planet", @@ -205,7 +207,7 @@ test("normalizeResponse with embedded objects inside embedded objects", function }); }); -test("normalizeResponse with embedded objects of same type", function() { +test("normalizeResponse with embedded objects of same type", function(assert) { env.registry.register('serializer:comment', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { children: { embedded: 'always' } @@ -235,7 +237,7 @@ test("normalizeResponse with embedded objects of same type", function() { json = serializer.normalizeResponse(env.store, Comment, json_hash, '1', 'findRecord'); }); - deepEqual(json, { + assert.deepEqual(json, { "data": { "id": "1", "type": "comment", @@ -272,7 +274,7 @@ test("normalizeResponse with embedded objects of same type", function() { }, "Primary record was correct"); }); -test("normalizeResponse with embedded objects inside embedded objects of same type", function() { +test("normalizeResponse with embedded objects inside embedded objects of same type", function(assert) { env.registry.register('serializer:comment', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { children: { embedded: 'always' } @@ -306,7 +308,7 @@ test("normalizeResponse with embedded objects inside embedded objects of same ty json = serializer.normalizeResponse(env.store, Comment, json_hash, '1', 'findRecord'); }); - deepEqual(json, { + assert.deepEqual(json, { "data": { "id": "1", "type": "comment", @@ -357,7 +359,7 @@ test("normalizeResponse with embedded objects inside embedded objects of same ty }, "Primary record was correct"); }); -test("normalizeResponse with embedded objects of same type, but from separate attributes", function() { +test("normalizeResponse with embedded objects of same type, but from separate attributes", function(assert) { HomePlanet.reopen({ reformedVillains: DS.hasMany('superVillain', { inverse: null, async: false }) }); @@ -395,7 +397,7 @@ test("normalizeResponse with embedded objects of same type, but from separate at json = serializer.normalizeResponse(env.store, HomePlanet, json_hash, '1', 'findRecord'); }); - deepEqual(json, { + assert.deepEqual(json, { "data": { "id": "1", "type": "home-planet", @@ -449,7 +451,7 @@ test("normalizeResponse with embedded objects of same type, but from separate at }, "Primary hash was correct"); }); -test("normalizeResponse with embedded objects", function() { +test("normalizeResponse with embedded objects", function(assert) { env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' } @@ -475,7 +477,7 @@ test("normalizeResponse with embedded objects", function() { array = serializer.normalizeResponse(env.store, HomePlanet, json_hash, null, 'findAll'); }); - deepEqual(array, { + assert.deepEqual(array, { "data": [{ "id": "1", "type": "home-planet", @@ -502,8 +504,8 @@ test("normalizeResponse with embedded objects", function() { }); }); -test("normalizeResponse with embedded objects with custom primary key", function() { - expect(1); +test("normalizeResponse with embedded objects with custom primary key", function(assert) { + assert.expect(1); env.registry.register('serializer:super-villain', DS.RESTSerializer.extend({ primaryKey: 'villain_id' })); @@ -532,7 +534,7 @@ test("normalizeResponse with embedded objects with custom primary key", function array = serializer.normalizeResponse(env.store, HomePlanet, json_hash, null, 'findAll'); }); - deepEqual(array, { + assert.deepEqual(array, { "data": [{ "id": "1", "type": "home-planet", @@ -559,8 +561,8 @@ test("normalizeResponse with embedded objects with custom primary key", function }); }); -test("normalizeResponse with embedded objects with identical relationship and attribute key ", function() { - expect(1); +test("normalizeResponse with embedded objects with identical relationship and attribute key ", function(assert) { + assert.expect(1); env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' } @@ -590,7 +592,7 @@ test("normalizeResponse with embedded objects with identical relationship and at array = serializer.normalizeResponse(env.store, HomePlanet, json_hash, null, 'findAll'); }); - deepEqual(array, { + assert.deepEqual(array, { "data": [{ "id": "1", "type": "home-planet", @@ -617,7 +619,7 @@ test("normalizeResponse with embedded objects with identical relationship and at }); }); -test("normalizeResponse with embedded objects of same type as primary type", function() { +test("normalizeResponse with embedded objects of same type as primary type", function(assert) { env.registry.register('serializer:comment', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { children: { embedded: 'always' } @@ -648,7 +650,7 @@ test("normalizeResponse with embedded objects of same type as primary type", fun array = serializer.normalizeResponse(env.store, Comment, json_hash, null, 'findAll'); }); - deepEqual(array, { + assert.deepEqual(array, { "data": [{ "id": "1", "type": "comment", @@ -685,7 +687,7 @@ test("normalizeResponse with embedded objects of same type as primary type", fun }, "Primary array is correct"); }); -test("normalizeResponse with embedded objects of same type, but from separate attributes", function() { +test("normalizeResponse with embedded objects of same type, but from separate attributes", function(assert) { HomePlanet.reopen({ reformedVillains: DS.hasMany('superVillain', { async: false }) }); @@ -741,7 +743,7 @@ test("normalizeResponse with embedded objects of same type, but from separate at json = serializer.normalizeResponse(env.store, HomePlanet, json_hash, null, 'findAll'); }); - deepEqual(json, { + assert.deepEqual(json, { "data": [{ "id": "1", "type": "home-planet", @@ -843,7 +845,7 @@ test("normalizeResponse with embedded objects of same type, but from separate at }, "Primary array was correct"); }); -test("serialize supports serialize:false on non-relationship properties", function() { +test("serialize supports serialize:false on non-relationship properties", function(assert) { var tom; run(function() { tom = env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", id: '1' }); @@ -860,14 +862,14 @@ test("serialize supports serialize:false on non-relationship properties", functi json = serializer.serialize(tom._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { lastName: "Dale", homePlanet: null, secretLab: null }); }); -test("serialize with embedded objects (hasMany relationship)", function() { +test("serialize with embedded objects (hasMany relationship)", function(assert) { var tom, league; run(function() { league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); @@ -887,7 +889,7 @@ test("serialize with embedded objects (hasMany relationship)", function() { json = serializer.serialize(league._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { name: "Villain League", villains: [{ id: get(tom, "id"), @@ -899,7 +901,7 @@ test("serialize with embedded objects (hasMany relationship)", function() { }); }); -test("serialize with embedded objects and a custom keyForAttribute (hasMany relationship)", function() { +test("serialize with embedded objects and a custom keyForAttribute (hasMany relationship)", function(assert) { var tom, league; run(function() { league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); @@ -922,7 +924,7 @@ test("serialize with embedded objects and a custom keyForAttribute (hasMany rela json = serializer.serialize(league._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { "name-custom": "Villain League", "villains-custom": [{ id: get(tom, "id"), @@ -934,7 +936,7 @@ test("serialize with embedded objects and a custom keyForAttribute (hasMany rela }); }); -test("serialize with embedded objects (unknown hasMany relationship)", function() { +test("serialize with embedded objects (unknown hasMany relationship)", function(assert) { var league; run(function() { env.store.push({ @@ -963,13 +965,13 @@ test("serialize with embedded objects (unknown hasMany relationship)", function( }); }, /The embedded relationship 'villains' is undefined for 'home-planet' with id '123'. Please include it in your original payload./); - deepEqual(json, { + assert.deepEqual(json, { name: "Villain League", villains: [] }); }); -test("serialize with embedded objects (hasMany relationship) supports serialize:false", function() { +test("serialize with embedded objects (hasMany relationship) supports serialize:false", function(assert) { run(function() { league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); @@ -987,12 +989,12 @@ test("serialize with embedded objects (hasMany relationship) supports serialize: json = serializer.serialize(league._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { name: "Villain League" }); }); -test("serialize with (new) embedded objects (hasMany relationship)", function() { +test("serialize with (new) embedded objects (hasMany relationship)", function(assert) { run(function() { league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league }); @@ -1009,7 +1011,7 @@ test("serialize with (new) embedded objects (hasMany relationship)", function() json = serializer.serialize(league._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { name: "Villain League", villains: [{ firstName: "Tom", @@ -1020,7 +1022,7 @@ test("serialize with (new) embedded objects (hasMany relationship)", function() }); }); -test("serialize with embedded objects (hasMany relationships, including related objects not embedded)", function() { +test("serialize with embedded objects (hasMany relationships, including related objects not embedded)", function(assert) { run(function() { superVillain = env.store.createRecord('super-villain', { id: 1, firstName: "Super", lastName: "Villian" }); evilMinion = env.store.createRecord('evil-minion', { id: 1, name: "Evil Minion", superVillian: superVillain }); @@ -1041,7 +1043,7 @@ test("serialize with embedded objects (hasMany relationships, including related json = serializer.serialize(superVillain._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { firstName: get(superVillain, "firstName"), lastName: get(superVillain, "lastName"), homePlanet: null, @@ -1055,7 +1057,7 @@ test("serialize with embedded objects (hasMany relationships, including related }); }); -test("normalizeResponse with embedded object (belongsTo relationship)", function() { +test("normalizeResponse with embedded object (belongsTo relationship)", function(assert) { env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { embedded: 'always' } @@ -1085,7 +1087,7 @@ test("normalizeResponse with embedded object (belongsTo relationship)", function json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); }); - deepEqual(json, { + assert.deepEqual(json, { "data": { "id": "1", "type": "super-villain", @@ -1124,7 +1126,7 @@ test("normalizeResponse with embedded object (belongsTo relationship)", function }); }); -test("serialize with embedded object (belongsTo relationship)", function() { +test("serialize with embedded object (belongsTo relationship)", function(assert) { env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { embedded: 'always' } @@ -1149,7 +1151,7 @@ test("serialize with embedded object (belongsTo relationship)", function() { json = serializer.serialize(tom._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { firstName: get(tom, "firstName"), lastName: get(tom, "lastName"), homePlanet: get(tom, "homePlanet").get("id"), @@ -1161,7 +1163,7 @@ test("serialize with embedded object (belongsTo relationship)", function() { }); }); -test("serialize with embedded object (belongsTo relationship) works with different primaryKeys", function() { +test("serialize with embedded object (belongsTo relationship) works with different primaryKeys", function(assert) { env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { primaryKey: '_id', attrs: { @@ -1191,7 +1193,7 @@ test("serialize with embedded object (belongsTo relationship) works with differe json = serializer.serialize(tom._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { firstName: get(tom, "firstName"), lastName: get(tom, "lastName"), homePlanet: get(tom, "homePlanet").get("id"), @@ -1203,7 +1205,7 @@ test("serialize with embedded object (belongsTo relationship) works with differe }); }); -test("serialize with embedded object (belongsTo relationship, new no id)", function() { +test("serialize with embedded object (belongsTo relationship, new no id)", function(assert) { env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { embedded: 'always' } @@ -1229,7 +1231,7 @@ test("serialize with embedded object (belongsTo relationship, new no id)", funct json = serializer.serialize(tom._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { firstName: get(tom, "firstName"), lastName: get(tom, "lastName"), homePlanet: get(tom, "homePlanet").get("id"), @@ -1240,7 +1242,7 @@ test("serialize with embedded object (belongsTo relationship, new no id)", funct }); }); -test("serialize with embedded object (belongsTo relationship) supports serialize:ids", function() { +test("serialize with embedded object (belongsTo relationship) supports serialize:ids", function(assert) { env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { serialize: 'ids' } @@ -1265,7 +1267,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize json = serializer.serialize(tom._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { firstName: get(tom, "firstName"), lastName: get(tom, "lastName"), homePlanet: get(tom, "homePlanet").get("id"), @@ -1273,7 +1275,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize }); }); -test("serialize with embedded object (belongsTo relationship) supports serialize:id", function() { +test("serialize with embedded object (belongsTo relationship) supports serialize:id", function(assert) { env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { serialize: 'id' } @@ -1299,7 +1301,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize json = serializer.serialize(tom._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { firstName: get(tom, "firstName"), lastName: get(tom, "lastName"), homePlanet: get(tom, "homePlanet").get("id"), @@ -1307,7 +1309,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize }); }); -test("serialize with embedded object (belongsTo relationship) supports serialize:id in conjunction with deserialize:records", function() { +test("serialize with embedded object (belongsTo relationship) supports serialize:id in conjunction with deserialize:records", function(assert) { env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { serialize: 'id', deserialize: 'records' } @@ -1333,7 +1335,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize json = serializer.serialize(tom._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { firstName: get(tom, "firstName"), lastName: get(tom, "lastName"), homePlanet: get(tom, "homePlanet").get("id"), @@ -1341,7 +1343,7 @@ test("serialize with embedded object (belongsTo relationship) supports serialize }); }); -test("serialize with embedded object (belongsTo relationship) supports serialize:false", function() { +test("serialize with embedded object (belongsTo relationship) supports serialize:false", function(assert) { env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { serialize: false } @@ -1366,14 +1368,14 @@ test("serialize with embedded object (belongsTo relationship) supports serialize json = serializer.serialize(tom._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { firstName: get(tom, "firstName"), lastName: get(tom, "lastName"), homePlanet: get(tom, "homePlanet").get("id") }); }); -test("serialize with embedded object (belongsTo relationship) serializes the id by default if no option specified", function() { +test("serialize with embedded object (belongsTo relationship) serializes the id by default if no option specified", function(assert) { env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin)); var serializer = env.store.serializerFor("super-villain"); @@ -1395,7 +1397,7 @@ test("serialize with embedded object (belongsTo relationship) serializes the id json = serializer.serialize(tom._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { firstName: get(tom, "firstName"), lastName: get(tom, "lastName"), homePlanet: get(tom, "homePlanet").get("id"), @@ -1403,7 +1405,7 @@ test("serialize with embedded object (belongsTo relationship) serializes the id }); }); -test("when related record is not present, serialize embedded record (with a belongsTo relationship) as null", function() { +test("when related record is not present, serialize embedded record (with a belongsTo relationship) as null", function(assert) { env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { secretLab: { embedded: 'always' } @@ -1425,7 +1427,7 @@ test("when related record is not present, serialize embedded record (with a belo json = serializer.serialize(tom._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { firstName: get(tom, "firstName"), lastName: get(tom, "lastName"), homePlanet: get(tom, "homePlanet").get("id"), @@ -1433,7 +1435,7 @@ test("when related record is not present, serialize embedded record (with a belo }); }); -test("normalizeResponse with multiply-nested belongsTo", function() { +test("normalizeResponse with multiply-nested belongsTo", function(assert) { env.registry.register('serializer:evil-minion', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { superVillain: { embedded: 'always' } @@ -1469,7 +1471,7 @@ test("normalizeResponse with multiply-nested belongsTo", function() { json = serializer.normalizeResponse(env.store, EvilMinion, json_hash, '1', 'findRecord'); }); - deepEqual(json, { + assert.deepEqual(json, { "data": { "id": "1", "type": "evil-minion", @@ -1516,7 +1518,7 @@ test("normalizeResponse with multiply-nested belongsTo", function() { }, "Primary hash was correct"); }); -test("normalizeResponse with polymorphic hasMany", function() { +test("normalizeResponse with polymorphic hasMany", function(assert) { SuperVillain.reopen({ secretWeapons: DS.hasMany("secretWeapon", { polymorphic: true, async: false }) }); @@ -1554,7 +1556,7 @@ test("normalizeResponse with polymorphic hasMany", function() { json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findAll'); }); - deepEqual(json, { + assert.deepEqual(json, { "data": { "id": "1", "type": "super-villain", @@ -1590,7 +1592,7 @@ test("normalizeResponse with polymorphic hasMany", function() { }, "Primary hash was correct"); }); -test("normalizeResponse with polymorphic hasMany and custom primary key", function() { +test("normalizeResponse with polymorphic hasMany and custom primary key", function(assert) { SuperVillain.reopen({ secretWeapons: DS.hasMany("secretWeapon", { polymorphic: true, async: false }) }); @@ -1631,7 +1633,7 @@ test("normalizeResponse with polymorphic hasMany and custom primary key", functi json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); }); - deepEqual(json, { + assert.deepEqual(json, { "data": { "attributes": { "firstName": "Tom", @@ -1670,7 +1672,7 @@ test("normalizeResponse with polymorphic hasMany and custom primary key", functi }, "Custom primary key of embedded hasMany is correctly normalized"); }); -test("normalizeResponse with polymorphic belongsTo", function() { +test("normalizeResponse with polymorphic belongsTo", function(assert) { SuperVillain.reopen({ secretLab: DS.belongsTo("secretLab", { polymorphic: true, async: true }) }); @@ -1701,7 +1703,7 @@ test("normalizeResponse with polymorphic belongsTo", function() { json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); }); - deepEqual(json, { + assert.deepEqual(json, { "data": { "id": "1", "type": "super-villain", @@ -1726,8 +1728,8 @@ test("normalizeResponse with polymorphic belongsTo", function() { }, "Primary has was correct"); }); -test("normalizeResponse with polymorphic belongsTo and custom primary key", function() { - expect(1); +test("normalizeResponse with polymorphic belongsTo and custom primary key", function(assert) { + assert.expect(1); SuperVillain.reopen({ secretLab: DS.belongsTo("secretLab", { polymorphic: true, async: true }) @@ -1762,7 +1764,7 @@ test("normalizeResponse with polymorphic belongsTo and custom primary key", func json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); }); - deepEqual(json, { + assert.deepEqual(json, { "data": { "attributes": { "firstName": "Tom", @@ -1793,7 +1795,7 @@ test("normalizeResponse with polymorphic belongsTo and custom primary key", func }); -test("Mixin can be used with RESTSerializer which does not define keyForAttribute", function() { +test("Mixin can be used with RESTSerializer which does not define keyForAttribute", function(assert) { run(function() { homePlanet = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); secretLab = env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); @@ -1818,7 +1820,7 @@ test("Mixin can be used with RESTSerializer which does not define keyForAttribut json = serializer.serialize(superVillain._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { firstName: get(superVillain, "firstName"), lastName: get(superVillain, "lastName"), homePlanet: "123", @@ -1833,7 +1835,7 @@ test("Mixin can be used with RESTSerializer which does not define keyForAttribut }); }); -test("normalize with custom belongsTo primary key", function() { +test("normalize with custom belongsTo primary key", function(assert) { env.registry.register('serializer:evil-minion', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { superVillain: { embedded: 'always' } @@ -1861,7 +1863,7 @@ test("normalize with custom belongsTo primary key", function() { json = serializer.normalizeResponse(env.store, EvilMinion, json_hash, '1', 'findRecord'); }); - deepEqual(json, { + assert.deepEqual(json, { "data": { "id": "1", "type": "evil-minion", @@ -1886,7 +1888,7 @@ test("normalize with custom belongsTo primary key", function() { }, "Primary hash was correct"); }); -test("serializing relationships with an embedded and without calls super when not attr not present", function() { +test("serializing relationships with an embedded and without calls super when not attr not present", function(assert) { run(function() { homePlanet = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); secretLab = env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); @@ -1935,7 +1937,7 @@ test("serializing relationships with an embedded and without calls super when no json = serializer.serialize(superVillain._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { firstName: get(superVillain, "firstName"), lastName: get(superVillain, "lastName"), homePlanet: "123", @@ -1948,11 +1950,11 @@ test("serializing relationships with an embedded and without calls super when no // customized serializeHasMany method to generate ids for "manyToOne" relation secretWeapons: ["1"] }); - ok(calledSerializeBelongsTo); - ok(calledSerializeHasMany); + assert.ok(calledSerializeBelongsTo); + assert.ok(calledSerializeHasMany); }); -test("serializing belongsTo correctly removes embedded foreign key", function() { +test("serializing belongsTo correctly removes embedded foreign key", function(assert) { SecretWeapon.reopen({ superVillain: null }); @@ -1979,7 +1981,7 @@ test("serializing belongsTo correctly removes embedded foreign key", function() json = serializer.serialize(evilMinion._createSnapshot()); }); - deepEqual(json, { + assert.deepEqual(json, { name: "Evil Minion", secretWeapon: { name: "Secret Weapon" diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index a99d1712c40..74f7f493e09 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, serializer; @@ -10,7 +12,7 @@ var run = Ember.run; var User, Handle, GithubHandle, TwitterHandle, Company; module('integration/serializers/json-api-serializer - JSONAPISerializer', { - setup: function() { + beforeEach: function() { User = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), @@ -50,12 +52,12 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', { serializer = store.serializerFor('-json-api'); }, - teardown: function() { + afterEach: function() { run(env.store, 'destroy'); } }); -test('Calling pushPayload works', function() { +test('Calling pushPayload works', function(assert) { run(function() { serializer.pushPayload(store, { data: { @@ -100,15 +102,15 @@ test('Calling pushPayload works', function() { var user = store.peekRecord('user', 1); - equal(get(user, 'firstName'), 'Yehuda', 'firstName is correct'); - equal(get(user, 'lastName'), 'Katz', 'lastName is correct'); - equal(get(user, 'company.name'), 'Tilde Inc.', 'company.name is correct'); - equal(get(user, 'handles.firstObject.username'), 'wycats', 'handles.firstObject.username is correct'); - equal(get(user, 'handles.lastObject.nickname'), '@wycats', 'handles.lastObject.nickname is correct'); + assert.equal(get(user, 'firstName'), 'Yehuda', 'firstName is correct'); + assert.equal(get(user, 'lastName'), 'Katz', 'lastName is correct'); + assert.equal(get(user, 'company.name'), 'Tilde Inc.', 'company.name is correct'); + assert.equal(get(user, 'handles.firstObject.username'), 'wycats', 'handles.firstObject.username is correct'); + assert.equal(get(user, 'handles.lastObject.nickname'), '@wycats', 'handles.lastObject.nickname is correct'); }); }); -test('Warns when normalizing an unknown type', function() { +test('Warns when normalizing an unknown type', function(assert) { var documentHash = { data: { type: 'UnknownType', @@ -126,7 +128,7 @@ test('Warns when normalizing an unknown type', function() { }, /Encountered a resource object with type "UnknownType", but no model was found for model name "unknown-type"/); }); -test('Serializer should respect the attrs hash when extracting attributes and relationships', function() { +test('Serializer should respect the attrs hash when extracting attributes and relationships', function(assert) { env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ attrs: { title: "title_attribute_key", @@ -158,11 +160,11 @@ test('Serializer should respect the attrs hash when extracting attributes and re var user = env.store.serializerFor("user").normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); - equal(user.data.attributes.title, "director"); - deepEqual(user.data.relationships.company.data, { id: "2", type: "company" }); + assert.equal(user.data.attributes.title, "director"); + assert.deepEqual(user.data.relationships.company.data, { id: "2", type: "company" }); }); -test('Serializer should respect the attrs hash when serializing attributes and relationships', function() { +test('Serializer should respect the attrs hash when serializing attributes and relationships', function(assert) { env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ attrs: { title: "title_attribute_key", @@ -187,6 +189,6 @@ test('Serializer should respect the attrs hash when serializing attributes and r var payload = env.store.serializerFor("user").serialize(user._createSnapshot()); - equal(payload.data.relationships['company_relationship_key'].data.id, "1"); - equal(payload.data.attributes['title_attribute_key'], "director"); + assert.equal(payload.data.relationships['company_relationship_key'].data.id, "1"); + assert.equal(payload.data.attributes['title_attribute_key'], "director"); }); diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 85512cc415a..7e97eed496b 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var Post, post, Comment, comment, Favorite, favorite, env; var run = Ember.run; module("integration/serializer/json - JSONSerializer", { - setup: function() { + beforeEach: function() { Post = DS.Model.extend({ title: DS.attr('string'), comments: DS.hasMany('comment', { inverse: null, async: false }) @@ -28,12 +30,12 @@ module("integration/serializer/json - JSONSerializer", { env.store.modelFor('favorite'); }, - teardown: function() { + afterEach: function() { run(env.store, 'destroy'); } }); -test("serialize doesn't include ID when includeId is false", function() { +test("serialize doesn't include ID when includeId is false", function(assert) { run(function() { post = env.store.createRecord('post', { title: 'Rails is omakase' }); }); @@ -41,13 +43,13 @@ test("serialize doesn't include ID when includeId is false", function() { json = env.serializer.serialize(post._createSnapshot(), { includeId: false }); - deepEqual(json, { + assert.deepEqual(json, { title: "Rails is omakase", comments: [] }); }); -test("serialize includes id when includeId is true", function() { +test("serialize includes id when includeId is true", function(assert) { run(function() { post = env.store.createRecord('post', { title: 'Rails is omakase' }); post.set('id', 'test'); @@ -56,14 +58,14 @@ test("serialize includes id when includeId is true", function() { json = env.serializer.serialize(post._createSnapshot(), { includeId: true }); - deepEqual(json, { + assert.deepEqual(json, { id: 'test', title: 'Rails is omakase', comments: [] }); }); -test("serializeAttribute", function() { +test("serializeAttribute", function(assert) { run(function() { post = env.store.createRecord('post', { title: "Rails is omakase" }); }); @@ -71,12 +73,12 @@ test("serializeAttribute", function() { env.serializer.serializeAttribute(post._createSnapshot(), json, "title", { type: "string" }); - deepEqual(json, { + assert.deepEqual(json, { title: "Rails is omakase" }); }); -test("serializeAttribute respects keyForAttribute", function() { +test("serializeAttribute respects keyForAttribute", function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend({ keyForAttribute: function(key) { return key.toUpperCase(); @@ -90,10 +92,10 @@ test("serializeAttribute respects keyForAttribute", function() { env.store.serializerFor("post").serializeAttribute(post._createSnapshot(), json, "title", { type: "string" }); - deepEqual(json, { TITLE: "Rails is omakase" }); + assert.deepEqual(json, { TITLE: "Rails is omakase" }); }); -test("serializeBelongsTo", function() { +test("serializeBelongsTo", function(assert) { run(function() { post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); @@ -103,10 +105,10 @@ test("serializeBelongsTo", function() { env.serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); - deepEqual(json, { post: "1" }); + assert.deepEqual(json, { post: "1" }); }); -test("serializeBelongsTo with null", function() { +test("serializeBelongsTo with null", function(assert) { run(function() { comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: null }); }); @@ -114,12 +116,12 @@ test("serializeBelongsTo with null", function() { env.serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); - deepEqual(json, { + assert.deepEqual(json, { post: null }, "Can set a belongsTo to a null value"); }); -test("async serializeBelongsTo with null", function() { +test("async serializeBelongsTo with null", function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: true }) }); @@ -130,12 +132,12 @@ test("async serializeBelongsTo with null", function() { env.serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); - deepEqual(json, { + assert.deepEqual(json, { post: null }, "Can set a belongsTo to a null value"); }); -test("serializeBelongsTo respects keyForRelationship", function() { +test("serializeBelongsTo respects keyForRelationship", function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend({ keyForRelationship: function(key, type) { return key.toUpperCase(); @@ -149,12 +151,12 @@ test("serializeBelongsTo respects keyForRelationship", function() { env.store.serializerFor("post").serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); - deepEqual(json, { + assert.deepEqual(json, { POST: "1" }); }); -test("serializeHasMany respects keyForRelationship", function() { +test("serializeHasMany respects keyForRelationship", function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend({ keyForRelationship: function(key, type) { return key.toUpperCase(); @@ -170,12 +172,12 @@ test("serializeHasMany respects keyForRelationship", function() { env.store.serializerFor("post").serializeHasMany(post._createSnapshot(), json, { key: "comments", options: {} }); - deepEqual(json, { + assert.deepEqual(json, { COMMENTS: ["1"] }); }); -test("serializeHasMany omits unknown relationships on pushed record", function() { +test("serializeHasMany omits unknown relationships on pushed record", function(assert) { run(function() { post = env.store.push({ @@ -193,10 +195,10 @@ test("serializeHasMany omits unknown relationships on pushed record", function() env.store.serializerFor("post").serializeHasMany(post._createSnapshot(), json, { key: "comments", options: {} }); - ok(!json.hasOwnProperty("comments"), "Does not add the relationship key to json"); + assert.ok(!json.hasOwnProperty("comments"), "Does not add the relationship key to json"); }); -test("serializeIntoHash", function() { +test("serializeIntoHash", function(assert) { run(function() { post = env.store.createRecord('post', { title: "Rails is omakase" }); }); @@ -205,14 +207,14 @@ test("serializeIntoHash", function() { env.serializer.serializeIntoHash(json, Post, post._createSnapshot()); - deepEqual(json, { + assert.deepEqual(json, { title: "Rails is omakase", comments: [] }); }); -test("serializePolymorphicType sync", function() { - expect(1); +test("serializePolymorphicType sync", function(assert) { + assert.expect(1); env.registry.register('serializer:comment', DS.JSONSerializer.extend({ serializePolymorphicType: function(record, json, relationship) { @@ -220,7 +222,7 @@ test("serializePolymorphicType sync", function() { var belongsTo = record.belongsTo(key); json[relationship.key + "TYPE"] = belongsTo.modelName; - ok(true, 'serializePolymorphicType is called when serialize a polymorphic belongsTo'); + assert.ok(true, 'serializePolymorphicType is called when serialize a polymorphic belongsTo'); } })); @@ -232,8 +234,8 @@ test("serializePolymorphicType sync", function() { env.store.serializerFor('comment').serializeBelongsTo(comment._createSnapshot(), {}, { key: 'post', options: { polymorphic: true } }); }); -test("serializePolymorphicType async", function() { - expect(1); +test("serializePolymorphicType async", function(assert) { + assert.expect(1); Comment.reopen({ post: DS.belongsTo('post', { async: true }) @@ -241,7 +243,7 @@ test("serializePolymorphicType async", function() { env.registry.register('serializer:comment', DS.JSONSerializer.extend({ serializePolymorphicType: function(record, json, relationship) { - ok(true, 'serializePolymorphicType is called when serialize a polymorphic belongsTo'); + assert.ok(true, 'serializePolymorphicType is called when serialize a polymorphic belongsTo'); } })); @@ -253,7 +255,7 @@ test("serializePolymorphicType async", function() { env.store.serializerFor('comment').serializeBelongsTo(comment._createSnapshot(), {}, { key: 'post', options: { async: true, polymorphic: true } }); }); -test("normalizeResponse normalizes each record in the array", function() { +test("normalizeResponse normalizes each record in the array", function(assert) { var postNormalizeCount = 0; var posts = [ { id: "1", title: "Rails is omakase" }, @@ -270,10 +272,10 @@ test("normalizeResponse normalizes each record in the array", function() { run(function() { env.store.serializerFor("post").normalizeResponse(env.store, Post, posts, null, 'findAll'); }); - equal(postNormalizeCount, 2, "two posts are normalized"); + assert.equal(postNormalizeCount, 2, "two posts are normalized"); }); -test('Serializer should respect the attrs hash when extracting records', function() { +test('Serializer should respect the attrs hash when extracting records', function(assert) { env.registry.register("serializer:post", DS.JSONSerializer.extend({ attrs: { title: "title_payload_key", @@ -289,11 +291,11 @@ test('Serializer should respect the attrs hash when extracting records', functio var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); - equal(post.data.attributes.title, "Rails is omakase"); - deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }, { id: "2", type: "comment" }]); + assert.equal(post.data.attributes.title, "Rails is omakase"); + assert.deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }, { id: "2", type: "comment" }]); }); -test('Serializer should respect the attrs hash when serializing records', function() { +test('Serializer should respect the attrs hash when serializing records', function(assert) { Post.reopen({ parentPost: DS.belongsTo('post', { inverse: null, async: true }) }); @@ -321,11 +323,11 @@ test('Serializer should respect the attrs hash when serializing records', functi var payload = env.store.serializerFor("post").serialize(post._createSnapshot()); - equal(payload.title_payload_key, "Rails is omakase"); - equal(payload.my_parent, '2'); + assert.equal(payload.title_payload_key, "Rails is omakase"); + assert.equal(payload.my_parent, '2'); }); -test('Serializer respects if embedded model has an attribute named "type" - #3726', function() { +test('Serializer respects if embedded model has an attribute named "type" - #3726', function(assert) { env.registry.register("serializer:parent", DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { child: { embedded: 'always' } @@ -348,7 +350,7 @@ test('Serializer respects if embedded model has an attribute named "type" - #372 var Parent = env.store.modelFor('parent'); var payload = env.store.serializerFor('parent').normalizeResponse(env.store, Parent, jsonHash, '1', 'findRecord'); - deepEqual(payload.included, [ + assert.deepEqual(payload.included, [ { id: '1', type: 'child', @@ -360,7 +362,7 @@ test('Serializer respects if embedded model has an attribute named "type" - #372 ]); }); -test('Serializer respects if embedded model has a relationship named "type" - #3726', function() { +test('Serializer respects if embedded model has a relationship named "type" - #3726', function(assert) { env.registry.register("serializer:parent", DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { child: { embedded: 'always' } @@ -384,7 +386,7 @@ test('Serializer respects if embedded model has a relationship named "type" - #3 var Parent = env.store.modelFor('parent'); var payload = env.store.serializerFor('parent').normalizeResponse(env.store, Parent, jsonHash, '1', 'findRecord'); - deepEqual(payload.included, [ + assert.deepEqual(payload.included, [ { id: '1', type: 'child', @@ -401,8 +403,8 @@ test('Serializer respects if embedded model has a relationship named "type" - #3 ]); }); -test('Serializer respects `serialize: false` on the attrs hash', function() { - expect(2); +test('Serializer respects `serialize: false` on the attrs hash', function(assert) { + assert.expect(2); env.registry.register("serializer:post", DS.JSONSerializer.extend({ attrs: { title: { serialize: false } @@ -415,12 +417,12 @@ test('Serializer respects `serialize: false` on the attrs hash', function() { var payload = env.store.serializerFor("post").serialize(post._createSnapshot()); - ok(!payload.hasOwnProperty('title'), "Does not add the key to instance"); - ok(!payload.hasOwnProperty('[object Object]'), "Does not add some random key like [object Object]"); + assert.ok(!payload.hasOwnProperty('title'), "Does not add the key to instance"); + assert.ok(!payload.hasOwnProperty('[object Object]'), "Does not add some random key like [object Object]"); }); -test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` property', function() { - expect(1); +test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` property', function(assert) { + assert.expect(1); env.registry.register("serializer:post", DS.JSONSerializer.extend({ attrs: { comments: { serialize: false } @@ -436,11 +438,11 @@ test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` p var serializedProperty = serializer.keyForRelationship('comments', 'hasMany'); var payload = serializer.serialize(post._createSnapshot()); - ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); + assert.ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); }); -test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` property', function() { - expect(1); +test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` property', function(assert) { + assert.expect(1); env.registry.register("serializer:comment", DS.JSONSerializer.extend({ attrs: { post: { serialize: false } @@ -456,11 +458,11 @@ test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` var serializedProperty = serializer.keyForRelationship('post', 'belongsTo'); var payload = serializer.serialize(comment._createSnapshot()); - ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); + assert.ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); }); -test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` property', function() { - expect(1); +test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` property', function(assert) { + assert.expect(1); env.registry.register("serializer:post", DS.JSONSerializer.extend({ attrs: { comments: { serialize: false } @@ -476,11 +478,11 @@ test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` p var serializedProperty = serializer.keyForRelationship('comments', 'hasMany'); var payload = serializer.serialize(post._createSnapshot()); - ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); + assert.ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); }); -test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` property', function() { - expect(1); +test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` property', function(assert) { + assert.expect(1); env.registry.register("serializer:comment", DS.JSONSerializer.extend({ attrs: { post: { serialize: false } @@ -496,11 +498,11 @@ test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` var serializedProperty = serializer.keyForRelationship('post', 'belongsTo'); var payload = serializer.serialize(comment._createSnapshot()); - ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); + assert.ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); }); -test('Serializer respects `serialize: true` on the attrs hash for a `hasMany` property', function() { - expect(1); +test('Serializer respects `serialize: true` on the attrs hash for a `hasMany` property', function(assert) { + assert.expect(1); env.registry.register("serializer:post", DS.JSONSerializer.extend({ attrs: { comments: { serialize: true } @@ -516,11 +518,11 @@ test('Serializer respects `serialize: true` on the attrs hash for a `hasMany` pr var serializedProperty = serializer.keyForRelationship('comments', 'hasMany'); var payload = serializer.serialize(post._createSnapshot()); - ok(payload.hasOwnProperty(serializedProperty), "Add the key to instance"); + assert.ok(payload.hasOwnProperty(serializedProperty), "Add the key to instance"); }); -test('Serializer respects `serialize: true` on the attrs hash for a `belongsTo` property', function() { - expect(1); +test('Serializer respects `serialize: true` on the attrs hash for a `belongsTo` property', function(assert) { + assert.expect(1); env.registry.register("serializer:comment", DS.JSONSerializer.extend({ attrs: { post: { serialize: true } @@ -536,11 +538,11 @@ test('Serializer respects `serialize: true` on the attrs hash for a `belongsTo` var serializedProperty = serializer.keyForRelationship('post', 'belongsTo'); var payload = serializer.serialize(comment._createSnapshot()); - ok(payload.hasOwnProperty(serializedProperty), "Add the key to instance"); + assert.ok(payload.hasOwnProperty(serializedProperty), "Add the key to instance"); }); -test("Serializer should merge attrs from superclasses", function() { - expect(4); +test("Serializer should merge attrs from superclasses", function(assert) { + assert.expect(4); Post.reopen({ description: DS.attr('string'), anotherString: DS.attr('string') @@ -564,13 +566,13 @@ test("Serializer should merge attrs from superclasses", function() { var payload = env.store.serializerFor("post").serialize(post._createSnapshot()); - equal(payload.title_payload_key, "Rails is omakase"); - equal(payload.description_payload_key, "Omakase is delicious"); - equal(payload.overwritten_another_string_key, "yet another string"); - ok(!payload.base_another_string_key, "overwritten key is not added"); + assert.equal(payload.title_payload_key, "Rails is omakase"); + assert.equal(payload.description_payload_key, "Omakase is delicious"); + assert.equal(payload.overwritten_another_string_key, "yet another string"); + assert.ok(!payload.base_another_string_key, "overwritten key is not added"); }); -test("Serializer should respect the primaryKey attribute when extracting records", function() { +test("Serializer should respect the primaryKey attribute when extracting records", function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend({ primaryKey: '_ID_' })); @@ -581,11 +583,11 @@ test("Serializer should respect the primaryKey attribute when extracting records post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); }); - equal(post.data.id, "1"); - equal(post.data.attributes.title, "Rails is omakase"); + assert.equal(post.data.id, "1"); + assert.equal(post.data.attributes.title, "Rails is omakase"); }); -test("Serializer should respect the primaryKey attribute when serializing records", function() { +test("Serializer should respect the primaryKey attribute when serializing records", function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend({ primaryKey: '_ID_' })); @@ -596,10 +598,10 @@ test("Serializer should respect the primaryKey attribute when serializing record var payload = env.store.serializerFor("post").serialize(post._createSnapshot(), { includeId: true }); - equal(payload._ID_, "1"); + assert.equal(payload._ID_, "1"); }); -test("Serializer should respect keyForAttribute when extracting records", function() { +test("Serializer should respect keyForAttribute when extracting records", function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend({ keyForAttribute: function(key) { return key.toUpperCase(); @@ -610,11 +612,11 @@ test("Serializer should respect keyForAttribute when extracting records", functi post = env.store.serializerFor("post").normalize(Post, jsonHash); - equal(post.data.id, "1"); - equal(post.data.attributes.title, "Rails is omakase"); + assert.equal(post.data.id, "1"); + assert.equal(post.data.attributes.title, "Rails is omakase"); }); -test("Serializer should respect keyForRelationship when extracting records", function() { +test("Serializer should respect keyForRelationship when extracting records", function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend({ keyForRelationship: function(key, type) { return key.toUpperCase(); @@ -625,11 +627,11 @@ test("Serializer should respect keyForRelationship when extracting records", fun post = env.store.serializerFor("post").normalize(Post, jsonHash); - deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }]); + assert.deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }]); }); -test("Calling normalize should normalize the payload (only the passed keys)", function () { - expect(1); +test("Calling normalize should normalize the payload (only the passed keys)", function(assert) { + assert.expect(1); var Person = DS.Model.extend({ posts: DS.hasMany('post', { async: false }) }); @@ -656,7 +658,7 @@ test("Calling normalize should normalize the payload (only the passed keys)", fu aCustomAttrInHash: 'blah' }); - deepEqual(normalizedPayload, { + assert.deepEqual(normalizedPayload, { "data": { "id": "1", "type": "post", @@ -673,7 +675,7 @@ test("Calling normalize should normalize the payload (only the passed keys)", fu }); }); -test('serializeBelongsTo with async polymorphic', function() { +test('serializeBelongsTo with async polymorphic', function(assert) { var json = {}; var expected = { post: '1', postTYPE: 'post' }; @@ -691,10 +693,10 @@ test('serializeBelongsTo with async polymorphic', function() { env.store.serializerFor('favorite').serializeBelongsTo(favorite._createSnapshot(), json, { key: 'post', options: { polymorphic: true, async: true } }); - deepEqual(json, expected, 'returned JSON is correct'); + assert.deepEqual(json, expected, 'returned JSON is correct'); }); -test('extractErrors respects custom key mappings', function() { +test('extractErrors respects custom key mappings', function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend({ attrs: { title: 'le_title', @@ -717,13 +719,13 @@ test('extractErrors respects custom key mappings', function() { var errors = env.store.serializerFor('post').extractErrors(env.store, Post, payload); - deepEqual(errors, { + assert.deepEqual(errors, { title: ["title errors"], comments: ["comments errors"] }); }); -test('extractErrors expects error information located on the errors property of payload', function() { +test('extractErrors expects error information located on the errors property of payload', function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend()); var payload = { @@ -738,10 +740,10 @@ test('extractErrors expects error information located on the errors property of var errors = env.store.serializerFor('post').extractErrors(env.store, Post, payload); - deepEqual(errors, { title: ["title errors"] }); + assert.deepEqual(errors, { title: ["title errors"] }); }); -test('extractErrors leaves payload untouched if it has no errors property', function() { +test('extractErrors leaves payload untouched if it has no errors property', function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend()); var payload = { @@ -750,10 +752,10 @@ test('extractErrors leaves payload untouched if it has no errors property', func var errors = env.store.serializerFor('post').extractErrors(env.store, Post, payload); - deepEqual(errors, { untouchedSinceNoErrorsSiblingPresent: ["true"] }); + assert.deepEqual(errors, { untouchedSinceNoErrorsSiblingPresent: ["true"] }); }); -test('normalizeResponse should extract meta using extractMeta', function() { +test('normalizeResponse should extract meta using extractMeta', function(assert) { env.registry.register("serializer:post", DS.JSONSerializer.extend({ extractMeta: function(store, modelClass, payload) { let meta = this._super(...arguments); @@ -773,10 +775,10 @@ test('normalizeResponse should extract meta using extractMeta', function() { var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); - deepEqual(post.meta.authors, ['Tomster', 'Tomhuda']); + assert.deepEqual(post.meta.authors, ['Tomster', 'Tomhuda']); }); -test('normalizeResponse returns empty `included` payload by default', function() { +test('normalizeResponse returns empty `included` payload by default', function(assert) { env.registry.register("serializer:post", DS.JSONSerializer.extend()); var jsonHash = { @@ -786,10 +788,10 @@ test('normalizeResponse returns empty `included` payload by default', function() var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); - deepEqual(post.included, []); + assert.deepEqual(post.included, []); }); -test('normalizeResponse returns empty `included` payload when relationship is undefined', function() { +test('normalizeResponse returns empty `included` payload when relationship is undefined', function(assert) { env.registry.register("serializer:post", DS.JSONSerializer.extend()); var jsonHash = { @@ -800,10 +802,10 @@ test('normalizeResponse returns empty `included` payload when relationship is un var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); - deepEqual(post.included, []); + assert.deepEqual(post.included, []); }); -test('normalizeResponse respects `included` items (single response)', function() { +test('normalizeResponse respects `included` items (single response)', function(assert) { env.registry.register("serializer:post", DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { comments: { embedded: 'always' } @@ -821,13 +823,13 @@ test('normalizeResponse respects `included` items (single response)', function() var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); - deepEqual(post.included, [ + assert.deepEqual(post.included, [ { id: "1", type: "comment", attributes: { body: "comment 1" }, relationships: {} }, { id: "2", type: "comment", attributes: { body: "comment 2" }, relationships: {} } ]); }); -test('normalizeResponse respects `included` items (array response)', function() { +test('normalizeResponse respects `included` items (array response)', function(assert) { env.registry.register("serializer:post", DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { comments: { embedded: 'always' } @@ -852,7 +854,7 @@ test('normalizeResponse respects `included` items (array response)', function() var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, payload, '1', 'findAll'); - deepEqual(post.included, [ + assert.deepEqual(post.included, [ { id: "1", type: "comment", attributes: { body: "comment 1" }, relationships: {} }, { id: "2", type: "comment", attributes: { body: "comment 2" }, relationships: {} }, { id: "3", type: "comment", attributes: { body: "comment 3" }, relationships: {} } diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 7fb87ffdbbb..e148d47b515 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var HomePlanet, league, SuperVillain, EvilMinion, YellowMinion, DoomsdayDevice, Comment, Basket, Container, env; var run = Ember.run; module("integration/serializer/rest - RESTSerializer", { - setup: function() { + beforeEach: function() { HomePlanet = DS.Model.extend({ name: DS.attr('string'), superVillains: DS.hasMany('super-villain', { async: false }) @@ -61,20 +63,20 @@ module("integration/serializer/rest - RESTSerializer", { env.store.modelFor('container'); }, - teardown: function() { + afterEach: function() { run(env.store, 'destroy'); } }); -test("modelNameFromPayloadKey returns always same modelName even for uncountable multi words keys", function() { - expect(2); +test("modelNameFromPayloadKey returns always same modelName even for uncountable multi words keys", function(assert) { + assert.expect(2); Ember.Inflector.inflector.uncountable('words'); var expectedModelName = 'multi-words'; - equal(env.restSerializer.modelNameFromPayloadKey('multi_words'), expectedModelName); - equal(env.restSerializer.modelNameFromPayloadKey('multi-words'), expectedModelName); + assert.equal(env.restSerializer.modelNameFromPayloadKey('multi_words'), expectedModelName); + assert.equal(env.restSerializer.modelNameFromPayloadKey('multi-words'), expectedModelName); }); -test('normalizeResponse should extract meta using extractMeta', function() { +test('normalizeResponse should extract meta using extractMeta', function(assert) { env.registry.register("serializer:home-planet", DS.RESTSerializer.extend({ extractMeta: function(store, modelClass, payload) { let meta = this._super(...arguments); @@ -90,11 +92,11 @@ test('normalizeResponse should extract meta using extractMeta', function() { var json = env.container.lookup("serializer:home-planet").normalizeResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); - deepEqual(json.meta.authors, ['Tomster', 'Tomhuda']); + assert.deepEqual(json.meta.authors, ['Tomster', 'Tomhuda']); }); -test("normalizeResponse with custom modelNameFromPayloadKey", function() { - expect(1); +test("normalizeResponse with custom modelNameFromPayloadKey", function(assert) { + assert.expect(1); env.restSerializer.modelNameFromPayloadKey = function(root) { var camelized = Ember.String.camelize(root); @@ -111,7 +113,7 @@ test("normalizeResponse with custom modelNameFromPayloadKey", function() { array = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, '1', 'findRecord'); }); - deepEqual(array, { + assert.deepEqual(array, { data: { id: '1', type: 'home-planet', @@ -140,7 +142,7 @@ test("normalizeResponse with custom modelNameFromPayloadKey", function() { }); }); -test("normalizeResponse warning with custom modelNameFromPayloadKey", function() { +test("normalizeResponse warning with custom modelNameFromPayloadKey", function(assert) { var homePlanet; var oldModelNameFromPayloadKey = env.restSerializer.modelNameFromPayloadKey; env.restSerializer.modelNameFromPayloadKey = function(root) { @@ -171,11 +173,11 @@ test("normalizeResponse warning with custom modelNameFromPayloadKey", function() }); }); - equal(homePlanet.data.attributes.name, "Umber"); - deepEqual(homePlanet.data.relationships.superVillains.data, [{ id: '1', type: 'super-villain' }]); + assert.equal(homePlanet.data.attributes.name, "Umber"); + assert.deepEqual(homePlanet.data.relationships.superVillains.data, [{ id: '1', type: 'super-villain' }]); }); -test("normalizeResponse warning with custom modelNameFromPayloadKey", function() { +test("normalizeResponse warning with custom modelNameFromPayloadKey", function(assert) { var homePlanets; env.restSerializer.modelNameFromPayloadKey = function(root) { //return some garbage that won"t resolve in the container @@ -205,12 +207,12 @@ test("normalizeResponse warning with custom modelNameFromPayloadKey", function() }); }); - equal(homePlanets.data.length, 1); - equal(homePlanets.data[0].attributes.name, "Umber"); - deepEqual(homePlanets.data[0].relationships.superVillains.data, [{ id: '1', type: 'super-villain' }]); + assert.equal(homePlanets.data.length, 1); + assert.equal(homePlanets.data[0].attributes.name, "Umber"); + assert.deepEqual(homePlanets.data[0].relationships.superVillains.data, [{ id: '1', type: 'super-villain' }]); }); -test("serialize polymorphicType", function() { +test("serialize polymorphicType", function(assert) { var tom, ray; run(function() { tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); @@ -219,14 +221,14 @@ test("serialize polymorphicType", function() { var json = env.restSerializer.serialize(ray._createSnapshot()); - deepEqual(json, { + assert.deepEqual(json, { name: "DeathRay", evilMinionType: "yellowMinion", evilMinion: "124" }); }); -test("serialize polymorphicType with decamelized modelName", function() { +test("serialize polymorphicType with decamelized modelName", function(assert) { YellowMinion.modelName = 'yellow-minion'; var tom, ray; run(function() { @@ -236,10 +238,10 @@ test("serialize polymorphicType with decamelized modelName", function() { var json = env.restSerializer.serialize(ray._createSnapshot()); - deepEqual(json["evilMinionType"], "yellowMinion"); + assert.deepEqual(json["evilMinionType"], "yellowMinion"); }); -test("serialize polymorphic when associated object is null", function() { +test("serialize polymorphic when associated object is null", function(assert) { var ray; run(function() { ray = env.store.createRecord('doomsday-device', { name: "DeathRay" }); @@ -247,10 +249,10 @@ test("serialize polymorphic when associated object is null", function() { var json = env.restSerializer.serialize(ray._createSnapshot()); - deepEqual(json["evilMinionType"], null); + assert.deepEqual(json["evilMinionType"], null); }); -test("normalizeResponse loads secondary records with correct serializer", function() { +test("normalizeResponse loads secondary records with correct serializer", function(assert) { var superVillainNormalizeCount = 0; env.registry.register('serializer:super-villain', DS.RESTSerializer.extend({ @@ -269,11 +271,11 @@ test("normalizeResponse loads secondary records with correct serializer", functi env.restSerializer.normalizeResponse(env.store, EvilMinion, jsonHash, '1', 'findRecord'); }); - equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); + assert.equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); }); -test("normalizeResponse returns null if payload contains null", function() { - expect(1); +test("normalizeResponse returns null if payload contains null", function(assert) { + assert.expect(1); var jsonHash = { evilMinion: null @@ -284,10 +286,10 @@ test("normalizeResponse returns null if payload contains null", function() { value = env.restSerializer.normalizeResponse(env.store, EvilMinion, jsonHash, null, 'findRecord'); }); - deepEqual(value, { data: null, included: [] }, "returned value is null"); + assert.deepEqual(value, { data: null, included: [] }, "returned value is null"); }); -test("normalizeResponse loads secondary records with correct serializer", function() { +test("normalizeResponse loads secondary records with correct serializer", function(assert) { var superVillainNormalizeCount = 0; env.registry.register('serializer:super-villain', DS.RESTSerializer.extend({ @@ -306,10 +308,10 @@ test("normalizeResponse loads secondary records with correct serializer", functi env.restSerializer.normalizeResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); }); - equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); + assert.equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); }); -test('normalizeHash normalizes specific parts of the payload', function() { +test('normalizeHash normalizes specific parts of the payload', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ normalizeHash: { homePlanets: function(hash) { @@ -329,7 +331,7 @@ test('normalizeHash normalizes specific parts of the payload', function() { array = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); }); - deepEqual(array, { + assert.deepEqual(array, { "data": [{ "id": "1", "type": "home-planet", @@ -349,7 +351,7 @@ test('normalizeHash normalizes specific parts of the payload', function() { }); -test('normalizeHash works with transforms', function() { +test('normalizeHash works with transforms', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ normalizeHash: { evilMinions: function(hash) { @@ -388,10 +390,10 @@ test('normalizeHash works with transforms', function() { array = env.restSerializer.normalizeResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); }); - equal(array.data[0].attributes.condition, "healing"); + assert.equal(array.data[0].attributes.condition, "healing"); }); -test('normalize should allow for different levels of normalization', function() { +test('normalize should allow for different levels of normalization', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ attrs: { superVillain: 'is_super_villain' @@ -410,10 +412,10 @@ test('normalize should allow for different levels of normalization', function() array = env.restSerializer.normalizeResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); }); - equal(array.data[0].relationships.superVillain.data.id, 1); + assert.equal(array.data[0].relationships.superVillain.data.id, 1); }); -test("serializeIntoHash", function() { +test("serializeIntoHash", function(assert) { run(function() { league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); }); @@ -421,14 +423,14 @@ test("serializeIntoHash", function() { env.restSerializer.serializeIntoHash(json, HomePlanet, league._createSnapshot()); - deepEqual(json, { + assert.deepEqual(json, { homePlanet: { name: "Umber" } }); }); -test("serializeIntoHash with decamelized modelName", function() { +test("serializeIntoHash with decamelized modelName", function(assert) { HomePlanet.modelName = 'home-planet'; run(function() { league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); @@ -437,14 +439,14 @@ test("serializeIntoHash with decamelized modelName", function() { env.restSerializer.serializeIntoHash(json, HomePlanet, league._createSnapshot()); - deepEqual(json, { + assert.deepEqual(json, { homePlanet: { name: "Umber" } }); }); -test('serializeBelongsTo with async polymorphic', function() { +test('serializeBelongsTo with async polymorphic', function(assert) { var evilMinion, doomsdayDevice; var json = {}; var expected = { evilMinion: '1', evilMinionType: 'evilMinion' }; @@ -456,10 +458,10 @@ test('serializeBelongsTo with async polymorphic', function() { env.restSerializer.serializeBelongsTo(doomsdayDevice._createSnapshot(), json, { key: 'evilMinion', options: { polymorphic: true, async: true } }); - deepEqual(json, expected, 'returned JSON is correct'); + assert.deepEqual(json, expected, 'returned JSON is correct'); }); -test('serializeBelongsTo logs deprecation when old behavior for getting polymorphic type key is used', function() { +test('serializeBelongsTo logs deprecation when old behavior for getting polymorphic type key is used', function(assert) { var evilMinion, doomsdayDevice; var json = {}; var expected = { evilMinion: '1', myCustomKeyType: 'evilMinion' }; @@ -477,10 +479,10 @@ test('serializeBelongsTo logs deprecation when old behavior for getting polymorp env.restSerializer.serializeBelongsTo(doomsdayDevice._createSnapshot(), json, { key: 'evilMinion', options: { polymorphic: true, async: true } }); }, "The key to serialize the type of a polymorphic record is created via keyForAttribute which has been deprecated. Use the keyForPolymorphicType hook instead."); - deepEqual(json, expected, 'returned JSON is correct'); + assert.deepEqual(json, expected, 'returned JSON is correct'); }); -test('keyForPolymorphicType can be used to overwrite how the type of a polymorphic record is serialized', function() { +test('keyForPolymorphicType can be used to overwrite how the type of a polymorphic record is serialized', function(assert) { var evilMinion, doomsdayDevice; var json = {}; var expected = { evilMinion: '1', typeForEvilMinion: 'evilMinion' }; @@ -496,10 +498,10 @@ test('keyForPolymorphicType can be used to overwrite how the type of a polymorph env.restSerializer.serializeBelongsTo(doomsdayDevice._createSnapshot(), json, { key: 'evilMinion', options: { polymorphic: true, async: true } }); - deepEqual(json, expected, 'returned JSON is correct'); + assert.deepEqual(json, expected, 'returned JSON is correct'); }); -test('keyForPolymorphicType can be used to overwrite how the type of a polymorphic record is looked up for normalization', function() { +test('keyForPolymorphicType can be used to overwrite how the type of a polymorphic record is looked up for normalization', function(assert) { var json = { doomsdayDevice: { id: '1', @@ -531,10 +533,10 @@ test('keyForPolymorphicType can be used to overwrite how the type of a polymorph var normalized = env.restSerializer.normalizeResponse(env.store, DoomsdayDevice, json, null, 'findRecord'); - deepEqual(normalized, expected, 'normalized JSON is correct'); + assert.deepEqual(normalized, expected, 'normalized JSON is correct'); }); -test('serializeIntoHash uses payloadKeyFromModelName to normalize the payload root key', function() { +test('serializeIntoHash uses payloadKeyFromModelName to normalize the payload root key', function(assert) { run(function() { league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); }); @@ -547,14 +549,14 @@ test('serializeIntoHash uses payloadKeyFromModelName to normalize the payload ro env.container.lookup('serializer:home-planet').serializeIntoHash(json, HomePlanet, league._createSnapshot()); - deepEqual(json, { + assert.deepEqual(json, { 'home-planet': { name: "Umber" } }); }); -test('normalizeResponse with async polymorphic belongsTo, using Type', function() { +test('normalizeResponse with async polymorphic belongsTo, using Type', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend()); var store = env.store; env.adapter.findRecord = (store, type) => { @@ -569,7 +571,7 @@ test('normalizeResponse with async polymorphic belongsTo, using { return deathRay.get('evilMinion'); }).then((evilMinion) => { - equal(evilMinion.get('eyes'), 3); + assert.equal(evilMinion.get('eyes'), 3); }); }); }); -test('normalizeResponse with async polymorphic belongsTo', function() { +test('normalizeResponse with async polymorphic belongsTo', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ isNewSerializerAPI: true })); @@ -621,12 +623,12 @@ test('normalizeResponse with async polymorphic belongsTo', function() { store.findRecord('doomsday-device', 1).then((deathRay) => { return deathRay.get('evilMinion'); }).then((evilMinion) => { - equal(evilMinion.get('eyes'), 3); + assert.equal(evilMinion.get('eyes'), 3); }); }); }); -test('normalizeResponse with async polymorphic hasMany', function() { +test('normalizeResponse with async polymorphic hasMany', function(assert) { SuperVillain.reopen({ evilMinions: DS.hasMany('evil-minion', { async: true, polymorphic: true }) }); env.registry.register('serializer:application', DS.RESTSerializer.extend({ isNewSerializerAPI: true @@ -659,13 +661,13 @@ test('normalizeResponse with async polymorphic hasMany', function() { store.findRecord('super-villain', 1).then((superVillain) => { return superVillain.get('evilMinions'); }).then((evilMinions) => { - ok(evilMinions.get('firstObject') instanceof YellowMinion); - equal(evilMinions.get('firstObject.eyes'), 3); + assert.ok(evilMinions.get('firstObject') instanceof YellowMinion); + assert.equal(evilMinions.get('firstObject.eyes'), 3); }); }); }); -test("normalizeResponse can load secondary records of the same type without affecting the query count", function() { +test("normalizeResponse can load secondary records of the same type without affecting the query count", function(assert) { var jsonHash = { comments: [{ id: "1", body: "Parent Comment", root: true, children: [2, 3] }], _comments: [ @@ -679,7 +681,7 @@ test("normalizeResponse can load secondary records of the same type without affe array = env.restSerializer.normalizeResponse(env.store, Comment, jsonHash, '1', 'findRecord'); }); - deepEqual(array, { + assert.deepEqual(array, { "data": { "id": "1", "type": "comment", @@ -716,7 +718,7 @@ test("normalizeResponse can load secondary records of the same type without affe }); }); -test("don't polymorphically deserialize base on the type key in payload when a type attribute exist", function() { +test("don't polymorphically deserialize base on the type key in payload when a type attribute exist", function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ isNewSerializerAPI: true })); @@ -731,17 +733,17 @@ test("don't polymorphically deserialize base on the type key in payload when a t }); const normalRecord = env.store.peekRecord('basket', '1'); - ok(normalRecord, "payload with type that doesn't exist"); - strictEqual(normalRecord.get('type'), 'bamboo'); - strictEqual(normalRecord.get('size'), 10); + assert.ok(normalRecord, "payload with type that doesn't exist"); + assert.strictEqual(normalRecord.get('type'), 'bamboo'); + assert.strictEqual(normalRecord.get('size'), 10); const clashingRecord = env.store.peekRecord('basket', '65536'); - ok(clashingRecord, 'payload with type that matches another model name'); - strictEqual(clashingRecord.get('type'), 'yellowMinion'); - strictEqual(clashingRecord.get('size'), 10); + assert.ok(clashingRecord, 'payload with type that matches another model name'); + assert.strictEqual(clashingRecord.get('type'), 'yellowMinion'); + assert.strictEqual(clashingRecord.get('size'), 10); }); -test("don't polymorphically deserialize base on the type key in payload when a type attribute exist on a singular response", function() { +test("don't polymorphically deserialize base on the type key in payload when a type attribute exist on a singular response", function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ isNewSerializerAPI: true })); @@ -753,13 +755,13 @@ test("don't polymorphically deserialize base on the type key in payload when a t }); const clashingRecord = env.store.peekRecord('basket', '65536'); - ok(clashingRecord, 'payload with type that matches another model name'); - strictEqual(clashingRecord.get('type'), 'yellowMinion'); - strictEqual(clashingRecord.get('size'), 10); + assert.ok(clashingRecord, 'payload with type that matches another model name'); + assert.strictEqual(clashingRecord.get('type'), 'yellowMinion'); + assert.strictEqual(clashingRecord.get('size'), 10); }); -test("don't polymorphically deserialize based on the type key in payload when a relationship exists named type", function() { +test("don't polymorphically deserialize based on the type key in payload when a relationship exists named type", function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ isNewSerializerAPI: true })); @@ -773,11 +775,11 @@ test("don't polymorphically deserialize based on the type key in payload when a run(function() { env.store.findRecord('container', 42).then((container) => { - strictEqual(container.get('volume'), '10 liters'); + assert.strictEqual(container.get('volume'), '10 liters'); return container.get('type'); }).then((basket) => { - ok(basket instanceof Basket); - equal(basket.get('size'), 4); + assert.ok(basket instanceof Basket); + assert.equal(basket.get('size'), 4); }); }); diff --git a/tests/integration/setup-container-test.js b/tests/integration/setup-container-test.js index 9ef73823df7..79a6e7b343a 100644 --- a/tests/integration/setup-container-test.js +++ b/tests/integration/setup-container-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var run = Ember.run; @@ -15,7 +17,7 @@ var container, registry, application; */ module("integration/setup-container - Setting up a container", { - setup: function() { + beforeEach: function() { run(function() { application = Ember.Application.create(); }); @@ -34,37 +36,37 @@ module("integration/setup-container - Setting up a container", { setupContainer(setupContainerArgument); }, - teardown: function() { + afterEach: function() { run(function() { application.destroy(); }); } }); -test("The store should be registered into a container.", function() { - ok(container.lookup('service:store') instanceof Store, "the custom store is instantiated"); +test("The store should be registered into a container.", function(assert) { + assert.ok(container.lookup('service:store') instanceof Store, "the custom store is instantiated"); }); -test("The store should be registered into the container as a service.", function() { - ok(container.lookup('service:store') instanceof Store, "the store as a service is registered"); +test("The store should be registered into the container as a service.", function(assert) { + assert.ok(container.lookup('service:store') instanceof Store, "the store as a service is registered"); }); -test("If a store is instantiated, it should be made available to each controller.", function() { +test("If a store is instantiated, it should be made available to each controller.", function(assert) { registry.register('controller:foo', EmberObject.extend({})); var fooController = container.lookup('controller:foo'); - ok(fooController.get('store') instanceof Store, "the store was injected"); + assert.ok(fooController.get('store') instanceof Store, "the store was injected"); }); -test("serializers are not returned as singletons - each lookup should return a different instance", function() { +test("serializers are not returned as singletons - each lookup should return a different instance", function(assert) { var serializer1, serializer2; serializer1 = container.lookup('serializer:-rest'); serializer2 = container.lookup('serializer:-rest'); - notEqual(serializer1, serializer2); + assert.notEqual(serializer1, serializer2); }); -test("adapters are not returned as singletons - each lookup should return a different instance", function() { +test("adapters are not returned as singletons - each lookup should return a different instance", function(assert) { var adapter1, adapter2; adapter1 = container.lookup('adapter:-rest'); adapter2 = container.lookup('adapter:-rest'); - notEqual(adapter1, adapter2); + assert.notEqual(adapter1, adapter2); }); diff --git a/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js index 55e39e37087..bdba0c40466 100644 --- a/tests/integration/snapshot-test.js +++ b/tests/integration/snapshot-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var run = Ember.run; var env, Post, Comment; module("integration/snapshot - DS.Snapshot", { - setup: function() { + beforeEach: function() { Post = DS.Model.extend({ author: DS.attr(), title: DS.attr(), @@ -23,15 +25,15 @@ module("integration/snapshot - DS.Snapshot", { }); }, - teardown: function() { + afterEach: function() { run(function() { env.store.destroy(); }); } }); -test("record._createSnapshot() returns a snapshot", function() { - expect(1); +test("record._createSnapshot() returns a snapshot", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -46,12 +48,12 @@ test("record._createSnapshot() returns a snapshot", function() { var post = env.store.peekRecord('post', 1); var snapshot = post._createSnapshot(); - ok(snapshot instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); + assert.ok(snapshot instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); }); }); -test("snapshot.id, snapshot.type and snapshot.modelName returns correctly", function() { - expect(3); +test("snapshot.id, snapshot.type and snapshot.modelName returns correctly", function(assert) { + assert.expect(3); run(function() { env.store.push({ @@ -66,14 +68,14 @@ test("snapshot.id, snapshot.type and snapshot.modelName returns correctly", func var post = env.store.peekRecord('post', 1); var snapshot = post._createSnapshot(); - equal(snapshot.id, '1', 'id is correct'); - ok(DS.Model.detect(snapshot.type), 'type is correct'); - equal(snapshot.modelName, 'post', 'modelName is correct'); + assert.equal(snapshot.id, '1', 'id is correct'); + assert.ok(DS.Model.detect(snapshot.type), 'type is correct'); + assert.equal(snapshot.modelName, 'post', 'modelName is correct'); }); }); -test("snapshot.attr() does not change when record changes", function() { - expect(2); +test("snapshot.attr() does not change when record changes", function(assert) { + assert.expect(2); run(function() { env.store.push({ @@ -88,14 +90,14 @@ test("snapshot.attr() does not change when record changes", function() { var post = env.store.peekRecord('post', 1); var snapshot = post._createSnapshot(); - equal(snapshot.attr('title'), 'Hello World', 'snapshot title is correct'); + assert.equal(snapshot.attr('title'), 'Hello World', 'snapshot title is correct'); post.set('title', 'Tomster'); - equal(snapshot.attr('title'), 'Hello World', 'snapshot title is still correct'); + assert.equal(snapshot.attr('title'), 'Hello World', 'snapshot title is still correct'); }); }); -test("snapshot.attr() throws an error attribute not found", function() { - expect(1); +test("snapshot.attr() throws an error attribute not found", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -110,14 +112,14 @@ test("snapshot.attr() throws an error attribute not found", function() { var post = env.store.peekRecord('post', 1); var snapshot = post._createSnapshot(); - throws(function() { + assert.throws(function() { snapshot.attr('unknown'); }, /has no attribute named 'unknown' defined/, 'attr throws error'); }); }); -test("snapshot.attributes() returns a copy of all attributes for the current snapshot", function() { - expect(1); +test("snapshot.attributes() returns a copy of all attributes for the current snapshot", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -134,12 +136,12 @@ test("snapshot.attributes() returns a copy of all attributes for the current sna var attributes = snapshot.attributes(); - deepEqual(attributes, { author: undefined, title: 'Hello World' }, 'attributes are returned correctly'); + assert.deepEqual(attributes, { author: undefined, title: 'Hello World' }, 'attributes are returned correctly'); }); }); -test("snapshot.changedAttributes() returns a copy of all changed attributes for the current snapshot", function() { - expect(1); +test("snapshot.changedAttributes() returns a copy of all changed attributes for the current snapshot", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -157,12 +159,12 @@ test("snapshot.changedAttributes() returns a copy of all changed attributes for var changes = snapshot.changedAttributes(); - deepEqual(changes.title, ['Hello World', 'Hello World!'], 'changed attributes are returned correctly'); + assert.deepEqual(changes.title, ['Hello World', 'Hello World!'], 'changed attributes are returned correctly'); }); }); -test("snapshot.belongsTo() returns undefined if relationship is undefined", function() { - expect(1); +test("snapshot.belongsTo() returns undefined if relationship is undefined", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -178,12 +180,12 @@ test("snapshot.belongsTo() returns undefined if relationship is undefined", func var snapshot = comment._createSnapshot(); var relationship = snapshot.belongsTo('post'); - equal(relationship, undefined, 'relationship is undefined'); + assert.equal(relationship, undefined, 'relationship is undefined'); }); }); -test("snapshot.belongsTo() returns null if relationship is unset", function() { - expect(1); +test("snapshot.belongsTo() returns null if relationship is unset", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -210,12 +212,12 @@ test("snapshot.belongsTo() returns null if relationship is unset", function() { var snapshot = comment._createSnapshot(); var relationship = snapshot.belongsTo('post'); - equal(relationship, null, 'relationship is unset'); + assert.equal(relationship, null, 'relationship is unset'); }); }); -test("snapshot.belongsTo() returns a snapshot if relationship is set", function() { - expect(3); +test("snapshot.belongsTo() returns a snapshot if relationship is set", function(assert) { + assert.expect(3); run(function() { env.store.push({ @@ -242,14 +244,14 @@ test("snapshot.belongsTo() returns a snapshot if relationship is set", function( var snapshot = comment._createSnapshot(); var relationship = snapshot.belongsTo('post'); - ok(relationship instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); - equal(relationship.id, '1', 'post id is correct'); - equal(relationship.attr('title'), 'Hello World', 'post title is correct'); + assert.ok(relationship instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); + assert.equal(relationship.id, '1', 'post id is correct'); + assert.equal(relationship.attr('title'), 'Hello World', 'post title is correct'); }); }); -test("snapshot.belongsTo() returns null if relationship is deleted", function() { - expect(1); +test("snapshot.belongsTo() returns null if relationship is deleted", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -280,12 +282,12 @@ test("snapshot.belongsTo() returns null if relationship is deleted", function() var snapshot = comment._createSnapshot(); var relationship = snapshot.belongsTo('post'); - equal(relationship, null, 'relationship unset after deleted'); + assert.equal(relationship, null, 'relationship unset after deleted'); }); }); -test("snapshot.belongsTo() returns undefined if relationship is a link", function() { - expect(1); +test("snapshot.belongsTo() returns undefined if relationship is a link", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -308,12 +310,12 @@ test("snapshot.belongsTo() returns undefined if relationship is a link", functio var snapshot = comment._createSnapshot(); var relationship = snapshot.belongsTo('post'); - equal(relationship, undefined, 'relationship is undefined'); + assert.equal(relationship, undefined, 'relationship is undefined'); }); }); -test("snapshot.belongsTo() throws error if relation doesn't exist", function() { - expect(1); +test("snapshot.belongsTo() throws error if relation doesn't exist", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -328,14 +330,14 @@ test("snapshot.belongsTo() throws error if relation doesn't exist", function() { var post = env.store.peekRecord('post', 1); var snapshot = post._createSnapshot(); - throws(function() { + assert.throws(function() { snapshot.belongsTo('unknown'); }, /has no belongsTo relationship named 'unknown'/, 'throws error'); }); }); -test("snapshot.belongsTo() returns a snapshot if relationship link has been fetched", function() { - expect(2); +test("snapshot.belongsTo() returns a snapshot if relationship link has been fetched", function(assert) { + assert.expect(2); env.adapter.findBelongsTo = function(store, snapshot, link, relationship) { return Ember.RSVP.resolve({ id: 1, title: 'Hello World' }); @@ -364,14 +366,14 @@ test("snapshot.belongsTo() returns a snapshot if relationship link has been fetc var snapshot = comment._createSnapshot(); var relationship = snapshot.belongsTo('post'); - ok(relationship instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); - equal(relationship.id, '1', 'post id is correct'); + assert.ok(relationship instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); + assert.equal(relationship.id, '1', 'post id is correct'); }); }); }); -test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when adding an object to a hasMany relationship", function() { - expect(4); +test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when adding an object to a hasMany relationship", function(assert) { + assert.expect(4); run(function() { env.store.push({ @@ -401,17 +403,17 @@ test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when adding var hasManyRelationship = postSnapshot.hasMany('comments'); var belongsToRelationship = commentSnapshot.belongsTo('post'); - ok(hasManyRelationship instanceof Array, 'hasMany relationship is an instance of Array'); - equal(hasManyRelationship.length, 1, 'hasMany relationship contains related object'); + assert.ok(hasManyRelationship instanceof Array, 'hasMany relationship is an instance of Array'); + assert.equal(hasManyRelationship.length, 1, 'hasMany relationship contains related object'); - ok(belongsToRelationship instanceof DS.Snapshot, 'belongsTo relationship is an instance of DS.Snapshot'); - equal(belongsToRelationship.attr('title'), 'Hello World', 'belongsTo relationship contains related object'); + assert.ok(belongsToRelationship instanceof DS.Snapshot, 'belongsTo relationship is an instance of DS.Snapshot'); + assert.equal(belongsToRelationship.attr('title'), 'Hello World', 'belongsTo relationship contains related object'); }); }); }); -test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when setting an object to a belongsTo relationship", function() { - expect(4); +test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when setting an object to a belongsTo relationship", function(assert) { + assert.expect(4); run(function() { env.store.push({ @@ -440,16 +442,16 @@ test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when setting var hasManyRelationship = postSnapshot.hasMany('comments'); var belongsToRelationship = commentSnapshot.belongsTo('post'); - ok(hasManyRelationship instanceof Array, 'hasMany relationship is an instance of Array'); - equal(hasManyRelationship.length, 1, 'hasMany relationship contains related object'); + assert.ok(hasManyRelationship instanceof Array, 'hasMany relationship is an instance of Array'); + assert.equal(hasManyRelationship.length, 1, 'hasMany relationship contains related object'); - ok(belongsToRelationship instanceof DS.Snapshot, 'belongsTo relationship is an instance of DS.Snapshot'); - equal(belongsToRelationship.attr('title'), 'Hello World', 'belongsTo relationship contains related object'); + assert.ok(belongsToRelationship instanceof DS.Snapshot, 'belongsTo relationship is an instance of DS.Snapshot'); + assert.equal(belongsToRelationship.attr('title'), 'Hello World', 'belongsTo relationship contains related object'); }); }); -test("snapshot.belongsTo() returns ID if option.id is set", function() { - expect(1); +test("snapshot.belongsTo() returns ID if option.id is set", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -476,12 +478,12 @@ test("snapshot.belongsTo() returns ID if option.id is set", function() { var snapshot = comment._createSnapshot(); var relationship = snapshot.belongsTo('post', { id: true }); - equal(relationship, '1', 'relationship ID correctly returned'); + assert.equal(relationship, '1', 'relationship ID correctly returned'); }); }); -test("snapshot.belongsTo() returns null if option.id is set but relationship was deleted", function() { - expect(1); +test("snapshot.belongsTo() returns null if option.id is set but relationship was deleted", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -512,12 +514,12 @@ test("snapshot.belongsTo() returns null if option.id is set but relationship was var snapshot = comment._createSnapshot(); var relationship = snapshot.belongsTo('post', { id: true }); - equal(relationship, null, 'relationship unset after deleted'); + assert.equal(relationship, null, 'relationship unset after deleted'); }); }); -test("snapshot.hasMany() returns undefined if relationship is undefined", function() { - expect(1); +test("snapshot.hasMany() returns undefined if relationship is undefined", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -533,12 +535,12 @@ test("snapshot.hasMany() returns undefined if relationship is undefined", functi var snapshot = post._createSnapshot(); var relationship = snapshot.hasMany('comments'); - equal(relationship, undefined, 'relationship is undefined'); + assert.equal(relationship, undefined, 'relationship is undefined'); }); }); -test("snapshot.hasMany() returns empty array if relationship is empty", function() { - expect(2); +test("snapshot.hasMany() returns empty array if relationship is empty", function(assert) { + assert.expect(2); run(function() { env.store.push({ @@ -559,13 +561,13 @@ test("snapshot.hasMany() returns empty array if relationship is empty", function var snapshot = post._createSnapshot(); var relationship = snapshot.hasMany('comments'); - ok(relationship instanceof Array, 'relationship is an instance of Array'); - equal(relationship.length, 0, 'relationship is empty'); + assert.ok(relationship instanceof Array, 'relationship is an instance of Array'); + assert.equal(relationship.length, 0, 'relationship is empty'); }); }); -test("snapshot.hasMany() returns array of snapshots if relationship is set", function() { - expect(5); +test("snapshot.hasMany() returns array of snapshots if relationship is set", function(assert) { + assert.expect(5); run(function() { env.store.push({ @@ -601,20 +603,20 @@ test("snapshot.hasMany() returns array of snapshots if relationship is set", fun var snapshot = post._createSnapshot(); var relationship = snapshot.hasMany('comments'); - ok(relationship instanceof Array, 'relationship is an instance of Array'); - equal(relationship.length, 2, 'relationship has two items'); + assert.ok(relationship instanceof Array, 'relationship is an instance of Array'); + assert.equal(relationship.length, 2, 'relationship has two items'); var relationship1 = relationship[0]; - ok(relationship1 instanceof DS.Snapshot, 'relationship item is an instance of DS.Snapshot'); + assert.ok(relationship1 instanceof DS.Snapshot, 'relationship item is an instance of DS.Snapshot'); - equal(relationship1.id, '1', 'relationship item id is correct'); - equal(relationship1.attr('body'), 'This is the first comment', 'relationship item body is correct'); + assert.equal(relationship1.id, '1', 'relationship item id is correct'); + assert.equal(relationship1.attr('body'), 'This is the first comment', 'relationship item body is correct'); }); }); -test("snapshot.hasMany() returns empty array if relationship records are deleted", function() { - expect(2); +test("snapshot.hasMany() returns empty array if relationship records are deleted", function(assert) { + assert.expect(2); run(function() { env.store.push({ @@ -656,13 +658,13 @@ test("snapshot.hasMany() returns empty array if relationship records are deleted var snapshot = post._createSnapshot(); var relationship = snapshot.hasMany('comments'); - ok(relationship instanceof Array, 'relationship is an instance of Array'); - equal(relationship.length, 0, 'relationship is empty'); + assert.ok(relationship instanceof Array, 'relationship is an instance of Array'); + assert.equal(relationship.length, 0, 'relationship is empty'); }); }); -test("snapshot.hasMany() returns array of IDs if option.ids is set", function() { - expect(1); +test("snapshot.hasMany() returns array of IDs if option.ids is set", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -686,12 +688,12 @@ test("snapshot.hasMany() returns array of IDs if option.ids is set", function() var snapshot = post._createSnapshot(); var relationship = snapshot.hasMany('comments', { ids: true }); - deepEqual(relationship, ['2', '3'], 'relationship IDs correctly returned'); + assert.deepEqual(relationship, ['2', '3'], 'relationship IDs correctly returned'); }); }); -test("snapshot.hasMany() returns empty array of IDs if option.ids is set but relationship records were deleted", function() { - expect(2); +test("snapshot.hasMany() returns empty array of IDs if option.ids is set but relationship records were deleted", function(assert) { + assert.expect(2); run(function() { env.store.push({ @@ -733,13 +735,13 @@ test("snapshot.hasMany() returns empty array of IDs if option.ids is set but rel var snapshot = post._createSnapshot(); var relationship = snapshot.hasMany('comments', { ids: true }); - ok(relationship instanceof Array, 'relationship is an instance of Array'); - equal(relationship.length, 0, 'relationship is empty'); + assert.ok(relationship instanceof Array, 'relationship is an instance of Array'); + assert.equal(relationship.length, 0, 'relationship is empty'); }); }); -test("snapshot.hasMany() returns undefined if relationship is a link", function() { - expect(1); +test("snapshot.hasMany() returns undefined if relationship is a link", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -762,12 +764,12 @@ test("snapshot.hasMany() returns undefined if relationship is a link", function( var snapshot = post._createSnapshot(); var relationship = snapshot.hasMany('comments'); - equal(relationship, undefined, 'relationship is undefined'); + assert.equal(relationship, undefined, 'relationship is undefined'); }); }); -test("snapshot.hasMany() returns array of snapshots if relationship link has been fetched", function() { - expect(2); +test("snapshot.hasMany() returns array of snapshots if relationship link has been fetched", function(assert) { + assert.expect(2); env.adapter.findHasMany = function(store, snapshot, link, relationship) { return Ember.RSVP.resolve([{ id: 2, body: 'This is comment' }]); @@ -796,14 +798,14 @@ test("snapshot.hasMany() returns array of snapshots if relationship link has bee var snapshot = post._createSnapshot(); var relationship = snapshot.hasMany('comments'); - ok(relationship instanceof Array, 'relationship is an instance of Array'); - equal(relationship.length, 1, 'relationship has one item'); + assert.ok(relationship instanceof Array, 'relationship is an instance of Array'); + assert.equal(relationship.length, 1, 'relationship has one item'); }); }); }); -test("snapshot.hasMany() throws error if relation doesn't exist", function() { - expect(1); +test("snapshot.hasMany() throws error if relation doesn't exist", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -818,14 +820,14 @@ test("snapshot.hasMany() throws error if relation doesn't exist", function() { var post = env.store.peekRecord('post', 1); var snapshot = post._createSnapshot(); - throws(function() { + assert.throws(function() { snapshot.hasMany('unknown'); }, /has no hasMany relationship named 'unknown'/, 'throws error'); }); }); -test("snapshot.hasMany() respects the order of items in the relationship", function() { - expect(3); +test("snapshot.hasMany() respects the order of items in the relationship", function(assert) { + assert.expect(3); run(function() { env.store.push({ @@ -873,14 +875,14 @@ test("snapshot.hasMany() respects the order of items in the relationship", funct var snapshot = post._createSnapshot(); var relationship = snapshot.hasMany('comments'); - equal(relationship[0].id, '3', 'order of comment 3 is correct'); - equal(relationship[1].id, '1', 'order of comment 1 is correct'); - equal(relationship[2].id, '2', 'order of comment 2 is correct'); + assert.equal(relationship[0].id, '3', 'order of comment 3 is correct'); + assert.equal(relationship[1].id, '1', 'order of comment 1 is correct'); + assert.equal(relationship[2].id, '2', 'order of comment 2 is correct'); }); }); -test("snapshot.eachAttribute() proxies to record", function() { - expect(1); +test("snapshot.eachAttribute() proxies to record", function(assert) { + assert.expect(1); run(function() { env.store.push({ @@ -899,12 +901,12 @@ test("snapshot.eachAttribute() proxies to record", function() { snapshot.eachAttribute(function(name) { attributes.push(name); }); - deepEqual(attributes, ['author', 'title'], 'attributes are iterated correctly'); + assert.deepEqual(attributes, ['author', 'title'], 'attributes are iterated correctly'); }); }); -test("snapshot.eachRelationship() proxies to record", function() { - expect(2); +test("snapshot.eachRelationship() proxies to record", function(assert) { + assert.expect(2); var getRelationships = function(snapshot) { var relationships = []; @@ -935,18 +937,18 @@ test("snapshot.eachRelationship() proxies to record", function() { var snapshot; snapshot = comment._createSnapshot(); - deepEqual(getRelationships(snapshot), ['post'], 'relationships are iterated correctly'); + assert.deepEqual(getRelationships(snapshot), ['post'], 'relationships are iterated correctly'); snapshot = post._createSnapshot(); - deepEqual(getRelationships(snapshot), ['comments'], 'relationships are iterated correctly'); + assert.deepEqual(getRelationships(snapshot), ['comments'], 'relationships are iterated correctly'); }); }); -test("snapshot.belongsTo() does not trigger a call to store.scheduleFetch", function() { - expect(0); +test("snapshot.belongsTo() does not trigger a call to store.scheduleFetch", function(assert) { + assert.expect(0); env.store.scheduleFetch = function() { - ok(false, 'store.scheduleFetch should not be called'); + assert.ok(false, 'store.scheduleFetch should not be called'); }; run(function() { @@ -971,11 +973,11 @@ test("snapshot.belongsTo() does not trigger a call to store.scheduleFetch", func }); }); -test("snapshot.hasMany() does not trigger a call to store.scheduleFetch", function() { - expect(0); +test("snapshot.hasMany() does not trigger a call to store.scheduleFetch", function(assert) { + assert.expect(0); env.store.scheduleFetch = function() { - ok(false, 'store.scheduleFetch should not be called'); + assert.ok(false, 'store.scheduleFetch should not be called'); }; run(function() { @@ -1003,8 +1005,8 @@ test("snapshot.hasMany() does not trigger a call to store.scheduleFetch", functi }); }); -test("snapshot.serialize() serializes itself", function() { - expect(2); +test("snapshot.serialize() serializes itself", function(assert) { + assert.expect(2); run(function() { env.store.push({ @@ -1021,7 +1023,7 @@ test("snapshot.serialize() serializes itself", function() { post.set('title', 'New Title'); - deepEqual(snapshot.serialize(), { author: undefined, title: 'Hello World' }, 'shapshot serializes correctly'); - deepEqual(snapshot.serialize({ includeId: true }), { id: "1", author: undefined, title: 'Hello World' }, 'serialize takes options'); + assert.deepEqual(snapshot.serialize(), { author: undefined, title: 'Hello World' }, 'shapshot serializes correctly'); + assert.deepEqual(snapshot.serialize({ includeId: true }), { id: "1", author: undefined, title: 'Hello World' }, 'serialize takes options'); }); }); diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index c113564e8e1..ebd2f34f1fa 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var store, env; @@ -32,7 +34,7 @@ function initializeStore(adapter) { } module("integration/store - destroy", { - setup: function() { + beforeEach: function() { initializeStore(DS.Adapter.extend()); } }); @@ -55,7 +57,7 @@ function tap(obj, methodName, callback) { } asyncTest("destroying record during find doesn't cause error", function() { - expect(0); + assert.expect(0); var TestAdapter = DS.Adapter.extend({ findRecord: function(store, type, id, snapshot) { @@ -83,7 +85,7 @@ asyncTest("destroying record during find doesn't cause error", function() { }); asyncTest("find calls do not resolve when the store is destroyed", function() { - expect(0); + assert.expect(0); var TestAdapter = DS.Adapter.extend({ findRecord: function(store, type, id, snapshot) { @@ -114,7 +116,7 @@ asyncTest("find calls do not resolve when the store is destroyed", function() { }); -test("destroying the store correctly cleans everything up", function() { +test("destroying the store correctly cleans everything up", function(assert) { var car, person; env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { @@ -179,27 +181,27 @@ test("destroying the store correctly cleans everything up", function() { store.findRecord('person', 2); }); - equal(personWillDestroy.called.length, 0, 'expected person.willDestroy to not have been called'); - equal(carWillDestroy.called.length, 0, 'expected car.willDestroy to not have been called'); - equal(carsWillDestroy.called.length, 0, 'expected cars.willDestroy to not have been called'); - equal(adapterPopulatedPeopleWillDestroy.called.length, 0, 'expected adapterPopulatedPeople.willDestroy to not have been called'); - equal(filterdPeopleWillDestroy.called.length, 0, 'expected filterdPeople.willDestroy to not have been called'); + assert.equal(personWillDestroy.called.length, 0, 'expected person.willDestroy to not have been called'); + assert.equal(carWillDestroy.called.length, 0, 'expected car.willDestroy to not have been called'); + assert.equal(carsWillDestroy.called.length, 0, 'expected cars.willDestroy to not have been called'); + assert.equal(adapterPopulatedPeopleWillDestroy.called.length, 0, 'expected adapterPopulatedPeople.willDestroy to not have been called'); + assert.equal(filterdPeopleWillDestroy.called.length, 0, 'expected filterdPeople.willDestroy to not have been called'); - equal(filterdPeople.get('length'), 2, 'expected filterdPeople to have 2 entries'); + assert.equal(filterdPeople.get('length'), 2, 'expected filterdPeople to have 2 entries'); - equal(car.get('person'), person, "expected car's person to be the correct person"); - equal(person.get('cars.firstObject'), car, " expected persons cars's firstRecord to be the correct car"); + assert.equal(car.get('person'), person, "expected car's person to be the correct person"); + assert.equal(person.get('cars.firstObject'), car, " expected persons cars's firstRecord to be the correct car"); Ember.run(person, person.destroy); Ember.run(store, 'destroy'); - equal(car.get('person'), null, "expected car.person to no longer be present"); + assert.equal(car.get('person'), null, "expected car.person to no longer be present"); - equal(personWillDestroy.called.length, 1, 'expected person to have recieved willDestroy once'); - equal(carWillDestroy.called.length, 1, 'expected car to recieve willDestroy once'); - equal(carsWillDestroy.called.length, 1, 'expected cars to recieve willDestroy once'); - equal(adapterPopulatedPeopleWillDestroy.called.length, 1, 'expected adapterPopulatedPeople to recieve willDestroy once'); - equal(filterdPeopleWillDestroy.called.length, 1, 'expected filterdPeople.willDestroy to have been called once'); + assert.equal(personWillDestroy.called.length, 1, 'expected person to have recieved willDestroy once'); + assert.equal(carWillDestroy.called.length, 1, 'expected car to recieve willDestroy once'); + assert.equal(carsWillDestroy.called.length, 1, 'expected cars to recieve willDestroy once'); + assert.equal(adapterPopulatedPeopleWillDestroy.called.length, 1, 'expected adapterPopulatedPeople to recieve willDestroy once'); + assert.equal(filterdPeopleWillDestroy.called.length, 1, 'expected filterdPeople.willDestroy to have been called once'); }); function ajaxResponse(value) { @@ -217,8 +219,8 @@ function ajaxResponse(value) { module("integration/store - findRecord"); -test("store#findRecord fetches record from server when cached record is not present", function() { - expect(2); +test("store#findRecord fetches record from server when cached record is not present", function(assert) { + assert.expect(2); initializeStore(DS.RESTAdapter.extend()); @@ -232,17 +234,17 @@ test("store#findRecord fetches record from server when cached record is not pres }); let cachedRecordIsPresent = store.hasRecordForId('car', 20); - ok(!cachedRecordIsPresent, 'Car with id=20 should not exist'); + assert.ok(!cachedRecordIsPresent, 'Car with id=20 should not exist'); run(function() { store.findRecord('car', 20).then(function(car) { - equal(car.get('make'), 'BMC', 'Car with id=20 is now loaded'); + assert.equal(car.get('make'), 'BMC', 'Car with id=20 is now loaded'); }); }); }); -test("store#findRecord returns cached record immediately and reloads record in the background", function() { - expect(2); +test("store#findRecord returns cached record immediately and reloads record in the background", function(assert) { + assert.expect(2); run(function() { store.push({ @@ -267,22 +269,22 @@ test("store#findRecord returns cached record immediately and reloads record in t run(function() { store.findRecord('car', 1).then(function(car) { - equal(car.get('model'), 'Mini', 'cached car record is returned'); + assert.equal(car.get('model'), 'Mini', 'cached car record is returned'); }); }); run(function() { let car = store.peekRecord('car', 1); - equal(car.get('model'), 'Princess', 'car record was reloaded'); + assert.equal(car.get('model'), 'Princess', 'car record was reloaded'); }); }); -test("store#findRecord { reload: true } ignores cached record and reloads record from server", function() { - expect(2); +test("store#findRecord { reload: true } ignores cached record and reloads record from server", function(assert) { + assert.expect(2); const testAdapter = DS.RESTAdapter.extend({ shouldReloadRecord(store, type, id, snapshot) { - ok(false, 'shouldReloadRecord should not be called when { reload: true }'); + assert.ok(false, 'shouldReloadRecord should not be called when { reload: true }'); } }); @@ -310,11 +312,11 @@ test("store#findRecord { reload: true } ignores cached record and reloads record }); let cachedCar = store.peekRecord('car', 1); - equal(cachedCar.get('model'), 'Mini', 'cached car has expected model'); + assert.equal(cachedCar.get('model'), 'Mini', 'cached car has expected model'); run(function() { store.findRecord('car', 1, { reload: true }).then(function(car) { - equal(car.get('model'), 'Princess', 'cached record ignored, record reloaded via server'); + assert.equal(car.get('model'), 'Princess', 'cached record ignored, record reloaded via server'); }); }); }); @@ -335,13 +337,13 @@ test('store#findRecord call with `id` of type different than non-empty string or }); module("integration/store - findAll", { - setup: function() { + beforeEach: function() { initializeStore(DS.RESTAdapter.extend()); } }); -test("Using store#findAll with no records triggers a query", function() { - expect(2); +test("Using store#findAll with no records triggers a query", function(assert) { + assert.expect(2); ajaxResponse({ cars: [{ @@ -357,17 +359,17 @@ test("Using store#findAll with no records triggers a query", function() { }); var cars = store.peekAll('car'); - ok(!cars.get('length'), 'There is no cars in the store'); + assert.ok(!cars.get('length'), 'There is no cars in the store'); run(function() { store.findAll('car').then(function(cars) { - equal(cars.get('length'), 2, 'Two car were fetched'); + assert.equal(cars.get('length'), 2, 'Two car were fetched'); }); }); }); -test("Using store#findAll with existing records performs a query in the background, updating existing records and returning new ones", function() { - expect(4); +test("Using store#findAll with existing records performs a query in the background, updating existing records and returning new ones", function(assert) { + assert.expect(4); run(function() { store.push({ @@ -396,24 +398,24 @@ test("Using store#findAll with existing records performs a query in the backgrou }); var cars = store.peekAll('car'); - equal(cars.get('length'), 1, 'There is one car in the store'); + assert.equal(cars.get('length'), 1, 'There is one car in the store'); run(function() { store.findAll('car').then(function(cars) { - equal(cars.get('length'), 1, 'Store resolves with the existing records'); + assert.equal(cars.get('length'), 1, 'Store resolves with the existing records'); }); }); run(function() { var cars = store.peekAll('car'); - equal(cars.get('length'), 2, 'There is 2 cars in the store now'); + assert.equal(cars.get('length'), 2, 'There is 2 cars in the store now'); var mini = cars.findBy('id', '1'); - equal(mini.get('model'), 'New Mini', 'Existing records have been updated'); + assert.equal(mini.get('model'), 'New Mini', 'Existing records have been updated'); }); }); -test("store#findAll should eventually return all known records even if they are not in the adapter response", function() { - expect(5); +test("store#findAll should eventually return all known records even if they are not in the adapter response", function(assert) { + assert.expect(5); run(function() { store.push({ @@ -444,30 +446,30 @@ test("store#findAll should eventually return all known records even if they are }); var cars = store.peekAll('car'); - equal(cars.get('length'), 2, 'There is two cars in the store'); + assert.equal(cars.get('length'), 2, 'There is two cars in the store'); run(function() { store.findAll('car').then(function(cars) { - equal(cars.get('length'), 2, 'It returns all cars'); + assert.equal(cars.get('length'), 2, 'It returns all cars'); var carsInStore = store.peekAll('car'); - equal(carsInStore.get('length'), 2, 'There is 2 cars in the store'); + assert.equal(carsInStore.get('length'), 2, 'There is 2 cars in the store'); }); }); run(function() { var cars = store.peekAll('car'); var mini = cars.findBy('id', '1'); - equal(mini.get('model'), 'New Mini', 'Existing records have been updated'); + assert.equal(mini.get('model'), 'New Mini', 'Existing records have been updated'); var carsInStore = store.peekAll('car'); - equal(carsInStore.get('length'), 2, 'There is 2 cars in the store'); + assert.equal(carsInStore.get('length'), 2, 'There is 2 cars in the store'); }); }); -test("Using store#fetch on an empty record calls find", function() { - expect(2); +test("Using store#fetch on an empty record calls find", function(assert) { + assert.expect(2); ajaxResponse({ cars: [{ @@ -497,42 +499,42 @@ test("Using store#fetch on an empty record calls find", function() { }); var car = store.recordForId('car', 20); - ok(car.get('isEmpty'), 'Car with id=20 should be empty'); + assert.ok(car.get('isEmpty'), 'Car with id=20 should be empty'); run(function() { store.findRecord('car', 20, { reload: true }).then(function (car) { - equal(car.get('make'), 'BMCW', 'Car with id=20 is now loaded'); + assert.equal(car.get('make'), 'BMCW', 'Car with id=20 is now loaded'); }); }); }); -test("Using store#adapterFor should not throw an error when looking up the application adapter", function() { - expect(1); +test("Using store#adapterFor should not throw an error when looking up the application adapter", function(assert) { + assert.expect(1); run(function() { var applicationAdapter = store.adapterFor('application'); - ok(applicationAdapter); + assert.ok(applicationAdapter); }); }); -test("Using store#serializerFor should not throw an error when looking up the application serializer", function() { - expect(1); +test("Using store#serializerFor should not throw an error when looking up the application serializer", function(assert) { + assert.expect(1); run(function() { var applicationSerializer = store.serializerFor('application'); - ok(applicationSerializer); + assert.ok(applicationSerializer); }); }); module("integration/store - deleteRecord", { - setup: function() { + beforeEach: function() { initializeStore(DS.RESTAdapter.extend()); } }); -test("Using store#deleteRecord should mark the model for removal", function() { - expect(3); +test("Using store#deleteRecord should mark the model for removal", function(assert) { + assert.expect(3); var person; run(function() { @@ -548,7 +550,7 @@ test("Using store#deleteRecord should mark the model for removal", function() { person = store.peekRecord('person', 1); }); - ok(store.hasRecordForId('person', 1), 'expected the record to be in the store'); + assert.ok(store.hasRecordForId('person', 1), 'expected the record to be in the store'); var personDeleteRecord = tap(person, 'deleteRecord'); @@ -556,13 +558,13 @@ test("Using store#deleteRecord should mark the model for removal", function() { store.deleteRecord(person); }); - equal(personDeleteRecord.called.length, 1, 'expected person.deleteRecord to have been called'); - ok(person.get('isDeleted'), 'expect person to be isDeleted'); + assert.equal(personDeleteRecord.called.length, 1, 'expected person.deleteRecord to have been called'); + assert.ok(person.get('isDeleted'), 'expect person to be isDeleted'); }); -test("Store should accept a null value for `data`", function() { - expect(0); +test("Store should accept a null value for `data`", function(assert) { + assert.expect(0); run(function() { store.push({ diff --git a/tests/integration/store/json-api-validation-test.js b/tests/integration/store/json-api-validation-test.js index 6a405432858..fa2a1d281a5 100644 --- a/tests/integration/store/json-api-validation-test.js +++ b/tests/integration/store/json-api-validation-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var Person, store, env; var run = Ember.run; module("integration/store/json-validation", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ updatedAt: DS.attr('string'), name: DS.attr('string'), @@ -20,12 +22,12 @@ module("integration/store/json-validation", { store = env.store; }, - teardown: function() { + afterEach: function() { run(store, 'destroy'); } }); -test("when normalizeResponse returns undefined (or doesn't return), throws an error", function() { +test("when normalizeResponse returns undefined (or doesn't return), throws an error", function(assert) { env.registry.register('serializer:person', DS.Serializer.extend({ normalizeResponse() {} @@ -37,14 +39,14 @@ test("when normalizeResponse returns undefined (or doesn't return), throws an er } })); - throws(function () { + assert.throws(function () { run(function() { store.find('person', 1); }); }, /Top level of a JSON API document must be an object/); }); -test("when normalizeResponse returns null, throws an error", function() { +test("when normalizeResponse returns null, throws an error", function(assert) { env.registry.register('serializer:person', DS.Serializer.extend({ normalizeResponse() {return null;} @@ -56,7 +58,7 @@ test("when normalizeResponse returns null, throws an error", function() { } })); - throws(function () { + assert.throws(function () { run(function() { store.find('person', 1); }); @@ -64,7 +66,7 @@ test("when normalizeResponse returns null, throws an error", function() { }); -test("when normalizeResponse returns an empty object, throws an error", function() { +test("when normalizeResponse returns an empty object, throws an error", function(assert) { env.registry.register('serializer:person', DS.Serializer.extend({ normalizeResponse() {return {};} @@ -76,14 +78,14 @@ test("when normalizeResponse returns an empty object, throws an error", function } })); - throws(function () { + assert.throws(function () { run(function() { store.find('person', 1); }); }, /One or more of the following keys must be present/); }); -test("when normalizeResponse returns a document with both data and errors, throws an error", function() { +test("when normalizeResponse returns a document with both data and errors, throws an error", function(assert) { env.registry.register('serializer:person', DS.Serializer.extend({ normalizeResponse() { @@ -100,7 +102,7 @@ test("when normalizeResponse returns a document with both data and errors, throw } })); - throws(function () { + assert.throws(function () { run(function() { store.find('person', 1); }); @@ -118,7 +120,7 @@ function testPayloadError(payload, expectedError) { return Ember.RSVP.resolve(payload); } })); - throws(function () { + assert.throws(function () { run(function() { store.find('person', 1); }); @@ -127,7 +129,7 @@ function testPayloadError(payload, expectedError) { env.registry.unregister('adapter:person'); } -test("normalizeResponse 'data' cannot be undefined, a number, a string or a boolean", function() { +test("normalizeResponse 'data' cannot be undefined, a number, a string or a boolean", function(assert) { testPayloadError({ data: undefined }, /data must be/); testPayloadError({ data: 1 }, /data must be/); @@ -136,7 +138,7 @@ test("normalizeResponse 'data' cannot be undefined, a number, a string or a bool }); -test("normalizeResponse 'meta' cannot be an array, undefined, a number, a string or a boolean", function() { +test("normalizeResponse 'meta' cannot be an array, undefined, a number, a string or a boolean", function(assert) { testPayloadError({ meta: undefined }, /meta must be an object/); testPayloadError({ meta: [] }, /meta must be an object/); @@ -146,7 +148,7 @@ test("normalizeResponse 'meta' cannot be an array, undefined, a number, a string }); -test("normalizeResponse 'links' cannot be an array, undefined, a number, a string or a boolean", function() { +test("normalizeResponse 'links' cannot be an array, undefined, a number, a string or a boolean", function(assert) { testPayloadError({ data: [], links: undefined }, /links must be an object/); testPayloadError({ data: [], links: [] }, /links must be an object/); @@ -156,7 +158,7 @@ test("normalizeResponse 'links' cannot be an array, undefined, a number, a strin }); -test("normalizeResponse 'jsonapi' cannot be an array, undefined, a number, a string or a boolean", function() { +test("normalizeResponse 'jsonapi' cannot be an array, undefined, a number, a string or a boolean", function(assert) { testPayloadError({ data: [], jsonapi: undefined }, /jsonapi must be an object/); testPayloadError({ data: [], jsonapi: [] }, /jsonapi must be an object/); @@ -166,7 +168,7 @@ test("normalizeResponse 'jsonapi' cannot be an array, undefined, a number, a str }); -test("normalizeResponse 'included' cannot be an object, undefined, a number, a string or a boolean", function() { +test("normalizeResponse 'included' cannot be an object, undefined, a number, a string or a boolean", function(assert) { testPayloadError({ included: undefined }, /included must be an array/); testPayloadError({ included: {} }, /included must be an array/); @@ -176,7 +178,7 @@ test("normalizeResponse 'included' cannot be an object, undefined, a number, a s }); -test("normalizeResponse 'errors' cannot be an object, undefined, a number, a string or a boolean", function() { +test("normalizeResponse 'errors' cannot be an object, undefined, a number, a string or a boolean", function(assert) { testPayloadError({ errors: undefined }, /errors must be an array/); testPayloadError({ errors: {} }, /errors must be an array/); diff --git a/tests/integration/store/query-record-test.js b/tests/integration/store/query-record-test.js index d7f022f0708..4f851b38d17 100644 --- a/tests/integration/store/query-record-test.js +++ b/tests/integration/store/query-record-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var Person, store, env; var run = Ember.run; module("integration/store/query-record - Query one record with a query hash", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ updatedAt: DS.attr('string'), name: DS.attr('string'), @@ -20,29 +22,29 @@ module("integration/store/query-record - Query one record with a query hash", { store = env.store; }, - teardown: function() { + afterEach: function() { run(store, 'destroy'); } }); -test("It raises an assertion when no type is passed", function() { +test("It raises an assertion when no type is passed", function(assert) { expectAssertion(function() { store.queryRecord(); }, "You need to pass a type to the store's queryRecord method"); }); -test("It raises an assertion when no query hash is passed", function() { +test("It raises an assertion when no query hash is passed", function(assert) { expectAssertion(function() { store.queryRecord('person'); }, "You need to pass a query hash to the store's queryRecord method"); }); -test("When a record is requested, the adapter's queryRecord method should be called.", function() { - expect(1); +test("When a record is requested, the adapter's queryRecord method should be called.", function(assert) { + assert.expect(1); env.registry.register('adapter:person', DS.Adapter.extend({ queryRecord: function(store, type, query) { - equal(type, Person, "the query method is called with the correct type"); + assert.equal(type, Person, "the query method is called with the correct type"); return Ember.RSVP.resolve({ id: 1, name: "Peter Wagenet" }); } })); @@ -52,7 +54,7 @@ test("When a record is requested, the adapter's queryRecord method should be cal }); }); -test("When a record is requested, and the promise is rejected, .queryRecord() is rejected.", function() { +test("When a record is requested, and the promise is rejected, .queryRecord() is rejected.", function(assert) { env.registry.register('adapter:person', DS.Adapter.extend({ queryRecord: function(store, type, query) { return Ember.RSVP.reject(); @@ -61,17 +63,17 @@ test("When a record is requested, and the promise is rejected, .queryRecord() is run(function() { store.queryRecord('person', {}).catch(function(reason) { - ok(true, "The rejection handler was called"); + assert.ok(true, "The rejection handler was called"); }); }); }); -test("When a record is requested, the serializer's normalizeQueryRecordResponse method should be called.", function() { - expect(1); +test("When a record is requested, the serializer's normalizeQueryRecordResponse method should be called.", function(assert) { + assert.expect(1); env.registry.register('serializer:person', DS.JSONAPISerializer.extend({ normalizeQueryRecordResponse: function(store, primaryModelClass, payload, id, requestType) { - equal(payload.data.id , '1', "the normalizeQueryRecordResponse method was called with the right payload"); + assert.equal(payload.data.id , '1', "the normalizeQueryRecordResponse method was called with the right payload"); return this._super(...arguments); } })); diff --git a/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js index f443672c1db..4f2570ff098 100644 --- a/tests/unit/adapter-errors-test.js +++ b/tests/unit/adapter-errors-test.js @@ -1,31 +1,33 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; module("unit/adapter-errors - DS.AdapterError"); -test("DS.AdapterError", function() { +test("DS.AdapterError", function(assert) { var error = new DS.AdapterError(); - ok(error instanceof Error); - ok(error instanceof Ember.Error); + assert.ok(error instanceof Error); + assert.ok(error instanceof Ember.Error); }); -test("DS.InvalidError", function() { +test("DS.InvalidError", function(assert) { var error = new DS.InvalidError(); - ok(error instanceof Error); - ok(error instanceof DS.AdapterError); + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); }); -test("DS.TimeoutError", function() { +test("DS.TimeoutError", function(assert) { var error = new DS.TimeoutError(); - ok(error instanceof Error); - ok(error instanceof DS.AdapterError); + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); }); -test("DS.AbortError", function() { +test("DS.AbortError", function(assert) { var error = new DS.AbortError(); - ok(error instanceof Error); - ok(error instanceof DS.AdapterError); + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); }); var errorsHash = { @@ -51,27 +53,27 @@ var errorsArray = [ } ]; -test("errorsHashToArray", function() { +test("errorsHashToArray", function(assert) { var result = DS.errorsHashToArray(errorsHash); - deepEqual(result, errorsArray); + assert.deepEqual(result, errorsArray); }); -test("errorsArrayToHash", function() { +test("errorsArrayToHash", function(assert) { var result = DS.errorsArrayToHash(errorsArray); - deepEqual(result, errorsHash); + assert.deepEqual(result, errorsHash); }); -test("errorsArrayToHash without trailing slash", function() { +test("errorsArrayToHash without trailing slash", function(assert) { var result = DS.errorsArrayToHash([ { detail: 'error message', source: { pointer: 'data/attributes/name' } } ]); - deepEqual(result, { name: ['error message'] }); + assert.deepEqual(result, { name: ['error message'] }); }); -test("DS.InvalidError will normalize errors hash will assert", function() { +test("DS.InvalidError will normalize errors hash will assert", function(assert) { var error; expectAssertion(function() { diff --git a/tests/unit/adapter-populated-record-array-test.js b/tests/unit/adapter-populated-record-array-test.js index 76195eca3da..8236089a035 100644 --- a/tests/unit/adapter-populated-record-array-test.js +++ b/tests/unit/adapter-populated-record-array-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var Person, store; @@ -12,7 +14,7 @@ var adapter = DS.Adapter.extend({ }); module("unit/adapter_populated_record_array - DS.AdapterPopulatedRecordArray", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ name: DS.attr('string') }); @@ -24,7 +26,7 @@ module("unit/adapter_populated_record_array - DS.AdapterPopulatedRecordArray", { } }); -test("when a record is deleted in an adapter populated record array, it should be removed", function() { +test("when a record is deleted in an adapter populated record array, it should be removed", function(assert) { var recordArray = store.recordArrayManager .createAdapterPopulatedRecordArray(store.modelFor('person'), null); @@ -53,20 +55,20 @@ test("when a record is deleted in an adapter populated record array, it should b recordArray.loadRecords(records); }); - equal(recordArray.get('length'), 3, "expected recordArray to contain exactly 3 records"); + assert.equal(recordArray.get('length'), 3, "expected recordArray to contain exactly 3 records"); run(function() { recordArray.get('firstObject').destroyRecord(); }); - equal(recordArray.get('length'), 2, "expected recordArray to contain exactly 2 records"); + assert.equal(recordArray.get('length'), 2, "expected recordArray to contain exactly 2 records"); }); -test('recordArray.replace() throws error', function() { +test('recordArray.replace() throws error', function(assert) { var recordArray = store.recordArrayManager .createAdapterPopulatedRecordArray(Person, null); - throws(function() { + assert.throws(function() { recordArray.replace(); }, Error("The result of a server query (on (subclass of DS.Model)) is immutable."), 'throws error'); }); diff --git a/tests/unit/adapters/build-url-mixin/path-for-type-test.js b/tests/unit/adapters/build-url-mixin/path-for-type-test.js index 79dcd0d9e3d..d50bf75a463 100644 --- a/tests/unit/adapters/build-url-mixin/path-for-type-test.js +++ b/tests/unit/adapters/build-url-mixin/path-for-type-test.js @@ -1,9 +1,11 @@ import DS from 'ember-data'; +import {module, test} from 'qunit'; + var env, adapter; module("unit/adapters/build-url-mixin/path-for-type - DS.BuildURLMixin#pathForType", { - setup: function() { + beforeEach: function() { // test for overriden pathForType methods which return null path values var customPathForType = { @@ -23,142 +25,142 @@ module("unit/adapters/build-url-mixin/path-for-type - DS.BuildURLMixin#pathForTy } }); -test('pathForType - works with camelized types', function() { - equal(adapter.pathForType('superUser'), "superUsers"); +test('pathForType - works with camelized types', function(assert) { + assert.equal(adapter.pathForType('superUser'), "superUsers"); }); -test('pathForType - works with dasherized types', function() { - equal(adapter.pathForType('super-user'), "superUsers"); +test('pathForType - works with dasherized types', function(assert) { + assert.equal(adapter.pathForType('super-user'), "superUsers"); }); -test('pathForType - works with underscored types', function() { - equal(adapter.pathForType('super_user'), "superUsers"); +test('pathForType - works with underscored types', function(assert) { + assert.equal(adapter.pathForType('super_user'), "superUsers"); }); -test('buildURL - works with empty paths', function() { - equal(adapter.buildURL('rootModel', 1), "/1"); +test('buildURL - works with empty paths', function(assert) { + assert.equal(adapter.buildURL('rootModel', 1), "/1"); }); -test('buildURL - find requestType delegates to urlForFindRecord', function() { - expect(4); +test('buildURL - find requestType delegates to urlForFindRecord', function(assert) { + assert.expect(4); var snapshotStub = { snapshot: true }; var originalMethod = adapter.urlForFindRecord; adapter.urlForFindRecord = function(id, type, snapshot) { - equal(id, 1); - equal(type, 'super-user'); - equal(snapshot, snapshotStub); + assert.equal(id, 1); + assert.equal(type, 'super-user'); + assert.equal(snapshot, snapshotStub); return originalMethod.apply(this, arguments); }; - equal(adapter.buildURL('super-user', 1, snapshotStub, 'findRecord'), '/superUsers/1'); + assert.equal(adapter.buildURL('super-user', 1, snapshotStub, 'findRecord'), '/superUsers/1'); }); -test('buildURL - findAll requestType delegates to urlForFindAll', function() { - expect(2); +test('buildURL - findAll requestType delegates to urlForFindAll', function(assert) { + assert.expect(2); var originalMethod = adapter.urlForFindAll; adapter.urlForFindAll = function(type) { - equal(type, 'super-user'); + assert.equal(type, 'super-user'); return originalMethod.apply(this, arguments); }; - equal(adapter.buildURL('super-user', null, null, 'findAll'), '/superUsers'); + assert.equal(adapter.buildURL('super-user', null, null, 'findAll'), '/superUsers'); }); -test('buildURL - query requestType delegates to urlForQuery', function() { - expect(3); +test('buildURL - query requestType delegates to urlForQuery', function(assert) { + assert.expect(3); var originalMethod = adapter.urlForQuery; var queryStub = { limit: 10 }; adapter.urlForQuery = function(query, type) { - equal(query, queryStub); - equal(type, 'super-user'); + assert.equal(query, queryStub); + assert.equal(type, 'super-user'); return originalMethod.apply(this, arguments); }; - equal(adapter.buildURL('super-user', null, null, 'query', queryStub), '/superUsers'); + assert.equal(adapter.buildURL('super-user', null, null, 'query', queryStub), '/superUsers'); }); -test('buildURL - queryRecord requestType delegates to urlForQueryRecord', function() { - expect(3); +test('buildURL - queryRecord requestType delegates to urlForQueryRecord', function(assert) { + assert.expect(3); var originalMethod = adapter.urlForQueryRecord; var queryStub = { companyId: 10 }; adapter.urlForQueryRecord = function(query, type) { - equal(query, queryStub); - equal(type, 'super-user'); + assert.equal(query, queryStub); + assert.equal(type, 'super-user'); return originalMethod.apply(this, arguments); }; - equal(adapter.buildURL('super-user', null, null, 'queryRecord', queryStub), '/superUsers'); + assert.equal(adapter.buildURL('super-user', null, null, 'queryRecord', queryStub), '/superUsers'); }); -test('buildURL - findMany requestType delegates to urlForFindMany', function() { - expect(3); +test('buildURL - findMany requestType delegates to urlForFindMany', function(assert) { + assert.expect(3); var originalMethod = adapter.urlForFindMany; var idsStub = [1, 2, 3]; adapter.urlForFindMany = function(ids, type) { - equal(ids, idsStub); - equal(type, 'super-user'); + assert.equal(ids, idsStub); + assert.equal(type, 'super-user'); return originalMethod.apply(this, arguments); }; - equal(adapter.buildURL('super-user', idsStub, null, 'findMany'), '/superUsers'); + assert.equal(adapter.buildURL('super-user', idsStub, null, 'findMany'), '/superUsers'); }); -test('buildURL - findHasMany requestType delegates to urlForFindHasMany', function() { - expect(3); +test('buildURL - findHasMany requestType delegates to urlForFindHasMany', function(assert) { + assert.expect(3); var originalMethod = adapter.urlForFindHasMany; adapter.urlForFindHasMany = function(id, type) { - equal(id, 1); - equal(type, 'super-user'); + assert.equal(id, 1); + assert.equal(type, 'super-user'); return originalMethod.apply(this, arguments); }; - equal(adapter.buildURL('super-user', 1, null, 'findHasMany'), '/superUsers/1'); + assert.equal(adapter.buildURL('super-user', 1, null, 'findHasMany'), '/superUsers/1'); }); -test('buildURL - findBelongsTo requestType delegates to urlForFindBelongsTo', function() { - expect(3); +test('buildURL - findBelongsTo requestType delegates to urlForFindBelongsTo', function(assert) { + assert.expect(3); var originalMethod = adapter.urlForFindBelongsTo; adapter.urlForFindBelongsTo = function(id, type) { - equal(id, 1); - equal(type, 'super-user'); + assert.equal(id, 1); + assert.equal(type, 'super-user'); return originalMethod.apply(this, arguments); }; - equal(adapter.buildURL('super-user', 1, null, 'findBelongsTo'), '/superUsers/1'); + assert.equal(adapter.buildURL('super-user', 1, null, 'findBelongsTo'), '/superUsers/1'); }); -test('buildURL - createRecord requestType delegates to urlForCreateRecord', function() { - expect(3); +test('buildURL - createRecord requestType delegates to urlForCreateRecord', function(assert) { + assert.expect(3); var snapshotStub = { snapshot: true }; var originalMethod = adapter.urlForCreateRecord; adapter.urlForCreateRecord = function(type, snapshot) { - equal(type, 'super-user'); - equal(snapshot, snapshotStub); + assert.equal(type, 'super-user'); + assert.equal(snapshot, snapshotStub); return originalMethod.apply(this, arguments); }; - equal(adapter.buildURL('super-user', null, snapshotStub, 'createRecord'), '/superUsers'); + assert.equal(adapter.buildURL('super-user', null, snapshotStub, 'createRecord'), '/superUsers'); }); -test('buildURL - updateRecord requestType delegates to urlForUpdateRecord', function() { - expect(4); +test('buildURL - updateRecord requestType delegates to urlForUpdateRecord', function(assert) { + assert.expect(4); var snapshotStub = { snapshot: true }; var originalMethod = adapter.urlForUpdateRecord; adapter.urlForUpdateRecord = function(id, type, snapshot) { - equal(id, 1); - equal(type, 'super-user'); - equal(snapshot, snapshotStub); + assert.equal(id, 1); + assert.equal(type, 'super-user'); + assert.equal(snapshot, snapshotStub); return originalMethod.apply(this, arguments); }; - equal(adapter.buildURL('super-user', 1, snapshotStub, 'updateRecord'), '/superUsers/1'); + assert.equal(adapter.buildURL('super-user', 1, snapshotStub, 'updateRecord'), '/superUsers/1'); }); -test('buildURL - deleteRecord requestType delegates to urlForDeleteRecord', function() { - expect(4); +test('buildURL - deleteRecord requestType delegates to urlForDeleteRecord', function(assert) { + assert.expect(4); var snapshotStub = { snapshot: true }; var originalMethod = adapter.urlForDeleteRecord; adapter.urlForDeleteRecord = function(id, type, snapshot) { - equal(id, 1); - equal(type, 'super-user'); - equal(snapshot, snapshotStub); + assert.equal(id, 1); + assert.equal(type, 'super-user'); + assert.equal(snapshot, snapshotStub); return originalMethod.apply(this, arguments); }; - equal(adapter.buildURL('super-user', 1, snapshotStub, 'deleteRecord'), '/superUsers/1'); + assert.equal(adapter.buildURL('super-user', 1, snapshotStub, 'deleteRecord'), '/superUsers/1'); }); -test('buildURL - unknown requestType', function() { - equal(adapter.buildURL('super-user', 1, null, 'unknown'), '/superUsers/1'); - equal(adapter.buildURL('super-user', null, null, 'unknown'), '/superUsers'); +test('buildURL - unknown requestType', function(assert) { + assert.equal(adapter.buildURL('super-user', 1, null, 'unknown'), '/superUsers/1'); + assert.equal(adapter.buildURL('super-user', null, null, 'unknown'), '/superUsers'); }); diff --git a/tests/unit/adapters/json-api-adapter/ajax-test.js b/tests/unit/adapters/json-api-adapter/ajax-test.js index 5a05c4d0eb2..f8a71c0c9e4 100644 --- a/tests/unit/adapters/json-api-adapter/ajax-test.js +++ b/tests/unit/adapters/json-api-adapter/ajax-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var Person, Place, store, adapter, env; var run = Ember.run; module("unit/adapters/json-api-adapter/ajax - building requests", { - setup: function() { + beforeEach: function() { Person = { modelName: 'person' }; Place = { modelName: 'place' }; env = setupStore({ adapter: DS.JSONAPIAdapter, person: Person, place: Place }); @@ -14,7 +16,7 @@ module("unit/adapters/json-api-adapter/ajax - building requests", { adapter = env.adapter; }, - teardown: function() { + afterEach: function() { run(function() { store.destroy(); env.container.destroy(); @@ -22,7 +24,7 @@ module("unit/adapters/json-api-adapter/ajax - building requests", { } }); -test("ajaxOptions() adds Accept when no other headers exist", function() { +test("ajaxOptions() adds Accept when no other headers exist", function(assert) { var url = 'example.com'; var type = 'GET'; var ajaxOptions = adapter.ajaxOptions(url, type, {}); @@ -33,10 +35,10 @@ test("ajaxOptions() adds Accept when no other headers exist", function() { } }; ajaxOptions.beforeSend(fakeXHR); - deepEqual(receivedHeaders, [['Accept', 'application/vnd.api+json']], 'headers assigned'); + assert.deepEqual(receivedHeaders, [['Accept', 'application/vnd.api+json']], 'headers assigned'); }); -test("ajaxOptions() adds Accept header to existing headers", function() { +test("ajaxOptions() adds Accept header to existing headers", function(assert) { adapter.headers = { 'Other-key': 'Other Value' }; var url = 'example.com'; var type = 'GET'; @@ -48,10 +50,10 @@ test("ajaxOptions() adds Accept header to existing headers", function() { } }; ajaxOptions.beforeSend(fakeXHR); - deepEqual(receivedHeaders, [['Accept', 'application/vnd.api+json'], ['Other-key', 'Other Value']], 'headers assigned'); + assert.deepEqual(receivedHeaders, [['Accept', 'application/vnd.api+json'], ['Other-key', 'Other Value']], 'headers assigned'); }); -test("ajaxOptions() adds Accept header to existing computed properties headers", function() { +test("ajaxOptions() adds Accept header to existing computed properties headers", function(assert) { adapter.headers = Ember.computed(function() { return { 'Other-key': 'Other Value' }; }); @@ -65,5 +67,5 @@ test("ajaxOptions() adds Accept header to existing computed properties headers", } }; ajaxOptions.beforeSend(fakeXHR); - deepEqual(receivedHeaders, [['Accept', 'application/vnd.api+json'], ['Other-key', 'Other Value']], 'headers assigned'); + assert.deepEqual(receivedHeaders, [['Accept', 'application/vnd.api+json'], ['Other-key', 'Other Value']], 'headers assigned'); }); diff --git a/tests/unit/adapters/rest-adapter/ajax-test.js b/tests/unit/adapters/rest-adapter/ajax-test.js index b11c9b4a68c..ffe43e2b7e9 100644 --- a/tests/unit/adapters/rest-adapter/ajax-test.js +++ b/tests/unit/adapters/rest-adapter/ajax-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var Person, Place, store, adapter, env; var run = Ember.run; module("unit/adapters/rest-adapter/ajax - building requests", { - setup: function() { + beforeEach: function() { Person = { modelName: 'person' }; Place = { modelName: 'place' }; env = setupStore({ adapter: DS.RESTAdapter, person: Person, place: Place }); @@ -14,7 +16,7 @@ module("unit/adapters/rest-adapter/ajax - building requests", { adapter = env.adapter; }, - teardown: function() { + afterEach: function() { run(function() { store.destroy(); env.container.destroy(); @@ -22,12 +24,12 @@ module("unit/adapters/rest-adapter/ajax - building requests", { } }); -test("When an id is searched, the correct url should be generated", function() { - expect(2); +test("When an id is searched, the correct url should be generated", function(assert) { + assert.expect(2); var count = 0; adapter.ajax = function(url, method) { - if (count === 0) { equal(url, '/people/1', "should create the correct url"); } - if (count === 1) { equal(url, '/places/1', "should create the correct url"); } + if (count === 0) { assert.equal(url, '/people/1', "should create the correct url"); } + if (count === 1) { assert.equal(url, '/places/1', "should create the correct url"); } count++; return Ember.RSVP.resolve(); }; @@ -37,10 +39,10 @@ test("When an id is searched, the correct url should be generated", function() { }); }); -test("id's should be sanatized", function() { - expect(1); +test("id's should be sanatized", function(assert) { + assert.expect(1); adapter.ajax = function(url, method) { - equal(url, '/people/..%2Fplace%2F1', "should create the correct url"); + assert.equal(url, '/people/..%2Fplace%2F1', "should create the correct url"); return Ember.RSVP.resolve(); }; run(function() { @@ -48,7 +50,7 @@ test("id's should be sanatized", function() { }); }); -test("ajaxOptions() headers are set", function() { +test("ajaxOptions() headers are set", function(assert) { adapter.headers = { 'Content-Type': 'application/json', 'Other-key': 'Other Value' }; var url = 'example.com'; var type = 'GET'; @@ -60,15 +62,15 @@ test("ajaxOptions() headers are set", function() { } }; ajaxOptions.beforeSend(fakeXHR); - deepEqual(receivedHeaders, [['Content-Type', 'application/json'], ['Other-key', 'Other Value']], 'headers assigned'); + assert.deepEqual(receivedHeaders, [['Content-Type', 'application/json'], ['Other-key', 'Other Value']], 'headers assigned'); }); -test("ajaxOptions() do not serializes data when GET", function() { +test("ajaxOptions() do not serializes data when GET", function(assert) { var url = 'example.com'; var type = 'GET'; var ajaxOptions = adapter.ajaxOptions(url, type, { data: { key: 'value' } }); - deepEqual(ajaxOptions, { + assert.deepEqual(ajaxOptions, { context: adapter, data: { key: 'value' @@ -79,12 +81,12 @@ test("ajaxOptions() do not serializes data when GET", function() { }); }); -test("ajaxOptions() serializes data when not GET", function() { +test("ajaxOptions() serializes data when not GET", function(assert) { var url = 'example.com'; var type = 'POST'; var ajaxOptions = adapter.ajaxOptions(url, type, { data: { key: 'value' } }); - deepEqual(ajaxOptions, { + assert.deepEqual(ajaxOptions, { contentType: "application/json; charset=utf-8", context: adapter, data: '{"key":"value"}', @@ -94,12 +96,12 @@ test("ajaxOptions() serializes data when not GET", function() { }); }); -test("ajaxOptions() empty data", function() { +test("ajaxOptions() empty data", function(assert) { var url = 'example.com'; var type = 'POST'; var ajaxOptions = adapter.ajaxOptions(url, type, {}); - deepEqual(ajaxOptions, { + assert.deepEqual(ajaxOptions, { context: adapter, dataType: 'json', type: 'POST', diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 4c6f105f001..77cab0d8bd8 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var GroupsAdapter, Store; @@ -7,7 +9,7 @@ var maxLength = -1; var lengths = Ember.A([]); module("unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAdapter#groupRecordsForFindMany", { - setup: function() { + beforeEach: function() { GroupsAdapter = DS.RESTAdapter.extend({ coalesceFindRequests: true, @@ -41,7 +43,7 @@ module("unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda } }); -test('groupRecordsForFindMany - findMany', function() { +test('groupRecordsForFindMany - findMany', function(assert) { Ember.run(function() { for (var i = 1; i <= 1024; i++) { @@ -49,7 +51,7 @@ test('groupRecordsForFindMany - findMany', function() { } }); - ok(lengths.every(function(len) { + assert.ok(lengths.every(function(len) { return len <= maxLength; }), "Some URLs are longer than " + maxLength + " chars"); diff --git a/tests/unit/debug-test.js b/tests/unit/debug-test.js index fada4dff728..a47669ffbaa 100644 --- a/tests/unit/debug-test.js +++ b/tests/unit/debug-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var run = Ember.run; @@ -8,7 +10,7 @@ var TestAdapter = DS.Adapter.extend(); module("Debug"); -test("_debugInfo groups the attributes and relationships correctly", function() { +test("_debugInfo groups the attributes and relationships correctly", function(assert) { var MaritalStatus = DS.Model.extend({ name: DS.attr('string') }); @@ -38,8 +40,8 @@ test("_debugInfo groups the attributes and relationships correctly", function() var propertyInfo = record._debugInfo().propertyInfo; - equal(propertyInfo.groups.length, 4); - deepEqual(propertyInfo.groups[0].properties, ['id', 'name', 'isDrugAddict']); - deepEqual(propertyInfo.groups[1].properties, ['maritalStatus']); - deepEqual(propertyInfo.groups[2].properties, ['posts']); + assert.equal(propertyInfo.groups.length, 4); + assert.deepEqual(propertyInfo.groups[0].properties, ['id', 'name', 'isDrugAddict']); + assert.deepEqual(propertyInfo.groups[1].properties, ['maritalStatus']); + assert.deepEqual(propertyInfo.groups[2].properties, ['posts']); }); diff --git a/tests/unit/many-array-test.js b/tests/unit/many-array-test.js index 3d13084be21..3449102b5c0 100644 --- a/tests/unit/many-array-test.js +++ b/tests/unit/many-array-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store; @@ -11,7 +13,7 @@ var run = Ember.run; var Post, Tag; module("unit/many_array - DS.ManyArray", { - setup: function() { + beforeEach: function() { Post = DS.Model.extend({ title: attr('string'), tags: hasMany('tag', { async: false }) @@ -35,20 +37,20 @@ module("unit/many_array - DS.ManyArray", { store = env.store; }, - teardown: function() { + afterEach: function() { run(function() { store.destroy(); }); } }); -test("manyArray.save() calls save() on all records", function() { - expect(3); +test("manyArray.save() calls save() on all records", function(assert) { + assert.expect(3); run(function() { Tag.reopen({ save: function() { - ok(true, 'record.save() was called'); + assert.ok(true, 'record.save() was called'); return Ember.RSVP.resolve(); } }); @@ -85,13 +87,13 @@ test("manyArray.save() calls save() on all records", function() { var post = store.peekRecord('post', 3); post.get('tags').save().then(function() { - ok(true, 'manyArray.save() promise resolved'); + assert.ok(true, 'manyArray.save() promise resolved'); }); }); }); -test("manyArray trigger arrayContentChange functions with the correct values", function() { - expect(12); +test("manyArray trigger arrayContentChange functions with the correct values", function(assert) { + assert.expect(12); var willChangeStartIdx; var willChangeRemoveAmt; var willChangeAddAmt; @@ -105,9 +107,9 @@ test("manyArray trigger arrayContentChange functions with the correct values", f return this._super.apply(this, arguments); }, arrayContentDidChange: function(startIdx, removeAmt, addAmt) { - equal(startIdx, willChangeStartIdx, 'WillChange and DidChange startIdx should match'); - equal(removeAmt, willChangeRemoveAmt, 'WillChange and DidChange removeAmt should match'); - equal(addAmt, willChangeAddAmt, 'WillChange and DidChange addAmt should match'); + assert.equal(startIdx, willChangeStartIdx, 'WillChange and DidChange startIdx should match'); + assert.equal(removeAmt, willChangeRemoveAmt, 'WillChange and DidChange removeAmt should match'); + assert.equal(addAmt, willChangeAddAmt, 'WillChange and DidChange addAmt should match'); return this._super.apply(this, arguments); } }); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 39762ca084f..8783d13daa6 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -9,7 +11,7 @@ var run = Ember.run; var Person, store, env; module("unit/model - DS.Model", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ name: DS.attr('string'), isDrugAddict: DS.attr('boolean') @@ -21,7 +23,7 @@ module("unit/model - DS.Model", { store = env.store; }, - teardown: function() { + afterEach: function() { run(function() { store.destroy(); }); @@ -30,18 +32,18 @@ module("unit/model - DS.Model", { } }); -test("can have a property set on it", function() { +test("can have a property set on it", function(assert) { var record; run(function() { record = store.createRecord('person'); set(record, 'name', 'bar'); }); - equal(get(record, 'name'), 'bar', "property was set on the record"); + assert.equal(get(record, 'name'), 'bar', "property was set on the record"); }); -test("setting a property on a record that has not changed does not cause it to become dirty", function() { - expect(2); +test("setting a property on a record that has not changed does not cause it to become dirty", function(assert) { + assert.expect(2); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.push({ @@ -56,18 +58,18 @@ test("setting a property on a record that has not changed does not cause it to b }); store.findRecord('person', 1).then(function(person) { - equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); + assert.equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); person.set('name', "Peter"); person.set('isDrugAddict', true); - equal(person.get('hasDirtyAttributes'), false, "record does not become dirty after setting property to old value"); + assert.equal(person.get('hasDirtyAttributes'), false, "record does not become dirty after setting property to old value"); }); }); }); -test("resetting a property on a record cause it to become clean again", function() { - expect(3); +test("resetting a property on a record cause it to become clean again", function(assert) { + assert.expect(3); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { @@ -82,17 +84,17 @@ test("resetting a property on a record cause it to become clean again", function } }); store.findRecord('person', 1).then(function(person) { - equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); + assert.equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); person.set('isDrugAddict', false); - equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting property to a new value"); + assert.equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting property to a new value"); person.set('isDrugAddict', true); - equal(person.get('hasDirtyAttributes'), false, "record becomes clean after resetting property to the old value"); + assert.equal(person.get('hasDirtyAttributes'), false, "record becomes clean after resetting property to the old value"); }); }); }); -test("a record becomes clean again only if all changed properties are reset", function() { - expect(5); +test("a record becomes clean again only if all changed properties are reset", function(assert) { + assert.expect(5); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { @@ -107,21 +109,21 @@ test("a record becomes clean again only if all changed properties are reset", fu } }); store.findRecord('person', 1).then(function(person) { - equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); + assert.equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); person.set('isDrugAddict', false); - equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting one property to a new value"); + assert.equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting one property to a new value"); person.set('name', 'Mark'); - equal(person.get('hasDirtyAttributes'), true, "record stays dirty after setting another property to a new value"); + assert.equal(person.get('hasDirtyAttributes'), true, "record stays dirty after setting another property to a new value"); person.set('isDrugAddict', true); - equal(person.get('hasDirtyAttributes'), true, "record stays dirty after resetting only one property to the old value"); + assert.equal(person.get('hasDirtyAttributes'), true, "record stays dirty after resetting only one property to the old value"); person.set('name', 'Peter'); - equal(person.get('hasDirtyAttributes'), false, "record becomes clean after resetting both properties to the old value"); + assert.equal(person.get('hasDirtyAttributes'), false, "record becomes clean after resetting both properties to the old value"); }); }); }); -test("a record reports its unique id via the `id` property", function() { - expect(1); +test("a record reports its unique id via the `id` property", function(assert) { + assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { @@ -132,13 +134,13 @@ test("a record reports its unique id via the `id` property", function() { } }); store.findRecord('person', 1).then(function(record) { - equal(get(record, 'id'), 1, "reports id as id by default"); + assert.equal(get(record, 'id'), 1, "reports id as id by default"); }); }); }); -test("a record's id is included in its toString representation", function() { - expect(1); +test("a record's id is included in its toString representation", function(assert) { + assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { @@ -149,12 +151,12 @@ test("a record's id is included in its toString representation", function() { } }); store.findRecord('person', 1).then(function(record) { - equal(record.toString(), '<(subclass of DS.Model):'+Ember.guidFor(record)+':1>', "reports id in toString"); + assert.equal(record.toString(), '<(subclass of DS.Model):'+Ember.guidFor(record)+':1>', "reports id in toString"); }); }); }); -test("trying to set an `id` attribute should raise", function() { +test("trying to set an `id` attribute should raise", function(assert) { Person = DS.Model.extend({ id: DS.attr('number'), name: DS.attr('string') @@ -180,8 +182,8 @@ test("trying to set an `id` attribute should raise", function() { }, /You may not set `id`/); }); -test("a collision of a record's id with object function's name", function() { - expect(1); +test("a collision of a record's id with object function's name", function(assert) { + assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; var hasWatchMethod = Object.prototype.watch; @@ -198,7 +200,7 @@ test("a collision of a record's id with object function's name", function() { }); store.findRecord('person', 'watch').then(function(record) { - equal(get(record, 'id'), 'watch', "record is successfully created and could be found by its id"); + assert.equal(get(record, 'id'), 'watch', "record is successfully created and could be found by its id"); }); }); } finally { @@ -222,8 +224,8 @@ test("it should use `_internalModel` and not `internalModel` to store its intern }); */ -test("it should cache attributes", function() { - expect(2); +test("it should cache attributes", function(assert) { + assert.expect(2); var Post = DS.Model.extend({ updatedAt: DS.attr('string') @@ -247,16 +249,16 @@ test("it should cache attributes", function() { run(function() { record.set('updatedAt', date); }); - deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); - strictEqual(get(record, 'updatedAt'), get(record, 'updatedAt'), "second get still returns the same object"); + assert.deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); + assert.strictEqual(get(record, 'updatedAt'), get(record, 'updatedAt'), "second get still returns the same object"); }).finally(function() { run(store, 'destroy'); }); }); }); -test("changedAttributes() return correct values", function() { - expect(4); +test("changedAttributes() return correct values", function(assert) { + assert.expect(4); var Mascot = DS.Model.extend({ name: DS.attr('string'), @@ -285,20 +287,20 @@ test("changedAttributes() return correct values", function() { mascot = store.peekRecord('mascot', 1); }); - equal(Object.keys(mascot.changedAttributes()).length, 0, 'there are no initial changes'); + assert.equal(Object.keys(mascot.changedAttributes()).length, 0, 'there are no initial changes'); run(function() { mascot.set('name', 'Tomster'); // new value mascot.set('likes', 'Ember.js'); // changed value mascot.set('isMascot', true); // same value }); var changedAttributes = mascot.changedAttributes(); - deepEqual(changedAttributes.name, [undefined, 'Tomster']); - deepEqual(changedAttributes.likes, ['JavaScript', 'Ember.js']); + assert.deepEqual(changedAttributes.name, [undefined, 'Tomster']); + assert.deepEqual(changedAttributes.likes, ['JavaScript', 'Ember.js']); run(function() { mascot.rollbackAttributes(); }); - equal(Object.keys(mascot.changedAttributes()).length, 0, 'after rollback attributes there are no changes'); + assert.equal(Object.keys(mascot.changedAttributes()).length, 0, 'after rollback attributes there are no changes'); }); function toObj(obj) { @@ -310,12 +312,12 @@ function toObj(obj) { return result; } -test("changedAttributes() works while the record is being saved", function() { - expect(1); +test("changedAttributes() works while the record is being saved", function(assert) { + assert.expect(1); var cat; var adapter = DS.Adapter.extend({ createRecord(store, model, snapshot) { - deepEqual(toObj(cat.changedAttributes()), { + assert.deepEqual(toObj(cat.changedAttributes()), { name: [undefined, 'Argon'], likes: [undefined, 'Cheese'] }); return {}; @@ -339,12 +341,12 @@ test("changedAttributes() works while the record is being saved", function() { }); }); -test("changedAttributes() works while the record is being updated", function() { - expect(1); +test("changedAttributes() works while the record is being updated", function(assert) { + assert.expect(1); var cat; var adapter = DS.Adapter.extend({ updateRecord(store, model, snapshot) { - deepEqual(toObj(cat.changedAttributes()), { name: ['Argon', 'Helia'], likes: ['Cheese', 'Mussels'] }); + assert.deepEqual(toObj(cat.changedAttributes()), { name: ['Argon', 'Helia'], likes: ['Cheese', 'Mussels'] }); return { id: '1', type: 'mascot' }; } }); @@ -376,7 +378,7 @@ test("changedAttributes() works while the record is being updated", function() { }); }); -test("a DS.Model does not require an attribute type", function() { +test("a DS.Model does not require an attribute type", function(assert) { var Tag = DS.Model.extend({ name: DS.attr() }); @@ -391,10 +393,10 @@ test("a DS.Model does not require an attribute type", function() { tag = store.createRecord('tag', { name: "test" }); }); - equal(get(tag, 'name'), "test", "the value is persisted"); + assert.equal(get(tag, 'name'), "test", "the value is persisted"); }); -test("a DS.Model can have a defaultValue without an attribute type", function() { +test("a DS.Model can have a defaultValue without an attribute type", function(assert) { var Tag = DS.Model.extend({ name: DS.attr({ defaultValue: "unknown" }) }); @@ -408,11 +410,11 @@ test("a DS.Model can have a defaultValue without an attribute type", function() tag = store.createRecord('tag'); }); - equal(get(tag, 'name'), "unknown", "the default value is found"); + assert.equal(get(tag, 'name'), "unknown", "the default value is found"); }); -test("Calling attr(), belongsTo() or hasMany() throws a warning", function() { - expect(3); +test("Calling attr(), belongsTo() or hasMany() throws a warning", function(assert) { + assert.expect(3); var Person = DS.Model.extend({ name: DS.attr('string') @@ -425,21 +427,21 @@ test("Calling attr(), belongsTo() or hasMany() throws a warning", function() { run(function() { var person = store.createRecord('person', { id: 1, name: 'TomHuda' }); - throws(function() { + assert.throws(function() { person.attr(); }, /The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected/, "attr() throws a warning"); - throws(function() { + assert.throws(function() { person.belongsTo(); }, /The `belongsTo` method is not available on DS.Model, a DS.Snapshot was probably expected/, "belongTo() throws a warning"); - throws(function() { + assert.throws(function() { person.hasMany(); }, /The `hasMany` method is not available on DS.Model, a DS.Snapshot was probably expected/, "hasMany() throws a warning"); }); }); -test("supports pushedData in root.deleted.uncommitted", function() { +test("supports pushedData in root.deleted.uncommitted", function(assert) { var record; var hash = { data: { @@ -451,12 +453,12 @@ test("supports pushedData in root.deleted.uncommitted", function() { record = store.push(hash); record.deleteRecord(); store.push(hash); - equal(get(record, 'currentState.stateName'), 'root.deleted.uncommitted', + assert.equal(get(record, 'currentState.stateName'), 'root.deleted.uncommitted', 'record accepts pushedData is in root.deleted.uncommitted state'); }); }); -test("currentState is accessible when the record is created", function() { +test("currentState is accessible when the record is created", function(assert) { var record; var hash = { data: { @@ -466,13 +468,13 @@ test("currentState is accessible when the record is created", function() { }; run(function() { record = store.push(hash); - equal(get(record, 'currentState.stateName'), 'root.loaded.saved', + assert.equal(get(record, 'currentState.stateName'), 'root.loaded.saved', 'records pushed into the store start in the loaded state'); }); }); module("unit/model - DS.Model updating", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ name: DS.attr('string') }); env = setupStore({ person: Person @@ -502,7 +504,7 @@ module("unit/model - DS.Model updating", { }); }); }, - teardown: function() { + afterEach: function() { run(function() { store.destroy(); Person = null; @@ -511,19 +513,19 @@ module("unit/model - DS.Model updating", { } }); -test("a DS.Model can update its attributes", function() { - expect(1); +test("a DS.Model can update its attributes", function(assert) { + assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.findRecord('person', 2).then(function(person) { set(person, 'name', "Brohuda Katz"); - equal(get(person, 'name'), "Brohuda Katz", "setting took hold"); + assert.equal(get(person, 'name'), "Brohuda Katz", "setting took hold"); }); }); }); -test("a DS.Model can have a defaultValue", function() { +test("a DS.Model can have a defaultValue", function(assert) { var Tag = DS.Model.extend({ name: DS.attr('string', { defaultValue: "unknown" }) }); @@ -537,16 +539,16 @@ test("a DS.Model can have a defaultValue", function() { tag = store.createRecord('tag'); }); - equal(get(tag, 'name'), "unknown", "the default value is found"); + assert.equal(get(tag, 'name'), "unknown", "the default value is found"); run(function() { set(tag, 'name', null); }); - equal(get(tag, 'name'), null, "null doesn't shadow defaultValue"); + assert.equal(get(tag, 'name'), null, "null doesn't shadow defaultValue"); }); -test("a DS.model can define 'setUnknownProperty'", function() { +test("a DS.model can define 'setUnknownProperty'", function(assert) { var tag; var Tag = DS.Model.extend({ name: DS.attr("string"), @@ -567,10 +569,10 @@ test("a DS.model can define 'setUnknownProperty'", function() { set(tag, "title", "new"); }); - equal(get(tag, "name"), "new", "setUnknownProperty not triggered"); + assert.equal(get(tag, "name"), "new", "setUnknownProperty not triggered"); }); -test("a defaultValue for an attribute can be a function", function() { +test("a defaultValue for an attribute can be a function", function(assert) { var Tag = DS.Model.extend({ createdAt: DS.attr('string', { defaultValue: function() { @@ -587,17 +589,17 @@ test("a defaultValue for an attribute can be a function", function() { run(function() { tag = store.createRecord('tag'); }); - equal(get(tag, 'createdAt'), "le default value", "the defaultValue function is evaluated"); + assert.equal(get(tag, 'createdAt'), "le default value", "the defaultValue function is evaluated"); }); -test("a defaultValue function gets the record, options, and key", function() { - expect(2); +test("a defaultValue function gets the record, options, and key", function(assert) { + assert.expect(2); var Tag = DS.Model.extend({ createdAt: DS.attr('string', { defaultValue: function(record, options, key) { - deepEqual(record, tag, "the record is passed in properly"); - equal(key, 'createdAt', "the attribute being defaulted is passed in properly"); + assert.deepEqual(record, tag, "the record is passed in properly"); + assert.equal(key, 'createdAt', "the attribute being defaulted is passed in properly"); return "le default value"; } }) @@ -615,7 +617,7 @@ test("a defaultValue function gets the record, options, and key", function() { get(tag, 'createdAt'); }); -test("a complex object defaultValue is deprecated ", function() { +test("a complex object defaultValue is deprecated ", function(assert) { var Tag = DS.Model.extend({ tagInfo: DS.attr({ defaultValue: [] }) }); @@ -633,7 +635,7 @@ test("a complex object defaultValue is deprecated ", function() { }, /Non primitive defaultValues are deprecated/); }); -test("a null defaultValue is not deprecated", function() { +test("a null defaultValue is not deprecated", function(assert) { var Tag = DS.Model.extend({ tagInfo: DS.attr({ defaultValue: null }) }); @@ -647,10 +649,10 @@ test("a null defaultValue is not deprecated", function() { tag = store.createRecord('tag'); }); expectNoDeprecation(); - equal(get(tag, 'tagInfo'), null); + assert.equal(get(tag, 'tagInfo'), null); }); -test("setting a property to undefined on a newly created record should not impact the current state", function() { +test("setting a property to undefined on a newly created record should not impact the current state", function(assert) { var Tag = DS.Model.extend({ name: DS.attr('string') }); @@ -667,38 +669,38 @@ test("setting a property to undefined on a newly created record should not impac set(tag, 'name', undefined); }); - equal(get(tag, 'currentState.stateName'), "root.loaded.created.uncommitted"); + assert.equal(get(tag, 'currentState.stateName'), "root.loaded.created.uncommitted"); run(function() { tag = store.createRecord('tag', { name: undefined }); }); - equal(get(tag, 'currentState.stateName'), "root.loaded.created.uncommitted"); + assert.equal(get(tag, 'currentState.stateName'), "root.loaded.created.uncommitted"); }); // NOTE: this is a 'backdoor' test that ensures internal consistency, and should be // thrown out if/when the current `_attributes` hash logic is removed. -test("setting a property back to its original value removes the property from the `_attributes` hash", function() { - expect(3); +test("setting a property back to its original value removes the property from the `_attributes` hash", function(assert) { + assert.expect(3); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.findRecord('person', 1).then(function(person) { - equal(person._internalModel._attributes.name, undefined, "the `_attributes` hash is clean"); + assert.equal(person._internalModel._attributes.name, undefined, "the `_attributes` hash is clean"); set(person, 'name', "Niceguy Dale"); - equal(person._internalModel._attributes.name, "Niceguy Dale", "the `_attributes` hash contains the changed value"); + assert.equal(person._internalModel._attributes.name, "Niceguy Dale", "the `_attributes` hash contains the changed value"); set(person, 'name', "Scumbag Dale"); - equal(person._internalModel._attributes.name, undefined, "the `_attributes` hash is reset"); + assert.equal(person._internalModel._attributes.name, undefined, "the `_attributes` hash is reset"); }); }); }); module("unit/model - with a simple Person model", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ name: DS.attr('string') }); @@ -729,7 +731,7 @@ module("unit/model - with a simple Person model", { }); }); }, - teardown: function() { + afterEach: function() { run(function() { store.destroy(); Person = null; @@ -738,14 +740,14 @@ module("unit/model - with a simple Person model", { } }); -test("can ask if record with a given id is loaded", function() { - equal(store.recordIsLoaded('person', 1), true, 'should have person with id 1'); - equal(store.recordIsLoaded('person', 1), true, 'should have person with id 1'); - equal(store.recordIsLoaded('person', 4), false, 'should not have person with id 4'); - equal(store.recordIsLoaded('person', 4), false, 'should not have person with id 4'); +test("can ask if record with a given id is loaded", function(assert) { + assert.equal(store.recordIsLoaded('person', 1), true, 'should have person with id 1'); + assert.equal(store.recordIsLoaded('person', 1), true, 'should have person with id 1'); + assert.equal(store.recordIsLoaded('person', 4), false, 'should not have person with id 4'); + assert.equal(store.recordIsLoaded('person', 4), false, 'should not have person with id 4'); }); -test("a listener can be added to a record", function() { +test("a listener can be added to a record", function(assert) { var count = 0; var F = function() { count++; }; var record; @@ -759,16 +761,16 @@ test("a listener can be added to a record", function() { record.trigger('event!'); }); - equal(count, 1, "the event was triggered"); + assert.equal(count, 1, "the event was triggered"); run(function() { record.trigger('event!'); }); - equal(count, 2, "the event was triggered"); + assert.equal(count, 2, "the event was triggered"); }); -test("when an event is triggered on a record the method with the same name is invoked with arguments", function() { +test("when an event is triggered on a record the method with the same name is invoked with arguments", function(assert) { var count = 0; var F = function() { count++; }; var record; @@ -783,10 +785,10 @@ test("when an event is triggered on a record the method with the same name is in record.trigger('eventNamedMethod'); }); - equal(count, 1, "the corresponding method was called"); + assert.equal(count, 1, "the corresponding method was called"); }); -test("when a method is invoked from an event with the same name the arguments are passed through", function() { +test("when a method is invoked from an event with the same name the arguments are passed through", function(assert) { var eventMethodArgs = null; var F = function() { eventMethodArgs = arguments; @@ -803,8 +805,8 @@ test("when a method is invoked from an event with the same name the arguments ar record.trigger('eventThatTriggersMethod', 1, 2); }); - equal(eventMethodArgs[0], 1); - equal(eventMethodArgs[1], 2); + assert.equal(eventMethodArgs[0], 1); + assert.equal(eventMethodArgs[1], 2); }); var converts = function(type, provided, expected) { @@ -826,7 +828,7 @@ var converts = function(type, provided, expected) { testStore.push(testStore.normalize('model', { id: 1, name: provided })); testStore.push(testStore.normalize('model', { id: 2 })); var record = testStore.peekRecord('model', 1); - deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); + assert.deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); }); // See: Github issue #421 @@ -858,7 +860,7 @@ var convertsFromServer = function(type, provided, expected) { run(function() { testStore.push(testStore.normalize('model', { id: "1", name: provided })); testStore.findRecord('model', 1).then(function(record) { - deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); + assert.deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); }); }); }; @@ -884,13 +886,13 @@ var convertsWhenSet = function(type, provided, expected) { }); testStore.findRecord('model', 2).then(function(record) { set(record, 'name', provided); - deepEqual(record.serialize().name, expected, type + " saves " + provided + " as " + expected); + assert.deepEqual(record.serialize().name, expected, type + " saves " + provided + " as " + expected); }); }); }; -test("a DS.Model can describe String attributes", function() { - expect(6); +test("a DS.Model can describe String attributes", function(assert) { + assert.expect(6); converts('string', "Scumbag Tom", "Scumbag Tom"); converts('string', 1, "1"); @@ -900,8 +902,8 @@ test("a DS.Model can describe String attributes", function() { convertsFromServer('string', undefined, null); }); -test("a DS.Model can describe Number attributes", function() { - expect(9); +test("a DS.Model can describe Number attributes", function(assert) { + assert.expect(9); converts('number', "1", 1); converts('number', "0", 0); @@ -914,8 +916,8 @@ test("a DS.Model can describe Number attributes", function() { converts('number', false, 0); }); -test("a DS.Model can describe Boolean attributes", function() { - expect(7); +test("a DS.Model can describe Boolean attributes", function(assert) { + assert.expect(7); converts('boolean', "1", true); converts('boolean', "", false); @@ -926,8 +928,8 @@ test("a DS.Model can describe Boolean attributes", function() { converts('boolean', false, false); }); -test("a DS.Model can describe Date attributes", function() { - expect(5); +test("a DS.Model can describe Date attributes", function(assert) { + assert.expect(5); converts('date', null, null); converts('date', undefined, undefined); @@ -958,14 +960,14 @@ test("a DS.Model can describe Date attributes", function() { run(function() { record.set('updatedAt', date); }); - deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); + assert.deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); }); }); convertsFromServer('date', dateString, date); convertsWhenSet('date', date, dateString); }); -test("don't allow setting", function() { +test("don't allow setting", function(assert) { var Person = DS.Model.extend(); var record; @@ -984,8 +986,8 @@ test("don't allow setting", function() { }, "raised error when trying to set an unsettable record"); }); -test("ensure model exits loading state, materializes data and fulfills promise only after data is available", function () { - expect(2); +test("ensure model exits loading state, materializes data and fulfills promise only after data is available", function(assert) { + assert.expect(2); var store = createStore({ adapter: DS.Adapter.extend({ @@ -998,13 +1000,13 @@ test("ensure model exits loading state, materializes data and fulfills promise o run(function() { store.findRecord('person', 1).then(function(person) { - equal(get(person, 'currentState.stateName'), 'root.loaded.saved', 'model is in loaded state'); - equal(get(person, 'isLoaded'), true, 'model is loaded'); + assert.equal(get(person, 'currentState.stateName'), 'root.loaded.saved', 'model is in loaded state'); + assert.equal(get(person, 'isLoaded'), true, 'model is loaded'); }); }); }); -test("A DS.Model can be JSONified", function() { +test("A DS.Model can be JSONified", function(assert) { var Person = DS.Model.extend({ name: DS.attr('string') }); @@ -1015,10 +1017,10 @@ test("A DS.Model can be JSONified", function() { run(function() { record = store.createRecord('person', { name: "TomHuda" }); }); - deepEqual(record.toJSON(), { name: "TomHuda" }); + assert.deepEqual(record.toJSON(), { name: "TomHuda" }); }); -test("A subclass of DS.Model can not use the `data` property", function() { +test("A subclass of DS.Model can not use the `data` property", function(assert) { var Person = DS.Model.extend({ data: DS.attr('string'), name: DS.attr('string') @@ -1033,7 +1035,7 @@ test("A subclass of DS.Model can not use the `data` property", function() { }, /`data` is a reserved property name on DS.Model objects/); }); -test("A subclass of DS.Model can not use the `store` property", function() { +test("A subclass of DS.Model can not use the `store` property", function(assert) { var Retailer = DS.Model.extend({ store: DS.attr(), name: DS.attr() @@ -1048,8 +1050,8 @@ test("A subclass of DS.Model can not use the `store` property", function() { }, /`store` is a reserved property name on DS.Model objects/); }); -test("A subclass of DS.Model can not use reserved properties", function() { - expect(3); +test("A subclass of DS.Model can not use reserved properties", function(assert) { + assert.expect(3); [ 'currentState', 'data', 'store' ].forEach(function(reservedProperty) { @@ -1067,7 +1069,7 @@ test("A subclass of DS.Model can not use reserved properties", function() { }); }); -test("Pushing a record into the store should transition it to the loaded state", function() { +test("Pushing a record into the store should transition it to the loaded state", function(assert) { var Person = DS.Model.extend({ name: DS.attr('string') }); @@ -1076,7 +1078,7 @@ test("Pushing a record into the store should transition it to the loaded state", run(function() { var person = store.createRecord('person', { id: 1, name: 'TomHuda' }); - equal(person.get('isNew'), true, 'createRecord should put records into the new state'); + assert.equal(person.get('isNew'), true, 'createRecord should put records into the new state'); store.push({ data: { type: 'person', @@ -1086,17 +1088,17 @@ test("Pushing a record into the store should transition it to the loaded state", } } }); - equal(person.get('isNew'), false, 'push should put records into the loaded state'); + assert.equal(person.get('isNew'), false, 'push should put records into the loaded state'); }); }); -test("A subclass of DS.Model throws an error when calling create() directly", function() { - throws(function() { +test("A subclass of DS.Model throws an error when calling create() directly", function(assert) { + assert.throws(function() { Person.create(); }, /You should not call `create` on a model/, "Throws an error when calling create() on model"); }); -test('toJSON looks up the JSONSerializer using the store instead of using JSONSerializer.create', function() { +test('toJSON looks up the JSONSerializer using the store instead of using JSONSerializer.create', function(assert) { var Person = DS.Model.extend({ posts: DS.hasMany('post', { async: false }) }); @@ -1131,19 +1133,19 @@ test('toJSON looks up the JSONSerializer using the store instead of using JSONSe errorThrown = true; } - ok(!errorThrown, 'error not thrown due to missing store'); - deepEqual(json, {}); + assert.ok(!errorThrown, 'error not thrown due to missing store'); + assert.deepEqual(json, {}); }); -test('accessing attributes in the initializer should not throw an error', function() { - expect(1); +test('accessing attributes in the initializer should not throw an error', function(assert) { + assert.expect(1); var Person = DS.Model.extend({ name: DS.attr('string'), init: function() { this._super.apply(this, arguments); - ok(!this.get('name')); + assert.ok(!this.get('name')); } }); @@ -1155,8 +1157,8 @@ test('accessing attributes in the initializer should not throw an error', functi run(() => store.createRecord('person')); }); -test('setting the id after model creation should correctly update the id', function () { - expect(2); +test('setting the id after model creation should correctly update the id', function(assert) { + assert.expect(2); var Person = DS.Model.extend({ name: DS.attr('string') }); @@ -1169,16 +1171,16 @@ test('setting the id after model creation should correctly update the id', funct run(function () { var person = store.createRecord('person'); - equal(person.get('id'), null, 'initial created model id should be null'); + assert.equal(person.get('id'), null, 'initial created model id should be null'); person.set('id', 'john'); - equal(person.get('id'), 'john', 'new id should be correctly set.'); + assert.equal(person.get('id'), 'john', 'new id should be correctly set.'); }); }); -test('updating the id with store.updateId should correctly when the id property is watched', function () { - expect(2); +test('updating the id with store.updateId should correctly when the id property is watched', function(assert) { + assert.expect(2); var Person = DS.Model.extend({ name: DS.attr('string'), idComputed: Ember.computed('id', function() {}) @@ -1192,16 +1194,16 @@ test('updating the id with store.updateId should correctly when the id property var person = store.createRecord('person'); person.get('idComputed'); - equal(person.get('id'), null, 'initial created model id should be null'); + assert.equal(person.get('id'), null, 'initial created model id should be null'); store.updateId(person._internalModel, { id: 'john' }); - equal(person.get('id'), 'john', 'new id should be correctly set.'); + assert.equal(person.get('id'), 'john', 'new id should be correctly set.'); }); }); -test('accessing the model id without the get function should work when id is watched', function () { - expect(2); +test('accessing the model id without the get function should work when id is watched', function(assert) { + assert.expect(2); var Person = DS.Model.extend({ name: DS.attr('string'), idComputed: Ember.computed('id', function() {}) @@ -1215,10 +1217,10 @@ test('accessing the model id without the get function should work when id is wat var person = store.createRecord('person'); person.get('idComputed'); - equal(person.get('id'), null, 'initial created model id should be null'); + assert.equal(person.get('id'), null, 'initial created model id should be null'); store.updateId(person._internalModel, { id: 'john' }); - equal(person.id, 'john', 'new id should be correctly set.'); + assert.equal(person.id, 'john', 'new id should be correctly set.'); }); }); diff --git a/tests/unit/model/errors-test.js b/tests/unit/model/errors-test.js index 6037b9927ae..e8554016b6e 100644 --- a/tests/unit/model/errors-test.js +++ b/tests/unit/model/errors-test.js @@ -1,110 +1,112 @@ import DS from 'ember-data'; +import {module, test} from 'qunit'; + var errors; module("unit/model/errors", { - setup: function() { + beforeEach: function() { errors = DS.Errors.create(); }, - teardown: function() { + afterEach: function() { } }); function becameInvalid(eventName) { if (eventName === 'becameInvalid') { - ok(true, 'becameInvalid send'); + assert.ok(true, 'becameInvalid send'); } else { - ok(false, eventName + ' is send instead of becameInvalid'); + assert.ok(false, eventName + ' is send instead of becameInvalid'); } } function becameValid(eventName) { if (eventName === 'becameValid') { - ok(true, 'becameValid send'); + assert.ok(true, 'becameValid send'); } else { - ok(false, eventName + ' is send instead of becameValid'); + assert.ok(false, eventName + ' is send instead of becameValid'); } } function unexpectedSend(eventName) { - ok(false, 'unexpected send : ' + eventName); + assert.ok(false, 'unexpected send : ' + eventName); } -test("add error", function() { - expect(6); +test("add error", function(assert) { + assert.expect(6); errors.trigger = becameInvalid; errors.add('firstName', 'error'); errors.trigger = unexpectedSend; - ok(errors.has('firstName'), 'it has firstName errors'); - equal(errors.get('length'), 1, 'it has 1 error'); + assert.ok(errors.has('firstName'), 'it has firstName errors'); + assert.equal(errors.get('length'), 1, 'it has 1 error'); errors.add('firstName', ['error1', 'error2']); - equal(errors.get('length'), 3, 'it has 3 errors'); - ok(!errors.get('isEmpty'), 'it is not empty'); + assert.equal(errors.get('length'), 3, 'it has 3 errors'); + assert.ok(!errors.get('isEmpty'), 'it is not empty'); errors.add('lastName', 'error'); errors.add('lastName', 'error'); - equal(errors.get('length'), 4, 'it has 4 errors'); + assert.equal(errors.get('length'), 4, 'it has 4 errors'); }); -test("get error", function() { - expect(8); - ok(errors.get('firstObject') === undefined, 'returns undefined'); +test("get error", function(assert) { + assert.expect(8); + assert.ok(errors.get('firstObject') === undefined, 'returns undefined'); errors.trigger = becameInvalid; errors.add('firstName', 'error'); errors.trigger = unexpectedSend; - ok(errors.get('firstName').length === 1, 'returns errors'); - deepEqual(errors.get('firstObject'), { attribute: 'firstName', message: 'error' }); + assert.ok(errors.get('firstName').length === 1, 'returns errors'); + assert.deepEqual(errors.get('firstObject'), { attribute: 'firstName', message: 'error' }); errors.add('firstName', 'error2'); - ok(errors.get('firstName').length === 2, 'returns errors'); + assert.ok(errors.get('firstName').length === 2, 'returns errors'); errors.add('lastName', 'error3'); - deepEqual(errors.toArray(), [ + assert.deepEqual(errors.toArray(), [ { attribute: 'firstName', message: 'error' }, { attribute: 'firstName', message: 'error2' }, { attribute: 'lastName', message: 'error3' } ]); - deepEqual(errors.get('firstName'), [ + assert.deepEqual(errors.get('firstName'), [ { attribute: 'firstName', message: 'error' }, { attribute: 'firstName', message: 'error2' } ]); - deepEqual(errors.get('messages'), ['error', 'error2', 'error3']); + assert.deepEqual(errors.get('messages'), ['error', 'error2', 'error3']); }); -test("remove error", function() { - expect(5); +test("remove error", function(assert) { + assert.expect(5); errors.trigger = becameInvalid; errors.add('firstName', 'error'); errors.trigger = becameValid; errors.remove('firstName'); errors.trigger = unexpectedSend; - ok(!errors.has('firstName'), 'it has no firstName errors'); - equal(errors.get('length'), 0, 'it has 0 error'); - ok(errors.get('isEmpty'), 'it is empty'); + assert.ok(!errors.has('firstName'), 'it has no firstName errors'); + assert.equal(errors.get('length'), 0, 'it has 0 error'); + assert.ok(errors.get('isEmpty'), 'it is empty'); errors.remove('firstName'); }); -test("remove same errors from different attributes", function() { - expect(5); +test("remove same errors from different attributes", function(assert) { + assert.expect(5); errors.trigger = becameInvalid; errors.add('firstName', 'error'); errors.add('lastName', 'error'); errors.trigger = unexpectedSend; - equal(errors.get('length'), 2, 'it has 2 error'); + assert.equal(errors.get('length'), 2, 'it has 2 error'); errors.remove('firstName'); - equal(errors.get('length'), 1, 'it has 1 error'); + assert.equal(errors.get('length'), 1, 'it has 1 error'); errors.trigger = becameValid; errors.remove('lastName'); - ok(errors.get('isEmpty'), 'it is empty'); + assert.ok(errors.get('isEmpty'), 'it is empty'); }); -test("clear errors", function() { - expect(5); +test("clear errors", function(assert) { + assert.expect(5); errors.trigger = becameInvalid; errors.add('firstName', ['error', 'error1']); - equal(errors.get('length'), 2, 'it has 2 errors'); + assert.equal(errors.get('length'), 2, 'it has 2 errors'); errors.trigger = becameValid; errors.clear(); errors.trigger = unexpectedSend; - ok(!errors.has('firstName'), 'it has no firstName errors'); - equal(errors.get('length'), 0, 'it has 0 error'); + assert.ok(!errors.has('firstName'), 'it has no firstName errors'); + assert.equal(errors.get('length'), 0, 'it has 0 error'); errors.clear(); }); diff --git a/tests/unit/model/internal-model-test.js b/tests/unit/model/internal-model-test.js index ca3f098ca87..cde8daabb16 100644 --- a/tests/unit/model/internal-model-test.js +++ b/tests/unit/model/internal-model-test.js @@ -1,5 +1,7 @@ import DS from 'ember-data'; +import {module, test} from 'qunit'; + module("unit/model/internal-model - Internal Model"); var mockModelFactory = { @@ -10,8 +12,8 @@ var mockModelFactory = { eachRelationship: function() { } }; -test("Materializing a model twice errors out", function() { - expect(1); +test("Materializing a model twice errors out", function(assert) { + assert.expect(1); var internalModel = new DS.InternalModel(mockModelFactory, null, null, null); internalModel.materializeRecord(); diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index a399586b212..a3de93ebde4 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -7,13 +9,13 @@ var run = Ember.run; module("unit/model/lifecycle_callbacks - Lifecycle Callbacks"); -test("a record receives a didLoad callback when it has finished loading", function() { - expect(3); +test("a record receives a didLoad callback when it has finished loading", function(assert) { + assert.expect(3); var Person = DS.Model.extend({ name: DS.attr(), didLoad: function() { - ok("The didLoad callback was called"); + assert.ok("The didLoad callback was called"); } }); @@ -30,14 +32,14 @@ test("a record receives a didLoad callback when it has finished loading", functi run(function() { store.findRecord('person', 1).then(function(person) { - equal(person.get('id'), "1", "The person's ID is available"); - equal(person.get('name'), "Foo", "The person's properties are available"); + assert.equal(person.get('id'), "1", "The person's ID is available"); + assert.equal(person.get('name'), "Foo", "The person's properties are available"); }); }); }); -test("TEMPORARY: a record receives a didLoad callback once it materializes if it wasn't materialized when loaded", function() { - expect(2); +test("TEMPORARY: a record receives a didLoad callback once it materializes if it wasn't materialized when loaded", function(assert) { + assert.expect(2); var didLoadCalled = 0; var Person = DS.Model.extend({ name: DS.attr(), @@ -52,18 +54,18 @@ test("TEMPORARY: a record receives a didLoad callback once it materializes if it run(function() { store._pushInternalModel({ id: 1, type: 'person' }); - equal(didLoadCalled, 0, "didLoad was not called"); + assert.equal(didLoadCalled, 0, "didLoad was not called"); }); run(function() { store.peekRecord('person', 1); }); run(function() { - equal(didLoadCalled, 1, "didLoad was called"); + assert.equal(didLoadCalled, 1, "didLoad was called"); }); }); -test("a record receives a didUpdate callback when it has finished updating", function() { - expect(5); +test("a record receives a didUpdate callback when it has finished updating", function(assert) { + assert.expect(5); var callCount = 0; @@ -73,8 +75,8 @@ test("a record receives a didUpdate callback when it has finished updating", fun didUpdate: function() { callCount++; - equal(get(this, 'isSaving'), false, "record should be saving"); - equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); + assert.equal(get(this, 'isSaving'), false, "record should be saving"); + assert.equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); } }); @@ -84,7 +86,7 @@ test("a record receives a didUpdate callback when it has finished updating", fun }, updateRecord: function(store, type, snapshot) { - equal(callCount, 0, "didUpdate callback was not called until didSaveRecord is called"); + assert.equal(callCount, 0, "didUpdate callback was not called until didSaveRecord is called"); return Ember.RSVP.resolve(); } @@ -99,7 +101,7 @@ test("a record receives a didUpdate callback when it has finished updating", fun run(function() { asyncPerson = store.findRecord('person', 1); }); - equal(callCount, 0, "precond - didUpdate callback was not called yet"); + assert.equal(callCount, 0, "precond - didUpdate callback was not called yet"); run(function() { asyncPerson.then(function(person) { @@ -108,27 +110,27 @@ test("a record receives a didUpdate callback when it has finished updating", fun return person.save(); }); }).then(function() { - equal(callCount, 1, "didUpdate called after update"); + assert.equal(callCount, 1, "didUpdate called after update"); }); }); }); -test("a record receives a didCreate callback when it has finished updating", function() { - expect(5); +test("a record receives a didCreate callback when it has finished updating", function(assert) { + assert.expect(5); var callCount = 0; var Person = DS.Model.extend({ didCreate: function() { callCount++; - equal(get(this, 'isSaving'), false, "record should not be saving"); - equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); + assert.equal(get(this, 'isSaving'), false, "record should not be saving"); + assert.equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); } }); var adapter = DS.Adapter.extend({ createRecord: function(store, type, snapshot) { - equal(callCount, 0, "didCreate callback was not called until didSaveRecord is called"); + assert.equal(callCount, 0, "didCreate callback was not called until didSaveRecord is called"); return Ember.RSVP.resolve(); } @@ -139,7 +141,7 @@ test("a record receives a didCreate callback when it has finished updating", fun person: Person }); - equal(callCount, 0, "precond - didCreate callback was not called yet"); + assert.equal(callCount, 0, "precond - didCreate callback was not called yet"); var person; run(function() { @@ -149,13 +151,13 @@ test("a record receives a didCreate callback when it has finished updating", fun run(function() { person.save().then(function() { - equal(callCount, 1, "didCreate called after commit"); + assert.equal(callCount, 1, "didCreate called after commit"); }); }); }); -test("a record receives a didDelete callback when it has finished deleting", function() { - expect(5); +test("a record receives a didDelete callback when it has finished deleting", function(assert) { + assert.expect(5); var callCount = 0; @@ -166,8 +168,8 @@ test("a record receives a didDelete callback when it has finished deleting", fun didDelete: function() { callCount++; - equal(get(this, 'isSaving'), false, "record should not be saving"); - equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); + assert.equal(get(this, 'isSaving'), false, "record should not be saving"); + assert.equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); } }); @@ -177,7 +179,7 @@ test("a record receives a didDelete callback when it has finished deleting", fun }, deleteRecord: function(store, type, snapshot) { - equal(callCount, 0, "didDelete callback was not called until didSaveRecord is called"); + assert.equal(callCount, 0, "didDelete callback was not called until didSaveRecord is called"); return Ember.RSVP.resolve(); } @@ -193,7 +195,7 @@ test("a record receives a didDelete callback when it has finished deleting", fun asyncPerson = store.findRecord('person', 1); }); - equal(callCount, 0, "precond - didDelete callback was not called yet"); + assert.equal(callCount, 0, "precond - didDelete callback was not called yet"); run(function() { asyncPerson.then(function(person) { @@ -202,13 +204,13 @@ test("a record receives a didDelete callback when it has finished deleting", fun return person.save(); }); }).then(function() { - equal(callCount, 1, "didDelete called after delete"); + assert.equal(callCount, 1, "didDelete called after delete"); }); }); }); -test("an uncommited record also receives a didDelete callback when it is deleted", function() { - expect(4); +test("an uncommited record also receives a didDelete callback when it is deleted", function(assert) { + assert.expect(4); var callCount = 0; @@ -218,8 +220,8 @@ test("an uncommited record also receives a didDelete callback when it is deleted didDelete: function() { callCount++; - equal(get(this, 'isSaving'), false, "record should not be saving"); - equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); + assert.equal(get(this, 'isSaving'), false, "record should not be saving"); + assert.equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); } }); @@ -233,17 +235,17 @@ test("an uncommited record also receives a didDelete callback when it is deleted person = store.createRecord('person', { name: 'Tomster' }); }); - equal(callCount, 0, "precond - didDelete callback was not called yet"); + assert.equal(callCount, 0, "precond - didDelete callback was not called yet"); run(function() { person.deleteRecord(); }); - equal(callCount, 1, "didDelete called after delete"); + assert.equal(callCount, 1, "didDelete called after delete"); }); -test("a record receives a becameInvalid callback when it became invalid", function() { - expect(5); +test("a record receives a becameInvalid callback when it became invalid", function(assert) { + assert.expect(5); var callCount = 0; @@ -254,8 +256,8 @@ test("a record receives a becameInvalid callback when it became invalid", functi becameInvalid: function() { callCount++; - equal(get(this, 'isSaving'), false, "record should not be saving"); - equal(get(this, 'hasDirtyAttributes'), true, "record should be dirty"); + assert.equal(get(this, 'isSaving'), false, "record should not be saving"); + assert.equal(get(this, 'hasDirtyAttributes'), true, "record should be dirty"); } }); @@ -265,7 +267,7 @@ test("a record receives a becameInvalid callback when it became invalid", functi }, updateRecord: function(store, type, snapshot) { - equal(callCount, 0, "becameInvalid callback was not called until recordWasInvalid is called"); + assert.equal(callCount, 0, "becameInvalid callback was not called until recordWasInvalid is called"); return Ember.RSVP.reject(new DS.InvalidError([ { @@ -288,7 +290,7 @@ test("a record receives a becameInvalid callback when it became invalid", functi run(function() { asyncPerson = store.findRecord('person', 1); }); - equal(callCount, 0, "precond - becameInvalid callback was not called yet"); + assert.equal(callCount, 0, "precond - becameInvalid callback was not called yet"); // Make sure that the error handler has a chance to attach before // save fails. @@ -299,12 +301,12 @@ test("a record receives a becameInvalid callback when it became invalid", functi return person.save(); }); }).then(null, function() { - equal(callCount, 1, "becameInvalid called after invalidating"); + assert.equal(callCount, 1, "becameInvalid called after invalidating"); }); }); }); -test("an ID of 0 is allowed", function() { +test("an ID of 0 is allowed", function(assert) { var Person = DS.Model.extend({ name: DS.attr('string') @@ -326,5 +328,5 @@ test("an ID of 0 is allowed", function() { }); }); - equal(store.peekAll('person').objectAt(0).get('name'), "Tom Dale", "found record with id 0"); + assert.equal(store.peekAll('person').objectAt(0).get('name'), "Tom Dale", "found record with id 0"); }); diff --git a/tests/unit/model/merge-test.js b/tests/unit/model/merge-test.js index 31b0dfb6002..316e2744c55 100644 --- a/tests/unit/model/merge-test.js +++ b/tests/unit/model/merge-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var Person; var run = Ember.run; module("unit/model/merge - Merging", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ name: DS.attr(), city: DS.attr() @@ -14,8 +16,8 @@ module("unit/model/merge - Merging", { } }); -test("When a record is in flight, changes can be made", function() { - expect(3); +test("When a record is in flight, changes can be made", function(assert) { + assert.expect(3); var adapter = DS.Adapter.extend({ createRecord: function(store, type, snapshot) { @@ -36,23 +38,23 @@ test("When a record is in flight, changes can be made", function() { run(function() { var promise = person.save(); - equal(person.get('name'), "Tom Dale"); + assert.equal(person.get('name'), "Tom Dale"); person.set('name', "Thomas Dale"); promise.then(function(person) { - equal(person.get('hasDirtyAttributes'), true, "The person is still dirty"); - equal(person.get('name'), "Thomas Dale", "The changes made still apply"); + assert.equal(person.get('hasDirtyAttributes'), true, "The person is still dirty"); + assert.equal(person.get('name'), "Thomas Dale", "The changes made still apply"); }); }); }); -test("Make sure snapshot is created at save time not at flush time", function() { - expect(5); +test("Make sure snapshot is created at save time not at flush time", function(assert) { + assert.expect(5); var adapter = DS.Adapter.extend({ updateRecord: function(store, type, snapshot) { - equal(snapshot.attr('name'), 'Thomas Dale'); + assert.equal(snapshot.attr('name'), 'Thomas Dale'); return Ember.RSVP.resolve(); } @@ -77,21 +79,21 @@ test("Make sure snapshot is created at save time not at flush time", function() run(function() { var promise = person.save(); - equal(person.get('name'), "Thomas Dale"); + assert.equal(person.get('name'), "Thomas Dale"); person.set('name', "Tomasz Dale"); - equal(person.get('name'), "Tomasz Dale", "the local changes applied on top"); + assert.equal(person.get('name'), "Tomasz Dale", "the local changes applied on top"); promise.then(async(function(person) { - equal(person.get('hasDirtyAttributes'), true, "The person is still dirty"); - equal(person.get('name'), "Tomasz Dale", "The local changes apply"); + assert.equal(person.get('hasDirtyAttributes'), true, "The person is still dirty"); + assert.equal(person.get('name'), "Tomasz Dale", "The local changes apply"); })); }); }); -test("When a record is in flight, pushes are applied underneath the in flight changes", function() { - expect(6); +test("When a record is in flight, pushes are applied underneath the in flight changes", function(assert) { + assert.expect(6); var adapter = DS.Adapter.extend({ updateRecord: function(store, type, snapshot) { @@ -124,7 +126,7 @@ test("When a record is in flight, pushes are applied underneath the in flight ch run(function() { var promise = person.save(); - equal(person.get('name'), "Thomas Dale"); + assert.equal(person.get('name'), "Thomas Dale"); person.set('name', "Tomasz Dale"); @@ -139,18 +141,18 @@ test("When a record is in flight, pushes are applied underneath the in flight ch } }); - equal(person.get('name'), "Tomasz Dale", "the local changes applied on top"); - equal(person.get('city'), "PDX", "the pushed change is available"); + assert.equal(person.get('name'), "Tomasz Dale", "the local changes applied on top"); + assert.equal(person.get('city'), "PDX", "the pushed change is available"); promise.then(async(function(person) { - equal(person.get('hasDirtyAttributes'), true, "The person is still dirty"); - equal(person.get('name'), "Tomasz Dale", "The local changes apply"); - equal(person.get('city'), "Portland", "The updates from the server apply on top of the previous pushes"); + assert.equal(person.get('hasDirtyAttributes'), true, "The person is still dirty"); + assert.equal(person.get('name'), "Tomasz Dale", "The local changes apply"); + assert.equal(person.get('city'), "Portland", "The updates from the server apply on top of the previous pushes"); })); }); }); -test("When a record is dirty, pushes are overridden by local changes", function() { +test("When a record is dirty, pushes are overridden by local changes", function(assert) { var store = createStore({ adapter: DS.Adapter, person: Person @@ -171,9 +173,9 @@ test("When a record is dirty, pushes are overridden by local changes", function( person.set('name', "Tomasz Dale"); }); - equal(person.get('hasDirtyAttributes'), true, "the person is currently dirty"); - equal(person.get('name'), "Tomasz Dale", "the update was effective"); - equal(person.get('city'), "San Francisco", "the original data applies"); + assert.equal(person.get('hasDirtyAttributes'), true, "the person is currently dirty"); + assert.equal(person.get('name'), "Tomasz Dale", "the update was effective"); + assert.equal(person.get('city'), "San Francisco", "the original data applies"); run(function() { store.push({ @@ -188,12 +190,12 @@ test("When a record is dirty, pushes are overridden by local changes", function( }); }); - equal(person.get('hasDirtyAttributes'), true, "the local changes are reapplied"); - equal(person.get('name'), "Tomasz Dale", "the local changes are reapplied"); - equal(person.get('city'), "Portland", "if there are no local changes, the new data applied"); + assert.equal(person.get('hasDirtyAttributes'), true, "the local changes are reapplied"); + assert.equal(person.get('name'), "Tomasz Dale", "the local changes are reapplied"); + assert.equal(person.get('city'), "Portland", "if there are no local changes, the new data applied"); }); -test("When a record is invalid, pushes are overridden by local changes", function() { +test("When a record is invalid, pushes are overridden by local changes", function(assert) { var store = createStore({ adapter: DS.Adapter, person: Person @@ -215,10 +217,10 @@ test("When a record is invalid, pushes are overridden by local changes", functio person.send('becameInvalid'); }); - equal(person.get('hasDirtyAttributes'), true, "the person is currently dirty"); - equal(person.get('isValid'), false, "the person is currently invalid"); - equal(person.get('name'), "Brondan McLoughlin", "the update was effective"); - equal(person.get('city'), "Boston", "the original data applies"); + assert.equal(person.get('hasDirtyAttributes'), true, "the person is currently dirty"); + assert.equal(person.get('isValid'), false, "the person is currently invalid"); + assert.equal(person.get('name'), "Brondan McLoughlin", "the update was effective"); + assert.equal(person.get('city'), "Boston", "the original data applies"); run(function() { store.push({ @@ -233,14 +235,14 @@ test("When a record is invalid, pushes are overridden by local changes", functio }); }); - equal(person.get('hasDirtyAttributes'), true, "the local changes are reapplied"); - equal(person.get('isValid'), false, "record is still invalid"); - equal(person.get('name'), "Brondan McLoughlin", "the local changes are reapplied"); - equal(person.get('city'), "Prague", "if there are no local changes, the new data applied"); + assert.equal(person.get('hasDirtyAttributes'), true, "the local changes are reapplied"); + assert.equal(person.get('isValid'), false, "record is still invalid"); + assert.equal(person.get('name'), "Brondan McLoughlin", "the local changes are reapplied"); + assert.equal(person.get('city'), "Prague", "if there are no local changes, the new data applied"); }); -test("A record with no changes can still be saved", function() { - expect(1); +test("A record with no changes can still be saved", function(assert) { + assert.expect(1); var adapter = DS.Adapter.extend({ updateRecord: function(store, type, snapshot) { @@ -268,13 +270,13 @@ test("A record with no changes can still be saved", function() { run(function() { person.save().then(function() { - equal(person.get('name'), "Thomas Dale", "the updates occurred"); + assert.equal(person.get('name'), "Thomas Dale", "the updates occurred"); }); }); }); -test("A dirty record can be reloaded", function() { - expect(3); +test("A dirty record can be reloaded", function(assert) { + assert.expect(3); var adapter = DS.Adapter.extend({ findRecord: function(store, type, id, snapshot) { @@ -303,9 +305,9 @@ test("A dirty record can be reloaded", function() { run(function() { person.reload().then(function() { - equal(person.get('hasDirtyAttributes'), true, "the person is dirty"); - equal(person.get('name'), "Tomasz Dale", "the local changes remain"); - equal(person.get('city'), "Portland", "the new changes apply"); + assert.equal(person.get('hasDirtyAttributes'), true, "the person is dirty"); + assert.equal(person.get('name'), "Tomasz Dale", "the local changes remain"); + assert.equal(person.get('city'), "Portland", "the new changes apply"); }); }); }); diff --git a/tests/unit/model/relationships-test.js b/tests/unit/model/relationships-test.js index 1e6fc089682..0a71035d3da 100644 --- a/tests/unit/model/relationships-test.js +++ b/tests/unit/model/relationships-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -7,7 +9,7 @@ var run = Ember.run; var Occupation, Person, store; module("unit/model/relationships - DS.Model", { - setup: function() { + beforeEach: function() { Occupation = DS.Model.extend(); Person = DS.Model.extend({ @@ -25,7 +27,7 @@ module("unit/model/relationships - DS.Model", { } }); -test("exposes a hash of the relationships on a model", function() { +test("exposes a hash of the relationships on a model", function(assert) { var person, occupation; run(function() { @@ -34,26 +36,26 @@ test("exposes a hash of the relationships on a model", function() { }); var relationships = get(Person, 'relationships'); - deepEqual(relationships.get('person'), [ + assert.deepEqual(relationships.get('person'), [ { name: "people", kind: "hasMany" }, { name: "parent", kind: "belongsTo" } ]); - deepEqual(relationships.get('occupation'), [ + assert.deepEqual(relationships.get('occupation'), [ { name: "occupations", kind: "hasMany" } ]); }); -test("relationshipNames a hash of the relationships on a model with type as a key", function() { - deepEqual(get(Person, 'relationshipNames'), +test("relationshipNames a hash of the relationships on a model with type as a key", function(assert) { + assert.deepEqual(get(Person, 'relationshipNames'), { hasMany: ['occupations', 'people'], belongsTo: ["parent"] }); }); -test("eachRelatedType() iterates over relations without duplication", function() { +test("eachRelatedType() iterates over relations without duplication", function(assert) { var relations = []; Person.eachRelatedType(function(modelName) { relations.push(modelName); }); - deepEqual(relations, ['occupation', 'person']); + assert.deepEqual(relations, ['occupation', 'person']); }); diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index 12eacfdbd20..d6772edcdff 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -7,8 +9,8 @@ var run = Ember.run; module("unit/model/relationships - DS.belongsTo"); -test("belongsTo lazily loads relationships as needed", function() { - expect(5); +test("belongsTo lazily loads relationships as needed", function(assert) { + assert.expect(5); var Tag = DS.Model.extend({ name: DS.attr('string'), @@ -63,19 +65,19 @@ test("belongsTo lazily loads relationships as needed", function() { run(function() { store.findRecord('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + assert.equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); - equal(get(person, 'tag.name'), "friendly", "the tag shuld have name"); + assert.equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); + assert.equal(get(person, 'tag.name'), "friendly", "the tag shuld have name"); - strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); + assert.strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); asyncEqual(get(person, 'tag'), store.findRecord('tag', 5), "relationship object is the same as object retrieved directly"); })); }); }); -test("async belongsTo relationships work when the data hash has not been loaded", function() { - expect(5); +test("async belongsTo relationships work when the data hash has not been loaded", function(assert) { + assert.expect(5); var Tag = DS.Model.extend({ name: DS.attr('string') @@ -91,11 +93,11 @@ test("async belongsTo relationships work when the data hash has not been loaded" env.adapter.findRecord = function(store, type, id, snapshot) { if (type === Person) { - equal(id, 1, "id should be 1"); + assert.equal(id, 1, "id should be 1"); return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", tag: 2 }); } else if (type === Tag) { - equal(id, 2, "id should be 2"); + assert.equal(id, 2, "id should be 2"); return Ember.RSVP.resolve({ id: 2, name: "friendly" }); } @@ -103,20 +105,20 @@ test("async belongsTo relationships work when the data hash has not been loaded" run(function() { store.findRecord('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "The person is now populated"); + assert.equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return run(function() { return get(person, 'tag'); }); })).then(async(function(tag) { - equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); - equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); + assert.equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); + assert.equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); })); }); }); -test("async belongsTo relationships work when the data hash has already been loaded", function() { - expect(3); +test("async belongsTo relationships work when the data hash has already been loaded", function(assert) { + assert.expect(3); var Tag = DS.Model.extend({ name: DS.attr('string') @@ -155,18 +157,18 @@ test("async belongsTo relationships work when the data hash has already been loa run(function() { var person = store.peekRecord('person', 1); - equal(get(person, 'name'), "Tom Dale", "The person is now populated"); + assert.equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return run(function() { return get(person, 'tag'); }).then(async(function(tag) { - equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); - equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); + assert.equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); + assert.equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); })); }); }); -test("calling createRecord and passing in an undefined value for a relationship should be treated as if null", function () { - expect(1); +test("calling createRecord and passing in an undefined value for a relationship should be treated as if null", function(assert) { + assert.expect(1); var Tag = DS.Model.extend({ name: DS.attr('string'), @@ -188,12 +190,12 @@ test("calling createRecord and passing in an undefined value for a relationship run(function() { store.findRecord('person', 1).then(async(function(person) { - strictEqual(person.get('tag'), null, "undefined values should return null relationships"); + assert.strictEqual(person.get('tag'), null, "undefined values should return null relationships"); })); }); }); -test("When finding a hasMany relationship the inverse belongsTo relationship is available immediately", function() { +test("When finding a hasMany relationship the inverse belongsTo relationship is available immediately", function(assert) { var Occupation = DS.Model.extend({ description: DS.attr('string'), person: DS.belongsTo('person', { async: false }) @@ -213,7 +215,7 @@ test("When finding a hasMany relationship the inverse belongsTo relationship is env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.findMany = function(store, type, ids, snapshots) { - equal(snapshots[0].belongsTo('person').id, '1'); + assert.equal(snapshots[0].belongsTo('person').id, '1'); return Ember.RSVP.resolve([{ id: 5, description: "fifth" }, { id: 2, description: "second" }]); }; @@ -241,21 +243,21 @@ test("When finding a hasMany relationship the inverse belongsTo relationship is run(function() { store.findRecord('person', 1).then(async(function(person) { - equal(get(person, 'isLoaded'), true, "isLoaded should be true"); - equal(get(person, 'name'), "Tom Dale", "the person is still Tom Dale"); + assert.equal(get(person, 'isLoaded'), true, "isLoaded should be true"); + assert.equal(get(person, 'name'), "Tom Dale", "the person is still Tom Dale"); return get(person, 'occupations'); })).then(async(function(occupations) { - equal(get(occupations, 'length'), 2, "the list of occupations should have the correct length"); + assert.equal(get(occupations, 'length'), 2, "the list of occupations should have the correct length"); - equal(get(occupations.objectAt(0), 'description'), "fifth", "the occupation is the fifth"); - equal(get(occupations.objectAt(0), 'isLoaded'), true, "the occupation is now loaded"); + assert.equal(get(occupations.objectAt(0), 'description'), "fifth", "the occupation is the fifth"); + assert.equal(get(occupations.objectAt(0), 'isLoaded'), true, "the occupation is now loaded"); })); }); }); -test("When finding a belongsTo relationship the inverse belongsTo relationship is available immediately", function() { - expect(1); +test("When finding a belongsTo relationship the inverse belongsTo relationship is available immediately", function(assert) { + assert.expect(1); var Occupation = DS.Model.extend({ description: DS.attr('string'), @@ -275,7 +277,7 @@ test("When finding a belongsTo relationship the inverse belongsTo relationship i var store = env.store; env.adapter.findRecord = function(store, type, id, snapshot) { - equal(snapshot.belongsTo('person').id, '1'); + assert.equal(snapshot.belongsTo('person').id, '1'); return Ember.RSVP.resolve({ id: 5, description: "fifth" }); }; @@ -301,8 +303,8 @@ test("When finding a belongsTo relationship the inverse belongsTo relationship i }); }); -test("belongsTo supports relationships to models with id 0", function() { - expect(5); +test("belongsTo supports relationships to models with id 0", function(assert) { + assert.expect(5); var Tag = DS.Model.extend({ name: DS.attr('string'), @@ -357,18 +359,18 @@ test("belongsTo supports relationships to models with id 0", function() { run(function() { store.findRecord('person', 1).then(async(function(person) { - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + assert.equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); - equal(get(person, 'tag.name'), "friendly", "the tag should have name"); + assert.equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); + assert.equal(get(person, 'tag.name'), "friendly", "the tag should have name"); - strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); + assert.strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); asyncEqual(get(person, 'tag'), store.findRecord('tag', 0), "relationship object is the same as object retrieved directly"); })); }); }); -test("belongsTo gives a warning when provided with a serialize option", function() { +test("belongsTo gives a warning when provided with a serialize option", function(assert) { var Hobby = DS.Model.extend({ name: DS.attr('string') }); @@ -422,7 +424,7 @@ test("belongsTo gives a warning when provided with a serialize option", function }, /You provided a serialize option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.Serializer and it's implementations/); }); -test("belongsTo gives a warning when provided with an embedded option", function() { +test("belongsTo gives a warning when provided with an embedded option", function(assert) { var Hobby = DS.Model.extend({ name: DS.attr('string') }); @@ -476,7 +478,7 @@ test("belongsTo gives a warning when provided with an embedded option", function }, /You provided an embedded option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin/); }); -test("DS.belongsTo should be async by default", function() { +test("DS.belongsTo should be async by default", function(assert) { var Tag = DS.Model.extend({ name: DS.attr('string'), people: DS.hasMany('person', { async: false }) @@ -494,6 +496,6 @@ test("DS.belongsTo should be async by default", function() { run(function() { var person = store.createRecord('person'); - ok(person.get('tag') instanceof DS.PromiseObject, 'tag should be an async relationship'); + assert.ok(person.get('tag') instanceof DS.PromiseObject, 'tag should be an async relationship'); }); }); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index ac92ceb8874..f1a919533b3 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -7,13 +9,13 @@ var run = Ember.run; var env; module("unit/model/relationships - DS.hasMany", { - setup: function() { + beforeEach: function() { env = setupStore(); } }); -test("hasMany handles pre-loaded relationships", function() { - expect(13); +test("hasMany handles pre-loaded relationships", function(assert) { + assert.expect(13); var Tag = DS.Model.extend({ name: DS.attr('string'), @@ -39,7 +41,7 @@ test("hasMany handles pre-loaded relationships", function() { if (type === Tag && id === '12') { return Ember.RSVP.resolve({ id: 12, name: "oohlala" }); } else { - ok(false, "findRecord() should not be called with these values"); + assert.ok(false, "findRecord() should not be called with these values"); } }; env.adapter.shouldBackgroundReloadRecord = () => false; @@ -110,11 +112,11 @@ test("hasMany handles pre-loaded relationships", function() { run(function() { store.findRecord('person', 1).then(function(person) { - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + assert.equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); var tags = get(person, 'tags'); - equal(get(tags, 'length'), 1, "the list of tags should have the correct length"); - equal(get(tags.objectAt(0), 'name'), "friendly", "the first tag should be a Tag"); + assert.equal(get(tags, 'length'), 1, "the list of tags should have the correct length"); + assert.equal(get(tags.objectAt(0), 'name'), "friendly", "the first tag should be a Tag"); run(function() { store.push({ @@ -136,10 +138,10 @@ test("hasMany handles pre-loaded relationships", function() { }); }); - equal(tags, get(person, 'tags'), "a relationship returns the same object every time"); - equal(get(get(person, 'tags'), 'length'), 2, "the length is updated after new data is loaded"); + assert.equal(tags, get(person, 'tags'), "a relationship returns the same object every time"); + assert.equal(get(get(person, 'tags'), 'length'), 2, "the length is updated after new data is loaded"); - strictEqual(get(person, 'tags').objectAt(0), get(person, 'tags').objectAt(0), "the returned object is always the same"); + assert.strictEqual(get(person, 'tags').objectAt(0), get(person, 'tags').objectAt(0), "the returned object is always the same"); asyncEqual(get(person, 'tags').objectAt(0), store.findRecord('tag', 5), "relationship objects are the same as objects retrieved directly"); run(function() { @@ -156,7 +158,7 @@ test("hasMany handles pre-loaded relationships", function() { return store.findRecord('person', 3); }).then(function(kselden) { - equal(get(get(kselden, 'tags'), 'length'), 0, "a relationship that has not been supplied returns an empty array"); + assert.equal(get(get(kselden, 'tags'), 'length'), 0, "a relationship that has not been supplied returns an empty array"); run(function() { store.push({ @@ -178,11 +180,11 @@ test("hasMany handles pre-loaded relationships", function() { }); return store.findRecord('person', 4); }).then(function(cyvid) { - equal(get(cyvid, 'name'), "Cyvid Hamluck", "precond - retrieves person record from store"); + assert.equal(get(cyvid, 'name'), "Cyvid Hamluck", "precond - retrieves person record from store"); var pets = get(cyvid, 'pets'); - equal(get(pets, 'length'), 1, "the list of pets should have the correct length"); - equal(get(pets.objectAt(0), 'name'), "fluffy", "the first pet should be correct"); + assert.equal(get(pets, 'length'), 1, "the list of pets should have the correct length"); + assert.equal(get(pets.objectAt(0), 'name'), "fluffy", "the first pet should be correct"); run(function() { store.push({ @@ -204,14 +206,14 @@ test("hasMany handles pre-loaded relationships", function() { }); }); - equal(pets, get(cyvid, 'pets'), "a relationship returns the same object every time"); - equal(get(get(cyvid, 'pets'), 'length'), 2, "the length is updated after new data is loaded"); + assert.equal(pets, get(cyvid, 'pets'), "a relationship returns the same object every time"); + assert.equal(get(get(cyvid, 'pets'), 'length'), 2, "the length is updated after new data is loaded"); }); }); }); -test("hasMany lazily loads async relationships", function() { - expect(5); +test("hasMany lazily loads async relationships", function(assert) { + assert.expect(5); var Tag = DS.Model.extend({ name: DS.attr('string'), @@ -237,7 +239,7 @@ test("hasMany lazily loads async relationships", function() { if (type === Tag && id === '12') { return Ember.RSVP.resolve({ id: 12, name: "oohlala" }); } else { - ok(false, "findRecord() should not be called with these values"); + assert.ok(false, "findRecord() should not be called with these values"); } }; env.adapter.shouldBackgroundReloadRecord = () => false; @@ -312,17 +314,17 @@ test("hasMany lazily loads async relationships", function() { store.findRecord('person', 2).then(function(person) { wycats = person; - equal(get(wycats, 'name'), "Yehuda Katz", "precond - retrieves person record from store"); + assert.equal(get(wycats, 'name'), "Yehuda Katz", "precond - retrieves person record from store"); return Ember.RSVP.hash({ wycats: wycats, tags: wycats.get('tags') }); }).then(function(records) { - equal(get(records.tags, 'length'), 1, "the list of tags should have the correct length"); - equal(get(records.tags.objectAt(0), 'name'), "oohlala", "the first tag should be a Tag"); + assert.equal(get(records.tags, 'length'), 1, "the list of tags should have the correct length"); + assert.equal(get(records.tags.objectAt(0), 'name'), "oohlala", "the first tag should be a Tag"); - strictEqual(records.tags.objectAt(0), records.tags.objectAt(0), "the returned object is always the same"); + assert.strictEqual(records.tags.objectAt(0), records.tags.objectAt(0), "the returned object is always the same"); asyncEqual(records.tags.objectAt(0), store.findRecord('tag', 12), "relationship objects are the same as objects retrieved directly"); return get(wycats, 'tags'); @@ -336,7 +338,7 @@ test("hasMany lazily loads async relationships", function() { }); }); -test("should be able to retrieve the type for a hasMany relationship without specifying a type from its metadata", function() { +test("should be able to retrieve the type for a hasMany relationship without specifying a type from its metadata", function(assert) { var Tag = DS.Model.extend({}); var Person = DS.Model.extend({ @@ -349,10 +351,10 @@ test("should be able to retrieve the type for a hasMany relationship without spe person: Person }); - equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, "returns the relationship type"); + assert.equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, "returns the relationship type"); }); -test("should be able to retrieve the type for a hasMany relationship specified using a string from its metadata", function() { +test("should be able to retrieve the type for a hasMany relationship specified using a string from its metadata", function(assert) { var Tag = DS.Model.extend({}); var Person = DS.Model.extend({ @@ -364,10 +366,10 @@ test("should be able to retrieve the type for a hasMany relationship specified u person: Person }); - equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, "returns the relationship type"); + assert.equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, "returns the relationship type"); }); -test("should be able to retrieve the type for a belongsTo relationship without specifying a type from its metadata", function() { +test("should be able to retrieve the type for a belongsTo relationship without specifying a type from its metadata", function(assert) { var Tag = DS.Model.extend({}); var Person = DS.Model.extend({ @@ -379,10 +381,10 @@ test("should be able to retrieve the type for a belongsTo relationship without s person: Person }); - equal(env.store.modelFor('person').typeForRelationship('tag', env.store), Tag, "returns the relationship type"); + assert.equal(env.store.modelFor('person').typeForRelationship('tag', env.store), Tag, "returns the relationship type"); }); -test("should be able to retrieve the type for a belongsTo relationship specified using a string from its metadata", function() { +test("should be able to retrieve the type for a belongsTo relationship specified using a string from its metadata", function(assert) { var Tag = DS.Model.extend({ name: DS.attr('string') }); @@ -396,11 +398,11 @@ test("should be able to retrieve the type for a belongsTo relationship specified person: Person }); - equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, "returns the relationship type"); + assert.equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, "returns the relationship type"); }); -test("relationships work when declared with a string path", function() { - expect(2); +test("relationships work when declared with a string path", function(assert) { + assert.expect(2); window.App = {}; @@ -459,14 +461,14 @@ test("relationships work when declared with a string path", function() { run(function() { env.store.findRecord('person', 1).then(function(person) { - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - equal(get(person, 'tags.length'), 2, "the list of tags should have the correct length"); + assert.equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + assert.equal(get(person, 'tags.length'), 2, "the list of tags should have the correct length"); }); }); }); -test("hasMany relationships work when the data hash has not been loaded", function() { - expect(8); +test("hasMany relationships work when the data hash has not been loaded", function(assert) { + assert.expect(8); var Tag = DS.Model.extend({ name: DS.attr('string'), @@ -487,36 +489,36 @@ test("hasMany relationships work when the data hash has not been loaded", functi env.adapter.coalesceFindRequests = true; env.adapter.findMany = function(store, type, ids, snapshots) { - equal(type, Tag, "type should be Tag"); - deepEqual(ids, ['5', '2'], "ids should be 5 and 2"); + assert.equal(type, Tag, "type should be Tag"); + assert.deepEqual(ids, ['5', '2'], "ids should be 5 and 2"); return Ember.RSVP.resolve([{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); }; env.adapter.findRecord = function(store, type, id, snapshot) { - equal(type, Person, "type should be Person"); - equal(id, 1, "id should be 1"); + assert.equal(type, Person, "type should be Person"); + assert.equal(id, 1, "id should be 1"); return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", tags: [5, 2] }); }; run(function() { store.findRecord('person', 1).then(function(person) { - equal(get(person, 'name'), "Tom Dale", "The person is now populated"); + assert.equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return run(function() { return person.get('tags'); }); }).then(function(tags) { - equal(get(tags, 'length'), 2, "the tags object still exists"); - equal(get(tags.objectAt(0), 'name'), "friendly", "Tom Dale is now friendly"); - equal(get(tags.objectAt(0), 'isLoaded'), true, "Tom Dale is now loaded"); + assert.equal(get(tags, 'length'), 2, "the tags object still exists"); + assert.equal(get(tags.objectAt(0), 'name'), "friendly", "Tom Dale is now friendly"); + assert.equal(get(tags.objectAt(0), 'isLoaded'), true, "Tom Dale is now loaded"); }); }); }); -test("it is possible to add a new item to a relationship", function() { - expect(2); +test("it is possible to add a new item to a relationship", function(assert) { + assert.expect(2); var Tag = DS.Model.extend({ name: DS.attr('string'), @@ -565,18 +567,18 @@ test("it is possible to add a new item to a relationship", function() { store.findRecord('person', 1).then(function(person) { var tag = get(person, 'tags').objectAt(0); - equal(get(tag, 'name'), "ember", "precond - relationships work"); + assert.equal(get(tag, 'name'), "ember", "precond - relationships work"); tag = store.createRecord('tag', { name: "js" }); get(person, 'tags').pushObject(tag); - equal(get(person, 'tags').objectAt(1), tag, "newly added relationship works"); + assert.equal(get(person, 'tags').objectAt(1), tag, "newly added relationship works"); }); }); }); -test("possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)", function() { - expect(2); +test("possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)", function(assert) { + assert.expect(2); var Tag = DS.Model.extend({ name: DS.attr('string'), @@ -645,12 +647,12 @@ test("possible to replace items in a relationship using setObjects w/ Ember Enum tom.get('tags').setObjects(sylvain.get('tags')); }); - equal(tom.get('tags.length'), 1); - equal(tom.get('tags.firstObject'), store.peekRecord('tag', 2)); + assert.equal(tom.get('tags.length'), 1); + assert.equal(tom.get('tags.firstObject'), store.peekRecord('tag', 2)); }); -test("it is possible to remove an item from a relationship", function() { - expect(2); +test("it is possible to remove an item from a relationship", function(assert) { + assert.expect(2); var Tag = DS.Model.extend({ name: DS.attr('string'), @@ -695,18 +697,18 @@ test("it is possible to remove an item from a relationship", function() { store.findRecord('person', 1).then(async(function(person) { var tag = get(person, 'tags').objectAt(0); - equal(get(tag, 'name'), "ember", "precond - relationships work"); + assert.equal(get(tag, 'name'), "ember", "precond - relationships work"); run(function() { get(person, 'tags').removeObject(tag); }); - equal(get(person, 'tags.length'), 0, "object is removed from the relationship"); + assert.equal(get(person, 'tags.length'), 0, "object is removed from the relationship"); })); }); }); -test("it is possible to add an item to a relationship, remove it, then add it again", function() { +test("it is possible to add an item to a relationship, remove it, then add it again", function(assert) { var Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person', { async: false }) @@ -738,21 +740,21 @@ test("it is possible to add an item to a relationship, remove it, then add it ag tags.removeObject(tag2); }); - equal(tags.objectAt(0), tag1); - equal(tags.objectAt(1), tag3); - equal(get(person, 'tags.length'), 2, "object is removed from the relationship"); + assert.equal(tags.objectAt(0), tag1); + assert.equal(tags.objectAt(1), tag3); + assert.equal(get(person, 'tags.length'), 2, "object is removed from the relationship"); run(function() { tags.insertAt(0, tag2); }); - equal(get(person, 'tags.length'), 3, "object is added back to the relationship"); - equal(tags.objectAt(0), tag2); - equal(tags.objectAt(1), tag1); - equal(tags.objectAt(2), tag3); + assert.equal(get(person, 'tags.length'), 3, "object is added back to the relationship"); + assert.equal(tags.objectAt(0), tag2); + assert.equal(tags.objectAt(1), tag1); + assert.equal(tags.objectAt(2), tag3); }); -test("DS.hasMany is async by default", function() { +test("DS.hasMany is async by default", function(assert) { var Tag = DS.Model.extend({ name: DS.attr('string'), people: DS.hasMany('person') @@ -768,11 +770,11 @@ test("DS.hasMany is async by default", function() { run(function() { var tag = store.createRecord('tag'); - ok(tag.get('people') instanceof DS.PromiseArray, 'people should be an async relationship'); + assert.ok(tag.get('people') instanceof DS.PromiseArray, 'people should be an async relationship'); }); }); -test("throws assertion if of not set with an array", function() { +test("throws assertion if of not set with an array", function(assert) { var Person = DS.Model.extend(); var Tag = DS.Model.extend({ people: DS.hasMany('person') @@ -793,7 +795,7 @@ test("throws assertion if of not set with an array", function() { }); }); -test("checks if passed array only contains instances of DS.Model", function() { +test("checks if passed array only contains instances of DS.Model", function(assert) { var Person = DS.Model.extend(); var Tag = DS.Model.extend({ people: DS.hasMany('person') diff --git a/tests/unit/model/relationships/record-array-test.js b/tests/unit/model/relationships/record-array-test.js index f22c0390a8d..d9e8181b0a9 100644 --- a/tests/unit/model/relationships/record-array-test.js +++ b/tests/unit/model/relationships/record-array-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -8,7 +10,7 @@ var run = Ember.run; module("unit/model/relationships - RecordArray"); -test("updating the content of a RecordArray updates its content", function() { +test("updating the content of a RecordArray updates its content", function(assert) { var Tag = DS.Model.extend({ name: DS.attr('string') }); @@ -45,18 +47,18 @@ test("updating the content of a RecordArray updates its content", function() { }); var tag = tags.objectAt(0); - equal(get(tag, 'name'), "friendly", "precond - we're working with the right tags"); + assert.equal(get(tag, 'name'), "friendly", "precond - we're working with the right tags"); run(function() { set(tags, 'content', Ember.A(internalModel.slice(1, 3))); }); tag = tags.objectAt(0); - equal(get(tag, 'name'), "smarmy", "the lookup was updated"); + assert.equal(get(tag, 'name'), "smarmy", "the lookup was updated"); }); -test("can create child record from a hasMany relationship", function() { - expect(3); +test("can create child record from a hasMany relationship", function(assert) { + assert.expect(3); var Tag = DS.Model.extend({ name: DS.attr('string'), @@ -88,9 +90,9 @@ test("can create child record from a hasMany relationship", function() { store.findRecord('person', 1).then(async(function(person) { person.get("tags").createRecord({ name: "cool" }); - equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - equal(get(person, 'tags.length'), 1, "tag is added to the parent record"); - equal(get(person, 'tags').objectAt(0).get("name"), "cool", "tag values are passed along"); + assert.equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + assert.equal(get(person, 'tags.length'), 1, "tag is added to the parent record"); + assert.equal(get(person, 'tags').objectAt(0).get("name"), "cool", "tag values are passed along"); })); }); }); diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index 64067ce3f37..177478cf56b 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, Person, Dog; var run = Ember.run; module("unit/model/rollbackAttributes - model.rollbackAttributes()", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ firstName: DS.attr(), lastName: DS.attr() @@ -17,7 +19,7 @@ module("unit/model/rollbackAttributes - model.rollbackAttributes()", { } }); -test("changes to attributes can be rolled back", function() { +test("changes to attributes can be rolled back", function(assert) { var person; run(function() { store.push({ @@ -34,17 +36,17 @@ test("changes to attributes can be rolled back", function() { person.set('firstName', "Thomas"); }); - equal(person.get('firstName'), "Thomas"); + assert.equal(person.get('firstName'), "Thomas"); run(function() { person.rollbackAttributes(); }); - equal(person.get('firstName'), "Tom"); - equal(person.get('hasDirtyAttributes'), false); + assert.equal(person.get('firstName'), "Tom"); + assert.equal(person.get('hasDirtyAttributes'), false); }); -test("changes to unassigned attributes can be rolled back", function() { +test("changes to unassigned attributes can be rolled back", function(assert) { var person; run(function() { store.push({ @@ -60,17 +62,17 @@ test("changes to unassigned attributes can be rolled back", function() { person.set('firstName', "Thomas"); }); - equal(person.get('firstName'), "Thomas"); + assert.equal(person.get('firstName'), "Thomas"); run(function() { person.rollbackAttributes(); }); - equal(person.get('firstName'), undefined); - equal(person.get('hasDirtyAttributes'), false); + assert.equal(person.get('firstName'), undefined); + assert.equal(person.get('hasDirtyAttributes'), false); }); -test("changes to attributes made after a record is in-flight only rolls back the local changes", function() { +test("changes to attributes made after a record is in-flight only rolls back the local changes", function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { // Make sure the save is async return new Ember.RSVP.Promise(function(resolve, reject) { @@ -97,25 +99,25 @@ test("changes to attributes made after a record is in-flight only rolls back the Ember.run(function() { var saving = person.save(); - equal(person.get('firstName'), "Thomas"); + assert.equal(person.get('firstName'), "Thomas"); person.set('lastName', "Dolly"); - equal(person.get('lastName'), "Dolly"); + assert.equal(person.get('lastName'), "Dolly"); person.rollbackAttributes(); - equal(person.get('firstName'), "Thomas"); - equal(person.get('lastName'), "Dale"); - equal(person.get('isSaving'), true); + assert.equal(person.get('firstName'), "Thomas"); + assert.equal(person.get('lastName'), "Dale"); + assert.equal(person.get('isSaving'), true); saving.then(async(function() { - equal(person.get('hasDirtyAttributes'), false, "The person is now clean"); + assert.equal(person.get('hasDirtyAttributes'), false, "The person is now clean"); })); }); }); -test("a record's changes can be made if it fails to save", function() { +test("a record's changes can be made if it fails to save", function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { return Ember.RSVP.reject(); }; @@ -136,24 +138,24 @@ test("a record's changes can be made if it fails to save", function() { person.set('firstName', "Thomas"); }); - deepEqual(person.changedAttributes().firstName, ["Tom", "Thomas"]); + assert.deepEqual(person.changedAttributes().firstName, ["Tom", "Thomas"]); run(function() { person.save().then(null, function() { - equal(person.get('isError'), true); - deepEqual(person.changedAttributes().firstName, ["Tom", "Thomas"]); + assert.equal(person.get('isError'), true); + assert.deepEqual(person.changedAttributes().firstName, ["Tom", "Thomas"]); person.rollbackAttributes(); - equal(person.get('firstName'), "Tom"); - equal(person.get('isError'), false); - equal(Object.keys(person.changedAttributes()).length, 0); + assert.equal(person.get('firstName'), "Tom"); + assert.equal(person.get('isError'), false); + assert.equal(Object.keys(person.changedAttributes()).length, 0); }); }); }); -test("a deleted record's attributes can be rollbacked if it fails to save, record arrays are updated accordingly", function() { - expect(8); +test("a deleted record's attributes can be rollbacked if it fails to save, record arrays are updated accordingly", function(assert) { + assert.expect(8); env.adapter.deleteRecord = function(store, type, snapshot) { return Ember.RSVP.reject(); }; @@ -177,43 +179,43 @@ test("a deleted record's attributes can be rollbacked if it fails to save, recor run(function() { person.deleteRecord(); }); - equal(people.get('length'), 1, "a deleted record appears in record array until it is saved"); - equal(people.objectAt(0), person, "a deleted record appears in record array until it is saved"); + assert.equal(people.get('length'), 1, "a deleted record appears in record array until it is saved"); + assert.equal(people.objectAt(0), person, "a deleted record appears in record array until it is saved"); run(function() { person.save().then(null, function() { - equal(person.get('isError'), true); - equal(person.get('isDeleted'), true); + assert.equal(person.get('isError'), true); + assert.equal(person.get('isDeleted'), true); run(function() { person.rollbackAttributes(); }); - equal(person.get('isDeleted'), false); - equal(person.get('isError'), false); - equal(person.get('hasDirtyAttributes'), false, "must be not dirty"); + assert.equal(person.get('isDeleted'), false); + assert.equal(person.get('isError'), false); + assert.equal(person.get('hasDirtyAttributes'), false, "must be not dirty"); }).then(function() { - equal(people.get('length'), 1, "the underlying record array is updated accordingly in an asynchronous way"); + assert.equal(people.get('length'), 1, "the underlying record array is updated accordingly in an asynchronous way"); }); }); }); -test("new record's attributes can be rollbacked", function() { +test("new record's attributes can be rollbacked", function(assert) { var person; run(function() { person = store.createRecord('person', { id: 1 }); }); - equal(person.get('isNew'), true, "must be new"); - equal(person.get('hasDirtyAttributes'), true, "must be dirty"); + assert.equal(person.get('isNew'), true, "must be new"); + assert.equal(person.get('hasDirtyAttributes'), true, "must be dirty"); Ember.run(person, 'rollbackAttributes'); - equal(person.get('isNew'), false, "must not be new"); - equal(person.get('hasDirtyAttributes'), false, "must not be dirty"); - equal(person.get('isDeleted'), true, "must be deleted"); + assert.equal(person.get('isNew'), false, "must not be new"); + assert.equal(person.get('hasDirtyAttributes'), false, "must not be dirty"); + assert.equal(person.get('isDeleted'), true, "must be deleted"); }); -test("invalid new record's attributes can be rollbacked", function() { +test("invalid new record's attributes can be rollbacked", function(assert) { var person; var error = new DS.InvalidError([ { @@ -233,22 +235,22 @@ test("invalid new record's attributes can be rollbacked", function() { person = env.store.createRecord('person', { id: 1 }); }); - equal(person.get('isNew'), true, "must be new"); - equal(person.get('hasDirtyAttributes'), true, "must be dirty"); + assert.equal(person.get('isNew'), true, "must be new"); + assert.equal(person.get('hasDirtyAttributes'), true, "must be dirty"); run(function() { person.save().then(null, async(function() { - equal(person.get('isValid'), false); + assert.equal(person.get('isValid'), false); person.rollbackAttributes(); - equal(person.get('isNew'), false, "must not be new"); - equal(person.get('hasDirtyAttributes'), false, "must not be dirty"); - equal(person.get('isDeleted'), true, "must be deleted"); + assert.equal(person.get('isNew'), false, "must not be new"); + assert.equal(person.get('hasDirtyAttributes'), false, "must not be dirty"); + assert.equal(person.get('isDeleted'), true, "must be deleted"); })); }); }); -test("invalid record's attributes can be rollbacked after multiple failed calls - #3677", function() { +test("invalid record's attributes can be rollbacked after multiple failed calls - #3677", function(assert) { var person; var adapter = DS.RESTAdapter.extend({ @@ -275,23 +277,23 @@ test("invalid record's attributes can be rollbacked after multiple failed calls }); run(function() { - equal(person.get('firstName'), 'updated name', "precondition: firstName is changed"); + assert.equal(person.get('firstName'), 'updated name', "precondition: firstName is changed"); person.save().then(null, async(function() { - equal(person.get('hasDirtyAttributes'), true, "has dirty attributes"); - equal(person.get('firstName'), 'updated name', "firstName is still changed"); + assert.equal(person.get('hasDirtyAttributes'), true, "has dirty attributes"); + assert.equal(person.get('firstName'), 'updated name', "firstName is still changed"); return person.save(); })).then(null, async(function() { person.rollbackAttributes(); - equal(person.get('hasDirtyAttributes'), false, "has no dirty attributes"); - equal(person.get('firstName'), 'original name', "after rollbackAttributes() firstName has the original value"); + assert.equal(person.get('hasDirtyAttributes'), false, "has no dirty attributes"); + assert.equal(person.get('firstName'), 'original name', "after rollbackAttributes() firstName has the original value"); })); }); }); -test("deleted record's attributes can be rollbacked", function() { +test("deleted record's attributes can be rollbacked", function(assert) { var person, people; run(function() { @@ -306,21 +308,21 @@ test("deleted record's attributes can be rollbacked", function() { person.deleteRecord(); }); - equal(people.get('length'), 1, "a deleted record appears in the record array until it is saved"); - equal(people.objectAt(0), person, "a deleted record appears in the record array until it is saved"); + assert.equal(people.get('length'), 1, "a deleted record appears in the record array until it is saved"); + assert.equal(people.objectAt(0), person, "a deleted record appears in the record array until it is saved"); - equal(person.get('isDeleted'), true, "must be deleted"); + assert.equal(person.get('isDeleted'), true, "must be deleted"); run(function() { person.rollbackAttributes(); }); - equal(people.get('length'), 1, "the rollbacked record should appear again in the record array"); - equal(person.get('isDeleted'), false, "must not be deleted"); - equal(person.get('hasDirtyAttributes'), false, "must not be dirty"); + assert.equal(people.get('length'), 1, "the rollbacked record should appear again in the record array"); + assert.equal(person.get('isDeleted'), false, "must not be deleted"); + assert.equal(person.get('hasDirtyAttributes'), false, "must not be dirty"); }); -test("invalid record's attributes can be rollbacked", function() { - expect(10); +test("invalid record's attributes can be rollbacked", function(assert) { + assert.expect(10); Dog = DS.Model.extend({ name: DS.attr() }); @@ -356,31 +358,31 @@ test("invalid record's attributes can be rollbacked", function() { run(function() { Ember.addObserver(dog, 'errors.name', function() { - ok(true, 'errors.name did change'); + assert.ok(true, 'errors.name did change'); }); dog.get('errors').addArrayObserver({}, { willChange: function() { - ok(true, 'errors will change'); + assert.ok(true, 'errors will change'); }, didChange: function() { - ok(true, 'errors did change'); + assert.ok(true, 'errors did change'); } }); dog.save().then(null, async(function() { dog.rollbackAttributes(); - equal(dog.get('hasDirtyAttributes'), false, "must not be dirty"); - equal(dog.get('name'), "Pluto"); - ok(Ember.isEmpty(dog.get('errors.name'))); - ok(dog.get('isValid')); + assert.equal(dog.get('hasDirtyAttributes'), false, "must not be dirty"); + assert.equal(dog.get('name'), "Pluto"); + assert.ok(Ember.isEmpty(dog.get('errors.name'))); + assert.ok(dog.get('isValid')); })); }); }); -test("invalid record's attributes rolled back to correct state after set", function() { - expect(13); +test("invalid record's attributes rolled back to correct state after set", function(assert) { + assert.expect(13); Dog = DS.Model.extend({ name: DS.attr(), breed: DS.attr() @@ -419,36 +421,36 @@ test("invalid record's attributes rolled back to correct state after set", funct run(function() { Ember.addObserver(dog, 'errors.name', function() { - ok(true, 'errors.name did change'); + assert.ok(true, 'errors.name did change'); }); dog.save().then(null, async(function() { - equal(dog.get('name'), "is a dwarf planet"); - equal(dog.get('breed'), "planet"); - ok(Ember.isPresent(dog.get('errors.name'))); - equal(dog.get('errors.name.length'), 1); + assert.equal(dog.get('name'), "is a dwarf planet"); + assert.equal(dog.get('breed'), "planet"); + assert.ok(Ember.isPresent(dog.get('errors.name'))); + assert.equal(dog.get('errors.name.length'), 1); run(function() { dog.set('name', 'Seymour Asses'); }); - equal(dog.get('name'), "Seymour Asses"); - equal(dog.get('breed'), "planet"); + assert.equal(dog.get('name'), "Seymour Asses"); + assert.equal(dog.get('breed'), "planet"); run(function() { dog.rollbackAttributes(); }); - equal(dog.get('name'), "Pluto"); - equal(dog.get('breed'), "Disney"); - equal(dog.get('hasDirtyAttributes'), false, "must not be dirty"); - ok(Ember.isEmpty(dog.get('errors.name'))); - ok(dog.get('isValid')); + assert.equal(dog.get('name'), "Pluto"); + assert.equal(dog.get('breed'), "Disney"); + assert.equal(dog.get('hasDirtyAttributes'), false, "must not be dirty"); + assert.ok(Ember.isEmpty(dog.get('errors.name'))); + assert.ok(dog.get('isValid')); })); }); }); -test("when destroying a record setup the record state to invalid, the record's attributes can be rollbacked", function() { +test("when destroying a record setup the record state to invalid, the record's attributes can be rollbacked", function(assert) { Dog = DS.Model.extend({ name: DS.attr() }); @@ -485,17 +487,17 @@ test("when destroying a record setup the record state to invalid, the record's a dog.destroyRecord().then(null, async(function() { - equal(dog.get('isError'), false, "must not be error"); - equal(dog.get('isDeleted'), true, "must be deleted"); - equal(dog.get('isValid'), false, "must not be valid"); - ok(dog.get('errors.length') > 0, "must have errors"); + assert.equal(dog.get('isError'), false, "must not be error"); + assert.equal(dog.get('isDeleted'), true, "must be deleted"); + assert.equal(dog.get('isValid'), false, "must not be valid"); + assert.ok(dog.get('errors.length') > 0, "must have errors"); dog.rollbackAttributes(); - equal(dog.get('isError'), false, "must not be error after `rollbackAttributes`"); - equal(dog.get('isDeleted'), false, "must not be deleted after `rollbackAttributes`"); - equal(dog.get('isValid'), true, "must be valid after `rollbackAttributes`"); - ok(dog.get('errors.length') === 0, "must not have errors"); + assert.equal(dog.get('isError'), false, "must not be error after `rollbackAttributes`"); + assert.equal(dog.get('isDeleted'), false, "must not be deleted after `rollbackAttributes`"); + assert.equal(dog.get('isValid'), true, "must be valid after `rollbackAttributes`"); + assert.ok(dog.get('errors.length') === 0, "must not have errors"); })); }); }); diff --git a/tests/unit/promise-proxies-test.js b/tests/unit/promise-proxies-test.js index a393a56e4e6..5b4e272b302 100644 --- a/tests/unit/promise-proxies-test.js +++ b/tests/unit/promise-proxies-test.js @@ -1,11 +1,13 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; module('PromiseManyArray'); -test('.reload should NOT leak the internal promise, rather return another promiseArray', function() { - expect(2); +test('.reload should NOT leak the internal promise, rather return another promiseArray', function(assert) { + assert.expect(2); var content = Ember.A(); @@ -20,10 +22,10 @@ test('.reload should NOT leak the internal promise, rather return another promis Ember.run(function() { var reloaded = array.reload(); - ok(reloaded instanceof DS.PromiseManyArray); + assert.ok(reloaded instanceof DS.PromiseManyArray); reloaded.then(function(value) { - equal(content, value); + assert.equal(content, value); }); }); }); diff --git a/tests/unit/record-array-test.js b/tests/unit/record-array-test.js index 64331cbad42..cc29a49a918 100644 --- a/tests/unit/record-array-test.js +++ b/tests/unit/record-array-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -8,7 +10,7 @@ var Person, array; var run = Ember.run; module("unit/record_array - DS.RecordArray", { - setup: function() { + beforeEach: function() { array = [{ id: '1', name: "Scumbag Dale" }, { id: '2', name: "Scumbag Katz" }, { id: '3', name: "Scumbag Bryn" }]; Person = DS.Model.extend({ @@ -17,8 +19,8 @@ module("unit/record_array - DS.RecordArray", { } }); -test("a record array is backed by records", function() { - expect(3); +test("a record array is backed by records", function(assert) { + assert.expect(3); var store = createStore({ person: Person, @@ -53,13 +55,13 @@ test("a record array is backed by records", function() { run(function() { store.findByIds('person', [1,2,3]).then(function(records) { for (var i=0, l=get(array, 'length'); i store.get('defaultAdapter')); }); -test("Calling Store#find invokes its adapter#find", function() { - expect(5); +test("Calling Store#find invokes its adapter#find", function(assert) { + assert.expect(5); var adapter = TestAdapter.extend({ findRecord: function(store, type, id, snapshot) { - ok(true, "Adapter#find was called"); - equal(store, currentStore, "Adapter#find was called with the right store"); - equal(type, store.modelFor('test'), "Adapter#find was called with the type passed into Store#find"); - equal(id, 1, "Adapter#find was called with the id passed into Store#find"); - equal(snapshot.id, '1', "Adapter#find was called with the record created from Store#find"); + assert.ok(true, "Adapter#find was called"); + assert.equal(store, currentStore, "Adapter#find was called with the right store"); + assert.equal(type, store.modelFor('test'), "Adapter#find was called with the type passed into Store#find"); + assert.equal(id, 1, "Adapter#find was called with the id passed into Store#find"); + assert.equal(snapshot.id, '1', "Adapter#find was called with the record created from Store#find"); return Ember.RSVP.resolve({ id: 1 }); } @@ -67,17 +69,17 @@ test("Calling Store#find invokes its adapter#find", function() { }); }); -test("Calling Store#findRecord multiple times coalesces the calls into a adapter#findMany call", function() { - expect(2); +test("Calling Store#findRecord multiple times coalesces the calls into a adapter#findMany call", function(assert) { + assert.expect(2); var adapter = TestAdapter.extend({ findRecord: function(store, type, id, snapshot) { - ok(false, "Adapter#findRecord was not called"); + assert.ok(false, "Adapter#findRecord was not called"); }, findMany: function(store, type, ids, snapshots) { start(); - ok(true, "Adapter#findMany was called"); - deepEqual(ids, ["1","2"], 'Correct ids were passed in to findMany'); + assert.ok(true, "Adapter#findMany was called"); + assert.deepEqual(ids, ["1","2"], 'Correct ids were passed in to findMany'); return Ember.RSVP.resolve([{ id: 1 }, { id: 2 }]); }, coalesceFindRequests: true @@ -93,8 +95,8 @@ test("Calling Store#findRecord multiple times coalesces the calls into a adapter }); }); -test("Returning a promise from `findRecord` asynchronously loads data", function() { - expect(1); +test("Returning a promise from `findRecord` asynchronously loads data", function(assert) { + assert.expect(1); var adapter = TestAdapter.extend({ findRecord: function(store, type, id, snapshot) { @@ -109,17 +111,17 @@ test("Returning a promise from `findRecord` asynchronously loads data", function run(function() { currentStore.findRecord('test', 1).then(async(function(object) { - strictEqual(get(object, 'name'), "Scumbag Dale", "the data was pushed"); + assert.strictEqual(get(object, 'name'), "Scumbag Dale", "the data was pushed"); })); }); }); -test("IDs provided as numbers are coerced to strings", function() { - expect(5); +test("IDs provided as numbers are coerced to strings", function(assert) { + assert.expect(5); var adapter = TestAdapter.extend({ findRecord: function(store, type, id, snapshot) { - equal(typeof id, 'string', "id has been normalized to a string"); + assert.equal(typeof id, 'string', "id has been normalized to a string"); return resolve({ id: 1, name: "Scumbag Sylvain" }); } }); @@ -131,7 +133,7 @@ test("IDs provided as numbers are coerced to strings", function() { run(function() { currentStore.findRecord('test', 1).then(async(function(object) { - equal(typeof object.get('id'), 'string', "id was coerced to a string"); + assert.equal(typeof object.get('id'), 'string', "id was coerced to a string"); run(function() { currentStore.push({ data: { @@ -145,14 +147,14 @@ test("IDs provided as numbers are coerced to strings", function() { }); return currentStore.findRecord('test', 2); })).then(async(function(object) { - ok(object, "object was found"); - equal(typeof object.get('id'), 'string', "id is a string despite being supplied and searched for as a number"); + assert.ok(object, "object was found"); + assert.equal(typeof object.get('id'), 'string', "id is a string despite being supplied and searched for as a number"); })); }); }); -test("can load data for the same record if it is not dirty", function() { - expect(3); +test("can load data for the same record if it is not dirty", function(assert) { + assert.expect(3); var Person = DS.Model.extend({ name: DS.attr('string') @@ -177,8 +179,8 @@ test("can load data for the same record if it is not dirty", function() { }); store.findRecord('person', 1).then(async(function(tom) { - equal(get(tom, 'hasDirtyAttributes'), false, "precond - record is not dirty"); - equal(get(tom, 'name'), "Tom Dale", "returns the correct name"); + assert.equal(get(tom, 'hasDirtyAttributes'), false, "precond - record is not dirty"); + assert.equal(get(tom, 'name'), "Tom Dale", "returns the correct name"); store.push({ data: { @@ -189,7 +191,7 @@ test("can load data for the same record if it is not dirty", function() { } } }); - equal(get(tom, 'name'), "Captain Underpants", "updated record with new date"); + assert.equal(get(tom, 'name'), "Captain Underpants", "updated record with new date"); })); }); }); @@ -206,8 +208,8 @@ test("DS.Store loads individual records without explicit IDs with a custom prima }); */ -test("loadMany takes an optional Object and passes it on to the Adapter", function() { - expect(2); +test("loadMany takes an optional Object and passes it on to the Adapter", function(assert) { + assert.expect(2); var passedQuery = { page: 1 }; @@ -217,8 +219,8 @@ test("loadMany takes an optional Object and passes it on to the Adapter", functi var adapter = TestAdapter.extend({ query: function(store, type, query) { - equal(type, store.modelFor('person'), 'The type was Person'); - equal(query, passedQuery, "The query was passed in"); + assert.equal(type, store.modelFor('person'), 'The type was Person'); + assert.equal(query, passedQuery, "The query was passed in"); return Ember.RSVP.resolve([]); } }); @@ -233,7 +235,7 @@ test("loadMany takes an optional Object and passes it on to the Adapter", functi }); }); -test("Find with query calls the correct normalizeResponse", function() { +test("Find with query calls the correct normalizeResponse", function(assert) { var passedQuery = { page: 1 }; var Person = DS.Model.extend({ @@ -266,10 +268,10 @@ test("Find with query calls the correct normalizeResponse", function() { run(function() { store.query('person', passedQuery); }); - equal(callCount, 1, 'normalizeQueryResponse was called'); + assert.equal(callCount, 1, 'normalizeQueryResponse was called'); }); -test("peekAll(type) returns a record array of all records of a specific type", function() { +test("peekAll(type) returns a record array of all records of a specific type", function(assert) { var Person = DS.Model.extend({ name: DS.attr('string') }); @@ -291,8 +293,8 @@ test("peekAll(type) returns a record array of all records of a specific type", f }); var results = store.peekAll('person'); - equal(get(results, 'length'), 1, "record array should have the original object"); - equal(get(results.objectAt(0), 'name'), "Tom Dale", "record has the correct information"); + assert.equal(get(results, 'length'), 1, "record array should have the original object"); + assert.equal(get(results.objectAt(0), 'name'), "Tom Dale", "record has the correct information"); run(function() { store.push({ @@ -305,13 +307,13 @@ test("peekAll(type) returns a record array of all records of a specific type", f } }); }); - equal(get(results, 'length'), 2, "record array should have the new object"); - equal(get(results.objectAt(1), 'name'), "Yehuda Katz", "record has the correct information"); + assert.equal(get(results, 'length'), 2, "record array should have the new object"); + assert.equal(get(results.objectAt(1), 'name'), "Yehuda Katz", "record has the correct information"); - strictEqual(results, store.peekAll('person'), "subsequent calls to peekAll return the same recordArray)"); + assert.strictEqual(results, store.peekAll('person'), "subsequent calls to peekAll return the same recordArray)"); }); -test("a new record of a particular type is created via store.createRecord(type)", function() { +test("a new record of a particular type is created via store.createRecord(type)", function(assert) { var Person = DS.Model.extend({ name: DS.attr('string') }); @@ -325,18 +327,18 @@ test("a new record of a particular type is created via store.createRecord(type)" person = store.createRecord('person'); }); - equal(get(person, 'isLoaded'), true, "A newly created record is loaded"); - equal(get(person, 'isNew'), true, "A newly created record is new"); - equal(get(person, 'hasDirtyAttributes'), true, "A newly created record is dirty"); + assert.equal(get(person, 'isLoaded'), true, "A newly created record is loaded"); + assert.equal(get(person, 'isNew'), true, "A newly created record is new"); + assert.equal(get(person, 'hasDirtyAttributes'), true, "A newly created record is dirty"); run(function() { set(person, 'name', "Braaahm Dale"); }); - equal(get(person, 'name'), "Braaahm Dale", "Even if no hash is supplied, `set` still worked"); + assert.equal(get(person, 'name'), "Braaahm Dale", "Even if no hash is supplied, `set` still worked"); }); -test("a new record with a specific id can't be created if this id is already used in the store", function() { +test("a new record with a specific id can't be created if this id is already used in the store", function(assert) { var Person = DS.Model.extend({ name: DS.attr('string') }); @@ -362,7 +364,7 @@ test("a new record with a specific id can't be created if this id is already use }, /The id 5 has already been used with another record of type Person/); }); -test("an initial data hash can be provided via store.createRecord(type, hash)", function() { +test("an initial data hash can be provided via store.createRecord(type, hash)", function(assert) { var Person = DS.Model.extend({ name: DS.attr('string') }); @@ -375,15 +377,15 @@ test("an initial data hash can be provided via store.createRecord(type, hash)", person = store.createRecord('person', { name: "Brohuda Katz" }); }); - equal(get(person, 'isLoaded'), true, "A newly created record is loaded"); - equal(get(person, 'isNew'), true, "A newly created record is new"); - equal(get(person, 'hasDirtyAttributes'), true, "A newly created record is dirty"); + assert.equal(get(person, 'isLoaded'), true, "A newly created record is loaded"); + assert.equal(get(person, 'isNew'), true, "A newly created record is new"); + assert.equal(get(person, 'hasDirtyAttributes'), true, "A newly created record is dirty"); - equal(get(person, 'name'), "Brohuda Katz", "The initial data hash is provided"); + assert.equal(get(person, 'name'), "Brohuda Katz", "The initial data hash is provided"); }); -test("if an id is supplied in the initial data hash, it can be looked up using `store.find`", function() { - expect(1); +test("if an id is supplied in the initial data hash, it can be looked up using `store.find`", function(assert) { + assert.expect(1); var Person = DS.Model.extend({ name: DS.attr('string') @@ -399,17 +401,17 @@ test("if an id is supplied in the initial data hash, it can be looked up using ` run(function() { person = store.createRecord('person', { id: 1, name: "Brohuda Katz" }); store.findRecord('person', 1).then(async(function(again) { - strictEqual(person, again, "the store returns the loaded object"); + assert.strictEqual(person, again, "the store returns the loaded object"); })); }); }); -test("initial values of attributes can be passed in as the third argument to find", function() { - expect(1); +test("initial values of attributes can be passed in as the third argument to find", function(assert) { + assert.expect(1); var adapter = TestAdapter.extend({ findRecord: function(store, type, id, snapshot) { - equal(snapshot.attr('name'), 'Test', 'Preloaded attribtue set'); + assert.equal(snapshot.attr('name'), 'Test', 'Preloaded attribtue set'); return Ember.RSVP.resolve({ id: '1', name: 'Test' }); } }); @@ -428,11 +430,11 @@ test("initial values of attributes can be passed in as the third argument to fin }); }); -test("initial values of belongsTo can be passed in as the third argument to find as records", function() { - expect(1); +test("initial values of belongsTo can be passed in as the third argument to find as records", function(assert) { + assert.expect(1); var adapter = TestAdapter.extend({ findRecord: function(store, type, id, snapshot) { - equal(snapshot.belongsTo('friend').attr('name'), 'Tom', 'Preloaded belongsTo set'); + assert.equal(snapshot.belongsTo('friend').attr('name'), 'Tom', 'Preloaded belongsTo set'); return new Ember.RSVP.Promise(function() {}); } }); @@ -465,8 +467,8 @@ test("initial values of belongsTo can be passed in as the third argument to find }); }); -test("initial values of belongsTo can be passed in as the third argument to find as ids", function() { - expect(1); +test("initial values of belongsTo can be passed in as the third argument to find as ids", function(assert) { + assert.expect(1); var adapter = TestAdapter.extend({ findRecord: function(store, type, id, snapshot) { @@ -489,17 +491,17 @@ test("initial values of belongsTo can be passed in as the third argument to find run(function() { store.findRecord('person', 1, { preload: { friend: 2 } }).then(async(function() { store.peekRecord('person', 1).get('friend').then(async(function(friend) { - equal(friend.get('id'), '2', 'Preloaded belongsTo set'); + assert.equal(friend.get('id'), '2', 'Preloaded belongsTo set'); })); })); }); }); -test("initial values of hasMany can be passed in as the third argument to find as records", function() { - expect(1); +test("initial values of hasMany can be passed in as the third argument to find as records", function(assert) { + assert.expect(1); var adapter = TestAdapter.extend({ findRecord: function(store, type, id, snapshot) { - equal(snapshot.hasMany('friends')[0].attr('name'), 'Tom', 'Preloaded hasMany set'); + assert.equal(snapshot.hasMany('friends')[0].attr('name'), 'Tom', 'Preloaded hasMany set'); return new Ember.RSVP.Promise(function() {}); } }); @@ -532,12 +534,12 @@ test("initial values of hasMany can be passed in as the third argument to find a }); }); -test("initial values of hasMany can be passed in as the third argument to find as ids", function() { - expect(1); +test("initial values of hasMany can be passed in as the third argument to find as ids", function(assert) { + assert.expect(1); var adapter = TestAdapter.extend({ findRecord: function(store, type, id, snapshot) { - equal(snapshot.hasMany('friends')[0].id, '2', 'Preloaded hasMany set'); + assert.equal(snapshot.hasMany('friends')[0].id, '2', 'Preloaded hasMany set'); return Ember.RSVP.resolve({ id: id }); } }); @@ -559,8 +561,8 @@ test("initial values of hasMany can be passed in as the third argument to find a }); }); -test("records should have their ids updated when the adapter returns the id data", function() { - expect(2); +test("records should have their ids updated when the adapter returns the id data", function(assert) { + assert.expect(2); var Person = DS.Model.extend({ name: DS.attr('string') @@ -589,14 +591,14 @@ test("records should have their ids updated when the adapter returns the id data run(function() { Ember.RSVP.all([tom.save(), yehuda.save()]).then(async(function() { people.forEach(function(person, index) { - equal(person.get('id'), index + 1, "The record's id should be correct."); + assert.equal(person.get('id'), index + 1, "The record's id should be correct."); }); })); }); }); -test("store.fetchMany should always return a promise", function() { - expect(3); +test("store.fetchMany should always return a promise", function(assert) { + assert.expect(3); var Person = DS.Model.extend(); var store = createStore({ @@ -612,16 +614,16 @@ test("store.fetchMany should always return a promise", function() { run(function() { results = store.scheduleFetchMany(records); }); - ok(results, "A call to store.scheduleFetchMany() should return a result"); - ok(results.then, "A call to store.scheduleFetchMany() should return a promise"); + assert.ok(results, "A call to store.scheduleFetchMany() should return a result"); + assert.ok(results.then, "A call to store.scheduleFetchMany() should return a promise"); results.then(async(function(returnedRecords) { - deepEqual(returnedRecords, [], "The correct records are returned"); + assert.deepEqual(returnedRecords, [], "The correct records are returned"); })); }); -test("store.scheduleFetchMany should not resolve until all the records are resolved", function() { - expect(1); +test("store.scheduleFetchMany should not resolve until all the records are resolved", function(assert) { + assert.expect(1); var Person = DS.Model.extend(); var Phone = DS.Model.extend(); @@ -673,13 +675,13 @@ test("store.scheduleFetchMany should not resolve until all the records are resol run(function() { store.scheduleFetchMany(records).then(async(function() { var unloadedRecords = records.filterBy('isEmpty'); - equal(get(unloadedRecords, 'length'), 0, 'All unloaded records should be loaded'); + assert.equal(get(unloadedRecords, 'length'), 0, 'All unloaded records should be loaded'); })); }); }); -test("the store calls adapter.findMany according to groupings returned by adapter.groupRecordsForFindMany", function() { - expect(3); +test("the store calls adapter.findMany according to groupings returned by adapter.groupRecordsForFindMany", function(assert) { + assert.expect(3); var Person = DS.Model.extend(); @@ -692,7 +694,7 @@ test("the store calls adapter.findMany according to groupings returned by adapte }, findRecord: function(store, type, id, snapshot) { - equal(id, "10", "The first group is passed to find"); + assert.equal(id, "10", "The first group is passed to find"); return Ember.RSVP.resolve({ id: id }); }, @@ -701,7 +703,7 @@ test("the store calls adapter.findMany according to groupings returned by adapte return { id: id }; }); - deepEqual(ids, ["20", "21"], "The second group is passed to findMany"); + assert.deepEqual(ids, ["20", "21"], "The second group is passed to findMany"); return new Ember.RSVP.Promise(function(resolve, reject) { resolve(records); @@ -723,13 +725,13 @@ test("the store calls adapter.findMany according to groupings returned by adapte run(function() { store.scheduleFetchMany(records).then(async(function() { var ids = records.mapBy('id'); - deepEqual(ids, ["10", "20", "21"], "The promise fulfills with the records"); + assert.deepEqual(ids, ["10", "20", "21"], "The promise fulfills with the records"); })); }); }); -test("the promise returned by `scheduleFetch`, when it resolves, does not depend on the promises returned to other calls to `scheduleFetch` that are in the same run loop, but different groups", function() { - expect(2); +test("the promise returned by `scheduleFetch`, when it resolves, does not depend on the promises returned to other calls to `scheduleFetch` that are in the same run loop, but different groups", function(assert) { + assert.expect(2); var Person = DS.Model.extend(); var davidResolved = false; @@ -768,17 +770,17 @@ test("the promise returned by `scheduleFetch`, when it resolves, does not depend var igorPromise = store.findRecord('test', 'igor'); igorPromise.then(async(function () { - equal(davidResolved, false, "Igor did not need to wait for David"); + assert.equal(davidResolved, false, "Igor did not need to wait for David"); })); davidPromise.then(async(function () { - equal(davidResolved, true, "David resolved"); + assert.equal(davidResolved, true, "David resolved"); })); }); }); -test("the promise returned by `scheduleFetch`, when it rejects, does not depend on the promises returned to other calls to `scheduleFetch` that are in the same run loop, but different groups", function() { - expect(2); +test("the promise returned by `scheduleFetch`, when it rejects, does not depend on the promises returned to other calls to `scheduleFetch` that are in the same run loop, but different groups", function(assert) { + assert.expect(2); var Person = DS.Model.extend(); var davidResolved = false; @@ -817,17 +819,17 @@ test("the promise returned by `scheduleFetch`, when it rejects, does not depend var igorPromise = store.findRecord('test', 'igor'); igorPromise.then(null, async(function () { - equal(davidResolved, false, "Igor did not need to wait for David"); + assert.equal(davidResolved, false, "Igor did not need to wait for David"); })); davidPromise.then(async(function () { - equal(davidResolved, true, "David resolved"); + assert.equal(davidResolved, true, "David resolved"); })); }); }); -test("store.fetchRecord reject records that were not found, even when those requests were coalesced with records that were found", function() { - expect(4); +test("store.fetchRecord reject records that were not found, even when those requests were coalesced with records that were found", function(assert) { + assert.expect(4); var Person = DS.Model.extend(); @@ -856,18 +858,18 @@ test("store.fetchRecord reject records that were not found, even when those requ var igorPromise = store.findRecord('test', 'igor'); davidPromise.then(async(function () { - ok(true, "David resolved"); + assert.ok(true, "David resolved"); })); igorPromise.then(null, async(function () { - ok(true, "Igor rejected"); + assert.ok(true, "Igor rejected"); })); }); }, /expected to find records with the following ids in the adapter response but they were missing/); }); -test("store should not call shouldReloadRecord when the record is not in the store", function() { - expect(1); +test("store should not call shouldReloadRecord when the record is not in the store", function(assert) { + assert.expect(1); var Person = DS.Model.extend({ name: DS.attr('string') @@ -875,11 +877,11 @@ test("store should not call shouldReloadRecord when the record is not in the sto var TestAdapter = DS.Adapter.extend({ shouldReloadRecord: function(store, type, id, snapshot) { - ok(false, 'shouldReloadRecord should not be called when the record is not loaded'); + assert.ok(false, 'shouldReloadRecord should not be called when the record is not loaded'); return false; }, findRecord: function() { - ok(true, 'find is always called when the record is not in the store'); + assert.ok(true, 'find is always called when the record is not in the store'); return { id: 1 }; } }); @@ -894,8 +896,8 @@ test("store should not call shouldReloadRecord when the record is not in the sto }); }); -test("store should not reload record when shouldReloadRecord returns false", function() { - expect(1); +test("store should not reload record when shouldReloadRecord returns false", function(assert) { + assert.expect(1); var Person = DS.Model.extend({ name: DS.attr('string') @@ -903,12 +905,12 @@ test("store should not reload record when shouldReloadRecord returns false", fun var TestAdapter = DS.Adapter.extend({ shouldReloadRecord: function(store, type, id, snapshot) { - ok(true, 'shouldReloadRecord should be called when the record is in the store'); + assert.ok(true, 'shouldReloadRecord should be called when the record is in the store'); return false; }, shouldBackgroundReloadRecord: () => false, findRecord: function() { - ok(false, 'find should not be called when shouldReloadRecord returns false'); + assert.ok(false, 'find should not be called when shouldReloadRecord returns false'); } }); @@ -928,8 +930,8 @@ test("store should not reload record when shouldReloadRecord returns false", fun }); }); -test("store should reload record when shouldReloadRecord returns true", function() { - expect(3); +test("store should reload record when shouldReloadRecord returns true", function(assert) { + assert.expect(3); var Person = DS.Model.extend({ name: DS.attr('string') @@ -937,11 +939,11 @@ test("store should reload record when shouldReloadRecord returns true", function var TestAdapter = DS.Adapter.extend({ shouldReloadRecord: function(store, type, id, snapshot) { - ok(true, 'shouldReloadRecord should be called when the record is in the store'); + assert.ok(true, 'shouldReloadRecord should be called when the record is in the store'); return true; }, findRecord: function() { - ok(true, 'find should not be called when shouldReloadRecord returns false'); + assert.ok(true, 'find should not be called when shouldReloadRecord returns false'); return { id: 1, name: 'Tom' }; } }); @@ -959,13 +961,13 @@ test("store should reload record when shouldReloadRecord returns true", function } }); store.findRecord('person', 1).then(function(record) { - equal(record.get('name'), 'Tom'); + assert.equal(record.get('name'), 'Tom'); }); }); }); -test("store should not call shouldBackgroundReloadRecord when the store is already loading the record", function() { - expect(2); +test("store should not call shouldBackgroundReloadRecord when the store is already loading the record", function(assert) { + assert.expect(2); var Person = DS.Model.extend({ name: DS.attr('string') @@ -976,10 +978,10 @@ test("store should not call shouldBackgroundReloadRecord when the store is alrea return true; }, shouldBackgroundReloadRecord: function(store, type, id, snapshot) { - ok(false, 'shouldBackgroundReloadRecord is not called when shouldReloadRecord returns true'); + assert.ok(false, 'shouldBackgroundReloadRecord is not called when shouldReloadRecord returns true'); }, findRecord: function() { - ok(true, 'find should be called'); + assert.ok(true, 'find should be called'); return { id: 1, name: 'Tom' }; } }); @@ -997,13 +999,13 @@ test("store should not call shouldBackgroundReloadRecord when the store is alrea } }); store.findRecord('person', 1).then(function(record) { - equal(record.get('name'), 'Tom'); + assert.equal(record.get('name'), 'Tom'); }); }); }); -test("store should not reload a record when `shouldBackgroundReloadRecord` is false", function() { - expect(2); +test("store should not reload a record when `shouldBackgroundReloadRecord` is false", function(assert) { + assert.expect(2); var Person = DS.Model.extend({ name: DS.attr('string') @@ -1011,11 +1013,11 @@ test("store should not reload a record when `shouldBackgroundReloadRecord` is fa var TestAdapter = DS.Adapter.extend({ shouldBackgroundReloadRecord: function(store, type, id, snapshot) { - ok(true, 'shouldBackgroundReloadRecord is called when record is loaded form the cache'); + assert.ok(true, 'shouldBackgroundReloadRecord is called when record is loaded form the cache'); return false; }, findRecord: function() { - ok(false, 'find should not be called'); + assert.ok(false, 'find should not be called'); return { id: 1, name: 'Tom' }; } }); @@ -1033,14 +1035,14 @@ test("store should not reload a record when `shouldBackgroundReloadRecord` is fa } }); store.findRecord('person', 1).then(function(record) { - equal(record.get('name'), undefined); + assert.equal(record.get('name'), undefined); }); }); }); -test("store should reload the record in the background when `shouldBackgroundReloadRecord` is true", function() { - expect(4); +test("store should reload the record in the background when `shouldBackgroundReloadRecord` is true", function(assert) { + assert.expect(4); var Person = DS.Model.extend({ name: DS.attr('string') @@ -1048,11 +1050,11 @@ test("store should reload the record in the background when `shouldBackgroundRel var TestAdapter = DS.Adapter.extend({ shouldBackgroundReloadRecord: function(store, type, id, snapshot) { - ok(true, 'shouldBackgroundReloadRecord is called when record is loaded form the cache'); + assert.ok(true, 'shouldBackgroundReloadRecord is called when record is loaded form the cache'); return true; }, findRecord: function() { - ok(true, 'find should not be called'); + assert.ok(true, 'find should not be called'); return { id: 1, name: 'Tom' }; } }); @@ -1070,15 +1072,15 @@ test("store should reload the record in the background when `shouldBackgroundRel } }); store.findRecord('person', 1).then(function(record) { - equal(record.get('name'), undefined); + assert.equal(record.get('name'), undefined); }); }); - equal(store.peekRecord('person', 1).get('name'), 'Tom'); + assert.equal(store.peekRecord('person', 1).get('name'), 'Tom'); }); -test("store should not reload record array when shouldReloadAll returns false", function() { - expect(1); +test("store should not reload record array when shouldReloadAll returns false", function(assert) { + assert.expect(1); var Person = DS.Model.extend({ name: DS.attr('string') @@ -1086,14 +1088,14 @@ test("store should not reload record array when shouldReloadAll returns false", var TestAdapter = DS.Adapter.extend({ shouldReloadAll: function(store, snapshot) { - ok(true, 'shouldReloadAll should be called when the record is in the store'); + assert.ok(true, 'shouldReloadAll should be called when the record is in the store'); return false; }, shouldBackgroundReloadAll: function(store, snapshot) { return false; }, findAll: function() { - ok(false, 'findAll should not be called when shouldReloadAll returns false'); + assert.ok(false, 'findAll should not be called when shouldReloadAll returns false'); } }); @@ -1107,8 +1109,8 @@ test("store should not reload record array when shouldReloadAll returns false", }); }); -test("store should reload all records when shouldReloadAll returns true", function() { - expect(3); +test("store should reload all records when shouldReloadAll returns true", function(assert) { + assert.expect(3); var Person = DS.Model.extend({ name: DS.attr('string') @@ -1116,11 +1118,11 @@ test("store should reload all records when shouldReloadAll returns true", functi var TestAdapter = DS.Adapter.extend({ shouldReloadAll: function(store, type, id, snapshot) { - ok(true, 'shouldReloadAll should be called when the record is in the store'); + assert.ok(true, 'shouldReloadAll should be called when the record is in the store'); return true; }, findAll: function() { - ok(true, 'findAll should be called when shouldReloadAll returns true'); + assert.ok(true, 'findAll should be called when shouldReloadAll returns true'); return [{ id: 1, name: 'Tom' }]; } }); @@ -1132,13 +1134,13 @@ test("store should reload all records when shouldReloadAll returns true", functi run(function() { store.findAll('person').then(function(records) { - equal(records.get('firstObject.name'), 'Tom'); + assert.equal(records.get('firstObject.name'), 'Tom'); }); }); }); -test("store should not call shouldBackgroundReloadAll when the store is already loading all records", function() { - expect(2); +test("store should not call shouldBackgroundReloadAll when the store is already loading all records", function(assert) { + assert.expect(2); var Person = DS.Model.extend({ name: DS.attr('string') @@ -1149,10 +1151,10 @@ test("store should not call shouldBackgroundReloadAll when the store is already return true; }, shouldBackgroundReloadAll: function(store, type, id, snapshot) { - ok(false, 'shouldBackgroundReloadRecord is not called when shouldReloadRecord returns true'); + assert.ok(false, 'shouldBackgroundReloadRecord is not called when shouldReloadRecord returns true'); }, findAll: function() { - ok(true, 'find should be called'); + assert.ok(true, 'find should be called'); return [{ id: 1, name: 'Tom' }]; } }); @@ -1164,13 +1166,13 @@ test("store should not call shouldBackgroundReloadAll when the store is already run(function() { store.findAll('person').then(function(records) { - equal(records.get('firstObject.name'), 'Tom'); + assert.equal(records.get('firstObject.name'), 'Tom'); }); }); }); -test("store should not reload all records when `shouldBackgroundReloadAll` is false", function() { - expect(3); +test("store should not reload all records when `shouldBackgroundReloadAll` is false", function(assert) { + assert.expect(3); var Person = DS.Model.extend({ name: DS.attr('string') @@ -1178,15 +1180,15 @@ test("store should not reload all records when `shouldBackgroundReloadAll` is fa var TestAdapter = DS.Adapter.extend({ shouldReloadAll: function(store, type, id, snapshot) { - ok(true, 'shouldReloadAll is called when record is loaded form the cache'); + assert.ok(true, 'shouldReloadAll is called when record is loaded form the cache'); return false; }, shouldBackgroundReloadAll: function(store, type, id, snapshot) { - ok(true, 'shouldBackgroundReloadAll is called when record is loaded form the cache'); + assert.ok(true, 'shouldBackgroundReloadAll is called when record is loaded form the cache'); return false; }, findAll: function() { - ok(false, 'findAll should not be called'); + assert.ok(false, 'findAll should not be called'); return [{ id: 1, name: 'Tom' }]; } }); @@ -1198,14 +1200,14 @@ test("store should not reload all records when `shouldBackgroundReloadAll` is fa run(function() { store.findAll('person').then(function(records) { - equal(records.get('firstObject'), undefined); + assert.equal(records.get('firstObject'), undefined); }); }); }); -test("store should reload all records in the background when `shouldBackgroundReloadAll` is true", function() { - expect(5); +test("store should reload all records in the background when `shouldBackgroundReloadAll` is true", function(assert) { + assert.expect(5); var Person = DS.Model.extend({ name: DS.attr('string') @@ -1213,15 +1215,15 @@ test("store should reload all records in the background when `shouldBackgroundRe var TestAdapter = DS.Adapter.extend({ shouldReloadAll: function() { - ok(true, 'shouldReloadAll is called'); + assert.ok(true, 'shouldReloadAll is called'); return false; }, shouldBackgroundReloadAll: function(store, snapshot) { - ok(true, 'shouldBackgroundReloadAll is called when record is loaded form the cache'); + assert.ok(true, 'shouldBackgroundReloadAll is called when record is loaded form the cache'); return true; }, findAll: function() { - ok(true, 'find should not be called'); + assert.ok(true, 'find should not be called'); return [{ id: 1, name: 'Tom' }]; } }); @@ -1233,15 +1235,15 @@ test("store should reload all records in the background when `shouldBackgroundRe run(function() { store.findAll('person').then(function(records) { - equal(records.get('firstObject.name'), undefined); + assert.equal(records.get('firstObject.name'), undefined); }); }); - equal(store.peekRecord('person', 1).get('name'), 'Tom'); + assert.equal(store.peekRecord('person', 1).get('name'), 'Tom'); }); -test("store should assert of the user tries to call store.filter", function() { - expect(1); +test("store should assert of the user tries to call store.filter", function(assert) { + assert.expect(1); var Person = DS.Model.extend({ name: DS.attr('string') @@ -1259,7 +1261,7 @@ test("store should assert of the user tries to call store.filter", function() { }); -test("Calling adapterFor with a model class should assert", function() { +test("Calling adapterFor with a model class should assert", function(assert) { var Person = DS.Model.extend({ name: DS.attr('string') }); diff --git a/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js index 1b906374062..9f1f40fc801 100644 --- a/tests/unit/store/create-record-test.js +++ b/tests/unit/store/create-record-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var store, container, Record, Storage; var run = Ember.run; module("unit/store/createRecord - Store creating records", { - setup: function() { + beforeEach: function() { Record = DS.Model.extend({ title: DS.attr('string') }); @@ -24,17 +26,17 @@ module("unit/store/createRecord - Store creating records", { } }); -test("doesn't modify passed in properties hash", function() { +test("doesn't modify passed in properties hash", function(assert) { var attributes = { foo: 'bar' }; run(function() { store.createRecord('record', attributes); store.createRecord('record', attributes); }); - deepEqual(attributes, { foo: 'bar' }, "The properties hash is not modified"); + assert.deepEqual(attributes, { foo: 'bar' }, "The properties hash is not modified"); }); -test("allow passing relationships as well as attributes", function() { +test("allow passing relationships as well as attributes", function(assert) { var records, storage; run(function() { store.push({ @@ -56,13 +58,13 @@ test("allow passing relationships as well as attributes", function() { storage = store.createRecord('storage', { name: 'Great store', records: records }); }); - equal(storage.get('name'), 'Great store', "The attribute is well defined"); - equal(storage.get('records').findBy('id', '1'), Ember.A(records).findBy('id', '1'), "Defined relationships are allowed in createRecord"); - equal(storage.get('records').findBy('id', '2'), Ember.A(records).findBy('id', '2'), "Defined relationships are allowed in createRecord"); + assert.equal(storage.get('name'), 'Great store', "The attribute is well defined"); + assert.equal(storage.get('records').findBy('id', '1'), Ember.A(records).findBy('id', '1'), "Defined relationships are allowed in createRecord"); + assert.equal(storage.get('records').findBy('id', '2'), Ember.A(records).findBy('id', '2'), "Defined relationships are allowed in createRecord"); }); module("unit/store/createRecord - Store with models by dash", { - setup: function() { + beforeEach: function() { var env = setupStore({ someThing: DS.Model.extend({ foo: DS.attr('string') }) }); @@ -71,7 +73,7 @@ module("unit/store/createRecord - Store with models by dash", { } }); -test("creating a record by camel-case string finds the model", function() { +test("creating a record by camel-case string finds the model", function(assert) { var attributes = { foo: 'bar' }; var record; @@ -79,11 +81,11 @@ test("creating a record by camel-case string finds the model", function() { record = store.createRecord('some-thing', attributes); }); - equal(record.get('foo'), attributes.foo, "The record is created"); - equal(store.modelFor('someThing').modelName, 'some-thing'); + assert.equal(record.get('foo'), attributes.foo, "The record is created"); + assert.equal(store.modelFor('someThing').modelName, 'some-thing'); }); -test("creating a record by dasherize string finds the model", function() { +test("creating a record by dasherize string finds the model", function(assert) { var attributes = { foo: 'bar' }; var record; @@ -91,6 +93,6 @@ test("creating a record by dasherize string finds the model", function() { record = store.createRecord('some-thing', attributes); }); - equal(record.get('foo'), attributes.foo, "The record is created"); - equal(store.modelFor('some-thing').modelName, 'some-thing'); + assert.equal(record.get('foo'), attributes.foo, "The record is created"); + assert.equal(store.modelFor('some-thing').modelName, 'some-thing'); }); diff --git a/tests/unit/store/has-record-for-id-test.js b/tests/unit/store/has-record-for-id-test.js index 11e025e3d6d..ba44d2016e4 100644 --- a/tests/unit/store/has-record-for-id-test.js +++ b/tests/unit/store/has-record-for-id-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, Person, PhoneNumber; @@ -9,7 +11,7 @@ var belongsTo = DS.belongsTo; var run = Ember.run; module("unit/store/hasRecordForId - Store hasRecordForId", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ firstName: attr('string'), @@ -37,12 +39,12 @@ module("unit/store/hasRecordForId - Store hasRecordForId", { }, - teardown: function() { + afterEach: function() { Ember.run(store, 'destroy'); } }); -test("hasRecordForId should return false for records in the empty state ", function() { +test("hasRecordForId should return false for records in the empty state ", function(assert) { run(function() { store.push({ @@ -63,12 +65,12 @@ test("hasRecordForId should return false for records in the empty state ", funct } }); - equal(false, store.hasRecordForId('phone-number', 1), 'hasRecordForId only returns true for loaded records'); + assert.equal(false, store.hasRecordForId('phone-number', 1), 'hasRecordForId only returns true for loaded records'); }); }); -test("hasRecordForId should return true for records in the loaded state ", function() { +test("hasRecordForId should return true for records in the loaded state ", function(assert) { run(function() { store.push({ data: { @@ -88,6 +90,6 @@ test("hasRecordForId should return true for records in the loaded state ", funct } }); - equal(true, store.hasRecordForId('person', 1), 'hasRecordForId returns true for records loaded into the store'); + assert.equal(true, store.hasRecordForId('person', 1), 'hasRecordForId returns true for records loaded into the store'); }); }); diff --git a/tests/unit/store/lookup-test.js b/tests/unit/store/lookup-test.js index 9284f76f95e..cef75d82851 100644 --- a/tests/unit/store/lookup-test.js +++ b/tests/unit/store/lookup-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var store, env, applicationAdapter, applicationSerializer, Person; @@ -40,7 +42,7 @@ function registerSerializer(serializerName, serializer) { } module('unit/store/lookup - Managed Instance lookups', { - setup() { + beforeEach() { Person = DS.Model.extend(); resetStore(); env.registry.register('adapter:application', DS.Adapter.extend()); @@ -50,7 +52,7 @@ module('unit/store/lookup - Managed Instance lookups', { applicationSerializer = run(store, 'serializerFor', 'application'); }, - teardown() { + afterEach() { run(store, 'destroy'); } }); @@ -58,20 +60,20 @@ module('unit/store/lookup - Managed Instance lookups', { test('when the adapter does not exist for a type, the fallback is returned', () => { let personAdapter = lookupAdapter('person'); - strictEqual(personAdapter, applicationAdapter); + assert.strictEqual(personAdapter, applicationAdapter); }); test('when the adapter for a type exists, returns that instead of the fallback', () => { registerAdapter('person', DS.Adapter.extend()); let personAdapter = lookupAdapter('person'); - ok(personAdapter !== applicationAdapter); + assert.ok(personAdapter !== applicationAdapter); }); test('when the serializer does not exist for a type, the fallback is returned', () => { let personSerializer = lookupSerializer('person'); - strictEqual(personSerializer, applicationSerializer); + assert.strictEqual(personSerializer, applicationSerializer); }); test('when the serializer does exist for a type, the serializer is returned', () => { @@ -79,30 +81,30 @@ test('when the serializer does exist for a type, the serializer is returned', () let personSerializer = lookupSerializer('person'); - ok(personSerializer !== applicationSerializer); + assert.ok(personSerializer !== applicationSerializer); }); test('adapter lookup order', () => { - expect(3); + assert.expect(3); resetStore(); let personAdapter = lookupAdapter('person'); - strictEqual(personAdapter, lookupAdapter('-rest'), 'looks up the RESTAdapter first'); + assert.strictEqual(personAdapter, lookupAdapter('-rest'), 'looks up the RESTAdapter first'); resetStore(); registerAdapter('application', DS.RESTSerializer.extend()); personAdapter = lookupAdapter('person'); - strictEqual(personAdapter, lookupAdapter('application'), 'looks up application adapter before RESTAdapter if it exists'); + assert.strictEqual(personAdapter, lookupAdapter('application'), 'looks up application adapter before RESTAdapter if it exists'); resetStore(); registerAdapter('application', DS.RESTSerializer.extend()); registerAdapter('person', DS.RESTSerializer.extend({ customThingy: true })); - ok(lookupAdapter('person').get('customThingy'), 'looks up type serializer before application'); + assert.ok(lookupAdapter('person').get('customThingy'), 'looks up type serializer before application'); }); test('serializer lookup order', () => { @@ -110,13 +112,13 @@ test('serializer lookup order', () => { let personSerializer = lookupSerializer('person'); - strictEqual(personSerializer, lookupSerializer('-rest')); + assert.strictEqual(personSerializer, lookupSerializer('-rest')); resetStore(); registerSerializer('application', DS.RESTSerializer.extend()); personSerializer = lookupSerializer('person'); - strictEqual(personSerializer, lookupSerializer('application'), 'looks up application before default'); + assert.strictEqual(personSerializer, lookupSerializer('application'), 'looks up application before default'); resetStore(); registerAdapter('person', DS.Adapter.extend({ @@ -124,7 +126,7 @@ test('serializer lookup order', () => { })); personSerializer = lookupSerializer('person'); - strictEqual(personSerializer, lookupSerializer('-rest'), 'uses defaultSerializer on adapterFor("model") if application not defined'); + assert.strictEqual(personSerializer, lookupSerializer('-rest'), 'uses defaultSerializer on adapterFor("model") if application not defined'); resetStore(); registerAdapter('person', DS.Adapter.extend({ @@ -134,6 +136,6 @@ test('serializer lookup order', () => { registerSerializer('person', DS.JSONSerializer.extend({ customThingy: true })); personSerializer = lookupSerializer('person'); - ok(personSerializer.get('customThingy'), 'uses the person serializer before any fallbacks if it is defined'); + assert.ok(personSerializer.get('customThingy'), 'uses the person serializer before any fallbacks if it is defined'); }); diff --git a/tests/unit/store/model-for-test.js b/tests/unit/store/model-for-test.js index 6b7ecdda20a..0571fe9ae7a 100644 --- a/tests/unit/store/model-for-test.js +++ b/tests/unit/store/model-for-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var container, store, registry; @@ -11,7 +13,7 @@ var run = Ember.run; var env; module("unit/store/model_for - DS.Store#modelFor", { - setup: function() { + beforeEach: function() { env = setupStore({ blogPost: DS.Model.extend(), "blog.post": DS.Model.extend() @@ -21,7 +23,7 @@ module("unit/store/model_for - DS.Store#modelFor", { registry = env.registry; }, - teardown: function() { + afterEach: function() { run(function() { container.destroy(); store.destroy(); @@ -29,25 +31,25 @@ module("unit/store/model_for - DS.Store#modelFor", { } }); -test("when fetching factory from string, sets a normalized key as modelName", function() { +test("when fetching factory from string, sets a normalized key as modelName", function(assert) { env.replaceContainerNormalize(function(key) { return dasherize(camelize(key)); }); - equal(registry.normalize('some.post'), 'some-post', 'precond - container camelizes'); - equal(store.modelFor("blog.post").modelName, "blog.post", "modelName is normalized to dasherized"); + assert.equal(registry.normalize('some.post'), 'some-post', 'precond - container camelizes'); + assert.equal(store.modelFor("blog.post").modelName, "blog.post", "modelName is normalized to dasherized"); }); -test("when fetching factory from string and dashing normalizer, sets a normalized key as modelName", function() { +test("when fetching factory from string and dashing normalizer, sets a normalized key as modelName", function(assert) { env.replaceContainerNormalize(function(key) { return dasherize(camelize(key)); }); - equal(registry.normalize('some.post'), 'some-post', 'precond - container dasherizes'); - equal(store.modelFor("blog.post").modelName, "blog.post", "modelName is normalized to dasherized"); + assert.equal(registry.normalize('some.post'), 'some-post', 'precond - container dasherizes'); + assert.equal(store.modelFor("blog.post").modelName, "blog.post", "modelName is normalized to dasherized"); }); -test("when fetching something that doesn't exist, throws error", function() { - throws(function() { +test("when fetching something that doesn't exist, throws error", function(assert) { + assert.throws(function() { store.modelFor('wild-stuff'); }, /No model was found/); }); diff --git a/tests/unit/store/peek-record-test.js b/tests/unit/store/peek-record-test.js index ab9dd43085f..ade7816b627 100644 --- a/tests/unit/store/peek-record-test.js +++ b/tests/unit/store/peek-record-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, Person; var run = Ember.run; module("unit/store/peekRecord - Store peekRecord", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend(); Person.toString = function() { @@ -19,12 +21,12 @@ module("unit/store/peekRecord - Store peekRecord", { store = env.store; }, - teardown: function() { + afterEach: function() { Ember.run(store, 'destroy'); } }); -test("peekRecord should return the record if it is in the store ", function() { +test("peekRecord should return the record if it is in the store ", function(assert) { run(function() { var person = store.push({ data: { @@ -32,12 +34,12 @@ test("peekRecord should return the record if it is in the store ", function() { id: '1' } }); - equal(person, store.peekRecord('person', 1), 'peekRecord only return the corresponding record in the store'); + assert.equal(person, store.peekRecord('person', 1), 'peekRecord only return the corresponding record in the store'); }); }); -test("peekRecord should return null if the record is not in the store ", function() { +test("peekRecord should return null if the record is not in the store ", function(assert) { run(function() { - equal(null, store.peekRecord('person', 1), 'peekRecord returns null if the corresponding record is not in the store'); + assert.equal(null, store.peekRecord('person', 1), 'peekRecord returns null if the corresponding record is not in the store'); }); }); diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index 60de010d15e..4266a805d9b 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var env, store, Person, PhoneNumber, Post; @@ -9,7 +11,7 @@ var belongsTo = DS.belongsTo; var run = Ember.run; module("unit/store/push - DS.Store#push", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ firstName: attr('string'), lastName: attr('string'), @@ -45,15 +47,15 @@ module("unit/store/push - DS.Store#push", { env.registry.register('serializer:post', DS.RESTSerializer); }, - teardown: function() { + afterEach: function() { run(function() { store.destroy(); }); } }); -test("Calling push with a normalized hash returns a record", function() { - expect(2); +test("Calling push with a normalized hash returns a record", function(assert) { + assert.expect(2); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { @@ -68,8 +70,8 @@ test("Calling push with a normalized hash returns a record", function() { } }); store.findRecord('person', 'wat').then(function(foundPerson) { - equal(foundPerson, person, "record returned via load() is the same as the record returned from findRecord()"); - deepEqual(foundPerson.getProperties('id', 'firstName', 'lastName'), { + assert.equal(foundPerson, person, "record returned via load() is the same as the record returned from findRecord()"); + assert.deepEqual(foundPerson.getProperties('id', 'firstName', 'lastName'), { id: 'wat', firstName: 'Yehuda', lastName: 'Katz' @@ -78,8 +80,8 @@ test("Calling push with a normalized hash returns a record", function() { }); }); -test("Supplying a model class for `push` is the same as supplying a string", function () { - expect(1); +test("Supplying a model class for `push` is the same as supplying a string", function(assert) { + assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; var Programmer = Person.extend(); @@ -98,7 +100,7 @@ test("Supplying a model class for `push` is the same as supplying a string", fun }); store.findRecord('programmer', 'wat').then(function(foundProgrammer) { - deepEqual(foundProgrammer.getProperties('id', 'firstName', 'lastName'), { + assert.deepEqual(foundProgrammer.getProperties('id', 'firstName', 'lastName'), { id: 'wat', firstName: 'Yehuda', lastName: 'Katz' @@ -107,12 +109,12 @@ test("Supplying a model class for `push` is the same as supplying a string", fun }); }); -test("Calling push triggers `didLoad` even if the record hasn't been requested from the adapter", function() { - expect(1); +test("Calling push triggers `didLoad` even if the record hasn't been requested from the adapter", function(assert) { + assert.expect(1); Person.reopen({ didLoad: async(function() { - ok(true, "The didLoad callback was called"); + assert.ok(true, "The didLoad callback was called"); }) }); @@ -130,8 +132,8 @@ test("Calling push triggers `didLoad` even if the record hasn't been requested f }); }); -test("Calling push with partial records updates just those attributes", function() { - expect(2); +test("Calling push with partial records updates just those attributes", function(assert) { + assert.expect(2); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { @@ -158,8 +160,8 @@ test("Calling push with partial records updates just those attributes", function }); store.findRecord('person', 'wat').then(function(foundPerson) { - equal(foundPerson, person, "record returned via load() is the same as the record returned from findRecord()"); - deepEqual(foundPerson.getProperties('id', 'firstName', 'lastName'), { + assert.equal(foundPerson, person, "record returned via load() is the same as the record returned from findRecord()"); + assert.deepEqual(foundPerson.getProperties('id', 'firstName', 'lastName'), { id: 'wat', firstName: 'Yehuda', lastName: "Katz!" @@ -168,7 +170,7 @@ test("Calling push with partial records updates just those attributes", function }); }); -test("Calling push on normalize allows partial updates with raw JSON", function () { +test("Calling push on normalize allows partial updates with raw JSON", function(assert) { env.registry.register('serializer:person', DS.RESTSerializer); var person; @@ -190,12 +192,12 @@ test("Calling push on normalize allows partial updates with raw JSON", function })); }); - equal(person.get('firstName'), "Jacquie", "you can push raw JSON into the store"); - equal(person.get('lastName'), "Jackson", "existing fields are untouched"); + assert.equal(person.get('firstName'), "Jacquie", "you can push raw JSON into the store"); + assert.equal(person.get('lastName'), "Jackson", "existing fields are untouched"); }); -test("Calling push with a normalized hash containing IDs of related records returns a record", function() { - expect(1); +test("Calling push with a normalized hash containing IDs of related records returns a record", function(assert) { + assert.expect(1); Person.reopen({ phoneNumbers: hasMany('phone-number', { async: true }) @@ -228,7 +230,7 @@ test("Calling push with a normalized hash containing IDs of related records retu phoneNumbers: ["1", "2"] })); person.get('phoneNumbers').then(function(phoneNumbers) { - deepEqual(phoneNumbers.map(function(item) { + assert.deepEqual(phoneNumbers.map(function(item) { return item.getProperties('id', 'number', 'person'); }), [{ id: "1", @@ -243,7 +245,7 @@ test("Calling push with a normalized hash containing IDs of related records retu }); }); -test("Calling pushPayload allows pushing raw JSON", function () { +test("Calling pushPayload allows pushing raw JSON", function(assert) { run(function() { store.pushPayload('post', { posts: [{ @@ -255,7 +257,7 @@ test("Calling pushPayload allows pushing raw JSON", function () { var post = store.peekRecord('post', 1); - equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); + assert.equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); run(function() { store.pushPayload('post', { @@ -266,10 +268,10 @@ test("Calling pushPayload allows pushing raw JSON", function () { }); }); - equal(post.get('postTitle'), "Ember rocks (updated)", "You can update data in the store"); + assert.equal(post.get('postTitle'), "Ember rocks (updated)", "You can update data in the store"); }); -test("Calling pushPayload allows pushing singular payload properties", function () { +test("Calling pushPayload allows pushing singular payload properties", function(assert) { run(function() { store.pushPayload('post', { post: { @@ -281,7 +283,7 @@ test("Calling pushPayload allows pushing singular payload properties", function var post = store.peekRecord('post', 1); - equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); + assert.equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); run(function() { store.pushPayload('post', { @@ -292,20 +294,20 @@ test("Calling pushPayload allows pushing singular payload properties", function }); }); - equal(post.get('postTitle'), "Ember rocks (updated)", "You can update data in the store"); + assert.equal(post.get('postTitle'), "Ember rocks (updated)", "You can update data in the store"); }); -test("Calling pushPayload should use the type's serializer for normalizing", function () { - expect(4); +test("Calling pushPayload should use the type's serializer for normalizing", function(assert) { + assert.expect(4); env.registry.register('serializer:post', DS.RESTSerializer.extend({ normalize: function(store, payload) { - ok(true, "normalized is called on Post serializer"); + assert.ok(true, "normalized is called on Post serializer"); return this._super(store, payload); } })); env.registry.register('serializer:person', DS.RESTSerializer.extend({ normalize: function(store, payload) { - ok(true, "normalized is called on Person serializer"); + assert.ok(true, "normalized is called on Person serializer"); return this._super(store, payload); } })); @@ -325,19 +327,19 @@ test("Calling pushPayload should use the type's serializer for normalizing", fun var post = store.peekRecord('post', 1); - equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); + assert.equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); var person = store.peekRecord('person', 2); - equal(person.get('firstName'), "Yehuda", "you can push raw JSON into the store"); + assert.equal(person.get('firstName'), "Yehuda", "you can push raw JSON into the store"); }); -test("Calling pushPayload without a type uses application serializer's pushPayload method", function () { - expect(1); +test("Calling pushPayload without a type uses application serializer's pushPayload method", function(assert) { + assert.expect(1); env.registry.register('serializer:application', DS.RESTSerializer.extend({ pushPayload: function(store, payload) { - ok(true, "pushPayload is called on Application serializer"); + assert.ok(true, "pushPayload is called on Application serializer"); return this._super(store, payload); } })); @@ -349,19 +351,19 @@ test("Calling pushPayload without a type uses application serializer's pushPaylo }); }); -test("Calling pushPayload without a type should use a model's serializer when normalizing", function () { - expect(4); +test("Calling pushPayload without a type should use a model's serializer when normalizing", function(assert) { + assert.expect(4); env.registry.register('serializer:post', DS.RESTSerializer.extend({ normalize: function(store, payload) { - ok(true, "normalized is called on Post serializer"); + assert.ok(true, "normalized is called on Post serializer"); return this._super(store, payload); } })); env.registry.register('serializer:application', DS.RESTSerializer.extend({ normalize: function(store, payload) { - ok(true, "normalized is called on Application serializer"); + assert.ok(true, "normalized is called on Application serializer"); return this._super(store, payload); } })); @@ -381,14 +383,14 @@ test("Calling pushPayload without a type should use a model's serializer when no var post = store.peekRecord('post', 1); - equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); + assert.equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); var person = store.peekRecord('person', 2); - equal(person.get('firstName'), "Yehuda", "you can push raw JSON into the store"); + assert.equal(person.get('firstName'), "Yehuda", "you can push raw JSON into the store"); }); -test("Calling pushPayload allows partial updates with raw JSON", function () { +test("Calling pushPayload allows partial updates with raw JSON", function(assert) { env.registry.register('serializer:person', DS.RESTSerializer); var person; @@ -405,8 +407,8 @@ test("Calling pushPayload allows partial updates with raw JSON", function () { person = store.peekRecord('person', 1); - equal(person.get('firstName'), "Robert", "you can push raw JSON into the store"); - equal(person.get('lastName'), "Jackson", "you can push raw JSON into the store"); + assert.equal(person.get('firstName'), "Robert", "you can push raw JSON into the store"); + assert.equal(person.get('lastName'), "Jackson", "you can push raw JSON into the store"); run(function() { store.pushPayload('person', { @@ -417,11 +419,11 @@ test("Calling pushPayload allows partial updates with raw JSON", function () { }); }); - equal(person.get('firstName'), "Jacquie", "you can push raw JSON into the store"); - equal(person.get('lastName'), "Jackson", "existing fields are untouched"); + assert.equal(person.get('firstName'), "Jacquie", "you can push raw JSON into the store"); + assert.equal(person.get('lastName'), "Jackson", "existing fields are untouched"); }); -test('calling push without data argument as an object raises an error', function() { +test('calling push without data argument as an object raises an error', function(assert) { var invalidValues = [ null, 1, @@ -431,10 +433,10 @@ test('calling push without data argument as an object raises an error', function true ]; - expect(invalidValues.length); + assert.expect(invalidValues.length); invalidValues.forEach(function(invalidValue) { - throws(function() { + assert.throws(function() { run(function() { store.push('person', invalidValue); }); @@ -442,7 +444,7 @@ test('calling push without data argument as an object raises an error', function }); }); -test('Calling push with a link for a non async relationship should warn', function() { +test('Calling push with a link for a non async relationship should warn', function(assert) { Person.reopen({ phoneNumbers: hasMany('phone-number', { async: false }) }); @@ -459,7 +461,7 @@ test('Calling push with a link for a non async relationship should warn', functi }, /You have pushed a record of type 'person' with 'phoneNumbers' as a link, but the association is not an async relationship./); }); -test('Calling push with an unknown model name throws an assertion error', function() { +test('Calling push with an unknown model name throws an assertion error', function(assert) { expectAssertion(function() { run(function() { @@ -473,7 +475,7 @@ test('Calling push with an unknown model name throws an assertion error', functi }, /You tried to push data with a type 'unknown' but no model could be found with that name/); }); -test('Calling push with a link containing an object', function() { +test('Calling push with a link containing an object', function(assert) { Person.reopen({ phoneNumbers: hasMany('phone-number', { async: true }) }); @@ -492,10 +494,10 @@ test('Calling push with a link containing an object', function() { var person = store.peekRecord('person', 1); - equal(person.get('firstName'), "Tan", "you can use links containing an object"); + assert.equal(person.get('firstName'), "Tan", "you can use links containing an object"); }); -test('Calling push with a link containing the value null', function() { +test('Calling push with a link containing the value null', function(assert) { run(function() { store.push(store.normalize('person', { id: '1', @@ -508,10 +510,10 @@ test('Calling push with a link containing the value null', function() { var person = store.peekRecord('person', 1); - equal(person.get('firstName'), "Tan", "you can use links that contain null as a value"); + assert.equal(person.get('firstName'), "Tan", "you can use links that contain null as a value"); }); -test('calling push with hasMany relationship the value must be an array', function() { +test('calling push with hasMany relationship the value must be an array', function(assert) { var invalidValues = [ 1, 'string', @@ -520,10 +522,10 @@ test('calling push with hasMany relationship the value must be an array', functi true ]; - expect(invalidValues.length); + assert.expect(invalidValues.length); invalidValues.forEach(function(invalidValue) { - throws(function() { + assert.throws(function() { run(function() { store.push({ data: { @@ -541,17 +543,17 @@ test('calling push with hasMany relationship the value must be an array', functi }); }); -test('calling push with missing or invalid `id` throws assertion error', function() { +test('calling push with missing or invalid `id` throws assertion error', function(assert) { var invalidValues = [ {}, { id: null }, { id: '' } ]; - expect(invalidValues.length); + assert.expect(invalidValues.length); invalidValues.forEach(function(invalidValue) { - throws(function() { + assert.throws(function() { run(function() { store.push({ data: invalidValue @@ -561,8 +563,8 @@ test('calling push with missing or invalid `id` throws assertion error', functio }); }); -test('calling push with belongsTo relationship the value must not be an array', function() { - throws(function() { +test('calling push with belongsTo relationship the value must not be an array', function(assert) { + assert.throws(function() { run(function() { store.push({ data: { @@ -579,7 +581,7 @@ test('calling push with belongsTo relationship the value must not be an array', }, /must not be an array/); }); -test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown keys", function() { +test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown keys", function(assert) { run(function() { var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; try { @@ -603,7 +605,7 @@ test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown keys", f }); }); -test("Calling push with unknown keys should not warn by default", function() { +test("Calling push with unknown keys should not warn by default", function(assert) { noWarns(function() { run(function() { store.push({ @@ -622,7 +624,7 @@ test("Calling push with unknown keys should not warn by default", function() { }); module("unit/store/push - DS.Store#push with JSON-API", { - setup: function() { + beforeEach: function() { var Person = DS.Model.extend({ name: DS.attr('string'), cars: DS.hasMany('car', { async: false }) @@ -647,7 +649,7 @@ module("unit/store/push - DS.Store#push with JSON-API", { }, - teardown: function() { + afterEach: function() { run(function() { store.destroy(); }); @@ -655,8 +657,8 @@ module("unit/store/push - DS.Store#push with JSON-API", { }); -test("Should support pushing multiple models into the store", function() { - expect(2); +test("Should support pushing multiple models into the store", function(assert) { + assert.expect(2); run(function() { store.push({ @@ -677,15 +679,15 @@ test("Should support pushing multiple models into the store", function() { }); var tom = store.peekRecord('person', 1); - equal(tom.get('name'), 'Tom Dale', 'Tom should be in the store'); + assert.equal(tom.get('name'), 'Tom Dale', 'Tom should be in the store'); var tomster = store.peekRecord('person', 2); - equal(tomster.get('name'), 'Tomster', 'Tomster should be in the store'); + assert.equal(tomster.get('name'), 'Tomster', 'Tomster should be in the store'); }); -test("Should support pushing included models into the store", function() { - expect(2); +test("Should support pushing included models into the store", function(assert) { + assert.expect(2); run(function() { store.push({ @@ -722,8 +724,8 @@ test("Should support pushing included models into the store", function() { }); var tomster = store.peekRecord('person', 1); - equal(tomster.get('name'), 'Tomster', 'Tomster should be in the store'); + assert.equal(tomster.get('name'), 'Tomster', 'Tomster should be in the store'); var car = store.peekRecord('car', 1); - equal(car.get('model'), 'Neon', 'Tomster\'s car should be in the store'); + assert.equal(car.get('model'), 'Neon', 'Tomster\'s car should be in the store'); }); diff --git a/tests/unit/store/serializer-for-test.js b/tests/unit/store/serializer-for-test.js index 87a8e3faf4f..b11570eaf55 100644 --- a/tests/unit/store/serializer-for-test.js +++ b/tests/unit/store/serializer-for-test.js @@ -1,12 +1,14 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var container, store, registry, Person; var run = Ember.run; module("unit/store/serializer_for - DS.Store#serializerFor", { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({}); var env = setupStore({ person: Person }); store = env.store; @@ -14,7 +16,7 @@ module("unit/store/serializer_for - DS.Store#serializerFor", { registry = env.registry; }, - teardown: function() { + afterEach: function() { run(function() { container.destroy(); store.destroy(); @@ -22,27 +24,27 @@ module("unit/store/serializer_for - DS.Store#serializerFor", { } }); -test("Calling serializerFor looks up 'serializer:' from the container", function() { +test("Calling serializerFor looks up 'serializer:' from the container", function(assert) { var PersonSerializer = DS.JSONSerializer.extend(); registry.register('serializer:person', PersonSerializer); - ok(store.serializerFor('person') instanceof PersonSerializer, "serializer returned from serializerFor is an instance of the registered Serializer class"); + assert.ok(store.serializerFor('person') instanceof PersonSerializer, "serializer returned from serializerFor is an instance of the registered Serializer class"); }); -test("Calling serializerFor with a type that has not been registered looks up the default ApplicationSerializer", function() { +test("Calling serializerFor with a type that has not been registered looks up the default ApplicationSerializer", function(assert) { var ApplicationSerializer = DS.JSONSerializer.extend(); registry.register('serializer:application', ApplicationSerializer); - ok(store.serializerFor('person') instanceof ApplicationSerializer, "serializer returned from serializerFor is an instance of ApplicationSerializer"); + assert.ok(store.serializerFor('person') instanceof ApplicationSerializer, "serializer returned from serializerFor is an instance of ApplicationSerializer"); }); -test("Calling serializerFor with a type that has not been registered and in an application that does not have an ApplicationSerializer looks up the default Ember Data serializer", function() { - ok(store.serializerFor('person') instanceof DS.JSONSerializer, "serializer returned from serializerFor is an instance of DS.JSONSerializer"); +test("Calling serializerFor with a type that has not been registered and in an application that does not have an ApplicationSerializer looks up the default Ember Data serializer", function(assert) { + assert.ok(store.serializerFor('person') instanceof DS.JSONSerializer, "serializer returned from serializerFor is an instance of DS.JSONSerializer"); }); -test("Calling serializerFor with a model class should assert", function() { +test("Calling serializerFor with a model class should assert", function(assert) { expectAssertion(function() { store.serializerFor(Person); }, /Passing classes to store.serializerFor has been removed/); diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index f285975e95a..9b46738f3c2 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; var get = Ember.get; @@ -7,7 +9,7 @@ var run = Ember.run; var store, tryToFind, Record; module("unit/store/unload - Store unloading records", { - setup: function() { + beforeEach: function() { Record = DS.Model.extend({ title: DS.attr('string'), @@ -24,13 +26,13 @@ module("unit/store/unload - Store unloading records", { }); }, - teardown: function() { + afterEach: function() { Ember.run(store, 'destroy'); } }); -test("unload a dirty record", function() { - expect(2); +test("unload a dirty record", function(assert) { + assert.expect(2); run(function() { store.push({ @@ -47,7 +49,7 @@ test("unload a dirty record", function() { record.set('title', 'toto2'); record._internalModel.send('willCommit'); - equal(get(record, 'hasDirtyAttributes'), true, "record is dirty"); + assert.equal(get(record, 'hasDirtyAttributes'), true, "record is dirty"); expectAssertion(function() { record.unloadRecord(); @@ -61,8 +63,8 @@ test("unload a dirty record", function() { }); }); -test("unload a record", function() { - expect(5); +test("unload a record", function(assert) { + assert.expect(5); run(function() { store.push({ @@ -75,19 +77,19 @@ test("unload a record", function() { } }); store.findRecord('record', 1).then(function(record) { - equal(get(record, 'id'), 1, "found record with id 1"); - equal(get(record, 'hasDirtyAttributes'), false, "record is not dirty"); + assert.equal(get(record, 'id'), 1, "found record with id 1"); + assert.equal(get(record, 'hasDirtyAttributes'), false, "record is not dirty"); run(function() { store.unloadRecord(record); }); - equal(get(record, 'hasDirtyAttributes'), false, "record is not dirty"); - equal(get(record, 'isDeleted'), true, "record is deleted"); + assert.equal(get(record, 'hasDirtyAttributes'), false, "record is not dirty"); + assert.equal(get(record, 'isDeleted'), true, "record is deleted"); tryToFind = false; return store.findRecord('record', 1).then(function() { - equal(tryToFind, true, "not found record with id 1"); + assert.equal(tryToFind, true, "not found record with id 1"); }); }); }); @@ -96,8 +98,8 @@ test("unload a record", function() { module("DS.Store - unload record with relationships"); -test("can commit store after unload record with relationships", function() { - expect(1); +test("can commit store after unload record with relationships", function(assert) { + assert.expect(1); var like, product; @@ -163,7 +165,7 @@ test("can commit store after unload record with relationships", function() { store.unloadRecord(records.product); return store.findRecord('product', 1); }).then(function(product) { - equal(product.get('description'), 'cuisinart', "The record was unloaded and the adapter's `findRecord` was called"); + assert.equal(product.get('description'), 'cuisinart', "The record was unloaded and the adapter's `findRecord` was called"); store.destroy(); }); }); diff --git a/tests/unit/transform/boolean-test.js b/tests/unit/transform/boolean-test.js index be454239176..df38a4f0924 100644 --- a/tests/unit/transform/boolean-test.js +++ b/tests/unit/transform/boolean-test.js @@ -1,40 +1,42 @@ import DS from 'ember-data'; +import {module, test} from 'qunit'; + module("unit/transform - DS.BooleanTransform"); -test("#serialize", function() { +test("#serialize", function(assert) { var transform = new DS.BooleanTransform(); - equal(transform.serialize(null), false); - equal(transform.serialize(undefined), false); + assert.equal(transform.serialize(null), false); + assert.equal(transform.serialize(undefined), false); - equal(transform.serialize(true), true); - equal(transform.serialize(false), false); + assert.equal(transform.serialize(true), true); + assert.equal(transform.serialize(false), false); }); -test("#deserialize", function() { +test("#deserialize", function(assert) { var transform = new DS.BooleanTransform(); - equal(transform.deserialize(null), false); - equal(transform.deserialize(undefined), false); + assert.equal(transform.deserialize(null), false); + assert.equal(transform.deserialize(undefined), false); - equal(transform.deserialize(true), true); - equal(transform.deserialize(false), false); + assert.equal(transform.deserialize(true), true); + assert.equal(transform.deserialize(false), false); - equal(transform.deserialize("true"), true); - equal(transform.deserialize("TRUE"), true); - equal(transform.deserialize("false"), false); - equal(transform.deserialize("FALSE"), false); + assert.equal(transform.deserialize("true"), true); + assert.equal(transform.deserialize("TRUE"), true); + assert.equal(transform.deserialize("false"), false); + assert.equal(transform.deserialize("FALSE"), false); - equal(transform.deserialize("t"), true); - equal(transform.deserialize("T"), true); - equal(transform.deserialize("f"), false); - equal(transform.deserialize("F"), false); + assert.equal(transform.deserialize("t"), true); + assert.equal(transform.deserialize("T"), true); + assert.equal(transform.deserialize("f"), false); + assert.equal(transform.deserialize("F"), false); - equal(transform.deserialize("1"), true); - equal(transform.deserialize("0"), false); + assert.equal(transform.deserialize("1"), true); + assert.equal(transform.deserialize("0"), false); - equal(transform.deserialize(1), true); - equal(transform.deserialize(2), false); - equal(transform.deserialize(0), false); + assert.equal(transform.deserialize(1), true); + assert.equal(transform.deserialize(2), false); + assert.equal(transform.deserialize(0), false); }); diff --git a/tests/unit/transform/date-test.js b/tests/unit/transform/date-test.js index 27ac00ea516..0734edc113c 100644 --- a/tests/unit/transform/date-test.js +++ b/tests/unit/transform/date-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; module("unit/transform - DS.DateTransform"); @@ -8,28 +10,28 @@ var dateString = "2015-01-01T00:00:00.000Z"; var dateInMillis = Ember.Date.parse(dateString); var date = new Date(dateInMillis); -test("#serialize", function() { +test("#serialize", function(assert) { var transform = new DS.DateTransform(); - equal(transform.serialize(null), null); - equal(transform.serialize(undefined), null); + assert.equal(transform.serialize(null), null); + assert.equal(transform.serialize(undefined), null); - equal(transform.serialize(date), dateString); + assert.equal(transform.serialize(date), dateString); }); -test("#deserialize", function() { +test("#deserialize", function(assert) { var transform = new DS.DateTransform(); // from String - equal(transform.deserialize(dateString).toISOString(), dateString); + assert.equal(transform.deserialize(dateString).toISOString(), dateString); // from Number - equal(transform.deserialize(dateInMillis).valueOf(), dateInMillis); + assert.equal(transform.deserialize(dateInMillis).valueOf(), dateInMillis); // from other - equal(transform.deserialize({}), null); + assert.equal(transform.deserialize({}), null); // from none - equal(transform.deserialize(null), null); - equal(transform.deserialize(undefined), null); + assert.equal(transform.deserialize(null), null); + assert.equal(transform.deserialize(undefined), null); }); diff --git a/tests/unit/transform/number-test.js b/tests/unit/transform/number-test.js index 48d1d95bb52..427a1274ef0 100644 --- a/tests/unit/transform/number-test.js +++ b/tests/unit/transform/number-test.js @@ -1,31 +1,33 @@ import DS from 'ember-data'; +import {module, test} from 'qunit'; + /* jshint -W053 */ module("unit/transform - DS.NumberTransform"); -test("#serialize", function() { +test("#serialize", function(assert) { var transform = new DS.NumberTransform(); - equal(transform.serialize(null), null); - equal(transform.serialize(undefined), null); - equal(transform.serialize("1.1"), 1.1); - equal(transform.serialize(1.1), 1.1); - equal(transform.serialize(new Number(1.1)), 1.1); - equal(transform.serialize(NaN), null); - equal(transform.serialize(Infinity), null); - equal(transform.serialize(-Infinity), null); + assert.equal(transform.serialize(null), null); + assert.equal(transform.serialize(undefined), null); + assert.equal(transform.serialize("1.1"), 1.1); + assert.equal(transform.serialize(1.1), 1.1); + assert.equal(transform.serialize(new Number(1.1)), 1.1); + assert.equal(transform.serialize(NaN), null); + assert.equal(transform.serialize(Infinity), null); + assert.equal(transform.serialize(-Infinity), null); }); -test("#deserialize", function() { +test("#deserialize", function(assert) { var transform = new DS.NumberTransform(); - equal(transform.deserialize(null), null); - equal(transform.deserialize(undefined), null); - equal(transform.deserialize("1.1"), 1.1); - equal(transform.deserialize(1.1), 1.1); - equal(transform.deserialize(new Number(1.1)), 1.1); - equal(transform.deserialize(NaN), null); - equal(transform.deserialize(Infinity), null); - equal(transform.deserialize(-Infinity), null); + assert.equal(transform.deserialize(null), null); + assert.equal(transform.deserialize(undefined), null); + assert.equal(transform.deserialize("1.1"), 1.1); + assert.equal(transform.deserialize(1.1), 1.1); + assert.equal(transform.deserialize(new Number(1.1)), 1.1); + assert.equal(transform.deserialize(NaN), null); + assert.equal(transform.deserialize(Infinity), null); + assert.equal(transform.deserialize(-Infinity), null); }); diff --git a/tests/unit/transform/string-test.js b/tests/unit/transform/string-test.js index 386e4706179..75175e20ae6 100644 --- a/tests/unit/transform/string-test.js +++ b/tests/unit/transform/string-test.js @@ -1,23 +1,25 @@ import DS from 'ember-data'; +import {module, test} from 'qunit'; + module("unit/transform - DS.StringTransform"); -test("#serialize", function() { +test("#serialize", function(assert) { var transform = new DS.StringTransform(); - equal(transform.serialize(null), null); - equal(transform.serialize(undefined), null); + assert.equal(transform.serialize(null), null); + assert.equal(transform.serialize(undefined), null); - equal(transform.serialize("foo"), "foo"); - equal(transform.serialize(1), "1"); + assert.equal(transform.serialize("foo"), "foo"); + assert.equal(transform.serialize(1), "1"); }); -test("#deserialize", function() { +test("#deserialize", function(assert) { var transform = new DS.StringTransform(); - equal(transform.deserialize(null), null); - equal(transform.deserialize(undefined), null); + assert.equal(transform.deserialize(null), null); + assert.equal(transform.deserialize(undefined), null); - equal(transform.deserialize("foo"), "foo"); - equal(transform.deserialize(1), "1"); + assert.equal(transform.deserialize("foo"), "foo"); + assert.equal(transform.deserialize(1), "1"); }); diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index 8fe478142e5..8776f9c5df0 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -1,5 +1,7 @@ import Ember from 'ember'; +import {module, test} from 'qunit'; + import DS from 'ember-data'; // TODO enable import once this is possible @@ -9,7 +11,7 @@ import DS from 'ember-data'; var env, User, Message, Post, Person, Video, Medium; module("unit/utils", { - setup() { + beforeEach() { Person = DS.Model.extend(); User = DS.Model.extend({ messages: DS.hasMany('message', { async: false }) @@ -34,12 +36,12 @@ module("unit/utils", { env.registry.register('mixin:medium', Medium); }, - teardown() { + afterEach() { Ember.run(env.container, 'destroy'); } }); -test("assertPolymorphicType works for subclasses", function() { +test("assertPolymorphicType works for subclasses", function(assert) { var user, post, person; Ember.run(function() { @@ -80,7 +82,7 @@ test("assertPolymorphicType works for subclasses", function() { // TODO enable once we can do "import { assertPolymorphicType } from "ember-data/utils" // assertPolymorphicType(user, relationship, post); } catch (e) { - ok(false, "should not throw an error"); + assert.ok(false, "should not throw an error"); } expectAssertion(function() { @@ -93,7 +95,25 @@ test("assertPolymorphicType works for subclasses", function() { }, "You cannot add a record of type 'person' to the 'user.messages' relationship (only 'message' allowed)"); }); -test("assertPolymorphicType works for mixins", function() { +// TODO enable once we can `import x from y;` in tests +// test("modelHasAttributeOrRelationshipNamedType", function() { +// var ModelWithTypeAttribute = DS.Model.extend({ +// type: DS.attr() +// }); +// var ModelWithTypeBelongsTo = DS.Model.extend({ +// type: DS.belongsTo() +// }); +// var ModelWithTypeHasMany = DS.Model.extend({ +// type: DS.hasMany() +// }); +// +// equal(modelHasAttributeOrRelationshipNamedType(DS.Model), false); +// +// equal(modelHasAttributeOrRelationshipNamedType(ModelWithTypeAttribute), true); +// equal(modelHasAttributeOrRelationshipNamedType(ModelWithTypeBelongsTo), true); +// equal(modelHasAttributeOrRelationshipNamedType(ModelWithTypeHasMany), true); +// }); +test("assertPolymorphicType works for mixins", function(assert) { var post, video, person; Ember.run(function() { @@ -128,7 +148,7 @@ test("assertPolymorphicType works for mixins", function() { // TODO enable once we can do "import { assertPolymorphicType } from "ember-data/utils" // assertPolymorphicType(post, relationship, video); } catch (e) { - ok(false, "should not throw an error"); + assert.ok(false, "should not throw an error"); } expectAssertion(function() { @@ -140,22 +160,3 @@ test("assertPolymorphicType works for mixins", function() { // assertPolymorphicType(post, relationship, person); }, "You cannot add a record of type 'person' to the 'post.medias' relationship (only 'medium' allowed)"); }); - -// TODO enable once we can `import x from y;` in tests -// test("modelHasAttributeOrRelationshipNamedType", function() { -// var ModelWithTypeAttribute = DS.Model.extend({ -// type: DS.attr() -// }); -// var ModelWithTypeBelongsTo = DS.Model.extend({ -// type: DS.belongsTo() -// }); -// var ModelWithTypeHasMany = DS.Model.extend({ -// type: DS.hasMany() -// }); -// -// equal(modelHasAttributeOrRelationshipNamedType(DS.Model), false); -// -// equal(modelHasAttributeOrRelationshipNamedType(ModelWithTypeAttribute), true); -// equal(modelHasAttributeOrRelationshipNamedType(ModelWithTypeBelongsTo), true); -// equal(modelHasAttributeOrRelationshipNamedType(ModelWithTypeHasMany), true); -// }); From 86a3f574a265b24efec6d9fc8dc4f2f349039031 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 4 Nov 2015 20:31:21 -0600 Subject: [PATCH 1198/2527] add ember-inflector as a dev dependency --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index 93bfcd190de..fdc62459d1a 100644 --- a/package.json +++ b/package.json @@ -34,9 +34,13 @@ "ember-disable-prototype-extensions": "^1.0.0", "ember-disable-proxy-controllers": "^1.0.0", "ember-export-application-global": "^1.0.3", + "ember-inflector": "^1.9.3", "ember-try": "0.0.6", "ember-watson": "^0.7.0" }, + "peerDependencies": { + "ember-inflector": "^1.0.0" + }, "keywords": [ "ember-addon" ], From 49d55cff6ec6ee37f32d4af1c83912676819bb20 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 4 Nov 2015 20:50:56 -0600 Subject: [PATCH 1199/2527] move configuration out of ember-configuration and into test/helpers --- config/environment.js | 11 ++- tests/ember-configuration.js | 179 ----------------------------------- tests/helpers/async.js | 41 ++++++++ tests/helpers/store.js | 65 +++++++++++++ tests/helpers/warns.js | 34 +++++++ tests/test-helper.js | 35 +++++++ 6 files changed, 184 insertions(+), 181 deletions(-) delete mode 100644 tests/ember-configuration.js create mode 100644 tests/helpers/async.js create mode 100644 tests/helpers/store.js create mode 100644 tests/helpers/warns.js diff --git a/config/environment.js b/config/environment.js index 0dfaed4728b..edfe28e19f3 100644 --- a/config/environment.js +++ b/config/environment.js @@ -1,5 +1,12 @@ 'use strict'; -module.exports = function(/* environment, appConfig */) { - return { }; +module.exports = function(environment, appConfig) { + const ENV = { }; + + if (environment === 'testing') { + ENV.RAISE_ON_DEPRECATION = true; + ENV.ENABLE_DS_FILTER = true; + } + + return ENV; }; diff --git a/tests/ember-configuration.js b/tests/ember-configuration.js deleted file mode 100644 index ad317c1bcdf..00000000000 --- a/tests/ember-configuration.js +++ /dev/null @@ -1,179 +0,0 @@ -/* globals ENV, QUnit */ - -(function () { - window.Ember = window.Ember || {}; - - Ember.config = {}; - Ember.testing = true; - Ember.LOG_VERSION = false; - - window.ENV = { TESTING: true, LOG_VERSION: false }; - - var extendPrototypes = QUnit.urlParams.extendprototypes; - ENV['EXTEND_PROTOTYPES'] = !!extendPrototypes; - ENV['ENABLE_DS_FILTER'] = true; - - // Handle testing feature flags - ENV['ENABLE_OPTIONAL_FEATURES'] = !!QUnit.urlParams.enableoptionalfeatures; - ENV['RAISE_ON_DEPRECATION'] = true; - - window.async = function(callback, timeout) { - var timer; - stop(); - - timer = setTimeout(function() { - start(); - ok(false, "Timeout was reached"); - }, timeout || 200); - - return function() { - clearTimeout(timer); - - start(); - - var args = arguments; - return Ember.run(function() { - return callback.apply(this, args); - }); - }; - }; - - window.asyncEqual = function(a, b, message) { - Ember.RSVP.all([Ember.RSVP.resolve(a), Ember.RSVP.resolve(b)]).then(async(function(array) { - /*globals QUnit*/ - QUnit.push(array[0] === array[1], array[0], array[1], message); - })); - }; - - window.invokeAsync = function(callback, timeout) { - timeout = timeout || 1; - - setTimeout(async(callback, timeout+100), timeout); - }; - - window.setupStore = function(options) { - var container, registry; - var env = {}; - options = options || {}; - - if (Ember.Registry) { - registry = env.registry = new Ember.Registry(); - container = env.container = registry.container(); - } else { - container = env.container = new Ember.Container(); - registry = env.registry = container; - } - - env.replaceContainerNormalize = function replaceContainerNormalize(fn) { - if (env.registry) { - env.registry.normalize = fn; - } else { - env.container.normalize = fn; - } - }; - - var adapter = env.adapter = (options.adapter || '-default'); - delete options.adapter; - - if (typeof adapter !== 'string') { - env.registry.register('adapter:-ember-data-test-custom', adapter); - adapter = '-ember-data-test-custom'; - } - - for (var prop in options) { - registry.register('model:' + Ember.String.dasherize(prop), options[prop]); - } - - registry.register('service:store', DS.Store.extend({ - adapter: adapter - })); - - registry.optionsForType('serializer', { singleton: false }); - registry.optionsForType('adapter', { singleton: false }); - registry.register('adapter:-default', DS.Adapter); - - registry.register('serializer:-default', DS.JSONSerializer); - registry.register('serializer:-rest', DS.RESTSerializer); - - registry.register('adapter:-rest', DS.RESTAdapter); - - registry.register('adapter:-json-api', DS.JSONAPIAdapter); - registry.register('serializer:-json-api', DS.JSONAPISerializer); - - env.restSerializer = container.lookup('serializer:-rest'); - env.store = container.lookup('service:store'); - env.serializer = env.store.serializerFor('-default'); - env.adapter = env.store.get('defaultAdapter'); - - return env; - }; - - window.createStore = function(options) { - return setupStore(options).store; - }; - - QUnit.begin(function() { - Ember.RSVP.configure('onerror', function(reason) { - // only print error messages if they're exceptions; - // otherwise, let a future turn of the event loop - // handle the error. - if (reason && reason instanceof Error) { - Ember.Logger.log(reason, reason.stack); - throw reason; - } - }); - - var transforms = { - 'boolean': DS.BooleanTransform.create(), - 'date': DS.DateTransform.create(), - 'number': DS.NumberTransform.create(), - 'string': DS.StringTransform.create() - }; - - // Prevent all tests involving serialization to require a container - DS.JSONSerializer.reopen({ - transformFor: function(attributeType) { - return this._super(attributeType, true) || transforms[attributeType]; - } - }); - - }); - - // Generate the jQuery expando on window ahead of time - // to make the QUnit global check run clean - jQuery(window).data('testing', true); - - window.warns = function(callback, regex) { - var warnWasCalled = false; - var oldWarn = Ember.warn; - Ember.warn = function Ember_assertWarning(message, test) { - if (!test) { - warnWasCalled = true; - if (regex) { - ok(regex.test(message), 'the call to Ember.warn got an unexpected message: ' + message); - } - } - }; - try { - callback(); - ok(warnWasCalled, 'expected Ember.warn to warn, but was not called'); - } finally { - Ember.warn = oldWarn; - } - }; - - window.noWarns = function(callback) { - var oldWarn = Ember.warn; - var warnWasCalled = false; - Ember.warn = function Ember_noWarn(message, test) { - warnWasCalled = !test; - }; - try { - callback(); - } finally { - ok(!warnWasCalled, 'Ember.warn warned when it should not have warned'); - Ember.warn = oldWarn; - } - }; - -})(); diff --git a/tests/helpers/async.js b/tests/helpers/async.js new file mode 100644 index 00000000000..22d686445f9 --- /dev/null +++ b/tests/helpers/async.js @@ -0,0 +1,41 @@ +import Ember from 'ember'; +import QUnit from 'qunit'; + +const qAsync = QUnit.assert.async; +const {ok} = QUnit.assert; + +export default function async(callback, timeout) { + var timer; + let done = qAsync(); + + timer = setTimeout(function() { + done(); + ok(false, "Timeout was reached"); + }, timeout || 200); + + return function() { + window.clearTimeout(timer); + + done(); + + var args = arguments; + return Ember.run(function() { + return callback.apply(this, args); + }); + }; +} +export {async}; + +export function asyncEqual(a, b, message) { + return Ember.RSVP.all([Ember.RSVP.resolve(a), Ember.RSVP.resolve(b)]).then(async(function(array) { + /*globals QUnit*/ + QUnit.push(array[0] === array[1], array[0], array[1], message); + })); +} + +export function invokeAsync(callback, timeout) { + timeout = timeout || 1; + + setTimeout(async(callback, timeout+100), timeout); +} + diff --git a/tests/helpers/store.js b/tests/helpers/store.js new file mode 100644 index 00000000000..9ba46388249 --- /dev/null +++ b/tests/helpers/store.js @@ -0,0 +1,65 @@ +import Ember from 'ember'; + +export default function setupStore(options) { + var container, registry; + var env = {}; + options = options || {}; + + if (Ember.Registry) { + registry = env.registry = new Ember.Registry(); + container = env.container = registry.container(); + } else { + container = env.container = new Ember.Container(); + registry = env.registry = container; + } + + env.replaceContainerNormalize = function replaceContainerNormalize(fn) { + if (env.registry) { + env.registry.normalize = fn; + } else { + env.container.normalize = fn; + } + }; + + var adapter = env.adapter = (options.adapter || '-default'); + delete options.adapter; + + if (typeof adapter !== 'string') { + env.registry.register('adapter:-ember-data-test-custom', adapter); + adapter = '-ember-data-test-custom'; + } + + for (var prop in options) { + registry.register('model:' + Ember.String.dasherize(prop), options[prop]); + } + + registry.register('service:store', DS.Store.extend({ + adapter: adapter + })); + + registry.optionsForType('serializer', { singleton: false }); + registry.optionsForType('adapter', { singleton: false }); + registry.register('adapter:-default', DS.Adapter); + + registry.register('serializer:-default', DS.JSONSerializer); + registry.register('serializer:-rest', DS.RESTSerializer); + + registry.register('adapter:-rest', DS.RESTAdapter); + + registry.register('adapter:-json-api', DS.JSONAPIAdapter); + registry.register('serializer:-json-api', DS.JSONAPISerializer); + + env.restSerializer = container.lookup('serializer:-rest'); + env.store = container.lookup('service:store'); + env.serializer = env.store.serializerFor('-default'); + env.adapter = env.store.get('defaultAdapter'); + + return env; +} + +export {setupStore}; + +export function createStore(options) { + return setupStore(options).store; +} + diff --git a/tests/helpers/warns.js b/tests/helpers/warns.js new file mode 100644 index 00000000000..612e468e4b7 --- /dev/null +++ b/tests/helpers/warns.js @@ -0,0 +1,34 @@ +import Ember from 'ember'; + +export default function warns(callback, regex) { + var warnWasCalled = false; + var oldWarn = Ember.warn; + Ember.warn = function Ember_assertWarning(message, test) { + if (!test) { + warnWasCalled = true; + if (regex) { + ok(regex.test(message), 'the call to Ember.warn got an unexpected message: ' + message); + } + } + }; + try { + callback(); + ok(warnWasCalled, 'expected Ember.warn to warn, but was not called'); + } finally { + Ember.warn = oldWarn; + } +} + +export function noWarns(callback) { + var oldWarn = Ember.warn; + var warnWasCalled = false; + Ember.warn = function Ember_noWarn(message, test) { + warnWasCalled = !test; + }; + try { + callback(); + } finally { + ok(!warnWasCalled, 'Ember.warn warned when it should not have warned'); + Ember.warn = oldWarn; + } +} diff --git a/tests/test-helper.js b/tests/test-helper.js index e6cfb70fe80..6f0f96fa6ea 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -2,5 +2,40 @@ import resolver from './helpers/resolver'; import { setResolver } from 'ember-qunit'; +import QUnit from 'qunit'; +import ENV from 'dummy/config/environment'; +import DS from 'ember-data'; setResolver(resolver); + +const QUNIT_PARAMS = QUnit.urlParams; + +ENV.EXTEND_PROTOTYPES = QUNIT_PARAMS.extendprototypes; +ENV.ENABLE_OPTIONAL_FEATURES = QUNIT_PARAMS.enableoptionalfeatures; + +QUnit.begin(function() { + Ember.RSVP.configure('onerror', function(reason) { + // only print error messages if they're exceptions; + // otherwise, let a future turn of the event loop + // handle the error. + if (reason && reason instanceof Error) { + Ember.Logger.log(reason, reason.stack); + throw reason; + } + }); + + var transforms = { + 'boolean': DS.BooleanTransform.create(), + 'date': DS.DateTransform.create(), + 'number': DS.NumberTransform.create(), + 'string': DS.StringTransform.create() + }; + + // Prevent all tests involving serialization to require a container + DS.JSONSerializer.reopen({ + transformFor: function(attributeType) { + return this._super(attributeType, true) || transforms[attributeType]; + } + }); + +}); From 91f5a4acda6872ee9243fe92b14e71b2c30f6290 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 4 Nov 2015 21:32:57 -0600 Subject: [PATCH 1200/2527] move test helpers into separate files and put them on Assert This moves the test helpers onto the Assert object's prototype in QUnit to comply with the new 2.0 syntax. setupStore and friends have also been moved to their own files. --- config/environment.js | 6 +- tests/.jshintrc | 2 +- tests/ember-data-setup.js | 31 -- tests/helpers/async.js | 35 +- tests/helpers/ember-assertions.js | 132 ++++++ .../ember-assertions/assertion-expectation.js | 48 +++ .../helpers/ember-assertions/deprecations.js | 21 + .../method-call-expectation.js | 36 ++ tests/helpers/warns.js | 10 +- .../adapter/build-url-mixin-test.js | 37 +- tests/integration/adapter/find-all-test.js | 2 + tests/integration/adapter/find-test.js | 27 +- .../adapter/json-api-adapter-test.js | 1 + tests/integration/adapter/queries-test.js | 5 +- .../adapter/record-persistence-test.js | 43 +- .../integration/adapter/rest-adapter-test.js | 181 +++++---- tests/integration/adapter/serialize-test.js | 1 + .../integration/adapter/store-adapter-test.js | 109 ++--- .../non-dasherized-lookups-test.js | 1 + .../integration/client-id-generation-test.js | 1 + tests/integration/filter-test.js | 53 ++- tests/integration/inverse-test.js | 5 +- tests/integration/lifecycle-hooks-test.js | 6 +- tests/integration/multiple_stores_test.js | 24 +- tests/integration/peek-all-test.js | 1 + .../polymorphic-belongs-to-test.js | 9 +- .../integration/record-array-manager-test.js | 1 + .../records/collection-save-test.js | 9 +- .../integration/records/delete-record-test.js | 1 + tests/integration/records/load-test.js | 3 +- .../records/property-changes-test.js | 1 + tests/integration/records/reload-test.js | 1 + tests/integration/records/save-test.js | 1 + tests/integration/records/unload-test.js | 1 + .../relationships/belongs-to-test.js | 25 +- .../relationships/has-many-test.js | 33 +- .../inverse-relationships-test.js | 6 +- .../relationships/many-to-many-test.js | 25 +- .../relationships/one-to-many-test.js | 1 + .../relationships/one-to-one-test.js | 7 +- .../polymorphic-mixins-belongs-to-test.js | 5 +- .../polymorphic-mixins-has-many-test.js | 5 +- .../embedded-records-mixin-test.js | 3 +- .../serializers/json-api-serializer-test.js | 3 +- .../serializers/json-serializer-test.js | 1 + .../serializers/rest-serializer-test.js | 11 +- tests/integration/snapshot-test.js | 1 + tests/integration/store-test.js | 15 +- .../store/json-api-validation-test.js | 69 ++-- tests/integration/store/query-record-test.js | 5 +- tests/qunit-configuration.js | 384 ------------------ tests/test-helper.js | 42 +- tests/unit/adapter-errors-test.js | 2 +- .../adapter-populated-record-array-test.js | 1 + .../build-url-mixin/path-for-type-test.js | 1 + .../adapters/json-api-adapter/ajax-test.js | 1 + tests/unit/adapters/rest-adapter/ajax-test.js | 1 + .../group-records-for-find-many-test.js | 1 + tests/unit/debug-test.js | 1 + tests/unit/many-array-test.js | 1 + tests/unit/model-test.js | 96 ++--- tests/unit/model/errors-test.js | 51 +-- tests/unit/model/internal-model-test.js | 2 +- tests/unit/model/lifecycle-callbacks-test.js | 1 + tests/unit/model/merge-test.js | 5 +- tests/unit/model/relationships-test.js | 1 + .../model/relationships/belongs-to-test.js | 35 +- .../unit/model/relationships/has-many-test.js | 13 +- .../model/relationships/record-array-test.js | 3 +- tests/unit/model/rollback-attributes-test.js | 15 +- tests/unit/record-array-test.js | 2 + tests/unit/states-test.js | 94 ++--- tests/unit/store/adapter-interop-test.js | 61 +-- tests/unit/store/create-record-test.js | 4 +- tests/unit/store/has-record-for-id-test.js | 1 + tests/unit/store/lookup-test.js | 13 +- tests/unit/store/model-for-test.js | 1 + tests/unit/store/peek-record-test.js | 1 + tests/unit/store/push-test.js | 11 +- tests/unit/store/serializer-for-test.js | 3 +- tests/unit/store/unload-test.js | 3 +- tests/unit/utils-test.js | 5 +- 82 files changed, 920 insertions(+), 996 deletions(-) delete mode 100644 tests/ember-data-setup.js create mode 100644 tests/helpers/ember-assertions.js create mode 100644 tests/helpers/ember-assertions/assertion-expectation.js create mode 100644 tests/helpers/ember-assertions/deprecations.js create mode 100644 tests/helpers/ember-assertions/method-call-expectation.js delete mode 100644 tests/qunit-configuration.js diff --git a/config/environment.js b/config/environment.js index edfe28e19f3..5f801651e2a 100644 --- a/config/environment.js +++ b/config/environment.js @@ -4,8 +4,10 @@ module.exports = function(environment, appConfig) { const ENV = { }; if (environment === 'testing') { - ENV.RAISE_ON_DEPRECATION = true; - ENV.ENABLE_DS_FILTER = true; + ENV.EmberENV = { + RAISE_ON_DEPRECATION: true, + ENABLE_DS_FILTER: true + }; } return ENV; diff --git a/tests/.jshintrc b/tests/.jshintrc index 6ec0b7c154b..1aecd8ac495 100644 --- a/tests/.jshintrc +++ b/tests/.jshintrc @@ -48,5 +48,5 @@ "white": false, "eqnull": true, "esnext": true, - "unused": true + "unused": "vars" } diff --git a/tests/ember-data-setup.js b/tests/ember-data-setup.js deleted file mode 100644 index 154ff38a8a5..00000000000 --- a/tests/ember-data-setup.js +++ /dev/null @@ -1,31 +0,0 @@ -import Ember from 'ember'; - -import DS from 'ember-data'; - -;(function() { - - Ember.RSVP.configure('onerror', function(reason) { - // only print error messages if they're exceptions; - // otherwise, let a future turn of the event loop - // handle the error. - if (reason && reason instanceof Error) { - Ember.Logger.log(reason, reason.stack); - throw reason; - } - }); - - var transforms = { - 'boolean': DS.BooleanTransform.create(), - 'date': DS.DateTransform.create(), - 'number': DS.NumberTransform.create(), - 'string': DS.StringTransform.create() - }; - - // Prevent all tests involving serialization to require a container - DS.JSONSerializer.reopen({ - transformFor: function(attributeType) { - return this._super(attributeType, true) || transforms[attributeType]; - } - }); - -})(); diff --git a/tests/helpers/async.js b/tests/helpers/async.js index 22d686445f9..0beedd41849 100644 --- a/tests/helpers/async.js +++ b/tests/helpers/async.js @@ -1,41 +1,38 @@ import Ember from 'ember'; -import QUnit from 'qunit'; -const qAsync = QUnit.assert.async; -const {ok} = QUnit.assert; +export function wait(callback, timeout) { + let done = this.async(); -export default function async(callback, timeout) { - var timer; - let done = qAsync(); - - timer = setTimeout(function() { + var timer = setTimeout(() => { + this.ok(false, "Timeout was reached"); done(); - ok(false, "Timeout was reached"); }, timeout || 200); return function() { window.clearTimeout(timer); - done(); - var args = arguments; - return Ember.run(function() { - return callback.apply(this, args); - }); + var result; + try { + result = Ember.run(function() { + return callback.apply(this, args); + }); + } finally { + done(); + } + return result; }; } -export {async}; export function asyncEqual(a, b, message) { - return Ember.RSVP.all([Ember.RSVP.resolve(a), Ember.RSVP.resolve(b)]).then(async(function(array) { - /*globals QUnit*/ - QUnit.push(array[0] === array[1], array[0], array[1], message); + return Ember.RSVP.all([Ember.RSVP.resolve(a), Ember.RSVP.resolve(b)]).then(this.wait((array) => { + this.push(array[0] === array[1], array[0], array[1], message); })); } export function invokeAsync(callback, timeout) { timeout = timeout || 1; - setTimeout(async(callback, timeout+100), timeout); + setTimeout(this.wait(callback, timeout+100), timeout); } diff --git a/tests/helpers/ember-assertions.js b/tests/helpers/ember-assertions.js new file mode 100644 index 00000000000..657ce9ba3d6 --- /dev/null +++ b/tests/helpers/ember-assertions.js @@ -0,0 +1,132 @@ +import Ember from 'ember'; +import AssertionExpectation from './ember-assertions/assertion-expectation'; +import deprecations from './ember-assertions/deprecations'; + +// Looks for an exception raised within the fn. +// +// expectAssertion(function(){ +// Ember.assert("Homie don't roll like that"); +// } /* , optionalMessageStringOrRegex */); +// +export function expectAssertion(fn, message) { + (new AssertionExpectation(message, this)).assert(fn); +} + +// Expects no deprecation to happen from the time of calling until +// the end of the test. +// +// expectNoDeprecation(/* optionalStringOrRegex */); +// Ember.deprecate("Old And Busted"); +// +export function expectNoDeprecation(message) { + if (Ember.isArray(deprecations.expecteds)) { + throw new Error("No deprecation was expected after expectDeprecation was called!"); + } + deprecations.stubEmber(); + deprecations.expecteds = deprecations.NONE; +} + +// Expect a deprecation to happen within a function, or if no function +// is pass, from the time of calling until the end of the test. Can be called +// multiple times to assert deprecations with different specific messages +// were fired. +// +// expectDeprecation(function(){ +// Ember.deprecate("Old And Busted"); +// }, /* optionalStringOrRegex */); +// +// expectDeprecation(/* optionalStringOrRegex */); +// Ember.deprecate("Old And Busted"); +// +export function expectDeprecation(fn, message) { + if (deprecations.expecteds === deprecations.NONE) { + throw("A deprecation was expected after expectNoDeprecation was called!"); + } + deprecations.stubEmber(); + deprecations.expecteds = deprecations.expecteds || []; + if (fn && typeof fn !== 'function') { + // fn is a message + deprecations.expecteds.push(fn); + } else { + deprecations.expecteds.push(message || /.*/); + if (fn) { + fn(); + this.assertDeprecation(); + } + } +} + +// Forces an assert the deprecations occurred, and resets the globals +// storing asserts for the next run. +// +// expectNoDeprecation(/Old/); +// setTimeout(function(){ +// Ember.deprecate("Old And Busted"); +// assertDeprecation(); +// }); +// +// assertDeprecation is called after each test run to catch any expectations +// without explicit asserts. +// +export function assertDeprecation() { + var expecteds = deprecations.expecteds; + var actuals = deprecations.actuals || []; + if (!expecteds) { + deprecations.actuals = null; + return; + } + + deprecations.restoreEmber(); + deprecations.actuals = null; + deprecations.expecteds = null; + + if (expecteds === deprecations.NONE) { + var actualMessages = []; + for (var _actual in actuals) { + actualMessages.push(_actual[0]); + } + this.ok(actuals.length === 0, "Expected no deprecation call, got: "+actualMessages.join(', ')); + } else { + for (var o=0;o < expecteds.length; o++) { + var expected = expecteds[o]; + var match, actual; + for (var i = 0; i < actuals.length; i++) { + actual = actuals[i]; + if (!actual[1]) { + if (expected instanceof RegExp) { + if (expected.test(actual[0])) { + match = actual; + break; + } + } else { + if (expected === actual[0]) { + match = actual; + break; + } + } + } + } + + if (!actual) { + this.ok(false, "Recieved no deprecate calls at all, expecting: " + expected); + } else if (match && !match[1]) { + this.ok(true, "Recieved failing deprecation with message: " + match[0]); + } else if (match && match[1]) { + this.ok(false, "Expected failing deprecation, got succeeding with message: " + match[0]); + } else if (actual[1]) { + this.ok(false, "Did not receive failing deprecation matching '" + expected + "', last was success with '" + actual[0] + "'"); + } else if (!actual[1]) { + this.ok(false, "Did not receive failing deprecation matching '" + expected + "', last was failure with '" + actual[0] + "'"); + } + } + } +} + +export default function addEmberAssertions(assertPrototype) { + Ember.merge(assertPrototype, { + expectAssertion, + expectNoDeprecation, + expectDeprecation, + assertDeprecation + }); +} diff --git a/tests/helpers/ember-assertions/assertion-expectation.js b/tests/helpers/ember-assertions/assertion-expectation.js new file mode 100644 index 00000000000..7fbc599dfad --- /dev/null +++ b/tests/helpers/ember-assertions/assertion-expectation.js @@ -0,0 +1,48 @@ +import Ember from 'ember'; +import MethodCallExpectation from './method-call-expectation'; + +export default function AssertExpectation(message, testAssert) { + MethodCallExpectation.call(this, Ember, 'assert', testAssert); + this.expectedMessage = message; + this.testAssert = testAssert; +} + +AssertExpectation.Error = function() {}; +AssertExpectation.prototype = Object.create(MethodCallExpectation.prototype); +AssertExpectation.prototype.handleCall = function(message, test) { + this.sawCall = true; + if (test) { return; } // Only get message for failures + this.actualMessage = message; + // Halt execution + throw new AssertExpectation.Error(); +}; +AssertExpectation.prototype.assert = function(fn) { + try { + this.runWithStub(fn); + } catch (e) { + if (!(e instanceof AssertExpectation.Error)) { + throw e; + } + } + + // Run assertions in an order that is useful when debugging a test failure. + // + let assert = this.testAssert; + if (!this.sawCall) { + assert.ok(false, "Expected Ember.assert to be called (Not called with any value)."); + } else if (!this.actualMessage) { + assert.ok(false, 'Expected a failing Ember.assert (Ember.assert called, but without a failing test).'); + } else { + if (this.expectedMessage) { + if (this.expectedMessage instanceof RegExp) { + assert.ok(this.expectedMessage.test(this.actualMessage), "Expected failing Ember.assert: '" + this.expectedMessage + "', but got '" + this.actualMessage + "'."); + } else { + assert.equal(this.actualMessage, this.expectedMessage, "Expected failing Ember.assert: '" + this.expectedMessage + "', but got '" + this.actualMessage + "'."); + } + } else { + // Positive assertion that assert was called + assert.ok(true, 'Expected a failing Ember.assert.'); + } + } +}; + diff --git a/tests/helpers/ember-assertions/deprecations.js b/tests/helpers/ember-assertions/deprecations.js new file mode 100644 index 00000000000..4e7d69e798d --- /dev/null +++ b/tests/helpers/ember-assertions/deprecations.js @@ -0,0 +1,21 @@ +import Ember from 'ember'; + +const deprecations = { + NONE: 99, // 99 problems and a deprecation ain't one + expecteds: null, + actuals: null, + stubEmber: function() { + if (!deprecations.originalEmberDeprecate && Ember.deprecate !== deprecations.originalEmberDeprecate) { + deprecations.originalEmberDeprecate = Ember.deprecate; + } + Ember.deprecate = function(msg, test) { + deprecations.actuals = deprecations.actuals || []; + deprecations.actuals.push([msg, test]); + }; + }, + restoreEmber: function() { + Ember.deprecate = deprecations.originalEmberDeprecate; + } +}; + +export default deprecations; diff --git a/tests/helpers/ember-assertions/method-call-expectation.js b/tests/helpers/ember-assertions/method-call-expectation.js new file mode 100644 index 00000000000..b7d89ade8fe --- /dev/null +++ b/tests/helpers/ember-assertions/method-call-expectation.js @@ -0,0 +1,36 @@ +// A light class for stubbing +// +export default function MethodCallExpectation(target, property, testAssert) { + this.target = target; + this.property = property; + this.testAssert = testAssert; +} + +MethodCallExpectation.prototype = { + handleCall: function() { + this.sawCall = true; + return this.originalMethod.apply(this.target, arguments); + }, + stubMethod: function(fn) { + var context = this; + this.originalMethod = this.target[this.property]; + this.target[this.property] = function() { + return context.handleCall.apply(context, arguments); + }; + }, + restoreMethod: function() { + this.target[this.property] = this.originalMethod; + }, + runWithStub: function(fn) { + try { + this.stubMethod(); + fn(); + } finally { + this.restoreMethod(); + } + }, + assert: function(fn) { + this.runWithStub(); + this.testAssert.ok(this.sawCall, "Expected "+this.property+" to be called."); + } +}; diff --git a/tests/helpers/warns.js b/tests/helpers/warns.js index 612e468e4b7..79a61b1ee95 100644 --- a/tests/helpers/warns.js +++ b/tests/helpers/warns.js @@ -1,19 +1,19 @@ import Ember from 'ember'; -export default function warns(callback, regex) { +export function warns(callback, regex) { var warnWasCalled = false; var oldWarn = Ember.warn; - Ember.warn = function Ember_assertWarning(message, test) { + Ember.warn = (message, test) => { if (!test) { warnWasCalled = true; if (regex) { - ok(regex.test(message), 'the call to Ember.warn got an unexpected message: ' + message); + this.ok(regex.test(message), 'the call to Ember.warn got an unexpected message: ' + message); } } }; try { callback(); - ok(warnWasCalled, 'expected Ember.warn to warn, but was not called'); + this.ok(warnWasCalled, 'expected Ember.warn to warn, but was not called'); } finally { Ember.warn = oldWarn; } @@ -28,7 +28,7 @@ export function noWarns(callback) { try { callback(); } finally { - ok(!warnWasCalled, 'Ember.warn warned when it should not have warned'); + this.ok(!warnWasCalled, 'Ember.warn warned when it should not have warned'); Ember.warn = oldWarn; } } diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index fb37baf242a..c01e0865d7f 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -61,7 +62,7 @@ test('buildURL - with host and namespace', function(assert) { ajaxResponse({ posts: [{ id: 1 }] }); - run(store, 'findRecord', 'post', 1).then(async(function(post) { + run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "http://example.com/api/v1/posts/1"); })); }); @@ -78,10 +79,10 @@ test('buildURL - with relative paths in links', function(assert) { ajaxResponse({ posts: [{ id: 1, links: { comments: 'comments' } }] }); - run(store, 'findRecord', 'post', '1').then(async(function(post) { + run(store, 'findRecord', 'post', '1').then(assert.wait(function(post) { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); - })).then(async(function (comments) { + })).then(assert.wait(function (comments) { assert.equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); })); }); @@ -98,10 +99,10 @@ test('buildURL - with absolute paths in links', function(assert) { ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - run(store, 'findRecord', 'post', 1).then(async(function(post) { + run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); - })).then(async(function (comments) { + })).then(assert.wait(function (comments) { assert.equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); })); }); @@ -119,10 +120,10 @@ test('buildURL - with absolute paths in links and protocol relative host', funct ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - run(store, 'findRecord', 'post', 1).then(async(function(post) { + run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); - })).then(async(function (comments) { + })).then(assert.wait(function (comments) { assert.equal(passedUrl, "//example.com/api/v1/posts/1/comments"); })); }); @@ -144,10 +145,10 @@ test('buildURL - with full URLs in links', function(assert) { }); run(function() { - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); - })).then(async(function (comments) { + })).then(assert.wait(function (comments) { assert.equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); })); }); @@ -164,7 +165,7 @@ test('buildURL - with camelized names', function(assert) { ajaxResponse({ superUsers: [{ id: 1 }] }); run(function() { - store.findRecord('super-user', 1).then(async(function(post) { + store.findRecord('super-user', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/super_users/1"); })); }); @@ -189,7 +190,7 @@ test('buildURL - buildURL takes a record from find', function(assert) { }); run(function() { - store.findRecord('comment', 1, { preload: { post: post } }).then(async(function(post) { + store.findRecord('comment', 1, { preload: { post: post } }).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/2/comments/1"); })); }); @@ -226,7 +227,7 @@ test('buildURL - buildURL takes the records from findMany', function(assert) { } } }); - post.get('comments').then(async(function(post) { + post.get('comments').then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/2/comments/"); })); }); @@ -249,7 +250,7 @@ test('buildURL - buildURL takes a record from create', function(assert) { }); var comment = store.createRecord('comment'); comment.set('post', post); - comment.save().then(async(function(post) { + comment.save().then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/2/comments/"); })); }); @@ -261,7 +262,7 @@ test('buildURL - buildURL takes a record from create to query a resolved async b ajaxResponse({ posts: [{ id: 2 }] }); run(function() { - store.findRecord('post', 2).then(async(function(post) { + store.findRecord('post', 2).then(assert.wait(function(post) { assert.equal(post.get('id'), 2); adapter.buildURL = function(type, id, snapshot) { @@ -272,7 +273,7 @@ test('buildURL - buildURL takes a record from create to query a resolved async b var comment = store.createRecord('comment'); comment.set('post', post); - comment.save().then(async(function(post) { + comment.save().then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/2/comments/"); })); @@ -305,7 +306,7 @@ test('buildURL - buildURL takes a record from update', function(assert) { comment.set('post', post); }); run(function() { - comment.save().then(async(function(post) { + comment.save().then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/2/comments/1"); })); }); @@ -339,7 +340,7 @@ test('buildURL - buildURL takes a record from delete', function(assert) { comment.deleteRecord(); }); run(function() { - comment.save().then(async(function(post) { + comment.save().then(assert.wait(function(post) { assert.equal(passedUrl, "posts/2/comments/1"); })); }); @@ -354,7 +355,7 @@ test('buildURL - with absolute namespace', function(assert) { ajaxResponse({ posts: [{ id: 1 }] }); - run(store, 'findRecord', 'post', 1).then(async(function(post) { + run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/api/v1/posts/1"); })); }); diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index 001267b6cdc..d7ea583c381 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -1,3 +1,5 @@ +import {createStore} from 'dummy/tests/helpers/store'; +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 009adad24fc..04608c5c507 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -28,11 +29,11 @@ module("integration/adapter/find - Finding Records", { }); test("It raises an assertion when `undefined` is passed as id (#1705)", function(assert) { - expectAssertion(function() { + assert.expectAssertion(function() { store.find('person', undefined); }, "You cannot pass `undefined` as id to the store's find method"); - expectAssertion(function() { + assert.expectAssertion(function() { store.find('person', null); }, "You cannot pass `null` as id to the store's find method"); }); @@ -68,33 +69,33 @@ test("When a single record is requested multiple times, all .find() calls are re })); run(function() { - store.findRecord('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { assert.equal(person.get('id'), "1"); assert.equal(person.get('name'), "Braaaahm Dale"); - stop(); + let done = assert.async(); deferred.promise.then(function(value) { - start(); assert.ok(true, 'expected deferred.promise to fulfill'); + done(); }, function(reason) { - start(); assert.ok(false, 'expected deferred.promise to fulfill, but rejected'); + done(); }); })); }); run(function() { - store.findRecord('person', 1).then(async(function(post) { + store.findRecord('person', 1).then(assert.wait(function(post) { assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Braaaahm Dale"); - stop(); + let done = assert.async(); deferred.promise.then(function(value) { - start(); assert.ok(true, 'expected deferred.promise to fulfill'); + done(); }, function(reason) { - start(); assert.ok(false, 'expected deferred.promise to fulfill, but rejected'); + done(); }); })); @@ -113,7 +114,7 @@ test("When a single record is requested, and the promise is rejected, .find() is })); run(function() { - store.findRecord('person', 1).then(null, async(function(reason) { + store.findRecord('person', 1).then(null, assert.wait(function(reason) { assert.ok(true, "The rejection handler was called"); })); }); @@ -129,10 +130,10 @@ test("When a single record is requested, and the promise is rejected, the record })); run(function() { - store.findRecord('person', 1).then(null, async(function(reason) { + store.findRecord('person', 1).then(null, assert.wait(function(reason) { assert.ok(true, "The rejection handler was called"); + assert.ok(!store.hasRecordForId('person', 1), "The record has been unloaded"); })); }); - assert.ok(!store.hasRecordForId('person', 1), "The record has been unloaded"); }); diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index b6e772a2092..20e789a13c5 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/adapter/queries-test.js b/tests/integration/adapter/queries-test.js index a1db29e4f7f..8045d85b3b1 100644 --- a/tests/integration/adapter/queries-test.js +++ b/tests/integration/adapter/queries-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -34,7 +35,7 @@ test("When a query is made, the adapter should receive a record array it can pop return Ember.RSVP.resolve([{ id: 1, name: "Peter Wagenet" }, { id: 2, name: "Brohuda Katz" }]); }; - store.query('person', { page: 1 }).then(async(function(queryResults) { + store.query('person', { page: 1 }).then(assert.wait(function(queryResults) { assert.equal(get(queryResults, 'length'), 2, "the record array has a length of 2 after the results are loaded"); assert.equal(get(queryResults, 'isLoaded'), true, "the record array's `isLoaded` property should be true"); @@ -54,7 +55,7 @@ test("The store asserts when query is made and the adapter responses with a sing return Ember.RSVP.resolve({ people: { id: 1, name: "Peter Wagenet" } }); }; - expectAssertion(function() { + assert.expectAssertion(function() { Ember.run(function() { store.query('person', { page: 1 }); }); diff --git a/tests/integration/adapter/record-persistence-test.js b/tests/integration/adapter/record-persistence-test.js index 1795f414aea..1eda625b1c9 100644 --- a/tests/integration/adapter/record-persistence-test.js +++ b/tests/integration/adapter/record-persistence-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -13,14 +14,6 @@ var run = Ember.run; var all = Ember.RSVP.all; var hash = Ember.RSVP.hash; -function assertClean(promise) { - return promise.then(async(function(record) { - assert.equal(record.get('hasDirtyAttributes'), false, "The record is now clean"); - return record; - })); -} - - module("integration/adapter/record_persistence - Persisting Records", { beforeEach: function() { Person = DS.Model.extend({ @@ -70,7 +63,7 @@ test("When a store is committed, the adapter's `commit` method should be called var tom; run(function() { - env.store.findRecord('person', 1).then(async(function(person) { + env.store.findRecord('person', 1).then(assert.wait(function(person) { tom = person; set(tom, "name", "Tom Dale"); tom.save(); @@ -108,7 +101,7 @@ test("After a created record has been assigned an ID, finding a record by that I tom.save(); }); - asyncEqual(tom, env.store.find('person', 1), "the retrieved record is the same as the created record"); + assert.asyncEqual(tom, env.store.find('person', 1), "the retrieved record is the same as the created record"); }); test("when a store is committed, the adapter's `commit` method should be called with records that have been deleted.", function(assert) { @@ -132,11 +125,11 @@ test("when a store is committed, the adapter's `commit` method should be called } }); }); - env.store.find('person', 1).then(async(function(person) { + env.store.find('person', 1).then(assert.wait(function(person) { tom = person; tom.deleteRecord(); return tom.save(); - })).then(async(function(tom) { + })).then(assert.wait(function(tom) { assert.equal(get(tom, 'isDeleted'), true, "record is marked as deleted"); })); }); @@ -163,7 +156,7 @@ test("An adapter can notify the store that records were updated by calling `didS }); all([env.store.find('person', 1), env.store.find('person', 2)]) - .then(async(function(array) { + .then(assert.wait(function(array) { tom = array[0]; yehuda = array[1]; @@ -173,11 +166,11 @@ test("An adapter can notify the store that records were updated by calling `didS assert.ok(tom.get('hasDirtyAttributes'), "tom is dirty"); assert.ok(yehuda.get('hasDirtyAttributes'), "yehuda is dirty"); - assertClean(tom.save()).then(async(function(record) { + assert.assertClean(tom.save()).then(assert.wait(function(record) { assert.equal(record, tom, "The record is correct"); })); - assertClean(yehuda.save()).then(async(function(record) { + assert.assertClean(yehuda.save()).then(assert.wait(function(record) { assert.equal(record, yehuda, "The record is correct"); })); })); @@ -210,12 +203,12 @@ test("An adapter can notify the store that records were updated and provide new }); }); - hash({ tom: env.store.find('person', 1), yehuda: env.store.find('person', 2) }).then(async(function(people) { + hash({ tom: env.store.find('person', 1), yehuda: env.store.find('person', 2) }).then(assert.wait(function(people) { people.tom.set('name', "Draaaaaahm Dale"); people.yehuda.set('name', "Goy Katz"); return hash({ tom: people.tom.save(), yehuda: people.yehuda.save() }); - })).then(async(function(people) { + })).then(assert.wait(function(people) { assert.equal(people.tom.get('name'), "Tom Dale", "name attribute should reflect value of hash passed to didSaveRecords"); assert.equal(people.tom.get('updatedAt'), "now", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); assert.equal(people.yehuda.get('name'), "Yehuda Katz", "name attribute should reflect value of hash passed to didSaveRecords"); @@ -240,15 +233,15 @@ test("An adapter can notify the store that a record was updated by calling `didS }); }); - hash({ tom: store.find('person', 1), yehuda: store.find('person', 2) }).then(async(function(people) { + hash({ tom: store.find('person', 1), yehuda: store.find('person', 2) }).then(assert.wait(function(people) { people.tom.set('name', "Tom Dale"); people.yehuda.set('name', "Yehuda Katz"); assert.ok(people.tom.get('hasDirtyAttributes'), "tom is dirty"); assert.ok(people.yehuda.get('hasDirtyAttributes'), "yehuda is dirty"); - assertClean(people.tom.save()); - assertClean(people.yehuda.save()); + assert.assertClean(people.tom.save()); + assert.assertClean(people.yehuda.save()); })); }); @@ -281,12 +274,12 @@ test("An adapter can notify the store that a record was updated and provide new }); }); - hash({ tom: store.find('person', 1), yehuda: store.find('person', 2) }).then(async(function(people) { + hash({ tom: store.find('person', 1), yehuda: store.find('person', 2) }).then(assert.wait(function(people) { people.tom.set('name', "Draaaaaahm Dale"); people.yehuda.set('name', "Goy Katz"); return hash({ tom: people.tom.save(), yehuda: people.yehuda.save() }); - })).then(async(function(people) { + })).then(assert.wait(function(people) { assert.equal(people.tom.get('name'), "Tom Dale", "name attribute should reflect value of hash passed to didSaveRecords"); assert.equal(people.tom.get('updatedAt'), "now", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); assert.equal(people.yehuda.get('name'), "Yehuda Katz", "name attribute should reflect value of hash passed to didSaveRecords"); @@ -318,11 +311,11 @@ test("An adapter can notify the store that records were deleted by calling `didS }); }); - hash({ tom: store.find('person', 1), yehuda: store.find('person', 2) }).then(async(function(people) { + hash({ tom: store.find('person', 1), yehuda: store.find('person', 2) }).then(assert.wait(function(people) { people.tom.deleteRecord(); people.yehuda.deleteRecord(); - assertClean(people.tom.save()); - assertClean(people.yehuda.save()); + assert.assertClean(people.tom.save()); + assert.assertClean(people.yehuda.save()); })); }); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 81b7ef4221a..f209197b839 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -52,7 +53,7 @@ function ajaxResponse(value) { test("find - basic payload", function(assert) { ajaxResponse({ posts: [{ id: 1, name: "Rails is omakase" }] }); - run(store, 'find', 'post', 1).then(async(function(post) { + run(store, 'find', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.equal(passedHash, undefined); @@ -71,7 +72,7 @@ test("findRecord - passes buildURL a requestType", function(assert) { ajaxResponse({ posts: [{ id: 1, name: "Rails is omakase" }] }); - run(store, 'findRecord', 'post', 1).then(async(function(post) { + run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/findRecord/post/1"); })); }); @@ -79,7 +80,7 @@ test("findRecord - passes buildURL a requestType", function(assert) { test("find - basic payload (with legacy singular name)", function(assert) { ajaxResponse({ post: { id: 1, name: "Rails is omakase" } }); - run(store, 'find', 'post', 1).then(async(function(post) { + run(store, 'find', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.equal(passedHash, undefined); @@ -97,7 +98,7 @@ test("find - payload with sideloaded records of the same type", function(assert) ] }); - run(store, 'find', 'post', 1).then(async(function(post) { + run(store, 'find', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.equal(passedHash, undefined); @@ -117,7 +118,7 @@ test("find - payload with sideloaded records of a different type", function(asse comments: [{ id: 1, name: "FIRST" }] }); - run(store, 'find', 'post', 1).then(async(function(post) { + run(store, 'find', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.equal(passedHash, undefined); @@ -139,7 +140,7 @@ test("find - payload with an serializer-specified primary key", function(assert) ajaxResponse({ posts: [{ "_ID_": 1, name: "Rails is omakase" }] }); - run(store, 'find', 'post', 1).then(async(function(post) { + run(store, 'find', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.equal(passedHash, undefined); @@ -163,7 +164,7 @@ test("find - payload with a serializer-specified attribute mapping", function(as ajaxResponse({ posts: [{ id: 1, _NAME_: "Rails is omakase", _CREATED_AT_: 2013 }] }); - run(store, 'find', 'post', 1).then(async(function(post) { + run(store, 'find', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.equal(passedHash, undefined); @@ -180,7 +181,7 @@ test("create - an empty payload is a basic success if an id was specified", func run(function() { post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); - post.save().then(async(function(post) { + post.save().then(assert.wait(function(post) { assert.equal(passedUrl, "/posts"); assert.equal(passedVerb, "POST"); assert.deepEqual(passedHash.data, { post: { id: "some-uuid", name: "The Parley Letter" } }); @@ -201,7 +202,7 @@ test("create - passes buildURL the requestType", function(assert) { run(function() { post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); - post.save().then(async(function(post) { + post.save().then(assert.wait(function(post) { assert.equal(passedUrl, "/post/createRecord"); })); }); @@ -212,7 +213,7 @@ test("create - a payload with a new ID and data applies the updates", function(a run(function() { var post = store.createRecord('post', { name: "The Parley Letter" }); - post.save().then(async(function(post) { + post.save().then(assert.wait(function(post) { assert.equal(passedUrl, "/posts"); assert.equal(passedVerb, "POST"); assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); @@ -231,7 +232,7 @@ test("create - a payload with a new ID and data applies the updates (with legacy post = store.createRecord('post', { name: "The Parley Letter" }); }); - run(post, 'save').then(async(function(post) { + run(post, 'save').then(assert.wait(function(post) { assert.equal(passedUrl, "/posts"); assert.equal(passedVerb, "POST"); assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); @@ -275,7 +276,7 @@ test("create - findMany doesn't overwrite owner", function(assert) { assert.equal(comment.get('post'), post, "the post has been set correctly"); run(function() { - comment.save().then(async(function(comment) { + comment.save().then(assert.wait(function(comment) { assert.equal(comment.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); assert.equal(comment.get('name'), "Dat Parley Letter", "the post was updated"); assert.equal(comment.get('post'), post, "the post is still set"); @@ -299,7 +300,7 @@ test("create - a serializer's primary key and attributes are consulted when buil post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); }); - run(post, 'save').then(async(function(post) { + run(post, 'save').then(assert.wait(function(post) { assert.deepEqual(passedHash.data, { post: { _id_: 'some-uuid', '_name_': "The Parley Letter" } }); })); }); @@ -319,7 +320,7 @@ test("create - a serializer's attributes are consulted when building the payload run(function() { post = store.createRecord('post', { name: "The Parley Letter" }); - post.save().then(async(function(post) { + post.save().then(assert.wait(function(post) { assert.deepEqual(passedHash.data, { post: { '_name_': "The Parley Letter" } }); })); }); @@ -341,7 +342,7 @@ test("create - a serializer's attribute mapping takes precdence over keyForAttri run(function() { var post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); - post.save().then(async(function(post) { + post.save().then(assert.wait(function(post) { assert.deepEqual(passedHash.data, { post: { 'given_name': "The Parley Letter", id: "some-uuid" } }); })); }); @@ -366,7 +367,7 @@ test("create - a serializer's attribute mapping takes precedence over keyForRela var post = store.createRecord('post', { id: "a-post-id", name: "The Parley Letter" }); var comment = store.createRecord('comment', { id: "some-uuid", name: "Letters are fun", post: post }); - comment.save().then(async(function(post) { + comment.save().then(assert.wait(function(post) { assert.deepEqual(passedHash.data, { comment: { article: "a-post-id", id: "some-uuid", name: "Letters are fun" } }); })); }); @@ -391,7 +392,7 @@ test("create - a serializer's attribute mapping takes precedence over keyForRela var comment = store.createRecord('comment', { id: "a-comment-id", name: "First!" }); var post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter", comments: [comment] }); - post.save().then(async(function(post) { + post.save().then(assert.wait(function(post) { assert.deepEqual(passedHash.data, { post: { opinions: ["a-comment-id"], id: "some-uuid", name: "The Parley Letter" } }); })); }); @@ -467,11 +468,11 @@ test("create - a record on the many side of a hasMany relationship should update run(function() { var comment = store.createRecord('comment', { name: "Another Comment", post: post }); - comment.save().then(async(function(comment) { + comment.save().then(assert.wait(function(comment) { assert.equal(comment.get('post'), post, "the comment is related to the post"); })); - post.reload().then(async(function(post) { + post.reload().then(assert.wait(function(post) { assert.equal(post.get('comments.length'), 2, "Post comment count has been updated"); })); }); @@ -494,7 +495,7 @@ test("create - sideloaded belongsTo relationships are both marked as loaded", fu }); run(function() { - post.save().then(async(function(record) { + post.save().then(assert.wait(function(record) { assert.equal(store.peekRecord('post', 1).get('comment.isLoaded'), true, "post's comment isLoaded (via store)"); assert.equal(store.peekRecord('comment', 1).get('post.isLoaded'), true, "comment's post isLoaded (via store)"); assert.equal(record.get('comment.isLoaded'), true, "post's comment isLoaded (via record)"); @@ -528,7 +529,7 @@ test("create - response can contain relationships the client doesn't yet know ab }); run(function() { - post.save().then(async(function(post) { + post.save().then(assert.wait(function(post) { assert.equal(post.get('comments.firstObject.post'), post, "the comments are related to the correct post model"); assert.equal(store.typeMapFor(Post).records.length, 1, "There should only be one post record in the store"); @@ -553,7 +554,7 @@ test("create - relationships are not duplicated", function(assert) { ajaxResponse({ post: [{ id: 1, name: "Rails is omakase", comments: [] }] }); - run(post, 'save').then(async(function(post) { + run(post, 'save').then(assert.wait(function(post) { assert.equal(post.get('comments.length'), 0, "post has 0 comments"); post.get('comments').pushObject(comment); assert.equal(post.get('comments.length'), 1, "post has 1 comment"); @@ -564,7 +565,7 @@ test("create - relationships are not duplicated", function(assert) { }); return post.save(); - })).then(async(function(post) { + })).then(assert.wait(function(post) { assert.equal(post.get('comments.length'), 1, "post has 1 comment"); })); }); @@ -587,7 +588,7 @@ test("update - an empty payload is a basic success", function(assert) { ajaxResponse(); post.set('name', "The Parley Letter"); - post.save().then(async(function(post) { + post.save().then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "PUT"); assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); @@ -617,12 +618,12 @@ test("update - passes the requestType to buildURL", function(assert) { }); run(function() { - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { ajaxResponse(); post.set('name', "The Parley Letter"); return post.save(); - })).then(async(function(post) { + })).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1/updateRecord"); })); }); @@ -642,12 +643,12 @@ test("update - a payload with updates applies the updates", function(assert) { }); }); - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { ajaxResponse({ posts: [{ id: 1, name: "Dat Parley Letter" }] }); post.set('name', "The Parley Letter"); return post.save(); - })).then(async(function(post) { + })).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "PUT"); assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); @@ -671,12 +672,12 @@ test("update - a payload with updates applies the updates (with legacy singular }); }); - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { ajaxResponse({ post: { id: 1, name: "Dat Parley Letter" } }); post.set('name', "The Parley Letter"); return post.save(); - })).then(async(function(post) { + })).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "PUT"); assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); @@ -694,7 +695,7 @@ test("update - a payload with sideloaded updates pushes the updates", function(a }); run(function() { post = store.createRecord('post', { name: "The Parley Letter" }); - post.save().then(async(function(post) { + post.save().then(assert.wait(function(post) { assert.equal(passedUrl, "/posts"); assert.equal(passedVerb, "POST"); assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); @@ -723,7 +724,7 @@ test("update - a payload with sideloaded updates pushes the updates", function(a }); }); - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { ajaxResponse({ posts: [{ id: 1, name: "Dat Parley Letter" }], comments: [{ id: 1, name: "FIRST" }] @@ -731,7 +732,7 @@ test("update - a payload with sideloaded updates pushes the updates", function(a post.set('name', "The Parley Letter"); return post.save(); - })).then(async(function(post) { + })).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "PUT"); assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); @@ -765,10 +766,10 @@ test("update - a serializer's primary key and attributes are consulted when buil }); ajaxResponse(); - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { post.set('name', "The Parley Letter"); return post.save(); - })).then(async(function(post) { + })).then(assert.wait(function(post) { assert.deepEqual(passedHash.data, { post: { '_name_': "The Parley Letter" } }); })); }); @@ -814,9 +815,9 @@ test("update - hasMany relationships faithfully reflect simultaneous adds and re posts: { id: 1, name: "Not everyone uses Rails", comments: [2] } }); - store.findRecord('comment', 2).then(async(function() { + store.findRecord('comment', 2).then(assert.wait(function() { return store.findRecord('post', 1); - })).then(async(function(post) { + })).then(assert.wait(function(post) { var newComment = store.peekRecord('comment', 2); var comments = post.get('comments'); @@ -825,7 +826,7 @@ test("update - hasMany relationships faithfully reflect simultaneous adds and re comments.pushObject(newComment); return post.save(); - })).then(async(function(post) { + })).then(assert.wait(function(post) { assert.equal(post.get('comments.length'), 1, "the post has the correct number of comments"); assert.equal(post.get('comments.firstObject.name'), "Yes. Yes it is.", "the post has the correct comment"); })); @@ -845,12 +846,12 @@ test("delete - an empty payload is a basic success", function(assert) { }); }); - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { ajaxResponse(); post.deleteRecord(); return post.save(); - })).then(async(function(post) { + })).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "DELETE"); assert.equal(passedHash, undefined); @@ -878,12 +879,12 @@ test("delete - passes the requestType to buildURL", function(assert) { }); }); - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { ajaxResponse(); post.deleteRecord(); return post.save(); - })).then(async(function(post) { + })).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1/deleteRecord"); })); }); @@ -902,12 +903,12 @@ test("delete - a payload with sideloaded updates pushes the updates", function(a }); }); - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { ajaxResponse({ comments: [{ id: 1, name: "FIRST" }] }); post.deleteRecord(); return post.save(); - })).then(async(function(post) { + })).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "DELETE"); assert.equal(passedHash, undefined); @@ -934,12 +935,12 @@ test("delete - a payload with sidloaded updates pushes the updates when the orig }); }); - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { ajaxResponse({ posts: [{ id: 2, name: "The Parley Letter" }] }); post.deleteRecord(); return post.save(); - })).then(async(function(post) { + })).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "DELETE"); assert.equal(passedHash, undefined); @@ -960,7 +961,7 @@ test("delete - deleting a newly created record should not throw an error", funct run(function() { post.deleteRecord(); - post.save().then(async(function(post) { + post.save().then(assert.wait(function(post) { assert.equal(passedUrl, null, "There is no ajax call to delete a record that has never been saved."); assert.equal(passedVerb, null, "There is no ajax call to delete a record that has never been saved."); assert.equal(passedHash, null, "There is no ajax call to delete a record that has never been saved."); @@ -979,7 +980,7 @@ test("findAll - returning an array populates the array", function(assert) { ] }); - store.findAll('post').then(async(function(posts) { + store.findAll('post').then(assert.wait(function(posts) { assert.equal(passedUrl, "/posts"); assert.equal(passedVerb, "GET"); assert.equal(passedHash.data, undefined); @@ -1022,7 +1023,7 @@ test("findAll - passes buildURL the requestType", function(assert) { ] }); - store.findAll('post').then(async(function(posts) { + store.findAll('post').then(assert.wait(function(posts) { assert.equal(passedUrl, "/findAll/posts"); })); }); @@ -1035,7 +1036,7 @@ test("findAll - returning sideloaded data loads the data", function(assert) { ], comments: [{ id: 1, name: "FIRST" }] }); - store.findAll('post').then(async(function(posts) { + store.findAll('post').then(assert.wait(function(posts) { var comment = store.peekRecord('comment', 1); assert.deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); @@ -1055,7 +1056,7 @@ test("findAll - data is normalized through custom serializers", function(assert) ] }); - store.findAll('post').then(async(function(posts) { + store.findAll('post').then(assert.wait(function(posts) { var post1 = store.peekRecord('post', 1); var post2 = store.peekRecord('post', 2); @@ -1091,7 +1092,7 @@ test("query - if `sortQueryParams` option is not provided, query params are sort return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); }; - store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { + store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(assert.wait(function() { // Noop })); }); @@ -1107,7 +1108,7 @@ test("query - passes buildURL the requestType", function(assert) { return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); }; - store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { + store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(assert.wait(function() { // NOOP })); }); @@ -1125,7 +1126,7 @@ test("query - if `sortQueryParams` is falsey, query params are not sorted at all adapter.sortQueryParams = null; - store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { + store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(assert.wait(function() { // Noop })); }); @@ -1152,7 +1153,7 @@ test("query - if `sortQueryParams` is a custom function, query params passed thr return newQueryParams; }; - store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(async(function() { + store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(assert.wait(function() { // Noop })); }); @@ -1163,7 +1164,7 @@ test("query - payload 'meta' is accessible on the record array", function(assert posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - store.query('post', { page: 2 }).then(async(function(posts) { + store.query('post', { page: 2 }).then(assert.wait(function(posts) { assert.equal( posts.get('meta.offset'), 5, @@ -1178,7 +1179,7 @@ test("query - each record array can have it's own meta object", function(assert) posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - store.query('post', { page: 2 }).then(async(function(posts) { + store.query('post', { page: 2 }).then(assert.wait(function(posts) { assert.equal( posts.get('meta.offset'), 5, @@ -1188,7 +1189,7 @@ test("query - each record array can have it's own meta object", function(assert) meta: { offset: 1 }, posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - store.query('post', { page: 1 }).then(async(function(newPosts) { + store.query('post', { page: 1 }).then(assert.wait(function(newPosts) { assert.equal(newPosts.get('meta.offset'), 1, 'new array has correct metadata'); assert.equal(posts.get('meta.offset'), 5, 'metadata on the old array hasnt been clobbered'); })); @@ -1203,7 +1204,7 @@ test("query - returning an array populates the array", function(assert) { { id: 2, name: "The Parley Letter" }] }); - store.query('post', { page: 1 }).then(async(function(posts) { + store.query('post', { page: 1 }).then(assert.wait(function(posts) { assert.equal(passedUrl, '/posts'); assert.equal(passedVerb, 'GET'); assert.deepEqual(passedHash.data, { page: 1 }); @@ -1241,7 +1242,7 @@ test("query - returning sideloaded data loads the data", function(assert) { comments: [{ id: 1, name: "FIRST" }] }); - store.query('post', { page: 1 }).then(async(function(posts) { + store.query('post', { page: 1 }).then(assert.wait(function(posts) { var comment = store.peekRecord('comment', 1); assert.deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); @@ -1259,7 +1260,7 @@ test("query - data is normalized through custom serializers", function(assert) { { _ID_: 2, _NAME_: "The Parley Letter" }] }); - store.query('post', { page: 1 }).then(async(function(posts) { + store.query('post', { page: 1 }).then(assert.wait(function(posts) { var post1 = store.peekRecord('post', 1); var post2 = store.peekRecord('post', 2); @@ -1293,7 +1294,7 @@ test("queryRecord - returns a single record in an object", function(assert) { } }); - store.queryRecord('post', { slug: 'ember-js-rocks' }).then(async(function(post) { + store.queryRecord('post', { slug: 'ember-js-rocks' }).then(assert.wait(function(post) { assert.deepEqual(post.get('name'), "Ember.js rocks"); })); }); @@ -1304,7 +1305,7 @@ test("queryRecord - returning sideloaded data loads the data", function(assert) comments: [{ id: 1, name: "FIRST" }] }); - store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(async(function(post) { + store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(assert.wait(function(post) { var comment = store.peekRecord('comment', 1); assert.deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); @@ -1316,7 +1317,7 @@ test("queryRecord - returning an array picks the first one but saves all records post: [{ id: 1, name: "Rails is omakase" }, { id: 2, name: "Ember is js" }] }); - store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(async(function(post) { + store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(assert.wait(function(post) { var post2 = store.peekRecord('post', 2); assert.deepEqual(post.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }); @@ -1334,7 +1335,7 @@ test("queryRecord - data is normalized through custom serializers", function(ass post: { _ID_: 1, _NAME_: "Rails is omakase" } }); - store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(async(function(post) { + store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(assert.wait(function(post) { assert.deepEqual( post.getProperties('id', 'name'), @@ -1377,7 +1378,7 @@ test("findMany - findMany uses a correct URL to access the records", function(as { id: 3, name: "What is omakase?" } ] }); - run(post, 'get', 'comments').then(async(function(comments) { + run(post, 'get', 'comments').then(assert.wait(function(comments) { assert.equal(passedUrl, "/comments"); assert.deepEqual(passedHash, { data: { ids: ["1", "2", "3"] } }); })); @@ -1420,7 +1421,7 @@ test("findMany - passes buildURL the requestType", function(assert) { { id: 3, name: "What is omakase?" } ] }); - run(post, 'get', 'comments').then(async(function(comments) { + run(post, 'get', 'comments').then(assert.wait(function(comments) { assert.equal(passedUrl, "/findMany/comment"); })); }); @@ -1458,7 +1459,7 @@ test("findMany - findMany does not coalesce by default", function(assert) { { id: 3, name: "What is omakase?" } ] }); - run(post, 'get', 'comments').then(async(function(comments) { + run(post, 'get', 'comments').then(assert.wait(function(comments) { assert.equal(passedUrl, "/comments/3"); assert.equal(passedHash, null); })); @@ -1490,7 +1491,7 @@ test("findMany - returning an array populates the array", function(assert) { }); }); - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1500,7 +1501,7 @@ test("findMany - returning an array populates the array", function(assert) { }); return post.get('comments'); - })).then(async(function(comments) { + })).then(assert.wait(function(comments) { var comment1 = store.peekRecord('comment', 1); var comment2 = store.peekRecord('comment', 2); var comment3 = store.peekRecord('comment', 3); @@ -1543,7 +1544,7 @@ test("findMany - returning sideloaded data loads the data", function(assert) { }); }); - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1555,7 +1556,7 @@ test("findMany - returning sideloaded data loads the data", function(assert) { }); return post.get('comments'); - })).then(async(function(comments) { + })).then(assert.wait(function(comments) { var comment1 = store.peekRecord('comment', 1); var comment2 = store.peekRecord('comment', 2); var comment3 = store.peekRecord('comment', 3); @@ -1609,7 +1610,7 @@ test("findMany - a custom serializer is used if present", function(assert) { }); }); - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { ajaxResponse({ comments: [ { _ID_: 1, _NAME_: "FIRST" }, @@ -1618,7 +1619,7 @@ test("findMany - a custom serializer is used if present", function(assert) { }); return post.get('comments'); - })).then(async(function(comments) { + })).then(assert.wait(function(comments) { var comment1 = store.peekRecord('comment', 1); var comment2 = store.peekRecord('comment', 2); var comment3 = store.peekRecord('comment', 3); @@ -1654,7 +1655,7 @@ test("findHasMany - returning an array populates the array", function(assert) { }); }); - run(store, 'findRecord', 'post', '1').then(async(function(post) { + run(store, 'findRecord', 'post', '1').then(assert.wait(function(post) { ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1664,7 +1665,7 @@ test("findHasMany - returning an array populates the array", function(assert) { }); return post.get('comments'); - })).then(async(function(comments) { + })).then(assert.wait(function(comments) { assert.equal(passedUrl, '/posts/1/comments'); assert.equal(passedVerb, 'GET'); assert.equal(passedHash, undefined); @@ -1708,7 +1709,7 @@ test("findHasMany - passes buildURL the requestType", function(assert) { }); }); - run(store, 'findRecord', 'post', '1').then(async(function(post) { + run(store, 'findRecord', 'post', '1').then(assert.wait(function(post) { ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1718,7 +1719,7 @@ test("findHasMany - passes buildURL the requestType", function(assert) { }); return post.get('comments'); - })).then(async(function(comments) { + })).then(assert.wait(function(comments) { // NOOP })); }); @@ -1749,7 +1750,7 @@ test("findMany - returning sideloaded data loads the data", function(assert) { }); }); - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1760,7 +1761,7 @@ test("findMany - returning sideloaded data loads the data", function(assert) { }); return post.get('comments'); - })).then(async(function(comments) { + })).then(assert.wait(function(comments) { var comment1 = store.peekRecord('comment', 1); var comment2 = store.peekRecord('comment', 2); var comment3 = store.peekRecord('comment', 3); @@ -1805,7 +1806,7 @@ test("findMany - a custom serializer is used if present", function(assert) { }); }); - store.findRecord('post', 1).then(async(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { ajaxResponse({ comments: [ { _ID_: 1, _NAME_: "FIRST" }, @@ -1814,7 +1815,7 @@ test("findMany - a custom serializer is used if present", function(assert) { ] }); return post.get('comments'); - })).then(async(function(comments) { + })).then(assert.wait(function(comments) { var comment1 = store.peekRecord('comment', 1); var comment2 = store.peekRecord('comment', 2); var comment3 = store.peekRecord('comment', 3); @@ -1854,15 +1855,15 @@ test('findBelongsTo - passes buildURL the requestType', function(assert) { }); }); - run(store, 'findRecord', 'comment', 1).then(async(function(comment) { + run(store, 'findRecord', 'comment', 1).then(assert.wait(function(comment) { ajaxResponse({ post: { id: 1, name: 'Rails is omakase' } }); return comment.get('post'); - })).then(async(function(post) { + })).then(assert.wait(function(post) { // NOOP })); }); -test('coalesceFindRequests warns if the expected records are not returned in the coalesced request', function(assert) { +test('coalesceFindRequests assert.warns if the expected records are not returned in the coalesced request', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -1871,7 +1872,7 @@ test('coalesceFindRequests warns if the expected records are not returned in the ajaxResponse({ comments: [{ id: 1 }] }); var post; - warns(function() { + assert.warns(function() { run(function() { store.push({ data: { @@ -2051,7 +2052,7 @@ test('normalizeKey - to set up _ids and _id', function(assert) { }); run(function() { - store.find('post', 1).then(async(function(post) { + store.find('post', 1).then(assert.wait(function(post) { assert.equal(post.get('authorName'), "@d2h"); assert.equal(post.get('author.name'), "D2H"); assert.deepEqual(post.get('comments').mapBy('body'), ["Rails is unagi", "What is omakase?"]); @@ -2311,7 +2312,7 @@ test('on error wraps the error string in an DS.AdapterError object', function(as } }); -test('findAll resolves with a collection of DS.Models, not DS.InternalModels', () => { +test('findAll resolves with a collection of DS.Models, not DS.InternalModels', (assert) => { assert.expect(4); ajaxResponse({ @@ -2332,9 +2333,9 @@ test('findAll resolves with a collection of DS.Models, not DS.InternalModels', ( }); run(() => { - store.findAll('post').then(async((posts) => { + store.findAll('post').then(assert.wait((posts) => { assert.equal(get(posts, 'length'), 3); - posts.forEach((post) => ok(post instanceof DS.Model)); + posts.forEach((post) => assert.ok(post instanceof DS.Model)); })); }); diff --git a/tests/integration/adapter/serialize-test.js b/tests/integration/adapter/serialize-test.js index 348edeb6c0d..90d3565b87c 100644 --- a/tests/integration/adapter/serialize-test.js +++ b/tests/integration/adapter/serialize-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 0fc2f21120d..169539001ff 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -56,11 +57,11 @@ test("Records loaded multiple times and retrieved in recordArray are ready to se }]); }; - run(store, 'query', 'person', { q: 'bla' }).then(async(function(people) { + run(store, 'query', 'person', { q: 'bla' }).then(assert.wait(function(people) { var people2 = store.query('person', { q: 'bla2' }); return Ember.RSVP.hash({ people: people, people2: people2 }); - })).then(async(function(results) { + })).then(assert.wait(function(results) { assert.equal(results.people2.get('length'), 2, 'return the elements'); assert.ok(results.people2.get('isLoaded'), 'array is loaded'); @@ -107,12 +108,12 @@ test("by default, createRecords calls createRecord once per record", function(as yehuda: yehuda.save() }); }); - promise.then(async(function(records) { + promise.then(assert.wait(function(records) { tom = records.tom; yehuda = records.yehuda; - asyncEqual(tom, store.findRecord('person', 1), "Once an ID is in, find returns the same object"); - asyncEqual(yehuda, store.findRecord('person', 2), "Once an ID is in, find returns the same object"); + assert.asyncEqual(tom, store.findRecord('person', 1), "Once an ID is in, find returns the same object"); + assert.asyncEqual(yehuda, store.findRecord('person', 2), "Once an ID is in, find returns the same object"); assert.equal(get(tom, 'updatedAt'), "now", "The new information is received"); assert.equal(get(yehuda, 'updatedAt'), "now", "The new information is received"); })); @@ -164,7 +165,7 @@ test("by default, updateRecords calls updateRecord once per record", function(as }); }); - promise.then(async(function(records) { + promise.then(assert.wait(function(records) { var tom = records.tom; var yehuda = records.yehuda; @@ -172,7 +173,7 @@ test("by default, updateRecords calls updateRecord once per record", function(as set(yehuda, "name", "Yehuda Katz"); return Ember.RSVP.hash({ tom: tom.save(), yehuda: yehuda.save() }); - })).then(async(function(records) { + })).then(assert.wait(function(records) { var tom = records.tom; var yehuda = records.yehuda; @@ -226,7 +227,7 @@ test("calling store.didSaveRecord can provide an optional hash", function(assert yehuda: store.findRecord('person', 2) }); }); - promise.then(async(function(records) { + promise.then(assert.wait(function(records) { var tom = records.tom; var yehuda = records.yehuda; @@ -234,7 +235,7 @@ test("calling store.didSaveRecord can provide an optional hash", function(assert set(yehuda, "name", "Yehuda Katz"); return Ember.RSVP.hash({ tom: tom.save(), yehuda: yehuda.save() }); - })).then(async(function(records) { + })).then(assert.wait(function(records) { var tom = records.tom; var yehuda = records.yehuda; @@ -292,7 +293,7 @@ test("by default, deleteRecord calls deleteRecord once per record", function(ass }); }); - promise.then(async(function(records) { + promise.then(assert.wait(function(records) { var tom = records.tom; var yehuda = records.yehuda; @@ -350,7 +351,7 @@ test("by default, destroyRecord calls deleteRecord once per record without requi }); }); - promise.then(async(function(records) { + promise.then(assert.wait(function(records) { var tom = records.tom; var yehuda = records.yehuda; @@ -390,14 +391,14 @@ test("if an existing model is edited then deleted, deleteRecord is called on the }); // Retrieve that loaded record and edit it so it becomes dirty - run(store, 'findRecord', 'person', 'deleted-record').then(async(function(tom) { + run(store, 'findRecord', 'person', 'deleted-record').then(assert.wait(function(tom) { tom.set('name', "Tom Mothereffin' Dale"); assert.equal(get(tom, 'hasDirtyAttributes'), true, "precond - record should be dirty after editing"); tom.deleteRecord(); return tom.save(); - })).then(async(function(tom) { + })).then(assert.wait(function(tom) { assert.equal(get(tom, 'hasDirtyAttributes'), false, "record should not be dirty"); assert.equal(get(tom, 'isDeleted'), true, "record should be considered deleted"); })); @@ -431,17 +432,17 @@ test("if a deleted record errors, it enters the error state", function(assert) { var tom; run(function() { - store.findRecord('person', 'deleted-record').then(async(function(person) { + store.findRecord('person', 'deleted-record').then(assert.wait(function(person) { tom = person; person.deleteRecord(); return person.save(); - })).then(null, async(function() { + })).then(null, assert.wait(function() { assert.equal(tom.get('isError'), true, "Tom is now errored"); assert.equal(tom.get('adapterError'), error, "error object is exposed"); // this time it succeeds return tom.save(); - })).then(async(function() { + })).then(assert.wait(function() { assert.equal(tom.get('isError'), false, "Tom is not errored anymore"); assert.equal(tom.get('adapterError'), null, "error object is discarded"); })); @@ -473,7 +474,7 @@ test("if a created record is marked as invalid by the server, it enters an error // Wrap this in an Ember.run so that all chained async behavior is set up // before flushing any scheduled behavior. Ember.run(function() { - yehuda.save().then(null, async(function(error) { + yehuda.save().then(null, assert.wait(function(error) { assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); assert.ok(get(yehuda, 'errors.name'), "The errors.name property exists"); @@ -488,7 +489,7 @@ test("if a created record is marked as invalid by the server, it enters an error assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); return yehuda.save(); - })).then(async(function(person) { + })).then(assert.wait(function(person) { assert.strictEqual(person, yehuda, "The promise resolves with the saved record"); assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); @@ -521,7 +522,7 @@ test("allows errors on arbitrary properties on create", function(assert) { // Wrap this in an Ember.run so that all chained async behavior is set up // before flushing any scheduled behavior. run(function() { - yehuda.save().then(null, async(function(error) { + yehuda.save().then(null, assert.wait(function(error) { assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); assert.ok(get(yehuda, 'errors.base'), "The errors.base property exists"); assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), [{ attribute: 'base', message: "is a generally unsavoury character" }]); @@ -537,7 +538,7 @@ test("allows errors on arbitrary properties on create", function(assert) { assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); return yehuda.save(); - })).then(async(function(person) { + })).then(assert.wait(function(person) { assert.strictEqual(person, yehuda, "The promise resolves with the saved record"); assert.ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), []); @@ -575,7 +576,7 @@ test("if a created record is marked as invalid by the server, you can attempt th // Wrap this in an Ember.run so that all chained async behavior is set up // before flushing any scheduled behavior. Ember.run(function() { - yehuda.save().then(null, async(function(reason) { + yehuda.save().then(null, assert.wait(function(reason) { assert.equal(saveCount, 1, "The record has been saved once"); assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); @@ -583,7 +584,7 @@ test("if a created record is marked as invalid by the server, you can attempt th assert.ok(get(yehuda, 'errors.name'), "The errors.name property exists"); assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); return yehuda.save(); - })).then(null, async(function(reason) { + })).then(null, assert.wait(function(reason) { assert.equal(saveCount, 2, "The record has been saved twice"); assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid"); @@ -592,7 +593,7 @@ test("if a created record is marked as invalid by the server, you can attempt th assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); set(yehuda, 'name', 'Brohuda Brokatz'); return yehuda.save(); - })).then(async(function(person) { + })).then(assert.wait(function(person) { assert.equal(saveCount, 3, "The record has been saved thrice"); assert.equal(get(yehuda, 'isValid'), true, "record is valid"); assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is not dirty"); @@ -611,7 +612,7 @@ test("if a created record is marked as erred by the server, it enters an error s Ember.run(function() { var person = store.createRecord('person', { id: 1, name: "John Doe" }); - person.save().then(null, async(function() { + person.save().then(null, assert.wait(function() { assert.ok(get(person, 'isError'), "the record is in the error state"); assert.equal(get(person, 'adapterError'), error, "error object is exposed"); })); @@ -651,8 +652,8 @@ test("if an updated record is marked as invalid by the server, it enters an erro return store.peekRecord('person', 1); }); - Ember.run(function() { - store.findRecord('person', 1).then(async(function(person) { + return Ember.run(function() { + return store.findRecord('person', 1).then(assert.wait(function(person) { assert.equal(person, yehuda, "The same object is passed through"); assert.equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); @@ -662,7 +663,7 @@ test("if an updated record is marked as invalid by the server, it enters an erro assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); return yehuda.save(); - })).then(null, async(function(reason) { + })).then(null, assert.wait(function(reason) { assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); @@ -674,7 +675,7 @@ test("if an updated record is marked as invalid by the server, it enters an erro assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); return yehuda.save(); - })).then(async(function(yehuda) { + })).then(assert.wait(function(yehuda) { assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is no longer new"); })); @@ -714,7 +715,7 @@ test("records can have errors on arbitrary properties after update", function(as }); run(function() { - store.findRecord('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { assert.equal(person, yehuda, "The same object is passed through"); assert.equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); @@ -724,7 +725,7 @@ test("records can have errors on arbitrary properties after update", function(as assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); return yehuda.save(); - })).then(null, async(function(reason) { + })).then(null, assert.wait(function(reason) { assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); assert.ok(get(yehuda, 'errors.base'), "The errors.base property exists"); @@ -738,7 +739,7 @@ test("records can have errors on arbitrary properties after update", function(as assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); return yehuda.save(); - })).then(async(function(yehuda) { + })).then(assert.wait(function(yehuda) { assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is no longer new"); assert.ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); @@ -784,7 +785,7 @@ test("if an updated record is marked as invalid by the server, you can attempt t }); Ember.run(function() { - store.findRecord('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { assert.equal(person, yehuda, "The same object is passed through"); assert.equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); @@ -794,20 +795,20 @@ test("if an updated record is marked as invalid by the server, you can attempt t assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); return yehuda.save(); - })).then(null, async(function(reason) { + })).then(null, assert.wait(function(reason) { assert.equal(saveCount, 1, "The record has been saved once"); assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); return yehuda.save(); - })).then(null, async(function(reason) { + })).then(null, assert.wait(function(reason) { assert.equal(saveCount, 2, "The record has been saved twice"); assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); assert.equal(get(yehuda, 'isValid'), false, "record is still invalid"); assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "record is still dirty"); set(yehuda, 'name', 'Brohuda Brokatz'); return yehuda.save(); - })).then(async(function(person) { + })).then(assert.wait(function(person) { assert.equal(saveCount, 3, "The record has been saved thrice"); assert.equal(get(yehuda, 'isValid'), true, "record is valid"); assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is not dirty"); @@ -838,11 +839,11 @@ test("if a updated record is marked as erred by the server, it enters an error s return store.peekRecord('person', 1); }); - run(store, 'findRecord', 'person', 1).then(async(function(record) { + run(store, 'findRecord', 'person', 1).then(assert.wait(function(record) { assert.equal(record, person, "The person was resolved"); person.set('name', "Jonathan Doe"); return person.save(); - })).then(null, async(function(reason) { + })).then(null, assert.wait(function(reason) { assert.ok(get(person, 'isError'), "the record is in the error state"); assert.equal(get(person, 'adapterError'), error, "error object is exposed"); })); @@ -876,10 +877,10 @@ test("the filter method can optionally take a server query as well", function(as var loadedFilter; - asyncFilter.then(async(function(filter) { + asyncFilter.then(assert.wait(function(filter) { loadedFilter = filter; return store.findRecord('person', 2); - })).then(async(function(tom) { + })).then(assert.wait(function(tom) { assert.equal(get(loadedFilter, 'length'), 1, "The filter has an item in it"); assert.deepEqual(loadedFilter.toArray(), [tom], "The filter has a single entry in it"); })); @@ -942,12 +943,12 @@ test("relationships returned via `commit` do not trigger additional findManys", }; run(function() { - store.findRecord('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { return Ember.RSVP.hash({ tom: person, dog: store.findRecord('dog', 1) }); - })).then(async(function(records) { + })).then(assert.wait(function(records) { records.tom.get('dogs'); return records.dog.save(); - })).then(async(function(tom) { + })).then(assert.wait(function(tom) { assert.ok(true, "Tom was saved"); })); }); @@ -988,11 +989,11 @@ test("relationships don't get reset if the links is the same", function(assert) var tom, dogs; - run(store, 'findRecord', 'person', 1).then(async(function(person) { + run(store, 'findRecord', 'person', 1).then(assert.wait(function(person) { tom = person; dogs = tom.get('dogs'); return dogs; - })).then(async(function(dogs) { + })).then(assert.wait(function(dogs) { assert.equal(dogs.get('length'), 1, "The dogs are loaded"); store.push({ data: { @@ -1012,7 +1013,7 @@ test("relationships don't get reset if the links is the same", function(assert) }); assert.ok(tom.get('dogs') instanceof DS.PromiseArray, 'dogs is a promise'); return tom.get('dogs'); - })).then(async(function(dogs) { + })).then(assert.wait(function(dogs) { assert.equal(dogs.get('length'), 1, "The same dogs are loaded"); })); }); @@ -1037,7 +1038,7 @@ test("async hasMany always returns a promise", function(assert) { assert.ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise before save"); run(function() { - tom.save().then(async(function() { + tom.save().then(assert.wait(function() { assert.ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise after save"); })); }); @@ -1212,7 +1213,7 @@ test("findBelongsTo receives a snapshot", function(assert) { dog: DS.belongsTo({ async: true }) }); - env.adapter.findBelongsTo = async(function(store, snapshot, link, relationship) { + env.adapter.findBelongsTo = assert.wait(function(store, snapshot, link, relationship) { assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); return Ember.RSVP.resolve({ id: 2 }); }); @@ -1244,7 +1245,7 @@ test("findBelongsTo receives a snapshot", function(assert) { test("record.save should pass adapterOptions to the updateRecord method", function(assert) { assert.expect(1); - env.adapter.updateRecord = async(function(store, type, snapshot) { + env.adapter.updateRecord = assert.wait(function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); return Ember.RSVP.resolve({ id: 1 }); }); @@ -1267,7 +1268,7 @@ test("record.save should pass adapterOptions to the updateRecord method", functi test("record.save should pass adapterOptions to the createRecord method", function(assert) { assert.expect(1); - env.adapter.createRecord = async(function(store, type, snapshot) { + env.adapter.createRecord = assert.wait(function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); return Ember.RSVP.resolve({ id: 1 }); }); @@ -1281,7 +1282,7 @@ test("record.save should pass adapterOptions to the createRecord method", functi test("record.save should pass adapterOptions to the deleteRecord method", function(assert) { assert.expect(1); - env.adapter.deleteRecord = async(function(store, type, snapshot) { + env.adapter.deleteRecord = assert.wait(function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); return Ember.RSVP.resolve({ id: 1 }); }); @@ -1305,7 +1306,7 @@ test("record.save should pass adapterOptions to the deleteRecord method", functi test("findRecord should pass adapterOptions to the find method", function(assert) { assert.expect(1); - env.adapter.findRecord = async(function(store, type, id, snapshot) { + env.adapter.findRecord = assert.wait(function(store, type, id, snapshot) { assert.deepEqual(snapshot.adapterOptions, { query: { embed: true } }); return Ember.RSVP.resolve({ id: 1 }); }); @@ -1319,7 +1320,7 @@ test("findRecord should pass adapterOptions to the find method", function(assert test("findAll should pass adapterOptions to the findAll method", function(assert) { assert.expect(1); - env.adapter.findAll = async(function(store, type, sinceToken, arraySnapshot) { + env.adapter.findAll = assert.wait(function(store, type, sinceToken, arraySnapshot) { var adapterOptions = arraySnapshot.adapterOptions; assert.deepEqual(adapterOptions, { query: { embed: true } }); return Ember.RSVP.resolve([{ id: 1 }]); @@ -1371,9 +1372,9 @@ test("An async hasMany relationship with links should not trigger shouldBackgrou store = env.store; - run(store, 'find', 'post', '1').then(async(function(post) { + run(store, 'find', 'post', '1').then(assert.wait(function(post) { return post.get('comments'); - })).then(async(function(comments) { + })).then(assert.wait(function(comments) { assert.equal(comments.get('length'), 3); })); }); diff --git a/tests/integration/backwards-compat/non-dasherized-lookups-test.js b/tests/integration/backwards-compat/non-dasherized-lookups-test.js index 28475fe6ea2..f888fd15403 100644 --- a/tests/integration/backwards-compat/non-dasherized-lookups-test.js +++ b/tests/integration/backwards-compat/non-dasherized-lookups-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index 4a7ed51736c..0f7c4ee2e06 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/filter-test.js b/tests/integration/filter-test.js index e715a8e8515..79bb18b599f 100644 --- a/tests/integration/filter-test.js +++ b/tests/integration/filter-test.js @@ -1,10 +1,11 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; -import customAdapter from 'ember-data/tests/helpers/custom-adapter'; +import customAdapter from 'dummy/tests/helpers/custom-adapter'; var get = Ember.get; var set = Ember.set; @@ -12,14 +13,6 @@ var run = Ember.run; var Person, store, env, array, recordArray; -var shouldContain = function(array, item) { - assert.ok(array.indexOf(item) !== -1, "array should contain "+item.get('name')); -}; - -var shouldNotContain = function(array, item) { - assert.ok(array.indexOf(item) === -1, "array should not contain "+item.get('name')); -}; - module("integration/filter - DS.Model updating", { beforeEach: function() { array = [{ @@ -242,13 +235,13 @@ test("a Record Array can update its filter", function(assert) { store.filter('person', function(hash) { if (hash.get('name').match(/Scumbag [KD]/)) { return true; } - }).then(async(function(recordArray) { + }).then(assert.wait(function(recordArray) { - Ember.RSVP.hash({ dale: asyncDale, katz: asyncKatz, bryn: asyncBryn }).then(async(function(records) { - shouldContain(recordArray, records.dale); - shouldContain(recordArray, records.katz); - shouldNotContain(recordArray, records.bryn); - shouldNotContain(recordArray, dickens); + Ember.RSVP.hash({ dale: asyncDale, katz: asyncKatz, bryn: asyncBryn }).then(assert.wait(function(records) { + assert.contains(recordArray, records.dale); + assert.contains(recordArray, records.katz); + assert.without(recordArray, records.bryn); + assert.without(recordArray, dickens); Ember.run(function() { recordArray.set('filterFunction', function(hash) { @@ -317,7 +310,7 @@ test("a Record Array can update its filter and notify array observers", function store.filter('person', function(hash) { if (hash.get('name').match(/Scumbag [KD]/)) { return true; } - }).then(async(function(recordArray) { + }).then(assert.wait(function(recordArray) { var didChangeIdx; var didChangeRemoved = 0; @@ -341,7 +334,7 @@ test("a Record Array can update its filter and notify array observers", function }); }); - Ember.RSVP.all([asyncDale, asyncKatz, asyncBryn]).then(async(function() { + Ember.RSVP.all([asyncDale, asyncKatz, asyncBryn]).then(assert.wait(function() { assert.equal(didChangeRemoved, 1, "removed one item from array"); didChangeRemoved = 0; @@ -423,7 +416,7 @@ test("it is possible to filter by computed properties", function(assert) { assert.equal(filter.get('length'), 1, "the filter now has a record in it"); - store.findRecord('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { Ember.run(function() { person.set('name', "Yehuda Katz"); }); @@ -463,7 +456,7 @@ test("a filter created after a record is already loaded works", function(assert) }); assert.equal(filter.get('length'), 1, "the filter now has a record in it"); - asyncEqual(filter.objectAt(0), store.findRecord('person', 1)); + assert.asyncEqual(filter.objectAt(0), store.findRecord('person', 1)); }); test("filter with query persists query on the resulting filteredRecordArray", function(assert) { @@ -517,9 +510,9 @@ test("it is possible to filter by state flags", function(assert) { assert.equal(filter.get('length'), 0, "the unloaded record isn't in the filter"); - asyncPerson.then(async(function(person) { + asyncPerson.then(assert.wait(function(person) { assert.equal(filter.get('length'), 1, "the now-loaded record is in the filter"); - asyncEqual(filter.objectAt(0), store.findRecord('person', 1)); + assert.asyncEqual(filter.objectAt(0), store.findRecord('person', 1)); })); }); }); @@ -548,7 +541,7 @@ test("it is possible to filter loaded records by dirtiness", function(assert) { }); }); - store.findRecord('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { assert.equal(filter.get('length'), 1, "the clean record is in the filter"); // Force synchronous update of the filter, even though @@ -560,7 +553,7 @@ test("it is possible to filter loaded records by dirtiness", function(assert) { assert.equal(filter.get('length'), 0, "the now-dirty record is not in the filter"); return person.save(); - })).then(async(function(person) { + })).then(assert.wait(function(person) { assert.equal(filter.get('length'), 1, "the clean record is back in the filter"); })); }); @@ -620,7 +613,7 @@ test("it is possible to filter created records by isReloading", function(assert) name: "Tom Dale" }); - person.reload().then(async(function(person) { + person.reload().then(assert.wait(function(person) { assert.equal(filter.get('length'), 1, "the filter correctly returned a reloaded object"); })); }); @@ -660,7 +653,7 @@ var serverResponds = function() { edited.forEach(function(person) { run(person, 'save'); }); }; -var setup = function(serverCallbacks) { +var setup = function(assert, serverCallbacks){ run(function() { customAdapter(env, DS.Adapter.extend(serverCallbacks)); @@ -675,7 +668,7 @@ var setup = function(serverCallbacks) { }; test("a Record Array can update its filter after server-side updates one record", function(assert) { - setup({ + setup(assert, { updateRecord: function(store, type, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Scumbag Server-side Dale" }); }, @@ -690,7 +683,7 @@ test("a Record Array can update its filter after server-side updates one record" }); test("a Record Array can update its filter after server-side updates multiple records", function(assert) { - setup({ + setup(assert, { updateRecord: function(store, type, snapshot) { switch (snapshot.id) { case "1": @@ -710,7 +703,7 @@ test("a Record Array can update its filter after server-side updates multiple re }); test("a Record Array can update its filter after server-side creates one record", function(assert) { - setup({ + setup(assert, { createRecord: function(store, type, snapshot) { return Ember.RSVP.resolve({ id: 4, name: "Scumbag Server-side Tim" }); } @@ -724,7 +717,7 @@ test("a Record Array can update its filter after server-side creates one record" }); test("a Record Array can update its filter after server-side creates multiple records", function(assert) { - setup({ + setup(assert, { createRecord: function(store, type, snapshot) { switch (snapshot.attr('name')) { case "Client-side Mike": @@ -743,7 +736,7 @@ test("a Record Array can update its filter after server-side creates multiple re }); test("a Record Array can update its filter after server-side creates multiple records", function(assert) { - setup({ + setup(assert, { createRecord: function(store, type, snapshot) { switch (snapshot.attr('name')) { case "Client-side Mike": diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index d60d4367289..c1d7b8f1e72 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -107,7 +108,7 @@ test("Errors out if you define 2 inverses to the same model", function(assert) { job: belongsTo('job', { async: false }) }); - expectAssertion(function() { + assert.expectAssertion(function() { User.inverseFor('job', store); }, "You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses"); }); @@ -127,7 +128,7 @@ test("Caches findInverseFor return value", function(assert) { test("Errors out if you do not define an inverse for a reflexive relationship", function(assert) { //Maybe store is evaluated lazily, so we need this :( - warns(function() { + assert.warns(function() { var reflexiveModel; run(function() { store.push({ diff --git a/tests/integration/lifecycle-hooks-test.js b/tests/integration/lifecycle-hooks-test.js index 62c3698f942..4dec8fd5522 100644 --- a/tests/integration/lifecycle-hooks-test.js +++ b/tests/integration/lifecycle-hooks-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -25,7 +26,8 @@ module("integration/lifecycle_hooks - Lifecycle Hooks", { } }); -asyncTest("When the adapter acknowledges that a record has been created, a `didCreate` event is triggered.", function() { +test("When the adapter acknowledges that a record has been created, a `didCreate` event is triggered.", function(assert) { + let done = assert.async(); assert.expect(3); env.adapter.createRecord = function(store, type, snapshot) { @@ -41,7 +43,7 @@ asyncTest("When the adapter acknowledges that a record has been created, a `didC assert.equal(this, person, "this is bound to the record"); assert.equal(this.get('id'), "99", "the ID has been assigned"); assert.equal(this.get('name'), "Yehuda Katz", "the attribute has been assigned"); - start(); + done(); }); run(person, 'save'); diff --git a/tests/integration/multiple_stores_test.js b/tests/integration/multiple_stores_test.js index e26e030f952..c959862e5bf 100644 --- a/tests/integration/multiple_stores_test.js +++ b/tests/integration/multiple_stores_test.js @@ -1,4 +1,6 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import { module, test } from 'qunit'; import DS from 'ember-data'; @@ -44,7 +46,7 @@ module("integration/multiple_stores - Multiple Stores Tests", { } }); -test("should be able to push into multiple stores", function() { +test("should be able to push into multiple stores", function(assert) { env.registry.register('adapter:home-planet', DS.RESTAdapter.extend({ shouldBackgroundReloadRecord: () => false })); @@ -59,21 +61,21 @@ test("should be able to push into multiple stores", function() { env.store_b.push(env.store_b.normalize('home-planet', home_planet_b)); }); - run(env.store, 'findRecord', 'home-planet', 1).then(async(function(homePlanet) { - equal(homePlanet.get('name'), "Earth"); + run(env.store, 'findRecord', 'home-planet', 1).then(assert.wait(function(homePlanet) { + assert.equal(homePlanet.get('name'), "Earth"); })); - run(env.store_a, 'findRecord', 'home-planet', 1).then(async(function(homePlanet) { - equal(homePlanet.get('name'), "Mars"); + run(env.store_a, 'findRecord', 'home-planet', 1).then(assert.wait(function(homePlanet) { + assert.equal(homePlanet.get('name'), "Mars"); })); - run(env.store_b, 'findRecord', 'home-planet', 1).then(async(function(homePlanet) { - equal(homePlanet.get('name'), "Saturn"); + run(env.store_b, 'findRecord', 'home-planet', 1).then(assert.wait(function(homePlanet) { + assert.equal(homePlanet.get('name'), "Saturn"); })); }); -test("embedded records should be created in multiple stores", function() { +test("embedded records should be created in multiple stores", function(assert) { env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' } @@ -122,19 +124,19 @@ test("embedded records should be created in multiple stores", function() { run(function() { json_main = serializer_main.normalizeResponse(env.store, env.store.modelFor('home-planet'), json_hash_main, 1, 'findRecord'); env.store.push(json_main); - equal(env.store.hasRecordForId('super-villain', "1"), true, "superVillain should exist in service:store"); + assert.equal(env.store.hasRecordForId('super-villain', "1"), true, "superVillain should exist in service:store"); }); run(function() { json_a = serializer_a.normalizeResponse(env.store_a, env.store_a.modelFor('home-planet'), json_hash_a, 1, 'findRecord'); env.store_a.push(json_a); - equal(env.store_a.hasRecordForId("super-villain", "1"), true, "superVillain should exist in store:store-a"); + assert.equal(env.store_a.hasRecordForId("super-villain", "1"), true, "superVillain should exist in store:store-a"); }); run(function() { json_b = serializer_b.normalizeResponse(env.store_b, env.store_a.modelFor('home-planet'), json_hash_b, 1, 'findRecord'); env.store_b.push(json_b); - equal(env.store_b.hasRecordForId("super-villain", "1"), true, "superVillain should exist in store:store-b"); + assert.equal(env.store_b.hasRecordForId("super-villain", "1"), true, "superVillain should exist in store:store-b"); }); }); diff --git a/tests/integration/peek-all-test.js b/tests/integration/peek-all-test.js index 126f60e9458..263c81d2a27 100644 --- a/tests/integration/peek-all-test.js +++ b/tests/integration/peek-all-test.js @@ -1,3 +1,4 @@ +import {createStore} from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/polymorphic-belongs-to-test.js b/tests/integration/polymorphic-belongs-to-test.js index 8c64116b51b..e6dd0d52fe6 100644 --- a/tests/integration/polymorphic-belongs-to-test.js +++ b/tests/integration/polymorphic-belongs-to-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -39,7 +40,7 @@ module('integration/polymorphic-belongs-to - Polymorphic BelongsTo', { }); -test('using store.push with a null value for a payload in relationships sets the Models relationship to null - sync relationship', () => { +test('using store.push with a null value for a payload in relationships sets the Models relationship to null - sync relationship', (assert) => { let payload = { data: { type: 'book', @@ -87,7 +88,7 @@ test('using store.push with a null value for a payload in relationships sets the assert.equal(book.get('author'), null); }); -test('using store.push with a null value for a payload in relationships sets the Models relationship to null - async relationship', () => { +test('using store.push with a null value for a payload in relationships sets the Models relationship to null - async relationship', (assert) => { let payload = { data: { type: 'async-book', @@ -129,13 +130,13 @@ test('using store.push with a null value for a payload in relationships sets the } }; - stop(); + let done = assert.async(); book.get('author').then((author) => { assert.equal(author.get('id'), 1); run(() => store.push(payloadThatResetsBelongToRelationship)); return book.get('author'); }).then((author) => { - start(); assert.equal(author, null); + done(); }); }); diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index a046a911906..fafc0a741f2 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/records/collection-save-test.js b/tests/integration/records/collection-save-test.js index 778dbe7eb24..96725228daa 100644 --- a/tests/integration/records/collection-save-test.js +++ b/tests/integration/records/collection-save-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -37,7 +38,7 @@ test("Collection will resolve save on success", function(assert) { }; run(function() { - posts.save().then(async(function() { + posts.save().then(assert.wait(function() { assert.ok(true, 'save operation was resolved'); })); }); @@ -56,7 +57,7 @@ test("Collection will reject save on error", function(assert) { }; run(function() { - posts.save().then(function() {}, async(function() { + posts.save().then(function() {}, assert.wait(function() { assert.ok(true, 'save operation was rejected'); })); }); @@ -85,9 +86,9 @@ test("Retry is allowed in a failure handler", function(assert) { }; run(function() { - posts.save().then(function() {}, async(function() { + posts.save().then(function() {}, assert.wait(function() { return posts.save(); - })).then(async(function(post) { + })).then(assert.wait(function(post) { assert.equal(posts.get('firstObject.id'), '123', "The post ID made it through"); })); }); diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index 0ccb876d245..ee4ef87ccf1 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/records/load-test.js b/tests/integration/records/load-test.js index 91d61056732..690adc61cc3 100644 --- a/tests/integration/records/load-test.js +++ b/tests/integration/records/load-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -33,7 +34,7 @@ test("When loading a record fails, the isLoading is set to false", function(asse }; run(function() { - env.store.findRecord('post', 1).then(null, async(function() { + env.store.findRecord('post', 1).then(null, assert.wait(function() { // store.recordForId is private, but there is currently no other way to // get the specific record instance, since it is not passed to this // rejection handler diff --git a/tests/integration/records/property-changes-test.js b/tests/integration/records/property-changes-test.js index eec961c7c49..66fec67ba61 100644 --- a/tests/integration/records/property-changes-test.js +++ b/tests/integration/records/property-changes-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/records/reload-test.js b/tests/integration/records/reload-test.js index cea6be8c3a0..8252bb714d6 100644 --- a/tests/integration/records/reload-test.js +++ b/tests/integration/records/reload-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/records/save-test.js b/tests/integration/records/save-test.js index f6b4e588f0b..748d375537f 100644 --- a/tests/integration/records/save-test.js +++ b/tests/integration/records/save-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 3556d30dbc9..619378f2fc9 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index c1f53293e2d..507dd9998a1 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -167,7 +168,7 @@ test("Only a record of the same type can be used with a monomorphic belongsTo re post: store.findRecord('post', 1), comment: store.findRecord('comment', 2) }).then(function(records) { - expectAssertion(function() { + assert.expectAssertion(function() { records.post.set('user', records.comment); }, /You cannot add a record of type 'comment' to the 'post.user' relationship/); }); @@ -218,7 +219,7 @@ test("Only a record of the same base type can be used with a polymorphic belongs comment.set('message', records.post); comment.set('message', null); - expectAssertion(function() { + assert.expectAssertion(function() { comment.set('message', records.user); }, /You cannot add a record of type 'user' to the 'comment.message' relationship \(only 'message' allowed\)/); }); @@ -300,6 +301,7 @@ test("The store can serialize a polymorphic belongsTo association", function(ass }); test("A serializer can materialize a belongsTo as a link that gets sent back to findBelongsTo", function(assert) { + let done = assert.async(); env.adapter.shouldBackgroundReloadRecord = () => false; var Group = DS.Model.extend({ people: DS.hasMany('person', { async: false }) @@ -332,7 +334,7 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to throw new Error("Adapter's find method should not be called"); }; - env.adapter.findBelongsTo = async(function(store, snapshot, link, relationship) { + env.adapter.findBelongsTo = assert.wait(function(store, snapshot, link, relationship) { assert.equal(relationship.type, 'group'); assert.equal(relationship.key, 'group'); assert.equal(link, "/people/1/group"); @@ -346,11 +348,13 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to }).then(function(group) { assert.ok(group instanceof Group, "A group object is loaded"); assert.ok(group.get('id') === '1', 'It is the group we are expecting'); + done(); }); }); }); test('A record with an async belongsTo relationship always returns a promise for that relationship', function(assert) { + let done = assert.async(); env.adapter.shouldBackgroundReloadRecord = () => false; var Seat = DS.Model.extend({ person: DS.belongsTo('person', { async: false }) @@ -383,7 +387,7 @@ test('A record with an async belongsTo relationship always returns a promise for throw new Error("Adapter's find method should not be called"); }; - env.adapter.findBelongsTo = async(function(store, snapshot, link, relationship) { + env.adapter.findBelongsTo = assert.wait(function(store, snapshot, link, relationship) { return Ember.RSVP.resolve({ id: 1 }); }); @@ -394,6 +398,7 @@ test('A record with an async belongsTo relationship always returns a promise for // ok(seat.get('person') === person, 'parent relationship should be populated'); seat.set('person', person); assert.ok(person.get('seat').then, 'seat should be a PromiseObject'); + done(); }); }); }); @@ -434,13 +439,13 @@ test("A record with an async belongsTo relationship returning null should resolv throw new Error("Adapter's find method should not be called"); }; - env.adapter.findBelongsTo = async(function(store, snapshot, link, relationship) { + env.adapter.findBelongsTo = assert.wait(function(store, snapshot, link, relationship) { return Ember.RSVP.resolve(null); }); - env.store.findRecord('person', '1').then(async(function(person) { + env.store.findRecord('person', '1').then(assert.wait(function(person) { return person.get('group'); - })).then(async(function(group) { + })).then(assert.wait(function(group) { assert.ok(group === null, "group should be null"); })); }); @@ -471,7 +476,7 @@ test("A record can be created with a resolved belongsTo promise", function(asser }); var groupPromise = store.findRecord('group', 1); - groupPromise.then(async(function(group) { + groupPromise.then(assert.wait(function(group) { var person = env.store.createRecord('person', { group: groupPromise }); @@ -756,7 +761,7 @@ test("A sync belongsTo errors out if the record is unlaoded", function(assert) { }); - expectAssertion(function() { + assert.expectAssertion(function() { message.get('user'); }, /You looked up the 'user' relationship on a 'message' with id 1 but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async \(`DS.belongsTo\({ async: true }\)`\)/); }); @@ -845,7 +850,7 @@ test("Rollbacking attributes for a deleted record restores implicit relationship test("Passing a model as type to belongsTo should not work", function(assert) { assert.expect(1); - expectAssertion(function() { + assert.expectAssertion(function() { User = DS.Model.extend(); Contact = DS.Model.extend({ diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 0df146558de..2828d6da6b9 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -202,9 +203,9 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi }; run(function() { - env.store.findRecord('post', 1).then(async(function(post) { + env.store.findRecord('post', 1).then(assert.wait(function(post) { return post.get('comments'); - })).then(async(function(comments) { + })).then(assert.wait(function(comments) { assert.equal(comments.get('isLoaded'), true, "comments are loaded"); assert.equal(comments.get('length'), 2, "comments have 2 length"); assert.equal(comments.objectAt(0).get('body'), 'First', "comment loaded successfully"); @@ -214,6 +215,7 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi test("Accessing a hasMany backed by a link multiple times triggers only one request", function(assert) { assert.expect(2); + let done = assert.async(); var count = 0; Post.reopen({ comments: DS.hasMany('comment', { async: true }) @@ -242,10 +244,8 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - start(); count++; assert.equal(count, 1, "findHasMany has only been called once"); - stop(); return new Ember.RSVP.Promise(function(resolve, reject) { setTimeout(function() { var value = [ @@ -257,7 +257,6 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ }); }; - stop(); var promise1, promise2; run(function() { promise1 = post.get('comments'); @@ -276,9 +275,9 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ promise2 = post.get('comments'); }); Ember.RSVP.all([promise1, promise2]).then(function() { - start(); + assert.equal(promise1.promise, promise2.promise, "Same promise is returned both times"); + done(); }); - assert.equal(promise1.promise, promise2.promise, "Same promise is returned both times"); }); test("A hasMany backed by a link remains a promise after a record has been added to it", function(assert) { @@ -1023,7 +1022,7 @@ test("A record can't be created from a polymorphic hasMany relationship", functi env.store.findRecord('user', 1).then(function(user) { return user.get('messages'); }).then(function(messages) { - expectAssertion(function() { + assert.expectAssertion(function() { messages.createRecord(); }, /You cannot add 'message' records to this polymorphic relationship/); }); @@ -1055,7 +1054,7 @@ test("Only records of the same type can be added to a monomorphic hasMany relati env.store.findRecord('post', 1), env.store.findRecord('post', 2) ]).then(function(records) { - expectAssertion(function() { + assert.expectAssertion(function() { records[0].get('comments').pushObject(records[1]); }, /You cannot add a record of type 'post' to the 'post.comments' relationship \(only 'comment' allowed\)/); }); @@ -1116,7 +1115,7 @@ test("Only records of the same base type can be added to a polymorphic hasMany r records.messages.pushObject(records.comment); assert.equal(records.messages.get('length'), 2, "The messages are correctly added"); - expectAssertion(function() { + assert.expectAssertion(function() { records.messages.pushObject(records.anotherUser); }, /You cannot add a record of type 'user' to the 'user.messages' relationship \(only 'message' allowed\)/); }); @@ -1265,7 +1264,7 @@ test("We can set records ASYNC HM relationship", function(assert) { post.set('comments', env.store.peekAll('comment')); }); - post.get('comments').then(async(function(comments) { + post.get('comments').then(assert.wait(function(comments) { assert.equal(comments.get('length') , 2, "we can set async HM relationship"); })); }); @@ -1382,7 +1381,7 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the }); run(function() { - post.get('comments').then(async(function(fetchedComments) { + post.get('comments').then(assert.wait(function(fetchedComments) { assert.equal(fetchedComments.get('length'), 2, 'comments fetched successfully'); assert.equal(fetchedComments.objectAt(0).get('body'), 'first', 'first comment loaded successfully'); env.store.push({ @@ -1400,7 +1399,7 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the } } }); - post.get('comments').then(async(function(newlyFetchedComments) { + post.get('comments').then(assert.wait(function(newlyFetchedComments) { assert.equal(newlyFetchedComments.get('length'), 3, 'all three comments fetched successfully'); assert.equal(newlyFetchedComments.objectAt(2).get('body'), 'third', 'third comment loaded successfully'); })); @@ -1428,7 +1427,7 @@ test("A sync hasMany errors out if there are unlaoded records in it", function(a post = env.store.peekRecord('post', 1); }); - expectAssertion(function() { + assert.expectAssertion(function() { run(post, 'get', 'comments'); }, /You looked up the 'comments' relationship on a 'post' with id 1 but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async \(`DS.hasMany\({ async: true }\)`\)/); }); @@ -1847,7 +1846,7 @@ test("ManyArray notifies the array observers and flushes bindings when adding", test("Passing a model as type to hasMany should not work", function(assert) { assert.expect(1); - expectAssertion(function() { + assert.expectAssertion(function() { User = DS.Model.extend(); Contact = DS.Model.extend({ @@ -1988,6 +1987,7 @@ test('unloading a record with associated records does not prevent the store from test("adding and removing records from hasMany relationship #2666", function(assert) { assert.expect(4); + let done = assert.async(); var Post = DS.Model.extend({ comments: DS.hasMany('comment', { async: true }) @@ -2045,7 +2045,6 @@ test("adding and removing records from hasMany relationship #2666", function(ass }); run(function() { - stop(); env.store.findRecord('post', 1).then(function (post) { var comments = post.get('comments'); assert.equal(comments.get('length'), 3, "Initial comments count"); @@ -2070,7 +2069,7 @@ test("adding and removing records from hasMany relationship #2666", function(ass }).then(function() { var comments = post.get('comments'); assert.equal(comments.get('length'), 4, "Comments count after second add"); - start(); + done(); }); }); }); diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index d17dee2f354..cd649ee8bf8 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -1,3 +1,5 @@ +import {createStore} from 'dummy/tests/helpers/store'; +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -436,7 +438,7 @@ test("Inverse relationships that don't exist throw a nice error for a hasMany", comment = env.store.createRecord('comment'); }); - expectAssertion(function() { + assert.expectAssertion(function() { run(function() { post = env.store.createRecord('post'); post.get('comments'); @@ -458,7 +460,7 @@ test("Inverse relationships that don't exist throw a nice error for a belongsTo" user = env.store.createRecord('user'); }); - expectAssertion(function() { + assert.expectAssertion(function() { run(function() { post = env.store.createRecord('post'); post.get('user'); diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index 8edba4925e4..45b6400b455 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -98,7 +99,7 @@ test("Loading from one hasMany side reflects on the other hasMany side - async", }); run(function() { - topic.get('users').then(async(function(fetchedUsers) { + topic.get('users').then(assert.wait(function(fetchedUsers) { assert.equal(fetchedUsers.get('length'), 1, 'User relationship was set up correctly'); })); }); @@ -176,10 +177,10 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan }); }); run(function() { - user.get('topics').then(async(function(fetchedTopics) { + user.get('topics').then(assert.wait(function(fetchedTopics) { assert.equal(fetchedTopics.get('length'), 0, 'Topics were removed correctly'); assert.equal(fetchedTopics.objectAt(0), null, "Topics can't be fetched"); - topic.get('users').then(async(function(fetchedUsers) { + topic.get('users').then(assert.wait(function(fetchedUsers) { assert.equal(fetchedUsers.get('length'), 0, 'Users were removed correctly'); assert.equal(fetchedUsers.objectAt(0), null, "User can't be fetched"); })); @@ -271,9 +272,9 @@ test("Pushing to a hasMany reflects on the other hasMany side - async", function }); run(function() { - topic.get('users').then(async(function(fetchedUsers) { + topic.get('users').then(assert.wait(function(fetchedUsers) { fetchedUsers.pushObject(user); - user.get('topics').then(async(function(fetchedTopics) { + user.get('topics').then(assert.wait(function(fetchedTopics) { assert.equal(fetchedTopics.get('length'), 1, 'User relationship was set up correctly'); })); })); @@ -339,10 +340,10 @@ test("Removing a record from a hasMany reflects on the other hasMany side - asyn }); run(function() { - user.get('topics').then(async(function(fetchedTopics) { + user.get('topics').then(assert.wait(function(fetchedTopics) { assert.equal(fetchedTopics.get('length'), 1, 'Topics were setup correctly'); fetchedTopics.removeObject(topic); - topic.get('users').then(async(function(fetchedUsers) { + topic.get('users').then(assert.wait(function(fetchedUsers) { assert.equal(fetchedUsers.get('length'), 0, 'Users were removed correctly'); assert.equal(fetchedUsers.objectAt(0), null, "User can't be fetched"); })); @@ -429,10 +430,10 @@ test("Rollbacking attributes for a deleted record that has a ManyToMany relation topic.rollbackAttributes(); }); run(function() { - topic.get('users').then(async(function(fetchedUsers) { + topic.get('users').then(assert.wait(function(fetchedUsers) { assert.equal(fetchedUsers.get('length'), 1, 'Users are still there'); })); - user.get('topics').then(async(function(fetchedTopics) { + user.get('topics').then(assert.wait(function(fetchedTopics) { assert.equal(fetchedTopics.get('length'), 1, 'Topic got rollbacked into the user'); })); }); @@ -493,14 +494,14 @@ test("Rollbacking attributes for a created record that has a ManyToMany relation topic = store.createRecord('topic'); }); run(function() { - user.get('topics').then(async(function(fetchedTopics) { + user.get('topics').then(assert.wait(function(fetchedTopics) { fetchedTopics.pushObject(topic); topic.rollbackAttributes(); - topic.get('users').then(async(function(fetchedUsers) { + topic.get('users').then(assert.wait(function(fetchedUsers) { assert.equal(fetchedUsers.get('length'), 0, 'Users got removed'); assert.equal(fetchedUsers.objectAt(0), null, "User can't be fetched"); })); - user.get('topics').then(async(function(fetchedTopics) { + user.get('topics').then(assert.wait(function(fetchedTopics) { assert.equal(fetchedTopics.get('length'), 0, 'Topics got removed'); assert.equal(fetchedTopics.objectAt(0), null, "Topic can't be fetched"); })); diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index cb1ae282aae..e6c5c92d9ff 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/relationships/one-to-one-test.js b/tests/integration/relationships/one-to-one-test.js index f775709d324..91ab933dd8d 100644 --- a/tests/integration/relationships/one-to-one-test.js +++ b/tests/integration/relationships/one-to-one-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -534,7 +535,7 @@ test("Setting a BelongsTo to a promise that didn't come from a relationship erro }); }); - expectAssertion(function() { + assert.expectAssertion(function() { run(function() { stanley.set('bestFriend', Ember.RSVP.resolve(igor)); }); @@ -594,10 +595,10 @@ test("Setting a BelongsTo to a promise multiple times is resistant to race condi if (id === '5') { return Ember.RSVP.resolve({ id: 5, name: "Igor's friend" }); } else if (id === '2') { - stop(); + let done = assert.async(); return new Ember.RSVP.Promise(function(resolve, reject) { setTimeout(function() { - start(); + done(); resolve({ id: 2, name: "Stanley's friend" }); }, 1); }); diff --git a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index 62572080df0..2f7624477be 100644 --- a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -150,7 +151,7 @@ test("Setting the polymorphic belongsTo with an object that does not implement t }); run(function() { - expectAssertion(function() { + assert.expectAssertion(function() { user.set('bestMessage', video); }, /You cannot add a record of type 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); }); @@ -225,7 +226,7 @@ test("Setting the polymorphic belongsTo with an object that does not implement t }); run(function() { - expectAssertion(function() { + assert.expectAssertion(function() { user.set('bestMessage', video); }, /You cannot add a record of type 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); }); diff --git a/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js index 1caa333a387..d528b00cc71 100644 --- a/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -166,7 +167,7 @@ test("Pushing a an object that does not implement the mixin to the mixin accepti run(function() { user.get('messages').then(function(fetchedMessages) { - expectAssertion(function() { + assert.expectAssertion(function() { fetchedMessages.pushObject(notMessage); }, /You cannot add a record of type 'not-message' to the 'user.messages' relationship \(only 'message' allowed\)/); }); @@ -253,7 +254,7 @@ test("Pushing a an object that does not implement the mixin to the mixin accepti run(function() { user.get('messages').then(function(fetchedMessages) { - expectAssertion(function() { + assert.expectAssertion(function() { fetchedMessages.pushObject(notMessage); }, /You cannot add a record of type 'not-message' to the 'user.messages' relationship \(only 'message' allowed\)/); }); diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index 7291ec2883e..73e10176a4b 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -958,7 +959,7 @@ test("serialize with embedded objects (unknown hasMany relationship)", function( })); var serializer, json; - warns(function() { + assert.warns(function() { run(function() { serializer = env.store.serializerFor("home-planet"); json = serializer.serialize(league._createSnapshot()); diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 74f7f493e09..b1d2d82eae6 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -121,7 +122,7 @@ test('Warns when normalizing an unknown type', function(assert) { } }; - warns(function() { + assert.warns(function() { run(function() { env.store.serializerFor('user').normalizeResponse(env.store, User, documentHash, '1', 'findRecord'); }); diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 7e97eed496b..ad05bcd629a 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index e148d47b515..d271087b2e8 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -154,7 +155,7 @@ test("normalizeResponse warning with custom modelNameFromPayloadKey", function(a home_planet: { id: "1", name: "Umber", superVillains: [1] } }; - warns(Ember.run.bind(null, function() { + assert.warns(Ember.run.bind(null, function() { run(function() { env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, '1', 'findRecord'); }); @@ -166,7 +167,7 @@ test("normalizeResponse warning with custom modelNameFromPayloadKey", function(a home_planet: { id: "1", name: "Umber", superVillains: [1] } }; - noWarns(function() { + assert.noWarns(function() { run(function() { homePlanet = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, 1, 'findRecord'); @@ -188,7 +189,7 @@ test("normalizeResponse warning with custom modelNameFromPayloadKey", function(a home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] }; - warns(function() { + assert.warns(function() { env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); @@ -201,7 +202,7 @@ test("normalizeResponse warning with custom modelNameFromPayloadKey", function(a home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] }; - noWarns(function() { + assert.noWarns(function() { run(function() { homePlanets = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); }); @@ -475,7 +476,7 @@ test('serializeBelongsTo logs deprecation when old behavior for getting polymorp doomsdayDevice = env.store.createRecord('doomsday-device', { id: 2, name: 'Yehuda', evilMinion: evilMinion }); }); - expectDeprecation(function() { + assert.expectDeprecation(function() { env.restSerializer.serializeBelongsTo(doomsdayDevice._createSnapshot(), json, { key: 'evilMinion', options: { polymorphic: true, async: true } }); }, "The key to serialize the type of a polymorphic record is created via keyForAttribute which has been deprecated. Use the keyForPolymorphicType hook instead."); diff --git a/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js index bdba0c40466..6a0aa14eeac 100644 --- a/tests/integration/snapshot-test.js +++ b/tests/integration/snapshot-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index ebd2f34f1fa..c371cd72130 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -56,8 +57,9 @@ function tap(obj, methodName, callback) { return summary; } -asyncTest("destroying record during find doesn't cause error", function() { +test("destroying record during find doesn't cause error", function(assert) { assert.expect(0); + let done = assert.async(); var TestAdapter = DS.Adapter.extend({ findRecord: function(store, type, id, snapshot) { @@ -75,17 +77,14 @@ asyncTest("destroying record during find doesn't cause error", function() { var type = "car"; var id = 1; - function done() { - start(); - } - run(function() { store.findRecord(type, id).then(done, done); }); }); -asyncTest("find calls do not resolve when the store is destroyed", function() { +test("find calls do not resolve when the store is destroyed", function(assert) { assert.expect(0); + let done = assert.async(); var TestAdapter = DS.Adapter.extend({ findRecord: function(store, type, id, snapshot) { @@ -111,7 +110,7 @@ asyncTest("find calls do not resolve when the store is destroyed", function() { }); setTimeout(function() { - start(); + done(); }, 500); }); @@ -329,7 +328,7 @@ test('store#findRecord call with `id` of type different than non-empty string or run(function() { badValues.map(item => { - expectAssertion(function() { + assert.expectAssertion(function() { store.findRecord('car', item); }, '`id` has to be non-empty string or number'); }); diff --git a/tests/integration/store/json-api-validation-test.js b/tests/integration/store/json-api-validation-test.js index fa2a1d281a5..fc96a46a16a 100644 --- a/tests/integration/store/json-api-validation-test.js +++ b/tests/integration/store/json-api-validation-test.js @@ -1,7 +1,6 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; - -import {module, test} from 'qunit'; - +import QUnit, {module, test} from 'qunit'; import DS from 'ember-data'; var Person, store, env; @@ -109,7 +108,7 @@ test("when normalizeResponse returns a document with both data and errors, throw }, /cannot both be present/); }); -function testPayloadError(payload, expectedError) { +QUnit.assert.payloadError = function payloadError(payload, expectedError) { env.registry.register('serializer:person', DS.Serializer.extend({ normalizeResponse(store, type, pld) { return pld; @@ -120,71 +119,71 @@ function testPayloadError(payload, expectedError) { return Ember.RSVP.resolve(payload); } })); - assert.throws(function () { + this.throws(function () { run(function() { store.find('person', 1); }); }, expectedError, `Payload ${JSON.stringify(payload)} should throw error ${expectedError}`); env.registry.unregister('serializer:person'); env.registry.unregister('adapter:person'); -} +}; test("normalizeResponse 'data' cannot be undefined, a number, a string or a boolean", function(assert) { - testPayloadError({ data: undefined }, /data must be/); - testPayloadError({ data: 1 }, /data must be/); - testPayloadError({ data: 'lollerskates' }, /data must be/); - testPayloadError({ data: true }, /data must be/); + assert.payloadError({ data: undefined }, /data must be/); + assert.payloadError({ data: 1 }, /data must be/); + assert.payloadError({ data: 'lollerskates' }, /data must be/); + assert.payloadError({ data: true }, /data must be/); }); test("normalizeResponse 'meta' cannot be an array, undefined, a number, a string or a boolean", function(assert) { - testPayloadError({ meta: undefined }, /meta must be an object/); - testPayloadError({ meta: [] }, /meta must be an object/); - testPayloadError({ meta: 1 }, /meta must be an object/); - testPayloadError({ meta: 'lollerskates' }, /meta must be an object/); - testPayloadError({ meta: true }, /meta must be an object/); + assert.payloadError({ meta: undefined }, /meta must be an object/); + assert.payloadError({ meta: [] }, /meta must be an object/); + assert.payloadError({ meta: 1 }, /meta must be an object/); + assert.payloadError({ meta: 'lollerskates' }, /meta must be an object/); + assert.payloadError({ meta: true }, /meta must be an object/); }); test("normalizeResponse 'links' cannot be an array, undefined, a number, a string or a boolean", function(assert) { - testPayloadError({ data: [], links: undefined }, /links must be an object/); - testPayloadError({ data: [], links: [] }, /links must be an object/); - testPayloadError({ data: [], links: 1 }, /links must be an object/); - testPayloadError({ data: [], links: 'lollerskates' }, /links must be an object/); - testPayloadError({ data: [], links: true }, /links must be an object/); + assert.payloadError({ data: [], links: undefined }, /links must be an object/); + assert.payloadError({ data: [], links: [] }, /links must be an object/); + assert.payloadError({ data: [], links: 1 }, /links must be an object/); + assert.payloadError({ data: [], links: 'lollerskates' }, /links must be an object/); + assert.payloadError({ data: [], links: true }, /links must be an object/); }); test("normalizeResponse 'jsonapi' cannot be an array, undefined, a number, a string or a boolean", function(assert) { - testPayloadError({ data: [], jsonapi: undefined }, /jsonapi must be an object/); - testPayloadError({ data: [], jsonapi: [] }, /jsonapi must be an object/); - testPayloadError({ data: [], jsonapi: 1 }, /jsonapi must be an object/); - testPayloadError({ data: [], jsonapi: 'lollerskates' }, /jsonapi must be an object/); - testPayloadError({ data: [], jsonapi: true }, /jsonapi must be an object/); + assert.payloadError({ data: [], jsonapi: undefined }, /jsonapi must be an object/); + assert.payloadError({ data: [], jsonapi: [] }, /jsonapi must be an object/); + assert.payloadError({ data: [], jsonapi: 1 }, /jsonapi must be an object/); + assert.payloadError({ data: [], jsonapi: 'lollerskates' }, /jsonapi must be an object/); + assert.payloadError({ data: [], jsonapi: true }, /jsonapi must be an object/); }); test("normalizeResponse 'included' cannot be an object, undefined, a number, a string or a boolean", function(assert) { - testPayloadError({ included: undefined }, /included must be an array/); - testPayloadError({ included: {} }, /included must be an array/); - testPayloadError({ included: 1 }, /included must be an array/); - testPayloadError({ included: 'lollerskates' }, /included must be an array/); - testPayloadError({ included: true }, /included must be an array/); + assert.payloadError({ included: undefined }, /included must be an array/); + assert.payloadError({ included: {} }, /included must be an array/); + assert.payloadError({ included: 1 }, /included must be an array/); + assert.payloadError({ included: 'lollerskates' }, /included must be an array/); + assert.payloadError({ included: true }, /included must be an array/); }); test("normalizeResponse 'errors' cannot be an object, undefined, a number, a string or a boolean", function(assert) { - testPayloadError({ errors: undefined }, /errors must be an array/); - testPayloadError({ errors: {} }, /errors must be an array/); - testPayloadError({ errors: 1 }, /errors must be an array/); - testPayloadError({ errors: 'lollerskates' }, /errors must be an array/); - testPayloadError({ errors: true }, /errors must be an array/); + assert.payloadError({ errors: undefined }, /errors must be an array/); + assert.payloadError({ errors: {} }, /errors must be an array/); + assert.payloadError({ errors: 1 }, /errors must be an array/); + assert.payloadError({ errors: 'lollerskates' }, /errors must be an array/); + assert.payloadError({ errors: true }, /errors must be an array/); }); diff --git a/tests/integration/store/query-record-test.js b/tests/integration/store/query-record-test.js index 4f851b38d17..b093c3c6e65 100644 --- a/tests/integration/store/query-record-test.js +++ b/tests/integration/store/query-record-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -28,13 +29,13 @@ module("integration/store/query-record - Query one record with a query hash", { }); test("It raises an assertion when no type is passed", function(assert) { - expectAssertion(function() { + assert.expectAssertion(function() { store.queryRecord(); }, "You need to pass a type to the store's queryRecord method"); }); test("It raises an assertion when no query hash is passed", function(assert) { - expectAssertion(function() { + assert.expectAssertion(function() { store.queryRecord('person'); }, "You need to pass a query hash to the store's queryRecord method"); }); diff --git a/tests/qunit-configuration.js b/tests/qunit-configuration.js deleted file mode 100644 index 1f62492f8e7..00000000000 --- a/tests/qunit-configuration.js +++ /dev/null @@ -1,384 +0,0 @@ -import Ember from 'ember'; - -(function() { - /*global namespace: true */ - - window.EmberDev = window.EmberDev || {}; - - EmberDev.afterEach = function() { - if (Ember && Ember.View) { - var viewIds = []; - for (var id in Ember.View.views) { - if (Ember.View.views[id] != null) { - viewIds.push(id); - } - } - - if (viewIds.length > 0) { - deepEqual(viewIds, [], "Ember.View.views should be empty"); - Ember.View.views = []; - } - } - - if (Ember && Ember.TEMPLATES) { - var templateNames = []; - for (var name in Ember.TEMPLATES) { - if (Ember.TEMPLATES[name] != null) { - templateNames.push(name); - } - } - - if (templateNames.length > 0) { - deepEqual(templateNames, [], "Ember.TEMPLATES should be empty"); - Ember.TEMPLATES = {}; - } - } - }; - - window.globalFailedTests = []; - window.globalTestResults = null; - window.lastAssertionTime = new Date().getTime(); - - var currentTest, assertCount; - - QUnit.testStart(function(data) { - // Reset the assertion count - assertCount = 0; - - currentTest = { - name: data.name, - failedAssertions: [], - total: 0, - passed: 0, - failed: 0, - start: new Date(), - time: 0 - }; - - }); - - QUnit.log(function(data) { - assertCount++; - lastAssertionTime = new Date().getTime(); - - // Ignore passing assertions - if (!data.result) { - currentTest.failedAssertions.push(data); - } - }); - - QUnit.testDone(function(data) { - currentTest.time = (new Date()).getTime() - currentTest.start.getTime(); // ms - currentTest.total = data.total; - currentTest.passed = data.passed; - currentTest.failed = data.failed; - - if (currentTest.failed > 0) { - window.globalFailedTests.push(currentTest); - } - - currentTest = null; - }); - - QUnit.done(function( details ) { - details.failedTests = globalFailedTests; - - window.globalTestResults = details; - }); - - // hack qunit to not suck for Ember objects - var originalTypeof = QUnit.jsDump.typeOf; - - QUnit.jsDump.typeOf = function(obj) { - if (Ember && Ember.Object && Ember.Object.detectInstance(obj)) { - return "emberObject"; - } - - return originalTypeof.call(this, obj); - }; - - // raises is deprecated, but we likely want to keep it around for our es3 - // test runs. - // taken from emberjs/ember-dev here: http://git.io/sQhl3A - QUnit.raises = QUnit['throws']; - window.raises = QUnit['throws']; - - QUnit.jsDump.parsers.emberObject = function(obj) { - return obj.toString(); - }; - - var originalModule = module; - module = function(name, origOpts) { - var opts = {}; - if (origOpts && origOpts.setup) { opts.setup = origOpts.setup; } - opts.teardown = function() { - if (origOpts && origOpts.teardown) { origOpts.teardown(); } - - if (Ember && Ember.run) { - if (Ember.run.currentRunLoop) { - ok(false, "Should not be in a run loop at end of test"); - while (Ember.run.currentRunLoop) { - Ember.run.end(); - } - } - if (Ember.run.hasScheduledTimers()) { - // Use `ok` so we get full description. - // Gate inside of `if` so that we don't mess up `expects` counts - ok(false, "Ember run should not have scheduled timers at end of test"); - Ember.run.cancelTimers(); - } - } - - if (EmberDev.afterEach) { - EmberDev.afterEach(); - } - }; - return originalModule(name, opts); - }; - - // Tests should time out after 5 seconds - QUnit.config.testTimeout = 5000; - - // Handle JSHint - QUnit.config.urlConfig.push('nojshint'); - - EmberDev.jsHint = !QUnit.urlParams.nojshint; - - EmberDev.jsHintReporter = function (file, errors) { - if (!errors) { return ''; } - - var len = errors.length; - var str = ''; - var error, idx; - - if (len === 0) { return ''; } - - for (idx=0; idx { + this.equal(record.get('hasDirtyAttributes'), false, "The record is now clean"); + return record; + })); +}; +assert.warns = warns; +assert.noWarns = noWarns; + +assert.contains = function(array, item) { + this.ok(array.indexOf(item) !== -1, `array contains ${item}`); +}; + +assert.without = function(array, item) { + this.ok(array.indexOf(item) === -1, `array doesn't contain ${item}`); +}; + +addEmberAssertions(assert); + +QUnit.config.testTimeout= 2000; +QUnit.config.urlConfig.push({ id: 'enableoptionalfeatures', label: "Enable Opt Features" }); + diff --git a/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js index 4f2570ff098..65ec56cc02b 100644 --- a/tests/unit/adapter-errors-test.js +++ b/tests/unit/adapter-errors-test.js @@ -76,7 +76,7 @@ test("errorsArrayToHash without trailing slash", function(assert) { test("DS.InvalidError will normalize errors hash will assert", function(assert) { var error; - expectAssertion(function() { + assert.expectAssertion(function() { error = new DS.InvalidError({ name: ['is invalid'] }); }, /expects json-api formatted errors/); }); diff --git a/tests/unit/adapter-populated-record-array-test.js b/tests/unit/adapter-populated-record-array-test.js index 8236089a035..bc33894420d 100644 --- a/tests/unit/adapter-populated-record-array-test.js +++ b/tests/unit/adapter-populated-record-array-test.js @@ -1,3 +1,4 @@ +import {createStore} from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/unit/adapters/build-url-mixin/path-for-type-test.js b/tests/unit/adapters/build-url-mixin/path-for-type-test.js index d50bf75a463..3f33e8d445c 100644 --- a/tests/unit/adapters/build-url-mixin/path-for-type-test.js +++ b/tests/unit/adapters/build-url-mixin/path-for-type-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import DS from 'ember-data'; import {module, test} from 'qunit'; diff --git a/tests/unit/adapters/json-api-adapter/ajax-test.js b/tests/unit/adapters/json-api-adapter/ajax-test.js index f8a71c0c9e4..d802bfcb101 100644 --- a/tests/unit/adapters/json-api-adapter/ajax-test.js +++ b/tests/unit/adapters/json-api-adapter/ajax-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/unit/adapters/rest-adapter/ajax-test.js b/tests/unit/adapters/rest-adapter/ajax-test.js index ffe43e2b7e9..12d817f5cba 100644 --- a/tests/unit/adapters/rest-adapter/ajax-test.js +++ b/tests/unit/adapters/rest-adapter/ajax-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 77cab0d8bd8..eb230dc6d7f 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -1,3 +1,4 @@ +import {createStore} from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/unit/debug-test.js b/tests/unit/debug-test.js index a47669ffbaa..e74ef60f79b 100644 --- a/tests/unit/debug-test.js +++ b/tests/unit/debug-test.js @@ -1,3 +1,4 @@ +import {createStore} from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/unit/many-array-test.js b/tests/unit/many-array-test.js index 3449102b5c0..f1609d723c8 100644 --- a/tests/unit/many-array-test.js +++ b/tests/unit/many-array-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 8783d13daa6..119a9df82b4 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -1,9 +1,11 @@ +import {createStore} from 'dummy/tests/helpers/store'; +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; - -import {module, test} from 'qunit'; - +import QUnit, {module, test} from 'qunit'; import DS from 'ember-data'; +const AssertionPrototype = QUnit.assert; + var get = Ember.get; var set = Ember.set; var run = Ember.run; @@ -166,7 +168,7 @@ test("trying to set an `id` attribute should raise", function(assert) { person: Person }); - expectAssertion(function() { + assert.expectAssertion(function() { run(function() { store.push({ data: { @@ -630,7 +632,7 @@ test("a complex object defaultValue is deprecated ", function(assert) { run(function() { tag = store.createRecord('tag'); }); - expectDeprecation(function() { + assert.expectDeprecation(function() { get(tag, 'tagInfo'); }, /Non primitive defaultValues are deprecated/); }); @@ -648,7 +650,7 @@ test("a null defaultValue is not deprecated", function(assert) { run(function() { tag = store.createRecord('tag'); }); - expectNoDeprecation(); + assert.expectNoDeprecation(); assert.equal(get(tag, 'tagInfo'), null); }); @@ -809,7 +811,7 @@ test("when a method is invoked from an event with the same name the arguments ar assert.equal(eventMethodArgs[1], 2); }); -var converts = function(type, provided, expected) { +AssertionPrototype.converts = function converts(type, provided, expected) { var Model = DS.Model.extend({ name: DS.attr(type) }); @@ -824,11 +826,11 @@ var converts = function(type, provided, expected) { } var testStore = createStore({ model: Model }); - run(function() { + run(() => { testStore.push(testStore.normalize('model', { id: 1, name: provided })); testStore.push(testStore.normalize('model', { id: 2 })); var record = testStore.peekRecord('model', 1); - assert.deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); + this.deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); }); // See: Github issue #421 @@ -837,7 +839,7 @@ var converts = function(type, provided, expected) { // deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); }; -var convertsFromServer = function(type, provided, expected) { +AssertionPrototype.convertsFromServer = function convertsFromServer(type, provided, expected) { var Model = DS.Model.extend({ name: DS.attr(type) }); @@ -857,15 +859,15 @@ var convertsFromServer = function(type, provided, expected) { }) }); - run(function() { + run(() => { testStore.push(testStore.normalize('model', { id: "1", name: provided })); - testStore.findRecord('model', 1).then(function(record) { - assert.deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); + testStore.findRecord('model', 1).then((record) => { + this.deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); }); }); }; -var convertsWhenSet = function(type, provided, expected) { +AssertionPrototype.convertsWhenSet = function(type, provided, expected) { var Model = DS.Model.extend({ name: DS.attr(type) }); @@ -877,16 +879,16 @@ var convertsWhenSet = function(type, provided, expected) { }) }); - run(function() { + run(() => { testStore.push({ data: { type: 'model', id: '2' } }); - testStore.findRecord('model', 2).then(function(record) { + testStore.findRecord('model', 2).then((record) => { set(record, 'name', provided); - assert.deepEqual(record.serialize().name, expected, type + " saves " + provided + " as " + expected); + this.deepEqual(record.serialize().name, expected, type + " saves " + provided + " as " + expected); }); }); }; @@ -894,45 +896,45 @@ var convertsWhenSet = function(type, provided, expected) { test("a DS.Model can describe String attributes", function(assert) { assert.expect(6); - converts('string', "Scumbag Tom", "Scumbag Tom"); - converts('string', 1, "1"); - converts('string', "", ""); - converts('string', null, null); - converts('string', undefined, null); - convertsFromServer('string', undefined, null); + assert.converts('string', "Scumbag Tom", "Scumbag Tom"); + assert.converts('string', 1, "1"); + assert.converts('string', "", ""); + assert.converts('string', null, null); + assert.converts('string', undefined, null); + assert.convertsFromServer('string', undefined, null); }); test("a DS.Model can describe Number attributes", function(assert) { assert.expect(9); - converts('number', "1", 1); - converts('number', "0", 0); - converts('number', 1, 1); - converts('number', 0, 0); - converts('number', "", null); - converts('number', null, null); - converts('number', undefined, null); - converts('number', true, 1); - converts('number', false, 0); + assert.converts('number', "1", 1); + assert.converts('number', "0", 0); + assert.converts('number', 1, 1); + assert.converts('number', 0, 0); + assert.converts('number', "", null); + assert.converts('number', null, null); + assert.converts('number', undefined, null); + assert.converts('number', true, 1); + assert.converts('number', false, 0); }); test("a DS.Model can describe Boolean attributes", function(assert) { assert.expect(7); - converts('boolean', "1", true); - converts('boolean', "", false); - converts('boolean', 1, true); - converts('boolean', 0, false); - converts('boolean', null, false); - converts('boolean', true, true); - converts('boolean', false, false); + assert.converts('boolean', "1", true); + assert.converts('boolean', "", false); + assert.converts('boolean', 1, true); + assert.converts('boolean', 0, false); + assert.converts('boolean', null, false); + assert.converts('boolean', true, true); + assert.converts('boolean', false, false); }); test("a DS.Model can describe Date attributes", function(assert) { assert.expect(5); - converts('date', null, null); - converts('date', undefined, undefined); + assert.converts('date', null, null); + assert.converts('date', undefined, undefined); var dateString = "2011-12-31T00:08:16.000Z"; var date = new Date(Ember.Date.parse(dateString)); @@ -963,8 +965,8 @@ test("a DS.Model can describe Date attributes", function(assert) { assert.deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); }); }); - convertsFromServer('date', dateString, date); - convertsWhenSet('date', date, dateString); + assert.convertsFromServer('date', dateString, date); + assert.convertsWhenSet('date', date, dateString); }); test("don't allow setting", function(assert) { @@ -979,7 +981,7 @@ test("don't allow setting", function(assert) { record = store.createRecord('person'); }); - raises(function() { + assert.throws(function() { run(function() { record.set('isLoaded', true); }); @@ -1028,7 +1030,7 @@ test("A subclass of DS.Model can not use the `data` property", function(assert) var store = createStore({ person: Person }); - expectAssertion(function() { + assert.expectAssertion(function() { run(function() { store.createRecord('person', { name: "TomHuda" }); }); @@ -1043,7 +1045,7 @@ test("A subclass of DS.Model can not use the `store` property", function(assert) var store = createStore({ retailer: Retailer }); - expectAssertion(function() { + assert.expectAssertion(function() { run(function() { store.createRecord('retailer', { name: "Buy n Large" }); }); @@ -1061,7 +1063,7 @@ test("A subclass of DS.Model can not use reserved properties", function(assert) var store = createStore({ post: Post }); - expectAssertion(function() { + assert.expectAssertion(function() { run(function() { store.createRecord('post', {}); }); diff --git a/tests/unit/model/errors-test.js b/tests/unit/model/errors-test.js index e8554016b6e..26367a11d60 100644 --- a/tests/unit/model/errors-test.js +++ b/tests/unit/model/errors-test.js @@ -1,6 +1,7 @@ import DS from 'ember-data'; +import QUnit, {module, test} from 'qunit'; -import {module, test} from 'qunit'; +const AssertPrototype = QUnit.assert; var errors; @@ -13,31 +14,31 @@ module("unit/model/errors", { } }); -function becameInvalid(eventName) { +AssertPrototype.becameInvalid = function becameInvalid(eventName) { if (eventName === 'becameInvalid') { - assert.ok(true, 'becameInvalid send'); + this.ok(true, 'becameInvalid send'); } else { - assert.ok(false, eventName + ' is send instead of becameInvalid'); + this.ok(false, eventName + ' is send instead of becameInvalid'); } -} +}.bind(AssertPrototype); -function becameValid(eventName) { +AssertPrototype.becameValid = function becameValid(eventName) { if (eventName === 'becameValid') { - assert.ok(true, 'becameValid send'); + this.ok(true, 'becameValid send'); } else { - assert.ok(false, eventName + ' is send instead of becameValid'); + this.ok(false, eventName + ' is send instead of becameValid'); } -} +}.bind(AssertPrototype); -function unexpectedSend(eventName) { - assert.ok(false, 'unexpected send : ' + eventName); -} +AssertPrototype.unexpectedSend = function unexpectedSend(eventName) { + this.ok(false, 'unexpected send : ' + eventName); +}.bind(AssertPrototype); test("add error", function(assert) { assert.expect(6); - errors.trigger = becameInvalid; + errors.trigger = assert.becameInvalid; errors.add('firstName', 'error'); - errors.trigger = unexpectedSend; + errors.trigger = assert.unexpectedSend; assert.ok(errors.has('firstName'), 'it has firstName errors'); assert.equal(errors.get('length'), 1, 'it has 1 error'); errors.add('firstName', ['error1', 'error2']); @@ -51,9 +52,9 @@ test("add error", function(assert) { test("get error", function(assert) { assert.expect(8); assert.ok(errors.get('firstObject') === undefined, 'returns undefined'); - errors.trigger = becameInvalid; + errors.trigger = assert.becameInvalid; errors.add('firstName', 'error'); - errors.trigger = unexpectedSend; + errors.trigger = assert.unexpectedSend; assert.ok(errors.get('firstName').length === 1, 'returns errors'); assert.deepEqual(errors.get('firstObject'), { attribute: 'firstName', message: 'error' }); errors.add('firstName', 'error2'); @@ -73,11 +74,11 @@ test("get error", function(assert) { test("remove error", function(assert) { assert.expect(5); - errors.trigger = becameInvalid; + errors.trigger = assert.becameInvalid; errors.add('firstName', 'error'); - errors.trigger = becameValid; + errors.trigger = assert.becameValid; errors.remove('firstName'); - errors.trigger = unexpectedSend; + errors.trigger = assert.unexpectedSend; assert.ok(!errors.has('firstName'), 'it has no firstName errors'); assert.equal(errors.get('length'), 0, 'it has 0 error'); assert.ok(errors.get('isEmpty'), 'it is empty'); @@ -86,26 +87,26 @@ test("remove error", function(assert) { test("remove same errors from different attributes", function(assert) { assert.expect(5); - errors.trigger = becameInvalid; + errors.trigger = assert.becameInvalid; errors.add('firstName', 'error'); errors.add('lastName', 'error'); - errors.trigger = unexpectedSend; + errors.trigger = assert.unexpectedSend; assert.equal(errors.get('length'), 2, 'it has 2 error'); errors.remove('firstName'); assert.equal(errors.get('length'), 1, 'it has 1 error'); - errors.trigger = becameValid; + errors.trigger = assert.becameValid; errors.remove('lastName'); assert.ok(errors.get('isEmpty'), 'it is empty'); }); test("clear errors", function(assert) { assert.expect(5); - errors.trigger = becameInvalid; + errors.trigger = assert.becameInvalid; errors.add('firstName', ['error', 'error1']); assert.equal(errors.get('length'), 2, 'it has 2 errors'); - errors.trigger = becameValid; + errors.trigger = assert.becameValid; errors.clear(); - errors.trigger = unexpectedSend; + errors.trigger = assert.unexpectedSend; assert.ok(!errors.has('firstName'), 'it has no firstName errors'); assert.equal(errors.get('length'), 0, 'it has 0 error'); errors.clear(); diff --git a/tests/unit/model/internal-model-test.js b/tests/unit/model/internal-model-test.js index cde8daabb16..8a3c2a1b304 100644 --- a/tests/unit/model/internal-model-test.js +++ b/tests/unit/model/internal-model-test.js @@ -17,7 +17,7 @@ test("Materializing a model twice errors out", function(assert) { var internalModel = new DS.InternalModel(mockModelFactory, null, null, null); internalModel.materializeRecord(); - expectAssertion(function() { + assert.expectAssertion(function() { internalModel.materializeRecord(); }, /more than once/); }); diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index a3de93ebde4..6c9778d505a 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -1,3 +1,4 @@ +import {createStore} from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/unit/model/merge-test.js b/tests/unit/model/merge-test.js index 316e2744c55..4647f4b2cde 100644 --- a/tests/unit/model/merge-test.js +++ b/tests/unit/model/merge-test.js @@ -1,3 +1,4 @@ +import {createStore} from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -85,7 +86,7 @@ test("Make sure snapshot is created at save time not at flush time", function(as assert.equal(person.get('name'), "Tomasz Dale", "the local changes applied on top"); - promise.then(async(function(person) { + promise.then(assert.wait(function(person) { assert.equal(person.get('hasDirtyAttributes'), true, "The person is still dirty"); assert.equal(person.get('name'), "Tomasz Dale", "The local changes apply"); })); @@ -144,7 +145,7 @@ test("When a record is in flight, pushes are applied underneath the in flight ch assert.equal(person.get('name'), "Tomasz Dale", "the local changes applied on top"); assert.equal(person.get('city'), "PDX", "the pushed change is available"); - promise.then(async(function(person) { + promise.then(assert.wait(function(person) { assert.equal(person.get('hasDirtyAttributes'), true, "The person is still dirty"); assert.equal(person.get('name'), "Tomasz Dale", "The local changes apply"); assert.equal(person.get('city'), "Portland", "The updates from the server apply on top of the previous pushes"); diff --git a/tests/unit/model/relationships-test.js b/tests/unit/model/relationships-test.js index 0a71035d3da..6c8f833165b 100644 --- a/tests/unit/model/relationships-test.js +++ b/tests/unit/model/relationships-test.js @@ -1,3 +1,4 @@ +import {createStore} from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index d6772edcdff..4558faaf291 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -64,14 +65,14 @@ test("belongsTo lazily loads relationships as needed", function(assert) { }); run(function() { - store.findRecord('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { assert.equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); assert.equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); assert.equal(get(person, 'tag.name'), "friendly", "the tag shuld have name"); assert.strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); - asyncEqual(get(person, 'tag'), store.findRecord('tag', 5), "relationship object is the same as object retrieved directly"); + assert.asyncEqual(get(person, 'tag'), store.findRecord('tag', 5), "relationship object is the same as object retrieved directly"); })); }); }); @@ -104,13 +105,13 @@ test("async belongsTo relationships work when the data hash has not been loaded" }; run(function() { - store.findRecord('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { assert.equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return run(function() { return get(person, 'tag'); }); - })).then(async(function(tag) { + })).then(assert.wait(function(tag) { assert.equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); assert.equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); })); @@ -160,7 +161,7 @@ test("async belongsTo relationships work when the data hash has already been loa assert.equal(get(person, 'name'), "Tom Dale", "The person is now populated"); return run(function() { return get(person, 'tag'); - }).then(async(function(tag) { + }).then(assert.wait(function(tag) { assert.equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); assert.equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); })); @@ -189,7 +190,7 @@ test("calling createRecord and passing in an undefined value for a relationship }); run(function() { - store.findRecord('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { assert.strictEqual(person.get('tag'), null, "undefined values should return null relationships"); })); }); @@ -242,12 +243,12 @@ test("When finding a hasMany relationship the inverse belongsTo relationship is }); run(function() { - store.findRecord('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { assert.equal(get(person, 'isLoaded'), true, "isLoaded should be true"); assert.equal(get(person, 'name'), "Tom Dale", "the person is still Tom Dale"); return get(person, 'occupations'); - })).then(async(function(occupations) { + })).then(assert.wait(function(occupations) { assert.equal(get(occupations, 'length'), 2, "the list of occupations should have the correct length"); assert.equal(get(occupations.objectAt(0), 'description'), "fifth", "the occupation is the fifth"); @@ -358,14 +359,14 @@ test("belongsTo supports relationships to models with id 0", function(assert) { }); run(function() { - store.findRecord('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { assert.equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); assert.equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); assert.equal(get(person, 'tag.name'), "friendly", "the tag should have name"); assert.strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); - asyncEqual(get(person, 'tag'), store.findRecord('tag', 0), "relationship object is the same as object retrieved directly"); + assert.asyncEqual(get(person, 'tag'), store.findRecord('tag', 0), "relationship object is the same as object retrieved directly"); })); }); }); @@ -415,13 +416,13 @@ test("belongsTo gives a warning when provided with a serialize option", function }); }); - warns(function() { run(function() { - store.find('person', 1).then(async(function(person) { - get(person, 'hobby'); + store.find('person', 1).then(assert.wait(function(person) { + assert.warns(function() { + get(person, 'hobby'); + }, /You provided a serialize option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.Serializer and it's implementations/); })); }); - }, /You provided a serialize option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.Serializer and it's implementations/); }); test("belongsTo gives a warning when provided with an embedded option", function(assert) { @@ -469,13 +470,13 @@ test("belongsTo gives a warning when provided with an embedded option", function }); }); - warns(function() { run(function() { - store.find('person', 1).then(async(function(person) { + store.find('person', 1).then(assert.wait(function(person) { + assert.warns(function() { get(person, 'hobby'); + }, /You provided an embedded option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin/); })); }); - }, /You provided an embedded option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin/); }); test("DS.belongsTo should be async by default", function(assert) { diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index f1a919533b3..7904740ae67 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -15,6 +16,7 @@ module("unit/model/relationships - DS.hasMany", { }); test("hasMany handles pre-loaded relationships", function(assert) { + let done = assert.async(); assert.expect(13); var Tag = DS.Model.extend({ @@ -142,7 +144,7 @@ test("hasMany handles pre-loaded relationships", function(assert) { assert.equal(get(get(person, 'tags'), 'length'), 2, "the length is updated after new data is loaded"); assert.strictEqual(get(person, 'tags').objectAt(0), get(person, 'tags').objectAt(0), "the returned object is always the same"); - asyncEqual(get(person, 'tags').objectAt(0), store.findRecord('tag', 5), "relationship objects are the same as objects retrieved directly"); + assert.asyncEqual(get(person, 'tags').objectAt(0), store.findRecord('tag', 5), "relationship objects are the same as objects retrieved directly"); run(function() { store.push({ @@ -208,6 +210,7 @@ test("hasMany handles pre-loaded relationships", function(assert) { assert.equal(pets, get(cyvid, 'pets'), "a relationship returns the same object every time"); assert.equal(get(get(cyvid, 'pets'), 'length'), 2, "the length is updated after new data is loaded"); + done(); }); }); }); @@ -325,7 +328,7 @@ test("hasMany lazily loads async relationships", function(assert) { assert.equal(get(records.tags.objectAt(0), 'name'), "oohlala", "the first tag should be a Tag"); assert.strictEqual(records.tags.objectAt(0), records.tags.objectAt(0), "the returned object is always the same"); - asyncEqual(records.tags.objectAt(0), store.findRecord('tag', 12), "relationship objects are the same as objects retrieved directly"); + assert.asyncEqual(records.tags.objectAt(0), store.findRecord('tag', 12), "relationship objects are the same as objects retrieved directly"); return get(wycats, 'tags'); }).then(function(tags) { @@ -694,7 +697,7 @@ test("it is possible to remove an item from a relationship", function(assert) { }); run(function() { - store.findRecord('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { var tag = get(person, 'tags').objectAt(0); assert.equal(get(tag, 'name'), "ember", "precond - relationships work"); @@ -789,7 +792,7 @@ test("throws assertion if of not set with an array", function(assert) { }); run(function() { - expectAssertion(function() { + assert.expectAssertion(function() { tag.set('people', person); }, /You must pass an array of records to set a hasMany relationship/); }); @@ -818,7 +821,7 @@ test("checks if passed array only contains instances of DS.Model", function(asse }); run(function() { - expectAssertion(function() { + assert.expectAssertion(function() { tag.set('people', [person]); }, /All elements of a hasMany relationship must be instances of DS.Model/); }); diff --git a/tests/unit/model/relationships/record-array-test.js b/tests/unit/model/relationships/record-array-test.js index d9e8181b0a9..9ea9f467036 100644 --- a/tests/unit/model/relationships/record-array-test.js +++ b/tests/unit/model/relationships/record-array-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -87,7 +88,7 @@ test("can create child record from a hasMany relationship", function(assert) { }); run(function() { - store.findRecord('person', 1).then(async(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { person.get("tags").createRecord({ name: "cool" }); assert.equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index 177478cf56b..f9d77bdee3c 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -111,7 +112,7 @@ test("changes to attributes made after a record is in-flight only rolls back the assert.equal(person.get('lastName'), "Dale"); assert.equal(person.get('isSaving'), true); - saving.then(async(function() { + saving.then(assert.wait(function() { assert.equal(person.get('hasDirtyAttributes'), false, "The person is now clean"); })); }); @@ -239,7 +240,7 @@ test("invalid new record's attributes can be rollbacked", function(assert) { assert.equal(person.get('hasDirtyAttributes'), true, "must be dirty"); run(function() { - person.save().then(null, async(function() { + person.save().then(null, assert.wait(function() { assert.equal(person.get('isValid'), false); person.rollbackAttributes(); @@ -279,12 +280,12 @@ test("invalid record's attributes can be rollbacked after multiple failed calls run(function() { assert.equal(person.get('firstName'), 'updated name', "precondition: firstName is changed"); - person.save().then(null, async(function() { + person.save().then(null, assert.wait(function() { assert.equal(person.get('hasDirtyAttributes'), true, "has dirty attributes"); assert.equal(person.get('firstName'), 'updated name', "firstName is still changed"); return person.save(); - })).then(null, async(function() { + })).then(null, assert.wait(function() { person.rollbackAttributes(); assert.equal(person.get('hasDirtyAttributes'), false, "has no dirty attributes"); @@ -370,7 +371,7 @@ test("invalid record's attributes can be rollbacked", function(assert) { } }); - dog.save().then(null, async(function() { + dog.save().then(null, assert.wait(function() { dog.rollbackAttributes(); assert.equal(dog.get('hasDirtyAttributes'), false, "must not be dirty"); @@ -424,7 +425,7 @@ test("invalid record's attributes rolled back to correct state after set", funct assert.ok(true, 'errors.name did change'); }); - dog.save().then(null, async(function() { + dog.save().then(null, assert.wait(function() { assert.equal(dog.get('name'), "is a dwarf planet"); assert.equal(dog.get('breed'), "planet"); assert.ok(Ember.isPresent(dog.get('errors.name'))); @@ -484,7 +485,7 @@ test("when destroying a record setup the record state to invalid, the record's a }); run(function() { - dog.destroyRecord().then(null, async(function() { + dog.destroyRecord().then(null, assert.wait(function() { assert.equal(dog.get('isError'), false, "must not be error"); diff --git a/tests/unit/record-array-test.js b/tests/unit/record-array-test.js index cc29a49a918..f2098914034 100644 --- a/tests/unit/record-array-test.js +++ b/tests/unit/record-array-test.js @@ -1,3 +1,5 @@ +import {createStore} from 'dummy/tests/helpers/store'; +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/unit/states-test.js b/tests/unit/states-test.js index 5631e9c9c26..5bd10b50f3a 100644 --- a/tests/unit/states-test.js +++ b/tests/unit/states-test.js @@ -1,9 +1,9 @@ import Ember from 'ember'; - -import {module, test} from 'qunit'; - +import QUnit, {module, test} from 'qunit'; import DS from 'ember-data'; +const {assert} = QUnit; + var get = Ember.get; var rootState, stateName; @@ -14,82 +14,82 @@ module("unit/states - Flags for record states", { } }); -var isTrue = function(flag) { - assert.equal(get(rootState, stateName + "." + flag), true, stateName + "." + flag + " should be true"); +assert.flagIsTrue = function flagIsTrue(flag) { + this.equal(get(rootState, stateName + "." + flag), true, stateName + "." + flag + " should be true"); }; -var isFalse = function(flag) { - assert.equal(get(rootState, stateName + "." + flag), false, stateName + "." + flag + " should be false"); +assert.flagIsFalse = function flagIsFalse(flag) { + this.equal(get(rootState, stateName + "." + flag), false, stateName + "." + flag + " should be false"); }; test("the empty state", function(assert) { stateName = "empty"; - isFalse("isLoading"); - isFalse("isLoaded"); - isFalse("isDirty"); - isFalse("isSaving"); - isFalse("isDeleted"); + assert.flagIsFalse("isLoading"); + assert.flagIsFalse("isLoaded"); + assert.flagIsFalse("isDirty"); + assert.flagIsFalse("isSaving"); + assert.flagIsFalse("isDeleted"); }); test("the loading state", function(assert) { stateName = "loading"; - isTrue("isLoading"); - isFalse("isLoaded"); - isFalse("isDirty"); - isFalse("isSaving"); - isFalse("isDeleted"); + assert.flagIsTrue("isLoading"); + assert.flagIsFalse("isLoaded"); + assert.flagIsFalse("isDirty"); + assert.flagIsFalse("isSaving"); + assert.flagIsFalse("isDeleted"); }); test("the loaded state", function(assert) { stateName = "loaded"; - isFalse("isLoading"); - isTrue("isLoaded"); - isFalse("isDirty"); - isFalse("isSaving"); - isFalse("isDeleted"); + assert.flagIsFalse("isLoading"); + assert.flagIsTrue("isLoaded"); + assert.flagIsFalse("isDirty"); + assert.flagIsFalse("isSaving"); + assert.flagIsFalse("isDeleted"); }); test("the updated state", function(assert) { stateName = "loaded.updated"; - isFalse("isLoading"); - isTrue("isLoaded"); - isTrue("isDirty"); - isFalse("isSaving"); - isFalse("isDeleted"); + assert.flagIsFalse("isLoading"); + assert.flagIsTrue("isLoaded"); + assert.flagIsTrue("isDirty"); + assert.flagIsFalse("isSaving"); + assert.flagIsFalse("isDeleted"); }); test("the saving state", function(assert) { stateName = "loaded.updated.inFlight"; - isFalse("isLoading"); - isTrue("isLoaded"); - isTrue("isDirty"); - isTrue("isSaving"); - isFalse("isDeleted"); + assert.flagIsFalse("isLoading"); + assert.flagIsTrue("isLoaded"); + assert.flagIsTrue("isDirty"); + assert.flagIsTrue("isSaving"); + assert.flagIsFalse("isDeleted"); }); test("the deleted state", function(assert) { stateName = "deleted"; - isFalse("isLoading"); - isTrue("isLoaded"); - isTrue("isDirty"); - isFalse("isSaving"); - isTrue("isDeleted"); + assert.flagIsFalse("isLoading"); + assert.flagIsTrue("isLoaded"); + assert.flagIsTrue("isDirty"); + assert.flagIsFalse("isSaving"); + assert.flagIsTrue("isDeleted"); }); test("the deleted.saving state", function(assert) { stateName = "deleted.inFlight"; - isFalse("isLoading"); - isTrue("isLoaded"); - isTrue("isDirty"); - isTrue("isSaving"); - isTrue("isDeleted"); + assert.flagIsFalse("isLoading"); + assert.flagIsTrue("isLoaded"); + assert.flagIsTrue("isDirty"); + assert.flagIsTrue("isSaving"); + assert.flagIsTrue("isDeleted"); }); test("the deleted.saved state", function(assert) { stateName = "deleted.saved"; - isFalse("isLoading"); - isTrue("isLoaded"); - isFalse("isDirty"); - isFalse("isSaving"); - isTrue("isDeleted"); + assert.flagIsFalse("isLoading"); + assert.flagIsTrue("isLoaded"); + assert.flagIsFalse("isDirty"); + assert.flagIsFalse("isSaving"); + assert.flagIsTrue("isDeleted"); }); diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index 5b5428201bb..9bdff260cbb 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -1,3 +1,5 @@ +import {createStore} from 'dummy/tests/helpers/store'; +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -42,11 +44,12 @@ test('Adapter can not be set as an instance', function(assert) { store = DS.Store.create({ adapter: DS.Adapter.create() }); - expectAssertion(() => store.get('defaultAdapter')); + assert.expectAssertion(() => store.get('defaultAdapter')); }); test("Calling Store#find invokes its adapter#find", function(assert) { assert.expect(5); + let done = assert.async(); var adapter = TestAdapter.extend({ findRecord: function(store, type, id, snapshot) { @@ -65,19 +68,19 @@ test("Calling Store#find invokes its adapter#find", function(assert) { run(function() { - currentStore.findRecord('test', 1); + currentStore.findRecord('test', 1).finally(done); }); }); test("Calling Store#findRecord multiple times coalesces the calls into a adapter#findMany call", function(assert) { assert.expect(2); + let done = assert.async(); var adapter = TestAdapter.extend({ findRecord: function(store, type, id, snapshot) { assert.ok(false, "Adapter#findRecord was not called"); }, findMany: function(store, type, ids, snapshots) { - start(); assert.ok(true, "Adapter#findMany was called"); assert.deepEqual(ids, ["1","2"], 'Correct ids were passed in to findMany'); return Ember.RSVP.resolve([{ id: 1 }, { id: 2 }]); @@ -88,10 +91,12 @@ test("Calling Store#findRecord multiple times coalesces the calls into a adapter var currentType = DS.Model.extend(); var currentStore = createStore({ adapter: adapter, test: currentType }); - stop(); run(function() { - currentStore.findRecord('test', 1); - currentStore.findRecord('test', 2); + let promises = [ + currentStore.findRecord('test', 1), + currentStore.findRecord('test', 2) + ]; + Ember.RSVP.all(promises).finally(done); }); }); @@ -110,7 +115,7 @@ test("Returning a promise from `findRecord` asynchronously loads data", function var currentStore = createStore({ adapter: adapter, test: currentType }); run(function() { - currentStore.findRecord('test', 1).then(async(function(object) { + currentStore.findRecord('test', 1).then(assert.wait(function(object) { assert.strictEqual(get(object, 'name'), "Scumbag Dale", "the data was pushed"); })); }); @@ -132,7 +137,7 @@ test("IDs provided as numbers are coerced to strings", function(assert) { var currentStore = createStore({ adapter: adapter, test: currentType }); run(function() { - currentStore.findRecord('test', 1).then(async(function(object) { + currentStore.findRecord('test', 1).then(assert.wait(function(object) { assert.equal(typeof object.get('id'), 'string', "id was coerced to a string"); run(function() { currentStore.push({ @@ -146,7 +151,7 @@ test("IDs provided as numbers are coerced to strings", function(assert) { }); }); return currentStore.findRecord('test', 2); - })).then(async(function(object) { + })).then(assert.wait(function(object) { assert.ok(object, "object was found"); assert.equal(typeof object.get('id'), 'string', "id is a string despite being supplied and searched for as a number"); })); @@ -178,7 +183,7 @@ test("can load data for the same record if it is not dirty", function(assert) { } }); - store.findRecord('person', 1).then(async(function(tom) { + store.findRecord('person', 1).then(assert.wait(function(tom) { assert.equal(get(tom, 'hasDirtyAttributes'), false, "precond - record is not dirty"); assert.equal(get(tom, 'name'), "Tom Dale", "returns the correct name"); @@ -357,7 +362,7 @@ test("a new record with a specific id can't be created if this id is already use store.createRecord('person', { id: 5 }); }); - expectAssertion(function() { + assert.expectAssertion(function() { run(function() { store.createRecord('person', { id: 5 }); }); @@ -400,7 +405,7 @@ test("if an id is supplied in the initial data hash, it can be looked up using ` run(function() { person = store.createRecord('person', { id: 1, name: "Brohuda Katz" }); - store.findRecord('person', 1).then(async(function(again) { + store.findRecord('person', 1).then(assert.wait(function(again) { assert.strictEqual(person, again, "the store returns the loaded object"); })); }); @@ -489,8 +494,8 @@ test("initial values of belongsTo can be passed in as the third argument to find env.registry.register('model:person', Person); run(function() { - store.findRecord('person', 1, { preload: { friend: 2 } }).then(async(function() { - store.peekRecord('person', 1).get('friend').then(async(function(friend) { + store.findRecord('person', 1, { preload: { friend: 2 } }).then(assert.wait(function() { + store.peekRecord('person', 1).get('friend').then(assert.wait(function(friend) { assert.equal(friend.get('id'), '2', 'Preloaded belongsTo set'); })); })); @@ -589,7 +594,7 @@ test("records should have their ids updated when the adapter returns the id data }); run(function() { - Ember.RSVP.all([tom.save(), yehuda.save()]).then(async(function() { + Ember.RSVP.all([tom.save(), yehuda.save()]).then(assert.wait(function() { people.forEach(function(person, index) { assert.equal(person.get('id'), index + 1, "The record's id should be correct."); }); @@ -617,7 +622,7 @@ test("store.fetchMany should always return a promise", function(assert) { assert.ok(results, "A call to store.scheduleFetchMany() should return a result"); assert.ok(results.then, "A call to store.scheduleFetchMany() should return a promise"); - results.then(async(function(returnedRecords) { + results.then(assert.wait(function(returnedRecords) { assert.deepEqual(returnedRecords, [], "The correct records are returned"); })); }); @@ -673,7 +678,7 @@ test("store.scheduleFetchMany should not resolve until all the records are resol ]); run(function() { - store.scheduleFetchMany(records).then(async(function() { + store.scheduleFetchMany(records).then(assert.wait(function() { var unloadedRecords = records.filterBy('isEmpty'); assert.equal(get(unloadedRecords, 'length'), 0, 'All unloaded records should be loaded'); })); @@ -723,7 +728,7 @@ test("the store calls adapter.findMany according to groupings returned by adapte ]); run(function() { - store.scheduleFetchMany(records).then(async(function() { + store.scheduleFetchMany(records).then(assert.wait(function() { var ids = records.mapBy('id'); assert.deepEqual(ids, ["10", "20", "21"], "The promise fulfills with the records"); })); @@ -769,11 +774,11 @@ test("the promise returned by `scheduleFetch`, when it resolves, does not depend var davidPromise = store.findRecord('test', 'david'); var igorPromise = store.findRecord('test', 'igor'); - igorPromise.then(async(function () { + igorPromise.then(assert.wait(function () { assert.equal(davidResolved, false, "Igor did not need to wait for David"); })); - davidPromise.then(async(function () { + davidPromise.then(assert.wait(function () { assert.equal(davidResolved, true, "David resolved"); })); }); @@ -818,11 +823,11 @@ test("the promise returned by `scheduleFetch`, when it rejects, does not depend var davidPromise = store.findRecord('test', 'david'); var igorPromise = store.findRecord('test', 'igor'); - igorPromise.then(null, async(function () { + igorPromise.then(null, assert.wait(function () { assert.equal(davidResolved, false, "Igor did not need to wait for David"); })); - davidPromise.then(async(function () { + davidPromise.then(assert.wait(function () { assert.equal(davidResolved, true, "David resolved"); })); }); @@ -852,20 +857,22 @@ test("store.fetchRecord reject records that were not found, even when those requ test: Person }); - warns(function() { + let done = assert.async(); + assert.warns(function() { run(function () { var davidPromise = store.findRecord('test', 'david'); var igorPromise = store.findRecord('test', 'igor'); - davidPromise.then(async(function () { + davidPromise.then(assert.wait(function () { assert.ok(true, "David resolved"); })); - igorPromise.then(null, async(function () { + igorPromise.then(null, assert.wait(function () { assert.ok(true, "Igor rejected"); })); }); }, /expected to find records with the following ids in the adapter response but they were missing/); + done(); }); test("store should not call shouldReloadRecord when the record is not in the store", function(assert) { @@ -1253,7 +1260,7 @@ test("store should assert of the user tries to call store.filter", function(asse person: Person }); - expectAssertion(function() { + assert.expectAssertion(function() { run(function() { store.filter('person', {}); }); @@ -1270,7 +1277,7 @@ test("Calling adapterFor with a model class should assert", function(assert) { person: Person }); - expectAssertion(function() { + assert.expectAssertion(function() { store.adapterFor(Person); }, /Passing classes to store.adapterFor has been removed/); }); diff --git a/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js index 9f1f40fc801..c276ca82789 100644 --- a/tests/unit/store/create-record-test.js +++ b/tests/unit/store/create-record-test.js @@ -1,7 +1,7 @@ +import {createStore} from 'dummy/tests/helpers/store'; +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; - import {module, test} from 'qunit'; - import DS from 'ember-data'; var store, container, Record, Storage; diff --git a/tests/unit/store/has-record-for-id-test.js b/tests/unit/store/has-record-for-id-test.js index ba44d2016e4..027f453a844 100644 --- a/tests/unit/store/has-record-for-id-test.js +++ b/tests/unit/store/has-record-for-id-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/unit/store/lookup-test.js b/tests/unit/store/lookup-test.js index cef75d82851..a8820d59174 100644 --- a/tests/unit/store/lookup-test.js +++ b/tests/unit/store/lookup-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -57,26 +58,26 @@ module('unit/store/lookup - Managed Instance lookups', { } }); -test('when the adapter does not exist for a type, the fallback is returned', () => { +test('when the adapter does not exist for a type, the fallback is returned', (assert) => { let personAdapter = lookupAdapter('person'); assert.strictEqual(personAdapter, applicationAdapter); }); -test('when the adapter for a type exists, returns that instead of the fallback', () => { +test('when the adapter for a type exists, returns that instead of the fallback', (assert) => { registerAdapter('person', DS.Adapter.extend()); let personAdapter = lookupAdapter('person'); assert.ok(personAdapter !== applicationAdapter); }); -test('when the serializer does not exist for a type, the fallback is returned', () => { +test('when the serializer does not exist for a type, the fallback is returned', (assert) => { let personSerializer = lookupSerializer('person'); assert.strictEqual(personSerializer, applicationSerializer); }); -test('when the serializer does exist for a type, the serializer is returned', () => { +test('when the serializer does exist for a type, the serializer is returned', (assert) => { registerSerializer('person', DS.Serializer.extend()); let personSerializer = lookupSerializer('person'); @@ -84,7 +85,7 @@ test('when the serializer does exist for a type, the serializer is returned', () assert.ok(personSerializer !== applicationSerializer); }); -test('adapter lookup order', () => { +test('adapter lookup order', (assert) => { assert.expect(3); resetStore(); @@ -107,7 +108,7 @@ test('adapter lookup order', () => { assert.ok(lookupAdapter('person').get('customThingy'), 'looks up type serializer before application'); }); -test('serializer lookup order', () => { +test('serializer lookup order', (assert) => { resetStore(); let personSerializer = lookupSerializer('person'); diff --git a/tests/unit/store/model-for-test.js b/tests/unit/store/model-for-test.js index 0571fe9ae7a..82688cc6955 100644 --- a/tests/unit/store/model-for-test.js +++ b/tests/unit/store/model-for-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/unit/store/peek-record-test.js b/tests/unit/store/peek-record-test.js index ade7816b627..6586755b20a 100644 --- a/tests/unit/store/peek-record-test.js +++ b/tests/unit/store/peek-record-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index 4266a805d9b..5ce830246a9 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -113,7 +114,7 @@ test("Calling push triggers `didLoad` even if the record hasn't been requested f assert.expect(1); Person.reopen({ - didLoad: async(function() { + didLoad: assert.wait(function() { assert.ok(true, "The didLoad callback was called"); }) }); @@ -449,7 +450,7 @@ test('Calling push with a link for a non async relationship should warn', functi phoneNumbers: hasMany('phone-number', { async: false }) }); - warns(function() { + assert.warns(function() { run(function() { store.push(store.normalize('person', { id: '1', @@ -463,7 +464,7 @@ test('Calling push with a link for a non async relationship should warn', functi test('Calling push with an unknown model name throws an assertion error', function(assert) { - expectAssertion(function() { + assert.expectAssertion(function() { run(function() { store.push({ data: { @@ -586,7 +587,7 @@ test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown keys", f var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; try { Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; - warns(function() { + assert.warns(function() { store.push({ data: { type: 'person', @@ -606,7 +607,7 @@ test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown keys", f }); test("Calling push with unknown keys should not warn by default", function(assert) { - noWarns(function() { + assert.noWarns(function() { run(function() { store.push({ data: { diff --git a/tests/unit/store/serializer-for-test.js b/tests/unit/store/serializer-for-test.js index b11570eaf55..3126bbfb623 100644 --- a/tests/unit/store/serializer-for-test.js +++ b/tests/unit/store/serializer-for-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -45,7 +46,7 @@ test("Calling serializerFor with a type that has not been registered and in an a }); test("Calling serializerFor with a model class should assert", function(assert) { - expectAssertion(function() { + assert.expectAssertion(function() { store.serializerFor(Person); }, /Passing classes to store.serializerFor has been removed/); }); diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index 9b46738f3c2..5a4cd1796cd 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -1,3 +1,4 @@ +import {createStore} from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -51,7 +52,7 @@ test("unload a dirty record", function(assert) { assert.equal(get(record, 'hasDirtyAttributes'), true, "record is dirty"); - expectAssertion(function() { + assert.expectAssertion(function() { record.unloadRecord(); }, "You can only unload a record which is not inFlight. `" + Ember.inspect(record) + "`", "can not unload dirty record"); diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index 8776f9c5df0..964eb6013c5 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -1,3 +1,4 @@ +import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -85,7 +86,7 @@ test("assertPolymorphicType works for subclasses", function(assert) { assert.ok(false, "should not throw an error"); } - expectAssertion(function() { + assert.expectAssertion(function() { Ember.run(function() { user.get('messages').addObject(person); }); @@ -151,7 +152,7 @@ test("assertPolymorphicType works for mixins", function(assert) { assert.ok(false, "should not throw an error"); } - expectAssertion(function() { + assert.expectAssertion(function() { Ember.run(function() { post.get('medias').addObject(person); }); From e053e6c0e69c5d893f8169bc3d773dd082948b91 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 5 Nov 2015 19:05:17 -0600 Subject: [PATCH 1201/2527] remove canary/beta tasks in favor of ember-try --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 84d2b30af73..7a547f9a4eb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,6 @@ install: script: - ./bin/lint-features - npm run-script test - - npm run-script test:beta - - npm run-script test:canary - - npm run-script test:optional-features after_success: - npm run-script publish-build:prebuilt - "./bin/bower-ember-data-build" From c7c50396edbb14955fe47076474d54575d8403f8 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 5 Nov 2015 22:20:48 -0600 Subject: [PATCH 1202/2527] fix bower related build issues in .travis.yml --- .bowerrc | 3 ++- .travis.yml | 1 + package.json | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.bowerrc b/.bowerrc index 69fad358018..869443b22d5 100644 --- a/.bowerrc +++ b/.bowerrc @@ -1,3 +1,4 @@ { - "directory": "bower_components" + "directory": "bower_components", + "interactive": false } diff --git a/.travis.yml b/.travis.yml index 7a547f9a4eb..7b38b948104 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,7 @@ before_install: - "npm install -g npm@^2" install: - npm install --no-optional + - ./node_modules/.bin/bower install script: - ./bin/lint-features - npm run-script test diff --git a/package.json b/package.json index fdc62459d1a..deb47bbde7e 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "author": "", "license": "MIT", "devDependencies": { + "bower": "^1.6.5", "broccoli-asset-rev": "^2.1.2", "ember-cli": "1.13.8", "ember-cli-app-version": "0.5.0", From e1d8b41f5c13f955d03218904ebd759d242bff01 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 5 Nov 2015 22:23:38 -0600 Subject: [PATCH 1203/2527] node can't use `const` --- config/environment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/environment.js b/config/environment.js index 5f801651e2a..80369f82b6c 100644 --- a/config/environment.js +++ b/config/environment.js @@ -1,7 +1,7 @@ 'use strict'; module.exports = function(environment, appConfig) { - const ENV = { }; + var ENV = { }; if (environment === 'testing') { ENV.EmberENV = { From 8011a0484f483cad26d7c2a1c5ba2774a24d0488 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 5 Nov 2015 22:34:09 -0600 Subject: [PATCH 1204/2527] use trusty beta environment to get phantomJS 2.0 --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7b38b948104..3a5624b13c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ --- language: node_js -sudo: false +sudo: required +dist: trusty node_js: - "0.10" before_install: From ea81afceec75110bded725977f62620c43064a56 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 5 Nov 2015 22:51:13 -0600 Subject: [PATCH 1205/2527] attempt to fix appveyor --- appveyor.yml | 2 +- package.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 59cb843ce25..8adf7c8dcb2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,7 +25,7 @@ install: - npm config set cache C:\nc - npm version - npm install --no-optional - + - npm run bower # Post-install test scripts. test_script: # Output useful info for debugging. diff --git a/package.json b/package.json index deb47bbde7e..8b2336fdf32 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "scripts": { "build": "ember build", "start": "ember server", - "test": "ember try:testall" + "test": "ember try:testall", + "bower": "bower install" }, "repository": "", "engines": { From d654d0db92b1bc5cb2ef371e6d8909d387afeb9d Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 5 Nov 2015 23:40:20 -0600 Subject: [PATCH 1206/2527] install phantomJS 2 on appveyor --- appveyor.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 8adf7c8dcb2..eb67ab5838a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,9 +14,8 @@ install: # Get the latest stable version of Node 0.STABLE.latest - ps: Install-Product node $env:nodejs_version # Install PhantomJS - - cinst PhantomJS -Version 1.9.8 - - set path=%path%;C:\tools\PhantomJS\ - - dir C:\tools\PhantomJS + - choco install phantomjs --version 2.0.0 -y + - set path=%path%;C:\ProgramData\chocolatey\lib\PhantomJS\tools\ # Typical npm stuff. - md C:\nc - npm install -g npm@^2 @@ -32,9 +31,6 @@ test_script: - npm version - npm run build - cmd: npm run test - - cmd: npm run test:beta - - cmd: npm run test:canary - - cmd: npm run test:optional-features # Don't actually build. build: off From 969fddc77ce371c29c4c7309ae5e1dea1b1eda00 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 10 Nov 2015 00:39:56 -0500 Subject: [PATCH 1207/2527] Use public API for container/registry when possible. Ember 2.3 will include `Ember.getOwner` and `Ember.setOwner` as public API's to access various registry and container features. As of Ember 2.3, using `this.container` in any instance looked up from the container will issue a deprecation (instructing the user to use `Ember.getOwner(this)` instead). This PR fixes all deprecations against ember#canary channel by adding a simplified polyfill so that the internal code can always operate with the `Ember.getOwner` API. --- .../lib/serializers/json-serializer.js | 8 ++++- .../lib/system/model/internal-model.js | 23 ++++++++++--- packages/ember-data/lib/system/model/model.js | 19 +++++++++++ packages/ember-data/lib/system/store.js | 22 +++++++++---- .../system/store/container-instance-cache.js | 10 +++--- packages/ember-data/lib/utils.js | 32 ++++++++++++++++++- .../tests/unit/model/internal-model-test.js | 14 ++++---- .../tests/unit/store/model-for-test.js | 2 +- .../tests/unit/store/serializer-for-test.js | 2 +- tests/ember-configuration.js | 26 +++++++++++++-- 10 files changed, 128 insertions(+), 30 deletions(-) diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index d3480799b58..599bccfa067 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -3,6 +3,10 @@ import coerceId from "ember-data/system/coerce-id"; import normalizeModelName from "ember-data/system/normalize-model-name"; import { modelHasAttributeOrRelationshipNamedType } from "ember-data/utils"; +import { + getOwner +} from 'ember-data/utils'; + import { errorsArrayToHash } from "ember-data/adapters/errors"; var get = Ember.get; @@ -1366,8 +1370,10 @@ export default Serializer.extend({ @return {DS.Transform} transform */ transformFor: function(attributeType, skipAssertion) { - var transform = this.container.lookup('transform:' + attributeType); + var transform = getOwner(this).lookup('transform:' + attributeType); + Ember.assert("Unable to find transform for '" + attributeType + "'", skipAssertion || !!transform); + return transform; } }); diff --git a/packages/ember-data/lib/system/model/internal-model.js b/packages/ember-data/lib/system/model/internal-model.js index b10e0f3e38e..e8a30f7a9b2 100644 --- a/packages/ember-data/lib/system/model/internal-model.js +++ b/packages/ember-data/lib/system/model/internal-model.js @@ -4,6 +4,10 @@ import Relationships from "ember-data/system/relationships/state/create"; import Snapshot from "ember-data/system/snapshot"; import EmptyObject from "ember-data/system/empty-object"; +import { + getOwner +} from 'ember-data/utils'; + var Promise = Ember.RSVP.Promise; var get = Ember.get; var set = Ember.set; @@ -46,11 +50,10 @@ var guid = 0; @class InternalModel */ -export default function InternalModel(type, id, store, container, data) { +export default function InternalModel(type, id, store, _, data) { this.type = type; this.id = id; this.store = store; - this.container = container; this._data = data || new EmptyObject(); this.modelName = type.modelName; this.dataHasInitialized = false; @@ -110,17 +113,27 @@ InternalModel.prototype = { constructor: InternalModel, materializeRecord: function() { Ember.assert("Materialized " + this.modelName + " record with id:" + this.id + "more than once", this.record === null || this.record === undefined); + // lookupFactory should really return an object that creates // instances with the injections applied - this.record = this.type._create({ + var createOptions = { store: this.store, - container: this.container, _internalModel: this, id: this.id, currentState: get(this, 'currentState'), isError: this.isError, adapterError: this.error - }); + }; + + if (Ember.setOwner) { + // ensure that `Ember.getOwner(this)` works inside a model instance + Ember.setOwner(createOptions, getOwner(this.store)); + } else { + createOptions.container = this.store.container; + } + + this.record = this.type._create(createOptions); + this._triggerDeferredTriggers(); }, diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 1438005ceb9..ef8971d6ae9 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -843,4 +843,23 @@ Model.reopenClass({ modelName: null }); +// if `Ember.setOwner` is defined, accessing `this.container` is +// deprecated (but functional). In "standard" Ember usage, this +// deprecation is actually created via an `.extend` of the factory +// inside the container itself, but that only happens on models +// with MODEL_FACTORY_INJECTIONS enabled :( +if (Ember.setOwner) { + Object.defineProperty(Model.prototype, 'container', { + configurable: true, + enumerable: false, + get() { + Ember.deprecate('Using the injected `container` is deprecated. Please use the `getOwner` helper instead to access the owner of this object.', + false, + { id: 'ember-application.injected-container', until: '3.0.0' }); + + return this.store.container; + } + }); +} + export default Model; diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 3a912f488aa..baa97c34ec4 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -40,6 +40,10 @@ import { _queryRecord } from "ember-data/system/store/finders"; +import { + getOwner +} from 'ember-data/utils'; + import coerceId from "ember-data/system/coerce-id"; import RecordArrayManager from "ember-data/system/record-array-manager"; @@ -220,7 +224,7 @@ Store = Service.extend({ store: this }); this._pendingSave = []; - this._instanceCache = new ContainerInstanceCache(this.container); + this._instanceCache = new ContainerInstanceCache(getOwner(this)); //Used to keep track of all the find requests that need to be coalesced this._pendingFetch = Map.create(); }, @@ -1475,11 +1479,12 @@ Store = Service.extend({ // container.registry = 2.1 // container._registry = 1.11 - 2.0 // container = < 1.11 - var registry = this.container.registry || this.container._registry || this.container; - var mixin = this.container.lookupFactory('mixin:' + normalizedModelName); + var owner = getOwner(this); + + var mixin = owner._lookupFactory('mixin:' + normalizedModelName); if (mixin) { //Cache the class as a model - registry.register('model:' + normalizedModelName, DS.Model.extend(mixin)); + owner.register('model:' + normalizedModelName, DS.Model.extend(mixin)); } var factory = this.modelFactoryFor(normalizedModelName); if (factory) { @@ -1518,7 +1523,10 @@ Store = Service.extend({ modelFactoryFor: function(modelName) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var normalizedKey = normalizeModelName(modelName); - return this.container.lookupFactory('model:' + normalizedKey); + + var owner = getOwner(this); + + return owner._lookupFactory('model:' + normalizedKey); }, /** @@ -1701,7 +1709,7 @@ Store = Service.extend({ }, _hasModelFor: function(type) { - return this.container.lookupFactory(`model:${type}`); + return getOwner(this)._lookupFactory(`model:${type}`); }, _pushInternalModel: function(data) { @@ -1867,7 +1875,7 @@ Store = Service.extend({ // lookupFactory should really return an object that creates // instances with the injections applied - var internalModel = new InternalModel(type, id, this, this.container, data); + var internalModel = new InternalModel(type, id, this, null, data); // if we're creating an item, this process will be done // later, once the object has been persisted. diff --git a/packages/ember-data/lib/system/store/container-instance-cache.js b/packages/ember-data/lib/system/store/container-instance-cache.js index 4f910314527..6dff1d2a348 100644 --- a/packages/ember-data/lib/system/store/container-instance-cache.js +++ b/packages/ember-data/lib/system/store/container-instance-cache.js @@ -19,9 +19,9 @@ import EmptyObject from "ember-data/system/empty-object"; * @class ContainerInstanceCache * */ -export default function ContainerInstanceCache(container) { - this._container = container; - this._cache = new EmptyObject(); +export default function ContainerInstanceCache(owner) { + this._owner = owner; + this._cache = new EmptyObject(); } ContainerInstanceCache.prototype = new EmptyObject(); @@ -55,7 +55,7 @@ Ember.merge(ContainerInstanceCache.prototype, { instanceFor: function(key) { let cache = this._cache; if (!cache[key]) { - let instance = this._container.lookup(key); + let instance = this._owner.lookup(key); if (instance) { cache[key] = instance; } @@ -74,7 +74,7 @@ Ember.merge(ContainerInstanceCache.prototype, { cacheEntry.destroy(); } } - this._container = null; + this._owner = null; }, constructor: ContainerInstanceCache, diff --git a/packages/ember-data/lib/utils.js b/packages/ember-data/lib/utils.js index b31e9262d10..107f3144341 100644 --- a/packages/ember-data/lib/utils.js +++ b/packages/ember-data/lib/utils.js @@ -54,7 +54,37 @@ function modelHasAttributeOrRelationshipNamedType(modelClass) { return get(modelClass, 'attributes').has('type') || get(modelClass, 'relationshipsByName').has('type'); } +/* + ember-container-inject-owner is a new feature in Ember 2.3 that finally provides a public + API for looking items up. This function serves as a super simple polyfill to avoid + triggering deprecations. +*/ +function getOwner(context) { + var owner; + + if (Ember.getOwner) { + owner = Ember.getOwner(context); + } + + if (!owner && context.container) { + owner = context.container; + } + + if (owner && owner.lookupFactory && !owner._lookupFactory) { + // `owner` is a container, we are just making this work + owner._lookupFactory = owner.lookupFactory; + owner.register = function() { + var registry = owner.registry || owner._registry || owner; + + return registry.register(...arguments); + }; + } + + return owner; +} + export { assertPolymorphicType, - modelHasAttributeOrRelationshipNamedType + modelHasAttributeOrRelationshipNamedType, + getOwner }; diff --git a/packages/ember-data/tests/unit/model/internal-model-test.js b/packages/ember-data/tests/unit/model/internal-model-test.js index 5e81ff5ab17..379d147e5aa 100644 --- a/packages/ember-data/tests/unit/model/internal-model-test.js +++ b/packages/ember-data/tests/unit/model/internal-model-test.js @@ -1,16 +1,16 @@ module("unit/model/internal-model - Internal Model"); -var mockModelFactory = { - _create: function() { - return { trigger: function() {} }; - }, +function MockModelFactory () { } - eachRelationship: function() { - } +MockModelFactory._create = function() { + return { trigger: function() {} }; }; + +MockModelFactory.eachRelationship = function() { }; + test("Materializing a model twice errors out", function() { expect(1); - var internalModel = new DS.InternalModel(mockModelFactory, null, null, null); + var internalModel = new DS.InternalModel(MockModelFactory, null, { }, null); internalModel.materializeRecord(); expectAssertion(function() { diff --git a/packages/ember-data/tests/unit/store/model-for-test.js b/packages/ember-data/tests/unit/store/model-for-test.js index c2c117fba91..eadca2207ee 100644 --- a/packages/ember-data/tests/unit/store/model-for-test.js +++ b/packages/ember-data/tests/unit/store/model-for-test.js @@ -13,7 +13,7 @@ module("unit/store/model_for - DS.Store#modelFor", { "blog.post": DS.Model.extend() }); store = env.store; - container = store.container; + container = env.container; registry = env.registry; }, diff --git a/packages/ember-data/tests/unit/store/serializer-for-test.js b/packages/ember-data/tests/unit/store/serializer-for-test.js index c525782cd00..58c1960bc5a 100644 --- a/packages/ember-data/tests/unit/store/serializer-for-test.js +++ b/packages/ember-data/tests/unit/store/serializer-for-test.js @@ -6,7 +6,7 @@ module("unit/store/serializer_for - DS.Store#serializerFor", { Person = DS.Model.extend({}); var env = setupStore({ person: Person }); store = env.store; - container = store.container; + container = env.container; registry = env.registry; }, diff --git a/tests/ember-configuration.js b/tests/ember-configuration.js index ad317c1bcdf..08485605455 100644 --- a/tests/ember-configuration.js +++ b/tests/ember-configuration.js @@ -17,6 +17,8 @@ ENV['ENABLE_OPTIONAL_FEATURES'] = !!QUnit.urlParams.enableoptionalfeatures; ENV['RAISE_ON_DEPRECATION'] = true; + var Owner; + window.async = function(callback, timeout) { var timer; stop(); @@ -52,13 +54,33 @@ }; window.setupStore = function(options) { - var container, registry; + var container, registry, owner; var env = {}; options = options || {}; + // This is done once upon first setupStore call (we cannot do it eagerly + // because this file is loaded before Ember itself). + if (!Owner) { + if (Ember._RegistryProxyMixin && Ember._ContainerProxyMixin) { + Owner = Ember.Object.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin); + } else { + Owner = Ember.Object.extend(); + } + } + if (Ember.Registry) { + registry = env.registry = new Ember.Registry(); - container = env.container = registry.container(); + + owner = Owner.create({ + __registry__: registry + }); + + container = env.container = registry.container({ + owner: owner + }); + + owner.__container__ = container; } else { container = env.container = new Ember.Container(); registry = env.registry = container; From e3f10749cda1b1f26eb1283d303c869a506c897b Mon Sep 17 00:00:00 2001 From: John Bohn Date: Tue, 10 Nov 2015 10:00:56 -0500 Subject: [PATCH 1208/2527] Add null implementation of findMany in DS.Adapter Since the other primary methods for override (findRecord, createRecord, findAll, etc) in the abstract class have null implementations, it makes sense to me to have this for findMany as well. --- packages/ember-data/lib/system/adapter.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ember-data/lib/system/adapter.js b/packages/ember-data/lib/system/adapter.js index 5b438025b2e..79a5c418449 100644 --- a/packages/ember-data/lib/system/adapter.js +++ b/packages/ember-data/lib/system/adapter.js @@ -437,6 +437,7 @@ export default Ember.Object.extend({ @param {Array} snapshots @return {Promise} promise */ + findMany: null, /** Organize records into groups, each of which is to be passed to separate From 7efa9db0281be9442e88e5e8ae7da7ee968ee082 Mon Sep 17 00:00:00 2001 From: Adam Knights Date: Thu, 5 Nov 2015 20:55:30 +0000 Subject: [PATCH 1209/2527] [BUGFIX beta] Correctly handle object level errors in json api --- packages/ember-data/lib/adapters/errors.js | 17 ++++++++++-- .../tests/unit/adapter-errors-test.js | 27 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/packages/ember-data/lib/adapters/errors.js b/packages/ember-data/lib/adapters/errors.js index 70a23d8a575..4dc9738adcb 100644 --- a/packages/ember-data/lib/adapters/errors.js +++ b/packages/ember-data/lib/adapters/errors.js @@ -1,6 +1,8 @@ const EmberError = Ember.Error; const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/; +const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/; +const PRIMARY_ATTRIBUTE_KEY = 'base'; /** @class AdapterError @@ -115,11 +117,17 @@ export function errorsHashToArray(errors) { Object.keys(errors).forEach((key) => { let messages = Ember.makeArray(errors[key]); for (let i = 0; i < messages.length; i++) { + let title = 'Invalid Attribute'; + let pointer = `/data/attributes/${key}`; + if (key === PRIMARY_ATTRIBUTE_KEY) { + title = 'Invalid Document'; + pointer = `/data`; + } out.push({ - title: 'Invalid Attribute', + title: title, detail: messages[i], source: { - pointer: `/data/attributes/${key}` + pointer: pointer } }); } @@ -143,6 +151,11 @@ export function errorsArrayToHash(errors) { if (key) { key = key[2]; + } else if (error.source.pointer.search(SOURCE_POINTER_PRIMARY_REGEXP) !== -1) { + key = PRIMARY_ATTRIBUTE_KEY; + } + + if (key) { out[key] = out[key] || []; out[key].push(error.detail || error.title); } diff --git a/packages/ember-data/tests/unit/adapter-errors-test.js b/packages/ember-data/tests/unit/adapter-errors-test.js index 2b4c0e3bdca..bad9a89e471 100644 --- a/packages/ember-data/tests/unit/adapter-errors-test.js +++ b/packages/ember-data/tests/unit/adapter-errors-test.js @@ -47,11 +47,33 @@ var errorsArray = [ } ]; +var errorsPrimaryHash = { + base: ['is invalid', 'error message'] +}; + +var errorsPrimaryArray = [ + { + title: 'Invalid Document', + detail: 'is invalid', + source: { pointer: '/data' } + }, + { + title: 'Invalid Document', + detail: 'error message', + source: { pointer: '/data' } + } +]; + test("errorsHashToArray", function() { var result = DS.errorsHashToArray(errorsHash); deepEqual(result, errorsArray); }); +test("errorsHashToArray for primary data object", function() { + var result = DS.errorsHashToArray(errorsPrimaryHash); + deepEqual(result, errorsPrimaryArray); +}); + test("errorsArrayToHash", function() { var result = DS.errorsArrayToHash(errorsArray); deepEqual(result, errorsHash); @@ -67,6 +89,11 @@ test("errorsArrayToHash without trailing slash", function() { deepEqual(result, { name: ['error message'] }); }); +test("errorsArrayToHash for primary data object", function() { + var result = DS.errorsArrayToHash(errorsPrimaryArray); + deepEqual(result, errorsPrimaryHash); +}); + test("DS.InvalidError will normalize errors hash will assert", function() { var error; From 45e6db99298f13db732b4b932eef4df5d733a3a5 Mon Sep 17 00:00:00 2001 From: Manuel Wiedenmann Date: Fri, 6 Nov 2015 11:26:32 +0100 Subject: [PATCH 1210/2527] [BUGFIX release] Normalize attrs keys --- .../lib/serializers/json-api-serializer.js | 13 ++--- .../lib/serializers/json-serializer.js | 29 ++++++---- .../serializers/json-api-serializer-test.js | 53 ++++++++++++++++++- .../serializers/json-serializer-test.js | 24 +++++++++ .../serializers/rest-serializer-test.js | 22 ++++++++ 5 files changed, 124 insertions(+), 17 deletions(-) diff --git a/packages/ember-data/lib/serializers/json-api-serializer.js b/packages/ember-data/lib/serializers/json-api-serializer.js index f90bcd0d353..b398ebeefaa 100644 --- a/packages/ember-data/lib/serializers/json-api-serializer.js +++ b/packages/ember-data/lib/serializers/json-api-serializer.js @@ -376,18 +376,19 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {Object} attribute */ serializeAttribute: function(snapshot, json, key, attribute) { - var type = attribute.type; + const type = attribute.type; if (this._canSerialize(key)) { json.attributes = json.attributes || {}; - var value = snapshot.attr(key); + let value = snapshot.attr(key); if (type) { - var transform = this.transformFor(type); + const transform = this.transformFor(type); value = transform.serialize(value); } - var payloadKey = this._getMappedKey(key); + let payloadKey = this._getMappedKey(key, snapshot.type); + if (payloadKey === key) { payloadKey = this.keyForAttribute(key, 'serialize'); } @@ -411,7 +412,7 @@ const JSONAPISerializer = JSONSerializer.extend({ json.relationships = json.relationships || {}; - var payloadKey = this._getMappedKey(key); + var payloadKey = this._getMappedKey(key, snapshot.type); if (payloadKey === key) { payloadKey = this.keyForRelationship(key, 'belongsTo', 'serialize'); } @@ -444,7 +445,7 @@ const JSONAPISerializer = JSONSerializer.extend({ json.relationships = json.relationships || {}; - var payloadKey = this._getMappedKey(key); + var payloadKey = this._getMappedKey(key, snapshot.type); if (payloadKey === key && this.keyForRelationship) { payloadKey = this.keyForRelationship(key, 'hasMany', 'serialize'); } diff --git a/packages/ember-data/lib/serializers/json-serializer.js b/packages/ember-data/lib/serializers/json-serializer.js index d3480799b58..f4f86cd5f9f 100644 --- a/packages/ember-data/lib/serializers/json-serializer.js +++ b/packages/ember-data/lib/serializers/json-serializer.js @@ -710,17 +710,26 @@ export default Serializer.extend({ @method normalizeUsingDeclaredMapping @private */ - normalizeUsingDeclaredMapping: function(typeClass, hash) { + normalizeUsingDeclaredMapping: function(modelClass, hash) { var attrs = get(this, 'attrs'); - var payloadKey, key; + var payloadKey, normalizedKey, key; if (attrs) { for (key in attrs) { - payloadKey = this._getMappedKey(key); + payloadKey = this._getMappedKey(key, modelClass); + if (!hash.hasOwnProperty(payloadKey)) { continue; } - if (payloadKey !== key) { - hash[key] = hash[payloadKey]; + if (get(modelClass, 'attributes').has(key)) { + normalizedKey = this.keyForAttribute(key); + } + + if (get(modelClass, 'relationshipsByName').has(key)) { + normalizedKey = this.keyForRelationship(key); + } + + if (payloadKey !== normalizedKey) { + hash[normalizedKey] = hash[payloadKey]; delete hash[payloadKey]; } } @@ -749,7 +758,9 @@ export default Serializer.extend({ @param {String} key @return {String} key */ - _getMappedKey: function(key) { + _getMappedKey: function(key, modelClass) { + Ember.assert('There is no attribute or relationship with the name `' + key + '` on `' + modelClass.modelName + '`. Check your serializers attrs hash.', get(modelClass, 'attributes').has(key) || get(modelClass, 'relationshipsByName').has(key)); + var attrs = get(this, 'attrs'); var mappedKey; if (attrs && attrs[key]) { @@ -1062,7 +1073,7 @@ export default Serializer.extend({ // if provided, use the mapping provided by `attrs` in // the serializer - var payloadKey = this._getMappedKey(key); + var payloadKey = this._getMappedKey(key, snapshot.type); if (payloadKey === key && this.keyForAttribute) { payloadKey = this.keyForAttribute(key, 'serialize'); @@ -1107,7 +1118,7 @@ export default Serializer.extend({ // if provided, use the mapping provided by `attrs` in // the serializer - var payloadKey = this._getMappedKey(key); + var payloadKey = this._getMappedKey(key, snapshot.type); if (payloadKey === key && this.keyForRelationship) { payloadKey = this.keyForRelationship(key, "belongsTo", "serialize"); } @@ -1159,7 +1170,7 @@ export default Serializer.extend({ if (hasMany !== undefined) { // if provided, use the mapping provided by `attrs` in // the serializer - var payloadKey = this._getMappedKey(key); + var payloadKey = this._getMappedKey(key, snapshot.type); if (payloadKey === key && this.keyForRelationship) { payloadKey = this.keyForRelationship(key, "hasMany", "serialize"); } diff --git a/packages/ember-data/tests/integration/serializers/json-api-serializer-test.js b/packages/ember-data/tests/integration/serializers/json-api-serializer-test.js index 29df8d57943..a64fd5b15d0 100644 --- a/packages/ember-data/tests/integration/serializers/json-api-serializer-test.js +++ b/packages/ember-data/tests/integration/serializers/json-api-serializer-test.js @@ -3,7 +3,7 @@ var env, store, serializer; var get = Ember.get; var run = Ember.run; -var User, Handle, GithubHandle, TwitterHandle, Company; +var User, Handle, GithubHandle, TwitterHandle, Company, Project; module('integration/serializers/json-api-serializer - JSONAPISerializer', { setup: function() { @@ -32,6 +32,10 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', { employees: DS.hasMany('user', { async: true }) }); + Project = DS.Model.extend({ + 'company-name': DS.attr('string') + }); + env = setupStore({ adapter: DS.JSONAPIAdapter, @@ -39,7 +43,8 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', { handle: Handle, 'github-handle': GithubHandle, 'twitter-handle': TwitterHandle, - company: Company + company: Company, + project: Project }); store = env.store; @@ -125,6 +130,7 @@ test('Warns when normalizing an unknown type', function() { test('Serializer should respect the attrs hash when extracting attributes and relationships', function() { env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ attrs: { + firstName: 'firstname_attribute_key', title: "title_attribute_key", company: { key: 'company_relationship_key' } } @@ -135,6 +141,7 @@ test('Serializer should respect the attrs hash when extracting attributes and re type: 'users', id: '1', attributes: { + 'firstname_attribute_key': 'Yehuda', 'title_attribute_key': 'director' }, relationships: { @@ -154,6 +161,7 @@ test('Serializer should respect the attrs hash when extracting attributes and re var user = env.store.serializerFor("user").normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); + equal(user.data.attributes.firstName, 'Yehuda'); equal(user.data.attributes.title, "director"); deepEqual(user.data.relationships.company.data, { id: "2", type: "company" }); }); @@ -161,6 +169,7 @@ test('Serializer should respect the attrs hash when extracting attributes and re test('Serializer should respect the attrs hash when serializing attributes and relationships', function() { env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ attrs: { + firstName: 'firstname_attribute_key', title: "title_attribute_key", company: { key: 'company_relationship_key' } } @@ -184,5 +193,45 @@ test('Serializer should respect the attrs hash when serializing attributes and r var payload = env.store.serializerFor("user").serialize(user._createSnapshot()); equal(payload.data.relationships['company_relationship_key'].data.id, "1"); + equal(payload.data.attributes['firstname_attribute_key'], 'Yehuda'); equal(payload.data.attributes['title_attribute_key'], "director"); }); + +test('Serializer should respect the attrs hash when extracting attributes with not camelized keys', function() { + env.registry.register('serializer:project', DS.JSONAPISerializer.extend({ + attrs: { + 'company-name': 'company_name' + } + })); + + var jsonHash = { + data: { + type: 'projects', + id: '1', + attributes: { + 'company_name': 'Tilde Inc.' + } + } + }; + + var project = env.store.serializerFor('project').normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); + + equal(project.data.attributes['company-name'], 'Tilde Inc.'); +}); + +test('Serializer should respect the attrs hash when serializing attributes with not camelized keys', function() { + env.registry.register('serializer:project', DS.JSONAPISerializer.extend({ + attrs: { + 'company-name': 'company_name' + } + })); + var project; + + run(function() { + project = env.store.createRecord('project', { 'company-name': 'Tilde Inc.' }); + }); + + var payload = env.store.serializerFor('project').serialize(project._createSnapshot()); + + equal(payload.data.attributes['company_name'], 'Tilde Inc.'); +}); diff --git a/packages/ember-data/tests/integration/serializers/json-serializer-test.js b/packages/ember-data/tests/integration/serializers/json-serializer-test.js index 79fd398d4ab..7256902661c 100644 --- a/packages/ember-data/tests/integration/serializers/json-serializer-test.js +++ b/packages/ember-data/tests/integration/serializers/json-serializer-test.js @@ -289,6 +289,30 @@ test('Serializer should respect the attrs hash when extracting records', functio deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }, { id: "2", type: "comment" }]); }); +test('Serializer should map `attrs` attributes directly when keyForAttribute also has a transform', function() { + Post = DS.Model.extend({ + authorName: DS.attr('string') + }); + env = setupStore({ + post: Post + }); + env.registry.register("serializer:post", DS.JSONSerializer.extend({ + keyForAttribute: Ember.String.underscore, + attrs: { + authorName: 'author_name_key' + } + })); + + var jsonHash = { + id: "1", + author_name_key: "DHH" + }; + + var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); + + equal(post.data.attributes.authorName, "DHH"); +}); + test('Serializer should respect the attrs hash when serializing records', function() { Post.reopen({ parentPost: DS.belongsTo('post', { inverse: null, async: true }) diff --git a/packages/ember-data/tests/integration/serializers/rest-serializer-test.js b/packages/ember-data/tests/integration/serializers/rest-serializer-test.js index 95ae9a9ca14..a302ac5062a 100644 --- a/packages/ember-data/tests/integration/serializers/rest-serializer-test.js +++ b/packages/ember-data/tests/integration/serializers/rest-serializer-test.js @@ -409,6 +409,28 @@ test('normalize should allow for different levels of normalization', function() equal(array.data[0].relationships.superVillain.data.id, 1); }); +test('normalize should allow for different levels of normalization - attributes', function() { + env.registry.register('serializer:application', DS.RESTSerializer.extend({ + attrs: { + name: 'full_name' + }, + keyForAttribute: function(attr) { + return Ember.String.decamelize(attr); + } + })); + + var jsonHash = { + evilMinions: [{ id: "1", full_name: "Tom Dale" }] + }; + var array; + + run(function() { + array = env.restSerializer.normalizeResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); + }); + + equal(array.data[0].attributes.name, 'Tom Dale'); +}); + test("serializeIntoHash", function() { run(function() { league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); From 38c8349df0ce288ed32e4afd117bcf2858ea1453 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 11 Nov 2015 19:42:40 -0600 Subject: [PATCH 1211/2527] get globals building again! --- addon/adapters/errors.js | 3 ++- addon/core.js | 6 ++++-- addon/debug.js | 30 +++++++++++++++++++++++++++ addon/index.js | 1 + lib/ember-shim.js | 6 ++++++ lib/globals.js | 12 +++++++++++ config/babel.js => lib/javascripts.js | 0 lib/version-replace.js | 13 ++++++++++++ lib/version.js | 13 ++++++++++++ 9 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 addon/debug.js create mode 100644 lib/ember-shim.js create mode 100644 lib/globals.js rename config/babel.js => lib/javascripts.js (100%) create mode 100644 lib/version-replace.js create mode 100644 lib/version.js diff --git a/addon/adapters/errors.js b/addon/adapters/errors.js index 70a23d8a575..df90fc66786 100644 --- a/addon/adapters/errors.js +++ b/addon/adapters/errors.js @@ -1,3 +1,4 @@ +import {assert} from 'ember-data/debug'; const EmberError = Ember.Error; const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/; @@ -78,7 +79,7 @@ AdapterError.prototype = Object.create(EmberError.prototype); @namespace DS */ export function InvalidError(errors) { - Ember.assert('`InvalidError` expects json-api formatted errors array.', Ember.isArray(errors || [])); + assert('`InvalidError` expects json-api formatted errors array.', Ember.isArray(errors || [])); AdapterError.call(this, errors, 'The adapter rejected the commit because it was invalid'); } diff --git a/addon/core.js b/addon/core.js index 539965386cd..abff6660a3f 100644 --- a/addon/core.js +++ b/addon/core.js @@ -1,3 +1,6 @@ +import Ember from 'ember'; +import VERSION from 'ember-data/version'; + /** @module ember-data */ @@ -12,12 +15,11 @@ /** @property VERSION @type String - @default 'VERSION_STRING_PLACEHOLDER' @static */ /*jshint -W079 */ var DS = Ember.Namespace.create({ - VERSION: 'VERSION_STRING_PLACEHOLDER' + VERSION: VERSION }); if (Ember.libraries) { diff --git a/addon/debug.js b/addon/debug.js new file mode 100644 index 00000000000..6ac646ef7ac --- /dev/null +++ b/addon/debug.js @@ -0,0 +1,30 @@ +import Ember from 'ember'; + +export function assert() { + return Ember.assert(...arguments); +} + +export function debug() { + return Ember.debug(...arguments); +} + +export function deprecate() { + return Ember.deprecate(...arguments); +} + +export function info() { + return Ember.info(...arguments); +} + +export function runInDebug() { + return Ember.runInDebug(...arguments); +} + +export function warn() { + return Ember.warn(...arguments); +} + +export function debugSeal() { + return Ember.debugSeal(...arguments); +} + diff --git a/addon/index.js b/addon/index.js index 66cd76d463f..537985bc56a 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,3 +1,4 @@ +import Ember from "ember"; /** Ember Data @module ember-data diff --git a/lib/ember-shim.js b/lib/ember-shim.js new file mode 100644 index 00000000000..4ed59dbb763 --- /dev/null +++ b/lib/ember-shim.js @@ -0,0 +1,6 @@ +define('ember', [], function() { + return { + default: Ember + }; +}); + diff --git a/lib/globals.js b/lib/globals.js new file mode 100644 index 00000000000..26396c4fa56 --- /dev/null +++ b/lib/globals.js @@ -0,0 +1,12 @@ +var merge = require('broccoli-merge-trees'); +var js = require('./javascripts'); +var versionReplace = require('./version-replace'); +var stew = require('broccoli-stew'); + +module.exports = function(jsDir, configDir) { + var javascripts = js(jsDir); + var configFiles = versionReplace(configDir); + + var globalFiles = merge([configFiles, javascripts]); + return stew.mv(globalFiles, 'globals'); +}; diff --git a/config/babel.js b/lib/javascripts.js similarity index 100% rename from config/babel.js rename to lib/javascripts.js diff --git a/lib/version-replace.js b/lib/version-replace.js new file mode 100644 index 00000000000..92fc17cb86d --- /dev/null +++ b/lib/version-replace.js @@ -0,0 +1,13 @@ +var VERSION = require('git-repo-version')(10); +var replace = require('broccoli-string-replace'); + +module.exports = function configFiles(tree) { + return replace(tree, { + files: ['*.{json,js}'], + pattern: { + match: /VERSION_STRING_PLACEHOLDER/g, + replacement: VERSION + } + }); +}; + diff --git a/lib/version.js b/lib/version.js new file mode 100644 index 00000000000..c76390fb201 --- /dev/null +++ b/lib/version.js @@ -0,0 +1,13 @@ +var createFile = require('broccoli-file-creator'); + +var version; + +try { + version = require('git-repo-version')(10); +} catch (e) { + version = require('../package').version; +} + +module.exports = function() { + return createFile('version.js', 'export default "' + version + '";'); +}; From b194e7e25ca25a8dff39c27c1a483f67041fbe09 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 11 Nov 2015 19:55:01 -0600 Subject: [PATCH 1212/2527] update some build files and package versions --- bower.json | 10 +-- ember-cli-build.js | 6 +- generators/license.js | 2 +- index.js | 9 ++- lib/javascripts.js | 149 ++++++++++++++++++++++++++++++++++++++---- package.json | 15 ++++- testem.json | 1 + 7 files changed, 170 insertions(+), 22 deletions(-) diff --git a/bower.json b/bower.json index b635590fe44..51a24b4e479 100644 --- a/bower.json +++ b/bower.json @@ -1,16 +1,18 @@ { "name": "ember-data", "dependencies": { - "ember": "1.13.7", + "ember": "components/ember#release", "ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3", "ember-cli-test-loader": "ember-cli-test-loader#0.1.3", - "ember-data": "1.13.8", "ember-load-initializers": "ember-cli/ember-load-initializers#0.1.5", "ember-qunit": "0.4.9", "ember-qunit-notifications": "0.0.7", "ember-resolver": "~0.1.18", "jquery": "^1.11.3", - "loader.js": "ember-cli/loader.js#3.2.1", + "loader.js": "3.3.0", "qunit": "~1.18.0" + }, + "resolutions": { + "ember": "release" } -} +} \ No newline at end of file diff --git a/ember-cli-build.js b/ember-cli-build.js index d37d64cd943..92a00dd870e 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -1,5 +1,7 @@ /* global require, module */ var EmberApp = require('ember-cli/lib/broccoli/ember-addon'); +var merge = require('broccoli-merge-trees'); +var globals = require('./lib/globals'); module.exports = function(defaults) { var app = new EmberApp(defaults, { @@ -13,5 +15,7 @@ module.exports = function(defaults) { behave. You most likely want to be modifying `./index.js` or app's build file */ - return app.toTree(); + var appTree = app.toTree(); + var globalsBuild = globals('addon', 'config/package-manager-files'); + return merge([appTree, globalsBuild]); }; diff --git a/generators/license.js b/generators/license.js index 21dff7fa06c..a8b24d89639 100644 --- a/generators/license.js +++ b/generators/license.js @@ -1,6 +1,6 @@ /*! * @overview Ember Data - * @copyright Copyright 2011-2014 Tilde Inc. and contributors. + * @copyright Copyright 2011-2015 Tilde Inc. and contributors. * Portions Copyright 2011 LivingSocial Inc. * @license Licensed under MIT license (see license.js) * @version VERSION_STRING_PLACEHOLDER diff --git a/index.js b/index.js index 3ad252c0448..38deac39edc 100644 --- a/index.js +++ b/index.js @@ -2,5 +2,12 @@ 'use strict'; module.exports = { - name: 'ember-data' + name: 'ember-data', + + treeForAddon: function(dir) { + var version = require('./lib/version'); + var merge = require('broccoli-merge-trees'); + + return this._super.treeForAddon.call(this, merge([version(), dir])); + } }; diff --git a/lib/javascripts.js b/lib/javascripts.js index 9f1a1440875..8a602b5ce85 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -1,14 +1,137 @@ -module.exports = { - loose: true, - whitelist: [ - 'es6.templateLiterals', - 'es6.parameters', - 'es6.arrowFunctions', - 'es6.destructuring', - 'es6.spread', - 'es6.properties.computed', - 'es6.properties.shorthand', - 'es6.blockScoping', - 'es6.constants' - ] +var filterImports = require('babel-plugin-filter-imports'); +var babel = require('broccoli-babel-transpiler'); +var merge = require('broccoli-merge-trees'); +var concat = require('broccoli-concat'); +var uglify = require('broccoli-uglify-sourcemap'); +var stew = require('broccoli-stew'); +var version = require('./version'); +var path = require('path'); +var Funnel = require('broccoli-funnel'); +var versionReplace = require('./version-replace'); + +function babelOptions(libraryName, _options) { + _options = _options || {}; + + var options = { + whitelist: [ + 'es6.templateLiterals', + 'es6.parameters', + 'es6.arrowFunctions', + 'es6.destructuring', + 'es6.spread', + 'es6.properties.computed', + 'es6.properties.shorthand', + 'es6.blockScoping', + 'es6.constants', + 'es6.modules' + ], + sourceMaps: false, + modules: 'amdStrict', + moduleRoot: libraryName, + moduleId: true, + // Transforms /index.js files to use their containing directory name + getModuleId: function (name) { + return name.replace(/\/index$/g, ''); + }, + resolveModuleSource: function(name, filename) { + if (name.indexOf('.') === 0) { + return libraryName + '/' + path.join(path.dirname(filename), name); + } else { + return name; + } + } + }; + + Object.keys(_options).forEach(function(opt) { + options[opt] = _options[opt]; + }); + + return options; +} + +function debugBuild(packageName, tree) { + var compiled = babel(tree, babelOptions(packageName)); + return stew.mv(compiled, packageName); +} + +function strippedBuild(packageName, tree) { + var plugins = [ + filterImports({ + 'ember-data/debug': [ + 'assert', + 'debug', + 'deprecate', + 'info', + 'runInDebug', + 'warn', + 'debugSeal' + ] + }) + ]; + + var withoutDebug = new Funnel(tree, { + exclude: ['debug.js'] + }); + + var compiled = babel(withoutDebug, babelOptions(packageName, { + plugins: plugins + })); + + return stew.mv(compiled, packageName); +} + +function collapse(tree, outputFileName) { + var bowerDir = path.join(__dirname, '..', 'bower_components', 'loader.js'); + var loader = new Funnel(bowerDir, { + include: ['loader.js'] + }); + + var emberShim = new Funnel(__dirname, { + include: ['ember-shim.js'] + }); + + var generatorDir = path.join(__dirname, '..', 'generators'); + var license = new Funnel(generatorDir, {include: ['license.js']}); + license = versionReplace(license); + + var withLoader = merge([tree, loader, license, emberShim]); + return concat(withLoader, { + inputFiles: ['license.js', 'loader.js', '**/*.js'], + outputFile: '/' + outputFileName, + header: '(function(){ \n"use strict";\n', + footer: '\nrequire("ember-data");\n})();\n' + }); +} + +function minify(tree) { + return uglify(tree, { + sourceMapIncludeSources: false, + sourceMapConfig: { + enabled: false + } + }); +} + + +module.exports = function(tree) { + var emberInflector = new Funnel(path.dirname(require.resolve('ember-inflector/addon')), { + include: ['**/*.js'] + }); + var emberData = merge([tree, version()]); + + var javascripts = merge([ + debugBuild('ember-inflector', emberInflector), + debugBuild('ember-data', emberData) + ]); + + var strippedJavascripts = merge([ + strippedBuild('ember-inflector', emberInflector), + strippedBuild('ember-data', emberData) + ]); + + var debug = collapse(javascripts, 'ember-data.js'); + var production = collapse(strippedJavascripts, 'ember-data.prod.js'); + var minified = stew.rename(minify(production), 'ember-data.prod.js', 'ember-data.min.js'); + + return merge([debug, production, minified]); }; diff --git a/package.json b/package.json index 8b2336fdf32..3c8678a9275 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "0.0.0", + "version": "2.3.0+canary", "description": "The default blueprint for ember-cli addons.", "directories": { "doc": "doc", @@ -19,8 +19,17 @@ "author": "", "license": "MIT", "devDependencies": { + "babel-plugin-filter-imports": "^0.2.0", "bower": "^1.6.5", "broccoli-asset-rev": "^2.1.2", + "broccoli-babel-transpiler": "^5.5.0", + "broccoli-concat": "0.0.13", + "broccoli-file-creator": "^1.0.0", + "broccoli-funnel": "^1.0.0", + "broccoli-merge-trees": "^1.0.0", + "broccoli-stew": "^1.0.1", + "broccoli-string-replace": "^0.1.1", + "broccoli-uglify-sourcemap": "^1.0.1", "ember-cli": "1.13.8", "ember-cli-app-version": "0.5.0", "ember-cli-content-security-policy": "0.4.0", @@ -38,7 +47,9 @@ "ember-export-application-global": "^1.0.3", "ember-inflector": "^1.9.3", "ember-try": "0.0.6", - "ember-watson": "^0.7.0" + "ember-watson": "^0.7.0", + "git-repo-version": "^0.3.0", + "lodash.assign": "^3.2.0" }, "peerDependencies": { "ember-inflector": "^1.0.0" diff --git a/testem.json b/testem.json index 71b50baf873..0f35392cf2e 100644 --- a/testem.json +++ b/testem.json @@ -6,6 +6,7 @@ "PhantomJS" ], "launch_in_dev": [ + "PhantomJS", "Chrome" ] } From 91f951af6c690897ff8436c8bea15866c361a803 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 11 Nov 2015 19:58:27 -0600 Subject: [PATCH 1213/2527] update bower build script to look in globals dist folder --- bin/bower-ember-data-build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/bower-ember-data-build b/bin/bower-ember-data-build index 496454da8da..e306b1b98ed 100755 --- a/bin/bower-ember-data-build +++ b/bin/bower-ember-data-build @@ -10,7 +10,7 @@ COMPONENTS_EMBER_REPO_SLUG="components/ember-data" USER="rwjblue" # This ensure that no directories within dist will be copied when script is run. -INCLUDED_FILES=`find dist -maxdepth 1 -type f` +INCLUDED_FILES=`find dist/globals -maxdepth 1 -type f` CURRENT_BRANCH=$TRAVIS_BRANCH From 569b45216a0c7b29a57d979021d9756895a7293b Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 11 Nov 2015 20:01:52 -0600 Subject: [PATCH 1214/2527] only build globals in production mode --- ember-cli-build.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ember-cli-build.js b/ember-cli-build.js index 92a00dd870e..d07501e26b1 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -1,4 +1,5 @@ /* global require, module */ +/* jshint node: true*/ var EmberApp = require('ember-cli/lib/broccoli/ember-addon'); var merge = require('broccoli-merge-trees'); var globals = require('./lib/globals'); @@ -16,6 +17,11 @@ module.exports = function(defaults) { */ var appTree = app.toTree(); - var globalsBuild = globals('addon', 'config/package-manager-files'); - return merge([appTree, globalsBuild]); + + if (process.env.EMBER_ENV === 'production') { + var globalsBuild = globals('addon', 'config/package-manager-files'); + return merge([appTree, globalsBuild]); + } else { + return appTree; + } }; From 56fced5526d9aaf29ab8f19d86d16e49429df9cd Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 11 Nov 2015 20:07:38 -0600 Subject: [PATCH 1215/2527] file-creator and merge-trees are dependencies, not devDependencies --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3c8678a9275..c2cf317533b 100644 --- a/package.json +++ b/package.json @@ -18,15 +18,18 @@ }, "author": "", "license": "MIT", + "dependencies": { + "broccoli-file-creator": "^1.0.0", + "broccoli-merge-trees": "^1.0.0", + "ember-cli-babel": "^5.1.3" + }, "devDependencies": { "babel-plugin-filter-imports": "^0.2.0", "bower": "^1.6.5", "broccoli-asset-rev": "^2.1.2", "broccoli-babel-transpiler": "^5.5.0", "broccoli-concat": "0.0.13", - "broccoli-file-creator": "^1.0.0", "broccoli-funnel": "^1.0.0", - "broccoli-merge-trees": "^1.0.0", "broccoli-stew": "^1.0.1", "broccoli-string-replace": "^0.1.1", "broccoli-uglify-sourcemap": "^1.0.1", @@ -57,9 +60,6 @@ "keywords": [ "ember-addon" ], - "dependencies": { - "ember-cli-babel": "^5.1.3" - }, "ember-addon": { "configPath": "tests/dummy/config" } From 5b0605207b723e97ac1cf65cfaef47b0e94df291 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 12 Nov 2015 16:36:36 -0600 Subject: [PATCH 1216/2527] generate API docs from YUIdoc --- ember-cli-build.js | 3 +- lib/yuidoc.js | 29 +++++++ old-Brocfile.js | 185 --------------------------------------------- package.json | 1 + 4 files changed, 32 insertions(+), 186 deletions(-) create mode 100644 lib/yuidoc.js delete mode 100644 old-Brocfile.js diff --git a/ember-cli-build.js b/ember-cli-build.js index d07501e26b1..bb27d556388 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -3,6 +3,7 @@ var EmberApp = require('ember-cli/lib/broccoli/ember-addon'); var merge = require('broccoli-merge-trees'); var globals = require('./lib/globals'); +var yuidoc = require('./lib/yuidoc'); module.exports = function(defaults) { var app = new EmberApp(defaults, { @@ -20,7 +21,7 @@ module.exports = function(defaults) { if (process.env.EMBER_ENV === 'production') { var globalsBuild = globals('addon', 'config/package-manager-files'); - return merge([appTree, globalsBuild]); + return merge([appTree, globalsBuild, yuidoc()]); } else { return appTree; } diff --git a/lib/yuidoc.js b/lib/yuidoc.js new file mode 100644 index 00000000000..0e0e300873f --- /dev/null +++ b/lib/yuidoc.js @@ -0,0 +1,29 @@ +var YUIDoc = require('broccoli-yuidoc'); +var version = require('git-repo-version')(10); +var path = require('path'); + +module.exports = function yui() { + var emberData = path.join(__dirname, '..', 'addon'); + var emberInflector = path.join(path.dirname(require.resolve('ember-inflector'), 'addon')); + + return new YUIDoc([emberData, emberInflector], { + srcDir: '/', + destDir: 'docs', + yuidoc: { + "name": "The ember-data API", + "description": "The ember-data API: a data persistence library for Ember.js", + "version": version, + "logo": "http://f.cl.ly/items/1A1L432s022u1O1q1V3p/ember%20logo.png", + "url": "https://github.com/emberjs/data", + "options": { + "paths": [ + "ember-data/lib", + "ember-inflector/addon" + ], + "exclude": "vendor", + "outdir": "docs/build" + } + } + }); +}; + diff --git a/old-Brocfile.js b/old-Brocfile.js deleted file mode 100644 index 7510f7981d1..00000000000 --- a/old-Brocfile.js +++ /dev/null @@ -1,185 +0,0 @@ -/* jshint node: true */ - -var es6 = require('broccoli-es6-module-transpiler'); -var PackageResolver = require('es6-module-transpiler-package-resolver'); -var concat = require('broccoli-sourcemap-concat'); -var uglify = require('broccoli-uglify-js'); -var es3SafeRecast = require('broccoli-es3-safe-recast'); -var env = process.env.EMBER_ENV; -var amdBuild = require('./lib/amd-build'); -var testTree = require('./lib/test-tree'); -var libTree = require('./lib/lib-tree'); -var pickFiles = require('broccoli-static-compiler'); -var merge = require('broccoli-merge-trees'); -var moveFile = require('broccoli-file-mover'); -var defeatureify = require('broccoli-defeatureify'); -var version = require('git-repo-version')(10); -var yuidoc = require('broccoli-yuidoc'); -var replace = require('broccoli-replace'); -var stew = require('broccoli-stew'); -var babel = require('broccoli-babel-transpiler'); -var babelOptions = require('./config/babel'); -var fileCreator = require('broccoli-file-creator'); -var jscs = require('broccoli-jscs'); -var features = require('./lib/feature-flags'); - -function minify(tree, name) { - var config = require('./config/ember-defeatureify'); - tree = defeatureify(tree, { - debugStatements: config.options.debugStatements, - enableStripDebug: config.enableStripDebug, - features: require('./config/features') - }); - tree = moveFile(tree, { - srcFile: name + '.js', - destFile: '/' + name + '.prod.js' - }); - tree = pickFiles(tree, { - srcDir: '/', - destDir: '/', - files: [name + '.prod.js'] - }); - tree = removeSourceMappingURL(tree); - var uglified = moveFile(uglify(tree, { mangle: true }), { - srcFile: name + '.prod.js', - destFile: '/' + name + '.min.js' - }); - return merge([uglified, tree], { overwrite: true }); -} - -var yuidocTree = yuidoc('packages', { - srcDir: '/', - destDir: 'docs', - yuidoc: { - "name": "The ember-data API", - "description": "The ember-data API: a data persistence library for Ember.js", - "version": version, - "logo": "http://f.cl.ly/items/1A1L432s022u1O1q1V3p/ember%20logo.png", - "url": "https://github.com/emberjs/data", - "options": { - "paths": [ - "packages/ember-data/lib", - "packages/ember-inflector/addon" - ], - "exclude": "vendor", - "outdir": "docs/build" - } - } -}); - -// Excludes tests files from package path -function package(packagePath, vendorPath) { - vendorPath = vendorPath || 'packages/'; - return pickFiles(vendorPath + packagePath, { - files: ['**/*.js'], - srcDir: '/', - destDir: '/' + packagePath - }); -} - -function packageAddon(packagePath, vendorPath) { - return stew.rename(pickFiles(vendorPath + packagePath, { - files: ['**/*.js'], - srcDir: '/addon', - destDir: '/' + packagePath + '/lib' - }), 'index.js', 'main.js'); -} - -var packages = merge([ - packageAddon('ember-inflector', 'node_modules/'), - package('ember-data'), - package('ember') -]); - -var globalBuild; - -var withFeatures = features(packages); -var transpiledPackages = babel(withFeatures, babelOptions); - -// Bundle formatter for smaller payload -if (env === 'production') { - globalBuild = es6(libTree(transpiledPackages), { - inputFiles: ['ember-data'], - output: '/ember-data.js', - resolvers: [PackageResolver], - formatter: 'bundle' - }); - - var tests = testTree(packages, amdBuild(transpiledPackages)); - globalBuild = merge([globalBuild, tests]); -} else { - // Use AMD for faster rebuilds in dev - var bootFile = fileCreator('/boot.js', 'require("ember-data");'); - - var compiled = amdBuild(transpiledPackages); - var libFiles = libTree(compiled); - - var emberData = merge([bootFile, libFiles]); - - emberData = concat(emberData, { - inputFiles: ['ember-data/**/*.js', 'boot.js'], - outputFile: '/ember-data.js' - }); - - globalBuild = merge([emberData, testTree(packages, compiled)]); -} - -var testRunner = pickFiles('tests', { - srcDir: '/', - files: ['**/*'], - destDir: '/' -}); - -var bower = pickFiles('bower_components', { - srcDir: '/', - destDir: '/bower_components' -}); - -var configurationFiles = pickFiles('config/package-manager-files', { - srcDir: '/', - destDir: '/', - files: ['**/*.json'] -}); - -function versionStamp(tree) { - return replace(tree, { - files: ['**/*'], - patterns: [{ - match: /VERSION_STRING_PLACEHOLDER/g, - replacement: version - }] - }); -} - -function removeSourceMappingURL(tree) { - return replace(tree, { - files: ['**/*'], - patterns: [{ - match: /\/\/(.*)sourceMappingURL=(.*)/g, - replacement: '' - }] - }); -} - -configurationFiles = versionStamp(configurationFiles); - -var jscsTree = jscs('packages'); - -var trees = [ - jscsTree, - testRunner, - bower, - configurationFiles -]; - -if (env === 'production') { - globalBuild = versionStamp(globalBuild); - globalBuild = es3SafeRecast(globalBuild); - var minifiedGlobals = minify(globalBuild, 'ember-data'); - trees.push(yuidocTree); - trees.push(minifiedGlobals); -} - -trees.push(globalBuild); - -module.exports = merge(trees, { overwrite: true }); diff --git a/package.json b/package.json index c2cf317533b..7710c59986b 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "broccoli-stew": "^1.0.1", "broccoli-string-replace": "^0.1.1", "broccoli-uglify-sourcemap": "^1.0.1", + "broccoli-yuidoc": "^2.1.0", "ember-cli": "1.13.8", "ember-cli-app-version": "0.5.0", "ember-cli-content-security-policy": "0.4.0", From ed484771288fdbcbf4cc29541e5e4d29866a3fd4 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 12 Nov 2015 16:43:36 -0600 Subject: [PATCH 1217/2527] enforce style with JSCS --- ember-cli-build.js | 4 ++++ package.json | 1 + tests/index.html | 2 +- tests/integration/filter-test.js | 2 +- tests/integration/polymorphic-belongs-to-test.js | 4 ++-- tests/test-helper.js | 2 +- tests/unit/model/relationships/belongs-to-test.js | 6 +++--- tests/unit/states-test.js | 2 +- 8 files changed, 14 insertions(+), 9 deletions(-) diff --git a/ember-cli-build.js b/ember-cli-build.js index bb27d556388..38eb600fa24 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -7,6 +7,10 @@ var yuidoc = require('./lib/yuidoc'); module.exports = function(defaults) { var app = new EmberApp(defaults, { + jscsOptions: { + enabled: true, + excludeFiles: ['tests/dummy/config'] + } // Add options here }); diff --git a/package.json b/package.json index 7710c59986b..830870be86a 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "broccoli-babel-transpiler": "^5.5.0", "broccoli-concat": "0.0.13", "broccoli-funnel": "^1.0.0", + "broccoli-jscs": "^1.1.0", "broccoli-stew": "^1.0.1", "broccoli-string-replace": "^0.1.1", "broccoli-uglify-sourcemap": "^1.0.1", diff --git a/tests/index.html b/tests/index.html index 8fea6fe700b..bd598bf0d51 100644 --- a/tests/index.html +++ b/tests/index.html @@ -24,7 +24,7 @@ - + {{content-for 'body-footer'}} diff --git a/tests/integration/filter-test.js b/tests/integration/filter-test.js index 79bb18b599f..846b56cd646 100644 --- a/tests/integration/filter-test.js +++ b/tests/integration/filter-test.js @@ -653,7 +653,7 @@ var serverResponds = function() { edited.forEach(function(person) { run(person, 'save'); }); }; -var setup = function(assert, serverCallbacks){ +var setup = function(assert, serverCallbacks) { run(function() { customAdapter(env, DS.Adapter.extend(serverCallbacks)); diff --git a/tests/integration/polymorphic-belongs-to-test.js b/tests/integration/polymorphic-belongs-to-test.js index e6dd0d52fe6..96ccd3a431c 100644 --- a/tests/integration/polymorphic-belongs-to-test.js +++ b/tests/integration/polymorphic-belongs-to-test.js @@ -5,8 +5,8 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -const {attr, belongsTo} = DS; -const {run} = Ember; +const { attr, belongsTo } = DS; +const { run } = Ember; let store; diff --git a/tests/test-helper.js b/tests/test-helper.js index 366110ec7ff..545280303fb 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -21,7 +21,7 @@ setResolver(resolver); const ENV = Ember.ENV; const QUNIT_PARAMS = QUnit.urlParams; -const {assert} = QUnit; +const { assert } = QUnit; ENV.EXTEND_PROTOTYPES = QUNIT_PARAMS.extendprototypes; ENV.ENABLE_OPTIONAL_FEATURES = QUNIT_PARAMS.enableoptionalfeatures; diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index 4558faaf291..cb8a16d6d00 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -416,7 +416,7 @@ test("belongsTo gives a warning when provided with a serialize option", function }); }); - run(function() { + run(function() { store.find('person', 1).then(assert.wait(function(person) { assert.warns(function() { get(person, 'hobby'); @@ -470,10 +470,10 @@ test("belongsTo gives a warning when provided with an embedded option", function }); }); - run(function() { + run(function() { store.find('person', 1).then(assert.wait(function(person) { assert.warns(function() { - get(person, 'hobby'); + get(person, 'hobby'); }, /You provided an embedded option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin/); })); }); diff --git a/tests/unit/states-test.js b/tests/unit/states-test.js index 5bd10b50f3a..12f5e4c0372 100644 --- a/tests/unit/states-test.js +++ b/tests/unit/states-test.js @@ -2,7 +2,7 @@ import Ember from 'ember'; import QUnit, {module, test} from 'qunit'; import DS from 'ember-data'; -const {assert} = QUnit; +const { assert } = QUnit; var get = Ember.get; From 0ee2cc7625ae49a85183e44d15ddaf254fc30002 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 12 Nov 2015 16:49:56 -0600 Subject: [PATCH 1218/2527] remove unused files --- config/testem-beta.json | 14 ---------- config/testem-canary.json | 14 ---------- config/testem-optional-features.json | 14 ---------- config/testem-stable.json | 14 ---------- lib/lib-tree.js | 9 ------- lib/test-tree.js | 38 ---------------------------- 6 files changed, 103 deletions(-) delete mode 100644 config/testem-beta.json delete mode 100644 config/testem-canary.json delete mode 100644 config/testem-optional-features.json delete mode 100644 config/testem-stable.json delete mode 100644 lib/lib-tree.js delete mode 100644 lib/test-tree.js diff --git a/config/testem-beta.json b/config/testem-beta.json deleted file mode 100644 index b0f802263f9..00000000000 --- a/config/testem-beta.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "test_page": "dist/index.html?emberchannel=beta&nojshint=true", - "serve_files": [ - "dist/**/*.js", - "tests/**/*" - ], - "launch_in_ci": [ - "PhantomJS" - ], - "routes": { - "/ember-data.js": "dist/ember-data.js", - "/tests/ember-data-tests.js": "dist/ember-data-tests.js" - } -} diff --git a/config/testem-canary.json b/config/testem-canary.json deleted file mode 100644 index 94d7ac430ad..00000000000 --- a/config/testem-canary.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "test_page": "dist/index.html?emberchannel=canary&nojshint=true", - "serve_files": [ - "dist/**/*.js", - "tests/**/*" - ], - "launch_in_ci": [ - "PhantomJS" - ], - "routes": { - "/ember-data.js": "dist/ember-data.js", - "/tests/ember-data-tests.js": "dist/ember-data-tests.js" - } -} diff --git a/config/testem-optional-features.json b/config/testem-optional-features.json deleted file mode 100644 index ee0c0b90e2b..00000000000 --- a/config/testem-optional-features.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "test_page": "dist/index.html?nojshint=true&enableoptionalfeatures=true", - "serve_files": [ - "dist/**/*.js", - "tests/**/*" - ], - "launch_in_ci": [ - "PhantomJS" - ], - "routes": { - "/ember-data.js": "dist/ember-data.js", - "/tests/ember-data-tests.js": "dist/ember-data-tests.js" - } -} diff --git a/config/testem-stable.json b/config/testem-stable.json deleted file mode 100644 index a1460127be0..00000000000 --- a/config/testem-stable.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "test_page": "dist/index.html?emberchannel=stable&nojshint=true", - "serve_files": [ - "dist/**/*.js", - "tests/**/*" - ], - "launch_in_ci": [ - "PhantomJS" - ], - "routes": { - "/ember-data.js": "dist/ember-data.js", - "/tests/ember-data-tests.js": "dist/ember-data-tests.js" - } -} diff --git a/lib/lib-tree.js b/lib/lib-tree.js deleted file mode 100644 index b140ea93168..00000000000 --- a/lib/lib-tree.js +++ /dev/null @@ -1,9 +0,0 @@ -var pickFiles = require('broccoli-static-compiler'); - -module.exports = function libTree(tree) { - return pickFiles(tree, { - files: ['**/*/lib/**/*.{js,map}'], - srcDir: '/', - destDir: '/' - }); -}; diff --git a/lib/test-tree.js b/lib/test-tree.js deleted file mode 100644 index 27d8211e187..00000000000 --- a/lib/test-tree.js +++ /dev/null @@ -1,38 +0,0 @@ -var concat = require('broccoli-sourcemap-concat'); -var pickFiles = require('broccoli-static-compiler'); -var jshint = require('broccoli-jshint'); -var path = require('path'); -var wrap = require('broccoli-wrap'); -var merge = require('broccoli-merge-trees'); - -module.exports = function testTree(sourceTree, compiled) { - var emberDataFiles = pickFiles(sourceTree, { - files: ['**/ember-data/**/*.{js,map}'], - srcDir: '/', - destDir: '/' - }); - - var hinted = hint(emberDataFiles); - var testFiles = pickFiles(compiled, { - srcDir: '/', - destDir: '/', - files: ['**/*/tests/**/*.{js,map}'] - }); - - var allTestFiles = merge([hinted, testFiles]); - - return concat(allTestFiles, { - inputFiles: ['**/*.js'], - outputFile: '/ember-data-tests.js' - }); -}; - -function hint(tree){ - var dirname = __dirname || path.resolve(path.dirname()); - var jshinted = jshint(tree, { - jshintrcPath: path.join(dirname, '..', '.jshintrc') - }); - return wrap(jshinted, { - wrapper: [ "if (!QUnit.urlParams.nojshint) {\n", "\n}"], - }); -} From 9cc967990d044da5ca9b3af37b119b6c1afe1877 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 12 Nov 2015 17:03:44 -0600 Subject: [PATCH 1219/2527] dont exclude debug from globals build yet --- lib/javascripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/javascripts.js b/lib/javascripts.js index 8a602b5ce85..761dd2ca8ec 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -73,7 +73,7 @@ function strippedBuild(packageName, tree) { exclude: ['debug.js'] }); - var compiled = babel(withoutDebug, babelOptions(packageName, { + var compiled = babel(tree , babelOptions(packageName, { plugins: plugins })); From ef7c1dbd95a2cca332c77e2fd0c6d21fd84ce759 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 12 Nov 2015 17:05:26 -0600 Subject: [PATCH 1220/2527] remove 'packages' directory --- packages/ember/lib/main.js | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 packages/ember/lib/main.js diff --git a/packages/ember/lib/main.js b/packages/ember/lib/main.js deleted file mode 100644 index ddf3b4462ee..00000000000 --- a/packages/ember/lib/main.js +++ /dev/null @@ -1,2 +0,0 @@ -// Shim Ember module -export default Ember; From bc0051b4782040af3a39fd3c4ee833dde160e814 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Fri, 13 Nov 2015 00:56:51 +0000 Subject: [PATCH 1221/2527] [DOC fix] Adds missing space before list --- addon/serializers/embedded-records-mixin.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 9f5a610d2c8..8cb8f4f6d71 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -85,6 +85,7 @@ var camelize = Ember.String.camelize; to modify it to fit your specific needs.** For example review the docs for each method of this mixin: + * [normalize](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_normalize) * [serializeBelongsTo](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeBelongsTo) * [serializeHasMany](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeHasMany) From df81e19edcb8813f54d5f35378d0e47d53f3c580 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Fri, 13 Nov 2015 09:49:25 -0500 Subject: [PATCH 1222/2527] [CLEANUP] Clean up adapter/find-all-test.js * Use ES6 `() =>` where applicable * Remove unnecessary `Ember.` and `Ember.RSVP` prefixes * Remove ignored closure parameters * One-line adapater overrides when possible --- tests/integration/adapter/find-all-test.js | 67 +++++++++++----------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index d7ea583c381..97320ad3e6f 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -1,23 +1,22 @@ import {createStore} from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; - import {module, test} from 'qunit'; - import DS from 'ember-data'; -var get = Ember.get; -var Person, store, allRecords; -var run = Ember.run; -var env; +const { attr } = DS; +const { get, run } = Ember; +const { resolve, reject } = Ember.RSVP; + +let Person, store, allRecords, env; module("integration/adapter/find_all - Finding All Records of a Type", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ - updatedAt: DS.attr('string'), - name: DS.attr('string'), - firstName: DS.attr('string'), - lastName: DS.attr('string') + updatedAt: attr('string'), + name: attr('string'), + firstName: attr('string'), + lastName: attr('string') }); allRecords = null; @@ -28,68 +27,68 @@ module("integration/adapter/find_all - Finding All Records of a Type", { store = env.store; }, - afterEach: function() { - run(function() { + afterEach() { + run(() => { if (allRecords) { allRecords.destroy(); } store.destroy(); }); } }); -test("When all records for a type are requested, the store should call the adapter's `findAll` method.", function(assert) { +test("When all records for a type are requested, the store should call the adapter's `findAll` method.", (assert) => { assert.expect(5); env.registry.register('adapter:person', DS.Adapter.extend({ - findAll: function(store, type, since) { + findAll() { // this will get called twice assert.ok(true, "the adapter's findAll method should be invoked"); - return Ember.RSVP.resolve([{ id: 1, name: "Braaaahm Dale" }]); + return resolve([{ id: 1, name: "Braaaahm Dale" }]); } })); - var allRecords; + let allRecords; - run(function() { - store.findAll('person').then(function(all) { + run(() => { + store.findAll('person').then((all) => { allRecords = all; assert.equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); assert.equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); }); }); - run(function() { - store.findAll('person').then(function(all) { + run(() => { + store.findAll('person').then((all) => { // Only one record array per type should ever be created (identity map) assert.strictEqual(allRecords, all, "the same record array is returned every time all records of a type are requested"); }); }); }); -test("When all records for a type are requested, a rejection should reject the promise", function(assert) { +test("When all records for a type are requested, a rejection should reject the promise", (assert) => { assert.expect(5); - var count = 0; + let count = 0; env.registry.register('adapter:person', DS.Adapter.extend({ - findAll: function(store, type, since) { + findAll() { // this will get called twice assert.ok(true, "the adapter's findAll method should be invoked"); if (count++ === 0) { - return Ember.RSVP.reject(); + return reject(); } else { - return Ember.RSVP.resolve([{ id: 1, name: "Braaaahm Dale" }]); + return resolve([{ id: 1, name: "Braaaahm Dale" }]); } } })); - var allRecords; + let allRecords; - run(function() { - store.findAll('person').then(null, function() { + run(() => { + store.findAll('person').then(null, () => { assert.ok(true, "The rejection should get here"); return store.findAll('person'); - }).then(function(all) { + }).then((all) => { allRecords = all; assert.equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); assert.equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); @@ -97,14 +96,14 @@ test("When all records for a type are requested, a rejection should reject the p }); }); -test("When all records for a type are requested, records that are already loaded should be returned immediately.", function(assert) { +test("When all records for a type are requested, records that are already loaded should be returned immediately.", (assert) => { assert.expect(3); store = createStore({ adapter: DS.Adapter.extend(), person: Person }); - run(function() { + run(() => { // Load a record from the server store.push({ data: { @@ -126,7 +125,7 @@ test("When all records for a type are requested, records that are already loaded assert.equal(allRecords.objectAt(1).get('name'), "Alex MacCaw", "the second item in the record array is Alex MacCaw"); }); -test("When all records for a type are requested, records that are created on the client should be added to the record array.", function(assert) { +test("When all records for a type are requested, records that are created on the client should be added to the record array.", (assert) => { assert.expect(3); store = createStore({ @@ -138,7 +137,7 @@ test("When all records for a type are requested, records that are created on the assert.equal(get(allRecords, 'length'), 0, "precond - the record array's length is zero before any records are loaded"); - run(function() { + run(() => { store.createRecord('person', { name: "Carsten Nielsen" }); }); From 2472b3a2bad15658fe42acf4800383bf1b02f1fc Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Fri, 13 Nov 2015 09:40:56 -0500 Subject: [PATCH 1223/2527] [CLEANUP] `tests/integration/adapter/find-test.js` * Use ES6 `() =>` where applicable * Remove unnecessary `Ember.` and `Ember.RSVP` prefixes * Remove ignored closure parameters * One-line adapater overrides when possible --- tests/integration/adapter/find-test.js | 78 ++++++++++++-------------- 1 file changed, 35 insertions(+), 43 deletions(-) diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 04608c5c507..9d289600db7 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -1,20 +1,21 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; - import {module, test} from 'qunit'; - import DS from 'ember-data'; -var Person, store, env; -var run = Ember.run; +const { run } = Ember; +const { attr } = DS; +const { reject } = Ember.RSVP; + +let Person, store, env; module("integration/adapter/find - Finding Records", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ - updatedAt: DS.attr('string'), - name: DS.attr('string'), - firstName: DS.attr('string'), - lastName: DS.attr('string') + updatedAt: attr('string'), + name: attr('string'), + firstName: attr('string'), + lastName: attr('string') }); env = setupStore({ @@ -23,28 +24,28 @@ module("integration/adapter/find - Finding Records", { store = env.store; }, - afterEach: function() { + afterEach() { run(store, 'destroy'); } }); -test("It raises an assertion when `undefined` is passed as id (#1705)", function(assert) { - assert.expectAssertion(function() { +test("It raises an assertion when `undefined` is passed as id (#1705)", (assert) => { + assert.expectAssertion(() => { store.find('person', undefined); }, "You cannot pass `undefined` as id to the store's find method"); - assert.expectAssertion(function() { + assert.expectAssertion(() => { store.find('person', null); }, "You cannot pass `null` as id to the store's find method"); }); -test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function(assert) { +test("When a single record is requested, the adapter's find method should be called unless it's loaded.", (assert) => { assert.expect(2); var count = 0; env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(_, type) { assert.equal(type, Person, "the find method is called with the correct type"); assert.equal(count, 0, "the find method is only called once"); @@ -53,47 +54,45 @@ test("When a single record is requested, the adapter's find method should be cal } })); - run(function() { + run(() => { store.findRecord('person', 1); store.findRecord('person', 1); }); }); -test("When a single record is requested multiple times, all .find() calls are resolved after the promise is resolved", function(assert) { +test("When a single record is requested multiple times, all .find() calls are resolved after the promise is resolved", (assert) => { var deferred = Ember.RSVP.defer(); env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { - return deferred.promise; - } + findRecord: () => deferred.promise })); - run(function() { + run(() => { store.findRecord('person', 1).then(assert.wait(function(person) { assert.equal(person.get('id'), "1"); assert.equal(person.get('name'), "Braaaahm Dale"); let done = assert.async(); - deferred.promise.then(function(value) { + deferred.promise.then(() => { assert.ok(true, 'expected deferred.promise to fulfill'); done(); - }, function(reason) { + }, () => { assert.ok(false, 'expected deferred.promise to fulfill, but rejected'); done(); }); })); }); - run(function() { - store.findRecord('person', 1).then(assert.wait(function(post) { + run(() => { + store.findRecord('person', 1).then(assert.wait((post) => { assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Braaaahm Dale"); let done = assert.async(); - deferred.promise.then(function(value) { + deferred.promise.then(() => { assert.ok(true, 'expected deferred.promise to fulfill'); done(); - }, function(reason) { + }, () => { assert.ok(false, 'expected deferred.promise to fulfill, but rejected'); done(); }); @@ -101,39 +100,32 @@ test("When a single record is requested multiple times, all .find() calls are re })); }); - Ember.run(function() { - deferred.resolve({ id: 1, name: "Braaaahm Dale" }); - }); + run(() => deferred.resolve({ id: 1, name: "Braaaahm Dale" })); }); -test("When a single record is requested, and the promise is rejected, .find() is rejected.", function(assert) { +test("When a single record is requested, and the promise is rejected, .find() is rejected.", (assert) => { env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { - return Ember.RSVP.reject(); - } + findRecord: () => reject() })); - run(function() { - store.findRecord('person', 1).then(null, assert.wait(function(reason) { + run(() => { + store.findRecord('person', 1).then(null, assert.wait(() => { assert.ok(true, "The rejection handler was called"); })); }); }); -test("When a single record is requested, and the promise is rejected, the record should be unloaded.", function(assert) { +test("When a single record is requested, and the promise is rejected, the record should be unloaded.", (assert) => { assert.expect(2); env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { - return Ember.RSVP.reject(); - } + findRecord: () => reject() })); - run(function() { - store.findRecord('person', 1).then(null, assert.wait(function(reason) { + run(() => { + store.findRecord('person', 1).then(null, assert.wait((reason) => { assert.ok(true, "The rejection handler was called"); assert.ok(!store.hasRecordForId('person', 1), "The record has been unloaded"); })); }); - }); From a51bea910065100fb610957b8df2bc8703d4e33c Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Tue, 10 Nov 2015 12:11:25 -0500 Subject: [PATCH 1224/2527] `Store._find` asserts `adapterPayload` not empty Currently, [Store._find][find] only asserts that the `adapterPayload` is non-null (i.e. `{}` is a valid payload). This commit forces the `adapterPayload` to be non-empty. When TDDing with Mirage, `adapterPayload` is often `{}`, which sneaks through the asserts and ends up as a non-descriptive: ``` Assertion Failed: You must include an 'id' for undefined in an object passed to 'push' ``` Which is triggered in [Store._pushInternalModel][_pushInternalModel], which is a few method invocations away from the source of the issue. [_pushInternalModel]: https://github.com/emberjs/data/blob/f1ccad8ab9356dd51f44d63585c27d8bb4ec9c3a/packages/ember-data/lib/system/store.js#L1709 [find]: https://github.com/emberjs/data/blob/f1ccad8ab9356dd51f44d63585c27d8bb4ec9c3a/packages/ember-data/lib/system/store/finders.js#L27 --- addon/system/store/finders.js | 14 ++++++++++- tests/integration/adapter/find-all-test.js | 10 ++++++++ tests/integration/adapter/find-test.js | 24 +++++++++++++++++++ .../store/json-api-validation-test.js | 8 +++---- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/addon/system/store/finders.js b/addon/system/store/finders.js index f386e8ebd48..e9fb4530dd3 100644 --- a/addon/system/store/finders.js +++ b/addon/system/store/finders.js @@ -14,6 +14,14 @@ import { var Promise = Ember.RSVP.Promise; +function payloadIsNotBlank(adapterPayload) { + if (Ember.isArray(adapterPayload)) { + return true; + } else { + return Object.keys(adapterPayload || {}).length; + } +} + export function _find(adapter, store, typeClass, id, internalModel, options) { var snapshot = internalModel.createSnapshot(options); var promise = adapter.findRecord(store, typeClass, id, snapshot); @@ -24,7 +32,7 @@ export function _find(adapter, store, typeClass, id, internalModel, options) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - Ember.assert("You made a request for a " + typeClass.typeClassKey + " with id " + id + ", but the adapter's response did not have any data", adapterPayload); + Ember.assert("You made a `find` request for a " + typeClass.typeClassKey + " with id " + id + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, id, 'findRecord'); //TODO Optimize @@ -56,6 +64,7 @@ export function _findMany(adapter, store, typeClass, ids, internalModels) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { + Ember.assert("You made a `findMany` request for a " + typeClass.typeClassKey + " with ids " + ids + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findMany'); //TODO Optimize, no need to materialize here @@ -77,6 +86,7 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) promise = _guard(promise, _bind(_objectIsAlive, internalModel)); return promise.then(function(adapterPayload) { + Ember.assert("You made a `findHasMany` request for a " + internalModel.modelName + "'s `" + relationship.key + "` relationship, using link " + link + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findHasMany'); //TODO Use a non record creating push @@ -126,6 +136,7 @@ export function _findAll(adapter, store, typeClass, sinceToken, options) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { + Ember.assert("You made a `findAll` request for " + typeClass.typeClassKey + "records, but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findAll'); //TODO Optimize @@ -172,6 +183,7 @@ export function _queryRecord(adapter, store, typeClass, query) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { + Ember.assert("You made a `queryRecord` request for " + typeClass.typeClassKey + "records, with query `" + query + "`, but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); var record; store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'queryRecord'); diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index d7ea583c381..37c5716e86f 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -145,3 +145,13 @@ test("When all records for a type are requested, records that are created on the assert.equal(get(allRecords, 'length'), 1, "the record array's length is 1"); assert.equal(allRecords.objectAt(0).get('name'), "Carsten Nielsen", "the first item in the record array is Carsten Nielsen"); }); + +test('When all records are requested, assert the payload is not blank', (assert) => { + env.registry.register('adapter:person', DS.Adapter.extend({ + findAll: () => Ember.RSVP.resolve({}) + })); + + assert.expectAssertion(() => { + run(() => store.findAll('person')); + }, /the adapter's response did not have any data/); +}); diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 04608c5c507..36f7fb3100e 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -137,3 +137,27 @@ test("When a single record is requested, and the promise is rejected, the record }); }); + +test('When a single record is requested, and the payload is blank', (assert) => { + env.registry.register('adapter:person', DS.Adapter.extend({ + findRecord: () => Ember.RSVP.resolve({}) + })); + + assert.expectAssertion(() => { + run(() => store.find('person', 'the-id')); + }, /the adapter's response did not have any data/); +}); + +test('When multiple records are requested, and the payload is blank', (assert) => { + env.registry.register('adapter:person', DS.Adapter.extend({ + coalesceFindRequests: true, + findMany: () => Ember.RSVP.resolve({}) + })); + + assert.expectAssertion(() => { + run(() => { + store.findRecord('person', '1'); + store.findRecord('person', '2'); + }); + }, /the adapter's response did not have any data/); +}); diff --git a/tests/integration/store/json-api-validation-test.js b/tests/integration/store/json-api-validation-test.js index fc96a46a16a..e53ab3708d4 100644 --- a/tests/integration/store/json-api-validation-test.js +++ b/tests/integration/store/json-api-validation-test.js @@ -34,7 +34,7 @@ test("when normalizeResponse returns undefined (or doesn't return), throws an er env.registry.register('adapter:person', DS.Adapter.extend({ findRecord() { - return Ember.RSVP.resolve({}); + return Ember.RSVP.resolve({ data: {} }); } })); @@ -53,7 +53,7 @@ test("when normalizeResponse returns null, throws an error", function(assert) { env.registry.register('adapter:person', DS.Adapter.extend({ findRecord() { - return Ember.RSVP.resolve({}); + return Ember.RSVP.resolve({ data: {} }); } })); @@ -73,7 +73,7 @@ test("when normalizeResponse returns an empty object, throws an error", function env.registry.register('adapter:person', DS.Adapter.extend({ findRecord() { - return Ember.RSVP.resolve({}); + return Ember.RSVP.resolve({ data: {} }); } })); @@ -97,7 +97,7 @@ test("when normalizeResponse returns a document with both data and errors, throw env.registry.register('adapter:person', DS.Adapter.extend({ findRecord() { - return Ember.RSVP.resolve({}); + return Ember.RSVP.resolve({ data: {} }); } })); From 88d4b9ef5ae38ffbee4ab29f3ff4e03a55c4ebe1 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 13 Nov 2015 09:49:10 -0600 Subject: [PATCH 1225/2527] restore globals publishing to canary build The globals only build in production mode, so we change travis to build that after success. --- .travis.yml | 2 +- package.json | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3a5624b13c1..782589970d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ script: - ./bin/lint-features - npm run-script test after_success: - - npm run-script publish-build:prebuilt + - npm run-script production - "./bin/bower-ember-data-build" env: global: diff --git a/package.json b/package.json index 830870be86a..7f229a2eb08 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,8 @@ { "name": "ember-data", "version": "2.3.0+canary", - "description": "The default blueprint for ember-cli addons.", + "description": "A data layer for your Ember applications.", + "repository": "git://github.com/emberjs/data.git", "directories": { "doc": "doc", "test": "tests" @@ -10,7 +11,8 @@ "build": "ember build", "start": "ember server", "test": "ember try:testall", - "bower": "bower install" + "bower": "bower install", + "production": "ember build --environment=production" }, "repository": "", "engines": { From 37711f7848ec63b975c24960704c4728c9a374e1 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 13 Nov 2015 10:09:28 -0600 Subject: [PATCH 1226/2527] update README stating no IE8 support --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 8bab4bf5f47..c318cdfd3eb 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,12 @@ after [setup](#setup). You'll find ember-data.js in the `dist` directory. #### Internet Explorer 8 +**Internet Explorer 8 is no longer supported by Ember Data on versions +2.0 and later.** + +If you require IE8 support, you can use the `1.13` series of releases. +The source code is available on the `release-1-13` branch. + Internet Explorer 8 support requires Ember 1.8.1 (which provides a polyfill for `Object.create`). ### Instantiating the Store From f6e675d5552f67f9513588d34afc92aafd99c1fb Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 13 Nov 2015 10:22:11 -0600 Subject: [PATCH 1227/2527] upgrade node to 4 on CI --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 782589970d8..e8dcd45020a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: node_js sudo: required dist: trusty node_js: - - "0.10" + - "4.2" before_install: - "npm config set spin false" - "npm install -g npm@^2" diff --git a/appveyor.yml b/appveyor.yml index eb67ab5838a..c3eb24b5586 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ init: # Test against these versions of Node.js. environment: matrix: - - nodejs_version: "0.12" + - nodejs_version: "4.2" # Install scripts. (runs after repo cloning) install: From 434527d0155acc7549f90a17aa469f0451003671 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 13 Nov 2015 10:38:00 -0600 Subject: [PATCH 1228/2527] don't run build on Appveyor due to slow --- appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index c3eb24b5586..bdbf7dbd759 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -29,7 +29,6 @@ install: test_script: # Output useful info for debugging. - npm version - - npm run build - cmd: npm run test # Don't actually build. From 90cb66bf26a63ec07a78f61cce2831c6a91fb3aa Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 14 Nov 2015 11:00:08 -0600 Subject: [PATCH 1229/2527] update ember-cli to 1.13.12 --- .editorconfig | 31 ++++++++++++++++++++++---- .ember-cli | 9 ++++++++ .npmignore | 14 ++++++++++++ .watchmanconfig | 3 +++ config/ember-try.js | 1 + package.json | 2 +- tests/dummy/app/app.js | 4 ++-- tests/dummy/app/router.js | 2 +- tests/helpers/destroy-app.js | 5 +++++ tests/helpers/module-for-acceptance.js | 23 +++++++++++++++++++ tests/helpers/resolver.js | 2 +- tests/helpers/start-app.js | 6 ++--- tests/index.html | 3 ++- 13 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 .ember-cli create mode 100644 .npmignore create mode 100644 .watchmanconfig create mode 100644 tests/helpers/destroy-app.js create mode 100644 tests/helpers/module-for-acceptance.js diff --git a/.editorconfig b/.editorconfig index e20a9680d23..47c5438403c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,11 +1,34 @@ -# http://editorconfig.org +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org root = true + [*] +end_of_line = lf charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true indent_style = space indent_size = 2 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true \ No newline at end of file + +[*.js] +indent_style = space +indent_size = 2 + +[*.hbs] +insert_final_newline = false +indent_style = space +indent_size = 2 + +[*.css] +indent_style = space +indent_size = 2 + +[*.html] +indent_style = space +indent_size = 2 + +[*.{diff,md}] +trim_trailing_whitespace = false diff --git a/.ember-cli b/.ember-cli new file mode 100644 index 00000000000..ee64cfed2a8 --- /dev/null +++ b/.ember-cli @@ -0,0 +1,9 @@ +{ + /** + Ember CLI sends analytics information by default. The data is completely + anonymous, but there are times when you might want to disable this behavior. + + Setting `disableAnalytics` to true will prevent any data from being sent. + */ + "disableAnalytics": false +} diff --git a/.npmignore b/.npmignore new file mode 100644 index 00000000000..49996f5a391 --- /dev/null +++ b/.npmignore @@ -0,0 +1,14 @@ +bower_components/ +tests/ +tmp/ +dist/ + +.bowerrc +.editorconfig +.ember-cli +.travis.yml +.npmignore +**/.gitkeep +bower.json +Brocfile.js +testem.json diff --git a/.watchmanconfig b/.watchmanconfig new file mode 100644 index 00000000000..e7834e3e4f3 --- /dev/null +++ b/.watchmanconfig @@ -0,0 +1,3 @@ +{ + "ignore_dirs": ["tmp", "dist"] +} diff --git a/config/ember-try.js b/config/ember-try.js index 83dab0f1846..3e88bc612a1 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -1,3 +1,4 @@ +/*jshint node:true*/ module.exports = { scenarios: [ { diff --git a/package.json b/package.json index 7f229a2eb08..cfb62ce1f53 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "broccoli-string-replace": "^0.1.1", "broccoli-uglify-sourcemap": "^1.0.1", "broccoli-yuidoc": "^2.1.0", - "ember-cli": "1.13.8", + "ember-cli": "1.13.12", "ember-cli-app-version": "0.5.0", "ember-cli-content-security-policy": "0.4.0", "ember-cli-dependency-checker": "^1.0.1", diff --git a/tests/dummy/app/app.js b/tests/dummy/app/app.js index 8d66b958758..8b234d6d57b 100644 --- a/tests/dummy/app/app.js +++ b/tests/dummy/app/app.js @@ -3,14 +3,14 @@ import Resolver from 'ember/resolver'; import loadInitializers from 'ember/load-initializers'; import config from './config/environment'; -var App; +let App; Ember.MODEL_FACTORY_INJECTIONS = true; App = Ember.Application.extend({ modulePrefix: config.modulePrefix, podModulePrefix: config.podModulePrefix, - Resolver: Resolver + Resolver }); loadInitializers(App, config.modulePrefix); diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js index cef554b3d9e..3bba78ebc80 100644 --- a/tests/dummy/app/router.js +++ b/tests/dummy/app/router.js @@ -1,7 +1,7 @@ import Ember from 'ember'; import config from './config/environment'; -var Router = Ember.Router.extend({ +const Router = Ember.Router.extend({ location: config.locationType }); diff --git a/tests/helpers/destroy-app.js b/tests/helpers/destroy-app.js new file mode 100644 index 00000000000..c3d4d1abb5d --- /dev/null +++ b/tests/helpers/destroy-app.js @@ -0,0 +1,5 @@ +import Ember from 'ember'; + +export default function destroyApp(application) { + Ember.run(application, 'destroy'); +} diff --git a/tests/helpers/module-for-acceptance.js b/tests/helpers/module-for-acceptance.js new file mode 100644 index 00000000000..ed23003db40 --- /dev/null +++ b/tests/helpers/module-for-acceptance.js @@ -0,0 +1,23 @@ +import { module } from 'qunit'; +import startApp from '../helpers/start-app'; +import destroyApp from '../helpers/destroy-app'; + +export default function(name, options = {}) { + module(name, { + beforeEach() { + this.application = startApp(); + + if (options.beforeEach) { + options.beforeEach.apply(this, arguments); + } + }, + + afterEach() { + destroyApp(this.application); + + if (options.afterEach) { + options.afterEach.apply(this, arguments); + } + } + }); +} diff --git a/tests/helpers/resolver.js b/tests/helpers/resolver.js index 28f4ece46a0..ebfb4e4d455 100644 --- a/tests/helpers/resolver.js +++ b/tests/helpers/resolver.js @@ -1,7 +1,7 @@ import Resolver from 'ember/resolver'; import config from '../../config/environment'; -var resolver = Resolver.create(); +const resolver = Resolver.create(); resolver.namespace = { modulePrefix: config.modulePrefix, diff --git a/tests/helpers/start-app.js b/tests/helpers/start-app.js index 0f7aab1afb5..e098f1d5be6 100644 --- a/tests/helpers/start-app.js +++ b/tests/helpers/start-app.js @@ -3,12 +3,12 @@ import Application from '../../app'; import config from '../../config/environment'; export default function startApp(attrs) { - var application; + let application; - var attributes = Ember.merge({}, config.APP); + let attributes = Ember.merge({}, config.APP); attributes = Ember.merge(attributes, attrs); // use defaults, but you can override; - Ember.run(function() { + Ember.run(() => { application = Application.create(attributes); application.setupForTesting(); application.injectTestHelpers(); diff --git a/tests/index.html b/tests/index.html index bd598bf0d51..5e88e5e10c2 100644 --- a/tests/index.html +++ b/tests/index.html @@ -18,13 +18,14 @@ {{content-for 'test-head-footer'}} - {{content-for 'body'}} {{content-for 'test-body'}} + + {{content-for 'body-footer'}} From dba19186508738220434f87ef37c4712eb77dce3 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 17 Nov 2015 10:30:37 -0500 Subject: [PATCH 1230/2527] [BUGFIX beta] Warn instead of asserting when a mapped key doesn't match an attribute or relationship --- addon/serializers/json-serializer.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addon/serializers/json-serializer.js b/addon/serializers/json-serializer.js index cd196f7ea0c..625f12cfff7 100644 --- a/addon/serializers/json-serializer.js +++ b/addon/serializers/json-serializer.js @@ -763,7 +763,9 @@ export default Serializer.extend({ @return {String} key */ _getMappedKey: function(key, modelClass) { - Ember.assert('There is no attribute or relationship with the name `' + key + '` on `' + modelClass.modelName + '`. Check your serializers attrs hash.', get(modelClass, 'attributes').has(key) || get(modelClass, 'relationshipsByName').has(key)); + Ember.warn('There is no attribute or relationship with the name `' + key + '` on `' + modelClass.modelName + '`. Check your serializers attrs hash.', get(modelClass, 'attributes').has(key) || get(modelClass, 'relationshipsByName').has(key), { + id: 'ds.serializer.no-mapped-attrs-key' + }); var attrs = get(this, 'attrs'); var mappedKey; From 838d51b9a23ee6cd4d5fa617080a6cb5a1078e77 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 17 Nov 2015 13:31:34 -0500 Subject: [PATCH 1231/2527] Update the changelog for Ember Data 2.2.0 --- CHANGELOG.md | 43 +++++++++++++++++++++++++++++++++++++++++++ package.json | 1 - 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3762fb3e559..6cc4674ba75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,49 @@ ### Master +### Release 2.2.0 (November 17, 2015) +- [#3937](https://github.com/emberjs/data/pull/3937) [BUGFIX beta] Warn instead of asserting when a mapped key doesn't mat… +- [#3868](https://github.com/emberjs/data/pull/3868) Reset changed attributes when matching data is pushed +- [#3875](https://github.com/emberjs/data/pull/3875) [BUGFIX beta] serialize type for embedded, polymorphic belongsTo +- [#3900](https://github.com/emberjs/data/pull/3900) [DOC fix] errors pointers should start with a / +- [#3905](https://github.com/emberjs/data/pull/3905) [BUGFIX release] Update the dependencies for Ember 2.x +- [#3909](https://github.com/emberjs/data/pull/3909) [BUGFIX beta] Correctly handle object level errors in json api +- [#3910](https://github.com/emberjs/data/pull/3910) [BUGFIX release] Normalize attrs keys +- [#3912](https://github.com/emberjs/data/pull/3912) Use public API for container/registry when possible.] +- [#3835](https://github.com/emberjs/data/pull/3835) [BUGFIX] extract polymorphic belongsTo in RESTSerializer +- [#3887](https://github.com/emberjs/data/pull/3887) [BUGFIX release] update ember-inflector to resolve default Inflector … +- [#3888](https://github.com/emberjs/data/pull/3888) [BUGFIX release] import from ember-inflector to use the default instance +- [#3832](https://github.com/emberjs/data/pull/3832) Fix API docs for JSONAPISerializer.normalize +- [#3837](https://github.com/emberjs/data/pull/3837) [BUGFIX] Attribute/relationship named "type" of embedded record is considered before normalization +- [#3846](https://github.com/emberjs/data/pull/3846) [BUGFIX beta] Attribute/relationship named "type" of primary record i… +- [#3847](https://github.com/emberjs/data/pull/3847) [BUGFIX beta] JSONAPI serializer not respecting 'attrs' hash +- [#3857](https://github.com/emberjs/data/pull/3857) [BUGFIX beta] rollbackAttributes() works after multiple failed saves +- [#3859](https://github.com/emberjs/data/pull/3859) [BUGFIX beta] Correctly handle invalid errors without payload or pointer +- [#3861](https://github.com/emberjs/data/pull/3861) [BUGFIX beta] Assert that an array is returned from the normalized re… +- [#3867](https://github.com/emberjs/data/pull/3867) Allow serializers to normalize response, remove old internal serializers code +- [#3697](https://github.com/emberjs/data/pull/3697) Fix typo in CHANGELOG +- [#3215](https://github.com/emberjs/data/pull/3215) remove Map/MapWithDefault polyfills, use Ember's ones +- [#3711](https://github.com/emberjs/data/pull/3711) Explicitly set length after setting a new content property +- [#3714](https://github.com/emberjs/data/pull/3714) Update the location of the custom store in the API doc example +- [#3699](https://github.com/emberjs/data/pull/3699) [refactor] add some tests asserting polymorphic relationships can be … +- [#3751](https://github.com/emberjs/data/pull/3751) Remove normalizePayload, associated docs, and mention of functionality. +- [#3732](https://github.com/emberjs/data/pull/3732) follow up fixes for #3701 +- [#3746](https://github.com/emberjs/data/pull/3746) Improve test coverage for store#findRecord() +- [#3722](https://github.com/emberjs/data/pull/3722) Shape and cleanup +- [#3739](https://github.com/emberjs/data/pull/3739) store example should use findRecord() +- [#3734](https://github.com/emberjs/data/pull/3734) Revert "Explicitly set length after setting a new content property" +- [#3783](https://github.com/emberjs/data/pull/3783) Update changelog for 2.0.1 release +- [#3771](https://github.com/emberjs/data/pull/3771) update coalesceFindRequests doc for JSONAPIAdapter +- [#3774](https://github.com/emberjs/data/pull/3774) Fix embedded key serialization bug and refactor key serialization +- [#3773](https://github.com/emberjs/data/pull/3773) Break apart embedded serialize methods in EmbeddedRecordsMixin +- [#3777](https://github.com/emberjs/data/pull/3777) Remove unused test module +- [#3788](https://github.com/emberjs/data/pull/3788) Port pr #3725 to the release 2.0 branch +- [#3795](https://github.com/emberjs/data/pull/3795) Trigger an assertion when calling `findRecord` with falsy (except 0) id +- [#3808](https://github.com/emberjs/data/pull/3808) Update internal-model.js +- [#3814](https://github.com/emberjs/data/pull/3814) [BUGFIX] Do not deserialize when a relationship named `type` exists +- [#3816](https://github.com/emberjs/data/pull/3816) run optional feature tests on AppVeyor +- [#3817](https://github.com/emberjs/data/pull/3817) Update the changelog for Ember Data 2.1.0 + ### Release 1.13.14 (October 18, 2015) - [#3665](https://github.com/emberjs/data/pull/3665) [BUGFIX beta] Fix usage of registry for 2.1.0+. - [#3825](https://github.com/emberjs/data/pull/3825) [BUGFIX] Restore IE8 compatibility by using Ember.create diff --git a/package.json b/package.json index cfb62ce1f53..4bcf8a4c991 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "ember-cli-inject-live-reload": "^1.3.1", "ember-cli-qunit": "^1.0.0", "ember-cli-release": "0.2.3", - "ember-cli-sri": "^1.0.3", "ember-cli-uglify": "^1.2.0", "ember-disable-prototype-extensions": "^1.0.0", "ember-disable-proxy-controllers": "^1.0.0", From 3fc52c4aeb09d13f258963209076be700d6b4c8c Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 17 Nov 2015 14:49:22 -0500 Subject: [PATCH 1232/2527] Bump the version number to 2.4.0-canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4bcf8a4c991..9970990d1e8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.3.0+canary", + "version": "2.4.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From 666f7a6d2c588e553a8313e3d2df36ec8e73186f Mon Sep 17 00:00:00 2001 From: Mikhail Topolskiy Date: Wed, 18 Nov 2015 16:30:41 +0300 Subject: [PATCH 1233/2527] Remove JSONSerializer#normalizeId JSONSerializer#normalizeId is unused, extractId/coerceId are used instead --- addon/serializers/json-serializer.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/addon/serializers/json-serializer.js b/addon/serializers/json-serializer.js index 625f12cfff7..22552cf1b98 100644 --- a/addon/serializers/json-serializer.js +++ b/addon/serializers/json-serializer.js @@ -740,19 +740,6 @@ export default Serializer.extend({ } }, - /** - @method normalizeId - @private - */ - normalizeId: function(hash) { - var primaryKey = get(this, 'primaryKey'); - - if (primaryKey === 'id') { return; } - - hash.id = hash[primaryKey]; - delete hash[primaryKey]; - }, - /** Looks up the property key that was set by the custom `attr` mapping passed to the serializer. From 38ef355b128be114192b7419d013c6343a72aa12 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 18 Nov 2015 10:25:22 -0500 Subject: [PATCH 1234/2527] Mark `adapterFor` and `serializerFor` as public --- addon/system/store.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/system/store.js b/addon/system/store.js index baa97c34ec4..d112e667562 100644 --- a/addon/system/store.js +++ b/addon/system/store.js @@ -1937,7 +1937,7 @@ Store = Service.extend({ the value of the `defaultAdapter`. @method adapterFor - @private + @public @param {String} modelName @return DS.Adapter */ @@ -1973,7 +1973,7 @@ Store = Service.extend({ to an instance of `DS.JSONSerializer`. @method serializerFor - @private + @public @param {String} modelName the record to serialize @return {DS.Serializer} */ From 06405d7275f59b5dcff2aaf9f407bbc97ad02b83 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 19 Nov 2015 16:29:11 -0600 Subject: [PATCH 1235/2527] [BUGFIX beta] create an empty sourcemap for bower users refs https://github.com/components/ember-data/issues/32 --- lib/javascripts.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/javascripts.js b/lib/javascripts.js index 761dd2ca8ec..2e39d30c0a5 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -8,6 +8,7 @@ var version = require('./version'); var path = require('path'); var Funnel = require('broccoli-funnel'); var versionReplace = require('./version-replace'); +var fileCreator = require('broccoli-file-creator'); function babelOptions(libraryName, _options) { _options = _options || {}; @@ -132,6 +133,8 @@ module.exports = function(tree) { var debug = collapse(javascripts, 'ember-data.js'); var production = collapse(strippedJavascripts, 'ember-data.prod.js'); var minified = stew.rename(minify(production), 'ember-data.prod.js', 'ember-data.min.js'); + // Hack to get around https://github.com/emberjs/data/blob/v2.1.0/lib/ember-addon/index.js#L28 + var emptySourcemapFile = fileCreator('ember-data.js.map', ''); - return merge([debug, production, minified]); + return merge([debug, production, minified, emptySourcemapFile]); }; From 4ece826843e700933fab76ae4dcdb1ca3ba49e5b Mon Sep 17 00:00:00 2001 From: Chad Hietala Date: Thu, 19 Nov 2015 12:06:29 -0800 Subject: [PATCH 1236/2527] [PERF] Ajax should join an existing run if one exists --- addon/adapters/rest-adapter.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/adapters/rest-adapter.js b/addon/adapters/rest-adapter.js index fedd8c72c0a..01820dea83b 100644 --- a/addon/adapters/rest-adapter.js +++ b/addon/adapters/rest-adapter.js @@ -824,9 +824,9 @@ export default Adapter.extend(BuildURLMixin, { ); if (response instanceof AdapterError) { - Ember.run(null, reject, response); + Ember.run.join(null, reject, response); } else { - Ember.run(null, resolve, response); + Ember.run.join(null, resolve, response); } }; @@ -849,7 +849,7 @@ export default Adapter.extend(BuildURLMixin, { } } - Ember.run(null, reject, error); + Ember.run.join(null, reject, error); }; Ember.$.ajax(hash); From f23f02fd6684faaeb2918a08b03c7e41fde9f755 Mon Sep 17 00:00:00 2001 From: Alex Speller Date: Sun, 22 Nov 2015 03:29:22 +0000 Subject: [PATCH 1237/2527] Fix incorrect reference --- addon/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/system/store.js b/addon/system/store.js index d112e667562..3ee59aabb4f 100644 --- a/addon/system/store.js +++ b/addon/system/store.js @@ -1054,7 +1054,7 @@ Store = Service.extend({ locally created records of the type, however, it will not make a request to the backend to retrieve additional records. If you would like to request all the records from the backend please use - [store.find](#method_find). + [store.findAll](#method_findAll). Also note that multiple calls to `peekAll` for a given type will always return the same `RecordArray`. From 8d0230c359d787afdddda041813a36c1d976e5ab Mon Sep 17 00:00:00 2001 From: Marten Schilstra Date: Fri, 20 Nov 2015 10:05:11 +0100 Subject: [PATCH 1238/2527] Report better error when `type` is missing from a JSONApi response --- addon/serializers/json-api-serializer.js | 7 +++++++ .../serializers/json-api-serializer-test.js | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/addon/serializers/json-api-serializer.js b/addon/serializers/json-api-serializer.js index b398ebeefaa..8b53ea568c5 100644 --- a/addon/serializers/json-api-serializer.js +++ b/addon/serializers/json-api-serializer.js @@ -136,6 +136,10 @@ const JSONAPISerializer = JSONSerializer.extend({ @private */ _normalizeResourceHelper: function(resourceHash) { + Ember.assert(this.warnMessageForUndefinedType(), !Ember.isNone(resourceHash.type), { + id: 'ds.serializer.type-is-undefined' + }); + let modelName = this.modelNameFromPayloadKey(resourceHash.type); if (!this.store._hasModelFor(modelName)) { @@ -465,6 +469,9 @@ const JSONAPISerializer = JSONSerializer.extend({ Ember.runInDebug(function() { JSONAPISerializer.reopen({ + warnMessageForUndefinedType: function() { + return 'Encountered a resource object with an undefined type (resolved resource using ' + this.constructor.toString() + ')'; + }, warnMessageNoModelForType: function(modelName, originalType) { return 'Encountered a resource object with type "' + originalType + '", but no model was found for model name "' + modelName + '" (resolved model name using ' + this.constructor.toString() + '.modelNameFromPayloadKey("' + originalType + '"))'; } diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 7536f865bce..6d8af4f3954 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -134,6 +134,23 @@ test('Warns when normalizing an unknown type', function(assert) { }, /Encountered a resource object with type "UnknownType", but no model was found for model name "unknown-type"/); }); +test('Warns when normalizing with type missing', function(assert) { + var documentHash = { + data: { + id: '1', + attributes: { + foo: 'bar' + } + } + }; + + assert.throws(function() { + run(function() { + env.store.serializerFor('user').normalizeResponse(env.store, User, documentHash, '1', 'findRecord'); + }); + }, /Encountered a resource object with an undefined type/); +}); + test('Serializer should respect the attrs hash when extracting attributes and relationships', function(assert) { env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ attrs: { From 071aa101bdb8fdeafa8be7e0f59cfcecb4ac3982 Mon Sep 17 00:00:00 2001 From: Austin Burdine Date: Sat, 28 Nov 2015 12:35:10 -0700 Subject: [PATCH 1239/2527] fix incorrect argument description... ...in `store.queryRecord` Docs incorrectly say that passed in modelName can be a subclass of DS.Model. That behavior has been removed. --- addon/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/system/store.js b/addon/system/store.js index 3ee59aabb4f..f4e4a8026dd 100644 --- a/addon/system/store.js +++ b/addon/system/store.js @@ -960,7 +960,7 @@ Store = Service.extend({ once the server returns. @method queryRecord - @param {String or subclass of DS.Model} type + @param {String} modelName @param {any} query an opaque query to be used by the adapter @return {Promise} promise */ From 840b48781ad21edc61cef306e92aae53a7db0c7f Mon Sep 17 00:00:00 2001 From: Jeffrey Biles Date: Mon, 30 Nov 2015 11:48:40 -0600 Subject: [PATCH 1240/2527] Use findRecord syntax in unloadRecord documentation Just a small update to the new syntax. --- addon/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/system/store.js b/addon/system/store.js index f4e4a8026dd..8d645d68326 100644 --- a/addon/system/store.js +++ b/addon/system/store.js @@ -407,7 +407,7 @@ Store = Service.extend({ Example ```javascript - store.find('post', 1).then(function(post) { + store.findRecord('post', 1).then(function(post) { store.unloadRecord(post); }); ``` From 0057b0435f1f484b20d93f1db4ea88c26d3f4b17 Mon Sep 17 00:00:00 2001 From: Aaron Renoir Date: Tue, 13 Oct 2015 19:31:13 -0700 Subject: [PATCH 1241/2527] fix transitioning into invalid state remove events from error class add functionality to become valid if errors are removed depricate adding errors change deprecations to regular warnings --- addon/system/model/errors.js | 93 +++++++++++++++++++++++--- addon/system/model/internal-model.js | 13 +++- addon/system/model/model.js | 3 +- addon/system/model/states.js | 8 +++ tests/integration/records/save-test.js | 12 +++- 5 files changed, 110 insertions(+), 19 deletions(-) diff --git a/addon/system/model/errors.js b/addon/system/model/errors.js index 415fcf9407c..1d11f6e0a60 100644 --- a/addon/system/model/errors.js +++ b/addon/system/model/errors.js @@ -107,12 +107,31 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @param {Object} target @param {Function} becameInvalid @param {Function} becameValid + @deprecated */ registerHandlers: function(target, becameInvalid, becameValid) { + Ember.deprecate( + `Record errors will no longer be evented.`, false, { + id: 'ds.errors.registerHandlers', + until: '3.0.0' + }); + + this._registerHandlers(target, becameInvalid, becameValid); + }, + + + /** + Register with target handler + + @method _registerHandlers + @private + */ + _registerHandlers: function(target, becameInvalid, becameValid) { this.on('becameInvalid', target, becameInvalid); this.on('becameValid', target, becameValid); }, + /** @property errorsByAttributeName @type {Ember.MapWithDefault} @@ -214,19 +233,35 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method add @param {String} attribute @param {(Array|String)} messages + @deprecated */ add: function(attribute, messages) { + Ember.warn(`Interacting with a record errors object will no longer change the record state.`, false, { + id: 'ds.errors.add' + }); + var wasEmpty = get(this, 'isEmpty'); + this._add(attribute, messages); + + if (wasEmpty && !get(this, 'isEmpty')) { + this.trigger('becameInvalid'); + } + }, + + + /** + Adds error messages to a given attribute without sending event. + + @method _add + @private + */ + _add: function(attribute, messages) { messages = this._findOrCreateMessages(attribute, messages); this.addObjects(messages); get(this, 'errorsByAttributeName').get(attribute).addObjects(messages); this.notifyPropertyChange(attribute); - - if (wasEmpty && !get(this, 'isEmpty')) { - this.trigger('becameInvalid'); - } }, /** @@ -277,8 +312,29 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method remove @param {String} attribute + @deprecated */ remove: function(attribute) { + Ember.warn(`Interacting with a record errors object will no longer change the record state.`, false, { + id: 'ds.errors.remove' + }); + + if (get(this, 'isEmpty')) { return; } + + this._remove(attribute); + + if (get(this, 'isEmpty')) { + this.trigger('becameValid'); + } + }, + + /** + Removes all error messages from the given attribute without sending event. + + @method _remove + @private + */ + _remove: function(attribute) { if (get(this, 'isEmpty')) { return; } let content = this.rejectBy('attribute', attribute); @@ -286,10 +342,6 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { get(this, 'errorsByAttributeName').delete(attribute); this.notifyPropertyChange(attribute); - - if (get(this, 'isEmpty')) { - this.trigger('becameValid'); - } }, /** @@ -312,8 +364,28 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { ``` @method clear + @deprecated */ clear: function() { + Ember.warn(`Interacting with a record errors object will no longer change the record state.`, false, { + id: 'ds.errors.clear' + }); + + if (get(this, 'isEmpty')) { return; } + + this._clear(); + this.trigger('becameValid'); + }, + + + /** + Removes all error messages. + to the record. + + @method _clear + @private + */ + _clear: function() { if (get(this, 'isEmpty')) { return; } let errorsByAttributeName = get(this, 'errorsByAttributeName'); @@ -328,11 +400,10 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { this.notifyPropertyChange(attribute); }, this); - this._super(); - - this.trigger('becameValid'); + Ember.ArrayProxy.prototype.clear.call(this); }, + /** Checks if there is error messages for the given attribute. diff --git a/addon/system/model/internal-model.js b/addon/system/model/internal-model.js index 13d47f608c2..1f4b30746b4 100644 --- a/addon/system/model/internal-model.js +++ b/addon/system/model/internal-model.js @@ -676,17 +676,24 @@ InternalModel.prototype = { addErrorMessageToAttribute: function(attribute, message) { var record = this.getRecord(); - get(record, 'errors').add(attribute, message); + get(record, 'errors')._add(attribute, message); }, removeErrorMessageFromAttribute: function(attribute) { var record = this.getRecord(); - get(record, 'errors').remove(attribute); + get(record, 'errors')._remove(attribute); }, clearErrorMessages: function() { var record = this.getRecord(); - get(record, 'errors').clear(); + get(record, 'errors')._clear(); + }, + + hasErrors: function() { + var record = this.getRecord(); + var errors = get(record, 'errors'); + + return !Ember.isEmpty(errors); }, // FOR USE DURING COMMIT PROCESS diff --git a/addon/system/model/model.js b/addon/system/model/model.js index bfa760cd6fb..dcc5a8bccdc 100644 --- a/addon/system/model/model.js +++ b/addon/system/model/model.js @@ -351,14 +351,13 @@ var Model = Ember.Object.extend(Ember.Evented, { errors: Ember.computed(function() { let errors = Errors.create(); - errors.registerHandlers(this._internalModel, + errors._registerHandlers(this._internalModel, function() { this.send('becameInvalid'); }, function() { this.send('becameValid'); }); - return errors; }).readOnly(), diff --git a/addon/system/model/states.js b/addon/system/model/states.js index f6fae3a4df0..e4c0cb9997a 100644 --- a/addon/system/model/states.js +++ b/addon/system/model/states.js @@ -326,6 +326,10 @@ var DirtyState = { internalModel.removeErrorMessageFromAttribute(context.name); didSetProperty(internalModel, context); + + if (!internalModel.hasErrors()) { + this.becameValid(internalModel); + } }, becameInvalid: Ember.K, @@ -695,6 +699,10 @@ var RootState = { internalModel.removeErrorMessageFromAttribute(context.name); didSetProperty(internalModel, context); + + if (!internalModel.hasErrors()) { + this.becameValid(internalModel); + } }, becameInvalid: Ember.K, diff --git a/tests/integration/records/save-test.js b/tests/integration/records/save-test.js index 748d375537f..a8e09a5ce82 100644 --- a/tests/integration/records/save-test.js +++ b/tests/integration/records/save-test.js @@ -58,7 +58,9 @@ test("Will reject save on error", function(assert) { }); env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.reject(); + var error = new DS.InvalidError([{ title: 'not valid' }]); + + return Ember.RSVP.reject(error); }; run(function() { @@ -77,8 +79,10 @@ test("Retry is allowed in a failure handler", function(assert) { var count = 0; env.adapter.createRecord = function(store, type, snapshot) { + var error = new DS.InvalidError([{ title: 'not valid' }]); + if (count++ === 0) { - return Ember.RSVP.reject(); + return Ember.RSVP.reject(error); } else { return Ember.RSVP.resolve({ id: 123 }); } @@ -181,7 +185,9 @@ test("Will reject save on invalid", function(assert) { }); env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.reject({ title: 'invalid' }); + var error = new DS.InvalidError([{ title: 'not valid' }]); + + return Ember.RSVP.reject(error); }; run(function() { From 110127a668909e17075c2c8cf520dad5526486cf Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 30 Nov 2015 17:18:15 -0500 Subject: [PATCH 1242/2527] Add a better error message when findRecord returns an array Closes #3950 --- addon/system/store/finders.js | 1 + tests/integration/store-test.js | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/addon/system/store/finders.js b/addon/system/store/finders.js index e9fb4530dd3..c5005b16a09 100644 --- a/addon/system/store/finders.js +++ b/addon/system/store/finders.js @@ -35,6 +35,7 @@ export function _find(adapter, store, typeClass, id, internalModel, options) { Ember.assert("You made a `find` request for a " + typeClass.typeClassKey + " with id " + id + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, id, 'findRecord'); + Ember.assert('Ember Data expected the primary data returned from a `findRecord` response to be an object but instead it found an array.', !Array.isArray(payload.data)); //TODO Optimize var record = store.push(payload); return record._internalModel; diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index c371cd72130..9e5a114f70f 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -571,3 +571,17 @@ test("Store should accept a null value for `data`", function(assert) { }); }); }); + +test('store#findRecord that returns an array should assert', assert => { + initializeStore(DS.JSONAPIAdapter.extend({ + findRecord: function() { + return { data: [] }; + } + })); + + assert.expectAssertion(function() { + run(function() { + store.findRecord('car', 1); + }); + }, /expected the primary data returned from a `findRecord` response to be an object but instead it found an array/); +}); From 16827a1ce8c74b3eb426ecf1e60d75e01f512256 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 2 Dec 2015 12:45:15 -0600 Subject: [PATCH 1243/2527] Revert "[DOC fix] Adds missing space before list" --- addon/serializers/embedded-records-mixin.js | 1 - 1 file changed, 1 deletion(-) diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 8cb8f4f6d71..9f5a610d2c8 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -85,7 +85,6 @@ var camelize = Ember.String.camelize; to modify it to fit your specific needs.** For example review the docs for each method of this mixin: - * [normalize](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_normalize) * [serializeBelongsTo](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeBelongsTo) * [serializeHasMany](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeHasMany) From ef6c167fc6c8092aafb8a3ad4b053debc6ad530e Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Fri, 13 Nov 2015 09:54:20 -0500 Subject: [PATCH 1244/2527] [CLEANUP] `ember watson:methodify addon/` Convert function declaration into ES6 syntax. --- addon/adapters/build-url-mixin.js | 28 ++-- addon/adapters/json-api-adapter.js | 8 +- addon/adapters/rest-adapter.js | 42 +++--- addon/serializers/embedded-records-mixin.js | 36 ++--- addon/serializers/json-api-serializer.js | 40 +++--- addon/serializers/json-serializer.js | 82 +++++------ addon/serializers/rest-serializer.js | 28 ++-- addon/system/adapter.js | 12 +- addon/system/debug/debug-adapter.js | 18 +-- addon/system/debug/debug-info.js | 2 +- addon/system/many-array.js | 24 ++-- addon/system/model/attributes.js | 10 +- addon/system/model/errors.js | 26 ++-- addon/system/model/internal-model.js | 116 ++++++++-------- addon/system/model/model.js | 42 +++--- addon/system/model/states.js | 88 ++++++------ addon/system/promise-proxies.js | 2 +- addon/system/record-array-manager.js | 38 +++--- .../adapter-populated-record-array.js | 4 +- .../record-arrays/filtered-record-array.js | 4 +- addon/system/record-arrays/record-array.js | 16 +-- addon/system/relationships/belongs-to.js | 6 +- addon/system/relationships/ext.js | 22 +-- addon/system/relationships/has-many.js | 6 +- .../relationships/state/relationship.js | 42 +++--- addon/system/serializer.js | 2 +- addon/system/snapshot.js | 16 +-- addon/system/store.js | 128 +++++++++--------- .../system/store/container-instance-cache.js | 10 +- addon/system/store/serializers.js | 2 +- addon/transforms/boolean.js | 4 +- addon/transforms/date.js | 4 +- addon/transforms/number.js | 4 +- addon/transforms/string.js | 4 +- 34 files changed, 458 insertions(+), 458 deletions(-) diff --git a/addon/adapters/build-url-mixin.js b/addon/adapters/build-url-mixin.js index 1baf0d7b176..4987b408378 100644 --- a/addon/adapters/build-url-mixin.js +++ b/addon/adapters/build-url-mixin.js @@ -49,7 +49,7 @@ export default Ember.Mixin.create({ @param {Object} query object of query parameters to send for query requests. @return {String} url */ - buildURL: function(modelName, id, snapshot, requestType, query) { + buildURL(modelName, id, snapshot, requestType, query) { switch (requestType) { case 'findRecord': return this.urlForFindRecord(id, modelName, snapshot); @@ -83,7 +83,7 @@ export default Ember.Mixin.create({ @param {String} id @return {String} url */ - _buildURL: function(modelName, id) { + _buildURL(modelName, id) { var url = []; var host = get(this, 'host'); var prefix = this.urlPrefix(); @@ -112,7 +112,7 @@ export default Ember.Mixin.create({ * @param {DS.Snapshot} snapshot * @return {String} url */ - urlForFindRecord: function(id, modelName, snapshot) { + urlForFindRecord(id, modelName, snapshot) { return this._buildURL(modelName, id); }, @@ -121,7 +121,7 @@ export default Ember.Mixin.create({ * @param {String} modelName * @return {String} url */ - urlForFindAll: function(modelName) { + urlForFindAll(modelName) { return this._buildURL(modelName); }, @@ -131,7 +131,7 @@ export default Ember.Mixin.create({ * @param {String} modelName * @return {String} url */ - urlForQuery: function(query, modelName) { + urlForQuery(query, modelName) { return this._buildURL(modelName); }, @@ -141,7 +141,7 @@ export default Ember.Mixin.create({ * @param {String} modelName * @return {String} url */ - urlForQueryRecord: function(query, modelName) { + urlForQueryRecord(query, modelName) { return this._buildURL(modelName); }, @@ -152,7 +152,7 @@ export default Ember.Mixin.create({ * @param {Array} snapshots * @return {String} url */ - urlForFindMany: function(ids, modelName, snapshots) { + urlForFindMany(ids, modelName, snapshots) { return this._buildURL(modelName); }, @@ -162,7 +162,7 @@ export default Ember.Mixin.create({ * @param {String} modelName * @return {String} url */ - urlForFindHasMany: function(id, modelName) { + urlForFindHasMany(id, modelName) { return this._buildURL(modelName, id); }, @@ -172,7 +172,7 @@ export default Ember.Mixin.create({ * @param {String} modelName * @return {String} url */ - urlForFindBelongsTo: function(id, modelName) { + urlForFindBelongsTo(id, modelName) { return this._buildURL(modelName, id); }, @@ -182,7 +182,7 @@ export default Ember.Mixin.create({ * @param {DS.Snapshot} snapshot * @return {String} url */ - urlForCreateRecord: function(modelName, snapshot) { + urlForCreateRecord(modelName, snapshot) { return this._buildURL(modelName); }, @@ -193,7 +193,7 @@ export default Ember.Mixin.create({ * @param {DS.Snapshot} snapshot * @return {String} url */ - urlForUpdateRecord: function(id, modelName, snapshot) { + urlForUpdateRecord(id, modelName, snapshot) { return this._buildURL(modelName, id); }, @@ -204,7 +204,7 @@ export default Ember.Mixin.create({ * @param {DS.Snapshot} snapshot * @return {String} url */ - urlForDeleteRecord: function(id, modelName, snapshot) { + urlForDeleteRecord(id, modelName, snapshot) { return this._buildURL(modelName, id); }, @@ -215,7 +215,7 @@ export default Ember.Mixin.create({ @param {String} parentURL @return {String} urlPrefix */ - urlPrefix: function(path, parentURL) { + urlPrefix(path, parentURL) { var host = get(this, 'host'); var namespace = get(this, 'namespace'); var url = []; @@ -277,7 +277,7 @@ export default Ember.Mixin.create({ @param {String} modelName @return {String} path **/ - pathForType: function(modelName) { + pathForType(modelName) { var camelized = Ember.String.camelize(modelName); return Ember.String.pluralize(camelized); } diff --git a/addon/adapters/json-api-adapter.js b/addon/adapters/json-api-adapter.js index 1f713a167cb..f5c9d80c58f 100644 --- a/addon/adapters/json-api-adapter.js +++ b/addon/adapters/json-api-adapter.js @@ -21,7 +21,7 @@ export default RESTAdapter.extend({ @param {Object} options @return {Object} */ - ajaxOptions: function(url, type, options) { + ajaxOptions(url, type, options) { let hash = this._super(...arguments); if (hash.contentType) { @@ -96,7 +96,7 @@ export default RESTAdapter.extend({ @param {Array} snapshots @return {Promise} promise */ - findMany: function(store, type, ids, snapshots) { + findMany(store, type, ids, snapshots) { var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); return this.ajax(url, 'GET', { data: { filter: { id: ids.join(',') } } }); }, @@ -106,7 +106,7 @@ export default RESTAdapter.extend({ @param {String} modelName @return {String} path **/ - pathForType: function(modelName) { + pathForType(modelName) { var dasherized = Ember.String.dasherize(modelName); return Ember.String.pluralize(dasherized); }, @@ -119,7 +119,7 @@ export default RESTAdapter.extend({ @param {DS.Snapshot} snapshot @return {Promise} promise */ - updateRecord: function(store, type, snapshot) { + updateRecord(store, type, snapshot) { var data = {}; var serializer = store.serializerFor(type.modelName); diff --git a/addon/adapters/rest-adapter.js b/addon/adapters/rest-adapter.js index 01820dea83b..26098e3eb58 100644 --- a/addon/adapters/rest-adapter.js +++ b/addon/adapters/rest-adapter.js @@ -233,7 +233,7 @@ export default Adapter.extend(BuildURLMixin, { @param {Object} obj @return {Object} */ - sortQueryParams: function(obj) { + sortQueryParams(obj) { var keys = Object.keys(obj); var len = keys.length; if (len < 2) { @@ -370,7 +370,7 @@ export default Adapter.extend(BuildURLMixin, { @param {DS.Snapshot} snapshot @return {Promise} promise */ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { return this.ajax(this.buildURL(type.modelName, id, snapshot, 'findRecord'), 'GET'); }, @@ -388,7 +388,7 @@ export default Adapter.extend(BuildURLMixin, { @param {DS.SnapshotRecordArray} snapshotRecordArray @return {Promise} promise */ - findAll: function(store, type, sinceToken, snapshotRecordArray) { + findAll(store, type, sinceToken, snapshotRecordArray) { var query, url; if (sinceToken) { @@ -417,7 +417,7 @@ export default Adapter.extend(BuildURLMixin, { @param {Object} query @return {Promise} promise */ - query: function(store, type, query) { + query(store, type, query) { var url = this.buildURL(type.modelName, null, null, 'query', query); if (this.sortQueryParams) { @@ -444,7 +444,7 @@ export default Adapter.extend(BuildURLMixin, { @param {Object} query @return {Promise} promise */ - queryRecord: function(store, type, query) { + queryRecord(store, type, query) { var url = this.buildURL(type.modelName, null, null, 'queryRecord', query); if (this.sortQueryParams) { @@ -487,7 +487,7 @@ export default Adapter.extend(BuildURLMixin, { @param {Array} snapshots @return {Promise} promise */ - findMany: function(store, type, ids, snapshots) { + findMany(store, type, ids, snapshots) { var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); return this.ajax(url, 'GET', { data: { ids: ids } }); }, @@ -519,7 +519,7 @@ export default Adapter.extend(BuildURLMixin, { @param {String} url @return {Promise} promise */ - findHasMany: function(store, snapshot, url, relationship) { + findHasMany(store, snapshot, url, relationship) { var id = snapshot.id; var type = snapshot.modelName; @@ -555,7 +555,7 @@ export default Adapter.extend(BuildURLMixin, { @param {String} url @return {Promise} promise */ - findBelongsTo: function(store, snapshot, url, relationship) { + findBelongsTo(store, snapshot, url, relationship) { var id = snapshot.id; var type = snapshot.modelName; @@ -579,7 +579,7 @@ export default Adapter.extend(BuildURLMixin, { @param {DS.Snapshot} snapshot @return {Promise} promise */ - createRecord: function(store, type, snapshot) { + createRecord(store, type, snapshot) { var data = {}; var serializer = store.serializerFor(type.modelName); var url = this.buildURL(type.modelName, null, snapshot, 'createRecord'); @@ -605,7 +605,7 @@ export default Adapter.extend(BuildURLMixin, { @param {DS.Snapshot} snapshot @return {Promise} promise */ - updateRecord: function(store, type, snapshot) { + updateRecord(store, type, snapshot) { var data = {}; var serializer = store.serializerFor(type.modelName); @@ -628,13 +628,13 @@ export default Adapter.extend(BuildURLMixin, { @param {DS.Snapshot} snapshot @return {Promise} promise */ - deleteRecord: function(store, type, snapshot) { + deleteRecord(store, type, snapshot) { var id = snapshot.id; return this.ajax(this.buildURL(type.modelName, id, snapshot, 'deleteRecord'), "DELETE"); }, - _stripIDFromURL: function(store, snapshot) { + _stripIDFromURL(store, snapshot) { var url = this.buildURL(snapshot.modelName, snapshot.id, snapshot); var expandedURL = url.split('/'); @@ -676,8 +676,8 @@ export default Adapter.extend(BuildURLMixin, { @return {Array} an array of arrays of records, each of which is to be loaded separately by `findMany`. */ - groupRecordsForFindMany: function (store, snapshots) { - var groups = MapWithDefault.create({ defaultValue: function() { return []; } }); + groupRecordsForFindMany(store, snapshots) { + var groups = MapWithDefault.create({ defaultValue() { return []; } }); var adapter = this; var maxURLLength = this.maxURLLength; @@ -745,7 +745,7 @@ export default Adapter.extend(BuildURLMixin, { @param {Object} payload @return {Object | DS.AdapterError} response */ - handleResponse: function(status, headers, payload) { + handleResponse(status, headers, payload) { if (this.isSuccess(status, headers, payload)) { return payload; } else if (this.isInvalid(status, headers, payload)) { @@ -767,7 +767,7 @@ export default Adapter.extend(BuildURLMixin, { @param {Object} payload @return {Boolean} */ - isSuccess: function(status, headers, payload) { + isSuccess(status, headers, payload) { return status >= 200 && status < 300 || status === 304; }, @@ -781,7 +781,7 @@ export default Adapter.extend(BuildURLMixin, { @param {Object} payload @return {Boolean} */ - isInvalid: function(status, headers, payload) { + isInvalid(status, headers, payload) { return status === 422; }, @@ -809,7 +809,7 @@ export default Adapter.extend(BuildURLMixin, { @param {Object} options @return {Promise} promise */ - ajax: function(url, type, options) { + ajax(url, type, options) { var adapter = this; return new Ember.RSVP.Promise(function(resolve, reject) { @@ -864,7 +864,7 @@ export default Adapter.extend(BuildURLMixin, { @param {Object} options @return {Object} */ - ajaxOptions: function(url, type, options) { + ajaxOptions(url, type, options) { var hash = options || {}; hash.url = url; hash.type = type; @@ -892,7 +892,7 @@ export default Adapter.extend(BuildURLMixin, { @param {String} responseText @return {Object} */ - parseErrorResponse: function(responseText) { + parseErrorResponse(responseText) { var json = responseText; try { @@ -910,7 +910,7 @@ export default Adapter.extend(BuildURLMixin, { @param {Object} payload @return {Object} errors payload */ - normalizeErrorResponse: function(status, headers, payload) { + normalizeErrorResponse(status, headers, payload) { if (payload && typeof payload === 'object' && payload.errors) { return payload.errors; } else { diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 8cb8f4f6d71..bd55be8064e 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -122,12 +122,12 @@ export default Ember.Mixin.create({ @param {String} prop the hash has been referenced by @return {Object} the normalized hash **/ - normalize: function(typeClass, hash, prop) { + normalize(typeClass, hash, prop) { var normalizedHash = this._super(typeClass, hash, prop); return this._extractEmbeddedRecords(this, this.store, typeClass, normalizedHash); }, - keyForRelationship: function(key, typeClass, method) { + keyForRelationship(key, typeClass, method) { if ((method === 'serialize' && this.hasSerializeRecordsOption(key)) || (method === 'deserialize' && this.hasDeserializeRecordsOption(key))) { return this.keyForAttribute(key, method); @@ -187,7 +187,7 @@ export default Ember.Mixin.create({ @param {Object} json @param {Object} relationship */ - serializeBelongsTo: function(snapshot, json, relationship) { + serializeBelongsTo(snapshot, json, relationship) { var attr = relationship.key; if (this.noSerializeOptionSpecified(attr)) { this._super(snapshot, json, relationship); @@ -213,7 +213,7 @@ export default Ember.Mixin.create({ } }, - _serializeEmbeddedBelongsTo: function(snapshot, json, relationship) { + _serializeEmbeddedBelongsTo(snapshot, json, relationship) { let embeddedSnapshot = snapshot.belongsTo(relationship.key); let serializedKey = this.keyForAttribute(relationship.key, 'serialize'); if (!embeddedSnapshot) { @@ -313,7 +313,7 @@ export default Ember.Mixin.create({ @param {Object} json @param {Object} relationship */ - serializeHasMany: function(snapshot, json, relationship) { + serializeHasMany(snapshot, json, relationship) { var attr = relationship.key; if (this.noSerializeOptionSpecified(attr)) { this._super(snapshot, json, relationship); @@ -329,7 +329,7 @@ export default Ember.Mixin.create({ } }, - _serializeEmbeddedHasMany: function(snapshot, json, relationship) { + _serializeEmbeddedHasMany(snapshot, json, relationship) { let serializedKey = this.keyForAttribute(relationship.key, 'serialize'); Ember.warn( @@ -344,7 +344,7 @@ export default Ember.Mixin.create({ /* Returns an array of embedded records serialized to JSON */ - _generateSerializedHasMany: function(snapshot, relationship) { + _generateSerializedHasMany(snapshot, relationship) { let hasMany = snapshot.hasMany(relationship.key); return Ember.A(hasMany).map((embeddedSnapshot) => { var embeddedJson = embeddedSnapshot.record.serialize({ includeId: true }); @@ -369,7 +369,7 @@ export default Ember.Mixin.create({ @param {Object} relationship @param {Object} json */ - removeEmbeddedForeignKey: function (snapshot, embeddedSnapshot, relationship, json) { + removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, json) { if (relationship.kind === 'hasMany') { return; } else if (relationship.kind === 'belongsTo') { @@ -386,26 +386,26 @@ export default Ember.Mixin.create({ }, // checks config for attrs option to embedded (always) - serialize and deserialize - hasEmbeddedAlwaysOption: function (attr) { + hasEmbeddedAlwaysOption(attr) { var option = this.attrsOption(attr); return option && option.embedded === 'always'; }, // checks config for attrs option to serialize ids - hasSerializeRecordsOption: function(attr) { + hasSerializeRecordsOption(attr) { var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); var option = this.attrsOption(attr); return alwaysEmbed || (option && (option.serialize === 'records')); }, // checks config for attrs option to serialize records - hasSerializeIdsOption: function(attr) { + hasSerializeIdsOption(attr) { var option = this.attrsOption(attr); return option && (option.serialize === 'ids' || option.serialize === 'id'); }, // checks config for attrs option to serialize records - noSerializeOptionSpecified: function(attr) { + noSerializeOptionSpecified(attr) { var option = this.attrsOption(attr); return !(option && (option.serialize || option.embedded)); }, @@ -413,13 +413,13 @@ export default Ember.Mixin.create({ // checks config for attrs option to deserialize records // a defined option object for a resource is treated the same as // `deserialize: 'records'` - hasDeserializeRecordsOption: function(attr) { + hasDeserializeRecordsOption(attr) { var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); var option = this.attrsOption(attr); return alwaysEmbed || (option && option.deserialize === 'records'); }, - attrsOption: function(attr) { + attrsOption(attr) { var attrs = this.get('attrs'); return attrs && (attrs[camelize(attr)] || attrs[attr]); }, @@ -428,7 +428,7 @@ export default Ember.Mixin.create({ @method _extractEmbeddedRecords @private */ - _extractEmbeddedRecords: function(serializer, store, typeClass, partial) { + _extractEmbeddedRecords(serializer, store, typeClass, partial) { typeClass.eachRelationship((key, relationship) => { if (serializer.hasDeserializeRecordsOption(key)) { if (relationship.kind === "hasMany") { @@ -446,7 +446,7 @@ export default Ember.Mixin.create({ @method _extractEmbeddedHasMany @private */ - _extractEmbeddedHasMany: function(store, key, hash, relationshipMeta) { + _extractEmbeddedHasMany(store, key, hash, relationshipMeta) { let relationshipHash = get(hash, `data.relationships.${key}.data`); if (!relationshipHash) { return; @@ -471,7 +471,7 @@ export default Ember.Mixin.create({ @method _extractEmbeddedBelongsTo @private */ - _extractEmbeddedBelongsTo: function(store, key, hash, relationshipMeta) { + _extractEmbeddedBelongsTo(store, key, hash, relationshipMeta) { let relationshipHash = get(hash, `data.relationships.${key}.data`); if (!relationshipHash) { return; @@ -494,7 +494,7 @@ export default Ember.Mixin.create({ @method _normalizeEmbeddedRelationship @private */ - _normalizeEmbeddedRelationship: function(store, relationshipMeta, relationshipHash) { + _normalizeEmbeddedRelationship(store, relationshipMeta, relationshipHash) { let modelName = relationshipMeta.type; if (relationshipMeta.options.polymorphic) { modelName = relationshipHash.type; diff --git a/addon/serializers/json-api-serializer.js b/addon/serializers/json-api-serializer.js index 8b53ea568c5..1162ecebd95 100644 --- a/addon/serializers/json-api-serializer.js +++ b/addon/serializers/json-api-serializer.js @@ -102,7 +102,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @return {Object} @private */ - _normalizeDocumentHelper: function(documentHash) { + _normalizeDocumentHelper(documentHash) { if (Ember.typeOf(documentHash.data) === 'object') { documentHash.data = this._normalizeResourceHelper(documentHash.data); @@ -123,7 +123,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @return {Object} @private */ - _normalizeRelationshipDataHelper: function(relationshipDataHash) { + _normalizeRelationshipDataHelper(relationshipDataHash) { let type = this.modelNameFromPayloadKey(relationshipDataHash.type); relationshipDataHash.type = type; return relationshipDataHash; @@ -135,7 +135,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @return {Object} @private */ - _normalizeResourceHelper: function(resourceHash) { + _normalizeResourceHelper(resourceHash) { Ember.assert(this.warnMessageForUndefinedType(), !Ember.isNone(resourceHash.type), { id: 'ds.serializer.type-is-undefined' }); @@ -160,7 +160,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {DS.Store} store @param {Object} payload */ - pushPayload: function(store, payload) { + pushPayload(store, payload) { let normalizedPayload = this._normalizeDocumentHelper(payload); store.push(normalizedPayload); }, @@ -176,7 +176,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @return {Object} JSON-API Document @private */ - _normalizeResponse: function(store, primaryModelClass, payload, id, requestType, isSingle) { + _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { let normalizedPayload = this._normalizeDocumentHelper(payload); return normalizedPayload; }, @@ -187,7 +187,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {Object} resourceHash @return {Object} */ - extractAttributes: function(modelClass, resourceHash) { + extractAttributes(modelClass, resourceHash) { var attributes = {}; if (resourceHash.attributes) { @@ -207,7 +207,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {Object} relationshipHash @return {Object} */ - extractRelationship: function(relationshipHash) { + extractRelationship(relationshipHash) { if (Ember.typeOf(relationshipHash.data) === 'object') { relationshipHash.data = this._normalizeRelationshipDataHelper(relationshipHash.data); @@ -226,7 +226,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {Object} resourceHash @return {Object} */ - extractRelationships: function(modelClass, resourceHash) { + extractRelationships(modelClass, resourceHash) { let relationships = {}; if (resourceHash.relationships) { @@ -251,7 +251,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @return {String} @private */ - _extractType: function(modelClass, resourceHash) { + _extractType(modelClass, resourceHash) { return this.modelNameFromPayloadKey(resourceHash.type); }, @@ -260,7 +260,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {String} key @return {String} the model's modelName */ - modelNameFromPayloadKey: function(key) { + modelNameFromPayloadKey(key) { return singularize(normalizeModelName(key)); }, @@ -269,7 +269,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {String} modelName @return {String} */ - payloadKeyFromModelName: function(modelName) { + payloadKeyFromModelName(modelName) { return pluralize(modelName); }, @@ -279,7 +279,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {Object} resourceHash the resource hash from the adapter @return {Object} the normalized resource hash */ - normalize: function(modelClass, resourceHash) { + normalize(modelClass, resourceHash) { if (resourceHash.attributes) { this.normalizeUsingDeclaredMapping(modelClass, resourceHash.attributes); } @@ -326,7 +326,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {String} method @return {String} normalized key */ - keyForAttribute: function(key, method) { + keyForAttribute(key, method) { return dasherize(key); }, @@ -356,7 +356,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {String} method @return {String} normalized key */ - keyForRelationship: function(key, typeClass, method) { + keyForRelationship(key, typeClass, method) { return dasherize(key); }, @@ -366,7 +366,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {Object} options @return {Object} json */ - serialize: function(snapshot, options) { + serialize(snapshot, options) { let data = this._super(...arguments); data.type = this.payloadKeyFromModelName(snapshot.modelName); return { data }; @@ -379,7 +379,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {String} key @param {Object} attribute */ - serializeAttribute: function(snapshot, json, key, attribute) { + serializeAttribute(snapshot, json, key, attribute) { const type = attribute.type; if (this._canSerialize(key)) { @@ -407,7 +407,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {Object} json @param {Object} relationship */ - serializeBelongsTo: function(snapshot, json, relationship) { + serializeBelongsTo(snapshot, json, relationship) { var key = relationship.key; if (this._canSerialize(key)) { @@ -440,7 +440,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {Object} json @param {Object} relationship */ - serializeHasMany: function(snapshot, json, relationship) { + serializeHasMany(snapshot, json, relationship) { var key = relationship.key; if (this._shouldSerializeHasMany(snapshot, key, relationship)) { @@ -469,10 +469,10 @@ const JSONAPISerializer = JSONSerializer.extend({ Ember.runInDebug(function() { JSONAPISerializer.reopen({ - warnMessageForUndefinedType: function() { + warnMessageForUndefinedType() { return 'Encountered a resource object with an undefined type (resolved resource using ' + this.constructor.toString() + ')'; }, - warnMessageNoModelForType: function(modelName, originalType) { + warnMessageNoModelForType(modelName, originalType) { return 'Encountered a resource object with type "' + originalType + '", but no model was found for model name "' + modelName + '" (resolved model name using ' + this.constructor.toString() + '.modelNameFromPayloadKey("' + originalType + '"))'; } }); diff --git a/addon/serializers/json-serializer.js b/addon/serializers/json-serializer.js index 22552cf1b98..69299ccf236 100644 --- a/addon/serializers/json-serializer.js +++ b/addon/serializers/json-serializer.js @@ -182,7 +182,7 @@ export default Serializer.extend({ @param {Object} data The data to transform @return {Object} data The transformed data object */ - applyTransforms: function(typeClass, data) { + applyTransforms(typeClass, data) { typeClass.eachTransformedAttribute((key, typeClass) => { if (!data.hasOwnProperty(key)) { return; } @@ -227,7 +227,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeResponse(store, primaryModelClass, payload, id, requestType) { switch (requestType) { case 'findRecord': return this.normalizeFindRecordResponse(...arguments); @@ -261,7 +261,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeFindRecordResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeFindRecordResponse(store, primaryModelClass, payload, id, requestType) { return this.normalizeSingleResponse(...arguments); }, @@ -274,7 +274,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeQueryRecordResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeQueryRecordResponse(store, primaryModelClass, payload, id, requestType) { return this.normalizeSingleResponse(...arguments); }, @@ -287,7 +287,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeFindAllResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeFindAllResponse(store, primaryModelClass, payload, id, requestType) { return this.normalizeArrayResponse(...arguments); }, @@ -300,7 +300,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeFindBelongsToResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeFindBelongsToResponse(store, primaryModelClass, payload, id, requestType) { return this.normalizeSingleResponse(...arguments); }, @@ -313,7 +313,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeFindHasManyResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeFindHasManyResponse(store, primaryModelClass, payload, id, requestType) { return this.normalizeArrayResponse(...arguments); }, @@ -326,7 +326,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeFindManyResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeFindManyResponse(store, primaryModelClass, payload, id, requestType) { return this.normalizeArrayResponse(...arguments); }, @@ -339,7 +339,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeQueryResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeQueryResponse(store, primaryModelClass, payload, id, requestType) { return this.normalizeArrayResponse(...arguments); }, @@ -352,7 +352,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeCreateRecordResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeCreateRecordResponse(store, primaryModelClass, payload, id, requestType) { return this.normalizeSaveResponse(...arguments); }, @@ -365,7 +365,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeDeleteRecordResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeDeleteRecordResponse(store, primaryModelClass, payload, id, requestType) { return this.normalizeSaveResponse(...arguments); }, @@ -378,7 +378,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeUpdateRecordResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeUpdateRecordResponse(store, primaryModelClass, payload, id, requestType) { return this.normalizeSaveResponse(...arguments); }, @@ -391,7 +391,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeSaveResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeSaveResponse(store, primaryModelClass, payload, id, requestType) { return this.normalizeSingleResponse(...arguments); }, @@ -404,7 +404,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeSingleResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeSingleResponse(store, primaryModelClass, payload, id, requestType) { return this._normalizeResponse(store, primaryModelClass, payload, id, requestType, true); }, @@ -417,7 +417,7 @@ export default Serializer.extend({ @param {String} requestType @return {Object} JSON-API Document */ - normalizeArrayResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) { return this._normalizeResponse(store, primaryModelClass, payload, id, requestType, false); }, @@ -432,7 +432,7 @@ export default Serializer.extend({ @return {Object} JSON-API Document @private */ - _normalizeResponse: function(store, primaryModelClass, payload, id, requestType, isSingle) { + _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { let documentHash = { data: null, included: [] @@ -501,7 +501,7 @@ export default Serializer.extend({ @param {Object} hash @return {Object} */ - normalize: function(modelClass, resourceHash) { + normalize(modelClass, resourceHash) { let data = null; if (resourceHash) { @@ -528,7 +528,7 @@ export default Serializer.extend({ @param {Object} resourceHash @return {String} */ - extractId: function(modelClass, resourceHash) { + extractId(modelClass, resourceHash) { var primaryKey = get(this, 'primaryKey'); var id = resourceHash[primaryKey]; return coerceId(id); @@ -544,7 +544,7 @@ export default Serializer.extend({ @param {Object} resourceHash @return {Object} */ - extractAttributes: function(modelClass, resourceHash) { + extractAttributes(modelClass, resourceHash) { var attributeKey; var attributes = {}; @@ -568,7 +568,7 @@ export default Serializer.extend({ @param {Object} relationshipHash @return {Object} */ - extractRelationship: function(relationshipModelName, relationshipHash) { + extractRelationship(relationshipModelName, relationshipHash) { if (Ember.isNone(relationshipHash)) { return null; } /* When `relationshipHash` is an object it usually means that the relationship @@ -608,7 +608,7 @@ export default Serializer.extend({ @param {Object} relationshipOptions @return {Object} */ - extractPolymorphicRelationship: function(relationshipModelName, relationshipHash, relationshipOptions) { + extractPolymorphicRelationship(relationshipModelName, relationshipHash, relationshipOptions) { return this.extractRelationship(relationshipModelName, relationshipHash); }, @@ -622,7 +622,7 @@ export default Serializer.extend({ @param {Object} resourceHash @return {Object} */ - extractRelationships: function(modelClass, resourceHash) { + extractRelationships(modelClass, resourceHash) { let relationships = {}; modelClass.eachRelationship((key, relationshipMeta) => { @@ -667,7 +667,7 @@ export default Serializer.extend({ @param {String} key @return {String} the model's modelName */ - modelNameFromPayloadKey: function(key) { + modelNameFromPayloadKey(key) { return normalizeModelName(key); }, @@ -676,7 +676,7 @@ export default Serializer.extend({ @method normalizeAttributes @private */ - normalizeAttributes: function(typeClass, hash) { + normalizeAttributes(typeClass, hash) { var payloadKey; if (this.keyForAttribute) { @@ -695,7 +695,7 @@ export default Serializer.extend({ @method normalizeRelationships @private */ - normalizeRelationships: function(typeClass, hash) { + normalizeRelationships(typeClass, hash) { var payloadKey; if (this.keyForRelationship) { @@ -714,7 +714,7 @@ export default Serializer.extend({ @method normalizeUsingDeclaredMapping @private */ - normalizeUsingDeclaredMapping: function(modelClass, hash) { + normalizeUsingDeclaredMapping(modelClass, hash) { var attrs = get(this, 'attrs'); var payloadKey, normalizedKey, key; @@ -749,7 +749,7 @@ export default Serializer.extend({ @param {String} key @return {String} key */ - _getMappedKey: function(key, modelClass) { + _getMappedKey(key, modelClass) { Ember.warn('There is no attribute or relationship with the name `' + key + '` on `' + modelClass.modelName + '`. Check your serializers attrs hash.', get(modelClass, 'attributes').has(key) || get(modelClass, 'relationshipsByName').has(key), { id: 'ds.serializer.no-mapped-attrs-key' }); @@ -780,7 +780,7 @@ export default Serializer.extend({ @param {String} key @return {boolean} true if the key can be serialized */ - _canSerialize: function(key) { + _canSerialize(key) { var attrs = get(this, 'attrs'); return !attrs || !attrs[key] || attrs[key].serialize !== false; @@ -796,7 +796,7 @@ export default Serializer.extend({ @param {String} key @return {boolean} true if the key must be serialized */ - _mustSerialize: function(key) { + _mustSerialize(key) { var attrs = get(this, 'attrs'); return attrs && attrs[key] && attrs[key].serialize === true; @@ -812,7 +812,7 @@ export default Serializer.extend({ @param {String} relationshipType @return {boolean} true if the hasMany relationship should be serialized */ - _shouldSerializeHasMany: function (snapshot, key, relationship) { + _shouldSerializeHasMany(snapshot, key, relationship) { var relationshipType = snapshot.type.determineRelationshipType(relationship, this.store); if (this._mustSerialize(key)) { return true; @@ -973,7 +973,7 @@ export default Serializer.extend({ @param {Object} options @return {Object} json */ - serialize: function(snapshot, options) { + serialize(snapshot, options) { var json = {}; if (options && options.includeId) { @@ -1025,7 +1025,7 @@ export default Serializer.extend({ @param {DS.Snapshot} snapshot @param {Object} options */ - serializeIntoHash: function(hash, typeClass, snapshot, options) { + serializeIntoHash(hash, typeClass, snapshot, options) { merge(hash, this.serialize(snapshot, options)); }, @@ -1054,7 +1054,7 @@ export default Serializer.extend({ @param {String} key @param {Object} attribute */ - serializeAttribute: function(snapshot, json, key, attribute) { + serializeAttribute(snapshot, json, key, attribute) { var type = attribute.type; if (this._canSerialize(key)) { @@ -1103,7 +1103,7 @@ export default Serializer.extend({ @param {Object} json @param {Object} relationship */ - serializeBelongsTo: function(snapshot, json, relationship) { + serializeBelongsTo(snapshot, json, relationship) { var key = relationship.key; if (this._canSerialize(key)) { @@ -1155,7 +1155,7 @@ export default Serializer.extend({ @param {Object} json @param {Object} relationship */ - serializeHasMany: function(snapshot, json, relationship) { + serializeHasMany(snapshot, json, relationship) { var key = relationship.key; if (this._shouldSerializeHasMany(snapshot, key, relationship)) { @@ -1232,7 +1232,7 @@ export default Serializer.extend({ @param {DS.Model} modelClass @param {Object} payload */ - extractMeta: function(store, modelClass, payload) { + extractMeta(store, modelClass, payload) { if (payload && payload.hasOwnProperty('meta')) { let meta = payload.meta; delete payload.meta; @@ -1269,7 +1269,7 @@ export default Serializer.extend({ @param {(String|Number)} id @return {Object} json The deserialized errors */ - extractErrors: function(store, typeClass, payload, id) { + extractErrors(store, typeClass, payload, id) { if (payload && typeof payload === 'object' && payload.errors) { payload = errorsArrayToHash(payload.errors); @@ -1316,7 +1316,7 @@ export default Serializer.extend({ @param {String} method @return {String} normalized key */ - keyForAttribute: function(key, method) { + keyForAttribute(key, method) { return key; }, @@ -1343,7 +1343,7 @@ export default Serializer.extend({ @param {String} method @return {String} normalized key */ - keyForRelationship: function(key, typeClass, method) { + keyForRelationship(key, typeClass, method) { return key; }, @@ -1356,7 +1356,7 @@ export default Serializer.extend({ @param {String} kind `belongsTo` or `hasMany` @return {String} normalized key */ - keyForLink: function(key, kind) { + keyForLink(key, kind) { return key; }, @@ -1369,7 +1369,7 @@ export default Serializer.extend({ @param {Boolean} skipAssertion @return {DS.Transform} transform */ - transformFor: function(attributeType, skipAssertion) { + transformFor(attributeType, skipAssertion) { var transform = getOwner(this).lookup('transform:' + attributeType); Ember.assert("Unable to find transform for '" + attributeType + "'", skipAssertion || !!transform); diff --git a/addon/serializers/rest-serializer.js b/addon/serializers/rest-serializer.js index 256f0a1ce54..0b9325142a0 100644 --- a/addon/serializers/rest-serializer.js +++ b/addon/serializers/rest-serializer.js @@ -80,7 +80,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {String} method @return {String} normalized key */ - keyForPolymorphicType: function(key, typeClass, method) { + keyForPolymorphicType(key, typeClass, method) { var relationshipKey = this.keyForRelationship(key); return `${relationshipKey}Type`; @@ -152,7 +152,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {String} prop @return {Object} */ - normalize: function(modelClass, resourceHash, prop) { + normalize(modelClass, resourceHash, prop) { if (this.normalizeHash && this.normalizeHash[prop]) { this.normalizeHash[prop](resourceHash); } @@ -171,7 +171,7 @@ var RESTSerializer = JSONSerializer.extend({ @return {Object} @private */ - _normalizeArray: function(store, modelName, arrayHash, prop) { + _normalizeArray(store, modelName, arrayHash, prop) { let documentHash = { data: [], included: [] @@ -192,7 +192,7 @@ var RESTSerializer = JSONSerializer.extend({ return documentHash; }, - _normalizePolymorphicRecord: function(store, hash, prop, primaryModelClass, primarySerializer) { + _normalizePolymorphicRecord(store, hash, prop, primaryModelClass, primarySerializer) { let serializer, modelClass; const primaryHasTypeAttribute = modelHasAttributeOrRelationshipNamedType(primaryModelClass); // Support polymorphic records in async relationships @@ -217,7 +217,7 @@ var RESTSerializer = JSONSerializer.extend({ @return {Object} JSON-API Document @private */ - _normalizeResponse: function(store, primaryModelClass, payload, id, requestType, isSingle) { + _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { let documentHash = { data: null, included: [] @@ -338,7 +338,7 @@ var RESTSerializer = JSONSerializer.extend({ return documentHash; }, - isPrimaryType: function(store, typeName, primaryTypeClass) { + isPrimaryType(store, typeName, primaryTypeClass) { var typeClass = store.modelFor(typeName); return typeClass.modelName === primaryTypeClass.modelName; }, @@ -374,7 +374,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {DS.Store} store @param {Object} payload */ - pushPayload: function(store, payload) { + pushPayload(store, payload) { let documentHash = { data: [], included: [] @@ -462,7 +462,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {String} key @return {String} the model's modelName */ - modelNameFromPayloadKey: function(key) { + modelNameFromPayloadKey(key) { return singularize(normalizeModelName(key)); }, @@ -619,7 +619,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {Object} options @return {Object} json */ - serialize: function(snapshot, options) { + serialize(snapshot, options) { return this._super(...arguments); }, @@ -647,7 +647,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {DS.Snapshot} snapshot @param {Object} options */ - serializeIntoHash: function(hash, typeClass, snapshot, options) { + serializeIntoHash(hash, typeClass, snapshot, options) { var normalizedRootKey = this.payloadKeyFromModelName(typeClass.modelName); hash[normalizedRootKey] = this.serialize(snapshot, options); }, @@ -697,7 +697,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {String} modelName @return {String} */ - payloadKeyFromModelName: function(modelName) { + payloadKeyFromModelName(modelName) { return camelize(modelName); }, @@ -711,7 +711,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {Object} json @param {Object} relationship */ - serializePolymorphicType: function(snapshot, json, relationship) { + serializePolymorphicType(snapshot, json, relationship) { var key = relationship.key; var belongsTo = snapshot.belongsTo(key); var typeKey = this.keyForPolymorphicType(key, relationship.type, 'serialize'); @@ -751,7 +751,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {Object} relationshipOptions @return {Object} */ - extractPolymorphicRelationship: function(relationshipType, relationshipHash, relationshipOptions) { + extractPolymorphicRelationship(relationshipType, relationshipHash, relationshipOptions) { var { key, resourceHash, relationshipMeta } = relationshipOptions; // A polymorphic belongsTo relationship can be present in the payload @@ -788,7 +788,7 @@ var RESTSerializer = JSONSerializer.extend({ Ember.runInDebug(function() { RESTSerializer.reopen({ - warnMessageNoModelForKey: function(prop, typeKey) { + warnMessageNoModelForKey(prop, typeKey) { return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + typeKey + '" (resolved model name using ' + this.constructor.toString() + '.modelNameFromPayloadKey("' + prop + '"))'; } }); diff --git a/addon/system/adapter.js b/addon/system/adapter.js index 79a5c418449..a9f1306a677 100644 --- a/addon/system/adapter.js +++ b/addon/system/adapter.js @@ -279,7 +279,7 @@ export default Ember.Object.extend({ @param {Object} options @return {Object} serialized snapshot */ - serialize: function(snapshot, options) { + serialize(snapshot, options) { return get(snapshot.record, 'store').serializerFor(snapshot.modelName).serialize(snapshot, options); }, @@ -454,7 +454,7 @@ export default Ember.Object.extend({ @return {Array} an array of arrays of records, each of which is to be loaded separately by `findMany`. */ - groupRecordsForFindMany: function(store, snapshots) { + groupRecordsForFindMany(store, snapshots) { return [snapshots]; }, @@ -473,7 +473,7 @@ export default Ember.Object.extend({ @param {DS.Snapshot} snapshot @return {Boolean} */ - shouldReloadRecord: function(store, snapshot) { + shouldReloadRecord(store, snapshot) { return false; }, @@ -491,7 +491,7 @@ export default Ember.Object.extend({ @param {DS.SnapshotRecordArray} snapshotRecordArray @return {Boolean} */ - shouldReloadAll: function(store, snapshotRecordArray) { + shouldReloadAll(store, snapshotRecordArray) { return !snapshotRecordArray.length; }, @@ -511,7 +511,7 @@ export default Ember.Object.extend({ @param {DS.Snapshot} snapshot @return {Boolean} */ - shouldBackgroundReloadRecord: function(store, snapshot) { + shouldBackgroundReloadRecord(store, snapshot) { return true; }, @@ -531,7 +531,7 @@ export default Ember.Object.extend({ @param {DS.SnapshotRecordArray} snapshotRecordArray @return {Boolean} */ - shouldBackgroundReloadAll: function(store, snapshotRecordArray) { + shouldBackgroundReloadAll(store, snapshotRecordArray) { return true; } }); diff --git a/addon/system/debug/debug-adapter.js b/addon/system/debug/debug-adapter.js index f414a08cef5..fabed06a7aa 100644 --- a/addon/system/debug/debug-adapter.js +++ b/addon/system/debug/debug-adapter.js @@ -16,7 +16,7 @@ const { assert } = Ember; @private */ export default Ember.DataAdapter.extend({ - getFilters: function() { + getFilters() { return [ { name: 'isNew', desc: 'New' }, { name: 'isModified', desc: 'Modified' }, @@ -24,11 +24,11 @@ export default Ember.DataAdapter.extend({ ]; }, - detect: function(typeClass) { + detect(typeClass) { return typeClass !== Model && Model.detect(typeClass); }, - columnsForType: function(typeClass) { + columnsForType(typeClass) { var columns = [{ name: 'id', desc: 'Id' @@ -43,7 +43,7 @@ export default Ember.DataAdapter.extend({ return columns; }, - getRecords: function(modelClass, modelName) { + getRecords(modelClass, modelName) { if (arguments.length < 2) { // Legacy Ember.js < 1.13 support let containerKey = modelClass._debugContainerKey; @@ -58,7 +58,7 @@ export default Ember.DataAdapter.extend({ return this.get('store').peekAll(modelName); }, - getRecordColumnValues: function(record) { + getRecordColumnValues(record) { var count = 0; var columnValues = { id: get(record, 'id') }; @@ -72,7 +72,7 @@ export default Ember.DataAdapter.extend({ return columnValues; }, - getRecordKeywords: function(record) { + getRecordKeywords(record) { var keywords = []; var keys = Ember.A(['id']); record.eachAttribute((key) => keys.push(key)); @@ -80,7 +80,7 @@ export default Ember.DataAdapter.extend({ return keywords; }, - getRecordFilterValues: function(record) { + getRecordFilterValues(record) { return { isNew: record.get('isNew'), isModified: record.get('hasDirtyAttributes') && !record.get('isNew'), @@ -88,7 +88,7 @@ export default Ember.DataAdapter.extend({ }; }, - getRecordColor: function(record) { + getRecordColor(record) { var color = 'black'; if (record.get('isNew')) { color = 'green'; @@ -98,7 +98,7 @@ export default Ember.DataAdapter.extend({ return color; }, - observeRecord: function(record, recordUpdated) { + observeRecord(record, recordUpdated) { var releaseMethods = Ember.A(); var keysToObserve = Ember.A(['id', 'isNew', 'hasDirtyAttributes']); diff --git a/addon/system/debug/debug-info.js b/addon/system/debug/debug-info.js index 573b8393a05..afd7009c4df 100644 --- a/addon/system/debug/debug-info.js +++ b/addon/system/debug/debug-info.js @@ -18,7 +18,7 @@ Model.reopen({ @for DS.Model @private */ - _debugInfo: function() { + _debugInfo() { var attributes = ['id']; var relationships = { belongsTo: [], hasMany: [] }; var expensiveProperties = []; diff --git a/addon/system/many-array.js b/addon/system/many-array.js index 140a0a46ded..2bf8b5bd300 100644 --- a/addon/system/many-array.js +++ b/addon/system/many-array.js @@ -50,7 +50,7 @@ var set = Ember.set; @uses Ember.MutableArray, Ember.Evented */ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { - init: function() { + init() { this._super(...arguments); this.currentState = Ember.A([]); }, @@ -62,7 +62,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { length: 0, - objectAt: function(index) { + objectAt(index) { //Ember observers such as 'firstObject', 'lastObject' might do out of bounds accesses if (!this.currentState[index]) { return undefined; @@ -70,7 +70,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { return this.currentState[index].getRecord(); }, - flushCanonical: function() { + flushCanonical() { //TODO make this smarter, currently its plenty stupid var toSet = this.canonicalState.filter((internalModel) => !internalModel.isDeleted()); @@ -150,7 +150,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { */ meta: null, - internalReplace: function(idx, amt, objects) { + internalReplace(idx, amt, objects) { if (!objects) { objects = []; } @@ -166,7 +166,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { }, //TODO(Igor) optimize - internalRemoveRecords: function(records) { + internalRemoveRecords(records) { var index; for (var i=0; i < records.length; i++) { index = this.currentState.indexOf(records[i]); @@ -175,14 +175,14 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { }, //TODO(Igor) optimize - internalAddRecords: function(records, idx) { + internalAddRecords(records, idx) { if (idx === undefined) { idx = this.currentState.length; } this.internalReplace(idx, 0, records); }, - replace: function(idx, amt, objects) { + replace(idx, amt, objects) { var records; if (amt > 0) { records = this.currentState.slice(idx, idx+amt); @@ -206,7 +206,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { @param {Number} count @private */ - loadingRecordsCount: function(count) { + loadingRecordsCount(count) { this.loadingRecordsCount = count; }, @@ -214,7 +214,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { @method loadedRecord @private */ - loadedRecord: function() { + loadedRecord() { this.loadingRecordsCount--; if (this.loadingRecordsCount === 0) { set(this, 'isLoaded', true); @@ -226,7 +226,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { @method reload @public */ - reload: function() { + reload() { return this.relationship.reload(); }, @@ -249,7 +249,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { @method save @return {DS.PromiseArray} promise */ - save: function() { + save() { var manyArray = this; var promiseLabel = "DS: ManyArray#save " + get(this, 'type'); var promise = Ember.RSVP.all(this.invoke("save"), promiseLabel).then(function(array) { @@ -267,7 +267,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { @param {Object} hash @return {DS.Model} record */ - createRecord: function(hash) { + createRecord(hash) { var store = get(this, 'store'); var type = get(this, 'type'); var record; diff --git a/addon/system/model/attributes.js b/addon/system/model/attributes.js index fe00babe6c9..8437ef103fe 100644 --- a/addon/system/model/attributes.js +++ b/addon/system/model/attributes.js @@ -158,7 +158,7 @@ Model.reopenClass({ @param {Object} [binding] the value to which the callback's `this` should be bound @static */ - eachAttribute: function(callback, binding) { + eachAttribute(callback, binding) { get(this, 'attributes').forEach((meta, name) => { callback.call(binding, name, meta); }); @@ -208,7 +208,7 @@ Model.reopenClass({ @param {Object} [binding] the value to which the callback's `this` should be bound @static */ - eachTransformedAttribute: function(callback, binding) { + eachTransformedAttribute(callback, binding) { get(this, 'transformedAttributes').forEach((type, name) => { callback.call(binding, name, type); }); @@ -217,7 +217,7 @@ Model.reopenClass({ Model.reopen({ - eachAttribute: function(callback, binding) { + eachAttribute(callback, binding) { this.constructor.eachAttribute(callback, binding); } }); @@ -318,7 +318,7 @@ export default function attr(type, options) { }; return Ember.computed({ - get: function(key) { + get(key) { var internalModel = this._internalModel; if (hasValue(internalModel, key)) { return getValue(internalModel, key); @@ -326,7 +326,7 @@ export default function attr(type, options) { return getDefaultValue(this, options, key); } }, - set: function(key, value) { + set(key, value) { var internalModel = this._internalModel; var oldValue = getValue(internalModel, key); diff --git a/addon/system/model/errors.js b/addon/system/model/errors.js index 1d11f6e0a60..4e26a004f1c 100644 --- a/addon/system/model/errors.js +++ b/addon/system/model/errors.js @@ -109,7 +109,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @param {Function} becameValid @deprecated */ - registerHandlers: function(target, becameInvalid, becameValid) { + registerHandlers(target, becameInvalid, becameValid) { Ember.deprecate( `Record errors will no longer be evented.`, false, { id: 'ds.errors.registerHandlers', @@ -126,7 +126,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method _registerHandlers @private */ - _registerHandlers: function(target, becameInvalid, becameValid) { + _registerHandlers(target, becameInvalid, becameValid) { this.on('becameInvalid', target, becameInvalid); this.on('becameValid', target, becameValid); }, @@ -139,7 +139,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { */ errorsByAttributeName: Ember.computed(function() { return MapWithDefault.create({ - defaultValue: function() { + defaultValue() { return Ember.A(); } }); @@ -163,7 +163,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @param {String} attribute @return {Array} */ - errorsFor: function(attribute) { + errorsFor(attribute) { return get(this, 'errorsByAttributeName').get(attribute); }, @@ -197,7 +197,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method unknownProperty @private */ - unknownProperty: function(attribute) { + unknownProperty(attribute) { var errors = this.errorsFor(attribute); if (isEmpty(errors)) { return null; } return errors; @@ -235,7 +235,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @param {(Array|String)} messages @deprecated */ - add: function(attribute, messages) { + add(attribute, messages) { Ember.warn(`Interacting with a record errors object will no longer change the record state.`, false, { id: 'ds.errors.add' }); @@ -256,7 +256,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method _add @private */ - _add: function(attribute, messages) { + _add(attribute, messages) { messages = this._findOrCreateMessages(attribute, messages); this.addObjects(messages); get(this, 'errorsByAttributeName').get(attribute).addObjects(messages); @@ -268,7 +268,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method _findOrCreateMessages @private */ - _findOrCreateMessages: function(attribute, messages) { + _findOrCreateMessages(attribute, messages) { var errors = this.errorsFor(attribute); return makeArray(messages).map((message) => { @@ -314,7 +314,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @param {String} attribute @deprecated */ - remove: function(attribute) { + remove(attribute) { Ember.warn(`Interacting with a record errors object will no longer change the record state.`, false, { id: 'ds.errors.remove' }); @@ -334,7 +334,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method _remove @private */ - _remove: function(attribute) { + _remove(attribute) { if (get(this, 'isEmpty')) { return; } let content = this.rejectBy('attribute', attribute); @@ -366,7 +366,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method clear @deprecated */ - clear: function() { + clear() { Ember.warn(`Interacting with a record errors object will no longer change the record state.`, false, { id: 'ds.errors.clear' }); @@ -385,7 +385,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method _clear @private */ - _clear: function() { + _clear() { if (get(this, 'isEmpty')) { return; } let errorsByAttributeName = get(this, 'errorsByAttributeName'); @@ -426,7 +426,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @param {String} attribute @return {Boolean} true if there some errors on given attribute */ - has: function(attribute) { + has(attribute) { return !isEmpty(this.errorsFor(attribute)); } }); diff --git a/addon/system/model/internal-model.js b/addon/system/model/internal-model.js index 1f4b30746b4..d87e97facb5 100644 --- a/addon/system/model/internal-model.js +++ b/addon/system/model/internal-model.js @@ -112,7 +112,7 @@ InternalModel.prototype = { dirtyType: retrieveFromCurrentState('dirtyType'), constructor: InternalModel, - materializeRecord: function() { + materializeRecord() { Ember.assert("Materialized " + this.modelName + " record with id:" + this.id + "more than once", this.record === null || this.record === undefined); // lookupFactory should really return an object that creates @@ -138,15 +138,15 @@ InternalModel.prototype = { this._triggerDeferredTriggers(); }, - recordObjectWillDestroy: function() { + recordObjectWillDestroy() { this.record = null; }, - deleteRecord: function() { + deleteRecord() { this.send('deleteRecord'); }, - save: function(options) { + save(options) { var promiseLabel = "DS: Model#save " + this; var resolver = Ember.RSVP.defer(promiseLabel); @@ -154,21 +154,21 @@ InternalModel.prototype = { return resolver.promise; }, - startedReloading: function() { + startedReloading() { this.isReloading = true; if (this.record) { set(this.record, 'isReloading', true); } }, - finishedReloading: function() { + finishedReloading() { this.isReloading = false; if (this.record) { set(this.record, 'isReloading', false); } }, - reload: function() { + reload() { this.startedReloading(); var record = this; var promiseLabel = "DS: Model#reload of " + this; @@ -186,30 +186,30 @@ InternalModel.prototype = { }); }, - getRecord: function() { + getRecord() { if (!this.record) { this.materializeRecord(); } return this.record; }, - unloadRecord: function() { + unloadRecord() { this.send('unloadRecord'); }, - eachRelationship: function(callback, binding) { + eachRelationship(callback, binding) { return this.type.eachRelationship(callback, binding); }, - eachAttribute: function(callback, binding) { + eachAttribute(callback, binding) { return this.type.eachAttribute(callback, binding); }, - inverseFor: function(key) { + inverseFor(key) { return this.type.inverseFor(key); }, - setupData: function(data) { + setupData(data) { var changedKeys = this._changedKeys(data.attributes); merge(this._data, data.attributes); this.pushedData(); @@ -219,18 +219,18 @@ InternalModel.prototype = { this.didInitalizeData(); }, - becameReady: function() { + becameReady() { Ember.run.schedule('actions', this.store.recordArrayManager, this.store.recordArrayManager.recordWasLoaded, this); }, - didInitalizeData: function() { + didInitalizeData() { if (!this.dataHasInitialized) { this.becameReady(); this.dataHasInitialized = true; } }, - destroy: function() { + destroy() { if (this.record) { return this.record.destroy(); } @@ -240,7 +240,7 @@ InternalModel.prototype = { @method createSnapshot @private */ - createSnapshot: function(options) { + createSnapshot(options) { var adapterOptions = options && options.adapterOptions; var snapshot = new Snapshot(this); snapshot.adapterOptions = adapterOptions; @@ -252,7 +252,7 @@ InternalModel.prototype = { @private @param {Promise} promise */ - loadingData: function(promise) { + loadingData(promise) { this.send('loadingData', promise); }, @@ -260,7 +260,7 @@ InternalModel.prototype = { @method loadedData @private */ - loadedData: function() { + loadedData() { this.send('loadedData'); this.didInitalizeData(); }, @@ -269,7 +269,7 @@ InternalModel.prototype = { @method notFound @private */ - notFound: function() { + notFound() { this.send('notFound'); }, @@ -277,16 +277,16 @@ InternalModel.prototype = { @method pushedData @private */ - pushedData: function() { + pushedData() { this.send('pushedData'); }, - flushChangedAttributes: function() { + flushChangedAttributes() { this._inFlightAttributes = this._attributes; this._attributes = new EmptyObject(); }, - hasChangedAttributes: function() { + hasChangedAttributes() { return Object.keys(this._attributes).length > 0; }, @@ -297,7 +297,7 @@ InternalModel.prototype = { This method is needed when data for the internal model is pushed and the pushed data might acknowledge dirty attributes as confirmed. */ - updateChangedAttributes: function() { + updateChangedAttributes() { var changedAttributes = this.changedAttributes(); var changedAttributeNames = Object.keys(changedAttributes); @@ -315,7 +315,7 @@ InternalModel.prototype = { Returns an object, whose keys are changed properties, and value is an [oldProp, newProp] array. */ - changedAttributes: function() { + changedAttributes() { var oldData = this._data; var currentData = this._attributes; var inFlightData = this._inFlightAttributes; @@ -336,7 +336,7 @@ InternalModel.prototype = { @method adapterWillCommit @private */ - adapterWillCommit: function() { + adapterWillCommit() { this.send('willCommit'); }, @@ -344,7 +344,7 @@ InternalModel.prototype = { @method adapterDidDirty @private */ - adapterDidDirty: function() { + adapterDidDirty() { this.send('becomeDirty'); this.updateRecordArraysLater(); }, @@ -355,7 +355,7 @@ InternalModel.prototype = { @param {String} name @param {Object} context */ - send: function(name, context) { + send(name, context) { var currentState = get(this, 'currentState'); if (!currentState[name]) { @@ -365,31 +365,31 @@ InternalModel.prototype = { return currentState[name](this, context); }, - notifyHasManyAdded: function(key, record, idx) { + notifyHasManyAdded(key, record, idx) { if (this.record) { this.record.notifyHasManyAdded(key, record, idx); } }, - notifyHasManyRemoved: function(key, record, idx) { + notifyHasManyRemoved(key, record, idx) { if (this.record) { this.record.notifyHasManyRemoved(key, record, idx); } }, - notifyBelongsToChanged: function(key, record) { + notifyBelongsToChanged(key, record) { if (this.record) { this.record.notifyBelongsToChanged(key, record); } }, - notifyPropertyChange: function(key) { + notifyPropertyChange(key) { if (this.record) { this.record.notifyPropertyChange(key); } }, - rollbackAttributes: function() { + rollbackAttributes() { var dirtyKeys = Object.keys(this._attributes); this._attributes = new EmptyObject(); @@ -425,7 +425,7 @@ InternalModel.prototype = { @private @param {String} name */ - transitionTo: function(name) { + transitionTo(name) { // POSSIBLE TODO: Remove this code and replace with // always having direct reference to state objects @@ -467,7 +467,7 @@ InternalModel.prototype = { this.updateRecordArraysLater(); }, - _unhandledEvent: function(state, name, context) { + _unhandledEvent(state, name, context) { var errorMessage = "Attempted to handle event `" + name + "` "; errorMessage += "on " + String(this) + " while in state "; errorMessage += state.stateName + ". "; @@ -479,7 +479,7 @@ InternalModel.prototype = { throw new Ember.Error(errorMessage); }, - triggerLater: function() { + triggerLater() { var length = arguments.length; var args = new Array(length); @@ -493,7 +493,7 @@ InternalModel.prototype = { Ember.run.scheduleOnce('actions', this, '_triggerDeferredTriggers'); }, - _triggerDeferredTriggers: function() { + _triggerDeferredTriggers() { //TODO: Before 1.0 we want to remove all the events that happen on the pre materialized record, //but for now, we queue up all the events triggered before the record was materialized, and flush //them once we have the record @@ -510,7 +510,7 @@ InternalModel.prototype = { @method clearRelationships @private */ - clearRelationships: function() { + clearRelationships() { this.eachRelationship((name, relationship) => { if (this._relationships.has(name)) { var rel = this._relationships.get(name); @@ -539,7 +539,7 @@ InternalModel.prototype = { @private @param {Object} preload */ - _preloadData: function(preload) { + _preloadData(preload) { //TODO(Igor) consider the polymorphic case Object.keys(preload).forEach((key) => { var preloadValue = get(preload, key); @@ -552,7 +552,7 @@ InternalModel.prototype = { }); }, - _preloadRelationship: function(key, preloadValue) { + _preloadRelationship(key, preloadValue) { var relationshipMeta = this.type.metaForProperty(key); var type = relationshipMeta.type; if (relationshipMeta.kind === 'hasMany') { @@ -562,7 +562,7 @@ InternalModel.prototype = { } }, - _preloadHasMany: function(key, preloadValue, type) { + _preloadHasMany(key, preloadValue, type) { Ember.assert("You need to pass in an array to set a hasMany property on a record", Ember.isArray(preloadValue)); var internalModel = this; @@ -574,7 +574,7 @@ InternalModel.prototype = { this._relationships.get(key).updateRecordsFromAdapter(recordsToSet); }, - _preloadBelongsTo: function(key, preloadValue, type) { + _preloadBelongsTo(key, preloadValue, type) { var recordToSet = this._convertStringOrNumberIntoInternalModel(preloadValue, type); //We use the pathway of setting the hasMany as if it came from the adapter @@ -582,7 +582,7 @@ InternalModel.prototype = { this._relationships.get(key).setRecord(recordToSet); }, - _convertStringOrNumberIntoInternalModel: function(value, type) { + _convertStringOrNumberIntoInternalModel(value, type) { if (typeof value === 'string' || typeof value === 'number') { return this.store._internalModelForId(type, value); } @@ -597,12 +597,12 @@ InternalModel.prototype = { @method updateRecordArrays @private */ - updateRecordArrays: function() { + updateRecordArrays() { this._updatingRecordArraysLater = false; this.store.dataWasUpdated(this.type, this); }, - setId: function(id) { + setId(id) { Ember.assert('A record\'s id cannot be changed once it is in the loaded state', this.id === null || this.id === id || this.isNew()); this.id = id; if (this.record.get('id') !== id) { @@ -610,7 +610,7 @@ InternalModel.prototype = { } }, - didError: function(error) { + didError(error) { this.error = error; this.isError = true; @@ -622,7 +622,7 @@ InternalModel.prototype = { } }, - didCleanError: function() { + didCleanError() { this.error = null; this.isError = false; @@ -640,7 +640,7 @@ InternalModel.prototype = { @method adapterDidCommit */ - adapterDidCommit: function(data) { + adapterDidCommit(data) { if (data) { data = data.attributes; } @@ -667,29 +667,29 @@ InternalModel.prototype = { @method updateRecordArraysLater @private */ - updateRecordArraysLater: function() { + updateRecordArraysLater() { // quick hack (something like this could be pushed into run.once if (this._updatingRecordArraysLater) { return; } this._updatingRecordArraysLater = true; Ember.run.schedule('actions', this, this.updateRecordArrays); }, - addErrorMessageToAttribute: function(attribute, message) { + addErrorMessageToAttribute(attribute, message) { var record = this.getRecord(); get(record, 'errors')._add(attribute, message); }, - removeErrorMessageFromAttribute: function(attribute) { + removeErrorMessageFromAttribute(attribute) { var record = this.getRecord(); get(record, 'errors')._remove(attribute); }, - clearErrorMessages: function() { + clearErrorMessages() { var record = this.getRecord(); get(record, 'errors')._clear(); }, - hasErrors: function() { + hasErrors() { var record = this.getRecord(); var errors = get(record, 'errors'); @@ -702,7 +702,7 @@ InternalModel.prototype = { @method adapterDidInvalidate @private */ - adapterDidInvalidate: function(errors) { + adapterDidInvalidate(errors) { var attribute; for (attribute in errors) { @@ -720,13 +720,13 @@ InternalModel.prototype = { @method adapterDidError @private */ - adapterDidError: function(error) { + adapterDidError(error) { this.send('becameError'); this.didError(error); this._saveWasRejected(); }, - _saveWasRejected: function() { + _saveWasRejected() { var keys = Object.keys(this._inFlightAttributes); for (var i=0; i < keys.length; i++) { if (this._attributes[keys[i]] === undefined) { @@ -777,7 +777,7 @@ InternalModel.prototype = { @method _changedKeys @private */ - _changedKeys: function(updates) { + _changedKeys(updates) { var changedKeys = []; if (updates) { @@ -809,7 +809,7 @@ InternalModel.prototype = { return changedKeys; }, - toString: function() { + toString() { if (this.record) { return this.record.toString(); } else { diff --git a/addon/system/model/model.js b/addon/system/model/model.js index dcc5a8bccdc..aca930d20ab 100644 --- a/addon/system/model/model.js +++ b/addon/system/model/model.js @@ -384,7 +384,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @param {Object} options @return {Object} an object whose values are primitive JSON values only */ - serialize: function(options) { + serialize(options) { return this.store.serialize(this, options); }, @@ -402,7 +402,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @param {Object} options @return {Object} A JSON representation of the object. */ - toJSON: function(options) { + toJSON(options) { // container is for lazy transform lookups var serializer = this.store.serializerFor('-default'); var snapshot = this._internalModel.createSnapshot(); @@ -481,7 +481,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @param {String} name @param {Object} context */ - send: function(name, context) { + send(name, context) { return this._internalModel.send(name, context); }, @@ -490,7 +490,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @private @param {String} name */ - transitionTo: function(name) { + transitionTo(name) { return this._internalModel.transitionTo(name); }, @@ -523,7 +523,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @method deleteRecord */ - deleteRecord: function() { + deleteRecord() { this._internalModel.deleteRecord(); }, @@ -552,7 +552,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @return {Promise} a promise that will be resolved when the adapter returns successfully or rejected if the adapter returns with an error. */ - destroyRecord: function(options) { + destroyRecord(options) { this.deleteRecord(); return this.save(options); }, @@ -561,7 +561,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @method unloadRecord @private */ - unloadRecord: function() { + unloadRecord() { if (this.isDestroyed) { return; } this._internalModel.unloadRecord(); }, @@ -570,7 +570,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @method _notifyProperties @private */ - _notifyProperties: function(keys) { + _notifyProperties(keys) { Ember.beginPropertyChanges(); var key; for (var i = 0, length = keys.length; i < length; i++) { @@ -605,7 +605,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @return {Object} an object, whose keys are changed properties, and value is an [oldProp, newProp] array. */ - changedAttributes: function() { + changedAttributes() { return this._internalModel.changedAttributes(); }, @@ -643,7 +643,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @method rollbackAttributes */ - rollbackAttributes: function() { + rollbackAttributes() { this._internalModel.rollbackAttributes(); }, @@ -651,11 +651,11 @@ var Model = Ember.Object.extend(Ember.Evented, { @method _createSnapshot @private */ - _createSnapshot: function() { + _createSnapshot() { return this._internalModel.createSnapshot(); }, - toStringExtension: function() { + toStringExtension() { return get(this, 'id'); }, @@ -678,7 +678,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @return {Promise} a promise that will be resolved when the adapter returns successfully or rejected if the adapter returns with an error. */ - save: function(options) { + save(options) { return PromiseObject.create({ promise: this._internalModel.save(options).then(() => this) }); @@ -710,7 +710,7 @@ var Model = Ember.Object.extend(Ember.Evented, { adapter returns successfully or rejected if the adapter returns with an error. */ - reload: function() { + reload() { return PromiseObject.create({ promise: this._internalModel.reload().then(() => this) }); @@ -725,7 +725,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @private @param {String} name */ - trigger: function(name) { + trigger(name) { var length = arguments.length; var args = new Array(length - 1); @@ -737,7 +737,7 @@ var Model = Ember.Object.extend(Ember.Evented, { this._super(...arguments); }, - willDestroy: function() { + willDestroy() { //TODO Move! this._super(...arguments); this._internalModel.clearRelationships(); @@ -747,21 +747,21 @@ var Model = Ember.Object.extend(Ember.Evented, { // This is a temporary solution until we refactor DS.Model to not // rely on the data property. - willMergeMixin: function(props) { + willMergeMixin(props) { var constructor = this.constructor; Ember.assert('`' + intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + constructor.toString(), !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0]); Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + constructor.toString(), Object.keys(props).indexOf('id') === -1); }, - attr: function() { + attr() { Ember.assert("The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); }, - belongsTo: function() { + belongsTo() { Ember.assert("The `belongsTo` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); }, - hasMany: function() { + hasMany() { Ember.assert("The `hasMany` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); }, @@ -793,7 +793,7 @@ Model.reopenClass({ @private @static */ - create: function() { + create() { throw new Ember.Error("You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set."); }, diff --git a/addon/system/model/states.js b/addon/system/model/states.js index e4c0cb9997a..a8fff59bb55 100644 --- a/addon/system/model/states.js +++ b/addon/system/model/states.js @@ -240,11 +240,11 @@ var DirtyState = { //loadingData event, though it seems fine? loadingData: Ember.K, - propertyWasReset: function(internalModel, name) { + propertyWasReset(internalModel, name) { if (!internalModel.hasChangedAttributes()) { internalModel.send('rolledBack'); } }, - pushedData: function(internalModel) { + pushedData(internalModel) { internalModel.updateChangedAttributes(); if (!internalModel.hasChangedAttributes()) { @@ -254,23 +254,23 @@ var DirtyState = { becomeDirty: Ember.K, - willCommit: function(internalModel) { + willCommit(internalModel) { internalModel.transitionTo('inFlight'); }, - reloadRecord: function(internalModel, resolve) { + reloadRecord(internalModel, resolve) { resolve(internalModel.store.reloadRecord(internalModel)); }, - rolledBack: function(internalModel) { + rolledBack(internalModel) { internalModel.transitionTo('loaded.saved'); }, - becameInvalid: function(internalModel) { + becameInvalid(internalModel) { internalModel.transitionTo('invalid'); }, - rollback: function(internalModel) { + rollback(internalModel) { internalModel.rollbackAttributes(); internalModel.triggerLater('ready'); } @@ -293,19 +293,19 @@ var DirtyState = { // TODO: More robust semantics around save-while-in-flight willCommit: Ember.K, - didCommit: function(internalModel) { + didCommit(internalModel) { var dirtyType = get(this, 'dirtyType'); internalModel.transitionTo('saved'); internalModel.send('invokeLifecycleCallbacks', dirtyType); }, - becameInvalid: function(internalModel) { + becameInvalid(internalModel) { internalModel.transitionTo('invalid'); internalModel.send('invokeLifecycleCallbacks'); }, - becameError: function(internalModel) { + becameError(internalModel) { internalModel.transitionTo('uncommitted'); internalModel.triggerLater('becameError', internalModel); } @@ -318,11 +318,11 @@ var DirtyState = { isValid: false, // EVENTS - deleteRecord: function(internalModel) { + deleteRecord(internalModel) { internalModel.transitionTo('deleted.uncommitted'); }, - didSetProperty: function(internalModel, context) { + didSetProperty(internalModel, context) { internalModel.removeErrorMessageFromAttribute(context.name); didSetProperty(internalModel, context); @@ -336,22 +336,22 @@ var DirtyState = { becomeDirty: Ember.K, pushedData: Ember.K, - willCommit: function(internalModel) { + willCommit(internalModel) { internalModel.clearErrorMessages(); internalModel.transitionTo('inFlight'); }, - rolledBack: function(internalModel) { + rolledBack(internalModel) { internalModel.clearErrorMessages(); internalModel.transitionTo('loaded.saved'); internalModel.triggerLater('ready'); }, - becameValid: function(internalModel) { + becameValid(internalModel) { internalModel.transitionTo('uncommitted'); }, - invokeLifecycleCallbacks: function(internalModel) { + invokeLifecycleCallbacks(internalModel) { internalModel.triggerLater('becameInvalid', internalModel); } } @@ -452,7 +452,7 @@ var RootState = { // in-flight state, rolling back the record doesn't move // you out of the in-flight state. rolledBack: Ember.K, - unloadRecord: function(internalModel) { + unloadRecord(internalModel) { // clear relationships before moving to deleted state // otherwise it fails internalModel.clearRelationships(); @@ -473,17 +473,17 @@ var RootState = { isEmpty: true, // EVENTS - loadingData: function(internalModel, promise) { + loadingData(internalModel, promise) { internalModel._loadingPromise = promise; internalModel.transitionTo('loading'); }, - loadedData: function(internalModel) { + loadedData(internalModel) { internalModel.transitionTo('loaded.created.uncommitted'); internalModel.triggerLater('ready'); }, - pushedData: function(internalModel) { + pushedData(internalModel) { internalModel.transitionTo('loaded.saved'); internalModel.triggerLater('didLoad'); internalModel.triggerLater('ready'); @@ -500,12 +500,12 @@ var RootState = { // FLAGS isLoading: true, - exit: function(internalModel) { + exit(internalModel) { internalModel._loadingPromise = null; }, // EVENTS - pushedData: function(internalModel) { + pushedData(internalModel) { internalModel.transitionTo('loaded.saved'); internalModel.triggerLater('didLoad'); internalModel.triggerLater('ready'); @@ -513,11 +513,11 @@ var RootState = { internalModel.didCleanError(); }, - becameError: function(internalModel) { + becameError(internalModel) { internalModel.triggerLater('becameError', internalModel); }, - notFound: function(internalModel) { + notFound(internalModel) { internalModel.transitionTo('empty'); } }, @@ -540,7 +540,7 @@ var RootState = { // If there are no local changes to a record, it remains // in the `saved` state. saved: { - setup: function(internalModel) { + setup(internalModel) { if (internalModel.hasChangedAttributes()) { internalModel.adapterDidDirty(); } @@ -551,30 +551,30 @@ var RootState = { pushedData: Ember.K, - becomeDirty: function(internalModel) { + becomeDirty(internalModel) { internalModel.transitionTo('updated.uncommitted'); }, - willCommit: function(internalModel) { + willCommit(internalModel) { internalModel.transitionTo('updated.inFlight'); }, - reloadRecord: function(internalModel, resolve) { + reloadRecord(internalModel, resolve) { resolve(internalModel.store.reloadRecord(internalModel)); }, - deleteRecord: function(internalModel) { + deleteRecord(internalModel) { internalModel.transitionTo('deleted.uncommitted'); }, - unloadRecord: function(internalModel) { + unloadRecord(internalModel) { // clear relationships before moving to deleted state // otherwise it fails internalModel.clearRelationships(); internalModel.transitionTo('deleted.saved'); }, - didCommit: function(internalModel) { + didCommit(internalModel) { internalModel.send('invokeLifecycleCallbacks', get(internalModel, 'lastDirtyType')); }, @@ -606,7 +606,7 @@ var RootState = { isDirty: true, // TRANSITIONS - setup: function(internalModel) { + setup(internalModel) { internalModel.updateRecordArrays(); }, @@ -619,11 +619,11 @@ var RootState = { // EVENTS - willCommit: function(internalModel) { + willCommit(internalModel) { internalModel.transitionTo('inFlight'); }, - rollback: function(internalModel) { + rollback(internalModel) { internalModel.rollbackAttributes(); internalModel.triggerLater('ready'); }, @@ -632,7 +632,7 @@ var RootState = { becomeDirty: Ember.K, deleteRecord: Ember.K, - rolledBack: function(internalModel) { + rolledBack(internalModel) { internalModel.transitionTo('loaded.saved'); internalModel.triggerLater('ready'); } @@ -652,18 +652,18 @@ var RootState = { // TODO: More robust semantics around save-while-in-flight willCommit: Ember.K, - didCommit: function(internalModel) { + didCommit(internalModel) { internalModel.transitionTo('saved'); internalModel.send('invokeLifecycleCallbacks'); }, - becameError: function(internalModel) { + becameError(internalModel) { internalModel.transitionTo('uncommitted'); internalModel.triggerLater('becameError', internalModel); }, - becameInvalid: function(internalModel) { + becameInvalid(internalModel) { internalModel.transitionTo('invalid'); internalModel.triggerLater('becameInvalid', internalModel); } @@ -676,13 +676,13 @@ var RootState = { // FLAGS isDirty: false, - setup: function(internalModel) { + setup(internalModel) { internalModel.clearRelationships(); var store = internalModel.store; store._dematerializeRecord(internalModel); }, - invokeLifecycleCallbacks: function(internalModel) { + invokeLifecycleCallbacks(internalModel) { internalModel.triggerLater('didDelete', internalModel); internalModel.triggerLater('didCommit', internalModel); }, @@ -695,7 +695,7 @@ var RootState = { invalid: { isValid: false, - didSetProperty: function(internalModel, context) { + didSetProperty(internalModel, context) { internalModel.removeErrorMessageFromAttribute(context.name); didSetProperty(internalModel, context); @@ -711,20 +711,20 @@ var RootState = { willCommit: Ember.K, - rolledBack: function(internalModel) { + rolledBack(internalModel) { internalModel.clearErrorMessages(); internalModel.transitionTo('loaded.saved'); internalModel.triggerLater('ready'); }, - becameValid: function(internalModel) { + becameValid(internalModel) { internalModel.transitionTo('uncommitted'); } } }, - invokeLifecycleCallbacks: function(internalModel, dirtyType) { + invokeLifecycleCallbacks(internalModel, dirtyType) { if (dirtyType === 'created') { internalModel.triggerLater('didCreate', internalModel); } else { diff --git a/addon/system/promise-proxies.js b/addon/system/promise-proxies.js index ac53fb5b19a..965e0cd643c 100644 --- a/addon/system/promise-proxies.js +++ b/addon/system/promise-proxies.js @@ -101,7 +101,7 @@ function proxyToContent(method) { } var PromiseManyArray = PromiseArray.extend({ - reload: function() { + reload() { //I don't think this should ever happen right now, but worth guarding if we refactor the async relationships Ember.assert('You are trying to reload an async manyArray before it has been created', get(this, 'content')); return PromiseManyArray.create({ diff --git a/addon/system/record-array-manager.js b/addon/system/record-array-manager.js index 80b85f74ca7..bd9d57a6915 100644 --- a/addon/system/record-array-manager.js +++ b/addon/system/record-array-manager.js @@ -18,9 +18,9 @@ var get = Ember.get; @extends Ember.Object */ export default Ember.Object.extend({ - init: function() { + init() { this.filteredRecordArrays = MapWithDefault.create({ - defaultValue: function() { return []; } + defaultValue() { return []; } }); this.liveRecordArrays = MapWithDefault.create({ @@ -33,13 +33,13 @@ export default Ember.Object.extend({ this._adapterPopulatedRecordArrays = []; }, - recordDidChange: function(record) { + recordDidChange(record) { if (this.changedRecords.push(record) !== 1) { return; } Ember.run.schedule('actions', this, this.updateRecordArrays); }, - recordArraysForRecord: function(record) { + recordArraysForRecord(record) { record._recordArrays = record._recordArrays || OrderedSet.create(); return record._recordArrays; }, @@ -54,7 +54,7 @@ export default Ember.Object.extend({ @method updateRecordArrays */ - updateRecordArrays: function() { + updateRecordArrays() { this.changedRecords.forEach((internalModel) => { if (get(internalModel, 'record.isDestroyed') || get(internalModel, 'record.isDestroying') || (get(internalModel, 'currentState.stateName') === 'root.deleted.saved')) { @@ -67,7 +67,7 @@ export default Ember.Object.extend({ this.changedRecords.length = 0; }, - _recordWasDeleted: function (record) { + _recordWasDeleted(record) { var recordArrays = record._recordArrays; if (!recordArrays) { return; } @@ -78,7 +78,7 @@ export default Ember.Object.extend({ }, - _recordWasChanged: function (record) { + _recordWasChanged(record) { var typeClass = record.type; var recordArrays = this.filteredRecordArrays.get(typeClass); var filter; @@ -89,7 +89,7 @@ export default Ember.Object.extend({ }, //Need to update live arrays on loading - recordWasLoaded: function(record) { + recordWasLoaded(record) { var typeClass = record.type; var recordArrays = this.filteredRecordArrays.get(typeClass); var filter; @@ -113,7 +113,7 @@ export default Ember.Object.extend({ @param {DS.Model} typeClass @param {InternalModel} record */ - updateFilterRecordArray: function(array, filter, typeClass, record) { + updateFilterRecordArray(array, filter, typeClass, record) { var shouldBeInArray = filter(record.getRecord()); var recordArrays = this.recordArraysForRecord(record); if (shouldBeInArray) { @@ -124,7 +124,7 @@ export default Ember.Object.extend({ } }, - _addRecordToRecordArray: function(array, record) { + _addRecordToRecordArray(array, record) { var recordArrays = this.recordArraysForRecord(record); if (!recordArrays.has(array)) { array.addInternalModel(record); @@ -132,7 +132,7 @@ export default Ember.Object.extend({ } }, - populateLiveRecordArray: function(array, modelName) { + populateLiveRecordArray(array, modelName) { var typeMap = this.store.typeMapFor(modelName); var records = typeMap.records; var record; @@ -158,7 +158,7 @@ export default Ember.Object.extend({ @param {String} modelName @param {Function} filter */ - updateFilter: function(array, modelName, filter) { + updateFilter(array, modelName, filter) { var typeMap = this.store.typeMapFor(modelName); var records = typeMap.records; var record; @@ -180,7 +180,7 @@ export default Ember.Object.extend({ @param {Class} typeClass @return {DS.RecordArray} */ - liveRecordArrayFor: function(typeClass) { + liveRecordArrayFor(typeClass) { return this.liveRecordArrays.get(typeClass); }, @@ -191,7 +191,7 @@ export default Ember.Object.extend({ @param {Class} typeClass @return {DS.RecordArray} */ - createRecordArray: function(typeClass) { + createRecordArray(typeClass) { var array = RecordArray.create({ type: typeClass, content: Ember.A(), @@ -212,7 +212,7 @@ export default Ember.Object.extend({ @param {Object} query (optional @return {DS.FilteredRecordArray} */ - createFilteredRecordArray: function(typeClass, filter, query) { + createFilteredRecordArray(typeClass, filter, query) { var array = FilteredRecordArray.create({ query: query, type: typeClass, @@ -235,7 +235,7 @@ export default Ember.Object.extend({ @param {Object} query @return {DS.AdapterPopulatedRecordArray} */ - createAdapterPopulatedRecordArray: function(typeClass, query) { + createAdapterPopulatedRecordArray(typeClass, query) { var array = AdapterPopulatedRecordArray.create({ type: typeClass, query: query, @@ -260,7 +260,7 @@ export default Ember.Object.extend({ @param {DS.Model} typeClass @param {Function} filter */ - registerFilteredRecordArray: function(array, typeClass, filter) { + registerFilteredRecordArray(array, typeClass, filter) { var recordArrays = this.filteredRecordArrays.get(typeClass); recordArrays.push(array); @@ -274,7 +274,7 @@ export default Ember.Object.extend({ @method unregisterRecordArray @param {DS.RecordArray} array */ - unregisterRecordArray: function(array) { + unregisterRecordArray(array) { var typeClass = array.type; // unregister filtered record array @@ -292,7 +292,7 @@ export default Ember.Object.extend({ } }, - willDestroy: function() { + willDestroy() { this._super(...arguments); this.filteredRecordArrays.forEach((value) => flatten(value).forEach(destroy)); diff --git a/addon/system/record-arrays/adapter-populated-record-array.js b/addon/system/record-arrays/adapter-populated-record-array.js index 18a2f868096..796866cf614 100644 --- a/addon/system/record-arrays/adapter-populated-record-array.js +++ b/addon/system/record-arrays/adapter-populated-record-array.js @@ -20,7 +20,7 @@ var get = Ember.get; export default RecordArray.extend({ query: null, - replace: function() { + replace() { var type = get(this, 'type').toString(); throw new Error("The result of a server query (on " + type + ") is immutable."); }, @@ -30,7 +30,7 @@ export default RecordArray.extend({ @param {Array} records @private */ - loadRecords: function(records) { + loadRecords(records) { var store = get(this, 'store'); var type = get(this, 'type'); var modelName = type.modelName; diff --git a/addon/system/record-arrays/filtered-record-array.js b/addon/system/record-arrays/filtered-record-array.js index 85f5b7def2f..7124aa8122e 100644 --- a/addon/system/record-arrays/filtered-record-array.js +++ b/addon/system/record-arrays/filtered-record-array.js @@ -46,7 +46,7 @@ export default RecordArray.extend({ filterFunction: null, isLoaded: true, - replace: function() { + replace() { var type = get(this, 'type').toString(); throw new Error("The result of a client-side filter (on " + type + ") is immutable."); }, @@ -55,7 +55,7 @@ export default RecordArray.extend({ @method updateFilter @private */ - _updateFilter: function() { + _updateFilter() { var manager = get(this, 'manager'); manager.updateFilter(this, get(this, 'type'), get(this, 'filterFunction')); }, diff --git a/addon/system/record-arrays/record-array.js b/addon/system/record-arrays/record-array.js index 0577f2ef3f4..da9e705a5e1 100644 --- a/addon/system/record-arrays/record-array.js +++ b/addon/system/record-arrays/record-array.js @@ -90,7 +90,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @param {Number} index @return {DS.Model} record */ - objectAtContent: function(index) { + objectAtContent(index) { var content = get(this, 'content'); var internalModel = content.objectAt(index); return internalModel && internalModel.getRecord(); @@ -111,7 +111,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method update */ - update: function() { + update() { if (get(this, 'isUpdating')) { return; } var store = get(this, 'store'); @@ -128,7 +128,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @param {InternalModel} internalModel @param {number} an optional index to insert at */ - addInternalModel: function(internalModel, idx) { + addInternalModel(internalModel, idx) { var content = get(this, 'content'); if (idx === undefined) { content.addObject(internalModel); @@ -144,7 +144,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @private @param {InternalModel} internalModel */ - removeInternalModel: function(internalModel) { + removeInternalModel(internalModel) { get(this, 'content').removeObject(internalModel); }, @@ -164,7 +164,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method save @return {DS.PromiseArray} promise */ - save: function() { + save() { var recordArray = this; var promiseLabel = "DS: RecordArray#save " + get(this, 'type'); var promise = Ember.RSVP.all(this.invoke("save"), promiseLabel).then(function(array) { @@ -174,7 +174,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { return PromiseArray.create({ promise: promise }); }, - _dissociateFromOwnRecords: function() { + _dissociateFromOwnRecords() { this.get('content').forEach((record) => { var recordArrays = record._recordArrays; @@ -188,12 +188,12 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method _unregisterFromManager @private */ - _unregisterFromManager: function() { + _unregisterFromManager() { var manager = get(this, 'manager'); manager.unregisterRecordArray(this); }, - willDestroy: function() { + willDestroy() { this._unregisterFromManager(); this._dissociateFromOwnRecords(); set(this, 'content', undefined); diff --git a/addon/system/relationships/belongs-to.js b/addon/system/relationships/belongs-to.js index 76770cd14f6..06e0db9a7bd 100644 --- a/addon/system/relationships/belongs-to.js +++ b/addon/system/relationships/belongs-to.js @@ -100,7 +100,7 @@ export default function belongsTo(modelName, options) { }; return Ember.computed({ - get: function(key) { + get(key) { if (opts.hasOwnProperty('serialize')) { Ember.warn(`You provided a serialize option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.Serializer and it's implementations http://emberjs.com/api/data/classes/DS.Serializer.html`, false, { id: 'ds.model.serialize-option-in-belongs-to' @@ -115,7 +115,7 @@ export default function belongsTo(modelName, options) { return this._internalModel._relationships.get(key).getRecord(); }, - set: function(key, value) { + set(key, value) { if (value === undefined) { value = null; } @@ -137,7 +137,7 @@ export default function belongsTo(modelName, options) { `relationships/ext` to see how these observers get their dependencies. */ Model.reopen({ - notifyBelongsToChanged: function(key) { + notifyBelongsToChanged(key) { this.notifyPropertyChange(key); } }); diff --git a/addon/system/relationships/ext.js b/addon/system/relationships/ext.js index 3da55e6539a..ccd28565ac3 100644 --- a/addon/system/relationships/ext.js +++ b/addon/system/relationships/ext.js @@ -15,7 +15,7 @@ var relationshipsDescriptor = Ember.computed(function() { } var map = new MapWithDefault({ - defaultValue: function() { return []; } + defaultValue() { return []; } }); // Loop through each computed property on the class @@ -124,7 +124,7 @@ Model.reopen({ @param {String} key @param {Ember.ComputedProperty} value */ - didDefineProperty: function(proto, key, value) { + didDefineProperty(proto, key, value) { // Check if the value being set is a computed property. if (value instanceof Ember.ComputedProperty) { @@ -178,7 +178,7 @@ Model.reopenClass({ @param {store} store an instance of DS.Store @return {DS.Model} the type of the relationship, or undefined */ - typeForRelationship: function(name, store) { + typeForRelationship(name, store) { var relationship = get(this, 'relationshipsByName').get(name); return relationship && store.modelFor(relationship.type); }, @@ -216,7 +216,7 @@ Model.reopenClass({ @param {String} name the name of the relationship @return {Object} the inverse relationship, or null */ - inverseFor: function(name, store) { + inverseFor(name, store) { var inverseMap = get(this, 'inverseMap'); if (inverseMap[name]) { return inverseMap[name]; @@ -228,7 +228,7 @@ Model.reopenClass({ }, //Calculate the inverse, ignoring the cache - _findInverseFor: function(name, store) { + _findInverseFor(name, store) { var inverseType = this.typeForRelationship(name, store); if (!inverseType) { @@ -549,7 +549,7 @@ Model.reopenClass({ @param {Function} callback the callback to invoke @param {any} binding the value to which the callback's `this` should be bound */ - eachRelationship: function(callback, binding) { + eachRelationship(callback, binding) { get(this, 'relationshipsByName').forEach((relationship, name) => { callback.call(binding, name, relationship); }); @@ -566,13 +566,13 @@ Model.reopenClass({ @param {Function} callback the callback to invoke @param {any} binding the value to which the callback's `this` should be bound */ - eachRelatedType: function(callback, binding) { + eachRelatedType(callback, binding) { get(this, 'relatedTypes').forEach((type) => { callback.call(binding, type); }); }, - determineRelationshipType: function(knownSide, store) { + determineRelationshipType(knownSide, store) { var knownKey = knownSide.key; var knownKind = knownSide.kind; var inverse = this.inverseFor(knownKey, store); @@ -647,15 +647,15 @@ Model.reopen({ @param {Function} callback the callback to invoke @param {any} binding the value to which the callback's `this` should be bound */ - eachRelationship: function(callback, binding) { + eachRelationship(callback, binding) { this.constructor.eachRelationship(callback, binding); }, - relationshipFor: function(name) { + relationshipFor(name) { return get(this.constructor, 'relationshipsByName').get(name); }, - inverseFor: function(key) { + inverseFor(key) { return this.constructor.inverseFor(key, this.store); } diff --git a/addon/system/relationships/has-many.js b/addon/system/relationships/has-many.js index f0c8db4253f..50e1ea634b6 100644 --- a/addon/system/relationships/has-many.js +++ b/addon/system/relationships/has-many.js @@ -139,11 +139,11 @@ export default function hasMany(type, options) { }; return Ember.computed({ - get: function(key) { + get(key) { var relationship = this._internalModel._relationships.get(key); return relationship.getRecords(); }, - set: function(key, records) { + set(key, records) { Ember.assert("You must pass an array of records to set a hasMany relationship", isArrayLike(records)); Ember.assert(`All elements of a hasMany relationship must be instances of DS.Model, you passed ${Ember.inspect(records)}`, (function() { return Ember.A(records).every((record) => Model.detectInstance(record) ); @@ -158,7 +158,7 @@ export default function hasMany(type, options) { } Model.reopen({ - notifyHasManyAdded: function(key) { + notifyHasManyAdded(key) { //We need to notifyPropertyChange in the adding case because we need to make sure //we fetch the newly added record in case it is unloaded //TODO(Igor): Consider whether we could do this only if the record state is unloaded diff --git a/addon/system/relationships/state/relationship.js b/addon/system/relationships/state/relationship.js index 966bf90e051..db019d1cb82 100644 --- a/addon/system/relationships/state/relationship.js +++ b/addon/system/relationships/state/relationship.js @@ -24,11 +24,11 @@ Relationship.prototype = { destroy: Ember.K, - updateMeta: function(meta) { + updateMeta(meta) { this.meta = meta; }, - clear: function() { + clear() { var members = this.members.list; var member; @@ -38,11 +38,11 @@ Relationship.prototype = { } }, - removeRecords: function(records) { + removeRecords(records) { records.forEach((record) => this.removeRecord(record)); }, - addRecords: function(records, idx) { + addRecords(records, idx) { records.forEach((record) => { this.addRecord(record, idx); if (idx !== undefined) { @@ -51,7 +51,7 @@ Relationship.prototype = { }); }, - addCanonicalRecords: function(records, idx) { + addCanonicalRecords(records, idx) { for (var i=0; i this.store._backburner.schedule('syncRelationships', this, this.flushCanonical)); }, - updateLink: function(link) { + updateLink(link) { Ember.warn(`You have pushed a record of type '${this.record.type.modelName}' with '${this.key}' as a link, but the association is not an async relationship.`, this.isAsync, { id: 'ds.store.push-link-for-sync-relationship' }); @@ -196,7 +196,7 @@ Relationship.prototype = { } }, - findLink: function() { + findLink() { if (this.linkPromise) { return this.linkPromise; } else { @@ -206,7 +206,7 @@ Relationship.prototype = { } }, - updateRecordsFromAdapter: function(records) { + updateRecordsFromAdapter(records) { //TODO(Igor) move this to a proper place //TODO Once we have adapter support, we need to handle updated and canonical changes this.computeChanges(records); @@ -227,7 +227,7 @@ Relationship.prototype = { All relationships for a newly created (`store.createRecord()`) are considered known (`hasData === true`). */ - setHasData: function(value) { + setHasData(value) { this.hasData = value; }, @@ -241,7 +241,7 @@ Relationship.prototype = { Updating the link will automatically set `hasLoaded` to `false`. */ - setHasLoaded: function(value) { + setHasLoaded(value) { this.hasLoaded = value; } }; diff --git a/addon/system/serializer.js b/addon/system/serializer.js index 3bd0eebd04a..254ff4b1297 100644 --- a/addon/system/serializer.js +++ b/addon/system/serializer.js @@ -78,7 +78,7 @@ export default Ember.Object.extend({ @param {Object} hash @return {Object} */ - normalize: function(typeClass, hash) { + normalize(typeClass, hash) { return hash; } diff --git a/addon/system/snapshot.js b/addon/system/snapshot.js index 6f9464fb59f..1bf8050f62f 100644 --- a/addon/system/snapshot.js +++ b/addon/system/snapshot.js @@ -97,7 +97,7 @@ Snapshot.prototype = { @param {String} keyName @return {Object} The attribute value or undefined */ - attr: function(keyName) { + attr(keyName) { if (keyName in this._attributes) { return this._attributes[keyName]; } @@ -117,7 +117,7 @@ Snapshot.prototype = { @method attributes @return {Object} All attributes of the current snapshot */ - attributes: function() { + attributes() { return Ember.copy(this._attributes); }, @@ -135,7 +135,7 @@ Snapshot.prototype = { @method changedAttributes @return {Object} All changed attributes of the current snapshot */ - changedAttributes: function() { + changedAttributes() { let changedAttributes = new EmptyObject(); let changedAttributeKeys = Object.keys(this._changedAttributes); @@ -182,7 +182,7 @@ Snapshot.prototype = { relationship or null if the relationship is known but unset. undefined will be returned if the contents of the relationship is unknown. */ - belongsTo: function(keyName, options) { + belongsTo(keyName, options) { var id = options && options.id; var relationship, inverseRecord, hasData; var result; @@ -253,7 +253,7 @@ Snapshot.prototype = { relationship or an empty array if the relationship is known but unset. undefined will be returned if the contents of the relationship is unknown. */ - hasMany: function(keyName, options) { + hasMany(keyName, options) { var ids = options && options.ids; var relationship, members, hasData; var results; @@ -312,7 +312,7 @@ Snapshot.prototype = { @param {Function} callback the callback to execute @param {Object} [binding] the value to which the callback's `this` should be bound */ - eachAttribute: function(callback, binding) { + eachAttribute(callback, binding) { this.record.eachAttribute(callback, binding); }, @@ -332,7 +332,7 @@ Snapshot.prototype = { @param {Function} callback the callback to execute @param {Object} [binding] the value to which the callback's `this` should be bound */ - eachRelationship: function(callback, binding) { + eachRelationship(callback, binding) { this.record.eachRelationship(callback, binding); }, @@ -341,7 +341,7 @@ Snapshot.prototype = { @param {Object} options @return {Object} an object whose values are primitive JSON values only */ - serialize: function(options) { + serialize(options) { return this.record.store.serializerFor(this.modelName).serialize(this, options); } }; diff --git a/addon/system/store.js b/addon/system/store.js index 8d645d68326..036139155d5 100644 --- a/addon/system/store.js +++ b/addon/system/store.js @@ -215,7 +215,7 @@ Store = Service.extend({ @method init @private */ - init: function() { + init() { this._super(...arguments); this._backburner = new Backburner(['normalizeRelationships', 'syncRelationships', 'finished']); // internal bookkeeping; not observable @@ -260,7 +260,7 @@ Store = Service.extend({ @param {DS.Model} record the record to serialize @param {Object} options an options hash */ - serialize: function(record, options) { + serialize(record, options) { var snapshot = record._internalModel.createSnapshot(); return snapshot.serialize(options); }, @@ -322,7 +322,7 @@ Store = Service.extend({ newly created record. @return {DS.Model} record */ - createRecord: function(modelName, inputProperties) { + createRecord(modelName, inputProperties) { Ember.assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var properties = copy(inputProperties) || new EmptyObject(); @@ -366,7 +366,7 @@ Store = Service.extend({ @param {Object} properties from the new record @return {String} if the adapter can generate one, an ID */ - _generateId: function(modelName, properties) { + _generateId(modelName, properties) { var adapter = this.adapterFor(modelName); if (adapter && adapter.generateIdForRecord) { @@ -396,7 +396,7 @@ Store = Service.extend({ @method deleteRecord @param {DS.Model} record */ - deleteRecord: function(record) { + deleteRecord(record) { record.deleteRecord(); }, @@ -415,7 +415,7 @@ Store = Service.extend({ @method unloadRecord @param {DS.Model} record */ - unloadRecord: function(record) { + unloadRecord(record) { record.unloadRecord(); }, @@ -431,7 +431,7 @@ Store = Service.extend({ @return {Promise} promise @private */ - find: function(modelName, id, options) { + find(modelName, id, options) { // The default `model` hook in Ember.Route calls `find(modelName, id)`, // that's why we have to keep this method around even though `findRecord` is // the public way to get a record by modelName and id. @@ -498,7 +498,7 @@ Store = Service.extend({ @param {Object} options @return {Promise} promise */ - findRecord: function(modelName, id, options) { + findRecord(modelName, id, options) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); Ember.assert(badIdFormatAssertion, (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id))); @@ -514,7 +514,7 @@ Store = Service.extend({ return promiseRecord(fetchedInternalModel, "DS: Store#findRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id')); }, - _findRecord: function(internalModel, options) { + _findRecord(internalModel, options) { // Refetch if the reload option is passed if (options.reload) { return this.scheduleFetch(internalModel, options); @@ -538,7 +538,7 @@ Store = Service.extend({ return Promise.resolve(internalModel); }, - _findByInternalModel: function(internalModel, options) { + _findByInternalModel(internalModel, options) { options = options || {}; if (options.preload) { @@ -550,7 +550,7 @@ Store = Service.extend({ return promiseRecord(fetchedInternalModel, "DS: Store#findRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id')); }, - _findEmptyInternalModel: function(internalModel, options) { + _findEmptyInternalModel(internalModel, options) { if (internalModel.isEmpty()) { return this.scheduleFetch(internalModel, options); } @@ -573,7 +573,7 @@ Store = Service.extend({ @param {Array} ids @return {Promise} promise */ - findByIds: function(modelName, ids) { + findByIds(modelName, ids) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var store = this; @@ -593,7 +593,7 @@ Store = Service.extend({ @return {Promise} promise */ // TODO rename this to have an underscore - fetchRecord: function(internalModel, options) { + fetchRecord(internalModel, options) { var typeClass = internalModel.type; var id = internalModel.id; var adapter = this.adapterFor(typeClass.modelName); @@ -605,12 +605,12 @@ Store = Service.extend({ return promise; }, - scheduleFetchMany: function(records) { + scheduleFetchMany(records) { var internalModels = records.map((record) => record._internalModel); return Promise.all(internalModels.map(this.scheduleFetch, this)); }, - scheduleFetch: function(internalModel, options) { + scheduleFetch(internalModel, options) { var typeClass = internalModel.type; if (internalModel._loadingPromise) { return internalModel._loadingPromise; } @@ -635,7 +635,7 @@ Store = Service.extend({ return promise; }, - flushAllPendingFetches: function() { + flushAllPendingFetches() { if (this.isDestroyed || this.isDestroying) { return; } @@ -644,7 +644,7 @@ Store = Service.extend({ this._pendingFetch = Map.create(); }, - _flushPendingFetchForType: function (pendingFetchItems, typeClass) { + _flushPendingFetchForType(pendingFetchItems, typeClass) { var store = this; var adapter = store.adapterFor(typeClass.modelName); var shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; @@ -752,7 +752,7 @@ Store = Service.extend({ @param {String|Integer} id @return {DS.Model|null} record */ - peekRecord: function(modelName, id) { + peekRecord(modelName, id) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); if (this.hasRecordForId(modelName, id)) { return this._internalModelForId(modelName, id).getRecord(); @@ -773,7 +773,7 @@ Store = Service.extend({ @param {DS.Model} internalModel @return {Promise} promise */ - reloadRecord: function(internalModel) { + reloadRecord(internalModel) { var modelName = internalModel.type.modelName; var adapter = this.adapterFor(modelName); var id = internalModel.id; @@ -793,7 +793,7 @@ Store = Service.extend({ @param {(String|Integer)} inputId @return {Boolean} */ - hasRecordForId: function(modelName, inputId) { + hasRecordForId(modelName, inputId) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var id = coerceId(inputId); @@ -811,12 +811,12 @@ Store = Service.extend({ @param {(String|Integer)} id @return {DS.Model} record */ - recordForId: function(modelName, id) { + recordForId(modelName, id) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); return this._internalModelForId(modelName, id).getRecord(); }, - _internalModelForId: function(typeName, inputId) { + _internalModelForId(typeName, inputId) { var typeClass = this.modelFor(typeName); var id = coerceId(inputId); var idToRecord = this.typeMapFor(typeClass).idToRecord; @@ -837,7 +837,7 @@ Store = Service.extend({ @param {Array} internalModels @return {Promise} promise */ - findMany: function(internalModels) { + findMany(internalModels) { return Promise.all(internalModels.map((internalModel) => this._findByInternalModel(internalModel))); }, @@ -860,7 +860,7 @@ Store = Service.extend({ @param {(Relationship)} relationship @return {Promise} promise */ - findHasMany: function(owner, link, relationship) { + findHasMany(owner, link, relationship) { var adapter = this.adapterFor(owner.type.modelName); Ember.assert("You tried to load a hasMany relationship but you have no adapter (for " + owner.type + ")", adapter); @@ -877,7 +877,7 @@ Store = Service.extend({ @param {Relationship} relationship @return {Promise} promise */ - findBelongsTo: function(owner, link, relationship) { + findBelongsTo(owner, link, relationship) { var adapter = this.adapterFor(owner.type.modelName); Ember.assert("You tried to load a belongsTo relationship but you have no adapter (for " + owner.type + ")", adapter); @@ -934,7 +934,7 @@ Store = Service.extend({ @param {any} query an opaque query to be used by the adapter @return {Promise} promise */ - query: function(modelName, query) { + query(modelName, query) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var array = this.recordArrayManager @@ -964,7 +964,7 @@ Store = Service.extend({ @param {any} query an opaque query to be used by the adapter @return {Promise} promise */ - queryRecord: function(modelName, query) { + queryRecord(modelName, query) { Ember.assert("You need to pass a type to the store's queryRecord method", modelName); Ember.assert("You need to pass a query hash to the store's queryRecord method", query); Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); @@ -1000,7 +1000,7 @@ Store = Service.extend({ @param {Object} options @return {DS.AdapterPopulatedRecordArray} */ - findAll: function(modelName, options) { + findAll(modelName, options) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); @@ -1014,7 +1014,7 @@ Store = Service.extend({ @param {DS.RecordArray} array @return {Promise} promise */ - _fetchAll: function(typeClass, array, options) { + _fetchAll(typeClass, array, options) { options = options || {}; var adapter = this.adapterFor(typeClass.modelName); var sinceToken = this.typeMapFor(typeClass).metadata.since; @@ -1041,7 +1041,7 @@ Store = Service.extend({ @param {DS.Model} typeClass @private */ - didUpdateAll: function(typeClass) { + didUpdateAll(typeClass) { var liveRecordArray = this.recordArrayManager.liveRecordArrayFor(typeClass); set(liveRecordArray, 'isUpdating', false); }, @@ -1069,7 +1069,7 @@ Store = Service.extend({ @param {String} modelName @return {DS.RecordArray} */ - peekAll: function(modelName) { + peekAll(modelName) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); @@ -1092,7 +1092,7 @@ Store = Service.extend({ @method unloadAll @param {String=} modelName */ - unloadAll: function(modelName) { + unloadAll(modelName) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), !modelName || typeof modelName === 'string'); if (arguments.length === 0) { var typeMaps = this.typeMaps; @@ -1173,7 +1173,7 @@ Store = Service.extend({ @param {Function} filter @return {DS.PromiseArray} */ - filter: function(modelName, query, filter) { + filter(modelName, query, filter) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); if (!Ember.ENV.ENABLE_DS_FILTER) { @@ -1224,7 +1224,7 @@ Store = Service.extend({ @param {string} id @return {boolean} */ - recordIsLoaded: function(modelName, id) { + recordIsLoaded(modelName, id) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); return this.hasRecordForId(modelName, id); }, @@ -1235,7 +1235,7 @@ Store = Service.extend({ @return {object} @private */ - _metadataFor: function(modelName) { + _metadataFor(modelName) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); return this.typeMapFor(typeClass).metadata; @@ -1247,7 +1247,7 @@ Store = Service.extend({ @param {Object} metadata metadata to set @private */ - _setMetadataFor: function(modelName, metadata) { + _setMetadataFor(modelName, metadata) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); Ember.merge(this.typeMapFor(typeClass).metadata, metadata); @@ -1268,7 +1268,7 @@ Store = Service.extend({ @param {Class} type @param {InternalModel} internalModel */ - dataWasUpdated: function(type, internalModel) { + dataWasUpdated(type, internalModel) { this.recordArrayManager.recordDidChange(internalModel); }, @@ -1288,7 +1288,7 @@ Store = Service.extend({ @param {Resolver} resolver @param {Object} options */ - scheduleSave: function(internalModel, resolver, options) { + scheduleSave(internalModel, resolver, options) { var snapshot = internalModel.createSnapshot(options); internalModel.flushChangedAttributes(); internalModel.adapterWillCommit(); @@ -1306,7 +1306,7 @@ Store = Service.extend({ @method flushPendingSave @private */ - flushPendingSave: function() { + flushPendingSave() { var pending = this._pendingSave.slice(); this._pendingSave = []; @@ -1344,7 +1344,7 @@ Store = Service.extend({ @param {InternalModel} internalModel the in-flight internal model @param {Object} data optional data (see above) */ - didSaveRecord: function(internalModel, dataArg) { + didSaveRecord(internalModel, dataArg) { var data; if (dataArg) { data = dataArg.data; @@ -1370,7 +1370,7 @@ Store = Service.extend({ @param {InternalModel} internalModel @param {Object} errors */ - recordWasInvalid: function(internalModel, errors) { + recordWasInvalid(internalModel, errors) { internalModel.adapterDidInvalidate(errors); }, @@ -1384,7 +1384,7 @@ Store = Service.extend({ @param {InternalModel} internalModel @param {Error} error */ - recordWasError: function(internalModel, error) { + recordWasError(internalModel, error) { internalModel.adapterDidError(error); }, @@ -1398,7 +1398,7 @@ Store = Service.extend({ @param {InternalModel} internalModel @param {Object} data */ - updateId: function(internalModel, data) { + updateId(internalModel, data) { var oldId = internalModel.id; var id = coerceId(data.id); @@ -1417,7 +1417,7 @@ Store = Service.extend({ @param {DS.Model} typeClass @return {Object} typeMap */ - typeMapFor: function(typeClass) { + typeMapFor(typeClass) { var typeMaps = get(this, 'typeMaps'); var guid = Ember.guidFor(typeClass); var typeMap = typeMaps[guid]; @@ -1448,7 +1448,7 @@ Store = Service.extend({ @param {(String|DS.Model)} type @param {Object} data */ - _load: function(data) { + _load(data) { var internalModel = this._internalModelForId(data.type, data.id); internalModel.setupData(data); @@ -1474,7 +1474,7 @@ Store = Service.extend({ in this case */ - _modelForMixin: function(modelName) { + _modelForMixin(modelName) { var normalizedModelName = normalizeModelName(modelName); // container.registry = 2.1 // container._registry = 1.11 - 2.0 @@ -1504,7 +1504,7 @@ Store = Service.extend({ @param {String} modelName @return {DS.Model} */ - modelFor: function(modelName) { + modelFor(modelName) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var factory = this.modelFactoryFor(modelName); @@ -1520,7 +1520,7 @@ Store = Service.extend({ return factory; }, - modelFactoryFor: function(modelName) { + modelFactoryFor(modelName) { Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var normalizedKey = normalizeModelName(modelName); @@ -1679,7 +1679,7 @@ Store = Service.extend({ @return {DS.Model|Array} the record(s) that was created or updated. */ - push: function(data) { + push(data) { var included = data.included; var i, length; if (included) { @@ -1708,11 +1708,11 @@ Store = Service.extend({ return internalModel.getRecord(); }, - _hasModelFor: function(type) { + _hasModelFor(type) { return getOwner(this)._lookupFactory(`model:${type}`); }, - _pushInternalModel: function(data) { + _pushInternalModel(data) { var modelName = data.type; Ember.assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id != null && data.id !== ''); Ember.assert(`You tried to push data with a type '${modelName}' but no model could be found with that name.`, this._hasModelFor(modelName)); @@ -1744,7 +1744,7 @@ Store = Service.extend({ return internalModel; }, - _setupRelationships: function(record, type, data) { + _setupRelationships(record, type, data) { // If the payload contains relationships that are specified as // IDs, normalizeRelationships will convert them into DS.Model instances // (possibly unloaded) before we push the payload into the @@ -1814,7 +1814,7 @@ Store = Service.extend({ @param {String} modelName Optionally, a model type used to determine which serializer will be used @param {Object} inputPayload */ - pushPayload: function (modelName, inputPayload) { + pushPayload(modelName, inputPayload) { var serializer; var payload; if (!inputPayload) { @@ -1848,7 +1848,7 @@ Store = Service.extend({ @param {Object} payload @return {Object} The normalized payload */ - normalize: function (modelName, payload) { + normalize(modelName, payload) { Ember.assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); var serializer = this.serializerFor(modelName); var model = this.modelFor(modelName); @@ -1866,7 +1866,7 @@ Store = Service.extend({ @param {Object} data @return {InternalModel} internal model */ - buildInternalModel: function(type, id, data) { + buildInternalModel(type, id, data) { var typeMap = this.typeMapFor(type); var idToRecord = typeMap.idToRecord; @@ -1889,7 +1889,7 @@ Store = Service.extend({ }, //Called by the state machine to notify the store that the record is ready to be interacted with - recordWasLoaded: function(record) { + recordWasLoaded(record) { this.recordArrayManager.recordWasLoaded(record); }, @@ -1905,7 +1905,7 @@ Store = Service.extend({ @private @param {InternalModel} internalModel */ - _dematerializeRecord: function(internalModel) { + _dematerializeRecord(internalModel) { var type = internalModel.type; var typeMap = this.typeMapFor(type); var id = internalModel.id; @@ -1941,14 +1941,14 @@ Store = Service.extend({ @param {String} modelName @return DS.Adapter */ - adapterFor: function(modelName) { + adapterFor(modelName) { Ember.assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); return this.lookupAdapter(modelName); }, - _adapterRun: function (fn) { + _adapterRun(fn) { return this._backburner.run(fn); }, @@ -1977,7 +1977,7 @@ Store = Service.extend({ @param {String} modelName the record to serialize @return {DS.Serializer} */ - serializerFor: function(modelName) { + serializerFor(modelName) { Ember.assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); @@ -2006,7 +2006,7 @@ Store = Service.extend({ @param {Array} fallbacks the fallback objects to lookup if the lookup for modelName or 'application' fails @return {Ember.Object} */ - retrieveManagedInstance: function(type, modelName, fallbacks) { + retrieveManagedInstance(type, modelName, fallbacks) { var normalizedModelName = normalizeModelName(modelName); var instance = this._instanceCache.get(type, normalizedModelName, fallbacks); @@ -2014,7 +2014,7 @@ Store = Service.extend({ return instance; }, - lookupAdapter: function(name) { + lookupAdapter(name) { return this.retrieveManagedInstance('adapter', name, this.get('_adapterFallbacks')); }, @@ -2023,11 +2023,11 @@ Store = Service.extend({ return ['application', adapter, '-json-api']; }), - lookupSerializer: function(name, fallbacks) { + lookupSerializer(name, fallbacks) { return this.retrieveManagedInstance('serializer', name, fallbacks); }, - willDestroy: function() { + willDestroy() { this._super(...arguments); this.recordArrayManager.destroy(); diff --git a/addon/system/store/container-instance-cache.js b/addon/system/store/container-instance-cache.js index 6dff1d2a348..c106dd661ed 100644 --- a/addon/system/store/container-instance-cache.js +++ b/addon/system/store/container-instance-cache.js @@ -27,7 +27,7 @@ export default function ContainerInstanceCache(owner) { ContainerInstanceCache.prototype = new EmptyObject(); Ember.merge(ContainerInstanceCache.prototype, { - get: function(type, preferredKey, fallbacks) { + get(type, preferredKey, fallbacks) { let cache = this._cache; let preferredLookupKey = `${type}:${preferredKey}`; @@ -40,7 +40,7 @@ Ember.merge(ContainerInstanceCache.prototype, { return cache[preferredLookupKey]; }, - _findInstance: function(type, fallbacks) { + _findInstance(type, fallbacks) { for (let i = 0, length = fallbacks.length; i < length; i++) { let fallback = fallbacks[i]; let lookupKey = `${type}:${fallback}`; @@ -52,7 +52,7 @@ Ember.merge(ContainerInstanceCache.prototype, { } }, - instanceFor: function(key) { + instanceFor(key) { let cache = this._cache; if (!cache[key]) { let instance = this._owner.lookup(key); @@ -63,7 +63,7 @@ Ember.merge(ContainerInstanceCache.prototype, { return cache[key]; }, - destroy: function() { + destroy() { let cache = this._cache; let cacheEntries = Object.keys(cache); @@ -79,7 +79,7 @@ Ember.merge(ContainerInstanceCache.prototype, { constructor: ContainerInstanceCache, - toString: function() { + toString() { return 'ContainerInstanceCache'; } }); diff --git a/addon/system/store/serializers.js b/addon/system/store/serializers.js index 58f4a976a40..f0e9453bfb5 100644 --- a/addon/system/store/serializers.js +++ b/addon/system/store/serializers.js @@ -7,7 +7,7 @@ export function serializerForAdapter(store, adapter, type) { if (serializer === null || serializer === undefined) { serializer = { - extract: function(store, type, payload) { return payload; } + extract(store, type, payload) { return payload; } }; } diff --git a/addon/transforms/boolean.js b/addon/transforms/boolean.js index c054f395d9c..05b81296cf8 100644 --- a/addon/transforms/boolean.js +++ b/addon/transforms/boolean.js @@ -23,7 +23,7 @@ import Transform from "ember-data/transforms/base"; @namespace DS */ export default Transform.extend({ - deserialize: function(serialized) { + deserialize(serialized) { var type = typeof serialized; if (type === "boolean") { @@ -37,7 +37,7 @@ export default Transform.extend({ } }, - serialize: function(deserialized) { + serialize(deserialized) { return Boolean(deserialized); } }); diff --git a/addon/transforms/date.js b/addon/transforms/date.js index 814dab640d1..f828b634089 100644 --- a/addon/transforms/date.js +++ b/addon/transforms/date.js @@ -21,7 +21,7 @@ import Transform from "ember-data/transforms/base"; export default Transform.extend({ - deserialize: function(serialized) { + deserialize(serialized) { var type = typeof serialized; if (type === "string") { @@ -37,7 +37,7 @@ export default Transform.extend({ } }, - serialize: function(date) { + serialize(date) { if (date instanceof Date) { return date.toISOString(); } else { diff --git a/addon/transforms/number.js b/addon/transforms/number.js index 6463756fc1f..cd8b98b4ef8 100644 --- a/addon/transforms/number.js +++ b/addon/transforms/number.js @@ -29,7 +29,7 @@ function isNumber(value) { @namespace DS */ export default Transform.extend({ - deserialize: function(serialized) { + deserialize(serialized) { var transformed; if (empty(serialized)) { @@ -41,7 +41,7 @@ export default Transform.extend({ } }, - serialize: function(deserialized) { + serialize(deserialized) { var transformed; if (empty(deserialized)) { diff --git a/addon/transforms/string.js b/addon/transforms/string.js index edce67db6a7..75db271fff4 100644 --- a/addon/transforms/string.js +++ b/addon/transforms/string.js @@ -24,10 +24,10 @@ var none = Ember.isNone; @namespace DS */ export default Transform.extend({ - deserialize: function(serialized) { + deserialize(serialized) { return none(serialized) ? null : String(serialized); }, - serialize: function(deserialized) { + serialize(deserialized) { return none(deserialized) ? null : String(deserialized); } }); From 9a57fa05aa6233425b2b04a61bbd1ec65bd4315a Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Fri, 13 Nov 2015 09:55:20 -0500 Subject: [PATCH 1245/2527] [CLEANUP] `ember watson:methodify tests/` Convert to ES6 function declarations in tests. --- .../helpers/ember-assertions/deprecations.js | 4 +- .../method-call-expectation.js | 10 +- .../adapter/build-url-mixin-test.js | 4 +- .../adapter/json-api-adapter-test.js | 4 +- tests/integration/adapter/queries-test.js | 4 +- .../adapter/record-persistence-test.js | 4 +- .../integration/adapter/rest-adapter-test.js | 24 ++-- tests/integration/adapter/serialize-test.js | 4 +- .../integration/adapter/store-adapter-test.js | 10 +- tests/integration/application-test.js | 26 ++--- .../non-dasherized-lookups-test.js | 8 +- .../integration/client-id-generation-test.js | 4 +- tests/integration/debug-adapter-test.js | 6 +- tests/integration/filter-test.js | 30 ++--- tests/integration/inverse-test.js | 4 +- tests/integration/lifecycle-hooks-test.js | 4 +- tests/integration/multiple_stores_test.js | 4 +- tests/integration/peek-all-test.js | 4 +- .../integration/record-array-manager-test.js | 2 +- .../records/collection-save-test.js | 4 +- .../integration/records/delete-record-test.js | 4 +- tests/integration/records/load-test.js | 4 +- .../records/property-changes-test.js | 4 +- tests/integration/records/reload-test.js | 4 +- tests/integration/records/save-test.js | 4 +- tests/integration/records/unload-test.js | 4 +- .../relationships/belongs-to-test.js | 4 +- .../relationships/has-many-test.js | 18 +-- .../relationships/many-to-many-test.js | 4 +- .../relationships/one-to-many-test.js | 4 +- .../relationships/one-to-one-test.js | 4 +- .../polymorphic-mixins-belongs-to-test.js | 4 +- .../polymorphic-mixins-has-many-test.js | 4 +- .../embedded-records-mixin-test.js | 12 +- .../serializers/json-api-serializer-test.js | 4 +- .../serializers/json-serializer-test.js | 24 ++-- .../serializers/rest-serializer-test.js | 24 ++-- tests/integration/setup-container-test.js | 4 +- tests/integration/snapshot-test.js | 4 +- tests/integration/store-test.js | 10 +- .../store/json-api-validation-test.js | 4 +- tests/integration/store/query-record-test.js | 12 +- tests/test-helper.js | 2 +- .../adapter-populated-record-array-test.js | 4 +- .../build-url-mixin/path-for-type-test.js | 4 +- .../adapters/json-api-adapter/ajax-test.js | 10 +- tests/unit/adapters/rest-adapter/ajax-test.js | 6 +- .../group-records-for-find-many-test.js | 6 +- tests/unit/many-array-test.js | 10 +- tests/unit/model-test.js | 22 ++-- tests/unit/model/errors-test.js | 4 +- tests/unit/model/internal-model-test.js | 2 +- tests/unit/model/lifecycle-callbacks-test.js | 30 ++--- tests/unit/model/merge-test.js | 12 +- tests/unit/model/relationships-test.js | 2 +- .../unit/model/relationships/has-many-test.js | 2 +- tests/unit/model/rollback-attributes-test.js | 16 +-- tests/unit/record-array-test.js | 2 +- .../filtered-record-array-test.js | 2 +- tests/unit/states-test.js | 2 +- tests/unit/store/adapter-interop-test.js | 108 +++++++++--------- tests/unit/store/create-record-test.js | 4 +- tests/unit/store/has-record-for-id-test.js | 4 +- tests/unit/store/model-for-test.js | 4 +- tests/unit/store/peek-record-test.js | 4 +- tests/unit/store/push-test.js | 18 +-- tests/unit/store/serializer-for-test.js | 4 +- tests/unit/store/unload-test.js | 10 +- 68 files changed, 311 insertions(+), 311 deletions(-) diff --git a/tests/helpers/ember-assertions/deprecations.js b/tests/helpers/ember-assertions/deprecations.js index 4e7d69e798d..88884daff4a 100644 --- a/tests/helpers/ember-assertions/deprecations.js +++ b/tests/helpers/ember-assertions/deprecations.js @@ -4,7 +4,7 @@ const deprecations = { NONE: 99, // 99 problems and a deprecation ain't one expecteds: null, actuals: null, - stubEmber: function() { + stubEmber() { if (!deprecations.originalEmberDeprecate && Ember.deprecate !== deprecations.originalEmberDeprecate) { deprecations.originalEmberDeprecate = Ember.deprecate; } @@ -13,7 +13,7 @@ const deprecations = { deprecations.actuals.push([msg, test]); }; }, - restoreEmber: function() { + restoreEmber() { Ember.deprecate = deprecations.originalEmberDeprecate; } }; diff --git a/tests/helpers/ember-assertions/method-call-expectation.js b/tests/helpers/ember-assertions/method-call-expectation.js index b7d89ade8fe..05f0d5178e3 100644 --- a/tests/helpers/ember-assertions/method-call-expectation.js +++ b/tests/helpers/ember-assertions/method-call-expectation.js @@ -7,21 +7,21 @@ export default function MethodCallExpectation(target, property, testAssert) { } MethodCallExpectation.prototype = { - handleCall: function() { + handleCall() { this.sawCall = true; return this.originalMethod.apply(this.target, arguments); }, - stubMethod: function(fn) { + stubMethod(fn) { var context = this; this.originalMethod = this.target[this.property]; this.target[this.property] = function() { return context.handleCall.apply(context, arguments); }; }, - restoreMethod: function() { + restoreMethod() { this.target[this.property] = this.originalMethod; }, - runWithStub: function(fn) { + runWithStub(fn) { try { this.stubMethod(); fn(); @@ -29,7 +29,7 @@ MethodCallExpectation.prototype = { this.restoreMethod(); } }, - assert: function(fn) { + assert(fn) { this.runWithStub(); this.testAssert.ok(this.sawCall, "Expected "+this.property+" to be called."); } diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index c01e0865d7f..a1c53ce9737 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -10,7 +10,7 @@ var passedUrl; var run = Ember.run; module("integration/adapter/build-url-mixin - BuildURLMixin with RESTAdapter", { - beforeEach: function() { + beforeEach() { Post = DS.Model.extend({ name: DS.attr("string") }); @@ -156,7 +156,7 @@ test('buildURL - with full URLs in links', function(assert) { test('buildURL - with camelized names', function(assert) { adapter.setProperties({ - pathForType: function(type) { + pathForType(type) { var decamelized = Ember.String.decamelize(type); return Ember.String.underscore(Ember.String.pluralize(decamelized)); } diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index 20e789a13c5..c6d71aed99f 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -13,7 +13,7 @@ var run = Ember.run; var User, Post, Comment, Handle, GithubHandle, TwitterHandle, Company, DevelopmentShop, DesignStudio; module('integration/adapter/json-api-adapter - JSONAPIAdapter', { - beforeEach: function() { + beforeEach() { User = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), @@ -76,7 +76,7 @@ module('integration/adapter/json-api-adapter - JSONAPIAdapter', { adapter = env.adapter; }, - afterEach: function() { + afterEach() { run(env.store, 'destroy'); } }); diff --git a/tests/integration/adapter/queries-test.js b/tests/integration/adapter/queries-test.js index 8045d85b3b1..8557997fba8 100644 --- a/tests/integration/adapter/queries-test.js +++ b/tests/integration/adapter/queries-test.js @@ -10,7 +10,7 @@ var Person, env, store, adapter; var run = Ember.run; module("integration/adapter/queries - Queries", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ updatedAt: DS.attr('string'), name: DS.attr('string'), @@ -23,7 +23,7 @@ module("integration/adapter/queries - Queries", { adapter = env.adapter; }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/adapter/record-persistence-test.js b/tests/integration/adapter/record-persistence-test.js index 1eda625b1c9..d1408bc591a 100644 --- a/tests/integration/adapter/record-persistence-test.js +++ b/tests/integration/adapter/record-persistence-test.js @@ -15,7 +15,7 @@ var all = Ember.RSVP.all; var hash = Ember.RSVP.hash; module("integration/adapter/record_persistence - Persisting Records", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ updatedAt: attr('string'), name: attr('string'), @@ -33,7 +33,7 @@ module("integration/adapter/record_persistence - Persisting Records", { store = env.store; }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index f209197b839..4d99db2543c 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -11,7 +11,7 @@ var run = Ember.run; var get = Ember.get; module("integration/adapter/rest_adapter - REST Adapter", { - beforeEach: function() { + beforeEach() { Post = DS.Model.extend({ name: DS.attr("string") }); @@ -332,7 +332,7 @@ test("create - a serializer's attribute mapping takes precdence over keyForAttri name: 'given_name' }, - keyForAttribute: function(attr) { + keyForAttribute(attr) { return attr.toUpperCase(); } })); @@ -354,7 +354,7 @@ test("create - a serializer's attribute mapping takes precedence over keyForRela post: 'article' }, - keyForRelationship: function(attr, kind) { + keyForRelationship(attr, kind) { return attr.toUpperCase(); } })); @@ -379,7 +379,7 @@ test("create - a serializer's attribute mapping takes precedence over keyForRela comments: 'opinions' }, - keyForRelationship: function(attr, kind) { + keyForRelationship(attr, kind) { return attr.toUpperCase(); } })); @@ -1994,14 +1994,14 @@ test('groupRecordsForFindMany groups records correctly when singular URLs are en test('normalizeKey - to set up _ids and _id', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ - keyForAttribute: function(attr) { + keyForAttribute(attr) { return Ember.String.underscore(attr); }, - keyForBelongsTo: function(belongsTo) { + keyForBelongsTo(belongsTo) { }, - keyForRelationship: function(rel, kind) { + keyForRelationship(rel, kind) { if (kind === 'belongsTo') { var underscored = Ember.String.underscore(rel); return underscored + '_id'; @@ -2166,7 +2166,7 @@ test("calls adapter.handleResponse with the jqXHR and json", function(assert) { var originalAjax = Ember.$.ajax; var jqXHR = { status: 200, - getAllResponseHeaders: function() { return ''; } + getAllResponseHeaders() { return ''; } }; var data = { post: { @@ -2200,7 +2200,7 @@ test('calls handleResponse with jqXHR, jqXHR.responseText', function(assert) { var jqXHR = { status: 400, responseText: 'Nope lol', - getAllResponseHeaders: function() { return ''; } + getAllResponseHeaders() { return ''; } }; Ember.$.ajax = function(hash) { @@ -2228,7 +2228,7 @@ test("rejects promise if DS.AdapterError is returned from adapter.handleResponse assert.expect(3); var originalAjax = Ember.$.ajax; var jqXHR = { - getAllResponseHeaders: function() { return ''; } + getAllResponseHeaders() { return ''; } }; var data = { something: 'is invalid' @@ -2259,7 +2259,7 @@ test('on error appends errorThrown for sanity', function(assert) { var originalAjax = Ember.$.ajax; var jqXHR = { responseText: 'Nope lol', - getAllResponseHeaders: function() { return ''; } + getAllResponseHeaders() { return ''; } }; var errorThrown = new Error('nope!'); @@ -2291,7 +2291,7 @@ test('on error wraps the error string in an DS.AdapterError object', function(as var originalAjax = Ember.$.ajax; var jqXHR = { responseText: '', - getAllResponseHeaders: function() { return ''; } + getAllResponseHeaders() { return ''; } }; var errorThrown = 'nope!'; diff --git a/tests/integration/adapter/serialize-test.js b/tests/integration/adapter/serialize-test.js index 90d3565b87c..de40aa3182d 100644 --- a/tests/integration/adapter/serialize-test.js +++ b/tests/integration/adapter/serialize-test.js @@ -9,7 +9,7 @@ var run = Ember.run; var env, store, adapter, serializer; module("integration/adapter/serialize - DS.Adapter integration test", { - beforeEach: function() { + beforeEach() { var Person = DS.Model.extend({ name: DS.attr('string') }); @@ -20,7 +20,7 @@ module("integration/adapter/serialize - DS.Adapter integration test", { serializer = store.serializerFor('person'); }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 169539001ff..1ccc6c3c418 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -24,7 +24,7 @@ var run = Ember.run; var Person, Dog, env, store, adapter; module("integration/adapter/store-adapter - DS.Store and DS.Adapter integration test", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ updatedAt: DS.attr('string'), name: DS.attr('string'), @@ -41,7 +41,7 @@ module("integration/adapter/store-adapter - DS.Store and DS.Adapter integration adapter = env.adapter; }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); @@ -1346,7 +1346,7 @@ test("An async hasMany relationship with links should not trigger shouldBackgrou post: Post, comment: Comment, adapter: DS.RESTAdapter.extend({ - findRecord: function() { + findRecord() { return { posts: { id: 1, @@ -1355,7 +1355,7 @@ test("An async hasMany relationship with links should not trigger shouldBackgrou } }; }, - findHasMany: function() { + findHasMany() { return Ember.RSVP.resolve({ comments: [ { id: 1, name: "FIRST" }, @@ -1364,7 +1364,7 @@ test("An async hasMany relationship with links should not trigger shouldBackgrou ] }); }, - shouldBackgroundReloadRecord: function() { + shouldBackgroundReloadRecord() { assert.ok(false, 'shouldBackgroundReloadRecord should not be called'); } }) diff --git a/tests/integration/application-test.js b/tests/integration/application-test.js index ca8a01fd5a5..519d359c2fa 100644 --- a/tests/integration/application-test.js +++ b/tests/integration/application-test.js @@ -26,7 +26,7 @@ function lookup(thing) { } module("integration/application - Injecting a Custom Store", { - beforeEach: function() { + beforeEach() { run(function() { app = Application.create({ StoreService: Store.extend({ isCustom: true }), @@ -40,7 +40,7 @@ module("integration/application - Injecting a Custom Store", { container = app.__container__; }, - afterEach: function() { + afterEach() { run(app, app.destroy); Ember.BOOTED = false; } @@ -69,7 +69,7 @@ test("The JSONAPIAdapter is the default adapter when no custom adapter is provid }); module("integration/application - Injecting the Default Store", { - beforeEach: function() { + beforeEach() { run(function() { app = Application.create({ FooController: Controller.extend(), @@ -81,7 +81,7 @@ module("integration/application - Injecting the Default Store", { container = app.__container__; }, - afterEach: function() { + afterEach() { run(app, 'destroy'); Ember.BOOTED = false; } @@ -106,7 +106,7 @@ test("the DS namespace should be accessible", function(assert) { if (Ember.inject && Ember.inject.service) { module("integration/application - Using the store as a service", { - beforeEach: function() { + beforeEach() { run(function() { app = Application.create({ DoodleService: Ember.Service.extend({ store: Ember.inject.service() }) @@ -116,7 +116,7 @@ if (Ember.inject && Ember.inject.service) { container = app.__container__; }, - afterEach: function() { + afterEach() { run(app, 'destroy'); Ember.BOOTED = false; } @@ -131,11 +131,11 @@ if (Ember.inject && Ember.inject.service) { } module("integration/application - Attaching initializer", { - beforeEach: function() { + beforeEach() { App = Application.extend(); }, - afterEach: function() { + afterEach() { if (app) { run(app, app.destroy); } @@ -148,7 +148,7 @@ test("ember-data initializer is run", function(assert) { App.initializer({ name: "after-ember-data", after: "ember-data", - initialize: function() { ran = true; } + initialize() { ran = true; } }); run(function() { @@ -167,7 +167,7 @@ test("ember-data initializer does not register the store service when it was alr App.initializer({ name: "after-ember-data", before: "ember-data", - initialize: function(registry) { + initialize(registry) { registry.register('service:store', AppStore); } }); @@ -187,7 +187,7 @@ test("store initializer is run (DEPRECATED)", function(assert) { App.initializer({ name: "after-store", after: 'store', - initialize: function() { ran = true; } + initialize() { ran = true; } }); run(function() { @@ -202,7 +202,7 @@ test("injectStore initializer is run (DEPRECATED)", function(assert) { App.initializer({ name: "after-store", after: 'injectStore', - initialize: function() { ran = true; } + initialize() { ran = true; } }); run(function() { @@ -217,7 +217,7 @@ test("transforms initializer is run (DEPRECATED)", function(assert) { App.initializer({ name: "after-store", after: 'transforms', - initialize: function() { ran = true; } + initialize() { ran = true; } }); run(function() { diff --git a/tests/integration/backwards-compat/non-dasherized-lookups-test.js b/tests/integration/backwards-compat/non-dasherized-lookups-test.js index f888fd15403..4741ad62c34 100644 --- a/tests/integration/backwards-compat/non-dasherized-lookups-test.js +++ b/tests/integration/backwards-compat/non-dasherized-lookups-test.js @@ -20,7 +20,7 @@ const { let store; module('integration/backwards-compat/non-dasherized-lookups - non dasherized lookups in application code finders', { - beforeEach: function() { + beforeEach() { const PostNote = Model.extend({ name: attr('string') }); @@ -39,7 +39,7 @@ module('integration/backwards-compat/non-dasherized-lookups - non dasherized loo store = env.store; }, - afterEach: function() { + afterEach() { run(store, 'destroy'); } }); @@ -89,7 +89,7 @@ test('can lookup records using under_scored strings', function(assert) { }); module('integration/backwards-compat/non-dasherized-lookups - non dasherized lookups in application code relationship macros', { - beforeEach: function() { + beforeEach() { const PostNote = Model.extend({ notePost: belongsTo('note-post', { async: false }), @@ -122,7 +122,7 @@ module('integration/backwards-compat/non-dasherized-lookups - non dasherized loo store = env.store; }, - afterEach: function() { + afterEach() { run(store, 'destroy'); } }); diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index 0f7c4ee2e06..72f008b5afa 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -10,7 +10,7 @@ var Post, Comment, Misc, env; var run = Ember.run; module("integration/client_id_generation - Client-side ID Generation", { - beforeEach: function() { + beforeEach() { Comment = DS.Model.extend({ post: DS.belongsTo('post', { async: false }) }); @@ -30,7 +30,7 @@ module("integration/client_id_generation - Client-side ID Generation", { }); }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index 4b08bce091f..41631bb2670 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -9,7 +9,7 @@ var get = Ember.get; var run = Ember.run; module("DS.DebugAdapter", { - beforeEach: function() { + beforeEach() { Ember.run(function() { App = Ember.Application.create(); App.toString = function() { return 'App'; }; @@ -35,12 +35,12 @@ module("DS.DebugAdapter", { debugAdapter = App.__container__.lookup('data-adapter:main'); debugAdapter.reopen({ - getModelTypes: function() { + getModelTypes() { return Ember.A([{ klass: App.__container__.lookupFactory('model:post'), name: 'post' }]); } }); }, - afterEach: function() { + afterEach() { run(App, App.destroy); } }); diff --git a/tests/integration/filter-test.js b/tests/integration/filter-test.js index 846b56cd646..3f359de96d6 100644 --- a/tests/integration/filter-test.js +++ b/tests/integration/filter-test.js @@ -14,7 +14,7 @@ var run = Ember.run; var Person, store, env, array, recordArray; module("integration/filter - DS.Model updating", { - beforeEach: function() { + beforeEach() { array = [{ id: '1', type: 'person', @@ -47,7 +47,7 @@ module("integration/filter - DS.Model updating", { env = setupStore({ person: Person }); store = env.store; }, - afterEach: function() { + afterEach() { run(store, 'destroy'); Person = null; array = null; @@ -210,7 +210,7 @@ test("a filtered record array includes created elements", function(assert) { test("a Record Array can update its filter", function(assert) { customAdapter(env, DS.Adapter.extend({ - deleteRecord: function(store, type, snapshot) { + deleteRecord(store, type, snapshot) { return Ember.RSVP.resolve(); }, shouldBackgroundReloadRecord: () => false @@ -284,7 +284,7 @@ test("a Record Array can update its filter", function(assert) { test("a Record Array can update its filter and notify array observers", function(assert) { customAdapter(env, DS.Adapter.extend({ - deleteRecord: function(store, type, snapshot) { + deleteRecord(store, type, snapshot) { return Ember.RSVP.resolve(); }, shouldBackgroundReloadRecord: () => false @@ -319,7 +319,7 @@ test("a Record Array can update its filter and notify array observers", function var arrayObserver = { arrayWillChange: Ember.K, - arrayDidChange: function(array, idx, removed, added) { + arrayDidChange(array, idx, removed, added) { didChangeIdx = idx; didChangeRemoved += removed; didChangeAdded += added; @@ -461,7 +461,7 @@ test("a filter created after a record is already loaded works", function(assert) test("filter with query persists query on the resulting filteredRecordArray", function(assert) { customAdapter(env, DS.Adapter.extend({ - query: function(store, type, id) { + query(store, type, id) { return Ember.RSVP.resolve([{ id: id, name: "Tom Dale" @@ -489,7 +489,7 @@ test("it is possible to filter by state flags", function(assert) { var filter; customAdapter(env, DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: id, name: "Tom Dale" }); } })); @@ -519,7 +519,7 @@ test("it is possible to filter by state flags", function(assert) { test("it is possible to filter loaded records by dirtiness", function(assert) { customAdapter(env, DS.Adapter.extend({ - updateRecord: function() { + updateRecord() { return Ember.RSVP.resolve(); }, shouldBackgroundReloadRecord: () => false @@ -561,7 +561,7 @@ test("it is possible to filter loaded records by dirtiness", function(assert) { test("it is possible to filter created records by dirtiness", function(assert) { run(function() { customAdapter(env, DS.Adapter.extend({ - createRecord: function() { + createRecord() { return Ember.RSVP.resolve(); }, shouldBackgroundReloadRecord: () => false @@ -596,7 +596,7 @@ test("it is possible to filter created records by dirtiness", function(assert) { test("it is possible to filter created records by isReloading", function(assert) { customAdapter(env, DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Tom Dalle" @@ -669,7 +669,7 @@ var setup = function(assert, serverCallbacks) { test("a Record Array can update its filter after server-side updates one record", function(assert) { setup(assert, { - updateRecord: function(store, type, snapshot) { + updateRecord(store, type, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Scumbag Server-side Dale" }); }, shouldBackgroundReloadRecord: () => false @@ -684,7 +684,7 @@ test("a Record Array can update its filter after server-side updates one record" test("a Record Array can update its filter after server-side updates multiple records", function(assert) { setup(assert, { - updateRecord: function(store, type, snapshot) { + updateRecord(store, type, snapshot) { switch (snapshot.id) { case "1": return Ember.RSVP.resolve({ id: 1, name: "Scumbag Server-side Dale" }); @@ -704,7 +704,7 @@ test("a Record Array can update its filter after server-side updates multiple re test("a Record Array can update its filter after server-side creates one record", function(assert) { setup(assert, { - createRecord: function(store, type, snapshot) { + createRecord(store, type, snapshot) { return Ember.RSVP.resolve({ id: 4, name: "Scumbag Server-side Tim" }); } }); @@ -718,7 +718,7 @@ test("a Record Array can update its filter after server-side creates one record" test("a Record Array can update its filter after server-side creates multiple records", function(assert) { setup(assert, { - createRecord: function(store, type, snapshot) { + createRecord(store, type, snapshot) { switch (snapshot.attr('name')) { case "Client-side Mike": return Ember.RSVP.resolve({ id: 4, name: "Scumbag Server-side Mike" }); @@ -737,7 +737,7 @@ test("a Record Array can update its filter after server-side creates multiple re test("a Record Array can update its filter after server-side creates multiple records", function(assert) { setup(assert, { - createRecord: function(store, type, snapshot) { + createRecord(store, type, snapshot) { switch (snapshot.attr('name')) { case "Client-side Mike": return Ember.RSVP.resolve({ id: 4, name: "Scumbag Server-side Mike" }); diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index c1d7b8f1e72..dab9266bce3 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -16,7 +16,7 @@ function stringify(string) { } module('integration/inverse_test - inverseFor', { - beforeEach: function() { + beforeEach() { User = DS.Model.extend({ name: attr('string'), bestFriend: belongsTo('user', { async: true, inverse: null }), @@ -51,7 +51,7 @@ module('integration/inverse_test - inverseFor', { ReflexiveModel = store.modelFor('reflexive-model'); }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/lifecycle-hooks-test.js b/tests/integration/lifecycle-hooks-test.js index 4dec8fd5522..35ad90e0823 100644 --- a/tests/integration/lifecycle-hooks-test.js +++ b/tests/integration/lifecycle-hooks-test.js @@ -11,7 +11,7 @@ var resolve = Ember.RSVP.resolve; var run = Ember.run; module("integration/lifecycle_hooks - Lifecycle Hooks", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ name: attr('string') }); @@ -21,7 +21,7 @@ module("integration/lifecycle_hooks - Lifecycle Hooks", { }); }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/multiple_stores_test.js b/tests/integration/multiple_stores_test.js index c959862e5bf..c7708821b92 100644 --- a/tests/integration/multiple_stores_test.js +++ b/tests/integration/multiple_stores_test.js @@ -9,7 +9,7 @@ var SuperVillain, HomePlanet, EvilMinion; var run = Ember.run; module("integration/multiple_stores - Multiple Stores Tests", { - setup: function() { + setup() { SuperVillain = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), @@ -41,7 +41,7 @@ module("integration/multiple_stores - Multiple Stores Tests", { env.store_b = env.container.lookup('store:store-b'); }, - teardown: function() { + teardown() { run(env.store, 'destroy'); } }); diff --git a/tests/integration/peek-all-test.js b/tests/integration/peek-all-test.js index 263c81d2a27..b505d0a8a2e 100644 --- a/tests/integration/peek-all-test.js +++ b/tests/integration/peek-all-test.js @@ -11,7 +11,7 @@ var run = Ember.run; var Person, store, array, moreArray; module("integration/peek-all - DS.Store#peekAll()", { - beforeEach: function() { + beforeEach() { array = { data: [{ type: 'person', @@ -41,7 +41,7 @@ module("integration/peek-all - DS.Store#peekAll()", { store = createStore({ person: Person }); }, - afterEach: function() { + afterEach() { run(store, 'destroy'); Person = null; array = null; diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index fafc0a741f2..a0906991a60 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -26,7 +26,7 @@ Car.toString = function() { return "Car"; }; var manager; module("integration/record_array_manager", { - beforeEach: function() { + beforeEach() { env = setupStore({ adapter: DS.RESTAdapter.extend() }); diff --git a/tests/integration/records/collection-save-test.js b/tests/integration/records/collection-save-test.js index 96725228daa..cf35717c74d 100644 --- a/tests/integration/records/collection-save-test.js +++ b/tests/integration/records/collection-save-test.js @@ -9,7 +9,7 @@ var Post, env; var run = Ember.run; module("integration/records/collection_save - Save Collection of Records", { - beforeEach: function() { + beforeEach() { Post = DS.Model.extend({ title: DS.attr('string') }); @@ -19,7 +19,7 @@ module("integration/records/collection_save - Save Collection of Records", { env = setupStore({ post: Post }); }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index ee4ef87ccf1..54e9a86b8ff 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -10,7 +10,7 @@ var Person, env; var run = Ember.run; module("integration/deletedRecord - Deleting Records", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ name: attr('string') }); @@ -22,7 +22,7 @@ module("integration/deletedRecord - Deleting Records", { }); }, - afterEach: function() { + afterEach() { Ember.run(function() { env.container.destroy(); }); diff --git a/tests/integration/records/load-test.js b/tests/integration/records/load-test.js index 690adc61cc3..c2dd0dd7eb5 100644 --- a/tests/integration/records/load-test.js +++ b/tests/integration/records/load-test.js @@ -10,7 +10,7 @@ var Post, Comment, env; var run = Ember.run; module("integration/load - Loading Records", { - beforeEach: function() { + beforeEach() { Post = DS.Model.extend({ comments: hasMany({ async: true }) }); @@ -23,7 +23,7 @@ module("integration/load - Loading Records", { env = setupStore({ post: Post, comment: Comment }); }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/records/property-changes-test.js b/tests/integration/records/property-changes-test.js index 66fec67ba61..212fd19f3c7 100644 --- a/tests/integration/records/property-changes-test.js +++ b/tests/integration/records/property-changes-test.js @@ -10,7 +10,7 @@ var attr = DS.attr; var run = Ember.run; module('integration/records/property-changes - Property changes', { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ firstName: attr('string'), lastName: attr('string') @@ -23,7 +23,7 @@ module('integration/records/property-changes - Property changes', { store = env.store; }, - afterEach: function() { + afterEach() { Ember.run(function() { env.container.destroy(); }); diff --git a/tests/integration/records/reload-test.js b/tests/integration/records/reload-test.js index 8252bb714d6..4e5af020d77 100644 --- a/tests/integration/records/reload-test.js +++ b/tests/integration/records/reload-test.js @@ -11,7 +11,7 @@ var Person, env; var run = Ember.run; module("integration/reload - Reloading Records", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ updatedAt: attr('string'), name: attr('string'), @@ -24,7 +24,7 @@ module("integration/reload - Reloading Records", { env = setupStore({ person: Person }); }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/records/save-test.js b/tests/integration/records/save-test.js index a8e09a5ce82..b467c676e01 100644 --- a/tests/integration/records/save-test.js +++ b/tests/integration/records/save-test.js @@ -9,7 +9,7 @@ var Post, env; var run = Ember.run; module("integration/records/save - Save Record", { - beforeEach: function() { + beforeEach() { Post = DS.Model.extend({ title: DS.attr('string') }); @@ -19,7 +19,7 @@ module("integration/records/save - Save Record", { env = setupStore({ post: Post }); }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 619378f2fc9..2a145a02047 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -33,7 +33,7 @@ var Car = DS.Model.extend({ Car.toString = function() { return "Car"; }; module("integration/unload - Unloading Records", { - beforeEach: function() { + beforeEach() { env = setupStore({ person: Person, car: Car, @@ -41,7 +41,7 @@ module("integration/unload - Unloading Records", { }); }, - afterEach: function() { + afterEach() { Ember.run(function() { env.container.destroy(); }); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 507dd9998a1..66949a24a98 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -30,7 +30,7 @@ function getComputedPropertyDesc(model, key) { } module("integration/relationship/belongs_to Belongs-To Relationships", { - beforeEach: function() { + beforeEach() { User = DS.Model.extend({ name: attr('string'), messages: hasMany('message', { polymorphic: true, async: false }), @@ -98,7 +98,7 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { Author = store.modelFor('author'); }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 2828d6da6b9..122873d950b 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -20,7 +20,7 @@ function stringify(string) { } module("integration/relationships/has_many - Has-Many Relationships", { - beforeEach: function() { + beforeEach() { User = DS.Model.extend({ name: attr('string'), messages: hasMany('message', { polymorphic: true, async: false }), @@ -91,7 +91,7 @@ module("integration/relationships/has_many - Has-Many Relationships", { store = env.store; }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); @@ -1766,12 +1766,12 @@ test("ManyArray notifies the array observers and flushes bindings when removing" chapter = env.store.peekRecord('chapter', 1); chapter.get('pages').addEnumerableObserver(this, { - willChange: function(pages, removing, addCount) { + willChange(pages, removing, addCount) { if (observe) { assert.equal(removing[0], page2, 'page2 is passed to willChange'); } }, - didChange: function(pages, removeCount, adding) { + didChange(pages, removeCount, adding) { if (observe) { assert.equal(removeCount, 1, 'removeCount is correct'); } @@ -1824,12 +1824,12 @@ test("ManyArray notifies the array observers and flushes bindings when adding", chapter = env.store.peekRecord('chapter', 1); chapter.get('pages').addEnumerableObserver(this, { - willChange: function(pages, removing, addCount) { + willChange(pages, removing, addCount) { if (observe) { assert.equal(addCount, 1, 'addCount is correct'); } }, - didChange: function(pages, removeCount, adding) { + didChange(pages, removeCount, adding) { if (observe) { assert.equal(adding[0], page2, 'page2 is passed to didChange'); } @@ -2006,13 +2006,13 @@ test("adding and removing records from hasMany relationship #2666", function(ass }); env.registry.register('adapter:comment', DS.RESTAdapter.extend({ - deleteRecord: function(record) { + deleteRecord(record) { return Ember.RSVP.resolve(); }, - updateRecord: function(record) { + updateRecord(record) { return Ember.RSVP.resolve(); }, - createRecord: function() { + createRecord() { return Ember.RSVP.resolve(); } })); diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index 45b6400b455..e2eb3499bfb 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -16,7 +16,7 @@ function stringify(string) { } module('integration/relationships/many_to_many_test - ManyToMany relationships', { - beforeEach: function() { + beforeEach() { User = DS.Model.extend({ name: attr('string'), topics: hasMany('topic', { async: true }), @@ -51,7 +51,7 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships', store = env.store; }, - afterEach: function() { + afterEach() { run(function() { env.container.destroy(); }); diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index e6c5c92d9ff..d9eb6f073dd 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -18,7 +18,7 @@ function stringify(string) { } module('integration/relationships/one_to_many_test - OneToMany relationships', { - beforeEach: function() { + beforeEach() { User = DS.Model.extend({ name: attr('string'), messages: hasMany('message', { async: true }), @@ -50,7 +50,7 @@ module('integration/relationships/one_to_many_test - OneToMany relationships', { store = env.store; }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/relationships/one-to-one-test.js b/tests/integration/relationships/one-to-one-test.js index 91ab933dd8d..500eec53a81 100644 --- a/tests/integration/relationships/one-to-one-test.js +++ b/tests/integration/relationships/one-to-one-test.js @@ -16,7 +16,7 @@ function stringify(string) { } module('integration/relationships/one_to_one_test - OneToOne relationships', { - beforeEach: function() { + beforeEach() { User = DS.Model.extend({ name: attr('string'), bestFriend: belongsTo('user', { async: true, inverse: 'bestFriend' }), @@ -41,7 +41,7 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', { store = env.store; }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index 2f7624477be..7be85133732 100644 --- a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -16,7 +16,7 @@ function stringify(string) { } module('integration/relationships/polymorphic_mixins_belongs_to_test - Polymorphic belongsTo relationships with mixins', { - beforeEach: function() { + beforeEach() { User = DS.Model.extend({ name: attr('string'), bestMessage: belongsTo('message', { async: true, polymorphic: true }) @@ -47,7 +47,7 @@ module('integration/relationships/polymorphic_mixins_belongs_to_test - Polymorph store = env.store; }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js index d528b00cc71..ef06a8bb159 100644 --- a/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -17,7 +17,7 @@ function stringify(string) { } module('integration/relationships/polymorphic_mixins_has_many_test - Polymorphic hasMany relationships with mixins', { - beforeEach: function() { + beforeEach() { User = DS.Model.extend({ name: attr('string'), messages: hasMany('message', { async: true, polymorphic: true }) @@ -48,7 +48,7 @@ module('integration/relationships/polymorphic_mixins_has_many_test - Polymorphic store = env.store; }, - afterEach: function() { + afterEach() { run(env.container, 'destroy'); } }); diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index ddddfeca4d4..c2122b0e1c0 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -12,7 +12,7 @@ var run = Ember.run; var LightSaber; module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { - beforeEach: function() { + beforeEach() { SuperVillain = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), @@ -75,7 +75,7 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { //env.amsAdapter = env.container.lookup("adapter:-active-model"); }, - afterEach: function() { + afterEach() { run(env.store, 'destroy'); } }); @@ -569,7 +569,7 @@ test("normalizeResponse with embedded objects with identical relationship and at villains: { embedded: 'always' } }, //Makes the keyForRelationship and keyForAttribute collide. - keyForRelationship: function(key, type) { + keyForRelationship(key, type) { return this.keyForAttribute(key, type); } })); @@ -910,7 +910,7 @@ test("serialize with embedded objects and a custom keyForAttribute (hasMany rela }); env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - keyForAttribute: function(key) { + keyForAttribute(key) { return key + '-custom'; }, attrs: { @@ -2062,11 +2062,11 @@ test("serializing relationships with an embedded and without calls super when no var calledSerializeHasMany = false; var Serializer = DS.RESTSerializer.extend({ - serializeBelongsTo: function(snapshot, json, relationship) { + serializeBelongsTo(snapshot, json, relationship) { calledSerializeBelongsTo = true; return this._super(snapshot, json, relationship); }, - serializeHasMany: function(snapshot, json, relationship) { + serializeHasMany(snapshot, json, relationship) { calledSerializeHasMany = true; var key = relationship.key; var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, "hasMany") : key; diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 6d8af4f3954..dea465a6b63 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -13,7 +13,7 @@ var run = Ember.run; var User, Handle, GithubHandle, TwitterHandle, Company, Project; module('integration/serializers/json-api-serializer - JSONAPISerializer', { - beforeEach: function() { + beforeEach() { User = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), @@ -58,7 +58,7 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', { serializer = store.serializerFor('-json-api'); }, - afterEach: function() { + afterEach() { run(env.store, 'destroy'); } }); diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index e6a4bc71895..1af7b5f0a33 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -9,7 +9,7 @@ var Post, post, Comment, comment, Favorite, favorite, env; var run = Ember.run; module("integration/serializer/json - JSONSerializer", { - beforeEach: function() { + beforeEach() { Post = DS.Model.extend({ title: DS.attr('string'), comments: DS.hasMany('comment', { inverse: null, async: false }) @@ -31,7 +31,7 @@ module("integration/serializer/json - JSONSerializer", { env.store.modelFor('favorite'); }, - afterEach: function() { + afterEach() { run(env.store, 'destroy'); } }); @@ -81,7 +81,7 @@ test("serializeAttribute", function(assert) { test("serializeAttribute respects keyForAttribute", function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend({ - keyForAttribute: function(key) { + keyForAttribute(key) { return key.toUpperCase(); } })); @@ -140,7 +140,7 @@ test("async serializeBelongsTo with null", function(assert) { test("serializeBelongsTo respects keyForRelationship", function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend({ - keyForRelationship: function(key, type) { + keyForRelationship(key, type) { return key.toUpperCase(); } })); @@ -159,7 +159,7 @@ test("serializeBelongsTo respects keyForRelationship", function(assert) { test("serializeHasMany respects keyForRelationship", function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend({ - keyForRelationship: function(key, type) { + keyForRelationship(key, type) { return key.toUpperCase(); } })); @@ -218,7 +218,7 @@ test("serializePolymorphicType sync", function(assert) { assert.expect(1); env.registry.register('serializer:comment', DS.JSONSerializer.extend({ - serializePolymorphicType: function(record, json, relationship) { + serializePolymorphicType(record, json, relationship) { var key = relationship.key; var belongsTo = record.belongsTo(key); json[relationship.key + "TYPE"] = belongsTo.modelName; @@ -243,7 +243,7 @@ test("serializePolymorphicType async", function(assert) { }); env.registry.register('serializer:comment', DS.JSONSerializer.extend({ - serializePolymorphicType: function(record, json, relationship) { + serializePolymorphicType(record, json, relationship) { assert.ok(true, 'serializePolymorphicType is called when serialize a polymorphic belongsTo'); } })); @@ -264,7 +264,7 @@ test("normalizeResponse normalizes each record in the array", function(assert) { ]; env.registry.register('serializer:post', DS.JSONSerializer.extend({ - normalize: function () { + normalize() { postNormalizeCount++; return this._super.apply(this, arguments); } @@ -628,7 +628,7 @@ test("Serializer should respect the primaryKey attribute when serializing record test("Serializer should respect keyForAttribute when extracting records", function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend({ - keyForAttribute: function(key) { + keyForAttribute(key) { return key.toUpperCase(); } })); @@ -643,7 +643,7 @@ test("Serializer should respect keyForAttribute when extracting records", functi test("Serializer should respect keyForRelationship when extracting records", function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend({ - keyForRelationship: function(key, type) { + keyForRelationship(key, type) { return key.toUpperCase(); } })); @@ -705,7 +705,7 @@ test('serializeBelongsTo with async polymorphic', function(assert) { var expected = { post: '1', postTYPE: 'post' }; env.registry.register('serializer:favorite', DS.JSONSerializer.extend({ - serializePolymorphicType: function(snapshot, json, relationship) { + serializePolymorphicType(snapshot, json, relationship) { var key = relationship.key; json[key + 'TYPE'] = snapshot.belongsTo(key).modelName; } @@ -782,7 +782,7 @@ test('extractErrors leaves payload untouched if it has no errors property', func test('normalizeResponse should extract meta using extractMeta', function(assert) { env.registry.register("serializer:post", DS.JSONSerializer.extend({ - extractMeta: function(store, modelClass, payload) { + extractMeta(store, modelClass, payload) { let meta = this._super(...arguments); meta.authors.push('Tomhuda'); return meta; diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 6b8203df6f5..0cd724b24d9 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -9,7 +9,7 @@ var HomePlanet, league, SuperVillain, EvilMinion, YellowMinion, DoomsdayDevice, var run = Ember.run; module("integration/serializer/rest - RESTSerializer", { - beforeEach: function() { + beforeEach() { HomePlanet = DS.Model.extend({ name: DS.attr('string'), superVillains: DS.hasMany('super-villain', { async: false }) @@ -64,7 +64,7 @@ module("integration/serializer/rest - RESTSerializer", { env.store.modelFor('container'); }, - afterEach: function() { + afterEach() { run(env.store, 'destroy'); } }); @@ -79,7 +79,7 @@ test("modelNameFromPayloadKey returns always same modelName even for uncountable test('normalizeResponse should extract meta using extractMeta', function(assert) { env.registry.register("serializer:home-planet", DS.RESTSerializer.extend({ - extractMeta: function(store, modelClass, payload) { + extractMeta(store, modelClass, payload) { let meta = this._super(...arguments); meta.authors.push('Tomhuda'); return meta; @@ -257,7 +257,7 @@ test("normalizeResponse loads secondary records with correct serializer", functi var superVillainNormalizeCount = 0; env.registry.register('serializer:super-villain', DS.RESTSerializer.extend({ - normalize: function() { + normalize() { superVillainNormalizeCount++; return this._super.apply(this, arguments); } @@ -294,7 +294,7 @@ test("normalizeResponse loads secondary records with correct serializer", functi var superVillainNormalizeCount = 0; env.registry.register('serializer:super-villain', DS.RESTSerializer.extend({ - normalize: function() { + normalize() { superVillainNormalizeCount++; return this._super.apply(this, arguments); } @@ -315,7 +315,7 @@ test("normalizeResponse loads secondary records with correct serializer", functi test('normalizeHash normalizes specific parts of the payload', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ normalizeHash: { - homePlanets: function(hash) { + homePlanets(hash) { hash.id = hash._id; delete hash._id; return hash; @@ -355,7 +355,7 @@ test('normalizeHash normalizes specific parts of the payload', function(assert) test('normalizeHash works with transforms', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ normalizeHash: { - evilMinions: function(hash) { + evilMinions(hash) { hash.condition = hash._condition; delete hash._condition; return hash; @@ -364,14 +364,14 @@ test('normalizeHash works with transforms', function(assert) { })); env.registry.register('transform:condition', DS.Transform.extend({ - deserialize: function(serialized) { + deserialize(serialized) { if (serialized === 1) { return "healing"; } else { return "unknown"; } }, - serialize: function(deserialized) { + serialize(deserialized) { if (deserialized === "healing") { return 1; } else { @@ -399,7 +399,7 @@ test('normalize should allow for different levels of normalization', function(as attrs: { superVillain: 'is_super_villain' }, - keyForAttribute: function(attr) { + keyForAttribute(attr) { return Ember.String.decamelize(attr); } })); @@ -421,7 +421,7 @@ test('normalize should allow for different levels of normalization - attributes' attrs: { name: 'full_name' }, - keyForAttribute: function(attr) { + keyForAttribute(attr) { return Ember.String.decamelize(attr); } })); @@ -565,7 +565,7 @@ test('serializeIntoHash uses payloadKeyFromModelName to normalize the payload ro }); var json = {}; env.registry.register('serializer:home-planet', DS.RESTSerializer.extend({ - payloadKeyFromModelName: function(modelName) { + payloadKeyFromModelName(modelName) { return Ember.String.dasherize(modelName); } })); diff --git a/tests/integration/setup-container-test.js b/tests/integration/setup-container-test.js index 79a6e7b343a..6fabea2a7fe 100644 --- a/tests/integration/setup-container-test.js +++ b/tests/integration/setup-container-test.js @@ -17,7 +17,7 @@ var container, registry, application; */ module("integration/setup-container - Setting up a container", { - beforeEach: function() { + beforeEach() { run(function() { application = Ember.Application.create(); }); @@ -36,7 +36,7 @@ module("integration/setup-container - Setting up a container", { setupContainer(setupContainerArgument); }, - afterEach: function() { + afterEach() { run(function() { application.destroy(); }); diff --git a/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js index 6a0aa14eeac..b63a5941892 100644 --- a/tests/integration/snapshot-test.js +++ b/tests/integration/snapshot-test.js @@ -9,7 +9,7 @@ var run = Ember.run; var env, Post, Comment; module("integration/snapshot - DS.Snapshot", { - beforeEach: function() { + beforeEach() { Post = DS.Model.extend({ author: DS.attr(), title: DS.attr(), @@ -26,7 +26,7 @@ module("integration/snapshot - DS.Snapshot", { }); }, - afterEach: function() { + afterEach() { run(function() { env.store.destroy(); }); diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index c371cd72130..da609bdc517 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -35,7 +35,7 @@ function initializeStore(adapter) { } module("integration/store - destroy", { - beforeEach: function() { + beforeEach() { initializeStore(DS.Adapter.extend()); } }); @@ -62,7 +62,7 @@ test("destroying record during find doesn't cause error", function(assert) { let done = assert.async(); var TestAdapter = DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { return new Ember.RSVP.Promise(function(resolve, reject) { Ember.run.next(function() { store.unloadAll(type.modelName); @@ -87,7 +87,7 @@ test("find calls do not resolve when the store is destroyed", function(assert) { let done = assert.async(); var TestAdapter = DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { store.destroy(); Ember.RSVP.resolve(null); } @@ -336,7 +336,7 @@ test('store#findRecord call with `id` of type different than non-empty string or }); module("integration/store - findAll", { - beforeEach: function() { + beforeEach() { initializeStore(DS.RESTAdapter.extend()); } }); @@ -527,7 +527,7 @@ test("Using store#serializerFor should not throw an error when looking up the ap }); module("integration/store - deleteRecord", { - beforeEach: function() { + beforeEach() { initializeStore(DS.RESTAdapter.extend()); } }); diff --git a/tests/integration/store/json-api-validation-test.js b/tests/integration/store/json-api-validation-test.js index e53ab3708d4..e3481ce6888 100644 --- a/tests/integration/store/json-api-validation-test.js +++ b/tests/integration/store/json-api-validation-test.js @@ -7,7 +7,7 @@ var Person, store, env; var run = Ember.run; module("integration/store/json-validation", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ updatedAt: DS.attr('string'), name: DS.attr('string'), @@ -21,7 +21,7 @@ module("integration/store/json-validation", { store = env.store; }, - afterEach: function() { + afterEach() { run(store, 'destroy'); } }); diff --git a/tests/integration/store/query-record-test.js b/tests/integration/store/query-record-test.js index b093c3c6e65..a695dec0354 100644 --- a/tests/integration/store/query-record-test.js +++ b/tests/integration/store/query-record-test.js @@ -9,7 +9,7 @@ var Person, store, env; var run = Ember.run; module("integration/store/query-record - Query one record with a query hash", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ updatedAt: DS.attr('string'), name: DS.attr('string'), @@ -23,7 +23,7 @@ module("integration/store/query-record - Query one record with a query hash", { store = env.store; }, - afterEach: function() { + afterEach() { run(store, 'destroy'); } }); @@ -44,7 +44,7 @@ test("When a record is requested, the adapter's queryRecord method should be cal assert.expect(1); env.registry.register('adapter:person', DS.Adapter.extend({ - queryRecord: function(store, type, query) { + queryRecord(store, type, query) { assert.equal(type, Person, "the query method is called with the correct type"); return Ember.RSVP.resolve({ id: 1, name: "Peter Wagenet" }); } @@ -57,7 +57,7 @@ test("When a record is requested, the adapter's queryRecord method should be cal test("When a record is requested, and the promise is rejected, .queryRecord() is rejected.", function(assert) { env.registry.register('adapter:person', DS.Adapter.extend({ - queryRecord: function(store, type, query) { + queryRecord(store, type, query) { return Ember.RSVP.reject(); } })); @@ -73,14 +73,14 @@ test("When a record is requested, the serializer's normalizeQueryRecordResponse assert.expect(1); env.registry.register('serializer:person', DS.JSONAPISerializer.extend({ - normalizeQueryRecordResponse: function(store, primaryModelClass, payload, id, requestType) { + normalizeQueryRecordResponse(store, primaryModelClass, payload, id, requestType) { assert.equal(payload.data.id , '1', "the normalizeQueryRecordResponse method was called with the right payload"); return this._super(...arguments); } })); env.registry.register('adapter:person', DS.Adapter.extend({ - queryRecord: function(store, type, query) { + queryRecord(store, type, query) { return Ember.RSVP.resolve({ data: { id: '1', diff --git a/tests/test-helper.js b/tests/test-helper.js index 545280303fb..ce98f980535 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -47,7 +47,7 @@ QUnit.begin(function() { // Prevent all tests involving serialization to require a container DS.JSONSerializer.reopen({ - transformFor: function(attributeType) { + transformFor(attributeType) { return this._super(attributeType, true) || transforms[attributeType]; } }); diff --git a/tests/unit/adapter-populated-record-array-test.js b/tests/unit/adapter-populated-record-array-test.js index bc33894420d..c808c47025d 100644 --- a/tests/unit/adapter-populated-record-array-test.js +++ b/tests/unit/adapter-populated-record-array-test.js @@ -9,13 +9,13 @@ var Person, store; var run = Ember.run; var adapter = DS.Adapter.extend({ - deleteRecord: function() { + deleteRecord() { return Ember.RSVP.Promise.resolve(); } }); module("unit/adapter_populated_record_array - DS.AdapterPopulatedRecordArray", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ name: DS.attr('string') }); diff --git a/tests/unit/adapters/build-url-mixin/path-for-type-test.js b/tests/unit/adapters/build-url-mixin/path-for-type-test.js index 3f33e8d445c..8aae7373d3d 100644 --- a/tests/unit/adapters/build-url-mixin/path-for-type-test.js +++ b/tests/unit/adapters/build-url-mixin/path-for-type-test.js @@ -6,11 +6,11 @@ import {module, test} from 'qunit'; var env, adapter; module("unit/adapters/build-url-mixin/path-for-type - DS.BuildURLMixin#pathForType", { - beforeEach: function() { + beforeEach() { // test for overriden pathForType methods which return null path values var customPathForType = { - pathForType: function(type) { + pathForType(type) { if (type === 'rootModel') { return ''; } return this._super(type); } diff --git a/tests/unit/adapters/json-api-adapter/ajax-test.js b/tests/unit/adapters/json-api-adapter/ajax-test.js index d802bfcb101..992e4adeb69 100644 --- a/tests/unit/adapters/json-api-adapter/ajax-test.js +++ b/tests/unit/adapters/json-api-adapter/ajax-test.js @@ -9,7 +9,7 @@ var Person, Place, store, adapter, env; var run = Ember.run; module("unit/adapters/json-api-adapter/ajax - building requests", { - beforeEach: function() { + beforeEach() { Person = { modelName: 'person' }; Place = { modelName: 'place' }; env = setupStore({ adapter: DS.JSONAPIAdapter, person: Person, place: Place }); @@ -17,7 +17,7 @@ module("unit/adapters/json-api-adapter/ajax - building requests", { adapter = env.adapter; }, - afterEach: function() { + afterEach() { run(function() { store.destroy(); env.container.destroy(); @@ -31,7 +31,7 @@ test("ajaxOptions() adds Accept when no other headers exist", function(assert) { var ajaxOptions = adapter.ajaxOptions(url, type, {}); var receivedHeaders = []; var fakeXHR = { - setRequestHeader: function(key, value) { + setRequestHeader(key, value) { receivedHeaders.push([key, value]); } }; @@ -46,7 +46,7 @@ test("ajaxOptions() adds Accept header to existing headers", function(assert) { var ajaxOptions = adapter.ajaxOptions(url, type, {}); var receivedHeaders = []; var fakeXHR = { - setRequestHeader: function(key, value) { + setRequestHeader(key, value) { receivedHeaders.push([key, value]); } }; @@ -63,7 +63,7 @@ test("ajaxOptions() adds Accept header to existing computed properties headers", var ajaxOptions = adapter.ajaxOptions(url, type, {}); var receivedHeaders = []; var fakeXHR = { - setRequestHeader: function(key, value) { + setRequestHeader(key, value) { receivedHeaders.push([key, value]); } }; diff --git a/tests/unit/adapters/rest-adapter/ajax-test.js b/tests/unit/adapters/rest-adapter/ajax-test.js index 12d817f5cba..ade40bc15d3 100644 --- a/tests/unit/adapters/rest-adapter/ajax-test.js +++ b/tests/unit/adapters/rest-adapter/ajax-test.js @@ -9,7 +9,7 @@ var Person, Place, store, adapter, env; var run = Ember.run; module("unit/adapters/rest-adapter/ajax - building requests", { - beforeEach: function() { + beforeEach() { Person = { modelName: 'person' }; Place = { modelName: 'place' }; env = setupStore({ adapter: DS.RESTAdapter, person: Person, place: Place }); @@ -17,7 +17,7 @@ module("unit/adapters/rest-adapter/ajax - building requests", { adapter = env.adapter; }, - afterEach: function() { + afterEach() { run(function() { store.destroy(); env.container.destroy(); @@ -58,7 +58,7 @@ test("ajaxOptions() headers are set", function(assert) { var ajaxOptions = adapter.ajaxOptions(url, type, {}); var receivedHeaders = []; var fakeXHR = { - setRequestHeader: function(key, value) { + setRequestHeader(key, value) { receivedHeaders.push([key, value]); } }; diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index eb230dc6d7f..2354905055e 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -10,16 +10,16 @@ var maxLength = -1; var lengths = Ember.A([]); module("unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAdapter#groupRecordsForFindMany", { - beforeEach: function() { + beforeEach() { GroupsAdapter = DS.RESTAdapter.extend({ coalesceFindRequests: true, - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { return Ember.RSVP.Promise.resolve({ id: id }); }, - ajax: function(url, type, options) { + ajax(url, type, options) { var queryString = options.data.ids.map(function(i) { return encodeURIComponent('ids[]') + '=' + encodeURIComponent(i); }).join('&'); diff --git a/tests/unit/many-array-test.js b/tests/unit/many-array-test.js index f1609d723c8..1ef1edf24e7 100644 --- a/tests/unit/many-array-test.js +++ b/tests/unit/many-array-test.js @@ -14,7 +14,7 @@ var run = Ember.run; var Post, Tag; module("unit/many_array - DS.ManyArray", { - beforeEach: function() { + beforeEach() { Post = DS.Model.extend({ title: attr('string'), tags: hasMany('tag', { async: false }) @@ -38,7 +38,7 @@ module("unit/many_array - DS.ManyArray", { store = env.store; }, - afterEach: function() { + afterEach() { run(function() { store.destroy(); }); @@ -50,7 +50,7 @@ test("manyArray.save() calls save() on all records", function(assert) { run(function() { Tag.reopen({ - save: function() { + save() { assert.ok(true, 'record.save() was called'); return Ember.RSVP.resolve(); } @@ -101,13 +101,13 @@ test("manyArray trigger arrayContentChange functions with the correct values", f var originalArrayContentWillChange = DS.ManyArray.prototype.arrayContentWillChange; var originalArrayContentDidChange = DS.ManyArray.prototype.arrayContentDidChange; DS.ManyArray.reopen({ - arrayContentWillChange: function(startIdx, removeAmt, addAmt) { + arrayContentWillChange(startIdx, removeAmt, addAmt) { willChangeStartIdx = startIdx; willChangeRemoveAmt = removeAmt; willChangeAddAmt = addAmt; return this._super.apply(this, arguments); }, - arrayContentDidChange: function(startIdx, removeAmt, addAmt) { + arrayContentDidChange(startIdx, removeAmt, addAmt) { assert.equal(startIdx, willChangeStartIdx, 'WillChange and DidChange startIdx should match'); assert.equal(removeAmt, willChangeRemoveAmt, 'WillChange and DidChange removeAmt should match'); assert.equal(addAmt, willChangeAddAmt, 'WillChange and DidChange addAmt should match'); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 119a9df82b4..54af7217039 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -13,7 +13,7 @@ var run = Ember.run; var Person, store, env; module("unit/model - DS.Model", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ name: DS.attr('string'), isDrugAddict: DS.attr('boolean') @@ -25,7 +25,7 @@ module("unit/model - DS.Model", { store = env.store; }, - afterEach: function() { + afterEach() { run(function() { store.destroy(); }); @@ -476,7 +476,7 @@ test("currentState is accessible when the record is created", function(assert) { }); module("unit/model - DS.Model updating", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ name: DS.attr('string') }); env = setupStore({ person: Person @@ -506,7 +506,7 @@ module("unit/model - DS.Model updating", { }); }); }, - afterEach: function() { + afterEach() { run(function() { store.destroy(); Person = null; @@ -555,7 +555,7 @@ test("a DS.model can define 'setUnknownProperty'", function(assert) { var Tag = DS.Model.extend({ name: DS.attr("string"), - setUnknownProperty: function(key, value) { + setUnknownProperty(key, value) { if (key === "title") { this.set("name", value); } @@ -577,7 +577,7 @@ test("a DS.model can define 'setUnknownProperty'", function(assert) { test("a defaultValue for an attribute can be a function", function(assert) { var Tag = DS.Model.extend({ createdAt: DS.attr('string', { - defaultValue: function() { + defaultValue() { return "le default value"; } }) @@ -599,7 +599,7 @@ test("a defaultValue function gets the record, options, and key", function(asser var Tag = DS.Model.extend({ createdAt: DS.attr('string', { - defaultValue: function(record, options, key) { + defaultValue(record, options, key) { assert.deepEqual(record, tag, "the record is passed in properly"); assert.equal(key, 'createdAt', "the attribute being defaulted is passed in properly"); return "le default value"; @@ -702,7 +702,7 @@ test("setting a property back to its original value removes the property from th }); module("unit/model - with a simple Person model", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ name: DS.attr('string') }); @@ -733,7 +733,7 @@ module("unit/model - with a simple Person model", { }); }); }, - afterEach: function() { + afterEach() { run(function() { store.destroy(); Person = null; @@ -993,7 +993,7 @@ test("ensure model exits loading state, materializes data and fulfills promise o var store = createStore({ adapter: DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "John" }); } }), @@ -1145,7 +1145,7 @@ test('accessing attributes in the initializer should not throw an error', functi var Person = DS.Model.extend({ name: DS.attr('string'), - init: function() { + init() { this._super.apply(this, arguments); assert.ok(!this.get('name')); } diff --git a/tests/unit/model/errors-test.js b/tests/unit/model/errors-test.js index 26367a11d60..9569a80c4de 100644 --- a/tests/unit/model/errors-test.js +++ b/tests/unit/model/errors-test.js @@ -6,11 +6,11 @@ const AssertPrototype = QUnit.assert; var errors; module("unit/model/errors", { - beforeEach: function() { + beforeEach() { errors = DS.Errors.create(); }, - afterEach: function() { + afterEach() { } }); diff --git a/tests/unit/model/internal-model-test.js b/tests/unit/model/internal-model-test.js index c273b9752e7..a6cc3690c79 100644 --- a/tests/unit/model/internal-model-test.js +++ b/tests/unit/model/internal-model-test.js @@ -7,7 +7,7 @@ module("unit/model/internal-model - Internal Model"); function MockModelFactory () { } MockModelFactory._create = function() { - return { trigger: function() {} }; + return { trigger() {} }; }; MockModelFactory.eachRelationship = function() { }; diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index 6c9778d505a..04b0fb8ae2c 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -15,13 +15,13 @@ test("a record receives a didLoad callback when it has finished loading", functi var Person = DS.Model.extend({ name: DS.attr(), - didLoad: function() { + didLoad() { assert.ok("The didLoad callback was called"); } }); var adapter = DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Foo" }); } }); @@ -44,7 +44,7 @@ test("TEMPORARY: a record receives a didLoad callback once it materializes if it var didLoadCalled = 0; var Person = DS.Model.extend({ name: DS.attr(), - didLoad: function() { + didLoad() { didLoadCalled++; } }); @@ -74,7 +74,7 @@ test("a record receives a didUpdate callback when it has finished updating", fun bar: DS.attr('string'), name: DS.attr('string'), - didUpdate: function() { + didUpdate() { callCount++; assert.equal(get(this, 'isSaving'), false, "record should be saving"); assert.equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); @@ -82,11 +82,11 @@ test("a record receives a didUpdate callback when it has finished updating", fun }); var adapter = DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Foo" }); }, - updateRecord: function(store, type, snapshot) { + updateRecord(store, type, snapshot) { assert.equal(callCount, 0, "didUpdate callback was not called until didSaveRecord is called"); return Ember.RSVP.resolve(); @@ -122,7 +122,7 @@ test("a record receives a didCreate callback when it has finished updating", fun var callCount = 0; var Person = DS.Model.extend({ - didCreate: function() { + didCreate() { callCount++; assert.equal(get(this, 'isSaving'), false, "record should not be saving"); assert.equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); @@ -130,7 +130,7 @@ test("a record receives a didCreate callback when it has finished updating", fun }); var adapter = DS.Adapter.extend({ - createRecord: function(store, type, snapshot) { + createRecord(store, type, snapshot) { assert.equal(callCount, 0, "didCreate callback was not called until didSaveRecord is called"); return Ember.RSVP.resolve(); @@ -166,7 +166,7 @@ test("a record receives a didDelete callback when it has finished deleting", fun bar: DS.attr('string'), name: DS.attr('string'), - didDelete: function() { + didDelete() { callCount++; assert.equal(get(this, 'isSaving'), false, "record should not be saving"); @@ -175,11 +175,11 @@ test("a record receives a didDelete callback when it has finished deleting", fun }); var adapter = DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Foo" }); }, - deleteRecord: function(store, type, snapshot) { + deleteRecord(store, type, snapshot) { assert.equal(callCount, 0, "didDelete callback was not called until didSaveRecord is called"); return Ember.RSVP.resolve(); @@ -219,7 +219,7 @@ test("an uncommited record also receives a didDelete callback when it is deleted bar: DS.attr('string'), name: DS.attr('string'), - didDelete: function() { + didDelete() { callCount++; assert.equal(get(this, 'isSaving'), false, "record should not be saving"); assert.equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); @@ -254,7 +254,7 @@ test("a record receives a becameInvalid callback when it became invalid", functi bar: DS.attr('string'), name: DS.attr('string'), - becameInvalid: function() { + becameInvalid() { callCount++; assert.equal(get(this, 'isSaving'), false, "record should not be saving"); @@ -263,11 +263,11 @@ test("a record receives a becameInvalid callback when it became invalid", functi }); var adapter = DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Foo" }); }, - updateRecord: function(store, type, snapshot) { + updateRecord(store, type, snapshot) { assert.equal(callCount, 0, "becameInvalid callback was not called until recordWasInvalid is called"); return Ember.RSVP.reject(new DS.InvalidError([ diff --git a/tests/unit/model/merge-test.js b/tests/unit/model/merge-test.js index 4647f4b2cde..11ae3cd9a03 100644 --- a/tests/unit/model/merge-test.js +++ b/tests/unit/model/merge-test.js @@ -9,7 +9,7 @@ var Person; var run = Ember.run; module("unit/model/merge - Merging", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ name: DS.attr(), city: DS.attr() @@ -21,7 +21,7 @@ test("When a record is in flight, changes can be made", function(assert) { assert.expect(3); var adapter = DS.Adapter.extend({ - createRecord: function(store, type, snapshot) { + createRecord(store, type, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Tom Dale" }); } }); @@ -54,7 +54,7 @@ test("Make sure snapshot is created at save time not at flush time", function(as assert.expect(5); var adapter = DS.Adapter.extend({ - updateRecord: function(store, type, snapshot) { + updateRecord(store, type, snapshot) { assert.equal(snapshot.attr('name'), 'Thomas Dale'); return Ember.RSVP.resolve(); @@ -97,7 +97,7 @@ test("When a record is in flight, pushes are applied underneath the in flight ch assert.expect(6); var adapter = DS.Adapter.extend({ - updateRecord: function(store, type, snapshot) { + updateRecord(store, type, snapshot) { // Make sure saving isn't resolved synchronously return new Ember.RSVP.Promise(function(resolve, reject) { run.next(null, resolve, { id: 1, name: "Senor Thomas Dale, Esq.", city: "Portland" }); @@ -246,7 +246,7 @@ test("A record with no changes can still be saved", function(assert) { assert.expect(1); var adapter = DS.Adapter.extend({ - updateRecord: function(store, type, snapshot) { + updateRecord(store, type, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Thomas Dale" }); } }); @@ -280,7 +280,7 @@ test("A dirty record can be reloaded", function(assert) { assert.expect(3); var adapter = DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, name: "Thomas Dale", city: "Portland" }); } }); diff --git a/tests/unit/model/relationships-test.js b/tests/unit/model/relationships-test.js index 6c8f833165b..751acb84407 100644 --- a/tests/unit/model/relationships-test.js +++ b/tests/unit/model/relationships-test.js @@ -10,7 +10,7 @@ var run = Ember.run; var Occupation, Person, store; module("unit/model/relationships - DS.Model", { - beforeEach: function() { + beforeEach() { Occupation = DS.Model.extend(); Person = DS.Model.extend({ diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 7904740ae67..ea6342a200d 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -10,7 +10,7 @@ var run = Ember.run; var env; module("unit/model/relationships - DS.hasMany", { - beforeEach: function() { + beforeEach() { env = setupStore(); } }); diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index f9d77bdee3c..1014af6ec95 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -9,7 +9,7 @@ var env, store, Person, Dog; var run = Ember.run; module("unit/model/rollbackAttributes - model.rollbackAttributes()", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ firstName: DS.attr(), lastName: DS.attr() @@ -225,7 +225,7 @@ test("invalid new record's attributes can be rollbacked", function(assert) { } ]); var adapter = DS.RESTAdapter.extend({ - ajax: function(url, type, hash) { + ajax(url, type, hash) { return Ember.RSVP.reject(error); } }); @@ -255,7 +255,7 @@ test("invalid record's attributes can be rollbacked after multiple failed calls var person; var adapter = DS.RESTAdapter.extend({ - ajax: function(url, type, hash) { + ajax(url, type, hash) { var error = new DS.InvalidError(); return Ember.RSVP.reject(error); } @@ -336,7 +336,7 @@ test("invalid record's attributes can be rollbacked", function(assert) { ]); var adapter = DS.RESTAdapter.extend({ - ajax: function(url, type, hash) { + ajax(url, type, hash) { return Ember.RSVP.reject(error); } }); @@ -363,10 +363,10 @@ test("invalid record's attributes can be rollbacked", function(assert) { }); dog.get('errors').addArrayObserver({}, { - willChange: function() { + willChange() { assert.ok(true, 'errors will change'); }, - didChange: function() { + didChange() { assert.ok(true, 'errors did change'); } }); @@ -397,7 +397,7 @@ test("invalid record's attributes rolled back to correct state after set", funct ]); var adapter = DS.RESTAdapter.extend({ - ajax: function(url, type, hash) { + ajax(url, type, hash) { return Ember.RSVP.reject(error); } }); @@ -464,7 +464,7 @@ test("when destroying a record setup the record state to invalid, the record's a ]); var adapter = DS.RESTAdapter.extend({ - ajax: function(url, type, hash) { + ajax(url, type, hash) { return Ember.RSVP.reject(error); } }); diff --git a/tests/unit/record-array-test.js b/tests/unit/record-array-test.js index f2098914034..0d03cb07743 100644 --- a/tests/unit/record-array-test.js +++ b/tests/unit/record-array-test.js @@ -12,7 +12,7 @@ var Person, array; var run = Ember.run; module("unit/record_array - DS.RecordArray", { - beforeEach: function() { + beforeEach() { array = [{ id: '1', name: "Scumbag Dale" }, { id: '2', name: "Scumbag Katz" }, { id: '3', name: "Scumbag Bryn" }]; Person = DS.Model.extend({ diff --git a/tests/unit/record-arrays/filtered-record-array-test.js b/tests/unit/record-arrays/filtered-record-array-test.js index 725f7428961..a8c08be4713 100644 --- a/tests/unit/record-arrays/filtered-record-array-test.js +++ b/tests/unit/record-arrays/filtered-record-array-test.js @@ -5,7 +5,7 @@ import {module, test} from 'qunit'; var filteredArray; module("unit/record-arrays/filtered-record-array - DS.FilteredRecordArray", { - beforeEach: function() { + beforeEach() { filteredArray = DS.FilteredRecordArray.create({ type: 'recordType' }); } }); diff --git a/tests/unit/states-test.js b/tests/unit/states-test.js index 12f5e4c0372..a46274c5524 100644 --- a/tests/unit/states-test.js +++ b/tests/unit/states-test.js @@ -9,7 +9,7 @@ var get = Ember.get; var rootState, stateName; module("unit/states - Flags for record states", { - beforeEach: function() { + beforeEach() { rootState = DS.RootState; } }); diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index 9bdff260cbb..c665d281c7c 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -13,12 +13,12 @@ var TestAdapter, store, person, oldFilterEnabled; var run = Ember.run; module("unit/store/adapter-interop - DS.Store working with a DS.Adapter", { - beforeEach: function() { + beforeEach() { TestAdapter = DS.Adapter.extend(); oldFilterEnabled = Ember.ENV.ENABLE_DS_FILTER; Ember.ENV.ENABLE_DS_FILTER = false; }, - afterEach: function() { + afterEach() { run(function() { if (store) { store.destroy(); } Ember.ENV.ENABLE_DS_FILTER = oldFilterEnabled; @@ -52,7 +52,7 @@ test("Calling Store#find invokes its adapter#find", function(assert) { let done = assert.async(); var adapter = TestAdapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { assert.ok(true, "Adapter#find was called"); assert.equal(store, currentStore, "Adapter#find was called with the right store"); assert.equal(type, store.modelFor('test'), "Adapter#find was called with the type passed into Store#find"); @@ -77,10 +77,10 @@ test("Calling Store#findRecord multiple times coalesces the calls into a adapter let done = assert.async(); var adapter = TestAdapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { assert.ok(false, "Adapter#findRecord was not called"); }, - findMany: function(store, type, ids, snapshots) { + findMany(store, type, ids, snapshots) { assert.ok(true, "Adapter#findMany was called"); assert.deepEqual(ids, ["1","2"], 'Correct ids were passed in to findMany'); return Ember.RSVP.resolve([{ id: 1 }, { id: 2 }]); @@ -104,7 +104,7 @@ test("Returning a promise from `findRecord` asynchronously loads data", function assert.expect(1); var adapter = TestAdapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { return resolve({ id: 1, name: "Scumbag Dale" }); } }); @@ -125,7 +125,7 @@ test("IDs provided as numbers are coerced to strings", function(assert) { assert.expect(5); var adapter = TestAdapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { assert.equal(typeof id, 'string', "id has been normalized to a string"); return resolve({ id: 1, name: "Scumbag Sylvain" }); } @@ -223,7 +223,7 @@ test("loadMany takes an optional Object and passes it on to the Adapter", functi }); var adapter = TestAdapter.extend({ - query: function(store, type, query) { + query(store, type, query) { assert.equal(type, store.modelFor('person'), 'The type was Person'); assert.equal(query, passedQuery, "The query was passed in"); return Ember.RSVP.resolve([]); @@ -248,7 +248,7 @@ test("Find with query calls the correct normalizeResponse", function(assert) { }); var adapter = TestAdapter.extend({ - query: function(store, type, query) { + query(store, type, query) { return Ember.RSVP.resolve([]); } }); @@ -256,7 +256,7 @@ test("Find with query calls the correct normalizeResponse", function(assert) { var callCount = 0; var ApplicationSerializer = DS.JSONSerializer.extend({ - normalizeQueryResponse: function() { + normalizeQueryResponse() { callCount++; return this._super(...arguments); } @@ -349,7 +349,7 @@ test("a new record with a specific id can't be created if this id is already use }); Person.reopenClass({ - toString: function() { + toString() { return 'Person'; } }); @@ -415,7 +415,7 @@ test("initial values of attributes can be passed in as the third argument to fin assert.expect(1); var adapter = TestAdapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { assert.equal(snapshot.attr('name'), 'Test', 'Preloaded attribtue set'); return Ember.RSVP.resolve({ id: '1', name: 'Test' }); } @@ -438,7 +438,7 @@ test("initial values of attributes can be passed in as the third argument to fin test("initial values of belongsTo can be passed in as the third argument to find as records", function(assert) { assert.expect(1); var adapter = TestAdapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { assert.equal(snapshot.belongsTo('friend').attr('name'), 'Tom', 'Preloaded belongsTo set'); return new Ember.RSVP.Promise(function() {}); } @@ -476,7 +476,7 @@ test("initial values of belongsTo can be passed in as the third argument to find assert.expect(1); var adapter = TestAdapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { return Ember.RSVP.Promise.resolve({ id: id }); } }); @@ -505,7 +505,7 @@ test("initial values of belongsTo can be passed in as the third argument to find test("initial values of hasMany can be passed in as the third argument to find as records", function(assert) { assert.expect(1); var adapter = TestAdapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { assert.equal(snapshot.hasMany('friends')[0].attr('name'), 'Tom', 'Preloaded hasMany set'); return new Ember.RSVP.Promise(function() {}); } @@ -543,7 +543,7 @@ test("initial values of hasMany can be passed in as the third argument to find a assert.expect(1); var adapter = TestAdapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { assert.equal(snapshot.hasMany('friends')[0].id, '2', 'Preloaded hasMany set'); return Ember.RSVP.resolve({ id: id }); } @@ -575,7 +575,7 @@ test("records should have their ids updated when the adapter returns the id data var idCounter = 1; var adapter = TestAdapter.extend({ - createRecord: function(store, type, snapshot) { + createRecord(store, type, snapshot) { return Ember.RSVP.resolve({ name: snapshot.attr('name'), id: idCounter++ }); } }); @@ -634,7 +634,7 @@ test("store.scheduleFetchMany should not resolve until all the records are resol var Phone = DS.Model.extend(); var adapter = TestAdapter.extend({ - findRecord: function (store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { var wait = 5; var record = { id: id }; @@ -646,7 +646,7 @@ test("store.scheduleFetchMany should not resolve until all the records are resol }); }, - findMany: function(store, type, ids, snapshots) { + findMany(store, type, ids, snapshots) { var wait = 15; var records = ids.map(function(id) { @@ -691,19 +691,19 @@ test("the store calls adapter.findMany according to groupings returned by adapte var Person = DS.Model.extend(); var adapter = TestAdapter.extend({ - groupRecordsForFindMany: function(store, snapshots) { + groupRecordsForFindMany(store, snapshots) { return [ [snapshots[0]], [snapshots[1], snapshots[2]] ]; }, - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { assert.equal(id, "10", "The first group is passed to find"); return Ember.RSVP.resolve({ id: id }); }, - findMany: function(store, type, ids, snapshots) { + findMany(store, type, ids, snapshots) { var records = ids.map(function(id) { return { id: id }; }); @@ -742,14 +742,14 @@ test("the promise returned by `scheduleFetch`, when it resolves, does not depend var davidResolved = false; var adapter = TestAdapter.extend({ - groupRecordsForFindMany: function (store, snapshots) { + groupRecordsForFindMany(store, snapshots) { return [ [snapshots[0]], [snapshots[1]] ]; }, - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { var record = { id: id }; return new Ember.RSVP.Promise(function(resolve, reject) { @@ -791,14 +791,14 @@ test("the promise returned by `scheduleFetch`, when it rejects, does not depend var davidResolved = false; var adapter = TestAdapter.extend({ - groupRecordsForFindMany: function(store, snapshots) { + groupRecordsForFindMany(store, snapshots) { return [ [snapshots[0]], [snapshots[1]] ]; }, - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { var record = { id: id }; return new Ember.RSVP.Promise(function(resolve, reject) { @@ -839,7 +839,7 @@ test("store.fetchRecord reject records that were not found, even when those requ var Person = DS.Model.extend(); var adapter = TestAdapter.extend({ - findMany: function(store, type, ids, snapshots) { + findMany(store, type, ids, snapshots) { var records = ids.map(function(id) { return { id: id }; }); @@ -883,11 +883,11 @@ test("store should not call shouldReloadRecord when the record is not in the sto }); var TestAdapter = DS.Adapter.extend({ - shouldReloadRecord: function(store, type, id, snapshot) { + shouldReloadRecord(store, type, id, snapshot) { assert.ok(false, 'shouldReloadRecord should not be called when the record is not loaded'); return false; }, - findRecord: function() { + findRecord() { assert.ok(true, 'find is always called when the record is not in the store'); return { id: 1 }; } @@ -911,12 +911,12 @@ test("store should not reload record when shouldReloadRecord returns false", fun }); var TestAdapter = DS.Adapter.extend({ - shouldReloadRecord: function(store, type, id, snapshot) { + shouldReloadRecord(store, type, id, snapshot) { assert.ok(true, 'shouldReloadRecord should be called when the record is in the store'); return false; }, shouldBackgroundReloadRecord: () => false, - findRecord: function() { + findRecord() { assert.ok(false, 'find should not be called when shouldReloadRecord returns false'); } }); @@ -945,11 +945,11 @@ test("store should reload record when shouldReloadRecord returns true", function }); var TestAdapter = DS.Adapter.extend({ - shouldReloadRecord: function(store, type, id, snapshot) { + shouldReloadRecord(store, type, id, snapshot) { assert.ok(true, 'shouldReloadRecord should be called when the record is in the store'); return true; }, - findRecord: function() { + findRecord() { assert.ok(true, 'find should not be called when shouldReloadRecord returns false'); return { id: 1, name: 'Tom' }; } @@ -981,13 +981,13 @@ test("store should not call shouldBackgroundReloadRecord when the store is alrea }); var TestAdapter = DS.Adapter.extend({ - shouldReloadRecord: function(store, type, id, snapshot) { + shouldReloadRecord(store, type, id, snapshot) { return true; }, - shouldBackgroundReloadRecord: function(store, type, id, snapshot) { + shouldBackgroundReloadRecord(store, type, id, snapshot) { assert.ok(false, 'shouldBackgroundReloadRecord is not called when shouldReloadRecord returns true'); }, - findRecord: function() { + findRecord() { assert.ok(true, 'find should be called'); return { id: 1, name: 'Tom' }; } @@ -1019,11 +1019,11 @@ test("store should not reload a record when `shouldBackgroundReloadRecord` is fa }); var TestAdapter = DS.Adapter.extend({ - shouldBackgroundReloadRecord: function(store, type, id, snapshot) { + shouldBackgroundReloadRecord(store, type, id, snapshot) { assert.ok(true, 'shouldBackgroundReloadRecord is called when record is loaded form the cache'); return false; }, - findRecord: function() { + findRecord() { assert.ok(false, 'find should not be called'); return { id: 1, name: 'Tom' }; } @@ -1056,11 +1056,11 @@ test("store should reload the record in the background when `shouldBackgroundRel }); var TestAdapter = DS.Adapter.extend({ - shouldBackgroundReloadRecord: function(store, type, id, snapshot) { + shouldBackgroundReloadRecord(store, type, id, snapshot) { assert.ok(true, 'shouldBackgroundReloadRecord is called when record is loaded form the cache'); return true; }, - findRecord: function() { + findRecord() { assert.ok(true, 'find should not be called'); return { id: 1, name: 'Tom' }; } @@ -1094,14 +1094,14 @@ test("store should not reload record array when shouldReloadAll returns false", }); var TestAdapter = DS.Adapter.extend({ - shouldReloadAll: function(store, snapshot) { + shouldReloadAll(store, snapshot) { assert.ok(true, 'shouldReloadAll should be called when the record is in the store'); return false; }, - shouldBackgroundReloadAll: function(store, snapshot) { + shouldBackgroundReloadAll(store, snapshot) { return false; }, - findAll: function() { + findAll() { assert.ok(false, 'findAll should not be called when shouldReloadAll returns false'); } }); @@ -1124,11 +1124,11 @@ test("store should reload all records when shouldReloadAll returns true", functi }); var TestAdapter = DS.Adapter.extend({ - shouldReloadAll: function(store, type, id, snapshot) { + shouldReloadAll(store, type, id, snapshot) { assert.ok(true, 'shouldReloadAll should be called when the record is in the store'); return true; }, - findAll: function() { + findAll() { assert.ok(true, 'findAll should be called when shouldReloadAll returns true'); return [{ id: 1, name: 'Tom' }]; } @@ -1154,13 +1154,13 @@ test("store should not call shouldBackgroundReloadAll when the store is already }); var TestAdapter = DS.Adapter.extend({ - shouldReloadAll: function(store, type, id, snapshot) { + shouldReloadAll(store, type, id, snapshot) { return true; }, - shouldBackgroundReloadAll: function(store, type, id, snapshot) { + shouldBackgroundReloadAll(store, type, id, snapshot) { assert.ok(false, 'shouldBackgroundReloadRecord is not called when shouldReloadRecord returns true'); }, - findAll: function() { + findAll() { assert.ok(true, 'find should be called'); return [{ id: 1, name: 'Tom' }]; } @@ -1186,15 +1186,15 @@ test("store should not reload all records when `shouldBackgroundReloadAll` is fa }); var TestAdapter = DS.Adapter.extend({ - shouldReloadAll: function(store, type, id, snapshot) { + shouldReloadAll(store, type, id, snapshot) { assert.ok(true, 'shouldReloadAll is called when record is loaded form the cache'); return false; }, - shouldBackgroundReloadAll: function(store, type, id, snapshot) { + shouldBackgroundReloadAll(store, type, id, snapshot) { assert.ok(true, 'shouldBackgroundReloadAll is called when record is loaded form the cache'); return false; }, - findAll: function() { + findAll() { assert.ok(false, 'findAll should not be called'); return [{ id: 1, name: 'Tom' }]; } @@ -1221,15 +1221,15 @@ test("store should reload all records in the background when `shouldBackgroundRe }); var TestAdapter = DS.Adapter.extend({ - shouldReloadAll: function() { + shouldReloadAll() { assert.ok(true, 'shouldReloadAll is called'); return false; }, - shouldBackgroundReloadAll: function(store, snapshot) { + shouldBackgroundReloadAll(store, snapshot) { assert.ok(true, 'shouldBackgroundReloadAll is called when record is loaded form the cache'); return true; }, - findAll: function() { + findAll() { assert.ok(true, 'find should not be called'); return [{ id: 1, name: 'Tom' }]; } diff --git a/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js index c276ca82789..dea148fd8af 100644 --- a/tests/unit/store/create-record-test.js +++ b/tests/unit/store/create-record-test.js @@ -8,7 +8,7 @@ var store, container, Record, Storage; var run = Ember.run; module("unit/store/createRecord - Store creating records", { - beforeEach: function() { + beforeEach() { Record = DS.Model.extend({ title: DS.attr('string') }); @@ -64,7 +64,7 @@ test("allow passing relationships as well as attributes", function(assert) { }); module("unit/store/createRecord - Store with models by dash", { - beforeEach: function() { + beforeEach() { var env = setupStore({ someThing: DS.Model.extend({ foo: DS.attr('string') }) }); diff --git a/tests/unit/store/has-record-for-id-test.js b/tests/unit/store/has-record-for-id-test.js index 027f453a844..0db692b79a5 100644 --- a/tests/unit/store/has-record-for-id-test.js +++ b/tests/unit/store/has-record-for-id-test.js @@ -12,7 +12,7 @@ var belongsTo = DS.belongsTo; var run = Ember.run; module("unit/store/hasRecordForId - Store hasRecordForId", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ firstName: attr('string'), @@ -40,7 +40,7 @@ module("unit/store/hasRecordForId - Store hasRecordForId", { }, - afterEach: function() { + afterEach() { Ember.run(store, 'destroy'); } }); diff --git a/tests/unit/store/model-for-test.js b/tests/unit/store/model-for-test.js index ffe86b7e6c9..d6d7130f7ee 100644 --- a/tests/unit/store/model-for-test.js +++ b/tests/unit/store/model-for-test.js @@ -14,7 +14,7 @@ var run = Ember.run; var env; module("unit/store/model_for - DS.Store#modelFor", { - beforeEach: function() { + beforeEach() { env = setupStore({ blogPost: DS.Model.extend(), "blog.post": DS.Model.extend() @@ -24,7 +24,7 @@ module("unit/store/model_for - DS.Store#modelFor", { registry = env.registry; }, - afterEach: function() { + afterEach() { run(function() { container.destroy(); store.destroy(); diff --git a/tests/unit/store/peek-record-test.js b/tests/unit/store/peek-record-test.js index 6586755b20a..27bd0570b01 100644 --- a/tests/unit/store/peek-record-test.js +++ b/tests/unit/store/peek-record-test.js @@ -9,7 +9,7 @@ var env, store, Person; var run = Ember.run; module("unit/store/peekRecord - Store peekRecord", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend(); Person.toString = function() { @@ -22,7 +22,7 @@ module("unit/store/peekRecord - Store peekRecord", { store = env.store; }, - afterEach: function() { + afterEach() { Ember.run(store, 'destroy'); } }); diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index c694f1e0a19..fa9ae404338 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -12,7 +12,7 @@ var belongsTo = DS.belongsTo; var run = Ember.run; module("unit/store/push - DS.Store#push", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({ firstName: attr('string'), lastName: attr('string'), @@ -48,7 +48,7 @@ module("unit/store/push - DS.Store#push", { env.registry.register('serializer:post', DS.RESTSerializer); }, - afterEach: function() { + afterEach() { run(function() { store.destroy(); }); @@ -345,13 +345,13 @@ test("Calling pushPayload allows pushing singular payload properties", function( test("Calling pushPayload should use the type's serializer for normalizing", function(assert) { assert.expect(4); env.registry.register('serializer:post', DS.RESTSerializer.extend({ - normalize: function(store, payload) { + normalize(store, payload) { assert.ok(true, "normalized is called on Post serializer"); return this._super(store, payload); } })); env.registry.register('serializer:person', DS.RESTSerializer.extend({ - normalize: function(store, payload) { + normalize(store, payload) { assert.ok(true, "normalized is called on Person serializer"); return this._super(store, payload); } @@ -383,7 +383,7 @@ test("Calling pushPayload without a type uses application serializer's pushPaylo assert.expect(1); env.registry.register('serializer:application', DS.RESTSerializer.extend({ - pushPayload: function(store, payload) { + pushPayload(store, payload) { assert.ok(true, "pushPayload is called on Application serializer"); return this._super(store, payload); } @@ -400,14 +400,14 @@ test("Calling pushPayload without a type should use a model's serializer when no assert.expect(4); env.registry.register('serializer:post', DS.RESTSerializer.extend({ - normalize: function(store, payload) { + normalize(store, payload) { assert.ok(true, "normalized is called on Post serializer"); return this._super(store, payload); } })); env.registry.register('serializer:application', DS.RESTSerializer.extend({ - normalize: function(store, payload) { + normalize(store, payload) { assert.ok(true, "normalized is called on Application serializer"); return this._super(store, payload); } @@ -669,7 +669,7 @@ test("Calling push with unknown keys should not warn by default", function(asser }); module("unit/store/push - DS.Store#push with JSON-API", { - beforeEach: function() { + beforeEach() { var Person = DS.Model.extend({ name: DS.attr('string'), cars: DS.hasMany('car', { async: false }) @@ -694,7 +694,7 @@ module("unit/store/push - DS.Store#push with JSON-API", { }, - afterEach: function() { + afterEach() { run(function() { store.destroy(); }); diff --git a/tests/unit/store/serializer-for-test.js b/tests/unit/store/serializer-for-test.js index 5b719e42858..81a3cea97d2 100644 --- a/tests/unit/store/serializer-for-test.js +++ b/tests/unit/store/serializer-for-test.js @@ -9,7 +9,7 @@ var container, store, registry, Person; var run = Ember.run; module("unit/store/serializer_for - DS.Store#serializerFor", { - beforeEach: function() { + beforeEach() { Person = DS.Model.extend({}); var env = setupStore({ person: Person }); store = env.store; @@ -17,7 +17,7 @@ module("unit/store/serializer_for - DS.Store#serializerFor", { registry = env.registry; }, - afterEach: function() { + afterEach() { run(function() { container.destroy(); store.destroy(); diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index 5a4cd1796cd..1375e0312e7 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -10,7 +10,7 @@ var run = Ember.run; var store, tryToFind, Record; module("unit/store/unload - Store unloading records", { - beforeEach: function() { + beforeEach() { Record = DS.Model.extend({ title: DS.attr('string'), @@ -18,7 +18,7 @@ module("unit/store/unload - Store unloading records", { }); store = createStore({ adapter: DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { tryToFind = true; return Ember.RSVP.resolve({ id: id, wasFetched: true }); } @@ -27,7 +27,7 @@ module("unit/store/unload - Store unloading records", { }); }, - afterEach: function() { + afterEach() { Ember.run(store, 'destroy'); } }); @@ -119,10 +119,10 @@ test("can commit store after unload record with relationships", function(assert) var store = createStore({ adapter: DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, description: 'cuisinart', brand: 1 }); }, - createRecord: function(store, type, snapshot) { + createRecord(store, type, snapshot) { return Ember.RSVP.resolve(); } }), From 828f8eaef753320bf39793b6b3f54a64c970f5a1 Mon Sep 17 00:00:00 2001 From: Trent Willis Date: Tue, 13 Oct 2015 20:59:24 -0700 Subject: [PATCH 1246/2527] Merge normalizeRelationships and setupRelationships methods in store --- addon/system/store.js | 59 ++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/addon/system/store.js b/addon/system/store.js index 036139155d5..84aac5db067 100644 --- a/addon/system/store.js +++ b/addon/system/store.js @@ -1351,7 +1351,7 @@ Store = Service.extend({ } if (data) { // normalize relationship IDs into records - this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, internalModel.type, data); + this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, data); this.updateId(internalModel, data); } @@ -1738,23 +1738,15 @@ Store = Service.extend({ var internalModel = this._load(data); this._backburner.join(() => { - this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, type, data); + this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, data); }); return internalModel; }, - _setupRelationships(record, type, data) { - // If the payload contains relationships that are specified as - // IDs, normalizeRelationships will convert them into DS.Model instances - // (possibly unloaded) before we push the payload into the - // store. - - data = normalizeRelationships(this, type, data); - - - // Now that the pushed record as well as any related records - // are in the store, create the data structures used to track + _setupRelationships(record, data) { + // This will convert relationships specified as IDs into DS.Model instances + // (possibly unloaded) and also create the data structures used to track // relationships. setupRelationships(this, record, data); }, @@ -2043,25 +2035,6 @@ Store = Service.extend({ }); - -function normalizeRelationships(store, type, data, record) { - data.relationships = data.relationships || {}; - type.eachRelationship(function(key, relationship) { - var kind = relationship.kind; - var value; - if (data.relationships[key] && data.relationships[key].data) { - value = data.relationships[key].data; - if (kind === 'belongsTo') { - data.relationships[key].data = deserializeRecordId(store, key, relationship, value); - } else if (kind === 'hasMany') { - data.relationships[key].data = deserializeRecordIds(store, key, relationship, value); - } - } - }); - - return data; -} - function deserializeRecordId(store, key, relationship, id) { if (isNone(id)) { return; @@ -2131,13 +2104,13 @@ function _commit(adapter, store, operation, snapshot) { } function setupRelationships(store, record, data) { - var typeClass = record.type; if (!data.relationships) { return; } - typeClass.eachRelationship((key, descriptor) => { + record.type.eachRelationship((key, descriptor) => { var kind = descriptor.kind; + if (!data.relationships[key]) { return; } @@ -2156,6 +2129,12 @@ function setupRelationships(store, record, data) { relationship = record._relationships.get(key); relationship.updateMeta(data.relationships[key].meta); } + + // If the data contains a relationship that is specified as an ID (or IDs), + // normalizeRelationship will convert them into DS.Model instances + // (possibly unloaded) before we push the payload into the store. + normalizeRelationship(store, key, descriptor, data.relationships[key]); + var value = data.relationships[key].data; if (value !== undefined) { @@ -2170,5 +2149,17 @@ function setupRelationships(store, record, data) { }); } +function normalizeRelationship(store, key, relationship, jsonPayload) { + var data = jsonPayload.data; + if (data) { + var kind = relationship.kind; + if (kind === 'belongsTo') { + jsonPayload.data = deserializeRecordId(store, key, relationship, data); + } else if (kind === 'hasMany') { + jsonPayload.data = deserializeRecordIds(store, key, relationship, data); + } + } +} + export { Store }; export default Store; From 362b0273e423ca5841f3f5ede35018494f9520fa Mon Sep 17 00:00:00 2001 From: Brian Thomas Storti Date: Fri, 4 Dec 2015 13:05:42 +0100 Subject: [PATCH 1247/2527] Specify the status code expected to populate the error object --- addon/system/model/errors.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/system/model/errors.js b/addon/system/model/errors.js index 4e26a004f1c..1412cd01c87 100644 --- a/addon/system/model/errors.js +++ b/addon/system/model/errors.js @@ -36,8 +36,8 @@ var MapWithDefault = Ember.MapWithDefault; user.save(); ``` - Your backend data store might return a response that looks like - this. This response will be used to populate the error object. + Your backend data store might return a response with status code 422 (Unprocessable Entity) + and that looks like this. This response will be used to populate the error object. ```javascript { From 8635f50361e4e970ebffc6bbc107c9edd29a90be Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 12 Oct 2015 10:09:01 -0400 Subject: [PATCH 1248/2527] [BUGFIX beta] Log a warning when when Ember Data is loaded with Ember 1.13 --- addon/index.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/addon/index.js b/addon/index.js index 537985bc56a..b53f48635c2 100644 --- a/addon/index.js +++ b/addon/index.js @@ -5,14 +5,16 @@ import Ember from "ember"; @main ember-data */ -if (Ember.VERSION.match(/^1\.[0-7]\./)) { - throw new Ember.Error("Ember Data requires at least Ember 1.8.0, but you have " + +if (Ember.VERSION.match(/^1\.([0-9]|1[0-2])\./)) { + throw new Ember.Error("Ember Data requires at least Ember 1.13.0, but you have " + Ember.VERSION + - ". Please upgrade your version of Ember, then upgrade Ember Data"); + ". Please upgrade your version of Ember, then upgrade Ember Data."); } -if (Ember.VERSION.match(/^1\.12\.0/)) { - throw new Ember.Error("Ember Data does not work with Ember 1.12.0. Please upgrade to Ember 1.12.1 or higher."); +if (Ember.VERSION.match(/^1\.13\./)) { + Ember.warn(`Use of Ember Data 2+ with Ember 1.13 is unsupported. Please upgrade your version of Ember to 2.0 or higher.`, false, { + id: 'ds.version.ember-1-13' + }); } import DS from "ember-data/core"; From 58819ccad9fb737bebae19ac0734db35ab0d1efe Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 3 Sep 2015 10:21:52 -0700 Subject: [PATCH 1249/2527] tests for #3707 --- .../tests/integration/records/error-test.js | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 packages/ember-data/tests/integration/records/error-test.js diff --git a/packages/ember-data/tests/integration/records/error-test.js b/packages/ember-data/tests/integration/records/error-test.js new file mode 100644 index 00000000000..e5e56eb4454 --- /dev/null +++ b/packages/ember-data/tests/integration/records/error-test.js @@ -0,0 +1,157 @@ +var env, store, Person; +var attr = DS.attr; +var run = Ember.run; + +module('integration/records/error', { + setup: function() { + Person = DS.Model.extend({ + firstName: attr('string'), + lastName: attr('string') + }); + Person.toString = function() { return 'Person'; }; + + env = setupStore({ + person: Person + }); + + store = env.store; + }, + + teardown: function() { + Ember.run(function() { + env.container.destroy(); + }); + } +}); + +test('adding errors during root.loaded.created.invalid works', function() { + expect(3); + + var person = run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + } + } + }); + return store.peekRecord('person', 'wat'); + }); + + Ember.run(() => { + person.set('firstName', null); + person.set('lastName', null); + }); + + equal(person._internalModel.currentState.stateName, 'root.loaded.updated.uncommitted'); + Ember.run(() => person.get('errors').add('firstName', 'is invalid') ); + + equal(person._internalModel.currentState.stateName, 'root.loaded.updated.invalid'); + + Ember.run(() => person.get('errors').add('lastName', 'is invalid') ); + + deepEqual(person.get('errors').toArray(), [ + { attribute: 'firstName', message: 'is invalid' }, + { attribute: 'lastName', message: 'is invalid' } + ]); +}); + + +test('adding errors root.loaded.created.invalid works', function() { + expect(3); + + var person = run(() => { + return store.createRecord('person', { + id: 'wat', + firstName: 'Yehuda', + lastName: 'Katz' + }); + }); + + Ember.run(() => { + person.set('firstName', null); + person.set('lastName', null); + }); + + equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); + + Ember.run(() => person.get('errors').add('firstName', 'is invalid') ); + + equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); + + Ember.run(() => person.get('errors').add('lastName', 'is invalid') ); + + deepEqual(person.get('errors').toArray(), [ + { attribute: 'firstName', message: 'is invalid' }, + { attribute: 'lastName', message: 'is invalid' } + ]); +}); + +test('adding errors root.loaded.created.invalid works add + remove + add', function() { + expect(4); + + var person = run(() => { + return store.createRecord('person', { + id: 'wat', + firstName: 'Yehuda' + }); + }); + + Ember.run(() => { + person.set('firstName', null); + }); + + equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); + + Ember.run(() => person.get('errors').add('firstName', 'is invalid') ); + + equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); + + Ember.run(() => person.get('errors').remove('firstName')); + + deepEqual(person.get('errors').toArray(), []); + + Ember.run(() => person.get('errors').add('firstName', 'is invalid') ); + + deepEqual(person.get('errors').toArray(), [ + { attribute: 'firstName', message: 'is invalid' } + ]); +}); + +test('adding errors root.loaded.created.invalid works add + (remove, add)', function() { + expect(4); + + var person = run(() => { + return store.createRecord('person', { + id: 'wat', + firstName: 'Yehuda' + }); + }); + + Ember.run(() => { + person.set('firstName', null); + }); + + equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); + + Ember.run(() => { + person.get('errors').add('firstName', 'is invalid'); + }); + + equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); + + Ember.run(() => { + person.get('errors').remove('firstName'); + person.get('errors').add('firstName', 'is invalid'); + }); + + + equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); + + deepEqual(person.get('errors').toArray(), [ + { attribute: 'firstName', message: 'is invalid' } + ]); +}); From 63e94324a468a113b4ade8d3385689fb9c29f9b6 Mon Sep 17 00:00:00 2001 From: Ryan Tablada Date: Sun, 16 Aug 2015 21:24:04 -0500 Subject: [PATCH 1250/2527] Added documentation to modify the hash by reference --- addon/serializers/json-serializer.js | 1 + addon/serializers/rest-serializer.js | 1 + 2 files changed, 2 insertions(+) diff --git a/addon/serializers/json-serializer.js b/addon/serializers/json-serializer.js index 69299ccf236..907da639ac1 100644 --- a/addon/serializers/json-serializer.js +++ b/addon/serializers/json-serializer.js @@ -1005,6 +1005,7 @@ export default Serializer.extend({ the payload and just sends the raw serialized JSON object. If your server expects namespaced keys, you should consider using the RESTSerializer. Otherwise you can override this method to customize how the record is added to the hash. + The hash property should be modified by reference. For example, your server may expect underscored root objects. diff --git a/addon/serializers/rest-serializer.js b/addon/serializers/rest-serializer.js index 0b9325142a0..b598e86ae10 100644 --- a/addon/serializers/rest-serializer.js +++ b/addon/serializers/rest-serializer.js @@ -625,6 +625,7 @@ var RESTSerializer = JSONSerializer.extend({ /** You can use this method to customize the root keys serialized into the JSON. + The hash property should be modified by reference (possibly using something like _.extend) By default the REST Serializer sends the modelName of a model, which is a camelized version of the name. From ef406a25a1c9ee18bbaa8e9ca5e7f0886c62c5bb Mon Sep 17 00:00:00 2001 From: Nik Wakelin Date: Fri, 4 Dec 2015 18:07:37 +0000 Subject: [PATCH 1251/2527] Adds more detailed ("friendly") RESTAdapter Error Messages --- addon/adapters/rest-adapter.js | 48 ++++++++++++-- .../integration/adapter/rest-adapter-test.js | 66 ++++++++++++++++++- .../rest-adapter/detailed-message-test.js | 51 ++++++++++++++ 3 files changed, 157 insertions(+), 8 deletions(-) create mode 100644 tests/unit/adapters/rest-adapter/detailed-message-test.js diff --git a/addon/adapters/rest-adapter.js b/addon/adapters/rest-adapter.js index 26098e3eb58..f2e1906354a 100644 --- a/addon/adapters/rest-adapter.js +++ b/addon/adapters/rest-adapter.js @@ -743,18 +743,20 @@ export default Adapter.extend(BuildURLMixin, { @param {Number} status @param {Object} headers @param {Object} payload + @param {Object} requestData - the original request information @return {Object | DS.AdapterError} response */ - handleResponse(status, headers, payload) { + handleResponse(status, headers, payload, requestData) { if (this.isSuccess(status, headers, payload)) { return payload; } else if (this.isInvalid(status, headers, payload)) { return new InvalidError(payload.errors); } - let errors = this.normalizeErrorResponse(status, headers, payload); + let errors = this.normalizeErrorResponse(status, headers, payload); + let detailedMessage = this.generatedDetailedMessage(status, headers, payload, requestData); - return new AdapterError(errors); + return new AdapterError(errors, detailedMessage); }, /** @@ -812,6 +814,11 @@ export default Adapter.extend(BuildURLMixin, { ajax(url, type, options) { var adapter = this; + var requestData = { + url: url, + method: type + }; + return new Ember.RSVP.Promise(function(resolve, reject) { var hash = adapter.ajaxOptions(url, type, options); @@ -820,7 +827,8 @@ export default Adapter.extend(BuildURLMixin, { let response = adapter.handleResponse( jqXHR.status, parseResponseHeaders(jqXHR.getAllResponseHeaders()), - payload + payload, + requestData ); if (response instanceof AdapterError) { @@ -844,7 +852,8 @@ export default Adapter.extend(BuildURLMixin, { error = adapter.handleResponse( jqXHR.status, parseResponseHeaders(jqXHR.getAllResponseHeaders()), - adapter.parseErrorResponse(jqXHR.responseText) || errorThrown + adapter.parseErrorResponse(jqXHR.responseText) || errorThrown, + requestData ); } } @@ -922,6 +931,35 @@ export default Adapter.extend(BuildURLMixin, { } ]; } + }, + + /** + Generates a detailed ("friendly") error message, with plenty + of information for debugging (good luck!) + + @method generatedDetailedMessage + @private + @param {Number} status + @param {Object} headers + @param {Object} payload + @return {Object} request information + */ + generatedDetailedMessage: function(status, headers, payload, requestData) { + var shortenedPayload; + var payloadContentType = headers["Content-Type"] || "Empty Content-Type"; + + if (payloadContentType === "text/html" && payload.length > 250) { + shortenedPayload = "[Omitted Lengthy HTML]"; + } else { + shortenedPayload = payload; + } + + var requestDescription = requestData.method + ' ' + requestData.url; + var payloadDescription = 'Payload (' + payloadContentType + ')'; + + return ['Ember Data Request ' + requestDescription + ' returned a ' + status, + payloadDescription, + shortenedPayload].join('\n'); } }); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 4d99db2543c..de6fefa4afc 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -2194,8 +2194,8 @@ test("calls adapter.handleResponse with the jqXHR and json", function(assert) { } }); -test('calls handleResponse with jqXHR, jqXHR.responseText', function(assert) { - assert.expect(3); +test('calls handleResponse with jqXHR, jqXHR.responseText, and requestData', function(assert) { + assert.expect(4); var originalAjax = Ember.$.ajax; var jqXHR = { status: 400, @@ -2203,13 +2203,19 @@ test('calls handleResponse with jqXHR, jqXHR.responseText', function(assert) { getAllResponseHeaders() { return ''; } }; + var expectedRequestData = { + method: "GET", + url: "/posts/1" + }; + Ember.$.ajax = function(hash) { hash.error(jqXHR, jqXHR.responseText, 'Bad Request'); }; - adapter.handleResponse = function(status, headers, json) { + adapter.handleResponse = function(status, headers, json, requestData) { assert.deepEqual(status, 400); assert.deepEqual(json, jqXHR.responseText); + assert.deepEqual(requestData, expectedRequestData); return new DS.AdapterError('nope!'); }; @@ -2312,6 +2318,60 @@ test('on error wraps the error string in an DS.AdapterError object', function(as } }); +test('error handling includes a detailed message from the server', (assert) => { + assert.expect(2); + + let originalAjax = Ember.$.ajax; + let jqXHR = { + status: 500, + responseText: 'An error message, perhaps generated from a backend server!', + getAllResponseHeaders: function() { return 'Content-Type: text/plain'; } + }; + + Ember.$.ajax = function(hash) { + hash.error(jqXHR, 'error'); + }; + + try { + run(function() { + store.find('post', '1').catch(function(err) { + assert.equal(err.message, "Ember Data Request GET /posts/1 returned a 500\nPayload (text/plain)\nAn error message, perhaps generated from a backend server!"); + assert.ok(err, 'promise rejected'); + }); + }); + } finally { + Ember.$.ajax = originalAjax; + } + +}); + +test('error handling with a very long HTML-formatted payload truncates the friendly message', (assert) => { + assert.expect(2); + + let originalAjax = Ember.$.ajax; + let jqXHR = { + status: 500, + responseText: new Array(100).join(""), + getAllResponseHeaders: function() { return 'Content-Type: text/html'; } + }; + + Ember.$.ajax = function(hash) { + hash.error(jqXHR, 'error'); + }; + + try { + run(function() { + store.find('post', '1').catch(function(err) { + assert.equal(err.message, "Ember Data Request GET /posts/1 returned a 500\nPayload (text/html)\n[Omitted Lengthy HTML]"); + assert.ok(err, 'promise rejected'); + }); + }); + } finally { + Ember.$.ajax = originalAjax; + } + +}); + test('findAll resolves with a collection of DS.Models, not DS.InternalModels', (assert) => { assert.expect(4); diff --git a/tests/unit/adapters/rest-adapter/detailed-message-test.js b/tests/unit/adapters/rest-adapter/detailed-message-test.js new file mode 100644 index 00000000000..0078b54f1a0 --- /dev/null +++ b/tests/unit/adapters/rest-adapter/detailed-message-test.js @@ -0,0 +1,51 @@ +import setupStore from 'dummy/tests/helpers/store'; + +import {module, test} from 'qunit'; + +import DS from 'ember-data'; + +let adapter, env; + +module("unit/adapters/rest_adapter/detailed_message_test - DS.RESTAdapter#generatedDetailedMessage", { + + beforeEach() { + env = setupStore({ adapter: DS.RESTAdapter }); + adapter = env.adapter; + } + +}); + +test("generating a wonderfully friendly error message should work", (assert) => { + assert.expect(1); + + let friendlyMessage = adapter.generatedDetailedMessage( + 418, + { "Content-Type": "text/plain" }, + "I'm a little teapot, short and stout", + { + url: "/teapots/testing", + method: "GET" + } + ); + + assert.equal(friendlyMessage, ["Ember Data Request GET /teapots/testing returned a 418", + "Payload (text/plain)", + "I'm a little teapot, short and stout"].join("\n")); +}); + +test("generating a friendly error message with a missing content-type header should work", (assert) => { + + let friendlyMessage = adapter.generatedDetailedMessage( + 418, + {}, + "I'm a little teapot, short and stout", + { + url: "/teapots/testing", + method: "GET" + } + ); + + assert.equal(friendlyMessage, ["Ember Data Request GET /teapots/testing returned a 418", + "Payload (Empty Content-Type)", + "I'm a little teapot, short and stout"].join("\n")); +}); From 94fd6422da1922f5250d2f027ec071425fa56f5e Mon Sep 17 00:00:00 2001 From: Sylvain Mina Date: Tue, 14 Oct 2014 11:04:39 +0200 Subject: [PATCH 1252/2527] Directly reloading a hasMany with links should trigger only one request Introducing a loading promise in the many relationship in order to keep track of its loading state. --- addon/system/relationships/state/has-many.js | 15 +++- .../relationships/has-many-test.js | 75 +++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/addon/system/relationships/state/has-many.js b/addon/system/relationships/state/has-many.js index 94bf50640cd..57218c8a682 100644 --- a/addon/system/relationships/state/has-many.js +++ b/addon/system/relationships/state/has-many.js @@ -99,6 +99,17 @@ ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) ManyRelationship.prototype.reload = function() { var self = this; + var manyArrayLoadedState = this.manyArray.get('isLoaded'); + + if (this._loadingPromise) { + if (this._loadingPromise.get('isPending')) { + return this._loadingPromise; + } + if (this._loadingPromise.get('isRejected')) { + this.manyArray.set('isLoaded', manyArrayLoadedState); + } + } + if (this.link) { return this.fetchLink(); } else { @@ -147,6 +158,7 @@ ManyRelationship.prototype.fetchLink = function() { } this.store._backburner.join(() => { this.updateRecordsFromAdapter(records); + this.manyArray.set('isLoaded', true); }); return this.manyArray; }); @@ -180,10 +192,11 @@ ManyRelationship.prototype.getRecords = function() { } else { promise = this.findRecords(); } - return PromiseManyArray.create({ + this._loadingPromise = PromiseManyArray.create({ content: this.manyArray, promise: promise }); + return this._loadingPromise; } else { Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 122873d950b..c85ce96382f 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -552,6 +552,81 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio }); }); +test("A hasMany relationship can be reloaded even if it failed at the first time", function(assert) { + assert.expect(4); + + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + env.adapter.findRecord = function(store, type, id) { + return Ember.RSVP.resolve({ id: 1, links: { comments: "/posts/1/comments" } }); + }; + + var loadingCount = -1; + env.adapter.findHasMany = function(store, record, link, relationship) { + loadingCount++; + if (loadingCount % 2 === 0) { + return Ember.RSVP.reject(); + } else { + return Ember.RSVP.resolve([ + { id: 1, body: "FirstUpdated" }, + { id: 2, body: "Second" } + ]); + } + }; + run(function() { + env.store.find('post', 1).then(function(post) { + var comments = post.get('comments'); + return comments.catch(function() { + return comments.reload(); + }).then(function(manyArray) { + assert.equal(manyArray.get('isLoaded'), true, "the reload worked, comments are now loaded"); + return manyArray.reload().catch(function () { + assert.equal(manyArray.get('isLoaded'), true, "the second reload failed, comments are still loaded though"); + return manyArray.reload().then(function(reloadedManyArray) { + assert.equal(reloadedManyArray.get('isLoaded'), true, "the third reload worked, comments are loaded again"); + assert.ok(reloadedManyArray === manyArray, "the many array stays the same"); + }); + }); + }); + }); + }); +}); + +test("A hasMany relationship can be directly reloaded if it was fetched via links", function(assert) { + assert.expect(6); + + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + env.adapter.findRecord = function(store, type, id) { + assert.equal(type, Post, "find type was Post"); + assert.equal(id, "1", "find id was 1"); + + return Ember.RSVP.resolve({ id: 1, links: { comments: "/posts/1/comments" } }); + }; + + env.adapter.findHasMany = function(store, record, link, relationship) { + assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); + + return Ember.RSVP.resolve([ + { id: 1, body: "FirstUpdated" }, + { id: 2, body: "Second" } + ]); + }; + run(function() { + env.store.find('post', 1).then(function(post) { + return post.get('comments').reload().then(function(comments) { + assert.equal(comments.get('isLoaded'), true, "comments are loaded"); + assert.equal(comments.get('length'), 2, "comments have 2 length"); + assert.equal(comments.get('firstObject.body'), "FirstUpdated", "Record body was correctly updated"); + }); + }); + }); +}); + test("A hasMany relationship can be directly reloaded if it was fetched via ids", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) From 890c2c1af9b4fda5fc17a8288dc488fb991493e2 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sat, 5 Dec 2015 19:40:42 +0100 Subject: [PATCH 1253/2527] [CLEANUP] move test file to correct location Also update test structure using `ember watson:upgrade-qunit-tests`. --- .../integration/records/error-test.js | 53 ++++++++++--------- 1 file changed, 29 insertions(+), 24 deletions(-) rename {packages/ember-data/tests => tests}/integration/records/error-test.js (64%) diff --git a/packages/ember-data/tests/integration/records/error-test.js b/tests/integration/records/error-test.js similarity index 64% rename from packages/ember-data/tests/integration/records/error-test.js rename to tests/integration/records/error-test.js index e5e56eb4454..47db5ef8f6d 100644 --- a/packages/ember-data/tests/integration/records/error-test.js +++ b/tests/integration/records/error-test.js @@ -1,9 +1,14 @@ +import Ember from 'ember'; +import {module, test} from 'qunit'; +import DS from 'ember-data'; +import setupStore from 'dummy/tests/helpers/store'; + var env, store, Person; var attr = DS.attr; var run = Ember.run; module('integration/records/error', { - setup: function() { + beforeEach: function() { Person = DS.Model.extend({ firstName: attr('string'), lastName: attr('string') @@ -17,15 +22,15 @@ module('integration/records/error', { store = env.store; }, - teardown: function() { + afterEach: function() { Ember.run(function() { env.container.destroy(); }); } }); -test('adding errors during root.loaded.created.invalid works', function() { - expect(3); +test('adding errors during root.loaded.created.invalid works', function(assert) { + assert.expect(3); var person = run(() => { store.push({ @@ -46,22 +51,22 @@ test('adding errors during root.loaded.created.invalid works', function() { person.set('lastName', null); }); - equal(person._internalModel.currentState.stateName, 'root.loaded.updated.uncommitted'); + assert.equal(person._internalModel.currentState.stateName, 'root.loaded.updated.uncommitted'); Ember.run(() => person.get('errors').add('firstName', 'is invalid') ); - equal(person._internalModel.currentState.stateName, 'root.loaded.updated.invalid'); + assert.equal(person._internalModel.currentState.stateName, 'root.loaded.updated.invalid'); Ember.run(() => person.get('errors').add('lastName', 'is invalid') ); - deepEqual(person.get('errors').toArray(), [ + assert.deepEqual(person.get('errors').toArray(), [ { attribute: 'firstName', message: 'is invalid' }, { attribute: 'lastName', message: 'is invalid' } ]); }); -test('adding errors root.loaded.created.invalid works', function() { - expect(3); +test('adding errors root.loaded.created.invalid works', function(assert) { + assert.expect(3); var person = run(() => { return store.createRecord('person', { @@ -76,22 +81,22 @@ test('adding errors root.loaded.created.invalid works', function() { person.set('lastName', null); }); - equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); + assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); Ember.run(() => person.get('errors').add('firstName', 'is invalid') ); - equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); + assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); Ember.run(() => person.get('errors').add('lastName', 'is invalid') ); - deepEqual(person.get('errors').toArray(), [ + assert.deepEqual(person.get('errors').toArray(), [ { attribute: 'firstName', message: 'is invalid' }, { attribute: 'lastName', message: 'is invalid' } ]); }); -test('adding errors root.loaded.created.invalid works add + remove + add', function() { - expect(4); +test('adding errors root.loaded.created.invalid works add + remove + add', function(assert) { + assert.expect(4); var person = run(() => { return store.createRecord('person', { @@ -104,25 +109,25 @@ test('adding errors root.loaded.created.invalid works add + remove + add', funct person.set('firstName', null); }); - equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); + assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); Ember.run(() => person.get('errors').add('firstName', 'is invalid') ); - equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); + assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); Ember.run(() => person.get('errors').remove('firstName')); - deepEqual(person.get('errors').toArray(), []); + assert.deepEqual(person.get('errors').toArray(), []); Ember.run(() => person.get('errors').add('firstName', 'is invalid') ); - deepEqual(person.get('errors').toArray(), [ + assert.deepEqual(person.get('errors').toArray(), [ { attribute: 'firstName', message: 'is invalid' } ]); }); -test('adding errors root.loaded.created.invalid works add + (remove, add)', function() { - expect(4); +test('adding errors root.loaded.created.invalid works add + (remove, add)', function(assert) { + assert.expect(4); var person = run(() => { return store.createRecord('person', { @@ -135,13 +140,13 @@ test('adding errors root.loaded.created.invalid works add + (remove, add)', func person.set('firstName', null); }); - equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); + assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); Ember.run(() => { person.get('errors').add('firstName', 'is invalid'); }); - equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); + assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); Ember.run(() => { person.get('errors').remove('firstName'); @@ -149,9 +154,9 @@ test('adding errors root.loaded.created.invalid works add + (remove, add)', func }); - equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); + assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); - deepEqual(person.get('errors').toArray(), [ + assert.deepEqual(person.get('errors').toArray(), [ { attribute: 'firstName', message: 'is invalid' } ]); }); From 647e80a647d43ccc028c964f3f35fe203f202539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Grosjean?= Date: Thu, 23 Oct 2014 00:31:43 +0300 Subject: [PATCH 1254/2527] Add failing test on PromiseArray.createRecord when called before hasMany is loaded --- .../relationships/has-many-test.js | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 122873d950b..913b029ca7f 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -2475,3 +2475,40 @@ test("Updated related link should take precedence over local data", function(ass }); }); }); + +test("PromiseArray proxies createRecord to its ManyArray before the hasMany is loaded", function(assert) { + assert.expect(1); + + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + env.adapter.findHasMany = function(store, record, link, relationship) { + return Ember.RSVP.resolve([ + { id: 1, body: "First" }, + { id: 2, body: "Second" } + ]); + }; + + run(function() { + var post = env.store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + links: { + related: 'someLink' + } + } + } + } + }); + + var comments = post.get('comments'); + comments.createRecord(); + comments.then(function(comments) { + assert.equal(comments.get('length'), 3, "comments have 3 length, including new record"); + }); + }); +}); From 27a2a18b7171a97ad3005124fab754c2b7071bb3 Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 7 Dec 2015 21:49:12 +0100 Subject: [PATCH 1255/2527] [CLEANUP] use debug helpers from ember-data/debug By this, the calls to `assert`, `warn` etcetera are corectly stripped when a new production build is created. --- addon/index.js | 3 +- addon/serializers/embedded-records-mixin.js | 4 +- addon/serializers/json-api-serializer.js | 7 +- addon/serializers/json-serializer.js | 7 +- addon/serializers/rest-serializer.js | 11 +- addon/system/container-proxy.js | 4 +- addon/system/many-array.js | 3 +- addon/system/model/attributes.js | 5 +- addon/system/model/errors.js | 10 +- addon/system/model/internal-model.js | 7 +- addon/system/model/model.js | 13 +- addon/system/model/states.js | 4 +- addon/system/promise-proxies.js | 4 +- addon/system/relationships/belongs-to.js | 7 +- addon/system/relationships/ext.js | 13 +- addon/system/relationships/has-many.js | 7 +- .../system/relationships/state/belongs-to.js | 5 +- addon/system/relationships/state/has-many.js | 3 +- .../relationships/state/relationship.js | 5 +- addon/system/store.js | 121 +++++++++--------- addon/system/store/finders.js | 15 ++- addon/system/store/serializer-response.js | 6 +- addon/utils.js | 3 +- 23 files changed, 148 insertions(+), 119 deletions(-) diff --git a/addon/index.js b/addon/index.js index b53f48635c2..60a62d2da1d 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,4 +1,5 @@ import Ember from "ember"; +import { warn } from "ember-data/debug"; /** Ember Data @module ember-data @@ -12,7 +13,7 @@ if (Ember.VERSION.match(/^1\.([0-9]|1[0-2])\./)) { } if (Ember.VERSION.match(/^1\.13\./)) { - Ember.warn(`Use of Ember Data 2+ with Ember 1.13 is unsupported. Please upgrade your version of Ember to 2.0 or higher.`, false, { + warn(`Use of Ember Data 2+ with Ember 1.13 is unsupported. Please upgrade your version of Ember to 2.0 or higher.`, false, { id: 'ds.version.ember-1-13' }); } diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 5036da48af7..3040baf6863 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -1,3 +1,5 @@ +import { warn } from "ember-data/debug"; + var get = Ember.get; var set = Ember.set; var camelize = Ember.String.camelize; @@ -331,7 +333,7 @@ export default Ember.Mixin.create({ _serializeEmbeddedHasMany(snapshot, json, relationship) { let serializedKey = this.keyForAttribute(relationship.key, 'serialize'); - Ember.warn( + warn( `The embedded relationship '${serializedKey}' is undefined for '${snapshot.modelName}' with id '${snapshot.id}'. Please include it in your original payload.`, Ember.typeOf(snapshot.hasMany(relationship.key)) !== 'undefined', { id: 'ds.serializer.embedded-relationship-undefined' } diff --git a/addon/serializers/json-api-serializer.js b/addon/serializers/json-api-serializer.js index 1162ecebd95..d29a01a641c 100644 --- a/addon/serializers/json-api-serializer.js +++ b/addon/serializers/json-api-serializer.js @@ -2,6 +2,7 @@ @module ember-data */ +import { assert, runInDebug, warn } from 'ember-data/debug'; import JSONSerializer from 'ember-data/serializers/json-serializer'; import normalizeModelName from 'ember-data/system/normalize-model-name'; import { pluralize, singularize } from 'ember-inflector'; @@ -136,14 +137,14 @@ const JSONAPISerializer = JSONSerializer.extend({ @private */ _normalizeResourceHelper(resourceHash) { - Ember.assert(this.warnMessageForUndefinedType(), !Ember.isNone(resourceHash.type), { + assert(this.warnMessageForUndefinedType(), !Ember.isNone(resourceHash.type), { id: 'ds.serializer.type-is-undefined' }); let modelName = this.modelNameFromPayloadKey(resourceHash.type); if (!this.store._hasModelFor(modelName)) { - Ember.warn(this.warnMessageNoModelForType(modelName, resourceHash.type), false, { + warn(this.warnMessageNoModelForType(modelName, resourceHash.type), false, { id: 'ds.serializer.model-for-type-missing' }); return null; @@ -467,7 +468,7 @@ const JSONAPISerializer = JSONSerializer.extend({ } }); -Ember.runInDebug(function() { +runInDebug(function() { JSONAPISerializer.reopen({ warnMessageForUndefinedType() { return 'Encountered a resource object with an undefined type (resolved resource using ' + this.constructor.toString() + ')'; diff --git a/addon/serializers/json-serializer.js b/addon/serializers/json-serializer.js index 907da639ac1..0f35d983b1e 100644 --- a/addon/serializers/json-serializer.js +++ b/addon/serializers/json-serializer.js @@ -1,3 +1,4 @@ +import { assert, warn } from 'ember-data/debug'; import Serializer from "ember-data/system/serializer"; import coerceId from "ember-data/system/coerce-id"; import normalizeModelName from "ember-data/system/normalize-model-name"; @@ -440,7 +441,7 @@ export default Serializer.extend({ let meta = this.extractMeta(store, primaryModelClass, payload); if (meta) { - Ember.assert('The `meta` returned from `extractMeta` has to be an object, not "' + Ember.typeOf(meta) + '".', Ember.typeOf(meta) === 'object'); + assert('The `meta` returned from `extractMeta` has to be an object, not "' + Ember.typeOf(meta) + '".', Ember.typeOf(meta) === 'object'); documentHash.meta = meta; } @@ -750,7 +751,7 @@ export default Serializer.extend({ @return {String} key */ _getMappedKey(key, modelClass) { - Ember.warn('There is no attribute or relationship with the name `' + key + '` on `' + modelClass.modelName + '`. Check your serializers attrs hash.', get(modelClass, 'attributes').has(key) || get(modelClass, 'relationshipsByName').has(key), { + warn('There is no attribute or relationship with the name `' + key + '` on `' + modelClass.modelName + '`. Check your serializers attrs hash.', get(modelClass, 'attributes').has(key) || get(modelClass, 'relationshipsByName').has(key), { id: 'ds.serializer.no-mapped-attrs-key' }); @@ -1373,7 +1374,7 @@ export default Serializer.extend({ transformFor(attributeType, skipAssertion) { var transform = getOwner(this).lookup('transform:' + attributeType); - Ember.assert("Unable to find transform for '" + attributeType + "'", skipAssertion || !!transform); + assert("Unable to find transform for '" + attributeType + "'", skipAssertion || !!transform); return transform; } diff --git a/addon/serializers/rest-serializer.js b/addon/serializers/rest-serializer.js index b598e86ae10..44496a3c4ab 100644 --- a/addon/serializers/rest-serializer.js +++ b/addon/serializers/rest-serializer.js @@ -2,6 +2,7 @@ @module ember-data */ +import { assert, deprecate, runInDebug, warn } from "ember-data/debug"; import JSONSerializer from "ember-data/serializers/json-serializer"; import normalizeModelName from "ember-data/system/normalize-model-name"; import {singularize} from "ember-inflector"; @@ -225,7 +226,7 @@ var RESTSerializer = JSONSerializer.extend({ let meta = this.extractMeta(store, primaryModelClass, payload); if (meta) { - Ember.assert('The `meta` returned from `extractMeta` has to be an object, not "' + Ember.typeOf(meta) + '".', Ember.typeOf(meta) === 'object'); + assert('The `meta` returned from `extractMeta` has to be an object, not "' + Ember.typeOf(meta) + '".', Ember.typeOf(meta) === 'object'); documentHash.meta = meta; } @@ -263,7 +264,7 @@ var RESTSerializer = JSONSerializer.extend({ var typeName = this.modelNameFromPayloadKey(modelName); if (!store.modelFactoryFor(typeName)) { - Ember.warn(this.warnMessageNoModelForKey(modelName, typeName), false, { + warn(this.warnMessageNoModelForKey(modelName, typeName), false, { id: 'ds.serializer.model-for-key-missing' }); continue; @@ -383,7 +384,7 @@ var RESTSerializer = JSONSerializer.extend({ for (var prop in payload) { var modelName = this.modelNameFromPayloadKey(prop); if (!store.modelFactoryFor(modelName)) { - Ember.warn(this.warnMessageNoModelForKey(prop, modelName), false, { + warn(this.warnMessageNoModelForKey(prop, modelName), false, { id: 'ds.serializer.model-for-key-missing' }); continue; @@ -727,7 +728,7 @@ var RESTSerializer = JSONSerializer.extend({ // `keyForPolymorphicType`. If this is the case, a deprecation warning is // logged and the old way is restored (so nothing breaks). if (key !== typeKey && this.keyForPolymorphicType === RESTSerializer.prototype.keyForPolymorphicType) { - Ember.deprecate("The key to serialize the type of a polymorphic record is created via keyForAttribute which has been deprecated. Use the keyForPolymorphicType hook instead.", false, { + deprecate("The key to serialize the type of a polymorphic record is created via keyForAttribute which has been deprecated. Use the keyForPolymorphicType hook instead.", false, { id: 'ds.rest-serializer.deprecated-key-for-polymorphic-type', until: '3.0.0' }); @@ -787,7 +788,7 @@ var RESTSerializer = JSONSerializer.extend({ } }); -Ember.runInDebug(function() { +runInDebug(function() { RESTSerializer.reopen({ warnMessageNoModelForKey(prop, typeKey) { return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + typeKey + '" (resolved model name using ' + this.constructor.toString() + '.modelNameFromPayloadKey("' + prop + '"))'; diff --git a/addon/system/container-proxy.js b/addon/system/container-proxy.js index 471f0f26f6a..7cf0a5dd1a4 100644 --- a/addon/system/container-proxy.js +++ b/addon/system/container-proxy.js @@ -1,3 +1,5 @@ +import { deprecate } from "ember-data/debug"; + /** This is used internally to enable deprecation of container paths and provide a decent message to the user indicating how to fix the issue. @@ -28,7 +30,7 @@ ContainerProxy.prototype.registerAlias = function(source, dest, preLookup) { ContainerProxy.prototype.registerDeprecation = function(deprecated, valid) { var preLookupCallback = function() { - Ember.deprecate(`You tried to look up '${deprecated}', but this has been deprecated in favor of '${valid}'.`, false, { + deprecate(`You tried to look up '${deprecated}', but this has been deprecated in favor of '${valid}'.`, false, { id: 'ds.store.deprecated-lookup', until: '2.0.0' }); diff --git a/addon/system/many-array.js b/addon/system/many-array.js index 2bf8b5bd300..4f376cbdafb 100644 --- a/addon/system/many-array.js +++ b/addon/system/many-array.js @@ -1,6 +1,7 @@ /** @module ember-data */ +import { assert } from "ember-data/debug"; import { PromiseArray } from "ember-data/system/promise-proxies"; var get = Ember.get; @@ -272,7 +273,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { var type = get(this, 'type'); var record; - Ember.assert("You cannot add '" + type.modelName + "' records to this polymorphic relationship.", !get(this, 'isPolymorphic')); + assert("You cannot add '" + type.modelName + "' records to this polymorphic relationship.", !get(this, 'isPolymorphic')); record = store.createRecord(type.modelName, hash); this.pushObject(record); diff --git a/addon/system/model/attributes.js b/addon/system/model/attributes.js index 8437ef103fe..aaf79ffc3f3 100644 --- a/addon/system/model/attributes.js +++ b/addon/system/model/attributes.js @@ -1,4 +1,5 @@ import Model from "ember-data/system/model/model"; +import { assert, deprecate } from "ember-data/debug"; /** @module ember-data @@ -55,7 +56,7 @@ Model.reopenClass({ this.eachComputedProperty((name, meta) => { if (meta.isAttribute) { - Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.toString(), name !== 'id'); + assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.toString(), name !== 'id'); meta.name = name; map.set(name, meta); @@ -227,7 +228,7 @@ function getDefaultValue(record, options, key) { return options.defaultValue.apply(null, arguments); } else { let defaultValue = options.defaultValue; - Ember.deprecate(`Non primitive defaultValues are deprecated because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.`, + deprecate(`Non primitive defaultValues are deprecated because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.`, typeof defaultValue !== 'object' || defaultValue === null, { id: 'ds.defaultValue.complex-object', until: '3.0.0' diff --git a/addon/system/model/errors.js b/addon/system/model/errors.js index 1412cd01c87..4899ea09926 100644 --- a/addon/system/model/errors.js +++ b/addon/system/model/errors.js @@ -1,3 +1,5 @@ +import { deprecate, warn } from "ember-data/debug"; + var get = Ember.get; var set = Ember.set; var isEmpty = Ember.isEmpty; @@ -110,7 +112,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @deprecated */ registerHandlers(target, becameInvalid, becameValid) { - Ember.deprecate( + deprecate( `Record errors will no longer be evented.`, false, { id: 'ds.errors.registerHandlers', until: '3.0.0' @@ -236,7 +238,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @deprecated */ add(attribute, messages) { - Ember.warn(`Interacting with a record errors object will no longer change the record state.`, false, { + warn(`Interacting with a record errors object will no longer change the record state.`, false, { id: 'ds.errors.add' }); @@ -315,7 +317,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @deprecated */ remove(attribute) { - Ember.warn(`Interacting with a record errors object will no longer change the record state.`, false, { + warn(`Interacting with a record errors object will no longer change the record state.`, false, { id: 'ds.errors.remove' }); @@ -367,7 +369,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @deprecated */ clear() { - Ember.warn(`Interacting with a record errors object will no longer change the record state.`, false, { + warn(`Interacting with a record errors object will no longer change the record state.`, false, { id: 'ds.errors.clear' }); diff --git a/addon/system/model/internal-model.js b/addon/system/model/internal-model.js index d87e97facb5..b21d2251418 100644 --- a/addon/system/model/internal-model.js +++ b/addon/system/model/internal-model.js @@ -1,3 +1,4 @@ +import { assert } from "ember-data/debug"; import merge from "ember-data/system/merge"; import RootState from "ember-data/system/model/states"; import Relationships from "ember-data/system/relationships/state/create"; @@ -113,7 +114,7 @@ InternalModel.prototype = { constructor: InternalModel, materializeRecord() { - Ember.assert("Materialized " + this.modelName + " record with id:" + this.id + "more than once", this.record === null || this.record === undefined); + assert("Materialized " + this.modelName + " record with id:" + this.id + "more than once", this.record === null || this.record === undefined); // lookupFactory should really return an object that creates // instances with the injections applied @@ -563,7 +564,7 @@ InternalModel.prototype = { }, _preloadHasMany(key, preloadValue, type) { - Ember.assert("You need to pass in an array to set a hasMany property on a record", Ember.isArray(preloadValue)); + assert("You need to pass in an array to set a hasMany property on a record", Ember.isArray(preloadValue)); var internalModel = this; var recordsToSet = preloadValue.map((recordToPush) => { @@ -603,7 +604,7 @@ InternalModel.prototype = { }, setId(id) { - Ember.assert('A record\'s id cannot be changed once it is in the loaded state', this.id === null || this.id === id || this.isNew()); + assert('A record\'s id cannot be changed once it is in the loaded state', this.id === null || this.id === id || this.isNew()); this.id = id; if (this.record.get('id') !== id) { this.record.set('id', id); diff --git a/addon/system/model/model.js b/addon/system/model/model.js index aca930d20ab..c8961461f30 100644 --- a/addon/system/model/model.js +++ b/addon/system/model/model.js @@ -1,3 +1,4 @@ +import { assert, deprecate } from "ember-data/debug"; import { PromiseObject } from "ember-data/system/promise-proxies"; import Errors from "ember-data/system/model/errors"; @@ -749,20 +750,20 @@ var Model = Ember.Object.extend(Ember.Evented, { // rely on the data property. willMergeMixin(props) { var constructor = this.constructor; - Ember.assert('`' + intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + constructor.toString(), !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0]); - Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + constructor.toString(), Object.keys(props).indexOf('id') === -1); + assert('`' + intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + constructor.toString(), !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0]); + assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + constructor.toString(), Object.keys(props).indexOf('id') === -1); }, attr() { - Ember.assert("The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); + assert("The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); }, belongsTo() { - Ember.assert("The `belongsTo` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); + assert("The `belongsTo` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); }, hasMany() { - Ember.assert("The `hasMany` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); + assert("The `hasMany` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); }, setId: Ember.observer('id', function () { @@ -836,7 +837,7 @@ if (Ember.setOwner) { configurable: true, enumerable: false, get() { - Ember.deprecate('Using the injected `container` is deprecated. Please use the `getOwner` helper instead to access the owner of this object.', + deprecate('Using the injected `container` is deprecated. Please use the `getOwner` helper instead to access the owner of this object.', false, { id: 'ember-application.injected-container', until: '3.0.0' }); diff --git a/addon/system/model/states.js b/addon/system/model/states.js index a8fff59bb55..a22f20c9f72 100644 --- a/addon/system/model/states.js +++ b/addon/system/model/states.js @@ -1,6 +1,8 @@ /** @module ember-data */ +import { assert } from "ember-data/debug"; + var get = Ember.get; /* This file encapsulates the various states that a record can transition @@ -425,7 +427,7 @@ createdState.uncommitted.pushedData = function(internalModel) { createdState.uncommitted.propertyWasReset = Ember.K; function assertAgainstUnloadRecord(internalModel) { - Ember.assert("You can only unload a record which is not inFlight. `" + internalModel + "`", false); + assert("You can only unload a record which is not inFlight. `" + internalModel + "`", false); } updatedState.inFlight.unloadRecord = assertAgainstUnloadRecord; diff --git a/addon/system/promise-proxies.js b/addon/system/promise-proxies.js index 965e0cd643c..b3283868e24 100644 --- a/addon/system/promise-proxies.js +++ b/addon/system/promise-proxies.js @@ -1,3 +1,5 @@ +import { assert } from "ember-data/debug"; + var Promise = Ember.RSVP.Promise; var get = Ember.get; @@ -103,7 +105,7 @@ function proxyToContent(method) { var PromiseManyArray = PromiseArray.extend({ reload() { //I don't think this should ever happen right now, but worth guarding if we refactor the async relationships - Ember.assert('You are trying to reload an async manyArray before it has been created', get(this, 'content')); + assert('You are trying to reload an async manyArray before it has been created', get(this, 'content')); return PromiseManyArray.create({ promise: get(this, 'content').reload() }); diff --git a/addon/system/relationships/belongs-to.js b/addon/system/relationships/belongs-to.js index 06e0db9a7bd..1950b11b9ea 100644 --- a/addon/system/relationships/belongs-to.js +++ b/addon/system/relationships/belongs-to.js @@ -1,3 +1,4 @@ +import { assert, warn } from "ember-data/debug"; import Model from 'ember-data/system/model'; import normalizeModelName from "ember-data/system/normalize-model-name"; @@ -87,7 +88,7 @@ export default function belongsTo(modelName, options) { userEnteredModelName = normalizeModelName(userEnteredModelName); } - Ember.assert("The first argument to DS.belongsTo must be a string representing a model type key, not an instance of " + Ember.inspect(userEnteredModelName) + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", typeof userEnteredModelName === 'string' || typeof userEnteredModelName === 'undefined'); + assert("The first argument to DS.belongsTo must be a string representing a model type key, not an instance of " + Ember.inspect(userEnteredModelName) + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", typeof userEnteredModelName === 'string' || typeof userEnteredModelName === 'undefined'); opts = opts || {}; @@ -102,13 +103,13 @@ export default function belongsTo(modelName, options) { return Ember.computed({ get(key) { if (opts.hasOwnProperty('serialize')) { - Ember.warn(`You provided a serialize option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.Serializer and it's implementations http://emberjs.com/api/data/classes/DS.Serializer.html`, false, { + warn(`You provided a serialize option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.Serializer and it's implementations http://emberjs.com/api/data/classes/DS.Serializer.html`, false, { id: 'ds.model.serialize-option-in-belongs-to' }); } if (opts.hasOwnProperty('embedded')) { - Ember.warn(`You provided an embedded option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html`, false, { + warn(`You provided an embedded option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html`, false, { id: 'ds.model.embedded-option-in-belongs-to' }); } diff --git a/addon/system/relationships/ext.js b/addon/system/relationships/ext.js index ccd28565ac3..53103dff38f 100644 --- a/addon/system/relationships/ext.js +++ b/addon/system/relationships/ext.js @@ -1,3 +1,4 @@ +import { assert, warn } from "ember-data/debug"; import { typeForRelationshipMeta, relationshipFromMeta @@ -52,10 +53,10 @@ var relatedTypesDescriptor = Ember.computed(function() { meta.key = name; modelName = typeForRelationshipMeta(meta); - Ember.assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", modelName); + assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", modelName); if (!types.contains(modelName)) { - Ember.assert("Trying to sideload " + name + " on " + this.toString() + " but the type doesn't exist.", !!modelName); + assert("Trying to sideload " + name + " on " + this.toString() + " but the type doesn't exist.", !!modelName); types.push(modelName); } } @@ -247,14 +248,14 @@ Model.reopenClass({ inverseName = options.inverse; inverse = Ember.get(inverseType, 'relationshipsByName').get(inverseName); - Ember.assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.modelName + + assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.modelName + "' model. This is most likely due to a missing attribute on your model definition.", !Ember.isNone(inverse)); inverseKind = inverse.kind; } else { //No inverse was specified manually, we need to use a heuristic to guess one if (propertyMeta.type === propertyMeta.parentType.modelName) { - Ember.warn(`Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at http://emberjs.com/guides/models/defining-models/#toc_reflexive-relation for how to explicitly specify inverses.`, false, { + warn(`Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at http://emberjs.com/guides/models/defining-models/#toc_reflexive-relation for how to explicitly specify inverses.`, false, { id: 'ds.model.reflexive-relationship-without-inverse' }); } @@ -268,7 +269,7 @@ Model.reopenClass({ return name === optionsForRelationship.inverse; }); - Ember.assert("You defined the '" + name + "' relationship on " + this + ", but you defined the inverse relationships of type " + + assert("You defined the '" + name + "' relationship on " + this + ", but you defined the inverse relationships of type " + inverseType.toString() + " multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", filteredRelationships.length < 2); @@ -276,7 +277,7 @@ Model.reopenClass({ possibleRelationships = filteredRelationships; } - Ember.assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + + assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + this + " were found on " + inverseType + ". Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", possibleRelationships.length === 1); diff --git a/addon/system/relationships/has-many.js b/addon/system/relationships/has-many.js index 50e1ea634b6..1e65e1668c5 100644 --- a/addon/system/relationships/has-many.js +++ b/addon/system/relationships/has-many.js @@ -2,6 +2,7 @@ @module ember-data */ +import { assert } from "ember-data/debug"; import Model from "ember-data/system/model"; import normalizeModelName from "ember-data/system/normalize-model-name"; import isArrayLike from "ember-data/system/is-array-like"; @@ -118,7 +119,7 @@ export default function hasMany(type, options) { type = undefined; } - Ember.assert("The first argument to DS.hasMany must be a string representing a model type key, not an instance of " + Ember.inspect(type) + ". E.g., to define a relation to the Comment model, use DS.hasMany('comment')", typeof type === 'string' || typeof type === 'undefined'); + assert("The first argument to DS.hasMany must be a string representing a model type key, not an instance of " + Ember.inspect(type) + ". E.g., to define a relation to the Comment model, use DS.hasMany('comment')", typeof type === 'string' || typeof type === 'undefined'); options = options || {}; @@ -144,8 +145,8 @@ export default function hasMany(type, options) { return relationship.getRecords(); }, set(key, records) { - Ember.assert("You must pass an array of records to set a hasMany relationship", isArrayLike(records)); - Ember.assert(`All elements of a hasMany relationship must be instances of DS.Model, you passed ${Ember.inspect(records)}`, (function() { + assert("You must pass an array of records to set a hasMany relationship", isArrayLike(records)); + assert(`All elements of a hasMany relationship must be instances of DS.Model, you passed ${Ember.inspect(records)}`, (function() { return Ember.A(records).every((record) => Model.detectInstance(record) ); })()); diff --git a/addon/system/relationships/state/belongs-to.js b/addon/system/relationships/state/belongs-to.js index b9cf8c0e571..d25bbb79ef8 100644 --- a/addon/system/relationships/state/belongs-to.js +++ b/addon/system/relationships/state/belongs-to.js @@ -1,3 +1,4 @@ +import { assert } from "ember-data/debug"; import { PromiseObject } from "ember-data/system/promise-proxies"; @@ -79,7 +80,7 @@ BelongsToRelationship.prototype.addRecord = function(newRecord) { BelongsToRelationship.prototype.setRecordPromise = function(newPromise) { var content = newPromise.get && newPromise.get('content'); - Ember.assert("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); + assert("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); this.setRecord(content ? content._internalModel : content); }; @@ -138,7 +139,7 @@ BelongsToRelationship.prototype.getRecord = function() { return null; } var toReturn = this.inverseRecord.getRecord(); - Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); + assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); return toReturn; } }; diff --git a/addon/system/relationships/state/has-many.js b/addon/system/relationships/state/has-many.js index 57218c8a682..ba343c90cbf 100644 --- a/addon/system/relationships/state/has-many.js +++ b/addon/system/relationships/state/has-many.js @@ -1,3 +1,4 @@ +import { assert } from "ember-data/debug"; import { PromiseManyArray } from "ember-data/system/promise-proxies"; import Relationship from "ember-data/system/relationships/state/relationship"; import OrderedSet from "ember-data/system/ordered-set"; @@ -198,7 +199,7 @@ ManyRelationship.prototype.getRecords = function() { }); return this._loadingPromise; } else { - Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); + assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); //TODO(Igor) WTF DO I DO HERE? if (!this.manyArray.get('isDestroyed')) { diff --git a/addon/system/relationships/state/relationship.js b/addon/system/relationships/state/relationship.js index db019d1cb82..181665dbfd8 100644 --- a/addon/system/relationships/state/relationship.js +++ b/addon/system/relationships/state/relationship.js @@ -1,3 +1,4 @@ +import { assert, warn } from "ember-data/debug"; import OrderedSet from "ember-data/system/ordered-set"; export default function Relationship(store, record, inverseKey, relationshipMeta) { @@ -184,10 +185,10 @@ Relationship.prototype = { }, updateLink(link) { - Ember.warn(`You have pushed a record of type '${this.record.type.modelName}' with '${this.key}' as a link, but the association is not an async relationship.`, this.isAsync, { + warn(`You have pushed a record of type '${this.record.type.modelName}' with '${this.key}' as a link, but the association is not an async relationship.`, this.isAsync, { id: 'ds.store.push-link-for-sync-relationship' }); - Ember.assert("You have pushed a record of type '" + this.record.type.modelName + "' with '" + this.key + "' as a link, but the value of that link is not a string.", typeof link === 'string' || link === null); + assert("You have pushed a record of type '" + this.record.type.modelName + "' with '" + this.key + "' as a link, but the value of that link is not a string.", typeof link === 'string' || link === null); if (link !== this.link) { this.link = link; this.linkPromise = null; diff --git a/addon/system/store.js b/addon/system/store.js index 84aac5db067..8d1e2b52ec8 100644 --- a/addon/system/store.js +++ b/addon/system/store.js @@ -5,6 +5,7 @@ @module ember-data */ +import { assert, warn } from "ember-data/debug"; import _normalizeLink from "ember-data/system/normalize-link"; import normalizeModelName from "ember-data/system/normalize-model-name"; import { @@ -283,7 +284,7 @@ Store = Service.extend({ defaultAdapter: Ember.computed('adapter', function() { var adapter = get(this, 'adapter'); - Ember.assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name', typeof adapter === 'string'); + assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name', typeof adapter === 'string'); adapter = this.retrieveManagedInstance('adapter', adapter); @@ -323,7 +324,7 @@ Store = Service.extend({ @return {DS.Model} record */ createRecord(modelName, inputProperties) { - Ember.assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var properties = copy(inputProperties) || new EmptyObject(); @@ -437,20 +438,20 @@ Store = Service.extend({ // the public way to get a record by modelName and id. if (arguments.length === 1) { - Ember.assert('Using store.find(type) has been removed. Use store.findAll(type) to retrieve all records for a given type.'); + assert('Using store.find(type) has been removed. Use store.findAll(type) to retrieve all records for a given type.'); } if (Ember.typeOf(id) === 'object') { - Ember.assert('Calling store.find() with a query object is no longer supported. Use store.query() instead.'); + assert('Calling store.find() with a query object is no longer supported. Use store.query() instead.'); } if (options) { - Ember.assert('Calling store.find(type, id, { preload: preload }) is no longer supported. Use store.findRecord(type, id, { preload: preload }) instead.'); + assert('Calling store.find(type, id, { preload: preload }) is no longer supported. Use store.findRecord(type, id, { preload: preload }) instead.'); } - Ember.assert("You need to pass the model name and id to the store's find method", arguments.length === 2); - Ember.assert("You cannot pass `" + Ember.inspect(id) + "` as id to the store's find method", Ember.typeOf(id) === 'string' || Ember.typeOf(id) === 'number'); - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert("You need to pass the model name and id to the store's find method", arguments.length === 2); + assert("You cannot pass `" + Ember.inspect(id) + "` as id to the store's find method", Ember.typeOf(id) === 'string' || Ember.typeOf(id) === 'number'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); return this.findRecord(modelName, id); }, @@ -499,8 +500,8 @@ Store = Service.extend({ @return {Promise} promise */ findRecord(modelName, id, options) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - Ember.assert(badIdFormatAssertion, (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id))); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert(badIdFormatAssertion, (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id))); var internalModel = this._internalModelForId(modelName, id); options = options || {}; @@ -574,7 +575,7 @@ Store = Service.extend({ @return {Promise} promise */ findByIds(modelName, ids) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var store = this; return promiseArray(Ember.RSVP.all(ids.map((id) => { @@ -598,8 +599,8 @@ Store = Service.extend({ var id = internalModel.id; var adapter = this.adapterFor(typeClass.modelName); - Ember.assert("You tried to find a record but you have no adapter (for " + typeClass + ")", adapter); - Ember.assert("You tried to find a record but your adapter (for " + typeClass + ") does not implement 'findRecord'", typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); + assert("You tried to find a record but you have no adapter (for " + typeClass + ")", adapter); + assert("You tried to find a record but your adapter (for " + typeClass + ") does not implement 'findRecord'", typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); var promise = _find(adapter, this, typeClass, id, internalModel, options); return promise; @@ -670,7 +671,7 @@ Store = Service.extend({ resolvedRecords = Ember.A(resolvedRecords); var missingRecords = requestedRecords.reject((record) => resolvedRecords.contains(record)); if (missingRecords.length) { - Ember.warn('Ember Data expected to find records with the following ids in the adapter response but they were missing: ' + Ember.inspect(Ember.A(missingRecords).mapBy('id')), false, { + warn('Ember Data expected to find records with the following ids in the adapter response but they were missing: ' + Ember.inspect(Ember.A(missingRecords).mapBy('id')), false, { id: 'ds.store.missing-records-from-adapter' }); } @@ -724,7 +725,7 @@ Store = Service.extend({ var pair = Ember.A(pendingFetchItems).findBy('record', groupOfRecords[0]); _fetchRecord(pair); } else { - Ember.assert("You cannot return an empty array from adapter's method groupRecordsForFindMany", false); + assert("You cannot return an empty array from adapter's method groupRecordsForFindMany", false); } }); } else { @@ -753,7 +754,7 @@ Store = Service.extend({ @return {DS.Model|null} record */ peekRecord(modelName, id) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); if (this.hasRecordForId(modelName, id)) { return this._internalModelForId(modelName, id).getRecord(); } else { @@ -778,9 +779,9 @@ Store = Service.extend({ var adapter = this.adapterFor(modelName); var id = internalModel.id; - Ember.assert("You cannot reload a record without an ID", id); - Ember.assert("You tried to reload a record but you have no adapter (for " + modelName + ")", adapter); - Ember.assert("You tried to reload a record but your adapter does not implement `findRecord`", typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); + assert("You cannot reload a record without an ID", id); + assert("You tried to reload a record but you have no adapter (for " + modelName + ")", adapter); + assert("You tried to reload a record but your adapter does not implement `findRecord`", typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); return this.scheduleFetch(internalModel); }, @@ -794,7 +795,7 @@ Store = Service.extend({ @return {Boolean} */ hasRecordForId(modelName, inputId) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var id = coerceId(inputId); var internalModel = this.typeMapFor(typeClass).idToRecord[id]; @@ -812,7 +813,7 @@ Store = Service.extend({ @return {DS.Model} record */ recordForId(modelName, id) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); return this._internalModelForId(modelName, id).getRecord(); }, @@ -863,8 +864,8 @@ Store = Service.extend({ findHasMany(owner, link, relationship) { var adapter = this.adapterFor(owner.type.modelName); - Ember.assert("You tried to load a hasMany relationship but you have no adapter (for " + owner.type + ")", adapter); - Ember.assert("You tried to load a hasMany relationship from a specified `link` in the original payload but your adapter does not implement `findHasMany`", typeof adapter.findHasMany === 'function'); + assert("You tried to load a hasMany relationship but you have no adapter (for " + owner.type + ")", adapter); + assert("You tried to load a hasMany relationship from a specified `link` in the original payload but your adapter does not implement `findHasMany`", typeof adapter.findHasMany === 'function'); return _findHasMany(adapter, this, owner, link, relationship); }, @@ -880,8 +881,8 @@ Store = Service.extend({ findBelongsTo(owner, link, relationship) { var adapter = this.adapterFor(owner.type.modelName); - Ember.assert("You tried to load a belongsTo relationship but you have no adapter (for " + owner.type + ")", adapter); - Ember.assert("You tried to load a belongsTo relationship from a specified `link` in the original payload but your adapter does not implement `findBelongsTo`", typeof adapter.findBelongsTo === 'function'); + assert("You tried to load a belongsTo relationship but you have no adapter (for " + owner.type + ")", adapter); + assert("You tried to load a belongsTo relationship from a specified `link` in the original payload but your adapter does not implement `findBelongsTo`", typeof adapter.findBelongsTo === 'function'); return _findBelongsTo(adapter, this, owner, link, relationship); }, @@ -935,15 +936,15 @@ Store = Service.extend({ @return {Promise} promise */ query(modelName, query) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var array = this.recordArrayManager .createAdapterPopulatedRecordArray(typeClass, query); var adapter = this.adapterFor(modelName); - Ember.assert("You tried to load a query but you have no adapter (for " + typeClass + ")", adapter); - Ember.assert("You tried to load a query but your adapter does not implement `query`", typeof adapter.query === 'function'); + assert("You tried to load a query but you have no adapter (for " + typeClass + ")", adapter); + assert("You tried to load a query but your adapter does not implement `query`", typeof adapter.query === 'function'); return promiseArray(_query(adapter, this, typeClass, query, array)); }, @@ -965,15 +966,15 @@ Store = Service.extend({ @return {Promise} promise */ queryRecord(modelName, query) { - Ember.assert("You need to pass a type to the store's queryRecord method", modelName); - Ember.assert("You need to pass a query hash to the store's queryRecord method", query); - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert("You need to pass a type to the store's queryRecord method", modelName); + assert("You need to pass a query hash to the store's queryRecord method", query); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var adapter = this.adapterFor(modelName); - Ember.assert("You tried to make a query but you have no adapter (for " + typeClass + ")", adapter); - Ember.assert("You tried to make a query but your adapter does not implement `queryRecord`", typeof adapter.queryRecord === 'function'); + assert("You tried to make a query but you have no adapter (for " + typeClass + ")", adapter); + assert("You tried to make a query but your adapter does not implement `queryRecord`", typeof adapter.queryRecord === 'function'); return promiseObject(_queryRecord(adapter, this, typeClass, query)); }, @@ -1001,7 +1002,7 @@ Store = Service.extend({ @return {DS.AdapterPopulatedRecordArray} */ findAll(modelName, options) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); return this._fetchAll(typeClass, this.peekAll(modelName), options); @@ -1021,8 +1022,8 @@ Store = Service.extend({ set(array, 'isUpdating', true); - Ember.assert("You tried to load all records but you have no adapter (for " + typeClass + ")", adapter); - Ember.assert("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function'); + assert("You tried to load all records but you have no adapter (for " + typeClass + ")", adapter); + assert("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function'); if (options.reload) { return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); } @@ -1070,7 +1071,7 @@ Store = Service.extend({ @return {DS.RecordArray} */ peekAll(modelName) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var liveRecordArray = this.recordArrayManager.liveRecordArrayFor(typeClass); @@ -1093,7 +1094,7 @@ Store = Service.extend({ @param {String=} modelName */ unloadAll(modelName) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), !modelName || typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), !modelName || typeof modelName === 'string'); if (arguments.length === 0) { var typeMaps = this.typeMaps; var keys = Object.keys(typeMaps); @@ -1174,10 +1175,10 @@ Store = Service.extend({ @return {DS.PromiseArray} */ filter(modelName, query, filter) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); if (!Ember.ENV.ENABLE_DS_FILTER) { - Ember.assert('The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', false); + assert('The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', false); } var promise; @@ -1225,7 +1226,7 @@ Store = Service.extend({ @return {boolean} */ recordIsLoaded(modelName, id) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); return this.hasRecordForId(modelName, id); }, @@ -1236,7 +1237,7 @@ Store = Service.extend({ @private */ _metadataFor(modelName) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); return this.typeMapFor(typeClass).metadata; }, @@ -1248,7 +1249,7 @@ Store = Service.extend({ @private */ _setMetadataFor(modelName, metadata) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); Ember.merge(this.typeMapFor(typeClass).metadata, metadata); }, @@ -1402,7 +1403,7 @@ Store = Service.extend({ var oldId = internalModel.id; var id = coerceId(data.id); - Ember.assert("An adapter cannot assign a new id to a record that already has an id. " + internalModel + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId); + assert("An adapter cannot assign a new id to a record that already has an id. " + internalModel + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId); this.typeMapFor(internalModel.type).idToRecord[id] = internalModel; @@ -1505,7 +1506,7 @@ Store = Service.extend({ @return {DS.Model} */ modelFor(modelName) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var factory = this.modelFactoryFor(modelName); if (!factory) { @@ -1521,7 +1522,7 @@ Store = Service.extend({ }, modelFactoryFor(modelName) { - Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var normalizedKey = normalizeModelName(modelName); var owner = getOwner(this); @@ -1701,7 +1702,7 @@ Store = Service.extend({ return null; } - Ember.assert(`Expected an object in the 'data' property in a call to 'push' for ${data.type}, but was ${Ember.typeOf(data.data)}`, Ember.typeOf(data.data) === 'object'); + assert(`Expected an object in the 'data' property in a call to 'push' for ${data.type}, but was ${Ember.typeOf(data.data)}`, Ember.typeOf(data.data) === 'object'); var internalModel = this._pushInternalModel(data.data); @@ -1714,8 +1715,8 @@ Store = Service.extend({ _pushInternalModel(data) { var modelName = data.type; - Ember.assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id != null && data.id !== ''); - Ember.assert(`You tried to push data with a type '${modelName}' but no model could be found with that name.`, this._hasModelFor(modelName)); + assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id != null && data.id !== ''); + assert(`You tried to push data with a type '${modelName}' but no model could be found with that name.`, this._hasModelFor(modelName)); var type = this.modelFor(modelName); @@ -1723,7 +1724,7 @@ Store = Service.extend({ // contains unknown keys, log a warning. if (Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS) { - Ember.warn("The payload for '" + type.modelName + "' contains these unknown keys: " + + warn("The payload for '" + type.modelName + "' contains these unknown keys: " + Ember.inspect(Object.keys(data).forEach((key) => { return !(key === 'id' || key === 'links' || get(type, 'fields').has(key) || key.match(/Type$/)); })) + ". Make sure they've been defined in your model.", @@ -1812,10 +1813,10 @@ Store = Service.extend({ if (!inputPayload) { payload = modelName; serializer = defaultSerializer(this); - Ember.assert("You cannot use `store#pushPayload` without a modelName unless your default serializer defines `pushPayload`", typeof serializer.pushPayload === 'function'); + assert("You cannot use `store#pushPayload` without a modelName unless your default serializer defines `pushPayload`", typeof serializer.pushPayload === 'function'); } else { payload = inputPayload; - Ember.assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); serializer = this.serializerFor(modelName); } this._adapterRun(() => serializer.pushPayload(this, payload)); @@ -1841,7 +1842,7 @@ Store = Service.extend({ @return {Object} The normalized payload */ normalize(modelName, payload) { - Ember.assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); var serializer = this.serializerFor(modelName); var model = this.modelFor(modelName); return serializer.normalize(model, payload); @@ -1862,8 +1863,8 @@ Store = Service.extend({ var typeMap = this.typeMapFor(type); var idToRecord = typeMap.idToRecord; - Ember.assert(`The id ${id} has already been used with another record of type ${type.toString()}.`, !id || !idToRecord[id]); - Ember.assert(`'${Ember.inspect(type)}' does not appear to be an ember-data model`, (typeof type._create === 'function') ); + assert(`The id ${id} has already been used with another record of type ${type.toString()}.`, !id || !idToRecord[id]); + assert(`'${Ember.inspect(type)}' does not appear to be an ember-data model`, (typeof type._create === 'function') ); // lookupFactory should really return an object that creates // instances with the injections applied @@ -1935,7 +1936,7 @@ Store = Service.extend({ */ adapterFor(modelName) { - Ember.assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); + assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); return this.lookupAdapter(modelName); }, @@ -1971,7 +1972,7 @@ Store = Service.extend({ */ serializerFor(modelName) { - Ember.assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); + assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); var fallbacks = [ 'application', @@ -2040,7 +2041,7 @@ function deserializeRecordId(store, key, relationship, id) { return; } - Ember.assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being ${Ember.inspect(id)}, but ${key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !isArray(id)); + assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being ${Ember.inspect(id)}, but ${key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !isArray(id)); //TODO:Better asserts return store._internalModelForId(id.type, id.id); @@ -2051,7 +2052,7 @@ function deserializeRecordIds(store, key, relationship, ids) { return; } - Ember.assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being '${Ember.inspect(ids)}', but ${key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, isArray(ids)); + assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being '${Ember.inspect(ids)}', but ${key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, isArray(ids)); return ids.map((id) => deserializeRecordId(store, key, relationship, id)); } @@ -2071,7 +2072,7 @@ function _commit(adapter, store, operation, snapshot) { var serializer = serializerForAdapter(store, adapter, modelName); var label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; - Ember.assert(`Your adapter's '${operation}' method must return a value, but it returned 'undefined'`, promise !==undefined); + assert(`Your adapter's '${operation}' method must return a value, but it returned 'undefined'`, promise !==undefined); promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); diff --git a/addon/system/store/finders.js b/addon/system/store/finders.js index c5005b16a09..c4e6ecb92e2 100644 --- a/addon/system/store/finders.js +++ b/addon/system/store/finders.js @@ -1,3 +1,4 @@ +import { assert } from "ember-data/debug"; import { _bind, _guard, @@ -32,10 +33,10 @@ export function _find(adapter, store, typeClass, id, internalModel, options) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - Ember.assert("You made a `find` request for a " + typeClass.typeClassKey + " with id " + id + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + assert("You made a `find` request for a " + typeClass.typeClassKey + " with id " + id + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, id, 'findRecord'); - Ember.assert('Ember Data expected the primary data returned from a `findRecord` response to be an object but instead it found an array.', !Array.isArray(payload.data)); + assert('Ember Data expected the primary data returned from a `findRecord` response to be an object but instead it found an array.', !Array.isArray(payload.data)); //TODO Optimize var record = store.push(payload); return record._internalModel; @@ -65,7 +66,7 @@ export function _findMany(adapter, store, typeClass, ids, internalModels) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - Ember.assert("You made a `findMany` request for a " + typeClass.typeClassKey + " with ids " + ids + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + assert("You made a `findMany` request for a " + typeClass.typeClassKey + " with ids " + ids + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findMany'); //TODO Optimize, no need to materialize here @@ -87,7 +88,7 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) promise = _guard(promise, _bind(_objectIsAlive, internalModel)); return promise.then(function(adapterPayload) { - Ember.assert("You made a `findHasMany` request for a " + internalModel.modelName + "'s `" + relationship.key + "` relationship, using link " + link + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + assert("You made a `findHasMany` request for a " + internalModel.modelName + "'s `" + relationship.key + "` relationship, using link " + link + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findHasMany'); //TODO Use a non record creating push @@ -137,7 +138,7 @@ export function _findAll(adapter, store, typeClass, sinceToken, options) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - Ember.assert("You made a `findAll` request for " + typeClass.typeClassKey + "records, but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + assert("You made a `findAll` request for " + typeClass.typeClassKey + "records, but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findAll'); //TODO Optimize @@ -167,7 +168,7 @@ export function _query(adapter, store, typeClass, query, recordArray) { records = store.push(payload); }); - Ember.assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Ember.isArray(records)); + assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Ember.isArray(records)); recordArray.loadRecords(records); return recordArray; @@ -184,7 +185,7 @@ export function _queryRecord(adapter, store, typeClass, query) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - Ember.assert("You made a `queryRecord` request for " + typeClass.typeClassKey + "records, with query `" + query + "`, but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + assert("You made a `queryRecord` request for " + typeClass.typeClassKey + "records, with query `" + query + "`, but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); var record; store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'queryRecord'); diff --git a/addon/system/store/serializer-response.js b/addon/system/store/serializer-response.js index 1c6781b2a00..e352d7ba4a7 100644 --- a/addon/system/store/serializer-response.js +++ b/addon/system/store/serializer-response.js @@ -1,3 +1,5 @@ +import { assert, runInDebug } from "ember-data/debug"; + /* This is a helper method that validates a JSON API top-level document @@ -72,10 +74,10 @@ export function validateDocumentStructure(doc) { export function normalizeResponseHelper(serializer, store, modelClass, payload, id, requestType) { let normalizedResponse = serializer.normalizeResponse(store, modelClass, payload, id, requestType); let validationErrors = []; - Ember.runInDebug(() => { + runInDebug(() => { validationErrors = validateDocumentStructure(normalizedResponse); }); - Ember.assert(`normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join('\n\t* ')}`, Ember.isEmpty(validationErrors)); + assert(`normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join('\n\t* ')}`, Ember.isEmpty(validationErrors)); // TODO: Remove after metadata refactor if (normalizedResponse.meta) { store._setMetadataFor(modelClass.modelName, normalizedResponse.meta); diff --git a/addon/utils.js b/addon/utils.js index 107f3144341..d86ef898294 100644 --- a/addon/utils.js +++ b/addon/utils.js @@ -1,4 +1,5 @@ import Ember from 'ember'; +import { assert } from "ember-data/debug"; const get = Ember.get; @@ -29,7 +30,7 @@ var assertPolymorphicType = function(record, relationshipMeta, addedRecord) { var assertionMessage = `You cannot add a record of type '${addedType}' to the '${recordType}.${key}' relationship (only '${typeClass.modelName}' allowed)`; - Ember.assert(assertionMessage, checkPolymorphic(typeClass, addedRecord)); + assert(assertionMessage, checkPolymorphic(typeClass, addedRecord)); }; function checkPolymorphic(typeClass, addedRecord) { From 0e62622f5a2e2a4e1488707683747630fb6b16fc Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 7 Dec 2015 17:52:08 -0500 Subject: [PATCH 1256/2527] Remove duplicate createRecord test Closes https://github.com/emberjs/data/issues/3969 This test has been obsolete since #3033 --- tests/unit/store/create-record-test.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js index dea148fd8af..71c6d6b63c1 100644 --- a/tests/unit/store/create-record-test.js +++ b/tests/unit/store/create-record-test.js @@ -73,18 +73,6 @@ module("unit/store/createRecord - Store with models by dash", { } }); -test("creating a record by camel-case string finds the model", function(assert) { - var attributes = { foo: 'bar' }; - var record; - - run(function() { - record = store.createRecord('some-thing', attributes); - }); - - assert.equal(record.get('foo'), attributes.foo, "The record is created"); - assert.equal(store.modelFor('someThing').modelName, 'some-thing'); -}); - test("creating a record by dasherize string finds the model", function(assert) { var attributes = { foo: 'bar' }; var record; From a2da96616c6278ff829661ddad1ecfc5fa3d83e8 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 8 Dec 2015 10:08:01 -0600 Subject: [PATCH 1257/2527] [BUGFIX beta] bump ember-inflector Fixes bugs when pluralization involves floats. See https://github.com/stefanpenner/ember-inflector/pull/97 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 9970990d1e8..95a9afe10ed 100644 --- a/package.json +++ b/package.json @@ -51,14 +51,14 @@ "ember-disable-prototype-extensions": "^1.0.0", "ember-disable-proxy-controllers": "^1.0.0", "ember-export-application-global": "^1.0.3", - "ember-inflector": "^1.9.3", + "ember-inflector": "^1.9.4", "ember-try": "0.0.6", "ember-watson": "^0.7.0", "git-repo-version": "^0.3.0", "lodash.assign": "^3.2.0" }, "peerDependencies": { - "ember-inflector": "^1.0.0" + "ember-inflector": "^1.9.4" }, "keywords": [ "ember-addon" From 22ef877d418de11acb46a8b010267df3af947e61 Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 8 Dec 2015 17:23:02 +0100 Subject: [PATCH 1258/2527] Strip code for feature flags, which are not enabled This add the `babel-plugin-feature-flag` BabelJS plugin to the build pipeline, so all code paths are stripped for features, which are not enabled in `config/features.json`. Feature detection within the addon is handled similar to the one in Ember.js: ``` import isEnabled from 'ember-data/features'; if (isEnabled("ds-new-feature")) { // code for the feature } ``` --- addon/features.js | 5 +++++ lib/javascripts.js | 10 ++++++++++ package.json | 1 + 3 files changed, 16 insertions(+) create mode 100644 addon/features.js diff --git a/addon/features.js b/addon/features.js new file mode 100644 index 00000000000..8e023905a04 --- /dev/null +++ b/addon/features.js @@ -0,0 +1,5 @@ +import Ember from 'ember'; + +export default function isEnabled() { + return Ember.FEATURES.isEnabled(...arguments); +} diff --git a/lib/javascripts.js b/lib/javascripts.js index 2e39d30c0a5..60eddc17dcb 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -1,10 +1,12 @@ var filterImports = require('babel-plugin-filter-imports'); +var featureFlags = require('babel-plugin-feature-flags'); var babel = require('broccoli-babel-transpiler'); var merge = require('broccoli-merge-trees'); var concat = require('broccoli-concat'); var uglify = require('broccoli-uglify-sourcemap'); var stew = require('broccoli-stew'); var version = require('./version'); +var fs = require('fs'); var path = require('path'); var Funnel = require('broccoli-funnel'); var versionReplace = require('./version-replace'); @@ -56,7 +58,15 @@ function debugBuild(packageName, tree) { } function strippedBuild(packageName, tree) { + var featuresJson = fs.readFileSync('config/features.json', { encoding: 'utf8' }); + var features = JSON.parse(featuresJson); + var plugins = [ + featureFlags({ + import: { module: 'ember-data/features' }, + features: features + }), + filterImports({ 'ember-data/debug': [ 'assert', diff --git a/package.json b/package.json index 95a9afe10ed..3a60d20a0ac 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "ember-cli-babel": "^5.1.3" }, "devDependencies": { + "babel-plugin-feature-flags": "^0.2.0", "babel-plugin-filter-imports": "^0.2.0", "bower": "^1.6.5", "broccoli-asset-rev": "^2.1.2", From f58ffe442dbbd26a9cc71b53d153c5bd56d617c6 Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 8 Dec 2015 20:22:45 +0100 Subject: [PATCH 1259/2527] Add possibility to run tests for feature flags via `ember test` Optional features and the corresponding tests can now be enabled within the tests by specifying the `test-optional-features` environment: ember test --environment=test-optional-features --- .travis.yml | 1 + config/environment.js | 20 +++++++++++++++----- package.json | 1 + 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index e8dcd45020a..ad55c004238 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,7 @@ install: script: - ./bin/lint-features - npm run-script test + - npm run-script test:optional-features after_success: - npm run-script production - "./bin/bower-ember-data-build" diff --git a/config/environment.js b/config/environment.js index 80369f82b6c..c7058a3411c 100644 --- a/config/environment.js +++ b/config/environment.js @@ -1,13 +1,23 @@ 'use strict'; +var fs = require('fs'); +var featuresJson = fs.readFileSync('config/features.json', { encoding: 'utf8' }); +var featureFlags = JSON.parse(featuresJson); + module.exports = function(environment, appConfig) { var ENV = { }; - if (environment === 'testing') { - ENV.EmberENV = { - RAISE_ON_DEPRECATION: true, - ENABLE_DS_FILTER: true - }; + ENV.EmberENV = { + FEATURES: featureFlags, + ENABLE_DS_FILTER: true, + + // don't raise on deprecation yet, since there are too many thrown errors; + // this should be addressed in another PR + // RAISE_ON_DEPRECATION: true + }; + + if (environment === 'test-optional-features') { + ENV.EmberENV.ENABLE_OPTIONAL_FEATURES = true; } return ENV; diff --git a/package.json b/package.json index 3a60d20a0ac..d876f57e666 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build": "ember build", "start": "ember server", "test": "ember try:testall", + "test:optional-features": "ember test --environment=test-optional-features", "bower": "bower install", "production": "ember build --environment=production" }, From a1cdc95aad289b66202949a13ac57d2ac10d4284 Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 8 Dec 2015 20:31:05 +0100 Subject: [PATCH 1260/2527] Re-add possibility to enable feature flags within Browser Optional feature flags can now be enabled via a checkbox, rendered at the top of the test page. The state of the checkbox is set as query parameter in the URL. An in-repo-addon ensures that the ENABLE_OPTIONAL_FEATURES flag works correctly, when the tests are run inside a browser: the workaround using the in-repo-addon is needed, since the flag needs to be set before Ember.js is loaded, but there is currently no other way. --- lib/enable-optional-features-via-url/index.js | 27 +++++++++++++++++++ .../package.json | 6 +++++ package.json | 5 +++- tests/test-helper.js | 9 +------ 4 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 lib/enable-optional-features-via-url/index.js create mode 100644 lib/enable-optional-features-via-url/package.json diff --git a/lib/enable-optional-features-via-url/index.js b/lib/enable-optional-features-via-url/index.js new file mode 100644 index 00000000000..0c16d924cc0 --- /dev/null +++ b/lib/enable-optional-features-via-url/index.js @@ -0,0 +1,27 @@ +/*jshint node:true*/ +module.exports = { + name: 'enable-optional-features-via-url', + + /** + So the ENABLE_OPTIONAL_FEATURES flag is considered correctly within the + index.html, it needs to be set before Ember.js is loaded. Since there is + currently no way to access the `window` object within config/environment.js + (and hereby check if there is a query parameter present for the checkbox), + a script is injected, before Ember.js is loaded. The script checks if there + is no value yet for the ENABLE_OPTIONAL_FEATURES flag, and if so, it sets + the flag to true when there is a `enableoptionalfeatures` query parameter. + */ + contentFor: function(name) { + if (name === "vendor-prefix") { + var array = [ + "", + "window.EmberENV = window.EmberENV || {};", + "if (typeof window.EmberENV.ENABLE_OPTIONAL_FEATURES === 'undefined') {", + " window.EmberENV.ENABLE_OPTIONAL_FEATURES = window.location.search.indexOf('enableoptionalfeatures') !== -1;", + "}" + ]; + + return array.join('\n'); + } + } +}; diff --git a/lib/enable-optional-features-via-url/package.json b/lib/enable-optional-features-via-url/package.json new file mode 100644 index 00000000000..ea6c08dab4d --- /dev/null +++ b/lib/enable-optional-features-via-url/package.json @@ -0,0 +1,6 @@ +{ + "name": "enable-optional-features-via-url", + "keywords": [ + "ember-addon" + ] +} diff --git a/package.json b/package.json index d876f57e666..f41d413d282 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,9 @@ "ember-addon" ], "ember-addon": { - "configPath": "tests/dummy/config" + "configPath": "tests/dummy/config", + "paths": [ + "lib/enable-optional-features-via-url" + ] } } diff --git a/tests/test-helper.js b/tests/test-helper.js index ce98f980535..bf6077bcb49 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -19,14 +19,8 @@ import Ember from 'ember'; setResolver(resolver); -const ENV = Ember.ENV; -const QUNIT_PARAMS = QUnit.urlParams; const { assert } = QUnit; -ENV.EXTEND_PROTOTYPES = QUNIT_PARAMS.extendprototypes; -ENV.ENABLE_OPTIONAL_FEATURES = QUNIT_PARAMS.enableoptionalfeatures; -ENV.ENABLE_DS_FILTER = true; - QUnit.begin(function() { Ember.RSVP.configure('onerror', function(reason) { // only print error messages if they're exceptions; @@ -76,6 +70,5 @@ assert.without = function(array, item) { addEmberAssertions(assert); -QUnit.config.testTimeout= 2000; +QUnit.config.testTimeout = 2000; QUnit.config.urlConfig.push({ id: 'enableoptionalfeatures', label: "Enable Opt Features" }); - From 1d3e833227a654661bb0c60f7f6d5110aefd5797 Mon Sep 17 00:00:00 2001 From: Nick Iaconis Date: Tue, 8 Dec 2015 13:30:13 -0800 Subject: [PATCH 1261/2527] Add license field to bower.json Also position license field in component.json to mirror Ember.js --- config/package-manager-files/bower.json | 1 + config/package-manager-files/component.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/config/package-manager-files/bower.json b/config/package-manager-files/bower.json index 9b5b58d3b69..8709e08bb9b 100644 --- a/config/package-manager-files/bower.json +++ b/config/package-manager-files/bower.json @@ -1,6 +1,7 @@ { "name": "ember-data", "version": "VERSION_STRING_PLACEHOLDER", + "license": "MIT", "main": "ember-data.js", "dependencies": { "ember": "^2.0.0" diff --git a/config/package-manager-files/component.json b/config/package-manager-files/component.json index 9be0ccdf0f6..5c025618391 100644 --- a/config/package-manager-files/component.json +++ b/config/package-manager-files/component.json @@ -3,6 +3,7 @@ "repo": "components/ember-data", "description": "A data persistence library for Ember.js.", "version": "VERSION_STRING_PLACEHOLDER", + "license": "MIT", "main": "ember-data.js", "scripts": [ "ember-data.js", @@ -11,6 +12,5 @@ ], "dependencies": { "components/ember": ">= 2.0.0 < 3.0.0" - }, - "license": "MIT" + } } From 0b3c304560bc07c9710a06368009968dbbe3f1e5 Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 9 Dec 2015 00:32:06 +0100 Subject: [PATCH 1262/2527] Cleanup .jshintrc since no globals are used anymore --- .jshintrc | 40 +------------------ addon/adapters/build-url-mixin.js | 2 + addon/adapters/errors.js | 2 + addon/adapters/json-api-adapter.js | 1 + addon/adapters/rest-adapter.js | 1 + addon/ember-initializer.js | 1 + addon/ext/date.js | 2 + addon/serializers/embedded-records-mixin.js | 1 + addon/serializers/json-api-serializer.js | 1 + addon/serializers/json-serializer.js | 1 + addon/serializers/rest-serializer.js | 1 + addon/system/adapter.js | 1 + addon/system/debug/debug-adapter.js | 1 + addon/system/is-array-like.js | 2 + addon/system/many-array.js | 1 + addon/system/model/attributes.js | 1 + addon/system/model/errors.js | 1 + addon/system/model/errors/invalid.js | 1 + addon/system/model/internal-model.js | 1 + addon/system/model/model.js | 1 + addon/system/model/states.js | 1 + addon/system/normalize-model-name.js | 2 + addon/system/ordered-set.js | 2 + addon/system/promise-proxies.js | 1 + addon/system/record-array-manager.js | 1 + .../adapter-populated-record-array.js | 1 + .../record-arrays/filtered-record-array.js | 1 + addon/system/record-arrays/record-array.js | 1 + addon/system/relationships/belongs-to.js | 1 + addon/system/relationships/ext.js | 1 + addon/system/relationships/has-many.js | 1 + .../system/relationships/state/belongs-to.js | 1 + addon/system/relationships/state/create.js | 1 + .../relationships/state/relationship.js | 1 + addon/system/serializer.js | 2 + addon/system/snapshot.js | 1 + addon/system/store.js | 4 +- addon/system/store/common.js | 2 + addon/system/store/finders.js | 1 + addon/system/store/serializer-response.js | 1 + addon/transforms/base.js | 2 + addon/transforms/date.js | 2 + addon/transforms/number.js | 1 + addon/transforms/string.js | 2 + tests/.jshintrc | 22 +--------- tests/helpers/store.js | 1 + 46 files changed, 60 insertions(+), 60 deletions(-) diff --git a/.jshintrc b/.jshintrc index 9c939529750..a578af3a7ff 100644 --- a/.jshintrc +++ b/.jshintrc @@ -1,45 +1,9 @@ { "predef": [ - "console", - "requireModule", - "-Promise", - "-Map", - "Ember", - "DS", - "Handlebars", - "Metamorph", - "ember_assert", - "ember_warn", - "ember_deprecate", - "ember_deprecateFunc", "require", "define", - "setupStore", - "createStore", - "equal", - "asyncEqual", - "notEqual", - "asyncTest", - "test", - "raises", - "deepEqual", - "start", - "stop", - "ok", - "strictEqual", - "module", - "expect", - "minispade", - "async", - "invokeAsync", - "jQuery", - "expectAssertion", - "expectDeprecation", - "expectNoDeprecation", - "warns", - "noWarns", - "throws", - "-Comment" + "-Map", + "-Promise" ], "node" : false, "browser" : true, diff --git a/addon/adapters/build-url-mixin.js b/addon/adapters/build-url-mixin.js index 4987b408378..8b5eda639ce 100644 --- a/addon/adapters/build-url-mixin.js +++ b/addon/adapters/build-url-mixin.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + var get = Ember.get; /** diff --git a/addon/adapters/errors.js b/addon/adapters/errors.js index 1e129463f82..d6f3a4010e9 100644 --- a/addon/adapters/errors.js +++ b/addon/adapters/errors.js @@ -1,4 +1,6 @@ +import Ember from 'ember'; import {assert} from 'ember-data/debug'; + const EmberError = Ember.Error; const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/; diff --git a/addon/adapters/json-api-adapter.js b/addon/adapters/json-api-adapter.js index f5c9d80c58f..f0e0d244ec8 100644 --- a/addon/adapters/json-api-adapter.js +++ b/addon/adapters/json-api-adapter.js @@ -2,6 +2,7 @@ @module ember-data */ +import Ember from 'ember'; import RESTAdapter from "ember-data/adapters/rest-adapter"; /** diff --git a/addon/adapters/rest-adapter.js b/addon/adapters/rest-adapter.js index 26098e3eb58..76f6cf3398e 100644 --- a/addon/adapters/rest-adapter.js +++ b/addon/adapters/rest-adapter.js @@ -2,6 +2,7 @@ @module ember-data */ +import Ember from 'ember'; import Adapter from "ember-data/system/adapter"; import { AdapterError, diff --git a/addon/ember-initializer.js b/addon/ember-initializer.js index 28322a714cf..9da818688b1 100644 --- a/addon/ember-initializer.js +++ b/addon/ember-initializer.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import setupContainer from 'ember-data/setup-container'; import initializeStoreService from 'ember-data/instance-initializers/initialize-store-service'; diff --git a/addon/ext/date.js b/addon/ext/date.js index 05475976adc..c662e88a0f1 100644 --- a/addon/ext/date.js +++ b/addon/ext/date.js @@ -2,6 +2,8 @@ @module ember-data */ +import Ember from 'ember'; + /** Date.parse with progressive enhancement for ISO 8601 diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 3040baf6863..d88f03ac458 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import { warn } from "ember-data/debug"; var get = Ember.get; diff --git a/addon/serializers/json-api-serializer.js b/addon/serializers/json-api-serializer.js index d29a01a641c..152158486e9 100644 --- a/addon/serializers/json-api-serializer.js +++ b/addon/serializers/json-api-serializer.js @@ -2,6 +2,7 @@ @module ember-data */ +import Ember from 'ember'; import { assert, runInDebug, warn } from 'ember-data/debug'; import JSONSerializer from 'ember-data/serializers/json-serializer'; import normalizeModelName from 'ember-data/system/normalize-model-name'; diff --git a/addon/serializers/json-serializer.js b/addon/serializers/json-serializer.js index 0f35d983b1e..0f0ff1c7fa9 100644 --- a/addon/serializers/json-serializer.js +++ b/addon/serializers/json-serializer.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import { assert, warn } from 'ember-data/debug'; import Serializer from "ember-data/system/serializer"; import coerceId from "ember-data/system/coerce-id"; diff --git a/addon/serializers/rest-serializer.js b/addon/serializers/rest-serializer.js index 44496a3c4ab..3a200e8a576 100644 --- a/addon/serializers/rest-serializer.js +++ b/addon/serializers/rest-serializer.js @@ -2,6 +2,7 @@ @module ember-data */ +import Ember from 'ember'; import { assert, deprecate, runInDebug, warn } from "ember-data/debug"; import JSONSerializer from "ember-data/serializers/json-serializer"; import normalizeModelName from "ember-data/system/normalize-model-name"; diff --git a/addon/system/adapter.js b/addon/system/adapter.js index a9f1306a677..93cad9a531d 100644 --- a/addon/system/adapter.js +++ b/addon/system/adapter.js @@ -2,6 +2,7 @@ @module ember-data */ +import Ember from 'ember'; var get = Ember.get; /** diff --git a/addon/system/debug/debug-adapter.js b/addon/system/debug/debug-adapter.js index fabed06a7aa..b70763781cc 100644 --- a/addon/system/debug/debug-adapter.js +++ b/addon/system/debug/debug-adapter.js @@ -1,6 +1,7 @@ /** @module ember-data */ +import Ember from 'ember'; import Model from "ember-data/system/model"; var get = Ember.get; var capitalize = Ember.String.capitalize; diff --git a/addon/system/is-array-like.js b/addon/system/is-array-like.js index bb1ca7b2870..3be11dac000 100644 --- a/addon/system/is-array-like.js +++ b/addon/system/is-array-like.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + /* We're using this to detect arrays and "array-like" objects. diff --git a/addon/system/many-array.js b/addon/system/many-array.js index 4f376cbdafb..42064152b05 100644 --- a/addon/system/many-array.js +++ b/addon/system/many-array.js @@ -1,6 +1,7 @@ /** @module ember-data */ +import Ember from 'ember'; import { assert } from "ember-data/debug"; import { PromiseArray } from "ember-data/system/promise-proxies"; diff --git a/addon/system/model/attributes.js b/addon/system/model/attributes.js index aaf79ffc3f3..a0ff4da4f43 100644 --- a/addon/system/model/attributes.js +++ b/addon/system/model/attributes.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import Model from "ember-data/system/model/model"; import { assert, deprecate } from "ember-data/debug"; diff --git a/addon/system/model/errors.js b/addon/system/model/errors.js index 4899ea09926..664cab24503 100644 --- a/addon/system/model/errors.js +++ b/addon/system/model/errors.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import { deprecate, warn } from "ember-data/debug"; var get = Ember.get; diff --git a/addon/system/model/errors/invalid.js b/addon/system/model/errors/invalid.js index c01ab0775bc..00cf7bc3c16 100644 --- a/addon/system/model/errors/invalid.js +++ b/addon/system/model/errors/invalid.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; var EmberError = Ember.Error; /** diff --git a/addon/system/model/internal-model.js b/addon/system/model/internal-model.js index b21d2251418..b01f81a07d3 100644 --- a/addon/system/model/internal-model.js +++ b/addon/system/model/internal-model.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import { assert } from "ember-data/debug"; import merge from "ember-data/system/merge"; import RootState from "ember-data/system/model/states"; diff --git a/addon/system/model/model.js b/addon/system/model/model.js index c8961461f30..e1cdd001ce7 100644 --- a/addon/system/model/model.js +++ b/addon/system/model/model.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import { assert, deprecate } from "ember-data/debug"; import { PromiseObject } from "ember-data/system/promise-proxies"; import Errors from "ember-data/system/model/errors"; diff --git a/addon/system/model/states.js b/addon/system/model/states.js index a22f20c9f72..1c1d59311d5 100644 --- a/addon/system/model/states.js +++ b/addon/system/model/states.js @@ -1,6 +1,7 @@ /** @module ember-data */ +import Ember from 'ember'; import { assert } from "ember-data/debug"; var get = Ember.get; diff --git a/addon/system/normalize-model-name.js b/addon/system/normalize-model-name.js index 813ef9b3727..4921ca79782 100644 --- a/addon/system/normalize-model-name.js +++ b/addon/system/normalize-model-name.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + /** All modelNames are dasherized internally. Changing this function may require changes to other normalization hooks (such as typeForRoot). diff --git a/addon/system/ordered-set.js b/addon/system/ordered-set.js index 903ec8afbe8..4c3a36ec162 100644 --- a/addon/system/ordered-set.js +++ b/addon/system/ordered-set.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + var EmberOrderedSet = Ember.OrderedSet; var guidFor = Ember.guidFor; diff --git a/addon/system/promise-proxies.js b/addon/system/promise-proxies.js index b3283868e24..aebce8fda57 100644 --- a/addon/system/promise-proxies.js +++ b/addon/system/promise-proxies.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import { assert } from "ember-data/debug"; var Promise = Ember.RSVP.Promise; diff --git a/addon/system/record-array-manager.js b/addon/system/record-array-manager.js index bd9d57a6915..740d088c763 100644 --- a/addon/system/record-array-manager.js +++ b/addon/system/record-array-manager.js @@ -2,6 +2,7 @@ @module ember-data */ +import Ember from 'ember'; import { RecordArray, FilteredRecordArray, diff --git a/addon/system/record-arrays/adapter-populated-record-array.js b/addon/system/record-arrays/adapter-populated-record-array.js index 796866cf614..80e392d4ff9 100644 --- a/addon/system/record-arrays/adapter-populated-record-array.js +++ b/addon/system/record-arrays/adapter-populated-record-array.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import RecordArray from "ember-data/system/record-arrays/record-array"; import cloneNull from "ember-data/system/clone-null"; diff --git a/addon/system/record-arrays/filtered-record-array.js b/addon/system/record-arrays/filtered-record-array.js index 7124aa8122e..bd1c21e2a22 100644 --- a/addon/system/record-arrays/filtered-record-array.js +++ b/addon/system/record-arrays/filtered-record-array.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import RecordArray from "ember-data/system/record-arrays/record-array"; /** diff --git a/addon/system/record-arrays/record-array.js b/addon/system/record-arrays/record-array.js index da9e705a5e1..5a6b3324af6 100644 --- a/addon/system/record-arrays/record-array.js +++ b/addon/system/record-arrays/record-array.js @@ -2,6 +2,7 @@ @module ember-data */ +import Ember from 'ember'; import { PromiseArray } from "ember-data/system/promise-proxies"; import SnapshotRecordArray from "ember-data/system/snapshot-record-array"; diff --git a/addon/system/relationships/belongs-to.js b/addon/system/relationships/belongs-to.js index 1950b11b9ea..28a905dd096 100644 --- a/addon/system/relationships/belongs-to.js +++ b/addon/system/relationships/belongs-to.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import { assert, warn } from "ember-data/debug"; import Model from 'ember-data/system/model'; import normalizeModelName from "ember-data/system/normalize-model-name"; diff --git a/addon/system/relationships/ext.js b/addon/system/relationships/ext.js index 53103dff38f..195f9e3b99e 100644 --- a/addon/system/relationships/ext.js +++ b/addon/system/relationships/ext.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import { assert, warn } from "ember-data/debug"; import { typeForRelationshipMeta, diff --git a/addon/system/relationships/has-many.js b/addon/system/relationships/has-many.js index 1e65e1668c5..42aa97520c0 100644 --- a/addon/system/relationships/has-many.js +++ b/addon/system/relationships/has-many.js @@ -2,6 +2,7 @@ @module ember-data */ +import Ember from 'ember'; import { assert } from "ember-data/debug"; import Model from "ember-data/system/model"; import normalizeModelName from "ember-data/system/normalize-model-name"; diff --git a/addon/system/relationships/state/belongs-to.js b/addon/system/relationships/state/belongs-to.js index d25bbb79ef8..a465be141e0 100644 --- a/addon/system/relationships/state/belongs-to.js +++ b/addon/system/relationships/state/belongs-to.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import { assert } from "ember-data/debug"; import { PromiseObject diff --git a/addon/system/relationships/state/create.js b/addon/system/relationships/state/create.js index 83cfefb6776..ccfc81d86af 100644 --- a/addon/system/relationships/state/create.js +++ b/addon/system/relationships/state/create.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import ManyRelationship from "ember-data/system/relationships/state/has-many"; import BelongsToRelationship from "ember-data/system/relationships/state/belongs-to"; import EmptyObject from "ember-data/system/empty-object"; diff --git a/addon/system/relationships/state/relationship.js b/addon/system/relationships/state/relationship.js index 181665dbfd8..768551b8bea 100644 --- a/addon/system/relationships/state/relationship.js +++ b/addon/system/relationships/state/relationship.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import { assert, warn } from "ember-data/debug"; import OrderedSet from "ember-data/system/ordered-set"; diff --git a/addon/system/serializer.js b/addon/system/serializer.js index 254ff4b1297..4ace384ad03 100644 --- a/addon/system/serializer.js +++ b/addon/system/serializer.js @@ -2,6 +2,8 @@ @module ember-data */ +import Ember from 'ember'; + /** `DS.Serializer` is an abstract base class that you should override in your application to customize it for your backend. The minimum set of methods diff --git a/addon/system/snapshot.js b/addon/system/snapshot.js index 1bf8050f62f..72673043bab 100644 --- a/addon/system/snapshot.js +++ b/addon/system/snapshot.js @@ -2,6 +2,7 @@ @module ember-data */ +import Ember from 'ember'; import EmptyObject from "ember-data/system/empty-object"; var get = Ember.get; diff --git a/addon/system/store.js b/addon/system/store.js index 8d1e2b52ec8..cca96bf7cfa 100644 --- a/addon/system/store.js +++ b/addon/system/store.js @@ -5,6 +5,8 @@ @module ember-data */ +import Ember from 'ember'; +import Model from 'ember-data/system/model'; import { assert, warn } from "ember-data/debug"; import _normalizeLink from "ember-data/system/normalize-link"; import normalizeModelName from "ember-data/system/normalize-model-name"; @@ -1485,7 +1487,7 @@ Store = Service.extend({ var mixin = owner._lookupFactory('mixin:' + normalizedModelName); if (mixin) { //Cache the class as a model - owner.register('model:' + normalizedModelName, DS.Model.extend(mixin)); + owner.register('model:' + normalizedModelName, Model.extend(mixin)); } var factory = this.modelFactoryFor(normalizedModelName); if (factory) { diff --git a/addon/system/store/common.js b/addon/system/store/common.js index 027288007cd..4e06691061c 100644 --- a/addon/system/store/common.js +++ b/addon/system/store/common.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + var get = Ember.get; export function _bind(fn) { diff --git a/addon/system/store/finders.js b/addon/system/store/finders.js index c4e6ecb92e2..d4455f2effd 100644 --- a/addon/system/store/finders.js +++ b/addon/system/store/finders.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import { assert } from "ember-data/debug"; import { _bind, diff --git a/addon/system/store/serializer-response.js b/addon/system/store/serializer-response.js index e352d7ba4a7..b51a5b8141d 100644 --- a/addon/system/store/serializer-response.js +++ b/addon/system/store/serializer-response.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import { assert, runInDebug } from "ember-data/debug"; /* diff --git a/addon/transforms/base.js b/addon/transforms/base.js index 252c35519b9..e9c45f2104a 100644 --- a/addon/transforms/base.js +++ b/addon/transforms/base.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + /** The `DS.Transform` class is used to serialize and deserialize model attributes when they are saved or loaded from an diff --git a/addon/transforms/date.js b/addon/transforms/date.js index f828b634089..434db18efe9 100644 --- a/addon/transforms/date.js +++ b/addon/transforms/date.js @@ -1,3 +1,5 @@ +import Ember from 'ember'; + /** The `DS.DateTransform` class is used to serialize and deserialize date attributes on Ember Data record objects. This transform is used diff --git a/addon/transforms/number.js b/addon/transforms/number.js index cd8b98b4ef8..1056842d410 100644 --- a/addon/transforms/number.js +++ b/addon/transforms/number.js @@ -1,3 +1,4 @@ +import Ember from 'ember'; import Transform from "ember-data/transforms/base"; var empty = Ember.isEmpty; diff --git a/addon/transforms/string.js b/addon/transforms/string.js index 75db271fff4..50ef6c0b232 100644 --- a/addon/transforms/string.js +++ b/addon/transforms/string.js @@ -1,4 +1,6 @@ +import Ember from 'ember'; import Transform from "ember-data/transforms/base"; + var none = Ember.isNone; /** diff --git a/tests/.jshintrc b/tests/.jshintrc index 1aecd8ac495..ff32395941f 100644 --- a/tests/.jshintrc +++ b/tests/.jshintrc @@ -1,27 +1,7 @@ { "predef": [ - "document", "window", - "location", - "setTimeout", - "$", - "-Promise", - "define", - "console", - "visit", - "exists", - "fillIn", - "click", - "keyEvent", - "triggerEvent", - "find", - "findWithAssert", - "wait", - "DS", - "andThen", - "currentURL", - "currentPath", - "currentRouteName" + "setTimeout" ], "node": false, "browser": false, diff --git a/tests/helpers/store.js b/tests/helpers/store.js index 9ba46388249..96deb9ab69b 100644 --- a/tests/helpers/store.js +++ b/tests/helpers/store.js @@ -1,4 +1,5 @@ import Ember from 'ember'; +import DS from 'ember-data'; export default function setupStore(options) { var container, registry; From f1762687b8985dc790f933e6cb29c6be4ec77b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Rohweder?= Date: Wed, 9 Dec 2015 10:46:43 +0100 Subject: [PATCH 1263/2527] [DOC beta] Fix documentation to use "serializedHasManyName" The variable was declared but never used in the documentation --- addon/system/relationships/ext.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/system/relationships/ext.js b/addon/system/relationships/ext.js index 53103dff38f..4d57891c2fe 100644 --- a/addon/system/relationships/ext.js +++ b/addon/system/relationships/ext.js @@ -635,7 +635,7 @@ Model.reopen({ record.eachRelationship(function(name, descriptor) { if (descriptor.kind === 'hasMany') { var serializedHasManyName = name.toUpperCase() + '_IDS'; - json[name.toUpperCase()] = record.get(name).mapBy('id'); + json[serializedHasManyName] = record.get(name).mapBy('id'); } }); From a10a849950ef989d1e8b09326b4a3d6ccc36bd22 Mon Sep 17 00:00:00 2001 From: Dave Wasmer Date: Thu, 10 Dec 2015 16:09:06 -0700 Subject: [PATCH 1264/2527] Remove extraneous conditional in ajax() The conditional was checking if `error` was not an instance of `Error`, but it was initialized on the previous line, ensuring the conditional would always pass. --- addon/adapters/rest-adapter.js | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/addon/adapters/rest-adapter.js b/addon/adapters/rest-adapter.js index ed3b9df8ec7..3b0426f20c6 100644 --- a/addon/adapters/rest-adapter.js +++ b/addon/adapters/rest-adapter.js @@ -842,21 +842,19 @@ export default Adapter.extend(BuildURLMixin, { hash.error = function(jqXHR, textStatus, errorThrown) { let error; - if (!(error instanceof Error)) { - if (errorThrown instanceof Error) { - error = errorThrown; - } else if (textStatus === 'timeout') { - error = new TimeoutError(); - } else if (textStatus === 'abort') { - error = new AbortError(); - } else { - error = adapter.handleResponse( - jqXHR.status, - parseResponseHeaders(jqXHR.getAllResponseHeaders()), - adapter.parseErrorResponse(jqXHR.responseText) || errorThrown, - requestData - ); - } + if (errorThrown instanceof Error) { + error = errorThrown; + } else if (textStatus === 'timeout') { + error = new TimeoutError(); + } else if (textStatus === 'abort') { + error = new AbortError(); + } else { + error = adapter.handleResponse( + jqXHR.status, + parseResponseHeaders(jqXHR.getAllResponseHeaders()), + adapter.parseErrorResponse(jqXHR.responseText) || errorThrown, + requestData + ); } Ember.run.join(null, reject, error); From 57e7c5537ee110e59007b0169f1921cc22fafa1c Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 10 Dec 2015 18:05:47 -0600 Subject: [PATCH 1265/2527] use JS comment instead of HTML comment --- lib/enable-optional-features-via-url/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/enable-optional-features-via-url/index.js b/lib/enable-optional-features-via-url/index.js index 0c16d924cc0..f705e66d5d4 100644 --- a/lib/enable-optional-features-via-url/index.js +++ b/lib/enable-optional-features-via-url/index.js @@ -14,7 +14,7 @@ module.exports = { contentFor: function(name) { if (name === "vendor-prefix") { var array = [ - "", + "// injected by lib/enable-optional-features-via-url", "window.EmberENV = window.EmberENV || {};", "if (typeof window.EmberENV.ENABLE_OPTIONAL_FEATURES === 'undefined') {", " window.EmberENV.ENABLE_OPTIONAL_FEATURES = window.location.search.indexOf('enableoptionalfeatures') !== -1;", From efd0e5dd0d52d7204600741cdaa23530f4eb3834 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 16 Oct 2015 09:11:00 -0400 Subject: [PATCH 1266/2527] Throw a more helpful error message if the response from queryRecord is empty --- addon/system/store/finders.js | 1 + tests/integration/adapter/rest-adapter-test.js | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/addon/system/store/finders.js b/addon/system/store/finders.js index d4455f2effd..b08fa06bbba 100644 --- a/addon/system/store/finders.js +++ b/addon/system/store/finders.js @@ -190,6 +190,7 @@ export function _queryRecord(adapter, store, typeClass, query) { var record; store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'queryRecord'); + Ember.assert('`store.queryRecord` expected the adapter to return one record but the response from the adapter was empty.', payload.data); //TODO Optimize record = store.push(payload); }); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index de6fefa4afc..c4583c57add 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1325,6 +1325,18 @@ test("queryRecord - returning an array picks the first one but saves all records })); }); +test("queryRecord - returning an empty array errors", function(assert) { + ajaxResponse({ + post: [] + }); + + assert.expectAssertion(function() { + Ember.run(function() { + store.queryRecord('post', { slug: 'rails-is-omakaze' }); + }); + }, /`store.queryRecord` expected the adapter to return one record/); +}); + test("queryRecord - data is normalized through custom serializers", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', From 883cf9c0ebe18277b1c8fab2381fe46eacfb13d9 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 11 Dec 2015 13:27:37 -0500 Subject: [PATCH 1267/2527] Move private modules into the `-private` directory to discourage importing from paths that may change in future versions --- addon/-private/adapters.js | 11 ++++ .../adapters/build-url-mixin.js | 0 addon/{ => -private}/adapters/errors.js | 2 +- .../adapters/json-api-adapter.js | 2 +- addon/{ => -private}/adapters/rest-adapter.js | 8 +-- addon/{ => -private}/core.js | 0 addon/{ => -private}/debug.js | 1 - addon/{ => -private}/ember-initializer.js | 4 +- addon/{ => -private}/ext/date.js | 0 addon/{ => -private}/features.js | 0 .../initializers/data-adapter.js | 2 +- .../initializers/store-injections.js | 0 addon/{ => -private}/initializers/store.js | 6 +-- .../{ => -private}/initializers/transforms.js | 2 +- .../initialize-store-service.js | 0 addon/-private/serializers.js | 13 +++++ .../serializers/embedded-records-mixin.js | 2 +- .../serializers/json-api-serializer.js | 6 +-- .../serializers/json-serializer.js | 14 ++--- .../serializers/rest-serializer.js | 10 ++-- addon/-private/setup-container.js | 11 ++++ addon/{ => -private}/system/adapter.js | 0 addon/{ => -private}/system/clone-null.js | 2 +- addon/{ => -private}/system/coerce-id.js | 0 .../{ => -private}/system/container-proxy.js | 2 +- addon/-private/system/debug.js | 8 +++ .../system/debug/debug-adapter.js | 2 +- .../{ => -private}/system/debug/debug-info.js | 2 +- addon/{ => -private}/system/empty-object.js | 0 addon/{ => -private}/system/is-array-like.js | 0 addon/{ => -private}/system/many-array.js | 4 +- addon/{ => -private}/system/merge.js | 0 addon/-private/system/model.js | 16 ++++++ .../{ => -private}/system/model/attributes.js | 4 +- addon/{ => -private}/system/model/errors.js | 2 +- .../system/model/errors/invalid.js | 0 .../system/model/internal-model.js | 14 ++--- addon/{ => -private}/system/model/model.js | 6 +-- addon/{ => -private}/system/model/states.js | 2 +- addon/{ => -private}/system/normalize-link.js | 0 .../system/normalize-model-name.js | 0 addon/{ => -private}/system/ordered-set.js | 0 .../{ => -private}/system/promise-proxies.js | 2 +- .../system/record-array-manager.js | 4 +- addon/-private/system/record-arrays.js | 13 +++++ .../adapter-populated-record-array.js | 4 +- .../record-arrays/filtered-record-array.js | 2 +- .../system/record-arrays/record-array.js | 4 +- .../system/relationship-meta.js | 2 +- addon/{ => -private}/system/relationships.js | 2 +- .../system/relationships/belongs-to.js | 6 +-- .../system/relationships/ext.js | 8 +-- .../system/relationships/has-many.js | 8 +-- .../system/relationships/state/belongs-to.js | 8 +-- .../system/relationships/state/create.js | 6 +-- .../system/relationships/state/has-many.js | 12 ++--- .../relationships/state/relationship.js | 4 +- addon/{ => -private}/system/serializer.js | 0 .../system/snapshot-record-array.js | 0 addon/{ => -private}/system/snapshot.js | 2 +- addon/{ => -private}/system/store.js | 32 +++++------ addon/{ => -private}/system/store/common.js | 0 .../system/store/container-instance-cache.js | 2 +- addon/{ => -private}/system/store/finders.js | 8 +-- .../system/store/serializer-response.js | 2 +- .../system/store/serializers.js | 0 addon/-private/transforms.js | 13 +++++ addon/{ => -private}/transforms/base.js | 0 addon/{ => -private}/transforms/boolean.js | 2 +- addon/{ => -private}/transforms/date.js | 2 +- addon/{ => -private}/transforms/number.js | 2 +- addon/{ => -private}/transforms/string.js | 2 +- addon/{ => -private}/utils.js | 2 +- addon/adapters.js | 11 ---- addon/index.js | 54 +++++++++---------- addon/serializers.js | 13 ----- addon/setup-container.js | 11 ---- addon/system/debug.js | 8 --- addon/system/model.js | 16 ------ addon/system/record-arrays.js | 13 ----- addon/transforms.js | 13 ----- 81 files changed, 225 insertions(+), 226 deletions(-) create mode 100644 addon/-private/adapters.js rename addon/{ => -private}/adapters/build-url-mixin.js (100%) rename addon/{ => -private}/adapters/errors.js (98%) rename addon/{ => -private}/adapters/json-api-adapter.js (98%) rename addon/{ => -private}/adapters/rest-adapter.js (99%) rename addon/{ => -private}/core.js (100%) rename addon/{ => -private}/debug.js (99%) rename addon/{ => -private}/ember-initializer.js (92%) rename addon/{ => -private}/ext/date.js (100%) rename addon/{ => -private}/features.js (100%) rename addon/{ => -private}/initializers/data-adapter.js (81%) rename addon/{ => -private}/initializers/store-injections.js (100%) rename addon/{ => -private}/initializers/store.js (88%) rename addon/{ => -private}/initializers/transforms.js (92%) rename addon/{ => -private}/instance-initializers/initialize-store-service.js (100%) create mode 100644 addon/-private/serializers.js rename addon/{ => -private}/serializers/embedded-records-mixin.js (99%) rename addon/{ => -private}/serializers/json-api-serializer.js (98%) rename addon/{ => -private}/serializers/json-serializer.js (99%) rename addon/{ => -private}/serializers/rest-serializer.js (98%) create mode 100644 addon/-private/setup-container.js rename addon/{ => -private}/system/adapter.js (100%) rename addon/{ => -private}/system/clone-null.js (70%) rename addon/{ => -private}/system/coerce-id.js (100%) rename addon/{ => -private}/system/container-proxy.js (96%) create mode 100644 addon/-private/system/debug.js rename addon/{ => -private}/system/debug/debug-adapter.js (98%) rename addon/{ => -private}/system/debug/debug-info.js (96%) rename addon/{ => -private}/system/empty-object.js (100%) rename addon/{ => -private}/system/is-array-like.js (100%) rename addon/{ => -private}/system/many-array.js (98%) rename addon/{ => -private}/system/merge.js (100%) create mode 100644 addon/-private/system/model.js rename addon/{ => -private}/system/model/attributes.js (98%) rename addon/{ => -private}/system/model/errors.js (99%) rename addon/{ => -private}/system/model/errors/invalid.js (100%) rename addon/{ => -private}/system/model/internal-model.js (98%) rename addon/{ => -private}/system/model/model.js (99%) rename addon/{ => -private}/system/model/states.js (99%) rename addon/{ => -private}/system/normalize-link.js (100%) rename addon/{ => -private}/system/normalize-model-name.js (100%) rename addon/{ => -private}/system/ordered-set.js (100%) rename addon/{ => -private}/system/promise-proxies.js (98%) rename addon/{ => -private}/system/record-array-manager.js (98%) create mode 100644 addon/-private/system/record-arrays.js rename addon/{ => -private}/system/record-arrays/adapter-populated-record-array.js (90%) rename addon/{ => -private}/system/record-arrays/filtered-record-array.js (95%) rename addon/{ => -private}/system/record-arrays/record-array.js (96%) rename addon/{ => -private}/system/relationship-meta.js (85%) rename addon/{ => -private}/system/relationships.js (75%) rename addon/{ => -private}/system/relationships/belongs-to.js (95%) rename addon/{ => -private}/system/relationships/ext.js (98%) rename addon/{ => -private}/system/relationships/has-many.js (94%) rename addon/{ => -private}/system/relationships/state/belongs-to.js (95%) rename addon/{ => -private}/system/relationships/state/create.js (81%) rename addon/{ => -private}/system/relationships/state/has-many.js (94%) rename addon/{ => -private}/system/relationships/state/relationship.js (98%) rename addon/{ => -private}/system/serializer.js (100%) rename addon/{ => -private}/system/snapshot-record-array.js (100%) rename addon/{ => -private}/system/snapshot.js (99%) rename addon/{ => -private}/system/store.js (98%) rename addon/{ => -private}/system/store/common.js (100%) rename addon/{ => -private}/system/store/container-instance-cache.js (97%) rename addon/{ => -private}/system/store/finders.js (97%) rename addon/{ => -private}/system/store/serializer-response.js (97%) rename addon/{ => -private}/system/store/serializers.js (100%) create mode 100644 addon/-private/transforms.js rename addon/{ => -private}/transforms/base.js (100%) rename addon/{ => -private}/transforms/boolean.js (94%) rename addon/{ => -private}/transforms/date.js (95%) rename addon/{ => -private}/transforms/number.js (95%) rename addon/{ => -private}/transforms/string.js (92%) rename addon/{ => -private}/utils.js (98%) delete mode 100644 addon/adapters.js delete mode 100644 addon/serializers.js delete mode 100644 addon/setup-container.js delete mode 100644 addon/system/debug.js delete mode 100644 addon/system/model.js delete mode 100644 addon/system/record-arrays.js delete mode 100644 addon/transforms.js diff --git a/addon/-private/adapters.js b/addon/-private/adapters.js new file mode 100644 index 00000000000..53fa2f9dbf3 --- /dev/null +++ b/addon/-private/adapters.js @@ -0,0 +1,11 @@ +/** + @module ember-data +*/ + +import JSONAPIAdapter from "ember-data/-private/adapters/json-api-adapter"; +import RESTAdapter from "ember-data/-private/adapters/rest-adapter"; + +export { + JSONAPIAdapter, + RESTAdapter +}; diff --git a/addon/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js similarity index 100% rename from addon/adapters/build-url-mixin.js rename to addon/-private/adapters/build-url-mixin.js diff --git a/addon/adapters/errors.js b/addon/-private/adapters/errors.js similarity index 98% rename from addon/adapters/errors.js rename to addon/-private/adapters/errors.js index d6f3a4010e9..dc548243a4c 100644 --- a/addon/adapters/errors.js +++ b/addon/-private/adapters/errors.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import {assert} from 'ember-data/debug'; +import {assert} from 'ember-data/-private/debug'; const EmberError = Ember.Error; diff --git a/addon/adapters/json-api-adapter.js b/addon/-private/adapters/json-api-adapter.js similarity index 98% rename from addon/adapters/json-api-adapter.js rename to addon/-private/adapters/json-api-adapter.js index f0e0d244ec8..0d21e7316e4 100644 --- a/addon/adapters/json-api-adapter.js +++ b/addon/-private/adapters/json-api-adapter.js @@ -3,7 +3,7 @@ */ import Ember from 'ember'; -import RESTAdapter from "ember-data/adapters/rest-adapter"; +import RESTAdapter from "ember-data/-private/adapters/rest-adapter"; /** @class JSONAPIAdapter diff --git a/addon/adapters/rest-adapter.js b/addon/-private/adapters/rest-adapter.js similarity index 99% rename from addon/adapters/rest-adapter.js rename to addon/-private/adapters/rest-adapter.js index 3b0426f20c6..7e28d4fdbf8 100644 --- a/addon/adapters/rest-adapter.js +++ b/addon/-private/adapters/rest-adapter.js @@ -3,18 +3,18 @@ */ import Ember from 'ember'; -import Adapter from "ember-data/system/adapter"; +import Adapter from "ember-data/-private/system/adapter"; import { AdapterError, InvalidError, TimeoutError, AbortError -} from 'ember-data/adapters/errors'; -import EmptyObject from "ember-data/system/empty-object"; +} from 'ember-data/-private/adapters/errors'; +import EmptyObject from "ember-data/-private/system/empty-object"; var get = Ember.get; var MapWithDefault = Ember.MapWithDefault; -import BuildURLMixin from "ember-data/adapters/build-url-mixin"; +import BuildURLMixin from "ember-data/-private/adapters/build-url-mixin"; /** The REST adapter allows your store to communicate with an HTTP server by diff --git a/addon/core.js b/addon/-private/core.js similarity index 100% rename from addon/core.js rename to addon/-private/core.js diff --git a/addon/debug.js b/addon/-private/debug.js similarity index 99% rename from addon/debug.js rename to addon/-private/debug.js index 6ac646ef7ac..ddd00cf17e1 100644 --- a/addon/debug.js +++ b/addon/-private/debug.js @@ -27,4 +27,3 @@ export function warn() { export function debugSeal() { return Ember.debugSeal(...arguments); } - diff --git a/addon/ember-initializer.js b/addon/-private/ember-initializer.js similarity index 92% rename from addon/ember-initializer.js rename to addon/-private/ember-initializer.js index 9da818688b1..5a0c19cb3ed 100644 --- a/addon/ember-initializer.js +++ b/addon/-private/ember-initializer.js @@ -1,6 +1,6 @@ import Ember from 'ember'; -import setupContainer from 'ember-data/setup-container'; -import initializeStoreService from 'ember-data/instance-initializers/initialize-store-service'; +import setupContainer from 'ember-data/-private/setup-container'; +import initializeStoreService from 'ember-data/-private/instance-initializers/initialize-store-service'; var K = Ember.K; diff --git a/addon/ext/date.js b/addon/-private/ext/date.js similarity index 100% rename from addon/ext/date.js rename to addon/-private/ext/date.js diff --git a/addon/features.js b/addon/-private/features.js similarity index 100% rename from addon/features.js rename to addon/-private/features.js diff --git a/addon/initializers/data-adapter.js b/addon/-private/initializers/data-adapter.js similarity index 81% rename from addon/initializers/data-adapter.js rename to addon/-private/initializers/data-adapter.js index 0c5ead0fe64..419392392f1 100644 --- a/addon/initializers/data-adapter.js +++ b/addon/-private/initializers/data-adapter.js @@ -1,4 +1,4 @@ -import DebugAdapter from "ember-data/system/debug/debug-adapter"; +import DebugAdapter from "ember-data/-private/system/debug/debug-adapter"; /** Configures a registry with injections on Ember applications diff --git a/addon/initializers/store-injections.js b/addon/-private/initializers/store-injections.js similarity index 100% rename from addon/initializers/store-injections.js rename to addon/-private/initializers/store-injections.js diff --git a/addon/initializers/store.js b/addon/-private/initializers/store.js similarity index 88% rename from addon/initializers/store.js rename to addon/-private/initializers/store.js index 4b2c12d7dd4..a40895bfa7c 100644 --- a/addon/initializers/store.js +++ b/addon/-private/initializers/store.js @@ -1,6 +1,6 @@ -import Store from "ember-data/system/store"; -import { JSONAPISerializer, JSONSerializer, RESTSerializer } from "ember-data/serializers"; -import { JSONAPIAdapter, RESTAdapter } from "ember-data/adapters"; +import Store from "ember-data/-private/system/store"; +import { JSONAPISerializer, JSONSerializer, RESTSerializer } from "ember-data/-private/serializers"; +import { JSONAPIAdapter, RESTAdapter } from "ember-data/-private/adapters"; function has(applicationOrRegistry, fullName) { if (applicationOrRegistry.has) { diff --git a/addon/initializers/transforms.js b/addon/-private/initializers/transforms.js similarity index 92% rename from addon/initializers/transforms.js rename to addon/-private/initializers/transforms.js index 91ac7f3f8bd..5503f924130 100644 --- a/addon/initializers/transforms.js +++ b/addon/-private/initializers/transforms.js @@ -3,7 +3,7 @@ import { DateTransform, StringTransform, NumberTransform -} from "ember-data/transforms"; +} from "ember-data/-private/transforms"; /** Configures a registry for use with Ember-Data diff --git a/addon/instance-initializers/initialize-store-service.js b/addon/-private/instance-initializers/initialize-store-service.js similarity index 100% rename from addon/instance-initializers/initialize-store-service.js rename to addon/-private/instance-initializers/initialize-store-service.js diff --git a/addon/-private/serializers.js b/addon/-private/serializers.js new file mode 100644 index 00000000000..ba7feb43a4f --- /dev/null +++ b/addon/-private/serializers.js @@ -0,0 +1,13 @@ +/** + @module ember-data +*/ + +import JSONAPISerializer from "ember-data/-private/serializers/json-api-serializer"; +import JSONSerializer from "ember-data/-private/serializers/json-serializer"; +import RESTSerializer from "ember-data/-private/serializers/rest-serializer"; + +export { + JSONAPISerializer, + JSONSerializer, + RESTSerializer +}; diff --git a/addon/serializers/embedded-records-mixin.js b/addon/-private/serializers/embedded-records-mixin.js similarity index 99% rename from addon/serializers/embedded-records-mixin.js rename to addon/-private/serializers/embedded-records-mixin.js index d88f03ac458..e7968bd13f6 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/-private/serializers/embedded-records-mixin.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { warn } from "ember-data/debug"; +import { warn } from "ember-data/-private/debug"; var get = Ember.get; var set = Ember.set; diff --git a/addon/serializers/json-api-serializer.js b/addon/-private/serializers/json-api-serializer.js similarity index 98% rename from addon/serializers/json-api-serializer.js rename to addon/-private/serializers/json-api-serializer.js index 152158486e9..1bcb674753f 100644 --- a/addon/serializers/json-api-serializer.js +++ b/addon/-private/serializers/json-api-serializer.js @@ -3,9 +3,9 @@ */ import Ember from 'ember'; -import { assert, runInDebug, warn } from 'ember-data/debug'; -import JSONSerializer from 'ember-data/serializers/json-serializer'; -import normalizeModelName from 'ember-data/system/normalize-model-name'; +import { assert, runInDebug, warn } from 'ember-data/-private/debug'; +import JSONSerializer from 'ember-data/-private/serializers/json-serializer'; +import normalizeModelName from 'ember-data/-private/system/normalize-model-name'; import { pluralize, singularize } from 'ember-inflector'; var dasherize = Ember.String.dasherize; diff --git a/addon/serializers/json-serializer.js b/addon/-private/serializers/json-serializer.js similarity index 99% rename from addon/serializers/json-serializer.js rename to addon/-private/serializers/json-serializer.js index 0f0ff1c7fa9..af32f6a727f 100644 --- a/addon/serializers/json-serializer.js +++ b/addon/-private/serializers/json-serializer.js @@ -1,15 +1,15 @@ import Ember from 'ember'; -import { assert, warn } from 'ember-data/debug'; -import Serializer from "ember-data/system/serializer"; -import coerceId from "ember-data/system/coerce-id"; -import normalizeModelName from "ember-data/system/normalize-model-name"; -import { modelHasAttributeOrRelationshipNamedType } from "ember-data/utils"; +import { assert, warn } from 'ember-data/-private/debug'; +import Serializer from "ember-data/-private/system/serializer"; +import coerceId from "ember-data/-private/system/coerce-id"; +import normalizeModelName from "ember-data/-private/system/normalize-model-name"; +import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; import { getOwner -} from 'ember-data/utils'; +} from 'ember-data/-private/utils'; -import { errorsArrayToHash } from "ember-data/adapters/errors"; +import { errorsArrayToHash } from "ember-data/-private/adapters/errors"; var get = Ember.get; var isNone = Ember.isNone; diff --git a/addon/serializers/rest-serializer.js b/addon/-private/serializers/rest-serializer.js similarity index 98% rename from addon/serializers/rest-serializer.js rename to addon/-private/serializers/rest-serializer.js index 3a200e8a576..dc2bcb4d800 100644 --- a/addon/serializers/rest-serializer.js +++ b/addon/-private/serializers/rest-serializer.js @@ -3,12 +3,12 @@ */ import Ember from 'ember'; -import { assert, deprecate, runInDebug, warn } from "ember-data/debug"; -import JSONSerializer from "ember-data/serializers/json-serializer"; -import normalizeModelName from "ember-data/system/normalize-model-name"; +import { assert, deprecate, runInDebug, warn } from "ember-data/-private/debug"; +import JSONSerializer from "ember-data/-private/serializers/json-serializer"; +import normalizeModelName from "ember-data/-private/system/normalize-model-name"; import {singularize} from "ember-inflector"; -import coerceId from "ember-data/system/coerce-id"; -import { modelHasAttributeOrRelationshipNamedType } from "ember-data/utils"; +import coerceId from "ember-data/-private/system/coerce-id"; +import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; var camelize = Ember.String.camelize; diff --git a/addon/-private/setup-container.js b/addon/-private/setup-container.js new file mode 100644 index 00000000000..937ddb9a876 --- /dev/null +++ b/addon/-private/setup-container.js @@ -0,0 +1,11 @@ +import initializeStore from 'ember-data/-private/initializers/store'; +import initializeTransforms from 'ember-data/-private/initializers/transforms'; +import initializeStoreInjections from 'ember-data/-private/initializers/store-injections'; +import initializeDataAdapter from 'ember-data/-private/initializers/data-adapter'; + +export default function setupContainer(application) { + initializeDataAdapter(application); + initializeTransforms(application); + initializeStoreInjections(application); + initializeStore(application); +} diff --git a/addon/system/adapter.js b/addon/-private/system/adapter.js similarity index 100% rename from addon/system/adapter.js rename to addon/-private/system/adapter.js diff --git a/addon/system/clone-null.js b/addon/-private/system/clone-null.js similarity index 70% rename from addon/system/clone-null.js rename to addon/-private/system/clone-null.js index a0c5337293c..96d37b9e44a 100644 --- a/addon/system/clone-null.js +++ b/addon/-private/system/clone-null.js @@ -1,4 +1,4 @@ -import EmptyObject from "ember-data/system/empty-object"; +import EmptyObject from "ember-data/-private/system/empty-object"; export default function cloneNull(source) { var clone = new EmptyObject(); for (var key in source) { diff --git a/addon/system/coerce-id.js b/addon/-private/system/coerce-id.js similarity index 100% rename from addon/system/coerce-id.js rename to addon/-private/system/coerce-id.js diff --git a/addon/system/container-proxy.js b/addon/-private/system/container-proxy.js similarity index 96% rename from addon/system/container-proxy.js rename to addon/-private/system/container-proxy.js index 7cf0a5dd1a4..0117042cdb5 100644 --- a/addon/system/container-proxy.js +++ b/addon/-private/system/container-proxy.js @@ -1,4 +1,4 @@ -import { deprecate } from "ember-data/debug"; +import { deprecate } from "ember-data/-private/debug"; /** This is used internally to enable deprecation of container paths and provide diff --git a/addon/-private/system/debug.js b/addon/-private/system/debug.js new file mode 100644 index 00000000000..44886d0d8d4 --- /dev/null +++ b/addon/-private/system/debug.js @@ -0,0 +1,8 @@ +/** + @module ember-data +*/ + +import "ember-data/-private/system/debug/debug-info"; +import DebugAdapter from "ember-data/-private/system/debug/debug-adapter"; + +export default DebugAdapter; diff --git a/addon/system/debug/debug-adapter.js b/addon/-private/system/debug/debug-adapter.js similarity index 98% rename from addon/system/debug/debug-adapter.js rename to addon/-private/system/debug/debug-adapter.js index b70763781cc..4080bc50874 100644 --- a/addon/system/debug/debug-adapter.js +++ b/addon/-private/system/debug/debug-adapter.js @@ -2,7 +2,7 @@ @module ember-data */ import Ember from 'ember'; -import Model from "ember-data/system/model"; +import Model from "ember-data/-private/system/model"; var get = Ember.get; var capitalize = Ember.String.capitalize; var underscore = Ember.String.underscore; diff --git a/addon/system/debug/debug-info.js b/addon/-private/system/debug/debug-info.js similarity index 96% rename from addon/system/debug/debug-info.js rename to addon/-private/system/debug/debug-info.js index afd7009c4df..6e079856fae 100644 --- a/addon/system/debug/debug-info.js +++ b/addon/-private/system/debug/debug-info.js @@ -1,4 +1,4 @@ -import Model from "ember-data/system/model"; +import Model from "ember-data/-private/system/model"; Model.reopen({ diff --git a/addon/system/empty-object.js b/addon/-private/system/empty-object.js similarity index 100% rename from addon/system/empty-object.js rename to addon/-private/system/empty-object.js diff --git a/addon/system/is-array-like.js b/addon/-private/system/is-array-like.js similarity index 100% rename from addon/system/is-array-like.js rename to addon/-private/system/is-array-like.js diff --git a/addon/system/many-array.js b/addon/-private/system/many-array.js similarity index 98% rename from addon/system/many-array.js rename to addon/-private/system/many-array.js index 42064152b05..bf09a7505dc 100644 --- a/addon/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -2,8 +2,8 @@ @module ember-data */ import Ember from 'ember'; -import { assert } from "ember-data/debug"; -import { PromiseArray } from "ember-data/system/promise-proxies"; +import { assert } from "ember-data/-private/debug"; +import { PromiseArray } from "ember-data/-private/system/promise-proxies"; var get = Ember.get; var set = Ember.set; diff --git a/addon/system/merge.js b/addon/-private/system/merge.js similarity index 100% rename from addon/system/merge.js rename to addon/-private/system/merge.js diff --git a/addon/-private/system/model.js b/addon/-private/system/model.js new file mode 100644 index 00000000000..f3f0c79bdff --- /dev/null +++ b/addon/-private/system/model.js @@ -0,0 +1,16 @@ +/** + @module ember-data +*/ + +import Model from "ember-data/-private/system/model/model"; +import attr from "ember-data/-private/system/model/attributes"; +import RootState from "ember-data/-private/system/model/states"; +import Errors from "ember-data/-private/system/model/errors"; + +export { + RootState, + attr, + Errors +}; + +export default Model; diff --git a/addon/system/model/attributes.js b/addon/-private/system/model/attributes.js similarity index 98% rename from addon/system/model/attributes.js rename to addon/-private/system/model/attributes.js index a0ff4da4f43..9a101508a16 100644 --- a/addon/system/model/attributes.js +++ b/addon/-private/system/model/attributes.js @@ -1,6 +1,6 @@ import Ember from 'ember'; -import Model from "ember-data/system/model/model"; -import { assert, deprecate } from "ember-data/debug"; +import Model from "ember-data/-private/system/model/model"; +import { assert, deprecate } from "ember-data/-private/debug"; /** @module ember-data diff --git a/addon/system/model/errors.js b/addon/-private/system/model/errors.js similarity index 99% rename from addon/system/model/errors.js rename to addon/-private/system/model/errors.js index 664cab24503..09c87ed628e 100644 --- a/addon/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { deprecate, warn } from "ember-data/debug"; +import { deprecate, warn } from "ember-data/-private/debug"; var get = Ember.get; var set = Ember.set; diff --git a/addon/system/model/errors/invalid.js b/addon/-private/system/model/errors/invalid.js similarity index 100% rename from addon/system/model/errors/invalid.js rename to addon/-private/system/model/errors/invalid.js diff --git a/addon/system/model/internal-model.js b/addon/-private/system/model/internal-model.js similarity index 98% rename from addon/system/model/internal-model.js rename to addon/-private/system/model/internal-model.js index b01f81a07d3..b28b2937a80 100644 --- a/addon/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -1,14 +1,14 @@ import Ember from 'ember'; -import { assert } from "ember-data/debug"; -import merge from "ember-data/system/merge"; -import RootState from "ember-data/system/model/states"; -import Relationships from "ember-data/system/relationships/state/create"; -import Snapshot from "ember-data/system/snapshot"; -import EmptyObject from "ember-data/system/empty-object"; +import { assert } from "ember-data/-private/debug"; +import merge from "ember-data/-private/system/merge"; +import RootState from "ember-data/-private/system/model/states"; +import Relationships from "ember-data/-private/system/relationships/state/create"; +import Snapshot from "ember-data/-private/system/snapshot"; +import EmptyObject from "ember-data/-private/system/empty-object"; import { getOwner -} from 'ember-data/utils'; +} from 'ember-data/-private/utils'; var Promise = Ember.RSVP.Promise; var get = Ember.get; diff --git a/addon/system/model/model.js b/addon/-private/system/model/model.js similarity index 99% rename from addon/system/model/model.js rename to addon/-private/system/model/model.js index e1cdd001ce7..60cc0edbd45 100644 --- a/addon/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1,7 +1,7 @@ import Ember from 'ember'; -import { assert, deprecate } from "ember-data/debug"; -import { PromiseObject } from "ember-data/system/promise-proxies"; -import Errors from "ember-data/system/model/errors"; +import { assert, deprecate } from "ember-data/-private/debug"; +import { PromiseObject } from "ember-data/-private/system/promise-proxies"; +import Errors from "ember-data/-private/system/model/errors"; /** @module ember-data diff --git a/addon/system/model/states.js b/addon/-private/system/model/states.js similarity index 99% rename from addon/system/model/states.js rename to addon/-private/system/model/states.js index 1c1d59311d5..6d362bec313 100644 --- a/addon/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -2,7 +2,7 @@ @module ember-data */ import Ember from 'ember'; -import { assert } from "ember-data/debug"; +import { assert } from "ember-data/-private/debug"; var get = Ember.get; /* diff --git a/addon/system/normalize-link.js b/addon/-private/system/normalize-link.js similarity index 100% rename from addon/system/normalize-link.js rename to addon/-private/system/normalize-link.js diff --git a/addon/system/normalize-model-name.js b/addon/-private/system/normalize-model-name.js similarity index 100% rename from addon/system/normalize-model-name.js rename to addon/-private/system/normalize-model-name.js diff --git a/addon/system/ordered-set.js b/addon/-private/system/ordered-set.js similarity index 100% rename from addon/system/ordered-set.js rename to addon/-private/system/ordered-set.js diff --git a/addon/system/promise-proxies.js b/addon/-private/system/promise-proxies.js similarity index 98% rename from addon/system/promise-proxies.js rename to addon/-private/system/promise-proxies.js index aebce8fda57..59f5efb30e8 100644 --- a/addon/system/promise-proxies.js +++ b/addon/-private/system/promise-proxies.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert } from "ember-data/debug"; +import { assert } from "ember-data/-private/debug"; var Promise = Ember.RSVP.Promise; var get = Ember.get; diff --git a/addon/system/record-array-manager.js b/addon/-private/system/record-array-manager.js similarity index 98% rename from addon/system/record-array-manager.js rename to addon/-private/system/record-array-manager.js index 740d088c763..d264b6f3349 100644 --- a/addon/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -7,9 +7,9 @@ import { RecordArray, FilteredRecordArray, AdapterPopulatedRecordArray -} from "ember-data/system/record-arrays"; +} from "ember-data/-private/system/record-arrays"; var MapWithDefault = Ember.MapWithDefault; -import OrderedSet from "ember-data/system/ordered-set"; +import OrderedSet from "ember-data/-private/system/ordered-set"; var get = Ember.get; /** diff --git a/addon/-private/system/record-arrays.js b/addon/-private/system/record-arrays.js new file mode 100644 index 00000000000..d2811b17ee7 --- /dev/null +++ b/addon/-private/system/record-arrays.js @@ -0,0 +1,13 @@ +/** + @module ember-data +*/ + +import RecordArray from "ember-data/-private/system/record-arrays/record-array"; +import FilteredRecordArray from "ember-data/-private/system/record-arrays/filtered-record-array"; +import AdapterPopulatedRecordArray from "ember-data/-private/system/record-arrays/adapter-populated-record-array"; + +export { + RecordArray, + FilteredRecordArray, + AdapterPopulatedRecordArray +}; diff --git a/addon/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js similarity index 90% rename from addon/system/record-arrays/adapter-populated-record-array.js rename to addon/-private/system/record-arrays/adapter-populated-record-array.js index 80e392d4ff9..ae923c46e36 100644 --- a/addon/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -1,6 +1,6 @@ import Ember from 'ember'; -import RecordArray from "ember-data/system/record-arrays/record-array"; -import cloneNull from "ember-data/system/clone-null"; +import RecordArray from "ember-data/-private/system/record-arrays/record-array"; +import cloneNull from "ember-data/-private/system/clone-null"; /** @module ember-data diff --git a/addon/system/record-arrays/filtered-record-array.js b/addon/-private/system/record-arrays/filtered-record-array.js similarity index 95% rename from addon/system/record-arrays/filtered-record-array.js rename to addon/-private/system/record-arrays/filtered-record-array.js index bd1c21e2a22..87b5cffdccf 100644 --- a/addon/system/record-arrays/filtered-record-array.js +++ b/addon/-private/system/record-arrays/filtered-record-array.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import RecordArray from "ember-data/system/record-arrays/record-array"; +import RecordArray from "ember-data/-private/system/record-arrays/record-array"; /** @module ember-data diff --git a/addon/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js similarity index 96% rename from addon/system/record-arrays/record-array.js rename to addon/-private/system/record-arrays/record-array.js index 5a6b3324af6..bb84147d6a4 100644 --- a/addon/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -3,8 +3,8 @@ */ import Ember from 'ember'; -import { PromiseArray } from "ember-data/system/promise-proxies"; -import SnapshotRecordArray from "ember-data/system/snapshot-record-array"; +import { PromiseArray } from "ember-data/-private/system/promise-proxies"; +import SnapshotRecordArray from "ember-data/-private/system/snapshot-record-array"; var get = Ember.get; var set = Ember.set; diff --git a/addon/system/relationship-meta.js b/addon/-private/system/relationship-meta.js similarity index 85% rename from addon/system/relationship-meta.js rename to addon/-private/system/relationship-meta.js index 1451d380699..fcfeb19488e 100644 --- a/addon/system/relationship-meta.js +++ b/addon/-private/system/relationship-meta.js @@ -1,5 +1,5 @@ import {singularize} from 'ember-inflector'; -import normalizeModelName from 'ember-data/system/normalize-model-name'; +import normalizeModelName from 'ember-data/-private/system/normalize-model-name'; export function typeForRelationshipMeta(meta) { var modelName; diff --git a/addon/system/relationships.js b/addon/-private/system/relationships.js similarity index 75% rename from addon/system/relationships.js rename to addon/-private/system/relationships.js index 221339ec707..72c0124740f 100644 --- a/addon/system/relationships.js +++ b/addon/-private/system/relationships.js @@ -5,7 +5,7 @@ import belongsTo from "./relationships/belongs-to"; import hasMany from "./relationships/has-many"; -import "ember-data/system/relationships/ext"; +import "ember-data/-private/system/relationships/ext"; export { belongsTo, diff --git a/addon/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js similarity index 95% rename from addon/system/relationships/belongs-to.js rename to addon/-private/system/relationships/belongs-to.js index 28a905dd096..0b9292647f0 100644 --- a/addon/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -1,7 +1,7 @@ import Ember from 'ember'; -import { assert, warn } from "ember-data/debug"; -import Model from 'ember-data/system/model'; -import normalizeModelName from "ember-data/system/normalize-model-name"; +import { assert, warn } from "ember-data/-private/debug"; +import Model from 'ember-data/-private/system/model'; +import normalizeModelName from "ember-data/-private/system/normalize-model-name"; /** `DS.belongsTo` is used to define One-To-One and One-To-Many diff --git a/addon/system/relationships/ext.js b/addon/-private/system/relationships/ext.js similarity index 98% rename from addon/system/relationships/ext.js rename to addon/-private/system/relationships/ext.js index 45227c22ecc..87277e5aaeb 100644 --- a/addon/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -1,11 +1,11 @@ import Ember from 'ember'; -import { assert, warn } from "ember-data/debug"; +import { assert, warn } from "ember-data/-private/debug"; import { typeForRelationshipMeta, relationshipFromMeta -} from "ember-data/system/relationship-meta"; -import Model from "ember-data/system/model"; -import EmptyObject from "ember-data/system/empty-object"; +} from "ember-data/-private/system/relationship-meta"; +import Model from "ember-data/-private/system/model"; +import EmptyObject from "ember-data/-private/system/empty-object"; var get = Ember.get; var Map = Ember.Map; diff --git a/addon/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js similarity index 94% rename from addon/system/relationships/has-many.js rename to addon/-private/system/relationships/has-many.js index 42aa97520c0..763b070ff3a 100644 --- a/addon/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -3,10 +3,10 @@ */ import Ember from 'ember'; -import { assert } from "ember-data/debug"; -import Model from "ember-data/system/model"; -import normalizeModelName from "ember-data/system/normalize-model-name"; -import isArrayLike from "ember-data/system/is-array-like"; +import { assert } from "ember-data/-private/debug"; +import Model from "ember-data/-private/system/model"; +import normalizeModelName from "ember-data/-private/system/normalize-model-name"; +import isArrayLike from "ember-data/-private/system/is-array-like"; /** `DS.hasMany` is used to define One-To-Many and Many-To-Many diff --git a/addon/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js similarity index 95% rename from addon/system/relationships/state/belongs-to.js rename to addon/-private/system/relationships/state/belongs-to.js index a465be141e0..fc3638d1997 100644 --- a/addon/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -1,12 +1,12 @@ import Ember from 'ember'; -import { assert } from "ember-data/debug"; +import { assert } from "ember-data/-private/debug"; import { PromiseObject -} from "ember-data/system/promise-proxies"; +} from "ember-data/-private/system/promise-proxies"; -import { assertPolymorphicType } from "ember-data/utils"; +import { assertPolymorphicType } from "ember-data/-private/utils"; -import Relationship from "ember-data/system/relationships/state/relationship"; +import Relationship from "ember-data/-private/system/relationships/state/relationship"; export default function BelongsToRelationship(store, record, inverseKey, relationshipMeta) { this._super$constructor(store, record, inverseKey, relationshipMeta); diff --git a/addon/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js similarity index 81% rename from addon/system/relationships/state/create.js rename to addon/-private/system/relationships/state/create.js index ccfc81d86af..e3953347a6f 100644 --- a/addon/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -1,7 +1,7 @@ import Ember from 'ember'; -import ManyRelationship from "ember-data/system/relationships/state/has-many"; -import BelongsToRelationship from "ember-data/system/relationships/state/belongs-to"; -import EmptyObject from "ember-data/system/empty-object"; +import ManyRelationship from "ember-data/-private/system/relationships/state/has-many"; +import BelongsToRelationship from "ember-data/-private/system/relationships/state/belongs-to"; +import EmptyObject from "ember-data/-private/system/empty-object"; var get = Ember.get; diff --git a/addon/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js similarity index 94% rename from addon/system/relationships/state/has-many.js rename to addon/-private/system/relationships/state/has-many.js index ba343c90cbf..b9f8296e107 100644 --- a/addon/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -1,10 +1,10 @@ -import { assert } from "ember-data/debug"; -import { PromiseManyArray } from "ember-data/system/promise-proxies"; -import Relationship from "ember-data/system/relationships/state/relationship"; -import OrderedSet from "ember-data/system/ordered-set"; -import ManyArray from "ember-data/system/many-array"; +import { assert } from "ember-data/-private/debug"; +import { PromiseManyArray } from "ember-data/-private/system/promise-proxies"; +import Relationship from "ember-data/-private/system/relationships/state/relationship"; +import OrderedSet from "ember-data/-private/system/ordered-set"; +import ManyArray from "ember-data/-private/system/many-array"; -import { assertPolymorphicType } from "ember-data/utils"; +import { assertPolymorphicType } from "ember-data/-private/utils"; export default function ManyRelationship(store, record, inverseKey, relationshipMeta) { this._super$constructor(store, record, inverseKey, relationshipMeta); diff --git a/addon/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js similarity index 98% rename from addon/system/relationships/state/relationship.js rename to addon/-private/system/relationships/state/relationship.js index 768551b8bea..ce3f106bc71 100644 --- a/addon/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -1,6 +1,6 @@ import Ember from 'ember'; -import { assert, warn } from "ember-data/debug"; -import OrderedSet from "ember-data/system/ordered-set"; +import { assert, warn } from "ember-data/-private/debug"; +import OrderedSet from "ember-data/-private/system/ordered-set"; export default function Relationship(store, record, inverseKey, relationshipMeta) { var async = relationshipMeta.options.async; diff --git a/addon/system/serializer.js b/addon/-private/system/serializer.js similarity index 100% rename from addon/system/serializer.js rename to addon/-private/system/serializer.js diff --git a/addon/system/snapshot-record-array.js b/addon/-private/system/snapshot-record-array.js similarity index 100% rename from addon/system/snapshot-record-array.js rename to addon/-private/system/snapshot-record-array.js diff --git a/addon/system/snapshot.js b/addon/-private/system/snapshot.js similarity index 99% rename from addon/system/snapshot.js rename to addon/-private/system/snapshot.js index 72673043bab..c7f23c9e29f 100644 --- a/addon/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -3,7 +3,7 @@ */ import Ember from 'ember'; -import EmptyObject from "ember-data/system/empty-object"; +import EmptyObject from "ember-data/-private/system/empty-object"; var get = Ember.get; /** diff --git a/addon/system/store.js b/addon/-private/system/store.js similarity index 98% rename from addon/system/store.js rename to addon/-private/system/store.js index cca96bf7cfa..e09f41c8734 100644 --- a/addon/system/store.js +++ b/addon/-private/system/store.js @@ -6,32 +6,32 @@ */ import Ember from 'ember'; -import Model from 'ember-data/system/model'; -import { assert, warn } from "ember-data/debug"; -import _normalizeLink from "ember-data/system/normalize-link"; -import normalizeModelName from "ember-data/system/normalize-model-name"; +import Model from 'ember-data/-private/system/model'; +import { assert, warn } from "ember-data/-private/debug"; +import _normalizeLink from "ember-data/-private/system/normalize-link"; +import normalizeModelName from "ember-data/-private/system/normalize-model-name"; import { InvalidError -} from 'ember-data/adapters/errors'; +} from 'ember-data/-private/adapters/errors'; import { promiseArray, promiseObject -} from "ember-data/system/promise-proxies"; +} from "ember-data/-private/system/promise-proxies"; import { _bind, _guard, _objectIsAlive -} from "ember-data/system/store/common"; +} from "ember-data/-private/system/store/common"; import { normalizeResponseHelper -} from "ember-data/system/store/serializer-response"; +} from "ember-data/-private/system/store/serializer-response"; import { serializerForAdapter -} from "ember-data/system/store/serializers"; +} from "ember-data/-private/system/store/serializers"; import { _find, @@ -41,20 +41,20 @@ import { _findAll, _query, _queryRecord -} from "ember-data/system/store/finders"; +} from "ember-data/-private/system/store/finders"; import { getOwner -} from 'ember-data/utils'; +} from 'ember-data/-private/utils'; -import coerceId from "ember-data/system/coerce-id"; +import coerceId from "ember-data/-private/system/coerce-id"; -import RecordArrayManager from "ember-data/system/record-array-manager"; -import ContainerInstanceCache from 'ember-data/system/store/container-instance-cache'; +import RecordArrayManager from "ember-data/-private/system/record-array-manager"; +import ContainerInstanceCache from 'ember-data/-private/system/store/container-instance-cache'; -import InternalModel from "ember-data/system/model/internal-model"; +import InternalModel from "ember-data/-private/system/model/internal-model"; -import EmptyObject from "ember-data/system/empty-object"; +import EmptyObject from "ember-data/-private/system/empty-object"; export let badIdFormatAssertion = '`id` has to be non-empty string or number'; diff --git a/addon/system/store/common.js b/addon/-private/system/store/common.js similarity index 100% rename from addon/system/store/common.js rename to addon/-private/system/store/common.js diff --git a/addon/system/store/container-instance-cache.js b/addon/-private/system/store/container-instance-cache.js similarity index 97% rename from addon/system/store/container-instance-cache.js rename to addon/-private/system/store/container-instance-cache.js index c106dd661ed..8d36e808d1b 100644 --- a/addon/system/store/container-instance-cache.js +++ b/addon/-private/system/store/container-instance-cache.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import EmptyObject from "ember-data/system/empty-object"; +import EmptyObject from "ember-data/-private/system/empty-object"; /** * The `ContainerInstanceCache` serves as a lazy cache for looking up diff --git a/addon/system/store/finders.js b/addon/-private/system/store/finders.js similarity index 97% rename from addon/system/store/finders.js rename to addon/-private/system/store/finders.js index b08fa06bbba..e032ad83b83 100644 --- a/addon/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -1,18 +1,18 @@ import Ember from 'ember'; -import { assert } from "ember-data/debug"; +import { assert } from "ember-data/-private/debug"; import { _bind, _guard, _objectIsAlive -} from "ember-data/system/store/common"; +} from "ember-data/-private/system/store/common"; import { normalizeResponseHelper -} from "ember-data/system/store/serializer-response"; +} from "ember-data/-private/system/store/serializer-response"; import { serializerForAdapter -} from "ember-data/system/store/serializers"; +} from "ember-data/-private/system/store/serializers"; var Promise = Ember.RSVP.Promise; diff --git a/addon/system/store/serializer-response.js b/addon/-private/system/store/serializer-response.js similarity index 97% rename from addon/system/store/serializer-response.js rename to addon/-private/system/store/serializer-response.js index b51a5b8141d..ab05296b3c2 100644 --- a/addon/system/store/serializer-response.js +++ b/addon/-private/system/store/serializer-response.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert, runInDebug } from "ember-data/debug"; +import { assert, runInDebug } from "ember-data/-private/debug"; /* This is a helper method that validates a JSON API top-level document diff --git a/addon/system/store/serializers.js b/addon/-private/system/store/serializers.js similarity index 100% rename from addon/system/store/serializers.js rename to addon/-private/system/store/serializers.js diff --git a/addon/-private/transforms.js b/addon/-private/transforms.js new file mode 100644 index 00000000000..89d9ae392c6 --- /dev/null +++ b/addon/-private/transforms.js @@ -0,0 +1,13 @@ +import Transform from "ember-data/-private/transforms/base"; +import NumberTransform from "ember-data/-private/transforms/number"; +import DateTransform from "ember-data/-private/transforms/date"; +import StringTransform from "ember-data/-private/transforms/string"; +import BooleanTransform from "ember-data/-private/transforms/boolean"; + +export { + Transform, + NumberTransform, + DateTransform, + StringTransform, + BooleanTransform +}; diff --git a/addon/transforms/base.js b/addon/-private/transforms/base.js similarity index 100% rename from addon/transforms/base.js rename to addon/-private/transforms/base.js diff --git a/addon/transforms/boolean.js b/addon/-private/transforms/boolean.js similarity index 94% rename from addon/transforms/boolean.js rename to addon/-private/transforms/boolean.js index 05b81296cf8..4d027bc557f 100644 --- a/addon/transforms/boolean.js +++ b/addon/-private/transforms/boolean.js @@ -1,4 +1,4 @@ -import Transform from "ember-data/transforms/base"; +import Transform from "ember-data/-private/transforms/base"; /** The `DS.BooleanTransform` class is used to serialize and deserialize diff --git a/addon/transforms/date.js b/addon/-private/transforms/date.js similarity index 95% rename from addon/transforms/date.js rename to addon/-private/transforms/date.js index 434db18efe9..09ae5af818e 100644 --- a/addon/transforms/date.js +++ b/addon/-private/transforms/date.js @@ -20,7 +20,7 @@ import Ember from 'ember'; @extends DS.Transform @namespace DS */ -import Transform from "ember-data/transforms/base"; +import Transform from "ember-data/-private/transforms/base"; export default Transform.extend({ deserialize(serialized) { diff --git a/addon/transforms/number.js b/addon/-private/transforms/number.js similarity index 95% rename from addon/transforms/number.js rename to addon/-private/transforms/number.js index 1056842d410..7d81ec2ba32 100644 --- a/addon/transforms/number.js +++ b/addon/-private/transforms/number.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import Transform from "ember-data/transforms/base"; +import Transform from "ember-data/-private/transforms/base"; var empty = Ember.isEmpty; diff --git a/addon/transforms/string.js b/addon/-private/transforms/string.js similarity index 92% rename from addon/transforms/string.js rename to addon/-private/transforms/string.js index 50ef6c0b232..746f233feb5 100644 --- a/addon/transforms/string.js +++ b/addon/-private/transforms/string.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import Transform from "ember-data/transforms/base"; +import Transform from "ember-data/-private/transforms/base"; var none = Ember.isNone; diff --git a/addon/utils.js b/addon/-private/utils.js similarity index 98% rename from addon/utils.js rename to addon/-private/utils.js index d86ef898294..1ac7b254f71 100644 --- a/addon/utils.js +++ b/addon/-private/utils.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert } from "ember-data/debug"; +import { assert } from "ember-data/-private/debug"; const get = Ember.get; diff --git a/addon/adapters.js b/addon/adapters.js deleted file mode 100644 index 1f183d01049..00000000000 --- a/addon/adapters.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - @module ember-data -*/ - -import JSONAPIAdapter from "ember-data/adapters/json-api-adapter"; -import RESTAdapter from "ember-data/adapters/rest-adapter"; - -export { - JSONAPIAdapter, - RESTAdapter -}; diff --git a/addon/index.js b/addon/index.js index 60a62d2da1d..e922fd73867 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,5 +1,5 @@ import Ember from "ember"; -import { warn } from "ember-data/debug"; +import { warn } from "ember-data/-private/debug"; /** Ember Data @module ember-data @@ -18,31 +18,31 @@ if (Ember.VERSION.match(/^1\.13\./)) { }); } -import DS from "ember-data/core"; -import "ember-data/ext/date"; +import DS from "ember-data/-private/core"; +import "ember-data/-private/ext/date"; -import normalizeModelName from "ember-data/system/normalize-model-name"; +import normalizeModelName from "ember-data/-private/system/normalize-model-name"; -import InternalModel from "ember-data/system/model/internal-model"; +import InternalModel from "ember-data/-private/system/model/internal-model"; import { PromiseArray, PromiseObject, PromiseManyArray -} from "ember-data/system/promise-proxies"; +} from "ember-data/-private/system/promise-proxies"; import { Store -} from "ember-data/system/store"; +} from "ember-data/-private/system/store"; import { Errors, RootState, attr -} from "ember-data/system/model"; -import Model from "ember-data/system/model"; -import Snapshot from "ember-data/system/snapshot"; -import Adapter from "ember-data/system/adapter"; -import Serializer from "ember-data/system/serializer"; -import DebugAdapter from "ember-data/system/debug"; +} from "ember-data/-private/system/model"; +import Model from "ember-data/-private/system/model"; +import Snapshot from "ember-data/-private/system/snapshot"; +import Adapter from "ember-data/-private/system/adapter"; +import Serializer from "ember-data/-private/system/serializer"; +import DebugAdapter from "ember-data/-private/system/debug"; import { AdapterError, @@ -51,27 +51,27 @@ import { AbortError, errorsHashToArray, errorsArrayToHash -} from "ember-data/adapters/errors"; +} from "ember-data/-private/adapters/errors"; import { RecordArray, FilteredRecordArray, AdapterPopulatedRecordArray -} from "ember-data/system/record-arrays"; -import ManyArray from "ember-data/system/many-array"; -import RecordArrayManager from "ember-data/system/record-array-manager"; +} from "ember-data/-private/system/record-arrays"; +import ManyArray from "ember-data/-private/system/many-array"; +import RecordArrayManager from "ember-data/-private/system/record-array-manager"; import { JSONAPIAdapter, RESTAdapter -} from "ember-data/adapters"; -import BuildURLMixin from "ember-data/adapters/build-url-mixin"; +} from "ember-data/-private/adapters"; +import BuildURLMixin from "ember-data/-private/adapters/build-url-mixin"; import { JSONAPISerializer, JSONSerializer, RESTSerializer -} from "ember-data/serializers"; +} from "ember-data/-private/serializers"; import "ember-inflector"; -import EmbeddedRecordsMixin from "ember-data/serializers/embedded-records-mixin"; +import EmbeddedRecordsMixin from "ember-data/-private/serializers/embedded-records-mixin"; import { Transform, @@ -79,14 +79,14 @@ import { NumberTransform, StringTransform, BooleanTransform -} from "ember-data/transforms"; +} from "ember-data/-private/transforms"; -import {hasMany, belongsTo} from "ember-data/system/relationships"; -import "ember-data/ember-initializer"; -import setupContainer from "ember-data/setup-container"; +import {hasMany, belongsTo} from "ember-data/-private/system/relationships"; +import "ember-data/-private/ember-initializer"; +import setupContainer from "ember-data/-private/setup-container"; -import ContainerProxy from "ember-data/system/container-proxy"; -import Relationship from "ember-data/system/relationships/state/relationship"; +import ContainerProxy from "ember-data/-private/system/container-proxy"; +import Relationship from "ember-data/-private/system/relationships/state/relationship"; DS.Store = Store; DS.PromiseArray = PromiseArray; diff --git a/addon/serializers.js b/addon/serializers.js deleted file mode 100644 index f423d5300e8..00000000000 --- a/addon/serializers.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - @module ember-data -*/ - -import JSONAPISerializer from "ember-data/serializers/json-api-serializer"; -import JSONSerializer from "ember-data/serializers/json-serializer"; -import RESTSerializer from "ember-data/serializers/rest-serializer"; - -export { - JSONAPISerializer, - JSONSerializer, - RESTSerializer -}; diff --git a/addon/setup-container.js b/addon/setup-container.js deleted file mode 100644 index eb2f0e2c486..00000000000 --- a/addon/setup-container.js +++ /dev/null @@ -1,11 +0,0 @@ -import initializeStore from 'ember-data/initializers/store'; -import initializeTransforms from 'ember-data/initializers/transforms'; -import initializeStoreInjections from 'ember-data/initializers/store-injections'; -import initializeDataAdapter from 'ember-data/initializers/data-adapter'; - -export default function setupContainer(application) { - initializeDataAdapter(application); - initializeTransforms(application); - initializeStoreInjections(application); - initializeStore(application); -} diff --git a/addon/system/debug.js b/addon/system/debug.js deleted file mode 100644 index 6712f959b28..00000000000 --- a/addon/system/debug.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - @module ember-data -*/ - -import "ember-data/system/debug/debug-info"; -import DebugAdapter from "ember-data/system/debug/debug-adapter"; - -export default DebugAdapter; diff --git a/addon/system/model.js b/addon/system/model.js deleted file mode 100644 index bd5b37ba496..00000000000 --- a/addon/system/model.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - @module ember-data -*/ - -import Model from "ember-data/system/model/model"; -import attr from "ember-data/system/model/attributes"; -import RootState from "ember-data/system/model/states"; -import Errors from "ember-data/system/model/errors"; - -export { - RootState, - attr, - Errors -}; - -export default Model; diff --git a/addon/system/record-arrays.js b/addon/system/record-arrays.js deleted file mode 100644 index 7314524abd9..00000000000 --- a/addon/system/record-arrays.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - @module ember-data -*/ - -import RecordArray from "ember-data/system/record-arrays/record-array"; -import FilteredRecordArray from "ember-data/system/record-arrays/filtered-record-array"; -import AdapterPopulatedRecordArray from "ember-data/system/record-arrays/adapter-populated-record-array"; - -export { - RecordArray, - FilteredRecordArray, - AdapterPopulatedRecordArray -}; diff --git a/addon/transforms.js b/addon/transforms.js deleted file mode 100644 index 5bb2a521508..00000000000 --- a/addon/transforms.js +++ /dev/null @@ -1,13 +0,0 @@ -import Transform from "ember-data/transforms/base"; -import NumberTransform from "ember-data/transforms/number"; -import DateTransform from "ember-data/transforms/date"; -import StringTransform from "ember-data/transforms/string"; -import BooleanTransform from "ember-data/transforms/boolean"; - -export { - Transform, - NumberTransform, - DateTransform, - StringTransform, - BooleanTransform -}; From dee1ab72758f511817f54a5bbb4205d1723e5681 Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Sat, 12 Dec 2015 15:45:33 -0500 Subject: [PATCH 1268/2527] Rely on internalModel.createSnapshot to set adapterOptions `internalModel.createSnapshot` already sets the `adapterOptions` on the new snapshot the same way when `options` are provided. --- addon/-private/system/store.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index e09f41c8734..0b74380e0bd 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -524,8 +524,7 @@ Store = Service.extend({ } // Refetch the record if the adapter thinks the record is stale - var snapshot = internalModel.createSnapshot(); - snapshot.adapterOptions = options && options.adapterOptions; + var snapshot = internalModel.createSnapshot(options); var typeClass = internalModel.type; var adapter = this.adapterFor(typeClass.modelName); if (adapter.shouldReloadRecord(this, snapshot)) { From 7db174b3e6e8014b07e0d9fa257141bd32f6b783 Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Sat, 12 Dec 2015 22:28:12 -0500 Subject: [PATCH 1269/2527] Update adapter function references in test - Replaces references to `find` with `findRecord` - Replaces references to `create` with `createRecord` - Replaces references to `update` with `updateRecord` - Replaces references to `delete` with `deleteRecord` --- .../integration/adapter/rest-adapter-test.js | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index c4583c57add..0f6749259d5 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -50,10 +50,10 @@ function ajaxResponse(value) { }; } -test("find - basic payload", function(assert) { +test("findRecord - basic payload", function(assert) { ajaxResponse({ posts: [{ id: 1, name: "Rails is omakase" }] }); - run(store, 'find', 'post', 1).then(assert.wait(function(post) { + run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.equal(passedHash, undefined); @@ -80,7 +80,7 @@ test("findRecord - passes buildURL a requestType", function(assert) { test("find - basic payload (with legacy singular name)", function(assert) { ajaxResponse({ post: { id: 1, name: "Rails is omakase" } }); - run(store, 'find', 'post', 1).then(assert.wait(function(post) { + run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.equal(passedHash, undefined); @@ -90,7 +90,7 @@ test("find - basic payload (with legacy singular name)", function(assert) { })); }); -test("find - payload with sideloaded records of the same type", function(assert) { +test("findRecord - payload with sideloaded records of the same type", function(assert) { ajaxResponse({ posts: [ { id: 1, name: "Rails is omakase" }, @@ -98,7 +98,7 @@ test("find - payload with sideloaded records of the same type", function(assert) ] }); - run(store, 'find', 'post', 1).then(assert.wait(function(post) { + run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.equal(passedHash, undefined); @@ -112,13 +112,13 @@ test("find - payload with sideloaded records of the same type", function(assert) })); }); -test("find - payload with sideloaded records of a different type", function(assert) { +test("findRecord - payload with sideloaded records of a different type", function(assert) { ajaxResponse({ posts: [{ id: 1, name: "Rails is omakase" }], comments: [{ id: 1, name: "FIRST" }] }); - run(store, 'find', 'post', 1).then(assert.wait(function(post) { + run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.equal(passedHash, undefined); @@ -133,14 +133,14 @@ test("find - payload with sideloaded records of a different type", function(asse }); -test("find - payload with an serializer-specified primary key", function(assert) { +test("findRecord - payload with an serializer-specified primary key", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_' })); ajaxResponse({ posts: [{ "_ID_": 1, name: "Rails is omakase" }] }); - run(store, 'find', 'post', 1).then(assert.wait(function(post) { + run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.equal(passedHash, undefined); @@ -150,7 +150,7 @@ test("find - payload with an serializer-specified primary key", function(assert) })); }); -test("find - payload with a serializer-specified attribute mapping", function(assert) { +test("findRecord - payload with a serializer-specified attribute mapping", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ attrs: { 'name': '_NAME_', @@ -164,7 +164,7 @@ test("find - payload with a serializer-specified attribute mapping", function(as ajaxResponse({ posts: [{ id: 1, _NAME_: "Rails is omakase", _CREATED_AT_: 2013 }] }); - run(store, 'find', 'post', 1).then(assert.wait(function(post) { + run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.equal(passedHash, undefined); @@ -175,7 +175,7 @@ test("find - payload with a serializer-specified attribute mapping", function(as })); }); -test("create - an empty payload is a basic success if an id was specified", function(assert) { +test("createRecord - an empty payload is a basic success if an id was specified", function(assert) { ajaxResponse(); var post; @@ -192,7 +192,7 @@ test("create - an empty payload is a basic success if an id was specified", func }); }); -test("create - passes buildURL the requestType", function(assert) { +test("createRecord - passes buildURL the requestType", function(assert) { adapter.buildURL = function(type, id, snapshot, requestType) { return "/post/" + requestType; }; @@ -208,7 +208,7 @@ test("create - passes buildURL the requestType", function(assert) { }); }); -test("create - a payload with a new ID and data applies the updates", function(assert) { +test("createRecord - a payload with a new ID and data applies the updates", function(assert) { ajaxResponse({ posts: [{ id: "1", name: "Dat Parley Letter" }] }); run(function() { var post = store.createRecord('post', { name: "The Parley Letter" }); @@ -225,7 +225,7 @@ test("create - a payload with a new ID and data applies the updates", function(a }); }); -test("create - a payload with a new ID and data applies the updates (with legacy singular name)", function(assert) { +test("createRecord - a payload with a new ID and data applies the updates (with legacy singular name)", function(assert) { var post; ajaxResponse({ post: { id: "1", name: "Dat Parley Letter" } }); run(function() { @@ -243,7 +243,7 @@ test("create - a payload with a new ID and data applies the updates (with legacy })); }); -test("create - findMany doesn't overwrite owner", function(assert) { +test("createRecord - findMany doesn't overwrite owner", function(assert) { ajaxResponse({ comment: { id: "1", name: "Dat Parley Letter", post: 1 } }); var comment; @@ -284,7 +284,7 @@ test("create - findMany doesn't overwrite owner", function(assert) { }); }); -test("create - a serializer's primary key and attributes are consulted when building the payload", function(assert) { +test("createRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { var post; env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_id_', @@ -305,7 +305,7 @@ test("create - a serializer's primary key and attributes are consulted when buil })); }); -test("create - a serializer's attributes are consulted when building the payload if no id is pre-defined", function(assert) { +test("createRecord - a serializer's attributes are consulted when building the payload if no id is pre-defined", function(assert) { var post; env.registry.register('serializer:post', DS.RESTSerializer.extend({ primarykey: '_id_', @@ -326,7 +326,7 @@ test("create - a serializer's attributes are consulted when building the payload }); }); -test("create - a serializer's attribute mapping takes precdence over keyForAttribute when building the payload", function(assert) { +test("createRecord - a serializer's attribute mapping takes precdence over keyForAttribute when building the payload", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ attrs: { name: 'given_name' @@ -348,7 +348,7 @@ test("create - a serializer's attribute mapping takes precdence over keyForAttri }); }); -test("create - a serializer's attribute mapping takes precedence over keyForRelationship (belongsTo) when building the payload", function(assert) { +test("createRecord - a serializer's attribute mapping takes precedence over keyForRelationship (belongsTo) when building the payload", function(assert) { env.registry.register('serializer:comment', DS.RESTSerializer.extend({ attrs: { post: 'article' @@ -373,7 +373,7 @@ test("create - a serializer's attribute mapping takes precedence over keyForRela }); }); -test("create - a serializer's attribute mapping takes precedence over keyForRelationship (hasMany) when building the payload", function(assert) { +test("createRecord - a serializer's attribute mapping takes precedence over keyForRelationship (hasMany) when building the payload", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ attrs: { comments: 'opinions' @@ -398,7 +398,7 @@ test("create - a serializer's attribute mapping takes precedence over keyForRela }); }); -test("create - a record on the many side of a hasMany relationship should update relationships when data is sideloaded", function(assert) { +test("createRecord - a record on the many side of a hasMany relationship should update relationships when data is sideloaded", function(assert) { assert.expect(3); ajaxResponse({ @@ -478,7 +478,7 @@ test("create - a record on the many side of a hasMany relationship should update }); }); -test("create - sideloaded belongsTo relationships are both marked as loaded", function(assert) { +test("createRecord - sideloaded belongsTo relationships are both marked as loaded", function(assert) { assert.expect(4); var post; @@ -504,7 +504,7 @@ test("create - sideloaded belongsTo relationships are both marked as loaded", fu }); }); -test("create - response can contain relationships the client doesn't yet know about", function(assert) { +test("createRecord - response can contain relationships the client doesn't yet know about", function(assert) { assert.expect(3); // while records.length is 2, we are getting 4 assertions ajaxResponse({ @@ -541,7 +541,7 @@ test("create - response can contain relationships the client doesn't yet know ab }); }); -test("create - relationships are not duplicated", function(assert) { +test("createRecord - relationships are not duplicated", function(assert) { var post, comment; Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); @@ -570,7 +570,7 @@ test("create - relationships are not duplicated", function(assert) { })); }); -test("update - an empty payload is a basic success", function(assert) { +test("updateRecord - an empty payload is a basic success", function(assert) { run(function() { store.push({ data: { @@ -599,7 +599,7 @@ test("update - an empty payload is a basic success", function(assert) { }); }); -test("update - passes the requestType to buildURL", function(assert) { +test("updateRecord - passes the requestType to buildURL", function(assert) { adapter.buildURL = function(type, id, snapshot, requestType) { return "/posts/" + id + "/" + requestType; }; @@ -629,7 +629,7 @@ test("update - passes the requestType to buildURL", function(assert) { }); }); -test("update - a payload with updates applies the updates", function(assert) { +test("updateRecord - a payload with updates applies the updates", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.push({ @@ -658,7 +658,7 @@ test("update - a payload with updates applies the updates", function(assert) { })); }); -test("update - a payload with updates applies the updates (with legacy singular name)", function(assert) { +test("updateRecord - a payload with updates applies the updates (with legacy singular name)", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.push({ @@ -687,7 +687,7 @@ test("update - a payload with updates applies the updates (with legacy singular })); }); -test("update - a payload with sideloaded updates pushes the updates", function(assert) { +test("updateRecord - a payload with sideloaded updates pushes the updates", function(assert) { var post; ajaxResponse({ posts: [{ id: 1, name: "Dat Parley Letter" }], @@ -710,7 +710,7 @@ test("update - a payload with sideloaded updates pushes the updates", function(a }); }); -test("update - a payload with sideloaded updates pushes the updates", function(assert) { +test("updateRecord - a payload with sideloaded updates pushes the updates", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.push({ @@ -745,7 +745,7 @@ test("update - a payload with sideloaded updates pushes the updates", function(a })); }); -test("update - a serializer's primary key and attributes are consulted when building the payload", function(assert) { +test("updateRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_id_', @@ -774,7 +774,7 @@ test("update - a serializer's primary key and attributes are consulted when buil })); }); -test("update - hasMany relationships faithfully reflect simultaneous adds and removes", function(assert) { +test("updateRecord - hasMany relationships faithfully reflect simultaneous adds and removes", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); adapter.shouldBackgroundReloadRecord = () => false; @@ -832,7 +832,7 @@ test("update - hasMany relationships faithfully reflect simultaneous adds and re })); }); -test("delete - an empty payload is a basic success", function(assert) { +test("deleteRecord - an empty payload is a basic success", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.push({ @@ -861,7 +861,7 @@ test("delete - an empty payload is a basic success", function(assert) { })); }); -test("delete - passes the requestType to buildURL", function(assert) { +test("deleteRecord - passes the requestType to buildURL", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.buildURL = function(type, id, snapshot, requestType) { return "/posts/" + id + "/" + requestType; @@ -889,7 +889,7 @@ test("delete - passes the requestType to buildURL", function(assert) { })); }); -test("delete - a payload with sideloaded updates pushes the updates", function(assert) { +test("deleteRecord - a payload with sideloaded updates pushes the updates", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.push({ @@ -921,7 +921,7 @@ test("delete - a payload with sideloaded updates pushes the updates", function(a })); }); -test("delete - a payload with sidloaded updates pushes the updates when the original record is omitted", function(assert) { +test("deleteRecord - a payload with sidloaded updates pushes the updates when the original record is omitted", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(function() { store.push({ @@ -953,7 +953,7 @@ test("delete - a payload with sidloaded updates pushes the updates when the orig })); }); -test("delete - deleting a newly created record should not throw an error", function(assert) { +test("deleteRecord - deleting a newly created record should not throw an error", function(assert) { var post; run(function() { post = store.createRecord('post'); @@ -2413,7 +2413,7 @@ test('findAll resolves with a collection of DS.Models, not DS.InternalModels', ( }); -test("create - sideloaded records are pushed to the store", function(assert) { +test("createRecord - sideloaded records are pushed to the store", function(assert) { Post.reopen({ comments: DS.hasMany('comment') }); From 586050babc03c31c433f8deaad40b9550ea7a050 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Mon, 14 Dec 2015 08:32:02 -0500 Subject: [PATCH 1270/2527] Do not publish .gem files to npm --- .npmignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.npmignore b/.npmignore index 49996f5a391..c3a18d19b6e 100644 --- a/.npmignore +++ b/.npmignore @@ -12,3 +12,4 @@ dist/ bower.json Brocfile.js testem.json +*.gem From 0e355c09bcbd5bd19bba77c76ac86c9f7b3f8a90 Mon Sep 17 00:00:00 2001 From: Chad Hietala Date: Fri, 11 Dec 2015 14:56:32 -0800 Subject: [PATCH 1271/2527] [PERF] Don't use array methods We shouldn't use array methods as they allocate and close over items that need to be GC'd. Memory preasure can be an issue and we should do everything to reduce that preasure. --- .../serializers/embedded-records-mixin.js | 24 ++++--- .../serializers/json-api-serializer.js | 42 ++++++++++--- addon/-private/serializers/json-serializer.js | 18 ++++-- addon/-private/system/model/errors.js | 24 ++++--- addon/-private/system/model/internal-model.js | 10 +-- addon/-private/system/relationships/ext.js | 15 +++-- .../system/relationships/state/has-many.js | 22 ++++--- addon/-private/system/store.js | 62 +++++++++++++------ addon/-private/system/store/finders.js | 20 +++--- 9 files changed, 165 insertions(+), 72 deletions(-) diff --git a/addon/-private/serializers/embedded-records-mixin.js b/addon/-private/serializers/embedded-records-mixin.js index e7968bd13f6..579ba8331e4 100644 --- a/addon/-private/serializers/embedded-records-mixin.js +++ b/addon/-private/serializers/embedded-records-mixin.js @@ -348,11 +348,17 @@ export default Ember.Mixin.create({ */ _generateSerializedHasMany(snapshot, relationship) { let hasMany = snapshot.hasMany(relationship.key); - return Ember.A(hasMany).map((embeddedSnapshot) => { - var embeddedJson = embeddedSnapshot.record.serialize({ includeId: true }); + let manyArray = Ember.A(hasMany); + let ret = new Array(manyArray.length); + + for (let i = 0, l = manyArray.length; i < l; i++) { + let embeddedSnapshot = manyArray[i]; + let embeddedJson = embeddedSnapshot.record.serialize({ includeId: true }); this.removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, embeddedJson); - return embeddedJson; - }); + ret[i] = embeddedJson; + } + + return ret; }, /** @@ -450,11 +456,15 @@ export default Ember.Mixin.create({ */ _extractEmbeddedHasMany(store, key, hash, relationshipMeta) { let relationshipHash = get(hash, `data.relationships.${key}.data`); + if (!relationshipHash) { return; } - let hasMany = relationshipHash.map(item => { + let hasMany = new Array(relationshipHash.length); + + for (let i = 0, l = relationshipHash.length; i < l; i++) { + let item = relationshipHash[i]; let { data, included } = this._normalizeEmbeddedRelationship(store, relationshipMeta, item); hash.included = hash.included || []; hash.included.push(data); @@ -462,8 +472,8 @@ export default Ember.Mixin.create({ hash.included.push(...included); } - return { id: data.id, type: data.type }; - }); + hasMany[i] = { id: data.id, type: data.type }; + } let relationship = { data: hasMany }; set(hash, `data.relationships.${key}`, relationship); diff --git a/addon/-private/serializers/json-api-serializer.js b/addon/-private/serializers/json-api-serializer.js index 1bcb674753f..5f56a1c65bc 100644 --- a/addon/-private/serializers/json-api-serializer.js +++ b/addon/-private/serializers/json-api-serializer.js @@ -108,12 +108,26 @@ const JSONAPISerializer = JSONSerializer.extend({ if (Ember.typeOf(documentHash.data) === 'object') { documentHash.data = this._normalizeResourceHelper(documentHash.data); - } else if (Ember.typeOf(documentHash.data) === 'array') { - documentHash.data = documentHash.data.map(this._normalizeResourceHelper, this); + } else if (Array.isArray(documentHash.data)) { + let ret = new Array(documentHash.data.length); + + for (let i = 0, l = documentHash.data.length; i < l; i++) { + let data = documentHash.data[i]; + ret[i] = this._normalizeResourceHelper(data); + } + + documentHash.data = ret; } - if (Ember.typeOf(documentHash.included) === 'array') { - documentHash.included = documentHash.included.map(this._normalizeResourceHelper, this); + if (Array.isArray(documentHash.included)) { + let ret = new Array(documentHash.included.length); + + for (let i = 0, l = documentHash.included.length; i < l; i++) { + let included = documentHash.included[i]; + ret[i] = this._normalizeResourceHelper(included); + } + + documentHash.included = ret; } return documentHash; @@ -215,8 +229,15 @@ const JSONAPISerializer = JSONSerializer.extend({ relationshipHash.data = this._normalizeRelationshipDataHelper(relationshipHash.data); } - if (Ember.typeOf(relationshipHash.data) === 'array') { - relationshipHash.data = relationshipHash.data.map(this._normalizeRelationshipDataHelper, this); + if (Array.isArray(relationshipHash.data)) { + let ret = new Array(relationshipHash.data.length); + + for (let i = 0, l = relationshipHash.data.length; i < l; i++) { + let data = relationshipHash.data[i]; + ret[i] = this._normalizeRelationshipDataHelper(data); + } + + relationshipHash.data = ret; } return relationshipHash; @@ -456,12 +477,15 @@ const JSONAPISerializer = JSONSerializer.extend({ payloadKey = this.keyForRelationship(key, 'hasMany', 'serialize'); } - let data = hasMany.map((item) => { - return { + let data = new Array(hasMany.length); + + for (let i = 0, l = hasMany.length; i < l; i++) { + let item = hasMany[i]; + data[i] = { type: this.payloadKeyFromModelName(item.modelName), id: item.id }; - }); + } json.relationships[payloadKey] = { data }; } diff --git a/addon/-private/serializers/json-serializer.js b/addon/-private/serializers/json-serializer.js index af32f6a727f..b43aafb0dc9 100644 --- a/addon/-private/serializers/json-serializer.js +++ b/addon/-private/serializers/json-serializer.js @@ -453,13 +453,17 @@ export default Serializer.extend({ documentHash.included = included; } } else { - documentHash.data = payload.map((item) => { + let ret = new Array(payload.length); + for (let i = 0, l = payload.length; i < l; i++) { + let item = payload[i]; let { data, included } = this.normalize(primaryModelClass, item); if (included) { documentHash.included.push(...included); } - return data; - }); + ret[i] = data; + } + + documentHash.data = ret; } return documentHash; @@ -644,7 +648,13 @@ export default Serializer.extend({ data = this.extractRelationship(relationshipMeta.type, relationshipHash); } } else if (relationshipMeta.kind === 'hasMany') { - data = Ember.isNone(relationshipHash) ? null : relationshipHash.map((item) => this.extractRelationship(relationshipMeta.type, item)); + if (!Ember.isNone(relationshipHash)) { + data = new Array(relationshipHash.length); + for (let i = 0, l = relationshipHash.length; i < l; i++) { + let item = relationshipHash[i]; + data[i] = this.extractRelationship(relationshipMeta.type, item); + } + } } relationship = { data }; } diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index 09c87ed628e..aba080301d0 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -272,14 +272,24 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @private */ _findOrCreateMessages(attribute, messages) { - var errors = this.errorsFor(attribute); + let errors = this.errorsFor(attribute); + let messagesArray = makeArray(messages); + let _messages = new Array(messagesArray.length); + + for (let i = 0, l = messagesArray.length; i < l; i++) { + let message = messagesArray[i]; + let err = errors.findBy('message', message); + if (err) { + _messages[i] = err; + } else { + _messages[i] = { + attribute: attribute, + message: message + }; + } + } - return makeArray(messages).map((message) => { - return errors.findBy('message', message) || { - attribute: attribute, - message: message - }; - }); + return _messages; }, /** diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index b28b2937a80..23f1f5f5ce3 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -566,11 +566,13 @@ InternalModel.prototype = { _preloadHasMany(key, preloadValue, type) { assert("You need to pass in an array to set a hasMany property on a record", Ember.isArray(preloadValue)); - var internalModel = this; + let recordsToSet = new Array(preloadValue.length); + + for (let i = 0, l = preloadValue.length; i < l; i++) { + let recordToPush = preloadValue[i]; + recordsToSet[i] = this._convertStringOrNumberIntoInternalModel(recordToPush, type); + } - var recordsToSet = preloadValue.map((recordToPush) => { - return internalModel._convertStringOrNumberIntoInternalModel(recordToPush, type); - }); //We use the pathway of setting the hasMany as if it came from the adapter //because the user told us that they know this relationships exists already this._relationships.get(key).updateRecordsFromAdapter(recordsToSet); diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 87277e5aaeb..1d2775e41e1 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -569,16 +569,19 @@ Model.reopenClass({ @param {any} binding the value to which the callback's `this` should be bound */ eachRelatedType(callback, binding) { - get(this, 'relatedTypes').forEach((type) => { + let relationshipTypes = get(this, 'relatedTypes'); + + for (let i = 0; i < relationshipTypes.length; i++) { + let type = relationshipTypes[i]; callback.call(binding, type); - }); + } }, determineRelationshipType(knownSide, store) { - var knownKey = knownSide.key; - var knownKind = knownSide.kind; - var inverse = this.inverseFor(knownKey, store); - var key, otherKind; + let knownKey = knownSide.key; + let knownKind = knownSide.kind; + let inverse = this.inverseFor(knownKey, store); + let key, otherKind; if (!inverse) { return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone'; diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index b9f8296e107..ca8bde09911 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -166,15 +166,21 @@ ManyRelationship.prototype.fetchLink = function() { }; ManyRelationship.prototype.findRecords = function() { + let manyArray = this.manyArray.toArray(); + let internalModels = new Array(manyArray.length); + + for (let i = 0, l = manyArray.length; i < l; i++) { + internalModels[i] = manyArray[i]._internalModel; + } + //TODO CLEANUP - return this.store.findMany(this.manyArray.toArray().map((rec) => rec._internalModel)). - then(() => { - if (!this.manyArray.get('isDestroyed')) { - //Goes away after the manyArray refactor - this.manyArray.set('isLoaded', true); - } - return this.manyArray; - }); + return this.store.findMany(internalModels).then(() => { + if (!this.manyArray.get('isDestroyed')) { + //Goes away after the manyArray refactor + this.manyArray.set('isLoaded', true); + } + return this.manyArray; + }); }; ManyRelationship.prototype.notifyHasManyChanged = function() { this.record.notifyHasManyAdded(this.key); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index e09f41c8734..15b1c9a8d24 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -578,11 +578,13 @@ Store = Service.extend({ */ findByIds(modelName, ids) { assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - var store = this; + let promises = new Array(ids.length); + + for (let i = 0, l = ids.length; i < l; i++) { + promises[i] = this.findRecord(modelName, ids[i]); + } - return promiseArray(Ember.RSVP.all(ids.map((id) => { - return store.findRecord(modelName, id); - })).then(Ember.A, null, "DS: Store#findByIds of " + modelName + " complete")); + return promiseArray(Ember.RSVP.all(promises).then(Ember.A, null, "DS: Store#findByIds of " + modelName + " complete")); }, /** @@ -609,8 +611,17 @@ Store = Service.extend({ }, scheduleFetchMany(records) { - var internalModels = records.map((record) => record._internalModel); - return Promise.all(internalModels.map(this.scheduleFetch, this)); + let internalModels = new Array(records.length); + let fetches = new Array(records.length); + for (let i = 0, l = records.length; i < l; i++) { + internalModels[i] = records[i]._internalModel; + } + + for (let i = 0, l = internalModels.length; i < l; i++) { + fetches[i] = this.scheduleFetch(internalModels[i]); + } + + return Ember.RSVP.Promise.all(fetches); }, scheduleFetch(internalModel, options) { @@ -841,7 +852,13 @@ Store = Service.extend({ @return {Promise} promise */ findMany(internalModels) { - return Promise.all(internalModels.map((internalModel) => this._findByInternalModel(internalModel))); + let finds = new Array(internalModels.length); + + for (let i = 0, l = internalModels.length; i < l; i++) { + finds[i] = this._findByInternalModel(internalModels[i]); + } + + return Promise.all(finds); }, @@ -1098,19 +1115,22 @@ Store = Service.extend({ unloadAll(modelName) { assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), !modelName || typeof modelName === 'string'); if (arguments.length === 0) { - var typeMaps = this.typeMaps; - var keys = Object.keys(typeMaps); + let typeMaps = this.typeMaps; + let keys = Object.keys(typeMaps); + let types = new Array(keys.length); - var types = keys.map(byType); + for (let i = 0, l = keys.length; i < l; i++) { + types[i] = typeMaps[keys[i]]['type'].modelName; + } types.forEach(this.unloadAll, this); } else { - var typeClass = this.modelFor(modelName); - var typeMap = this.typeMapFor(typeClass); - var records = typeMap.records.slice(); - var record; + let typeClass = this.modelFor(modelName); + let typeMap = this.typeMapFor(typeClass); + let records = typeMap.records.slice(); + let record; - for (var i = 0; i < records.length; i++) { + for (let i = 0; i < records.length; i++) { record = records[i]; record.unloadRecord(); record.destroy(); // maybe within unloadRecord @@ -1118,10 +1138,6 @@ Store = Service.extend({ typeMap.metadata = new EmptyObject(); } - - function byType(entry) { - return typeMaps[entry]['type'].modelName; - } }, /** @@ -2055,7 +2071,13 @@ function deserializeRecordIds(store, key, relationship, ids) { } assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being '${Ember.inspect(ids)}', but ${key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, isArray(ids)); - return ids.map((id) => deserializeRecordId(store, key, relationship, id)); + let _ids = new Array(ids.length); + + for (let i = 0, l = ids.length; i < l; i++) { + _ids[i] = deserializeRecordId(store, key, relationship, ids[i]); + } + + return _ids; } // Delegation to the adapter and promise management diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index e032ad83b83..6962cb1f63f 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -54,10 +54,10 @@ export function _find(adapter, store, typeClass, id, internalModel, options) { export function _findMany(adapter, store, typeClass, ids, internalModels) { - var snapshots = Ember.A(internalModels).invoke('createSnapshot'); - var promise = adapter.findMany(store, typeClass, ids, snapshots); - var serializer = serializerForAdapter(store, adapter, typeClass.modelName); - var label = "DS: Handle Adapter#findMany of " + typeClass; + let snapshots = Ember.A(internalModels).invoke('createSnapshot'); + let promise = adapter.findMany(store, typeClass, ids, snapshots); + let serializer = serializerForAdapter(store, adapter, typeClass.modelName); + let label = "DS: Handle Adapter#findMany of " + typeClass; if (promise === undefined) { throw new Error('adapter.findMany returned undefined, this was very likely a mistake'); @@ -69,10 +69,16 @@ export function _findMany(adapter, store, typeClass, ids, internalModels) { return promise.then(function(adapterPayload) { assert("You made a `findMany` request for a " + typeClass.typeClassKey + " with ids " + ids + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { - var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findMany'); + let payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findMany'); //TODO Optimize, no need to materialize here - var records = store.push(payload); - return records.map((record) => record._internalModel); + let records = store.push(payload); + let internalModels = new Array(records.length); + + for (let i = 0, l = records.length; i < l; i++) { + internalModels[i] = records[i]._internalModel; + } + + return internalModels; }); }, null, "DS: Extract payload of " + typeClass); } From e132fe16b60088df4c041acb76d95afc65cc4f49 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 14 Dec 2015 14:20:42 -0500 Subject: [PATCH 1272/2527] [BUGFIX beta] Implement public module API. This replaces the public module API from ember-cli-shims. --- addon/adapter.js | 1 + addon/adapters/json-api.js | 1 + addon/adapters/rest.js | 1 + addon/attr.js | 1 + addon/model.js | 1 + addon/relationships.js | 1 + addon/serializers/json-api.js | 1 + addon/serializers/json.js | 1 + addon/serializers/rest.js | 1 + addon/store.js | 1 + addon/transform.js | 1 + 11 files changed, 11 insertions(+) create mode 100644 addon/adapter.js create mode 100644 addon/adapters/json-api.js create mode 100644 addon/adapters/rest.js create mode 100644 addon/attr.js create mode 100644 addon/model.js create mode 100644 addon/relationships.js create mode 100644 addon/serializers/json-api.js create mode 100644 addon/serializers/json.js create mode 100644 addon/serializers/rest.js create mode 100644 addon/store.js create mode 100644 addon/transform.js diff --git a/addon/adapter.js b/addon/adapter.js new file mode 100644 index 00000000000..7eebb9ff9f7 --- /dev/null +++ b/addon/adapter.js @@ -0,0 +1 @@ +export { default } from "ember-data/-private/system/adapter"; diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js new file mode 100644 index 00000000000..da06897728e --- /dev/null +++ b/addon/adapters/json-api.js @@ -0,0 +1 @@ +export { default } from "ember-data/-private/adapters/json-api-adapter"; diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js new file mode 100644 index 00000000000..add0345f012 --- /dev/null +++ b/addon/adapters/rest.js @@ -0,0 +1 @@ +export { default } from "ember-data/-private/adapters/rest-adapter"; diff --git a/addon/attr.js b/addon/attr.js new file mode 100644 index 00000000000..803920b23cf --- /dev/null +++ b/addon/attr.js @@ -0,0 +1 @@ +export { default } from "ember-data/-private/system/model/attributes"; diff --git a/addon/model.js b/addon/model.js new file mode 100644 index 00000000000..837dc55c6a0 --- /dev/null +++ b/addon/model.js @@ -0,0 +1 @@ +export { default } from "ember-data/-private/system/model"; diff --git a/addon/relationships.js b/addon/relationships.js new file mode 100644 index 00000000000..2d67cbb92c9 --- /dev/null +++ b/addon/relationships.js @@ -0,0 +1 @@ +export * from 'ember-data/-private/system/relationships'; diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js new file mode 100644 index 00000000000..8173a37dd53 --- /dev/null +++ b/addon/serializers/json-api.js @@ -0,0 +1 @@ +export { default } from "ember-data/-private/serializers/json-api-serializer"; diff --git a/addon/serializers/json.js b/addon/serializers/json.js new file mode 100644 index 00000000000..39a167ec9a2 --- /dev/null +++ b/addon/serializers/json.js @@ -0,0 +1 @@ +export { default } from "ember-data/-private/serializers/json-serializer"; diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js new file mode 100644 index 00000000000..3815008bb4c --- /dev/null +++ b/addon/serializers/rest.js @@ -0,0 +1 @@ +export { default } from "ember-data/-private/serializers/rest-serializer"; diff --git a/addon/store.js b/addon/store.js new file mode 100644 index 00000000000..011380454f5 --- /dev/null +++ b/addon/store.js @@ -0,0 +1 @@ +export { default } from "ember-data/-private/system/store"; diff --git a/addon/transform.js b/addon/transform.js new file mode 100644 index 00000000000..ac58081c856 --- /dev/null +++ b/addon/transform.js @@ -0,0 +1 @@ +export { default } from "ember-data/-private/transforms/base"; From 6b630c1eb41492ffe25b0f297ca5514fe4c02f68 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 14 Dec 2015 14:51:50 -0500 Subject: [PATCH 1273/2527] [BUGFIX beta] Ensure shims are included automatically in globals builds. --- lib/ember-data-shims.js | 36 ++++++++++++++++++++++++++++++++++++ lib/javascripts.js | 5 ++++- 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 lib/ember-data-shims.js diff --git a/lib/ember-data-shims.js b/lib/ember-data-shims.js new file mode 100644 index 00000000000..50ddf3e47ac --- /dev/null +++ b/lib/ember-data-shims.js @@ -0,0 +1,36 @@ +;(function() { + function processEmberDataShims() { + var shims = { + 'ember-data': { default: DS }, + 'ember-data/model': { default: DS.Model }, + 'ember-data/serializers/rest': { default: DS.RESTSerializer }, + 'ember-data/serializers/active-model': { default: DS.ActiveModelSerializer }, + 'ember-data/serializers/json': { default: DS.JSONSerializer }, + 'ember-data/serializers/json-api': { default: DS.JSONAPISerializer }, + 'ember-data/adapters/json-api': { default: DS.JSONAPIAdapter }, + 'ember-data/adapters/rest': { default: DS.RESTAdapter }, + 'ember-data/adapter': { default: DS.Adapter }, + 'ember-data/adapters/active-model': { default: DS.ActiveModelAdapter }, + 'ember-data/store': { default: DS.Store }, + 'ember-data/transform': { default: DS.Transform }, + 'ember-data/attr': { default: DS.attr }, + 'ember-data/relationships': { hasMany: DS.hasMany, belongsTo: DS.belongsTo } + }; + + for (var moduleName in shims) { + generateModule(moduleName, shims[moduleName]); + } + } + + function generateModule(name, values) { + define(name, [], function() { + 'use strict'; + + return values; + }); + } + + if (typeof define !== 'undefined' && define && define.petal) { + processEmberDataShims(); + } +})(); diff --git a/lib/javascripts.js b/lib/javascripts.js index 60eddc17dcb..5ea125386f0 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -105,12 +105,15 @@ function collapse(tree, outputFileName) { var license = new Funnel(generatorDir, {include: ['license.js']}); license = versionReplace(license); + var emberDataShimsPath = path.join(__dirname, 'ember-data-shims.js'); + var emberDataShims = fs.readFileSync(emberDataShimsPath, { encoding: 'utf8' }); + var withLoader = merge([tree, loader, license, emberShim]); return concat(withLoader, { inputFiles: ['license.js', 'loader.js', '**/*.js'], outputFile: '/' + outputFileName, header: '(function(){ \n"use strict";\n', - footer: '\nrequire("ember-data");\n})();\n' + footer: '\nrequire("ember-data");\n})();\n' + emberDataShims }); } From ec8e22ae879cea885f9dd89f8216e1f5c991859d Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 14 Dec 2015 15:03:54 -0500 Subject: [PATCH 1274/2527] [BUGFIX beta] Remove old addon + blueprint. --- .../blueprints/ember-data/index.js | 15 --------- lib/ember-addon/index.js | 31 ------------------- 2 files changed, 46 deletions(-) delete mode 100644 lib/ember-addon/blueprints/ember-data/index.js delete mode 100644 lib/ember-addon/index.js diff --git a/lib/ember-addon/blueprints/ember-data/index.js b/lib/ember-addon/blueprints/ember-data/index.js deleted file mode 100644 index 0de95eb439c..00000000000 --- a/lib/ember-addon/blueprints/ember-data/index.js +++ /dev/null @@ -1,15 +0,0 @@ -/* jshint node: true */ -'use strict'; - -module.exports = { - normalizeEntityName: function() { - // this prevents an error when the entityName is - // not specified (since that doesn't actually matter - // to us - }, - - afterInstall: function() { - var json = require('../../../../package.json'); - return this.addBowerPackageToProject('ember-data', json.version); - } -}; diff --git a/lib/ember-addon/index.js b/lib/ember-addon/index.js deleted file mode 100644 index 8aa40289352..00000000000 --- a/lib/ember-addon/index.js +++ /dev/null @@ -1,31 +0,0 @@ -/* jshint node: true */ -'use strict'; - -var path = require('path'); - -module.exports = { - name: 'ember-data', - blueprintsPath: function() { - return path.join(__dirname, 'blueprints'); - }, - included: function(app) { - this._super.included(app); - - var options = { - exports: { - 'ember-data': [ - 'default' - ] - } - }; - - this.app.import({ - development: app.bowerDirectory + '/ember-data/ember-data.js', - production: app.bowerDirectory + '/ember-data/ember-data.prod.js' - }, options); - // Source maps - this.app.import({ - development: app.bowerDirectory + '/ember-data/ember-data.js.map' - }, {destDir: 'assets'}); - } -}; From 446d65f7ebbb6b34a3dc50c24a5d992889d581a1 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 14 Dec 2015 15:39:37 -0500 Subject: [PATCH 1275/2527] [BUGFIX beta] Use `bower` version of ember-data if present. In order to keep backwards compat, we must honor the version of ember-data that is present in `bower.json` (even though it is not needed). This is due to the fact that many people update the `package.json` and `bower.json` versions of Ember Data completely independently. If `bower.json` includes `ember-data` a warning will be issued, and that version will be used. --- index.js | 40 ++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 38deac39edc..baae5a6815e 100644 --- a/index.js +++ b/index.js @@ -4,10 +4,50 @@ module.exports = { name: 'ember-data', + _warn: function(message) { + var chalk = require('chalk'); + var warning = chalk.yellow('WARNING: ' + message); + + if (this.ui && this.ui.writeWarnLine) { + this.ui.writeWarnLine(message); + } else if (this.ui) { + this.ui.writeLine(warning); + } else { + console.log(warning); + } + }, + + init: function() { + var bowerDeps = this.project.bowerDependencies(); + + if (bowerDeps['ember-data']) { + this._warn('Please remove `ember-data` from `bower.json`. As of Ember Data 2.3.0, only the NPM package is needed.'); + this._forceBowerUsage = true; + } else { + this._forceBowerUsage = false; + } + }, + treeForAddon: function(dir) { + if (this._forceBowerUsage) { + // Fakes an empty broccoli tree + return { inputTree: dir, rebuild: function() { return []; } }; + } + var version = require('./lib/version'); var merge = require('broccoli-merge-trees'); return this._super.treeForAddon.call(this, merge([version(), dir])); + }, + + included: function(app) { + this._super.included.apply(this, arguments); + + if (this._forceBowerUsage) { + this.app.import({ + development: app.bowerDirectory + '/ember-data/ember-data.js', + production: app.bowerDirectory + '/ember-data/ember-data.prod.js' + }); + } } }; diff --git a/package.json b/package.json index f41d413d282..c82c3073dd1 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "bower": "bower install", "production": "ember build --environment=production" }, - "repository": "", "engines": { "node": ">= 0.10.0" }, @@ -24,6 +23,7 @@ "dependencies": { "broccoli-file-creator": "^1.0.0", "broccoli-merge-trees": "^1.0.0", + "chalk": "^1.1.1", "ember-cli-babel": "^5.1.3" }, "devDependencies": { From 120aa16e6189919976ba27c6ef531414248a6362 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 14 Dec 2015 16:13:44 -0500 Subject: [PATCH 1276/2527] Do not ENABLE_OPTIONAL_FEATURES in consuming applications. `config/environment.js` is used by ember-cli to allow the addon to provide default configuration to the consuming app. In this case, the configuration here is for the addon's internal development so it belongs in `tests/dummy/config/environment.js` instead. --- config/environment.js | 24 ------------------------ tests/dummy/config/environment.js | 18 ++++++++++++++---- 2 files changed, 14 insertions(+), 28 deletions(-) delete mode 100644 config/environment.js diff --git a/config/environment.js b/config/environment.js deleted file mode 100644 index c7058a3411c..00000000000 --- a/config/environment.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -var fs = require('fs'); -var featuresJson = fs.readFileSync('config/features.json', { encoding: 'utf8' }); -var featureFlags = JSON.parse(featuresJson); - -module.exports = function(environment, appConfig) { - var ENV = { }; - - ENV.EmberENV = { - FEATURES: featureFlags, - ENABLE_DS_FILTER: true, - - // don't raise on deprecation yet, since there are too many thrown errors; - // this should be addressed in another PR - // RAISE_ON_DEPRECATION: true - }; - - if (environment === 'test-optional-features') { - ENV.EmberENV.ENABLE_OPTIONAL_FEATURES = true; - } - - return ENV; -}; diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index c59bcd538ea..f367c52449c 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -1,5 +1,9 @@ /* jshint node: true */ +var fs = require('fs'); +var featuresJson = fs.readFileSync('config/features.json', { encoding: 'utf8' }); +var featureFlags = JSON.parse(featuresJson); + module.exports = function(environment) { var ENV = { modulePrefix: 'dummy', @@ -7,10 +11,12 @@ module.exports = function(environment) { baseURL: '/', locationType: 'auto', EmberENV: { - FEATURES: { - // Here you can enable experimental features on an ember canary build - // e.g. 'with-controller': true - } + FEATURES: featureFlags, + ENABLE_DS_FILTER: true, + + // don't raise on deprecation yet, since there are too many thrown errors; + // this should be addressed in another PR + // RAISE_ON_DEPRECATION: true }, APP: { @@ -19,6 +25,10 @@ module.exports = function(environment) { } }; + if (environment === 'test-optional-features') { + ENV.EmberENV.ENABLE_OPTIONAL_FEATURES = true; + } + if (environment === 'development') { // ENV.APP.LOG_RESOLVER = true; // ENV.APP.LOG_ACTIVE_GENERATION = true; From 8cd375ee9fec16d7a2d190d9815f22b9e05ac0bc Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 14 Dec 2015 16:29:51 -0500 Subject: [PATCH 1277/2527] [BUGFIX beta] Provide helpful warning for using older ember-cli-shims. When using ember-cli-shims prior to 0.1.0, the `ember-data` module that we provide in this addon is overridden by the one provided by the shims repo. This warning should help folks understand what to do *before* they notice an issue. --- index.js | 9 +++++++++ package.json | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index baae5a6815e..03ae7ec4ea8 100644 --- a/index.js +++ b/index.js @@ -26,6 +26,15 @@ module.exports = { } else { this._forceBowerUsage = false; } + + var VersionChecker = require('ember-cli-version-checker'); + + var checker = new VersionChecker(this); + var dep = checker.for('ember-cli-shims', 'bower'); + + if (!dep.satisfies('>= 0.1.0')) { + this._warn('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3+. Please update ember-cli-shims from ' + dep.version + ' to 0.1.0.'); + } }, treeForAddon: function(dir) { diff --git a/package.json b/package.json index c82c3073dd1..935d77278d7 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "broccoli-file-creator": "^1.0.0", "broccoli-merge-trees": "^1.0.0", "chalk": "^1.1.1", - "ember-cli-babel": "^5.1.3" + "ember-cli-babel": "^5.1.3", + "ember-cli-version-checker": "^1.1.4" }, "devDependencies": { "babel-plugin-feature-flags": "^0.2.0", From c14cda3e04de231c4595374b607a6923415ac20e Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Mon, 14 Dec 2015 18:06:35 -0500 Subject: [PATCH 1278/2527] Update ember-cli-shims to 0.1.0 to silence ED's own warning --- bower.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index 51a24b4e479..d39308fd45c 100644 --- a/bower.json +++ b/bower.json @@ -2,7 +2,7 @@ "name": "ember-data", "dependencies": { "ember": "components/ember#release", - "ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3", + "ember-cli-shims": "ember-cli/ember-cli-shims#0.1.0", "ember-cli-test-loader": "ember-cli-test-loader#0.1.3", "ember-load-initializers": "ember-cli/ember-load-initializers#0.1.5", "ember-qunit": "0.4.9", @@ -15,4 +15,4 @@ "resolutions": { "ember": "release" } -} \ No newline at end of file +} From 58bf36676b3a1e83ad4e12533b2740335b58fc2d Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 2 Oct 2015 10:38:05 -0700 Subject: [PATCH 1279/2527] ember-data should provide its blueprints --- .../files/tests/unit/__path__/__test__.js | 12 +++ blueprints/model-test/index.js | 16 ++++ blueprints/model/HELP.md | 25 ++++++ .../model/files/__root__/__path__/__name__.js | 5 ++ blueprints/model/index.js | 77 +++++++++++++++++++ .../files/tests/unit/__path__/__test__.js | 15 ++++ blueprints/serializer-test/index.js | 12 +++ .../files/__root__/__path__/__name__.js | 4 + blueprints/serializer/index.js | 5 ++ .../files/tests/unit/__path__/__test__.js | 12 +++ blueprints/transform-test/index.js | 12 +++ .../files/__root__/__path__/__name__.js | 11 +++ blueprints/transform/index.js | 5 ++ index.js | 6 ++ shims/shims.js | 35 +++++++++ 15 files changed, 252 insertions(+) create mode 100644 blueprints/model-test/files/tests/unit/__path__/__test__.js create mode 100644 blueprints/model-test/index.js create mode 100644 blueprints/model/HELP.md create mode 100644 blueprints/model/files/__root__/__path__/__name__.js create mode 100644 blueprints/model/index.js create mode 100644 blueprints/serializer-test/files/tests/unit/__path__/__test__.js create mode 100644 blueprints/serializer-test/index.js create mode 100644 blueprints/serializer/files/__root__/__path__/__name__.js create mode 100644 blueprints/serializer/index.js create mode 100644 blueprints/transform-test/files/tests/unit/__path__/__test__.js create mode 100644 blueprints/transform-test/index.js create mode 100644 blueprints/transform/files/__root__/__path__/__name__.js create mode 100644 blueprints/transform/index.js create mode 100644 shims/shims.js diff --git a/blueprints/model-test/files/tests/unit/__path__/__test__.js b/blueprints/model-test/files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..88003fc2be8 --- /dev/null +++ b/blueprints/model-test/files/tests/unit/__path__/__test__.js @@ -0,0 +1,12 @@ +import { moduleForModel, test } from 'ember-qunit'; + +moduleForModel('<%= dasherizedModuleName %>', '<%= friendlyDescription %>', { + // Specify the other units that are required for this test. +<%= typeof needs !== 'undefined' ? needs : '' %> +}); + +test('it exists', function(assert) { + var model = this.subject(); + // var store = this.store(); + assert.ok(!!model); +}); diff --git a/blueprints/model-test/index.js b/blueprints/model-test/index.js new file mode 100644 index 00000000000..d85bd57e38b --- /dev/null +++ b/blueprints/model-test/index.js @@ -0,0 +1,16 @@ +/*jshint node:true*/ + +var ModelBlueprint = require('../model'); +var testInfo = require('ember-cli-test-info'); + +module.exports = { + description: 'Generates a model unit test.', + + locals: function(options) { + var result = ModelBlueprint.locals.apply(this, arguments); + + result.friendlyDescription = testInfo.description(options.entity.name, "Unit", "Model"); + + return result; + } +}; diff --git a/blueprints/model/HELP.md b/blueprints/model/HELP.md new file mode 100644 index 00000000000..78bd0af7d43 --- /dev/null +++ b/blueprints/model/HELP.md @@ -0,0 +1,25 @@ +You may generate models with as many attrs as you would like to pass. The following attribute types are supported: + + :array + :boolean + :date + :object + :number + :string + :your-custom-transform + :belongs-to: + :has-many: + +For instance: \`ember generate model taco filling:belongs-to:protein toppings:has-many:toppings name:string price:number misc\` +would result in the following model: + +```js +import DS from 'ember-data'; +export default DS.Model.extend({ + filling: DS.belongsTo('protein'), + toppings: DS.hasMany('topping'), + name: DS.attr('string'), + price: DS.attr('number'), + misc: DS.attr() +}); +``` diff --git a/blueprints/model/files/__root__/__path__/__name__.js b/blueprints/model/files/__root__/__path__/__name__.js new file mode 100644 index 00000000000..c1b8b8fac45 --- /dev/null +++ b/blueprints/model/files/__root__/__path__/__name__.js @@ -0,0 +1,5 @@ +import DS from 'ember-data'; + +export default DS.Model.extend({ + <%= attrs %> +}); diff --git a/blueprints/model/index.js b/blueprints/model/index.js new file mode 100644 index 00000000000..5acd699db5a --- /dev/null +++ b/blueprints/model/index.js @@ -0,0 +1,77 @@ +/*jshint node:true*/ + +var inflection = require('inflection'); +var stringUtils = require('ember-cli-string-utils'); +var EOL = require('os').EOL; + +module.exports = { + description: 'Generates an ember-data model.', + + anonymousOptions: [ + 'name', + 'attr:type' + ], + + locals: function(options) { + var attrs = []; + var needs = []; + var entityOptions = options.entity.options; + + for (var name in entityOptions) { + var type = entityOptions[name] || ''; + var foreignModel = name; + if (type.indexOf(':') > -1) { + foreignModel = type.split(':')[1]; + type = type.split(':')[0]; + } + var dasherizedName = stringUtils.dasherize(name); + var dasherizedNameSingular = inflection.singularize(dasherizedName); + var camelizedName = stringUtils.camelize(name); + var dasherizedType = stringUtils.dasherize(type); + var dasherizedForeignModel = stringUtils.dasherize(foreignModel); + var dasherizedForeignModelSingular = inflection.singularize(dasherizedForeignModel); + + if (/has-many/.test(dasherizedType)) { + var camelizedNamePlural = inflection.pluralize(camelizedName); + var attr = dsAttr(dasherizedForeignModelSingular, dasherizedType); + attrs.push(camelizedNamePlural + ': ' + attr); + } else if (/belongs-to/.test(dasherizedType)) { + var attr = dsAttr(dasherizedForeignModel, dasherizedType) + attrs.push(camelizedName + ': ' + attr); + } else { + var attr = dsAttr(dasherizedName, dasherizedType) + attrs.push(camelizedName + ': ' + attr); + } + + if (/has-many|belongs-to/.test(dasherizedType)) { + needs.push("'model:" + dasherizedForeignModelSingular + "'"); + } + } + var needsDeduplicated = needs.filter(function(need, i) { + return needs.indexOf(need) === i; + }) + + attrs = attrs.join(',' + EOL + ' '); + needs = ' needs: [' + needsDeduplicated.join(', ') + ']'; + + return { + attrs: attrs, + needs: needs + }; + } +}; + +function dsAttr(name, type) { + switch (type) { + case 'belongs-to': + return 'DS.belongsTo(\'' + name + '\')'; + case 'has-many': + return 'DS.hasMany(\'' + name + '\')'; + case '': + //"If you don't specify the type of the attribute, it will be whatever was provided by the server" + //http://emberjs.com/guides/models/defining-models/ + return 'DS.attr()'; + default: + return 'DS.attr(\'' + type + '\')'; + } +} diff --git a/blueprints/serializer-test/files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..55e0bd031b2 --- /dev/null +++ b/blueprints/serializer-test/files/tests/unit/__path__/__test__.js @@ -0,0 +1,15 @@ +import { moduleForModel, test } from 'ember-qunit'; + +moduleForModel('<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', { + // Specify the other units that are required for this test. + needs: ['serializer:<%= dasherizedModuleName %>'] +}); + +// Replace this with your real tests. +test('it serializes records', function(assert) { + var record = this.subject(); + + var serializedRecord = record.serialize(); + + assert.ok(serializedRecord); +}); diff --git a/blueprints/serializer-test/index.js b/blueprints/serializer-test/index.js new file mode 100644 index 00000000000..4da25f30a64 --- /dev/null +++ b/blueprints/serializer-test/index.js @@ -0,0 +1,12 @@ +/*jshint node:true*/ + +var testInfo = require('ember-cli-test-info'); + +module.exports = { + description: 'Generates a serializer unit test.', + locals: function(options) { + return { + friendlyTestDescription: testInfo.description(options.entity.name, "Unit", "Serializer") + }; + }, +}; diff --git a/blueprints/serializer/files/__root__/__path__/__name__.js b/blueprints/serializer/files/__root__/__path__/__name__.js new file mode 100644 index 00000000000..d698ab7a750 --- /dev/null +++ b/blueprints/serializer/files/__root__/__path__/__name__.js @@ -0,0 +1,4 @@ +import DS from 'ember-data'; + +export default DS.RESTSerializer.extend({ +}); diff --git a/blueprints/serializer/index.js b/blueprints/serializer/index.js new file mode 100644 index 00000000000..bd3f41c12cd --- /dev/null +++ b/blueprints/serializer/index.js @@ -0,0 +1,5 @@ +/*jshint node:true*/ + +module.exports = { + description: 'Generates an ember-data serializer.' +}; diff --git a/blueprints/transform-test/files/tests/unit/__path__/__test__.js b/blueprints/transform-test/files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..5b628648490 --- /dev/null +++ b/blueprints/transform-test/files/tests/unit/__path__/__test__.js @@ -0,0 +1,12 @@ +import { moduleFor, test } from 'ember-qunit'; + +moduleFor('transform:<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', { + // Specify the other units that are required for this test. + // needs: ['serializer:foo'] +}); + +// Replace this with your real tests. +test('it exists', function(assert) { + var transform = this.subject(); + assert.ok(transform); +}); diff --git a/blueprints/transform-test/index.js b/blueprints/transform-test/index.js new file mode 100644 index 00000000000..59b7e9e8734 --- /dev/null +++ b/blueprints/transform-test/index.js @@ -0,0 +1,12 @@ +/*jshint node:true*/ + +var testInfo = require('ember-cli-test-info'); + +module.exports = { + description: 'Generates a transform unit test.', + locals: function(options) { + return { + friendlyTestDescription: testInfo.description(options.entity.name, "Unit", "Transform") + }; + }, +}; diff --git a/blueprints/transform/files/__root__/__path__/__name__.js b/blueprints/transform/files/__root__/__path__/__name__.js new file mode 100644 index 00000000000..3fb7bbf57e8 --- /dev/null +++ b/blueprints/transform/files/__root__/__path__/__name__.js @@ -0,0 +1,11 @@ +import DS from 'ember-data'; + +export default DS.Transform.extend({ + deserialize: function(serialized) { + return serialized; + }, + + serialize: function(deserialized) { + return deserialized; + } +}); diff --git a/blueprints/transform/index.js b/blueprints/transform/index.js new file mode 100644 index 00000000000..a258ff364ce --- /dev/null +++ b/blueprints/transform/index.js @@ -0,0 +1,5 @@ +/*jshint node:true*/ + +module.exports = { + description: 'Generates an ember-data value transform.' +}; diff --git a/index.js b/index.js index 03ae7ec4ea8..b8527540cb7 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,8 @@ /* jshint node: true */ 'use strict'; +var path = require('path'); + module.exports = { name: 'ember-data', @@ -37,6 +39,10 @@ module.exports = { } }, + blueprintsPath: function() { + return path.join(__dirname, 'blueprints'); + }, + treeForAddon: function(dir) { if (this._forceBowerUsage) { // Fakes an empty broccoli tree diff --git a/shims/shims.js b/shims/shims.js new file mode 100644 index 00000000000..8ec8e2106fa --- /dev/null +++ b/shims/shims.js @@ -0,0 +1,35 @@ +;(function() { + 'use strict'; + + function defineModule(name, value) { + define(name, [], function() { + + return { default: value }; + }); + } + + defineModule('ember-data', DS); + defineModule('ember-data/model', DS.Model); + defineModule('ember-data/serializers/rest', DS.RESTSerializer); + defineModule('ember-data/serializers/active-model', DS.ActiveModelSerializer); + defineModule('ember-data/serializers/json', DS.JSONSerializer); + defineModule('ember-data/serializers/json-api', DS.JSONAPISerializer); + defineModule('ember-data/adapters/json-api', DS.JSONAPIAdapter); + defineModule('ember-data/adapters/rest', DS.RESTAdapter); + defineModule('ember-data/adapter', DS.Adapter); + defineModule('ember-data/adapters/active-model', DS.ActiveModelAdapter); + defineModule('ember-data/store', DS.Store); + defineModule('ember-data/transform', DS.Transform); + defineModule('ember-data/attr', DS.attr); + define('ember-data/relationships', [], function() { + return { + hasMany: DS.hasMany, + belongsTo: DS.belongsTo + }; + }); + + if (Ember.Test) { + defineModule('ember-test/adapter', Ember.Test.Adapter); + defineModule('ember-test/qunit-adapter', Ember.Test.QUnitAdapter); + } +}()); From 1d936c6427916742971c0bfd7ae4c461da080b43 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 14 Dec 2015 18:24:14 -0500 Subject: [PATCH 1280/2527] Remove unused `shims` file. These shims are already provided by `lib/ember-data-shims.js`. --- shims/shims.js | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 shims/shims.js diff --git a/shims/shims.js b/shims/shims.js deleted file mode 100644 index 8ec8e2106fa..00000000000 --- a/shims/shims.js +++ /dev/null @@ -1,35 +0,0 @@ -;(function() { - 'use strict'; - - function defineModule(name, value) { - define(name, [], function() { - - return { default: value }; - }); - } - - defineModule('ember-data', DS); - defineModule('ember-data/model', DS.Model); - defineModule('ember-data/serializers/rest', DS.RESTSerializer); - defineModule('ember-data/serializers/active-model', DS.ActiveModelSerializer); - defineModule('ember-data/serializers/json', DS.JSONSerializer); - defineModule('ember-data/serializers/json-api', DS.JSONAPISerializer); - defineModule('ember-data/adapters/json-api', DS.JSONAPIAdapter); - defineModule('ember-data/adapters/rest', DS.RESTAdapter); - defineModule('ember-data/adapter', DS.Adapter); - defineModule('ember-data/adapters/active-model', DS.ActiveModelAdapter); - defineModule('ember-data/store', DS.Store); - defineModule('ember-data/transform', DS.Transform); - defineModule('ember-data/attr', DS.attr); - define('ember-data/relationships', [], function() { - return { - hasMany: DS.hasMany, - belongsTo: DS.belongsTo - }; - }); - - if (Ember.Test) { - defineModule('ember-test/adapter', Ember.Test.Adapter); - defineModule('ember-test/qunit-adapter', Ember.Test.QUnitAdapter); - } -}()); From 304f0176b2b9fd434d50ebc2c440c57d602d75aa Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 14 Dec 2015 21:47:22 -0500 Subject: [PATCH 1281/2527] Update blueprints to match ember-cli 2.2.0-beta.1. --- .../files/tests/unit/__path__/__test__.js | 12 +++++ blueprints/adapter-test/index.js | 12 +++++ .../files/__root__/__path__/__name__.js | 4 ++ blueprints/adapter/index.js | 44 +++++++++++++++++++ .../files/tests/unit/__path__/__test__.js | 4 +- blueprints/model/index.js | 10 ++--- .../files/tests/unit/__path__/__test__.js | 4 +- .../files/tests/unit/__path__/__test__.js | 2 +- .../files/__root__/__path__/__name__.js | 4 +- 9 files changed, 84 insertions(+), 12 deletions(-) create mode 100644 blueprints/adapter-test/files/tests/unit/__path__/__test__.js create mode 100644 blueprints/adapter-test/index.js create mode 100644 blueprints/adapter/files/__root__/__path__/__name__.js create mode 100644 blueprints/adapter/index.js diff --git a/blueprints/adapter-test/files/tests/unit/__path__/__test__.js b/blueprints/adapter-test/files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..739d5eb7303 --- /dev/null +++ b/blueprints/adapter-test/files/tests/unit/__path__/__test__.js @@ -0,0 +1,12 @@ +import { moduleFor, test } from 'ember-qunit'; + +moduleFor('adapter:<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', { + // Specify the other units that are required for this test. + // needs: ['serializer:foo'] +}); + +// Replace this with your real tests. +test('it exists', function(assert) { + let adapter = this.subject(); + assert.ok(adapter); +}); diff --git a/blueprints/adapter-test/index.js b/blueprints/adapter-test/index.js new file mode 100644 index 00000000000..0f73ca498f6 --- /dev/null +++ b/blueprints/adapter-test/index.js @@ -0,0 +1,12 @@ +/*jshint node:true*/ + +var testInfo = require('ember-cli-test-info'); + +module.exports = { + description: 'Generates an ember-data adapter unit test', + locals: function(options) { + return { + friendlyTestDescription: testInfo.description(options.entity.name, "Unit", "Adapter") + }; + } +}; diff --git a/blueprints/adapter/files/__root__/__path__/__name__.js b/blueprints/adapter/files/__root__/__path__/__name__.js new file mode 100644 index 00000000000..2b54b829447 --- /dev/null +++ b/blueprints/adapter/files/__root__/__path__/__name__.js @@ -0,0 +1,4 @@ +<%= importStatement %> + +export default <%= baseClass %>.extend({ +}); diff --git a/blueprints/adapter/index.js b/blueprints/adapter/index.js new file mode 100644 index 00000000000..f277c3111a6 --- /dev/null +++ b/blueprints/adapter/index.js @@ -0,0 +1,44 @@ +/*jshint node:true*/ + +var stringUtil = require('ember-cli-string-utils'); +var SilentError = require('silent-error'); +var pathUtil = require('ember-cli-path-utils'); + +module.exports = { + description: 'Generates an ember-data adapter.', + + availableOptions: [ + { name: 'base-class', type: String } + ], + + locals: function(options) { + var adapterName = options.entity.name; + var baseClass = 'DS.RESTAdapter'; + var importStatement = 'import DS from \'ember-data\';'; + var isAddon = options.inRepoAddon || options.project.isEmberCLIAddon(); + var relativePath = pathUtil.getRelativePath(options.entity.name); + + if (options.pod && options.podPath) { + relativePath = pathUtil.getRelativePath(options.podPath + options.entity.name); + } + + if (!isAddon && !options.baseClass && adapterName !== 'application') { + options.baseClass = 'application'; + } + + if (options.baseClass === adapterName) { + throw new SilentError('Adapters cannot extend from themself. To resolve this, remove the `--base-class` option or change to a different base-class.'); + } + + if (options.baseClass) { + baseClass = stringUtil.classify(options.baseClass.replace('\/', '-')); + baseClass = baseClass + 'Adapter'; + importStatement = 'import ' + baseClass + ' from \'' + relativePath + options.baseClass + '\';'; + } + + return { + importStatement: importStatement, + baseClass: baseClass + }; + } +}; diff --git a/blueprints/model-test/files/tests/unit/__path__/__test__.js b/blueprints/model-test/files/tests/unit/__path__/__test__.js index 88003fc2be8..8f26bfd1b67 100644 --- a/blueprints/model-test/files/tests/unit/__path__/__test__.js +++ b/blueprints/model-test/files/tests/unit/__path__/__test__.js @@ -6,7 +6,7 @@ moduleForModel('<%= dasherizedModuleName %>', '<%= friendlyDescription %>', { }); test('it exists', function(assert) { - var model = this.subject(); - // var store = this.store(); + let model = this.subject(); + // let store = this.store(); assert.ok(!!model); }); diff --git a/blueprints/model/index.js b/blueprints/model/index.js index 5acd699db5a..1787ad788a1 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -25,21 +25,21 @@ module.exports = { type = type.split(':')[0]; } var dasherizedName = stringUtils.dasherize(name); - var dasherizedNameSingular = inflection.singularize(dasherizedName); var camelizedName = stringUtils.camelize(name); var dasherizedType = stringUtils.dasherize(type); var dasherizedForeignModel = stringUtils.dasherize(foreignModel); var dasherizedForeignModelSingular = inflection.singularize(dasherizedForeignModel); + var attr; if (/has-many/.test(dasherizedType)) { var camelizedNamePlural = inflection.pluralize(camelizedName); - var attr = dsAttr(dasherizedForeignModelSingular, dasherizedType); + attr = dsAttr(dasherizedForeignModelSingular, dasherizedType); attrs.push(camelizedNamePlural + ': ' + attr); } else if (/belongs-to/.test(dasherizedType)) { - var attr = dsAttr(dasherizedForeignModel, dasherizedType) + attr = dsAttr(dasherizedForeignModel, dasherizedType); attrs.push(camelizedName + ': ' + attr); } else { - var attr = dsAttr(dasherizedName, dasherizedType) + attr = dsAttr(dasherizedName, dasherizedType); attrs.push(camelizedName + ': ' + attr); } @@ -49,7 +49,7 @@ module.exports = { } var needsDeduplicated = needs.filter(function(need, i) { return needs.indexOf(need) === i; - }) + }); attrs = attrs.join(',' + EOL + ' '); needs = ' needs: [' + needsDeduplicated.join(', ') + ']'; diff --git a/blueprints/serializer-test/files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/files/tests/unit/__path__/__test__.js index 55e0bd031b2..bfc3aa943ca 100644 --- a/blueprints/serializer-test/files/tests/unit/__path__/__test__.js +++ b/blueprints/serializer-test/files/tests/unit/__path__/__test__.js @@ -7,9 +7,9 @@ moduleForModel('<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', // Replace this with your real tests. test('it serializes records', function(assert) { - var record = this.subject(); + let record = this.subject(); - var serializedRecord = record.serialize(); + let serializedRecord = record.serialize(); assert.ok(serializedRecord); }); diff --git a/blueprints/transform-test/files/tests/unit/__path__/__test__.js b/blueprints/transform-test/files/tests/unit/__path__/__test__.js index 5b628648490..ef14ae150b3 100644 --- a/blueprints/transform-test/files/tests/unit/__path__/__test__.js +++ b/blueprints/transform-test/files/tests/unit/__path__/__test__.js @@ -7,6 +7,6 @@ moduleFor('transform:<%= dasherizedModuleName %>', '<%= friendlyTestDescription // Replace this with your real tests. test('it exists', function(assert) { - var transform = this.subject(); + let transform = this.subject(); assert.ok(transform); }); diff --git a/blueprints/transform/files/__root__/__path__/__name__.js b/blueprints/transform/files/__root__/__path__/__name__.js index 3fb7bbf57e8..722408742d7 100644 --- a/blueprints/transform/files/__root__/__path__/__name__.js +++ b/blueprints/transform/files/__root__/__path__/__name__.js @@ -1,11 +1,11 @@ import DS from 'ember-data'; export default DS.Transform.extend({ - deserialize: function(serialized) { + deserialize(serialized) { return serialized; }, - serialize: function(deserialized) { + serialize(deserialized) { return deserialized; } }); From 7066d77c4b8ef25ee9de99914323cf0e58934328 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 14 Dec 2015 18:28:04 -0500 Subject: [PATCH 1282/2527] Add missing dependencies. --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 935d77278d7..c4f202ec43d 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,10 @@ "broccoli-merge-trees": "^1.0.0", "chalk": "^1.1.1", "ember-cli-babel": "^5.1.3", - "ember-cli-version-checker": "^1.1.4" + "ember-cli-string-utils": "^1.0.0", + "ember-cli-test-info": "^1.0.0", + "ember-cli-version-checker": "^1.1.4", + "inflection": "^1.8.0" }, "devDependencies": { "babel-plugin-feature-flags": "^0.2.0", From 3446090ff474dc1601025c0b7659d45c6ba7c5bf Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 14 Dec 2015 21:15:27 -0500 Subject: [PATCH 1283/2527] Ensure `config/features.json` works with different cwd. --- tests/dummy/config/environment.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index f367c52449c..9cd862b02ca 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -1,7 +1,9 @@ /* jshint node: true */ var fs = require('fs'); -var featuresJson = fs.readFileSync('config/features.json', { encoding: 'utf8' }); +var path = require('path'); +var featuresJsonPath = path.join(__dirname, '../../../config/features.json'); +var featuresJson = fs.readFileSync(featuresJsonPath, { encoding: 'utf8' }); var featureFlags = JSON.parse(featuresJson); module.exports = function(environment) { From 7f03ec70ff41739af51ffc8e2e14a96f8f3e0878 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 14 Dec 2015 21:23:17 -0500 Subject: [PATCH 1284/2527] Add tests for blueprints. --- .travis.yml | 1 + node-tests/blueprints/adapter-test.js | 40 ++++++++++++++++++++++ node-tests/blueprints/model-test.js | 40 ++++++++++++++++++++++ node-tests/blueprints/serializer-test.js | 40 ++++++++++++++++++++++ node-tests/blueprints/transform-test.js | 42 ++++++++++++++++++++++++ package.json | 9 +++-- 6 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 node-tests/blueprints/adapter-test.js create mode 100644 node-tests/blueprints/model-test.js create mode 100644 node-tests/blueprints/serializer-test.js create mode 100644 node-tests/blueprints/transform-test.js diff --git a/.travis.yml b/.travis.yml index ad55c004238..1f3eff604a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ script: - ./bin/lint-features - npm run-script test - npm run-script test:optional-features + - npm run-script node-tests after_success: - npm run-script production - "./bin/bower-ember-data-build" diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js new file mode 100644 index 00000000000..d57b54a6119 --- /dev/null +++ b/node-tests/blueprints/adapter-test.js @@ -0,0 +1,40 @@ +var setupTestHooks = require('ember-cli-blueprint-test-helpers/lib/helpers/setup'); +var BlueprintHelpers = require('ember-cli-blueprint-test-helpers/lib/helpers/blueprint-helper'); +var generateAndDestroy = BlueprintHelpers.generateAndDestroy; + +describe('Acceptance: generate and destroy adapter blueprints', function() { + setupTestHooks(this); + + it('adapter', function() { + return generateAndDestroy(['adapter', 'foo'], { + files: [ + { + file: 'app/adapters/foo.js', + contains: [ + 'import ApplicationAdapter from \'./application\';', + 'export default ApplicationAdapter.extend({' + ] + }, + { + file: 'tests/unit/adapters/foo-test.js', + contains: [ + 'moduleFor(\'adapter:foo\'' + ] + } + ] + }); + }); + + it('adapter-test', function() { + return generateAndDestroy(['adapter-test', 'foo'], { + files: [ + { + file: 'tests/unit/adapters/foo-test.js', + contains: [ + 'moduleFor(\'adapter:foo\'' + ] + } + ] + }); + }); +}); diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js new file mode 100644 index 00000000000..9dbe6213a92 --- /dev/null +++ b/node-tests/blueprints/model-test.js @@ -0,0 +1,40 @@ +var setupTestHooks = require('ember-cli-blueprint-test-helpers/lib/helpers/setup'); +var BlueprintHelpers = require('ember-cli-blueprint-test-helpers/lib/helpers/blueprint-helper'); +var generateAndDestroy = BlueprintHelpers.generateAndDestroy; + +describe('Acceptance: generate and destroy model blueprints', function() { + setupTestHooks(this); + + it('model', function() { + return generateAndDestroy(['model', 'foo'], { + files: [ + { + file: 'app/models/foo.js', + contains: [ + 'import DS from \'ember-data\';', + 'export default DS.Model.extend(' + ] + }, + { + file: 'tests/unit/models/foo-test.js', + contains: [ + 'moduleForModel(\'foo\'' + ] + } + ] + }); + }); + + it('model-test', function() { + return generateAndDestroy(['model-test', 'foo'], { + files: [ + { + file: 'tests/unit/models/foo-test.js', + contains: [ + 'moduleForModel(\'foo\'' + ] + } + ] + }); + }); +}); diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js new file mode 100644 index 00000000000..cdea2670704 --- /dev/null +++ b/node-tests/blueprints/serializer-test.js @@ -0,0 +1,40 @@ +var setupTestHooks = require('ember-cli-blueprint-test-helpers/lib/helpers/setup'); +var BlueprintHelpers = require('ember-cli-blueprint-test-helpers/lib/helpers/blueprint-helper'); +var generateAndDestroy = BlueprintHelpers.generateAndDestroy; + +describe('Acceptance: generate and destroy serializer blueprints', function() { + setupTestHooks(this); + + it('serializer', function() { + return generateAndDestroy(['serializer', 'foo'], { + files: [ + { + file: 'app/serializers/foo.js', + contains: [ + 'import DS from \'ember-data\';', + 'export default DS.RESTSerializer.extend(' + ] + }, + { + file: 'tests/unit/serializers/foo-test.js', + contains: [ + 'moduleForModel(\'foo\'' + ] + } + ] + }); + }); + + it('serializer-test', function() { + return generateAndDestroy(['serializer-test', 'foo'], { + files: [ + { + file: 'tests/unit/serializers/foo-test.js', + contains: [ + 'moduleForModel(\'foo\'' + ] + } + ] + }); + }); +}); diff --git a/node-tests/blueprints/transform-test.js b/node-tests/blueprints/transform-test.js new file mode 100644 index 00000000000..07768e44c6f --- /dev/null +++ b/node-tests/blueprints/transform-test.js @@ -0,0 +1,42 @@ +var setupTestHooks = require('ember-cli-blueprint-test-helpers/lib/helpers/setup'); +var BlueprintHelpers = require('ember-cli-blueprint-test-helpers/lib/helpers/blueprint-helper'); +var generateAndDestroy = BlueprintHelpers.generateAndDestroy; + +describe('Acceptance: generate and destroy transform blueprints', function() { + setupTestHooks(this); + + it('transform', function() { + return generateAndDestroy(['transform', 'foo'], { + files: [ + { + file: 'app/transforms/foo.js', + contains: [ + 'import DS from \'ember-data\';', + 'export default DS.Transform.extend(', + 'deserialize(serialized) {', + 'serialize(deserialized) {' + ] + }, + { + file: 'tests/unit/transforms/foo-test.js', + contains: [ + 'moduleFor(\'transform:foo\'' + ] + } + ] + }); + }); + + it('transforms-test', function() { + return generateAndDestroy(['transform-test', 'foo'], { + files: [ + { + file: 'tests/unit/transforms/foo-test.js', + contains: [ + 'moduleFor(\'transform:foo\'' + ] + } + ] + }); + }); +}); diff --git a/package.json b/package.json index c4f202ec43d..d3e7f5f1ae6 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build": "ember build", "start": "ember server", "test": "ember try:testall", + "node-tests": "mocha node-tests/blueprints/*-test.js", "test:optional-features": "ember test --environment=test-optional-features", "bower": "bower install", "production": "ember build --environment=production" @@ -25,10 +26,12 @@ "broccoli-merge-trees": "^1.0.0", "chalk": "^1.1.1", "ember-cli-babel": "^5.1.3", + "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.0.0", "ember-cli-test-info": "^1.0.0", "ember-cli-version-checker": "^1.1.4", - "inflection": "^1.8.0" + "inflection": "^1.8.0", + "silent-error": "^1.0.0" }, "devDependencies": { "babel-plugin-feature-flags": "^0.2.0", @@ -45,6 +48,7 @@ "broccoli-yuidoc": "^2.1.0", "ember-cli": "1.13.12", "ember-cli-app-version": "0.5.0", + "ember-cli-blueprint-test-helpers": "^0.5.0", "ember-cli-content-security-policy": "0.4.0", "ember-cli-dependency-checker": "^1.0.1", "ember-cli-htmlbars": "0.7.9", @@ -61,7 +65,8 @@ "ember-try": "0.0.6", "ember-watson": "^0.7.0", "git-repo-version": "^0.3.0", - "lodash.assign": "^3.2.0" + "lodash.assign": "^3.2.0", + "mocha": "^2.3.4" }, "peerDependencies": { "ember-inflector": "^1.9.4" From 4a30273a02ac85a86994c478c425c8e11ef4faee Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 10 Jun 2015 10:56:37 +0200 Subject: [PATCH 1285/2527] Implement RFC#57 - Reference Unification --- FEATURES.md | 2 + addon/-private/system/model/internal-model.js | 26 + addon/-private/system/model/model.js | 125 ++++ addon/-private/system/references.js | 5 + .../-private/system/references/belongs-to.js | 82 +++ addon/-private/system/references/has-many.js | 99 ++++ addon/-private/system/references/record.js | 39 ++ addon/-private/system/references/reference.js | 10 + .../system/relationships/state/belongs-to.js | 15 + addon/-private/system/store.js | 48 ++ config/features.json | 2 +- .../integration/references/belongs-to-test.js | 557 ++++++++++++++++++ tests/integration/references/has-many-test.js | 535 +++++++++++++++++ tests/integration/references/record-test.js | 237 ++++++++ .../relationships/belongs-to-test.js | 134 +++++ tests/unit/model-test.js | 12 +- 16 files changed, 1917 insertions(+), 11 deletions(-) create mode 100644 addon/-private/system/references.js create mode 100644 addon/-private/system/references/belongs-to.js create mode 100644 addon/-private/system/references/has-many.js create mode 100644 addon/-private/system/references/record.js create mode 100644 addon/-private/system/references/reference.js create mode 100644 tests/integration/references/belongs-to-test.js create mode 100644 tests/integration/references/has-many-test.js create mode 100644 tests/integration/references/record-test.js diff --git a/FEATURES.md b/FEATURES.md index 92cc95cdb0b..8e86c748d37 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -11,4 +11,6 @@ entry in `config/features.json`. ## Feature Flags +- `ds-references` + Adds references as described in [RFC 57](https://github.com/emberjs/rfcs/pull/57) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index b28b2937a80..51efca00e4c 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -10,6 +10,12 @@ import { getOwner } from 'ember-data/-private/utils'; +import { + RecordReference, + BelongsToReference, + HasManyReference +} from "ember-data/-private/system/references"; + var Promise = Ember.RSVP.Promise; var get = Ember.get; var set = Ember.set; @@ -67,6 +73,8 @@ export default function InternalModel(type, id, store, _, data) { this._relationships = new Relationships(this); this._recordArrays = undefined; this.currentState = RootState.empty; + this.recordReference = new RecordReference(store, this); + this.references = {}; this.isReloading = false; this.isError = false; this.error = null; @@ -594,6 +602,24 @@ InternalModel.prototype = { return value; }, + referenceFor: function(type, name) { + var reference = this.references[name]; + + if (!reference) { + var relationship = this._relationships.get(name); + + if (type === "belongsTo") { + reference = new BelongsToReference(this.store, this, relationship); + } else if (type === "hasMany") { + reference = new HasManyReference(this.store, this, relationship); + } + + this.references[name] = reference; + } + + return reference; + }, + /** @method updateRecordArrays diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 60cc0edbd45..5b447de30b5 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -2,6 +2,7 @@ import Ember from 'ember'; import { assert, deprecate } from "ember-data/-private/debug"; import { PromiseObject } from "ember-data/-private/system/promise-proxies"; import Errors from "ember-data/-private/system/model/errors"; +import isEnabled from 'ember-data/-private/features'; /** @module ember-data @@ -847,4 +848,128 @@ if (Ember.setOwner) { }); } +if (isEnabled("ds-references")) { + + Model.reopen({ + + /** + Get the reference for the specified belongsTo relationship. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + store.push({ + type: 'blog', + id: 1, + relationships: { + user: { type: 'user', id: 1 } + } + }); + var userRef = blog.belongsTo('user'); + + // check if the user relationship is loaded + var isLoaded = userRef.value() !== null; + + // get the record of the reference (null if not yet available) + var user = userRef.value(); + + // get the identifier of the reference + if (userRef.remoteType() === "id") { + var id = userRef.id(); + } else if (userRef.remoteType() === "link") { + var link = userRef.link(); + } + + // load user (via store.find or store.findBelongsTo) + userRef.load().then(...) + + // or trigger a reload + userRef.reload().then(...) + + // provide data for reference + userRef.push({ + type: 'user', + id: 1, + attributes: { + username: "@user" + } + }).then(function(user) { + userRef.value() === user; + }); + ``` + + @method belongsTo + @param {String} name of the relationship + @return {BelongsToReference} reference for this relationship + */ + belongsTo: function(name) { + return this._internalModel.referenceFor('belongsTo', name); + }, + + /** + Get the reference for the specified hasMany relationship. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + + store.push({ + type: 'blog', + id: 1, + relationships: { + comments: { + data: [ + { type: 'comment', id: 1 }, + { type: 'comment', id: 2 } + ] + } + } + }); + var commentsRef = blog.hasMany('comments'); + + // check if the comments are loaded already + var isLoaded = commentsRef.value() !== null; + + // get the records of the reference (null if not yet available) + var comments = commentsRef.value(); + + // get the identifier of the reference + if (commentsRef.remoteType() === "ids") { + var ids = commentsRef.ids(); + } else if (commentsRef.remoteType() === "link") { + var link = commentsRef.link(); + } + + // load comments (via store.findMany or store.findHasMany) + commentsRef.load().then(...) + + // or trigger a reload + commentsRef.reload().then(...) + + // provide data for reference + commentsRef.push([{ type: 'comment', id: 1 }, { type: 'comment', id: 2 }]).then(function(comments) { + commentsRef.value() === comments; + }); + ``` + + @method hasMany + @param {String} name of the relationship + @return {HasManyReference} reference for this relationship + */ + hasMany: function(name) { + return this._internalModel.referenceFor('hasMany', name); + } + }); + +} + export default Model; diff --git a/addon/-private/system/references.js b/addon/-private/system/references.js new file mode 100644 index 00000000000..ad073f586ca --- /dev/null +++ b/addon/-private/system/references.js @@ -0,0 +1,5 @@ +import RecordReference from './references/record'; +import BelongsToReference from './references/belongs-to'; +import HasManyReference from './references/has-many'; + +export { RecordReference, BelongsToReference, HasManyReference }; diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js new file mode 100644 index 00000000000..0d0a47d11e8 --- /dev/null +++ b/addon/-private/system/references/belongs-to.js @@ -0,0 +1,82 @@ +import Model from 'ember-data/-private/system/model'; +import Ember from 'ember'; +import Reference from './reference'; + +import { assertPolymorphicType } from "ember-data/-private/utils"; + +var BelongsToReference = function(store, parentInternalModel, belongsToRelationship) { + this._super$constructor(store, parentInternalModel); + this.belongsToRelationship = belongsToRelationship; + this.type = belongsToRelationship.relationshipMeta.type; + this.parent = parentInternalModel.recordReference; + + // TODO inverse +}; + +BelongsToReference.prototype = Object.create(Reference.prototype); +BelongsToReference.prototype.constructor = BelongsToReference; +BelongsToReference.prototype._super$constructor = Reference; + +BelongsToReference.prototype.remoteType = function() { + if (this.belongsToRelationship.link) { + return "link"; + } + + return "id"; +}; + +BelongsToReference.prototype.id = function() { + var inverseRecord = this.belongsToRelationship.inverseRecord; + return inverseRecord && inverseRecord.id; +}; + +BelongsToReference.prototype.link = function() { + return this.belongsToRelationship.link; +}; + +BelongsToReference.prototype.meta = function() { + return this.belongsToRelationship.meta; +}; + +BelongsToReference.prototype.push = function(objectOrPromise) { + return Ember.RSVP.resolve(objectOrPromise).then((data) => { + var record; + + if (data instanceof Model) { + record = data; + } else { + record = this.store.push(data); + } + + assertPolymorphicType(this.internalModel, this.belongsToRelationship.relationshipMeta, record._internalModel); + + this.belongsToRelationship.setCanonicalRecord(record._internalModel); + + return record; + }); +}; + +BelongsToReference.prototype.value = function() { + var inverseRecord = this.belongsToRelationship.inverseRecord; + return inverseRecord && inverseRecord.record; +}; + +BelongsToReference.prototype.load = function() { + if (this.remoteType() === "id") { + return this.belongsToRelationship.getRecord(); + } + + if (this.remoteType() === "link") { + return this.belongsToRelationship.findLink().then((internalModel) => { + return this.value(); + }); + } +}; + +BelongsToReference.prototype.reload = function() { + return this.belongsToRelationship.reload().then((internalModel) => { + return this.value(); + }); +}; + +export default BelongsToReference; diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js new file mode 100644 index 00000000000..18e766cb6cb --- /dev/null +++ b/addon/-private/system/references/has-many.js @@ -0,0 +1,99 @@ +import Ember from 'ember'; +import Reference from './reference'; + +const get = Ember.get; + +var HasManyReference = function(store, parentInternalModel, hasManyRelationship) { + this._super$constructor(store, parentInternalModel); + this.hasManyRelationship = hasManyRelationship; + this.type = hasManyRelationship.relationshipMeta.type; + this.parent = parentInternalModel.recordReference; + + // TODO inverse +}; + +HasManyReference.prototype = Object.create(Reference.prototype); +HasManyReference.prototype.constructor = HasManyReference; +HasManyReference.prototype._super$constructor = Reference; + +HasManyReference.prototype.remoteType = function() { + if (this.hasManyRelationship.link) { + return "link"; + } + + return "ids"; +}; + +HasManyReference.prototype.link = function() { + return this.hasManyRelationship.link; +}; + +HasManyReference.prototype.ids = function() { + var members = this.hasManyRelationship.members; + var ids = members.toArray().map(function(internalModel) { + return internalModel.id; + }); + + return ids; +}; + +HasManyReference.prototype.meta = function() { + return this.hasManyRelationship.manyArray.meta; +}; + +HasManyReference.prototype.push = function(objectOrPromise) { + return Ember.RSVP.resolve(objectOrPromise).then((payload) => { + var array = payload; + if (typeof payload === "object" && payload.data) { + array = payload.data; + } + + var internalModels = array.map((obj) => { + var record = this.store.push(obj); + return record._internalModel; + }); + + // TODO add assertion for polymorphic type + + this.hasManyRelationship.computeChanges(internalModels); + + return this.hasManyRelationship.manyArray; + }); +}; + +HasManyReference.prototype._isLoaded = function() { + var hasData = get(this.hasManyRelationship, 'hasData'); + if (!hasData) { + return false; + } + + var members = this.hasManyRelationship.members.toArray(); + var isEveryLoaded = members.every(function(internalModel) { + return internalModel.isLoaded() === true; + }); + + return isEveryLoaded; +}; + +HasManyReference.prototype.value = function() { + if (this._isLoaded()) { + return this.hasManyRelationship.manyArray; + } + + return null; +}; + +HasManyReference.prototype.load = function() { + if (!this._isLoaded()) { + return this.hasManyRelationship.getRecords(); + } + + var manyArray = this.hasManyRelationship.manyArray; + return Ember.RSVP.resolve(manyArray); +}; + +HasManyReference.prototype.reload = function() { + return this.hasManyRelationship.reload(); +}; + +export default HasManyReference; diff --git a/addon/-private/system/references/record.js b/addon/-private/system/references/record.js new file mode 100644 index 00000000000..87885d7cdab --- /dev/null +++ b/addon/-private/system/references/record.js @@ -0,0 +1,39 @@ +import Ember from 'ember'; +import Reference from './reference'; + +var RecordReference = function(store, internalModel) { + this._super$constructor(store, internalModel); + this.type = internalModel.modelName; + this.id = internalModel.id; + this.remoteType = 'identity'; +}; + +RecordReference.prototype = Object.create(Reference.prototype); +RecordReference.prototype.constructor = RecordReference; +RecordReference.prototype._super$constructor = Reference; + +RecordReference.prototype.push = function(objectOrPromise) { + return Ember.RSVP.resolve(objectOrPromise).then((data) => { + var record = this.store.push(data); + return record; + }); +}; + +RecordReference.prototype.value = function() { + return this.internalModel.record; +}; + +RecordReference.prototype.load = function() { + return this.store.findRecord(this.type, this.id); +}; + +RecordReference.prototype.reload = function() { + var record = this.value(); + if (record) { + return record.reload(); + } + + return this.load(); +}; + +export default RecordReference; diff --git a/addon/-private/system/references/reference.js b/addon/-private/system/references/reference.js new file mode 100644 index 00000000000..5f3fbdae646 --- /dev/null +++ b/addon/-private/system/references/reference.js @@ -0,0 +1,10 @@ +var Reference = function(store, internalModel) { + this.store = store; + this.internalModel = internalModel; +}; + +Reference.prototype = { + constructor: Reference +}; + +export default Reference; diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index fc3638d1997..3ab114c2a0b 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -144,3 +144,18 @@ BelongsToRelationship.prototype.getRecord = function() { return toReturn; } }; + +BelongsToRelationship.prototype.reload = function() { + // TODO handle case when reload() is triggered multiple times + + if (this.link) { + return this.fetchLink(); + } + + // reload record, if it is already loaded + if (this.inverseRecord && this.inverseRecord.record) { + return this.inverseRecord.record.reload(); + } + + return this.findRecord(); +}; diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 0b74380e0bd..9d9e5edb78d 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -56,6 +56,8 @@ import InternalModel from "ember-data/-private/system/model/internal-model"; import EmptyObject from "ember-data/-private/system/empty-object"; +import isEnabled from 'ember-data/-private/features'; + export let badIdFormatAssertion = '`id` has to be non-empty string or number'; var Backburner = Ember._Backburner || Ember.Backburner || Ember.__loader.require('backburner')['default'] || Ember.__loader.require('backburner')['Backburner']; @@ -2037,6 +2039,52 @@ Store = Service.extend({ }); +if (isEnabled("ds-references")) { + + Store.reopen({ + /** + Get the reference for the specified record. + + Example + + ```javascript + var userRef = store.getReference('user', 1); + + // check if the user is loaded + var isLoaded = userRef.value() !== null; + + // get the record of the reference (null if not yet available) + var user = userRef.value(); + + // get the identifier of the reference + if (userRef.remoteType() === "id") { + var id = userRef.id(); + } + + // load user (via store.find) + userRef.load().then(...) + + // or trigger a reload + userRef.reload().then(...) + + // provide data for reference + userRef.push({ id: 1, username: "@user" }).then(function(user) { + userRef.value() === user; + }); + ``` + + @method getReference + @param {String} type + @param {String|Integer} id + @return {RecordReference} + */ + getReference: function(type, id) { + return this._internalModelForId(type, id).recordReference; + } + }); + +} + function deserializeRecordId(store, key, relationship, id) { if (isNone(id)) { return; diff --git a/config/features.json b/config/features.json index 0db3279e44b..444c96da30d 100644 --- a/config/features.json +++ b/config/features.json @@ -1,3 +1,3 @@ { - + "ds-references": null } diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js new file mode 100644 index 00000000000..83bc2c41f3a --- /dev/null +++ b/tests/integration/references/belongs-to-test.js @@ -0,0 +1,557 @@ +import DS from 'ember-data'; +import Ember from 'ember'; +import setupStore from 'dummy/tests/helpers/store'; +import { module, test } from 'qunit'; +import isEnabled from 'ember-data/-private/features'; + +if (isEnabled("ds-references")) { + + var get = Ember.get; + var run = Ember.run; + var env, Family; + + module("integration/references/belongs-to", { + beforeEach() { + Family = DS.Model.extend({ + persons: DS.hasMany(), + name: DS.attr() + }); + var Person = DS.Model.extend({ + family: DS.belongsTo({ async: true }) + }); + + env = setupStore({ + person: Person, + family: Family + }); + }, + + afterEach() { + run(env.container, 'destroy'); + } + }); + + test("record#belongsTo", function(assert) { + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } + } + } + } + }); + }); + + var familyReference = person.belongsTo('family'); + + assert.equal(familyReference.remoteType(), 'id'); + assert.equal(familyReference.type, 'family'); + assert.equal(familyReference.id(), 1); + }); + + test("record#belongsTo for a linked reference", function(assert) { + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + links: { related: '/families/1' } + } + } + } + }); + }); + + var familyReference = person.belongsTo('family'); + + assert.equal(familyReference.remoteType(), 'link'); + assert.equal(familyReference.type, 'family'); + assert.equal(familyReference.link(), "/families/1"); + }); + + test("BelongsToReference#parent is a reference to the parent where the relationship is defined", function(assert) { + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } + } + } + } + }); + }); + + var personReference = env.store.getReference('person', 1); + var familyReference = person.belongsTo('family'); + + assert.ok(personReference); + assert.equal(familyReference.parent, personReference); + }); + + test("BelongsToReference#meta() returns the most recent meta for the relationship", function(assert) { + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + links: { + related: '/families/1' + }, + meta: { + foo: true + } + } + } + } + }); + }); + + var familyReference = person.belongsTo('family'); + assert.deepEqual(familyReference.meta(), { foo: true }); + }); + + test("push(object)", function(assert) { + var done = assert.async(); + + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } + } + } + } + }); + }); + + var familyReference = person.belongsTo('family'); + + run(function() { + var data = { + data: { + type: 'family', + id: 1, + attributes: { + name: "Coreleone" + } + } + }; + + familyReference.push(data).then(function(record) { + assert.ok(Family.detectInstance(record), "push resolves with the referenced record"); + assert.equal(get(record, 'name'), "Coreleone", "name is set"); + + done(); + }); + }); + }); + + test("push(record)", function(assert) { + var done = assert.async(); + + var person, family; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } + } + } + } + }); + family = env.store.push({ + data: { + type: 'family', + id: 1, + attributes: { + name: "Coreleone" + } + } + }); + }); + + var familyReference = person.belongsTo('family'); + + run(function() { + familyReference.push(family).then(function(record) { + assert.ok(Family.detectInstance(record), "push resolves with the referenced record"); + assert.equal(get(record, 'name'), "Coreleone", "name is set"); + assert.equal(record, family); + + done(); + }); + }); + }); + + test("push(promise)", function(assert) { + var done = assert.async(); + + var push; + var deferred = Ember.RSVP.defer(); + + run(function() { + var person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } + } + } + } + }); + var familyReference = person.belongsTo('family'); + push = familyReference.push(deferred.promise); + }); + + assert.ok(push.then, 'BelongsToReference.push returns a promise'); + + run(function() { + deferred.resolve({ + data: { + type: 'family', + id: 1, + attributes: { + name: "Coreleone" + } + } + }); + }); + + run(function() { + push.then(function(record) { + assert.ok(Family.detectInstance(record), "push resolves with the record"); + assert.equal(get(record, 'name'), "Coreleone", "name is updated"); + + done(); + }); + }); + }); + + test("push(record) asserts for invalid type", function(assert) { + var person, anotherPerson; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } + } + } + } + }); + anotherPerson = env.store.push({ + data: { + type: 'person', + id: 2 + } + }); + }); + + var familyReference = person.belongsTo('family'); + + assert.expectAssertion(function() { + run(function() { + familyReference.push(anotherPerson); + }); + }, "You cannot add a record of type 'person' to the 'person.family' relationship (only 'family' allowed)"); + }); + + test("push(record) works with polymorphic type", function(assert) { + var done = assert.async(); + + var person, mafiaFamily; + + env.registry.register('model:mafia-family', Family.extend()); + + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1 + } + }); + mafiaFamily = env.store.push({ + data: { + type: 'mafia-family', + id: 1 + } + }); + }); + + var familyReference = person.belongsTo('family'); + run(function() { + familyReference.push(mafiaFamily).then(function(family) { + assert.equal(family, mafiaFamily); + + done(); + }); + }); + }); + + test("value() is null when reference is not yet loaded", function(assert) { + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } + } + } + } + }); + }); + + var familyReference = person.belongsTo('family'); + assert.equal(familyReference.value(), null); + }); + + test("value() returns the referenced record when loaded", function(assert) { + var person, family; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } + } + } + } + }); + family = env.store.push({ + data: { + type: 'family', + id: 1 + } + }); + }); + + var familyReference = person.belongsTo('family'); + assert.equal(familyReference.value(), family); + }); + + test("load() fetches the record", function(assert) { + var done = assert.async(); + + env.adapter.findRecord = function(store, type, id) { + return Ember.RSVP.resolve({ + id: 1, name: "Coreleone" + }); + }; + + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } + } + } + } + }); + }); + + var familyReference = person.belongsTo('family'); + + run(function() { + familyReference.load().then(function(record) { + assert.equal(get(record, 'name'), "Coreleone"); + + done(); + }); + }); + }); + + test("load() fetches link when remoteType is link", function(assert) { + var done = assert.async(); + + env.adapter.findBelongsTo = function(store, snapshot, link) { + assert.equal(link, "/families/1"); + + return Ember.RSVP.resolve({ + id: 1, name: "Coreleone" + }); + }; + + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + links: { related: '/families/1' } + } + } + } + }); + }); + + var familyReference = person.belongsTo('family'); + assert.equal(familyReference.remoteType(), "link"); + + run(function() { + familyReference.load().then(function(record) { + assert.equal(get(record, 'name'), "Coreleone"); + + done(); + }); + }); + }); + + test("reload() - loads the record when not yet loaded", function(assert) { + var done = assert.async(); + + var count = 0; + env.adapter.findRecord = function(store, type, id) { + count++; + assert.equal(count, 1); + + return Ember.RSVP.resolve({ + id: 1, name: "Coreleone" + }); + }; + + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } + } + } + } + }); + }); + + var familyReference = person.belongsTo('family'); + + run(function() { + familyReference.reload().then(function(record) { + assert.equal(get(record, 'name'), "Coreleone"); + + done(); + }); + }); + }); + + test("reload() - reloads the record when already loaded", function(assert) { + var done = assert.async(); + + var count = 0; + env.adapter.findRecord = function(store, type, id) { + count++; + assert.equal(count, 1); + + return Ember.RSVP.resolve({ + id: 1, name: "Coreleone" + }); + }; + + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } + } + } + } + }); + env.store.push({ + data: { + type: 'family', + id: 1 + } + }); + }); + + var familyReference = person.belongsTo('family'); + + run(function() { + familyReference.reload().then(function(record) { + assert.equal(get(record, 'name'), "Coreleone"); + + done(); + }); + }); + }); + + test("reload() - uses link to reload record", function(assert) { + var done = assert.async(); + + env.adapter.findBelongsTo = function(store, snapshot, link) { + assert.equal(link, "/families/1"); + + return Ember.RSVP.resolve({ + id: 1, name: "Coreleone" + }); + }; + + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + links: { related: '/families/1' } + } + } + } + }); + }); + + var familyReference = person.belongsTo('family'); + + run(function() { + familyReference.reload().then(function(record) { + assert.equal(get(record, 'name'), "Coreleone"); + + done(); + }); + }); + }); + +} diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js new file mode 100644 index 00000000000..af7946a277b --- /dev/null +++ b/tests/integration/references/has-many-test.js @@ -0,0 +1,535 @@ +import DS from 'ember-data'; +import Ember from 'ember'; +import setupStore from 'dummy/tests/helpers/store'; +import { module, test } from 'qunit'; +import isEnabled from 'ember-data/-private/features'; + +if (isEnabled("ds-references")) { + + var get = Ember.get; + var run = Ember.run; + var env, Person; + + module("integration/references/has-many", { + beforeEach() { + var Family = DS.Model.extend({ + persons: DS.hasMany({ async: true }) + }); + Person = DS.Model.extend({ + name: DS.attr(), + family: DS.belongsTo() + }); + env = setupStore({ + person: Person, + family: Family + }); + }, + + afterEach() { + run(env.container, 'destroy'); + } + }); + + test("record#hasMany", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] + } + } + } + }); + }); + + var personsReference = family.hasMany('persons'); + + assert.equal(personsReference.remoteType(), 'ids'); + assert.equal(personsReference.type, 'person'); + assert.deepEqual(personsReference.ids(), ['1', '2']); + }); + + test("record#hasMany for linked references", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + links: { related: '/families/1/persons' } + } + } + } + }); + }); + + var personsReference = family.hasMany('persons'); + + assert.equal(personsReference.remoteType(), 'link'); + assert.equal(personsReference.type, 'person'); + assert.equal(personsReference.link(), '/families/1/persons'); + }); + + test("HasManyReference#parent is a reference to the parent where the relationship is defined", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] + } + } + } + }); + }); + + var familyReference = env.store.getReference('family', 1); + var personsReference = family.hasMany('persons'); + + assert.ok(familyReference); + assert.equal(personsReference.parent, familyReference); + }); + + test("HasManyReference#meta() returns the most recent meta for the relationship", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + links: { related: '/families/1/persons' }, + meta: { + foo: true + } + } + } + } + }); + }); + + var personsReference = family.hasMany('persons'); + assert.deepEqual(personsReference.meta(), { foo: true }); + }); + + test("push(array)", function(assert) { + var done = assert.async(); + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] + } + } + } + }); + }); + + var personsReference = family.hasMany('persons'); + + run(function() { + var data = [ + { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, + { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } + ]; + + personsReference.push(data).then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito"); + assert.equal(records.objectAt(1).get('name'), "Michael"); + + done(); + }); + }); + }); + + test("push(object) supports JSON-API payload", function(assert) { + var done = assert.async(); + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] + } + } + } + }); + }); + + var personsReference = family.hasMany('persons'); + + run(function() { + var data = { + data: [ + { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, + { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } + ] + }; + + personsReference.push(data).then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito"); + assert.equal(records.objectAt(1).get('name'), "Michael"); + + done(); + }); + }); + }); + + test("push(promise)", function(assert) { + var done = assert.async(); + + var push; + var deferred = Ember.RSVP.defer(); + + run(function() { + var family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] + } + } + } + }); + var personsReference = family.hasMany('persons'); + push = personsReference.push(deferred.promise); + }); + + assert.ok(push.then, 'HasManyReference.push returns a promise'); + + run(function() { + var data = [ + { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, + { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } + ]; + deferred.resolve(data); + }); + + run(function() { + push.then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito"); + assert.equal(records.objectAt(1).get('name'), "Michael"); + + done(); + }); + }); + }); + + test("value() returns null when reference is not yet loaded", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] + } + } + } + }); + }); + + var personsReference = family.hasMany('persons'); + assert.equal(personsReference.value(), null); + }); + + test("value() returns the referenced records when all records are loaded", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] + } + } + } + }); + env.store.push({ data: { type: 'person', id: 1, attributes: { name: "Vito" } } }); + env.store.push({ data: { type: 'person', id: 2, attributes: { name: "Michael" } } }); + }); + + var personsReference = family.hasMany('persons'); + var records = personsReference.value(); + assert.equal(get(records, 'length'), 2); + assert.equal(records.isEvery('isLoaded'), true); + }); + + test("load() fetches the referenced records", function(assert) { + var done = assert.async(); + + env.adapter.findMany = function(store, type, id) { + return Ember.RSVP.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); + }; + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] + } + } + } + }); + }); + + var personsReference = family.hasMany('persons'); + + run(function() { + personsReference.load().then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito"); + assert.equal(records.objectAt(1).get('name'), "Michael"); + + done(); + }); + }); + }); + + test("load() fetches link when remoteType is link", function(assert) { + var done = assert.async(); + + env.adapter.findHasMany = function(store, snapshot, link) { + assert.equal(link, "/families/1/persons"); + + return Ember.RSVP.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); + }; + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + links: { related: '/families/1/persons' } + } + } + } + }); + }); + + var personsReference = family.hasMany('persons'); + assert.equal(personsReference.remoteType(), "link"); + + run(function() { + personsReference.load().then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito"); + assert.equal(records.objectAt(1).get('name'), "Michael"); + + done(); + }); + }); + }); + + test("load() - only a single find is triggered", function(assert) { + var done = assert.async(); + + var deferred = Ember.RSVP.defer(); + var count = 0; + + env.adapter.findMany = function(store, type, id) { + count++; + assert.equal(count, 1); + + return deferred.promise; + }; + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] + } + } + } + }); + }); + + var personsReference = family.hasMany('persons'); + + run(function() { + personsReference.load(); + personsReference.load().then(function(records) { + assert.equal(get(records, 'length'), 2); + }); + }); + + run(function() { + deferred.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); + }); + + run(function() { + personsReference.load().then(function(records) { + assert.equal(get(records, 'length'), 2); + + done(); + }); + }); + }); + + test("reload()", function(assert) { + var done = assert.async(); + + env.adapter.findMany = function(store, type, id) { + return Ember.RSVP.resolve([ + { id: 1, name: "Vito Coreleone" }, + { id: 2, name: "Michael Coreleone" } + ]); + }; + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] + } + } + } + }); + env.store.push({ data: { type: 'person', id: 1, attributes: { name: "Vito" } } }); + env.store.push({ data: { type: 'person', id: 2, attributes: { name: "Michael" } } }); + }); + + var personsReference = family.hasMany('persons'); + + run(function() { + personsReference.reload().then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito Coreleone"); + assert.equal(records.objectAt(1).get('name'), "Michael Coreleone"); + + done(); + }); + }); + }); + + test("reload() fetches link when remoteType is link", function(assert) { + var done = assert.async(); + + var count = 0; + env.adapter.findHasMany = function(store, snapshot, link) { + count++; + assert.equal(link, "/families/1/persons"); + + if (count === 1) { + return Ember.RSVP.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); + } else { + return Ember.RSVP.resolve([ + { id: 1, name: "Vito Coreleone" }, + { id: 2, name: "Michael Coreleone" } + ]); + } + }; + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + links: { related: '/families/1/persons' } + } + } + } + }); + }); + + var personsReference = family.hasMany('persons'); + assert.equal(personsReference.remoteType(), "link"); + + run(function() { + personsReference.load().then(function() { + return personsReference.reload(); + }).then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito Coreleone"); + assert.equal(records.objectAt(1).get('name'), "Michael Coreleone"); + + done(); + }); + }); + }); + +} diff --git a/tests/integration/references/record-test.js b/tests/integration/references/record-test.js new file mode 100644 index 00000000000..3522d542463 --- /dev/null +++ b/tests/integration/references/record-test.js @@ -0,0 +1,237 @@ +import DS from 'ember-data'; +import Ember from 'ember'; +import setupStore from 'dummy/tests/helpers/store'; +import { module, test } from 'qunit'; +import isEnabled from 'ember-data/-private/features'; + +if (isEnabled("ds-references")) { + + var get = Ember.get; + var run = Ember.run; + var env, Person; + + module("integration/references/record", { + beforeEach() { + Person = DS.Model.extend({ + name: DS.attr() + }); + + env = setupStore({ + person: Person + }); + }, + + afterEach() { + run(env.store, 'unloadAll'); + run(env.container, 'destroy'); + } + }); + + test("a RecordReference can be retrieved via store.getReference(type, id)", function(assert) { + var recordReference = env.store.getReference('person', 1); + + assert.equal(recordReference.remoteType, 'identity'); + assert.equal(recordReference.type, 'person'); + assert.equal(recordReference.id, 1); + }); + + test("push(object)", function(assert) { + var done = assert.async(); + + var push; + var recordReference = env.store.getReference('person', 1); + + run(function() { + push = recordReference.push({ + data: { + type: 'person', + id: 1, + attributes: { + name: "le name" + } + } + }); + }); + + assert.ok(push.then, 'RecordReference.push returns a promise'); + + run(function() { + push.then(function(record) { + assert.ok(record instanceof Person, "push resolves with the record"); + assert.equal(get(record, 'name'), "le name"); + + done(); + }); + }); + }); + + test("push(promise)", function(assert) { + var done = assert.async(); + + var push; + var deferred = Ember.RSVP.defer(); + var recordReference = env.store.getReference('person', 1); + + run(function() { + push = recordReference.push(deferred.promise); + }); + + assert.ok(push.then, 'RecordReference.push returns a promise'); + + run(function() { + deferred.resolve({ + data: { + type: 'person', + id: 1, + attributes: { + name: "le name" + } + } + }); + }); + + run(function() { + push.then(function(record) { + assert.ok(record instanceof Person, "push resolves with the record"); + assert.equal(get(record, 'name'), "le name", "name is updated"); + + done(); + }); + }); + }); + + test("value() returns null when not yet loaded", function(assert) { + var recordReference = env.store.getReference('person', 1); + assert.equal(recordReference.value(), null); + }); + + test("value() returns the record when loaded", function(assert) { + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1 + } + }); + }); + + var recordReference = env.store.getReference('person', 1); + assert.equal(recordReference.value(), person); + }); + + test("load() fetches the record", function(assert) { + var done = assert.async(); + + env.adapter.findRecord = function(store, type, id) { + return Ember.RSVP.resolve({ + id: 1, name: "Vito" + }); + }; + + var recordReference = env.store.getReference('person', 1); + + run(function() { + recordReference.load().then(function(record) { + assert.equal(get(record, 'name'), "Vito"); + done(); + }); + }); + }); + + test("load() only a single find is triggered", function(assert) { + var done = assert.async(); + + var deferred = Ember.RSVP.defer(); + var count = 0; + + env.adapter.shouldReloadRecord = function() { return false; }; + env.adapter.shouldBackgroundReloadRecord = function() { return false; }; + env.adapter.findRecord = function(store, type, id) { + count++; + assert.equal(count, 1); + + return deferred.promise; + }; + + var recordReference = env.store.getReference('person', 1); + + run(function() { + recordReference.load(); + recordReference.load().then(function(record) { + assert.equal(get(record, 'name'), "Vito"); + }); + }); + + run(function() { + deferred.resolve({ + id: 1, name: "Vito" + }); + }); + + run(function() { + recordReference.load().then(function(record) { + assert.equal(get(record, 'name'), "Vito"); + + done(); + }); + }); + }); + + test("reload() loads the record if not yet loaded", function(assert) { + var done = assert.async(); + + var count = 0; + env.adapter.findRecord = function(store, type, id) { + count++; + assert.equal(count, 1); + + return Ember.RSVP.resolve({ + id: 1, name: "Vito Coreleone" + }); + }; + + var recordReference = env.store.getReference('person', 1); + + run(function() { + recordReference.reload().then(function(record) { + assert.equal(get(record, 'name'), "Vito Coreleone"); + + done(); + }); + }); + }); + + test("reload() fetches the record", function(assert) { + var done = assert.async(); + + env.adapter.findRecord = function(store, type, id) { + return Ember.RSVP.resolve({ + id: 1, name: "Vito Coreleone" + }); + }; + + run(function() { + env.store.push({ + data: { + type: 'person', + id: 1, + attributes: { + name: 'Vito' + } + } + }); + }); + + var recordReference = env.store.getReference('person', 1); + + run(function() { + recordReference.reload().then(function(record) { + assert.equal(get(record, 'name'), "Vito Coreleone"); + + done(); + }); + }); + }); + +} diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 66949a24a98..c451b096e4c 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1121,3 +1121,137 @@ test("Updated related link should take precedence over local data", function(ass }); }); }); + +if (Ember.FEATURES.isEnabled('ds-references')) { + + test("A belongsTo relationship can be reloaded using the reference if it was fetched via link", function(assert) { + var done = assert.async(); + + Chapter.reopen({ + book: DS.belongsTo({ async: true }) + }); + + env.adapter.findRecord = function() { + return Ember.RSVP.resolve({ + id: 1, + links: { book: '/books/1' } + }); + }; + + env.adapter.findBelongsTo = function() { + return Ember.RSVP.resolve({ id: 1, name: "book title" }); + }; + + run(function() { + var chapter; + store.find('chapter', 1).then(function(_chapter) { + chapter = _chapter; + + return chapter.get('book'); + }).then(function(book) { + assert.equal(book.get('name'), "book title"); + + env.adapter.findBelongsTo = function() { + return Ember.RSVP.resolve({ id: 1, name: "updated book title" }); + }; + + return chapter.belongsTo('book').reload(); + }).then(function(book) { + assert.equal(book.get('name'), "updated book title"); + + done(); + }); + }); + }); + + test("A sync belongsTo relationship can be reloaded using a reference if it was fetched via id", function(assert) { + var done = assert.async(); + + Chapter.reopen({ + book: DS.belongsTo() + }); + + var chapter; + run(function() { + chapter = env.store.push({ + data: { + type: 'chapter', + id: 1, + relationships: { + book: { + data: { type: 'book', id: 1 } + } + } + } + }); + env.store.push({ + data: { + type: 'book', + id: 1, + attributes: { + name: "book title" + } + } + }); + }); + + env.adapter.findRecord = function() { + return Ember.RSVP.resolve({ id: 1, name: "updated book title" }); + }; + + run(function() { + var book = chapter.get('book'); + assert.equal(book.get('name'), "book title"); + + chapter.belongsTo('book').reload().then(function(book) { + assert.equal(book.get('name'), "updated book title"); + + done(); + }); + }); + }); + + test("A belongsTo relationship can be reloaded using a reference if it was fetched via id", function(assert) { + var done = assert.async(); + + Chapter.reopen({ + book: DS.belongsTo({ async: true }) + }); + + var chapter; + run(function() { + chapter = env.store.push({ + data: { + type: 'chapter', + id: 1, + relationships: { + book: { + data: { type: 'book', id: 1 } + } + } + } + }); + }); + + env.adapter.findRecord = function() { + return Ember.RSVP.resolve({ id: 1, name: "book title" }); + }; + + run(function() { + chapter.get('book').then(function(book) { + assert.equal(book.get('name'), "book title"); + + env.adapter.findRecord = function() { + return Ember.RSVP.resolve({ id: 1, name: "updated book title" }); + }; + + return chapter.belongsTo('book').reload(); + }).then(function(book) { + assert.equal(book.get('name'), "updated book title"); + + done(); + }); + }); + }); + +} diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 54af7217039..7481316dfb8 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -415,8 +415,8 @@ test("a DS.Model can have a defaultValue without an attribute type", function(as assert.equal(get(tag, 'name'), "unknown", "the default value is found"); }); -test("Calling attr(), belongsTo() or hasMany() throws a warning", function(assert) { - assert.expect(3); +test("Calling attr() throws a warning", function(assert) { + assert.expect(1); var Person = DS.Model.extend({ name: DS.attr('string') @@ -432,14 +432,6 @@ test("Calling attr(), belongsTo() or hasMany() throws a warning", function(asser assert.throws(function() { person.attr(); }, /The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected/, "attr() throws a warning"); - - assert.throws(function() { - person.belongsTo(); - }, /The `belongsTo` method is not available on DS.Model, a DS.Snapshot was probably expected/, "belongTo() throws a warning"); - - assert.throws(function() { - person.hasMany(); - }, /The `hasMany` method is not available on DS.Model, a DS.Snapshot was probably expected/, "hasMany() throws a warning"); }); }); From 9ac62ad874c3df2781fbb247faf51e69541160bd Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 15 Dec 2015 16:52:41 -0500 Subject: [PATCH 1286/2527] [BUGFIX beta] Run the Ember Data initializer when Ember Data is loaded as an Ember CLI addon. --- app/initializers/ember-data.js | 6 ++++++ app/instance-initializers/ember-data.js | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 app/initializers/ember-data.js create mode 100644 app/instance-initializers/ember-data.js diff --git a/app/initializers/ember-data.js b/app/initializers/ember-data.js new file mode 100644 index 00000000000..8c6853d299d --- /dev/null +++ b/app/initializers/ember-data.js @@ -0,0 +1,6 @@ +import setupContainer from 'ember-data/-private/setup-container'; + +export default { + name: 'ember-data', + initialize: setupContainer +}; diff --git a/app/instance-initializers/ember-data.js b/app/instance-initializers/ember-data.js new file mode 100644 index 00000000000..e5bf74200c8 --- /dev/null +++ b/app/instance-initializers/ember-data.js @@ -0,0 +1,6 @@ +import initializeStoreService from 'ember-data/-private/instance-initializers/initialize-store-service'; + +export default { + name: "ember-data", + initialize: initializeStoreService +}; From a15cbf3ca6edd7781a06b743bcfae879c6775a95 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 16 Dec 2015 03:10:03 -0500 Subject: [PATCH 1287/2527] Update to use ember-cli-blueprint-test-helpers@0.6.0. --- .npmignore | 1 + .../fixtures/addon/package/package.json | 51 +++++++++++++ node-tests/fixtures/app/package/package.json | 43 +++++++++++ node-tests/nodetest-runner.js | 74 +++++++++++++++++++ package.json | 10 ++- 5 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 node-tests/fixtures/addon/package/package.json create mode 100644 node-tests/fixtures/app/package/package.json create mode 100644 node-tests/nodetest-runner.js diff --git a/.npmignore b/.npmignore index c3a18d19b6e..dac217ccf9d 100644 --- a/.npmignore +++ b/.npmignore @@ -13,3 +13,4 @@ bower.json Brocfile.js testem.json *.gem +node-tests/ diff --git a/node-tests/fixtures/addon/package/package.json b/node-tests/fixtures/addon/package/package.json new file mode 100644 index 00000000000..5aaa25001a6 --- /dev/null +++ b/node-tests/fixtures/addon/package/package.json @@ -0,0 +1,51 @@ +{ + "name": "my-addon", + "version": "0.0.0", + "description": "The default blueprint for ember-cli addons.", + "directories": { + "doc": "doc", + "test": "tests" + }, + "scripts": { + "build": "ember build", + "start": "ember server", + "test": "ember try:testall" + }, + "repository": "", + "engines": { + "node": ">= 0.10.0" + }, + "author": "", + "license": "MIT", + "devDependencies": { + "broccoli-asset-rev": "^2.1.2", + "ember-ajax": "0.6.2", + "ember-cli": "1.13.12", + "ember-cli-app-version": "^1.0.0", + "ember-cli-content-security-policy": "0.4.0", + "ember-cli-dependency-checker": "^1.1.0", + "ember-cli-htmlbars-inline-precompile": "^0.3.1", + "ember-cli-inject-live-reload": "^1.3.1", + "ember-cli-qunit": "^1.0.1", + "ember-cli-release": "0.2.3", + "ember-cli-sri": "^1.0.3", + "ember-cli-uglify": "^1.2.0", + "ember-data": "2.0.0", + "ember-disable-proxy-controllers": "^1.0.0", + "ember-export-application-global": "^1.0.4", + "ember-resolver": "^2.0.2", + "ember-disable-prototype-extensions": "^1.0.0", + "ember-try": "~0.0.8", + "ember-data": "*" + }, + "keywords": [ + "ember-addon" + ], + "dependencies": { + "ember-cli-htmlbars": "^1.0.0", + "ember-cli-babel": "^5.1.3" + }, + "ember-addon": { + "configPath": "tests/dummy/config" + } +} diff --git a/node-tests/fixtures/app/package/package.json b/node-tests/fixtures/app/package/package.json new file mode 100644 index 00000000000..a97d1c6e103 --- /dev/null +++ b/node-tests/fixtures/app/package/package.json @@ -0,0 +1,43 @@ +{ + "name": "my-app", + "version": "0.0.0", + "description": "Small description for nested-project goes here", + "private": true, + "directories": { + "doc": "doc", + "test": "tests" + }, + "scripts": { + "build": "ember build", + "start": "ember server", + "test": "ember test" + }, + "repository": "", + "engines": { + "node": ">= 0.10.0" + }, + "author": "", + "license": "MIT", + "devDependencies": { + "broccoli-asset-rev": "^2.1.2", + "ember-ajax": "0.6.2", + "ember-cli": "1.13.8", + "ember-cli-app-version": "^1.0.0", + "ember-cli-babel": "^5.1.3", + "ember-cli-content-security-policy": "0.4.0", + "ember-cli-dependency-checker": "^1.1.0", + "ember-cli-htmlbars": "^1.0.0", + "ember-cli-htmlbars-inline-precompile": "^0.3.1", + "ember-cli-inject-live-reload": "^1.3.1", + "ember-cli-legacy-blueprints": "*", + "ember-cli-qunit": "^1.0.1", + "ember-cli-release": "0.2.3", + "ember-cli-sri": "^1.0.3", + "ember-cli-uglify": "^1.2.0", + "ember-data": "2.0.0", + "ember-disable-proxy-controllers": "^1.0.0", + "ember-export-application-global": "^1.0.4", + "ember-resolver": "^2.0.2", + "ember-data": "*" + } +} diff --git a/node-tests/nodetest-runner.js b/node-tests/nodetest-runner.js new file mode 100644 index 00000000000..0cdde7a897f --- /dev/null +++ b/node-tests/nodetest-runner.js @@ -0,0 +1,74 @@ +'use strict'; + +var glob = require('glob'); +var Mocha = require('mocha'); +var Promise = require('ember-cli/lib/ext/promise'); +var rimraf = require('rimraf'); +var mochaOnlyDetector = require('mocha-only-detector'); + +if (process.env.EOLNEWLINE) { + require('os').EOL = '\n'; +} + +rimraf.sync('.node_modules-tmp'); +rimraf.sync('.bower_components-tmp'); + +var root = 'node-tests/{blueprints,acceptance,unit}'; +var _checkOnlyInTests = Promise.denodeify(mochaOnlyDetector.checkFolder.bind(null, root + '/**/*{-test}.js')); +var optionOrFile = process.argv[2]; +var mocha = new Mocha({ + timeout: 5000, + reporter: 'spec' +}); +var testFiles = glob.sync(root + '**/*-test.js'); +/*var jshintPosition = testFiles.indexOf('tests/unit/jshint-test.js'); +var jshint = testFiles.splice(jshintPosition, 1); + +testFiles = jshint.concat(testFiles); +*/ +if (optionOrFile === 'all') { + addFiles(mocha, testFiles); + addFiles(mocha, 'node-tests/**/*-test.js'); + addFiles(mocha, '/**/*-test-slow.js'); +} else if (process.argv.length > 2) { + addFiles(mocha, process.argv.slice(2)); +} else { + addFiles(mocha, testFiles); +} + +function addFiles(mocha, files) { + files = (typeof files === 'string') ? glob.sync(root + files) : files; + files.forEach(mocha.addFile.bind(mocha)); +} + +function checkOnlyInTests() { + console.log('Verifing `.only` in tests'); + return _checkOnlyInTests().then(function() { + console.log('No `.only` found'); + }); +} + +function runMocha() { + mocha.run(function(failures) { + process.on('exit', function() { + process.exit(failures); + }); + }); +} + +function ciVerificationStep() { + if (process.env.CI === 'true') { + return checkOnlyInTests(); + } else { + return Promise.resolve(); + } +} + +ciVerificationStep() + .then(function() { + runMocha(); + }) + .catch(function(error) { + console.error(error); + process.exit(1); + }); diff --git a/package.json b/package.json index d3e7f5f1ae6..32081531e83 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "build": "ember build", "start": "ember server", "test": "ember try:testall", - "node-tests": "mocha node-tests/blueprints/*-test.js", + "node-tests": "node node-tests/nodetest-runner.js", "test:optional-features": "ember test --environment=test-optional-features", "bower": "bower install", "production": "ember build --environment=production" @@ -48,13 +48,14 @@ "broccoli-yuidoc": "^2.1.0", "ember-cli": "1.13.12", "ember-cli-app-version": "0.5.0", - "ember-cli-blueprint-test-helpers": "^0.5.0", + "ember-cli-blueprint-test-helpers": "^0.6.0", "ember-cli-content-security-policy": "0.4.0", "ember-cli-dependency-checker": "^1.0.1", "ember-cli-htmlbars": "0.7.9", "ember-cli-htmlbars-inline-precompile": "^0.2.0", "ember-cli-ic-ajax": "0.2.1", "ember-cli-inject-live-reload": "^1.3.1", + "ember-cli-internal-test-helpers": "^0.5.0", "ember-cli-qunit": "^1.0.0", "ember-cli-release": "0.2.3", "ember-cli-uglify": "^1.2.0", @@ -65,8 +66,11 @@ "ember-try": "0.0.6", "ember-watson": "^0.7.0", "git-repo-version": "^0.3.0", + "glob": "^5.0.13", "lodash.assign": "^3.2.0", - "mocha": "^2.3.4" + "mocha": "^2.3.4", + "mocha-only-detector": "0.0.2", + "rimraf": "^2.3.2" }, "peerDependencies": { "ember-inflector": "^1.9.4" From 266d3b0fee59efdd6b6a91556b922425ce57f19e Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Mon, 7 Dec 2015 23:21:41 -0500 Subject: [PATCH 1288/2527] Allow `include` query parameter with store.findRecord & store.findAll Related RFC: https://github.com/emberjs/rfcs/pull/99 These changes allow an `include` paremeter to be specified when using `store.findRecord` and `store.findAll`: ```javascript store.findRecord('post', 123, { include: 'comments' }); store.findAll('post', { include: 'comments' }); ``` The value for `include` is copied onto the `DS.Snapshot` or `DS.SnapshotRecordArray` that is passed to the corresponding adapter function. This value is then pulled from the snapshot and used as a query parameter (`include`) when making an AJAX request via `adapter.ajax`. --- FEATURES.md | 6 +++ addon/-private/adapters/rest-adapter.js | 35 ++++++++++--- addon/-private/system/model/internal-model.js | 5 +- .../system/record-arrays/record-array.js | 5 +- .../-private/system/snapshot-record-array.js | 10 +++- addon/-private/system/snapshot.js | 15 +++++- config/features.json | 1 + .../integration/adapter/rest-adapter-test.js | 51 ++++++++++++++++--- .../integration/adapter/store-adapter-test.js | 29 ++++++++++- tests/unit/adapters/rest-adapter/ajax-test.js | 6 +-- .../adapters/rest-adapter/build-query-test.js | 25 +++++++++ 11 files changed, 157 insertions(+), 31 deletions(-) create mode 100644 tests/unit/adapters/rest-adapter/build-query-test.js diff --git a/FEATURES.md b/FEATURES.md index 8e86c748d37..9456bb987bd 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -11,6 +11,12 @@ entry in `config/features.json`. ## Feature Flags +- `ds-find-include` + + Allows an `include` query parameter to be specified with using + `store.findRecord()` and `store.findAll()` as described in [RFC + 99](https://github.com/emberjs/rfcs/pull/99) + - `ds-references` Adds references as described in [RFC 57](https://github.com/emberjs/rfcs/pull/57) diff --git a/addon/-private/adapters/rest-adapter.js b/addon/-private/adapters/rest-adapter.js index 7e28d4fdbf8..f27b8e164c6 100644 --- a/addon/-private/adapters/rest-adapter.js +++ b/addon/-private/adapters/rest-adapter.js @@ -11,10 +11,13 @@ import { AbortError } from 'ember-data/-private/adapters/errors'; import EmptyObject from "ember-data/-private/system/empty-object"; -var get = Ember.get; -var MapWithDefault = Ember.MapWithDefault; - import BuildURLMixin from "ember-data/-private/adapters/build-url-mixin"; +import isEnabled from 'ember-data/-private/features'; + +const { + MapWithDefault, + get +} = Ember; /** The REST adapter allows your store to communicate with an HTTP server by @@ -372,7 +375,10 @@ export default Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findRecord(store, type, id, snapshot) { - return this.ajax(this.buildURL(type.modelName, id, snapshot, 'findRecord'), 'GET'); + const url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); + const query = this.buildQuery(snapshot); + + return this.ajax(url, 'GET', { data: query }); }, /** @@ -390,14 +396,13 @@ export default Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findAll(store, type, sinceToken, snapshotRecordArray) { - var query, url; + const url = this.buildURL(type.modelName, null, null, 'findAll'); + const query = this.buildQuery(snapshotRecordArray); if (sinceToken) { - query = { since: sinceToken }; + query.since = sinceToken; } - url = this.buildURL(type.modelName, null, null, 'findAll'); - return this.ajax(url, 'GET', { data: query }); }, @@ -959,6 +964,20 @@ export default Adapter.extend(BuildURLMixin, { return ['Ember Data Request ' + requestDescription + ' returned a ' + status, payloadDescription, shortenedPayload].join('\n'); + }, + + buildQuery(snapshot) { + const { include } = snapshot; + + let query = {}; + + if (isEnabled('ds-finder-include')) { + if (include) { + query.include = include; + } + } + + return query; } }); diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 51efca00e4c..9b42b151868 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -251,10 +251,7 @@ InternalModel.prototype = { @private */ createSnapshot(options) { - var adapterOptions = options && options.adapterOptions; - var snapshot = new Snapshot(this); - snapshot.adapterOptions = adapterOptions; - return snapshot; + return new Snapshot(this, options); }, /** diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index bb84147d6a4..a34aa397d62 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -202,8 +202,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { }, createSnapshot(options) { - var adapterOptions = options && options.adapterOptions; - var meta = this.get('meta'); - return new SnapshotRecordArray(this, meta, adapterOptions); + const meta = this.get('meta'); + return new SnapshotRecordArray(this, meta, options); } }); diff --git a/addon/-private/system/snapshot-record-array.js b/addon/-private/system/snapshot-record-array.js index 130cde032c2..a7ccfa8c13d 100644 --- a/addon/-private/system/snapshot-record-array.js +++ b/addon/-private/system/snapshot-record-array.js @@ -2,6 +2,8 @@ @module ember-data */ +import isEnabled from 'ember-data/-private/features'; + /** @class SnapshotRecordArray @namespace DS @@ -10,7 +12,7 @@ @param {Array} snapshots An array of snapshots @param {Object} meta */ -export default function SnapshotRecordArray(recordArray, meta, adapterOptions) { +export default function SnapshotRecordArray(recordArray, meta, options = {}) { /** An array of snapshots @private @@ -48,7 +50,11 @@ export default function SnapshotRecordArray(recordArray, meta, adapterOptions) { @property adapterOptions @type {Object} */ - this.adapterOptions = adapterOptions; + this.adapterOptions = options.adapterOptions; + + if (isEnabled('ds-finder-include')) { + this.include = options.include; + } } /** diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index c7f23c9e29f..e594b4dd252 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -4,6 +4,8 @@ import Ember from 'ember'; import EmptyObject from "ember-data/-private/system/empty-object"; +import isEnabled from 'ember-data/-private/features'; + var get = Ember.get; /** @@ -13,7 +15,7 @@ var get = Ember.get; @constructor @param {DS.Model} internalModel The model to create a snapshot from */ -export default function Snapshot(internalModel) { +export default function Snapshot(internalModel, options = {}) { this._attributes = new EmptyObject(); this._belongsToRelationships = new EmptyObject(); this._belongsToIds = new EmptyObject(); @@ -29,6 +31,17 @@ export default function Snapshot(internalModel) { this.type = internalModel.type; this.modelName = internalModel.type.modelName; + /** + A hash of adapter options + @property adapterOptions + @type {Object} + */ + this.adapterOptions = options.adapterOptions; + + if (isEnabled('ds-finder-include')) { + this.include = options.include; + } + this._changedAttributes = record.changedAttributes(); } diff --git a/config/features.json b/config/features.json index 444c96da30d..82108bcfad3 100644 --- a/config/features.json +++ b/config/features.json @@ -1,3 +1,4 @@ { + "ds-finder-include": null, "ds-references": null } diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 0f6749259d5..cb44493cd1f 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -4,6 +4,7 @@ import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; var env, store, adapter, Post, Comment, SuperUser; var passedUrl, passedVerb, passedHash; @@ -56,7 +57,7 @@ test("findRecord - basic payload", function(assert) { run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); - assert.equal(passedHash, undefined); + assert.deepEqual(passedHash.data, {}); assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); @@ -83,7 +84,7 @@ test("find - basic payload (with legacy singular name)", function(assert) { run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); - assert.equal(passedHash, undefined); + assert.deepEqual(passedHash.data, {}); assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); @@ -101,7 +102,7 @@ test("findRecord - payload with sideloaded records of the same type", function(a run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); - assert.equal(passedHash, undefined); + assert.deepEqual(passedHash.data, {}); assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); @@ -121,7 +122,7 @@ test("findRecord - payload with sideloaded records of a different type", functio run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); - assert.equal(passedHash, undefined); + assert.deepEqual(passedHash.data, {}); assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); @@ -143,7 +144,7 @@ test("findRecord - payload with an serializer-specified primary key", function(a run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); - assert.equal(passedHash, undefined); + assert.deepEqual(passedHash.data, {}); assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); @@ -167,7 +168,7 @@ test("findRecord - payload with a serializer-specified attribute mapping", funct run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); - assert.equal(passedHash, undefined); + assert.deepEqual(passedHash.data, {}); assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); @@ -175,6 +176,23 @@ test("findRecord - payload with a serializer-specified attribute mapping", funct })); }); +if (isEnabled('ds-finder-include')) { + test("findRecord - passes `include` as a query parameter to ajax", function(assert) { + adapter.ajax = function(url, verb, hash) { + assert.deepEqual(hash.data, { include: 'comments' }, + '`include` parameter sent to adapter.ajax'); + + return run(Ember.RSVP, 'resolve', { + post: { id: 1, name: 'Rails is very expensive sushi' } + }); + }; + + run(store, 'findRecord', 'post', 1, { include: 'comments' }).then(assert.wait(function() { + // Noop + })); + }); +} + test("createRecord - an empty payload is a basic success if an id was specified", function(assert) { ajaxResponse(); var post; @@ -983,7 +1001,7 @@ test("findAll - returning an array populates the array", function(assert) { store.findAll('post').then(assert.wait(function(posts) { assert.equal(passedUrl, "/posts"); assert.equal(passedVerb, "GET"); - assert.equal(passedHash.data, undefined); + assert.deepEqual(passedHash.data, {}); var post1 = store.peekRecord('post', 1); var post2 = store.peekRecord('post', 2); @@ -1028,6 +1046,23 @@ test("findAll - passes buildURL the requestType", function(assert) { })); }); +if (isEnabled('ds-finder-include')) { + test("findAll - passed `include` as a query parameter to ajax", function(assert) { + adapter.ajax = function(url, verb, hash) { + assert.deepEqual(hash.data, { include: 'comments' }, + '`include` params sent to adapter.ajax'); + + return run(Ember.RSVP, 'resolve', { + posts: [{ id: 1, name: 'Rails is very expensive sushi' }] + }); + }; + + run(store, 'findAll', 'post', { include: 'comments' }).then(assert.wait(function() { + // Noop + })); + }); +} + test("findAll - returning sideloaded data loads the data", function(assert) { ajaxResponse({ posts: [ @@ -1473,7 +1508,7 @@ test("findMany - findMany does not coalesce by default", function(assert) { }); run(post, 'get', 'comments').then(assert.wait(function(comments) { assert.equal(passedUrl, "/comments/3"); - assert.equal(passedHash, null); + assert.deepEqual(passedHash.data, {}); })); }); diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 1ccc6c3c418..008f967738f 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -4,6 +4,7 @@ import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; /* This is an integration test that tests the communication between a store @@ -1303,7 +1304,7 @@ test("record.save should pass adapterOptions to the deleteRecord method", functi }); -test("findRecord should pass adapterOptions to the find method", function(assert) { +test("store.findRecord should pass adapterOptions to adapter.findRecord", function(assert) { assert.expect(1); env.adapter.findRecord = assert.wait(function(store, type, id, snapshot) { @@ -1316,8 +1317,20 @@ test("findRecord should pass adapterOptions to the find method", function(assert }); }); +if (isEnabled('ds-finder-include')) { + test("store.findRecord should pass 'include' to adapter.findRecord", function(assert) { + assert.expect(1); -test("findAll should pass adapterOptions to the findAll method", function(assert) { + env.adapter.findRecord = assert.wait((store, type, id, snapshot) => { + assert.equal(snapshot.include, 'books', 'include passed to adapter.findRecord'); + return Ember.RSVP.resolve({ id: 1 }); + }); + + run(() => store.findRecord('person', 1, { include: 'books' })); + }); +} + +test("store.findAll should pass adapterOptions to the adapter.findAll method", function(assert) { assert.expect(1); env.adapter.findAll = assert.wait(function(store, type, sinceToken, arraySnapshot) { @@ -1331,6 +1344,18 @@ test("findAll should pass adapterOptions to the findAll method", function(assert }); }); +if (isEnabled('ds-finder-include')) { + test("store.findAll should pass 'include' to adapter.findAll", function(assert) { + assert.expect(1); + + env.adapter.findAll = assert.wait((store, type, sinceToken, arraySnapshot) => { + assert.equal(arraySnapshot.include, 'books', 'include passed to adapter.findAll'); + return Ember.RSVP.resolve([{ id: 1 }]); + }); + + run(() => store.findAll('person', { include: 'books' })); + }); +} test("An async hasMany relationship with links should not trigger shouldBackgroundReloadRecord", function(assert) { var Post = DS.Model.extend({ diff --git a/tests/unit/adapters/rest-adapter/ajax-test.js b/tests/unit/adapters/rest-adapter/ajax-test.js index ade40bc15d3..f699282cf67 100644 --- a/tests/unit/adapters/rest-adapter/ajax-test.js +++ b/tests/unit/adapters/rest-adapter/ajax-test.js @@ -35,8 +35,8 @@ test("When an id is searched, the correct url should be generated", function(ass return Ember.RSVP.resolve(); }; run(function() { - adapter.findRecord(store, Person, 1); - adapter.findRecord(store, Place, 1); + adapter.findRecord(store, Person, 1, {}); + adapter.findRecord(store, Place, 1, {}); }); }); @@ -47,7 +47,7 @@ test("id's should be sanatized", function(assert) { return Ember.RSVP.resolve(); }; run(function() { - adapter.findRecord(store, Person, '../place/1'); + adapter.findRecord(store, Person, '../place/1', {}); }); }); diff --git a/tests/unit/adapters/rest-adapter/build-query-test.js b/tests/unit/adapters/rest-adapter/build-query-test.js new file mode 100644 index 00000000000..fa098e56c2e --- /dev/null +++ b/tests/unit/adapters/rest-adapter/build-query-test.js @@ -0,0 +1,25 @@ +import { module, test } from 'qunit'; +import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; + +module("unit/adapters/rest-adapter/build-query - building queries"); + +test("buildQuery() returns an empty query when snapshot has no query params", function(assert) { + const adapter = DS.RESTAdapter.create(); + const snapshotStub = {}; + + const query = adapter.buildQuery(snapshotStub); + + assert.deepEqual(query, {}, 'query is empty'); +}); + +if (isEnabled('ds-finder-include')) { + test("buildQuery() returns query with `include` from snapshot", function(assert) { + const adapter = DS.RESTAdapter.create(); + const snapshotStub = { include: 'comments' }; + + const query = adapter.buildQuery(snapshotStub); + + assert.deepEqual(query, { include: 'comments' }, 'query includes `include`'); + }); +} From d2b03564030c82811ce46bc73b1cef8783d995f3 Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 16 Dec 2015 18:35:27 +0100 Subject: [PATCH 1289/2527] Re-enable pushing builds to S3 --- .travis.yml | 2 +- bin/publish-builds | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100755 bin/publish-builds diff --git a/.travis.yml b/.travis.yml index ad55c004238..07ac7cec96d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ script: - npm run-script test:optional-features after_success: - npm run-script production - - "./bin/bower-ember-data-build" + - "./bin/publish-builds" env: global: - BROCCOLI_ENV="production" diff --git a/bin/publish-builds b/bin/publish-builds new file mode 100755 index 00000000000..98eb397aa50 --- /dev/null +++ b/bin/publish-builds @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +echo -e "CURRENT_BRANCH: ${TRAVIS_BRANCH}\n" +echo -e "PULL_REQUEST: ${TRAVIS_PULL_REQUEST}\n" + +if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then + ./bin/publish-to-s3.js + ./bin/bower-ember-data-build +fi From f865847ebc77749660bc668dfaeb075e59da001d Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 16 Dec 2015 18:54:58 +0100 Subject: [PATCH 1290/2527] Add ember-publisher to package.json This package is needed within bin/publish-to-s3.js --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 935d77278d7..994a99ec8b7 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "ember-disable-proxy-controllers": "^1.0.0", "ember-export-application-global": "^1.0.3", "ember-inflector": "^1.9.4", + "ember-publisher": "0.0.7", "ember-try": "0.0.6", "ember-watson": "^0.7.0", "git-repo-version": "^0.3.0", From d2e0ae95adbec5941287ba34c8d9ac4dbc93be1e Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 16 Dec 2015 19:33:51 +0100 Subject: [PATCH 1291/2527] Fix paths to files which should be uploaded to S3 The generated files via `ember build --env=production` are located inside the `dist/globals` directory. --- config/s3ProjectConfig.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config/s3ProjectConfig.js b/config/s3ProjectConfig.js index e24fafd558c..7750e4bdac6 100644 --- a/config/s3ProjectConfig.js +++ b/config/s3ProjectConfig.js @@ -1,10 +1,10 @@ function fileMap(revision,tag,date) { return { - 'ember-data.js': fileObject('ember-data', '.js', 'text/javascript', revision, tag, date), - 'ember-data.js.map': fileObject('ember-data.js', '.map', 'application/json', revision, tag, date), - 'ember-data.min.js': fileObject('ember-data.min', '.js', 'text/javascript', revision, tag, date), - 'ember-data.prod.js': fileObject('ember-data.prod', '.js', 'text/javascript', revision, tag, date), - 'docs/data.json': fileObject('ember-data-docs', '.json', 'application/json', revision, tag, date) + 'globals/ember-data.js': fileObject('ember-data', '.js', 'text/javascript', revision, tag, date), + 'globals/ember-data.js.map': fileObject('ember-data.js', '.map', 'application/json', revision, tag, date), + 'globals/ember-data.min.js': fileObject('ember-data.min', '.js', 'text/javascript', revision, tag, date), + 'globals/ember-data.prod.js': fileObject('ember-data.prod', '.js', 'text/javascript', revision, tag, date), + 'docs/data.json': fileObject('ember-data-docs', '.json', 'application/json', revision, tag, date) }; } From 3958a375ba6815ec7c5da02979fde746c6e26254 Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 16 Dec 2015 23:20:39 +0100 Subject: [PATCH 1292/2527] [CLEANUP] remove unused feature-flags.js --- lib/feature-flags.js | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 lib/feature-flags.js diff --git a/lib/feature-flags.js b/lib/feature-flags.js deleted file mode 100644 index add23037452..00000000000 --- a/lib/feature-flags.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -var replace = require('broccoli-replace'); -var pickFiles = require('broccoli-static-compiler'); -var merge = require('broccoli-merge-trees'); - -module.exports = function(tree){ - var features = require('../config/features'); - var core = pickFiles(tree, { - srcDir: '/', - destDir: '/', - files: ['**/*/core.js'] - }); - var replaced = replace(tree, { - files: ['**/*.js'], - patterns: [{ - match: /EMBER_DATA_FEATURES_PLACEHOLDER/g, - replacement: JSON.stringify(features, null, 2) - }] - }); - return merge([tree, replaced], {overwrite: true}); -}; - From a41290ad7e435b37d5c9523b99aede03ce8c2f64 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 16 Dec 2015 16:35:33 -0600 Subject: [PATCH 1293/2527] don't cache length in for loops --- addon/-private/serializers/embedded-records-mixin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/serializers/embedded-records-mixin.js b/addon/-private/serializers/embedded-records-mixin.js index 579ba8331e4..c99afcb1f49 100644 --- a/addon/-private/serializers/embedded-records-mixin.js +++ b/addon/-private/serializers/embedded-records-mixin.js @@ -351,7 +351,7 @@ export default Ember.Mixin.create({ let manyArray = Ember.A(hasMany); let ret = new Array(manyArray.length); - for (let i = 0, l = manyArray.length; i < l; i++) { + for (let i = 0; i < manyArray.length; i++) { let embeddedSnapshot = manyArray[i]; let embeddedJson = embeddedSnapshot.record.serialize({ includeId: true }); this.removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, embeddedJson); From 942d1f4044d769fb34b022b22bce88b683378116 Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Wed, 16 Dec 2015 23:21:09 -0500 Subject: [PATCH 1294/2527] [CLEANUP] Separate buildURL tests from pathForType tests It was not obvious that I would find the tests for `adapter.buildURL` inside the file at `build-url-mixin/path-for-type-test.js`. I figured it might be helpful to others to move these tests to their own location. --- .../build-url-mixin/build-url-test.js | 153 ++++++++++++++++++ .../build-url-mixin/path-for-type-test.js | 128 --------------- 2 files changed, 153 insertions(+), 128 deletions(-) create mode 100644 tests/unit/adapters/build-url-mixin/build-url-test.js diff --git a/tests/unit/adapters/build-url-mixin/build-url-test.js b/tests/unit/adapters/build-url-mixin/build-url-test.js new file mode 100644 index 00000000000..866fcf787b7 --- /dev/null +++ b/tests/unit/adapters/build-url-mixin/build-url-test.js @@ -0,0 +1,153 @@ +import setupStore from 'dummy/tests/helpers/store'; +import DS from 'ember-data'; + +import { module, test } from 'qunit'; + +let adapter, env; + +module("unit/adapters/build-url-mixin/build-url - DS.BuildURLMixin#buildURL", { + beforeEach() { + const customPathForType = { + pathForType(type) { + if (type === 'rootModel') { return ''; } + return this._super(type); + } + }; + + const Adapter = DS.Adapter.extend(DS.BuildURLMixin, customPathForType); + + env = setupStore({ + adapter: Adapter + }); + + adapter = env.adapter; + } +}); + +test('buildURL - works with empty paths', function(assert) { + assert.equal(adapter.buildURL('rootModel', 1), '/1'); +}); + +test('buildURL - find requestType delegates to urlForFindRecord', function(assert) { + assert.expect(4); + let snapshotStub = { snapshot: true }; + let originalMethod = adapter.urlForFindRecord; + adapter.urlForFindRecord = function(id, type, snapshot) { + assert.equal(id, 1); + assert.equal(type, 'super-user'); + assert.equal(snapshot, snapshotStub); + return originalMethod.apply(this, arguments); + }; + assert.equal(adapter.buildURL('super-user', 1, snapshotStub, 'findRecord'), '/superUsers/1'); +}); + +test('buildURL - findAll requestType delegates to urlForFindAll', function(assert) { + assert.expect(2); + let originalMethod = adapter.urlForFindAll; + adapter.urlForFindAll = function(type) { + assert.equal(type, 'super-user'); + return originalMethod.apply(this, arguments); + }; + assert.equal(adapter.buildURL('super-user', null, null, 'findAll'), '/superUsers'); +}); + +test('buildURL - query requestType delegates to urlForQuery', function(assert) { + assert.expect(3); + let originalMethod = adapter.urlForQuery; + let queryStub = { limit: 10 }; + adapter.urlForQuery = function(query, type) { + assert.equal(query, queryStub); + assert.equal(type, 'super-user'); + return originalMethod.apply(this, arguments); + }; + assert.equal(adapter.buildURL('super-user', null, null, 'query', queryStub), '/superUsers'); +}); + +test('buildURL - queryRecord requestType delegates to urlForQueryRecord', function(assert) { + assert.expect(3); + let originalMethod = adapter.urlForQueryRecord; + let queryStub = { companyId: 10 }; + adapter.urlForQueryRecord = function(query, type) { + assert.equal(query, queryStub); + assert.equal(type, 'super-user'); + return originalMethod.apply(this, arguments); + }; + assert.equal(adapter.buildURL('super-user', null, null, 'queryRecord', queryStub), '/superUsers'); +}); + +test('buildURL - findMany requestType delegates to urlForFindMany', function(assert) { + assert.expect(3); + let originalMethod = adapter.urlForFindMany; + let idsStub = [1, 2, 3]; + adapter.urlForFindMany = function(ids, type) { + assert.equal(ids, idsStub); + assert.equal(type, 'super-user'); + return originalMethod.apply(this, arguments); + }; + assert.equal(adapter.buildURL('super-user', idsStub, null, 'findMany'), '/superUsers'); +}); + +test('buildURL - findHasMany requestType delegates to urlForFindHasMany', function(assert) { + assert.expect(3); + let originalMethod = adapter.urlForFindHasMany; + adapter.urlForFindHasMany = function(id, type) { + assert.equal(id, 1); + assert.equal(type, 'super-user'); + return originalMethod.apply(this, arguments); + }; + assert.equal(adapter.buildURL('super-user', 1, null, 'findHasMany'), '/superUsers/1'); +}); + +test('buildURL - findBelongsTo requestType delegates to urlForFindBelongsTo', function(assert) { + assert.expect(3); + let originalMethod = adapter.urlForFindBelongsTo; + adapter.urlForFindBelongsTo = function(id, type) { + assert.equal(id, 1); + assert.equal(type, 'super-user'); + return originalMethod.apply(this, arguments); + }; + assert.equal(adapter.buildURL('super-user', 1, null, 'findBelongsTo'), '/superUsers/1'); +}); + +test('buildURL - createRecord requestType delegates to urlForCreateRecord', function(assert) { + assert.expect(3); + let snapshotStub = { snapshot: true }; + let originalMethod = adapter.urlForCreateRecord; + adapter.urlForCreateRecord = function(type, snapshot) { + assert.equal(type, 'super-user'); + assert.equal(snapshot, snapshotStub); + return originalMethod.apply(this, arguments); + }; + assert.equal(adapter.buildURL('super-user', null, snapshotStub, 'createRecord'), '/superUsers'); +}); + +test('buildURL - updateRecord requestType delegates to urlForUpdateRecord', function(assert) { + assert.expect(4); + let snapshotStub = { snapshot: true }; + let originalMethod = adapter.urlForUpdateRecord; + adapter.urlForUpdateRecord = function(id, type, snapshot) { + assert.equal(id, 1); + assert.equal(type, 'super-user'); + assert.equal(snapshot, snapshotStub); + return originalMethod.apply(this, arguments); + }; + assert.equal(adapter.buildURL('super-user', 1, snapshotStub, 'updateRecord'), '/superUsers/1'); +}); + +test('buildURL - deleteRecord requestType delegates to urlForDeleteRecord', function(assert) { + assert.expect(4); + let snapshotStub = { snapshot: true }; + let originalMethod = adapter.urlForDeleteRecord; + adapter.urlForDeleteRecord = function(id, type, snapshot) { + assert.equal(id, 1); + assert.equal(type, 'super-user'); + assert.equal(snapshot, snapshotStub); + return originalMethod.apply(this, arguments); + }; + assert.equal(adapter.buildURL('super-user', 1, snapshotStub, 'deleteRecord'), '/superUsers/1'); +}); + +test('buildURL - unknown requestType', function(assert) { + assert.equal(adapter.buildURL('super-user', 1, null, 'unknown'), '/superUsers/1'); + assert.equal(adapter.buildURL('super-user', null, null, 'unknown'), '/superUsers'); +}); diff --git a/tests/unit/adapters/build-url-mixin/path-for-type-test.js b/tests/unit/adapters/build-url-mixin/path-for-type-test.js index 8aae7373d3d..f6861ac4cd6 100644 --- a/tests/unit/adapters/build-url-mixin/path-for-type-test.js +++ b/tests/unit/adapters/build-url-mixin/path-for-type-test.js @@ -37,131 +37,3 @@ test('pathForType - works with dasherized types', function(assert) { test('pathForType - works with underscored types', function(assert) { assert.equal(adapter.pathForType('super_user'), "superUsers"); }); - -test('buildURL - works with empty paths', function(assert) { - assert.equal(adapter.buildURL('rootModel', 1), "/1"); -}); - -test('buildURL - find requestType delegates to urlForFindRecord', function(assert) { - assert.expect(4); - var snapshotStub = { snapshot: true }; - var originalMethod = adapter.urlForFindRecord; - adapter.urlForFindRecord = function(id, type, snapshot) { - assert.equal(id, 1); - assert.equal(type, 'super-user'); - assert.equal(snapshot, snapshotStub); - return originalMethod.apply(this, arguments); - }; - assert.equal(adapter.buildURL('super-user', 1, snapshotStub, 'findRecord'), '/superUsers/1'); -}); - -test('buildURL - findAll requestType delegates to urlForFindAll', function(assert) { - assert.expect(2); - var originalMethod = adapter.urlForFindAll; - adapter.urlForFindAll = function(type) { - assert.equal(type, 'super-user'); - return originalMethod.apply(this, arguments); - }; - assert.equal(adapter.buildURL('super-user', null, null, 'findAll'), '/superUsers'); -}); - -test('buildURL - query requestType delegates to urlForQuery', function(assert) { - assert.expect(3); - var originalMethod = adapter.urlForQuery; - var queryStub = { limit: 10 }; - adapter.urlForQuery = function(query, type) { - assert.equal(query, queryStub); - assert.equal(type, 'super-user'); - return originalMethod.apply(this, arguments); - }; - assert.equal(adapter.buildURL('super-user', null, null, 'query', queryStub), '/superUsers'); -}); - -test('buildURL - queryRecord requestType delegates to urlForQueryRecord', function(assert) { - assert.expect(3); - var originalMethod = adapter.urlForQueryRecord; - var queryStub = { companyId: 10 }; - adapter.urlForQueryRecord = function(query, type) { - assert.equal(query, queryStub); - assert.equal(type, 'super-user'); - return originalMethod.apply(this, arguments); - }; - assert.equal(adapter.buildURL('super-user', null, null, 'queryRecord', queryStub), '/superUsers'); -}); - -test('buildURL - findMany requestType delegates to urlForFindMany', function(assert) { - assert.expect(3); - var originalMethod = adapter.urlForFindMany; - var idsStub = [1, 2, 3]; - adapter.urlForFindMany = function(ids, type) { - assert.equal(ids, idsStub); - assert.equal(type, 'super-user'); - return originalMethod.apply(this, arguments); - }; - assert.equal(adapter.buildURL('super-user', idsStub, null, 'findMany'), '/superUsers'); -}); - -test('buildURL - findHasMany requestType delegates to urlForFindHasMany', function(assert) { - assert.expect(3); - var originalMethod = adapter.urlForFindHasMany; - adapter.urlForFindHasMany = function(id, type) { - assert.equal(id, 1); - assert.equal(type, 'super-user'); - return originalMethod.apply(this, arguments); - }; - assert.equal(adapter.buildURL('super-user', 1, null, 'findHasMany'), '/superUsers/1'); -}); - -test('buildURL - findBelongsTo requestType delegates to urlForFindBelongsTo', function(assert) { - assert.expect(3); - var originalMethod = adapter.urlForFindBelongsTo; - adapter.urlForFindBelongsTo = function(id, type) { - assert.equal(id, 1); - assert.equal(type, 'super-user'); - return originalMethod.apply(this, arguments); - }; - assert.equal(adapter.buildURL('super-user', 1, null, 'findBelongsTo'), '/superUsers/1'); -}); - -test('buildURL - createRecord requestType delegates to urlForCreateRecord', function(assert) { - assert.expect(3); - var snapshotStub = { snapshot: true }; - var originalMethod = adapter.urlForCreateRecord; - adapter.urlForCreateRecord = function(type, snapshot) { - assert.equal(type, 'super-user'); - assert.equal(snapshot, snapshotStub); - return originalMethod.apply(this, arguments); - }; - assert.equal(adapter.buildURL('super-user', null, snapshotStub, 'createRecord'), '/superUsers'); -}); - -test('buildURL - updateRecord requestType delegates to urlForUpdateRecord', function(assert) { - assert.expect(4); - var snapshotStub = { snapshot: true }; - var originalMethod = adapter.urlForUpdateRecord; - adapter.urlForUpdateRecord = function(id, type, snapshot) { - assert.equal(id, 1); - assert.equal(type, 'super-user'); - assert.equal(snapshot, snapshotStub); - return originalMethod.apply(this, arguments); - }; - assert.equal(adapter.buildURL('super-user', 1, snapshotStub, 'updateRecord'), '/superUsers/1'); -}); - -test('buildURL - deleteRecord requestType delegates to urlForDeleteRecord', function(assert) { - assert.expect(4); - var snapshotStub = { snapshot: true }; - var originalMethod = adapter.urlForDeleteRecord; - adapter.urlForDeleteRecord = function(id, type, snapshot) { - assert.equal(id, 1); - assert.equal(type, 'super-user'); - assert.equal(snapshot, snapshotStub); - return originalMethod.apply(this, arguments); - }; - assert.equal(adapter.buildURL('super-user', 1, snapshotStub, 'deleteRecord'), '/superUsers/1'); -}); - -test('buildURL - unknown requestType', function(assert) { - assert.equal(adapter.buildURL('super-user', 1, null, 'unknown'), '/superUsers/1'); - assert.equal(adapter.buildURL('super-user', null, null, 'unknown'), '/superUsers'); -}); From 1eaafe4a50f2d14f150d8a9587062976f7cab9be Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Wed, 16 Dec 2015 23:38:07 -0500 Subject: [PATCH 1295/2527] Use `isEnabled` instead of `Ember.FEATURES` directly To stay consistent with the usage elsewhere --- tests/integration/relationships/belongs-to-test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index c451b096e4c..a6cfcca701c 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1,5 +1,6 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import isEnabled from 'ember-data/-private/features'; import {module, test} from 'qunit'; @@ -1122,7 +1123,7 @@ test("Updated related link should take precedence over local data", function(ass }); }); -if (Ember.FEATURES.isEnabled('ds-references')) { +if (isEnabled('ds-references')) { test("A belongsTo relationship can be reloaded using the reference if it was fetched via link", function(assert) { var done = assert.async(); From 34a245c53df292773953d8d44648f0a0f3684fce Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 17 Dec 2015 15:26:36 +0100 Subject: [PATCH 1296/2527] [FEATURE ds-references] More conistency for RecordReference Since those properties are functions on a BelongsToReference and a HasManyReference, they are changed for the RecordReference as well. This makes it consistent. --- addon/-private/system/references/record.js | 13 ++++++++++--- tests/integration/references/record-test.js | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/addon/-private/system/references/record.js b/addon/-private/system/references/record.js index 87885d7cdab..c687709e58d 100644 --- a/addon/-private/system/references/record.js +++ b/addon/-private/system/references/record.js @@ -4,14 +4,21 @@ import Reference from './reference'; var RecordReference = function(store, internalModel) { this._super$constructor(store, internalModel); this.type = internalModel.modelName; - this.id = internalModel.id; - this.remoteType = 'identity'; + this._id = internalModel.id; }; RecordReference.prototype = Object.create(Reference.prototype); RecordReference.prototype.constructor = RecordReference; RecordReference.prototype._super$constructor = Reference; +RecordReference.prototype.id = function() { + return this._id; +}; + +RecordReference.prototype.remoteType = function() { + return 'identity'; +}; + RecordReference.prototype.push = function(objectOrPromise) { return Ember.RSVP.resolve(objectOrPromise).then((data) => { var record = this.store.push(data); @@ -24,7 +31,7 @@ RecordReference.prototype.value = function() { }; RecordReference.prototype.load = function() { - return this.store.findRecord(this.type, this.id); + return this.store.findRecord(this.type, this._id); }; RecordReference.prototype.reload = function() { diff --git a/tests/integration/references/record-test.js b/tests/integration/references/record-test.js index 3522d542463..67983616b66 100644 --- a/tests/integration/references/record-test.js +++ b/tests/integration/references/record-test.js @@ -30,9 +30,9 @@ if (isEnabled("ds-references")) { test("a RecordReference can be retrieved via store.getReference(type, id)", function(assert) { var recordReference = env.store.getReference('person', 1); - assert.equal(recordReference.remoteType, 'identity'); + assert.equal(recordReference.remoteType(), 'identity'); assert.equal(recordReference.type, 'person'); - assert.equal(recordReference.id, 1); + assert.equal(recordReference.id(), 1); }); test("push(object)", function(assert) { From e0c552d25e5e2ec9bbac0705ebf138350ca755f7 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 17 Dec 2015 15:40:56 +0100 Subject: [PATCH 1297/2527] [DOC beta] Mark comments as private Otherwise YUIDoc complains that those methods don't have an item type. --- addon/-private/system/model/internal-model.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index d048d4bf011..944e93635dc 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -303,6 +303,8 @@ InternalModel.prototype = { This method is needed when data for the internal model is pushed and the pushed data might acknowledge dirty attributes as confirmed. + + @private */ updateChangedAttributes() { var changedAttributes = this.changedAttributes(); @@ -321,6 +323,8 @@ InternalModel.prototype = { /** Returns an object, whose keys are changed properties, and value is an [oldProp, newProp] array. + + @private */ changedAttributes() { var oldData = this._data; From baedc73167c88d5941b1660aa03db08367de20c2 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 17 Dec 2015 15:40:56 +0100 Subject: [PATCH 1298/2527] [CLEANUP] Update and remove obsolete comments - add @method to comment so is processed correctly by YUIDoc - remove obsolete comments - remove onsolete .gitkeep --- addon/-private/core.js | 5 ----- addon/-private/system/model/internal-model.js | 2 ++ addon/.gitkeep | 0 3 files changed, 2 insertions(+), 5 deletions(-) delete mode 100644 addon/.gitkeep diff --git a/addon/-private/core.js b/addon/-private/core.js index abff6660a3f..05c892d99cc 100644 --- a/addon/-private/core.js +++ b/addon/-private/core.js @@ -17,7 +17,6 @@ import VERSION from 'ember-data/version'; @type String @static */ -/*jshint -W079 */ var DS = Ember.Namespace.create({ VERSION: VERSION }); @@ -26,8 +25,4 @@ if (Ember.libraries) { Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); } -// var EMBER_DATA_FEATURES = EMBER_DATA_FEATURES_PLACEHOLDER; //jshint ignore: line - -// Ember.merge(Ember.FEATURES, EMBER_DATA_FEATURES); - export default DS; diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 944e93635dc..57b0163cd4b 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -304,6 +304,7 @@ InternalModel.prototype = { This method is needed when data for the internal model is pushed and the pushed data might acknowledge dirty attributes as confirmed. + @method updateChangedAttributes @private */ updateChangedAttributes() { @@ -324,6 +325,7 @@ InternalModel.prototype = { Returns an object, whose keys are changed properties, and value is an [oldProp, newProp] array. + @method changedAttributes @private */ changedAttributes() { diff --git a/addon/.gitkeep b/addon/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 From 040398e58b351147d1424f128fb458349017db62 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 16 Dec 2015 15:26:06 -0500 Subject: [PATCH 1299/2527] Only run the Ember.onload initializers in globals mode --- addon/-private/ember-initializer.js | 80 ----------------------------- addon/index.js | 3 +- app/initializers/ember-data.js | 32 ++++++++++++ lib/javascripts.js | 4 +- tests/ember-data-initializers.js | 42 +++++++++++++++ tests/test-helper.js | 1 + 6 files changed, 80 insertions(+), 82 deletions(-) delete mode 100644 addon/-private/ember-initializer.js create mode 100644 tests/ember-data-initializers.js diff --git a/addon/-private/ember-initializer.js b/addon/-private/ember-initializer.js deleted file mode 100644 index 5a0c19cb3ed..00000000000 --- a/addon/-private/ember-initializer.js +++ /dev/null @@ -1,80 +0,0 @@ -import Ember from 'ember'; -import setupContainer from 'ember-data/-private/setup-container'; -import initializeStoreService from 'ember-data/-private/instance-initializers/initialize-store-service'; - - -var K = Ember.K; - -/** - @module ember-data -*/ - -/* - - This code initializes Ember-Data onto an Ember application. - - If an Ember.js developer defines a subclass of DS.Store on their application, - as `App.StoreService` (or via a module system that resolves to `service:store`) - this code will automatically instantiate it and make it available on the - router. - - Additionally, after an application's controllers have been injected, they will - each have the store made available to them. - - For example, imagine an Ember.js application with the following classes: - - App.StoreService = DS.Store.extend({ - adapter: 'custom' - }); - - App.PostsController = Ember.ArrayController.extend({ - // ... - }); - - When the application is initialized, `App.ApplicationStore` will automatically be - instantiated, and the instance of `App.PostsController` will have its `store` - property set to that instance. - - Note that this code will only be run if the `ember-application` package is - loaded. If Ember Data is being used in an environment other than a - typical application (e.g., node.js where only `ember-runtime` is available), - this code will be ignored. -*/ - -Ember.onLoad('Ember.Application', function(Application) { - - Application.initializer({ - name: "ember-data", - initialize: setupContainer - }); - - Application.instanceInitializer({ - name: "ember-data", - initialize: initializeStoreService - }); - - // Deprecated initializers to satisfy old code that depended on them - Application.initializer({ - name: "store", - after: "ember-data", - initialize: K - }); - - Application.initializer({ - name: "transforms", - before: "store", - initialize: K - }); - - Application.initializer({ - name: "data-adapter", - before: "store", - initialize: K - }); - - Application.initializer({ - name: "injectStore", - before: "store", - initialize: K - }); -}); diff --git a/addon/index.js b/addon/index.js index e922fd73867..241ed273ffa 100644 --- a/addon/index.js +++ b/addon/index.js @@ -82,8 +82,8 @@ import { } from "ember-data/-private/transforms"; import {hasMany, belongsTo} from "ember-data/-private/system/relationships"; -import "ember-data/-private/ember-initializer"; import setupContainer from "ember-data/-private/setup-container"; +import initializeStoreService from 'ember-data/-private/instance-initializers/initialize-store-service'; import ContainerProxy from "ember-data/-private/system/container-proxy"; import Relationship from "ember-data/-private/system/relationships/state/relationship"; @@ -148,6 +148,7 @@ DS.Relationship = Relationship; DS.ContainerProxy = ContainerProxy; DS._setupContainer = setupContainer; +DS._initializeStoreService = initializeStoreService; Object.defineProperty(DS, 'normalizeModelName', { enumerable: true, diff --git a/app/initializers/ember-data.js b/app/initializers/ember-data.js index 8c6853d299d..7abc97caadf 100644 --- a/app/initializers/ember-data.js +++ b/app/initializers/ember-data.js @@ -1,5 +1,37 @@ import setupContainer from 'ember-data/-private/setup-container'; +/* + + This code initializes Ember-Data onto an Ember application. + + If an Ember.js developer defines a subclass of DS.Store on their application, + as `App.StoreService` (or via a module system that resolves to `service:store`) + this code will automatically instantiate it and make it available on the + router. + + Additionally, after an application's controllers have been injected, they will + each have the store made available to them. + + For example, imagine an Ember.js application with the following classes: + + App.StoreService = DS.Store.extend({ + adapter: 'custom' + }); + + App.PostsController = Ember.ArrayController.extend({ + // ... + }); + + When the application is initialized, `App.ApplicationStore` will automatically be + instantiated, and the instance of `App.PostsController` will have its `store` + property set to that instance. + + Note that this code will only be run if the `ember-application` package is + loaded. If Ember Data is being used in an environment other than a + typical application (e.g., node.js where only `ember-runtime` is available), + this code will be ignored. +*/ + export default { name: 'ember-data', initialize: setupContainer diff --git a/lib/javascripts.js b/lib/javascripts.js index 5ea125386f0..ae56f758d02 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -107,13 +107,15 @@ function collapse(tree, outputFileName) { var emberDataShimsPath = path.join(__dirname, 'ember-data-shims.js'); var emberDataShims = fs.readFileSync(emberDataShimsPath, { encoding: 'utf8' }); + var emberDataInitialierPath = path.join(__dirname, '../tests/ember-data-initializers.js'); + var emberDataInitialier = fs.readFileSync(emberDataInitialierPath, { encoding: 'utf8' }); var withLoader = merge([tree, loader, license, emberShim]); return concat(withLoader, { inputFiles: ['license.js', 'loader.js', '**/*.js'], outputFile: '/' + outputFileName, header: '(function(){ \n"use strict";\n', - footer: '\nrequire("ember-data");\n})();\n' + emberDataShims + footer: '\nrequire("ember-data");\n})();\n' + emberDataShims + emberDataInitialier }); } diff --git a/tests/ember-data-initializers.js b/tests/ember-data-initializers.js new file mode 100644 index 00000000000..0dc930de9c4 --- /dev/null +++ b/tests/ember-data-initializers.js @@ -0,0 +1,42 @@ +;(function() { + /* globals Ember */ + /* globals DS */ + var K = Ember.K; + Ember.onLoad('Ember.Application', function(Application) { + + Application.initializer({ + name: "ember-data", + initialize: DS._setupContainer + }); + + Application.instanceInitializer({ + name: "ember-data", + initialize: DS._initializeStoreService + }); + + // Deprecated initializers to satisfy old code that depended on them + Application.initializer({ + name: "store", + after: "ember-data", + initialize: K + }); + + Application.initializer({ + name: "transforms", + before: "store", + initialize: K + }); + + Application.initializer({ + name: "data-adapter", + before: "store", + initialize: K + }); + + Application.initializer({ + name: "injectStore", + before: "store", + initialize: K + }); + }); +})(); diff --git a/tests/test-helper.js b/tests/test-helper.js index bf6077bcb49..902dbaa3d22 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -15,6 +15,7 @@ import { } from 'dummy/tests/helpers/warns'; import addEmberAssertions from 'dummy/tests/helpers/ember-assertions'; import Ember from 'ember'; +import './ember-data-initializers'; setResolver(resolver); From 3ff8f4472214eaf1388988f3d0b4dc4fed7bd566 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 18 Dec 2015 11:22:17 -0500 Subject: [PATCH 1300/2527] [BUGFIX beta] Register the version before the DEBUG versions are printed when loading Ember Data via ember cli --- app/initializers/ember-data.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/initializers/ember-data.js b/app/initializers/ember-data.js index 8c6853d299d..f3fedd0e210 100644 --- a/app/initializers/ember-data.js +++ b/app/initializers/ember-data.js @@ -1,4 +1,5 @@ import setupContainer from 'ember-data/-private/setup-container'; +import 'ember-data/-private/core'; export default { name: 'ember-data', From a665c9827e7c943a958ebd7e18dc1852b6c40449 Mon Sep 17 00:00:00 2001 From: Damian Senn Date: Fri, 18 Dec 2015 18:20:16 +0100 Subject: [PATCH 1301/2527] Don't cache length in for loops --- .../-private/serializers/embedded-records-mixin.js | 2 +- addon/-private/serializers/json-api-serializer.js | 8 ++++---- addon/-private/system/model/errors.js | 2 +- addon/-private/system/model/internal-model.js | 2 +- addon/-private/system/record-array-manager.js | 4 ++-- .../system/relationships/state/has-many.js | 2 +- addon/-private/system/store.js | 14 +++++++------- addon/-private/system/store/finders.js | 2 +- lib/jscs-rules/disallow-space-before-semicolon.js | 2 +- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/addon/-private/serializers/embedded-records-mixin.js b/addon/-private/serializers/embedded-records-mixin.js index c99afcb1f49..accf903c404 100644 --- a/addon/-private/serializers/embedded-records-mixin.js +++ b/addon/-private/serializers/embedded-records-mixin.js @@ -463,7 +463,7 @@ export default Ember.Mixin.create({ let hasMany = new Array(relationshipHash.length); - for (let i = 0, l = relationshipHash.length; i < l; i++) { + for (let i = 0; i < relationshipHash.length; i++) { let item = relationshipHash[i]; let { data, included } = this._normalizeEmbeddedRelationship(store, relationshipMeta, item); hash.included = hash.included || []; diff --git a/addon/-private/serializers/json-api-serializer.js b/addon/-private/serializers/json-api-serializer.js index 5f56a1c65bc..f68e948bf68 100644 --- a/addon/-private/serializers/json-api-serializer.js +++ b/addon/-private/serializers/json-api-serializer.js @@ -111,7 +111,7 @@ const JSONAPISerializer = JSONSerializer.extend({ } else if (Array.isArray(documentHash.data)) { let ret = new Array(documentHash.data.length); - for (let i = 0, l = documentHash.data.length; i < l; i++) { + for (let i = 0; i < documentHash.data.length; i++) { let data = documentHash.data[i]; ret[i] = this._normalizeResourceHelper(data); } @@ -122,7 +122,7 @@ const JSONAPISerializer = JSONSerializer.extend({ if (Array.isArray(documentHash.included)) { let ret = new Array(documentHash.included.length); - for (let i = 0, l = documentHash.included.length; i < l; i++) { + for (let i = 0; i < documentHash.included.length; i++) { let included = documentHash.included[i]; ret[i] = this._normalizeResourceHelper(included); } @@ -232,7 +232,7 @@ const JSONAPISerializer = JSONSerializer.extend({ if (Array.isArray(relationshipHash.data)) { let ret = new Array(relationshipHash.data.length); - for (let i = 0, l = relationshipHash.data.length; i < l; i++) { + for (let i = 0; i < relationshipHash.data.length; i++) { let data = relationshipHash.data[i]; ret[i] = this._normalizeRelationshipDataHelper(data); } @@ -479,7 +479,7 @@ const JSONAPISerializer = JSONSerializer.extend({ let data = new Array(hasMany.length); - for (let i = 0, l = hasMany.length; i < l; i++) { + for (let i = 0; i < hasMany.length; i++) { let item = hasMany[i]; data[i] = { type: this.payloadKeyFromModelName(item.modelName), diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index aba080301d0..438178750d3 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -276,7 +276,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { let messagesArray = makeArray(messages); let _messages = new Array(messagesArray.length); - for (let i = 0, l = messagesArray.length; i < l; i++) { + for (let i = 0; i < messagesArray.length; i++) { let message = messagesArray[i]; let err = errors.findBy('message', message); if (err) { diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 57b0163cd4b..86922d00eb3 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -579,7 +579,7 @@ InternalModel.prototype = { assert("You need to pass in an array to set a hasMany property on a record", Ember.isArray(preloadValue)); let recordsToSet = new Array(preloadValue.length); - for (let i = 0, l = preloadValue.length; i < l; i++) { + for (let i = 0; i < preloadValue.length; i++) { let recordToPush = preloadValue[i]; recordsToSet[i] = this._convertStringOrNumberIntoInternalModel(recordToPush, type); } diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index d264b6f3349..c80a74e3269 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -138,7 +138,7 @@ export default Ember.Object.extend({ var records = typeMap.records; var record; - for (var i = 0, l = records.length; i < l; i++) { + for (var i = 0; i < records.length; i++) { record = records[i]; if (!record.isDeleted() && !record.isEmpty()) { @@ -164,7 +164,7 @@ export default Ember.Object.extend({ var records = typeMap.records; var record; - for (var i = 0, l = records.length; i < l; i++) { + for (var i = 0; i < records.length; i++) { record = records[i]; if (!record.isDeleted() && !record.isEmpty()) { diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index ca8bde09911..432a3ada511 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -169,7 +169,7 @@ ManyRelationship.prototype.findRecords = function() { let manyArray = this.manyArray.toArray(); let internalModels = new Array(manyArray.length); - for (let i = 0, l = manyArray.length; i < l; i++) { + for (let i = 0; i < manyArray.length; i++) { internalModels[i] = manyArray[i]._internalModel; } diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 7cae0f30564..a76fafc3f68 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -93,7 +93,7 @@ if (!Backburner.prototype.join) { return method.call(target); } else { var args = new Array(length - 2); - for (var i =0, l = length - 2; i < l; i++) { + for (var i = 0; i < args.length; i++) { args[i] = arguments[i + 2]; } return method.apply(target, args); @@ -581,7 +581,7 @@ Store = Service.extend({ assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); let promises = new Array(ids.length); - for (let i = 0, l = ids.length; i < l; i++) { + for (let i = 0; i < ids.length; i++) { promises[i] = this.findRecord(modelName, ids[i]); } @@ -614,11 +614,11 @@ Store = Service.extend({ scheduleFetchMany(records) { let internalModels = new Array(records.length); let fetches = new Array(records.length); - for (let i = 0, l = records.length; i < l; i++) { + for (let i = 0; i < records.length; i++) { internalModels[i] = records[i]._internalModel; } - for (let i = 0, l = internalModels.length; i < l; i++) { + for (let i = 0; i < internalModels.length; i++) { fetches[i] = this.scheduleFetch(internalModels[i]); } @@ -855,7 +855,7 @@ Store = Service.extend({ findMany(internalModels) { let finds = new Array(internalModels.length); - for (let i = 0, l = internalModels.length; i < l; i++) { + for (let i = 0; i < internalModels.length; i++) { finds[i] = this._findByInternalModel(internalModels[i]); } @@ -1120,7 +1120,7 @@ Store = Service.extend({ let keys = Object.keys(typeMaps); let types = new Array(keys.length); - for (let i = 0, l = keys.length; i < l; i++) { + for (let i = 0; i < keys.length; i++) { types[i] = typeMaps[keys[i]]['type'].modelName; } @@ -2120,7 +2120,7 @@ function deserializeRecordIds(store, key, relationship, ids) { assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being '${Ember.inspect(ids)}', but ${key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, isArray(ids)); let _ids = new Array(ids.length); - for (let i = 0, l = ids.length; i < l; i++) { + for (let i = 0; i < ids.length; i++) { _ids[i] = deserializeRecordId(store, key, relationship, ids[i]); } diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 6962cb1f63f..a064f700018 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -74,7 +74,7 @@ export function _findMany(adapter, store, typeClass, ids, internalModels) { let records = store.push(payload); let internalModels = new Array(records.length); - for (let i = 0, l = records.length; i < l; i++) { + for (let i = 0; i < records.length; i++) { internalModels[i] = records[i]._internalModel; } diff --git a/lib/jscs-rules/disallow-space-before-semicolon.js b/lib/jscs-rules/disallow-space-before-semicolon.js index 85554a87f22..d755672d1cf 100644 --- a/lib/jscs-rules/disallow-space-before-semicolon.js +++ b/lib/jscs-rules/disallow-space-before-semicolon.js @@ -20,7 +20,7 @@ module.exports.prototype = { check: function(file, errors) { var lines = file.getLines(); - for (var i = 0, l = lines.length; i < l; i++) { + for (var i = 0; i < lines.length; i++) { if (lines[i].match(/\s+;$/)) { errors.add('Spaces are disallowed before semicolons.', i + 1, lines[i].length - 2); } From 2ed55708ade0f535f228feeacbdb1afe2fedff22 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 18 Dec 2015 17:16:41 -0500 Subject: [PATCH 1302/2527] Add missing dependencies for the changelog script --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 11df75a7015..43af745ed31 100644 --- a/package.json +++ b/package.json @@ -67,11 +67,13 @@ "ember-try": "0.0.6", "ember-watson": "^0.7.0", "git-repo-version": "^0.3.0", + "github": "^0.2.4", "glob": "^5.0.13", "lodash.assign": "^3.2.0", "mocha": "^2.3.4", "mocha-only-detector": "0.0.2", - "rimraf": "^2.3.2" + "rimraf": "^2.3.2", + "rsvp": "^3.1.0" }, "peerDependencies": { "ember-inflector": "^1.9.4" From ba153ead65f1cfd9b85e8048f243f7afc58f7cf2 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sat, 19 Dec 2015 12:13:18 +0100 Subject: [PATCH 1303/2527] [FEATURE ds-references] bring back accidentally removed tests The tests for `Model#belongsTo()` and `Model#hasMany()` throwing an error have been accidentally removed when the `ds-references` feature has been implemented. This commit brings those tests back, so they are run when the feature is not enabled. --- tests/unit/model-test.js | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 7481316dfb8..70b1f759c12 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -3,6 +3,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import QUnit, {module, test} from 'qunit'; import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; const AssertionPrototype = QUnit.assert; @@ -418,14 +419,6 @@ test("a DS.Model can have a defaultValue without an attribute type", function(as test("Calling attr() throws a warning", function(assert) { assert.expect(1); - var Person = DS.Model.extend({ - name: DS.attr('string') - }); - - var store = createStore({ - person: Person - }); - run(function() { var person = store.createRecord('person', { id: 1, name: 'TomHuda' }); @@ -435,6 +428,32 @@ test("Calling attr() throws a warning", function(assert) { }); }); +if (!isEnabled('ds-references')) { + test("Calling belongsTo() throws a warning", function(assert) { + assert.expect(1); + + run(function() { + var person = store.createRecord('person', { id: 1, name: 'TomHuda' }); + + assert.throws(function() { + person.belongsTo(); + }, /The `belongsTo` method is not available on DS.Model, a DS.Snapshot was probably expected/, "belongsTo() throws a warning"); + }); + }); + + test("Calling hasMany() throws a warning", function(assert) { + assert.expect(1); + + run(function() { + var person = store.createRecord('person', { id: 1, name: 'TomHuda' }); + + assert.throws(function() { + person.hasMany(); + }, /The `hasMany` method is not available on DS.Model, a DS.Snapshot was probably expected/, "hasMany() throws a warning"); + }); + }); +} + test("supports pushedData in root.deleted.uncommitted", function(assert) { var record; var hash = { From 30d736224e434b68a7b0219bfe15fb8205ac9082 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sat, 19 Dec 2015 18:49:11 +0100 Subject: [PATCH 1304/2527] [CLEANUP] re-use test setup to assert correct call to adapter.ajax `adapter.ajax` is setup before the tests, so a made AJAX call can be asserted by checking `passedUrl`, `passedVerb` and `passedHash`. This commit cleans up the tests so the existig setup is re-used. --- .../integration/adapter/rest-adapter-test.js | 78 ++++++------------- 1 file changed, 24 insertions(+), 54 deletions(-) diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index cb44493cd1f..c304a1f6fa4 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -178,17 +178,12 @@ test("findRecord - payload with a serializer-specified attribute mapping", funct if (isEnabled('ds-finder-include')) { test("findRecord - passes `include` as a query parameter to ajax", function(assert) { - adapter.ajax = function(url, verb, hash) { - assert.deepEqual(hash.data, { include: 'comments' }, - '`include` parameter sent to adapter.ajax'); - - return run(Ember.RSVP, 'resolve', { - post: { id: 1, name: 'Rails is very expensive sushi' } - }); - }; + ajaxResponse({ + post: { id: 1, name: 'Rails is very expensive sushi' } + }); run(store, 'findRecord', 'post', 1, { include: 'comments' }).then(assert.wait(function() { - // Noop + assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` parameter sent to adapter.ajax'); })); }); } @@ -1048,17 +1043,12 @@ test("findAll - passes buildURL the requestType", function(assert) { if (isEnabled('ds-finder-include')) { test("findAll - passed `include` as a query parameter to ajax", function(assert) { - adapter.ajax = function(url, verb, hash) { - assert.deepEqual(hash.data, { include: 'comments' }, - '`include` params sent to adapter.ajax'); - - return run(Ember.RSVP, 'resolve', { - posts: [{ id: 1, name: 'Rails is very expensive sushi' }] - }); - }; + ajaxResponse({ + posts: [{ id: 1, name: 'Rails is very expensive sushi' }] + }); run(store, 'findAll', 'post', { include: 'comments' }).then(assert.wait(function() { - // Noop + assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` params sent to adapter.ajax'); })); }); } @@ -1117,18 +1107,12 @@ test("findAll - data is normalized through custom serializers", function(assert) }); test("query - if `sortQueryParams` option is not provided, query params are sorted alphabetically", function(assert) { - adapter.ajax = function(url, verb, hash) { - passedUrl = url; - passedVerb = verb; - passedHash = hash; - - assert.deepEqual(Object.keys(hash.data), ["in", "order", "params", "wrong"], 'query params are received in alphabetical order'); - - return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - }; + ajaxResponse({ + posts: [{ id: 1, name: "Rails is very expensive sushi" }] + }); store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(assert.wait(function() { - // Noop + assert.deepEqual(Object.keys(passedHash.data), ["in", "order", "params", "wrong"], 'query params are received in alphabetical order'); })); }); @@ -1137,45 +1121,31 @@ test("query - passes buildURL the requestType", function(assert) { return "/" + requestType + "/posts"; }; - adapter.ajax = function(url, verb, hash) { - assert.equal(url, '/query/posts'); - - return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - }; + ajaxResponse({ + posts: [{ id: 1, name: "Rails is very expensive sushi" }] + }); store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(assert.wait(function() { - // NOOP + assert.equal(passedUrl, '/query/posts'); })); }); test("query - if `sortQueryParams` is falsey, query params are not sorted at all", function(assert) { - adapter.ajax = function(url, verb, hash) { - passedUrl = url; - passedVerb = verb; - passedHash = hash; - - assert.deepEqual(Object.keys(hash.data), ["params", "in", "wrong", "order"], 'query params are received in their original order'); - - return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - }; + ajaxResponse({ + posts: [{ id: 1, name: "Rails is very expensive sushi" }] + }); adapter.sortQueryParams = null; store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(assert.wait(function() { - // Noop + assert.deepEqual(Object.keys(passedHash.data), ["params", "in", "wrong", "order"], 'query params are received in their original order'); })); }); test("query - if `sortQueryParams` is a custom function, query params passed through that function", function(assert) { - adapter.ajax = function(url, verb, hash) { - passedUrl = url; - passedVerb = verb; - passedHash = hash; - - assert.deepEqual(Object.keys(hash.data), ["wrong", "params", "order", "in"], 'query params are received in reverse alphabetical order'); - - return run(Ember.RSVP, 'resolve', { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - }; + ajaxResponse({ + posts: [{ id: 1, name: "Rails is very expensive sushi" }] + }); adapter.sortQueryParams = function(obj) { var sortedKeys = Object.keys(obj).sort().reverse(); @@ -1189,7 +1159,7 @@ test("query - if `sortQueryParams` is a custom function, query params passed thr }; store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(assert.wait(function() { - // Noop + assert.deepEqual(Object.keys(passedHash.data), ["wrong", "params", "order", "in"], 'query params are received in reverse alphabetical order'); })); }); From 99832adc0786c337c204a45a33453b9704ceb08e Mon Sep 17 00:00:00 2001 From: pangratz Date: Sun, 20 Dec 2015 14:53:24 +0100 Subject: [PATCH 1305/2527] [BUGFIX beta] Use JSON-API adapter and serializer in blueprints --- blueprints/adapter/index.js | 2 +- blueprints/serializer/files/__root__/__path__/__name__.js | 2 +- node-tests/blueprints/serializer-test.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/blueprints/adapter/index.js b/blueprints/adapter/index.js index f277c3111a6..64dbb294461 100644 --- a/blueprints/adapter/index.js +++ b/blueprints/adapter/index.js @@ -13,7 +13,7 @@ module.exports = { locals: function(options) { var adapterName = options.entity.name; - var baseClass = 'DS.RESTAdapter'; + var baseClass = 'DS.JSONAPIAdapter'; var importStatement = 'import DS from \'ember-data\';'; var isAddon = options.inRepoAddon || options.project.isEmberCLIAddon(); var relativePath = pathUtil.getRelativePath(options.entity.name); diff --git a/blueprints/serializer/files/__root__/__path__/__name__.js b/blueprints/serializer/files/__root__/__path__/__name__.js index d698ab7a750..74689dcb59a 100644 --- a/blueprints/serializer/files/__root__/__path__/__name__.js +++ b/blueprints/serializer/files/__root__/__path__/__name__.js @@ -1,4 +1,4 @@ import DS from 'ember-data'; -export default DS.RESTSerializer.extend({ +export default DS.JSONAPISerializer.extend({ }); diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index cdea2670704..a3d8cd199c1 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -12,7 +12,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { file: 'app/serializers/foo.js', contains: [ 'import DS from \'ember-data\';', - 'export default DS.RESTSerializer.extend(' + 'export default DS.JSONAPISerializer.extend(' ] }, { From 4fab9abac9e7f510a95c2a6ae8dd84a22b26f5a0 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 21 Dec 2015 10:22:27 -0500 Subject: [PATCH 1306/2527] [BUGFIX beta] Move ember-inflector to an explicit dependency for the Ember CLI build --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 11df75a7015..88b365f4f87 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "ember-cli-string-utils": "^1.0.0", "ember-cli-test-info": "^1.0.0", "ember-cli-version-checker": "^1.1.4", + "ember-inflector": "^1.9.4", "inflection": "^1.8.0", "silent-error": "^1.0.0" }, @@ -62,7 +63,6 @@ "ember-disable-prototype-extensions": "^1.0.0", "ember-disable-proxy-controllers": "^1.0.0", "ember-export-application-global": "^1.0.3", - "ember-inflector": "^1.9.4", "ember-publisher": "0.0.7", "ember-try": "0.0.6", "ember-watson": "^0.7.0", From 6951988784d05e33b2be052a759a286bb10a9066 Mon Sep 17 00:00:00 2001 From: GCorbel Date: Tue, 22 Dec 2015 06:40:14 -0500 Subject: [PATCH 1307/2527] Use keyForReliationship for belongsTo and hasMany --- addon/-private/serializers/embedded-records-mixin.js | 4 ++-- tests/integration/serializers/embedded-records-mixin-test.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addon/-private/serializers/embedded-records-mixin.js b/addon/-private/serializers/embedded-records-mixin.js index accf903c404..2d231921ad6 100644 --- a/addon/-private/serializers/embedded-records-mixin.js +++ b/addon/-private/serializers/embedded-records-mixin.js @@ -217,7 +217,7 @@ export default Ember.Mixin.create({ _serializeEmbeddedBelongsTo(snapshot, json, relationship) { let embeddedSnapshot = snapshot.belongsTo(relationship.key); - let serializedKey = this.keyForAttribute(relationship.key, 'serialize'); + let serializedKey = this.keyForRelationship(relationship.key, 'serialize'); if (!embeddedSnapshot) { json[serializedKey] = null; } else { @@ -332,7 +332,7 @@ export default Ember.Mixin.create({ }, _serializeEmbeddedHasMany(snapshot, json, relationship) { - let serializedKey = this.keyForAttribute(relationship.key, 'serialize'); + let serializedKey = this.keyForRelationship(relationship.key, 'serialize'); warn( `The embedded relationship '${serializedKey}' is undefined for '${snapshot.modelName}' with id '${snapshot.id}'. Please include it in your original payload.`, diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index c2122b0e1c0..4a7691cac1a 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -910,7 +910,7 @@ test("serialize with embedded objects and a custom keyForAttribute (hasMany rela }); env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - keyForAttribute(key) { + keyForRelationship(key) { return key + '-custom'; }, attrs: { @@ -926,7 +926,7 @@ test("serialize with embedded objects and a custom keyForAttribute (hasMany rela }); assert.deepEqual(json, { - "name-custom": "Villain League", + "name": "Villain League", "villains-custom": [{ id: get(tom, "id"), firstName: "Tom", From 72a6290b50a5e8c01034d283ce177098ee4ceb29 Mon Sep 17 00:00:00 2001 From: Julian Paas Date: Fri, 27 Nov 2015 11:58:03 -0500 Subject: [PATCH 1308/2527] [BUGFIX beta] ignores keys that are not found in the map --- addon/-private/serializers/json-serializer.js | 4 ++-- .../serializers/json-serializer-test.js | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/addon/-private/serializers/json-serializer.js b/addon/-private/serializers/json-serializer.js index b43aafb0dc9..0eb2389897a 100644 --- a/addon/-private/serializers/json-serializer.js +++ b/addon/-private/serializers/json-serializer.js @@ -728,11 +728,11 @@ export default Serializer.extend({ */ normalizeUsingDeclaredMapping(modelClass, hash) { var attrs = get(this, 'attrs'); - var payloadKey, normalizedKey, key; + var normalizedKey, payloadKey, key; if (attrs) { for (key in attrs) { - payloadKey = this._getMappedKey(key, modelClass); + normalizedKey = payloadKey = this._getMappedKey(key, modelClass); if (!hash.hasOwnProperty(payloadKey)) { continue; } diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 1af7b5f0a33..b926f828593 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -885,3 +885,22 @@ test('normalizeResponse respects `included` items (array response)', function(as { id: "3", type: "comment", attributes: { body: "comment 3" }, relationships: {} } ]); }); + +test('normalizeResponse ignores unmapped attributes', function(assert) { + env.registry.register("serializer:post", DS.JSONSerializer.extend({ + attrs: { + title: { serialize: false }, + notInMapping: { serialize: false } + } + })); + + var jsonHash = { + id: "1", + notInMapping: 'I should be ignored', + title: "Rails is omakase" + }; + + var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); + + assert.equal(post.data.attributes.title, "Rails is omakase"); +}); From 61e622722a820391ea6706ef63fb7c67f3dbc816 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 24 Dec 2015 12:11:54 +0100 Subject: [PATCH 1309/2527] [CLEANUP] use methods from utils module directly Since ember-data is a proper addon now, the utility functions in `ember-data/-private/utils` can now be imported and invoked within the tests. `assertPolymorphicType()` is now tested directly instead of relying on it being used within `Model.get('relationship').add()`. `modelHasAttributeOrRelationshipNamedType` hasn't been tested since it couldn't be imported in the tests. --- tests/unit/utils-test.js | 96 ++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 59 deletions(-) diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index 964eb6013c5..5e7009960e8 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -4,27 +4,27 @@ import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; +import Model from 'ember-data/model'; -// TODO enable import once this is possible -// import { assertPolymorphicType } from "ember-data/utils"; -// import { modelHasAttributeOrRelationshipNamedType } from "ember-data/utils"; +import { assertPolymorphicType } from "ember-data/-private/utils"; +import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; var env, User, Message, Post, Person, Video, Medium; module("unit/utils", { beforeEach() { - Person = DS.Model.extend(); - User = DS.Model.extend({ + Person = Model.extend(); + User = Model.extend({ messages: DS.hasMany('message', { async: false }) }); - Message = DS.Model.extend(); + Message = Model.extend(); Post = Message.extend({ medias: DS.hasMany('medium', { async: false }) }); Medium = Ember.Mixin.create(); - Video = DS.Model.extend(Medium); + Video = Model.extend(Medium); env = setupStore({ user: User, @@ -69,51 +69,40 @@ test("assertPolymorphicType works for subclasses", function(assert) { person = env.store.peekRecord('person', 1); }); - // TODO un-comment once we test the assertPolymorphicType directly - // var relationship = user.relationshipFor('messages'); - // user = user._internalModel; - // post = post._internalModel; - // person = person._internalModel; + var relationship = user.relationshipFor('messages'); + user = user._internalModel; + post = post._internalModel; + person = person._internalModel; try { - Ember.run(function() { - user.get('messages').addObject(post); - }); - - // TODO enable once we can do "import { assertPolymorphicType } from "ember-data/utils" - // assertPolymorphicType(user, relationship, post); + assertPolymorphicType(user, relationship, post); } catch (e) { assert.ok(false, "should not throw an error"); } assert.expectAssertion(function() { - Ember.run(function() { - user.get('messages').addObject(person); - }); - - // TODO enable once we can do "import { assertPolymorphicType } from "ember-data/utils" - // assertPolymorphicType(user, relationship, person); + assertPolymorphicType(user, relationship, person); }, "You cannot add a record of type 'person' to the 'user.messages' relationship (only 'message' allowed)"); }); -// TODO enable once we can `import x from y;` in tests -// test("modelHasAttributeOrRelationshipNamedType", function() { -// var ModelWithTypeAttribute = DS.Model.extend({ -// type: DS.attr() -// }); -// var ModelWithTypeBelongsTo = DS.Model.extend({ -// type: DS.belongsTo() -// }); -// var ModelWithTypeHasMany = DS.Model.extend({ -// type: DS.hasMany() -// }); -// -// equal(modelHasAttributeOrRelationshipNamedType(DS.Model), false); -// -// equal(modelHasAttributeOrRelationshipNamedType(ModelWithTypeAttribute), true); -// equal(modelHasAttributeOrRelationshipNamedType(ModelWithTypeBelongsTo), true); -// equal(modelHasAttributeOrRelationshipNamedType(ModelWithTypeHasMany), true); -// }); +test("modelHasAttributeOrRelationshipNamedType", function(assert) { + var ModelWithTypeAttribute = Model.extend({ + type: DS.attr() + }); + var ModelWithTypeBelongsTo = Model.extend({ + type: DS.belongsTo() + }); + var ModelWithTypeHasMany = Model.extend({ + type: DS.hasMany() + }); + + assert.equal(modelHasAttributeOrRelationshipNamedType(Model), false); + + assert.equal(modelHasAttributeOrRelationshipNamedType(ModelWithTypeAttribute), true); + assert.equal(modelHasAttributeOrRelationshipNamedType(ModelWithTypeBelongsTo), true); + assert.equal(modelHasAttributeOrRelationshipNamedType(ModelWithTypeHasMany), true); +}); + test("assertPolymorphicType works for mixins", function(assert) { var post, video, person; @@ -135,29 +124,18 @@ test("assertPolymorphicType works for mixins", function(assert) { person = env.store.peekRecord('person', 1); }); - // TODO un-comment once we test the assertPolymorphicType directly - // var relationship = post.relationshipFor('medias'); - // post = post._internalModel; - // video = video._internalModel; - // person = person._internalModel; + var relationship = post.relationshipFor('medias'); + post = post._internalModel; + video = video._internalModel; + person = person._internalModel; try { - Ember.run(function() { - post.get('medias').addObject(video); - }); - - // TODO enable once we can do "import { assertPolymorphicType } from "ember-data/utils" - // assertPolymorphicType(post, relationship, video); + assertPolymorphicType(post, relationship, video); } catch (e) { assert.ok(false, "should not throw an error"); } assert.expectAssertion(function() { - Ember.run(function() { - post.get('medias').addObject(person); - }); - - // TODO enable once we can do "import { assertPolymorphicType } from "ember-data/utils" - // assertPolymorphicType(post, relationship, person); + assertPolymorphicType(post, relationship, person); }, "You cannot add a record of type 'person' to the 'post.medias' relationship (only 'medium' allowed)"); }); From 1940dd538f90325f28dddb762887f1c24672a4c3 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sat, 26 Dec 2015 15:28:49 +0100 Subject: [PATCH 1310/2527] [CLEANUP] Remove special logic for meta.descs in tests This is no more needed since Ember.js v1.11.0 --- tests/unit/record-array-test.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/unit/record-array-test.js b/tests/unit/record-array-test.js index 0d03cb07743..140fa64b688 100644 --- a/tests/unit/record-array-test.js +++ b/tests/unit/record-array-test.js @@ -102,10 +102,6 @@ test("stops updating when destroyed", function(assert) { var store = createStore({ person: Person }); - // TODO remove once - // https://github.com/emberjs/ember.js/commit/c3f13e85a62069295965dd49ca487fe6ddba1188 - // is on the release branch - var emptyLength = Ember.meta(store).descs ? undefined : 0; var recordArray = store.peekAll('person'); run(function() { @@ -125,7 +121,7 @@ test("stops updating when destroyed", function(assert) { }); run(function() { - assert.equal(recordArray.get('length'), emptyLength, "Has no more records"); + assert.equal(recordArray.get('length'), 0, "Has no more records"); store.push({ data: { type: 'person', @@ -137,11 +133,10 @@ test("stops updating when destroyed", function(assert) { }); }); - assert.equal(recordArray.get('length'), emptyLength, "Has not been updated"); + assert.equal(recordArray.get('length'), 0, "Has not been updated"); assert.equal(recordArray.get('content'), undefined, "Has not been updated"); }); - test("a loaded record is removed from a record array when it is deleted", function(assert) { assert.expect(5); From 5ac8b810360a2ddaffd201e7d4012ecb15dae970 Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 28 Dec 2015 13:16:00 +0100 Subject: [PATCH 1311/2527] [CLEANUP] remove obsolete code within Store#willDestroy `this._containerCache` has was added in 31583db and removed from the store in ee97760. --- addon/-private/system/store.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index a76fafc3f68..6275dcad17a 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2044,13 +2044,6 @@ Store = Service.extend({ this.recordArrayManager.destroy(); this.unloadAll(); - - for (var cacheKey in this._containerCache) { - this._containerCache[cacheKey].destroy(); - delete this._containerCache[cacheKey]; - } - - delete this._containerCache; } }); From b5028e617c2f4513b42e88b5ec70649706587f58 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 30 Dec 2015 10:47:52 -0500 Subject: [PATCH 1312/2527] Simplify the urlPrefix method to make it easier to understand --- addon/-private/adapters/build-url-mixin.js | 32 ++++++++-------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index 8b5eda639ce..f67cc558e3d 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -218,41 +218,31 @@ export default Ember.Mixin.create({ @return {String} urlPrefix */ urlPrefix(path, parentURL) { - var host = get(this, 'host'); + var host = get(this, 'host') || ''; var namespace = get(this, 'namespace'); - var url = []; if (path) { // Protocol relative url - //jscs:disable disallowEmptyBlocks - if (/^\/\//.test(path)) { - // Do nothing, the full host is already included. This branch - // avoids the absolute path logic and the relative path logic. + if (/^\/\//.test(path) || /http(s)?:\/\//.test(path)) { + // Do nothing, the full host is already included. + return path; // Absolute path } else if (path.charAt(0) === '/') { - //jscs:enable disallowEmptyBlocks - if (host) { - path = path.slice(1); - url.push(host); - } + return `${host}${path}`; // Relative path - } else if (!/^http(s)?:\/\//.test(path)) { - url.push(parentURL); + } else { + return `${parentURL}/${path}`; } - } else { - if (host) { url.push(host); } - if (namespace) { url.push(namespace); } - } - - if (path) { - url.push(path); } + // No path provided + var url = []; + if (host) { url.push(host); } + if (namespace) { url.push(namespace); } return url.join('/'); }, - /** Determines the pathname for a given type. From ddc20675409ffa00c697a3f74576b3d859fb77d6 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 23 Dec 2015 09:41:51 -0500 Subject: [PATCH 1313/2527] [BUGFIX beta] Move public modules out of the `-private` folder Closes #3998 --- addon/-private/adapters.js | 4 +- addon/-private/adapters/json-api-adapter.js | 134 -- addon/-private/adapters/rest-adapter.js | 1011 ------------ addon/-private/serializers.js | 6 +- .../serializers/json-api-serializer.js | 507 ------ addon/-private/serializers/json-serializer.js | 1392 ---------------- addon/-private/serializers/rest-serializer.js | 800 ---------- addon/-private/system/adapter.js | 538 ------- addon/-private/system/debug/debug-adapter.js | 2 +- addon/-private/system/debug/debug-info.js | 2 +- addon/-private/system/model.js | 2 +- addon/-private/system/model/attributes.js | 351 ----- .../-private/system/references/belongs-to.js | 2 +- addon/-private/system/relationships.js | 13 - .../system/relationships/belongs-to.js | 2 +- addon/-private/system/relationships/ext.js | 2 +- .../-private/system/relationships/has-many.js | 2 +- addon/-private/system/store.js | 2 +- addon/-private/transforms.js | 2 +- addon/-private/transforms/base.js | 76 - addon/-private/transforms/boolean.js | 2 +- addon/-private/transforms/date.js | 2 +- addon/-private/transforms/number.js | 2 +- addon/-private/transforms/string.js | 2 +- addon/adapter.js | 539 ++++++- addon/adapters/json-api.js | 135 +- addon/adapters/rest.js | 1012 +++++++++++- addon/attr.js | 352 ++++- addon/index.js | 6 +- addon/model.js | 4 +- addon/relationships.js | 15 +- addon/serializers/json-api.js | 508 +++++- addon/serializers/json.js | 1393 ++++++++++++++++- addon/serializers/rest.js | 801 +++++++++- addon/store.js | 4 +- addon/transform.js | 77 +- 36 files changed, 4850 insertions(+), 4854 deletions(-) delete mode 100644 addon/-private/adapters/json-api-adapter.js delete mode 100644 addon/-private/adapters/rest-adapter.js delete mode 100644 addon/-private/serializers/json-api-serializer.js delete mode 100644 addon/-private/serializers/json-serializer.js delete mode 100644 addon/-private/serializers/rest-serializer.js delete mode 100644 addon/-private/system/adapter.js delete mode 100644 addon/-private/system/model/attributes.js delete mode 100644 addon/-private/system/relationships.js delete mode 100644 addon/-private/transforms/base.js diff --git a/addon/-private/adapters.js b/addon/-private/adapters.js index 53fa2f9dbf3..0b385f6f689 100644 --- a/addon/-private/adapters.js +++ b/addon/-private/adapters.js @@ -2,8 +2,8 @@ @module ember-data */ -import JSONAPIAdapter from "ember-data/-private/adapters/json-api-adapter"; -import RESTAdapter from "ember-data/-private/adapters/rest-adapter"; +import JSONAPIAdapter from "ember-data/adapters/json-api"; +import RESTAdapter from "ember-data/adapters/rest"; export { JSONAPIAdapter, diff --git a/addon/-private/adapters/json-api-adapter.js b/addon/-private/adapters/json-api-adapter.js deleted file mode 100644 index 0d21e7316e4..00000000000 --- a/addon/-private/adapters/json-api-adapter.js +++ /dev/null @@ -1,134 +0,0 @@ -/** - @module ember-data -*/ - -import Ember from 'ember'; -import RESTAdapter from "ember-data/-private/adapters/rest-adapter"; - -/** - @class JSONAPIAdapter - @constructor - @namespace DS - @extends DS.RESTAdapter -*/ -export default RESTAdapter.extend({ - defaultSerializer: '-json-api', - - /** - @method ajaxOptions - @private - @param {String} url - @param {String} type The request type GET, POST, PUT, DELETE etc. - @param {Object} options - @return {Object} - */ - ajaxOptions(url, type, options) { - let hash = this._super(...arguments); - - if (hash.contentType) { - hash.contentType = 'application/vnd.api+json'; - } - - let beforeSend = hash.beforeSend; - hash.beforeSend = function(xhr) { - xhr.setRequestHeader('Accept', 'application/vnd.api+json'); - if (beforeSend) { - beforeSend(xhr); - } - }; - - return hash; - }, - - /** - By default the JSONAPIAdapter will send each find request coming from a `store.find` - or from accessing a relationship separately to the server. If your server supports passing - ids as a query string, you can set coalesceFindRequests to true to coalesce all find requests - within a single runloop. - - For example, if you have an initial payload of: - - ```javascript - { - post: { - id: 1, - comments: [1, 2] - } - } - ``` - - By default calling `post.get('comments')` will trigger the following requests(assuming the - comments haven't been loaded before): - - ``` - GET /comments/1 - GET /comments/2 - ``` - - If you set coalesceFindRequests to `true` it will instead trigger the following request: - - ``` - GET /comments?filter[id]=1,2 - ``` - - Setting coalesceFindRequests to `true` also works for `store.find` requests and `belongsTo` - relationships accessed within the same runloop. If you set `coalesceFindRequests: true` - - ```javascript - store.findRecord('comment', 1); - store.findRecord('comment', 2); - ``` - - will also send a request to: `GET /comments?filter[id]=1,2` - - Note: Requests coalescing rely on URL building strategy. So if you override `buildURL` in your app - `groupRecordsForFindMany` more likely should be overridden as well in order for coalescing to work. - - @property coalesceFindRequests - @type {boolean} - */ - coalesceFindRequests: false, - - /** - @method findMany - @param {DS.Store} store - @param {DS.Model} type - @param {Array} ids - @param {Array} snapshots - @return {Promise} promise - */ - findMany(store, type, ids, snapshots) { - var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); - return this.ajax(url, 'GET', { data: { filter: { id: ids.join(',') } } }); - }, - - /** - @method pathForType - @param {String} modelName - @return {String} path - **/ - pathForType(modelName) { - var dasherized = Ember.String.dasherize(modelName); - return Ember.String.pluralize(dasherized); - }, - - // TODO: Remove this once we have a better way to override HTTP verbs. - /** - @method updateRecord - @param {DS.Store} store - @param {DS.Model} type - @param {DS.Snapshot} snapshot - @return {Promise} promise - */ - updateRecord(store, type, snapshot) { - var data = {}; - var serializer = store.serializerFor(type.modelName); - - serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); - - var id = snapshot.id; - var url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); - - return this.ajax(url, 'PATCH', { data: data }); - } -}); diff --git a/addon/-private/adapters/rest-adapter.js b/addon/-private/adapters/rest-adapter.js deleted file mode 100644 index f27b8e164c6..00000000000 --- a/addon/-private/adapters/rest-adapter.js +++ /dev/null @@ -1,1011 +0,0 @@ -/** - @module ember-data -*/ - -import Ember from 'ember'; -import Adapter from "ember-data/-private/system/adapter"; -import { - AdapterError, - InvalidError, - TimeoutError, - AbortError -} from 'ember-data/-private/adapters/errors'; -import EmptyObject from "ember-data/-private/system/empty-object"; -import BuildURLMixin from "ember-data/-private/adapters/build-url-mixin"; -import isEnabled from 'ember-data/-private/features'; - -const { - MapWithDefault, - get -} = Ember; - -/** - The REST adapter allows your store to communicate with an HTTP server by - transmitting JSON via XHR. Most Ember.js apps that consume a JSON API - should use the REST adapter. - - This adapter is designed around the idea that the JSON exchanged with - the server should be conventional. - - ## JSON Structure - - The REST adapter expects the JSON returned from your server to follow - these conventions. - - ### Object Root - - The JSON payload should be an object that contains the record inside a - root property. For example, in response to a `GET` request for - `/posts/1`, the JSON should look like this: - - ```js - { - "post": { - "id": 1, - "title": "I'm Running to Reform the W3C's Tag", - "author": "Yehuda Katz" - } - } - ``` - - Similarly, in response to a `GET` request for `/posts`, the JSON should - look like this: - - ```js - { - "posts": [ - { - "id": 1, - "title": "I'm Running to Reform the W3C's Tag", - "author": "Yehuda Katz" - }, - { - "id": 2, - "title": "Rails is omakase", - "author": "D2H" - } - ] - } - ``` - - Note that the object root can be pluralized for both a single-object response - and an array response: the REST adapter is not strict on this. Further, if the - HTTP server responds to a `GET` request to `/posts/1` (e.g. the response to a - `findRecord` query) with more than one object in the array, Ember Data will - only display the object with the matching ID. - - ### Conventional Names - - Attribute names in your JSON payload should be the camelCased versions of - the attributes in your Ember.js models. - - For example, if you have a `Person` model: - - ```app/models/person.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - occupation: DS.attr('string') - }); - ``` - - The JSON returned should look like this: - - ```js - { - "person": { - "id": 5, - "firstName": "Barack", - "lastName": "Obama", - "occupation": "President" - } - } - ``` - - ## Customization - - ### Endpoint path customization - - Endpoint paths can be prefixed with a `namespace` by setting the namespace - property on the adapter: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - namespace: 'api/1' - }); - ``` - Requests for the `Person` model would now target `/api/1/people/1`. - - ### Host customization - - An adapter can target other hosts by setting the `host` property. - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - host: 'https://api.example.com' - }); - ``` - - ### Headers customization - - Some APIs require HTTP headers, e.g. to provide an API key. Arbitrary - headers can be set as key/value pairs on the `RESTAdapter`'s `headers` - object and Ember Data will send them along with each ajax request. - - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - headers: { - "API_KEY": "secret key", - "ANOTHER_HEADER": "Some header value" - } - }); - ``` - - `headers` can also be used as a computed property to support dynamic - headers. In the example below, the `session` object has been - injected into an adapter by Ember's container. - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - headers: Ember.computed('session.authToken', function() { - return { - "API_KEY": this.get("session.authToken"), - "ANOTHER_HEADER": "Some header value" - }; - }) - }); - ``` - - In some cases, your dynamic headers may require data from some - object outside of Ember's observer system (for example - `document.cookie`). You can use the - [volatile](/api/classes/Ember.ComputedProperty.html#method_volatile) - function to set the property into a non-cached mode causing the headers to - be recomputed with every request. - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - headers: Ember.computed(function() { - return { - "API_KEY": Ember.get(document.cookie.match(/apiKey\=([^;]*)/), "1"), - "ANOTHER_HEADER": "Some header value" - }; - }).volatile() - }); - ``` - - @class RESTAdapter - @constructor - @namespace DS - @extends DS.Adapter - @uses DS.BuildURLMixin -*/ -export default Adapter.extend(BuildURLMixin, { - defaultSerializer: '-rest', - - /** - By default, the RESTAdapter will send the query params sorted alphabetically to the - server. - - For example: - - ```js - store.query('posts', { sort: 'price', category: 'pets' }); - ``` - - will generate a requests like this `/posts?category=pets&sort=price`, even if the - parameters were specified in a different order. - - That way the generated URL will be deterministic and that simplifies caching mechanisms - in the backend. - - Setting `sortQueryParams` to a falsey value will respect the original order. - - In case you want to sort the query parameters with a different criteria, set - `sortQueryParams` to your custom sort function. - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - sortQueryParams: function(params) { - var sortedKeys = Object.keys(params).sort().reverse(); - var len = sortedKeys.length, newParams = {}; - - for (var i = 0; i < len; i++) { - newParams[sortedKeys[i]] = params[sortedKeys[i]]; - } - return newParams; - } - }); - ``` - - @method sortQueryParams - @param {Object} obj - @return {Object} - */ - sortQueryParams(obj) { - var keys = Object.keys(obj); - var len = keys.length; - if (len < 2) { - return obj; - } - var newQueryParams = {}; - var sortedKeys = keys.sort(); - - for (var i = 0; i < len; i++) { - newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]]; - } - return newQueryParams; - }, - - /** - By default the RESTAdapter will send each find request coming from a `store.find` - or from accessing a relationship separately to the server. If your server supports passing - ids as a query string, you can set coalesceFindRequests to true to coalesce all find requests - within a single runloop. - - For example, if you have an initial payload of: - - ```javascript - { - post: { - id: 1, - comments: [1, 2] - } - } - ``` - - By default calling `post.get('comments')` will trigger the following requests(assuming the - comments haven't been loaded before): - - ``` - GET /comments/1 - GET /comments/2 - ``` - - If you set coalesceFindRequests to `true` it will instead trigger the following request: - - ``` - GET /comments?ids[]=1&ids[]=2 - ``` - - Setting coalesceFindRequests to `true` also works for `store.find` requests and `belongsTo` - relationships accessed within the same runloop. If you set `coalesceFindRequests: true` - - ```javascript - store.findRecord('comment', 1); - store.findRecord('comment', 2); - ``` - - will also send a request to: `GET /comments?ids[]=1&ids[]=2` - - Note: Requests coalescing rely on URL building strategy. So if you override `buildURL` in your app - `groupRecordsForFindMany` more likely should be overridden as well in order for coalescing to work. - - @property coalesceFindRequests - @type {boolean} - */ - coalesceFindRequests: false, - - /** - Endpoint paths can be prefixed with a `namespace` by setting the namespace - property on the adapter: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - namespace: 'api/1' - }); - ``` - - Requests for the `Post` model would now target `/api/1/post/`. - - @property namespace - @type {String} - */ - - /** - An adapter can target other hosts by setting the `host` property. - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - host: 'https://api.example.com' - }); - ``` - - Requests for the `Post` model would now target `https://api.example.com/post/`. - - @property host - @type {String} - */ - - /** - Some APIs require HTTP headers, e.g. to provide an API - key. Arbitrary headers can be set as key/value pairs on the - `RESTAdapter`'s `headers` object and Ember Data will send them - along with each ajax request. For dynamic headers see [headers - customization](/api/data/classes/DS.RESTAdapter.html#toc_headers-customization). - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - headers: { - "API_KEY": "secret key", - "ANOTHER_HEADER": "Some header value" - } - }); - ``` - - @property headers - @type {Object} - */ - - /** - Called by the store in order to fetch the JSON for a given - type and ID. - - The `findRecord` method makes an Ajax request to a URL computed by - `buildURL`, and returns a promise for the resulting payload. - - This method performs an HTTP `GET` request with the id provided as part of the query string. - - @method findRecord - @param {DS.Store} store - @param {DS.Model} type - @param {String} id - @param {DS.Snapshot} snapshot - @return {Promise} promise - */ - findRecord(store, type, id, snapshot) { - const url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); - const query = this.buildQuery(snapshot); - - return this.ajax(url, 'GET', { data: query }); - }, - - /** - Called by the store in order to fetch a JSON array for all - of the records for a given type. - - The `findAll` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a - promise for the resulting payload. - - @method findAll - @param {DS.Store} store - @param {DS.Model} type - @param {String} sinceToken - @param {DS.SnapshotRecordArray} snapshotRecordArray - @return {Promise} promise - */ - findAll(store, type, sinceToken, snapshotRecordArray) { - const url = this.buildURL(type.modelName, null, null, 'findAll'); - const query = this.buildQuery(snapshotRecordArray); - - if (sinceToken) { - query.since = sinceToken; - } - - return this.ajax(url, 'GET', { data: query }); - }, - - /** - Called by the store in order to fetch a JSON array for - the records that match a particular query. - - The `query` method makes an Ajax (HTTP GET) request to a URL - computed by `buildURL`, and returns a promise for the resulting - payload. - - The `query` argument is a simple JavaScript object that will be passed directly - to the server as parameters. - - @method query - @param {DS.Store} store - @param {DS.Model} type - @param {Object} query - @return {Promise} promise - */ - query(store, type, query) { - var url = this.buildURL(type.modelName, null, null, 'query', query); - - if (this.sortQueryParams) { - query = this.sortQueryParams(query); - } - - return this.ajax(url, 'GET', { data: query }); - }, - - /** - Called by the store in order to fetch a JSON object for - the record that matches a particular query. - - The `queryRecord` method makes an Ajax (HTTP GET) request to a URL - computed by `buildURL`, and returns a promise for the resulting - payload. - - The `query` argument is a simple JavaScript object that will be passed directly - to the server as parameters. - - @method queryRecord - @param {DS.Store} store - @param {DS.Model} type - @param {Object} query - @return {Promise} promise - */ - queryRecord(store, type, query) { - var url = this.buildURL(type.modelName, null, null, 'queryRecord', query); - - if (this.sortQueryParams) { - query = this.sortQueryParams(query); - } - - return this.ajax(url, 'GET', { data: query }); - }, - - /** - Called by the store in order to fetch several records together if `coalesceFindRequests` is true - - For example, if the original payload looks like: - - ```js - { - "id": 1, - "title": "Rails is omakase", - "comments": [ 1, 2, 3 ] - } - ``` - - The IDs will be passed as a URL-encoded Array of IDs, in this form: - - ``` - ids[]=1&ids[]=2&ids[]=3 - ``` - - Many servers, such as Rails and PHP, will automatically convert this URL-encoded array - into an Array for you on the server-side. If you want to encode the - IDs, differently, just override this (one-line) method. - - The `findMany` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a - promise for the resulting payload. - - @method findMany - @param {DS.Store} store - @param {DS.Model} type - @param {Array} ids - @param {Array} snapshots - @return {Promise} promise - */ - findMany(store, type, ids, snapshots) { - var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); - return this.ajax(url, 'GET', { data: { ids: ids } }); - }, - - /** - Called by the store in order to fetch a JSON array for - the unloaded records in a has-many relationship that were originally - specified as a URL (inside of `links`). - - For example, if your original payload looks like this: - - ```js - { - "post": { - "id": 1, - "title": "Rails is omakase", - "links": { "comments": "/posts/1/comments" } - } - } - ``` - - This method will be called with the parent record and `/posts/1/comments`. - - The `findHasMany` method will make an Ajax (HTTP GET) request to the originally specified URL. - - @method findHasMany - @param {DS.Store} store - @param {DS.Snapshot} snapshot - @param {String} url - @return {Promise} promise - */ - findHasMany(store, snapshot, url, relationship) { - var id = snapshot.id; - var type = snapshot.modelName; - - url = this.urlPrefix(url, this.buildURL(type, id, null, 'findHasMany')); - - return this.ajax(url, 'GET'); - }, - - /** - Called by the store in order to fetch a JSON array for - the unloaded records in a belongs-to relationship that were originally - specified as a URL (inside of `links`). - - For example, if your original payload looks like this: - - ```js - { - "person": { - "id": 1, - "name": "Tom Dale", - "links": { "group": "/people/1/group" } - } - } - ``` - - This method will be called with the parent record and `/people/1/group`. - - The `findBelongsTo` method will make an Ajax (HTTP GET) request to the originally specified URL. - - @method findBelongsTo - @param {DS.Store} store - @param {DS.Snapshot} snapshot - @param {String} url - @return {Promise} promise - */ - findBelongsTo(store, snapshot, url, relationship) { - var id = snapshot.id; - var type = snapshot.modelName; - - url = this.urlPrefix(url, this.buildURL(type, id, null, 'findBelongsTo')); - return this.ajax(url, 'GET'); - }, - - /** - Called by the store when a newly created record is - saved via the `save` method on a model record instance. - - The `createRecord` method serializes the record and makes an Ajax (HTTP POST) request - to a URL computed by `buildURL`. - - See `serialize` for information on how to customize the serialized form - of a record. - - @method createRecord - @param {DS.Store} store - @param {DS.Model} type - @param {DS.Snapshot} snapshot - @return {Promise} promise - */ - createRecord(store, type, snapshot) { - var data = {}; - var serializer = store.serializerFor(type.modelName); - var url = this.buildURL(type.modelName, null, snapshot, 'createRecord'); - - serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); - - return this.ajax(url, "POST", { data: data }); - }, - - /** - Called by the store when an existing record is saved - via the `save` method on a model record instance. - - The `updateRecord` method serializes the record and makes an Ajax (HTTP PUT) request - to a URL computed by `buildURL`. - - See `serialize` for information on how to customize the serialized form - of a record. - - @method updateRecord - @param {DS.Store} store - @param {DS.Model} type - @param {DS.Snapshot} snapshot - @return {Promise} promise - */ - updateRecord(store, type, snapshot) { - var data = {}; - var serializer = store.serializerFor(type.modelName); - - serializer.serializeIntoHash(data, type, snapshot); - - var id = snapshot.id; - var url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); - - return this.ajax(url, "PUT", { data: data }); - }, - - /** - Called by the store when a record is deleted. - - The `deleteRecord` method makes an Ajax (HTTP DELETE) request to a URL computed by `buildURL`. - - @method deleteRecord - @param {DS.Store} store - @param {DS.Model} type - @param {DS.Snapshot} snapshot - @return {Promise} promise - */ - deleteRecord(store, type, snapshot) { - var id = snapshot.id; - - return this.ajax(this.buildURL(type.modelName, id, snapshot, 'deleteRecord'), "DELETE"); - }, - - _stripIDFromURL(store, snapshot) { - var url = this.buildURL(snapshot.modelName, snapshot.id, snapshot); - - var expandedURL = url.split('/'); - //Case when the url is of the format ...something/:id - var lastSegment = expandedURL[expandedURL.length - 1]; - var id = snapshot.id; - if (lastSegment === id) { - expandedURL[expandedURL.length - 1] = ""; - } else if (endsWith(lastSegment, '?id=' + id)) { - //Case when the url is of the format ...something?id=:id - expandedURL[expandedURL.length - 1] = lastSegment.substring(0, lastSegment.length - id.length - 1); - } - - return expandedURL.join('/'); - }, - - // http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers - maxURLLength: 2048, - - /** - Organize records into groups, each of which is to be passed to separate - calls to `findMany`. - - This implementation groups together records that have the same base URL but - differing ids. For example `/comments/1` and `/comments/2` will be grouped together - because we know findMany can coalesce them together as `/comments?ids[]=1&ids[]=2` - - It also supports urls where ids are passed as a query param, such as `/comments?id=1` - but not those where there is more than 1 query param such as `/comments?id=2&name=David` - Currently only the query param of `id` is supported. If you need to support others, please - override this or the `_stripIDFromURL` method. - - It does not group records that have differing base urls, such as for example: `/posts/1/comments/2` - and `/posts/2/comments/3` - - @method groupRecordsForFindMany - @param {DS.Store} store - @param {Array} snapshots - @return {Array} an array of arrays of records, each of which is to be - loaded separately by `findMany`. - */ - groupRecordsForFindMany(store, snapshots) { - var groups = MapWithDefault.create({ defaultValue() { return []; } }); - var adapter = this; - var maxURLLength = this.maxURLLength; - - snapshots.forEach((snapshot) => { - var baseUrl = adapter._stripIDFromURL(store, snapshot); - groups.get(baseUrl).push(snapshot); - }); - - function splitGroupToFitInUrl(group, maxURLLength, paramNameLength) { - var baseUrl = adapter._stripIDFromURL(store, group[0]); - var idsSize = 0; - var splitGroups = [[]]; - - group.forEach((snapshot) => { - var additionalLength = encodeURIComponent(snapshot.id).length + paramNameLength; - if (baseUrl.length + idsSize + additionalLength >= maxURLLength) { - idsSize = 0; - splitGroups.push([]); - } - - idsSize += additionalLength; - - var lastGroupIndex = splitGroups.length - 1; - splitGroups[lastGroupIndex].push(snapshot); - }); - - return splitGroups; - } - - var groupsArray = []; - groups.forEach((group, key) => { - var paramNameLength = '&ids%5B%5D='.length; - var splitGroups = splitGroupToFitInUrl(group, maxURLLength, paramNameLength); - - splitGroups.forEach((splitGroup) => groupsArray.push(splitGroup)); - }); - - return groupsArray; - }, - - /** - Takes an ajax response, and returns the json payload or an error. - - By default this hook just returns the json payload passed to it. - You might want to override it in two cases: - - 1. Your API might return useful results in the response headers. - Response headers are passed in as the second argument. - - 2. Your API might return errors as successful responses with status code - 200 and an Errors text or object. You can return a `DS.InvalidError` or a - `DS.AdapterError` (or a sub class) from this hook and it will automatically - reject the promise and put your record into the invalid or error state. - - Returning a `DS.InvalidError` from this method will cause the - record to transition into the `invalid` state and make the - `errors` object available on the record. When returning an - `DS.InvalidError` the store will attempt to normalize the error data - returned from the server using the serializer's `extractErrors` - method. - - @method handleResponse - @param {Number} status - @param {Object} headers - @param {Object} payload - @param {Object} requestData - the original request information - @return {Object | DS.AdapterError} response - */ - handleResponse(status, headers, payload, requestData) { - if (this.isSuccess(status, headers, payload)) { - return payload; - } else if (this.isInvalid(status, headers, payload)) { - return new InvalidError(payload.errors); - } - - let errors = this.normalizeErrorResponse(status, headers, payload); - let detailedMessage = this.generatedDetailedMessage(status, headers, payload, requestData); - - return new AdapterError(errors, detailedMessage); - }, - - /** - Default `handleResponse` implementation uses this hook to decide if the - response is a success. - - @method isSuccess - @param {Number} status - @param {Object} headers - @param {Object} payload - @return {Boolean} - */ - isSuccess(status, headers, payload) { - return status >= 200 && status < 300 || status === 304; - }, - - /** - Default `handleResponse` implementation uses this hook to decide if the - response is a an invalid error. - - @method isInvalid - @param {Number} status - @param {Object} headers - @param {Object} payload - @return {Boolean} - */ - isInvalid(status, headers, payload) { - return status === 422; - }, - - /** - Takes a URL, an HTTP method and a hash of data, and makes an - HTTP request. - - When the server responds with a payload, Ember Data will call into `extractSingle` - or `extractArray` (depending on whether the original query was for one record or - many records). - - By default, `ajax` method has the following behavior: - - * It sets the response `dataType` to `"json"` - * If the HTTP method is not `"GET"`, it sets the `Content-Type` to be - `application/json; charset=utf-8` - * If the HTTP method is not `"GET"`, it stringifies the data passed in. The - data is the serialized record in the case of a save. - * Registers success and failure handlers. - - @method ajax - @private - @param {String} url - @param {String} type The request type GET, POST, PUT, DELETE etc. - @param {Object} options - @return {Promise} promise - */ - ajax(url, type, options) { - var adapter = this; - - var requestData = { - url: url, - method: type - }; - - return new Ember.RSVP.Promise(function(resolve, reject) { - var hash = adapter.ajaxOptions(url, type, options); - - hash.success = function(payload, textStatus, jqXHR) { - - let response = adapter.handleResponse( - jqXHR.status, - parseResponseHeaders(jqXHR.getAllResponseHeaders()), - payload, - requestData - ); - - if (response instanceof AdapterError) { - Ember.run.join(null, reject, response); - } else { - Ember.run.join(null, resolve, response); - } - }; - - hash.error = function(jqXHR, textStatus, errorThrown) { - let error; - - if (errorThrown instanceof Error) { - error = errorThrown; - } else if (textStatus === 'timeout') { - error = new TimeoutError(); - } else if (textStatus === 'abort') { - error = new AbortError(); - } else { - error = adapter.handleResponse( - jqXHR.status, - parseResponseHeaders(jqXHR.getAllResponseHeaders()), - adapter.parseErrorResponse(jqXHR.responseText) || errorThrown, - requestData - ); - } - - Ember.run.join(null, reject, error); - }; - - Ember.$.ajax(hash); - }, 'DS: RESTAdapter#ajax ' + type + ' to ' + url); - }, - - /** - @method ajaxOptions - @private - @param {String} url - @param {String} type The request type GET, POST, PUT, DELETE etc. - @param {Object} options - @return {Object} - */ - ajaxOptions(url, type, options) { - var hash = options || {}; - hash.url = url; - hash.type = type; - hash.dataType = 'json'; - hash.context = this; - - if (hash.data && type !== 'GET') { - hash.contentType = 'application/json; charset=utf-8'; - hash.data = JSON.stringify(hash.data); - } - - var headers = get(this, 'headers'); - if (headers !== undefined) { - hash.beforeSend = function (xhr) { - Object.keys(headers).forEach((key) => xhr.setRequestHeader(key, headers[key])); - }; - } - - return hash; - }, - - /** - @method parseErrorResponse - @private - @param {String} responseText - @return {Object} - */ - parseErrorResponse(responseText) { - var json = responseText; - - try { - json = Ember.$.parseJSON(responseText); - } catch (e) {} - - return json; - }, - - /** - @method normalizeErrorResponse - @private - @param {Number} status - @param {Object} headers - @param {Object} payload - @return {Object} errors payload - */ - normalizeErrorResponse(status, headers, payload) { - if (payload && typeof payload === 'object' && payload.errors) { - return payload.errors; - } else { - return [ - { - status: `${status}`, - title: "The backend responded with an error", - detail: `${payload}` - } - ]; - } - }, - - /** - Generates a detailed ("friendly") error message, with plenty - of information for debugging (good luck!) - - @method generatedDetailedMessage - @private - @param {Number} status - @param {Object} headers - @param {Object} payload - @return {Object} request information - */ - generatedDetailedMessage: function(status, headers, payload, requestData) { - var shortenedPayload; - var payloadContentType = headers["Content-Type"] || "Empty Content-Type"; - - if (payloadContentType === "text/html" && payload.length > 250) { - shortenedPayload = "[Omitted Lengthy HTML]"; - } else { - shortenedPayload = payload; - } - - var requestDescription = requestData.method + ' ' + requestData.url; - var payloadDescription = 'Payload (' + payloadContentType + ')'; - - return ['Ember Data Request ' + requestDescription + ' returned a ' + status, - payloadDescription, - shortenedPayload].join('\n'); - }, - - buildQuery(snapshot) { - const { include } = snapshot; - - let query = {}; - - if (isEnabled('ds-finder-include')) { - if (include) { - query.include = include; - } - } - - return query; - } -}); - -function parseResponseHeaders(headerStr) { - var headers = new EmptyObject(); - if (!headerStr) { return headers; } - - var headerPairs = headerStr.split('\u000d\u000a'); - for (var i = 0; i < headerPairs.length; i++) { - var headerPair = headerPairs[i]; - // Can't use split() here because it does the wrong thing - // if the header value has the string ": " in it. - var index = headerPair.indexOf('\u003a\u0020'); - if (index > 0) { - var key = headerPair.substring(0, index); - var val = headerPair.substring(index + 2); - headers[key] = val; - } - } - - return headers; -} - -//From http://stackoverflow.com/questions/280634/endswith-in-javascript -function endsWith(string, suffix) { - if (typeof String.prototype.endsWith !== 'function') { - return string.indexOf(suffix, string.length - suffix.length) !== -1; - } else { - return string.endsWith(suffix); - } -} diff --git a/addon/-private/serializers.js b/addon/-private/serializers.js index ba7feb43a4f..d79327d9d15 100644 --- a/addon/-private/serializers.js +++ b/addon/-private/serializers.js @@ -2,9 +2,9 @@ @module ember-data */ -import JSONAPISerializer from "ember-data/-private/serializers/json-api-serializer"; -import JSONSerializer from "ember-data/-private/serializers/json-serializer"; -import RESTSerializer from "ember-data/-private/serializers/rest-serializer"; +import JSONAPISerializer from "ember-data/serializers/json-api"; +import JSONSerializer from "ember-data/serializers/json"; +import RESTSerializer from "ember-data/serializers/rest"; export { JSONAPISerializer, diff --git a/addon/-private/serializers/json-api-serializer.js b/addon/-private/serializers/json-api-serializer.js deleted file mode 100644 index f68e948bf68..00000000000 --- a/addon/-private/serializers/json-api-serializer.js +++ /dev/null @@ -1,507 +0,0 @@ -/** - @module ember-data -*/ - -import Ember from 'ember'; -import { assert, runInDebug, warn } from 'ember-data/-private/debug'; -import JSONSerializer from 'ember-data/-private/serializers/json-serializer'; -import normalizeModelName from 'ember-data/-private/system/normalize-model-name'; -import { pluralize, singularize } from 'ember-inflector'; - -var dasherize = Ember.String.dasherize; - -/** - Ember Data 2.0 Serializer: - - In Ember Data a Serializer is used to serialize and deserialize - records when they are transferred in and out of an external source. - This process involves normalizing property names, transforming - attribute values and serializing relationships. - - `JSONAPISerializer` supports the http://jsonapi.org/ spec and is the - serializer recommended by Ember Data. - - This serializer normalizes a JSON API payload that looks like: - - ```js - - // models/player.js - import DS from "ember-data"; - - export default DS.Model.extend({ - name: DS.attr(), - skill: DS.attr(), - gamesPlayed: DS.attr(), - club: DS.belongsTo('club') - }); - - // models/club.js - import DS from "ember-data"; - - export default DS.Model.extend({ - name: DS.attr(), - location: DS.attr(), - players: DS.hasMany('player') - }); - ``` - - ```js - - { - "data": [ - { - "attributes": { - "name": "Benfica", - "location": "Portugal" - }, - "id": "1", - "relationships": { - "players": { - "data": [ - { - "id": "3", - "type": "players" - } - ] - } - }, - "type": "clubs" - } - ], - "included": [ - { - "attributes": { - "name": "Eusebio Silva Ferreira", - "skill": "Rocket shot", - "games-played": 431 - }, - "id": "3", - "relationships": { - "club": { - "data": { - "id": "1", - "type": "clubs" - } - } - }, - "type": "players" - } - ] - } - ``` - - to the format that the Ember Data store expects. - - @class JSONAPISerializer - @namespace DS - @extends DS.JSONSerializer -*/ -const JSONAPISerializer = JSONSerializer.extend({ - - /** - @method _normalizeDocumentHelper - @param {Object} documentHash - @return {Object} - @private - */ - _normalizeDocumentHelper(documentHash) { - - if (Ember.typeOf(documentHash.data) === 'object') { - documentHash.data = this._normalizeResourceHelper(documentHash.data); - } else if (Array.isArray(documentHash.data)) { - let ret = new Array(documentHash.data.length); - - for (let i = 0; i < documentHash.data.length; i++) { - let data = documentHash.data[i]; - ret[i] = this._normalizeResourceHelper(data); - } - - documentHash.data = ret; - } - - if (Array.isArray(documentHash.included)) { - let ret = new Array(documentHash.included.length); - - for (let i = 0; i < documentHash.included.length; i++) { - let included = documentHash.included[i]; - ret[i] = this._normalizeResourceHelper(included); - } - - documentHash.included = ret; - } - - return documentHash; - }, - - /** - @method _normalizeRelationshipDataHelper - @param {Object} relationshipDataHash - @return {Object} - @private - */ - _normalizeRelationshipDataHelper(relationshipDataHash) { - let type = this.modelNameFromPayloadKey(relationshipDataHash.type); - relationshipDataHash.type = type; - return relationshipDataHash; - }, - - /** - @method _normalizeResourceHelper - @param {Object} resourceHash - @return {Object} - @private - */ - _normalizeResourceHelper(resourceHash) { - assert(this.warnMessageForUndefinedType(), !Ember.isNone(resourceHash.type), { - id: 'ds.serializer.type-is-undefined' - }); - - let modelName = this.modelNameFromPayloadKey(resourceHash.type); - - if (!this.store._hasModelFor(modelName)) { - warn(this.warnMessageNoModelForType(modelName, resourceHash.type), false, { - id: 'ds.serializer.model-for-type-missing' - }); - return null; - } - - let modelClass = this.store.modelFor(modelName); - let serializer = this.store.serializerFor(modelName); - let { data } = serializer.normalize(modelClass, resourceHash); - return data; - }, - - /** - @method pushPayload - @param {DS.Store} store - @param {Object} payload - */ - pushPayload(store, payload) { - let normalizedPayload = this._normalizeDocumentHelper(payload); - store.push(normalizedPayload); - }, - - /** - @method _normalizeResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @param {Boolean} isSingle - @return {Object} JSON-API Document - @private - */ - _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { - let normalizedPayload = this._normalizeDocumentHelper(payload); - return normalizedPayload; - }, - - /** - @method extractAttributes - @param {DS.Model} modelClass - @param {Object} resourceHash - @return {Object} - */ - extractAttributes(modelClass, resourceHash) { - var attributes = {}; - - if (resourceHash.attributes) { - modelClass.eachAttribute((key) => { - let attributeKey = this.keyForAttribute(key, 'deserialize'); - if (resourceHash.attributes.hasOwnProperty(attributeKey)) { - attributes[key] = resourceHash.attributes[attributeKey]; - } - }); - } - - return attributes; - }, - - /** - @method extractRelationship - @param {Object} relationshipHash - @return {Object} - */ - extractRelationship(relationshipHash) { - - if (Ember.typeOf(relationshipHash.data) === 'object') { - relationshipHash.data = this._normalizeRelationshipDataHelper(relationshipHash.data); - } - - if (Array.isArray(relationshipHash.data)) { - let ret = new Array(relationshipHash.data.length); - - for (let i = 0; i < relationshipHash.data.length; i++) { - let data = relationshipHash.data[i]; - ret[i] = this._normalizeRelationshipDataHelper(data); - } - - relationshipHash.data = ret; - } - - return relationshipHash; - }, - - /** - @method extractRelationships - @param {Object} modelClass - @param {Object} resourceHash - @return {Object} - */ - extractRelationships(modelClass, resourceHash) { - let relationships = {}; - - if (resourceHash.relationships) { - modelClass.eachRelationship((key, relationshipMeta) => { - let relationshipKey = this.keyForRelationship(key, relationshipMeta.kind, 'deserialize'); - if (resourceHash.relationships.hasOwnProperty(relationshipKey)) { - - let relationshipHash = resourceHash.relationships[relationshipKey]; - relationships[key] = this.extractRelationship(relationshipHash); - - } - }); - } - - return relationships; - }, - - /** - @method _extractType - @param {DS.Model} modelClass - @param {Object} resourceHash - @return {String} - @private - */ - _extractType(modelClass, resourceHash) { - return this.modelNameFromPayloadKey(resourceHash.type); - }, - - /** - @method modelNameFromPayloadKey - @param {String} key - @return {String} the model's modelName - */ - modelNameFromPayloadKey(key) { - return singularize(normalizeModelName(key)); - }, - - /** - @method payloadKeyFromModelName - @param {String} modelName - @return {String} - */ - payloadKeyFromModelName(modelName) { - return pluralize(modelName); - }, - - /** - @method normalize - @param {DS.Model} modelClass - @param {Object} resourceHash the resource hash from the adapter - @return {Object} the normalized resource hash - */ - normalize(modelClass, resourceHash) { - if (resourceHash.attributes) { - this.normalizeUsingDeclaredMapping(modelClass, resourceHash.attributes); - } - - if (resourceHash.relationships) { - this.normalizeUsingDeclaredMapping(modelClass, resourceHash.relationships); - } - - let data = { - id: this.extractId(modelClass, resourceHash), - type: this._extractType(modelClass, resourceHash), - attributes: this.extractAttributes(modelClass, resourceHash), - relationships: this.extractRelationships(modelClass, resourceHash) - }; - - this.applyTransforms(modelClass, data.attributes); - - return { data }; - }, - - /** - `keyForAttribute` can be used to define rules for how to convert an - attribute name in your model to a key in your JSON. - By default `JSONAPISerializer` follows the format used on the examples of - http://jsonapi.org/format and uses dashes as the word separator in the JSON - attribute keys. - - This behaviour can be easily customized by extending this method. - - Example - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.JSONAPISerializer.extend({ - keyForAttribute: function(attr, method) { - return Ember.String.dasherize(attr).toUpperCase(); - } - }); - ``` - - @method keyForAttribute - @param {String} key - @param {String} method - @return {String} normalized key - */ - keyForAttribute(key, method) { - return dasherize(key); - }, - - /** - `keyForRelationship` can be used to define a custom key when - serializing and deserializing relationship properties. - By default `JSONAPISerializer` follows the format used on the examples of - http://jsonapi.org/format and uses dashes as word separators in - relationship properties. - - This behaviour can be easily customized by extending this method. - - Example - - ```app/serializers/post.js - import DS from 'ember-data'; - - export default DS.JSONAPISerializer.extend({ - keyForRelationship: function(key, relationship, method) { - return Ember.String.underscore(key); - } - }); - ``` - @method keyForRelationship - @param {String} key - @param {String} typeClass - @param {String} method - @return {String} normalized key - */ - keyForRelationship(key, typeClass, method) { - return dasherize(key); - }, - - /** - @method serialize - @param {DS.Snapshot} snapshot - @param {Object} options - @return {Object} json - */ - serialize(snapshot, options) { - let data = this._super(...arguments); - data.type = this.payloadKeyFromModelName(snapshot.modelName); - return { data }; - }, - - /** - @method serializeAttribute - @param {DS.Snapshot} snapshot - @param {Object} json - @param {String} key - @param {Object} attribute - */ - serializeAttribute(snapshot, json, key, attribute) { - const type = attribute.type; - - if (this._canSerialize(key)) { - json.attributes = json.attributes || {}; - - let value = snapshot.attr(key); - if (type) { - const transform = this.transformFor(type); - value = transform.serialize(value); - } - - let payloadKey = this._getMappedKey(key, snapshot.type); - - if (payloadKey === key) { - payloadKey = this.keyForAttribute(key, 'serialize'); - } - - json.attributes[payloadKey] = value; - } - }, - - /** - @method serializeBelongsTo - @param {DS.Snapshot} snapshot - @param {Object} json - @param {Object} relationship - */ - serializeBelongsTo(snapshot, json, relationship) { - var key = relationship.key; - - if (this._canSerialize(key)) { - var belongsTo = snapshot.belongsTo(key); - if (belongsTo !== undefined) { - - json.relationships = json.relationships || {}; - - var payloadKey = this._getMappedKey(key, snapshot.type); - if (payloadKey === key) { - payloadKey = this.keyForRelationship(key, 'belongsTo', 'serialize'); - } - - let data = null; - if (belongsTo) { - data = { - type: this.payloadKeyFromModelName(belongsTo.modelName), - id: belongsTo.id - }; - } - - json.relationships[payloadKey] = { data }; - } - } - }, - - /** - @method serializeHasMany - @param {DS.Snapshot} snapshot - @param {Object} json - @param {Object} relationship - */ - serializeHasMany(snapshot, json, relationship) { - var key = relationship.key; - - if (this._shouldSerializeHasMany(snapshot, key, relationship)) { - var hasMany = snapshot.hasMany(key); - if (hasMany !== undefined) { - - json.relationships = json.relationships || {}; - - var payloadKey = this._getMappedKey(key, snapshot.type); - if (payloadKey === key && this.keyForRelationship) { - payloadKey = this.keyForRelationship(key, 'hasMany', 'serialize'); - } - - let data = new Array(hasMany.length); - - for (let i = 0; i < hasMany.length; i++) { - let item = hasMany[i]; - data[i] = { - type: this.payloadKeyFromModelName(item.modelName), - id: item.id - }; - } - - json.relationships[payloadKey] = { data }; - } - } - } -}); - -runInDebug(function() { - JSONAPISerializer.reopen({ - warnMessageForUndefinedType() { - return 'Encountered a resource object with an undefined type (resolved resource using ' + this.constructor.toString() + ')'; - }, - warnMessageNoModelForType(modelName, originalType) { - return 'Encountered a resource object with type "' + originalType + '", but no model was found for model name "' + modelName + '" (resolved model name using ' + this.constructor.toString() + '.modelNameFromPayloadKey("' + originalType + '"))'; - } - }); -}); - -export default JSONAPISerializer; diff --git a/addon/-private/serializers/json-serializer.js b/addon/-private/serializers/json-serializer.js deleted file mode 100644 index 0eb2389897a..00000000000 --- a/addon/-private/serializers/json-serializer.js +++ /dev/null @@ -1,1392 +0,0 @@ -import Ember from 'ember'; -import { assert, warn } from 'ember-data/-private/debug'; -import Serializer from "ember-data/-private/system/serializer"; -import coerceId from "ember-data/-private/system/coerce-id"; -import normalizeModelName from "ember-data/-private/system/normalize-model-name"; -import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; - -import { - getOwner -} from 'ember-data/-private/utils'; - -import { errorsArrayToHash } from "ember-data/-private/adapters/errors"; - -var get = Ember.get; -var isNone = Ember.isNone; -var merge = Ember.merge; - -/** - Ember Data 2.0 Serializer: - - In Ember Data a Serializer is used to serialize and deserialize - records when they are transferred in and out of an external source. - This process involves normalizing property names, transforming - attribute values and serializing relationships. - - By default, Ember Data uses and recommends the `JSONAPISerializer`. - - `JSONSerializer` is useful for simpler or legacy backends that may - not support the http://jsonapi.org/ spec. - - For example, given the following `User` model and JSON payload: - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - friends: DS.hasMany('user'), - house: DS.belongsTo('location'), - - name: DS.attr('string') - }); - ``` - - ```js - { - id: 1, - name: 'Sebastian', - friends: [3, 4], - links: { - house: '/houses/lefkada' - } - } - ``` - - `JSONSerializer` will normalize the JSON payload to the JSON API format that the - Ember Data store expects. - - You can customize how JSONSerializer processes its payload by passing options in - the `attrs` hash or by subclassing the `JSONSerializer` and overriding hooks: - - - To customize how a single record is normalized, use the `normalize` hook. - - To customize how `JSONSerializer` normalizes the whole server response, use the - `normalizeResponse` hook. - - To customize how `JSONSerializer` normalizes a specific response from the server, - use one of the many specific `normalizeResponse` hooks. - - To customize how `JSONSerializer` normalizes your id, attributes or relationships, - use the `extractId`, `extractAttributes` and `extractRelationships` hooks. - - The `JSONSerializer` normalization process follows these steps: - - - `normalizeResponse` - entry method to the serializer. - - `normalizeCreateRecordResponse` - a `normalizeResponse` for a specific operation is called. - - `normalizeSingleResponse`|`normalizeArrayResponse` - for methods like `createRecord` we expect - a single record back, while for methods like `findAll` we expect multiple methods back. - - `normalize` - `normalizeArray` iterates and calls `normalize` for each of its records while `normalizeSingle` - calls it once. This is the method you most likely want to subclass. - - `extractId` | `extractAttributes` | `extractRelationships` - `normalize` delegates to these methods to - turn the record payload into the JSON API format. - - @class JSONSerializer - @namespace DS - @extends DS.Serializer -*/ -export default Serializer.extend({ - - /** - The `primaryKey` is used when serializing and deserializing - data. Ember Data always uses the `id` property to store the id of - the record. The external source may not always follow this - convention. In these cases it is useful to override the - `primaryKey` property to match the `primaryKey` of your external - store. - - Example - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - primaryKey: '_id' - }); - ``` - - @property primaryKey - @type {String} - @default 'id' - */ - primaryKey: 'id', - - /** - The `attrs` object can be used to declare a simple mapping between - property names on `DS.Model` records and payload keys in the - serialized JSON object representing the record. An object with the - property `key` can also be used to designate the attribute's key on - the response payload. - - Example - - ```app/models/person.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - occupation: DS.attr('string'), - admin: DS.attr('boolean') - }); - ``` - - ```app/serializers/person.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - attrs: { - admin: 'is_admin', - occupation: { key: 'career' } - } - }); - ``` - - You can also remove attributes by setting the `serialize` key to - `false` in your mapping object. - - Example - - ```app/serializers/person.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - attrs: { - admin: { serialize: false }, - occupation: { key: 'career' } - } - }); - ``` - - When serialized: - - ```javascript - { - "firstName": "Harry", - "lastName": "Houdini", - "career": "magician" - } - ``` - - Note that the `admin` is now not included in the payload. - - @property attrs - @type {Object} - */ - mergedProperties: ['attrs'], - - /** - Given a subclass of `DS.Model` and a JSON object this method will - iterate through each attribute of the `DS.Model` and invoke the - `DS.Transform#deserialize` method on the matching property of the - JSON object. This method is typically called after the - serializer's `normalize` method. - - @method applyTransforms - @private - @param {DS.Model} typeClass - @param {Object} data The data to transform - @return {Object} data The transformed data object - */ - applyTransforms(typeClass, data) { - typeClass.eachTransformedAttribute((key, typeClass) => { - if (!data.hasOwnProperty(key)) { return; } - - var transform = this.transformFor(typeClass); - data[key] = transform.deserialize(data[key]); - }); - - return data; - }, - - /** - The `normalizeResponse` method is used to normalize a payload from the - server to a JSON-API Document. - - http://jsonapi.org/format/#document-structure - - This method delegates to a more specific normalize method based on - the `requestType`. - - To override this method with a custom one, make sure to call - `return this._super(store, primaryModelClass, payload, id, requestType)` with your - pre-processed data. - - Here's an example of using `normalizeResponse` manually: - - ```javascript - socket.on('message', function(message) { - var data = message.data; - var modelClass = store.modelFor(data.modelName); - var serializer = store.serializerFor(data.modelName); - var json = serializer.normalizeSingleResponse(store, modelClass, data, data.id); - - store.push(normalized); - }); - ``` - - @method normalizeResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document - */ - normalizeResponse(store, primaryModelClass, payload, id, requestType) { - switch (requestType) { - case 'findRecord': - return this.normalizeFindRecordResponse(...arguments); - case 'queryRecord': - return this.normalizeQueryRecordResponse(...arguments); - case 'findAll': - return this.normalizeFindAllResponse(...arguments); - case 'findBelongsTo': - return this.normalizeFindBelongsToResponse(...arguments); - case 'findHasMany': - return this.normalizeFindHasManyResponse(...arguments); - case 'findMany': - return this.normalizeFindManyResponse(...arguments); - case 'query': - return this.normalizeQueryResponse(...arguments); - case 'createRecord': - return this.normalizeCreateRecordResponse(...arguments); - case 'deleteRecord': - return this.normalizeDeleteRecordResponse(...arguments); - case 'updateRecord': - return this.normalizeUpdateRecordResponse(...arguments); - } - }, - - /** - @method normalizeFindRecordResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document - */ - normalizeFindRecordResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeSingleResponse(...arguments); - }, - - /** - @method normalizeQueryRecordResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document - */ - normalizeQueryRecordResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeSingleResponse(...arguments); - }, - - /** - @method normalizeFindAllResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document - */ - normalizeFindAllResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeArrayResponse(...arguments); - }, - - /** - @method normalizeFindBelongsToResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document - */ - normalizeFindBelongsToResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeSingleResponse(...arguments); - }, - - /** - @method normalizeFindHasManyResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document - */ - normalizeFindHasManyResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeArrayResponse(...arguments); - }, - - /** - @method normalizeFindManyResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document - */ - normalizeFindManyResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeArrayResponse(...arguments); - }, - - /** - @method normalizeQueryResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document - */ - normalizeQueryResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeArrayResponse(...arguments); - }, - - /** - @method normalizeCreateRecordResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document - */ - normalizeCreateRecordResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeSaveResponse(...arguments); - }, - - /** - @method normalizeDeleteRecordResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document - */ - normalizeDeleteRecordResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeSaveResponse(...arguments); - }, - - /** - @method normalizeUpdateRecordResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document - */ - normalizeUpdateRecordResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeSaveResponse(...arguments); - }, - - /** - @method normalizeSaveResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document - */ - normalizeSaveResponse(store, primaryModelClass, payload, id, requestType) { - return this.normalizeSingleResponse(...arguments); - }, - - /** - @method normalizeSingleResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document - */ - normalizeSingleResponse(store, primaryModelClass, payload, id, requestType) { - return this._normalizeResponse(store, primaryModelClass, payload, id, requestType, true); - }, - - /** - @method normalizeArrayResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document - */ - normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) { - return this._normalizeResponse(store, primaryModelClass, payload, id, requestType, false); - }, - - /** - @method _normalizeResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @param {Boolean} isSingle - @return {Object} JSON-API Document - @private - */ - _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { - let documentHash = { - data: null, - included: [] - }; - - let meta = this.extractMeta(store, primaryModelClass, payload); - if (meta) { - assert('The `meta` returned from `extractMeta` has to be an object, not "' + Ember.typeOf(meta) + '".', Ember.typeOf(meta) === 'object'); - documentHash.meta = meta; - } - - if (isSingle) { - let { data, included } = this.normalize(primaryModelClass, payload); - documentHash.data = data; - if (included) { - documentHash.included = included; - } - } else { - let ret = new Array(payload.length); - for (let i = 0, l = payload.length; i < l; i++) { - let item = payload[i]; - let { data, included } = this.normalize(primaryModelClass, item); - if (included) { - documentHash.included.push(...included); - } - ret[i] = data; - } - - documentHash.data = ret; - } - - return documentHash; - }, - - - /** - Normalizes a part of the JSON payload returned by - the server. You should override this method, munge the hash - and call super if you have generic normalization to do. - - It takes the type of the record that is being normalized - (as a DS.Model class), the property where the hash was - originally found, and the hash to normalize. - - You can use this method, for example, to normalize underscored keys to camelized - or other general-purpose normalizations. - - Example - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - normalize: function(typeClass, hash) { - var fields = Ember.get(typeClass, 'fields'); - fields.forEach(function(field) { - var payloadField = Ember.String.underscore(field); - if (field === payloadField) { return; } - - hash[field] = hash[payloadField]; - delete hash[payloadField]; - }); - return this._super.apply(this, arguments); - } - }); - ``` - - @method normalize - @param {DS.Model} typeClass - @param {Object} hash - @return {Object} - */ - normalize(modelClass, resourceHash) { - let data = null; - - if (resourceHash) { - this.normalizeUsingDeclaredMapping(modelClass, resourceHash); - - data = { - id: this.extractId(modelClass, resourceHash), - type: modelClass.modelName, - attributes: this.extractAttributes(modelClass, resourceHash), - relationships: this.extractRelationships(modelClass, resourceHash) - }; - - this.applyTransforms(modelClass, data.attributes); - } - - return { data }; - }, - - /** - Returns the resource's ID. - - @method extractId - @param {Object} modelClass - @param {Object} resourceHash - @return {String} - */ - extractId(modelClass, resourceHash) { - var primaryKey = get(this, 'primaryKey'); - var id = resourceHash[primaryKey]; - return coerceId(id); - }, - - /** - Returns the resource's attributes formatted as a JSON-API "attributes object". - - http://jsonapi.org/format/#document-resource-object-attributes - - @method extractAttributes - @param {Object} modelClass - @param {Object} resourceHash - @return {Object} - */ - extractAttributes(modelClass, resourceHash) { - var attributeKey; - var attributes = {}; - - modelClass.eachAttribute((key) => { - attributeKey = this.keyForAttribute(key, 'deserialize'); - if (resourceHash.hasOwnProperty(attributeKey)) { - attributes[key] = resourceHash[attributeKey]; - } - }); - - return attributes; - }, - - /** - Returns a relationship formatted as a JSON-API "relationship object". - - http://jsonapi.org/format/#document-resource-object-relationships - - @method extractRelationship - @param {Object} relationshipModelName - @param {Object} relationshipHash - @return {Object} - */ - extractRelationship(relationshipModelName, relationshipHash) { - if (Ember.isNone(relationshipHash)) { return null; } - /* - When `relationshipHash` is an object it usually means that the relationship - is polymorphic. It could however also be embedded resources that the - EmbeddedRecordsMixin has be able to process. - */ - if (Ember.typeOf(relationshipHash) === 'object') { - if (relationshipHash.id) { - relationshipHash.id = coerceId(relationshipHash.id); - } - - const modelClass = this.store.modelFor(relationshipModelName); - if (relationshipHash.type && !modelHasAttributeOrRelationshipNamedType(modelClass)) { - relationshipHash.type = this.modelNameFromPayloadKey(relationshipHash.type); - } - return relationshipHash; - } - return { id: coerceId(relationshipHash), type: relationshipModelName }; - }, - - /** - Returns a polymorphic relationship formatted as a JSON-API "relationship object". - - http://jsonapi.org/format/#document-resource-object-relationships - - `relationshipOptions` is a hash which contains more information about the - polymorphic relationship which should be extracted: - - `resourceHash` complete hash of the resource the relationship should be - extracted from - - `relationshipKey` key under which the value for the relationship is - extracted from the resourceHash - - `relationshipMeta` meta information about the relationship - - @method extractPolymorphicRelationship - @param {Object} relationshipModelName - @param {Object} relationshipHash - @param {Object} relationshipOptions - @return {Object} - */ - extractPolymorphicRelationship(relationshipModelName, relationshipHash, relationshipOptions) { - return this.extractRelationship(relationshipModelName, relationshipHash); - }, - - /** - Returns the resource's relationships formatted as a JSON-API "relationships object". - - http://jsonapi.org/format/#document-resource-object-relationships - - @method extractRelationships - @param {Object} modelClass - @param {Object} resourceHash - @return {Object} - */ - extractRelationships(modelClass, resourceHash) { - let relationships = {}; - - modelClass.eachRelationship((key, relationshipMeta) => { - let relationship = null; - let relationshipKey = this.keyForRelationship(key, relationshipMeta.kind, 'deserialize'); - if (resourceHash.hasOwnProperty(relationshipKey)) { - let data = null; - let relationshipHash = resourceHash[relationshipKey]; - if (relationshipMeta.kind === 'belongsTo') { - if (relationshipMeta.options.polymorphic) { - // extracting a polymorphic belongsTo may need more information - // than the type and the hash (which might only be an id) for the - // relationship, hence we pass the key, resource and - // relationshipMeta too - data = this.extractPolymorphicRelationship(relationshipMeta.type, relationshipHash, { key, resourceHash, relationshipMeta }); - } else { - data = this.extractRelationship(relationshipMeta.type, relationshipHash); - } - } else if (relationshipMeta.kind === 'hasMany') { - if (!Ember.isNone(relationshipHash)) { - data = new Array(relationshipHash.length); - for (let i = 0, l = relationshipHash.length; i < l; i++) { - let item = relationshipHash[i]; - data[i] = this.extractRelationship(relationshipMeta.type, item); - } - } - } - relationship = { data }; - } - - let linkKey = this.keyForLink(key, relationshipMeta.kind); - if (resourceHash.links && resourceHash.links.hasOwnProperty(linkKey)) { - let related = resourceHash.links[linkKey]; - relationship = relationship || {}; - relationship.links = { related }; - } - - if (relationship) { - relationships[key] = relationship; - } - }); - - return relationships; - }, - - /** - @method modelNameFromPayloadKey - @param {String} key - @return {String} the model's modelName - */ - modelNameFromPayloadKey(key) { - return normalizeModelName(key); - }, - - - /** - @method normalizeAttributes - @private - */ - normalizeAttributes(typeClass, hash) { - var payloadKey; - - if (this.keyForAttribute) { - typeClass.eachAttribute((key) => { - payloadKey = this.keyForAttribute(key, 'deserialize'); - if (key === payloadKey) { return; } - if (!hash.hasOwnProperty(payloadKey)) { return; } - - hash[key] = hash[payloadKey]; - delete hash[payloadKey]; - }); - } - }, - - /** - @method normalizeRelationships - @private - */ - normalizeRelationships(typeClass, hash) { - var payloadKey; - - if (this.keyForRelationship) { - typeClass.eachRelationship((key, relationship) => { - payloadKey = this.keyForRelationship(key, relationship.kind, 'deserialize'); - if (key === payloadKey) { return; } - if (!hash.hasOwnProperty(payloadKey)) { return; } - - hash[key] = hash[payloadKey]; - delete hash[payloadKey]; - }); - } - }, - - /** - @method normalizeUsingDeclaredMapping - @private - */ - normalizeUsingDeclaredMapping(modelClass, hash) { - var attrs = get(this, 'attrs'); - var normalizedKey, payloadKey, key; - - if (attrs) { - for (key in attrs) { - normalizedKey = payloadKey = this._getMappedKey(key, modelClass); - - if (!hash.hasOwnProperty(payloadKey)) { continue; } - - if (get(modelClass, 'attributes').has(key)) { - normalizedKey = this.keyForAttribute(key); - } - - if (get(modelClass, 'relationshipsByName').has(key)) { - normalizedKey = this.keyForRelationship(key); - } - - if (payloadKey !== normalizedKey) { - hash[normalizedKey] = hash[payloadKey]; - delete hash[payloadKey]; - } - } - } - }, - - /** - Looks up the property key that was set by the custom `attr` mapping - passed to the serializer. - - @method _getMappedKey - @private - @param {String} key - @return {String} key - */ - _getMappedKey(key, modelClass) { - warn('There is no attribute or relationship with the name `' + key + '` on `' + modelClass.modelName + '`. Check your serializers attrs hash.', get(modelClass, 'attributes').has(key) || get(modelClass, 'relationshipsByName').has(key), { - id: 'ds.serializer.no-mapped-attrs-key' - }); - - var attrs = get(this, 'attrs'); - var mappedKey; - if (attrs && attrs[key]) { - mappedKey = attrs[key]; - //We need to account for both the { title: 'post_title' } and - //{ title: { key: 'post_title' }} forms - if (mappedKey.key) { - mappedKey = mappedKey.key; - } - if (typeof mappedKey === 'string') { - key = mappedKey; - } - } - - return key; - }, - - /** - Check attrs.key.serialize property to inform if the `key` - can be serialized - - @method _canSerialize - @private - @param {String} key - @return {boolean} true if the key can be serialized - */ - _canSerialize(key) { - var attrs = get(this, 'attrs'); - - return !attrs || !attrs[key] || attrs[key].serialize !== false; - }, - - /** - When attrs.key.serialize is set to true then - it takes priority over the other checks and the related - attribute/relationship will be serialized - - @method _mustSerialize - @private - @param {String} key - @return {boolean} true if the key must be serialized - */ - _mustSerialize(key) { - var attrs = get(this, 'attrs'); - - return attrs && attrs[key] && attrs[key].serialize === true; - }, - - /** - Check if the given hasMany relationship should be serialized - - @method _shouldSerializeHasMany - @private - @param {DS.Snapshot} snapshot - @param {String} key - @param {String} relationshipType - @return {boolean} true if the hasMany relationship should be serialized - */ - _shouldSerializeHasMany(snapshot, key, relationship) { - var relationshipType = snapshot.type.determineRelationshipType(relationship, this.store); - if (this._mustSerialize(key)) { - return true; - } - return this._canSerialize(key) && (relationshipType === 'manyToNone' || relationshipType === 'manyToMany'); - }, - - - // SERIALIZE - /** - Called when a record is saved in order to convert the - record into JSON. - - By default, it creates a JSON object with a key for - each attribute and belongsTo relationship. - - For example, consider this model: - - ```app/models/comment.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - title: DS.attr(), - body: DS.attr(), - - author: DS.belongsTo('user') - }); - ``` - - The default serialization would create a JSON object like: - - ```javascript - { - "title": "Rails is unagi", - "body": "Rails? Omakase? O_O", - "author": 12 - } - ``` - - By default, attributes are passed through as-is, unless - you specified an attribute type (`DS.attr('date')`). If - you specify a transform, the JavaScript value will be - serialized when inserted into the JSON hash. - - By default, belongs-to relationships are converted into - IDs when inserted into the JSON hash. - - ## IDs - - `serialize` takes an options hash with a single option: - `includeId`. If this option is `true`, `serialize` will, - by default include the ID in the JSON object it builds. - - The adapter passes in `includeId: true` when serializing - a record for `createRecord`, but not for `updateRecord`. - - ## Customization - - Your server may expect a different JSON format than the - built-in serialization format. - - In that case, you can implement `serialize` yourself and - return a JSON hash of your choosing. - - ```app/serializers/post.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - serialize: function(snapshot, options) { - var json = { - POST_TTL: snapshot.attr('title'), - POST_BDY: snapshot.attr('body'), - POST_CMS: snapshot.hasMany('comments', { ids: true }) - } - - if (options.includeId) { - json.POST_ID_ = snapshot.id; - } - - return json; - } - }); - ``` - - ## Customizing an App-Wide Serializer - - If you want to define a serializer for your entire - application, you'll probably want to use `eachAttribute` - and `eachRelationship` on the record. - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - serialize: function(snapshot, options) { - var json = {}; - - snapshot.eachAttribute(function(name) { - json[serverAttributeName(name)] = snapshot.attr(name); - }) - - snapshot.eachRelationship(function(name, relationship) { - if (relationship.kind === 'hasMany') { - json[serverHasManyName(name)] = snapshot.hasMany(name, { ids: true }); - } - }); - - if (options.includeId) { - json.ID_ = snapshot.id; - } - - return json; - } - }); - - function serverAttributeName(attribute) { - return attribute.underscore().toUpperCase(); - } - - function serverHasManyName(name) { - return serverAttributeName(name.singularize()) + "_IDS"; - } - ``` - - This serializer will generate JSON that looks like this: - - ```javascript - { - "TITLE": "Rails is omakase", - "BODY": "Yep. Omakase.", - "COMMENT_IDS": [ 1, 2, 3 ] - } - ``` - - ## Tweaking the Default JSON - - If you just want to do some small tweaks on the default JSON, - you can call super first and make the tweaks on the returned - JSON. - - ```app/serializers/post.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - serialize: function(snapshot, options) { - var json = this._super.apply(this, arguments); - - json.subject = json.title; - delete json.title; - - return json; - } - }); - ``` - - @method serialize - @param {DS.Snapshot} snapshot - @param {Object} options - @return {Object} json - */ - serialize(snapshot, options) { - var json = {}; - - if (options && options.includeId) { - var id = snapshot.id; - - if (id) { - json[get(this, 'primaryKey')] = id; - } - } - - snapshot.eachAttribute((key, attribute) => { - this.serializeAttribute(snapshot, json, key, attribute); - }); - - snapshot.eachRelationship((key, relationship) => { - if (relationship.kind === 'belongsTo') { - this.serializeBelongsTo(snapshot, json, relationship); - } else if (relationship.kind === 'hasMany') { - this.serializeHasMany(snapshot, json, relationship); - } - }); - - return json; - }, - - /** - You can use this method to customize how a serialized record is added to the complete - JSON hash to be sent to the server. By default the JSON Serializer does not namespace - the payload and just sends the raw serialized JSON object. - If your server expects namespaced keys, you should consider using the RESTSerializer. - Otherwise you can override this method to customize how the record is added to the hash. - The hash property should be modified by reference. - - For example, your server may expect underscored root objects. - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.RESTSerializer.extend({ - serializeIntoHash: function(data, type, snapshot, options) { - var root = Ember.String.decamelize(type.modelName); - data[root] = this.serialize(snapshot, options); - } - }); - ``` - - @method serializeIntoHash - @param {Object} hash - @param {DS.Model} typeClass - @param {DS.Snapshot} snapshot - @param {Object} options - */ - serializeIntoHash(hash, typeClass, snapshot, options) { - merge(hash, this.serialize(snapshot, options)); - }, - - /** - `serializeAttribute` can be used to customize how `DS.attr` - properties are serialized - - For example if you wanted to ensure all your attributes were always - serialized as properties on an `attributes` object you could - write: - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - serializeAttribute: function(snapshot, json, key, attributes) { - json.attributes = json.attributes || {}; - this._super(snapshot, json.attributes, key, attributes); - } - }); - ``` - - @method serializeAttribute - @param {DS.Snapshot} snapshot - @param {Object} json - @param {String} key - @param {Object} attribute - */ - serializeAttribute(snapshot, json, key, attribute) { - var type = attribute.type; - - if (this._canSerialize(key)) { - var value = snapshot.attr(key); - if (type) { - var transform = this.transformFor(type); - value = transform.serialize(value); - } - - // if provided, use the mapping provided by `attrs` in - // the serializer - var payloadKey = this._getMappedKey(key, snapshot.type); - - if (payloadKey === key && this.keyForAttribute) { - payloadKey = this.keyForAttribute(key, 'serialize'); - } - - json[payloadKey] = value; - } - }, - - /** - `serializeBelongsTo` can be used to customize how `DS.belongsTo` - properties are serialized. - - Example - - ```app/serializers/post.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - serializeBelongsTo: function(snapshot, json, relationship) { - var key = relationship.key; - - var belongsTo = snapshot.belongsTo(key); - - key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo", "serialize") : key; - - json[key] = Ember.isNone(belongsTo) ? belongsTo : belongsTo.record.toJSON(); - } - }); - ``` - - @method serializeBelongsTo - @param {DS.Snapshot} snapshot - @param {Object} json - @param {Object} relationship - */ - serializeBelongsTo(snapshot, json, relationship) { - var key = relationship.key; - - if (this._canSerialize(key)) { - var belongsToId = snapshot.belongsTo(key, { id: true }); - - // if provided, use the mapping provided by `attrs` in - // the serializer - var payloadKey = this._getMappedKey(key, snapshot.type); - if (payloadKey === key && this.keyForRelationship) { - payloadKey = this.keyForRelationship(key, "belongsTo", "serialize"); - } - - //Need to check whether the id is there for new&async records - if (isNone(belongsToId)) { - json[payloadKey] = null; - } else { - json[payloadKey] = belongsToId; - } - - if (relationship.options.polymorphic) { - this.serializePolymorphicType(snapshot, json, relationship); - } - } - }, - - /** - `serializeHasMany` can be used to customize how `DS.hasMany` - properties are serialized. - - Example - - ```app/serializers/post.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - serializeHasMany: function(snapshot, json, relationship) { - var key = relationship.key; - if (key === 'comments') { - return; - } else { - this._super.apply(this, arguments); - } - } - }); - ``` - - @method serializeHasMany - @param {DS.Snapshot} snapshot - @param {Object} json - @param {Object} relationship - */ - serializeHasMany(snapshot, json, relationship) { - var key = relationship.key; - - if (this._shouldSerializeHasMany(snapshot, key, relationship)) { - var hasMany = snapshot.hasMany(key, { ids: true }); - if (hasMany !== undefined) { - // if provided, use the mapping provided by `attrs` in - // the serializer - var payloadKey = this._getMappedKey(key, snapshot.type); - if (payloadKey === key && this.keyForRelationship) { - payloadKey = this.keyForRelationship(key, "hasMany", "serialize"); - } - - json[payloadKey] = hasMany; - // TODO support for polymorphic manyToNone and manyToMany relationships - } - } - }, - - /** - You can use this method to customize how polymorphic objects are - serialized. Objects are considered to be polymorphic if - `{ polymorphic: true }` is pass as the second argument to the - `DS.belongsTo` function. - - Example - - ```app/serializers/comment.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - serializePolymorphicType: function(snapshot, json, relationship) { - var key = relationship.key, - belongsTo = snapshot.belongsTo(key); - key = this.keyForAttribute ? this.keyForAttribute(key, "serialize") : key; - - if (Ember.isNone(belongsTo)) { - json[key + "_type"] = null; - } else { - json[key + "_type"] = belongsTo.modelName; - } - } - }); - ``` - - @method serializePolymorphicType - @param {DS.Snapshot} snapshot - @param {Object} json - @param {Object} relationship - */ - serializePolymorphicType: Ember.K, - - /** - `extractMeta` is used to deserialize any meta information in the - adapter payload. By default Ember Data expects meta information to - be located on the `meta` property of the payload object. - - Example - - ```app/serializers/post.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - extractMeta: function(store, typeClass, payload) { - if (payload && payload._pagination) { - store.setMetadataFor(typeClass, payload._pagination); - delete payload._pagination; - } - } - }); - ``` - - @method extractMeta - @param {DS.Store} store - @param {DS.Model} modelClass - @param {Object} payload - */ - extractMeta(store, modelClass, payload) { - if (payload && payload.hasOwnProperty('meta')) { - let meta = payload.meta; - delete payload.meta; - return meta; - } - }, - - /** - `extractErrors` is used to extract model errors when a call is made - to `DS.Model#save` which fails with an `InvalidError`. By default - Ember Data expects error information to be located on the `errors` - property of the payload object. - - Example - - ```app/serializers/post.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - extractErrors: function(store, typeClass, payload, id) { - if (payload && typeof payload === 'object' && payload._problems) { - payload = payload._problems; - this.normalizeErrors(typeClass, payload); - } - return payload; - } - }); - ``` - - @method extractErrors - @param {DS.Store} store - @param {DS.Model} typeClass - @param {Object} payload - @param {(String|Number)} id - @return {Object} json The deserialized errors - */ - extractErrors(store, typeClass, payload, id) { - if (payload && typeof payload === 'object' && payload.errors) { - payload = errorsArrayToHash(payload.errors); - - this.normalizeUsingDeclaredMapping(typeClass, payload); - - typeClass.eachAttribute((name) => { - let key = this.keyForAttribute(name, 'deserialize'); - if (key !== name && payload.hasOwnProperty(key)) { - payload[name] = payload[key]; - delete payload[key]; - } - }); - - typeClass.eachRelationship((name) => { - let key = this.keyForRelationship(name, 'deserialize'); - if (key !== name && payload.hasOwnProperty(key)) { - payload[name] = payload[key]; - delete payload[key]; - } - }); - } - - return payload; - }, - - /** - `keyForAttribute` can be used to define rules for how to convert an - attribute name in your model to a key in your JSON. - - Example - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.RESTSerializer.extend({ - keyForAttribute: function(attr, method) { - return Ember.String.underscore(attr).toUpperCase(); - } - }); - ``` - - @method keyForAttribute - @param {String} key - @param {String} method - @return {String} normalized key - */ - keyForAttribute(key, method) { - return key; - }, - - /** - `keyForRelationship` can be used to define a custom key when - serializing and deserializing relationship properties. By default - `JSONSerializer` does not provide an implementation of this method. - - Example - - ```app/serializers/post.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - keyForRelationship: function(key, relationship, method) { - return 'rel_' + Ember.String.underscore(key); - } - }); - ``` - - @method keyForRelationship - @param {String} key - @param {String} typeClass - @param {String} method - @return {String} normalized key - */ - keyForRelationship(key, typeClass, method) { - return key; - }, - - /** - `keyForLink` can be used to define a custom key when deserializing link - properties. - - @method keyForLink - @param {String} key - @param {String} kind `belongsTo` or `hasMany` - @return {String} normalized key - */ - keyForLink(key, kind) { - return key; - }, - - // HELPERS - - /** - @method transformFor - @private - @param {String} attributeType - @param {Boolean} skipAssertion - @return {DS.Transform} transform - */ - transformFor(attributeType, skipAssertion) { - var transform = getOwner(this).lookup('transform:' + attributeType); - - assert("Unable to find transform for '" + attributeType + "'", skipAssertion || !!transform); - - return transform; - } -}); diff --git a/addon/-private/serializers/rest-serializer.js b/addon/-private/serializers/rest-serializer.js deleted file mode 100644 index dc2bcb4d800..00000000000 --- a/addon/-private/serializers/rest-serializer.js +++ /dev/null @@ -1,800 +0,0 @@ -/** - @module ember-data -*/ - -import Ember from 'ember'; -import { assert, deprecate, runInDebug, warn } from "ember-data/-private/debug"; -import JSONSerializer from "ember-data/-private/serializers/json-serializer"; -import normalizeModelName from "ember-data/-private/system/normalize-model-name"; -import {singularize} from "ember-inflector"; -import coerceId from "ember-data/-private/system/coerce-id"; -import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; - -var camelize = Ember.String.camelize; - -/** - Normally, applications will use the `RESTSerializer` by implementing - the `normalize` method and individual normalizations under - `normalizeHash`. - - This allows you to do whatever kind of munging you need, and is - especially useful if your server is inconsistent and you need to - do munging differently for many different kinds of responses. - - See the `normalize` documentation for more information. - - ## Across the Board Normalization - - There are also a number of hooks that you might find useful to define - across-the-board rules for your payload. These rules will be useful - if your server is consistent, or if you're building an adapter for - an infrastructure service, like Parse, and want to encode service - conventions. - - For example, if all of your keys are underscored and all-caps, but - otherwise consistent with the names you use in your models, you - can implement across-the-board rules for how to convert an attribute - name in your model to a key in your JSON. - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.RESTSerializer.extend({ - keyForAttribute: function(attr, method) { - return Ember.String.underscore(attr).toUpperCase(); - } - }); - ``` - - You can also implement `keyForRelationship`, which takes the name - of the relationship as the first parameter, the kind of - relationship (`hasMany` or `belongsTo`) as the second parameter, and - the method (`serialize` or `deserialize`) as the third parameter. - - @class RESTSerializer - @namespace DS - @extends DS.JSONSerializer -*/ -var RESTSerializer = JSONSerializer.extend({ - - /** - `keyForPolymorphicType` can be used to define a custom key when - serializing and deserializing a polymorphic type. By default, the - returned key is `${key}Type`. - - Example - - ```app/serializers/post.js - import DS from 'ember-data'; - - export default DS.RESTSerializer.extend({ - keyForPolymorphicType: function(key, relationship) { - var relationshipKey = this.keyForRelationship(key); - - return 'type-' + relationshipKey; - } - }); - ``` - - @method keyForPolymorphicType - @param {String} key - @param {String} typeClass - @param {String} method - @return {String} normalized key - */ - keyForPolymorphicType(key, typeClass, method) { - var relationshipKey = this.keyForRelationship(key); - - return `${relationshipKey}Type`; - }, - - /** - Normalizes a part of the JSON payload returned by - the server. You should override this method, munge the hash - and call super if you have generic normalization to do. - - It takes the type of the record that is being normalized - (as a DS.Model class), the property where the hash was - originally found, and the hash to normalize. - - For example, if you have a payload that looks like this: - - ```js - { - "post": { - "id": 1, - "title": "Rails is omakase", - "comments": [ 1, 2 ] - }, - "comments": [{ - "id": 1, - "body": "FIRST" - }, { - "id": 2, - "body": "Rails is unagi" - }] - } - ``` - - The `normalize` method will be called three times: - - * With `App.Post`, `"posts"` and `{ id: 1, title: "Rails is omakase", ... }` - * With `App.Comment`, `"comments"` and `{ id: 1, body: "FIRST" }` - * With `App.Comment`, `"comments"` and `{ id: 2, body: "Rails is unagi" }` - - You can use this method, for example, to normalize underscored keys to camelized - or other general-purpose normalizations. - - If you want to do normalizations specific to some part of the payload, you - can specify those under `normalizeHash`. - - For example, if the `IDs` under `"comments"` are provided as `_id` instead of - `id`, you can specify how to normalize just the comments: - - ```app/serializers/post.js - import DS from 'ember-data'; - - export default DS.RESTSerializer.extend({ - normalizeHash: { - comments: function(hash) { - hash.id = hash._id; - delete hash._id; - return hash; - } - } - }); - ``` - - The key under `normalizeHash` is just the original key that was in the original - payload. - - @method normalize - @param {DS.Model} modelClass - @param {Object} resourceHash - @param {String} prop - @return {Object} - */ - normalize(modelClass, resourceHash, prop) { - if (this.normalizeHash && this.normalizeHash[prop]) { - this.normalizeHash[prop](resourceHash); - } - return this._super(modelClass, resourceHash, prop); - }, - - /** - Normalizes an array of resource payloads and returns a JSON-API Document - with primary data and, if any, included data as `{ data, included }`. - - @method _normalizeArray - @param {DS.Store} store - @param {String} modelName - @param {Object} arrayHash - @param {String} prop - @return {Object} - @private - */ - _normalizeArray(store, modelName, arrayHash, prop) { - let documentHash = { - data: [], - included: [] - }; - - let modelClass = store.modelFor(modelName); - let serializer = store.serializerFor(modelName); - - /*jshint loopfunc:true*/ - arrayHash.forEach((hash) => { - let { data, included } = this._normalizePolymorphicRecord(store, hash, prop, modelClass, serializer); - documentHash.data.push(data); - if (included) { - documentHash.included.push(...included); - } - }); - - return documentHash; - }, - - _normalizePolymorphicRecord(store, hash, prop, primaryModelClass, primarySerializer) { - let serializer, modelClass; - const primaryHasTypeAttribute = modelHasAttributeOrRelationshipNamedType(primaryModelClass); - // Support polymorphic records in async relationships - if (!primaryHasTypeAttribute && hash.type && store._hasModelFor(this.modelNameFromPayloadKey(hash.type))) { - serializer = store.serializerFor(hash.type); - modelClass = store.modelFor(hash.type); - } else { - serializer = primarySerializer; - modelClass = primaryModelClass; - } - return serializer.normalize(modelClass, hash, prop); - }, - - /* - @method _normalizeResponse - @param {DS.Store} store - @param {DS.Model} primaryModelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @param {Boolean} isSingle - @return {Object} JSON-API Document - @private - */ - _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { - let documentHash = { - data: null, - included: [] - }; - - let meta = this.extractMeta(store, primaryModelClass, payload); - if (meta) { - assert('The `meta` returned from `extractMeta` has to be an object, not "' + Ember.typeOf(meta) + '".', Ember.typeOf(meta) === 'object'); - documentHash.meta = meta; - } - - var keys = Object.keys(payload); - - for (let i = 0, length = keys.length; i < length; i++) { - let prop = keys[i]; - var modelName = prop; - var forcedSecondary = false; - - /* - If you want to provide sideloaded records of the same type that the - primary data you can do that by prefixing the key with `_`. - - Example - - ``` - { - users: [ - { id: 1, title: 'Tom', manager: 3 }, - { id: 2, title: 'Yehuda', manager: 3 } - ], - _users: [ - { id: 3, title: 'Tomster' } - ] - } - ``` - - This forces `_users` to be added to `included` instead of `data`. - */ - if (prop.charAt(0) === '_') { - forcedSecondary = true; - modelName = prop.substr(1); - } - - var typeName = this.modelNameFromPayloadKey(modelName); - if (!store.modelFactoryFor(typeName)) { - warn(this.warnMessageNoModelForKey(modelName, typeName), false, { - id: 'ds.serializer.model-for-key-missing' - }); - continue; - } - - var isPrimary = (!forcedSecondary && this.isPrimaryType(store, typeName, primaryModelClass)); - var value = payload[prop]; - - if (value === null) { - continue; - } - - /* - Support primary data as an object instead of an array. - - Example - - ``` - { - user: { id: 1, title: 'Tom', manager: 3 } - } - ``` - */ - if (isPrimary && Ember.typeOf(value) !== 'array') { - let { data, included } = this._normalizePolymorphicRecord(store, value, prop, primaryModelClass, this); - documentHash.data = data; - if (included) { - documentHash.included.push(...included); - } - continue; - } - - let { data, included } = this._normalizeArray(store, typeName, value, prop); - - if (included) { - documentHash.included.push(...included); - } - - if (isSingle) { - /*jshint loopfunc:true*/ - data.forEach((resource) => { - - /* - Figures out if this is the primary record or not. - - It's either: - - 1. The record with the same ID as the original request - 2. If it's a newly created record without an ID, the first record - in the array - */ - var isUpdatedRecord = isPrimary && coerceId(resource.id) === id; - var isFirstCreatedRecord = isPrimary && !id && !documentHash.data; - - if (isFirstCreatedRecord || isUpdatedRecord) { - documentHash.data = resource; - } else { - documentHash.included.push(resource); - } - }); - } else { - if (isPrimary) { - documentHash.data = data; - } else { - if (data) { - documentHash.included.push(...data); - } - } - } - } - - return documentHash; - }, - - isPrimaryType(store, typeName, primaryTypeClass) { - var typeClass = store.modelFor(typeName); - return typeClass.modelName === primaryTypeClass.modelName; - }, - - /** - This method allows you to push a payload containing top-level - collections of records organized per type. - - ```js - { - "posts": [{ - "id": "1", - "title": "Rails is omakase", - "author", "1", - "comments": [ "1" ] - }], - "comments": [{ - "id": "1", - "body": "FIRST" - }], - "users": [{ - "id": "1", - "name": "@d2h" - }] - } - ``` - - It will first normalize the payload, so you can use this to push - in data streaming in from your server structured the same way - that fetches and saves are structured. - - @method pushPayload - @param {DS.Store} store - @param {Object} payload - */ - pushPayload(store, payload) { - let documentHash = { - data: [], - included: [] - }; - - for (var prop in payload) { - var modelName = this.modelNameFromPayloadKey(prop); - if (!store.modelFactoryFor(modelName)) { - warn(this.warnMessageNoModelForKey(prop, modelName), false, { - id: 'ds.serializer.model-for-key-missing' - }); - continue; - } - var type = store.modelFor(modelName); - var typeSerializer = store.serializerFor(type.modelName); - - /*jshint loopfunc:true*/ - Ember.makeArray(payload[prop]).forEach((hash) => { - let { data, included } = typeSerializer.normalize(type, hash, prop); - documentHash.data.push(data); - if (included) { - documentHash.included.push(...included); - } - }); - } - - store.push(documentHash); - }, - - /** - This method is used to convert each JSON root key in the payload - into a modelName that it can use to look up the appropriate model for - that part of the payload. - - For example, your server may send a model name that does not correspond with - the name of the model in your app. Let's take a look at an example model, - and an example payload: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - }); - ``` - - ```javascript - { - "blog/post": { - "id": "1 - } - } - ``` - - Ember Data is going to normalize the payload's root key for the modelName. As a result, - it will try to look up the "blog/post" model. Since we don't have a model called "blog/post" - (or a file called app/models/blog/post.js in ember-cli), Ember Data will throw an error - because it cannot find the "blog/post" model. - - Since we want to remove this namespace, we can define a serializer for the application that will - remove "blog/" from the payload key whenver it's encountered by Ember Data: - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.RESTSerializer.extend({ - modelNameFromPayloadKey: function(payloadKey) { - if (payloadKey === 'blog/post') { - return this._super(payloadKey.replace('blog/', '')); - } else { - return this._super(payloadKey); - } - } - }); - ``` - - After refreshing, Ember Data will appropriately look up the "post" model. - - By default the modelName for a model is its - name in dasherized form. This means that a payload key like "blogPost" would be - normalized to "blog-post" when Ember Data looks up the model. Usually, Ember Data - can use the correct inflection to do this for you. Most of the time, you won't - need to override `modelNameFromPayloadKey` for this purpose. - - @method modelNameFromPayloadKey - @param {String} key - @return {String} the model's modelName - */ - modelNameFromPayloadKey(key) { - return singularize(normalizeModelName(key)); - }, - - // SERIALIZE - - /** - Called when a record is saved in order to convert the - record into JSON. - - By default, it creates a JSON object with a key for - each attribute and belongsTo relationship. - - For example, consider this model: - - ```app/models/comment.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - title: DS.attr(), - body: DS.attr(), - - author: DS.belongsTo('user') - }); - ``` - - The default serialization would create a JSON object like: - - ```js - { - "title": "Rails is unagi", - "body": "Rails? Omakase? O_O", - "author": 12 - } - ``` - - By default, attributes are passed through as-is, unless - you specified an attribute type (`DS.attr('date')`). If - you specify a transform, the JavaScript value will be - serialized when inserted into the JSON hash. - - By default, belongs-to relationships are converted into - IDs when inserted into the JSON hash. - - ## IDs - - `serialize` takes an options hash with a single option: - `includeId`. If this option is `true`, `serialize` will, - by default include the ID in the JSON object it builds. - - The adapter passes in `includeId: true` when serializing - a record for `createRecord`, but not for `updateRecord`. - - ## Customization - - Your server may expect a different JSON format than the - built-in serialization format. - - In that case, you can implement `serialize` yourself and - return a JSON hash of your choosing. - - ```app/serializers/post.js - import DS from 'ember-data'; - - export default DS.RESTSerializer.extend({ - serialize: function(snapshot, options) { - var json = { - POST_TTL: snapshot.attr('title'), - POST_BDY: snapshot.attr('body'), - POST_CMS: snapshot.hasMany('comments', { ids: true }) - } - - if (options.includeId) { - json.POST_ID_ = snapshot.id; - } - - return json; - } - }); - ``` - - ## Customizing an App-Wide Serializer - - If you want to define a serializer for your entire - application, you'll probably want to use `eachAttribute` - and `eachRelationship` on the record. - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.RESTSerializer.extend({ - serialize: function(snapshot, options) { - var json = {}; - - snapshot.eachAttribute(function(name) { - json[serverAttributeName(name)] = snapshot.attr(name); - }) - - snapshot.eachRelationship(function(name, relationship) { - if (relationship.kind === 'hasMany') { - json[serverHasManyName(name)] = snapshot.hasMany(name, { ids: true }); - } - }); - - if (options.includeId) { - json.ID_ = snapshot.id; - } - - return json; - } - }); - - function serverAttributeName(attribute) { - return attribute.underscore().toUpperCase(); - } - - function serverHasManyName(name) { - return serverAttributeName(name.singularize()) + "_IDS"; - } - ``` - - This serializer will generate JSON that looks like this: - - ```js - { - "TITLE": "Rails is omakase", - "BODY": "Yep. Omakase.", - "COMMENT_IDS": [ 1, 2, 3 ] - } - ``` - - ## Tweaking the Default JSON - - If you just want to do some small tweaks on the default JSON, - you can call super first and make the tweaks on the returned - JSON. - - ```app/serializers/post.js - import DS from 'ember-data'; - - export default DS.RESTSerializer.extend({ - serialize: function(snapshot, options) { - var json = this._super(snapshot, options); - - json.subject = json.title; - delete json.title; - - return json; - } - }); - ``` - - @method serialize - @param {DS.Snapshot} snapshot - @param {Object} options - @return {Object} json - */ - serialize(snapshot, options) { - return this._super(...arguments); - }, - - /** - You can use this method to customize the root keys serialized into the JSON. - The hash property should be modified by reference (possibly using something like _.extend) - By default the REST Serializer sends the modelName of a model, which is a camelized - version of the name. - - For example, your server may expect underscored root objects. - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.RESTSerializer.extend({ - serializeIntoHash: function(data, type, record, options) { - var root = Ember.String.decamelize(type.modelName); - data[root] = this.serialize(record, options); - } - }); - ``` - - @method serializeIntoHash - @param {Object} hash - @param {DS.Model} typeClass - @param {DS.Snapshot} snapshot - @param {Object} options - */ - serializeIntoHash(hash, typeClass, snapshot, options) { - var normalizedRootKey = this.payloadKeyFromModelName(typeClass.modelName); - hash[normalizedRootKey] = this.serialize(snapshot, options); - }, - - /** - You can use `payloadKeyFromModelName` to override the root key for an outgoing - request. By default, the RESTSerializer returns a camelized version of the - model's name. - - For a model called TacoParty, its `modelName` would be the string `taco-party`. The RESTSerializer - will send it to the server with `tacoParty` as the root key in the JSON payload: - - ```js - { - "tacoParty": { - "id": "1", - "location": "Matthew Beale's House" - } - } - ``` - - For example, your server may expect dasherized root objects: - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.RESTSerializer.extend({ - payloadKeyFromModelName: function(modelName) { - return Ember.String.dasherize(modelName); - } - }); - ``` - - Given a `TacoParty' model, calling `save` on a tacoModel would produce an outgoing - request like: - - ```js - { - "taco-party": { - "id": "1", - "location": "Matthew Beale's House" - } - } - ``` - - @method payloadKeyFromModelName - @param {String} modelName - @return {String} - */ - payloadKeyFromModelName(modelName) { - return camelize(modelName); - }, - - /** - You can use this method to customize how polymorphic objects are serialized. - By default the REST Serializer creates the key by appending `Type` to - the attribute and value from the model's camelcased model name. - - @method serializePolymorphicType - @param {DS.Snapshot} snapshot - @param {Object} json - @param {Object} relationship - */ - serializePolymorphicType(snapshot, json, relationship) { - var key = relationship.key; - var belongsTo = snapshot.belongsTo(key); - var typeKey = this.keyForPolymorphicType(key, relationship.type, 'serialize'); - - // old way of getting the key for the polymorphic type - key = this.keyForAttribute ? this.keyForAttribute(key, "serialize") : key; - key = `${key}Type`; - - // The old way of serializing the type of a polymorphic record used - // `keyForAttribute`, which is not correct. The next code checks if the old - // way is used and if it differs from the new way of using - // `keyForPolymorphicType`. If this is the case, a deprecation warning is - // logged and the old way is restored (so nothing breaks). - if (key !== typeKey && this.keyForPolymorphicType === RESTSerializer.prototype.keyForPolymorphicType) { - deprecate("The key to serialize the type of a polymorphic record is created via keyForAttribute which has been deprecated. Use the keyForPolymorphicType hook instead.", false, { - id: 'ds.rest-serializer.deprecated-key-for-polymorphic-type', - until: '3.0.0' - }); - - typeKey = key; - } - - if (Ember.isNone(belongsTo)) { - json[typeKey] = null; - } else { - json[typeKey] = camelize(belongsTo.modelName); - } - }, - - /** - You can use this method to customize how a polymorphic relationship should - be extracted. - - @method extractPolymorphicRelationship - @param {Object} relationshipType - @param {Object} relationshipHash - @param {Object} relationshipOptions - @return {Object} - */ - extractPolymorphicRelationship(relationshipType, relationshipHash, relationshipOptions) { - var { key, resourceHash, relationshipMeta } = relationshipOptions; - - // A polymorphic belongsTo relationship can be present in the payload - // either in the form where the `id` and the `type` are given: - // - // { - // message: { id: 1, type: 'post' } - // } - // - // or by the `id` and a `Type` attribute: - // - // { - // message: 1, - // messageType: 'post' - // } - // - // The next code checks if the latter case is present and returns the - // corresponding JSON-API representation. The former case is handled within - // the base class JSONSerializer. - var isPolymorphic = relationshipMeta.options.polymorphic; - var typeProperty = this.keyForPolymorphicType(key, relationshipType, 'deserialize'); - - if (isPolymorphic && resourceHash.hasOwnProperty(typeProperty) && typeof relationshipHash !== 'object') { - let type = this.modelNameFromPayloadKey(resourceHash[typeProperty]); - return { - id: relationshipHash, - type: type - }; - } - - return this._super(...arguments); - } -}); - -runInDebug(function() { - RESTSerializer.reopen({ - warnMessageNoModelForKey(prop, typeKey) { - return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + typeKey + '" (resolved model name using ' + this.constructor.toString() + '.modelNameFromPayloadKey("' + prop + '"))'; - } - }); -}); - -export default RESTSerializer; diff --git a/addon/-private/system/adapter.js b/addon/-private/system/adapter.js deleted file mode 100644 index 93cad9a531d..00000000000 --- a/addon/-private/system/adapter.js +++ /dev/null @@ -1,538 +0,0 @@ -/** - @module ember-data -*/ - -import Ember from 'ember'; -var get = Ember.get; - -/** - An adapter is an object that receives requests from a store and - translates them into the appropriate action to take against your - persistence layer. The persistence layer is usually an HTTP API, but - may be anything, such as the browser's local storage. Typically the - adapter is not invoked directly instead its functionality is accessed - through the `store`. - - ### Creating an Adapter - - Create a new subclass of `DS.Adapter` in the `app/adapters` folder: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - // ...your code here - }); - ``` - - Model-specific adapters can be created by putting your adapter - class in an `app/adapters/` + `model-name` + `.js` file of the application. - - ```app/adapters/post.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - // ...Post-specific adapter code goes here - }); - ``` - - `DS.Adapter` is an abstract base class that you should override in your - application to customize it for your backend. The minimum set of methods - that you should implement is: - - * `findRecord()` - * `createRecord()` - * `updateRecord()` - * `deleteRecord()` - * `findAll()` - * `query()` - - To improve the network performance of your application, you can optimize - your adapter by overriding these lower-level methods: - - * `findMany()` - - - For an example implementation, see `DS.RESTAdapter`, the - included REST adapter. - - @class Adapter - @namespace DS - @extends Ember.Object -*/ - -export default Ember.Object.extend({ - - /** - If you would like your adapter to use a custom serializer you can - set the `defaultSerializer` property to be the name of the custom - serializer. - - Note the `defaultSerializer` serializer has a lower priority than - a model specific serializer (i.e. `PostSerializer`) or the - `application` serializer. - - ```app/adapters/django.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - defaultSerializer: 'django' - }); - ``` - - @property defaultSerializer - @type {String} - */ - defaultSerializer: '-default', - - /** - The `findRecord()` method is invoked when the store is asked for a record that - has not previously been loaded. In response to `findRecord()` being called, you - should query your persistence layer for a record with the given ID. Once - found, you can asynchronously call the store's `push()` method to push - the record into the store. - - Here is an example `findRecord` implementation: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { - var url = [type.modelName, id].join('/'); - - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.getJSON(url).then(function(data) { - Ember.run(null, resolve, data); - }, function(jqXHR) { - jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); - }); - }); - } - }); - ``` - - @method findRecord - @param {DS.Store} store - @param {DS.Model} type - @param {String} id - @param {DS.Snapshot} snapshot - @return {Promise} promise - */ - findRecord: null, - - /** - The `findAll()` method is used to retrieve all records for a given type. - - Example - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - findAll: function(store, type, sinceToken) { - var url = type; - var query = { since: sinceToken }; - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.getJSON(url, query).then(function(data) { - Ember.run(null, resolve, data); - }, function(jqXHR) { - jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); - }); - }); - } - }); - ``` - - @method findAll - @param {DS.Store} store - @param {DS.Model} type - @param {String} sinceToken - @param {DS.SnapshotRecordArray} snapshotRecordArray - @return {Promise} promise - */ - findAll: null, - - /** - This method is called when you call `query` on the store. - - Example - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - query: function(store, type, query) { - var url = type; - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.getJSON(url, query).then(function(data) { - Ember.run(null, resolve, data); - }, function(jqXHR) { - jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); - }); - }); - } - }); - ``` - - @method query - @param {DS.Store} store - @param {DS.Model} type - @param {Object} query - @param {DS.AdapterPopulatedRecordArray} recordArray - @return {Promise} promise - */ - query: null, - - /** - The `queryRecord()` method is invoked when the store is asked for a single - record through a query object. - - In response to `queryRecord()` being called, you should always fetch fresh - data. Once found, you can asynchronously call the store's `push()` method - to push the record into the store. - - Here is an example `queryRecord` implementation: - - Example - - ```app/adapters/application.js - import DS from 'ember-data'; - import Ember from 'ember'; - - export default DS.Adapter.extend(DS.BuildURLMixin, { - queryRecord: function(store, type, query) { - var urlForQueryRecord = this.buildURL(type.modelName, null, null, 'queryRecord', query); - - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.getJSON(urlForQueryRecord, query).then(function(data) { - Ember.run(null, resolve, data); - }, function(jqXHR) { - jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); - }); - }); - } - }); - ``` - - @method queryRecord - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} query - @return {Promise} promise - */ - queryRecord: null, - - /** - If the globally unique IDs for your records should be generated on the client, - implement the `generateIdForRecord()` method. This method will be invoked - each time you create a new record, and the value returned from it will be - assigned to the record's `primaryKey`. - - Most traditional REST-like HTTP APIs will not use this method. Instead, the ID - of the record will be set by the server, and your adapter will update the store - with the new ID when it calls `didCreateRecord()`. Only implement this method if - you intend to generate record IDs on the client-side. - - The `generateIdForRecord()` method will be invoked with the requesting store as - the first parameter and the newly created record as the second parameter: - - ```javascript - generateIdForRecord: function(store, inputProperties) { - var uuid = App.generateUUIDWithStatisticallyLowOddsOfCollision(); - return uuid; - } - ``` - - @method generateIdForRecord - @param {DS.Store} store - @param {DS.Model} type the DS.Model class of the record - @param {Object} inputProperties a hash of properties to set on the - newly created record. - @return {(String|Number)} id - */ - generateIdForRecord: null, - - /** - Proxies to the serializer's `serialize` method. - - Example - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - createRecord: function(store, type, snapshot) { - var data = this.serialize(snapshot, { includeId: true }); - var url = type; - - // ... - } - }); - ``` - - @method serialize - @param {DS.Snapshot} snapshot - @param {Object} options - @return {Object} serialized snapshot - */ - serialize(snapshot, options) { - return get(snapshot.record, 'store').serializerFor(snapshot.modelName).serialize(snapshot, options); - }, - - /** - Implement this method in a subclass to handle the creation of - new records. - - Serializes the record and sends it to the server. - - Example - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - createRecord: function(store, type, snapshot) { - var data = this.serialize(snapshot, { includeId: true }); - var url = type; - - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.ajax({ - type: 'POST', - url: url, - dataType: 'json', - data: data - }).then(function(data) { - Ember.run(null, resolve, data); - }, function(jqXHR) { - jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); - }); - }); - } - }); - ``` - - @method createRecord - @param {DS.Store} store - @param {DS.Model} type the DS.Model class of the record - @param {DS.Snapshot} snapshot - @return {Promise} promise - */ - createRecord: null, - - /** - Implement this method in a subclass to handle the updating of - a record. - - Serializes the record update and sends it to the server. - - The updateRecord method is expected to return a promise that will - resolve with the serialized record. This allows the backend to - inform the Ember Data store the current state of this record after - the update. If it is not possible to return a serialized record - the updateRecord promise can also resolve with `undefined` and the - Ember Data store will assume all of the updates were successfully - applied on the backend. - - Example - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - updateRecord: function(store, type, snapshot) { - var data = this.serialize(snapshot, { includeId: true }); - var id = snapshot.id; - var url = [type, id].join('/'); - - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.ajax({ - type: 'PUT', - url: url, - dataType: 'json', - data: data - }).then(function(data) { - Ember.run(null, resolve, data); - }, function(jqXHR) { - jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); - }); - }); - } - }); - ``` - - @method updateRecord - @param {DS.Store} store - @param {DS.Model} type the DS.Model class of the record - @param {DS.Snapshot} snapshot - @return {Promise} promise - */ - updateRecord: null, - - /** - Implement this method in a subclass to handle the deletion of - a record. - - Sends a delete request for the record to the server. - - Example - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - deleteRecord: function(store, type, snapshot) { - var data = this.serialize(snapshot, { includeId: true }); - var id = snapshot.id; - var url = [type, id].join('/'); - - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.ajax({ - type: 'DELETE', - url: url, - dataType: 'json', - data: data - }).then(function(data) { - Ember.run(null, resolve, data); - }, function(jqXHR) { - jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); - }); - }); - } - }); - ``` - - @method deleteRecord - @param {DS.Store} store - @param {DS.Model} type the DS.Model class of the record - @param {DS.Snapshot} snapshot - @return {Promise} promise - */ - deleteRecord: null, - - /** - By default the store will try to coalesce all `fetchRecord` calls within the same runloop - into as few requests as possible by calling groupRecordsForFindMany and passing it into a findMany call. - You can opt out of this behaviour by either not implementing the findMany hook or by setting - coalesceFindRequests to false. - - @property coalesceFindRequests - @type {boolean} - */ - coalesceFindRequests: true, - - /** - Find multiple records at once if coalesceFindRequests is true. - - @method findMany - @param {DS.Store} store - @param {DS.Model} type the DS.Model class of the records - @param {Array} ids - @param {Array} snapshots - @return {Promise} promise - */ - findMany: null, - - /** - Organize records into groups, each of which is to be passed to separate - calls to `findMany`. - - For example, if your api has nested URLs that depend on the parent, you will - want to group records by their parent. - - The default implementation returns the records as a single group. - - @method groupRecordsForFindMany - @param {DS.Store} store - @param {Array} snapshots - @return {Array} an array of arrays of records, each of which is to be - loaded separately by `findMany`. - */ - groupRecordsForFindMany(store, snapshots) { - return [snapshots]; - }, - - - /** - This method is used by the store to determine if the store should - reload a record from the adapter when a record is requested by - `store.findRecord`. - - If this method returns true, the store will re-fetch a record from - the adapter. If this method returns false, the store will resolve - immediately using the cached record. - - @method shouldReloadRecord - @param {DS.Store} store - @param {DS.Snapshot} snapshot - @return {Boolean} - */ - shouldReloadRecord(store, snapshot) { - return false; - }, - - /** - This method is used by the store to determine if the store should - reload all records from the adapter when records are requested by - `store.findAll`. - - If this method returns true, the store will re-fetch all records from - the adapter. If this method returns false, the store will resolve - immediately using the cached record. - - @method shouldReloadAll - @param {DS.Store} store - @param {DS.SnapshotRecordArray} snapshotRecordArray - @return {Boolean} - */ - shouldReloadAll(store, snapshotRecordArray) { - return !snapshotRecordArray.length; - }, - - /** - This method is used by the store to determine if the store should - reload a record after the `store.findRecord` method resolves a - cached record. - - This method is *only* checked by the store when the store is - returning a cached record. - - If this method returns true the store will re-fetch a record from - the adapter. - - @method shouldBackgroundReloadRecord - @param {DS.Store} store - @param {DS.Snapshot} snapshot - @return {Boolean} - */ - shouldBackgroundReloadRecord(store, snapshot) { - return true; - }, - - /** - This method is used by the store to determine if the store should - reload a record array after the `store.findAll` method resolves - with a cached record array. - - This method is *only* checked by the store when the store is - returning a cached record array. - - If this method returns true the store will re-fetch all records - from the adapter. - - @method shouldBackgroundReloadAll - @param {DS.Store} store - @param {DS.SnapshotRecordArray} snapshotRecordArray - @return {Boolean} - */ - shouldBackgroundReloadAll(store, snapshotRecordArray) { - return true; - } -}); diff --git a/addon/-private/system/debug/debug-adapter.js b/addon/-private/system/debug/debug-adapter.js index 4080bc50874..52d715d7c3c 100644 --- a/addon/-private/system/debug/debug-adapter.js +++ b/addon/-private/system/debug/debug-adapter.js @@ -2,7 +2,7 @@ @module ember-data */ import Ember from 'ember'; -import Model from "ember-data/-private/system/model"; +import Model from "ember-data/model"; var get = Ember.get; var capitalize = Ember.String.capitalize; var underscore = Ember.String.underscore; diff --git a/addon/-private/system/debug/debug-info.js b/addon/-private/system/debug/debug-info.js index 6e079856fae..6d9a0e791af 100644 --- a/addon/-private/system/debug/debug-info.js +++ b/addon/-private/system/debug/debug-info.js @@ -1,4 +1,4 @@ -import Model from "ember-data/-private/system/model"; +import Model from "ember-data/model"; Model.reopen({ diff --git a/addon/-private/system/model.js b/addon/-private/system/model.js index f3f0c79bdff..70b928f6b9b 100644 --- a/addon/-private/system/model.js +++ b/addon/-private/system/model.js @@ -3,7 +3,7 @@ */ import Model from "ember-data/-private/system/model/model"; -import attr from "ember-data/-private/system/model/attributes"; +import attr from "ember-data/attr"; import RootState from "ember-data/-private/system/model/states"; import Errors from "ember-data/-private/system/model/errors"; diff --git a/addon/-private/system/model/attributes.js b/addon/-private/system/model/attributes.js deleted file mode 100644 index 9a101508a16..00000000000 --- a/addon/-private/system/model/attributes.js +++ /dev/null @@ -1,351 +0,0 @@ -import Ember from 'ember'; -import Model from "ember-data/-private/system/model/model"; -import { assert, deprecate } from "ember-data/-private/debug"; - -/** - @module ember-data -*/ - -var get = Ember.get; -var Map = Ember.Map; - -/** - @class Model - @namespace DS -*/ -Model.reopenClass({ - /** - A map whose keys are the attributes of the model (properties - described by DS.attr) and whose values are the meta object for the - property. - - Example - - ```app/models/person.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - firstName: attr('string'), - lastName: attr('string'), - birthday: attr('date') - }); - ``` - - ```javascript - import Ember from 'ember'; - import Person from 'app/models/person'; - - var attributes = Ember.get(Person, 'attributes') - - attributes.forEach(function(meta, name) { - console.log(name, meta); - }); - - // prints: - // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} - // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} - // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} - ``` - - @property attributes - @static - @type {Ember.Map} - @readOnly - */ - attributes: Ember.computed(function() { - var map = Map.create(); - - this.eachComputedProperty((name, meta) => { - if (meta.isAttribute) { - assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.toString(), name !== 'id'); - - meta.name = name; - map.set(name, meta); - } - }); - - return map; - }).readOnly(), - - /** - A map whose keys are the attributes of the model (properties - described by DS.attr) and whose values are type of transformation - applied to each attribute. This map does not include any - attributes that do not have an transformation type. - - Example - - ```app/models/person.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - firstName: attr(), - lastName: attr('string'), - birthday: attr('date') - }); - ``` - - ```javascript - import Ember from 'ember'; - import Person from 'app/models/person'; - - var transformedAttributes = Ember.get(Person, 'transformedAttributes') - - transformedAttributes.forEach(function(field, type) { - console.log(field, type); - }); - - // prints: - // lastName string - // birthday date - ``` - - @property transformedAttributes - @static - @type {Ember.Map} - @readOnly - */ - transformedAttributes: Ember.computed(function() { - var map = Map.create(); - - this.eachAttribute((key, meta) => { - if (meta.type) { - map.set(key, meta.type); - } - }); - - return map; - }).readOnly(), - - /** - Iterates through the attributes of the model, calling the passed function on each - attribute. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, meta); - ``` - - - `name` the name of the current property in the iteration - - `meta` the meta object for the attribute property in the iteration - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```javascript - import DS from 'ember-data'; - - var Person = DS.Model.extend({ - firstName: attr('string'), - lastName: attr('string'), - birthday: attr('date') - }); - - Person.eachAttribute(function(name, meta) { - console.log(name, meta); - }); - - // prints: - // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} - // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} - // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} - ``` - - @method eachAttribute - @param {Function} callback The callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - @static - */ - eachAttribute(callback, binding) { - get(this, 'attributes').forEach((meta, name) => { - callback.call(binding, name, meta); - }); - }, - - /** - Iterates through the transformedAttributes of the model, calling - the passed function on each attribute. Note the callback will not be - called for any attributes that do not have an transformation type. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, type); - ``` - - - `name` the name of the current property in the iteration - - `type` a string containing the name of the type of transformed - applied to the attribute - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```javascript - import DS from 'ember-data'; - - var Person = DS.Model.extend({ - firstName: attr(), - lastName: attr('string'), - birthday: attr('date') - }); - - Person.eachTransformedAttribute(function(name, type) { - console.log(name, type); - }); - - // prints: - // lastName string - // birthday date - ``` - - @method eachTransformedAttribute - @param {Function} callback The callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - @static - */ - eachTransformedAttribute(callback, binding) { - get(this, 'transformedAttributes').forEach((type, name) => { - callback.call(binding, name, type); - }); - } -}); - - -Model.reopen({ - eachAttribute(callback, binding) { - this.constructor.eachAttribute(callback, binding); - } -}); - -function getDefaultValue(record, options, key) { - if (typeof options.defaultValue === "function") { - return options.defaultValue.apply(null, arguments); - } else { - let defaultValue = options.defaultValue; - deprecate(`Non primitive defaultValues are deprecated because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.`, - typeof defaultValue !== 'object' || defaultValue === null, { - id: 'ds.defaultValue.complex-object', - until: '3.0.0' - }); - return defaultValue; - } -} - -function hasValue(record, key) { - return key in record._attributes || - key in record._inFlightAttributes || - key in record._data; -} - -function getValue(record, key) { - if (key in record._attributes) { - return record._attributes[key]; - } else if (key in record._inFlightAttributes) { - return record._inFlightAttributes[key]; - } else { - return record._data[key]; - } -} - -/** - `DS.attr` defines an attribute on a [DS.Model](/api/data/classes/DS.Model.html). - By default, attributes are passed through as-is, however you can specify an - optional type to have the value automatically transformed. - Ember Data ships with four basic transform types: `string`, `number`, - `boolean` and `date`. You can define your own transforms by subclassing - [DS.Transform](/api/data/classes/DS.Transform.html). - - Note that you cannot use `attr` to define an attribute of `id`. - - `DS.attr` takes an optional hash as a second parameter, currently - supported options are: - - - `defaultValue`: Pass a string or a function to be called to set the attribute - to a default value if none is supplied. - - Example - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - username: DS.attr('string'), - email: DS.attr('string'), - verified: DS.attr('boolean', { defaultValue: false }) - }); - ``` - - Default value can also be a function. This is useful it you want to return - a new object for each attribute. - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - username: attr('string'), - email: attr('string'), - settings: attr({defaultValue: function() { - return {}; - }}) - }); - ``` - - @namespace - @method attr - @for DS - @param {String} type the attribute type - @param {Object} options a hash of options - @return {Attribute} -*/ - -export default function attr(type, options) { - if (typeof type === 'object') { - options = type; - type = undefined; - } else { - options = options || {}; - } - - var meta = { - type: type, - isAttribute: true, - options: options - }; - - return Ember.computed({ - get(key) { - var internalModel = this._internalModel; - if (hasValue(internalModel, key)) { - return getValue(internalModel, key); - } else { - return getDefaultValue(this, options, key); - } - }, - set(key, value) { - var internalModel = this._internalModel; - var oldValue = getValue(internalModel, key); - - if (value !== oldValue) { - // Add the new value to the changed attributes hash; it will get deleted by - // the 'didSetProperty' handler if it is no different from the original value - internalModel._attributes[key] = value; - - this._internalModel.send('didSetProperty', { - name: key, - oldValue: oldValue, - originalValue: internalModel._data[key], - value: value - }); - } - - return value; - } - }).meta(meta); -} diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 0d0a47d11e8..b18b500beb0 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -1,4 +1,4 @@ -import Model from 'ember-data/-private/system/model'; +import Model from 'ember-data/model'; import Ember from 'ember'; import Reference from './reference'; diff --git a/addon/-private/system/relationships.js b/addon/-private/system/relationships.js deleted file mode 100644 index 72c0124740f..00000000000 --- a/addon/-private/system/relationships.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - @module ember-data -*/ - -import belongsTo from "./relationships/belongs-to"; -import hasMany from "./relationships/has-many"; - -import "ember-data/-private/system/relationships/ext"; - -export { - belongsTo, - hasMany -}; diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 0b9292647f0..e8c0c7e5de5 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -1,6 +1,6 @@ import Ember from 'ember'; import { assert, warn } from "ember-data/-private/debug"; -import Model from 'ember-data/-private/system/model'; +import Model from 'ember-data/model'; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; /** diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 1d2775e41e1..b91c24a887f 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -4,7 +4,7 @@ import { typeForRelationshipMeta, relationshipFromMeta } from "ember-data/-private/system/relationship-meta"; -import Model from "ember-data/-private/system/model"; +import Model from "ember-data/model"; import EmptyObject from "ember-data/-private/system/empty-object"; var get = Ember.get; diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index 763b070ff3a..86f2234ea21 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -4,7 +4,7 @@ import Ember from 'ember'; import { assert } from "ember-data/-private/debug"; -import Model from "ember-data/-private/system/model"; +import Model from "ember-data/model"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; import isArrayLike from "ember-data/-private/system/is-array-like"; diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index a76fafc3f68..d0d961c1f85 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -6,7 +6,7 @@ */ import Ember from 'ember'; -import Model from 'ember-data/-private/system/model'; +import Model from 'ember-data/model'; import { assert, warn } from "ember-data/-private/debug"; import _normalizeLink from "ember-data/-private/system/normalize-link"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; diff --git a/addon/-private/transforms.js b/addon/-private/transforms.js index 89d9ae392c6..6658a7a6cea 100644 --- a/addon/-private/transforms.js +++ b/addon/-private/transforms.js @@ -1,4 +1,4 @@ -import Transform from "ember-data/-private/transforms/base"; +import Transform from "ember-data/transform"; import NumberTransform from "ember-data/-private/transforms/number"; import DateTransform from "ember-data/-private/transforms/date"; import StringTransform from "ember-data/-private/transforms/string"; diff --git a/addon/-private/transforms/base.js b/addon/-private/transforms/base.js deleted file mode 100644 index e9c45f2104a..00000000000 --- a/addon/-private/transforms/base.js +++ /dev/null @@ -1,76 +0,0 @@ -import Ember from 'ember'; - -/** - The `DS.Transform` class is used to serialize and deserialize model - attributes when they are saved or loaded from an - adapter. Subclassing `DS.Transform` is useful for creating custom - attributes. All subclasses of `DS.Transform` must implement a - `serialize` and a `deserialize` method. - - Example - - ```app/transforms/temperature.js - import DS from 'ember-data'; - - // Converts centigrade in the JSON to fahrenheit in the app - export default DS.Transform.extend({ - deserialize: function(serialized) { - return (serialized * 1.8) + 32; - }, - serialize: function(deserialized) { - return (deserialized - 32) / 1.8; - } - }); - ``` - - Usage - - ```app/models/requirement.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - name: DS.attr('string'), - temperature: DS.attr('temperature') - }); - ``` - - @class Transform - @namespace DS - */ -export default Ember.Object.extend({ - /** - When given a deserialized value from a record attribute this - method must return the serialized value. - - Example - - ```javascript - serialize: function(deserialized) { - return Ember.isEmpty(deserialized) ? null : Number(deserialized); - } - ``` - - @method serialize - @param deserialized The deserialized value - @return The serialized value - */ - serialize: null, - - /** - When given a serialize value from a JSON object this method must - return the deserialized value for the record attribute. - - Example - - ```javascript - deserialize: function(serialized) { - return empty(serialized) ? null : Number(serialized); - } - ``` - - @method deserialize - @param serialized The serialized value - @return The deserialized value - */ - deserialize: null -}); diff --git a/addon/-private/transforms/boolean.js b/addon/-private/transforms/boolean.js index 4d027bc557f..81338ba6fee 100644 --- a/addon/-private/transforms/boolean.js +++ b/addon/-private/transforms/boolean.js @@ -1,4 +1,4 @@ -import Transform from "ember-data/-private/transforms/base"; +import Transform from "ember-data/transform"; /** The `DS.BooleanTransform` class is used to serialize and deserialize diff --git a/addon/-private/transforms/date.js b/addon/-private/transforms/date.js index 09ae5af818e..60944b6b95d 100644 --- a/addon/-private/transforms/date.js +++ b/addon/-private/transforms/date.js @@ -20,7 +20,7 @@ import Ember from 'ember'; @extends DS.Transform @namespace DS */ -import Transform from "ember-data/-private/transforms/base"; +import Transform from "ember-data/transform"; export default Transform.extend({ deserialize(serialized) { diff --git a/addon/-private/transforms/number.js b/addon/-private/transforms/number.js index 7d81ec2ba32..96ae62e3ca2 100644 --- a/addon/-private/transforms/number.js +++ b/addon/-private/transforms/number.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import Transform from "ember-data/-private/transforms/base"; +import Transform from "ember-data/transform"; var empty = Ember.isEmpty; diff --git a/addon/-private/transforms/string.js b/addon/-private/transforms/string.js index 746f233feb5..671139d5809 100644 --- a/addon/-private/transforms/string.js +++ b/addon/-private/transforms/string.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import Transform from "ember-data/-private/transforms/base"; +import Transform from "ember-data/transform"; var none = Ember.isNone; diff --git a/addon/adapter.js b/addon/adapter.js index 7eebb9ff9f7..93cad9a531d 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -1 +1,538 @@ -export { default } from "ember-data/-private/system/adapter"; +/** + @module ember-data +*/ + +import Ember from 'ember'; +var get = Ember.get; + +/** + An adapter is an object that receives requests from a store and + translates them into the appropriate action to take against your + persistence layer. The persistence layer is usually an HTTP API, but + may be anything, such as the browser's local storage. Typically the + adapter is not invoked directly instead its functionality is accessed + through the `store`. + + ### Creating an Adapter + + Create a new subclass of `DS.Adapter` in the `app/adapters` folder: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + // ...your code here + }); + ``` + + Model-specific adapters can be created by putting your adapter + class in an `app/adapters/` + `model-name` + `.js` file of the application. + + ```app/adapters/post.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + // ...Post-specific adapter code goes here + }); + ``` + + `DS.Adapter` is an abstract base class that you should override in your + application to customize it for your backend. The minimum set of methods + that you should implement is: + + * `findRecord()` + * `createRecord()` + * `updateRecord()` + * `deleteRecord()` + * `findAll()` + * `query()` + + To improve the network performance of your application, you can optimize + your adapter by overriding these lower-level methods: + + * `findMany()` + + + For an example implementation, see `DS.RESTAdapter`, the + included REST adapter. + + @class Adapter + @namespace DS + @extends Ember.Object +*/ + +export default Ember.Object.extend({ + + /** + If you would like your adapter to use a custom serializer you can + set the `defaultSerializer` property to be the name of the custom + serializer. + + Note the `defaultSerializer` serializer has a lower priority than + a model specific serializer (i.e. `PostSerializer`) or the + `application` serializer. + + ```app/adapters/django.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + defaultSerializer: 'django' + }); + ``` + + @property defaultSerializer + @type {String} + */ + defaultSerializer: '-default', + + /** + The `findRecord()` method is invoked when the store is asked for a record that + has not previously been loaded. In response to `findRecord()` being called, you + should query your persistence layer for a record with the given ID. Once + found, you can asynchronously call the store's `push()` method to push + the record into the store. + + Here is an example `findRecord` implementation: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + findRecord: function(store, type, id, snapshot) { + var url = [type.modelName, id].join('/'); + + return new Ember.RSVP.Promise(function(resolve, reject) { + Ember.$.getJSON(url).then(function(data) { + Ember.run(null, resolve, data); + }, function(jqXHR) { + jqXHR.then = null; // tame jQuery's ill mannered promises + Ember.run(null, reject, jqXHR); + }); + }); + } + }); + ``` + + @method findRecord + @param {DS.Store} store + @param {DS.Model} type + @param {String} id + @param {DS.Snapshot} snapshot + @return {Promise} promise + */ + findRecord: null, + + /** + The `findAll()` method is used to retrieve all records for a given type. + + Example + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + findAll: function(store, type, sinceToken) { + var url = type; + var query = { since: sinceToken }; + return new Ember.RSVP.Promise(function(resolve, reject) { + Ember.$.getJSON(url, query).then(function(data) { + Ember.run(null, resolve, data); + }, function(jqXHR) { + jqXHR.then = null; // tame jQuery's ill mannered promises + Ember.run(null, reject, jqXHR); + }); + }); + } + }); + ``` + + @method findAll + @param {DS.Store} store + @param {DS.Model} type + @param {String} sinceToken + @param {DS.SnapshotRecordArray} snapshotRecordArray + @return {Promise} promise + */ + findAll: null, + + /** + This method is called when you call `query` on the store. + + Example + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + query: function(store, type, query) { + var url = type; + return new Ember.RSVP.Promise(function(resolve, reject) { + Ember.$.getJSON(url, query).then(function(data) { + Ember.run(null, resolve, data); + }, function(jqXHR) { + jqXHR.then = null; // tame jQuery's ill mannered promises + Ember.run(null, reject, jqXHR); + }); + }); + } + }); + ``` + + @method query + @param {DS.Store} store + @param {DS.Model} type + @param {Object} query + @param {DS.AdapterPopulatedRecordArray} recordArray + @return {Promise} promise + */ + query: null, + + /** + The `queryRecord()` method is invoked when the store is asked for a single + record through a query object. + + In response to `queryRecord()` being called, you should always fetch fresh + data. Once found, you can asynchronously call the store's `push()` method + to push the record into the store. + + Here is an example `queryRecord` implementation: + + Example + + ```app/adapters/application.js + import DS from 'ember-data'; + import Ember from 'ember'; + + export default DS.Adapter.extend(DS.BuildURLMixin, { + queryRecord: function(store, type, query) { + var urlForQueryRecord = this.buildURL(type.modelName, null, null, 'queryRecord', query); + + return new Ember.RSVP.Promise(function(resolve, reject) { + Ember.$.getJSON(urlForQueryRecord, query).then(function(data) { + Ember.run(null, resolve, data); + }, function(jqXHR) { + jqXHR.then = null; // tame jQuery's ill mannered promises + Ember.run(null, reject, jqXHR); + }); + }); + } + }); + ``` + + @method queryRecord + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} query + @return {Promise} promise + */ + queryRecord: null, + + /** + If the globally unique IDs for your records should be generated on the client, + implement the `generateIdForRecord()` method. This method will be invoked + each time you create a new record, and the value returned from it will be + assigned to the record's `primaryKey`. + + Most traditional REST-like HTTP APIs will not use this method. Instead, the ID + of the record will be set by the server, and your adapter will update the store + with the new ID when it calls `didCreateRecord()`. Only implement this method if + you intend to generate record IDs on the client-side. + + The `generateIdForRecord()` method will be invoked with the requesting store as + the first parameter and the newly created record as the second parameter: + + ```javascript + generateIdForRecord: function(store, inputProperties) { + var uuid = App.generateUUIDWithStatisticallyLowOddsOfCollision(); + return uuid; + } + ``` + + @method generateIdForRecord + @param {DS.Store} store + @param {DS.Model} type the DS.Model class of the record + @param {Object} inputProperties a hash of properties to set on the + newly created record. + @return {(String|Number)} id + */ + generateIdForRecord: null, + + /** + Proxies to the serializer's `serialize` method. + + Example + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + createRecord: function(store, type, snapshot) { + var data = this.serialize(snapshot, { includeId: true }); + var url = type; + + // ... + } + }); + ``` + + @method serialize + @param {DS.Snapshot} snapshot + @param {Object} options + @return {Object} serialized snapshot + */ + serialize(snapshot, options) { + return get(snapshot.record, 'store').serializerFor(snapshot.modelName).serialize(snapshot, options); + }, + + /** + Implement this method in a subclass to handle the creation of + new records. + + Serializes the record and sends it to the server. + + Example + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + createRecord: function(store, type, snapshot) { + var data = this.serialize(snapshot, { includeId: true }); + var url = type; + + return new Ember.RSVP.Promise(function(resolve, reject) { + Ember.$.ajax({ + type: 'POST', + url: url, + dataType: 'json', + data: data + }).then(function(data) { + Ember.run(null, resolve, data); + }, function(jqXHR) { + jqXHR.then = null; // tame jQuery's ill mannered promises + Ember.run(null, reject, jqXHR); + }); + }); + } + }); + ``` + + @method createRecord + @param {DS.Store} store + @param {DS.Model} type the DS.Model class of the record + @param {DS.Snapshot} snapshot + @return {Promise} promise + */ + createRecord: null, + + /** + Implement this method in a subclass to handle the updating of + a record. + + Serializes the record update and sends it to the server. + + The updateRecord method is expected to return a promise that will + resolve with the serialized record. This allows the backend to + inform the Ember Data store the current state of this record after + the update. If it is not possible to return a serialized record + the updateRecord promise can also resolve with `undefined` and the + Ember Data store will assume all of the updates were successfully + applied on the backend. + + Example + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + updateRecord: function(store, type, snapshot) { + var data = this.serialize(snapshot, { includeId: true }); + var id = snapshot.id; + var url = [type, id].join('/'); + + return new Ember.RSVP.Promise(function(resolve, reject) { + Ember.$.ajax({ + type: 'PUT', + url: url, + dataType: 'json', + data: data + }).then(function(data) { + Ember.run(null, resolve, data); + }, function(jqXHR) { + jqXHR.then = null; // tame jQuery's ill mannered promises + Ember.run(null, reject, jqXHR); + }); + }); + } + }); + ``` + + @method updateRecord + @param {DS.Store} store + @param {DS.Model} type the DS.Model class of the record + @param {DS.Snapshot} snapshot + @return {Promise} promise + */ + updateRecord: null, + + /** + Implement this method in a subclass to handle the deletion of + a record. + + Sends a delete request for the record to the server. + + Example + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + deleteRecord: function(store, type, snapshot) { + var data = this.serialize(snapshot, { includeId: true }); + var id = snapshot.id; + var url = [type, id].join('/'); + + return new Ember.RSVP.Promise(function(resolve, reject) { + Ember.$.ajax({ + type: 'DELETE', + url: url, + dataType: 'json', + data: data + }).then(function(data) { + Ember.run(null, resolve, data); + }, function(jqXHR) { + jqXHR.then = null; // tame jQuery's ill mannered promises + Ember.run(null, reject, jqXHR); + }); + }); + } + }); + ``` + + @method deleteRecord + @param {DS.Store} store + @param {DS.Model} type the DS.Model class of the record + @param {DS.Snapshot} snapshot + @return {Promise} promise + */ + deleteRecord: null, + + /** + By default the store will try to coalesce all `fetchRecord` calls within the same runloop + into as few requests as possible by calling groupRecordsForFindMany and passing it into a findMany call. + You can opt out of this behaviour by either not implementing the findMany hook or by setting + coalesceFindRequests to false. + + @property coalesceFindRequests + @type {boolean} + */ + coalesceFindRequests: true, + + /** + Find multiple records at once if coalesceFindRequests is true. + + @method findMany + @param {DS.Store} store + @param {DS.Model} type the DS.Model class of the records + @param {Array} ids + @param {Array} snapshots + @return {Promise} promise + */ + findMany: null, + + /** + Organize records into groups, each of which is to be passed to separate + calls to `findMany`. + + For example, if your api has nested URLs that depend on the parent, you will + want to group records by their parent. + + The default implementation returns the records as a single group. + + @method groupRecordsForFindMany + @param {DS.Store} store + @param {Array} snapshots + @return {Array} an array of arrays of records, each of which is to be + loaded separately by `findMany`. + */ + groupRecordsForFindMany(store, snapshots) { + return [snapshots]; + }, + + + /** + This method is used by the store to determine if the store should + reload a record from the adapter when a record is requested by + `store.findRecord`. + + If this method returns true, the store will re-fetch a record from + the adapter. If this method returns false, the store will resolve + immediately using the cached record. + + @method shouldReloadRecord + @param {DS.Store} store + @param {DS.Snapshot} snapshot + @return {Boolean} + */ + shouldReloadRecord(store, snapshot) { + return false; + }, + + /** + This method is used by the store to determine if the store should + reload all records from the adapter when records are requested by + `store.findAll`. + + If this method returns true, the store will re-fetch all records from + the adapter. If this method returns false, the store will resolve + immediately using the cached record. + + @method shouldReloadAll + @param {DS.Store} store + @param {DS.SnapshotRecordArray} snapshotRecordArray + @return {Boolean} + */ + shouldReloadAll(store, snapshotRecordArray) { + return !snapshotRecordArray.length; + }, + + /** + This method is used by the store to determine if the store should + reload a record after the `store.findRecord` method resolves a + cached record. + + This method is *only* checked by the store when the store is + returning a cached record. + + If this method returns true the store will re-fetch a record from + the adapter. + + @method shouldBackgroundReloadRecord + @param {DS.Store} store + @param {DS.Snapshot} snapshot + @return {Boolean} + */ + shouldBackgroundReloadRecord(store, snapshot) { + return true; + }, + + /** + This method is used by the store to determine if the store should + reload a record array after the `store.findAll` method resolves + with a cached record array. + + This method is *only* checked by the store when the store is + returning a cached record array. + + If this method returns true the store will re-fetch all records + from the adapter. + + @method shouldBackgroundReloadAll + @param {DS.Store} store + @param {DS.SnapshotRecordArray} snapshotRecordArray + @return {Boolean} + */ + shouldBackgroundReloadAll(store, snapshotRecordArray) { + return true; + } +}); diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index da06897728e..97923564492 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -1 +1,134 @@ -export { default } from "ember-data/-private/adapters/json-api-adapter"; +/** + @module ember-data +*/ + +import Ember from 'ember'; +import RESTAdapter from "ember-data/adapters/rest"; + +/** + @class JSONAPIAdapter + @constructor + @namespace DS + @extends DS.RESTAdapter +*/ +export default RESTAdapter.extend({ + defaultSerializer: '-json-api', + + /** + @method ajaxOptions + @private + @param {String} url + @param {String} type The request type GET, POST, PUT, DELETE etc. + @param {Object} options + @return {Object} + */ + ajaxOptions(url, type, options) { + let hash = this._super(...arguments); + + if (hash.contentType) { + hash.contentType = 'application/vnd.api+json'; + } + + let beforeSend = hash.beforeSend; + hash.beforeSend = function(xhr) { + xhr.setRequestHeader('Accept', 'application/vnd.api+json'); + if (beforeSend) { + beforeSend(xhr); + } + }; + + return hash; + }, + + /** + By default the JSONAPIAdapter will send each find request coming from a `store.find` + or from accessing a relationship separately to the server. If your server supports passing + ids as a query string, you can set coalesceFindRequests to true to coalesce all find requests + within a single runloop. + + For example, if you have an initial payload of: + + ```javascript + { + post: { + id: 1, + comments: [1, 2] + } + } + ``` + + By default calling `post.get('comments')` will trigger the following requests(assuming the + comments haven't been loaded before): + + ``` + GET /comments/1 + GET /comments/2 + ``` + + If you set coalesceFindRequests to `true` it will instead trigger the following request: + + ``` + GET /comments?filter[id]=1,2 + ``` + + Setting coalesceFindRequests to `true` also works for `store.find` requests and `belongsTo` + relationships accessed within the same runloop. If you set `coalesceFindRequests: true` + + ```javascript + store.findRecord('comment', 1); + store.findRecord('comment', 2); + ``` + + will also send a request to: `GET /comments?filter[id]=1,2` + + Note: Requests coalescing rely on URL building strategy. So if you override `buildURL` in your app + `groupRecordsForFindMany` more likely should be overridden as well in order for coalescing to work. + + @property coalesceFindRequests + @type {boolean} + */ + coalesceFindRequests: false, + + /** + @method findMany + @param {DS.Store} store + @param {DS.Model} type + @param {Array} ids + @param {Array} snapshots + @return {Promise} promise + */ + findMany(store, type, ids, snapshots) { + var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); + return this.ajax(url, 'GET', { data: { filter: { id: ids.join(',') } } }); + }, + + /** + @method pathForType + @param {String} modelName + @return {String} path + **/ + pathForType(modelName) { + var dasherized = Ember.String.dasherize(modelName); + return Ember.String.pluralize(dasherized); + }, + + // TODO: Remove this once we have a better way to override HTTP verbs. + /** + @method updateRecord + @param {DS.Store} store + @param {DS.Model} type + @param {DS.Snapshot} snapshot + @return {Promise} promise + */ + updateRecord(store, type, snapshot) { + var data = {}; + var serializer = store.serializerFor(type.modelName); + + serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); + + var id = snapshot.id; + var url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); + + return this.ajax(url, 'PATCH', { data: data }); + } +}); diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index add0345f012..76f9e1d9abd 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1 +1,1011 @@ -export { default } from "ember-data/-private/adapters/rest-adapter"; +/** + @module ember-data +*/ + +import Ember from 'ember'; +import Adapter from "ember-data/adapter"; +import { + AdapterError, + InvalidError, + TimeoutError, + AbortError +} from 'ember-data/-private/adapters/errors'; +import EmptyObject from "ember-data/-private/system/empty-object"; +import BuildURLMixin from "ember-data/-private/adapters/build-url-mixin"; +import isEnabled from 'ember-data/-private/features'; + +const { + MapWithDefault, + get +} = Ember; + +/** + The REST adapter allows your store to communicate with an HTTP server by + transmitting JSON via XHR. Most Ember.js apps that consume a JSON API + should use the REST adapter. + + This adapter is designed around the idea that the JSON exchanged with + the server should be conventional. + + ## JSON Structure + + The REST adapter expects the JSON returned from your server to follow + these conventions. + + ### Object Root + + The JSON payload should be an object that contains the record inside a + root property. For example, in response to a `GET` request for + `/posts/1`, the JSON should look like this: + + ```js + { + "post": { + "id": 1, + "title": "I'm Running to Reform the W3C's Tag", + "author": "Yehuda Katz" + } + } + ``` + + Similarly, in response to a `GET` request for `/posts`, the JSON should + look like this: + + ```js + { + "posts": [ + { + "id": 1, + "title": "I'm Running to Reform the W3C's Tag", + "author": "Yehuda Katz" + }, + { + "id": 2, + "title": "Rails is omakase", + "author": "D2H" + } + ] + } + ``` + + Note that the object root can be pluralized for both a single-object response + and an array response: the REST adapter is not strict on this. Further, if the + HTTP server responds to a `GET` request to `/posts/1` (e.g. the response to a + `findRecord` query) with more than one object in the array, Ember Data will + only display the object with the matching ID. + + ### Conventional Names + + Attribute names in your JSON payload should be the camelCased versions of + the attributes in your Ember.js models. + + For example, if you have a `Person` model: + + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + occupation: DS.attr('string') + }); + ``` + + The JSON returned should look like this: + + ```js + { + "person": { + "id": 5, + "firstName": "Barack", + "lastName": "Obama", + "occupation": "President" + } + } + ``` + + ## Customization + + ### Endpoint path customization + + Endpoint paths can be prefixed with a `namespace` by setting the namespace + property on the adapter: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + namespace: 'api/1' + }); + ``` + Requests for the `Person` model would now target `/api/1/people/1`. + + ### Host customization + + An adapter can target other hosts by setting the `host` property. + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + host: 'https://api.example.com' + }); + ``` + + ### Headers customization + + Some APIs require HTTP headers, e.g. to provide an API key. Arbitrary + headers can be set as key/value pairs on the `RESTAdapter`'s `headers` + object and Ember Data will send them along with each ajax request. + + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + headers: { + "API_KEY": "secret key", + "ANOTHER_HEADER": "Some header value" + } + }); + ``` + + `headers` can also be used as a computed property to support dynamic + headers. In the example below, the `session` object has been + injected into an adapter by Ember's container. + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + headers: Ember.computed('session.authToken', function() { + return { + "API_KEY": this.get("session.authToken"), + "ANOTHER_HEADER": "Some header value" + }; + }) + }); + ``` + + In some cases, your dynamic headers may require data from some + object outside of Ember's observer system (for example + `document.cookie`). You can use the + [volatile](/api/classes/Ember.ComputedProperty.html#method_volatile) + function to set the property into a non-cached mode causing the headers to + be recomputed with every request. + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + headers: Ember.computed(function() { + return { + "API_KEY": Ember.get(document.cookie.match(/apiKey\=([^;]*)/), "1"), + "ANOTHER_HEADER": "Some header value" + }; + }).volatile() + }); + ``` + + @class RESTAdapter + @constructor + @namespace DS + @extends DS.Adapter + @uses DS.BuildURLMixin +*/ +export default Adapter.extend(BuildURLMixin, { + defaultSerializer: '-rest', + + /** + By default, the RESTAdapter will send the query params sorted alphabetically to the + server. + + For example: + + ```js + store.query('posts', { sort: 'price', category: 'pets' }); + ``` + + will generate a requests like this `/posts?category=pets&sort=price`, even if the + parameters were specified in a different order. + + That way the generated URL will be deterministic and that simplifies caching mechanisms + in the backend. + + Setting `sortQueryParams` to a falsey value will respect the original order. + + In case you want to sort the query parameters with a different criteria, set + `sortQueryParams` to your custom sort function. + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + sortQueryParams: function(params) { + var sortedKeys = Object.keys(params).sort().reverse(); + var len = sortedKeys.length, newParams = {}; + + for (var i = 0; i < len; i++) { + newParams[sortedKeys[i]] = params[sortedKeys[i]]; + } + return newParams; + } + }); + ``` + + @method sortQueryParams + @param {Object} obj + @return {Object} + */ + sortQueryParams(obj) { + var keys = Object.keys(obj); + var len = keys.length; + if (len < 2) { + return obj; + } + var newQueryParams = {}; + var sortedKeys = keys.sort(); + + for (var i = 0; i < len; i++) { + newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]]; + } + return newQueryParams; + }, + + /** + By default the RESTAdapter will send each find request coming from a `store.find` + or from accessing a relationship separately to the server. If your server supports passing + ids as a query string, you can set coalesceFindRequests to true to coalesce all find requests + within a single runloop. + + For example, if you have an initial payload of: + + ```javascript + { + post: { + id: 1, + comments: [1, 2] + } + } + ``` + + By default calling `post.get('comments')` will trigger the following requests(assuming the + comments haven't been loaded before): + + ``` + GET /comments/1 + GET /comments/2 + ``` + + If you set coalesceFindRequests to `true` it will instead trigger the following request: + + ``` + GET /comments?ids[]=1&ids[]=2 + ``` + + Setting coalesceFindRequests to `true` also works for `store.find` requests and `belongsTo` + relationships accessed within the same runloop. If you set `coalesceFindRequests: true` + + ```javascript + store.findRecord('comment', 1); + store.findRecord('comment', 2); + ``` + + will also send a request to: `GET /comments?ids[]=1&ids[]=2` + + Note: Requests coalescing rely on URL building strategy. So if you override `buildURL` in your app + `groupRecordsForFindMany` more likely should be overridden as well in order for coalescing to work. + + @property coalesceFindRequests + @type {boolean} + */ + coalesceFindRequests: false, + + /** + Endpoint paths can be prefixed with a `namespace` by setting the namespace + property on the adapter: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + namespace: 'api/1' + }); + ``` + + Requests for the `Post` model would now target `/api/1/post/`. + + @property namespace + @type {String} + */ + + /** + An adapter can target other hosts by setting the `host` property. + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + host: 'https://api.example.com' + }); + ``` + + Requests for the `Post` model would now target `https://api.example.com/post/`. + + @property host + @type {String} + */ + + /** + Some APIs require HTTP headers, e.g. to provide an API + key. Arbitrary headers can be set as key/value pairs on the + `RESTAdapter`'s `headers` object and Ember Data will send them + along with each ajax request. For dynamic headers see [headers + customization](/api/data/classes/DS.RESTAdapter.html#toc_headers-customization). + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + headers: { + "API_KEY": "secret key", + "ANOTHER_HEADER": "Some header value" + } + }); + ``` + + @property headers + @type {Object} + */ + + /** + Called by the store in order to fetch the JSON for a given + type and ID. + + The `findRecord` method makes an Ajax request to a URL computed by + `buildURL`, and returns a promise for the resulting payload. + + This method performs an HTTP `GET` request with the id provided as part of the query string. + + @method findRecord + @param {DS.Store} store + @param {DS.Model} type + @param {String} id + @param {DS.Snapshot} snapshot + @return {Promise} promise + */ + findRecord(store, type, id, snapshot) { + const url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); + const query = this.buildQuery(snapshot); + + return this.ajax(url, 'GET', { data: query }); + }, + + /** + Called by the store in order to fetch a JSON array for all + of the records for a given type. + + The `findAll` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a + promise for the resulting payload. + + @method findAll + @param {DS.Store} store + @param {DS.Model} type + @param {String} sinceToken + @param {DS.SnapshotRecordArray} snapshotRecordArray + @return {Promise} promise + */ + findAll(store, type, sinceToken, snapshotRecordArray) { + const url = this.buildURL(type.modelName, null, null, 'findAll'); + const query = this.buildQuery(snapshotRecordArray); + + if (sinceToken) { + query.since = sinceToken; + } + + return this.ajax(url, 'GET', { data: query }); + }, + + /** + Called by the store in order to fetch a JSON array for + the records that match a particular query. + + The `query` method makes an Ajax (HTTP GET) request to a URL + computed by `buildURL`, and returns a promise for the resulting + payload. + + The `query` argument is a simple JavaScript object that will be passed directly + to the server as parameters. + + @method query + @param {DS.Store} store + @param {DS.Model} type + @param {Object} query + @return {Promise} promise + */ + query(store, type, query) { + var url = this.buildURL(type.modelName, null, null, 'query', query); + + if (this.sortQueryParams) { + query = this.sortQueryParams(query); + } + + return this.ajax(url, 'GET', { data: query }); + }, + + /** + Called by the store in order to fetch a JSON object for + the record that matches a particular query. + + The `queryRecord` method makes an Ajax (HTTP GET) request to a URL + computed by `buildURL`, and returns a promise for the resulting + payload. + + The `query` argument is a simple JavaScript object that will be passed directly + to the server as parameters. + + @method queryRecord + @param {DS.Store} store + @param {DS.Model} type + @param {Object} query + @return {Promise} promise + */ + queryRecord(store, type, query) { + var url = this.buildURL(type.modelName, null, null, 'queryRecord', query); + + if (this.sortQueryParams) { + query = this.sortQueryParams(query); + } + + return this.ajax(url, 'GET', { data: query }); + }, + + /** + Called by the store in order to fetch several records together if `coalesceFindRequests` is true + + For example, if the original payload looks like: + + ```js + { + "id": 1, + "title": "Rails is omakase", + "comments": [ 1, 2, 3 ] + } + ``` + + The IDs will be passed as a URL-encoded Array of IDs, in this form: + + ``` + ids[]=1&ids[]=2&ids[]=3 + ``` + + Many servers, such as Rails and PHP, will automatically convert this URL-encoded array + into an Array for you on the server-side. If you want to encode the + IDs, differently, just override this (one-line) method. + + The `findMany` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a + promise for the resulting payload. + + @method findMany + @param {DS.Store} store + @param {DS.Model} type + @param {Array} ids + @param {Array} snapshots + @return {Promise} promise + */ + findMany(store, type, ids, snapshots) { + var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); + return this.ajax(url, 'GET', { data: { ids: ids } }); + }, + + /** + Called by the store in order to fetch a JSON array for + the unloaded records in a has-many relationship that were originally + specified as a URL (inside of `links`). + + For example, if your original payload looks like this: + + ```js + { + "post": { + "id": 1, + "title": "Rails is omakase", + "links": { "comments": "/posts/1/comments" } + } + } + ``` + + This method will be called with the parent record and `/posts/1/comments`. + + The `findHasMany` method will make an Ajax (HTTP GET) request to the originally specified URL. + + @method findHasMany + @param {DS.Store} store + @param {DS.Snapshot} snapshot + @param {String} url + @return {Promise} promise + */ + findHasMany(store, snapshot, url, relationship) { + var id = snapshot.id; + var type = snapshot.modelName; + + url = this.urlPrefix(url, this.buildURL(type, id, null, 'findHasMany')); + + return this.ajax(url, 'GET'); + }, + + /** + Called by the store in order to fetch a JSON array for + the unloaded records in a belongs-to relationship that were originally + specified as a URL (inside of `links`). + + For example, if your original payload looks like this: + + ```js + { + "person": { + "id": 1, + "name": "Tom Dale", + "links": { "group": "/people/1/group" } + } + } + ``` + + This method will be called with the parent record and `/people/1/group`. + + The `findBelongsTo` method will make an Ajax (HTTP GET) request to the originally specified URL. + + @method findBelongsTo + @param {DS.Store} store + @param {DS.Snapshot} snapshot + @param {String} url + @return {Promise} promise + */ + findBelongsTo(store, snapshot, url, relationship) { + var id = snapshot.id; + var type = snapshot.modelName; + + url = this.urlPrefix(url, this.buildURL(type, id, null, 'findBelongsTo')); + return this.ajax(url, 'GET'); + }, + + /** + Called by the store when a newly created record is + saved via the `save` method on a model record instance. + + The `createRecord` method serializes the record and makes an Ajax (HTTP POST) request + to a URL computed by `buildURL`. + + See `serialize` for information on how to customize the serialized form + of a record. + + @method createRecord + @param {DS.Store} store + @param {DS.Model} type + @param {DS.Snapshot} snapshot + @return {Promise} promise + */ + createRecord(store, type, snapshot) { + var data = {}; + var serializer = store.serializerFor(type.modelName); + var url = this.buildURL(type.modelName, null, snapshot, 'createRecord'); + + serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); + + return this.ajax(url, "POST", { data: data }); + }, + + /** + Called by the store when an existing record is saved + via the `save` method on a model record instance. + + The `updateRecord` method serializes the record and makes an Ajax (HTTP PUT) request + to a URL computed by `buildURL`. + + See `serialize` for information on how to customize the serialized form + of a record. + + @method updateRecord + @param {DS.Store} store + @param {DS.Model} type + @param {DS.Snapshot} snapshot + @return {Promise} promise + */ + updateRecord(store, type, snapshot) { + var data = {}; + var serializer = store.serializerFor(type.modelName); + + serializer.serializeIntoHash(data, type, snapshot); + + var id = snapshot.id; + var url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); + + return this.ajax(url, "PUT", { data: data }); + }, + + /** + Called by the store when a record is deleted. + + The `deleteRecord` method makes an Ajax (HTTP DELETE) request to a URL computed by `buildURL`. + + @method deleteRecord + @param {DS.Store} store + @param {DS.Model} type + @param {DS.Snapshot} snapshot + @return {Promise} promise + */ + deleteRecord(store, type, snapshot) { + var id = snapshot.id; + + return this.ajax(this.buildURL(type.modelName, id, snapshot, 'deleteRecord'), "DELETE"); + }, + + _stripIDFromURL(store, snapshot) { + var url = this.buildURL(snapshot.modelName, snapshot.id, snapshot); + + var expandedURL = url.split('/'); + //Case when the url is of the format ...something/:id + var lastSegment = expandedURL[expandedURL.length - 1]; + var id = snapshot.id; + if (lastSegment === id) { + expandedURL[expandedURL.length - 1] = ""; + } else if (endsWith(lastSegment, '?id=' + id)) { + //Case when the url is of the format ...something?id=:id + expandedURL[expandedURL.length - 1] = lastSegment.substring(0, lastSegment.length - id.length - 1); + } + + return expandedURL.join('/'); + }, + + // http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers + maxURLLength: 2048, + + /** + Organize records into groups, each of which is to be passed to separate + calls to `findMany`. + + This implementation groups together records that have the same base URL but + differing ids. For example `/comments/1` and `/comments/2` will be grouped together + because we know findMany can coalesce them together as `/comments?ids[]=1&ids[]=2` + + It also supports urls where ids are passed as a query param, such as `/comments?id=1` + but not those where there is more than 1 query param such as `/comments?id=2&name=David` + Currently only the query param of `id` is supported. If you need to support others, please + override this or the `_stripIDFromURL` method. + + It does not group records that have differing base urls, such as for example: `/posts/1/comments/2` + and `/posts/2/comments/3` + + @method groupRecordsForFindMany + @param {DS.Store} store + @param {Array} snapshots + @return {Array} an array of arrays of records, each of which is to be + loaded separately by `findMany`. + */ + groupRecordsForFindMany(store, snapshots) { + var groups = MapWithDefault.create({ defaultValue() { return []; } }); + var adapter = this; + var maxURLLength = this.maxURLLength; + + snapshots.forEach((snapshot) => { + var baseUrl = adapter._stripIDFromURL(store, snapshot); + groups.get(baseUrl).push(snapshot); + }); + + function splitGroupToFitInUrl(group, maxURLLength, paramNameLength) { + var baseUrl = adapter._stripIDFromURL(store, group[0]); + var idsSize = 0; + var splitGroups = [[]]; + + group.forEach((snapshot) => { + var additionalLength = encodeURIComponent(snapshot.id).length + paramNameLength; + if (baseUrl.length + idsSize + additionalLength >= maxURLLength) { + idsSize = 0; + splitGroups.push([]); + } + + idsSize += additionalLength; + + var lastGroupIndex = splitGroups.length - 1; + splitGroups[lastGroupIndex].push(snapshot); + }); + + return splitGroups; + } + + var groupsArray = []; + groups.forEach((group, key) => { + var paramNameLength = '&ids%5B%5D='.length; + var splitGroups = splitGroupToFitInUrl(group, maxURLLength, paramNameLength); + + splitGroups.forEach((splitGroup) => groupsArray.push(splitGroup)); + }); + + return groupsArray; + }, + + /** + Takes an ajax response, and returns the json payload or an error. + + By default this hook just returns the json payload passed to it. + You might want to override it in two cases: + + 1. Your API might return useful results in the response headers. + Response headers are passed in as the second argument. + + 2. Your API might return errors as successful responses with status code + 200 and an Errors text or object. You can return a `DS.InvalidError` or a + `DS.AdapterError` (or a sub class) from this hook and it will automatically + reject the promise and put your record into the invalid or error state. + + Returning a `DS.InvalidError` from this method will cause the + record to transition into the `invalid` state and make the + `errors` object available on the record. When returning an + `DS.InvalidError` the store will attempt to normalize the error data + returned from the server using the serializer's `extractErrors` + method. + + @method handleResponse + @param {Number} status + @param {Object} headers + @param {Object} payload + @param {Object} requestData - the original request information + @return {Object | DS.AdapterError} response + */ + handleResponse(status, headers, payload, requestData) { + if (this.isSuccess(status, headers, payload)) { + return payload; + } else if (this.isInvalid(status, headers, payload)) { + return new InvalidError(payload.errors); + } + + let errors = this.normalizeErrorResponse(status, headers, payload); + let detailedMessage = this.generatedDetailedMessage(status, headers, payload, requestData); + + return new AdapterError(errors, detailedMessage); + }, + + /** + Default `handleResponse` implementation uses this hook to decide if the + response is a success. + + @method isSuccess + @param {Number} status + @param {Object} headers + @param {Object} payload + @return {Boolean} + */ + isSuccess(status, headers, payload) { + return status >= 200 && status < 300 || status === 304; + }, + + /** + Default `handleResponse` implementation uses this hook to decide if the + response is a an invalid error. + + @method isInvalid + @param {Number} status + @param {Object} headers + @param {Object} payload + @return {Boolean} + */ + isInvalid(status, headers, payload) { + return status === 422; + }, + + /** + Takes a URL, an HTTP method and a hash of data, and makes an + HTTP request. + + When the server responds with a payload, Ember Data will call into `extractSingle` + or `extractArray` (depending on whether the original query was for one record or + many records). + + By default, `ajax` method has the following behavior: + + * It sets the response `dataType` to `"json"` + * If the HTTP method is not `"GET"`, it sets the `Content-Type` to be + `application/json; charset=utf-8` + * If the HTTP method is not `"GET"`, it stringifies the data passed in. The + data is the serialized record in the case of a save. + * Registers success and failure handlers. + + @method ajax + @private + @param {String} url + @param {String} type The request type GET, POST, PUT, DELETE etc. + @param {Object} options + @return {Promise} promise + */ + ajax(url, type, options) { + var adapter = this; + + var requestData = { + url: url, + method: type + }; + + return new Ember.RSVP.Promise(function(resolve, reject) { + var hash = adapter.ajaxOptions(url, type, options); + + hash.success = function(payload, textStatus, jqXHR) { + + let response = adapter.handleResponse( + jqXHR.status, + parseResponseHeaders(jqXHR.getAllResponseHeaders()), + payload, + requestData + ); + + if (response instanceof AdapterError) { + Ember.run.join(null, reject, response); + } else { + Ember.run.join(null, resolve, response); + } + }; + + hash.error = function(jqXHR, textStatus, errorThrown) { + let error; + + if (errorThrown instanceof Error) { + error = errorThrown; + } else if (textStatus === 'timeout') { + error = new TimeoutError(); + } else if (textStatus === 'abort') { + error = new AbortError(); + } else { + error = adapter.handleResponse( + jqXHR.status, + parseResponseHeaders(jqXHR.getAllResponseHeaders()), + adapter.parseErrorResponse(jqXHR.responseText) || errorThrown, + requestData + ); + } + + Ember.run.join(null, reject, error); + }; + + Ember.$.ajax(hash); + }, 'DS: RESTAdapter#ajax ' + type + ' to ' + url); + }, + + /** + @method ajaxOptions + @private + @param {String} url + @param {String} type The request type GET, POST, PUT, DELETE etc. + @param {Object} options + @return {Object} + */ + ajaxOptions(url, type, options) { + var hash = options || {}; + hash.url = url; + hash.type = type; + hash.dataType = 'json'; + hash.context = this; + + if (hash.data && type !== 'GET') { + hash.contentType = 'application/json; charset=utf-8'; + hash.data = JSON.stringify(hash.data); + } + + var headers = get(this, 'headers'); + if (headers !== undefined) { + hash.beforeSend = function (xhr) { + Object.keys(headers).forEach((key) => xhr.setRequestHeader(key, headers[key])); + }; + } + + return hash; + }, + + /** + @method parseErrorResponse + @private + @param {String} responseText + @return {Object} + */ + parseErrorResponse(responseText) { + var json = responseText; + + try { + json = Ember.$.parseJSON(responseText); + } catch (e) {} + + return json; + }, + + /** + @method normalizeErrorResponse + @private + @param {Number} status + @param {Object} headers + @param {Object} payload + @return {Object} errors payload + */ + normalizeErrorResponse(status, headers, payload) { + if (payload && typeof payload === 'object' && payload.errors) { + return payload.errors; + } else { + return [ + { + status: `${status}`, + title: "The backend responded with an error", + detail: `${payload}` + } + ]; + } + }, + + /** + Generates a detailed ("friendly") error message, with plenty + of information for debugging (good luck!) + + @method generatedDetailedMessage + @private + @param {Number} status + @param {Object} headers + @param {Object} payload + @return {Object} request information + */ + generatedDetailedMessage: function(status, headers, payload, requestData) { + var shortenedPayload; + var payloadContentType = headers["Content-Type"] || "Empty Content-Type"; + + if (payloadContentType === "text/html" && payload.length > 250) { + shortenedPayload = "[Omitted Lengthy HTML]"; + } else { + shortenedPayload = payload; + } + + var requestDescription = requestData.method + ' ' + requestData.url; + var payloadDescription = 'Payload (' + payloadContentType + ')'; + + return ['Ember Data Request ' + requestDescription + ' returned a ' + status, + payloadDescription, + shortenedPayload].join('\n'); + }, + + buildQuery(snapshot) { + const { include } = snapshot; + + let query = {}; + + if (isEnabled('ds-finder-include')) { + if (include) { + query.include = include; + } + } + + return query; + } +}); + +function parseResponseHeaders(headerStr) { + var headers = new EmptyObject(); + if (!headerStr) { return headers; } + + var headerPairs = headerStr.split('\u000d\u000a'); + for (var i = 0; i < headerPairs.length; i++) { + var headerPair = headerPairs[i]; + // Can't use split() here because it does the wrong thing + // if the header value has the string ": " in it. + var index = headerPair.indexOf('\u003a\u0020'); + if (index > 0) { + var key = headerPair.substring(0, index); + var val = headerPair.substring(index + 2); + headers[key] = val; + } + } + + return headers; +} + +//From http://stackoverflow.com/questions/280634/endswith-in-javascript +function endsWith(string, suffix) { + if (typeof String.prototype.endsWith !== 'function') { + return string.indexOf(suffix, string.length - suffix.length) !== -1; + } else { + return string.endsWith(suffix); + } +} diff --git a/addon/attr.js b/addon/attr.js index 803920b23cf..9a101508a16 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -1 +1,351 @@ -export { default } from "ember-data/-private/system/model/attributes"; +import Ember from 'ember'; +import Model from "ember-data/-private/system/model/model"; +import { assert, deprecate } from "ember-data/-private/debug"; + +/** + @module ember-data +*/ + +var get = Ember.get; +var Map = Ember.Map; + +/** + @class Model + @namespace DS +*/ +Model.reopenClass({ + /** + A map whose keys are the attributes of the model (properties + described by DS.attr) and whose values are the meta object for the + property. + + Example + + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + birthday: attr('date') + }); + ``` + + ```javascript + import Ember from 'ember'; + import Person from 'app/models/person'; + + var attributes = Ember.get(Person, 'attributes') + + attributes.forEach(function(meta, name) { + console.log(name, meta); + }); + + // prints: + // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} + // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} + // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} + ``` + + @property attributes + @static + @type {Ember.Map} + @readOnly + */ + attributes: Ember.computed(function() { + var map = Map.create(); + + this.eachComputedProperty((name, meta) => { + if (meta.isAttribute) { + assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.toString(), name !== 'id'); + + meta.name = name; + map.set(name, meta); + } + }); + + return map; + }).readOnly(), + + /** + A map whose keys are the attributes of the model (properties + described by DS.attr) and whose values are type of transformation + applied to each attribute. This map does not include any + attributes that do not have an transformation type. + + Example + + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + firstName: attr(), + lastName: attr('string'), + birthday: attr('date') + }); + ``` + + ```javascript + import Ember from 'ember'; + import Person from 'app/models/person'; + + var transformedAttributes = Ember.get(Person, 'transformedAttributes') + + transformedAttributes.forEach(function(field, type) { + console.log(field, type); + }); + + // prints: + // lastName string + // birthday date + ``` + + @property transformedAttributes + @static + @type {Ember.Map} + @readOnly + */ + transformedAttributes: Ember.computed(function() { + var map = Map.create(); + + this.eachAttribute((key, meta) => { + if (meta.type) { + map.set(key, meta.type); + } + }); + + return map; + }).readOnly(), + + /** + Iterates through the attributes of the model, calling the passed function on each + attribute. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(name, meta); + ``` + + - `name` the name of the current property in the iteration + - `meta` the meta object for the attribute property in the iteration + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. + + Example + + ```javascript + import DS from 'ember-data'; + + var Person = DS.Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + birthday: attr('date') + }); + + Person.eachAttribute(function(name, meta) { + console.log(name, meta); + }); + + // prints: + // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} + // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} + // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} + ``` + + @method eachAttribute + @param {Function} callback The callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + @static + */ + eachAttribute(callback, binding) { + get(this, 'attributes').forEach((meta, name) => { + callback.call(binding, name, meta); + }); + }, + + /** + Iterates through the transformedAttributes of the model, calling + the passed function on each attribute. Note the callback will not be + called for any attributes that do not have an transformation type. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(name, type); + ``` + + - `name` the name of the current property in the iteration + - `type` a string containing the name of the type of transformed + applied to the attribute + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. + + Example + + ```javascript + import DS from 'ember-data'; + + var Person = DS.Model.extend({ + firstName: attr(), + lastName: attr('string'), + birthday: attr('date') + }); + + Person.eachTransformedAttribute(function(name, type) { + console.log(name, type); + }); + + // prints: + // lastName string + // birthday date + ``` + + @method eachTransformedAttribute + @param {Function} callback The callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + @static + */ + eachTransformedAttribute(callback, binding) { + get(this, 'transformedAttributes').forEach((type, name) => { + callback.call(binding, name, type); + }); + } +}); + + +Model.reopen({ + eachAttribute(callback, binding) { + this.constructor.eachAttribute(callback, binding); + } +}); + +function getDefaultValue(record, options, key) { + if (typeof options.defaultValue === "function") { + return options.defaultValue.apply(null, arguments); + } else { + let defaultValue = options.defaultValue; + deprecate(`Non primitive defaultValues are deprecated because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.`, + typeof defaultValue !== 'object' || defaultValue === null, { + id: 'ds.defaultValue.complex-object', + until: '3.0.0' + }); + return defaultValue; + } +} + +function hasValue(record, key) { + return key in record._attributes || + key in record._inFlightAttributes || + key in record._data; +} + +function getValue(record, key) { + if (key in record._attributes) { + return record._attributes[key]; + } else if (key in record._inFlightAttributes) { + return record._inFlightAttributes[key]; + } else { + return record._data[key]; + } +} + +/** + `DS.attr` defines an attribute on a [DS.Model](/api/data/classes/DS.Model.html). + By default, attributes are passed through as-is, however you can specify an + optional type to have the value automatically transformed. + Ember Data ships with four basic transform types: `string`, `number`, + `boolean` and `date`. You can define your own transforms by subclassing + [DS.Transform](/api/data/classes/DS.Transform.html). + + Note that you cannot use `attr` to define an attribute of `id`. + + `DS.attr` takes an optional hash as a second parameter, currently + supported options are: + + - `defaultValue`: Pass a string or a function to be called to set the attribute + to a default value if none is supplied. + + Example + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + username: DS.attr('string'), + email: DS.attr('string'), + verified: DS.attr('boolean', { defaultValue: false }) + }); + ``` + + Default value can also be a function. This is useful it you want to return + a new object for each attribute. + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + username: attr('string'), + email: attr('string'), + settings: attr({defaultValue: function() { + return {}; + }}) + }); + ``` + + @namespace + @method attr + @for DS + @param {String} type the attribute type + @param {Object} options a hash of options + @return {Attribute} +*/ + +export default function attr(type, options) { + if (typeof type === 'object') { + options = type; + type = undefined; + } else { + options = options || {}; + } + + var meta = { + type: type, + isAttribute: true, + options: options + }; + + return Ember.computed({ + get(key) { + var internalModel = this._internalModel; + if (hasValue(internalModel, key)) { + return getValue(internalModel, key); + } else { + return getDefaultValue(this, options, key); + } + }, + set(key, value) { + var internalModel = this._internalModel; + var oldValue = getValue(internalModel, key); + + if (value !== oldValue) { + // Add the new value to the changed attributes hash; it will get deleted by + // the 'didSetProperty' handler if it is no different from the original value + internalModel._attributes[key] = value; + + this._internalModel.send('didSetProperty', { + name: key, + oldValue: oldValue, + originalValue: internalModel._data[key], + value: value + }); + } + + return value; + } + }).meta(meta); +} diff --git a/addon/index.js b/addon/index.js index 241ed273ffa..e74808fca15 100644 --- a/addon/index.js +++ b/addon/index.js @@ -38,9 +38,9 @@ import { RootState, attr } from "ember-data/-private/system/model"; -import Model from "ember-data/-private/system/model"; +import Model from "ember-data/model"; import Snapshot from "ember-data/-private/system/snapshot"; -import Adapter from "ember-data/-private/system/adapter"; +import Adapter from "ember-data/adapter"; import Serializer from "ember-data/-private/system/serializer"; import DebugAdapter from "ember-data/-private/system/debug"; @@ -81,7 +81,7 @@ import { BooleanTransform } from "ember-data/-private/transforms"; -import {hasMany, belongsTo} from "ember-data/-private/system/relationships"; +import {hasMany, belongsTo} from "ember-data/relationships"; import setupContainer from "ember-data/-private/setup-container"; import initializeStoreService from 'ember-data/-private/instance-initializers/initialize-store-service'; diff --git a/addon/model.js b/addon/model.js index 837dc55c6a0..b0c7b811b47 100644 --- a/addon/model.js +++ b/addon/model.js @@ -1 +1,3 @@ -export { default } from "ember-data/-private/system/model"; +import Model from "ember-data/-private/system/model"; + +export default Model; diff --git a/addon/relationships.js b/addon/relationships.js index 2d67cbb92c9..23c1f6f7e55 100644 --- a/addon/relationships.js +++ b/addon/relationships.js @@ -1 +1,14 @@ -export * from 'ember-data/-private/system/relationships'; +/** + @module ember-data +*/ + +import belongsTo from "ember-data/-private/system/relationships/belongs-to"; +import hasMany from "ember-data/-private/system/relationships/has-many"; + +import "ember-data/-private/system/relationships/ext"; + +export { + belongsTo, + hasMany +}; + diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 8173a37dd53..a4888a054d5 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -1 +1,507 @@ -export { default } from "ember-data/-private/serializers/json-api-serializer"; +/** + @module ember-data +*/ + +import Ember from 'ember'; +import { assert, runInDebug, warn } from 'ember-data/-private/debug'; +import JSONSerializer from 'ember-data/serializers/json'; +import normalizeModelName from 'ember-data/-private/system/normalize-model-name'; +import { pluralize, singularize } from 'ember-inflector'; + +var dasherize = Ember.String.dasherize; + +/** + Ember Data 2.0 Serializer: + + In Ember Data a Serializer is used to serialize and deserialize + records when they are transferred in and out of an external source. + This process involves normalizing property names, transforming + attribute values and serializing relationships. + + `JSONAPISerializer` supports the http://jsonapi.org/ spec and is the + serializer recommended by Ember Data. + + This serializer normalizes a JSON API payload that looks like: + + ```js + + // models/player.js + import DS from "ember-data"; + + export default DS.Model.extend({ + name: DS.attr(), + skill: DS.attr(), + gamesPlayed: DS.attr(), + club: DS.belongsTo('club') + }); + + // models/club.js + import DS from "ember-data"; + + export default DS.Model.extend({ + name: DS.attr(), + location: DS.attr(), + players: DS.hasMany('player') + }); + ``` + + ```js + + { + "data": [ + { + "attributes": { + "name": "Benfica", + "location": "Portugal" + }, + "id": "1", + "relationships": { + "players": { + "data": [ + { + "id": "3", + "type": "players" + } + ] + } + }, + "type": "clubs" + } + ], + "included": [ + { + "attributes": { + "name": "Eusebio Silva Ferreira", + "skill": "Rocket shot", + "games-played": 431 + }, + "id": "3", + "relationships": { + "club": { + "data": { + "id": "1", + "type": "clubs" + } + } + }, + "type": "players" + } + ] + } + ``` + + to the format that the Ember Data store expects. + + @class JSONAPISerializer + @namespace DS + @extends DS.JSONSerializer +*/ +const JSONAPISerializer = JSONSerializer.extend({ + + /** + @method _normalizeDocumentHelper + @param {Object} documentHash + @return {Object} + @private + */ + _normalizeDocumentHelper(documentHash) { + + if (Ember.typeOf(documentHash.data) === 'object') { + documentHash.data = this._normalizeResourceHelper(documentHash.data); + } else if (Array.isArray(documentHash.data)) { + let ret = new Array(documentHash.data.length); + + for (let i = 0; i < documentHash.data.length; i++) { + let data = documentHash.data[i]; + ret[i] = this._normalizeResourceHelper(data); + } + + documentHash.data = ret; + } + + if (Array.isArray(documentHash.included)) { + let ret = new Array(documentHash.included.length); + + for (let i = 0; i < documentHash.included.length; i++) { + let included = documentHash.included[i]; + ret[i] = this._normalizeResourceHelper(included); + } + + documentHash.included = ret; + } + + return documentHash; + }, + + /** + @method _normalizeRelationshipDataHelper + @param {Object} relationshipDataHash + @return {Object} + @private + */ + _normalizeRelationshipDataHelper(relationshipDataHash) { + let type = this.modelNameFromPayloadKey(relationshipDataHash.type); + relationshipDataHash.type = type; + return relationshipDataHash; + }, + + /** + @method _normalizeResourceHelper + @param {Object} resourceHash + @return {Object} + @private + */ + _normalizeResourceHelper(resourceHash) { + assert(this.warnMessageForUndefinedType(), !Ember.isNone(resourceHash.type), { + id: 'ds.serializer.type-is-undefined' + }); + + let modelName = this.modelNameFromPayloadKey(resourceHash.type); + + if (!this.store._hasModelFor(modelName)) { + warn(this.warnMessageNoModelForType(modelName, resourceHash.type), false, { + id: 'ds.serializer.model-for-type-missing' + }); + return null; + } + + let modelClass = this.store.modelFor(modelName); + let serializer = this.store.serializerFor(modelName); + let { data } = serializer.normalize(modelClass, resourceHash); + return data; + }, + + /** + @method pushPayload + @param {DS.Store} store + @param {Object} payload + */ + pushPayload(store, payload) { + let normalizedPayload = this._normalizeDocumentHelper(payload); + store.push(normalizedPayload); + }, + + /** + @method _normalizeResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @param {Boolean} isSingle + @return {Object} JSON-API Document + @private + */ + _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { + let normalizedPayload = this._normalizeDocumentHelper(payload); + return normalizedPayload; + }, + + /** + @method extractAttributes + @param {DS.Model} modelClass + @param {Object} resourceHash + @return {Object} + */ + extractAttributes(modelClass, resourceHash) { + var attributes = {}; + + if (resourceHash.attributes) { + modelClass.eachAttribute((key) => { + let attributeKey = this.keyForAttribute(key, 'deserialize'); + if (resourceHash.attributes.hasOwnProperty(attributeKey)) { + attributes[key] = resourceHash.attributes[attributeKey]; + } + }); + } + + return attributes; + }, + + /** + @method extractRelationship + @param {Object} relationshipHash + @return {Object} + */ + extractRelationship(relationshipHash) { + + if (Ember.typeOf(relationshipHash.data) === 'object') { + relationshipHash.data = this._normalizeRelationshipDataHelper(relationshipHash.data); + } + + if (Array.isArray(relationshipHash.data)) { + let ret = new Array(relationshipHash.data.length); + + for (let i = 0; i < relationshipHash.data.length; i++) { + let data = relationshipHash.data[i]; + ret[i] = this._normalizeRelationshipDataHelper(data); + } + + relationshipHash.data = ret; + } + + return relationshipHash; + }, + + /** + @method extractRelationships + @param {Object} modelClass + @param {Object} resourceHash + @return {Object} + */ + extractRelationships(modelClass, resourceHash) { + let relationships = {}; + + if (resourceHash.relationships) { + modelClass.eachRelationship((key, relationshipMeta) => { + let relationshipKey = this.keyForRelationship(key, relationshipMeta.kind, 'deserialize'); + if (resourceHash.relationships.hasOwnProperty(relationshipKey)) { + + let relationshipHash = resourceHash.relationships[relationshipKey]; + relationships[key] = this.extractRelationship(relationshipHash); + + } + }); + } + + return relationships; + }, + + /** + @method _extractType + @param {DS.Model} modelClass + @param {Object} resourceHash + @return {String} + @private + */ + _extractType(modelClass, resourceHash) { + return this.modelNameFromPayloadKey(resourceHash.type); + }, + + /** + @method modelNameFromPayloadKey + @param {String} key + @return {String} the model's modelName + */ + modelNameFromPayloadKey(key) { + return singularize(normalizeModelName(key)); + }, + + /** + @method payloadKeyFromModelName + @param {String} modelName + @return {String} + */ + payloadKeyFromModelName(modelName) { + return pluralize(modelName); + }, + + /** + @method normalize + @param {DS.Model} modelClass + @param {Object} resourceHash the resource hash from the adapter + @return {Object} the normalized resource hash + */ + normalize(modelClass, resourceHash) { + if (resourceHash.attributes) { + this.normalizeUsingDeclaredMapping(modelClass, resourceHash.attributes); + } + + if (resourceHash.relationships) { + this.normalizeUsingDeclaredMapping(modelClass, resourceHash.relationships); + } + + let data = { + id: this.extractId(modelClass, resourceHash), + type: this._extractType(modelClass, resourceHash), + attributes: this.extractAttributes(modelClass, resourceHash), + relationships: this.extractRelationships(modelClass, resourceHash) + }; + + this.applyTransforms(modelClass, data.attributes); + + return { data }; + }, + + /** + `keyForAttribute` can be used to define rules for how to convert an + attribute name in your model to a key in your JSON. + By default `JSONAPISerializer` follows the format used on the examples of + http://jsonapi.org/format and uses dashes as the word separator in the JSON + attribute keys. + + This behaviour can be easily customized by extending this method. + + Example + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONAPISerializer.extend({ + keyForAttribute: function(attr, method) { + return Ember.String.dasherize(attr).toUpperCase(); + } + }); + ``` + + @method keyForAttribute + @param {String} key + @param {String} method + @return {String} normalized key + */ + keyForAttribute(key, method) { + return dasherize(key); + }, + + /** + `keyForRelationship` can be used to define a custom key when + serializing and deserializing relationship properties. + By default `JSONAPISerializer` follows the format used on the examples of + http://jsonapi.org/format and uses dashes as word separators in + relationship properties. + + This behaviour can be easily customized by extending this method. + + Example + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONAPISerializer.extend({ + keyForRelationship: function(key, relationship, method) { + return Ember.String.underscore(key); + } + }); + ``` + @method keyForRelationship + @param {String} key + @param {String} typeClass + @param {String} method + @return {String} normalized key + */ + keyForRelationship(key, typeClass, method) { + return dasherize(key); + }, + + /** + @method serialize + @param {DS.Snapshot} snapshot + @param {Object} options + @return {Object} json + */ + serialize(snapshot, options) { + let data = this._super(...arguments); + data.type = this.payloadKeyFromModelName(snapshot.modelName); + return { data }; + }, + + /** + @method serializeAttribute + @param {DS.Snapshot} snapshot + @param {Object} json + @param {String} key + @param {Object} attribute + */ + serializeAttribute(snapshot, json, key, attribute) { + const type = attribute.type; + + if (this._canSerialize(key)) { + json.attributes = json.attributes || {}; + + let value = snapshot.attr(key); + if (type) { + const transform = this.transformFor(type); + value = transform.serialize(value); + } + + let payloadKey = this._getMappedKey(key, snapshot.type); + + if (payloadKey === key) { + payloadKey = this.keyForAttribute(key, 'serialize'); + } + + json.attributes[payloadKey] = value; + } + }, + + /** + @method serializeBelongsTo + @param {DS.Snapshot} snapshot + @param {Object} json + @param {Object} relationship + */ + serializeBelongsTo(snapshot, json, relationship) { + var key = relationship.key; + + if (this._canSerialize(key)) { + var belongsTo = snapshot.belongsTo(key); + if (belongsTo !== undefined) { + + json.relationships = json.relationships || {}; + + var payloadKey = this._getMappedKey(key, snapshot.type); + if (payloadKey === key) { + payloadKey = this.keyForRelationship(key, 'belongsTo', 'serialize'); + } + + let data = null; + if (belongsTo) { + data = { + type: this.payloadKeyFromModelName(belongsTo.modelName), + id: belongsTo.id + }; + } + + json.relationships[payloadKey] = { data }; + } + } + }, + + /** + @method serializeHasMany + @param {DS.Snapshot} snapshot + @param {Object} json + @param {Object} relationship + */ + serializeHasMany(snapshot, json, relationship) { + var key = relationship.key; + + if (this._shouldSerializeHasMany(snapshot, key, relationship)) { + var hasMany = snapshot.hasMany(key); + if (hasMany !== undefined) { + + json.relationships = json.relationships || {}; + + var payloadKey = this._getMappedKey(key, snapshot.type); + if (payloadKey === key && this.keyForRelationship) { + payloadKey = this.keyForRelationship(key, 'hasMany', 'serialize'); + } + + let data = new Array(hasMany.length); + + for (let i = 0; i < hasMany.length; i++) { + let item = hasMany[i]; + data[i] = { + type: this.payloadKeyFromModelName(item.modelName), + id: item.id + }; + } + + json.relationships[payloadKey] = { data }; + } + } + } +}); + +runInDebug(function() { + JSONAPISerializer.reopen({ + warnMessageForUndefinedType() { + return 'Encountered a resource object with an undefined type (resolved resource using ' + this.constructor.toString() + ')'; + }, + warnMessageNoModelForType(modelName, originalType) { + return 'Encountered a resource object with type "' + originalType + '", but no model was found for model name "' + modelName + '" (resolved model name using ' + this.constructor.toString() + '.modelNameFromPayloadKey("' + originalType + '"))'; + } + }); +}); + +export default JSONAPISerializer; diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 39a167ec9a2..0eb2389897a 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1 +1,1392 @@ -export { default } from "ember-data/-private/serializers/json-serializer"; +import Ember from 'ember'; +import { assert, warn } from 'ember-data/-private/debug'; +import Serializer from "ember-data/-private/system/serializer"; +import coerceId from "ember-data/-private/system/coerce-id"; +import normalizeModelName from "ember-data/-private/system/normalize-model-name"; +import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; + +import { + getOwner +} from 'ember-data/-private/utils'; + +import { errorsArrayToHash } from "ember-data/-private/adapters/errors"; + +var get = Ember.get; +var isNone = Ember.isNone; +var merge = Ember.merge; + +/** + Ember Data 2.0 Serializer: + + In Ember Data a Serializer is used to serialize and deserialize + records when they are transferred in and out of an external source. + This process involves normalizing property names, transforming + attribute values and serializing relationships. + + By default, Ember Data uses and recommends the `JSONAPISerializer`. + + `JSONSerializer` is useful for simpler or legacy backends that may + not support the http://jsonapi.org/ spec. + + For example, given the following `User` model and JSON payload: + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + friends: DS.hasMany('user'), + house: DS.belongsTo('location'), + + name: DS.attr('string') + }); + ``` + + ```js + { + id: 1, + name: 'Sebastian', + friends: [3, 4], + links: { + house: '/houses/lefkada' + } + } + ``` + + `JSONSerializer` will normalize the JSON payload to the JSON API format that the + Ember Data store expects. + + You can customize how JSONSerializer processes its payload by passing options in + the `attrs` hash or by subclassing the `JSONSerializer` and overriding hooks: + + - To customize how a single record is normalized, use the `normalize` hook. + - To customize how `JSONSerializer` normalizes the whole server response, use the + `normalizeResponse` hook. + - To customize how `JSONSerializer` normalizes a specific response from the server, + use one of the many specific `normalizeResponse` hooks. + - To customize how `JSONSerializer` normalizes your id, attributes or relationships, + use the `extractId`, `extractAttributes` and `extractRelationships` hooks. + + The `JSONSerializer` normalization process follows these steps: + + - `normalizeResponse` - entry method to the serializer. + - `normalizeCreateRecordResponse` - a `normalizeResponse` for a specific operation is called. + - `normalizeSingleResponse`|`normalizeArrayResponse` - for methods like `createRecord` we expect + a single record back, while for methods like `findAll` we expect multiple methods back. + - `normalize` - `normalizeArray` iterates and calls `normalize` for each of its records while `normalizeSingle` + calls it once. This is the method you most likely want to subclass. + - `extractId` | `extractAttributes` | `extractRelationships` - `normalize` delegates to these methods to + turn the record payload into the JSON API format. + + @class JSONSerializer + @namespace DS + @extends DS.Serializer +*/ +export default Serializer.extend({ + + /** + The `primaryKey` is used when serializing and deserializing + data. Ember Data always uses the `id` property to store the id of + the record. The external source may not always follow this + convention. In these cases it is useful to override the + `primaryKey` property to match the `primaryKey` of your external + store. + + Example + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + primaryKey: '_id' + }); + ``` + + @property primaryKey + @type {String} + @default 'id' + */ + primaryKey: 'id', + + /** + The `attrs` object can be used to declare a simple mapping between + property names on `DS.Model` records and payload keys in the + serialized JSON object representing the record. An object with the + property `key` can also be used to designate the attribute's key on + the response payload. + + Example + + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + occupation: DS.attr('string'), + admin: DS.attr('boolean') + }); + ``` + + ```app/serializers/person.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + attrs: { + admin: 'is_admin', + occupation: { key: 'career' } + } + }); + ``` + + You can also remove attributes by setting the `serialize` key to + `false` in your mapping object. + + Example + + ```app/serializers/person.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + attrs: { + admin: { serialize: false }, + occupation: { key: 'career' } + } + }); + ``` + + When serialized: + + ```javascript + { + "firstName": "Harry", + "lastName": "Houdini", + "career": "magician" + } + ``` + + Note that the `admin` is now not included in the payload. + + @property attrs + @type {Object} + */ + mergedProperties: ['attrs'], + + /** + Given a subclass of `DS.Model` and a JSON object this method will + iterate through each attribute of the `DS.Model` and invoke the + `DS.Transform#deserialize` method on the matching property of the + JSON object. This method is typically called after the + serializer's `normalize` method. + + @method applyTransforms + @private + @param {DS.Model} typeClass + @param {Object} data The data to transform + @return {Object} data The transformed data object + */ + applyTransforms(typeClass, data) { + typeClass.eachTransformedAttribute((key, typeClass) => { + if (!data.hasOwnProperty(key)) { return; } + + var transform = this.transformFor(typeClass); + data[key] = transform.deserialize(data[key]); + }); + + return data; + }, + + /** + The `normalizeResponse` method is used to normalize a payload from the + server to a JSON-API Document. + + http://jsonapi.org/format/#document-structure + + This method delegates to a more specific normalize method based on + the `requestType`. + + To override this method with a custom one, make sure to call + `return this._super(store, primaryModelClass, payload, id, requestType)` with your + pre-processed data. + + Here's an example of using `normalizeResponse` manually: + + ```javascript + socket.on('message', function(message) { + var data = message.data; + var modelClass = store.modelFor(data.modelName); + var serializer = store.serializerFor(data.modelName); + var json = serializer.normalizeSingleResponse(store, modelClass, data, data.id); + + store.push(normalized); + }); + ``` + + @method normalizeResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeResponse(store, primaryModelClass, payload, id, requestType) { + switch (requestType) { + case 'findRecord': + return this.normalizeFindRecordResponse(...arguments); + case 'queryRecord': + return this.normalizeQueryRecordResponse(...arguments); + case 'findAll': + return this.normalizeFindAllResponse(...arguments); + case 'findBelongsTo': + return this.normalizeFindBelongsToResponse(...arguments); + case 'findHasMany': + return this.normalizeFindHasManyResponse(...arguments); + case 'findMany': + return this.normalizeFindManyResponse(...arguments); + case 'query': + return this.normalizeQueryResponse(...arguments); + case 'createRecord': + return this.normalizeCreateRecordResponse(...arguments); + case 'deleteRecord': + return this.normalizeDeleteRecordResponse(...arguments); + case 'updateRecord': + return this.normalizeUpdateRecordResponse(...arguments); + } + }, + + /** + @method normalizeFindRecordResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeFindRecordResponse(store, primaryModelClass, payload, id, requestType) { + return this.normalizeSingleResponse(...arguments); + }, + + /** + @method normalizeQueryRecordResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeQueryRecordResponse(store, primaryModelClass, payload, id, requestType) { + return this.normalizeSingleResponse(...arguments); + }, + + /** + @method normalizeFindAllResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeFindAllResponse(store, primaryModelClass, payload, id, requestType) { + return this.normalizeArrayResponse(...arguments); + }, + + /** + @method normalizeFindBelongsToResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeFindBelongsToResponse(store, primaryModelClass, payload, id, requestType) { + return this.normalizeSingleResponse(...arguments); + }, + + /** + @method normalizeFindHasManyResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeFindHasManyResponse(store, primaryModelClass, payload, id, requestType) { + return this.normalizeArrayResponse(...arguments); + }, + + /** + @method normalizeFindManyResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeFindManyResponse(store, primaryModelClass, payload, id, requestType) { + return this.normalizeArrayResponse(...arguments); + }, + + /** + @method normalizeQueryResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeQueryResponse(store, primaryModelClass, payload, id, requestType) { + return this.normalizeArrayResponse(...arguments); + }, + + /** + @method normalizeCreateRecordResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeCreateRecordResponse(store, primaryModelClass, payload, id, requestType) { + return this.normalizeSaveResponse(...arguments); + }, + + /** + @method normalizeDeleteRecordResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeDeleteRecordResponse(store, primaryModelClass, payload, id, requestType) { + return this.normalizeSaveResponse(...arguments); + }, + + /** + @method normalizeUpdateRecordResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeUpdateRecordResponse(store, primaryModelClass, payload, id, requestType) { + return this.normalizeSaveResponse(...arguments); + }, + + /** + @method normalizeSaveResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeSaveResponse(store, primaryModelClass, payload, id, requestType) { + return this.normalizeSingleResponse(...arguments); + }, + + /** + @method normalizeSingleResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeSingleResponse(store, primaryModelClass, payload, id, requestType) { + return this._normalizeResponse(store, primaryModelClass, payload, id, requestType, true); + }, + + /** + @method normalizeArrayResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document + */ + normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) { + return this._normalizeResponse(store, primaryModelClass, payload, id, requestType, false); + }, + + /** + @method _normalizeResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @param {Boolean} isSingle + @return {Object} JSON-API Document + @private + */ + _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { + let documentHash = { + data: null, + included: [] + }; + + let meta = this.extractMeta(store, primaryModelClass, payload); + if (meta) { + assert('The `meta` returned from `extractMeta` has to be an object, not "' + Ember.typeOf(meta) + '".', Ember.typeOf(meta) === 'object'); + documentHash.meta = meta; + } + + if (isSingle) { + let { data, included } = this.normalize(primaryModelClass, payload); + documentHash.data = data; + if (included) { + documentHash.included = included; + } + } else { + let ret = new Array(payload.length); + for (let i = 0, l = payload.length; i < l; i++) { + let item = payload[i]; + let { data, included } = this.normalize(primaryModelClass, item); + if (included) { + documentHash.included.push(...included); + } + ret[i] = data; + } + + documentHash.data = ret; + } + + return documentHash; + }, + + + /** + Normalizes a part of the JSON payload returned by + the server. You should override this method, munge the hash + and call super if you have generic normalization to do. + + It takes the type of the record that is being normalized + (as a DS.Model class), the property where the hash was + originally found, and the hash to normalize. + + You can use this method, for example, to normalize underscored keys to camelized + or other general-purpose normalizations. + + Example + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + normalize: function(typeClass, hash) { + var fields = Ember.get(typeClass, 'fields'); + fields.forEach(function(field) { + var payloadField = Ember.String.underscore(field); + if (field === payloadField) { return; } + + hash[field] = hash[payloadField]; + delete hash[payloadField]; + }); + return this._super.apply(this, arguments); + } + }); + ``` + + @method normalize + @param {DS.Model} typeClass + @param {Object} hash + @return {Object} + */ + normalize(modelClass, resourceHash) { + let data = null; + + if (resourceHash) { + this.normalizeUsingDeclaredMapping(modelClass, resourceHash); + + data = { + id: this.extractId(modelClass, resourceHash), + type: modelClass.modelName, + attributes: this.extractAttributes(modelClass, resourceHash), + relationships: this.extractRelationships(modelClass, resourceHash) + }; + + this.applyTransforms(modelClass, data.attributes); + } + + return { data }; + }, + + /** + Returns the resource's ID. + + @method extractId + @param {Object} modelClass + @param {Object} resourceHash + @return {String} + */ + extractId(modelClass, resourceHash) { + var primaryKey = get(this, 'primaryKey'); + var id = resourceHash[primaryKey]; + return coerceId(id); + }, + + /** + Returns the resource's attributes formatted as a JSON-API "attributes object". + + http://jsonapi.org/format/#document-resource-object-attributes + + @method extractAttributes + @param {Object} modelClass + @param {Object} resourceHash + @return {Object} + */ + extractAttributes(modelClass, resourceHash) { + var attributeKey; + var attributes = {}; + + modelClass.eachAttribute((key) => { + attributeKey = this.keyForAttribute(key, 'deserialize'); + if (resourceHash.hasOwnProperty(attributeKey)) { + attributes[key] = resourceHash[attributeKey]; + } + }); + + return attributes; + }, + + /** + Returns a relationship formatted as a JSON-API "relationship object". + + http://jsonapi.org/format/#document-resource-object-relationships + + @method extractRelationship + @param {Object} relationshipModelName + @param {Object} relationshipHash + @return {Object} + */ + extractRelationship(relationshipModelName, relationshipHash) { + if (Ember.isNone(relationshipHash)) { return null; } + /* + When `relationshipHash` is an object it usually means that the relationship + is polymorphic. It could however also be embedded resources that the + EmbeddedRecordsMixin has be able to process. + */ + if (Ember.typeOf(relationshipHash) === 'object') { + if (relationshipHash.id) { + relationshipHash.id = coerceId(relationshipHash.id); + } + + const modelClass = this.store.modelFor(relationshipModelName); + if (relationshipHash.type && !modelHasAttributeOrRelationshipNamedType(modelClass)) { + relationshipHash.type = this.modelNameFromPayloadKey(relationshipHash.type); + } + return relationshipHash; + } + return { id: coerceId(relationshipHash), type: relationshipModelName }; + }, + + /** + Returns a polymorphic relationship formatted as a JSON-API "relationship object". + + http://jsonapi.org/format/#document-resource-object-relationships + + `relationshipOptions` is a hash which contains more information about the + polymorphic relationship which should be extracted: + - `resourceHash` complete hash of the resource the relationship should be + extracted from + - `relationshipKey` key under which the value for the relationship is + extracted from the resourceHash + - `relationshipMeta` meta information about the relationship + + @method extractPolymorphicRelationship + @param {Object} relationshipModelName + @param {Object} relationshipHash + @param {Object} relationshipOptions + @return {Object} + */ + extractPolymorphicRelationship(relationshipModelName, relationshipHash, relationshipOptions) { + return this.extractRelationship(relationshipModelName, relationshipHash); + }, + + /** + Returns the resource's relationships formatted as a JSON-API "relationships object". + + http://jsonapi.org/format/#document-resource-object-relationships + + @method extractRelationships + @param {Object} modelClass + @param {Object} resourceHash + @return {Object} + */ + extractRelationships(modelClass, resourceHash) { + let relationships = {}; + + modelClass.eachRelationship((key, relationshipMeta) => { + let relationship = null; + let relationshipKey = this.keyForRelationship(key, relationshipMeta.kind, 'deserialize'); + if (resourceHash.hasOwnProperty(relationshipKey)) { + let data = null; + let relationshipHash = resourceHash[relationshipKey]; + if (relationshipMeta.kind === 'belongsTo') { + if (relationshipMeta.options.polymorphic) { + // extracting a polymorphic belongsTo may need more information + // than the type and the hash (which might only be an id) for the + // relationship, hence we pass the key, resource and + // relationshipMeta too + data = this.extractPolymorphicRelationship(relationshipMeta.type, relationshipHash, { key, resourceHash, relationshipMeta }); + } else { + data = this.extractRelationship(relationshipMeta.type, relationshipHash); + } + } else if (relationshipMeta.kind === 'hasMany') { + if (!Ember.isNone(relationshipHash)) { + data = new Array(relationshipHash.length); + for (let i = 0, l = relationshipHash.length; i < l; i++) { + let item = relationshipHash[i]; + data[i] = this.extractRelationship(relationshipMeta.type, item); + } + } + } + relationship = { data }; + } + + let linkKey = this.keyForLink(key, relationshipMeta.kind); + if (resourceHash.links && resourceHash.links.hasOwnProperty(linkKey)) { + let related = resourceHash.links[linkKey]; + relationship = relationship || {}; + relationship.links = { related }; + } + + if (relationship) { + relationships[key] = relationship; + } + }); + + return relationships; + }, + + /** + @method modelNameFromPayloadKey + @param {String} key + @return {String} the model's modelName + */ + modelNameFromPayloadKey(key) { + return normalizeModelName(key); + }, + + + /** + @method normalizeAttributes + @private + */ + normalizeAttributes(typeClass, hash) { + var payloadKey; + + if (this.keyForAttribute) { + typeClass.eachAttribute((key) => { + payloadKey = this.keyForAttribute(key, 'deserialize'); + if (key === payloadKey) { return; } + if (!hash.hasOwnProperty(payloadKey)) { return; } + + hash[key] = hash[payloadKey]; + delete hash[payloadKey]; + }); + } + }, + + /** + @method normalizeRelationships + @private + */ + normalizeRelationships(typeClass, hash) { + var payloadKey; + + if (this.keyForRelationship) { + typeClass.eachRelationship((key, relationship) => { + payloadKey = this.keyForRelationship(key, relationship.kind, 'deserialize'); + if (key === payloadKey) { return; } + if (!hash.hasOwnProperty(payloadKey)) { return; } + + hash[key] = hash[payloadKey]; + delete hash[payloadKey]; + }); + } + }, + + /** + @method normalizeUsingDeclaredMapping + @private + */ + normalizeUsingDeclaredMapping(modelClass, hash) { + var attrs = get(this, 'attrs'); + var normalizedKey, payloadKey, key; + + if (attrs) { + for (key in attrs) { + normalizedKey = payloadKey = this._getMappedKey(key, modelClass); + + if (!hash.hasOwnProperty(payloadKey)) { continue; } + + if (get(modelClass, 'attributes').has(key)) { + normalizedKey = this.keyForAttribute(key); + } + + if (get(modelClass, 'relationshipsByName').has(key)) { + normalizedKey = this.keyForRelationship(key); + } + + if (payloadKey !== normalizedKey) { + hash[normalizedKey] = hash[payloadKey]; + delete hash[payloadKey]; + } + } + } + }, + + /** + Looks up the property key that was set by the custom `attr` mapping + passed to the serializer. + + @method _getMappedKey + @private + @param {String} key + @return {String} key + */ + _getMappedKey(key, modelClass) { + warn('There is no attribute or relationship with the name `' + key + '` on `' + modelClass.modelName + '`. Check your serializers attrs hash.', get(modelClass, 'attributes').has(key) || get(modelClass, 'relationshipsByName').has(key), { + id: 'ds.serializer.no-mapped-attrs-key' + }); + + var attrs = get(this, 'attrs'); + var mappedKey; + if (attrs && attrs[key]) { + mappedKey = attrs[key]; + //We need to account for both the { title: 'post_title' } and + //{ title: { key: 'post_title' }} forms + if (mappedKey.key) { + mappedKey = mappedKey.key; + } + if (typeof mappedKey === 'string') { + key = mappedKey; + } + } + + return key; + }, + + /** + Check attrs.key.serialize property to inform if the `key` + can be serialized + + @method _canSerialize + @private + @param {String} key + @return {boolean} true if the key can be serialized + */ + _canSerialize(key) { + var attrs = get(this, 'attrs'); + + return !attrs || !attrs[key] || attrs[key].serialize !== false; + }, + + /** + When attrs.key.serialize is set to true then + it takes priority over the other checks and the related + attribute/relationship will be serialized + + @method _mustSerialize + @private + @param {String} key + @return {boolean} true if the key must be serialized + */ + _mustSerialize(key) { + var attrs = get(this, 'attrs'); + + return attrs && attrs[key] && attrs[key].serialize === true; + }, + + /** + Check if the given hasMany relationship should be serialized + + @method _shouldSerializeHasMany + @private + @param {DS.Snapshot} snapshot + @param {String} key + @param {String} relationshipType + @return {boolean} true if the hasMany relationship should be serialized + */ + _shouldSerializeHasMany(snapshot, key, relationship) { + var relationshipType = snapshot.type.determineRelationshipType(relationship, this.store); + if (this._mustSerialize(key)) { + return true; + } + return this._canSerialize(key) && (relationshipType === 'manyToNone' || relationshipType === 'manyToMany'); + }, + + + // SERIALIZE + /** + Called when a record is saved in order to convert the + record into JSON. + + By default, it creates a JSON object with a key for + each attribute and belongsTo relationship. + + For example, consider this model: + + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + title: DS.attr(), + body: DS.attr(), + + author: DS.belongsTo('user') + }); + ``` + + The default serialization would create a JSON object like: + + ```javascript + { + "title": "Rails is unagi", + "body": "Rails? Omakase? O_O", + "author": 12 + } + ``` + + By default, attributes are passed through as-is, unless + you specified an attribute type (`DS.attr('date')`). If + you specify a transform, the JavaScript value will be + serialized when inserted into the JSON hash. + + By default, belongs-to relationships are converted into + IDs when inserted into the JSON hash. + + ## IDs + + `serialize` takes an options hash with a single option: + `includeId`. If this option is `true`, `serialize` will, + by default include the ID in the JSON object it builds. + + The adapter passes in `includeId: true` when serializing + a record for `createRecord`, but not for `updateRecord`. + + ## Customization + + Your server may expect a different JSON format than the + built-in serialization format. + + In that case, you can implement `serialize` yourself and + return a JSON hash of your choosing. + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + serialize: function(snapshot, options) { + var json = { + POST_TTL: snapshot.attr('title'), + POST_BDY: snapshot.attr('body'), + POST_CMS: snapshot.hasMany('comments', { ids: true }) + } + + if (options.includeId) { + json.POST_ID_ = snapshot.id; + } + + return json; + } + }); + ``` + + ## Customizing an App-Wide Serializer + + If you want to define a serializer for your entire + application, you'll probably want to use `eachAttribute` + and `eachRelationship` on the record. + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + serialize: function(snapshot, options) { + var json = {}; + + snapshot.eachAttribute(function(name) { + json[serverAttributeName(name)] = snapshot.attr(name); + }) + + snapshot.eachRelationship(function(name, relationship) { + if (relationship.kind === 'hasMany') { + json[serverHasManyName(name)] = snapshot.hasMany(name, { ids: true }); + } + }); + + if (options.includeId) { + json.ID_ = snapshot.id; + } + + return json; + } + }); + + function serverAttributeName(attribute) { + return attribute.underscore().toUpperCase(); + } + + function serverHasManyName(name) { + return serverAttributeName(name.singularize()) + "_IDS"; + } + ``` + + This serializer will generate JSON that looks like this: + + ```javascript + { + "TITLE": "Rails is omakase", + "BODY": "Yep. Omakase.", + "COMMENT_IDS": [ 1, 2, 3 ] + } + ``` + + ## Tweaking the Default JSON + + If you just want to do some small tweaks on the default JSON, + you can call super first and make the tweaks on the returned + JSON. + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + serialize: function(snapshot, options) { + var json = this._super.apply(this, arguments); + + json.subject = json.title; + delete json.title; + + return json; + } + }); + ``` + + @method serialize + @param {DS.Snapshot} snapshot + @param {Object} options + @return {Object} json + */ + serialize(snapshot, options) { + var json = {}; + + if (options && options.includeId) { + var id = snapshot.id; + + if (id) { + json[get(this, 'primaryKey')] = id; + } + } + + snapshot.eachAttribute((key, attribute) => { + this.serializeAttribute(snapshot, json, key, attribute); + }); + + snapshot.eachRelationship((key, relationship) => { + if (relationship.kind === 'belongsTo') { + this.serializeBelongsTo(snapshot, json, relationship); + } else if (relationship.kind === 'hasMany') { + this.serializeHasMany(snapshot, json, relationship); + } + }); + + return json; + }, + + /** + You can use this method to customize how a serialized record is added to the complete + JSON hash to be sent to the server. By default the JSON Serializer does not namespace + the payload and just sends the raw serialized JSON object. + If your server expects namespaced keys, you should consider using the RESTSerializer. + Otherwise you can override this method to customize how the record is added to the hash. + The hash property should be modified by reference. + + For example, your server may expect underscored root objects. + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ + serializeIntoHash: function(data, type, snapshot, options) { + var root = Ember.String.decamelize(type.modelName); + data[root] = this.serialize(snapshot, options); + } + }); + ``` + + @method serializeIntoHash + @param {Object} hash + @param {DS.Model} typeClass + @param {DS.Snapshot} snapshot + @param {Object} options + */ + serializeIntoHash(hash, typeClass, snapshot, options) { + merge(hash, this.serialize(snapshot, options)); + }, + + /** + `serializeAttribute` can be used to customize how `DS.attr` + properties are serialized + + For example if you wanted to ensure all your attributes were always + serialized as properties on an `attributes` object you could + write: + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + serializeAttribute: function(snapshot, json, key, attributes) { + json.attributes = json.attributes || {}; + this._super(snapshot, json.attributes, key, attributes); + } + }); + ``` + + @method serializeAttribute + @param {DS.Snapshot} snapshot + @param {Object} json + @param {String} key + @param {Object} attribute + */ + serializeAttribute(snapshot, json, key, attribute) { + var type = attribute.type; + + if (this._canSerialize(key)) { + var value = snapshot.attr(key); + if (type) { + var transform = this.transformFor(type); + value = transform.serialize(value); + } + + // if provided, use the mapping provided by `attrs` in + // the serializer + var payloadKey = this._getMappedKey(key, snapshot.type); + + if (payloadKey === key && this.keyForAttribute) { + payloadKey = this.keyForAttribute(key, 'serialize'); + } + + json[payloadKey] = value; + } + }, + + /** + `serializeBelongsTo` can be used to customize how `DS.belongsTo` + properties are serialized. + + Example + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + serializeBelongsTo: function(snapshot, json, relationship) { + var key = relationship.key; + + var belongsTo = snapshot.belongsTo(key); + + key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo", "serialize") : key; + + json[key] = Ember.isNone(belongsTo) ? belongsTo : belongsTo.record.toJSON(); + } + }); + ``` + + @method serializeBelongsTo + @param {DS.Snapshot} snapshot + @param {Object} json + @param {Object} relationship + */ + serializeBelongsTo(snapshot, json, relationship) { + var key = relationship.key; + + if (this._canSerialize(key)) { + var belongsToId = snapshot.belongsTo(key, { id: true }); + + // if provided, use the mapping provided by `attrs` in + // the serializer + var payloadKey = this._getMappedKey(key, snapshot.type); + if (payloadKey === key && this.keyForRelationship) { + payloadKey = this.keyForRelationship(key, "belongsTo", "serialize"); + } + + //Need to check whether the id is there for new&async records + if (isNone(belongsToId)) { + json[payloadKey] = null; + } else { + json[payloadKey] = belongsToId; + } + + if (relationship.options.polymorphic) { + this.serializePolymorphicType(snapshot, json, relationship); + } + } + }, + + /** + `serializeHasMany` can be used to customize how `DS.hasMany` + properties are serialized. + + Example + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + serializeHasMany: function(snapshot, json, relationship) { + var key = relationship.key; + if (key === 'comments') { + return; + } else { + this._super.apply(this, arguments); + } + } + }); + ``` + + @method serializeHasMany + @param {DS.Snapshot} snapshot + @param {Object} json + @param {Object} relationship + */ + serializeHasMany(snapshot, json, relationship) { + var key = relationship.key; + + if (this._shouldSerializeHasMany(snapshot, key, relationship)) { + var hasMany = snapshot.hasMany(key, { ids: true }); + if (hasMany !== undefined) { + // if provided, use the mapping provided by `attrs` in + // the serializer + var payloadKey = this._getMappedKey(key, snapshot.type); + if (payloadKey === key && this.keyForRelationship) { + payloadKey = this.keyForRelationship(key, "hasMany", "serialize"); + } + + json[payloadKey] = hasMany; + // TODO support for polymorphic manyToNone and manyToMany relationships + } + } + }, + + /** + You can use this method to customize how polymorphic objects are + serialized. Objects are considered to be polymorphic if + `{ polymorphic: true }` is pass as the second argument to the + `DS.belongsTo` function. + + Example + + ```app/serializers/comment.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + serializePolymorphicType: function(snapshot, json, relationship) { + var key = relationship.key, + belongsTo = snapshot.belongsTo(key); + key = this.keyForAttribute ? this.keyForAttribute(key, "serialize") : key; + + if (Ember.isNone(belongsTo)) { + json[key + "_type"] = null; + } else { + json[key + "_type"] = belongsTo.modelName; + } + } + }); + ``` + + @method serializePolymorphicType + @param {DS.Snapshot} snapshot + @param {Object} json + @param {Object} relationship + */ + serializePolymorphicType: Ember.K, + + /** + `extractMeta` is used to deserialize any meta information in the + adapter payload. By default Ember Data expects meta information to + be located on the `meta` property of the payload object. + + Example + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + extractMeta: function(store, typeClass, payload) { + if (payload && payload._pagination) { + store.setMetadataFor(typeClass, payload._pagination); + delete payload._pagination; + } + } + }); + ``` + + @method extractMeta + @param {DS.Store} store + @param {DS.Model} modelClass + @param {Object} payload + */ + extractMeta(store, modelClass, payload) { + if (payload && payload.hasOwnProperty('meta')) { + let meta = payload.meta; + delete payload.meta; + return meta; + } + }, + + /** + `extractErrors` is used to extract model errors when a call is made + to `DS.Model#save` which fails with an `InvalidError`. By default + Ember Data expects error information to be located on the `errors` + property of the payload object. + + Example + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + extractErrors: function(store, typeClass, payload, id) { + if (payload && typeof payload === 'object' && payload._problems) { + payload = payload._problems; + this.normalizeErrors(typeClass, payload); + } + return payload; + } + }); + ``` + + @method extractErrors + @param {DS.Store} store + @param {DS.Model} typeClass + @param {Object} payload + @param {(String|Number)} id + @return {Object} json The deserialized errors + */ + extractErrors(store, typeClass, payload, id) { + if (payload && typeof payload === 'object' && payload.errors) { + payload = errorsArrayToHash(payload.errors); + + this.normalizeUsingDeclaredMapping(typeClass, payload); + + typeClass.eachAttribute((name) => { + let key = this.keyForAttribute(name, 'deserialize'); + if (key !== name && payload.hasOwnProperty(key)) { + payload[name] = payload[key]; + delete payload[key]; + } + }); + + typeClass.eachRelationship((name) => { + let key = this.keyForRelationship(name, 'deserialize'); + if (key !== name && payload.hasOwnProperty(key)) { + payload[name] = payload[key]; + delete payload[key]; + } + }); + } + + return payload; + }, + + /** + `keyForAttribute` can be used to define rules for how to convert an + attribute name in your model to a key in your JSON. + + Example + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ + keyForAttribute: function(attr, method) { + return Ember.String.underscore(attr).toUpperCase(); + } + }); + ``` + + @method keyForAttribute + @param {String} key + @param {String} method + @return {String} normalized key + */ + keyForAttribute(key, method) { + return key; + }, + + /** + `keyForRelationship` can be used to define a custom key when + serializing and deserializing relationship properties. By default + `JSONSerializer` does not provide an implementation of this method. + + Example + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + keyForRelationship: function(key, relationship, method) { + return 'rel_' + Ember.String.underscore(key); + } + }); + ``` + + @method keyForRelationship + @param {String} key + @param {String} typeClass + @param {String} method + @return {String} normalized key + */ + keyForRelationship(key, typeClass, method) { + return key; + }, + + /** + `keyForLink` can be used to define a custom key when deserializing link + properties. + + @method keyForLink + @param {String} key + @param {String} kind `belongsTo` or `hasMany` + @return {String} normalized key + */ + keyForLink(key, kind) { + return key; + }, + + // HELPERS + + /** + @method transformFor + @private + @param {String} attributeType + @param {Boolean} skipAssertion + @return {DS.Transform} transform + */ + transformFor(attributeType, skipAssertion) { + var transform = getOwner(this).lookup('transform:' + attributeType); + + assert("Unable to find transform for '" + attributeType + "'", skipAssertion || !!transform); + + return transform; + } +}); diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 3815008bb4c..9abc42b302a 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -1 +1,800 @@ -export { default } from "ember-data/-private/serializers/rest-serializer"; +/** + @module ember-data +*/ + +import Ember from 'ember'; +import { assert, deprecate, runInDebug, warn } from "ember-data/-private/debug"; +import JSONSerializer from "ember-data/serializers/json"; +import normalizeModelName from "ember-data/-private/system/normalize-model-name"; +import {singularize} from "ember-inflector"; +import coerceId from "ember-data/-private/system/coerce-id"; +import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; + +var camelize = Ember.String.camelize; + +/** + Normally, applications will use the `RESTSerializer` by implementing + the `normalize` method and individual normalizations under + `normalizeHash`. + + This allows you to do whatever kind of munging you need, and is + especially useful if your server is inconsistent and you need to + do munging differently for many different kinds of responses. + + See the `normalize` documentation for more information. + + ## Across the Board Normalization + + There are also a number of hooks that you might find useful to define + across-the-board rules for your payload. These rules will be useful + if your server is consistent, or if you're building an adapter for + an infrastructure service, like Parse, and want to encode service + conventions. + + For example, if all of your keys are underscored and all-caps, but + otherwise consistent with the names you use in your models, you + can implement across-the-board rules for how to convert an attribute + name in your model to a key in your JSON. + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ + keyForAttribute: function(attr, method) { + return Ember.String.underscore(attr).toUpperCase(); + } + }); + ``` + + You can also implement `keyForRelationship`, which takes the name + of the relationship as the first parameter, the kind of + relationship (`hasMany` or `belongsTo`) as the second parameter, and + the method (`serialize` or `deserialize`) as the third parameter. + + @class RESTSerializer + @namespace DS + @extends DS.JSONSerializer +*/ +var RESTSerializer = JSONSerializer.extend({ + + /** + `keyForPolymorphicType` can be used to define a custom key when + serializing and deserializing a polymorphic type. By default, the + returned key is `${key}Type`. + + Example + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ + keyForPolymorphicType: function(key, relationship) { + var relationshipKey = this.keyForRelationship(key); + + return 'type-' + relationshipKey; + } + }); + ``` + + @method keyForPolymorphicType + @param {String} key + @param {String} typeClass + @param {String} method + @return {String} normalized key + */ + keyForPolymorphicType(key, typeClass, method) { + var relationshipKey = this.keyForRelationship(key); + + return `${relationshipKey}Type`; + }, + + /** + Normalizes a part of the JSON payload returned by + the server. You should override this method, munge the hash + and call super if you have generic normalization to do. + + It takes the type of the record that is being normalized + (as a DS.Model class), the property where the hash was + originally found, and the hash to normalize. + + For example, if you have a payload that looks like this: + + ```js + { + "post": { + "id": 1, + "title": "Rails is omakase", + "comments": [ 1, 2 ] + }, + "comments": [{ + "id": 1, + "body": "FIRST" + }, { + "id": 2, + "body": "Rails is unagi" + }] + } + ``` + + The `normalize` method will be called three times: + + * With `App.Post`, `"posts"` and `{ id: 1, title: "Rails is omakase", ... }` + * With `App.Comment`, `"comments"` and `{ id: 1, body: "FIRST" }` + * With `App.Comment`, `"comments"` and `{ id: 2, body: "Rails is unagi" }` + + You can use this method, for example, to normalize underscored keys to camelized + or other general-purpose normalizations. + + If you want to do normalizations specific to some part of the payload, you + can specify those under `normalizeHash`. + + For example, if the `IDs` under `"comments"` are provided as `_id` instead of + `id`, you can specify how to normalize just the comments: + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ + normalizeHash: { + comments: function(hash) { + hash.id = hash._id; + delete hash._id; + return hash; + } + } + }); + ``` + + The key under `normalizeHash` is just the original key that was in the original + payload. + + @method normalize + @param {DS.Model} modelClass + @param {Object} resourceHash + @param {String} prop + @return {Object} + */ + normalize(modelClass, resourceHash, prop) { + if (this.normalizeHash && this.normalizeHash[prop]) { + this.normalizeHash[prop](resourceHash); + } + return this._super(modelClass, resourceHash, prop); + }, + + /** + Normalizes an array of resource payloads and returns a JSON-API Document + with primary data and, if any, included data as `{ data, included }`. + + @method _normalizeArray + @param {DS.Store} store + @param {String} modelName + @param {Object} arrayHash + @param {String} prop + @return {Object} + @private + */ + _normalizeArray(store, modelName, arrayHash, prop) { + let documentHash = { + data: [], + included: [] + }; + + let modelClass = store.modelFor(modelName); + let serializer = store.serializerFor(modelName); + + /*jshint loopfunc:true*/ + arrayHash.forEach((hash) => { + let { data, included } = this._normalizePolymorphicRecord(store, hash, prop, modelClass, serializer); + documentHash.data.push(data); + if (included) { + documentHash.included.push(...included); + } + }); + + return documentHash; + }, + + _normalizePolymorphicRecord(store, hash, prop, primaryModelClass, primarySerializer) { + let serializer, modelClass; + const primaryHasTypeAttribute = modelHasAttributeOrRelationshipNamedType(primaryModelClass); + // Support polymorphic records in async relationships + if (!primaryHasTypeAttribute && hash.type && store._hasModelFor(this.modelNameFromPayloadKey(hash.type))) { + serializer = store.serializerFor(hash.type); + modelClass = store.modelFor(hash.type); + } else { + serializer = primarySerializer; + modelClass = primaryModelClass; + } + return serializer.normalize(modelClass, hash, prop); + }, + + /* + @method _normalizeResponse + @param {DS.Store} store + @param {DS.Model} primaryModelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @param {Boolean} isSingle + @return {Object} JSON-API Document + @private + */ + _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { + let documentHash = { + data: null, + included: [] + }; + + let meta = this.extractMeta(store, primaryModelClass, payload); + if (meta) { + assert('The `meta` returned from `extractMeta` has to be an object, not "' + Ember.typeOf(meta) + '".', Ember.typeOf(meta) === 'object'); + documentHash.meta = meta; + } + + var keys = Object.keys(payload); + + for (let i = 0, length = keys.length; i < length; i++) { + let prop = keys[i]; + var modelName = prop; + var forcedSecondary = false; + + /* + If you want to provide sideloaded records of the same type that the + primary data you can do that by prefixing the key with `_`. + + Example + + ``` + { + users: [ + { id: 1, title: 'Tom', manager: 3 }, + { id: 2, title: 'Yehuda', manager: 3 } + ], + _users: [ + { id: 3, title: 'Tomster' } + ] + } + ``` + + This forces `_users` to be added to `included` instead of `data`. + */ + if (prop.charAt(0) === '_') { + forcedSecondary = true; + modelName = prop.substr(1); + } + + var typeName = this.modelNameFromPayloadKey(modelName); + if (!store.modelFactoryFor(typeName)) { + warn(this.warnMessageNoModelForKey(modelName, typeName), false, { + id: 'ds.serializer.model-for-key-missing' + }); + continue; + } + + var isPrimary = (!forcedSecondary && this.isPrimaryType(store, typeName, primaryModelClass)); + var value = payload[prop]; + + if (value === null) { + continue; + } + + /* + Support primary data as an object instead of an array. + + Example + + ``` + { + user: { id: 1, title: 'Tom', manager: 3 } + } + ``` + */ + if (isPrimary && Ember.typeOf(value) !== 'array') { + let { data, included } = this._normalizePolymorphicRecord(store, value, prop, primaryModelClass, this); + documentHash.data = data; + if (included) { + documentHash.included.push(...included); + } + continue; + } + + let { data, included } = this._normalizeArray(store, typeName, value, prop); + + if (included) { + documentHash.included.push(...included); + } + + if (isSingle) { + /*jshint loopfunc:true*/ + data.forEach((resource) => { + + /* + Figures out if this is the primary record or not. + + It's either: + + 1. The record with the same ID as the original request + 2. If it's a newly created record without an ID, the first record + in the array + */ + var isUpdatedRecord = isPrimary && coerceId(resource.id) === id; + var isFirstCreatedRecord = isPrimary && !id && !documentHash.data; + + if (isFirstCreatedRecord || isUpdatedRecord) { + documentHash.data = resource; + } else { + documentHash.included.push(resource); + } + }); + } else { + if (isPrimary) { + documentHash.data = data; + } else { + if (data) { + documentHash.included.push(...data); + } + } + } + } + + return documentHash; + }, + + isPrimaryType(store, typeName, primaryTypeClass) { + var typeClass = store.modelFor(typeName); + return typeClass.modelName === primaryTypeClass.modelName; + }, + + /** + This method allows you to push a payload containing top-level + collections of records organized per type. + + ```js + { + "posts": [{ + "id": "1", + "title": "Rails is omakase", + "author", "1", + "comments": [ "1" ] + }], + "comments": [{ + "id": "1", + "body": "FIRST" + }], + "users": [{ + "id": "1", + "name": "@d2h" + }] + } + ``` + + It will first normalize the payload, so you can use this to push + in data streaming in from your server structured the same way + that fetches and saves are structured. + + @method pushPayload + @param {DS.Store} store + @param {Object} payload + */ + pushPayload(store, payload) { + let documentHash = { + data: [], + included: [] + }; + + for (var prop in payload) { + var modelName = this.modelNameFromPayloadKey(prop); + if (!store.modelFactoryFor(modelName)) { + warn(this.warnMessageNoModelForKey(prop, modelName), false, { + id: 'ds.serializer.model-for-key-missing' + }); + continue; + } + var type = store.modelFor(modelName); + var typeSerializer = store.serializerFor(type.modelName); + + /*jshint loopfunc:true*/ + Ember.makeArray(payload[prop]).forEach((hash) => { + let { data, included } = typeSerializer.normalize(type, hash, prop); + documentHash.data.push(data); + if (included) { + documentHash.included.push(...included); + } + }); + } + + store.push(documentHash); + }, + + /** + This method is used to convert each JSON root key in the payload + into a modelName that it can use to look up the appropriate model for + that part of the payload. + + For example, your server may send a model name that does not correspond with + the name of the model in your app. Let's take a look at an example model, + and an example payload: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + }); + ``` + + ```javascript + { + "blog/post": { + "id": "1 + } + } + ``` + + Ember Data is going to normalize the payload's root key for the modelName. As a result, + it will try to look up the "blog/post" model. Since we don't have a model called "blog/post" + (or a file called app/models/blog/post.js in ember-cli), Ember Data will throw an error + because it cannot find the "blog/post" model. + + Since we want to remove this namespace, we can define a serializer for the application that will + remove "blog/" from the payload key whenver it's encountered by Ember Data: + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ + modelNameFromPayloadKey: function(payloadKey) { + if (payloadKey === 'blog/post') { + return this._super(payloadKey.replace('blog/', '')); + } else { + return this._super(payloadKey); + } + } + }); + ``` + + After refreshing, Ember Data will appropriately look up the "post" model. + + By default the modelName for a model is its + name in dasherized form. This means that a payload key like "blogPost" would be + normalized to "blog-post" when Ember Data looks up the model. Usually, Ember Data + can use the correct inflection to do this for you. Most of the time, you won't + need to override `modelNameFromPayloadKey` for this purpose. + + @method modelNameFromPayloadKey + @param {String} key + @return {String} the model's modelName + */ + modelNameFromPayloadKey(key) { + return singularize(normalizeModelName(key)); + }, + + // SERIALIZE + + /** + Called when a record is saved in order to convert the + record into JSON. + + By default, it creates a JSON object with a key for + each attribute and belongsTo relationship. + + For example, consider this model: + + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + title: DS.attr(), + body: DS.attr(), + + author: DS.belongsTo('user') + }); + ``` + + The default serialization would create a JSON object like: + + ```js + { + "title": "Rails is unagi", + "body": "Rails? Omakase? O_O", + "author": 12 + } + ``` + + By default, attributes are passed through as-is, unless + you specified an attribute type (`DS.attr('date')`). If + you specify a transform, the JavaScript value will be + serialized when inserted into the JSON hash. + + By default, belongs-to relationships are converted into + IDs when inserted into the JSON hash. + + ## IDs + + `serialize` takes an options hash with a single option: + `includeId`. If this option is `true`, `serialize` will, + by default include the ID in the JSON object it builds. + + The adapter passes in `includeId: true` when serializing + a record for `createRecord`, but not for `updateRecord`. + + ## Customization + + Your server may expect a different JSON format than the + built-in serialization format. + + In that case, you can implement `serialize` yourself and + return a JSON hash of your choosing. + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ + serialize: function(snapshot, options) { + var json = { + POST_TTL: snapshot.attr('title'), + POST_BDY: snapshot.attr('body'), + POST_CMS: snapshot.hasMany('comments', { ids: true }) + } + + if (options.includeId) { + json.POST_ID_ = snapshot.id; + } + + return json; + } + }); + ``` + + ## Customizing an App-Wide Serializer + + If you want to define a serializer for your entire + application, you'll probably want to use `eachAttribute` + and `eachRelationship` on the record. + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ + serialize: function(snapshot, options) { + var json = {}; + + snapshot.eachAttribute(function(name) { + json[serverAttributeName(name)] = snapshot.attr(name); + }) + + snapshot.eachRelationship(function(name, relationship) { + if (relationship.kind === 'hasMany') { + json[serverHasManyName(name)] = snapshot.hasMany(name, { ids: true }); + } + }); + + if (options.includeId) { + json.ID_ = snapshot.id; + } + + return json; + } + }); + + function serverAttributeName(attribute) { + return attribute.underscore().toUpperCase(); + } + + function serverHasManyName(name) { + return serverAttributeName(name.singularize()) + "_IDS"; + } + ``` + + This serializer will generate JSON that looks like this: + + ```js + { + "TITLE": "Rails is omakase", + "BODY": "Yep. Omakase.", + "COMMENT_IDS": [ 1, 2, 3 ] + } + ``` + + ## Tweaking the Default JSON + + If you just want to do some small tweaks on the default JSON, + you can call super first and make the tweaks on the returned + JSON. + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ + serialize: function(snapshot, options) { + var json = this._super(snapshot, options); + + json.subject = json.title; + delete json.title; + + return json; + } + }); + ``` + + @method serialize + @param {DS.Snapshot} snapshot + @param {Object} options + @return {Object} json + */ + serialize(snapshot, options) { + return this._super(...arguments); + }, + + /** + You can use this method to customize the root keys serialized into the JSON. + The hash property should be modified by reference (possibly using something like _.extend) + By default the REST Serializer sends the modelName of a model, which is a camelized + version of the name. + + For example, your server may expect underscored root objects. + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ + serializeIntoHash: function(data, type, record, options) { + var root = Ember.String.decamelize(type.modelName); + data[root] = this.serialize(record, options); + } + }); + ``` + + @method serializeIntoHash + @param {Object} hash + @param {DS.Model} typeClass + @param {DS.Snapshot} snapshot + @param {Object} options + */ + serializeIntoHash(hash, typeClass, snapshot, options) { + var normalizedRootKey = this.payloadKeyFromModelName(typeClass.modelName); + hash[normalizedRootKey] = this.serialize(snapshot, options); + }, + + /** + You can use `payloadKeyFromModelName` to override the root key for an outgoing + request. By default, the RESTSerializer returns a camelized version of the + model's name. + + For a model called TacoParty, its `modelName` would be the string `taco-party`. The RESTSerializer + will send it to the server with `tacoParty` as the root key in the JSON payload: + + ```js + { + "tacoParty": { + "id": "1", + "location": "Matthew Beale's House" + } + } + ``` + + For example, your server may expect dasherized root objects: + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.RESTSerializer.extend({ + payloadKeyFromModelName: function(modelName) { + return Ember.String.dasherize(modelName); + } + }); + ``` + + Given a `TacoParty' model, calling `save` on a tacoModel would produce an outgoing + request like: + + ```js + { + "taco-party": { + "id": "1", + "location": "Matthew Beale's House" + } + } + ``` + + @method payloadKeyFromModelName + @param {String} modelName + @return {String} + */ + payloadKeyFromModelName(modelName) { + return camelize(modelName); + }, + + /** + You can use this method to customize how polymorphic objects are serialized. + By default the REST Serializer creates the key by appending `Type` to + the attribute and value from the model's camelcased model name. + + @method serializePolymorphicType + @param {DS.Snapshot} snapshot + @param {Object} json + @param {Object} relationship + */ + serializePolymorphicType(snapshot, json, relationship) { + var key = relationship.key; + var belongsTo = snapshot.belongsTo(key); + var typeKey = this.keyForPolymorphicType(key, relationship.type, 'serialize'); + + // old way of getting the key for the polymorphic type + key = this.keyForAttribute ? this.keyForAttribute(key, "serialize") : key; + key = `${key}Type`; + + // The old way of serializing the type of a polymorphic record used + // `keyForAttribute`, which is not correct. The next code checks if the old + // way is used and if it differs from the new way of using + // `keyForPolymorphicType`. If this is the case, a deprecation warning is + // logged and the old way is restored (so nothing breaks). + if (key !== typeKey && this.keyForPolymorphicType === RESTSerializer.prototype.keyForPolymorphicType) { + deprecate("The key to serialize the type of a polymorphic record is created via keyForAttribute which has been deprecated. Use the keyForPolymorphicType hook instead.", false, { + id: 'ds.rest-serializer.deprecated-key-for-polymorphic-type', + until: '3.0.0' + }); + + typeKey = key; + } + + if (Ember.isNone(belongsTo)) { + json[typeKey] = null; + } else { + json[typeKey] = camelize(belongsTo.modelName); + } + }, + + /** + You can use this method to customize how a polymorphic relationship should + be extracted. + + @method extractPolymorphicRelationship + @param {Object} relationshipType + @param {Object} relationshipHash + @param {Object} relationshipOptions + @return {Object} + */ + extractPolymorphicRelationship(relationshipType, relationshipHash, relationshipOptions) { + var { key, resourceHash, relationshipMeta } = relationshipOptions; + + // A polymorphic belongsTo relationship can be present in the payload + // either in the form where the `id` and the `type` are given: + // + // { + // message: { id: 1, type: 'post' } + // } + // + // or by the `id` and a `Type` attribute: + // + // { + // message: 1, + // messageType: 'post' + // } + // + // The next code checks if the latter case is present and returns the + // corresponding JSON-API representation. The former case is handled within + // the base class JSONSerializer. + var isPolymorphic = relationshipMeta.options.polymorphic; + var typeProperty = this.keyForPolymorphicType(key, relationshipType, 'deserialize'); + + if (isPolymorphic && resourceHash.hasOwnProperty(typeProperty) && typeof relationshipHash !== 'object') { + let type = this.modelNameFromPayloadKey(resourceHash[typeProperty]); + return { + id: relationshipHash, + type: type + }; + } + + return this._super(...arguments); + } +}); + +runInDebug(function() { + RESTSerializer.reopen({ + warnMessageNoModelForKey(prop, typeKey) { + return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + typeKey + '" (resolved model name using ' + this.constructor.toString() + '.modelNameFromPayloadKey("' + prop + '"))'; + } + }); +}); + +export default RESTSerializer; diff --git a/addon/store.js b/addon/store.js index 011380454f5..12ac8ed7591 100644 --- a/addon/store.js +++ b/addon/store.js @@ -1 +1,3 @@ -export { default } from "ember-data/-private/system/store"; +import Store from "ember-data/-private/system/store"; + +export default Store; diff --git a/addon/transform.js b/addon/transform.js index ac58081c856..e9c45f2104a 100644 --- a/addon/transform.js +++ b/addon/transform.js @@ -1 +1,76 @@ -export { default } from "ember-data/-private/transforms/base"; +import Ember from 'ember'; + +/** + The `DS.Transform` class is used to serialize and deserialize model + attributes when they are saved or loaded from an + adapter. Subclassing `DS.Transform` is useful for creating custom + attributes. All subclasses of `DS.Transform` must implement a + `serialize` and a `deserialize` method. + + Example + + ```app/transforms/temperature.js + import DS from 'ember-data'; + + // Converts centigrade in the JSON to fahrenheit in the app + export default DS.Transform.extend({ + deserialize: function(serialized) { + return (serialized * 1.8) + 32; + }, + serialize: function(deserialized) { + return (deserialized - 32) / 1.8; + } + }); + ``` + + Usage + + ```app/models/requirement.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + name: DS.attr('string'), + temperature: DS.attr('temperature') + }); + ``` + + @class Transform + @namespace DS + */ +export default Ember.Object.extend({ + /** + When given a deserialized value from a record attribute this + method must return the serialized value. + + Example + + ```javascript + serialize: function(deserialized) { + return Ember.isEmpty(deserialized) ? null : Number(deserialized); + } + ``` + + @method serialize + @param deserialized The deserialized value + @return The serialized value + */ + serialize: null, + + /** + When given a serialize value from a JSON object this method must + return the deserialized value for the record attribute. + + Example + + ```javascript + deserialize: function(serialized) { + return empty(serialized) ? null : Number(serialized); + } + ``` + + @method deserialize + @param serialized The serialized value + @return The deserialized value + */ + deserialize: null +}); From 13320456c2f73d15f8252ac608c0f51a7516ca5d Mon Sep 17 00:00:00 2001 From: Seth Date: Wed, 30 Dec 2015 12:25:00 -0500 Subject: [PATCH 1314/2527] Links formatting affects the resulting request URL Just some description about how the formatting of the `links` value in a payload can affect the request URL that is produced --- addon/adapters/rest.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 76f9e1d9abd..5519d6fdd0b 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -519,6 +519,14 @@ export default Adapter.extend(BuildURLMixin, { The `findHasMany` method will make an Ajax (HTTP GET) request to the originally specified URL. + The format of your `links` value will influence the final request URL via the `urlPrefix` method: + + * Links beginning with `//`, `http://`, `https://`, will be used as is, with no further manipulation. + + * Links beginning with a single `/` will have the current adapter's `host` value prepended to it. + + * Links with no beginning `/` will have a parentURL prepended to it, via the current adapter's `buildURL`. + @method findHasMany @param {DS.Store} store @param {DS.Snapshot} snapshot @@ -555,6 +563,14 @@ export default Adapter.extend(BuildURLMixin, { The `findBelongsTo` method will make an Ajax (HTTP GET) request to the originally specified URL. + The format of your `links` value will influence the final request URL via the `urlPrefix` method: + + * Links beginning with `//`, `http://`, `https://`, will be used as is, with no further manipulation. + + * Links beginning with a single `/` will have the current adapter's `host` value prepended to it. + + * Links with no beginning `/` will have a parentURL prepended to it, via the current adapter's `buildURL`. + @method findBelongsTo @param {DS.Store} store @param {DS.Snapshot} snapshot From 3e0bf4d2d9bfb3e7a98d7064686bd7bcb56520ce Mon Sep 17 00:00:00 2001 From: pangratz Date: Fri, 1 Jan 2016 14:16:26 +0100 Subject: [PATCH 1315/2527] Happy New Year! --- LICENSE | 2 +- generators/license.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index c20984612e8..1db12779883 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2011-2015 Tilde, Inc. and contributors. +Copyright (C) 2011-2016 Tilde, Inc. and contributors. Portions Copyright (C) 2011 LivingSocial Inc. Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/generators/license.js b/generators/license.js index a8b24d89639..ba16857cda3 100644 --- a/generators/license.js +++ b/generators/license.js @@ -1,6 +1,6 @@ /*! * @overview Ember Data - * @copyright Copyright 2011-2015 Tilde Inc. and contributors. + * @copyright Copyright 2011-2016 Tilde Inc. and contributors. * Portions Copyright 2011 LivingSocial Inc. * @license Licensed under MIT license (see license.js) * @version VERSION_STRING_PLACEHOLDER From cf889b35a1f31d42fd54598ca9d5bc7753644a52 Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 4 Jan 2016 12:00:16 +0100 Subject: [PATCH 1316/2527] [DOC release] Replace deprecated `store.find` with `store.findRecord` --- addon/-private/system/coerce-id.js | 2 +- addon/-private/system/many-array.js | 2 +- addon/-private/system/model/internal-model.js | 2 +- addon/-private/system/model/model.js | 8 ++++---- addon/-private/system/store.js | 4 ++-- addon/-private/system/store/finders.js | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/addon/-private/system/coerce-id.js b/addon/-private/system/coerce-id.js index f325671ce05..59726f32e6d 100644 --- a/addon/-private/system/coerce-id.js +++ b/addon/-private/system/coerce-id.js @@ -1,5 +1,5 @@ // Used by the store to normalize IDs entering the store. Despite the fact -// that developers may provide IDs as numbers (e.g., `store.find(Person, 1)`), +// that developers may provide IDs as numbers (e.g., `store.findRecord('person', 1)`), // it is important that internally we use strings, since IDs may be serialized // and lose type information. For example, Ember's router may put a record's // ID into the URL, and if we later try to deserialize that URL and find the diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index bf09a7505dc..ac0c32d5a6b 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -238,7 +238,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { Example ```javascript - store.find('inbox', 1).then(function(inbox) { + store.findRecord('inbox', 1).then(function(inbox) { inbox.get('messages').then(function(messages) { messages.forEach(function(message) { message.set('isRead', true); diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 86922d00eb3..89e62028635 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -543,7 +543,7 @@ InternalModel.prototype = { came back from the server, except the user obtained them out of band and is informing the store of their existence. The most common use case is for supporting client side nested URLs, such as `/posts/1/comments/2` so the user can do - `store.find('comment', 2, {post:1})` without having to fetch the post. + `store.findRecord('comment', 2, { preload: { post: 1 } })` without having to fetch the post. Preloaded data can be attributes and relationships passed in either as IDs or as actual models. diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 5b447de30b5..f89d802b569 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -83,7 +83,7 @@ var Model = Ember.Object.extend(Ember.Evented, { var record = store.createRecord('model'); record.get('isLoaded'); // true - store.find('model', 1).then(function(model) { + store.findRecord('model', 1).then(function(model) { model.get('isLoaded'); // true }); ``` @@ -105,7 +105,7 @@ var Model = Ember.Object.extend(Ember.Evented, { var record = store.createRecord('model'); record.get('hasDirtyAttributes'); // true - store.find('model', 1).then(function(model) { + store.findRecord('model', 1).then(function(model) { model.get('hasDirtyAttributes'); // false model.set('foo', 'some value'); model.get('hasDirtyAttributes'); // true @@ -284,7 +284,7 @@ var Model = Ember.Object.extend(Ember.Evented, { var record = store.createRecord('model'); record.get('id'); // null - store.find('model', 1).then(function(model) { + store.findRecord('model', 1).then(function(model) { model.get('id'); // '1' }); ``` @@ -885,7 +885,7 @@ if (isEnabled("ds-references")) { var link = userRef.link(); } - // load user (via store.find or store.findBelongsTo) + // load user (via store.findRecord or store.findBelongsTo) userRef.load().then(...) // or trigger a reload diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index fb8006da201..db2c6d4cd41 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1227,14 +1227,14 @@ Store = Service.extend({ /** This method returns if a certain record is already loaded - in the store. Use this function to know beforehand if a find() + in the store. Use this function to know beforehand if a findRecord() will result in a request or that it will be a cache hit. Example ```javascript store.recordIsLoaded('post', 1); // false - store.find('post', 1).then(function() { + store.findRecord('post', 1).then(function() { store.recordIsLoaded('post', 1); // true }); ``` diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index a064f700018..5c690243753 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -28,13 +28,13 @@ export function _find(adapter, store, typeClass, id, internalModel, options) { var snapshot = internalModel.createSnapshot(options); var promise = adapter.findRecord(store, typeClass, id, snapshot); var serializer = serializerForAdapter(store, adapter, internalModel.type.modelName); - var label = "DS: Handle Adapter#find of " + typeClass + " with id: " + id; + var label = "DS: Handle Adapter#findRecord of " + typeClass + " with id: " + id; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - assert("You made a `find` request for a " + typeClass.typeClassKey + " with id " + id + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + assert("You made a `findRecord` request for a " + typeClass.typeClassKey + " with id " + id + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, id, 'findRecord'); assert('Ember Data expected the primary data returned from a `findRecord` response to be an object but instead it found an array.', !Array.isArray(payload.data)); From 766777de2bfa762f5db328902fd501031b7f59db Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 4 Jan 2016 12:02:11 +0100 Subject: [PATCH 1317/2527] [BUGFIX] Replace deprecated calls in tests to `find` with `findRecord` --- tests/integration/adapter/find-test.js | 6 ++--- .../adapter/json-api-adapter-test.js | 22 +++++++++---------- .../adapter/record-persistence-test.js | 14 ++++++------ .../integration/adapter/rest-adapter-test.js | 20 ++++++++--------- .../integration/adapter/store-adapter-test.js | 8 +++---- tests/integration/debug-adapter-test.js | 2 +- .../relationships/belongs-to-test.js | 2 +- .../relationships/has-many-test.js | 4 ++-- .../store/json-api-validation-test.js | 10 ++++----- .../group-records-for-find-many-test.js | 2 +- .../model/relationships/belongs-to-test.js | 4 ++-- 11 files changed, 47 insertions(+), 47 deletions(-) diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index fb07df7dc8b..46576aacd34 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -60,7 +60,7 @@ test("When a single record is requested, the adapter's find method should be cal }); }); -test("When a single record is requested multiple times, all .find() calls are resolved after the promise is resolved", (assert) => { +test("When a single record is requested multiple times, all .findRecord() calls are resolved after the promise is resolved", (assert) => { var deferred = Ember.RSVP.defer(); env.registry.register('adapter:person', DS.Adapter.extend({ @@ -103,7 +103,7 @@ test("When a single record is requested multiple times, all .find() calls are re run(() => deferred.resolve({ id: 1, name: "Braaaahm Dale" })); }); -test("When a single record is requested, and the promise is rejected, .find() is rejected.", (assert) => { +test("When a single record is requested, and the promise is rejected, .findRecord() is rejected.", (assert) => { env.registry.register('adapter:person', DS.Adapter.extend({ findRecord: () => reject() })); @@ -136,7 +136,7 @@ test('When a single record is requested, and the payload is blank', (assert) => })); assert.expectAssertion(() => { - run(() => store.find('person', 'the-id')); + run(() => store.findRecord('person', 'the-id')); }, /the adapter's response did not have any data/); }); diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index c6d71aed99f..4012a4b2d2f 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -114,7 +114,7 @@ test('find a single record', function(assert) { }]); run(function() { - store.find('post', 1).then(function(post) { + store.findRecord('post', 1).then(function(post) { assert.equal(passedUrl[0], '/posts/1'); assert.equal(post.get('id'), '1'); @@ -251,7 +251,7 @@ test('find a single record with belongsTo link as object { related }', function( }]); run(function() { - store.find('post', 1).then(function(post) { + store.findRecord('post', 1).then(function(post) { assert.equal(passedUrl[0], '/posts/1'); assert.equal(post.get('id'), '1'); @@ -296,7 +296,7 @@ test('find a single record with belongsTo link as object { data }', function(ass }]); run(function() { - store.find('post', 1).then(function(post) { + store.findRecord('post', 1).then(function(post) { assert.equal(passedUrl[0], '/posts/1'); assert.equal(post.get('id'), '1'); @@ -342,7 +342,7 @@ test('find a single record with belongsTo link as object { data } (polymorphic)' }]); run(function() { - store.find('user', 1).then(function(user) { + store.findRecord('user', 1).then(function(user) { assert.equal(passedUrl[0], '/users/1'); assert.equal(user.get('id'), '1'); @@ -388,7 +388,7 @@ test('find a single record with sideloaded belongsTo link as object { data }', f run(function() { - store.find('post', 1).then(function(post) { + store.findRecord('post', 1).then(function(post) { assert.equal(passedUrl[0], '/posts/1'); assert.equal(post.get('id'), '1'); @@ -440,7 +440,7 @@ test('find a single record with hasMany link as object { related }', function(as }]); run(function() { - store.find('post', 1).then(function(post) { + store.findRecord('post', 1).then(function(post) { assert.equal(passedUrl[0], '/posts/1'); assert.equal(post.get('id'), '1'); @@ -495,7 +495,7 @@ test('find a single record with hasMany link as object { data }', function(asser }]); run(function() { - store.find('post', 1).then(function(post) { + store.findRecord('post', 1).then(function(post) { assert.equal(passedUrl[0], '/posts/1'); assert.equal(post.get('id'), '1'); @@ -552,7 +552,7 @@ test('find a single record with hasMany link as object { data } (polymorphic)', }]); run(function() { - store.find('user', 1).then(function(user) { + store.findRecord('user', 1).then(function(user) { assert.equal(passedUrl[0], '/users/1'); assert.equal(user.get('id'), '1'); @@ -606,7 +606,7 @@ test('find a single record with sideloaded hasMany link as object { data }', fun }]); run(function() { - store.find('post', 1).then(function(post) { + store.findRecord('post', 1).then(function(post) { assert.equal(passedUrl[0], '/posts/1'); assert.equal(post.get('id'), '1'); @@ -659,7 +659,7 @@ test('find a single record with sideloaded hasMany link as object { data } (poly }]); run(function() { - store.find('user', 1).then(function(user) { + store.findRecord('user', 1).then(function(user) { assert.equal(passedUrl[0], '/users/1'); assert.equal(user.get('id'), '1'); @@ -906,7 +906,7 @@ test('fetching a belongsTo relationship link that returns null', function(assert }]); run(function() { - store.find('post', 1).then(function(post) { + store.findRecord('post', 1).then(function(post) { assert.equal(passedUrl[0], '/posts/1'); return post.get('author'); diff --git a/tests/integration/adapter/record-persistence-test.js b/tests/integration/adapter/record-persistence-test.js index d1408bc591a..51b770a081d 100644 --- a/tests/integration/adapter/record-persistence-test.js +++ b/tests/integration/adapter/record-persistence-test.js @@ -101,7 +101,7 @@ test("After a created record has been assigned an ID, finding a record by that I tom.save(); }); - assert.asyncEqual(tom, env.store.find('person', 1), "the retrieved record is the same as the created record"); + assert.asyncEqual(tom, env.store.findRecord('person', 1), "the retrieved record is the same as the created record"); }); test("when a store is committed, the adapter's `commit` method should be called with records that have been deleted.", function(assert) { @@ -125,7 +125,7 @@ test("when a store is committed, the adapter's `commit` method should be called } }); }); - env.store.find('person', 1).then(assert.wait(function(person) { + env.store.findRecord('person', 1).then(assert.wait(function(person) { tom = person; tom.deleteRecord(); return tom.save(); @@ -155,7 +155,7 @@ test("An adapter can notify the store that records were updated by calling `didS }); }); - all([env.store.find('person', 1), env.store.find('person', 2)]) + all([env.store.findRecord('person', 1), env.store.findRecord('person', 2)]) .then(assert.wait(function(array) { tom = array[0]; yehuda = array[1]; @@ -203,7 +203,7 @@ test("An adapter can notify the store that records were updated and provide new }); }); - hash({ tom: env.store.find('person', 1), yehuda: env.store.find('person', 2) }).then(assert.wait(function(people) { + hash({ tom: env.store.findRecord('person', 1), yehuda: env.store.findRecord('person', 2) }).then(assert.wait(function(people) { people.tom.set('name', "Draaaaaahm Dale"); people.yehuda.set('name', "Goy Katz"); @@ -233,7 +233,7 @@ test("An adapter can notify the store that a record was updated by calling `didS }); }); - hash({ tom: store.find('person', 1), yehuda: store.find('person', 2) }).then(assert.wait(function(people) { + hash({ tom: store.findRecord('person', 1), yehuda: store.findRecord('person', 2) }).then(assert.wait(function(people) { people.tom.set('name', "Tom Dale"); people.yehuda.set('name', "Yehuda Katz"); @@ -274,7 +274,7 @@ test("An adapter can notify the store that a record was updated and provide new }); }); - hash({ tom: store.find('person', 1), yehuda: store.find('person', 2) }).then(assert.wait(function(people) { + hash({ tom: store.findRecord('person', 1), yehuda: store.findRecord('person', 2) }).then(assert.wait(function(people) { people.tom.set('name', "Draaaaaahm Dale"); people.yehuda.set('name', "Goy Katz"); @@ -311,7 +311,7 @@ test("An adapter can notify the store that records were deleted by calling `didS }); }); - hash({ tom: store.find('person', 1), yehuda: store.find('person', 2) }).then(assert.wait(function(people) { + hash({ tom: store.findRecord('person', 1), yehuda: store.findRecord('person', 2) }).then(assert.wait(function(people) { people.tom.deleteRecord(); people.yehuda.deleteRecord(); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index c304a1f6fa4..c1fb7576da4 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -78,7 +78,7 @@ test("findRecord - passes buildURL a requestType", function(assert) { })); }); -test("find - basic payload (with legacy singular name)", function(assert) { +test("findRecord - basic payload (with legacy singular name)", function(assert) { ajaxResponse({ post: { id: 1, name: "Rails is omakase" } }); run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { @@ -2069,7 +2069,7 @@ test('normalizeKey - to set up _ids and _id', function(assert) { }); run(function() { - store.find('post', 1).then(assert.wait(function(post) { + store.findRecord('post', 1).then(assert.wait(function(post) { assert.equal(post.get('authorName'), "@d2h"); assert.equal(post.get('author.name'), "D2H"); assert.deepEqual(post.get('comments').mapBy('body'), ["Rails is unagi", "What is omakase?"]); @@ -2163,7 +2163,7 @@ test('groupRecordsForFindMany groups calls for small ids', function(assert) { adapter.coalesceFindRequests = true; adapter.findRecord = function(store, type, id, snapshot) { - assert.ok(false, "find should not be called - we expect 1 call to findMany for a100 and b100"); + assert.ok(false, "findRecord should not be called - we expect 1 call to findMany for a100 and b100"); return Ember.RSVP.reject(); }; @@ -2204,7 +2204,7 @@ test("calls adapter.handleResponse with the jqXHR and json", function(assert) { try { run(function() { - store.find('post', '1'); + store.findRecord('post', '1'); }); } finally { Ember.$.ajax = originalAjax; @@ -2238,7 +2238,7 @@ test('calls handleResponse with jqXHR, jqXHR.responseText, and requestData', fun try { run(function() { - store.find('post', '1').catch(function(err) { + store.findRecord('post', '1').catch(function(err) { assert.ok(err, 'promise rejected'); }); }); @@ -2267,7 +2267,7 @@ test("rejects promise if DS.AdapterError is returned from adapter.handleResponse }; Ember.run(function() { - store.find('post', '1').then(null, function(reason) { + store.findRecord('post', '1').then(null, function(reason) { assert.ok(true, 'promise should be rejected'); assert.ok(reason instanceof DS.AdapterError, 'reason should be an instance of DS.AdapterError'); }); @@ -2297,7 +2297,7 @@ test('on error appends errorThrown for sanity', function(assert) { try { run(function() { - store.find('post', '1').catch(function(err) { + store.findRecord('post', '1').catch(function(err) { assert.equal(err, errorThrown); assert.ok(err, 'promise rejected'); }); @@ -2325,7 +2325,7 @@ test('on error wraps the error string in an DS.AdapterError object', function(as try { run(function() { - store.find('post', '1').catch(function(err) { + store.findRecord('post', '1').catch(function(err) { assert.equal(err.errors[0].detail, errorThrown); assert.ok(err, 'promise rejected'); }); @@ -2351,7 +2351,7 @@ test('error handling includes a detailed message from the server', (assert) => { try { run(function() { - store.find('post', '1').catch(function(err) { + store.findRecord('post', '1').catch(function(err) { assert.equal(err.message, "Ember Data Request GET /posts/1 returned a 500\nPayload (text/plain)\nAn error message, perhaps generated from a backend server!"); assert.ok(err, 'promise rejected'); }); @@ -2378,7 +2378,7 @@ test('error handling with a very long HTML-formatted payload truncates the frien try { run(function() { - store.find('post', '1').catch(function(err) { + store.findRecord('post', '1').catch(function(err) { assert.equal(err.message, "Ember Data Request GET /posts/1 returned a 500\nPayload (text/html)\n[Omitted Lengthy HTML]"); assert.ok(err, 'promise rejected'); }); diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 008f967738f..a5435cd9acb 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -113,8 +113,8 @@ test("by default, createRecords calls createRecord once per record", function(as tom = records.tom; yehuda = records.yehuda; - assert.asyncEqual(tom, store.findRecord('person', 1), "Once an ID is in, find returns the same object"); - assert.asyncEqual(yehuda, store.findRecord('person', 2), "Once an ID is in, find returns the same object"); + assert.asyncEqual(tom, store.findRecord('person', 1), "Once an ID is in, findRecord returns the same object"); + assert.asyncEqual(yehuda, store.findRecord('person', 2), "Once an ID is in, findRecord returns the same object"); assert.equal(get(tom, 'updatedAt'), "now", "The new information is received"); assert.equal(get(yehuda, 'updatedAt'), "now", "The new information is received"); })); @@ -1119,7 +1119,7 @@ test("deleteRecord receives a snapshot", function(assert) { }); }); -test("find receives a snapshot", function(assert) { +test("findRecord receives a snapshot", function(assert) { assert.expect(1); adapter.findRecord = function(store, type, id, snapshot) { @@ -1397,7 +1397,7 @@ test("An async hasMany relationship with links should not trigger shouldBackgrou store = env.store; - run(store, 'find', 'post', '1').then(assert.wait(function(post) { + run(store, 'findRecord', 'post', '1').then(assert.wait(function(post) { return post.get('comments'); })).then(assert.wait(function(comments) { assert.equal(comments.get('length'), 3); diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index 41631bb2670..b8636ce14c2 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -116,7 +116,7 @@ test("Watching Records", function(assert) { assert.deepEqual(record.color, 'black'); Ember.run(function() { - post = store.find('post', 1); + post = store.findRecord('post', 1); }); Ember.run(function() { diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index a6cfcca701c..746861fb1d8 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1145,7 +1145,7 @@ if (isEnabled('ds-references')) { run(function() { var chapter; - store.find('chapter', 1).then(function(_chapter) { + store.findRecord('chapter', 1).then(function(_chapter) { chapter = _chapter; return chapter.get('book'); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 948a8414c92..610d616e4ef 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -576,7 +576,7 @@ test("A hasMany relationship can be reloaded even if it failed at the first time } }; run(function() { - env.store.find('post', 1).then(function(post) { + env.store.findRecord('post', 1).then(function(post) { var comments = post.get('comments'); return comments.catch(function() { return comments.reload(); @@ -617,7 +617,7 @@ test("A hasMany relationship can be directly reloaded if it was fetched via link ]); }; run(function() { - env.store.find('post', 1).then(function(post) { + env.store.findRecord('post', 1).then(function(post) { return post.get('comments').reload().then(function(comments) { assert.equal(comments.get('isLoaded'), true, "comments are loaded"); assert.equal(comments.get('length'), 2, "comments have 2 length"); diff --git a/tests/integration/store/json-api-validation-test.js b/tests/integration/store/json-api-validation-test.js index e3481ce6888..97ff456f596 100644 --- a/tests/integration/store/json-api-validation-test.js +++ b/tests/integration/store/json-api-validation-test.js @@ -40,7 +40,7 @@ test("when normalizeResponse returns undefined (or doesn't return), throws an er assert.throws(function () { run(function() { - store.find('person', 1); + store.findRecord('person', 1); }); }, /Top level of a JSON API document must be an object/); }); @@ -59,7 +59,7 @@ test("when normalizeResponse returns null, throws an error", function(assert) { assert.throws(function () { run(function() { - store.find('person', 1); + store.findRecord('person', 1); }); }, /Top level of a JSON API document must be an object/); }); @@ -79,7 +79,7 @@ test("when normalizeResponse returns an empty object, throws an error", function assert.throws(function () { run(function() { - store.find('person', 1); + store.findRecord('person', 1); }); }, /One or more of the following keys must be present/); }); @@ -103,7 +103,7 @@ test("when normalizeResponse returns a document with both data and errors, throw assert.throws(function () { run(function() { - store.find('person', 1); + store.findRecord('person', 1); }); }, /cannot both be present/); }); @@ -121,7 +121,7 @@ QUnit.assert.payloadError = function payloadError(payload, expectedError) { })); this.throws(function () { run(function() { - store.find('person', 1); + store.findRecord('person', 1); }); }, expectedError, `Payload ${JSON.stringify(payload)} should throw error ${expectedError}`); env.registry.unregister('serializer:person'); diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 2354905055e..49baf6d173b 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -48,7 +48,7 @@ test('groupRecordsForFindMany - findMany', function(assert) { Ember.run(function() { for (var i = 1; i <= 1024; i++) { - Store.find('testRecord', i); + Store.findRecord('testRecord', i); } }); diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index cb8a16d6d00..79969d0c212 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -417,7 +417,7 @@ test("belongsTo gives a warning when provided with a serialize option", function }); run(function() { - store.find('person', 1).then(assert.wait(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { assert.warns(function() { get(person, 'hobby'); }, /You provided a serialize option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.Serializer and it's implementations/); @@ -471,7 +471,7 @@ test("belongsTo gives a warning when provided with an embedded option", function }); run(function() { - store.find('person', 1).then(assert.wait(function(person) { + store.findRecord('person', 1).then(assert.wait(function(person) { assert.warns(function() { get(person, 'hobby'); }, /You provided an embedded option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin/); From 0eedecb021742ad5f593ad1526fea273aeb61289 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 4 Jan 2016 14:03:26 -0600 Subject: [PATCH 1318/2527] [BUGFIX beta] prevent calls to store.query leaking Although the result from `store.query` is intended to never be re-used as we delegate to the server for the truth of a query, the user still needs an escape hatch to destroy these AdapterPopulatedRecordArrays created by query in order to prevent excessive memory. Before, calling `destroy` on an AdapterPopulatedRecordArray (the type returned from store.query), the logic in RecordArrayManager#unregisterRecordArray did not account for adapter populated record arrays resulting in a leak. This commit changes the logic to search for the array in the RecordArrayManager's AdapterPopulatedRecordArray collection when unregistering a record array. Fixes #4041 --- addon/-private/system/record-array-manager.js | 36 +++++++++++++------ .../integration/record-array-manager-test.js | 24 +++++++++++++ 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index c80a74e3269..92dc7de4fe4 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -279,17 +279,22 @@ export default Ember.Object.extend({ var typeClass = array.type; // unregister filtered record array - var recordArrays = this.filteredRecordArrays.get(typeClass); - var index = recordArrays.indexOf(array); - if (index !== -1) { - recordArrays.splice(index, 1); - - // unregister live record array - } else if (this.liveRecordArrays.has(typeClass)) { - var liveRecordArrayForType = this.liveRecordArrayFor(typeClass); - if (array === liveRecordArrayForType) { - this.liveRecordArrays.delete(typeClass); + const recordArrays = this.filteredRecordArrays.get(typeClass); + const removedFromFiltered = remove(recordArrays, array); + + // remove from adapter populated record array + const removedFromAdapterPopulated = remove(this._adapterPopulatedRecordArrays, array); + + if (!removedFromFiltered && !removedFromAdapterPopulated) { + + // unregister live record array + if (this.liveRecordArrays.has(typeClass)) { + var liveRecordArrayForType = this.liveRecordArrayFor(typeClass); + if (array === liveRecordArrayForType) { + this.liveRecordArrays.delete(typeClass); + } } + } }, @@ -316,3 +321,14 @@ function flatten(list) { return result; } + +function remove(array, item) { + const index = array.indexOf(item); + + if (index !== -1) { + array.splice(index, 1); + return true; + } + + return false; +} diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index a0906991a60..55ead281254 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -171,3 +171,27 @@ test("Should not filter a store.peekAll() array when a record property is change assert.equal(updateFilterRecordArray.called.length, 0); }); + +test('#GH-4041 store#query AdapterPopulatedRecordArrays are removed from their managers instead of retained when #destroy is called', function(assert) { + run(() => { + store.push({ + data: { + type: 'car', + id: '1', + attributes: { + make: 'Honda', + model: 'fit' + } + } + }); + }); + const query = {}; + + var adapterPopulated = manager.createAdapterPopulatedRecordArray(Car, query); + + run(() => { + adapterPopulated.destroy(); + }); + + assert.equal(manager._adapterPopulatedRecordArrays.length, 0); +}); From 9615003ad5cb9c7f503f198ff5617a4cd9fba547 Mon Sep 17 00:00:00 2001 From: Erik Trom Date: Thu, 31 Dec 2015 13:08:25 -0800 Subject: [PATCH 1319/2527] [BUGFIX beta] strip debug statements from production builds --- lib/javascripts.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/javascripts.js b/lib/javascripts.js index ae56f758d02..77f2de04c84 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -1,3 +1,5 @@ +/* jshint node:true */ + var filterImports = require('babel-plugin-filter-imports'); var featureFlags = require('babel-plugin-feature-flags'); var babel = require('broccoli-babel-transpiler'); @@ -63,12 +65,12 @@ function strippedBuild(packageName, tree) { var plugins = [ featureFlags({ - import: { module: 'ember-data/features' }, + import: { module: 'ember-data/-private/features' }, features: features }), filterImports({ - 'ember-data/debug': [ + 'ember-data/-private/debug': [ 'assert', 'debug', 'deprecate', @@ -81,10 +83,10 @@ function strippedBuild(packageName, tree) { ]; var withoutDebug = new Funnel(tree, { - exclude: ['debug.js'] + exclude: ['ember-data/-private/debug.js'] }); - var compiled = babel(tree , babelOptions(packageName, { + var compiled = babel(withoutDebug , babelOptions(packageName, { plugins: plugins })); From bca9de65c41128b52cada8a53499b2927b9ba1d6 Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 5 Jan 2016 22:50:53 +0100 Subject: [PATCH 1320/2527] Run node tests and optional feature tests on AppVeyor --- appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index bdbf7dbd759..45e719e1e9e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -30,6 +30,8 @@ test_script: # Output useful info for debugging. - npm version - cmd: npm run test + - cmd: npm run test:optional-features + - cmd: npm run node-tests # Don't actually build. build: off From a24a8060ce254b5f6fe5b1eeee239f77d75f09e4 Mon Sep 17 00:00:00 2001 From: Kostas Date: Tue, 5 Jan 2016 20:23:43 -0600 Subject: [PATCH 1321/2527] [BUGFIX beta] Functional update for adapter populated record arrays permit for adapter populated record array contents to be updated by calling `update` method. refs #3082 --- .../system/record-arrays/record-array.js | 9 ++- addon/-private/system/store.js | 4 +- .../adapter-populated-record-array-test.js | 60 ++++++++++++++++++- 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index a34aa397d62..d70b98e3625 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -115,8 +115,13 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { update() { if (get(this, 'isUpdating')) { return; } - var store = get(this, 'store'); - var modelName = get(this, 'type.modelName'); + let store = get(this, 'store'); + let modelName = get(this, 'type.modelName'); + let query = get(this, 'query'); + + if (query) { + return store.query(modelName, query, this); + } return store.findAll(modelName, { reload: true }); }, diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index fb8006da201..780df60b619 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -955,10 +955,10 @@ Store = Service.extend({ @param {any} query an opaque query to be used by the adapter @return {Promise} promise */ - query(modelName, query) { + query(modelName, query, array) { assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); - var array = this.recordArrayManager + array = array || this.recordArrayManager .createAdapterPopulatedRecordArray(typeClass, query); var adapter = this.adapterFor(modelName); diff --git a/tests/unit/adapter-populated-record-array-test.js b/tests/unit/adapter-populated-record-array-test.js index c808c47025d..6616a54085d 100644 --- a/tests/unit/adapter-populated-record-array-test.js +++ b/tests/unit/adapter-populated-record-array-test.js @@ -1,4 +1,4 @@ -import {createStore} from 'dummy/tests/helpers/store'; +import {setupStore, createStore} from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; @@ -73,3 +73,61 @@ test('recordArray.replace() throws error', function(assert) { recordArray.replace(); }, Error("The result of a server query (on (subclass of DS.Model)) is immutable."), 'throws error'); }); + +test("when an adapter populated record gets updated the array contents are also updated", function(assert) { + assert.expect(8); + var filteredPromise, filteredArr, findPromise, findArray; + var env = setupStore({ person: Person }); + var store = env.store; + var array = [{ id: '1', name: "Scumbag Dale" }]; + + // resemble server side filtering + env.adapter.query = function(store, type, query, recordArray) { + return Ember.RSVP.resolve(array.slice(query.slice)); + }; + + // implement findAll to further test that query updates won't muddle + // with the non-query record arrays + env.adapter.findAll = function(store, type, sinceToken) { + return Ember.RSVP.resolve(array.slice(0)); + }; + + run(function() { + filteredPromise = store.query('person', { slice: 1 }); + findPromise = store.findAll('person'); + + // initialize adapter populated record array and assert initial state + filteredPromise.then(function(_filteredArr) { + filteredArr = _filteredArr; + assert.equal(filteredArr.get('length'), 0, "No records for this query"); + assert.equal(filteredArr.get('isUpdating'), false, "Record array isUpdating state updated"); + }); + + // initialize a record collection array and assert initial state + findPromise.then(function(_findArr) { + findArray = _findArr; + assert.equal(findArray.get('length'), 1, "All records are included in collection array"); + }); + }); + + // a new element gets pushed in record array + run(function() { + array.push({ id: '2', name: "Scumbag Katz" }); + filteredArr.update().then(function() { + assert.equal(filteredArr.get('length'), 1, "The new record is returned and added in adapter populated array"); + assert.equal(filteredArr.get('isUpdating'), false, "Record array isUpdating state updated"); + assert.equal(findArray.get('length'), 2); + }); + }); + + // element gets removed + run(function() { + array.pop(0); + filteredArr.update().then(function() { + assert.equal(filteredArr.get('length'), 0, "Record removed from array"); + // record not removed from the model collection + assert.equal(findArray.get('length'), 2, "Record still remains in collection array"); + }); + }); + +}); From e3a396809116ca7b0f446e581883b01c46a3d18c Mon Sep 17 00:00:00 2001 From: Luke Melia Date: Wed, 6 Jan 2016 19:21:58 -0500 Subject: [PATCH 1322/2527] [bugfix beta] Make setup-container public to allow consuming apps more flexibility with initializer --- addon/index.js | 2 +- addon/{-private => }/setup-container.js | 0 app/initializers/ember-data.js | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename addon/{-private => }/setup-container.js (100%) diff --git a/addon/index.js b/addon/index.js index e74808fca15..fd11ee95353 100644 --- a/addon/index.js +++ b/addon/index.js @@ -82,7 +82,7 @@ import { } from "ember-data/-private/transforms"; import {hasMany, belongsTo} from "ember-data/relationships"; -import setupContainer from "ember-data/-private/setup-container"; +import setupContainer from "ember-data/setup-container"; import initializeStoreService from 'ember-data/-private/instance-initializers/initialize-store-service'; import ContainerProxy from "ember-data/-private/system/container-proxy"; diff --git a/addon/-private/setup-container.js b/addon/setup-container.js similarity index 100% rename from addon/-private/setup-container.js rename to addon/setup-container.js diff --git a/app/initializers/ember-data.js b/app/initializers/ember-data.js index a9eccc19188..fc6386fdc81 100644 --- a/app/initializers/ember-data.js +++ b/app/initializers/ember-data.js @@ -1,4 +1,4 @@ -import setupContainer from 'ember-data/-private/setup-container'; +import setupContainer from 'ember-data/setup-container'; import 'ember-data/-private/core'; /* From 6c1ce7155a33d53ef13da06c9dd4681682c9d263 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 7 Jan 2016 12:56:15 +0100 Subject: [PATCH 1323/2527] [FEATURE ds-references] Only add function to prototype if enabled Currently the `referenceFor` function is added to the InternalModel's prototype, regardless if the ds-references feature is enabled or not. --- addon/-private/system/model/internal-model.js | 42 ++++++++++--------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 89e62028635..34a5ef70967 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -5,6 +5,7 @@ import RootState from "ember-data/-private/system/model/states"; import Relationships from "ember-data/-private/system/relationships/state/create"; import Snapshot from "ember-data/-private/system/snapshot"; import EmptyObject from "ember-data/-private/system/empty-object"; +import isEnabled from "ember-data/-private/features"; import { getOwner @@ -607,25 +608,6 @@ InternalModel.prototype = { return value; }, - referenceFor: function(type, name) { - var reference = this.references[name]; - - if (!reference) { - var relationship = this._relationships.get(name); - - if (type === "belongsTo") { - reference = new BelongsToReference(this.store, this, relationship); - } else if (type === "hasMany") { - reference = new HasManyReference(this.store, this, relationship); - } - - this.references[name] = reference; - } - - return reference; - }, - - /** @method updateRecordArrays @private @@ -850,3 +832,25 @@ InternalModel.prototype = { } } }; + +if (isEnabled('ds-references')) { + + InternalModel.prototype.referenceFor = function(type, name) { + var reference = this.references[name]; + + if (!reference) { + var relationship = this._relationships.get(name); + + if (type === "belongsTo") { + reference = new BelongsToReference(this.store, this, relationship); + } else if (type === "hasMany") { + reference = new HasManyReference(this.store, this, relationship); + } + + this.references[name] = reference; + } + + return reference; + }; + +} From b6bd6775ddc1ae165eb323f054907d83c078bf8f Mon Sep 17 00:00:00 2001 From: bmac Date: Sat, 9 Jan 2016 13:26:17 -0500 Subject: [PATCH 1324/2527] [BUGFIX beta] pin jquery to 1.11.3 to fix broken build See: http://benlimmer.com/2016/01/08/ember-jquery-dependancies/ --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index d39308fd45c..4ed1c4b9ee6 100644 --- a/bower.json +++ b/bower.json @@ -8,7 +8,7 @@ "ember-qunit": "0.4.9", "ember-qunit-notifications": "0.0.7", "ember-resolver": "~0.1.18", - "jquery": "^1.11.3", + "jquery": "1.11.3", "loader.js": "3.3.0", "qunit": "~1.18.0" }, From a11303dac652a40bb0f2750de7e90d5c2751f939 Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 4 Jan 2016 22:36:13 +0100 Subject: [PATCH 1325/2527] [BUGFIX beta] Correctly strip debug statements when used as addon --- index.js | 21 ++++++++-- lib/babel-build.js | 48 ++++++++++++++++++++++ lib/javascripts.js | 93 ++++++++----------------------------------- lib/stripped-build.js | 44 ++++++++++++++++++++ package.json | 6 +-- 5 files changed, 130 insertions(+), 82 deletions(-) create mode 100644 lib/babel-build.js create mode 100644 lib/stripped-build.js diff --git a/index.js b/index.js index b8527540cb7..040a736c4a8 100644 --- a/index.js +++ b/index.js @@ -49,10 +49,25 @@ module.exports = { return { inputTree: dir, rebuild: function() { return []; } }; } - var version = require('./lib/version'); - var merge = require('broccoli-merge-trees'); + var version = require('./lib/version'); + var merge = require('broccoli-merge-trees'); + var addonTree = merge([version(), dir]); - return this._super.treeForAddon.call(this, merge([version(), dir])); + if (process.env.EMBER_ENV === 'production') { + var strippedBuild = require('./lib/stripped-build'); + + // blacklist es6.modules so the modules are not compiled but simply the + // debug statements / features are stripped; this is taken from + // ember-cli-babel: + // https://github.com/babel/ember-cli-babel/blob/master/index.js#L71 + var strippedAddon = strippedBuild('ember-data', addonTree, { + blacklist: ['es6.modules', 'useStrict'] + }); + + return this._super.treeForAddon.call(this, strippedAddon); + } + + return this._super.treeForAddon.call(this, addonTree); }, included: function(app) { diff --git a/lib/babel-build.js b/lib/babel-build.js new file mode 100644 index 00000000000..6d5dde2147c --- /dev/null +++ b/lib/babel-build.js @@ -0,0 +1,48 @@ +var babel = require('broccoli-babel-transpiler'); +var path = require('path'); + +function babelOptions(libraryName, _options) { + _options = _options || {}; + + var options = { + whitelist: [ + 'es6.templateLiterals', + 'es6.parameters', + 'es6.arrowFunctions', + 'es6.destructuring', + 'es6.spread', + 'es6.properties.computed', + 'es6.properties.shorthand', + 'es6.blockScoping', + 'es6.constants', + 'es6.modules' + ], + sourceMaps: false, + modules: 'amdStrict', + moduleRoot: libraryName, + moduleId: true, + // Transforms /index.js files to use their containing directory name + getModuleId: function (name) { + return name.replace(/\/index$/g, ''); + }, + resolveModuleSource: function(name, filename) { + if (name.indexOf('.') === 0) { + return libraryName + '/' + path.join(path.dirname(filename), name); + } else { + return name; + } + } + }; + + Object.keys(_options).forEach(function(opt) { + options[opt] = _options[opt]; + }); + + return options; +} + +module.exports = function(packageName, tree, _options) { + var options = babelOptions(packageName, _options); + + return babel(tree, options); +} diff --git a/lib/javascripts.js b/lib/javascripts.js index 77f2de04c84..40cb79e6956 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -1,8 +1,5 @@ /* jshint node:true */ -var filterImports = require('babel-plugin-filter-imports'); -var featureFlags = require('babel-plugin-feature-flags'); -var babel = require('broccoli-babel-transpiler'); var merge = require('broccoli-merge-trees'); var concat = require('broccoli-concat'); var uglify = require('broccoli-uglify-sourcemap'); @@ -13,84 +10,23 @@ var path = require('path'); var Funnel = require('broccoli-funnel'); var versionReplace = require('./version-replace'); var fileCreator = require('broccoli-file-creator'); - -function babelOptions(libraryName, _options) { - _options = _options || {}; - - var options = { - whitelist: [ - 'es6.templateLiterals', - 'es6.parameters', - 'es6.arrowFunctions', - 'es6.destructuring', - 'es6.spread', - 'es6.properties.computed', - 'es6.properties.shorthand', - 'es6.blockScoping', - 'es6.constants', - 'es6.modules' - ], - sourceMaps: false, - modules: 'amdStrict', - moduleRoot: libraryName, - moduleId: true, - // Transforms /index.js files to use their containing directory name - getModuleId: function (name) { - return name.replace(/\/index$/g, ''); - }, - resolveModuleSource: function(name, filename) { - if (name.indexOf('.') === 0) { - return libraryName + '/' + path.join(path.dirname(filename), name); - } else { - return name; - } - } - }; - - Object.keys(_options).forEach(function(opt) { - options[opt] = _options[opt]; - }); - - return options; -} +var babelBuild = require('./babel-build'); +var strippedBuild = require('./stripped-build'); function debugBuild(packageName, tree) { - var compiled = babel(tree, babelOptions(packageName)); + var compiled = babelBuild(packageName, tree); + return stew.mv(compiled, packageName); } -function strippedBuild(packageName, tree) { - var featuresJson = fs.readFileSync('config/features.json', { encoding: 'utf8' }); - var features = JSON.parse(featuresJson); - - var plugins = [ - featureFlags({ - import: { module: 'ember-data/-private/features' }, - features: features - }), - - filterImports({ - 'ember-data/-private/debug': [ - 'assert', - 'debug', - 'deprecate', - 'info', - 'runInDebug', - 'warn', - 'debugSeal' - ] - }) - ]; - +function makeStrippedBuild(packageName, tree) { var withoutDebug = new Funnel(tree, { exclude: ['ember-data/-private/debug.js'] }); - var compiled = babel(withoutDebug , babelOptions(packageName, { - plugins: plugins - })); + var stripped = strippedBuild(packageName, withoutDebug); - return stew.mv(compiled, packageName); + return stew.mv(stripped, packageName); } function collapse(tree, outputFileName) { @@ -130,21 +66,26 @@ function minify(tree) { }); } - -module.exports = function(tree) { +function buildEmberInflector() { var emberInflector = new Funnel(path.dirname(require.resolve('ember-inflector/addon')), { include: ['**/*.js'] }); + + return debugBuild('ember-inflector', emberInflector); +} + +module.exports = function(tree) { + var emberInflector = buildEmberInflector(); var emberData = merge([tree, version()]); var javascripts = merge([ - debugBuild('ember-inflector', emberInflector), + emberInflector, debugBuild('ember-data', emberData) ]); var strippedJavascripts = merge([ - strippedBuild('ember-inflector', emberInflector), - strippedBuild('ember-data', emberData) + emberInflector, + makeStrippedBuild('ember-data', emberData) ]); var debug = collapse(javascripts, 'ember-data.js'); diff --git a/lib/stripped-build.js b/lib/stripped-build.js new file mode 100644 index 00000000000..b26a38e7ecb --- /dev/null +++ b/lib/stripped-build.js @@ -0,0 +1,44 @@ +var fs = require('fs'); +var path = require('path'); +var filterImports = require('babel-plugin-filter-imports'); +var featureFlags = require('babel-plugin-feature-flags'); +var babelBuild = require('./babel-build'); + +module.exports = function(packageName, tree, _options) { + var featuresJsonPath = path.join(__dirname, '../config/features.json'); + var featuresJson = fs.readFileSync(featuresJsonPath, { encoding: 'utf8' }); + var features = JSON.parse(featuresJson); + + // TODO explicitly set all features which are not enabled to `false`, so + // they are stripped --> make this configurable or pass features + // + // for (var feature in features) { + // if (features[feature] !== true) { + // features[feature] = false; + // } + // } + + var plugins = [ + featureFlags({ + import: { module: 'ember-data/-private/features' }, + features: features + }), + + filterImports({ + 'ember-data/-private/debug': [ + 'assert', + 'debug', + 'deprecate', + 'info', + 'runInDebug', + 'warn', + 'debugSeal' + ] + }) + ]; + + var options = _options || {}; + options.plugins = plugins; + + return babelBuild(packageName, tree, options); +}; diff --git a/package.json b/package.json index b80ffa40b86..01e424639ab 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,9 @@ "author": "", "license": "MIT", "dependencies": { + "babel-plugin-feature-flags": "^0.2.0", + "babel-plugin-filter-imports": "^0.2.0", + "broccoli-babel-transpiler": "^5.5.0", "broccoli-file-creator": "^1.0.0", "broccoli-merge-trees": "^1.0.0", "chalk": "^1.1.1", @@ -35,11 +38,8 @@ "silent-error": "^1.0.0" }, "devDependencies": { - "babel-plugin-feature-flags": "^0.2.0", - "babel-plugin-filter-imports": "^0.2.0", "bower": "^1.6.5", "broccoli-asset-rev": "^2.1.2", - "broccoli-babel-transpiler": "^5.5.0", "broccoli-concat": "0.0.13", "broccoli-funnel": "^1.0.0", "broccoli-jscs": "^1.1.0", From c214990a48d2d8dd43dcca5f10b081d54097af74 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 7 Jan 2016 01:24:08 +0100 Subject: [PATCH 1326/2527] [DOC beta] Hide private classes from YUIDoc It looks like marking classes as `@private` is not enough to hide them from showing up in the API doc at http://emberjs.com/api/data/. This commit changes the used comments to start with `/*`, which are definitely ignored by YUIDoc. --- addon/-private/system/container-proxy.js | 2 +- addon/-private/system/debug/debug-adapter.js | 2 +- addon/-private/system/model/internal-model.js | 41 ++++++++++--------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/addon/-private/system/container-proxy.js b/addon/-private/system/container-proxy.js index 0117042cdb5..eb2b1dc2c5f 100644 --- a/addon/-private/system/container-proxy.js +++ b/addon/-private/system/container-proxy.js @@ -1,6 +1,6 @@ import { deprecate } from "ember-data/-private/debug"; -/** +/* This is used internally to enable deprecation of container paths and provide a decent message to the user indicating how to fix the issue. diff --git a/addon/-private/system/debug/debug-adapter.js b/addon/-private/system/debug/debug-adapter.js index 52d715d7c3c..6d9c62f4aca 100644 --- a/addon/-private/system/debug/debug-adapter.js +++ b/addon/-private/system/debug/debug-adapter.js @@ -8,7 +8,7 @@ var capitalize = Ember.String.capitalize; var underscore = Ember.String.underscore; const { assert } = Ember; -/** +/* Extend `Ember.DataAdapter` with ED specific code. @class DebugAdapter diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 34a5ef70967..1235f805fc1 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -44,7 +44,7 @@ function retrieveFromCurrentState(key) { } var guid = 0; -/** +/* `InternalModel` is the Model class that we use internally inside Ember Data to represent models. Internal ED methods should only deal with `InternalModel` objects. It is a fast, plain Javascript class. @@ -57,6 +57,7 @@ var guid = 0; We need to make sure that the properties from `InternalModel` are correctly exposed/proxied on `Model` if they are needed. + @private @class InternalModel */ @@ -247,7 +248,7 @@ InternalModel.prototype = { } }, - /** + /* @method createSnapshot @private */ @@ -255,7 +256,7 @@ InternalModel.prototype = { return new Snapshot(this, options); }, - /** + /* @method loadingData @private @param {Promise} promise @@ -264,7 +265,7 @@ InternalModel.prototype = { this.send('loadingData', promise); }, - /** + /* @method loadedData @private */ @@ -273,7 +274,7 @@ InternalModel.prototype = { this.didInitalizeData(); }, - /** + /* @method notFound @private */ @@ -281,7 +282,7 @@ InternalModel.prototype = { this.send('notFound'); }, - /** + /* @method pushedData @private */ @@ -298,7 +299,7 @@ InternalModel.prototype = { return Object.keys(this._attributes).length > 0; }, - /** + /* Checks if the attributes which are considered as changed are still different to the state which is acknowledged by the server. @@ -322,7 +323,7 @@ InternalModel.prototype = { } }, - /** + /* Returns an object, whose keys are changed properties, and value is an [oldProp, newProp] array. @@ -346,7 +347,7 @@ InternalModel.prototype = { return diffData; }, - /** + /* @method adapterWillCommit @private */ @@ -354,7 +355,7 @@ InternalModel.prototype = { this.send('willCommit'); }, - /** + /* @method adapterDidDirty @private */ @@ -363,7 +364,7 @@ InternalModel.prototype = { this.updateRecordArraysLater(); }, - /** + /* @method send @private @param {String} name @@ -434,7 +435,7 @@ InternalModel.prototype = { this.record._notifyProperties(dirtyKeys); }, - /** + /* @method transitionTo @private @param {String} name @@ -520,7 +521,7 @@ InternalModel.prototype = { this._deferredTriggers.length = 0; }, - /** + /* @method clearRelationships @private */ @@ -538,7 +539,7 @@ InternalModel.prototype = { }); }, - /** + /* When a find request is triggered on the store, the user can optionally pass in attributes and relationships to be preloaded. These are meant to behave as if they came back from the server, except the user obtained them out of band and is informing @@ -608,7 +609,7 @@ InternalModel.prototype = { return value; }, - /** + /* @method updateRecordArrays @private */ @@ -648,7 +649,7 @@ InternalModel.prototype = { }); } }, - /** + /* If the adapter did not return a hash in response to a commit, merge the changed attributes and relationships into the existing saved data. @@ -678,7 +679,7 @@ InternalModel.prototype = { this.record._notifyProperties(changedKeys); }, - /** + /* @method updateRecordArraysLater @private */ @@ -713,7 +714,7 @@ InternalModel.prototype = { // FOR USE DURING COMMIT PROCESS - /** + /* @method adapterDidInvalidate @private */ @@ -731,7 +732,7 @@ InternalModel.prototype = { this._saveWasRejected(); }, - /** + /* @method adapterDidError @private */ @@ -751,7 +752,7 @@ InternalModel.prototype = { this._inFlightAttributes = new EmptyObject(); }, - /** + /* Ember Data has 3 buckets for storing the value of an attribute on an internalModel. `_data` holds all of the attributes that have been acknowledged by From fd2c83bfa1d43d8947d3eb8cb715d036cda7b3a1 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 11 Jan 2016 14:56:52 -0500 Subject: [PATCH 1327/2527] [BUGFIX beta] Do not expose the `array` argument on store.query --- addon/-private/system/record-arrays/record-array.js | 2 +- addon/-private/system/store.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index d70b98e3625..ae1252ccd49 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -120,7 +120,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { let query = get(this, 'query'); if (query) { - return store.query(modelName, query, this); + return store._query(modelName, query, this); } return store.findAll(modelName, { reload: true }); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 947dfcf193d..b8049519968 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -955,7 +955,11 @@ Store = Service.extend({ @param {any} query an opaque query to be used by the adapter @return {Promise} promise */ - query(modelName, query, array) { + query(modelName, query) { + return this._query(modelName, query); + }, + + _query(modelName, query, array) { assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); array = array || this.recordArrayManager From 3454fe57d186122c316882761f80ebdecfe4a221 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 11 Jan 2016 12:47:20 -0600 Subject: [PATCH 1328/2527] [BUGFIX beta] fail builds in ember-cli when ember-cli-shims isn't met fixes #4044 --- index.js | 39 +++++++++++++++++++++++++++-------- node-tests/nodetest-runner.js | 2 ++ package.json | 1 + 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index 040a736c4a8..cc1c7022ff0 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,7 @@ 'use strict'; var path = require('path'); +var SilentError = require('silent-error'); module.exports = { name: 'ember-data', @@ -21,21 +22,41 @@ module.exports = { init: function() { var bowerDeps = this.project.bowerDependencies(); + var VersionChecker = require('ember-cli-version-checker'); + + var checker = new VersionChecker(this); + var shims = checker.for('ember-cli-shims', 'bower'); + + var semver = require('semver'); + var version = require('./package').version; + + if (process.env.EMBER_DATA_SKIP_VERSION_CHECKING_DO_NOT_USE_THIS_ENV_VARIABLE) { + // Skip for node tests as we can't currently override the version of ember-cli-shims + // before the test helpers run. + return; + } if (bowerDeps['ember-data']) { - this._warn('Please remove `ember-data` from `bower.json`. As of Ember Data 2.3.0, only the NPM package is needed.'); + this._warn('Please remove `ember-data` from `bower.json`. As of Ember Data 2.3.0, only the NPM package is needed. If you need an ' + + 'earlier version of ember-data (< 2.3.0), you can leave this unchanged for now, but we strongly suggest you upgrade your version of Ember Data ' + + 'as soon as possible.'); this._forceBowerUsage = true; - } else { - this._forceBowerUsage = false; - } - var VersionChecker = require('ember-cli-version-checker'); + var emberDataBower = checker.for('ember-data', 'bower'); - var checker = new VersionChecker(this); - var dep = checker.for('ember-cli-shims', 'bower'); + if (!shims.satisfies('< 0.1.0') && emberDataBower.satisfies('< 2.3.0-beta.3')) { + throw new SilentError('Using a version of ember-cli-shims greater than or equal to 0.1.0 will cause errors while loading Ember Data < 2.3.0-beta.3 Please update ember-cli-shims from ' + shims.version + ' to 0.0.6'); + } + + if (!shims.satisfies('>= 0.1.0') && emberDataBower.satisfies('>= 2.3.0-beta.3')) { + throw new SilentError('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3.0-beta.3+. Please update ember-cli-shims from ' + shims.version + ' to 0.1.0.'); + } - if (!dep.satisfies('>= 0.1.0')) { - this._warn('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3+. Please update ember-cli-shims from ' + dep.version + ' to 0.1.0.'); + } else { + // NPM only, but ember-cli-shims does not match + if (!shims.satisfies('>= 0.1.0') && semver.satisfies(version, '^2.3.0-beta.3')) { + throw new SilentError('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3.0-beta.3+. Please update ember-cli-shims from ' + shims.version + ' to 0.1.0.'); + } } }, diff --git a/node-tests/nodetest-runner.js b/node-tests/nodetest-runner.js index 0cdde7a897f..cc3bdc2c481 100644 --- a/node-tests/nodetest-runner.js +++ b/node-tests/nodetest-runner.js @@ -6,6 +6,8 @@ var Promise = require('ember-cli/lib/ext/promise'); var rimraf = require('rimraf'); var mochaOnlyDetector = require('mocha-only-detector'); +process.env.EMBER_DATA_SKIP_VERSION_CHECKING_DO_NOT_USE_THIS_ENV_VARIABLE = true; + if (process.env.EOLNEWLINE) { require('os').EOL = '\n'; } diff --git a/package.json b/package.json index 01e424639ab..2d6d087db57 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "ember-cli-version-checker": "^1.1.4", "ember-inflector": "^1.9.4", "inflection": "^1.8.0", + "semver": "^5.1.0", "silent-error": "^1.0.0" }, "devDependencies": { From c781bdf7777a18d931265e8740fdcd527bec3a2c Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 12 Jan 2016 10:58:42 +0100 Subject: [PATCH 1329/2527] Update name for feature in FEATURES.md The feature is implemented in 266d3b0 as `ds-finder-include`. --- FEATURES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FEATURES.md b/FEATURES.md index 9456bb987bd..f3abee8ae9b 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -11,7 +11,7 @@ entry in `config/features.json`. ## Feature Flags -- `ds-find-include` +- `ds-finder-include` Allows an `include` query parameter to be specified with using `store.findRecord()` and `store.findAll()` as described in [RFC From cc70c8c6d126f6c7612f480166924c68e6897d41 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Tue, 12 Jan 2016 20:06:53 +0900 Subject: [PATCH 1330/2527] Require ember-source 2.x In favor of https://github.com/emberjs/data/issues/3650 --- ember-data-source.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ember-data-source.gemspec b/ember-data-source.gemspec index 59eec65e4eb..fdf68656d09 100644 --- a/ember-data-source.gemspec +++ b/ember-data-source.gemspec @@ -12,7 +12,7 @@ Gem::Specification.new do |gem| gem.version = Ember::Data::VERSION gem.license = "MIT" - gem.add_dependency "ember-source", ">= 1.8", "< 3.0" + gem.add_dependency "ember-source", ">= 2", "< 3.0" gem.files = %w(package.json) + Dir['dist/ember-data*.js', 'dist/ember-data.js.map', 'lib/ember/data/*.rb'] end From 67800e5427393f8983e05f59c80cc339f326a659 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 12 Jan 2016 08:28:49 -0500 Subject: [PATCH 1331/2527] Update changelog for 2.3.0 --- CHANGELOG.md | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cc4674ba75..543155927ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,78 @@ ### Master + +### Release 2.3.0 (January 12, 2015) +- [#4039](https://github.com/emberjs/data/pull/4039) Replace calls to store.find with store.findRecord +- [#4042](https://github.com/emberjs/data/pull/4042) [BUGFIX beta] prevent calls to store.query leaking +- [#4048](https://github.com/emberjs/data/pull/4048) Strip stuff from addon before it is added to app +- [#4050](https://github.com/emberjs/data/pull/4050) [BUGFIX beta] Functional update for adapter populated record arrays +- [#4051](https://github.com/emberjs/data/pull/4051) Make setup-container public to allow consuming apps more flexibility with initializer +- [#4052](https://github.com/emberjs/data/pull/4052) [DOC beta] Hide private classes from YUIDoc +- [#4055](https://github.com/emberjs/data/pull/4055) [BUGFIX beta] pin jquery to 1.11.3 to fix broken build +- [#4057](https://github.com/emberjs/data/pull/4057) [BUGFIX beta] fail builds in ember-cli when ember-cli-shims isn't met +- [#4058](https://github.com/emberjs/data/pull/4058) [BUGFIX beta] Do not expose the array argument on store.query +- [#4060](https://github.com/emberjs/data/pull/4060) Require ember-source 2.x +- [#4018](https://github.com/emberjs/data/pull/4018) [CLEANUP] re-use test setup to assert correct call to adapter.ajax +- [#4019](https://github.com/emberjs/data/pull/4019) Use JSON-API adapter and serializer in blueprints +- [#4021](https://github.com/emberjs/data/pull/4021) [BUGFIX beta] Move ember-inflector to an explicit dependency for the … +- [#4025](https://github.com/emberjs/data/pull/4025) Use keyForReliationship for belongsTo and hasMany +- [#4029](https://github.com/emberjs/data/pull/4029) [BUGFIX beta] Move public modules out of the `-private` folder +- [#4026](https://github.com/emberjs/data/pull/4026) [BUGFIX beta] ignores keys that are not found in the map +- [#3813](https://github.com/emberjs/data/pull/3813) ember-data should provide its blueprints +- [#3996](https://github.com/emberjs/data/pull/3996) Update ember-cli-shims to 0.1.0 to silence ED's own warning +- [#3999](https://github.com/emberjs/data/pull/3999) Run the Ember Data initializer when Ember Data is loaded as an Ember … +- [#4003](https://github.com/emberjs/data/pull/4003) Only run the Ember.onload initializers in globals mode +- [#4010](https://github.com/emberjs/data/pull/4010) [DOC beta] Mark comments as private +- [#4014](https://github.com/emberjs/data/pull/4014) Register the version before the DEBUG version are printed when loadin… +- [#3995](https://github.com/emberjs/data/pull/3995) [BUGFIX beta] Implement public module API. +- [#3865](https://github.com/emberjs/data/pull/3943) [PERF] Ajax should join an existing run if one exists +- [#3949](https://github.com/emberjs/data/pull/3949) Fix incorrect reference in store api docs +- [#3841](https://github.com/emberjs/data/pull/3841) Log a deprecation warning when when Ember Data is loaded with Ember 1.13 +- [#3973](https://github.com/emberjs/data/pull/3973) [CLEANUP] use debug helpers from ember-data/debug +- [#3978](https://github.com/emberjs/data/pull/3978) [BUGFIX beta] bump ember-inflector +- [#3983](https://github.com/emberjs/data/pull/3983) [DOC beta] Fix documentation to use "serializedHasManyName" +- [#3986](https://github.com/emberjs/data/pull/3986) Move private modules into the `-private` directory +- [#3865](https://github.com/emberjs/data/pull/3865) Assert that passed array to set a hasMany consists of records +- [#3820](https://github.com/emberjs/data/pull/3820) [CLEANUP] Remove duplicate test for creating record +- [#3819](https://github.com/emberjs/data/pull/3819) [CLEANUP] Remove duplicate `default export` in snapshot.js +- [#3713](https://github.com/emberjs/data/pull/3713) Document the return value of DS.Adapter#updateRecord +- [#3390](https://github.com/emberjs/data/pull/3390) Update the jsbin link so it has no deprecation warnings +- [#3835](https://github.com/emberjs/data/pull/3835) [BUGFIX] extract polymorphic belongsTo in RESTSerializer +- [#3829](https://github.com/emberjs/data/pull/3829) Remove references to findQuery +- [#3824](https://github.com/emberjs/data/pull/3824) [DOCS] Improve docs for JSONSerializer +- [#3828](https://github.com/emberjs/data/pull/3828) [CLEANUP] Make idiomatic use of `export default` +- [#3821](https://github.com/emberjs/data/pull/3821) [CLEANUP] Remove unecessary wrap of rejection in run-loop +- [#3827](https://github.com/emberjs/data/pull/3827) [DOC] Remove reference to `isDirty` in DS.Model documentation +- [#3839](https://github.com/emberjs/data/pull/3839) Cleanup build +- [#3831](https://github.com/emberjs/data/pull/3831) [CLEANUP] dasherize file name for hasRecordForId test +- [#3830](https://github.com/emberjs/data/pull/3830) Fix tests for non-dasherized lookups +- [#3837](https://github.com/emberjs/data/pull/3837) [BUGFIX] Attribute/relationship named "type" of embedded record is considered before normalization +- [#3832](https://github.com/emberjs/data/pull/3832) Fix API docs for JSONAPISerializer.normalize +- [#3834](https://github.com/emberjs/data/pull/3834) raise errors on deprecation +- [#3843](https://github.com/emberjs/data/pull/3843) Remove unneeded PromiseArray allocation +- [#3844](https://github.com/emberjs/data/pull/3844) Remove conditional statement that is always true +- [#3855](https://github.com/emberjs/data/pull/3855) Deprecate complex objects as an attributes `defaultValue`. +- [#3850](https://github.com/emberjs/data/pull/3850) [DOC] Document snapshotRecordArray param passed to adapter.findAll +- [#3868](https://github.com/emberjs/data/pull/3868) Reset changed attributes when matching data is pushed +- [#3869](https://github.com/emberjs/data/pull/3869) Update the Changelog for 1.13.14 +- [#3867](https://github.com/emberjs/data/pull/3867) Allow serializers to normalize response, remove old internal serializers code +- [#3858](https://github.com/emberjs/data/pull/3858) [DOC] remove documentation for `isError` in states +- [#3866](https://github.com/emberjs/data/pull/3866) Allow store.push to accept { data: null } +- [#3860](https://github.com/emberjs/data/pull/3860) [CLEANUP] remove unused private method in AdapterPopulatedRecordArray +- [#3907](https://github.com/emberjs/data/pull/3907) Addonize +- [#3898](https://github.com/emberjs/data/pull/3898) Fix DS.Errors summary and error object example +- [#3889](https://github.com/emberjs/data/pull/3889) [perf] minor adjustments to `store#push` flow +- [#3928](https://github.com/emberjs/data/pull/3928) update README stating no IE8 support +- [#3915](https://github.com/emberjs/data/pull/3915) Add null implementation of findMany in DS.Adapter +- [#3904](https://github.com/emberjs/data/pull/3904) Cleanup `.codeclimate.yml` +- [#3912](https://github.com/emberjs/data/pull/3912) Use public API for container/registry when possible. +- [#3924](https://github.com/emberjs/data/pull/3924) [CLEANUP] `tests/integration/adapter/find-test.js` +- [#3925](https://github.com/emberjs/data/pull/3925) [CLEANUP] Clean up adapter/find-all-test.js +- [#3927](https://github.com/emberjs/data/pull/3927) restore globals publishing to canary build +- [#3929](https://github.com/emberjs/data/pull/3929) upgrade node to 4 on CI +- [#3931](https://github.com/emberjs/data/pull/3931) update ember-cli to 1.13.12 + ### Release 2.2.0 (November 17, 2015) - [#3937](https://github.com/emberjs/data/pull/3937) [BUGFIX beta] Warn instead of asserting when a mapped key doesn't mat… - [#3868](https://github.com/emberjs/data/pull/3868) Reset changed attributes when matching data is pushed From b731ebb1a757042cad82c1f7017b75dc9d6cbf08 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Tue, 12 Jan 2016 09:44:18 -0500 Subject: [PATCH 1332/2527] Update release year --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 543155927ce..ae7c9e846f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ### Master -### Release 2.3.0 (January 12, 2015) +### Release 2.3.0 (January 12, 2016) - [#4039](https://github.com/emberjs/data/pull/4039) Replace calls to store.find with store.findRecord - [#4042](https://github.com/emberjs/data/pull/4042) [BUGFIX beta] prevent calls to store.query leaking - [#4048](https://github.com/emberjs/data/pull/4048) Strip stuff from addon before it is added to app From b13a81baac70983be16e10be2d59530c979f261a Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 12 Jan 2016 10:44:20 -0800 Subject: [PATCH 1333/2527] [BUGFIX release] Use correct version number when used as an addon. --- lib/calculate-version.js | 16 ++++++++++++++++ lib/version-replace.js | 5 ++--- lib/version.js | 11 ++--------- package.json | 3 ++- 4 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 lib/calculate-version.js diff --git a/lib/calculate-version.js b/lib/calculate-version.js new file mode 100644 index 00000000000..75b7af2c185 --- /dev/null +++ b/lib/calculate-version.js @@ -0,0 +1,16 @@ +var path = require('path'); +var existsSync = require('exists-sync'); +var gitRepoInfo = require('git-repo-info'); + +module.exports = function() { + var gitPath = path.join(__dirname, '..', '.git'); + var packageVersion = require('../package.json').version; + + if (existsSync(gitPath)) { + var info = gitRepoInfo(gitPath); + + return packageVersion + '+' + info.sha.slice(0, 10); + } else { + return packageVersion; + } +}; diff --git a/lib/version-replace.js b/lib/version-replace.js index 92fc17cb86d..bb443549a22 100644 --- a/lib/version-replace.js +++ b/lib/version-replace.js @@ -1,4 +1,4 @@ -var VERSION = require('git-repo-version')(10); +var calculateVersion = require('./calculate-version'); var replace = require('broccoli-string-replace'); module.exports = function configFiles(tree) { @@ -6,8 +6,7 @@ module.exports = function configFiles(tree) { files: ['*.{json,js}'], pattern: { match: /VERSION_STRING_PLACEHOLDER/g, - replacement: VERSION + replacement: calculateVersion() } }); }; - diff --git a/lib/version.js b/lib/version.js index c76390fb201..dd80c315bd2 100644 --- a/lib/version.js +++ b/lib/version.js @@ -1,13 +1,6 @@ +var calculateVersion = require('./calculate-version'); var createFile = require('broccoli-file-creator'); -var version; - -try { - version = require('git-repo-version')(10); -} catch (e) { - version = require('../package').version; -} - module.exports = function() { - return createFile('version.js', 'export default "' + version + '";'); + return createFile('version.js', 'export default "' + calculateVersion() + '";'); }; diff --git a/package.json b/package.json index 2d6d087db57..943664f3d05 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,8 @@ "ember-cli-test-info": "^1.0.0", "ember-cli-version-checker": "^1.1.4", "ember-inflector": "^1.9.4", + "exists-sync": "0.0.3", + "git-repo-info": "^1.1.2", "inflection": "^1.8.0", "semver": "^5.1.0", "silent-error": "^1.0.0" @@ -67,7 +69,6 @@ "ember-publisher": "0.0.7", "ember-try": "0.0.6", "ember-watson": "^0.7.0", - "git-repo-version": "^0.3.0", "github": "^0.2.4", "glob": "^5.0.13", "lodash.assign": "^3.2.0", From 1a861bb19e96f5e01930e8d5651abf175e989379 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 12 Jan 2016 12:01:30 -0600 Subject: [PATCH 1334/2527] [BUGFIX release] don't load "app" code when loading globals files The code that gets compiled for the globals build is in a closure with its own instance of `loader.js`, so the entries for ember-data don't end up in ember-cli's instance of `loader.js`. The ember-data code does include shims that end up in the app's instance of loader.js, so we exclude the app code from running in this case. --- index.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/index.js b/index.js index cc1c7022ff0..ce7c24a49cc 100644 --- a/index.js +++ b/index.js @@ -64,6 +64,17 @@ module.exports = { return path.join(__dirname, 'blueprints'); }, + treeForApp: function(dir) { + if (this._forceBowerUsage) { + // Fake an empty broccoli tree + return { inputTree: dir, rebuild: function() { return []; } }; + } + + // this._super.treeForApp is undefined in ember-cli (1.13) for some reason. + // TODO: investigate why treeForApp isn't on _super + return dir; + }, + treeForAddon: function(dir) { if (this._forceBowerUsage) { // Fakes an empty broccoli tree From 7bc99d8c55164c8d53405be9694d6084e665009b Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Tue, 12 Jan 2016 14:42:41 -0500 Subject: [PATCH 1335/2527] Bump canary to 2.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2d6d087db57..034d1671e2e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.4.0-canary", + "version": "2.5.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From 44e3c703bc7439b72f4a659d1e1639b0b1d27896 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 12 Jan 2016 15:27:36 -0500 Subject: [PATCH 1336/2527] [BUGFIX release] use calcualteVersion in yuidoc do not prefix globals versions with v --- lib/calculate-version.js | 3 +++ lib/version-replace.js | 3 ++- lib/yuidoc.js | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/calculate-version.js b/lib/calculate-version.js index 75b7af2c185..941e54208ee 100644 --- a/lib/calculate-version.js +++ b/lib/calculate-version.js @@ -8,6 +8,9 @@ module.exports = function() { if (existsSync(gitPath)) { var info = gitRepoInfo(gitPath); + if (info.tag) { + return info.tag; + } return packageVersion + '+' + info.sha.slice(0, 10); } else { diff --git a/lib/version-replace.js b/lib/version-replace.js index bb443549a22..d3952f49fba 100644 --- a/lib/version-replace.js +++ b/lib/version-replace.js @@ -1,4 +1,5 @@ var calculateVersion = require('./calculate-version'); +var version = calculateVersion().replace(/^v/, ''); var replace = require('broccoli-string-replace'); module.exports = function configFiles(tree) { @@ -6,7 +7,7 @@ module.exports = function configFiles(tree) { files: ['*.{json,js}'], pattern: { match: /VERSION_STRING_PLACEHOLDER/g, - replacement: calculateVersion() + replacement: version } }); }; diff --git a/lib/yuidoc.js b/lib/yuidoc.js index 0e0e300873f..eb5cede87e6 100644 --- a/lib/yuidoc.js +++ b/lib/yuidoc.js @@ -1,5 +1,5 @@ var YUIDoc = require('broccoli-yuidoc'); -var version = require('git-repo-version')(10); +var calculateVersion = require('./calculate-version'); var path = require('path'); module.exports = function yui() { @@ -12,7 +12,7 @@ module.exports = function yui() { yuidoc: { "name": "The ember-data API", "description": "The ember-data API: a data persistence library for Ember.js", - "version": version, + "version": calculateVersion(), "logo": "http://f.cl.ly/items/1A1L432s022u1O1q1V3p/ember%20logo.png", "url": "https://github.com/emberjs/data", "options": { From 0991de4f9453de334ad2b070dc4b8cbed191c827 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 12 Jan 2016 16:43:50 -0500 Subject: [PATCH 1337/2527] Update changelog for 2.3.1 release --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae7c9e846f8..61965d28670 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ### Master +### Release 2.3.1 (January 12, 2016) +- [#4063](https://github.com/emberjs/data/pull/4063) [BUGFIX release] don't load "app" code when loading globals files +- [#4066](https://github.com/emberjs/data/pull/4066) Use correct version number when used as an addon. ### Release 2.3.0 (January 12, 2016) - [#4039](https://github.com/emberjs/data/pull/4039) Replace calls to store.find with store.findRecord From fb9f4f1267c45b3b2790d8bbd0de4a1a442720be Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Tue, 12 Jan 2016 23:38:20 -0500 Subject: [PATCH 1338/2527] Add more tests for adapter and model blueprints --- node-tests/blueprints/adapter-test.js | 49 +++++++++++++++ node-tests/blueprints/model-test.js | 85 +++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index d57b54a6119..276e6a9c05a 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -25,6 +25,55 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { }); }); + it('adapter with --base-class', function() { + return generateAndDestroy(['adapter', 'foo', '--base-class=bar'], { + files: [ + { + file: 'app/adapters/foo.js', + contains: [ + 'import BarAdapter from \'./bar\';', + 'export default BarAdapter.extend({' + ] + }, + { + file: 'tests/unit/adapters/foo-test.js', + contains: [ + 'moduleFor(\'adapter:foo\'' + ] + } + ] + }); + }); + + it('adapter throws when --base-class is same as name', function() { + return generateAndDestroy(['adapter', 'application', '--base-class=application'], { + throws: { + message: /Adapters cannot extend from themself/, + type: 'SilentError' + } + }); + }); + + it('adapter when is named "application"', function() { + return generateAndDestroy(['adapter', 'application'], { + files: [ + { + file: 'app/adapters/application.js', + contains: [ + 'import DS from \'ember-data\';', + 'export default DS.JSONAPIAdapter.extend({' + ] + }, + { + file: 'tests/unit/adapters/application-test.js', + contains: [ + 'moduleFor(\'adapter:application\'' + ] + } + ] + }); + }); + it('adapter-test', function() { return generateAndDestroy(['adapter-test', 'foo'], { files: [ diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index 9dbe6213a92..64e616baaa4 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -25,6 +25,91 @@ describe('Acceptance: generate and destroy model blueprints', function() { }); }); + it('model with attrs', function() { + return generateAndDestroy([ + 'model', + 'foo', + 'misc', + 'skills:array', + 'isActive:boolean', + 'birthday:date', + 'someObject:object', + 'age:number', + 'name:string', + 'customAttr:custom-transform' + ], { + files: [ + { + file: 'app/models/foo.js', + contains: [ + 'import DS from \'ember-data\';', + 'export default DS.Model.extend(', + 'misc: DS.attr()', + 'skills: DS.attr(\'array\')', + 'isActive: DS.attr(\'boolean\')', + 'birthday: DS.attr(\'date\')', + 'someObject: DS.attr(\'object\')', + 'age: DS.attr(\'number\')', + 'name: DS.attr(\'string\')', + 'customAttr: DS.attr(\'custom-transform\')' + ] + }, + { + file: 'tests/unit/models/foo-test.js', + contains: [ + 'moduleForModel(\'foo\'' + ] + } + ] + }); + }); + + it('model with belongsTo', function() { + return generateAndDestroy(['model', 'comment', 'post:belongs-to', 'author:belongs-to:user'], { + files: [ + { + file: 'app/models/comment.js', + contains: [ + 'import DS from \'ember-data\';', + 'export default DS.Model.extend(', + 'post: DS.belongsTo(\'post\')', + 'author: DS.belongsTo(\'user\')', + ] + }, + { + file: 'tests/unit/models/comment-test.js', + contains: [ + 'moduleForModel(\'comment\'', + 'needs: [\'model:post\', \'model:user\']' + ] + } + ] + }); + }); + + it('model with hasMany', function() { + return generateAndDestroy(['model', 'post', 'comments:has-many', 'otherComments:has-many:comment'], { + files: [ + { + file: 'app/models/post.js', + contains: [ + 'import DS from \'ember-data\';', + 'export default DS.Model.extend(', + 'comments: DS.hasMany(\'comment\')', + 'otherComments: DS.hasMany(\'comment\')', + ] + }, + { + file: 'tests/unit/models/post-test.js', + contains: [ + 'moduleForModel(\'post\'', + 'needs: [\'model:comment\']' + ] + } + ] + }); + }); + it('model-test', function() { return generateAndDestroy(['model-test', 'foo'], { files: [ From 11dd60d907a36b1e922077f89c7656c62fb08402 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Thu, 14 Jan 2016 01:40:47 +0900 Subject: [PATCH 1339/2527] [BUGFIX release] Fix bundled source path Currently, global builds are placed into `./dist/globals`. --- lib/ember/data/source.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ember/data/source.rb b/lib/ember/data/source.rb index 9140be09c4c..142d061de0d 100644 --- a/lib/ember/data/source.rb +++ b/lib/ember/data/source.rb @@ -4,7 +4,7 @@ module Ember module Data module Source def self.bundled_path_for(distro) - File.expand_path("../../../../dist/#{distro}", __FILE__) + File.expand_path("../../../../dist/globals/#{distro}", __FILE__) end end end From 07435036397207fcd59325b8aef613d359f993bc Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Thu, 14 Jan 2016 01:52:05 +0900 Subject: [PATCH 1340/2527] [BUGFIX release] Add missing dist source to gem --- ember-data-source.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ember-data-source.gemspec b/ember-data-source.gemspec index fdf68656d09..d73b168d87e 100644 --- a/ember-data-source.gemspec +++ b/ember-data-source.gemspec @@ -14,5 +14,5 @@ Gem::Specification.new do |gem| gem.add_dependency "ember-source", ">= 2", "< 3.0" - gem.files = %w(package.json) + Dir['dist/ember-data*.js', 'dist/ember-data.js.map', 'lib/ember/data/*.rb'] + gem.files = %w(package.json) + Dir['dist/globals/ember-data*.js', 'dist/globals/ember-data.js.map', 'lib/ember/data/*.rb'] end From f6749c7e1eec302f30ac3a8d5029e8c6ed0a12a4 Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 13 Jan 2016 18:18:19 +0100 Subject: [PATCH 1341/2527] [skip ci] Update README, now that ember-data is a proper addon --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index c318cdfd3eb..dc298b2b057 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,18 @@ Christoffer Persson and Stanley Stuart. ### Getting Ember Data +Since version `2.3` ember-data is a proper Ember-CLI addon which can be added +to your app via: + +```no-highlight +ember install ember-data +``` + +If you need to use a version of ember-data package `< 2.3`, you need to add the +npm package and add the dependency via bower: + ```no-highlight +npm install ember-data@v2.2.1 --save-dev bower install ember-data --save ``` From 4a90dea1b7d6b353008baf155b4910c1ca4d8bf5 Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 4 Jan 2016 15:28:48 +0100 Subject: [PATCH 1342/2527] Re-use test helpers from ember-dev This change re-uses the test helpers from ember-dev to check for expected assertions and deprecations as well as to confirm that there is no pending run-loop at the end of a test. --- package.json | 1 + tests/helpers/ember-assertions.js | 132 ------------------ .../ember-assertions/assertion-expectation.js | 48 ------- .../helpers/ember-assertions/deprecations.js | 21 --- .../method-call-expectation.js | 36 ----- tests/helpers/setup-ember-dev.js | 54 +++++++ tests/test-helper.js | 5 +- 7 files changed, 56 insertions(+), 241 deletions(-) delete mode 100644 tests/helpers/ember-assertions.js delete mode 100644 tests/helpers/ember-assertions/assertion-expectation.js delete mode 100644 tests/helpers/ember-assertions/deprecations.js delete mode 100644 tests/helpers/ember-assertions/method-call-expectation.js create mode 100644 tests/helpers/setup-ember-dev.js diff --git a/package.json b/package.json index adc6a5a2dfd..26ffb14e110 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "ember-cli-qunit": "^1.0.0", "ember-cli-release": "0.2.3", "ember-cli-uglify": "^1.2.0", + "ember-dev": "emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed", "ember-disable-prototype-extensions": "^1.0.0", "ember-disable-proxy-controllers": "^1.0.0", "ember-export-application-global": "^1.0.3", diff --git a/tests/helpers/ember-assertions.js b/tests/helpers/ember-assertions.js deleted file mode 100644 index 657ce9ba3d6..00000000000 --- a/tests/helpers/ember-assertions.js +++ /dev/null @@ -1,132 +0,0 @@ -import Ember from 'ember'; -import AssertionExpectation from './ember-assertions/assertion-expectation'; -import deprecations from './ember-assertions/deprecations'; - -// Looks for an exception raised within the fn. -// -// expectAssertion(function(){ -// Ember.assert("Homie don't roll like that"); -// } /* , optionalMessageStringOrRegex */); -// -export function expectAssertion(fn, message) { - (new AssertionExpectation(message, this)).assert(fn); -} - -// Expects no deprecation to happen from the time of calling until -// the end of the test. -// -// expectNoDeprecation(/* optionalStringOrRegex */); -// Ember.deprecate("Old And Busted"); -// -export function expectNoDeprecation(message) { - if (Ember.isArray(deprecations.expecteds)) { - throw new Error("No deprecation was expected after expectDeprecation was called!"); - } - deprecations.stubEmber(); - deprecations.expecteds = deprecations.NONE; -} - -// Expect a deprecation to happen within a function, or if no function -// is pass, from the time of calling until the end of the test. Can be called -// multiple times to assert deprecations with different specific messages -// were fired. -// -// expectDeprecation(function(){ -// Ember.deprecate("Old And Busted"); -// }, /* optionalStringOrRegex */); -// -// expectDeprecation(/* optionalStringOrRegex */); -// Ember.deprecate("Old And Busted"); -// -export function expectDeprecation(fn, message) { - if (deprecations.expecteds === deprecations.NONE) { - throw("A deprecation was expected after expectNoDeprecation was called!"); - } - deprecations.stubEmber(); - deprecations.expecteds = deprecations.expecteds || []; - if (fn && typeof fn !== 'function') { - // fn is a message - deprecations.expecteds.push(fn); - } else { - deprecations.expecteds.push(message || /.*/); - if (fn) { - fn(); - this.assertDeprecation(); - } - } -} - -// Forces an assert the deprecations occurred, and resets the globals -// storing asserts for the next run. -// -// expectNoDeprecation(/Old/); -// setTimeout(function(){ -// Ember.deprecate("Old And Busted"); -// assertDeprecation(); -// }); -// -// assertDeprecation is called after each test run to catch any expectations -// without explicit asserts. -// -export function assertDeprecation() { - var expecteds = deprecations.expecteds; - var actuals = deprecations.actuals || []; - if (!expecteds) { - deprecations.actuals = null; - return; - } - - deprecations.restoreEmber(); - deprecations.actuals = null; - deprecations.expecteds = null; - - if (expecteds === deprecations.NONE) { - var actualMessages = []; - for (var _actual in actuals) { - actualMessages.push(_actual[0]); - } - this.ok(actuals.length === 0, "Expected no deprecation call, got: "+actualMessages.join(', ')); - } else { - for (var o=0;o < expecteds.length; o++) { - var expected = expecteds[o]; - var match, actual; - for (var i = 0; i < actuals.length; i++) { - actual = actuals[i]; - if (!actual[1]) { - if (expected instanceof RegExp) { - if (expected.test(actual[0])) { - match = actual; - break; - } - } else { - if (expected === actual[0]) { - match = actual; - break; - } - } - } - } - - if (!actual) { - this.ok(false, "Recieved no deprecate calls at all, expecting: " + expected); - } else if (match && !match[1]) { - this.ok(true, "Recieved failing deprecation with message: " + match[0]); - } else if (match && match[1]) { - this.ok(false, "Expected failing deprecation, got succeeding with message: " + match[0]); - } else if (actual[1]) { - this.ok(false, "Did not receive failing deprecation matching '" + expected + "', last was success with '" + actual[0] + "'"); - } else if (!actual[1]) { - this.ok(false, "Did not receive failing deprecation matching '" + expected + "', last was failure with '" + actual[0] + "'"); - } - } - } -} - -export default function addEmberAssertions(assertPrototype) { - Ember.merge(assertPrototype, { - expectAssertion, - expectNoDeprecation, - expectDeprecation, - assertDeprecation - }); -} diff --git a/tests/helpers/ember-assertions/assertion-expectation.js b/tests/helpers/ember-assertions/assertion-expectation.js deleted file mode 100644 index 7fbc599dfad..00000000000 --- a/tests/helpers/ember-assertions/assertion-expectation.js +++ /dev/null @@ -1,48 +0,0 @@ -import Ember from 'ember'; -import MethodCallExpectation from './method-call-expectation'; - -export default function AssertExpectation(message, testAssert) { - MethodCallExpectation.call(this, Ember, 'assert', testAssert); - this.expectedMessage = message; - this.testAssert = testAssert; -} - -AssertExpectation.Error = function() {}; -AssertExpectation.prototype = Object.create(MethodCallExpectation.prototype); -AssertExpectation.prototype.handleCall = function(message, test) { - this.sawCall = true; - if (test) { return; } // Only get message for failures - this.actualMessage = message; - // Halt execution - throw new AssertExpectation.Error(); -}; -AssertExpectation.prototype.assert = function(fn) { - try { - this.runWithStub(fn); - } catch (e) { - if (!(e instanceof AssertExpectation.Error)) { - throw e; - } - } - - // Run assertions in an order that is useful when debugging a test failure. - // - let assert = this.testAssert; - if (!this.sawCall) { - assert.ok(false, "Expected Ember.assert to be called (Not called with any value)."); - } else if (!this.actualMessage) { - assert.ok(false, 'Expected a failing Ember.assert (Ember.assert called, but without a failing test).'); - } else { - if (this.expectedMessage) { - if (this.expectedMessage instanceof RegExp) { - assert.ok(this.expectedMessage.test(this.actualMessage), "Expected failing Ember.assert: '" + this.expectedMessage + "', but got '" + this.actualMessage + "'."); - } else { - assert.equal(this.actualMessage, this.expectedMessage, "Expected failing Ember.assert: '" + this.expectedMessage + "', but got '" + this.actualMessage + "'."); - } - } else { - // Positive assertion that assert was called - assert.ok(true, 'Expected a failing Ember.assert.'); - } - } -}; - diff --git a/tests/helpers/ember-assertions/deprecations.js b/tests/helpers/ember-assertions/deprecations.js deleted file mode 100644 index 88884daff4a..00000000000 --- a/tests/helpers/ember-assertions/deprecations.js +++ /dev/null @@ -1,21 +0,0 @@ -import Ember from 'ember'; - -const deprecations = { - NONE: 99, // 99 problems and a deprecation ain't one - expecteds: null, - actuals: null, - stubEmber() { - if (!deprecations.originalEmberDeprecate && Ember.deprecate !== deprecations.originalEmberDeprecate) { - deprecations.originalEmberDeprecate = Ember.deprecate; - } - Ember.deprecate = function(msg, test) { - deprecations.actuals = deprecations.actuals || []; - deprecations.actuals.push([msg, test]); - }; - }, - restoreEmber() { - Ember.deprecate = deprecations.originalEmberDeprecate; - } -}; - -export default deprecations; diff --git a/tests/helpers/ember-assertions/method-call-expectation.js b/tests/helpers/ember-assertions/method-call-expectation.js deleted file mode 100644 index 05f0d5178e3..00000000000 --- a/tests/helpers/ember-assertions/method-call-expectation.js +++ /dev/null @@ -1,36 +0,0 @@ -// A light class for stubbing -// -export default function MethodCallExpectation(target, property, testAssert) { - this.target = target; - this.property = property; - this.testAssert = testAssert; -} - -MethodCallExpectation.prototype = { - handleCall() { - this.sawCall = true; - return this.originalMethod.apply(this.target, arguments); - }, - stubMethod(fn) { - var context = this; - this.originalMethod = this.target[this.property]; - this.target[this.property] = function() { - return context.handleCall.apply(context, arguments); - }; - }, - restoreMethod() { - this.target[this.property] = this.originalMethod; - }, - runWithStub(fn) { - try { - this.stubMethod(); - fn(); - } finally { - this.restoreMethod(); - } - }, - assert(fn) { - this.runWithStub(); - this.testAssert.ok(this.sawCall, "Expected "+this.property+" to be called."); - } -}; diff --git a/tests/helpers/setup-ember-dev.js b/tests/helpers/setup-ember-dev.js new file mode 100644 index 00000000000..f9fd230501e --- /dev/null +++ b/tests/helpers/setup-ember-dev.js @@ -0,0 +1,54 @@ +/* globals QUnit */ +import Ember from 'ember'; +import EmberTestHelpers from "ember-dev/test-helper/index"; + +const AVAILABLE_ASSERTIONS = ['expectAssertion', 'expectDeprecation', 'expectNoDeprecation', 'expectWarning', 'expectNoWarning']; + +function getDebugFunction(name) { + return Ember[name]; +} + +function setDebugFunction(name, func) { + Ember[name] = func; +} + +var originalModule = QUnit.module; + +/** + * We patch QUnit.module here so we can setup and teardown the helpers from + * ember-dev before every test. + * + * Creating the helpers within QUnit.testStart and checking for the assertions + * in QUnit.testDone doesn't work, as failed assertions in QUnit.testDone won't + * make the corresponding test fail. + */ +QUnit.module = function(name, options = {}) { + var testHelpers = new EmberTestHelpers({ + Ember, + getDebugFunction, + setDebugFunction + }); + + var originalBeforeEach = options.beforeEach || function() { }; + var originalAfterEach = options.afterEach || function() { }; + + options.beforeEach = function(assert) { + testHelpers.reset(); + testHelpers.inject(); + + AVAILABLE_ASSERTIONS.forEach((name) => assert[name] = window[name] ); + + originalBeforeEach.apply(this, arguments); + }; + + options.afterEach = function(assert) { + originalAfterEach.apply(this, arguments); + + testHelpers.assert(); + testHelpers.restore(); + + AVAILABLE_ASSERTIONS.forEach((name) => assert[name] = null ); + }; + + return originalModule(name, options); +}; diff --git a/tests/test-helper.js b/tests/test-helper.js index 902dbaa3d22..af021cf0714 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -1,3 +1,4 @@ +import 'dummy/tests/helpers/setup-ember-dev'; import resolver from './helpers/resolver'; import { setResolver @@ -13,11 +14,9 @@ import { warns, noWarns } from 'dummy/tests/helpers/warns'; -import addEmberAssertions from 'dummy/tests/helpers/ember-assertions'; import Ember from 'ember'; import './ember-data-initializers'; - setResolver(resolver); const { assert } = QUnit; @@ -69,7 +68,5 @@ assert.without = function(array, item) { this.ok(array.indexOf(item) === -1, `array doesn't contain ${item}`); }; -addEmberAssertions(assert); - QUnit.config.testTimeout = 2000; QUnit.config.urlConfig.push({ id: 'enableoptionalfeatures', label: "Enable Opt Features" }); From 2567ccf60223fba7a8780b3f60e4e5bf525df30f Mon Sep 17 00:00:00 2001 From: pangratz Date: Fri, 8 Jan 2016 22:54:52 +0100 Subject: [PATCH 1343/2527] Re-use expectWarning and expectNoWarning test helpers from ember-dev --- tests/helpers/warns.js | 34 ------------------- .../integration/adapter/rest-adapter-test.js | 2 +- tests/integration/inverse-test.js | 2 +- .../embedded-records-mixin-test.js | 2 +- .../serializers/json-api-serializer-test.js | 2 +- .../serializers/rest-serializer-test.js | 8 ++--- tests/test-helper.js | 6 ---- .../model/relationships/belongs-to-test.js | 4 +-- tests/unit/store/adapter-interop-test.js | 4 +-- tests/unit/store/push-test.js | 6 ++-- 10 files changed, 15 insertions(+), 55 deletions(-) delete mode 100644 tests/helpers/warns.js diff --git a/tests/helpers/warns.js b/tests/helpers/warns.js deleted file mode 100644 index 79a61b1ee95..00000000000 --- a/tests/helpers/warns.js +++ /dev/null @@ -1,34 +0,0 @@ -import Ember from 'ember'; - -export function warns(callback, regex) { - var warnWasCalled = false; - var oldWarn = Ember.warn; - Ember.warn = (message, test) => { - if (!test) { - warnWasCalled = true; - if (regex) { - this.ok(regex.test(message), 'the call to Ember.warn got an unexpected message: ' + message); - } - } - }; - try { - callback(); - this.ok(warnWasCalled, 'expected Ember.warn to warn, but was not called'); - } finally { - Ember.warn = oldWarn; - } -} - -export function noWarns(callback) { - var oldWarn = Ember.warn; - var warnWasCalled = false; - Ember.warn = function Ember_noWarn(message, test) { - warnWasCalled = !test; - }; - try { - callback(); - } finally { - this.ok(!warnWasCalled, 'Ember.warn warned when it should not have warned'); - Ember.warn = oldWarn; - } -} diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index c1fb7576da4..3103a6adfc3 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1889,7 +1889,7 @@ test('coalesceFindRequests assert.warns if the expected records are not returned ajaxResponse({ comments: [{ id: 1 }] }); var post; - assert.warns(function() { + assert.expectWarning(function() { run(function() { store.push({ data: { diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index dab9266bce3..cd2b1a78411 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -128,7 +128,7 @@ test("Caches findInverseFor return value", function(assert) { test("Errors out if you do not define an inverse for a reflexive relationship", function(assert) { //Maybe store is evaluated lazily, so we need this :( - assert.warns(function() { + assert.expectWarning(function() { var reflexiveModel; run(function() { store.push({ diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index 4a7691cac1a..e6a9d98a242 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -959,7 +959,7 @@ test("serialize with embedded objects (unknown hasMany relationship)", function( })); var serializer, json; - assert.warns(function() { + assert.expectWarning(function() { run(function() { serializer = env.store.serializerFor("home-planet"); json = serializer.serialize(league._createSnapshot()); diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index dea465a6b63..42ed40cdf32 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -127,7 +127,7 @@ test('Warns when normalizing an unknown type', function(assert) { } }; - assert.warns(function() { + assert.expectWarning(function() { run(function() { env.store.serializerFor('user').normalizeResponse(env.store, User, documentHash, '1', 'findRecord'); }); diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 0cd724b24d9..1133c152d38 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -155,7 +155,7 @@ test("normalizeResponse warning with custom modelNameFromPayloadKey", function(a home_planet: { id: "1", name: "Umber", superVillains: [1] } }; - assert.warns(Ember.run.bind(null, function() { + assert.expectWarning(Ember.run.bind(null, function() { run(function() { env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, '1', 'findRecord'); }); @@ -167,7 +167,7 @@ test("normalizeResponse warning with custom modelNameFromPayloadKey", function(a home_planet: { id: "1", name: "Umber", superVillains: [1] } }; - assert.noWarns(function() { + assert.expectNoWarning(function() { run(function() { homePlanet = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, 1, 'findRecord'); @@ -189,7 +189,7 @@ test("normalizeResponse warning with custom modelNameFromPayloadKey", function(a home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] }; - assert.warns(function() { + assert.expectWarning(function() { env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); }, /Encountered "home_planets" in payload, but no model was found for model name "garbage"/); @@ -202,7 +202,7 @@ test("normalizeResponse warning with custom modelNameFromPayloadKey", function(a home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] }; - assert.noWarns(function() { + assert.expectNoWarning(function() { run(function() { homePlanets = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); }); diff --git a/tests/test-helper.js b/tests/test-helper.js index af021cf0714..ffabc8b27f1 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -10,10 +10,6 @@ import { asyncEqual, invokeAsync } from 'dummy/tests/helpers/async'; -import { - warns, - noWarns -} from 'dummy/tests/helpers/warns'; import Ember from 'ember'; import './ember-data-initializers'; @@ -57,8 +53,6 @@ assert.assertClean = function(promise) { return record; })); }; -assert.warns = warns; -assert.noWarns = noWarns; assert.contains = function(array, item) { this.ok(array.indexOf(item) !== -1, `array contains ${item}`); diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index 79969d0c212..8e71da3fa46 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -418,7 +418,7 @@ test("belongsTo gives a warning when provided with a serialize option", function run(function() { store.findRecord('person', 1).then(assert.wait(function(person) { - assert.warns(function() { + assert.expectWarning(function() { get(person, 'hobby'); }, /You provided a serialize option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.Serializer and it's implementations/); })); @@ -472,7 +472,7 @@ test("belongsTo gives a warning when provided with an embedded option", function run(function() { store.findRecord('person', 1).then(assert.wait(function(person) { - assert.warns(function() { + assert.expectWarning(function() { get(person, 'hobby'); }, /You provided an embedded option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin/); })); diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index c665d281c7c..24eff8b82b5 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -834,7 +834,7 @@ test("the promise returned by `scheduleFetch`, when it rejects, does not depend }); test("store.fetchRecord reject records that were not found, even when those requests were coalesced with records that were found", function(assert) { - assert.expect(4); + assert.expect(3); var Person = DS.Model.extend(); @@ -858,7 +858,7 @@ test("store.fetchRecord reject records that were not found, even when those requ }); let done = assert.async(); - assert.warns(function() { + assert.expectWarning(function() { run(function () { var davidPromise = store.findRecord('test', 'david'); var igorPromise = store.findRecord('test', 'igor'); diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index fa9ae404338..4abd31518f9 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -494,7 +494,7 @@ test('Calling push with a link for a non async relationship should warn', functi phoneNumbers: hasMany('phone-number', { async: false }) }); - assert.warns(function() { + assert.expectWarning(function() { run(function() { store.push(store.normalize('person', { id: '1', @@ -631,7 +631,7 @@ test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown keys", f var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; try { Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; - assert.warns(function() { + assert.expectWarning(function() { store.push({ data: { type: 'person', @@ -651,7 +651,7 @@ test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown keys", f }); test("Calling push with unknown keys should not warn by default", function(assert) { - assert.noWarns(function() { + assert.expectNoWarning(function() { run(function() { store.push({ data: { From 04156126842d1d0122a2964520c71b00fde90a86 Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 4 Jan 2016 15:31:19 +0100 Subject: [PATCH 1344/2527] Change test for asserting that model is available Currently `this._hasModelFor` returns the specific model, though - as the name implies - a boolean should be returned. --- Context: this change is especially needed so the assertion helper from ember-dev works correctly: this helper uses the checkTest function in test-helper/utils.js https://git.io/vuZK3. If a class is passed to the assertion, like in `Ember.assert("should exists", MyEmberClass)`, it is treated as a function and invoked within `checkTest`. This throws an error since ember classes are not function which can be invoked. --- addon/-private/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b8049519968..60e3bfc3970 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1733,7 +1733,7 @@ Store = Service.extend({ }, _hasModelFor(type) { - return getOwner(this)._lookupFactory(`model:${type}`); + return !!getOwner(this)._lookupFactory(`model:${type}`); }, _pushInternalModel(data) { From 5096975685c3e444c0f36f0e12c186ec24f1cc45 Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 13 Jan 2016 22:13:35 +0100 Subject: [PATCH 1345/2527] Fix failing test by wrapping in Ember.run Getting an async`hasMany` relationship triggers a run-loop, so this needs to be wrapped inside `Ember.run`. --- tests/integration/adapter/store-adapter-test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index a5435cd9acb..227518a7043 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -1036,7 +1036,9 @@ test("async hasMany always returns a promise", function(assert) { tom = store.createRecord('person', { name: "Tom Dale" }); }); - assert.ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise before save"); + run(function() { + assert.ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise before save"); + }); run(function() { tom.save().then(assert.wait(function() { From 31d793ca051420b54d3abe3d9039dffad9252d43 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Fri, 15 Jan 2016 00:37:50 +0900 Subject: [PATCH 1346/2527] Use `Ember.merge` instead of ember-data's shim This shim was introduced to compatible with old Ember that couldn't merge object that has no `hasOwnProperty` method. https://github.com/emberjs/data/pull/2506 However current Ember Data supports Ember >= 2 (it can merge objects safely since this change. 751f76dac ) https://github.com/emberjs/ember.js/pull/5645 So now this shim is unnecessary. --- addon/-private/system/merge.js | 16 ---------------- addon/-private/system/model/internal-model.js | 2 +- 2 files changed, 1 insertion(+), 17 deletions(-) delete mode 100644 addon/-private/system/merge.js diff --git a/addon/-private/system/merge.js b/addon/-private/system/merge.js deleted file mode 100644 index fd95d74500a..00000000000 --- a/addon/-private/system/merge.js +++ /dev/null @@ -1,16 +0,0 @@ -export default function merge(original, updates) { - if (!updates || typeof updates !== 'object') { - return original; - } - - var props = Object.keys(updates); - var prop; - var length = props.length; - - for (var i = 0; i < length; i++) { - prop = props[i]; - original[prop] = updates[prop]; - } - - return original; -} diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 1235f805fc1..6d0378c550c 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -1,6 +1,5 @@ import Ember from 'ember'; import { assert } from "ember-data/-private/debug"; -import merge from "ember-data/-private/system/merge"; import RootState from "ember-data/-private/system/model/states"; import Relationships from "ember-data/-private/system/relationships/state/create"; import Snapshot from "ember-data/-private/system/snapshot"; @@ -21,6 +20,7 @@ var Promise = Ember.RSVP.Promise; var get = Ember.get; var set = Ember.set; var copy = Ember.copy; +var merge = Ember.merge; var _extractPivotNameCache = new EmptyObject(); var _splitOnDotCache = new EmptyObject(); From daab7b7f7a5adc87e60d8888df6b4897d3330da0 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 14 Jan 2016 17:07:55 +0100 Subject: [PATCH 1347/2527] [CLEANUP] remove unused config/ember-defeatureify.js Since we are using `babel-plugin-feature-flags` and `babel-plugin-filter-imports`, ember defeatureify is no more needed... :boom: --- config/ember-defeatureify.js | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 config/ember-defeatureify.js diff --git a/config/ember-defeatureify.js b/config/ember-defeatureify.js deleted file mode 100644 index 25b3f8baa66..00000000000 --- a/config/ember-defeatureify.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - options: { - debugStatements: [ - "Ember.warn", - "emberWarn", - "Ember.assert", - "emberAssert", - "Ember.deprecate", - "emberDeprecate", - "Ember.debug", - "emberDebug", - "Ember.Logger.info", - "Ember.runInDebug" - ] - }, - enableStripDebug: true -}; From 935d5f18629fb183ef1da58d499bf1886a11b25b Mon Sep 17 00:00:00 2001 From: Dan McClain Date: Thu, 14 Jan 2016 07:42:03 -0500 Subject: [PATCH 1348/2527] [CLEANUP beta] Change the way metadata in response is stored on record array The previous implementation of inserting metadata from an ajax response onto a record array used the store as temporary storage for the metadata via `store._metadataFor` and `store._setMetadataFor`. Although rare, this could store the wrong value on the record array due to a race condition, as the metadata was stored based on the query's model's name. This moves the storing of metadata to `AdapterPopulatedRecordArray.loadRecords` since, at the time that that method is called, the payload is present, so we don't have to use `store.{_setMetadataFor,_metadataFor}`. `store._metadataFor` was only used in `AdapterPopulatedRecordArray.loadRecords`, so it is no longer needed with this new implementation. --- .../adapter-populated-record-array.js | 10 +-- addon/-private/system/store.js | 24 ------ addon/-private/system/store/finders.js | 6 +- .../system/store/serializer-response.js | 4 - .../adapter-populated-record-array-test.js | 81 ++++++++++++++----- 5 files changed, 65 insertions(+), 60 deletions(-) diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index ae923c46e36..24f09dc8804 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -29,20 +29,16 @@ export default RecordArray.extend({ /** @method loadRecords @param {Array} records + @param {Object} payload normalized payload @private */ - loadRecords(records) { - var store = get(this, 'store'); - var type = get(this, 'type'); - var modelName = type.modelName; - var meta = store._metadataFor(modelName); - + loadRecords(records, payload) { //TODO Optimize var internalModels = Ember.A(records).mapBy('_internalModel'); this.setProperties({ content: Ember.A(internalModels), isLoaded: true, - meta: cloneNull(meta) + meta: cloneNull(payload.meta) }); internalModels.forEach((record) => { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b8049519968..c344ba8d14f 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1253,30 +1253,6 @@ Store = Service.extend({ return this.hasRecordForId(modelName, id); }, - /** - @method _metadataFor - @param {String} modelName - @return {object} - @private - */ - _metadataFor(modelName) { - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - var typeClass = this.modelFor(modelName); - return this.typeMapFor(typeClass).metadata; - }, - - /** - @method _setMetadataFor - @param {String} modelName - @param {Object} metadata metadata to set - @private - */ - _setMetadataFor(modelName, metadata) { - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - var typeClass = this.modelFor(modelName); - Ember.merge(this.typeMapFor(typeClass).metadata, metadata); - }, - // ............ // . UPDATING . // ............ diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 5c690243753..e80e5a216d6 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -168,15 +168,15 @@ export function _query(adapter, store, typeClass, query, recordArray) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - var records; + var records, payload; store._adapterRun(function() { - var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'query'); + payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'query'); //TODO Optimize records = store.push(payload); }); assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Ember.isArray(records)); - recordArray.loadRecords(records); + recordArray.loadRecords(records, payload); return recordArray; }, null, "DS: Extract payload of query " + typeClass); diff --git a/addon/-private/system/store/serializer-response.js b/addon/-private/system/store/serializer-response.js index ab05296b3c2..9679e4e5903 100644 --- a/addon/-private/system/store/serializer-response.js +++ b/addon/-private/system/store/serializer-response.js @@ -79,10 +79,6 @@ export function normalizeResponseHelper(serializer, store, modelClass, payload, validationErrors = validateDocumentStructure(normalizedResponse); }); assert(`normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join('\n\t* ')}`, Ember.isEmpty(validationErrors)); - // TODO: Remove after metadata refactor - if (normalizedResponse.meta) { - store._setMetadataFor(modelClass.modelName, normalizedResponse.meta); - } return normalizedResponse; } diff --git a/tests/unit/adapter-populated-record-array-test.js b/tests/unit/adapter-populated-record-array-test.js index 6616a54085d..15c6ef56408 100644 --- a/tests/unit/adapter-populated-record-array-test.js +++ b/tests/unit/adapter-populated-record-array-test.js @@ -30,30 +30,31 @@ module("unit/adapter_populated_record_array - DS.AdapterPopulatedRecordArray", { test("when a record is deleted in an adapter populated record array, it should be removed", function(assert) { var recordArray = store.recordArrayManager .createAdapterPopulatedRecordArray(store.modelFor('person'), null); + var payload = { + data: [{ + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale' + } + }, { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz' + } + }, { + type: 'person', + id: '3', + attributes: { + name: 'Scumbag Bryn' + } + }] + }; run(function() { - var records = store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Scumbag Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Scumbag Katz' - } - }, { - type: 'person', - id: '3', - attributes: { - name: 'Scumbag Bryn' - } - }] - }); - recordArray.loadRecords(records); + var records = store.push(payload); + recordArray.loadRecords(records, payload); }); assert.equal(recordArray.get('length'), 3, "expected recordArray to contain exactly 3 records"); @@ -65,6 +66,42 @@ test("when a record is deleted in an adapter populated record array, it should b assert.equal(recordArray.get('length'), 2, "expected recordArray to contain exactly 2 records"); }); +test("stores the metadata off the payload", function(assert) { + var recordArray = store.recordArrayManager + .createAdapterPopulatedRecordArray(store.modelFor('person'), null); + var payload = { + data: [{ + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale' + } + }, { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz' + } + }, { + type: 'person', + id: '3', + attributes: { + name: 'Scumbag Bryn' + } + }], + meta: { + foo: 'bar' + } + }; + + run(function() { + var records = store.push(payload); + recordArray.loadRecords(records, payload); + }); + + assert.equal(recordArray.get('meta.foo'), 'bar', 'expected meta.foo to be bar from payload'); +}); + test('recordArray.replace() throws error', function(assert) { var recordArray = store.recordArrayManager .createAdapterPopulatedRecordArray(Person, null); From 67c4bc8964ae0c146589656d98646b57fb2cc89f Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Thu, 14 Jan 2016 23:52:15 -0500 Subject: [PATCH 1349/2527] [cleanup] Remove unnecessary inline JSHint config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ember is imported below so we don’t need the global :smile: - The `eqnull:true` rule was originally added for https://github.com/emberjs/data/commit/beb2f26d653a9df0a746b1d90a4aee44c 050fd7b but was later added to the `.jshintrc` in https://github.com/emberjs/data/commit/caa2753d9cb6cdf7661a0c663cdacad23 3ed8fd7?diff=unified --- addon/-private/system/store.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 60e3bfc3970..6ece71e45e6 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1,6 +1,3 @@ -/*globals Ember*/ -/*jshint eqnull:true*/ - /** @module ember-data */ From bcab3b554f3fc06e8ae402923d0a1189547597ca Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Wed, 13 Jan 2016 00:18:06 -0500 Subject: [PATCH 1350/2527] Update blueprints to import modules directly - Import JSONAPIAdapter module directly in blueprint - Import JSONAPISerializer module directly in blueprint - Import Transform module directly in blueprint - Import attr module directly in model blueprints when needed - Import belongsTo and hasMany modules directly in blueprints when needed --- blueprints/adapter/index.js | 4 +- .../model/files/__root__/__path__/__name__.js | 4 +- blueprints/model/index.js | 30 ++++++- .../files/__root__/__path__/__name__.js | 4 +- .../files/__root__/__path__/__name__.js | 4 +- node-tests/blueprints/adapter-test.js | 4 +- node-tests/blueprints/model-test.js | 82 ++++++++++++++----- node-tests/blueprints/serializer-test.js | 4 +- node-tests/blueprints/transform-test.js | 4 +- 9 files changed, 102 insertions(+), 38 deletions(-) diff --git a/blueprints/adapter/index.js b/blueprints/adapter/index.js index 64dbb294461..b6a3416e381 100644 --- a/blueprints/adapter/index.js +++ b/blueprints/adapter/index.js @@ -13,8 +13,8 @@ module.exports = { locals: function(options) { var adapterName = options.entity.name; - var baseClass = 'DS.JSONAPIAdapter'; - var importStatement = 'import DS from \'ember-data\';'; + var baseClass = 'JSONAPIAdapter'; + var importStatement = 'import JSONAPIAdapter from \'ember-data/adapters/json-api\';'; var isAddon = options.inRepoAddon || options.project.isEmberCLIAddon(); var relativePath = pathUtil.getRelativePath(options.entity.name); diff --git a/blueprints/model/files/__root__/__path__/__name__.js b/blueprints/model/files/__root__/__path__/__name__.js index c1b8b8fac45..81e0f12b75a 100644 --- a/blueprints/model/files/__root__/__path__/__name__.js +++ b/blueprints/model/files/__root__/__path__/__name__.js @@ -1,5 +1,5 @@ -import DS from 'ember-data'; +<%= importStatements %> -export default DS.Model.extend({ +export default Model.extend({ <%= attrs %> }); diff --git a/blueprints/model/index.js b/blueprints/model/index.js index 1787ad788a1..a16c859c548 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -16,6 +16,10 @@ module.exports = { var attrs = []; var needs = []; var entityOptions = options.entity.options; + var importStatements = ['import Model from \'ember-data/model\';']; + var shouldImportAttr = false; + var shouldImportBelongsTo = false; + var shouldImportHasMany = false; for (var name in entityOptions) { var type = entityOptions[name] || ''; @@ -35,26 +39,44 @@ module.exports = { var camelizedNamePlural = inflection.pluralize(camelizedName); attr = dsAttr(dasherizedForeignModelSingular, dasherizedType); attrs.push(camelizedNamePlural + ': ' + attr); + shouldImportHasMany = true; } else if (/belongs-to/.test(dasherizedType)) { attr = dsAttr(dasherizedForeignModel, dasherizedType); attrs.push(camelizedName + ': ' + attr); + shouldImportBelongsTo = true; } else { attr = dsAttr(dasherizedName, dasherizedType); attrs.push(camelizedName + ': ' + attr); + shouldImportAttr = true; } if (/has-many|belongs-to/.test(dasherizedType)) { needs.push("'model:" + dasherizedForeignModelSingular + "'"); } } + var needsDeduplicated = needs.filter(function(need, i) { return needs.indexOf(need) === i; }); + if (shouldImportAttr) { + importStatements.push('import attr from \'ember-data/attr\';'); + } + + if (shouldImportBelongsTo && shouldImportHasMany) { + importStatements.push('import { belongsTo, hasMany } from \'ember-data/relationships\';'); + } else if (shouldImportBelongsTo) { + importStatements.push('import { belongsTo } from \'ember-data/relationships\';'); + } else if (shouldImportHasMany) { + importStatements.push('import { hasMany } from \'ember-data/relationships\';'); + } + + importStatements = importStatements.join(EOL); attrs = attrs.join(',' + EOL + ' '); needs = ' needs: [' + needsDeduplicated.join(', ') + ']'; return { + importStatements: importStatements, attrs: attrs, needs: needs }; @@ -64,14 +86,14 @@ module.exports = { function dsAttr(name, type) { switch (type) { case 'belongs-to': - return 'DS.belongsTo(\'' + name + '\')'; + return 'belongsTo(\'' + name + '\')'; case 'has-many': - return 'DS.hasMany(\'' + name + '\')'; + return 'hasMany(\'' + name + '\')'; case '': //"If you don't specify the type of the attribute, it will be whatever was provided by the server" //http://emberjs.com/guides/models/defining-models/ - return 'DS.attr()'; + return 'attr()'; default: - return 'DS.attr(\'' + type + '\')'; + return 'attr(\'' + type + '\')'; } } diff --git a/blueprints/serializer/files/__root__/__path__/__name__.js b/blueprints/serializer/files/__root__/__path__/__name__.js index 74689dcb59a..4678cc2c37a 100644 --- a/blueprints/serializer/files/__root__/__path__/__name__.js +++ b/blueprints/serializer/files/__root__/__path__/__name__.js @@ -1,4 +1,4 @@ -import DS from 'ember-data'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; -export default DS.JSONAPISerializer.extend({ +export default JSONAPISerializer.extend({ }); diff --git a/blueprints/transform/files/__root__/__path__/__name__.js b/blueprints/transform/files/__root__/__path__/__name__.js index 722408742d7..1d048927535 100644 --- a/blueprints/transform/files/__root__/__path__/__name__.js +++ b/blueprints/transform/files/__root__/__path__/__name__.js @@ -1,6 +1,6 @@ -import DS from 'ember-data'; +import Transform from 'ember-data/transform'; -export default DS.Transform.extend({ +export default Transform.extend({ deserialize(serialized) { return serialized; }, diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 276e6a9c05a..17f78384bd0 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -60,8 +60,8 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { { file: 'app/adapters/application.js', contains: [ - 'import DS from \'ember-data\';', - 'export default DS.JSONAPIAdapter.extend({' + 'import JSONAPIAdapter from \'ember-data/adapters/json-api\';', + 'export default JSONAPIAdapter.extend({' ] }, { diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index 64e616baaa4..d86dbd11599 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -11,8 +11,14 @@ describe('Acceptance: generate and destroy model blueprints', function() { { file: 'app/models/foo.js', contains: [ - 'import DS from \'ember-data\';', - 'export default DS.Model.extend(' + 'import Model from \'ember-data/model\';', + 'export default Model.extend(' + ], + doesNotContain: [ + 'import attr from \'ember-data/attr\';', + 'import { belongsTo } from \'ember-data/relationships\';', + 'import { hasMany } from \'ember-data/relationships\';', + 'import { belongsTo, hasMany } from \'ember-data/relationships\';' ] }, { @@ -42,16 +48,22 @@ describe('Acceptance: generate and destroy model blueprints', function() { { file: 'app/models/foo.js', contains: [ - 'import DS from \'ember-data\';', - 'export default DS.Model.extend(', - 'misc: DS.attr()', - 'skills: DS.attr(\'array\')', - 'isActive: DS.attr(\'boolean\')', - 'birthday: DS.attr(\'date\')', - 'someObject: DS.attr(\'object\')', - 'age: DS.attr(\'number\')', - 'name: DS.attr(\'string\')', - 'customAttr: DS.attr(\'custom-transform\')' + 'import Model from \'ember-data/model\';', + 'import attr from \'ember-data/attr\';', + 'export default Model.extend(', + 'misc: attr()', + 'skills: attr(\'array\')', + 'isActive: attr(\'boolean\')', + 'birthday: attr(\'date\')', + 'someObject: attr(\'object\')', + 'age: attr(\'number\')', + 'name: attr(\'string\')', + 'customAttr: attr(\'custom-transform\')' + ], + doesNotContain: [ + 'import { belongsTo } from \'ember-data/relationships\';', + 'import { hasMany } from \'ember-data/relationships\';', + 'import { belongsTo, hasMany } from \'ember-data/relationships\';' ] }, { @@ -70,10 +82,16 @@ describe('Acceptance: generate and destroy model blueprints', function() { { file: 'app/models/comment.js', contains: [ - 'import DS from \'ember-data\';', - 'export default DS.Model.extend(', - 'post: DS.belongsTo(\'post\')', - 'author: DS.belongsTo(\'user\')', + 'import Model from \'ember-data/model\';', + 'import { belongsTo } from \'ember-data/relationships\';', + 'export default Model.extend(', + 'post: belongsTo(\'post\')', + 'author: belongsTo(\'user\')', + ], + doesNotContain: [ + 'import attr from \'ember-data/attr\';', + 'import { hasMany } from \'ember-data/relationships\';', + 'import { belongsTo, hasMany } from \'ember-data/relationships\';' ] }, { @@ -93,10 +111,16 @@ describe('Acceptance: generate and destroy model blueprints', function() { { file: 'app/models/post.js', contains: [ - 'import DS from \'ember-data\';', - 'export default DS.Model.extend(', - 'comments: DS.hasMany(\'comment\')', - 'otherComments: DS.hasMany(\'comment\')', + 'import Model from \'ember-data/model\';', + 'import { hasMany } from \'ember-data/relationships\';', + 'export default Model.extend(', + 'comments: hasMany(\'comment\')', + 'otherComments: hasMany(\'comment\')', + ], + doesNotContain: [ + 'import attr from \'ember-data/attr\';', + 'import { belongsTo } from \'ember-data/relationships\';', + 'import { belongsTo, hasMany } from \'ember-data/relationships\';' ] }, { @@ -110,6 +134,24 @@ describe('Acceptance: generate and destroy model blueprints', function() { }); }); + it('model with belongsTo and hasMany has both imports', function() { + return generateAndDestroy(['model', 'post', 'comments:has-many', 'user:belongs-to'], { + files: [ + { + file: 'app/models/post.js', + contains: [ + 'import { belongsTo, hasMany } from \'ember-data/relationships\';' + ], + doesNotContain: [ + 'import attr from \'ember-data/attr\';', + 'import { belongsTo } from \'ember-data/relationships\';', + 'import { hasMany } from \'ember-data/relationships\';' + ] + } + ] + }); + }); + it('model-test', function() { return generateAndDestroy(['model-test', 'foo'], { files: [ diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index a3d8cd199c1..ac7b60f9a75 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -11,8 +11,8 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { { file: 'app/serializers/foo.js', contains: [ - 'import DS from \'ember-data\';', - 'export default DS.JSONAPISerializer.extend(' + 'import JSONAPISerializer from \'ember-data/serializers/json-api\';', + 'export default JSONAPISerializer.extend(' ] }, { diff --git a/node-tests/blueprints/transform-test.js b/node-tests/blueprints/transform-test.js index 07768e44c6f..ebb88e0d26d 100644 --- a/node-tests/blueprints/transform-test.js +++ b/node-tests/blueprints/transform-test.js @@ -11,8 +11,8 @@ describe('Acceptance: generate and destroy transform blueprints', function() { { file: 'app/transforms/foo.js', contains: [ - 'import DS from \'ember-data\';', - 'export default DS.Transform.extend(', + 'import Transform from \'ember-data/transform\';', + 'export default Transform.extend(', 'deserialize(serialized) {', 'serialize(deserialized) {' ] From 9b516d026f3568605f710b605d873b51b91a0127 Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 14 Jan 2016 19:36:45 -0500 Subject: [PATCH 1351/2527] Move the date import to where it is used intead of the root module --- addon/-private/transforms/date.js | 1 + addon/index.js | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/transforms/date.js b/addon/-private/transforms/date.js index 60944b6b95d..66ac73996e9 100644 --- a/addon/-private/transforms/date.js +++ b/addon/-private/transforms/date.js @@ -1,4 +1,5 @@ import Ember from 'ember'; +import "ember-data/-private/ext/date"; /** The `DS.DateTransform` class is used to serialize and deserialize diff --git a/addon/index.js b/addon/index.js index fd11ee95353..7135ca97846 100644 --- a/addon/index.js +++ b/addon/index.js @@ -19,7 +19,6 @@ if (Ember.VERSION.match(/^1\.13\./)) { } import DS from "ember-data/-private/core"; -import "ember-data/-private/ext/date"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; From 40a0534bc685b245c0c7aa10e09c48ed17ff1ce5 Mon Sep 17 00:00:00 2001 From: pangratz Date: Fri, 15 Jan 2016 17:18:51 +0100 Subject: [PATCH 1352/2527] [skip ci] Update codeclimate.yml - use correct path to tests (this has changed since being an addon) - add codeclimate badge to README --- .codeclimate.yml | 3 +-- README.md | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index 84d319bb281..71daed66b79 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -2,5 +2,4 @@ languages: JavaScript: true exclude_paths: - - "packages/ember/tests/*" - - "packages/ember-data/tests/*" + - "tests/*" diff --git a/README.md b/README.md index dc298b2b057..3d321b591ef 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Ember Data [![Build Status](https://secure.travis-ci.org/emberjs/data.svg?branch=master)](http://travis-ci.org/emberjs/data) +## Ember Data [![Build Status](https://secure.travis-ci.org/emberjs/data.svg?branch=master)](http://travis-ci.org/emberjs/data) [![Code Climate](https://codeclimate.com/github/emberjs/data/badges/gpa.svg)](https://codeclimate.com/github/emberjs/data) Ember Data is a library for robustly managing model data in your Ember.js applications. From 9ab5c5e1501b66fa597a095f050dbd63f7e8df65 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sat, 16 Jan 2016 12:44:34 +0100 Subject: [PATCH 1353/2527] [FEATURE ds-transform-pass-options] pass options to DS.Transform This feature passes the options hash defined for an attribute to the `serialize` and `deserialize` methods of `DS.Transform`: ```js // app/models/post.js export default Model.extend({ text: DS.attr('text'), otherText: DS.attr('text', { lowercaseInput: true, uppercaseOutput: true }) }); // app/transforms/text.js export default DS.Tranform.extend({ serialize(value, options) { if (options.uppercaseOutput) { return value.toUpperCase(); } return value; }, deserialize(value, options) { if (options.lowercaseInput) { return value.toLowerCase(); } return value; } }); ``` --- FEATURES.md | 5 ++ addon/attr.js | 32 ++++++++++++ addon/serializers/json.js | 20 +++++++- config/features.json | 3 +- .../serializers/json-serializer-test.js | 49 +++++++++++++++++++ 5 files changed, 106 insertions(+), 3 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index f3abee8ae9b..a3f2677c738 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -20,3 +20,8 @@ entry in `config/features.json`. - `ds-references` Adds references as described in [RFC 57](https://github.com/emberjs/rfcs/pull/57) + +- `ds-transform-pass-options` + + Pass options specified for a `DS.attr` to the `DS.Tranform`'s `serialize` and + `deserialize` methods (described in [RFC 1](https://github.com/emberjs/rfcs/pull/1)) diff --git a/addon/attr.js b/addon/attr.js index 9a101508a16..4c804f38397 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -349,3 +349,35 @@ export default function attr(type, options) { } }).meta(meta); } + +// TODO add to documentation of `attr` function above, once this feature is added +// /** +// * The `options` hash is passed as second argument to a transforms' +// * `serialize` and `deserialize` method. This allows to configure a +// * transformation and adapt the corresponding value, based on the config: +// * +// * ```app/models/post.js +// * export default DS.Model.extend({ +// * text: DS.attr('text', { +// * uppercase: true +// * }) +// * }); +// * ``` +// * +// * ```app/transforms/text.js +// * export default DS.Transform.extend({ +// * serialize: function(value, options) { +// * if (options.uppercase) { +// * return value.toUpperCase(); +// * } +// * +// * return value; +// * }, +// * +// * deserialize: function(value) { +// * return value; +// * } +// * }) +// * ``` +// * +// */ diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 0eb2389897a..330c7b90930 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -11,6 +11,8 @@ import { import { errorsArrayToHash } from "ember-data/-private/adapters/errors"; +import isEnabled from 'ember-data/-private/features'; + var get = Ember.get; var isNone = Ember.isNone; var merge = Ember.merge; @@ -185,11 +187,21 @@ export default Serializer.extend({ @return {Object} data The transformed data object */ applyTransforms(typeClass, data) { + let attributes; + if (isEnabled('ds-transform-pass-options')) { + attributes = get(typeClass, 'attributes'); + } + typeClass.eachTransformedAttribute((key, typeClass) => { if (!data.hasOwnProperty(key)) { return; } var transform = this.transformFor(typeClass); - data[key] = transform.deserialize(data[key]); + if (isEnabled('ds-transform-pass-options')) { + var transformMeta = attributes.get(key); + data[key] = transform.deserialize(data[key], transformMeta.options); + } else { + data[key] = transform.deserialize(data[key]); + } }); return data; @@ -1074,7 +1086,11 @@ export default Serializer.extend({ var value = snapshot.attr(key); if (type) { var transform = this.transformFor(type); - value = transform.serialize(value); + if (isEnabled('ds-transform-pass-options')) { + value = transform.serialize(value, attribute.options); + } else { + value = transform.serialize(value); + } } // if provided, use the mapping provided by `attrs` in diff --git a/config/features.json b/config/features.json index 82108bcfad3..23d2aaf0f1b 100644 --- a/config/features.json +++ b/config/features.json @@ -1,4 +1,5 @@ { "ds-finder-include": null, - "ds-references": null + "ds-references": null, + "ds-transform-pass-options": null } diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index b926f828593..06546974ed7 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -5,6 +5,8 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; + var Post, post, Comment, comment, Favorite, favorite, env; var run = Ember.run; @@ -904,3 +906,50 @@ test('normalizeResponse ignores unmapped attributes', function(assert) { assert.equal(post.data.attributes.title, "Rails is omakase"); }); + +if (isEnabled('ds-transform-pass-options')) { + + test('options are passed to transform for serialization', function(assert) { + assert.expect(1); + + env.registry.register('transform:custom', DS.Transform.extend({ + serialize: function(deserialized, options) { + assert.deepEqual(options, { custom: 'config' }); + } + })); + + Post.reopen({ + custom: DS.attr('custom', { + custom: 'config' + }) + }); + + var post; + run(function() { + post = env.store.createRecord('post', { custom: 'value' }); + }); + + env.serializer.serialize(post._createSnapshot()); + }); + + test('options are passed to transform for normalization', function(assert) { + assert.expect(1); + + env.registry.register('transform:custom', DS.Transform.extend({ + deserialize: function(serialized, options) { + assert.deepEqual(options, { custom: 'config' }); + } + })); + + Post.reopen({ + custom: DS.attr('custom', { + custom: 'config' + }) + }); + + env.serializer.normalize(Post, { + custom: 'value' + }); + }); + +} From 08e4f12426812816cdb58ce3886c100555892d4e Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Mon, 18 Jan 2016 19:01:45 +0100 Subject: [PATCH 1354/2527] [BUFGIX release] Fix regression with missing initializers --- app/initializers/data-adapter.js | 14 ++++++++++++++ app/initializers/injectStore.js | 14 ++++++++++++++ app/initializers/store.js | 14 ++++++++++++++ app/initializers/transforms.js | 14 ++++++++++++++ 4 files changed, 56 insertions(+) create mode 100644 app/initializers/data-adapter.js create mode 100644 app/initializers/injectStore.js create mode 100644 app/initializers/store.js create mode 100644 app/initializers/transforms.js diff --git a/app/initializers/data-adapter.js b/app/initializers/data-adapter.js new file mode 100644 index 00000000000..3cc5b9ba27a --- /dev/null +++ b/app/initializers/data-adapter.js @@ -0,0 +1,14 @@ +import Ember from 'ember'; + +/* + This initializer is here to keep backwards compatibility with code depending + on the `data-adapter` initializer (before Ember Data was an addon). + + Should be removed for Ember Data 3.x +*/ + +export default { + name: 'data-adapter', + before: 'store', + initialize: Ember.K +}; diff --git a/app/initializers/injectStore.js b/app/initializers/injectStore.js new file mode 100644 index 00000000000..354080e6105 --- /dev/null +++ b/app/initializers/injectStore.js @@ -0,0 +1,14 @@ +import Ember from 'ember'; + +/* + This initializer is here to keep backwards compatibility with code depending + on the `injectStore` initializer (before Ember Data was an addon). + + Should be removed for Ember Data 3.x +*/ + +export default { + name: 'injectStore', + before: 'store', + initialize: Ember.K +}; diff --git a/app/initializers/store.js b/app/initializers/store.js new file mode 100644 index 00000000000..d98880c77ee --- /dev/null +++ b/app/initializers/store.js @@ -0,0 +1,14 @@ +import Ember from 'ember'; + +/* + This initializer is here to keep backwards compatibility with code depending + on the `store` initializer (before Ember Data was an addon). + + Should be removed for Ember Data 3.x +*/ + +export default { + name: 'store', + after: 'ember-data', + initialize: Ember.K +}; diff --git a/app/initializers/transforms.js b/app/initializers/transforms.js new file mode 100644 index 00000000000..c2fb02097cc --- /dev/null +++ b/app/initializers/transforms.js @@ -0,0 +1,14 @@ +import Ember from 'ember'; + +/* + This initializer is here to keep backwards compatibility with code depending + on the `transforms` initializer (before Ember Data was an addon). + + Should be removed for Ember Data 3.x +*/ + +export default { + name: 'transforms', + before: 'store', + initialize: Ember.K +}; From 616611272367bebf4477014002dddd41bcbbaed6 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 18 Jan 2016 14:04:59 -0500 Subject: [PATCH 1355/2527] Make yui doc generate links from the project root instead of the filesystem root --- lib/yuidoc.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/lib/yuidoc.js b/lib/yuidoc.js index eb5cede87e6..3292300894f 100644 --- a/lib/yuidoc.js +++ b/lib/yuidoc.js @@ -3,11 +3,7 @@ var calculateVersion = require('./calculate-version'); var path = require('path'); module.exports = function yui() { - var emberData = path.join(__dirname, '..', 'addon'); - var emberInflector = path.join(path.dirname(require.resolve('ember-inflector'), 'addon')); - - return new YUIDoc([emberData, emberInflector], { - srcDir: '/', + return new YUIDoc(['addon', 'node_modules/ember-inflector/addon'], { destDir: 'docs', yuidoc: { "name": "The ember-data API", @@ -16,10 +12,6 @@ module.exports = function yui() { "logo": "http://f.cl.ly/items/1A1L432s022u1O1q1V3p/ember%20logo.png", "url": "https://github.com/emberjs/data", "options": { - "paths": [ - "ember-data/lib", - "ember-inflector/addon" - ], "exclude": "vendor", "outdir": "docs/build" } From b8e393c3f4882249b7454fe00744435478d8ac14 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 18 Jan 2016 15:00:55 -0500 Subject: [PATCH 1356/2527] [BUGFIX release] Refactor Model.reopen to use mixins This fixes bugs where users import Model form 'ember-data/model' and it was missing required methods --- addon/-private/system/debug.js | 1 - addon/-private/system/debug/debug-info.js | 6 +- addon/-private/system/model/attr.js | 226 ++++++++++++++++++ addon/-private/system/model/model.js | 16 +- .../system/relationships/belongs-to.js | 3 +- addon/-private/system/relationships/ext.js | 7 +- .../-private/system/relationships/has-many.js | 2 +- addon/attr.js | 221 +---------------- addon/relationships.js | 2 - 9 files changed, 249 insertions(+), 235 deletions(-) create mode 100644 addon/-private/system/model/attr.js diff --git a/addon/-private/system/debug.js b/addon/-private/system/debug.js index 44886d0d8d4..8e605cb4b9a 100644 --- a/addon/-private/system/debug.js +++ b/addon/-private/system/debug.js @@ -2,7 +2,6 @@ @module ember-data */ -import "ember-data/-private/system/debug/debug-info"; import DebugAdapter from "ember-data/-private/system/debug/debug-adapter"; export default DebugAdapter; diff --git a/addon/-private/system/debug/debug-info.js b/addon/-private/system/debug/debug-info.js index 6d9a0e791af..f570f261de0 100644 --- a/addon/-private/system/debug/debug-info.js +++ b/addon/-private/system/debug/debug-info.js @@ -1,6 +1,6 @@ -import Model from "ember-data/model"; +import Ember from "ember"; -Model.reopen({ +export default Ember.Mixin.create({ /** Provides info about the model for debugging purposes @@ -63,5 +63,3 @@ Model.reopen({ }; } }); - -export default Model; diff --git a/addon/-private/system/model/attr.js b/addon/-private/system/model/attr.js new file mode 100644 index 00000000000..e111424e977 --- /dev/null +++ b/addon/-private/system/model/attr.js @@ -0,0 +1,226 @@ +import Ember from 'ember'; +import { assert } from "ember-data/-private/debug"; + + +var get = Ember.get; +var Map = Ember.Map; + +/** + @module ember-data +*/ + +/** + @class Model + @namespace DS +*/ + +export const AttrClassMethodsMixin = Ember.Mixin.create({ + /** + A map whose keys are the attributes of the model (properties + described by DS.attr) and whose values are the meta object for the + property. + + Example + + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + birthday: attr('date') + }); + ``` + + ```javascript + import Ember from 'ember'; + import Person from 'app/models/person'; + + var attributes = Ember.get(Person, 'attributes') + + attributes.forEach(function(meta, name) { + console.log(name, meta); + }); + + // prints: + // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} + // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} + // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} + ``` + + @property attributes + @static + @type {Ember.Map} + @readOnly + */ + attributes: Ember.computed(function() { + var map = Map.create(); + + this.eachComputedProperty((name, meta) => { + if (meta.isAttribute) { + assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.toString(), name !== 'id'); + + meta.name = name; + map.set(name, meta); + } + }); + + return map; + }).readOnly(), + + /** + A map whose keys are the attributes of the model (properties + described by DS.attr) and whose values are type of transformation + applied to each attribute. This map does not include any + attributes that do not have an transformation type. + + Example + + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + firstName: attr(), + lastName: attr('string'), + birthday: attr('date') + }); + ``` + + ```javascript + import Ember from 'ember'; + import Person from 'app/models/person'; + + var transformedAttributes = Ember.get(Person, 'transformedAttributes') + + transformedAttributes.forEach(function(field, type) { + console.log(field, type); + }); + + // prints: + // lastName string + // birthday date + ``` + + @property transformedAttributes + @static + @type {Ember.Map} + @readOnly + */ + transformedAttributes: Ember.computed(function() { + var map = Map.create(); + + this.eachAttribute((key, meta) => { + if (meta.type) { + map.set(key, meta.type); + } + }); + + return map; + }).readOnly(), + + /** + Iterates through the attributes of the model, calling the passed function on each + attribute. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(name, meta); + ``` + + - `name` the name of the current property in the iteration + - `meta` the meta object for the attribute property in the iteration + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. + + Example + + ```javascript + import DS from 'ember-data'; + + var Person = DS.Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + birthday: attr('date') + }); + + Person.eachAttribute(function(name, meta) { + console.log(name, meta); + }); + + // prints: + // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} + // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} + // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} + ``` + + @method eachAttribute + @param {Function} callback The callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + @static + */ + eachAttribute(callback, binding) { + get(this, 'attributes').forEach((meta, name) => { + callback.call(binding, name, meta); + }); + }, + + /** + Iterates through the transformedAttributes of the model, calling + the passed function on each attribute. Note the callback will not be + called for any attributes that do not have an transformation type. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(name, type); + ``` + + - `name` the name of the current property in the iteration + - `type` a string containing the name of the type of transformed + applied to the attribute + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. + + Example + + ```javascript + import DS from 'ember-data'; + + var Person = DS.Model.extend({ + firstName: attr(), + lastName: attr('string'), + birthday: attr('date') + }); + + Person.eachTransformedAttribute(function(name, type) { + console.log(name, type); + }); + + // prints: + // lastName string + // birthday date + ``` + + @method eachTransformedAttribute + @param {Function} callback The callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + @static + */ + eachTransformedAttribute(callback, binding) { + get(this, 'transformedAttributes').forEach((type, name) => { + callback.call(binding, name, type); + }); + } +}); + + +export const AttrInstanceMethodsMixin = Ember.Mixin.create({ + eachAttribute(callback, binding) { + this.constructor.eachAttribute(callback, binding); + } +}); diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index f89d802b569..f854d16166d 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -3,6 +3,11 @@ import { assert, deprecate } from "ember-data/-private/debug"; import { PromiseObject } from "ember-data/-private/system/promise-proxies"; import Errors from "ember-data/-private/system/model/errors"; import isEnabled from 'ember-data/-private/features'; +import DebuggerInfoMixin from 'ember-data/-private/system/debug/debug-info'; +import { BelongsToMixin } from 'ember-data/-private/system/relationships/belongs-to'; +import { HasManyMixin } from 'ember-data/-private/system/relationships/has-many'; +import { DidDefinePropertyMixin, RelationshipsClassMethodsMixin, RelationshipsInstanceMethodsMixin } from 'ember-data/-private/system/relationships/ext'; +import { AttrClassMethodsMixin, AttrInstanceMethodsMixin } from 'ember-data/-private/system/model/attr'; /** @module ember-data @@ -972,4 +977,13 @@ if (isEnabled("ds-references")) { } -export default Model; +Model.reopenClass(RelationshipsClassMethodsMixin); +Model.reopenClass(AttrClassMethodsMixin); + +export default Model.extend( + DebuggerInfoMixin, + BelongsToMixin, + DidDefinePropertyMixin, + RelationshipsInstanceMethodsMixin, + HasManyMixin, + AttrInstanceMethodsMixin); diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index e8c0c7e5de5..59d9ca468f4 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -1,6 +1,5 @@ import Ember from 'ember'; import { assert, warn } from "ember-data/-private/debug"; -import Model from 'ember-data/model'; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; /** @@ -138,7 +137,7 @@ export default function belongsTo(modelName, options) { These observers observe all `belongsTo` relationships on the record. See `relationships/ext` to see how these observers get their dependencies. */ -Model.reopen({ +export const BelongsToMixin = Ember.Mixin.create({ notifyBelongsToChanged(key) { this.notifyPropertyChange(key); } diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index b91c24a887f..7741feba944 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -4,7 +4,6 @@ import { typeForRelationshipMeta, relationshipFromMeta } from "ember-data/-private/system/relationship-meta"; -import Model from "ember-data/model"; import EmptyObject from "ember-data/-private/system/empty-object"; var get = Ember.get; @@ -98,7 +97,7 @@ var relationshipsByNameDescriptor = Ember.computed(function() { @class Model @namespace DS */ -Model.reopen({ +export const DidDefinePropertyMixin = Ember.Mixin.create({ /** This Ember.js hook allows an object to be notified when a property @@ -157,7 +156,7 @@ Model.reopen({ extensively. */ -Model.reopenClass({ +export const RelationshipsClassMethodsMixin = Ember.Mixin.create({ /** For a given relationship name, returns the model type of the relationship. @@ -599,7 +598,7 @@ Model.reopenClass({ }); -Model.reopen({ +export const RelationshipsInstanceMethodsMixin = Ember.Mixin.create({ /** Given a callback, iterates over each of the relationships in the model, invoking the callback with the name of each relationship and its relationship diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index 86f2234ea21..7241fbf7142 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -159,7 +159,7 @@ export default function hasMany(type, options) { }).meta(meta); } -Model.reopen({ +export const HasManyMixin = Ember.Mixin.create({ notifyHasManyAdded(key) { //We need to notifyPropertyChange in the adding case because we need to make sure //we fetch the newly added record in case it is unloaded diff --git a/addon/attr.js b/addon/attr.js index 9a101508a16..bf628e3f316 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -1,229 +1,10 @@ import Ember from 'ember'; -import Model from "ember-data/-private/system/model/model"; -import { assert, deprecate } from "ember-data/-private/debug"; +import { deprecate } from "ember-data/-private/debug"; /** @module ember-data */ -var get = Ember.get; -var Map = Ember.Map; - -/** - @class Model - @namespace DS -*/ -Model.reopenClass({ - /** - A map whose keys are the attributes of the model (properties - described by DS.attr) and whose values are the meta object for the - property. - - Example - - ```app/models/person.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - firstName: attr('string'), - lastName: attr('string'), - birthday: attr('date') - }); - ``` - - ```javascript - import Ember from 'ember'; - import Person from 'app/models/person'; - - var attributes = Ember.get(Person, 'attributes') - - attributes.forEach(function(meta, name) { - console.log(name, meta); - }); - - // prints: - // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} - // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} - // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} - ``` - - @property attributes - @static - @type {Ember.Map} - @readOnly - */ - attributes: Ember.computed(function() { - var map = Map.create(); - - this.eachComputedProperty((name, meta) => { - if (meta.isAttribute) { - assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.toString(), name !== 'id'); - - meta.name = name; - map.set(name, meta); - } - }); - - return map; - }).readOnly(), - - /** - A map whose keys are the attributes of the model (properties - described by DS.attr) and whose values are type of transformation - applied to each attribute. This map does not include any - attributes that do not have an transformation type. - - Example - - ```app/models/person.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - firstName: attr(), - lastName: attr('string'), - birthday: attr('date') - }); - ``` - - ```javascript - import Ember from 'ember'; - import Person from 'app/models/person'; - - var transformedAttributes = Ember.get(Person, 'transformedAttributes') - - transformedAttributes.forEach(function(field, type) { - console.log(field, type); - }); - - // prints: - // lastName string - // birthday date - ``` - - @property transformedAttributes - @static - @type {Ember.Map} - @readOnly - */ - transformedAttributes: Ember.computed(function() { - var map = Map.create(); - - this.eachAttribute((key, meta) => { - if (meta.type) { - map.set(key, meta.type); - } - }); - - return map; - }).readOnly(), - - /** - Iterates through the attributes of the model, calling the passed function on each - attribute. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, meta); - ``` - - - `name` the name of the current property in the iteration - - `meta` the meta object for the attribute property in the iteration - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```javascript - import DS from 'ember-data'; - - var Person = DS.Model.extend({ - firstName: attr('string'), - lastName: attr('string'), - birthday: attr('date') - }); - - Person.eachAttribute(function(name, meta) { - console.log(name, meta); - }); - - // prints: - // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} - // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} - // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} - ``` - - @method eachAttribute - @param {Function} callback The callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - @static - */ - eachAttribute(callback, binding) { - get(this, 'attributes').forEach((meta, name) => { - callback.call(binding, name, meta); - }); - }, - - /** - Iterates through the transformedAttributes of the model, calling - the passed function on each attribute. Note the callback will not be - called for any attributes that do not have an transformation type. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, type); - ``` - - - `name` the name of the current property in the iteration - - `type` a string containing the name of the type of transformed - applied to the attribute - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```javascript - import DS from 'ember-data'; - - var Person = DS.Model.extend({ - firstName: attr(), - lastName: attr('string'), - birthday: attr('date') - }); - - Person.eachTransformedAttribute(function(name, type) { - console.log(name, type); - }); - - // prints: - // lastName string - // birthday date - ``` - - @method eachTransformedAttribute - @param {Function} callback The callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - @static - */ - eachTransformedAttribute(callback, binding) { - get(this, 'transformedAttributes').forEach((type, name) => { - callback.call(binding, name, type); - }); - } -}); - - -Model.reopen({ - eachAttribute(callback, binding) { - this.constructor.eachAttribute(callback, binding); - } -}); - function getDefaultValue(record, options, key) { if (typeof options.defaultValue === "function") { return options.defaultValue.apply(null, arguments); diff --git a/addon/relationships.js b/addon/relationships.js index 23c1f6f7e55..e642287c6d8 100644 --- a/addon/relationships.js +++ b/addon/relationships.js @@ -5,8 +5,6 @@ import belongsTo from "ember-data/-private/system/relationships/belongs-to"; import hasMany from "ember-data/-private/system/relationships/has-many"; -import "ember-data/-private/system/relationships/ext"; - export { belongsTo, hasMany From 1161e8452335ef3fa2ef4300906e466ebe4996a7 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 18 Jan 2016 13:55:01 -0800 Subject: [PATCH 1357/2527] Delete TRANSITION.md This is pretty out of date, and isn't a good resource any longer. If folks need the document for their version, they can view it via browsing the tag itself. --- TRANSITION.md | 969 -------------------------------------------------- 1 file changed, 969 deletions(-) delete mode 100644 TRANSITION.md diff --git a/TRANSITION.md b/TRANSITION.md deleted file mode 100644 index 9fc893926d2..00000000000 --- a/TRANSITION.md +++ /dev/null @@ -1,969 +0,0 @@ -Ember Data 1.0 has a number of changes from Ember Data 0.13. The changes -are pretty significant, so you should assume that you will need to -dedicate some time to the upgrade. - -# Elimination of Model.find and Model.createRecord - -This change future-proofs the API for modules and makes it less -error-prone to clean up state between tests. - -Ember Data 0.13: - -```js -App.PostsRoute = Ember.Route.extend({ - model: function() { - return App.Post.find() - } -}); - -App.PostRoute = Ember.Route.extend({ - model: function(params) { - return App.Post.find(params.post_id) - } -}); -``` - -Ember Data 1.0.beta.1: - -```js -App.PostsRoute = Ember.Route.extend({ - model: function() { - return this.store.findAll('post'); - } -}); - -App.PostRoute = Ember.Route.extend({ - model: function(params) { - return this.store.find('post', params.post_id); - } -}); -``` - -Ember Data 0.13: - -```js -App.NewPostRoute = Ember.Route.extend({ - model: function() { - return App.Post.createRecord(); - } -}); -``` - -Ember Data 1.0.beta.1: - -```js -App.NewPostRoute = Ember.Route.extend({ - model: function() { - return this.store.createRecord('post'); - } -}); -``` - -Note that the store is automatically injected into all routes and -controllers. If you were looking up records in views or components, you -may wish to inject the store into those as well: - -```js -// inject the store into all components -App.inject('component', 'store', 'store:main'); -``` - -In general, looking up models directly in a component is an -anti-pattern, and you should prefer to pass in any model you need in the -template that included the component. - -```js -{{my-popup person=user}} -``` - -# All Finders Return Promises - -In Ember Data 0.13, finders returned empty models or record arrays that -would get filled in with the data once the server responded. - -In Ember Data 1.0.beta.1, finders always return promises. - -Ember Data 0.13: - -```js -var person = App.Post.find(1); -person.one('didLoad', function() { - // do something with the post -}); -``` - -Ember Data 1.0.beta.1: - -```js -this.store.find('post', 1).then(function(post) { - // do something with post -}); -``` - -If you need to wait for several `find` operations to return, you can use -`RSVP.all` to join them together. - -Ember Data 0.13: - -```js -var person1 = App.Person.find(1); -var person2 = App.Person.find(2); - -var counter = 2; - -person1.one('didLoad', bothLoaded); -person2.one('didLoad', bothLoaded); - -function bothLoaded() { - if (--counter === 0) { - // work with person1 and person2 - } -} -``` - -Ember Data 1.0.beta.1: - -```js -var promise1 = this.store.find('person', 1); -var promise2 = this.store.find('person', 2); - -Ember.RSVP.all([ promise1, promise2 ]).then(function(people) { - // people is an array of Person records - // work with people here -}); -``` - -Note that the promises returned from finders have special support for -Ember data-binding. They can be used in templates and templates will -automatically update once the promise has resolved. - -# Transaction is Gone: Save Individual Records - -You no longer need to push records into a transaction in order to save -them. - -Ember Data 0.13: - -```js -App.NewPostRoute = Ember.Route.extend({ - model: function() { - return App.Post.createRecord(); - }, - - setupController: function(controller, model) { - var transaction = this.store.transaction() - controller.set('transaction', this.store.transaction()); - transaction.add(model); - }, - - actions: { - save: function() { - this.controllerFor('newPost').get('transaction').commit(); - } - } -}); -``` - -Ember Data 1.0.beta.1: - -```js -App.NewPostRoute = Ember.Route.extend({ - model: function() { - return this.store.createRecord('post'); - } - - actions: { - save: function() { - this.modelFor('newPost').save(); - } - } -}); -``` - -You also no longer need transactions to save relationships independently -of the model it belongs to, e.g. comments of a post. - -Ember Data 0.13: - -```js -App.PostController = Ember.ObjectController.extend({ - saveComment: function(){ - var transaction = this.get('store').transaction(); - var comment = { - userId: this.get('userId'), - post: this.get('model'), - comment: this.get('comment'), - created_at: Date.create().format(Date.ISO8601_DATETIME) - }; - if (transaction) { - this.set('transaction', transaction); - transaction.createRecord(App.Comment, comment); - } else { - console.log('store.transaction() returned null'); - } - - this.get('transaction').commit(); - this.set('comment', ''); - } -}); -``` - -Ember Data 1.0.beta.1: - -```js -App.PostController = Ember.ObjectController.extend({ - saveComment: function(){ - var comment = { - userId: this.get('userId'), - post: this.get('model'), - comment: this.get('comment'), - createdAt: Date.create().format(Date.ISO8601_DATETIME) - }; - var comment = this.store.createRecord('comment', comment); - comment.save(); - this.set('comment', ''); - } -}); -``` - -If you want to batch up a bunch of records to save and save them all at -once, you can just put them in an Array and call `.invoke('save')` when -you're ready. - -We plan to support batch saving with a single HTTP request through a -dedicated API in the future. - -# Save Returns a Promise - -Calling `save` on a record returns a promise that will be resolved when -the server returns successfully or rejected if the server returns with -an error code. - -Ember Data 0.13: - -```js -person.save(); - -person.one('didCommit', function() { - // work with saved person - // some bugs existed regarding newly created records and ID timing -}); - -person.one('didError', function() { - // work with errored person -}); -``` - -Ember Data 1.0.beta.1: - -```js -person.save().then(function() { - // work with saved person - // newly created records are guaranteed to have IDs assigned -}, function() { - // work with person that failed to save -}); -``` - -This also means that retrying should be simple in Ember Data 1.0.beta.1: - -```js -person.save().then(null, function() { - return person.save(); -}).then(function() { - // person was retried once -}); -``` - -You can of course implement whatever retry strategy you want -(incremental backoff, try N times, etc.) on top of the basic promise -primitive. - -```js -function retry(promise, retryCallback, nTimes) { - // if the promise fails, - return promise.then(null, function(reason) { - // if we haven't hit the retry limit - if (nTimes-- > 0) { - // retry again with the result of calling the retry callback - // and the new retry limit - return retry(retryCallback(), retryCallback, nTimes); - } - - // otherwise, if we hit the retry limit, rethrow the error - throw reason; - }); -} - -// try to save the person up to 5 times -retry(person.save(), function() { - return person.save(); -}, 5); -``` - -Because all async operations in Ember Data 1.0.beta.1 are promises, you -can combine them together using normal promise primitives. - -```js -this.store.findAll('person').then(function(people) { - people.forEach(function(person) { - person.set('isPaidUp', true); - }); - - return Ember.RSVP.all(people.invoke('save')); -}).then(function(people) { - // people we successfully saved -}); -``` - -In Ember 0.13, the semantics for how to determine that a `find` had -finished loading were unclear and confusing. - -# Adapters - -The adapter API has undergone a significant change. - -Existing adapters will likely need to be rebuilt. The good news is that -the new adapter API is somewhat simpler. - -To register your own adapter in place of the default RESTAdapter - -Ember Data 0.13: - -```js -App.Store = DS.Store.extend({ - adapter: DS.MyRESTAdapter.create() -}); -``` - -Ember Data 1.0.beta.1: - -```js -App.ApplicationAdapter = DS.MyRESTAdapter; -``` - -## Promises - -Adapter hooks no longer call directly into the store to notify the store -that the backend has returned. Instead, all adapter hooks return a -promise that the store will automatically handle as appropriate for the -type of query that kicked off the request. - -Ember Data 0.13: - -```js -App.MyAdapter = DS.Adapter.extend({ - find: function(store, type, id) { - $.getJSON("/" + this.pluralize(type) + "/" + id, function(payload) { - store.push(payload); - } - } -}); -``` - -Ember Data 1.0.beta.1: - -```js -App.MyAdapter = DS.Adapter.extend({ - find: function(store, type, id) { - return $.getJSON("/" + this.pluralize(type) + "/" + id); - } -}); -``` - -The short version is that adapter hooks don't need to know how to update -the store, records, or record arrays once the server has returned a -payload. They just need to return a promise, and Ember Data will take -care of interpreting it correctly. - -## Per Type Adapters - -Ember Data 0.13: - -```js -App.Post = DS.Model.extend({ - // ... -}); - -App.PostAdapter = DS.RESTAdapter.extend({ - // ... -}); - -App.Store = DS.Store.extend(); - -App.Store.registerAdapter(App.Post, App.PostAdapter); -``` - -Ember Data 1.0.beta.1: - -```js -App.Post = DS.Model.extend({ - // ... -}); - -App.PostAdapter = DS.RESTAdapter.extend({ - // ... -}); - -// No store is needed -// Adapters are wired up by name -``` - -## Per Type Serializers - -Ember Data 0.13: - -```js -App.Post = DS.Model.extend({ - // ... -}); - -App.PostSerializer = DS.RESTSerializer.extend({ - // ... -}); - -App.PostAdapter = DS.RESTAdapter.extend({ - serializer: 'App.PostSerializer', -}); - -App.Store = DS.Store.extend(); - -App.Store.registerAdapter(App.Post, App.PostAdapter); -``` - -Ember Data 1.0.beta.1: - -```js -App.Post = DS.Model.extend({ - // ... -}); - -App.PostSerializer = DS.RESTSerializer.extend({ - // ... -}); - -// That's it. Everything is wired up by naming -``` - -## REST Adapter and Serializer Configuration - -There are significant improvements and simplifications to configuring -the REST Adapter and Serializer. - -The short version is that once an Ajax request has completed, the -resulting payload is sent through the following hooks: - -1. The payload is sent to `extractSingle` if the original request was - for a single record (like `find`/`save`) or `extractArray` if the - original request was for an Array of records (like - `findAll`/`query`) -2. The default behavior of those methods is to pull apart the top-level - of the payload into multiple smaller records. -3. Each of those smaller records is sent to `normalize`, which can do - normalization a record at a time. -4. Finally, specific types of records can be specially normalized. - -Here's how it works. - -Imagine you start with a payload like this for request for Post 1. - -```js -{ - "id": "1", - "title": "Rails is omakase", - "_links": [{ - "user": { - "href": "/people/dhh" - } - }], - "_embedded": { - "comments": [{ - "ID_": "1", - "CMT_BODY": "Rails is unagi" - }, { - "ID_": "2", - "CMT_BODY": "Omakase O_o" - }] - } -} -``` - -Ember Data 1.0.beta.1 is expecting a payload like this: - -```js -{ - "post": { - "id": 1 - "title": "Rails is omakase", - "comments": ["1", "2"], - "links": { - "user": "/people/dhh" - }, - }, - - "comments": [{ - "id": "1", - "body": "Rails is unagi" - }, { - "id": "2", - "body": "Omakase O_o" - }] -} -``` - -The simplest way to approach this would be to override the -`extractSingle` method and do all the munging in one place. This would -totally work. - -```js -App.PostSerializer = DS.RESTSerializer.extend({ - extractSingle: function(store, type, payload, id) { - var post = {}, commentIds = []; - - post.id = payload.id; - post.title = payload.title; - post.links = { user: payload._links.mapBy('user').findBy('href').href }; - - // Leave the original un-normalized comments alone, but put them - // in the right place in the payload. We'll normalize the comments - // below in `normalizeHash` - var comments = payload._embedded.comments.map(function(comment) { - commentIds.push(comment.ID_); - return { id: comment.ID_, body: comment.CMT_BODY }; - }); - - post.comments = commentIds; - - var post_payload = { post: post, comments: comments }; - - return this._super(store, type, post_payload, id); - } -}); -``` - -However, Ember Data also allows you to break things into into more -sensible chunks. This is especially useful if you have a lot of custom -normalization to do on different pieces of the JSON. - -```js -App.PostSerializer = DS.RESTSerializer.extend({ - extractSingle: function(store, type, payload, id) { - var post = {}, commentIds = []; - - post.id = payload.id; - post.title = payload.title; - post.links = { user: payload._links.mapBy('user').findBy('href').href }; - - // Leave the original un-normalized comments alone, but put them - // in the right place in the payload. We'll normalize the comments - // below in `normalizeHash` - var comments = payload._embedded.comments; - post.comments = comments.mapBy('ID_'); - - var post_payload = { post: post, comments: comments }; - - return this._super(store, type, post_payload, id); - }, - - normalizeHash: { - comments: function(hash) { - return { id: hash.ID_, body: hash.CMT_BODY }; - } - } -}); -``` - -You can also implement the `normalize` method to do generic things like -camelize all of the keys in a hash. The `normalize` method gets called -once for every sub-hash. - -Imagine that we have a payload like this, which is totally fine except -for the use of underscores rather than camelization and `"_id"` instead -of `"id"`: - -```js -{ - "post": { - "_id": "1", - "author_name": "DHH", - "title": "Rails is omakase", - "comments": [ "1", "2" ] - }, - "comments": [{ - "_id": "1", - "author_name": "unagisan", - "like_count": 12, - "body": "Unagi!" - }, { - "_id": "2", - "author_name": "tlo", - "like_count": 100, - "body": "Omakase is delicious" - }] -} -``` - -We don't need to implement `extractSingle`, because the top-level is -already organized perfectly. - -```js -App.PostSerializer = DS.RESTSerializer.extend({ - // This method will be called 3 times: once for the post, and once - // for each of the comments - normalize: function(type, hash, property) { - // property will be "post" for the post and "comments" for the - // comments (the name in the payload) - - // normalize the `_id` - var json = { id: hash._id }; - delete hash._id; - - // normalize the underscored properties - for (var prop in hash) { - json[prop.camelize()] = hash[prop]; - } - - // delegate to any type-specific normalizations - return this._super(type, json, property); - } -}); -``` - -So to sum up, you should: - -* use `extractSingle` and `extractArray` when the top-level of your - payload is organized differently than Ember Data expects -* use `normalize` to normalize sub-hashes if all sub-hashes in the - payload can be normalized in the same way. -* use `normalizeHash` to normalize specific sub-hashes. -* make sure to call super if you override `extractSingle`, - `extractArray` or `normalize` so the rest of the chain will get - called. -* beta.1 expects `comments` key now instead of `comments_ids`. - This is likely to be configurable in beta.2. - -### Underscored Keys, `_id` and `_ids` - -In 0.13, the REST Adapter automatically camelized incoming keys for -you. It also expected `belongsTo` relationships to be listed under -`name_id` and `hasMany` relationships to be listed under `name_ids`. - -If your application returns json with underscored attributes and `_id` or `_ids` -for relation, you can extend `ActiveModelSerializer` and all will work out of the box. - -```js -App.ApplicationSerializer = DS.ActiveModelSerializer.extend({}); -``` - -Note: DS.ActiveModelSerializer is not to be confused with the ActiveModelSerializer gem -that is part of Rails API project. A conventional Rails API project with produce underscored output -and the `DS.ActiveModelSerializer` will perform the expected normalization behavior such as camelizing -property keys in your JSON. - - -### Underscored API Endpoints - -In 0.13 the REST Adapter automatically generated API endpoints for multi -word models with an underscore (`'/blog_posts'`), begining with Beta 1 -the REST Adapter will generate endpoints camelized. To go back to -underscored endpoints you can define the `pathForType` method in your -`ApplicationAdapter`. - -```js -App.ApplicationAdapter = DS.RESTAdapter.extend({ - pathForType: function(type) { - var underscored = Ember.String.underscore(type) - return Ember.String.pluralize(underscored); - } -}); - -``` - -### Underscored Root Objects in JSON Responses - -In 0.13 the REST Adapter expected the root objects of a JSON response to -be underscored for multi word models. - -```js -{ - "blog_posts": [{ - "id": 1, - "title": "A Post" - }, { - "id": 2, - "title": "Another Post" - }] -} -``` - -Beginning in Beta 1 the REST Adapter expects the root objects of a JSON -response to be camelized. - -```js -{ - "blogPosts": [{ - "id": 1, - "title": "A Post" - }, { - "id": 2, - "title": "Another Post" - }] -} -``` - -If your server uses underscored root objects you can define the -`modelNameFromPayloadKey` method in your `ApplicationSerializer`. - -```js -App.ApplicationSerializer = DS.RESTSerializer.extend({ - modelNameFromPayloadKey: function(root) { - var dasherize = Ember.String.dasherize(root); - return Ember.String.singularize(dasherize); - } -}); -``` - -### Underscored Root Objects in JSON Requests - -In 0.13 the REST Adapter would send underscored versions of multi word -model names as the root element. Beginning in Beta 1 the REST Adapter -sends camelized root object. - -If your server expects underscored root objects you can define the `serializeIntoHash` -method in your `ApplicationSerializer`. - -```js -App.ApplicationSerializer = DS.RESTSerializer.extend({ - serializeIntoHash: function(data, type, record, options) { - var root = Ember.String.decamelize(type.typeKey); - data[root] = this.serialize(record, options); - } -}); -``` - - -### Underscored JSON for Saving - -In 0.13 the REST Adapter would send underscored JSON for create/update -requests. Beginning in Beta 1 the REST Adapter sends camelized JSON. - -If your server expects underscored JSON you can define the -`serializeAttribute` method in your `ApplicationSerializer`. - -```js -App.ApplicationSerializer = DS.RESTSerializer.extend({ - serializeAttribute: function(record, json, key, attribute) { - var attrs = Ember.get(this, 'attrs'); - var value = Ember.get(record, key), type = attribute.type; - - if (type) { - var transform = this.transformFor(type); - value = transform.serialize(value); - } - - // if provided, use the mapping provided by `attrs` in - // the serializer - key = attrs && attrs[key] || Ember.String.decamelize(key); - - json[key] = value; - } -}); -``` - -### Embedded Records - -Explicit support for embedded records has been moved into a mixin within -the activemodel-adapter package. - -You can handle embedded records yourself by implementing `extractSingle` -and reorganizing the payload, or using the DS.EmbeddedRecordsMixin - -Consider this payload: - -```js -{ - "post": { - "id": "1", - "title": "Rails is omakase", - "comments": [{ - "id": "1", - "body": "I like omakase" - }, { - "id": "2", - "body": "I prefer not to rely on elitist chefs" - }] - } -} -``` - -You could handle embedded records like this: - -```js -App.PostSerializer = DS.RESTSerializer.extend({ - extractSingle: function(store, type, payload, id) { - var comments = payload.post.comments, - commentIds = comments.mapBy('id'); - - payload.comments = comments; - payload.post.comments = commentIds; - - return this._super.apply(this, arguments); - } -}); -``` - -# JSON Transforms - -Ember Data 0.13: - -```js -DS.RESTAdapter.registerTransform('raw', { - deserialize: function(serialized) { - return serialized; - }, - serialize: function(deserialized) { - return deserialized; - } -}); -``` - -Ember Data 1.0.beta.1: - -```js -App.RawTransform = DS.Transform.extend({ - deserialize: function(serialized) { - return serialized; - }, - serialize: function(deserialized) { - return deserialized; - } -}); -``` - -# Host and Namespace Configuration - -Ember Data 0.13: - -```js -DS.RESTAdapter.reopen({ - url: 'http://www.google.com', - namespace: 'api/v1' -}); -``` - -Ember Data 1.0.beta.1: - -```js -App.ApplicationAdapter = DS.RESTAdapter.extend({ - host: 'http://www.google.com', - namespace: 'api/v1' -}); -``` - -# Relationships - -## Defining Relationships in Models - -Defining relationships now uses the 'shorthand' name of your model, not -the fully qualified path to the class. - -Instead of `App.Comment`, use `comment`. - -Instead of `App.BlogPost`, use `blogPost`. - -Ember Data 0.13: - -```js -App.BlogPost = DS.Model.extend({ - comments: DS.hasMany("App.Comment") -}); - -App.Comment = DS.Model.extend({ - post: DS.belongsTo("App.BlogPost") -}); -``` - -Ember Data 1.0.beta.1: - -```js -App.BlogPost = DS.Model.extend({ - comments: DS.hasMany("comment") -}); - -App.Comment = DS.Model.extend({ - post: DS.belongsTo("blogPost") -}); -``` - -### Polymorphic relationships - -Polymorphic types are now serialized with a json key of the model name + "Type" - -For example given the polymorphic relationship: - -``` -App.Comment = DS.Model.extend({ - message: DS.belongsTo('message', { - polymorphic: true - }) -}); -``` - -Ember Data 0.13 - -``` -{ - "message": 12, - "message_type": "post" -} -``` - -Ember Data 1.0.beta.3: - -``` -{ - "message": 12, - "messageType": "post" -} -``` - -You can override this behaviour by defining the `serializePolymorphicType` method -on your serializer. - -``` -App.CommentSerializer = DS.RESTSerializer.extend({ - serializePolymorphicType: function(record, json, relationship) { - var key = relationship.key, - belongsTo = get(record, key); - key = this.keyForAttribute ? this.keyForAttribute(key) : key; - json[key + "_type"] = belongsTo.constructor.typeKey; - } -}); -``` - -## Defining a Custom Serializer - -If you have a custom adapter you will likely need to wire up a custom -serializer. - -Ember Data 0.13: - -```js -DS.DjangoRESTSerializer = DS.RESTSerializer.extend(); -DS.DjangoRESTAdapter = DS.RESTAdapter.extend({ - serializer: DS.DjangoRESTSerializer -}); -``` - -Ember Data 1.0.beta.1: - -```js -DS.DjangoRESTSerializer = DS.RESTSerializer.extend(); -DS.DjangoRESTAdapter = DS.RESTAdapter.extend({ - defaultSerializer: "DS/djangoREST" -}); -``` - -Your users will still be able to define custom serializers that extend -your default serializer. If they do, they should make sure to subclass -your custom serializer and not a built-in Ember Data serializer. From a43df737a55bd10f629a593b000a4ccb393323e6 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 18 Jan 2016 18:08:33 -0500 Subject: [PATCH 1358/2527] Fix circular reference in model imports --- addon/-private/system/relationships/has-many.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index 7241fbf7142..a5de409cb91 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -4,7 +4,6 @@ import Ember from 'ember'; import { assert } from "ember-data/-private/debug"; -import Model from "ember-data/model"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; import isArrayLike from "ember-data/-private/system/is-array-like"; @@ -146,6 +145,7 @@ export default function hasMany(type, options) { return relationship.getRecords(); }, set(key, records) { + var Model = require('ember-data/model').default; assert("You must pass an array of records to set a hasMany relationship", isArrayLike(records)); assert(`All elements of a hasMany relationship must be instances of DS.Model, you passed ${Ember.inspect(records)}`, (function() { return Ember.A(records).every((record) => Model.detectInstance(record) ); From 43a447e7a60f0930b1f588ba8a9863a6c235c93d Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 18 Jan 2016 18:21:46 -0500 Subject: [PATCH 1359/2527] Update changelog for 2.3.2 release --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61965d28670..2d8729dad2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ ### Master +### Release 2.3.2 (January 18, 2016) +- [#4000](https://github.com/emberjs/data/pull/4000) Re-enable pushing builds to S3 +- [#4002](https://github.com/emberjs/data/pull/4002) Fix paths to files which should be uploaded to S3 +- [#4072](https://github.com/emberjs/data/pull/4072) [BUGFIX release] Fix bundled source path for gem +- [#4073](https://github.com/emberjs/data/pull/4073) [BUGFIX release] Add missing dist source to gem +- [#4082](https://github.com/emberjs/data/pull/4082) Move the date import to where it is used intead of the root module +- [#4084](https://github.com/emberjs/data/pull/4084) [cleanup] Remove unnecessary inline JSHint config +- [#4088](https://github.com/emberjs/data/pull/4088) [BUFGIX release] Fix regression with missing initializers +- [#4090](https://github.com/emberjs/data/pull/4090) Make yui doc generate links from the project root instead of the file… +- [#4091](https://github.com/emberjs/data/pull/4091) [BUGFIX release] Refactor Model.reopen to use mixins + ### Release 2.3.1 (January 12, 2016) - [#4063](https://github.com/emberjs/data/pull/4063) [BUGFIX release] don't load "app" code when loading globals files - [#4066](https://github.com/emberjs/data/pull/4066) Use correct version number when used as an addon. From bcd9eb817b7ed71f563d96f4d3a2bf77c61aa6c1 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Tue, 19 Jan 2016 22:38:46 +0900 Subject: [PATCH 1360/2527] Update `.npmignore` * Ruby files and testing yaml is unnecessary as a npm module. * Now `Brocfile.js` is not exist anywhere. --- .npmignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.npmignore b/.npmignore index dac217ccf9d..08ef4c5b7f8 100644 --- a/.npmignore +++ b/.npmignore @@ -7,10 +7,12 @@ dist/ .editorconfig .ember-cli .travis.yml +.appveyor.yml .npmignore **/.gitkeep bower.json -Brocfile.js testem.json *.gem +*.gemspec +**/*.rb node-tests/ From 19a975ea489d635bf850e9f251f44e9f4962de9f Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Tue, 19 Jan 2016 20:52:23 -0500 Subject: [PATCH 1361/2527] [DOC] Replace reference to DS.Store.find Replaces a reference to `DS.Store.find` in the docs for `DS.Store.filter` --- addon/-private/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index daede7f14f2..b7ee49bba14 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1167,7 +1167,7 @@ Store = Service.extend({ still be in the array. Optionally you can pass a query, which is the equivalent of calling - [find](#method_find) with that same query, to fetch additional records + [query](#method_query) with that same query, to fetch additional records from the server. The results returned by the server could then appear in the filter if they match the filter function. From b0fe3b0d2ef57c9b87205b5aff702c8c6079347e Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Tue, 19 Jan 2016 23:15:55 -0500 Subject: [PATCH 1362/2527] [cleanup] Remove unneeded `getComputedPropertyDesc` test helper As the comment in the code says, this is no longer needed since https://github.com/emberjs/ember.js/pull/10323 was merged in. --- .../relationships/belongs-to-test.js | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 746861fb1d8..524c6883da2 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -15,21 +15,6 @@ var hasMany = DS.hasMany; var belongsTo = DS.belongsTo; var hash = Ember.RSVP.hash; -// Before https://github.com/emberjs/ember.js/pull/10323 the computed -// property descriptor was stored on the ember meta object. After that -// pr it was moved to the ember object. This code normalized that -// lookup because the Ember Data ci tests run against diferent version -// of Ember. Once that code reaches the release branch this code can -// be removed. -function getComputedPropertyDesc(model, key) { - if (Ember.meta(model).descs) { - return Ember.meta(model).descs[key]; - } - var possibleDesc = model[key]; - var desc = (possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor) ? possibleDesc : undefined; - return desc; -} - module("integration/relationship/belongs_to Belongs-To Relationships", { beforeEach() { User = DS.Model.extend({ @@ -563,7 +548,7 @@ test("relationshipsByName is cached in production", function(assert) { var oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it //did not get dynamically changed when accessed - var relationshipsByName = getComputedPropertyDesc(model, 'relationshipsByName'); + var relationshipsByName = model.relationshipsByName; var oldCacheable = relationshipsByName._cacheable; relationshipsByName._cacheable = true; Ember.testing = false; @@ -581,7 +566,7 @@ test("relatedTypes is cached in production", function(assert) { var oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it //did not get dynamically changed when accessed - var relatedTypes = getComputedPropertyDesc(model, 'relatedTypes'); + var relatedTypes = model.relatedTypes; var oldCacheable = relatedTypes._cacheable; relatedTypes._cacheable = true; Ember.testing = false; @@ -599,7 +584,7 @@ test("relationships is cached in production", function(assert) { var oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it //did not get dynamically changed when accessed - var relationships = getComputedPropertyDesc(model, 'relationships'); + var relationships = model.relationships; var oldCacheable = relationships._cacheable; relationships._cacheable = true; Ember.testing = false; From 5284f30ed22fd0102dded9e83ea43e19bff20a61 Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Wed, 20 Jan 2016 00:00:49 -0500 Subject: [PATCH 1363/2527] [DOC] Fix misleading docs for `DS.RESTAdapter.findBelongsTo` This fixes some misleading docs for `DS.RESTAdapter.findBelongsTo` that make it seems like it expects a JSON array rather than a JSON object in the response. --- addon/adapters/rest.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 5519d6fdd0b..c7bc6c73adc 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -543,9 +543,9 @@ export default Adapter.extend(BuildURLMixin, { }, /** - Called by the store in order to fetch a JSON array for - the unloaded records in a belongs-to relationship that were originally - specified as a URL (inside of `links`). + Called by the store in order to fetch the JSON for the unloaded record in a + belongs-to relationship that was originally specified as a URL (inside of + `links`). For example, if your original payload looks like this: From 5625cbd22307f00838f3f190fc4ace41103a15b6 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Tue, 19 Jan 2016 21:56:16 +0900 Subject: [PATCH 1364/2527] [BUGFIX release] Remove 'v' prefix from `DS.VERSION` The change of version number format may break version checking from other libs. --- lib/calculate-version.js | 2 +- lib/version-replace.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/calculate-version.js b/lib/calculate-version.js index 941e54208ee..790a912429f 100644 --- a/lib/calculate-version.js +++ b/lib/calculate-version.js @@ -9,7 +9,7 @@ module.exports = function() { if (existsSync(gitPath)) { var info = gitRepoInfo(gitPath); if (info.tag) { - return info.tag; + return info.tag.replace(/^v/, ''); } return packageVersion + '+' + info.sha.slice(0, 10); diff --git a/lib/version-replace.js b/lib/version-replace.js index d3952f49fba..56eeb8f1574 100644 --- a/lib/version-replace.js +++ b/lib/version-replace.js @@ -1,5 +1,5 @@ var calculateVersion = require('./calculate-version'); -var version = calculateVersion().replace(/^v/, ''); +var version = calculateVersion(); var replace = require('broccoli-string-replace'); module.exports = function configFiles(tree) { From ae7146c5199b9c59ef39c9ca22685e3ab04ffc6a Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Wed, 20 Jan 2016 10:58:32 -0500 Subject: [PATCH 1365/2527] [DOC] Mark `DS.Store.filter` as private `DS.Store.filter` was deprecated and moved to an addon in https://github.com/emberjs/data/pull/3364.. It has not been available without using the addon since https://github.com/emberjs/data/pull/3778/files. The addon can be found at https://github.com/ember-data/ember-data-filter --- addon/-private/system/store.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b7ee49bba14..8711f06fb49 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1189,6 +1189,7 @@ Store = Service.extend({ ``` @method filter + @private @param {String} modelName @param {Object} query optional query @param {Function} filter From 89f124b5771ef1688f691cba4b7ec68446975a1c Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Wed, 20 Jan 2016 22:10:46 -0500 Subject: [PATCH 1366/2527] [BUGFIX beta] Fix `BuildUrlMixin.urlPrefix` regression when host is "/" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/emberjs/data/issues/4105 I couldn't think of a better name for the test ¯\_(ツ)_/¯ --- addon/-private/adapters/build-url-mixin.js | 6 +++++- .../adapter/build-url-mixin-test.js | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index f67cc558e3d..07ab6d79e68 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -218,9 +218,13 @@ export default Ember.Mixin.create({ @return {String} urlPrefix */ urlPrefix(path, parentURL) { - var host = get(this, 'host') || ''; + var host = get(this, 'host'); var namespace = get(this, 'namespace'); + if (!host || host === '/') { + host = ''; + } + if (path) { // Protocol relative url if (/^\/\//.test(path) || /http(s)?:\/\//.test(path)) { diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index a1c53ce9737..7f6bf98e67c 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -128,6 +128,26 @@ test('buildURL - with absolute paths in links and protocol relative host', funct })); }); +test('buildURL - with absolute paths in links and host is /', function(assert) { + run(function() { + adapter.setProperties({ + host: '/', + namespace: 'api/v1' + }); + }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + + ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); + + run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { + ajaxResponse({ comments: [{ id: 1 }] }); + return post.get('comments'); + })).then(assert.wait(function (comments) { + assert.equal(passedUrl, '/api/v1/posts/1/comments', 'host stripped out properly'); + })); +}); + test('buildURL - with full URLs in links', function(assert) { adapter.setProperties({ host: 'http://example.com', From c540db136a87c61c71de7fc28600ce9e9a5edb33 Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 21 Jan 2016 18:52:42 -0500 Subject: [PATCH 1367/2527] Update changelog for 2.3.3 release --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d8729dad2f..1561763d79a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ### Master +### Release 2.3.3 (January 21, 2016) +- [#4095](https://github.com/emberjs/data/pull/4095) [BUGFIX release] Remove 'v' prefix from `DS.VERSION` + ### Release 2.3.2 (January 18, 2016) - [#4000](https://github.com/emberjs/data/pull/4000) Re-enable pushing builds to S3 - [#4002](https://github.com/emberjs/data/pull/4002) Fix paths to files which should be uploaded to S3 From 5dab079e239630241b4174500d4d033d498038b8 Mon Sep 17 00:00:00 2001 From: Dan McClain Date: Mon, 25 Jan 2016 08:34:29 -0500 Subject: [PATCH 1368/2527] [BUGFIX beta] Move `jQuery.ajax` call to a method separate method Allow for overriding of the `ajax` request by overriding `RESTAdapter.ajaxRequest` instead of the `RESTAdapter.ajax`, which perform promise wrapping and Ember Data specific errors --- addon/adapters/rest.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index c7bc6c73adc..a36aecf39be 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -881,10 +881,19 @@ export default Adapter.extend(BuildURLMixin, { Ember.run.join(null, reject, error); }; - Ember.$.ajax(hash); + adapter._ajaxRequest(hash); }, 'DS: RESTAdapter#ajax ' + type + ' to ' + url); }, + /** + @method _ajaxRequest + @private + @param {Object} options jQuery ajax options to be used for the ajax request + */ + _ajaxRequest(options) { + Ember.$.ajax(options); + }, + /** @method ajaxOptions @private From fcf060d6e38b97b6d22bb4acd411c7e6c502932d Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 26 Jan 2016 22:13:02 +0100 Subject: [PATCH 1369/2527] [ci skip] Sort CHANGELOG by version and not date of release This also removes the entries for *Release 2.1.0-beta.1 (August 20, 2015)*, as those are already tracked in *Release 2.1.0*. --- CHANGELOG.md | 93 +++++++++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1561763d79a..d240ac5ea5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -134,16 +134,6 @@ - [#3816](https://github.com/emberjs/data/pull/3816) run optional feature tests on AppVeyor - [#3817](https://github.com/emberjs/data/pull/3817) Update the changelog for Ember Data 2.1.0 -### Release 1.13.14 (October 18, 2015) -- [#3665](https://github.com/emberjs/data/pull/3665) [BUGFIX beta] Fix usage of registry for 2.1.0+. -- [#3825](https://github.com/emberjs/data/pull/3825) [BUGFIX] Restore IE8 compatibility by using Ember.create -- [#3837](https://github.com/emberjs/data/pull/3837) [BUGFIX] Attribute/relationship named "type" of embedded record is considered before normalization -- [#3840](https://github.com/emberjs/data/pull/3840) Backport Fix usage of registry for 2.1.0+ from pr #3665 -- [#3846](https://github.com/emberjs/data/pull/3846) [BUGFIX beta] Attribute/relationship named "type" of primary record i… -- [#3847](https://github.com/emberjs/data/pull/3847) [BUGFIX beta] JSONAPI serializer not respecting 'attrs' hash -- [#3857](https://github.com/emberjs/data/pull/3857) [BUGFIX beta] rollbackAttributes() works after multiple failed saves -- [#3859](https://github.com/emberjs/data/pull/3859) [BUGFIX beta] Correctly handle invalid errors without payload or pointer - ### Release 2.1.0 (October 5, 2015) - [#3811](https://github.com/emberjs/data/pull/3811) Format lists in JSONSerializer docs for rendering - [#3814](https://github.com/emberjs/data/pull/3814) [BUGFIX] Do not deserialize when a relationship named `type` exists @@ -177,10 +167,6 @@ - [#3649](https://github.com/emberjs/data/pull/3649) Empty object - [#3647](https://github.com/emberjs/data/pull/3647) Adapter.query should be part of the public overrideable interface. -### Release 1.13.13 (September 17, 2015) -- [#3762](https://github.com/emberjs/data/pull/3762) [BUGFIX release] - Improve links vs. local data for relationships - ### Release 2.0.1 (September 17, 2015) - [#3751](https://github.com/emberjs/data/pull/3751) Remove normalizePayload, associated docs, and mention of functionality. @@ -192,41 +178,6 @@ - [#3779](https://github.com/emberjs/data/pull/3779) [BUGFIX release] Remove store method deprecations - [#3782](https://github.com/emberjs/data/pull/3782) [DOC release] Remove private label for findAll, query, queryRecord -### Release 1.13.12 (September 10, 2015) -- [#3689](https://github.com/emberjs/data/pull/3689) Backport - empty-object performance improvements from 2.1.0-beta1 -- [#3690](https://github.com/emberjs/data/pull/3690) - [BUGFIX release-1-13] Ensure that `service:store` is cleared before - regsitering. -- [#3725](https://github.com/emberjs/data/pull/3725) - [BUGFIX release-1-13] Disable polymorphic deserialization when a - mode… -- [#3753](https://github.com/emberjs/data/pull/3753) Bumped the - ember-inflector version to 1.9.2. -- [#3754](https://github.com/emberjs/data/pull/3754) Do not run tests - with Ember 2.0 in the Ember Data 1.13 appveyor builds - - -### Release 1.13.11 (August 21, 2015) - -- [#3685](https://github.com/emberjs/data/pull/3685) Fixing typo that - causes Ember-Data v1.13.10 to crash with Ember v2.0. -- [#3686](https://github.com/emberjs/data/pull/3686) Fix broken - rest-serializer test. - -### Release 1.13.10 (August 20, 2015) - -- [#3577](https://github.com/emberjs/data/pull/3577) Use the correct - modelClass and serializer to extract a polymorphic -- [#3667](https://github.com/emberjs/data/pull/3667) Don’t crash \w - Ember 2.0 - - -### Release 2.1.0-beta.1 (August 20, 2015) -- [#3641](https://github.com/emberjs/data/pull/3641) Improve InternalModel (2x - 3x faster) -- [#3649](https://github.com/emberjs/data/pull/3649) Empty object -- [#3647](https://github.com/emberjs/data/pull/3647) Adapter.query should be part of the public overrideable interface. - ### Release 2.0.0 (August 20, 2015) #### Breaking Changes @@ -304,6 +255,50 @@ In Ember Data 2.0 a record will no longer be removed from hasMany relationships - [#3567](https://github.com/emberjs/data/pull/3567) Use Ember.$ instead of jQuery for AJAX requests - [#3570](https://github.com/emberjs/data/pull/3570) Update `Ember.deprecate` and `Ember.warn` calls to include required information +### Release 1.13.14 (October 18, 2015) +- [#3665](https://github.com/emberjs/data/pull/3665) [BUGFIX beta] Fix usage of registry for 2.1.0+. +- [#3825](https://github.com/emberjs/data/pull/3825) [BUGFIX] Restore IE8 compatibility by using Ember.create +- [#3837](https://github.com/emberjs/data/pull/3837) [BUGFIX] Attribute/relationship named "type" of embedded record is considered before normalization +- [#3840](https://github.com/emberjs/data/pull/3840) Backport Fix usage of registry for 2.1.0+ from pr #3665 +- [#3846](https://github.com/emberjs/data/pull/3846) [BUGFIX beta] Attribute/relationship named "type" of primary record i… +- [#3847](https://github.com/emberjs/data/pull/3847) [BUGFIX beta] JSONAPI serializer not respecting 'attrs' hash +- [#3857](https://github.com/emberjs/data/pull/3857) [BUGFIX beta] rollbackAttributes() works after multiple failed saves +- [#3859](https://github.com/emberjs/data/pull/3859) [BUGFIX beta] Correctly handle invalid errors without payload or pointer + +### Release 1.13.13 (September 17, 2015) +- [#3762](https://github.com/emberjs/data/pull/3762) [BUGFIX release] + Improve links vs. local data for relationships + +### Release 1.13.12 (September 10, 2015) +- [#3689](https://github.com/emberjs/data/pull/3689) Backport + empty-object performance improvements from 2.1.0-beta1 +- [#3690](https://github.com/emberjs/data/pull/3690) + [BUGFIX release-1-13] Ensure that `service:store` is cleared before + regsitering. +- [#3725](https://github.com/emberjs/data/pull/3725) + [BUGFIX release-1-13] Disable polymorphic deserialization when a + mode… +- [#3753](https://github.com/emberjs/data/pull/3753) Bumped the + ember-inflector version to 1.9.2. +- [#3754](https://github.com/emberjs/data/pull/3754) Do not run tests + with Ember 2.0 in the Ember Data 1.13 appveyor builds + + +### Release 1.13.11 (August 21, 2015) + +- [#3685](https://github.com/emberjs/data/pull/3685) Fixing typo that + causes Ember-Data v1.13.10 to crash with Ember v2.0. +- [#3686](https://github.com/emberjs/data/pull/3686) Fix broken + rest-serializer test. + +### Release 1.13.10 (August 20, 2015) + +- [#3577](https://github.com/emberjs/data/pull/3577) Use the correct + modelClass and serializer to extract a polymorphic +- [#3667](https://github.com/emberjs/data/pull/3667) Don’t crash \w + Ember 2.0 + + ### Release 1.13.9 (August 13, 2015) #### Breaking Changes From 731836dca8f4be95f25998d0a9499f4f63cca054 Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 27 Jan 2016 00:30:03 +0100 Subject: [PATCH 1370/2527] [skip ci] Add ember.js and ember-data tags automatically to SO question This prefills the tags with `ember.js` and `ember-data`. --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4508ec698be..3dffba76125 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,8 +3,9 @@ This is the issue tracker for Ember Data. The Ember.js community uses this site to collect and track bugs and discussions of new features. If you are having difficulties using Ember Data or have a question about usage please ask a -question on StackOverflow: http://stackoverflow.com/questions/ask and tag -your question with `ember.js` and `ember-data`. +question on StackOverflow: +[http://stackoverflow.com/questions/ask](http://stackoverflow.com/questions/ask?tags=ember.js&tags=ember-data) +and tag your question with `ember.js` and `ember-data`. The Ember.js community is very active on StackOverflow and most questions receive attention the same day they're posted: From 5b8439711a01d29052fd5f805341e06558bd6d88 Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 26 Jan 2016 19:18:26 +0100 Subject: [PATCH 1371/2527] [BUGFIX beta] Add assertions for store#query() Currently invoking `store.query('person')` will fail with an error within `RESTAdapter#sortQueryParams`, which is not helpful. This adds the following assertions to store#query(): - a type is passed to the query method - a query hash is passed to the query method --- addon/-private/system/store.js | 2 ++ tests/integration/adapter/queries-test.js | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 8711f06fb49..9c53391551b 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -957,6 +957,8 @@ Store = Service.extend({ }, _query(modelName, query, array) { + assert("You need to pass a type to the store's query method", modelName); + assert("You need to pass a query hash to the store's query method", query); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); array = array || this.recordArrayManager diff --git a/tests/integration/adapter/queries-test.js b/tests/integration/adapter/queries-test.js index 8557997fba8..79e905fde96 100644 --- a/tests/integration/adapter/queries-test.js +++ b/tests/integration/adapter/queries-test.js @@ -28,6 +28,18 @@ module("integration/adapter/queries - Queries", { } }); +test("It raises an assertion when no type is passed", function(assert) { + assert.expectAssertion(function() { + store.query(); + }, "You need to pass a type to the store's query method"); +}); + +test("It raises an assertion when no query hash is passed", function(assert) { + assert.expectAssertion(function() { + store.query('person'); + }, "You need to pass a query hash to the store's query method"); +}); + test("When a query is made, the adapter should receive a record array it can populate with the results of the query.", function(assert) { adapter.query = function(store, type, query, recordArray) { assert.equal(type, Person, "the query method is called with the correct type"); From ed26cdcee4ef5acd21fbaee42abf7b879eef3d36 Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 26 Jan 2016 21:33:34 +0100 Subject: [PATCH 1372/2527] Add assertion for polymorphic type for HasManyReference#push --- addon/-private/system/references/has-many.js | 10 +++- tests/integration/references/has-many-test.js | 60 +++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 18e766cb6cb..7c0d9ae79ce 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -1,5 +1,7 @@ import Ember from 'ember'; import Reference from './reference'; +import { assertPolymorphicType } from 'ember-data/-private/utils'; +import { runInDebug } from 'ember-data/-private/debug'; const get = Ember.get; @@ -50,11 +52,15 @@ HasManyReference.prototype.push = function(objectOrPromise) { var internalModels = array.map((obj) => { var record = this.store.push(obj); + + runInDebug(() => { + var relationshipMeta = this.hasManyRelationship.relationshipMeta; + assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel); + }); + return record._internalModel; }); - // TODO add assertion for polymorphic type - this.hasManyRelationship.computeChanges(internalModels); return this.hasManyRelationship.manyArray; diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index af7946a277b..f1a27e18c6b 100644 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -168,6 +168,66 @@ if (isEnabled("ds-references")) { }); }); + test("push(array) works with polymorphic type", function(assert) { + var done = assert.async(); + + env.container.register('model:mafia-boss', Person.extend()); + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1 + } + }); + }); + + var personsReference = family.hasMany('persons'); + + run(() => { + var data = { + data: [ + { data: { type: 'mafia-boss', id: 1, attributes: { name: "Vito" } } } + ] + }; + + personsReference.push(data).then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 1); + assert.equal(records.objectAt(0).get('name'), "Vito"); + + done(); + }); + }); + }); + + test("push(array) asserts polymorphic type", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1 + } + }); + }); + + var personsReference = family.hasMany('persons'); + + assert.expectAssertion(() => { + run(() => { + var data = { + data: [ + { data: { type: 'family', id: 1 } } + ] + }; + + personsReference.push(data); + }); + }, "You cannot add a record of type 'family' to the 'family.persons' relationship (only 'person' allowed)"); + }); + test("push(object) supports JSON-API payload", function(assert) { var done = assert.async(); From 1097530ed68c5feffc5819c4129b3776189b7536 Mon Sep 17 00:00:00 2001 From: Wesley Workman Date: Thu, 21 Jan 2016 19:12:01 -0500 Subject: [PATCH 1373/2527] Changing `store.pushPayload` and `serializer.pushPayload` to return the "pushed value". Either a record or array of records. --- FEATURES.md | 5 +++++ addon/-private/system/store.js | 6 +++++- addon/serializers/json-api.js | 7 ++++++- addon/serializers/rest.js | 7 ++++++- config/features.json | 3 ++- tests/unit/store/push-test.js | 31 +++++++++++++++++++++++++++++++ 6 files changed, 55 insertions(+), 4 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index a3f2677c738..faad23d82d4 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -25,3 +25,8 @@ entry in `config/features.json`. Pass options specified for a `DS.attr` to the `DS.Tranform`'s `serialize` and `deserialize` methods (described in [RFC 1](https://github.com/emberjs/rfcs/pull/1)) + +- `ds-pushpayload-return` + + Enables `pushPayload` to return the model(s) that are created or + updated via the internal `store.push`. [PR 4110](https://github.com/emberjs/data/pull/4110) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 9c53391551b..f2a44beb630 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1818,7 +1818,11 @@ Store = Service.extend({ assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); serializer = this.serializerFor(modelName); } - this._adapterRun(() => serializer.pushPayload(this, payload)); + if (isEnabled('ds-pushpayload-return')) { + return this._adapterRun(() => { return serializer.pushPayload(this, payload); }); + } else { + this._adapterRun(() => serializer.pushPayload(this, payload)); + } }, /** diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index a4888a054d5..a811ed4b5c0 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -7,6 +7,7 @@ import { assert, runInDebug, warn } from 'ember-data/-private/debug'; import JSONSerializer from 'ember-data/serializers/json'; import normalizeModelName from 'ember-data/-private/system/normalize-model-name'; import { pluralize, singularize } from 'ember-inflector'; +import isEnabled from 'ember-data/-private/features'; var dasherize = Ember.String.dasherize; @@ -178,7 +179,11 @@ const JSONAPISerializer = JSONSerializer.extend({ */ pushPayload(store, payload) { let normalizedPayload = this._normalizeDocumentHelper(payload); - store.push(normalizedPayload); + if (isEnabled('ds-pushpayload-return')) { + return store.push(normalizedPayload); + } else { + store.push(normalizedPayload); + } }, /** diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 9abc42b302a..1e2eb5e937f 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -9,6 +9,7 @@ import normalizeModelName from "ember-data/-private/system/normalize-model-name" import {singularize} from "ember-inflector"; import coerceId from "ember-data/-private/system/coerce-id"; import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; +import isEnabled from 'ember-data/-private/features'; var camelize = Ember.String.camelize; @@ -403,7 +404,11 @@ var RESTSerializer = JSONSerializer.extend({ }); } - store.push(documentHash); + if (isEnabled('ds-pushpayload-return')) { + return store.push(documentHash); + } else { + store.push(documentHash); + } }, /** diff --git a/config/features.json b/config/features.json index 23d2aaf0f1b..1188f0b5d10 100644 --- a/config/features.json +++ b/config/features.json @@ -1,5 +1,6 @@ { "ds-finder-include": null, "ds-references": null, - "ds-transform-pass-options": null + "ds-transform-pass-options": null, + "ds-pushpayload-return": null } diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index 4abd31518f9..5055dfe9ad7 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -5,6 +5,8 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; + var env, store, Person, PhoneNumber, Post; var attr = DS.attr; var hasMany = DS.hasMany; @@ -668,6 +670,35 @@ test("Calling push with unknown keys should not warn by default", function(asser }, /The payload for 'person' contains these unknown keys: \[emailAddress,isMascot\]. Make sure they've been defined in your model./); }); +if (isEnabled('ds-pushpayload-return')) { + test("Calling pushPayload returns records", function(assert) { + env.registry.register('serializer:person', DS.RESTSerializer); + + var people; + + run(function() { + people = store.pushPayload('person', { + people: [{ + id: '1', + firstName: "Robert", + lastName: "Jackson" + }, { + id: '2', + firstName: "Matthew", + lastName: "Beale" + }] + }); + }); + + assert.equal(people.length, 2, "both records were returned by `store.pushPayload`"); + + assert.equal(people[0].get('firstName'), "Robert", "pushPayload returns pushed records"); + assert.equal(people[0].get('lastName'), "Jackson", "pushPayload returns pushed records"); + assert.equal(people[1].get('firstName'), "Matthew", "pushPayload returns pushed records"); + assert.equal(people[1].get('lastName'), "Beale", "pushPayload returns pushed records"); + }); +} + module("unit/store/push - DS.Store#push with JSON-API", { beforeEach() { var Person = DS.Model.extend({ From ee7bc80104df6a41f80c877a7ec0dd7a46d0b488 Mon Sep 17 00:00:00 2001 From: Dan McClain Date: Thu, 21 Jan 2016 20:56:49 -0500 Subject: [PATCH 1374/2527] [BUGFIX beta] Add ducktyping of `AdapterError` There are `instanceof` checks for `AdapterError` this removes them in favor of checking for a property on the error, `isAdapterError` appears on all errors that use `AdapterError` as the base. --- addon/-private/adapters/errors.js | 1 + addon/adapters/rest.js | 2 +- tests/unit/adapter-errors-test.js | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/addon/-private/adapters/errors.js b/addon/-private/adapters/errors.js index dc548243a4c..7a5d42af936 100644 --- a/addon/-private/adapters/errors.js +++ b/addon/-private/adapters/errors.js @@ -12,6 +12,7 @@ const PRIMARY_ATTRIBUTE_KEY = 'base'; @namespace DS */ export function AdapterError(errors, message = 'Adapter operation failed') { + this.isAdapterError = true; EmberError.call(this, message); this.errors = errors || [ diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index c7bc6c73adc..478f9196eca 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -853,7 +853,7 @@ export default Adapter.extend(BuildURLMixin, { requestData ); - if (response instanceof AdapterError) { + if (response && response.isAdapterError) { Ember.run.join(null, reject, response); } else { Ember.run.join(null, resolve, response); diff --git a/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js index 962fa1bcb7b..7ea5f43060a 100644 --- a/tests/unit/adapter-errors-test.js +++ b/tests/unit/adapter-errors-test.js @@ -10,24 +10,28 @@ test("DS.AdapterError", function(assert) { var error = new DS.AdapterError(); assert.ok(error instanceof Error); assert.ok(error instanceof Ember.Error); + assert.ok(error.isAdapterError); }); test("DS.InvalidError", function(assert) { var error = new DS.InvalidError(); assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); }); test("DS.TimeoutError", function(assert) { var error = new DS.TimeoutError(); assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); }); test("DS.AbortError", function(assert) { var error = new DS.AbortError(); assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); }); var errorsHash = { From e9c347adb9472c3a116f5bea7bf560325cce79ed Mon Sep 17 00:00:00 2001 From: Allen Hsu Date: Fri, 29 Jan 2016 16:56:57 +1100 Subject: [PATCH 1375/2527] Fix calls to keyForRelationship in embedded records --- addon/-private/serializers/embedded-records-mixin.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/serializers/embedded-records-mixin.js b/addon/-private/serializers/embedded-records-mixin.js index 2d231921ad6..451a80041c2 100644 --- a/addon/-private/serializers/embedded-records-mixin.js +++ b/addon/-private/serializers/embedded-records-mixin.js @@ -217,7 +217,7 @@ export default Ember.Mixin.create({ _serializeEmbeddedBelongsTo(snapshot, json, relationship) { let embeddedSnapshot = snapshot.belongsTo(relationship.key); - let serializedKey = this.keyForRelationship(relationship.key, 'serialize'); + let serializedKey = this.keyForRelationship(relationship.key, relationship.kind, 'serialize'); if (!embeddedSnapshot) { json[serializedKey] = null; } else { @@ -332,7 +332,7 @@ export default Ember.Mixin.create({ }, _serializeEmbeddedHasMany(snapshot, json, relationship) { - let serializedKey = this.keyForRelationship(relationship.key, 'serialize'); + let serializedKey = this.keyForRelationship(relationship.key, relationship.kind, 'serialize'); warn( `The embedded relationship '${serializedKey}' is undefined for '${snapshot.modelName}' with id '${snapshot.id}'. Please include it in your original payload.`, From e7193f632b73639579865821d9520d215cc91dd6 Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Tue, 2 Feb 2016 21:04:11 +0900 Subject: [PATCH 1376/2527] [BUGFIX beta] Add sha suffix to `DS.VERSION` for unreleased version --- lib/calculate-version.js | 14 +++++++++++--- package.json | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/calculate-version.js b/lib/calculate-version.js index 790a912429f..db2eb446447 100644 --- a/lib/calculate-version.js +++ b/lib/calculate-version.js @@ -1,10 +1,13 @@ var path = require('path'); var existsSync = require('exists-sync'); var gitRepoInfo = require('git-repo-info'); +var npmGitInfo = require('npm-git-info'); module.exports = function() { var gitPath = path.join(__dirname, '..', '.git'); - var packageVersion = require('../package.json').version; + var package = require('../package.json'); + var packageVersion = package.version; + var suffix = ''; if (existsSync(gitPath)) { var info = gitRepoInfo(gitPath); @@ -12,8 +15,13 @@ module.exports = function() { return info.tag.replace(/^v/, ''); } - return packageVersion + '+' + info.sha.slice(0, 10); + suffix = '+' + info.sha.slice(0, 10); } else { - return packageVersion; + var info = npmGitInfo(package); + if (info.isInstalledAsNpmPackage() && !info.hasVersionInRef()) { + suffix = '+' + info.abbreviatedSha; + } } + + return packageVersion + suffix; }; diff --git a/package.json b/package.json index 26ffb14e110..c015b26eaac 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "exists-sync": "0.0.3", "git-repo-info": "^1.1.2", "inflection": "^1.8.0", + "npm-git-info": "^1.0.0", "semver": "^5.1.0", "silent-error": "^1.0.0" }, From 29cee9089943c4ac126a8ba786111e4c8818c50e Mon Sep 17 00:00:00 2001 From: Ryunosuke SATO Date: Tue, 2 Feb 2016 21:58:39 +0900 Subject: [PATCH 1377/2527] [BUGFIX beta] Remove unused dev-dependency module --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 26ffb14e110..90bfa209344 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,6 @@ "ember-watson": "^0.7.0", "github": "^0.2.4", "glob": "^5.0.13", - "lodash.assign": "^3.2.0", "mocha": "^2.3.4", "mocha-only-detector": "0.0.2", "rimraf": "^2.3.2", From dce22e37735344eef3bd95a46a1196dc48fe2f8c Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Fri, 5 Feb 2016 19:20:24 -0700 Subject: [PATCH 1378/2527] [BUGFIX beta] Allow optional spaces when parsing response headers Fixes https://github.com/emberjs/data/issues/4122 - Allows header field-value without preceding whitespace - Removes leading/trailing whitespace from header field-names - Removes leading/trailing whitespace from header field-values - Moves `parseResponseHeaders` function out of `DS.RestAdapter` to its own module The main reason for moving to a module was to make it easier to unit test in order to document current behavior before making the fix. Let me know if this is undesirable. --- .../-private/utils/parse-response-headers.js | 26 +++++++ addon/adapters/rest.js | 22 +----- .../unit/utils/parse-response-headers-test.js | 67 +++++++++++++++++++ 3 files changed, 94 insertions(+), 21 deletions(-) create mode 100644 addon/-private/utils/parse-response-headers.js create mode 100644 tests/unit/utils/parse-response-headers-test.js diff --git a/addon/-private/utils/parse-response-headers.js b/addon/-private/utils/parse-response-headers.js new file mode 100644 index 00000000000..18112552d6b --- /dev/null +++ b/addon/-private/utils/parse-response-headers.js @@ -0,0 +1,26 @@ +import EmptyObject from 'ember-data/-private/system/empty-object'; + +const CLRF = '\u000d\u000a'; + +export default function parseResponseHeaders(headersString) { + let headers = new EmptyObject(); + + if (!headersString) { + return headers; + } + + let headerPairs = headersString.split(CLRF); + + headerPairs.forEach((header) => { + let [field, ...value] = header.split(':'); + + field = field.trim(); + value = value.join(':').trim(); + + if (value) { + headers[field] = value; + } + }); + + return headers; +} diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index cee4f7854d6..28b9f6a99c3 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -10,9 +10,9 @@ import { TimeoutError, AbortError } from 'ember-data/-private/adapters/errors'; -import EmptyObject from "ember-data/-private/system/empty-object"; import BuildURLMixin from "ember-data/-private/adapters/build-url-mixin"; import isEnabled from 'ember-data/-private/features'; +import parseResponseHeaders from 'ember-data/-private/utils/parse-response-headers'; const { MapWithDefault, @@ -1006,26 +1006,6 @@ export default Adapter.extend(BuildURLMixin, { } }); -function parseResponseHeaders(headerStr) { - var headers = new EmptyObject(); - if (!headerStr) { return headers; } - - var headerPairs = headerStr.split('\u000d\u000a'); - for (var i = 0; i < headerPairs.length; i++) { - var headerPair = headerPairs[i]; - // Can't use split() here because it does the wrong thing - // if the header value has the string ": " in it. - var index = headerPair.indexOf('\u003a\u0020'); - if (index > 0) { - var key = headerPair.substring(0, index); - var val = headerPair.substring(index + 2); - headers[key] = val; - } - } - - return headers; -} - //From http://stackoverflow.com/questions/280634/endswith-in-javascript function endsWith(string, suffix) { if (typeof String.prototype.endsWith !== 'function') { diff --git a/tests/unit/utils/parse-response-headers-test.js b/tests/unit/utils/parse-response-headers-test.js new file mode 100644 index 00000000000..98adef7bd14 --- /dev/null +++ b/tests/unit/utils/parse-response-headers-test.js @@ -0,0 +1,67 @@ +import EmptyObject from 'ember-data/-private/system/empty-object'; +import parseResponseHeaders from 'ember-data/-private/utils/parse-response-headers'; +import { module, test } from 'qunit'; + +const CRLF = '\u000d\u000a'; + +module('unit/adapters/parse-response-headers'); + +test('returns an EmptyObject when headersString is undefined', function(assert) { + let headers = parseResponseHeaders(undefined); + + assert.deepEqual(headers, new EmptyObject(), 'EmptyObject is returned'); +}); + +test('header parsing', function(assert) { + let headersString = [ + 'Content-Encoding: gzip', + 'content-type: application/json; charset=utf-8', + 'date: Fri, 05 Feb 2016 21:47:56 GMT' + ].join(CRLF); + + let headers = parseResponseHeaders(headersString); + + assert.equal(headers['Content-Encoding'], 'gzip', 'parses basic header pair'); + assert.equal(headers['content-type'], 'application/json; charset=utf-8', 'parses header with complex value'); + assert.equal(headers['date'], 'Fri, 05 Feb 2016 21:47:56 GMT', 'parses header with date value'); +}); + +test('field-name parsing', function(assert) { + let headersString = [ + ' name-with-leading-whitespace: some value', + 'name-with-whitespace-before-colon : another value' + ].join(CRLF); + + let headers = parseResponseHeaders(headersString); + + assert.equal(headers['name-with-leading-whitespace'], 'some value', 'strips leading whitespace from field-name'); + assert.equal(headers['name-with-whitespace-before-colon'], 'another value', 'strips whitespace before colon from field-name'); +}); + +test('field-value parsing', function(assert) { + let headersString = [ + 'value-with-leading-space: value with leading whitespace', + 'value-without-leading-space:value without leading whitespace', + 'value-with-colon: value with: a colon', + 'value-with-trailing-whitespace: banana ' + ].join(CRLF); + + let headers = parseResponseHeaders(headersString); + + assert.equal(headers['value-with-leading-space'], 'value with leading whitespace', 'strips leading whitespace in field-value'); + assert.equal(headers['value-without-leading-space'], 'value without leading whitespace', 'works without leaading whitespace in field-value'); + assert.equal(headers['value-with-colon'], 'value with: a colon', 'has correct value when value contains a colon'); + assert.equal(headers['value-with-trailing-whitespace'], 'banana', 'strips trailing whitespace from field-value'); +}); + +test('ignores headers that do not contain a colon', function(assert) { + let headersString = [ + 'Content-Encoding: gzip', + 'I am ignored because I do not contain a colon' + ].join(CRLF); + + let headers = parseResponseHeaders(headersString); + + assert.deepEqual(headers['Content-Encoding'], 'gzip', 'parses basic header pair'); + assert.equal(Object.keys(headers).length, 1, 'only has the one valid header'); +}); From 5529f0fb661c92177911aaa299e6aa23dab9ffe1 Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 8 Feb 2016 17:32:52 +0100 Subject: [PATCH 1379/2527] [BUGFIX beta] strip assertPolymorphicType in production builds This assert statement checks if a record is of the expected polymporhic type. Currently, this function is located in -private/utils and it is not stripped from production builds. Since this function only contains an `assert` (which gets stripped correctly), having this function in a production build is not a severe issue. Stripping it in production makes sense though since hereby we can get rid of superfluous calls and it minifies the build size :hammer: --- addon/-private/debug.js | 42 ++++++++++++++++++ .../-private/system/references/belongs-to.js | 2 +- addon/-private/system/references/has-many.js | 6 ++- .../system/relationships/state/belongs-to.js | 2 +- .../system/relationships/state/has-many.js | 2 +- addon/-private/utils.js | 44 ------------------- lib/stripped-build.js | 1 + tests/unit/utils-test.js | 2 +- 8 files changed, 51 insertions(+), 50 deletions(-) diff --git a/addon/-private/debug.js b/addon/-private/debug.js index ddd00cf17e1..0144e65c470 100644 --- a/addon/-private/debug.js +++ b/addon/-private/debug.js @@ -27,3 +27,45 @@ export function warn() { export function debugSeal() { return Ember.debugSeal(...arguments); } + +function checkPolymorphic(typeClass, addedRecord) { + if (typeClass.__isMixin) { + //TODO Need to do this in order to support mixins, should convert to public api + //once it exists in Ember + return typeClass.__mixin.detect(addedRecord.type.PrototypeMixin); + } + if (Ember.MODEL_FACTORY_INJECTIONS) { + typeClass = typeClass.superclass; + } + return typeClass.detect(addedRecord.type); +} + +/** + Assert that `addedRecord` has a valid type so it can be added to the + relationship of the `record`. + + The assert basically checks if the `addedRecord` can be added to the + relationship (specified via `relationshipMeta`) of the `record`. + + This utility should only be used internally, as both record parameters must + be an InternalModel and the `relationshipMeta` needs to be the meta + information about the relationship, retrieved via + `record.relationshipFor(key)`. + + @method assertPolymorphicType + @param {InternalModel} record + @param {RelationshipMeta} relationshipMeta retrieved via + `record.relationshipFor(key)` + @param {InternalModel} addedRecord record which + should be added/set for the relationship +*/ +export function assertPolymorphicType(record, relationshipMeta, addedRecord) { + var addedType = addedRecord.type.modelName; + var recordType = record.type.modelName; + var key = relationshipMeta.key; + var typeClass = record.store.modelFor(relationshipMeta.type); + + var assertionMessage = `You cannot add a record of type '${addedType}' to the '${recordType}.${key}' relationship (only '${typeClass.modelName}' allowed)`; + + assert(assertionMessage, checkPolymorphic(typeClass, addedRecord)); +} diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index b18b500beb0..c2909e98bb7 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -2,7 +2,7 @@ import Model from 'ember-data/model'; import Ember from 'ember'; import Reference from './reference'; -import { assertPolymorphicType } from "ember-data/-private/utils"; +import { assertPolymorphicType } from "ember-data/-private/debug"; var BelongsToReference = function(store, parentInternalModel, belongsToRelationship) { this._super$constructor(store, parentInternalModel); diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 7c0d9ae79ce..dc5fe98d616 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -1,7 +1,9 @@ import Ember from 'ember'; import Reference from './reference'; -import { assertPolymorphicType } from 'ember-data/-private/utils'; -import { runInDebug } from 'ember-data/-private/debug'; +import { + assertPolymorphicType, + runInDebug +} from 'ember-data/-private/debug'; const get = Ember.get; diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 3ab114c2a0b..0c5eb32ea81 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -4,7 +4,7 @@ import { PromiseObject } from "ember-data/-private/system/promise-proxies"; -import { assertPolymorphicType } from "ember-data/-private/utils"; +import { assertPolymorphicType } from "ember-data/-private/debug"; import Relationship from "ember-data/-private/system/relationships/state/relationship"; diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 432a3ada511..e435dedc996 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -4,7 +4,7 @@ import Relationship from "ember-data/-private/system/relationships/state/relatio import OrderedSet from "ember-data/-private/system/ordered-set"; import ManyArray from "ember-data/-private/system/many-array"; -import { assertPolymorphicType } from "ember-data/-private/utils"; +import { assertPolymorphicType } from "ember-data/-private/debug"; export default function ManyRelationship(store, record, inverseKey, relationshipMeta) { this._super$constructor(store, record, inverseKey, relationshipMeta); diff --git a/addon/-private/utils.js b/addon/-private/utils.js index 1ac7b254f71..a930180029e 100644 --- a/addon/-private/utils.js +++ b/addon/-private/utils.js @@ -1,50 +1,7 @@ import Ember from 'ember'; -import { assert } from "ember-data/-private/debug"; const get = Ember.get; -/** - Assert that `addedRecord` has a valid type so it can be added to the - relationship of the `record`. - - The assert basically checks if the `addedRecord` can be added to the - relationship (specified via `relationshipMeta`) of the `record`. - - This utility should only be used internally, as both record parameters must - be an InternalModel and the `relationshipMeta` needs to be the meta - information about the relationship, retrieved via - `record.relationshipFor(key)`. - - @method assertPolymorphicType - @param {InternalModel} record - @param {RelationshipMeta} relationshipMeta retrieved via - `record.relationshipFor(key)` - @param {InternalModel} addedRecord record which - should be added/set for the relationship -*/ -var assertPolymorphicType = function(record, relationshipMeta, addedRecord) { - var addedType = addedRecord.type.modelName; - var recordType = record.type.modelName; - var key = relationshipMeta.key; - var typeClass = record.store.modelFor(relationshipMeta.type); - - var assertionMessage = `You cannot add a record of type '${addedType}' to the '${recordType}.${key}' relationship (only '${typeClass.modelName}' allowed)`; - - assert(assertionMessage, checkPolymorphic(typeClass, addedRecord)); -}; - -function checkPolymorphic(typeClass, addedRecord) { - if (typeClass.__isMixin) { - //TODO Need to do this in order to support mixins, should convert to public api - //once it exists in Ember - return typeClass.__mixin.detect(addedRecord.type.PrototypeMixin); - } - if (Ember.MODEL_FACTORY_INJECTIONS) { - typeClass = typeClass.superclass; - } - return typeClass.detect(addedRecord.type); -} - /** Check if the passed model has a `type` attribute or a relationship named `type`. @@ -85,7 +42,6 @@ function getOwner(context) { } export { - assertPolymorphicType, modelHasAttributeOrRelationshipNamedType, getOwner }; diff --git a/lib/stripped-build.js b/lib/stripped-build.js index b26a38e7ecb..282e93bd9a3 100644 --- a/lib/stripped-build.js +++ b/lib/stripped-build.js @@ -27,6 +27,7 @@ module.exports = function(packageName, tree, _options) { filterImports({ 'ember-data/-private/debug': [ 'assert', + 'assertPolymorphicType', 'debug', 'deprecate', 'info', diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index 5e7009960e8..a8640b27003 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -6,7 +6,7 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; import Model from 'ember-data/model'; -import { assertPolymorphicType } from "ember-data/-private/utils"; +import { assertPolymorphicType } from "ember-data/-private/debug"; import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; var env, User, Message, Post, Person, Video, Medium; From 8dc694025e0a9d3de57c10609f483bf929d64fbf Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 9 Feb 2016 14:57:02 -0600 Subject: [PATCH 1380/2527] update changelog for 1.13.15 and 1.13.16 --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d240ac5ea5f..e2fb45829b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -255,6 +255,16 @@ In Ember Data 2.0 a record will no longer be removed from hasMany relationships - [#3567](https://github.com/emberjs/data/pull/3567) Use Ember.$ instead of jQuery for AJAX requests - [#3570](https://github.com/emberjs/data/pull/3570) Update `Ember.deprecate` and `Ember.warn` calls to include required information +### Release 1.13.16 (February 9, 2016) + +- [#4143](https://github.com/emberjs/data/pull/4143) Update Ember + Inflector and correct Ember Data's usage of it so that users' default + custom inflections work. + +### Release 1.13.15 (November 9, 2015) +- [#3876](https://github.com/emberjs/data/pull/3876) [BACKPORT] [BUGFIX beta] serialize type for embedded, polymorphic belongsTo +- [#3891](https://github.com/emberjs/data/pull/3891) Don't use Ember.create by default + ### Release 1.13.14 (October 18, 2015) - [#3665](https://github.com/emberjs/data/pull/3665) [BUGFIX beta] Fix usage of registry for 2.1.0+. - [#3825](https://github.com/emberjs/data/pull/3825) [BUGFIX] Restore IE8 compatibility by using Ember.create From 48fb5df2cc6f8fc219a0bc00fb4d74e0d73382a5 Mon Sep 17 00:00:00 2001 From: Adam Knights Date: Tue, 9 Feb 2016 11:14:11 +0000 Subject: [PATCH 1381/2527] [DOC] Document behavior of object level errors with JSON API --- addon/-private/system/model/errors.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index 438178750d3..c521c5d7e6c 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -96,6 +96,33 @@ var MapWithDefault = Ember.MapWithDefault; {{/each}} ``` + The JSON API spec also allows for object level errors to be placed + in an object with pointer `data`. + + ```javascript + { + "errors": [ + { + "detail": "Some generic non property error message", + "source": { + "pointer": "data" + } + } + ] + } + ``` + + You can access these errors by using the `base` property on the errors + object. + + ```handlebars + {{#each model.errors.base as |error|}} +
      + {{error.message}} +
      + {{/each}} + ``` + @class Errors @namespace DS @extends Ember.Object From 6091508fdea34fea01dd15d01647c23e2f9c5cce Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Wed, 10 Feb 2016 02:07:44 -0500 Subject: [PATCH 1382/2527] [BUGFIX beta] Fix key remapping for embedded records Closes #4068. This implements the same semantics for `key` that are used in JSONSerializer, for both belongsTo and hasMany embedded records. --- .../serializers/embedded-records-mixin.js | 12 +++- .../embedded-records-mixin-test.js | 66 +++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/addon/-private/serializers/embedded-records-mixin.js b/addon/-private/serializers/embedded-records-mixin.js index 451a80041c2..5c77b5eb340 100644 --- a/addon/-private/serializers/embedded-records-mixin.js +++ b/addon/-private/serializers/embedded-records-mixin.js @@ -217,7 +217,11 @@ export default Ember.Mixin.create({ _serializeEmbeddedBelongsTo(snapshot, json, relationship) { let embeddedSnapshot = snapshot.belongsTo(relationship.key); - let serializedKey = this.keyForRelationship(relationship.key, relationship.kind, 'serialize'); + var serializedKey = this._getMappedKey(relationship.key, snapshot.type); + if (serializedKey === relationship.key && this.keyForRelationship) { + serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); + } + if (!embeddedSnapshot) { json[serializedKey] = null; } else { @@ -332,7 +336,11 @@ export default Ember.Mixin.create({ }, _serializeEmbeddedHasMany(snapshot, json, relationship) { - let serializedKey = this.keyForRelationship(relationship.key, relationship.kind, 'serialize'); + var serializedKey = this._getMappedKey(relationship.key, snapshot.type); + if (serializedKey === relationship.key && this.keyForRelationship) { + serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); + } + warn( `The embedded relationship '${serializedKey}' is undefined for '${snapshot.modelName}' with id '${snapshot.id}'. Please include it in your original payload.`, diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index e6a9d98a242..e1f9e1e20ae 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -2145,3 +2145,69 @@ test("serializing belongsTo correctly removes embedded foreign key", function(as } }); }); + + +test("serializing embedded belongsTo respects remapped attrs key", function(assert) { + run(function() { + homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); + superVillain = env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); + }); + + env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + homePlanet: { embedded: 'always', key: 'favorite_place' } + } + })); + + var serializer = env.store.serializerFor("super-villain"); + var json; + + run(function() { + json = serializer.serialize(superVillain._createSnapshot()); + }); + + assert.deepEqual(json, { + firstName: "Ice", + lastName: "Creature", + favorite_place: { + name: "Hoth" + }, + secretLab: null + }); +}); + +test("serializing embedded hasMany respects remapped attrs key", function(assert) { + run(function() { + homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); + superVillain = env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); + }); + + env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always', key: 'notable_persons' } + } + })); + + env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + homePlanet: { serialize: false }, + secretLab: { serialize: false } + } + })); + + + var serializer = env.store.serializerFor("home-planet"); + var json; + + run(function() { + json = serializer.serialize(homePlanet._createSnapshot()); + }); + + assert.deepEqual(json, { + name: "Hoth", + notable_persons: [{ + firstName: 'Ice', + lastName: 'Creature' + }] + }); +}); From e51dd76c50b943c3342589c3abfc8bc6ec03b8ed Mon Sep 17 00:00:00 2001 From: Sylvain MINA Date: Thu, 11 Feb 2016 09:06:43 +0100 Subject: [PATCH 1383/2527] Remove extra definition of InvalidError --- addon/-private/system/model/errors/invalid.js | 84 ------------------- 1 file changed, 84 deletions(-) delete mode 100644 addon/-private/system/model/errors/invalid.js diff --git a/addon/-private/system/model/errors/invalid.js b/addon/-private/system/model/errors/invalid.js deleted file mode 100644 index 00cf7bc3c16..00000000000 --- a/addon/-private/system/model/errors/invalid.js +++ /dev/null @@ -1,84 +0,0 @@ -import Ember from 'ember'; -var EmberError = Ember.Error; - -/** - A `DS.InvalidError` is used by an adapter to signal the external API - was unable to process a request because the content was not - semantically correct or meaningful per the API. Usually this means a - record failed some form of server side validation. When a promise - from an adapter is rejected with a `DS.InvalidError` the record will - transition to the `invalid` state and the errors will be set to the - `errors` property on the record. - - For Ember Data to correctly map errors to their corresponding - properties on the model, Ember Data expects each error to be - namespaced under a key that matches the property name. For example - if you had a Post model that looked like this. - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - title: DS.attr('string'), - content: DS.attr('string') - }); - ``` - - To show an error from the server related to the `title` and - `content` properties your adapter could return a promise that - rejects with a `DS.InvalidError` object that looks like this: - - ```app/adapters/post.js - import Ember from 'ember'; - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - updateRecord: function() { - // Fictional adapter that always rejects - return Ember.RSVP.reject(new DS.InvalidError({ - title: ['Must be unique'], - content: ['Must not be blank'], - })); - } - }); - ``` - - Your backend may use different property names for your records the - store will attempt extract and normalize the errors using the - serializer's `extractErrors` method before the errors get added to - the the model. As a result, it is safe for the `InvalidError` to - wrap the error payload unaltered. - - Example - - ```app/adapters/application.js - import Ember from 'ember'; - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - ajaxError: function(jqXHR) { - var error = this._super(jqXHR); - - // 422 is used by this fictional server to signal a validation error - if (jqXHR && jqXHR.status === 422) { - var jsonErrors = Ember.$.parseJSON(jqXHR.responseText); - return new DS.InvalidError(jsonErrors); - } else { - // The ajax request failed however it is not a result of this - // record being in an invalid state so we do not return a - // `InvalidError` object. - return error; - } - } - }); - ``` - - @class InvalidError - @namespace DS -*/ -export default function InvalidError(errors) { - EmberError.call(this, "The backend rejected the commit because it was invalid: " + Ember.inspect(errors)); - this.errors = errors; -} - -InvalidError.prototype = Object.create(EmberError.prototype); From 23defc2d3c4bcb6b5bf0f0634e9f59cb013b7912 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 28 Jan 2016 18:54:41 +0100 Subject: [PATCH 1384/2527] [BUGFIX beta] Export more public API's via modules This change allows to import more public API's via modules: - import Serializer from "ember-data/serializer" - import EmbeddedRecords from "ember-data/serializers/embedded-records-mixin" --- addon/index.js | 4 +- addon/{-private/system => }/serializer.js | 0 .../serializers/embedded-records-mixin.js | 0 addon/serializers/json.js | 2 +- lib/ember-data-shims.js | 2 + tests/unit/modules-test.js | 74 +++++++++++++++++++ 6 files changed, 79 insertions(+), 3 deletions(-) rename addon/{-private/system => }/serializer.js (100%) rename addon/{-private => }/serializers/embedded-records-mixin.js (100%) create mode 100644 tests/unit/modules-test.js diff --git a/addon/index.js b/addon/index.js index 7135ca97846..33a31a9ff95 100644 --- a/addon/index.js +++ b/addon/index.js @@ -40,7 +40,7 @@ import { import Model from "ember-data/model"; import Snapshot from "ember-data/-private/system/snapshot"; import Adapter from "ember-data/adapter"; -import Serializer from "ember-data/-private/system/serializer"; +import Serializer from "ember-data/serializer"; import DebugAdapter from "ember-data/-private/system/debug"; import { @@ -70,7 +70,7 @@ import { RESTSerializer } from "ember-data/-private/serializers"; import "ember-inflector"; -import EmbeddedRecordsMixin from "ember-data/-private/serializers/embedded-records-mixin"; +import EmbeddedRecordsMixin from "ember-data/serializers/embedded-records-mixin"; import { Transform, diff --git a/addon/-private/system/serializer.js b/addon/serializer.js similarity index 100% rename from addon/-private/system/serializer.js rename to addon/serializer.js diff --git a/addon/-private/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js similarity index 100% rename from addon/-private/serializers/embedded-records-mixin.js rename to addon/serializers/embedded-records-mixin.js diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 330c7b90930..84c334643be 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1,6 +1,6 @@ import Ember from 'ember'; import { assert, warn } from 'ember-data/-private/debug'; -import Serializer from "ember-data/-private/system/serializer"; +import Serializer from "ember-data/serializer"; import coerceId from "ember-data/-private/system/coerce-id"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; diff --git a/lib/ember-data-shims.js b/lib/ember-data-shims.js index 50ddf3e47ac..dcb9bbb3236 100644 --- a/lib/ember-data-shims.js +++ b/lib/ember-data-shims.js @@ -3,10 +3,12 @@ var shims = { 'ember-data': { default: DS }, 'ember-data/model': { default: DS.Model }, + 'ember-data/mixins/embedded-records': { default: DS.EmbeddedRecordsMixin }, 'ember-data/serializers/rest': { default: DS.RESTSerializer }, 'ember-data/serializers/active-model': { default: DS.ActiveModelSerializer }, 'ember-data/serializers/json': { default: DS.JSONSerializer }, 'ember-data/serializers/json-api': { default: DS.JSONAPISerializer }, + 'ember-data/serializer': { default: DS.Serializer }, 'ember-data/adapters/json-api': { default: DS.JSONAPIAdapter }, 'ember-data/adapters/rest': { default: DS.RESTAdapter }, 'ember-data/adapter': { default: DS.Adapter }, diff --git a/tests/unit/modules-test.js b/tests/unit/modules-test.js new file mode 100644 index 00000000000..9249ac78323 --- /dev/null +++ b/tests/unit/modules-test.js @@ -0,0 +1,74 @@ +import { module, test } from 'qunit'; + +import Transform from "ember-data/transform"; + +import Adapter from "ember-data/adapter"; +import JSONAPIAdapter from "ember-data/adapters/json-api"; +import RESTAdapter from "ember-data/adapters/rest"; + +import Store from "ember-data/store"; + +import Model from "ember-data/model"; +import attr from "ember-data/attr"; +import { belongsTo, hasMany } from "ember-data/relationships"; + +import Serializer from "ember-data/serializer"; +import JSONSerializer from "ember-data/serializers/json"; +import JSONAPISerializer from "ember-data/serializers/json-api"; +import RESTSerializer from "ember-data/serializers/rest"; +import EmbeddedRecordsMixin from "ember-data/serializers/embedded-records-mixin"; + +module("unit/modules - public modules"); + +test("ember-data/transform", function(assert) { + assert.ok(Transform); +}); + +test("ember-data/adapter", function(assert) { + assert.ok(Adapter); +}); + +test("ember-data/adapters/json-api", function(assert) { + assert.ok(JSONAPIAdapter); +}); + +test("ember-data/adapters/rest", function(assert) { + assert.ok(RESTAdapter); +}); + +test("ember-data/attr", function(assert) { + assert.ok(attr); +}); + +test("ember-data/relationships", function(assert) { + assert.ok(belongsTo); + assert.ok(hasMany); +}); + +test("ember-data/store", function(assert) { + assert.ok(Store); +}); + +test("ember-data/model", function(assert) { + assert.ok(Model); +}); + +test("ember-data/mixins/embedded-records", function(assert) { + assert.ok(EmbeddedRecordsMixin); +}); + +test("ember-data/serializer", function(assert) { + assert.ok(Serializer); +}); + +test("ember-data/serializers/json-api", function(assert) { + assert.ok(JSONAPISerializer); +}); + +test("ember-data/serializers/json", function(assert) { + assert.ok(JSONSerializer); +}); + +test("ember-data/serializers/rest", function(assert) { + assert.ok(RESTSerializer); +}); From 617f5a6329fa0e4234e3a31a9719e40b903eb524 Mon Sep 17 00:00:00 2001 From: James Murphy Date: Fri, 5 Feb 2016 15:47:05 +1100 Subject: [PATCH 1385/2527] Fix global require The global require in this file was causing an error when using babel 6 with the transform-es2015-modules-amd plugin fixes #4134 --- addon/-private/system/relationships/has-many.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index a5de409cb91..8cf881730d3 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -2,6 +2,7 @@ @module ember-data */ + import Ember from 'ember'; import { assert } from "ember-data/-private/debug"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; @@ -145,10 +146,9 @@ export default function hasMany(type, options) { return relationship.getRecords(); }, set(key, records) { - var Model = require('ember-data/model').default; assert("You must pass an array of records to set a hasMany relationship", isArrayLike(records)); assert(`All elements of a hasMany relationship must be instances of DS.Model, you passed ${Ember.inspect(records)}`, (function() { - return Ember.A(records).every((record) => Model.detectInstance(record) ); + return Ember.A(records).every((record) => record.hasOwnProperty('_internalModel') === true); })()); var relationship = this._internalModel._relationships.get(key); From d0334a62081b9e11a79e78e1648cb1efd01b39bf Mon Sep 17 00:00:00 2001 From: Sylvain MINA Date: Thu, 11 Feb 2016 12:01:48 +0100 Subject: [PATCH 1386/2527] calling reload multiple times on a has many triggers only one request --- .../system/relationships/state/has-many.js | 15 ++--- .../relationships/has-many-test.js | 65 +++++++++++++++++++ 2 files changed, 72 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index e435dedc996..bae53b3bc8d 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -1,5 +1,5 @@ import { assert } from "ember-data/-private/debug"; -import { PromiseManyArray } from "ember-data/-private/system/promise-proxies"; +import { PromiseManyArray, promiseManyArray } from "ember-data/-private/system/promise-proxies"; import Relationship from "ember-data/-private/system/relationships/state/relationship"; import OrderedSet from "ember-data/-private/system/ordered-set"; import ManyArray from "ember-data/-private/system/many-array"; @@ -99,7 +99,6 @@ ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) }; ManyRelationship.prototype.reload = function() { - var self = this; var manyArrayLoadedState = this.manyArray.get('isLoaded'); if (this._loadingPromise) { @@ -112,13 +111,13 @@ ManyRelationship.prototype.reload = function() { } if (this.link) { - return this.fetchLink(); + this._loadingPromise = promiseManyArray(this.fetchLink(), 'Reload with link'); + return this._loadingPromise; } else { - return this.store.scheduleFetchMany(this.manyArray.toArray()).then(function() { - //Goes away after the manyArray refactor - self.manyArray.set('isLoaded', true); - return self.manyArray; - }); + this._loadingPromise = promiseManyArray(this.store.scheduleFetchMany(this.manyArray.toArray()).then(() => { + return this.manyArray; + }), 'Reload with ids'); + return this._loadingPromise; } }; diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 610d616e4ef..caa94562e3f 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -627,6 +627,38 @@ test("A hasMany relationship can be directly reloaded if it was fetched via link }); }); +test("Has many via links - Calling reload multiple times does not send a new request if the first one is not settled", function(assert) { + assert.expect(1); + let done = assert.async(); + + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + env.adapter.findRecord = function(store, type, id) { + return Ember.RSVP.resolve({ id: 1, links: { comments: "/posts/1/comments" } }); + }; + + let count = 0; + env.adapter.findHasMany = function(store, record, link, relationship) { + count++; + return Ember.RSVP.resolve([ + { id: 1, body: "First" }, + { id: 2, body: "Second" } + ]); + }; + run(function() { + env.store.findRecord('post', 1).then(function(post) { + post.get('comments').then(function(comments) { + Ember.RSVP.all([comments.reload(), comments.reload(), comments.reload()]).then(function(comments) { + assert.equal(count, 2, "One request for the original access and only one request for the mulitple reloads"); + done(); + }); + }); + }); + }); +}); + test("A hasMany relationship can be directly reloaded if it was fetched via ids", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) @@ -657,6 +689,39 @@ test("A hasMany relationship can be directly reloaded if it was fetched via ids" }); }); +test("Has many via ids - Calling reload multiple times does not send a new request if the first one is not settled", function(assert) { + assert.expect(1); + let done = assert.async(); + + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + env.adapter.findRecord = function(store, type, id, snapshot) { + return Ember.RSVP.resolve({ id: 1, comments: [1,2] }); + }; + + let count = 0; + env.adapter.findMany = function(store, type, ids, snapshots) { + count++; + return Ember.RSVP.resolve([ + { id: 1, body: "FirstUpdated" }, + { id: 2, body: "Second" } + ]); + }; + + run(function() { + env.store.findRecord('post', 1).then(function(post) { + post.get('comments').then(function(comments) { + Ember.RSVP.all([comments.reload(), comments.reload(), comments.reload()]).then(function(comments) { + assert.equal(count, 2, "One request for the original access and only one request for the mulitple reloads"); + done(); + }); + }); + }); + }); +}); + test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loaded", function(assert) { assert.expect(4); From 86424a30a01f51aeeb383f58bc1fe9a0c79f8148 Mon Sep 17 00:00:00 2001 From: Sylvain MINA Date: Thu, 11 Feb 2016 16:43:04 +0100 Subject: [PATCH 1387/2527] remove container related deprecation warnings --- tests/helpers/owner.js | 11 +++++++++++ tests/helpers/store.js | 12 +++++++++--- tests/integration/references/has-many-test.js | 2 +- 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 tests/helpers/owner.js diff --git a/tests/helpers/owner.js b/tests/helpers/owner.js new file mode 100644 index 00000000000..f4037cda0e4 --- /dev/null +++ b/tests/helpers/owner.js @@ -0,0 +1,11 @@ +import Ember from 'ember'; + +let Owner; + +if (Ember._RegistryProxyMixin && Ember._ContainerProxyMixin) { + Owner = Ember.Object.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin); +} else { + Owner = Ember.Object.extend(); +} + +export default Owner; diff --git a/tests/helpers/store.js b/tests/helpers/store.js index 96deb9ab69b..a2a4ef22545 100644 --- a/tests/helpers/store.js +++ b/tests/helpers/store.js @@ -1,14 +1,21 @@ import Ember from 'ember'; import DS from 'ember-data'; +import Owner from './owner'; export default function setupStore(options) { - var container, registry; + var container, registry, owner; var env = {}; options = options || {}; if (Ember.Registry) { registry = env.registry = new Ember.Registry(); - container = env.container = registry.container(); + owner = Owner.create({ + __registry__: registry + }); + container = env.container = registry.container({ + owner: owner + }); + owner.__container__ = container; } else { container = env.container = new Ember.Container(); registry = env.registry = container; @@ -63,4 +70,3 @@ export {setupStore}; export function createStore(options) { return setupStore(options).store; } - diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index f1a27e18c6b..a94ab28eb65 100644 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -171,7 +171,7 @@ if (isEnabled("ds-references")) { test("push(array) works with polymorphic type", function(assert) { var done = assert.async(); - env.container.register('model:mafia-boss', Person.extend()); + env.registry.register('model:mafia-boss', Person.extend()); var family; run(function() { From 8abacbeb8fe8b0c82efbbad3825c87c1d5558954 Mon Sep 17 00:00:00 2001 From: Chris Krycho Date: Fri, 12 Feb 2016 09:14:50 -0500 Subject: [PATCH 1388/2527] Mark store.filter as deprecated in JSDoc. --- addon/-private/system/store.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index f2a44beb630..a967e07eb17 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1196,6 +1196,7 @@ Store = Service.extend({ @param {Object} query optional query @param {Function} filter @return {DS.PromiseArray} + @deprecated */ filter(modelName, query, filter) { assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); From f32a51a26e8072585bb5a7e89845069f9a758f0e Mon Sep 17 00:00:00 2001 From: Joshua Bailey Date: Fri, 12 Feb 2016 14:01:33 -0500 Subject: [PATCH 1389/2527] Fixes broken link Previously the link to the emberjs guides on customizing adapters was broken, this fix points to the correct link for the current stable version of emberjs an ember data. --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 3d321b591ef..c38631df26f 100644 --- a/README.md +++ b/README.md @@ -139,8 +139,7 @@ set of RESTful JSON conventions. To learn more about adapters, including what conventions the `RESTAdapter` follows and how to build your own, see the Ember.js -Guides: [Connecting to an HTTP -Server](http://emberjs.com/guides/models/connecting-to-an-http-server/). +Guides: [Customizing Adapters](https://guides.emberjs.com/v2.3.0/models/customizing-adapters/). ### Fetching a Collection of Models From d9c62c4c3bb809069f30dd54fdf75a84af81f49f Mon Sep 17 00:00:00 2001 From: Olivier Chatry Date: Thu, 11 Feb 2016 15:23:37 +0100 Subject: [PATCH 1390/2527] [BUGFIX beta] fixes #4149, new record does not added twice in many --- addon/-private/system/many-array.js | 4 +- .../relationships/has-many-test.js | 58 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index ac0c32d5a6b..c3d0b0b6f7f 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -78,7 +78,9 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { //a hack for not removing new records //TODO remove once we have proper diffing - var newRecords = this.currentState.filter((internalModel) => internalModel.isNew()); + var newRecords = this.currentState.filter( + (internalModel) => internalModel.isNew() && toSet.indexOf(internalModel) === -1 + ); toSet = toSet.concat(newRecords); var oldLength = this.length; this.arrayContentWillChange(0, this.length, toSet.length); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 610d616e4ef..3183000fccc 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -414,6 +414,64 @@ test("A hasMany updated link should not remove new children when the parent reco }); }); +test("A hasMany updated link should not remove new children when the parent record has children already with feedback from the server after save", function(assert) { + + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + Comment.reopen({ + message: DS.belongsTo('post', { async: true }) + }); + + env.adapter.createRecord = function(store, snapshot, link, relationship) { + return Ember.RSVP.resolve({ + id: 5 + }); + }; + + + env.adapter.findHasMany = function(store, snapshot, link, relationship) { + return Ember.RSVP.resolve([{ id: 5 }]); + }; + + + run(function() { + var post = env.store.createRecord('post', {}); + env.store.createRecord('comment', { id: 5, message: post }); + + post.get('comments') + .then(function(comments) { + assert.equal(comments.get('length'), 1); + return post.save(); + }) + .then(function() { + return env.store.push({ + data: { + type: "post", + id: 5, + relationships: { + comments: { + data: [ + { + id: 5, + type: "comment" + } + ] + } + } + } + }); + }) + .then(function() { + return post.get('comments'); + }) + .then(function(comments) { + assert.equal(comments.get('length'), 1); + }); + }); +}); + test("A hasMany relationship can be reloaded if it was fetched via a link", function(assert) { Post.reopen({ From 377e7f1a5e27bc6b9d9717b1f926e68d0c370216 Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 15 Feb 2016 19:58:41 +0100 Subject: [PATCH 1391/2527] [CLEANUP] remove `toString` definitions for models in tests My string theory: the definitions for `toString` are a relict from the pre-container era where this might have been needed. :barber: This makes the recently failing builds for `master` green again. :green_apple: --- Note: the tests were failing since `2.3.1` ember seals `Mixin` so adding stuff after `create` will error out. --- tests/integration/adapter/build-url-mixin-test.js | 4 ---- .../adapter/record-persistence-test.js | 1 - tests/integration/adapter/rest-adapter-test.js | 4 ---- tests/integration/debug-adapter-test.js | 1 - tests/integration/record-array-manager-test.js | 4 ---- tests/integration/records/collection-save-test.js | 2 -- tests/integration/records/delete-record-test.js | 2 -- tests/integration/records/error-test.js | 1 - tests/integration/records/load-test.js | 3 --- .../integration/records/property-changes-test.js | 1 - tests/integration/records/reload-test.js | 2 -- tests/integration/records/save-test.js | 2 -- tests/integration/records/unload-test.js | 6 ------ tests/integration/relationships/has-many-test.js | 10 ---------- .../relationships/many-to-many-test.js | 10 ---------- .../integration/relationships/one-to-many-test.js | 7 ------- .../integration/relationships/one-to-one-test.js | 6 ------ .../polymorphic-mixins-belongs-to-test.js | 6 ------ .../polymorphic-mixins-has-many-test.js | 6 ------ tests/integration/store-test.js | 4 ---- tests/unit/many-array-test.js | 6 ------ tests/unit/model/relationships/belongs-to-test.js | 15 --------------- tests/unit/model/relationships/has-many-test.js | 7 ------- tests/unit/store/has-record-for-id-test.js | 6 ------ tests/unit/store/peek-record-test.js | 3 --- tests/unit/store/push-test.js | 13 ------------- 26 files changed, 132 deletions(-) diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index 7f6bf98e67c..cb5ce7f4ae9 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -15,10 +15,6 @@ module("integration/adapter/build-url-mixin - BuildURLMixin with RESTAdapter", { name: DS.attr("string") }); - Post.toString = function() { - return "Post"; - }; - Comment = DS.Model.extend({ name: DS.attr("string") }); diff --git a/tests/integration/adapter/record-persistence-test.js b/tests/integration/adapter/record-persistence-test.js index 51b770a081d..289976dac5f 100644 --- a/tests/integration/adapter/record-persistence-test.js +++ b/tests/integration/adapter/record-persistence-test.js @@ -22,7 +22,6 @@ module("integration/adapter/record_persistence - Persisting Records", { firstName: attr('string'), lastName: attr('string') }); - Person.toString = function() { return "Person"; }; env = setupStore({ adapter: DS.Adapter.extend({ diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 3103a6adfc3..36251d94c2b 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -17,10 +17,6 @@ module("integration/adapter/rest_adapter - REST Adapter", { name: DS.attr("string") }); - Post.toString = function() { - return "Post"; - }; - Comment = DS.Model.extend({ name: DS.attr("string") }); diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index b8636ce14c2..c152247f3b4 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -12,7 +12,6 @@ module("DS.DebugAdapter", { beforeEach() { Ember.run(function() { App = Ember.Application.create(); - App.toString = function() { return 'App'; }; App.StoreService = DS.Store.extend({}); diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index 55ead281254..c62003a0284 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -13,16 +13,12 @@ var Person = DS.Model.extend({ cars: DS.hasMany('car', { async: false }) }); -Person.toString = function() { return "Person"; }; - var Car = DS.Model.extend({ make: DS.attr('string'), model: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); -Car.toString = function() { return "Car"; }; - var manager; module("integration/record_array_manager", { diff --git a/tests/integration/records/collection-save-test.js b/tests/integration/records/collection-save-test.js index cf35717c74d..779afd1c4b0 100644 --- a/tests/integration/records/collection-save-test.js +++ b/tests/integration/records/collection-save-test.js @@ -14,8 +14,6 @@ module("integration/records/collection_save - Save Collection of Records", { title: DS.attr('string') }); - Post.toString = function() { return "Post"; }; - env = setupStore({ post: Post }); }, diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index 54e9a86b8ff..5b2e580c232 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -15,8 +15,6 @@ module("integration/deletedRecord - Deleting Records", { name: attr('string') }); - Person.toString = function() { return "Person"; }; - env = setupStore({ person: Person }); diff --git a/tests/integration/records/error-test.js b/tests/integration/records/error-test.js index 47db5ef8f6d..0c8e1bfe77d 100644 --- a/tests/integration/records/error-test.js +++ b/tests/integration/records/error-test.js @@ -13,7 +13,6 @@ module('integration/records/error', { firstName: attr('string'), lastName: attr('string') }); - Person.toString = function() { return 'Person'; }; env = setupStore({ person: Person diff --git a/tests/integration/records/load-test.js b/tests/integration/records/load-test.js index c2dd0dd7eb5..d3e4b96b2fe 100644 --- a/tests/integration/records/load-test.js +++ b/tests/integration/records/load-test.js @@ -17,9 +17,6 @@ module("integration/load - Loading Records", { Comment = DS.Model.extend(); - Post.toString = function() { return "Post"; }; - Comment.toString = function() { return "Comment"; }; - env = setupStore({ post: Post, comment: Comment }); }, diff --git a/tests/integration/records/property-changes-test.js b/tests/integration/records/property-changes-test.js index 212fd19f3c7..55c688c85bf 100644 --- a/tests/integration/records/property-changes-test.js +++ b/tests/integration/records/property-changes-test.js @@ -15,7 +15,6 @@ module('integration/records/property-changes - Property changes', { firstName: attr('string'), lastName: attr('string') }); - Person.toString = function() { return 'Person'; }; env = setupStore({ person: Person diff --git a/tests/integration/records/reload-test.js b/tests/integration/records/reload-test.js index 4e5af020d77..c5aedf2f05c 100644 --- a/tests/integration/records/reload-test.js +++ b/tests/integration/records/reload-test.js @@ -19,8 +19,6 @@ module("integration/reload - Reloading Records", { lastName: attr('string') }); - Person.toString = function() { return "Person"; }; - env = setupStore({ person: Person }); }, diff --git a/tests/integration/records/save-test.js b/tests/integration/records/save-test.js index b467c676e01..99125f1413a 100644 --- a/tests/integration/records/save-test.js +++ b/tests/integration/records/save-test.js @@ -14,8 +14,6 @@ module("integration/records/save - Save Record", { title: DS.attr('string') }); - Post.toString = function() { return "Post"; }; - env = setupStore({ post: Post }); }, diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 2a145a02047..9ff6366f92e 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -16,22 +16,16 @@ var Person = DS.Model.extend({ cars: hasMany('car', { async: false }) }); -Person.toString = function() { return "Person"; }; - var Group = DS.Model.extend({ people: hasMany('person', { async: false }) }); -Group.toString = function() { return "Group"; }; - var Car = DS.Model.extend({ make: attr('string'), model: attr('string'), person: belongsTo('person', { async: false }) }); -Car.toString = function() { return "Car"; }; - module("integration/unload - Unloading Records", { beforeEach() { env = setupStore({ diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 610d616e4ef..b9844528727 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -15,10 +15,6 @@ var attr = DS.attr; var hasMany = DS.hasMany; var belongsTo = DS.belongsTo; -function stringify(string) { - return function() { return string; }; -} - module("integration/relationships/has_many - Has-Many Relationships", { beforeEach() { User = DS.Model.extend({ @@ -43,37 +39,31 @@ module("integration/relationships/has_many - Has-Many Relationships", { user: belongsTo('user', { async: false }), created_at: attr('date') }); - Message.toString = stringify('Message'); Post = Message.extend({ title: attr('string'), comments: hasMany('comment', { async: false }) }); - Post.toString = stringify('Post'); Comment = Message.extend({ body: DS.attr('string'), message: DS.belongsTo('post', { polymorphic: true, async: true }) }); - Comment.toString = stringify('Comment'); Book = DS.Model.extend({ title: attr(), chapters: hasMany('chapter', { async: true }) }); - Book.toString = stringify('Book'); Chapter = DS.Model.extend({ title: attr(), pages: hasMany('page', { async: false }) }); - Chapter.toString = stringify('Chapter'); Page = DS.Model.extend({ number: attr('number'), chapter: belongsTo('chapter', { async: false }) }); - Page.toString = stringify('Page'); env = setupStore({ user: User, diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index e2eb3499bfb..f2068758895 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -11,10 +11,6 @@ var run = Ember.run; var attr = DS.attr; var hasMany = DS.hasMany; -function stringify(string) { - return function() { return string; }; -} - module('integration/relationships/many_to_many_test - ManyToMany relationships', { beforeEach() { User = DS.Model.extend({ @@ -23,22 +19,16 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships', accounts: hasMany('account', { async: false }) }); - User.toString = stringify('User'); - Account = DS.Model.extend({ state: attr(), users: hasMany('user', { async: false }) }); - Account.toString = stringify('Account'); - Topic = DS.Model.extend({ title: attr('string'), users: hasMany('user', { async: true }) }); - Topic.toString = stringify('Topic'); - env = setupStore({ user: User, topic: Topic, diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index d9eb6f073dd..3b32698bfbf 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -13,10 +13,6 @@ var attr = DS.attr; var hasMany = DS.hasMany; var belongsTo = DS.belongsTo; -function stringify(string) { - return function() { return string; }; -} - module('integration/relationships/one_to_many_test - OneToMany relationships', { beforeEach() { User = DS.Model.extend({ @@ -24,19 +20,16 @@ module('integration/relationships/one_to_many_test - OneToMany relationships', { messages: hasMany('message', { async: true }), accounts: hasMany('account', { async: false }) }); - User.toString = stringify('User'); Account = DS.Model.extend({ state: attr(), user: belongsTo('user', { async: false }) }); - Account.toString = stringify('Account'); Message = DS.Model.extend({ title: attr('string'), user: belongsTo('user', { async: true }) }); - Message.toString = stringify('Message'); env = setupStore({ user: User, diff --git a/tests/integration/relationships/one-to-one-test.js b/tests/integration/relationships/one-to-one-test.js index 500eec53a81..79dbd81f808 100644 --- a/tests/integration/relationships/one-to-one-test.js +++ b/tests/integration/relationships/one-to-one-test.js @@ -11,10 +11,6 @@ var run = Ember.run; var attr = DS.attr; var belongsTo = DS.belongsTo; -function stringify(string) { - return function() { return string; }; -} - module('integration/relationships/one_to_one_test - OneToOne relationships', { beforeEach() { User = DS.Model.extend({ @@ -22,13 +18,11 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', { bestFriend: belongsTo('user', { async: true, inverse: 'bestFriend' }), job: belongsTo('job', { async: false }) }); - User.toString = stringify('User'); Job = DS.Model.extend({ isGood: attr(), user: belongsTo('user', { async: false }) }); - Job.toString = stringify('Job'); env = setupStore({ user: User, diff --git a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index 7be85133732..661ed9514f8 100644 --- a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -11,23 +11,17 @@ var run = Ember.run; var attr = DS.attr; var belongsTo = DS.belongsTo; -function stringify(string) { - return function() { return string; }; -} - module('integration/relationships/polymorphic_mixins_belongs_to_test - Polymorphic belongsTo relationships with mixins', { beforeEach() { User = DS.Model.extend({ name: attr('string'), bestMessage: belongsTo('message', { async: true, polymorphic: true }) }); - User.toString = stringify('User'); Message = Ember.Mixin.create({ title: attr('string'), user: belongsTo('user', { async: true }) }); - Message.toString = stringify('Message'); NotMessage = DS.Model.extend({ video: attr() diff --git a/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js index ef06a8bb159..2cbe646420e 100644 --- a/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -12,23 +12,17 @@ var attr = DS.attr; var hasMany = DS.hasMany; var belongsTo = DS.belongsTo; -function stringify(string) { - return function() { return string; }; -} - module('integration/relationships/polymorphic_mixins_has_many_test - Polymorphic hasMany relationships with mixins', { beforeEach() { User = DS.Model.extend({ name: attr('string'), messages: hasMany('message', { async: true, polymorphic: true }) }); - User.toString = stringify('User'); Message = Ember.Mixin.create({ title: attr('string'), user: belongsTo('user', { async: true }) }); - Message.toString = stringify('Message'); Video = DS.Model.extend(Message, { video: attr() diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index e7e5b81a35f..c9f36478016 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -14,16 +14,12 @@ var Person = DS.Model.extend({ var run = Ember.run; -Person.toString = function() { return "Person"; }; - var Car = DS.Model.extend({ make: DS.attr('string'), model: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); -Car.toString = function() { return "Car"; }; - function initializeStore(adapter) { env = setupStore({ adapter: adapter diff --git a/tests/unit/many-array-test.js b/tests/unit/many-array-test.js index 1ef1edf24e7..969acd15128 100644 --- a/tests/unit/many-array-test.js +++ b/tests/unit/many-array-test.js @@ -19,17 +19,11 @@ module("unit/many_array - DS.ManyArray", { title: attr('string'), tags: hasMany('tag', { async: false }) }); - Post.toString = function() { - return 'Post'; - }; Tag = DS.Model.extend({ name: attr('string'), post: belongsTo('post', { async: false }) }); - Tag.toString = function() { - return 'Tag'; - }; env = setupStore({ post: Post, diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index 8e71da3fa46..b4fd713e679 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -17,13 +17,11 @@ test("belongsTo lazily loads relationships as needed", function(assert) { name: DS.attr('string'), people: DS.hasMany('person', { async: false }) }); - Tag.toString = function() { return "Tag"; }; var Person = DS.Model.extend({ name: DS.attr('string'), tag: DS.belongsTo('tag', { async: false }) }); - Person.toString = function() { return "Person"; }; var env = setupStore({ tag: Tag, person: Person }); var store = env.store; @@ -202,15 +200,11 @@ test("When finding a hasMany relationship the inverse belongsTo relationship is person: DS.belongsTo('person', { async: false }) }); - Occupation.toString = function() { return "Occupation"; }; - var Person = DS.Model.extend({ name: DS.attr('string'), occupations: DS.hasMany('occupation', { async: true }) }); - Person.toString = function() { return "Person"; }; - var env = setupStore({ occupation: Occupation, person: Person }); var store = env.store; env.adapter.shouldBackgroundReloadRecord = () => false; @@ -265,15 +259,11 @@ test("When finding a belongsTo relationship the inverse belongsTo relationship i person: DS.belongsTo('person', { async: false }) }); - Occupation.toString = function() { return "Occupation"; }; - var Person = DS.Model.extend({ name: DS.attr('string'), occupation: DS.belongsTo('occupation', { async: true }) }); - Person.toString = function() { return "Person"; }; - var env = setupStore({ occupation: Occupation, person: Person }); var store = env.store; @@ -317,7 +307,6 @@ test("belongsTo supports relationships to models with id 0", function(assert) { name: DS.attr('string'), tag: DS.belongsTo('tag', { async: false }) }); - Person.toString = function() { return "Person"; }; var env = setupStore({ tag: Tag, person: Person }); var store = env.store; @@ -375,13 +364,11 @@ test("belongsTo gives a warning when provided with a serialize option", function var Hobby = DS.Model.extend({ name: DS.attr('string') }); - Hobby.toString = function() { return "Hobby"; }; var Person = DS.Model.extend({ name: DS.attr('string'), hobby: DS.belongsTo('hobby', { serialize: true, async: true }) }); - Person.toString = function() { return "Person"; }; var env = setupStore({ hobby: Hobby, person: Person }); var store = env.store; @@ -429,13 +416,11 @@ test("belongsTo gives a warning when provided with an embedded option", function var Hobby = DS.Model.extend({ name: DS.attr('string') }); - Hobby.toString = function() { return "Hobby"; }; var Person = DS.Model.extend({ name: DS.attr('string'), hobby: DS.belongsTo('hobby', { embedded: true, async: true }) }); - Person.toString = function() { return "Person"; }; var env = setupStore({ hobby: Hobby, person: Person }); var store = env.store; diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index ea6342a200d..7c5040ccd85 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -478,15 +478,11 @@ test("hasMany relationships work when the data hash has not been loaded", functi person: DS.belongsTo('person', { async: false }) }); - Tag.toString = function() { return "Tag"; }; - var Person = DS.Model.extend({ name: DS.attr('string'), tags: DS.hasMany('tag', { async: true }) }); - Person.toString = function() { return "Person"; }; - var env = setupStore({ tag: Tag, person: Person }); var store = env.store; @@ -722,9 +718,6 @@ test("it is possible to add an item to a relationship, remove it, then add it ag tags: DS.hasMany('tag', { async: false }) }); - Tag.toString = function() { return "Tag"; }; - Person.toString = function() { return "Person"; }; - var env = setupStore({ tag: Tag, person: Person }); var store = env.store; var person, tag1, tag2, tag3; diff --git a/tests/unit/store/has-record-for-id-test.js b/tests/unit/store/has-record-for-id-test.js index 0db692b79a5..2350f72c176 100644 --- a/tests/unit/store/has-record-for-id-test.js +++ b/tests/unit/store/has-record-for-id-test.js @@ -19,17 +19,11 @@ module("unit/store/hasRecordForId - Store hasRecordForId", { lastName: attr('string'), phoneNumbers: hasMany('phone-number', { async: false }) }); - Person.toString = function() { - return 'Person'; - }; PhoneNumber = DS.Model.extend({ number: attr('string'), person: belongsTo('person', { async: false }) }); - PhoneNumber.toString = function() { - return 'PhoneNumber'; - }; env = setupStore({ person: Person, diff --git a/tests/unit/store/peek-record-test.js b/tests/unit/store/peek-record-test.js index 27bd0570b01..2c38ed3b86c 100644 --- a/tests/unit/store/peek-record-test.js +++ b/tests/unit/store/peek-record-test.js @@ -12,9 +12,6 @@ module("unit/store/peekRecord - Store peekRecord", { beforeEach() { Person = DS.Model.extend(); - Person.toString = function() { - return 'Person'; - }; env = setupStore({ person: Person diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index 5055dfe9ad7..aa5f2a036c3 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -20,24 +20,15 @@ module("unit/store/push - DS.Store#push", { lastName: attr('string'), phoneNumbers: hasMany('phone-number', { async: false }) }); - Person.toString = function() { - return 'Person'; - }; PhoneNumber = DS.Model.extend({ number: attr('string'), person: belongsTo('person', { async: false }) }); - PhoneNumber.toString = function() { - return 'PhoneNumber'; - }; Post = DS.Model.extend({ postTitle: attr('string') }); - Post.toString = function() { - return 'Post'; - }; env = setupStore({ post: Post, @@ -706,16 +697,12 @@ module("unit/store/push - DS.Store#push with JSON-API", { cars: DS.hasMany('car', { async: false }) }); - Person.toString = function() { return "Person"; }; - var Car = DS.Model.extend({ make: DS.attr('string'), model: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); - Car.toString = function() { return "Car"; }; - env = setupStore({ adapter: DS.Adapter, car: Car, From 4e78a9d4ba458b9e35465a8631f6c15fc90d00d6 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sun, 20 Dec 2015 18:57:28 +0100 Subject: [PATCH 1392/2527] [FEATURE ds-boolean-transform-allow-null] allow null for boolean This feature allows `null` / `undefined` values for `DS.attr('boolean')` attributes. Currently `DS.BooleanTransform` converts those values to `false`; which means that a `DS.attr('boolean')` cannot be set to `null` from the server. Other transforms (`string`, `number`) do allow `null` values, so this is an inconsistency. Current behavior of `DS.attr('boolean')`: | incoming | DS | serialized | |-------------|---------|------------| | `null` | `false` | `false` | | `undefined` | `false` | `false` | Behavior of `DS.attr('boolean')`, having `ds-boolean-transform-allow-null` feature enabled and having an attribute `DS.attr('boolean', { allowNull: true })`: | incoming | DS | serialized | |-------------|---------|------------| | `null` | `null` | `null` | | `undefined` | `null` | `null` | --- Note that this feature only works if `ds-transform-pass-options` is enabled as well, since passing the options from `DS.attr` to the transform is added with that feature. --- FEATURES.md | 6 ++++++ addon/-private/transforms/boolean.js | 24 +++++++++++++++++++-- config/features.json | 1 + tests/unit/model-test.js | 24 ++++++++++++++++----- tests/unit/transform/boolean-test.js | 31 ++++++++++++++++++++++++---- 5 files changed, 75 insertions(+), 11 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index faad23d82d4..ebd4b0149d5 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -11,6 +11,12 @@ entry in `config/features.json`. ## Feature Flags +- `ds-boolean-transform-allow-null` + + Allow `null`/`undefined` values for `boolean` attributes via `DS.attr('boolean', { allowNull: true })` + + Note that this feature only works when `ds-transform-pass-options` is enabled too. + - `ds-finder-include` Allows an `include` query parameter to be specified with using diff --git a/addon/-private/transforms/boolean.js b/addon/-private/transforms/boolean.js index 81338ba6fee..9aabfaa6683 100644 --- a/addon/-private/transforms/boolean.js +++ b/addon/-private/transforms/boolean.js @@ -1,4 +1,8 @@ +import Ember from 'ember'; import Transform from "ember-data/transform"; +import isEnabled from 'ember-data/-private/features'; + +const { isNone } = Ember; /** The `DS.BooleanTransform` class is used to serialize and deserialize @@ -23,9 +27,17 @@ import Transform from "ember-data/transform"; @namespace DS */ export default Transform.extend({ - deserialize(serialized) { + deserialize(serialized, options) { var type = typeof serialized; + if (isEnabled('ds-transform-pass-options')) { + if (isEnabled('ds-boolean-transform-allow-null')) { + if (isNone(serialized) && options.allowNull === true) { + return null; + } + } + } + if (type === "boolean") { return serialized; } else if (type === "string") { @@ -37,7 +49,15 @@ export default Transform.extend({ } }, - serialize(deserialized) { + serialize(deserialized, options) { + if (isEnabled('ds-transform-pass-options')) { + if (isEnabled('ds-boolean-transform-allow-null')) { + if (isNone(deserialized) && options.allowNull === true) { + return null; + } + } + } + return Boolean(deserialized); } }); diff --git a/config/features.json b/config/features.json index 1188f0b5d10..79d47a005ee 100644 --- a/config/features.json +++ b/config/features.json @@ -1,4 +1,5 @@ { + "ds-boolean-transform-allow-null": null, "ds-finder-include": null, "ds-references": null, "ds-transform-pass-options": null, diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 70b1f759c12..2554e7d2cea 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -822,9 +822,9 @@ test("when a method is invoked from an event with the same name the arguments ar assert.equal(eventMethodArgs[1], 2); }); -AssertionPrototype.converts = function converts(type, provided, expected) { +AssertionPrototype.converts = function converts(type, provided, expected, options = {}) { var Model = DS.Model.extend({ - name: DS.attr(type) + name: DS.attr(type, options) }); var registry, container; @@ -930,13 +930,27 @@ test("a DS.Model can describe Number attributes", function(assert) { }); test("a DS.Model can describe Boolean attributes", function(assert) { - assert.expect(7); - assert.converts('boolean', "1", true); assert.converts('boolean', "", false); assert.converts('boolean', 1, true); assert.converts('boolean', 0, false); - assert.converts('boolean', null, false); + + if (isEnabled('ds-transform-pass-options') && isEnabled('ds-boolean-transform-allow-null')) { + assert.converts('boolean', null, null, { allowNull: true }); + assert.converts('boolean', undefined, null, { allowNull: true }); + + assert.converts('boolean', null, false, { allowNull: false }); + assert.converts('boolean', undefined, false, { allowNull: false }); + + // duplicating the tests from the else branch here, so once the feature is + // enabled and the else branch is deleted, those assertions are kept + assert.converts('boolean', null, false); + assert.converts('boolean', undefined, false); + } else { + assert.converts('boolean', null, false); + assert.converts('boolean', undefined, false); + } + assert.converts('boolean', true, true); assert.converts('boolean', false, false); }); diff --git a/tests/unit/transform/boolean-test.js b/tests/unit/transform/boolean-test.js index df38a4f0924..aa257be005c 100644 --- a/tests/unit/transform/boolean-test.js +++ b/tests/unit/transform/boolean-test.js @@ -1,4 +1,5 @@ import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; import {module, test} from 'qunit'; @@ -7,8 +8,19 @@ module("unit/transform - DS.BooleanTransform"); test("#serialize", function(assert) { var transform = new DS.BooleanTransform(); - assert.equal(transform.serialize(null), false); - assert.equal(transform.serialize(undefined), false); + if (isEnabled('ds-transform-pass-options') && isEnabled('ds-boolean-transform-allow-null')) { + assert.equal(transform.serialize(null, { allowNull: true }), null); + assert.equal(transform.serialize(undefined, { allowNull: true }), null); + + assert.equal(transform.serialize(null, { allowNull: false }), false); + assert.equal(transform.serialize(undefined, { allowNull: false }), false); + + assert.equal(transform.serialize(null, {}), false); + assert.equal(transform.serialize(undefined, {}), false); + } else { + assert.equal(transform.serialize(null), false); + assert.equal(transform.serialize(undefined), false); + } assert.equal(transform.serialize(true), true); assert.equal(transform.serialize(false), false); @@ -17,8 +29,19 @@ test("#serialize", function(assert) { test("#deserialize", function(assert) { var transform = new DS.BooleanTransform(); - assert.equal(transform.deserialize(null), false); - assert.equal(transform.deserialize(undefined), false); + if (isEnabled('ds-transform-pass-options') && isEnabled('ds-boolean-transform-allow-null')) { + assert.equal(transform.deserialize(null, { allowNull: true }), null); + assert.equal(transform.deserialize(undefined, { allowNull: true }), null); + + assert.equal(transform.deserialize(null, { allowNull: false }), false); + assert.equal(transform.deserialize(undefined, { allowNull: false }), false); + + assert.equal(transform.deserialize(null, {}), false); + assert.equal(transform.deserialize(undefined, {}), false); + } else { + assert.equal(transform.deserialize(null), false); + assert.equal(transform.deserialize(undefined), false); + } assert.equal(transform.deserialize(true), true); assert.equal(transform.deserialize(false), false); From 5bb9b8134fba690de66763e6e31e1277fae18a3e Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 17 Feb 2016 18:34:57 +0100 Subject: [PATCH 1393/2527] Revert "use trusty beta environment to get phantomJS 2.0" This reverts commit 8011a0484f483cad26d7c2a1c5ba2774a24d0488. --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3c89d59afc3..1ac9ea1e3df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ --- language: node_js -sudo: required -dist: trusty +sudo: false node_js: - "4.2" before_install: From b320a74861cb7408ecbe0d537c4bb0e849c01e2a Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 17 Feb 2016 18:38:19 +0100 Subject: [PATCH 1394/2527] TravisCI: Install PhantomJS v2.1.1 --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1ac9ea1e3df..dd428ec62f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,10 @@ sudo: false node_js: - "4.2" before_install: + - mkdir travis-phantomjs + - wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2 -O $PWD/travis-phantomjs/phantomjs-2.1.1-linux-x86_64.tar.bz2 + - tar -xvf $PWD/travis-phantomjs/phantomjs-2.1.1-linux-x86_64.tar.bz2 -C $PWD/travis-phantomjs + - export PATH=$PWD/travis-phantomjs/phantomjs-2.1.1-linux-x86_64/bin:$PATH - "npm config set spin false" - "npm install -g npm@^2" install: From 7dc3218a72d7005406a46a54296f5bcd77d1cf51 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 17 Feb 2016 15:24:36 +0100 Subject: [PATCH 1395/2527] [BUGFIX beta] Add test blueprints from "ember-cli-mocha" The filesPath() method will automatically figure out if "qunit" or "mocha" files should be used by looking at the project packages. --- blueprints/adapter-test/index.js | 6 +++-- .../tests/unit/__path__/__test__.js | 19 +++++++++++++++ .../tests/unit/__path__/__test__.js | 0 blueprints/model-test/index.js | 5 ++-- .../tests/unit/__path__/__test__.js | 20 ++++++++++++++++ .../tests/unit/__path__/__test__.js | 0 blueprints/serializer-test/index.js | 8 ++++--- .../tests/unit/__path__/__test__.js | 22 +++++++++++++++++ .../tests/unit/__path__/__test__.js | 0 blueprints/test-framework-detector.js | 24 +++++++++++++++++++ blueprints/transform-test/index.js | 8 ++++--- .../tests/unit/__path__/__test__.js | 19 +++++++++++++++ .../tests/unit/__path__/__test__.js | 0 package.json | 7 +++--- 14 files changed, 125 insertions(+), 13 deletions(-) create mode 100644 blueprints/adapter-test/mocha-files/tests/unit/__path__/__test__.js rename blueprints/adapter-test/{files => qunit-files}/tests/unit/__path__/__test__.js (100%) create mode 100644 blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js rename blueprints/model-test/{files => qunit-files}/tests/unit/__path__/__test__.js (100%) create mode 100644 blueprints/serializer-test/mocha-files/tests/unit/__path__/__test__.js rename blueprints/serializer-test/{files => qunit-files}/tests/unit/__path__/__test__.js (100%) create mode 100644 blueprints/test-framework-detector.js create mode 100644 blueprints/transform-test/mocha-files/tests/unit/__path__/__test__.js rename blueprints/transform-test/{files => qunit-files}/tests/unit/__path__/__test__.js (100%) diff --git a/blueprints/adapter-test/index.js b/blueprints/adapter-test/index.js index 0f73ca498f6..2180c9f2ac6 100644 --- a/blueprints/adapter-test/index.js +++ b/blueprints/adapter-test/index.js @@ -1,12 +1,14 @@ /*jshint node:true*/ var testInfo = require('ember-cli-test-info'); +var useTestFrameworkDetector = require('../test-framework-detector'); -module.exports = { +module.exports = useTestFrameworkDetector({ description: 'Generates an ember-data adapter unit test', + locals: function(options) { return { friendlyTestDescription: testInfo.description(options.entity.name, "Unit", "Adapter") }; } -}; +}); diff --git a/blueprints/adapter-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/adapter-test/mocha-files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..e09a1e584e2 --- /dev/null +++ b/blueprints/adapter-test/mocha-files/tests/unit/__path__/__test__.js @@ -0,0 +1,19 @@ +/* jshint expr:true */ +import { expect } from 'chai'; +import { describeModule, it } from 'ember-mocha'; + +describeModule( + 'adapter:<%= dasherizedModuleName %>', + '<%= friendlyTestDescription %>', + { + // Specify the other units that are required for this test. + // needs: ['serializer:foo'] + }, + function() { + // Replace this with your real tests. + it('exists', function() { + let adapter = this.subject(); + expect(adapter).to.be.ok; + }); + } +); diff --git a/blueprints/adapter-test/files/tests/unit/__path__/__test__.js b/blueprints/adapter-test/qunit-files/tests/unit/__path__/__test__.js similarity index 100% rename from blueprints/adapter-test/files/tests/unit/__path__/__test__.js rename to blueprints/adapter-test/qunit-files/tests/unit/__path__/__test__.js diff --git a/blueprints/model-test/index.js b/blueprints/model-test/index.js index d85bd57e38b..c87bc2d652e 100644 --- a/blueprints/model-test/index.js +++ b/blueprints/model-test/index.js @@ -2,8 +2,9 @@ var ModelBlueprint = require('../model'); var testInfo = require('ember-cli-test-info'); +var useTestFrameworkDetector = require('../test-framework-detector'); -module.exports = { +module.exports = useTestFrameworkDetector({ description: 'Generates a model unit test.', locals: function(options) { @@ -13,4 +14,4 @@ module.exports = { return result; } -}; +}); diff --git a/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..8ccea636b4a --- /dev/null +++ b/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js @@ -0,0 +1,20 @@ +/* jshint expr:true */ +import { expect } from 'chai'; +import { describeModel, it } from 'ember-mocha'; + +describeModel( + '<%= dasherizedModuleName %>', + '<%= friendlyDescription %>', + { + // Specify the other units that are required for this test. + <%= typeof needs !== 'undefined' ? needs : '' %> + }, + function() { + // Replace this with your real tests. + it('exists', function() { + let model = this.subject(); + // var store = this.store(); + expect(model).to.be.ok; + }); + } +); diff --git a/blueprints/model-test/files/tests/unit/__path__/__test__.js b/blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js similarity index 100% rename from blueprints/model-test/files/tests/unit/__path__/__test__.js rename to blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js diff --git a/blueprints/serializer-test/index.js b/blueprints/serializer-test/index.js index 4da25f30a64..a280df94bc3 100644 --- a/blueprints/serializer-test/index.js +++ b/blueprints/serializer-test/index.js @@ -1,12 +1,14 @@ /*jshint node:true*/ var testInfo = require('ember-cli-test-info'); +var useTestFrameworkDetector = require('../test-framework-detector'); -module.exports = { +module.exports = useTestFrameworkDetector({ description: 'Generates a serializer unit test.', + locals: function(options) { return { friendlyTestDescription: testInfo.description(options.entity.name, "Unit", "Serializer") }; - }, -}; + } +}); diff --git a/blueprints/serializer-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/mocha-files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..327fd27c1b5 --- /dev/null +++ b/blueprints/serializer-test/mocha-files/tests/unit/__path__/__test__.js @@ -0,0 +1,22 @@ +/* jshint expr:true */ +import { expect } from 'chai'; +import { describeModel, it } from 'ember-mocha'; + +describeModel( + '<%= dasherizedModuleName %>', + '<%= friendlyTestDescription %>', + { + // Specify the other units that are required for this test. + needs: ['serializer:<%= dasherizedModuleName %>'] + }, + function() { + // Replace this with your real tests. + it('serializes records', function() { + let record = this.subject(); + + let serializedRecord = record.serialize(); + + expect(serializedRecord).to.be.ok; + }); + } +); diff --git a/blueprints/serializer-test/files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/qunit-files/tests/unit/__path__/__test__.js similarity index 100% rename from blueprints/serializer-test/files/tests/unit/__path__/__test__.js rename to blueprints/serializer-test/qunit-files/tests/unit/__path__/__test__.js diff --git a/blueprints/test-framework-detector.js b/blueprints/test-framework-detector.js new file mode 100644 index 00000000000..c7da486335c --- /dev/null +++ b/blueprints/test-framework-detector.js @@ -0,0 +1,24 @@ +var path = require('path'); + +module.exports = function(blueprint) { + blueprint.supportsAddon = function() { + return false; + }; + + blueprint.filesPath = function() { + var type; + + if ('ember-cli-mocha' in this.project.addonPackages) { + type = 'mocha'; + } else if ('ember-cli-qunit' in this.project.addonPackages) { + type = 'qunit'; + } else { + this.ui.writeLine('Couldn\'t determine test style - using QUnit'); + type = 'qunit'; + } + + return path.join(this.path, type + '-files'); + }; + + return blueprint; +}; diff --git a/blueprints/transform-test/index.js b/blueprints/transform-test/index.js index 59b7e9e8734..9a3394a5cd9 100644 --- a/blueprints/transform-test/index.js +++ b/blueprints/transform-test/index.js @@ -1,12 +1,14 @@ /*jshint node:true*/ var testInfo = require('ember-cli-test-info'); +var useTestFrameworkDetector = require('../test-framework-detector'); -module.exports = { +module.exports = useTestFrameworkDetector({ description: 'Generates a transform unit test.', + locals: function(options) { return { friendlyTestDescription: testInfo.description(options.entity.name, "Unit", "Transform") }; - }, -}; + } +}); diff --git a/blueprints/transform-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/transform-test/mocha-files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..88fb24805e8 --- /dev/null +++ b/blueprints/transform-test/mocha-files/tests/unit/__path__/__test__.js @@ -0,0 +1,19 @@ +/* jshint expr:true */ +import { expect } from 'chai'; +import { describeModule, it } from 'ember-mocha'; + +describeModule( + 'transform:<%= dasherizedModuleName %>', + '<%= friendlyTestDescription %>', + { + // Specify the other units that are required for this test. + // needs: ['transform:foo'] + }, + function() { + // Replace this with your real tests. + it('exists', function() { + let transform = this.subject(); + expect(transform).to.be.ok; + }); + } +); diff --git a/blueprints/transform-test/files/tests/unit/__path__/__test__.js b/blueprints/transform-test/qunit-files/tests/unit/__path__/__test__.js similarity index 100% rename from blueprints/transform-test/files/tests/unit/__path__/__test__.js rename to blueprints/transform-test/qunit-files/tests/unit/__path__/__test__.js diff --git a/package.json b/package.json index a095661ebc8..26da2ec683c 100644 --- a/package.json +++ b/package.json @@ -53,14 +53,14 @@ "broccoli-yuidoc": "^2.1.0", "ember-cli": "1.13.12", "ember-cli-app-version": "0.5.0", - "ember-cli-blueprint-test-helpers": "^0.6.0", + "ember-cli-blueprint-test-helpers": "^0.8.0", "ember-cli-content-security-policy": "0.4.0", "ember-cli-dependency-checker": "^1.0.1", "ember-cli-htmlbars": "0.7.9", "ember-cli-htmlbars-inline-precompile": "^0.2.0", "ember-cli-ic-ajax": "0.2.1", "ember-cli-inject-live-reload": "^1.3.1", - "ember-cli-internal-test-helpers": "^0.5.0", + "ember-cli-internal-test-helpers": "^0.8.0", "ember-cli-qunit": "^1.0.0", "ember-cli-release": "0.2.3", "ember-cli-uglify": "^1.2.0", @@ -88,6 +88,7 @@ "configPath": "tests/dummy/config", "paths": [ "lib/enable-optional-features-via-url" - ] + ], + "after": "ember-cli-mocha" } } From 87c4024fe85f59b6b7151aa1c97a488c31df3113 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Thu, 18 Feb 2016 14:22:03 +0100 Subject: [PATCH 1396/2527] TravisCI: Use the "phantomjs-prebuilt" NPM package to install PhantomJS This does essentially the same, but requires less steps --- .travis.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index dd428ec62f9..45b372fdfd2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,12 +4,10 @@ sudo: false node_js: - "4.2" before_install: - - mkdir travis-phantomjs - - wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2 -O $PWD/travis-phantomjs/phantomjs-2.1.1-linux-x86_64.tar.bz2 - - tar -xvf $PWD/travis-phantomjs/phantomjs-2.1.1-linux-x86_64.tar.bz2 -C $PWD/travis-phantomjs - - export PATH=$PWD/travis-phantomjs/phantomjs-2.1.1-linux-x86_64/bin:$PATH - "npm config set spin false" - "npm install -g npm@^2" + - npm install -g phantomjs-prebuilt@2 + install: - npm install --no-optional - ./node_modules/.bin/bower install From c5219f63f4115546a81ae4ff8bc05c059d17853c Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Thu, 18 Feb 2016 20:21:28 -0500 Subject: [PATCH 1397/2527] [CLEANUP] Remove shim for Backburner.join This shim was added a long while back when we could not rely on the version of Backburner that Ember was using to have the `join()` function. Any currently supported version of Ember (2.x) should have this now. Similarly, any currently supported (2.x) version of Ember also has `Ember._Backburner` available. Shim was added in: https://github.com/emberjs/data/pull/2608 `Backburner.join()` was added in: https://github.com/ebryn/backburner.js/pull/119 --- addon/-private/system/store.js | 43 +--------------------------------- 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index a967e07eb17..83482f2792e 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -57,51 +57,10 @@ import isEnabled from 'ember-data/-private/features'; export let badIdFormatAssertion = '`id` has to be non-empty string or number'; -var Backburner = Ember._Backburner || Ember.Backburner || Ember.__loader.require('backburner')['default'] || Ember.__loader.require('backburner')['Backburner']; +const Backburner = Ember._Backburner; var Map = Ember.Map; var isArray = Array.isArray || Ember.isArray; -//Shim Backburner.join -if (!Backburner.prototype.join) { - var isString = function(suspect) { - return typeof suspect === 'string'; - }; - - Backburner.prototype.join = function(/*target, method, args */) { - var method, target; - - if (this.currentInstance) { - var length = arguments.length; - if (length === 1) { - method = arguments[0]; - target = null; - } else { - target = arguments[0]; - method = arguments[1]; - } - - if (isString(method)) { - method = target[method]; - } - - if (length === 1) { - return method(); - } else if (length === 2) { - return method.call(target); - } else { - var args = new Array(length - 2); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i + 2]; - } - return method.apply(target, args); - } - } else { - return this.run.apply(this, arguments); - } - }; -} - - //Get the materialized model from the internalModel/promise that returns //an internal model and return it in a promiseObject. Useful for returning //from find methods From cb262406991ccbdf443cb49a566854f24dc6ad1a Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Thu, 18 Feb 2016 20:47:08 -0500 Subject: [PATCH 1398/2527] [CLEANUP] Remove shim for Ember.Service Removes a shim for `Ember.Service`. This isn't needed anymore since Ember 2.x+ all have `Ember.Service` available. --- addon/-private/system/store.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index a967e07eb17..7ae4bbe743d 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -118,10 +118,7 @@ var Promise = Ember.RSVP.Promise; var copy = Ember.copy; var Store; -var Service = Ember.Service; -if (!Service) { - Service = Ember.Object; -} +const { Service } = Ember; // Implementors Note: // From c9604ca6a8fa0be8d1fcedec52a01c64fc90fc5e Mon Sep 17 00:00:00 2001 From: Aaron Sikes Date: Sun, 21 Feb 2016 20:54:57 -0500 Subject: [PATCH 1399/2527] Elaborate on running tests in browser Visting `http://localhost:4200` displays the dummy app's "Welcome to Ember" screen. The tests reside at `/tests` --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c38631df26f..0d0ad4ff6a6 100644 --- a/README.md +++ b/README.md @@ -190,7 +190,7 @@ See [CONTRIBUTING.md](https://github.com/emberjs/data/blob/master/CONTRIBUTING.m 1. To start the development server, run `npm start`. -2. Visit http://localhost:4200 +2. Visit `http://localhost:4200/tests` ### From the CLI From 95782fc973c661d74b0dd4a875e17b92a96facc7 Mon Sep 17 00:00:00 2001 From: Aaron Sikes Date: Sun, 21 Feb 2016 22:14:10 -0500 Subject: [PATCH 1400/2527] Update tests url --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3dffba76125..8c1a55b451b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -66,7 +66,7 @@ We love pull requests. Here's a quick guide: 2. Run the tests. We only take pull requests with passing tests, and it's great to know that you have a clean slate, see notes on how to run unit tests [here](https://github.com/emberjs/data#how-to-run-unit-tests). (To see tests in the browser, -run `npm start` and open `http://localhost:4200`.) +run `npm start` and open `http://localhost:4200/tests`.) 3. Add a test for your change. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, we need From a6eec9ba308629f4141f21bf159aea7df9b8a3d1 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 24 Feb 2016 17:32:46 +0100 Subject: [PATCH 1401/2527] [BUGFIX beta] blueprints: Use project.dependencies() to determine test framework This has the advantage of not requiring the package to actually be installed and will enable us to test the mocha blueprints properly. blueprints: Prioritize "ember-cli-qunit" over "ember-cli-mocha" --- blueprints/test-framework-detector.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/blueprints/test-framework-detector.js b/blueprints/test-framework-detector.js index c7da486335c..8f04dca3a60 100644 --- a/blueprints/test-framework-detector.js +++ b/blueprints/test-framework-detector.js @@ -8,10 +8,11 @@ module.exports = function(blueprint) { blueprint.filesPath = function() { var type; - if ('ember-cli-mocha' in this.project.addonPackages) { - type = 'mocha'; - } else if ('ember-cli-qunit' in this.project.addonPackages) { + var dependencies = this.project.dependencies(); + if ('ember-cli-qunit' in dependencies) { type = 'qunit'; + } else if ('ember-cli-mocha' in dependencies) { + type = 'mocha'; } else { this.ui.writeLine('Couldn\'t determine test style - using QUnit'); type = 'qunit'; From 7989453f3938656d36608fb0fad9a0afc90f6c2e Mon Sep 17 00:00:00 2001 From: cibernox Date: Tue, 13 Oct 2015 20:18:33 +0100 Subject: [PATCH 1402/2527] [FEATURE ds-serialize-ids-and-types] Create a new `ids-and-types` embedding strategy for non STI polymorphic hasMany Taking as example this scenario: ```js User = DS.Model.extend({ name: DS.attr('string'), pets: DS.hasMany('pet', { polymorphic: true }) }); Pet = DS.Model.extend({ name: DS.attr('string'), }); Cat = Pet.extend({ // ... }); Parrot = Pet.extend({ // ... }); ``` As of today, when using the `DS.EmbeddedRecordsMixin` in a serializer and configuring the serialization stategy like this: ``` attrs: { pets: { serialize: 'ids' } } ``` The relationship is serialized: ```json { "user": { "id": "1" "name": "Bertin Osborne", "pets": [1,2] } } ``` This works ok if the polymorphism is based on STI, but that is just one specific implementation does not cover all use cases. Probably when a hasMany relationship is polymorphic the serialization should generate an array of object containing `id` and `type` by default, but at this point this can't be changed because it would break apps in the wild. Because of that a new serialization strategy named `ids-and-types` has been created that covers this use case. Probably this should become the default behavior of the `ids` strategy in ember 3.0, but not for now. For the same example above, this stragegy would generate the following payload: ```js { "user": { "id": "1" "name": "Bertin Osborne", "pets": [ { "id": "1", "type": "Cat" }, { "id": "2", "type": "Parrot"} ] } } ``` Note that with this strategy if the differenty type of records don't whare the same ids space, that is not a problem. ```js { "user": { "id": "1" "name": "Bertin Osborne", "pets": [ { "id": "1", "type": "Cat" }, { "id": "1", "type": "Parrot"} // Same id, but different type ] } } ``` --- FEATURES.md | 24 +++++ addon/serializers/embedded-records-mixin.js | 97 +++++++++++++++++-- config/features.json | 3 +- .../embedded-records-mixin-test.js | 69 ++++++++++--- 4 files changed, 175 insertions(+), 18 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index faad23d82d4..3f640cef01b 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -30,3 +30,27 @@ entry in `config/features.json`. Enables `pushPayload` to return the model(s) that are created or updated via the internal `store.push`. [PR 4110](https://github.com/emberjs/data/pull/4110) + +- `ds-serialize-ids-and-types` + + Enables a new `ids-and-type` strategy (in addition to the already existing `ids` and `records`) for + serializing has many relationships using the `DS.EmbeddedRecordsMixin` that will include both + `id` and `type` of each model as an object. + + For instance, if a use has many pets, which is a polymorphic relationship, the generated payload would be: + + ```js + { + "user": { + "id": "1" + "name": "Bertin Osborne", + "pets": [ + { "id": "1", "type": "Cat" }, + { "id": "2", "type": "Parrot"} + ] + } + } + ``` + + This is particularly useful for polymorphic relationships not backed by STI when just including the id + of the records is not enough. diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 5c77b5eb340..8285321a3e0 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -1,5 +1,6 @@ import Ember from 'ember'; import { warn } from "ember-data/-private/debug"; +import isEnabled from 'ember-data/-private/features'; var get = Ember.get; var set = Ember.set; @@ -235,7 +236,7 @@ export default Ember.Mixin.create({ }, /** - Serialize `hasMany` relationship when it is configured as embedded objects. + Serializes `hasMany` relationships when it is configured as embedded objects. This example of a post model has many comments: @@ -285,7 +286,7 @@ export default Ember.Mixin.create({ ``` The attrs options object can use more specific instruction for extracting and - serializing. When serializing, an option to embed `ids` or `records` can be set. + serializing. When serializing, an option to embed `ids`, `ids-and-types` or `records` can be set. When extracting the only option is `records`. So `{ embedded: 'always' }` is shorthand for: @@ -314,6 +315,58 @@ export default Ember.Mixin.create({ } ``` + To embed the relationship as a collection of objects with `id` and `type` keys, set + `ids-and-types` for the related object. + + This is particularly useful for polymorphic relationships where records don't share + the same table and the `id` is not enough information. + + By example having a user that has many pets: + + ```js + User = DS.Model.extend({ + name: DS.attr('string'), + pets: DS.hasMany('pet', { polymorphic: true }) + }); + + Pet = DS.Model.extend({ + name: DS.attr('string'), + }); + + Cat = Pet.extend({ + // ... + }); + + Parrot = Pet.extend({ + // ... + }); + ``` + + ```app/serializers/user.js + import DS from 'ember-data; + + export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + pets: { serialize: 'ids-and-types', deserialize: 'records' } + } + }); + ``` + + ```js + { + "user": { + "id": "1" + "name": "Bertin Osborne", + "pets": [ + { "id": "1", "type": "Cat" }, + { "id": "1", "type": "Parrot"} + ] + } + } + ``` + + Note that the `ids-and-types` strategy is still behind the `ds-serialize-ids-and-types` feature flag. + @method serializeHasMany @param {DS.Snapshot} snapshot @param {Object} json @@ -325,16 +378,42 @@ export default Ember.Mixin.create({ this._super(snapshot, json, relationship); return; } - var includeIds = this.hasSerializeIdsOption(attr); - var includeRecords = this.hasSerializeRecordsOption(attr); - if (includeIds) { + + if (this.hasSerializeIdsOption(attr)) { let serializedKey = this.keyForRelationship(attr, relationship.kind, 'serialize'); json[serializedKey] = snapshot.hasMany(attr, { ids: true }); - } else if (includeRecords) { + } else if (this.hasSerializeRecordsOption(attr)) { this._serializeEmbeddedHasMany(snapshot, json, relationship); + } else { + if (isEnabled("ds-serialize-ids-and-types")) { + if (this.hasSerializeIdsAndTypesOption(attr)) { + this._serializeHasManyAsIdsAndTypes(snapshot, json, relationship); + } + } } }, + /** + Serializes a hasMany relationship as an array of objects containing only `id` and `type` + keys. + This has its use case on polymorphic hasMany relationships where the server is not storing + all records in the same table using STI, and therefore the `id` is not enough information + + TODO: Make the default in Ember-data 3.0?? + */ + _serializeHasManyAsIdsAndTypes(snapshot, json, relationship) { + var serializedKey = this.keyForAttribute(relationship.key, 'serialize'); + var hasMany = snapshot.hasMany(relationship.key); + + json[serializedKey] = Ember.A(hasMany).map(function (recordSnapshot) { + // + // I'm sure I'm being utterly naive here. Propably id is a configurate property and + // type too, and the modelName has to be normalized somehow. + // + return { id: recordSnapshot.id, type: recordSnapshot.modelName }; + }); + }, + _serializeEmbeddedHasMany(snapshot, json, relationship) { var serializedKey = this._getMappedKey(relationship.key, snapshot.type); if (serializedKey === relationship.key && this.keyForRelationship) { @@ -420,6 +499,12 @@ export default Ember.Mixin.create({ return option && (option.serialize === 'ids' || option.serialize === 'id'); }, + // checks config for attrs option to serialize records as objects containing id and types + hasSerializeIdsAndTypesOption(attr) { + var option = this.attrsOption(attr); + return option && (option.serialize === 'ids-and-types' || option.serialize === 'id-and-type'); + }, + // checks config for attrs option to serialize records noSerializeOptionSpecified(attr) { var option = this.attrsOption(attr); diff --git a/config/features.json b/config/features.json index 1188f0b5d10..85762ada0c3 100644 --- a/config/features.json +++ b/config/features.json @@ -2,5 +2,6 @@ "ds-finder-include": null, "ds-references": null, "ds-transform-pass-options": null, - "ds-pushpayload-return": null + "ds-pushpayload-return": null, + "ds-serialize-ids-and-types": null } diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index e1f9e1e20ae..330a39bf715 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -4,10 +4,11 @@ import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; var get = Ember.get; -var HomePlanet, SuperVillain, EvilMinion, SecretLab, SecretWeapon, BatCave, Comment, - league, superVillain, evilMinion, secretWeapon, homePlanet, secretLab, env; +var HomePlanet, SuperVillain, CommanderVillain, NormalMinion, EvilMinion, YellowMinion, RedMinion, SecretLab, SecretWeapon, BatCave, Comment, + league, superVillain, commanderVillain, evilMinion, yellowMinion, redMinion, secretWeapon, homePlanet, secretLab, env; var run = Ember.run; var LightSaber; @@ -44,22 +45,36 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { superVillain: DS.belongsTo('super-villain', { async: false }), name: DS.attr('string') }); + NormalMinion = DS.Model.extend({ + name: DS.attr('string') + }); + YellowMinion = NormalMinion.extend(); + RedMinion = NormalMinion.extend(); + CommanderVillain = DS.Model.extend({ + name: DS.attr('string'), + minions: DS.hasMany('normal-minion', { polymorphic: true }) + }); Comment = DS.Model.extend({ body: DS.attr('string'), root: DS.attr('boolean'), children: DS.hasMany('comment', { inverse: null, async: false }) }); env = setupStore({ - superVillain: SuperVillain, - homePlanet: HomePlanet, - secretLab: SecretLab, - batCave: BatCave, - secretWeapon: SecretWeapon, - lightSaber: LightSaber, - evilMinion: EvilMinion, - comment: Comment + superVillain: SuperVillain, + commanderVillain: CommanderVillain, + homePlanet: HomePlanet, + secretLab: SecretLab, + batCave: BatCave, + secretWeapon: SecretWeapon, + lightSaber: LightSaber, + evilMinion: EvilMinion, + normalMinion: NormalMinion, + yellowMinion: YellowMinion, + redMinion: RedMinion, + comment: Comment }); env.store.modelFor('super-villain'); + env.store.modelFor('commander-villain'); env.store.modelFor('home-planet'); env.store.modelFor('secret-lab'); env.store.modelFor('bat-cave'); @@ -1058,6 +1073,39 @@ test("serialize with embedded objects (hasMany relationships, including related }); }); +if (isEnabled("ds-serialize-ids-and-types")) { + test("serialize has many relationship using the `ids-and-types` strategy", function(assert) { + run(function() { + yellowMinion = env.store.createRecord('yellow-minion', { id: 1, name: "Yellowy" }); + redMinion = env.store.createRecord('red-minion', { id: 1, name: "Reddy" }); + commanderVillain = env.store.createRecord('commander-villain', { id: 1, name: "Jeff", minions: [yellowMinion, redMinion] }); + }); + + env.registry.register('serializer:commander-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + minions: { serialize: 'ids-and-types' } + } + })); + var serializer, json; + run(function() { + serializer = env.container.lookup("serializer:commander-villain"); + var snapshot = commanderVillain._createSnapshot(); + json = serializer.serialize(snapshot); + }); + + assert.deepEqual(json, { + name: 'Jeff', + minions: [{ + id: '1', + type: 'yellow-minion' + }, { + id: '1', + type: 'red-minion' + }] + }); + }); +} + test("normalizeResponse with embedded object (belongsTo relationship)", function(assert) { env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1949,7 +1997,6 @@ test("normalizeResponse with polymorphic belongsTo and custom primary key", func } ] }, "Custom primary key is correctly normalized"); - }); test("Mixin can be used with RESTSerializer which does not define keyForAttribute", function(assert) { From bc52576e482f56565a28b14e42b0c36865246beb Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 17 Feb 2016 16:15:39 +0100 Subject: [PATCH 1403/2527] Update ember-cli to v2.3.0 The diff should basically be the same as this one: https://github.com/kellyselden/ember-addon-output/compare/v1.13.12...v2.3.0 Also, since loader.js is a npm module now, the custom build pipeline for the globals build has been adapted, so the loader.js is now read from the corresponding folder in the node_modules directory. --- .npmignore | 21 +++++++++++-------- bower.json | 12 +++-------- config/ember-try.js | 40 ++++++++++++++++++++++--------------- ember-cli-build.js | 2 +- lib/javascripts.js | 4 ++-- package.json | 19 ++++++++++-------- tests/dummy/app/app.js | 4 ++-- tests/dummy/app/index.html | 8 ++++---- tests/dummy/app/resolver.js | 3 +++ tests/helpers/resolver.js | 2 +- tests/index.html | 16 +++++++-------- 11 files changed, 72 insertions(+), 59 deletions(-) create mode 100644 tests/dummy/app/resolver.js diff --git a/.npmignore b/.npmignore index 08ef4c5b7f8..299ab96cbd8 100644 --- a/.npmignore +++ b/.npmignore @@ -1,18 +1,23 @@ -bower_components/ -tests/ -tmp/ -dist/ +/bower_components +/config/ember-try.js +/dist +/node-tests +/tests +/tmp +**/.gitkeep +.appveyor.yml .bowerrc .editorconfig .ember-cli +.gitignore +.jshintrc .travis.yml -.appveyor.yml -.npmignore -**/.gitkeep +.watchmanconfig bower.json +ember-cli-build.js testem.json + *.gem *.gemspec **/*.rb -node-tests/ diff --git a/bower.json b/bower.json index 4ed1c4b9ee6..8df7ae85297 100644 --- a/bower.json +++ b/bower.json @@ -2,15 +2,9 @@ "name": "ember-data", "dependencies": { "ember": "components/ember#release", - "ember-cli-shims": "ember-cli/ember-cli-shims#0.1.0", - "ember-cli-test-loader": "ember-cli-test-loader#0.1.3", - "ember-load-initializers": "ember-cli/ember-load-initializers#0.1.5", - "ember-qunit": "0.4.9", - "ember-qunit-notifications": "0.0.7", - "ember-resolver": "~0.1.18", - "jquery": "1.11.3", - "loader.js": "3.3.0", - "qunit": "~1.18.0" + "ember-cli-shims": "0.1.0", + "ember-cli-test-loader": "0.2.2", + "ember-qunit-notifications": "0.1.0" }, "resolutions": { "ember": "release" diff --git a/config/ember-try.js b/config/ember-try.js index 3e88bc612a1..be846e137dc 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -3,33 +3,41 @@ module.exports = { scenarios: [ { name: 'default', - dependencies: { } + bower: { + dependencies: { } + } }, { name: 'ember-release', - dependencies: { - 'ember': 'components/ember#release' - }, - resolutions: { - 'ember': 'release' + bower: { + dependencies: { + 'ember': 'components/ember#release' + }, + resolutions: { + 'ember': 'release' + } } }, { name: 'ember-beta', - dependencies: { - 'ember': 'components/ember#beta' - }, - resolutions: { - 'ember': 'beta' + bower: { + dependencies: { + 'ember': 'components/ember#beta' + }, + resolutions: { + 'ember': 'beta' + } } }, { name: 'ember-canary', - dependencies: { - 'ember': 'components/ember#canary' - }, - resolutions: { - 'ember': 'canary' + bower: { + dependencies: { + 'ember': 'components/ember#canary' + }, + resolutions: { + 'ember': 'canary' + } } } ] diff --git a/ember-cli-build.js b/ember-cli-build.js index 38eb600fa24..43abc781fda 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -15,7 +15,7 @@ module.exports = function(defaults) { }); /* - This build file specifes the options for the dummy test app of this + This build file specifies the options for the dummy test app of this addon, located in `/tests/dummy` This build file does *not* influence how the addon or the app using it behave. You most likely want to be modifying `./index.js` or app's build file diff --git a/lib/javascripts.js b/lib/javascripts.js index 40cb79e6956..da66aa74ede 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -30,8 +30,8 @@ function makeStrippedBuild(packageName, tree) { } function collapse(tree, outputFileName) { - var bowerDir = path.join(__dirname, '..', 'bower_components', 'loader.js'); - var loader = new Funnel(bowerDir, { + var loaderDir = path.join(__dirname, '..', 'node_modules', 'loader.js', 'lib', 'loader'); + var loader = new Funnel(loaderDir, { include: ['loader.js'] }); diff --git a/package.json b/package.json index 26da2ec683c..251d0d66bdf 100644 --- a/package.json +++ b/package.json @@ -51,28 +51,31 @@ "broccoli-string-replace": "^0.1.1", "broccoli-uglify-sourcemap": "^1.0.1", "broccoli-yuidoc": "^2.1.0", - "ember-cli": "1.13.12", + "ember-ajax": "0.7.1", + "ember-cli": "2.3.0", "ember-cli-app-version": "0.5.0", "ember-cli-blueprint-test-helpers": "^0.8.0", - "ember-cli-content-security-policy": "0.4.0", - "ember-cli-dependency-checker": "^1.0.1", + "ember-cli-dependency-checker": "^1.2.0", "ember-cli-htmlbars": "0.7.9", "ember-cli-htmlbars-inline-precompile": "^0.2.0", - "ember-cli-ic-ajax": "0.2.1", "ember-cli-inject-live-reload": "^1.3.1", - "ember-cli-internal-test-helpers": "^0.8.0", - "ember-cli-qunit": "^1.0.0", + "ember-cli-internal-test-helpers": "^0.8.1", + "ember-cli-qunit": "^1.2.1", "ember-cli-release": "0.2.3", + "ember-cli-sri": "^2.0.0", "ember-cli-uglify": "^1.2.0", "ember-dev": "emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed", - "ember-disable-prototype-extensions": "^1.0.0", + "ember-disable-prototype-extensions": "^1.1.0", "ember-disable-proxy-controllers": "^1.0.0", "ember-export-application-global": "^1.0.3", + "ember-load-initializers": "^0.5.0", "ember-publisher": "0.0.7", - "ember-try": "0.0.6", + "ember-resolver": "^2.0.3", + "ember-try": "^0.1.2", "ember-watson": "^0.7.0", "github": "^0.2.4", "glob": "^5.0.13", + "loader.js": "^4.0.0", "mocha": "^2.3.4", "mocha-only-detector": "0.0.2", "rimraf": "^2.3.2", diff --git a/tests/dummy/app/app.js b/tests/dummy/app/app.js index 8b234d6d57b..831ad6106dd 100644 --- a/tests/dummy/app/app.js +++ b/tests/dummy/app/app.js @@ -1,6 +1,6 @@ import Ember from 'ember'; -import Resolver from 'ember/resolver'; -import loadInitializers from 'ember/load-initializers'; +import Resolver from './resolver'; +import loadInitializers from 'ember-load-initializers'; import config from './config/environment'; let App; diff --git a/tests/dummy/app/index.html b/tests/dummy/app/index.html index 1c49d36d0e1..c9b432708dd 100644 --- a/tests/dummy/app/index.html +++ b/tests/dummy/app/index.html @@ -7,19 +7,19 @@ - {{content-for 'head'}} + {{content-for "head"}} - {{content-for 'head-footer'}} + {{content-for "head-footer"}} - {{content-for 'body'}} + {{content-for "body"}} - {{content-for 'body-footer'}} + {{content-for "body-footer"}} diff --git a/tests/dummy/app/resolver.js b/tests/dummy/app/resolver.js new file mode 100644 index 00000000000..2fb563d6c04 --- /dev/null +++ b/tests/dummy/app/resolver.js @@ -0,0 +1,3 @@ +import Resolver from 'ember-resolver'; + +export default Resolver; diff --git a/tests/helpers/resolver.js b/tests/helpers/resolver.js index ebfb4e4d455..b208d38d097 100644 --- a/tests/helpers/resolver.js +++ b/tests/helpers/resolver.js @@ -1,4 +1,4 @@ -import Resolver from 'ember/resolver'; +import Resolver from '../../resolver'; import config from '../../config/environment'; const resolver = Resolver.create(); diff --git a/tests/index.html b/tests/index.html index 5e88e5e10c2..2d3ff6ade04 100644 --- a/tests/index.html +++ b/tests/index.html @@ -7,19 +7,19 @@ - {{content-for 'head'}} - {{content-for 'test-head'}} + {{content-for "head"}} + {{content-for "test-head"}} - {{content-for 'head-footer'}} - {{content-for 'test-head-footer'}} + {{content-for "head-footer"}} + {{content-for "test-head-footer"}} - {{content-for 'body'}} - {{content-for 'test-body'}} + {{content-for "body"}} + {{content-for "test-body"}} @@ -28,7 +28,7 @@ - {{content-for 'body-footer'}} - {{content-for 'test-body-footer'}} + {{content-for "body-footer"}} + {{content-for "test-body-footer"}} From 021f41461be9ccdadaafb488f79fbd164a37c323 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Thu, 25 Feb 2016 21:50:56 +0100 Subject: [PATCH 1404/2527] AppVeyor: Use same line endings as original files --- appveyor.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 45e719e1e9e..d8d597a6d8a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,9 +1,5 @@ # http://www.appveyor.com/docs/appveyor-yml -# Fix line endings in Windows. (runs before repo cloning) -init: - - git config --global core.autocrlf true - # Test against these versions of Node.js. environment: matrix: From 08f25dc2ba44e4830740c193bd4b21dcbc1b0bfd Mon Sep 17 00:00:00 2001 From: asakusuma Date: Fri, 26 Feb 2016 16:25:31 -0800 Subject: [PATCH 1405/2527] Don't resolve model name unless actually needed --- addon/-private/system/store.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index e265a74d95c..09e95be4f52 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1674,12 +1674,11 @@ Store = Service.extend({ assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id != null && data.id !== ''); assert(`You tried to push data with a type '${modelName}' but no model could be found with that name.`, this._hasModelFor(modelName)); - var type = this.modelFor(modelName); - // If Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload // contains unknown keys, log a warning. if (Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS) { + var type = this.modelFor(modelName); warn("The payload for '" + type.modelName + "' contains these unknown keys: " + Ember.inspect(Object.keys(data).forEach((key) => { return !(key === 'id' || key === 'links' || get(type, 'fields').has(key) || key.match(/Type$/)); From 717bb4f491b4b64fbd75961239c4ba0e66215810 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Sat, 27 Feb 2016 20:20:02 -0600 Subject: [PATCH 1406/2527] support 1.13 officially --- addon/index.js | 6 ------ config/ember-try.js | 11 +++++++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/addon/index.js b/addon/index.js index 33a31a9ff95..ce424112180 100644 --- a/addon/index.js +++ b/addon/index.js @@ -12,12 +12,6 @@ if (Ember.VERSION.match(/^1\.([0-9]|1[0-2])\./)) { ". Please upgrade your version of Ember, then upgrade Ember Data."); } -if (Ember.VERSION.match(/^1\.13\./)) { - warn(`Use of Ember Data 2+ with Ember 1.13 is unsupported. Please upgrade your version of Ember to 2.0 or higher.`, false, { - id: 'ds.version.ember-1-13' - }); -} - import DS from "ember-data/-private/core"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; diff --git a/config/ember-try.js b/config/ember-try.js index be846e137dc..18617f0e40c 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -7,6 +7,17 @@ module.exports = { dependencies: { } } }, + { + name: 'ember-1-13', + bower: { + dependencies: { + 'ember': '1.13.13' + }, + resolutions: { + 'ember': '1.13.13' + } + } + }, { name: 'ember-release', bower: { From d65804fe62e49c730ed4a55e0344475e1a07d56d Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 24 Feb 2016 17:52:59 +0100 Subject: [PATCH 1407/2527] Add acceptance tests for the mocha blueprints Update "ember-cli-blueprint-test-helpers" to v0.9.0 node-tests/blueprints/model: Add test for "mocha" blueprint node-tests/blueprints/adapter: Add test for "mocha" blueprint node-tests/blueprints/serializer: Add test for "mocha" blueprint node-tests/blueprints/transform: Add test for "mocha" blueprint --- node-tests/blueprints/adapter-test.js | 19 +++++++++++++++++++ node-tests/blueprints/model-test.js | 19 +++++++++++++++++++ node-tests/blueprints/serializer-test.js | 21 +++++++++++++++++++++ node-tests/blueprints/transform-test.js | 19 +++++++++++++++++++ package.json | 2 +- 5 files changed, 79 insertions(+), 1 deletion(-) diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 17f78384bd0..074f3cc3079 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -86,4 +86,23 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { ] }); }); + + it('adapter-test for mocha', function() { + return generateAndDestroy(['adapter-test', 'foo'], { + packages: [ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true } + ], + files: [ + { + file: 'tests/unit/adapters/foo-test.js', + contains: [ + 'import { describeModule, it } from \'ember-mocha\';', + 'describeModule(\n \'adapter:foo\',', + 'expect(adapter).to.be.ok;' + ] + } + ] + }); + }); }); diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index d86dbd11599..692d9c0996b 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -164,4 +164,23 @@ describe('Acceptance: generate and destroy model blueprints', function() { ] }); }); + + it('model-test for mocha', function() { + return generateAndDestroy(['model-test', 'foo'], { + packages: [ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true } + ], + files: [ + { + file: 'tests/unit/models/foo-test.js', + contains: [ + 'import { describeModel, it } from \'ember-mocha\';', + 'describeModel(\n \'foo\',', + 'expect(model).to.be.ok;' + ] + } + ] + }); + }); }); diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index ac7b60f9a75..958eaa0e42a 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -37,4 +37,25 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { ] }); }); + + it('serializer-test for mocha', function() { + return generateAndDestroy(['serializer-test', 'foo'], { + packages: [ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true } + ], + files: [ + { + file: 'tests/unit/serializers/foo-test.js', + contains: [ + 'import { describeModel, it } from \'ember-mocha\';', + 'describeModel(\n \'foo\',', + 'Unit | Serializer | foo', + 'needs: [\'serializer:foo\']', + 'expect(serializedRecord).to.be.ok;' + ] + } + ] + }); + }); }); diff --git a/node-tests/blueprints/transform-test.js b/node-tests/blueprints/transform-test.js index ebb88e0d26d..c018792c506 100644 --- a/node-tests/blueprints/transform-test.js +++ b/node-tests/blueprints/transform-test.js @@ -39,4 +39,23 @@ describe('Acceptance: generate and destroy transform blueprints', function() { ] }); }); + + it('transform-test for mocha', function() { + return generateAndDestroy(['transform-test', 'foo'], { + packages: [ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true } + ], + files: [ + { + file: 'tests/unit/transforms/foo-test.js', + contains: [ + 'import { describeModule, it } from \'ember-mocha\';', + 'describeModule(\n \'transform:foo\',', + 'expect(transform).to.be.ok;' + ] + } + ] + }); + }); }); diff --git a/package.json b/package.json index 251d0d66bdf..1accc1dfd1d 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "ember-ajax": "0.7.1", "ember-cli": "2.3.0", "ember-cli-app-version": "0.5.0", - "ember-cli-blueprint-test-helpers": "^0.8.0", + "ember-cli-blueprint-test-helpers": "^0.9.0", "ember-cli-dependency-checker": "^1.2.0", "ember-cli-htmlbars": "0.7.9", "ember-cli-htmlbars-inline-precompile": "^0.2.0", From a9914ae9cabbf960984f938cbaa0cde700823620 Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 29 Feb 2016 21:10:15 +0100 Subject: [PATCH 1408/2527] Restructure and elaborate on test which fixes a tricky bug This slightly restructures and adds more comments to a test, which fixed a tricky bug which occurred while updating the canonical state of a hasMany relationship in combination with locally created records. --- addon/-private/system/many-array.js | 3 ++ .../relationships/has-many-test.js | 43 ++++++++++++------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index c3d0b0b6f7f..9944b92178b 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -79,6 +79,9 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { //a hack for not removing new records //TODO remove once we have proper diffing var newRecords = this.currentState.filter( + // only add new records which are not yet in the canonical state of this + // relationship (a new record can be in the canonical state if it has + // been 'acknowleged' to be in the relationship via a store.push) (internalModel) => internalModel.isNew() && toSet.indexOf(internalModel) === -1 ); toSet = toSet.concat(newRecords); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 31ffb6506a3..05324675f3a 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -404,7 +404,7 @@ test("A hasMany updated link should not remove new children when the parent reco }); }); -test("A hasMany updated link should not remove new children when the parent record has children already with feedback from the server after save", function(assert) { +test("A hasMany relationship doesn't contain duplicate children, after the canonical state of the relationship is updated via store#push", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) @@ -416,48 +416,59 @@ test("A hasMany updated link should not remove new children when the parent reco env.adapter.createRecord = function(store, snapshot, link, relationship) { return Ember.RSVP.resolve({ - id: 5 + id: 1 }); }; - - env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve([{ id: 5 }]); - }; - - run(function() { var post = env.store.createRecord('post', {}); - env.store.createRecord('comment', { id: 5, message: post }); + + // create a new comment with id 'local', which is in the 'comments' + // relationship of post + var localComment = env.store.createRecord('comment', { id: 'local', message: post }); post.get('comments') .then(function(comments) { assert.equal(comments.get('length'), 1); + assert.equal(localComment.get('isNew'), true); + return post.save(); }) .then(function() { - return env.store.push({ + + // Now the post is saved but the locally created comment with the id + // 'local' is still in the created state since it hasn't been saved + // yet. + // + // As next we are pushing the post into the store again, having the + // locally created comment in the 'comments' relationship. By this the + // canonical state of the relationship is defined to consist of one + // comment: the one with id 'local'. + // + // This setup is needed to demonstrate the bug which has been fixed + // in #4154, where the locally created comment was duplicated in the + // comment relationship. + env.store.push({ data: { - type: "post", - id: 5, + type: 'post', + id: 1, relationships: { comments: { data: [ - { - id: 5, - type: "comment" - } + { id: 'local', type: 'comment' } ] } } } }); + }) .then(function() { return post.get('comments'); }) .then(function(comments) { assert.equal(comments.get('length'), 1); + assert.equal(localComment.get('isNew'), true); }); }); }); From aa43596484edee8862f004a175a257e31f028098 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 29 Feb 2016 19:18:45 -0500 Subject: [PATCH 1409/2527] Update changelog for Ember Data 2.4 --- CHANGELOG.md | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2fb45829b2..154e298ab42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,90 @@ ### Master +### Release 2.4.0 (February 29, 2016) +- [#4125](https://github.com/emberjs/data/pull/4125) [BUGFIX beta] Export more public API's via modules +- [#4135](https://github.com/emberjs/data/pull/4135) import require +- [#4137](https://github.com/emberjs/data/pull/4137) [BUGFIX beta] Allow optional spaces when parsing response headers +- [#4141](https://github.com/emberjs/data/pull/4141) [DOC] Document behavior of object level errors with JSON API +- [#4147](https://github.com/emberjs/data/pull/4147) Fix key remapping for embedded belongsTo +- [#4167](https://github.com/emberjs/data/pull/4167) Add blueprints from ember-cli-mocha +- [#4082](https://github.com/emberjs/data/pull/4082) Move the date import to where it is used intead of the root module +- [#4063](https://github.com/emberjs/data/pull/4063) [BUGFIX release] don't load "app" code when loading globals files +- [#4088](https://github.com/emberjs/data/pull/4088) [BUFGIX release] Fix regression with missing initializers +- [#4066](https://github.com/emberjs/data/pull/4066) Use correct version number when used as an addon. +- [#4072](https://github.com/emberjs/data/pull/4072) [BUGFIX release] Fix bundled source path for gem +- [#4073](https://github.com/emberjs/data/pull/4073) [BUGFIX release] Add missing dist source to gem +- [#4077](https://github.com/emberjs/data/pull/4077) [CLEANUP beta] Change the way metadata in response is stored on record array +- [#4084](https://github.com/emberjs/data/pull/4084) [cleanup] Remove unnecessary inline JSHint config +- [#4090](https://github.com/emberjs/data/pull/4090) Make yui doc generate links from the project root instead of the file… +- [#4091](https://github.com/emberjs/data/pull/4091) [BUGFIX release] Refactor Model.reopen to use mixins +- [#4095](https://github.com/emberjs/data/pull/4095) [BUGFIX release] Remove 'v' prefix from `DS.VERSION` +- [#4108](https://github.com/emberjs/data/pull/4108) [BUGFIX beta] Fix `BuildUrlMixin.urlPrefix` regression when host=/ +- [#3999](https://github.com/emberjs/data/pull/3999) Run the Ember Data initializer when Ember Data is loaded as an Ember … +- [#3941](https://github.com/emberjs/data/pull/3941) Mark `adapterFor` and `serializerFor` as public +- [#3813](https://github.com/emberjs/data/pull/3813) ember-data should provide its blueprints +- [#3916](https://github.com/emberjs/data/pull/3916) `Store._find` asserts `adapterPayload` not empty +- [#3940](https://github.com/emberjs/data/pull/3940) Remove JSONSerializer#normalizeId +- [#3303](https://github.com/emberjs/data/pull/3303) Implement RFC 57 - Reference Unification +- [#3864](https://github.com/emberjs/data/pull/3864) Throw a more helpful error message if the response from queryRecord i… +- [#3930](https://github.com/emberjs/data/pull/3930) Friendly Errors +- [#2384](https://github.com/emberjs/data/pull/2384) Directly reloading a hasMany with links should trigger only one request +- [#3853](https://github.com/emberjs/data/pull/3853) fix transitioning into invalid state +- [#3841](https://github.com/emberjs/data/pull/3841) Log a deprecation warning when when Ember Data is loaded with Ember 1.13 +- [#3926](https://github.com/emberjs/data/pull/3926) Run `ember watson: methodify` on `addon/` and `test/` +- [#4009](https://github.com/emberjs/data/pull/4009) [FEATURE ds-references] More conistency for RecordReference +- [#3961](https://github.com/emberjs/data/pull/3961) Add a better error message when findRecord returns an array +- [#3949](https://github.com/emberjs/data/pull/3949) Fix incorrect reference in store api docs +- [#3946](https://github.com/emberjs/data/pull/3946) Report better error when `type` is missing from a JSONApi response +- [#3958](https://github.com/emberjs/data/pull/3958) [DOCS fix] fix incorrect argument description... +- [#4014](https://github.com/emberjs/data/pull/4014) Register the version before the DEBUG version are printed when loadin… +- [#3968](https://github.com/emberjs/data/pull/3968) Add failing test on PromiseArray.createRecord when called before hasM… +- [#3965](https://github.com/emberjs/data/pull/3965) [Doc] Specify the status code expected to populate the error object +- [#3964](https://github.com/emberjs/data/pull/3964) Merge normalizeRelationships and setupRelationships methods in store +- [#3967](https://github.com/emberjs/data/pull/3967) Added documentation to modify the hash by reference +- [#3966](https://github.com/emberjs/data/pull/3966) tests for #3707 +- [#4016](https://github.com/emberjs/data/pull/4016) Add missing dependencies for the changelog script +- [#3970](https://github.com/emberjs/data/pull/3970) [CLEANUP] move test file to correct location +- [#4017](https://github.com/emberjs/data/pull/4017) [FEATURE ds-references] bring back accidentally removed tests +- [#3985](https://github.com/emberjs/data/pull/3985) Remove extraneous conditional in ajax() +- [#3980](https://github.com/emberjs/data/pull/3980) Add license field to bower.json +- [#3979](https://github.com/emberjs/data/pull/3979) Re-enable feature flags +- [#3974](https://github.com/emberjs/data/pull/3974) Remove duplicate createRecord test +- [#3973](https://github.com/emberjs/data/pull/3973) [CLEANUP] use debug helpers from ember-data/debug +- [#3983](https://github.com/emberjs/data/pull/3983) Fix documentation to use "serializedHasManyName" +- [#3984](https://github.com/emberjs/data/pull/3984) Cleanup .jshintrc since no globals are used anymore +- [#3976](https://github.com/emberjs/data/pull/3976) Allow `include` query parameter with store.findRecord & store.findAll +- [#4000](https://github.com/emberjs/data/pull/4000) Re-enable pushing builds to S3 +- [#3996](https://github.com/emberjs/data/pull/3996) Update ember-cli-shims to 0.1.0 to silence ED's own warning +- [#3988](https://github.com/emberjs/data/pull/3988) [PERF] Don't use array methods +- [#3989](https://github.com/emberjs/data/pull/3989) Rely on internalModel.createSnapshot to set adapterOptions +- [#3990](https://github.com/emberjs/data/pull/3990) Update adapter function references in test +- [#3993](https://github.com/emberjs/data/pull/3993) Do not publish .gem files to npm +- [#4025](https://github.com/emberjs/data/pull/4025) Use keyForReliationship for belongsTo and hasMany +- [#4007](https://github.com/emberjs/data/pull/4007) [CLEANUP] Use `isEnabled` instead of `Ember.FEATURES` directly +- [#4006](https://github.com/emberjs/data/pull/4006) [CLEANUP] Separate buildURL tests from pathForType tests +- [#4001](https://github.com/emberjs/data/pull/4001) Add ember-publisher to package.json +- [#4004](https://github.com/emberjs/data/pull/4004) [CLEANUP] remove unused feature-flags.js +- [#4003](https://github.com/emberjs/data/pull/4003) Only run the Ember.onload initializers in globals mode +- [#4005](https://github.com/emberjs/data/pull/4005) don't cache length in for loops +- [#4002](https://github.com/emberjs/data/pull/4002) Fix paths to files which should be uploaded to S3 +- [#4049](https://github.com/emberjs/data/pull/4049) Run node tests and optional feature tests on AppVeyor +- [#4015](https://github.com/emberjs/data/pull/4015) [CLEANUP] Don't cache length in for loops +- [#4019](https://github.com/emberjs/data/pull/4019) Use JSON-API adapter and serializer in blueprints +- [#4018](https://github.com/emberjs/data/pull/4018) [CLEANUP] re-use test setup to assert correct call to adapter.ajax +- [#4011](https://github.com/emberjs/data/pull/4011) [CLEANUP] Update and remove obsolete comments +- [#4030](https://github.com/emberjs/data/pull/4030) [CLEANUP] use methods from utils module directly +- [#4029](https://github.com/emberjs/data/pull/4029) Move public modules out of the `-private` folder +- [#4051](https://github.com/emberjs/data/pull/4051) Make setup-container public to allow consuming apps more flexibility with initializer +- [#4037](https://github.com/emberjs/data/pull/4037) Happy New Year! +- [#4035](https://github.com/emberjs/data/pull/4035) Simplify the urlPrefix method to make it easier to understand +- [#4031](https://github.com/emberjs/data/pull/4031) [CLEANUP] Remove special logic for meta.descs in tests +- [#4032](https://github.com/emberjs/data/pull/4032) [CLEANUP] remove obsolete code within Store#willDestroy +- [#4039](https://github.com/emberjs/data/pull/4039) Replace calls to store.find with store.findRecord +- [#4053](https://github.com/emberjs/data/pull/4053) [FEATURE ds-references] Only add function to prototype if enabled +- [#4059](https://github.com/emberjs/data/pull/4059) Update name for feature in FEATURES.md + + ### Release 2.3.3 (January 21, 2016) - [#4095](https://github.com/emberjs/data/pull/4095) [BUGFIX release] Remove 'v' prefix from `DS.VERSION` From 111260a5c46603dcc137c6cb8e3e58296465d8f4 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Tue, 1 Mar 2016 10:50:43 -0500 Subject: [PATCH 1410/2527] [DOC beta] Fix error message internal docs --- addon/adapters/rest.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 28b9f6a99c3..81fb9273da7 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -946,7 +946,7 @@ export default Adapter.extend(BuildURLMixin, { @param {Number} status @param {Object} headers @param {Object} payload - @return {Object} errors payload + @return {Array} errors payload */ normalizeErrorResponse(status, headers, payload) { if (payload && typeof payload === 'object' && payload.errors) { @@ -971,7 +971,8 @@ export default Adapter.extend(BuildURLMixin, { @param {Number} status @param {Object} headers @param {Object} payload - @return {Object} request information + @param {Object} requestData + @return {String} detailed error message */ generatedDetailedMessage: function(status, headers, payload, requestData) { var shortenedPayload; From 0534783d28e2abf359bb7290d7f9f5184f4d3969 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 1 Mar 2016 13:04:36 -0500 Subject: [PATCH 1411/2527] Update master to Ember Data 2.6.0-canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1accc1dfd1d..14bfa50f839 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.5.0-canary", + "version": "2.6.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From bc8e4911426e0b0e378ca6990f8ae4bebf8e7ea2 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 1 Mar 2016 22:27:06 -0500 Subject: [PATCH 1412/2527] Avoid errors when ember-cli-shims is not included. --- index.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index ce7c24a49cc..c3ca5e9fd52 100644 --- a/index.js +++ b/index.js @@ -25,7 +25,8 @@ module.exports = { var VersionChecker = require('ember-cli-version-checker'); var checker = new VersionChecker(this); - var shims = checker.for('ember-cli-shims', 'bower'); + // prevent errors when ember-cli-shims is no longer required + var shims = bowerDeps['ember-cli-shims'] && checker.for('ember-cli-shims', 'bower'); var semver = require('semver'); var version = require('./package').version; @@ -44,17 +45,17 @@ module.exports = { var emberDataBower = checker.for('ember-data', 'bower'); - if (!shims.satisfies('< 0.1.0') && emberDataBower.satisfies('< 2.3.0-beta.3')) { + if (shims && !shims.satisfies('< 0.1.0') && emberDataBower.satisfies('< 2.3.0-beta.3')) { throw new SilentError('Using a version of ember-cli-shims greater than or equal to 0.1.0 will cause errors while loading Ember Data < 2.3.0-beta.3 Please update ember-cli-shims from ' + shims.version + ' to 0.0.6'); } - if (!shims.satisfies('>= 0.1.0') && emberDataBower.satisfies('>= 2.3.0-beta.3')) { + if (shims && !shims.satisfies('>= 0.1.0') && emberDataBower.satisfies('>= 2.3.0-beta.3')) { throw new SilentError('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3.0-beta.3+. Please update ember-cli-shims from ' + shims.version + ' to 0.1.0.'); } } else { // NPM only, but ember-cli-shims does not match - if (!shims.satisfies('>= 0.1.0') && semver.satisfies(version, '^2.3.0-beta.3')) { + if (shims && !shims.satisfies('>= 0.1.0') && semver.satisfies(version, '^2.3.0-beta.3')) { throw new SilentError('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3.0-beta.3+. Please update ember-cli-shims from ' + shims.version + ' to 0.1.0.'); } } From d3f37c31da1bcee00f1ac4c83453eb38a0f45e75 Mon Sep 17 00:00:00 2001 From: Jamie White Date: Fri, 17 Jul 2015 18:51:39 +0100 Subject: [PATCH 1413/2527] [BUGFIX release] Guard against isDestroyed in ManyArray.flushCanonical Addresses #3084 --- addon/-private/system/many-array.js | 6 +- .../relationships/has-many-test.js | 62 +++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index c3d0b0b6f7f..69b9bcb5a45 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -4,6 +4,7 @@ import Ember from 'ember'; import { assert } from "ember-data/-private/debug"; import { PromiseArray } from "ember-data/-private/system/promise-proxies"; +import { _objectIsAlive } from "ember-data/-private/system/store/common"; var get = Ember.get; var set = Ember.set; @@ -84,7 +85,10 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { toSet = toSet.concat(newRecords); var oldLength = this.length; this.arrayContentWillChange(0, this.length, toSet.length); - this.set('length', toSet.length); + // It’s possible the parent side of the relationship may have been unloaded by this point + if (_objectIsAlive(this)) { + this.set('length', toSet.length); + } this.currentState = toSet; this.arrayContentDidChange(0, oldLength, this.length); //TODO Figure out to notify only on additions and maybe only if unloaded diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 31ffb6506a3..a0794adc833 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -2700,3 +2700,65 @@ test("PromiseArray proxies createRecord to its ManyArray before the hasMany is l }); }); }); + +test("unloading and reloading a record with hasMany relationship - #3084", function(assert) { + var user; + var message; + + run(function() { + env.store.push({ + data: [{ + type: 'user', + id: 'user-1', + attributes: { + name: 'Adolfo Builes' + }, + relationships: { + messages: { + data: [ + { type: 'message', id: 'message-1' } + ] + } + } + }, { + type: 'message', + id: 'message-1' + }] + }); + + user = env.store.peekRecord('user', 'user-1'); + message = env.store.peekRecord('message', 'message-1'); + + assert.equal(get(user, 'messages.firstObject.id'), 'message-1'); + assert.equal(get(message, 'user.id'), 'user-1'); + }); + + run(function() { + env.store.unloadRecord(user); + }); + + run(function() { + // The record is resurrected for some reason. + env.store.push({ + data: [{ + type: 'user', + id: 'user-1', + attributes: { + name: 'Adolfo Builes' + }, + relationships: { + messages: { + data: [ + { type: 'message', id: 'message-1' } + ] + } + } + }] + }); + + user = env.store.peekRecord('user', 'user-1'); + + assert.equal(get(user, 'messages.firstObject.id'), 'message-1'); + assert.equal(get(message, 'user.id'), 'user-1'); + }); +}); From 9def562a63aa7336ad5d1380954f570709a7b656 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 2 Mar 2016 08:59:10 -0800 Subject: [PATCH 1414/2527] [BUGFIX release] ensure import paths are resolved \w posix separators * share the same algorithm ember.js uses * path.join defaults to path[platform].join which results in path.win32.join on windows and path.posix.join on everything else. --- lib/babel-build.js | 8 +------- package.json | 1 + 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/babel-build.js b/lib/babel-build.js index 6d5dde2147c..9bb5f0d61e7 100644 --- a/lib/babel-build.js +++ b/lib/babel-build.js @@ -25,13 +25,7 @@ function babelOptions(libraryName, _options) { getModuleId: function (name) { return name.replace(/\/index$/g, ''); }, - resolveModuleSource: function(name, filename) { - if (name.indexOf('.') === 0) { - return libraryName + '/' + path.join(path.dirname(filename), name); - } else { - return name; - } - } + resolveModuleSource: require('amd-name-resolver').moduleResolve }; Object.keys(_options).forEach(function(opt) { diff --git a/package.json b/package.json index 14bfa50f839..8e56d6f973d 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "author": "", "license": "MIT", "dependencies": { + "amd-name-resolver": "0.0.5", "babel-plugin-feature-flags": "^0.2.0", "babel-plugin-filter-imports": "^0.2.0", "broccoli-babel-transpiler": "^5.5.0", From 29383cb1bb43f1ff0517be6c32cf2ad4ade255db Mon Sep 17 00:00:00 2001 From: Chad Hietala Date: Sun, 6 Mar 2016 20:50:56 -0800 Subject: [PATCH 1415/2527] Fix AMD dependencies This fixes the module name resolution. Currently production builds do not resolve correctly as the dependencies of modules are being resolved like the following. ``` define('ember-data/-private/system/references', ['exports', '-private/system/references/record', '-private/system/references/belongs-to', '-private/system/references/has-many'], function (exports, _privateSystemReferencesRecord, _privateSystemReferencesBelongsTo, _privateSystemReferencesHasMany) {...}); ``` The modules now are fully resolved. --- lib/babel-build.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/babel-build.js b/lib/babel-build.js index 9bb5f0d61e7..295ae7682b5 100644 --- a/lib/babel-build.js +++ b/lib/babel-build.js @@ -1,5 +1,6 @@ var babel = require('broccoli-babel-transpiler'); var path = require('path'); +var moduleResolve = require('amd-name-resolver').moduleResolve; function babelOptions(libraryName, _options) { _options = _options || {}; @@ -20,12 +21,12 @@ function babelOptions(libraryName, _options) { sourceMaps: false, modules: 'amdStrict', moduleRoot: libraryName, - moduleId: true, + moduleIds: true, // Transforms /index.js files to use their containing directory name getModuleId: function (name) { return name.replace(/\/index$/g, ''); }, - resolveModuleSource: require('amd-name-resolver').moduleResolve + resolveModuleSource: moduleResolve }; Object.keys(_options).forEach(function(opt) { From ea6f7e1033079a80efc2d318ba642c6df3ffd53a Mon Sep 17 00:00:00 2001 From: Justin Brown Date: Mon, 7 Mar 2016 23:01:01 -0400 Subject: [PATCH 1416/2527] Use single quotes --- addon/attr.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/attr.js b/addon/attr.js index 817f48ef82f..87a95d3615e 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -1,12 +1,12 @@ import Ember from 'ember'; -import { deprecate } from "ember-data/-private/debug"; +import { deprecate } from 'ember-data/-private/debug'; /** @module ember-data */ function getDefaultValue(record, options, key) { - if (typeof options.defaultValue === "function") { + if (typeof options.defaultValue === 'function') { return options.defaultValue.apply(null, arguments); } else { let defaultValue = options.defaultValue; From 6615add73c7080e88aabcf2fca108e2d406af6e5 Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 8 Mar 2016 08:38:38 +0100 Subject: [PATCH 1417/2527] [BUGFIX beta] use assert from debug utils so it is stripped correctly --- addon/-private/system/store/finders.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index e80e5a216d6..638e0257de0 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -196,7 +196,7 @@ export function _queryRecord(adapter, store, typeClass, query) { var record; store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'queryRecord'); - Ember.assert('`store.queryRecord` expected the adapter to return one record but the response from the adapter was empty.', payload.data); + assert('`store.queryRecord` expected the adapter to return one record but the response from the adapter was empty.', payload.data); //TODO Optimize record = store.push(payload); }); From c3b6094bc96c29bbbc0ecd9ea883e7316b4aca0d Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Wed, 2 Mar 2016 18:15:50 +0100 Subject: [PATCH 1418/2527] [BUGFIX release] Fix RESTAdapter.buildQuery without a snapshot Before introducing a feature ds-finder-include it was possible to run findRecord on an adapter without passing a snapshot. After introducing the feature it's no longer possible even if the feature is disabled, because some of the code was outsief of the flag check. This commit fixes the code to work like before introducing the ds-finder-include change. --- addon/adapters/rest.js | 10 ++++++---- tests/unit/adapters/rest-adapter/build-query-test.js | 7 +++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 81fb9273da7..7cded79adb2 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -993,13 +993,15 @@ export default Adapter.extend(BuildURLMixin, { }, buildQuery(snapshot) { - const { include } = snapshot; - let query = {}; if (isEnabled('ds-finder-include')) { - if (include) { - query.include = include; + if(snapshot) { + const { include } = snapshot; + + if (include) { + query.include = include; + } } } diff --git a/tests/unit/adapters/rest-adapter/build-query-test.js b/tests/unit/adapters/rest-adapter/build-query-test.js index fa098e56c2e..6632346548d 100644 --- a/tests/unit/adapters/rest-adapter/build-query-test.js +++ b/tests/unit/adapters/rest-adapter/build-query-test.js @@ -13,6 +13,13 @@ test("buildQuery() returns an empty query when snapshot has no query params", fu assert.deepEqual(query, {}, 'query is empty'); }); +test("buildQuery - doesn't fail without a snapshot", function(assert) { + const adapter = DS.RESTAdapter.create(); + const query = adapter.buildQuery(); + + assert.deepEqual(query, {}, 'returns an empty query'); +}); + if (isEnabled('ds-finder-include')) { test("buildQuery() returns query with `include` from snapshot", function(assert) { const adapter = DS.RESTAdapter.create(); From bbc3d46bd35dce10f186e81eabd88b21c2064afd Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 8 Mar 2016 21:34:19 +0100 Subject: [PATCH 1419/2527] Strip code for DS_WARN_ON_UNKNOWN_KEYS warning in production - wrap code inside runInDebug so it is stripped from production - update checks so they work correctly with passed payload, which is actually a JSON-API document --- addon/-private/system/store.js | 39 ++++++++++++++++++++-------------- tests/unit/store/push-test.js | 30 +++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 09e95be4f52..b810eba43bb 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -4,7 +4,7 @@ import Ember from 'ember'; import Model from 'ember-data/model'; -import { assert, warn } from "ember-data/-private/debug"; +import { assert, warn, runInDebug } from "ember-data/-private/debug"; import _normalizeLink from "ember-data/-private/system/normalize-link"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; import { @@ -1674,21 +1674,28 @@ Store = Service.extend({ assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id != null && data.id !== ''); assert(`You tried to push data with a type '${modelName}' but no model could be found with that name.`, this._hasModelFor(modelName)); - // If Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload - // contains unknown keys, log a warning. - - if (Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS) { - var type = this.modelFor(modelName); - warn("The payload for '" + type.modelName + "' contains these unknown keys: " + - Ember.inspect(Object.keys(data).forEach((key) => { - return !(key === 'id' || key === 'links' || get(type, 'fields').has(key) || key.match(/Type$/)); - })) + ". Make sure they've been defined in your model.", - Object.keys(data).filter((key) => { - return !(key === 'id' || key === 'links' || get(type, 'fields').has(key) || key.match(/Type$/)); - }).length === 0, - { id: 'ds.store.unknown-keys-in-payload' } - ); - } + runInDebug(() => { + // If Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload + // contains unknown attributes or relationships, log a warning. + + if (Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS) { + let type = this.modelFor(modelName); + + // Check unknown attributes + let unknownAttributes = Object.keys(data.attributes || {}).filter((key) => { + return !get(type, 'fields').has(key); + }); + let unknownAttributesMessage = `The payload for '${type.modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`; + warn(unknownAttributesMessage, unknownAttributes.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); + + // Check unknown relationships + let unknownRelationships = Object.keys(data.relationships || {}).filter((key) => { + return !get(type, 'fields').has(key); + }); + let unknownRelationshipsMessage = `The payload for '${type.modelName}' contains these unknown relationships: ${unknownRelationships}. Make sure they've been defined in your model.`; + warn(unknownRelationshipsMessage, unknownRelationships.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); + } + }); // Actually load the record into the store. var internalModel = this._load(data); diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index aa5f2a036c3..bc29f255792 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -619,7 +619,7 @@ test('calling push with belongsTo relationship the value must not be an array', }, /must not be an array/); }); -test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown keys", function(assert) { +test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown attributes", function(assert) { run(function() { var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; try { @@ -636,7 +636,31 @@ test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown keys", f } } }); - }); + }, "The payload for 'person' contains these unknown attributes: emailAddress,isMascot. Make sure they've been defined in your model."); + } finally { + Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = originalFlagValue; + } + }); +}); + +test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown relationships", function(assert) { + run(function() { + var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; + try { + Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; + assert.expectWarning(function() { + store.push({ + data: { + type: 'person', + id: '1', + relationships: { + phoneNumbers: {}, + emailAddresses: {}, + mascots: {} + } + } + }); + }, "The payload for 'person' contains these unknown relationships: emailAddresses,mascots. Make sure they've been defined in your model."); } finally { Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = originalFlagValue; } @@ -658,7 +682,7 @@ test("Calling push with unknown keys should not warn by default", function(asser } }); }); - }, /The payload for 'person' contains these unknown keys: \[emailAddress,isMascot\]. Make sure they've been defined in your model./); + }, /The payload for 'person' contains these unknown .*: .* Make sure they've been defined in your model./); }); if (isEnabled('ds-pushpayload-return')) { From e1be17587d8df42f9910aaf02dfbaf182569bfcd Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 2 Mar 2016 09:54:42 -0800 Subject: [PATCH 1420/2527] unify prod/dev add-on build --- index.js | 33 +++++++++++++++-------------- lib/stripped-build-plugins.js | 39 +++++++++++++++++++++++++++++++++++ lib/stripped-build.js | 36 ++------------------------------ package.json | 4 ++-- 4 files changed, 60 insertions(+), 52 deletions(-) create mode 100644 lib/stripped-build-plugins.js diff --git a/index.js b/index.js index c3ca5e9fd52..40f1e8bb68d 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,11 @@ var path = require('path'); var SilentError = require('silent-error'); +function add(options, name, array) { + var option = options[name] = options[name] || []; + option.push.apply(option, array); +} + module.exports = { name: 'ember-data', @@ -22,7 +27,9 @@ module.exports = { init: function() { var bowerDeps = this.project.bowerDependencies(); + var VersionChecker = require('ember-cli-version-checker'); + var options = this.options = this.options || {}; var checker = new VersionChecker(this); // prevent errors when ember-cli-shims is no longer required @@ -84,28 +91,22 @@ module.exports = { var version = require('./lib/version'); var merge = require('broccoli-merge-trees'); - var addonTree = merge([version(), dir]); - - if (process.env.EMBER_ENV === 'production') { - var strippedBuild = require('./lib/stripped-build'); - - // blacklist es6.modules so the modules are not compiled but simply the - // debug statements / features are stripped; this is taken from - // ember-cli-babel: - // https://github.com/babel/ember-cli-babel/blob/master/index.js#L71 - var strippedAddon = strippedBuild('ember-data', addonTree, { - blacklist: ['es6.modules', 'useStrict'] - }); - return this._super.treeForAddon.call(this, strippedAddon); - } - - return this._super.treeForAddon.call(this, addonTree); + return this._super.treeForAddon.call(this, merge([ + version(), + dir + ])); }, included: function(app) { this._super.included.apply(this, arguments); + if (process.env.EMBER_ENV === 'production') { + this.options.babel = this.options.babel || {}; + add(this.options.babel, 'blacklist', ['es6.modules', 'useStrict']); + add(this.options.babel, 'plugins', require('./lib/stripped-build-plugins')()); + } + if (this._forceBowerUsage) { this.app.import({ development: app.bowerDirectory + '/ember-data/ember-data.js', diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js new file mode 100644 index 00000000000..49afe181683 --- /dev/null +++ b/lib/stripped-build-plugins.js @@ -0,0 +1,39 @@ +var fs = require('fs'); +var path = require('path'); +var filterImports = require('babel-plugin-filter-imports'); +var featureFlags = require('babel-plugin-feature-flags'); + +module.exports = function() { + var featuresJsonPath = __dirname + '/../config/features.json'; + var featuresJson = fs.readFileSync(featuresJsonPath, { encoding: 'utf8' }); + var features = JSON.parse(featuresJson); + + // TODO explicitly set all features which are not enabled to `false`, so + // they are stripped --> make this configurable or pass features + // + // for (var feature in features) { + // if (features[feature] !== true) { + // features[feature] = false; + // } + // } + + return [ + featureFlags({ + import: { module: 'ember-data/-private/features' }, + features: features + }), + + filterImports({ + 'ember-data/-private/debug': [ + 'assert', + 'assertPolymorphicType', + 'debug', + 'deprecate', + 'info', + 'runInDebug', + 'warn', + 'debugSeal' + ] + }) + ]; +}; diff --git a/lib/stripped-build.js b/lib/stripped-build.js index 282e93bd9a3..ddb9a0d39db 100644 --- a/lib/stripped-build.js +++ b/lib/stripped-build.js @@ -3,43 +3,11 @@ var path = require('path'); var filterImports = require('babel-plugin-filter-imports'); var featureFlags = require('babel-plugin-feature-flags'); var babelBuild = require('./babel-build'); +var strippedBuildPlugins = require('./stripped-build-plugins'); module.exports = function(packageName, tree, _options) { - var featuresJsonPath = path.join(__dirname, '../config/features.json'); - var featuresJson = fs.readFileSync(featuresJsonPath, { encoding: 'utf8' }); - var features = JSON.parse(featuresJson); - - // TODO explicitly set all features which are not enabled to `false`, so - // they are stripped --> make this configurable or pass features - // - // for (var feature in features) { - // if (features[feature] !== true) { - // features[feature] = false; - // } - // } - - var plugins = [ - featureFlags({ - import: { module: 'ember-data/-private/features' }, - features: features - }), - - filterImports({ - 'ember-data/-private/debug': [ - 'assert', - 'assertPolymorphicType', - 'debug', - 'deprecate', - 'info', - 'runInDebug', - 'warn', - 'debugSeal' - ] - }) - ]; - var options = _options || {}; - options.plugins = plugins; + options.plugins = strippedBuildPlugins(); return babelBuild(packageName, tree, options); }; diff --git a/package.json b/package.json index 8e56d6f973d..e82485b09be 100644 --- a/package.json +++ b/package.json @@ -54,10 +54,10 @@ "broccoli-yuidoc": "^2.1.0", "ember-ajax": "0.7.1", "ember-cli": "2.3.0", - "ember-cli-app-version": "0.5.0", + "ember-cli-app-version": "^1.0.0", "ember-cli-blueprint-test-helpers": "^0.9.0", "ember-cli-dependency-checker": "^1.2.0", - "ember-cli-htmlbars": "0.7.9", + "ember-cli-htmlbars": "^1.0.3", "ember-cli-htmlbars-inline-precompile": "^0.2.0", "ember-cli-inject-live-reload": "^1.3.1", "ember-cli-internal-test-helpers": "^0.8.1", From ced181ff68f87eecd149c6d15b1f8b6887f17142 Mon Sep 17 00:00:00 2001 From: asakusuma Date: Wed, 9 Mar 2016 12:42:00 -0800 Subject: [PATCH 1421/2527] Don't do inverse calculation if inverse explicitly turned off --- addon/-private/system/relationships/state/create.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index e3953347a6f..b5da724a921 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -5,9 +5,17 @@ import EmptyObject from "ember-data/-private/system/empty-object"; var get = Ember.get; +function shouldFindInverse(relationshipMeta) { + let options = relationshipMeta.options; + return !(options && options.inverse === null); +} + function createRelationshipFor(record, relationshipMeta, store) { - var inverseKey; - var inverse = record.type.inverseFor(relationshipMeta.key, store); + let inverseKey; + let inverse = null; + if (shouldFindInverse(relationshipMeta)) { + inverse = record.type.inverseFor(relationshipMeta.key, store); + } if (inverse) { inverseKey = inverse.name; From 168d6de50a84e1c3de9a1cb15e4baafb87f8c609 Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 9 Mar 2016 09:16:31 +0100 Subject: [PATCH 1422/2527] Split test for rejected records in store.fetchRecord This test contains assertions for correctly rejected records in coalesced requests AND an assertion that a warning is logged. This commit splits the test into two: the first tests the correct behavior for rejected records and the second tests that the warning for missing records is logged. The splitting is necessary since in an upcoming commit the tests are run in production too: since in that environment tests which check for assertions are stripped, currently we would lose this test. That's why this test is split beforehand so the behavior is tested in production build as well. --- tests/unit/store/adapter-interop-test.js | 52 ++++++++++++++++++------ 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index 24eff8b82b5..69ba59b1626 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -834,7 +834,7 @@ test("the promise returned by `scheduleFetch`, when it rejects, does not depend }); test("store.fetchRecord reject records that were not found, even when those requests were coalesced with records that were found", function(assert) { - assert.expect(3); + assert.expect(2); var Person = DS.Model.extend(); @@ -857,22 +857,48 @@ test("store.fetchRecord reject records that were not found, even when those requ test: Person }); - let done = assert.async(); - assert.expectWarning(function() { - run(function () { - var davidPromise = store.findRecord('test', 'david'); - var igorPromise = store.findRecord('test', 'igor'); + run(function () { + var davidPromise = store.findRecord('test', 'david'); + var igorPromise = store.findRecord('test', 'igor'); - davidPromise.then(assert.wait(function () { - assert.ok(true, "David resolved"); - })); + davidPromise.then(assert.wait(function () { + assert.ok(true, "David resolved"); + })); - igorPromise.then(null, assert.wait(function () { - assert.ok(true, "Igor rejected"); - })); + igorPromise.then(null, assert.wait(function () { + assert.ok(true, "Igor rejected"); + })); + }); +}); + +test("store.fetchRecord warns when records are missing", function(assert) { + var Person = DS.Model.extend(); + + var adapter = TestAdapter.extend({ + findMany(store, type, ids, snapshots) { + var records = ids.map(function(id) { + return { id: id }; + }); + + return new Ember.RSVP.Promise(function(resolve, reject) { + resolve([ + records[0] + ]); + }); + } + }); + + var store = createStore({ + adapter: adapter, + test: Person + }); + + assert.expectWarning(function() { + run(function () { + store.findRecord('test', 'david'); + store.findRecord('test', 'igor'); }); }, /expected to find records with the following ids in the adapter response but they were missing/); - done(); }); test("store should not call shouldReloadRecord when the record is not in the store", function(assert) { From c86ce5e380dc1513bcac82d8f7b17fbf6afea73b Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 9 Mar 2016 09:22:26 +0100 Subject: [PATCH 1423/2527] Run tests in production environment This adds a `testInDebug` helper, which skips tests when run in production. This helper either runs the tests normally via QUnit.test if we are not in a production environment. If the test is executed within production however, QUnit.skip is used instead so the test is skipped. This allows us to skip tests which don't make sense in the production environment: this are tests which check for warnings and assertions thrown within code. Since those assertions/warnings are stripped from production code, it doesn't make sense to run those tests in that environment. --- .travis.yml | 1 + appveyor.yml | 1 + package.json | 1 + tests/helpers/test-in-debug.js | 16 +++++++++++++ tests/integration/adapter/find-all-test.js | 3 ++- tests/integration/adapter/find-test.js | 7 +++--- tests/integration/adapter/queries-test.js | 7 +++--- .../integration/adapter/rest-adapter-test.js | 5 ++-- tests/integration/inverse-test.js | 5 ++-- .../integration/references/belongs-to-test.js | 3 ++- tests/integration/references/has-many-test.js | 3 ++- .../relationships/belongs-to-test.js | 9 ++++---- .../relationships/has-many-test.js | 11 +++++---- .../inverse-relationships-test.js | 5 ++-- .../relationships/one-to-one-test.js | 3 ++- .../polymorphic-mixins-belongs-to-test.js | 5 ++-- .../polymorphic-mixins-has-many-test.js | 5 ++-- .../embedded-records-mixin-test.js | 3 ++- .../serializers/json-api-serializer-test.js | 5 ++-- .../serializers/rest-serializer-test.js | 7 +++--- tests/integration/store-test.js | 5 ++-- .../store/json-api-validation-test.js | 23 ++++++++++--------- tests/integration/store/query-record-test.js | 5 ++-- tests/unit/adapter-errors-test.js | 3 ++- tests/unit/model-test.js | 23 ++++++++++--------- tests/unit/model/internal-model-test.js | 5 ++-- .../model/relationships/belongs-to-test.js | 5 ++-- .../unit/model/relationships/has-many-test.js | 5 ++-- tests/unit/store/adapter-interop-test.js | 11 +++++---- tests/unit/store/push-test.js | 17 +++++++------- tests/unit/store/serializer-for-test.js | 3 ++- tests/unit/store/unload-test.js | 3 ++- tests/unit/utils-test.js | 5 ++-- 33 files changed, 133 insertions(+), 85 deletions(-) create mode 100644 tests/helpers/test-in-debug.js diff --git a/.travis.yml b/.travis.yml index 45b372fdfd2..9b5a6506b5b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ script: - ./bin/lint-features - npm run-script test - npm run-script test:optional-features + - npm run-script test:production - npm run-script node-tests after_success: - npm run-script production diff --git a/appveyor.yml b/appveyor.yml index d8d597a6d8a..8b86725066d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,6 +27,7 @@ test_script: - npm version - cmd: npm run test - cmd: npm run test:optional-features + - cmd: npm run test:production - cmd: npm run node-tests # Don't actually build. diff --git a/package.json b/package.json index e82485b09be..cca19dbbdda 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "test": "ember try:testall", "node-tests": "node node-tests/nodetest-runner.js", "test:optional-features": "ember test --environment=test-optional-features", + "test:production": "ember test --environment=production", "bower": "bower install", "production": "ember build --environment=production" }, diff --git a/tests/helpers/test-in-debug.js b/tests/helpers/test-in-debug.js new file mode 100644 index 00000000000..d8bdd45a595 --- /dev/null +++ b/tests/helpers/test-in-debug.js @@ -0,0 +1,16 @@ +import { runInDebug } from 'ember-data/-private/debug'; +import { test, skip } from 'qunit'; + +export default function testInDebug() { + let isDebug = false; + + runInDebug(function() { + isDebug = true; + }); + + if (isDebug) { + test(...arguments); + } else { + skip(...arguments); + } +} diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index a6d5c93c126..3689ab97e79 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -1,6 +1,7 @@ import {createStore} from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -145,7 +146,7 @@ test("When all records for a type are requested, records that are created on the assert.equal(allRecords.objectAt(0).get('name'), "Carsten Nielsen", "the first item in the record array is Carsten Nielsen"); }); -test('When all records are requested, assert the payload is not blank', (assert) => { +testInDebug('When all records are requested, assert the payload is not blank', (assert) => { env.registry.register('adapter:person', DS.Adapter.extend({ findAll: () => Ember.RSVP.resolve({}) })); diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 46576aacd34..0c8043163ca 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -1,5 +1,6 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -29,7 +30,7 @@ module("integration/adapter/find - Finding Records", { } }); -test("It raises an assertion when `undefined` is passed as id (#1705)", (assert) => { +testInDebug("It raises an assertion when `undefined` is passed as id (#1705)", (assert) => { assert.expectAssertion(() => { store.find('person', undefined); }, "You cannot pass `undefined` as id to the store's find method"); @@ -130,7 +131,7 @@ test("When a single record is requested, and the promise is rejected, the record }); }); -test('When a single record is requested, and the payload is blank', (assert) => { +testInDebug('When a single record is requested, and the payload is blank', (assert) => { env.registry.register('adapter:person', DS.Adapter.extend({ findRecord: () => Ember.RSVP.resolve({}) })); @@ -140,7 +141,7 @@ test('When a single record is requested, and the payload is blank', (assert) => }, /the adapter's response did not have any data/); }); -test('When multiple records are requested, and the payload is blank', (assert) => { +testInDebug('When multiple records are requested, and the payload is blank', (assert) => { env.registry.register('adapter:person', DS.Adapter.extend({ coalesceFindRequests: true, findMany: () => Ember.RSVP.resolve({}) diff --git a/tests/integration/adapter/queries-test.js b/tests/integration/adapter/queries-test.js index 79e905fde96..dc5df8f39dc 100644 --- a/tests/integration/adapter/queries-test.js +++ b/tests/integration/adapter/queries-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -28,13 +29,13 @@ module("integration/adapter/queries - Queries", { } }); -test("It raises an assertion when no type is passed", function(assert) { +testInDebug("It raises an assertion when no type is passed", function(assert) { assert.expectAssertion(function() { store.query(); }, "You need to pass a type to the store's query method"); }); -test("It raises an assertion when no query hash is passed", function(assert) { +testInDebug("It raises an assertion when no query hash is passed", function(assert) { assert.expectAssertion(function() { store.query('person'); }, "You need to pass a query hash to the store's query method"); @@ -56,7 +57,7 @@ test("When a query is made, the adapter should receive a record array it can pop })); }); -test("The store asserts when query is made and the adapter responses with a single record.", function(assert) { +testInDebug("The store asserts when query is made and the adapter responses with a single record.", function(assert) { env = setupStore({ person: Person, adapter: DS.RESTAdapter }); store = env.store; adapter = env.adapter; diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 36251d94c2b..92350f1770f 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -1326,7 +1327,7 @@ test("queryRecord - returning an array picks the first one but saves all records })); }); -test("queryRecord - returning an empty array errors", function(assert) { +testInDebug("queryRecord - returning an empty array errors", function(assert) { ajaxResponse({ post: [] }); @@ -1876,7 +1877,7 @@ test('findBelongsTo - passes buildURL the requestType', function(assert) { })); }); -test('coalesceFindRequests assert.warns if the expected records are not returned in the coalesced request', function(assert) { +testInDebug('coalesceFindRequests assert.warns if the expected records are not returned in the coalesced request', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index cd2b1a78411..1b9a74beb47 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -98,7 +99,7 @@ test("Returns null if inverse relationship it is manually set with a different r assert.equal(User.inverseFor('job', store), null, 'There is no inverse'); }); -test("Errors out if you define 2 inverses to the same model", function(assert) { +testInDebug("Errors out if you define 2 inverses to the same model", function(assert) { Job.reopen({ user: belongsTo('user', { inverse: 'job', async: false }), owner: belongsTo('user', { inverse: 'job', async: false }) @@ -125,7 +126,7 @@ test("Caches findInverseFor return value", function(assert) { assert.equal(inverseForUser, Job.inverseFor('user', store), 'Inverse cached succesfully'); }); -test("Errors out if you do not define an inverse for a reflexive relationship", function(assert) { +testInDebug("Errors out if you do not define an inverse for a reflexive relationship", function(assert) { //Maybe store is evaluated lazily, so we need this :( assert.expectWarning(function() { diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index 83bc2c41f3a..b4cb24684bc 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -1,6 +1,7 @@ import DS from 'ember-data'; import Ember from 'ember'; import setupStore from 'dummy/tests/helpers/store'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; import isEnabled from 'ember-data/-private/features'; @@ -251,7 +252,7 @@ if (isEnabled("ds-references")) { }); }); - test("push(record) asserts for invalid type", function(assert) { + testInDebug("push(record) asserts for invalid type", function(assert) { var person, anotherPerson; run(function() { person = env.store.push({ diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index a94ab28eb65..38b68852cc2 100644 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -1,6 +1,7 @@ import DS from 'ember-data'; import Ember from 'ember'; import setupStore from 'dummy/tests/helpers/store'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; import isEnabled from 'ember-data/-private/features'; @@ -202,7 +203,7 @@ if (isEnabled("ds-references")) { }); }); - test("push(array) asserts polymorphic type", function(assert) { + testInDebug("push(array) asserts polymorphic type", function(assert) { var family; run(function() { family = env.store.push({ diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 524c6883da2..c016e7f834f 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -2,6 +2,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import isEnabled from 'ember-data/-private/features'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -130,7 +131,7 @@ test("The store can materialize a non loaded monomorphic belongsTo association", }); }); -test("Only a record of the same type can be used with a monomorphic belongsTo relationship", function(assert) { +testInDebug("Only a record of the same type can be used with a monomorphic belongsTo relationship", function(assert) { assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { @@ -161,7 +162,7 @@ test("Only a record of the same type can be used with a monomorphic belongsTo re }); }); -test("Only a record of the same base type can be used with a polymorphic belongsTo relationship", function(assert) { +testInDebug("Only a record of the same base type can be used with a polymorphic belongsTo relationship", function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; assert.expect(1); run(function() { @@ -727,7 +728,7 @@ test("Destroying a record with an unloaded aync belongsTo association does not f run(post, 'destroyRecord'); }); -test("A sync belongsTo errors out if the record is unlaoded", function(assert) { +testInDebug("A sync belongsTo errors out if the record is unlaoded", function(assert) { var message; run(function() { message = env.store.push({ @@ -833,7 +834,7 @@ test("Rollbacking attributes for a deleted record restores implicit relationship assert.equal(book.get('author'), author, 'Book has an author after rollback attributes'); }); -test("Passing a model as type to belongsTo should not work", function(assert) { +testInDebug("Passing a model as type to belongsTo should not work", function(assert) { assert.expect(1); assert.expectAssertion(function() { diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index a7178c5b2d7..ebd2e6f1971 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -1201,7 +1202,7 @@ test("Polymorphic relationships with a hasMany is set up correctly on both sides assert.equal(get(email, 'posts.length'), 1, "The inverse has many is set up correctly on the email side."); }); -test("A record can't be created from a polymorphic hasMany relationship", function(assert) { +testInDebug("A record can't be created from a polymorphic hasMany relationship", function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { env.store.push({ @@ -1228,7 +1229,7 @@ test("A record can't be created from a polymorphic hasMany relationship", functi }); }); -test("Only records of the same type can be added to a monomorphic hasMany relationship", function(assert) { +testInDebug("Only records of the same type can be added to a monomorphic hasMany relationship", function(assert) { assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { @@ -1260,7 +1261,7 @@ test("Only records of the same type can be added to a monomorphic hasMany relati }); }); -test("Only records of the same base type can be added to a polymorphic hasMany relationship", function(assert) { +testInDebug("Only records of the same base type can be added to a polymorphic hasMany relationship", function(assert) { assert.expect(2); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { @@ -1606,7 +1607,7 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the }); }); -test("A sync hasMany errors out if there are unlaoded records in it", function(assert) { +testInDebug("A sync hasMany errors out if there are unlaoded records in it", function(assert) { var post; run(function() { env.store.push({ @@ -2042,7 +2043,7 @@ test("ManyArray notifies the array observers and flushes bindings when adding", }); }); -test("Passing a model as type to hasMany should not work", function(assert) { +testInDebug("Passing a model as type to hasMany should not work", function(assert) { assert.expect(1); assert.expectAssertion(function() { diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index cd649ee8bf8..ce6cd166dd1 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -2,6 +2,7 @@ import {createStore} from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -424,7 +425,7 @@ test("When a record's polymorphic belongsTo relationship is set, it can specify assert.equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); }); -test("Inverse relationships that don't exist throw a nice error for a hasMany", function(assert) { +testInDebug("Inverse relationships that don't exist throw a nice error for a hasMany", function(assert) { User = DS.Model.extend(); Comment = DS.Model.extend(); @@ -446,7 +447,7 @@ test("Inverse relationships that don't exist throw a nice error for a hasMany", }, /We found no inverse relationships by the name of 'testPost' on the 'comment' model/); }); -test("Inverse relationships that don't exist throw a nice error for a belongsTo", function(assert) { +testInDebug("Inverse relationships that don't exist throw a nice error for a belongsTo", function(assert) { User = DS.Model.extend(); Comment = DS.Model.extend(); diff --git a/tests/integration/relationships/one-to-one-test.js b/tests/integration/relationships/one-to-one-test.js index 79dbd81f808..1ae4d48eecb 100644 --- a/tests/integration/relationships/one-to-one-test.js +++ b/tests/integration/relationships/one-to-one-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -498,7 +499,7 @@ test("Setting a BelongsTo to a promise works when the promise returns null- asyn }); -test("Setting a BelongsTo to a promise that didn't come from a relationship errors out", function(assert) { +testInDebug("Setting a BelongsTo to a promise that didn't come from a relationship errors out", function(assert) { var stanley, igor; run(function() { stanley = store.push({ diff --git a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index 661ed9514f8..0b9dee9114a 100644 --- a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -122,7 +123,7 @@ test("Setting the polymorphic belongsTo gets propagated to the inverse side - as }); }); -test("Setting the polymorphic belongsTo with an object that does not implement the mixin errors out", function(assert) { +testInDebug("Setting the polymorphic belongsTo with an object that does not implement the mixin errors out", function(assert) { var user, video; run(function() { store.push({ @@ -193,7 +194,7 @@ test("Setting the polymorphic belongsTo gets propagated to the inverse side - mo } }); -test("Setting the polymorphic belongsTo with an object that does not implement the mixin errors out - model injections true", function(assert) { +testInDebug("Setting the polymorphic belongsTo with an object that does not implement the mixin errors out - model injections true", function(assert) { var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; Ember.MODEL_FACTORY_INJECTIONS = true; diff --git a/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js index 2cbe646420e..a9f7e9962b8 100644 --- a/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -132,7 +133,7 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - async", /* Local edits */ -test("Pushing a an object that does not implement the mixin to the mixin accepting array errors out", function(assert) { +testInDebug("Pushing a an object that does not implement the mixin to the mixin accepting array errors out", function(assert) { var user,notMessage; run(function() { store.push({ @@ -215,7 +216,7 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - model i /* Local edits */ -test("Pushing a an object that does not implement the mixin to the mixin accepting array errors out - model injections true", function(assert) { +testInDebug("Pushing a an object that does not implement the mixin to the mixin accepting array errors out - model injections true", function(assert) { var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; Ember.MODEL_FACTORY_INJECTIONS = true; diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index 330a39bf715..0d8f4351931 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -952,7 +953,7 @@ test("serialize with embedded objects and a custom keyForAttribute (hasMany rela }); }); -test("serialize with embedded objects (unknown hasMany relationship)", function(assert) { +testInDebug("serialize with embedded objects (unknown hasMany relationship)", function(assert) { var league; run(function() { env.store.push({ diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 42ed40cdf32..0cbdb900577 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -116,7 +117,7 @@ test('Calling pushPayload works', function(assert) { }); }); -test('Warns when normalizing an unknown type', function(assert) { +testInDebug('Warns when normalizing an unknown type', function(assert) { var documentHash = { data: { type: 'UnknownType', @@ -134,7 +135,7 @@ test('Warns when normalizing an unknown type', function(assert) { }, /Encountered a resource object with type "UnknownType", but no model was found for model name "unknown-type"/); }); -test('Warns when normalizing with type missing', function(assert) { +testInDebug('Warns when normalizing with type missing', function(assert) { var documentHash = { data: { id: '1', diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 1133c152d38..a052cade369 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -143,7 +144,7 @@ test("normalizeResponse with custom modelNameFromPayloadKey", function(assert) { }); }); -test("normalizeResponse warning with custom modelNameFromPayloadKey", function(assert) { +testInDebug("normalizeResponse warning with custom modelNameFromPayloadKey", function(assert) { var homePlanet; var oldModelNameFromPayloadKey = env.restSerializer.modelNameFromPayloadKey; env.restSerializer.modelNameFromPayloadKey = function(root) { @@ -178,7 +179,7 @@ test("normalizeResponse warning with custom modelNameFromPayloadKey", function(a assert.deepEqual(homePlanet.data.relationships.superVillains.data, [{ id: '1', type: 'super-villain' }]); }); -test("normalizeResponse warning with custom modelNameFromPayloadKey", function(assert) { +testInDebug("normalizeResponse warning with custom modelNameFromPayloadKey", function(assert) { var homePlanets; env.restSerializer.modelNameFromPayloadKey = function(root) { //return some garbage that won"t resolve in the container @@ -484,7 +485,7 @@ test('serializeBelongsTo with async polymorphic', function(assert) { assert.deepEqual(json, expected, 'returned JSON is correct'); }); -test('serializeBelongsTo logs deprecation when old behavior for getting polymorphic type key is used', function(assert) { +testInDebug('serializeBelongsTo logs deprecation when old behavior for getting polymorphic type key is used', function(assert) { var evilMinion, doomsdayDevice; var json = {}; var expected = { evilMinion: '1', myCustomKeyType: 'evilMinion' }; diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index c9f36478016..e3c98b1c68e 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -316,7 +317,7 @@ test("store#findRecord { reload: true } ignores cached record and reloads record }); }); -test('store#findRecord call with `id` of type different than non-empty string or number should trigger an assertion', assert => { +testInDebug('store#findRecord call with `id` of type different than non-empty string or number should trigger an assertion', assert => { const badValues = ['', undefined, null, NaN, false]; assert.expect(badValues.length); @@ -568,7 +569,7 @@ test("Store should accept a null value for `data`", function(assert) { }); }); -test('store#findRecord that returns an array should assert', assert => { +testInDebug('store#findRecord that returns an array should assert', assert => { initializeStore(DS.JSONAPIAdapter.extend({ findRecord: function() { return { data: [] }; diff --git a/tests/integration/store/json-api-validation-test.js b/tests/integration/store/json-api-validation-test.js index 97ff456f596..0f5d7638763 100644 --- a/tests/integration/store/json-api-validation-test.js +++ b/tests/integration/store/json-api-validation-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; -import QUnit, {module, test} from 'qunit'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import QUnit, { module } from 'qunit'; import DS from 'ember-data'; var Person, store, env; @@ -26,7 +27,7 @@ module("integration/store/json-validation", { } }); -test("when normalizeResponse returns undefined (or doesn't return), throws an error", function(assert) { +testInDebug("when normalizeResponse returns undefined (or doesn't return), throws an error", function(assert) { env.registry.register('serializer:person', DS.Serializer.extend({ normalizeResponse() {} @@ -45,7 +46,7 @@ test("when normalizeResponse returns undefined (or doesn't return), throws an er }, /Top level of a JSON API document must be an object/); }); -test("when normalizeResponse returns null, throws an error", function(assert) { +testInDebug("when normalizeResponse returns null, throws an error", function(assert) { env.registry.register('serializer:person', DS.Serializer.extend({ normalizeResponse() {return null;} @@ -65,7 +66,7 @@ test("when normalizeResponse returns null, throws an error", function(assert) { }); -test("when normalizeResponse returns an empty object, throws an error", function(assert) { +testInDebug("when normalizeResponse returns an empty object, throws an error", function(assert) { env.registry.register('serializer:person', DS.Serializer.extend({ normalizeResponse() {return {};} @@ -84,7 +85,7 @@ test("when normalizeResponse returns an empty object, throws an error", function }, /One or more of the following keys must be present/); }); -test("when normalizeResponse returns a document with both data and errors, throws an error", function(assert) { +testInDebug("when normalizeResponse returns a document with both data and errors, throws an error", function(assert) { env.registry.register('serializer:person', DS.Serializer.extend({ normalizeResponse() { @@ -128,7 +129,7 @@ QUnit.assert.payloadError = function payloadError(payload, expectedError) { env.registry.unregister('adapter:person'); }; -test("normalizeResponse 'data' cannot be undefined, a number, a string or a boolean", function(assert) { +testInDebug("normalizeResponse 'data' cannot be undefined, a number, a string or a boolean", function(assert) { assert.payloadError({ data: undefined }, /data must be/); assert.payloadError({ data: 1 }, /data must be/); @@ -137,7 +138,7 @@ test("normalizeResponse 'data' cannot be undefined, a number, a string or a bool }); -test("normalizeResponse 'meta' cannot be an array, undefined, a number, a string or a boolean", function(assert) { +testInDebug("normalizeResponse 'meta' cannot be an array, undefined, a number, a string or a boolean", function(assert) { assert.payloadError({ meta: undefined }, /meta must be an object/); assert.payloadError({ meta: [] }, /meta must be an object/); @@ -147,7 +148,7 @@ test("normalizeResponse 'meta' cannot be an array, undefined, a number, a string }); -test("normalizeResponse 'links' cannot be an array, undefined, a number, a string or a boolean", function(assert) { +testInDebug("normalizeResponse 'links' cannot be an array, undefined, a number, a string or a boolean", function(assert) { assert.payloadError({ data: [], links: undefined }, /links must be an object/); assert.payloadError({ data: [], links: [] }, /links must be an object/); @@ -157,7 +158,7 @@ test("normalizeResponse 'links' cannot be an array, undefined, a number, a strin }); -test("normalizeResponse 'jsonapi' cannot be an array, undefined, a number, a string or a boolean", function(assert) { +testInDebug("normalizeResponse 'jsonapi' cannot be an array, undefined, a number, a string or a boolean", function(assert) { assert.payloadError({ data: [], jsonapi: undefined }, /jsonapi must be an object/); assert.payloadError({ data: [], jsonapi: [] }, /jsonapi must be an object/); @@ -167,7 +168,7 @@ test("normalizeResponse 'jsonapi' cannot be an array, undefined, a number, a str }); -test("normalizeResponse 'included' cannot be an object, undefined, a number, a string or a boolean", function(assert) { +testInDebug("normalizeResponse 'included' cannot be an object, undefined, a number, a string or a boolean", function(assert) { assert.payloadError({ included: undefined }, /included must be an array/); assert.payloadError({ included: {} }, /included must be an array/); @@ -177,7 +178,7 @@ test("normalizeResponse 'included' cannot be an object, undefined, a number, a s }); -test("normalizeResponse 'errors' cannot be an object, undefined, a number, a string or a boolean", function(assert) { +testInDebug("normalizeResponse 'errors' cannot be an object, undefined, a number, a string or a boolean", function(assert) { assert.payloadError({ errors: undefined }, /errors must be an array/); assert.payloadError({ errors: {} }, /errors must be an array/); diff --git a/tests/integration/store/query-record-test.js b/tests/integration/store/query-record-test.js index a695dec0354..e69611d7912 100644 --- a/tests/integration/store/query-record-test.js +++ b/tests/integration/store/query-record-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -28,13 +29,13 @@ module("integration/store/query-record - Query one record with a query hash", { } }); -test("It raises an assertion when no type is passed", function(assert) { +testInDebug("It raises an assertion when no type is passed", function(assert) { assert.expectAssertion(function() { store.queryRecord(); }, "You need to pass a type to the store's queryRecord method"); }); -test("It raises an assertion when no query hash is passed", function(assert) { +testInDebug("It raises an assertion when no query hash is passed", function(assert) { assert.expectAssertion(function() { store.queryRecord('person'); }, "You need to pass a query hash to the store's queryRecord method"); diff --git a/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js index 7ea5f43060a..f3fc8c25dcd 100644 --- a/tests/unit/adapter-errors-test.js +++ b/tests/unit/adapter-errors-test.js @@ -1,5 +1,6 @@ import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -104,7 +105,7 @@ test("errorsArrayToHash for primary data object", function(assert) { assert.deepEqual(result, errorsPrimaryHash); }); -test("DS.InvalidError will normalize errors hash will assert", function(assert) { +testInDebug("DS.InvalidError will normalize errors hash will assert", function(assert) { var error; assert.expectAssertion(function() { diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 70b1f759c12..5d709d48760 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -1,6 +1,7 @@ import {createStore} from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import QUnit, {module, test} from 'qunit'; import DS from 'ember-data'; import isEnabled from 'ember-data/-private/features'; @@ -159,7 +160,7 @@ test("a record's id is included in its toString representation", function(assert }); }); -test("trying to set an `id` attribute should raise", function(assert) { +testInDebug("trying to set an `id` attribute should raise", function(assert) { Person = DS.Model.extend({ id: DS.attr('number'), name: DS.attr('string') @@ -416,7 +417,7 @@ test("a DS.Model can have a defaultValue without an attribute type", function(as assert.equal(get(tag, 'name'), "unknown", "the default value is found"); }); -test("Calling attr() throws a warning", function(assert) { +testInDebug("Calling attr() throws a warning", function(assert) { assert.expect(1); run(function() { @@ -429,7 +430,7 @@ test("Calling attr() throws a warning", function(assert) { }); if (!isEnabled('ds-references')) { - test("Calling belongsTo() throws a warning", function(assert) { + testInDebug("Calling belongsTo() throws a warning", function(assert) { assert.expect(1); run(function() { @@ -441,7 +442,7 @@ if (!isEnabled('ds-references')) { }); }); - test("Calling hasMany() throws a warning", function(assert) { + testInDebug("Calling hasMany() throws a warning", function(assert) { assert.expect(1); run(function() { @@ -630,7 +631,7 @@ test("a defaultValue function gets the record, options, and key", function(asser get(tag, 'createdAt'); }); -test("a complex object defaultValue is deprecated ", function(assert) { +testInDebug("a complex object defaultValue is deprecated ", function(assert) { var Tag = DS.Model.extend({ tagInfo: DS.attr({ defaultValue: [] }) }); @@ -648,7 +649,7 @@ test("a complex object defaultValue is deprecated ", function(assert) { }, /Non primitive defaultValues are deprecated/); }); -test("a null defaultValue is not deprecated", function(assert) { +testInDebug("a null defaultValue is not deprecated", function(assert) { var Tag = DS.Model.extend({ tagInfo: DS.attr({ defaultValue: null }) }); @@ -980,7 +981,7 @@ test("a DS.Model can describe Date attributes", function(assert) { assert.convertsWhenSet('date', date, dateString); }); -test("don't allow setting", function(assert) { +testInDebug("don't allow setting", function(assert) { var Person = DS.Model.extend(); var record; @@ -1033,7 +1034,7 @@ test("A DS.Model can be JSONified", function(assert) { assert.deepEqual(record.toJSON(), { name: "TomHuda" }); }); -test("A subclass of DS.Model can not use the `data` property", function(assert) { +testInDebug("A subclass of DS.Model can not use the `data` property", function(assert) { var Person = DS.Model.extend({ data: DS.attr('string'), name: DS.attr('string') @@ -1048,7 +1049,7 @@ test("A subclass of DS.Model can not use the `data` property", function(assert) }, /`data` is a reserved property name on DS.Model objects/); }); -test("A subclass of DS.Model can not use the `store` property", function(assert) { +testInDebug("A subclass of DS.Model can not use the `store` property", function(assert) { var Retailer = DS.Model.extend({ store: DS.attr(), name: DS.attr() @@ -1063,7 +1064,7 @@ test("A subclass of DS.Model can not use the `store` property", function(assert) }, /`store` is a reserved property name on DS.Model objects/); }); -test("A subclass of DS.Model can not use reserved properties", function(assert) { +testInDebug("A subclass of DS.Model can not use reserved properties", function(assert) { assert.expect(3); [ 'currentState', 'data', 'store' @@ -1105,7 +1106,7 @@ test("Pushing a record into the store should transition it to the loaded state", }); }); -test("A subclass of DS.Model throws an error when calling create() directly", function(assert) { +testInDebug("A subclass of DS.Model throws an error when calling create() directly", function(assert) { assert.throws(function() { Person.create(); }, /You should not call `create` on a model/, "Throws an error when calling create() on model"); diff --git a/tests/unit/model/internal-model-test.js b/tests/unit/model/internal-model-test.js index a6cc3690c79..04f21f4c363 100644 --- a/tests/unit/model/internal-model-test.js +++ b/tests/unit/model/internal-model-test.js @@ -1,6 +1,7 @@ import DS from 'ember-data'; -import {module, test} from 'qunit'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import { module } from 'qunit'; module("unit/model/internal-model - Internal Model"); @@ -12,7 +13,7 @@ MockModelFactory._create = function() { MockModelFactory.eachRelationship = function() { }; -test("Materializing a model twice errors out", function(assert) { +testInDebug("Materializing a model twice errors out", function(assert) { assert.expect(1); var internalModel = new DS.InternalModel(MockModelFactory, null, { }, null); diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index b4fd713e679..80bf52b3458 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -360,7 +361,7 @@ test("belongsTo supports relationships to models with id 0", function(assert) { }); }); -test("belongsTo gives a warning when provided with a serialize option", function(assert) { +testInDebug("belongsTo gives a warning when provided with a serialize option", function(assert) { var Hobby = DS.Model.extend({ name: DS.attr('string') }); @@ -412,7 +413,7 @@ test("belongsTo gives a warning when provided with a serialize option", function }); }); -test("belongsTo gives a warning when provided with an embedded option", function(assert) { +testInDebug("belongsTo gives a warning when provided with an embedded option", function(assert) { var Hobby = DS.Model.extend({ name: DS.attr('string') }); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 7c5040ccd85..d57ab8e6cce 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -770,7 +771,7 @@ test("DS.hasMany is async by default", function(assert) { }); }); -test("throws assertion if of not set with an array", function(assert) { +testInDebug("throws assertion if of not set with an array", function(assert) { var Person = DS.Model.extend(); var Tag = DS.Model.extend({ people: DS.hasMany('person') @@ -791,7 +792,7 @@ test("throws assertion if of not set with an array", function(assert) { }); }); -test("checks if passed array only contains instances of DS.Model", function(assert) { +testInDebug("checks if passed array only contains instances of DS.Model", function(assert) { var Person = DS.Model.extend(); var Tag = DS.Model.extend({ people: DS.hasMany('person') diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index 69ba59b1626..506c4079985 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -2,6 +2,7 @@ import {createStore} from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -38,7 +39,7 @@ test('Adapter can be set as a name', function(assert) { assert.ok(store.get('defaultAdapter') instanceof DS.RESTAdapter); }); -test('Adapter can not be set as an instance', function(assert) { +testInDebug('Adapter can not be set as an instance', function(assert) { assert.expect(1); store = DS.Store.create({ @@ -343,7 +344,7 @@ test("a new record of a particular type is created via store.createRecord(type)" assert.equal(get(person, 'name'), "Braaahm Dale", "Even if no hash is supplied, `set` still worked"); }); -test("a new record with a specific id can't be created if this id is already used in the store", function(assert) { +testInDebug("a new record with a specific id can't be created if this id is already used in the store", function(assert) { var Person = DS.Model.extend({ name: DS.attr('string') }); @@ -871,7 +872,7 @@ test("store.fetchRecord reject records that were not found, even when those requ }); }); -test("store.fetchRecord warns when records are missing", function(assert) { +testInDebug("store.fetchRecord warns when records are missing", function(assert) { var Person = DS.Model.extend(); var adapter = TestAdapter.extend({ @@ -1275,7 +1276,7 @@ test("store should reload all records in the background when `shouldBackgroundRe assert.equal(store.peekRecord('person', 1).get('name'), 'Tom'); }); -test("store should assert of the user tries to call store.filter", function(assert) { +testInDebug("store should assert of the user tries to call store.filter", function(assert) { assert.expect(1); var Person = DS.Model.extend({ @@ -1294,7 +1295,7 @@ test("store should assert of the user tries to call store.filter", function(asse }); -test("Calling adapterFor with a model class should assert", function(assert) { +testInDebug("Calling adapterFor with a model class should assert", function(assert) { var Person = DS.Model.extend({ name: DS.attr('string') }); diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index bc29f255792..d263b0dc004 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -482,7 +483,7 @@ test('calling push without data argument as an object raises an error', function }); }); -test('Calling push with a link for a non async relationship should warn', function(assert) { +testInDebug('Calling push with a link for a non async relationship should warn', function(assert) { Person.reopen({ phoneNumbers: hasMany('phone-number', { async: false }) }); @@ -499,7 +500,7 @@ test('Calling push with a link for a non async relationship should warn', functi }, /You have pushed a record of type 'person' with 'phoneNumbers' as a link, but the association is not an async relationship./); }); -test('Calling push with an unknown model name throws an assertion error', function(assert) { +testInDebug('Calling push with an unknown model name throws an assertion error', function(assert) { assert.expectAssertion(function() { run(function() { @@ -551,7 +552,7 @@ test('Calling push with a link containing the value null', function(assert) { assert.equal(person.get('firstName'), "Tan", "you can use links that contain null as a value"); }); -test('calling push with hasMany relationship the value must be an array', function(assert) { +testInDebug('calling push with hasMany relationship the value must be an array', function(assert) { var invalidValues = [ 1, 'string', @@ -581,7 +582,7 @@ test('calling push with hasMany relationship the value must be an array', functi }); }); -test('calling push with missing or invalid `id` throws assertion error', function(assert) { +testInDebug('calling push with missing or invalid `id` throws assertion error', function(assert) { var invalidValues = [ {}, { id: null }, @@ -601,7 +602,7 @@ test('calling push with missing or invalid `id` throws assertion error', functio }); }); -test('calling push with belongsTo relationship the value must not be an array', function(assert) { +testInDebug('calling push with belongsTo relationship the value must not be an array', function(assert) { assert.throws(function() { run(function() { store.push({ @@ -619,7 +620,7 @@ test('calling push with belongsTo relationship the value must not be an array', }, /must not be an array/); }); -test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown attributes", function(assert) { +testInDebug("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown attributes", function(assert) { run(function() { var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; try { @@ -643,7 +644,7 @@ test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown attribut }); }); -test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown relationships", function(assert) { +testInDebug("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown relationships", function(assert) { run(function() { var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; try { @@ -667,7 +668,7 @@ test("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown relation }); }); -test("Calling push with unknown keys should not warn by default", function(assert) { +testInDebug("Calling push with unknown keys should not warn by default", function(assert) { assert.expectNoWarning(function() { run(function() { store.push({ diff --git a/tests/unit/store/serializer-for-test.js b/tests/unit/store/serializer-for-test.js index 81a3cea97d2..701e85b3a65 100644 --- a/tests/unit/store/serializer-for-test.js +++ b/tests/unit/store/serializer-for-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -45,7 +46,7 @@ test("Calling serializerFor with a type that has not been registered and in an a assert.ok(store.serializerFor('person') instanceof DS.JSONSerializer, "serializer returned from serializerFor is an instance of DS.JSONSerializer"); }); -test("Calling serializerFor with a model class should assert", function(assert) { +testInDebug("Calling serializerFor with a model class should assert", function(assert) { assert.expectAssertion(function() { store.serializerFor(Person); }, /Passing classes to store.serializerFor has been removed/); diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index 1375e0312e7..f2a131ff676 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -1,6 +1,7 @@ import {createStore} from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -32,7 +33,7 @@ module("unit/store/unload - Store unloading records", { } }); -test("unload a dirty record", function(assert) { +testInDebug("unload a dirty record asserts", function(assert) { assert.expect(2); run(function() { diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index a8640b27003..36819fdf2f3 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -42,7 +43,7 @@ module("unit/utils", { } }); -test("assertPolymorphicType works for subclasses", function(assert) { +testInDebug("assertPolymorphicType works for subclasses", function(assert) { var user, post, person; Ember.run(function() { @@ -103,7 +104,7 @@ test("modelHasAttributeOrRelationshipNamedType", function(assert) { assert.equal(modelHasAttributeOrRelationshipNamedType(ModelWithTypeHasMany), true); }); -test("assertPolymorphicType works for mixins", function(assert) { +testInDebug("assertPolymorphicType works for mixins", function(assert) { var post, video, person; Ember.run(function() { From c60bb5bd32100c2af709852b18762648940c9298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20San=20Gil?= Date: Sun, 13 Mar 2016 17:59:43 +0100 Subject: [PATCH 1424/2527] Solves #4186 and fixes `this._super` call within `normalize` method. --- addon/serializers/rest.js | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 1e2eb5e937f..4be1b5cb793 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -15,8 +15,7 @@ var camelize = Ember.String.camelize; /** Normally, applications will use the `RESTSerializer` by implementing - the `normalize` method and individual normalizations under - `normalizeHash`. + the `normalize` method. This allows you to do whatever kind of munging you need, and is especially useful if your server is inconsistent and you need to @@ -29,7 +28,7 @@ var camelize = Ember.String.camelize; There are also a number of hooks that you might find useful to define across-the-board rules for your payload. These rules will be useful if your server is consistent, or if you're building an adapter for - an infrastructure service, like Parse, and want to encode service + an infrastructure service, like Firebase, and want to encode service conventions. For example, if all of your keys are underscored and all-caps, but @@ -124,10 +123,8 @@ var RESTSerializer = JSONSerializer.extend({ * With `App.Comment`, `"comments"` and `{ id: 2, body: "Rails is unagi" }` You can use this method, for example, to normalize underscored keys to camelized - or other general-purpose normalizations. - - If you want to do normalizations specific to some part of the payload, you - can specify those under `normalizeHash`. + or other general-purpose normalizations. You will only need to implement + `normalize` and manipulate the payload as desired. For example, if the `IDs` under `"comments"` are provided as `_id` instead of `id`, you can specify how to normalize just the comments: @@ -136,18 +133,20 @@ var RESTSerializer = JSONSerializer.extend({ import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - normalizeHash: { - comments: function(hash) { + normalize(model, hash, prop) { + if (prop === 'comments') { hash.id = hash._id; - delete hash._id; - return hash; + delete hash._id; } + + return this._super(...arguments); } }); ``` - The key under `normalizeHash` is just the original key that was in the original - payload. + On each call to the `normalize` method, the third parameter (`prop`) is always + one of the keys that were in the original payload or in the result of another + normalization as `normalizeResponse`. @method normalize @param {DS.Model} modelClass @@ -159,7 +158,7 @@ var RESTSerializer = JSONSerializer.extend({ if (this.normalizeHash && this.normalizeHash[prop]) { this.normalizeHash[prop](resourceHash); } - return this._super(modelClass, resourceHash, prop); + return this._super(modelClass, resourceHash); }, /** From e6868ccf907b914b8b57eda6b480bdfc3f53b26a Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Mon, 14 Mar 2016 14:32:23 +0100 Subject: [PATCH 1425/2527] Only show ember-cli-shims errors if actually installed This is useful for blueprint testing scenarios of other Ember.js addons, where ember-cli-shims might be mentioned in bower.json but is not actually installed just for the blueprint testing. --- index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 40f1e8bb68d..f6a6ca6d979 100644 --- a/index.js +++ b/index.js @@ -52,17 +52,17 @@ module.exports = { var emberDataBower = checker.for('ember-data', 'bower'); - if (shims && !shims.satisfies('< 0.1.0') && emberDataBower.satisfies('< 2.3.0-beta.3')) { + if (shims && shims.version && !shims.satisfies('< 0.1.0') && emberDataBower.satisfies('< 2.3.0-beta.3')) { throw new SilentError('Using a version of ember-cli-shims greater than or equal to 0.1.0 will cause errors while loading Ember Data < 2.3.0-beta.3 Please update ember-cli-shims from ' + shims.version + ' to 0.0.6'); } - if (shims && !shims.satisfies('>= 0.1.0') && emberDataBower.satisfies('>= 2.3.0-beta.3')) { + if (shims && shims.version && !shims.satisfies('>= 0.1.0') && emberDataBower.satisfies('>= 2.3.0-beta.3')) { throw new SilentError('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3.0-beta.3+. Please update ember-cli-shims from ' + shims.version + ' to 0.1.0.'); } } else { // NPM only, but ember-cli-shims does not match - if (shims && !shims.satisfies('>= 0.1.0') && semver.satisfies(version, '^2.3.0-beta.3')) { + if (shims && shims.version && !shims.satisfies('>= 0.1.0') && semver.satisfies(version, '^2.3.0-beta.3')) { throw new SilentError('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3.0-beta.3+. Please update ember-cli-shims from ' + shims.version + ' to 0.1.0.'); } } From 81615417961e393f732b6489534a9bbf92fd8c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Kvasni=C4=8Dka?= Date: Mon, 14 Mar 2016 16:07:12 +0100 Subject: [PATCH 1426/2527] fixed date parsing in IE --- addon/-private/ext/date.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/ext/date.js b/addon/-private/ext/date.js index c662e88a0f1..8bcc667e9a4 100644 --- a/addon/-private/ext/date.js +++ b/addon/-private/ext/date.js @@ -33,7 +33,7 @@ Ember.Date.parse = function (date) { // before falling back to any implementation-specific date parsing, so that’s what we do, even if native // implementations could be faster // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm - if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) { + if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?:(\d{2}))?)?)?$/.exec(date))) { // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC for (var i = 0, k; (k = numericKeys[i]); ++i) { struct[k] = +struct[k] || 0; From 5d592286004c09a17ffc6493c5e9ae7f2fcaa59d Mon Sep 17 00:00:00 2001 From: asakusuma Date: Tue, 15 Mar 2016 21:09:45 -0700 Subject: [PATCH 1427/2527] [DOC] Fix store.findAll return type --- addon/-private/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b810eba43bb..76846508d14 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -978,7 +978,7 @@ Store = Service.extend({ @method findAll @param {String} modelName @param {Object} options - @return {DS.AdapterPopulatedRecordArray} + @return {Promise} promise */ findAll(modelName, options) { assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); From 789208b8a90caec6af932f5e5ca181fc28e603cd Mon Sep 17 00:00:00 2001 From: Balint Erdi Date: Wed, 16 Mar 2016 10:31:10 +0100 Subject: [PATCH 1428/2527] [DOC beta] Fix typo in inline doc. of normalizeResponse --- addon/serializers/json.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 84c334643be..1a30272ef87 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -227,7 +227,7 @@ export default Serializer.extend({ var data = message.data; var modelClass = store.modelFor(data.modelName); var serializer = store.serializerFor(data.modelName); - var json = serializer.normalizeSingleResponse(store, modelClass, data, data.id); + var normalized = serializer.normalizeSingleResponse(store, modelClass, data, data.id); store.push(normalized); }); From d7d035b0996c4e1a25bb9b76fcc25d98e405de8e Mon Sep 17 00:00:00 2001 From: Aaron Sikes Date: Sun, 21 Feb 2016 21:44:05 -0500 Subject: [PATCH 1429/2527] [BUGFIX beta] Add asserts for passing the model name to store methods --- addon/-private/system/store.js | 22 +++++++++--- tests/integration/adapter/queries-test.js | 2 +- tests/integration/store/query-record-test.js | 2 +- tests/unit/store/asserts-test.js | 36 ++++++++++++++++++++ 4 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 tests/unit/store/asserts-test.js diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 76846508d14..d1dab334812 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -73,6 +73,7 @@ var get = Ember.get; var set = Ember.set; var once = Ember.run.once; var isNone = Ember.isNone; +var isPresent = Ember.isPresent; var Promise = Ember.RSVP.Promise; var copy = Ember.copy; var Store; @@ -281,6 +282,7 @@ Store = Service.extend({ @return {DS.Model} record */ createRecord(modelName, inputProperties) { + assert("You need to pass a model name to the store's createRecord method", isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var properties = copy(inputProperties) || new EmptyObject(); @@ -457,6 +459,7 @@ Store = Service.extend({ @return {Promise} promise */ findRecord(modelName, id, options) { + assert("You need to pass a model name to the store's findRecord method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); assert(badIdFormatAssertion, (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id))); @@ -531,6 +534,7 @@ Store = Service.extend({ @return {Promise} promise */ findByIds(modelName, ids) { + assert("You need to pass a model name to the store's findByIds method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); let promises = new Array(ids.length); @@ -721,6 +725,7 @@ Store = Service.extend({ @return {DS.Model|null} record */ peekRecord(modelName, id) { + assert("You need to pass a model name to the store's peekRecord method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); if (this.hasRecordForId(modelName, id)) { return this._internalModelForId(modelName, id).getRecord(); @@ -762,6 +767,7 @@ Store = Service.extend({ @return {Boolean} */ hasRecordForId(modelName, inputId) { + assert("You need to pass a model name to the store's hasRecordForId method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); var id = coerceId(inputId); @@ -780,6 +786,7 @@ Store = Service.extend({ @return {DS.Model} record */ recordForId(modelName, id) { + assert("You need to pass a model name to the store's recordForId method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); return this._internalModelForId(modelName, id).getRecord(); }, @@ -913,7 +920,7 @@ Store = Service.extend({ }, _query(modelName, query, array) { - assert("You need to pass a type to the store's query method", modelName); + assert("You need to pass a model name to the store's query method", isPresent(modelName)); assert("You need to pass a query hash to the store's query method", query); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); @@ -945,7 +952,7 @@ Store = Service.extend({ @return {Promise} promise */ queryRecord(modelName, query) { - assert("You need to pass a type to the store's queryRecord method", modelName); + assert("You need to pass a model name to the store's queryRecord method", isPresent(modelName)); assert("You need to pass a query hash to the store's queryRecord method", query); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); @@ -981,6 +988,7 @@ Store = Service.extend({ @return {Promise} promise */ findAll(modelName, options) { + assert("You need to pass a model name to the store's findAll method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); @@ -1050,6 +1058,7 @@ Store = Service.extend({ @return {DS.RecordArray} */ peekAll(modelName) { + assert("You need to pass a model name to the store's peekAll method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); @@ -1155,6 +1164,7 @@ Store = Service.extend({ @deprecated */ filter(modelName, query, filter) { + assert("You need to pass a model name to the store's filter method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); if (!Ember.ENV.ENABLE_DS_FILTER) { @@ -1206,6 +1216,7 @@ Store = Service.extend({ @return {boolean} */ recordIsLoaded(modelName, id) { + assert("You need to pass a model name to the store's recordIsLoaded method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); return this.hasRecordForId(modelName, id); }, @@ -1462,6 +1473,7 @@ Store = Service.extend({ @return {DS.Model} */ modelFor(modelName) { + assert("You need to pass a model name to the store's modelFor method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var factory = this.modelFactoryFor(modelName); @@ -1478,6 +1490,7 @@ Store = Service.extend({ }, modelFactoryFor(modelName) { + assert("You need to pass a model name to the store's modelFactoryFor method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var normalizedKey = normalizeModelName(modelName); @@ -1808,6 +1821,7 @@ Store = Service.extend({ @return {Object} The normalized payload */ normalize(modelName, payload) { + assert("You need to pass a model name to the store's normalize method", isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); var serializer = this.serializerFor(modelName); var model = this.modelFor(modelName); @@ -1901,7 +1915,7 @@ Store = Service.extend({ @return DS.Adapter */ adapterFor(modelName) { - + assert("You need to pass a model name to the store's adapterFor method", isPresent(modelName)); assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); return this.lookupAdapter(modelName); @@ -1937,7 +1951,7 @@ Store = Service.extend({ @return {DS.Serializer} */ serializerFor(modelName) { - + assert("You need to pass a model name to the store's serializerFor method", isPresent(modelName)); assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); var fallbacks = [ diff --git a/tests/integration/adapter/queries-test.js b/tests/integration/adapter/queries-test.js index dc5df8f39dc..966fe20009a 100644 --- a/tests/integration/adapter/queries-test.js +++ b/tests/integration/adapter/queries-test.js @@ -32,7 +32,7 @@ module("integration/adapter/queries - Queries", { testInDebug("It raises an assertion when no type is passed", function(assert) { assert.expectAssertion(function() { store.query(); - }, "You need to pass a type to the store's query method"); + }, "You need to pass a model name to the store's query method"); }); testInDebug("It raises an assertion when no query hash is passed", function(assert) { diff --git a/tests/integration/store/query-record-test.js b/tests/integration/store/query-record-test.js index e69611d7912..76376e5792a 100644 --- a/tests/integration/store/query-record-test.js +++ b/tests/integration/store/query-record-test.js @@ -32,7 +32,7 @@ module("integration/store/query-record - Query one record with a query hash", { testInDebug("It raises an assertion when no type is passed", function(assert) { assert.expectAssertion(function() { store.queryRecord(); - }, "You need to pass a type to the store's queryRecord method"); + }, "You need to pass a model name to the store's queryRecord method"); }); testInDebug("It raises an assertion when no query hash is passed", function(assert) { diff --git a/tests/unit/store/asserts-test.js b/tests/unit/store/asserts-test.js new file mode 100644 index 00000000000..a54134bf049 --- /dev/null +++ b/tests/unit/store/asserts-test.js @@ -0,0 +1,36 @@ +import {module} from 'qunit'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import {createStore} from 'dummy/tests/helpers/store'; + +module("unit/store/asserts - DS.Store methods produce useful assertion messages"); + +const MODEL_NAME_METHODS = [ + 'createRecord', + 'findRecord', + 'findByIds', + 'peekRecord', + 'hasRecordForId', + 'recordForId', + 'query', + 'queryRecord', + 'findAll', + 'peekAll', + 'filter', + 'recordIsLoaded', + 'modelFor', + 'modelFactoryFor', + 'normalize', + 'adapterFor', + 'serializerFor' +]; + +testInDebug("Calling Store methods with no type asserts", function(assert) { + assert.expect(MODEL_NAME_METHODS.length); + let store = createStore(); + + MODEL_NAME_METHODS.forEach(function(methodName) { + assert.expectAssertion(function() { + store[methodName](null); + }, new RegExp(`You need to pass a model name to the store's ${methodName} method`)); + }); +}); From c23fc6c73322dd1a4bf30411d68c036168064cff Mon Sep 17 00:00:00 2001 From: Aaron Sikes Date: Fri, 18 Mar 2016 11:09:48 -0400 Subject: [PATCH 1430/2527] [DOC] Add note on `testInDebug` Addresses point 4 in Issue #4238 --- CONTRIBUTING.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8c1a55b451b..291513ecaf6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -90,7 +90,7 @@ taken straight from the Ruby on Rails guide: * Update the documentation, the surrounding one, examples elsewhere, guides, whatever is affected by your contribution -Syntax: +## Syntax: * Two spaces, no tabs. * No trailing whitespace. Blank lines should not have any space. @@ -99,4 +99,10 @@ Syntax: And in case we didn't emphasize it enough: we love tests! +## Writing Tests + +* We do write tests for our warns and assertion messages, using the `assert.expectAssertion()` and `assert.expectWarning()` helpers. +* Because Travis runs tests in the `production` environment, assertions and warnings are stripped out. To avoid tests on warning/assertion messages failing for your PR, use the `testInDebug` helper to skip them in production. See [this](https://github.com/emberjs/data/blob/b3eb9c098ef8c2cf9ff3378ed079769782c02bb5/tests/integration/adapter/queries-test.js#L32) example. + + NOTE: Partially copied from https://raw.github.com/thoughtbot/factory_girl_rails/master/CONTRIBUTING.md From 2f7f15be612a4bde61ba8d53ee500926c13f3ca7 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 18 Mar 2016 11:52:26 -0400 Subject: [PATCH 1431/2527] Add release notes for Ember Data 2.4.1 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 154e298ab42..cd7c5b29834 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ### Master +### Release 2.4.1 (March 18, 2016) +- [#3559](https://github.com/emberjs/data/pull/3559) [BUGFIX release] Guard against isDestroyed in ManyArray.flushCanonical +- [#4154](https://github.com/emberjs/data/pull/4154) Make sure new record are not pushed twice when parent is saved before. +- [#4204](https://github.com/emberjs/data/pull/4204) Fix RESTAdapter.findRecord without a snapshot +- [#4205](https://github.com/emberjs/data/pull/4205) [BUGFIX release] ensure import paths are resolved \w posix separators +- [#4214](https://github.com/emberjs/data/pull/4214) Fix AMD dependencies + ### Release 2.4.0 (February 29, 2016) - [#4125](https://github.com/emberjs/data/pull/4125) [BUGFIX beta] Export more public API's via modules - [#4135](https://github.com/emberjs/data/pull/4135) import require From 75dc527fc247260a4fc750fd4beb7c1cb3ce0bdf Mon Sep 17 00:00:00 2001 From: Travis Peterson Date: Fri, 18 Mar 2016 11:03:32 -0500 Subject: [PATCH 1432/2527] moves the ember dependency in the package-manager package.json into optionalDependencies --- config/package-manager-files/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/package-manager-files/package.json b/config/package-manager-files/package.json index d61ac1dc4e5..766038782b4 100644 --- a/config/package-manager-files/package.json +++ b/config/package-manager-files/package.json @@ -6,7 +6,7 @@ "ember" ], "main": "./ember-data.js", - "dependencies": { + "optionalDependencies": { "ember": ">= 2.0.0 < 3.0.0" }, "jspm": { From bc80bc72c85688845b150d8d3396bdd1c3f8de66 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Fri, 19 Feb 2016 10:49:09 -0500 Subject: [PATCH 1433/2527] Create RELEASE.md --- RELEASE.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 RELEASE.md diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 00000000000..9ee2b4eee11 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,62 @@ +Release +======= + +Although not very tricky, the Ember Data release process does have a +lot of manual steps. The following steps navigate us through +some of the release gotchas and will hopefully result in a successful +release. + +STEPS: +------ + +* generate changelog (`PRIOR_VERSION=v2.0.0 HEAD=release ./bin/changelog`) +* prepend changelog output to `CHANGELOG.md` +* edit changelog output to be as user-friendly as possible (drop [INTERNAL] changes, non-code changes, etc.) + * If this is the release branch make sure to pr the changelog to the master branch and cherry pick it to the release branch. + * If this is the beta branch the changelogs do not need to be pred to the master branch as master will be updated when the beta goes to release. +* Bump version in package.json + * `git add package.json` + * `git commit -m "Release Ember Data X.Y.Z-beta.n"` +* Git tag version + * `git tag vX.Y.Z-beta.n` +* Do a production build. `rm -rf node_modules bower_components; npm install; bower install; npm run production` +* Publish to Bower + * Commit built globals code to the https://github.com/components/ember-data repo + * `cp dist/globals/* ../components-ember-data/` +* Publish Rubygems + * `gem build ember-data-source.gemspec` + * `gem push ember-data-source-2.4.0.beta.1.gem` +* Publish to NPM + * `npm publish` or `npm publish --tag beta` or `npm publish --tag release-1-13` +* Update the `/builds/` page on the website + * `cd ../website` + * Edit [lastRelease, futureVersion and date](https://github.com/emberjs/website/blob/master/source/javascripts/app/builds/app.js#L238-L241) values for the release channel we are releasing. + * Commit updated `javascripts/app/builds/app.js` file + * `rake deploy` +* Website API docs (This step does not happen for beta releases) + * `cd ../website` + * `rake generate_ember_data_docs` + * Commit updated `data/data_api.yml` file + * `rake deploy` +* Write a Release Blog Post (Does not happen for beta releases) + * Commits since last release: `git log --oneline release..beta | wc -l`. + * Contributors since last release: `git shortlog -s -n release...beta | wc -l` +* Submit a Pull request to the https://github.com/ember-cli/ember-cli to update the version of Ember Data + * (per request by @rwjblue and is also a great idea to make upgrading/new apps easier) +* Bump version in package.json back to a canary version +* For beta.1 releases, branch beta from master and update https://github.com/emberjs/data/blob/master/config/features.json to have `false` values instead of `null` and update the version in package.json + + +Tag the release + +1. Under `Releases` on GitHub choose `Draft New Release` +* enter the new version number as the tag prefixed with `v` e.g. (`v0.1.12`) +* for release title choose a great name, no pressure +* in the description paste the changelog items for this release only +* click pre-release for beta releases +* publish the release + +Announce release! + +1. on Twitter +* then crosslink Twitter post on slack #dev-ember-data and #ember-data From 8c67ac7492ba8efd2f34a3a98b82ddd16beae813 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 18 Mar 2016 11:16:59 -0400 Subject: [PATCH 1434/2527] Fix spacing issue thats causing jscs errors on the beta branch --- addon/adapters/rest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 7cded79adb2..1b018c9bcf5 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -996,7 +996,7 @@ export default Adapter.extend(BuildURLMixin, { let query = {}; if (isEnabled('ds-finder-include')) { - if(snapshot) { + if (snapshot) { const { include } = snapshot; if (include) { From 110c08d7ff9e8f202975d61ab28dd5aff26c805a Mon Sep 17 00:00:00 2001 From: Aaron Sikes Date: Fri, 18 Mar 2016 13:20:32 -0400 Subject: [PATCH 1435/2527] [DOC] Add section on commit tagging to CONTRIBUTING.md --- CONTRIBUTING.md | 54 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 291513ecaf6..b8ccc7683f6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -74,7 +74,18 @@ a test! 4. Make the test pass. -5. Push to your fork and submit a pull request. Please provide us with some +5. Commit your changes. Please use an appropriate commit prefix. +If your pull request fixes an issue specify it in the commit message. Some examples: + + ``` + [DOC beta] Update CONTRIBUTING.md for commit prefixes + [FEATURE ds-pushpayload-return] Change `pushPayload` to return a value. #4110 + [BUGFIX beta] Allow optional spaces when parsing response headers + ``` + + For more information about commit prefixes see [Commit Tagging](#commit-tagging). + +6. Push to your fork and submit a pull request. Please provide us with some explanation of why you made the changes you made. For new features make sure to explain a standard use case to us. @@ -99,10 +110,49 @@ taken straight from the Ruby on Rails guide: And in case we didn't emphasize it enough: we love tests! + ## Writing Tests * We do write tests for our warns and assertion messages, using the `assert.expectAssertion()` and `assert.expectWarning()` helpers. * Because Travis runs tests in the `production` environment, assertions and warnings are stripped out. To avoid tests on warning/assertion messages failing for your PR, use the `testInDebug` helper to skip them in production. See [this](https://github.com/emberjs/data/blob/b3eb9c098ef8c2cf9ff3378ed079769782c02bb5/tests/integration/adapter/queries-test.js#L32) example. +## Commit Tagging + +All commits should be tagged. Tags are denoted by square brackets (`[]`) and come at the start of the commit message. + +### Bug Fixes + +In general bug fixes are pulled into the beta branch. As such, the prefix is: `[BUGFIX beta]`. If a bug fix is a serious regression that requires a new patch release, `[BUGFIX release]` can be used instead. + +For bugs related to canary features, follow the prefixing rules for features. + +The vast majority of bug fixes apply to the current stable or beta releases, so submit your PR against the `master` branch with one of the above mentioned BUGFIX tags. +(In the unusual case of a bug fix specifically for a past release, tag for that release `[BUGFIX release-1-13]` and submit the PR against the stable branch for that release: `stable-1-13`.) + +### Cleanup + +Cleanup commits are for removing deprecated functionality and should be tagged +as `[CLEANUP beta]`. + +### Features + +All additions and fixes for features in canary should be tagged as `[FEATURE name]` where name is the same as the flag for that feature. + +### Documentation + +Documentation commits are tagged as `[DOC channel]` where channel is `canary`, +`beta`, or `release`. If no release is provided `canary` is assumed. The channel should be the most stable release that this documentation change applies to. + +### Security + +Security commits will be tagged as `[SECURITY cve]`. Please do not submit security related PRs without coordinating with the security team. See the [Security Policy](http://emberjs.com/security/) for more information. + +### Other + +In general almost all commits should fall into one of these categories. In the cases where they don't please submit your PR untagged. An ember-data contributor will let you know if tagging is required. + + +NOTE: +* Partially copied from https://raw.github.com/thoughtbot/factory_girl_rails/master/CONTRIBUTING.md +* Commit tagging section taken from [ember.js](https://github.com/emberjs/ember.js/blob/5641c3089180bdd1d4fa54e9dd2d3ac285f088e4/CONTRIBUTING.md#commit-tagging) -NOTE: Partially copied from https://raw.github.com/thoughtbot/factory_girl_rails/master/CONTRIBUTING.md From 41f2089f959e3da3226b97019966cb72fd9e8ffe Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 22 Dec 2015 20:36:14 +0100 Subject: [PATCH 1436/2527] [FEATURE ds-improved-ajax] Finer control over customizing a request Though `ajax()` (and `ajaxOptions()`) of `DS.RESTAdapter` are marked as private, they have been overwritten in many applications, since there is currently no other way to customize the request. This feature adds new public methods to `DS.RESTAdapter`, which allow to customize the properties of a request: - `methodForRequest` to get the HTTP verb - `urlForRequest` to get the URL - `headersForRequest` to get the headers - `dataForRequest` to get the data (query params or request body) The `params` hash passed to those methods has all the properties with which the corresponding `find`, `createRecord`, `findQuery`, ... call have been invoked: store, type, snapshot(s), id(s) and query. The `requestType` property indicates which method is requested; the possible values are: - `createRecord` - `updateRecord` - `deleteRecord` - `query` - `queryRecord` - `findRecord` - `findAll` - `findMany` - `findHasMany` - `findBelongsTo` Performing the actual AJAX request is handled by the `_makeRequest` method, which is similar to the existing `ajax` method: it makes the request using `jQuery.ajax` and attaches success and failure handlers. --- Say your API handles creation of resources via PUT, this can now be customized as follows: ``` js // adapters/application.js import DS from 'ember-data'; export DS.RESTAdapter.extend({ methodForRequest: function(params) { if (params.requestType === 'createRecord') { return "PUT"; } return this._super(...arguments); } }); ``` --- FEATURES.md | 6 + addon/adapters/json-api.js | 85 +++- addon/adapters/rest.js | 425 ++++++++++++++++-- config/features.json | 1 + .../adapter/build-url-mixin-test.js | 19 +- .../adapter/json-api-adapter-test.js | 27 +- .../integration/adapter/rest-adapter-test.js | 24 +- tests/integration/store-test.js | 20 +- tests/unit/adapters/rest-adapter/ajax-test.js | 40 +- .../group-records-for-find-many-test.js | 53 ++- tests/unit/model/rollback-attributes-test.js | 101 +++-- 11 files changed, 673 insertions(+), 128 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index d9129ee65ba..b929d18f8ea 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -23,6 +23,12 @@ entry in `config/features.json`. `store.findRecord()` and `store.findAll()` as described in [RFC 99](https://github.com/emberjs/rfcs/pull/99) +- `ds-improved-ajax` + + This feature allows to customize how a request is formed by overwriting + `methodForRequest`, `urlForRequest`, `headersForRequest` and `bodyForRequest` + in the `DS.RESTAdapter`. + - `ds-references` Adds references as described in [RFC 57](https://github.com/emberjs/rfcs/pull/57) diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index 97923564492..7fd59392376 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -4,6 +4,7 @@ import Ember from 'ember'; import RESTAdapter from "ember-data/adapters/rest"; +import isEnabled from 'ember-data/-private/features'; /** @class JSONAPIAdapter @@ -11,7 +12,7 @@ import RESTAdapter from "ember-data/adapters/rest"; @namespace DS @extends DS.RESTAdapter */ -export default RESTAdapter.extend({ +var JSONAPIAdapter = RESTAdapter.extend({ defaultSerializer: '-json-api', /** @@ -98,8 +99,12 @@ export default RESTAdapter.extend({ @return {Promise} promise */ findMany(store, type, ids, snapshots) { - var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); - return this.ajax(url, 'GET', { data: { filter: { id: ids.join(',') } } }); + if (isEnabled('ds-improved-ajax')) { + return this._super(...arguments); + } else { + var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); + return this.ajax(url, 'GET', { data: { filter: { id: ids.join(',') } } }); + } }, /** @@ -121,14 +126,76 @@ export default RESTAdapter.extend({ @return {Promise} promise */ updateRecord(store, type, snapshot) { - var data = {}; - var serializer = store.serializerFor(type.modelName); + if (isEnabled('ds-improved-ajax')) { + return this._super(...arguments); + } else { + var data = {}; + var serializer = store.serializerFor(type.modelName); - serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); + serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); - var id = snapshot.id; - var url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); + var id = snapshot.id; + var url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); - return this.ajax(url, 'PATCH', { data: data }); + return this.ajax(url, 'PATCH', { data: data }); + } } }); + +if (isEnabled('ds-improved-ajax')) { + + JSONAPIAdapter.reopen({ + + methodForRequest(params) { + if (params.requestType === 'updateRecord') { + return 'PATCH'; + } + + return this._super(...arguments); + }, + + dataForRequest(params) { + const { requestType, ids } = params; + + if (requestType === 'findMany') { + return { + filter: { id: ids.join(',') } + }; + } + + if (requestType === 'updateRecord') { + const { store, type, snapshot } = params; + const data = {}; + const serializer = store.serializerFor(type.modelName); + + serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); + + return data; + } + + return this._super(...arguments); + }, + + headersForRequest() { + const headers = this._super(...arguments) || {}; + + headers['Accept'] = 'application/vnd.api+json'; + + return headers; + }, + + _requestToJQueryAjaxHash() { + const hash = this._super(...arguments); + + if (hash.contentType) { + hash.contentType = 'application/vnd.api+json'; + } + + return hash; + } + + }); + +} + +export default JSONAPIAdapter; diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 7cded79adb2..438b33aa94b 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -193,7 +193,7 @@ const { @extends DS.Adapter @uses DS.BuildURLMixin */ -export default Adapter.extend(BuildURLMixin, { +var RESTAdapter = Adapter.extend(BuildURLMixin, { defaultSerializer: '-rest', /** @@ -375,10 +375,19 @@ export default Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findRecord(store, type, id, snapshot) { - const url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); - const query = this.buildQuery(snapshot); + if (isEnabled('ds-improved-ajax')) { + const request = this._requestFor({ + store, type, id, snapshot, + requestType: 'findRecord' + }); + + return this._makeRequest(request); + } else { + const url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); + const query = this.buildQuery(snapshot); - return this.ajax(url, 'GET', { data: query }); + return this.ajax(url, 'GET', { data: query }); + } }, /** @@ -396,14 +405,25 @@ export default Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findAll(store, type, sinceToken, snapshotRecordArray) { - const url = this.buildURL(type.modelName, null, null, 'findAll'); const query = this.buildQuery(snapshotRecordArray); - if (sinceToken) { - query.since = sinceToken; - } + if (isEnabled('ds-improved-ajax')) { + const request = this._requestFor({ + store, type, sinceToken, query, + snapshots: snapshotRecordArray, + requestType: 'findAll' + }); + + return this._makeRequest(request); + } else { + const url = this.buildURL(type.modelName, null, null, 'findAll'); + + if (sinceToken) { + query.since = sinceToken; + } - return this.ajax(url, 'GET', { data: query }); + return this.ajax(url, 'GET', { data: query }); + } }, /** @@ -424,13 +444,22 @@ export default Adapter.extend(BuildURLMixin, { @return {Promise} promise */ query(store, type, query) { - var url = this.buildURL(type.modelName, null, null, 'query', query); + if (isEnabled('ds-improved-ajax')) { + const request = this._requestFor({ + store, type, query, + requestType: 'query' + }); - if (this.sortQueryParams) { - query = this.sortQueryParams(query); - } + return this._makeRequest(request); + } else { + var url = this.buildURL(type.modelName, null, null, 'query', query); - return this.ajax(url, 'GET', { data: query }); + if (this.sortQueryParams) { + query = this.sortQueryParams(query); + } + + return this.ajax(url, 'GET', { data: query }); + } }, /** @@ -451,13 +480,22 @@ export default Adapter.extend(BuildURLMixin, { @return {Promise} promise */ queryRecord(store, type, query) { - var url = this.buildURL(type.modelName, null, null, 'queryRecord', query); + if (isEnabled('ds-improved-ajax')) { + const request = this._requestFor({ + store, type, query, + requestType: 'queryRecord' + }); - if (this.sortQueryParams) { - query = this.sortQueryParams(query); - } + return this._makeRequest(request); + } else { + var url = this.buildURL(type.modelName, null, null, 'queryRecord', query); + + if (this.sortQueryParams) { + query = this.sortQueryParams(query); + } - return this.ajax(url, 'GET', { data: query }); + return this.ajax(url, 'GET', { data: query }); + } }, /** @@ -494,8 +532,17 @@ export default Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findMany(store, type, ids, snapshots) { - var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); - return this.ajax(url, 'GET', { data: { ids: ids } }); + if (isEnabled('ds-improved-ajax')) { + const request = this._requestFor({ + store, type, ids, snapshots, + requestType: 'findMany' + }); + + return this._makeRequest(request); + } else { + var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); + return this.ajax(url, 'GET', { data: { ids: ids } }); + } }, /** @@ -534,12 +581,21 @@ export default Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findHasMany(store, snapshot, url, relationship) { - var id = snapshot.id; - var type = snapshot.modelName; + if (isEnabled('ds-improved-ajax')) { + const request = this._requestFor({ + store, snapshot, url, relationship, + requestType: 'findHasMany' + }); - url = this.urlPrefix(url, this.buildURL(type, id, null, 'findHasMany')); + return this._makeRequest(request); + } else { + var id = snapshot.id; + var type = snapshot.modelName; - return this.ajax(url, 'GET'); + url = this.urlPrefix(url, this.buildURL(type, id, null, 'findHasMany')); + + return this.ajax(url, 'GET'); + } }, /** @@ -578,11 +634,20 @@ export default Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findBelongsTo(store, snapshot, url, relationship) { - var id = snapshot.id; - var type = snapshot.modelName; + if (isEnabled('ds-improved-ajax')) { + const request = this._requestFor({ + store, snapshot, url, relationship, + requestType: 'findBelongsTo' + }); + + return this._makeRequest(request); + } else { + var id = snapshot.id; + var type = snapshot.modelName; - url = this.urlPrefix(url, this.buildURL(type, id, null, 'findBelongsTo')); - return this.ajax(url, 'GET'); + url = this.urlPrefix(url, this.buildURL(type, id, null, 'findBelongsTo')); + return this.ajax(url, 'GET'); + } }, /** @@ -602,13 +667,22 @@ export default Adapter.extend(BuildURLMixin, { @return {Promise} promise */ createRecord(store, type, snapshot) { - var data = {}; - var serializer = store.serializerFor(type.modelName); - var url = this.buildURL(type.modelName, null, snapshot, 'createRecord'); + if (isEnabled('ds-improved-ajax')) { + const request = this._requestFor({ + store, type, snapshot, + requestType: 'createRecord' + }); + + return this._makeRequest(request); + } else { + var data = {}; + var serializer = store.serializerFor(type.modelName); + var url = this.buildURL(type.modelName, null, snapshot, 'createRecord'); - serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); + serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); - return this.ajax(url, "POST", { data: data }); + return this.ajax(url, "POST", { data: data }); + } }, /** @@ -628,15 +702,24 @@ export default Adapter.extend(BuildURLMixin, { @return {Promise} promise */ updateRecord(store, type, snapshot) { - var data = {}; - var serializer = store.serializerFor(type.modelName); + if (isEnabled('ds-improved-ajax')) { + const request = this._requestFor({ + store, type, snapshot, + requestType: 'updateRecord' + }); - serializer.serializeIntoHash(data, type, snapshot); + return this._makeRequest(request); + } else { + var data = {}; + var serializer = store.serializerFor(type.modelName); - var id = snapshot.id; - var url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); + serializer.serializeIntoHash(data, type, snapshot); + + var id = snapshot.id; + var url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); - return this.ajax(url, "PUT", { data: data }); + return this.ajax(url, "PUT", { data: data }); + } }, /** @@ -651,9 +734,18 @@ export default Adapter.extend(BuildURLMixin, { @return {Promise} promise */ deleteRecord(store, type, snapshot) { - var id = snapshot.id; + if (isEnabled('ds-improved-ajax')) { + const request = this._requestFor({ + store, type, snapshot, + requestType: 'deleteRecord' + }); + + return this._makeRequest(request); + } else { + var id = snapshot.id; - return this.ajax(this.buildURL(type.modelName, id, snapshot, 'deleteRecord'), "DELETE"); + return this.ajax(this.buildURL(type.modelName, id, snapshot, 'deleteRecord'), "DELETE"); + } }, _stripIDFromURL(store, snapshot) { @@ -1009,6 +1101,253 @@ export default Adapter.extend(BuildURLMixin, { } }); +if (isEnabled('ds-improved-ajax')) { + + RESTAdapter.reopen({ + + /** + * Get the data (body or query params) for a request. + * + * @public + * @method dataForRequest + * @param {Object} params + * @return {Object} data + */ + dataForRequest(params) { + var { store, type, snapshot, requestType, query } = params; + + // type is not passed to findBelongsTo and findHasMany + type = type || (snapshot && snapshot.type); + + var serializer = store.serializerFor(type.modelName); + var data = {}; + + switch (requestType) { + case 'createRecord': + serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); + break; + + case 'updateRecord': + serializer.serializeIntoHash(data, type, snapshot); + break; + + case 'findRecord': + data = this.buildQuery(snapshot); + break; + + case 'findAll': + if (params.sinceToken) { + query = query || {}; + query.since = params.sinceToken; + } + data = query; + break; + + case 'query': + case 'queryRecord': + if (this.sortQueryParams) { + query = this.sortQueryParams(query); + } + data = query; + break; + + case 'findMany': + data = { ids: params.ids }; + break; + + default: + data = undefined; + break; + } + + return data; + }, + + /** + * Get the HTTP method for a request. + * + * @public + * @method methodForRequest + * @param {Object} params + * @return {String} HTTP method + */ + methodForRequest(params) { + const { requestType } = params; + + switch (requestType) { + case 'createRecord': return 'POST'; + case 'updateRecord': return 'PUT'; + case 'deleteRecord': return 'DELETE'; + } + + return 'GET'; + }, + + /** + * Get the URL for a request. + * + * @public + * @method urlForRequest + * @param {Object} params + * @return {String} URL + */ + urlForRequest(params) { + var { type, id, ids, snapshot, snapshots, requestType, query } = params; + + // type and id are not passed from updateRecord and deleteRecord, hence they + // are defined if not set + type = type || (snapshot && snapshot.type); + id = id || (snapshot && snapshot.id); + + switch (requestType) { + case 'findAll': + return this.buildURL(type.modelName, null, null, requestType); + + case 'query': + case 'queryRecord': + return this.buildURL(type.modelName, null, null, requestType, query); + + case 'findMany': + return this.buildURL(type.modelName, ids, snapshots, requestType); + + case 'findHasMany': + case 'findBelongsTo': + let url = this.buildURL(type.modelName, id, null, requestType); + return this.urlPrefix(params.url, url); + } + + return this.buildURL(type.modelName, id, snapshot, requestType, query); + }, + + /** + * Get the headers for a request. + * + * By default the value of the `headers` property of the adapter is + * returned. + * + * @public + * @method headersForRequest + * @param {Object} params + * @return {Object} headers + */ + headersForRequest(params) { + return this.get('headers'); + }, + + /** + * Get an object which contains all properties for a request which should + * be made. + * + * @private + * @method _requestFor + * @param {Object} params + * @return {Object} request object + */ + _requestFor(params) { + const method = this.methodForRequest(params); + const url = this.urlForRequest(params); + const headers = this.headersForRequest(params); + const data = this.dataForRequest(params); + + return { method, url, headers, data }; + }, + + /** + * Convert a request object into a hash which can be passed to `jQuery.ajax`. + * + * @private + * @method _requestToJQueryAjaxHash + * @param {Object} request + * @return {Object} jQuery ajax hash + */ + _requestToJQueryAjaxHash(request) { + const hash = {}; + + hash.type = request.method; + hash.url = request.url; + hash.dataType = 'json'; + hash.context = this; + + if (request.data) { + if (request.type !== 'GET') { + hash.contentType = 'application/json; charset=utf-8'; + hash.data = JSON.stringify(request.data); + } else { + hash.data = request.data; + } + } + + var headers = request.headers; + if (headers !== undefined) { + hash.beforeSend = function(xhr) { + Object.keys(headers).forEach((key) => xhr.setRequestHeader(key, headers[key])); + }; + } + + return hash; + }, + + /** + * Make a request using `jQuery.ajax`. + * + * @private + * @method _makeRequest + * @param {Object} request + * @return {Promise} promise + */ + _makeRequest(request) { + const adapter = this; + const hash = this._requestToJQueryAjaxHash(request); + + const { method, url } = request; + const requestData = { method, url }; + + return new Ember.RSVP.Promise((resolve, reject) => { + + hash.success = function(payload, textStatus, jqXHR) { + let response = adapter.handleResponse( + jqXHR.status, + parseResponseHeaders(jqXHR.getAllResponseHeaders()), + payload, + requestData + ); + + if (response instanceof AdapterError) { + Ember.run.join(null, reject, response); + } else { + Ember.run.join(null, resolve, response); + } + }; + + hash.error = function(jqXHR, textStatus, errorThrown) { + let error; + + if (errorThrown instanceof Error) { + error = errorThrown; + } else if (textStatus === 'timeout') { + error = new TimeoutError(); + } else if (textStatus === 'abort') { + error = new AbortError(); + } else { + error = adapter.handleResponse( + jqXHR.status, + parseResponseHeaders(jqXHR.getAllResponseHeaders()), + adapter.parseErrorResponse(jqXHR.responseText) || errorThrown, + requestData + ); + } + + Ember.run.join(null, reject, error); + }; + + adapter._ajaxRequest(hash); + + }, `DS: RESTAdapter#makeRequest: ${method} ${url}`); + } + }); + +} + //From http://stackoverflow.com/questions/280634/endswith-in-javascript function endsWith(string, suffix) { if (typeof String.prototype.endsWith !== 'function') { @@ -1017,3 +1356,5 @@ function endsWith(string, suffix) { return string.endsWith(suffix); } } + +export default RESTAdapter; diff --git a/config/features.json b/config/features.json index 1ef9bd5a04b..4bb5e64d30b 100644 --- a/config/features.json +++ b/config/features.json @@ -1,6 +1,7 @@ { "ds-boolean-transform-allow-null": null, "ds-finder-include": null, + "ds-improved-ajax": null, "ds-references": null, "ds-transform-pass-options": null, "ds-pushpayload-return": null, diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index cb5ce7f4ae9..c77edd82c23 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -1,5 +1,6 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import isEnabled from 'ember-data/-private/features'; import {module, test} from 'qunit'; @@ -40,11 +41,19 @@ module("integration/adapter/build-url-mixin - BuildURLMixin with RESTAdapter", { }); function ajaxResponse(value) { - adapter.ajax = function(url, verb, hash) { - passedUrl = url; - - return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); - }; + if (isEnabled('ds-improved-ajax')) { + adapter._makeRequest = function(request) { + passedUrl = request.url; + + return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); + }; + } else { + adapter.ajax = function(url, verb, hash) { + passedUrl = url; + + return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); + }; + } } diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index 4012a4b2d2f..1ddff308851 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -4,6 +4,7 @@ import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; var env, store, adapter; var passedUrl, passedVerb, passedHash; @@ -89,15 +90,27 @@ function ajaxResponse(responses) { passedVerb = []; passedHash = []; - adapter.ajax = function(url, verb, hash) { - index = counter++; + if (isEnabled('ds-improved-ajax')) { + adapter._makeRequest = function(request) { + index = counter++; - passedUrl[index] = url; - passedVerb[index] = verb; - passedHash[index] = hash; + passedUrl[index] = request.url; + passedVerb[index] = request.method; + passedHash[index] = request.data ? { data: request.data } : undefined; - return run(Ember.RSVP, 'resolve', responses[index]); - }; + return run(Ember.RSVP, 'resolve', responses[index]); + }; + } else { + adapter.ajax = function(url, verb, hash) { + index = counter++; + + passedUrl[index] = url; + passedVerb[index] = verb; + passedHash[index] = hash; + + return run(Ember.RSVP, 'resolve', responses[index]); + }; + } } test('find a single record', function(assert) { diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 92350f1770f..0b98572ff3e 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -39,13 +39,23 @@ module("integration/adapter/rest_adapter - REST Adapter", { }); function ajaxResponse(value) { - adapter.ajax = function(url, verb, hash) { - passedUrl = url; - passedVerb = verb; - passedHash = hash; - - return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); - }; + if (isEnabled('ds-improved-ajax')) { + adapter._makeRequest = function(request) { + passedUrl = request.url; + passedVerb = request.method; + passedHash = request.data ? { data: request.data } : undefined; + + return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); + }; + } else { + adapter.ajax = function(url, verb, hash) { + passedUrl = url; + passedVerb = verb; + passedHash = hash; + + return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); + }; + } } test("findRecord - basic payload", function(assert) { diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index e3c98b1c68e..d6c7785a4e0 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -5,6 +5,7 @@ import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; var store, env; @@ -202,13 +203,20 @@ test("destroying the store correctly cleans everything up", function(assert) { function ajaxResponse(value) { var passedUrl, passedVerb, passedHash; - env.adapter.ajax = function(url, verb, hash) { - passedUrl = url; - passedVerb = verb; - passedHash = hash; - return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); - }; + if (isEnabled('ds-improved-ajax')) { + env.adapter._makeRequest = function() { + return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); + }; + } else { + env.adapter.ajax = function(url, verb, hash) { + passedUrl = url; + passedVerb = verb; + passedHash = hash; + + return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); + }; + } } diff --git a/tests/unit/adapters/rest-adapter/ajax-test.js b/tests/unit/adapters/rest-adapter/ajax-test.js index f699282cf67..1dc80a2c662 100644 --- a/tests/unit/adapters/rest-adapter/ajax-test.js +++ b/tests/unit/adapters/rest-adapter/ajax-test.js @@ -4,6 +4,7 @@ import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; var Person, Place, store, adapter, env; var run = Ember.run; @@ -28,12 +29,23 @@ module("unit/adapters/rest-adapter/ajax - building requests", { test("When an id is searched, the correct url should be generated", function(assert) { assert.expect(2); var count = 0; - adapter.ajax = function(url, method) { - if (count === 0) { assert.equal(url, '/people/1', "should create the correct url"); } - if (count === 1) { assert.equal(url, '/places/1', "should create the correct url"); } - count++; - return Ember.RSVP.resolve(); - }; + + if (isEnabled('ds-improved-ajax')) { + adapter._makeRequest = function(request) { + if (count === 0) { assert.equal(request.url, '/people/1', "should create the correct url"); } + if (count === 1) { assert.equal(request.url, '/places/1', "should create the correct url"); } + count++; + return Ember.RSVP.resolve(); + }; + } else { + adapter.ajax = function(url, method) { + if (count === 0) { assert.equal(url, '/people/1', "should create the correct url"); } + if (count === 1) { assert.equal(url, '/places/1', "should create the correct url"); } + count++; + return Ember.RSVP.resolve(); + }; + } + run(function() { adapter.findRecord(store, Person, 1, {}); adapter.findRecord(store, Place, 1, {}); @@ -42,10 +54,18 @@ test("When an id is searched, the correct url should be generated", function(ass test("id's should be sanatized", function(assert) { assert.expect(1); - adapter.ajax = function(url, method) { - assert.equal(url, '/people/..%2Fplace%2F1', "should create the correct url"); - return Ember.RSVP.resolve(); - }; + + if (isEnabled('ds-improved-ajax')) { + adapter._makeRequest = function(request) { + assert.equal(request.url, '/people/..%2Fplace%2F1', "should create the correct url"); + return Ember.RSVP.resolve(); + }; + } else { + adapter.ajax = function(url, method) { + assert.equal(url, '/people/..%2Fplace%2F1', "should create the correct url"); + return Ember.RSVP.resolve(); + }; + } run(function() { adapter.findRecord(store, Person, '../place/1', {}); }); diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 49baf6d173b..87d68414090 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -4,6 +4,7 @@ import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; var GroupsAdapter, Store; var maxLength = -1; @@ -17,25 +18,45 @@ module("unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda findRecord(store, type, id, snapshot) { return Ember.RSVP.Promise.resolve({ id: id }); - }, - - ajax(url, type, options) { - var queryString = options.data.ids.map(function(i) { - return encodeURIComponent('ids[]') + '=' + encodeURIComponent(i); - }).join('&'); - var fullUrl = url + '?' + queryString; - - maxLength = this.get('maxURLLength'); - lengths.push(fullUrl.length); - - var testRecords = options.data.ids.map(function(id) { - return { id: id }; - }); - return Ember.RSVP.Promise.resolve({ 'testRecords' : testRecords }); } - }); + if (isEnabled('ds-improved-ajax')) { + GroupsAdapter.reopen({ + _makeRequest(request) { + var queryString = request.data.ids.map(function(i) { + return encodeURIComponent('ids[]') + '=' + encodeURIComponent(i); + }).join('&'); + var fullUrl = request.url + '?' + queryString; + + maxLength = this.get('maxURLLength'); + lengths.push(fullUrl.length); + + var testRecords = request.data.ids.map(function(id) { + return { id: id }; + }); + return Ember.RSVP.Promise.resolve({ 'testRecords' : testRecords }); + } + }); + } else { + GroupsAdapter.reopen({ + ajax(url, type, options) { + var queryString = options.data.ids.map(function(i) { + return encodeURIComponent('ids[]') + '=' + encodeURIComponent(i); + }).join('&'); + var fullUrl = url + '?' + queryString; + + maxLength = this.get('maxURLLength'); + lengths.push(fullUrl.length); + + var testRecords = options.data.ids.map(function(id) { + return { id: id }; + }); + return Ember.RSVP.Promise.resolve({ 'testRecords' : testRecords }); + } + }); + } + Store = createStore({ adapter: GroupsAdapter, testRecord: DS.Model.extend() diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index 1014af6ec95..9c58865b958 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -4,6 +4,7 @@ import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; var env, store, Person, Dog; var run = Ember.run; @@ -224,11 +225,21 @@ test("invalid new record's attributes can be rollbacked", function(assert) { source: { pointer: 'data/attributes/name' } } ]); - var adapter = DS.RESTAdapter.extend({ - ajax(url, type, hash) { - return Ember.RSVP.reject(error); - } - }); + + var adapter; + if (isEnabled('ds-improved-ajax')) { + adapter = DS.RESTAdapter.extend({ + _makeRequest() { + return Ember.RSVP.reject(error); + } + }); + } else { + adapter = DS.RESTAdapter.extend({ + ajax(url, type, hash) { + return Ember.RSVP.reject(error); + } + }); + } env = setupStore({ person: Person, adapter: adapter }); @@ -254,12 +265,22 @@ test("invalid new record's attributes can be rollbacked", function(assert) { test("invalid record's attributes can be rollbacked after multiple failed calls - #3677", function(assert) { var person; - var adapter = DS.RESTAdapter.extend({ - ajax(url, type, hash) { - var error = new DS.InvalidError(); - return Ember.RSVP.reject(error); - } - }); + var adapter; + if (isEnabled('ds-improved-ajax')) { + adapter = DS.RESTAdapter.extend({ + _makeRequest() { + var error = new DS.InvalidError(); + return Ember.RSVP.reject(error); + } + }); + } else { + adapter = DS.RESTAdapter.extend({ + ajax(url, type, hash) { + var error = new DS.InvalidError(); + return Ember.RSVP.reject(error); + } + }); + } env = setupStore({ person: Person, adapter: adapter }); @@ -335,11 +356,21 @@ test("invalid record's attributes can be rollbacked", function(assert) { } ]); - var adapter = DS.RESTAdapter.extend({ - ajax(url, type, hash) { - return Ember.RSVP.reject(error); - } - }); + var adapter; + if (isEnabled('ds-improved-ajax')) { + adapter = DS.RESTAdapter.extend({ + _makeRequest() { + return Ember.RSVP.reject(error); + } + }); + } else { + adapter = DS.RESTAdapter.extend({ + ajax(url, type, hash) { + return Ember.RSVP.reject(error); + } + }); + } + env = setupStore({ dog: Dog, adapter: adapter }); var dog; @@ -396,11 +427,20 @@ test("invalid record's attributes rolled back to correct state after set", funct } ]); - var adapter = DS.RESTAdapter.extend({ - ajax(url, type, hash) { - return Ember.RSVP.reject(error); - } - }); + var adapter; + if (isEnabled('ds-improved-ajax')) { + adapter = DS.RESTAdapter.extend({ + _makeRequest() { + return Ember.RSVP.reject(error); + } + }); + } else { + adapter = DS.RESTAdapter.extend({ + ajax(url, type, hash) { + return Ember.RSVP.reject(error); + } + }); + } env = setupStore({ dog: Dog, adapter: adapter }); var dog; @@ -463,11 +503,20 @@ test("when destroying a record setup the record state to invalid, the record's a } ]); - var adapter = DS.RESTAdapter.extend({ - ajax(url, type, hash) { - return Ember.RSVP.reject(error); - } - }); + var adapter; + if (isEnabled('ds-improved-ajax')) { + adapter = DS.RESTAdapter.extend({ + _makeRequest() { + return Ember.RSVP.reject(error); + } + }); + } else { + adapter = DS.RESTAdapter.extend({ + ajax(url, type, hash) { + return Ember.RSVP.reject(error); + } + }); + } env = setupStore({ dog: Dog, adapter: adapter }); var dog; From 0f46f66de19f6b0443a87bd634b1f5b5f14187aa Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Sun, 28 Feb 2016 12:06:11 -0500 Subject: [PATCH 1437/2527] [BUGFIX beta] Use modelNameFromPayloadKey for type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code checked for a model using the possibly-overridden modelNameFromPayloadKey but didn’t use the override when getting the serialiser and model. --- addon/serializers/rest.js | 4 +- .../serializers/rest-serializer-test.js | 39 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 1e2eb5e937f..b2692ffc6fc 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -200,8 +200,8 @@ var RESTSerializer = JSONSerializer.extend({ const primaryHasTypeAttribute = modelHasAttributeOrRelationshipNamedType(primaryModelClass); // Support polymorphic records in async relationships if (!primaryHasTypeAttribute && hash.type && store._hasModelFor(this.modelNameFromPayloadKey(hash.type))) { - serializer = store.serializerFor(hash.type); - modelClass = store.modelFor(hash.type); + serializer = store.serializerFor(this.modelNameFromPayloadKey(hash.type)); + modelClass = store.modelFor(this.modelNameFromPayloadKey(hash.type)); } else { serializer = primarySerializer; modelClass = primaryModelClass; diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index a052cade369..b7e850e0f5f 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -144,6 +144,45 @@ test("normalizeResponse with custom modelNameFromPayloadKey", function(assert) { }); }); +test("normalizeResponse with type and custom modelNameFromPayloadKey", function(assert) { + assert.expect(2); + + var homePlanetNormalizeCount = 0; + + env.restSerializer.modelNameFromPayloadKey = function(root) { + return "home-planet"; + }; + + env.registry.register('serializer:home-planet', DS.RESTSerializer.extend({ + normalize() { + homePlanetNormalizeCount++; + return this._super.apply(this, arguments); + } + })); + + var jsonHash = { + "my-custom-type": [{ id: "1", name: "Umber", type: "my-custom-type" }] + }; + var array; + + run(function() { + array = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, '1', 'findAll'); + }); + + assert.deepEqual(array, { + data: [{ + id: '1', + type: 'home-planet', + attributes: { + name: 'Umber' + }, + relationships: {} + }], + included: [] + }); + assert.equal(homePlanetNormalizeCount, 1, "homePlanet is normalized once"); +}); + testInDebug("normalizeResponse warning with custom modelNameFromPayloadKey", function(assert) { var homePlanet; var oldModelNameFromPayloadKey = env.restSerializer.modelNameFromPayloadKey; From 0550d4517900ba9d1620d110376a3fcfe4e3c24f Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Sat, 19 Mar 2016 13:43:58 -0700 Subject: [PATCH 1438/2527] [BUGFIX release] fix prod-build issue --- lib/babel-build.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/babel-build.js b/lib/babel-build.js index 295ae7682b5..a66b5d49cc5 100644 --- a/lib/babel-build.js +++ b/lib/babel-build.js @@ -26,7 +26,9 @@ function babelOptions(libraryName, _options) { getModuleId: function (name) { return name.replace(/\/index$/g, ''); }, - resolveModuleSource: moduleResolve + resolveModuleSource: function(source, fileName) { + return moduleResolve.call(this, source, libraryName + '/' + fileName); + } }; Object.keys(_options).forEach(function(opt) { From 38d04715093176340d605c1a1f264234e3672137 Mon Sep 17 00:00:00 2001 From: bmac Date: Sat, 19 Mar 2016 19:15:36 -0400 Subject: [PATCH 1439/2527] [DOC release] Update changelog for the 2.4.2 release --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd7c5b29834..f7ae38b191f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ### Master +### Release 2.4.2 (March 19, 2016) +- [#4248](https://github.com/emberjs/data/pull/4248) [BUGFIX release] fix prod-build issue + ### Release 2.4.1 (March 18, 2016) - [#3559](https://github.com/emberjs/data/pull/3559) [BUGFIX release] Guard against isDestroyed in ManyArray.flushCanonical - [#4154](https://github.com/emberjs/data/pull/4154) Make sure new record are not pushed twice when parent is saved before. From 1471288f46628eade52ae2f2cb61ab5f791f6c39 Mon Sep 17 00:00:00 2001 From: bmac Date: Sat, 19 Mar 2016 20:36:25 -0400 Subject: [PATCH 1440/2527] [BUGFIX beta] Use Ember.assign when availability Closes https://github.com/emberjs/data/issues/4233. --- addon/-private/system/model/internal-model.js | 14 +++++++------- .../system/store/container-instance-cache.js | 3 ++- addon/serializers/json.js | 4 ++-- tests/helpers/start-app.js | 5 +++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 6d0378c550c..fbf64a21e28 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -20,7 +20,7 @@ var Promise = Ember.RSVP.Promise; var get = Ember.get; var set = Ember.set; var copy = Ember.copy; -var merge = Ember.merge; +var assign = Ember.assign || Ember.merge; var _extractPivotNameCache = new EmptyObject(); var _splitOnDotCache = new EmptyObject(); @@ -223,7 +223,7 @@ InternalModel.prototype = { setupData(data) { var changedKeys = this._changedKeys(data.attributes); - merge(this._data, data.attributes); + assign(this._data, data.attributes); this.pushedData(); if (this.record) { this.record._notifyProperties(changedKeys); @@ -334,7 +334,7 @@ InternalModel.prototype = { var oldData = this._data; var currentData = this._attributes; var inFlightData = this._inFlightAttributes; - var newData = merge(copy(inFlightData), currentData); + var newData = assign(copy(inFlightData), currentData); var diffData = new EmptyObject(); var newDataKeys = Object.keys(newData); @@ -664,9 +664,9 @@ InternalModel.prototype = { this.didCleanError(); var changedKeys = this._changedKeys(data); - merge(this._data, this._inFlightAttributes); + assign(this._data, this._inFlightAttributes); if (data) { - merge(this._data, data); + assign(this._data, data); } this._inFlightAttributes = new EmptyObject(); @@ -801,8 +801,8 @@ InternalModel.prototype = { var keys = Object.keys(updates); var length = keys.length; - original = merge(new EmptyObject(), this._data); - original = merge(original, this._inFlightAttributes); + original = assign(new EmptyObject(), this._data); + original = assign(original, this._inFlightAttributes); for (i = 0; i < length; i++) { key = keys[i]; diff --git a/addon/-private/system/store/container-instance-cache.js b/addon/-private/system/store/container-instance-cache.js index 8d36e808d1b..07d00e17e7e 100644 --- a/addon/-private/system/store/container-instance-cache.js +++ b/addon/-private/system/store/container-instance-cache.js @@ -1,5 +1,6 @@ import Ember from 'ember'; import EmptyObject from "ember-data/-private/system/empty-object"; +const assign = Ember.assign || Ember.merge; /** * The `ContainerInstanceCache` serves as a lazy cache for looking up @@ -26,7 +27,7 @@ export default function ContainerInstanceCache(owner) { ContainerInstanceCache.prototype = new EmptyObject(); -Ember.merge(ContainerInstanceCache.prototype, { +assign(ContainerInstanceCache.prototype, { get(type, preferredKey, fallbacks) { let cache = this._cache; let preferredLookupKey = `${type}:${preferredKey}`; diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 1a30272ef87..a11e5f771ab 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -15,7 +15,7 @@ import isEnabled from 'ember-data/-private/features'; var get = Ember.get; var isNone = Ember.isNone; -var merge = Ember.merge; +var assign = Ember.assign || Ember.merge; /** Ember Data 2.0 Serializer: @@ -1051,7 +1051,7 @@ export default Serializer.extend({ @param {Object} options */ serializeIntoHash(hash, typeClass, snapshot, options) { - merge(hash, this.serialize(snapshot, options)); + assign(hash, this.serialize(snapshot, options)); }, /** diff --git a/tests/helpers/start-app.js b/tests/helpers/start-app.js index e098f1d5be6..0bb77910549 100644 --- a/tests/helpers/start-app.js +++ b/tests/helpers/start-app.js @@ -1,12 +1,13 @@ import Ember from 'ember'; import Application from '../../app'; import config from '../../config/environment'; +var assign = Ember.assign || Ember.merge; export default function startApp(attrs) { let application; - let attributes = Ember.merge({}, config.APP); - attributes = Ember.merge(attributes, attrs); // use defaults, but you can override; + let attributes = assign({}, config.APP); + attributes = assign(attributes, attrs); // use defaults, but you can override; Ember.run(() => { application = Application.create(attributes); From 04a114bd679eaa0d877d87fd403f4408356a32b7 Mon Sep 17 00:00:00 2001 From: asakusuma Date: Mon, 21 Mar 2016 13:01:43 -0700 Subject: [PATCH 1441/2527] Add test asserting no unnecessary inverse work Addresses https://github.com/emberjs/data/issues/4236 --- .../inverse-relationships-test.js | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index ce6cd166dd1..4bf9f882ee7 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -468,3 +468,140 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a bel }); }, /We found no inverse relationships by the name of 'testPost' on the 'user' model/); }); + +test("inverseFor is only called when inverse is not null", function(assert) { + assert.expect(2); + Post = DS.Model.extend({ + comments: DS.hasMany('comment', { async: false, inverse: null }) + }); + + Comment = DS.Model.extend({ + post: DS.belongsTo('post', { async: false, inverse: null }) + }); + + User = DS.Model.extend({ + messages: DS.hasMany('message', { async: false, inverse: 'user' }) + }); + + Message = DS.Model.extend({ + user: DS.belongsTo('user', { async: false, inverse: 'messages' }) + }); + + var env = setupStore({ post: Post, comment: Comment, user: User, message: Message }); + var store = env.store; + + Post.inverseFor = function() { + assert.notOk(true, 'Post model inverseFor is not called'); + }; + + Comment.inverseFor = function() { + assert.notOk(true, 'Comment model inverseFor is not called'); + }; + + Message.inverseFor = function() { + assert.ok(true, 'Message model inverseFor is called'); + }; + + User.inverseFor = function() { + assert.ok(true, 'User model inverseFor is called'); + }; + + run(function() { + store.push({ + data: { + id: '1', + type: 'post', + relationships: { + comments: { + data: [ + { + id: '1', + type: 'comment' + }, + { + id: '2', + type: 'comment' + } + ] + } + } + } + }); + store.push({ + data: [ + { + id: '1', + type: 'comment', + relationships: { + post: { + data: { + id: '1', + type: 'post' + } + } + } + }, + { + id: '2', + type: 'comment', + relationships: { + post: { + data: { + id: '1', + type: 'post' + } + } + } + } + ] + }); + store.push({ + data: { + id: '1', + type: 'user', + relationships: { + messages: { + data: [ + { + id: '1', + type: 'message' + }, + { + id: '2', + type: 'message' + } + ] + } + } + } + }); + store.push({ + data: [ + { + id: '1', + type: 'message', + relationships: { + user: { + data: { + id: '1', + type: 'user' + } + } + } + }, + { + id: '2', + type: 'message', + relationships: { + post: { + data: { + id: '1', + type: 'user' + } + } + } + } + ] + }); + }); +}); From 274d7b1622c578bc47ea56c7bb86dd8f0e6f03db Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 21 Mar 2016 17:28:15 -0400 Subject: [PATCH 1442/2527] [BUGFIX release] Revert pr #3864 The origial intent was for a queryRecord with no response to reject the promise so it would act like a `findRecord` with a 404. This change introduced a regression that broke existing apps so it is going to be reverted. Closes #4219 --- addon/-private/system/store/finders.js | 1 - tests/integration/adapter/rest-adapter-test.js | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 638e0257de0..13b61c12183 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -196,7 +196,6 @@ export function _queryRecord(adapter, store, typeClass, query) { var record; store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'queryRecord'); - assert('`store.queryRecord` expected the adapter to return one record but the response from the adapter was empty.', payload.data); //TODO Optimize record = store.push(payload); }); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 0b98572ff3e..445cc1f0da8 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1337,18 +1337,6 @@ test("queryRecord - returning an array picks the first one but saves all records })); }); -testInDebug("queryRecord - returning an empty array errors", function(assert) { - ajaxResponse({ - post: [] - }); - - assert.expectAssertion(function() { - Ember.run(function() { - store.queryRecord('post', { slug: 'rails-is-omakaze' }); - }); - }, /`store.queryRecord` expected the adapter to return one record/); -}); - test("queryRecord - data is normalized through custom serializers", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', From e4f3e148a14fc5a3de0dc1d1a2ee5a628a1597d0 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 22 Mar 2016 10:11:01 -0400 Subject: [PATCH 1443/2527] Update changelog for Ember Data 2.4.3 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7ae38b191f..29f653013bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ### Master +### Release 2.4.3 (March 22, 2016) +- [#4243](https://github.com/emberjs/data/pull/4243) moves the ember dep in the package-manager package.json into optionalDependencies +- [#4256](https://github.com/emberjs/data/pull/4256) [BUGFIX release] Revert pr #3864 + ### Release 2.4.2 (March 19, 2016) - [#4248](https://github.com/emberjs/data/pull/4248) [BUGFIX release] fix prod-build issue From 59c70d5b42cd568a44cf0ae7d7a711580460c24e Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Tue, 22 Mar 2016 11:24:56 -0400 Subject: [PATCH 1444/2527] Update RELEASE.md --- RELEASE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 9ee2b4eee11..d68d2f45aa7 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -19,7 +19,8 @@ STEPS: * `git commit -m "Release Ember Data X.Y.Z-beta.n"` * Git tag version * `git tag vX.Y.Z-beta.n` -* Do a production build. `rm -rf node_modules bower_components; npm install; bower install; npm run production` +* Do a production build. + * `rm -rf node_modules bower_components; npm install; bower install; npm run production` * Publish to Bower * Commit built globals code to the https://github.com/components/ember-data repo * `cp dist/globals/* ../components-ember-data/` From 41b0ad0cec779b8d44b6de2849ef38e16d31e72a Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 22 Mar 2016 14:01:53 -0400 Subject: [PATCH 1445/2527] Warn when the JSONAPISerializer is extended with the EmbeddedRecordsMixin --- addon/serializers/embedded-records-mixin.js | 3 ++- addon/serializers/json-api.js | 5 +++++ tests/integration/serializers/json-api-serializer-test.js | 7 +++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 8285321a3e0..70801baf119 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -608,5 +608,6 @@ export default Ember.Mixin.create({ let serializer = store.serializerFor(modelName); return serializer.normalize(modelClass, relationshipHash, null); - } + }, + isEmbeddedRecordsMixin: true }); diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index a811ed4b5c0..3c940b1113f 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -500,6 +500,11 @@ const JSONAPISerializer = JSONSerializer.extend({ runInDebug(function() { JSONAPISerializer.reopen({ + willMergeMixin(props) { + warn('The JSONAPISerializer does not work with the EmbeddedRecordsMixin because the JSON API spec does not describe how to format embedded resources.', !props.isEmbeddedRecordsMixin, { + id: 'ds.serializer.embedded-records-mixin-not-supported' + }); + }, warnMessageForUndefinedType() { return 'Encountered a resource object with an undefined type (resolved resource using ' + this.constructor.toString() + ')'; }, diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 0cbdb900577..ac13e34c6b5 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -260,3 +260,10 @@ test('Serializer should respect the attrs hash when serializing attributes with assert.equal(payload.data.attributes['company_name'], 'Tilde Inc.'); }); + + +testInDebug('JSON warns when combined with EmbeddedRecordsMixin', function(assert) { + assert.expectWarning(function() { + DS.JSONAPISerializer.extend(DS.EmbeddedRecordsMixin).create(); + }, /The JSONAPISerializer does not work with the EmbeddedRecordsMixin/); +}); From de43c2ccf834ec081d58387d5fefece12697b721 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 22 Mar 2016 13:32:31 -0400 Subject: [PATCH 1446/2527] Deprecate normalizeHash method on the rest serializer --- addon/serializers/rest.js | 4 ++++ .../serializers/rest-serializer-test.js | 23 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 6b3c90623bf..edc8bb67122 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -156,6 +156,10 @@ var RESTSerializer = JSONSerializer.extend({ */ normalize(modelClass, resourceHash, prop) { if (this.normalizeHash && this.normalizeHash[prop]) { + deprecate('`RESTSerializer.normalizeHash` has been deprecated. Please use `serializer.normalize` to modify the payload of single resources.', false, { + id: 'ds.serializer.normalize-hash-deprecated', + until: '3.0.0' + }); this.normalizeHash[prop](resourceHash); } return this._super(modelClass, resourceHash); diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index b7e850e0f5f..e36ee5c3db1 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -392,6 +392,29 @@ test('normalizeHash normalizes specific parts of the payload', function(assert) }); +testInDebug('normalizeHash has been deprecated', function(assert) { + env.registry.register('serializer:application', DS.RESTSerializer.extend({ + normalizeHash: { + homePlanets(hash) { + hash.id = hash._id; + delete hash._id; + return hash; + } + } + })); + + var jsonHash = { + homePlanets: [{ _id: "1", name: "Umber", superVillains: [1] }] + }; + + run(function() { + assert.expectDeprecation(function() { + env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); + }, /`RESTSerializer.normalizeHash` has been deprecated/); + }); +}); + + test('normalizeHash works with transforms', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ normalizeHash: { From 2105fc3636bd9d9d6cdfd64775dfc9eb6541d27a Mon Sep 17 00:00:00 2001 From: Wesley Workman Date: Tue, 22 Mar 2016 14:51:08 -0400 Subject: [PATCH 1447/2527] Modified the setup-ember-dev test helper to use `ember-metal/debug`s override hooks. Ember no longer uses `Ember.deprecate` internally, so overriding that has little effect. --- tests/helpers/setup-ember-dev.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/tests/helpers/setup-ember-dev.js b/tests/helpers/setup-ember-dev.js index f9fd230501e..faf10add6af 100644 --- a/tests/helpers/setup-ember-dev.js +++ b/tests/helpers/setup-ember-dev.js @@ -4,12 +4,26 @@ import EmberTestHelpers from "ember-dev/test-helper/index"; const AVAILABLE_ASSERTIONS = ['expectAssertion', 'expectDeprecation', 'expectNoDeprecation', 'expectWarning', 'expectNoWarning']; +// Maintain backwards compatiblity with older versions of ember. +var emberDebugModule; +if (Ember.__loader && Ember.__loader.registry && Ember.__loader.registry["ember-metal/debug"]) { + emberDebugModule = Ember.__loader.require('ember-metal/debug'); +} + function getDebugFunction(name) { - return Ember[name]; + if (emberDebugModule && emberDebugModule.getDebugFunction) { + return emberDebugModule.getDebugFunction(name); + } else { + return Ember[name]; + } } function setDebugFunction(name, func) { - Ember[name] = func; + if (emberDebugModule && emberDebugModule.setDebugFunction) { + emberDebugModule.setDebugFunction(name, func); + } else { + Ember[name] = func; + } } var originalModule = QUnit.module; From d33a160a11d0712e0adb20721f26c9ad2129f603 Mon Sep 17 00:00:00 2001 From: Sergio Arbeo Date: Sun, 27 Mar 2016 17:59:04 -0400 Subject: [PATCH 1448/2527] Add test for normalizing attrs inside links. This tests checkes that the attrs object in serializers are taking into account inside the links object too. Fix 3188 --- .../serializers/json-serializer-test.js | 21 ++++++++++++++++ .../serializers/rest-serializer-test.js | 24 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 06546974ed7..64dcd01e07d 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -953,3 +953,24 @@ if (isEnabled('ds-transform-pass-options')) { }); } + +test('Serializer should respect the attrs hash in links', function(assert) { + env.registry.register("serializer:post", DS.JSONSerializer.extend({ + attrs: { + title: "title_payload_key", + comments: { key: 'my_comments' } + } + })); + + var jsonHash = { + title_payload_key: "Rails is omakase", + links: { + my_comments: 'posts/1/comments' + } + }; + + var post = env.container.lookup("serializer:post").normalizeSingleResponse(env.store, Post, jsonHash); + + assert.equal(post.data.attributes.title, "Rails is omakase"); + assert.equal(post.data.relationships.comments.links.related, 'posts/1/comments'); +}); diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index b7e850e0f5f..c231bccaf17 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -847,3 +847,27 @@ test("don't polymorphically deserialize based on the type key in payload when a }); }); + +test('Serializer should respect the attrs hash in links', function(assert) { + env.registry.register("serializer:super-villain", DS.RESTSerializer.extend({ + attrs: { + evilMinions: { key: 'my_minions' } + } + })); + + var jsonHash = { + "super-villains": [ + { + firstName: 'Tom', + lastName: 'Dale', + links: { + my_minions: 'me/minions' + } + } + ] + }; + + var documentHash = env.container.lookup("serializer:super-villain").normalizeSingleResponse(env.store, SuperVillain, jsonHash); + + assert.equal(documentHash.data.relationships.evilMinions.links.related, 'me/minions'); +}); From fd0e32015c8ecd70b6b45bb9fd4c7da450f2b52b Mon Sep 17 00:00:00 2001 From: bmac Date: Sun, 27 Mar 2016 18:00:00 -0400 Subject: [PATCH 1449/2527] [BUGFIX beta] Normalize attrs inside the links object when using the JSONSerializer and RestSerializer. --- addon/serializers/json.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index a11e5f771ab..9fcf8bccb36 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -524,6 +524,9 @@ export default Serializer.extend({ if (resourceHash) { this.normalizeUsingDeclaredMapping(modelClass, resourceHash); + if (Ember.typeOf(resourceHash.links) === 'object') { + this.normalizeUsingDeclaredMapping(modelClass, resourceHash.links); + } data = { id: this.extractId(modelClass, resourceHash), From 648c7b845eaf7c2206adcfaa7007956fa7e6ad89 Mon Sep 17 00:00:00 2001 From: Pablo Brasero Date: Sun, 27 Mar 2016 23:08:00 +0100 Subject: [PATCH 1450/2527] [DOC] Detail handling of server validation errors --- addon/-private/system/model/errors.js | 62 +++++---------------------- addon/adapters/rest.js | 36 ++++++++++++++++ addon/serializers/json.js | 62 +++++++++++++++++++++++++-- 3 files changed, 105 insertions(+), 55 deletions(-) diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index c521c5d7e6c..5a7c656597d 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -13,13 +13,13 @@ var MapWithDefault = Ember.MapWithDefault; */ /** - Holds validation errors for a given record organized by attribute names. + Holds validation errors for a given record, organized by attribute names. - Every DS.Model has an `errors` property that is an instance of + Every `DS.Model` has an `errors` property that is an instance of `DS.Errors`. This can be used to display validation error messages returned from the server when a `record.save()` rejects. - For Example, if you had an `User` model that looked like this: + For Example, if you had a `User` model that looked like this: ```app/models/user.js import DS from 'ember-data'; @@ -29,7 +29,7 @@ var MapWithDefault = Ember.MapWithDefault; email: attr('string') }); ``` - And you attempted to save a record that did not validate on the backend. + And you attempted to save a record that did not validate on the backend: ```javascript var user = store.createRecord('user', { @@ -39,28 +39,13 @@ var MapWithDefault = Ember.MapWithDefault; user.save(); ``` - Your backend data store might return a response with status code 422 (Unprocessable Entity) - and that looks like this. This response will be used to populate the error object. + Your backend would be expected to return an error response that described + the problem, so that error messages can be generated on the app. - ```javascript - { - "errors": [ - { - "detail": "This username is already taken!", - "source": { - "pointer": "data/attributes/username" - } - }, { - "detail": "Doesn't look like a valid email.", - "source": { - "pointer": "data/attributes/email" - } - } - ] - } - ``` - - For additional information on the error object, see the [JSON API spec](http://jsonapi.org/format/#error-objects). + API responses will be translated into instances of `DS.Errors` differently, + depending on the specific combination of adapter and serializer used. You + may want to check the documentation or the source code of the libraries + that you are using, to know how they expect errors to be communicated. Errors can be displayed to the user by accessing their property name to get an array of all the error objects for that property. Each @@ -96,33 +81,6 @@ var MapWithDefault = Ember.MapWithDefault; {{/each}} ``` - The JSON API spec also allows for object level errors to be placed - in an object with pointer `data`. - - ```javascript - { - "errors": [ - { - "detail": "Some generic non property error message", - "source": { - "pointer": "data" - } - } - ] - } - ``` - - You can access these errors by using the `base` property on the errors - object. - - ```handlebars - {{#each model.errors.base as |error|}} -
      - {{error.message}} -
      - {{/each}} - ``` - @class Errors @namespace DS @extends Ember.Object diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index df3fa0d7e8e..16712fa6244 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -27,6 +27,24 @@ const { This adapter is designed around the idea that the JSON exchanged with the server should be conventional. + ## Success and failure + + The REST adapter will consider a success any response with a status code + of the 2xx family ("Success"), as well as 304 ("Not Modified"). Any other + status code will be considered a failure. + + On success, the request promise will be resolved with the full response + payload. + + Failed responses with status code 422 ("Unprocessable Entity") will be + considered "invalid". The response will be discarded, except for the + `errors` key. The request promise will be rejected with a `DS.InvalidError`. + This error object will encapsulate the saved `errors` value. + + Any other status codes will be treated as an "adapter error". The request + promise will be rejected, similarly to the "invalid" case, but with + an instance of `DS.AdapterError` instead. + ## JSON Structure The REST adapter expects the JSON returned from your server to follow @@ -104,6 +122,24 @@ const { } ``` + ### Errors + + If a response is considered a failure, the JSON payload is expected to include + a top-level key `errors`, detailing any specific issues. For example: + + ```js + { + "errors": { + "msg": "Something went wrong" + } + } + ``` + + This adapter does not make any assumptions as to the format of the `errors` + object. It will simply be passed along as is, wrapped in an instance + of `DS.InvalidError` or `DS.AdapterError`. The serializer can interpret it + afterwards. + ## Customization ### Endpoint path customization diff --git a/addon/serializers/json.js b/addon/serializers/json.js index a11e5f771ab..57a2c678e5b 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1270,12 +1270,68 @@ export default Serializer.extend({ }, /** - `extractErrors` is used to extract model errors when a call is made - to `DS.Model#save` which fails with an `InvalidError`. By default + `extractErrors` is used to extract model errors when a call + to `DS.Model#save` fails with an `InvalidError`. By default Ember Data expects error information to be located on the `errors` property of the payload object. - Example + This serializer expects this `errors` object to be an Array similar + to the following, compliant with the JSON-API specification: + + ```js + { + "errors": [ + { + "detail": "This username is already taken!", + "source": { + "pointer": "data/attributes/username" + } + }, { + "detail": "Doesn't look like a valid email.", + "source": { + "pointer": "data/attributes/email" + } + } + ] + } + ``` + + The key `detail` provides a textual description of the problem. + Alternatively, the key `title` can be used for the same purpose. + + The nested keys `source.pointer` detail which specific element + of the request data was invalid. + + Note that JSON-API also allows for object-level errors to be placed + in an object with pointer `data`, signifying that the problem + cannot be traced to a specific attribute: + + ```javascript + { + "errors": [ + { + "detail": "Some generic non property error message", + "source": { + "pointer": "data" + } + } + ] + } + ``` + + When turn into a `DS.Errors` object, you can read these errors + through the property `base`: + + ```handlebars + {{#each model.errors.base as |error|}} +
      + {{error.message}} +
      + {{/each}} + ``` + + Example of alternative implementation, overriding the default + behavior to deal with a different format of errors: ```app/serializers/post.js import DS from 'ember-data'; From 8400b9ddbce36f7d93c5b519eda974e46f612fd8 Mon Sep 17 00:00:00 2001 From: Jakub Sedlacek Date: Thu, 17 Dec 2015 20:48:25 +0100 Subject: [PATCH 1451/2527] setCanonicalRecord should check for this.canonicalState, not this.inverseRecord when calling setCanonicalRecord with null it should check for presence of canonicalState instead of inverseRecord. --- addon/-private/system/relationships/state/belongs-to.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 0c5eb32ea81..82df9f7a74a 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -33,8 +33,8 @@ BelongsToRelationship.prototype.setRecord = function(newRecord) { BelongsToRelationship.prototype.setCanonicalRecord = function(newRecord) { if (newRecord) { this.addCanonicalRecord(newRecord); - } else if (this.inverseRecord) { - this.removeCanonicalRecord(this.inverseRecord); + } else if (this.canonicalState) { + this.removeCanonicalRecord(this.canonicalState); } this.setHasData(true); this.setHasLoaded(true); From 7581c94e176207132510ac1b99f2a9b793e9bfd8 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Sun, 27 Mar 2016 22:18:35 -0400 Subject: [PATCH 1452/2527] Fix incorrect reference to `push` in the `findRecord` docs --- addon/adapter.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/adapter.js b/addon/adapter.js index 93cad9a531d..e555e8e830e 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -88,9 +88,9 @@ export default Ember.Object.extend({ /** The `findRecord()` method is invoked when the store is asked for a record that has not previously been loaded. In response to `findRecord()` being called, you - should query your persistence layer for a record with the given ID. Once - found, you can asynchronously call the store's `push()` method to push - the record into the store. + should query your persistence layer for a record with the given ID. The `findRecord` + method should return a promise that will resolve to a JavaScript object that will be + normalized by the serializer. Here is an example `findRecord` implementation: From 88a80dac23d65f86b0375c02da64b3354d888fc1 Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 28 Mar 2016 14:48:44 +0200 Subject: [PATCH 1453/2527] [BUGFIX beta] Ensure `null` is returned for Reference#value() The documentation states that `null` is returned for `Reference#value()`, when it is not yet loaded. This commit fixes the bug where `undefined` has been returned for `BelongsToReference#value()`. --- addon/-private/system/references/belongs-to.js | 7 ++++++- tests/integration/references/belongs-to-test.js | 2 +- tests/integration/references/has-many-test.js | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index c2909e98bb7..9684af001b3 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -58,7 +58,12 @@ BelongsToReference.prototype.push = function(objectOrPromise) { BelongsToReference.prototype.value = function() { var inverseRecord = this.belongsToRelationship.inverseRecord; - return inverseRecord && inverseRecord.record; + + if (inverseRecord && inverseRecord.record) { + return inverseRecord.record; + } + + return null; }; BelongsToReference.prototype.load = function() { diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index b4cb24684bc..b66dc17f6c0 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -332,7 +332,7 @@ if (isEnabled("ds-references")) { }); var familyReference = person.belongsTo('family'); - assert.equal(familyReference.value(), null); + assert.strictEqual(familyReference.value(), null); }); test("value() returns the referenced record when loaded", function(assert) { diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 38b68852cc2..0742366158e 100644 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -338,7 +338,7 @@ if (isEnabled("ds-references")) { }); var personsReference = family.hasMany('persons'); - assert.equal(personsReference.value(), null); + assert.strictEqual(personsReference.value(), null); }); test("value() returns the referenced records when all records are loaded", function(assert) { From 11f6b6b5d304bb3b888bfc1631e90325876a97c4 Mon Sep 17 00:00:00 2001 From: Ju Liu Date: Mon, 28 Mar 2016 11:23:13 -0700 Subject: [PATCH 1454/2527] [DOC canary] Update extractMeta documentation --- addon/serializers/json.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 57a2c678e5b..cf7a69cd053 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1248,9 +1248,10 @@ export default Serializer.extend({ export default DS.JSONSerializer.extend({ extractMeta: function(store, typeClass, payload) { - if (payload && payload._pagination) { - store.setMetadataFor(typeClass, payload._pagination); + if (payload && payload.hasOwnProperty('_pagination')) { + let meta = payload._pagination; delete payload._pagination; + return meta; } } }); From 4c3e7d2e2d0672a0e1d03d351ff1def906102ef7 Mon Sep 17 00:00:00 2001 From: Wesley Workman Date: Fri, 25 Mar 2016 09:00:14 -0400 Subject: [PATCH 1455/2527] Moved the adapter errors into the public API space. These errors are documented as public and required for people implementing a customer adapter. --- addon/-private/system/store.js | 2 +- addon/{-private => }/adapters/errors.js | 0 addon/adapters/rest.js | 2 +- addon/index.js | 2 +- addon/serializers/json.js | 2 +- tests/unit/modules-test.js | 14 ++++++++++++++ 6 files changed, 18 insertions(+), 4 deletions(-) rename addon/{-private => }/adapters/errors.js (100%) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index d1dab334812..83c24d2c8c0 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -9,7 +9,7 @@ import _normalizeLink from "ember-data/-private/system/normalize-link"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; import { InvalidError -} from 'ember-data/-private/adapters/errors'; +} from 'ember-data/adapters/errors'; import { promiseArray, diff --git a/addon/-private/adapters/errors.js b/addon/adapters/errors.js similarity index 100% rename from addon/-private/adapters/errors.js rename to addon/adapters/errors.js diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 16712fa6244..f48b66ea56b 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -9,7 +9,7 @@ import { InvalidError, TimeoutError, AbortError -} from 'ember-data/-private/adapters/errors'; +} from 'ember-data/adapters/errors'; import BuildURLMixin from "ember-data/-private/adapters/build-url-mixin"; import isEnabled from 'ember-data/-private/features'; import parseResponseHeaders from 'ember-data/-private/utils/parse-response-headers'; diff --git a/addon/index.js b/addon/index.js index ce424112180..749e32c25b4 100644 --- a/addon/index.js +++ b/addon/index.js @@ -44,7 +44,7 @@ import { AbortError, errorsHashToArray, errorsArrayToHash -} from "ember-data/-private/adapters/errors"; +} from "ember-data/adapters/errors"; import { RecordArray, diff --git a/addon/serializers/json.js b/addon/serializers/json.js index cf7a69cd053..b0405e6159c 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -9,7 +9,7 @@ import { getOwner } from 'ember-data/-private/utils'; -import { errorsArrayToHash } from "ember-data/-private/adapters/errors"; +import { errorsArrayToHash } from "ember-data/adapters/errors"; import isEnabled from 'ember-data/-private/features'; diff --git a/tests/unit/modules-test.js b/tests/unit/modules-test.js index 9249ac78323..b8a087dbc3c 100644 --- a/tests/unit/modules-test.js +++ b/tests/unit/modules-test.js @@ -18,6 +18,13 @@ import JSONAPISerializer from "ember-data/serializers/json-api"; import RESTSerializer from "ember-data/serializers/rest"; import EmbeddedRecordsMixin from "ember-data/serializers/embedded-records-mixin"; +import { + AdapterError, + InvalidError, + TimeoutError, + AbortError +} from "ember-data/adapters/errors"; + module("unit/modules - public modules"); test("ember-data/transform", function(assert) { @@ -72,3 +79,10 @@ test("ember-data/serializers/json", function(assert) { test("ember-data/serializers/rest", function(assert) { assert.ok(RESTSerializer); }); + +test("ember-data/adapters/errors", function(assert) { + assert.ok(AdapterError); + assert.ok(InvalidError); + assert.ok(TimeoutError); + assert.ok(AbortError); +}); From aa2ef4cae3bd7351f8f9fa1b516846a9b96db59b Mon Sep 17 00:00:00 2001 From: Ju Liu Date: Mon, 28 Mar 2016 11:44:08 -0700 Subject: [PATCH 1456/2527] [BUGFIX canary] Improve finders assertion messages --- addon/-private/system/store/finders.js | 8 ++++---- tests/integration/adapter/find-all-test.js | 2 +- tests/integration/adapter/find-test.js | 14 ++++++++++++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 13b61c12183..5f8dbed72c8 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -34,7 +34,7 @@ export function _find(adapter, store, typeClass, id, internalModel, options) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - assert("You made a `findRecord` request for a " + typeClass.typeClassKey + " with id " + id + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + assert("You made a `findRecord` request for a " + typeClass.modelName + " with id " + id + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, id, 'findRecord'); assert('Ember Data expected the primary data returned from a `findRecord` response to be an object but instead it found an array.', !Array.isArray(payload.data)); @@ -67,7 +67,7 @@ export function _findMany(adapter, store, typeClass, ids, internalModels) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - assert("You made a `findMany` request for a " + typeClass.typeClassKey + " with ids " + ids + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + assert("You made a `findMany` request for " + typeClass.modelName + " records with ids " + ids + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { let payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findMany'); //TODO Optimize, no need to materialize here @@ -145,7 +145,7 @@ export function _findAll(adapter, store, typeClass, sinceToken, options) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - assert("You made a `findAll` request for " + typeClass.typeClassKey + "records, but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + assert("You made a `findAll` request for " + typeClass.modelName + " records, but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findAll'); //TODO Optimize @@ -192,7 +192,7 @@ export function _queryRecord(adapter, store, typeClass, query) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - assert("You made a `queryRecord` request for " + typeClass.typeClassKey + "records, with query `" + query + "`, but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + assert("You made a `queryRecord` request for a " + typeClass.modelName + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); var record; store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'queryRecord'); diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index 3689ab97e79..c33cb1235cd 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -153,5 +153,5 @@ testInDebug('When all records are requested, assert the payload is not blank', ( assert.expectAssertion(() => { run(() => store.findAll('person')); - }, /the adapter's response did not have any data/); + }, /You made a `findAll` request for person records, but the adapter's response did not have any data/); }); diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 0c8043163ca..c60df2c7ece 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -138,7 +138,17 @@ testInDebug('When a single record is requested, and the payload is blank', (asse assert.expectAssertion(() => { run(() => store.findRecord('person', 'the-id')); - }, /the adapter's response did not have any data/); + }, /You made a `findRecord` request for a person with id the-id, but the adapter's response did not have any data/); +}); + +testInDebug('When a single record is queried for, and the payload is blank', (assert) => { + env.registry.register('adapter:person', DS.Adapter.extend({ + queryRecord: () => Ember.RSVP.resolve({}) + })); + + assert.expectAssertion(() => { + run(() => store.queryRecord('person', { name: 'the-name' })); + }, /You made a `queryRecord` request for a person, but the adapter's response did not have any data/); }); testInDebug('When multiple records are requested, and the payload is blank', (assert) => { @@ -152,5 +162,5 @@ testInDebug('When multiple records are requested, and the payload is blank', (as store.findRecord('person', '1'); store.findRecord('person', '2'); }); - }, /the adapter's response did not have any data/); + }, /You made a `findMany` request for person records with ids 1,2, but the adapter's response did not have any data/); }); From 217b2935a7d358e1fcce54dca623245a80675da1 Mon Sep 17 00:00:00 2001 From: Ashish Dixit Date: Mon, 28 Mar 2016 13:02:46 -0700 Subject: [PATCH 1457/2527] Uses bin/start with friendly error message for npm start. Running npm start (which originally ran ember serve) before runing npm install and bower install was confusing. This introduces bin/start which checks if node_modules or bower_components exists before trying to run ember serve. --- bin/start | 13 +++++++++++++ package.json | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100755 bin/start diff --git a/bin/start b/bin/start new file mode 100755 index 00000000000..6f35ab59125 --- /dev/null +++ b/bin/start @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +if [ ! -d "node_modules" ]; then + echo "Please make sure you run npm install before running npm start"; + exit 0; +fi + +if [ ! -d "bower_components" ]; then + echo "Please make sure you run bower install before running npm start"; + exit 0; +fi + +ember server; diff --git a/package.json b/package.json index cca19dbbdda..e63c2176bc2 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ }, "scripts": { "build": "ember build", - "start": "ember server", + "start": "./bin/start", "test": "ember try:testall", "node-tests": "node node-tests/nodetest-runner.js", "test:optional-features": "ember test --environment=test-optional-features", From c2839ac545b25c22c8dc51387761874d9ecdc781 Mon Sep 17 00:00:00 2001 From: Balint Erdi Date: Mon, 28 Mar 2016 14:17:04 -0700 Subject: [PATCH 1458/2527] Speed up JSONSerializer#applyTransforms --- addon/serializers/json.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 57a2c678e5b..5bbd0a2ff03 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -193,7 +193,7 @@ export default Serializer.extend({ } typeClass.eachTransformedAttribute((key, typeClass) => { - if (!data.hasOwnProperty(key)) { return; } + if (!(key in data)) { return; } var transform = this.transformFor(typeClass); if (isEnabled('ds-transform-pass-options')) { From 404af751fa23d0ea973cdf66e3857514f3d7f07f Mon Sep 17 00:00:00 2001 From: tchak Date: Wed, 17 Jun 2015 11:49:34 +0200 Subject: [PATCH 1459/2527] [FEATURE ds-extended-errors] Make adapter error extendable and add more error types --- FEATURES.md | 15 ++++ addon/adapters/errors.js | 75 +++++++++++++++---- addon/adapters/rest.js | 17 +++++ addon/index.js | 12 +++ config/features.json | 3 +- .../integration/adapter/rest-adapter-test.js | 60 +++++++++++++++ tests/unit/adapter-errors-test.js | 54 +++++++++++++ 7 files changed, 220 insertions(+), 16 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index b929d18f8ea..ab8f59f32f0 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -66,3 +66,18 @@ entry in `config/features.json`. This is particularly useful for polymorphic relationships not backed by STI when just including the id of the records is not enough. + +- `ds-extended-errors` + + Enables `extend` method on errors. It means you can extend from `DS.AdapterError`. + + ```js + const MyCustomError = DS.AdapterError.extend({ message: "My custom error." }); + ``` + + It will also add a few new errors to rest adapter based on http status. + + * [401] `DS.UnauthorizedError` + * [403] `DS.ForbiddenError` + * [404] `DS.NotFoundError` + * [409] `DS.ConflictError` diff --git a/addon/adapters/errors.js b/addon/adapters/errors.js index 7a5d42af936..93b8ca1e40c 100644 --- a/addon/adapters/errors.js +++ b/addon/adapters/errors.js @@ -1,5 +1,6 @@ import Ember from 'ember'; import {assert} from 'ember-data/-private/debug'; +import isEnabled from "ember-data/-private/features"; const EmberError = Ember.Error; @@ -23,8 +24,34 @@ export function AdapterError(errors, message = 'Adapter operation failed') { ]; } +const extendedErrorsEnabled = isEnabled('ds-extended-errors'); + +function extendFn(ErrorClass) { + return function({ message: defaultMessage } = {}) { + return extend(ErrorClass, defaultMessage); + }; +} + +function extend(ParentErrorClass, defaultMessage) { + let ErrorClass = function(errors, message) { + assert('`AdapterError` expects json-api formatted errors array.', Ember.isArray(errors || [])); + ParentErrorClass.call(this, errors, message || defaultMessage); + }; + ErrorClass.prototype = Object.create(ParentErrorClass.prototype); + + if (extendedErrorsEnabled) { + ErrorClass.extend = extendFn(ErrorClass); + } + + return ErrorClass; +} + AdapterError.prototype = Object.create(EmberError.prototype); +if (extendedErrorsEnabled) { + AdapterError.extend = extendFn(AdapterError); +} + /** A `DS.InvalidError` is used by an adapter to signal the external API was unable to process a request because the content was not @@ -83,32 +110,50 @@ AdapterError.prototype = Object.create(EmberError.prototype); @class InvalidError @namespace DS */ -export function InvalidError(errors) { - assert('`InvalidError` expects json-api formatted errors array.', Ember.isArray(errors || [])); - AdapterError.call(this, errors, 'The adapter rejected the commit because it was invalid'); -} - -InvalidError.prototype = Object.create(AdapterError.prototype); +export const InvalidError = extend(AdapterError, + 'The adapter rejected the commit because it was invalid'); /** @class TimeoutError @namespace DS */ -export function TimeoutError() { - AdapterError.call(this, null, 'The adapter operation timed out'); -} - -TimeoutError.prototype = Object.create(AdapterError.prototype); +export const TimeoutError = extend(AdapterError, + 'The adapter operation timed out'); /** @class AbortError @namespace DS */ -export function AbortError() { - AdapterError.call(this, null, 'The adapter operation was aborted'); -} +export const AbortError = extend(AdapterError, + 'The adapter operation was aborted'); -AbortError.prototype = Object.create(AdapterError.prototype); +/** + @class UnauthorizedError + @namespace DS +*/ +export const UnauthorizedError = extendedErrorsEnabled ? + extend(AdapterError, 'The adapter operation is unauthorized') : null; + +/** + @class ForbiddenError + @namespace DS +*/ +export const ForbiddenError = extendedErrorsEnabled ? + extend(AdapterError, 'The adapter operation is forbidden') : null; + +/** + @class NotFoundError + @namespace DS +*/ +export const NotFoundError = extendedErrorsEnabled ? + extend(AdapterError, 'The adapter could not find the resource') : null; + +/** + @class ConflictError + @namespace DS +*/ +export const ConflictError = extendedErrorsEnabled ? + extend(AdapterError, 'The adapter operation failed due to a conflict') : null; /** @method errorsHashToArray diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index f48b66ea56b..448c901af26 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -7,6 +7,10 @@ import Adapter from "ember-data/adapter"; import { AdapterError, InvalidError, + UnauthorizedError, + ForbiddenError, + NotFoundError, + ConflictError, TimeoutError, AbortError } from 'ember-data/adapters/errors'; @@ -906,6 +910,19 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { let errors = this.normalizeErrorResponse(status, headers, payload); let detailedMessage = this.generatedDetailedMessage(status, headers, payload, requestData); + if (isEnabled('ds-extended-errors')) { + switch (status) { + case 401: + return new UnauthorizedError(errors, detailedMessage); + case 403: + return new ForbiddenError(errors, detailedMessage); + case 404: + return new NotFoundError(errors, detailedMessage); + case 409: + return new ConflictError(errors, detailedMessage); + } + } + return new AdapterError(errors, detailedMessage); }, diff --git a/addon/index.js b/addon/index.js index 749e32c25b4..cb812ef3567 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,5 +1,6 @@ import Ember from "ember"; import { warn } from "ember-data/-private/debug"; +import isEnabled from "ember-data/-private/features"; /** Ember Data @module ember-data @@ -40,6 +41,10 @@ import DebugAdapter from "ember-data/-private/system/debug"; import { AdapterError, InvalidError, + UnauthorizedError, + ForbiddenError, + NotFoundError, + ConflictError, TimeoutError, AbortError, errorsHashToArray, @@ -102,6 +107,13 @@ DS.InvalidError = InvalidError; DS.TimeoutError = TimeoutError; DS.AbortError = AbortError; +if (isEnabled('ds-extended-errors')) { + DS.UnauthorizedError = UnauthorizedError; + DS.ForbiddenError = ForbiddenError; + DS.NotFoundError = NotFoundError; + DS.ConflictError = ConflictError; +} + DS.errorsHashToArray = errorsHashToArray; DS.errorsArrayToHash = errorsArrayToHash; diff --git a/config/features.json b/config/features.json index 4bb5e64d30b..9b315a88126 100644 --- a/config/features.json +++ b/config/features.json @@ -5,5 +5,6 @@ "ds-references": null, "ds-transform-pass-options": null, "ds-pushpayload-return": null, - "ds-serialize-ids-and-types": null + "ds-serialize-ids-and-types": null, + "ds-extended-errors": null } diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 445cc1f0da8..f0c0fa26755 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -2302,6 +2302,66 @@ test('on error appends errorThrown for sanity', function(assert) { } }); +if (isEnabled('ds-extended-errors')) { + test("rejects promise with a specialized subclass of DS.AdapterError if ajax responds with http error codes", function(assert) { + assert.expect(8); + + var originalAjax = Ember.$.ajax; + var jqXHR = { + getAllResponseHeaders: function() { return ''; } + }; + + Ember.$.ajax = function(hash) { + jqXHR.status = 401; + hash.error(jqXHR, 'error'); + }; + + Ember.run(function() { + store.find('post', '1').then(null, function(reason) { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.UnauthorizedError, 'reason should be an instance of DS.UnauthorizedError'); + }); + }); + + Ember.$.ajax = function(hash) { + jqXHR.status = 403; + hash.error(jqXHR, 'error'); + }; + + Ember.run(function() { + store.find('post', '1').then(null, function(reason) { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.ForbiddenError, 'reason should be an instance of DS.ForbiddenError'); + }); + }); + + Ember.$.ajax = function(hash) { + jqXHR.status = 404; + hash.error(jqXHR, 'error'); + }; + + Ember.run(function() { + store.find('post', '1').then(null, function(reason) { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.NotFoundError, 'reason should be an instance of DS.NotFoundError'); + }); + }); + + Ember.$.ajax = function(hash) { + jqXHR.status = 409; + hash.error(jqXHR, 'error'); + }; + + Ember.run(function() { + store.find('post', '1').then(null, function(reason) { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.ConflictError, 'reason should be an instance of DS.ConflictError'); + }); + }); + + Ember.$.ajax = originalAjax; + }); +} test('on error wraps the error string in an DS.AdapterError object', function(assert) { assert.expect(2); diff --git a/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js index f3fc8c25dcd..a81950dc419 100644 --- a/tests/unit/adapter-errors-test.js +++ b/tests/unit/adapter-errors-test.js @@ -1,5 +1,6 @@ import Ember from 'ember'; +import isEnabled from "ember-data/-private/features"; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; @@ -12,6 +13,7 @@ test("DS.AdapterError", function(assert) { assert.ok(error instanceof Error); assert.ok(error instanceof Ember.Error); assert.ok(error.isAdapterError); + assert.equal(error.message, 'Adapter operation failed'); }); test("DS.InvalidError", function(assert) { @@ -19,6 +21,7 @@ test("DS.InvalidError", function(assert) { assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); assert.ok(error.isAdapterError); + assert.equal(error.message, 'The adapter rejected the commit because it was invalid'); }); test("DS.TimeoutError", function(assert) { @@ -26,6 +29,7 @@ test("DS.TimeoutError", function(assert) { assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); assert.ok(error.isAdapterError); + assert.equal(error.message, 'The adapter operation timed out'); }); test("DS.AbortError", function(assert) { @@ -33,8 +37,58 @@ test("DS.AbortError", function(assert) { assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); assert.ok(error.isAdapterError); + assert.equal(error.message, 'The adapter operation was aborted'); }); +if (isEnabled('ds-extended-errors')) { + test("DS.UnauthorizedError", function(assert) { + var error = new DS.UnauthorizedError(); + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); + assert.equal(error.message, 'The adapter operation is unauthorized'); + }); + + test("DS.ForbiddenError", function(assert) { + var error = new DS.ForbiddenError(); + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); + assert.equal(error.message, 'The adapter operation is forbidden'); + }); + + test("DS.NotFoundError", function(assert) { + var error = new DS.NotFoundError(); + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); + assert.equal(error.message, 'The adapter could not find the resource'); + }); + + test("DS.ConflictError", function(assert) { + var error = new DS.ConflictError(); + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); + assert.equal(error.message, 'The adapter operation failed due to a conflict'); + }); + + test("CustomAdapterError", function(assert) { + var CustomAdapterError = DS.AdapterError.extend(); + var error = new CustomAdapterError(); + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); + assert.equal(error.message, 'Adapter operation failed'); + }); + + test("CustomAdapterError with default message", function(assert) { + var CustomAdapterError = DS.AdapterError.extend({ message: 'custom error!' }); + var error = new CustomAdapterError(); + assert.equal(error.message, 'custom error!'); + }); +} + var errorsHash = { name: ['is invalid', 'must be a string'], age: ['must be a number'] From 8fc54bd07c39cc6d72b3b04870f15e14efebcd5b Mon Sep 17 00:00:00 2001 From: Dan McClain Date: Thu, 24 Mar 2016 08:55:55 -0400 Subject: [PATCH 1460/2527] [FEATURE ds-links-in-record-array] Add links to RecordArray when present on payload --- .../adapter-populated-record-array.js | 20 +++++++--- config/features.json | 3 +- .../adapter-populated-record-array-test.js | 40 +++++++++++++++++++ 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index 24f09dc8804..a1997699a8b 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -1,6 +1,7 @@ import Ember from 'ember'; import RecordArray from "ember-data/-private/system/record-arrays/record-array"; import cloneNull from "ember-data/-private/system/clone-null"; +import isEnabled from 'ember-data/-private/features'; /** @module ember-data @@ -35,11 +36,20 @@ export default RecordArray.extend({ loadRecords(records, payload) { //TODO Optimize var internalModels = Ember.A(records).mapBy('_internalModel'); - this.setProperties({ - content: Ember.A(internalModels), - isLoaded: true, - meta: cloneNull(payload.meta) - }); + if (isEnabled('ds-links-in-record-array')) { + this.setProperties({ + content: Ember.A(internalModels), + isLoaded: true, + meta: cloneNull(payload.meta), + links: cloneNull(payload.links) + }); + } else { + this.setProperties({ + content: Ember.A(internalModels), + isLoaded: true, + meta: cloneNull(payload.meta) + }); + } internalModels.forEach((record) => { this.manager.recordArraysForRecord(record).add(this); diff --git a/config/features.json b/config/features.json index 9b315a88126..e42f1bb4a7f 100644 --- a/config/features.json +++ b/config/features.json @@ -6,5 +6,6 @@ "ds-transform-pass-options": null, "ds-pushpayload-return": null, "ds-serialize-ids-and-types": null, - "ds-extended-errors": null + "ds-extended-errors": null, + "ds-links-in-record-array": null } diff --git a/tests/unit/adapter-populated-record-array-test.js b/tests/unit/adapter-populated-record-array-test.js index 15c6ef56408..ca185142a1e 100644 --- a/tests/unit/adapter-populated-record-array-test.js +++ b/tests/unit/adapter-populated-record-array-test.js @@ -5,6 +5,8 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; + var Person, store; var run = Ember.run; @@ -102,6 +104,44 @@ test("stores the metadata off the payload", function(assert) { assert.equal(recordArray.get('meta.foo'), 'bar', 'expected meta.foo to be bar from payload'); }); +if (isEnabled('ds-links-in-record-array')) { + test('stores the links off the payload', function(assert) { + var recordArray = store.recordArrayManager + .createAdapterPopulatedRecordArray(store.modelFor('person'), null); + var payload = { + data: [{ + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale' + } + }, { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz' + } + }, { + type: 'person', + id: '3', + attributes: { + name: 'Scumbag Bryn' + } + }], + links: { + first: '/foo?page=1' + } + }; + + run(function() { + var records = store.push(payload); + recordArray.loadRecords(records, payload); + }); + + assert.equal(recordArray.get('links.first'), '/foo?page=1', 'expected links.first to be "/foo?page=1" from payload'); + }); +} + test('recordArray.replace() throws error', function(assert) { var recordArray = store.recordArrayManager .createAdapterPopulatedRecordArray(Person, null); From 39955e65a25b55c06a87f388bb7f69ed8056d3fc Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 29 Mar 2016 12:46:56 -0400 Subject: [PATCH 1461/2527] Use the dot reporter to reduce the noise in travis output --- testem.json | 1 + 1 file changed, 1 insertion(+) diff --git a/testem.json b/testem.json index 0f35392cf2e..d26cfc9cacb 100644 --- a/testem.json +++ b/testem.json @@ -2,6 +2,7 @@ "framework": "qunit", "test_page": "tests/index.html?hidepassed", "disable_watching": true, + "reporter": "dot", "launch_in_ci": [ "PhantomJS" ], From 35c3d81405b7b8199a11176ef60cb8783cc5641a Mon Sep 17 00:00:00 2001 From: tchak Date: Mon, 28 Mar 2016 18:36:32 -0700 Subject: [PATCH 1462/2527] [CLEANUP] Use Array.isArray everywhere instead of Ember.isArray --- addon/-private/system/model/internal-model.js | 2 +- addon/-private/system/store.js | 7 +++---- addon/-private/system/store/finders.js | 4 ++-- addon/-private/system/store/serializer-response.js | 4 ++-- addon/adapters/errors.js | 2 +- tests/integration/adapter/build-url-mixin-test.js | 2 +- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index fbf64a21e28..58501ea5656 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -578,7 +578,7 @@ InternalModel.prototype = { }, _preloadHasMany(key, preloadValue, type) { - assert("You need to pass in an array to set a hasMany property on a record", Ember.isArray(preloadValue)); + assert("You need to pass in an array to set a hasMany property on a record", Array.isArray(preloadValue)); let recordsToSet = new Array(preloadValue.length); for (let i = 0; i < preloadValue.length; i++) { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 83c24d2c8c0..bf8265b313d 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -59,7 +59,6 @@ export let badIdFormatAssertion = '`id` has to be non-empty string or number'; const Backburner = Ember._Backburner; var Map = Ember.Map; -var isArray = Array.isArray || Ember.isArray; //Get the materialized model from the internalModel/promise that returns //an internal model and return it in a promiseObject. Useful for returning @@ -1658,7 +1657,7 @@ Store = Service.extend({ } } - if (isArray(data.data)) { + if (Array.isArray(data.data)) { length = data.data.length; var internalModels = new Array(length); for (i = 0; i < length; i++) { @@ -2060,7 +2059,7 @@ function deserializeRecordId(store, key, relationship, id) { return; } - assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being ${Ember.inspect(id)}, but ${key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !isArray(id)); + assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being ${Ember.inspect(id)}, but ${key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(id)); //TODO:Better asserts return store._internalModelForId(id.type, id.id); @@ -2071,7 +2070,7 @@ function deserializeRecordIds(store, key, relationship, ids) { return; } - assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being '${Ember.inspect(ids)}', but ${key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, isArray(ids)); + assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being '${Ember.inspect(ids)}', but ${key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(ids)); let _ids = new Array(ids.length); for (let i = 0; i < ids.length; i++) { diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 5f8dbed72c8..07c82a99f89 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -17,7 +17,7 @@ import { var Promise = Ember.RSVP.Promise; function payloadIsNotBlank(adapterPayload) { - if (Ember.isArray(adapterPayload)) { + if (Array.isArray(adapterPayload)) { return true; } else { return Object.keys(adapterPayload || {}).length; @@ -175,7 +175,7 @@ export function _query(adapter, store, typeClass, query, recordArray) { records = store.push(payload); }); - assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Ember.isArray(records)); + assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Array.isArray(records)); recordArray.loadRecords(records, payload); return recordArray; diff --git a/addon/-private/system/store/serializer-response.js b/addon/-private/system/store/serializer-response.js index 9679e4e5903..debad488a22 100644 --- a/addon/-private/system/store/serializer-response.js +++ b/addon/-private/system/store/serializer-response.js @@ -26,7 +26,7 @@ export function validateDocumentStructure(doc) { } } if ('data' in doc) { - if (!(doc.data === null || Ember.isArray(doc.data) || typeof doc.data === 'object')) { + if (!(doc.data === null || Array.isArray(doc.data) || typeof doc.data === 'object')) { errors.push('data must be null, an object, or an array'); } } @@ -36,7 +36,7 @@ export function validateDocumentStructure(doc) { } } if ('errors' in doc) { - if (!Ember.isArray(doc.errors)) { + if (!Array.isArray(doc.errors)) { errors.push('errors must be an array'); } } diff --git a/addon/adapters/errors.js b/addon/adapters/errors.js index 93b8ca1e40c..c8962a8bbb2 100644 --- a/addon/adapters/errors.js +++ b/addon/adapters/errors.js @@ -34,7 +34,7 @@ function extendFn(ErrorClass) { function extend(ParentErrorClass, defaultMessage) { let ErrorClass = function(errors, message) { - assert('`AdapterError` expects json-api formatted errors array.', Ember.isArray(errors || [])); + assert('`AdapterError` expects json-api formatted errors array.', Array.isArray(errors || [])); ParentErrorClass.call(this, errors, message || defaultMessage); }; ErrorClass.prototype = Object.create(ParentErrorClass.prototype); diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index c77edd82c23..7409788f5bc 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -226,7 +226,7 @@ test('buildURL - buildURL takes the records from findMany', function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.buildURL = function(type, ids, snapshots) { - if (Ember.isArray(snapshots)) { + if (Array.isArray(snapshots)) { return "/posts/" + snapshots.get('firstObject').belongsTo('post', { id: true }) + '/comments/'; } return ""; From 3c9f5e29e552dcf7026a1fdb82e501692515fdbd Mon Sep 17 00:00:00 2001 From: tchak Date: Tue, 29 Mar 2016 10:02:36 -0700 Subject: [PATCH 1463/2527] [FEATURE ds-extended-errors] add DS.ServerError --- FEATURES.md | 1 + addon/adapters/errors.js | 7 +++++++ addon/adapters/rest.js | 5 +++++ addon/index.js | 2 ++ tests/integration/adapter/rest-adapter-test.js | 14 +++++++++++++- tests/unit/adapter-errors-test.js | 8 ++++++++ 6 files changed, 36 insertions(+), 1 deletion(-) diff --git a/FEATURES.md b/FEATURES.md index ab8f59f32f0..2e883106167 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -81,3 +81,4 @@ entry in `config/features.json`. * [403] `DS.ForbiddenError` * [404] `DS.NotFoundError` * [409] `DS.ConflictError` + * [500] `DS.ServerError` diff --git a/addon/adapters/errors.js b/addon/adapters/errors.js index c8962a8bbb2..29c00c8208b 100644 --- a/addon/adapters/errors.js +++ b/addon/adapters/errors.js @@ -155,6 +155,13 @@ export const NotFoundError = extendedErrorsEnabled ? export const ConflictError = extendedErrorsEnabled ? extend(AdapterError, 'The adapter operation failed due to a conflict') : null; +/** + @class ServerError + @namespace DS +*/ +export const ServerError = extendedErrorsEnabled ? + extend(AdapterError, 'The adapter operation failed due to a server error') : null; + /** @method errorsHashToArray @private diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 448c901af26..42841876c98 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -11,6 +11,7 @@ import { ForbiddenError, NotFoundError, ConflictError, + ServerError, TimeoutError, AbortError } from 'ember-data/adapters/errors'; @@ -920,6 +921,10 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { return new NotFoundError(errors, detailedMessage); case 409: return new ConflictError(errors, detailedMessage); + default: + if (status >= 500) { + return new ServerError(errors, detailedMessage); + } } } diff --git a/addon/index.js b/addon/index.js index cb812ef3567..81963b0358e 100644 --- a/addon/index.js +++ b/addon/index.js @@ -45,6 +45,7 @@ import { ForbiddenError, NotFoundError, ConflictError, + ServerError, TimeoutError, AbortError, errorsHashToArray, @@ -112,6 +113,7 @@ if (isEnabled('ds-extended-errors')) { DS.ForbiddenError = ForbiddenError; DS.NotFoundError = NotFoundError; DS.ConflictError = ConflictError; + DS.ServerError = ServerError; } DS.errorsHashToArray = errorsHashToArray; diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index f0c0fa26755..22af01b327e 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -2304,7 +2304,7 @@ test('on error appends errorThrown for sanity', function(assert) { if (isEnabled('ds-extended-errors')) { test("rejects promise with a specialized subclass of DS.AdapterError if ajax responds with http error codes", function(assert) { - assert.expect(8); + assert.expect(10); var originalAjax = Ember.$.ajax; var jqXHR = { @@ -2359,6 +2359,18 @@ if (isEnabled('ds-extended-errors')) { }); }); + Ember.$.ajax = function(hash) { + jqXHR.status = 500; + hash.error(jqXHR, 'error'); + }; + + Ember.run(function() { + store.find('post', '1').then(null, function(reason) { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.ServerError, 'reason should be an instance of DS.ServerError'); + }); + }); + Ember.$.ajax = originalAjax; }); } diff --git a/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js index a81950dc419..646d6bc2edb 100644 --- a/tests/unit/adapter-errors-test.js +++ b/tests/unit/adapter-errors-test.js @@ -73,6 +73,14 @@ if (isEnabled('ds-extended-errors')) { assert.equal(error.message, 'The adapter operation failed due to a conflict'); }); + test("DS.ServerError", function(assert) { + var error = new DS.ServerError(); + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); + assert.equal(error.message, 'The adapter operation failed due to a server error'); + }); + test("CustomAdapterError", function(assert) { var CustomAdapterError = DS.AdapterError.extend(); var error = new CustomAdapterError(); From 93a16dfd2a73bb2e018990cfae9468087dfb5a2a Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Mon, 28 Mar 2016 18:43:16 +0200 Subject: [PATCH 1464/2527] tests/index.html: Fix script order --- tests/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/index.html b/tests/index.html index 2d3ff6ade04..64cb47e31ff 100644 --- a/tests/index.html +++ b/tests/index.html @@ -21,10 +21,10 @@ {{content-for "body"}} {{content-for "test-body"}} + - From e0ce8f9c91284d421f25e08cd13c73113641f185 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Mon, 28 Mar 2016 19:11:00 +0200 Subject: [PATCH 1465/2527] Update "ember-cli" to v2.4.0 --- .npmignore | 2 +- package.json | 2 +- testem.json => testem.js | 5 +++-- tests/helpers/module-for-acceptance.js | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) rename testem.json => testem.js (83%) diff --git a/.npmignore b/.npmignore index 299ab96cbd8..b51700bad75 100644 --- a/.npmignore +++ b/.npmignore @@ -16,7 +16,7 @@ .watchmanconfig bower.json ember-cli-build.js -testem.json +testem.js *.gem *.gemspec diff --git a/package.json b/package.json index e63c2176bc2..8d5c9de0ad6 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "broccoli-uglify-sourcemap": "^1.0.1", "broccoli-yuidoc": "^2.1.0", "ember-ajax": "0.7.1", - "ember-cli": "2.3.0", + "ember-cli": "2.4.0", "ember-cli-app-version": "^1.0.0", "ember-cli-blueprint-test-helpers": "^0.9.0", "ember-cli-dependency-checker": "^1.2.0", diff --git a/testem.json b/testem.js similarity index 83% rename from testem.json rename to testem.js index d26cfc9cacb..c9bae137d2f 100644 --- a/testem.json +++ b/testem.js @@ -1,4 +1,5 @@ -{ +/*jshint node:true*/ +module.exports = { "framework": "qunit", "test_page": "tests/index.html?hidepassed", "disable_watching": true, @@ -10,4 +11,4 @@ "PhantomJS", "Chrome" ] -} +}; diff --git a/tests/helpers/module-for-acceptance.js b/tests/helpers/module-for-acceptance.js index ed23003db40..8c8b74ecb2b 100644 --- a/tests/helpers/module-for-acceptance.js +++ b/tests/helpers/module-for-acceptance.js @@ -13,11 +13,11 @@ export default function(name, options = {}) { }, afterEach() { - destroyApp(this.application); - if (options.afterEach) { options.afterEach.apply(this, arguments); } + + destroyApp(this.application); } }); } From 0a9140fb87ac6a5ae83389cac78f9426a344c066 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Mon, 28 Mar 2016 19:44:13 +0200 Subject: [PATCH 1466/2527] Update "ember-cli" to v2.4.1 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8d5c9de0ad6..19e7dd791a2 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "broccoli-uglify-sourcemap": "^1.0.1", "broccoli-yuidoc": "^2.1.0", "ember-ajax": "0.7.1", - "ember-cli": "2.4.0", + "ember-cli": "2.4.1", "ember-cli-app-version": "^1.0.0", "ember-cli-blueprint-test-helpers": "^0.9.0", "ember-cli-dependency-checker": "^1.2.0", @@ -64,7 +64,7 @@ "ember-cli-internal-test-helpers": "^0.8.1", "ember-cli-qunit": "^1.2.1", "ember-cli-release": "0.2.3", - "ember-cli-sri": "^2.0.0", + "ember-cli-sri": "^2.1.0", "ember-cli-uglify": "^1.2.0", "ember-dev": "emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed", "ember-disable-prototype-extensions": "^1.1.0", From 680f5125d0284de0f9e272418f92a3f46a5dd91c Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Mon, 28 Mar 2016 23:13:32 +0200 Subject: [PATCH 1467/2527] Update "ember-cli-blueprint-test-helpers" to v0.10.1 --- .npmignore | 1 + .../fixtures/addon/package/package.json | 37 ++----------------- node-tests/fixtures/app/package/package.json | 34 +---------------- node-tests/nodetest-runner.js | 14 ++----- package.json | 10 ++--- 5 files changed, 16 insertions(+), 80 deletions(-) diff --git a/.npmignore b/.npmignore index b51700bad75..707b5a5fdbb 100644 --- a/.npmignore +++ b/.npmignore @@ -21,3 +21,4 @@ testem.js *.gem *.gemspec **/*.rb +node-tests/ \ No newline at end of file diff --git a/node-tests/fixtures/addon/package/package.json b/node-tests/fixtures/addon/package/package.json index 5aaa25001a6..e6e50684368 100644 --- a/node-tests/fixtures/addon/package/package.json +++ b/node-tests/fixtures/addon/package/package.json @@ -1,49 +1,20 @@ { "name": "my-addon", "version": "0.0.0", - "description": "The default blueprint for ember-cli addons.", - "directories": { - "doc": "doc", - "test": "tests" - }, - "scripts": { - "build": "ember build", - "start": "ember server", - "test": "ember try:testall" - }, - "repository": "", + "description": "Addon fixture package for ember-cli-blueprint-test-helpers", "engines": { "node": ">= 0.10.0" }, - "author": "", - "license": "MIT", "devDependencies": { - "broccoli-asset-rev": "^2.1.2", - "ember-ajax": "0.6.2", - "ember-cli": "1.13.12", - "ember-cli-app-version": "^1.0.0", - "ember-cli-content-security-policy": "0.4.0", - "ember-cli-dependency-checker": "^1.1.0", - "ember-cli-htmlbars-inline-precompile": "^0.3.1", - "ember-cli-inject-live-reload": "^1.3.1", - "ember-cli-qunit": "^1.0.1", - "ember-cli-release": "0.2.3", - "ember-cli-sri": "^1.0.3", - "ember-cli-uglify": "^1.2.0", - "ember-data": "2.0.0", - "ember-disable-proxy-controllers": "^1.0.0", - "ember-export-application-global": "^1.0.4", - "ember-resolver": "^2.0.2", - "ember-disable-prototype-extensions": "^1.0.0", - "ember-try": "~0.0.8", + "ember-cli": "*", "ember-data": "*" }, "keywords": [ "ember-addon" ], "dependencies": { - "ember-cli-htmlbars": "^1.0.0", - "ember-cli-babel": "^5.1.3" + "ember-cli-htmlbars": "*", + "ember-cli-babel": "*" }, "ember-addon": { "configPath": "tests/dummy/config" diff --git a/node-tests/fixtures/app/package/package.json b/node-tests/fixtures/app/package/package.json index a97d1c6e103..768bc49c219 100644 --- a/node-tests/fixtures/app/package/package.json +++ b/node-tests/fixtures/app/package/package.json @@ -1,43 +1,13 @@ { "name": "my-app", "version": "0.0.0", - "description": "Small description for nested-project goes here", + "description": "App fixture package for ember-cli-blueprint-test-helpers", "private": true, - "directories": { - "doc": "doc", - "test": "tests" - }, - "scripts": { - "build": "ember build", - "start": "ember server", - "test": "ember test" - }, - "repository": "", "engines": { "node": ">= 0.10.0" }, - "author": "", - "license": "MIT", "devDependencies": { - "broccoli-asset-rev": "^2.1.2", - "ember-ajax": "0.6.2", - "ember-cli": "1.13.8", - "ember-cli-app-version": "^1.0.0", - "ember-cli-babel": "^5.1.3", - "ember-cli-content-security-policy": "0.4.0", - "ember-cli-dependency-checker": "^1.1.0", - "ember-cli-htmlbars": "^1.0.0", - "ember-cli-htmlbars-inline-precompile": "^0.3.1", - "ember-cli-inject-live-reload": "^1.3.1", - "ember-cli-legacy-blueprints": "*", - "ember-cli-qunit": "^1.0.1", - "ember-cli-release": "0.2.3", - "ember-cli-sri": "^1.0.3", - "ember-cli-uglify": "^1.2.0", - "ember-data": "2.0.0", - "ember-disable-proxy-controllers": "^1.0.0", - "ember-export-application-global": "^1.0.4", - "ember-resolver": "^2.0.2", + "ember-cli": "*", "ember-data": "*" } } diff --git a/node-tests/nodetest-runner.js b/node-tests/nodetest-runner.js index cc3bdc2c481..1f81b257c96 100644 --- a/node-tests/nodetest-runner.js +++ b/node-tests/nodetest-runner.js @@ -2,27 +2,21 @@ var glob = require('glob'); var Mocha = require('mocha'); -var Promise = require('ember-cli/lib/ext/promise'); +var RSVP = require('rsvp'); var rimraf = require('rimraf'); var mochaOnlyDetector = require('mocha-only-detector'); -process.env.EMBER_DATA_SKIP_VERSION_CHECKING_DO_NOT_USE_THIS_ENV_VARIABLE = true; - -if (process.env.EOLNEWLINE) { - require('os').EOL = '\n'; -} - rimraf.sync('.node_modules-tmp'); rimraf.sync('.bower_components-tmp'); var root = 'node-tests/{blueprints,acceptance,unit}'; -var _checkOnlyInTests = Promise.denodeify(mochaOnlyDetector.checkFolder.bind(null, root + '/**/*{-test}.js')); +var _checkOnlyInTests = RSVP.denodeify(mochaOnlyDetector.checkFolder.bind(null, root + '/**/*{-test}.js')); var optionOrFile = process.argv[2]; var mocha = new Mocha({ timeout: 5000, reporter: 'spec' }); -var testFiles = glob.sync(root + '**/*-test.js'); +var testFiles = glob.sync(root + '/**/*-test.js'); /*var jshintPosition = testFiles.indexOf('tests/unit/jshint-test.js'); var jshint = testFiles.splice(jshintPosition, 1); @@ -62,7 +56,7 @@ function ciVerificationStep() { if (process.env.CI === 'true') { return checkOnlyInTests(); } else { - return Promise.resolve(); + return RSVP.Promise.resolve(); } } diff --git a/package.json b/package.json index 19e7dd791a2..f36e7c39658 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "ember-ajax": "0.7.1", "ember-cli": "2.4.1", "ember-cli-app-version": "^1.0.0", - "ember-cli-blueprint-test-helpers": "^0.9.0", + "ember-cli-blueprint-test-helpers": "0.10.1", "ember-cli-dependency-checker": "^1.2.0", "ember-cli-htmlbars": "^1.0.3", "ember-cli-htmlbars-inline-precompile": "^0.2.0", @@ -76,12 +76,12 @@ "ember-try": "^0.1.2", "ember-watson": "^0.7.0", "github": "^0.2.4", - "glob": "^5.0.13", + "glob": "5.0.13", "loader.js": "^4.0.0", - "mocha": "^2.3.4", + "mocha": "2.4.5", "mocha-only-detector": "0.0.2", - "rimraf": "^2.3.2", - "rsvp": "^3.1.0" + "rimraf": "2.5.2", + "rsvp": "3.2.1" }, "peerDependencies": { "ember-inflector": "^1.9.4" From 0885dcea0943c3e5e095e9c07f5379153e9d5d79 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 30 Mar 2016 17:42:11 +0200 Subject: [PATCH 1468/2527] Update "ember-cli-blueprint-test-helpers" to v0.10.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f36e7c39658..386e99424b6 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "ember-ajax": "0.7.1", "ember-cli": "2.4.1", "ember-cli-app-version": "^1.0.0", - "ember-cli-blueprint-test-helpers": "0.10.1", + "ember-cli-blueprint-test-helpers": "0.10.2", "ember-cli-dependency-checker": "^1.2.0", "ember-cli-htmlbars": "^1.0.3", "ember-cli-htmlbars-inline-precompile": "^0.2.0", From ec38f496cb8d9135904f5b177b9aaaf63c66c122 Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 30 Mar 2016 21:58:14 +0200 Subject: [PATCH 1469/2527] [BUGFIX beta] add custom warning when invalid JSON is returned When the server returns an empty string for a response which doesn't indicate that the content is empty, jQuery tries to parse the JSON which results in an error, which is not very helpful at first: JSON.parse("") === "SyntaxError: Unexpected end of input" This change adds a custom warning when such a response is returned, so the feedback is more valuable. --- addon/adapters/rest.js | 17 ++++++++++++++ bower.json | 3 ++- package.json | 2 ++ .../integration/adapter/rest-adapter-test.js | 23 +++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 42841876c98..26285e6d782 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -17,6 +17,7 @@ import { } from 'ember-data/adapters/errors'; import BuildURLMixin from "ember-data/-private/adapters/build-url-mixin"; import isEnabled from 'ember-data/-private/features'; +import { runInDebug, warn } from 'ember-data/-private/debug'; import parseResponseHeaders from 'ember-data/-private/utils/parse-response-headers'; const { @@ -1011,6 +1012,14 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { }; hash.error = function(jqXHR, textStatus, errorThrown) { + runInDebug(function() { + let message = `The server returned an empty string for ${type} ${url}, which cannot be parsed into a valid JSON. Return either null or {}.`; + let validJSONString = !(textStatus === "parsererror" && jqXHR.responseText === ""); + warn(message, validJSONString, { + id: 'ds.adapter.returned-empty-string-as-JSON' + }); + }); + let error; if (errorThrown instanceof Error) { @@ -1378,6 +1387,14 @@ if (isEnabled('ds-improved-ajax')) { }; hash.error = function(jqXHR, textStatus, errorThrown) { + runInDebug(function() { + let message = `The server returned an empty string for ${method} ${url}, which cannot be parsed into a valid JSON. Return either null or {}.`; + let validJSONString = !(textStatus === "parsererror" && jqXHR.responseText === ""); + warn(message, validJSONString, { + id: 'ds.adapter.returned-empty-string-as-JSON' + }); + }); + let error; if (errorThrown instanceof Error) { diff --git a/bower.json b/bower.json index 8df7ae85297..7ca7fb2f1e2 100644 --- a/bower.json +++ b/bower.json @@ -4,7 +4,8 @@ "ember": "components/ember#release", "ember-cli-shims": "0.1.0", "ember-cli-test-loader": "0.2.2", - "ember-qunit-notifications": "0.1.0" + "ember-qunit-notifications": "0.1.0", + "pretender": "^0.12.0" }, "resolutions": { "ember": "release" diff --git a/package.json b/package.json index 386e99424b6..ca3757108dd 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "ember-cli-htmlbars-inline-precompile": "^0.2.0", "ember-cli-inject-live-reload": "^1.3.1", "ember-cli-internal-test-helpers": "^0.8.1", + "ember-cli-pretender": "0.6.0", "ember-cli-qunit": "^1.2.1", "ember-cli-release": "0.2.3", "ember-cli-sri": "^2.1.0", @@ -80,6 +81,7 @@ "loader.js": "^4.0.0", "mocha": "2.4.5", "mocha-only-detector": "0.0.2", + "pretender": "1.0.0", "rimraf": "2.5.2", "rsvp": "3.2.1" }, diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 22af01b327e..7b9a8624a56 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -4,6 +4,8 @@ import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; +import Pretender from "pretender"; + import DS from 'ember-data'; import isEnabled from 'ember-data/-private/features'; @@ -2517,3 +2519,24 @@ test("createRecord - sideloaded records are pushed to the store", function(asser }); }); }); + +testInDebug("warns when an empty response is returned, though a valid stringified JSON is expected", function(assert) { + let done = assert.async(); + let server = new Pretender(); + + server.post('/posts', function() { + return [201, { "Content-Type": "application/json" }, ""]; + }); + + run(function() { + let post = store.createRecord('post'); + let save = post.save(); + + save.then(null, function() { + server.shutdown(); + done(); + }); + }); + + assert.expectWarning("The server returned an empty string for POST /posts, which cannot be parsed into a valid JSON. Return either null or {}."); +}); From ded01e5cd63f00bfb52c8cc1cc110cf4f8f0a541 Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 30 Mar 2016 19:02:10 +0200 Subject: [PATCH 1470/2527] [FEATURE ds-extended-errors] fix usage of isEnabled Using `isEnabled()` not within "if / else if / else" doesn't work since the statement will not be stripped. This results in a call to `isEnabled` being present in production code. --- addon/adapters/errors.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addon/adapters/errors.js b/addon/adapters/errors.js index 29c00c8208b..84500994751 100644 --- a/addon/adapters/errors.js +++ b/addon/adapters/errors.js @@ -24,7 +24,10 @@ export function AdapterError(errors, message = 'Adapter operation failed') { ]; } -const extendedErrorsEnabled = isEnabled('ds-extended-errors'); +let extendedErrorsEnabled = false; +if (isEnabled('ds-extended-errors')) { + extendedErrorsEnabled = true; +} function extendFn(ErrorClass) { return function({ message: defaultMessage } = {}) { From 30ce2664fe2fd023b598c9d8cecbda18959b06e4 Mon Sep 17 00:00:00 2001 From: Vishak Date: Sat, 2 Apr 2016 01:05:58 +0530 Subject: [PATCH 1471/2527] [DOC release] Mistaken back tick. --- addon/serializers/rest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index edc8bb67122..fd43cee67ef 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -692,7 +692,7 @@ var RESTSerializer = JSONSerializer.extend({ }); ``` - Given a `TacoParty' model, calling `save` on a tacoModel would produce an outgoing + Given a `TacoParty` model, calling `save` on it would produce an outgoing request like: ```js From e190634f526339ee97dcd62e8bc3ffa8417986c0 Mon Sep 17 00:00:00 2001 From: James Brennan Date: Sun, 3 Apr 2016 22:50:13 +0100 Subject: [PATCH 1472/2527] [DOC] Fix typo in urlForFindBelongsTo adapter method --- addon/-private/adapters/build-url-mixin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index 07ab6d79e68..cdded53d58a 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -169,7 +169,7 @@ export default Ember.Mixin.create({ }, /** - * @method urlForFindBelongTo + * @method urlForFindBelongsTo * @param {String} id * @param {String} modelName * @return {String} url From 0151b763b5ce24e4234347889148b8988639bfd4 Mon Sep 17 00:00:00 2001 From: Ahmad Suhendri Date: Tue, 5 Apr 2016 17:39:20 +0700 Subject: [PATCH 1473/2527] =?UTF-8?q?[DOC]=C2=A0Fix=20example=20code=20on?= =?UTF-8?q?=20normalize=20method?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addon/-private/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index bf8265b313d..638776894e5 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1810,7 +1810,7 @@ Store = Service.extend({ socket.on('message', function(message) { var modelName = message.model; var data = message.data; - store.push(modelName, store.normalize(modelName, data)); + store.push(store.normalize(modelName, data)); }); ``` From 42c296b352718d12040d1d21a2bbd3ed18aff213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Ko=C5=82ek?= Date: Wed, 6 Apr 2016 11:15:16 +0200 Subject: [PATCH 1474/2527] fix rest-adapter-test typo --- tests/integration/adapter/rest-adapter-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 7b9a8624a56..ffac75b484e 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -348,7 +348,7 @@ test("createRecord - a serializer's attributes are consulted when building the p }); }); -test("createRecord - a serializer's attribute mapping takes precdence over keyForAttribute when building the payload", function(assert) { +test("createRecord - a serializer's attribute mapping takes precedence over keyForAttribute when building the payload", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ attrs: { name: 'given_name' From b6c2c7c25dface19bb0ff9f78f36848f17284740 Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 19 Jan 2016 14:41:51 +0100 Subject: [PATCH 1475/2527] Only extend from application serializer / adapter, if it exists This change updates the blueprints for adapter and serializer, so they extend from the application entity if it exists: If there is an application adapter - located in `app/adapters/application.js` - and the command `ember g adapter foo` is invoked, the created adapter extends from the application adapter: ```js // app/adapters/foo.js import ApplicationAdapter from './application'; export default ApplicationAdapter.extend(); ``` If there is no application entity, the JSONAPI equivalent is used. Consider no application serializer in `app/serializers/appliation.js` and the command `ember generate serializer foo` is invoked, then the created serializer extends from JSONAPISerializer: ```js // app/serializers/foo.js import JSONAPISerializer from 'ember-data/serializers/json-api'; export default JSONAPISerializer.extend(); ``` --- blueprints/adapter/index.js | 33 +-------- .../files/__root__/__path__/__name__.js | 4 +- blueprints/serializer/index.js | 12 ++- .../extend-from-application-entity.js | 40 ++++++++++ node-tests/blueprints/adapter-test.js | 29 +++++++- node-tests/blueprints/serializer-test.js | 74 +++++++++++++++++++ 6 files changed, 156 insertions(+), 36 deletions(-) create mode 100644 lib/utilities/extend-from-application-entity.js diff --git a/blueprints/adapter/index.js b/blueprints/adapter/index.js index b6a3416e381..9295dc6fd75 100644 --- a/blueprints/adapter/index.js +++ b/blueprints/adapter/index.js @@ -1,8 +1,6 @@ /*jshint node:true*/ -var stringUtil = require('ember-cli-string-utils'); -var SilentError = require('silent-error'); -var pathUtil = require('ember-cli-path-utils'); +var extendFromApplicationEntity = require('../../lib/utilities/extend-from-application-entity'); module.exports = { description: 'Generates an ember-data adapter.', @@ -12,33 +10,6 @@ module.exports = { ], locals: function(options) { - var adapterName = options.entity.name; - var baseClass = 'JSONAPIAdapter'; - var importStatement = 'import JSONAPIAdapter from \'ember-data/adapters/json-api\';'; - var isAddon = options.inRepoAddon || options.project.isEmberCLIAddon(); - var relativePath = pathUtil.getRelativePath(options.entity.name); - - if (options.pod && options.podPath) { - relativePath = pathUtil.getRelativePath(options.podPath + options.entity.name); - } - - if (!isAddon && !options.baseClass && adapterName !== 'application') { - options.baseClass = 'application'; - } - - if (options.baseClass === adapterName) { - throw new SilentError('Adapters cannot extend from themself. To resolve this, remove the `--base-class` option or change to a different base-class.'); - } - - if (options.baseClass) { - baseClass = stringUtil.classify(options.baseClass.replace('\/', '-')); - baseClass = baseClass + 'Adapter'; - importStatement = 'import ' + baseClass + ' from \'' + relativePath + options.baseClass + '\';'; - } - - return { - importStatement: importStatement, - baseClass: baseClass - }; + return extendFromApplicationEntity('adapter', 'JSONAPIAdapter', 'ember-data/adapters/json-api', options); } }; diff --git a/blueprints/serializer/files/__root__/__path__/__name__.js b/blueprints/serializer/files/__root__/__path__/__name__.js index 4678cc2c37a..2b54b829447 100644 --- a/blueprints/serializer/files/__root__/__path__/__name__.js +++ b/blueprints/serializer/files/__root__/__path__/__name__.js @@ -1,4 +1,4 @@ -import JSONAPISerializer from 'ember-data/serializers/json-api'; +<%= importStatement %> -export default JSONAPISerializer.extend({ +export default <%= baseClass %>.extend({ }); diff --git a/blueprints/serializer/index.js b/blueprints/serializer/index.js index bd3f41c12cd..91b57db3976 100644 --- a/blueprints/serializer/index.js +++ b/blueprints/serializer/index.js @@ -1,5 +1,15 @@ /*jshint node:true*/ +var extendFromApplicationEntity = require('../../lib/utilities/extend-from-application-entity'); + module.exports = { - description: 'Generates an ember-data serializer.' + description: 'Generates an ember-data serializer.', + + availableOptions: [ + { name: 'base-class', type: String } + ], + + locals: function(options) { + return extendFromApplicationEntity('serializer', 'JSONAPISerializer', 'ember-data/serializers/json-api', options); + } }; diff --git a/lib/utilities/extend-from-application-entity.js b/lib/utilities/extend-from-application-entity.js new file mode 100644 index 00000000000..cb340293364 --- /dev/null +++ b/lib/utilities/extend-from-application-entity.js @@ -0,0 +1,40 @@ +var stringUtil = require('ember-cli-string-utils'); +var SilentError = require('silent-error'); +var pathUtil = require('ember-cli-path-utils'); +var existsSync = require('exists-sync'); +var path = require('path'); + +module.exports = function(type, baseClass, packagePath, options) { + var entityName = options.entity.name; + var isAddon = options.inRepoAddon || options.project.isEmberCLIAddon(); + var relativePath = pathUtil.getRelativePath(options.entity.name); + + if (options.pod && options.podPath) { + relativePath = pathUtil.getRelativePath(options.podPath + options.entity.name); + } + + var entityDirectory = type + 's'; + var applicationEntityPath = path.join(options.project.root, 'app', entityDirectory, 'application.js'); + var hasApplicationEntity = existsSync(applicationEntityPath); + if (!isAddon && !options.baseClass && entityName !== 'application' && hasApplicationEntity) { + options.baseClass = 'application'; + packagePath = './application'; + } + + if (options.baseClass === entityName) { + throw new SilentError(stringUtil.classify(type) + 's cannot extend from themself. To resolve this, remove the `--base-class` option or change to a different base-class.'); + } + + var importStatement = 'import ' + baseClass + ' from \'' + packagePath + '\';'; + + if (options.baseClass) { + baseClass = stringUtil.classify(options.baseClass.replace('\/', '-')); + baseClass = baseClass + stringUtil.classify(type); + importStatement = 'import ' + baseClass + ' from \'' + relativePath + options.baseClass + '\';'; + } + + return { + importStatement: importStatement, + baseClass: baseClass + }; +}; diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 074f3cc3079..74be00aa4e4 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -11,8 +11,8 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { { file: 'app/adapters/foo.js', contains: [ - 'import ApplicationAdapter from \'./application\';', - 'export default ApplicationAdapter.extend({' + 'import JSONAPIAdapter from \'ember-data/adapters/json-api\';', + 'export default JSONAPIAdapter.extend({' ] }, { @@ -25,6 +25,31 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { }); }); + it('adapter extends application adapter if it exists', function() { + return generateAndDestroy(['adapter', 'application'], { + afterGenerate: function() { + return generateAndDestroy(['adapter', 'foo'], { + skipInit: true, + files: [ + { + file: 'app/adapters/foo.js', + contains: [ + 'import ApplicationAdapter from \'./application\';', + 'export default ApplicationAdapter.extend({' + ] + }, + { + file: 'tests/unit/adapters/foo-test.js', + contains: [ + 'moduleFor(\'adapter:foo\'' + ] + } + ] + }); + } + }); + }); + it('adapter with --base-class', function() { return generateAndDestroy(['adapter', 'foo', '--base-class=bar'], { files: [ diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index 958eaa0e42a..b955f75f843 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -25,6 +25,80 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { }); }); + it('serializer extends application serializer if it exists', function() { + return generateAndDestroy(['serializer', 'application'], { + afterGenerate: function() { + return generateAndDestroy(['serializer', 'foo'], { + skipInit: true, + files: [ + { + file: 'app/serializers/foo.js', + contains: [ + 'import ApplicationSerializer from \'./application\';', + 'export default ApplicationSerializer.extend({' + ] + }, + { + file: 'tests/unit/serializers/foo-test.js', + contains: [ + 'moduleForModel(\'foo\'' + ] + } + ] + }); + } + }); + }); + + it('serializer with --base-class', function() { + return generateAndDestroy(['serializer', 'foo', '--base-class=bar'], { + files: [ + { + file: 'app/serializers/foo.js', + contains: [ + 'import BarSerializer from \'./bar\';', + 'export default BarSerializer.extend({' + ] + }, + { + file: 'tests/unit/serializers/foo-test.js', + contains: [ + 'moduleForModel(\'foo\'' + ] + } + ] + }); + }); + + it('serializer throws when --base-class is same as name', function() { + return generateAndDestroy(['serializer', 'application', '--base-class=application'], { + throws: { + message: /Serializers cannot extend from themself/, + type: 'SilentError' + } + }); + }); + + it('serializer when is named "application"', function() { + return generateAndDestroy(['serializer', 'application'], { + files: [ + { + file: 'app/serializers/application.js', + contains: [ + 'import JSONAPISerializer from \'ember-data/serializers/json-api\';', + 'export default JSONAPISerializer.extend({' + ] + }, + { + file: 'tests/unit/serializers/application-test.js', + contains: [ + 'moduleForModel(\'application\'' + ] + } + ] + }); + }); + it('serializer-test', function() { return generateAndDestroy(['serializer-test', 'foo'], { files: [ From 8387e12617441522e90143acc147a6593b00db86 Mon Sep 17 00:00:00 2001 From: Trevor John Date: Wed, 6 Apr 2016 16:33:11 -0400 Subject: [PATCH 1476/2527] [FEATURE ds-improved-ajax] pass snapshotRecordArray to urlForFindAll --- addon/adapters/rest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 26285e6d782..dea132ca7b0 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1268,7 +1268,7 @@ if (isEnabled('ds-improved-ajax')) { switch (requestType) { case 'findAll': - return this.buildURL(type.modelName, null, null, requestType); + return this.buildURL(type.modelName, null, snapshots, requestType); case 'query': case 'queryRecord': From 3868436fc784e2de54d3f05d14707e170a2e2b65 Mon Sep 17 00:00:00 2001 From: Trevor John Date: Wed, 6 Apr 2016 13:06:54 -0400 Subject: [PATCH 1477/2527] [BUGFIX beta] pass DS.SnapshotRecordArray to urlForFindAll --- addon/-private/adapters/build-url-mixin.js | 5 +++-- addon/adapters/rest.js | 2 +- tests/integration/adapter/rest-adapter-test.js | 7 +++++-- tests/unit/adapters/build-url-mixin/build-url-test.js | 8 +++++--- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index cdded53d58a..4d8ca008346 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -56,7 +56,7 @@ export default Ember.Mixin.create({ case 'findRecord': return this.urlForFindRecord(id, modelName, snapshot); case 'findAll': - return this.urlForFindAll(modelName); + return this.urlForFindAll(modelName, snapshot); case 'query': return this.urlForQuery(query, modelName); case 'queryRecord': @@ -121,9 +121,10 @@ export default Ember.Mixin.create({ /** * @method urlForFindAll * @param {String} modelName + * @param {DS.SnapshotRecordArray} snapshot * @return {String} url */ - urlForFindAll(modelName) { + urlForFindAll(modelName, snapshot) { return this._buildURL(modelName); }, diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index dea132ca7b0..4d97b5d7df7 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -458,7 +458,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { return this._makeRequest(request); } else { - const url = this.buildURL(type.modelName, null, null, 'findAll'); + const url = this.buildURL(type.modelName, null, snapshotRecordArray, 'findAll'); if (sinceToken) { query.since = sinceToken; diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index ffac75b484e..8967521d13e 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1033,8 +1033,11 @@ test("findAll - returning an array populates the array", function(assert) { }); -test("findAll - passes buildURL the requestType", function(assert) { +test("findAll - passes buildURL the requestType and snapshot", function(assert) { + assert.expect(2); + let adapterOptionsStub = { stub: true }; adapter.buildURL = function(type, id, snapshot, requestType) { + assert.equal(snapshot.adapterOptions, adapterOptionsStub); return "/" + requestType + "/posts"; }; @@ -1045,7 +1048,7 @@ test("findAll - passes buildURL the requestType", function(assert) { ] }); - store.findAll('post').then(assert.wait(function(posts) { + store.findAll('post', { adapterOptions: adapterOptionsStub }).then(assert.wait(function(posts) { assert.equal(passedUrl, "/findAll/posts"); })); }); diff --git a/tests/unit/adapters/build-url-mixin/build-url-test.js b/tests/unit/adapters/build-url-mixin/build-url-test.js index 866fcf787b7..152bba1e9dc 100644 --- a/tests/unit/adapters/build-url-mixin/build-url-test.js +++ b/tests/unit/adapters/build-url-mixin/build-url-test.js @@ -42,13 +42,15 @@ test('buildURL - find requestType delegates to urlForFindRecord', function(asser }); test('buildURL - findAll requestType delegates to urlForFindAll', function(assert) { - assert.expect(2); + assert.expect(3); let originalMethod = adapter.urlForFindAll; - adapter.urlForFindAll = function(type) { + let snapshotStub = { snapshot: true }; + adapter.urlForFindAll = function(type, snapshot) { assert.equal(type, 'super-user'); + assert.equal(snapshot, snapshotStub); return originalMethod.apply(this, arguments); }; - assert.equal(adapter.buildURL('super-user', null, null, 'findAll'), '/superUsers'); + assert.equal(adapter.buildURL('super-user', null, snapshotStub, 'findAll'), '/superUsers'); }); test('buildURL - query requestType delegates to urlForQuery', function(assert) { From 3df6308f83dfe405be72b6ec21c71ec15974eb57 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 7 Apr 2016 13:23:33 +0200 Subject: [PATCH 1478/2527] [skip ci] fix invalid indentation in codeclimate.yml --- .codeclimate.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index 71daed66b79..8a27d7029a0 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,5 +1,6 @@ # Save as .codeclimate.yml (note leading .) in project root directory languages: JavaScript: true - exclude_paths: + +exclude_paths: - "tests/*" From 56b541b06c252c48da6145a763415d1a696c2aea Mon Sep 17 00:00:00 2001 From: Trevor John Date: Thu, 7 Apr 2016 12:35:40 -0400 Subject: [PATCH 1479/2527] [FEATURE ds-improved-ajax] pass snapshot for findHasMany and findBelongsTo --- addon/adapters/rest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 4d97b5d7df7..dd279339f99 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1279,7 +1279,7 @@ if (isEnabled('ds-improved-ajax')) { case 'findHasMany': case 'findBelongsTo': - let url = this.buildURL(type.modelName, id, null, requestType); + let url = this.buildURL(type.modelName, id, snapshot, requestType); return this.urlPrefix(params.url, url); } From 85a12209f09ec51bbc23f757c7cd463cd18461ad Mon Sep 17 00:00:00 2001 From: Trevor John Date: Thu, 7 Apr 2016 14:36:48 -0400 Subject: [PATCH 1480/2527] [BUGFIX beta] pass snapshot into urlForFindHasMany/BelongsTo --- addon/-private/adapters/build-url-mixin.js | 10 ++++++---- addon/adapters/rest.js | 4 ++-- tests/integration/adapter/rest-adapter-test.js | 4 ++++ .../adapters/build-url-mixin/build-url-test.js | 16 ++++++++++------ 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index 4d8ca008346..407e665381a 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -64,9 +64,9 @@ export default Ember.Mixin.create({ case 'findMany': return this.urlForFindMany(id, modelName, snapshot); case 'findHasMany': - return this.urlForFindHasMany(id, modelName); + return this.urlForFindHasMany(id, modelName, snapshot); case 'findBelongsTo': - return this.urlForFindBelongsTo(id, modelName); + return this.urlForFindBelongsTo(id, modelName, snapshot); case 'createRecord': return this.urlForCreateRecord(modelName, snapshot); case 'updateRecord': @@ -163,9 +163,10 @@ export default Ember.Mixin.create({ * @method urlForFindHasMany * @param {String} id * @param {String} modelName + * @param {DS.Snapshot} snapshot * @return {String} url */ - urlForFindHasMany(id, modelName) { + urlForFindHasMany(id, modelName, snapshot) { return this._buildURL(modelName, id); }, @@ -173,9 +174,10 @@ export default Ember.Mixin.create({ * @method urlForFindBelongsTo * @param {String} id * @param {String} modelName + * @param {DS.Snapshot} snapshot * @return {String} url */ - urlForFindBelongsTo(id, modelName) { + urlForFindBelongsTo(id, modelName, snapshot) { return this._buildURL(modelName, id); }, diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index dd279339f99..e7597c91ee8 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -634,7 +634,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { var id = snapshot.id; var type = snapshot.modelName; - url = this.urlPrefix(url, this.buildURL(type, id, null, 'findHasMany')); + url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findHasMany')); return this.ajax(url, 'GET'); } @@ -687,7 +687,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { var id = snapshot.id; var type = snapshot.modelName; - url = this.urlPrefix(url, this.buildURL(type, id, null, 'findBelongsTo')); + url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findBelongsTo')); return this.ajax(url, 'GET'); } }, diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 8967521d13e..e079c8809dc 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1700,8 +1700,10 @@ test("findHasMany - returning an array populates the array", function(assert) { }); test("findHasMany - passes buildURL the requestType", function(assert) { + assert.expect(2); adapter.shouldBackgroundReloadRecord = () => false; adapter.buildURL = function(type, id, snapshot, requestType) { + assert.ok(snapshot instanceof DS.Snapshot); assert.equal(requestType, 'findHasMany'); }; @@ -1846,8 +1848,10 @@ test("findMany - a custom serializer is used if present", function(assert) { }); test('findBelongsTo - passes buildURL the requestType', function(assert) { + assert.expect(2); adapter.shouldBackgroundReloadRecord = () => false; adapter.buildURL = function(type, id, snapshot, requestType) { + assert.ok(snapshot instanceof DS.Snapshot); assert.equal(requestType, 'findBelongsTo'); }; diff --git a/tests/unit/adapters/build-url-mixin/build-url-test.js b/tests/unit/adapters/build-url-mixin/build-url-test.js index 152bba1e9dc..cc7ce50d5f5 100644 --- a/tests/unit/adapters/build-url-mixin/build-url-test.js +++ b/tests/unit/adapters/build-url-mixin/build-url-test.js @@ -90,25 +90,29 @@ test('buildURL - findMany requestType delegates to urlForFindMany', function(ass }); test('buildURL - findHasMany requestType delegates to urlForFindHasMany', function(assert) { - assert.expect(3); + assert.expect(4); let originalMethod = adapter.urlForFindHasMany; - adapter.urlForFindHasMany = function(id, type) { + let snapshotStub = { snapshot: true }; + adapter.urlForFindHasMany = function(id, type, snapshot) { assert.equal(id, 1); assert.equal(type, 'super-user'); + assert.equal(snapshot, snapshotStub); return originalMethod.apply(this, arguments); }; - assert.equal(adapter.buildURL('super-user', 1, null, 'findHasMany'), '/superUsers/1'); + assert.equal(adapter.buildURL('super-user', 1, snapshotStub, 'findHasMany'), '/superUsers/1'); }); test('buildURL - findBelongsTo requestType delegates to urlForFindBelongsTo', function(assert) { - assert.expect(3); + assert.expect(4); let originalMethod = adapter.urlForFindBelongsTo; - adapter.urlForFindBelongsTo = function(id, type) { + let snapshotStub = { snapshot: true }; + adapter.urlForFindBelongsTo = function(id, type, snapshot) { assert.equal(id, 1); assert.equal(type, 'super-user'); + assert.equal(snapshot, snapshotStub); return originalMethod.apply(this, arguments); }; - assert.equal(adapter.buildURL('super-user', 1, null, 'findBelongsTo'), '/superUsers/1'); + assert.equal(adapter.buildURL('super-user', 1, snapshotStub, 'findBelongsTo'), '/superUsers/1'); }); test('buildURL - createRecord requestType delegates to urlForCreateRecord', function(assert) { From a2bd7dbb2b95a7f18bfaab6bbd9e305a29d7ef9a Mon Sep 17 00:00:00 2001 From: Balint Erdi Date: Thu, 7 Apr 2016 20:41:54 +0200 Subject: [PATCH 1481/2527] Use property lookup in applyTransforms A property lookup is used to speed up the hot path of applying transforms when normalizing data received from the server. --- addon/serializers/json.js | 2 +- tests/unit/model-test.js | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 37fdf3da119..4a54f26c21d 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -193,7 +193,7 @@ export default Serializer.extend({ } typeClass.eachTransformedAttribute((key, typeClass) => { - if (!(key in data)) { return; } + if (data[key] === undefined) { return; } var transform = this.transformFor(typeClass); if (isEnabled('ds-transform-pass-options')) { diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index c476e39718a..1e838600742 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -906,18 +906,16 @@ AssertionPrototype.convertsWhenSet = function(type, provided, expected) { }; test("a DS.Model can describe String attributes", function(assert) { - assert.expect(6); + assert.expect(4); assert.converts('string', "Scumbag Tom", "Scumbag Tom"); assert.converts('string', 1, "1"); assert.converts('string', "", ""); assert.converts('string', null, null); - assert.converts('string', undefined, null); - assert.convertsFromServer('string', undefined, null); }); test("a DS.Model can describe Number attributes", function(assert) { - assert.expect(9); + assert.expect(8); assert.converts('number', "1", 1); assert.converts('number', "0", 0); @@ -925,7 +923,6 @@ test("a DS.Model can describe Number attributes", function(assert) { assert.converts('number', 0, 0); assert.converts('number', "", null); assert.converts('number', null, null); - assert.converts('number', undefined, null); assert.converts('number', true, 1); assert.converts('number', false, 0); }); @@ -938,18 +935,14 @@ test("a DS.Model can describe Boolean attributes", function(assert) { if (isEnabled('ds-transform-pass-options') && isEnabled('ds-boolean-transform-allow-null')) { assert.converts('boolean', null, null, { allowNull: true }); - assert.converts('boolean', undefined, null, { allowNull: true }); assert.converts('boolean', null, false, { allowNull: false }); - assert.converts('boolean', undefined, false, { allowNull: false }); // duplicating the tests from the else branch here, so once the feature is // enabled and the else branch is deleted, those assertions are kept assert.converts('boolean', null, false); - assert.converts('boolean', undefined, false); } else { assert.converts('boolean', null, false); - assert.converts('boolean', undefined, false); } assert.converts('boolean', true, true); From 1ced8b5a21fbc921afc00bce22dc0e200621e638 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Thu, 7 Apr 2016 13:24:07 -0700 Subject: [PATCH 1482/2527] Use new blueprint testing API (#4309) * Update "ember-cli-blueprint-test-helpers" to v0.11.0 * tests/blueprints: Use new testing API --- node-tests/blueprints/adapter-test.js | 189 +++++++--------- node-tests/blueprints/model-test.js | 264 ++++++++++------------- node-tests/blueprints/serializer-test.js | 193 +++++++---------- node-tests/blueprints/transform-test.js | 89 ++++---- package.json | 2 +- 5 files changed, 319 insertions(+), 418 deletions(-) diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 74be00aa4e4..26475faca6a 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -1,133 +1,106 @@ -var setupTestHooks = require('ember-cli-blueprint-test-helpers/lib/helpers/setup'); -var BlueprintHelpers = require('ember-cli-blueprint-test-helpers/lib/helpers/blueprint-helper'); -var generateAndDestroy = BlueprintHelpers.generateAndDestroy; +var blueprintHelpers = require('ember-cli-blueprint-test-helpers/helpers'); +var setupTestHooks = blueprintHelpers.setupTestHooks; +var emberNew = blueprintHelpers.emberNew; +var emberGenerate = blueprintHelpers.emberGenerate; +var emberGenerateDestroy = blueprintHelpers.emberGenerateDestroy; +var modifyPackages = blueprintHelpers.modifyPackages; + +var chai = require('ember-cli-blueprint-test-helpers/chai'); +var expect = chai.expect; + +var SilentError = require('silent-error'); describe('Acceptance: generate and destroy adapter blueprints', function() { setupTestHooks(this); it('adapter', function() { - return generateAndDestroy(['adapter', 'foo'], { - files: [ - { - file: 'app/adapters/foo.js', - contains: [ - 'import JSONAPIAdapter from \'ember-data/adapters/json-api\';', - 'export default JSONAPIAdapter.extend({' - ] - }, - { - file: 'tests/unit/adapters/foo-test.js', - contains: [ - 'moduleFor(\'adapter:foo\'' - ] - } - ] - }); + var args = ['adapter', 'foo']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('app/adapters/foo.js')) + .to.contain('import JSONAPIAdapter from \'ember-data/adapters/json-api\';') + .to.contain('export default JSONAPIAdapter.extend({'); + + expect(_file('tests/unit/adapters/foo-test.js')) + .to.contain('moduleFor(\'adapter:foo\''); + })); }); it('adapter extends application adapter if it exists', function() { - return generateAndDestroy(['adapter', 'application'], { - afterGenerate: function() { - return generateAndDestroy(['adapter', 'foo'], { - skipInit: true, - files: [ - { - file: 'app/adapters/foo.js', - contains: [ - 'import ApplicationAdapter from \'./application\';', - 'export default ApplicationAdapter.extend({' - ] - }, - { - file: 'tests/unit/adapters/foo-test.js', - contains: [ - 'moduleFor(\'adapter:foo\'' - ] - } - ] - }); - } - }); + var args = ['adapter', 'foo']; + + return emberNew() + .then(() => emberGenerate(['adapter', 'application'])) + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('app/adapters/foo.js')) + .to.contain('import ApplicationAdapter from \'./application\';') + .to.contain('export default ApplicationAdapter.extend({'); + + expect(_file('tests/unit/adapters/foo-test.js')) + .to.contain('moduleFor(\'adapter:foo\''); + })); }); it('adapter with --base-class', function() { - return generateAndDestroy(['adapter', 'foo', '--base-class=bar'], { - files: [ - { - file: 'app/adapters/foo.js', - contains: [ - 'import BarAdapter from \'./bar\';', - 'export default BarAdapter.extend({' - ] - }, - { - file: 'tests/unit/adapters/foo-test.js', - contains: [ - 'moduleFor(\'adapter:foo\'' - ] - } - ] - }); + var args = ['adapter', 'foo', '--base-class=bar']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('app/adapters/foo.js')) + .to.contain('import BarAdapter from \'./bar\';') + .to.contain('export default BarAdapter.extend({'); + + expect(_file('tests/unit/adapters/foo-test.js')) + .to.contain('moduleFor(\'adapter:foo\''); + })); }); it('adapter throws when --base-class is same as name', function() { - return generateAndDestroy(['adapter', 'application', '--base-class=application'], { - throws: { - message: /Adapters cannot extend from themself/, - type: 'SilentError' - } - }); + var args = ['adapter', 'foo', '--base-class=foo']; + + return emberNew() + .then(() => expect(emberGenerate(args)) + .to.be.rejectedWith(SilentError, /Adapters cannot extend from themself/)); }); it('adapter when is named "application"', function() { - return generateAndDestroy(['adapter', 'application'], { - files: [ - { - file: 'app/adapters/application.js', - contains: [ - 'import JSONAPIAdapter from \'ember-data/adapters/json-api\';', - 'export default JSONAPIAdapter.extend({' - ] - }, - { - file: 'tests/unit/adapters/application-test.js', - contains: [ - 'moduleFor(\'adapter:application\'' - ] - } - ] - }); + var args = ['adapter', 'application']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('app/adapters/application.js')) + .to.contain('import JSONAPIAdapter from \'ember-data/adapters/json-api\';') + .to.contain('export default JSONAPIAdapter.extend({'); + + expect(_file('tests/unit/adapters/application-test.js')) + .to.contain('moduleFor(\'adapter:application\''); + })); }); it('adapter-test', function() { - return generateAndDestroy(['adapter-test', 'foo'], { - files: [ - { - file: 'tests/unit/adapters/foo-test.js', - contains: [ - 'moduleFor(\'adapter:foo\'' - ] - } - ] - }); + var args = ['adapter-test', 'foo']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/adapters/foo-test.js')) + .to.contain('moduleFor(\'adapter:foo\''); + })); }); it('adapter-test for mocha', function() { - return generateAndDestroy(['adapter-test', 'foo'], { - packages: [ - { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-cli-mocha', dev: true } - ], - files: [ - { - file: 'tests/unit/adapters/foo-test.js', - contains: [ - 'import { describeModule, it } from \'ember-mocha\';', - 'describeModule(\n \'adapter:foo\',', - 'expect(adapter).to.be.ok;' - ] - } - ] - }); + var args = ['adapter-test', 'foo']; + + return emberNew() + .then(() => modifyPackages([ + {name: 'ember-cli-qunit', delete: true}, + {name: 'ember-cli-mocha', dev: true} + ])) + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/adapters/foo-test.js')) + .to.contain('import { describeModule, it } from \'ember-mocha\';') + .to.contain('describeModule(\n \'adapter:foo\',') + .to.contain('expect(adapter).to.be.ok;'); + })); }); }); diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index 692d9c0996b..05531bd4ce1 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -1,38 +1,35 @@ -var setupTestHooks = require('ember-cli-blueprint-test-helpers/lib/helpers/setup'); -var BlueprintHelpers = require('ember-cli-blueprint-test-helpers/lib/helpers/blueprint-helper'); -var generateAndDestroy = BlueprintHelpers.generateAndDestroy; +var blueprintHelpers = require('ember-cli-blueprint-test-helpers/helpers'); +var setupTestHooks = blueprintHelpers.setupTestHooks; +var emberNew = blueprintHelpers.emberNew; +var emberGenerateDestroy = blueprintHelpers.emberGenerateDestroy; +var modifyPackages = blueprintHelpers.modifyPackages; + +var chai = require('ember-cli-blueprint-test-helpers/chai'); +var expect = chai.expect; describe('Acceptance: generate and destroy model blueprints', function() { setupTestHooks(this); it('model', function() { - return generateAndDestroy(['model', 'foo'], { - files: [ - { - file: 'app/models/foo.js', - contains: [ - 'import Model from \'ember-data/model\';', - 'export default Model.extend(' - ], - doesNotContain: [ - 'import attr from \'ember-data/attr\';', - 'import { belongsTo } from \'ember-data/relationships\';', - 'import { hasMany } from \'ember-data/relationships\';', - 'import { belongsTo, hasMany } from \'ember-data/relationships\';' - ] - }, - { - file: 'tests/unit/models/foo-test.js', - contains: [ - 'moduleForModel(\'foo\'' - ] - } - ] - }); + var args = ['model', 'foo']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('app/models/foo.js')) + .to.contain('import Model from \'ember-data/model\';') + .to.contain('export default Model.extend(') + .to.not.contain('import attr from \'ember-data/attr\';') + .to.not.contain('import { belongsTo } from \'ember-data/relationships\';') + .to.not.contain('import { hasMany } from \'ember-data/relationships\';') + .to.not.contain('import { belongsTo, hasMany } from \'ember-data/relationships\';'); + + expect(_file('tests/unit/models/foo-test.js')) + .to.contain('moduleForModel(\'foo\''); + })); }); it('model with attrs', function() { - return generateAndDestroy([ + var args = [ 'model', 'foo', 'misc', @@ -43,144 +40,109 @@ describe('Acceptance: generate and destroy model blueprints', function() { 'age:number', 'name:string', 'customAttr:custom-transform' - ], { - files: [ - { - file: 'app/models/foo.js', - contains: [ - 'import Model from \'ember-data/model\';', - 'import attr from \'ember-data/attr\';', - 'export default Model.extend(', - 'misc: attr()', - 'skills: attr(\'array\')', - 'isActive: attr(\'boolean\')', - 'birthday: attr(\'date\')', - 'someObject: attr(\'object\')', - 'age: attr(\'number\')', - 'name: attr(\'string\')', - 'customAttr: attr(\'custom-transform\')' - ], - doesNotContain: [ - 'import { belongsTo } from \'ember-data/relationships\';', - 'import { hasMany } from \'ember-data/relationships\';', - 'import { belongsTo, hasMany } from \'ember-data/relationships\';' - ] - }, - { - file: 'tests/unit/models/foo-test.js', - contains: [ - 'moduleForModel(\'foo\'' - ] - } - ] - }); + ]; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('app/models/foo.js')) + .to.contain('import Model from \'ember-data/model\';') + .to.contain('import attr from \'ember-data/attr\';') + .to.contain('export default Model.extend(') + .to.contain('misc: attr()') + .to.contain('skills: attr(\'array\')') + .to.contain('isActive: attr(\'boolean\')') + .to.contain('birthday: attr(\'date\')') + .to.contain('someObject: attr(\'object\')') + .to.contain('age: attr(\'number\')') + .to.contain('name: attr(\'string\')') + .to.contain('customAttr: attr(\'custom-transform\')') + .to.not.contain('import { belongsTo } from \'ember-data/relationships\';') + .to.not.contain('import { hasMany } from \'ember-data/relationships\';') + .to.not.contain('import { belongsTo, hasMany } from \'ember-data/relationships\';'); + + expect(_file('tests/unit/models/foo-test.js')) + .to.contain('moduleForModel(\'foo\''); + })); }); it('model with belongsTo', function() { - return generateAndDestroy(['model', 'comment', 'post:belongs-to', 'author:belongs-to:user'], { - files: [ - { - file: 'app/models/comment.js', - contains: [ - 'import Model from \'ember-data/model\';', - 'import { belongsTo } from \'ember-data/relationships\';', - 'export default Model.extend(', - 'post: belongsTo(\'post\')', - 'author: belongsTo(\'user\')', - ], - doesNotContain: [ - 'import attr from \'ember-data/attr\';', - 'import { hasMany } from \'ember-data/relationships\';', - 'import { belongsTo, hasMany } from \'ember-data/relationships\';' - ] - }, - { - file: 'tests/unit/models/comment-test.js', - contains: [ - 'moduleForModel(\'comment\'', - 'needs: [\'model:post\', \'model:user\']' - ] - } - ] - }); + var args = ['model', 'comment', 'post:belongs-to', 'author:belongs-to:user']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('app/models/comment.js')) + .to.contain('import Model from \'ember-data/model\';') + .to.contain('import { belongsTo } from \'ember-data/relationships\';') + .to.contain('export default Model.extend(') + .to.contain('post: belongsTo(\'post\')') + .to.contain('author: belongsTo(\'user\')') + .to.not.contain('import attr from \'ember-data/attr\';') + .to.not.contain('import { hasMany } from \'ember-data/relationships\';') + .to.not.contain('import { belongsTo, hasMany } from \'ember-data/relationships\';'); + + expect(_file('tests/unit/models/comment-test.js')) + .to.contain('moduleForModel(\'comment\'') + .to.contain('needs: [\'model:post\', \'model:user\']'); + })); }); it('model with hasMany', function() { - return generateAndDestroy(['model', 'post', 'comments:has-many', 'otherComments:has-many:comment'], { - files: [ - { - file: 'app/models/post.js', - contains: [ - 'import Model from \'ember-data/model\';', - 'import { hasMany } from \'ember-data/relationships\';', - 'export default Model.extend(', - 'comments: hasMany(\'comment\')', - 'otherComments: hasMany(\'comment\')', - ], - doesNotContain: [ - 'import attr from \'ember-data/attr\';', - 'import { belongsTo } from \'ember-data/relationships\';', - 'import { belongsTo, hasMany } from \'ember-data/relationships\';' - ] - }, - { - file: 'tests/unit/models/post-test.js', - contains: [ - 'moduleForModel(\'post\'', - 'needs: [\'model:comment\']' - ] - } - ] - }); + var args = ['model', 'post', 'comments:has-many', 'otherComments:has-many:comment']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('app/models/post.js')) + .to.contain('import Model from \'ember-data/model\';') + .to.contain('import { hasMany } from \'ember-data/relationships\';') + .to.contain('export default Model.extend(') + .to.contain('comments: hasMany(\'comment\')') + .to.contain('otherComments: hasMany(\'comment\')') + .to.not.contain('import attr from \'ember-data/attr\';') + .to.not.contain('import { belongsTo } from \'ember-data/relationships\';') + .to.not.contain('import { belongsTo, hasMany } from \'ember-data/relationships\';'); + + expect(_file('tests/unit/models/post-test.js')) + .to.contain('moduleForModel(\'post\'') + .to.contain('needs: [\'model:comment\']'); + })); }); it('model with belongsTo and hasMany has both imports', function() { - return generateAndDestroy(['model', 'post', 'comments:has-many', 'user:belongs-to'], { - files: [ - { - file: 'app/models/post.js', - contains: [ - 'import { belongsTo, hasMany } from \'ember-data/relationships\';' - ], - doesNotContain: [ - 'import attr from \'ember-data/attr\';', - 'import { belongsTo } from \'ember-data/relationships\';', - 'import { hasMany } from \'ember-data/relationships\';' - ] - } - ] - }); + var args = ['model', 'post', 'comments:has-many', 'user:belongs-to']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('app/models/post.js')) + .to.contain('import { belongsTo, hasMany } from \'ember-data/relationships\';') + .to.not.contain('import attr from \'ember-data/attr\';') + .to.not.contain('import { belongsTo } from \'ember-data/relationships\';') + .to.not.contain('import { hasMany } from \'ember-data/relationships\';'); + })); }); it('model-test', function() { - return generateAndDestroy(['model-test', 'foo'], { - files: [ - { - file: 'tests/unit/models/foo-test.js', - contains: [ - 'moduleForModel(\'foo\'' - ] - } - ] - }); + var args = ['model-test', 'foo']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/models/foo-test.js')) + .to.contain('moduleForModel(\'foo\''); + })); }); it('model-test for mocha', function() { - return generateAndDestroy(['model-test', 'foo'], { - packages: [ - { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-cli-mocha', dev: true } - ], - files: [ - { - file: 'tests/unit/models/foo-test.js', - contains: [ - 'import { describeModel, it } from \'ember-mocha\';', - 'describeModel(\n \'foo\',', - 'expect(model).to.be.ok;' - ] - } - ] - }); + var args = ['model-test', 'foo']; + + return emberNew() + .then(() => modifyPackages([ + {name: 'ember-cli-qunit', delete: true}, + {name: 'ember-cli-mocha', dev: true} + ])) + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/models/foo-test.js')) + .to.contain('import { describeModel, it } from \'ember-mocha\';') + .to.contain('describeModel(\n \'foo\',') + .to.contain('expect(model).to.be.ok;'); + })); }); }); diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index b955f75f843..8adc60f1745 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -1,135 +1,108 @@ -var setupTestHooks = require('ember-cli-blueprint-test-helpers/lib/helpers/setup'); -var BlueprintHelpers = require('ember-cli-blueprint-test-helpers/lib/helpers/blueprint-helper'); -var generateAndDestroy = BlueprintHelpers.generateAndDestroy; +var blueprintHelpers = require('ember-cli-blueprint-test-helpers/helpers'); +var setupTestHooks = blueprintHelpers.setupTestHooks; +var emberNew = blueprintHelpers.emberNew; +var emberGenerate = blueprintHelpers.emberGenerate; +var emberGenerateDestroy = blueprintHelpers.emberGenerateDestroy; +var modifyPackages = blueprintHelpers.modifyPackages; + +var chai = require('ember-cli-blueprint-test-helpers/chai'); +var expect = chai.expect; + +var SilentError = require('silent-error'); describe('Acceptance: generate and destroy serializer blueprints', function() { setupTestHooks(this); it('serializer', function() { - return generateAndDestroy(['serializer', 'foo'], { - files: [ - { - file: 'app/serializers/foo.js', - contains: [ - 'import JSONAPISerializer from \'ember-data/serializers/json-api\';', - 'export default JSONAPISerializer.extend(' - ] - }, - { - file: 'tests/unit/serializers/foo-test.js', - contains: [ - 'moduleForModel(\'foo\'' - ] - } - ] - }); + var args = ['serializer', 'foo']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('app/serializers/foo.js')) + .to.contain('import JSONAPISerializer from \'ember-data/serializers/json-api\';') + .to.contain('export default JSONAPISerializer.extend('); + + expect(_file('tests/unit/serializers/foo-test.js')) + .to.contain('moduleForModel(\'foo\''); + })); }); it('serializer extends application serializer if it exists', function() { - return generateAndDestroy(['serializer', 'application'], { - afterGenerate: function() { - return generateAndDestroy(['serializer', 'foo'], { - skipInit: true, - files: [ - { - file: 'app/serializers/foo.js', - contains: [ - 'import ApplicationSerializer from \'./application\';', - 'export default ApplicationSerializer.extend({' - ] - }, - { - file: 'tests/unit/serializers/foo-test.js', - contains: [ - 'moduleForModel(\'foo\'' - ] - } - ] - }); - } - }); + var args = ['serializer', 'foo']; + + return emberNew() + .then(() => emberGenerate(['serializer', 'application'])) + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('app/serializers/foo.js')) + .to.contain('import ApplicationSerializer from \'./application\';') + .to.contain('export default ApplicationSerializer.extend({'); + + expect(_file('tests/unit/serializers/foo-test.js')) + .to.contain('moduleForModel(\'foo\''); + })); }); it('serializer with --base-class', function() { - return generateAndDestroy(['serializer', 'foo', '--base-class=bar'], { - files: [ - { - file: 'app/serializers/foo.js', - contains: [ - 'import BarSerializer from \'./bar\';', - 'export default BarSerializer.extend({' - ] - }, - { - file: 'tests/unit/serializers/foo-test.js', - contains: [ - 'moduleForModel(\'foo\'' - ] - } - ] - }); + var args = ['serializer', 'foo', '--base-class=bar']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('app/serializers/foo.js')) + .to.contain('import BarSerializer from \'./bar\';') + .to.contain('export default BarSerializer.extend({'); + + expect(_file('tests/unit/serializers/foo-test.js')) + .to.contain('moduleForModel(\'foo\''); + })); }); it('serializer throws when --base-class is same as name', function() { - return generateAndDestroy(['serializer', 'application', '--base-class=application'], { - throws: { - message: /Serializers cannot extend from themself/, - type: 'SilentError' - } - }); + var args = ['serializer', 'foo', '--base-class=foo']; + + return emberNew() + .then(() => expect(emberGenerate(args)) + .to.be.rejectedWith(SilentError, /Serializers cannot extend from themself/)); }); it('serializer when is named "application"', function() { - return generateAndDestroy(['serializer', 'application'], { - files: [ - { - file: 'app/serializers/application.js', - contains: [ - 'import JSONAPISerializer from \'ember-data/serializers/json-api\';', - 'export default JSONAPISerializer.extend({' - ] - }, - { - file: 'tests/unit/serializers/application-test.js', - contains: [ - 'moduleForModel(\'application\'' - ] - } - ] - }); + var args = ['serializer', 'application']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('app/serializers/application.js')) + .to.contain('import JSONAPISerializer from \'ember-data/serializers/json-api\';') + .to.contain('export default JSONAPISerializer.extend({'); + + expect(_file('tests/unit/serializers/application-test.js')) + .to.contain('moduleForModel(\'application\''); + })); }); it('serializer-test', function() { - return generateAndDestroy(['serializer-test', 'foo'], { - files: [ - { - file: 'tests/unit/serializers/foo-test.js', - contains: [ - 'moduleForModel(\'foo\'' - ] - } - ] - }); + var args = ['serializer-test', 'foo']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/serializers/foo-test.js')) + .to.contain('moduleForModel(\'foo\''); + })); }); it('serializer-test for mocha', function() { - return generateAndDestroy(['serializer-test', 'foo'], { - packages: [ - { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-cli-mocha', dev: true } - ], - files: [ - { - file: 'tests/unit/serializers/foo-test.js', - contains: [ - 'import { describeModel, it } from \'ember-mocha\';', - 'describeModel(\n \'foo\',', - 'Unit | Serializer | foo', - 'needs: [\'serializer:foo\']', - 'expect(serializedRecord).to.be.ok;' - ] - } - ] - }); + var args = ['serializer-test', 'foo']; + + return emberNew() + .then(() => modifyPackages([ + {name: 'ember-cli-qunit', delete: true}, + {name: 'ember-cli-mocha', dev: true} + ])) + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/serializers/foo-test.js')) + .to.contain('import { describeModel, it } from \'ember-mocha\';') + .to.contain('describeModel(\n \'foo\',') + .to.contain('Unit | Serializer | foo') + .to.contain('needs: [\'serializer:foo\']') + .to.contain('expect(serializedRecord).to.be.ok;'); + })); }); }); diff --git a/node-tests/blueprints/transform-test.js b/node-tests/blueprints/transform-test.js index c018792c506..f52814c712e 100644 --- a/node-tests/blueprints/transform-test.js +++ b/node-tests/blueprints/transform-test.js @@ -1,61 +1,54 @@ -var setupTestHooks = require('ember-cli-blueprint-test-helpers/lib/helpers/setup'); -var BlueprintHelpers = require('ember-cli-blueprint-test-helpers/lib/helpers/blueprint-helper'); -var generateAndDestroy = BlueprintHelpers.generateAndDestroy; +var blueprintHelpers = require('ember-cli-blueprint-test-helpers/helpers'); +var setupTestHooks = blueprintHelpers.setupTestHooks; +var emberNew = blueprintHelpers.emberNew; +var emberGenerateDestroy = blueprintHelpers.emberGenerateDestroy; +var modifyPackages = blueprintHelpers.modifyPackages; + +var chai = require('ember-cli-blueprint-test-helpers/chai'); +var expect = chai.expect; describe('Acceptance: generate and destroy transform blueprints', function() { setupTestHooks(this); it('transform', function() { - return generateAndDestroy(['transform', 'foo'], { - files: [ - { - file: 'app/transforms/foo.js', - contains: [ - 'import Transform from \'ember-data/transform\';', - 'export default Transform.extend(', - 'deserialize(serialized) {', - 'serialize(deserialized) {' - ] - }, - { - file: 'tests/unit/transforms/foo-test.js', - contains: [ - 'moduleFor(\'transform:foo\'' - ] - } - ] - }); + var args = ['transform', 'foo']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('app/transforms/foo.js')) + .to.contain('import Transform from \'ember-data/transform\';') + .to.contain('export default Transform.extend(') + .to.contain('deserialize(serialized) {') + .to.contain('serialize(deserialized) {'); + + expect(_file('tests/unit/transforms/foo-test.js')) + .to.contain('moduleFor(\'transform:foo\''); + })); }); it('transforms-test', function() { - return generateAndDestroy(['transform-test', 'foo'], { - files: [ - { - file: 'tests/unit/transforms/foo-test.js', - contains: [ - 'moduleFor(\'transform:foo\'' - ] - } - ] - }); + var args = ['transform-test', 'foo']; + + return emberNew() + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/transforms/foo-test.js')) + .to.contain('moduleFor(\'transform:foo\''); + })); }); it('transform-test for mocha', function() { - return generateAndDestroy(['transform-test', 'foo'], { - packages: [ - { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-cli-mocha', dev: true } - ], - files: [ - { - file: 'tests/unit/transforms/foo-test.js', - contains: [ - 'import { describeModule, it } from \'ember-mocha\';', - 'describeModule(\n \'transform:foo\',', - 'expect(transform).to.be.ok;' - ] - } - ] - }); + var args = ['transform-test', 'foo']; + + return emberNew() + .then(() => modifyPackages([ + {name: 'ember-cli-qunit', delete: true}, + {name: 'ember-cli-mocha', dev: true} + ])) + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/transforms/foo-test.js')) + .to.contain('import { describeModule, it } from \'ember-mocha\';') + .to.contain('describeModule(\n \'transform:foo\',') + .to.contain('expect(transform).to.be.ok;'); + })); }); }); diff --git a/package.json b/package.json index ca3757108dd..9c5a2119b6e 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "ember-ajax": "0.7.1", "ember-cli": "2.4.1", "ember-cli-app-version": "^1.0.0", - "ember-cli-blueprint-test-helpers": "0.10.2", + "ember-cli-blueprint-test-helpers": "0.11.0", "ember-cli-dependency-checker": "^1.2.0", "ember-cli-htmlbars": "^1.0.3", "ember-cli-htmlbars-inline-precompile": "^0.2.0", From c68d0ef892dcea92a68399d06af3f2072086a7cf Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Fri, 8 Apr 2016 14:14:14 -0500 Subject: [PATCH 1483/2527] [BUGFIX beta] convert single record sideloaded records to plural Before, `_normalizeArray` would call `forEach` even if the object wasn't an array. We guard against it by using `Ember.makeArray`. fixes #3805 https://github.com/emberjs/data/issues/3805 --- addon/serializers/rest.js | 2 +- .../serializers/rest-serializer-test.js | 69 ++++++++++++++++++- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index fd43cee67ef..11e4d4c8ee2 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -187,7 +187,7 @@ var RESTSerializer = JSONSerializer.extend({ let serializer = store.serializerFor(modelName); /*jshint loopfunc:true*/ - arrayHash.forEach((hash) => { + Ember.makeArray(arrayHash).forEach((hash) => { let { data, included } = this._normalizePolymorphicRecord(store, hash, prop, modelClass, serializer); documentHash.data.push(data); if (included) { diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 5ad3f021069..6bc505f36c7 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -23,7 +23,8 @@ module("integration/serializer/rest - RESTSerializer", { }); EvilMinion = DS.Model.extend({ superVillain: DS.belongsTo('super-villain', { async: false }), - name: DS.attr('string') + name: DS.attr('string'), + doomsdayDevice: DS.belongsTo('doomsday-device', { async: false }) }); YellowMinion = EvilMinion.extend({ eyes: DS.attr('number') @@ -894,3 +895,69 @@ test('Serializer should respect the attrs hash in links', function(assert) { assert.equal(documentHash.data.relationships.evilMinions.links.related, 'me/minions'); }); + +// https://github.com/emberjs/data/issues/3805 +test('normalizes sideloaded single record so that it sideloads correctly - belongsTo - GH-3805', function(assert) { + env.registry.register("serializer:doomsday-device", DS.RESTSerializer.extend()); + let payload = { + doomsdayDevice: { + id: 1, + evilMinion: 2 + }, + evilMinion: { + id: 2, + doomsdayDevice: 1 + } + }; + + let document = env.store.serializerFor('doomsday-device').normalizeSingleResponse(env.store, DoomsdayDevice, payload); + assert.equal(document.data.relationships.evilMinion.data.id, 2); + assert.equal(document.included.length, 1); + assert.deepEqual(document.included[0], { + attributes: {}, + id: '2', + type: 'evil-minion', + relationships: { + doomsdayDevice: { + data: { + id: '1', + type: 'doomsday-device' + } + } + } + }); +}); + +// https://github.com/emberjs/data/issues/3805 +test('normalizes sideloaded single record so that it sideloads correctly - hasMany - GH-3805', function(assert) { + env.registry.register("serializer:home-planet", DS.RESTSerializer.extend()); + let payload = { + homePlanet: { + id: 1, + superVillains: [2] + }, + superVillain: { + id: 2, + homePlanet: 1 + } + }; + + let document = env.store.serializerFor('home-planet').normalizeSingleResponse(env.store, HomePlanet, payload); + + assert.equal(document.data.relationships.superVillains.data.length, 1); + assert.equal(document.data.relationships.superVillains.data[0].id, 2); + assert.equal(document.included.length, 1); + assert.deepEqual(document.included[0], { + attributes: {}, + id: '2', + type: 'super-villain', + relationships: { + homePlanet: { + data: { + id: '1', + type: 'home-planet' + } + } + } + }); +}); From 93123c77cd84b9558e11e38ca50cd255c1333fe7 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sat, 9 Apr 2016 16:42:00 +0200 Subject: [PATCH 1484/2527] [FEATURE ds-links-in-record-array] DRY up logic for setting properties --- .../adapter-populated-record-array.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index a1997699a8b..80bb7f0e7ca 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -36,19 +36,14 @@ export default RecordArray.extend({ loadRecords(records, payload) { //TODO Optimize var internalModels = Ember.A(records).mapBy('_internalModel'); + this.setProperties({ + content: Ember.A(internalModels), + isLoaded: true, + meta: cloneNull(payload.meta) + }); + if (isEnabled('ds-links-in-record-array')) { - this.setProperties({ - content: Ember.A(internalModels), - isLoaded: true, - meta: cloneNull(payload.meta), - links: cloneNull(payload.links) - }); - } else { - this.setProperties({ - content: Ember.A(internalModels), - isLoaded: true, - meta: cloneNull(payload.meta) - }); + this.set('links', cloneNull(payload.links)); } internalModels.forEach((record) => { From 89ce6cde4070b68606cef4fc66364b6b5462e9cd Mon Sep 17 00:00:00 2001 From: pangratz Date: Sat, 9 Apr 2016 16:59:45 +0200 Subject: [PATCH 1485/2527] [BUGFIX beta] fix isUpdating for AdapterPopulatedRecordArray#update() The `isUpdating` flag is not set to `true` when the `update()` method on a `DS.AdapterPopulatedRecordArray` is invoked. As with the flag on `DS.RecordArray`, this should be `true` until the update is finished and the array contains the most reset result for the query, fetched from the adapter. --- .../adapter-populated-record-array.js | 9 ++++++ .../system/record-arrays/record-array.js | 20 ++++++++---- addon/-private/system/store.js | 2 -- tests/integration/adapter/queries-test.js | 31 +++++++++++++++++++ 4 files changed, 54 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index 80bb7f0e7ca..b86a5380910 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -27,6 +27,14 @@ export default RecordArray.extend({ throw new Error("The result of a server query (on " + type + ") is immutable."); }, + _update() { + let store = get(this, 'store'); + let modelName = get(this, 'type.modelName'); + let query = get(this, 'query'); + + return store._query(modelName, query, this); + }, + /** @method loadRecords @param {Array} records @@ -39,6 +47,7 @@ export default RecordArray.extend({ this.setProperties({ content: Ember.A(internalModels), isLoaded: true, + isUpdating: false, meta: cloneNull(payload.meta) }); diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index ae1252ccd49..b3f020d44b6 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -106,7 +106,11 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { ```javascript var people = store.peekAll('person'); people.get('isUpdating'); // false - people.update(); + + people.update().then(function() { + people.get('isUpdating'); // false + }); + people.get('isUpdating'); // true ``` @@ -115,13 +119,17 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { update() { if (get(this, 'isUpdating')) { return; } + this.set('isUpdating', true); + return this._update(); + }, + + /* + Update this RecordArray and return a promise which resolves once the update + is finished. + */ + _update() { let store = get(this, 'store'); let modelName = get(this, 'type.modelName'); - let query = get(this, 'query'); - - if (query) { - return store._query(modelName, query, this); - } return store.findAll(modelName, { reload: true }); }, diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 638776894e5..6b1c068c69d 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1006,8 +1006,6 @@ Store = Service.extend({ var adapter = this.adapterFor(typeClass.modelName); var sinceToken = this.typeMapFor(typeClass).metadata.since; - set(array, 'isUpdating', true); - assert("You tried to load all records but you have no adapter (for " + typeClass + ")", adapter); assert("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function'); if (options.reload) { diff --git a/tests/integration/adapter/queries-test.js b/tests/integration/adapter/queries-test.js index 966fe20009a..fcc354a5196 100644 --- a/tests/integration/adapter/queries-test.js +++ b/tests/integration/adapter/queries-test.js @@ -57,6 +57,37 @@ test("When a query is made, the adapter should receive a record array it can pop })); }); +test("a query can be updated via `update()`", function(assert) { + adapter.query = function() { + return Ember.RSVP.resolve([{ id: 'first' }]); + }; + + run(function() { + store.query('person', {}).then(function(query) { + assert.equal(query.get('length'), 1); + assert.equal(query.get('firstObject.id'), 'first'); + assert.equal(query.get('isUpdating'), false); + + adapter.query = function() { + assert.ok('query is called a second time'); + return Ember.RSVP.resolve([{ id: 'second' }]); + }; + + let updateQuery = query.update(); + + assert.equal(query.get('isUpdating'), true); + + return updateQuery; + + }).then(function(query) { + assert.equal(query.get('length'), 1); + assert.equal(query.get('firstObject.id'), 'second'); + + assert.equal(query.get('isUpdating'), false); + }); + }); +}); + testInDebug("The store asserts when query is made and the adapter responses with a single record.", function(assert) { env = setupStore({ person: Person, adapter: DS.RESTAdapter }); store = env.store; From 4da8b08815a7c76e1e18cfe6a63ce3a65a20dd78 Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 31 Mar 2016 13:01:24 -0400 Subject: [PATCH 1486/2527] [BUGFIX beta] Transition an invalid created record to the deleted saved state when deleted. Closes #4289 --- addon/-private/system/model/states.js | 8 +- .../integration/records/delete-record-test.js | 76 +++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index 6d362bec313..54c19820f35 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -410,10 +410,14 @@ var updatedState = dirtyState({ dirtyType: 'updated' }); -createdState.uncommitted.deleteRecord = function(internalModel) { +function createdStateDeleteRecord(internalModel) { internalModel.transitionTo('deleted.saved'); internalModel.send('invokeLifecycleCallbacks'); -}; +} + +createdState.uncommitted.deleteRecord = createdStateDeleteRecord; + +createdState.invalid.deleteRecord = createdStateDeleteRecord; createdState.uncommitted.rollback = function(internalModel) { DirtyState.uncommitted.rollback.apply(this, arguments); diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index 5b2e580c232..0bfd9a14c05 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -8,6 +8,7 @@ import DS from 'ember-data'; var attr = DS.attr; var Person, env; var run = Ember.run; +var get = Ember.get; module("integration/deletedRecord - Deleting Records", { beforeEach() { @@ -149,3 +150,78 @@ test("when deleted records are rolled back, they are still in their previous rec assert.equal(all.get('length'), 2, 'record was not removed'); assert.equal(filtered.get('length'), 2, 'record was not removed'); }); + +test("Deleting an invalid newly created record should remove it from the store", function(assert) { + var record; + var store = env.store; + + env.adapter.createRecord = function() { + return Ember.RSVP.Promise.reject(new DS.InvalidError([ + { + title: 'Invalid Attribute', + detail: 'name is invalid', + source: { + pointer: '/data/attributes/name' + } + } + ])); + }; + + run(function() { + record = store.createRecord('person', { name: 'pablobm' }); + // Invalidate the record to put it in the `root.loaded.created.invalid` state + record.save().catch(Ember.K); + }); + + // Preconditions + assert.equal(get(record, 'currentState.stateName'), 'root.loaded.created.invalid', + 'records should start in the created.invalid state'); + assert.equal(get(store.peekAll('person'), 'length'), 1, 'The new person should be in the store'); + + run(function() { + record.deleteRecord(); + }); + + assert.equal(get(record, 'currentState.stateName'), 'root.deleted.saved'); + assert.equal(get(store.peekAll('person'), 'length'), 0, 'The new person should be removed from the store'); +}); + + +test("Destroying an invalid newly created record should remove it from the store", function(assert) { + var record; + var store = env.store; + + env.adapter.deleteRecord = function() { + assert.fail('The adapter\'s deletedRecord method should not be called when the record was created locally.'); + }; + + env.adapter.createRecord = function() { + return Ember.RSVP.Promise.reject(new DS.InvalidError([ + { + title: 'Invalid Attribute', + detail: 'name is invalid', + source: { + pointer: '/data/attributes/name' + } + } + ])); + }; + + run(function() { + record = store.createRecord('person', { name: 'pablobm' }); + // Invalidate the record to put it in the `root.loaded.created.invalid` state + record.save().catch(Ember.K); + }); + + // Preconditions + assert.equal(get(record, 'currentState.stateName'), 'root.loaded.created.invalid', + 'records should start in the created.invalid state'); + assert.equal(get(store.peekAll('person'), 'length'), 1, 'The new person should be in the store'); + + run(function() { + record.destroyRecord(); + }); + + assert.equal(get(record, 'currentState.stateName'), 'root.deleted.saved'); + assert.equal(get(store.peekAll('person'), 'length'), 0, 'The new person should be removed from the store'); +}); From f78db62d6453e9f4dfee54e9102d0c04d6bb75c0 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sat, 9 Apr 2016 22:33:43 +0200 Subject: [PATCH 1487/2527] [CLEANUP] remove reference to no more used isNewSerializerAPI flag This flag has been used when transitioning from 1.13 to 2.0 and is no more needed in 2.x --- .../serializers/rest-serializer-test.js | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 6bc505f36c7..0fe0f744dac 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -680,9 +680,7 @@ test('normalizeResponse with async polymorphic belongsTo, using { return { @@ -717,9 +715,7 @@ test('normalizeResponse with async polymorphic belongsTo', function(assert) { test('normalizeResponse with async polymorphic hasMany', function(assert) { SuperVillain.reopen({ evilMinions: DS.hasMany('evil-minion', { async: true, polymorphic: true }) }); - env.registry.register('serializer:application', DS.RESTSerializer.extend({ - isNewSerializerAPI: true - })); + env.registry.register('serializer:application', DS.RESTSerializer.extend()); var store = env.store; env.adapter.findRecord = () => { return { @@ -806,9 +802,7 @@ test("normalizeResponse can load secondary records of the same type without affe }); test("don't polymorphically deserialize base on the type key in payload when a type attribute exist", function(assert) { - env.registry.register('serializer:application', DS.RESTSerializer.extend({ - isNewSerializerAPI: true - })); + env.registry.register('serializer:application', DS.RESTSerializer.extend()); run(function() { env.store.push(env.restSerializer.normalizeArrayResponse(env.store, Basket, { @@ -831,9 +825,7 @@ test("don't polymorphically deserialize base on the type key in payload when a t }); test("don't polymorphically deserialize base on the type key in payload when a type attribute exist on a singular response", function(assert) { - env.registry.register('serializer:application', DS.RESTSerializer.extend({ - isNewSerializerAPI: true - })); + env.registry.register('serializer:application', DS.RESTSerializer.extend()); run(function() { env.store.push(env.restSerializer.normalizeSingleResponse(env.store, Basket, { @@ -849,9 +841,7 @@ test("don't polymorphically deserialize base on the type key in payload when a t test("don't polymorphically deserialize based on the type key in payload when a relationship exists named type", function(assert) { - env.registry.register('serializer:application', DS.RESTSerializer.extend({ - isNewSerializerAPI: true - })); + env.registry.register('serializer:application', DS.RESTSerializer.extend()); env.adapter.findRecord = () => { return { From c7282a5f8768354b46585c9a5bba3c3cffed61ec Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 12 Apr 2016 00:18:02 -0400 Subject: [PATCH 1488/2527] Update changelog for the Ember Data 2.5.0 release --- CHANGELOG.md | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29f653013bf..ea041c871c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,79 @@ ### Master +### Release 2.5.0 (April 11, 2016) +- [#4293](https://github.com/emberjs/data/pull/4293) Transition an invalid created record to the deleted saved state when deleted +- [#4304](https://github.com/emberjs/data/pull/4304) pass DS.SnapshotRecordArray to build-url-mixin buildURL +- [#4308](https://github.com/emberjs/data/pull/4308) pass snapshot through to urlForFindHasMany and urlForFindBelongsTo +- [#4314](https://github.com/emberjs/data/pull/4314) [BUGFIX beta] convert single record sideloaded records to plural +- [#4316](https://github.com/emberjs/data/pull/4316) Fix `isUpdating` for DS.AdapterPopulatedRecordArray#update() +- [#4245](https://github.com/emberjs/data/pull/4245) Tweaks to docs on error responses +- [#4268](https://github.com/emberjs/data/pull/4268) JSONSerializer should normalize the links object using the attrs hash +- [#4270](https://github.com/emberjs/data/pull/4270) Fix incorrect reference to `push` in the `findRecord` docs +- [#4271](https://github.com/emberjs/data/pull/4271) [BUGFIX beta] Ensure `null` is returned for Reference#value() +- [#4274](https://github.com/emberjs/data/pull/4274) [DOC canary] Update extractMeta documentation +- [#4295](https://github.com/emberjs/data/pull/4295) [DOC release] Mistaken back tick. +- [#4178](https://github.com/emberjs/data/pull/4178) DS.Store type presence checks +- [#4194](https://github.com/emberjs/data/pull/4194) Use modelNameFromPayloadKey when type is given +- [#4243](https://github.com/emberjs/data/pull/4243) moves the ember dep in the package-manager package.json into optionalDependencies +- [#4248](https://github.com/emberjs/data/pull/4248) fix prod-build issue +- [#4250](https://github.com/emberjs/data/pull/4250) [BUGFIX beta] Use Ember.assign when availability +- [#4256](https://github.com/emberjs/data/pull/4256) [BUGFIX release] Revert pr #3864 +- [#4214](https://github.com/emberjs/data/pull/4214) Fix AMD dependencies +- [#4184](https://github.com/emberjs/data/pull/4184) blueprints: Use project.dependencies() to determine test framework +- [#3559](https://github.com/emberjs/data/pull/3559) [BUGFIX release] Guard against isDestroyed in ManyArray.flushCanonical +- [#4154](https://github.com/emberjs/data/pull/4154) Make sure new record are not pushed twice when parent is saved before. +- [#4198](https://github.com/emberjs/data/pull/4198) [DOC beta] Fix error message internal docs +- [#4200](https://github.com/emberjs/data/pull/4200) Avoid errors when ember-cli-shims is not included. +- [#4204](https://github.com/emberjs/data/pull/4204) Fix RESTAdapter.findRecord without a snapshot +- [#4205](https://github.com/emberjs/data/pull/4205) [BUGFIX release] ensure import paths are resolved \w posix separators +- [#4221](https://github.com/emberjs/data/pull/4221) [BUGFIX beta] use assert from debug utils so it is stripped correctly +- [#4235](https://github.com/emberjs/data/pull/4235) [DOC] Fix store.findAll return type +- [#4237](https://github.com/emberjs/data/pull/4237) [DOC beta] Fix typo in inline doc. of normalizeResponse +- [#4119](https://github.com/emberjs/data/pull/4119) Add ember.js and ember-data tags automatically to SO question +- [#4063](https://github.com/emberjs/data/pull/4063) [BUGFIX release] don't load "app" code when loading globals files +- [#4040](https://github.com/emberjs/data/pull/4040) Use test helpers from ember dev +- [#4116](https://github.com/emberjs/data/pull/4116) Add assertions for store#query() +- [#4066](https://github.com/emberjs/data/pull/4066) Use correct version number when used as an addon. +- [#4065](https://github.com/emberjs/data/pull/4065) Bump canary to 2.5.0 +- [#4070](https://github.com/emberjs/data/pull/4070) Update blueprints to import modules directly +- [#4111](https://github.com/emberjs/data/pull/4111) [BUGFIX beta] Add ducktyping of `AdapterError` +- [#4084](https://github.com/emberjs/data/pull/4084) [cleanup] Remove unnecessary inline JSHint config +- [#4082](https://github.com/emberjs/data/pull/4082) Move the date import to where it is used intead of the root module +- [#4074](https://github.com/emberjs/data/pull/4074) Update README, now that ember-data is a proper addon +- [#4079](https://github.com/emberjs/data/pull/4079) [CLEANUP] remove unused config/ember-defeatureify.js +- [#4078](https://github.com/emberjs/data/pull/4078) Use `Ember.merge` instead of ember-data's shim +- [#4090](https://github.com/emberjs/data/pull/4090) Make yui doc generate links from the project root instead of the file… +- [#4085](https://github.com/emberjs/data/pull/4085) Update codeclimate.yml +- [#4086](https://github.com/emberjs/data/pull/4086) [FEATURE ds-transform-pass-options] pass options to DS.Transform +- [#4141](https://github.com/emberjs/data/pull/4141) [DOC] Document behavior of object level errors with JSON API +- [#4094](https://github.com/emberjs/data/pull/4094) Update changelog for 2.3.2 release +- [#4092](https://github.com/emberjs/data/pull/4092) Delete TRANSITION.md +- [#4152](https://github.com/emberjs/data/pull/4152) Remove extra definition of InvalidError +- [#4100](https://github.com/emberjs/data/pull/4100) [DOC] Replace reference to DS.Store.find +- [#4102](https://github.com/emberjs/data/pull/4102) [DOC] Fix misleading docs for `DS.RESTAdapter.findBelongsTo` +- [#4110](https://github.com/emberjs/data/pull/4110) [FEATURE ds-pushpayload-return] Change `pushPayload` to return a value. +- [#4097](https://github.com/emberjs/data/pull/4097) Update `.npmignore` +- [#4104](https://github.com/emberjs/data/pull/4104) [DOC] Mark `DS.Store.filter` as private +- [#4101](https://github.com/emberjs/data/pull/4101) [cleanup] Remove unneeded `getComputedPropertyDesc` test helper +- [#4160](https://github.com/emberjs/data/pull/4160) Fixes broken link +- [#4128](https://github.com/emberjs/data/pull/4128) Fix calls to keyForRelationship in embedded records +- [#4117](https://github.com/emberjs/data/pull/4117) Add assertion for polymorphic type for HasManyReference#push +- [#4118](https://github.com/emberjs/data/pull/4118) [ci skip] Sort CHANGELOG by version and not date of release +- [#4164](https://github.com/emberjs/data/pull/4164) [CLEANUP] remove `toString` definitions for models in tests +- [#4147](https://github.com/emberjs/data/pull/4147) Fix key remapping for embedded belongsTo +- [#4135](https://github.com/emberjs/data/pull/4135) import require +- [#4153](https://github.com/emberjs/data/pull/4153) calling reload multiple times on a has many triggers only one request +- [#4155](https://github.com/emberjs/data/pull/4155) remove container related deprecation warnings +- [#4159](https://github.com/emberjs/data/pull/4159) [DOC] Mark store.filter as deprecated in JSDoc. +- [#4167](https://github.com/emberjs/data/pull/4167) Add blueprints from ember-cli-mocha +- [#4168](https://github.com/emberjs/data/pull/4168) TravisCI: Use PhantomJS v2.1.1 +- [#4169](https://github.com/emberjs/data/pull/4169) Simplify PhantomJS installation on TravisCI +- [#4171](https://github.com/emberjs/data/pull/4171) [CLEANUP] Remove shim for Backburner.join +- [#4172](https://github.com/emberjs/data/pull/4172) [CLEANUP] Remove shim for Ember.Service +- [#4224](https://github.com/emberjs/data/pull/4224) Enable feature flags for 2.5 beta cycle + + ### Release 2.4.3 (March 22, 2016) - [#4243](https://github.com/emberjs/data/pull/4243) moves the ember dep in the package-manager package.json into optionalDependencies - [#4256](https://github.com/emberjs/data/pull/4256) [BUGFIX release] Revert pr #3864 From cb0f7e77f5e7a322dbce74617ea847b12b6a0c01 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 12 Apr 2016 00:22:53 -0400 Subject: [PATCH 1489/2527] Bump version to 2.6.0-canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9c5a2119b6e..06905944c59 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.6.0-canary", + "version": "2.7.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From 76223e0cad82d5834266aa5c50d3ce1463d23d68 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 12 Apr 2016 07:40:28 -0400 Subject: [PATCH 1490/2527] [BUGFIX canary] Enable features that have been "go"ed. --- config/features.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/features.json b/config/features.json index e42f1bb4a7f..f8dced67655 100644 --- a/config/features.json +++ b/config/features.json @@ -1,11 +1,11 @@ { "ds-boolean-transform-allow-null": null, - "ds-finder-include": null, + "ds-finder-include": true, "ds-improved-ajax": null, - "ds-references": null, - "ds-transform-pass-options": null, + "ds-references": true, + "ds-transform-pass-options": true, "ds-pushpayload-return": null, - "ds-serialize-ids-and-types": null, + "ds-serialize-ids-and-types": true, "ds-extended-errors": null, "ds-links-in-record-array": null } From eeb8ee369ad3c32fc91042a4c9bde3b1f8922acb Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 12 Apr 2016 07:41:20 -0400 Subject: [PATCH 1491/2527] [BUGFIX release] Ensure feature flag stripping works for all builds. Prior to this, the feature flags would only be processed for `production` builds (from within an ember-cli app). This is incorrect, they should be processed for all builds (for every environment) so that any features explicitly enabled or disabled in the version of Ember data being used are stripped properly. --- index.js | 8 +++----- lib/javascripts.js | 5 ++--- lib/stripped-build-plugins.js | 37 ++++++++++++++++++++--------------- lib/stripped-build.js | 6 +++--- 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/index.js b/index.js index f6a6ca6d979..e23683c1a8a 100644 --- a/index.js +++ b/index.js @@ -101,11 +101,9 @@ module.exports = { included: function(app) { this._super.included.apply(this, arguments); - if (process.env.EMBER_ENV === 'production') { - this.options.babel = this.options.babel || {}; - add(this.options.babel, 'blacklist', ['es6.modules', 'useStrict']); - add(this.options.babel, 'plugins', require('./lib/stripped-build-plugins')()); - } + this.options.babel = this.options.babel || {}; + add(this.options.babel, 'blacklist', ['es6.modules', 'useStrict']); + add(this.options.babel, 'plugins', require('./lib/stripped-build-plugins')(process.env.EMBER_ENV)); if (this._forceBowerUsage) { this.app.import({ diff --git a/lib/javascripts.js b/lib/javascripts.js index da66aa74ede..2209df30b17 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -10,11 +10,10 @@ var path = require('path'); var Funnel = require('broccoli-funnel'); var versionReplace = require('./version-replace'); var fileCreator = require('broccoli-file-creator'); -var babelBuild = require('./babel-build'); var strippedBuild = require('./stripped-build'); function debugBuild(packageName, tree) { - var compiled = babelBuild(packageName, tree); + var compiled = strippedBuild(packageName, tree, 'development'); return stew.mv(compiled, packageName); } @@ -24,7 +23,7 @@ function makeStrippedBuild(packageName, tree) { exclude: ['ember-data/-private/debug.js'] }); - var stripped = strippedBuild(packageName, withoutDebug); + var stripped = strippedBuild(packageName, withoutDebug, 'production'); return stew.mv(stripped, packageName); } diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 49afe181683..2d9a7d08128 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -3,7 +3,7 @@ var path = require('path'); var filterImports = require('babel-plugin-filter-imports'); var featureFlags = require('babel-plugin-feature-flags'); -module.exports = function() { +module.exports = function(environment) { var featuresJsonPath = __dirname + '/../config/features.json'; var featuresJson = fs.readFileSync(featuresJsonPath, { encoding: 'utf8' }); var features = JSON.parse(featuresJson); @@ -16,24 +16,29 @@ module.exports = function() { // features[feature] = false; // } // } - - return [ + var plugins = [ featureFlags({ import: { module: 'ember-data/-private/features' }, features: features - }), - - filterImports({ - 'ember-data/-private/debug': [ - 'assert', - 'assertPolymorphicType', - 'debug', - 'deprecate', - 'info', - 'runInDebug', - 'warn', - 'debugSeal' - ] }) ]; + + if (environment === 'production') { + plugins.push( + filterImports({ + 'ember-data/-private/debug': [ + 'assert', + 'assertPolymorphicType', + 'debug', + 'deprecate', + 'info', + 'runInDebug', + 'warn', + 'debugSeal' + ] + }) + ); + } + + return plugins; }; diff --git a/lib/stripped-build.js b/lib/stripped-build.js index ddb9a0d39db..3eef7603efa 100644 --- a/lib/stripped-build.js +++ b/lib/stripped-build.js @@ -5,9 +5,9 @@ var featureFlags = require('babel-plugin-feature-flags'); var babelBuild = require('./babel-build'); var strippedBuildPlugins = require('./stripped-build-plugins'); -module.exports = function(packageName, tree, _options) { - var options = _options || {}; - options.plugins = strippedBuildPlugins(); +module.exports = function(packageName, tree, environmentBuildingFor) { + var options = {}; + options.plugins = strippedBuildPlugins(environmentBuildingFor); return babelBuild(packageName, tree, options); }; From e5b3268d2121b63c2d74f1f0063b481e5de7188f Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 13 Apr 2016 08:25:28 +0200 Subject: [PATCH 1492/2527] [DOC beta] Clarify DS.Model#changedAttributes() --- addon/-private/system/model/model.js | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index f854d16166d..32caa0c7364 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -592,21 +592,40 @@ var Model = Ember.Object.extend(Ember.Evented, { Returns an object, whose keys are changed properties, and value is an [oldProp, newProp] array. + The array represents the diff of the canonical state with the local state + of the model. Note: if the model is created locally, the canonical state is + empty since the adapter hasn't acknowledged the attributes yet: + Example ```app/models/mascot.js import DS from 'ember-data'; export default DS.Model.extend({ - name: attr('string') + name: attr('string'), + isAdmin: attr('boolean', { + defaultValue: false + }) }); ``` ```javascript var mascot = store.createRecord('mascot'); + mascot.changedAttributes(); // {} + mascot.set('name', 'Tomster'); - mascot.changedAttributes(); // {name: [undefined, 'Tomster']} + mascot.changedAttributes(); // { name: [undefined, 'Tomster'] } + + mascot.set('isAdmin', true); + mascot.changedAttributes(); // { isAdmin: [undefined, true], name: [undefined, 'Tomster'] } + + mascot.save().then(function() { + mascot.changedAttributes(); // {} + + mascot.set('isAdmin', false); + mascot.changedAttributes(); // { isAdmin: [true, false] } + }); ``` @method changedAttributes From 1521d5af71b342b718e0f3ca3a716e9387be9633 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sun, 10 Apr 2016 10:58:21 +0200 Subject: [PATCH 1493/2527] [FEATURE ds-payload-hooks] Add hooks to map type in payload to modelName The `modelNameFromPayloadKey` and `payloadKeyFromModelName` hooks on the serializer allow to customize the mapping between the key of a JSON and the corresponding name of the model. Consider the following payload: ```json { "blog/post": { "id": 1 } } ``` To map the "blog/post" key to the `post` model, the `modelNameFromPayloadKey` hook is used: ```js serializer.modelNameFromPayloadKey("blog/post") ``` --- There are some issues with the current code base, as the `modelNameFromPayloadKey` and `payloadKeyFromModelName` hooks are also used to map the "value" of a type from / to the payload. Consider the following payload of a JSON-API document: ```json { "data": { "id": 1, "type": "API:V1::User" } } ``` To map the namespaced type to the model name ember-data is using, currently the `modelNameFromPayloadKey` is used: ```js serializer.modelNameFromPayloadKey("API::V1::User") ``` Now this gets complicated if your API responds with the following payload (using custom key and custom types for polymorphic records for example): ```json { "blog/post": { "id": 1, "user": 2, "userType": "API:V1::Administrator" } } ``` Now the `modelNameFromPayloadKey` is invoked for both: ```js serializer.modelNameFromPayloadKey("blog/post") serializer.modelNameFromPayloadKey("API::V1::Administrator") ``` This means that the logic within the hook would get complicated. --- As the name suggests, the method should only be used to map the key, not the value. This commit adds `modelNameFromPayloadType` and `payloadTypeFromModelName` hooks and uses them during normalization and serialization. This commit maintains the old behavior using, if it is used and logs a deprecation warning to move to the new hooks. --- FEATURES.md | 49 ++++ addon/serializers/json-api.js | 243 +++++++++++++++++- addon/serializers/json.js | 49 +++- addon/serializers/rest.js | 200 +++++++++++++- config/features.json | 3 +- .../serializers/json-api-serializer-test.js | 236 +++++++++++++++++ .../serializers/json-serializer-test.js | 75 ++++++ .../serializers/rest-serializer-test.js | 172 +++++++++++++ 8 files changed, 998 insertions(+), 29 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 2e883106167..3d7b31d63cf 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -82,3 +82,52 @@ entry in `config/features.json`. * [404] `DS.NotFoundError` * [409] `DS.ConflictError` * [500] `DS.ServerError` + +- `ds-payload-type-hooks` + + Adds two new hooks `modelNameFromPayloadType` and `payloadTypeFromModelName` + hooks to the serializers. They are used to map a custom type in the payload + to the Ember-Data model name and vice versa. + + It also deprecates `modelNameFromPayloadKey` and `payloadKeyFromModelName` + for the JSONSerializer and JSONAPISerializer: those payloads don't have + _keys_ which represent a model name. Only the keys in the payload for a + RESTSerializer represent model names, so the `payloadKeyFromModelName` and + `modelNameFromPayloadKey` are available in that serializer. + + ```js + // rest reponse + { + "blog/post": { + "id": 1, + "user": 1, + "userType": "api::v1::administrator" + } + } + + // RESTSerializer invokes the following hooks + restSerializer.modelNameFromPayloadKey("blog/post"); + restSerializer.modelNameFromPayloadType("api::v1::administrator"); + ``` + + ```js + // json-api reponse + { + "data": { + "id": 1, + "type": "api::v1::administrator", + "relationships": { + "supervisor": { + "data": { + "id": 1, + "type": "api::v1::super-user" + } + } + } + } + } + + // JSONAPISerializer invokes the following hooks + jsonApiSerializer.modelNameFromPayloadType("api::v1::administrator"); + jsonApiSerializer.modelNameFromPayloadType("api::v1::super-user"); + ``` diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 3c940b1113f..ed710a6ca28 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -3,7 +3,7 @@ */ import Ember from 'ember'; -import { assert, runInDebug, warn } from 'ember-data/-private/debug'; +import { assert, deprecate, runInDebug, warn } from 'ember-data/-private/debug'; import JSONSerializer from 'ember-data/serializers/json'; import normalizeModelName from 'ember-data/-private/system/normalize-model-name'; import { pluralize, singularize } from 'ember-inflector'; @@ -141,8 +141,25 @@ const JSONAPISerializer = JSONSerializer.extend({ @private */ _normalizeRelationshipDataHelper(relationshipDataHash) { - let type = this.modelNameFromPayloadKey(relationshipDataHash.type); - relationshipDataHash.type = type; + if (isEnabled("ds-payload-type-hooks")) { + let modelName = this.modelNameFromPayloadType(relationshipDataHash.type); + let deprecatedModelNameLookup = this.modelNameFromPayloadKey(relationshipDataHash.type); + + if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { + deprecate("You are using modelNameFromPayloadKey to normalize the type for a relationship. This has been deprecated in favor of modelNameFromPayloadType", false, { + id: 'ds.json-api-serializer.deprecated-model-name-for-relationship', + until: '3.0.0' + }); + + modelName = deprecatedModelNameLookup; + } + + relationshipDataHash.type = modelName; + } else { + let type = this.modelNameFromPayloadKey(relationshipDataHash.type); + relationshipDataHash.type = type; + } + return relationshipDataHash; }, @@ -157,10 +174,30 @@ const JSONAPISerializer = JSONSerializer.extend({ id: 'ds.serializer.type-is-undefined' }); - let modelName = this.modelNameFromPayloadKey(resourceHash.type); + let modelName, usedLookup; + + if (isEnabled("ds-payload-type-hooks")) { + modelName = this.modelNameFromPayloadType(resourceHash.type); + let deprecatedModelNameLookup = this.modelNameFromPayloadKey(resourceHash.type); + + usedLookup = 'modelNameFromPayloadType'; + + if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { + deprecate("You are using modelNameFromPayloadKey to normalize the type for a resource. This has been deprecated in favor of modelNameFromPayloadType", false, { + id: 'ds.json-api-serializer.deprecated-model-name-for-resource', + until: '3.0.0' + }); + + modelName = deprecatedModelNameLookup; + usedLookup = 'modelNameFromPayloadKey'; + } + } else { + modelName = this.modelNameFromPayloadKey(resourceHash.type); + usedLookup = 'modelNameFromPayloadKey'; + } if (!this.store._hasModelFor(modelName)) { - warn(this.warnMessageNoModelForType(modelName, resourceHash.type), false, { + warn(this.warnMessageNoModelForType(modelName, resourceHash.type, usedLookup), false, { id: 'ds.serializer.model-for-type-missing' }); return null; @@ -280,7 +317,23 @@ const JSONAPISerializer = JSONSerializer.extend({ @private */ _extractType(modelClass, resourceHash) { - return this.modelNameFromPayloadKey(resourceHash.type); + if (isEnabled("ds-payload-type-hooks")) { + let modelName = this.modelNameFromPayloadType(resourceHash.type); + let deprecatedModelNameLookup = this.modelNameFromPayloadKey(resourceHash.type); + + if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { + deprecate("You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This has been deprecated in favor of modelNameFromPayloadType", false, { + id: 'ds.json-api-serializer.deprecated-model-name-for-polymorphic-type', + until: '3.0.0' + }); + + modelName = deprecatedModelNameLookup; + } + + return modelName; + } else { + return this.modelNameFromPayloadKey(resourceHash.type); + } }, /** @@ -288,6 +341,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {String} key @return {String} the model's modelName */ + // TODO @deprecated Use modelNameFromPayloadType instead modelNameFromPayloadKey(key) { return singularize(normalizeModelName(key)); }, @@ -297,6 +351,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @param {String} modelName @return {String} */ + // TODO @deprecated Use payloadTypeFromModelName instead payloadKeyFromModelName(modelName) { return pluralize(modelName); }, @@ -396,7 +451,25 @@ const JSONAPISerializer = JSONSerializer.extend({ */ serialize(snapshot, options) { let data = this._super(...arguments); - data.type = this.payloadKeyFromModelName(snapshot.modelName); + + let payloadType; + if (isEnabled("ds-payload-type-hooks")) { + payloadType = this.payloadTypeFromModelName(snapshot.modelName); + let deprecatedPayloadTypeLookup = this.payloadKeyFromModelName(snapshot.modelName); + + if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { + deprecate("You used payloadKeyFromModelName to customize how a type is serialized. Use payloadTypeFromModelName instead.", false, { + id: 'ds.json-api-serializer.deprecated-payload-type-for-model', + until: '3.0.0' + }); + + payloadType = deprecatedPayloadTypeLookup; + } + } else { + payloadType = this.payloadKeyFromModelName(snapshot.modelName); + } + + data.type = payloadType; return { data }; }, @@ -451,8 +524,26 @@ const JSONAPISerializer = JSONSerializer.extend({ let data = null; if (belongsTo) { + let payloadType; + + if (isEnabled("ds-payload-type-hooks")) { + payloadType = this.payloadTypeFromModelName(belongsTo.modelName); + let deprecatedPayloadTypeLookup = this.payloadKeyFromModelName(belongsTo.modelName); + + if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { + deprecate("You used payloadKeyFromModelName to serialize type for belongs-to relationship. Use payloadTypeFromModelName instead.", false, { + id: 'ds.json-api-serializer.deprecated-payload-type-for-belongs-to', + until: '3.0.0' + }); + + payloadType = deprecatedPayloadTypeLookup; + } + } else { + payloadType = this.payloadKeyFromModelName(belongsTo.modelName); + } + data = { - type: this.payloadKeyFromModelName(belongsTo.modelName), + type: payloadType, id: belongsTo.id }; } @@ -486,8 +577,27 @@ const JSONAPISerializer = JSONSerializer.extend({ for (let i = 0; i < hasMany.length; i++) { let item = hasMany[i]; + + let payloadType; + + if (isEnabled("ds-payload-type-hooks")) { + payloadType = this.payloadTypeFromModelName(item.modelName); + let deprecatedPayloadTypeLookup = this.payloadKeyFromModelName(item.modelName); + + if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { + deprecate("You used payloadKeyFromModelName to serialize type for belongs-to relationship. Use payloadTypeFromModelName instead.", false, { + id: 'ds.json-api-serializer.deprecated-payload-type-for-has-many', + until: '3.0.0' + }); + + payloadType = deprecatedPayloadTypeLookup; + } + } else { + payloadType = this.payloadKeyFromModelName(item.modelName); + } + data[i] = { - type: this.payloadKeyFromModelName(item.modelName), + type: payloadType, id: item.id }; } @@ -498,6 +608,117 @@ const JSONAPISerializer = JSONSerializer.extend({ } }); +if (isEnabled("ds-payload-type-hooks")) { + + JSONAPISerializer.reopen({ + + /** + `modelNameFromPayloadType` can be used to change the mapping for a DS model + name, taken from the value in the payload. + + Say your API namespaces the type of a model and returns the following + payload for the `post` model: + + ```javascript + // GET /api/posts/1 + { + "data": { + "id": 1, + "type: "api::v1::post" + } + } + ``` + + By overwriting `modelNameFromPayloadType` you can specify that the + `posr` model should be used: + + ```app/serializers/application.js + import JSONAPISerializer from "ember-data/serializers/json-api"; + + export default JSONAPISerializer.extend({ + modelNameFromPayloadType(payloadType) { + return payloadType.replace('api::v1::', ''); + } + }); + ``` + + By default the modelName for a model is its singularized name in dasherized + form. Usually, Ember Data can use the correct inflection to do this for + you. Most of the time, you won't need to override + `modelNameFromPayloadType` for this purpose. + + Also take a look at + [payloadTypeFromModelName](#method_payloadTypeFromModelName) to customize + how the type of a record should be serialized. + + @method modelNameFromPayloadType + @public + @param {String} payloadType type from payload + @return {String} modelName + */ + modelNameFromPayloadType(type) { + return singularize(normalizeModelName(type)); + }, + + /** + `payloadTypeFromModelName` can be used to change the mapping for the type in + the payload, taken from the model name. + + Say your API namespaces the type of a model and expects the following + payload when you update the `post` model: + + ```javascript + // POST /api/posts/1 + { + "data": { + "id": 1, + "type": "api::v1::post" + } + } + ``` + + By overwriting `payloadTypeFromModelName` you can specify that the + namespaces model name for the `post` should be used: + + ```app/serializers/application.js + import JSONAPISerializer from "ember-data/serializers/json-api"; + + export default JSONAPISerializer.extend({ + payloadTypeFromModelName(modelName) { + return "api::v1::" + modelName; + } + }); + ``` + + By default the payload type is the pluralized model name. Usually, Ember + Data can use the correct inflection to do this for you. Most of the time, + you won't need to override `payloadTypeFromModelName` for this purpose. + + Also take a look at + [modelNameFromPayloadType](#method_modelNameFromPayloadType) to customize + how the model name from should be mapped from the payload. + + @method payloadTypeFromModelName + @public + @param {String} modelname modelName from the record + @return {String} payloadType + */ + payloadTypeFromModelName(modelName) { + return pluralize(modelName); + }, + + _hasCustomModelNameFromPayloadKey() { + return this.modelNameFromPayloadKey !== JSONAPISerializer.prototype.modelNameFromPayloadKey; + }, + + _hasCustomPayloadKeyFromModelName() { + return this.payloadKeyFromModelName !== JSONAPISerializer.prototype.payloadKeyFromModelName; + } + + }); + +} + runInDebug(function() { JSONAPISerializer.reopen({ willMergeMixin(props) { @@ -508,8 +729,8 @@ runInDebug(function() { warnMessageForUndefinedType() { return 'Encountered a resource object with an undefined type (resolved resource using ' + this.constructor.toString() + ')'; }, - warnMessageNoModelForType(modelName, originalType) { - return 'Encountered a resource object with type "' + originalType + '", but no model was found for model name "' + modelName + '" (resolved model name using ' + this.constructor.toString() + '.modelNameFromPayloadKey("' + originalType + '"))'; + warnMessageNoModelForType(modelName, originalType, usedLookup) { + return `Encountered a resource object with type "${originalType}", but no model was found for model name "${modelName}" (resolved model name using '${this.constructor.toString()}.${usedLookup}("${originalType}")).`; } }); }); diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 37fdf3da119..c88e0cd927e 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert, warn } from 'ember-data/-private/debug'; +import { assert, deprecate, warn } from 'ember-data/-private/debug'; import Serializer from "ember-data/serializer"; import coerceId from "ember-data/-private/system/coerce-id"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; @@ -83,7 +83,7 @@ var assign = Ember.assign || Ember.merge; @namespace DS @extends DS.Serializer */ -export default Serializer.extend({ +var JSONSerializer = Serializer.extend({ /** The `primaryKey` is used when serializing and deserializing @@ -603,7 +603,25 @@ export default Serializer.extend({ const modelClass = this.store.modelFor(relationshipModelName); if (relationshipHash.type && !modelHasAttributeOrRelationshipNamedType(modelClass)) { - relationshipHash.type = this.modelNameFromPayloadKey(relationshipHash.type); + + if (isEnabled("ds-payload-type-hooks")) { + let modelName = this.modelNameFromPayloadType(relationshipHash.type); + let deprecatedModelNameLookup = this.modelNameFromPayloadKey(relationshipHash.type); + + if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { + deprecate("You used modelNameFromPayloadKey to customize how a type is normalized. Use modelNameFromPayloadType instead", false, { + id: 'ds.json-serializer.deprecated-type-for-polymorphic-relationship', + until: '3.0.0' + }); + + modelName = deprecatedModelNameLookup; + } + + relationshipHash.type = modelName; + + } else { + relationshipHash.type = this.modelNameFromPayloadKey(relationshipHash.type); + } } return relationshipHash; } @@ -694,6 +712,7 @@ export default Serializer.extend({ @param {String} key @return {String} the model's modelName */ + // TODO @deprecated Use modelNameFromPayloadType instead modelNameFromPayloadKey(key) { return normalizeModelName(key); }, @@ -1466,3 +1485,27 @@ export default Serializer.extend({ return transform; } }); + +if (isEnabled("ds-payload-type-hooks")) { + + JSONSerializer.reopen({ + + /** + @method modelNameFromPayloadType + @public + @param {String} type + @return {String} the model's modelName + */ + modelNameFromPayloadType(type) { + return normalizeModelName(type); + }, + + _hasCustomModelNameFromPayloadKey() { + return this.modelNameFromPayloadKey !== JSONSerializer.prototype.modelNameFromPayloadKey; + } + + }); + +} + +export default JSONSerializer; diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 11e4d4c8ee2..8f06c190f96 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -199,16 +199,36 @@ var RESTSerializer = JSONSerializer.extend({ }, _normalizePolymorphicRecord(store, hash, prop, primaryModelClass, primarySerializer) { - let serializer, modelClass; + let serializer = primarySerializer; + let modelClass = primaryModelClass; + const primaryHasTypeAttribute = modelHasAttributeOrRelationshipNamedType(primaryModelClass); - // Support polymorphic records in async relationships - if (!primaryHasTypeAttribute && hash.type && store._hasModelFor(this.modelNameFromPayloadKey(hash.type))) { - serializer = store.serializerFor(this.modelNameFromPayloadKey(hash.type)); - modelClass = store.modelFor(this.modelNameFromPayloadKey(hash.type)); - } else { - serializer = primarySerializer; - modelClass = primaryModelClass; + + if (!primaryHasTypeAttribute && hash.type) { + // Support polymorphic records in async relationships + let modelName; + if (isEnabled("ds-payload-type-hooks")) { + modelName = this.modelNameFromPayloadType(hash.type); + let deprecatedModelNameLookup = this.modelNameFromPayloadKey(hash.type); + + if (modelName !== deprecatedModelNameLookup && !this._hasCustomModelNameFromPayloadType() && this._hasCustomModelNameFromPayloadKey()) { + deprecate("You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This is has been deprecated in favor of modelNameFromPayloadType", false, { + id: 'ds.rest-serializer.deprecated-model-name-for-polymorphic-type', + until: '3.0.0' + }); + + modelName = deprecatedModelNameLookup; + } + } else { + modelName = this.modelNameFromPayloadKey(hash.type); + } + + if (store._hasModelFor(modelName)) { + serializer = store.serializerFor(modelName); + modelClass = store.modelFor(modelName); + } } + return serializer.normalize(modelClass, hash, prop); }, @@ -748,7 +768,11 @@ var RESTSerializer = JSONSerializer.extend({ if (Ember.isNone(belongsTo)) { json[typeKey] = null; } else { - json[typeKey] = camelize(belongsTo.modelName); + if (isEnabled("ds-payload-type-hooks")) { + json[typeKey] = this.payloadTypeFromModelName(belongsTo.modelName); + } else { + json[typeKey] = camelize(belongsTo.modelName); + } } }, @@ -786,17 +810,165 @@ var RESTSerializer = JSONSerializer.extend({ var typeProperty = this.keyForPolymorphicType(key, relationshipType, 'deserialize'); if (isPolymorphic && resourceHash.hasOwnProperty(typeProperty) && typeof relationshipHash !== 'object') { - let type = this.modelNameFromPayloadKey(resourceHash[typeProperty]); - return { - id: relationshipHash, - type: type - }; + + if (isEnabled("ds-payload-type-hooks")) { + + let payloadType = resourceHash[typeProperty]; + let type = this.modelNameFromPayloadType(payloadType); + let deprecatedTypeLookup = this.modelNameFromPayloadKey(payloadType); + + if (payloadType !== deprecatedTypeLookup && !this._hasCustomModelNameFromPayloadType() && this._hasCustomModelNameFromPayloadKey()) { + deprecate("You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This has been deprecated in favor of modelNameFromPayloadType", false, { + id: 'ds.rest-serializer.deprecated-model-name-for-polymorphic-type', + until: '3.0.0' + }); + + type = deprecatedTypeLookup; + } + + return { + id: relationshipHash, + type: type + }; + + } else { + + let type = this.modelNameFromPayloadKey(resourceHash[typeProperty]); + return { + id: relationshipHash, + type: type + }; + + } } return this._super(...arguments); } }); + +if (isEnabled("ds-payload-type-hooks")) { + + RESTSerializer.reopen({ + + /** + `modelNameFromPayloadType` can be used to change the mapping for a DS model + name, taken from the value in the payload. + + Say your API namespaces the type of a model and returns the following + payload for the `post` model, which has a polymorphic `user` relationship: + + ```javascript + // GET /api/posts/1 + { + "post": { + "id": 1, + "user": 1, + "userType: "api::v1::administrator" + } + } + ``` + + By overwriting `modelNameFromPayloadType` you can specify that the + `administrator` model should be used: + + ```app/serializers/application.js + import RESTSerializer from "ember-data/serializers/rest"; + + export default RESTSerializer.extend({ + modelNameFromPayloadType(payloadType) { + return payloadType.replace('api::v1::', ''); + } + }); + ``` + + By default the modelName for a model is its name in dasherized form. + Usually, Ember Data can use the correct inflection to do this for you. Most + of the time, you won't need to override `modelNameFromPayloadType` for this + purpose. + + Also take a look at + [payloadTypeFromModelName](#method_payloadTypeFromModelName) to customize + how the type of a record should be serialized. + + @method modelNameFromPayloadType + @public + @param {String} payloadType type from payload + @return {String} modelName + */ + modelNameFromPayloadType(payloadType) { + return singularize(normalizeModelName(payloadType)); + }, + + /** + `payloadTypeFromModelName` can be used to change the mapping for the type in + the payload, taken from the model name. + + Say your API namespaces the type of a model and expects the following + payload when you update the `post` model, which has a polymorphic `user` + relationship: + + ```javascript + // POST /api/posts/1 + { + "post": { + "id": 1, + "user": 1, + "userType": "api::v1::administrator" + } + } + ``` + + By overwriting `payloadTypeFromModelName` you can specify that the + namespaces model name for the `administrator` should be used: + + ```app/serializers/application.js + import RESTSerializer from "ember-data/serializers/rest"; + + export default RESTSerializer.extend({ + payloadTypeFromModelName(modelName) { + return "api::v1::" + modelName; + } + }); + ``` + + By default the payload type is the camelized model name. Usually, Ember + Data can use the correct inflection to do this for you. Most of the time, + you won't need to override `payloadTypeFromModelName` for this purpose. + + Also take a look at + [modelNameFromPayloadType](#method_modelNameFromPayloadType) to customize + how the model name from should be mapped from the payload. + + @method payloadTypeFromModelName + @public + @param {String} modelname modelName from the record + @return {String} payloadType + */ + payloadTypeFromModelName(modelName) { + return camelize(modelName); + }, + + _hasCustomModelNameFromPayloadKey() { + return this.modelNameFromPayloadKey !== RESTSerializer.prototype.modelNameFromPayloadKey; + }, + + _hasCustomModelNameFromPayloadType() { + return this.modelNameFromPayloadType !== RESTSerializer.prototype.modelNameFromPayloadType; + }, + + _hasCustomPayloadTypeFromModelName() { + return this.payloadTypeFromModelName !== RESTSerializer.prototype.payloadTypeFromModelName; + }, + + _hasCustomPayloadKeyFromModelName() { + return this.payloadKeyFromModelName !== RESTSerializer.prototype.payloadKeyFromModelName; + }, + + }); + +} + runInDebug(function() { RESTSerializer.reopen({ warnMessageNoModelForKey(prop, typeKey) { diff --git a/config/features.json b/config/features.json index f8dced67655..5a5fe7157e3 100644 --- a/config/features.json +++ b/config/features.json @@ -7,5 +7,6 @@ "ds-pushpayload-return": null, "ds-serialize-ids-and-types": true, "ds-extended-errors": null, - "ds-links-in-record-array": null + "ds-links-in-record-array": null, + "ds-payload-type-hooks": null } diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index ac13e34c6b5..2b25cac3287 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -4,6 +4,8 @@ import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; +import isEnabled from 'ember-data/-private/features'; + import DS from 'ember-data'; var env, store, serializer; @@ -267,3 +269,237 @@ testInDebug('JSON warns when combined with EmbeddedRecordsMixin', function(asser DS.JSONAPISerializer.extend(DS.EmbeddedRecordsMixin).create(); }, /The JSONAPISerializer does not work with the EmbeddedRecordsMixin/); }); + +if (isEnabled("ds-payload-type-hooks")) { + test('mapping of payload type can be customized via modelNameFromPayloadType', function(assert) { + env.registry.register('serializer:user', DS.JSONAPISerializer.extend({ + modelNameFromPayloadType: function(payloadType) { + return payloadType.replace("api::v1::", ""); + } + })); + + let jsonHash = { + data: { + id: "1", + type: "api::v1::user", + relationships: { + company: { + data: { + id: "1", + type: "api::v1::company" + } + }, + handles: { + data: [{ + id: "1", + type: "api::v1::handle" + }] + } + } + } + }; + + assert.expectNoDeprecation(); + + let user = env.store.serializerFor('user').normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); + + assert.deepEqual(user, { + data: { + id: "1", + type: "user", + attributes: {}, + relationships: { + company: { + data: { + id: "1", + type: "company" + } + }, + handles: { + data: [{ + id: "1", + type: "handle" + }] + } + } + } + }); + }); + + testInDebug('DEPRECATED - mapping of payload type can be customized via modelNameFromPayloadKey', function(assert) { + env.registry.register('serializer:user', DS.JSONAPISerializer.extend({ + modelNameFromPayloadKey: function(payloadType) { + return payloadType.replace("api::v1::", ""); + } + })); + + let jsonHash = { + data: { + id: "1", + type: "api::v1::user", + relationships: { + company: { + data: { + id: "1", + type: "api::v1::company" + } + }, + handles: { + data: [{ + id: "1", + type: "api::v1::handle" + }] + } + } + } + }; + + assert.expectDeprecation("You are using modelNameFromPayloadKey to normalize the type for a relationship. This has been deprecated in favor of modelNameFromPayloadType"); + + let user = env.store.serializerFor('user').normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); + + assert.deepEqual(user, { + data: { + id: "1", + type: "user", + attributes: {}, + relationships: { + company: { + data: { + id: "1", + type: "company" + } + }, + handles: { + data: [{ + id: "1", + type: "handle" + }] + } + } + } + }); + }); + + test('mapping of model name can be customized via payloadTypeFromModelName', function(assert) { + env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ + attrs: { + handles: { serialize: true }, + firstName: { serialize: false }, + lastName: { serialize: false }, + title: { serialize: false } + }, + payloadTypeFromModelName: function(modelName) { + return `api::v1::${modelName}`; + } + })); + + let user; + + run(function() { + let company = env.store.push({ + data: { + type: 'company', + id: '1' + } + }); + + let handle = env.store.push({ + data: { + type: 'handle', + id: '1' + } + }); + + user = env.store.createRecord('user', { + company, + handles: [handle] + }); + }); + + assert.expectNoDeprecation(); + + var payload = env.store.serializerFor("user").serialize(user._createSnapshot()); + + assert.deepEqual(payload, { + data: { + type: 'api::v1::user', + relationships: { + company: { + data: { + id: '1', + type: 'api::v1::company' + } + }, + handles: { + data: [{ + id: '1', + type: 'api::v1::handle' + }] + } + } + } + }); + }); + + testInDebug('DEPRECATED - mapping of model name can be customized via payloadKeyFromModelName', function(assert) { + env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ + attrs: { + handles: { serialize: true }, + firstName: { serialize: false }, + lastName: { serialize: false }, + title: { serialize: false } + }, + payloadKeyFromModelName: function(modelName) { + return `api::v1::${modelName}`; + } + })); + + let user; + + run(function() { + let company = env.store.push({ + data: { + type: 'company', + id: '1' + } + }); + + let handle = env.store.push({ + data: { + type: 'handle', + id: '1' + } + }); + + user = env.store.createRecord('user', { + company, + handles: [handle] + }); + }); + + assert.expectDeprecation("You used payloadKeyFromModelName to customize how a type is serialized. Use payloadTypeFromModelName instead."); + + var payload = env.store.serializerFor("user").serialize(user._createSnapshot()); + + assert.deepEqual(payload, { + data: { + type: 'api::v1::user', + relationships: { + company: { + data: { + id: '1', + type: 'api::v1::company' + } + }, + handles: { + data: [{ + id: '1', + type: 'api::v1::handle' + }] + } + } + } + }); + }); +} diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 64dcd01e07d..8a419b9e3cc 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -1,6 +1,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -974,3 +975,77 @@ test('Serializer should respect the attrs hash in links', function(assert) { assert.equal(post.data.attributes.title, "Rails is omakase"); assert.equal(post.data.relationships.comments.links.related, 'posts/1/comments'); }); + +if (isEnabled("ds-payload-type-hooks")) { + + test("mapping of model name can be customized via modelNameFromPayloadType", function(assert) { + env.serializer.modelNameFromPayloadType = function(payloadType) { + return payloadType.replace("api::v1::", ""); + }; + + let jsonHash = { + id: '1', + post: { + id: '1', + type: "api::v1::post" + } + }; + + assert.expectNoDeprecation(); + + let normalized = env.serializer.normalizeSingleResponse(env.store, Favorite, jsonHash); + + assert.deepEqual(normalized, { + data: { + id: '1', + type: 'favorite', + attributes: {}, + relationships: { + post: { + data: { + id: '1', + type: 'post' + } + } + } + }, + included: [] + }); + }); + + testInDebug("DEPRECATED - mapping of model name can be customized via modelNameFromPayloadKey", function(assert) { + env.serializer.modelNameFromPayloadKey = function(payloadType) { + return payloadType.replace("api::v1::", ""); + }; + + let jsonHash = { + id: '1', + post: { + id: '1', + type: "api::v1::post" + } + }; + + assert.expectDeprecation("You used modelNameFromPayloadKey to customize how a type is normalized. Use modelNameFromPayloadType instead"); + + let normalized = env.serializer.normalizeSingleResponse(env.store, Favorite, jsonHash); + + assert.deepEqual(normalized, { + data: { + id: '1', + type: 'favorite', + attributes: {}, + relationships: { + post: { + data: { + id: '1', + type: 'post' + } + } + } + }, + included: [] + }); + }); + +} diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 0fe0f744dac..54f8c78f4a1 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -4,6 +4,8 @@ import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; +import isEnabled from 'ember-data/-private/features'; + import DS from 'ember-data'; var HomePlanet, league, SuperVillain, EvilMinion, YellowMinion, DoomsdayDevice, Comment, Basket, Container, env; @@ -951,3 +953,173 @@ test('normalizes sideloaded single record so that it sideloads correctly - hasMa } }); }); + +if (isEnabled("ds-payload-type-hooks")) { + + test("mapping of payload type can be customized via modelNameFromPayloadType", function(assert) { + env.restSerializer.modelNameFromPayloadType = function(payloadType) { + return payloadType.replace("api::v1::", ""); + }; + + var jsonHash = { + doomsdayDevice: { + id: '1', + evilMinion: '1', + evilMinionType: "api::v1::evil-minion" + } + }; + + assert.expectNoDeprecation(); + + let normalized = env.restSerializer.normalizeResponse(env.store, DoomsdayDevice, jsonHash, '1', 'findRecord'); + + assert.deepEqual(normalized, { + data: { + id: '1', + type: 'doomsday-device', + attributes: {}, + relationships: { + evilMinion: { + data: { + id: '1', + type: 'evil-minion' + } + } + } + }, + included: [] + }); + }); + + test("payload key and payload type can be mapped", function(assert) { + env.restSerializer.modelNameFromPayloadKey = function(payloadKey) { + return 'doomsday-device'; + }; + + env.restSerializer.modelNameFromPayloadType = function(payloadType) { + return payloadType.replace("api::v1::", ""); + }; + + var jsonHash = { + "api/models/doomsday-device": { + id: '1', + evilMinion: '1', + evilMinionType: "api::v1::evil-minion" + } + }; + + assert.expectNoDeprecation(); + + let normalized = env.restSerializer.normalizeResponse(env.store, DoomsdayDevice, jsonHash, '1', 'findRecord'); + + assert.deepEqual(normalized, { + data: { + id: '1', + type: 'doomsday-device', + attributes: {}, + relationships: { + evilMinion: { + data: { + id: '1', + type: 'evil-minion' + } + } + } + }, + included: [] + }); + }); + + test("only overwriting modelNameFromPayloadKey works", function(assert) { + env.restSerializer.modelNameFromPayloadKey = function(payloadKey) { + return payloadKey.replace("api/models/", ""); + }; + + var jsonHash = { + "api/models/doomsday-device": { + id: '1', + evilMinion: '1', + evilMinionType: "evil-minion" + } + }; + + assert.expectNoDeprecation(); + + let normalized = env.restSerializer.normalizeResponse(env.store, DoomsdayDevice, jsonHash, '1', 'findRecord'); + + assert.deepEqual(normalized, { + data: { + id: '1', + type: 'doomsday-device', + attributes: {}, + relationships: { + evilMinion: { + data: { + id: '1', + type: 'evil-minion' + } + } + } + }, + included: [] + }); + }); + + testInDebug("DEPRECATED - mapping of payload type can be customized via modelNameFromPayloadKey", function(assert) { + env.restSerializer.modelNameFromPayloadKey = function(payloadType) { + return payloadType.replace("api::v1::", ""); + }; + + var jsonHash = { + doomsdayDevice: { + id: '1', + evilMinion: '1', + evilMinionType: "api::v1::evil-minion" + } + }; + + assert.expectDeprecation("You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This has been deprecated in favor of modelNameFromPayloadType"); + + let normalized = env.restSerializer.normalizeResponse(env.store, DoomsdayDevice, jsonHash, '1', 'findRecord'); + + assert.deepEqual(normalized, { + data: { + id: '1', + type: 'doomsday-device', + attributes: {}, + relationships: { + evilMinion: { + data: { + id: '1', + type: 'evil-minion' + } + } + } + }, + included: [] + }); + }); + + test("mapping of model name can be customized via payloadTypeFromModelName", function(assert) { + env.restSerializer.payloadTypeFromModelName = function(modelName) { + return `api::v1::${modelName}`; + }; + + let tom, ray; + run(function() { + tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); + ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: "DeathRay" }); + }); + + assert.expectNoDeprecation(); + + let json = env.restSerializer.serialize(ray._createSnapshot()); + + assert.deepEqual(json, { + name: "DeathRay", + evilMinion: "124", + evilMinionType: "api::v1::yellow-minion" + }); + }); + +} From 545f0a3445de89bfb21ad960f2c3607704713aca Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 13 Apr 2016 15:22:13 -0400 Subject: [PATCH 1494/2527] [BUGFIX release] Only setup babel options once. `included` is called for each instance of `EmberApp` created within the consuming applicationm, which means that we would be adding the same plugins if the consuming application happened to be creating two `EmberApp` instances. For example, ember-cli-fastboot currently uses this technique to build both for fastboot AND the normal build. I know of a few other applications that use similar techniques to build two versions of the same `EmberApp` (i.e. a mobile version and a desktop one). This allows us to ensure that `this.options.babel` is only setup once (regardless of how many times `included` is being called) during init. --- index.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index e23683c1a8a..7850942618e 100644 --- a/index.js +++ b/index.js @@ -98,13 +98,23 @@ module.exports = { ])); }, - included: function(app) { - this._super.included.apply(this, arguments); + _setupBabelOptions() { + if (this._hasSetupBabelOptions) { + return; + } this.options.babel = this.options.babel || {}; add(this.options.babel, 'blacklist', ['es6.modules', 'useStrict']); add(this.options.babel, 'plugins', require('./lib/stripped-build-plugins')(process.env.EMBER_ENV)); + this._hasSetupBabelOptions = true; + }, + + included: function(app) { + this._super.included.apply(this, arguments); + + this._setupBabelOptions(); + if (this._forceBowerUsage) { this.app.import({ development: app.bowerDirectory + '/ember-data/ember-data.js', From 63daa57cf302f5abba7b4f6f39cac56f130d5335 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 14 Apr 2016 00:13:39 +0200 Subject: [PATCH 1495/2527] [DOC beta] Make clear where `blog` is coming from --- addon/-private/system/model/model.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index f854d16166d..3c4f77454b1 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -868,7 +868,7 @@ if (isEnabled("ds-references")) { user: DS.belongsTo({ async: true }) }); - store.push({ + var blog = store.push({ type: 'blog', id: 1, relationships: { @@ -927,7 +927,7 @@ if (isEnabled("ds-references")) { comments: DS.hasMany({ async: true }) }); - store.push({ + var blog = store.push({ type: 'blog', id: 1, relationships: { From 2f511a8b6059807041639f586b8529a70ef27b46 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 14 Apr 2016 10:29:11 +0200 Subject: [PATCH 1496/2527] [BUGFIX beta] Overhaul attr/relationships imports in model blueprint When a model is generated via `ember generate model` without attributes and relationships, then it is not immediately clear from the generated blueprint, on how to add attributes and relationships via importing stuff from the modules. This change adds the imports as comments, so uncommenting allows to quickly add the imports without writing the import statement. So the command `ember genrate model foo` now creates this file: ```js import Model from "ember-data/model"; // import attr from "ember-data/attr"; // import { belongsTo, hasMany } from "ember-data/relationships"; export default Model.extend({ }); ``` --- blueprints/model/HELP.md | 18 +++++++++++------- blueprints/model/index.js | 6 ++++++ node-tests/blueprints/model-test.js | 20 ++++++++++---------- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/blueprints/model/HELP.md b/blueprints/model/HELP.md index 78bd0af7d43..bfd70568519 100644 --- a/blueprints/model/HELP.md +++ b/blueprints/model/HELP.md @@ -14,12 +14,16 @@ For instance: \`ember generate model taco filling:belongs-to:protein topp would result in the following model: ```js -import DS from 'ember-data'; -export default DS.Model.extend({ - filling: DS.belongsTo('protein'), - toppings: DS.hasMany('topping'), - name: DS.attr('string'), - price: DS.attr('number'), - misc: DS.attr() +import Model from 'ember-data/model'; + +import attr from 'ember-data/attr'; +import { belongsTo, hasMany } from 'ember-data/relationships'; + +export default Model.extend({ + filling: belongsTo('protein'), + toppings: hasMany('topping'), + name: attr('string'), + price: attr('number'), + misc: attr() }); ``` diff --git a/blueprints/model/index.js b/blueprints/model/index.js index a16c859c548..cca67b2f30a 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -61,14 +61,20 @@ module.exports = { if (shouldImportAttr) { importStatements.push('import attr from \'ember-data/attr\';'); + } else { + importStatements.push('// import attr from \'ember-data/attr\';'); } if (shouldImportBelongsTo && shouldImportHasMany) { importStatements.push('import { belongsTo, hasMany } from \'ember-data/relationships\';'); } else if (shouldImportBelongsTo) { importStatements.push('import { belongsTo } from \'ember-data/relationships\';'); + importStatements.push('// import { hasMany } from \'ember-data/relationships\';'); } else if (shouldImportHasMany) { + importStatements.push('// import { belongsTo } from \'ember-data/relationships\';'); importStatements.push('import { hasMany } from \'ember-data/relationships\';'); + } else { + importStatements.push('// import { belongsTo, hasMany } from \'ember-data/relationships\';'); } importStatements = importStatements.join(EOL); diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index 05531bd4ce1..d3565b41ea3 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -18,10 +18,10 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('app/models/foo.js')) .to.contain('import Model from \'ember-data/model\';') .to.contain('export default Model.extend(') - .to.not.contain('import attr from \'ember-data/attr\';') + .to.contain('// import attr from \'ember-data/attr\';') + .to.contain('// import { belongsTo, hasMany } from \'ember-data/relationships\';') .to.not.contain('import { belongsTo } from \'ember-data/relationships\';') - .to.not.contain('import { hasMany } from \'ember-data/relationships\';') - .to.not.contain('import { belongsTo, hasMany } from \'ember-data/relationships\';'); + .to.not.contain('import { hasMany } from \'ember-data/relationships\';'); expect(_file('tests/unit/models/foo-test.js')) .to.contain('moduleForModel(\'foo\''); @@ -56,9 +56,9 @@ describe('Acceptance: generate and destroy model blueprints', function() { .to.contain('age: attr(\'number\')') .to.contain('name: attr(\'string\')') .to.contain('customAttr: attr(\'custom-transform\')') + .to.contain('// import { belongsTo, hasMany } from \'ember-data/relationships\';') .to.not.contain('import { belongsTo } from \'ember-data/relationships\';') - .to.not.contain('import { hasMany } from \'ember-data/relationships\';') - .to.not.contain('import { belongsTo, hasMany } from \'ember-data/relationships\';'); + .to.not.contain('import { hasMany } from \'ember-data/relationships\';'); expect(_file('tests/unit/models/foo-test.js')) .to.contain('moduleForModel(\'foo\''); @@ -76,8 +76,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { .to.contain('export default Model.extend(') .to.contain('post: belongsTo(\'post\')') .to.contain('author: belongsTo(\'user\')') - .to.not.contain('import attr from \'ember-data/attr\';') - .to.not.contain('import { hasMany } from \'ember-data/relationships\';') + .to.contain('// import attr from \'ember-data/attr\';') + .to.contain('// import { hasMany } from \'ember-data/relationships\';') .to.not.contain('import { belongsTo, hasMany } from \'ember-data/relationships\';'); expect(_file('tests/unit/models/comment-test.js')) @@ -97,8 +97,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { .to.contain('export default Model.extend(') .to.contain('comments: hasMany(\'comment\')') .to.contain('otherComments: hasMany(\'comment\')') - .to.not.contain('import attr from \'ember-data/attr\';') - .to.not.contain('import { belongsTo } from \'ember-data/relationships\';') + .to.contain('// import attr from \'ember-data/attr\';') + .to.contain('// import { belongsTo } from \'ember-data/relationships\';') .to.not.contain('import { belongsTo, hasMany } from \'ember-data/relationships\';'); expect(_file('tests/unit/models/post-test.js')) @@ -114,7 +114,7 @@ describe('Acceptance: generate and destroy model blueprints', function() { .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/models/post.js')) .to.contain('import { belongsTo, hasMany } from \'ember-data/relationships\';') - .to.not.contain('import attr from \'ember-data/attr\';') + .to.contain('// import attr from \'ember-data/attr\';') .to.not.contain('import { belongsTo } from \'ember-data/relationships\';') .to.not.contain('import { hasMany } from \'ember-data/relationships\';'); })); From 4e6fe7f21b65df23040ce96910a5da61bbacb30d Mon Sep 17 00:00:00 2001 From: Scott Batson Date: Wed, 13 Apr 2016 14:49:56 -0400 Subject: [PATCH 1497/2527] [DOC] Update CONTRIBUTING.md for feature flags --- CONTRIBUTING.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b8ccc7683f6..25ea22e4e57 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -58,6 +58,58 @@ this will also help us to understand it better ourselves. always have more work to do than time to do it. If you can write some code then that will speed the process along. +### Using Feature Flags + +Feature flags allow new features to be tested easily and strips them out of +production builds automatically. + +1. Add your new feature flag to the [config/features.json](https://github.com/emberjs/data/blob/master/config/features.json) file. + + ```js + { + "ds-boolean-transform-allow-null": null, + "ds-mynew-feature": null + } + ``` + + Give it a default of `null` so it will not be used in production builds. + +2. Import `isEnabled` from `ember-data/-private/features`, wrapping any new + code with your feature: + + ```js + import isEnabled from 'ember-data/-private/features'; + + if (isEnabled('ds-mynew-feature')) { + // ... any additional code + } else { + // ... any previous code that may have been overwritten + } + ``` + +3. Similarly, you will want to wrap any new or edited tests with the same + feature flag. + + ```js + import isEnabled from 'ember-data/-private/features'; + + if (isEnabled('ds-mynew-feature')) { + test('test for new feature', function(assert) { + // ... + }) + } + ``` + + This will allow the test suite to run as normal. + +4. Running tests with all feature flags enabled is possible via + `ember test --environment=test-optional-features` This is also possible while + running tests in the browser via the `Enable Opt Feature` checkbox. + +5. Add your feature to the [Features](https://github.com/emberjs/data/blob/master/FEATURES.md) file. + Be sure to leave a description of the feature and possible example of how to + use it (if necessary). + # Pull Requests We love pull requests. Here's a quick guide: @@ -155,4 +207,3 @@ In general almost all commits should fall into one of these categories. In the c NOTE: * Partially copied from https://raw.github.com/thoughtbot/factory_girl_rails/master/CONTRIBUTING.md * Commit tagging section taken from [ember.js](https://github.com/emberjs/ember.js/blob/5641c3089180bdd1d4fa54e9dd2d3ac285f088e4/CONTRIBUTING.md#commit-tagging) - From 6bdeb31cb9335e40e0b6abb895b4ac319d0cf1c6 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 14 Apr 2016 10:43:38 -0500 Subject: [PATCH 1498/2527] [BUGFIX release] use es5 syntax for addon's index.js file (#4333) Older versions of node can't use the concise method syntax. --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 7850942618e..220387f3991 100644 --- a/index.js +++ b/index.js @@ -98,7 +98,7 @@ module.exports = { ])); }, - _setupBabelOptions() { + _setupBabelOptions: function() { if (this._hasSetupBabelOptions) { return; } From ae99a24005e165c0c55f74546f4253dd1b8d961d Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 14 Apr 2016 20:40:39 -0400 Subject: [PATCH 1499/2527] Port the 2.5.x changelog entires to master --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea041c871c4..352f25b26c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ### Master +### Release 2.5.2 (April 14, 2016) +- [#4328](https://github.com/emberjs/data/pull/4328) [BUGFIX release] Only setup babel options once. +- [#4333](https://github.com/emberjs/data/pull/4333) [BUGFIX release] use es5 syntax for addon's index.js file + +### Release 2.5.1 (April 12, 2016) +- [#4320](https://github.com/emberjs/data/pull/4320) [BUGFIX release] Ensure feature flag stripping works for all builds. + ### Release 2.5.0 (April 11, 2016) - [#4293](https://github.com/emberjs/data/pull/4293) Transition an invalid created record to the deleted saved state when deleted - [#4304](https://github.com/emberjs/data/pull/4304) pass DS.SnapshotRecordArray to build-url-mixin buildURL From cbf2ff72ba79de53c6712e50d8eabb47cbaf53e2 Mon Sep 17 00:00:00 2001 From: Michael Villander Date: Sat, 16 Apr 2016 01:22:15 -0300 Subject: [PATCH 1500/2527] [DOC] Update README.md for improve ES6 sintax in example --- README.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0d0ad4ff6a6..f61d7cd9e9c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ground up to manage loading and saving records, so integrating with other JavaScript APIs is easy. Igor Terzic is currently the lead maintainer of Ember Data, while the rest -of the core team include Yehuda Katz, Tom Dale, Brendan McLoughlin, +of the core team include Yehuda Katz, Tom Dale, Brendan McLoughlin, Christoffer Persson and Stanley Stuart. ## Using Ember Data @@ -81,21 +81,25 @@ ES6 modules (via ember-cli): // app/models/blog-post.js import DS from 'ember-data'; +const { attr, hasMany } = DS; + export default DS.Model.extend({ - title: DS.attr('string'), - createdAt: DS.attr('date'), + title: attr('string'), + createdAt: attr('date'), - comments: DS.hasMany('comment') + comments: hasMany('comment') }); // app/models/comment.js import DS from 'ember-data'; +const { attr, belongsTo } = DS; + export default DS.Model.extend({ - body: DS.attr('string'), - username: DS.attr('string'), + body: attr('string'), + username: attr('string'), - post: DS.belongsTo('blog-post') + post: belongsTo('blog-post') }); ``` From 0ad69cb43680706cbf09d9396c633a08de7d62f6 Mon Sep 17 00:00:00 2001 From: Mattia Gheda Date: Wed, 20 Apr 2016 15:18:15 -0400 Subject: [PATCH 1501/2527] [DOC] fix example syntax (will fix highlighting in docs) --- addon/serializers/embedded-records-mixin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 70801baf119..32ff71fe03a 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -160,7 +160,7 @@ export default Ember.Mixin.create({ Use a custom (type) serializer for the post model to configure embedded author ```app/serializers/post.js - import DS from 'ember-data; + import DS from 'ember-data'; export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { From 87e6e60e9b6266b27eceae17891839cf2b7a1787 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 21 Apr 2016 16:20:18 +0200 Subject: [PATCH 1502/2527] [CLEANUP ds-serialize-ids-and-types] --- FEATURES.md | 24 -------- addon/serializers/embedded-records-mixin.js | 13 +---- config/features.json | 1 - .../embedded-records-mixin-test.js | 57 +++++++++---------- 4 files changed, 30 insertions(+), 65 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 2e883106167..1110d2369bd 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -43,30 +43,6 @@ entry in `config/features.json`. Enables `pushPayload` to return the model(s) that are created or updated via the internal `store.push`. [PR 4110](https://github.com/emberjs/data/pull/4110) -- `ds-serialize-ids-and-types` - - Enables a new `ids-and-type` strategy (in addition to the already existing `ids` and `records`) for - serializing has many relationships using the `DS.EmbeddedRecordsMixin` that will include both - `id` and `type` of each model as an object. - - For instance, if a use has many pets, which is a polymorphic relationship, the generated payload would be: - - ```js - { - "user": { - "id": "1" - "name": "Bertin Osborne", - "pets": [ - { "id": "1", "type": "Cat" }, - { "id": "2", "type": "Parrot"} - ] - } - } - ``` - - This is particularly useful for polymorphic relationships not backed by STI when just including the id - of the records is not enough. - - `ds-extended-errors` Enables `extend` method on errors. It means you can extend from `DS.AdapterError`. diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 32ff71fe03a..0bdc29290de 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -1,6 +1,5 @@ import Ember from 'ember'; import { warn } from "ember-data/-private/debug"; -import isEnabled from 'ember-data/-private/features'; var get = Ember.get; var set = Ember.set; @@ -365,8 +364,6 @@ export default Ember.Mixin.create({ } ``` - Note that the `ids-and-types` strategy is still behind the `ds-serialize-ids-and-types` feature flag. - @method serializeHasMany @param {DS.Snapshot} snapshot @param {Object} json @@ -384,16 +381,12 @@ export default Ember.Mixin.create({ json[serializedKey] = snapshot.hasMany(attr, { ids: true }); } else if (this.hasSerializeRecordsOption(attr)) { this._serializeEmbeddedHasMany(snapshot, json, relationship); - } else { - if (isEnabled("ds-serialize-ids-and-types")) { - if (this.hasSerializeIdsAndTypesOption(attr)) { - this._serializeHasManyAsIdsAndTypes(snapshot, json, relationship); - } - } + } else if (this.hasSerializeIdsAndTypesOption(attr)) { + this._serializeHasManyAsIdsAndTypes(snapshot, json, relationship); } }, - /** + /* Serializes a hasMany relationship as an array of objects containing only `id` and `type` keys. This has its use case on polymorphic hasMany relationships where the server is not storing diff --git a/config/features.json b/config/features.json index f8dced67655..ec497dbad0f 100644 --- a/config/features.json +++ b/config/features.json @@ -5,7 +5,6 @@ "ds-references": true, "ds-transform-pass-options": true, "ds-pushpayload-return": null, - "ds-serialize-ids-and-types": true, "ds-extended-errors": null, "ds-links-in-record-array": null } diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index 0d8f4351931..4b151636adb 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -5,7 +5,6 @@ import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; var get = Ember.get; var HomePlanet, SuperVillain, CommanderVillain, NormalMinion, EvilMinion, YellowMinion, RedMinion, SecretLab, SecretWeapon, BatCave, Comment, @@ -1074,38 +1073,36 @@ test("serialize with embedded objects (hasMany relationships, including related }); }); -if (isEnabled("ds-serialize-ids-and-types")) { - test("serialize has many relationship using the `ids-and-types` strategy", function(assert) { - run(function() { - yellowMinion = env.store.createRecord('yellow-minion', { id: 1, name: "Yellowy" }); - redMinion = env.store.createRecord('red-minion', { id: 1, name: "Reddy" }); - commanderVillain = env.store.createRecord('commander-villain', { id: 1, name: "Jeff", minions: [yellowMinion, redMinion] }); - }); +test("serialize has many relationship using the `ids-and-types` strategy", function(assert) { + run(function() { + yellowMinion = env.store.createRecord('yellow-minion', { id: 1, name: "Yellowy" }); + redMinion = env.store.createRecord('red-minion', { id: 1, name: "Reddy" }); + commanderVillain = env.store.createRecord('commander-villain', { id: 1, name: "Jeff", minions: [yellowMinion, redMinion] }); + }); - env.registry.register('serializer:commander-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - minions: { serialize: 'ids-and-types' } - } - })); - var serializer, json; - run(function() { - serializer = env.container.lookup("serializer:commander-villain"); - var snapshot = commanderVillain._createSnapshot(); - json = serializer.serialize(snapshot); - }); + env.registry.register('serializer:commander-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + minions: { serialize: 'ids-and-types' } + } + })); + var serializer, json; + run(function() { + serializer = env.container.lookup("serializer:commander-villain"); + var snapshot = commanderVillain._createSnapshot(); + json = serializer.serialize(snapshot); + }); - assert.deepEqual(json, { - name: 'Jeff', - minions: [{ - id: '1', - type: 'yellow-minion' - }, { - id: '1', - type: 'red-minion' - }] - }); + assert.deepEqual(json, { + name: 'Jeff', + minions: [{ + id: '1', + type: 'yellow-minion' + }, { + id: '1', + type: 'red-minion' + }] }); -} +}); test("normalizeResponse with embedded object (belongsTo relationship)", function(assert) { env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { From 3c88c9cac995ee7476d812f3e9f47aed3971b5d7 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 21 Apr 2016 16:27:03 +0200 Subject: [PATCH 1503/2527] [CLEANUP ds-finder-include] --- FEATURES.md | 6 --- .../-private/system/snapshot-record-array.js | 4 +- addon/-private/system/snapshot.js | 4 +- addon/adapters/rest.js | 10 ++--- config/features.json | 1 - .../integration/adapter/rest-adapter-test.js | 36 ++++++++---------- .../integration/adapter/store-adapter-test.js | 37 ++++++++----------- .../adapters/rest-adapter/build-query-test.js | 15 +++----- 8 files changed, 44 insertions(+), 69 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 2e883106167..ba0588b4eb4 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -17,12 +17,6 @@ entry in `config/features.json`. Note that this feature only works when `ds-transform-pass-options` is enabled too. -- `ds-finder-include` - - Allows an `include` query parameter to be specified with using - `store.findRecord()` and `store.findAll()` as described in [RFC - 99](https://github.com/emberjs/rfcs/pull/99) - - `ds-improved-ajax` This feature allows to customize how a request is formed by overwriting diff --git a/addon/-private/system/snapshot-record-array.js b/addon/-private/system/snapshot-record-array.js index a7ccfa8c13d..8435f027a7b 100644 --- a/addon/-private/system/snapshot-record-array.js +++ b/addon/-private/system/snapshot-record-array.js @@ -52,9 +52,7 @@ export default function SnapshotRecordArray(recordArray, meta, options = {}) { */ this.adapterOptions = options.adapterOptions; - if (isEnabled('ds-finder-include')) { - this.include = options.include; - } + this.include = options.include; } /** diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index e594b4dd252..ebb75d8e1bf 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -38,9 +38,7 @@ export default function Snapshot(internalModel, options = {}) { */ this.adapterOptions = options.adapterOptions; - if (isEnabled('ds-finder-include')) { - this.include = options.include; - } + this.include = options.include; this._changedAttributes = record.changedAttributes(); } diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index e7597c91ee8..32961341753 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1154,13 +1154,11 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { buildQuery(snapshot) { let query = {}; - if (isEnabled('ds-finder-include')) { - if (snapshot) { - const { include } = snapshot; + if (snapshot) { + const { include } = snapshot; - if (include) { - query.include = include; - } + if (include) { + query.include = include; } } diff --git a/config/features.json b/config/features.json index f8dced67655..2e996577ea9 100644 --- a/config/features.json +++ b/config/features.json @@ -1,6 +1,5 @@ { "ds-boolean-transform-allow-null": null, - "ds-finder-include": true, "ds-improved-ajax": null, "ds-references": true, "ds-transform-pass-options": true, diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index e079c8809dc..9b29c36ed0a 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -185,17 +185,15 @@ test("findRecord - payload with a serializer-specified attribute mapping", funct })); }); -if (isEnabled('ds-finder-include')) { - test("findRecord - passes `include` as a query parameter to ajax", function(assert) { - ajaxResponse({ - post: { id: 1, name: 'Rails is very expensive sushi' } - }); - - run(store, 'findRecord', 'post', 1, { include: 'comments' }).then(assert.wait(function() { - assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` parameter sent to adapter.ajax'); - })); +test("findRecord - passes `include` as a query parameter to ajax", function(assert) { + ajaxResponse({ + post: { id: 1, name: 'Rails is very expensive sushi' } }); -} + + run(store, 'findRecord', 'post', 1, { include: 'comments' }).then(assert.wait(function() { + assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` parameter sent to adapter.ajax'); + })); +}); test("createRecord - an empty payload is a basic success if an id was specified", function(assert) { ajaxResponse(); @@ -1053,17 +1051,15 @@ test("findAll - passes buildURL the requestType and snapshot", function(assert) })); }); -if (isEnabled('ds-finder-include')) { - test("findAll - passed `include` as a query parameter to ajax", function(assert) { - ajaxResponse({ - posts: [{ id: 1, name: 'Rails is very expensive sushi' }] - }); - - run(store, 'findAll', 'post', { include: 'comments' }).then(assert.wait(function() { - assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` params sent to adapter.ajax'); - })); +test("findAll - passed `include` as a query parameter to ajax", function(assert) { + ajaxResponse({ + posts: [{ id: 1, name: 'Rails is very expensive sushi' }] }); -} + + run(store, 'findAll', 'post', { include: 'comments' }).then(assert.wait(function() { + assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` params sent to adapter.ajax'); + })); +}); test("findAll - returning sideloaded data loads the data", function(assert) { ajaxResponse({ diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 227518a7043..eec8b75b16b 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -4,7 +4,6 @@ import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; /* This is an integration test that tests the communication between a store @@ -1319,18 +1318,16 @@ test("store.findRecord should pass adapterOptions to adapter.findRecord", functi }); }); -if (isEnabled('ds-finder-include')) { - test("store.findRecord should pass 'include' to adapter.findRecord", function(assert) { - assert.expect(1); - - env.adapter.findRecord = assert.wait((store, type, id, snapshot) => { - assert.equal(snapshot.include, 'books', 'include passed to adapter.findRecord'); - return Ember.RSVP.resolve({ id: 1 }); - }); +test("store.findRecord should pass 'include' to adapter.findRecord", function(assert) { + assert.expect(1); - run(() => store.findRecord('person', 1, { include: 'books' })); + env.adapter.findRecord = assert.wait((store, type, id, snapshot) => { + assert.equal(snapshot.include, 'books', 'include passed to adapter.findRecord'); + return Ember.RSVP.resolve({ id: 1 }); }); -} + + run(() => store.findRecord('person', 1, { include: 'books' })); +}); test("store.findAll should pass adapterOptions to the adapter.findAll method", function(assert) { assert.expect(1); @@ -1346,18 +1343,16 @@ test("store.findAll should pass adapterOptions to the adapter.findAll method", f }); }); -if (isEnabled('ds-finder-include')) { - test("store.findAll should pass 'include' to adapter.findAll", function(assert) { - assert.expect(1); - - env.adapter.findAll = assert.wait((store, type, sinceToken, arraySnapshot) => { - assert.equal(arraySnapshot.include, 'books', 'include passed to adapter.findAll'); - return Ember.RSVP.resolve([{ id: 1 }]); - }); +test("store.findAll should pass 'include' to adapter.findAll", function(assert) { + assert.expect(1); - run(() => store.findAll('person', { include: 'books' })); + env.adapter.findAll = assert.wait((store, type, sinceToken, arraySnapshot) => { + assert.equal(arraySnapshot.include, 'books', 'include passed to adapter.findAll'); + return Ember.RSVP.resolve([{ id: 1 }]); }); -} + + run(() => store.findAll('person', { include: 'books' })); +}); test("An async hasMany relationship with links should not trigger shouldBackgroundReloadRecord", function(assert) { var Post = DS.Model.extend({ diff --git a/tests/unit/adapters/rest-adapter/build-query-test.js b/tests/unit/adapters/rest-adapter/build-query-test.js index 6632346548d..ca991cc1ea9 100644 --- a/tests/unit/adapters/rest-adapter/build-query-test.js +++ b/tests/unit/adapters/rest-adapter/build-query-test.js @@ -1,6 +1,5 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; module("unit/adapters/rest-adapter/build-query - building queries"); @@ -20,13 +19,11 @@ test("buildQuery - doesn't fail without a snapshot", function(assert) { assert.deepEqual(query, {}, 'returns an empty query'); }); -if (isEnabled('ds-finder-include')) { - test("buildQuery() returns query with `include` from snapshot", function(assert) { - const adapter = DS.RESTAdapter.create(); - const snapshotStub = { include: 'comments' }; +test("buildQuery() returns query with `include` from snapshot", function(assert) { + const adapter = DS.RESTAdapter.create(); + const snapshotStub = { include: 'comments' }; - const query = adapter.buildQuery(snapshotStub); + const query = adapter.buildQuery(snapshotStub); - assert.deepEqual(query, { include: 'comments' }, 'query includes `include`'); - }); -} + assert.deepEqual(query, { include: 'comments' }, 'query includes `include`'); +}); From 29a5fa964d62f3634a20fb205a2fa2724ee397d5 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 21 Apr 2016 16:03:06 +0200 Subject: [PATCH 1504/2527] [CLEANUP ds-references] --- FEATURES.md | 4 - addon/-private/system/model/internal-model.js | 13 +- addon/-private/system/model/model.js | 244 +++-- addon/-private/system/store.js | 87 +- config/features.json | 1 - .../integration/references/belongs-to-test.js | 841 ++++++++-------- tests/integration/references/has-many-test.js | 943 +++++++++--------- tests/integration/references/record-test.js | 345 ++++--- .../relationships/belongs-to-test.js | 189 ++-- tests/unit/model-test.js | 26 - 10 files changed, 1309 insertions(+), 1384 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 2e883106167..9aed1080275 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -29,10 +29,6 @@ entry in `config/features.json`. `methodForRequest`, `urlForRequest`, `headersForRequest` and `bodyForRequest` in the `DS.RESTAdapter`. -- `ds-references` - - Adds references as described in [RFC 57](https://github.com/emberjs/rfcs/pull/57) - - `ds-transform-pass-options` Pass options specified for a `DS.attr` to the `DS.Tranform`'s `serialize` and diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 58501ea5656..b4dec58313d 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -4,7 +4,6 @@ import RootState from "ember-data/-private/system/model/states"; import Relationships from "ember-data/-private/system/relationships/state/create"; import Snapshot from "ember-data/-private/system/snapshot"; import EmptyObject from "ember-data/-private/system/empty-object"; -import isEnabled from "ember-data/-private/features"; import { getOwner @@ -831,12 +830,9 @@ InternalModel.prototype = { } else { return `<${this.modelName}:${this.id}>`; } - } -}; - -if (isEnabled('ds-references')) { + }, - InternalModel.prototype.referenceFor = function(type, name) { + referenceFor(type, name) { var reference = this.references[name]; if (!reference) { @@ -852,6 +848,5 @@ if (isEnabled('ds-references')) { } return reference; - }; - -} + } +}; diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index cb8bb2cab0f..f42acb0d48f 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -2,7 +2,6 @@ import Ember from 'ember'; import { assert, deprecate } from "ember-data/-private/debug"; import { PromiseObject } from "ember-data/-private/system/promise-proxies"; import Errors from "ember-data/-private/system/model/errors"; -import isEnabled from 'ember-data/-private/features'; import DebuggerInfoMixin from 'ember-data/-private/system/debug/debug-info'; import { BelongsToMixin } from 'ember-data/-private/system/relationships/belongs-to'; import { HasManyMixin } from 'ember-data/-private/system/relationships/has-many'; @@ -784,12 +783,123 @@ var Model = Ember.Object.extend(Ember.Evented, { assert("The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); }, - belongsTo() { - assert("The `belongsTo` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); + /** + Get the reference for the specified belongsTo relationship. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + var blog = store.push({ + type: 'blog', + id: 1, + relationships: { + user: { type: 'user', id: 1 } + } + }); + var userRef = blog.belongsTo('user'); + + // check if the user relationship is loaded + var isLoaded = userRef.value() !== null; + + // get the record of the reference (null if not yet available) + var user = userRef.value(); + + // get the identifier of the reference + if (userRef.remoteType() === "id") { + var id = userRef.id(); + } else if (userRef.remoteType() === "link") { + var link = userRef.link(); + } + + // load user (via store.findRecord or store.findBelongsTo) + userRef.load().then(...) + + // or trigger a reload + userRef.reload().then(...) + + // provide data for reference + userRef.push({ + type: 'user', + id: 1, + attributes: { + username: "@user" + } + }).then(function(user) { + userRef.value() === user; + }); + ``` + + @method belongsTo + @param {String} name of the relationship + @since 2.5.0 + @return {BelongsToReference} reference for this relationship + */ + belongsTo: function(name) { + return this._internalModel.referenceFor('belongsTo', name); }, - hasMany() { - assert("The `hasMany` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); + /** + Get the reference for the specified hasMany relationship. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + + var blog = store.push({ + type: 'blog', + id: 1, + relationships: { + comments: { + data: [ + { type: 'comment', id: 1 }, + { type: 'comment', id: 2 } + ] + } + } + }); + var commentsRef = blog.hasMany('comments'); + + // check if the comments are loaded already + var isLoaded = commentsRef.value() !== null; + + // get the records of the reference (null if not yet available) + var comments = commentsRef.value(); + + // get the identifier of the reference + if (commentsRef.remoteType() === "ids") { + var ids = commentsRef.ids(); + } else if (commentsRef.remoteType() === "link") { + var link = commentsRef.link(); + } + + // load comments (via store.findMany or store.findHasMany) + commentsRef.load().then(...) + + // or trigger a reload + commentsRef.reload().then(...) + + // provide data for reference + commentsRef.push([{ type: 'comment', id: 1 }, { type: 'comment', id: 2 }]).then(function(comments) { + commentsRef.value() === comments; + }); + ``` + + @method hasMany + @param {String} name of the relationship + @since 2.5.0 + @return {HasManyReference} reference for this relationship + */ + hasMany: function(name) { + return this._internalModel.referenceFor('hasMany', name); }, setId: Ember.observer('id', function () { @@ -872,130 +982,6 @@ if (Ember.setOwner) { }); } -if (isEnabled("ds-references")) { - - Model.reopen({ - - /** - Get the reference for the specified belongsTo relationship. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - var blog = store.push({ - type: 'blog', - id: 1, - relationships: { - user: { type: 'user', id: 1 } - } - }); - var userRef = blog.belongsTo('user'); - - // check if the user relationship is loaded - var isLoaded = userRef.value() !== null; - - // get the record of the reference (null if not yet available) - var user = userRef.value(); - - // get the identifier of the reference - if (userRef.remoteType() === "id") { - var id = userRef.id(); - } else if (userRef.remoteType() === "link") { - var link = userRef.link(); - } - - // load user (via store.findRecord or store.findBelongsTo) - userRef.load().then(...) - - // or trigger a reload - userRef.reload().then(...) - - // provide data for reference - userRef.push({ - type: 'user', - id: 1, - attributes: { - username: "@user" - } - }).then(function(user) { - userRef.value() === user; - }); - ``` - - @method belongsTo - @param {String} name of the relationship - @return {BelongsToReference} reference for this relationship - */ - belongsTo: function(name) { - return this._internalModel.referenceFor('belongsTo', name); - }, - - /** - Get the reference for the specified hasMany relationship. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - - var blog = store.push({ - type: 'blog', - id: 1, - relationships: { - comments: { - data: [ - { type: 'comment', id: 1 }, - { type: 'comment', id: 2 } - ] - } - } - }); - var commentsRef = blog.hasMany('comments'); - - // check if the comments are loaded already - var isLoaded = commentsRef.value() !== null; - - // get the records of the reference (null if not yet available) - var comments = commentsRef.value(); - - // get the identifier of the reference - if (commentsRef.remoteType() === "ids") { - var ids = commentsRef.ids(); - } else if (commentsRef.remoteType() === "link") { - var link = commentsRef.link(); - } - - // load comments (via store.findMany or store.findHasMany) - commentsRef.load().then(...) - - // or trigger a reload - commentsRef.reload().then(...) - - // provide data for reference - commentsRef.push([{ type: 'comment', id: 1 }, { type: 'comment', id: 2 }]).then(function(comments) { - commentsRef.value() === comments; - }); - ``` - - @method hasMany - @param {String} name of the relationship - @return {HasManyReference} reference for this relationship - */ - hasMany: function(name) { - return this._internalModel.referenceFor('hasMany', name); - } - }); - -} - Model.reopenClass(RelationshipsClassMethodsMixin); Model.reopenClass(AttrClassMethodsMixin); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 6b1c068c69d..cf389fcb508 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -703,6 +703,47 @@ Store = Service.extend({ } }, + /** + Get the reference for the specified record. + + Example + + ```javascript + var userRef = store.getReference('user', 1); + + // check if the user is loaded + var isLoaded = userRef.value() !== null; + + // get the record of the reference (null if not yet available) + var user = userRef.value(); + + // get the identifier of the reference + if (userRef.remoteType() === "id") { + var id = userRef.id(); + } + + // load user (via store.find) + userRef.load().then(...) + + // or trigger a reload + userRef.reload().then(...) + + // provide data for reference + userRef.push({ id: 1, username: "@user" }).then(function(user) { + userRef.value() === user; + }); + ``` + + @method getReference + @param {String} type + @param {String|Integer} id + @since 2.5.0 + @return {RecordReference} + */ + getReference: function(type, id) { + return this._internalModelForId(type, id).recordReference; + }, + /** Get a record by a given type and ID without triggering a fetch. @@ -2006,52 +2047,6 @@ Store = Service.extend({ }); -if (isEnabled("ds-references")) { - - Store.reopen({ - /** - Get the reference for the specified record. - - Example - - ```javascript - var userRef = store.getReference('user', 1); - - // check if the user is loaded - var isLoaded = userRef.value() !== null; - - // get the record of the reference (null if not yet available) - var user = userRef.value(); - - // get the identifier of the reference - if (userRef.remoteType() === "id") { - var id = userRef.id(); - } - - // load user (via store.find) - userRef.load().then(...) - - // or trigger a reload - userRef.reload().then(...) - - // provide data for reference - userRef.push({ id: 1, username: "@user" }).then(function(user) { - userRef.value() === user; - }); - ``` - - @method getReference - @param {String} type - @param {String|Integer} id - @return {RecordReference} - */ - getReference: function(type, id) { - return this._internalModelForId(type, id).recordReference; - } - }); - -} - function deserializeRecordId(store, key, relationship, id) { if (isNone(id)) { return; diff --git a/config/features.json b/config/features.json index f8dced67655..5907b5e321d 100644 --- a/config/features.json +++ b/config/features.json @@ -2,7 +2,6 @@ "ds-boolean-transform-allow-null": null, "ds-finder-include": true, "ds-improved-ajax": null, - "ds-references": true, "ds-transform-pass-options": true, "ds-pushpayload-return": null, "ds-serialize-ids-and-types": true, diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index b66dc17f6c0..77031ff17ad 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -3,556 +3,551 @@ import Ember from 'ember'; import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; -import isEnabled from 'ember-data/-private/features'; - -if (isEnabled("ds-references")) { - - var get = Ember.get; - var run = Ember.run; - var env, Family; - - module("integration/references/belongs-to", { - beforeEach() { - Family = DS.Model.extend({ - persons: DS.hasMany(), - name: DS.attr() - }); - var Person = DS.Model.extend({ - family: DS.belongsTo({ async: true }) - }); - - env = setupStore({ - person: Person, - family: Family - }); - }, - - afterEach() { - run(env.container, 'destroy'); - } - }); - test("record#belongsTo", function(assert) { - var person; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - data: { type: 'family', id: 1 } - } +var get = Ember.get; +var run = Ember.run; +var env, Family; + +module("integration/references/belongs-to", { + beforeEach() { + Family = DS.Model.extend({ + persons: DS.hasMany(), + name: DS.attr() + }); + var Person = DS.Model.extend({ + family: DS.belongsTo({ async: true }) + }); + + env = setupStore({ + person: Person, + family: Family + }); + }, + + afterEach() { + run(env.container, 'destroy'); + } +}); + +test("record#belongsTo", function(assert) { + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } } } - }); + } }); - - var familyReference = person.belongsTo('family'); - - assert.equal(familyReference.remoteType(), 'id'); - assert.equal(familyReference.type, 'family'); - assert.equal(familyReference.id(), 1); }); - test("record#belongsTo for a linked reference", function(assert) { - var person; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - links: { related: '/families/1' } - } + var familyReference = person.belongsTo('family'); + + assert.equal(familyReference.remoteType(), 'id'); + assert.equal(familyReference.type, 'family'); + assert.equal(familyReference.id(), 1); +}); + +test("record#belongsTo for a linked reference", function(assert) { + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + links: { related: '/families/1' } } } - }); + } }); - - var familyReference = person.belongsTo('family'); - - assert.equal(familyReference.remoteType(), 'link'); - assert.equal(familyReference.type, 'family'); - assert.equal(familyReference.link(), "/families/1"); }); - test("BelongsToReference#parent is a reference to the parent where the relationship is defined", function(assert) { - var person; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - data: { type: 'family', id: 1 } - } + var familyReference = person.belongsTo('family'); + + assert.equal(familyReference.remoteType(), 'link'); + assert.equal(familyReference.type, 'family'); + assert.equal(familyReference.link(), "/families/1"); +}); + +test("BelongsToReference#parent is a reference to the parent where the relationship is defined", function(assert) { + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } } } - }); + } }); - - var personReference = env.store.getReference('person', 1); - var familyReference = person.belongsTo('family'); - - assert.ok(personReference); - assert.equal(familyReference.parent, personReference); }); - test("BelongsToReference#meta() returns the most recent meta for the relationship", function(assert) { - var person; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - links: { - related: '/families/1' - }, - meta: { - foo: true - } + var personReference = env.store.getReference('person', 1); + var familyReference = person.belongsTo('family'); + + assert.ok(personReference); + assert.equal(familyReference.parent, personReference); +}); + +test("BelongsToReference#meta() returns the most recent meta for the relationship", function(assert) { + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + links: { + related: '/families/1' + }, + meta: { + foo: true } } } - }); + } }); - - var familyReference = person.belongsTo('family'); - assert.deepEqual(familyReference.meta(), { foo: true }); }); - test("push(object)", function(assert) { - var done = assert.async(); - - var person; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - data: { type: 'family', id: 1 } - } + var familyReference = person.belongsTo('family'); + assert.deepEqual(familyReference.meta(), { foo: true }); +}); + +test("push(object)", function(assert) { + var done = assert.async(); + + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } } } - }); + } }); + }); - var familyReference = person.belongsTo('family'); + var familyReference = person.belongsTo('family'); - run(function() { - var data = { - data: { - type: 'family', - id: 1, - attributes: { - name: "Coreleone" - } + run(function() { + var data = { + data: { + type: 'family', + id: 1, + attributes: { + name: "Coreleone" } - }; + } + }; - familyReference.push(data).then(function(record) { - assert.ok(Family.detectInstance(record), "push resolves with the referenced record"); - assert.equal(get(record, 'name'), "Coreleone", "name is set"); + familyReference.push(data).then(function(record) { + assert.ok(Family.detectInstance(record), "push resolves with the referenced record"); + assert.equal(get(record, 'name'), "Coreleone", "name is set"); - done(); - }); + done(); }); }); - - test("push(record)", function(assert) { - var done = assert.async(); - - var person, family; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - data: { type: 'family', id: 1 } - } +}); + +test("push(record)", function(assert) { + var done = assert.async(); + + var person, family; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } } } - }); - family = env.store.push({ - data: { - type: 'family', - id: 1, - attributes: { - name: "Coreleone" - } + } + }); + family = env.store.push({ + data: { + type: 'family', + id: 1, + attributes: { + name: "Coreleone" } - }); + } }); + }); - var familyReference = person.belongsTo('family'); + var familyReference = person.belongsTo('family'); - run(function() { - familyReference.push(family).then(function(record) { - assert.ok(Family.detectInstance(record), "push resolves with the referenced record"); - assert.equal(get(record, 'name'), "Coreleone", "name is set"); - assert.equal(record, family); + run(function() { + familyReference.push(family).then(function(record) { + assert.ok(Family.detectInstance(record), "push resolves with the referenced record"); + assert.equal(get(record, 'name'), "Coreleone", "name is set"); + assert.equal(record, family); - done(); - }); + done(); }); }); - - test("push(promise)", function(assert) { - var done = assert.async(); - - var push; - var deferred = Ember.RSVP.defer(); - - run(function() { - var person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - data: { type: 'family', id: 1 } - } +}); + +test("push(promise)", function(assert) { + var done = assert.async(); + + var push; + var deferred = Ember.RSVP.defer(); + + run(function() { + var person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } } } - }); - var familyReference = person.belongsTo('family'); - push = familyReference.push(deferred.promise); + } }); + var familyReference = person.belongsTo('family'); + push = familyReference.push(deferred.promise); + }); - assert.ok(push.then, 'BelongsToReference.push returns a promise'); + assert.ok(push.then, 'BelongsToReference.push returns a promise'); - run(function() { - deferred.resolve({ - data: { - type: 'family', - id: 1, - attributes: { - name: "Coreleone" - } + run(function() { + deferred.resolve({ + data: { + type: 'family', + id: 1, + attributes: { + name: "Coreleone" } - }); + } }); + }); - run(function() { - push.then(function(record) { - assert.ok(Family.detectInstance(record), "push resolves with the record"); - assert.equal(get(record, 'name'), "Coreleone", "name is updated"); + run(function() { + push.then(function(record) { + assert.ok(Family.detectInstance(record), "push resolves with the record"); + assert.equal(get(record, 'name'), "Coreleone", "name is updated"); - done(); - }); + done(); }); }); - - testInDebug("push(record) asserts for invalid type", function(assert) { - var person, anotherPerson; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - data: { type: 'family', id: 1 } - } +}); + +testInDebug("push(record) asserts for invalid type", function(assert) { + var person, anotherPerson; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } } } - }); - anotherPerson = env.store.push({ - data: { - type: 'person', - id: 2 - } - }); + } }); + anotherPerson = env.store.push({ + data: { + type: 'person', + id: 2 + } + }); + }); - var familyReference = person.belongsTo('family'); + var familyReference = person.belongsTo('family'); - assert.expectAssertion(function() { - run(function() { - familyReference.push(anotherPerson); - }); - }, "You cannot add a record of type 'person' to the 'person.family' relationship (only 'family' allowed)"); - }); + assert.expectAssertion(function() { + run(function() { + familyReference.push(anotherPerson); + }); + }, "You cannot add a record of type 'person' to the 'person.family' relationship (only 'family' allowed)"); +}); - test("push(record) works with polymorphic type", function(assert) { - var done = assert.async(); +test("push(record) works with polymorphic type", function(assert) { + var done = assert.async(); - var person, mafiaFamily; + var person, mafiaFamily; - env.registry.register('model:mafia-family', Family.extend()); + env.registry.register('model:mafia-family', Family.extend()); - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1 - } - }); - mafiaFamily = env.store.push({ - data: { - type: 'mafia-family', - id: 1 - } - }); + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1 + } }); + mafiaFamily = env.store.push({ + data: { + type: 'mafia-family', + id: 1 + } + }); + }); - var familyReference = person.belongsTo('family'); - run(function() { - familyReference.push(mafiaFamily).then(function(family) { - assert.equal(family, mafiaFamily); + var familyReference = person.belongsTo('family'); + run(function() { + familyReference.push(mafiaFamily).then(function(family) { + assert.equal(family, mafiaFamily); - done(); - }); + done(); }); }); - - test("value() is null when reference is not yet loaded", function(assert) { - var person; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - data: { type: 'family', id: 1 } - } +}); + +test("value() is null when reference is not yet loaded", function(assert) { + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } } } - }); + } }); - - var familyReference = person.belongsTo('family'); - assert.strictEqual(familyReference.value(), null); }); - test("value() returns the referenced record when loaded", function(assert) { - var person, family; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - data: { type: 'family', id: 1 } - } + var familyReference = person.belongsTo('family'); + assert.strictEqual(familyReference.value(), null); +}); + +test("value() returns the referenced record when loaded", function(assert) { + var person, family; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } } } - }); - family = env.store.push({ - data: { - type: 'family', - id: 1 - } - }); + } + }); + family = env.store.push({ + data: { + type: 'family', + id: 1 + } }); - - var familyReference = person.belongsTo('family'); - assert.equal(familyReference.value(), family); }); - test("load() fetches the record", function(assert) { - var done = assert.async(); + var familyReference = person.belongsTo('family'); + assert.equal(familyReference.value(), family); +}); - env.adapter.findRecord = function(store, type, id) { - return Ember.RSVP.resolve({ - id: 1, name: "Coreleone" - }); - }; +test("load() fetches the record", function(assert) { + var done = assert.async(); - var person; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - data: { type: 'family', id: 1 } - } + env.adapter.findRecord = function(store, type, id) { + return Ember.RSVP.resolve({ + id: 1, name: "Coreleone" + }); + }; + + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } } } - }); + } }); + }); - var familyReference = person.belongsTo('family'); + var familyReference = person.belongsTo('family'); - run(function() { - familyReference.load().then(function(record) { - assert.equal(get(record, 'name'), "Coreleone"); + run(function() { + familyReference.load().then(function(record) { + assert.equal(get(record, 'name'), "Coreleone"); - done(); - }); + done(); }); }); +}); - test("load() fetches link when remoteType is link", function(assert) { - var done = assert.async(); +test("load() fetches link when remoteType is link", function(assert) { + var done = assert.async(); - env.adapter.findBelongsTo = function(store, snapshot, link) { - assert.equal(link, "/families/1"); - - return Ember.RSVP.resolve({ - id: 1, name: "Coreleone" - }); - }; + env.adapter.findBelongsTo = function(store, snapshot, link) { + assert.equal(link, "/families/1"); - var person; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - links: { related: '/families/1' } - } + return Ember.RSVP.resolve({ + id: 1, name: "Coreleone" + }); + }; + + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + links: { related: '/families/1' } } } - }); + } }); + }); - var familyReference = person.belongsTo('family'); - assert.equal(familyReference.remoteType(), "link"); + var familyReference = person.belongsTo('family'); + assert.equal(familyReference.remoteType(), "link"); - run(function() { - familyReference.load().then(function(record) { - assert.equal(get(record, 'name'), "Coreleone"); + run(function() { + familyReference.load().then(function(record) { + assert.equal(get(record, 'name'), "Coreleone"); - done(); - }); + done(); }); }); +}); - test("reload() - loads the record when not yet loaded", function(assert) { - var done = assert.async(); - - var count = 0; - env.adapter.findRecord = function(store, type, id) { - count++; - assert.equal(count, 1); +test("reload() - loads the record when not yet loaded", function(assert) { + var done = assert.async(); - return Ember.RSVP.resolve({ - id: 1, name: "Coreleone" - }); - }; + var count = 0; + env.adapter.findRecord = function(store, type, id) { + count++; + assert.equal(count, 1); - var person; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - data: { type: 'family', id: 1 } - } + return Ember.RSVP.resolve({ + id: 1, name: "Coreleone" + }); + }; + + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } } } - }); + } }); + }); - var familyReference = person.belongsTo('family'); + var familyReference = person.belongsTo('family'); - run(function() { - familyReference.reload().then(function(record) { - assert.equal(get(record, 'name'), "Coreleone"); + run(function() { + familyReference.reload().then(function(record) { + assert.equal(get(record, 'name'), "Coreleone"); - done(); - }); + done(); }); }); +}); - test("reload() - reloads the record when already loaded", function(assert) { - var done = assert.async(); +test("reload() - reloads the record when already loaded", function(assert) { + var done = assert.async(); - var count = 0; - env.adapter.findRecord = function(store, type, id) { - count++; - assert.equal(count, 1); + var count = 0; + env.adapter.findRecord = function(store, type, id) { + count++; + assert.equal(count, 1); - return Ember.RSVP.resolve({ - id: 1, name: "Coreleone" - }); - }; - - var person; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - data: { type: 'family', id: 1 } - } + return Ember.RSVP.resolve({ + id: 1, name: "Coreleone" + }); + }; + + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } } } - }); - env.store.push({ - data: { - type: 'family', - id: 1 - } - }); + } }); + env.store.push({ + data: { + type: 'family', + id: 1 + } + }); + }); - var familyReference = person.belongsTo('family'); + var familyReference = person.belongsTo('family'); - run(function() { - familyReference.reload().then(function(record) { - assert.equal(get(record, 'name'), "Coreleone"); + run(function() { + familyReference.reload().then(function(record) { + assert.equal(get(record, 'name'), "Coreleone"); - done(); - }); + done(); }); }); +}); - test("reload() - uses link to reload record", function(assert) { - var done = assert.async(); +test("reload() - uses link to reload record", function(assert) { + var done = assert.async(); - env.adapter.findBelongsTo = function(store, snapshot, link) { - assert.equal(link, "/families/1"); - - return Ember.RSVP.resolve({ - id: 1, name: "Coreleone" - }); - }; + env.adapter.findBelongsTo = function(store, snapshot, link) { + assert.equal(link, "/families/1"); - var person; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - links: { related: '/families/1' } - } + return Ember.RSVP.resolve({ + id: 1, name: "Coreleone" + }); + }; + + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + links: { related: '/families/1' } } } - }); + } }); + }); - var familyReference = person.belongsTo('family'); + var familyReference = person.belongsTo('family'); - run(function() { - familyReference.reload().then(function(record) { - assert.equal(get(record, 'name'), "Coreleone"); + run(function() { + familyReference.reload().then(function(record) { + assert.equal(get(record, 'name'), "Coreleone"); - done(); - }); + done(); }); }); - -} +}); diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 0742366158e..5e165c99eb0 100644 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -3,594 +3,589 @@ import Ember from 'ember'; import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; -import isEnabled from 'ember-data/-private/features'; - -if (isEnabled("ds-references")) { - - var get = Ember.get; - var run = Ember.run; - var env, Person; - - module("integration/references/has-many", { - beforeEach() { - var Family = DS.Model.extend({ - persons: DS.hasMany({ async: true }) - }); - Person = DS.Model.extend({ - name: DS.attr(), - family: DS.belongsTo() - }); - env = setupStore({ - person: Person, - family: Family - }); - }, - - afterEach() { - run(env.container, 'destroy'); - } - }); - test("record#hasMany", function(assert) { - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } +var get = Ember.get; +var run = Ember.run; +var env, Person; + +module("integration/references/has-many", { + beforeEach() { + var Family = DS.Model.extend({ + persons: DS.hasMany({ async: true }) + }); + Person = DS.Model.extend({ + name: DS.attr(), + family: DS.belongsTo() + }); + env = setupStore({ + person: Person, + family: Family + }); + }, + + afterEach() { + run(env.container, 'destroy'); + } +}); + +test("record#hasMany", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] } } - }); + } }); - - var personsReference = family.hasMany('persons'); - - assert.equal(personsReference.remoteType(), 'ids'); - assert.equal(personsReference.type, 'person'); - assert.deepEqual(personsReference.ids(), ['1', '2']); }); - test("record#hasMany for linked references", function(assert) { - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - links: { related: '/families/1/persons' } - } + var personsReference = family.hasMany('persons'); + + assert.equal(personsReference.remoteType(), 'ids'); + assert.equal(personsReference.type, 'person'); + assert.deepEqual(personsReference.ids(), ['1', '2']); +}); + +test("record#hasMany for linked references", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + links: { related: '/families/1/persons' } } } - }); + } }); - - var personsReference = family.hasMany('persons'); - - assert.equal(personsReference.remoteType(), 'link'); - assert.equal(personsReference.type, 'person'); - assert.equal(personsReference.link(), '/families/1/persons'); }); - test("HasManyReference#parent is a reference to the parent where the relationship is defined", function(assert) { - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } + var personsReference = family.hasMany('persons'); + + assert.equal(personsReference.remoteType(), 'link'); + assert.equal(personsReference.type, 'person'); + assert.equal(personsReference.link(), '/families/1/persons'); +}); + +test("HasManyReference#parent is a reference to the parent where the relationship is defined", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] } } - }); + } }); - - var familyReference = env.store.getReference('family', 1); - var personsReference = family.hasMany('persons'); - - assert.ok(familyReference); - assert.equal(personsReference.parent, familyReference); }); - test("HasManyReference#meta() returns the most recent meta for the relationship", function(assert) { - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - links: { related: '/families/1/persons' }, - meta: { - foo: true - } + var familyReference = env.store.getReference('family', 1); + var personsReference = family.hasMany('persons'); + + assert.ok(familyReference); + assert.equal(personsReference.parent, familyReference); +}); + +test("HasManyReference#meta() returns the most recent meta for the relationship", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + links: { related: '/families/1/persons' }, + meta: { + foo: true } } } - }); + } }); - - var personsReference = family.hasMany('persons'); - assert.deepEqual(personsReference.meta(), { foo: true }); }); - test("push(array)", function(assert) { - var done = assert.async(); - - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } + var personsReference = family.hasMany('persons'); + assert.deepEqual(personsReference.meta(), { foo: true }); +}); + +test("push(array)", function(assert) { + var done = assert.async(); + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] } } - }); + } }); + }); - var personsReference = family.hasMany('persons'); + var personsReference = family.hasMany('persons'); - run(function() { - var data = [ - { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, - { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } - ]; + run(function() { + var data = [ + { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, + { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } + ]; - personsReference.push(data).then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); - assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito"); - assert.equal(records.objectAt(1).get('name'), "Michael"); + personsReference.push(data).then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito"); + assert.equal(records.objectAt(1).get('name'), "Michael"); - done(); - }); + done(); }); }); +}); - test("push(array) works with polymorphic type", function(assert) { - var done = assert.async(); +test("push(array) works with polymorphic type", function(assert) { + var done = assert.async(); - env.registry.register('model:mafia-boss', Person.extend()); + env.registry.register('model:mafia-boss', Person.extend()); - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1 - } - }); + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1 + } }); + }); - var personsReference = family.hasMany('persons'); + var personsReference = family.hasMany('persons'); - run(() => { - var data = { - data: [ - { data: { type: 'mafia-boss', id: 1, attributes: { name: "Vito" } } } - ] - }; + run(() => { + var data = { + data: [ + { data: { type: 'mafia-boss', id: 1, attributes: { name: "Vito" } } } + ] + }; - personsReference.push(data).then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); - assert.equal(get(records, 'length'), 1); - assert.equal(records.objectAt(0).get('name'), "Vito"); + personsReference.push(data).then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 1); + assert.equal(records.objectAt(0).get('name'), "Vito"); - done(); - }); + done(); }); }); - - testInDebug("push(array) asserts polymorphic type", function(assert) { - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1 - } - }); +}); + +testInDebug("push(array) asserts polymorphic type", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1 + } }); - - var personsReference = family.hasMany('persons'); - - assert.expectAssertion(() => { - run(() => { - var data = { - data: [ - { data: { type: 'family', id: 1 } } - ] - }; - - personsReference.push(data); - }); - }, "You cannot add a record of type 'family' to the 'family.persons' relationship (only 'person' allowed)"); }); - test("push(object) supports JSON-API payload", function(assert) { - var done = assert.async(); - - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } - } - } - }); - }); + var personsReference = family.hasMany('persons'); - var personsReference = family.hasMany('persons'); - - run(function() { + assert.expectAssertion(() => { + run(() => { var data = { data: [ - { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, - { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } + { data: { type: 'family', id: 1 } } ] }; - personsReference.push(data).then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); - assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito"); - assert.equal(records.objectAt(1).get('name'), "Michael"); - - done(); - }); + personsReference.push(data); }); - }); - - test("push(promise)", function(assert) { - var done = assert.async(); - - var push; - var deferred = Ember.RSVP.defer(); - - run(function() { - var family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } + }, "You cannot add a record of type 'family' to the 'family.persons' relationship (only 'person' allowed)"); +}); + +test("push(object) supports JSON-API payload", function(assert) { + var done = assert.async(); + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] } } - }); - var personsReference = family.hasMany('persons'); - push = personsReference.push(deferred.promise); + } }); + }); - assert.ok(push.then, 'HasManyReference.push returns a promise'); + var personsReference = family.hasMany('persons'); - run(function() { - var data = [ + run(function() { + var data = { + data: [ { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } - ]; - deferred.resolve(data); - }); + ] + }; - run(function() { - push.then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); - assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito"); - assert.equal(records.objectAt(1).get('name'), "Michael"); + personsReference.push(data).then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito"); + assert.equal(records.objectAt(1).get('name'), "Michael"); - done(); - }); + done(); }); }); - - test("value() returns null when reference is not yet loaded", function(assert) { - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } +}); + +test("push(promise)", function(assert) { + var done = assert.async(); + + var push; + var deferred = Ember.RSVP.defer(); + + run(function() { + var family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] } } - }); + } }); - var personsReference = family.hasMany('persons'); - assert.strictEqual(personsReference.value(), null); + push = personsReference.push(deferred.promise); }); - test("value() returns the referenced records when all records are loaded", function(assert) { - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } - } - } - }); - env.store.push({ data: { type: 'person', id: 1, attributes: { name: "Vito" } } }); - env.store.push({ data: { type: 'person', id: 2, attributes: { name: "Michael" } } }); - }); + assert.ok(push.then, 'HasManyReference.push returns a promise'); - var personsReference = family.hasMany('persons'); - var records = personsReference.value(); - assert.equal(get(records, 'length'), 2); - assert.equal(records.isEvery('isLoaded'), true); + run(function() { + var data = [ + { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, + { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } + ]; + deferred.resolve(data); }); - test("load() fetches the referenced records", function(assert) { - var done = assert.async(); + run(function() { + push.then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito"); + assert.equal(records.objectAt(1).get('name'), "Michael"); - env.adapter.findMany = function(store, type, id) { - return Ember.RSVP.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); - }; - - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } + done(); + }); + }); +}); + +test("value() returns null when reference is not yet loaded", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] } } - }); + } }); + }); - var personsReference = family.hasMany('persons'); - - run(function() { - personsReference.load().then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); - assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito"); - assert.equal(records.objectAt(1).get('name'), "Michael"); - - done(); - }); + var personsReference = family.hasMany('persons'); + assert.strictEqual(personsReference.value(), null); +}); + +test("value() returns the referenced records when all records are loaded", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] + } + } + } }); + env.store.push({ data: { type: 'person', id: 1, attributes: { name: "Vito" } } }); + env.store.push({ data: { type: 'person', id: 2, attributes: { name: "Michael" } } }); }); - test("load() fetches link when remoteType is link", function(assert) { - var done = assert.async(); - - env.adapter.findHasMany = function(store, snapshot, link) { - assert.equal(link, "/families/1/persons"); - - return Ember.RSVP.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); - }; - - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - links: { related: '/families/1/persons' } - } + var personsReference = family.hasMany('persons'); + var records = personsReference.value(); + assert.equal(get(records, 'length'), 2); + assert.equal(records.isEvery('isLoaded'), true); +}); + +test("load() fetches the referenced records", function(assert) { + var done = assert.async(); + + env.adapter.findMany = function(store, type, id) { + return Ember.RSVP.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); + }; + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] } } - }); + } }); + }); - var personsReference = family.hasMany('persons'); - assert.equal(personsReference.remoteType(), "link"); + var personsReference = family.hasMany('persons'); - run(function() { - personsReference.load().then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); - assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito"); - assert.equal(records.objectAt(1).get('name'), "Michael"); + run(function() { + personsReference.load().then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito"); + assert.equal(records.objectAt(1).get('name'), "Michael"); - done(); - }); + done(); }); }); - - test("load() - only a single find is triggered", function(assert) { - var done = assert.async(); - - var deferred = Ember.RSVP.defer(); - var count = 0; - - env.adapter.findMany = function(store, type, id) { - count++; - assert.equal(count, 1); - - return deferred.promise; - }; - - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } +}); + +test("load() fetches link when remoteType is link", function(assert) { + var done = assert.async(); + + env.adapter.findHasMany = function(store, snapshot, link) { + assert.equal(link, "/families/1/persons"); + + return Ember.RSVP.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); + }; + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + links: { related: '/families/1/persons' } } } - }); + } }); + }); - var personsReference = family.hasMany('persons'); + var personsReference = family.hasMany('persons'); + assert.equal(personsReference.remoteType(), "link"); - run(function() { - personsReference.load(); - personsReference.load().then(function(records) { - assert.equal(get(records, 'length'), 2); - }); - }); + run(function() { + personsReference.load().then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito"); + assert.equal(records.objectAt(1).get('name'), "Michael"); - run(function() { - deferred.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); + done(); }); + }); +}); + +test("load() - only a single find is triggered", function(assert) { + var done = assert.async(); + + var deferred = Ember.RSVP.defer(); + var count = 0; + + env.adapter.findMany = function(store, type, id) { + count++; + assert.equal(count, 1); + + return deferred.promise; + }; + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] + } + } + } + }); + }); - run(function() { - personsReference.load().then(function(records) { - assert.equal(get(records, 'length'), 2); + var personsReference = family.hasMany('persons'); - done(); - }); + run(function() { + personsReference.load(); + personsReference.load().then(function(records) { + assert.equal(get(records, 'length'), 2); }); }); - test("reload()", function(assert) { - var done = assert.async(); + run(function() { + deferred.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); + }); - env.adapter.findMany = function(store, type, id) { - return Ember.RSVP.resolve([ - { id: 1, name: "Vito Coreleone" }, - { id: 2, name: "Michael Coreleone" } - ]); - }; + run(function() { + personsReference.load().then(function(records) { + assert.equal(get(records, 'length'), 2); - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } + done(); + }); + }); +}); + +test("reload()", function(assert) { + var done = assert.async(); + + env.adapter.findMany = function(store, type, id) { + return Ember.RSVP.resolve([ + { id: 1, name: "Vito Coreleone" }, + { id: 2, name: "Michael Coreleone" } + ]); + }; + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] } } - }); - env.store.push({ data: { type: 'person', id: 1, attributes: { name: "Vito" } } }); - env.store.push({ data: { type: 'person', id: 2, attributes: { name: "Michael" } } }); + } }); + env.store.push({ data: { type: 'person', id: 1, attributes: { name: "Vito" } } }); + env.store.push({ data: { type: 'person', id: 2, attributes: { name: "Michael" } } }); + }); - var personsReference = family.hasMany('persons'); + var personsReference = family.hasMany('persons'); - run(function() { - personsReference.reload().then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); - assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito Coreleone"); - assert.equal(records.objectAt(1).get('name'), "Michael Coreleone"); + run(function() { + personsReference.reload().then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito Coreleone"); + assert.equal(records.objectAt(1).get('name'), "Michael Coreleone"); - done(); - }); + done(); }); }); +}); - test("reload() fetches link when remoteType is link", function(assert) { - var done = assert.async(); - - var count = 0; - env.adapter.findHasMany = function(store, snapshot, link) { - count++; - assert.equal(link, "/families/1/persons"); - - if (count === 1) { - return Ember.RSVP.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); - } else { - return Ember.RSVP.resolve([ - { id: 1, name: "Vito Coreleone" }, - { id: 2, name: "Michael Coreleone" } - ]); - } - }; +test("reload() fetches link when remoteType is link", function(assert) { + var done = assert.async(); - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - links: { related: '/families/1/persons' } - } + var count = 0; + env.adapter.findHasMany = function(store, snapshot, link) { + count++; + assert.equal(link, "/families/1/persons"); + + if (count === 1) { + return Ember.RSVP.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); + } else { + return Ember.RSVP.resolve([ + { id: 1, name: "Vito Coreleone" }, + { id: 2, name: "Michael Coreleone" } + ]); + } + }; + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + links: { related: '/families/1/persons' } } } - }); + } }); + }); - var personsReference = family.hasMany('persons'); - assert.equal(personsReference.remoteType(), "link"); - - run(function() { - personsReference.load().then(function() { - return personsReference.reload(); - }).then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); - assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito Coreleone"); - assert.equal(records.objectAt(1).get('name'), "Michael Coreleone"); - - done(); - }); + var personsReference = family.hasMany('persons'); + assert.equal(personsReference.remoteType(), "link"); + + run(function() { + personsReference.load().then(function() { + return personsReference.reload(); + }).then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito Coreleone"); + assert.equal(records.objectAt(1).get('name'), "Michael Coreleone"); + + done(); }); }); - -} +}); diff --git a/tests/integration/references/record-test.js b/tests/integration/references/record-test.js index 67983616b66..7f66074d8f4 100644 --- a/tests/integration/references/record-test.js +++ b/tests/integration/references/record-test.js @@ -2,236 +2,231 @@ import DS from 'ember-data'; import Ember from 'ember'; import setupStore from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; -import isEnabled from 'ember-data/-private/features'; -if (isEnabled("ds-references")) { +var get = Ember.get; +var run = Ember.run; +var env, Person; - var get = Ember.get; - var run = Ember.run; - var env, Person; - - module("integration/references/record", { - beforeEach() { - Person = DS.Model.extend({ - name: DS.attr() - }); - - env = setupStore({ - person: Person - }); - }, - - afterEach() { - run(env.store, 'unloadAll'); - run(env.container, 'destroy'); - } - }); - - test("a RecordReference can be retrieved via store.getReference(type, id)", function(assert) { - var recordReference = env.store.getReference('person', 1); - - assert.equal(recordReference.remoteType(), 'identity'); - assert.equal(recordReference.type, 'person'); - assert.equal(recordReference.id(), 1); - }); - - test("push(object)", function(assert) { - var done = assert.async(); - - var push; - var recordReference = env.store.getReference('person', 1); +module("integration/references/record", { + beforeEach() { + Person = DS.Model.extend({ + name: DS.attr() + }); - run(function() { - push = recordReference.push({ - data: { - type: 'person', - id: 1, - attributes: { - name: "le name" - } + env = setupStore({ + person: Person + }); + }, + + afterEach() { + run(env.store, 'unloadAll'); + run(env.container, 'destroy'); + } +}); + +test("a RecordReference can be retrieved via store.getReference(type, id)", function(assert) { + var recordReference = env.store.getReference('person', 1); + + assert.equal(recordReference.remoteType(), 'identity'); + assert.equal(recordReference.type, 'person'); + assert.equal(recordReference.id(), 1); +}); + +test("push(object)", function(assert) { + var done = assert.async(); + + var push; + var recordReference = env.store.getReference('person', 1); + + run(function() { + push = recordReference.push({ + data: { + type: 'person', + id: 1, + attributes: { + name: "le name" } - }); + } }); + }); - assert.ok(push.then, 'RecordReference.push returns a promise'); + assert.ok(push.then, 'RecordReference.push returns a promise'); - run(function() { - push.then(function(record) { - assert.ok(record instanceof Person, "push resolves with the record"); - assert.equal(get(record, 'name'), "le name"); + run(function() { + push.then(function(record) { + assert.ok(record instanceof Person, "push resolves with the record"); + assert.equal(get(record, 'name'), "le name"); - done(); - }); + done(); }); }); +}); - test("push(promise)", function(assert) { - var done = assert.async(); +test("push(promise)", function(assert) { + var done = assert.async(); - var push; - var deferred = Ember.RSVP.defer(); - var recordReference = env.store.getReference('person', 1); + var push; + var deferred = Ember.RSVP.defer(); + var recordReference = env.store.getReference('person', 1); - run(function() { - push = recordReference.push(deferred.promise); - }); + run(function() { + push = recordReference.push(deferred.promise); + }); - assert.ok(push.then, 'RecordReference.push returns a promise'); + assert.ok(push.then, 'RecordReference.push returns a promise'); - run(function() { - deferred.resolve({ - data: { - type: 'person', - id: 1, - attributes: { - name: "le name" - } + run(function() { + deferred.resolve({ + data: { + type: 'person', + id: 1, + attributes: { + name: "le name" } - }); + } }); + }); - run(function() { - push.then(function(record) { - assert.ok(record instanceof Person, "push resolves with the record"); - assert.equal(get(record, 'name'), "le name", "name is updated"); + run(function() { + push.then(function(record) { + assert.ok(record instanceof Person, "push resolves with the record"); + assert.equal(get(record, 'name'), "le name", "name is updated"); - done(); - }); + done(); }); }); - - test("value() returns null when not yet loaded", function(assert) { - var recordReference = env.store.getReference('person', 1); - assert.equal(recordReference.value(), null); - }); - - test("value() returns the record when loaded", function(assert) { - var person; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1 - } - }); +}); + +test("value() returns null when not yet loaded", function(assert) { + var recordReference = env.store.getReference('person', 1); + assert.equal(recordReference.value(), null); +}); + +test("value() returns the record when loaded", function(assert) { + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1 + } }); - - var recordReference = env.store.getReference('person', 1); - assert.equal(recordReference.value(), person); }); - test("load() fetches the record", function(assert) { - var done = assert.async(); + var recordReference = env.store.getReference('person', 1); + assert.equal(recordReference.value(), person); +}); + +test("load() fetches the record", function(assert) { + var done = assert.async(); - env.adapter.findRecord = function(store, type, id) { - return Ember.RSVP.resolve({ - id: 1, name: "Vito" - }); - }; + env.adapter.findRecord = function(store, type, id) { + return Ember.RSVP.resolve({ + id: 1, name: "Vito" + }); + }; - var recordReference = env.store.getReference('person', 1); + var recordReference = env.store.getReference('person', 1); - run(function() { - recordReference.load().then(function(record) { - assert.equal(get(record, 'name'), "Vito"); - done(); - }); + run(function() { + recordReference.load().then(function(record) { + assert.equal(get(record, 'name'), "Vito"); + done(); }); }); +}); - test("load() only a single find is triggered", function(assert) { - var done = assert.async(); +test("load() only a single find is triggered", function(assert) { + var done = assert.async(); - var deferred = Ember.RSVP.defer(); - var count = 0; + var deferred = Ember.RSVP.defer(); + var count = 0; - env.adapter.shouldReloadRecord = function() { return false; }; - env.adapter.shouldBackgroundReloadRecord = function() { return false; }; - env.adapter.findRecord = function(store, type, id) { - count++; - assert.equal(count, 1); + env.adapter.shouldReloadRecord = function() { return false; }; + env.adapter.shouldBackgroundReloadRecord = function() { return false; }; + env.adapter.findRecord = function(store, type, id) { + count++; + assert.equal(count, 1); - return deferred.promise; - }; + return deferred.promise; + }; - var recordReference = env.store.getReference('person', 1); + var recordReference = env.store.getReference('person', 1); - run(function() { - recordReference.load(); - recordReference.load().then(function(record) { - assert.equal(get(record, 'name'), "Vito"); - }); + run(function() { + recordReference.load(); + recordReference.load().then(function(record) { + assert.equal(get(record, 'name'), "Vito"); }); + }); - run(function() { - deferred.resolve({ - id: 1, name: "Vito" - }); + run(function() { + deferred.resolve({ + id: 1, name: "Vito" }); + }); - run(function() { - recordReference.load().then(function(record) { - assert.equal(get(record, 'name'), "Vito"); + run(function() { + recordReference.load().then(function(record) { + assert.equal(get(record, 'name'), "Vito"); - done(); - }); + done(); }); }); +}); - test("reload() loads the record if not yet loaded", function(assert) { - var done = assert.async(); +test("reload() loads the record if not yet loaded", function(assert) { + var done = assert.async(); - var count = 0; - env.adapter.findRecord = function(store, type, id) { - count++; - assert.equal(count, 1); + var count = 0; + env.adapter.findRecord = function(store, type, id) { + count++; + assert.equal(count, 1); - return Ember.RSVP.resolve({ - id: 1, name: "Vito Coreleone" - }); - }; + return Ember.RSVP.resolve({ + id: 1, name: "Vito Coreleone" + }); + }; - var recordReference = env.store.getReference('person', 1); + var recordReference = env.store.getReference('person', 1); - run(function() { - recordReference.reload().then(function(record) { - assert.equal(get(record, 'name'), "Vito Coreleone"); + run(function() { + recordReference.reload().then(function(record) { + assert.equal(get(record, 'name'), "Vito Coreleone"); - done(); - }); + done(); }); }); +}); + +test("reload() fetches the record", function(assert) { + var done = assert.async(); - test("reload() fetches the record", function(assert) { - var done = assert.async(); - - env.adapter.findRecord = function(store, type, id) { - return Ember.RSVP.resolve({ - id: 1, name: "Vito Coreleone" - }); - }; - - run(function() { - env.store.push({ - data: { - type: 'person', - id: 1, - attributes: { - name: 'Vito' - } + env.adapter.findRecord = function(store, type, id) { + return Ember.RSVP.resolve({ + id: 1, name: "Vito Coreleone" + }); + }; + + run(function() { + env.store.push({ + data: { + type: 'person', + id: 1, + attributes: { + name: 'Vito' } - }); + } }); + }); - var recordReference = env.store.getReference('person', 1); + var recordReference = env.store.getReference('person', 1); - run(function() { - recordReference.reload().then(function(record) { - assert.equal(get(record, 'name'), "Vito Coreleone"); + run(function() { + recordReference.reload().then(function(record) { + assert.equal(get(record, 'name'), "Vito Coreleone"); - done(); - }); + done(); }); }); - -} +}); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index c016e7f834f..9e8c0d0f46b 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1,6 +1,5 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; -import isEnabled from 'ember-data/-private/features'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; @@ -1109,136 +1108,132 @@ test("Updated related link should take precedence over local data", function(ass }); }); -if (isEnabled('ds-references')) { +test("A belongsTo relationship can be reloaded using the reference if it was fetched via link", function(assert) { + var done = assert.async(); - test("A belongsTo relationship can be reloaded using the reference if it was fetched via link", function(assert) { - var done = assert.async(); + Chapter.reopen({ + book: DS.belongsTo({ async: true }) + }); - Chapter.reopen({ - book: DS.belongsTo({ async: true }) + env.adapter.findRecord = function() { + return Ember.RSVP.resolve({ + id: 1, + links: { book: '/books/1' } }); + }; - env.adapter.findRecord = function() { - return Ember.RSVP.resolve({ - id: 1, - links: { book: '/books/1' } - }); - }; - - env.adapter.findBelongsTo = function() { - return Ember.RSVP.resolve({ id: 1, name: "book title" }); - }; + env.adapter.findBelongsTo = function() { + return Ember.RSVP.resolve({ id: 1, name: "book title" }); + }; - run(function() { - var chapter; - store.findRecord('chapter', 1).then(function(_chapter) { - chapter = _chapter; + run(function() { + var chapter; + store.findRecord('chapter', 1).then(function(_chapter) { + chapter = _chapter; - return chapter.get('book'); - }).then(function(book) { - assert.equal(book.get('name'), "book title"); + return chapter.get('book'); + }).then(function(book) { + assert.equal(book.get('name'), "book title"); - env.adapter.findBelongsTo = function() { - return Ember.RSVP.resolve({ id: 1, name: "updated book title" }); - }; + env.adapter.findBelongsTo = function() { + return Ember.RSVP.resolve({ id: 1, name: "updated book title" }); + }; - return chapter.belongsTo('book').reload(); - }).then(function(book) { - assert.equal(book.get('name'), "updated book title"); + return chapter.belongsTo('book').reload(); + }).then(function(book) { + assert.equal(book.get('name'), "updated book title"); - done(); - }); + done(); }); }); +}); - test("A sync belongsTo relationship can be reloaded using a reference if it was fetched via id", function(assert) { - var done = assert.async(); +test("A sync belongsTo relationship can be reloaded using a reference if it was fetched via id", function(assert) { + var done = assert.async(); - Chapter.reopen({ - book: DS.belongsTo() - }); + Chapter.reopen({ + book: DS.belongsTo() + }); - var chapter; - run(function() { - chapter = env.store.push({ - data: { - type: 'chapter', - id: 1, - relationships: { - book: { - data: { type: 'book', id: 1 } - } + var chapter; + run(function() { + chapter = env.store.push({ + data: { + type: 'chapter', + id: 1, + relationships: { + book: { + data: { type: 'book', id: 1 } } } - }); - env.store.push({ - data: { - type: 'book', - id: 1, - attributes: { - name: "book title" - } + } + }); + env.store.push({ + data: { + type: 'book', + id: 1, + attributes: { + name: "book title" } - }); + } }); + }); - env.adapter.findRecord = function() { - return Ember.RSVP.resolve({ id: 1, name: "updated book title" }); - }; + env.adapter.findRecord = function() { + return Ember.RSVP.resolve({ id: 1, name: "updated book title" }); + }; - run(function() { - var book = chapter.get('book'); - assert.equal(book.get('name'), "book title"); + run(function() { + var book = chapter.get('book'); + assert.equal(book.get('name'), "book title"); - chapter.belongsTo('book').reload().then(function(book) { - assert.equal(book.get('name'), "updated book title"); + chapter.belongsTo('book').reload().then(function(book) { + assert.equal(book.get('name'), "updated book title"); - done(); - }); + done(); }); }); +}); - test("A belongsTo relationship can be reloaded using a reference if it was fetched via id", function(assert) { - var done = assert.async(); +test("A belongsTo relationship can be reloaded using a reference if it was fetched via id", function(assert) { + var done = assert.async(); - Chapter.reopen({ - book: DS.belongsTo({ async: true }) - }); + Chapter.reopen({ + book: DS.belongsTo({ async: true }) + }); - var chapter; - run(function() { - chapter = env.store.push({ - data: { - type: 'chapter', - id: 1, - relationships: { - book: { - data: { type: 'book', id: 1 } - } + var chapter; + run(function() { + chapter = env.store.push({ + data: { + type: 'chapter', + id: 1, + relationships: { + book: { + data: { type: 'book', id: 1 } } } - }); + } }); + }); - env.adapter.findRecord = function() { - return Ember.RSVP.resolve({ id: 1, name: "book title" }); - }; + env.adapter.findRecord = function() { + return Ember.RSVP.resolve({ id: 1, name: "book title" }); + }; - run(function() { - chapter.get('book').then(function(book) { - assert.equal(book.get('name'), "book title"); + run(function() { + chapter.get('book').then(function(book) { + assert.equal(book.get('name'), "book title"); - env.adapter.findRecord = function() { - return Ember.RSVP.resolve({ id: 1, name: "updated book title" }); - }; + env.adapter.findRecord = function() { + return Ember.RSVP.resolve({ id: 1, name: "updated book title" }); + }; - return chapter.belongsTo('book').reload(); - }).then(function(book) { - assert.equal(book.get('name'), "updated book title"); + return chapter.belongsTo('book').reload(); + }).then(function(book) { + assert.equal(book.get('name'), "updated book title"); - done(); - }); + done(); }); }); - -} +}); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index c476e39718a..a79cebb57be 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -429,32 +429,6 @@ testInDebug("Calling attr() throws a warning", function(assert) { }); }); -if (!isEnabled('ds-references')) { - testInDebug("Calling belongsTo() throws a warning", function(assert) { - assert.expect(1); - - run(function() { - var person = store.createRecord('person', { id: 1, name: 'TomHuda' }); - - assert.throws(function() { - person.belongsTo(); - }, /The `belongsTo` method is not available on DS.Model, a DS.Snapshot was probably expected/, "belongsTo() throws a warning"); - }); - }); - - testInDebug("Calling hasMany() throws a warning", function(assert) { - assert.expect(1); - - run(function() { - var person = store.createRecord('person', { id: 1, name: 'TomHuda' }); - - assert.throws(function() { - person.hasMany(); - }, /The `hasMany` method is not available on DS.Model, a DS.Snapshot was probably expected/, "hasMany() throws a warning"); - }); - }); -} - test("supports pushedData in root.deleted.uncommitted", function(assert) { var record; var hash = { From 7d137c3560049adb57f3984aac21331a9cb5704a Mon Sep 17 00:00:00 2001 From: pangratz Date: Fri, 15 Apr 2016 21:46:41 +0200 Subject: [PATCH 1505/2527] [DOC beta] Overhaul documentation for reload / background reload --- addon/-private/system/store.js | 181 +++++++++++++++++++++++++++++---- addon/adapter.js | 103 +++++++++++++++++-- 2 files changed, 259 insertions(+), 25 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 6b1c068c69d..cefef181064 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -417,14 +417,12 @@ Store = Service.extend({ /** This method returns a record for a given type and id combination. - The `findRecord` method will always return a **promise** that will be - resolved with the record. If the record was already in the store, - the promise will be resolved immediately. Otherwise, the store - will ask the adapter's `find` method to find the necessary data. - The `findRecord` method will always resolve its promise with the same object for a given type and `id`. + The `findRecord` method will always return a **promise** that will be + resolved with the record. + Example ```app/routes/post.js @@ -437,20 +435,89 @@ Store = Service.extend({ }); ``` - If you would like to force the record to reload, instead of - loading it from the cache when present you can set `reload: true` - in the options object for `findRecord`. + If the record is not yet available, the store will ask the adapter's `find` + method to find the necessary data. If the record is already present in the + store, it depends on the reload behavior _when_ the returned promise + resolves. - ```app/routes/post/edit.js - import Ember from 'ember'; + The reload behavior is configured either via the passed `options` hash or + the result of the adapter's `shouldReloadRecord`. - export default Ember.Route.extend({ - model: function(params) { - return this.store.findRecord('post', params.post_id, { reload: true }); + If `{ reload: true }` is passed or `adapter.shouldReloadRecord` evaluates + to `true`, then the returned promise resolves once the adapter returns + data, regardless if the requested record is already in the store: + + ```js + store.push({ + data: { + id: 1, + type: 'post', + revision: 1 + } + }); + + // adapter#findRecord resolves with + // [ + // { + // id: 1, + // type: 'post', + // revision: 2 + // } + // ] + store.findRecord('post', 1, { reload: true }).then(function(post) { + post.get("revision"); // 2 + }); + ``` + + If no reload is indicated via the abovementioned ways, then the promise + immediately resolves with the cached version in the store. + + Optionally, if `adapter.shouldBackgroundReloadRecord` evaluates to `true`, + then a background reload is started, which updates the records' data, once + it is available: + + ```js + // app/adapters/post.js + import ApplicationAdapter from "./application"; + + export default ApplicationAdapter.extend({ + shouldReloadRecord(store, snapshot) { + return false; + }, + + shouldBackgroundReloadRecord(store, snapshot) { + return true; + } + }); + + // ... + + store.push({ + data: { + id: 1, + type: 'post', + revision: 1 } }); + + var blogPost = store.findRecord('post', 1).then(function(post) { + post.get('revision'); // 1 + }); + + // later, once adapter#findRecord resolved with + // [ + // { + // id: 1, + // type: 'post', + // revision: 2 + // } + // ] + + blogPost.get('revision'); // 2 ``` + See [peekRecord](#method_peekRecord) to get the cached version of a record. + @method findRecord @param {String} modelName @param {(String|Integer)} id @@ -965,11 +1032,10 @@ Store = Service.extend({ }, /** - `findAll` ask the adapter's `findAll` method to find the records - for the given type, and return a promise that will be resolved - once the server returns the values. The promise will resolve into - all records of this type present in the store, even if the server - only returns a subset of them. + `findAll` ask the adapter's `findAll` method to find the records for the + given type, and returns a promise which will resolve with all records of + this type present in the store, even if the adapter only returns a subset + of them. ```app/routes/authors.js import Ember from 'ember'; @@ -981,6 +1047,85 @@ Store = Service.extend({ }); ``` + _When_ the returned promise resolves depends on the reload behavior, + configured via the passed `options` hash and the result of the adapter's + `shouldReloadAll` method. + + If `{ reload: true }` is passed or `adapter.shouldReloadAll` evaluates to + `true`, then the returned promise resolves once the adapter returns data, + regardless if there are already records in the store: + + ```js + store.push({ + data: { + id: 'first', + type: 'author' + } + }); + + // adapter#findAll resolves with + // [ + // { + // id: 'second', + // type: 'author' + // } + // ] + store.findAll('author', { reload: true }).then(function(authors) { + authors.getEach("id"); // ['first', 'second'] + }); + ``` + + If no reload is indicated via the abovementioned ways, then the promise + immediately resolves with all the records currently loaded in the store. + Optionally, if `adapter.shouldBackgroundReloadAll` evaluates to `true`, + then a background reload is started. Once this resolves, the array with + which the promise resolves, is updated automatically so it contains all the + records in the store: + + ```js + // app/adapters/application.js + export default DS.Adapter.extend({ + shouldReloadAll(store, snapshotsArray) { + return false; + }, + + shouldBackgroundReloadAll(store, snapshotsArray) { + return true; + } + }); + + // ... + + store.push({ + data: { + id: 'first', + type: 'author' + } + }); + + var allAuthors; + store.findAll('author').then(function(authors) { + authors.getEach('id'); // ['first'] + + allAuthors = authors; + }); + + // later, once adapter#findAll resolved with + // [ + // { + // id: 'second', + // type: 'author' + // } + // ] + + allAuthors.getEach('id'); // ['first', 'second'] + ``` + + See [peekAll](#method_peekAll) to get an array of current records in the + store, without waiting until a reload is finished. + + See [query](#method_query) to only get a subset of records from the server. + @method findAll @param {String} modelName @param {Object} options diff --git a/addon/adapter.js b/addon/adapter.js index e555e8e830e..ddc0ff27abf 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -465,10 +465,34 @@ export default Ember.Object.extend({ reload a record from the adapter when a record is requested by `store.findRecord`. - If this method returns true, the store will re-fetch a record from - the adapter. If this method returns false, the store will resolve + If this method returns `true`, the store will re-fetch a record from + the adapter. If this method returns `false`, the store will resolve immediately using the cached record. + For example, if you are building an events ticketing system, in which users + can only reserve tickets for 20 minutes at a time, and want to ensure that + in each route you have data that is no more than 20 minutes old you could + write: + + ```javascript + shouldReloadRecord: function(store, ticketSnapshot) { + var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt')).minutes(); + if (timeDiff > 20) { + return true; + } else { + return false; + } + } + ``` + + This method would ensure that whenever you do `store.findRecord('ticket', + id)` you will always get a ticket that is no more than 20 minutes old. In + case the cached version is more than 20 minutes old, `findRecord` will not + resolve until you fetched the latest version. + + By default this hook returns `false`, as most UIs should not block user + interactions while waiting on data update. + @method shouldReloadRecord @param {DS.Store} store @param {DS.Snapshot} snapshot @@ -483,9 +507,38 @@ export default Ember.Object.extend({ reload all records from the adapter when records are requested by `store.findAll`. - If this method returns true, the store will re-fetch all records from - the adapter. If this method returns false, the store will resolve - immediately using the cached record. + If this method returns `true`, the store will re-fetch all records from + the adapter. If this method returns `false`, the store will resolve + immediately using the cached records. + + For example, if you are building an events ticketing system, in which users + can only reserve tickets for 20 minutes at a time, and want to ensure that + in each route you have data that is no more than 20 minutes old you could + write: + + ```javascript + shouldReloadAll: function(store, snapshotArray) { + var snapshots = snapshotArray.snapshots(); + + return snapshots.any(function(ticketSnapshot) { + var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt')).minutes(); + if (timeDiff > 20) { + return true; + } else { + return false; + } + }); + } + ``` + + This method would ensure that whenever you do `store.findAll('ticket')` you + will always get a list of tickets that are no more than 20 minutes old. In + case a cached version is more than 20 minutes old, `findAll` will not + resolve until you fetched the latest versions. + + By default this methods returns `true` if the passed `snapshotRecordArray` + is empty (meaning that there are no records locally available yet), + otherwise it returns `false`. @method shouldReloadAll @param {DS.Store} store @@ -504,9 +557,27 @@ export default Ember.Object.extend({ This method is *only* checked by the store when the store is returning a cached record. - If this method returns true the store will re-fetch a record from + If this method returns `true` the store will re-fetch a record from the adapter. + For example, if you do not want to fetch complex data over a mobile + connection, or if the network is down, you can implement + `shouldBackgroundReloadRecord` as follows: + + ```javascript + shouldBackgroundReloadRecord: function(store, snapshot) { + var connection = window.navigator.connection; + if (connection === 'cellular' || connection === 'none') { + return false; + } else { + return true; + } + } + ``` + + By default this hook returns `true` so the data for the record is updated + in the background. + @method shouldBackgroundReloadRecord @param {DS.Store} store @param {DS.Snapshot} snapshot @@ -524,9 +595,27 @@ export default Ember.Object.extend({ This method is *only* checked by the store when the store is returning a cached record array. - If this method returns true the store will re-fetch all records + If this method returns `true` the store will re-fetch all records from the adapter. + For example, if you do not want to fetch complex data over a mobile + connection, or if the network is down, you can implement + `shouldBackgroundReloadAll` as follows: + + ```javascript + shouldBackgroundReloadAll: function(store, snapshotArray) { + var connection = window.navigator.connection; + if (connection === 'cellular' || connection === 'none') { + return false; + } else { + return true; + } + } + ``` + + By default this method returns `true`, indicating that a background reload + should always be triggered. + @method shouldBackgroundReloadAll @param {DS.Store} store @param {DS.SnapshotRecordArray} snapshotRecordArray From f5df24677fb7a9ca265d636f38c6e6d959f936f6 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 21 Apr 2016 16:16:17 +0200 Subject: [PATCH 1506/2527] [CLEANUP ds-transform-pass-options] --- FEATURES.md | 7 -- addon/-private/transforms/boolean.js | 16 ++--- addon/attr.js | 60 ++++++++-------- addon/serializers/json.js | 21 ++---- addon/transform.js | 6 +- config/features.json | 1 - .../serializers/json-serializer-test.js | 70 +++++++++---------- tests/unit/model-test.js | 2 +- tests/unit/transform/boolean-test.js | 4 +- 9 files changed, 77 insertions(+), 110 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index a3904ed37eb..8fcdc171391 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -15,19 +15,12 @@ entry in `config/features.json`. Allow `null`/`undefined` values for `boolean` attributes via `DS.attr('boolean', { allowNull: true })` - Note that this feature only works when `ds-transform-pass-options` is enabled too. - - `ds-improved-ajax` This feature allows to customize how a request is formed by overwriting `methodForRequest`, `urlForRequest`, `headersForRequest` and `bodyForRequest` in the `DS.RESTAdapter`. -- `ds-transform-pass-options` - - Pass options specified for a `DS.attr` to the `DS.Tranform`'s `serialize` and - `deserialize` methods (described in [RFC 1](https://github.com/emberjs/rfcs/pull/1)) - - `ds-pushpayload-return` Enables `pushPayload` to return the model(s) that are created or diff --git a/addon/-private/transforms/boolean.js b/addon/-private/transforms/boolean.js index 9aabfaa6683..e9724eaf1ed 100644 --- a/addon/-private/transforms/boolean.js +++ b/addon/-private/transforms/boolean.js @@ -30,11 +30,9 @@ export default Transform.extend({ deserialize(serialized, options) { var type = typeof serialized; - if (isEnabled('ds-transform-pass-options')) { - if (isEnabled('ds-boolean-transform-allow-null')) { - if (isNone(serialized) && options.allowNull === true) { - return null; - } + if (isEnabled('ds-boolean-transform-allow-null')) { + if (isNone(serialized) && options.allowNull === true) { + return null; } } @@ -50,11 +48,9 @@ export default Transform.extend({ }, serialize(deserialized, options) { - if (isEnabled('ds-transform-pass-options')) { - if (isEnabled('ds-boolean-transform-allow-null')) { - if (isNone(deserialized) && options.allowNull === true) { - return null; - } + if (isEnabled('ds-boolean-transform-allow-null')) { + if (isNone(deserialized) && options.allowNull === true) { + return null; } } diff --git a/addon/attr.js b/addon/attr.js index 87a95d3615e..673fb7ee429 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -78,6 +78,34 @@ function getValue(record, key) { }); ``` + The `options` hash is passed as second argument to a transforms' + `serialize` and `deserialize` method. This allows to configure a + transformation and adapt the corresponding value, based on the config: + + ```app/models/post.js + export default DS.Model.extend({ + text: DS.attr('text', { + uppercase: true + }) + }); + ``` + + ```app/transforms/text.js + export default DS.Transform.extend({ + serialize: function(value, options) { + if (options.uppercase) { + return value.toUpperCase(); + } + + return value; + }, + + deserialize: function(value) { + return value; + } + }) + ``` + @namespace @method attr @for DS @@ -130,35 +158,3 @@ export default function attr(type, options) { } }).meta(meta); } - -// TODO add to documentation of `attr` function above, once this feature is added -// /** -// * The `options` hash is passed as second argument to a transforms' -// * `serialize` and `deserialize` method. This allows to configure a -// * transformation and adapt the corresponding value, based on the config: -// * -// * ```app/models/post.js -// * export default DS.Model.extend({ -// * text: DS.attr('text', { -// * uppercase: true -// * }) -// * }); -// * ``` -// * -// * ```app/transforms/text.js -// * export default DS.Transform.extend({ -// * serialize: function(value, options) { -// * if (options.uppercase) { -// * return value.toUpperCase(); -// * } -// * -// * return value; -// * }, -// * -// * deserialize: function(value) { -// * return value; -// * } -// * }) -// * ``` -// * -// */ diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 37fdf3da119..caee949ba49 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -11,8 +11,6 @@ import { import { errorsArrayToHash } from "ember-data/adapters/errors"; -import isEnabled from 'ember-data/-private/features'; - var get = Ember.get; var isNone = Ember.isNone; var assign = Ember.assign || Ember.merge; @@ -187,21 +185,14 @@ export default Serializer.extend({ @return {Object} data The transformed data object */ applyTransforms(typeClass, data) { - let attributes; - if (isEnabled('ds-transform-pass-options')) { - attributes = get(typeClass, 'attributes'); - } + let attributes = get(typeClass, 'attributes'); typeClass.eachTransformedAttribute((key, typeClass) => { if (!(key in data)) { return; } var transform = this.transformFor(typeClass); - if (isEnabled('ds-transform-pass-options')) { - var transformMeta = attributes.get(key); - data[key] = transform.deserialize(data[key], transformMeta.options); - } else { - data[key] = transform.deserialize(data[key]); - } + var transformMeta = attributes.get(key); + data[key] = transform.deserialize(data[key], transformMeta.options); }); return data; @@ -1089,11 +1080,7 @@ export default Serializer.extend({ var value = snapshot.attr(key); if (type) { var transform = this.transformFor(type); - if (isEnabled('ds-transform-pass-options')) { - value = transform.serialize(value, attribute.options); - } else { - value = transform.serialize(value); - } + value = transform.serialize(value, attribute.options); } // if provided, use the mapping provided by `attrs` in diff --git a/addon/transform.js b/addon/transform.js index e9c45f2104a..232c79e5f72 100644 --- a/addon/transform.js +++ b/addon/transform.js @@ -45,13 +45,14 @@ export default Ember.Object.extend({ Example ```javascript - serialize: function(deserialized) { + serialize: function(deserialized, options) { return Ember.isEmpty(deserialized) ? null : Number(deserialized); } ``` @method serialize @param deserialized The deserialized value + @param options hash of options passed to `DS.attr` @return The serialized value */ serialize: null, @@ -63,13 +64,14 @@ export default Ember.Object.extend({ Example ```javascript - deserialize: function(serialized) { + deserialize: function(serialized, options) { return empty(serialized) ? null : Number(serialized); } ``` @method deserialize @param serialized The serialized value + @param options hash of options passed to `DS.attr` @return The deserialized value */ deserialize: null diff --git a/config/features.json b/config/features.json index 9ae9b4b894a..1750dc2d709 100644 --- a/config/features.json +++ b/config/features.json @@ -1,7 +1,6 @@ { "ds-boolean-transform-allow-null": null, "ds-improved-ajax": null, - "ds-transform-pass-options": true, "ds-pushpayload-return": null, "ds-extended-errors": null, "ds-links-in-record-array": null diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 64dcd01e07d..521828b9dac 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -5,8 +5,6 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; - var Post, post, Comment, comment, Favorite, favorite, env; var run = Ember.run; @@ -907,52 +905,48 @@ test('normalizeResponse ignores unmapped attributes', function(assert) { assert.equal(post.data.attributes.title, "Rails is omakase"); }); -if (isEnabled('ds-transform-pass-options')) { - - test('options are passed to transform for serialization', function(assert) { - assert.expect(1); - - env.registry.register('transform:custom', DS.Transform.extend({ - serialize: function(deserialized, options) { - assert.deepEqual(options, { custom: 'config' }); - } - })); +test('options are passed to transform for serialization', function(assert) { + assert.expect(1); - Post.reopen({ - custom: DS.attr('custom', { - custom: 'config' - }) - }); + env.registry.register('transform:custom', DS.Transform.extend({ + serialize: function(deserialized, options) { + assert.deepEqual(options, { custom: 'config' }); + } + })); - var post; - run(function() { - post = env.store.createRecord('post', { custom: 'value' }); - }); + Post.reopen({ + custom: DS.attr('custom', { + custom: 'config' + }) + }); - env.serializer.serialize(post._createSnapshot()); + var post; + run(function() { + post = env.store.createRecord('post', { custom: 'value' }); }); - test('options are passed to transform for normalization', function(assert) { - assert.expect(1); + env.serializer.serialize(post._createSnapshot()); +}); - env.registry.register('transform:custom', DS.Transform.extend({ - deserialize: function(serialized, options) { - assert.deepEqual(options, { custom: 'config' }); - } - })); +test('options are passed to transform for normalization', function(assert) { + assert.expect(1); - Post.reopen({ - custom: DS.attr('custom', { - custom: 'config' - }) - }); + env.registry.register('transform:custom', DS.Transform.extend({ + deserialize: function(serialized, options) { + assert.deepEqual(options, { custom: 'config' }); + } + })); - env.serializer.normalize(Post, { - custom: 'value' - }); + Post.reopen({ + custom: DS.attr('custom', { + custom: 'config' + }) }); -} + env.serializer.normalize(Post, { + custom: 'value' + }); +}); test('Serializer should respect the attrs hash in links', function(assert) { env.registry.register("serializer:post", DS.JSONSerializer.extend({ diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index a79cebb57be..67ed420f3ba 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -910,7 +910,7 @@ test("a DS.Model can describe Boolean attributes", function(assert) { assert.converts('boolean', 1, true); assert.converts('boolean', 0, false); - if (isEnabled('ds-transform-pass-options') && isEnabled('ds-boolean-transform-allow-null')) { + if (isEnabled('ds-boolean-transform-allow-null')) { assert.converts('boolean', null, null, { allowNull: true }); assert.converts('boolean', undefined, null, { allowNull: true }); diff --git a/tests/unit/transform/boolean-test.js b/tests/unit/transform/boolean-test.js index aa257be005c..32c6a69d057 100644 --- a/tests/unit/transform/boolean-test.js +++ b/tests/unit/transform/boolean-test.js @@ -8,7 +8,7 @@ module("unit/transform - DS.BooleanTransform"); test("#serialize", function(assert) { var transform = new DS.BooleanTransform(); - if (isEnabled('ds-transform-pass-options') && isEnabled('ds-boolean-transform-allow-null')) { + if (isEnabled('ds-boolean-transform-allow-null')) { assert.equal(transform.serialize(null, { allowNull: true }), null); assert.equal(transform.serialize(undefined, { allowNull: true }), null); @@ -29,7 +29,7 @@ test("#serialize", function(assert) { test("#deserialize", function(assert) { var transform = new DS.BooleanTransform(); - if (isEnabled('ds-transform-pass-options') && isEnabled('ds-boolean-transform-allow-null')) { + if (isEnabled('ds-boolean-transform-allow-null')) { assert.equal(transform.deserialize(null, { allowNull: true }), null); assert.equal(transform.deserialize(undefined, { allowNull: true }), null); From 80cbddd6df04d695e07ba1ec5a0349218bd8a707 Mon Sep 17 00:00:00 2001 From: Michael Newman Date: Fri, 29 Apr 2016 16:03:02 -0500 Subject: [PATCH 1507/2527] [DOC] Fix hard-coded "Customizing Adapters" link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f61d7cd9e9c..9b511bd0a43 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ set of RESTful JSON conventions. To learn more about adapters, including what conventions the `RESTAdapter` follows and how to build your own, see the Ember.js -Guides: [Customizing Adapters](https://guides.emberjs.com/v2.3.0/models/customizing-adapters/). +Guides: [Customizing Adapters](http://emberjs.com/guides/models/customizing-adapters). ### Fetching a Collection of Models From 5399de0c4820fe26474d667254592c2c5eb7310d Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 6 Apr 2016 00:13:18 +0200 Subject: [PATCH 1508/2527] [BUGFIX beta] Overhaul queryRecord Currently the use case for `store.queryRecord` is not communicated very well and there has been some confusion on what the expected server response should look like (array, or an object). There are several issues with the current code base: - in general, if the serializer returns an array for the primary data returned by `normalizeQueryRecordResponse`, then `store.queryRecord` resolves with an array - if rest serializer is used and an array is returned by the adapter, then the first entry of the array is used as primary data and `store.queryRecord` resolves with the first record - if json-api serializer is used and the primary data is an array, then `store.queryRecord` resolves with an array of the primary records - the API documentation for `queryRecord` is similar to `query` and doesn't indicate when this method should be used in contrast to `store.query` and getting the first record of the array - an assertion for the payload returned by the adapter for `queryRecord` not being an empty object has been added in 2.4, which is a regression to the behavior of 2.3 ----------------------------------------------------------------------- This commit addresses the above issues and makes the following changes: - add assertion that `store.queryRecord` never resolves with an array - add deprecation warning for the rest-serializers' `queryRecord`, if an array is returned instead of a single record - removes the assertion that the returned payload from the adapter for `queryRecord` is not an empty object - add assertion within json-api serializer that the primary data of the normalized response is not an array --- addon/-private/system/store.js | 92 +++++++++++++++++-- addon/-private/system/store/finders.js | 6 +- addon/serializers/json-api.js | 10 ++ addon/serializers/rest.js | 10 ++ tests/integration/adapter/find-test.js | 10 -- .../adapter/json-api-adapter-test.js | 50 ++++++++++ .../integration/adapter/rest-adapter-test.js | 52 ++++++++++- tests/integration/store-test.js | 26 ++++++ 8 files changed, 236 insertions(+), 20 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 60922465a43..965051ee590 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1043,20 +1043,96 @@ Store = Service.extend({ }, /** - This method delegates a query to the adapter. This is the one place where - adapter-level semantics are exposed to the application. + This method makes a request for one record, where the `id` is not known + beforehand (if the `id` is known, use `findRecord` instead). - Exposing queries this way seems preferable to creating an abstract query - language for all server-side queries, and then require all adapters to - implement them. + This method can be used when it is certain that the server will return a + single object for the primary data. - This method returns a promise, which is resolved with a `RecordObject` - once the server returns. + Let's assume our API provides an endpoint for the currently logged in user + via: + + ``` + // GET /api/current_user + { + user: { + id: 1234, + username: 'admin' + } + } + ``` + + Since the specific `id` of the `user` is not known beforehand, we can use + `queryRecord` to get the user: + + ```javascript + store.queryRecord('user', {}).then(function(user) { + let username = user.get('username'); + console.log(`Currently logged in as ${username}`); + }); + ``` + + The request is made through the adapters' `queryRecord`: + + ```javascript + // app/adapters/user.js + import Adapter from "ember-data/adapter"; + + export default Adapter.extend({ + queryRecord(modelName, query) { + return Ember.$.getJSON("/api/current_user"); + } + }); + ``` + + Note: the primary use case for `store.queryRecord` is when a single record + is queried and the `id` is not kown beforehand. In all other cases + `store.query` and using the first item of the array is likely the preferred + way: + + ``` + // GET /users?username=unique + { + data: [{ + id: 1234, + type: 'user', + attributes: { + username: "unique" + } + }] + } + ``` + + ```javascript + store.query('user', { username: 'unique' }).then(function(users) { + return users.get('firstObject'); + }).then(function(user) { + let id = user.get('id'); + }); + ``` + + This method returns a promise, which resolves with the found record. + + If the adapter returns no data for the primary data of the payload, then + `queryRecord` resolves with `null`: + + ``` + // GET /users?username=unique + { + data: null + } + ``` + + ```javascript + store.queryRecord('user', { username: 'unique' }).then(function(user) { + console.log(user); // null + }); + ``` @method queryRecord @param {String} modelName @param {any} query an opaque query to be used by the adapter - @return {Promise} promise + @return {Promise} promise which resolves with the found record or `null` */ queryRecord(modelName, query) { assert("You need to pass a model name to the store's queryRecord method", isPresent(modelName)); diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 07c82a99f89..99146be067e 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -192,10 +192,14 @@ export function _queryRecord(adapter, store, typeClass, query) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - assert("You made a `queryRecord` request for a " + typeClass.modelName + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); var record; store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'queryRecord'); + + assert("Expected the primary data returned by the serializer for a `queryRecord` response to be a single object or null but instead it was an array.", !Array.isArray(payload.data), { + id: 'ds.store.queryRecord-array-response' + }); + //TODO Optimize record = store.push(payload); }); diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 3c940b1113f..60656f96a10 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -202,6 +202,16 @@ const JSONAPISerializer = JSONSerializer.extend({ return normalizedPayload; }, + normalizeQueryRecordResponse() { + let normalized = this._super(...arguments); + + assert('Expected the primary data returned by the serializer for a `queryRecord` response to be a single object but instead it was an array.', !Array.isArray(normalized.data), { + id: 'ds.serializer.json-api.queryRecord-array-response' + }); + + return normalized; + }, + /** @method extractAttributes @param {DS.Model} modelClass diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 11e4d4c8ee2..e8d95cced5f 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -282,6 +282,16 @@ var RESTSerializer = JSONSerializer.extend({ continue; } + runInDebug(function() { + let isQueryRecordAnArray = requestType === 'queryRecord' && isPrimary && Array.isArray(value); + let message = "The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record."; + + deprecate(message, !isQueryRecordAnArray, { + id: 'ds.serializer.rest.queryRecord-array-response', + until: '3.0' + }); + }); + /* Support primary data as an object instead of an array. diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index c60df2c7ece..2e2546175b7 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -141,16 +141,6 @@ testInDebug('When a single record is requested, and the payload is blank', (asse }, /You made a `findRecord` request for a person with id the-id, but the adapter's response did not have any data/); }); -testInDebug('When a single record is queried for, and the payload is blank', (assert) => { - env.registry.register('adapter:person', DS.Adapter.extend({ - queryRecord: () => Ember.RSVP.resolve({}) - })); - - assert.expectAssertion(() => { - run(() => store.queryRecord('person', { name: 'the-name' })); - }, /You made a `queryRecord` request for a person, but the adapter's response did not have any data/); -}); - testInDebug('When multiple records are requested, and the payload is blank', (assert) => { env.registry.register('adapter:person', DS.Adapter.extend({ coalesceFindRequests: true, diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index 1ddff308851..21eb5368526 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -2,6 +2,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import DS from 'ember-data'; import isEnabled from 'ember-data/-private/features'; @@ -234,6 +235,55 @@ test('find many records', function(assert) { }); }); +test('queryRecord - primary data being a single record', function(assert) { + ajaxResponse([{ + data: { + type: 'posts', + id: '1', + attributes: { + title: 'Ember.js rocks' + } + } + }]); + + run(function() { + store.queryRecord('post', {}).then(function(post) { + assert.equal(passedUrl[0], '/posts'); + + assert.equal(post.get('title'), 'Ember.js rocks'); + }); + }); +}); + +test('queryRecord - primary data being null', function(assert) { + ajaxResponse([{ + data: null + }]); + + run(function() { + store.queryRecord('post', {}).then(function(post) { + assert.equal(passedUrl[0], '/posts'); + + assert.strictEqual(post, null); + }); + }); +}); + +testInDebug('queryRecord - primary data being an array throws an assertion', function(assert) { + ajaxResponse([{ + data: [{ + type: 'posts', + id: '1' + }] + }]); + + assert.expectAssertion(function() { + run(function() { + store.queryRecord('post', {}); + }); + }, "Expected the primary data returned by the serializer for a `queryRecord` response to be a single object but instead it was an array."); +}); + test('find a single record with belongsTo link as object { related }', function(assert) { assert.expect(7); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 9b29c36ed0a..d0b1a9ddcf9 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1299,7 +1299,25 @@ test("query - data is normalized through custom serializers", function(assert) { })); }); -test("queryRecord - returns a single record in an object", function(assert) { +test("queryRecord - empty response", function(assert) { + ajaxResponse({}); + + store.queryRecord('post', { slug: 'ember-js-rocks' }).then(assert.wait(function(post) { + assert.strictEqual(post, null); + })); +}); + +test("queryRecord - primary data being null", function(assert) { + ajaxResponse({ + post: null + }); + + store.queryRecord('post', { slug: 'ember-js-rocks' }).then(assert.wait(function(post) { + assert.strictEqual(post, null); + })); +}); + +test("queryRecord - primary data being a single object", function(assert) { ajaxResponse({ post: { id: '1', @@ -1338,6 +1356,38 @@ test("queryRecord - returning an array picks the first one but saves all records })); }); +testInDebug("queryRecord - returning an array is deprecated", function(assert) { + let done = assert.async(); + + ajaxResponse({ + post: [{ id: 1, name: "Rails is omakase" }, { id: 2, name: "Ember is js" }] + }); + + assert.expectDeprecation('The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record.'); + + run(function() { + store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(function() { + done(); + }); + }); +}); + +testInDebug("queryRecord - returning an single object doesn't throw a deprecation", function(assert) { + let done = assert.async(); + + ajaxResponse({ + post: { id: 1, name: "Rails is omakase" } + }); + + assert.expectNoDeprecation(); + + run(function() { + store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(function() { + done(); + }); + }); +}); + test("queryRecord - data is normalized through custom serializers", function(assert) { env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index d6c7785a4e0..2b6aba58cb3 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -590,3 +590,29 @@ testInDebug('store#findRecord that returns an array should assert', assert => { }); }, /expected the primary data returned from a `findRecord` response to be an object but instead it found an array/); }); + +module("integration/store - queryRecord", { + beforeEach() { + initializeStore(DS.Adapter.extend()); + } +}); + +testInDebug('store#queryRecord should assert when normalized payload of adapter has an array an data', function(assert) { + env.adapter.queryRecord = function() { + return { + cars: [{ id: 1 }] + }; + }; + + env.serializer.normalizeQueryRecordResponse = function() { + return { + data: [{ id: 1, type: 'car' }] + }; + }; + + assert.expectAssertion(function() { + run(function() { + store.queryRecord('car', {}); + }); + }, /Expected the primary data returned by the serializer for a `queryRecord` response to be a single object or null but instead it was an array./); +}); From f2812cb251b79bab74eb06e4ef37e55ff7d6c009 Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 4 May 2016 16:47:22 +0200 Subject: [PATCH 1509/2527] Revert "[CLEANUP ds-serialize-ids-and-types]" This reverts commit 87e6e60e9b6266b27eceae17891839cf2b7a1787. The cleanup for the ds-serialize-ids-and-types feature is made too eagerly, since it hasn't been enabled in beta yet. This commit reverts the cleanup so the functionality is still behind the (enabled) feature flag. By this it can be tested via the beta channel. Once the feature is go'ed in a release channel, this can be finally be cleaned. --- FEATURES.md | 24 ++++++++ addon/serializers/embedded-records-mixin.js | 13 ++++- config/features.json | 1 + .../embedded-records-mixin-test.js | 57 ++++++++++--------- 4 files changed, 65 insertions(+), 30 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 8fcdc171391..f2b0913f7df 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -26,6 +26,30 @@ entry in `config/features.json`. Enables `pushPayload` to return the model(s) that are created or updated via the internal `store.push`. [PR 4110](https://github.com/emberjs/data/pull/4110) +- `ds-serialize-ids-and-types` + + Enables a new `ids-and-type` strategy (in addition to the already existing `ids` and `records`) for + serializing has many relationships using the `DS.EmbeddedRecordsMixin` that will include both + `id` and `type` of each model as an object. + + For instance, if a use has many pets, which is a polymorphic relationship, the generated payload would be: + + ```js + { + "user": { + "id": "1" + "name": "Bertin Osborne", + "pets": [ + { "id": "1", "type": "Cat" }, + { "id": "2", "type": "Parrot"} + ] + } + } + ``` + + This is particularly useful for polymorphic relationships not backed by STI when just including the id + of the records is not enough. + - `ds-extended-errors` Enables `extend` method on errors. It means you can extend from `DS.AdapterError`. diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 0bdc29290de..32ff71fe03a 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -1,5 +1,6 @@ import Ember from 'ember'; import { warn } from "ember-data/-private/debug"; +import isEnabled from 'ember-data/-private/features'; var get = Ember.get; var set = Ember.set; @@ -364,6 +365,8 @@ export default Ember.Mixin.create({ } ``` + Note that the `ids-and-types` strategy is still behind the `ds-serialize-ids-and-types` feature flag. + @method serializeHasMany @param {DS.Snapshot} snapshot @param {Object} json @@ -381,12 +384,16 @@ export default Ember.Mixin.create({ json[serializedKey] = snapshot.hasMany(attr, { ids: true }); } else if (this.hasSerializeRecordsOption(attr)) { this._serializeEmbeddedHasMany(snapshot, json, relationship); - } else if (this.hasSerializeIdsAndTypesOption(attr)) { - this._serializeHasManyAsIdsAndTypes(snapshot, json, relationship); + } else { + if (isEnabled("ds-serialize-ids-and-types")) { + if (this.hasSerializeIdsAndTypesOption(attr)) { + this._serializeHasManyAsIdsAndTypes(snapshot, json, relationship); + } + } } }, - /* + /** Serializes a hasMany relationship as an array of objects containing only `id` and `type` keys. This has its use case on polymorphic hasMany relationships where the server is not storing diff --git a/config/features.json b/config/features.json index 1750dc2d709..887461de3d2 100644 --- a/config/features.json +++ b/config/features.json @@ -2,6 +2,7 @@ "ds-boolean-transform-allow-null": null, "ds-improved-ajax": null, "ds-pushpayload-return": null, + "ds-serialize-ids-and-types": true, "ds-extended-errors": null, "ds-links-in-record-array": null } diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index 4b151636adb..0d8f4351931 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -5,6 +5,7 @@ import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; +import isEnabled from 'ember-data/-private/features'; var get = Ember.get; var HomePlanet, SuperVillain, CommanderVillain, NormalMinion, EvilMinion, YellowMinion, RedMinion, SecretLab, SecretWeapon, BatCave, Comment, @@ -1073,36 +1074,38 @@ test("serialize with embedded objects (hasMany relationships, including related }); }); -test("serialize has many relationship using the `ids-and-types` strategy", function(assert) { - run(function() { - yellowMinion = env.store.createRecord('yellow-minion', { id: 1, name: "Yellowy" }); - redMinion = env.store.createRecord('red-minion', { id: 1, name: "Reddy" }); - commanderVillain = env.store.createRecord('commander-villain', { id: 1, name: "Jeff", minions: [yellowMinion, redMinion] }); - }); +if (isEnabled("ds-serialize-ids-and-types")) { + test("serialize has many relationship using the `ids-and-types` strategy", function(assert) { + run(function() { + yellowMinion = env.store.createRecord('yellow-minion', { id: 1, name: "Yellowy" }); + redMinion = env.store.createRecord('red-minion', { id: 1, name: "Reddy" }); + commanderVillain = env.store.createRecord('commander-villain', { id: 1, name: "Jeff", minions: [yellowMinion, redMinion] }); + }); - env.registry.register('serializer:commander-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - minions: { serialize: 'ids-and-types' } - } - })); - var serializer, json; - run(function() { - serializer = env.container.lookup("serializer:commander-villain"); - var snapshot = commanderVillain._createSnapshot(); - json = serializer.serialize(snapshot); - }); + env.registry.register('serializer:commander-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + minions: { serialize: 'ids-and-types' } + } + })); + var serializer, json; + run(function() { + serializer = env.container.lookup("serializer:commander-villain"); + var snapshot = commanderVillain._createSnapshot(); + json = serializer.serialize(snapshot); + }); - assert.deepEqual(json, { - name: 'Jeff', - minions: [{ - id: '1', - type: 'yellow-minion' - }, { - id: '1', - type: 'red-minion' - }] + assert.deepEqual(json, { + name: 'Jeff', + minions: [{ + id: '1', + type: 'yellow-minion' + }, { + id: '1', + type: 'red-minion' + }] + }); }); -}); +} test("normalizeResponse with embedded object (belongsTo relationship)", function(assert) { env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { From 2168c2c50bc3742488cd8f8b61f659b9579c1b66 Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 9 May 2016 21:33:26 +0200 Subject: [PATCH 1510/2527] [DOC] Add link to PR's for every feature This makes it easier to navigate to a feature to see its implementation and additional context. --- FEATURES.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index f2b0913f7df..fea5cb15187 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -11,22 +11,22 @@ entry in `config/features.json`. ## Feature Flags -- `ds-boolean-transform-allow-null` +- `ds-boolean-transform-allow-null` [#4022](https://github.com/emberjs/data/pull/4022) Allow `null`/`undefined` values for `boolean` attributes via `DS.attr('boolean', { allowNull: true })` -- `ds-improved-ajax` +- `ds-improved-ajax` [#3099](https://github.com/emberjs/data/pull/3099) This feature allows to customize how a request is formed by overwriting `methodForRequest`, `urlForRequest`, `headersForRequest` and `bodyForRequest` in the `DS.RESTAdapter`. -- `ds-pushpayload-return` +- `ds-pushpayload-return` [#4110](https://github.com/emberjs/data/pull/4110) Enables `pushPayload` to return the model(s) that are created or - updated via the internal `store.push`. [PR 4110](https://github.com/emberjs/data/pull/4110) + updated via the internal `store.push`. -- `ds-serialize-ids-and-types` +- `ds-serialize-ids-and-types` [#3848](https://github.com/emberjs/data/pull/3848) Enables a new `ids-and-type` strategy (in addition to the already existing `ids` and `records`) for serializing has many relationships using the `DS.EmbeddedRecordsMixin` that will include both @@ -50,7 +50,7 @@ entry in `config/features.json`. This is particularly useful for polymorphic relationships not backed by STI when just including the id of the records is not enough. -- `ds-extended-errors` +- `ds-extended-errors` [#3586](https://github.com/emberjs/data/pull/3586) [#4287](https://github.com/emberjs/data/pull/4287) Enables `extend` method on errors. It means you can extend from `DS.AdapterError`. From 91454da085be1b764eea0aeba02c0efe4c4ee329 Mon Sep 17 00:00:00 2001 From: Danail Nachev Date: Sun, 8 May 2016 12:53:01 -0700 Subject: [PATCH 1511/2527] [BUGFIX beta] Reuse snapshot when serializing embedded relationships --- addon/serializers/embedded-records-mixin.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 32ff71fe03a..cfdd86a9430 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -226,7 +226,7 @@ export default Ember.Mixin.create({ if (!embeddedSnapshot) { json[serializedKey] = null; } else { - json[serializedKey] = embeddedSnapshot.record.serialize({ includeId: true }); + json[serializedKey] = embeddedSnapshot.serialize({ includeId: true }); this.removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, json[serializedKey]); if (relationship.options.polymorphic) { @@ -440,7 +440,7 @@ export default Ember.Mixin.create({ for (let i = 0; i < manyArray.length; i++) { let embeddedSnapshot = manyArray[i]; - let embeddedJson = embeddedSnapshot.record.serialize({ includeId: true }); + let embeddedJson = embeddedSnapshot.serialize({ includeId: true }); this.removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, embeddedJson); ret[i] = embeddedJson; } From 8046c48cc2fe6645a50c41bdfeaa756e12931cd9 Mon Sep 17 00:00:00 2001 From: Aaron Sikes Date: Tue, 10 May 2016 11:32:34 -0400 Subject: [PATCH 1512/2527] [BUGFIX beta] Fix resetting of properties to in-flight values Changing the value of an in-flight property, then changing back, had the side effect that the record would be marked dirty once the save completed. `changedAttributes` would report that `name` had been changed from 'Thomas' to 'Thomas' This is because the attr computed was only checking to see if the value was being reset to the canonical value, not if it was being reset to the in-flight value --- addon/attr.js | 9 +++++++- tests/unit/model-test.js | 45 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/addon/attr.js b/addon/attr.js index 673fb7ee429..8ea5e864c56 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -140,16 +140,23 @@ export default function attr(type, options) { set(key, value) { var internalModel = this._internalModel; var oldValue = getValue(internalModel, key); + var originalValue; if (value !== oldValue) { // Add the new value to the changed attributes hash; it will get deleted by // the 'didSetProperty' handler if it is no different from the original value internalModel._attributes[key] = value; + if (key in internalModel._inFlightAttributes) { + originalValue = internalModel._inFlightAttributes[key] + } else { + originalValue = internalModel._data[key] + } + this._internalModel.send('didSetProperty', { name: key, oldValue: oldValue, - originalValue: internalModel._data[key], + originalValue: originalValue, value: value }); } diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 67ed420f3ba..0d5d38f0477 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -97,6 +97,51 @@ test("resetting a property on a record cause it to become clean again", function }); }); +test("resetting a property to the current in-flight value causes it to become clean when the save completes", function(assert) { + assert.expect(4); + + var person, finishSaving; + + env.adapter.updateRecord = function(store, type, snapshot) { + // Make sure the save is async + return new Ember.RSVP.Promise(function(resolve, reject) { + finishSaving = resolve; + }); + }; + + run(function() { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Tom' + } + } + }); + person = store.peekRecord('person', 1); + person.set('name', "Thomas"); + + person.save(); + }); + + run(function() { + assert.equal(person.get('name'), "Thomas"); + + person.set('name', 'Tomathy'); + assert.equal(person.get('name'), "Tomathy"); + + person.set('name', 'Thomas'); + assert.equal(person.get('name'), "Thomas"); + + finishSaving(); + }); + + run(function() { + assert.equal(person.get('hasDirtyAttributes'), false, "The person is now clean"); + }); +}); + test("a record becomes clean again only if all changed properties are reset", function(assert) { assert.expect(5); env.adapter.shouldBackgroundReloadRecord = () => false; From 382e09acf97232da359cb94334d80698913d5649 Mon Sep 17 00:00:00 2001 From: Scott Batson Date: Wed, 11 May 2016 09:19:49 -0400 Subject: [PATCH 1513/2527] [BUGFIX beta] remove trailing new lines from blueprints --- blueprints/model/files/__root__/__path__/__name__.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blueprints/model/files/__root__/__path__/__name__.js b/blueprints/model/files/__root__/__path__/__name__.js index 81e0f12b75a..d92b5042812 100644 --- a/blueprints/model/files/__root__/__path__/__name__.js +++ b/blueprints/model/files/__root__/__path__/__name__.js @@ -1,5 +1,5 @@ <%= importStatements %> export default Model.extend({ - <%= attrs %> +<%= attrs.length ? ' ' + attrs : '' %> }); From 52ea222ab131596229d23cb9cbaea6e057174b52 Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Sun, 15 May 2016 14:51:03 -0400 Subject: [PATCH 1514/2527] [BUGFIX beta] Consider `backgroundReload` option for `findRecord` & `findAll` Fixes #3772 This adds support for controlling when records are reloaded in the background to `store.findRecord()` and `store.findAll()`. --- addon/-private/system/store.js | 61 ++++++- tests/integration/store-test.js | 282 ++++++++++++++++++++++++++++++++ 2 files changed, 338 insertions(+), 5 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 965051ee590..79d15311af1 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -440,6 +440,8 @@ Store = Service.extend({ store, it depends on the reload behavior _when_ the returned promise resolves. + ### Reloading + The reload behavior is configured either via the passed `options` hash or the result of the adapter's `shouldReloadRecord`. @@ -472,6 +474,8 @@ Store = Service.extend({ If no reload is indicated via the abovementioned ways, then the promise immediately resolves with the cached version in the store. + ### Background Reloading + Optionally, if `adapter.shouldBackgroundReloadRecord` evaluates to `true`, then a background reload is started, which updates the records' data, once it is available: @@ -516,6 +520,20 @@ Store = Service.extend({ blogPost.get('revision'); // 2 ``` + If you would like to force or prevent background reloading, you can set a + boolean value for `backgroundReload` in the options object for + `findRecord`. + + ```app/routes/post/edit.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model: function(params) { + return this.store.findRecord('post', params.post_id, { backgroundReload: false }); + } + }); + ``` + See [peekRecord](#method_peekRecord) to get the cached version of a record. @method findRecord @@ -547,16 +565,21 @@ Store = Service.extend({ return this.scheduleFetch(internalModel, options); } - // Refetch the record if the adapter thinks the record is stale var snapshot = internalModel.createSnapshot(options); var typeClass = internalModel.type; var adapter = this.adapterFor(typeClass.modelName); + + // Refetch the record if the adapter thinks the record is stale if (adapter.shouldReloadRecord(this, snapshot)) { return this.scheduleFetch(internalModel, options); } - // Trigger the background refetch if all the previous checks fail - if (adapter.shouldBackgroundReloadRecord(this, snapshot)) { + if (options.backgroundReload === false) { + return Promise.resolve(internalModel); + } + + // Trigger the background refetch if backgroundReload option is passed + if (options.backgroundReload || adapter.shouldBackgroundReloadRecord(this, snapshot)) { this.scheduleFetch(internalModel, options); } @@ -1149,7 +1172,7 @@ Store = Service.extend({ }, /** - `findAll` ask the adapter's `findAll` method to find the records for the + `findAll` asks the adapter's `findAll` method to find the records for the given type, and returns a promise which will resolve with all records of this type present in the store, even if the adapter only returns a subset of them. @@ -1168,6 +1191,8 @@ Store = Service.extend({ configured via the passed `options` hash and the result of the adapter's `shouldReloadAll` method. + ### Reloading + If `{ reload: true }` is passed or `adapter.shouldReloadAll` evaluates to `true`, then the returned promise resolves once the adapter returns data, regardless if there are already records in the store: @@ -1194,6 +1219,9 @@ Store = Service.extend({ If no reload is indicated via the abovementioned ways, then the promise immediately resolves with all the records currently loaded in the store. + + ### Background Reloading + Optionally, if `adapter.shouldBackgroundReloadAll` evaluates to `true`, then a background reload is started. Once this resolves, the array with which the promise resolves, is updated automatically so it contains all the @@ -1238,6 +1266,20 @@ Store = Service.extend({ allAuthors.getEach('id'); // ['first', 'second'] ``` + If you would like to force or prevent background reloading, you can set a + boolean value for `backgroundReload` in the options object for + `findAll`. + + ```app/routes/post/edit.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model: function() { + return this.store.findAll('post', { backgroundReload: false }); + } + }); + ``` + See [peekAll](#method_peekAll) to get an array of current records in the store, without waiting until a reload is finished. @@ -1270,16 +1312,25 @@ Store = Service.extend({ assert("You tried to load all records but you have no adapter (for " + typeClass + ")", adapter); assert("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function'); + if (options.reload) { return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); } + var snapshotArray = array.createSnapshot(options); + if (adapter.shouldReloadAll(this, snapshotArray)) { return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); } - if (adapter.shouldBackgroundReloadAll(this, snapshotArray)) { + + if (options.backgroundReload === false) { + return promiseArray(Promise.resolve(array)); + } + + if (options.backgroundReload || adapter.shouldBackgroundReloadAll(this, snapshotArray)) { _findAll(adapter, this, typeClass, sinceToken, options); } + return promiseArray(Promise.resolve(array)); }, diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 2b6aba58cb3..4a4a6e7b397 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -325,6 +325,138 @@ test("store#findRecord { reload: true } ignores cached record and reloads record }); }); +test("store#findRecord { backgroundReload: false } returns cached record and does not reload in the background", function(assert) { + assert.expect(2); + + let testAdapter = DS.RESTAdapter.extend({ + shouldBackgroundReloadRecord() { + assert.ok(false, 'shouldBackgroundReloadRecord should not be called when { backgroundReload: false }'); + }, + + findRecord() { + assert.ok(false, 'findRecord() should not be called when { backgroundReload: false }'); + } + }); + + initializeStore(testAdapter); + + run(() => { + store.push({ + data: { + type: 'car', + id: '1', + attributes: { + make: 'BMC', + model: 'Mini' + } + } + }); + }); + + run(() => { + store.findRecord('car', 1, { backgroundReload: false }).then((car) => { + assert.equal(car.get('model'), 'Mini', 'cached car record is returned'); + }); + }); + + run(() => { + let car = store.peekRecord('car', 1); + assert.equal(car.get('model'), 'Mini', 'car record was not reloaded'); + }); +}); + +test("store#findRecord { backgroundReload: true } returns cached record and reloads record in background", function(assert) { + assert.expect(2); + + let testAdapter = DS.RESTAdapter.extend({ + shouldBackgroundReloadRecord() { + assert.ok(false, 'shouldBackgroundReloadRecord should not be called when { backgroundReload: true }'); + } + }); + + initializeStore(testAdapter); + + run(() => { + store.push({ + data: { + type: 'car', + id: '1', + attributes: { + make: 'BMC', + model: 'Mini' + } + } + }); + }); + + ajaxResponse({ + cars: [{ + id: 1, + make: 'BMC', + model: 'Princess' + }] + }); + + run(() => { + store.findRecord('car', 1, { backgroundReload: true }).then((car) => { + assert.equal(car.get('model'), 'Mini', 'cached car record is returned'); + }); + }); + + run(() => { + let car = store.peekRecord('car', 1); + assert.equal(car.get('model'), 'Princess', 'car record was reloaded'); + }); +}); + +test("store#findRecord { backgroundReload: false } is ignored if adapter.shouldReloadRecord is true", function(assert) { + assert.expect(2); + + let testAdapter = DS.RESTAdapter.extend({ + shouldReloadRecord() { + return true; + }, + + shouldBackgroundReloadRecord() { + assert.ok(false, 'shouldBackgroundReloadRecord should not be called when adapter.shouldReloadRecord = true'); + } + }); + + initializeStore(testAdapter); + + run(() => { + store.push({ + data: { + type: 'car', + id: '1', + attributes: { + make: 'BMC', + model: 'Mini' + } + } + }); + }); + + ajaxResponse({ + cars: [{ + id: 1, + make: 'BMC', + model: 'Princess' + }] + }); + + run(() => { + let car = store.peekRecord('car', 1); + assert.equal(car.get('model'), 'Mini', 'Car record is initially a Mini'); + }); + + run(() => { + store.findRecord('car', 1, { backgroundReload: false }).then((car) => { + assert.equal(car.get('model'), 'Princess', 'Car record is reloaded immediately (not in the background)'); + }); + }); +}); + testInDebug('store#findRecord call with `id` of type different than non-empty string or number should trigger an assertion', assert => { const badValues = ['', undefined, null, NaN, false]; assert.expect(badValues.length); @@ -418,6 +550,156 @@ test("Using store#findAll with existing records performs a query in the backgrou }); }); +test("store#findAll { backgroundReload: false } skips shouldBackgroundReloadAll, returns cached records & does not reload in the background", function(assert) { + assert.expect(4); + + let testAdapter = DS.RESTAdapter.extend({ + shouldBackgroundReloadAll() { + assert.ok(false, 'shouldBackgroundReloadAll should not be called when { backgroundReload: false }'); + }, + + findAll() { + assert.ok(false, 'findAll() should not be called when { backgroundReload: true }'); + } + }); + + initializeStore(testAdapter); + + run(() => { + store.push({ + data: { + type: 'car', + id: '1', + attributes: { + make: 'BMC', + model: 'Mini' + } + } + }); + }); + + run(() => { + store.findAll('car', { backgroundReload: false }).then((cars) => { + assert.equal(cars.get('length'), 1, 'single cached car record is returned'); + assert.equal(cars.get('firstObject.model'), 'Mini', 'correct cached car record is returned'); + }); + }); + + run(() => { + let cars = store.peekAll('car'); + assert.equal(cars.get('length'), 1, 'single cached car record is returned again'); + assert.equal(cars.get('firstObject.model'), 'Mini', 'correct cached car record is returned again'); + }); +}); + +test("store#findAll { backgroundReload: true } skips shouldBackgroundReloadAll, returns cached records, & reloads in background", function(assert) { + assert.expect(5); + + let testAdapter = DS.RESTAdapter.extend({ + shouldBackgroundReloadAll() { + assert.ok(false, 'shouldBackgroundReloadAll should not be called when { backgroundReload: true }'); + } + }); + + initializeStore(testAdapter); + + run(() => { + store.push({ + data: { + type: 'car', + id: '1', + attributes: { + make: 'BMC', + model: 'Mini' + } + } + }); + }); + + ajaxResponse({ + cars: [{ + id: 1, + make: 'BMC', + model: 'New Mini' + }, + { + id: 2, + make: 'BMCW', + model: 'Isetta' + }] + }); + + run(() => { + store.findAll('car', { backgroundReload: true }).then((cars) => { + assert.equal(cars.get('length'), 1, 'single cached car record is returned'); + assert.equal(cars.get('firstObject.model'), 'Mini', 'correct cached car record is returned'); + }); + }); + + run(() => { + let cars = store.peekAll('car'); + assert.equal(cars.get('length'), 2, 'multiple cars now in the store'); + assert.equal(cars.get('firstObject.model'), 'New Mini', 'existing record updated correctly'); + assert.equal(cars.get('lastObject.model'), 'Isetta', 'new record added to the store'); + }); +}); + +test("store#findAll { backgroundReload: false } is ignored if adapter.shouldReloadAll is true", function(assert) { + assert.expect(5); + + let testAdapter = DS.RESTAdapter.extend({ + shouldReloadAll() { + return true; + }, + + shouldBackgroundReloadAll() { + assert.ok(false, 'shouldBackgroundReloadAll should not be called when adapter.shouldReloadAll = true'); + } + }); + + initializeStore(testAdapter); + + run(() => { + store.push({ + data: { + type: 'car', + id: '1', + attributes: { + make: 'BMC', + model: 'Mini' + } + } + }); + }); + + ajaxResponse({ + cars: [{ + id: 1, + make: 'BMC', + model: 'New Mini' + }, + { + id: 2, + make: 'BMCW', + model: 'Isetta' + }] + }); + + run(() => { + let cars = store.peekAll('car'); + assert.equal(cars.get('length'), 1, 'one car in the store'); + assert.equal(cars.get('firstObject.model'), 'Mini', 'correct car is in the store'); + }); + + run(() => { + store.findAll('car', { backgroundReload: false }).then((cars) => { + assert.equal(cars.get('length'), 2, 'multiple car records are returned'); + assert.equal(cars.get('firstObject.model'), 'New Mini', 'initial car record was updated'); + assert.equal(cars.get('lastObject.model'), 'Isetta', 'second car record was loaded'); + }); + }); +}); + test("store#findAll should eventually return all known records even if they are not in the adapter response", function(assert) { assert.expect(5); From 50b4c27c51d8c99f72723351d901f4ff47ed95ed Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 16 May 2016 13:09:56 +0200 Subject: [PATCH 1515/2527] [BUGFIX release] `isUpdating` flag is set correctly for `store.findAll` A regression for the `isUpdating` flag on the RecordArray returned for `store.peekAll` has been introduced in #4316: the flag isn't set to true anymore when records are reloaded or a background reloaded. --- addon/-private/system/store.js | 2 + tests/integration/adapter/find-all-test.js | 86 ++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 79d15311af1..cf1850fbdf9 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1313,6 +1313,8 @@ Store = Service.extend({ assert("You tried to load all records but you have no adapter (for " + typeClass + ")", adapter); assert("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function'); + set(array, 'isUpdating', true); + if (options.reload) { return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); } diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index c33cb1235cd..7a6616f25ae 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -155,3 +155,89 @@ testInDebug('When all records are requested, assert the payload is not blank', ( run(() => store.findAll('person')); }, /You made a `findAll` request for person records, but the adapter's response did not have any data/); }); + +test("isUpdating is true while records are fetched", function(assert) { + let done = assert.async(); + + let findAllDeferred = Ember.RSVP.defer(); + env.registry.register('adapter:person', DS.Adapter.extend({ + findAll() { + return findAllDeferred.promise; + }, + + shouldReloadAll: () => true + })); + + run(function() { + store.push({ + data: [{ + type: 'person', + id: 1 + }] + }); + }); + + let persons = store.peekAll('person'); + assert.equal(persons.get("length"), 1); + + run(function() { + store.findAll('person').then(function(persons) { + assert.equal(persons.get("isUpdating"), false); + assert.equal(persons.get("length"), 2); + + done(); + }); + }); + + assert.equal(persons.get("isUpdating"), true); + + findAllDeferred.resolve([{ id: 2 }]); +}); + +test("isUpdating is true while records are fetched in the background", function(assert) { + let done = assert.async(); + + let findAllDeferred = Ember.RSVP.defer(); + env.registry.register('adapter:person', DS.Adapter.extend({ + findAll() { + return findAllDeferred.promise; + }, + + shouldReloadAll: () => false, + shouldBackgroundReloadAll: () => true + })); + + run(function() { + store.push({ + data: [{ + type: 'person', + id: 1 + }] + }); + }); + + let persons = store.peekAll('person'); + assert.equal(persons.get("length"), 1); + + run(function() { + store.findAll('person').then(function(persons) { + assert.equal(persons.get("isUpdating"), true); + assert.equal(persons.get("length"), 1, "persons are updated in the background"); + }); + }); + + assert.equal(persons.get("isUpdating"), true); + + run(function() { + findAllDeferred.resolve([{ id: 2 }]); + }); + + run(function() { + findAllDeferred.promise.then(function() { + assert.equal(persons.get("isUpdating"), false); + assert.equal(persons.get("length"), 2); + + done(); + }); + }); +}); From 562de64f84c970bdf746562897eee03ed613a59d Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 17 May 2016 16:43:41 -0400 Subject: [PATCH 1516/2527] Update the changelog for the 2.5.3 release --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 352f25b26c6..ec2421949a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ### Master +### Release 2.5.3 (May 17, 2016) +- [#4386](https://github.com/emberjs/data/pull/4386) [BUGFIX release] `isUpdating` flag is set correctly for `store.findAll` + ### Release 2.5.2 (April 14, 2016) - [#4328](https://github.com/emberjs/data/pull/4328) [BUGFIX release] Only setup babel options once. - [#4333](https://github.com/emberjs/data/pull/4333) [BUGFIX release] use es5 syntax for addon's index.js file From 0d8686ebe756539e10e7be23680542f3c069c8a4 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 19 May 2016 21:46:14 -0700 Subject: [PATCH 1517/2527] call super in addon#init --- index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.js b/index.js index 220387f3991..b09d5ccc4ed 100644 --- a/index.js +++ b/index.js @@ -26,6 +26,8 @@ module.exports = { }, init: function() { + this._super.init && this._super.init.apply(this, arguments); + var bowerDeps = this.project.bowerDependencies(); var VersionChecker = require('ember-cli-version-checker'); From 6d1076acf242af0fb1b532adfedce73be5d56881 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Mon, 23 May 2016 05:28:05 -0700 Subject: [PATCH 1518/2527] Update ember-cli to v2.5.1 This updates "ember-cli" to v2.5.1 and makes smaller changes in the course of the update: - Update "ember-cli-qunit" to v1.4.0 - Update "ember-cli-shims" to v0.1.1 - Fix whitespace issues - Remove unused imports - Add missing semicolons - JSHint: Disable "loopfunc" rule --- .jshintrc | 3 ++- addon/-private/system/snapshot-record-array.js | 2 -- addon/-private/system/snapshot.js | 1 - addon/adapter.js | 4 ++-- addon/adapters/rest.js | 2 +- addon/attr.js | 4 ++-- addon/index.js | 1 - addon/serializers/rest.js | 8 ++++---- bower.json | 2 +- package.json | 5 +++-- 10 files changed, 15 insertions(+), 17 deletions(-) diff --git a/.jshintrc b/.jshintrc index a578af3a7ff..a7314bde146 100644 --- a/.jshintrc +++ b/.jshintrc @@ -31,5 +31,6 @@ "white": false, "eqnull": true, "esnext": true, - "unused": "vars" + "unused": "vars", + "loopfunc": true } diff --git a/addon/-private/system/snapshot-record-array.js b/addon/-private/system/snapshot-record-array.js index 8435f027a7b..13076ccd657 100644 --- a/addon/-private/system/snapshot-record-array.js +++ b/addon/-private/system/snapshot-record-array.js @@ -2,8 +2,6 @@ @module ember-data */ -import isEnabled from 'ember-data/-private/features'; - /** @class SnapshotRecordArray @namespace DS diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index ebb75d8e1bf..4800ae80458 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -4,7 +4,6 @@ import Ember from 'ember'; import EmptyObject from "ember-data/-private/system/empty-object"; -import isEnabled from 'ember-data/-private/features'; var get = Ember.get; diff --git a/addon/adapter.js b/addon/adapter.js index ddc0ff27abf..a7ef83a90ac 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -88,8 +88,8 @@ export default Ember.Object.extend({ /** The `findRecord()` method is invoked when the store is asked for a record that has not previously been loaded. In response to `findRecord()` being called, you - should query your persistence layer for a record with the given ID. The `findRecord` - method should return a promise that will resolve to a JavaScript object that will be + should query your persistence layer for a record with the given ID. The `findRecord` + method should return a promise that will resolve to a JavaScript object that will be normalized by the serializer. Here is an example `findRecord` implementation: diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 32961341753..b6182e6a2c1 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1308,7 +1308,7 @@ if (isEnabled('ds-improved-ajax')) { * @param {Object} params * @return {Object} request object */ - _requestFor(params) { + _requestFor(params) { const method = this.methodForRequest(params); const url = this.urlForRequest(params); const headers = this.headersForRequest(params); diff --git a/addon/attr.js b/addon/attr.js index 8ea5e864c56..431cbbb75d5 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -148,9 +148,9 @@ export default function attr(type, options) { internalModel._attributes[key] = value; if (key in internalModel._inFlightAttributes) { - originalValue = internalModel._inFlightAttributes[key] + originalValue = internalModel._inFlightAttributes[key]; } else { - originalValue = internalModel._data[key] + originalValue = internalModel._data[key]; } this._internalModel.send('didSetProperty', { diff --git a/addon/index.js b/addon/index.js index 81963b0358e..8701df0ccc3 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,5 +1,4 @@ import Ember from "ember"; -import { warn } from "ember-data/-private/debug"; import isEnabled from "ember-data/-private/features"; /** Ember Data diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index e8d95cced5f..4df4f7904ff 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -123,7 +123,7 @@ var RESTSerializer = JSONSerializer.extend({ * With `App.Comment`, `"comments"` and `{ id: 2, body: "Rails is unagi" }` You can use this method, for example, to normalize underscored keys to camelized - or other general-purpose normalizations. You will only need to implement + or other general-purpose normalizations. You will only need to implement `normalize` and manipulate the payload as desired. For example, if the `IDs` under `"comments"` are provided as `_id` instead of @@ -136,7 +136,7 @@ var RESTSerializer = JSONSerializer.extend({ normalize(model, hash, prop) { if (prop === 'comments') { hash.id = hash._id; - delete hash._id; + delete hash._id; } return this._super(...arguments); @@ -144,8 +144,8 @@ var RESTSerializer = JSONSerializer.extend({ }); ``` - On each call to the `normalize` method, the third parameter (`prop`) is always - one of the keys that were in the original payload or in the result of another + On each call to the `normalize` method, the third parameter (`prop`) is always + one of the keys that were in the original payload or in the result of another normalization as `normalizeResponse`. @method normalize diff --git a/bower.json b/bower.json index 7ca7fb2f1e2..e454d4ea623 100644 --- a/bower.json +++ b/bower.json @@ -2,7 +2,7 @@ "name": "ember-data", "dependencies": { "ember": "components/ember#release", - "ember-cli-shims": "0.1.0", + "ember-cli-shims": "0.1.1", "ember-cli-test-loader": "0.2.2", "ember-qunit-notifications": "0.1.0", "pretender": "^0.12.0" diff --git a/package.json b/package.json index 06905944c59..b0638e3ec34 100644 --- a/package.json +++ b/package.json @@ -54,16 +54,17 @@ "broccoli-uglify-sourcemap": "^1.0.1", "broccoli-yuidoc": "^2.1.0", "ember-ajax": "0.7.1", - "ember-cli": "2.4.1", + "ember-cli": "2.5.1", "ember-cli-app-version": "^1.0.0", "ember-cli-blueprint-test-helpers": "0.11.0", "ember-cli-dependency-checker": "^1.2.0", "ember-cli-htmlbars": "^1.0.3", "ember-cli-htmlbars-inline-precompile": "^0.2.0", "ember-cli-inject-live-reload": "^1.3.1", + "ember-cli-jshint": "^1.0.0", "ember-cli-internal-test-helpers": "^0.8.1", "ember-cli-pretender": "0.6.0", - "ember-cli-qunit": "^1.2.1", + "ember-cli-qunit": "^1.4.0", "ember-cli-release": "0.2.3", "ember-cli-sri": "^2.1.0", "ember-cli-uglify": "^1.2.0", From 49a1db2e8ee79084124c5befe37edd72979ac895 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 23 May 2016 10:59:09 -0400 Subject: [PATCH 1519/2527] [FEATURE ds-payload-hooks] Fix lint errors caused by merging an older pr --- addon/serializers/json.js | 1 + addon/serializers/rest.js | 2 +- tests/integration/serializers/json-serializer-test.js | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 4176e95b966..9c2ee4d0e95 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -4,6 +4,7 @@ import Serializer from "ember-data/serializer"; import coerceId from "ember-data/-private/system/coerce-id"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; +import isEnabled from 'ember-data/-private/features'; import { getOwner diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 3383745cffb..5534a312fce 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -973,7 +973,7 @@ if (isEnabled("ds-payload-type-hooks")) { _hasCustomPayloadKeyFromModelName() { return this.payloadKeyFromModelName !== RESTSerializer.prototype.payloadKeyFromModelName; - }, + } }); diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 3be5cc17743..cb43e3addc5 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -1,5 +1,6 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import isEnabled from 'ember-data/-private/features'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; From fec260a38c3f7227ffe17a3af09973ce2718acca Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Mon, 23 May 2016 22:19:07 -0700 Subject: [PATCH 1520/2527] Replace JSHint/JSCS with ESLint (#4360) * Add "ember-cli-eslint" dependency * ESLint: Use JS config files ... instead of JSON * ESLint: Use recommended ruleset instead of outdated "eslint-config-ember" * tests/ember-data-initializer: Disable "no-extra-semi" rule * tests/integration/adapter/find-all: Remove unused variable * tests/integration/records: Ignore deliberatly unused variables * tests/integration/relationships: Resolve unused variable warnings * tests/integration/store: Remove unused variables * tests/unit: Remove unused variables * ESLint: Enable equivalent rules from ".jshintrc" * tests: Fix indentation * ESLint: Enable equivalent rules from ".jscsrc" * Remove obsolete "broccoli-jscs" addon * Replace obsolete "ember-cli-jshint" addon with ESLint * Fix remaining ESLint issues --- .eslintrc.js | 59 +++++++++++++++++++ .jscsrc | 59 ------------------- .jshintrc | 36 ----------- .npmignore | 4 +- addon/-private/system/coerce-id.js | 2 +- addon/-private/system/model/states.js | 1 - addon/-private/system/ordered-set.js | 2 +- addon/-private/system/relationships/ext.js | 5 +- addon/-private/system/store.js | 2 +- addon/adapters/rest.js | 31 +++++----- addon/serializers/rest.js | 3 - blueprints/adapter-test/index.js | 2 +- blueprints/adapter/index.js | 2 +- blueprints/model-test/index.js | 2 +- blueprints/model/index.js | 2 +- blueprints/serializer-test/index.js | 2 +- blueprints/serializer/index.js | 2 +- blueprints/transform-test/index.js | 2 +- blueprints/transform/index.js | 2 +- config/ember-try.js | 2 +- ember-cli-build.js | 7 +-- index.js | 2 +- lib/enable-optional-features-via-url/index.js | 2 +- lib/javascripts.js | 2 +- package.json | 3 +- testem.js | 2 +- tests/.eslintrc.js | 6 ++ tests/.jshintrc | 32 ---------- tests/dummy/config/environment.js | 2 +- tests/ember-data-initializers.js | 2 + tests/integration/adapter/find-all-test.js | 3 - .../integration/records/delete-record-test.js | 2 + tests/integration/records/unload-test.js | 2 + .../relationships/belongs-to-test.js | 11 ++-- .../relationships/has-many-test.js | 2 + .../inverse-relationships-test.js | 8 +-- .../relationships/many-to-many-test.js | 2 + .../relationships/one-to-many-test.js | 8 ++- .../serializers/json-serializer-test.js | 3 +- tests/integration/store-test.js | 6 -- tests/unit/adapter-errors-test.js | 4 +- .../group-records-for-find-many-test.js | 4 +- tests/unit/many-array-test.js | 5 +- tests/unit/model/relationships-test.js | 6 +- .../model/relationships/belongs-to-test.js | 24 ++++---- tests/unit/store/create-record-test.js | 3 +- tests/unit/transform/number-test.js | 2 - 47 files changed, 152 insertions(+), 225 deletions(-) create mode 100644 .eslintrc.js delete mode 100644 .jscsrc delete mode 100644 .jshintrc create mode 100644 tests/.eslintrc.js delete mode 100644 tests/.jshintrc diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000000..9f2f1ee24e2 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,59 @@ +/* global module */ +module.exports = { + root: true, + parserOptions: { + ecmaVersion: 6, + sourceType: 'module', + }, + extends: 'eslint:recommended', + env: { + 'browser': true, + }, + rules: { + 'no-unused-vars': ['error', { + 'args': 'none', + }], + + // from JSHint + 'no-cond-assign': ['error', 'except-parens'], + 'eqeqeq': 'error', + 'no-eval': 'error', + 'new-cap': ['error', { + 'capIsNew': false, + }], + 'no-caller': 'error', + 'no-irregular-whitespace': 'error', + 'no-undef': 'error', + 'no-eq-null': 'error', + + // from JSCS + 'array-bracket-spacing': ['error', 'never'], + 'comma-style': ['error', 'last'], + 'brace-style': ['error', '1tbs', { + 'allowSingleLine': true, + }], + 'no-spaced-func': 'error', + 'no-empty': 'error', + 'curly': ['error', 'all'], + 'eol-last': 'error', + 'no-trailing-spaces': 'error', + 'comma-dangle': ['error', 'never'], + 'space-before-blocks': ['error', 'always'], + 'indent': ['error', 2, { + 'SwitchCase': 1, + }], + 'keyword-spacing': ['error', { + 'overrides': { + 'else': { + 'before': true, + }, + 'while': { + 'before': true, + }, + 'catch': { + 'before': true, + }, + }, + }], + }, +}; diff --git a/.jscsrc b/.jscsrc deleted file mode 100644 index a60b40bc2c3..00000000000 --- a/.jscsrc +++ /dev/null @@ -1,59 +0,0 @@ -{ - "esnext": true, - "additionalRules": [ "lib/jscs-rules/*.js" ], - "disallowSpacesInsideArrayBrackets": "all", - "disallowMultipleVarDeclWithAssignment": true, - "requireSpaceBeforeObjectValues": true, - "requireCommaBeforeLineBreak": true, - "requireBlocksOnNewline": 1, - "disallowKeywordsOnNewLine": ["else"], - "disallowSpacesBeforeSemicolons": true, - "disallowNewlineBeforeBlockStatements": true, - "requireSpacesInConditionalExpression": { - "afterTest": true, - "beforeConsequent": true, - "afterConsequent": true, - "beforeAlternate": true - }, - "disallowSpacesInCallExpression": true, - "disallowSpacesInsideRoundBracesInCallExpression": true, - "disallowEmptyBlocks": true, - "requireSpacesInsideObjectBrackets": "all", - "requireCurlyBraces": [ - "if", - "else", - "for", - "while", - "do", - "try", - "catch" - ], - "requireLineFeedAtFileEnd": true, - "disallowTrailingWhitespace": true, - "disallowTrailingComma": true, - "requireSpaceBeforeBlockStatements": true, - "validateIndentation": 2, - "validateParameterSeparator": ", ", - "requireSpaceBeforeKeywords": [ - "else", - "while", - "catch" - ], - "requireSpaceAfterKeywords": [ - "do", - "for", - "if", - "else", - "switch", - "case", - "try", - "while", - "with", - "return" - ], - "requireSpaceBetweenArguments": true, - "requireSpacesAfterClosingParenthesisInFunctionDeclaration": { - "beforeOpeningRoundBrace": false, - "beforeOpeningCurlyBrace": true - } -} diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index a7314bde146..00000000000 --- a/.jshintrc +++ /dev/null @@ -1,36 +0,0 @@ -{ - "predef": [ - "require", - "define", - "-Map", - "-Promise" - ], - "node" : false, - "browser" : true, - "boss" : true, - "curly": false, - "debug": false, - "devel": false, - "eqeqeq": true, - "evil": true, - "forin": false, - "immed": false, - "laxbreak": false, - "newcap": true, - "noarg": true, - "noempty": false, - "nonbsp": true, - "nonew": false, - "nomen": false, - "onevar": false, - "plusplus": false, - "regexp": false, - "undef": true, - "sub": true, - "strict": false, - "white": false, - "eqnull": true, - "esnext": true, - "unused": "vars", - "loopfunc": true -} diff --git a/.npmignore b/.npmignore index 707b5a5fdbb..38a8d226e1f 100644 --- a/.npmignore +++ b/.npmignore @@ -11,7 +11,7 @@ .editorconfig .ember-cli .gitignore -.jshintrc +.eslintrc.js .travis.yml .watchmanconfig bower.json @@ -21,4 +21,4 @@ testem.js *.gem *.gemspec **/*.rb -node-tests/ \ No newline at end of file +node-tests/ diff --git a/addon/-private/system/coerce-id.js b/addon/-private/system/coerce-id.js index 59726f32e6d..f15c722c954 100644 --- a/addon/-private/system/coerce-id.js +++ b/addon/-private/system/coerce-id.js @@ -5,5 +5,5 @@ // ID into the URL, and if we later try to deserialize that URL and find the // corresponding record, we will not know if it is a string or a number. export default function coerceId(id) { - return id == null || id === '' ? null : id+''; + return id === null || id === undefined || id === '' ? null : id+''; } diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index 54c19820f35..d4c650a1f0d 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -743,7 +743,6 @@ var RootState = { }; function wireState(object, parent, name) { - /*jshint proto:true*/ // TODO: Use Object.create and copy instead object = mixin(parent ? Object.create(parent) : {}, object); object.parentState = parent; diff --git a/addon/-private/system/ordered-set.js b/addon/-private/system/ordered-set.js index 4c3a36ec162..d09a1451871 100644 --- a/addon/-private/system/ordered-set.js +++ b/addon/-private/system/ordered-set.js @@ -27,7 +27,7 @@ OrderedSet.prototype.addWithIndex = function(obj, idx) { presenceSet[guid] = true; - if (idx === undefined || idx == null) { + if (idx === undefined || idx === null) { list.push(obj); } else { list.splice(idx, 0, obj); diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 7741feba944..18265cd5151 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -580,13 +580,14 @@ export const RelationshipsClassMethodsMixin = Ember.Mixin.create({ let knownKey = knownSide.key; let knownKind = knownSide.kind; let inverse = this.inverseFor(knownKey, store); - let key, otherKind; + // let key; + let otherKind; if (!inverse) { return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone'; } - key = inverse.name; + // key = inverse.name; otherKind = inverse.kind; if (otherKind === 'belongsTo') { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index cf1850fbdf9..48dff663447 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1996,7 +1996,7 @@ Store = Service.extend({ _pushInternalModel(data) { var modelName = data.type; - assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id != null && data.id !== ''); + assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id !== null && data.id !== undefined && data.id !== ''); assert(`You tried to push data with a type '${modelName}' but no model could be found with that name.`, this._hasModelFor(modelName)); runInDebug(() => { diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index b6182e6a2c1..14ac90b6c90 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -914,18 +914,18 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { if (isEnabled('ds-extended-errors')) { switch (status) { - case 401: - return new UnauthorizedError(errors, detailedMessage); - case 403: - return new ForbiddenError(errors, detailedMessage); - case 404: - return new NotFoundError(errors, detailedMessage); - case 409: - return new ConflictError(errors, detailedMessage); - default: - if (status >= 500) { - return new ServerError(errors, detailedMessage); - } + case 401: + return new UnauthorizedError(errors, detailedMessage); + case 403: + return new ForbiddenError(errors, detailedMessage); + case 404: + return new NotFoundError(errors, detailedMessage); + case 409: + return new ConflictError(errors, detailedMessage); + default: + if (status >= 500) { + return new ServerError(errors, detailedMessage); + } } } @@ -1094,7 +1094,9 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { try { json = Ember.$.parseJSON(responseText); - } catch (e) {} + } catch (e) { + // ignored + } return json; }, @@ -1276,9 +1278,10 @@ if (isEnabled('ds-improved-ajax')) { return this.buildURL(type.modelName, ids, snapshots, requestType); case 'findHasMany': - case 'findBelongsTo': + case 'findBelongsTo': { let url = this.buildURL(type.modelName, id, snapshot, requestType); return this.urlPrefix(params.url, url); + } } return this.buildURL(type.modelName, id, snapshot, requestType, query); diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 5534a312fce..ceed5088e5e 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -186,7 +186,6 @@ var RESTSerializer = JSONSerializer.extend({ let modelClass = store.modelFor(modelName); let serializer = store.serializerFor(modelName); - /*jshint loopfunc:true*/ Ember.makeArray(arrayHash).forEach((hash) => { let { data, included } = this._normalizePolymorphicRecord(store, hash, prop, modelClass, serializer); documentHash.data.push(data); @@ -339,7 +338,6 @@ var RESTSerializer = JSONSerializer.extend({ } if (isSingle) { - /*jshint loopfunc:true*/ data.forEach((resource) => { /* @@ -427,7 +425,6 @@ var RESTSerializer = JSONSerializer.extend({ var type = store.modelFor(modelName); var typeSerializer = store.serializerFor(type.modelName); - /*jshint loopfunc:true*/ Ember.makeArray(payload[prop]).forEach((hash) => { let { data, included } = typeSerializer.normalize(type, hash, prop); documentHash.data.push(data); diff --git a/blueprints/adapter-test/index.js b/blueprints/adapter-test/index.js index 2180c9f2ac6..1373dc62c71 100644 --- a/blueprints/adapter-test/index.js +++ b/blueprints/adapter-test/index.js @@ -1,4 +1,4 @@ -/*jshint node:true*/ +/* eslint-env node */ var testInfo = require('ember-cli-test-info'); var useTestFrameworkDetector = require('../test-framework-detector'); diff --git a/blueprints/adapter/index.js b/blueprints/adapter/index.js index 9295dc6fd75..1f8ea57a426 100644 --- a/blueprints/adapter/index.js +++ b/blueprints/adapter/index.js @@ -1,4 +1,4 @@ -/*jshint node:true*/ +/* eslint-env node */ var extendFromApplicationEntity = require('../../lib/utilities/extend-from-application-entity'); diff --git a/blueprints/model-test/index.js b/blueprints/model-test/index.js index c87bc2d652e..5dc0767032a 100644 --- a/blueprints/model-test/index.js +++ b/blueprints/model-test/index.js @@ -1,4 +1,4 @@ -/*jshint node:true*/ +/* eslint-env node */ var ModelBlueprint = require('../model'); var testInfo = require('ember-cli-test-info'); diff --git a/blueprints/model/index.js b/blueprints/model/index.js index cca67b2f30a..4d813b39b59 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -1,4 +1,4 @@ -/*jshint node:true*/ +/* eslint-env node */ var inflection = require('inflection'); var stringUtils = require('ember-cli-string-utils'); diff --git a/blueprints/serializer-test/index.js b/blueprints/serializer-test/index.js index a280df94bc3..3216223b666 100644 --- a/blueprints/serializer-test/index.js +++ b/blueprints/serializer-test/index.js @@ -1,4 +1,4 @@ -/*jshint node:true*/ +/* eslint-env node */ var testInfo = require('ember-cli-test-info'); var useTestFrameworkDetector = require('../test-framework-detector'); diff --git a/blueprints/serializer/index.js b/blueprints/serializer/index.js index 91b57db3976..1e43a8a2fa0 100644 --- a/blueprints/serializer/index.js +++ b/blueprints/serializer/index.js @@ -1,4 +1,4 @@ -/*jshint node:true*/ +/* eslint-env node */ var extendFromApplicationEntity = require('../../lib/utilities/extend-from-application-entity'); diff --git a/blueprints/transform-test/index.js b/blueprints/transform-test/index.js index 9a3394a5cd9..fe0ed6781f6 100644 --- a/blueprints/transform-test/index.js +++ b/blueprints/transform-test/index.js @@ -1,4 +1,4 @@ -/*jshint node:true*/ +/* eslint-env node */ var testInfo = require('ember-cli-test-info'); var useTestFrameworkDetector = require('../test-framework-detector'); diff --git a/blueprints/transform/index.js b/blueprints/transform/index.js index a258ff364ce..a272e5162ed 100644 --- a/blueprints/transform/index.js +++ b/blueprints/transform/index.js @@ -1,4 +1,4 @@ -/*jshint node:true*/ +/* eslint-env node */ module.exports = { description: 'Generates an ember-data value transform.' diff --git a/config/ember-try.js b/config/ember-try.js index 18617f0e40c..f1d73b10491 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -1,4 +1,4 @@ -/*jshint node:true*/ +/* eslint-env node */ module.exports = { scenarios: [ { diff --git a/ember-cli-build.js b/ember-cli-build.js index 43abc781fda..55ec56292ba 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -1,5 +1,4 @@ -/* global require, module */ -/* jshint node: true*/ +/* eslint-env node */ var EmberApp = require('ember-cli/lib/broccoli/ember-addon'); var merge = require('broccoli-merge-trees'); var globals = require('./lib/globals'); @@ -7,10 +6,6 @@ var yuidoc = require('./lib/yuidoc'); module.exports = function(defaults) { var app = new EmberApp(defaults, { - jscsOptions: { - enabled: true, - excludeFiles: ['tests/dummy/config'] - } // Add options here }); diff --git a/index.js b/index.js index b09d5ccc4ed..a64b61301b8 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -/* jshint node: true */ +/* eslint-env node */ 'use strict'; var path = require('path'); diff --git a/lib/enable-optional-features-via-url/index.js b/lib/enable-optional-features-via-url/index.js index f705e66d5d4..968a0373d38 100644 --- a/lib/enable-optional-features-via-url/index.js +++ b/lib/enable-optional-features-via-url/index.js @@ -1,4 +1,4 @@ -/*jshint node:true*/ +/* eslint-env node */ module.exports = { name: 'enable-optional-features-via-url', diff --git a/lib/javascripts.js b/lib/javascripts.js index 2209df30b17..025214e4183 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -1,4 +1,4 @@ -/* jshint node:true */ +/* eslint-env node */ var merge = require('broccoli-merge-trees'); var concat = require('broccoli-concat'); diff --git a/package.json b/package.json index b0638e3ec34..3c63ccd48b7 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,6 @@ "broccoli-asset-rev": "^2.1.2", "broccoli-concat": "0.0.13", "broccoli-funnel": "^1.0.0", - "broccoli-jscs": "^1.1.0", "broccoli-stew": "^1.0.1", "broccoli-string-replace": "^0.1.1", "broccoli-uglify-sourcemap": "^1.0.1", @@ -58,10 +57,10 @@ "ember-cli-app-version": "^1.0.0", "ember-cli-blueprint-test-helpers": "0.11.0", "ember-cli-dependency-checker": "^1.2.0", + "ember-cli-eslint": "1.3.0", "ember-cli-htmlbars": "^1.0.3", "ember-cli-htmlbars-inline-precompile": "^0.2.0", "ember-cli-inject-live-reload": "^1.3.1", - "ember-cli-jshint": "^1.0.0", "ember-cli-internal-test-helpers": "^0.8.1", "ember-cli-pretender": "0.6.0", "ember-cli-qunit": "^1.4.0", diff --git a/testem.js b/testem.js index c9bae137d2f..4cb09405ca0 100644 --- a/testem.js +++ b/testem.js @@ -1,4 +1,4 @@ -/*jshint node:true*/ +/* eslint-env node */ module.exports = { "framework": "qunit", "test_page": "tests/index.html?hidepassed", diff --git a/tests/.eslintrc.js b/tests/.eslintrc.js new file mode 100644 index 00000000000..8520ae6310b --- /dev/null +++ b/tests/.eslintrc.js @@ -0,0 +1,6 @@ +/* global module */ +module.exports = { + rules: { + 'no-console': 0 + }, +}; diff --git a/tests/.jshintrc b/tests/.jshintrc deleted file mode 100644 index ff32395941f..00000000000 --- a/tests/.jshintrc +++ /dev/null @@ -1,32 +0,0 @@ -{ - "predef": [ - "window", - "setTimeout" - ], - "node": false, - "browser": false, - "boss": true, - "curly": true, - "debug": false, - "devel": false, - "eqeqeq": true, - "evil": true, - "forin": false, - "immed": false, - "laxbreak": false, - "newcap": true, - "noarg": true, - "noempty": false, - "nonew": false, - "nomen": false, - "onevar": false, - "plusplus": false, - "regexp": false, - "undef": true, - "sub": true, - "strict": false, - "white": false, - "eqnull": true, - "esnext": true, - "unused": "vars" -} diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index 9cd862b02ca..199a5f7abc0 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -1,4 +1,4 @@ -/* jshint node: true */ +/* eslint-env node */ var fs = require('fs'); var path = require('path'); diff --git a/tests/ember-data-initializers.js b/tests/ember-data-initializers.js index 0dc930de9c4..ff90bb3e79a 100644 --- a/tests/ember-data-initializers.js +++ b/tests/ember-data-initializers.js @@ -1,3 +1,5 @@ +/* eslint no-extra-semi: "off" */ + ;(function() { /* globals Ember */ /* globals DS */ diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index 7a6616f25ae..dfe533356bd 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -83,14 +83,11 @@ test("When all records for a type are requested, a rejection should reject the p } })); - let allRecords; - run(() => { store.findAll('person').then(null, () => { assert.ok(true, "The rejection should get here"); return store.findAll('person'); }).then((all) => { - allRecords = all; assert.equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); assert.equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); }); diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index 0bfd9a14c05..e7f32523dfc 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -1,3 +1,5 @@ +/*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(adam|dave|cersei)" }]*/ + import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 9ff6366f92e..b97a79797cc 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -1,3 +1,5 @@ +/*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(adam|bob|dudu)" }]*/ + import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 9e8c0d0f46b..593ca6accc0 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -6,7 +6,7 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var env, store, User, Message, Post, Contact, Comment, Book, Chapter, Author, NewMessage; +var env, store, User, Message, Post, Comment, Book, Chapter, Author, NewMessage; var get = Ember.get; var run = Ember.run; @@ -451,9 +451,8 @@ test("A record can be created with a resolved belongsTo promise", function(asser env.registry.register('model:group', Group); env.registry.register('model:person', Person); - var group; run(function() { - group = store.push({ + store.push({ data: { id: 1, type: 'group' @@ -623,9 +622,9 @@ test("relationship changes shouldn’t cause async fetches", function(assert) { env.store.modelFor('comment').reopen({ post: DS.belongsTo('post', { async: false }) }); - var post, comment; + var comment; run(function() { - post = env.store.push({ + env.store.push({ data: { id: '1', type: 'post', @@ -839,7 +838,7 @@ testInDebug("Passing a model as type to belongsTo should not work", function(ass assert.expectAssertion(function() { User = DS.Model.extend(); - Contact = DS.Model.extend({ + DS.Model.extend({ user: belongsTo(User, { async: false }) }); }, /The first argument to DS.belongsTo must be a string/); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index ebd2e6f1971..49a46557509 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1,3 +1,5 @@ +/*eslint no-unused-vars: ["error", { "args": "none", "varsIgnorePattern": "(page)" }]*/ + import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index 4bf9f882ee7..96d0be84b55 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -434,9 +434,9 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a has }); var env = setupStore({ post: Post, comment: Comment, user: User }); - var comment, post; + var post; run(function() { - comment = env.store.createRecord('comment'); + env.store.createRecord('comment'); }); assert.expectAssertion(function() { @@ -456,9 +456,9 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a bel }); var env = setupStore({ post: Post, comment: Comment, user: User }); - var user, post; + var post; run(function() { - user = env.store.createRecord('user'); + env.store.createRecord('user'); }); assert.expectAssertion(function() { diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index f2068758895..99ca92d786e 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -1,3 +1,5 @@ +/*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(ada)" }]*/ + import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index 3b32698bfbf..2af63fe7f96 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -255,9 +255,9 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio }); test("Fetching a belongsTo that is set to null removes the record from a relationship - sync", function(assert) { - var account, user; + var user; run(function () { - account = store.push({ + store.push({ data: { id: '2', type: 'account', @@ -266,6 +266,7 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio } } }); + user = store.push({ data: { id: '1', @@ -283,7 +284,8 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio } } }); - account = store.push({ + + store.push({ data: { id: '2', type: 'account', diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index cb43e3addc5..773feab2246 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -869,8 +869,7 @@ test('normalizeResponse respects `included` items (array response)', function(as comments: [ { id: "1", body: "comment 1" } ] - }, - { + }, { id: "2", title: "Post 2", comments: [ diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 4a4a6e7b397..b4cc2f9de9a 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -202,18 +202,12 @@ test("destroying the store correctly cleans everything up", function(assert) { }); function ajaxResponse(value) { - var passedUrl, passedVerb, passedHash; - if (isEnabled('ds-improved-ajax')) { env.adapter._makeRequest = function() { return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); }; } else { env.adapter.ajax = function(url, verb, hash) { - passedUrl = url; - passedVerb = verb; - passedHash = hash; - return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); }; } diff --git a/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js index 646d6bc2edb..ca275677e33 100644 --- a/tests/unit/adapter-errors-test.js +++ b/tests/unit/adapter-errors-test.js @@ -168,9 +168,7 @@ test("errorsArrayToHash for primary data object", function(assert) { }); testInDebug("DS.InvalidError will normalize errors hash will assert", function(assert) { - var error; - assert.expectAssertion(function() { - error = new DS.InvalidError({ name: ['is invalid'] }); + new DS.InvalidError({ name: ['is invalid'] }); }, /expects json-api formatted errors/); }); diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 87d68414090..2ec015a8804 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -74,7 +74,7 @@ test('groupRecordsForFindMany - findMany', function(assert) { }); assert.ok(lengths.every(function(len) { - return len <= maxLength; - }), "Some URLs are longer than " + maxLength + " chars"); + return len <= maxLength; + }), "Some URLs are longer than " + maxLength + " chars"); }); diff --git a/tests/unit/many-array-test.js b/tests/unit/many-array-test.js index 969acd15128..49dc753537a 100644 --- a/tests/unit/many-array-test.js +++ b/tests/unit/many-array-test.js @@ -137,7 +137,8 @@ test("manyArray trigger arrayContentChange functions with the correct values", f } }] }); - var post = store.peekRecord('post', 3); + + store.peekRecord('post', 3); store.push({ data: { @@ -157,7 +158,7 @@ test("manyArray trigger arrayContentChange functions with the correct values", f } }); - post = store.peekRecord('post', 3); + store.peekRecord('post', 3); }); DS.ManyArray.reopen({ arrayContentWillChange: originalArrayContentWillChange, diff --git a/tests/unit/model/relationships-test.js b/tests/unit/model/relationships-test.js index 751acb84407..f229c451c14 100644 --- a/tests/unit/model/relationships-test.js +++ b/tests/unit/model/relationships-test.js @@ -29,11 +29,9 @@ module("unit/model/relationships - DS.Model", { }); test("exposes a hash of the relationships on a model", function(assert) { - var person, occupation; - run(function() { - person = store.createRecord('person'); - occupation = store.createRecord('occupation'); + store.createRecord('person'); + store.createRecord('occupation'); }); var relationships = get(Person, 'relationships'); diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index 80bf52b3458..76394b406b9 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -405,12 +405,12 @@ testInDebug("belongsTo gives a warning when provided with a serialize option", f }); run(function() { - store.findRecord('person', 1).then(assert.wait(function(person) { - assert.expectWarning(function() { - get(person, 'hobby'); - }, /You provided a serialize option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.Serializer and it's implementations/); - })); - }); + store.findRecord('person', 1).then(assert.wait(function(person) { + assert.expectWarning(function() { + get(person, 'hobby'); + }, /You provided a serialize option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.Serializer and it's implementations/); + })); + }); }); testInDebug("belongsTo gives a warning when provided with an embedded option", function(assert) { @@ -457,12 +457,12 @@ testInDebug("belongsTo gives a warning when provided with an embedded option", f }); run(function() { - store.findRecord('person', 1).then(assert.wait(function(person) { - assert.expectWarning(function() { - get(person, 'hobby'); - }, /You provided an embedded option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin/); - })); - }); + store.findRecord('person', 1).then(assert.wait(function(person) { + assert.expectWarning(function() { + get(person, 'hobby'); + }, /You provided an embedded option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin/); + })); + }); }); test("DS.belongsTo should be async by default", function(assert) { diff --git a/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js index 71c6d6b63c1..6c9b25bef39 100644 --- a/tests/unit/store/create-record-test.js +++ b/tests/unit/store/create-record-test.js @@ -4,7 +4,7 @@ import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; -var store, container, Record, Storage; +var store, Record, Storage; var run = Ember.run; module("unit/store/createRecord - Store creating records", { @@ -69,7 +69,6 @@ module("unit/store/createRecord - Store with models by dash", { someThing: DS.Model.extend({ foo: DS.attr('string') }) }); store = env.store; - container = env.container; } }); diff --git a/tests/unit/transform/number-test.js b/tests/unit/transform/number-test.js index 427a1274ef0..60ad23db792 100644 --- a/tests/unit/transform/number-test.js +++ b/tests/unit/transform/number-test.js @@ -2,8 +2,6 @@ import DS from 'ember-data'; import {module, test} from 'qunit'; -/* jshint -W053 */ - module("unit/transform - DS.NumberTransform"); test("#serialize", function(assert) { From 03b34e20521ca285a679b340746d3450e481bcb5 Mon Sep 17 00:00:00 2001 From: Sylvain MINA Date: Fri, 8 Apr 2016 10:19:57 +0200 Subject: [PATCH 1521/2527] During normalization, use property lookup instead of hasOwnProp checks --- addon/serializers/json-api.js | 4 ++-- addon/serializers/json.js | 18 +++++++++--------- addon/serializers/rest.js | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 093cd348989..10253f42a61 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -261,7 +261,7 @@ const JSONAPISerializer = JSONSerializer.extend({ if (resourceHash.attributes) { modelClass.eachAttribute((key) => { let attributeKey = this.keyForAttribute(key, 'deserialize'); - if (resourceHash.attributes.hasOwnProperty(attributeKey)) { + if (resourceHash.attributes[attributeKey] !== undefined) { attributes[key] = resourceHash.attributes[attributeKey]; } }); @@ -307,7 +307,7 @@ const JSONAPISerializer = JSONSerializer.extend({ if (resourceHash.relationships) { modelClass.eachRelationship((key, relationshipMeta) => { let relationshipKey = this.keyForRelationship(key, relationshipMeta.kind, 'deserialize'); - if (resourceHash.relationships.hasOwnProperty(relationshipKey)) { + if (resourceHash.relationships[relationshipKey] !== undefined) { let relationshipHash = resourceHash.relationships[relationshipKey]; relationships[key] = this.extractRelationship(relationshipHash); diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 9c2ee4d0e95..ef4ca3a9bbc 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -563,7 +563,7 @@ var JSONSerializer = Serializer.extend({ modelClass.eachAttribute((key) => { attributeKey = this.keyForAttribute(key, 'deserialize'); - if (resourceHash.hasOwnProperty(attributeKey)) { + if (resourceHash[attributeKey] !== undefined) { attributes[key] = resourceHash[attributeKey]; } }); @@ -659,7 +659,7 @@ var JSONSerializer = Serializer.extend({ modelClass.eachRelationship((key, relationshipMeta) => { let relationship = null; let relationshipKey = this.keyForRelationship(key, relationshipMeta.kind, 'deserialize'); - if (resourceHash.hasOwnProperty(relationshipKey)) { + if (resourceHash[relationshipKey] !== undefined) { let data = null; let relationshipHash = resourceHash[relationshipKey]; if (relationshipMeta.kind === 'belongsTo') { @@ -685,7 +685,7 @@ var JSONSerializer = Serializer.extend({ } let linkKey = this.keyForLink(key, relationshipMeta.kind); - if (resourceHash.links && resourceHash.links.hasOwnProperty(linkKey)) { + if (resourceHash.links && resourceHash.links[linkKey] !== undefined) { let related = resourceHash.links[linkKey]; relationship = relationship || {}; relationship.links = { related }; @@ -721,7 +721,7 @@ var JSONSerializer = Serializer.extend({ typeClass.eachAttribute((key) => { payloadKey = this.keyForAttribute(key, 'deserialize'); if (key === payloadKey) { return; } - if (!hash.hasOwnProperty(payloadKey)) { return; } + if (hash[payloadKey] === undefined) { return; } hash[key] = hash[payloadKey]; delete hash[payloadKey]; @@ -740,7 +740,7 @@ var JSONSerializer = Serializer.extend({ typeClass.eachRelationship((key, relationship) => { payloadKey = this.keyForRelationship(key, relationship.kind, 'deserialize'); if (key === payloadKey) { return; } - if (!hash.hasOwnProperty(payloadKey)) { return; } + if (hash[payloadKey] === undefined) { return; } hash[key] = hash[payloadKey]; delete hash[payloadKey]; @@ -760,7 +760,7 @@ var JSONSerializer = Serializer.extend({ for (key in attrs) { normalizedKey = payloadKey = this._getMappedKey(key, modelClass); - if (!hash.hasOwnProperty(payloadKey)) { continue; } + if (hash[payloadKey] === undefined) { continue; } if (get(modelClass, 'attributes').has(key)) { normalizedKey = this.keyForAttribute(key); @@ -1273,7 +1273,7 @@ var JSONSerializer = Serializer.extend({ @param {Object} payload */ extractMeta(store, modelClass, payload) { - if (payload && payload.hasOwnProperty('meta')) { + if (payload && payload['meta'] !== undefined) { let meta = payload.meta; delete payload.meta; return meta; @@ -1373,7 +1373,7 @@ var JSONSerializer = Serializer.extend({ typeClass.eachAttribute((name) => { let key = this.keyForAttribute(name, 'deserialize'); - if (key !== name && payload.hasOwnProperty(key)) { + if (key !== name && payload[key] !== undefined) { payload[name] = payload[key]; delete payload[key]; } @@ -1381,7 +1381,7 @@ var JSONSerializer = Serializer.extend({ typeClass.eachRelationship((name) => { let key = this.keyForRelationship(name, 'deserialize'); - if (key !== name && payload.hasOwnProperty(key)) { + if (key !== name && payload[key] !== undefined) { payload[name] = payload[key]; delete payload[key]; } diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index ceed5088e5e..2093f7680f0 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -816,7 +816,7 @@ var RESTSerializer = JSONSerializer.extend({ var isPolymorphic = relationshipMeta.options.polymorphic; var typeProperty = this.keyForPolymorphicType(key, relationshipType, 'deserialize'); - if (isPolymorphic && resourceHash.hasOwnProperty(typeProperty) && typeof relationshipHash !== 'object') { + if (isPolymorphic && resourceHash[typeProperty] !== undefined && typeof relationshipHash !== 'object') { if (isEnabled("ds-payload-type-hooks")) { From dcafebfc5a00ac6b4e1ea805a70e9ee37628e606 Mon Sep 17 00:00:00 2001 From: zigahertz Date: Mon, 28 Mar 2016 11:48:07 -0700 Subject: [PATCH 1522/2527] adds deprecation warning and returns native Date.parse method --- addon/-private/ext/date.js | 49 +++++++++++++++++++------------ addon/-private/transforms/date.js | 4 +-- tests/unit/model-test.js | 3 +- tests/unit/transform/date-test.js | 17 +++++++++-- 4 files changed, 49 insertions(+), 24 deletions(-) diff --git a/addon/-private/ext/date.js b/addon/-private/ext/date.js index 8bcc667e9a4..0430f7304f0 100644 --- a/addon/-private/ext/date.js +++ b/addon/-private/ext/date.js @@ -3,29 +3,14 @@ */ import Ember from 'ember'; +import { deprecate } from 'ember-data/-private/debug'; -/** - Date.parse with progressive enhancement for ISO 8601 - - © 2011 Colin Snover - - Released under MIT license. - - @class Date - @namespace Ember - @static -*/ Ember.Date = Ember.Date || {}; var origParse = Date.parse; var numericKeys = [1, 4, 5, 6, 7, 10, 11]; -/** - @method parse - @param {Date} date - @return {Number} timestamp -*/ -Ember.Date.parse = function (date) { +export const parseDate = function (date) { var timestamp, struct; var minutesOffset = 0; @@ -59,6 +44,34 @@ Ember.Date.parse = function (date) { return timestamp; }; +Ember.Date.parse = function (date) { + // throw deprecation + deprecate(`Ember.Date.parse is deprecated because Safari 5-, IE8-, and + Firefox 3.6- are no longer supported (see + https://github.com/csnover/js-iso8601 for the history of this issue). + Please use Date.parse instead`, false, { + id: 'ds.ember.date.parse-deprecate', + until: '3.0.0' + }); + + return parseDate(date); +}; + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Date) { - Date.parse = Ember.Date.parse; + deprecate(`Overriding Date.parse with Ember.Date.parse is deprecated. Please set ENV.EmberENV.EXTEND_PROTOTYPES.Date to false in config/environment.js + + +// config/environment.js +ENV = { + EmberENV: { + EXTEND_PROTOTYPES: { + Date: false, + } + } +} +`, false, { + id: 'ds.date.parse-deprecate', + until: '3.0.0' + }); + Date.parse = parseDate; } diff --git a/addon/-private/transforms/date.js b/addon/-private/transforms/date.js index 66ac73996e9..698be1b1910 100644 --- a/addon/-private/transforms/date.js +++ b/addon/-private/transforms/date.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import "ember-data/-private/ext/date"; +import { parseDate } from "ember-data/-private/ext/date"; /** The `DS.DateTransform` class is used to serialize and deserialize @@ -28,7 +28,7 @@ export default Transform.extend({ var type = typeof serialized; if (type === "string") { - return new Date(Ember.Date.parse(serialized)); + return new Date(parseDate(serialized)); } else if (type === "number") { return new Date(serialized); } else if (serialized === null || serialized === undefined) { diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 5d709d48760..0058c01c08a 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -5,6 +5,7 @@ import testInDebug from 'dummy/tests/helpers/test-in-debug'; import QUnit, {module, test} from 'qunit'; import DS from 'ember-data'; import isEnabled from 'ember-data/-private/features'; +import { parseDate } from "ember-data/-private/ext/date"; const AssertionPrototype = QUnit.assert; @@ -949,7 +950,7 @@ test("a DS.Model can describe Date attributes", function(assert) { assert.converts('date', undefined, undefined); var dateString = "2011-12-31T00:08:16.000Z"; - var date = new Date(Ember.Date.parse(dateString)); + var date = new Date(parseDate(dateString)); var Person = DS.Model.extend({ diff --git a/tests/unit/transform/date-test.js b/tests/unit/transform/date-test.js index 0734edc113c..ca991fbc766 100644 --- a/tests/unit/transform/date-test.js +++ b/tests/unit/transform/date-test.js @@ -1,14 +1,17 @@ -import Ember from 'ember'; - import {module, test} from 'qunit'; import DS from 'ember-data'; +import Ember from 'ember'; + +import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import { parseDate } from "ember-data/-private/ext/date"; module("unit/transform - DS.DateTransform"); var dateString = "2015-01-01T00:00:00.000Z"; -var dateInMillis = Ember.Date.parse(dateString); +var dateInMillis = parseDate(dateString); var date = new Date(dateInMillis); +var run = Ember.run; test("#serialize", function(assert) { var transform = new DS.DateTransform(); @@ -35,3 +38,11 @@ test("#deserialize", function(assert) { assert.equal(transform.deserialize(null), null); assert.equal(transform.deserialize(undefined), null); }); + +testInDebug('Ember.Date.parse has been deprecated', function(assert) { + run(function() { + assert.expectDeprecation(function() { + Ember.Date.parse(dateString); + }, /Ember.Date.parse is deprecated/); + }); +}); From 17b1f1c08cfd00ad03940c5593e25d3581c13ad6 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 24 May 2016 06:11:29 -0400 Subject: [PATCH 1523/2527] Add tests for the datetransform with a timezone --- addon/-private/ext/date.js | 18 +++++++++--------- addon/-private/transforms/date.js | 1 - tests/unit/transform/date-test.js | 11 +++++++++++ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/addon/-private/ext/date.js b/addon/-private/ext/date.js index 0430f7304f0..532f2d00130 100644 --- a/addon/-private/ext/date.js +++ b/addon/-private/ext/date.js @@ -47,12 +47,12 @@ export const parseDate = function (date) { Ember.Date.parse = function (date) { // throw deprecation deprecate(`Ember.Date.parse is deprecated because Safari 5-, IE8-, and - Firefox 3.6- are no longer supported (see - https://github.com/csnover/js-iso8601 for the history of this issue). - Please use Date.parse instead`, false, { - id: 'ds.ember.date.parse-deprecate', - until: '3.0.0' - }); + Firefox 3.6- are no longer supported (see + https://github.com/csnover/js-iso8601 for the history of this issue). + Please use Date.parse instead`, false, { + id: 'ds.ember.date.parse-deprecate', + until: '3.0.0' + }); return parseDate(date); }; @@ -70,8 +70,8 @@ ENV = { } } `, false, { - id: 'ds.date.parse-deprecate', - until: '3.0.0' - }); + id: 'ds.date.parse-deprecate', + until: '3.0.0' +}); Date.parse = parseDate; } diff --git a/addon/-private/transforms/date.js b/addon/-private/transforms/date.js index 698be1b1910..1907e9effb6 100644 --- a/addon/-private/transforms/date.js +++ b/addon/-private/transforms/date.js @@ -1,4 +1,3 @@ -import Ember from 'ember'; import { parseDate } from "ember-data/-private/ext/date"; /** diff --git a/tests/unit/transform/date-test.js b/tests/unit/transform/date-test.js index ca991fbc766..62da125bba5 100644 --- a/tests/unit/transform/date-test.js +++ b/tests/unit/transform/date-test.js @@ -39,6 +39,17 @@ test("#deserialize", function(assert) { assert.equal(transform.deserialize(undefined), null); }); +test("#deserialize with different offset formats", function(assert) { + var transform = new DS.DateTransform(); + var dateString = '2003-05-24T23:00:00.000+0000'; + var dateStringColon = '2013-03-15T23:22:00.000+00:00'; + var dateStringShortOffset = '2016-12-02T17:30:00.000+00'; + + assert.equal(transform.deserialize(dateString).getTime(), 1053817200000); + assert.equal(transform.deserialize(dateStringShortOffset).getTime(), 1480699800000); + assert.equal(transform.deserialize(dateStringColon).getTime(), 1363389720000); +}); + testInDebug('Ember.Date.parse has been deprecated', function(assert) { run(function() { assert.expectDeprecation(function() { From 1d9d2c0f0f8838cafec40239dac4717677091329 Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 24 May 2016 21:31:32 +0300 Subject: [PATCH 1524/2527] Add link to PR of ds-payload-type-hooks feature --- FEATURES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FEATURES.md b/FEATURES.md index 5381ba7b839..b2afd1772a8 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -66,7 +66,7 @@ entry in `config/features.json`. * [409] `DS.ConflictError` * [500] `DS.ServerError` -- `ds-payload-type-hooks` +- `ds-payload-type-hooks` [#4318](https://github.com/emberjs/data/pull/4318) Adds two new hooks `modelNameFromPayloadType` and `payloadTypeFromModelName` hooks to the serializers. They are used to map a custom type in the payload From 960f8372659ded0323bb40d4ea751b02eebed59e Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 24 May 2016 20:55:19 +0300 Subject: [PATCH 1525/2527] [FEATURE ds-overhaul-references] Fix inconsistencies with Reference#push `push()` for a belongs-to and has-many reference accepts weird formats, where it basically should only support a JSON-API document. If this feature is enabled, it adds deprecation messages if something different than a JSON-API document is pushed. --- FEATURES.md | 19 ++ .../-private/system/references/belongs-to.js | 9 +- addon/-private/system/references/has-many.js | 51 ++++- config/features.json | 1 + .../integration/references/belongs-to-test.js | 7 +- tests/integration/references/has-many-test.js | 175 ++++++++++++++++-- 6 files changed, 233 insertions(+), 29 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 5381ba7b839..a2020313fdf 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -114,3 +114,22 @@ entry in `config/features.json`. jsonApiSerializer.modelNameFromPayloadType("api::v1::administrator"); jsonApiSerializer.modelNameFromPayloadType("api::v1::super-user"); ``` + +- `ds-overhaul-references` [#4398](https://github.com/emberjs/data/pull/4398) + + This tackles some inconsistencies within `push()` on references. It should + only be used to push a JSON-API payload. The following use cases are + addressed and deprecated: + + - `BelongsToReference#push()` accepts a `DS.Model` + - `HasManyReference#push()` accepts a plain array + - `HasManyReference#push()` accepts a pseudo-JSON-API format: + + ```js + { + data: [ + { data: { type: 'model', id: 1 } } + ] + } + ``` + diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 9684af001b3..603a0c34140 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -2,7 +2,8 @@ import Model from 'ember-data/model'; import Ember from 'ember'; import Reference from './reference'; -import { assertPolymorphicType } from "ember-data/-private/debug"; +import isEnabled from 'ember-data/-private/features'; +import { assertPolymorphicType, deprecate } from "ember-data/-private/debug"; var BelongsToReference = function(store, parentInternalModel, belongsToRelationship) { this._super$constructor(store, parentInternalModel); @@ -43,6 +44,12 @@ BelongsToReference.prototype.push = function(objectOrPromise) { var record; if (data instanceof Model) { + if (isEnabled('ds-overhaul-references')) { + deprecate("BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead.", false, { + id: 'ds.references.belongs-to.push-record', + until: '3.0' + }); + } record = data; } else { record = this.store.push(data); diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index dc5fe98d616..8efc18fd6d1 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -2,9 +2,12 @@ import Ember from 'ember'; import Reference from './reference'; import { assertPolymorphicType, + deprecate, runInDebug } from 'ember-data/-private/debug'; +import isEnabled from 'ember-data/-private/features'; + const get = Ember.get; var HasManyReference = function(store, parentInternalModel, hasManyRelationship) { @@ -48,20 +51,54 @@ HasManyReference.prototype.meta = function() { HasManyReference.prototype.push = function(objectOrPromise) { return Ember.RSVP.resolve(objectOrPromise).then((payload) => { var array = payload; + + if (isEnabled("ds-overhaul-references")) { + deprecate("HasManyReference#push(array) is deprecated. Push a JSON-API document instead.", !Array.isArray(payload), { + id: 'ds.references.has-many.push-array', + until: '3.0' + }); + } + + let useLegacyArrayPush = true; if (typeof payload === "object" && payload.data) { array = payload.data; + useLegacyArrayPush = array.length && array[0].data; + + if (isEnabled('ds-overhaul-references')) { + deprecate("HasManyReference#push() expects a valid JSON-API document.", !useLegacyArrayPush, { + id: 'ds.references.has-many.push-invalid-json-api', + until: '3.0' + }); + } + } + + if (!isEnabled('ds-overhaul-references')) { + useLegacyArrayPush = true; } - var internalModels = array.map((obj) => { - var record = this.store.push(obj); + let internalModels; + if (useLegacyArrayPush) { + internalModels = array.map((obj) => { + var record = this.store.push(obj); - runInDebug(() => { - var relationshipMeta = this.hasManyRelationship.relationshipMeta; - assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel); + runInDebug(() => { + var relationshipMeta = this.hasManyRelationship.relationshipMeta; + assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel); + }); + + return record._internalModel; }); + } else { + let records = this.store.push(payload); + internalModels = Ember.A(records).mapBy('_internalModel'); - return record._internalModel; - }); + runInDebug(() => { + internalModels.forEach((internalModel) => { + var relationshipMeta = this.hasManyRelationship.relationshipMeta; + assertPolymorphicType(this.internalModel, relationshipMeta, internalModel); + }); + }); + } this.hasManyRelationship.computeChanges(internalModels); diff --git a/config/features.json b/config/features.json index 24cd135bcad..786c106b184 100644 --- a/config/features.json +++ b/config/features.json @@ -5,5 +5,6 @@ "ds-serialize-ids-and-types": true, "ds-extended-errors": null, "ds-links-in-record-array": null, + "ds-overhaul-references": null, "ds-payload-type-hooks": null } diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index 77031ff17ad..fe96eedac1c 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -2,6 +2,7 @@ import DS from 'ember-data'; import Ember from 'ember'; import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import isEnabled from 'ember-data/-private/features'; import { module, test } from 'qunit'; var get = Ember.get; @@ -163,7 +164,7 @@ test("push(object)", function(assert) { }); }); -test("push(record)", function(assert) { +testInDebug("push(record)", function(assert) { var done = assert.async(); var person, family; @@ -193,6 +194,10 @@ test("push(record)", function(assert) { var familyReference = person.belongsTo('family'); run(function() { + if (isEnabled('ds-overhaul-references')) { + assert.expectDeprecation("BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead."); + } + familyReference.push(family).then(function(record) { assert.ok(Family.detectInstance(record), "push resolves with the referenced record"); assert.equal(get(record, 'name'), "Coreleone", "name is set"); diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 5e165c99eb0..7bee6b35109 100644 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -1,6 +1,7 @@ import DS from 'ember-data'; import Ember from 'ember'; import setupStore from 'dummy/tests/helpers/store'; +import isEnabled from 'ember-data/-private/features'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; @@ -126,7 +127,7 @@ test("HasManyReference#meta() returns the most recent meta for the relationship" assert.deepEqual(personsReference.meta(), { foo: true }); }); -test("push(array)", function(assert) { +testInDebug("push(array)", function(assert) { var done = assert.async(); var family; @@ -149,6 +150,10 @@ test("push(array)", function(assert) { var personsReference = family.hasMany('persons'); + if (isEnabled('ds-overhaul-references')) { + assert.expectDeprecation("HasManyReference#push(array) is deprecated. Push a JSON-API document instead."); + } + run(function() { var data = [ { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, @@ -166,7 +171,7 @@ test("push(array)", function(assert) { }); }); -test("push(array) works with polymorphic type", function(assert) { +testInDebug("push(array) works with polymorphic type", function(assert) { var done = assert.async(); env.registry.register('model:mafia-boss', Person.extend()); @@ -184,11 +189,15 @@ test("push(array) works with polymorphic type", function(assert) { var personsReference = family.hasMany('persons'); run(() => { - var data = { - data: [ - { data: { type: 'mafia-boss', id: 1, attributes: { name: "Vito" } } } - ] - }; + var data = [ + { data: { type: 'mafia-boss', id: 1, attributes: { name: "Vito" } } } + ]; + + if (isEnabled('ds-overhaul-references')) { + assert.expectDeprecation("HasManyReference#push(array) is deprecated. Push a JSON-API document instead."); + } else { + assert.expectNoDeprecation(); + } personsReference.push(data).then(function(records) { assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); @@ -213,20 +222,24 @@ testInDebug("push(array) asserts polymorphic type", function(assert) { var personsReference = family.hasMany('persons'); + if (isEnabled('ds-overhaul-references')) { + assert.expectDeprecation("HasManyReference#push(array) is deprecated. Push a JSON-API document instead."); + } else { + assert.expectNoDeprecation(); + } + assert.expectAssertion(() => { run(() => { - var data = { - data: [ - { data: { type: 'family', id: 1 } } - ] - }; + var data = [ + { data: { type: 'family', id: 1 } } + ]; personsReference.push(data); }); }, "You cannot add a record of type 'family' to the 'family.persons' relationship (only 'person' allowed)"); }); -test("push(object) supports JSON-API payload", function(assert) { +testInDebug("push(object) supports legacy, non-JSON-API-conform payload", function(assert) { var done = assert.async(); var family; @@ -250,14 +263,20 @@ test("push(object) supports JSON-API payload", function(assert) { var personsReference = family.hasMany('persons'); run(function() { - var data = { + var payload = { data: [ { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } ] }; - personsReference.push(data).then(function(records) { + if (isEnabled('ds-overhaul-references')) { + assert.expectDeprecation("HasManyReference#push() expects a valid JSON-API document."); + } else { + assert.expectNoDeprecation(); + } + + personsReference.push(payload).then(function(records) { assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); assert.equal(get(records, 'length'), 2); assert.equal(records.objectAt(0).get('name'), "Vito"); @@ -268,6 +287,110 @@ test("push(object) supports JSON-API payload", function(assert) { }); }); +if (isEnabled('ds-overhaul-references')) { + test("push(object) supports JSON-API payload", function(assert) { + var done = assert.async(); + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] + } + } + } + }); + }); + + var personsReference = family.hasMany('persons'); + + run(function() { + var payload = { + data: [ + { type: 'person', id: 1, attributes: { name: "Vito" } }, + { type: 'person', id: 2, attributes: { name: "Michael" } } + ] + }; + + personsReference.push(payload).then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito"); + assert.equal(records.objectAt(1).get('name'), "Michael"); + + done(); + }); + }); + }); + + test("push(object) works with polymorphic type", function(assert) { + var done = assert.async(); + + env.registry.register('model:mafia-boss', Person.extend()); + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1 + } + }); + }); + + var personsReference = family.hasMany('persons'); + + run(() => { + var payload = { + data: [ + { type: 'mafia-boss', id: 1, attributes: { name: "Vito" } } + ] + }; + + personsReference.push(payload).then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 1); + assert.equal(records.objectAt(0).get('name'), "Vito"); + + done(); + }); + }); + }); + + test("push(object) asserts polymorphic type", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1 + } + }); + }); + + var personsReference = family.hasMany('persons'); + + assert.expectAssertion(() => { + run(() => { + var payload = { + data: [ + { type: 'family', id: 1 } + ] + }; + + personsReference.push(payload); + }); + }, "You cannot add a record of type 'family' to the 'family.persons' relationship (only 'person' allowed)"); + }); +} + test("push(promise)", function(assert) { var done = assert.async(); @@ -296,11 +419,23 @@ test("push(promise)", function(assert) { assert.ok(push.then, 'HasManyReference.push returns a promise'); run(function() { - var data = [ - { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, - { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } - ]; - deferred.resolve(data); + var payload = { + data: [ + { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, + { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } + ] + }; + + if (isEnabled('ds-overhaul-references')) { + payload = { + data: [ + { type: 'person', id: 1, attributes: { name: "Vito" } }, + { type: 'person', id: 2, attributes: { name: "Michael" } } + ] + }; + } + + deferred.resolve(payload); }); run(function() { From fe076470b77e2d6abd614bc8710c37fb31b64e3b Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Wed, 25 May 2016 04:40:36 -0400 Subject: [PATCH 1526/2527] Rebase 4343 (#4397) * [BUGFIX beta] Avoid using `Ember.lookup` to setup global. `Ember.lookup` is an internal mechanism used by older versions of Ember to "lookup" things on the global scope. In Ember 2.7 usage of `Ember.lookup` will be deprecated, so this removes our need for it. This also adds a deprecation when using the global `DS` (suggesting imports instead). * Explicitly name the namespace Since the DS namespace is not added to Ember.lookup anymore, the name for the namespace needs to be defined explicitly. * Disable the window.DS warning in the bower build --- addon/-private/core.js | 5 +++-- addon/-private/global.js | 19 +++++++++++++++++++ addon/index.js | 17 ++++++++++++++++- lib/ds-global.js | 9 +++++++++ lib/javascripts.js | 4 +++- 5 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 addon/-private/global.js create mode 100644 lib/ds-global.js diff --git a/addon/-private/core.js b/addon/-private/core.js index 05c892d99cc..86b8aaf51f6 100644 --- a/addon/-private/core.js +++ b/addon/-private/core.js @@ -17,8 +17,9 @@ import VERSION from 'ember-data/version'; @type String @static */ -var DS = Ember.Namespace.create({ - VERSION: VERSION +const DS = Ember.Namespace.create({ + VERSION: VERSION, + name: "DS" }); if (Ember.libraries) { diff --git a/addon/-private/global.js b/addon/-private/global.js new file mode 100644 index 00000000000..be3d0e4a4c1 --- /dev/null +++ b/addon/-private/global.js @@ -0,0 +1,19 @@ +/* globals global, window, self */ + +// originally from https://github.com/emberjs/ember.js/blob/c0bd26639f50efd6a03ee5b87035fd200e313b8e/packages/ember-environment/lib/global.js + +// from lodash to catch fake globals +function checkGlobal(value) { + return (value && value.Object === Object) ? value : undefined; +} + +// element ids can ruin global miss checks +function checkElementIdShadowing(value) { + return (value && value.nodeType === undefined) ? value : undefined; +} + +// export real global +export default checkGlobal(checkElementIdShadowing(typeof global === 'object' && global)) || + checkGlobal(typeof self === 'object' && self) || + checkGlobal(typeof window === 'object' && window) || + new Function('return this')(); // eval outside of strict mode diff --git a/addon/index.js b/addon/index.js index 8701df0ccc3..58aaa3449aa 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,5 +1,8 @@ import Ember from "ember"; +import { deprecate } from "ember-data/-private/debug"; import isEnabled from "ember-data/-private/features"; +import global from "ember-data/-private/global"; + /** Ember Data @module ember-data @@ -163,6 +166,18 @@ Object.defineProperty(DS, 'normalizeModelName', { value: normalizeModelName }); -Ember.lookup.DS = DS; +Object.defineProperty(global, 'DS', { + configurable: true, + get() { + deprecate( + 'Using the global version of DS is deprecated. Please either import ' + + 'the specific modules needed or `import DS from \'ember-data\';`.', + false, + { id: 'ember-data.global-ds', until: '3.0.0' } + ); + + return DS; + } +}); export default DS; diff --git a/lib/ds-global.js b/lib/ds-global.js new file mode 100644 index 00000000000..8208c950821 --- /dev/null +++ b/lib/ds-global.js @@ -0,0 +1,9 @@ +;(function() { + var global = require('ember-data/-private/global').default; + var DS = require('ember-data').default; + Object.defineProperty(global, 'DS', { + get: function() { + return DS; + } + }); +})(); diff --git a/lib/javascripts.js b/lib/javascripts.js index 025214e4183..3c37a8bdd9b 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -44,6 +44,8 @@ function collapse(tree, outputFileName) { var emberDataShimsPath = path.join(__dirname, 'ember-data-shims.js'); var emberDataShims = fs.readFileSync(emberDataShimsPath, { encoding: 'utf8' }); + var dsGlobalPath = path.join(__dirname, 'ds-global.js'); + var dsGlobal = fs.readFileSync(dsGlobalPath, { encoding: 'utf8' }); var emberDataInitialierPath = path.join(__dirname, '../tests/ember-data-initializers.js'); var emberDataInitialier = fs.readFileSync(emberDataInitialierPath, { encoding: 'utf8' }); @@ -52,7 +54,7 @@ function collapse(tree, outputFileName) { inputFiles: ['license.js', 'loader.js', '**/*.js'], outputFile: '/' + outputFileName, header: '(function(){ \n"use strict";\n', - footer: '\nrequire("ember-data");\n})();\n' + emberDataShims + emberDataInitialier + footer: '\nrequire("ember-data");\n' + dsGlobal + '})();\n' + emberDataShims + emberDataInitialier }); } From e96570393c4d49240e944e807f434cea4f2159df Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 26 May 2016 10:25:01 +0300 Subject: [PATCH 1527/2527] [BUGFIX beta] Correctly coalesce URI encoded ids When checking if the URL of a record is of the format `...something/:id`, we need to decode the last part of the path before comparing, since the part in the URL is encoded when the URL is constructed within buildURL. --- addon/adapters/rest.js | 8 +++- .../group-records-for-find-many-test.js | 43 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 14ac90b6c90..ebfc66aede8 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -794,10 +794,14 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { var url = this.buildURL(snapshot.modelName, snapshot.id, snapshot); var expandedURL = url.split('/'); - //Case when the url is of the format ...something/:id + // Case when the url is of the format ...something/:id + // We are decodeURIComponent-ing the lastSegment because if it represents + // the id, it has been encodeURIComponent-ified within `buildURL`. If we + // don't do this, then records with id having special characters are not + // coalesced correctly (see GH #4190 for the reported bug) var lastSegment = expandedURL[expandedURL.length - 1]; var id = snapshot.id; - if (lastSegment === id) { + if (decodeURIComponent(lastSegment) === id) { expandedURL[expandedURL.length - 1] = ""; } else if (endsWith(lastSegment, '?id=' + id)) { //Case when the url is of the format ...something?id=:id diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 2ec015a8804..00748933f4d 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -9,9 +9,12 @@ import isEnabled from 'ember-data/-private/features'; var GroupsAdapter, Store; var maxLength = -1; var lengths = Ember.A([]); +var requests; module("unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAdapter#groupRecordsForFindMany", { beforeEach() { + requests = []; + GroupsAdapter = DS.RESTAdapter.extend({ coalesceFindRequests: true, @@ -24,6 +27,11 @@ module("unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda if (isEnabled('ds-improved-ajax')) { GroupsAdapter.reopen({ _makeRequest(request) { + requests.push({ + url: request.url, + ids: request.data.ids + }); + var queryString = request.data.ids.map(function(i) { return encodeURIComponent('ids[]') + '=' + encodeURIComponent(i); }).join('&'); @@ -41,6 +49,11 @@ module("unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda } else { GroupsAdapter.reopen({ ajax(url, type, options) { + requests.push({ + url, + ids: options.data.ids + }); + var queryString = options.data.ids.map(function(i) { return encodeURIComponent('ids[]') + '=' + encodeURIComponent(i); }).join('&'); @@ -62,6 +75,10 @@ module("unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda testRecord: DS.Model.extend() }); + }, + + afterEach() { + requests = null; } }); @@ -78,3 +95,29 @@ test('groupRecordsForFindMany - findMany', function(assert) { }), "Some URLs are longer than " + maxLength + " chars"); }); + +test('groupRecordsForFindMany works for encodeURIComponent-ified ids', function(assert) { + Ember.run(function() { + Store.findRecord('testRecord', 'my-id:1'); + Store.findRecord('testRecord', 'my-id:2'); + }); + + assert.equal(requests.length, 1); + assert.equal(requests[0].url, '/testRecords'); + assert.deepEqual(requests[0].ids, ['my-id:1', 'my-id:2']); +}); + +test('_stripIDFromURL works with id being encoded - #4190', function(assert) { + let record; + Ember.run(function() { + record = Store.createRecord('testRecord', { + id: "id:123" + }); + }); + + let adapter = Store.adapterFor('testRecord'); + let snapshot = record._internalModel.createSnapshot(); + let strippedUrl = adapter._stripIDFromURL(Store, snapshot); + + assert.equal(strippedUrl, '/testRecords/'); +}); From 8337df0e365dced1845a1fad7e0fc946bc663314 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Thu, 26 May 2016 10:30:04 -0400 Subject: [PATCH 1528/2527] Add a note to the changelog about the addon upgrade Closes https://github.com/emberjs/data/issues/3921 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec2421949a0..a15172b2360 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -202,6 +202,11 @@ - [#4066](https://github.com/emberjs/data/pull/4066) Use correct version number when used as an addon. ### Release 2.3.0 (January 12, 2016) + +Ember Data 2.3 is now published as and Ember CLI addon in addition to a bower package. +See the [release notes](http://emberjs.com/blog/2016/01/12/ember-data-2-3-released.html#toc_changes-in-ember-data-2-3) +for instruction on how to upgrade your Ember CLI project to take advantage of the Ember Data addon. + - [#4039](https://github.com/emberjs/data/pull/4039) Replace calls to store.find with store.findRecord - [#4042](https://github.com/emberjs/data/pull/4042) [BUGFIX beta] prevent calls to store.query leaking - [#4048](https://github.com/emberjs/data/pull/4048) Strip stuff from addon before it is added to app From 387630db5e7daec6aac7ef8c6172358a3bd6394c Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 26 May 2016 11:19:59 -0400 Subject: [PATCH 1529/2527] [BUGFIX beta] Document the adapterOptions property Closes https://github.com/emberjs/data/issues/4303 --- addon/-private/system/model/model.js | 41 ++++++++++++++++++++ addon/-private/system/store.js | 57 ++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index f42acb0d48f..64d59c3cd39 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -554,6 +554,26 @@ var Model = Ember.Object.extend(Ember.Evented, { }); ``` + If you pass an object on the `adapterOptions` property of the options + argument it will be passed to you adapter via the snapshot + + ```js + record.destroyRecord({ adapterOptions: { subscribe: false } }); + ``` + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + deleteRecord: function(store, type, snapshot) { + if (snapshot.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + @method destroyRecord @param {Object} options @return {Promise} a promise that will be resolved when the adapter returns @@ -699,6 +719,27 @@ var Model = Ember.Object.extend(Ember.Evented, { // Error callback }); ``` + + If you pass an object on the `adapterOptions` property of the options + argument it will be passed to you adapter via the snapshot + + ```js + record.save({ adapterOptions: { subscribe: false } }); + ``` + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + updateRecord: function(store, type, snapshot) { + if (snapshot.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + @method save @param {Object} options @return {Promise} a promise that will be resolved when the adapter returns diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 48dff663447..5e7795d4e38 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -534,6 +534,34 @@ Store = Service.extend({ }); ``` + If you pass an object on the `adapterOptions` property of the options + argument it will be passed to you adapter via the snapshot + + ```app/routes/post/edit.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model: function(params) { + return this.store.findRecord('post', params.post_id, { + adapterOptions: { subscribe: false } + }); + } + }); + ``` + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + findRecord: function(store, type, id, snapshot) { + if (snapshot.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + See [peekRecord](#method_peekRecord) to get the cached version of a record. @method findRecord @@ -1280,6 +1308,35 @@ Store = Service.extend({ }); ``` + If you pass an object on the `adapterOptions` property of the options + argument it will be passed to you adapter via the `snapshotRecordArray` + + ```app/routes/posts.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model: function(params) { + return this.store.findAll('post', { + adapterOptions: { subscribe: false } + }); + } + }); + ``` + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + findAll: function(store, type, sinceToken, snapshotRecordArray) { + if (snapshotRecordArray.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + + See [peekAll](#method_peekAll) to get an array of current records in the store, without waiting until a reload is finished. From 27054dfd2447d65dc639701b2bd161a8e6020bab Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 27 May 2016 15:22:10 -0400 Subject: [PATCH 1530/2527] Log an assertion if the response from createRecord does not have an id and the id was not already provided by the client Closes #4346 --- addon/-private/system/store.js | 2 +- tests/integration/adapter/rest-adapter-test.js | 6 +++--- tests/integration/adapter/store-adapter-test.js | 2 +- tests/integration/client-id-generation-test.js | 2 +- tests/integration/relationships/has-many-test.js | 5 ++++- tests/integration/store-test.js | 15 +++++++++++++++ tests/unit/model-test.js | 2 +- 7 files changed, 26 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 48dff663447..c82a9e71e31 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1634,7 +1634,7 @@ Store = Service.extend({ this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, data); this.updateId(internalModel, data); } - + assert(`Your ${internalModel.type.modelName} record was saved but it does not have an id. Please make the server provides an id in the createRecord response or you are setting the on the client side before saving the record.`, internalModel.id !== null); //We first make sure the primary data has been updated //TODO try to move notification to the user to the end of the runloop internalModel.adapterDidCommit(data); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index d0b1a9ddcf9..d2ab0e33da5 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -328,14 +328,14 @@ test("createRecord - a serializer's primary key and attributes are consulted whe test("createRecord - a serializer's attributes are consulted when building the payload if no id is pre-defined", function(assert) { var post; env.registry.register('serializer:post', DS.RESTSerializer.extend({ - primarykey: '_id_', - attrs: { name: '_name_' } })); - ajaxResponse(); + ajaxResponse({ + post: { '_name_': "The Parley Letter", id: '1' } + }); run(function() { post = store.createRecord('post', { name: "The Parley Letter" }); diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index eec8b75b16b..0094d5a7bdd 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -1057,7 +1057,7 @@ test("createRecord receives a snapshot", function(assert) { var person; run(function() { - person = store.createRecord('person', { name: "Tom Dale" }); + person = store.createRecord('person', { name: "Tom Dale", id: 1 }); person.save(); }); }); diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index 72f008b5afa..b98a439db50 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -86,7 +86,7 @@ test("empty string and undefined ids should coerce to null", function(assert) { env.adapter.createRecord = function(store, type, record) { assert.equal(typeof get(record, 'id'), 'object', 'correct type'); - return Ember.RSVP.resolve(); + return Ember.RSVP.resolve({ id: 1 }); }; run(function() { diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 49a46557509..2300815875a 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -342,6 +342,7 @@ test("A hasMany updated link should not remove new children", function(assert) { env.adapter.createRecord = function(store, snapshot, link, relationship) { return Ember.RSVP.resolve({ + id: 1, links: { comments: '/some/link' } @@ -382,6 +383,7 @@ test("A hasMany updated link should not remove new children when the parent reco env.adapter.createRecord = function(store, snapshot, link, relationship) { return Ember.RSVP.resolve({ + id: 1, links: { comments: '/some/link' } @@ -2207,6 +2209,7 @@ test("adding and removing records from hasMany relationship #2666", function(ass }) }); + var commentId = 4; env.registry.register('adapter:comment', DS.RESTAdapter.extend({ deleteRecord(record) { return Ember.RSVP.resolve(); @@ -2215,7 +2218,7 @@ test("adding and removing records from hasMany relationship #2666", function(ass return Ember.RSVP.resolve(); }, createRecord() { - return Ember.RSVP.resolve(); + return Ember.RSVP.resolve({ comments: { id: commentId++ }}); } })); diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index b4cc2f9de9a..de9456263e9 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -867,6 +867,19 @@ testInDebug('store#findRecord that returns an array should assert', assert => { }, /expected the primary data returned from a `findRecord` response to be an object but instead it found an array/); }); +testInDebug('store#didSaveRecord should assert when the response to a save does not include the id', function(assert) { + env.adapter.createRecord = function() { + return {}; + }; + + assert.expectAssertion(function() { + run(function() { + var car = store.createRecord('car'); + car.save(); + }); + }, /record was saved but it does not have an id. Please make the server provides an id in the createRecord/); +}); + module("integration/store - queryRecord", { beforeEach() { initializeStore(DS.Adapter.extend()); @@ -892,3 +905,5 @@ testInDebug('store#queryRecord should assert when normalized payload of adapter }); }, /Expected the primary data returned by the serializer for a `queryRecord` response to be a single object or null but instead it was an array./); }); + + diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index cb25cc457a2..25adcbb3ef3 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -370,7 +370,7 @@ test("changedAttributes() works while the record is being saved", function(asser assert.deepEqual(toObj(cat.changedAttributes()), { name: [undefined, 'Argon'], likes: [undefined, 'Cheese'] }); - return {}; + return { id: 1 }; } }); var Mascot = DS.Model.extend({ From 933aa45e366ce9c80c66d328c961a92a90d4727c Mon Sep 17 00:00:00 2001 From: Mikael Riska Date: Sun, 29 May 2016 22:21:56 +0200 Subject: [PATCH 1531/2527] Fix documentation - DS.Model eachRelationship - DS.Model relationshipsByName --- addon/-private/system/relationships/ext.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 18265cd5151..248b5ad4bb8 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -473,9 +473,9 @@ export const RelationshipsClassMethodsMixin = Ember.Mixin.create({ var relationshipsByName = Ember.get(Blog, 'relationshipsByName'); relationshipsByName.get('users'); - //=> { key: 'users', kind: 'hasMany', type: App.User } + //=> { key: 'users', kind: 'hasMany', type: 'user', options: Object, isRelationship: true } relationshipsByName.get('owner'); - //=> { key: 'owner', kind: 'belongsTo', type: App.User } + //=> { key: 'owner', kind: 'belongsTo', type: 'user', options: Object, isRelationship: true } ``` @property relationshipsByName @@ -622,7 +622,7 @@ export const RelationshipsInstanceMethodsMixin = Ember.Mixin.create({ - **kind** String "hasMany" or "belongsTo" - **options** Object the original options hash passed when the relationship was declared - **parentType** DS.Model the type of the Model that owns this relationship - - **type** DS.Model the type of the related Model + - **type** String the type name of the related Model Note that in addition to a callback, you can also pass an optional target object that will be set as `this` on the context. From da342e60d1b070c14a84fca0fcdc8d43c4d09132 Mon Sep 17 00:00:00 2001 From: Seth Date: Tue, 31 May 2016 14:30:52 -0400 Subject: [PATCH 1532/2527] Small improvement for the badIdFormatAssertion (#4413) * Small improvement for the badIdFormatAssertion Just a small helpful improvement. Could potentially save users tens of minutes finding the cause. :tada: My original assumption was that a payload was not including an `id`.. then i discovered it was my `findRecord()` call * Update store-test.js nice tests --- addon/-private/system/store.js | 2 +- tests/integration/store-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 5e7795d4e38..851d006fa8e 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -55,7 +55,7 @@ import EmptyObject from "ember-data/-private/system/empty-object"; import isEnabled from 'ember-data/-private/features'; -export let badIdFormatAssertion = '`id` has to be non-empty string or number'; +export let badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; const Backburner = Ember._Backburner; var Map = Ember.Map; diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index b4cc2f9de9a..df4c42e1acc 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -461,7 +461,7 @@ testInDebug('store#findRecord call with `id` of type different than non-empty st badValues.map(item => { assert.expectAssertion(function() { store.findRecord('car', item); - }, '`id` has to be non-empty string or number'); + }, '`id` passed to `findRecord()` has to be non-empty string or number'); }); }); }); From 2226818c64e9442e0b60aabd0439ca5d90c56c05 Mon Sep 17 00:00:00 2001 From: Hilst Date: Wed, 1 Jun 2016 17:28:45 +0200 Subject: [PATCH 1533/2527] remove deprecation DEPRECATION: Using the global version of DS is deprecated. --- tests/ember-data-initializers.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ember-data-initializers.js b/tests/ember-data-initializers.js index ff90bb3e79a..3526bc8c869 100644 --- a/tests/ember-data-initializers.js +++ b/tests/ember-data-initializers.js @@ -1,8 +1,9 @@ /* eslint no-extra-semi: "off" */ +import DS from 'ember-data'; + ;(function() { /* globals Ember */ - /* globals DS */ var K = Ember.K; Ember.onLoad('Ember.Application', function(Application) { From deebfa5dcbc0176bcb9ee0f2a230081947ec6a2a Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Wed, 1 Jun 2016 20:30:35 -0400 Subject: [PATCH 1534/2527] Revert "Uses bin/start with friendly error message for npm start." --- bin/start | 13 ------------- package.json | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) delete mode 100755 bin/start diff --git a/bin/start b/bin/start deleted file mode 100755 index 6f35ab59125..00000000000 --- a/bin/start +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -if [ ! -d "node_modules" ]; then - echo "Please make sure you run npm install before running npm start"; - exit 0; -fi - -if [ ! -d "bower_components" ]; then - echo "Please make sure you run bower install before running npm start"; - exit 0; -fi - -ember server; diff --git a/package.json b/package.json index 3c63ccd48b7..050d16352b0 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ }, "scripts": { "build": "ember build", - "start": "./bin/start", + "start": "ember server", "test": "ember try:testall", "node-tests": "node node-tests/nodetest-runner.js", "test:optional-features": "ember test --environment=test-optional-features", From e4758d30be2a01d75d27cc46cc2b944c90fe8173 Mon Sep 17 00:00:00 2001 From: Jon Dayton Date: Wed, 1 Jun 2016 20:34:11 -0400 Subject: [PATCH 1535/2527] make shouldSerializeHasMany public #2494 (#4279) --- FEATURES.md | 4 +++ addon/serializers/json-api.js | 6 ++++- addon/serializers/json.js | 27 ++++++++++++++++++- config/features.json | 3 ++- .../serializers/json-serializer-test.js | 26 ++++++++++++++++++ 5 files changed, 63 insertions(+), 3 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 5fa0f1d1fcc..721b054ba9d 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -133,3 +133,7 @@ entry in `config/features.json`. } ``` +- `ds-check-should-serialize-relationships` + +Adds public method for `shouldSerializeHasMany`, used to determine if a +`hasMany` relationship can be serialized. diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 10253f42a61..df31f0adec6 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -571,8 +571,12 @@ const JSONAPISerializer = JSONSerializer.extend({ */ serializeHasMany(snapshot, json, relationship) { var key = relationship.key; + var shouldSerializeHasMany = '_shouldSerializeHasMany'; + if (isEnabled("ds-check-should-serialize-relationships")) { + shouldSerializeHasMany = 'shouldSerializeHasMany'; + } - if (this._shouldSerializeHasMany(snapshot, key, relationship)) { + if (this[shouldSerializeHasMany](snapshot, key, relationship)) { var hasMany = snapshot.hasMany(key); if (hasMany !== undefined) { diff --git a/addon/serializers/json.js b/addon/serializers/json.js index ef4ca3a9bbc..0833e0bc1ae 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -840,6 +840,27 @@ var JSONSerializer = Serializer.extend({ return attrs && attrs[key] && attrs[key].serialize === true; }, + /** + Check if the given hasMany relationship should be serialized + + @method shouldSerializeHasMany + @param {DS.Snapshot} snapshot + @param {String} key + @param {String} relationshipType + @return {boolean} true if the hasMany relationship should be serialized + */ + + shouldSerializeHasMany(snapshot, key, relationship) { + if ((this._shouldSerializeHasMany !== JSONSerializer.prototype._shouldSerializeHasMany)) { + deprecate('The private method _shouldSerializeHasMany has been promoted to the public API. Please remove the underscore to use the public shouldSerializeHasMany method.', false, { + id: 'ds.serializer.private-should-serialize-has-many', + until: '3.0.0' + }); + } + + return this._shouldSerializeHasMany(snapshot, key, relationship); + }, + /** Check if the given hasMany relationship should be serialized @@ -1196,8 +1217,12 @@ var JSONSerializer = Serializer.extend({ */ serializeHasMany(snapshot, json, relationship) { var key = relationship.key; + var shouldSerializeHasMany = '_shouldSerializeHasMany'; + if (isEnabled("ds-check-should-serialize-relationships")) { + shouldSerializeHasMany = 'shouldSerializeHasMany'; + } - if (this._shouldSerializeHasMany(snapshot, key, relationship)) { + if (this[shouldSerializeHasMany](snapshot, key, relationship)) { var hasMany = snapshot.hasMany(key, { ids: true }); if (hasMany !== undefined) { // if provided, use the mapping provided by `attrs` in diff --git a/config/features.json b/config/features.json index 786c106b184..0e486cb5006 100644 --- a/config/features.json +++ b/config/features.json @@ -6,5 +6,6 @@ "ds-extended-errors": null, "ds-links-in-record-array": null, "ds-overhaul-references": null, - "ds-payload-type-hooks": null + "ds-payload-type-hooks": null, + "ds-check-should-serialize-relationships": null } diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 773feab2246..73fc5b9bf50 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -201,6 +201,32 @@ test("serializeHasMany omits unknown relationships on pushed record", function(a assert.ok(!json.hasOwnProperty("comments"), "Does not add the relationship key to json"); }); +test("shouldSerializeHasMany", function(assert) { + + run(function() { + post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); + comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post, id: "1" }); + }); + + var snapshot = post._createSnapshot(); + var relationship = snapshot.record.relationshipFor('comments'); + var key = relationship.key; + + var shouldSerialize = env.store.serializerFor("post").shouldSerializeHasMany(snapshot, relationship, key); + + assert.ok(shouldSerialize, 'shouldSerializeHasMany correctly identifies with hasMany relationship'); +}); + +if (isEnabled("ds-check-should-serialize-relationships")) { + testInDebug("_shouldSerializeHasMany deprecation", function(assert) { + env.store.serializerFor("post")._shouldSerializeHasMany = Ember.K; + + assert.expectDeprecation(function() { + env.store.serializerFor("post").shouldSerializeHasMany(); + }, /_shouldSerializeHasMany has been promoted to the public API/); + }); +} + test("serializeIntoHash", function(assert) { run(function() { post = env.store.createRecord('post', { title: "Rails is omakase" }); From 58132aead5805938f65362b9bacf46690a3fbfbb Mon Sep 17 00:00:00 2001 From: Josemar Luedke Date: Tue, 7 Jun 2016 17:36:37 -0700 Subject: [PATCH 1536/2527] [BUGFIX] Pass options to transform for serialization in json-api Since json serializer's serializeAttribute function is been overwritten in json api serializer, the feature to pass the options to the transform is not working when using the json api adapter. This fixes the problem. --- addon/serializers/json-api.js | 2 +- .../serializers/json-api-serializer-test.js | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index df31f0adec6..46867299232 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -499,7 +499,7 @@ const JSONAPISerializer = JSONSerializer.extend({ let value = snapshot.attr(key); if (type) { const transform = this.transformFor(type); - value = transform.serialize(value); + value = transform.serialize(value, attribute.options); } let payloadKey = this._getMappedKey(key, snapshot.type); diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 2b25cac3287..64aa398ba17 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -263,6 +263,28 @@ test('Serializer should respect the attrs hash when serializing attributes with assert.equal(payload.data.attributes['company_name'], 'Tilde Inc.'); }); +test('options are passed to transform for serialization', function(assert) { + assert.expect(1); + + env.registry.register('transform:custom', DS.Transform.extend({ + serialize: function(deserialized, options) { + assert.deepEqual(options, { custom: 'config' }); + } + })); + + User.reopen({ + myCustomField: DS.attr('custom', { + custom: 'config' + }) + }); + + var user; + run(function() { + user = env.store.createRecord('user', { myCustomField: 'value' }); + }); + + env.store.serializerFor('user').serialize(user._createSnapshot()); +}); testInDebug('JSON warns when combined with EmbeddedRecordsMixin', function(assert) { assert.expectWarning(function() { From 9e7f90aaa568cee61b73e33f24c246724373be83 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 8 Jun 2016 17:07:24 -0400 Subject: [PATCH 1537/2527] Update changelog for the 2.6.0 release --- CHANGELOG.md | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec2421949a0..3f51f9ec728 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,84 @@ ### Master +### Release 2.6.0 (June 8, 2016) +- [#4386](https://github.com/emberjs/data/pull/4386) [BUGFIX release] `isUpdating` flag is set correctly for `store.findAll` +- [#4374](https://github.com/emberjs/data/pull/4374) Fix #4366: EmbeddedRecordsMixin embeds the record, not the snapshot +- [#4379](https://github.com/emberjs/data/pull/4379) [BUGFIX beta] Fix resetting of properties to in-flight values +- [#4380](https://github.com/emberjs/data/pull/4380) [BUGFIX beta] remove trailing whitespace from model blueprint +- [#4300](https://github.com/emberjs/data/pull/4300) [BUGFIX beta] Overhaul queryRecord +- [#4363](https://github.com/emberjs/data/pull/4363) [DOC] Fix hard-coded "Customizing Adapters" link +- [#4320](https://github.com/emberjs/data/pull/4320) Fixup feature flagging infrastructure. +- [#4324](https://github.com/emberjs/data/pull/4324) [DOC beta] Clarify DS.Model#changedAttributes() +- [#4324](https://github.com/emberjs/data/pull/4324) [DOC beta] Clarify DS.Model#changedAttributes() +- [#4327](https://github.com/emberjs/data/pull/4327) [DOC] Update CONTRIBUTING.md for feature flags +- [#4328](https://github.com/emberjs/data/pull/4328) [BUGFIX release] Only setup babel options once. +- [#4330](https://github.com/emberjs/data/pull/4330) [DOC beta] Make clear where `blog` is coming from +- [#4331](https://github.com/emberjs/data/pull/4331) [BUGFIX beta] Overhaul attr/relationships imports in model blueprint +- [#4338](https://github.com/emberjs/data/pull/4338) [DOC beta] Overhaul documentation for reload / background reload +- [#4345](https://github.com/emberjs/data/pull/4345) [DOC] fix example syntax +- [#4184](https://github.com/emberjs/data/pull/4184) blueprints: Use project.dependencies() to determine test framework +- [#3848](https://github.com/emberjs/data/pull/3848) [BUGFIX] EmbeddedRecordMixin should include the type serializing hasMany as ids +- [#4154](https://github.com/emberjs/data/pull/4154) Make sure new record are not pushed twice when parent is saved before. +- [#4023](https://github.com/emberjs/data/pull/4023) Enhance blueprints: only extend from application entity if it exists +- [#4177](https://github.com/emberjs/data/pull/4177) Elaborate on running tests in browser +- [#3586](https://github.com/emberjs/data/pull/3586) [FEATURE ds-extended-errors] Make adapter error extendable and add more error types +- [#3099](https://github.com/emberjs/data/pull/3099) [FEATURE ds-improved-ajax] Finer control over customizing a request +- [#4022](https://github.com/emberjs/data/pull/4022) [FEATURE ds-boolean-transform-allow-null] allow null for boolean +- [#4173](https://github.com/emberjs/data/pull/4173) Create RELEASE.md +- [#4178](https://github.com/emberjs/data/pull/4178) DS.Store type presence checks +- [#3559](https://github.com/emberjs/data/pull/3559) [BUGFIX release] Guard against isDestroyed in ManyArray.flushCanonical +- [#4259](https://github.com/emberjs/data/pull/4259) Warn when the JSONAPISerializer is extended with the EmbeddedRecordsM… +- [#4200](https://github.com/emberjs/data/pull/4200) Avoid errors when ember-cli-shims is not included. +- [#4188](https://github.com/emberjs/data/pull/4188) Update ember-cli to v2.3.0 +- [#4191](https://github.com/emberjs/data/pull/4191) Don't resolve model name unless actually needed +- [#4189](https://github.com/emberjs/data/pull/4189) AppVeyor: Use same line endings as original files +- [#4193](https://github.com/emberjs/data/pull/4193) support 1.13 officially +- [#4194](https://github.com/emberjs/data/pull/4194) Use modelNameFromPayloadKey when type is given +- [#4196](https://github.com/emberjs/data/pull/4196) Restructure and elaborate on test which fixes a tricky bug +- [#4187](https://github.com/emberjs/data/pull/4187) Add acceptance tests for the mocha blueprints +- [#4197](https://github.com/emberjs/data/pull/4197) Update changelog for Ember Data 2.4 +- [#4274](https://github.com/emberjs/data/pull/4274) [DOC canary] Update extractMeta documentation +- [#4230](https://github.com/emberjs/data/pull/4230) Only show ember-cli-shims errors if actually installed +- [#4214](https://github.com/emberjs/data/pull/4214) Fix AMD dependencies +- [#4223](https://github.com/emberjs/data/pull/4223) Run tests in production +- [#4205](https://github.com/emberjs/data/pull/4205) [BUGFIX release] ensure import paths are resolved \w posix separators +- [#4215](https://github.com/emberjs/data/pull/4215) unify prod/dev add-on build +- [#4225](https://github.com/emberjs/data/pull/4225) Don't do inverse work if inverse is explicitly turned off +- [#4228](https://github.com/emberjs/data/pull/4228) Solves #4186 and fixes `this._super` call within `normalize` method. +- [#4222](https://github.com/emberjs/data/pull/4222) Strip code for DS_WARN_ON_UNKNOWN_KEYS warning in production +- [#4220](https://github.com/emberjs/data/pull/4220) Use single quotes +- [#4204](https://github.com/emberjs/data/pull/4204) Fix RESTAdapter.findRecord without a snapshot +- [#4264](https://github.com/emberjs/data/pull/4264) Moved the adapter errors into the public API space. +- [#4247](https://github.com/emberjs/data/pull/4247) Add test asserting no unnecessary inverse work +- [#4235](https://github.com/emberjs/data/pull/4235) [DOC] Fix store.findAll return type +- [#4243](https://github.com/emberjs/data/pull/4243) moves the ember dep in the package-manager package.json into optionalDependencies +- [#4241](https://github.com/emberjs/data/pull/4241) Fix spacing issue thats causing jscs errors on the beta branch +- [#4240](https://github.com/emberjs/data/pull/4240) Add note on `testInDebug` +- [#4248](https://github.com/emberjs/data/pull/4248) fix prod-build issue +- [#4244](https://github.com/emberjs/data/pull/4244) [DOC] Add section on commit tagging to CONTRIBUTING.md +- [#4245](https://github.com/emberjs/data/pull/4245) Tweaks to docs on error responses +- [#4287](https://github.com/emberjs/data/pull/4287) [FEATURE ds-extended-errors] add DS.ServerError +- [#4270](https://github.com/emberjs/data/pull/4270) Fix incorrect reference to `push` in the `findRecord` docs +- [#4260](https://github.com/emberjs/data/pull/4260) Modified the setup-ember-dev test helper to use `ember-metal/debug`s override hooks +- [#4263](https://github.com/emberjs/data/pull/4263) [FEATURE ds-links-in-record-array] Add links to RecordArray when present on payload +- [#4257](https://github.com/emberjs/data/pull/4257) Update changelog for Ember Data 2.4.3 +- [#4268](https://github.com/emberjs/data/pull/4268) JSONSerializer should normalize the links object using the attrs hash +- [#4258](https://github.com/emberjs/data/pull/4258) Deprecate normalizeHash method on the rest serializer +- [#4301](https://github.com/emberjs/data/pull/4301) fix rest-adapter-test typo +- [#4278](https://github.com/emberjs/data/pull/4278) Uses bin/start with friendly error message for npm start. +- [#4276](https://github.com/emberjs/data/pull/4276) [BUGFIX canary] Improve finders assertion messages +- [#4304](https://github.com/emberjs/data/pull/4304) pass DS.SnapshotRecordArray to build-url-mixin buildURL +- [#4280](https://github.com/emberjs/data/pull/4280) Update "blueprint-test-helpers" and "ember-cli" +- [#4307](https://github.com/emberjs/data/pull/4307) [skip ci] fix invalid indentation in codeclimate.yml +- [#4288](https://github.com/emberjs/data/pull/4288) [FEATURE ds-extended-errors] fix usage of isEnabled +- [#4284](https://github.com/emberjs/data/pull/4284) [CLEANUP] Use Array.isArray everywhere instead of Ember.isArray +- [#4281](https://github.com/emberjs/data/pull/4281) Speed up JSONSerializer#applyTransforms +- [#4286](https://github.com/emberjs/data/pull/4286) Use the dot reporter to reduce the noise in travis output +- [#4308](https://github.com/emberjs/data/pull/4308) pass snapshot through to urlForFindHasMany and urlForFindBelongsTo +- [#4316](https://github.com/emberjs/data/pull/4316) Fix `isUpdating` for DS.AdapterPopulatedRecordArray#update() +- [#4317](https://github.com/emberjs/data/pull/4317) [CLEANUP] remove reference to no more used isNewSerializerAPI flag + ### Release 2.5.3 (May 17, 2016) - [#4386](https://github.com/emberjs/data/pull/4386) [BUGFIX release] `isUpdating` flag is set correctly for `store.findAll` From 60b8ea25967148d434f6b7c45c807e49ba4a0120 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 8 Jun 2016 17:30:28 -0400 Subject: [PATCH 1538/2527] Bump the master version to 2.8.0-canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3c63ccd48b7..998500f8978 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.7.0-canary", + "version": "2.8.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From b9870a338ed29c2ba67f1c0f5dd471a21ab78656 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 15 Jun 2016 14:45:50 -0400 Subject: [PATCH 1539/2527] Update changelog for 2.6.1 release --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae5ac537f8b..a3a351bf8a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ### Master +### Release 2.6.1 (June 15, 2016) +- [#4425](https://github.com/emberjs/data/pull/4425) [BUGFIX] Pass options to transform for serialization in json-api +- [#4389](https://github.com/emberjs/data/pull/4389) call super in addon#init + ### Release 2.6.0 (June 8, 2016) - [#4386](https://github.com/emberjs/data/pull/4386) [BUGFIX release] `isUpdating` flag is set correctly for `store.findAll` - [#4374](https://github.com/emberjs/data/pull/4374) Fix #4366: EmbeddedRecordsMixin embeds the record, not the snapshot From 8ee72bc0de247568d9a6dd7c8120b52eb7300c4b Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Sat, 18 Jun 2016 13:10:53 +0200 Subject: [PATCH 1540/2527] [BUGFIX beta] Remove JSHint directives from Mocha test blueprints The `expr` rule should instead be deactivated in `tests/.jshintrc` --- .../adapter-test/mocha-files/tests/unit/__path__/__test__.js | 1 - .../model-test/mocha-files/tests/unit/__path__/__test__.js | 1 - .../serializer-test/mocha-files/tests/unit/__path__/__test__.js | 1 - .../transform-test/mocha-files/tests/unit/__path__/__test__.js | 1 - 4 files changed, 4 deletions(-) diff --git a/blueprints/adapter-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/adapter-test/mocha-files/tests/unit/__path__/__test__.js index e09a1e584e2..f26b5338dbf 100644 --- a/blueprints/adapter-test/mocha-files/tests/unit/__path__/__test__.js +++ b/blueprints/adapter-test/mocha-files/tests/unit/__path__/__test__.js @@ -1,4 +1,3 @@ -/* jshint expr:true */ import { expect } from 'chai'; import { describeModule, it } from 'ember-mocha'; diff --git a/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js index 8ccea636b4a..b7bf32aa4cd 100644 --- a/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js +++ b/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js @@ -1,4 +1,3 @@ -/* jshint expr:true */ import { expect } from 'chai'; import { describeModel, it } from 'ember-mocha'; diff --git a/blueprints/serializer-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/mocha-files/tests/unit/__path__/__test__.js index 327fd27c1b5..d8112c9884f 100644 --- a/blueprints/serializer-test/mocha-files/tests/unit/__path__/__test__.js +++ b/blueprints/serializer-test/mocha-files/tests/unit/__path__/__test__.js @@ -1,4 +1,3 @@ -/* jshint expr:true */ import { expect } from 'chai'; import { describeModel, it } from 'ember-mocha'; diff --git a/blueprints/transform-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/transform-test/mocha-files/tests/unit/__path__/__test__.js index 88fb24805e8..c3d20680218 100644 --- a/blueprints/transform-test/mocha-files/tests/unit/__path__/__test__.js +++ b/blueprints/transform-test/mocha-files/tests/unit/__path__/__test__.js @@ -1,4 +1,3 @@ -/* jshint expr:true */ import { expect } from 'chai'; import { describeModule, it } from 'ember-mocha'; From b8099610d5f8713b5e5f018229996ecabf5b8ac7 Mon Sep 17 00:00:00 2001 From: Cory Forsyth Date: Mon, 20 Jun 2016 15:33:43 -0400 Subject: [PATCH 1541/2527] [DOC] typo fix for queryRecord (kown -> known) --- addon/-private/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 851d006fa8e..749ec20ac47 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1137,7 +1137,7 @@ Store = Service.extend({ ``` Note: the primary use case for `store.queryRecord` is when a single record - is queried and the `id` is not kown beforehand. In all other cases + is queried and the `id` is not known beforehand. In all other cases `store.query` and using the first item of the array is likely the preferred way: From 6790d84cde4fa4a10c1aa40d1e86e0b0767eed17 Mon Sep 17 00:00:00 2001 From: Hilst Date: Tue, 21 Jun 2016 11:22:28 +0200 Subject: [PATCH 1542/2527] use require to import DS fixes tests failing in production mode fixes deprecation message using global DS in tests --- tests/ember-data-initializers.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ember-data-initializers.js b/tests/ember-data-initializers.js index 3526bc8c869..ba8a96e9e62 100644 --- a/tests/ember-data-initializers.js +++ b/tests/ember-data-initializers.js @@ -1,12 +1,12 @@ /* eslint no-extra-semi: "off" */ -import DS from 'ember-data'; - ;(function() { - /* globals Ember */ + /* globals Ember, require */ var K = Ember.K; Ember.onLoad('Ember.Application', function(Application) { + var DS = require('ember-data').default; + Application.initializer({ name: "ember-data", initialize: DS._setupContainer From 0355ed91f0ac651788e337e09c1ee28d3ebc995d Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 21 Jun 2016 12:20:29 -0500 Subject: [PATCH 1543/2527] add `relationship` property to findHasMany RESTAdapter docs --- addon/adapters/rest.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index ebfc66aede8..4b9f90b09ce 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -619,6 +619,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @method findHasMany @param {DS.Store} store @param {DS.Snapshot} snapshot + @param {DS.Snapshot} relationship snapshot of the hasMany relationship @param {String} url @return {Promise} promise */ From db58d9367e544652943badb2c8f5340db4fb8dd1 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 22 Jun 2016 14:09:34 -0400 Subject: [PATCH 1544/2527] Remove manual initializer override in tests. (#4439) * Remove manual initializer override in tests. * Use ember-load-initializers in bower builds. --- lib/javascripts.js | 16 +++++++++--- tests/ember-data-initializers.js | 45 -------------------------------- tests/test-helper.js | 3 ++- 3 files changed, 15 insertions(+), 49 deletions(-) delete mode 100644 tests/ember-data-initializers.js diff --git a/lib/javascripts.js b/lib/javascripts.js index 3c37a8bdd9b..a88cc38ac9f 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -46,15 +46,13 @@ function collapse(tree, outputFileName) { var emberDataShims = fs.readFileSync(emberDataShimsPath, { encoding: 'utf8' }); var dsGlobalPath = path.join(__dirname, 'ds-global.js'); var dsGlobal = fs.readFileSync(dsGlobalPath, { encoding: 'utf8' }); - var emberDataInitialierPath = path.join(__dirname, '../tests/ember-data-initializers.js'); - var emberDataInitialier = fs.readFileSync(emberDataInitialierPath, { encoding: 'utf8' }); var withLoader = merge([tree, loader, license, emberShim]); return concat(withLoader, { inputFiles: ['license.js', 'loader.js', '**/*.js'], outputFile: '/' + outputFileName, header: '(function(){ \n"use strict";\n', - footer: '\nrequire("ember-data");\n' + dsGlobal + '})();\n' + emberDataShims + emberDataInitialier + footer: '\nrequire("ember-data");\nrequire("ember-load-initializers")["default"](Ember.Application, "ember-data");\n' + dsGlobal + '})();\n' + emberDataShims }); } @@ -75,12 +73,24 @@ function buildEmberInflector() { return debugBuild('ember-inflector', emberInflector); } +function buildLoadInitializers() { + var emberLoadInitializers = new Funnel(path.dirname(require.resolve('ember-load-initializers/addon')), { + include: ['**/*.js'] + }); + + return debugBuild('ember-load-initializers', emberLoadInitializers); +} + module.exports = function(tree) { var emberInflector = buildEmberInflector(); + var loadInitializers = buildLoadInitializers(); var emberData = merge([tree, version()]); var javascripts = merge([ emberInflector, + loadInitializers, + debugBuild('ember-data/initializers', 'app/initializers'), + debugBuild('ember-data/instance-initializers', 'app/instance-initializers'), debugBuild('ember-data', emberData) ]); diff --git a/tests/ember-data-initializers.js b/tests/ember-data-initializers.js deleted file mode 100644 index ba8a96e9e62..00000000000 --- a/tests/ember-data-initializers.js +++ /dev/null @@ -1,45 +0,0 @@ -/* eslint no-extra-semi: "off" */ - -;(function() { - /* globals Ember, require */ - var K = Ember.K; - Ember.onLoad('Ember.Application', function(Application) { - - var DS = require('ember-data').default; - - Application.initializer({ - name: "ember-data", - initialize: DS._setupContainer - }); - - Application.instanceInitializer({ - name: "ember-data", - initialize: DS._initializeStoreService - }); - - // Deprecated initializers to satisfy old code that depended on them - Application.initializer({ - name: "store", - after: "ember-data", - initialize: K - }); - - Application.initializer({ - name: "transforms", - before: "store", - initialize: K - }); - - Application.initializer({ - name: "data-adapter", - before: "store", - initialize: K - }); - - Application.initializer({ - name: "injectStore", - before: "store", - initialize: K - }); - }); -})(); diff --git a/tests/test-helper.js b/tests/test-helper.js index ffabc8b27f1..3e26b1b29d4 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -11,9 +11,10 @@ import { invokeAsync } from 'dummy/tests/helpers/async'; import Ember from 'ember'; -import './ember-data-initializers'; +import loadInitializers from 'ember-load-initializers'; setResolver(resolver); +loadInitializers(Ember.Application, 'dummy'); const { assert } = QUnit; From d5988350e7e11c33bfec2ec3e795ae192799ccf7 Mon Sep 17 00:00:00 2001 From: Joshua Trees Date: Thu, 23 Jun 2016 11:35:46 +0200 Subject: [PATCH 1545/2527] Fix typo in comment --- addon/-private/system/model/states.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index d4c650a1f0d..234dc0e4fd9 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -223,7 +223,7 @@ function didSetProperty(internalModel, context) { // `inFlight`: the store has handed off the record to be saved, // but the adapter has not yet acknowledged success. // `invalid`: the record has invalid information and cannot be -// send to the adapter yet. +// sent to the adapter yet. var DirtyState = { initialState: 'uncommitted', From 3c921ce9c8da52637118250088ccb54e2da3e94f Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 23 Jun 2016 15:12:35 -0400 Subject: [PATCH 1546/2527] Update the API docs for the DS.Adapter class --- addon/adapter.js | 62 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/addon/adapter.js b/addon/adapter.js index a7ef83a90ac..2d1800b934c 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -99,10 +99,9 @@ export default Ember.Object.extend({ export default DS.Adapter.extend({ findRecord: function(store, type, id, snapshot) { - var url = [type.modelName, id].join('/'); return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.getJSON(url).then(function(data) { + Ember.$.getJSON(`/${type.modelName}/${id}`).then(function(data) { Ember.run(null, resolve, data); }, function(jqXHR) { jqXHR.then = null; // tame jQuery's ill mannered promises @@ -132,10 +131,9 @@ export default Ember.Object.extend({ export default DS.Adapter.extend({ findAll: function(store, type, sinceToken) { - var url = type; var query = { since: sinceToken }; return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.getJSON(url, query).then(function(data) { + Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { Ember.run(null, resolve, data); }, function(jqXHR) { jqXHR.then = null; // tame jQuery's ill mannered promises @@ -165,9 +163,8 @@ export default Ember.Object.extend({ export default DS.Adapter.extend({ query: function(store, type, query) { - var url = type; return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.getJSON(url, query).then(function(data) { + Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { Ember.run(null, resolve, data); }, function(jqXHR) { jqXHR.then = null; // tame jQuery's ill mannered promises @@ -205,10 +202,8 @@ export default Ember.Object.extend({ export default DS.Adapter.extend(DS.BuildURLMixin, { queryRecord: function(store, type, query) { - var urlForQueryRecord = this.buildURL(type.modelName, null, null, 'queryRecord', query); - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.getJSON(urlForQueryRecord, query).then(function(data) { + Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { Ember.run(null, resolve, data); }, function(jqXHR) { jqXHR.then = null; // tame jQuery's ill mannered promises @@ -242,10 +237,14 @@ export default Ember.Object.extend({ the first parameter and the newly created record as the second parameter: ```javascript - generateIdForRecord: function(store, inputProperties) { - var uuid = App.generateUUIDWithStatisticallyLowOddsOfCollision(); - return uuid; - } + import DS from 'ember-data'; + import { v4 } from 'uuid'; + + export default DS.Adapter.extend({ + generateIdForRecord: function(store, inputProperties) { + return v4(); + } + }); ``` @method generateIdForRecord @@ -268,7 +267,7 @@ export default Ember.Object.extend({ export default DS.Adapter.extend({ createRecord: function(store, type, snapshot) { var data = this.serialize(snapshot, { includeId: true }); - var url = type; + var url = `/${type.modelName}`; // ... } @@ -298,12 +297,11 @@ export default Ember.Object.extend({ export default DS.Adapter.extend({ createRecord: function(store, type, snapshot) { var data = this.serialize(snapshot, { includeId: true }); - var url = type; return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.ajax({ type: 'POST', - url: url, + url: `/${type.modelName}`, dataType: 'json', data: data }).then(function(data) { @@ -348,12 +346,11 @@ export default Ember.Object.extend({ updateRecord: function(store, type, snapshot) { var data = this.serialize(snapshot, { includeId: true }); var id = snapshot.id; - var url = [type, id].join('/'); return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.ajax({ type: 'PUT', - url: url, + url: `/${type.modelName}/${id}`, dataType: 'json', data: data }).then(function(data) { @@ -390,12 +387,11 @@ export default Ember.Object.extend({ deleteRecord: function(store, type, snapshot) { var data = this.serialize(snapshot, { includeId: true }); var id = snapshot.id; - var url = [type, id].join('/'); return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.ajax({ type: 'DELETE', - url: url, + url: `/${type.modelName}/${id}`, dataType: 'json', data: data }).then(function(data) { @@ -429,7 +425,31 @@ export default Ember.Object.extend({ coalesceFindRequests: true, /** - Find multiple records at once if coalesceFindRequests is true. + The store will call `findMany` instead of multiple `findRecord` + requests to find multiple records at once if coalesceFindRequests + is true. + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + findMany(store, type, ids, snapshots) { + return new Ember.RSVP.Promise(function(resolve, reject) { + Ember.$.ajax({ + type: 'GET', + url: `/${type.modelName}/`, + dataType: 'json', + data: { filter: { id: ids.join(',') } } + }).then(function(data) { + Ember.run(null, resolve, data); + }, function(jqXHR) { + jqXHR.then = null; // tame jQuery's ill mannered promises + Ember.run(null, reject, jqXHR); + }); + }); + } + }); + ``` @method findMany @param {DS.Store} store From 9cb1b337d536a278e0ffbf6066297f49bc839d66 Mon Sep 17 00:00:00 2001 From: Aaron Sikes Date: Fri, 18 Mar 2016 13:36:33 -0400 Subject: [PATCH 1547/2527] [FEATURE ds-reset-attribute] Add rolling back of a single model attribute --- FEATURES.md | 21 +++ addon/-private/system/model/internal-model.js | 21 ++- addon/-private/system/model/model.js | 27 +++ config/features.json | 3 +- tests/unit/model-test.js | 178 ++++++++++++++++++ 5 files changed, 248 insertions(+), 2 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 721b054ba9d..b6fd0768593 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -137,3 +137,24 @@ entry in `config/features.json`. Adds public method for `shouldSerializeHasMany`, used to determine if a `hasMany` relationship can be serialized. + +- `ds-reset-attribute` [#4246](https://github.com/emberjs/data/pull/4246) + + Adds a `resetAttribute` method to models. Similar to `rollbackAttributes`, + but for only a single attribute. + + ```js + // { firstName: 'Tom', lastName: 'Dale' } + let tom = store.peekRecord('person', 1); + + tom.setProperties({ + firstName: 'Yehuda', + lastName: 'Katz' + }); + + tom.resetAttribute('firstName') // { firstName: 'Tom', lastName: 'Katz' } + tom.get('hasDirtyAttributes') // true + + tom.resetAttribute('lastName') // { firstName: 'Tom', lastName: 'Dale' } + tom.get('hasDirtyAttributes') // false + ``` diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index b4dec58313d..88928d51158 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -4,6 +4,7 @@ import RootState from "ember-data/-private/system/model/states"; import Relationships from "ember-data/-private/system/relationships/state/create"; import Snapshot from "ember-data/-private/system/snapshot"; import EmptyObject from "ember-data/-private/system/empty-object"; +import isEnabled from 'ember-data/-private/features'; import { getOwner @@ -434,6 +435,7 @@ InternalModel.prototype = { this.record._notifyProperties(dirtyKeys); }, + /* @method transitionTo @private @@ -849,4 +851,21 @@ InternalModel.prototype = { return reference; } -}; +} + +if (isEnabled('ds-reset-attribute')) { + /* + Returns the latest truth for an attribute - the canonical value, or the + in-flight value. + + @method lastAcknowledgedValue + @private + */ + InternalModel.prototype.lastAcknowledgedValue = function lastAcknowledgedValue(key) { + if (key in this._inFlightAttributes) { + return this._inFlightAttributes[key]; + } else { + return this._data[key]; + } + }; +} diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 64d59c3cd39..2685f5d8960 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -7,6 +7,7 @@ import { BelongsToMixin } from 'ember-data/-private/system/relationships/belongs import { HasManyMixin } from 'ember-data/-private/system/relationships/has-many'; import { DidDefinePropertyMixin, RelationshipsClassMethodsMixin, RelationshipsInstanceMethodsMixin } from 'ember-data/-private/system/relationships/ext'; import { AttrClassMethodsMixin, AttrInstanceMethodsMixin } from 'ember-data/-private/system/model/attr'; +import isEnabled from 'ember-data/-private/features'; /** @module ember-data @@ -1023,6 +1024,32 @@ if (Ember.setOwner) { }); } +if (isEnabled('ds-reset-attribute')) { + Model.reopen({ + /** + Discards any unsaved changes to the given attribute. + + Example + + ```javascript + record.get('name'); // 'Untitled Document' + record.set('name', 'Doc 1'); + record.get('name'); // 'Doc 1' + record.resetAttribute('name'); + record.get('name'); // 'Untitled Document' + ``` + + @method resetAttribute + */ + resetAttribute(attributeName) { + if (attributeName in this._internalModel._attributes) { + this.set(attributeName, this._internalModel.lastAcknowledgedValue(attributeName)); + } + } + }); +} + + Model.reopenClass(RelationshipsClassMethodsMixin); Model.reopenClass(AttrClassMethodsMixin); diff --git a/config/features.json b/config/features.json index 0e486cb5006..79ca3c55c68 100644 --- a/config/features.json +++ b/config/features.json @@ -7,5 +7,6 @@ "ds-links-in-record-array": null, "ds-overhaul-references": null, "ds-payload-type-hooks": null, - "ds-check-should-serialize-relationships": null + "ds-check-should-serialize-relationships": null, + "ds-reset-attribute": null } diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index cb25cc457a2..a58452a6537 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -428,6 +428,184 @@ test("changedAttributes() works while the record is being updated", function(ass }); }); +if (isEnabled('ds-reset-attribute')) { + test("resetAttribute() reverts a single attribute to its canonical value", function(assert) { + assert.expect(5); + + run(function() { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Peter', + isDrugAddict: true + } + } + }); + + let person = store.peekRecord('person', 1); + + assert.equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); + person.setProperties({ + name: 'Piper', + isDrugAddict: false + }); + assert.equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting property to a new value"); + person.resetAttribute('isDrugAddict'); + assert.equal(person.get('isDrugAddict'), true, "The specified attribute is rolled back"); + assert.equal(person.get('name'), 'Piper', "Unspecified attributes are not rolled back"); + assert.equal(person.get('hasDirtyAttributes'), true, "record with changed attributes is still dirty"); + }); + }); + + test("calling resetAttribute() on an unmodified property has no effect", function(assert) { + assert.expect(5); + + run(function() { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Peter', + isDrugAddict: true + } + } + }); + + let person = store.peekRecord('person', 1); + + assert.equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); + person.set('name', 'Piper'); + assert.equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting property to a new value"); + person.resetAttribute('isDrugAddict'); + assert.equal(person.get('isDrugAddict'), true, "The specified attribute does not change value"); + assert.equal(person.get('name'), 'Piper', "Unspecified attributes are not rolled back"); + assert.equal(person.get('hasDirtyAttributes'), true, "record with changed attributes is still dirty"); + }); + }); + + test("Rolling back the final value with resetAttribute() causes the record to become clean again", function(assert) { + assert.expect(3); + + run(function() { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Peter', + isDrugAddict: true + } + } + }); + + let person = store.peekRecord('person', 1); + + assert.equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); + person.set('isDrugAddict', false); + assert.equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting property to a new value"); + person.resetAttribute('isDrugAddict'); + assert.equal(person.get('hasDirtyAttributes'), false, "record becomes clean after resetting property to the old value"); + }); + }); + + test("Using resetAttribute on an in-flight record reverts to the latest in-flight value", function(assert) { + assert.expect(4); + + var person, finishSaving; + + // Make sure the save is async + env.adapter.updateRecord = function(store, type, snapshot) { + return new Ember.RSVP.Promise(function(resolve, reject) { + finishSaving = resolve; + }); + }; + + run(function() { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: "Tom" + } + } + }); + person = store.peekRecord('person', 1); + person.set('name', "Thomas"); + + person.save(); + }); + + run(function() { + assert.equal(person.get('isSaving'), true); + assert.equal(person.get('name'), "Thomas"); + + person.set('name', "Tomathy"); + assert.equal(person.get('name'), "Tomathy"); + + person.resetAttribute('name'); + assert.equal(person.get('name'), "Thomas"); + + finishSaving(); + }); + }); + + test("Saving an in-flight record updates the in-flight value resetAttribute will use", function(assert) { + assert.expect(7); + + var person, finishSaving; + + // Make sure the save is async + env.adapter.updateRecord = function(store, type, snapshot) { + return new Ember.RSVP.Promise(function(resolve, reject) { + finishSaving = resolve; + }); + }; + + run(function() { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: "Tom" + } + } + }); + person = store.peekRecord('person', 1); + person.set('name', "Thomas"); + + person.save(); + }); + + run(function() { + assert.equal(person.get('isSaving'), true); + assert.equal(person.get('name'), "Thomas"); + + person.set('name', "Tomathy"); + assert.equal(person.get('name'), "Tomathy"); + + person.save(); + }); + + run(function() { + assert.equal(person.get('isSaving'), true); + assert.equal(person.get('name'), "Tomathy"); + + person.set('name', "Tomny"); + assert.equal(person.get('name'), "Tomny"); + + person.resetAttribute('name'); + assert.equal(person.get('name'), 'Tomathy'); + + finishSaving(); + }); + }); +} + test("a DS.Model does not require an attribute type", function(assert) { var Tag = DS.Model.extend({ name: DS.attr() From f81f7cf7fd5e3590cb12a4d1c05db3cdaf69ec4b Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 24 Jun 2016 12:28:07 -0400 Subject: [PATCH 1548/2527] `modelHasAttributeOrRelationshipNamedType` should not show up in the API docs `assertPolymorphicType` should not show up in the API docs --- addon/-private/debug.js | 2 +- addon/-private/utils.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/debug.js b/addon/-private/debug.js index 0144e65c470..c98e7064378 100644 --- a/addon/-private/debug.js +++ b/addon/-private/debug.js @@ -40,7 +40,7 @@ function checkPolymorphic(typeClass, addedRecord) { return typeClass.detect(addedRecord.type); } -/** +/* Assert that `addedRecord` has a valid type so it can be added to the relationship of the `record`. diff --git a/addon/-private/utils.js b/addon/-private/utils.js index a930180029e..c19332bc8cd 100644 --- a/addon/-private/utils.js +++ b/addon/-private/utils.js @@ -2,7 +2,7 @@ import Ember from 'ember'; const get = Ember.get; -/** +/* Check if the passed model has a `type` attribute or a relationship named `type`. @method modelHasAttributeOrRelationshipNamedType From d6e6d73e87088083a38b60a5f779b4a49889a922 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 24 Jun 2016 12:43:01 -0400 Subject: [PATCH 1549/2527] Remove initializer methods from the API docs (they are showing up on the DS.Model class) Add missing API docs for Ember.Date Add minor doc update to the DS namespace API docs. --- addon/-private/core.js | 2 +- addon/-private/ext/date.js | 13 +++++++++++++ addon/-private/initializers/data-adapter.js | 4 ++-- addon/-private/initializers/store-injections.js | 2 +- addon/-private/initializers/store.js | 2 +- addon/-private/initializers/transforms.js | 2 +- .../initialize-store-service.js | 4 ++-- 7 files changed, 21 insertions(+), 8 deletions(-) diff --git a/addon/-private/core.js b/addon/-private/core.js index 86b8aaf51f6..b16369a0ff4 100644 --- a/addon/-private/core.js +++ b/addon/-private/core.js @@ -6,7 +6,7 @@ import VERSION from 'ember-data/version'; */ /** - All Ember Data methods and functions are defined inside of this namespace. + All Ember Data classes, methods and functions are defined inside of this namespace. @class DS @static diff --git a/addon/-private/ext/date.js b/addon/-private/ext/date.js index 532f2d00130..4067a45f769 100644 --- a/addon/-private/ext/date.js +++ b/addon/-private/ext/date.js @@ -5,6 +5,19 @@ import Ember from 'ember'; import { deprecate } from 'ember-data/-private/debug'; + +/** + Date.parse with progressive enhancement for ISO 8601 + + © 2011 Colin Snover + + Released under MIT license. + + @class Date + @namespace Ember + @static + @deprecated +*/ Ember.Date = Ember.Date || {}; var origParse = Date.parse; diff --git a/addon/-private/initializers/data-adapter.js b/addon/-private/initializers/data-adapter.js index 419392392f1..84369679d8c 100644 --- a/addon/-private/initializers/data-adapter.js +++ b/addon/-private/initializers/data-adapter.js @@ -1,10 +1,10 @@ import DebugAdapter from "ember-data/-private/system/debug/debug-adapter"; -/** +/* Configures a registry with injections on Ember applications for the Ember-Data store. Accepts an optional namespace argument. - @method initializeStoreInjections + @method initializeDebugAdapter @param {Ember.Registry} registry */ export default function initializeDebugAdapter(registry) { diff --git a/addon/-private/initializers/store-injections.js b/addon/-private/initializers/store-injections.js index 06fe88b3506..70af3500aea 100644 --- a/addon/-private/initializers/store-injections.js +++ b/addon/-private/initializers/store-injections.js @@ -1,4 +1,4 @@ -/** +/* Configures a registry with injections on Ember applications for the Ember-Data store. Accepts an optional namespace argument. diff --git a/addon/-private/initializers/store.js b/addon/-private/initializers/store.js index a40895bfa7c..95d737fa974 100644 --- a/addon/-private/initializers/store.js +++ b/addon/-private/initializers/store.js @@ -12,7 +12,7 @@ function has(applicationOrRegistry, fullName) { } } -/** +/* Configures a registry for use with an Ember-Data store. Accepts an optional namespace argument. diff --git a/addon/-private/initializers/transforms.js b/addon/-private/initializers/transforms.js index 5503f924130..57c1df9395f 100644 --- a/addon/-private/initializers/transforms.js +++ b/addon/-private/initializers/transforms.js @@ -5,7 +5,7 @@ import { NumberTransform } from "ember-data/-private/transforms"; -/** +/* Configures a registry for use with Ember-Data transforms. diff --git a/addon/-private/instance-initializers/initialize-store-service.js b/addon/-private/instance-initializers/initialize-store-service.js index 5e6268b2922..b2d9fa1ec99 100644 --- a/addon/-private/instance-initializers/initialize-store-service.js +++ b/addon/-private/instance-initializers/initialize-store-service.js @@ -1,8 +1,8 @@ -/** +/* Configures a registry for use with an Ember-Data store. - @method initializeStore + @method initializeStoreService @param {Ember.ApplicationInstance} applicationOrRegistry */ export default function initializeStoreService(application) { From e3d71fa7b354a5f4724cc1c9c13de8508ae68e55 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sat, 25 Jun 2016 12:10:56 +0200 Subject: [PATCH 1550/2527] Add link to PR for ds-check-should-serialize-relationships feature --- FEATURES.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index b6fd0768593..ba45a16dccd 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -133,10 +133,10 @@ entry in `config/features.json`. } ``` -- `ds-check-should-serialize-relationships` +- `ds-check-should-serialize-relationships` [#4279](https://github.com/emberjs/data/pull/4279) -Adds public method for `shouldSerializeHasMany`, used to determine if a -`hasMany` relationship can be serialized. + Adds public method for `shouldSerializeHasMany`, used to determine if a + `hasMany` relationship can be serialized. - `ds-reset-attribute` [#4246](https://github.com/emberjs/data/pull/4246) From e51a0e13e82ffde9f0d752a5658de7d45e13af7e Mon Sep 17 00:00:00 2001 From: Lisa Backer Date: Sun, 26 Jun 2016 20:22:45 -0400 Subject: [PATCH 1551/2527] [CLEANUP beta] Remove feature flag for ds-serialize-ids-and-types (shipped in 2.6) #4416 --- FEATURES.md | 24 -------- addon/serializers/embedded-records-mixin.js | 9 +-- config/features.json | 1 - .../embedded-records-mixin-test.js | 57 +++++++++---------- 4 files changed, 29 insertions(+), 62 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index ba45a16dccd..1c6e0de793a 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -26,30 +26,6 @@ entry in `config/features.json`. Enables `pushPayload` to return the model(s) that are created or updated via the internal `store.push`. -- `ds-serialize-ids-and-types` [#3848](https://github.com/emberjs/data/pull/3848) - - Enables a new `ids-and-type` strategy (in addition to the already existing `ids` and `records`) for - serializing has many relationships using the `DS.EmbeddedRecordsMixin` that will include both - `id` and `type` of each model as an object. - - For instance, if a use has many pets, which is a polymorphic relationship, the generated payload would be: - - ```js - { - "user": { - "id": "1" - "name": "Bertin Osborne", - "pets": [ - { "id": "1", "type": "Cat" }, - { "id": "2", "type": "Parrot"} - ] - } - } - ``` - - This is particularly useful for polymorphic relationships not backed by STI when just including the id - of the records is not enough. - - `ds-extended-errors` [#3586](https://github.com/emberjs/data/pull/3586) [#4287](https://github.com/emberjs/data/pull/4287) Enables `extend` method on errors. It means you can extend from `DS.AdapterError`. diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index cfdd86a9430..f0da1a1f82e 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -1,6 +1,5 @@ import Ember from 'ember'; import { warn } from "ember-data/-private/debug"; -import isEnabled from 'ember-data/-private/features'; var get = Ember.get; var set = Ember.set; @@ -365,8 +364,6 @@ export default Ember.Mixin.create({ } ``` - Note that the `ids-and-types` strategy is still behind the `ds-serialize-ids-and-types` feature flag. - @method serializeHasMany @param {DS.Snapshot} snapshot @param {Object} json @@ -385,10 +382,8 @@ export default Ember.Mixin.create({ } else if (this.hasSerializeRecordsOption(attr)) { this._serializeEmbeddedHasMany(snapshot, json, relationship); } else { - if (isEnabled("ds-serialize-ids-and-types")) { - if (this.hasSerializeIdsAndTypesOption(attr)) { - this._serializeHasManyAsIdsAndTypes(snapshot, json, relationship); - } + if (this.hasSerializeIdsAndTypesOption(attr)) { + this._serializeHasManyAsIdsAndTypes(snapshot, json, relationship); } } }, diff --git a/config/features.json b/config/features.json index 79ca3c55c68..ab513781705 100644 --- a/config/features.json +++ b/config/features.json @@ -2,7 +2,6 @@ "ds-boolean-transform-allow-null": null, "ds-improved-ajax": null, "ds-pushpayload-return": null, - "ds-serialize-ids-and-types": true, "ds-extended-errors": null, "ds-links-in-record-array": null, "ds-overhaul-references": null, diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index 0d8f4351931..4b151636adb 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -5,7 +5,6 @@ import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; var get = Ember.get; var HomePlanet, SuperVillain, CommanderVillain, NormalMinion, EvilMinion, YellowMinion, RedMinion, SecretLab, SecretWeapon, BatCave, Comment, @@ -1074,38 +1073,36 @@ test("serialize with embedded objects (hasMany relationships, including related }); }); -if (isEnabled("ds-serialize-ids-and-types")) { - test("serialize has many relationship using the `ids-and-types` strategy", function(assert) { - run(function() { - yellowMinion = env.store.createRecord('yellow-minion', { id: 1, name: "Yellowy" }); - redMinion = env.store.createRecord('red-minion', { id: 1, name: "Reddy" }); - commanderVillain = env.store.createRecord('commander-villain', { id: 1, name: "Jeff", minions: [yellowMinion, redMinion] }); - }); +test("serialize has many relationship using the `ids-and-types` strategy", function(assert) { + run(function() { + yellowMinion = env.store.createRecord('yellow-minion', { id: 1, name: "Yellowy" }); + redMinion = env.store.createRecord('red-minion', { id: 1, name: "Reddy" }); + commanderVillain = env.store.createRecord('commander-villain', { id: 1, name: "Jeff", minions: [yellowMinion, redMinion] }); + }); - env.registry.register('serializer:commander-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - minions: { serialize: 'ids-and-types' } - } - })); - var serializer, json; - run(function() { - serializer = env.container.lookup("serializer:commander-villain"); - var snapshot = commanderVillain._createSnapshot(); - json = serializer.serialize(snapshot); - }); + env.registry.register('serializer:commander-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + minions: { serialize: 'ids-and-types' } + } + })); + var serializer, json; + run(function() { + serializer = env.container.lookup("serializer:commander-villain"); + var snapshot = commanderVillain._createSnapshot(); + json = serializer.serialize(snapshot); + }); - assert.deepEqual(json, { - name: 'Jeff', - minions: [{ - id: '1', - type: 'yellow-minion' - }, { - id: '1', - type: 'red-minion' - }] - }); + assert.deepEqual(json, { + name: 'Jeff', + minions: [{ + id: '1', + type: 'yellow-minion' + }, { + id: '1', + type: 'red-minion' + }] }); -} +}); test("normalizeResponse with embedded object (belongsTo relationship)", function(assert) { env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { From a7e0020e63ac97aa3b81228f619d045b0b178799 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 27 Jun 2016 14:41:16 -0400 Subject: [PATCH 1552/2527] Do not display in the API docs --- addon/-private/system/normalize-link.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/normalize-link.js b/addon/-private/system/normalize-link.js index edb1e52e404..59d9d6536e8 100644 --- a/addon/-private/system/normalize-link.js +++ b/addon/-private/system/normalize-link.js @@ -1,4 +1,4 @@ -/** +/* This method normalizes a link to an "links object". If the passed link is already an object it's returned without any modifications. From 963ac6518815de9ff43d8bc028220ccbe29a1902 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 27 Jun 2016 14:41:41 -0400 Subject: [PATCH 1553/2527] Add since tags for methods added in Ember Data 1.13 --- addon/-private/system/model/model.js | 2 ++ addon/-private/system/store.js | 6 ++++++ addon/adapter.js | 4 ++++ addon/adapters/json-api.js | 1 + addon/adapters/rest.js | 6 ++++++ addon/serializer.js | 1 + addon/serializers/json-api.js | 1 + addon/serializers/json.js | 14 ++++++++++++++ 8 files changed, 35 insertions(+) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 2685f5d8960..2c3b0a65852 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -117,6 +117,7 @@ var Model = Ember.Object.extend(Ember.Evented, { }); ``` + @since 1.13.0 @property hasDirtyAttributes @type {Boolean} @readOnly @@ -688,6 +689,7 @@ var Model = Ember.Object.extend(Ember.Evented, { record.get('name'); // 'Untitled Document' ``` + @since 1.13.0 @method rollbackAttributes */ rollbackAttributes() { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b083a475993..236ae592223 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -564,6 +564,7 @@ Store = Service.extend({ See [peekRecord](#method_peekRecord) to get the cached version of a record. + @since 1.13.0 @method findRecord @param {String} modelName @param {(String|Integer)} id @@ -877,6 +878,7 @@ Store = Service.extend({ post.get('id'); // 1 ``` + @since 1.13.0 @method peekRecord @param {String} modelName @param {String|Integer} id @@ -1068,6 +1070,7 @@ Store = Service.extend({ This method returns a promise, which is resolved with a `RecordArray` once the server returns. + @since 1.13.0 @method query @param {String} modelName @param {any} query an opaque query to be used by the adapter @@ -1180,6 +1183,7 @@ Store = Service.extend({ }); ``` + @since 1.13.0 @method queryRecord @param {String} modelName @param {any} query an opaque query to be used by the adapter @@ -1342,6 +1346,7 @@ Store = Service.extend({ See [query](#method_query) to only get a subset of records from the server. + @since 1.13.0 @method findAll @param {String} modelName @param {Object} options @@ -1422,6 +1427,7 @@ Store = Service.extend({ var localPosts = store.peekAll('post'); ``` + @since 1.13.0 @method peekAll @param {String} modelName @return {DS.RecordArray} diff --git a/addon/adapter.js b/addon/adapter.js index 2d1800b934c..93407617004 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -513,6 +513,7 @@ export default Ember.Object.extend({ By default this hook returns `false`, as most UIs should not block user interactions while waiting on data update. + @since 1.13.0 @method shouldReloadRecord @param {DS.Store} store @param {DS.Snapshot} snapshot @@ -560,6 +561,7 @@ export default Ember.Object.extend({ is empty (meaning that there are no records locally available yet), otherwise it returns `false`. + @since 1.13.0 @method shouldReloadAll @param {DS.Store} store @param {DS.SnapshotRecordArray} snapshotRecordArray @@ -598,6 +600,7 @@ export default Ember.Object.extend({ By default this hook returns `true` so the data for the record is updated in the background. + @since 1.13.0 @method shouldBackgroundReloadRecord @param {DS.Store} store @param {DS.Snapshot} snapshot @@ -636,6 +639,7 @@ export default Ember.Object.extend({ By default this method returns `true`, indicating that a background reload should always be triggered. + @since 1.13.0 @method shouldBackgroundReloadAll @param {DS.Store} store @param {DS.SnapshotRecordArray} snapshotRecordArray diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index 7fd59392376..87a817b88ef 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -7,6 +7,7 @@ import RESTAdapter from "ember-data/adapters/rest"; import isEnabled from 'ember-data/-private/features'; /** + @since 1.13.0 @class JSONAPIAdapter @constructor @namespace DS diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index ebfc66aede8..2415c0d7419 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -409,6 +409,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { This method performs an HTTP `GET` request with the id provided as part of the query string. + @since 1.13.0 @method findRecord @param {DS.Store} store @param {DS.Model} type @@ -515,6 +516,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { The `query` argument is a simple JavaScript object that will be passed directly to the server as parameters. + @since 1.13.0 @method queryRecord @param {DS.Store} store @param {DS.Model} type @@ -899,6 +901,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { returned from the server using the serializer's `extractErrors` method. + @since 1.13.0 @method handleResponse @param {Number} status @param {Object} headers @@ -940,6 +943,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { Default `handleResponse` implementation uses this hook to decide if the response is a success. + @since 1.13.0 @method isSuccess @param {Number} status @param {Object} headers @@ -954,6 +958,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { Default `handleResponse` implementation uses this hook to decide if the response is a an invalid error. + @since 1.13.0 @method isInvalid @param {Number} status @param {Object} headers @@ -1157,6 +1162,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { shortenedPayload].join('\n'); }, + // @since 2.5.0 buildQuery(snapshot) { let query = {}; diff --git a/addon/serializer.js b/addon/serializer.js index 4ace384ad03..1601766770d 100644 --- a/addon/serializer.js +++ b/addon/serializer.js @@ -43,6 +43,7 @@ export default Ember.Object.extend({ http://jsonapi.org/format/#document-structure + @since 1.13.0 @method normalizeResponse @param {DS.Store} store @param {DS.Model} primaryModelClass diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 46867299232..fd7b5b0b9e5 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -93,6 +93,7 @@ var dasherize = Ember.String.dasherize; to the format that the Ember Data store expects. + @since 1.13.0 @class JSONAPISerializer @namespace DS @extends DS.JSONSerializer diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 0833e0bc1ae..29ee9ad0dc5 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -225,6 +225,7 @@ var JSONSerializer = Serializer.extend({ }); ``` + @since 1.13.0 @method normalizeResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @@ -259,6 +260,7 @@ var JSONSerializer = Serializer.extend({ }, /** + @since 1.13.0 @method normalizeFindRecordResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @@ -272,6 +274,7 @@ var JSONSerializer = Serializer.extend({ }, /** + @since 1.13.0 @method normalizeQueryRecordResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @@ -285,6 +288,7 @@ var JSONSerializer = Serializer.extend({ }, /** + @since 1.13.0 @method normalizeFindAllResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @@ -298,6 +302,7 @@ var JSONSerializer = Serializer.extend({ }, /** + @since 1.13.0 @method normalizeFindBelongsToResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @@ -311,6 +316,7 @@ var JSONSerializer = Serializer.extend({ }, /** + @since 1.13.0 @method normalizeFindHasManyResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @@ -324,6 +330,7 @@ var JSONSerializer = Serializer.extend({ }, /** + @since 1.13.0 @method normalizeFindManyResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @@ -337,6 +344,7 @@ var JSONSerializer = Serializer.extend({ }, /** + @since 1.13.0 @method normalizeQueryResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @@ -350,6 +358,7 @@ var JSONSerializer = Serializer.extend({ }, /** + @since 1.13.0 @method normalizeCreateRecordResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @@ -363,6 +372,7 @@ var JSONSerializer = Serializer.extend({ }, /** + @since 1.13.0 @method normalizeDeleteRecordResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @@ -376,6 +386,7 @@ var JSONSerializer = Serializer.extend({ }, /** + @since 1.13.0 @method normalizeUpdateRecordResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @@ -389,6 +400,7 @@ var JSONSerializer = Serializer.extend({ }, /** + @since 1.13.0 @method normalizeSaveResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @@ -402,6 +414,7 @@ var JSONSerializer = Serializer.extend({ }, /** + @since 1.13.0 @method normalizeSingleResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @@ -415,6 +428,7 @@ var JSONSerializer = Serializer.extend({ }, /** + @since 1.13.0 @method normalizeArrayResponse @param {DS.Store} store @param {DS.Model} primaryModelClass From 7c94e33c7bc8bf53a04e296e2ccabcf35321b5e9 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 24 Jun 2016 15:36:27 -0400 Subject: [PATCH 1554/2527] [BUGFIX beta] The adapter should call `ajax` instead of the new methods if it has been customized. --- addon/adapters/json-api.js | 25 ++++++++++- addon/adapters/rest.js | 42 +++++++++++++----- config/features.json | 6 +-- package.json | 2 +- .../integration/adapter/rest-adapter-test.js | 43 +++++++++++++++++++ 5 files changed, 101 insertions(+), 17 deletions(-) diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index 7fd59392376..e0cdd14d283 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -5,6 +5,7 @@ import Ember from 'ember'; import RESTAdapter from "ember-data/adapters/rest"; import isEnabled from 'ember-data/-private/features'; +import { deprecate } from 'ember-data/-private/debug'; /** @class JSONAPIAdapter @@ -99,7 +100,7 @@ var JSONAPIAdapter = RESTAdapter.extend({ @return {Promise} promise */ findMany(store, type, ids, snapshots) { - if (isEnabled('ds-improved-ajax')) { + if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { return this._super(...arguments); } else { var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); @@ -126,7 +127,7 @@ var JSONAPIAdapter = RESTAdapter.extend({ @return {Promise} promise */ updateRecord(store, type, snapshot) { - if (isEnabled('ds-improved-ajax')) { + if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { return this._super(...arguments); } else { var data = {}; @@ -139,6 +140,26 @@ var JSONAPIAdapter = RESTAdapter.extend({ return this.ajax(url, 'PATCH', { data: data }); } + }, + + _hasCustomizedAjax() { + if (this.ajax !== JSONAPIAdapter.prototype.ajax) { + deprecate('JSONAPIAdapter#ajax has been deprecated please use. `methodForRequest`, `urlForRequest`, `headersForRequest` or `dataForRequest` instead.', false, { + id: 'ds.json-api-adapter.ajax', + until: '3.0.0' + }); + return true; + } + + if (this.ajaxOptions !== JSONAPIAdapter.prototype.ajaxOptions) { + deprecate('JSONAPIAdapterr#ajaxOptions has been deprecated please use. `methodForRequest`, `urlForRequest`, `headersForRequest` or `dataForRequest` instead.', false, { + id: 'ds.json-api-adapter.ajax-options', + until: '3.0.0' + }); + return true; + } + + return false; } }); diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index ebfc66aede8..91d82a70d26 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -17,7 +17,7 @@ import { } from 'ember-data/adapters/errors'; import BuildURLMixin from "ember-data/-private/adapters/build-url-mixin"; import isEnabled from 'ember-data/-private/features'; -import { runInDebug, warn } from 'ember-data/-private/debug'; +import { runInDebug, warn, deprecate } from 'ember-data/-private/debug'; import parseResponseHeaders from 'ember-data/-private/utils/parse-response-headers'; const { @@ -417,7 +417,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findRecord(store, type, id, snapshot) { - if (isEnabled('ds-improved-ajax')) { + if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { const request = this._requestFor({ store, type, id, snapshot, requestType: 'findRecord' @@ -449,7 +449,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { findAll(store, type, sinceToken, snapshotRecordArray) { const query = this.buildQuery(snapshotRecordArray); - if (isEnabled('ds-improved-ajax')) { + if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { const request = this._requestFor({ store, type, sinceToken, query, snapshots: snapshotRecordArray, @@ -486,7 +486,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ query(store, type, query) { - if (isEnabled('ds-improved-ajax')) { + if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { const request = this._requestFor({ store, type, query, requestType: 'query' @@ -522,7 +522,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ queryRecord(store, type, query) { - if (isEnabled('ds-improved-ajax')) { + if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { const request = this._requestFor({ store, type, query, requestType: 'queryRecord' @@ -574,7 +574,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findMany(store, type, ids, snapshots) { - if (isEnabled('ds-improved-ajax')) { + if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { const request = this._requestFor({ store, type, ids, snapshots, requestType: 'findMany' @@ -623,7 +623,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findHasMany(store, snapshot, url, relationship) { - if (isEnabled('ds-improved-ajax')) { + if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { const request = this._requestFor({ store, snapshot, url, relationship, requestType: 'findHasMany' @@ -676,7 +676,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findBelongsTo(store, snapshot, url, relationship) { - if (isEnabled('ds-improved-ajax')) { + if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { const request = this._requestFor({ store, snapshot, url, relationship, requestType: 'findBelongsTo' @@ -709,7 +709,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ createRecord(store, type, snapshot) { - if (isEnabled('ds-improved-ajax')) { + if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { const request = this._requestFor({ store, type, snapshot, requestType: 'createRecord' @@ -744,7 +744,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ updateRecord(store, type, snapshot) { - if (isEnabled('ds-improved-ajax')) { + if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { const request = this._requestFor({ store, type, snapshot, requestType: 'updateRecord' @@ -776,7 +776,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ deleteRecord(store, type, snapshot) { - if (isEnabled('ds-improved-ajax')) { + if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { const request = this._requestFor({ store, type, snapshot, requestType: 'deleteRecord' @@ -1169,6 +1169,26 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { } return query; + }, + + _hasCustomizedAjax() { + if (this.ajax !== RESTAdapter.prototype.ajax) { + deprecate('RESTAdapter#ajax has been deprecated please use. `methodForRequest`, `urlForRequest`, `headersForRequest` or `dataForRequest` instead.', false, { + id: 'ds.rest-adapter.ajax', + until: '3.0.0' + }); + return true; + } + + if (this.ajaxOptions !== RESTAdapter.prototype.ajaxOptions) { + deprecate('RESTAdapter#ajaxOptions has been deprecated please use. `methodForRequest`, `urlForRequest`, `headersForRequest` or `dataForRequest` instead.', false, { + id: 'ds.rest-adapter.ajax-options', + until: '3.0.0' + }); + return true; + } + + return false; } }); diff --git a/config/features.json b/config/features.json index 79ca3c55c68..16a1fe42265 100644 --- a/config/features.json +++ b/config/features.json @@ -1,10 +1,10 @@ { - "ds-boolean-transform-allow-null": null, - "ds-improved-ajax": null, + "ds-boolean-transform-allow-null": true, + "ds-improved-ajax": true, "ds-pushpayload-return": null, "ds-serialize-ids-and-types": true, "ds-extended-errors": null, - "ds-links-in-record-array": null, + "ds-links-in-record-array": true, "ds-overhaul-references": null, "ds-payload-type-hooks": null, "ds-check-should-serialize-relationships": null, diff --git a/package.json b/package.json index 2c3a25b2db9..b044a605b1f 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "license": "MIT", "dependencies": { "amd-name-resolver": "0.0.5", - "babel-plugin-feature-flags": "^0.2.0", + "babel-plugin-feature-flags": "^0.2.1", "babel-plugin-filter-imports": "^0.2.0", "broccoli-babel-transpiler": "^5.5.0", "broccoli-file-creator": "^1.0.0", diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index d2ab0e33da5..c6732bccdc0 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -2593,3 +2593,46 @@ testInDebug("warns when an empty response is returned, though a valid stringifie assert.expectWarning("The server returned an empty string for POST /posts, which cannot be parsed into a valid JSON. Return either null or {}."); }); + + +if (isEnabled('ds-improved-ajax')) { + testInDebug("The RESTAdapter should use `ajax` with a deprecation message when it is overridden by the user.", function(assert) { + assert.expect(2) + + adapter.ajax = function(url, verb, hash) { + assert.ok(true, 'The ajax method should be called when it is overridden'); + return { posts: { id: 1, name: "Rails is omakase" } }; + }; + + assert.expectDeprecation(function() { + run(function() { + store.findRecord('post', 1); + }); + }, /RESTAdapter#ajax has been deprecated/) + }); + + + testInDebug("The RESTAdapter should use `ajaxOptions` with a deprecation message when it is overridden by the user.", function(assert) { + assert.expect(2) + + adapter._ajaxRequest = function(hash) { + var jqXHR = { + status: 200, + getAllResponseHeaders() { return ''; } + }; + hash.success({ posts: { id: 1, name: "Rails is omakase" } }, 'OK', jqXHR); + } + + var oldAjaxOptions = adapter.ajaxOptions; + adapter.ajaxOptions = function() { + assert.ok(true, 'The ajaxOptions method should be called when it is overridden'); + return oldAjaxOptions.apply(this, arguments); + }; + + assert.expectDeprecation(function() { + run(function() { + store.findRecord('post', 1); + }); + }, /RESTAdapter#ajaxOptions has been deprecated/) + }); +} From 9adfe8d38fed0aada18fff31996cffcd34f13abb Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 4 Jul 2016 08:38:43 -0400 Subject: [PATCH 1555/2527] =?UTF-8?q?Ember=20Data=20is=20no=20Dummy=20?= =?UTF-8?q?=F0=9F=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I kept getting confused between Ember Data's tests and an addon I had been testing. --- tests/dummy/app/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/dummy/app/index.html b/tests/dummy/app/index.html index c9b432708dd..190c96a0605 100644 --- a/tests/dummy/app/index.html +++ b/tests/dummy/app/index.html @@ -3,7 +3,7 @@ - Dummy + Ember Data From d73e575711519091d2c685bee575e4f57ed9d6a5 Mon Sep 17 00:00:00 2001 From: Jacob Jewell Date: Wed, 6 Jul 2016 21:53:01 -0400 Subject: [PATCH 1556/2527] Add benchmarks directory to npmignore --- .npmignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.npmignore b/.npmignore index 38a8d226e1f..3f8caf945a5 100644 --- a/.npmignore +++ b/.npmignore @@ -4,6 +4,7 @@ /node-tests /tests /tmp +/benchmarks **/.gitkeep .appveyor.yml From 75d82bed158a4bf07c00e4ad5d198cf5d38a8c9a Mon Sep 17 00:00:00 2001 From: Jeroen van de Ven Date: Fri, 24 Jun 2016 12:10:56 +0200 Subject: [PATCH 1557/2527] [BUGFIX beta] Fixes issue with GET requests appending ?{} to url --- addon/adapters/rest.js | 2 +- .../integration/adapter/rest-adapter-test.js | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 91d82a70d26..25eaafc8d8d 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1361,7 +1361,7 @@ if (isEnabled('ds-improved-ajax')) { hash.context = this; if (request.data) { - if (request.type !== 'GET') { + if (request.method !== 'GET') { hash.contentType = 'application/json; charset=utf-8'; hash.data = JSON.stringify(request.data); } else { diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index c6732bccdc0..0343dd98662 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -2635,4 +2635,25 @@ if (isEnabled('ds-improved-ajax')) { }); }, /RESTAdapter#ajaxOptions has been deprecated/) }); + + test("_requestToJQueryAjaxHash works correctly for GET requests - GH-4445", function(assert) { + let done = assert.async(); + let server = new Pretender(); + + server.get('/posts/1', function(request) { + assert.equal(request.url, "/posts/1", "no query param is added to the GET request"); + + return [201, { "Content-Type": "application/json" }, JSON.stringify({ post: { id: 1 } })]; + }); + + run(function() { + let post = store.findRecord('post', 1); + + post.then(function() { + server.shutdown(); + done(); + }); + }); + }); + } From a7b8ad97e6b7dbc7df134065060d77e8c9880bbd Mon Sep 17 00:00:00 2001 From: The Game Date: Thu, 7 Jul 2016 10:15:13 +0100 Subject: [PATCH 1558/2527] [BUGFIX] if canonical state exists always apply it for belongsTo relationships #4469 --- .../system/relationships/state/belongs-to.js | 1 + .../model/relationships/belongs-to-test.js | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 82df9f7a74a..4dcb1a0322e 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -36,6 +36,7 @@ BelongsToRelationship.prototype.setCanonicalRecord = function(newRecord) { } else if (this.canonicalState) { this.removeCanonicalRecord(this.canonicalState); } + this.flushCanonicalLater(); this.setHasData(true); this.setHasLoaded(true); }; diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index 76394b406b9..b852b37aa37 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -167,6 +167,50 @@ test("async belongsTo relationships work when the data hash has already been loa }); }); +test("when response to saving a belongsTo is a success but includes changes that reset the users change", function(assert) { + var Tag = DS.Model.extend(); + var User = DS.Model.extend({ tag: DS.belongsTo() }); + var env = setupStore({ user: User, tag: Tag }); + var store = env.store; + + run(function() { + store.push({ + data: [ + { type: 'user', + id: '1', + relationships: { + tag: { + data: { type: 'tag', id: '1' } + } + } + }, + { type: 'tag', id: '1' }, + { type: 'tag', id: '2' } + ] + }); + }); + + let user = store.peekRecord('user', '1'); + + run(function() { + user.set('tag', store.peekRecord('tag', '2')); + }); + + env.adapter.updateRecord = function() { + return { + type: 'user', + id: '1', + tag: { type: 'tag', id: '1' } + }; + }; + + run(function() { + user.save().then(assert.wait(function(user) { + assert.equal(user.get('tag.id'), '1', 'expected new server state to be applied'); + })); + }); +}); + test("calling createRecord and passing in an undefined value for a relationship should be treated as if null", function(assert) { assert.expect(1); From 7792213b1b46c67f170be75f51dfe268260ad788 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 25 Jul 2016 09:42:05 -0400 Subject: [PATCH 1559/2527] [BUGFIX release] Revert blueprints to use the old import DS format --- blueprints/adapter/index.js | 2 +- blueprints/model/HELP.md | 17 ++--- .../model/files/__root__/__path__/__name__.js | 4 +- blueprints/model/index.js | 35 ++-------- blueprints/serializer/index.js | 2 +- .../files/__root__/__path__/__name__.js | 4 +- .../extend-from-application-entity.js | 6 +- node-tests/blueprints/adapter-test.js | 8 +-- node-tests/blueprints/model-test.js | 69 ++++++------------- node-tests/blueprints/serializer-test.js | 8 +-- node-tests/blueprints/transform-test.js | 4 +- 11 files changed, 49 insertions(+), 110 deletions(-) diff --git a/blueprints/adapter/index.js b/blueprints/adapter/index.js index 1f8ea57a426..b3ecab8c23f 100644 --- a/blueprints/adapter/index.js +++ b/blueprints/adapter/index.js @@ -10,6 +10,6 @@ module.exports = { ], locals: function(options) { - return extendFromApplicationEntity('adapter', 'JSONAPIAdapter', 'ember-data/adapters/json-api', options); + return extendFromApplicationEntity('adapter', 'DS.JSONAPIAdapter', options); } }; diff --git a/blueprints/model/HELP.md b/blueprints/model/HELP.md index bfd70568519..caba05ddbac 100644 --- a/blueprints/model/HELP.md +++ b/blueprints/model/HELP.md @@ -14,16 +14,13 @@ For instance: \`ember generate model taco filling:belongs-to:protein topp would result in the following model: ```js -import Model from 'ember-data/model'; +import DS from 'ember-data'; -import attr from 'ember-data/attr'; -import { belongsTo, hasMany } from 'ember-data/relationships'; - -export default Model.extend({ - filling: belongsTo('protein'), - toppings: hasMany('topping'), - name: attr('string'), - price: attr('number'), - misc: attr() +export default DS.Model.extend({ + filling: DS.belongsTo('protein'), + toppings: DS.hasMany('topping'), + name: DS.attr('string'), + price: DS.attr('number'), + misc: DS.attr() }); ``` diff --git a/blueprints/model/files/__root__/__path__/__name__.js b/blueprints/model/files/__root__/__path__/__name__.js index d92b5042812..3661e07bc60 100644 --- a/blueprints/model/files/__root__/__path__/__name__.js +++ b/blueprints/model/files/__root__/__path__/__name__.js @@ -1,5 +1,5 @@ -<%= importStatements %> +import DS from 'ember-data'; -export default Model.extend({ +export default DS.Model.extend({ <%= attrs.length ? ' ' + attrs : '' %> }); diff --git a/blueprints/model/index.js b/blueprints/model/index.js index 4d813b39b59..6f19377212c 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -16,10 +16,6 @@ module.exports = { var attrs = []; var needs = []; var entityOptions = options.entity.options; - var importStatements = ['import Model from \'ember-data/model\';']; - var shouldImportAttr = false; - var shouldImportBelongsTo = false; - var shouldImportHasMany = false; for (var name in entityOptions) { var type = entityOptions[name] || ''; @@ -39,15 +35,12 @@ module.exports = { var camelizedNamePlural = inflection.pluralize(camelizedName); attr = dsAttr(dasherizedForeignModelSingular, dasherizedType); attrs.push(camelizedNamePlural + ': ' + attr); - shouldImportHasMany = true; } else if (/belongs-to/.test(dasherizedType)) { attr = dsAttr(dasherizedForeignModel, dasherizedType); attrs.push(camelizedName + ': ' + attr); - shouldImportBelongsTo = true; } else { attr = dsAttr(dasherizedName, dasherizedType); attrs.push(camelizedName + ': ' + attr); - shouldImportAttr = true; } if (/has-many|belongs-to/.test(dasherizedType)) { @@ -59,30 +52,10 @@ module.exports = { return needs.indexOf(need) === i; }); - if (shouldImportAttr) { - importStatements.push('import attr from \'ember-data/attr\';'); - } else { - importStatements.push('// import attr from \'ember-data/attr\';'); - } - - if (shouldImportBelongsTo && shouldImportHasMany) { - importStatements.push('import { belongsTo, hasMany } from \'ember-data/relationships\';'); - } else if (shouldImportBelongsTo) { - importStatements.push('import { belongsTo } from \'ember-data/relationships\';'); - importStatements.push('// import { hasMany } from \'ember-data/relationships\';'); - } else if (shouldImportHasMany) { - importStatements.push('// import { belongsTo } from \'ember-data/relationships\';'); - importStatements.push('import { hasMany } from \'ember-data/relationships\';'); - } else { - importStatements.push('// import { belongsTo, hasMany } from \'ember-data/relationships\';'); - } - - importStatements = importStatements.join(EOL); attrs = attrs.join(',' + EOL + ' '); needs = ' needs: [' + needsDeduplicated.join(', ') + ']'; return { - importStatements: importStatements, attrs: attrs, needs: needs }; @@ -92,14 +65,14 @@ module.exports = { function dsAttr(name, type) { switch (type) { case 'belongs-to': - return 'belongsTo(\'' + name + '\')'; + return 'DS.belongsTo(\'' + name + '\')'; case 'has-many': - return 'hasMany(\'' + name + '\')'; + return 'DS.hasMany(\'' + name + '\')'; case '': //"If you don't specify the type of the attribute, it will be whatever was provided by the server" //http://emberjs.com/guides/models/defining-models/ - return 'attr()'; + return 'DS.attr()'; default: - return 'attr(\'' + type + '\')'; + return 'DS.attr(\'' + type + '\')'; } } diff --git a/blueprints/serializer/index.js b/blueprints/serializer/index.js index 1e43a8a2fa0..b5b278ae70a 100644 --- a/blueprints/serializer/index.js +++ b/blueprints/serializer/index.js @@ -10,6 +10,6 @@ module.exports = { ], locals: function(options) { - return extendFromApplicationEntity('serializer', 'JSONAPISerializer', 'ember-data/serializers/json-api', options); + return extendFromApplicationEntity('serializer', 'DS.JSONAPISerializer', options); } }; diff --git a/blueprints/transform/files/__root__/__path__/__name__.js b/blueprints/transform/files/__root__/__path__/__name__.js index 1d048927535..722408742d7 100644 --- a/blueprints/transform/files/__root__/__path__/__name__.js +++ b/blueprints/transform/files/__root__/__path__/__name__.js @@ -1,6 +1,6 @@ -import Transform from 'ember-data/transform'; +import DS from 'ember-data'; -export default Transform.extend({ +export default DS.Transform.extend({ deserialize(serialized) { return serialized; }, diff --git a/lib/utilities/extend-from-application-entity.js b/lib/utilities/extend-from-application-entity.js index cb340293364..437a38818b4 100644 --- a/lib/utilities/extend-from-application-entity.js +++ b/lib/utilities/extend-from-application-entity.js @@ -4,7 +4,7 @@ var pathUtil = require('ember-cli-path-utils'); var existsSync = require('exists-sync'); var path = require('path'); -module.exports = function(type, baseClass, packagePath, options) { +module.exports = function(type, baseClass, options) { var entityName = options.entity.name; var isAddon = options.inRepoAddon || options.project.isEmberCLIAddon(); var relativePath = pathUtil.getRelativePath(options.entity.name); @@ -18,14 +18,12 @@ module.exports = function(type, baseClass, packagePath, options) { var hasApplicationEntity = existsSync(applicationEntityPath); if (!isAddon && !options.baseClass && entityName !== 'application' && hasApplicationEntity) { options.baseClass = 'application'; - packagePath = './application'; } if (options.baseClass === entityName) { throw new SilentError(stringUtil.classify(type) + 's cannot extend from themself. To resolve this, remove the `--base-class` option or change to a different base-class.'); } - - var importStatement = 'import ' + baseClass + ' from \'' + packagePath + '\';'; + var importStatement = 'import DS from \'ember-data\';'; if (options.baseClass) { baseClass = stringUtil.classify(options.baseClass.replace('\/', '-')); diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 26475faca6a..699abfa1454 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -19,8 +19,8 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/adapters/foo.js')) - .to.contain('import JSONAPIAdapter from \'ember-data/adapters/json-api\';') - .to.contain('export default JSONAPIAdapter.extend({'); + .to.contain('import DS from \'ember-data\';') + .to.contain('export default DS.JSONAPIAdapter.extend({'); expect(_file('tests/unit/adapters/foo-test.js')) .to.contain('moduleFor(\'adapter:foo\''); @@ -70,8 +70,8 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/adapters/application.js')) - .to.contain('import JSONAPIAdapter from \'ember-data/adapters/json-api\';') - .to.contain('export default JSONAPIAdapter.extend({'); + .to.contain('import DS from \'ember-data\';') + .to.contain('export default DS.JSONAPIAdapter.extend({'); expect(_file('tests/unit/adapters/application-test.js')) .to.contain('moduleFor(\'adapter:application\''); diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index d3565b41ea3..70e046f9517 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -16,12 +16,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/models/foo.js')) - .to.contain('import Model from \'ember-data/model\';') - .to.contain('export default Model.extend(') - .to.contain('// import attr from \'ember-data/attr\';') - .to.contain('// import { belongsTo, hasMany } from \'ember-data/relationships\';') - .to.not.contain('import { belongsTo } from \'ember-data/relationships\';') - .to.not.contain('import { hasMany } from \'ember-data/relationships\';'); + .to.contain('import DS from \'ember-data\';') + .to.contain('export default DS.Model.extend(') expect(_file('tests/unit/models/foo-test.js')) .to.contain('moduleForModel(\'foo\''); @@ -45,20 +41,16 @@ describe('Acceptance: generate and destroy model blueprints', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/models/foo.js')) - .to.contain('import Model from \'ember-data/model\';') - .to.contain('import attr from \'ember-data/attr\';') - .to.contain('export default Model.extend(') - .to.contain('misc: attr()') - .to.contain('skills: attr(\'array\')') - .to.contain('isActive: attr(\'boolean\')') - .to.contain('birthday: attr(\'date\')') - .to.contain('someObject: attr(\'object\')') - .to.contain('age: attr(\'number\')') - .to.contain('name: attr(\'string\')') - .to.contain('customAttr: attr(\'custom-transform\')') - .to.contain('// import { belongsTo, hasMany } from \'ember-data/relationships\';') - .to.not.contain('import { belongsTo } from \'ember-data/relationships\';') - .to.not.contain('import { hasMany } from \'ember-data/relationships\';'); + .to.contain('import DS from \'ember-data\';') + .to.contain('export default DS.Model.extend(') + .to.contain('misc: DS.attr()') + .to.contain('skills: DS.attr(\'array\')') + .to.contain('isActive: DS.attr(\'boolean\')') + .to.contain('birthday: DS.attr(\'date\')') + .to.contain('someObject: DS.attr(\'object\')') + .to.contain('age: DS.attr(\'number\')') + .to.contain('name: DS.attr(\'string\')') + .to.contain('customAttr: DS.attr(\'custom-transform\')') expect(_file('tests/unit/models/foo-test.js')) .to.contain('moduleForModel(\'foo\''); @@ -71,14 +63,10 @@ describe('Acceptance: generate and destroy model blueprints', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/models/comment.js')) - .to.contain('import Model from \'ember-data/model\';') - .to.contain('import { belongsTo } from \'ember-data/relationships\';') - .to.contain('export default Model.extend(') - .to.contain('post: belongsTo(\'post\')') - .to.contain('author: belongsTo(\'user\')') - .to.contain('// import attr from \'ember-data/attr\';') - .to.contain('// import { hasMany } from \'ember-data/relationships\';') - .to.not.contain('import { belongsTo, hasMany } from \'ember-data/relationships\';'); + .to.contain('import DS from \'ember-data\';') + .to.contain('export default DS.Model.extend(') + .to.contain('post: DS.belongsTo(\'post\')') + .to.contain('author: DS.belongsTo(\'user\')') expect(_file('tests/unit/models/comment-test.js')) .to.contain('moduleForModel(\'comment\'') @@ -92,14 +80,10 @@ describe('Acceptance: generate and destroy model blueprints', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/models/post.js')) - .to.contain('import Model from \'ember-data/model\';') - .to.contain('import { hasMany } from \'ember-data/relationships\';') - .to.contain('export default Model.extend(') - .to.contain('comments: hasMany(\'comment\')') - .to.contain('otherComments: hasMany(\'comment\')') - .to.contain('// import attr from \'ember-data/attr\';') - .to.contain('// import { belongsTo } from \'ember-data/relationships\';') - .to.not.contain('import { belongsTo, hasMany } from \'ember-data/relationships\';'); + .to.contain('import DS from \'ember-data\';') + .to.contain('export default DS.Model.extend(') + .to.contain('comments: DS.hasMany(\'comment\')') + .to.contain('otherComments: DS.hasMany(\'comment\')') expect(_file('tests/unit/models/post-test.js')) .to.contain('moduleForModel(\'post\'') @@ -107,19 +91,6 @@ describe('Acceptance: generate and destroy model blueprints', function() { })); }); - it('model with belongsTo and hasMany has both imports', function() { - var args = ['model', 'post', 'comments:has-many', 'user:belongs-to']; - - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { - expect(_file('app/models/post.js')) - .to.contain('import { belongsTo, hasMany } from \'ember-data/relationships\';') - .to.contain('// import attr from \'ember-data/attr\';') - .to.not.contain('import { belongsTo } from \'ember-data/relationships\';') - .to.not.contain('import { hasMany } from \'ember-data/relationships\';'); - })); - }); - it('model-test', function() { var args = ['model-test', 'foo']; diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index 8adc60f1745..b7eb757e527 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -19,8 +19,8 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/serializers/foo.js')) - .to.contain('import JSONAPISerializer from \'ember-data/serializers/json-api\';') - .to.contain('export default JSONAPISerializer.extend('); + .to.contain('import DS from \'ember-data\';') + .to.contain('export default DS.JSONAPISerializer.extend('); expect(_file('tests/unit/serializers/foo-test.js')) .to.contain('moduleForModel(\'foo\''); @@ -70,8 +70,8 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/serializers/application.js')) - .to.contain('import JSONAPISerializer from \'ember-data/serializers/json-api\';') - .to.contain('export default JSONAPISerializer.extend({'); + .to.contain('import DS from \'ember-data\';') + .to.contain('export default DS.JSONAPISerializer.extend({'); expect(_file('tests/unit/serializers/application-test.js')) .to.contain('moduleForModel(\'application\''); diff --git a/node-tests/blueprints/transform-test.js b/node-tests/blueprints/transform-test.js index f52814c712e..cebe88093b6 100644 --- a/node-tests/blueprints/transform-test.js +++ b/node-tests/blueprints/transform-test.js @@ -16,8 +16,8 @@ describe('Acceptance: generate and destroy transform blueprints', function() { return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/transforms/foo.js')) - .to.contain('import Transform from \'ember-data/transform\';') - .to.contain('export default Transform.extend(') + .to.contain('import DS from \'ember-data\';') + .to.contain('export default DS.Transform.extend(') .to.contain('deserialize(serialized) {') .to.contain('serialize(deserialized) {'); From 5d3c1b1de309bc2462d03d204d25b22e2102e00c Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 25 Jul 2016 11:36:06 -0400 Subject: [PATCH 1560/2527] [BUGFIX beta] Update API docs to import DS from 'ember-data' --- addon/-private/system/store.js | 4 ++-- addon/serializers/json-api.js | 6 +++--- addon/serializers/rest.js | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b083a475993..caa31ed677f 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1127,9 +1127,9 @@ Store = Service.extend({ ```javascript // app/adapters/user.js - import Adapter from "ember-data/adapter"; + import DS from "ember-data"; - export default Adapter.extend({ + export default DS.Adapter.extend({ queryRecord(modelName, query) { return Ember.$.getJSON("/api/current_user"); } diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 46867299232..c77a1d83a69 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -647,9 +647,9 @@ if (isEnabled("ds-payload-type-hooks")) { `posr` model should be used: ```app/serializers/application.js - import JSONAPISerializer from "ember-data/serializers/json-api"; + import DS from "ember-data"; - export default JSONAPISerializer.extend({ + export default DS.JSONAPISerializer.extend({ modelNameFromPayloadType(payloadType) { return payloadType.replace('api::v1::', ''); } @@ -695,7 +695,7 @@ if (isEnabled("ds-payload-type-hooks")) { namespaces model name for the `post` should be used: ```app/serializers/application.js - import JSONAPISerializer from "ember-data/serializers/json-api"; + import DS from "ember-data"; export default JSONAPISerializer.extend({ payloadTypeFromModelName(modelName) { diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 2093f7680f0..13864f50cf1 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -880,9 +880,9 @@ if (isEnabled("ds-payload-type-hooks")) { `administrator` model should be used: ```app/serializers/application.js - import RESTSerializer from "ember-data/serializers/rest"; + import DS from "ember-data"; - export default RESTSerializer.extend({ + export default DS.RESTSerializer.extend({ modelNameFromPayloadType(payloadType) { return payloadType.replace('api::v1::', ''); } @@ -930,9 +930,9 @@ if (isEnabled("ds-payload-type-hooks")) { namespaces model name for the `administrator` should be used: ```app/serializers/application.js - import RESTSerializer from "ember-data/serializers/rest"; + import DS from "ember-data"; - export default RESTSerializer.extend({ + export default DS.RESTSerializer.extend({ payloadTypeFromModelName(modelName) { return "api::v1::" + modelName; } From 4afb8d4dbc4ef74324027984a95ba9a265e94e12 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 25 Jul 2016 16:21:24 -0400 Subject: [PATCH 1561/2527] Update changelog for the Ember Data 2.7.0 release --- CHANGELOG.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3a351bf8a6..830a29dd0b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,41 @@ ### Master +### Release 2.7.0 (July 25, 2016) +- [#4482](https://github.com/emberjs/data/pull/4482) Disable ds-improved-ajax for the 2.7 release +- [#4470](https://github.com/emberjs/data/pull/4470) Belongs to not updating when response contains a change with the previous value +- [#4481](https://github.com/emberjs/data/pull/4481) [BUGFIX release] Revert blueprints to use the old import DS format +- [#4484](https://github.com/emberjs/data/pull/4484) [BUGFIX beta] Update API docs to import DS from 'ember-data' +- [#4454](https://github.com/emberjs/data/pull/4454) Add since tags for methods added in Ember Data 1.13 +- [#4464](https://github.com/emberjs/data/pull/4464) Add benchmarks directory to npmignore +- [#4466](https://github.com/emberjs/data/pull/4466) [BUGFIX beta] Fixes issue with GET requests appending ?{} to url +- [#4425](https://github.com/emberjs/data/pull/4425) [BUGFIX] Pass options to transform for serialization in json-api +- [#4433](https://github.com/emberjs/data/pull/4433) Remove JSHint directives from Mocha test blueprints +- [#4435](https://github.com/emberjs/data/pull/4435) [DOC] typo fix for queryRecord (kown -> known) +- [#4448](https://github.com/emberjs/data/pull/4448) [BUGFIX beta] The adapter should call `ajax` instead of the new metho… +- [#4320](https://github.com/emberjs/data/pull/4320) Fixup feature flagging infrastructure. +- [#4311](https://github.com/emberjs/data/pull/4311) Use property lookup in applyTransforms +- [#4318](https://github.com/emberjs/data/pull/4318) [FEATURE ds-payload-hooks] Add hooks to map type in payload to modelName +- [#4378](https://github.com/emberjs/data/pull/4378) [DOC] Add link to PR's for every feature +- [#4327](https://github.com/emberjs/data/pull/4327) [DOC] Update CONTRIBUTING.md for feature flags +- [#4389](https://github.com/emberjs/data/pull/4389) call super in addon#init +- [#4337](https://github.com/emberjs/data/pull/4337) [DOC] Update README.md for improve ES6 syntax in example +- [#4348](https://github.com/emberjs/data/pull/4348) [CLEANUP ds-finder-include] +- [#4347](https://github.com/emberjs/data/pull/4347) [CLEANUP ds-references] +- [#4345](https://github.com/emberjs/data/pull/4345) [DOC] fix example syntax +- [#4334](https://github.com/emberjs/data/pull/4334) Port the 2.5.x changelog entires to master +- [#4393](https://github.com/emberjs/data/pull/4393) During normalization, use property lookup instead of hasOwnProp checks +- [#4363](https://github.com/emberjs/data/pull/4363) [DOC] Fix hard-coded "Customizing Adapters" link +- [#4350](https://github.com/emberjs/data/pull/4350) [CLEANUP ds-transform-pass-options] +- [#4374](https://github.com/emberjs/data/pull/4374) Fix #4366: EmbeddedRecordsMixin embeds the record, not the snapshot +- [#4392](https://github.com/emberjs/data/pull/4392) Fix lint errors caused by merging an older pr +- [#4396](https://github.com/emberjs/data/pull/4396) Deprecate date parse +- [#4398](https://github.com/emberjs/data/pull/4398) [FEATURE ds-overhaul-references] Fix inconsistencies with Reference#push +- [#4399](https://github.com/emberjs/data/pull/4399) Add link to PR of ds-payload-type-hooks feature +- [#4403](https://github.com/emberjs/data/pull/4403) [BUGFIX beta] Correctly coalesce URI encoded ids +- [#4405](https://github.com/emberjs/data/pull/4405) [BUGFIX beta] Document the adapterOptions property +- [#4427](https://github.com/emberjs/data/pull/4427) Update changelog for the 2.6.0 release + ### Release 2.6.1 (June 15, 2016) - [#4425](https://github.com/emberjs/data/pull/4425) [BUGFIX] Pass options to transform for serialization in json-api - [#4389](https://github.com/emberjs/data/pull/4389) call super in addon#init From c535f8dfcebcee4bec2d09712045a8d5d43fab23 Mon Sep 17 00:00:00 2001 From: Chad Hietala Date: Mon, 1 Aug 2016 14:36:47 -0700 Subject: [PATCH 1562/2527] [DOCS] No need to use Ember.run in succes and failure of wrapped getJSON --- addon/adapter.js | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/addon/adapter.js b/addon/adapter.js index 93407617004..8d199aba585 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -102,10 +102,9 @@ export default Ember.Object.extend({ return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.getJSON(`/${type.modelName}/${id}`).then(function(data) { - Ember.run(null, resolve, data); + resolve(data); }, function(jqXHR) { - jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); + reject(jqXHR); }); }); } @@ -134,10 +133,9 @@ export default Ember.Object.extend({ var query = { since: sinceToken }; return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { - Ember.run(null, resolve, data); + resolve(data); }, function(jqXHR) { - jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); + reject(jqXHR); }); }); } @@ -165,10 +163,9 @@ export default Ember.Object.extend({ query: function(store, type, query) { return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { - Ember.run(null, resolve, data); + resolve(data); }, function(jqXHR) { - jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); + reject(jqXHR); }); }); } @@ -204,10 +201,9 @@ export default Ember.Object.extend({ queryRecord: function(store, type, query) { return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { - Ember.run(null, resolve, data); + resolve(data); }, function(jqXHR) { - jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); + reject(jqXHR); }); }); } From bd50280e44913320b76d2f821706409c218f879f Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 1 Aug 2016 16:57:05 -0400 Subject: [PATCH 1563/2527] [BUGFIX beta] Fix Brittle Promise Usage --- addon/adapters/rest.js | 146 +++++++++--------- .../integration/adapter/rest-adapter-test.js | 55 +++++++ 2 files changed, 129 insertions(+), 72 deletions(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index f0ca0c60a83..e5affdabe6a 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -25,6 +25,8 @@ const { get } = Ember; +const Promise = Ember.RSVP.Promise; + /** The REST adapter allows your store to communicate with an HTTP server by transmitting JSON via XHR. Most Ember.js apps that consume a JSON API @@ -1001,52 +1003,29 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { method: type }; - return new Ember.RSVP.Promise(function(resolve, reject) { + return new Promise(function(resolve, reject) { var hash = adapter.ajaxOptions(url, type, options); hash.success = function(payload, textStatus, jqXHR) { - - let response = adapter.handleResponse( - jqXHR.status, - parseResponseHeaders(jqXHR.getAllResponseHeaders()), - payload, - requestData - ); - - if (response && response.isAdapterError) { - Ember.run.join(null, reject, response); - } else { + try { + var response = ajaxSuccess(adapter, jqXHR, payload, requestData); Ember.run.join(null, resolve, response); + } catch (error) { + Ember.run.join(null, reject, error); } }; hash.error = function(jqXHR, textStatus, errorThrown) { - runInDebug(function() { - let message = `The server returned an empty string for ${type} ${url}, which cannot be parsed into a valid JSON. Return either null or {}.`; - let validJSONString = !(textStatus === "parsererror" && jqXHR.responseText === ""); - warn(message, validJSONString, { - id: 'ds.adapter.returned-empty-string-as-JSON' - }); - }); - - let error; - - if (errorThrown instanceof Error) { - error = errorThrown; - } else if (textStatus === 'timeout') { - error = new TimeoutError(); - } else if (textStatus === 'abort') { - error = new AbortError(); - } else { - error = adapter.handleResponse( - jqXHR.status, - parseResponseHeaders(jqXHR.getAllResponseHeaders()), - adapter.parseErrorResponse(jqXHR.responseText) || errorThrown, - requestData - ); + try { + var responseData = { + textStatus, + errorThrown + }; + var error = ajaxError(adapter, jqXHR, requestData, responseData); + Ember.run.join(null, reject, error); + } catch (error) { + Ember.run.join(null, reject, error); } - - Ember.run.join(null, reject, error); }; adapter._ajaxRequest(hash); @@ -1403,47 +1382,26 @@ if (isEnabled('ds-improved-ajax')) { return new Ember.RSVP.Promise((resolve, reject) => { hash.success = function(payload, textStatus, jqXHR) { - let response = adapter.handleResponse( - jqXHR.status, - parseResponseHeaders(jqXHR.getAllResponseHeaders()), - payload, - requestData - ); - - if (response instanceof AdapterError) { - Ember.run.join(null, reject, response); - } else { + try { + var response = ajaxSuccess(adapter, jqXHR, payload, requestData); Ember.run.join(null, resolve, response); + } catch (error) { + Ember.run.join(null, reject, error); } + }; hash.error = function(jqXHR, textStatus, errorThrown) { - runInDebug(function() { - let message = `The server returned an empty string for ${method} ${url}, which cannot be parsed into a valid JSON. Return either null or {}.`; - let validJSONString = !(textStatus === "parsererror" && jqXHR.responseText === ""); - warn(message, validJSONString, { - id: 'ds.adapter.returned-empty-string-as-JSON' - }); - }); - - let error; - - if (errorThrown instanceof Error) { - error = errorThrown; - } else if (textStatus === 'timeout') { - error = new TimeoutError(); - } else if (textStatus === 'abort') { - error = new AbortError(); - } else { - error = adapter.handleResponse( - jqXHR.status, - parseResponseHeaders(jqXHR.getAllResponseHeaders()), - adapter.parseErrorResponse(jqXHR.responseText) || errorThrown, - requestData - ); + try { + var responseData = { + textStatus, + errorThrown + }; + var error = ajaxError(adapter, jqXHR, requestData, responseData); + Ember.run.join(null, reject, error); + } catch (error) { + Ember.run.join(null, reject, error); } - - Ember.run.join(null, reject, error); }; adapter._ajaxRequest(hash); @@ -1454,6 +1412,50 @@ if (isEnabled('ds-improved-ajax')) { } +function ajaxSuccess(adapter, jqXHR, payload, requestData) { + let response = adapter.handleResponse( + jqXHR.status, + parseResponseHeaders(jqXHR.getAllResponseHeaders()), + payload, + requestData + ); + + if (response && response.isAdapterError) { + return Promise.reject(response); + } else { + return response; + } +} + +function ajaxError(adapter, jqXHR, requestData, responseData) { + runInDebug(function() { + let message = `The server returned an empty string for ${requestData.method} ${requestData.url}, which cannot be parsed into a valid JSON. Return either null or {}.`; + let validJSONString = !(responseData.textStatus === "parsererror" && jqXHR.responseText === ""); + warn(message, validJSONString, { + id: 'ds.adapter.returned-empty-string-as-JSON' + }); + }); + + let error; + + if (responseData.errorThrown instanceof Error) { + error = responseData.errorThrown; + } else if (responseData.textStatus === 'timeout') { + error = new TimeoutError(); + } else if (responseData.textStatus === 'abort') { + error = new AbortError(); + } else { + error = adapter.handleResponse( + jqXHR.status, + parseResponseHeaders(jqXHR.getAllResponseHeaders()), + adapter.parseErrorResponse(jqXHR.responseText) || responseData.errorThrown, + requestData + ); + } + + return error; +} + //From http://stackoverflow.com/questions/280634/endswith-in-javascript function endsWith(string, suffix) { if (typeof String.prototype.endsWith !== 'function') { diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 0343dd98662..47ebc3d3cff 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -2326,6 +2326,61 @@ test("rejects promise if DS.AdapterError is returned from adapter.handleResponse Ember.$.ajax = originalAjax; }); +test("gracefully handles exceptions in handleResponse", function(assert) { + assert.expect(1); + var originalAjax = Ember.$.ajax; + var jqXHR = { + status: 200, + getAllResponseHeaders() { return ''; } + }; + + Ember.$.ajax = function(hash) { + setTimeout(function() { hash.success({}, 'ok', jqXHR); }, 1) + }; + + adapter.handleResponse = function(status, headers, json) { + throw new Error('Unexpected error'); + }; + + try { + return run(function() { + return store.findRecord('post', '1').catch(function(error) { + assert.ok(true, 'Unexpected error is captured by the promise chain'); + }); + + }); + } finally { + Ember.$.ajax = originalAjax; + } +}); + +test("gracefully handles exceptions in handleResponse where the ajax request errors", function(assert) { + assert.expect(1); + var originalAjax = Ember.$.ajax; + var jqXHR = { + status: 500, + getAllResponseHeaders() { return ''; } + }; + + Ember.$.ajax = function(hash) { + setTimeout(function() { hash.error({}, 'Internal Server Error', jqXHR); }, 1) + }; + + adapter.handleResponse = function(status, headers, json) { + throw new Error('Unexpected error'); + }; + + try { + return run(function() { + return store.findRecord('post', '1').catch(function(error) { + assert.ok(true, 'Unexpected error is captured by the promise chain'); + }); + }); + } finally { + Ember.$.ajax = originalAjax; + } +}); + test('on error appends errorThrown for sanity', function(assert) { assert.expect(2); From f7064aae7fb66b14c4b9611fae273bfec0d3750a Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Thu, 4 Aug 2016 11:43:49 +0100 Subject: [PATCH 1564/2527] Addresses #4492 --- .npmignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.npmignore b/.npmignore index 3f8caf945a5..ada672d4b66 100644 --- a/.npmignore +++ b/.npmignore @@ -5,6 +5,8 @@ /tests /tmp /benchmarks +/bin +/docs **/.gitkeep .appveyor.yml From db49f961653246318f67f86d0427c929810fae44 Mon Sep 17 00:00:00 2001 From: frunjik Date: Thu, 11 Aug 2016 17:05:07 +0200 Subject: [PATCH 1565/2527] Remove deprecation on using normalizeHash when running tests (#4443) * remove deprecation normalizeHash when running tests * wrapped normalizeHash tests with assertDeprecation to prevent deprecation warnings * testInDebug deprecated normalizeHash tests --- .../integration/serializers/rest-serializer-test.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 54f8c78f4a1..991e2756299 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -355,7 +355,7 @@ test("normalizeResponse loads secondary records with correct serializer", functi assert.equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); }); -test('normalizeHash normalizes specific parts of the payload', function(assert) { +testInDebug('normalizeHash normalizes specific parts of the payload (DEPRECATED)', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ normalizeHash: { homePlanets(hash) { @@ -372,7 +372,9 @@ test('normalizeHash normalizes specific parts of the payload', function(assert) var array; run(function() { - array = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); + assert.expectDeprecation(function() { + array = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); + }, /`RESTSerializer.normalizeHash` has been deprecated/); }); assert.deepEqual(array, { @@ -397,6 +399,7 @@ test('normalizeHash normalizes specific parts of the payload', function(assert) testInDebug('normalizeHash has been deprecated', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ + normalizeHash: { homePlanets(hash) { hash.id = hash._id; @@ -418,7 +421,7 @@ testInDebug('normalizeHash has been deprecated', function(assert) { }); -test('normalizeHash works with transforms', function(assert) { +testInDebug('normalizeHash works with transforms (DEPRECATED)', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ normalizeHash: { evilMinions(hash) { @@ -454,7 +457,9 @@ test('normalizeHash works with transforms', function(assert) { var array; run(function() { - array = env.restSerializer.normalizeResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); + assert.expectDeprecation(function() { + array = env.restSerializer.normalizeResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); + }, /`RESTSerializer.normalizeHash` has been deprecated/); }); assert.equal(array.data[0].attributes.condition, "healing"); From 9451e7ac3ec4298f114ef1b6f3e974d779015757 Mon Sep 17 00:00:00 2001 From: Matt d'Entremont Date: Mon, 15 Aug 2016 14:48:44 -0400 Subject: [PATCH 1566/2527] [BUGFIX beta] Fix key remapping for id/ids belongsTo with embedded-records-mixin This implements the same semantics for `key` that are used in JSONSerializer, for both belongsTo and hasMany records when serialized as id/ids. --- addon/serializers/embedded-records-mixin.js | 17 ++++-- .../embedded-records-mixin-test.js | 60 +++++++++++++++++++ 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index f0da1a1f82e..b7dd3359b1e 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -198,13 +198,16 @@ export default Ember.Mixin.create({ var includeIds = this.hasSerializeIdsOption(attr); var includeRecords = this.hasSerializeRecordsOption(attr); var embeddedSnapshot = snapshot.belongsTo(attr); - var key; if (includeIds) { - key = this.keyForRelationship(attr, relationship.kind, 'serialize'); + var serializedKey = this._getMappedKey(relationship.key, snapshot.type); + if (serializedKey === relationship.key && this.keyForRelationship) { + serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); + } + if (!embeddedSnapshot) { - json[key] = null; + json[serializedKey] = null; } else { - json[key] = embeddedSnapshot.id; + json[serializedKey] = embeddedSnapshot.id; if (relationship.options.polymorphic) { this.serializePolymorphicType(snapshot, json, relationship); @@ -377,7 +380,11 @@ export default Ember.Mixin.create({ } if (this.hasSerializeIdsOption(attr)) { - let serializedKey = this.keyForRelationship(attr, relationship.kind, 'serialize'); + let serializedKey = this._getMappedKey(relationship.key, snapshot.type); + if (serializedKey === relationship.key && this.keyForRelationship) { + serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); + } + json[serializedKey] = snapshot.hasMany(attr, { ids: true }); } else if (this.hasSerializeRecordsOption(attr)) { this._serializeEmbeddedHasMany(snapshot, json, relationship); diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index 4b151636adb..78ca55ae5ca 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -2256,3 +2256,63 @@ test("serializing embedded hasMany respects remapped attrs key", function(assert }] }); }); + +test("serializing id belongsTo respects remapped attrs key", function(assert) { + run(function() { + homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); + superVillain = env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); + }); + + env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + homePlanet: { serialize: 'id', key: 'favorite_place' } + } + })); + + var serializer = env.store.serializerFor("super-villain"); + var json; + + run(function() { + json = serializer.serialize(superVillain._createSnapshot()); + }); + + assert.deepEqual(json, { + firstName: "Ice", + lastName: "Creature", + favorite_place: homePlanet.id, + secretLab: null + }); +}); + +test("serializing ids hasMany respects remapped attrs key", function(assert) { + run(function() { + homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); + superVillain = env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); + }); + + env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { serialize: 'ids', key: 'notable_persons' } + } + })); + + env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + homePlanet: { serialize: false }, + secretLab: { serialize: false } + } + })); + + + var serializer = env.store.serializerFor("home-planet"); + var json; + + run(function() { + json = serializer.serialize(homePlanet._createSnapshot()); + }); + + assert.deepEqual(json, { + name: "Hoth", + notable_persons: [superVillain.id] + }); +}); From 113ee68f27c808e1abb9c958e216d0d30c5cd95f Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 15 Aug 2016 21:32:23 +0200 Subject: [PATCH 1567/2527] [BUGFIX beta] add assertions for reference methods on DS.Model Assertions are thrown when the specified relationship doesn't exist or the passed type mismatches the one of the actual relationship. --- addon/-private/system/model/internal-model.js | 10 +++++- .../integration/references/belongs-to-test.js | 36 +++++++++++++++++++ tests/integration/references/has-many-test.js | 36 +++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 88928d51158..fa7c77c8516 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert } from "ember-data/-private/debug"; +import { assert, runInDebug } from "ember-data/-private/debug"; import RootState from "ember-data/-private/system/model/states"; import Relationships from "ember-data/-private/system/relationships/state/create"; import Snapshot from "ember-data/-private/system/snapshot"; @@ -840,6 +840,14 @@ InternalModel.prototype = { if (!reference) { var relationship = this._relationships.get(name); + runInDebug(() => { + let modelName = this.modelName; + assert(`There is no ${type} relationship named '${name}' on a model of type '${modelName}'`, relationship); + + let actualRelationshipKind = relationship.relationshipMeta.kind; + assert(`You tried to get the '${name}' relationship on a '${modelName}' via record.${type}('${name}'), but the relationship is of type '${actualRelationshipKind}'. Use record.${actualRelationshipKind}('${name}') instead.`, actualRelationshipKind === type); + }); + if (type === "belongsTo") { reference = new BelongsToReference(this.store, this, relationship); } else if (type === "hasMany") { diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index fe96eedac1c..2232e88e0ca 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -30,6 +30,42 @@ module("integration/references/belongs-to", { } }); +testInDebug("record#belongsTo asserts when specified relationship doesn't exist", function(assert) { + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1 + } + }); + }); + + assert.expectAssertion(function() { + run(function() { + person.belongsTo("unknown-relationship"); + }); + }, "There is no belongsTo relationship named 'unknown-relationship' on a model of type 'person'"); +}); + +testInDebug("record#belongsTo asserts when the type of the specified relationship isn't the requested one", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1 + } + }); + }); + + assert.expectAssertion(function() { + run(function() { + family.belongsTo("persons"); + }); + }, "You tried to get the 'persons' relationship on a 'family' via record.belongsTo('persons'), but the relationship is of type 'hasMany'. Use record.hasMany('persons') instead."); +}); + test("record#belongsTo", function(assert) { var person; run(function() { diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 7bee6b35109..32fee3c8af6 100644 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -29,6 +29,42 @@ module("integration/references/has-many", { } }); +testInDebug("record#hasMany asserts when specified relationship doesn't exist", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1 + } + }); + }); + + assert.expectAssertion(function() { + run(function() { + family.hasMany("unknown-relationship"); + }); + }, "There is no hasMany relationship named 'unknown-relationship' on a model of type 'family'"); +}); + +testInDebug("record#hasMany asserts when the type of the specified relationship isn't the requested one", function(assert) { + var person; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1 + } + }); + }); + + assert.expectAssertion(function() { + run(function() { + person.hasMany("family"); + }); + }, "You tried to get the 'family' relationship on a 'person' via record.hasMany('family'), but the relationship is of type 'belongsTo'. Use record.belongsTo('family') instead."); +}); + test("record#hasMany", function(assert) { var family; run(function() { From 1daba1286de87dda10ca14e9c6b656ef734e388e Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 18 Aug 2016 22:38:35 -0400 Subject: [PATCH 1568/2527] Update ember-try config to test against alpha. --- config/ember-try.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/config/ember-try.js b/config/ember-try.js index f1d73b10491..982d2b5417f 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -50,6 +50,17 @@ module.exports = { 'ember': 'canary' } } + }, + { + name: 'ember-alpha', + bower: { + dependencies: { + 'ember': 'alpha' + }, + resolutions: { + 'ember': 'alpha' + } + } } ] }; From b87a82d77828475e407ee76d4136d44e48ccbc0d Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Thu, 25 Aug 2016 14:46:58 +0100 Subject: [PATCH 1569/2527] Update DateTransform documentation to specifically mention ISO 8601 (#4506) --- addon/-private/transforms/date.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/-private/transforms/date.js b/addon/-private/transforms/date.js index 1907e9effb6..e49bcc05b7b 100644 --- a/addon/-private/transforms/date.js +++ b/addon/-private/transforms/date.js @@ -4,7 +4,8 @@ import { parseDate } from "ember-data/-private/ext/date"; The `DS.DateTransform` class is used to serialize and deserialize date attributes on Ember Data record objects. This transform is used when `date` is passed as the type parameter to the - [DS.attr](../../data#method_attr) function. + [DS.attr](../../data#method_attr) function. It uses the [`ISO 8601`](https://en.wikipedia.org/wiki/ISO_8601) + standard. ```app/models/score.js import DS from 'ember-data'; From 79c81a589c753d3b0068599fc3b73b454a1ccf91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Clemens=20M=C3=BCller?= Date: Thu, 25 Aug 2016 15:58:02 +0200 Subject: [PATCH 1570/2527] [DOC] clarify docs on Model#modelName and Store#modelFor (#4498) --- addon/-private/system/model/model.js | 1 + addon/-private/system/store.js | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 2c3b0a65852..e13536d9fc5 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1003,6 +1003,7 @@ Model.reopenClass({ @property modelName @type String @readonly + @static */ modelName: null }); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index e376ab8669f..df54a59d21f 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1839,9 +1839,12 @@ Store = Service.extend({ }, /** - Returns a model class for a particular key. Used by - methods that take a type key (like `find`, `createRecord`, - etc.) + Returns the model class for the particular `modelName`. + + The class of a model might be useful if you want to get a list of all the + relationship names of the model, see + [`relationshipNames`](http://emberjs.com/api/data/classes/DS.Model.html#property_relationshipNames) + for example. @method modelFor @param {String} modelName From 5d9b2105d5c41cb827745d40587a9fcd679204e3 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Fri, 26 Aug 2016 14:24:58 -0400 Subject: [PATCH 1571/2527] Remove ContainerInstanceCache from the API docs since it is not exposed to consumers (#4517) --- addon/-private/system/store/container-instance-cache.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/store/container-instance-cache.js b/addon/-private/system/store/container-instance-cache.js index 07d00e17e7e..5cf5e41bdcf 100644 --- a/addon/-private/system/store/container-instance-cache.js +++ b/addon/-private/system/store/container-instance-cache.js @@ -2,7 +2,7 @@ import Ember from 'ember'; import EmptyObject from "ember-data/-private/system/empty-object"; const assign = Ember.assign || Ember.merge; -/** +/* * The `ContainerInstanceCache` serves as a lazy cache for looking up * instances of serializers and adapters. It has some additional logic for * finding the 'fallback' adapter or serializer. From ed794d92b485e2d32a947298970544ec19e08704 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 26 Aug 2016 13:04:18 -0400 Subject: [PATCH 1572/2527] Document the allowNull property on the boolean transform --- addon/-private/transforms/boolean.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/addon/-private/transforms/boolean.js b/addon/-private/transforms/boolean.js index e9724eaf1ed..fd4e6d0a9ac 100644 --- a/addon/-private/transforms/boolean.js +++ b/addon/-private/transforms/boolean.js @@ -22,6 +22,20 @@ const { isNone } = Ember; }); ``` + By default the boolean transform only allows for values of `true` or + `false`. You can opt into allowing `null` values for + boolean attributes via `DS.attr('boolean', { allowNull: true })` + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + email: DS.attr('string'), + username: DS.attr('string'), + wantsWeeklyEmail: DS.attr('boolean', { allowNull: true }) + }); + ``` + @class BooleanTransform @extends DS.Transform @namespace DS From c45ea65471d2304c8adef43a276e8d5db6a72466 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 26 Aug 2016 13:43:41 -0400 Subject: [PATCH 1573/2527] Update the docs for normalizeModelName so they explain the intent of the function --- addon/-private/system/normalize-model-name.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/normalize-model-name.js b/addon/-private/system/normalize-model-name.js index 4921ca79782..f885e5ddd61 100644 --- a/addon/-private/system/normalize-model-name.js +++ b/addon/-private/system/normalize-model-name.js @@ -1,12 +1,16 @@ import Ember from 'ember'; +// All modelNames are dasherized internally. Changing this function may +// require changes to other normalization hooks (such as typeForRoot). + /** - All modelNames are dasherized internally. Changing this function may - require changes to other normalization hooks (such as typeForRoot). + This method normalizes a modelName into the format Ember Data uses + internally. + @method normalizeModelName @public @param {String} modelName - @return {String} if the adapter can generate one, an ID + @return {String} normalizedModelName @for DS */ export default function normalizeModelName(modelName) { From db4cded04a34f9290aac2e4013bb3c353c7dccd6 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 26 Aug 2016 16:08:44 -0400 Subject: [PATCH 1574/2527] [BUGFIX beta] Prefer includes over contains This pr adds the [ember-runtime-enumerable-includes-polyfill](https://github.com/rwjblue/ember-runtime-enumerable-includes-polyfill) to add includes if the user's version of Ember doesn't support it. --- addon/-private/system/record-arrays/record-array.js | 2 +- addon/-private/system/relationships/ext.js | 2 +- addon/-private/system/store.js | 2 +- package.json | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index b3f020d44b6..35171878f74 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -146,7 +146,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { var content = get(this, 'content'); if (idx === undefined) { content.addObject(internalModel); - } else if (!content.contains(internalModel)) { + } else if (!content.includes(internalModel)) { content.insertAt(idx, internalModel); } }, diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 248b5ad4bb8..2b0e2a1e167 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -55,7 +55,7 @@ var relatedTypesDescriptor = Ember.computed(function() { assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", modelName); - if (!types.contains(modelName)) { + if (!types.includes(modelName)) { assert("Trying to sideload " + name + " on " + this.toString() + " but the type doesn't exist.", !!modelName); types.push(modelName); } diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index df54a59d21f..be8b7ea3e24 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -758,7 +758,7 @@ Store = Service.extend({ function makeMissingRecordsRejector(requestedRecords) { return function rejectMissingRecords(resolvedRecords) { resolvedRecords = Ember.A(resolvedRecords); - var missingRecords = requestedRecords.reject((record) => resolvedRecords.contains(record)); + var missingRecords = requestedRecords.reject((record) => resolvedRecords.includes(record)); if (missingRecords.length) { warn('Ember Data expected to find records with the following ids in the adapter response but they were missing: ' + Ember.inspect(Ember.A(missingRecords).mapBy('id')), false, { id: 'ds.store.missing-records-from-adapter' diff --git a/package.json b/package.json index b044a605b1f..7d308c45977 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "ember-cli-test-info": "^1.0.0", "ember-cli-version-checker": "^1.1.4", "ember-inflector": "^1.9.4", + "ember-runtime-enumerable-includes-polyfill": "^1.0.0", "exists-sync": "0.0.3", "git-repo-info": "^1.1.2", "inflection": "^1.8.0", From 22e0d21aa51ce8d711f8bb3cf00286ed8e7f4efd Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 28 Mar 2016 18:07:02 -0400 Subject: [PATCH 1575/2527] Add better error messaging for adapters that do not implement createRecord, updateRecord or deleteRecord. --- addon/-private/system/store.js | 4 +++- .../integration/adapter/store-adapter-test.js | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index df54a59d21f..04ec7b06fe6 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -680,7 +680,7 @@ Store = Service.extend({ var adapter = this.adapterFor(typeClass.modelName); assert("You tried to find a record but you have no adapter (for " + typeClass + ")", adapter); - assert("You tried to find a record but your adapter (for " + typeClass + ") does not implement 'findRecord'", typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); + assert("You tried to find a record but your adapter (for " + typeClass + ") does not implement 'findRecord'", typeof adapter.findRecord === 'function'); var promise = _find(adapter, this, typeClass, id, internalModel, options); return promise; @@ -2425,6 +2425,8 @@ function _commit(adapter, store, operation, snapshot) { var internalModel = snapshot._internalModel; var modelName = snapshot.modelName; var typeClass = store.modelFor(modelName); + assert(`You tried to update a record but you have no adapter (for ${typeClass})`, adapter); + assert(`You tried to update a record but your adapter (for ${typeClass}) does not implement '${operation}'`, typeof adapter[operation] === 'function'); var promise = adapter[operation](store, typeClass, snapshot); var serializer = serializerForAdapter(store, adapter, modelName); var label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 0094d5a7bdd..8048750aad0 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -2,6 +2,7 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import DS from 'ember-data'; @@ -108,6 +109,7 @@ test("by default, createRecords calls createRecord once per record", function(as yehuda: yehuda.save() }); }); + promise.then(assert.wait(function(records) { tom = records.tom; yehuda = records.yehuda; @@ -116,6 +118,7 @@ test("by default, createRecords calls createRecord once per record", function(as assert.asyncEqual(yehuda, store.findRecord('person', 2), "Once an ID is in, findRecord returns the same object"); assert.equal(get(tom, 'updatedAt'), "now", "The new information is received"); assert.equal(get(yehuda, 'updatedAt'), "now", "The new information is received"); + })); }); @@ -1400,3 +1403,21 @@ test("An async hasMany relationship with links should not trigger shouldBackgrou assert.equal(comments.get('length'), 3); })); }); + + +testInDebug("There should be a friendly error for if the adapter does not implement createRecord", function(assert) { + adapter.createRecord = null; + + let tom; + assert.expectAssertion(function() { + run(function() { + tom = store.createRecord('person', { name: "Tom Dale" }); + tom.save(); + }); + }, /does not implement 'createRecord'/); + run(function() { + // move record out of the inflight state so the tests can clean up + // correctly + store.recordWasError(tom._internalModel, new Error()); + }); +}); From 99cfcf7ba17288e3d8313e052216ed02b1d80c88 Mon Sep 17 00:00:00 2001 From: bmac Date: Sat, 27 Aug 2016 23:27:21 -0400 Subject: [PATCH 1576/2527] Remove ContainerProxy --- addon/-private/system/container-proxy.js | 52 ------------------------ addon/index.js | 3 -- 2 files changed, 55 deletions(-) delete mode 100644 addon/-private/system/container-proxy.js diff --git a/addon/-private/system/container-proxy.js b/addon/-private/system/container-proxy.js deleted file mode 100644 index eb2b1dc2c5f..00000000000 --- a/addon/-private/system/container-proxy.js +++ /dev/null @@ -1,52 +0,0 @@ -import { deprecate } from "ember-data/-private/debug"; - -/* - This is used internally to enable deprecation of container paths and provide - a decent message to the user indicating how to fix the issue. - - @class ContainerProxy - @namespace DS - @private -*/ -export default function ContainerProxy(container) { - this.container = container; -} - -ContainerProxy.prototype.aliasedFactory = function(path, preLookup) { - return { - create: () => { - if (preLookup) { preLookup(); } - - return this.container.lookup(path); - } - }; -}; - -ContainerProxy.prototype.registerAlias = function(source, dest, preLookup) { - var factory = this.aliasedFactory(dest, preLookup); - - return this.container.register(source, factory); -}; - -ContainerProxy.prototype.registerDeprecation = function(deprecated, valid) { - var preLookupCallback = function() { - deprecate(`You tried to look up '${deprecated}', but this has been deprecated in favor of '${valid}'.`, false, { - id: 'ds.store.deprecated-lookup', - until: '2.0.0' - }); - }; - - return this.registerAlias(deprecated, valid, preLookupCallback); -}; - -ContainerProxy.prototype.registerDeprecations = function(proxyPairs) { - var i, proxyPair, deprecated, valid; - - for (i = proxyPairs.length; i > 0; i--) { - proxyPair = proxyPairs[i - 1]; - deprecated = proxyPair['deprecated']; - valid = proxyPair['valid']; - - this.registerDeprecation(deprecated, valid); - } -}; diff --git a/addon/index.js b/addon/index.js index 58aaa3449aa..a07ed371bee 100644 --- a/addon/index.js +++ b/addon/index.js @@ -86,7 +86,6 @@ import {hasMany, belongsTo} from "ember-data/relationships"; import setupContainer from "ember-data/setup-container"; import initializeStoreService from 'ember-data/-private/instance-initializers/initialize-store-service'; -import ContainerProxy from "ember-data/-private/system/container-proxy"; import Relationship from "ember-data/-private/system/relationships/state/relationship"; DS.Store = Store; @@ -154,8 +153,6 @@ DS.hasMany = hasMany; DS.Relationship = Relationship; -DS.ContainerProxy = ContainerProxy; - DS._setupContainer = setupContainer; DS._initializeStoreService = initializeStoreService; From 318e9fef9eef47df2f830c08a3ef39ed0d8523f9 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Sun, 28 Aug 2016 16:59:45 -0400 Subject: [PATCH 1577/2527] Document the options argument in the DS.Transform class (#4514) --- addon/transform.js | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/addon/transform.js b/addon/transform.js index 232c79e5f72..4e7457229a4 100644 --- a/addon/transform.js +++ b/addon/transform.js @@ -14,15 +14,44 @@ import Ember from 'ember'; // Converts centigrade in the JSON to fahrenheit in the app export default DS.Transform.extend({ - deserialize: function(serialized) { + deserialize: function(serialized, options) { return (serialized * 1.8) + 32; }, - serialize: function(deserialized) { + serialize: function(deserialized, options) { return (deserialized - 32) / 1.8; } }); ``` + The options passed into the `DS.attr` function when the attribute is + declared on the model is also available in the transform. + + ```app/models/post.js + export default DS.Model.extend({ + title: DS.attr('string'), + markdown: DS.attr('markdown', { + markdown: { + gfm: false, + sanitize: true + } + }) + }); + ``` + + ```app/transforms/markdown.js + export default DS.Transform.extend({ + serialize: function (deserialized, options) { + return deserialized.raw; + }, + + deserialize: function (serialized, options) { + var markdownOptions = options.markdown || {}; + + return marked(serialized, markdownOptions); + } + }); + ``` + Usage ```app/models/requirement.js From 59fa1b7355b097c72eb938f0f399ba3f29f40431 Mon Sep 17 00:00:00 2001 From: Ed Date: Tue, 30 Aug 2016 10:34:12 +1200 Subject: [PATCH 1578/2527] add license to bower.json --- bower.json | 1 + 1 file changed, 1 insertion(+) diff --git a/bower.json b/bower.json index e454d4ea623..858d21de7a1 100644 --- a/bower.json +++ b/bower.json @@ -1,5 +1,6 @@ { "name": "ember-data", + "license": "MIT", "dependencies": { "ember": "components/ember#release", "ember-cli-shims": "0.1.1", From b258df44be2464b51b815868b69e21a8eaa54c72 Mon Sep 17 00:00:00 2001 From: Ben Limmer Date: Wed, 31 Aug 2016 09:28:38 -0600 Subject: [PATCH 1579/2527] =?UTF-8?q?[DOC]=C2=A0Update=20docs=20for=20shou?= =?UTF-8?q?ldReload*=20methods=20(#4524)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was very unclear to me why the server was being hit when returning `false` from `shouldReloadRecord` upon digging through the tests, I finally realized that background reload was what was actually hitting the server. --- addon/adapter.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/addon/adapter.js b/addon/adapter.js index 8d199aba585..5772e6170be 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -492,7 +492,7 @@ export default Ember.Object.extend({ ```javascript shouldReloadRecord: function(store, ticketSnapshot) { - var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt')).minutes(); + var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt'), 'minutes'); if (timeDiff > 20) { return true; } else { @@ -509,6 +509,11 @@ export default Ember.Object.extend({ By default this hook returns `false`, as most UIs should not block user interactions while waiting on data update. + Note that, with default settings, `shouldBackgroundReloadRecord` will always + re-fetch the records in the background even if `shouldReloadRecord` returns + `false`. You can override `shouldBackgroundReloadRecord` if this does not + suit your use case. + @since 1.13.0 @method shouldReloadRecord @param {DS.Store} store @@ -538,7 +543,7 @@ export default Ember.Object.extend({ var snapshots = snapshotArray.snapshots(); return snapshots.any(function(ticketSnapshot) { - var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt')).minutes(); + var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt'), 'minutes'); if (timeDiff > 20) { return true; } else { @@ -557,6 +562,11 @@ export default Ember.Object.extend({ is empty (meaning that there are no records locally available yet), otherwise it returns `false`. + Note that, with default settings, `shouldBackgroundReloadAll` will always + re-fetch all the records in the background even if `shouldReloadAll` returns + `false`. You can override `shouldBackgroundReloadAll` if this does not suit + your use case. + @since 1.13.0 @method shouldReloadAll @param {DS.Store} store From b04a6fec2a1655b8b5b1250effee0f83faaba525 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 8 Sep 2016 16:45:16 -0500 Subject: [PATCH 1580/2527] post release version bump & Changelog updates --- CHANGELOG.md | 31 +++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 830a29dd0b5..c4012aa5675 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,37 @@ ### Master +### Release 2.8.0 (September 8, 2016) + +- [#4464](https://github.com/emberjs/data/pull/4464) Add benchmarks directory to npmignore +- [#4425](https://github.com/emberjs/data/pull/4425) [BUGFIX] Pass options to transform for serialization in json-api +- [#4408](https://github.com/emberjs/data/pull/4408) Log an assertion if the response from createRecord does not have an id and the id was not already provided by the client +- [#4246](https://github.com/emberjs/data/pull/4246) [FEATURE ds-rollback-attribute] Add rolling back of a single model attribute +- [#4418](https://github.com/emberjs/data/pull/4418) remove DEPRECATION: Using the global version of DS is deprecated when running tests +- [#4481](https://github.com/emberjs/data/pull/4481) [BUGFIX release] Revert blueprints to use the old import DS format +- [#4433](https://github.com/emberjs/data/pull/4433) Remove JSHint directives from Mocha test blueprints +- [#4435](https://github.com/emberjs/data/pull/4435) [DOC] typo fix for queryRecord (kown -> known) +- [#4431](https://github.com/emberjs/data/pull/4431) Update changelog for 2.6.1 release +- [#4454](https://github.com/emberjs/data/pull/4454) Add since tags for methods added in Ember Data 1.13 +- [#4447](https://github.com/emberjs/data/pull/4447) Remove initializer methods from the API docs +- [#4446](https://github.com/emberjs/data/pull/4446) `modelHasAttributeOrRelationshipNamedType` should not show up in the API docs +- [#4444](https://github.com/emberjs/data/pull/4444) Update the API docs for the DS.Adapter class +- [#4448](https://github.com/emberjs/data/pull/4448) [BUGFIX beta] The adapter should call `ajax` instead of the new methods if it has been customized. +- [#4490](https://github.com/emberjs/data/pull/4490) [DOCS] No need to use Ember.run in success and failure of wrapped getJSON +- [#4449](https://github.com/emberjs/data/pull/4449) Add link to PR for ds-check-should-serialize-relationships feature +- [#4489](https://github.com/emberjs/data/pull/4489) [BUGFIX beta] Fix Brittle Promise Usage +- [#4470](https://github.com/emberjs/data/pull/4470) Belongs to not updating when response contains a change with the previous value +- [#4451](https://github.com/emberjs/data/pull/4451) [CLEANUP beta] Remove feature flag for ds-serialize-ids-and-types (shipped in 2.6) #4416 +- [#4466](https://github.com/emberjs/data/pull/4466) [BUGFIX beta] Fixes issue with GET requests appending ?{} to url +- [#4484](https://github.com/emberjs/data/pull/4484) [BUGFIX beta] Update API docs to import DS from 'ember-data' +- [#4485](https://github.com/emberjs/data/pull/4485) Update changelog for the Ember Data 2.7.0 release +- [#4499](https://github.com/emberjs/data/pull/4499) [BUGFIX beta] add assertions for reference methods on DS.Model +- [#4503](https://github.com/emberjs/data/pull/4503) Update ember-try config to test against alpha. +- [#4515](https://github.com/emberjs/data/pull/4515) Document the allowNull property on the boolean transform +- [#4516](https://github.com/emberjs/data/pull/4516) Update the docs for normalizeModelName so they explain the intent of the function +- [#4519](https://github.com/emberjs/data/pull/4519) [BUGFIX beta] Prefer includes over contains +- [#4521](https://github.com/emberjs/data/pull/4521) Remove ContainerProxy + ### Release 2.7.0 (July 25, 2016) - [#4482](https://github.com/emberjs/data/pull/4482) Disable ds-improved-ajax for the 2.7 release - [#4470](https://github.com/emberjs/data/pull/4470) Belongs to not updating when response contains a change with the previous value diff --git a/package.json b/package.json index 7d308c45977..971263bdfe0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.8.0-canary", + "version": "2.9.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From d2fb980918c6222a8bf48a01315e0172906d19a7 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 8 Sep 2016 19:05:01 -0500 Subject: [PATCH 1581/2527] try busting the cache by keeping phantomjs info in npm (#4528) * try busting the cache by keeping phantomjs info in npm * bump ember-try * bump node version on travis --- .travis.yml | 3 +-- package.json | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9b5a6506b5b..2203a1b3eb4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,11 +2,10 @@ language: node_js sudo: false node_js: - - "4.2" + - "4" before_install: - "npm config set spin false" - "npm install -g npm@^2" - - npm install -g phantomjs-prebuilt@2 install: - npm install --no-optional diff --git a/package.json b/package.json index 971263bdfe0..89e022a842e 100644 --- a/package.json +++ b/package.json @@ -75,13 +75,14 @@ "ember-load-initializers": "^0.5.0", "ember-publisher": "0.0.7", "ember-resolver": "^2.0.3", - "ember-try": "^0.1.2", + "ember-try": "^0.2.5", "ember-watson": "^0.7.0", "github": "^0.2.4", "glob": "5.0.13", "loader.js": "^4.0.0", "mocha": "2.4.5", "mocha-only-detector": "0.0.2", + "phantomjs-prebuilt": "^2.1.12", "pretender": "1.0.0", "rimraf": "2.5.2", "rsvp": "3.2.1" From c12fff95dc59165fb4e8a3e513a5cb7326cdc76e Mon Sep 17 00:00:00 2001 From: Wong Pei Yi Date: Fri, 9 Sep 2016 15:25:25 +0800 Subject: [PATCH 1582/2527] isUpdating should be true only if a reload happens `findAll` should not set `isUpdating` to true if `backgroundReload` or `shouldBackgroundReloadAll` returns false --- addon/-private/system/store.js | 5 ++-- tests/integration/adapter/find-all-test.js | 31 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index be8b7ea3e24..fc3b917fbec 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1375,15 +1375,15 @@ Store = Service.extend({ assert("You tried to load all records but you have no adapter (for " + typeClass + ")", adapter); assert("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function'); - set(array, 'isUpdating', true); - if (options.reload) { + set(array, 'isUpdating', true); return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); } var snapshotArray = array.createSnapshot(options); if (adapter.shouldReloadAll(this, snapshotArray)) { + set(array, 'isUpdating', true); return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); } @@ -1392,6 +1392,7 @@ Store = Service.extend({ } if (options.backgroundReload || adapter.shouldBackgroundReloadAll(this, snapshotArray)) { + set(array, 'isUpdating', true); _findAll(adapter, this, typeClass, sinceToken, options); } diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index dfe533356bd..b9ba670bbe6 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -238,3 +238,34 @@ test("isUpdating is true while records are fetched in the background", function( }); }); }); + +test("isUpdating is false if records are not fetched in the background", function(assert) { + let findAllDeferred = Ember.RSVP.defer(); + env.registry.register('adapter:person', DS.Adapter.extend({ + findAll() { + return findAllDeferred.promise; + }, + shouldReloadAll: () => false, + shouldBackgroundReloadAll: () => false + })); + + run(function() { + store.push({ + data: [{ + type: 'person', + id: 1 + }] + }); + }); + + let persons = store.peekAll('person'); + assert.equal(persons.get("length"), 1); + + run(function() { + store.findAll('person').then(function(persons) { + assert.equal(persons.get("isUpdating"), false); + }); + }); + + assert.equal(persons.get("isUpdating"), false); +}); From c9d8212c857ca78218ad98d11621819b38dba98f Mon Sep 17 00:00:00 2001 From: bmac Date: Sat, 10 Sep 2016 11:28:32 -0400 Subject: [PATCH 1583/2527] Bump the version to 2.10.0-canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 89e022a842e..b96432e54b7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.9.0-canary", + "version": "2.10.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From 523e87fc4427cdcdad90df9e98089ee5f94e63c0 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 15 Sep 2016 19:24:35 -0700 Subject: [PATCH 1584/2527] bump to latest ember-cli, run ember init, cleanup post init (#4536) --- .editorconfig | 14 -------------- .npmignore | 2 +- bower.json | 2 -- config/environment.js | 6 ++++++ package.json | 26 +++++++++++++------------- tests/dummy/app/index.html | 8 ++++---- tests/dummy/app/router.js | 3 ++- tests/dummy/config/environment.js | 3 +-- tests/helpers/module-for-acceptance.js | 12 ++++++------ tests/helpers/start-app.js | 5 ++--- tests/index.html | 17 ++++++++--------- 11 files changed, 43 insertions(+), 55 deletions(-) create mode 100644 config/environment.js diff --git a/.editorconfig b/.editorconfig index 47c5438403c..219985c2289 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,22 +13,8 @@ insert_final_newline = true indent_style = space indent_size = 2 -[*.js] -indent_style = space -indent_size = 2 - [*.hbs] insert_final_newline = false -indent_style = space -indent_size = 2 - -[*.css] -indent_style = space -indent_size = 2 - -[*.html] -indent_style = space -indent_size = 2 [*.{diff,md}] trim_trailing_whitespace = false diff --git a/.npmignore b/.npmignore index ada672d4b66..076f02ba550 100644 --- a/.npmignore +++ b/.npmignore @@ -15,8 +15,8 @@ .ember-cli .gitignore .eslintrc.js -.travis.yml .watchmanconfig +.travis.yml bower.json ember-cli-build.js testem.js diff --git a/bower.json b/bower.json index 858d21de7a1..18ac48e998c 100644 --- a/bower.json +++ b/bower.json @@ -4,8 +4,6 @@ "dependencies": { "ember": "components/ember#release", "ember-cli-shims": "0.1.1", - "ember-cli-test-loader": "0.2.2", - "ember-qunit-notifications": "0.1.0", "pretender": "^0.12.0" }, "resolutions": { diff --git a/config/environment.js b/config/environment.js new file mode 100644 index 00000000000..28a787b62f4 --- /dev/null +++ b/config/environment.js @@ -0,0 +1,6 @@ +/*jshint node:true*/ +'use strict'; + +module.exports = function(/* environment, appConfig */) { + return { }; +}; diff --git a/package.json b/package.json index b96432e54b7..317f3add0bf 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "broccoli-file-creator": "^1.0.0", "broccoli-merge-trees": "^1.0.0", "chalk": "^1.1.1", - "ember-cli-babel": "^5.1.3", + "ember-cli-babel": "^5.1.6", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.0.0", "ember-cli-test-info": "^1.0.0", @@ -46,46 +46,46 @@ }, "devDependencies": { "bower": "^1.6.5", - "broccoli-asset-rev": "^2.1.2", + "broccoli-asset-rev": "^2.4.2", "broccoli-concat": "0.0.13", "broccoli-funnel": "^1.0.0", "broccoli-stew": "^1.0.1", "broccoli-string-replace": "^0.1.1", "broccoli-uglify-sourcemap": "^1.0.1", "broccoli-yuidoc": "^2.1.0", - "ember-ajax": "0.7.1", - "ember-cli": "2.5.1", + "ember-ajax": "^2.0.1", + "ember-cli": "^2.8.0", "ember-cli-app-version": "^1.0.0", "ember-cli-blueprint-test-helpers": "0.11.0", "ember-cli-dependency-checker": "^1.2.0", "ember-cli-eslint": "1.3.0", "ember-cli-htmlbars": "^1.0.3", - "ember-cli-htmlbars-inline-precompile": "^0.2.0", - "ember-cli-inject-live-reload": "^1.3.1", + "ember-cli-htmlbars-inline-precompile": "^0.3.1", + "ember-cli-inject-live-reload": "^1.4.0", "ember-cli-internal-test-helpers": "^0.8.1", "ember-cli-pretender": "0.6.0", - "ember-cli-qunit": "^1.4.0", - "ember-cli-release": "0.2.3", + "ember-cli-qunit": "^2.1.0", + "ember-cli-release": "^0.2.9", "ember-cli-sri": "^2.1.0", + "ember-cli-test-loader": "^1.1.0", "ember-cli-uglify": "^1.2.0", "ember-dev": "emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed", "ember-disable-prototype-extensions": "^1.1.0", "ember-disable-proxy-controllers": "^1.0.0", - "ember-export-application-global": "^1.0.3", - "ember-load-initializers": "^0.5.0", + "ember-export-application-global": "^1.0.5", + "ember-load-initializers": "^0.5.1", "ember-publisher": "0.0.7", "ember-resolver": "^2.0.3", - "ember-try": "^0.2.5", "ember-watson": "^0.7.0", "github": "^0.2.4", "glob": "5.0.13", - "loader.js": "^4.0.0", "mocha": "2.4.5", "mocha-only-detector": "0.0.2", "phantomjs-prebuilt": "^2.1.12", "pretender": "1.0.0", "rimraf": "2.5.2", - "rsvp": "3.2.1" + "rsvp": "3.2.1", + "loader.js": "^4.0.1" }, "peerDependencies": { "ember-inflector": "^1.9.4" diff --git a/tests/dummy/app/index.html b/tests/dummy/app/index.html index 190c96a0605..12684546ade 100644 --- a/tests/dummy/app/index.html +++ b/tests/dummy/app/index.html @@ -9,16 +9,16 @@ {{content-for "head"}} - - + + {{content-for "head-footer"}} {{content-for "body"}} - - + + {{content-for "body-footer"}} diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js index 3bba78ebc80..cdc257875f7 100644 --- a/tests/dummy/app/router.js +++ b/tests/dummy/app/router.js @@ -2,7 +2,8 @@ import Ember from 'ember'; import config from './config/environment'; const Router = Ember.Router.extend({ - location: config.locationType + location: config.locationType, + rootURL: config.rootURL }); Router.map(function() { diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index 199a5f7abc0..28558b13154 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -10,7 +10,7 @@ module.exports = function(environment) { var ENV = { modulePrefix: 'dummy', environment: environment, - baseURL: '/', + rootURL: '/', locationType: 'auto', EmberENV: { FEATURES: featureFlags, @@ -41,7 +41,6 @@ module.exports = function(environment) { if (environment === 'test') { // Testem prefers this... - ENV.baseURL = '/'; ENV.locationType = 'none'; // keep test console output quieter diff --git a/tests/helpers/module-for-acceptance.js b/tests/helpers/module-for-acceptance.js index 8c8b74ecb2b..76996fd0428 100644 --- a/tests/helpers/module-for-acceptance.js +++ b/tests/helpers/module-for-acceptance.js @@ -1,23 +1,23 @@ import { module } from 'qunit'; +import Ember from 'ember'; import startApp from '../helpers/start-app'; import destroyApp from '../helpers/destroy-app'; +const { RSVP: { Promise } } = Ember; + export default function(name, options = {}) { module(name, { beforeEach() { this.application = startApp(); if (options.beforeEach) { - options.beforeEach.apply(this, arguments); + return options.beforeEach.apply(this, arguments); } }, afterEach() { - if (options.afterEach) { - options.afterEach.apply(this, arguments); - } - - destroyApp(this.application); + let afterEach = options.afterEach && options.afterEach.apply(this, arguments); + return Promise.resolve(afterEach).then(() => destroyApp(this.application)); } }); } diff --git a/tests/helpers/start-app.js b/tests/helpers/start-app.js index 0bb77910549..e098f1d5be6 100644 --- a/tests/helpers/start-app.js +++ b/tests/helpers/start-app.js @@ -1,13 +1,12 @@ import Ember from 'ember'; import Application from '../../app'; import config from '../../config/environment'; -var assign = Ember.assign || Ember.merge; export default function startApp(attrs) { let application; - let attributes = assign({}, config.APP); - attributes = assign(attributes, attrs); // use defaults, but you can override; + let attributes = Ember.merge({}, config.APP); + attributes = Ember.merge(attributes, attrs); // use defaults, but you can override; Ember.run(() => { application = Application.create(attributes); diff --git a/tests/index.html b/tests/index.html index 64cb47e31ff..f7ff652109d 100644 --- a/tests/index.html +++ b/tests/index.html @@ -10,9 +10,9 @@ {{content-for "head"}} {{content-for "test-head"}} - - - + + + {{content-for "head-footer"}} {{content-for "test-head-footer"}} @@ -21,12 +21,11 @@ {{content-for "body"}} {{content-for "test-body"}} - - - - - - + + + + + {{content-for "body-footer"}} {{content-for "test-body-footer"}} From 52a4d43605ca798df601851f6a5ce398f3d34f22 Mon Sep 17 00:00:00 2001 From: Scott Batson Date: Thu, 15 Sep 2016 22:26:52 -0400 Subject: [PATCH 1585/2527] [DOC] fix features response typo (#4530) --- FEATURES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 1c6e0de793a..6bccd4f01be 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -55,7 +55,7 @@ entry in `config/features.json`. `modelNameFromPayloadKey` are available in that serializer. ```js - // rest reponse + // rest response { "blog/post": { "id": 1, @@ -70,7 +70,7 @@ entry in `config/features.json`. ``` ```js - // json-api reponse + // json-api response { "data": { "id": 1, From 1f7e2a24a4f5758ce0ec288db29e814d8d637124 Mon Sep 17 00:00:00 2001 From: Bradley Priest Date: Fri, 16 Sep 2016 10:54:10 +0800 Subject: [PATCH 1586/2527] Fixes a typo of a private method (#4531) --- addon/-private/system/model/internal-model.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index fa7c77c8516..f82bb844761 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -228,14 +228,14 @@ InternalModel.prototype = { if (this.record) { this.record._notifyProperties(changedKeys); } - this.didInitalizeData(); + this.didInitializeData(); }, becameReady() { Ember.run.schedule('actions', this.store.recordArrayManager, this.store.recordArrayManager.recordWasLoaded, this); }, - didInitalizeData() { + didInitializeData() { if (!this.dataHasInitialized) { this.becameReady(); this.dataHasInitialized = true; @@ -271,7 +271,7 @@ InternalModel.prototype = { */ loadedData() { this.send('loadedData'); - this.didInitalizeData(); + this.didInitializeData(); }, /* From 5e0ee7e6b8032a1dfe04e53acbac4cdee8be5ecf Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 19 Sep 2016 08:35:03 -0400 Subject: [PATCH 1587/2527] [BUGFIX beta] Ember Data should not swallow exceptions from the run loop Closes #4533 --- addon/adapters/rest.js | 82 +++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 45 deletions(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index e5affdabe6a..7ad5d7d8269 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1007,25 +1007,17 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { var hash = adapter.ajaxOptions(url, type, options); hash.success = function(payload, textStatus, jqXHR) { - try { - var response = ajaxSuccess(adapter, jqXHR, payload, requestData); - Ember.run.join(null, resolve, response); - } catch (error) { - Ember.run.join(null, reject, error); - } + var response = ajaxSuccess(adapter, jqXHR, payload, requestData); + Ember.run.join(null, resolve, response); }; hash.error = function(jqXHR, textStatus, errorThrown) { - try { - var responseData = { - textStatus, - errorThrown - }; - var error = ajaxError(adapter, jqXHR, requestData, responseData); - Ember.run.join(null, reject, error); - } catch (error) { - Ember.run.join(null, reject, error); - } + var responseData = { + textStatus, + errorThrown + }; + var error = ajaxError(adapter, jqXHR, requestData, responseData); + Ember.run.join(null, reject, error); }; adapter._ajaxRequest(hash); @@ -1382,26 +1374,17 @@ if (isEnabled('ds-improved-ajax')) { return new Ember.RSVP.Promise((resolve, reject) => { hash.success = function(payload, textStatus, jqXHR) { - try { - var response = ajaxSuccess(adapter, jqXHR, payload, requestData); - Ember.run.join(null, resolve, response); - } catch (error) { - Ember.run.join(null, reject, error); - } - + var response = ajaxSuccess(adapter, jqXHR, payload, requestData); + Ember.run.join(null, resolve, response); }; hash.error = function(jqXHR, textStatus, errorThrown) { - try { - var responseData = { - textStatus, - errorThrown - }; - var error = ajaxError(adapter, jqXHR, requestData, responseData); - Ember.run.join(null, reject, error); - } catch (error) { - Ember.run.join(null, reject, error); - } + var responseData = { + textStatus, + errorThrown + }; + var error = ajaxError(adapter, jqXHR, requestData, responseData); + Ember.run.join(null, reject, error); }; adapter._ajaxRequest(hash); @@ -1413,12 +1396,17 @@ if (isEnabled('ds-improved-ajax')) { } function ajaxSuccess(adapter, jqXHR, payload, requestData) { - let response = adapter.handleResponse( - jqXHR.status, - parseResponseHeaders(jqXHR.getAllResponseHeaders()), - payload, - requestData - ); + let response; + try { + response = adapter.handleResponse( + jqXHR.status, + parseResponseHeaders(jqXHR.getAllResponseHeaders()), + payload, + requestData + ); + } catch (error) { + return Promise.reject(error); + } if (response && response.isAdapterError) { return Promise.reject(response); @@ -1445,12 +1433,16 @@ function ajaxError(adapter, jqXHR, requestData, responseData) { } else if (responseData.textStatus === 'abort') { error = new AbortError(); } else { - error = adapter.handleResponse( - jqXHR.status, - parseResponseHeaders(jqXHR.getAllResponseHeaders()), - adapter.parseErrorResponse(jqXHR.responseText) || responseData.errorThrown, - requestData - ); + try { + error = adapter.handleResponse( + jqXHR.status, + parseResponseHeaders(jqXHR.getAllResponseHeaders()), + adapter.parseErrorResponse(jqXHR.responseText) || responseData.errorThrown, + requestData + ); + } catch (e) { + error = e; + } } return error; From 43e0b11a8e42916554d1cf080e8210eee06d1a42 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 21 Sep 2016 21:41:29 -0700 Subject: [PATCH 1588/2527] [BUGFIX beta] Make `Model#data` a plain getter. In Ember 2.9, using an `Ember.computed.alias` or `Ember.computed.readOnly` automatically adds mandatory setter's getter/setter to the properties being watched, and defers reading the current value to the objects own meta. This avoids creating an watcher for `_internalModel` and therefore prevents an error that ocurrs when we attempt to read from `meta` after the object has been destroyed. --- addon/-private/system/model/model.js | 18 +++++++++++------- tests/integration/store-test.js | 2 -- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index e13536d9fc5..cddcd8693f6 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -476,13 +476,6 @@ var Model = Ember.Object.extend(Ember.Evented, { */ rolledBack: Ember.K, - /** - @property data - @private - @type {Object} - */ - data: Ember.computed.readOnly('_internalModel._data'), - //TODO Do we want to deprecate these? /** @method send @@ -951,6 +944,17 @@ var Model = Ember.Object.extend(Ember.Evented, { }) }); +/** + @property data + @private + @type {Object} + */ +Object.defineProperty(Model.prototype, 'data', { + get() { + return this._internalModel._data; + } +}); + Model.reopenClass({ /** Alias DS.Model's `create` method to `_create`. This allows us to create DS.Model diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 15adc9a4727..b4fde419326 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -905,5 +905,3 @@ testInDebug('store#queryRecord should assert when normalized payload of adapter }); }, /Expected the primary data returned by the serializer for a `queryRecord` response to be a single object or null but instead it was an array./); }); - - From cf3ac13eb8ffa5fe0ee9cb0de80de8dbb9ac4ded Mon Sep 17 00:00:00 2001 From: Ryunosuke Sato Date: Thu, 22 Sep 2016 22:37:55 +0900 Subject: [PATCH 1589/2527] [BUGFIX release] Include initializers for global production build (#4541) In [`ember-data.prod.js`](http://builds.emberjs.com/tags/v2.8.0/ember-data.prod.js), the Ember Data's initializers are missing since 2.8.0. Without these initializes, `DS.Store` isn't setup for Ember application :< --- lib/javascripts.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/javascripts.js b/lib/javascripts.js index a88cc38ac9f..ba28882c876 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -96,6 +96,9 @@ module.exports = function(tree) { var strippedJavascripts = merge([ emberInflector, + loadInitializers, + makeStrippedBuild('ember-data/initializers', 'app/initializers'), + makeStrippedBuild('ember-data/instance-initializers', 'app/instance-initializers'), makeStrippedBuild('ember-data', emberData) ]); From a67315459dc644af6718c178a0724775c6d3b42d Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Thu, 22 Sep 2016 13:47:36 -0500 Subject: [PATCH 1590/2527] =?UTF-8?q?Revert=20"Log=20an=20assertion=20if?= =?UTF-8?q?=20the=20response=20from=20createRecord=20does=20not=20have=20a?= =?UTF-8?q?n=20i=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addon/-private/system/store.js | 2 +- tests/integration/adapter/rest-adapter-test.js | 6 +++--- tests/integration/adapter/store-adapter-test.js | 2 +- tests/integration/client-id-generation-test.js | 2 +- tests/integration/relationships/has-many-test.js | 5 +---- tests/integration/store-test.js | 13 ------------- tests/unit/model-test.js | 2 +- 7 files changed, 8 insertions(+), 24 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index be8b7ea3e24..8eb10a99547 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1697,7 +1697,7 @@ Store = Service.extend({ this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, data); this.updateId(internalModel, data); } - assert(`Your ${internalModel.type.modelName} record was saved but it does not have an id. Please make the server provides an id in the createRecord response or you are setting the on the client side before saving the record.`, internalModel.id !== null); + //We first make sure the primary data has been updated //TODO try to move notification to the user to the end of the runloop internalModel.adapterDidCommit(data); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 47ebc3d3cff..5fa73ba1984 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -328,14 +328,14 @@ test("createRecord - a serializer's primary key and attributes are consulted whe test("createRecord - a serializer's attributes are consulted when building the payload if no id is pre-defined", function(assert) { var post; env.registry.register('serializer:post', DS.RESTSerializer.extend({ + primarykey: '_id_', + attrs: { name: '_name_' } })); - ajaxResponse({ - post: { '_name_': "The Parley Letter", id: '1' } - }); + ajaxResponse(); run(function() { post = store.createRecord('post', { name: "The Parley Letter" }); diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 0094d5a7bdd..eec8b75b16b 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -1057,7 +1057,7 @@ test("createRecord receives a snapshot", function(assert) { var person; run(function() { - person = store.createRecord('person', { name: "Tom Dale", id: 1 }); + person = store.createRecord('person', { name: "Tom Dale" }); person.save(); }); }); diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index b98a439db50..72f008b5afa 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -86,7 +86,7 @@ test("empty string and undefined ids should coerce to null", function(assert) { env.adapter.createRecord = function(store, type, record) { assert.equal(typeof get(record, 'id'), 'object', 'correct type'); - return Ember.RSVP.resolve({ id: 1 }); + return Ember.RSVP.resolve(); }; run(function() { diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 2300815875a..49a46557509 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -342,7 +342,6 @@ test("A hasMany updated link should not remove new children", function(assert) { env.adapter.createRecord = function(store, snapshot, link, relationship) { return Ember.RSVP.resolve({ - id: 1, links: { comments: '/some/link' } @@ -383,7 +382,6 @@ test("A hasMany updated link should not remove new children when the parent reco env.adapter.createRecord = function(store, snapshot, link, relationship) { return Ember.RSVP.resolve({ - id: 1, links: { comments: '/some/link' } @@ -2209,7 +2207,6 @@ test("adding and removing records from hasMany relationship #2666", function(ass }) }); - var commentId = 4; env.registry.register('adapter:comment', DS.RESTAdapter.extend({ deleteRecord(record) { return Ember.RSVP.resolve(); @@ -2218,7 +2215,7 @@ test("adding and removing records from hasMany relationship #2666", function(ass return Ember.RSVP.resolve(); }, createRecord() { - return Ember.RSVP.resolve({ comments: { id: commentId++ }}); + return Ember.RSVP.resolve(); } })); diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index b4fde419326..df4c42e1acc 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -867,19 +867,6 @@ testInDebug('store#findRecord that returns an array should assert', assert => { }, /expected the primary data returned from a `findRecord` response to be an object but instead it found an array/); }); -testInDebug('store#didSaveRecord should assert when the response to a save does not include the id', function(assert) { - env.adapter.createRecord = function() { - return {}; - }; - - assert.expectAssertion(function() { - run(function() { - var car = store.createRecord('car'); - car.save(); - }); - }, /record was saved but it does not have an id. Please make the server provides an id in the createRecord/); -}); - module("integration/store - queryRecord", { beforeEach() { initializeStore(DS.Adapter.extend()); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index ea2cc1dc17a..a58452a6537 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -370,7 +370,7 @@ test("changedAttributes() works while the record is being saved", function(asser assert.deepEqual(toObj(cat.changedAttributes()), { name: [undefined, 'Argon'], likes: [undefined, 'Cheese'] }); - return { id: 1 }; + return {}; } }); var Mascot = DS.Model.extend({ From 75e878196843d2a703ad21b88e166ff8a54596e8 Mon Sep 17 00:00:00 2001 From: Ryunosuke Sato Date: Fri, 23 Sep 2016 03:51:36 +0900 Subject: [PATCH 1591/2527] [DOC beta] Remove `Ember.ArrayController` from initializer example (#4540) `Ember.ArrayController` is deprecated since Ember 1.11. ref: http://emberjs.com/deprecations/v1.x/#toc_arraycontroller --- app/initializers/ember-data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/initializers/ember-data.js b/app/initializers/ember-data.js index fc6386fdc81..af05b1c36e4 100644 --- a/app/initializers/ember-data.js +++ b/app/initializers/ember-data.js @@ -19,7 +19,7 @@ import 'ember-data/-private/core'; adapter: 'custom' }); - App.PostsController = Ember.ArrayController.extend({ + App.PostsController = Ember.Controller.extend({ // ... }); From 77844641c124c1623d93d3e4499b943445ca39da Mon Sep 17 00:00:00 2001 From: Tyler Hansen Date: Thu, 22 Sep 2016 12:22:13 -0700 Subject: [PATCH 1592/2527] [BUGFIX beta] Correctly serialize invalid dates Invalid Date objects - such as `new Date("foo")` - are Date objects that throw a `RangeError` when calling `date.toISOString()`. These are now serialized like all other garbage-in inputs. --- addon/-private/transforms/date.js | 2 +- tests/unit/transform/date-test.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/-private/transforms/date.js b/addon/-private/transforms/date.js index e49bcc05b7b..b0cb5ac29b2 100644 --- a/addon/-private/transforms/date.js +++ b/addon/-private/transforms/date.js @@ -41,7 +41,7 @@ export default Transform.extend({ }, serialize(date) { - if (date instanceof Date) { + if (date instanceof Date && !isNaN(date)) { return date.toISOString(); } else { return null; diff --git a/tests/unit/transform/date-test.js b/tests/unit/transform/date-test.js index 62da125bba5..6c4a94223ea 100644 --- a/tests/unit/transform/date-test.js +++ b/tests/unit/transform/date-test.js @@ -18,6 +18,7 @@ test("#serialize", function(assert) { assert.equal(transform.serialize(null), null); assert.equal(transform.serialize(undefined), null); + assert.equal(transform.serialize(new Date("invalid")), null); assert.equal(transform.serialize(date), dateString); }); From 07a003763215ea3d14844eef0c66caf826b05ded Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Thu, 22 Sep 2016 23:13:22 -0400 Subject: [PATCH 1593/2527] Add examples to the build-url-mixin API docs (#4512) --- addon/-private/adapters/build-url-mixin.js | 239 +++++++++++++++++---- 1 file changed, 198 insertions(+), 41 deletions(-) diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index 407e665381a..b2b1a09314b 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -108,101 +108,258 @@ export default Ember.Mixin.create({ }, /** - * @method urlForFindRecord - * @param {String} id - * @param {String} modelName - * @param {DS.Snapshot} snapshot - * @return {String} url + Builds a URL for a `store.findRecord(type, id)` call. + + Example: + + ```app/adapters/user.js + import DS from 'ember-data'; + + export default DS.JSONAPIAdapter.extend({ + urlForFindRecord(id, modelName, snapshot) { + let baseUrl = this.buildURL(); + return `${baseUrl}/users/${snapshot.adapterOptions.user_id}/playlists/${id}`; + } + }); + ``` + + @method urlForFindRecord + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url + */ urlForFindRecord(id, modelName, snapshot) { return this._buildURL(modelName, id); }, /** - * @method urlForFindAll - * @param {String} modelName - * @param {DS.SnapshotRecordArray} snapshot - * @return {String} url + Builds a URL for a `store.findAll(type)` call. + + Example: + + ```app/adapters/comment.js + import DS from 'ember-data'; + + export default DS.JSONAPIAdapter.extend({ + urlForFindAll(id, modelName, snapshot) { + return 'data/comments.json'; + } + }); + ``` + + @method urlForFindAll + @param {String} modelName + @param {DS.SnapshotRecordArray} snapshot + @return {String} url */ urlForFindAll(modelName, snapshot) { return this._buildURL(modelName); }, /** - * @method urlForQuery - * @param {Object} query - * @param {String} modelName - * @return {String} url + Builds a URL for a `store.query(type, query)` call. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + host: 'https://api.github.com', + urlForQuery (query, modelName) { + switch(modelName) { + case 'repo': + return `https://api.github.com/orgs/${query.orgId}/repos`; + default: + return this._super(...arguments); + } + } + }); + ``` + + @method urlForQuery + @param {Object} query + @param {String} modelName + @return {String} url */ urlForQuery(query, modelName) { return this._buildURL(modelName); }, /** - * @method urlForQueryRecord - * @param {Object} query - * @param {String} modelName - * @return {String} url + Builds a URL for a `store.queryRecord(type, query)` call. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForQueryRecord({ slug }, modelName) { + let baseUrl = this.buildURL(); + return `${baseUrl}/${encodeURIComponent(slug)}`; + } + }); + ``` + + @method urlForQueryRecord + @param {Object} query + @param {String} modelName + @return {String} url */ urlForQueryRecord(query, modelName) { return this._buildURL(modelName); }, /** - * @method urlForFindMany - * @param {Array} ids - * @param {String} modelName - * @param {Array} snapshots - * @return {String} url + Builds a URL for coalesceing multiple `store.findRecord(type, id) + records into 1 request when the adapter's `coalesceFindRequests` + property is true. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForFindMany(ids, modelName) { + let baseUrl = this.buildURL(); + return `${baseUrl}/coalesce`; + } + }); + ``` + + @method urlForFindMany + @param {Array} ids + @param {String} modelName + @param {Array} snapshots + @return {String} url */ urlForFindMany(ids, modelName, snapshots) { return this._buildURL(modelName); }, /** - * @method urlForFindHasMany - * @param {String} id - * @param {String} modelName - * @param {DS.Snapshot} snapshot - * @return {String} url + Builds a URL for fetching a async hasMany relationship when a url + is not provided by the server. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.JSONAPIAdapter.extend({ + urlForFindHasMany(id, modelName, snapshot) { + let baseUrl = this.buildURL(id, modelName); + return `${baseUrl}/relationships`; + } + }); + ``` + + @method urlForFindHasMany + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url */ urlForFindHasMany(id, modelName, snapshot) { return this._buildURL(modelName, id); }, /** - * @method urlForFindBelongsTo - * @param {String} id - * @param {String} modelName - * @param {DS.Snapshot} snapshot - * @return {String} url + Builds a URL for fetching a async belongsTo relationship when a url + is not provided by the server. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.JSONAPIAdapter.extend({ + urlForFindBelongsTo(id, modelName, snapshot) { + let baseUrl = this.buildURL(id, modelName); + return `${baseUrl}/relationships`; + } + }); + ``` + + @method urlForFindBelongsTo + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url */ urlForFindBelongsTo(id, modelName, snapshot) { return this._buildURL(modelName, id); }, /** - * @method urlForCreateRecord - * @param {String} modelName - * @param {DS.Snapshot} snapshot - * @return {String} url + Builds a URL for a `record.save()` call when the record was created + locally using `store.createRecord()`. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForCreateRecord(modelName, snapshot) { + return this._super(...arguments) + '/new'; + } + }); + ``` + + @method urlForCreateRecord + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url */ urlForCreateRecord(modelName, snapshot) { return this._buildURL(modelName); }, /** - * @method urlForUpdateRecord - * @param {String} id - * @param {String} modelName - * @param {DS.Snapshot} snapshot - * @return {String} url + Builds a URL for a `record.save()` call when the record has been update locally. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForUpdateRecord(id, modelName, snapshot) { + return `/${id}/feed?access_token=${snapshot.adapterOptions.token}`; + } + }); + ``` + + @method urlForUpdateRecord + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url */ urlForUpdateRecord(id, modelName, snapshot) { return this._buildURL(modelName, id); }, /** + Builds a URL for a `record.save()` call when the record has been deleted locally. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForDeleteRecord(id, modelName, snapshot) { + return this._super(...arguments) + '/destroy'; + } + }); + ``` + * @method urlForDeleteRecord * @param {String} id * @param {String} modelName From cdbdcfd614bf6707a1e3bb80fdcb93d06199c1c2 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Sun, 25 Sep 2016 20:33:47 -0400 Subject: [PATCH 1594/2527] Update the changelog for the 2.8.1 release (#4548) --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4012aa5675..4eca5499a0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ ### Master +### Release 2.8.1 (September 23, 2016) +- [#4536](https://github.com/emberjs/data/pull/4536) bump to latest ember-cli, run ember init, cleanup post init +- [#4546](https://github.com/emberjs/data/pull/4546) Revert "Log an assertion if the response from createRecord does not have an I…" +- [#4537](https://github.com/emberjs/data/pull/4537) [BUGFIX beta] Ember Data should not swallow exceptions from the run loop +- [#4545](https://github.com/emberjs/data/pull/4545) [BUGFIX beta] Make `Model#data` a plain getter. +- [#4541](https://github.com/emberjs/data/pull/4541) [BUGFIX release] Include initializers for global production build + + ### Release 2.8.0 (September 8, 2016) - [#4464](https://github.com/emberjs/data/pull/4464) Add benchmarks directory to npmignore From 8c24053d366c294f7f04a7a230dcfd3b9d549661 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Mon, 26 Sep 2016 11:40:57 -0400 Subject: [PATCH 1595/2527] [DOCS] Fix store.unloadAll modelName param type Remove extra character --- addon/-private/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 8eb10a99547..ad776377d17 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1454,7 +1454,7 @@ Store = Service.extend({ ``` @method unloadAll - @param {String=} modelName + @param {String} modelName */ unloadAll(modelName) { assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), !modelName || typeof modelName === 'string'); From 9e97dced436637fd1e37c32a8ed4b5f0849803cc Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 29 Sep 2016 10:45:07 -0400 Subject: [PATCH 1596/2527] [BUGFIX beta] Ensure record array length is reset during willDestroy. In Ember 2.10+ objects that are in the middle of being destroyed no longer notify property changes on itself (or other destroying objects) to avoid wasted work. This means that `set(this, 'content', undefined)` isn't enough to ensure that `Enumerable` mixin will `notifyPropertyChange(this, 'length')` (since its observers are not fired). This change also sets `length` during cleanup so it properly resets to `0`. --- addon/-private/system/record-arrays/record-array.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index 35171878f74..58b365bb503 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -211,6 +211,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { this._unregisterFromManager(); this._dissociateFromOwnRecords(); set(this, 'content', undefined); + set(this, 'length', 0); this._super.apply(this, arguments); }, From 68941e774a3ba260bab6a123f76f77ac39fab4c4 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 29 Sep 2016 00:28:53 -0400 Subject: [PATCH 1597/2527] [BUGFIX beta] Use Ember.guidFor to set InternalModel's guid. In future versions of Ember, the `Ember.GUID_KEY` property may not be the place that guids are stored per object (may be moving to a `WeakMap`). This change keeps `this[GUID_KEY]` around for easier debugging (though it isn't _required_ per-se), and uses `Ember.guidFor` to get the guid and setup the object. --- addon/-private/system/model/internal-model.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index f82bb844761..5662da11273 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -43,7 +43,6 @@ function retrieveFromCurrentState(key) { }; } -var guid = 0; /* `InternalModel` is the Model class that we use internally inside Ember Data to represent models. Internal ED methods should only deal with `InternalModel` objects. It is a fast, plain Javascript class. @@ -81,7 +80,7 @@ export default function InternalModel(type, id, store, _, data) { this.isError = false; this.error = null; this.__ember_meta__ = null; - this[Ember.GUID_KEY] = guid++ + 'internal-model'; + this[Ember.GUID_KEY] = Ember.guidFor(this); /* implicit relationships are relationship which have not been declared but the inverse side exists on another record somewhere From d3966fa614eab3e1971a47cd6f5b92b49dee4809 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 22 Aug 2016 23:17:20 -0700 Subject: [PATCH 1598/2527] adds a mock server, dummy app, and heimdall instrumentation for benchmarking --- .eslintrc.js | 3 + .gitignore | 2 + addon/-private/debug.js | 4 + addon/-private/system/model/internal-model.js | 39 +++++++++ addon/-private/system/model/states.js | 2 + addon/-private/system/record-array-manager.js | 61 ++++++++++++++ .../adapter-populated-record-array.js | 2 + .../relationships/state/relationship.js | 71 ++++++++++++++++ addon/-private/system/store.js | 82 ++++++++++++++++++- addon/-private/system/store/common.js | 13 +++ .../system/store/container-instance-cache.js | 11 +++ addon/-private/system/store/finders.js | 2 +- addon/adapters/json-api.js | 19 ++++- addon/adapters/rest.js | 41 +++++++++- benchmarks/.gitignore | 1 + benchmarks/bash-analyze.js | 8 ++ benchmarks/bash-run.js | 7 ++ benchmarks/config.js | 78 ++++++++++++++++++ benchmarks/index.js | 7 ++ .../results/development-stripped}/.gitkeep | 0 .../results/development}/.gitkeep | 0 .../results/production-stripped}/.gitkeep | 0 benchmarks/results/production/.gitkeep | 0 ember-cli-build.js | 11 ++- lib/babel-build.js | 2 +- lib/stripped-build-plugins.js | 22 ++++- package.json | 6 ++ server/.jshintrc | 3 + server/index.js | 14 ++++ tests/.eslintrc.js | 3 + tests/dummy/app/adapters/application.js | 5 ++ .../app/helpers/reopen-instrumentation.js | 51 ++++++++++++ tests/dummy/app/models/baz.js | 14 ++++ tests/dummy/app/models/complex.js | 15 ++++ tests/dummy/app/models/foo.js | 14 ++++ tests/dummy/app/models/heavy-baz.js | 15 ++++ tests/dummy/app/models/heavy-foo.js | 14 ++++ tests/dummy/app/models/heavy.js | 15 ++++ tests/dummy/app/models/simple.js | 11 +++ tests/dummy/app/router.js | 1 + tests/dummy/app/routes/application/route.js | 4 + .../dummy/app/routes/application/template.hbs | 2 + tests/dummy/app/routes/components/.gitkeep | 0 tests/dummy/app/routes/index/route.js | 4 + tests/dummy/app/routes/index/template.hbs | 5 ++ tests/dummy/app/routes/query/controller.js | 11 +++ tests/dummy/app/routes/query/route.js | 43 ++++++++++ tests/dummy/app/routes/query/template.hbs | 1 + tests/dummy/app/templates/.gitkeep | 0 tests/dummy/app/templates/application.hbs | 3 - tests/dummy/config/environment.js | 3 +- vendor/.gitkeep | 0 52 files changed, 730 insertions(+), 15 deletions(-) create mode 100644 benchmarks/.gitignore create mode 100644 benchmarks/bash-analyze.js create mode 100644 benchmarks/bash-run.js create mode 100644 benchmarks/config.js create mode 100644 benchmarks/index.js rename {tests/dummy/app/components => benchmarks/results/development-stripped}/.gitkeep (100%) rename {tests/dummy/app/controllers => benchmarks/results/development}/.gitkeep (100%) rename {tests/dummy/app/templates/components => benchmarks/results/production-stripped}/.gitkeep (100%) create mode 100644 benchmarks/results/production/.gitkeep create mode 100644 server/.jshintrc create mode 100644 server/index.js create mode 100644 tests/dummy/app/adapters/application.js create mode 100644 tests/dummy/app/helpers/reopen-instrumentation.js create mode 100644 tests/dummy/app/models/baz.js create mode 100644 tests/dummy/app/models/complex.js create mode 100644 tests/dummy/app/models/foo.js create mode 100644 tests/dummy/app/models/heavy-baz.js create mode 100644 tests/dummy/app/models/heavy-foo.js create mode 100644 tests/dummy/app/models/heavy.js create mode 100644 tests/dummy/app/models/simple.js create mode 100644 tests/dummy/app/routes/application/route.js create mode 100644 tests/dummy/app/routes/application/template.hbs create mode 100644 tests/dummy/app/routes/components/.gitkeep create mode 100644 tests/dummy/app/routes/index/route.js create mode 100644 tests/dummy/app/routes/index/template.hbs create mode 100644 tests/dummy/app/routes/query/controller.js create mode 100644 tests/dummy/app/routes/query/route.js create mode 100644 tests/dummy/app/routes/query/template.hbs create mode 100644 tests/dummy/app/templates/.gitkeep delete mode 100644 tests/dummy/app/templates/application.hbs create mode 100644 vendor/.gitkeep diff --git a/.eslintrc.js b/.eslintrc.js index 9f2f1ee24e2..7772cb11d12 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -9,6 +9,9 @@ module.exports = { env: { 'browser': true, }, + globals: { + 'heimdall': true + }, rules: { 'no-unused-vars': ['error', { 'args': 'none', diff --git a/.gitignore b/.gitignore index 719df70414a..11c4f19a7f7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ dist/ .idea *.iml +benchmarks/results/*.json + .DS_Store .project diff --git a/addon/-private/debug.js b/addon/-private/debug.js index c98e7064378..952dfd2f20d 100644 --- a/addon/-private/debug.js +++ b/addon/-private/debug.js @@ -20,6 +20,10 @@ export function runInDebug() { return Ember.runInDebug(...arguments); } +export function instrument() { + return Ember.runInDebug(...arguments); +} + export function warn() { return Ember.warn(...arguments); } diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 5662da11273..de74ba4a0a9 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -43,6 +43,34 @@ function retrieveFromCurrentState(key) { }; } +// this (and all heimdall instrumentation) will be stripped by a babel transform +// https://github.com/heimdalljs/babel5-plugin-strip-heimdall +const { + new_InternalModel, + materializeRecord, + setupData, + createSnapshot, + flushChangedAttributes, + hasChangedAttributes, + updateChangedAttributes, + changedAttributes, + send, + transitionTo, + _triggerDeferredTriggers +} = heimdall.registerMonitor('InternalModel', + 'new_InternalModel', + 'materializeRecord', + 'setupData', + 'createSnapshot', + 'flushChangedAttributes', + 'hasChangedAttributes', + 'updateChangedAttributes', + 'changedAttributes', + 'send', + 'transitionTo', + '_triggerDeferredTriggers' +); + /* `InternalModel` is the Model class that we use internally inside Ember Data to represent models. Internal ED methods should only deal with `InternalModel` objects. It is a fast, plain Javascript class. @@ -61,6 +89,7 @@ function retrieveFromCurrentState(key) { */ export default function InternalModel(type, id, store, _, data) { + heimdall.increment(new_InternalModel); this.type = type; this.id = id; this.store = store; @@ -124,6 +153,7 @@ InternalModel.prototype = { constructor: InternalModel, materializeRecord() { + heimdall.increment(materializeRecord); assert("Materialized " + this.modelName + " record with id:" + this.id + "more than once", this.record === null || this.record === undefined); // lookupFactory should really return an object that creates @@ -221,6 +251,7 @@ InternalModel.prototype = { }, setupData(data) { + heimdall.increment(setupData); var changedKeys = this._changedKeys(data.attributes); assign(this._data, data.attributes); this.pushedData(); @@ -252,6 +283,7 @@ InternalModel.prototype = { @private */ createSnapshot(options) { + heimdall.increment(createSnapshot); return new Snapshot(this, options); }, @@ -290,11 +322,13 @@ InternalModel.prototype = { }, flushChangedAttributes() { + heimdall.increment(flushChangedAttributes); this._inFlightAttributes = this._attributes; this._attributes = new EmptyObject(); }, hasChangedAttributes() { + heimdall.increment(hasChangedAttributes); return Object.keys(this._attributes).length > 0; }, @@ -309,6 +343,7 @@ InternalModel.prototype = { @private */ updateChangedAttributes() { + heimdall.increment(updateChangedAttributes); var changedAttributes = this.changedAttributes(); var changedAttributeNames = Object.keys(changedAttributes); @@ -330,6 +365,7 @@ InternalModel.prototype = { @private */ changedAttributes() { + heimdall.increment(changedAttributes); var oldData = this._data; var currentData = this._attributes; var inFlightData = this._inFlightAttributes; @@ -370,6 +406,7 @@ InternalModel.prototype = { @param {Object} context */ send(name, context) { + heimdall.increment(send); var currentState = get(this, 'currentState'); if (!currentState[name]) { @@ -441,6 +478,7 @@ InternalModel.prototype = { @param {String} name */ transitionTo(name) { + heimdall.increment(transitionTo); // POSSIBLE TODO: Remove this code and replace with // always having direct reference to state objects @@ -509,6 +547,7 @@ InternalModel.prototype = { }, _triggerDeferredTriggers() { + heimdall.increment(_triggerDeferredTriggers); //TODO: Before 1.0 we want to remove all the events that happen on the pre materialized record, //but for now, we queue up all the events triggered before the record was materialized, and flush //them once we have the record diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index 234dc0e4fd9..934d6e4fa6d 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -248,11 +248,13 @@ var DirtyState = { }, pushedData(internalModel) { + let token = heimdall.start('stats.uncommitted.pushedData'); internalModel.updateChangedAttributes(); if (!internalModel.hasChangedAttributes()) { internalModel.transitionTo('loaded.saved'); } + heimdall.stop(token); }, becomeDirty: Ember.K, diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 92dc7de4fe4..cccbb69ce70 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -12,6 +12,48 @@ var MapWithDefault = Ember.MapWithDefault; import OrderedSet from "ember-data/-private/system/ordered-set"; var get = Ember.get; +const { + create, + recordDidChange, + recordArraysForRecord, + updateRecordArrays, + _recordWasDeleted, + _recordWasChanged, + recordWasLoaded, + updateFilterRecordArray, + _addRecordToRecordArray, + populateLiveRecordArray, + updateFilter, + liveRecordArrayFor, + createRecordArray, + createFilteredRecordArray, + createAdapterPopulatedRecordArray, + registerFilteredRecordArray, + unregisterRecordArray, + array_flatten, + array_remove +} = heimdall.registerMonitor('recordArrayManager', + 'create', + 'recordDidChange', + 'recordArraysForRecord', + 'updateRecordArrays', + '_recordWasDeleted', + '_recordWasChanged', + 'recordWasLoaded', + 'updateFilterRecordArray', + '_addRecordToRecordArray', + 'populateLiveRecordArray', + 'updateFilter', + 'liveRecordArrayFor', + 'createRecordArray', + 'createFilteredRecordArray', + 'createAdapterPopulatedRecordArray', + 'registerFilteredRecordArray', + 'unregisterRecordArray', + 'array_fatten', + 'array_remove' +); + /** @class RecordArrayManager @namespace DS @@ -20,6 +62,7 @@ var get = Ember.get; */ export default Ember.Object.extend({ init() { + heimdall.increment(create); this.filteredRecordArrays = MapWithDefault.create({ defaultValue() { return []; } }); @@ -35,12 +78,14 @@ export default Ember.Object.extend({ }, recordDidChange(record) { + heimdall.increment(recordDidChange); if (this.changedRecords.push(record) !== 1) { return; } Ember.run.schedule('actions', this, this.updateRecordArrays); }, recordArraysForRecord(record) { + heimdall.increment(recordArraysForRecord); record._recordArrays = record._recordArrays || OrderedSet.create(); return record._recordArrays; }, @@ -56,6 +101,7 @@ export default Ember.Object.extend({ @method updateRecordArrays */ updateRecordArrays() { + heimdall.increment(updateRecordArrays); this.changedRecords.forEach((internalModel) => { if (get(internalModel, 'record.isDestroyed') || get(internalModel, 'record.isDestroying') || (get(internalModel, 'currentState.stateName') === 'root.deleted.saved')) { @@ -69,6 +115,7 @@ export default Ember.Object.extend({ }, _recordWasDeleted(record) { + heimdall.increment(_recordWasDeleted); var recordArrays = record._recordArrays; if (!recordArrays) { return; } @@ -80,6 +127,7 @@ export default Ember.Object.extend({ _recordWasChanged(record) { + heimdall.increment(_recordWasChanged); var typeClass = record.type; var recordArrays = this.filteredRecordArrays.get(typeClass); var filter; @@ -91,6 +139,7 @@ export default Ember.Object.extend({ //Need to update live arrays on loading recordWasLoaded(record) { + heimdall.increment(recordWasLoaded); var typeClass = record.type; var recordArrays = this.filteredRecordArrays.get(typeClass); var filter; @@ -115,6 +164,7 @@ export default Ember.Object.extend({ @param {InternalModel} record */ updateFilterRecordArray(array, filter, typeClass, record) { + heimdall.increment(updateFilterRecordArray); var shouldBeInArray = filter(record.getRecord()); var recordArrays = this.recordArraysForRecord(record); if (shouldBeInArray) { @@ -126,6 +176,7 @@ export default Ember.Object.extend({ }, _addRecordToRecordArray(array, record) { + heimdall.increment(_addRecordToRecordArray); var recordArrays = this.recordArraysForRecord(record); if (!recordArrays.has(array)) { array.addInternalModel(record); @@ -134,6 +185,7 @@ export default Ember.Object.extend({ }, populateLiveRecordArray(array, modelName) { + heimdall.increment(populateLiveRecordArray); var typeMap = this.store.typeMapFor(modelName); var records = typeMap.records; var record; @@ -160,6 +212,7 @@ export default Ember.Object.extend({ @param {Function} filter */ updateFilter(array, modelName, filter) { + heimdall.increment(updateFilter); var typeMap = this.store.typeMapFor(modelName); var records = typeMap.records; var record; @@ -182,6 +235,7 @@ export default Ember.Object.extend({ @return {DS.RecordArray} */ liveRecordArrayFor(typeClass) { + heimdall.increment(liveRecordArrayFor); return this.liveRecordArrays.get(typeClass); }, @@ -193,6 +247,7 @@ export default Ember.Object.extend({ @return {DS.RecordArray} */ createRecordArray(typeClass) { + heimdall.increment(createRecordArray); var array = RecordArray.create({ type: typeClass, content: Ember.A(), @@ -214,6 +269,7 @@ export default Ember.Object.extend({ @return {DS.FilteredRecordArray} */ createFilteredRecordArray(typeClass, filter, query) { + heimdall.increment(createFilteredRecordArray); var array = FilteredRecordArray.create({ query: query, type: typeClass, @@ -237,6 +293,7 @@ export default Ember.Object.extend({ @return {DS.AdapterPopulatedRecordArray} */ createAdapterPopulatedRecordArray(typeClass, query) { + heimdall.increment(createAdapterPopulatedRecordArray); var array = AdapterPopulatedRecordArray.create({ type: typeClass, query: query, @@ -262,6 +319,7 @@ export default Ember.Object.extend({ @param {Function} filter */ registerFilteredRecordArray(array, typeClass, filter) { + heimdall.increment(registerFilteredRecordArray); var recordArrays = this.filteredRecordArrays.get(typeClass); recordArrays.push(array); @@ -276,6 +334,7 @@ export default Ember.Object.extend({ @param {DS.RecordArray} array */ unregisterRecordArray(array) { + heimdall.increment(unregisterRecordArray); var typeClass = array.type; // unregister filtered record array @@ -312,6 +371,7 @@ function destroy(entry) { } function flatten(list) { + heimdall.increment(array_flatten); var length = list.length; var result = Ember.A(); @@ -323,6 +383,7 @@ function flatten(list) { } function remove(array, item) { + heimdall.increment(array_remove); const index = array.indexOf(item); if (index !== -1) { diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index b86a5380910..fb28d6e8c43 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -42,6 +42,7 @@ export default RecordArray.extend({ @private */ loadRecords(records, payload) { + let token = heimdall.start('AdapterPopulatedRecordArray.loadRecords'); //TODO Optimize var internalModels = Ember.A(records).mapBy('_internalModel'); this.setProperties({ @@ -61,5 +62,6 @@ export default RecordArray.extend({ // TODO: should triggering didLoad event be the last action of the runLoop? Ember.run.once(this, 'trigger', 'didLoad'); + heimdall.stop(token); } }); diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index ce3f106bc71..f9fe7794b40 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -1,8 +1,58 @@ +/* global heimdall */ import Ember from 'ember'; import { assert, warn } from "ember-data/-private/debug"; import OrderedSet from "ember-data/-private/system/ordered-set"; +const { + newRelationship, + updateMeta, + clear, + removeRecords, + addRecords, + addCanonicalRecords, + addCanonicalRecord, + removeCanonicalRecords, + removeCanonicalRecord, + addRecord, + removeRecord, + removeRecordFromInverse, + removeRecordFromOwn, + removeCanonicalRecordFromInverse, + removeCanonicalRecordFromOwn, + flushCanonical, + flushCanonicalLater, + updateLink, + findLink, + updateRecordsFromAdapter, + setHasData, + setHasLoaded +} = heimdall.registerMonitor('system.relationships.state.relationship', + 'newRelationship', + 'updateMeta', + 'clear', + 'removeRecords', + 'addRecords', + 'addCanonicalRecords', + 'addCanonicalRecord', + 'removeCanonicalRecords', + 'removeCanonicalRecord', + 'addRecord', + 'removeRecord', + 'removeRecordFromInverse', + 'removeRecordFromOwn', + 'removeCanonicalRecordFromInverse', + 'removeCanonicalRecordFromOwn', + 'flushCanonical', + 'flushCanonicalLater', + 'updateLink', + 'findLink', + 'updateRecordsFromAdapter', + 'setHasData', + 'setHasLoaded' +); + export default function Relationship(store, record, inverseKey, relationshipMeta) { + heimdall.increment(newRelationship); var async = relationshipMeta.options.async; this.members = new OrderedSet(); this.canonicalMembers = new OrderedSet(); @@ -27,10 +77,12 @@ Relationship.prototype = { destroy: Ember.K, updateMeta(meta) { + heimdall.increment(updateMeta); this.meta = meta; }, clear() { + heimdall.increment(clear); var members = this.members.list; var member; @@ -41,10 +93,12 @@ Relationship.prototype = { }, removeRecords(records) { + heimdall.increment(removeRecords); records.forEach((record) => this.removeRecord(record)); }, addRecords(records, idx) { + heimdall.increment(addRecords); records.forEach((record) => { this.addRecord(record, idx); if (idx !== undefined) { @@ -54,6 +108,7 @@ Relationship.prototype = { }, addCanonicalRecords(records, idx) { + heimdall.increment(addCanonicalRecords); for (var i=0; i { + pA.finally(() => { heimdall.stop(token); }); + }); + return pA; }, /** @@ -1355,9 +1403,17 @@ Store = Service.extend({ findAll(modelName, options) { assert("You need to pass a model name to the store's findAll method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + let token = heimdall.start('store.findAll'); + var typeClass = this.modelFor(modelName); - return this._fetchAll(typeClass, this.peekAll(modelName), options); + let fetch = this._fetchAll(typeClass, this.peekAll(modelName), options); + + instrument(() => { + fetch.finally(() => { heimdall.stop(token); }); + }); + + return fetch; }, /** @@ -1404,6 +1460,7 @@ Store = Service.extend({ @private */ didUpdateAll(typeClass) { + heimdall.increment(didUpdateAll); var liveRecordArray = this.recordArrayManager.liveRecordArrayFor(typeClass); set(liveRecordArray, 'isUpdating', false); }, @@ -1433,6 +1490,7 @@ Store = Service.extend({ @return {DS.RecordArray} */ peekAll(modelName) { + heimdall.increment(peekAll); assert("You need to pass a model name to the store's peekAll method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var typeClass = this.modelFor(modelName); @@ -1761,12 +1819,14 @@ Store = Service.extend({ @return {Object} typeMap */ typeMapFor(typeClass) { + heimdall.increment(typeMapFor); var typeMaps = get(this, 'typeMaps'); var guid = Ember.guidFor(typeClass); var typeMap = typeMaps[guid]; if (typeMap) { return typeMap; } + heimdall.increment(typeMapFor_allocate); typeMap = { idToRecord: new EmptyObject(), records: [], @@ -1792,6 +1852,7 @@ Store = Service.extend({ @param {Object} data */ _load(data) { + heimdall.increment(_load); var internalModel = this._internalModelForId(data.type, data.id); internalModel.setupData(data); @@ -1818,6 +1879,7 @@ Store = Service.extend({ */ _modelForMixin(modelName) { + heimdall.increment(_modelForMixin); var normalizedModelName = normalizeModelName(modelName); // container.registry = 2.1 // container._registry = 1.11 - 2.0 @@ -1851,6 +1913,7 @@ Store = Service.extend({ @return {DS.Model} */ modelFor(modelName) { + heimdall.increment(modelFor); assert("You need to pass a model name to the store's modelFor method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); @@ -1868,6 +1931,7 @@ Store = Service.extend({ }, modelFactoryFor(modelName) { + heimdall.increment(modelFactoryFor); assert("You need to pass a model name to the store's modelFactoryFor method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); var normalizedKey = normalizeModelName(modelName); @@ -2028,6 +2092,7 @@ Store = Service.extend({ updated. */ push(data) { + let token = heimdall.start('store.push'); var included = data.included; var i, length; if (included) { @@ -2042,10 +2107,12 @@ Store = Service.extend({ for (i = 0; i < length; i++) { internalModels[i] = this._pushInternalModel(data.data[i]).getRecord(); } + heimdall.stop(token); return internalModels; } if (data.data === null) { + heimdall.stop(token); return null; } @@ -2053,7 +2120,9 @@ Store = Service.extend({ var internalModel = this._pushInternalModel(data.data); - return internalModel.getRecord(); + var record = internalModel.getRecord(); + heimdall.stop(token); + return record; }, _hasModelFor(type) { @@ -2061,6 +2130,7 @@ Store = Service.extend({ }, _pushInternalModel(data) { + heimdall.increment(_pushInternalModel); var modelName = data.type; assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id !== null && data.id !== undefined && data.id !== ''); assert(`You tried to push data with a type '${modelName}' but no model could be found with that name.`, this._hasModelFor(modelName)); @@ -2099,6 +2169,7 @@ Store = Service.extend({ }, _setupRelationships(record, data) { + heimdall.increment(_setupRelationships); // This will convert relationships specified as IDs into DS.Model instances // (possibly unloaded) and also create the data structures used to track // relationships. @@ -2199,6 +2270,7 @@ Store = Service.extend({ @return {Object} The normalized payload */ normalize(modelName, payload) { + heimdall.increment(normalize); assert("You need to pass a model name to the store's normalize method", isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); var serializer = this.serializerFor(modelName); @@ -2218,6 +2290,7 @@ Store = Service.extend({ @return {InternalModel} internal model */ buildInternalModel(type, id, data) { + heimdall.increment(buildInternalModel); var typeMap = this.typeMapFor(type); var idToRecord = typeMap.idToRecord; @@ -2293,6 +2366,7 @@ Store = Service.extend({ @return DS.Adapter */ adapterFor(modelName) { + heimdall.increment(adapterFor); assert("You need to pass a model name to the store's adapterFor method", isPresent(modelName)); assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); @@ -2329,6 +2403,7 @@ Store = Service.extend({ @return {DS.Serializer} */ serializerFor(modelName) { + heimdall.increment(serializerFor); assert("You need to pass a model name to the store's serializerFor method", isPresent(modelName)); assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); @@ -2358,6 +2433,7 @@ Store = Service.extend({ @return {Ember.Object} */ retrieveManagedInstance(type, modelName, fallbacks) { + heimdall.increment(retrieveManagedInstance); var normalizedModelName = normalizeModelName(modelName); var instance = this._instanceCache.get(type, normalizedModelName, fallbacks); diff --git a/addon/-private/system/store/common.js b/addon/-private/system/store/common.js index 4e06691061c..92d61d24e32 100644 --- a/addon/-private/system/store/common.js +++ b/addon/-private/system/store/common.js @@ -2,7 +2,18 @@ import Ember from 'ember'; var get = Ember.get; +const { + __bind, + __guard, + __objectIsAlive +} = heimdall.registerMonitor('system.store.common', + '_bind', + '_guard', + '_objectIsAlive' +); + export function _bind(fn) { + heimdall.increment(__bind); var args = Array.prototype.slice.call(arguments, 1); return function() { @@ -11,6 +22,7 @@ export function _bind(fn) { } export function _guard(promise, test) { + heimdall.increment(__guard); var guarded = promise['finally'](function() { if (!test()) { guarded._subscribers.length = 0; @@ -21,5 +33,6 @@ export function _guard(promise, test) { } export function _objectIsAlive(object) { + heimdall.increment(__objectIsAlive); return !(get(object, "isDestroyed") || get(object, "isDestroying")); } diff --git a/addon/-private/system/store/container-instance-cache.js b/addon/-private/system/store/container-instance-cache.js index 5cf5e41bdcf..a5127af3238 100644 --- a/addon/-private/system/store/container-instance-cache.js +++ b/addon/-private/system/store/container-instance-cache.js @@ -1,3 +1,4 @@ +/* global heimdall */ import Ember from 'ember'; import EmptyObject from "ember-data/-private/system/empty-object"; const assign = Ember.assign || Ember.merge; @@ -25,10 +26,19 @@ export default function ContainerInstanceCache(owner) { this._cache = new EmptyObject(); } +const { + __get, + instanceFor +} = heimdall.registerMonitor('system.store.container-instance-cache', + 'get', + 'instanceFor' +); + ContainerInstanceCache.prototype = new EmptyObject(); assign(ContainerInstanceCache.prototype, { get(type, preferredKey, fallbacks) { + heimdall.increment(__get); let cache = this._cache; let preferredLookupKey = `${type}:${preferredKey}`; @@ -54,6 +64,7 @@ assign(ContainerInstanceCache.prototype, { }, instanceFor(key) { + heimdall.increment(instanceFor); let cache = this._cache; if (!cache[key]) { let instance = this._owner.lookup(key); diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 99146be067e..9d195657279 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -177,8 +177,8 @@ export function _query(adapter, store, typeClass, query, recordArray) { assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Array.isArray(records)); recordArray.loadRecords(records, payload); - return recordArray; + return recordArray; }, null, "DS: Extract payload of query " + typeClass); } diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index e564ce665bf..d9c05921484 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -1,3 +1,4 @@ +/* global heimdall */ /** @module ember-data */ @@ -5,7 +6,7 @@ import Ember from 'ember'; import RESTAdapter from "ember-data/adapters/rest"; import isEnabled from 'ember-data/-private/features'; -import { deprecate } from 'ember-data/-private/debug'; +import { instrument, deprecate } from 'ember-data/-private/debug'; /** @since 1.13.0 @@ -32,6 +33,22 @@ var JSONAPIAdapter = RESTAdapter.extend({ hash.contentType = 'application/vnd.api+json'; } + instrument(function() { + hash.converters = { + 'text json': function(payload) { + let token = heimdall.start('json.parse'); + let json; + try { + json = Ember.$.parseJSON(payload); + } catch (e) { + json = payload; + } + heimdall.stop(token); + return json; + } + }; + }); + let beforeSend = hash.beforeSend; hash.beforeSend = function(xhr) { xhr.setRequestHeader('Accept', 'application/vnd.api+json'); diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 7ad5d7d8269..16e61302fe3 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1,3 +1,4 @@ +/* global heimdall */ /** @module ember-data */ @@ -17,7 +18,7 @@ import { } from 'ember-data/adapters/errors'; import BuildURLMixin from "ember-data/-private/adapters/build-url-mixin"; import isEnabled from 'ember-data/-private/features'; -import { runInDebug, warn, deprecate } from 'ember-data/-private/debug'; +import { instrument, runInDebug, warn, deprecate } from 'ember-data/-private/debug'; import parseResponseHeaders from 'ember-data/-private/utils/parse-response-headers'; const { @@ -996,6 +997,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ ajax(url, type, options) { + let token = heimdall.start('adapter.ajax'); var adapter = this; var requestData = { @@ -1007,11 +1009,13 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { var hash = adapter.ajaxOptions(url, type, options); hash.success = function(payload, textStatus, jqXHR) { + heimdall.stop(token); var response = ajaxSuccess(adapter, jqXHR, payload, requestData); Ember.run.join(null, resolve, response); }; hash.error = function(jqXHR, textStatus, errorThrown) { + heimdall.stop(token); var responseData = { textStatus, errorThrown @@ -1048,6 +1052,22 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { hash.dataType = 'json'; hash.context = this; + instrument(function() { + hash.converters = { + 'text json': function(payload) { + let token = heimdall.start('json.parse'); + let json; + try { + json = Ember.$.parseJSON(payload); + } catch (e) { + json = payload; + } + heimdall.stop(token); + return json; + } + }; + }); + if (hash.data && type !== 'GET') { hash.contentType = 'application/json; charset=utf-8'; hash.data = JSON.stringify(hash.data); @@ -1365,6 +1385,7 @@ if (isEnabled('ds-improved-ajax')) { * @return {Promise} promise */ _makeRequest(request) { + let token = heimdall.start('adapter._makeRequest'); const adapter = this; const hash = this._requestToJQueryAjaxHash(request); @@ -1374,11 +1395,13 @@ if (isEnabled('ds-improved-ajax')) { return new Ember.RSVP.Promise((resolve, reject) => { hash.success = function(payload, textStatus, jqXHR) { + heimdall.stop(token); var response = ajaxSuccess(adapter, jqXHR, payload, requestData); Ember.run.join(null, resolve, response); }; hash.error = function(jqXHR, textStatus, errorThrown) { + heimdall.stop(token); var responseData = { textStatus, errorThrown @@ -1387,6 +1410,22 @@ if (isEnabled('ds-improved-ajax')) { Ember.run.join(null, reject, error); }; + instrument(function() { + hash.converters = { + 'text json': function(payload) { + let token = heimdall.start('json.parse'); + let json; + try { + json = Ember.$.parseJSON(payload); + } catch (e) { + json = payload; + } + heimdall.stop(token); + return json; + } + }; + }); + adapter._ajaxRequest(hash); }, `DS: RESTAdapter#makeRequest: ${method} ${url}`); diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore new file mode 100644 index 00000000000..fbca2253799 --- /dev/null +++ b/benchmarks/.gitignore @@ -0,0 +1 @@ +results/ diff --git a/benchmarks/bash-analyze.js b/benchmarks/bash-analyze.js new file mode 100644 index 00000000000..99815744dd7 --- /dev/null +++ b/benchmarks/bash-analyze.js @@ -0,0 +1,8 @@ +const config = require('./config'); +const CACHE_DIR = process.argv[2] === '-c' ? process.argv[3] : '.'; +const path = require('path'); +const cachePath = path.join(__dirname, './results', CACHE_DIR); +const analyze = require('heimdall-query/analyze'); + +analyze(config, cachePath); + diff --git a/benchmarks/bash-run.js b/benchmarks/bash-run.js new file mode 100644 index 00000000000..215c43b0d01 --- /dev/null +++ b/benchmarks/bash-run.js @@ -0,0 +1,7 @@ +const config = require('./config'); +const CACHE_DIR = process.argv[2] === '-c' ? process.argv[3] : '.'; +const path = require('path'); +const cachePath = path.join(__dirname, './results', CACHE_DIR); +const run = require('heimdall-query/run'); + +run(config, cachePath); diff --git a/benchmarks/config.js b/benchmarks/config.js new file mode 100644 index 00000000000..ceab3faaedd --- /dev/null +++ b/benchmarks/config.js @@ -0,0 +1,78 @@ +module.exports = { + runs: 5, + domain: 'http://localhost:4200/', + slugs: [ + // simple returns a 1 simple record with no relationships per count in limit + + "query?modelName=complex&limit=100", // 1 total + // "query?modelName=simple&limit=2", // 2 total + // "query?modelName=simple&limit=34", // 34 total + // "query?modelName=simple&limit=119", // 119 total + // "query?modelName=simple&limit=238", // 238 total + + + // complex returns 7 total records of 3 model types per count in limit + // a primary record with 5 hasMany 1 belongsTo + + // "query?modelName=complex&limit=1", // 7 total + // "query?modelName=complex&limit=2", // 14 total + // "query?modelName=complex&limit=5", // 35 total + // "query?modelName=complex&limit=17", // 119 total + // "query?modelName=complex&limit=34", // 238 total + + + // heavy returns 17 total records of 5 model types per count in limit + // a primary record with + // - 5 hasMany with 1 belongsTo each + // - 1 belongsTo with 5 hasMany + + // "query?modelName=heavy&limit=1", // 17 total + // "query?modelName=heavy&limit=2", // 34 total + // "query?modelName=heavy&limit=7", // 119 total + // "query?modelName=heavy&limit=14" // 238 total + + ], + ignoreBranches: [ + // 'adapter._makeRequest', + // 'InternalModel._materializeRecord' + ], + stats: [ + { + key: "stats.self.selfTime", + name: 'Count', + rollup: false, + transform: function(t, c) { return c;} + }, + /* + { key: "stats.self.selfTime", name: 'Self Time', rollup: false }, + { key: "stats.self.selfTime", name: 'Total Time', rollup: true }, + */ + { + key: "stats.self.duration", + name: 'Duration', + rollup: false, + transform: function(t) { + return `${(t / 1e6).toFixed(2)}ms`; + } + }, + // { key: "stats.store.modelFor", name: 'modelFor', transform: function(t, c) { console.log(t); return t; }, rollup: false }, + // { key: "stats.store.modelFactoryFor", name: 'modelFactoryFor', account: 0.00025, rollup: false }, + { key: "stats.self.selfTime", name: 'Self Time', account: 0, rollup: false }, + { key: "stats.self.selfTime", name: 'Total Time', account: 0, rollup: true }, + /* + { + key: "stats.self.selfTime", + name: 'Throughput', + rollup: false, + account: 0.00025, + transform: function(t, c) { return `${(c / (t / 1e6)).toFixed(2)} ops/ms`;} + } + */ + ], + "browser": "chrome", + "name": "Performance Analysis", + "compressAfter": 10, + "maxDepth": 25, + "collapseByName": true, + "finderPath": "ember-data" +}; diff --git a/benchmarks/index.js b/benchmarks/index.js new file mode 100644 index 00000000000..c3eaaaca258 --- /dev/null +++ b/benchmarks/index.js @@ -0,0 +1,7 @@ +const config = require('./config'); +const CACHE_DIR = process.argv[2] === '-c' ? process.argv[3] : '.'; +const path = require('path'); +const cachePath = path.join(__dirname, './results', CACHE_DIR); +const run = require('heimdall-query'); + +run(config, cachePath); diff --git a/tests/dummy/app/components/.gitkeep b/benchmarks/results/development-stripped/.gitkeep similarity index 100% rename from tests/dummy/app/components/.gitkeep rename to benchmarks/results/development-stripped/.gitkeep diff --git a/tests/dummy/app/controllers/.gitkeep b/benchmarks/results/development/.gitkeep similarity index 100% rename from tests/dummy/app/controllers/.gitkeep rename to benchmarks/results/development/.gitkeep diff --git a/tests/dummy/app/templates/components/.gitkeep b/benchmarks/results/production-stripped/.gitkeep similarity index 100% rename from tests/dummy/app/templates/components/.gitkeep rename to benchmarks/results/production-stripped/.gitkeep diff --git a/benchmarks/results/production/.gitkeep b/benchmarks/results/production/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ember-cli-build.js b/ember-cli-build.js index 55ec56292ba..f2d8fddc098 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -1,14 +1,19 @@ /* eslint-env node */ -var EmberApp = require('ember-cli/lib/broccoli/ember-addon'); +var EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); var merge = require('broccoli-merge-trees'); +var Funnel = require('broccoli-funnel'); var globals = require('./lib/globals'); var yuidoc = require('./lib/yuidoc'); module.exports = function(defaults) { - var app = new EmberApp(defaults, { - // Add options here + var app = new EmberAddon(defaults); + var heimdallTree = new Funnel('node_modules/heimdalljs', { + destDir: 'heimdalljs' }); + app.trees.vendor = merge([app.trees.vendor, heimdallTree]); + app.import('vendor/heimdalljs/dist/heimdalljs.iife.js', { prepend: true }); + /* This build file specifies the options for the dummy test app of this addon, located in `/tests/dummy` diff --git a/lib/babel-build.js b/lib/babel-build.js index a66b5d49cc5..da3a2bbf968 100644 --- a/lib/babel-build.js +++ b/lib/babel-build.js @@ -42,4 +42,4 @@ module.exports = function(packageName, tree, _options) { var options = babelOptions(packageName, _options); return babel(tree, options); -} +}; diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 2d9a7d08128..c0440b5656b 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -2,6 +2,7 @@ var fs = require('fs'); var path = require('path'); var filterImports = require('babel-plugin-filter-imports'); var featureFlags = require('babel-plugin-feature-flags'); +var stripHeimdall = require('babel5-plugin-strip-heimdall'); module.exports = function(environment) { var featuresJsonPath = __dirname + '/../config/features.json'; @@ -36,7 +37,26 @@ module.exports = function(environment) { 'warn', 'debugSeal' ] - }) + }), + // comment out when running non-baseline production benchmarks + // WARNING do not ever commit the commented out version! + stripHeimdall + ); + } + + if (environment === 'development') { + // uncomment when running baseline development benchmarks + // plugins.push(stripHeimdall); + } + + if (environment === 'test') { + plugins.push( + filterImports({ + 'ember-data/-private/debug': [ + 'instrument' + ] + }), + stripHeimdall ); } diff --git a/package.json b/package.json index 317f3add0bf..0897c9050b7 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "amd-name-resolver": "0.0.5", "babel-plugin-feature-flags": "^0.2.1", "babel-plugin-filter-imports": "^0.2.0", + "babel5-plugin-strip-heimdall": "^5.0.2", "broccoli-babel-transpiler": "^5.5.0", "broccoli-file-creator": "^1.0.0", "broccoli-merge-trees": "^1.0.0", @@ -77,11 +78,16 @@ "ember-publisher": "0.0.7", "ember-resolver": "^2.0.3", "ember-watson": "^0.7.0", + "express": "^4.14.0", "github": "^0.2.4", "glob": "5.0.13", + "heimdalljs": "~0.3.0-alpha3", + "heimdall-query": "^0.0.4", + "json-api-mock-server": "0.0.2", "mocha": "2.4.5", "mocha-only-detector": "0.0.2", "phantomjs-prebuilt": "^2.1.12", + "morgan": "^1.7.0", "pretender": "1.0.0", "rimraf": "2.5.2", "rsvp": "3.2.1", diff --git a/server/.jshintrc b/server/.jshintrc new file mode 100644 index 00000000000..c1f2978bcf7 --- /dev/null +++ b/server/.jshintrc @@ -0,0 +1,3 @@ +{ + "node": true +} diff --git a/server/index.js b/server/index.js new file mode 100644 index 00000000000..b90b6ec2f61 --- /dev/null +++ b/server/index.js @@ -0,0 +1,14 @@ +/* jshint node:true */ +var mountEndpoints = require('json-api-mock-server'); +var path = require('path'); + +module.exports = function(app, project) { + var configPath = path.join(project.project.root, project.project.configPath()); + var config = require(configPath)(project.environment).mockServer || {}; + + // Log proxy requests + var morgan = require('morgan'); + app.use(morgan('dev')); + + mountEndpoints(app, config); +}; diff --git a/tests/.eslintrc.js b/tests/.eslintrc.js index 8520ae6310b..3a43edc6e04 100644 --- a/tests/.eslintrc.js +++ b/tests/.eslintrc.js @@ -3,4 +3,7 @@ module.exports = { rules: { 'no-console': 0 }, + globals: { + 'heimdall': true + } }; diff --git a/tests/dummy/app/adapters/application.js b/tests/dummy/app/adapters/application.js new file mode 100644 index 00000000000..f1b1ab1ea42 --- /dev/null +++ b/tests/dummy/app/adapters/application.js @@ -0,0 +1,5 @@ +import DS from 'ember-data'; + +export default DS.JSONAPIAdapter.extend({ + namespace: 'api' +}); diff --git a/tests/dummy/app/helpers/reopen-instrumentation.js b/tests/dummy/app/helpers/reopen-instrumentation.js new file mode 100644 index 00000000000..f037e5b0e9a --- /dev/null +++ b/tests/dummy/app/helpers/reopen-instrumentation.js @@ -0,0 +1,51 @@ +/* global heimdall */ +import Ember from 'ember'; +import DS from "ember-data"; + +const { + Model +} = DS; + +const { + Object: Obj +} = Ember; + +export default function instrumentBaseObjects(owner) { + const [__a, __b] = heimdall.registerMonitor('owner', 'lookup', '_lookupFactory'); + let originalLookup = owner.lookup; + let originalLookupFactory = owner._lookupFactory; + + owner.lookup = function lookup() { + heimdall.increment(__a); + return originalLookup.apply(this, arguments); + }; + + owner._lookupFactory = function _lookupFactory() { + heimdall.increment(__b); + return originalLookupFactory.apply(this, arguments); + }; + + const [__c] = heimdall.registerMonitor('reopened-model', '_create'); + const [__d, __e] = heimdall.registerMonitor('reopened-object', 'create', 'extend'); + let originalModelCreate = Model._create; + let originalCreate = Obj.create; + let originalExtend = Obj.extend; + + Model.reopenClass({ + _create() { + heimdall.increment(__c); + return originalModelCreate.apply(this, arguments); + } + }); + + Obj.reopenClass({ + create() { + heimdall.increment(__d); + return originalCreate.apply(this, arguments); + }, + extend() { + heimdall.increment(__e); + return originalExtend.apply(this, arguments); + } + }); +} diff --git a/tests/dummy/app/models/baz.js b/tests/dummy/app/models/baz.js new file mode 100644 index 00000000000..fbb4ff990fb --- /dev/null +++ b/tests/dummy/app/models/baz.js @@ -0,0 +1,14 @@ +import DS from 'ember-data'; + +const { + attr, + belongsTo, + Model +} = DS; + +export default Model.extend({ + name: attr(), + description: attr(), + complex: belongsTo('complex', { inverse: 'baz', async: false }), + heavyFoo: belongsTo('heavy-foo', { inverse: 'heavyBaz', async: false }) +}); diff --git a/tests/dummy/app/models/complex.js b/tests/dummy/app/models/complex.js new file mode 100644 index 00000000000..d217eb5f34f --- /dev/null +++ b/tests/dummy/app/models/complex.js @@ -0,0 +1,15 @@ +import DS from 'ember-data'; + +const { + attr, + belongsTo, + hasMany, + Model +} = DS; + +export default Model.extend({ + name: attr(), + description: attr(), + baz: belongsTo('baz', { inverse: 'complex', async: false }), + foos: hasMany('foo', { inverse: 'complex', async: false }) +}); diff --git a/tests/dummy/app/models/foo.js b/tests/dummy/app/models/foo.js new file mode 100644 index 00000000000..75d7b269f81 --- /dev/null +++ b/tests/dummy/app/models/foo.js @@ -0,0 +1,14 @@ +import DS from 'ember-data'; + +const { + attr, + belongsTo, + Model +} = DS; + +export default Model.extend({ + name: attr(), + description: attr(), + complex: belongsTo('complex', { inverse: 'foos', async: false }), + heavyBaz: belongsTo('heavy-baz', { inverse: 'foos', async: false }) +}); diff --git a/tests/dummy/app/models/heavy-baz.js b/tests/dummy/app/models/heavy-baz.js new file mode 100644 index 00000000000..0c1c3facc06 --- /dev/null +++ b/tests/dummy/app/models/heavy-baz.js @@ -0,0 +1,15 @@ +import DS from 'ember-data'; + +const { + attr, + belongsTo, + hasMany, + Model +} = DS; + +export default Model.extend({ + name: attr(), + description: attr(), + heavy: belongsTo('heavy', { inverse: 'heavyBaz', async: false }), + foos: hasMany('foo', { inverse: 'heavyBaz', async: false}) +}); diff --git a/tests/dummy/app/models/heavy-foo.js b/tests/dummy/app/models/heavy-foo.js new file mode 100644 index 00000000000..3e152ada5bb --- /dev/null +++ b/tests/dummy/app/models/heavy-foo.js @@ -0,0 +1,14 @@ +import DS from 'ember-data'; + +const { + attr, + belongsTo, + Model +} = DS; + +export default Model.extend({ + name: attr(), + description: attr(), + heavy: belongsTo('heavy', { inverse: 'heavyFoos', async: false }), + baz: belongsTo('baz', { inverse: 'heavyFoo', async: false }) +}); diff --git a/tests/dummy/app/models/heavy.js b/tests/dummy/app/models/heavy.js new file mode 100644 index 00000000000..9d937ef9180 --- /dev/null +++ b/tests/dummy/app/models/heavy.js @@ -0,0 +1,15 @@ +import DS from 'ember-data'; + +const { + attr, + belongsTo, + hasMany, + Model +} = DS; + +export default Model.extend({ + name: attr(), + description: attr(), + heavyBaz: belongsTo('heavy-baz', { inverse: 'heavy', async: false }), + heavyFoos: hasMany('heavy-foo', { inverse: 'heavy', async: false }) +}); diff --git a/tests/dummy/app/models/simple.js b/tests/dummy/app/models/simple.js new file mode 100644 index 00000000000..f8181b0c38a --- /dev/null +++ b/tests/dummy/app/models/simple.js @@ -0,0 +1,11 @@ +import DS from 'ember-data'; + +const { + Model, + attr +} = DS; + +export default Model.extend({ + title: attr(), + description: attr() +}); diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js index cdc257875f7..206b248415f 100644 --- a/tests/dummy/app/router.js +++ b/tests/dummy/app/router.js @@ -7,6 +7,7 @@ const Router = Ember.Router.extend({ }); Router.map(function() { + this.route('query'); }); export default Router; diff --git a/tests/dummy/app/routes/application/route.js b/tests/dummy/app/routes/application/route.js new file mode 100644 index 00000000000..26d9f3124ec --- /dev/null +++ b/tests/dummy/app/routes/application/route.js @@ -0,0 +1,4 @@ +import Ember from 'ember'; + +export default Ember.Route.extend({ +}); diff --git a/tests/dummy/app/routes/application/template.hbs b/tests/dummy/app/routes/application/template.hbs new file mode 100644 index 00000000000..cecd031c69b --- /dev/null +++ b/tests/dummy/app/routes/application/template.hbs @@ -0,0 +1,2 @@ +

      Ember Data Performance Test Suite

      +{{outlet}} diff --git a/tests/dummy/app/routes/components/.gitkeep b/tests/dummy/app/routes/components/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/dummy/app/routes/index/route.js b/tests/dummy/app/routes/index/route.js new file mode 100644 index 00000000000..26d9f3124ec --- /dev/null +++ b/tests/dummy/app/routes/index/route.js @@ -0,0 +1,4 @@ +import Ember from 'ember'; + +export default Ember.Route.extend({ +}); diff --git a/tests/dummy/app/routes/index/template.hbs b/tests/dummy/app/routes/index/template.hbs new file mode 100644 index 00000000000..f1b8bec2631 --- /dev/null +++ b/tests/dummy/app/routes/index/template.hbs @@ -0,0 +1,5 @@ +
        +
      • + {{#link-to 'query'}}Query{{/link-to}} +
      • +
      \ No newline at end of file diff --git a/tests/dummy/app/routes/query/controller.js b/tests/dummy/app/routes/query/controller.js new file mode 100644 index 00000000000..c182a851873 --- /dev/null +++ b/tests/dummy/app/routes/query/controller.js @@ -0,0 +1,11 @@ +import Ember from 'ember'; + +const { + Controller +} = Ember; + +export default Controller.extend({ + queryParams: ['limit', 'modelName'], + limit: 240, + modelName: 'simple' +}); diff --git a/tests/dummy/app/routes/query/route.js b/tests/dummy/app/routes/query/route.js new file mode 100644 index 00000000000..7e035ba2542 --- /dev/null +++ b/tests/dummy/app/routes/query/route.js @@ -0,0 +1,43 @@ +/* global window, heimdall, console */ +import Ember from 'ember'; +import instrumentBaseObjects from '../../helpers/reopen-instrumentation'; +import config from 'dummy/config/environment'; + +const { + getOwner, + Route +} = Ember; + +let HAS_INSTRUMENTED = false; + +export default Route.extend({ + + queryParams: { + limit: { + refreshModel: true + }, + modelName: { + refreshModel: true + } + }, + + model(params) { + // switch this to 'production' when generating production build baselines + if (config.environment === 'development' && !HAS_INSTRUMENTED) { + instrumentBaseObjects(getOwner(this)); + HAS_INSTRUMENTED = true; + } + + let modelName = params.modelName; + delete params.modelName; + + let token = heimdall.start('ember-data'); + return this.get('store').query(modelName, params) + .then((records) => { + heimdall.stop(token); + window.result = heimdall.toString(); + + return records; + }); + } +}); diff --git a/tests/dummy/app/routes/query/template.hbs b/tests/dummy/app/routes/query/template.hbs new file mode 100644 index 00000000000..31a48f866bf --- /dev/null +++ b/tests/dummy/app/routes/query/template.hbs @@ -0,0 +1 @@ +

      Test Complete

      \ No newline at end of file diff --git a/tests/dummy/app/templates/.gitkeep b/tests/dummy/app/templates/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/dummy/app/templates/application.hbs b/tests/dummy/app/templates/application.hbs deleted file mode 100644 index f8bc38e7b6a..00000000000 --- a/tests/dummy/app/templates/application.hbs +++ /dev/null @@ -1,3 +0,0 @@ -

      Welcome to Ember

      - -{{outlet}} diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index 28558b13154..cf10d93440f 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -9,12 +9,13 @@ var featureFlags = JSON.parse(featuresJson); module.exports = function(environment) { var ENV = { modulePrefix: 'dummy', + podModulePrefix: 'dummy/routes', environment: environment, rootURL: '/', locationType: 'auto', EmberENV: { FEATURES: featureFlags, - ENABLE_DS_FILTER: true, + ENABLE_DS_FILTER: true // don't raise on deprecation yet, since there are too many thrown errors; // this should be addressed in another PR diff --git a/vendor/.gitkeep b/vendor/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d From 5b046bad78bbf4adbad5c18dcdd1936668ae2189 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 16 Sep 2016 15:55:00 -0700 Subject: [PATCH 1599/2527] fix benchmarking for latest ember-cli --- addon/-private/system/store.js | 2 +- benchmarks/config.js | 12 ++++++------ server/index.js | 3 +-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index f00c16af274..ca328b18011 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -4,7 +4,7 @@ import Ember from 'ember'; import Model from 'ember-data/model'; -import { assert, warn, runInDebug } from "ember-data/-private/debug"; +import { instrument, assert, warn, runInDebug } from "ember-data/-private/debug"; import _normalizeLink from "ember-data/-private/system/normalize-link"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; import { diff --git a/benchmarks/config.js b/benchmarks/config.js index ceab3faaedd..ee53474de8c 100644 --- a/benchmarks/config.js +++ b/benchmarks/config.js @@ -1,14 +1,14 @@ module.exports = { - runs: 5, + runs: 1, domain: 'http://localhost:4200/', slugs: [ // simple returns a 1 simple record with no relationships per count in limit - "query?modelName=complex&limit=100", // 1 total + // "query?modelName=simple&limit=1", // 1 total // "query?modelName=simple&limit=2", // 2 total // "query?modelName=simple&limit=34", // 34 total // "query?modelName=simple&limit=119", // 119 total - // "query?modelName=simple&limit=238", // 238 total + "query?modelName=simple&limit=238", // 238 total // complex returns 7 total records of 3 model types per count in limit @@ -18,7 +18,7 @@ module.exports = { // "query?modelName=complex&limit=2", // 14 total // "query?modelName=complex&limit=5", // 35 total // "query?modelName=complex&limit=17", // 119 total - // "query?modelName=complex&limit=34", // 238 total + "query?modelName=complex&limit=34", // 238 total // heavy returns 17 total records of 5 model types per count in limit @@ -29,11 +29,11 @@ module.exports = { // "query?modelName=heavy&limit=1", // 17 total // "query?modelName=heavy&limit=2", // 34 total // "query?modelName=heavy&limit=7", // 119 total - // "query?modelName=heavy&limit=14" // 238 total + "query?modelName=heavy&limit=14" // 238 total ], ignoreBranches: [ - // 'adapter._makeRequest', + 'adapter._makeRequest', // 'InternalModel._materializeRecord' ], stats: [ diff --git a/server/index.js b/server/index.js index b90b6ec2f61..9a758f9bf21 100644 --- a/server/index.js +++ b/server/index.js @@ -1,9 +1,8 @@ /* jshint node:true */ var mountEndpoints = require('json-api-mock-server'); -var path = require('path'); module.exports = function(app, project) { - var configPath = path.join(project.project.root, project.project.configPath()); + var configPath = project.project.configPath(); var config = require(configPath)(project.environment).mockServer || {}; // Log proxy requests From 86bb1d0f419f14043d2ea0e5cf93d5ad186ea42c Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 20 Sep 2016 11:44:11 -0700 Subject: [PATCH 1600/2527] safer toggling of instrumentation --- index.js | 12 ++++++++++++ lib/stripped-build-plugins.js | 17 ++++++----------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/index.js b/index.js index a64b61301b8..1b484898905 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,18 @@ var path = require('path'); var SilentError = require('silent-error'); +// allow toggling of heimdall instrumentation +var INSTRUMENT_HEIMDALL = false; +var args = process.argv; + +for (var i = 0; i < args.length; i++) { + if (args[i] === '--instrument') { + INSTRUMENT_HEIMDALL = true; + break; + } +} +process.env.INSTRUMENT_HEIMDALL = INSTRUMENT_HEIMDALL; + function add(options, name, array) { var option = options[name] = options[name] || []; option.push.apply(option, array); diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index c0440b5656b..67cb83afb50 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -24,6 +24,10 @@ module.exports = function(environment) { }) ]; + if (process.env.INSTRUMENT_HEIMDALL === false) { + plugins.push(stripHeimdall) + } + if (environment === 'production') { plugins.push( filterImports({ @@ -37,26 +41,17 @@ module.exports = function(environment) { 'warn', 'debugSeal' ] - }), - // comment out when running non-baseline production benchmarks - // WARNING do not ever commit the commented out version! - stripHeimdall + }) ); } - if (environment === 'development') { - // uncomment when running baseline development benchmarks - // plugins.push(stripHeimdall); - } - if (environment === 'test') { plugins.push( filterImports({ 'ember-data/-private/debug': [ 'instrument' ] - }), - stripHeimdall + }) ); } From e390bd93be1e997fe766c253731ac7fc234c4da3 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 20 Sep 2016 11:54:06 -0700 Subject: [PATCH 1601/2527] adds note on benchmarking to the readme --- CONTRIBUTING.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 25ea22e4e57..73da5c282c3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -110,6 +110,27 @@ production builds automatically. Be sure to leave a description of the feature and possible example of how to use it (if necessary). +## Benchmarking + +Ember Data is instrumented with [heimdalljs](https://github.com/heimdalljs/heimdalljs-lib) + Top level scenarios for benchmarking are available via the `query` route in + the dummy app, and desired scenarios to be run can be configured via `benchmarks/config.js`. + + The scenarios are configured to interop with [heimdall-query](https://github.com/heimdalljs/heimdall-query) + for analysis. To run scenarios: + + 1. Start the dummy app with instrumentation on: `ember s --instrument` + + 2. Configure `benchmarks/config.js` with desired scenarios + + 3. To run both the benchmarks and the analysis: `node ./benchmarks` + + a.) To just collect data (no analysis): `node ./benchmarks/bash-run.js` + b.) To just run analysis (w/cached data): `node ./benchmarks/bash-analyze.js` + c.) To cache a data set or use a cached data set, all commands accept `-c ./path/to/cache/dir` + + 4. Do not commit cached data results, these should be git ignored already. + # Pull Requests We love pull requests. Here's a quick guide: From e8f425d6c4d33369160eb470c7ff50326a9f746d Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 20 Sep 2016 14:51:30 -0700 Subject: [PATCH 1602/2527] improve benchmarks and instrumentation --- addon/-private/debug.js | 4 ++-- benchmarks/bash-analyze.js | 2 +- benchmarks/bash-run.js | 2 +- benchmarks/config.js | 9 ++++++--- ember-cli-build.js | 13 ++++++++++++- lib/stripped-build-plugins.js | 19 ++++++++----------- package.json | 1 + 7 files changed, 31 insertions(+), 19 deletions(-) diff --git a/addon/-private/debug.js b/addon/-private/debug.js index 952dfd2f20d..d3a503b8d1e 100644 --- a/addon/-private/debug.js +++ b/addon/-private/debug.js @@ -20,8 +20,8 @@ export function runInDebug() { return Ember.runInDebug(...arguments); } -export function instrument() { - return Ember.runInDebug(...arguments); +export function instrument(method) { + return method(); } export function warn() { diff --git a/benchmarks/bash-analyze.js b/benchmarks/bash-analyze.js index 99815744dd7..30b95ae6f4d 100644 --- a/benchmarks/bash-analyze.js +++ b/benchmarks/bash-analyze.js @@ -2,7 +2,7 @@ const config = require('./config'); const CACHE_DIR = process.argv[2] === '-c' ? process.argv[3] : '.'; const path = require('path'); const cachePath = path.join(__dirname, './results', CACHE_DIR); -const analyze = require('heimdall-query/analyze'); +const analyze = require('heimdall-query/src/analyze'); analyze(config, cachePath); diff --git a/benchmarks/bash-run.js b/benchmarks/bash-run.js index 215c43b0d01..949bceddb24 100644 --- a/benchmarks/bash-run.js +++ b/benchmarks/bash-run.js @@ -2,6 +2,6 @@ const config = require('./config'); const CACHE_DIR = process.argv[2] === '-c' ? process.argv[3] : '.'; const path = require('path'); const cachePath = path.join(__dirname, './results', CACHE_DIR); -const run = require('heimdall-query/run'); +const run = require('heimdall-query/src/run'); run(config, cachePath); diff --git a/benchmarks/config.js b/benchmarks/config.js index ee53474de8c..d412a981008 100644 --- a/benchmarks/config.js +++ b/benchmarks/config.js @@ -1,5 +1,5 @@ module.exports = { - runs: 1, + runs: 5, domain: 'http://localhost:4200/', slugs: [ // simple returns a 1 simple record with no relationships per count in limit @@ -18,7 +18,7 @@ module.exports = { // "query?modelName=complex&limit=2", // 14 total // "query?modelName=complex&limit=5", // 35 total // "query?modelName=complex&limit=17", // 119 total - "query?modelName=complex&limit=34", // 238 total + // "query?modelName=complex&limit=34", // 238 total // heavy returns 17 total records of 5 model types per count in limit @@ -29,13 +29,16 @@ module.exports = { // "query?modelName=heavy&limit=1", // 17 total // "query?modelName=heavy&limit=2", // 34 total // "query?modelName=heavy&limit=7", // 119 total - "query?modelName=heavy&limit=14" // 238 total + // "query?modelName=heavy&limit=14" // 238 total ], ignoreBranches: [ 'adapter._makeRequest', // 'InternalModel._materializeRecord' ], + buckets: { + + }, stats: [ { key: "stats.self.selfTime", diff --git a/ember-cli-build.js b/ember-cli-build.js index f2d8fddc098..90580991e67 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -4,9 +4,18 @@ var merge = require('broccoli-merge-trees'); var Funnel = require('broccoli-funnel'); var globals = require('./lib/globals'); var yuidoc = require('./lib/yuidoc'); +var stripClassCallCheck = require('babel5-plugin-strip-class-callcheck'); +var path = require('path'); module.exports = function(defaults) { - var app = new EmberAddon(defaults); + var app = new EmberAddon(defaults, { + babel: { + plugins: [ + // while ember-data strips itself, ember does not currently + { transformer: stripClassCallCheck, position: 'after' } + ] + } + }); var heimdallTree = new Funnel('node_modules/heimdalljs', { destDir: 'heimdalljs' }); @@ -14,6 +23,8 @@ module.exports = function(defaults) { app.trees.vendor = merge([app.trees.vendor, heimdallTree]); app.import('vendor/heimdalljs/dist/heimdalljs.iife.js', { prepend: true }); + app.vendorFiles['ember.js'].development = path.join(app.bowerDirectory, 'ember/ember.prod.js'); + /* This build file specifies the options for the dummy test app of this addon, located in `/tests/dummy` diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 67cb83afb50..2c1b8bb3c1c 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -25,7 +25,14 @@ module.exports = function(environment) { ]; if (process.env.INSTRUMENT_HEIMDALL === false) { - plugins.push(stripHeimdall) + plugins.push( + stripHeimdall, + filterImports({ + 'ember-data/-private/debug': [ + 'instrument' + ] + }) + ); } if (environment === 'production') { @@ -45,15 +52,5 @@ module.exports = function(environment) { ); } - if (environment === 'test') { - plugins.push( - filterImports({ - 'ember-data/-private/debug': [ - 'instrument' - ] - }) - ); - } - return plugins; }; diff --git a/package.json b/package.json index 0897c9050b7..d984d45ed07 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "amd-name-resolver": "0.0.5", "babel-plugin-feature-flags": "^0.2.1", "babel-plugin-filter-imports": "^0.2.0", + "babel5-plugin-strip-class-callcheck": "^5.1.0", "babel5-plugin-strip-heimdall": "^5.0.2", "broccoli-babel-transpiler": "^5.5.0", "broccoli-file-creator": "^1.0.0", From bdf1ac96a03a97a552f3d7222ff5cd57cc7b4a5c Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 21 Sep 2016 14:05:10 -0700 Subject: [PATCH 1603/2527] bump dep --- benchmarks/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/config.js b/benchmarks/config.js index d412a981008..39c1462b2aa 100644 --- a/benchmarks/config.js +++ b/benchmarks/config.js @@ -1,5 +1,5 @@ module.exports = { - runs: 5, + runs: 35, domain: 'http://localhost:4200/', slugs: [ // simple returns a 1 simple record with no relationships per count in limit From 0c8022fad93386f39d98ad632718cdaa1b039416 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 22 Sep 2016 17:41:14 -0700 Subject: [PATCH 1604/2527] alphabetize counters --- addon/-private/system/model/internal-model.js | 24 +++---- addon/-private/system/record-array-manager.js | 56 ++++++++-------- .../relationships/state/relationship.js | 64 +++++++++---------- addon/-private/system/store.js | 40 ++++++------ 4 files changed, 92 insertions(+), 92 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index de74ba4a0a9..6cfab4699b6 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -46,29 +46,29 @@ function retrieveFromCurrentState(key) { // this (and all heimdall instrumentation) will be stripped by a babel transform // https://github.com/heimdalljs/babel5-plugin-strip-heimdall const { - new_InternalModel, - materializeRecord, - setupData, + _triggerDeferredTriggers, + changedAttributes, createSnapshot, flushChangedAttributes, hasChangedAttributes, - updateChangedAttributes, - changedAttributes, + materializeRecord, + new_InternalModel, send, + setupData, transitionTo, - _triggerDeferredTriggers + updateChangedAttributes } = heimdall.registerMonitor('InternalModel', - 'new_InternalModel', - 'materializeRecord', - 'setupData', + '_triggerDeferredTriggers', + 'changedAttributes', 'createSnapshot', 'flushChangedAttributes', 'hasChangedAttributes', - 'updateChangedAttributes', - 'changedAttributes', + 'materializeRecord', + 'new_InternalModel', 'send', + 'setupData', 'transitionTo', - '_triggerDeferredTriggers' + 'updateChangedAttributes' ); /* diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index cccbb69ce70..4c40c396de9 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -13,45 +13,45 @@ import OrderedSet from "ember-data/-private/system/ordered-set"; var get = Ember.get; const { + _addRecordToRecordArray, + _recordWasChanged, + _recordWasDeleted, + array_flatten, + array_remove, create, - recordDidChange, + createAdapterPopulatedRecordArray, + createFilteredRecordArray, + createRecordArray, + liveRecordArrayFor, + populateLiveRecordArray, recordArraysForRecord, - updateRecordArrays, - _recordWasDeleted, - _recordWasChanged, + recordDidChange, recordWasLoaded, - updateFilterRecordArray, - _addRecordToRecordArray, - populateLiveRecordArray, - updateFilter, - liveRecordArrayFor, - createRecordArray, - createFilteredRecordArray, - createAdapterPopulatedRecordArray, registerFilteredRecordArray, unregisterRecordArray, - array_flatten, - array_remove + updateFilter, + updateFilterRecordArray, + updateRecordArrays } = heimdall.registerMonitor('recordArrayManager', + '_addRecordToRecordArray', + '_recordWasChanged', + '_recordWasDeleted', + 'array_fatten', + 'array_remove', 'create', - 'recordDidChange', + 'createAdapterPopulatedRecordArray', + 'createFilteredRecordArray', + 'createRecordArray', + 'liveRecordArrayFor', + 'populateLiveRecordArray', 'recordArraysForRecord', - 'updateRecordArrays', - '_recordWasDeleted', - '_recordWasChanged', + 'recordDidChange', 'recordWasLoaded', - 'updateFilterRecordArray', - '_addRecordToRecordArray', - 'populateLiveRecordArray', - 'updateFilter', - 'liveRecordArrayFor', - 'createRecordArray', - 'createFilteredRecordArray', - 'createAdapterPopulatedRecordArray', 'registerFilteredRecordArray', 'unregisterRecordArray', - 'array_fatten', - 'array_remove' + 'updateFilter', + 'updateFilterRecordArray', + 'updateRecordArrays' ); /** diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index f9fe7794b40..9ba41caabb1 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -4,51 +4,51 @@ import { assert, warn } from "ember-data/-private/debug"; import OrderedSet from "ember-data/-private/system/ordered-set"; const { - newRelationship, - updateMeta, - clear, - removeRecords, - addRecords, - addCanonicalRecords, addCanonicalRecord, - removeCanonicalRecords, - removeCanonicalRecord, + addCanonicalRecords, addRecord, + addRecords, + clear, + findLink, + flushCanonical, + flushCanonicalLater, + newRelationship, + removeCanonicalRecord, + removeCanonicalRecordFromInverse, + removeCanonicalRecordFromOwn, + removeCanonicalRecords, removeRecord, removeRecordFromInverse, removeRecordFromOwn, - removeCanonicalRecordFromInverse, - removeCanonicalRecordFromOwn, - flushCanonical, - flushCanonicalLater, - updateLink, - findLink, - updateRecordsFromAdapter, + removeRecords, setHasData, - setHasLoaded + setHasLoaded, + updateLink, + updateMeta, + updateRecordsFromAdapter } = heimdall.registerMonitor('system.relationships.state.relationship', - 'newRelationship', - 'updateMeta', - 'clear', - 'removeRecords', - 'addRecords', - 'addCanonicalRecords', 'addCanonicalRecord', - 'removeCanonicalRecords', - 'removeCanonicalRecord', + 'addCanonicalRecords', 'addRecord', + 'addRecords', + 'clear', + 'findLink', + 'flushCanonical', + 'flushCanonicalLater', + 'newRelationship', + 'removeCanonicalRecord', + 'removeCanonicalRecordFromInverse', + 'removeCanonicalRecordFromOwn', + 'removeCanonicalRecords', 'removeRecord', 'removeRecordFromInverse', 'removeRecordFromOwn', - 'removeCanonicalRecordFromInverse', - 'removeCanonicalRecordFromOwn', - 'flushCanonical', - 'flushCanonicalLater', - 'updateLink', - 'findLink', - 'updateRecordsFromAdapter', + 'removeRecords', 'setHasData', - 'setHasLoaded' + 'setHasLoaded', + 'updateLink', + 'updateMeta', + 'updateRecordsFromAdapter' ); export default function Relationship(store, record, inverseKey, relationshipMeta) { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index ca328b18011..979aa7f33fe 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -96,42 +96,42 @@ const { Service } = Ember; const { _generateId, - peekRecord, _internalModelForId, - didUpdateAll, - peekAll, - typeMapFor, - typeMapFor_allocate, _load, _modelForMixin, - modelFor, - modelFactoryFor, _pushInternalModel, _setupRelationships, - normalize, adapterFor, - serializerFor, + buildInternalModel, + didUpdateAll, + modelFactoryFor, + modelFor, + normalize, + peekAll, + peekRecord, retrieveManagedInstance, - buildInternalModel + serializerFor, + typeMapFor, + typeMapFor_allocate } = heimdall.registerMonitor('store', '_generateId', - 'peekRecord', '_internalModelForId', - 'didUpdateAll', - 'peekAll', - 'typeMapFor', - 'typeMapFor_allocate', '_load', '_modelForMixin', - 'modelFor', - 'modelFactoryFor', '_pushInternalModel', '_setupRelationships', - 'normalize', 'adapterFor', - 'serializerFor', + 'buildInternalModel', + 'didUpdateAll', + 'modelFactoryFor', + 'modelFor', + 'normalize', + 'peekAll', + 'peekRecord', 'retrieveManagedInstance', - 'buildInternalModel' + 'serializerFor', + 'typeMapFor', + 'typeMapFor_allocate' ); /** From 0c99e46276b85b671e940a5b2cf3ed9b82bd6251 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 22 Sep 2016 17:48:36 -0700 Subject: [PATCH 1605/2527] dont import heimdall unless instrumentation is needed --- ember-cli-build.js | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/ember-cli-build.js b/ember-cli-build.js index 90580991e67..b57c57acf83 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -7,23 +7,38 @@ var yuidoc = require('./lib/yuidoc'); var stripClassCallCheck = require('babel5-plugin-strip-class-callcheck'); var path = require('path'); +// allow toggling of heimdall instrumentation +var INSTRUMENT_HEIMDALL = false; +var args = process.argv; + +for (var i = 0; i < args.length; i++) { + if (args[i] === '--instrument') { + INSTRUMENT_HEIMDALL = true; + break; + } +} +process.env.INSTRUMENT_HEIMDALL = INSTRUMENT_HEIMDALL; + module.exports = function(defaults) { var app = new EmberAddon(defaults, { babel: { plugins: [ // while ember-data strips itself, ember does not currently - { transformer: stripClassCallCheck, position: 'after' } + {transformer: stripClassCallCheck, position: 'after'} ] } }); - var heimdallTree = new Funnel('node_modules/heimdalljs', { - destDir: 'heimdalljs' - }); - app.trees.vendor = merge([app.trees.vendor, heimdallTree]); - app.import('vendor/heimdalljs/dist/heimdalljs.iife.js', { prepend: true }); + if (INSTRUMENT_HEIMDALL) { + var heimdallTree = new Funnel('node_modules/heimdalljs', { + destDir: 'heimdalljs' + }); + + app.trees.vendor = merge([app.trees.vendor, heimdallTree]); - app.vendorFiles['ember.js'].development = path.join(app.bowerDirectory, 'ember/ember.prod.js'); + app.import('vendor/heimdalljs/dist/heimdalljs.iife.js', {prepend: true}); + app.vendorFiles['ember.js'].development = path.join(app.bowerDirectory, 'ember/ember.prod.js'); + } /* This build file specifies the options for the dummy test app of this From b49e4eed46babdd0162464dc3b2e62817f2996a2 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 22 Sep 2016 18:06:11 -0700 Subject: [PATCH 1606/2527] fix env variable --- ember-cli-build.js | 2 +- lib/stripped-build-plugins.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ember-cli-build.js b/ember-cli-build.js index b57c57acf83..4b6ad84bd75 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -17,7 +17,6 @@ for (var i = 0; i < args.length; i++) { break; } } -process.env.INSTRUMENT_HEIMDALL = INSTRUMENT_HEIMDALL; module.exports = function(defaults) { var app = new EmberAddon(defaults, { @@ -30,6 +29,7 @@ module.exports = function(defaults) { }); if (INSTRUMENT_HEIMDALL) { + console.warn('IMPORTED HEIMDALL & SET EMBER TO PRODUCTION'); var heimdallTree = new Funnel('node_modules/heimdalljs', { destDir: 'heimdalljs' }); diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 2c1b8bb3c1c..0376c36e2d4 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -24,7 +24,7 @@ module.exports = function(environment) { }) ]; - if (process.env.INSTRUMENT_HEIMDALL === false) { + if (process.env.INSTRUMENT_HEIMDALL === 'false') { plugins.push( stripHeimdall, filterImports({ @@ -33,6 +33,8 @@ module.exports = function(environment) { ] }) ); + } else { + console.warn('NOT STRIPPING HEIMDALL'); } if (environment === 'production') { From 7a1a957190d0079ec64cb6ad30ce31771fbf8b10 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 29 Sep 2016 11:25:41 -0700 Subject: [PATCH 1607/2527] safe merge filtered imports --- lib/stripped-build-plugins.js | 46 ++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 0376c36e2d4..24e0141bd2b 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -4,10 +4,21 @@ var filterImports = require('babel-plugin-filter-imports'); var featureFlags = require('babel-plugin-feature-flags'); var stripHeimdall = require('babel5-plugin-strip-heimdall'); +function uniqueAdd(obj, key, values) { + var a = obj[key] = obj[key] || []; + + for (var i = 0; i < values.length; i++) { + if (a.indexOf(values[i]) === -1) { + a.push(values[i]); + } + } +} + module.exports = function(environment) { var featuresJsonPath = __dirname + '/../config/features.json'; var featuresJson = fs.readFileSync(featuresJsonPath, { encoding: 'utf8' }); var features = JSON.parse(featuresJson); + var filteredImports = {}; // TODO explicitly set all features which are not enabled to `false`, so // they are stripped --> make this configurable or pass features @@ -25,34 +36,25 @@ module.exports = function(environment) { ]; if (process.env.INSTRUMENT_HEIMDALL === 'false') { - plugins.push( - stripHeimdall, - filterImports({ - 'ember-data/-private/debug': [ - 'instrument' - ] - }) - ); + plugins.push(stripHeimdall); + uniqueAdd(filteredImports, 'ember-data/-private/debug', ['instrument']); } else { console.warn('NOT STRIPPING HEIMDALL'); } if (environment === 'production') { - plugins.push( - filterImports({ - 'ember-data/-private/debug': [ - 'assert', - 'assertPolymorphicType', - 'debug', - 'deprecate', - 'info', - 'runInDebug', - 'warn', - 'debugSeal' - ] - }) - ); + uniqueAdd(filteredImports, 'ember-data/-private/debug', [ + 'assert', + 'assertPolymorphicType', + 'debug', + 'deprecate', + 'info', + 'runInDebug', + 'warn', + 'debugSeal' + ]); } + plugins.push(filterImports(filteredImports)); return plugins; }; From eb4ff3f91e2422f168cb884bf23921e195a4c18e Mon Sep 17 00:00:00 2001 From: Bryan Hickerson Date: Fri, 30 Sep 2016 17:02:27 -0700 Subject: [PATCH 1608/2527] Treat status code 0 as an abort --- addon/adapters/rest.js | 2 +- .../integration/adapter/rest-adapter-test.js | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 16e61302fe3..b87a26ff0d6 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1469,7 +1469,7 @@ function ajaxError(adapter, jqXHR, requestData, responseData) { error = responseData.errorThrown; } else if (responseData.textStatus === 'timeout') { error = new TimeoutError(); - } else if (responseData.textStatus === 'abort') { + } else if (responseData.textStatus === 'abort' || jqXHR.status === 0) { error = new AbortError(); } else { try { diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 5fa73ba1984..fb5dc35a65e 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -2381,6 +2381,34 @@ test("gracefully handles exceptions in handleResponse where the ajax request err } }); +test('treats status code 0 as an abort', function(assert) { + assert.expect(1); + + var originalAjax = Ember.$.ajax; + var jqXHR = { + status: 0, + getAllResponseHeaders() { return ''; } + }; + + Ember.$.ajax = function(hash) { + hash.error(jqXHR, 'error'); + }; + + adapter.handleResponse = function(status, headers, payload) { + assert.ok(false); + }; + + try { + run(function() { + store.findRecord('post', '1').catch(function(err) { + assert.ok(err instanceof DS.AbortError, 'reason should be an instance of DS.AbortError'); + }); + }); + } finally { + Ember.$.ajax = originalAjax; + } +}); + test('on error appends errorThrown for sanity', function(assert) { assert.expect(2); From 8472a5a333346327238fc0ac5461bb41bdfdef31 Mon Sep 17 00:00:00 2001 From: IgorT Date: Sat, 1 Oct 2016 21:53:22 -0700 Subject: [PATCH 1609/2527] Properly cleanup store and env in store integration test The find test was failing when run by itself as it wasn't setting up the store correctly. It just happens to have worked on Travis due to us not cleaning up the store --- tests/integration/store-test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index df4c42e1acc..d1c68c9db8f 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -35,6 +35,10 @@ function initializeStore(adapter) { module("integration/store - destroy", { beforeEach() { initializeStore(DS.Adapter.extend()); + }, + afterEach() { + store = null; + env = null; } }); @@ -244,6 +248,8 @@ test("store#findRecord fetches record from server when cached record is not pres test("store#findRecord returns cached record immediately and reloads record in the background", function(assert) { assert.expect(2); + initializeStore(DS.RESTAdapter.extend()); + run(function() { store.push({ data: { From 99ffd78566af19d98f8cad2231731e0e2c9ec603 Mon Sep 17 00:00:00 2001 From: Bryan Hickerson Date: Fri, 30 Sep 2016 17:02:27 -0700 Subject: [PATCH 1610/2527] [bugfix beta] Treat status code 0 as an abort --- addon/adapters/rest.js | 2 +- .../integration/adapter/rest-adapter-test.js | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 16e61302fe3..b87a26ff0d6 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1469,7 +1469,7 @@ function ajaxError(adapter, jqXHR, requestData, responseData) { error = responseData.errorThrown; } else if (responseData.textStatus === 'timeout') { error = new TimeoutError(); - } else if (responseData.textStatus === 'abort') { + } else if (responseData.textStatus === 'abort' || jqXHR.status === 0) { error = new AbortError(); } else { try { diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 5fa73ba1984..fb5dc35a65e 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -2381,6 +2381,34 @@ test("gracefully handles exceptions in handleResponse where the ajax request err } }); +test('treats status code 0 as an abort', function(assert) { + assert.expect(1); + + var originalAjax = Ember.$.ajax; + var jqXHR = { + status: 0, + getAllResponseHeaders() { return ''; } + }; + + Ember.$.ajax = function(hash) { + hash.error(jqXHR, 'error'); + }; + + adapter.handleResponse = function(status, headers, payload) { + assert.ok(false); + }; + + try { + run(function() { + store.findRecord('post', '1').catch(function(err) { + assert.ok(err instanceof DS.AbortError, 'reason should be an instance of DS.AbortError'); + }); + }); + } finally { + Ember.$.ajax = originalAjax; + } +}); + test('on error appends errorThrown for sanity', function(assert) { assert.expect(2); From 5ab07dbd931f3a2994bcc77b3c3afbbe8c2ffc4d Mon Sep 17 00:00:00 2001 From: ckl1989 Date: Tue, 4 Oct 2016 07:43:59 -0700 Subject: [PATCH 1611/2527] =?UTF-8?q?Add=20a=20real=20error=20message=20fo?= =?UTF-8?q?r=20attempts=20to=20manipulate=20a=20recordArray=20and=E2=80=A6?= =?UTF-8?q?=20(#4520)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add a real error message for attempts to manipulate a recordArray and prevent it from trying to perform manipulation #4513 * Moving recordArray manipulation test to existing record-array-test.js and refactor test to use real model * Update error message with suggestion to use toArray() * Update test to reflect new error message. Forgot to include this in my previous commit woops --- addon/-private/system/record-arrays/record-array.js | 5 +++++ tests/unit/record-array-test.js | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index 58b365bb503..4200ce9feac 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -83,6 +83,11 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { */ store: null, + replace() { + var type = get(this, 'type').toString(); + throw new Error("The result of a server query (for all " + type + " types) is immutable. To modify contents, use toArray()"); + }, + /** Retrieves an object from the content by index. diff --git a/tests/unit/record-array-test.js b/tests/unit/record-array-test.js index 140fa64b688..ea43fe29b3e 100644 --- a/tests/unit/record-array-test.js +++ b/tests/unit/record-array-test.js @@ -459,3 +459,14 @@ test("a record array should return a promise when updating", function(assert) { }); assert.ok(promise.then && typeof promise.then === "function", "#update returns a promise"); }); + +test('recordArray.replace() throws error', function(assert) { + var recordArray; + var env = setupStore({ person: Person }); + var store = env.store; + + assert.throws(function() { + recordArray = store.peekAll('person'); + recordArray.replace(); + }, Error("The result of a server query (for all (subclass of DS.Model) types) is immutable. To modify contents, use toArray()"), 'throws error'); +}); From 0e84da4e791504cb06edfe5d80754f63df2fa0ac Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Wed, 12 Oct 2016 15:13:42 -0700 Subject: [PATCH 1612/2527] Move heimdalljs to dependencies heimdalljs is actually a dev dependency, but `npm install` will fail to install the nested (non-dev) dependencies, eg for broccoli-funnel, due to https://github.com/npm/npm/issues/13974 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d984d45ed07..7d5bfaf31db 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "ember-runtime-enumerable-includes-polyfill": "^1.0.0", "exists-sync": "0.0.3", "git-repo-info": "^1.1.2", + "heimdalljs": "^0.3.0", "inflection": "^1.8.0", "npm-git-info": "^1.0.0", "semver": "^5.1.0", @@ -82,7 +83,6 @@ "express": "^4.14.0", "github": "^0.2.4", "glob": "5.0.13", - "heimdalljs": "~0.3.0-alpha3", "heimdall-query": "^0.0.4", "json-api-mock-server": "0.0.2", "mocha": "2.4.5", From 1f76fdb3fcf934cbca1ac8a087a28717859d967b Mon Sep 17 00:00:00 2001 From: David Baker Date: Sat, 15 Oct 2016 14:24:49 -0600 Subject: [PATCH 1613/2527] [DOC] Update Readme to reflect new default adapter Believe this is out of date at this point --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9b511bd0a43..5bb734d6836 100644 --- a/README.md +++ b/README.md @@ -138,11 +138,10 @@ Data store for a record of type `person` with an ID of `123`, the adapter translates that into an XHR request to (for example) `api.example.com/v3/person/123.json`. -By default, Ember Data will use the `RESTAdapter`, which adheres to a -set of RESTful JSON conventions. +By default, Ember Data will use the `JSONAPIAdapter`, which adheres to the [JSON-API spec](http://jsonapi.org/). To learn more about adapters, including what conventions the -`RESTAdapter` follows and how to build your own, see the Ember.js +various adapters follow and how to build your own, see the Ember.js Guides: [Customizing Adapters](http://emberjs.com/guides/models/customizing-adapters). ### Fetching a Collection of Models From 2d2e6cea483d6d196c76abeaf048a8eb2af35e9a Mon Sep 17 00:00:00 2001 From: Mikael Riska Date: Mon, 17 Oct 2016 12:54:31 +0200 Subject: [PATCH 1614/2527] [DOC] fix typo --- addon/serializers/json-api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 6e047ac229b..52acb8871b2 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -645,7 +645,7 @@ if (isEnabled("ds-payload-type-hooks")) { ``` By overwriting `modelNameFromPayloadType` you can specify that the - `posr` model should be used: + `post` model should be used: ```app/serializers/application.js import DS from "ember-data"; From 7d7017c44161f30c537bdd50b96c628fcf83298c Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 27 May 2016 15:22:10 -0400 Subject: [PATCH 1615/2527] Log an assertion if the response from createRecord does not have an id and the id was not already provided by the client Closes #4346 --- addon/-private/system/store.js | 2 +- tests/integration/adapter/rest-adapter-test.js | 6 +++--- tests/integration/adapter/store-adapter-test.js | 2 +- tests/integration/client-id-generation-test.js | 2 +- tests/integration/relationships/has-many-test.js | 5 ++++- tests/integration/store-test.js | 15 +++++++++++++++ tests/unit/model-test.js | 2 +- 7 files changed, 26 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 772da72a8e7..9625066b5ad 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1756,7 +1756,7 @@ Store = Service.extend({ this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, data); this.updateId(internalModel, data); } - + assert(`Your ${internalModel.type.modelName} record was saved but it does not have an id. Please make the server provides an id in the createRecord response or you are setting the on the client side before saving the record.`, internalModel.id !== null); //We first make sure the primary data has been updated //TODO try to move notification to the user to the end of the runloop internalModel.adapterDidCommit(data); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index fb5dc35a65e..26510668bf0 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -328,14 +328,14 @@ test("createRecord - a serializer's primary key and attributes are consulted whe test("createRecord - a serializer's attributes are consulted when building the payload if no id is pre-defined", function(assert) { var post; env.registry.register('serializer:post', DS.RESTSerializer.extend({ - primarykey: '_id_', - attrs: { name: '_name_' } })); - ajaxResponse(); + ajaxResponse({ + post: { '_name_': "The Parley Letter", id: '1' } + }); run(function() { post = store.createRecord('post', { name: "The Parley Letter" }); diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index eec8b75b16b..0094d5a7bdd 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -1057,7 +1057,7 @@ test("createRecord receives a snapshot", function(assert) { var person; run(function() { - person = store.createRecord('person', { name: "Tom Dale" }); + person = store.createRecord('person', { name: "Tom Dale", id: 1 }); person.save(); }); }); diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index 72f008b5afa..b98a439db50 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -86,7 +86,7 @@ test("empty string and undefined ids should coerce to null", function(assert) { env.adapter.createRecord = function(store, type, record) { assert.equal(typeof get(record, 'id'), 'object', 'correct type'); - return Ember.RSVP.resolve(); + return Ember.RSVP.resolve({ id: 1 }); }; run(function() { diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 49a46557509..2300815875a 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -342,6 +342,7 @@ test("A hasMany updated link should not remove new children", function(assert) { env.adapter.createRecord = function(store, snapshot, link, relationship) { return Ember.RSVP.resolve({ + id: 1, links: { comments: '/some/link' } @@ -382,6 +383,7 @@ test("A hasMany updated link should not remove new children when the parent reco env.adapter.createRecord = function(store, snapshot, link, relationship) { return Ember.RSVP.resolve({ + id: 1, links: { comments: '/some/link' } @@ -2207,6 +2209,7 @@ test("adding and removing records from hasMany relationship #2666", function(ass }) }); + var commentId = 4; env.registry.register('adapter:comment', DS.RESTAdapter.extend({ deleteRecord(record) { return Ember.RSVP.resolve(); @@ -2215,7 +2218,7 @@ test("adding and removing records from hasMany relationship #2666", function(ass return Ember.RSVP.resolve(); }, createRecord() { - return Ember.RSVP.resolve(); + return Ember.RSVP.resolve({ comments: { id: commentId++ }}); } })); diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index d1c68c9db8f..523742c5c40 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -873,6 +873,19 @@ testInDebug('store#findRecord that returns an array should assert', assert => { }, /expected the primary data returned from a `findRecord` response to be an object but instead it found an array/); }); +testInDebug('store#didSaveRecord should assert when the response to a save does not include the id', function(assert) { + env.adapter.createRecord = function() { + return {}; + }; + + assert.expectAssertion(function() { + run(function() { + var car = store.createRecord('car'); + car.save(); + }); + }, /record was saved but it does not have an id. Please make the server provides an id in the createRecord/); +}); + module("integration/store - queryRecord", { beforeEach() { initializeStore(DS.Adapter.extend()); @@ -898,3 +911,5 @@ testInDebug('store#queryRecord should assert when normalized payload of adapter }); }, /Expected the primary data returned by the serializer for a `queryRecord` response to be a single object or null but instead it was an array./); }); + + diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index a58452a6537..ea2cc1dc17a 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -370,7 +370,7 @@ test("changedAttributes() works while the record is being saved", function(asser assert.deepEqual(toObj(cat.changedAttributes()), { name: [undefined, 'Argon'], likes: [undefined, 'Cheese'] }); - return {}; + return { id: 1 }; } }); var Mascot = DS.Model.extend({ From efc98ea64d4330c00f92d3322dc2d8987adb54cc Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 21 Sep 2016 18:52:52 -0700 Subject: [PATCH 1616/2527] [BUGFIX RELEASE] fix regression in store beahvior when an updated record has a null id --- addon/-private/system/store.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 9625066b5ad..ebe99c68ff9 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1804,7 +1804,17 @@ Store = Service.extend({ var oldId = internalModel.id; var id = coerceId(data.id); - assert("An adapter cannot assign a new id to a record that already has an id. " + internalModel + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId); + // ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record) + assert(`The store cannot assign an empty id to record '${internalModel.type.modelName}:${internalModel._id}', because it already has an empty ID.`, id !== null && oldId !== null); + + // ID absolutely can't be different than oldID if oldID is not null + assert("The store cannot assign a new id to a record that already has an id. " + internalModel + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId); + + // ID can be null if oldID is not null (altered ID in response for a record) + if (id === null) { + warn(`Your ${internalModel.type.modelName} record was saved but it does not have an id. Please make the server provides an id in the createRecord response or you are setting the id on the client side before saving the record.`, id !== null); + return; + } this.typeMapFor(internalModel.type).idToRecord[id] = internalModel; From b26035ea3eee888dfa631004413e6d179e9e5252 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 22 Sep 2016 12:21:27 -0700 Subject: [PATCH 1617/2527] improve assertion flow --- addon/-private/system/store.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index ebe99c68ff9..803fc87cd9a 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1755,6 +1755,8 @@ Store = Service.extend({ // normalize relationship IDs into records this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, data); this.updateId(internalModel, data); + } else { + assert(`Your ${internalModel.type.modelName} record was saved but it does not have an id. Please make the server provides an id in the createRecord response or you are setting the id on the client side before saving the record.`, internalModel.id); } assert(`Your ${internalModel.type.modelName} record was saved but it does not have an id. Please make the server provides an id in the createRecord response or you are setting the on the client side before saving the record.`, internalModel.id !== null); //We first make sure the primary data has been updated @@ -1808,11 +1810,11 @@ Store = Service.extend({ assert(`The store cannot assign an empty id to record '${internalModel.type.modelName}:${internalModel._id}', because it already has an empty ID.`, id !== null && oldId !== null); // ID absolutely can't be different than oldID if oldID is not null - assert("The store cannot assign a new id to a record that already has an id. " + internalModel + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId); + assert("The store cannot assign a new id to a record that already has an id. " + internalModel + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId !== null && id === oldId); // ID can be null if oldID is not null (altered ID in response for a record) - if (id === null) { - warn(`Your ${internalModel.type.modelName} record was saved but it does not have an id. Please make the server provides an id in the createRecord response or you are setting the id on the client side before saving the record.`, id !== null); + if (oldId !== null && id === null) { + warn(`Your ${internalModel.type.modelName} record was saved but it does not have an id. Please make the server provides an id in the createRecord response or you are setting the id on the client side before saving the record.`, !(oldId !== null && id === null)); return; } From 97daea86e514311eaa554e2ccce09a2cb2c43944 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 17 Oct 2016 07:58:58 -0700 Subject: [PATCH 1618/2527] improved error messaging --- addon/-private/system/store.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 803fc87cd9a..3ac93feaa33 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1756,7 +1756,7 @@ Store = Service.extend({ this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, data); this.updateId(internalModel, data); } else { - assert(`Your ${internalModel.type.modelName} record was saved but it does not have an id. Please make the server provides an id in the createRecord response or you are setting the id on the client side before saving the record.`, internalModel.id); + assert(`Your ${internalModel.type.modelName} record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, internalModel.id); } assert(`Your ${internalModel.type.modelName} record was saved but it does not have an id. Please make the server provides an id in the createRecord response or you are setting the on the client side before saving the record.`, internalModel.id !== null); //We first make sure the primary data has been updated @@ -1813,8 +1813,9 @@ Store = Service.extend({ assert("The store cannot assign a new id to a record that already has an id. " + internalModel + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId !== null && id === oldId); // ID can be null if oldID is not null (altered ID in response for a record) + // however, this is more than likely a developer error. if (oldId !== null && id === null) { - warn(`Your ${internalModel.type.modelName} record was saved but it does not have an id. Please make the server provides an id in the createRecord response or you are setting the id on the client side before saving the record.`, !(oldId !== null && id === null)); + warn(`Your ${internalModel.type.modelName} record was saved to the server, but the response does not have an id.`, !(oldId !== null && id === null)); return; } From 58baca4cc917002eb7da6c2dfee14cc67bfeb784 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 17 Oct 2016 08:05:56 -0700 Subject: [PATCH 1619/2527] fix id in error message --- addon/-private/system/store.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 3ac93feaa33..8124af39526 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -68,16 +68,19 @@ function promiseRecord(internalModel, label) { return promiseObject(toReturn, label); } -var get = Ember.get; -var set = Ember.set; var once = Ember.run.once; -var isNone = Ember.isNone; -var isPresent = Ember.isPresent; var Promise = Ember.RSVP.Promise; -var copy = Ember.copy; var Store; -const { Service } = Ember; +const { + copy, + get, + GUID_KEY, + isNone, + isPresent, + set, + Service +} = Ember; // Implementors Note: // @@ -1807,7 +1810,7 @@ Store = Service.extend({ var id = coerceId(data.id); // ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record) - assert(`The store cannot assign an empty id to record '${internalModel.type.modelName}:${internalModel._id}', because it already has an empty ID.`, id !== null && oldId !== null); + assert(`The store cannot assign an empty id to record '${internalModel.type.modelName}:${internalModel[GUID_KEY]}', because it already has an empty ID.`, id !== null && oldId !== null); // ID absolutely can't be different than oldID if oldID is not null assert("The store cannot assign a new id to a record that already has an id. " + internalModel + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId !== null && id === oldId); From b52399b299b11566dc7e8db97bded60945cb6287 Mon Sep 17 00:00:00 2001 From: MarkMT Date: Mon, 17 Oct 2016 13:29:12 -0500 Subject: [PATCH 1620/2527] [DOC] Update descriptions of findRecord() and findAll() This commit adds documentation on the use of the `include` query parameter in `DS.Store` methods `findRecord()` and `findAll()`. This feature allows records of models related to those requested to be retrieved from JSON API compliant server in a single request. This capability was added in https://github.com/emberjs/data/pull/3976 but is not currently documented. --- addon/-private/system/store.js | 87 ++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 772da72a8e7..b85c386a807 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -605,6 +605,51 @@ Store = Service.extend({ See [peekRecord](#method_peekRecord) to get the cached version of a record. + ### Retrieving Related Model Records + + If you use an adapter such as Ember's default + [`JSONAPIAdapter`](http://emberjs.com/api/data/classes/DS.JSONAPIAdapter.html) + that supports the [JSON API specification](http://jsonapi.org/) and if your server + endpoint supports the use of an + ['include' query parameter](http://jsonapi.org/format/#fetching-includes), + you can use `findRecord()` to automatically retrieve additional records related to + the one you request by supplying an `include` parameter in the `options` object. + + For example, given a `post` model that has a `hasMany` relationship with a `comment` + model, when we retrieve a specific post we can have the server also return that post's + comments in the same request: + + ``` + // app/routes/post.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model: function(params) { + return this.store.findRecord('post', params.post_id, {include: 'comments'}); + } + }); + + ``` + In this case, the post's comments would then be available in your template as + `model.comments`. + + Multiple relationships can be requested using an `include` parameter consisting of a + comma-separated list (without white-space) while nested relationships can be specified + using a dot-separated sequence of relationship names. So to request both the post's + comments and the authors of those comments the request would look like this: + + ``` + // app/routes/post.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model: function(params) { + return this.store.findRecord('post', params.post_id, {include: 'comments,comments.author'}); + } + }); + + ``` + @since 1.13.0 @method findRecord @param {String} modelName @@ -1392,6 +1437,48 @@ Store = Service.extend({ See [peekAll](#method_peekAll) to get an array of current records in the store, without waiting until a reload is finished. + ### Retrieving Related Model Records + + If you use an adapter such as Ember's default + [`JSONAPIAdapter`](http://emberjs.com/api/data/classes/DS.JSONAPIAdapter.html) + that supports the [JSON API specification](http://jsonapi.org/) and if your server + endpoint supports the use of an + ['include' query parameter](http://jsonapi.org/format/#fetching-includes), + you can use `findAll()` to automatically retrieve additional records related to + those requested by supplying an `include` parameter in the `options` object. + + For example, given a `post` model that has a `hasMany` relationship with a `comment` + model, when we retrieve all of the post records we can have the server also return + all of the posts' comments in the same request: + + ``` + // app/routes/posts.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model: function() { + return this.store.findAll('post', {include: 'comments'}); + } + }); + + ``` + Multiple relationships can be requested using an `include` parameter consisting of a + comma-separated list (without white-space) while nested relationships can be specified + using a dot-separated sequence of relationship names. So to request both the posts' + comments and the authors of those comments the request would look like this: + + ``` + // app/routes/posts.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model: function() { + return this.store.findAll('post', {include: 'comments,comments.author'}); + } + }); + + ``` + See [query](#method_query) to only get a subset of records from the server. @since 1.13.0 From 2d464dc37595443f4e01a433b8717df9c8b955c6 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 17 Oct 2016 13:53:38 -0700 Subject: [PATCH 1621/2527] fix assertion tests --- addon/-private/system/store.js | 6 +++--- tests/integration/store-test.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 8124af39526..0d1d8d20a44 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1761,7 +1761,7 @@ Store = Service.extend({ } else { assert(`Your ${internalModel.type.modelName} record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, internalModel.id); } - assert(`Your ${internalModel.type.modelName} record was saved but it does not have an id. Please make the server provides an id in the createRecord response or you are setting the on the client side before saving the record.`, internalModel.id !== null); + //We first make sure the primary data has been updated //TODO try to move notification to the user to the end of the runloop internalModel.adapterDidCommit(data); @@ -1810,10 +1810,10 @@ Store = Service.extend({ var id = coerceId(data.id); // ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record) - assert(`The store cannot assign an empty id to record '${internalModel.type.modelName}:${internalModel[GUID_KEY]}', because it already has an empty ID.`, id !== null && oldId !== null); + assert(`'${internalModel.type.modelName}:${internalModel[GUID_KEY]}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null)); // ID absolutely can't be different than oldID if oldID is not null - assert("The store cannot assign a new id to a record that already has an id. " + internalModel + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId !== null && id === oldId); + assert(`'${internalModel.type.modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, !(oldId !== null && id !== oldId)); // ID can be null if oldID is not null (altered ID in response for a record) // however, this is more than likely a developer error. diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 523742c5c40..ec1a03c47eb 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -883,7 +883,7 @@ testInDebug('store#didSaveRecord should assert when the response to a save does var car = store.createRecord('car'); car.save(); }); - }, /record was saved but it does not have an id. Please make the server provides an id in the createRecord/); + }, /Your car record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response./); }); module("integration/store - queryRecord", { From dec22c6fe6ed5004006af570e4b6cee27b8aa985 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 18 Oct 2016 00:52:15 +0300 Subject: [PATCH 1622/2527] tidy up integration/filter-test * remove unneeded reopens * remove assert.wait, instead use the promise chaining * consistent quotes * remove unneeded promises * some ES6 --- tests/integration/filter-test.js | 727 +++++++++++++++---------------- 1 file changed, 358 insertions(+), 369 deletions(-) diff --git a/tests/integration/filter-test.js b/tests/integration/filter-test.js index 3f359de96d6..7d650812499 100644 --- a/tests/integration/filter-test.js +++ b/tests/integration/filter-test.js @@ -1,164 +1,164 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; import customAdapter from 'dummy/tests/helpers/custom-adapter'; -var get = Ember.get; -var set = Ember.set; -var run = Ember.run; +const { + get, + set, + run +} = Ember; -var Person, store, env, array, recordArray; +let store, env, data, recordArray; -module("integration/filter - DS.Model updating", { +const Person = DS.Model.extend({ + name: DS.attr('string'), + bestFriend: DS.belongsTo('person', { inverse: null, async: false }), + upperName: Ember.computed('name', function() { + return this.get('name').toUpperCase(); + }).readOnly() +}); + +module('integration/filter - DS.Model updating', { beforeEach() { - array = [{ - id: '1', - type: 'person', - attributes: { - name: 'Scumbag Dale' - }, - relationships: { - bestFriend: { - data: { - id: '2', - type: 'person' + data = [ + { + id: '1', + type: 'person', + attributes: { + name: 'Scumbag Dale' + }, + relationships: { + bestFriend: { + data: { + id: '2', + type: 'person' + } } } + }, + { + id: '2', + type: 'person', + attributes: { + name: 'Scumbag Katz' + } + }, + { + id: '3', + type: 'person', + attributes: { + name: 'Scumbag Bryn' + } } - }, { - id: '2', - type: 'person', - attributes: { - name: 'Scumbag Katz' - } - }, { - id: '3', - type: 'person', - attributes: { - name: 'Scumbag Bryn' - } - }]; - Person = DS.Model.extend({ name: DS.attr('string'), bestFriend: DS.belongsTo('person', { inverse: null, async: false }) }); + ]; env = setupStore({ person: Person }); store = env.store; }, + afterEach() { + edited = null; + data = null; + run(store, 'destroy'); - Person = null; - array = null; } }); function tapFn(fn, callback) { - var old_fn = fn; + const old_fn = fn; - var new_fn = function() { - var result = old_fn.apply(this, arguments); + function new_fn() { + let result = old_fn.apply(this, arguments); if (callback) { callback.apply(fn, arguments); } new_fn.summary.called.push(arguments); return result; - }; + } new_fn.summary = { called: [] }; return new_fn; } -test("when a DS.Model updates its attributes, its changes affect its filtered Array membership", function(assert) { - run(function() { - store.push({ data: array }); - }); - var people; +test('when a DS.Model updates its attributes, its changes affect its filtered Array membership', function(assert) { + run(() => store.push({ data })); - run(function() { - people = store.filter('person', function(hash) { - if (hash.get('name').match(/Katz$/)) { return true; } + let people = run(() => { + return store.filter('person', hash => { + if (hash.get('name').match(/Katz$/)) { + return true; + } }); }); - run(function() { - assert.equal(get(people, 'length'), 1, "precond - one item is in the RecordArray"); - }); + assert.equal(get(people, 'length'), 1, 'precond - one item is in the RecordArray'); - var person = people.objectAt(0); + const person = people.objectAt(0); - assert.equal(get(person, 'name'), "Scumbag Katz", "precond - the item is correct"); + assert.equal(get(person, 'name'), 'Scumbag Katz', 'precond - the item is correct'); - run(function() { - set(person, 'name', "Yehuda Katz"); - }); + run(() => set(person, 'name', 'Yehuda Katz')); - assert.equal(get(people, 'length'), 1, "there is still one item"); - assert.equal(get(person, 'name'), "Yehuda Katz", "it has the updated item"); + assert.equal(get(people, 'length'), 1, 'there is still one item'); + assert.equal(get(person, 'name'), 'Yehuda Katz', "it has the updated item"); - run(function() { - set(person, 'name', "Yehuda Katz-Foo"); - }); + run(() => set(person, 'name', 'Yehuda Katz-Foo')); assert.equal(get(people, 'query'), null, 'expected no query object set'); - assert.equal(get(people, 'length'), 0, "there are now no items"); + assert.equal(get(people, 'length'), 0, 'there are now no items'); }); -test("when a DS.Model updates its relationships, its changes affect its filtered Array membership", function(assert) { - run(function() { - store.push({ data: array }); - }); - var people; +test('when a DS.Model updates its relationships, its changes affect its filtered Array membership', function(assert) { + run(() => store.push({ data })); - run(function() { - people = store.filter('person', function(person) { - if (person.get('bestFriend') && person.get('bestFriend.name').match(/Katz$/)) { return true; } + let people = run(() => { + return store.filter('person', person => { + if (person.get('bestFriend') && person.get('bestFriend.name').match(/Katz$/)) { + return true; + } }); }); - run(function() { - assert.equal(get(people, 'length'), 1, "precond - one item is in the RecordArray"); - }); + run(() => assert.equal(get(people, 'length'), 1, 'precond - one item is in the RecordArray')); - var person = people.objectAt(0); + let person = people.objectAt(0); - assert.equal(get(person, 'name'), "Scumbag Dale", "precond - the item is correct"); + assert.equal(get(person, 'name'), 'Scumbag Dale', 'precond - the item is correct'); - run(function() { - set(person, 'bestFriend', null); - }); + run(() => set(person, 'bestFriend', null)); - assert.equal(get(people, 'length'), 0, "there are now 0 items"); + assert.equal(get(people, 'length'), 0, 'there are now 0 items'); - var erik = store.peekRecord('person', 3); - var yehuda = store.peekRecord('person', 2); - run(function() { - erik.set('bestFriend', yehuda); - }); + let erik = store.peekRecord('person', 3); + let yehuda = store.peekRecord('person', 2); + + run(() => erik.set('bestFriend', yehuda)); person = people.objectAt(0); - assert.equal(get(people, 'length'), 1, "there is now 1 item"); - assert.equal(get(person, 'name'), "Scumbag Bryn", "precond - the item is correct"); + assert.equal(get(people, 'length'), 1, 'there is now 1 item'); + assert.equal(get(person, 'name'), 'Scumbag Bryn', 'precond - the item is correct'); }); +test('a record array can have a filter on it', function(assert) { + run(() => store.push({ data })); -test("a record array can have a filter on it", function(assert) { - run(function() { - store.push({ data: array }); - }); - var recordArray; - - run(function() { - recordArray = store.filter('person', function(hash) { - if (hash.get('name').match(/Scumbag [KD]/)) { return true; } + let recordArray = run(() => { + return store.filter('person', hash => { + if (hash.get('name').match(/Scumbag [KD]/)) { + return true; + } }); }); - assert.equal(get(recordArray, 'length'), 2, "The Record Array should have the filtered objects on it"); + assert.equal(get(recordArray, 'length'), 2, 'The Record Array should have the filtered objects on it'); - run(function () { + run(() => { store.push({ data: [{ id: '4', @@ -170,9 +170,9 @@ test("a record array can have a filter on it", function(assert) { }); }); - assert.equal(get(recordArray, 'length'), 3, "The Record Array should be updated as new items are added to the store"); + assert.equal(get(recordArray, 'length'), 3, 'The Record Array should be updated as new items are added to the store'); - run(function () { + run(() => { store.push({ data: [{ id: '1', @@ -184,74 +184,74 @@ test("a record array can have a filter on it", function(assert) { }); }); - assert.equal(get(recordArray, 'length'), 2, "The Record Array should be updated as existing members are updated"); + assert.equal(get(recordArray, 'length'), 2, 'The Record Array should be updated as existing members are updated'); }); -test("a filtered record array includes created elements", function(assert) { - run(function() { - store.push({ data: array }); - }); - var recordArray; +test('a filtered record array includes created elements', function(assert) { + run(() => store.push({ data })); - run(function() { - recordArray = store.filter('person', function(hash) { - if (hash.get('name').match(/Scumbag [KD]/)) { return true; } + let recordArray = run(() => { + return store.filter('person', hash => { + if (hash.get('name').match(/Scumbag [KD]/)) { + return true; + } }); }); - assert.equal(get(recordArray, 'length'), 2, "precond - The Record Array should have the filtered objects on it"); + assert.equal(get(recordArray, 'length'), 2, 'precond - The Record Array should have the filtered objects on it'); - run(function() { - store.createRecord('person', { name: "Scumbag Koz" }); + run(() => { + store.createRecord('person', { name: 'Scumbag Koz' }); }); - assert.equal(get(recordArray, 'length'), 3, "The record array has the new object on it"); + assert.equal(get(recordArray, 'length'), 3, 'The record array has the new object on it'); }); -test("a Record Array can update its filter", function(assert) { +test('a Record Array can update its filter', function(assert) { customAdapter(env, DS.Adapter.extend({ - deleteRecord(store, type, snapshot) { - return Ember.RSVP.resolve(); - }, - shouldBackgroundReloadRecord: () => false + deleteRecord(store, type, snapshot) { }, + shouldBackgroundReloadRecord() { return false; } })); - run(function() { - store.push({ data: array }); - }); + run(() => store.push({ data })); - var dickens = run(function() { - var record = store.createRecord('person', { id: 4, name: "Scumbag Dickens" }); + let dickens = run(() => { + let record = store.createRecord('person', { id: 4, name: 'Scumbag Dickens' }); record.deleteRecord(); return record; }); - var asyncDale, asyncKatz, asyncBryn; - run(function() { - asyncDale = store.findRecord('person', 1); - asyncKatz = store.findRecord('person', 2); - asyncBryn = store.findRecord('person', 3); + let asyncData = run(() => { + return { + dale: store.findRecord('person', 1), + katz: store.findRecord('person', 2), + bryn: store.findRecord('person', 3) + }; }); - store.filter('person', function(hash) { - if (hash.get('name').match(/Scumbag [KD]/)) { return true; } - }).then(assert.wait(function(recordArray) { + return store.filter('person', hash => { + if (hash.get('name').match(/Scumbag [KD]/)) { + return true; + } + }).then(recordArray => { - Ember.RSVP.hash({ dale: asyncDale, katz: asyncKatz, bryn: asyncBryn }).then(assert.wait(function(records) { + return Ember.RSVP.hash(asyncData).then(records => { assert.contains(recordArray, records.dale); assert.contains(recordArray, records.katz); assert.without(recordArray, records.bryn); assert.without(recordArray, dickens); - Ember.run(function() { - recordArray.set('filterFunction', function(hash) { - if (hash.get('name').match(/Katz/)) { return true; } + run(() => { + recordArray.set('filterFunction', hash => { + if (hash.get('name').match(/Katz/)) { + return true; + } }); }); - assert.equal(get(recordArray, 'length'), 1, "The Record Array should have one object on it"); + assert.equal(get(recordArray, 'length'), 1, 'The Record Array should have one object on it'); - Ember.run(function () { + run(() => { store.push({ data: [{ id: '5', @@ -263,9 +263,9 @@ test("a Record Array can update its filter", function(assert) { }); }); - assert.equal(get(recordArray, 'length'), 2, "The Record Array now has the new object matching the filter"); + assert.equal(get(recordArray, 'length'), 2, 'The Record Array now has the new object matching the filter'); - Ember.run(function () { + run(() => { store.push({ data: [{ id: '6', @@ -277,47 +277,45 @@ test("a Record Array can update its filter", function(assert) { }); }); - assert.equal(get(recordArray, 'length'), 2, "The Record Array doesn't have objects matching the old filter"); - })); - })); + assert.equal(get(recordArray, 'length'), 2, 'The Record Array doesn\'t have objects matching the old filter'); + }); + }); }); -test("a Record Array can update its filter and notify array observers", function(assert) { +test('a Record Array can update its filter and notify array observers', function(assert) { customAdapter(env, DS.Adapter.extend({ - deleteRecord(store, type, snapshot) { - return Ember.RSVP.resolve(); - }, - shouldBackgroundReloadRecord: () => false + deleteRecord(store, type, snapshot) { }, + shouldBackgroundReloadRecord() { return false; } })); - run(function() { - store.push({ data: array }); - }); - var dickens; + run(() => store.push({ data })); - run(function() { - dickens = store.createRecord('person', { id: 4, name: "Scumbag Dickens" }); + let dickens = run(() => { + dickens = store.createRecord('person', { id: 4, name: 'Scumbag Dickens' }); dickens.deleteRecord(); + return dickens; }); - var asyncDale, asyncKatz, asyncBryn; - - run(function() { - asyncDale = store.findRecord('person', 1); - asyncKatz = store.findRecord('person', 2); - asyncBryn = store.findRecord('person', 3); + let asyncData = run(() => { + return [ + store.findRecord('person', 1), + store.findRecord('person', 2), + store.findRecord('person', 3) + ]; }); - store.filter('person', function(hash) { - if (hash.get('name').match(/Scumbag [KD]/)) { return true; } - }).then(assert.wait(function(recordArray) { + store.filter('person', hash => { + if (hash.get('name').match(/Scumbag [KD]/)) { + return true; + } + }).then(assert.wait(recordArray => { - var didChangeIdx; - var didChangeRemoved = 0; - var didChangeAdded = 0; + let didChangeIdx; + let didChangeRemoved = 0; + let didChangeAdded = 0; - var arrayObserver = { - arrayWillChange: Ember.K, + let arrayObserver = { + arrayWillChange() { }, arrayDidChange(array, idx, removed, added) { didChangeIdx = idx; @@ -328,17 +326,19 @@ test("a Record Array can update its filter and notify array observers", function recordArray.addArrayObserver(arrayObserver); - Ember.run(function() { - recordArray.set('filterFunction', function(hash) { - if (hash.get('name').match(/Katz/)) { return true; } + run(() => { + recordArray.set('filterFunction', hash => { + if (hash.get('name').match(/Katz/)) { + return true; + } }); }); - Ember.RSVP.all([asyncDale, asyncKatz, asyncBryn]).then(assert.wait(function() { - assert.equal(didChangeRemoved, 1, "removed one item from array"); + return Ember.RSVP.all(asyncData).then(() => { + assert.equal(didChangeRemoved, 1, 'removed one item from array'); didChangeRemoved = 0; - Ember.run(function () { + run(() => { store.push({ data: [{ id: '5', @@ -350,12 +350,12 @@ test("a Record Array can update its filter and notify array observers", function }); }); - assert.equal(didChangeAdded, 1, "one item was added"); + assert.equal(didChangeAdded, 1, 'one item was added'); didChangeAdded = 0; - assert.equal(recordArray.objectAt(didChangeIdx).get('name'), "Other Katz"); + assert.equal(recordArray.objectAt(didChangeIdx).get('name'), 'Other Katz'); - Ember.run(function () { + run(() => { store.push({ data: [{ id: '6', @@ -367,42 +367,35 @@ test("a Record Array can update its filter and notify array observers", function }); }); - assert.equal(didChangeAdded, 0, "did not get called when an object that doesn't match is added"); + assert.equal(didChangeAdded, 0, 'did not get called when an object that doesn\'t match is added'); - Ember.run(function() { - recordArray.set('filterFunction', function(hash) { - if (hash.get('name').match(/Scumbag [KD]/)) { return true; } + run(() => { + recordArray.set('filterFunction', hash => { + if (hash.get('name').match(/Scumbag [KD]/)) { + return true; + } }); }); - assert.equal(didChangeAdded, 2, "one item is added when going back"); - assert.equal(recordArray.objectAt(didChangeIdx).get('name'), "Scumbag Demon"); - assert.equal(recordArray.objectAt(didChangeIdx-1).get('name'), "Scumbag Dale"); - })); + assert.equal(didChangeAdded, 2, 'one item is added when going back'); + assert.equal(recordArray.objectAt(didChangeIdx).get('name'), 'Scumbag Demon'); + assert.equal(recordArray.objectAt(didChangeIdx-1).get('name'), 'Scumbag Dale'); + }); })); }); -test("it is possible to filter by computed properties", function(assert) { +test('it is possible to filter by computed properties', function(assert) { customAdapter(env, DS.Adapter.extend({ shouldBackgroundReloadRecord: () => false })); - Person.reopen({ - name: DS.attr('string'), - upperName: Ember.computed(function() { - return this.get('name').toUpperCase(); - }).property('name') - }); - var filter; - run(function() { - filter = store.filter('person', function(person) { - return person.get('upperName') === "TOM DALE"; - }); + let filter = run(() => { + return store.filter('person', person => person.get('upperName') === 'TOM DALE'); }); - assert.equal(filter.get('length'), 0, "precond - the filter starts empty"); + assert.equal(filter.get('length'), 0, 'precond - the filter starts empty'); - run(function () { + run(() => { store.push({ data: [{ id: '1', @@ -414,29 +407,23 @@ test("it is possible to filter by computed properties", function(assert) { }); }); - assert.equal(filter.get('length'), 1, "the filter now has a record in it"); + assert.equal(filter.get('length'), 1, 'the filter now has a record in it'); - store.findRecord('person', 1).then(assert.wait(function(person) { - Ember.run(function() { - person.set('name', "Yehuda Katz"); + return store.findRecord('person', 1).then(person => { + run(() => { + person.set('name', 'Yehuda Katz'); }); - assert.equal(filter.get('length'), 0, "the filter is empty again"); - })); + assert.equal(filter.get('length'), 0, 'the filter is empty again'); + }); }); -test("a filter created after a record is already loaded works", function(assert) { +test('a filter created after a record is already loaded works', function(assert) { customAdapter(env, DS.Adapter.extend({ - shouldBackgroundReloadRecord: () => false + shouldBackgroundReloadRecord() { return false; } })); - Person.reopen({ - name: DS.attr('string'), - upperName: Ember.computed(function() { - return this.get('name').toUpperCase(); - }).property('name') - }); - run(function () { + run(() => { store.push({ data: [{ id: '1', @@ -447,89 +434,83 @@ test("a filter created after a record is already loaded works", function(assert) }] }); }); - var filter; - run(function() { - filter = store.filter('person', function(person) { - return person.get('upperName') === "TOM DALE"; - }); + let filter = run(() => { + return store.filter('person', person => person.get('upperName') === 'TOM DALE'); }); - assert.equal(filter.get('length'), 1, "the filter now has a record in it"); + assert.equal(filter.get('length'), 1, 'the filter now has a record in it'); assert.asyncEqual(filter.objectAt(0), store.findRecord('person', 1)); }); -test("filter with query persists query on the resulting filteredRecordArray", function(assert) { +test('filter with query persists query on the resulting filteredRecordArray', function(assert) { customAdapter(env, DS.Adapter.extend({ query(store, type, id) { - return Ember.RSVP.resolve([{ - id: id, - name: "Tom Dale" - }]); + return [ + { + id: id, + name: 'Tom Dale' + } + ]; } })); - var filter; - - run(function() { - filter = store.filter('person', { foo: 1 }, function(person) { - return true; - }); + let filter = run(() => { + return store.filter('person', { foo: 1 }, person => true); }); - Ember.run(function() { - filter.then(function(array) { + return run(() => { + return filter.then(array => { assert.deepEqual(get(array, 'query'), { foo: 1 }, 'has expected query'); }); }); }); - -test("it is possible to filter by state flags", function(assert) { - var filter; - +test('it is possible to filter by state flags', function(assert) { customAdapter(env, DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: id, name: "Tom Dale" }); + return { + id, + name: 'Tom Dale' + }; } })); - run(function() { - filter = store.filter('person', function(person) { - return person.get('isLoaded'); - }); + let filter = run(() => { + return store.filter('person', person => person.get('isLoaded')); }); - assert.equal(filter.get('length'), 0, "precond - there are no records yet"); + assert.equal(filter.get('length'), 0, 'precond - there are no records yet'); - Ember.run(function() { - var asyncPerson = store.findRecord('person', 1); + let person = run(() => { + let person = store.findRecord('person', 1); - // Ember.run will block `find` from being synchronously + // run will block `find` from being synchronously // resolved in test mode - assert.equal(filter.get('length'), 0, "the unloaded record isn't in the filter"); + assert.equal(filter.get('length'), 0, 'the unloaded record isn\'t in the filter'); + return person; + }); - asyncPerson.then(assert.wait(function(person) { - assert.equal(filter.get('length'), 1, "the now-loaded record is in the filter"); - assert.asyncEqual(filter.objectAt(0), store.findRecord('person', 1)); - })); + return person.then(person => { + assert.equal(filter.get('length'), 1, 'the now-loaded record is in the filter'); + assert.asyncEqual(filter.objectAt(0), store.findRecord('person', 1)); }); }); -test("it is possible to filter loaded records by dirtiness", function(assert) { +test('it is possible to filter loaded records by dirtiness', function(assert) { customAdapter(env, DS.Adapter.extend({ - updateRecord() { - return Ember.RSVP.resolve(); + updateRecord(type, model, snapshot) { + return { id: snapshot.id }; }, - shouldBackgroundReloadRecord: () => false + shouldBackgroundReloadRecord() { + return false; + } })); - var filter = store.filter('person', function(person) { - return !person.get('hasDirtyAttributes'); - }); + let filter = store.filter('person', person => !person.get('hasDirtyAttributes')); - run(function () { + run(() => { store.push({ data: [{ id: '1', @@ -541,225 +522,240 @@ test("it is possible to filter loaded records by dirtiness", function(assert) { }); }); - store.findRecord('person', 1).then(assert.wait(function(person) { - assert.equal(filter.get('length'), 1, "the clean record is in the filter"); + return store.findRecord('person', 1).then(person => { + assert.equal(filter.get('length'), 1, 'the clean record is in the filter'); // Force synchronous update of the filter, even though // we're already inside a run loop - Ember.run(function() { - person.set('name', "Yehuda Katz"); - }); + run(() => person.set('name', 'Yehuda Katz')); - assert.equal(filter.get('length'), 0, "the now-dirty record is not in the filter"); + assert.equal(filter.get('length'), 0, 'the now-dirty record is not in the filter'); return person.save(); - })).then(assert.wait(function(person) { - assert.equal(filter.get('length'), 1, "the clean record is back in the filter"); - })); + }).then(person => { + assert.equal(filter.get('length'), 1, 'the clean record is back in the filter'); + }); }); -test("it is possible to filter created records by dirtiness", function(assert) { - run(function() { +test('it is possible to filter created records by dirtiness', function(assert) { + run(() => { customAdapter(env, DS.Adapter.extend({ - createRecord() { - return Ember.RSVP.resolve(); + createRecord(type, model, snapshot) { + return Ember.merge(Ember.merge({}, snapshot._attributes), { id: snapshot.id} ) }, - shouldBackgroundReloadRecord: () => false + shouldBackgroundReloadRecord() { return false; } })); }); - var filter; - - run(function() { - filter = store.filter('person', function(person) { - return !person.get('hasDirtyAttributes'); - }); + let filter = run(() => { + return store.filter('person', person => !person.get('hasDirtyAttributes')); }); - var person; - - run(function() { - person = store.createRecord('person', { + let person = run(() => { + return store.createRecord('person', { id: 1, - name: "Tom Dale" + name: 'Tom Dale' }); }); - assert.equal(filter.get('length'), 0, "the dirty record is not in the filter"); + assert.equal(filter.get('length'), 0, 'the dirty record is not in the filter'); - run(function() { - person.save().then(function(person) { - assert.equal(filter.get('length'), 1, "the clean record is in the filter"); + return run(() => { + return person.save().then(person => { + assert.equal(filter.get('length'), 1, 'the clean record is in the filter'); }); }); }); -test("it is possible to filter created records by isReloading", function(assert) { +test('it is possible to filter created records by isReloading', function(assert) { customAdapter(env, DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return Ember.RSVP.resolve({ + return { id: 1, - name: "Tom Dalle" - }); + name: 'Tom Dalle' + }; } })); - var filter = store.filter('person', function(person) { + let filter = store.filter('person', person => { return !person.get('isReloading'); }); - var person = store.createRecord('person', { + let person = store.createRecord('person', { id: 1, - name: "Tom Dale" + name: 'Tom Dale' }); - person.reload().then(assert.wait(function(person) { - assert.equal(filter.get('length'), 1, "the filter correctly returned a reloaded object"); + return person.reload().then(assert.wait(person => { + assert.equal(filter.get('length'), 1, 'the filter correctly returned a reloaded object'); })); }); - // SERVER SIDE TESTS -var edited; +let edited; -var clientEdits = function(ids) { +function clientEdits(ids) { edited = []; - ids.forEach((id) => { - // wrap in an Ember.run to guarantee coalescence of the + ids.forEach(id => { + // wrap in an run to guarantee coalescence of the // iterated `set` calls and promise resolution. - Ember.run(function() { - store.findRecord('person', id).then(function(person) { + run(() => { + store.findRecord('person', id).then(person => { edited.push(person); person.set('name', 'Client-side ' + id ); }); }); }); -}; - -var clientCreates = function(names) { - edited = []; +} - // wrap in an Ember.run to guarantee coalescence of the +function clientCreates(names) { + // wrap in an run to guarantee coalescence of the // iterated `set` calls. - Ember.run(function() { - names.forEach(function(name) { - edited.push(store.createRecord('person', { name: 'Client-side ' + name })); - }); + edited = run(() => { + return names.map(name => store.createRecord('person', { name: 'Client-side ' + name })); }); -}; +} -var serverResponds = function() { - edited.forEach(function(person) { run(person, 'save'); }); -}; +function serverResponds() { + edited.forEach(person => run(person, 'save')); +} -var setup = function(assert, serverCallbacks) { - run(function() { - customAdapter(env, DS.Adapter.extend(serverCallbacks)); +function setup(assert, serverCallbacks) { + customAdapter(env, DS.Adapter.extend(serverCallbacks)); - store.push({ data: array }); + run(() => { + store.push({ data }); - recordArray = store.filter('person', function(hash) { - if (hash.get('name').match(/Scumbag/)) { return true; } + recordArray = store.filter('person', hash => { + if (hash.get('name').match(/Scumbag/)) { + return true; + } }); }); - assert.equal(get(recordArray, 'length'), 3, "The filter function should work"); -}; + assert.equal(get(recordArray, 'length'), 3, 'The filter function should work'); +} -test("a Record Array can update its filter after server-side updates one record", function(assert) { +test('a Record Array can update its filter after server-side updates one record', function(assert) { setup(assert, { updateRecord(store, type, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: "Scumbag Server-side Dale" }); + return { + id: 1, + name: 'Scumbag Server-side Dale' + }; }, - shouldBackgroundReloadRecord: () => false + shouldBackgroundReloadRecord() { return false; } }); clientEdits([1]); - assert.equal(get(recordArray, 'length'), 2, "The record array updates when the client changes records"); + assert.equal(get(recordArray, 'length'), 2, 'The record array updates when the client changes records'); serverResponds(); - assert.equal(get(recordArray, 'length'), 3, "The record array updates when the server changes one record"); + assert.equal(get(recordArray, 'length'), 3, 'The record array updates when the server changes one record'); }); -test("a Record Array can update its filter after server-side updates multiple records", function(assert) { +test('a Record Array can update its filter after server-side updates multiple records', function(assert) { setup(assert, { updateRecord(store, type, snapshot) { switch (snapshot.id) { - case "1": - return Ember.RSVP.resolve({ id: 1, name: "Scumbag Server-side Dale" }); - case "2": - return Ember.RSVP.resolve({ id: 2, name: "Scumbag Server-side Katz" }); + case '1': + return { + id: 1, + name: 'Scumbag Server-side Dale' + }; + case '2': + return { + id: 2, + name: 'Scumbag Server-side Katz' + }; } }, - shouldBackgroundReloadRecord: () => false + shouldBackgroundReloadRecord() { return false; } }); - clientEdits([1,2]); - assert.equal(get(recordArray, 'length'), 1, "The record array updates when the client changes records"); + clientEdits([1, 2]); + assert.equal(get(recordArray, 'length'), 1, 'The record array updates when the client changes records'); serverResponds(); - assert.equal(get(recordArray, 'length'), 3, "The record array updates when the server changes multiple records"); + assert.equal(get(recordArray, 'length'), 3, 'The record array updates when the server changes multiple records'); }); -test("a Record Array can update its filter after server-side creates one record", function(assert) { +test('a Record Array can update its filter after server-side creates one record', function(assert) { setup(assert, { createRecord(store, type, snapshot) { - return Ember.RSVP.resolve({ id: 4, name: "Scumbag Server-side Tim" }); + return { + id: 4, + name: 'Scumbag Server-side Tim' + }; } }); - clientCreates(["Tim"]); - assert.equal(get(recordArray, 'length'), 3, "The record array does not include non-matching records"); + clientCreates(['Tim']); + assert.equal(get(recordArray, 'length'), 3, 'The record array does not include non-matching records'); serverResponds(); - assert.equal(get(recordArray, 'length'), 4, "The record array updates when the server creates a record"); + assert.equal(get(recordArray, 'length'), 4, 'The record array updates when the server creates a record'); }); -test("a Record Array can update its filter after server-side creates multiple records", function(assert) { +test('a Record Array can update its filter after server-side creates multiple records', function(assert) { setup(assert, { createRecord(store, type, snapshot) { switch (snapshot.attr('name')) { - case "Client-side Mike": - return Ember.RSVP.resolve({ id: 4, name: "Scumbag Server-side Mike" }); - case "Client-side David": - return Ember.RSVP.resolve({ id: 5, name: "Scumbag Server-side David" }); + case 'Client-side Mike': + return { + id: 4, + name: 'Scumbag Server-side Mike' + }; + case 'Client-side David': + return { + id: 5, + name: 'Scumbag Server-side David' + }; } } }); - clientCreates(["Mike", "David"]); - assert.equal(get(recordArray, 'length'), 3, "The record array does not include non-matching records"); + clientCreates(['Mike', 'David']); + assert.equal(get(recordArray, 'length'), 3, 'The record array does not include non-matching records'); serverResponds(); - assert.equal(get(recordArray, 'length'), 5, "The record array updates when the server creates multiple records"); + assert.equal(get(recordArray, 'length'), 5, 'The record array updates when the server creates multiple records'); }); -test("a Record Array can update its filter after server-side creates multiple records", function(assert) { +test('a Record Array can update its filter after server-side creates multiple records', function(assert) { setup(assert, { createRecord(store, type, snapshot) { switch (snapshot.attr('name')) { - case "Client-side Mike": - return Ember.RSVP.resolve({ id: 4, name: "Scumbag Server-side Mike" }); - case "Client-side David": - return Ember.RSVP.resolve({ id: 5, name: "Scumbag Server-side David" }); + case 'Client-side Mike': + return { + id: 4, + name: 'Scumbag Server-side Mike' + }; + case 'Client-side David': + return { + id: 5, + name: 'Scumbag Server-side David' + }; } } }); - clientCreates(["Mike", "David"]); - assert.equal(get(recordArray, 'length'), 3, "The record array does not include non-matching records"); + clientCreates(['Mike', 'David']); + assert.equal(get(recordArray, 'length'), 3, 'The record array does not include non-matching records'); serverResponds(); - assert.equal(get(recordArray, 'length'), 5, "The record array updates when the server creates multiple records"); + assert.equal(get(recordArray, 'length'), 5, 'The record array updates when the server creates multiple records'); }); -test("destroying filteredRecordArray unregisters models from being filtered", function(assert) { - var filterFn = tapFn(function() { return true; }); +test('destroying filteredRecordArray unregisters models from being filtered', function(assert) { + const filterFn = tapFn(() => true); + customAdapter(env, DS.Adapter.extend({ - shouldBackgroundReloadRecord: () => false + shouldBackgroundReloadRecord() { return false; } })); - run(function () { + + run(() => { store.push({ data: [{ id: '1', @@ -771,19 +767,12 @@ test("destroying filteredRecordArray unregisters models from being filtered", fu }); }); - var recordArray; - - run(function() { - recordArray = store.filter('person', filterFn); - }); + const recordArray = run(() => store.filter('person', filterFn)); assert.equal(filterFn.summary.called.length, 1); - Ember.run(function() { - recordArray.then(function(array) { - array.destroy(); - }); - }); + run(() => recordArray.then(array => array.destroy())); + clientEdits([1]); assert.equal(filterFn.summary.called.length, 1, 'expected the filter function not being called anymore'); From 677d255c9fa2a5e44c78a70b0f7331e86fa684f6 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 18 Oct 2016 01:24:35 +0300 Subject: [PATCH 1623/2527] tidy up record array manager * var -> let * destructuring * remove unused `Ember.A` * misc cleanup --- addon/-private/system/record-array-manager.js | 88 +++++++++---------- 1 file changed, 42 insertions(+), 46 deletions(-) diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 4c40c396de9..473040a25e6 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -8,9 +8,8 @@ import { FilteredRecordArray, AdapterPopulatedRecordArray } from "ember-data/-private/system/record-arrays"; -var MapWithDefault = Ember.MapWithDefault; +const { get, MapWithDefault } = Ember; import OrderedSet from "ember-data/-private/system/ordered-set"; -var get = Ember.get; const { _addRecordToRecordArray, @@ -68,9 +67,7 @@ export default Ember.Object.extend({ }); this.liveRecordArrays = MapWithDefault.create({ - defaultValue: (typeClass) => { - return this.createRecordArray(typeClass); - } + defaultValue: typeClass => this.createRecordArray(typeClass) }); this.changedRecords = []; @@ -102,8 +99,9 @@ export default Ember.Object.extend({ */ updateRecordArrays() { heimdall.increment(updateRecordArrays); - this.changedRecords.forEach((internalModel) => { - if (get(internalModel, 'record.isDestroyed') || get(internalModel, 'record.isDestroying') || + this.changedRecords.forEach(internalModel => { + if (get(internalModel, 'record.isDestroyed') || + get(internalModel, 'record.isDestroying') || (get(internalModel, 'currentState.stateName') === 'root.deleted.saved')) { this._recordWasDeleted(internalModel); } else { @@ -116,11 +114,11 @@ export default Ember.Object.extend({ _recordWasDeleted(record) { heimdall.increment(_recordWasDeleted); - var recordArrays = record._recordArrays; + let recordArrays = record._recordArrays; if (!recordArrays) { return; } - recordArrays.forEach((array) => array.removeInternalModel(record)); + recordArrays.forEach(array => array.removeInternalModel(record)); record._recordArrays = null; }, @@ -128,10 +126,10 @@ export default Ember.Object.extend({ _recordWasChanged(record) { heimdall.increment(_recordWasChanged); - var typeClass = record.type; - var recordArrays = this.filteredRecordArrays.get(typeClass); - var filter; - recordArrays.forEach((array) => { + let typeClass = record.type; + let recordArrays = this.filteredRecordArrays.get(typeClass); + let filter; + recordArrays.forEach(array => { filter = get(array, 'filterFunction'); this.updateFilterRecordArray(array, filter, typeClass, record); }); @@ -140,17 +138,17 @@ export default Ember.Object.extend({ //Need to update live arrays on loading recordWasLoaded(record) { heimdall.increment(recordWasLoaded); - var typeClass = record.type; - var recordArrays = this.filteredRecordArrays.get(typeClass); - var filter; + let typeClass = record.type; + let recordArrays = this.filteredRecordArrays.get(typeClass); + let filter; - recordArrays.forEach((array) => { + recordArrays.forEach(array => { filter = get(array, 'filterFunction'); this.updateFilterRecordArray(array, filter, typeClass, record); }); if (this.liveRecordArrays.has(typeClass)) { - var liveRecordArray = this.liveRecordArrays.get(typeClass); + let liveRecordArray = this.liveRecordArrays.get(typeClass); this._addRecordToRecordArray(liveRecordArray, record); } }, @@ -165,8 +163,8 @@ export default Ember.Object.extend({ */ updateFilterRecordArray(array, filter, typeClass, record) { heimdall.increment(updateFilterRecordArray); - var shouldBeInArray = filter(record.getRecord()); - var recordArrays = this.recordArraysForRecord(record); + let shouldBeInArray = filter(record.getRecord()); + let recordArrays = this.recordArraysForRecord(record); if (shouldBeInArray) { this._addRecordToRecordArray(array, record); } else { @@ -177,7 +175,7 @@ export default Ember.Object.extend({ _addRecordToRecordArray(array, record) { heimdall.increment(_addRecordToRecordArray); - var recordArrays = this.recordArraysForRecord(record); + let recordArrays = this.recordArraysForRecord(record); if (!recordArrays.has(array)) { array.addInternalModel(record); recordArrays.add(array); @@ -186,11 +184,11 @@ export default Ember.Object.extend({ populateLiveRecordArray(array, modelName) { heimdall.increment(populateLiveRecordArray); - var typeMap = this.store.typeMapFor(modelName); - var records = typeMap.records; - var record; + let typeMap = this.store.typeMapFor(modelName); + let records = typeMap.records; + let record; - for (var i = 0; i < records.length; i++) { + for (let i = 0; i < records.length; i++) { record = records[i]; if (!record.isDeleted() && !record.isEmpty()) { @@ -213,11 +211,11 @@ export default Ember.Object.extend({ */ updateFilter(array, modelName, filter) { heimdall.increment(updateFilter); - var typeMap = this.store.typeMapFor(modelName); - var records = typeMap.records; - var record; + let typeMap = this.store.typeMapFor(modelName); + let records = typeMap.records; + let record; - for (var i = 0; i < records.length; i++) { + for (let i = 0; i < records.length; i++) { record = records[i]; if (!record.isDeleted() && !record.isEmpty()) { @@ -248,15 +246,13 @@ export default Ember.Object.extend({ */ createRecordArray(typeClass) { heimdall.increment(createRecordArray); - var array = RecordArray.create({ + return RecordArray.create({ type: typeClass, content: Ember.A(), store: this.store, isLoaded: true, manager: this }); - - return array; }, /** @@ -270,7 +266,7 @@ export default Ember.Object.extend({ */ createFilteredRecordArray(typeClass, filter, query) { heimdall.increment(createFilteredRecordArray); - var array = FilteredRecordArray.create({ + let array = FilteredRecordArray.create({ query: query, type: typeClass, content: Ember.A(), @@ -294,7 +290,7 @@ export default Ember.Object.extend({ */ createAdapterPopulatedRecordArray(typeClass, query) { heimdall.increment(createAdapterPopulatedRecordArray); - var array = AdapterPopulatedRecordArray.create({ + let array = AdapterPopulatedRecordArray.create({ type: typeClass, query: query, content: Ember.A(), @@ -320,7 +316,7 @@ export default Ember.Object.extend({ */ registerFilteredRecordArray(array, typeClass, filter) { heimdall.increment(registerFilteredRecordArray); - var recordArrays = this.filteredRecordArrays.get(typeClass); + let recordArrays = this.filteredRecordArrays.get(typeClass); recordArrays.push(array); this.updateFilter(array, typeClass, filter); @@ -335,32 +331,32 @@ export default Ember.Object.extend({ */ unregisterRecordArray(array) { heimdall.increment(unregisterRecordArray); - var typeClass = array.type; + + let typeClass = array.type; // unregister filtered record array - const recordArrays = this.filteredRecordArrays.get(typeClass); - const removedFromFiltered = remove(recordArrays, array); + let recordArrays = this.filteredRecordArrays.get(typeClass); + let removedFromFiltered = remove(recordArrays, array); // remove from adapter populated record array - const removedFromAdapterPopulated = remove(this._adapterPopulatedRecordArrays, array); + let removedFromAdapterPopulated = remove(this._adapterPopulatedRecordArrays, array); if (!removedFromFiltered && !removedFromAdapterPopulated) { // unregister live record array if (this.liveRecordArrays.has(typeClass)) { - var liveRecordArrayForType = this.liveRecordArrayFor(typeClass); + let liveRecordArrayForType = this.liveRecordArrayFor(typeClass); if (array === liveRecordArrayForType) { this.liveRecordArrays.delete(typeClass); } } - } }, willDestroy() { this._super(...arguments); - this.filteredRecordArrays.forEach((value) => flatten(value).forEach(destroy)); + this.filteredRecordArrays.forEach(value => flatten(value).forEach(destroy)); this.liveRecordArrays.forEach(destroy); this._adapterPopulatedRecordArrays.forEach(destroy); } @@ -372,10 +368,10 @@ function destroy(entry) { function flatten(list) { heimdall.increment(array_flatten); - var length = list.length; - var result = Ember.A(); + let length = list.length; + let result = []; - for (var i = 0; i < length; i++) { + for (let i = 0; i < length; i++) { result = result.concat(list[i]); } @@ -384,7 +380,7 @@ function flatten(list) { function remove(array, item) { heimdall.increment(array_remove); - const index = array.indexOf(item); + let index = array.indexOf(item); if (index !== -1) { array.splice(index, 1); From ec4ccf90f4591e1254682fe82ad817c1d09127a9 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 18 Oct 2016 11:40:31 +0300 Subject: [PATCH 1624/2527] cleanup states --- addon/-private/system/model/states.js | 86 +++++++++++++-------------- 1 file changed, 40 insertions(+), 46 deletions(-) diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index 934d6e4fa6d..23fddd3ae71 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -4,7 +4,7 @@ import Ember from 'ember'; import { assert } from "ember-data/-private/debug"; -var get = Ember.get; +const { get } = Ember; /* This file encapsulates the various states that a record can transition through during its lifecycle. @@ -224,7 +224,7 @@ function didSetProperty(internalModel, context) { // but the adapter has not yet acknowledged success. // `invalid`: the record has invalid information and cannot be // sent to the adapter yet. -var DirtyState = { +const DirtyState = { initialState: 'uncommitted', // FLAGS @@ -237,11 +237,11 @@ var DirtyState = { // have not yet begun to be saved, and are not invalid. uncommitted: { // EVENTS - didSetProperty: didSetProperty, + didSetProperty, //TODO(Igor) reloading now triggers a //loadingData event, though it seems fine? - loadingData: Ember.K, + loadingData() { }, propertyWasReset(internalModel, name) { if (!internalModel.hasChangedAttributes()) { internalModel.send('rolledBack'); } @@ -257,7 +257,7 @@ var DirtyState = { heimdall.stop(token); }, - becomeDirty: Ember.K, + becomeDirty() { }, willCommit(internalModel) { internalModel.transitionTo('inFlight'); @@ -289,20 +289,18 @@ var DirtyState = { isSaving: true, // EVENTS - didSetProperty: didSetProperty, - becomeDirty: Ember.K, - pushedData: Ember.K, + didSetProperty, + becomeDirty() { }, + pushedData() { }, unloadRecord: assertAgainstUnloadRecord, // TODO: More robust semantics around save-while-in-flight - willCommit: Ember.K, + willCommit() { }, didCommit(internalModel) { - var dirtyType = get(this, 'dirtyType'); - internalModel.transitionTo('saved'); - internalModel.send('invokeLifecycleCallbacks', dirtyType); + internalModel.send('invokeLifecycleCallbacks', this.dirtyType); }, becameInvalid(internalModel) { @@ -337,9 +335,9 @@ var DirtyState = { } }, - becameInvalid: Ember.K, - becomeDirty: Ember.K, - pushedData: Ember.K, + becameInvalid() { }, + becomeDirty() { }, + pushedData() { }, willCommit(internalModel) { internalModel.clearErrorMessages(); @@ -367,10 +365,10 @@ var DirtyState = { // necessary. function deepClone(object) { - var clone = {}; - var value; + const clone = {}; + let value; - for (var prop in object) { + for (let prop in object) { value = object[prop]; if (value && typeof value === 'object') { clone[prop] = deepClone(value); @@ -383,7 +381,7 @@ function deepClone(object) { } function mixin(original, hash) { - for (var prop in hash) { + for (let prop in hash) { original[prop] = hash[prop]; } @@ -395,7 +393,7 @@ function dirtyState(options) { return mixin(newState, options); } -var createdState = dirtyState({ +const createdState = dirtyState({ dirtyType: 'created', // FLAGS isNew: true @@ -404,11 +402,12 @@ var createdState = dirtyState({ createdState.invalid.rolledBack = function(internalModel) { internalModel.transitionTo('deleted.saved'); }; + createdState.uncommitted.rolledBack = function(internalModel) { internalModel.transitionTo('deleted.saved'); }; -var updatedState = dirtyState({ +const updatedState = dirtyState({ dirtyType: 'updated' }); @@ -443,7 +442,7 @@ updatedState.uncommitted.deleteRecord = function(internalModel) { internalModel.transitionTo('deleted.uncommitted'); }; -var RootState = { +const RootState = { // FLAGS isEmpty: false, isLoading: false, @@ -460,7 +459,7 @@ var RootState = { // doesn't change your state. For example, if you're in the // in-flight state, rolling back the record doesn't move // you out of the in-flight state. - rolledBack: Ember.K, + rolledBack() { }, unloadRecord(internalModel) { // clear relationships before moving to deleted state // otherwise it fails @@ -468,8 +467,7 @@ var RootState = { internalModel.transitionTo('deleted.saved'); }, - - propertyWasReset: Ember.K, + propertyWasReset() { }, // SUBSTATES @@ -542,7 +540,7 @@ var RootState = { //TODO(Igor) Reloading now triggers a loadingData event, //but it should be ok? - loadingData: Ember.K, + loadingData() { }, // SUBSTATES @@ -556,9 +554,9 @@ var RootState = { }, // EVENTS - didSetProperty: didSetProperty, + didSetProperty, - pushedData: Ember.K, + pushedData() { }, becomeDirty(internalModel) { internalModel.transitionTo('updated.uncommitted'); @@ -589,8 +587,7 @@ var RootState = { // loaded.saved.notFound would be triggered by a failed // `reload()` on an unchanged record - notFound: Ember.K - + notFound() { } }, // A record is in this state after it has been locally @@ -637,9 +634,9 @@ var RootState = { internalModel.triggerLater('ready'); }, - pushedData: Ember.K, - becomeDirty: Ember.K, - deleteRecord: Ember.K, + pushedData() { }, + becomeDirty() { }, + deleteRecord() { }, rolledBack(internalModel) { internalModel.transitionTo('loaded.saved'); @@ -660,7 +657,7 @@ var RootState = { unloadRecord: assertAgainstUnloadRecord, // TODO: More robust semantics around save-while-in-flight - willCommit: Ember.K, + willCommit() { }, didCommit(internalModel) { internalModel.transitionTo('saved'); @@ -696,9 +693,8 @@ var RootState = { internalModel.triggerLater('didCommit', internalModel); }, - willCommit: Ember.K, - - didCommit: Ember.K + willCommit() { }, + didCommit() { } }, invalid: { @@ -714,10 +710,10 @@ var RootState = { } }, - becameInvalid: Ember.K, - becomeDirty: Ember.K, - deleteRecord: Ember.K, - willCommit: Ember.K, + becameInvalid() { }, + becomeDirty() { }, + deleteRecord() { }, + willCommit() { }, rolledBack(internalModel) { @@ -750,16 +746,14 @@ function wireState(object, parent, name) { object.parentState = parent; object.stateName = name; - for (var prop in object) { + for (let prop in object) { if (!object.hasOwnProperty(prop) || prop === 'parentState' || prop === 'stateName') { continue; } if (typeof object[prop] === 'object') { - object[prop] = wireState(object[prop], object, name + "." + prop); + object[prop] = wireState(object[prop], object, name + '.' + prop); } } return object; } -RootState = wireState(RootState, null, "root"); - -export default RootState; +export default wireState(RootState, null, 'root'); From bd96f61a89152b980ae1b422b62e6d7bcff1985f Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 18 Oct 2016 12:27:48 +0300 Subject: [PATCH 1625/2527] No longer reach into internalModel.record in record-array-manager --- addon/-private/system/model/internal-model.js | 6 ++++++ addon/-private/system/record-array-manager.js | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 6cfab4699b6..236dd1617af 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -106,6 +106,7 @@ export default function InternalModel(type, id, store, _, data) { this.recordReference = new RecordReference(store, this); this.references = {}; this.isReloading = false; + this._isDestroyed = false; this.isError = false; this.error = null; this.__ember_meta__ = null; @@ -272,7 +273,12 @@ InternalModel.prototype = { } }, + get isDestroyed() { + return this._isDestroyed; + }, + destroy() { + this._isDestroyed = true; if (this.record) { return this.record.destroy(); } diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 473040a25e6..1b44f1279d3 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -100,9 +100,9 @@ export default Ember.Object.extend({ updateRecordArrays() { heimdall.increment(updateRecordArrays); this.changedRecords.forEach(internalModel => { - if (get(internalModel, 'record.isDestroyed') || - get(internalModel, 'record.isDestroying') || - (get(internalModel, 'currentState.stateName') === 'root.deleted.saved')) { + + if (internalModel.isDestroyed || + internalModel.currentState.stateName === 'root.deleted.saved') { this._recordWasDeleted(internalModel); } else { this._recordWasChanged(internalModel); From 139076454150fdf5cbc3a9e23dc232a0f45e72a0 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 18 Oct 2016 08:50:47 -0400 Subject: [PATCH 1626/2527] Update changelog for the Ember Data 2.9.0 release --- CHANGELOG.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4eca5499a0d..a03620a89ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,27 @@ ### Master +### Release 2.9.0 (October 18, 2016) +- [#4577](https://github.com/emberjs/data/pull/4577) [DOC] fix typo +- [#4529](https://github.com/emberjs/data/pull/4529) isUpdating should be true only if a reload happens +- [#4566](https://github.com/emberjs/data/pull/4566) Properly cleanup store and env in store integration test +- [#4567](https://github.com/emberjs/data/pull/4567) [bugfix beta] Treat status code 0 as an abort +- [#4559](https://github.com/emberjs/data/pull/4559) [BUGFIX beta] Use Ember.guidFor to set InternalModel's guid. +- [#4560](https://github.com/emberjs/data/pull/4560) [BUGFIX beta] Ensure record array length is reset during willDestroy. +- [#4545](https://github.com/emberjs/data/pull/4545) [BUGFIX beta] Make `Model#data` a plain getter. +- [#4541](https://github.com/emberjs/data/pull/4541) [DOC beta] Remove `Ember.ArrayController` from initializer example (#4540) +- [#4540](https://github.com/emberjs/data/pull/4540) Add examples to the build-url-mixin API docs (#4512) +- [#4537](https://github.com/emberjs/data/pull/4537) [BUGFIX beta] Ember Data should not swallow exceptions from the run loop +- [#4546](https://github.com/emberjs/data/pull/4546) Revert "Log an assertion if the response from createRecord does not have an i…" +- [#4536](https://github.com/emberjs/data/pull/4536) [DOC] fix features response typo (#4530) +- [#4490](https://github.com/emberjs/data/pull/4490) [DOCS] No need to use Ember.run in succes and failure of wrapped getJSON +- [#4493](https://github.com/emberjs/data/pull/4493) Addresses #4492 +- [#4503](https://github.com/emberjs/data/pull/4503) Update ember-try config to test against alpha. +- [#4515](https://github.com/emberjs/data/pull/4515) Document the allowNull property on the boolean transform +- [#4516](https://github.com/emberjs/data/pull/4516) Update the docs for normalizeModelName so they explain the intent of … +- [#4521](https://github.com/emberjs/data/pull/4521) Remove ContainerProxy +- [#4522](https://github.com/emberjs/data/pull/4522) add license to bower.json + ### Release 2.8.1 (September 23, 2016) - [#4536](https://github.com/emberjs/data/pull/4536) bump to latest ember-cli, run ember init, cleanup post init - [#4546](https://github.com/emberjs/data/pull/4546) Revert "Log an assertion if the response from createRecord does not have an I…" From e27e29e0ed6e9ca2f257198005d361a782cad404 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 18 Oct 2016 09:03:24 -0400 Subject: [PATCH 1627/2527] Remove ds-links-in-record-array feature flag --- .../adapter-populated-record-array.js | 5 +- config/features.json | 1 - .../adapter-populated-record-array-test.js | 68 +++++++++---------- 3 files changed, 33 insertions(+), 41 deletions(-) diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index fb28d6e8c43..7727e85bf72 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -1,7 +1,6 @@ import Ember from 'ember'; import RecordArray from "ember-data/-private/system/record-arrays/record-array"; import cloneNull from "ember-data/-private/system/clone-null"; -import isEnabled from 'ember-data/-private/features'; /** @module ember-data @@ -52,9 +51,7 @@ export default RecordArray.extend({ meta: cloneNull(payload.meta) }); - if (isEnabled('ds-links-in-record-array')) { - this.set('links', cloneNull(payload.links)); - } + this.set('links', cloneNull(payload.links)); internalModels.forEach((record) => { this.manager.recordArraysForRecord(record).add(this); diff --git a/config/features.json b/config/features.json index 607aa00310d..4bbc510cd77 100644 --- a/config/features.json +++ b/config/features.json @@ -3,7 +3,6 @@ "ds-improved-ajax": true, "ds-pushpayload-return": null, "ds-extended-errors": null, - "ds-links-in-record-array": true, "ds-overhaul-references": null, "ds-payload-type-hooks": null, "ds-check-should-serialize-relationships": null, diff --git a/tests/unit/adapter-populated-record-array-test.js b/tests/unit/adapter-populated-record-array-test.js index ca185142a1e..b430ae031a0 100644 --- a/tests/unit/adapter-populated-record-array-test.js +++ b/tests/unit/adapter-populated-record-array-test.js @@ -5,8 +5,6 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; - var Person, store; var run = Ember.run; @@ -104,43 +102,41 @@ test("stores the metadata off the payload", function(assert) { assert.equal(recordArray.get('meta.foo'), 'bar', 'expected meta.foo to be bar from payload'); }); -if (isEnabled('ds-links-in-record-array')) { - test('stores the links off the payload', function(assert) { - var recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray(store.modelFor('person'), null); - var payload = { - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Scumbag Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Scumbag Katz' - } - }, { - type: 'person', - id: '3', - attributes: { - name: 'Scumbag Bryn' - } - }], - links: { - first: '/foo?page=1' +test('stores the links off the payload', function(assert) { + var recordArray = store.recordArrayManager + .createAdapterPopulatedRecordArray(store.modelFor('person'), null); + var payload = { + data: [{ + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale' } - }; - - run(function() { - var records = store.push(payload); - recordArray.loadRecords(records, payload); - }); + }, { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz' + } + }, { + type: 'person', + id: '3', + attributes: { + name: 'Scumbag Bryn' + } + }], + links: { + first: '/foo?page=1' + } + }; - assert.equal(recordArray.get('links.first'), '/foo?page=1', 'expected links.first to be "/foo?page=1" from payload'); + run(function() { + var records = store.push(payload); + recordArray.loadRecords(records, payload); }); -} + + assert.equal(recordArray.get('links.first'), '/foo?page=1', 'expected links.first to be "/foo?page=1" from payload'); +}); test('recordArray.replace() throws error', function(assert) { var recordArray = store.recordArrayManager From 50fcc466b42895a4385f530b074366e053267da1 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 18 Oct 2016 09:55:26 -0400 Subject: [PATCH 1628/2527] Bump the canary version on master --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7d5bfaf31db..7f2a8a273cd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.10.0-canary", + "version": "2.11.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From a8a3e83dc2b2d482f6e8fc46202dbd894f13b77e Mon Sep 17 00:00:00 2001 From: MarkMT Date: Tue, 18 Oct 2016 11:30:30 -0500 Subject: [PATCH 1629/2527] Show file names in code example headers --- addon/-private/system/store.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b85c386a807..4cb529aa76f 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -619,8 +619,7 @@ Store = Service.extend({ model, when we retrieve a specific post we can have the server also return that post's comments in the same request: - ``` - // app/routes/post.js + ```app/routes/post.js import Ember from 'ember'; export default Ember.Route.extend({ @@ -638,8 +637,7 @@ Store = Service.extend({ using a dot-separated sequence of relationship names. So to request both the post's comments and the authors of those comments the request would look like this: - ``` - // app/routes/post.js + ```app/routes/post.js import Ember from 'ember'; export default Ember.Route.extend({ @@ -1451,8 +1449,7 @@ Store = Service.extend({ model, when we retrieve all of the post records we can have the server also return all of the posts' comments in the same request: - ``` - // app/routes/posts.js + ```app/routes/posts.js import Ember from 'ember'; export default Ember.Route.extend({ @@ -1467,8 +1464,7 @@ Store = Service.extend({ using a dot-separated sequence of relationship names. So to request both the posts' comments and the authors of those comments the request would look like this: - ``` - // app/routes/posts.js + ```app/routes/posts.js import Ember from 'ember'; export default Ember.Route.extend({ From fe039213b2642b6364e976149eca0957fdab4c9a Mon Sep 17 00:00:00 2001 From: pangratz Date: Tue, 18 Oct 2016 20:57:13 +0300 Subject: [PATCH 1630/2527] Fix YUIDoc warnings --- addon/-private/adapters/build-url-mixin.js | 10 +++++----- addon/serializers/embedded-records-mixin.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index b2b1a09314b..6fa1315c1e5 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -360,11 +360,11 @@ export default Ember.Mixin.create({ }); ``` - * @method urlForDeleteRecord - * @param {String} id - * @param {String} modelName - * @param {DS.Snapshot} snapshot - * @return {String} url + @method urlForDeleteRecord + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url */ urlForDeleteRecord(id, modelName, snapshot) { return this._buildURL(modelName, id); diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index b7dd3359b1e..ad345370fb5 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -395,7 +395,7 @@ export default Ember.Mixin.create({ } }, - /** + /* Serializes a hasMany relationship as an array of objects containing only `id` and `type` keys. This has its use case on polymorphic hasMany relationships where the server is not storing From 7b5103e4a6201304676057bfab0f95d469c463f2 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 10:21:12 +0300 Subject: [PATCH 1631/2527] fix whitespace --- addon/-private/system/record-array-manager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 1b44f1279d3..e1d597741b5 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -102,7 +102,7 @@ export default Ember.Object.extend({ this.changedRecords.forEach(internalModel => { if (internalModel.isDestroyed || - internalModel.currentState.stateName === 'root.deleted.saved') { + internalModel.currentState.stateName === 'root.deleted.saved') { this._recordWasDeleted(internalModel); } else { this._recordWasChanged(internalModel); @@ -123,7 +123,6 @@ export default Ember.Object.extend({ record._recordArrays = null; }, - _recordWasChanged(record) { heimdall.increment(_recordWasChanged); let typeClass = record.type; @@ -152,6 +151,7 @@ export default Ember.Object.extend({ this._addRecordToRecordArray(liveRecordArray, record); } }, + /** Update an individual filter. From 3a5a197c2577ee2cdf6b71a47515740d5ad48737 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 10:45:47 +0300 Subject: [PATCH 1632/2527] tidy-up promise-proxies --- addon/-private/system/promise-proxies.js | 36 ++++++++---------------- 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/addon/-private/system/promise-proxies.js b/addon/-private/system/promise-proxies.js index 59f5efb30e8..83c503b558b 100644 --- a/addon/-private/system/promise-proxies.js +++ b/addon/-private/system/promise-proxies.js @@ -1,8 +1,7 @@ import Ember from 'ember'; import { assert } from "ember-data/-private/debug"; -var Promise = Ember.RSVP.Promise; -var get = Ember.get; +const { get , RSVP: { Promise }} = Ember; /** A `PromiseArray` is an object that acts like both an `Ember.Array` @@ -33,7 +32,7 @@ var get = Ember.get; @extends Ember.ArrayProxy @uses Ember.PromiseProxyMixin */ -var PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin); +export const PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin); /** A `PromiseObject` is an object that acts like both an `Ember.Object` @@ -64,19 +63,19 @@ var PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin); @extends Ember.ObjectProxy @uses Ember.PromiseProxyMixin */ -var PromiseObject = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin); +export const PromiseObject = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin); -var promiseObject = function(promise, label) { +export function promiseObject(promise, label) { return PromiseObject.create({ promise: Promise.resolve(promise, label) }); -}; +} -var promiseArray = function(promise, label) { +export function promiseArray(promise, label) { return PromiseArray.create({ promise: Promise.resolve(promise, label) }); -}; +} /** A PromiseManyArray is a PromiseArray that also proxies certain method calls @@ -96,14 +95,13 @@ var promiseArray = function(promise, label) { @extends Ember.ArrayProxy */ -function proxyToContent(method) { +export function proxyToContent(method) { return function() { - var content = get(this, 'content'); - return content[method].apply(content, arguments); + return get(this, 'content')[method](...arguments); }; } -var PromiseManyArray = PromiseArray.extend({ +export const PromiseManyArray = PromiseArray.extend({ reload() { //I don't think this should ever happen right now, but worth guarding if we refactor the async relationships assert('You are trying to reload an async manyArray before it has been created', get(this, 'content')); @@ -125,18 +123,8 @@ var PromiseManyArray = PromiseArray.extend({ has: proxyToContent('has') }); -var promiseManyArray = function(promise, label) { +export function promiseManyArray(promise, label) { return PromiseManyArray.create({ promise: Promise.resolve(promise, label) }); -}; - - -export { - PromiseArray, - PromiseObject, - PromiseManyArray, - promiseArray, - promiseObject, - promiseManyArray -}; +} From fef544ff20367289e797d3f1ddeffc976db3b38b Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 10:45:58 +0300 Subject: [PATCH 1633/2527] tidy up adapter-populated-record-array --- .../adapter-populated-record-array.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index fb28d6e8c43..5c69bde359b 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -7,7 +7,7 @@ import isEnabled from 'ember-data/-private/features'; @module ember-data */ -var get = Ember.get; +const { get } = Ember; /** Represents an ordered list of records whose order and membership is @@ -20,11 +20,14 @@ var get = Ember.get; @extends DS.RecordArray */ export default RecordArray.extend({ - query: null, + init() { + this._super(...arguments); + this.query = this.query || null; + }, replace() { - var type = get(this, 'type').toString(); - throw new Error("The result of a server query (on " + type + ") is immutable."); + let type = get(this, 'type').toString(); + throw new Error(`The result of a server query (on ${type}) is immutable.`); }, _update() { @@ -44,7 +47,7 @@ export default RecordArray.extend({ loadRecords(records, payload) { let token = heimdall.start('AdapterPopulatedRecordArray.loadRecords'); //TODO Optimize - var internalModels = Ember.A(records).mapBy('_internalModel'); + let internalModels = records.map(record => get(record, '_internalModel')); this.setProperties({ content: Ember.A(internalModels), isLoaded: true, @@ -56,7 +59,7 @@ export default RecordArray.extend({ this.set('links', cloneNull(payload.links)); } - internalModels.forEach((record) => { + internalModels.forEach(record => { this.manager.recordArraysForRecord(record).add(this); }); From adc884f5046535530cb0c05e7091a81cdb2b412a Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 10:46:07 +0300 Subject: [PATCH 1634/2527] tidy up filtered-record-array --- .../record-arrays/filtered-record-array.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/addon/-private/system/record-arrays/filtered-record-array.js b/addon/-private/system/record-arrays/filtered-record-array.js index 87b5cffdccf..2a3a870dea1 100644 --- a/addon/-private/system/record-arrays/filtered-record-array.js +++ b/addon/-private/system/record-arrays/filtered-record-array.js @@ -5,7 +5,7 @@ import RecordArray from "ember-data/-private/system/record-arrays/record-array"; @module ember-data */ -var get = Ember.get; +const { get } = Ember; /** Represents a list of records whose membership is determined by the @@ -18,6 +18,12 @@ var get = Ember.get; @extends DS.RecordArray */ export default RecordArray.extend({ + init() { + this._super(...arguments); + + this.filterFunction = this.filterFunction || null; + this.isLoaded = true; + }, /** The filterFunction is a function used to test records from the store to determine if they should be part of the record array. @@ -44,12 +50,10 @@ export default RecordArray.extend({ @param {DS.Model} record @return {Boolean} `true` if the record should be in the array */ - filterFunction: null, - isLoaded: true, replace() { - var type = get(this, 'type').toString(); - throw new Error("The result of a client-side filter (on " + type + ") is immutable."); + let type = get(this, 'type').toString(); + throw new Error(`The result of a client-side filter (on ${type}) is immutable.`); }, /** @@ -57,8 +61,7 @@ export default RecordArray.extend({ @private */ _updateFilter() { - var manager = get(this, 'manager'); - manager.updateFilter(this, get(this, 'type'), get(this, 'filterFunction')); + get(this, 'manager').updateFilter(this, get(this, 'type'), get(this, 'filterFunction')); }, updateFilter: Ember.observer('filterFunction', function() { From f33d0fcc227f4dc084d4ee3502949081213dcd48 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 10:46:13 +0300 Subject: [PATCH 1635/2527] tidy up record-array --- .../system/record-arrays/record-array.js | 97 +++++++++---------- 1 file changed, 47 insertions(+), 50 deletions(-) diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index 4200ce9feac..baaeeb2e4d3 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -6,8 +6,7 @@ import Ember from 'ember'; import { PromiseArray } from "ember-data/-private/system/promise-proxies"; import SnapshotRecordArray from "ember-data/-private/system/snapshot-record-array"; -var get = Ember.get; -var set = Ember.set; +const { get, set, RSVP: { Promise } } = Ember; /** A record array is an array that contains records of a certain type. The record @@ -23,27 +22,30 @@ var set = Ember.set; */ export default Ember.ArrayProxy.extend(Ember.Evented, { - /** - The model type contained by this record array. - - @property type - @type DS.Model - */ - type: null, - - /** - The array of client ids backing the record array. When a - record is requested from the record array, the record - for the client id at the same index is materialized, if - necessary, by the store. - - @property content - @private - @type Ember.Array - */ - content: null, - - /** + init() { + this._super(...arguments); + + /** + The model type contained by this record array. + + @property type + @type DS.Model + */ + this.type = this.type || null; + + /** + The array of client ids backing the record array. When a + record is requested from the record array, the record + for the client id at the same index is materialized, if + necessary, by the store. + + @property content + @private + @type Ember.Array + */ + this.content = this.content || null; + + /** The flag to signal a `RecordArray` is finished loading data. Example @@ -55,9 +57,9 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @property isLoaded @type Boolean - */ - isLoaded: false, - /** + */ + this.isLoaded = this.isLoaded || false; + /** The flag to signal a `RecordArray` is currently loading data. Example @@ -71,21 +73,21 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @property isUpdating @type Boolean - */ - isUpdating: false, + */ + this.isUpdating = this.isUpdating || false; - /** + /** The store that created this record array. @property store @private @type DS.Store - */ - store: null, - + */ + this.store = this.store || null; + }, replace() { - var type = get(this, 'type').toString(); - throw new Error("The result of a server query (for all " + type + " types) is immutable. To modify contents, use toArray()"); + let type = get(this, 'type').toString(); + throw new Error(`The result of a server query (for all ${type} types) is immutable. To modify contents, use toArray()`); }, /** @@ -97,8 +99,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @return {DS.Model} record */ objectAtContent(index) { - var content = get(this, 'content'); - var internalModel = content.objectAt(index); + let internalModel = get(this, 'content').objectAt(index); return internalModel && internalModel.getRecord(); }, @@ -148,7 +149,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @param {number} an optional index to insert at */ addInternalModel(internalModel, idx) { - var content = get(this, 'content'); + let content = get(this, 'content'); if (idx === undefined) { content.addObject(internalModel); } else if (!content.includes(internalModel)) { @@ -184,18 +185,16 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @return {DS.PromiseArray} promise */ save() { - var recordArray = this; - var promiseLabel = "DS: RecordArray#save " + get(this, 'type'); - var promise = Ember.RSVP.all(this.invoke("save"), promiseLabel).then(function(array) { - return recordArray; - }, null, "DS: RecordArray#save return RecordArray"); + let promiseLabel = 'DS: RecordArray#save ' + get(this, 'type'); + let promise = Promise.all(this.invoke('save'), promiseLabel). + then(() => this, null, 'DS: RecordArray#save return RecordArray'); - return PromiseArray.create({ promise: promise }); + return PromiseArray.create({ promise }); }, _dissociateFromOwnRecords() { - this.get('content').forEach((record) => { - var recordArrays = record._recordArrays; + this.get('content').forEach(record => { + let recordArrays = record._recordArrays; if (recordArrays) { recordArrays.delete(this); @@ -208,8 +207,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @private */ _unregisterFromManager() { - var manager = get(this, 'manager'); - manager.unregisterRecordArray(this); + get(this, 'manager').unregisterRecordArray(this); }, willDestroy() { @@ -217,11 +215,10 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { this._dissociateFromOwnRecords(); set(this, 'content', undefined); set(this, 'length', 0); - this._super.apply(this, arguments); + this._super(...arguments); }, createSnapshot(options) { - const meta = this.get('meta'); - return new SnapshotRecordArray(this, meta, options); + return new SnapshotRecordArray(this, this.get('meta'), options); } }); From 26f9a571a815d17c8a9290398ac4f39e2b263c7e Mon Sep 17 00:00:00 2001 From: Ryan Cook Date: Mon, 28 Mar 2016 12:31:09 -0700 Subject: [PATCH 1636/2527] store#unloadRecord to destroy record. add test to show record is destroyed and observers removed --- addon/-private/system/model/model.js | 4 +-- addon/-private/system/store.js | 4 +-- tests/unit/store/unload-test.js | 39 +++++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index cddcd8693f6..1fe2d3c5e13 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -122,8 +122,8 @@ var Model = Ember.Object.extend(Ember.Evented, { @type {Boolean} @readOnly */ - hasDirtyAttributes: Ember.computed('currentState.isDirty', function() { - return this.get('currentState.isDirty'); + hasDirtyAttributes: Ember.computed('currentState', function() { + return this.get('_internalModel.currentState.isDirty'); }), /** If this property is `true` the record is in the `saving` state. A diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 8953f59f7dc..51285823bda 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -420,6 +420,7 @@ Store = Service.extend({ */ unloadRecord(record) { record.unloadRecord(); + record.destroy(); }, // ................ @@ -1621,8 +1622,7 @@ Store = Service.extend({ for (let i = 0; i < records.length; i++) { record = records[i]; - record.unloadRecord(); - record.destroy(); // maybe within unloadRecord + this.unloadRecord(record); } typeMap.metadata = new EmptyObject(); diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index f2a131ff676..2379bcb0477 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -66,7 +66,7 @@ testInDebug("unload a dirty record asserts", function(assert) { }); test("unload a record", function(assert) { - assert.expect(5); + assert.expect(6); run(function() { store.push({ @@ -87,6 +87,7 @@ test("unload a record", function(assert) { }); assert.equal(get(record, 'hasDirtyAttributes'), false, "record is not dirty"); + assert.equal(get(record, 'isDestroyed'), true, 'record is destroyed'); assert.equal(get(record, 'isDeleted'), true, "record is deleted"); tryToFind = false; @@ -97,6 +98,42 @@ test("unload a record", function(assert) { }); }); +test("unload a record - observers should be removed", function(assert) { + assert.expect(4); + + run(function() { + store.push({ + data: { + type: 'record', + id: '1', + attributes: { + title: 'toto' + } + } + }); + + store.findRecord('record', 1).then(function(record) { + Ember.addObserver(record, 'title', record, function() { + assert.ok(false, 'observer for record.title'); + }); + + let observers = Ember.observersFor(record, 'title'); + assert.equal(observers.length, 1, 'record should have 1 observer'); + + run(function() { + store.unloadRecord(record); + }); + + run(function() { + let observers = Ember.observersFor(record, 'title'); + assert.equal(get(record, 'isDeleted'), true, 'record is deleted'); + assert.equal(get(record, 'isDestroyed'), true, 'record is destroyed'); + assert.equal(observers.length, 0, 'record should not have observers'); + }); + }); + }); +}); + module("DS.Store - unload record with relationships"); From 2f723beb9417c944502ff00f630d0cdd0bccc307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Clemens=20M=C3=BCller?= Date: Wed, 19 Oct 2016 18:39:57 +0300 Subject: [PATCH 1637/2527] Revert "unloadRecord does not remove observers" --- addon/-private/system/model/model.js | 4 +-- addon/-private/system/store.js | 4 +-- tests/unit/store/unload-test.js | 39 +--------------------------- 3 files changed, 5 insertions(+), 42 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 1fe2d3c5e13..cddcd8693f6 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -122,8 +122,8 @@ var Model = Ember.Object.extend(Ember.Evented, { @type {Boolean} @readOnly */ - hasDirtyAttributes: Ember.computed('currentState', function() { - return this.get('_internalModel.currentState.isDirty'); + hasDirtyAttributes: Ember.computed('currentState.isDirty', function() { + return this.get('currentState.isDirty'); }), /** If this property is `true` the record is in the `saving` state. A diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 51285823bda..8953f59f7dc 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -420,7 +420,6 @@ Store = Service.extend({ */ unloadRecord(record) { record.unloadRecord(); - record.destroy(); }, // ................ @@ -1622,7 +1621,8 @@ Store = Service.extend({ for (let i = 0; i < records.length; i++) { record = records[i]; - this.unloadRecord(record); + record.unloadRecord(); + record.destroy(); // maybe within unloadRecord } typeMap.metadata = new EmptyObject(); diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index 2379bcb0477..f2a131ff676 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -66,7 +66,7 @@ testInDebug("unload a dirty record asserts", function(assert) { }); test("unload a record", function(assert) { - assert.expect(6); + assert.expect(5); run(function() { store.push({ @@ -87,7 +87,6 @@ test("unload a record", function(assert) { }); assert.equal(get(record, 'hasDirtyAttributes'), false, "record is not dirty"); - assert.equal(get(record, 'isDestroyed'), true, 'record is destroyed'); assert.equal(get(record, 'isDeleted'), true, "record is deleted"); tryToFind = false; @@ -98,42 +97,6 @@ test("unload a record", function(assert) { }); }); -test("unload a record - observers should be removed", function(assert) { - assert.expect(4); - - run(function() { - store.push({ - data: { - type: 'record', - id: '1', - attributes: { - title: 'toto' - } - } - }); - - store.findRecord('record', 1).then(function(record) { - Ember.addObserver(record, 'title', record, function() { - assert.ok(false, 'observer for record.title'); - }); - - let observers = Ember.observersFor(record, 'title'); - assert.equal(observers.length, 1, 'record should have 1 observer'); - - run(function() { - store.unloadRecord(record); - }); - - run(function() { - let observers = Ember.observersFor(record, 'title'); - assert.equal(get(record, 'isDeleted'), true, 'record is deleted'); - assert.equal(get(record, 'isDestroyed'), true, 'record is destroyed'); - assert.equal(observers.length, 0, 'record should not have observers'); - }); - }); - }); -}); - module("DS.Store - unload record with relationships"); From 4c261940650ab427c7b2c2792427905da6382033 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 11:46:46 +0300 Subject: [PATCH 1638/2527] [BUGFIX] recordArray.update() can now be called more then once --- .../system/record-arrays/record-array.js | 16 +- tests/unit/record-arrays/record-array-test.js | 138 ++++++++++++++++++ 2 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 tests/unit/record-arrays/record-array-test.js diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index baaeeb2e4d3..f7443ffd931 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -74,7 +74,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @property isUpdating @type Boolean */ - this.isUpdating = this.isUpdating || false; + this.isUpdating = false; /** The store that created this record array. @@ -84,6 +84,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @type DS.Store */ this.store = this.store || null; + this._updatingPromise = null; }, replace() { let type = get(this, 'type').toString(); @@ -123,10 +124,19 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method update */ update() { - if (get(this, 'isUpdating')) { return; } + if (get(this, 'isUpdating')) { return this._updatingPromise; } this.set('isUpdating', true); - return this._update(); + + let updatingPromise = this._update().finally(() => { + this._updatingPromise = null; + if (this.get('isDestroying') || this.get('isDestroyed')) { return } + this.set('isUpdating', false); + }); + + this._updatingPromise = updatingPromise; + + return updatingPromise; }, /* diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js new file mode 100644 index 00000000000..8c7e7d4240d --- /dev/null +++ b/tests/unit/record-arrays/record-array-test.js @@ -0,0 +1,138 @@ +import DS from 'ember-data'; +import Ember from 'ember'; +import { module, test } from 'qunit'; + +const { get, RSVP } = Ember; +const { RecordArray } = DS; + +module('unit/record-arrays/record-array - DS.RecordArray'); + +test('default initial state', function(assert) { + let recordArray = RecordArray.create({ type: 'recordType' }); + + assert.equal(get(recordArray, 'isLoaded'), false); + assert.equal(get(recordArray, 'isUpdating'), false); + assert.equal(get(recordArray, 'type'), 'recordType'); + assert.equal(get(recordArray, 'content'), null); + assert.equal(get(recordArray, 'store'), null); +}); + +test('custom initial state', function(assert) { + let content = []; + let store = {}; + let recordArray = RecordArray.create({ + type: 'apple', + isLoaded: true, + isUpdating: true, + content, + store + }) + assert.equal(get(recordArray, 'isLoaded'), true); + assert.equal(get(recordArray, 'isUpdating'), false); // cannot set as default value: + assert.equal(get(recordArray, 'type'), 'apple'); + assert.equal(get(recordArray, 'content'), content); + assert.equal(get(recordArray, 'store'), store); +}); + +test('#replace() throws error', function(assert) { + let recordArray = RecordArray.create({ type: 'recordType' }); + + assert.throws(function() { + recordArray.replace(); + }, Error('The result of a server query (for all recordType types) is immutable. To modify contents, use toArray()'), 'throws error'); +}); + +test('#objectAtContent', function(assert) { + let content = Ember.A([ + { getRecord() { return 'foo'; }}, + { getRecord() { return 'bar'; }}, + { getRecord() { return 'baz'; }} + ]); + + let recordArray = RecordArray.create({ + type: 'recordType', + content + }); + + assert.equal(get(recordArray, 'length'), 3); + assert.equal(recordArray.objectAtContent(0), 'foo'); + assert.equal(recordArray.objectAtContent(1), 'bar'); + assert.equal(recordArray.objectAtContent(2), 'baz'); + assert.equal(recordArray.objectAtContent(3), undefined); +}); + + +test('#update', function(assert) { + let findAllCalled = 0; + let deferred = RSVP.defer(); + + const store = { + findAll(modelName, options) { + findAllCalled++; + assert.equal(modelName, 'recordType'); + assert.equal(options.reload, true, 'options should contain reload: true'); + return deferred.promise; + } + }; + + let recordArray = RecordArray.create({ + type: { modelName: 'recordType' }, + store + }); + + assert.equal(get(recordArray, 'isUpdating'), false, 'should not yet be updating'); + + assert.equal(findAllCalled, 0); + + let updateResult = recordArray.update(); + + assert.equal(findAllCalled, 1); + + deferred.resolve('return value'); + + assert.equal(get(recordArray, 'isUpdating'), true, 'should be updating'); + + return updateResult.then(result => { + assert.equal(result, 'return value'); + assert.equal(get(recordArray, 'isUpdating'), false, 'should no longer be updating'); + }); +}); + + +test('#update while updating', function(assert) { + let findAllCalled = 0; + let deferred = RSVP.defer(); + const store = { + findAll(modelName, options) { + findAllCalled++; + return deferred.promise; + } + }; + + let recordArray = RecordArray.create({ + type: { modelName: 'recordType' }, + store + }); + + assert.equal(get(recordArray, 'isUpdating'), false, 'should not be updating'); + assert.equal(findAllCalled, 0); + + let updateResult1 = recordArray.update(); + + assert.equal(findAllCalled, 1); + + let updateResult2 = recordArray.update(); + + assert.equal(findAllCalled, 1); + + assert.equal(updateResult1, updateResult2); + + deferred.resolve('return value'); + + assert.equal(get(recordArray, 'isUpdating'), true, 'should be updating'); + + return updateResult1.then(result => { + assert.equal(result, 'return value'); + assert.equal(get(recordArray, 'isUpdating'), false, 'should no longer be updating'); + }); +}); From 8ed11450cc6057d5a88a94957dee70f347c2c001 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 12:22:18 +0300 Subject: [PATCH 1639/2527] cleanup RecordArray#addInternalModel * add tests * remove unused feature of passing in an optional index to insert at --- .../system/record-arrays/record-array.js | 10 ++-------- tests/unit/record-arrays/record-array-test.js | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index f7443ffd931..4d793af1ac0 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -156,15 +156,9 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @method addInternalModel @private @param {InternalModel} internalModel - @param {number} an optional index to insert at */ - addInternalModel(internalModel, idx) { - let content = get(this, 'content'); - if (idx === undefined) { - content.addObject(internalModel); - } else if (!content.includes(internalModel)) { - content.insertAt(idx, internalModel); - } + addInternalModel(internalModel) { + get(this, 'content').addObject(internalModel); }, /** diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js index 8c7e7d4240d..fb686bf9174 100644 --- a/tests/unit/record-arrays/record-array-test.js +++ b/tests/unit/record-arrays/record-array-test.js @@ -136,3 +136,19 @@ test('#update while updating', function(assert) { assert.equal(get(recordArray, 'isUpdating'), false, 'should no longer be updating'); }); }); + +test('#addInternalMdoel', function(assert) { + let content = Ember.A(); + let recordArray = RecordArray.create({ + content + }); + + let model1 = { getRecord() { return 'model-1'; } }; + + assert.equal(recordArray.addInternalModel(model1), undefined, 'addInternalModel has no return value'); + assert.deepEqual(content, [model1]); + + // cannot add duplicates + recordArray.addInternalModel(model1); + assert.deepEqual(content, [model1]); +}); From c066166c4d62721273345726e3cd90ca257f1c5e Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 12:38:16 +0300 Subject: [PATCH 1640/2527] test RecordArray#removeInternalModel --- tests/unit/record-arrays/record-array-test.js | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js index fb686bf9174..7e29c747b09 100644 --- a/tests/unit/record-arrays/record-array-test.js +++ b/tests/unit/record-arrays/record-array-test.js @@ -152,3 +152,32 @@ test('#addInternalMdoel', function(assert) { recordArray.addInternalModel(model1); assert.deepEqual(content, [model1]); }); + +test('#removeInternalModel', function(assert) { + let content = Ember.A(); + let recordArray = RecordArray.create({ + content + }); + + let model1 = { getRecord() { return 'model-1'; } }; + let model2 = { getRecord() { return 'model-2'; } }; + + assert.equal(content.length, 0); + assert.equal(recordArray.removeInternalModel(model1), undefined, 'removeInternalModel has no return value'); + assert.deepEqual(content, []); + + recordArray.addInternalModel(model1); + recordArray.addInternalModel(model2); + + assert.deepEqual(content, [model1, model2]); + assert.equal(recordArray.removeInternalModel(model1), undefined, 'removeInternalModel has no return value'); + assert.deepEqual(content, [model2]); + assert.equal(recordArray.removeInternalModel(model2), undefined, 'removeInternalModel has no return value'); + assert.deepEqual(content, []); +}); + +function internalModelFor(record) { + return { + getRecord() { return record; } + }; +} From 5f483eb03a38105883cf1468868c60e683fde223 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 12:38:38 +0300 Subject: [PATCH 1641/2527] test RecordArray#save --- tests/unit/record-arrays/record-array-test.js | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js index 7e29c747b09..40d2696261e 100644 --- a/tests/unit/record-arrays/record-array-test.js +++ b/tests/unit/record-arrays/record-array-test.js @@ -181,3 +181,31 @@ function internalModelFor(record) { getRecord() { return record; } }; } + +test('#save', function(assert) { + let model1 = { save() { model1Saved++; return this;} }; + let model2 = { save() { model2Saved++; return this;} }; + let content = Ember.A([ + internalModelFor(model1), + internalModelFor(model2) + ]); + + let recordArray = RecordArray.create({ + content + }); + + let model1Saved = 0; + let model2Saved = 0; + + assert.equal(model1Saved, 0); + assert.equal(model2Saved, 0); + + let result = recordArray.save(); + + assert.equal(model1Saved, 1); + assert.equal(model2Saved, 1); + + return result.then(result => { + assert.equal(result, result, 'save promise should fulfill with the original recordArray'); + }) +}); From 641e66779ecf0e839bc91e1552b0adce91a4372c Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 12:38:43 +0300 Subject: [PATCH 1642/2527] add whitespace --- addon/-private/system/record-arrays/record-array.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index 4d793af1ac0..aac92cf5d1d 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -86,6 +86,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { this.store = this.store || null; this._updatingPromise = null; }, + replace() { let type = get(this, 'type').toString(); throw new Error(`The result of a server query (for all ${type} types) is immutable. To modify contents, use toArray()`); From a69fdd7d07f6cb2e1476608e197e556c51ff80e9 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 14:00:15 +0300 Subject: [PATCH 1643/2527] Add tests for RecordArray.destroy * leave note for future work, e.g. the cleanup that is happening should likely not happen. --- .../system/record-arrays/record-array.js | 13 +++-- tests/unit/record-arrays/record-array-test.js | 50 ++++++++++++++++++- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index aac92cf5d1d..6a971ed5b54 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -198,8 +198,8 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { }, _dissociateFromOwnRecords() { - this.get('content').forEach(record => { - let recordArrays = record._recordArrays; + this.get('content').forEach(internalModel => { + let recordArrays = internalModel._recordArrays; if (recordArrays) { recordArrays.delete(this); @@ -218,7 +218,14 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { willDestroy() { this._unregisterFromManager(); this._dissociateFromOwnRecords(); - set(this, 'content', undefined); + // TODO: we should not do work during destroy: + // * when objects are destroyed, they should simply be left to do + // * if logic errors do to this, that logic needs to be more careful during + // teardown (ember provides isDestroying/isDestroyed) for this reason + // * the exception being: if an dominator has a reference to this object, + // and must be informed to release e.g. e.g. removing itself from th + // recordArrayMananger + set(this, 'content', null); set(this, 'length', 0); this._super(...arguments); }, diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js index 40d2696261e..c1791e89a69 100644 --- a/tests/unit/record-arrays/record-array-test.js +++ b/tests/unit/record-arrays/record-array-test.js @@ -2,7 +2,7 @@ import DS from 'ember-data'; import Ember from 'ember'; import { module, test } from 'qunit'; -const { get, RSVP } = Ember; +const { get, RSVP, run } = Ember; const { RecordArray } = DS; module('unit/record-arrays/record-array - DS.RecordArray'); @@ -178,6 +178,7 @@ test('#removeInternalModel', function(assert) { function internalModelFor(record) { return { + _recordArrays: undefined, getRecord() { return record; } }; } @@ -207,5 +208,50 @@ test('#save', function(assert) { return result.then(result => { assert.equal(result, result, 'save promise should fulfill with the original recordArray'); - }) + }); }); + +test('#destroy', function(assert) { + let didUnregisterRecordArray = 0; + let didDissociatieFromOwnRecords = 0; + let model1 = { }; + let internalModel1 = internalModelFor(model1); + + // TODO: this will be removed once we fix ownership related memory leaks. + internalModel1._recordArrays = { + delete(array) { + didDissociatieFromOwnRecords++; + assert.equal(array, recordArray); + } + }; + // end TODO: + + let recordArray = RecordArray.create({ + content: Ember.A([internalModel1]), + manager: { + unregisterRecordArray(_recordArray) { + didUnregisterRecordArray++; + assert.equal(recordArray, _recordArray); + } + } + }); + + assert.equal(get(recordArray, 'isDestroyed'), false, 'should not be destroyed'); + assert.equal(get(recordArray, 'isDestroying'), false, 'should not be destroying'); + + run(() => { + assert.equal(get(recordArray, 'length'), 1, 'before destroy, length should be 1'); + assert.equal(didUnregisterRecordArray, 0, 'before destroy, we should not yet have unregisterd the record array'); + assert.equal(didDissociatieFromOwnRecords, 0, 'before destroy, we should not yet have dissociated from own record array'); + recordArray.destroy(); + }); + + assert.equal(didUnregisterRecordArray, 1, 'after destroy we should have unregistered the record array'); + assert.equal(didDissociatieFromOwnRecords, 1, 'after destroy, we should have dissociated from own record array'); + recordArray.destroy(); + + assert.equal(get(recordArray, 'content'), null); + assert.equal(get(recordArray, 'length'), 0, 'after destroy we should have no length'); + assert.equal(get(recordArray, 'isDestroyed'), true, 'should be destroyed'); +}); + From b93ab53cc11575048ce591b5d6b81da0ddbd09d9 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 15:37:29 +0300 Subject: [PATCH 1644/2527] [BUGFIX] RecordArray snapshot works MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * recordArray.invoke(‘createSnapshot’) was previously invoked on the result of `internal.getRecord()` which no longer has createSnapshot, but `invoke` doesn’t error if a method isn’t found. * recordArray.snapshot is private, we should underscore it * add tests --- .../system/record-arrays/record-array.js | 15 +++++- .../-private/system/snapshot-record-array.js | 6 +-- addon/-private/system/store.js | 2 +- addon/-private/system/store/finders.js | 2 +- tests/unit/record-arrays/record-array-test.js | 31 +++++++++++- .../unit/system/snapshot-record-array-test.js | 49 +++++++++++++++++++ 6 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 tests/unit/system/snapshot-record-array-test.js diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index 6a971ed5b54..1d161f80a15 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -230,7 +230,20 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { this._super(...arguments); }, - createSnapshot(options) { + /** +r @method _createSnapshot + @private + */ + _createSnapshot(options) { + // this is private for users, but public for ember-data internals return new SnapshotRecordArray(this, this.get('meta'), options); + }, + + /** +r @method _takeSnapshot + @private + */ + _takeSnapshot() { + return get(this, 'content').map(internalModel => internalModel.createSnapshot()); } }); diff --git a/addon/-private/system/snapshot-record-array.js b/addon/-private/system/snapshot-record-array.js index 13076ccd657..ac76dd9498b 100644 --- a/addon/-private/system/snapshot-record-array.js +++ b/addon/-private/system/snapshot-record-array.js @@ -59,11 +59,11 @@ export default function SnapshotRecordArray(recordArray, meta, options = {}) { @return {Array} Array of snapshots */ SnapshotRecordArray.prototype.snapshots = function() { - if (this._snapshots) { + if (this._snapshots !== null) { return this._snapshots; } - var recordArray = this._recordArray; - this._snapshots = recordArray.invoke('createSnapshot'); + + this._snapshots = this._recordArray._takeSnapshot(); return this._snapshots; }; diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 0d1d8d20a44..eecffa1e76b 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1439,7 +1439,7 @@ Store = Service.extend({ return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); } - var snapshotArray = array.createSnapshot(options); + var snapshotArray = array._createSnapshot(options); if (adapter.shouldReloadAll(this, snapshotArray)) { set(array, 'isUpdating', true); diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 9d195657279..1681622fab7 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -136,7 +136,7 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship export function _findAll(adapter, store, typeClass, sinceToken, options) { var modelName = typeClass.modelName; var recordArray = store.peekAll(modelName); - var snapshotArray = recordArray.createSnapshot(options); + var snapshotArray = recordArray._createSnapshot(options); var promise = adapter.findAll(store, typeClass, sinceToken, snapshotArray); var serializer = serializerForAdapter(store, adapter, modelName); var label = "DS: Handle Adapter#findAll of " + typeClass; diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js index c1791e89a69..feb2312a274 100644 --- a/tests/unit/record-arrays/record-array-test.js +++ b/tests/unit/record-arrays/record-array-test.js @@ -179,7 +179,10 @@ test('#removeInternalModel', function(assert) { function internalModelFor(record) { return { _recordArrays: undefined, - getRecord() { return record; } + getRecord() { return record; }, + createSnapshot() { + return record; + } }; } @@ -255,3 +258,29 @@ test('#destroy', function(assert) { assert.equal(get(recordArray, 'isDestroyed'), true, 'should be destroyed'); }); +test('#_createSnapshot', function(assert) { + let model1 = { + id: 1 + }; + + let model2 = { + id: 2 + }; + + let content = Ember.A([ + internalModelFor(model1), + internalModelFor(model2) + ]); + + let recordArray = RecordArray.create({ + content + }); + + let snapshot = recordArray._createSnapshot(); + let snapshots = snapshot.snapshots(); + + assert.deepEqual(snapshots, [ + model1, + model2 + ], 'record array snapshot should contain the internalModel.createSnapshot result'); +}); diff --git a/tests/unit/system/snapshot-record-array-test.js b/tests/unit/system/snapshot-record-array-test.js new file mode 100644 index 00000000000..a5ee16b5ea5 --- /dev/null +++ b/tests/unit/system/snapshot-record-array-test.js @@ -0,0 +1,49 @@ +import SnapshotRecordArray from 'ember-data/-private/system/snapshot-record-array'; +import Ember from 'ember'; +import {module, test} from 'qunit'; + +module('Unit - snapshot-record-array'); + +test('constructor', function(assert) { + let array = Ember.A([1, 2]); + array.type = 'some type'; + let meta = { }; + let options = { + adapterOptions: 'some options', + include: 'include me' + }; + + let snapshot = new SnapshotRecordArray(array, meta, options); + + assert.equal(snapshot.length, 2); + assert.equal(snapshot.meta, meta); + assert.equal(snapshot.type, 'some type'); + assert.equal(snapshot.adapterOptions, 'some options'); + assert.equal(snapshot.include, 'include me'); +}); + +test('#snapshot', function(assert) { + let array = Ember.A([1, 2]); + let didTakeSnapshot = 0; + let snapshotTaken = {}; + + array.type = 'some type'; + array._takeSnapshot = function() { + didTakeSnapshot++; + return snapshotTaken; + }; + + let meta = { }; + let options = { + adapterOptions: 'some options', + include: 'include me' + }; + + let snapshot = new SnapshotRecordArray(array, meta, options); + + assert.equal(didTakeSnapshot, 0, 'no shapshot shouldn yet be taken'); + assert.equal(snapshot.snapshots(), snapshotTaken, 'should be correct snapshot'); + assert.equal(didTakeSnapshot, 1, 'one snapshot should have been taken'); + assert.equal(snapshot.snapshots(), snapshotTaken, 'should return the exact same snapshot'); + assert.equal(didTakeSnapshot, 1, 'still only one snapshot should have been taken'); +}); From c7fab1615767221416af41b0af6841270db4c0fc Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 15:38:18 +0300 Subject: [PATCH 1645/2527] test record-array#destroy --- tests/unit/record-arrays/record-array-test.js | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js index feb2312a274..21c4176ca5c 100644 --- a/tests/unit/record-arrays/record-array-test.js +++ b/tests/unit/record-arrays/record-array-test.js @@ -284,3 +284,48 @@ test('#_createSnapshot', function(assert) { model2 ], 'record array snapshot should contain the internalModel.createSnapshot result'); }); + +test('#destroy', function(assert) { + let didUnregisterRecordArray = 0; + let didDissociatieFromOwnRecords = 0; + let model1 = { }; + let internalModel1 = internalModelFor(model1); + + // TODO: this will be removed once we fix ownership related memory leaks. + internalModel1._recordArrays = { + delete(array) { + didDissociatieFromOwnRecords++; + assert.equal(array, recordArray); + } + }; + // end TODO: + + let recordArray = RecordArray.create({ + content: Ember.A([internalModel1]), + manager: { + unregisterRecordArray(_recordArray) { + didUnregisterRecordArray++; + assert.equal(recordArray, _recordArray); + } + } + }); + + assert.equal(get(recordArray, 'isDestroyed'), false, 'should not be destroyed'); + assert.equal(get(recordArray, 'isDestroying'), false, 'should not be destroying'); + + run(() => { + assert.equal(get(recordArray, 'length'), 1, 'before destroy, length should be 1'); + assert.equal(didUnregisterRecordArray, 0, 'before destroy, we should not yet have unregisterd the record array'); + assert.equal(didDissociatieFromOwnRecords, 0, 'before destroy, we should not yet have dissociated from own record array'); + recordArray.destroy(); + }); + + assert.equal(didUnregisterRecordArray, 1, 'after destroy we should have unregistered the record array'); + assert.equal(didDissociatieFromOwnRecords, 1, 'after destroy, we should have dissociated from own record array'); + recordArray.destroy(); + + assert.equal(get(recordArray, 'content'), null); + assert.equal(get(recordArray, 'length'), 0, 'after destroy we should have no length'); + assert.equal(get(recordArray, 'isDestroyed'), true, 'should be destroyed'); +}); + From 6bf9d46a2aae2ac7e9d13d3c06129a920c2c7f04 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 17:20:56 +0300 Subject: [PATCH 1646/2527] Fixup record-array/filtered-record-array * ensure filter function updates just before destroy are ignored * add unit test coverage for what makes filtered-record-arrays different then RecordArray --- .../record-arrays/filtered-record-array.js | 3 + .../filtered-record-array-test.js | 88 +++++++++++++++++-- 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/record-arrays/filtered-record-array.js b/addon/-private/system/record-arrays/filtered-record-array.js index 2a3a870dea1..83aa90ec69b 100644 --- a/addon/-private/system/record-arrays/filtered-record-array.js +++ b/addon/-private/system/record-arrays/filtered-record-array.js @@ -61,6 +61,9 @@ export default RecordArray.extend({ @private */ _updateFilter() { + if (get(this, 'isDestroying') || get(this, 'isDestroyed')) { + return; + } get(this, 'manager').updateFilter(this, get(this, 'type'), get(this, 'filterFunction')); }, diff --git a/tests/unit/record-arrays/filtered-record-array-test.js b/tests/unit/record-arrays/filtered-record-array-test.js index a8c08be4713..28fda273d31 100644 --- a/tests/unit/record-arrays/filtered-record-array-test.js +++ b/tests/unit/record-arrays/filtered-record-array-test.js @@ -1,17 +1,89 @@ import DS from 'ember-data'; +import Ember from 'ember'; import {module, test} from 'qunit'; -var filteredArray; +const { get } = Ember; +const { FilteredRecordArray } = DS; -module("unit/record-arrays/filtered-record-array - DS.FilteredRecordArray", { - beforeEach() { - filteredArray = DS.FilteredRecordArray.create({ type: 'recordType' }); - } +module('unit/record-arrays/filtered-record-array - DS.FilteredRecordArray'); + +test('default initial state', function(assert) { + let recordArray = FilteredRecordArray.create({ type: 'recordType' }); + + assert.equal(get(recordArray, 'isLoaded'), true); + assert.equal(get(recordArray, 'type'), 'recordType'); + assert.equal(get(recordArray, 'content'), null); + assert.equal(get(recordArray, 'filterFunction'), null); + assert.equal(get(recordArray, 'store'), null); +}); + +test('custom initial state', function(assert) { + let content = []; + let store = {}; + let filterFunction = () => true; + let recordArray = FilteredRecordArray.create({ + type: 'apple', + isLoaded: false, // ignored + isUpdating: true, + content, + store, + filterFunction + }) + assert.equal(get(recordArray, 'isLoaded'), true); + assert.equal(get(recordArray, 'isUpdating'), false); // cannot set as default value: + assert.equal(get(recordArray, 'type'), 'apple'); + assert.equal(get(recordArray, 'content'), content); + assert.equal(get(recordArray, 'store'), store); + assert.equal(get(recordArray, 'filterFunction'), filterFunction); }); -test('recordArray.replace() throws error', function(assert) { +test('#replace() throws error', function(assert) { + let recordArray = FilteredRecordArray.create({ type: 'recordType' }); + assert.throws(function() { - filteredArray.replace(); - }, Error("The result of a client-side filter (on recordType) is immutable."), 'throws error'); + recordArray.replace(); + }, Error('The result of a client-side filter (on recordType) is immutable.'), 'throws error'); }); + +test('updateFilter', function(assert) { + let didUpdateFilter = 0; + const updatedFilterFunction = () => true; + + const manager = { + updateFilter(array, type, filterFunction) { + didUpdateFilter++; + assert.equal(recordArray, array); + assert.equal(type, 'recordType'); + assert.equal(filterFunction, updatedFilterFunction); + }, + unregisterRecordArray() {} + }; + + let recordArray = FilteredRecordArray.create({ + type: 'recordType', + manager, + content: Ember.A() + }); + + assert.equal(didUpdateFilter, 0, 'no filterFunction should have been changed yet'); + + Ember.run(() => { + recordArray.set('filterFunction', updatedFilterFunction); + assert.equal(didUpdateFilter, 0, 'record array manager should not yet be informed of the filterFunction change'); + recordArray.set('filterFunction', updatedFilterFunction); + assert.equal(didUpdateFilter, 0, 'record array manager should not yet be informed of the filterFunction change') + }); + + assert.equal(didUpdateFilter, 1, 'record array manager should have been informed once that the array filterFunction has changed'); + + didUpdateFilter = 0; + Ember.run(() => { + recordArray.set('filterFunction', updatedFilterFunction); + assert.equal(didUpdateFilter, 0, 'record array manager should not be informed of this change'); + recordArray.destroy(); + assert.equal(didUpdateFilter, 0, 'record array manager should not be informed of this change'); + }); + + assert.equal(didUpdateFilter, 0, 'record array manager should not be informed of this change'); +}) From 1dd3aaa9524c89f6f38199d5233fe074a010e256 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 18:47:44 +0300 Subject: [PATCH 1647/2527] Fixup record-array/adapter-populate-record-array * add unit tests * fixup shape --- .../adapter-populated-record-array.js | 1 + .../adapter-populated-record-array-test.js | 147 ++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 tests/unit/record-arrays/adapter-populated-record-array-test.js diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index 5c69bde359b..da10adc7d7f 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -23,6 +23,7 @@ export default RecordArray.extend({ init() { this._super(...arguments); this.query = this.query || null; + this.links = null; }, replace() { diff --git a/tests/unit/record-arrays/adapter-populated-record-array-test.js b/tests/unit/record-arrays/adapter-populated-record-array-test.js new file mode 100644 index 00000000000..4ebeee1c5fa --- /dev/null +++ b/tests/unit/record-arrays/adapter-populated-record-array-test.js @@ -0,0 +1,147 @@ +import DS from 'ember-data'; + +import {module, test} from 'qunit'; +import Ember from 'ember'; + +const { RSVP, run } = Ember; +const { AdapterPopulatedRecordArray } = DS; + +module('unit/record-arrays/adapter-populated-record-array - DS.AdapterPopulatedRecordArray'); + +test('default initial state', function(assert) { + let recordArray = AdapterPopulatedRecordArray.create({ type: 'recordType' }); + + assert.equal(recordArray.get('isLoaded'), false, 'expected isLoaded to be false'); + assert.equal(recordArray.get('type'), 'recordType'); + assert.equal(recordArray.get('content'), null); + assert.equal(recordArray.get('query'), null); + assert.equal(recordArray.get('store'), null); + assert.equal(recordArray.get('links'), null); +}); + +test('custom initial state', function(assert) { + let content = []; + let store = {}; + let recordArray = AdapterPopulatedRecordArray.create({ + type: 'apple', + isLoaded: true, + isUpdating: true, + content, + store, + query: 'some-query', + links: 'foo' + }) + assert.equal(recordArray.get('isLoaded'), true); + assert.equal(recordArray.get('isUpdating'), false); + assert.equal(recordArray.get('type'), 'apple'); + assert.equal(recordArray.get('content'), content); + assert.equal(recordArray.get('store'), store); + assert.equal(recordArray.get('query'), 'some-query'); + assert.equal(recordArray.get('links'), null); +}); + +test('#replace() throws error', function(assert) { + let recordArray = AdapterPopulatedRecordArray.create({ type: 'recordType' }); + + assert.throws(() => { + recordArray.replace(); + }, Error('The result of a server query (on recordType) is immutable.'), 'throws error'); +}); + +test('#update uses _update enabling query specific behavior', function(assert) { + let queryCalled = 0; + let deferred = RSVP.defer(); + + const store = { + _query(modelName, query, array) { + queryCalled++; + assert.equal(modelName, 'recordType'); + assert.equal(query, 'some-query'); + assert.equal(array, recordArray); + + return deferred.promise; + } + }; + + let recordArray = AdapterPopulatedRecordArray.create({ + type: { modelName: 'recordType' }, + store, + query: 'some-query' + }); + + assert.equal(recordArray.get('isUpdating'), false, 'should not yet be updating'); + + assert.equal(queryCalled, 0); + + let updateResult = recordArray.update(); + + assert.equal(queryCalled, 1); + + deferred.resolve('return value'); + + assert.equal(recordArray.get('isUpdating'), true, 'should be updating'); + + return updateResult.then(result => { + assert.equal(result, 'return value'); + assert.equal(recordArray.get('isUpdating'), false, 'should no longer be updating'); + }); +}); + +// TODO: is this method required, i suspect store._query should be refactor so this is not needed +test('#loadRecords', function(assert) { + let didAddRecord = 0; + const manager = { + recordArraysForRecord(record) { + return { + add(array) { + didAddRecord++; + assert.equal(array, recordArray); + } + } + } + }; + + let recordArray = AdapterPopulatedRecordArray.create({ + query: 'some-query', + manager + }); + + let model1 = { + id: 2, + _internalModel: { getRecord() { return model1; }} + }; + + let model2 = { + id: 2, + _internalModel: { getRecord() { return model2; }} + }; + + assert.equal(didAddRecord, 0, 'no records should have been added yet'); + + let didLoad = 0; + recordArray.on('didLoad', function() { + didLoad++; + }); + + let links = { foo:1 }; + let meta = { bar:2 }; + + run(() => { + assert.equal(recordArray.loadRecords([model1, model2], { + links, + meta + }), undefined, 'loadRecords should have no return value'); + + assert.equal(didAddRecord, 2, 'two records should have been adde'); + + assert.deepEqual(recordArray.toArray(), [ + model1, + model2 + ], 'should now contain the loaded records'); + + assert.equal(didLoad, 0, 'didLoad event should not have fired'); + assert.equal(recordArray.get('links').foo, 1); + assert.equal(recordArray.get('meta').bar, 2); + }); + assert.equal(didLoad, 1, 'didLoad event should have fired once'); +}); From 8fdf8dbcb2fe2eb35f4933c12951d52b45aa53f6 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 19:16:07 +0300 Subject: [PATCH 1648/2527] tidy up integration/record-array-manager-test --- .../integration/record-array-manager-test.js | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index c62003a0284..2b12d21185d 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -5,23 +5,22 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var store, env; -var run = Ember.run; +let store, env, manager; -var Person = DS.Model.extend({ +const { run } = Ember; + +const Person = DS.Model.extend({ name: DS.attr('string'), cars: DS.hasMany('car', { async: false }) }); -var Car = DS.Model.extend({ +const Car = DS.Model.extend({ make: DS.attr('string'), model: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); -var manager; - -module("integration/record_array_manager", { +module('integration/record_array_manager', { beforeEach() { env = setupStore({ adapter: DS.RESTAdapter.extend() @@ -52,11 +51,11 @@ function tap(obj, methodName, callback) { return summary; } -test("destroying the store correctly cleans everything up", function(assert) { - var query = { }; - var person; +test('destroying the store correctly cleans everything up', function(assert) { + let query = { }; + let person; - run(function() { + run(() => { store.push({ data: { type: 'car', @@ -74,7 +73,7 @@ test("destroying the store correctly cleans everything up", function(assert) { }); }); - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -94,50 +93,54 @@ test("destroying the store correctly cleans everything up", function(assert) { person = store.peekRecord('person', 1); }); - var filterd = manager.createFilteredRecordArray(Person, function() { return true; }); - var filterd2 = manager.createFilteredRecordArray(Person, function() { return true; }); - var all = store.peekAll('person'); - var adapterPopulated = manager.createAdapterPopulatedRecordArray(Person, query); + let filterd = manager.createFilteredRecordArray(Person, () => true); + let filterd2 = manager.createFilteredRecordArray(Person, () => true); + let all = store.peekAll('person'); + let adapterPopulated = manager.createAdapterPopulatedRecordArray(Person, query); - var filterdSummary = tap(filterd, 'willDestroy'); - var filterd2Summary = tap(filterd2, 'willDestroy'); - var allSummary = tap(all, 'willDestroy'); - var adapterPopulatedSummary = tap(adapterPopulated, 'willDestroy'); + let filterdSummary = tap(filterd, 'willDestroy'); + let filterd2Summary = tap(filterd2, 'willDestroy'); + let allSummary = tap(all, 'willDestroy'); + let adapterPopulatedSummary = tap(adapterPopulated, 'willDestroy'); + + let internalPersonModel = person._internalModel; assert.equal(filterdSummary.called.length, 0); assert.equal(filterd2Summary.called.length, 0); assert.equal(allSummary.called.length, 0); assert.equal(adapterPopulatedSummary.called.length, 0); - assert.equal(person._internalModel._recordArrays.list.length, 3, 'expected the person to be a member of 3 recordArrays'); + assert.equal(manager.recordArraysForRecord(internalPersonModel).size, 3, 'expected the person to be a member of 3 recordArrays'); Ember.run(filterd2, filterd2.destroy); - assert.equal(person._internalModel._recordArrays.list.length, 2, 'expected the person to be a member of 2 recordArrays'); + + assert.equal(manager.recordArraysForRecord(internalPersonModel).size, 2, 'expected the person to be a member of 2 recordArrays'); assert.equal(filterd2Summary.called.length, 1); assert.equal(manager.liveRecordArrays.has(all.type), true); + Ember.run(all, all.destroy); - assert.equal(person._internalModel._recordArrays.list.length, 1, 'expected the person to be a member of 1 recordArrays'); + + assert.equal(manager.recordArraysForRecord(internalPersonModel).size, 1, 'expected the person to be a member of 1 recordArrays'); assert.equal(allSummary.called.length, 1); assert.equal(manager.liveRecordArrays.has(all.type), false); Ember.run(manager, manager.destroy); - assert.equal(person._internalModel._recordArrays.list.length, 0, 'expected the person to be a member of no recordArrays'); + + assert.equal(manager.recordArraysForRecord(internalPersonModel).size, 0, 'expected the person to be a member of no recordArrays'); assert.equal(filterdSummary.called.length, 1); assert.equal(filterd2Summary.called.length, 1); assert.equal(allSummary.called.length, 1); assert.equal(adapterPopulatedSummary.called.length, 1); }); -test("Should not filter a store.peekAll() array when a record property is changed", function(assert) { - var car; - - var populateLiveRecordArray = tap(store.recordArrayManager, 'populateLiveRecordArray'); - var updateFilterRecordArray = tap(store.recordArrayManager, 'updateFilterRecordArray'); +test('Should not filter a store.peekAll() array when a record property is changed', function(assert) { + let populateLiveRecordArray = tap(store.recordArrayManager, 'populateLiveRecordArray'); + let updateFilterRecordArray = tap(store.recordArrayManager, 'updateFilterRecordArray'); store.peekAll('car'); - run(function() { + let car = run(() => { store.push({ data: { type: 'car', @@ -153,19 +156,17 @@ test("Should not filter a store.peekAll() array when a record property is change } } }); - car = store.peekRecord('car', 1); + + return store.peekRecord('car', 1); }); assert.equal(populateLiveRecordArray.called.length, 1); assert.equal(updateFilterRecordArray.called.length, 0); - run(function() { - car.set('model', 'Mini'); - }); + run(() => car.set('model', 'Mini')); assert.equal(populateLiveRecordArray.called.length, 1); assert.equal(updateFilterRecordArray.called.length, 0); - }); test('#GH-4041 store#query AdapterPopulatedRecordArrays are removed from their managers instead of retained when #destroy is called', function(assert) { @@ -181,13 +182,12 @@ test('#GH-4041 store#query AdapterPopulatedRecordArrays are removed from their m } }); }); + const query = {}; - var adapterPopulated = manager.createAdapterPopulatedRecordArray(Car, query); + let adapterPopulated = manager.createAdapterPopulatedRecordArray(Car, query); - run(() => { - adapterPopulated.destroy(); - }); + run(() => adapterPopulated.destroy()); assert.equal(manager._adapterPopulatedRecordArrays.length, 0); }); From bf9caf9228c145ebd7fbed723ce740b26f4ab0e7 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 19:17:51 +0300 Subject: [PATCH 1649/2527] fix tests for 1.13 --- addon/-private/system/record-arrays/filtered-record-array.js | 2 +- addon/-private/system/record-arrays/record-array.js | 2 +- tests/unit/record-arrays/adapter-populated-record-array-test.js | 2 +- tests/unit/record-arrays/filtered-record-array-test.js | 2 +- tests/unit/record-arrays/record-array-test.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/addon/-private/system/record-arrays/filtered-record-array.js b/addon/-private/system/record-arrays/filtered-record-array.js index 83aa90ec69b..ccec9bba3bc 100644 --- a/addon/-private/system/record-arrays/filtered-record-array.js +++ b/addon/-private/system/record-arrays/filtered-record-array.js @@ -21,7 +21,7 @@ export default RecordArray.extend({ init() { this._super(...arguments); - this.filterFunction = this.filterFunction || null; + this.set('filterFunction', this.get('filterFunction') || null); this.isLoaded = true; }, /** diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index 1d161f80a15..68da7f38196 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -43,7 +43,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @private @type Ember.Array */ - this.content = this.content || null; + this.set('content', this.content || null); /** The flag to signal a `RecordArray` is finished loading data. diff --git a/tests/unit/record-arrays/adapter-populated-record-array-test.js b/tests/unit/record-arrays/adapter-populated-record-array-test.js index 4ebeee1c5fa..6385c704189 100644 --- a/tests/unit/record-arrays/adapter-populated-record-array-test.js +++ b/tests/unit/record-arrays/adapter-populated-record-array-test.js @@ -20,7 +20,7 @@ test('default initial state', function(assert) { }); test('custom initial state', function(assert) { - let content = []; + let content = Ember.A([]); let store = {}; let recordArray = AdapterPopulatedRecordArray.create({ type: 'apple', diff --git a/tests/unit/record-arrays/filtered-record-array-test.js b/tests/unit/record-arrays/filtered-record-array-test.js index 28fda273d31..dc9245e3081 100644 --- a/tests/unit/record-arrays/filtered-record-array-test.js +++ b/tests/unit/record-arrays/filtered-record-array-test.js @@ -19,7 +19,7 @@ test('default initial state', function(assert) { }); test('custom initial state', function(assert) { - let content = []; + let content = Ember.A(); let store = {}; let filterFunction = () => true; let recordArray = FilteredRecordArray.create({ diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js index 21c4176ca5c..ba693dae2f8 100644 --- a/tests/unit/record-arrays/record-array-test.js +++ b/tests/unit/record-arrays/record-array-test.js @@ -18,7 +18,7 @@ test('default initial state', function(assert) { }); test('custom initial state', function(assert) { - let content = []; + let content = Ember.A(); let store = {}; let recordArray = RecordArray.create({ type: 'apple', From 4b5fa40ddaba1df725cd46dc36fb36736fad841e Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Oct 2016 22:49:35 +0300 Subject: [PATCH 1650/2527] tidy up some record-array-tests * move to integration (as it is tests interaction between store/manager/array) * remove unit tests already covered by tests/unit/record-arrays/record-arrays-test * cleanup file --- .../record-array-test.js | 287 ++++++++---------- 1 file changed, 133 insertions(+), 154 deletions(-) rename tests/{unit => integration}/record-array-test.js (53%) diff --git a/tests/unit/record-array-test.js b/tests/integration/record-array-test.js similarity index 53% rename from tests/unit/record-array-test.js rename to tests/integration/record-array-test.js index ea43fe29b3e..de20880dc6f 100644 --- a/tests/unit/record-array-test.js +++ b/tests/integration/record-array-test.js @@ -6,70 +6,89 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var get = Ember.get; +const { get, run, RSVP: { Promise }} = Ember; -var Person, array; -var run = Ember.run; +let array; -module("unit/record_array - DS.RecordArray", { - beforeEach() { - array = [{ id: '1', name: "Scumbag Dale" }, { id: '2', name: "Scumbag Katz" }, { id: '3', name: "Scumbag Bryn" }]; +const Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: false }) +}); - Person = DS.Model.extend({ - name: DS.attr('string') - }); +const Tag = DS.Model.extend({ + people: DS.hasMany('person', { async: false }) +}); + +const Tool = DS.Model.extend({ + person: DS.belongsTo('person', { async: false }) +}); + +module('unit/record_array - DS.RecordArray', { + beforeEach() { + array = Ember.A([ + { id: '1', name: "Scumbag Dale" }, + { id: '2', name: "Scumbag Katz" }, + { id: '3', name: "Scumbag Bryn" } + ]); } }); -test("a record array is backed by records", function(assert) { +test('a record array is backed by records', function(assert) { assert.expect(3); - var store = createStore({ + let store = createStore({ person: Person, adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord: () => false + shouldBackgroundReloadRecord() { + return false; + } }) }); - run(function() { + + run(() => { store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Scumbag Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Scumbag Katz' - } - }, { - type: 'person', - id: '3', - attributes: { - name: 'Scumbag Bryn' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale' + } + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz' + } + }, + { + type: 'person', + id: '3', + attributes: { + name: 'Scumbag Bryn' + } + }] }); }); - run(function() { - store.findByIds('person', [1,2,3]).then(function(records) { - for (var i=0, l=get(array, 'length'); i { + return store.findByIds('person', [1,2,3]).then(records => { + for (let i=0, l = get(array, 'length'); i { store.push({ data: { type: 'person', @@ -80,9 +99,10 @@ test("acts as a live query", function(assert) { } }); }); + assert.equal(get(recordArray, 'lastObject.name'), 'wycats'); - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -96,15 +116,15 @@ test("acts as a live query", function(assert) { assert.equal(get(recordArray, 'lastObject.name'), 'brohuda'); }); -test("stops updating when destroyed", function(assert) { +test('stops updating when destroyed', function(assert) { assert.expect(3); - var store = createStore({ + let store = createStore({ person: Person }); - var recordArray = store.peekAll('person'); - run(function() { + let recordArray = store.peekAll('person'); + run(() => { store.push({ data: { type: 'person', @@ -116,12 +136,10 @@ test("stops updating when destroyed", function(assert) { }); }); - run(function() { - recordArray.destroy(); - }); + run(() => recordArray.destroy()); - run(function() { - assert.equal(recordArray.get('length'), 0, "Has no more records"); + run(() => { + assert.equal(recordArray.get('length'), 0, 'Has no more records'); store.push({ data: { type: 'person', @@ -133,32 +151,29 @@ test("stops updating when destroyed", function(assert) { }); }); - assert.equal(recordArray.get('length'), 0, "Has not been updated"); - assert.equal(recordArray.get('content'), undefined, "Has not been updated"); + assert.equal(recordArray.get('length'), 0, 'Has not been updated'); + assert.equal(recordArray.get('content'), undefined, 'Has not been updated'); }); -test("a loaded record is removed from a record array when it is deleted", function(assert) { +test('a loaded record is removed from a record array when it is deleted', function(assert) { assert.expect(5); - var Tag = DS.Model.extend({ - people: DS.hasMany('person', { async: false }) - }); - - Person.reopen({ - tag: DS.belongsTo('tag', { async: false }) - }); - - var env = setupStore({ + let env = setupStore({ tag: Tag, person: Person, adapter: DS.Adapter.extend({ - deleteRecord: () => Ember.RSVP.resolve(), - shouldBackgroundReloadRecord: () => false + deleteRecord() { + return Promise.resolve(); + }, + shouldBackgroundReloadRecord() { + return false; + } }) }); - var store = env.store; - run(function() { + let store = env.store; + + run(() => { store.push({ data: [{ type: 'person', @@ -185,53 +200,49 @@ test("a loaded record is removed from a record array when it is deleted", functi }); }); - run(function() { - var asyncRecords = Ember.RSVP.hash({ + return run(() => { + return Ember.RSVP.hash({ scumbag: store.findRecord('person', 1), tag: store.findRecord('tag', 1) - }); + }).then(records => { + let scumbag = records.scumbag; + let tag = records.tag; - asyncRecords.then(function(records) { - var scumbag = records.scumbag; - var tag = records.tag; + run(() => tag.get('people').addObject(scumbag)); - run(function() { - tag.get('people').addObject(scumbag); - }); assert.equal(get(scumbag, 'tag'), tag, "precond - the scumbag's tag has been set"); - var recordArray = tag.get('people'); + let recordArray = tag.get('people'); - assert.equal(get(recordArray, 'length'), 1, "precond - record array has one item"); - assert.equal(get(recordArray.objectAt(0), 'name'), "Scumbag Dale", "item at index 0 is record with id 1"); + assert.equal(get(recordArray, 'length'), 1, 'precond - record array has one item'); + assert.equal(get(recordArray.objectAt(0), 'name'), 'Scumbag Dale', "item at index 0 is record with id 1"); scumbag.deleteRecord(); - assert.equal(get(recordArray, 'length'), 1, "record is still in the record array until it is saved"); + assert.equal(get(recordArray, 'length'), 1, 'record is still in the record array until it is saved'); Ember.run(scumbag, 'save'); - assert.equal(get(recordArray, 'length'), 0, "record is removed from the array when it is saved"); + assert.equal(get(recordArray, 'length'), 0, 'record is removed from the array when it is saved'); }); }); }); -test("a loaded record is not removed from a record array when it is deleted even if the belongsTo side isn't defined", function(assert) { - var Tag = DS.Model.extend({ - people: DS.hasMany('person', { async: false }) - }); - - var env = setupStore({ +test('a loaded record is not removed from a record array when it is deleted even if the belongsTo side isn\'t defined', function(assert) { + let env = setupStore({ tag: Tag, - person: Person, + person: Person.reopen({tags: null }), adapter: DS.Adapter.extend({ - deleteRecord: () => Ember.RSVP.resolve() + deleteRecord() { + return Promise.resolve(); + } }) }); - var store = env.store; - var scumbag, tag; - run(function() { + let store = env.store; + let scumbag, tag; + + run(() => { store.push({ data: [{ type: 'person', @@ -261,26 +272,22 @@ test("a loaded record is not removed from a record array when it is deleted even }); test("a loaded record is not removed from both the record array and from the belongs to, even if the belongsTo side isn't defined", function(assert) { - var Tag = DS.Model.extend({ - people: DS.hasMany('person', { async: false }) - }); - - var Tool = DS.Model.extend({ - person: DS.belongsTo('person', { async: false }) - }); - var env = setupStore({ + let env = setupStore({ tag: Tag, person: Person, tool: Tool, adapter: DS.Adapter.extend({ - deleteRecord: () => Ember.RSVP.resolve() + deleteRecord() { + return Promise.resolve(); + } }) }); - var store = env.store; - var scumbag, tag, tool; - run(function() { + let store = env.store; + let scumbag, tag, tool; + + run(() => { store.push({ data: [{ type: 'person', @@ -313,24 +320,22 @@ test("a loaded record is not removed from both the record array and from the bel tool = store.peekRecord('tool', 1); }); - assert.equal(tag.get('people.length'), 1, "record is in the record array"); - assert.equal(tool.get('person'), scumbag, "the tool belongs to the record"); + assert.equal(tag.get('people.length'), 1, 'record is in the record array'); + assert.equal(tool.get('person'), scumbag, 'the tool belongs to the record'); - run(function() { - scumbag.deleteRecord(); - }); + run(() => scumbag.deleteRecord()); - assert.equal(tag.get('people.length'), 1, "record is stil in the record array"); - assert.equal(tool.get('person'), scumbag, "the tool still belongs to the record"); + assert.equal(tag.get('people.length'), 1, 'record is stil in the record array'); + assert.equal(tool.get('person'), scumbag, 'the tool still belongs to the record'); }); // GitHub Issue #168 -test("a newly created record is removed from a record array when it is deleted", function(assert) { - var store = createStore({ +test('a newly created record is removed from a record array when it is deleted', function(assert) { + let store = createStore({ person: Person }); - var recordArray = store.peekAll('person'); - var scumbag; + let recordArray = store.peekAll('person'); + let scumbag; run(function() { scumbag = store.createRecord('person', { @@ -358,11 +363,11 @@ test("a newly created record is removed from a record array when it is deleted", }); test("a record array returns undefined when asking for a member outside of its content Array's range", function(assert) { - var store = createStore({ + let store = createStore({ person: Person }); - run(function() { + run(() => { store.push({ data: [{ type: 'person', @@ -386,17 +391,18 @@ test("a record array returns undefined when asking for a member outside of its c }); }); - var recordArray = store.peekAll('person'); + let recordArray = store.peekAll('person'); assert.strictEqual(recordArray.objectAt(20), undefined, "objects outside of the range just return undefined"); }); // This tests for a bug in the recordCache, where the records were being cached in the incorrect order. -test("a record array should be able to be enumerated in any order", function(assert) { - var store = createStore({ +test('a record array should be able to be enumerated in any order', function(assert) { + let store = createStore({ person: Person }); - run(function() { + + run(() => { store.push({ data: [{ type: 'person', @@ -420,7 +426,7 @@ test("a record array should be able to be enumerated in any order", function(ass }); }); - var recordArray = store.peekAll('person'); + let recordArray = store.peekAll('person'); assert.equal(get(recordArray.objectAt(2), 'id'), 3, "should retrieve correct record at index 2"); assert.equal(get(recordArray.objectAt(1), 'id'), 2, "should retrieve correct record at index 1"); @@ -430,43 +436,16 @@ test("a record array should be able to be enumerated in any order", function(ass test("an AdapterPopulatedRecordArray knows if it's loaded or not", function(assert) { assert.expect(1); - var env = setupStore({ person: Person }); - var store = env.store; + let env = setupStore({ person: Person }); + let store = env.store; env.adapter.query = function(store, type, query, recordArray) { - return Ember.RSVP.resolve(array); + return Promise.resolve(array); }; - run(function() { - store.query('person', { page: 1 }).then(function(people) { + return run(() => { + return store.query('person', { page: 1 }).then(people => { assert.equal(get(people, 'isLoaded'), true, "The array is now loaded"); }); }); }); - -test("a record array should return a promise when updating", function(assert) { - var recordArray, promise; - var env = setupStore({ person: Person }); - var store = env.store; - - env.adapter.findAll = function(store, type, query, recordArray) { - return Ember.RSVP.resolve(array); - }; - - recordArray = store.peekAll('person'); - run(function() { - promise = recordArray.update(); - }); - assert.ok(promise.then && typeof promise.then === "function", "#update returns a promise"); -}); - -test('recordArray.replace() throws error', function(assert) { - var recordArray; - var env = setupStore({ person: Person }); - var store = env.store; - - assert.throws(function() { - recordArray = store.peekAll('person'); - recordArray.replace(); - }, Error("The result of a server query (for all (subclass of DS.Model) types) is immutable. To modify contents, use toArray()"), 'throws error'); -}); From a28fb0071e9ae9bc319cfd511ee48ad70cc61f92 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 16 Sep 2016 16:49:37 -0700 Subject: [PATCH 1651/2527] perf(internal-model): lazily allocation internal state. - allocations are now lazy - InternalModel is now an ES2015 class, the expensive classCallCheck is stripped via a babel plugin - TransitionMapCache has been added to make transitionTo function faster - get/set of currentState has been moved to dot notation access - overall this appears to be a 20% perf improvement, with more gains still realizable. --- addon/-private/system/model/internal-model.js | 442 +++++++++++------- addon/-private/system/model/model.js | 15 +- addon/-private/system/model/states.js | 11 +- addon/-private/system/record-array-manager.js | 9 +- addon/-private/system/store.js | 59 +-- ember-cli-build.js | 2 +- lib/babel-build.js | 3 +- lib/stripped-build-plugins.js | 4 +- tests/unit/store/unload-test.js | 2 +- 9 files changed, 326 insertions(+), 221 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 236dd1617af..aa15574a875 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -16,11 +16,33 @@ import { HasManyReference } from "ember-data/-private/system/references"; -var Promise = Ember.RSVP.Promise; -var get = Ember.get; -var set = Ember.set; -var copy = Ember.copy; -var assign = Ember.assign || Ember.merge; +const { + get, + set, + copy, + Error: EmberError, + inspect, + isEmpty, + isEqual, + run: emberRun, + setOwner, + RSVP, + RSVP: { Promise } +} = Ember; + +const assign = Ember.assign || Ember.merge; + +/* + The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached + when transitioning from one state to another, so that future transitions can replay the + transition without needing to walk the state tree, collect these hook calls and determine + the state to transition into. + + A future optimization would be to build a single chained method out of the collected enters + and setups. It may also be faster to do a two level cache (from: { to }) instead of caching based + on a key that adds the two together. + */ +const TransitionChainMap = new EmptyObject(); var _extractPivotNameCache = new EmptyObject(); var _splitOnDotCache = new EmptyObject(); @@ -37,12 +59,6 @@ function extractPivotName(name) { ); } -function retrieveFromCurrentState(key) { - return function() { - return get(this.currentState, key); - }; -} - // this (and all heimdall instrumentation) will be stripped by a babel transform // https://github.com/heimdalljs/babel5-plugin-strip-heimdall const { @@ -87,72 +103,154 @@ const { @private @class InternalModel */ +export default class InternalModel { + constructor(type, id, store, _, data) { + heimdall.increment(new_InternalModel); + this.type = type; + this.id = id; + this.store = store; + this._data = data || new EmptyObject(); + this.modelName = type.modelName; + this.dataHasInitialized = false; + this._loadingPromise = null; + this._recordArrays = undefined; + this.currentState = RootState.empty; + this.isReloading = false; + this._isDestroyed = false; + this.isError = false; + this.error = null; + + // caches for lazy getters + this.__deferredTriggers = null; + this._references = null; + this._recordReference = null; + this.__inFlightAttributes = null; + this.__relationships = null; + this.__attributes = null; + this.__implicitRelationships = null; + } + + get recordReference() { + if (this._recordReference === null) { + this._recordReference = new RecordReference(this.store, this) + } + return this._recordReference; + } + + get references() { + if (this._references === null) { + this._references = new EmptyObject(); + } + return this._references; + } + + get _deferredTriggers() { + if (this.__deferredTriggers === null) { + this.__deferredTriggers = []; + } + return this.__deferredTriggers; + } + + get _attributes() { + if (this.__attributes === null) { + this.__attributes = new EmptyObject(); + } + return this.__attributes; + } + + set _attributes(v) { + this.__attributes = v; + } + + get _relationships() { + if (this.__relationships === null) { + this.__relationships = new Relationships(this); + } + + return this.__relationships; + } + + get _inFlightAttributes() { + if (this.__inFlightAttributes === null) { + this.__inFlightAttributes = new EmptyObject(); + } + return this.__inFlightAttributes; + } + + set _inFlightAttributes(v) { + this.__inFlightAttributes = v; + } -export default function InternalModel(type, id, store, _, data) { - heimdall.increment(new_InternalModel); - this.type = type; - this.id = id; - this.store = store; - this._data = data || new EmptyObject(); - this.modelName = type.modelName; - this.dataHasInitialized = false; - //Look into making this lazy - this._deferredTriggers = []; - this._attributes = new EmptyObject(); - this._inFlightAttributes = new EmptyObject(); - this._relationships = new Relationships(this); - this._recordArrays = undefined; - this.currentState = RootState.empty; - this.recordReference = new RecordReference(store, this); - this.references = {}; - this.isReloading = false; - this._isDestroyed = false; - this.isError = false; - this.error = null; - this.__ember_meta__ = null; - this[Ember.GUID_KEY] = Ember.guidFor(this); /* - implicit relationships are relationship which have not been declared but the inverse side exists on - another record somewhere - For example if there was + implicit relationships are relationship which have not been declared but the inverse side exists on + another record somewhere + For example if there was - ```app/models/comment.js - import DS from 'ember-data'; + ```app/models/comment.js + import DS from 'ember-data'; - export default DS.Model.extend({ - name: DS.attr() - }) - ``` + export default DS.Model.extend({ + name: DS.attr() + }) + ``` - but there is also + but there is also - ```app/models/post.js - import DS from 'ember-data'; + ```app/models/post.js + import DS from 'ember-data'; - export default DS.Model.extend({ - name: DS.attr(), - comments: DS.hasMany('comment') - }) - ``` + export default DS.Model.extend({ + name: DS.attr(), + comments: DS.hasMany('comment') + }) + ``` - would have a implicit post relationship in order to be do things like remove ourselves from the post - when we are deleted + would have a implicit post relationship in order to be do things like remove ourselves from the post + when we are deleted */ - this._implicitRelationships = new EmptyObject(); -} + get _implicitRelationships() { + if (this.__implicitRelationships === null) { + this.__implicitRelationships = new EmptyObject(); + } + return this.__implicitRelationships; + } + + isEmpty() { + return this.currentState.isEmpty; + } + + isLoading() { + return this.currentState.isLoading; + } + + isLoaded() { + return this.currentState.isLoaded; + } + + hasDirtyAttributes() { + return this.currentState.hasDirtyAttributes; + } + + isSaving() { + return this.currentState.isSaving; + } + + isDeleted() { + return this.currentState.isDeleted; + } + + isNew() { + return this.currentState.isNew; + } + + isValid() { + return this.currentState.isValid; + } + + dirtyType() { + return this.currentState.dirtyType; + } -InternalModel.prototype = { - isEmpty: retrieveFromCurrentState('isEmpty'), - isLoading: retrieveFromCurrentState('isLoading'), - isLoaded: retrieveFromCurrentState('isLoaded'), - hasDirtyAttributes: retrieveFromCurrentState('hasDirtyAttributes'), - isSaving: retrieveFromCurrentState('isSaving'), - isDeleted: retrieveFromCurrentState('isDeleted'), - isNew: retrieveFromCurrentState('isNew'), - isValid: retrieveFromCurrentState('isValid'), - dirtyType: retrieveFromCurrentState('dirtyType'), - - constructor: InternalModel, materializeRecord() { heimdall.increment(materializeRecord); assert("Materialized " + this.modelName + " record with id:" + this.id + "more than once", this.record === null || this.record === undefined); @@ -163,14 +261,14 @@ InternalModel.prototype = { store: this.store, _internalModel: this, id: this.id, - currentState: get(this, 'currentState'), + currentState: this.currentState, isError: this.isError, adapterError: this.error }; - if (Ember.setOwner) { - // ensure that `Ember.getOwner(this)` works inside a model instance - Ember.setOwner(createOptions, getOwner(this.store)); + if (setOwner) { + // ensure that `getOwner(this)` works inside a model instance + setOwner(createOptions, getOwner(this.store)); } else { createOptions.container = this.store.container; } @@ -178,37 +276,37 @@ InternalModel.prototype = { this.record = this.type._create(createOptions); this._triggerDeferredTriggers(); - }, + } recordObjectWillDestroy() { this.record = null; - }, + } deleteRecord() { this.send('deleteRecord'); - }, + } save(options) { var promiseLabel = "DS: Model#save " + this; - var resolver = Ember.RSVP.defer(promiseLabel); + var resolver = RSVP.defer(promiseLabel); this.store.scheduleSave(this, resolver, options); return resolver.promise; - }, + } startedReloading() { this.isReloading = true; if (this.record) { set(this.record, 'isReloading', true); } - }, + } finishedReloading() { this.isReloading = false; if (this.record) { set(this.record, 'isReloading', false); } - }, + } reload() { this.startedReloading(); @@ -226,30 +324,30 @@ InternalModel.prototype = { record.finishedReloading(); record.updateRecordArrays(); }); - }, + } getRecord() { if (!this.record) { this.materializeRecord(); } return this.record; - }, + } unloadRecord() { this.send('unloadRecord'); - }, + } eachRelationship(callback, binding) { return this.type.eachRelationship(callback, binding); - }, + } eachAttribute(callback, binding) { return this.type.eachAttribute(callback, binding); - }, + } inverseFor(key) { return this.type.inverseFor(key); - }, + } setupData(data) { heimdall.increment(setupData); @@ -260,29 +358,29 @@ InternalModel.prototype = { this.record._notifyProperties(changedKeys); } this.didInitializeData(); - }, + } becameReady() { - Ember.run.schedule('actions', this.store.recordArrayManager, this.store.recordArrayManager.recordWasLoaded, this); - }, + emberRun.schedule('actions', this.store.recordArrayManager, this.store.recordArrayManager.recordWasLoaded, this); + } didInitializeData() { if (!this.dataHasInitialized) { this.becameReady(); this.dataHasInitialized = true; } - }, + } get isDestroyed() { return this._isDestroyed; - }, + } destroy() { this._isDestroyed = true; if (this.record) { return this.record.destroy(); } - }, + } /* @method createSnapshot @@ -291,7 +389,7 @@ InternalModel.prototype = { createSnapshot(options) { heimdall.increment(createSnapshot); return new Snapshot(this, options); - }, + } /* @method loadingData @@ -300,7 +398,7 @@ InternalModel.prototype = { */ loadingData(promise) { this.send('loadingData', promise); - }, + } /* @method loadedData @@ -309,7 +407,7 @@ InternalModel.prototype = { loadedData() { this.send('loadedData'); this.didInitializeData(); - }, + } /* @method notFound @@ -317,7 +415,7 @@ InternalModel.prototype = { */ notFound() { this.send('notFound'); - }, + } /* @method pushedData @@ -325,18 +423,18 @@ InternalModel.prototype = { */ pushedData() { this.send('pushedData'); - }, + } flushChangedAttributes() { heimdall.increment(flushChangedAttributes); this._inFlightAttributes = this._attributes; this._attributes = new EmptyObject(); - }, + } hasChangedAttributes() { heimdall.increment(hasChangedAttributes); return Object.keys(this._attributes).length > 0; - }, + } /* Checks if the attributes which are considered as changed are still @@ -352,16 +450,17 @@ InternalModel.prototype = { heimdall.increment(updateChangedAttributes); var changedAttributes = this.changedAttributes(); var changedAttributeNames = Object.keys(changedAttributes); + let attrs = this._attributes; for (let i = 0, length = changedAttributeNames.length; i < length; i++) { let attribute = changedAttributeNames[i]; let [oldData, newData] = changedAttributes[attribute]; if (oldData === newData) { - delete this._attributes[attribute]; + delete attrs[attribute]; } } - }, + } /* Returns an object, whose keys are changed properties, and value is an @@ -386,7 +485,7 @@ InternalModel.prototype = { } return diffData; - }, + } /* @method adapterWillCommit @@ -394,7 +493,7 @@ InternalModel.prototype = { */ adapterWillCommit() { this.send('willCommit'); - }, + } /* @method adapterDidDirty @@ -403,7 +502,7 @@ InternalModel.prototype = { adapterDidDirty() { this.send('becomeDirty'); this.updateRecordArraysLater(); - }, + } /* @method send @@ -413,38 +512,38 @@ InternalModel.prototype = { */ send(name, context) { heimdall.increment(send); - var currentState = get(this, 'currentState'); + var currentState = this.currentState; if (!currentState[name]) { this._unhandledEvent(currentState, name, context); } return currentState[name](this, context); - }, + } notifyHasManyAdded(key, record, idx) { if (this.record) { this.record.notifyHasManyAdded(key, record, idx); } - }, + } notifyHasManyRemoved(key, record, idx) { if (this.record) { this.record.notifyHasManyRemoved(key, record, idx); } - }, + } notifyBelongsToChanged(key, record) { if (this.record) { this.record.notifyBelongsToChanged(key, record); } - }, + } notifyPropertyChange(key) { if (this.record) { this.record.notifyPropertyChange(key); } - }, + } rollbackAttributes() { var dirtyKeys = Object.keys(this._attributes); @@ -475,8 +574,7 @@ InternalModel.prototype = { this.send('rolledBack'); this.record._notifyProperties(dirtyKeys); - - }, + } /* @method transitionTo @@ -489,42 +587,55 @@ InternalModel.prototype = { // always having direct reference to state objects var pivotName = extractPivotName(name); - var currentState = get(this, 'currentState'); - var state = currentState; + var state = this.currentState; + let transitionMapId = `${state.stateName}->${name}`; do { if (state.exit) { state.exit(this); } state = state.parentState; - } while (!state.hasOwnProperty(pivotName)); + } while (!state[pivotName]); + + let setups; + let enters; + let i; + let l; + let map = TransitionChainMap[transitionMapId]; + + if (map) { + setups = map.setups; + enters = map.enters; + state = map.state; + } else { + setups = []; + enters = []; + + let path = splitOnDot(name); - var path = splitOnDot(name); - var setups = []; - var enters = []; - var i, l; + for (i = 0, l = path.length; i < l; i++) { + state = state[path[i]]; - for (i=0, l=path.length; i`; - } - }, + return `<${this.modelName}:${this.id}>`; + } referenceFor(type, name) { var reference = this.references[name]; diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index cddcd8693f6..fffc6e50af1 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -8,13 +8,17 @@ import { HasManyMixin } from 'ember-data/-private/system/relationships/has-many' import { DidDefinePropertyMixin, RelationshipsClassMethodsMixin, RelationshipsInstanceMethodsMixin } from 'ember-data/-private/system/relationships/ext'; import { AttrClassMethodsMixin, AttrInstanceMethodsMixin } from 'ember-data/-private/system/model/attr'; import isEnabled from 'ember-data/-private/features'; +import RootState from 'ember-data/-private/system/model/states'; + +const { + get, + computed +} = Ember; /** @module ember-data */ -var get = Ember.get; - function intersection (array1, array2) { var result = []; array1.forEach((element) => { @@ -30,7 +34,7 @@ var RESERVED_MODEL_PROPS = [ 'currentState', 'data', 'store' ]; -var retrieveFromCurrentState = Ember.computed('currentState', function(key) { +var retrieveFromCurrentState = computed('currentState', function(key) { return get(this._internalModel.currentState, key); }).readOnly(); @@ -122,7 +126,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @type {Boolean} @readOnly */ - hasDirtyAttributes: Ember.computed('currentState.isDirty', function() { + hasDirtyAttributes: computed('currentState.isDirty', function() { return this.get('currentState.isDirty'); }), /** @@ -305,6 +309,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @private @type {Object} */ + currentState: RootState.empty, /** When the record is in the `invalid` state this object will contain @@ -357,7 +362,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @property errors @type {DS.Errors} */ - errors: Ember.computed(function() { + errors: computed(function() { let errors = Errors.create(); errors._registerHandlers(this._internalModel, diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index 23fddd3ae71..85cecb4c06c 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -1,10 +1,8 @@ /** @module ember-data */ -import Ember from 'ember'; import { assert } from "ember-data/-private/debug"; -const { get } = Ember; /* This file encapsulates the various states that a record can transition through during its lifecycle. @@ -257,7 +255,7 @@ const DirtyState = { heimdall.stop(token); }, - becomeDirty() { }, + becomeDirty() {}, willCommit(internalModel) { internalModel.transitionTo('inFlight'); @@ -430,7 +428,7 @@ createdState.uncommitted.pushedData = function(internalModel) { internalModel.triggerLater('didLoad'); }; -createdState.uncommitted.propertyWasReset = Ember.K; +createdState.uncommitted.propertyWasReset = function() {}; function assertAgainstUnloadRecord(internalModel) { assert("You can only unload a record which is not inFlight. `" + internalModel + "`", false); @@ -581,9 +579,7 @@ const RootState = { internalModel.transitionTo('deleted.saved'); }, - didCommit(internalModel) { - internalModel.send('invokeLifecycleCallbacks', get(internalModel, 'lastDirtyType')); - }, + didCommit() {}, // loaded.saved.notFound would be triggered by a failed // `reload()` on an unchanged record @@ -715,7 +711,6 @@ const RootState = { deleteRecord() { }, willCommit() { }, - rolledBack(internalModel) { internalModel.clearErrorMessages(); internalModel.transitionTo('loaded.saved'); diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 1b44f1279d3..669b0c54d35 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -8,9 +8,14 @@ import { FilteredRecordArray, AdapterPopulatedRecordArray } from "ember-data/-private/system/record-arrays"; -const { get, MapWithDefault } = Ember; import OrderedSet from "ember-data/-private/system/ordered-set"; +const { + get, + MapWithDefault, + run: emberRun +} = Ember; + const { _addRecordToRecordArray, _recordWasChanged, @@ -78,7 +83,7 @@ export default Ember.Object.extend({ heimdall.increment(recordDidChange); if (this.changedRecords.push(record) !== 1) { return; } - Ember.run.schedule('actions', this, this.updateRecordArrays); + emberRun.schedule('actions', this, this.updateRecordArrays); }, recordArraysForRecord(record) { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 8953f59f7dc..c153a72ad75 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -7,9 +7,7 @@ import Model from 'ember-data/model'; import { instrument, assert, warn, runInDebug } from "ember-data/-private/debug"; import _normalizeLink from "ember-data/-private/system/normalize-link"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; -import { - InvalidError -} from 'ember-data/adapters/errors'; +import { InvalidError } from 'ember-data/adapters/errors'; import { promiseArray, @@ -22,13 +20,8 @@ import { _objectIsAlive } from "ember-data/-private/system/store/common"; -import { - normalizeResponseHelper -} from "ember-data/-private/system/store/serializer-response"; - -import { - serializerForAdapter -} from "ember-data/-private/system/store/serializers"; +import { normalizeResponseHelper } from "ember-data/-private/system/store/serializer-response"; +import { serializerForAdapter } from "ember-data/-private/system/store/serializers"; import { _find, @@ -40,25 +33,27 @@ import { _queryRecord } from "ember-data/-private/system/store/finders"; -import { - getOwner -} from 'ember-data/-private/utils'; - +import { getOwner } from 'ember-data/-private/utils'; import coerceId from "ember-data/-private/system/coerce-id"; - import RecordArrayManager from "ember-data/-private/system/record-array-manager"; import ContainerInstanceCache from 'ember-data/-private/system/store/container-instance-cache'; - import InternalModel from "ember-data/-private/system/model/internal-model"; - import EmptyObject from "ember-data/-private/system/empty-object"; - import isEnabled from 'ember-data/-private/features'; export let badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; -const Backburner = Ember._Backburner; -var Map = Ember.Map; +const { + _Backburner: Backburner, + copy, + get, + isNone, + isPresent, + Map, + run: emberRun, + set, + Service +} = Ember; //Get the materialized model from the internalModel/promise that returns //an internal model and return it in a promiseObject. Useful for returning @@ -68,19 +63,9 @@ function promiseRecord(internalModel, label) { return promiseObject(toReturn, label); } -var once = Ember.run.once; -var Promise = Ember.RSVP.Promise; -var Store; +const Promise = Ember.RSVP.Promise; -const { - copy, - get, - GUID_KEY, - isNone, - isPresent, - set, - Service -} = Ember; +let Store; // Implementors Note: // @@ -807,7 +792,7 @@ Store = Service.extend({ } else { this._pendingFetch.get(typeClass).push(pendingFetchItem); } - Ember.run.scheduleOnce('afterRender', this, this.flushAllPendingFetches); + emberRun.scheduleOnce('afterRender', this, this.flushAllPendingFetches); return promise; }, @@ -1784,7 +1769,7 @@ Store = Service.extend({ snapshot: snapshot, resolver: resolver }); - once(this, 'flushPendingSave'); + emberRun.once(this, this.flushPendingSave); }, /** @@ -1839,7 +1824,7 @@ Store = Service.extend({ } if (data) { // normalize relationship IDs into records - this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, data); + this._backburner.schedule('normalizeRelationships', this, this._setupRelationships, internalModel, data); this.updateId(internalModel, data); } else { assert(`Your ${internalModel.type.modelName} record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, internalModel.id); @@ -1893,7 +1878,7 @@ Store = Service.extend({ var id = coerceId(data.id); // ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record) - assert(`'${internalModel.type.modelName}:${internalModel[GUID_KEY]}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null)); + assert(`'${internalModel.type.modelName}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null)); // ID absolutely can't be different than oldID if oldID is not null assert(`'${internalModel.type.modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, !(oldId !== null && id !== oldId)); @@ -2262,7 +2247,7 @@ Store = Service.extend({ var internalModel = this._load(data); this._backburner.join(() => { - this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', internalModel, data); + this._backburner.schedule('normalizeRelationships', this, this._setupRelationships, internalModel, data); }); return internalModel; diff --git a/ember-cli-build.js b/ember-cli-build.js index 4b6ad84bd75..0e697964f0b 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -23,7 +23,7 @@ module.exports = function(defaults) { babel: { plugins: [ // while ember-data strips itself, ember does not currently - {transformer: stripClassCallCheck, position: 'after'} + { transformer: stripClassCallCheck, position: 'after' } ] } }); diff --git a/lib/babel-build.js b/lib/babel-build.js index da3a2bbf968..1135048aee4 100644 --- a/lib/babel-build.js +++ b/lib/babel-build.js @@ -16,7 +16,8 @@ function babelOptions(libraryName, _options) { 'es6.properties.shorthand', 'es6.blockScoping', 'es6.constants', - 'es6.modules' + 'es6.modules', + 'es6.classes' ], sourceMaps: false, modules: 'amdStrict', diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 24e0141bd2b..478622b780a 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -3,6 +3,7 @@ var path = require('path'); var filterImports = require('babel-plugin-filter-imports'); var featureFlags = require('babel-plugin-feature-flags'); var stripHeimdall = require('babel5-plugin-strip-heimdall'); +var stripClassCallCheck = require('babel5-plugin-strip-class-callcheck'); function uniqueAdd(obj, key, values) { var a = obj[key] = obj[key] || []; @@ -32,7 +33,8 @@ module.exports = function(environment) { featureFlags({ import: { module: 'ember-data/-private/features' }, features: features - }) + }), + { transformer: stripClassCallCheck, position: 'after' } ]; if (process.env.INSTRUMENT_HEIMDALL === 'false') { diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index f2a131ff676..9bcd77696c5 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -55,7 +55,7 @@ testInDebug("unload a dirty record asserts", function(assert) { assert.expectAssertion(function() { record.unloadRecord(); - }, "You can only unload a record which is not inFlight. `" + Ember.inspect(record) + "`", "can not unload dirty record"); + }, "You can only unload a record which is not inFlight. `" + record._internalModel.toString() + "`", "can not unload dirty record"); // force back into safe to unload mode. run(function() { From d42cb000bcb390cde97a9058ca206cff539b6b4e Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 18 Oct 2016 09:00:34 -0400 Subject: [PATCH 1652/2527] Remove the ds-boolean-transform-allow-null feature flag --- FEATURES.md | 4 ---- addon/-private/transforms/boolean.js | 13 ++++------- config/features.json | 1 - tests/unit/model-test.js | 12 +++------- tests/unit/transform/boolean-test.js | 35 ++++++++++------------------ 5 files changed, 19 insertions(+), 46 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 6bccd4f01be..e542252d6fc 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -11,10 +11,6 @@ entry in `config/features.json`. ## Feature Flags -- `ds-boolean-transform-allow-null` [#4022](https://github.com/emberjs/data/pull/4022) - - Allow `null`/`undefined` values for `boolean` attributes via `DS.attr('boolean', { allowNull: true })` - - `ds-improved-ajax` [#3099](https://github.com/emberjs/data/pull/3099) This feature allows to customize how a request is formed by overwriting diff --git a/addon/-private/transforms/boolean.js b/addon/-private/transforms/boolean.js index fd4e6d0a9ac..c1c8fc656a7 100644 --- a/addon/-private/transforms/boolean.js +++ b/addon/-private/transforms/boolean.js @@ -1,6 +1,5 @@ import Ember from 'ember'; import Transform from "ember-data/transform"; -import isEnabled from 'ember-data/-private/features'; const { isNone } = Ember; @@ -44,10 +43,8 @@ export default Transform.extend({ deserialize(serialized, options) { var type = typeof serialized; - if (isEnabled('ds-boolean-transform-allow-null')) { - if (isNone(serialized) && options.allowNull === true) { - return null; - } + if (isNone(serialized) && options.allowNull === true) { + return null; } if (type === "boolean") { @@ -62,10 +59,8 @@ export default Transform.extend({ }, serialize(deserialized, options) { - if (isEnabled('ds-boolean-transform-allow-null')) { - if (isNone(deserialized) && options.allowNull === true) { - return null; - } + if (isNone(deserialized) && options.allowNull === true) { + return null; } return Boolean(deserialized); diff --git a/config/features.json b/config/features.json index 607aa00310d..2427abf3d2b 100644 --- a/config/features.json +++ b/config/features.json @@ -1,5 +1,4 @@ { - "ds-boolean-transform-allow-null": true, "ds-improved-ajax": true, "ds-pushpayload-return": null, "ds-extended-errors": null, diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index ea2cc1dc17a..5afdfe4ec7b 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -1131,17 +1131,11 @@ test("a DS.Model can describe Boolean attributes", function(assert) { assert.converts('boolean', 1, true); assert.converts('boolean', 0, false); - if (isEnabled('ds-boolean-transform-allow-null')) { - assert.converts('boolean', null, null, { allowNull: true }); + assert.converts('boolean', null, null, { allowNull: true }); - assert.converts('boolean', null, false, { allowNull: false }); + assert.converts('boolean', null, false, { allowNull: false }); - // duplicating the tests from the else branch here, so once the feature is - // enabled and the else branch is deleted, those assertions are kept - assert.converts('boolean', null, false); - } else { - assert.converts('boolean', null, false); - } + assert.converts('boolean', null, false); assert.converts('boolean', true, true); assert.converts('boolean', false, false); diff --git a/tests/unit/transform/boolean-test.js b/tests/unit/transform/boolean-test.js index 32c6a69d057..7f57d5fc52e 100644 --- a/tests/unit/transform/boolean-test.js +++ b/tests/unit/transform/boolean-test.js @@ -1,5 +1,4 @@ import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; import {module, test} from 'qunit'; @@ -8,19 +7,14 @@ module("unit/transform - DS.BooleanTransform"); test("#serialize", function(assert) { var transform = new DS.BooleanTransform(); - if (isEnabled('ds-boolean-transform-allow-null')) { - assert.equal(transform.serialize(null, { allowNull: true }), null); - assert.equal(transform.serialize(undefined, { allowNull: true }), null); + assert.equal(transform.serialize(null, { allowNull: true }), null); + assert.equal(transform.serialize(undefined, { allowNull: true }), null); - assert.equal(transform.serialize(null, { allowNull: false }), false); - assert.equal(transform.serialize(undefined, { allowNull: false }), false); + assert.equal(transform.serialize(null, { allowNull: false }), false); + assert.equal(transform.serialize(undefined, { allowNull: false }), false); - assert.equal(transform.serialize(null, {}), false); - assert.equal(transform.serialize(undefined, {}), false); - } else { - assert.equal(transform.serialize(null), false); - assert.equal(transform.serialize(undefined), false); - } + assert.equal(transform.serialize(null, {}), false); + assert.equal(transform.serialize(undefined, {}), false); assert.equal(transform.serialize(true), true); assert.equal(transform.serialize(false), false); @@ -29,19 +23,14 @@ test("#serialize", function(assert) { test("#deserialize", function(assert) { var transform = new DS.BooleanTransform(); - if (isEnabled('ds-boolean-transform-allow-null')) { - assert.equal(transform.deserialize(null, { allowNull: true }), null); - assert.equal(transform.deserialize(undefined, { allowNull: true }), null); + assert.equal(transform.deserialize(null, { allowNull: true }), null); + assert.equal(transform.deserialize(undefined, { allowNull: true }), null); - assert.equal(transform.deserialize(null, { allowNull: false }), false); - assert.equal(transform.deserialize(undefined, { allowNull: false }), false); + assert.equal(transform.deserialize(null, { allowNull: false }), false); + assert.equal(transform.deserialize(undefined, { allowNull: false }), false); - assert.equal(transform.deserialize(null, {}), false); - assert.equal(transform.deserialize(undefined, {}), false); - } else { - assert.equal(transform.deserialize(null), false); - assert.equal(transform.deserialize(undefined), false); - } + assert.equal(transform.deserialize(null, {}), false); + assert.equal(transform.deserialize(undefined, {}), false); assert.equal(transform.deserialize(true), true); assert.equal(transform.deserialize(false), false); From 3d37d1132de09b78826cc1d50f5a247083c71c1f Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 20 Oct 2016 00:40:26 +0300 Subject: [PATCH 1653/2527] fix integration/record-array-test setup --- tests/integration/record-array-test.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/integration/record-array-test.js b/tests/integration/record-array-test.js index de20880dc6f..d0c0b5f9e10 100644 --- a/tests/integration/record-array-test.js +++ b/tests/integration/record-array-test.js @@ -26,9 +26,9 @@ const Tool = DS.Model.extend({ module('unit/record_array - DS.RecordArray', { beforeEach() { array = Ember.A([ - { id: '1', name: "Scumbag Dale" }, - { id: '2', name: "Scumbag Katz" }, - { id: '3', name: "Scumbag Bryn" } + { id: '1', name: 'Scumbag Dale' }, + { id: '2', name: 'Scumbag Katz' }, + { id: '3', name: 'Scumbag Bryn' } ]); } }); @@ -332,7 +332,8 @@ test("a loaded record is not removed from both the record array and from the bel // GitHub Issue #168 test('a newly created record is removed from a record array when it is deleted', function(assert) { let store = createStore({ - person: Person + person: Person, + tag: Tag }); let recordArray = store.peekAll('person'); let scumbag; From f7249735e499f845d47236feb86e9241ec7f1e31 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 20 Oct 2016 15:42:32 +0300 Subject: [PATCH 1654/2527] Warn when findRecord returns a different id than the one requested --- addon/-private/system/store/finders.js | 7 ++++++- tests/integration/adapter/find-test.js | 14 ++++++++++++++ tests/integration/relationships/belongs-to-test.js | 2 +- tests/unit/store/adapter-interop-test.js | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 1681622fab7..97a51f63a0e 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert } from "ember-data/-private/debug"; +import { assert, warn } from "ember-data/-private/debug"; import { _bind, _guard, @@ -38,6 +38,11 @@ export function _find(adapter, store, typeClass, id, internalModel, options) { return store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, id, 'findRecord'); assert('Ember Data expected the primary data returned from a `findRecord` response to be an object but instead it found an array.', !Array.isArray(payload.data)); + + warn(`You requested a record of type '${typeClass.modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Looks like you want to use store.queryRecord instead http://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, payload.data.id === id, { + id: 'ds.store.findRecord.id-mismatch' + }); + //TODO Optimize var record = store.push(payload); return record._internalModel; diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 2e2546175b7..0028b1ce0f3 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -154,3 +154,17 @@ testInDebug('When multiple records are requested, and the payload is blank', (as }); }, /You made a `findMany` request for person records with ids 1,2, but the adapter's response did not have any data/); }); + +testInDebug("warns when returned record has different id", function(assert) { + env.registry.register('adapter:person', DS.Adapter.extend({ + findRecord() { + return { id: 1, name: "Braaaahm Dale" }; + } + })); + + assert.expectWarning(/You requested a record of type 'person' with id 'me' but the adapter returned a payload with primary data having an id of '1'/); + + run(function() { + env.store.findRecord('person', 'me'); + }); +}); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 593ca6accc0..fa31f36526d 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -102,7 +102,7 @@ test("The store can materialize a non loaded monomorphic belongsTo association", env.adapter.findRecord = function(store, type, id, snapshot) { assert.ok(true, "The adapter's find method should be called"); return Ember.RSVP.resolve({ - id: 1 + id }); }; diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index 506c4079985..100d7f069f4 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -128,7 +128,7 @@ test("IDs provided as numbers are coerced to strings", function(assert) { var adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(typeof id, 'string', "id has been normalized to a string"); - return resolve({ id: 1, name: "Scumbag Sylvain" }); + return resolve({ id, name: "Scumbag Sylvain" }); } }); From 236bf17e07c699ec797e67f828a66d6b6aa8d7ae Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 20 Oct 2016 13:25:54 -0700 Subject: [PATCH 1655/2527] fix(instrumentation): heimdall-query needed bumped to work properly --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7f2a8a273cd..49804505c40 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "express": "^4.14.0", "github": "^0.2.4", "glob": "5.0.13", - "heimdall-query": "^0.0.4", + "heimdall-query": "^0.0.5", "json-api-mock-server": "0.0.2", "mocha": "2.4.5", "mocha-only-detector": "0.0.2", From 851a7c13c38d1d3e0b745992cab9b3f62e0ad157 Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 19 Oct 2016 15:32:25 +0300 Subject: [PATCH 1656/2527] [DOC] Add documentation for query#update() to refresh query --- .../adapter-populated-record-array.js | 27 +++++++++++++++++++ addon/-private/system/store.js | 3 ++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index 7727e85bf72..8448b7470b0 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -14,6 +14,33 @@ var get = Ember.get; may trigger a search on the server, whose results would be loaded into an instance of the `AdapterPopulatedRecordArray`. + --- + + If you want to update the array and get the latest records from the + adapter, you can invoke [`update()`](#method_update): + + Example + + ```javascript + // GET /users?isAdmin=true + var admins = store.query('user', { isAdmin: true }); + + admins.then(function() { + console.log(admins.get("length")); // 42 + }); + + // somewhere later in the app code, when new admins have been created + // in the meantime + // + // GET /users?isAdmin=true + admins.update().then(function() { + admins.get('isUpdating'); // false + console.log(admins.get("length")); // 123 + }); + + admins.get('isUpdating'); // true + ``` + @class AdapterPopulatedRecordArray @namespace DS @extends DS.RecordArray diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 8953f59f7dc..e86825de649 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1156,7 +1156,8 @@ Store = Service.extend({ Parameters: { "ids" => ["1", "2", "3"] } ``` - This method returns a promise, which is resolved with a `RecordArray` + This method returns a promise, which is resolved with an + [`AdapterPopulatedRecordArray`](http://emberjs.com/api/data/classes/DS.AdapterPopulatedRecordArray.html) once the server returns. @since 1.13.0 From d1dd78c9cdb3652479ac23b514b3f70d63360325 Mon Sep 17 00:00:00 2001 From: pangratz Date: Thu, 10 Mar 2016 09:23:15 +0100 Subject: [PATCH 1657/2527] [BUGFIX beta] Don't unnecessarily materialize records This adds a `store#_push` method which returns DS.InternalModel's instead of materialized DS.Model instances. This allows us to defer the materialization process of an InternalModel until the corresponding record is actually needed. --- .../adapter-populated-record-array.js | 6 +-- .../-private/system/references/belongs-to.js | 4 +- addon/-private/system/store.js | 47 +++++++++++++++++-- addon/-private/system/store/finders.js | 38 +++++---------- .../adapter-populated-record-array-test.js | 8 ++-- .../adapter-populated-record-array-test.js | 2 +- tests/unit/store/push-test.js | 44 +++++++++++++++++ 7 files changed, 108 insertions(+), 41 deletions(-) diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index 782e41a29fb..5c73727d1a1 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -67,14 +67,12 @@ export default RecordArray.extend({ /** @method loadRecords - @param {Array} records + @param {Array} internalModels @param {Object} payload normalized payload @private */ - loadRecords(records, payload) { + loadRecords(internalModels, payload) { let token = heimdall.start('AdapterPopulatedRecordArray.loadRecords'); - //TODO Optimize - let internalModels = records.map(record => get(record, '_internalModel')); this.setProperties({ content: Ember.A(internalModels), isLoaded: true, diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 603a0c34140..4a13c26f37c 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -66,8 +66,8 @@ BelongsToReference.prototype.push = function(objectOrPromise) { BelongsToReference.prototype.value = function() { var inverseRecord = this.belongsToRelationship.inverseRecord; - if (inverseRecord && inverseRecord.record) { - return inverseRecord.record; + if (inverseRecord && inverseRecord.isLoaded()) { + return inverseRecord.getRecord(); } return null; diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index bcfd228d04b..ef85c0c409a 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1295,7 +1295,15 @@ Store = Service.extend({ assert("You tried to make a query but you have no adapter (for " + typeClass + ")", adapter); assert("You tried to make a query but your adapter does not implement `queryRecord`", typeof adapter.queryRecord === 'function'); - return promiseObject(_queryRecord(adapter, this, typeClass, query)); + return promiseObject(_queryRecord(adapter, this, typeClass, query).then((internalModel) => { + // the promise returned by store.queryRecord is expected to resolve with + // an instance of DS.Model + if (internalModel) { + return internalModel.getRecord(); + } + + return null; + })); }, /** @@ -2194,6 +2202,37 @@ Store = Service.extend({ */ push(data) { let token = heimdall.start('store.push'); + let pushed = this._push(data); + + if (Array.isArray(pushed)) { + let records = pushed.map(function(internalModel) { + return internalModel.getRecord(); + }); + heimdall.stop(token); + return records; + } + + if (pushed === null) { + heimdall.stop(token); + return null; + } + + var record = pushed.getRecord(); + heimdall.stop(token); + return record; + }, + + /* + Push some data into the store, without creating materialized records. + + @method _push + @private + @param {Object} data + @return {DS.InternalModel|Array} pushed InternalModel(s) + */ + _push(data) { + let token = heimdall.start('store._push'); + var included = data.included; var i, length; if (included) { @@ -2206,7 +2245,7 @@ Store = Service.extend({ length = data.data.length; var internalModels = new Array(length); for (i = 0; i < length; i++) { - internalModels[i] = this._pushInternalModel(data.data[i]).getRecord(); + internalModels[i] = this._pushInternalModel(data.data[i]); } heimdall.stop(token); return internalModels; @@ -2220,10 +2259,8 @@ Store = Service.extend({ assert(`Expected an object in the 'data' property in a call to 'push' for ${data.type}, but was ${Ember.typeOf(data.data)}`, Ember.typeOf(data.data) === 'object'); var internalModel = this._pushInternalModel(data.data); - - var record = internalModel.getRecord(); heimdall.stop(token); - return record; + return internalModel; }, _hasModelFor(type) { diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 97a51f63a0e..5684f0f275f 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -43,9 +43,8 @@ export function _find(adapter, store, typeClass, id, internalModel, options) { id: 'ds.store.findRecord.id-mismatch' }); - //TODO Optimize - var record = store.push(payload); - return record._internalModel; + var internalModel = store._push(payload); + return internalModel; }); }, function(error) { internalModel.notFound(); @@ -75,14 +74,7 @@ export function _findMany(adapter, store, typeClass, ids, internalModels) { assert("You made a `findMany` request for " + typeClass.modelName + " records with ids " + ids + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { let payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findMany'); - //TODO Optimize, no need to materialize here - let records = store.push(payload); - let internalModels = new Array(records.length); - - for (let i = 0; i < records.length; i++) { - internalModels[i] = records[i]._internalModel; - } - + let internalModels = store._push(payload); return internalModels; }); }, null, "DS: Extract payload of " + typeClass); @@ -131,9 +123,8 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship return null; } - //TODO Optimize - var record = store.push(payload); - return record._internalModel; + var internalModel = store._push(payload); + return internalModel; }); }, null, "DS: Extract payload of " + internalModel + " : " + relationship.type); } @@ -153,8 +144,7 @@ export function _findAll(adapter, store, typeClass, sinceToken, options) { assert("You made a `findAll` request for " + typeClass.modelName + " records, but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findAll'); - //TODO Optimize - store.push(payload); + store._push(payload); }); store.didUpdateAll(typeClass); @@ -173,15 +163,14 @@ export function _query(adapter, store, typeClass, query, recordArray) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - var records, payload; + var internalModels, payload; store._adapterRun(function() { payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'query'); - //TODO Optimize - records = store.push(payload); + internalModels = store._push(payload); }); - assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Array.isArray(records)); - recordArray.loadRecords(records, payload); + assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Array.isArray(internalModels)); + recordArray.loadRecords(internalModels, payload); return recordArray; }, null, "DS: Extract payload of query " + typeClass); @@ -197,7 +186,7 @@ export function _queryRecord(adapter, store, typeClass, query) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - var record; + var internalModel; store._adapterRun(function() { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'queryRecord'); @@ -205,11 +194,10 @@ export function _queryRecord(adapter, store, typeClass, query) { id: 'ds.store.queryRecord-array-response' }); - //TODO Optimize - record = store.push(payload); + internalModel = store._push(payload); }); - return record; + return internalModel; }, null, "DS: Extract payload of queryRecord " + typeClass); } diff --git a/tests/unit/adapter-populated-record-array-test.js b/tests/unit/adapter-populated-record-array-test.js index b430ae031a0..d4c47544815 100644 --- a/tests/unit/adapter-populated-record-array-test.js +++ b/tests/unit/adapter-populated-record-array-test.js @@ -53,7 +53,7 @@ test("when a record is deleted in an adapter populated record array, it should b }; run(function() { - var records = store.push(payload); + var records = store._push(payload); recordArray.loadRecords(records, payload); }); @@ -95,7 +95,7 @@ test("stores the metadata off the payload", function(assert) { }; run(function() { - var records = store.push(payload); + var records = store._push(payload); recordArray.loadRecords(records, payload); }); @@ -131,8 +131,8 @@ test('stores the links off the payload', function(assert) { }; run(function() { - var records = store.push(payload); - recordArray.loadRecords(records, payload); + var internalModels = store._push(payload); + recordArray.loadRecords(internalModels, payload); }); assert.equal(recordArray.get('links.first'), '/foo?page=1', 'expected links.first to be "/foo?page=1" from payload'); diff --git a/tests/unit/record-arrays/adapter-populated-record-array-test.js b/tests/unit/record-arrays/adapter-populated-record-array-test.js index 6385c704189..c8f2c785ab2 100644 --- a/tests/unit/record-arrays/adapter-populated-record-array-test.js +++ b/tests/unit/record-arrays/adapter-populated-record-array-test.js @@ -127,7 +127,7 @@ test('#loadRecords', function(assert) { let meta = { bar:2 }; run(() => { - assert.equal(recordArray.loadRecords([model1, model2], { + assert.equal(recordArray.loadRecords([model1._internalModel, model2._internalModel], { links, meta }), undefined, 'loadRecords should have no return value'); diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index d263b0dc004..31763c87660 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -715,6 +715,50 @@ if (isEnabled('ds-pushpayload-return')) { }); } +test("_push returns an instance of InternalModel if an object is pushed", function(assert) { + let pushResult; + + run(function() { + pushResult = store._push({ + data: { + id: 1, + type: 'person' + } + }); + }); + + assert.ok(pushResult instanceof DS.InternalModel); +}); + +test("_push returns an array of InternalModels if an array is pushed", function(assert) { + let pushResult; + + run(function() { + pushResult = store._push({ + data: [{ + id: 1, + type: 'person' + }] + }); + }); + + assert.ok(pushResult instanceof Array); + assert.ok(pushResult[0] instanceof DS.InternalModel); +}); + + +test("_push returns null if no data is pushed", function(assert) { + let pushResult; + + run(function() { + pushResult = store._push({ + data: null + }); + }); + + assert.strictEqual(pushResult, null); +}); + module("unit/store/push - DS.Store#push with JSON-API", { beforeEach() { var Person = DS.Model.extend({ From 482689c7bf4ded84beccf211017a3b1bcc7746b7 Mon Sep 17 00:00:00 2001 From: IgorT Date: Fri, 21 Oct 2016 02:06:22 +0300 Subject: [PATCH 1658/2527] Fix dummy app serializer We were not correctly deserializing relationships coming from the mock server, because we try to dasherize by default. --- tests/dummy/app/serializers/application.js | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/dummy/app/serializers/application.js diff --git a/tests/dummy/app/serializers/application.js b/tests/dummy/app/serializers/application.js new file mode 100644 index 00000000000..8ac3fba7ce4 --- /dev/null +++ b/tests/dummy/app/serializers/application.js @@ -0,0 +1,7 @@ +import DS from 'ember-data'; + +export default DS.JSONAPISerializer.extend({ + keyForRelationship(key) { + return key; + } +}); From 2ff2107e246b3cb56dcdad09b99794d9599e349f Mon Sep 17 00:00:00 2001 From: tchak Date: Thu, 20 Oct 2016 01:29:15 +0300 Subject: [PATCH 1659/2527] make DS.ManyArray lazy --- addon/-private/system/many-array.js | 8 +- addon/-private/system/references/has-many.js | 16 ++-- .../system/relationships/state/has-many.js | 82 +++++++++++-------- .../integration/adapter/rest-adapter-test.js | 12 ++- tests/integration/record-array-test.js | 13 ++- tests/integration/references/has-many-test.js | 10 ++- .../relationships/has-many-test.js | 3 +- .../inverse-relationships-test.js | 24 ++---- .../relationships/many-to-many-test.js | 22 +++-- .../relationships/one-to-many-test.js | 31 +++++-- tests/integration/store-test.js | 4 +- tests/unit/many-array-test.js | 4 +- .../unit/model/relationships/has-many-test.js | 29 ++++++- 13 files changed, 163 insertions(+), 95 deletions(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 56827f6c783..d3724a34f35 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -56,6 +56,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { init() { this._super(...arguments); this.currentState = Ember.A([]); + this.flushCanonical(); }, record: null, @@ -74,19 +75,18 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { }, flushCanonical() { - //TODO make this smarter, currently its plenty stupid - var toSet = this.canonicalState.filter((internalModel) => !internalModel.isDeleted()); + let toSet = this.canonicalState; //a hack for not removing new records //TODO remove once we have proper diffing - var newRecords = this.currentState.filter( + let newRecords = this.currentState.filter( // only add new records which are not yet in the canonical state of this // relationship (a new record can be in the canonical state if it has // been 'acknowleged' to be in the relationship via a store.push) (internalModel) => internalModel.isNew() && toSet.indexOf(internalModel) === -1 ); toSet = toSet.concat(newRecords); - var oldLength = this.length; + let oldLength = this.length; this.arrayContentWillChange(0, this.length, toSet.length); // It’s possible the parent side of the relationship may have been unloaded by this point if (_objectIsAlive(this)) { diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 8efc18fd6d1..4235e93673e 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -8,7 +8,10 @@ import { import isEnabled from 'ember-data/-private/features'; -const get = Ember.get; +const { + RSVP: { resolve }, + get +} = Ember; var HasManyReference = function(store, parentInternalModel, hasManyRelationship) { this._super$constructor(store, parentInternalModel); @@ -45,11 +48,11 @@ HasManyReference.prototype.ids = function() { }; HasManyReference.prototype.meta = function() { - return this.hasManyRelationship.manyArray.meta; + return this.hasManyRelationship.meta; }; HasManyReference.prototype.push = function(objectOrPromise) { - return Ember.RSVP.resolve(objectOrPromise).then((payload) => { + return resolve(objectOrPromise).then((payload) => { var array = payload; if (isEnabled("ds-overhaul-references")) { @@ -102,7 +105,7 @@ HasManyReference.prototype.push = function(objectOrPromise) { this.hasManyRelationship.computeChanges(internalModels); - return this.hasManyRelationship.manyArray; + return this.hasManyRelationship.getManyArray(); }); }; @@ -122,7 +125,7 @@ HasManyReference.prototype._isLoaded = function() { HasManyReference.prototype.value = function() { if (this._isLoaded()) { - return this.hasManyRelationship.manyArray; + return this.hasManyRelationship.getManyArray(); } return null; @@ -133,8 +136,7 @@ HasManyReference.prototype.load = function() { return this.hasManyRelationship.getRecords(); } - var manyArray = this.hasManyRelationship.manyArray; - return Ember.RSVP.resolve(manyArray); + return resolve(this.hasManyRelationship.getManyArray()); }; HasManyReference.prototype.reload = function() { diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index bae53b3bc8d..9aa3286abf0 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -10,29 +10,40 @@ export default function ManyRelationship(store, record, inverseKey, relationship this._super$constructor(store, record, inverseKey, relationshipMeta); this.belongsToType = relationshipMeta.type; this.canonicalState = []; - this.manyArray = ManyArray.create({ - canonicalState: this.canonicalState, - store: this.store, - relationship: this, - type: this.store.modelFor(this.belongsToType), - record: record - }); this.isPolymorphic = relationshipMeta.options.polymorphic; - this.manyArray.isPolymorphic = this.isPolymorphic; } ManyRelationship.prototype = Object.create(Relationship.prototype); +ManyRelationship.prototype.getManyArray = function() { + if (!this._manyArray) { + this._manyArray = ManyArray.create({ + canonicalState: this.canonicalState, + store: this.store, + relationship: this, + type: this.store.modelFor(this.belongsToType), + record: this.record, + meta: this.meta, + isPolymorphic: this.isPolymorphic + }); + } + return this._manyArray; +}; + ManyRelationship.prototype.constructor = ManyRelationship; ManyRelationship.prototype._super$constructor = Relationship; ManyRelationship.prototype.destroy = function() { - this.manyArray.destroy(); + if (this._manyArray) { + this._manyArray.destroy(); + } }; ManyRelationship.prototype._super$updateMeta = Relationship.prototype.updateMeta; ManyRelationship.prototype.updateMeta = function(meta) { this._super$updateMeta(meta); - this.manyArray.set('meta', meta); + if (this._manyArray) { + this._manyArray.set('meta', meta); + } }; ManyRelationship.prototype._super$addCanonicalRecord = Relationship.prototype.addCanonicalRecord; @@ -54,7 +65,8 @@ ManyRelationship.prototype.addRecord = function(record, idx) { return; } this._super$addRecord(record, idx); - this.manyArray.internalAddRecords([record], idx); + // make lazy later + this.getManyArray().internalAddRecords([record], idx); }; ManyRelationship.prototype._super$removeCanonicalRecordFromOwn = Relationship.prototype.removeCanonicalRecordFromOwn; @@ -74,7 +86,9 @@ ManyRelationship.prototype.removeCanonicalRecordFromOwn = function(record, idx) ManyRelationship.prototype._super$flushCanonical = Relationship.prototype.flushCanonical; ManyRelationship.prototype.flushCanonical = function() { - this.manyArray.flushCanonical(); + if (this._manyArray) { + this._manyArray.flushCanonical(); + } this._super$flushCanonical(); }; @@ -84,11 +98,12 @@ ManyRelationship.prototype.removeRecordFromOwn = function(record, idx) { return; } this._super$removeRecordFromOwn(record, idx); + let manyArray = this.getManyArray(); if (idx !== undefined) { //TODO(Igor) not used currently, fix - this.manyArray.currentState.removeAt(idx); + manyArray.currentState.removeAt(idx); } else { - this.manyArray.internalRemoveRecords([record]); + manyArray.internalRemoveRecords([record]); } }; @@ -99,14 +114,15 @@ ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) }; ManyRelationship.prototype.reload = function() { - var manyArrayLoadedState = this.manyArray.get('isLoaded'); + let manyArray = this.getManyArray(); + let manyArrayLoadedState = manyArray.get('isLoaded'); if (this._loadingPromise) { if (this._loadingPromise.get('isPending')) { return this._loadingPromise; } if (this._loadingPromise.get('isRejected')) { - this.manyArray.set('isLoaded', manyArrayLoadedState); + manyArray.set('isLoaded', manyArrayLoadedState); } } @@ -114,8 +130,8 @@ ManyRelationship.prototype.reload = function() { this._loadingPromise = promiseManyArray(this.fetchLink(), 'Reload with link'); return this._loadingPromise; } else { - this._loadingPromise = promiseManyArray(this.store.scheduleFetchMany(this.manyArray.toArray()).then(() => { - return this.manyArray; + this._loadingPromise = promiseManyArray(this.store.scheduleFetchMany(manyArray.toArray()).then(() => { + return manyArray; }), 'Reload with ids'); return this._loadingPromise; } @@ -158,27 +174,28 @@ ManyRelationship.prototype.fetchLink = function() { } this.store._backburner.join(() => { this.updateRecordsFromAdapter(records); - this.manyArray.set('isLoaded', true); + this.getManyArray().set('isLoaded', true); }); - return this.manyArray; + return this.getManyArray(); }); }; ManyRelationship.prototype.findRecords = function() { - let manyArray = this.manyArray.toArray(); - let internalModels = new Array(manyArray.length); + let manyArray = this.getManyArray() + let array = manyArray.toArray(); + let internalModels = new Array(array.length); - for (let i = 0; i < manyArray.length; i++) { - internalModels[i] = manyArray[i]._internalModel; + for (let i = 0; i < array.length; i++) { + internalModels[i] = array[i]._internalModel; } //TODO CLEANUP return this.store.findMany(internalModels).then(() => { - if (!this.manyArray.get('isDestroyed')) { + if (!manyArray.get('isDestroyed')) { //Goes away after the manyArray refactor - this.manyArray.set('isLoaded', true); + manyArray.set('isLoaded', true); } - return this.manyArray; + return manyArray; }); }; ManyRelationship.prototype.notifyHasManyChanged = function() { @@ -187,6 +204,7 @@ ManyRelationship.prototype.notifyHasManyChanged = function() { ManyRelationship.prototype.getRecords = function() { //TODO(Igor) sync server here, once our syncing is not stupid + let manyArray = this.getManyArray(); if (this.isAsync) { var promise; if (this.link) { @@ -199,18 +217,18 @@ ManyRelationship.prototype.getRecords = function() { promise = this.findRecords(); } this._loadingPromise = PromiseManyArray.create({ - content: this.manyArray, + content: manyArray, promise: promise }); return this._loadingPromise; } else { - assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); + assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", manyArray.isEvery('isEmpty', false)); //TODO(Igor) WTF DO I DO HERE? - if (!this.manyArray.get('isDestroyed')) { - this.manyArray.set('isLoaded', true); + if (!manyArray.get('isDestroyed')) { + manyArray.set('isLoaded', true); } - return this.manyArray; + return manyArray; } }; diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 26510668bf0..0f0167ec8f7 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -291,9 +291,12 @@ test("createRecord - findMany doesn't overwrite owner", function(assert) { run(function() { comment = store.createRecord('comment', { name: "The Parley Letter" }); }); - post.get('comments').pushObject(comment); - assert.equal(comment.get('post'), post, "the post has been set correctly"); + run(function() { + post.get('comments').pushObject(comment); + + assert.equal(comment.get('post'), post, "the post has been set correctly"); + }); run(function() { comment.save().then(assert.wait(function(comment) { @@ -482,7 +485,10 @@ test("createRecord - a record on the many side of a hasMany relationship should }); var post = store.peekRecord('post', 1); - var commentCount = post.get('comments.length'); + var commentCount = run(function() { + return post.get('comments.length'); + }); + assert.equal(commentCount, 1, "the post starts life with a comment"); run(function() { diff --git a/tests/integration/record-array-test.js b/tests/integration/record-array-test.js index d0c0b5f9e10..1bf129bbf37 100644 --- a/tests/integration/record-array-test.js +++ b/tests/integration/record-array-test.js @@ -264,11 +264,14 @@ test('a loaded record is not removed from a record array when it is deleted even }); scumbag = store.peekRecord('person', 1); tag = store.peekRecord('tag', 1); + scumbag.deleteRecord(); }); - assert.equal(tag.get('people.length'), 1, 'record is not removed from the record array'); - assert.equal(tag.get('people').objectAt(0), scumbag, 'tag still has the scumbag'); + run(function() { + assert.equal(tag.get('people.length'), 1, 'record is not removed from the record array'); + assert.equal(tag.get('people').objectAt(0), scumbag, 'tag still has the scumbag'); + }); }); test("a loaded record is not removed from both the record array and from the belongs to, even if the belongsTo side isn't defined", function(assert) { @@ -320,8 +323,10 @@ test("a loaded record is not removed from both the record array and from the bel tool = store.peekRecord('tool', 1); }); - assert.equal(tag.get('people.length'), 1, 'record is in the record array'); - assert.equal(tool.get('person'), scumbag, 'the tool belongs to the record'); + run(function() { + assert.equal(tag.get('people.length'), 1, 'record is in the record array'); + assert.equal(tool.get('person'), scumbag, 'the tool belongs to the record'); + }); run(() => scumbag.deleteRecord()); diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 32fee3c8af6..2ddd2d049ea 100644 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -530,10 +530,12 @@ test("value() returns the referenced records when all records are loaded", funct env.store.push({ data: { type: 'person', id: 2, attributes: { name: "Michael" } } }); }); - var personsReference = family.hasMany('persons'); - var records = personsReference.value(); - assert.equal(get(records, 'length'), 2); - assert.equal(records.isEvery('isLoaded'), true); + run(function() { + var personsReference = family.hasMany('persons'); + var records = personsReference.value(); + assert.equal(get(records, 'length'), 2); + assert.equal(records.isEvery('isLoaded'), true); + }); }); test("load() fetches the referenced records", function(assert) { diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 2300815875a..5509add44a9 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1678,8 +1678,9 @@ test("If reordered hasMany data has been pushed to the store, the many array ref } }); post = env.store.peekRecord('post', 1); + + assert.deepEqual(post.get('comments').toArray(), [comment1, comment2], 'Initial ordering is correct'); }); - assert.deepEqual(post.get('comments').toArray(), [comment1, comment2], 'Initial ordering is correct'); run(function() { env.store.push({ diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index 96d0be84b55..3d26be599b2 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -120,13 +120,11 @@ test("When a record's belongsTo relationship is set, it can specify the inverse run(function() { comment = store.createRecord('comment'); post = store.createRecord('post'); - }); - assert.equal(post.get('meComments.length'), 0, "meComments has no posts"); - assert.equal(post.get('youComments.length'), 0, "youComments has no posts"); - assert.equal(post.get('everyoneWeKnowComments.length'), 0, "everyoneWeKnowComments has no posts"); + assert.equal(post.get('meComments.length'), 0, "meComments has no posts"); + assert.equal(post.get('youComments.length'), 0, "youComments has no posts"); + assert.equal(post.get('everyoneWeKnowComments.length'), 0, "everyoneWeKnowComments has no posts"); - run(function() { comment.set('post', post); }); @@ -355,13 +353,11 @@ test("When a record's belongsTo relationship is set, it can specify the inverse run(function() { user = store.createRecord('user'); post = store.createRecord('post'); - }); - assert.equal(user.get('meMessages.length'), 0, "meMessages has no posts"); - assert.equal(user.get('youMessages.length'), 0, "youMessages has no posts"); - assert.equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(user.get('meMessages.length'), 0, "meMessages has no posts"); + assert.equal(user.get('youMessages.length'), 0, "youMessages has no posts"); + assert.equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); - run(function() { post.set('user', user); }); @@ -402,13 +398,11 @@ test("When a record's polymorphic belongsTo relationship is set, it can specify run(function() { comment = store.createRecord('comment'); post = store.createRecord('post'); - }); - assert.equal(post.get('meMessages.length'), 0, "meMessages has no posts"); - assert.equal(post.get('youMessages.length'), 0, "youMessages has no posts"); - assert.equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(post.get('meMessages.length'), 0, "meMessages has no posts"); + assert.equal(post.get('youMessages.length'), 0, "youMessages has no posts"); + assert.equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); - run(function() { comment.set('message', post); }); diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index 99ca92d786e..f133d1bea4e 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -180,7 +180,7 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan }); }); -test("Fetching a hasMany where a record was removed reflects on the other hasMany side - async", function(assert) { +test("Fetching a hasMany where a record was removed reflects on the other hasMany side - sync", function(assert) { var account, user; run(function() { account = store.push({ @@ -225,8 +225,10 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan }); }); - assert.equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); - assert.equal(account.get('users.length'), 0, 'Users were removed correctly'); + run(function() { + assert.equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); + assert.equal(account.get('users.length'), 0, 'Users were removed correctly'); + }); }); /* @@ -297,7 +299,9 @@ test("Pushing to a hasMany reflects on the other hasMany side - sync", function( stanley.get('accounts').pushObject(account); }); - assert.equal(account.get('users.length'), 1, 'User relationship was set up correctly'); + run(function() { + assert.equal(account.get('users.length'), 1, 'User relationship was set up correctly'); + }); }); test("Removing a record from a hasMany reflects on the other hasMany side - async", function(assert) { @@ -374,12 +378,12 @@ test("Removing a record from a hasMany reflects on the other hasMany side - sync }); }); - assert.equal(account.get('users.length'), 1, 'Users were setup correctly'); run(function() { + assert.equal(account.get('users.length'), 1, 'Users were setup correctly'); account.get('users').removeObject(user); + assert.equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); + assert.equal(account.get('users.length'), 0, 'Users were removed correctly'); }); - assert.equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); - assert.equal(account.get('users.length'), 0, 'Users were removed correctly'); }); /* @@ -465,9 +469,9 @@ test("Deleting a record that has a hasMany relationship removes it from the othe run(function() { account.deleteRecord(); account.rollbackAttributes(); + assert.equal(account.get('users.length'), 1, 'Users are still there'); + assert.equal(user.get('accounts.length'), 1, 'Account got rolledback correctly into the user'); }); - assert.equal(account.get('users.length'), 1, 'Users are still there'); - assert.equal(user.get('accounts.length'), 1, 'Account got rolledback correctly into the user'); }); test("Rollbacking attributes for a created record that has a ManyToMany relationship works correctly - async", function(assert) { diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index 2af63fe7f96..6225205f555 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -189,7 +189,9 @@ test("Relationship is available from the hasMany side even if only loaded from t } }); }); - assert.equal(user.get('accounts').objectAt(0), account, 'Accounts relationship was set up correctly'); + run(function() { + assert.equal(user.get('accounts').objectAt(0), account, 'Accounts relationship was set up correctly'); + }); }); test("Fetching a belongsTo that is set to null removes the record from a relationship - async", function(assert) { @@ -300,7 +302,10 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio } }); }); - assert.equal(user.get('accounts').objectAt(0), null, 'Account was sucesfully removed'); + + run(function() { + assert.equal(user.get('accounts').objectAt(0), null, 'Account was sucesfully removed'); + }); }); test("Fetching a belongsTo that is not defined does not remove the record from a relationship - async", function(assert) { @@ -398,7 +403,10 @@ test("Fetching a belongsTo that is not defined does not remove the record from a } }); }); - assert.equal(user.get('accounts').objectAt(0), account, 'Account was sucesfully removed'); + + run(function() { + assert.equal(user.get('accounts').objectAt(0), account, 'Account was sucesfully removed'); + }); }); test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsTo to null - async", function(assert) { @@ -542,7 +550,10 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT } }); }); - assert.equal(account.get('user'), null, 'User was removed correctly'); + + run(function() { + assert.equal(account.get('user'), null, 'User was removed correctly'); + }); }); test("Fetching the hasMany side where the hasMany is undefined does not change the belongsTo side - async", function(assert) { @@ -657,7 +668,9 @@ test("Fetching the hasMany side where the hasMany is undefined does not change t }); }); - assert.equal(account.get('user'), user, 'User was not removed'); + run(function() { + assert.equal(account.get('user'), user, 'User was not removed'); + }); }); /* @@ -1249,9 +1262,9 @@ test("Rollbacking attributes of a deleted record works correctly when the hasMan run(function() { account.deleteRecord(); account.rollbackAttributes(); + assert.equal(user.get('accounts.length'), 1, "Accounts are rolled back"); + assert.equal(account.get('user'), user, 'Account still has the user'); }); - assert.equal(user.get('accounts.length'), 1, "Accounts are rolled back"); - assert.equal(account.get('user'), user, 'Account still has the user'); }); test("Rollbacking attributes of deleted record works correctly when the belongsTo side has been deleted - async", function(assert) { @@ -1331,9 +1344,9 @@ test("Rollbacking attributes of a deleted record works correctly when the belong run(function() { user.deleteRecord(); user.rollbackAttributes(); + assert.equal(user.get('accounts.length'), 1, "User still has the accounts"); + assert.equal(account.get('user'), user, 'Account has the user again'); }); - assert.equal(user.get('accounts.length'), 1, "User still has the accounts"); - assert.equal(account.get('user'), user, 'Account has the user again'); }); /* diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index ec1a03c47eb..176de164571 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -155,7 +155,9 @@ test("destroying the store correctly cleans everything up", function(assert) { var personWillDestroy = tap(person, 'willDestroy'); var carWillDestroy = tap(car, 'willDestroy'); - var carsWillDestroy = tap(car.get('person.cars'), 'willDestroy'); + var carsWillDestroy = run(function() { + return tap(car.get('person.cars'), 'willDestroy'); + }); env.adapter.query = function() { return [{ diff --git a/tests/unit/many-array-test.js b/tests/unit/many-array-test.js index 49dc753537a..cd2fd323cf5 100644 --- a/tests/unit/many-array-test.js +++ b/tests/unit/many-array-test.js @@ -94,6 +94,7 @@ test("manyArray trigger arrayContentChange functions with the correct values", f var willChangeAddAmt; var originalArrayContentWillChange = DS.ManyArray.prototype.arrayContentWillChange; var originalArrayContentDidChange = DS.ManyArray.prototype.arrayContentDidChange; + DS.ManyArray.reopen({ arrayContentWillChange(startIdx, removeAmt, addAmt) { willChangeStartIdx = startIdx; @@ -138,7 +139,7 @@ test("manyArray trigger arrayContentChange functions with the correct values", f }] }); - store.peekRecord('post', 3); + store.peekRecord('post', 3).get('tags'); store.push({ data: { @@ -158,7 +159,6 @@ test("manyArray trigger arrayContentChange functions with the correct values", f } }); - store.peekRecord('post', 3); }); DS.ManyArray.reopen({ arrayContentWillChange: originalArrayContentWillChange, diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index d57ab8e6cce..db8d92ebb34 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -721,18 +721,16 @@ test("it is possible to add an item to a relationship, remove it, then add it ag var env = setupStore({ tag: Tag, person: Person }); var store = env.store; - var person, tag1, tag2, tag3; + var person, tag1, tag2, tag3, tags; run(function() { person = store.createRecord('person'); tag1 = store.createRecord('tag'); tag2 = store.createRecord('tag'); tag3 = store.createRecord('tag'); - }); - var tags = get(person, 'tags'); + tags = get(person, 'tags'); - run(function() { tags.pushObjects([tag1, tag2, tag3]); tags.removeObject(tag2); }); @@ -771,6 +769,29 @@ test("DS.hasMany is async by default", function(assert) { }); }); +test("DS.ManyArray is lazy", function(assert) { + let Tag = DS.Model.extend({ + name: DS.attr('string'), + people: DS.hasMany('person') + }); + + let Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: false }) + }); + + let env = setupStore({ tag: Tag, person: Person }); + let tag = run(function() { + return env.store.createRecord('tag'); + }); + let hasManyRelationship = tag.hasMany('people').hasManyRelationship; + assert.ok(!hasManyRelationship._manyArray); + run(function() { + tag.get('people'); + }); + assert.ok(hasManyRelationship._manyArray instanceof DS.ManyArray); +}); + testInDebug("throws assertion if of not set with an array", function(assert) { var Person = DS.Model.extend(); var Tag = DS.Model.extend({ From effe89d43ee57a8f1e596451932a83e6cc46bafd Mon Sep 17 00:00:00 2001 From: pangratz Date: Fri, 21 Oct 2016 11:33:23 +0300 Subject: [PATCH 1660/2527] [DOC] Improve warning for mismatched id in store.findRecord --- addon/-private/system/store.js | 6 +++--- addon/-private/system/store/finders.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 5358148d35b..e2922e3553d 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1178,7 +1178,8 @@ Store = Service.extend({ /** This method makes a request for one record, where the `id` is not known - beforehand (if the `id` is known, use `findRecord` instead). + beforehand (if the `id` is known, use [`findRecord`](#method_findRecord) + instead). This method can be used when it is certain that the server will return a single object for the primary data. @@ -1208,8 +1209,7 @@ Store = Service.extend({ The request is made through the adapters' `queryRecord`: - ```javascript - // app/adapters/user.js + ```app/adapters/user.js import DS from "ember-data"; export default DS.Adapter.extend({ diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 97a51f63a0e..3fc2d3fa371 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -39,7 +39,7 @@ export function _find(adapter, store, typeClass, id, internalModel, options) { var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, id, 'findRecord'); assert('Ember Data expected the primary data returned from a `findRecord` response to be an object but instead it found an array.', !Array.isArray(payload.data)); - warn(`You requested a record of type '${typeClass.modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Looks like you want to use store.queryRecord instead http://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, payload.data.id === id, { + warn(`You requested a record of type '${typeClass.modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead http://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, payload.data.id === id, { id: 'ds.store.findRecord.id-mismatch' }); From 36bc08ab942d0a4113178f1c131c9e7024f0c995 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 18 Oct 2016 02:08:29 -0700 Subject: [PATCH 1661/2527] feat(improved-cache): makes the adapter/serializer instance cache faster. Reduces the number of lookups, sets, expense of detection, allocations for fallbacks. Also includes additional internalModel cleanup and backburner/state machine optimizations, and deprecates store.lookupAdater and store.lookupSerializer --- addon/-private/system/store.js | 71 +++------- .../system/store/container-instance-cache.js | 128 +++++++++++------- tests/helpers/store.js | 2 +- 3 files changed, 101 insertions(+), 100 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 5358148d35b..085860f770d 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -4,7 +4,7 @@ import Ember from 'ember'; import Model from 'ember-data/model'; -import { instrument, assert, warn, runInDebug } from "ember-data/-private/debug"; +import { instrument, assert, deprecate, warn, runInDebug } from "ember-data/-private/debug"; import _normalizeLink from "ember-data/-private/system/normalize-link"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; import { InvalidError } from 'ember-data/adapters/errors'; @@ -97,7 +97,6 @@ const { normalize, peekAll, peekRecord, - retrieveManagedInstance, serializerFor, typeMapFor, typeMapFor_allocate @@ -116,7 +115,6 @@ const { 'normalize', 'peekAll', 'peekRecord', - 'retrieveManagedInstance', 'serializerFor', 'typeMapFor', 'typeMapFor_allocate' @@ -210,7 +208,8 @@ Store = Service.extend({ store: this }); this._pendingSave = []; - this._instanceCache = new ContainerInstanceCache(getOwner(this)); + this._instanceCache = new ContainerInstanceCache(getOwner(this), this); + //Used to keep track of all the find requests that need to be coalesced this._pendingFetch = Map.create(); }, @@ -267,13 +266,11 @@ Store = Service.extend({ @return DS.Adapter */ defaultAdapter: Ember.computed('adapter', function() { - var adapter = get(this, 'adapter'); + let adapter = get(this, 'adapter'); assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name', typeof adapter === 'string'); - adapter = this.retrieveManagedInstance('adapter', adapter); - - return adapter; + return this.adapterFor(adapter); }), // ..................... @@ -2456,7 +2453,9 @@ Store = Service.extend({ assert("You need to pass a model name to the store's adapterFor method", isPresent(modelName)); assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); - return this.lookupAdapter(modelName); + let normalizedModelName = normalizeModelName(modelName); + + return this._instanceCache.get('adapter', normalizedModelName); }, _adapterRun(fn) { @@ -2493,60 +2492,34 @@ Store = Service.extend({ assert("You need to pass a model name to the store's serializerFor method", isPresent(modelName)); assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); - var fallbacks = [ - 'application', - this.adapterFor(modelName).get('defaultSerializer'), - '-default' - ]; + let normalizedModelName = normalizeModelName(modelName); - var serializer = this.lookupSerializer(modelName, fallbacks); - return serializer; - }, - - /** - Retrieve a particular instance from the - container cache. If not found, creates it and - placing it in the cache. - - Enabled a store to manage local instances of - adapters and serializers. - - @method retrieveManagedInstance - @private - @param {String} modelName the object modelName - @param {String} name the object name - @param {Array} fallbacks the fallback objects to lookup if the lookup for modelName or 'application' fails - @return {Ember.Object} - */ - retrieveManagedInstance(type, modelName, fallbacks) { - heimdall.increment(retrieveManagedInstance); - var normalizedModelName = normalizeModelName(modelName); - - var instance = this._instanceCache.get(type, normalizedModelName, fallbacks); - set(instance, 'store', this); - return instance; + return this._instanceCache.get('serializer', normalizedModelName); }, lookupAdapter(name) { - return this.retrieveManagedInstance('adapter', name, this.get('_adapterFallbacks')); + deprecate(`Use of lookupAdapter is deprecated, use adapterFor instead.`, { + id: 'ds.store.lookupAdapter', + until: '3.0' + }); + return this.adapterFor(name); }, - _adapterFallbacks: Ember.computed('adapter', function() { - var adapter = this.get('adapter'); - return ['application', adapter, '-json-api']; - }), - - lookupSerializer(name, fallbacks) { - return this.retrieveManagedInstance('serializer', name, fallbacks); + lookupSerializer(name) { + deprecate(`Use of lookupSerializer is deprecated, use serializerFor instead.`, { + id: 'ds.store.lookupSerializer', + until: '3.0' + }); + return this.serializerFor(name); }, willDestroy() { this._super(...arguments); this.recordArrayManager.destroy(); + this._instanceCache.destroy(); this.unloadAll(); } - }); function deserializeRecordId(store, key, relationship, id) { diff --git a/addon/-private/system/store/container-instance-cache.js b/addon/-private/system/store/container-instance-cache.js index a5127af3238..08c8cf1e0c0 100644 --- a/addon/-private/system/store/container-instance-cache.js +++ b/addon/-private/system/store/container-instance-cache.js @@ -1,7 +1,15 @@ /* global heimdall */ import Ember from 'ember'; import EmptyObject from "ember-data/-private/system/empty-object"; -const assign = Ember.assign || Ember.merge; +const { set } = Ember; + +const { + __get, + _instanceFor +} = heimdall.registerMonitor('system.store.container-instance-cache', + '__get', + '_instanceFor' +); /* * The `ContainerInstanceCache` serves as a lazy cache for looking up @@ -12,71 +20,86 @@ const assign = Ember.assign || Ember.merge; * when the preferred lookup fails. For example, say you try to look up `adapter:post`, * but there is no entry (app/adapters/post.js in EmberCLI) for `adapter:post` in the registry. * - * The `fallbacks` array passed will then be used; the first entry in the fallbacks array - * that exists in the container will then be cached for `adapter:post`. So, the next time you - * look up `adapter:post`, you'll get the `adapter:application` instance (or whatever the fallback - * was if `adapter:application` doesn't exist). + * When an adapter or serializer is unfound, getFallbacks will be invoked with the current namespace + * ('adapter' or 'serializer') and the 'preferredKey' (usually a modelName). The method should return + * an array of keys to check against. + * + * The first entry in the fallbacks array that exists in the container will then be cached for + * `adapter:post`. So, the next time you look up `adapter:post`, you'll get the `adapter:application` + * instance (or whatever the fallback was if `adapter:application` doesn't exist). * * @private * @class ContainerInstanceCache * */ -export default function ContainerInstanceCache(owner) { - this._owner = owner; - this._cache = new EmptyObject(); -} +export default class ContainerInstanceCache { + constructor(owner, store) { + this._owner = owner; + this._store = store; + this._namespaces = { + adapter: new EmptyObject(), + serializer: new EmptyObject() + }; + } -const { - __get, - instanceFor -} = heimdall.registerMonitor('system.store.container-instance-cache', - 'get', - 'instanceFor' -); + get(namespace, preferredKey) { + heimdall.increment(__get); + let cache = this._namespaces[namespace]; -ContainerInstanceCache.prototype = new EmptyObject(); + if (cache[preferredKey]) { + return cache[preferredKey]; + } -assign(ContainerInstanceCache.prototype, { - get(type, preferredKey, fallbacks) { - heimdall.increment(__get); - let cache = this._cache; - let preferredLookupKey = `${type}:${preferredKey}`; + let preferredLookupKey = `${namespace}:${preferredKey}`; - if (!(preferredLookupKey in cache)) { - let instance = this.instanceFor(preferredLookupKey) || this._findInstance(type, fallbacks); - if (instance) { - cache[preferredLookupKey] = instance; - } + let instance = this._instanceFor(preferredLookupKey) || this._findInstance(namespace, this._fallbacksFor(namespace, preferredKey)); + if (instance) { + cache[preferredKey] = instance; + set(instance, 'store', this._store); } - return cache[preferredLookupKey]; - }, - _findInstance(type, fallbacks) { + return cache[preferredKey]; + } + + _fallbacksFor(namespace, preferredKey) { + if (namespace === 'adapter') { + return ['application', this._store.get('adapter'), '-json-api']; + } + + // serializer + return [ + 'application', + this.get('adapter', preferredKey).get('defaultSerializer'), + '-default' + ]; + } + + _findInstance(namespace, fallbacks) { + let cache = this._namespaces[namespace]; + for (let i = 0, length = fallbacks.length; i < length; i++) { let fallback = fallbacks[i]; - let lookupKey = `${type}:${fallback}`; - let instance = this.instanceFor(lookupKey); - if (instance) { - return instance; + if (cache[fallback]) { + return cache[fallback]; } - } - }, - instanceFor(key) { - heimdall.increment(instanceFor); - let cache = this._cache; - if (!cache[key]) { - let instance = this._owner.lookup(key); + let lookupKey = `${namespace}:${fallback}`; + let instance = this._instanceFor(lookupKey); + if (instance) { - cache[key] = instance; + cache[fallback] = instance; + return instance; } } - return cache[key]; - }, + } - destroy() { - let cache = this._cache; + _instanceFor(key) { + heimdall.increment(_instanceFor); + return this._owner.lookup(key); + } + + destroyCache(cache) { let cacheEntries = Object.keys(cache); for (let i = 0, length = cacheEntries.length; i < length; i++) { @@ -86,12 +109,17 @@ assign(ContainerInstanceCache.prototype, { cacheEntry.destroy(); } } - this._owner = null; - }, + } - constructor: ContainerInstanceCache, + destroy() { + this.destroyCache(this._namespaces.adapter); + this.destroyCache(this._namespaces.serializer); + this._namespaces = null; + this._store = null; + this._owner = null; + } toString() { return 'ContainerInstanceCache'; } -}); +} diff --git a/tests/helpers/store.js b/tests/helpers/store.js index a2a4ef22545..4b87186e428 100644 --- a/tests/helpers/store.js +++ b/tests/helpers/store.js @@ -65,7 +65,7 @@ export default function setupStore(options) { return env; } -export {setupStore}; +export { setupStore }; export function createStore(options) { return setupStore(options).store; From 49dee7f270868fbee33307c1d42ef78ead82fee8 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 22 Jun 2016 12:27:49 -0400 Subject: [PATCH 1662/2527] Add examples to the Serializer API docs --- addon/serializer.js | 81 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/addon/serializer.js b/addon/serializer.js index 1601766770d..049300c692c 100644 --- a/addon/serializer.js +++ b/addon/serializer.js @@ -27,10 +27,21 @@ import Ember from 'ember'; export default Ember.Object.extend({ /** - The `store` property is the application's `store` that contains all records. - It's injected as a service. - It can be used to push records from a non flat data structure server - response. + The `store` property is the application's `store` that contains + all records. It can be used to look up serializer for other model + type that may be nested inside the payload response. + + Example: + + ```js + Serializer.extend({ + extractRelationship: function(relationshipModelName, relationshipHash) { + var modelClass = this.store.modelFor(relationshipModelName); + var relationshipSerializer = this.store.serializerFor(relationshipModelName); + return relationshipSerializer.normalize(modelClass, relationshipHash); + } + }); + ``` @property store @type {DS.Store} @@ -43,6 +54,25 @@ export default Ember.Object.extend({ http://jsonapi.org/format/#document-structure + Example: + + ```js + Serializer.extend({ + normalizeResponse(store, primaryModelClass, payload, id, requestType) { + if (requestType === 'findRecord') { + return this.normalize(primaryModelClass, payload); + } else { + return payload.reduce(function(documentHash, item) { + let { data, included } = this.normalize(primaryModelClass, item); + documentHash.included.push(...included); + documentHash.data.push(data); + return documentHash; + }, { data: [], included: [] }) + } + } + }); + ``` + @since 1.13.0 @method normalizeResponse @param {DS.Store} store @@ -63,8 +93,34 @@ export default Ember.Object.extend({ - `includeId`: If this is `true`, `serialize` should include the ID in the serialized object it builds. + Example: + + ```js + Serializer.extend({ + serialize(snapshot, options) { + var json = { + id: snapshot.id + }; + + snapshot.eachAttribute((key, attribute) => { + json[key] = snapshot.attr(key); + }); + + snapshot.eachRelationship((key, relationship) => { + if (relationship.kind === 'belongsTo') { + json[key] = snapshot.belongsTo(key, { id: true }); + } else if (relationship.kind === 'hasMany') { + json[key] = snapshot.hasMany(key, { ids: true }); + } + }); + + return json; + }, + }); + ``` + @method serialize - @param {DS.Model} record + @param {DS.Snapshot} record @param {Object} [options] @return {Object} */ @@ -76,6 +132,21 @@ export default Ember.Object.extend({ should override this method, munge the hash and return the normalized payload. + Example: + + ```js + Serializer.extend({ + normalize(modelClass, resourceHash) { + var data = { + id: resourceHash.id, + type: modelClass.modelName, + attributes: resourceHash + }; + return { data: data }; + } + }) + ``` + @method normalize @param {DS.Model} typeClass @param {Object} hash From eba4aef0ea5f2f65ef87a508f312de4bf1aa9dde Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Thu, 20 Oct 2016 22:39:50 +0300 Subject: [PATCH 1663/2527] Don't notify belongsTo changes if nothing changed --- .../system/relationships/state/belongs-to.js | 6 +- .../records/relationship-changes-test.js | 108 ++++++++++++++++++ 2 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 tests/integration/records/relationship-changes-test.js diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 4dcb1a0322e..bcdffb60699 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -60,8 +60,10 @@ BelongsToRelationship.prototype.flushCanonical = function() { if (this.inverseRecord && this.inverseRecord.isNew() && !this.canonicalState) { return; } - this.inverseRecord = this.canonicalState; - this.record.notifyBelongsToChanged(this.key); + if (this.inverseRecord !== this.canonicalState) { + this.inverseRecord = this.canonicalState; + this.record.notifyBelongsToChanged(this.key); + } this._super$flushCanonical(); }; diff --git a/tests/integration/records/relationship-changes-test.js b/tests/integration/records/relationship-changes-test.js new file mode 100644 index 00000000000..b798556bf84 --- /dev/null +++ b/tests/integration/records/relationship-changes-test.js @@ -0,0 +1,108 @@ +import setupStore from 'dummy/tests/helpers/store'; +import Ember from 'ember'; +import DS from 'ember-data'; +import { module, test } from 'qunit'; + +const { run } = Ember; +const { attr, belongsTo, Model } = DS; + +const Author = Model.extend({ + name: attr('string') +}); + +const Post = Model.extend({ + author: belongsTo() +}); + +let env; + +module('integration/records/relationship-changes - Relationship changes', { + beforeEach() { + env = setupStore({ + author: Author, + post: Post + }); + }, + + afterEach() { + run(function() { + env.container.destroy(); + }); + } +}); + +test('Calling push with updated belongsTo relationship trigger observer', function(assert) { + assert.expect(1); + + let observerCount = 0; + + run(function() { + let post = env.store.push({ + data: { + type: 'post', + id: '1', + relationships: { + author: { + data: { type: 'author', id: '2' } + } + } + } + }); + + post.addObserver('author', function() { + observerCount++; + }); + + env.store.push({ + data: { + type: 'post', + id: '1', + relationships: { + author: { + data: { type: 'author', id: '3' } + } + } + } + }); + }); + + assert.equal(observerCount, 1, 'author observer should be triggered once'); +}); + +test('Calling push with same belongsTo relationship does not trigger observer', function(assert) { + assert.expect(1); + + let observerCount = 0; + + run(function() { + let post = env.store.push({ + data: { + type: 'post', + id: '1', + relationships: { + author: { + data: { type: 'author', id: '2' } + } + } + } + }); + + post.addObserver('author', function() { + observerCount++; + }); + + env.store.push({ + data: { + type: 'post', + id: '1', + relationships: { + author: { + data: { type: 'author', id: '2' } + } + } + } + }); + }); + + assert.equal(observerCount, 0, 'author observer should not be triggered'); +}); From df1a2e934adff118a113d11620ebcb96b3c76df5 Mon Sep 17 00:00:00 2001 From: pangratz Date: Fri, 21 Oct 2016 22:48:44 +0300 Subject: [PATCH 1664/2527] Assert that InternalModel is indeed not materialized on store._push --- tests/unit/store/push-test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index 31763c87660..eaa29a0c2e2 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -728,6 +728,7 @@ test("_push returns an instance of InternalModel if an object is pushed", functi }); assert.ok(pushResult instanceof DS.InternalModel); + assert.notOk(pushResult.record, 'InternalModel is not materialized'); }); test("_push returns an array of InternalModels if an array is pushed", function(assert) { @@ -744,6 +745,7 @@ test("_push returns an array of InternalModels if an array is pushed", function( assert.ok(pushResult instanceof Array); assert.ok(pushResult[0] instanceof DS.InternalModel); + assert.notOk(pushResult[0].record, 'InternalModel is not materialized'); }); From 6982fc0c1c5fc0f5a2074073376fcfe3177011b8 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Fri, 21 Oct 2016 22:57:34 +0300 Subject: [PATCH 1665/2527] [DOC] Minor changes to addon/serializer.js --- addon/serializer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/serializer.js b/addon/serializer.js index 049300c692c..d15cf4d9acf 100644 --- a/addon/serializer.js +++ b/addon/serializer.js @@ -28,8 +28,8 @@ export default Ember.Object.extend({ /** The `store` property is the application's `store` that contains - all records. It can be used to look up serializer for other model - type that may be nested inside the payload response. + all records. It can be used to look up serializers for other model + types that may be nested inside the payload response. Example: @@ -120,7 +120,7 @@ export default Ember.Object.extend({ ``` @method serialize - @param {DS.Snapshot} record + @param {DS.Snapshot} snapshot @param {Object} [options] @return {Object} */ From c88215c6fe6d5f83f754207fe311ee236ae88fdc Mon Sep 17 00:00:00 2001 From: pangratz Date: Fri, 21 Oct 2016 19:10:17 +0300 Subject: [PATCH 1666/2527] [DOC] Mark `errorsHashToArray` and `errorsArrayToHash` public This methods are already present on the `DS` namespace, so this change marks the officially as public and adds documentation how they can be used. --- addon/adapters/errors.js | 82 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/addon/adapters/errors.js b/addon/adapters/errors.js index 84500994751..23cbed79dcb 100644 --- a/addon/adapters/errors.js +++ b/addon/adapters/errors.js @@ -166,8 +166,50 @@ export const ServerError = extendedErrorsEnabled ? extend(AdapterError, 'The adapter operation failed due to a server error') : null; /** + Convert an hash of errors into an array with errors in JSON-API format. + + ```javascript + import DS from 'ember-data'; + + const { errorsHashToArray } = DS; + + let errors = { + base: "Invalid attributes on saving this record", + name: "Must be present", + age: ["Must be present", "Must be a number"] + }; + + let errorsArray = errorsHashToArray(errors); + // [ + // { + // title: "Invalid Document", + // detail: "Invalid attributes on saving this record", + // source: { pointer: "/data" } + // }, + // { + // title: "Invalid Attribute", + // detail: "Must be present", + // source: { pointer: "/data/attributes/name" } + // }, + // { + // title: "Invalid Attribute", + // detail: "Must be present", + // source: { pointer: "/data/attributes/age" } + // }, + // { + // title: "Invalid Attribute", + // detail: "Must be a number", + // source: { pointer: "/data/attributes/age" } + // } + // ] + ``` + @method errorsHashToArray - @private + @public + @namespace + @for DS + @param {Object} errors hash with errors as properties + @return {Array} array of errors in JSON-API format */ export function errorsHashToArray(errors) { let out = []; @@ -197,8 +239,44 @@ export function errorsHashToArray(errors) { } /** + Convert an array of errors in JSON-API format into an object. + + ```javascript + import DS from 'ember-data'; + + const { errorsArrayToHash } = DS; + + let errorsArray = [ + { + title: "Invalid Attribute", + detail: "Must be present", + source: { pointer: "/data/attributes/name" } + }, + { + title: "Invalid Attribute", + detail: "Must be present", + source: { pointer: "/data/attributes/age" } + }, + { + title: "Invalid Attribute", + detail: "Must be a number", + source: { pointer: "/data/attributes/age" } + } + ]; + + let errors = errorsArrayToHash(errorsArray); + // { + // "name": ["Must be present"], + // "age": ["Must be present", "must be a number"] + // } + ``` + @method errorsArrayToHash - @private + @public + @namespace + @for DS + @param {Array} errors array of errors in JSON-API format + @return {Object} */ export function errorsArrayToHash(errors) { let out = {}; From bdf8556b7715d5d8309381e7d813c01faef1686e Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Thu, 20 Oct 2016 17:59:37 +0300 Subject: [PATCH 1667/2527] [WARNING] Warn when extending JSONAPISerializer with extractMeta --- addon/serializers/json-api.js | 39 ++++++++++++++++++- .../serializers/json-api-serializer-test.js | 8 ++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 52acb8871b2..44022ab98ca 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -93,6 +93,39 @@ var dasherize = Ember.String.dasherize; to the format that the Ember Data store expects. + ### Customizing meta + + Since a JSON API Document can have meta defined in multiple locations you can + use the specific serializer hooks if you need to customize the meta. + + One scenario would be to camelCase the meta keys of your payload. The example + below shows how this could be done using `normalizeArrayResponse` and + `extractRelationship`. + + ```app/serializers/application.js + export default JSONAPISerializer.extend({ + + normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) { + let normalizedDocument = this._super(...arguments); + + // Customize document meta + normalizedDocument.meta = camelCaseKeys(normalizedDocument.meta); + + return normalizedDocument; + }, + + extractRelationship(relationshipHash) { + let normalizedRelationship = this._super(...arguments); + + // Customize relationship meta + normalizedRelationship.meta = camelCaseKeys(normalizedRelationship.meta); + + return normalizedRelationship; + } + + }); + ``` + @since 1.13.0 @class JSONAPISerializer @namespace DS @@ -737,6 +770,10 @@ if (isEnabled("ds-payload-type-hooks")) { runInDebug(function() { JSONAPISerializer.reopen({ willMergeMixin(props) { + var constructor = this.constructor; + warn(`You've defined 'extractMeta' in ${constructor.toString()} which is not used for serializers extending JSONAPISerializer. Read more at http://emberjs.com/api/data/classes/DS.JSONAPISerializer.html#toc_customizing-meta on how to customize meta when using JSON API.`, Ember.isNone(props.extractMeta) || props.extractMeta === JSONSerializer.prototype.extractMeta, { + id: 'ds.serializer.json-api.extractMeta' + }); warn('The JSONAPISerializer does not work with the EmbeddedRecordsMixin because the JSON API spec does not describe how to format embedded resources.', !props.isEmbeddedRecordsMixin, { id: 'ds.serializer.embedded-records-mixin-not-supported' }); @@ -745,7 +782,7 @@ runInDebug(function() { return 'Encountered a resource object with an undefined type (resolved resource using ' + this.constructor.toString() + ')'; }, warnMessageNoModelForType(modelName, originalType, usedLookup) { - return `Encountered a resource object with type "${originalType}", but no model was found for model name "${modelName}" (resolved model name using '${this.constructor.toString()}.${usedLookup}("${originalType}")).`; + return `Encountered a resource object with type "${originalType}", but no model was found for model name "${modelName}" (resolved model name using '${this.constructor.toString()}.${usedLookup}("${originalType}")').`; } }); }); diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 64aa398ba17..fb7d242166b 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -286,6 +286,14 @@ test('options are passed to transform for serialization', function(assert) { env.store.serializerFor('user').serialize(user._createSnapshot()); }); +testInDebug('Warns when defining extractMeta()', function(assert) { + assert.expectWarning(function() { + DS.JSONAPISerializer.extend({ + extractMeta() {} + }).create(); + }, /You've defined 'extractMeta' in/); +}); + testInDebug('JSON warns when combined with EmbeddedRecordsMixin', function(assert) { assert.expectWarning(function() { DS.JSONAPISerializer.extend(DS.EmbeddedRecordsMixin).create(); From 2790f8bbdd21d72ff06d1c0c45c991853c2f0cf3 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Sat, 22 Oct 2016 02:27:56 +0300 Subject: [PATCH 1668/2527] Assert when original and not normalized key is found in payload --- addon/serializers/json-api.js | 10 +++++ .../serializers/json-api-serializer-test.js | 41 +++++++++++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 52acb8871b2..107ed1b3d0c 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -265,6 +265,11 @@ const JSONAPISerializer = JSONSerializer.extend({ if (resourceHash.attributes[attributeKey] !== undefined) { attributes[key] = resourceHash.attributes[attributeKey]; } + runInDebug(() => { + if (resourceHash.attributes[attributeKey] === undefined && resourceHash.attributes[key] !== undefined) { + assert(`Your payload for '${modelClass.modelName}' contains '${key}', but your serializer is setup to look for '${attributeKey}'. This is most likely because Ember Data's JSON API serializer dasherizes attribute keys by default. You should subclass JSONAPISerializer and implement 'keyForAttribute(key) { return key; }' to prevent Ember Data from customizing your attribute keys.`, false); + } + }); }); } @@ -314,6 +319,11 @@ const JSONAPISerializer = JSONSerializer.extend({ relationships[key] = this.extractRelationship(relationshipHash); } + runInDebug(() => { + if (resourceHash.relationships[relationshipKey] === undefined && resourceHash.relationships[key] !== undefined) { + assert(`Your payload for '${modelClass.modelName}' contains '${key}', but your serializer is setup to look for '${relationshipKey}'. This is most likely because Ember Data's JSON API serializer dasherizes relationship keys by default. You should subclass JSONAPISerializer and implement 'keyForRelationship(key) { return key; }' to prevent Ember Data from customizing your relationship keys.`, false); + } + }); }); } diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 64aa398ba17..342a0c7f2a7 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -22,7 +22,8 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', { lastName: DS.attr('string'), title: DS.attr('string'), handles: DS.hasMany('handle', { async: true, polymorphic: true }), - company: DS.belongsTo('company', { async: true }) + company: DS.belongsTo('company', { async: true }), + reportsTo: DS.belongsTo('user', { async: true, inverse: null }) }); Handle = DS.Model.extend({ @@ -292,6 +293,38 @@ testInDebug('JSON warns when combined with EmbeddedRecordsMixin', function(asser }, /The JSONAPISerializer does not work with the EmbeddedRecordsMixin/); }); +testInDebug('Asserts when normalized attribute key is not found in payload but original key is', function(assert) { + var jsonHash = { + data: { + type: 'users', + id: '1', + attributes: { + 'firstName': 'Yehuda' + } + } + }; + assert.expectAssertion(function() { + env.store.serializerFor("user").normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); + }, /Your payload for 'user' contains 'firstName', but your serializer is setup to look for 'first-name'/); +}); + +testInDebug('Asserts when normalized relationship key is not found in payload but original key is', function(assert) { + var jsonHash = { + data: { + type: 'users', + id: '1', + relationships: { + 'reportsTo': { + data: null + } + } + } + }; + assert.expectAssertion(function() { + env.store.serializerFor("user").normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); + }, /Your payload for 'user' contains 'reportsTo', but your serializer is setup to look for 'reports-to'/); +}); + if (isEnabled("ds-payload-type-hooks")) { test('mapping of payload type can be customized via modelNameFromPayloadType', function(assert) { env.registry.register('serializer:user', DS.JSONAPISerializer.extend({ @@ -409,7 +442,8 @@ if (isEnabled("ds-payload-type-hooks")) { handles: { serialize: true }, firstName: { serialize: false }, lastName: { serialize: false }, - title: { serialize: false } + title: { serialize: false }, + reportsTo: { serialize: false } }, payloadTypeFromModelName: function(modelName) { return `api::v1::${modelName}`; @@ -470,7 +504,8 @@ if (isEnabled("ds-payload-type-hooks")) { handles: { serialize: true }, firstName: { serialize: false }, lastName: { serialize: false }, - title: { serialize: false } + title: { serialize: false }, + reportsTo: { serialize: false } }, payloadKeyFromModelName: function(modelName) { return `api::v1::${modelName}`; From 890d05174e5820a8a3e58e1238da8514cf7f6616 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 20 Oct 2016 00:44:02 +0300 Subject: [PATCH 1669/2527] [PERF pt.1] avoid extra scanning of recordArrays when adding records MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * make adding/removing from recordArrays private * make recordArray add/remove support batches * rename addInternalModel -> _pushInternalModels to be more accurate (push not add, and plural)) * [PERF] don’t use addObject in recordArrays, as the RecordArrayManager via internalRecord._recordArrays already checks containment, no need in duplicating that work by re-scanning addObject for each record added to the recordArray. * add tests, covering the duplication behavior * add comments, to ensure we don’t accidentally go back to pushObject --- addon/-private/system/record-array-manager.js | 6 +-- .../system/record-arrays/record-array.js | 11 ++-- tests/unit/record-arrays/record-array-test.js | 54 ++++++++++++------- 3 files changed, 45 insertions(+), 26 deletions(-) diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 32b103a33ea..c87795376cc 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -123,7 +123,7 @@ export default Ember.Object.extend({ if (!recordArrays) { return; } - recordArrays.forEach(array => array.removeInternalModel(record)); + recordArrays.forEach(array => array._removeInternalModels([record])); record._recordArrays = null; }, @@ -174,7 +174,7 @@ export default Ember.Object.extend({ this._addRecordToRecordArray(array, record); } else { recordArrays.delete(array); - array.removeInternalModel(record); + array._removeInternalModels([record]); } }, @@ -182,7 +182,7 @@ export default Ember.Object.extend({ heimdall.increment(_addRecordToRecordArray); let recordArrays = this.recordArraysForRecord(record); if (!recordArrays.has(array)) { - array.addInternalModel(record); + array._pushInternalModels([record]); recordArrays.add(array); } }, diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index 68da7f38196..cd05a98023b 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -158,8 +158,11 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @private @param {InternalModel} internalModel */ - addInternalModel(internalModel) { - get(this, 'content').addObject(internalModel); + _pushInternalModels(internalModels) { + // pushObjects because the internalModels._recordArrays set was already + // consulted for inclusion, so addObject and its on .contains call is not + // required. + get(this, 'content').pushObjects(internalModels); }, /** @@ -169,8 +172,8 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @private @param {InternalModel} internalModel */ - removeInternalModel(internalModel) { - get(this, 'content').removeObject(internalModel); + _removeInternalModels(internalModels) { + get(this, 'content').removeObjects(internalModels); }, /** diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js index ba693dae2f8..eb4f68a15cf 100644 --- a/tests/unit/record-arrays/record-array-test.js +++ b/tests/unit/record-arrays/record-array-test.js @@ -137,43 +137,59 @@ test('#update while updating', function(assert) { }); }); -test('#addInternalMdoel', function(assert) { +test('#_pushInternalModels', function(assert) { let content = Ember.A(); let recordArray = RecordArray.create({ content }); - let model1 = { getRecord() { return 'model-1'; } }; + let model1 = { id: 1, getRecord() { return 'model-1'; } }; + let model2 = { id: 2, getRecord() { return 'model-2'; } }; + let model3 = { id: 3, getRecord() { return 'model-3'; } }; - assert.equal(recordArray.addInternalModel(model1), undefined, 'addInternalModel has no return value'); - assert.deepEqual(content, [model1]); + assert.equal(recordArray._pushInternalModels([model1]), undefined, '_pushInternalModels has no return value'); + assert.deepEqual(content, [model1], 'now contains model1'); - // cannot add duplicates - recordArray.addInternalModel(model1); - assert.deepEqual(content, [model1]); + recordArray._pushInternalModels([model1]); + assert.deepEqual(content, [model1, model1], 'allows duplicates, because record-array-manager via internalModel._recordArrays ensures no duplicates, this layer should not double check'); + + recordArray._removeInternalModels([model1]); + recordArray._pushInternalModels([model1]); + + // can add multiple models at once + recordArray._pushInternalModels([model2, model3]); + assert.deepEqual(content, [model1, model2, model3], 'now contains model1, model2, model3'); }); -test('#removeInternalModel', function(assert) { +test('#_removeInternalModels', function(assert) { let content = Ember.A(); let recordArray = RecordArray.create({ content }); - let model1 = { getRecord() { return 'model-1'; } }; - let model2 = { getRecord() { return 'model-2'; } }; + let model1 = { id: 1, getRecord() { return 'model-1'; } }; + let model2 = { id: 2, getRecord() { return 'model-2'; } }; + let model3 = { id: 3, getRecord() { return 'model-3'; } }; assert.equal(content.length, 0); - assert.equal(recordArray.removeInternalModel(model1), undefined, 'removeInternalModel has no return value'); - assert.deepEqual(content, []); + assert.equal(recordArray._removeInternalModels([model1]), undefined, '_removeInternalModels has no return value'); + assert.deepEqual(content, [], 'now contains no models'); + + recordArray._pushInternalModels([model1, model2]); + + assert.deepEqual(content, [model1, model2], 'now contains model1, model2,'); + assert.equal(recordArray._removeInternalModels([model1]), undefined, '_removeInternalModels has no return value'); + assert.deepEqual(content, [model2], 'now only contains model2'); + assert.equal(recordArray._removeInternalModels([model2]), undefined, '_removeInternalModels has no return value'); + assert.deepEqual(content, [], 'now contains no models'); + + recordArray._pushInternalModels([model1, model2, model3]) - recordArray.addInternalModel(model1); - recordArray.addInternalModel(model2); + assert.equal(recordArray._removeInternalModels([model1, model3]), undefined, '_removeInternalModels has no return value'); - assert.deepEqual(content, [model1, model2]); - assert.equal(recordArray.removeInternalModel(model1), undefined, 'removeInternalModel has no return value'); - assert.deepEqual(content, [model2]); - assert.equal(recordArray.removeInternalModel(model2), undefined, 'removeInternalModel has no return value'); - assert.deepEqual(content, []); + assert.deepEqual(content, [model2], 'now contains model2'); + assert.equal(recordArray._removeInternalModels([model2]), undefined, '_removeInternalModels has no return value'); + assert.deepEqual(content, [], 'now contains no models'); }); function internalModelFor(record) { From f5c2ba57ef6f2ffd937474829c77cd39bbab259f Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 21 Oct 2016 15:42:11 +0300 Subject: [PATCH 1670/2527] tidy up tests related to adapter-populated-record-arrays * cleanup code * move non-unit tests to integration folder --- .../adapter-populated-record-array-test.js | 322 ++++++++++++++++++ .../adapter-populated-record-array-test.js | 206 ----------- 2 files changed, 322 insertions(+), 206 deletions(-) create mode 100644 tests/integration/record-arrays/adapter-populated-record-array-test.js delete mode 100644 tests/unit/adapter-populated-record-array-test.js diff --git a/tests/integration/record-arrays/adapter-populated-record-array-test.js b/tests/integration/record-arrays/adapter-populated-record-array-test.js new file mode 100644 index 00000000000..d6576079d3d --- /dev/null +++ b/tests/integration/record-arrays/adapter-populated-record-array-test.js @@ -0,0 +1,322 @@ +import {setupStore, createStore} from 'dummy/tests/helpers/store'; +import Ember from 'ember'; + +import {module, test} from 'qunit'; + +import DS from 'ember-data'; + +let store; +const { run, RSVP: { Promise } } = Ember; + +const Person = DS.Model.extend({ + name: DS.attr('string') +}); + +const adapter = DS.Adapter.extend({ + deleteRecord() { + return Promise.resolve(); + } +}); + +module('integration/record-arrays/adapter_populated_record_array - DS.AdapterPopulatedRecordArray', { + beforeEach() { + store = createStore({ + adapter: adapter, + person: Person + }); + } +}); + +test('when a record is deleted in an adapter populated record array, it should be removed', function(assert) { + let recordArray = store.recordArrayManager + .createAdapterPopulatedRecordArray(store.modelFor('person'), null); + + let payload = { + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale' + } + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz' + } + }, + { + type: 'person', + id: '3', + attributes: { + name: 'Scumbag Bryn' + } + } + ] + }; + + run(() => { + let records = store.push(payload); + recordArray.loadRecords(records, payload); + }); + + assert.equal(recordArray.get('length'), 3, "expected recordArray to contain exactly 3 records"); + + run(() => recordArray.get('firstObject').destroyRecord()); + + assert.equal(recordArray.get('length'), 2, "expected recordArray to contain exactly 2 records"); +}); + +test('stores the metadata off the payload', function(assert) { + let recordArray = store.recordArrayManager + .createAdapterPopulatedRecordArray(store.modelFor('person'), null); + + let payload = { + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale' + } + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz' + } + }, + { + type: 'person', + id: '3', + attributes: { + name: 'Scumbag Bryn' + } + } + ], + meta: { + foo: 'bar' + } + }; + + run(() => { + let records = store.push(payload); + recordArray.loadRecords(records, payload); + }); + + assert.equal(recordArray.get('meta.foo'), 'bar', 'expected meta.foo to be bar from payload'); +}); + +test('stores the links off the payload', function(assert) { + let recordArray = store.recordArrayManager + .createAdapterPopulatedRecordArray(store.modelFor('person'), null); + + let payload = { + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale' + } + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz' + } + }, + { + type: 'person', + id: '3', + attributes: { + name: 'Scumbag Bryn' + } + } + ], + links: { + first: '/foo?page=1' + } + }; + + run(() => { + let records = store.push(payload); + recordArray.loadRecords(records, payload); + }); + + assert.equal(recordArray.get('links.first'), '/foo?page=1', 'expected links.first to be "/foo?page=1" from payload'); +}); + +test('recordArray.replace() throws error', function(assert) { + let recordArray = store.recordArrayManager + .createAdapterPopulatedRecordArray(Person, null); + + assert.throws(() => { + recordArray.replace(); + }, Error('The result of a server query (on (subclass of DS.Model)) is immutable.'), 'throws error'); +}); + +test('when an adapter populated record gets updated the array contents are also updated', function(assert) { + assert.expect(8); + + let filteredPromise, filteredArr, findPromise, findArray; + let env = setupStore({ person: Person }); + let store = env.store; + let array = [{ id: '1', name: 'Scumbag Dale' }]; + + // resemble server side filtering + env.adapter.query = function(store, type, query, recordArray) { + return array.slice(query.slice); + }; + + // implement findAll to further test that query updates won't muddle + // with the non-query record arrays + env.adapter.findAll = function(store, type, sinceToken) { + return array.slice(0); + }; + + run(() => { + filteredPromise = store.query('person', { slice: 1 }); + findPromise = store.findAll('person'); + + // initialize adapter populated record array and assert initial state + filteredPromise.then((_filteredArr) => { + filteredArr = _filteredArr; + assert.equal(filteredArr.get('length'), 0, 'No records for this query'); + assert.equal(filteredArr.get('isUpdating'), false, 'Record array isUpdating state updated'); + }); + + // initialize a record collection array and assert initial state + findPromise.then((_findArr) => { + findArray = _findArr; + assert.equal(findArray.get('length'), 1, 'All records are included in collection array'); + }); + }); + + // a new element gets pushed in record array + run(() => { + array.push({ id: '2', name: 'Scumbag Katz' }); + filteredArr.update().then(() => { + assert.equal(filteredArr.get('length'), 1, 'The new record is returned and added in adapter populated array'); + assert.equal(filteredArr.get('isUpdating'), false, 'Record array isUpdating state updated'); + assert.equal(findArray.get('length'), 2); + }); + }); + + // element gets removed + run(() => { + array.pop(0); + filteredArr.update().then(() => { + assert.equal(filteredArr.get('length'), 0, 'Record removed from array'); + // record not removed from the model collection + assert.equal(findArray.get('length'), 2, 'Record still remains in collection array'); + }); + }); +}); + +test('batches adds/removals', function(assert) { + assert.expect(23); + + let env = setupStore({ person: Person }); + let store = env.store; + let query1 = {} + + let payload = [ + { id: '1', name: 'Scumbag Dale' }, + { id: '2', name: 'Scumbag Katz' } + ]; + // resemble server side filtering + env.adapter.query = function(store, type, query, recordArray) { + return payload; + }; + + let result = Ember.run(() => { + return store.query('person', query1); + }); + + let arrayDidChange = 0; + let contentDidChange = 0; + + let lastRecordArray; + return result.then(recordArray => { + lastRecordArray = recordArray; + assert.deepEqual(recordArray.map(x => x.get('name')), ['Scumbag Dale', 'Scumbag Katz']); + + assert.equal(arrayDidChange, 0, 'array should not yet have emitted a change event'); + assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); + + recordArray.addObserver('content', function() { + contentDidChange++; + }); + + recordArray.one('@array:change', function(array, startIdx, removeAmt, addAmt) { + arrayDidChange++; + + // first time invoked + assert.equal(array, recordArray, 'should be same record array as above'); + assert.equal(startIdx, 0, 'expected startIdx'); + assert.equal(removeAmt, 2, 'expcted removeAmt'); + assert.equal(addAmt, 2, 'expected addAmt'); + }); + + // set next payload; + payload = [ + { id: '3', name: 'Scumbag Penner' }, + { id: '4', name: 'Scumbag Hamilton' } + ]; + + return Ember.run(() => { + // re-query + let result = recordArray.update(); + assert.equal(arrayDidChange, 0); + assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); + return result; + }); + }).then(recordArray => { + assert.equal(arrayDidChange, 1, 'record array should have omitted ONE change event'); + assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); + assert.equal(recordArray, lastRecordArray); + + lastRecordArray = recordArray; + + assert.deepEqual(recordArray.map(x => x.get('name')), ['Scumbag Penner', 'Scumbag Hamilton']); + + // set next payload; + payload = [ + { id: '3', name: 'Scumbag Penner' } + ]; + + arrayDidChange = 0; // reset change event counter + contentDidChange = 0; // reset change event counter + + recordArray.one('@array:change', function(array, startIdx, removeAmt, addAmt) { + arrayDidChange++; + + // first time invoked + assert.equal(array, recordArray, 'should be same recordArray as above'); + assert.equal(startIdx, 0, 'expected startIdx'); + assert.equal(removeAmt, 2, 'expcted removeAmt'); + assert.equal(addAmt, 1, 'expected addAmt'); + }); + + return Ember.run(() => { + // re-query + let result = recordArray.update(); + assert.equal(arrayDidChange, 0, 'record array should not yet have omitted a change event'); + assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); + return result; + }); + }).then(recordArray => { + assert.equal(arrayDidChange, 1, 'record array should have emitted one change event'); + assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); + assert.equal(recordArray, lastRecordArray); + + lastRecordArray = recordArray; + + assert.deepEqual(recordArray.map(x => x.get('name')), ['Scumbag Penner']); + }); +}); diff --git a/tests/unit/adapter-populated-record-array-test.js b/tests/unit/adapter-populated-record-array-test.js deleted file mode 100644 index d4c47544815..00000000000 --- a/tests/unit/adapter-populated-record-array-test.js +++ /dev/null @@ -1,206 +0,0 @@ -import {setupStore, createStore} from 'dummy/tests/helpers/store'; -import Ember from 'ember'; - -import {module, test} from 'qunit'; - -import DS from 'ember-data'; - -var Person, store; -var run = Ember.run; - -var adapter = DS.Adapter.extend({ - deleteRecord() { - return Ember.RSVP.Promise.resolve(); - } -}); - -module("unit/adapter_populated_record_array - DS.AdapterPopulatedRecordArray", { - beforeEach() { - Person = DS.Model.extend({ - name: DS.attr('string') - }); - - store = createStore({ - adapter: adapter, - person: Person - }); - } -}); - -test("when a record is deleted in an adapter populated record array, it should be removed", function(assert) { - var recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray(store.modelFor('person'), null); - var payload = { - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Scumbag Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Scumbag Katz' - } - }, { - type: 'person', - id: '3', - attributes: { - name: 'Scumbag Bryn' - } - }] - }; - - run(function() { - var records = store._push(payload); - recordArray.loadRecords(records, payload); - }); - - assert.equal(recordArray.get('length'), 3, "expected recordArray to contain exactly 3 records"); - - run(function() { - recordArray.get('firstObject').destroyRecord(); - }); - - assert.equal(recordArray.get('length'), 2, "expected recordArray to contain exactly 2 records"); -}); - -test("stores the metadata off the payload", function(assert) { - var recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray(store.modelFor('person'), null); - var payload = { - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Scumbag Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Scumbag Katz' - } - }, { - type: 'person', - id: '3', - attributes: { - name: 'Scumbag Bryn' - } - }], - meta: { - foo: 'bar' - } - }; - - run(function() { - var records = store._push(payload); - recordArray.loadRecords(records, payload); - }); - - assert.equal(recordArray.get('meta.foo'), 'bar', 'expected meta.foo to be bar from payload'); -}); - -test('stores the links off the payload', function(assert) { - var recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray(store.modelFor('person'), null); - var payload = { - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Scumbag Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Scumbag Katz' - } - }, { - type: 'person', - id: '3', - attributes: { - name: 'Scumbag Bryn' - } - }], - links: { - first: '/foo?page=1' - } - }; - - run(function() { - var internalModels = store._push(payload); - recordArray.loadRecords(internalModels, payload); - }); - - assert.equal(recordArray.get('links.first'), '/foo?page=1', 'expected links.first to be "/foo?page=1" from payload'); -}); - -test('recordArray.replace() throws error', function(assert) { - var recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray(Person, null); - - assert.throws(function() { - recordArray.replace(); - }, Error("The result of a server query (on (subclass of DS.Model)) is immutable."), 'throws error'); -}); - -test("when an adapter populated record gets updated the array contents are also updated", function(assert) { - assert.expect(8); - var filteredPromise, filteredArr, findPromise, findArray; - var env = setupStore({ person: Person }); - var store = env.store; - var array = [{ id: '1', name: "Scumbag Dale" }]; - - // resemble server side filtering - env.adapter.query = function(store, type, query, recordArray) { - return Ember.RSVP.resolve(array.slice(query.slice)); - }; - - // implement findAll to further test that query updates won't muddle - // with the non-query record arrays - env.adapter.findAll = function(store, type, sinceToken) { - return Ember.RSVP.resolve(array.slice(0)); - }; - - run(function() { - filteredPromise = store.query('person', { slice: 1 }); - findPromise = store.findAll('person'); - - // initialize adapter populated record array and assert initial state - filteredPromise.then(function(_filteredArr) { - filteredArr = _filteredArr; - assert.equal(filteredArr.get('length'), 0, "No records for this query"); - assert.equal(filteredArr.get('isUpdating'), false, "Record array isUpdating state updated"); - }); - - // initialize a record collection array and assert initial state - findPromise.then(function(_findArr) { - findArray = _findArr; - assert.equal(findArray.get('length'), 1, "All records are included in collection array"); - }); - }); - - // a new element gets pushed in record array - run(function() { - array.push({ id: '2', name: "Scumbag Katz" }); - filteredArr.update().then(function() { - assert.equal(filteredArr.get('length'), 1, "The new record is returned and added in adapter populated array"); - assert.equal(filteredArr.get('isUpdating'), false, "Record array isUpdating state updated"); - assert.equal(findArray.get('length'), 2); - }); - }); - - // element gets removed - run(function() { - array.pop(0); - filteredArr.update().then(function() { - assert.equal(filteredArr.get('length'), 0, "Record removed from array"); - // record not removed from the model collection - assert.equal(findArray.get('length'), 2, "Record still remains in collection array"); - }); - }); - -}); From b5785fe714f07dc76df5a90877faac6447a5d649 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 21 Oct 2016 17:52:20 +0300 Subject: [PATCH 1671/2527] tidy up proxy related change events for AdapterPopulatedRecordArray during loadRecords Replace the values contained within content, rather then replacing content. Without this we: * signal `content` changed (no point) * signal strange array mutations on the ArrayProxy (from empty content, instead of previous content); Backfill missing tests --- .../adapter-populated-record-array.js | 15 +- .../adapter-populated-record-array-test.js | 103 ------------- .../adapter-populated-record-array-test.js | 142 ++++++++++++++++-- 3 files changed, 143 insertions(+), 117 deletions(-) diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index 5c73727d1a1..cd18d9cc1aa 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -47,6 +47,9 @@ const { get } = Ember; */ export default RecordArray.extend({ init() { + // yes we are touching `this` before super, but ArrayProxy has a bug that requires this. + this.set('content', this.get('content') || Ember.A()); + this._super(...arguments); this.query = this.query || null; this.links = null; @@ -73,15 +76,19 @@ export default RecordArray.extend({ */ loadRecords(internalModels, payload) { let token = heimdall.start('AdapterPopulatedRecordArray.loadRecords'); + + // TODO: initial load should not cause change events at all, only + // subsequent. This requires changing the public api of adapter.query, but + // hopefully we can do that soon. + this.get('content').setObjects(internalModels); + this.setProperties({ - content: Ember.A(internalModels), isLoaded: true, isUpdating: false, - meta: cloneNull(payload.meta) + meta: cloneNull(payload.meta), + links: cloneNull(payload.links) }); - this.set('links', cloneNull(payload.links)); - internalModels.forEach(record => { this.manager.recordArraysForRecord(record).add(this); }); diff --git a/tests/integration/record-arrays/adapter-populated-record-array-test.js b/tests/integration/record-arrays/adapter-populated-record-array-test.js index d6576079d3d..7fc4ec5c406 100644 --- a/tests/integration/record-arrays/adapter-populated-record-array-test.js +++ b/tests/integration/record-arrays/adapter-populated-record-array-test.js @@ -217,106 +217,3 @@ test('when an adapter populated record gets updated the array contents are also }); }); }); - -test('batches adds/removals', function(assert) { - assert.expect(23); - - let env = setupStore({ person: Person }); - let store = env.store; - let query1 = {} - - let payload = [ - { id: '1', name: 'Scumbag Dale' }, - { id: '2', name: 'Scumbag Katz' } - ]; - // resemble server side filtering - env.adapter.query = function(store, type, query, recordArray) { - return payload; - }; - - let result = Ember.run(() => { - return store.query('person', query1); - }); - - let arrayDidChange = 0; - let contentDidChange = 0; - - let lastRecordArray; - return result.then(recordArray => { - lastRecordArray = recordArray; - assert.deepEqual(recordArray.map(x => x.get('name')), ['Scumbag Dale', 'Scumbag Katz']); - - assert.equal(arrayDidChange, 0, 'array should not yet have emitted a change event'); - assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); - - recordArray.addObserver('content', function() { - contentDidChange++; - }); - - recordArray.one('@array:change', function(array, startIdx, removeAmt, addAmt) { - arrayDidChange++; - - // first time invoked - assert.equal(array, recordArray, 'should be same record array as above'); - assert.equal(startIdx, 0, 'expected startIdx'); - assert.equal(removeAmt, 2, 'expcted removeAmt'); - assert.equal(addAmt, 2, 'expected addAmt'); - }); - - // set next payload; - payload = [ - { id: '3', name: 'Scumbag Penner' }, - { id: '4', name: 'Scumbag Hamilton' } - ]; - - return Ember.run(() => { - // re-query - let result = recordArray.update(); - assert.equal(arrayDidChange, 0); - assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); - return result; - }); - }).then(recordArray => { - assert.equal(arrayDidChange, 1, 'record array should have omitted ONE change event'); - assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); - assert.equal(recordArray, lastRecordArray); - - lastRecordArray = recordArray; - - assert.deepEqual(recordArray.map(x => x.get('name')), ['Scumbag Penner', 'Scumbag Hamilton']); - - // set next payload; - payload = [ - { id: '3', name: 'Scumbag Penner' } - ]; - - arrayDidChange = 0; // reset change event counter - contentDidChange = 0; // reset change event counter - - recordArray.one('@array:change', function(array, startIdx, removeAmt, addAmt) { - arrayDidChange++; - - // first time invoked - assert.equal(array, recordArray, 'should be same recordArray as above'); - assert.equal(startIdx, 0, 'expected startIdx'); - assert.equal(removeAmt, 2, 'expcted removeAmt'); - assert.equal(addAmt, 1, 'expected addAmt'); - }); - - return Ember.run(() => { - // re-query - let result = recordArray.update(); - assert.equal(arrayDidChange, 0, 'record array should not yet have omitted a change event'); - assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); - return result; - }); - }).then(recordArray => { - assert.equal(arrayDidChange, 1, 'record array should have emitted one change event'); - assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); - assert.equal(recordArray, lastRecordArray); - - lastRecordArray = recordArray; - - assert.deepEqual(recordArray.map(x => x.get('name')), ['Scumbag Penner']); - }); -}); diff --git a/tests/unit/record-arrays/adapter-populated-record-array-test.js b/tests/unit/record-arrays/adapter-populated-record-array-test.js index c8f2c785ab2..d5d742377c7 100644 --- a/tests/unit/record-arrays/adapter-populated-record-array-test.js +++ b/tests/unit/record-arrays/adapter-populated-record-array-test.js @@ -8,12 +8,26 @@ const { AdapterPopulatedRecordArray } = DS; module('unit/record-arrays/adapter-populated-record-array - DS.AdapterPopulatedRecordArray'); +function recordFor(record) { + let _internalModel = { + getRecord() { + record._internalModel = _internalModel + return record; + } + } + + return { + id: record.id, + _internalModel + }; +} + test('default initial state', function(assert) { let recordArray = AdapterPopulatedRecordArray.create({ type: 'recordType' }); assert.equal(recordArray.get('isLoaded'), false, 'expected isLoaded to be false'); assert.equal(recordArray.get('type'), 'recordType'); - assert.equal(recordArray.get('content'), null); + assert.deepEqual(recordArray.get('content'), []); assert.equal(recordArray.get('query'), null); assert.equal(recordArray.get('store'), null); assert.equal(recordArray.get('links'), null); @@ -106,15 +120,8 @@ test('#loadRecords', function(assert) { manager }); - let model1 = { - id: 2, - _internalModel: { getRecord() { return model1; }} - }; - - let model2 = { - id: 2, - _internalModel: { getRecord() { return model2; }} - }; + let model1 = recordFor({ id: 1 }); + let model2 = recordFor({ id: 2 }); assert.equal(didAddRecord, 0, 'no records should have been added yet'); @@ -145,3 +152,118 @@ test('#loadRecords', function(assert) { }); assert.equal(didLoad, 1, 'didLoad event should have fired once'); }); + +test('change events when receiving a new query payload', function(assert) { + assert.expect(37); + + let arrayDidChange = 0; + let contentDidChange = 0; + let didAddRecord = 0; + + const manager = { + recordArraysForRecord(record) { + return { + add(array) { + didAddRecord++; + assert.equal(array, recordArray); + } + } + } + }; + + let recordArray = AdapterPopulatedRecordArray.create({ + query: 'some-query', + manager + }); + + run(() => { + recordArray.loadRecords([ + recordFor({ id: '1', name: 'Scumbag Dale' }), + recordFor({ id: '2', name: 'Scumbag Katz' }) + ], {}); + }); + + assert.equal(didAddRecord, 2, 'expected 2 didAddRecords'); + assert.deepEqual(recordArray.map(x => x.name), ['Scumbag Dale', 'Scumbag Katz']); + + assert.equal(arrayDidChange, 0, 'array should not yet have emitted a change event'); + assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); + + recordArray.addObserver('content', function() { + contentDidChange++; + }); + + recordArray.one('@array:change', function(array, startIdx, removeAmt, addAmt) { + arrayDidChange++; + + // first time invoked + assert.equal(array, recordArray, 'should be same record array as above'); + assert.equal(startIdx, 0, 'expected startIdx'); + assert.equal(removeAmt, 2, 'expcted removeAmt'); + assert.equal(addAmt, 2, 'expected addAmt'); + }); + + assert.equal(recordArray.get('isLoaded'), true, 'should be considered loaded'); + assert.equal(recordArray.get('isUpdating'), false, 'should not yet be updating'); + + assert.equal(arrayDidChange, 0); + assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); + + arrayDidChange = 0; + contentDidChange = 0; + didAddRecord = 0; + + run(() => { + // re-query + recordArray.loadRecords([ + recordFor({ id: '3', name: 'Scumbag Penner' }), + recordFor({ id: '4', name: 'Scumbag Hamilton' }) + ], {}); + }); + + assert.equal(didAddRecord, 2, 'expected 2 didAddRecords'); + assert.equal(recordArray.get('isLoaded'), true, 'should be considered loaded'); + assert.equal(recordArray.get('isUpdating'), false, 'should no longer be updating'); + + assert.equal(arrayDidChange, 1, 'record array should have omitted ONE change event'); + assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); + + assert.deepEqual(recordArray.map(x => x.name), ['Scumbag Penner', 'Scumbag Hamilton']); + + arrayDidChange = 0; // reset change event counter + contentDidChange = 0; // reset change event counter + didAddRecord = 0; + + recordArray.one('@array:change', function(array, startIdx, removeAmt, addAmt) { + arrayDidChange++; + + // first time invoked + assert.equal(array, recordArray, 'should be same recordArray as above'); + assert.equal(startIdx, 0, 'expected startIdx'); + assert.equal(removeAmt, 2, 'expcted removeAmt'); + assert.equal(addAmt, 1, 'expected addAmt'); + }); + + // re-query + assert.equal(recordArray.get('isLoaded'), true, 'should be considered loaded'); + assert.equal(recordArray.get('isUpdating'), false, 'should not yet be updating'); + + assert.equal(arrayDidChange, 0, 'record array should not yet have omitted a change event'); + assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); + + run(() => { + recordArray.loadRecords([ + recordFor({ id: '3', name: 'Scumbag Penner' }) + ], {}); + }); + + assert.equal(didAddRecord, 1, 'expected 1 didAddRecord'); + + assert.equal(recordArray.get('isLoaded'), true, 'should be considered loaded'); + assert.equal(recordArray.get('isUpdating'), false, 'should not longer be updating'); + + assert.equal(arrayDidChange, 1, 'record array should have emitted one change event'); + assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); + + assert.deepEqual(recordArray.map(x => x.name), ['Scumbag Penner']); +}); From e5f106e58a3498b8d6ea92ed171c0bb109d7abb7 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 21 Oct 2016 22:51:31 +0300 Subject: [PATCH 1672/2527] tidy-up AdapterPopulatedRecordArrays: * make the very private method more private \w underscore * rename loadRecords to _setInternalModels --- .../adapter-populated-record-array.js | 12 ++-- addon/-private/system/store/finders.js | 18 +++--- .../adapter-populated-record-array-test.js | 44 ++++++++++++--- .../adapter-populated-record-array-test.js | 55 ++++++++++--------- 4 files changed, 80 insertions(+), 49 deletions(-) diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index cd18d9cc1aa..6fa9f24044a 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -69,15 +69,15 @@ export default RecordArray.extend({ }, /** - @method loadRecords + @method _setInternalModels @param {Array} internalModels @param {Object} payload normalized payload @private */ - loadRecords(internalModels, payload) { - let token = heimdall.start('AdapterPopulatedRecordArray.loadRecords'); + _setInternalModels(internalModels, payload) { + let token = heimdall.start('AdapterPopulatedRecordArray._setInternalModels'); - // TODO: initial load should not cause change events at all, only + // TODO: initial load should not cause change events at all, only // subsequent. This requires changing the public api of adapter.query, but // hopefully we can do that soon. this.get('content').setObjects(internalModels); @@ -89,9 +89,7 @@ export default RecordArray.extend({ links: cloneNull(payload.links) }); - internalModels.forEach(record => { - this.manager.recordArraysForRecord(record).add(this); - }); + internalModels.forEach(record => this.manager.recordArraysForRecord(record).add(this)); // TODO: should triggering didLoad event be the last action of the runLoop? Ember.run.once(this, 'trigger', 'didLoad'); diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index f863de7eb54..ecca90fd1cf 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -153,27 +153,27 @@ export function _findAll(adapter, store, typeClass, sinceToken, options) { } export function _query(adapter, store, typeClass, query, recordArray) { - var modelName = typeClass.modelName; - var promise = adapter.query(store, typeClass, query, recordArray); + let modelName = typeClass.modelName; + let promise = adapter.query(store, typeClass, query, recordArray); - var serializer = serializerForAdapter(store, adapter, modelName); - var label = "DS: Handle Adapter#query of " + typeClass; + let serializer = serializerForAdapter(store, adapter, modelName); + let label = 'DS: Handle Adapter#query of ' + typeClass; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); - return promise.then(function(adapterPayload) { - var internalModels, payload; - store._adapterRun(function() { + return promise.then(adapterPayload => { + let internalModels, payload; + store._adapterRun(() => { payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'query'); internalModels = store._push(payload); }); assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Array.isArray(internalModels)); - recordArray.loadRecords(internalModels, payload); + recordArray._setInternalModels(internalModels, payload); return recordArray; - }, null, "DS: Extract payload of query " + typeClass); + }, null, 'DS: Extract payload of query ' + typeClass); } export function _queryRecord(adapter, store, typeClass, query) { diff --git a/tests/integration/record-arrays/adapter-populated-record-array-test.js b/tests/integration/record-arrays/adapter-populated-record-array-test.js index 7fc4ec5c406..a06e187ed9e 100644 --- a/tests/integration/record-arrays/adapter-populated-record-array-test.js +++ b/tests/integration/record-arrays/adapter-populated-record-array-test.js @@ -9,9 +9,13 @@ let store; const { run, RSVP: { Promise } } = Ember; const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), + toString() { + return ``; + } }); + const adapter = DS.Adapter.extend({ deleteRecord() { return Promise.resolve(); @@ -58,8 +62,7 @@ test('when a record is deleted in an adapter populated record array, it should b }; run(() => { - let records = store.push(payload); - recordArray.loadRecords(records, payload); + recordArray._setInternalModels(store._push(payload), payload); }); assert.equal(recordArray.get('length'), 3, "expected recordArray to contain exactly 3 records"); @@ -103,8 +106,7 @@ test('stores the metadata off the payload', function(assert) { }; run(() => { - let records = store.push(payload); - recordArray.loadRecords(records, payload); + recordArray._setInternalModels(store._push(payload), payload); }); assert.equal(recordArray.get('meta.foo'), 'bar', 'expected meta.foo to be bar from payload'); @@ -144,8 +146,7 @@ test('stores the links off the payload', function(assert) { }; run(() => { - let records = store.push(payload); - recordArray.loadRecords(records, payload); + recordArray._setInternalModels(store._push(payload), payload); }); assert.equal(recordArray.get('links.first'), '/foo?page=1', 'expected links.first to be "/foo?page=1" from payload'); @@ -160,6 +161,35 @@ test('recordArray.replace() throws error', function(assert) { }, Error('The result of a server query (on (subclass of DS.Model)) is immutable.'), 'throws error'); }); +test('loadRecord re-syncs internalModels recordArrays', function(assert) { + let env = setupStore({ person: Person }); + let store = env.store; + + let payload = [ + { id: '1', name: 'Scumbag Dale' }, + { id: '2', name: 'Scumbag Katz' } + ]; + + env.adapter.query = function(store, type, query, recordArray) { + return payload; + }; + + return store.query('person', { }).then(recordArray => { + return recordArray.update().then(recordArray => { + assert.deepEqual(recordArray.getEach('name'), ['Scumbag Dale', 'Scumbag Katz'], 'expected query to contain specific records'); + + payload = [ + { id: '1', name: 'Scumbag Dale' }, + { id: '3', name: 'Scumbag Penner' } + ]; + + return recordArray.update(); + }).then(recordArray => { + assert.deepEqual(recordArray.getEach('name'), ['Scumbag Dale', 'Scumbag Penner']); + }); + }); +}); + test('when an adapter populated record gets updated the array contents are also updated', function(assert) { assert.expect(8); diff --git a/tests/unit/record-arrays/adapter-populated-record-array-test.js b/tests/unit/record-arrays/adapter-populated-record-array-test.js index d5d742377c7..1c020e44b13 100644 --- a/tests/unit/record-arrays/adapter-populated-record-array-test.js +++ b/tests/unit/record-arrays/adapter-populated-record-array-test.js @@ -8,18 +8,18 @@ const { AdapterPopulatedRecordArray } = DS; module('unit/record-arrays/adapter-populated-record-array - DS.AdapterPopulatedRecordArray'); -function recordFor(record) { +function internalModelFor(record) { let _internalModel = { + get id() { + return record.id; + }, getRecord() { - record._internalModel = _internalModel return record; } - } - - return { - id: record.id, - _internalModel }; + + record._internalModel = _internalModel + return _internalModel; } test('default initial state', function(assert) { @@ -102,7 +102,7 @@ test('#update uses _update enabling query specific behavior', function(assert) { }); // TODO: is this method required, i suspect store._query should be refactor so this is not needed -test('#loadRecords', function(assert) { +test('#_setInternalModels', function(assert) { let didAddRecord = 0; const manager = { recordArraysForRecord(record) { @@ -120,8 +120,8 @@ test('#loadRecords', function(assert) { manager }); - let model1 = recordFor({ id: 1 }); - let model2 = recordFor({ id: 2 }); + let model1 = internalModelFor({ id: 1 }); + let model2 = internalModelFor({ id: 2 }); assert.equal(didAddRecord, 0, 'no records should have been added yet'); @@ -130,21 +130,21 @@ test('#loadRecords', function(assert) { didLoad++; }); - let links = { foo:1 }; - let meta = { bar:2 }; + let links = { foo: 1 }; + let meta = { bar: 2 }; run(() => { - assert.equal(recordArray.loadRecords([model1._internalModel, model2._internalModel], { + assert.equal(recordArray._setInternalModels([model1, model2], { links, meta - }), undefined, 'loadRecords should have no return value'); + }), undefined, '_setInternalModels should have no return value'); - assert.equal(didAddRecord, 2, 'two records should have been adde'); + assert.equal(didAddRecord, 2, 'two records should have been added'); assert.deepEqual(recordArray.toArray(), [ model1, model2 - ], 'should now contain the loaded records'); + ].map(x => x.getRecord()), 'should now contain the loaded records'); assert.equal(didLoad, 0, 'didLoad event should not have fired'); assert.equal(recordArray.get('links').foo, 1); @@ -166,8 +166,11 @@ test('change events when receiving a new query payload', function(assert) { add(array) { didAddRecord++; assert.equal(array, recordArray); + }, + delete(array) { + assert.equal(array, recordArray); } - } + }; } }; @@ -177,9 +180,9 @@ test('change events when receiving a new query payload', function(assert) { }); run(() => { - recordArray.loadRecords([ - recordFor({ id: '1', name: 'Scumbag Dale' }), - recordFor({ id: '2', name: 'Scumbag Katz' }) + recordArray._setInternalModels([ + internalModelFor({ id: '1', name: 'Scumbag Dale' }), + internalModelFor({ id: '2', name: 'Scumbag Katz' }) ], {}); }); @@ -215,9 +218,9 @@ test('change events when receiving a new query payload', function(assert) { run(() => { // re-query - recordArray.loadRecords([ - recordFor({ id: '3', name: 'Scumbag Penner' }), - recordFor({ id: '4', name: 'Scumbag Hamilton' }) + recordArray._setInternalModels([ + internalModelFor({ id: '3', name: 'Scumbag Penner' }), + internalModelFor({ id: '4', name: 'Scumbag Hamilton' }) ], {}); }); @@ -252,12 +255,12 @@ test('change events when receiving a new query payload', function(assert) { assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); run(() => { - recordArray.loadRecords([ - recordFor({ id: '3', name: 'Scumbag Penner' }) + recordArray._setInternalModels([ + internalModelFor({ id: '3', name: 'Scumbag Penner' }) ], {}); }); - assert.equal(didAddRecord, 1, 'expected 1 didAddRecord'); + assert.equal(didAddRecord, 1, 'expected 0 didAddRecord'); assert.equal(recordArray.get('isLoaded'), true, 'should be considered loaded'); assert.equal(recordArray.get('isUpdating'), false, 'should not longer be updating'); From b699683fc4238fd2d0e0c46249ddea01c3b6e3a7 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 21 Oct 2016 23:49:34 +0300 Subject: [PATCH 1673/2527] fixup based on PR review --- .../record-arrays/adapter-populated-record-array-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/record-arrays/adapter-populated-record-array-test.js b/tests/integration/record-arrays/adapter-populated-record-array-test.js index a06e187ed9e..05634db3875 100644 --- a/tests/integration/record-arrays/adapter-populated-record-array-test.js +++ b/tests/integration/record-arrays/adapter-populated-record-array-test.js @@ -74,7 +74,7 @@ test('when a record is deleted in an adapter populated record array, it should b test('stores the metadata off the payload', function(assert) { let recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray(store.modelFor('person'), null); + .createAdapterPopulatedRecordArray(Person, null); let payload = { data: [ From 44bdeef48a66f7d4c2602a69a41416df1084992d Mon Sep 17 00:00:00 2001 From: Sang Mercado Date: Sat, 22 Oct 2016 03:16:52 -0700 Subject: [PATCH 1674/2527] Renaming `multiple_stores_test` to `multiple-stores-test` Fixes #4618 --- .../{multiple_stores_test.js => multiple-stores-test.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/integration/{multiple_stores_test.js => multiple-stores-test.js} (100%) diff --git a/tests/integration/multiple_stores_test.js b/tests/integration/multiple-stores-test.js similarity index 100% rename from tests/integration/multiple_stores_test.js rename to tests/integration/multiple-stores-test.js From bf5dcfa7b65da4a24e4f330bda14afe19b23e3b3 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Sat, 22 Oct 2016 16:23:27 +0300 Subject: [PATCH 1675/2527] tidy-up integration/filter-test * use promises directly, rather then indirect async test helpers. QUnit now just supports them --- tests/integration/filter-test.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tests/integration/filter-test.js b/tests/integration/filter-test.js index 7d650812499..de0aa5ba646 100644 --- a/tests/integration/filter-test.js +++ b/tests/integration/filter-test.js @@ -304,11 +304,11 @@ test('a Record Array can update its filter and notify array observers', function ]; }); - store.filter('person', hash => { + return store.filter('person', hash => { if (hash.get('name').match(/Scumbag [KD]/)) { return true; } - }).then(assert.wait(recordArray => { + }).then(recordArray => { let didChangeIdx; let didChangeRemoved = 0; @@ -381,7 +381,7 @@ test('a Record Array can update its filter and notify array observers', function assert.equal(recordArray.objectAt(didChangeIdx).get('name'), 'Scumbag Demon'); assert.equal(recordArray.objectAt(didChangeIdx-1).get('name'), 'Scumbag Dale'); }); - })); + }); }); test('it is possible to filter by computed properties', function(assert) { @@ -440,7 +440,10 @@ test('a filter created after a record is already loaded works', function(assert) }); assert.equal(filter.get('length'), 1, 'the filter now has a record in it'); - assert.asyncEqual(filter.objectAt(0), store.findRecord('person', 1)); + + return store.findRecord('person', 1).then(person => { + assert.equal(filter.objectAt(0), person); + }); }); test('filter with query persists query on the resulting filteredRecordArray', function(assert) { @@ -494,7 +497,7 @@ test('it is possible to filter by state flags', function(assert) { return person.then(person => { assert.equal(filter.get('length'), 1, 'the now-loaded record is in the filter'); - assert.asyncEqual(filter.objectAt(0), store.findRecord('person', 1)); + assert.equal(filter.objectAt(0), person); }); }); @@ -586,9 +589,9 @@ test('it is possible to filter created records by isReloading', function(assert) name: 'Tom Dale' }); - return person.reload().then(assert.wait(person => { + return person.reload().then(person => { assert.equal(filter.get('length'), 1, 'the filter correctly returned a reloaded object'); - })); + }); }); // SERVER SIDE TESTS From 73a31854ff18874bdacd7e3013b1766fff131f94 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 20 Oct 2016 03:00:37 -0700 Subject: [PATCH 1676/2527] chore(modelClass): works toward consistent use of kind/modelClass/internalModel/record --- addon/-private/debug.js | 27 +- addon/-private/system/many-array.js | 1 + addon/-private/system/model/internal-model.js | 247 +++++++++--------- addon/-private/system/record-array-manager.js | 26 +- addon/-private/system/references/has-many.js | 14 +- addon/-private/system/references/record.js | 3 +- .../system/relationships/state/belongs-to.js | 4 +- addon/-private/system/snapshot.js | 2 +- addon/-private/system/store.js | 51 ++-- .../integration/references/belongs-to-test.js | 10 +- tests/integration/references/has-many-test.js | 8 +- .../relationships/belongs-to-test.js | 10 +- .../relationships/has-many-test.js | 6 +- .../polymorphic-mixins-belongs-to-test.js | 4 +- .../polymorphic-mixins-has-many-test.js | 4 +- tests/unit/model/internal-model-test.js | 24 -- tests/unit/utils-test.js | 4 +- 17 files changed, 211 insertions(+), 234 deletions(-) delete mode 100644 tests/unit/model/internal-model-test.js diff --git a/addon/-private/debug.js b/addon/-private/debug.js index d3a503b8d1e..8eb19b48d56 100644 --- a/addon/-private/debug.js +++ b/addon/-private/debug.js @@ -32,16 +32,16 @@ export function debugSeal() { return Ember.debugSeal(...arguments); } -function checkPolymorphic(typeClass, addedRecord) { - if (typeClass.__isMixin) { +function checkPolymorphic(modelClass, addedModelClass) { + if (modelClass.__isMixin) { //TODO Need to do this in order to support mixins, should convert to public api //once it exists in Ember - return typeClass.__mixin.detect(addedRecord.type.PrototypeMixin); + return modelClass.__mixin.detect(addedModelClass.PrototypeMixin); } if (Ember.MODEL_FACTORY_INJECTIONS) { - typeClass = typeClass.superclass; + modelClass = modelClass.superclass; } - return typeClass.detect(addedRecord.type); + return modelClass.detect(addedModelClass); } /* @@ -57,19 +57,18 @@ function checkPolymorphic(typeClass, addedRecord) { `record.relationshipFor(key)`. @method assertPolymorphicType - @param {InternalModel} record + @param {InternalModel} internalModel @param {RelationshipMeta} relationshipMeta retrieved via `record.relationshipFor(key)` @param {InternalModel} addedRecord record which should be added/set for the relationship */ -export function assertPolymorphicType(record, relationshipMeta, addedRecord) { - var addedType = addedRecord.type.modelName; - var recordType = record.type.modelName; - var key = relationshipMeta.key; - var typeClass = record.store.modelFor(relationshipMeta.type); +export function assertPolymorphicType(parentInternalModel, relationshipMeta, addedInternalModel) { + let addedModelName = addedInternalModel.modelName; + let parentModelName = parentInternalModel.modelName; + let key = relationshipMeta.key; + let relationshipClass = parentInternalModel.store.modelFor(relationshipMeta.type); + let assertionMessage = `You cannot add a record of modelClass '${addedModelName}' to the '${parentModelName}.${key}' relationship (only '${relationshipClass.modelName}' allowed)`; - var assertionMessage = `You cannot add a record of type '${addedType}' to the '${recordType}.${key}' relationship (only '${typeClass.modelName}' allowed)`; - - assert(assertionMessage, checkPolymorphic(typeClass, addedRecord)); + assert(assertionMessage, checkPolymorphic(relationshipClass, addedInternalModel.modelClass)); } diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index d3724a34f35..7810fa5b72f 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -71,6 +71,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { if (!this.currentState[index]) { return undefined; } + return this.currentState[index].getRecord(); }, diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index aa15574a875..97f06480143 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -44,8 +44,8 @@ const assign = Ember.assign || Ember.merge; */ const TransitionChainMap = new EmptyObject(); -var _extractPivotNameCache = new EmptyObject(); -var _splitOnDotCache = new EmptyObject(); +const _extractPivotNameCache = new EmptyObject(); +const _splitOnDotCache = new EmptyObject(); function splitOnDot(name) { return _splitOnDotCache[name] || ( @@ -104,16 +104,17 @@ const { @class InternalModel */ export default class InternalModel { - constructor(type, id, store, _, data) { + constructor(modelClass, id, store, data) { heimdall.increment(new_InternalModel); - this.type = type; + this.modelClass = modelClass; this.id = id; this.store = store; this._data = data || new EmptyObject(); - this.modelName = type.modelName; + this.modelName = modelClass.modelName; this.dataHasInitialized = false; this._loadingPromise = null; this._recordArrays = undefined; + this._record = null; this.currentState = RootState.empty; this.isReloading = false; this._isDestroyed = false; @@ -130,6 +131,10 @@ export default class InternalModel { this.__implicitRelationships = null; } + get type() { + return this.modelClass; + } + get recordReference() { if (this._recordReference === null) { this._recordReference = new RecordReference(this.store, this) @@ -251,35 +256,42 @@ export default class InternalModel { return this.currentState.dirtyType; } - materializeRecord() { - heimdall.increment(materializeRecord); - assert("Materialized " + this.modelName + " record with id:" + this.id + "more than once", this.record === null || this.record === undefined); - - // lookupFactory should really return an object that creates - // instances with the injections applied - var createOptions = { - store: this.store, - _internalModel: this, - id: this.id, - currentState: this.currentState, - isError: this.isError, - adapterError: this.error - }; - - if (setOwner) { - // ensure that `getOwner(this)` works inside a model instance - setOwner(createOptions, getOwner(this.store)); - } else { - createOptions.container = this.store.container; - } + get record() { + return this._record; + } + + getRecord() { + if (!this._record) { + heimdall.increment(materializeRecord); + + // lookupFactory should really return an object that creates + // instances with the injections applied + let createOptions = { + store: this.store, + _internalModel: this, + id: this.id, + currentState: this.currentState, + isError: this.isError, + adapterError: this.error + }; + + if (setOwner) { + // ensure that `getOwner(this)` works inside a model instance + setOwner(createOptions, getOwner(this.store)); + } else { + createOptions.container = this.store.container; + } - this.record = this.type._create(createOptions); + this._record = this.modelClass._create(createOptions); - this._triggerDeferredTriggers(); + this._triggerDeferredTriggers(); + } + + return this._record; } recordObjectWillDestroy() { - this.record = null; + this._record = null; } deleteRecord() { @@ -287,8 +299,8 @@ export default class InternalModel { } save(options) { - var promiseLabel = "DS: Model#save " + this; - var resolver = RSVP.defer(promiseLabel); + let promiseLabel = "DS: Model#save " + this; + let resolver = RSVP.defer(promiseLabel); this.store.scheduleSave(this, resolver, options); return resolver.promise; @@ -296,65 +308,59 @@ export default class InternalModel { startedReloading() { this.isReloading = true; - if (this.record) { + if (this.hasRecord) { set(this.record, 'isReloading', true); } } finishedReloading() { this.isReloading = false; - if (this.record) { + if (this.hasRecord) { set(this.record, 'isReloading', false); } } reload() { this.startedReloading(); - var record = this; - var promiseLabel = "DS: Model#reload of " + this; + let internalModel = this; + let promiseLabel = "DS: Model#reload of " + this; + return new Promise(function(resolve) { - record.send('reloadRecord', resolve); + internalModel.send('reloadRecord', resolve); }, promiseLabel).then(function() { - record.didCleanError(); - return record; + internalModel.didCleanError(); + return internalModel; }, function(error) { - record.didError(error); + internalModel.didError(error); throw error; }, "DS: Model#reload complete, update flags").finally(function () { - record.finishedReloading(); - record.updateRecordArrays(); + internalModel.finishedReloading(); + internalModel.updateRecordArrays(); }); } - getRecord() { - if (!this.record) { - this.materializeRecord(); - } - return this.record; - } - unloadRecord() { this.send('unloadRecord'); } eachRelationship(callback, binding) { - return this.type.eachRelationship(callback, binding); + return this.modelClass.eachRelationship(callback, binding); } eachAttribute(callback, binding) { - return this.type.eachAttribute(callback, binding); + return this.modelClass.eachAttribute(callback, binding); } inverseFor(key) { - return this.type.inverseFor(key); + return this.modelClass.inverseFor(key); } setupData(data) { heimdall.increment(setupData); - var changedKeys = this._changedKeys(data.attributes); + let changedKeys = this._changedKeys(data.attributes); assign(this._data, data.attributes); this.pushedData(); - if (this.record) { + if (this.hasRecord) { this.record._notifyProperties(changedKeys); } this.didInitializeData(); @@ -375,9 +381,13 @@ export default class InternalModel { return this._isDestroyed; } + get hasRecord() { + return !!this._record; + } + destroy() { this._isDestroyed = true; - if (this.record) { + if (this.hasRecord) { return this.record.destroy(); } } @@ -448,8 +458,8 @@ export default class InternalModel { */ updateChangedAttributes() { heimdall.increment(updateChangedAttributes); - var changedAttributes = this.changedAttributes(); - var changedAttributeNames = Object.keys(changedAttributes); + let changedAttributes = this.changedAttributes(); + let changedAttributeNames = Object.keys(changedAttributes); let attrs = this._attributes; for (let i = 0, length = changedAttributeNames.length; i < length; i++) { @@ -471,13 +481,12 @@ export default class InternalModel { */ changedAttributes() { heimdall.increment(changedAttributes); - var oldData = this._data; - var currentData = this._attributes; - var inFlightData = this._inFlightAttributes; - var newData = assign(copy(inFlightData), currentData); - var diffData = new EmptyObject(); - - var newDataKeys = Object.keys(newData); + let oldData = this._data; + let currentData = this._attributes; + let inFlightData = this._inFlightAttributes; + let newData = assign(copy(inFlightData), currentData); + let diffData = new EmptyObject(); + let newDataKeys = Object.keys(newData); for (let i = 0, length = newDataKeys.length; i < length; i++) { let key = newDataKeys[i]; @@ -512,7 +521,7 @@ export default class InternalModel { */ send(name, context) { heimdall.increment(send); - var currentState = this.currentState; + let currentState = this.currentState; if (!currentState[name]) { this._unhandledEvent(currentState, name, context); @@ -522,31 +531,31 @@ export default class InternalModel { } notifyHasManyAdded(key, record, idx) { - if (this.record) { + if (this.hasRecord) { this.record.notifyHasManyAdded(key, record, idx); } } notifyHasManyRemoved(key, record, idx) { - if (this.record) { + if (this.hasRecord) { this.record.notifyHasManyRemoved(key, record, idx); } } notifyBelongsToChanged(key, record) { - if (this.record) { + if (this.hasRecord) { this.record.notifyBelongsToChanged(key, record); } } notifyPropertyChange(key) { - if (this.record) { + if (this.hasRecord) { this.record.notifyPropertyChange(key); } } rollbackAttributes() { - var dirtyKeys = Object.keys(this._attributes); + let dirtyKeys = Object.keys(this._attributes); this._attributes = new EmptyObject(); @@ -586,8 +595,8 @@ export default class InternalModel { // POSSIBLE TODO: Remove this code and replace with // always having direct reference to state objects - var pivotName = extractPivotName(name); - var state = this.currentState; + let pivotName = extractPivotName(name); + let state = this.currentState; let transitionMapId = `${state.stateName}->${name}`; do { @@ -626,7 +635,7 @@ export default class InternalModel { } this.currentState = state; - if (this.record) { + if (this.hasRecord) { set(this.record, 'currentState', state); } @@ -638,7 +647,7 @@ export default class InternalModel { } _unhandledEvent(state, name, context) { - var errorMessage = "Attempted to handle event `" + name + "` "; + let errorMessage = "Attempted to handle event `" + name + "` "; errorMessage += "on " + String(this) + " while in state "; errorMessage += state.stateName + ". "; @@ -649,14 +658,7 @@ export default class InternalModel { throw new EmberError(errorMessage); } - triggerLater() { - var length = arguments.length; - var args = new Array(length); - - for (var i = 0; i < length; i++) { - args[i] = arguments[i]; - } - + triggerLater(...args) { if (this._deferredTriggers.push(args) !== 1) { return; } @@ -668,10 +670,10 @@ export default class InternalModel { //TODO: Before 1.0 we want to remove all the events that happen on the pre materialized record, //but for now, we queue up all the events triggered before the record was materialized, and flush //them once we have the record - if (!this.record) { + if (!this.hasRecord) { return; } - for (var i = 0, l= this._deferredTriggers.length; i { if (this._relationships.has(name)) { - var rel = this._relationships.get(name); + let rel = this._relationships.get(name); rel.clear(); rel.destroy(); } @@ -714,8 +716,8 @@ export default class InternalModel { _preloadData(preload) { //TODO(Igor) consider the polymorphic case Object.keys(preload).forEach((key) => { - var preloadValue = get(preload, key); - var relationshipMeta = this.type.metaForProperty(key); + let preloadValue = get(preload, key); + let relationshipMeta = this.modelClass.metaForProperty(key); if (relationshipMeta.isRelationship) { this._preloadRelationship(key, preloadValue); } else { @@ -725,22 +727,22 @@ export default class InternalModel { } _preloadRelationship(key, preloadValue) { - var relationshipMeta = this.type.metaForProperty(key); - var type = relationshipMeta.type; + let relationshipMeta = this.modelClass.metaForProperty(key); + let modelClass = relationshipMeta.type; if (relationshipMeta.kind === 'hasMany') { - this._preloadHasMany(key, preloadValue, type); + this._preloadHasMany(key, preloadValue, modelClass); } else { - this._preloadBelongsTo(key, preloadValue, type); + this._preloadBelongsTo(key, preloadValue, modelClass); } } - _preloadHasMany(key, preloadValue, type) { + _preloadHasMany(key, preloadValue, modelClass) { assert("You need to pass in an array to set a hasMany property on a record", Array.isArray(preloadValue)); let recordsToSet = new Array(preloadValue.length); for (let i = 0; i < preloadValue.length; i++) { let recordToPush = preloadValue[i]; - recordsToSet[i] = this._convertStringOrNumberIntoInternalModel(recordToPush, type); + recordsToSet[i] = this._convertStringOrNumberIntoInternalModel(recordToPush, modelClass); } //We use the pathway of setting the hasMany as if it came from the adapter @@ -748,17 +750,17 @@ export default class InternalModel { this._relationships.get(key).updateRecordsFromAdapter(recordsToSet); } - _preloadBelongsTo(key, preloadValue, type) { - var recordToSet = this._convertStringOrNumberIntoInternalModel(preloadValue, type); + _preloadBelongsTo(key, preloadValue, modelClass) { + let recordToSet = this._convertStringOrNumberIntoInternalModel(preloadValue, modelClass); //We use the pathway of setting the hasMany as if it came from the adapter //because the user told us that they know this relationships exists already this._relationships.get(key).setRecord(recordToSet); } - _convertStringOrNumberIntoInternalModel(value, type) { + _convertStringOrNumberIntoInternalModel(value, modelClass) { if (typeof value === 'string' || typeof value === 'number') { - return this.store._internalModelForId(type, value); + return this.store._internalModelForId(modelClass, value); } if (value._internalModel) { return value._internalModel; @@ -772,7 +774,7 @@ export default class InternalModel { */ updateRecordArrays() { this._updatingRecordArraysLater = false; - this.store.dataWasUpdated(this.type, this); + this.store.dataWasUpdated(this.modelClass, this); } setId(id) { @@ -787,7 +789,7 @@ export default class InternalModel { this.error = error; this.isError = true; - if (this.record) { + if (this.hasRecord) { this.record.setProperties({ isError: true, adapterError: error @@ -799,7 +801,7 @@ export default class InternalModel { this.error = null; this.isError = false; - if (this.record) { + if (this.hasRecord) { this.record.setProperties({ isError: false, adapterError: null @@ -820,7 +822,7 @@ export default class InternalModel { } this.didCleanError(); - var changedKeys = this._changedKeys(data); + let changedKeys = this._changedKeys(data); assign(this._data, this._inFlightAttributes); if (data) { @@ -849,23 +851,19 @@ export default class InternalModel { } addErrorMessageToAttribute(attribute, message) { - var record = this.getRecord(); - get(record, 'errors')._add(attribute, message); + get(this.getRecord(), 'errors')._add(attribute, message); } removeErrorMessageFromAttribute(attribute) { - var record = this.getRecord(); - get(record, 'errors')._remove(attribute); + get(this.getRecord(), 'errors')._remove(attribute); } clearErrorMessages() { - var record = this.getRecord(); - get(record, 'errors')._clear(); + get(this.getRecord(), 'errors')._clear(); } hasErrors() { - var record = this.getRecord(); - var errors = get(record, 'errors'); + let errors = get(this.getRecord(), 'errors'); return !isEmpty(errors); } @@ -877,10 +875,9 @@ export default class InternalModel { @private */ adapterDidInvalidate(errors) { - var attribute; + let attribute; for (attribute in errors) { - // TODO @runspired we probably dont need hasOwnProperty if (errors.hasOwnProperty(attribute)) { this.addErrorMessageToAttribute(attribute, errors[attribute]); } @@ -902,9 +899,9 @@ export default class InternalModel { } _saveWasRejected() { - var keys = Object.keys(this._inFlightAttributes); - var attrs = this._attributes; - for (var i=0; i < keys.length; i++) { + let keys = Object.keys(this._inFlightAttributes); + let attrs = this._attributes; + for (let i=0; i < keys.length; i++) { if (attrs[keys[i]] === undefined) { attrs[keys[i]] = this._inFlightAttributes[keys[i]]; } @@ -954,13 +951,13 @@ export default class InternalModel { @private */ _changedKeys(updates) { - var changedKeys = []; + let changedKeys = []; if (updates) { - var original, i, value, key; - var keys = Object.keys(updates); - var length = keys.length; - var attrs = this._attributes; + let original, i, value, key; + let keys = Object.keys(updates); + let length = keys.length; + let attrs = this._attributes; original = assign(new EmptyObject(), this._data); original = assign(original, this._inFlightAttributes); @@ -990,23 +987,23 @@ export default class InternalModel { return `<${this.modelName}:${this.id}>`; } - referenceFor(type, name) { - var reference = this.references[name]; + referenceFor(kind, name) { + let reference = this.references[name]; if (!reference) { - var relationship = this._relationships.get(name); + let relationship = this._relationships.get(name); runInDebug(() => { let modelName = this.modelName; - assert(`There is no ${type} relationship named '${name}' on a model of type '${modelName}'`, relationship); + assert(`There is no ${kind} relationship named '${name}' on a model of modelClass '${modelName}'`, relationship); let actualRelationshipKind = relationship.relationshipMeta.kind; - assert(`You tried to get the '${name}' relationship on a '${modelName}' via record.${type}('${name}'), but the relationship is of type '${actualRelationshipKind}'. Use record.${actualRelationshipKind}('${name}') instead.`, actualRelationshipKind === type); + assert(`You tried to get the '${name}' relationship on a '${modelName}' via record.${kind}('${name}'), but the relationship is of kind '${actualRelationshipKind}'. Use record.${actualRelationshipKind}('${name}') instead.`, actualRelationshipKind === kind); }); - if (type === "belongsTo") { + if (kind === "belongsTo") { reference = new BelongsToReference(this.store, this, relationship); - } else if (type === "hasMany") { + } else if (kind === "hasMany") { reference = new HasManyReference(this.store, this, relationship); } diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index c87795376cc..f51e30eb3f9 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -37,7 +37,7 @@ const { updateFilterRecordArray, updateRecordArrays } = heimdall.registerMonitor('recordArrayManager', - '_addRecordToRecordArray', + '_addInternalModelToRecordArray', '_recordWasChanged', '_recordWasDeleted', 'array_fatten', @@ -153,7 +153,7 @@ export default Ember.Object.extend({ if (this.liveRecordArrays.has(typeClass)) { let liveRecordArray = this.liveRecordArrays.get(typeClass); - this._addRecordToRecordArray(liveRecordArray, record); + this._addInternalModelToRecordArray(liveRecordArray, record); } }, @@ -163,26 +163,26 @@ export default Ember.Object.extend({ @method updateFilterRecordArray @param {DS.FilteredRecordArray} array @param {Function} filter - @param {DS.Model} typeClass - @param {InternalModel} record + @param {DS.Model} modelClass + @param {InternalModel} internalModel */ - updateFilterRecordArray(array, filter, typeClass, record) { + updateFilterRecordArray(array, filter, modelClass, internalModel) { heimdall.increment(updateFilterRecordArray); - let shouldBeInArray = filter(record.getRecord()); - let recordArrays = this.recordArraysForRecord(record); + let shouldBeInArray = filter(internalModel.getRecord()); + let recordArrays = this.recordArraysForRecord(internalModel); if (shouldBeInArray) { - this._addRecordToRecordArray(array, record); + this._addInternalModelToRecordArray(array, internalModel); } else { recordArrays.delete(array); - array._removeInternalModels([record]); + array._removeInternalModels([internalModel]); } }, - _addRecordToRecordArray(array, record) { + _addInternalModelToRecordArray(array, internalModel) { heimdall.increment(_addRecordToRecordArray); - let recordArrays = this.recordArraysForRecord(record); + let recordArrays = this.recordArraysForRecord(internalModel); if (!recordArrays.has(array)) { - array._pushInternalModels([record]); + array._pushInternalModels([internalModel]); recordArrays.add(array); } }, @@ -197,7 +197,7 @@ export default Ember.Object.extend({ record = records[i]; if (!record.isDeleted() && !record.isEmpty()) { - this._addRecordToRecordArray(array, record); + this._addInternalModelToRecordArray(array, record); } } }, diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 4235e93673e..de18a83ab2b 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -39,12 +39,11 @@ HasManyReference.prototype.link = function() { }; HasManyReference.prototype.ids = function() { - var members = this.hasManyRelationship.members; - var ids = members.toArray().map(function(internalModel) { + let members = this.hasManyRelationship.members.toArray(); + + return members.map(function(internalModel) { return internalModel.id; }); - - return ids; }; HasManyReference.prototype.meta = function() { @@ -115,12 +114,11 @@ HasManyReference.prototype._isLoaded = function() { return false; } - var members = this.hasManyRelationship.members.toArray(); - var isEveryLoaded = members.every(function(internalModel) { + let members = this.hasManyRelationship.members.toArray(); + + return members.every(function(internalModel) { return internalModel.isLoaded() === true; }); - - return isEveryLoaded; }; HasManyReference.prototype.value = function() { diff --git a/addon/-private/system/references/record.js b/addon/-private/system/references/record.js index c687709e58d..9e9284453e3 100644 --- a/addon/-private/system/references/record.js +++ b/addon/-private/system/references/record.js @@ -21,8 +21,7 @@ RecordReference.prototype.remoteType = function() { RecordReference.prototype.push = function(objectOrPromise) { return Ember.RSVP.resolve(objectOrPromise).then((data) => { - var record = this.store.push(data); - return record; + return this.store.push(data); }); }; diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index bcdffb60699..9ac3db807f9 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -143,7 +143,7 @@ BelongsToRelationship.prototype.getRecord = function() { return null; } var toReturn = this.inverseRecord.getRecord(); - assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); + assert("You looked up the '" + this.key + "' relationship on a '" + this.record.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); return toReturn; } }; @@ -156,7 +156,7 @@ BelongsToRelationship.prototype.reload = function() { } // reload record, if it is already loaded - if (this.inverseRecord && this.inverseRecord.record) { + if (this.inverseRecord && this.inverseRecord.hasRecord) { return this.inverseRecord.record.reload(); } diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index 4800ae80458..aea59e2ebf5 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -21,7 +21,7 @@ export default function Snapshot(internalModel, options = {}) { this._hasManyRelationships = new EmptyObject(); this._hasManyIds = new EmptyObject(); - var record = internalModel.getRecord(); + let record = internalModel.getRecord(); this.record = record; record.eachAttribute((keyName) => this._attributes[keyName] = get(record, keyName)); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index e30e25bc857..1a07c0b8101 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -58,8 +58,9 @@ const { //Get the materialized model from the internalModel/promise that returns //an internal model and return it in a promiseObject. Useful for returning //from find methods -function promiseRecord(internalModel, label) { - var toReturn = internalModel.then((model) => model.getRecord()); +function promiseRecord(internalModelPromise, label) { + let toReturn = internalModelPromise.then((internalModel) => internalModel.getRecord()); + return promiseObject(toReturn, label); } @@ -308,8 +309,8 @@ Store = Service.extend({ createRecord(modelName, inputProperties) { assert("You need to pass a model name to the store's createRecord method", isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); - var typeClass = this.modelFor(modelName); - var properties = copy(inputProperties) || new EmptyObject(); + let modelClass = this.modelFor(modelName); + let properties = copy(inputProperties) || new EmptyObject(); // If the passed properties do not include a primary key, // give the adapter an opportunity to generate one. Typically, @@ -323,16 +324,19 @@ Store = Service.extend({ // Coerce ID to a string properties.id = coerceId(properties.id); - var internalModel = this.buildInternalModel(typeClass, properties.id); - var record = internalModel.getRecord(); + let internalModel = this.buildInternalModel(modelClass, properties.id); + let record = internalModel.getRecord(); // Move the record out of its initial `empty` state into // the `loaded` state. + // TODO @runspired this seems really bad, store should not be changing the state internalModel.loadedData(); // Set the properties specified on the record. + // TODO @runspired this is probably why we do the bad thing above record.setProperties(properties); + // TODO @runspired this should also be coalesced into some form of internalModel.setState() internalModel.eachRelationship((key, descriptor) => { internalModel._relationships.get(key).setHasData(true); }); @@ -758,6 +762,7 @@ Store = Service.extend({ scheduleFetchMany(records) { let internalModels = new Array(records.length); let fetches = new Array(records.length); + for (let i = 0; i < records.length; i++) { internalModels[i] = records[i]._internalModel; } @@ -999,9 +1004,9 @@ Store = Service.extend({ hasRecordForId(modelName, inputId) { assert("You need to pass a model name to the store's hasRecordForId method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - var typeClass = this.modelFor(modelName); - var id = coerceId(inputId); - var internalModel = this.typeMapFor(typeClass).idToRecord[id]; + let modelClass = this.modelFor(modelName); + let id = coerceId(inputId); + let internalModel = this.typeMapFor(modelClass).idToRecord[id]; return !!internalModel && internalModel.isLoaded(); }, @@ -1021,15 +1026,15 @@ Store = Service.extend({ return this._internalModelForId(modelName, id).getRecord(); }, - _internalModelForId(typeName, inputId) { + _internalModelForId(modelName, inputId) { heimdall.increment(_internalModelForId); - var typeClass = this.modelFor(typeName); + var modelClass = this.modelFor(modelName); var id = coerceId(inputId); - var idToRecord = this.typeMapFor(typeClass).idToRecord; + var idToRecord = this.typeMapFor(modelClass).idToRecord; var record = idToRecord[id]; if (!record || !idToRecord[id]) { - record = this.buildInternalModel(typeClass, id); + record = this.buildInternalModel(modelClass, id); } return record; @@ -1271,13 +1276,13 @@ Store = Service.extend({ assert("You need to pass a query hash to the store's queryRecord method", query); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - var typeClass = this.modelFor(modelName); + var modelClass = this.modelFor(modelName); var adapter = this.adapterFor(modelName); - assert("You tried to make a query but you have no adapter (for " + typeClass + ")", adapter); + assert("You tried to make a query but you have no adapter (for " + modelName + ")", adapter); assert("You tried to make a query but your adapter does not implement `queryRecord`", typeof adapter.queryRecord === 'function'); - return promiseObject(_queryRecord(adapter, this, typeClass, query).then((internalModel) => { + return promiseObject(_queryRecord(adapter, this, modelClass, query).then((internalModel) => { // the promise returned by store.queryRecord is expected to resolve with // an instance of DS.Model if (internalModel) { @@ -2199,7 +2204,7 @@ Store = Service.extend({ return null; } - var record = pushed.getRecord(); + let record = pushed.getRecord(); heimdall.stop(token); return record; }, @@ -2214,9 +2219,9 @@ Store = Service.extend({ */ _push(data) { let token = heimdall.start('store._push'); + let included = data.included; + let i, length; - var included = data.included; - var i, length; if (included) { for (i = 0, length = included.length; i < length; i++) { this._pushInternalModel(included[i]); @@ -2225,7 +2230,8 @@ Store = Service.extend({ if (Array.isArray(data.data)) { length = data.data.length; - var internalModels = new Array(length); + let internalModels = new Array(length); + for (i = 0; i < length; i++) { internalModels[i] = this._pushInternalModel(data.data[i]); } @@ -2240,7 +2246,8 @@ Store = Service.extend({ assert(`Expected an object in the 'data' property in a call to 'push' for ${data.type}, but was ${Ember.typeOf(data.data)}`, Ember.typeOf(data.data) === 'object'); - var internalModel = this._pushInternalModel(data.data); + let internalModel = this._pushInternalModel(data.data); + heimdall.stop(token); return internalModel; }, @@ -2419,7 +2426,7 @@ Store = Service.extend({ // lookupFactory should really return an object that creates // instances with the injections applied - var internalModel = new InternalModel(type, id, this, null, data); + var internalModel = new InternalModel(type, id, this, data); // if we're creating an item, this process will be done // later, once the object has been persisted. diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index 2232e88e0ca..cf8614cab09 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -45,7 +45,7 @@ testInDebug("record#belongsTo asserts when specified relationship doesn't exist" run(function() { person.belongsTo("unknown-relationship"); }); - }, "There is no belongsTo relationship named 'unknown-relationship' on a model of type 'person'"); + }, "There is no belongsTo relationship named 'unknown-relationship' on a model of modelClass 'person'"); }); testInDebug("record#belongsTo asserts when the type of the specified relationship isn't the requested one", function(assert) { @@ -63,7 +63,7 @@ testInDebug("record#belongsTo asserts when the type of the specified relationshi run(function() { family.belongsTo("persons"); }); - }, "You tried to get the 'persons' relationship on a 'family' via record.belongsTo('persons'), but the relationship is of type 'hasMany'. Use record.hasMany('persons') instead."); + }, "You tried to get the 'persons' relationship on a 'family' via record.belongsTo('persons'), but the relationship is of kind 'hasMany'. Use record.hasMany('persons') instead."); }); test("record#belongsTo", function(assert) { @@ -290,7 +290,7 @@ test("push(promise)", function(assert) { }); }); -testInDebug("push(record) asserts for invalid type", function(assert) { +testInDebug("push(record) asserts for invalid modelClass", function(assert) { var person, anotherPerson; run(function() { person = env.store.push({ @@ -318,10 +318,10 @@ testInDebug("push(record) asserts for invalid type", function(assert) { run(function() { familyReference.push(anotherPerson); }); - }, "You cannot add a record of type 'person' to the 'person.family' relationship (only 'family' allowed)"); + }, "You cannot add a record of modelClass 'person' to the 'person.family' relationship (only 'family' allowed)"); }); -test("push(record) works with polymorphic type", function(assert) { +test("push(record) works with polymorphic modelClass", function(assert) { var done = assert.async(); var person, mafiaFamily; diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 2ddd2d049ea..8419fada0c4 100644 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -44,7 +44,7 @@ testInDebug("record#hasMany asserts when specified relationship doesn't exist", run(function() { family.hasMany("unknown-relationship"); }); - }, "There is no hasMany relationship named 'unknown-relationship' on a model of type 'family'"); + }, "There is no hasMany relationship named 'unknown-relationship' on a model of modelClass 'family'"); }); testInDebug("record#hasMany asserts when the type of the specified relationship isn't the requested one", function(assert) { @@ -62,7 +62,7 @@ testInDebug("record#hasMany asserts when the type of the specified relationship run(function() { person.hasMany("family"); }); - }, "You tried to get the 'family' relationship on a 'person' via record.hasMany('family'), but the relationship is of type 'belongsTo'. Use record.belongsTo('family') instead."); + }, "You tried to get the 'family' relationship on a 'person' via record.hasMany('family'), but the relationship is of kind 'belongsTo'. Use record.belongsTo('family') instead."); }); test("record#hasMany", function(assert) { @@ -272,7 +272,7 @@ testInDebug("push(array) asserts polymorphic type", function(assert) { personsReference.push(data); }); - }, "You cannot add a record of type 'family' to the 'family.persons' relationship (only 'person' allowed)"); + }, "You cannot add a record of modelClass 'family' to the 'family.persons' relationship (only 'person' allowed)"); }); testInDebug("push(object) supports legacy, non-JSON-API-conform payload", function(assert) { @@ -423,7 +423,7 @@ if (isEnabled('ds-overhaul-references')) { personsReference.push(payload); }); - }, "You cannot add a record of type 'family' to the 'family.persons' relationship (only 'person' allowed)"); + }, "You cannot add a record of modelClass 'family' to the 'family.persons' relationship (only 'person' allowed)"); }); } diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index fa31f36526d..5efa0e42218 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -130,7 +130,7 @@ test("The store can materialize a non loaded monomorphic belongsTo association", }); }); -testInDebug("Only a record of the same type can be used with a monomorphic belongsTo relationship", function(assert) { +testInDebug("Only a record of the same modelClass can be used with a monomorphic belongsTo relationship", function(assert) { assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { @@ -156,12 +156,12 @@ testInDebug("Only a record of the same type can be used with a monomorphic belon }).then(function(records) { assert.expectAssertion(function() { records.post.set('user', records.comment); - }, /You cannot add a record of type 'comment' to the 'post.user' relationship/); + }, /You cannot add a record of modelClass 'comment' to the 'post.user' relationship/); }); }); }); -testInDebug("Only a record of the same base type can be used with a polymorphic belongsTo relationship", function(assert) { +testInDebug("Only a record of the same base modelClass can be used with a polymorphic belongsTo relationship", function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; assert.expect(1); run(function() { @@ -207,7 +207,7 @@ testInDebug("Only a record of the same base type can be used with a polymorphic assert.expectAssertion(function() { comment.set('message', records.user); - }, /You cannot add a record of type 'user' to the 'comment.message' relationship \(only 'message' allowed\)/); + }, /You cannot add a record of modelClass 'user' to the 'comment.message' relationship \(only 'message' allowed\)/); }); }); }); @@ -469,7 +469,7 @@ test("A record can be created with a resolved belongsTo promise", function(asser })); }); -test("polymorphic belongsTo type-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled", function(assert) { +test("polymorphic belongsTo class-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled", function(assert) { assert.expect(1); var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 5509add44a9..bf49959d009 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1260,12 +1260,12 @@ testInDebug("Only records of the same type can be added to a monomorphic hasMany ]).then(function(records) { assert.expectAssertion(function() { records[0].get('comments').pushObject(records[1]); - }, /You cannot add a record of type 'post' to the 'post.comments' relationship \(only 'comment' allowed\)/); + }, /You cannot add a record of modelClass 'post' to the 'post.comments' relationship \(only 'comment' allowed\)/); }); }); }); -testInDebug("Only records of the same base type can be added to a polymorphic hasMany relationship", function(assert) { +testInDebug("Only records of the same base modelClass can be added to a polymorphic hasMany relationship", function(assert) { assert.expect(2); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { @@ -1321,7 +1321,7 @@ testInDebug("Only records of the same base type can be added to a polymorphic ha assert.expectAssertion(function() { records.messages.pushObject(records.anotherUser); - }, /You cannot add a record of type 'user' to the 'user.messages' relationship \(only 'message' allowed\)/); + }, /You cannot add a record of modelClass 'user' to the 'user.messages' relationship \(only 'message' allowed\)/); }); }); }); diff --git a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index 0b9dee9114a..9439b60d168 100644 --- a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -148,7 +148,7 @@ testInDebug("Setting the polymorphic belongsTo with an object that does not impl run(function() { assert.expectAssertion(function() { user.set('bestMessage', video); - }, /You cannot add a record of type 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); + }, /You cannot add a record of modelClass 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); }); }); @@ -223,7 +223,7 @@ testInDebug("Setting the polymorphic belongsTo with an object that does not impl run(function() { assert.expectAssertion(function() { user.set('bestMessage', video); - }, /You cannot add a record of type 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); + }, /You cannot add a record of modelClass 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); }); } finally { Ember.MODEL_FACTORY_INJECTIONS = injectionValue; diff --git a/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js index a9f7e9962b8..9141b088522 100644 --- a/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -164,7 +164,7 @@ testInDebug("Pushing a an object that does not implement the mixin to the mixin user.get('messages').then(function(fetchedMessages) { assert.expectAssertion(function() { fetchedMessages.pushObject(notMessage); - }, /You cannot add a record of type 'not-message' to the 'user.messages' relationship \(only 'message' allowed\)/); + }, /You cannot add a record of modelClass 'not-message' to the 'user.messages' relationship \(only 'message' allowed\)/); }); }); }); @@ -251,7 +251,7 @@ testInDebug("Pushing a an object that does not implement the mixin to the mixin user.get('messages').then(function(fetchedMessages) { assert.expectAssertion(function() { fetchedMessages.pushObject(notMessage); - }, /You cannot add a record of type 'not-message' to the 'user.messages' relationship \(only 'message' allowed\)/); + }, /You cannot add a record of modelClass 'not-message' to the 'user.messages' relationship \(only 'message' allowed\)/); }); }); } finally { diff --git a/tests/unit/model/internal-model-test.js b/tests/unit/model/internal-model-test.js deleted file mode 100644 index 04f21f4c363..00000000000 --- a/tests/unit/model/internal-model-test.js +++ /dev/null @@ -1,24 +0,0 @@ -import DS from 'ember-data'; - -import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import { module } from 'qunit'; - -module("unit/model/internal-model - Internal Model"); - -function MockModelFactory () { } - -MockModelFactory._create = function() { - return { trigger() {} }; -}; - -MockModelFactory.eachRelationship = function() { }; - -testInDebug("Materializing a model twice errors out", function(assert) { - assert.expect(1); - var internalModel = new DS.InternalModel(MockModelFactory, null, { }, null); - - internalModel.materializeRecord(); - assert.expectAssertion(function() { - internalModel.materializeRecord(); - }, /more than once/); -}); diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index 36819fdf2f3..c9bee2a87ff 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -83,7 +83,7 @@ testInDebug("assertPolymorphicType works for subclasses", function(assert) { assert.expectAssertion(function() { assertPolymorphicType(user, relationship, person); - }, "You cannot add a record of type 'person' to the 'user.messages' relationship (only 'message' allowed)"); + }, "You cannot add a record of modelClass 'person' to the 'user.messages' relationship (only 'message' allowed)"); }); test("modelHasAttributeOrRelationshipNamedType", function(assert) { @@ -138,5 +138,5 @@ testInDebug("assertPolymorphicType works for mixins", function(assert) { assert.expectAssertion(function() { assertPolymorphicType(post, relationship, person); - }, "You cannot add a record of type 'person' to the 'post.medias' relationship (only 'medium' allowed)"); + }, "You cannot add a record of modelClass 'person' to the 'post.medias' relationship (only 'medium' allowed)"); }); From 8e788d242bb0c10554157341ac01d73d3c018521 Mon Sep 17 00:00:00 2001 From: pangratz Date: Sun, 23 Oct 2016 13:52:43 +0300 Subject: [PATCH 1677/2527] Test assertions when updateRecord & deleteRecord don't exist on adapter --- .../integration/adapter/store-adapter-test.js | 46 ++++++++++++++++--- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 8048750aad0..3348ca6a9ca 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -24,6 +24,15 @@ var set = Ember.set; var run = Ember.run; var Person, Dog, env, store, adapter; +function moveRecordOutOfInFlight(record) { + run(function() { + // move record out of the inflight state so the tests can clean up + // correctly + let { store, _internalModel } = record; + store.recordWasError(_internalModel, new Error()); + }); +} + module("integration/adapter/store-adapter - DS.Store and DS.Adapter integration test", { beforeEach() { Person = DS.Model.extend({ @@ -1404,7 +1413,6 @@ test("An async hasMany relationship with links should not trigger shouldBackgrou })); }); - testInDebug("There should be a friendly error for if the adapter does not implement createRecord", function(assert) { adapter.createRecord = null; @@ -1415,9 +1423,35 @@ testInDebug("There should be a friendly error for if the adapter does not implem tom.save(); }); }, /does not implement 'createRecord'/); - run(function() { - // move record out of the inflight state so the tests can clean up - // correctly - store.recordWasError(tom._internalModel, new Error()); - }); + + moveRecordOutOfInFlight(tom); +}); + +testInDebug("There should be a friendly error for if the adapter does not implement updateRecord", function(assert) { + adapter.updateRecord = null; + + let tom; + assert.expectAssertion(function() { + run(function() { + tom = store.push({ data: { type: 'person', id: 1 } }); + tom.save(); + }); + }, /does not implement 'updateRecord'/); + + moveRecordOutOfInFlight(tom); +}); + +testInDebug("There should be a friendly error for if the adapter does not implement deleteRecord", function(assert) { + adapter.deleteRecord = null; + + let tom; + assert.expectAssertion(function() { + run(function() { + tom = store.push({ data: { type: 'person', id: 1 } }); + tom.deleteRecord(); + tom.save(); + }); + }, /does not implement 'deleteRecord'/); + + moveRecordOutOfInFlight(tom); }); From 0a204bbd069dcfb7ca7378f66774c7a907ad11eb Mon Sep 17 00:00:00 2001 From: Romanior Date: Sat, 22 Oct 2016 15:51:48 +0300 Subject: [PATCH 1678/2527] [FEATURE ds-serialize-id] add serializeId to json-serializer --- FEATURES.md | 16 +++++ addon/serializers/json.js | 48 +++++++++++++-- config/features.json | 3 +- .../serializers/json-serializer-test.js | 60 +++++++++++++++++++ 4 files changed, 122 insertions(+), 5 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index e542252d6fc..5757625abfd 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -130,3 +130,19 @@ entry in `config/features.json`. tom.resetAttribute('lastName') // { firstName: 'Tom', lastName: 'Dale' } tom.get('hasDirtyAttributes') // false ``` + +- `ds-serialize-id` [#4620](https://github.com/emberjs/data/pull/4620) + + Adds a `serializeId` method to JSONSerializer. + + ```js + // app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + serializeId(snapshot, json, primaryKey) { + var id = snapshot.id; + json[primaryKey] = parseInt(id, 10); + } + }); + ``` diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 29ee9ad0dc5..5ab4ad7c27a 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1050,10 +1050,13 @@ var JSONSerializer = Serializer.extend({ var json = {}; if (options && options.includeId) { - var id = snapshot.id; - - if (id) { - json[get(this, 'primaryKey')] = id; + if (isEnabled('ds-serialize-id')) { + this.serializeId(snapshot, json, get(this, 'primaryKey')); + } else { + var id = snapshot.id; + if (id) { + json[get(this, 'primaryKey')] = id; + } } } @@ -1535,4 +1538,41 @@ if (isEnabled("ds-payload-type-hooks")) { } +if (isEnabled("ds-serialize-id")) { + + JSONSerializer.reopen({ + + /** + serializeId can be used to customize how id is serialized + For example, your server may expect integer datatype of id + + By default the snapshot's id (String) is set on the json hash via json[primaryKey] = snapshot.id. + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + serializeId(snapshot, json, primaryKey) { + var id = snapshot.id; + json[primaryKey] = parseInt(id, 10); + } + }); + ``` + + @method serializeId + @public + @param {DS.Snapshot} snapshot + @param {Object} json + @param {String} primaryKey + */ + serializeId(snapshot, json, primaryKey) { + var id = snapshot.id; + + if (id) { + json[primaryKey] = id; + } + } + }); +} + export default JSONSerializer; diff --git a/config/features.json b/config/features.json index b68623e34ef..4b9c28cb124 100644 --- a/config/features.json +++ b/config/features.json @@ -5,5 +5,6 @@ "ds-overhaul-references": null, "ds-payload-type-hooks": null, "ds-check-should-serialize-relationships": null, - "ds-reset-attribute": null + "ds-reset-attribute": null, + "ds-serialize-id": null } diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 73fc5b9bf50..00cb4d20105 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -68,6 +68,66 @@ test("serialize includes id when includeId is true", function(assert) { }); }); +if (isEnabled("ds-serialize-id")) { + test("serializeId", function(assert) { + run(function() { + post = env.store.createRecord('post'); + post.set('id', 'test'); + }); + var json = {}; + + env.serializer.serializeId(post._createSnapshot(), json, 'id'); + + assert.deepEqual(json, { + id: 'test' + }); + }); + + test("modified serializeId is called from serialize", function(assert) { + env.registry.register('serializer:post', DS.JSONSerializer.extend({ + serializeId(snapshot, json, primaryKey) { + var id = snapshot.id; + json[primaryKey] = id.toUpperCase(); + } + })); + + run(function() { + post = env.store.createRecord('post', { title: 'Rails is omakase' }); + post.set('id', 'test'); + }); + var json = {}; + + json = env.store.serializerFor("post").serialize(post._createSnapshot(), { includeId: true }); + + assert.deepEqual(json, { + id: 'TEST', + title: 'Rails is omakase', + comments: [] + }); + }); + + test("serializeId respects `primaryKey` serializer property", function(assert) { + env.registry.register('serializer:post', DS.JSONSerializer.extend({ + primaryKey: '_ID_' + })); + + run(function() { + post = env.store.createRecord('post', { title: 'Rails is omakase' }); + post.set('id', 'test'); + }); + var json = {}; + + json = env.store.serializerFor("post").serialize(post._createSnapshot(), { includeId: true }); + + assert.deepEqual(json, { + _ID_: 'test', + title: 'Rails is omakase', + comments: [] + }); + }); + +} + test("serializeAttribute", function(assert) { run(function() { post = env.store.createRecord('post', { title: "Rails is omakase" }); From ae1d7aedb06a53abd7d778b0b4d1a86441fe56ab Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 24 Oct 2016 16:02:44 -0400 Subject: [PATCH 1679/2527] Clean up extra whitespace in FEATURES.md --- FEATURES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 5757625abfd..1768898f93c 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -130,10 +130,10 @@ entry in `config/features.json`. tom.resetAttribute('lastName') // { firstName: 'Tom', lastName: 'Dale' } tom.get('hasDirtyAttributes') // false ``` - + - `ds-serialize-id` [#4620](https://github.com/emberjs/data/pull/4620) - Adds a `serializeId` method to JSONSerializer. + Adds a `serializeId` method to JSONSerializer. ```js // app/serializers/application.js From 65006ccad18233cb3aa8505f405f1c0c608f26bd Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 26 Aug 2016 14:13:33 -0400 Subject: [PATCH 1680/2527] Update the relationship docs to remove some references to a globals style namespace --- addon/-private/system/relationships/ext.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 248b5ad4bb8..bc69b5c02cf 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -171,7 +171,7 @@ export const RelationshipsClassMethodsMixin = Ember.Mixin.create({ }); ``` - Calling `App.Post.typeForRelationship('comments')` will return `App.Comment`. + Calling `store.modelFor('post').typeForRelationship('comments', store)` will return `Comment`. @method typeForRelationship @static @@ -209,12 +209,13 @@ export const RelationshipsClassMethodsMixin = Ember.Mixin.create({ }); ``` - App.Post.inverseFor('comments') -> { type: App.Message, name: 'owner', kind: 'belongsTo' } - App.Message.inverseFor('owner') -> { type: App.Post, name: 'comments', kind: 'hasMany' } + store.modelFor('post').inverseFor('comments', store) -> { type: App.Message, name: 'owner', kind: 'belongsTo' } + store.modelFor('message').inverseFor('owner', store) -> { type: App.Post, name: 'comments', kind: 'hasMany' } @method inverseFor @static @param {String} name the name of the relationship + @param {DS.Store} store @return {Object} the inverse relationship, or null */ inverseFor(name, store) { @@ -346,12 +347,14 @@ export const RelationshipsClassMethodsMixin = Ember.Mixin.create({ ```javascript import Ember from 'ember'; import Blog from 'app/models/blog'; + import User from 'app/models/user'; + import Post from 'app/models/post'; var relationships = Ember.get(Blog, 'relationships'); - relationships.get(App.User); + relationships.get(User); //=> [ { name: 'users', kind: 'hasMany' }, // { name: 'owner', kind: 'belongsTo' } ] - relationships.get(App.Post); + relationships.get(Post); //=> [ { name: 'posts', kind: 'hasMany' } ] ``` @@ -437,7 +440,7 @@ export const RelationshipsClassMethodsMixin = Ember.Mixin.create({ import Blog from 'app/models/blog'; var relatedTypes = Ember.get(Blog, 'relatedTypes'); - //=> [ App.User, App.Post ] + //=> [ User, Post ] ``` @property relatedTypes From 061850f03220d75436385d0cada0cf6537f18f24 Mon Sep 17 00:00:00 2001 From: Scott Batson Date: Wed, 26 Oct 2016 14:14:03 -0400 Subject: [PATCH 1681/2527] [DOC] #4595 revise unloadAll description --- addon/-private/system/store.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index fe862e628d6..669d56552a1 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1581,6 +1581,7 @@ Store = Service.extend({ /** This method unloads all records in the store. + It schedules unloading to happen during the next run loop. Optionally you can pass a type which unload all records for a given type. From dfd7a03e0c3e7e027c8f1e0fec64967f48e4a64e Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 26 Oct 2016 14:31:49 -0700 Subject: [PATCH 1682/2527] port models/scenarios from json-api-mock-server and fix develop mode serving --- server/models/baz.js | 12 +++++ server/models/complex.js | 13 +++++ server/models/foo.js | 12 +++++ server/models/heavy-baz.js | 13 +++++ server/models/heavy-foo.js | 12 +++++ server/models/heavy.js | 13 +++++ server/models/simple.js | 9 ++++ server/scenarios/default.js | 6 +++ .../app/helpers/reopen-instrumentation.js | 51 ------------------- tests/dummy/app/routes/query/route.js | 10 ---- 10 files changed, 90 insertions(+), 61 deletions(-) create mode 100644 server/models/baz.js create mode 100644 server/models/complex.js create mode 100644 server/models/foo.js create mode 100644 server/models/heavy-baz.js create mode 100644 server/models/heavy-foo.js create mode 100644 server/models/heavy.js create mode 100644 server/models/simple.js create mode 100644 server/scenarios/default.js delete mode 100644 tests/dummy/app/helpers/reopen-instrumentation.js diff --git a/server/models/baz.js b/server/models/baz.js new file mode 100644 index 00000000000..66435e61a3d --- /dev/null +++ b/server/models/baz.js @@ -0,0 +1,12 @@ +var faker = require('faker'); +var props = require('../store/props'); +var attr = props.attr; +var one = props.one; +var between = require('../utils/between'); + +module.exports = { + name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), + description: attr('string', { defaultValue: function() { return faker.lorem.sentences(between(3, 7)); }}), + complex: one('complex', { inverse: 'baz', defaultValue: false }), + heavyBaz: one('heavy-baz', { inverse: 'bazs', defaultValue: false }) +}; diff --git a/server/models/complex.js b/server/models/complex.js new file mode 100644 index 00000000000..1a7d238c531 --- /dev/null +++ b/server/models/complex.js @@ -0,0 +1,13 @@ +var faker = require('faker'); +var props = require('../store/props'); +var attr = props.attr; +var many = props.many; +var one = props.one; +var between = require('../utils/between'); + +module.exports = { + name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), + description: attr('string', { defaultValue: function() { return faker.lorem.sentences(between(3, 7)); }}), + baz: one('baz', { inverse: 'complex', defaultValue: true }), + foos: many('foo', { inverse: 'complex', defaultValue: 5 }) +}; diff --git a/server/models/foo.js b/server/models/foo.js new file mode 100644 index 00000000000..b358ca037b2 --- /dev/null +++ b/server/models/foo.js @@ -0,0 +1,12 @@ +var faker = require('faker'); +var props = require('../store/props'); +var attr = props.attr; +var one = props.one; +var between = require('../utils/between'); + +module.exports = { + name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), + description: attr('string', { defaultValue: function() { return faker.lorem.sentences(between(3, 7)); }}), + complex: one('complex', { inverse: 'foos', defaultValue: false }), + heavyFoo: one('heavy-foo', { inverse: 'foo', defaultValue: false }) +}; diff --git a/server/models/heavy-baz.js b/server/models/heavy-baz.js new file mode 100644 index 00000000000..5fe43bde274 --- /dev/null +++ b/server/models/heavy-baz.js @@ -0,0 +1,13 @@ +var faker = require('faker'); +var props = require('../store/props'); +var attr = props.attr; +var one = props.one; +var many = props.many; +var between = require('../utils/between'); + +module.exports = { + name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), + description: attr('string', { defaultValue: function() { return faker.lorem.sentences(between(3, 7)); }}), + heavy: one('heavy', { inverse: 'heavyBaz', defaultValue: false }), + bazs: many('baz', { inverse: 'heavyBaz', defaultValue: 5 }) +}; diff --git a/server/models/heavy-foo.js b/server/models/heavy-foo.js new file mode 100644 index 00000000000..24e3e285438 --- /dev/null +++ b/server/models/heavy-foo.js @@ -0,0 +1,12 @@ +var faker = require('faker'); +var props = require('../store/props'); +var attr = props.attr; +var one = props.one; +var between = require('../utils/between'); + +module.exports = { + name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), + description: attr('string', { defaultValue: function() { return faker.lorem.sentences(between(3, 7)); }}), + heavy: one('heavy', { inverse: 'heavyFoos', defaultValue: false }), + foo: one('foo', { inverse: 'heavyFoo', defaultValue: true }) +}; diff --git a/server/models/heavy.js b/server/models/heavy.js new file mode 100644 index 00000000000..8ce6bb52b4b --- /dev/null +++ b/server/models/heavy.js @@ -0,0 +1,13 @@ +var faker = require('faker'); +var props = require('../store/props'); +var attr = props.attr; +var many = props.many; +var one = props.one; +var between = require('../utils/between'); + +module.exports = { + name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), + description: attr('string', { defaultValue: function() { return faker.lorem.sentences(between(3, 7)); }}), + heavyBaz: one('heavy-baz', { inverse: 'heavy', defaultValue: true }), + heavyFoos: many('heavy-foo', { inverse: 'heavy', defaultValue: 5 }) +}; diff --git a/server/models/simple.js b/server/models/simple.js new file mode 100644 index 00000000000..689e0690ff0 --- /dev/null +++ b/server/models/simple.js @@ -0,0 +1,9 @@ +var faker = require('faker'); +var props = require('../store/props'); +var attr = props.attr; +var between = require('../utils/between'); + +module.exports = { + title: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), + description: attr('string', { defaultValue: function() { return faker.lorem.sentences(between(3, 7)); }}) +}; diff --git a/server/scenarios/default.js b/server/scenarios/default.js new file mode 100644 index 00000000000..954423e0102 --- /dev/null +++ b/server/scenarios/default.js @@ -0,0 +1,6 @@ +module.exports = function(store) { + store.seed('simple', 240); + store.seed('complex', 35); + store.seed('heavy', 14); +}; + diff --git a/tests/dummy/app/helpers/reopen-instrumentation.js b/tests/dummy/app/helpers/reopen-instrumentation.js deleted file mode 100644 index f037e5b0e9a..00000000000 --- a/tests/dummy/app/helpers/reopen-instrumentation.js +++ /dev/null @@ -1,51 +0,0 @@ -/* global heimdall */ -import Ember from 'ember'; -import DS from "ember-data"; - -const { - Model -} = DS; - -const { - Object: Obj -} = Ember; - -export default function instrumentBaseObjects(owner) { - const [__a, __b] = heimdall.registerMonitor('owner', 'lookup', '_lookupFactory'); - let originalLookup = owner.lookup; - let originalLookupFactory = owner._lookupFactory; - - owner.lookup = function lookup() { - heimdall.increment(__a); - return originalLookup.apply(this, arguments); - }; - - owner._lookupFactory = function _lookupFactory() { - heimdall.increment(__b); - return originalLookupFactory.apply(this, arguments); - }; - - const [__c] = heimdall.registerMonitor('reopened-model', '_create'); - const [__d, __e] = heimdall.registerMonitor('reopened-object', 'create', 'extend'); - let originalModelCreate = Model._create; - let originalCreate = Obj.create; - let originalExtend = Obj.extend; - - Model.reopenClass({ - _create() { - heimdall.increment(__c); - return originalModelCreate.apply(this, arguments); - } - }); - - Obj.reopenClass({ - create() { - heimdall.increment(__d); - return originalCreate.apply(this, arguments); - }, - extend() { - heimdall.increment(__e); - return originalExtend.apply(this, arguments); - } - }); -} diff --git a/tests/dummy/app/routes/query/route.js b/tests/dummy/app/routes/query/route.js index 7e035ba2542..f64fd666cd3 100644 --- a/tests/dummy/app/routes/query/route.js +++ b/tests/dummy/app/routes/query/route.js @@ -1,15 +1,10 @@ /* global window, heimdall, console */ import Ember from 'ember'; -import instrumentBaseObjects from '../../helpers/reopen-instrumentation'; -import config from 'dummy/config/environment'; const { - getOwner, Route } = Ember; -let HAS_INSTRUMENTED = false; - export default Route.extend({ queryParams: { @@ -23,11 +18,6 @@ export default Route.extend({ model(params) { // switch this to 'production' when generating production build baselines - if (config.environment === 'development' && !HAS_INSTRUMENTED) { - instrumentBaseObjects(getOwner(this)); - HAS_INSTRUMENTED = true; - } - let modelName = params.modelName; delete params.modelName; From cddfd4d2633fa99933e782f01f4590ca8f2e1c10 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 26 Oct 2016 15:28:45 -0700 Subject: [PATCH 1683/2527] update mock server deps --- package.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 49804505c40..1a85a8ecc93 100644 --- a/package.json +++ b/package.json @@ -81,18 +81,19 @@ "ember-resolver": "^2.0.3", "ember-watson": "^0.7.0", "express": "^4.14.0", + "faker": "^3.1.0", "github": "^0.2.4", "glob": "5.0.13", "heimdall-query": "^0.0.5", - "json-api-mock-server": "0.0.2", + "json-api-mock-server": "0.1.1", + "loader.js": "^4.0.1", "mocha": "2.4.5", "mocha-only-detector": "0.0.2", - "phantomjs-prebuilt": "^2.1.12", "morgan": "^1.7.0", + "phantomjs-prebuilt": "^2.1.12", "pretender": "1.0.0", "rimraf": "2.5.2", - "rsvp": "3.2.1", - "loader.js": "^4.0.1" + "rsvp": "3.2.1" }, "peerDependencies": { "ember-inflector": "^1.9.4" From 37c33e2cbfee33a47074e3229b199e190b43734d Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 21 Oct 2016 18:00:39 -0700 Subject: [PATCH 1684/2527] chore(store): cleans up and optimizes code paths around fetching relationships and single records --- addon/-private/system/model/internal-model.js | 4 +- .../system/relationships/state/has-many.js | 4 +- addon/-private/system/snapshot.js | 1 - addon/-private/system/store.js | 224 ++++++++++-------- tests/integration/snapshot-test.js | 12 +- tests/unit/store/adapter-interop-test.js | 47 ++-- 6 files changed, 155 insertions(+), 137 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 97f06480143..a3ce1f81a7b 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -709,11 +709,11 @@ export default class InternalModel { Preloaded data can be attributes and relationships passed in either as IDs or as actual models. - @method _preloadData + @method preloadData @private @param {Object} preload */ - _preloadData(preload) { + preloadData(preload) { //TODO(Igor) consider the polymorphic case Object.keys(preload).forEach((key) => { let preloadValue = get(preload, key); diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 9aa3286abf0..3314a350a43 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -130,9 +130,7 @@ ManyRelationship.prototype.reload = function() { this._loadingPromise = promiseManyArray(this.fetchLink(), 'Reload with link'); return this._loadingPromise; } else { - this._loadingPromise = promiseManyArray(this.store.scheduleFetchMany(manyArray.toArray()).then(() => { - return manyArray; - }), 'Reload with ids'); + this._loadingPromise = promiseManyArray(this.store._scheduleFetchMany(manyArray.currentState).then(() => manyArray), 'Reload with ids'); return this._loadingPromise; } }; diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index aea59e2ebf5..cd206d1ade1 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -36,7 +36,6 @@ export default function Snapshot(internalModel, options = {}) { @type {Object} */ this.adapterOptions = options.adapterOptions; - this.include = options.include; this._changedAttributes = record.changedAttributes(); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index fd6a2565d02..3aa87f66e8f 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -49,7 +49,7 @@ const { get, isNone, isPresent, - Map, + MapWithDefault, run: emberRun, set, Service @@ -212,7 +212,7 @@ Store = Service.extend({ this._instanceCache = new ContainerInstanceCache(getOwner(this), this); //Used to keep track of all the find requests that need to be coalesced - this._pendingFetch = Map.create(); + this._pendingFetch = MapWithDefault.create({ defaultValue() { return []; } }); }, /** @@ -664,7 +664,7 @@ Store = Service.extend({ _findRecord(internalModel, options) { // Refetch if the reload option is passed if (options.reload) { - return this.scheduleFetch(internalModel, options); + return this._scheduleFetch(internalModel, options); } var snapshot = internalModel.createSnapshot(options); @@ -673,7 +673,7 @@ Store = Service.extend({ // Refetch the record if the adapter thinks the record is stale if (adapter.shouldReloadRecord(this, snapshot)) { - return this.scheduleFetch(internalModel, options); + return this._scheduleFetch(internalModel, options); } if (options.backgroundReload === false) { @@ -682,7 +682,7 @@ Store = Service.extend({ // Trigger the background refetch if backgroundReload option is passed if (options.backgroundReload || adapter.shouldBackgroundReloadRecord(this, snapshot)) { - this.scheduleFetch(internalModel, options); + this._scheduleFetch(internalModel, options); } // Return the cached record @@ -693,7 +693,7 @@ Store = Service.extend({ options = options || {}; if (options.preload) { - internalModel._preloadData(options.preload); + internalModel.preloadData(options.preload); } var fetchedInternalModel = this._findEmptyInternalModel(internalModel, options); @@ -703,7 +703,7 @@ Store = Service.extend({ _findEmptyInternalModel(internalModel, options) { if (internalModel.isEmpty()) { - return this.scheduleFetch(internalModel, options); + return this._scheduleFetch(internalModel, options); } //TODO double check about reloading @@ -741,59 +741,47 @@ Store = Service.extend({ type/id pair hasn't been loaded yet to kick off a request to the adapter. - @method fetchRecord + @method _fetchRecord @private @param {InternalModel} internalModel model @return {Promise} promise */ - // TODO rename this to have an underscore - fetchRecord(internalModel, options) { - var typeClass = internalModel.type; - var id = internalModel.id; - var adapter = this.adapterFor(typeClass.modelName); + _fetchRecord(internalModel, options) { + let modelClass = internalModel.type; + let id = internalModel.id; + let adapter = this.adapterFor(modelClass.modelName); - assert("You tried to find a record but you have no adapter (for " + typeClass + ")", adapter); - assert("You tried to find a record but your adapter (for " + typeClass + ") does not implement 'findRecord'", typeof adapter.findRecord === 'function'); + assert("You tried to find a record but you have no adapter (for " + modelClass.modelName + ")", adapter); + assert("You tried to find a record but your adapter (for " + modelClass.modelName + ") does not implement 'findRecord'", typeof adapter.findRecord === 'function'); - var promise = _find(adapter, this, typeClass, id, internalModel, options); - return promise; + return _find(adapter, this, modelClass, id, internalModel, options); }, - scheduleFetchMany(records) { - let internalModels = new Array(records.length); - let fetches = new Array(records.length); - - for (let i = 0; i < records.length; i++) { - internalModels[i] = records[i]._internalModel; - } + _scheduleFetchMany(internalModels) { + let fetches = new Array(internalModels.length); for (let i = 0; i < internalModels.length; i++) { - fetches[i] = this.scheduleFetch(internalModels[i]); + fetches[i] = this._scheduleFetch(internalModels[i]); } - return Ember.RSVP.Promise.all(fetches); + return Promise.all(fetches); }, - scheduleFetch(internalModel, options) { - var typeClass = internalModel.type; - + _scheduleFetch(internalModel, options) { if (internalModel._loadingPromise) { return internalModel._loadingPromise; } - var resolver = Ember.RSVP.defer('Fetching ' + typeClass + 'with id: ' + internalModel.id); - var pendingFetchItem = { - record: internalModel, - resolver: resolver, - options: options + let modelClass = internalModel.type; + let resolver = Ember.RSVP.defer('Fetching ' + modelClass.modelName + ' with id: ' + internalModel.id); + let pendingFetchItem = { + internalModel, + resolver, + options }; - var promise = resolver.promise; + let promise = resolver.promise; internalModel.loadingData(promise); + this._pendingFetch.get(modelClass).push(pendingFetchItem); - if (!this._pendingFetch.get(typeClass)) { - this._pendingFetch.set(typeClass, [pendingFetchItem]); - } else { - this._pendingFetch.get(typeClass).push(pendingFetchItem); - } emberRun.scheduleOnce('afterRender', this, this.flushAllPendingFetches); return promise; @@ -805,63 +793,77 @@ Store = Service.extend({ } this._pendingFetch.forEach(this._flushPendingFetchForType, this); - this._pendingFetch = Map.create(); + this._pendingFetch.clear(); }, - _flushPendingFetchForType(pendingFetchItems, typeClass) { - var store = this; - var adapter = store.adapterFor(typeClass.modelName); - var shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; - var records = Ember.A(pendingFetchItems).mapBy('record'); + _flushPendingFetchForType(pendingFetchItems, modelClass) { + let store = this; + let adapter = store.adapterFor(modelClass.modelName); + let shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; + let totalItems = pendingFetchItems.length; + let internalModels = new Array(totalItems); + let seeking = new EmptyObject(); + + for (let i = 0; i < totalItems; i++) { + let pendingItem = pendingFetchItems[i]; + let internalModel = pendingItem.internalModel; + internalModels[i] = internalModel; + seeking[internalModel.id] = pendingItem; + } function _fetchRecord(recordResolverPair) { - recordResolverPair.resolver.resolve(store.fetchRecord(recordResolverPair.record, recordResolverPair.options)); // TODO adapter options + let recordFetch = store._fetchRecord( + recordResolverPair.internalModel, + recordResolverPair.options + ); // TODO adapter options + + recordResolverPair.resolver.resolve(recordFetch); } - function resolveFoundRecords(records) { - records.forEach((record) => { - var pair = Ember.A(pendingFetchItems).findBy('record', record); + function handleFoundRecords(foundInternalModels, expectedInternalModels) { + // resolve found records + let found = new EmptyObject(); + for (let i = 0, l = foundInternalModels.length; i < l; i++) { + let internalModel = foundInternalModels[i]; + let pair = seeking[internalModel.id]; + found[internalModel.id] = internalModel; + if (pair) { - var resolver = pair.resolver; - resolver.resolve(record); + let resolver = pair.resolver; + resolver.resolve(internalModel); } - }); - return records; - } + } + + // reject missing records + let missingInternalModels = []; - function makeMissingRecordsRejector(requestedRecords) { - return function rejectMissingRecords(resolvedRecords) { - resolvedRecords = Ember.A(resolvedRecords); - var missingRecords = requestedRecords.reject((record) => resolvedRecords.includes(record)); - if (missingRecords.length) { - warn('Ember Data expected to find records with the following ids in the adapter response but they were missing: ' + Ember.inspect(Ember.A(missingRecords).mapBy('id')), false, { - id: 'ds.store.missing-records-from-adapter' - }); + for (let i = 0, l = expectedInternalModels.length; i < l; i++) { + let internalModel = expectedInternalModels[i]; + + if (!found[internalModel.id]) { + missingInternalModels.push(internalModel); } - rejectRecords(missingRecords); - }; - } + } - function makeRecordsRejector(records) { - return function (error) { - rejectRecords(records, error); - }; + if (missingInternalModels.length) { + warn('Ember Data expected to find records with the following ids in the adapter response but they were missing: ' + Ember.inspect(missingInternalModels.map(r => r.id)), false, { + id: 'ds.store.missing-records-from-adapter' + }); + rejectInternalModels(missingInternalModels); + } } - function rejectRecords(records, error) { - records.forEach((record) => { - var pair = Ember.A(pendingFetchItems).findBy('record', record); + function rejectInternalModels(internalModels, error) { + for (let i = 0, l = internalModels.length; i < l; i++) { + let pair = seeking[internalModels[i].id]; + if (pair) { - var resolver = pair.resolver; - resolver.reject(error); + pair.resolver.reject(error); } - }); + } } - if (pendingFetchItems.length === 1) { - _fetchRecord(pendingFetchItems[0]); - } else if (shouldCoalesce) { - + if (shouldCoalesce) { // TODO: Improve records => snapshots => records => snapshots // // We want to provide records to all store methods and snapshots to all @@ -872,27 +874,45 @@ Store = Service.extend({ // But since the _findMany() finder is a store method we need to get the // records from the grouped snapshots even though the _findMany() finder // will once again convert the records to snapshots for adapter.findMany() + let snapshots = new Array(totalItems); + for (let i = 0; i < totalItems; i++) { + snapshots[i] = internalModels[i].createSnapshot(); + } + + let groups = adapter.groupRecordsForFindMany(this, snapshots); + + for (let i = 0, l = groups.length; i < l; i++) { + let group = groups[i]; + let totalInGroup = groups[i].length; + let ids = new Array(totalInGroup); + let groupedInternalModels = new Array(totalInGroup); + + for (let j = 0; j < totalInGroup; j++) { + let internalModel = group[j]._internalModel; - var snapshots = Ember.A(records).invoke('createSnapshot'); - var groups = adapter.groupRecordsForFindMany(this, snapshots); - groups.forEach((groupOfSnapshots) => { - var groupOfRecords = Ember.A(groupOfSnapshots).mapBy('_internalModel'); - var requestedRecords = Ember.A(groupOfRecords); - var ids = requestedRecords.mapBy('id'); - if (ids.length > 1) { - _findMany(adapter, store, typeClass, ids, requestedRecords). - then(resolveFoundRecords). - then(makeMissingRecordsRejector(requestedRecords)). - then(null, makeRecordsRejector(requestedRecords)); + groupedInternalModels[j] = internalModel; + ids[j] = internalModel.id; + } + + if (totalInGroup > 1) { + _findMany(adapter, store, modelClass, ids, groupedInternalModels) + .then(function(foundInternalModels) { + handleFoundRecords(foundInternalModels, groupedInternalModels); + }) + .catch(function(error) { + rejectInternalModels(groupedInternalModels, error); + }); } else if (ids.length === 1) { - var pair = Ember.A(pendingFetchItems).findBy('record', groupOfRecords[0]); + let pair = seeking[groupedInternalModels[0].id]; _fetchRecord(pair); } else { assert("You cannot return an empty array from adapter's method groupRecordsForFindMany", false); } - }); + } } else { - pendingFetchItems.forEach(_fetchRecord); + for (let i = 0; i < totalItems; i++) { + _fetchRecord(pendingFetchItems[i]); + } } }, @@ -990,7 +1010,7 @@ Store = Service.extend({ assert("You tried to reload a record but you have no adapter (for " + modelName + ")", adapter); assert("You tried to reload a record but your adapter does not implement `findRecord`", typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); - return this.scheduleFetch(internalModel); + return this._scheduleFetch(internalModel); }, /** @@ -1028,16 +1048,16 @@ Store = Service.extend({ _internalModelForId(modelName, inputId) { heimdall.increment(_internalModelForId); - var modelClass = this.modelFor(modelName); - var id = coerceId(inputId); - var idToRecord = this.typeMapFor(modelClass).idToRecord; - var record = idToRecord[id]; + let modelClass = this.modelFor(modelName); + let id = coerceId(inputId); + let idToRecord = this.typeMapFor(modelClass).idToRecord; + let internalModel = idToRecord[id]; - if (!record || !idToRecord[id]) { - record = this.buildInternalModel(modelClass, id); + if (!internalModel || !idToRecord[id]) { + internalModel = this.buildInternalModel(modelClass, id); } - return record; + return internalModel; }, diff --git a/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js index b63a5941892..00fc28db881 100644 --- a/tests/integration/snapshot-test.js +++ b/tests/integration/snapshot-test.js @@ -945,11 +945,11 @@ test("snapshot.eachRelationship() proxies to record", function(assert) { }); }); -test("snapshot.belongsTo() does not trigger a call to store.scheduleFetch", function(assert) { +test("snapshot.belongsTo() does not trigger a call to store._scheduleFetch", function(assert) { assert.expect(0); - env.store.scheduleFetch = function() { - assert.ok(false, 'store.scheduleFetch should not be called'); + env.store._scheduleFetch = function() { + assert.ok(false, 'store._scheduleFetch should not be called'); }; run(function() { @@ -974,11 +974,11 @@ test("snapshot.belongsTo() does not trigger a call to store.scheduleFetch", func }); }); -test("snapshot.hasMany() does not trigger a call to store.scheduleFetch", function(assert) { +test("snapshot.hasMany() does not trigger a call to store._scheduleFetch", function(assert) { assert.expect(0); - env.store.scheduleFetch = function() { - assert.ok(false, 'store.scheduleFetch should not be called'); + env.store._scheduleFetch = function() { + assert.ok(false, 'store._scheduleFetch should not be called'); }; run(function() { diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index 100d7f069f4..f2e04bbe782 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -614,21 +614,21 @@ test("store.fetchMany should always return a promise", function(assert) { run(function() { store.createRecord('person'); }); - var records = Ember.A([]); + var records = []; var results; run(function() { - results = store.scheduleFetchMany(records); + results = store._scheduleFetchMany(records); }); - assert.ok(results, "A call to store.scheduleFetchMany() should return a result"); - assert.ok(results.then, "A call to store.scheduleFetchMany() should return a promise"); + assert.ok(results, "A call to store._scheduleFetchMany() should return a result"); + assert.ok(results.then, "A call to store._scheduleFetchMany() should return a promise"); results.then(assert.wait(function(returnedRecords) { assert.deepEqual(returnedRecords, [], "The correct records are returned"); })); }); -test("store.scheduleFetchMany should not resolve until all the records are resolved", function(assert) { +test("store._scheduleFetchMany should not resolve until all the records are resolved", function(assert) { assert.expect(1); var Person = DS.Model.extend(); @@ -672,15 +672,16 @@ test("store.scheduleFetchMany should not resolve until all the records are resol store.createRecord('test'); }); - var records = Ember.A([ - store.recordForId('test', 10), - store.recordForId('phone', 20), - store.recordForId('phone', 21) - ]); + let internalModels = [ + store._internalModelForId('test', 10), + store._internalModelForId('phone', 20), + store._internalModelForId('phone', 21) + ]; run(function() { - store.scheduleFetchMany(records).then(assert.wait(function() { - var unloadedRecords = records.filterBy('isEmpty'); + store._scheduleFetchMany(internalModels).then(assert.wait(function() { + var unloadedRecords = Ember.A(internalModels.map(r => r.record)).filterBy('isEmpty'); + assert.equal(get(unloadedRecords, 'length'), 0, 'All unloaded records should be loaded'); })); }); @@ -722,21 +723,21 @@ test("the store calls adapter.findMany according to groupings returned by adapte test: Person }); - var records = Ember.A([ - store.recordForId('test', 10), - store.recordForId('test', 20), - store.recordForId('test', 21) - ]); + var internalModels = [ + store._internalModelForId('test', 10), + store._internalModelForId('test', 20), + store._internalModelForId('test', 21) + ]; run(function() { - store.scheduleFetchMany(records).then(assert.wait(function() { - var ids = records.mapBy('id'); + store._scheduleFetchMany(internalModels).then(assert.wait(function() { + var ids = Ember.A(internalModels).mapBy('id'); assert.deepEqual(ids, ["10", "20", "21"], "The promise fulfills with the records"); })); }); }); -test("the promise returned by `scheduleFetch`, when it resolves, does not depend on the promises returned to other calls to `scheduleFetch` that are in the same run loop, but different groups", function(assert) { +test("the promise returned by `_scheduleFetch`, when it resolves, does not depend on the promises returned to other calls to `_scheduleFetch` that are in the same run loop, but different groups", function(assert) { assert.expect(2); var Person = DS.Model.extend(); @@ -785,7 +786,7 @@ test("the promise returned by `scheduleFetch`, when it resolves, does not depend }); }); -test("the promise returned by `scheduleFetch`, when it rejects, does not depend on the promises returned to other calls to `scheduleFetch` that are in the same run loop, but different groups", function(assert) { +test("the promise returned by `_scheduleFetch`, when it rejects, does not depend on the promises returned to other calls to `_scheduleFetch` that are in the same run loop, but different groups", function(assert) { assert.expect(2); var Person = DS.Model.extend(); @@ -834,7 +835,7 @@ test("the promise returned by `scheduleFetch`, when it rejects, does not depend }); }); -test("store.fetchRecord reject records that were not found, even when those requests were coalesced with records that were found", function(assert) { +test("store._fetchRecord reject records that were not found, even when those requests were coalesced with records that were found", function(assert) { assert.expect(2); var Person = DS.Model.extend(); @@ -872,7 +873,7 @@ test("store.fetchRecord reject records that were not found, even when those requ }); }); -testInDebug("store.fetchRecord warns when records are missing", function(assert) { +testInDebug("store._fetchRecord warns when records are missing", function(assert) { var Person = DS.Model.extend(); var adapter = TestAdapter.extend({ From e7b19a58c1d8fee346b6aad5f21fae74a91d9cca Mon Sep 17 00:00:00 2001 From: Christopher Gammie Date: Mon, 31 Oct 2016 11:47:52 +0000 Subject: [PATCH 1685/2527] [DOC ds-extended-errors] Add docs for extended errors --- addon/adapters/errors.js | 173 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/addon/adapters/errors.js b/addon/adapters/errors.js index 23cbed79dcb..5594ccd8920 100644 --- a/addon/adapters/errors.js +++ b/addon/adapters/errors.js @@ -9,6 +9,69 @@ const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/; const PRIMARY_ATTRIBUTE_KEY = 'base'; /** + A `DS.AdapterError` is used by an adapter to signal that an error occurred + during a request to an external API. It indicates a generic error, and + subclasses are used to indicate specific error states. The following + subclasses are provided: + + - `DS.InvalidError` + - `DS.TimeoutError` + - `DS.AbortError` + - `DS.UnauthorizedError` + - `DS.ForbiddenError` + - `DS.NotFoundError` + - `DS.ConflictError` + - `DS.ServerError` + + To create a custom error to signal a specific error state in communicating + with an external API, extend the `DS.AdapterError`. For example if the + external API exclusively used HTTP `503 Service Unavailable` to indicate + it was closed for maintenance: + + ```app/adapters/maintenance-error.js + import DS from 'ember-data'; + + export default DS.AdapterError.extend({ message: "Down for maintenance." }); + ``` + + This error would then be returned by an adapter's `handleResponse` method: + + ```app/adapters/application.js + import DS from 'ember-data'; + import MaintenanceError from './maintenance-error'; + + export default DS.JSONAPIAdapter.extend({ + handleResponse(status) { + if (503 === status) { + return new MaintenanceError(); + } + + return this._super(...arguments); + } + }); + ``` + + And can then be detected in an application and used to send the user to an + `under-maintenance` route: + + ```app/routes/application.js + import Ember from 'ember'; + import MaintenanceError from '../adapters/maintenance-error'; + + export default Ember.Route.extend({ + actions: { + error(error, transition) { + if (error instanceof MaintenanceError) { + this.transitionTo('under-maintenance'); + return; + } + + // ...other error handling logic + } + } + }); + ``` + @class AdapterError @namespace DS */ @@ -117,6 +180,34 @@ export const InvalidError = extend(AdapterError, 'The adapter rejected the commit because it was invalid'); /** + A `DS.TimeoutError` is used by an adapter to signal that a request + to the external API has timed out. I.e. no response was received from + the external API within an allowed time period. + + An example use case would be to warn the user to check their internet + connection if an adapter operation has timed out: + + ```app/routes/application.js + import Ember from 'ember'; + import DS from 'ember-data'; + + const { TimeoutError } = DS; + + export default Ember.Route.extend({ + actions: { + error(error, transition) { + if (error instanceof TimeoutError) { + // alert the user + alert('Are you still connected to the internet?'); + return; + } + + // ...other error handling logic + } + } + }); + ``` + @class TimeoutError @namespace DS */ @@ -124,6 +215,11 @@ export const TimeoutError = extend(AdapterError, 'The adapter operation timed out'); /** + A `DS.AbortError` is used by an adapter to signal that a request to + the external API was aborted. For example, this can occur if the user + navigates away from the current page after a request to the external API + has been initiated but before a response has been received. + @class AbortError @namespace DS */ @@ -131,6 +227,35 @@ export const AbortError = extend(AdapterError, 'The adapter operation was aborted'); /** + A `DS.UnauthorizedError` equates to a HTTP `401 Unauthorized` response + status. It is used by an adapter to signal that a request to the external + API was rejected because authorization is required and has failed or has not + yet been provided. + + An example use case would be to redirect the user to a log in route if a + request is unauthorized: + + ```app/routes/application.js + import Ember from 'ember'; + import DS from 'ember-data'; + + const { UnauthorizedError } = DS; + + export default Ember.Route.extend({ + actions: { + error(error, transition) { + if (error instanceof UnauthorizedError) { + // go to the sign in route + this.transitionTo('login'); + return; + } + + // ...other error handling logic + } + } + }); + ``` + @class UnauthorizedError @namespace DS */ @@ -138,6 +263,12 @@ export const UnauthorizedError = extendedErrorsEnabled ? extend(AdapterError, 'The adapter operation is unauthorized') : null; /** + A `DS.ForbiddenError` equates to a HTTP `403 Forbidden` response status. + It is used by an adapter to signal that a request to the external API was + valid but the server is refusing to respond to it. If authorization was + provided and is valid, then the authenticated user does not have the + necessary permissions for the request. + @class ForbiddenError @namespace DS */ @@ -145,6 +276,38 @@ export const ForbiddenError = extendedErrorsEnabled ? extend(AdapterError, 'The adapter operation is forbidden') : null; /** + A `DS.NotFoundError` equates to a HTTP `404 Not Found` response status. + It is used by an adapter to signal that a request to the external API + was rejected because the resource could not be found on the API. + + An example use case would be to detect if the user has entered a route + for a specific model that does not exist. For example: + + ```app/routes/post.js + import Ember from 'ember'; + import DS from 'ember-data'; + + const { NotFoundError } = DS; + + export default Ember.Route.extend({ + model(params) { + return this.get('store').findRecord('post', params.post_id); + }, + + actions: { + error(error, transition) { + if (error instanceof NotFoundError) { + // redirect to a list of all posts instead + this.transitionTo('posts'); + } else { + // otherwise let the error bubble + return true; + } + } + } + }); + ``` + @class NotFoundError @namespace DS */ @@ -152,6 +315,12 @@ export const NotFoundError = extendedErrorsEnabled ? extend(AdapterError, 'The adapter could not find the resource') : null; /** + A `DS.ConflictError` equates to a HTTP `409 Conflict` response status. + It is used by an adapter to indicate that the request could not be processed + because of a conflict in the request. An example scenario would be when + creating a record with a client generated id but that id is already known + to the external API. + @class ConflictError @namespace DS */ @@ -159,6 +328,10 @@ export const ConflictError = extendedErrorsEnabled ? extend(AdapterError, 'The adapter operation failed due to a conflict') : null; /** + A `DS.ServerError` equates to a HTTP `500 Internal Server Error` response + status. It is used by the adapter to indicate that a request has failed + because of an error in the external API. + @class ServerError @namespace DS */ From 2455f7164e40554b9d2ae59294349dbf3cadc6bc Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 9 Nov 2016 16:37:05 -0500 Subject: [PATCH 1686/2527] Simplify Adapter#serialize by using snapshot.serialize() since they duplicate the same logic --- addon/adapter.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addon/adapter.js b/addon/adapter.js index 5772e6170be..9999a596a68 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -3,7 +3,6 @@ */ import Ember from 'ember'; -var get = Ember.get; /** An adapter is an object that receives requests from a store and @@ -276,7 +275,7 @@ export default Ember.Object.extend({ @return {Object} serialized snapshot */ serialize(snapshot, options) { - return get(snapshot.record, 'store').serializerFor(snapshot.modelName).serialize(snapshot, options); + return snapshot.serialize(options) }, /** From d83de4f7cfb44fdc7bc3ce945e62754f6488c22a Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 10 Nov 2016 19:36:24 -0800 Subject: [PATCH 1687/2527] build ember-data attribute debug info dynamically * allow other relationship types to be first-class and not crash the inspector * improve tests --- addon/-private/system/debug/debug-info.js | 47 +++++------ addon/-private/system/relationship-meta.js | 1 + .../system/relationships/belongs-to.js | 1 + .../-private/system/relationships/has-many.js | 1 + tests/unit/debug-test.js | 81 +++++++++++++++++++ 5 files changed, 108 insertions(+), 23 deletions(-) diff --git a/addon/-private/system/debug/debug-info.js b/addon/-private/system/debug/debug-info.js index f570f261de0..bebc89c38e7 100644 --- a/addon/-private/system/debug/debug-info.js +++ b/addon/-private/system/debug/debug-info.js @@ -19,39 +19,40 @@ export default Ember.Mixin.create({ @private */ _debugInfo() { - var attributes = ['id']; - var relationships = { belongsTo: [], hasMany: [] }; - var expensiveProperties = []; + let attributes = ['id']; + let relationships = { }; + let expensiveProperties = []; this.eachAttribute((name, meta) => attributes.push(name)); - this.eachRelationship((name, relationship) => { - relationships[relationship.kind].push(name); - expensiveProperties.push(name); - }); - - var groups = [ + let groups = [ { name: 'Attributes', properties: attributes, expand: true - }, - { - name: 'Belongs To', - properties: relationships.belongsTo, - expand: true - }, - { - name: 'Has Many', - properties: relationships.hasMany, - expand: true - }, - { - name: 'Flags', - properties: ['isLoaded', 'hasDirtyAttributes', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'] } ]; + this.eachRelationship((name, relationship) => { + let properties = relationships[relationship.kind]; + + if (properties === undefined) { + properties = relationships[relationship.kind] = []; + groups.push({ + name: relationship.name, + properties, + expand: true + }); + } + properties.push(name); + expensiveProperties.push(name); + }); + + groups.push({ + name: 'Flags', + properties: ['isLoaded', 'hasDirtyAttributes', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'] + }); + return { propertyInfo: { // include all other mixins / properties (not just the grouped ones) diff --git a/addon/-private/system/relationship-meta.js b/addon/-private/system/relationship-meta.js index fcfeb19488e..356a155c120 100644 --- a/addon/-private/system/relationship-meta.js +++ b/addon/-private/system/relationship-meta.js @@ -17,6 +17,7 @@ export function relationshipFromMeta(meta) { kind: meta.kind, type: typeForRelationshipMeta(meta), options: meta.options, + name: meta.name, parentType: meta.parentType, isRelationship: true }; diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 59d9ca468f4..15a9d875409 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -97,6 +97,7 @@ export default function belongsTo(modelName, options) { isRelationship: true, options: opts, kind: 'belongsTo', + name: 'Belongs To', key: null }; diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index 8cf881730d3..cd2848cf386 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -137,6 +137,7 @@ export default function hasMany(type, options) { isRelationship: true, options: options, kind: 'hasMany', + name: 'Has Many', key: null }; diff --git a/tests/unit/debug-test.js b/tests/unit/debug-test.js index e74ef60f79b..97db31f7898 100644 --- a/tests/unit/debug-test.js +++ b/tests/unit/debug-test.js @@ -46,3 +46,84 @@ test("_debugInfo groups the attributes and relationships correctly", function(as assert.deepEqual(propertyInfo.groups[1].properties, ['maritalStatus']); assert.deepEqual(propertyInfo.groups[2].properties, ['posts']); }); + + +test("_debugInfo supports arbitray relationship types", function(assert) { + let MaritalStatus = DS.Model.extend({ + name: DS.attr('string') + }); + + let Post = DS.Model.extend({ + title: DS.attr('string') + }); + + let User = DS.Model.extend({ + name: DS.attr('string'), + isDrugAddict: DS.attr('boolean'), + maritalStatus: DS.belongsTo('marital-status', { async: false }), + posts: Ember.computed(() => [1, 2, 3] ) + .readOnly().meta({ + options: { inverse: null }, + isRelationship: true, + kind: 'customRelationship', + name: 'Custom Relationship' + }) + }); + + let store = createStore({ + adapter: TestAdapter.extend(), + maritalStatus: MaritalStatus, + post: Post, + user: User + }); + + let record = run(() => store.createRecord('user')); + + let propertyInfo = record._debugInfo().propertyInfo; + + assert.deepEqual(propertyInfo, { + includeOtherProperties: true, + groups: [ + { + name: 'Attributes', + properties: [ + 'id', + 'name', + 'isDrugAddict' + ], + expand: true + }, + { + name: 'Belongs To', + properties: [ + 'maritalStatus' + ], + expand: true + }, + { + name: 'Custom Relationship', + properties: [ + 'posts' + ], + expand: true + }, + { + name: 'Flags', + properties: [ + 'isLoaded', + 'hasDirtyAttributes', + 'isSaving', + 'isDeleted', + 'isError', + 'isNew', + 'isValid' + ] + } + ], + expensiveProperties: [ + 'maritalStatus', + 'posts' + ] + } + ) +}); From 0af1903e9a4d8047996a8eec7f153fe7993bc312 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 11 Nov 2016 13:57:33 -0800 Subject: [PATCH 1688/2527] [PERF] HasMany doesn't need to inform RecordArrayManager At one point, relationships were managed by the recordArrayManager, this is no longer true. But we still spuriously inform the manager when we flush a relationship --- addon/-private/system/many-array.js | 1 - 1 file changed, 1 deletion(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 7810fa5b72f..0b27136e542 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -174,7 +174,6 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { //TODO(Igor) probably needed only for unloaded records this.relationship.notifyHasManyChanged(); } - this.record.updateRecordArrays(); }, //TODO(Igor) optimize From 0e3f803f751bfebb58cee33e7bc80a21c35171eb Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 11 Nov 2016 14:05:23 -0800 Subject: [PATCH 1689/2527] cleanup system/many-array * ensure shape is stable * use tidier ES6 syntax when appropriate --- addon/-private/system/many-array.js | 165 +++++++++++++--------------- 1 file changed, 79 insertions(+), 86 deletions(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 7810fa5b72f..a77b44ee572 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -6,8 +6,7 @@ import { assert } from "ember-data/-private/debug"; import { PromiseArray } from "ember-data/-private/system/promise-proxies"; import { _objectIsAlive } from "ember-data/-private/system/store/common"; -var get = Ember.get; -var set = Ember.set; +const { get, set } = Ember; /** A `ManyArray` is a `MutableArray` that represents the contents of a has-many @@ -55,74 +54,25 @@ var set = Ember.set; export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { init() { this._super(...arguments); - this.currentState = Ember.A([]); - this.flushCanonical(); - }, - - record: null, - - canonicalState: null, - currentState: null, - - length: 0, - - objectAt(index) { - //Ember observers such as 'firstObject', 'lastObject' might do out of bounds accesses - if (!this.currentState[index]) { - return undefined; - } - - return this.currentState[index].getRecord(); - }, - - flushCanonical() { - let toSet = this.canonicalState; - - //a hack for not removing new records - //TODO remove once we have proper diffing - let newRecords = this.currentState.filter( - // only add new records which are not yet in the canonical state of this - // relationship (a new record can be in the canonical state if it has - // been 'acknowleged' to be in the relationship via a store.push) - (internalModel) => internalModel.isNew() && toSet.indexOf(internalModel) === -1 - ); - toSet = toSet.concat(newRecords); - let oldLength = this.length; - this.arrayContentWillChange(0, this.length, toSet.length); - // It’s possible the parent side of the relationship may have been unloaded by this point - if (_objectIsAlive(this)) { - this.set('length', toSet.length); - } - this.currentState = toSet; - this.arrayContentDidChange(0, oldLength, this.length); - //TODO Figure out to notify only on additions and maybe only if unloaded - this.relationship.notifyHasManyChanged(); - this.record.updateRecordArrays(); - }, - /** - `true` if the relationship is polymorphic, `false` otherwise. - @property {Boolean} isPolymorphic - @private - */ - isPolymorphic: false, - - /** + /** The loading state of this array @property {Boolean} isLoaded - */ - isLoaded: false, + */ + this.isLoaded = false; + this.length = 0; - /** - The relationship which manages this array. + /** + Used for async `hasMany` arrays + to keep track of when they will resolve. - @property {ManyRelationship} relationship + @property {Ember.RSVP.Promise} promise @private - */ - relationship: null, + */ + this.promise = null; - /** + /** Metadata associated with the request for async hasMany relationships. Example @@ -136,7 +86,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { "id": 1, "comment": "This is the first comment", }, { - // ... + // ... }], "meta": { @@ -152,15 +102,68 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { post.get('comments').then(function(comments) { var meta = comments.get('meta'); - // meta.page => 1 - // meta.total => 5 + // meta.page => 1 + // meta.total => 5 }); ``` @property {Object} meta @public - */ - meta: null, + */ + this.meta = this.meta || null; + + /** + `true` if the relationship is polymorphic, `false` otherwise. + + @property {Boolean} isPolymorphic + @private + */ + this.isPolymorphic = this.isPolymorphic || false; + + /** + The relationship which manages this array. + + @property {ManyRelationship} relationship + @private + */ + this.relationship = this.relationship || null; + + this.currentState = Ember.A([]); + this.flushCanonical(); + }, + + objectAt(index) { + //Ember observers such as 'firstObject', 'lastObject' might do out of bounds accesses + if (!this.currentState[index]) { + return undefined; + } + + return this.currentState[index].getRecord(); + }, + + flushCanonical() { + let toSet = this.canonicalState; + + //a hack for not removing new records + //TODO remove once we have proper diffing + let newRecords = this.currentState.filter( + // only add new records which are not yet in the canonical state of this + // relationship (a new record can be in the canonical state if it has + // been 'acknowleged' to be in the relationship via a store.push) + (internalModel) => internalModel.isNew() && toSet.indexOf(internalModel) === -1 + ); + toSet = toSet.concat(newRecords); + let oldLength = this.length; + this.arrayContentWillChange(0, this.length, toSet.length); + // It’s possible the parent side of the relationship may have been unloaded by this point + if (_objectIsAlive(this)) { + this.set('length', toSet.length); + } + this.currentState = toSet; + this.arrayContentDidChange(0, oldLength, this.length); + //TODO Figure out to notify only on additions and maybe only if unloaded + this.relationship.notifyHasManyChanged(); + }, internalReplace(idx, amt, objects) { if (!objects) { @@ -179,9 +182,8 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { //TODO(Igor) optimize internalRemoveRecords(records) { - var index; - for (var i=0; i < records.length; i++) { - index = this.currentState.indexOf(records[i]); + for (let i=0; i < records.length; i++) { + let index = this.currentState.indexOf(records[i]); this.internalReplace(index, 1); } }, @@ -195,23 +197,15 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { }, replace(idx, amt, objects) { - var records; + let records; if (amt > 0) { records = this.currentState.slice(idx, idx+amt); this.get('relationship').removeRecords(records); } if (objects) { - this.get('relationship').addRecords(objects.map((obj) => obj._internalModel), idx); + this.get('relationship').addRecords(objects.map(obj => obj._internalModel), idx); } }, - /** - Used for async `hasMany` arrays - to keep track of when they will resolve. - - @property {Ember.RSVP.Promise} promise - @private - */ - promise: null, /** @method loadingRecordsCount @@ -262,11 +256,10 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { @return {DS.PromiseArray} promise */ save() { - var manyArray = this; - var promiseLabel = "DS: ManyArray#save " + get(this, 'type'); - var promise = Ember.RSVP.all(this.invoke("save"), promiseLabel).then(function(array) { - return manyArray; - }, null, "DS: ManyArray#save return ManyArray"); + let manyArray = this; + let promiseLabel = 'DS: ManyArray#save ' + get(this, 'type'); + let promise = Ember.RSVP.all(this.invoke("save"), promiseLabel). + then(() => manyArray, null, 'DS: ManyArray#save return ManyArray'); return PromiseArray.create({ promise }); }, @@ -284,7 +277,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { var type = get(this, 'type'); var record; - assert("You cannot add '" + type.modelName + "' records to this polymorphic relationship.", !get(this, 'isPolymorphic')); + assert(`You cannot add '${type.modelName}' records to this polymorphic relationship.`, !get(this, 'isPolymorphic')); record = store.createRecord(type.modelName, hash); this.pushObject(record); From b3e1d67899b06b051a0cc2c12635998215ad6621 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 11 Nov 2016 12:54:57 -0800 Subject: [PATCH 1690/2527] [BUGFIX #4649 #4648] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * no longer invalid relationships property when accessing it the first time #4649 * no longer duplicate “notifyHasManyChange” when adding a record fixes #4648 No longer warn/error in glimmer 2 by accidentally causing duplicate work. --- addon/-private/system/many-array.js | 15 +++++++-------- tests/unit/model/relationships/has-many-test.js | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 8501010f9df..a79d590ee24 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -129,7 +129,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { this.relationship = this.relationship || null; this.currentState = Ember.A([]); - this.flushCanonical(); + this.flushCanonical(false); }, objectAt(index) { @@ -141,7 +141,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { return this.currentState[index].getRecord(); }, - flushCanonical() { + flushCanonical(isInitialized = true) { let toSet = this.canonicalState; //a hack for not removing new records @@ -161,8 +161,11 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { } this.currentState = toSet; this.arrayContentDidChange(0, oldLength, this.length); - //TODO Figure out to notify only on additions and maybe only if unloaded - this.relationship.notifyHasManyChanged(); + + if (isInitialized) { + //TODO Figure out to notify only on additions and maybe only if unloaded + this.relationship.notifyHasManyChanged(); + } }, internalReplace(idx, amt, objects) { @@ -173,10 +176,6 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { this.currentState.splice.apply(this.currentState, [idx, amt].concat(objects)); this.set('length', this.currentState.length); this.arrayContentDidChange(idx, amt, objects.length); - if (objects) { - //TODO(Igor) probably needed only for unloaded records - this.relationship.notifyHasManyChanged(); - } }, //TODO(Igor) optimize diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index db8d92ebb34..57bf2f9dabb 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -770,9 +770,13 @@ test("DS.hasMany is async by default", function(assert) { }); test("DS.ManyArray is lazy", function(assert) { + let peopleDidChange = 0; let Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.hasMany('person') + people: DS.hasMany('person'), + peopleDidChange: Ember.observer('people', function() { + peopleDidChange++; + }) }); let Person = DS.Model.extend({ @@ -787,9 +791,20 @@ test("DS.ManyArray is lazy", function(assert) { let hasManyRelationship = tag.hasMany('people').hasManyRelationship; assert.ok(!hasManyRelationship._manyArray); run(function() { + assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (before access)'); tag.get('people'); + assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (sync after access)'); }); + assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (after access, but after the current run loop)'); assert.ok(hasManyRelationship._manyArray instanceof DS.ManyArray); + + let person = Ember.run(() => env.store.createRecord('person')); + + Ember.run(() => { + assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (before access)'); + tag.get('people').addObject(person); + assert.equal(peopleDidChange, 1, 'expect people hasMany to have changed exactly once'); + }); }); testInDebug("throws assertion if of not set with an array", function(assert) { From 000b1e88463592747411a1e140ffb8deac7d4e1e Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 11 Nov 2016 20:21:08 -0800 Subject: [PATCH 1691/2527] remove Ember.K usage from state/relationship.js (#4647) * remove Ember.K usage from state/relationship.js * Update relationship.js --- addon/-private/system/relationships/state/relationship.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 9ba41caabb1..651eed61162 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -1,5 +1,4 @@ /* global heimdall */ -import Ember from 'ember'; import { assert, warn } from "ember-data/-private/debug"; import OrderedSet from "ember-data/-private/system/ordered-set"; @@ -74,7 +73,7 @@ export default function Relationship(store, record, inverseKey, relationshipMeta Relationship.prototype = { constructor: Relationship, - destroy: Ember.K, + destroy() { }, updateMeta(meta) { heimdall.increment(updateMeta); @@ -285,8 +284,8 @@ Relationship.prototype = { this.setHasLoaded(true); }, - notifyRecordRelationshipAdded: Ember.K, - notifyRecordRelationshipRemoved: Ember.K, + notifyRecordRelationshipAdded() { }, + notifyRecordRelationshipRemoved() { }, /* `hasData` for a relationship is a flag to indicate if we consider the From 3f4ae526a086dcb42c9bb0f60758c9769ea41feb Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 15 Nov 2016 09:27:04 -0800 Subject: [PATCH 1692/2527] [PERF] fix sub-optimal compiler output (#4655) * [PERF] fix sub-optimal compiler output given: ```js let [a, b] = thing; ``` If it is not statically known to babel, it will assume an iterator may be present. At which the following code is omitted. ```js var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = [];var _n = true;var _d = false;var _e = undefined;try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value);if (i && _arr.length === i) break; } } catch (err) { _d = true;_e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } }return _arr; }return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; })(); ``` * Update internal-model.js --- addon/-private/system/model/internal-model.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index a3ce1f81a7b..a329db3c476 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -464,7 +464,9 @@ export default class InternalModel { for (let i = 0, length = changedAttributeNames.length; i < length; i++) { let attribute = changedAttributeNames[i]; - let [oldData, newData] = changedAttributes[attribute]; + let data = changedAttributes[attribute]; + let oldData = data[0]; + let newData = data[1]; if (oldData === newData) { delete attrs[attribute]; From 0f8fb7a0ffa12463ca82ca43d1cf169e4fc29504 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 14 Nov 2016 17:18:27 -0500 Subject: [PATCH 1693/2527] Update the API docs on the JSONAPISerializer --- addon/serializers/json-api.js | 59 +++++++---------------------------- 1 file changed, 11 insertions(+), 48 deletions(-) diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index d562b43b8fa..295266c2f55 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -283,12 +283,6 @@ const JSONAPISerializer = JSONSerializer.extend({ return normalized; }, - /** - @method extractAttributes - @param {DS.Model} modelClass - @param {Object} resourceHash - @return {Object} - */ extractAttributes(modelClass, resourceHash) { var attributes = {}; @@ -309,11 +303,6 @@ const JSONAPISerializer = JSONSerializer.extend({ return attributes; }, - /** - @method extractRelationship - @param {Object} relationshipHash - @return {Object} - */ extractRelationship(relationshipHash) { if (Ember.typeOf(relationshipHash.data) === 'object') { @@ -334,12 +323,6 @@ const JSONAPISerializer = JSONSerializer.extend({ return relationshipHash; }, - /** - @method extractRelationships - @param {Object} modelClass - @param {Object} resourceHash - @return {Object} - */ extractRelationships(modelClass, resourceHash) { let relationships = {}; @@ -391,6 +374,12 @@ const JSONAPISerializer = JSONSerializer.extend({ }, /** + Dasherizes and singularizes the model name in the payload to match + the format Ember Data uses internally for the model name. + + For example the key `posts` would be converted to `post` and the + key `studentAssesments` would be converted to `student-assesment`. + @method modelNameFromPayloadKey @param {String} key @return {String} the model's modelName @@ -401,6 +390,11 @@ const JSONAPISerializer = JSONSerializer.extend({ }, /** + Converts the model name to a pluralized version of the model name. + + For example `post` would be converted to `posts` and + `student-assesment` would be converted to `student-assesments`. + @method payloadKeyFromModelName @param {String} modelName @return {String} @@ -410,12 +404,6 @@ const JSONAPISerializer = JSONSerializer.extend({ return pluralize(modelName); }, - /** - @method normalize - @param {DS.Model} modelClass - @param {Object} resourceHash the resource hash from the adapter - @return {Object} the normalized resource hash - */ normalize(modelClass, resourceHash) { if (resourceHash.attributes) { this.normalizeUsingDeclaredMapping(modelClass, resourceHash.attributes); @@ -497,12 +485,6 @@ const JSONAPISerializer = JSONSerializer.extend({ return dasherize(key); }, - /** - @method serialize - @param {DS.Snapshot} snapshot - @param {Object} options - @return {Object} json - */ serialize(snapshot, options) { let data = this._super(...arguments); @@ -527,13 +509,6 @@ const JSONAPISerializer = JSONSerializer.extend({ return { data }; }, - /** - @method serializeAttribute - @param {DS.Snapshot} snapshot - @param {Object} json - @param {String} key - @param {Object} attribute - */ serializeAttribute(snapshot, json, key, attribute) { const type = attribute.type; @@ -556,12 +531,6 @@ const JSONAPISerializer = JSONSerializer.extend({ } }, - /** - @method serializeBelongsTo - @param {DS.Snapshot} snapshot - @param {Object} json - @param {Object} relationship - */ serializeBelongsTo(snapshot, json, relationship) { var key = relationship.key; @@ -607,12 +576,6 @@ const JSONAPISerializer = JSONSerializer.extend({ } }, - /** - @method serializeHasMany - @param {DS.Snapshot} snapshot - @param {Object} json - @param {Object} relationship - */ serializeHasMany(snapshot, json, relationship) { var key = relationship.key; var shouldSerializeHasMany = '_shouldSerializeHasMany'; From 55c34ed02c894cff24b04ed62dc0303ad6833b37 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 14 Nov 2016 16:38:21 -0500 Subject: [PATCH 1694/2527] Improve the API docs for the JSONAPI adapter --- addon/adapters/json-api.js | 161 ++++++++++++++++++++++++++++++++----- 1 file changed, 139 insertions(+), 22 deletions(-) diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index d9c05921484..50605632301 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -9,6 +9,135 @@ import isEnabled from 'ember-data/-private/features'; import { instrument, deprecate } from 'ember-data/-private/debug'; /** + The `JSONAPIAdapter` is the default adapter used by Ember Data. It + is responsible for transforming the store's requests into HTTP + requests that follow the [JSON API](http://jsonapi.org/format/) + format. + + ## JSON API Conventions + + The JSONAPIAdapter uses JSON API conventions for building the url + for a record and selecting the HTTP verb to use with a request. The + actions you can take on a record map onto the following URLs in the + JSON API adapter: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + Action + + HTTP Verb + + URL +
      + `store.findRecord('post', 123)` + + GET + + /posts/123 +
      + `store.findAll('post')` + + GET + + /posts +
      + Update `postRecord.save()` + + PATCH + + /posts/123 +
      + Create `store.createRecord('post').save()` + + POST + + /posts +
      + Delete `postRecord.destroyRecord()` + + DELETE + + /posts/123 +
      + + ## Success and failure + + The JSONAPIAdapter will consider a success any response with a + status code of the 2xx family ("Success"), as well as 304 ("Not + Modified"). Any other status code will be considered a failure. + + On success, the request promise will be resolved with the full + response payload. + + Failed responses with status code 422 ("Unprocessable Entity") will + be considered "invalid". The response will be discarded, except for + the `errors` key. The request promise will be rejected with a + `DS.InvalidError`. This error object will encapsulate the saved + `errors` value. + + Any other status codes will be treated as an adapter error. The + request promise will be rejected, similarly to the invalid case, + but with an instance of `DS.AdapterError` instead. + + ### Endpoint path customization + + Endpoint paths can be prefixed with a `namespace` by setting the + namespace property on the adapter: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.JSONAPIAdapter.extend({ + namespace: 'api/1' + }); + ``` + Requests for the `person` model would now target `/api/1/people/1`. + + ### Host customization + + An adapter can target other hosts by setting the `host` property. + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.JSONAPIAdapter.extend({ + host: 'https://api.example.com' + }); + ``` + + Requests for the `person` model would now target + `https://api.example.com/people/1`. + @since 1.13.0 @class JSONAPIAdapter @constructor @@ -70,9 +199,17 @@ var JSONAPIAdapter = RESTAdapter.extend({ ```javascript { - post: { + data: { id: 1, - comments: [1, 2] + type: 'post', + relationship: { + comments: { + data: [ + { id: 1, type: 'comment' }, + { id: 2, type: 'comment' } + ] + } + } } } ``` @@ -109,14 +246,6 @@ var JSONAPIAdapter = RESTAdapter.extend({ */ coalesceFindRequests: false, - /** - @method findMany - @param {DS.Store} store - @param {DS.Model} type - @param {Array} ids - @param {Array} snapshots - @return {Promise} promise - */ findMany(store, type, ids, snapshots) { if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { return this._super(...arguments); @@ -126,24 +255,12 @@ var JSONAPIAdapter = RESTAdapter.extend({ } }, - /** - @method pathForType - @param {String} modelName - @return {String} path - **/ pathForType(modelName) { var dasherized = Ember.String.dasherize(modelName); return Ember.String.pluralize(dasherized); }, // TODO: Remove this once we have a better way to override HTTP verbs. - /** - @method updateRecord - @param {DS.Store} store - @param {DS.Model} type - @param {DS.Snapshot} snapshot - @return {Promise} promise - */ updateRecord(store, type, snapshot) { if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { return this._super(...arguments); From c3db94cdb453943ed5cca43d6fa5eb4858c79326 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 16 Nov 2016 08:30:12 -0800 Subject: [PATCH 1695/2527] adds tests coverage for record removal from hasMany array following deletion --- .../integration/records/delete-record-test.js | 62 ++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index e7f32523dfc..9da101ea2db 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -30,7 +30,7 @@ module("integration/deletedRecord - Deleting Records", { } }); -test("records should not be removed from record arrays just after deleting, but only after commiting them", function(assert) { +test("records should not be removed from record arrays just after deleting, but only after committing them", function(assert) { var adam, dave; env.adapter.deleteRecord = function() { @@ -72,6 +72,66 @@ test("records should not be removed from record arrays just after deleting, but assert.equal(all.get('length'), 1, '1 record in array after deleteRecord and save'); }); +test('deleting a record that is part of a hasMany removes it from the hasMany recordArray', function(assert) { + let group; + let person; + const Group = DS.Model.extend({ + people: DS.hasMany('person', { inverse: null, async: false }) + }); + + env.adapter.deleteRecord = function() { + return Ember.RSVP.Promise.resolve(); + }; + + env.registry.register('model:group', Group); + + run(function() { + env.store.push({ + data: { + type: 'group', + id: '1', + relationships: { + people: { + data: [ + { type: 'person', id: '1' }, + { type: 'person', id: '2' } + ] + } + } + }, + included: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + } + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Dave Sunderland' + } + } + ] + }); + + group = env.store.peekRecord('group', '1'); + person = env.store.peekRecord('person', '1'); + }); + + // Sanity Check we are in the correct state. + assert.equal(group.get('people.length'), 2, 'expected 2 related records before delete'); + assert.equal(person.get('name'), 'Adam Sunderland', 'expected related records to be loaded'); + + run(function() { + person.destroyRecord(); + }); + + assert.equal(group.get('people.length'), 1, 'expected 1 related records after delete'); +}); + test("records can be deleted during record array enumeration", function(assert) { var adam, dave; From 3d2362bb06056a460f1845fac643f7375e819257 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 16 Nov 2016 11:54:20 -0500 Subject: [PATCH 1696/2527] Document the relationship serialized format in the RESTAdapter --- addon/adapters/rest.js | 49 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index b87a26ff0d6..2e0aca6d111 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -67,7 +67,7 @@ const Promise = Ember.RSVP.Promise; ```js { - "post": { + "posts": { "id": 1, "title": "I'm Running to Reform the W3C's Tag", "author": "Yehuda Katz" @@ -122,7 +122,7 @@ const Promise = Ember.RSVP.Promise; ```js { - "person": { + "people": { "id": 5, "firstName": "Barack", "lastName": "Obama", @@ -131,6 +131,51 @@ const Promise = Ember.RSVP.Promise; } ``` + #### Relationships + + Relationships are usually represented by ids to the record in the + relationship. The related records can then be sideloaded in the + response under a key for the type. + + ```js + { + "posts": { + "id": 5, + "title": "I'm Running to Reform the W3C's Tag", + "author": "Yehuda Katz", + "comments": [1, 2] + }, + "comments": [{ + "id": 1, + "author": "User 1", + "message": "First!", + }, { + "id": 2, + "author": "User 2", + "message": "Good Luck!", + }] + } + ``` + + If the records in the relationship are not known when the response + is serialized its also possible to represent the relationship as a + url using the `links` key in the response. Ember Data will fetch + this url to resolve the relationship when it is accessed for the + first time. + + ```js + { + "posts": { + "id": 5, + "title": "I'm Running to Reform the W3C's Tag", + "author": "Yehuda Katz", + "links": { + "comments": "/posts/5/comments" + } + } + } + ``` + ### Errors If a response is considered a failure, the JSON payload is expected to include From 06c216d3c5e67341c8c9db12c3b1bce179d6091e Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 16 Nov 2016 10:32:10 -0800 Subject: [PATCH 1697/2527] dirty check to prevent liveRecordArrays being rebuilt too often --- addon/-private/system/record-array-manager.js | 38 ++++++++++++++----- addon/-private/system/store.js | 6 +-- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index f51e30eb3f9..a1196df38a0 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -72,7 +72,7 @@ export default Ember.Object.extend({ }); this.liveRecordArrays = MapWithDefault.create({ - defaultValue: typeClass => this.createRecordArray(typeClass) + defaultValue: modelClass => this.createRecordArray(modelClass) }); this.changedRecords = []; @@ -187,9 +187,27 @@ export default Ember.Object.extend({ } }, - populateLiveRecordArray(array, modelName) { + syncLiveRecordArray(array, modelClass) { + let hasNoPotentialDeletions = this.changedRecords.length === 0; + let typeMap = this.store.typeMapFor(modelClass); + let hasNoInsertionsOrRemovals = typeMap.records.length === array.length; + + /* + Ideally the recordArrayManager has knowledge of the changes to be applied to + liveRecordArrays, and is capable of strategically flushing those changes and applying + small diffs if desired. However, until we've refactored recordArrayManager, this dirty + check prevents us from unnecessarily wiping out live record arrays returned by peekAll. + */ + if (hasNoPotentialDeletions && hasNoInsertionsOrRemovals) { + return; + } + + this.populateLiveRecordArray(array, modelClass); + }, + + populateLiveRecordArray(array, modelClass) { heimdall.increment(populateLiveRecordArray); - let typeMap = this.store.typeMapFor(modelName); + let typeMap = this.store.typeMapFor(modelClass); let records = typeMap.records; let record; @@ -211,12 +229,12 @@ export default Ember.Object.extend({ @method updateFilter @param {Array} array - @param {String} modelName + @param {Class} modelClass @param {Function} filter */ - updateFilter(array, modelName, filter) { + updateFilter(array, modelClass, filter) { heimdall.increment(updateFilter); - let typeMap = this.store.typeMapFor(modelName); + let typeMap = this.store.typeMapFor(modelClass); let records = typeMap.records; let record; @@ -224,7 +242,7 @@ export default Ember.Object.extend({ record = records[i]; if (!record.isDeleted() && !record.isEmpty()) { - this.updateFilterRecordArray(array, filter, modelName, record); + this.updateFilterRecordArray(array, filter, modelClass, record); } } }, @@ -246,13 +264,13 @@ export default Ember.Object.extend({ Create a `DS.RecordArray` for a type. @method createRecordArray - @param {Class} typeClass + @param {Class} modelClass @return {DS.RecordArray} */ - createRecordArray(typeClass) { + createRecordArray(modelClass) { heimdall.increment(createRecordArray); return RecordArray.create({ - type: typeClass, + type: modelClass, content: Ember.A(), store: this.store, isLoaded: true, diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 3aa87f66e8f..b8bd6b66d90 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1596,10 +1596,10 @@ Store = Service.extend({ heimdall.increment(peekAll); assert("You need to pass a model name to the store's peekAll method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - var typeClass = this.modelFor(modelName); + let modelClass = this.modelFor(modelName); + let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(modelClass); - var liveRecordArray = this.recordArrayManager.liveRecordArrayFor(typeClass); - this.recordArrayManager.populateLiveRecordArray(liveRecordArray, typeClass); + this.recordArrayManager.syncLiveRecordArray(liveRecordArray, modelClass); return liveRecordArray; }, From 758ebe7991fb6e9d51fa119b08141d48e19f0252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Umpi=C3=A9rrez?= Date: Wed, 16 Nov 2016 19:34:22 +0100 Subject: [PATCH 1698/2527] Fixed link (#4660) * fixed link Changed isDirty link for hasDirtyAttributes link * Revert "fixed link" This reverts commit 48dc34a274a9dc653f2fc655cef083cb7784fc26. * fixed link Replaced isDirty link for hasDirtyAttributes link --- addon/-private/system/model/states.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index 85cecb4c06c..d4e88df0bc3 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -162,7 +162,7 @@ import { assert } from "ember-data/-private/debug"; * [isEmpty](DS.Model.html#property_isEmpty) * [isLoading](DS.Model.html#property_isLoading) * [isLoaded](DS.Model.html#property_isLoaded) - * [isDirty](DS.Model.html#property_isDirty) + * [hasDirtyAttributes](DS.Model.html#property_hasDirtyAttributes) * [isSaving](DS.Model.html#property_isSaving) * [isDeleted](DS.Model.html#property_isDeleted) * [isNew](DS.Model.html#property_isNew) From 48460072b0c869a668d7c8eeb7a9ac0c85dbcaf7 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 16 Nov 2016 17:07:52 -0800 Subject: [PATCH 1699/2527] code tidyup --- addon/-private/system/store.js | 331 ++++++++++++----------- tests/unit/store/adapter-interop-test.js | 2 +- 2 files changed, 175 insertions(+), 158 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b8bd6b66d90..fe2f6cb1a00 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -44,17 +44,28 @@ import isEnabled from 'ember-data/-private/features'; export let badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; const { + A, _Backburner: Backburner, + computed, copy, + ENV, + Error: EmberError, get, + guidFor, + inspect, isNone, isPresent, MapWithDefault, run: emberRun, set, - Service + RSVP, + Service, + typeOf } = Ember; + +const { Promise } = RSVP; + //Get the materialized model from the internalModel/promise that returns //an internal model and return it in a promiseObject. Useful for returning //from find methods @@ -64,7 +75,6 @@ function promiseRecord(internalModelPromise, label) { return promiseObject(toReturn, label); } -const Promise = Ember.RSVP.Promise; let Store; @@ -247,7 +257,7 @@ Store = Service.extend({ @param {Object} options an options hash */ serialize(record, options) { - var snapshot = record._internalModel.createSnapshot(); + let snapshot = record._internalModel.createSnapshot(); return snapshot.serialize(options); }, @@ -266,7 +276,7 @@ Store = Service.extend({ @private @return DS.Adapter */ - defaultAdapter: Ember.computed('adapter', function() { + defaultAdapter: computed('adapter', function() { let adapter = get(this, 'adapter'); assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name', typeof adapter === 'string'); @@ -293,7 +303,7 @@ Store = Service.extend({ To create a new instance of a `Post` that has a relationship with a `User` record: ```js - var user = this.store.peekRecord('user', 1); + let user = this.store.peekRecord('user', 1); store.createRecord('post', { title: "Rails is omakase", user: user @@ -308,7 +318,7 @@ Store = Service.extend({ */ createRecord(modelName, inputProperties) { assert("You need to pass a model name to the store's createRecord method", isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); let modelClass = this.modelFor(modelName); let properties = copy(inputProperties) || new EmptyObject(); @@ -356,7 +366,7 @@ Store = Service.extend({ */ _generateId(modelName, properties) { heimdall.increment(_generateId); - var adapter = this.adapterFor(modelName); + let adapter = this.adapterFor(modelName); if (adapter && adapter.generateIdForRecord) { return adapter.generateIdForRecord(this, modelName, properties); @@ -375,7 +385,7 @@ Store = Service.extend({ Example ```javascript - var post = store.createRecord('post', { + let post = store.createRecord('post', { title: "Rails is omakase" }); @@ -429,7 +439,7 @@ Store = Service.extend({ assert('Using store.find(type) has been removed. Use store.findAll(type) to retrieve all records for a given type.'); } - if (Ember.typeOf(id) === 'object') { + if (typeOf(id) === 'object') { assert('Calling store.find() with a query object is no longer supported. Use store.query() instead.'); } @@ -438,8 +448,8 @@ Store = Service.extend({ } assert("You need to pass the model name and id to the store's find method", arguments.length === 2); - assert("You cannot pass `" + Ember.inspect(id) + "` as id to the store's find method", Ember.typeOf(id) === 'string' || Ember.typeOf(id) === 'number'); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert("You cannot pass `" + inspect(id) + "` as id to the store's find method", typeOf(id) === 'string' || typeOf(id) === 'number'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); return this.findRecord(modelName, id); }, @@ -534,7 +544,7 @@ Store = Service.extend({ } }); - var blogPost = store.findRecord('post', 1).then(function(post) { + let blogPost = store.findRecord('post', 1).then(function(post) { post.get('revision'); // 1 }); @@ -646,17 +656,17 @@ Store = Service.extend({ */ findRecord(modelName, id, options) { assert("You need to pass a model name to the store's findRecord method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); assert(badIdFormatAssertion, (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id))); - var internalModel = this._internalModelForId(modelName, id); + let internalModel = this._internalModelForId(modelName, id); options = options || {}; if (!this.hasRecordForId(modelName, id)) { return this._findByInternalModel(internalModel, options); } - var fetchedInternalModel = this._findRecord(internalModel, options); + let fetchedInternalModel = this._findRecord(internalModel, options); return promiseRecord(fetchedInternalModel, "DS: Store#findRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id')); }, @@ -667,9 +677,9 @@ Store = Service.extend({ return this._scheduleFetch(internalModel, options); } - var snapshot = internalModel.createSnapshot(options); - var typeClass = internalModel.type; - var adapter = this.adapterFor(typeClass.modelName); + let snapshot = internalModel.createSnapshot(options); + let modelClass = internalModel.type; + let adapter = this.adapterFor(modelClass.modelName); // Refetch the record if the adapter thinks the record is stale if (adapter.shouldReloadRecord(this, snapshot)) { @@ -696,7 +706,7 @@ Store = Service.extend({ internalModel.preloadData(options.preload); } - var fetchedInternalModel = this._findEmptyInternalModel(internalModel, options); + let fetchedInternalModel = this._findEmptyInternalModel(internalModel, options); return promiseRecord(fetchedInternalModel, "DS: Store#findRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id')); }, @@ -726,14 +736,14 @@ Store = Service.extend({ */ findByIds(modelName, ids) { assert("You need to pass a model name to the store's findByIds method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); let promises = new Array(ids.length); for (let i = 0; i < ids.length; i++) { promises[i] = this.findRecord(modelName, ids[i]); } - return promiseArray(Ember.RSVP.all(promises).then(Ember.A, null, "DS: Store#findByIds of " + modelName + " complete")); + return promiseArray(RSVP.all(promises).then(A, null, "DS: Store#findByIds of " + modelName + " complete")); }, /** @@ -771,7 +781,7 @@ Store = Service.extend({ if (internalModel._loadingPromise) { return internalModel._loadingPromise; } let modelClass = internalModel.type; - let resolver = Ember.RSVP.defer('Fetching ' + modelClass.modelName + ' with id: ' + internalModel.id); + let resolver = RSVP.defer('Fetching ' + modelClass.modelName + ' with id: ' + internalModel.id); let pendingFetchItem = { internalModel, resolver, @@ -846,7 +856,7 @@ Store = Service.extend({ } if (missingInternalModels.length) { - warn('Ember Data expected to find records with the following ids in the adapter response but they were missing: ' + Ember.inspect(missingInternalModels.map(r => r.id)), false, { + warn('Ember Data expected to find records with the following ids in the adapter response but they were missing: ' + inspect(missingInternalModels.map(r => r.id)), false, { id: 'ds.store.missing-records-from-adapter' }); rejectInternalModels(missingInternalModels); @@ -922,17 +932,17 @@ Store = Service.extend({ Example ```javascript - var userRef = store.getReference('user', 1); + let userRef = store.getReference('user', 1); // check if the user is loaded - var isLoaded = userRef.value() !== null; + let isLoaded = userRef.value() !== null; // get the record of the reference (null if not yet available) - var user = userRef.value(); + let user = userRef.value(); // get the identifier of the reference if (userRef.remoteType() === "id") { - var id = userRef.id(); + let id = userRef.id(); } // load user (via store.find) @@ -967,7 +977,7 @@ Store = Service.extend({ _Note: This is an synchronous method and does not return a promise._ ```js - var post = store.peekRecord('post', 1); + let post = store.peekRecord('post', 1); post.get('id'); // 1 ``` @@ -981,7 +991,7 @@ Store = Service.extend({ peekRecord(modelName, id) { heimdall.increment(peekRecord); assert("You need to pass a model name to the store's peekRecord method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); if (this.hasRecordForId(modelName, id)) { return this._internalModelForId(modelName, id).getRecord(); } else { @@ -1001,10 +1011,11 @@ Store = Service.extend({ @param {DS.Model} internalModel @return {Promise} promise */ + // TODO @runspired this should be underscored reloadRecord(internalModel) { - var modelName = internalModel.type.modelName; - var adapter = this.adapterFor(modelName); - var id = internalModel.id; + let modelName = internalModel.type.modelName; + let adapter = this.adapterFor(modelName); + let id = internalModel.id; assert("You cannot reload a record without an ID", id); assert("You tried to reload a record but you have no adapter (for " + modelName + ")", adapter); @@ -1023,10 +1034,12 @@ Store = Service.extend({ */ hasRecordForId(modelName, inputId) { assert("You need to pass a model name to the store's hasRecordForId method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - let modelClass = this.modelFor(modelName); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + let id = coerceId(inputId); + let modelClass = this.modelFor(modelName); let internalModel = this.typeMapFor(modelClass).idToRecord[id]; + return !!internalModel && internalModel.isLoaded(); }, @@ -1042,7 +1055,7 @@ Store = Service.extend({ */ recordForId(modelName, id) { assert("You need to pass a model name to the store's recordForId method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); return this._internalModelForId(modelName, id).getRecord(); }, @@ -1098,7 +1111,7 @@ Store = Service.extend({ @return {Promise} promise */ findHasMany(owner, link, relationship) { - var adapter = this.adapterFor(owner.type.modelName); + let adapter = this.adapterFor(owner.type.modelName); assert("You tried to load a hasMany relationship but you have no adapter (for " + owner.type + ")", adapter); assert("You tried to load a hasMany relationship from a specified `link` in the original payload but your adapter does not implement `findHasMany`", typeof adapter.findHasMany === 'function'); @@ -1115,7 +1128,7 @@ Store = Service.extend({ @return {Promise} promise */ findBelongsTo(owner, link, relationship) { - var adapter = this.adapterFor(owner.type.modelName); + let adapter = this.adapterFor(owner.type.modelName); assert("You tried to load a belongsTo relationship but you have no adapter (for " + owner.type + ")", adapter); assert("You tried to load a belongsTo relationship from a specified `link` in the original payload but your adapter does not implement `findBelongsTo`", typeof adapter.findBelongsTo === 'function'); @@ -1181,17 +1194,18 @@ Store = Service.extend({ let token = heimdall.start('store._query'); assert("You need to pass a model name to the store's query method", isPresent(modelName)); assert("You need to pass a query hash to the store's query method", query); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - var typeClass = this.modelFor(modelName); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + let modelClass = this.modelFor(modelName); + array = array || this.recordArrayManager - .createAdapterPopulatedRecordArray(typeClass, query); + .createAdapterPopulatedRecordArray(modelClass, query); - var adapter = this.adapterFor(modelName); + let adapter = this.adapterFor(modelName); - assert("You tried to load a query but you have no adapter (for " + typeClass + ")", adapter); + assert("You tried to load a query but you have no adapter (for " + modelClass.modelName + ")", adapter); assert("You tried to load a query but your adapter does not implement `query`", typeof adapter.query === 'function'); - let pA = promiseArray(_query(adapter, this, typeClass, query, array)); + let pA = promiseArray(_query(adapter, this, modelClass, query, array)); instrument(() => { pA.finally(() => { heimdall.stop(token); }); }); @@ -1294,10 +1308,10 @@ Store = Service.extend({ queryRecord(modelName, query) { assert("You need to pass a model name to the store's queryRecord method", isPresent(modelName)); assert("You need to pass a query hash to the store's queryRecord method", query); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); - var modelClass = this.modelFor(modelName); - var adapter = this.adapterFor(modelName); + let modelClass = this.modelFor(modelName); + let adapter = this.adapterFor(modelName); assert("You tried to make a query but you have no adapter (for " + modelName + ")", adapter); assert("You tried to make a query but your adapter does not implement `queryRecord`", typeof adapter.queryRecord === 'function'); @@ -1390,7 +1404,7 @@ Store = Service.extend({ } }); - var allAuthors; + let allAuthors; store.findAll('author').then(function(authors) { authors.getEach('id'); // ['first'] @@ -1504,12 +1518,11 @@ Store = Service.extend({ */ findAll(modelName, options) { assert("You need to pass a model name to the store's findAll method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); let token = heimdall.start('store.findAll'); + let modelClass = this.modelFor(modelName); - var typeClass = this.modelFor(modelName); - - let fetch = this._fetchAll(typeClass, this.peekAll(modelName), options); + let fetch = this._fetchAll(modelClass, this.peekAll(modelName), options); instrument(() => { fetch.finally(() => { heimdall.stop(token); }); @@ -1521,28 +1534,29 @@ Store = Service.extend({ /** @method _fetchAll @private - @param {DS.Model} typeClass + @param {DS.Model} modelClass @param {DS.RecordArray} array @return {Promise} promise */ - _fetchAll(typeClass, array, options) { + _fetchAll(modelClass, array, options) { options = options || {}; - var adapter = this.adapterFor(typeClass.modelName); - var sinceToken = this.typeMapFor(typeClass).metadata.since; - assert("You tried to load all records but you have no adapter (for " + typeClass + ")", adapter); + let adapter = this.adapterFor(modelClass.modelName); + let sinceToken = this.typeMapFor(modelClass).metadata.since; + + assert("You tried to load all records but you have no adapter (for " + modelClass.modelName + ")", adapter); assert("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function'); if (options.reload) { set(array, 'isUpdating', true); - return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); + return promiseArray(_findAll(adapter, this, modelClass, sinceToken, options)); } - var snapshotArray = array._createSnapshot(options); + let snapshotArray = array._createSnapshot(options); if (adapter.shouldReloadAll(this, snapshotArray)) { set(array, 'isUpdating', true); - return promiseArray(_findAll(adapter, this, typeClass, sinceToken, options)); + return promiseArray(_findAll(adapter, this, modelClass, sinceToken, options)); } if (options.backgroundReload === false) { @@ -1551,7 +1565,7 @@ Store = Service.extend({ if (options.backgroundReload || adapter.shouldBackgroundReloadAll(this, snapshotArray)) { set(array, 'isUpdating', true); - _findAll(adapter, this, typeClass, sinceToken, options); + _findAll(adapter, this, modelClass, sinceToken, options); } return promiseArray(Promise.resolve(array)); @@ -1559,12 +1573,13 @@ Store = Service.extend({ /** @method didUpdateAll - @param {DS.Model} typeClass + @param {DS.Model} modelClass @private */ - didUpdateAll(typeClass) { + didUpdateAll(modelClass) { heimdall.increment(didUpdateAll); - var liveRecordArray = this.recordArrayManager.liveRecordArrayFor(typeClass); + let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(modelClass); + set(liveRecordArray, 'isUpdating', false); }, @@ -1584,7 +1599,7 @@ Store = Service.extend({ Example ```javascript - var localPosts = store.peekAll('post'); + let localPosts = store.peekAll('post'); ``` @since 1.13.0 @@ -1595,7 +1610,7 @@ Store = Service.extend({ peekAll(modelName) { heimdall.increment(peekAll); assert("You need to pass a model name to the store's peekAll method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); let modelClass = this.modelFor(modelName); let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(modelClass); @@ -1619,7 +1634,8 @@ Store = Service.extend({ @param {String} modelName */ unloadAll(modelName) { - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), !modelName || typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), !modelName || typeof modelName === 'string'); + if (arguments.length === 0) { let typeMaps = this.typeMaps; let keys = Object.keys(typeMaps); @@ -1631,8 +1647,8 @@ Store = Service.extend({ types.forEach(this.unloadAll, this); } else { - let typeClass = this.modelFor(modelName); - let typeMap = this.typeMapFor(typeClass); + let modelClass = this.modelFor(modelName); + let typeMap = this.typeMapFor(modelClass); let records = typeMap.records.slice(); let record; @@ -1686,7 +1702,7 @@ Store = Service.extend({ return post.get('unread'); }).then(function(unreadPosts) { unreadPosts.get('length'); // 5 - var unreadPost = unreadPosts.objectAt(0); + let unreadPost = unreadPosts.objectAt(0); unreadPost.set('unread', false); unreadPosts.get('length'); // 4 }); @@ -1702,16 +1718,16 @@ Store = Service.extend({ */ filter(modelName, query, filter) { assert("You need to pass a model name to the store's filter method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); - if (!Ember.ENV.ENABLE_DS_FILTER) { + if (!ENV.ENABLE_DS_FILTER) { assert('The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', false); } - var promise; - var length = arguments.length; - var array; - var hasQuery = length === 3; + let promise; + let length = arguments.length; + let array; + let hasQuery = length === 3; // allow an optional server query if (hasQuery) { @@ -1754,7 +1770,7 @@ Store = Service.extend({ */ recordIsLoaded(modelName, id) { assert("You need to pass a model name to the store's recordIsLoaded method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); return this.hasRecordForId(modelName, id); }, @@ -1794,7 +1810,7 @@ Store = Service.extend({ @param {Object} options */ scheduleSave(internalModel, resolver, options) { - var snapshot = internalModel.createSnapshot(options); + let snapshot = internalModel.createSnapshot(options); internalModel.flushChangedAttributes(); internalModel.adapterWillCommit(); this._pendingSave.push({ @@ -1812,15 +1828,15 @@ Store = Service.extend({ @private */ flushPendingSave() { - var pending = this._pendingSave.slice(); + let pending = this._pendingSave.slice(); this._pendingSave = []; pending.forEach((pendingItem) => { - var snapshot = pendingItem.snapshot; - var resolver = pendingItem.resolver; - var record = snapshot._internalModel; - var adapter = this.adapterFor(record.type.modelName); - var operation; + let snapshot = pendingItem.snapshot; + let resolver = pendingItem.resolver; + let record = snapshot._internalModel; + let adapter = this.adapterFor(record.modelClass.modelName); + let operation; if (get(record, 'currentState.stateName') === 'root.deleted.saved') { return resolver.resolve(); @@ -1850,7 +1866,7 @@ Store = Service.extend({ @param {Object} data optional data (see above) */ didSaveRecord(internalModel, dataArg) { - var data; + let data; if (dataArg) { data = dataArg.data; } @@ -1906,8 +1922,8 @@ Store = Service.extend({ @param {Object} data */ updateId(internalModel, data) { - var oldId = internalModel.id; - var id = coerceId(data.id); + let oldId = internalModel.id; + let id = coerceId(data.id); // ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record) assert(`'${internalModel.type.modelName}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null)); @@ -1932,14 +1948,14 @@ Store = Service.extend({ @method typeMapFor @private - @param {DS.Model} typeClass + @param {DS.Model} modelClass @return {Object} typeMap */ - typeMapFor(typeClass) { + typeMapFor(modelClass) { heimdall.increment(typeMapFor); - var typeMaps = get(this, 'typeMaps'); - var guid = Ember.guidFor(typeClass); - var typeMap = typeMaps[guid]; + let typeMaps = get(this, 'typeMaps'); + let guid = guidFor(modelClass); + let typeMap = typeMaps[guid]; if (typeMap) { return typeMap; } @@ -1948,7 +1964,7 @@ Store = Service.extend({ idToRecord: new EmptyObject(), records: [], metadata: new EmptyObject(), - type: typeClass + type: modelClass }; typeMaps[guid] = typeMap; @@ -1970,7 +1986,7 @@ Store = Service.extend({ */ _load(data) { heimdall.increment(_load); - var internalModel = this._internalModelForId(data.type, data.id); + let internalModel = this._internalModelForId(data.type, data.id); internalModel.setupData(data); @@ -1982,10 +1998,10 @@ Store = Service.extend({ /* In case someone defined a relationship to a mixin, for example: ``` - var Comment = DS.Model.extend({ + let Comment = DS.Model.extend({ owner: belongsTo('commentable'. { polymorphic: true}) }); - var Commentable = Ember.Mixin.create({ + let Commentable = Ember.Mixin.create({ comments: hasMany('comment') }); ``` @@ -1997,18 +2013,18 @@ Store = Service.extend({ _modelForMixin(modelName) { heimdall.increment(_modelForMixin); - var normalizedModelName = normalizeModelName(modelName); + let normalizedModelName = normalizeModelName(modelName); // container.registry = 2.1 // container._registry = 1.11 - 2.0 // container = < 1.11 - var owner = getOwner(this); + let owner = getOwner(this); - var mixin = owner._lookupFactory('mixin:' + normalizedModelName); + let mixin = owner._lookupFactory('mixin:' + normalizedModelName); if (mixin) { //Cache the class as a model owner.register('model:' + normalizedModelName, Model.extend(mixin)); } - var factory = this.modelFactoryFor(normalizedModelName); + let factory = this.modelFactoryFor(normalizedModelName); if (factory) { factory.__isMixin = true; factory.__mixin = mixin; @@ -2032,15 +2048,15 @@ Store = Service.extend({ modelFor(modelName) { heimdall.increment(modelFor); assert("You need to pass a model name to the store's modelFor method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); - var factory = this.modelFactoryFor(modelName); + let factory = this.modelFactoryFor(modelName); if (!factory) { //Support looking up mixins as base types for polymorphic relationships factory = this._modelForMixin(modelName); } if (!factory) { - throw new Ember.Error("No model was found for '" + modelName + "'"); + throw new EmberError("No model was found for '" + modelName + "'"); } factory.modelName = factory.modelName || normalizeModelName(modelName); @@ -2050,10 +2066,10 @@ Store = Service.extend({ modelFactoryFor(modelName) { heimdall.increment(modelFactoryFor); assert("You need to pass a model name to the store's modelFactoryFor method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string'); - var normalizedKey = normalizeModelName(modelName); + assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + let normalizedKey = normalizeModelName(modelName); - var owner = getOwner(this); + let owner = getOwner(this); return owner._lookupFactory('model:' + normalizedKey); }, @@ -2265,7 +2281,7 @@ Store = Service.extend({ return null; } - assert(`Expected an object in the 'data' property in a call to 'push' for ${data.type}, but was ${Ember.typeOf(data.data)}`, Ember.typeOf(data.data) === 'object'); + assert(`Expected an object in the 'data' property in a call to 'push' for ${data.type}, but was ${typeOf(data.data)}`, typeOf(data.data) === 'object'); let internalModel = this._pushInternalModel(data.data); @@ -2273,41 +2289,41 @@ Store = Service.extend({ return internalModel; }, - _hasModelFor(type) { - return !!getOwner(this)._lookupFactory(`model:${type}`); + _hasModelFor(modelName) { + return !!getOwner(this)._lookupFactory(`model:${modelName}`); }, _pushInternalModel(data) { heimdall.increment(_pushInternalModel); - var modelName = data.type; + let modelName = data.type; assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id !== null && data.id !== undefined && data.id !== ''); assert(`You tried to push data with a type '${modelName}' but no model could be found with that name.`, this._hasModelFor(modelName)); runInDebug(() => { - // If Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload + // If ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload // contains unknown attributes or relationships, log a warning. - if (Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS) { - let type = this.modelFor(modelName); + if (ENV.DS_WARN_ON_UNKNOWN_KEYS) { + let modelClass = this.modelFor(modelName); // Check unknown attributes let unknownAttributes = Object.keys(data.attributes || {}).filter((key) => { - return !get(type, 'fields').has(key); + return !get(modelClass, 'fields').has(key); }); - let unknownAttributesMessage = `The payload for '${type.modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`; + let unknownAttributesMessage = `The payload for '${modelClass.modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`; warn(unknownAttributesMessage, unknownAttributes.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); // Check unknown relationships let unknownRelationships = Object.keys(data.relationships || {}).filter((key) => { - return !get(type, 'fields').has(key); + return !get(modelClass, 'fields').has(key); }); - let unknownRelationshipsMessage = `The payload for '${type.modelName}' contains these unknown relationships: ${unknownRelationships}. Make sure they've been defined in your model.`; + let unknownRelationshipsMessage = `The payload for '${modelClass.modelName}' contains these unknown relationships: ${unknownRelationships}. Make sure they've been defined in your model.`; warn(unknownRelationshipsMessage, unknownRelationships.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); } }); // Actually load the record into the store. - var internalModel = this._load(data); + let internalModel = this._load(data); this._backburner.join(() => { this._backburner.schedule('normalizeRelationships', this, this._setupRelationships, internalModel, data); @@ -2340,7 +2356,7 @@ Store = Service.extend({ ``` ```js - var pushData = { + let pushData = { posts: [ { id: 1, post_title: "Great post", comment_ids: [2] } ], @@ -2380,15 +2396,15 @@ Store = Service.extend({ @param {Object} inputPayload */ pushPayload(modelName, inputPayload) { - var serializer; - var payload; + let serializer; + let payload; if (!inputPayload) { payload = modelName; serializer = defaultSerializer(this); assert("You cannot use `store#pushPayload` without a modelName unless your default serializer defines `pushPayload`", typeof serializer.pushPayload === 'function'); } else { payload = inputPayload; - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); serializer = this.serializerFor(modelName); } if (isEnabled('ds-pushpayload-return')) { @@ -2406,8 +2422,8 @@ Store = Service.extend({ ```js socket.on('message', function(message) { - var modelName = message.model; - var data = message.data; + let modelName = message.model; + let data = message.data; store.push(store.normalize(modelName, data)); }); ``` @@ -2420,9 +2436,9 @@ Store = Service.extend({ normalize(modelName, payload) { heimdall.increment(normalize); assert("You need to pass a model name to the store's normalize method", isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); - var serializer = this.serializerFor(modelName); - var model = this.modelFor(modelName); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); + let serializer = this.serializerFor(modelName); + let model = this.modelFor(modelName); return serializer.normalize(model, payload); }, @@ -2432,22 +2448,22 @@ Store = Service.extend({ @method buildRecord @private - @param {DS.Model} type + @param {DS.Model} modelClass @param {String} id @param {Object} data @return {InternalModel} internal model */ - buildInternalModel(type, id, data) { + buildInternalModel(modelClass, id, data) { heimdall.increment(buildInternalModel); - var typeMap = this.typeMapFor(type); - var idToRecord = typeMap.idToRecord; + let typeMap = this.typeMapFor(modelClass); + let idToRecord = typeMap.idToRecord; - assert(`The id ${id} has already been used with another record of type ${type.toString()}.`, !id || !idToRecord[id]); - assert(`'${Ember.inspect(type)}' does not appear to be an ember-data model`, (typeof type._create === 'function') ); + assert(`The id ${id} has already been used with another record for modelClass ${modelClass}.`, !id || !idToRecord[id]); + assert(`'${inspect(modelClass)}' does not appear to be an ember-data model`, (typeof modelClass._create === 'function') ); // lookupFactory should really return an object that creates // instances with the injections applied - var internalModel = new InternalModel(type, id, this, data); + let internalModel = new InternalModel(modelClass, id, this, data); // if we're creating an item, this process will be done // later, once the object has been persisted. @@ -2478,9 +2494,9 @@ Store = Service.extend({ @param {InternalModel} internalModel */ _dematerializeRecord(internalModel) { - var type = internalModel.type; - var typeMap = this.typeMapFor(type); - var id = internalModel.id; + let modelClass = internalModel.type; + let typeMap = this.typeMapFor(modelClass); + let id = internalModel.id; internalModel.updateRecordArrays(); @@ -2488,7 +2504,7 @@ Store = Service.extend({ delete typeMap.idToRecord[id]; } - var loc = typeMap.records.indexOf(internalModel); + let loc = typeMap.records.indexOf(internalModel); typeMap.records.splice(loc, 1); }, @@ -2516,7 +2532,7 @@ Store = Service.extend({ adapterFor(modelName) { heimdall.increment(adapterFor); assert("You need to pass a model name to the store's adapterFor method", isPresent(modelName)); - assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); + assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); let normalizedModelName = normalizeModelName(modelName); @@ -2555,7 +2571,7 @@ Store = Service.extend({ serializerFor(modelName) { heimdall.increment(serializerFor); assert("You need to pass a model name to the store's serializerFor method", isPresent(modelName)); - assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${Ember.inspect(modelName)}`, typeof modelName === 'string'); + assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); let normalizedModelName = normalizeModelName(modelName); @@ -2592,7 +2608,7 @@ function deserializeRecordId(store, key, relationship, id) { return; } - assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being ${Ember.inspect(id)}, but ${key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(id)); + assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being ${inspect(id)}, but ${key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(id)); //TODO:Better asserts return store._internalModelForId(id.type, id.id); @@ -2603,7 +2619,7 @@ function deserializeRecordIds(store, key, relationship, ids) { return; } - assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being '${Ember.inspect(ids)}', but ${key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(ids)); + assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being '${inspect(ids)}', but ${key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(ids)); let _ids = new Array(ids.length); for (let i = 0; i < ids.length; i++) { @@ -2622,14 +2638,14 @@ function defaultSerializer(store) { } function _commit(adapter, store, operation, snapshot) { - var internalModel = snapshot._internalModel; - var modelName = snapshot.modelName; - var typeClass = store.modelFor(modelName); - assert(`You tried to update a record but you have no adapter (for ${typeClass})`, adapter); - assert(`You tried to update a record but your adapter (for ${typeClass}) does not implement '${operation}'`, typeof adapter[operation] === 'function'); - var promise = adapter[operation](store, typeClass, snapshot); - var serializer = serializerForAdapter(store, adapter, modelName); - var label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; + let internalModel = snapshot._internalModel; + let modelName = snapshot.modelName; + let modelClass = store.modelFor(modelName); + assert(`You tried to update a record but you have no adapter (for ${modelClass.modelName})`, adapter); + assert(`You tried to update a record but your adapter (for ${modelClass.modelName}) does not implement '${operation}'`, typeof adapter[operation] === 'function'); + let promise = adapter[operation](store, modelClass, snapshot); + let serializer = serializerForAdapter(store, adapter, modelName); + let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; assert(`Your adapter's '${operation}' method must return a value, but it returned 'undefined'`, promise !==undefined); @@ -2639,9 +2655,9 @@ function _commit(adapter, store, operation, snapshot) { return promise.then((adapterPayload) => { store._adapterRun(() => { - var payload, data; + let payload, data; if (adapterPayload) { - payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, snapshot.id, operation); + payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, snapshot.id, operation); if (payload.included) { store.push({ data: payload.included }); } @@ -2653,7 +2669,8 @@ function _commit(adapter, store, operation, snapshot) { return internalModel; }, function(error) { if (error instanceof InvalidError) { - var errors = serializer.extractErrors(store, typeClass, error, snapshot.id); + let errors = serializer.extractErrors(store, modelClass, error, snapshot.id); + store.recordWasInvalid(internalModel, errors); } else { store.recordWasError(internalModel, error); @@ -2669,13 +2686,13 @@ function setupRelationships(store, record, data) { } record.type.eachRelationship((key, descriptor) => { - var kind = descriptor.kind; + let kind = descriptor.kind; if (!data.relationships[key]) { return; } - var relationship; + let relationship; if (data.relationships[key].links && data.relationships[key].links.related) { let relatedLink = _normalizeLink(data.relationships[key].links.related); @@ -2695,7 +2712,7 @@ function setupRelationships(store, record, data) { // (possibly unloaded) before we push the payload into the store. normalizeRelationship(store, key, descriptor, data.relationships[key]); - var value = data.relationships[key].data; + let value = data.relationships[key].data; if (value !== undefined) { if (kind === 'belongsTo') { @@ -2710,9 +2727,9 @@ function setupRelationships(store, record, data) { } function normalizeRelationship(store, key, relationship, jsonPayload) { - var data = jsonPayload.data; + let data = jsonPayload.data; if (data) { - var kind = relationship.kind; + let kind = relationship.kind; if (kind === 'belongsTo') { jsonPayload.data = deserializeRecordId(store, key, relationship, data); } else if (kind === 'hasMany') { diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index f2e04bbe782..b6fd7b7e3fa 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -367,7 +367,7 @@ testInDebug("a new record with a specific id can't be created if this id is alre run(function() { store.createRecord('person', { id: 5 }); }); - }, /The id 5 has already been used with another record of type Person/); + }, /The id 5 has already been used with another record for modelClass Person/); }); test("an initial data hash can be provided via store.createRecord(type, hash)", function(assert) { From 4eda936bef8b6c859eb4bb0e41cdd83fb5b8258b Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 17 Nov 2016 17:25:40 -0800 Subject: [PATCH 1700/2527] deprecate store.recordIsLoaded --- addon/-private/system/store.js | 42 +++++++++++++++++--------------- tests/unit/store/asserts-test.js | 3 +-- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index fe2f6cb1a00..753b8f21ee4 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1025,20 +1025,31 @@ Store = Service.extend({ }, /** - Returns true if a record for a given type and ID is already loaded. + This method returns true if a record for a given modelName and id is already + loaded in the store. Use this function to know beforehand if a findRecord() + will result in a request or that it will be a cache hit. + + Example + + ```javascript + store.hasRecordForId('post', 1); // false + store.findRecord('post', 1).then(function() { + store.hasRecordForId('post', 1); // true + }); + ``` @method hasRecordForId @param {(String|DS.Model)} modelName - @param {(String|Integer)} inputId + @param {(String|Integer)} id @return {Boolean} */ - hasRecordForId(modelName, inputId) { + hasRecordForId(modelName, id) { assert("You need to pass a model name to the store's hasRecordForId method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); - let id = coerceId(inputId); + let trueId = coerceId(id); let modelClass = this.modelFor(modelName); - let internalModel = this.typeMapFor(modelClass).idToRecord[id]; + let internalModel = this.typeMapFor(modelClass).idToRecord[trueId]; return !!internalModel && internalModel.isLoaded(); }, @@ -1750,27 +1761,20 @@ Store = Service.extend({ }, /** - This method returns if a certain record is already loaded - in the store. Use this function to know beforehand if a findRecord() - will result in a request or that it will be a cache hit. - - Example - - ```javascript - store.recordIsLoaded('post', 1); // false - store.findRecord('post', 1).then(function() { - store.recordIsLoaded('post', 1); // true - }); - ``` + This method has been deprecated and is an alias for store.hasRecordForId, which should + be used instead. + @deprecated @method recordIsLoaded @param {String} modelName @param {string} id @return {boolean} */ recordIsLoaded(modelName, id) { - assert("You need to pass a model name to the store's recordIsLoaded method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + deprecate(`Use of recordIsLoaded is deprecated, use hasRecordForId instead.`, { + id: 'ds.store.recordIsLoaded', + until: '3.0' + }); return this.hasRecordForId(modelName, id); }, diff --git a/tests/unit/store/asserts-test.js b/tests/unit/store/asserts-test.js index a54134bf049..49c3dd01fa4 100644 --- a/tests/unit/store/asserts-test.js +++ b/tests/unit/store/asserts-test.js @@ -16,7 +16,6 @@ const MODEL_NAME_METHODS = [ 'findAll', 'peekAll', 'filter', - 'recordIsLoaded', 'modelFor', 'modelFactoryFor', 'normalize', @@ -24,7 +23,7 @@ const MODEL_NAME_METHODS = [ 'serializerFor' ]; -testInDebug("Calling Store methods with no type asserts", function(assert) { +testInDebug("Calling Store methods with no modelName asserts", function(assert) { assert.expect(MODEL_NAME_METHODS.length); let store = createStore(); From 84961dcf89333cbf5c226e9886810957ad6e06a6 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 17 Nov 2016 17:26:42 -0800 Subject: [PATCH 1701/2527] fix test usage of store.recordIsLoaded --- tests/unit/model-test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 5afdfe4ec7b..4bf896805ad 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -953,10 +953,10 @@ module("unit/model - with a simple Person model", { }); test("can ask if record with a given id is loaded", function(assert) { - assert.equal(store.recordIsLoaded('person', 1), true, 'should have person with id 1'); - assert.equal(store.recordIsLoaded('person', 1), true, 'should have person with id 1'); - assert.equal(store.recordIsLoaded('person', 4), false, 'should not have person with id 4'); - assert.equal(store.recordIsLoaded('person', 4), false, 'should not have person with id 4'); + assert.equal(store.hasRecordForId('person', 1), true, 'should have person with id 1'); + assert.equal(store.hasRecordForId('person', 1), true, 'should have person with id 1'); + assert.equal(store.hasRecordForId('person', 4), false, 'should not have person with id 4'); + assert.equal(store.hasRecordForId('person', 4), false, 'should not have person with id 4'); }); test("a listener can be added to a record", function(assert) { From 2b1cc7fca2a2afc3ab5ad842c23dc41be1963d23 Mon Sep 17 00:00:00 2001 From: sly7-7 Date: Tue, 15 Nov 2016 09:48:46 +0100 Subject: [PATCH 1702/2527] [FEATURE ds-deprecate-store-serialize] deprecate private store.serialize api --- FEATURES.md | 4 +++ addon/-private/system/model/model.js | 2 +- addon/-private/system/store.js | 7 ++++ config/features.json | 3 +- .../relationships/belongs-to-test.js | 2 +- tests/unit/store/serialize-test.js | 34 +++++++++++++++++++ 6 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 tests/unit/store/serialize-test.js diff --git a/FEATURES.md b/FEATURES.md index 1768898f93c..2f49b841849 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -146,3 +146,7 @@ entry in `config/features.json`. } }); ``` +- `ds-deprecate-store-serialize` [#4654](https://github.com/emberjs/data/pull/4654) + + Adds a deprecation warning when using Store#serialize(record) method. + You can use record.serialize() instead. diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index fffc6e50af1..55eec3aae95 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -399,7 +399,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @return {Object} an object whose values are primitive JSON values only */ serialize(options) { - return this.store.serialize(this, options); + return this._internalModel.createSnapshot().serialize(options); }, /** diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index fe2f6cb1a00..78da6fa3cd0 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -253,10 +253,17 @@ Store = Service.extend({ @method serialize @private + @deprecated @param {DS.Model} record the record to serialize @param {Object} options an options hash */ serialize(record, options) { + if (isEnabled('ds-deprecate-store-serialize')) { + deprecate('Use of store.serialize is deprecated, use record.serialize instead.', false, { + id: 'ds.store.serialize', + until: '3.0' + }); + } let snapshot = record._internalModel.createSnapshot(); return snapshot.serialize(options); }, diff --git a/config/features.json b/config/features.json index 4b9c28cb124..b235af06c91 100644 --- a/config/features.json +++ b/config/features.json @@ -6,5 +6,6 @@ "ds-payload-type-hooks": null, "ds-check-should-serialize-relationships": null, "ds-reset-attribute": null, - "ds-serialize-id": null + "ds-serialize-id": null, + "ds-deprecate-store-serialize": true } diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 5efa0e42218..c1695bc2e87 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -279,7 +279,7 @@ test("The store can serialize a polymorphic belongsTo association", function(ass }); store.findRecord('comment', 2).then(function(comment) { - var serialized = store.serialize(comment, { includeId: true }); + var serialized = comment.serialize({ includeId: true }); assert.equal(serialized['message'], 1); assert.equal(serialized['message_type'], 'post'); }); diff --git a/tests/unit/store/serialize-test.js b/tests/unit/store/serialize-test.js new file mode 100644 index 00000000000..b90c64a0eea --- /dev/null +++ b/tests/unit/store/serialize-test.js @@ -0,0 +1,34 @@ +import { module } from 'qunit'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import attr from 'ember-data/attr'; +import Model from 'ember-data/model'; +import { createStore } from 'dummy/tests/helpers/store'; +import Ember from 'ember'; +import isEnabled from 'ember-data/-private/features'; + +const { run } = Ember; + +if (isEnabled('ds-deprecate-store-serialize')) { + module("unit/store/serialize - DS.Store#serialize"); + + testInDebug('Store#serialize is deprecated', function(assert) { + let store = createStore({ + person: Model.extend({ firstName: attr() }) + }); + + run(function() { + let person = store.push({ + data: { + type: 'person', + id: 1, + attributes: { + firstName: 'original first name' + } + } + }); + assert.expectDeprecation("Use of store.serialize is deprecated, use record.serialize instead."); + store.serialize(person); + }); + + }); +} From 3d49afeb6d01bcbdfe2f7f5dad21ca274938df08 Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 17 Nov 2016 09:58:20 -0500 Subject: [PATCH 1703/2527] Silence warnings and deprecations in the console durring tests --- tests/helpers/setup-ember-dev.js | 2 +- .../integration/adapter/rest-adapter-test.js | 16 +++-- tests/integration/records/error-test.js | 44 +++++++------ .../serializers/json-serializer-test.js | 9 +-- tests/unit/model/errors-test.js | 61 ++++++++++--------- tests/unit/store/adapter-interop-test.js | 26 ++++---- 6 files changed, 89 insertions(+), 69 deletions(-) diff --git a/tests/helpers/setup-ember-dev.js b/tests/helpers/setup-ember-dev.js index faf10add6af..703c9c4dac6 100644 --- a/tests/helpers/setup-ember-dev.js +++ b/tests/helpers/setup-ember-dev.js @@ -2,7 +2,7 @@ import Ember from 'ember'; import EmberTestHelpers from "ember-dev/test-helper/index"; -const AVAILABLE_ASSERTIONS = ['expectAssertion', 'expectDeprecation', 'expectNoDeprecation', 'expectWarning', 'expectNoWarning']; +const AVAILABLE_ASSERTIONS = ['expectAssertion', 'expectDeprecation', 'expectNoDeprecation', 'expectWarning', 'expectNoWarning', 'ignoreDeprecation']; // Maintain backwards compatiblity with older versions of ember. var emberDebugModule; diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 0f0167ec8f7..a91d402581f 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1349,17 +1349,21 @@ test("queryRecord - returning sideloaded data loads the data", function(assert) })); }); -test("queryRecord - returning an array picks the first one but saves all records to the store", function(assert) { +testInDebug("queryRecord - returning an array picks the first one but saves all records to the store", function(assert) { ajaxResponse({ post: [{ id: 1, name: "Rails is omakase" }, { id: 2, name: "Ember is js" }] }); - store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(assert.wait(function(post) { - var post2 = store.peekRecord('post', 2); + assert.expectDeprecation('The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record.'); - assert.deepEqual(post.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }); - assert.deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "Ember is js" }); - })); + run(function() { + store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(assert.wait(function(post) { + var post2 = store.peekRecord('post', 2); + + assert.deepEqual(post.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }); + assert.deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "Ember is js" }); + })); + }); }); testInDebug("queryRecord - returning an array is deprecated", function(assert) { diff --git a/tests/integration/records/error-test.js b/tests/integration/records/error-test.js index 0c8e1bfe77d..a0ca3f3a941 100644 --- a/tests/integration/records/error-test.js +++ b/tests/integration/records/error-test.js @@ -1,12 +1,19 @@ import Ember from 'ember'; -import {module, test} from 'qunit'; +import {module} from 'qunit'; import DS from 'ember-data'; import setupStore from 'dummy/tests/helpers/store'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; var env, store, Person; var attr = DS.attr; var run = Ember.run; +function updateErrors(func) { + window.expectWarning(function() { + run(func); + }, 'Interacting with a record errors object will no longer change the record state.'); +} + module('integration/records/error', { beforeEach: function() { Person = DS.Model.extend({ @@ -28,8 +35,8 @@ module('integration/records/error', { } }); -test('adding errors during root.loaded.created.invalid works', function(assert) { - assert.expect(3); +testInDebug('adding errors during root.loaded.created.invalid works', function(assert) { + assert.expect(5); var person = run(() => { store.push({ @@ -51,11 +58,12 @@ test('adding errors during root.loaded.created.invalid works', function(assert) }); assert.equal(person._internalModel.currentState.stateName, 'root.loaded.updated.uncommitted'); - Ember.run(() => person.get('errors').add('firstName', 'is invalid') ); + + updateErrors(() => person.get('errors').add('firstName', 'is invalid') , assert); assert.equal(person._internalModel.currentState.stateName, 'root.loaded.updated.invalid'); - Ember.run(() => person.get('errors').add('lastName', 'is invalid') ); + updateErrors(() => person.get('errors').add('lastName', 'is invalid'), assert); assert.deepEqual(person.get('errors').toArray(), [ { attribute: 'firstName', message: 'is invalid' }, @@ -64,8 +72,8 @@ test('adding errors during root.loaded.created.invalid works', function(assert) }); -test('adding errors root.loaded.created.invalid works', function(assert) { - assert.expect(3); +testInDebug('adding errors root.loaded.created.invalid works', function(assert) { + assert.expect(5); var person = run(() => { return store.createRecord('person', { @@ -82,11 +90,11 @@ test('adding errors root.loaded.created.invalid works', function(assert) { assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); - Ember.run(() => person.get('errors').add('firstName', 'is invalid') ); + updateErrors(() => person.get('errors').add('firstName', 'is invalid') ); assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); - Ember.run(() => person.get('errors').add('lastName', 'is invalid') ); + updateErrors(() => person.get('errors').add('lastName', 'is invalid') ); assert.deepEqual(person.get('errors').toArray(), [ { attribute: 'firstName', message: 'is invalid' }, @@ -94,8 +102,8 @@ test('adding errors root.loaded.created.invalid works', function(assert) { ]); }); -test('adding errors root.loaded.created.invalid works add + remove + add', function(assert) { - assert.expect(4); +testInDebug('adding errors root.loaded.created.invalid works add + remove + add', function(assert) { + assert.expect(7); var person = run(() => { return store.createRecord('person', { @@ -110,23 +118,23 @@ test('adding errors root.loaded.created.invalid works add + remove + add', funct assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); - Ember.run(() => person.get('errors').add('firstName', 'is invalid') ); + updateErrors(() => person.get('errors').add('firstName', 'is invalid') ); assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); - Ember.run(() => person.get('errors').remove('firstName')); + updateErrors(() => person.get('errors').remove('firstName')); assert.deepEqual(person.get('errors').toArray(), []); - Ember.run(() => person.get('errors').add('firstName', 'is invalid') ); + updateErrors(() => person.get('errors').add('firstName', 'is invalid') ); assert.deepEqual(person.get('errors').toArray(), [ { attribute: 'firstName', message: 'is invalid' } ]); }); -test('adding errors root.loaded.created.invalid works add + (remove, add)', function(assert) { - assert.expect(4); +testInDebug('adding errors root.loaded.created.invalid works add + (remove, add)', function(assert) { + assert.expect(6); var person = run(() => { return store.createRecord('person', { @@ -141,13 +149,13 @@ test('adding errors root.loaded.created.invalid works add + (remove, add)', func assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); - Ember.run(() => { + updateErrors(() => { person.get('errors').add('firstName', 'is invalid'); }); assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); - Ember.run(() => { + updateErrors(() => { person.get('errors').remove('firstName'); person.get('errors').add('firstName', 'is invalid'); }); diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 00cb4d20105..66e547b7e60 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -973,7 +973,7 @@ test('normalizeResponse respects `included` items (array response)', function(as ]); }); -test('normalizeResponse ignores unmapped attributes', function(assert) { +testInDebug('normalizeResponse ignores unmapped attributes', function(assert) { env.registry.register("serializer:post", DS.JSONSerializer.extend({ attrs: { title: { serialize: false }, @@ -987,9 +987,10 @@ test('normalizeResponse ignores unmapped attributes', function(assert) { title: "Rails is omakase" }; - var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); - - assert.equal(post.data.attributes.title, "Rails is omakase"); + assert.expectWarning(function() { + var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); + assert.equal(post.data.attributes.title, "Rails is omakase"); + }, /There is no attribute or relationship with the name/); }); test('options are passed to transform for serialization', function(assert) { diff --git a/tests/unit/model/errors-test.js b/tests/unit/model/errors-test.js index 9569a80c4de..b1efef07942 100644 --- a/tests/unit/model/errors-test.js +++ b/tests/unit/model/errors-test.js @@ -1,5 +1,6 @@ import DS from 'ember-data'; -import QUnit, {module, test} from 'qunit'; +import QUnit, {module} from 'qunit'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; const AssertPrototype = QUnit.assert; @@ -14,6 +15,10 @@ module("unit/model/errors", { } }); +function updateErrors(func) { + window.expectWarning(func, 'Interacting with a record errors object will no longer change the record state.'); +} + AssertPrototype.becameInvalid = function becameInvalid(eventName) { if (eventName === 'becameInvalid') { this.ok(true, 'becameInvalid send'); @@ -34,32 +39,32 @@ AssertPrototype.unexpectedSend = function unexpectedSend(eventName) { this.ok(false, 'unexpected send : ' + eventName); }.bind(AssertPrototype); -test("add error", function(assert) { - assert.expect(6); +testInDebug("add error", function(assert) { + assert.expect(10); errors.trigger = assert.becameInvalid; - errors.add('firstName', 'error'); + updateErrors(() => errors.add('firstName', 'error')); errors.trigger = assert.unexpectedSend; assert.ok(errors.has('firstName'), 'it has firstName errors'); assert.equal(errors.get('length'), 1, 'it has 1 error'); - errors.add('firstName', ['error1', 'error2']); + updateErrors(() => errors.add('firstName', ['error1', 'error2'])); assert.equal(errors.get('length'), 3, 'it has 3 errors'); assert.ok(!errors.get('isEmpty'), 'it is not empty'); - errors.add('lastName', 'error'); - errors.add('lastName', 'error'); + updateErrors(() => errors.add('lastName', 'error')); + updateErrors(() => errors.add('lastName', 'error')); assert.equal(errors.get('length'), 4, 'it has 4 errors'); }); -test("get error", function(assert) { - assert.expect(8); +testInDebug("get error", function(assert) { + assert.expect(11); assert.ok(errors.get('firstObject') === undefined, 'returns undefined'); errors.trigger = assert.becameInvalid; - errors.add('firstName', 'error'); + updateErrors(() => errors.add('firstName', 'error')); errors.trigger = assert.unexpectedSend; assert.ok(errors.get('firstName').length === 1, 'returns errors'); assert.deepEqual(errors.get('firstObject'), { attribute: 'firstName', message: 'error' }); - errors.add('firstName', 'error2'); + updateErrors(() => errors.add('firstName', 'error2')); assert.ok(errors.get('firstName').length === 2, 'returns errors'); - errors.add('lastName', 'error3'); + updateErrors(() => errors.add('lastName', 'error3')); assert.deepEqual(errors.toArray(), [ { attribute: 'firstName', message: 'error' }, { attribute: 'firstName', message: 'error2' }, @@ -72,42 +77,42 @@ test("get error", function(assert) { assert.deepEqual(errors.get('messages'), ['error', 'error2', 'error3']); }); -test("remove error", function(assert) { - assert.expect(5); +testInDebug("remove error", function(assert) { + assert.expect(8); errors.trigger = assert.becameInvalid; - errors.add('firstName', 'error'); + updateErrors(() => errors.add('firstName', 'error')); errors.trigger = assert.becameValid; - errors.remove('firstName'); + updateErrors(() => errors.remove('firstName')); errors.trigger = assert.unexpectedSend; assert.ok(!errors.has('firstName'), 'it has no firstName errors'); assert.equal(errors.get('length'), 0, 'it has 0 error'); assert.ok(errors.get('isEmpty'), 'it is empty'); - errors.remove('firstName'); + updateErrors(() => errors.remove('firstName')); }); -test("remove same errors from different attributes", function(assert) { - assert.expect(5); +testInDebug("remove same errors from different attributes", function(assert) { + assert.expect(9); errors.trigger = assert.becameInvalid; - errors.add('firstName', 'error'); - errors.add('lastName', 'error'); + updateErrors(() => errors.add('firstName', 'error')); + updateErrors(() => errors.add('lastName', 'error')); errors.trigger = assert.unexpectedSend; assert.equal(errors.get('length'), 2, 'it has 2 error'); - errors.remove('firstName'); + updateErrors(() => errors.remove('firstName')); assert.equal(errors.get('length'), 1, 'it has 1 error'); errors.trigger = assert.becameValid; - errors.remove('lastName'); + updateErrors(() => errors.remove('lastName')); assert.ok(errors.get('isEmpty'), 'it is empty'); }); -test("clear errors", function(assert) { - assert.expect(5); +testInDebug("clear errors", function(assert) { + assert.expect(8); errors.trigger = assert.becameInvalid; - errors.add('firstName', ['error', 'error1']); + updateErrors(() => errors.add('firstName', ['error', 'error1'])); assert.equal(errors.get('length'), 2, 'it has 2 errors'); errors.trigger = assert.becameValid; - errors.clear(); + updateErrors(() => errors.clear()); errors.trigger = assert.unexpectedSend; assert.ok(!errors.has('firstName'), 'it has no firstName errors'); assert.equal(errors.get('length'), 0, 'it has 0 error'); - errors.clear(); + updateErrors(() => errors.clear()); }); diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index f2e04bbe782..09b8939f85d 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -835,8 +835,8 @@ test("the promise returned by `_scheduleFetch`, when it rejects, does not depend }); }); -test("store._fetchRecord reject records that were not found, even when those requests were coalesced with records that were found", function(assert) { - assert.expect(2); +testInDebug("store._fetchRecord reject records that were not found, even when those requests were coalesced with records that were found", function(assert) { + assert.expect(3); var Person = DS.Model.extend(); @@ -859,18 +859,20 @@ test("store._fetchRecord reject records that were not found, even when those req test: Person }); - run(function () { - var davidPromise = store.findRecord('test', 'david'); - var igorPromise = store.findRecord('test', 'igor'); + assert.expectWarning(function() { + run(function () { + var davidPromise = store.findRecord('test', 'david'); + var igorPromise = store.findRecord('test', 'igor'); - davidPromise.then(assert.wait(function () { - assert.ok(true, "David resolved"); - })); + davidPromise.then(function () { + assert.ok(true, "David resolved"); + }); - igorPromise.then(null, assert.wait(function () { - assert.ok(true, "Igor rejected"); - })); - }); + igorPromise.then(null, function () { + assert.ok(true, "Igor rejected"); + }); + }); + }, /expected to find records with the following ids/); }); testInDebug("store._fetchRecord warns when records are missing", function(assert) { From ff0cbd86043a0efe3fc3dba39cdf3241d74dda39 Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 10 Nov 2016 14:07:14 -0500 Subject: [PATCH 1704/2527] Update API docs for BelongsToReference --- addon/-private/system/model/model.js | 4 +- .../-private/system/references/belongs-to.js | 317 ++++++++++++++++++ 2 files changed, 320 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index fffc6e50af1..dd7195a162b 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -840,7 +840,9 @@ var Model = Ember.Object.extend(Ember.Evented, { type: 'blog', id: 1, relationships: { - user: { type: 'user', id: 1 } + user: { + data: { type: 'user', id: 1 } + } } }); var userRef = blog.belongsTo('user'); diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 4a13c26f37c..81dd48abb86 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -5,6 +5,16 @@ import Reference from './reference'; import isEnabled from 'ember-data/-private/features'; import { assertPolymorphicType, deprecate } from "ember-data/-private/debug"; + +/** + A BelongsToReference is a low level API that allows users and + addon author to perform meta-operations on a belongs-to + relationship. + + @class BelongsToReference + @namespace DS + @extends DS.Reference +*/ var BelongsToReference = function(store, parentInternalModel, belongsToRelationship) { this._super$constructor(store, parentInternalModel); this.belongsToRelationship = belongsToRelationship; @@ -18,6 +28,41 @@ BelongsToReference.prototype = Object.create(Reference.prototype); BelongsToReference.prototype.constructor = BelongsToReference; BelongsToReference.prototype._super$constructor = Reference; +/** + This returns a string that represents how the reference will be + looked up when it is loaded. If the relationship has a link it will + use the "link" otherwise it defaults to "id". + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + var blog = store.push({ + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + }); + var userRef = blog.belongsTo('user'); + + // get the identifier of the reference + if (userRef.remoteType() === "id") { + var id = userRef.id(); + } else if (userRef.remoteType() === "link") { + var link = userRef.link(); + } + ``` + + @method remoteType + @return {String} The name of the remote type. This should either be "link" or "id" +*/ BelongsToReference.prototype.remoteType = function() { if (this.belongsToRelationship.link) { return "link"; @@ -26,19 +71,174 @@ BelongsToReference.prototype.remoteType = function() { return "id"; }; +/** + The `id` of the record that this reference refers to. Together, the + `type()` and `id()` methods form a composite key for the identity + map. This can be used to access the id of an async relationship + without triggering a fetch that would normally happen if you + attempted to use `record.get('relationship.id')`. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + var blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + var userRef = blog.belongsTo('user'); + + // get the identifier of the reference + if (userRef.remoteType() === "id") { + var id = userRef.id(); + } + ``` + + @method id + @return {String} The id of the record in this belongsTo relationship. +*/ BelongsToReference.prototype.id = function() { var inverseRecord = this.belongsToRelationship.inverseRecord; return inverseRecord && inverseRecord.id; }; +/** + The link Ember Data will use to fetch or reload this belongs-to + relationship. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + var blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + links: { + related: '/articles/1/author' + } + } + } + } + }); + var userRef = blog.belongsTo('user'); + + // get the identifier of the reference + if (userRef.remoteType() === "link") { + var link = userRef.link(); + } + ``` + + @method link + @return {String} The link Ember Data will use to fetch or reload this belongs-to relationship. +*/ BelongsToReference.prototype.link = function() { return this.belongsToRelationship.link; }; +/** + The meta data for the belongs-to relationship. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + var blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + links: { + related: { + href: '/articles/1/author', + meta: { + lastUpdated: 1458014400000 + } + } + } + } + } + } + }); + + var userRef = blog.belongsTo('user'); + + userRef.meta() // { lastUpdated: 1458014400000 } + ``` + + @method meta + @return {Object} The meta information for the belongs-oo relationship. +*/ BelongsToReference.prototype.meta = function() { return this.belongsToRelationship.meta; }; +/** + `push` can be used to update the data in the relationship and Ember + Data will treat the new data as the conanical value of this + relationship on the backend. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + var blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + var userRef = blog.belongsTo('user'); + + // provide data for reference + userRef.push({ + data: { + type: 'user', + id: 1, + attributes: { + username: "@user" + } + } + }).then(function(user) { + userRef.value() === user; + }); + ``` + + @method push + @param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. + @return {Promise} A promise that resolves with the new value in this belongs-to relationship. +*/ BelongsToReference.prototype.push = function(objectOrPromise) { return Ember.RSVP.resolve(objectOrPromise).then((data) => { var record; @@ -63,6 +263,54 @@ BelongsToReference.prototype.push = function(objectOrPromise) { }); }; +/** + `value()` synchronously returns the current value of the belongs-to + relationship. Unlike `record.get('relationshipName')`, calling + `value()` on a reference does not trigger a fetch if the async + relationship is not yet loaded. If the relationship is not loaded + it will always return `null`. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + var blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + var userRef = blog.belongsTo('user'); + + userRef.value(); // null + + // provide data for reference + userRef.push({ + data: { + type: 'user', + id: 1, + attributes: { + username: "@user" + } + } + }).then(function(user) { + userRef.value(); // user + }); + ``` + + @method value + @param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. + @return {DS.Model} the record in this relationship +*/ BelongsToReference.prototype.value = function() { var inverseRecord = this.belongsToRelationship.inverseRecord; @@ -73,6 +321,41 @@ BelongsToReference.prototype.value = function() { return null; }; +/** + Loads a record in a belongs to relationship if it is not already + loaded. If the relationship is already loaded this method does not + trigger a new load. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + var blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + var userRef = blog.belongsTo('user'); + + userRef.value(); // null + + userRef.load().then(function(user) { + userRef.value() === user + }); + + @method load + @return {Promise} a promise that resolves with the record in this belongs-to relationship. +*/ BelongsToReference.prototype.load = function() { if (this.remoteType() === "id") { return this.belongsToRelationship.getRecord(); @@ -85,6 +368,40 @@ BelongsToReference.prototype.load = function() { } }; +/** + Triggers a reload of the value in this relationship. If the + remoteType is `"link"` Ember Data will use the relationship link to + reload the relationship. Otherwise it will reload the record by its + id. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + var blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + var userRef = blog.belongsTo('user'); + + userRef.reload().then(function(user) { + userRef.value() === user + }); + + @method reload + @return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed. +*/ BelongsToReference.prototype.reload = function() { return this.belongsToRelationship.reload().then((internalModel) => { return this.value(); From 4fc9133740d2edb8b62a44ed6a592563a0bee508 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 11 Nov 2016 14:02:55 -0500 Subject: [PATCH 1705/2527] Add API docs for the RecordReference --- addon/-private/system/references/record.js | 118 +++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/addon/-private/system/references/record.js b/addon/-private/system/references/record.js index 9e9284453e3..0e0104ea628 100644 --- a/addon/-private/system/references/record.js +++ b/addon/-private/system/references/record.js @@ -1,6 +1,13 @@ import Ember from 'ember'; import Reference from './reference'; +/** + An RecordReference is a low level API that allows users and + addon author to perform meta-operations on a record. + + @class RecordReference + @namespace DS +*/ var RecordReference = function(store, internalModel) { this._super$constructor(store, internalModel); this.type = internalModel.modelName; @@ -11,28 +18,139 @@ RecordReference.prototype = Object.create(Reference.prototype); RecordReference.prototype.constructor = RecordReference; RecordReference.prototype._super$constructor = Reference; +/** + The `id` of the record that this reference refers to. + + Together, the `type` and `id` properties form a composite key for + the identity map. + + Example + + ```javascript + var userRef = store.getReference('user', 1); + + userRef.id(); // '1' + ``` + + @method id + @return {String} The id of the record. +*/ RecordReference.prototype.id = function() { return this._id; }; +/** + How the reference will be looked up when it is loaded: Currently + this always return `identity` to signifying that a record will be + loaded by the `type` and `id`. + + Example + + ```javascript + var userRef = store.getReference('user', 1); + + userRef.remoteType(); // 'identity' + ``` + + @method remoteType + @return {String} 'identity' +*/ RecordReference.prototype.remoteType = function() { return 'identity'; }; +/** + This API allows you to provide a reference with new data. The + simplest usage of this API is similar to `store.push`: you provide a + normalized hash of data and the object represented by the reference + will update. + + If you pass a promise to `push`, Ember Data will not ask the adapter + for the data if another attempt to fetch it is made in the + interim. When the promise resolves, the underlying object is updated + with the new data, and the promise returned by *this function* is resolved + with that object. + + For example, `recordReference.push(promise)` will be resolved with a + record. + + Example + + ```javascript + var userRef = store.getReference('user', 1); + + // provide data for reference + userRef.push({ data: { id: 1, username: "@user" }}).then(function(user) { + userRef.value() === user; + }); + ``` + + @method + @param {Promise|Object} + @returns Promise a promise for the value (record or relationship) +*/ RecordReference.prototype.push = function(objectOrPromise) { return Ember.RSVP.resolve(objectOrPromise).then((data) => { return this.store.push(data); }); }; +/** + If the entity referred to by the reference is already loaded, it is + present as `reference.value`. Otherwise the value returned by this function + is `null`. + + Example + + ```javascript + var userRef = store.getReference('user', 1); + + userRef.value(); // user + ``` + + @method value + @return {DS.Model} the record for this RecordReference +*/ RecordReference.prototype.value = function() { return this.internalModel.record; }; +/** + Triggers a fetch for the backing entity based on its `remoteType` + (see `remoteType` definitions per reference type). + + Example + + ```javascript + var userRef = store.getReference('user', 1); + + // load user (via store.find) + userRef.load().then(...) + ``` + + @method load + @return {Promise} the record for this RecordReference +*/ RecordReference.prototype.load = function() { return this.store.findRecord(this.type, this._id); }; +/** + Reloads the record if it is already loaded. If the record is not + loaded it will load the record via `store.findRecord` + + Example + + ```javascript + var userRef = store.getReference('user', 1); + + // or trigger a reload + userRef.reload().then(...) + ``` + + @method reload + @return {Promise} the record for this RecordReference +*/ RecordReference.prototype.reload = function() { var record = this.value(); if (record) { From 672a1fcf726138011cd020290f459435ccc3b28f Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 18 Nov 2016 09:13:01 -0500 Subject: [PATCH 1706/2527] Enable the RAISE_ON_DEPRECATION flag so tests fail if there is a deprecation --- tests/dummy/config/environment.js | 7 ++----- tests/integration/references/belongs-to-test.js | 8 +++++++- tests/integration/serializers/rest-serializer-test.js | 8 ++++++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index cf10d93440f..ad6657a6117 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -15,11 +15,8 @@ module.exports = function(environment) { locationType: 'auto', EmberENV: { FEATURES: featureFlags, - ENABLE_DS_FILTER: true - - // don't raise on deprecation yet, since there are too many thrown errors; - // this should be addressed in another PR - // RAISE_ON_DEPRECATION: true + ENABLE_DS_FILTER: true, + RAISE_ON_DEPRECATION: true }, APP: { diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index cf8614cab09..e69b67540e0 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -292,6 +292,9 @@ test("push(promise)", function(assert) { testInDebug("push(record) asserts for invalid modelClass", function(assert) { var person, anotherPerson; + if (isEnabled('ds-overhaul-references')) { + assert.expectDeprecation('BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set(\'relationshipName\', value)` instead.') + } run(function() { person = env.store.push({ data: { @@ -321,11 +324,14 @@ testInDebug("push(record) asserts for invalid modelClass", function(assert) { }, "You cannot add a record of modelClass 'person' to the 'person.family' relationship (only 'family' allowed)"); }); -test("push(record) works with polymorphic modelClass", function(assert) { +testInDebug("push(record) works with polymorphic modelClass", function(assert) { var done = assert.async(); var person, mafiaFamily; + if (isEnabled('ds-overhaul-references')) { + assert.expectDeprecation('BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set(\'relationshipName\', value)` instead.') + } env.registry.register('model:mafia-family', Family.extend()); run(function() { diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 991e2756299..fd99b33fa8a 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -147,8 +147,8 @@ test("normalizeResponse with custom modelNameFromPayloadKey", function(assert) { }); }); -test("normalizeResponse with type and custom modelNameFromPayloadKey", function(assert) { - assert.expect(2); +testInDebug("normalizeResponse with type and custom modelNameFromPayloadKey", function(assert) { + assert.expect(isEnabled("ds-payload-type-hooks") ? 3 : 2); var homePlanetNormalizeCount = 0; @@ -168,6 +168,10 @@ test("normalizeResponse with type and custom modelNameFromPayloadKey", function( }; var array; + + if (isEnabled("ds-payload-type-hooks")) { + assert.expectDeprecation('You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This is has been deprecated in favor of modelNameFromPayloadType'); + } run(function() { array = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, '1', 'findAll'); }); From c93c7695d6b91239c9db1ba66a98ca8fe41fbe3e Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 18 Nov 2016 14:49:08 -0800 Subject: [PATCH 1707/2527] fix mock server --- server/models/baz.js | 4 ++-- server/models/complex.js | 4 ++-- server/models/foo.js | 4 ++-- server/models/heavy-baz.js | 4 ++-- server/models/heavy-foo.js | 4 ++-- server/models/heavy.js | 4 ++-- server/models/simple.js | 4 ++-- server/scenarios/default.js | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/server/models/baz.js b/server/models/baz.js index 66435e61a3d..c8d20ae2979 100644 --- a/server/models/baz.js +++ b/server/models/baz.js @@ -1,8 +1,8 @@ var faker = require('faker'); -var props = require('../store/props'); +var props = require('json-api-mock-server/lib/store/props'); var attr = props.attr; var one = props.one; -var between = require('../utils/between'); +var between = require('json-api-mock-server/lib/utils/between'); module.exports = { name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), diff --git a/server/models/complex.js b/server/models/complex.js index 1a7d238c531..48449179d54 100644 --- a/server/models/complex.js +++ b/server/models/complex.js @@ -1,9 +1,9 @@ var faker = require('faker'); -var props = require('../store/props'); +var props = require('json-api-mock-server/lib/store/props'); var attr = props.attr; var many = props.many; var one = props.one; -var between = require('../utils/between'); +var between = require('json-api-mock-server/lib/utils/between'); module.exports = { name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), diff --git a/server/models/foo.js b/server/models/foo.js index b358ca037b2..5a4988da31d 100644 --- a/server/models/foo.js +++ b/server/models/foo.js @@ -1,8 +1,8 @@ var faker = require('faker'); -var props = require('../store/props'); +var props = require('json-api-mock-server/lib/store/props'); var attr = props.attr; var one = props.one; -var between = require('../utils/between'); +var between = require('json-api-mock-server/lib/utils/between'); module.exports = { name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), diff --git a/server/models/heavy-baz.js b/server/models/heavy-baz.js index 5fe43bde274..3e4de0f4d48 100644 --- a/server/models/heavy-baz.js +++ b/server/models/heavy-baz.js @@ -1,9 +1,9 @@ var faker = require('faker'); -var props = require('../store/props'); +var props = require('json-api-mock-server/lib/store/props'); var attr = props.attr; var one = props.one; var many = props.many; -var between = require('../utils/between'); +var between = require('json-api-mock-server/lib/utils/between'); module.exports = { name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), diff --git a/server/models/heavy-foo.js b/server/models/heavy-foo.js index 24e3e285438..af67f260353 100644 --- a/server/models/heavy-foo.js +++ b/server/models/heavy-foo.js @@ -1,8 +1,8 @@ var faker = require('faker'); -var props = require('../store/props'); +var props = require('json-api-mock-server/lib/store/props'); var attr = props.attr; var one = props.one; -var between = require('../utils/between'); +var between = require('json-api-mock-server/lib/utils/between'); module.exports = { name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), diff --git a/server/models/heavy.js b/server/models/heavy.js index 8ce6bb52b4b..c521ac6677f 100644 --- a/server/models/heavy.js +++ b/server/models/heavy.js @@ -1,9 +1,9 @@ var faker = require('faker'); -var props = require('../store/props'); +var props = require('json-api-mock-server/lib/store/props'); var attr = props.attr; var many = props.many; var one = props.one; -var between = require('../utils/between'); +var between = require('json-api-mock-server/lib/utils/between'); module.exports = { name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), diff --git a/server/models/simple.js b/server/models/simple.js index 689e0690ff0..9e4806eba14 100644 --- a/server/models/simple.js +++ b/server/models/simple.js @@ -1,7 +1,7 @@ var faker = require('faker'); -var props = require('../store/props'); +var props = require('json-api-mock-server/lib/store/props'); var attr = props.attr; -var between = require('../utils/between'); +var between = require('json-api-mock-server/lib/utils/between'); module.exports = { title: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), diff --git a/server/scenarios/default.js b/server/scenarios/default.js index 954423e0102..930772c8dea 100644 --- a/server/scenarios/default.js +++ b/server/scenarios/default.js @@ -1,5 +1,5 @@ module.exports = function(store) { - store.seed('simple', 240); + store.seed('simple', 10000); // 240 store.seed('complex', 35); store.seed('heavy', 14); }; From fdf56b79d6035c4be191a8fbf26d29da7a9afbca Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Sun, 20 Nov 2016 02:30:17 +0000 Subject: [PATCH 1708/2527] Removes Ember.K from codebase (#4670) --- addon/-private/system/model/model.js | 16 ++++++++-------- addon/serializers/json.js | 2 +- app/initializers/data-adapter.js | 2 +- app/initializers/injectStore.js | 2 +- app/initializers/store.js | 2 +- app/initializers/transforms.js | 2 +- tests/integration/records/delete-record-test.js | 6 +++--- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 646ca33fdaa..6fe3fbaf541 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -430,56 +430,56 @@ var Model = Ember.Object.extend(Ember.Evented, { @event ready */ - ready: Ember.K, + ready() {}, /** Fired when the record is loaded from the server. @event didLoad */ - didLoad: Ember.K, + didLoad() {}, /** Fired when the record is updated. @event didUpdate */ - didUpdate: Ember.K, + didUpdate() {}, /** Fired when a new record is commited to the server. @event didCreate */ - didCreate: Ember.K, + didCreate() {}, /** Fired when the record is deleted. @event didDelete */ - didDelete: Ember.K, + didDelete() {}, /** Fired when the record becomes invalid. @event becameInvalid */ - becameInvalid: Ember.K, + becameInvalid() {}, /** Fired when the record enters the error state. @event becameError */ - becameError: Ember.K, + becameError() {}, /** Fired when the record is rolled back. @event rolledBack */ - rolledBack: Ember.K, + rolledBack() {}, //TODO Do we want to deprecate these? /** diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 5ab4ad7c27a..fe0b6a46c91 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1286,7 +1286,7 @@ var JSONSerializer = Serializer.extend({ @param {Object} json @param {Object} relationship */ - serializePolymorphicType: Ember.K, + serializePolymorphicType() {}, /** `extractMeta` is used to deserialize any meta information in the diff --git a/app/initializers/data-adapter.js b/app/initializers/data-adapter.js index 3cc5b9ba27a..f7447138eb8 100644 --- a/app/initializers/data-adapter.js +++ b/app/initializers/data-adapter.js @@ -10,5 +10,5 @@ import Ember from 'ember'; export default { name: 'data-adapter', before: 'store', - initialize: Ember.K + initialize() {} }; diff --git a/app/initializers/injectStore.js b/app/initializers/injectStore.js index 354080e6105..7494c510b2d 100644 --- a/app/initializers/injectStore.js +++ b/app/initializers/injectStore.js @@ -10,5 +10,5 @@ import Ember from 'ember'; export default { name: 'injectStore', before: 'store', - initialize: Ember.K + initialize() {} }; diff --git a/app/initializers/store.js b/app/initializers/store.js index d98880c77ee..5c497439bca 100644 --- a/app/initializers/store.js +++ b/app/initializers/store.js @@ -10,5 +10,5 @@ import Ember from 'ember'; export default { name: 'store', after: 'ember-data', - initialize: Ember.K + initialize() {} }; diff --git a/app/initializers/transforms.js b/app/initializers/transforms.js index c2fb02097cc..769e191e518 100644 --- a/app/initializers/transforms.js +++ b/app/initializers/transforms.js @@ -10,5 +10,5 @@ import Ember from 'ember'; export default { name: 'transforms', before: 'store', - initialize: Ember.K + initialize() {} }; diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index 9da101ea2db..acade17ec63 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -1,4 +1,4 @@ -/*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(adam|dave|cersei)" }]*/ +3/*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(adam|dave|cersei)" }]*/ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; @@ -232,7 +232,7 @@ test("Deleting an invalid newly created record should remove it from the store", run(function() { record = store.createRecord('person', { name: 'pablobm' }); // Invalidate the record to put it in the `root.loaded.created.invalid` state - record.save().catch(Ember.K); + record.save().catch(() => {}); }); // Preconditions @@ -272,7 +272,7 @@ test("Destroying an invalid newly created record should remove it from the store run(function() { record = store.createRecord('person', { name: 'pablobm' }); // Invalidate the record to put it in the `root.loaded.created.invalid` state - record.save().catch(Ember.K); + record.save().catch(() => {}); }); // Preconditions From cd1cb30eb96410eda74f57eda4a652dbfbde16c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Duque?= Date: Sun, 20 Nov 2016 09:38:56 +0000 Subject: [PATCH 1709/2527] Fix typo in delete-record-test This slipped in https://github.com/emberjs/data/pull/4670 --- tests/integration/records/delete-record-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index acade17ec63..78d90206222 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -1,4 +1,4 @@ -3/*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(adam|dave|cersei)" }]*/ +/*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(adam|dave|cersei)" }]*/ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; From 1a9dee614b1282f997aae20ed66d3c00fe1c0dd0 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 9 Nov 2016 15:55:01 -0500 Subject: [PATCH 1710/2527] Add a missing example to the ManyArray api docs --- addon/-private/system/many-array.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index a79d590ee24..53b4383b18b 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -227,6 +227,25 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { }, /** + Reloads all of the records in the manyArray. If the manyArray + holds a relationship that was originally fetched using a links url + Ember Data will revisit the original links url to repopulate the + relationship. + + If the manyArray holds the result of a `store.query()` reload will + re-run the original query. + + Example + + ```javascript + var user = store.peekRecord('user', 1) + user.login().then(function() { + user.get('permissions').then(function(permissions) { + return permissions.reload(); + }); + }); + ``` + @method reload @public */ From 2ab5e73169c3f60532415b5cac653d74a784e42f Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Thu, 20 Oct 2016 14:58:44 +0300 Subject: [PATCH 1711/2527] Move most of store.setupRelationships() to relationship.push() - Improve related link tests --- .../system/relationships/state/belongs-to.js | 7 +- .../system/relationships/state/has-many.js | 5 + .../relationships/state/relationship.js | 70 +++++++-- addon/-private/system/store.js | 89 +++--------- .../relationships/belongs-to-test.js | 134 +++++++++++++++++- 5 files changed, 224 insertions(+), 81 deletions(-) diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 9ac3db807f9..4679524fb24 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -37,8 +37,6 @@ BelongsToRelationship.prototype.setCanonicalRecord = function(newRecord) { this.removeCanonicalRecord(this.canonicalState); } this.flushCanonicalLater(); - this.setHasData(true); - this.setHasLoaded(true); }; BelongsToRelationship.prototype._super$addCanonicalRecord = Relationship.prototype.addCanonicalRecord; @@ -162,3 +160,8 @@ BelongsToRelationship.prototype.reload = function() { return this.findRecord(); }; + +BelongsToRelationship.prototype.updateData = function(data) { + let internalModel = this.store._pushResourceIdentity(this, data); + this.setCanonicalRecord(internalModel); +}; diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 3314a350a43..65410985e5a 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -230,6 +230,11 @@ ManyRelationship.prototype.getRecords = function() { } }; +ManyRelationship.prototype.updateData = function(data) { + let internalModels = this.store._pushResourceIdentities(this, data); + this.updateRecordsFromAdapter(internalModels); +}; + function setForArray(array) { var set = new OrderedSet(); diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 651eed61162..4e27dc4ec1e 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -1,6 +1,7 @@ /* global heimdall */ import { assert, warn } from "ember-data/-private/debug"; import OrderedSet from "ember-data/-private/system/ordered-set"; +import _normalizeLink from "ember-data/-private/system/normalize-link"; const { addCanonicalRecord, @@ -12,6 +13,7 @@ const { flushCanonical, flushCanonicalLater, newRelationship, + push, removeCanonicalRecord, removeCanonicalRecordFromInverse, removeCanonicalRecordFromOwn, @@ -35,6 +37,7 @@ const { 'flushCanonical', 'flushCanonicalLater', 'newRelationship', + 'push', 'removeCanonicalRecord', 'removeCanonicalRecordFromInverse', 'removeCanonicalRecordFromOwn', @@ -256,12 +259,10 @@ Relationship.prototype = { id: 'ds.store.push-link-for-sync-relationship' }); assert("You have pushed a record of type '" + this.record.type.modelName + "' with '" + this.key + "' as a link, but the value of that link is not a string.", typeof link === 'string' || link === null); - if (link !== this.link) { - this.link = link; - this.linkPromise = null; - this.setHasLoaded(false); - this.record.notifyPropertyChange(this.key); - } + + this.link = link; + this.linkPromise = null; + this.record.notifyPropertyChange(this.key); }, findLink() { @@ -280,8 +281,6 @@ Relationship.prototype = { //TODO(Igor) move this to a proper place //TODO Once we have adapter support, we need to handle updated and canonical changes this.computeChanges(records); - this.setHasData(true); - this.setHasLoaded(true); }, notifyRecordRelationshipAdded() { }, @@ -315,5 +314,58 @@ Relationship.prototype = { setHasLoaded(value) { heimdall.increment(setHasLoaded); this.hasLoaded = value; - } + }, + + /* + `push` for a relationship allows the store to push a JSON API Relationship + Object onto the relationship. The relationship will then extract and set the + meta, data and links of that relationship. + + `push` use `updateMeta`, `updateData` and `updateLink` to update the state + of the relationship. + */ + push(payload) { + heimdall.increment(push); + + let hasData = false; + let hasLink = false; + + if (payload.meta) { + this.updateMeta(payload.meta); + } + + if (payload.data !== undefined) { + hasData = true; + this.updateData(payload.data); + } + + if (payload.links && payload.links.related) { + let relatedLink = _normalizeLink(payload.links.related); + if (relatedLink && relatedLink.href && relatedLink.href !== this.link) { + hasLink = true; + this.updateLink(relatedLink.href); + } + } + + /* + Data being pushed into the relationship might contain only data or links, + or a combination of both. + + If we got data we want to set both hasData and hasLoaded to true since + this would indicate that we should prefer the local state instead of + trying to fetch the link or call findRecord(). + + If we have no data but a link is present we want to set hasLoaded to false + without modifying the hasData flag. This will ensure we fetch the updated + link next time the relationship is accessed. + */ + if (hasData) { + this.setHasData(true); + this.setHasLoaded(true); + } else if (hasLink) { + this.setHasLoaded(false); + } + }, + + updateData() {} }; diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 48dbf07fd77..c8f8ba6dcdd 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -5,7 +5,6 @@ import Ember from 'ember'; import Model from 'ember-data/model'; import { instrument, assert, deprecate, warn, runInDebug } from "ember-data/-private/debug"; -import _normalizeLink from "ember-data/-private/system/normalize-link"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; import { InvalidError } from 'ember-data/adapters/errors'; @@ -2611,34 +2610,33 @@ Store = Service.extend({ this._instanceCache.destroy(); this.unloadAll(); - } -}); + }, -function deserializeRecordId(store, key, relationship, id) { - if (isNone(id)) { - return; - } + _pushResourceIdentity(relationship, resourceIdentity) { + if (isNone(resourceIdentity)) { + return; + } - assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being ${inspect(id)}, but ${key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(id)); + assert(`A ${relationship.parentType} record was pushed into the store with the value of ${relationship.key} being ${inspect(resourceIdentity)}, but ${relationship.key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(resourceIdentity)); - //TODO:Better asserts - return store._internalModelForId(id.type, id.id); -} + //TODO:Better asserts + return this._internalModelForId(resourceIdentity.type, resourceIdentity.id); + }, -function deserializeRecordIds(store, key, relationship, ids) { - if (isNone(ids)) { - return; - } + _pushResourceIdentities(relationship, resourceIdentities) { + if (isNone(resourceIdentities)) { + return; + } - assert(`A ${relationship.parentType} record was pushed into the store with the value of ${key} being '${inspect(ids)}', but ${key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(ids)); - let _ids = new Array(ids.length); + assert(`A ${relationship.parentType} record was pushed into the store with the value of ${relationship.key} being '${inspect(resourceIdentities)}', but ${relationship.key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(resourceIdentities)); - for (let i = 0; i < ids.length; i++) { - _ids[i] = deserializeRecordId(store, key, relationship, ids[i]); + let _internalModels = new Array(resourceIdentities.length); + for (let i = 0; i < resourceIdentities.length; i++) { + _internalModels[i] = this._pushResourceIdentity(relationship, resourceIdentities[i]); + } + return _internalModels; } - - return _ids; -} +}); // Delegation to the adapter and promise management @@ -2697,57 +2695,14 @@ function setupRelationships(store, record, data) { } record.type.eachRelationship((key, descriptor) => { - let kind = descriptor.kind; - if (!data.relationships[key]) { return; } - let relationship; - - if (data.relationships[key].links && data.relationships[key].links.related) { - let relatedLink = _normalizeLink(data.relationships[key].links.related); - if (relatedLink && relatedLink.href) { - relationship = record._relationships.get(key); - relationship.updateLink(relatedLink.href); - } - } - - if (data.relationships[key].meta) { - relationship = record._relationships.get(key); - relationship.updateMeta(data.relationships[key].meta); - } - - // If the data contains a relationship that is specified as an ID (or IDs), - // normalizeRelationship will convert them into DS.Model instances - // (possibly unloaded) before we push the payload into the store. - normalizeRelationship(store, key, descriptor, data.relationships[key]); - - let value = data.relationships[key].data; - - if (value !== undefined) { - if (kind === 'belongsTo') { - relationship = record._relationships.get(key); - relationship.setCanonicalRecord(value); - } else if (kind === 'hasMany') { - relationship = record._relationships.get(key); - relationship.updateRecordsFromAdapter(value); - } - } + let relationship = record._relationships.get(key); + relationship.push(data.relationships[key]); }); } -function normalizeRelationship(store, key, relationship, jsonPayload) { - let data = jsonPayload.data; - if (data) { - let kind = relationship.kind; - if (kind === 'belongsTo') { - jsonPayload.data = deserializeRecordId(store, key, relationship, data); - } else if (kind === 'hasMany') { - jsonPayload.data = deserializeRecordIds(store, key, relationship, data); - } - } -} - export { Store }; export default Store; diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index c1695bc2e87..b7625e5566f 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1052,7 +1052,7 @@ test("Local data should take precedence over related link", function(assert) { }); }); -test("Updated related link should take precedence over local data", function(assert) { +test("New related link should take precedence over local data", function(assert) { assert.expect(3); Book.reopen({ @@ -1060,7 +1060,7 @@ test("Updated related link should take precedence over local data", function(ass }); env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { - assert.equal(url, 'author-updated-link', 'url is correct'); + assert.equal(url, 'author-new-link', 'url is correct'); assert.ok(true, "The adapter's findBelongsTo method should be called"); return Ember.RSVP.resolve( { id: 1, name: 'This is author' } @@ -1071,6 +1071,61 @@ test("Updated related link should take precedence over local data", function(ass assert.ok(false, "The adapter's findRecord method should not be called"); }; + run(function() { + let book = env.store.push({ + data: { + type: 'book', + id: '1', + relationships: { + author: { + data: { + type: 'author', + id: '1' + } + } + } + } + }); + + env.store.push({ + data: { + type: 'book', + id: '1', + relationships: { + author: { + links: { + related: 'author-new-link' + } + } + } + } + }); + + book.get('author').then((author) => { + assert.equal(author.get('name'), 'This is author', 'author name is correct'); + }); + }); +}); + +test("Updated related link should take precedence over local data", function(assert) { + assert.expect(4); + + Book.reopen({ + author: DS.belongsTo('author', { async: true }) + }); + + env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { + assert.equal(url, 'author-updated-link', 'url is correct'); + assert.ok(true, "The adapter's findBelongsTo method should be called"); + return Ember.RSVP.resolve( + { id: 1, name: 'This is updated author' } + ); + }; + + env.adapter.findRecord = function(store, type, id, snapshot) { + assert.ok(false, "The adapter's findRecord method should not be called"); + }; + run(function() { let book = env.store.push({ data: { @@ -1084,7 +1139,18 @@ test("Updated related link should take precedence over local data", function(ass data: { type: 'author', id: '1' } } } - } + }, + included: [{ + type: 'author', + id: '1', + attributes: { + name: 'This is author' + } + }] + }); + + book.get('author').then((author) => { + assert.equal(author.get('name'), 'This is author', 'author name is correct'); }); env.store.push({ @@ -1101,6 +1167,68 @@ test("Updated related link should take precedence over local data", function(ass } }); + book.get('author').then((author) => { + assert.equal(author.get('name'), 'This is updated author', 'author name is correct'); + }); + }); +}); + +test("Updated identical related link should not take precedence over local data", function(assert) { + assert.expect(2); + + Book.reopen({ + author: DS.belongsTo('author', { async: true }) + }); + + env.adapter.findBelongsTo = function() { + assert.ok(false, "The adapter's findBelongsTo method should not be called"); + }; + + env.adapter.findRecord = function() { + assert.ok(false, "The adapter's findRecord method should not be called"); + }; + + run(function() { + let book = env.store.push({ + data: { + type: 'book', + id: '1', + relationships: { + author: { + links: { + related: 'author' + }, + data: { type: 'author', id: '1' } + } + } + }, + included: [{ + type: 'author', + id: '1', + attributes: { + name: 'This is author' + } + }] + }); + + book.get('author').then((author) => { + assert.equal(author.get('name'), 'This is author', 'author name is correct'); + }); + + env.store.push({ + data: { + type: 'book', + id: '1', + relationships: { + author: { + links: { + related: 'author' + } + } + } + } + }); + book.get('author').then((author) => { assert.equal(author.get('name'), 'This is author', 'author name is correct'); }); From ae7e8ab308f91efbcc598c7d06ab0409b9e2c23b Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 11 Nov 2016 14:56:26 -0500 Subject: [PATCH 1712/2527] Add API docs for the HasManyReference --- addon/-private/system/model/model.js | 35 ++- addon/-private/system/references/has-many.js | 304 +++++++++++++++++++ 2 files changed, 324 insertions(+), 15 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 6fe3fbaf541..fdd239ef614 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -830,18 +830,21 @@ var Model = Ember.Object.extend(Ember.Evented, { Example - ```javascript - // models/blog.js + ```app/models/blog.js export default DS.Model.extend({ user: DS.belongsTo({ async: true }) }); + ``` + ```javascript var blog = store.push({ - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } } } }); @@ -899,14 +902,16 @@ var Model = Ember.Object.extend(Ember.Evented, { }); var blog = store.push({ - type: 'blog', - id: 1, - relationships: { - comments: { - data: [ - { type: 'comment', id: 1 }, - { type: 'comment', id: 2 } - ] + data: { + type: 'blog', + id: 1, + relationships: { + comments: { + data: [ + { type: 'comment', id: 1 }, + { type: 'comment', id: 2 } + ] + } } } }); diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index de18a83ab2b..a92d9dca0c2 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -13,6 +13,13 @@ const { get } = Ember; +/** + A HasManyReference is a low level API that allows users and addon + author to perform meta-operations on a has-many relationship. + + @class HasManyReference + @namespace DS +*/ var HasManyReference = function(store, parentInternalModel, hasManyRelationship) { this._super$constructor(store, parentInternalModel); this.hasManyRelationship = hasManyRelationship; @@ -26,6 +33,45 @@ HasManyReference.prototype = Object.create(Reference.prototype); HasManyReference.prototype.constructor = HasManyReference; HasManyReference.prototype._super$constructor = Reference; +/** + This returns a string that represents how the reference will be + looked up when it is loaded. If the relationship has a link it will + use the "link" otherwise it defaults to "id". + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + var post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + var commentsRef = post.hasMany('comments'); + + // get the identifier of the reference + if (commentsRef.remoteType() === "ids") { + var ids = commentsRef.ids(); + } else if (commentsRef.remoteType() === "link") { + var link = commentsRef.link(); + } + ``` + + @method remoteType + @return {String} The name of the remote type. This should either be "link" or "ids" +*/ HasManyReference.prototype.remoteType = function() { if (this.hasManyRelationship.link) { return "link"; @@ -34,10 +80,77 @@ HasManyReference.prototype.remoteType = function() { return "ids"; }; +/** + The link Ember Data will use to fetch or reload this has-many + relationship. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + var post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + links: { + related: '/posts/1/comments' + } + } + } + } + }); + + var commentsRef = post.hasMany('comments'); + + commentsRef.link(); // '/posts/1/comments' + ``` + + @method link + @return {String} The link Ember Data will use to fetch or reload this has-many relationship. +*/ HasManyReference.prototype.link = function() { return this.hasManyRelationship.link; }; +/** + `ids()` returns an array of the record ids in this relationship. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + var post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + var commentsRef = post.hasMany('comments'); + + commentsRef.ids(); // ['1'] + ``` + + @method remoteType + @return {Array} The ids in this has-many relationship +*/ HasManyReference.prototype.ids = function() { let members = this.hasManyRelationship.members.toArray(); @@ -46,10 +159,92 @@ HasManyReference.prototype.ids = function() { }); }; +/** + The link Ember Data will use to fetch or reload this has-many + relationship. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + var post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + links: { + related: { + href: '/posts/1/comments', + meta: { + count: 10 + } + } + } + } + } + } + }); + + var commentsRef = post.hasMany('comments'); + + commentsRef.meta(); // { count: 10 } + ``` + + @method meta + @return {Object} The meta information for the has-many relationship. +*/ HasManyReference.prototype.meta = function() { return this.hasManyRelationship.meta; }; +/** + `push` can be used to update the data in the relationship and Ember + Data will treat the new data as the canonical value of this + relationship on the backend. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ``` + var post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + var commentsRef = post.hasMany('comments'); + + commentsRef.ids(); // ['1'] + + commentsRef.push([ + [{ type: 'comment', id: 2 }], + [{ type: 'comment', id: 3 }], + ]) + + commentsRef.ids(); // ['2', '3'] + ``` + + @method push + @param {Array|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. + @return {DS.ManyArray} +*/ HasManyReference.prototype.push = function(objectOrPromise) { return resolve(objectOrPromise).then((payload) => { var array = payload; @@ -121,6 +316,44 @@ HasManyReference.prototype._isLoaded = function() { }); }; +/** + `value()` sycronously returns the current value of the has-many + relationship. Unlike `record.get('relationshipName')`, calling + `value()` on a reference does not trigger a fetch if the async + relationship is not yet loaded. If the relationship is not loaded + it will always return `null`. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + var post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + var commentsRef = post.hasMany('comments'); + + post.get('comments').then(function(comments) { + commentsRef.value() === comments + }) + ``` + + @method value + @return {DS.ManyArray} +*/ HasManyReference.prototype.value = function() { if (this._isLoaded()) { return this.hasManyRelationship.getManyArray(); @@ -129,6 +362,43 @@ HasManyReference.prototype.value = function() { return null; }; +/** + Loads the relationship if it is not already loaded. If the + relationship is already loaded this method does not trigger a new + load. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + var post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + var commentsRef = post.hasMany('comments'); + + commentsRef.load().then(function(comments) { + //... + }); + ``` + + @method load + @return {Promise} a promise that resolves with the ManyArray in + this has-many relationship. +*/ HasManyReference.prototype.load = function() { if (!this._isLoaded()) { return this.hasManyRelationship.getRecords(); @@ -137,6 +407,40 @@ HasManyReference.prototype.load = function() { return resolve(this.hasManyRelationship.getManyArray()); }; +/** + Reloads this has-many relationship. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + var post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + var commentsRef = post.hasMany('comments'); + + commentsRef.reload().then(function(comments) { + //... + }); + ``` + + @method reload + @return {Promise} a promise that resolves with the ManyArray in this has-many relationship. +*/ HasManyReference.prototype.reload = function() { return this.hasManyRelationship.reload(); }; From 223767fa0011cb0e6e84e15997e8470b3dfa6d2f Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 15 Nov 2016 15:10:15 -0500 Subject: [PATCH 1713/2527] Deprecate unused initializers --- .../initialize-store-service.js | 51 +++++++++++++++++-- tests/integration/application-test.js | 31 ++++++----- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/addon/-private/instance-initializers/initialize-store-service.js b/addon/-private/instance-initializers/initialize-store-service.js index b2d9fa1ec99..ed4e8b92af4 100644 --- a/addon/-private/instance-initializers/initialize-store-service.js +++ b/addon/-private/instance-initializers/initialize-store-service.js @@ -1,12 +1,53 @@ +import { deprecate } from 'ember-data/-private/debug'; /* - Configures a registry for use with an Ember-Data - store. + Configures a registry for use with an Ember-Data + store. - @method initializeStoreService - @param {Ember.ApplicationInstance} applicationOrRegistry - */ + @method initializeStoreService + @param {Ember.ApplicationInstance} applicationOrRegistry +*/ export default function initializeStoreService(application) { var container = application.lookup ? application : application.container; // Eagerly generate the store so defaultStore is populated. container.lookup('service:store'); + + let initializers = application.application.constructor.initializers; + deprecateOldEmberDataInitializers(initializers) +} + + + +let deprecatedInitializerNames = ['data-adapter', 'injectStore', 'transforms', 'store']; + +function matchesDeprecatedInititalizer(name) { + return deprecatedInitializerNames.indexOf(name) !== -1; +} + +function deprecateOldEmberDataInitializers(initializers) { + // collect all of the initializers + let initializersArray = Object.keys(initializers).map(key => initializers[key]); + + // filter out all of the Ember Data initializer. We have some + // deprecated initializers that depend on other deprecated + // initializers which may trigger the deprecation warning + // unintentionally. + let nonEmberDataInitializers = initializersArray.filter((initializer) => { + return !matchesDeprecatedInititalizer(initializer.name) + }) + + nonEmberDataInitializers.forEach(warnForDeprecatedInitializers) +} + +function warnForDeprecatedInitializers(initializer) { + var deprecatedBeforeInitializer = matchesDeprecatedInititalizer(initializer.before) + var deprecatedAfterInitializer = matchesDeprecatedInititalizer(initializer.after) + let deprecatedProp = deprecatedBeforeInitializer ? 'before' : 'after' + + deprecate( + `The initializer \`${initializer[deprecatedProp]}\` has been deprecated. Please update your \`${initializer.name}\` initializer to use use \`${deprecatedProp}: \'ember-data\'\` instead.`, + !(deprecatedBeforeInitializer || deprecatedAfterInitializer), + { + id: 'ds.deprecated-initializers', + until: '3.0.0' + }) } diff --git a/tests/integration/application-test.js b/tests/integration/application-test.js index 519d359c2fa..43316c3bd41 100644 --- a/tests/integration/application-test.js +++ b/tests/integration/application-test.js @@ -1,4 +1,5 @@ import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; @@ -182,7 +183,7 @@ test("ember-data initializer does not register the store service when it was alr }); -test("store initializer is run (DEPRECATED)", function(assert) { +testInDebug("store initializer is run (DEPRECATED)", function(assert) { var ran = false; App.initializer({ name: "after-store", @@ -190,14 +191,16 @@ test("store initializer is run (DEPRECATED)", function(assert) { initialize() { ran = true; } }); - run(function() { - app = App.create(); - }); + assert.expectDeprecation(function() { + run(function() { + app = App.create(); + }); + }, /The initializer `store` has been deprecated/) assert.ok(ran, 'store initializer was found'); }); -test("injectStore initializer is run (DEPRECATED)", function(assert) { +testInDebug("injectStore initializer is run (DEPRECATED)", function(assert) { var ran = false; App.initializer({ name: "after-store", @@ -205,14 +208,16 @@ test("injectStore initializer is run (DEPRECATED)", function(assert) { initialize() { ran = true; } }); - run(function() { - app = App.create(); - }); + assert.expectDeprecation(function() { + run(function() { + app = App.create(); + }); + }, /The initializer `injectStore` has been deprecated/) assert.ok(ran, 'injectStore initializer was found'); }); -test("transforms initializer is run (DEPRECATED)", function(assert) { +testInDebug("transforms initializer is run (DEPRECATED)", function(assert) { var ran = false; App.initializer({ name: "after-store", @@ -220,9 +225,11 @@ test("transforms initializer is run (DEPRECATED)", function(assert) { initialize() { ran = true; } }); - run(function() { - app = App.create(); - }); + assert.expectDeprecation(function() { + run(function() { + app = App.create(); + }); + }, /The initializer `transforms` has been deprecated/) assert.ok(ran, 'transforms initializer was found'); }); From 4e256dc85e17b2e05b6b705be3780f30bc8f1967 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 14 Nov 2016 11:55:31 -0500 Subject: [PATCH 1714/2527] Add some minor updates to the store documentation --- addon/-private/system/store.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 48dbf07fd77..2d2aabf5fb9 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -226,19 +226,23 @@ Store = Service.extend({ }, /** - The adapter to use to communicate to a backend server or other persistence layer. - - This can be specified as an instance, class, or string. + The default adapter to use to communicate to a backend server or + other persistence layer. This will be overridden by an application + adapter if present. If you want to specify `app/adapters/custom.js` as a string, do: ```js - adapter: 'custom' + import DS from 'ember-data'; + + export default DS.Store.extend({ + adapter: 'custom', + }); ``` @property adapter - @default DS.JSONAPIAdapter - @type {(DS.Adapter|String)} + @default '-json-api' + @type {String} */ adapter: '-json-api', @@ -1046,7 +1050,7 @@ Store = Service.extend({ ``` @method hasRecordForId - @param {(String|DS.Model)} modelName + @param {String} modelName @param {(String|Integer)} id @return {Boolean} */ From 5b0a772665aafba6aa1b3cf6eba21241ce132678 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 9 Nov 2016 16:57:59 -0500 Subject: [PATCH 1715/2527] Update the API docs for snapshots --- .../-private/system/snapshot-record-array.js | 93 ++++++++++++++++++- addon/-private/system/snapshot.js | 20 ++++ addon/-private/system/store.js | 1 - 3 files changed, 111 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/snapshot-record-array.js b/addon/-private/system/snapshot-record-array.js index ac76dd9498b..652f1bd1906 100644 --- a/addon/-private/system/snapshot-record-array.js +++ b/addon/-private/system/snapshot-record-array.js @@ -25,36 +25,125 @@ export default function SnapshotRecordArray(recordArray, meta, options = {}) { @type {Array} */ this._recordArray = recordArray; + /** Number of records in the array + + Example + + ```app/adapters/post.js + import DS from 'ember-data' + + export default DS.JSONAPIAdapter.extend({ + shouldReloadAll(store, snapshotRecordArray) { + return !snapshotRecordArray.length; + }, + }); + ``` + @property length @type {Number} */ this.length = recordArray.get('length'); + /** The type of the underlying records for the snapshots in the array, as a DS.Model @property type @type {DS.Model} */ this.type = recordArray.get('type'); + /** - Meta object + Meta objects for the record array. + + Example + + ```app/adapters/post.js + import DS from 'ember-data' + + export default DS.JSONAPIAdapter.extend({ + shouldReloadAll(store, snapshotRecordArray) { + var lastRequestTime = snapshotRecordArray.meta.lastRequestTime; + var twentyMinutes = 20 * 60 * 1000; + return Date.now() > lastRequestTime + twentyMinutes; + }, + }); + ``` + @property meta @type {Object} */ this.meta = meta; + /** - A hash of adapter options + A hash of adapter options passed into the store method for this request. + + Example + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + findAll(store, type, sinceToken, snapshotRecordArray) { + if (snapshotRecordArray.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + @property adapterOptions @type {Object} */ this.adapterOptions = options.adapterOptions; + /** + The relationships to include for this request. + + Example + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + findAll(store, type, snapshotRecordArray) { + var url = `/${type.modelName}?include=${encodeURIComponent(snapshotRecordArray.include)}`; + + return fetch(url).then((response) => response.json()) + } + }); + + @property include + @type {String|Array} + */ this.include = options.include; } /** Get snapshots of the underlying record array + + Example + + ```app/adapters/post.js + import DS from 'ember-data' + + export default DS.JSONAPIAdapter.extend({ + shouldReloadAll(store, snapshotArray) { + var snapshots = snapshotArray.snapshots(); + + return snapshots.any(function(ticketSnapshot) { + var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt'), 'minutes'); + if (timeDiff > 20) { + return true; + } else { + return false; + } + }); + } + }); + ``` + @method snapshots @return {Array} Array of snapshots */ diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index cd206d1ade1..7194e9790ff 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -347,6 +347,26 @@ Snapshot.prototype = { }, /** + Serializes the snapshot using the serializer for the model. + + Example + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + createRecord(store, type, snapshot) { + var data = snapshot.serialize({ includeId: true }); + var url = `/${type.modelName}`; + + return fetch(url, { + method: 'POST', + body: data, + }).then((response) => response.json()) + } + }); + ``` + @method serialize @param {Object} options @return {Object} an object whose values are primitive JSON values only diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 3aa87f66e8f..a016cd22d25 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1450,7 +1450,6 @@ Store = Service.extend({ }); ``` - See [peekAll](#method_peekAll) to get an array of current records in the store, without waiting until a reload is finished. From 78a7fd51e0669ba7ed2a37974059ba649e8024c7 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Mon, 21 Nov 2016 08:48:15 -0500 Subject: [PATCH 1716/2527] Update `findHasMany` API docs --- addon/adapters/rest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index b307de551d4..4c0d3c0e50c 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -669,7 +669,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @method findHasMany @param {DS.Store} store @param {DS.Snapshot} snapshot - @param {DS.Snapshot} relationship snapshot of the hasMany relationship + @param {Object} relationship meta object describing the relationship @param {String} url @return {Promise} promise */ From 98171705baae99d2045afc6103f5bf908180e986 Mon Sep 17 00:00:00 2001 From: Christoffer Persson Date: Thu, 20 Oct 2016 14:59:49 +0300 Subject: [PATCH 1717/2527] Don't warn for 'async: false' relationships with link + data --- .../system/relationships/state/belongs-to.js | 2 +- .../system/relationships/state/has-many.js | 2 +- .../relationships/state/relationship.js | 2 +- addon/-private/system/store.js | 20 ++++---- tests/unit/store/push-test.js | 49 ++++++++++++++++--- 5 files changed, 55 insertions(+), 20 deletions(-) diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 4679524fb24..802708cc5b0 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -162,6 +162,6 @@ BelongsToRelationship.prototype.reload = function() { }; BelongsToRelationship.prototype.updateData = function(data) { - let internalModel = this.store._pushResourceIdentity(this, data); + let internalModel = this.store._pushResourceIdentifier(this, data); this.setCanonicalRecord(internalModel); }; diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 65410985e5a..76f790eb6e0 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -231,7 +231,7 @@ ManyRelationship.prototype.getRecords = function() { }; ManyRelationship.prototype.updateData = function(data) { - let internalModels = this.store._pushResourceIdentities(this, data); + let internalModels = this.store._pushResourceIdentifiers(this, data); this.updateRecordsFromAdapter(internalModels); }; diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 4e27dc4ec1e..7266ef6cb28 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -255,7 +255,7 @@ Relationship.prototype = { updateLink(link) { heimdall.increment(updateLink); - warn(`You have pushed a record of type '${this.record.type.modelName}' with '${this.key}' as a link, but the association is not an async relationship.`, this.isAsync, { + warn(`You pushed a record of type '${this.record.type.modelName}' with a relationship '${this.key}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, this.isAsync || this.hasData , { id: 'ds.store.push-link-for-sync-relationship' }); assert("You have pushed a record of type '" + this.record.type.modelName + "' with '" + this.key + "' as a link, but the value of that link is not a string.", typeof link === 'string' || link === null); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index c8f8ba6dcdd..4ecb15a2f5f 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2612,27 +2612,27 @@ Store = Service.extend({ this.unloadAll(); }, - _pushResourceIdentity(relationship, resourceIdentity) { - if (isNone(resourceIdentity)) { + _pushResourceIdentifier(relationship, resourceIdentifier) { + if (isNone(resourceIdentifier)) { return; } - assert(`A ${relationship.parentType} record was pushed into the store with the value of ${relationship.key} being ${inspect(resourceIdentity)}, but ${relationship.key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(resourceIdentity)); + assert(`A ${relationship.parentType} record was pushed into the store with the value of ${relationship.key} being ${inspect(resourceIdentifier)}, but ${relationship.key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(resourceIdentifier)); //TODO:Better asserts - return this._internalModelForId(resourceIdentity.type, resourceIdentity.id); + return this._internalModelForId(resourceIdentifier.type, resourceIdentifier.id); }, - _pushResourceIdentities(relationship, resourceIdentities) { - if (isNone(resourceIdentities)) { + _pushResourceIdentifiers(relationship, resourceIdentifiers) { + if (isNone(resourceIdentifiers)) { return; } - assert(`A ${relationship.parentType} record was pushed into the store with the value of ${relationship.key} being '${inspect(resourceIdentities)}', but ${relationship.key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(resourceIdentities)); + assert(`A ${relationship.parentType} record was pushed into the store with the value of ${relationship.key} being '${inspect(resourceIdentifiers)}', but ${relationship.key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(resourceIdentifiers)); - let _internalModels = new Array(resourceIdentities.length); - for (let i = 0; i < resourceIdentities.length; i++) { - _internalModels[i] = this._pushResourceIdentity(relationship, resourceIdentities[i]); + let _internalModels = new Array(resourceIdentifiers.length); + for (let i = 0; i < resourceIdentifiers.length; i++) { + _internalModels[i] = this._pushResourceIdentifier(relationship, resourceIdentifiers[i]); } return _internalModels; } diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index eaa29a0c2e2..c0864e9fb4c 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -483,21 +483,56 @@ test('calling push without data argument as an object raises an error', function }); }); -testInDebug('Calling push with a link for a non async relationship should warn', function(assert) { +testInDebug('Calling push with a link for a non async relationship should warn if no data', function(assert) { Person.reopen({ phoneNumbers: hasMany('phone-number', { async: false }) }); assert.expectWarning(function() { run(function() { - store.push(store.normalize('person', { - id: '1', - links: { - phoneNumbers: '/api/people/1/phone-numbers' + store.push({ + data: { + type: 'person', + id: '1', + relationships: { + phoneNumbers: { + links: { + related: '/api/people/1/phone-numbers' + } + } + } + } + }); + }); + }, /You pushed a record of type 'person' with a relationship 'phoneNumbers' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload./); +}); + +testInDebug('Calling push with a link for a non async relationship should not warn when data is present', function(assert) { + Person.reopen({ + phoneNumbers: hasMany('phone-number', { async: false }) + }); + + assert.expectNoWarning(function() { + run(function() { + store.push({ + data: { + type: 'person', + id: '1', + relationships: { + phoneNumbers: { + data: [ + { type: 'phone-number', id: '2' }, + { type: 'phone-number', id: '3' } + ], + links: { + related: '/api/people/1/phone-numbers' + } + } + } } - })); + }); }); - }, /You have pushed a record of type 'person' with 'phoneNumbers' as a link, but the association is not an async relationship./); + }); }); testInDebug('Calling push with an unknown model name throws an assertion error', function(assert) { From 483721a3650f5c2f53fe6ff6ffc375f0ea2f60a9 Mon Sep 17 00:00:00 2001 From: Petr Kosikhin Date: Mon, 21 Nov 2016 18:12:24 +0300 Subject: [PATCH 1718/2527] inverse:null relationships should check for underlying model presence at least in debug to avoid introducing potential bugs and display appropriate error messages. for performance those checks in prod should be disabled --- .../-private/system/relationships/state/create.js | 5 +++++ .../relationships/inverse-relationships-test.js | 14 ++++++++++++++ tests/unit/debug-test.js | 3 ++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index b5da724a921..14d97d4a670 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -2,6 +2,7 @@ import Ember from 'ember'; import ManyRelationship from "ember-data/-private/system/relationships/state/has-many"; import BelongsToRelationship from "ember-data/-private/system/relationships/state/belongs-to"; import EmptyObject from "ember-data/-private/system/empty-object"; +import { runInDebug } from 'ember-data/-private/debug'; var get = Ember.get; @@ -15,6 +16,10 @@ function createRelationshipFor(record, relationshipMeta, store) { let inverse = null; if (shouldFindInverse(relationshipMeta)) { inverse = record.type.inverseFor(relationshipMeta.key, store); + } else { + runInDebug(() => { + record.type.typeForRelationship(relationshipMeta.key, store); + }); } if (inverse) { diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index 3d26be599b2..f4b77941448 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -599,3 +599,17 @@ test("inverseFor is only called when inverse is not null", function(assert) { }); }); }); + +testInDebug("Inverse null relationships with models that don't exist throw a nice error", function(assert) { + User = DS.Model.extend({ + post: DS.belongsTo('post', { inverse: null }) + }); + + var env = setupStore({ user: User }); + + assert.throws(function() { + run(function() { + env.store.createRecord('user'); + }); + }, /No model was found for 'post'/); +}); diff --git a/tests/unit/debug-test.js b/tests/unit/debug-test.js index 97db31f7898..81d828113ea 100644 --- a/tests/unit/debug-test.js +++ b/tests/unit/debug-test.js @@ -66,7 +66,8 @@ test("_debugInfo supports arbitray relationship types", function(assert) { options: { inverse: null }, isRelationship: true, kind: 'customRelationship', - name: 'Custom Relationship' + name: 'Custom Relationship', + type: 'post' }) }); From f3c4e7aaebfa50da356bf223bc33abcfb2c333c1 Mon Sep 17 00:00:00 2001 From: Erwin Oegema Date: Thu, 24 Nov 2016 15:28:29 +0100 Subject: [PATCH 1719/2527] Remove unused helper function `normalizeAttributes` --- addon/serializers/json.js | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index fe0b6a46c91..02ac2db30d3 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -723,26 +723,6 @@ var JSONSerializer = Serializer.extend({ return normalizeModelName(key); }, - - /** - @method normalizeAttributes - @private - */ - normalizeAttributes(typeClass, hash) { - var payloadKey; - - if (this.keyForAttribute) { - typeClass.eachAttribute((key) => { - payloadKey = this.keyForAttribute(key, 'deserialize'); - if (key === payloadKey) { return; } - if (hash[payloadKey] === undefined) { return; } - - hash[key] = hash[payloadKey]; - delete hash[payloadKey]; - }); - } - }, - /** @method normalizeRelationships @private From d266a68c923c9a1999e8e2c3c62e249b85d611be Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 28 Nov 2016 12:02:27 -0500 Subject: [PATCH 1720/2527] Update changelog for the Ember Data 2.10.0 release --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a03620a89ae..5a1fe84af84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ ### Master +### Release 2.10.0 (November 28, 2016) +- [#4656](https://github.com/emberjs/data/pull/4656) [PERF backport to beta] fix sub-optimal compiler output ([#4655](https://github.com/emberjs/data/pull/4655)) +- [#4592](https://github.com/emberjs/data/pull/4592) [DOC] Add documentation for query#update() to refresh query +- [#4510](https://github.com/emberjs/data/pull/4510) Heimdall instrumentation +- [#4546](https://github.com/emberjs/data/pull/4546) Revert "Log an assertion if the response from createRecord does not have an i…" +- [#4553](https://github.com/emberjs/data/pull/4553) [DOCS] Fix store.unloadAll modelName param type +- [#4566](https://github.com/emberjs/data/pull/4566) Properly cleanup store and env in store integration test +- [#4574](https://github.com/emberjs/data/pull/4574) Move heimdalljs to dependencies +- [#4576](https://github.com/emberjs/data/pull/4576) [DOC] Update Readme to reflect new default adapter +- [#4578](https://github.com/emberjs/data/pull/4578) Improved null id assertions + ### Release 2.9.0 (October 18, 2016) - [#4577](https://github.com/emberjs/data/pull/4577) [DOC] fix typo - [#4529](https://github.com/emberjs/data/pull/4529) isUpdating should be true only if a reload happens From f76a96169e324c7a34af8cfb172d64ddccf0159b Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 28 Nov 2016 12:59:21 -0500 Subject: [PATCH 1721/2527] Bump version for 2.12.0 canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1a85a8ecc93..4488091a58d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.11.0-canary", + "version": "2.12.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From a946dce146dbe9dcdbbd0f481400ff8ca1635493 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 29 Nov 2016 14:18:44 -0800 Subject: [PATCH 1722/2527] modernize relationships --- .../system/relationships/state/belongs-to.js | 251 ++++++------ .../system/relationships/state/create.js | 48 ++- .../system/relationships/state/has-many.js | 372 +++++++++--------- .../relationships/state/relationship.js | 159 ++++---- 4 files changed, 417 insertions(+), 413 deletions(-) diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 802708cc5b0..2b6089d828a 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -5,163 +5,156 @@ import { } from "ember-data/-private/system/promise-proxies"; import { assertPolymorphicType } from "ember-data/-private/debug"; - import Relationship from "ember-data/-private/system/relationships/state/relationship"; -export default function BelongsToRelationship(store, record, inverseKey, relationshipMeta) { - this._super$constructor(store, record, inverseKey, relationshipMeta); - this.record = record; - this.key = relationshipMeta.key; - this.inverseRecord = null; - this.canonicalState = null; -} +export default class BelongsToRelationship extends Relationship { + constructor(store, internalModel, inverseKey, relationshipMeta) { + super(store, internalModel, inverseKey, relationshipMeta); + this.internalModel = internalModel; + this.key = relationshipMeta.key; + this.inverseRecord = null; + this.canonicalState = null; + } -BelongsToRelationship.prototype = Object.create(Relationship.prototype); -BelongsToRelationship.prototype.constructor = BelongsToRelationship; -BelongsToRelationship.prototype._super$constructor = Relationship; + setRecord(newRecord) { + if (newRecord) { + this.addRecord(newRecord); + } else if (this.inverseRecord) { + this.removeRecord(this.inverseRecord); + } + this.setHasData(true); + this.setHasLoaded(true); + } -BelongsToRelationship.prototype.setRecord = function(newRecord) { - if (newRecord) { - this.addRecord(newRecord); - } else if (this.inverseRecord) { - this.removeRecord(this.inverseRecord); + setCanonicalRecord(newRecord) { + if (newRecord) { + this.addCanonicalRecord(newRecord); + } else if (this.canonicalState) { + this.removeCanonicalRecord(this.canonicalState); + } + this.flushCanonicalLater(); } - this.setHasData(true); - this.setHasLoaded(true); -}; - -BelongsToRelationship.prototype.setCanonicalRecord = function(newRecord) { - if (newRecord) { - this.addCanonicalRecord(newRecord); - } else if (this.canonicalState) { - this.removeCanonicalRecord(this.canonicalState); + + addCanonicalRecord(newRecord) { + if (this.canonicalMembers.has(newRecord)) { return;} + + if (this.canonicalState) { + this.removeCanonicalRecord(this.canonicalState); + } + + this.canonicalState = newRecord; + super.addCanonicalRecord(newRecord); } - this.flushCanonicalLater(); -}; -BelongsToRelationship.prototype._super$addCanonicalRecord = Relationship.prototype.addCanonicalRecord; -BelongsToRelationship.prototype.addCanonicalRecord = function(newRecord) { - if (this.canonicalMembers.has(newRecord)) { return;} + flushCanonical() { + //temporary fix to not remove newly created records if server returned null. + //TODO remove once we have proper diffing + if (this.inverseRecord && this.inverseRecord.isNew() && !this.canonicalState) { + return; + } + if (this.inverseRecord !== this.canonicalState) { + this.inverseRecord = this.canonicalState; + this.internalModel.notifyBelongsToChanged(this.key); + } - if (this.canonicalState) { - this.removeCanonicalRecord(this.canonicalState); + super.flushCanonical(); } - this.canonicalState = newRecord; - this._super$addCanonicalRecord(newRecord); -}; + addRecord(newRecord) { + if (this.members.has(newRecord)) { return; } + + assertPolymorphicType(this.internalModel, this.relationshipMeta, newRecord); + + if (this.inverseRecord) { + this.removeRecord(this.inverseRecord); + } -BelongsToRelationship.prototype._super$flushCanonical = Relationship.prototype.flushCanonical; -BelongsToRelationship.prototype.flushCanonical = function() { - //temporary fix to not remove newly created records if server returned null. - //TODO remove once we have proper diffing - if (this.inverseRecord && this.inverseRecord.isNew() && !this.canonicalState) { - return; + this.inverseRecord = newRecord; + super.addRecord(newRecord); + this.internalModel.notifyBelongsToChanged(this.key); } - if (this.inverseRecord !== this.canonicalState) { - this.inverseRecord = this.canonicalState; - this.record.notifyBelongsToChanged(this.key); + + setRecordPromise(newPromise) { + var content = newPromise.get && newPromise.get('content'); + assert("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); + this.setRecord(content ? content._internalModel : content); } - this._super$flushCanonical(); -}; -BelongsToRelationship.prototype._super$addRecord = Relationship.prototype.addRecord; -BelongsToRelationship.prototype.addRecord = function(newRecord) { - if (this.members.has(newRecord)) { return;} + removeRecordFromOwn(record) { + if (!this.members.has(record)) { return;} + this.inverseRecord = null; + super.removeRecordFromOwn(record); + this.internalModel.notifyBelongsToChanged(this.key); + } - assertPolymorphicType(this.record, this.relationshipMeta, newRecord); + removeCanonicalRecordFromOwn(record) { + if (!this.canonicalMembers.has(record)) { return;} + this.canonicalState = null; + super.removeCanonicalRecordFromOwn(record); + } - if (this.inverseRecord) { - this.removeRecord(this.inverseRecord); + findRecord() { + if (this.inverseRecord) { + return this.store._findByInternalModel(this.inverseRecord); + } else { + return Ember.RSVP.Promise.resolve(null); + } } - this.inverseRecord = newRecord; - this._super$addRecord(newRecord); - this.record.notifyBelongsToChanged(this.key); -}; - -BelongsToRelationship.prototype.setRecordPromise = function(newPromise) { - var content = newPromise.get && newPromise.get('content'); - assert("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); - this.setRecord(content ? content._internalModel : content); -}; - -BelongsToRelationship.prototype._super$removeRecordFromOwn = Relationship.prototype.removeRecordFromOwn; -BelongsToRelationship.prototype.removeRecordFromOwn = function(record) { - if (!this.members.has(record)) { return;} - this.inverseRecord = null; - this._super$removeRecordFromOwn(record); - this.record.notifyBelongsToChanged(this.key); -}; - -BelongsToRelationship.prototype._super$removeCanonicalRecordFromOwn = Relationship.prototype.removeCanonicalRecordFromOwn; -BelongsToRelationship.prototype.removeCanonicalRecordFromOwn = function(record) { - if (!this.canonicalMembers.has(record)) { return;} - this.canonicalState = null; - this._super$removeCanonicalRecordFromOwn(record); -}; - -BelongsToRelationship.prototype.findRecord = function() { - if (this.inverseRecord) { - return this.store._findByInternalModel(this.inverseRecord); - } else { - return Ember.RSVP.Promise.resolve(null); + fetchLink() { + return this.store.findBelongsTo(this.internalModel, this.link, this.relationshipMeta).then((record) => { + if (record) { + this.addRecord(record); + } + return record; + }); } -}; -BelongsToRelationship.prototype.fetchLink = function() { - return this.store.findBelongsTo(this.record, this.link, this.relationshipMeta).then((record) => { - if (record) { - this.addRecord(record); - } - return record; - }); -}; - -BelongsToRelationship.prototype.getRecord = function() { - //TODO(Igor) flushCanonical here once our syncing is not stupid - if (this.isAsync) { - var promise; - if (this.link) { - if (this.hasLoaded) { - promise = this.findRecord(); + getRecord() { + //TODO(Igor) flushCanonical here once our syncing is not stupid + if (this.isAsync) { + var promise; + if (this.link) { + if (this.hasLoaded) { + promise = this.findRecord(); + } else { + promise = this.findLink().then(() => this.findRecord()); + } } else { - promise = this.findLink().then(() => this.findRecord()); + promise = this.findRecord(); } + + return PromiseObject.create({ + promise: promise, + content: this.inverseRecord ? this.inverseRecord.getRecord() : null + }); } else { - promise = this.findRecord(); + if (this.inverseRecord === null) { + return null; + } + var toReturn = this.inverseRecord.getRecord(); + assert("You looked up the '" + this.key + "' relationship on a '" + this.internalModel.modelName + "' with id " + this.internalModel.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); + return toReturn; } + } - return PromiseObject.create({ - promise: promise, - content: this.inverseRecord ? this.inverseRecord.getRecord() : null - }); - } else { - if (this.inverseRecord === null) { - return null; + reload() { + // TODO handle case when reload() is triggered multiple times + + if (this.link) { + return this.fetchLink(); } - var toReturn = this.inverseRecord.getRecord(); - assert("You looked up the '" + this.key + "' relationship on a '" + this.record.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); - return toReturn; - } -}; -BelongsToRelationship.prototype.reload = function() { - // TODO handle case when reload() is triggered multiple times + // reload record, if it is already loaded + if (this.inverseRecord && this.inverseRecord.hasRecord) { + return this.inverseRecord.record.reload(); + } - if (this.link) { - return this.fetchLink(); + return this.findRecord(); } - // reload record, if it is already loaded - if (this.inverseRecord && this.inverseRecord.hasRecord) { - return this.inverseRecord.record.reload(); + updateData(data) { + let internalModel = this.store._pushResourceIdentifier(this, data); + this.setCanonicalRecord(internalModel); } - - return this.findRecord(); -}; - -BelongsToRelationship.prototype.updateData = function(data) { - let internalModel = this.store._pushResourceIdentifier(this, data); - this.setCanonicalRecord(internalModel); -}; +} diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index b5da724a921..6b6c1c67c31 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -3,18 +3,18 @@ import ManyRelationship from "ember-data/-private/system/relationships/state/has import BelongsToRelationship from "ember-data/-private/system/relationships/state/belongs-to"; import EmptyObject from "ember-data/-private/system/empty-object"; -var get = Ember.get; +const { get } = Ember; function shouldFindInverse(relationshipMeta) { let options = relationshipMeta.options; return !(options && options.inverse === null); } -function createRelationshipFor(record, relationshipMeta, store) { +function createRelationshipFor(internalModel, relationshipMeta, store) { let inverseKey; let inverse = null; if (shouldFindInverse(relationshipMeta)) { - inverse = record.type.inverseFor(relationshipMeta.key, store); + inverse = internalModel.type.inverseFor(relationshipMeta.key, store); } if (inverse) { @@ -22,26 +22,36 @@ function createRelationshipFor(record, relationshipMeta, store) { } if (relationshipMeta.kind === 'hasMany') { - return new ManyRelationship(store, record, inverseKey, relationshipMeta); + return new ManyRelationship(store, internalModel, inverseKey, relationshipMeta); } else { - return new BelongsToRelationship(store, record, inverseKey, relationshipMeta); + return new BelongsToRelationship(store, internalModel, inverseKey, relationshipMeta); } } -export default function Relationships(record) { - this.record = record; - this.initializedRelationships = new EmptyObject(); -} +export default class Relationships { + constructor(internalModel) { + this.internalModel = internalModel; + this.initializedRelationships = new EmptyObject(); + } + + // TODO @runspired deprecate this as it was never truly a record instance + get record() { + return this.internalModel; + } -Relationships.prototype.has = function(key) { - return !!this.initializedRelationships[key]; -}; + has(key) { + return !!this.initializedRelationships[key]; + } + + get(key) { + let relationships = this.initializedRelationships; + let internalModel = this.internalModel; + let relationshipsByName = get(internalModel.type, 'relationshipsByName'); -Relationships.prototype.get = function(key) { - var relationships = this.initializedRelationships; - var relationshipsByName = get(this.record.type, 'relationshipsByName'); - if (!relationships[key] && relationshipsByName.get(key)) { - relationships[key] = createRelationshipFor(this.record, relationshipsByName.get(key), this.record.store); + if (!relationships[key] && relationshipsByName.get(key)) { + relationships[key] = createRelationshipFor(internalModel, relationshipsByName.get(key), internalModel.store); + } + + return relationships[key]; } - return relationships[key]; -}; +} diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 76f790eb6e0..881552024dd 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -6,234 +6,228 @@ import ManyArray from "ember-data/-private/system/many-array"; import { assertPolymorphicType } from "ember-data/-private/debug"; -export default function ManyRelationship(store, record, inverseKey, relationshipMeta) { - this._super$constructor(store, record, inverseKey, relationshipMeta); - this.belongsToType = relationshipMeta.type; - this.canonicalState = []; - this.isPolymorphic = relationshipMeta.options.polymorphic; -} - -ManyRelationship.prototype = Object.create(Relationship.prototype); -ManyRelationship.prototype.getManyArray = function() { - if (!this._manyArray) { - this._manyArray = ManyArray.create({ - canonicalState: this.canonicalState, - store: this.store, - relationship: this, - type: this.store.modelFor(this.belongsToType), - record: this.record, - meta: this.meta, - isPolymorphic: this.isPolymorphic - }); +export default class ManyRelationship extends Relationship { + constructor(store, record, inverseKey, relationshipMeta) { + super(store, record, inverseKey, relationshipMeta); + this.belongsToType = relationshipMeta.type; + this.canonicalState = []; + this.isPolymorphic = relationshipMeta.options.polymorphic; + } + + getManyArray() { + if (!this._manyArray) { + this._manyArray = ManyArray.create({ + canonicalState: this.canonicalState, + store: this.store, + relationship: this, + type: this.store.modelFor(this.belongsToType), + record: this.record, + meta: this.meta, + isPolymorphic: this.isPolymorphic + }); + } + return this._manyArray; } - return this._manyArray; -}; -ManyRelationship.prototype.constructor = ManyRelationship; -ManyRelationship.prototype._super$constructor = Relationship; - -ManyRelationship.prototype.destroy = function() { - if (this._manyArray) { - this._manyArray.destroy(); + destroy() { + if (this._manyArray) { + this._manyArray.destroy(); + } } -}; -ManyRelationship.prototype._super$updateMeta = Relationship.prototype.updateMeta; -ManyRelationship.prototype.updateMeta = function(meta) { - this._super$updateMeta(meta); - if (this._manyArray) { - this._manyArray.set('meta', meta); + updateMeta(meta) { + super.updateMeta(meta); + if (this._manyArray) { + this._manyArray.set('meta', meta); + } } -}; -ManyRelationship.prototype._super$addCanonicalRecord = Relationship.prototype.addCanonicalRecord; -ManyRelationship.prototype.addCanonicalRecord = function(record, idx) { - if (this.canonicalMembers.has(record)) { - return; - } - if (idx !== undefined) { - this.canonicalState.splice(idx, 0, record); - } else { - this.canonicalState.push(record); + addCanonicalRecord(record, idx) { + if (this.canonicalMembers.has(record)) { + return; + } + if (idx !== undefined) { + this.canonicalState.splice(idx, 0, record); + } else { + this.canonicalState.push(record); + } + super.addCanonicalRecord(record, idx); } - this._super$addCanonicalRecord(record, idx); -}; -ManyRelationship.prototype._super$addRecord = Relationship.prototype.addRecord; -ManyRelationship.prototype.addRecord = function(record, idx) { - if (this.members.has(record)) { - return; + addRecord(record, idx) { + if (this.members.has(record)) { + return; + } + super.addRecord(record, idx); + // make lazy later + this.getManyArray().internalAddRecords([record], idx); } - this._super$addRecord(record, idx); - // make lazy later - this.getManyArray().internalAddRecords([record], idx); -}; -ManyRelationship.prototype._super$removeCanonicalRecordFromOwn = Relationship.prototype.removeCanonicalRecordFromOwn; -ManyRelationship.prototype.removeCanonicalRecordFromOwn = function(record, idx) { - var i = idx; - if (!this.canonicalMembers.has(record)) { - return; - } - if (i === undefined) { - i = this.canonicalState.indexOf(record); - } - if (i > -1) { - this.canonicalState.splice(i, 1); + removeCanonicalRecordFromOwn(record, idx) { + var i = idx; + if (!this.canonicalMembers.has(record)) { + return; + } + if (i === undefined) { + i = this.canonicalState.indexOf(record); + } + if (i > -1) { + this.canonicalState.splice(i, 1); + } + super.removeCanonicalRecordFromOwn(record, idx); } - this._super$removeCanonicalRecordFromOwn(record, idx); -}; -ManyRelationship.prototype._super$flushCanonical = Relationship.prototype.flushCanonical; -ManyRelationship.prototype.flushCanonical = function() { - if (this._manyArray) { - this._manyArray.flushCanonical(); + flushCanonical() { + if (this._manyArray) { + this._manyArray.flushCanonical(); + } + super.flushCanonical(); } - this._super$flushCanonical(); -}; -ManyRelationship.prototype._super$removeRecordFromOwn = Relationship.prototype.removeRecordFromOwn; -ManyRelationship.prototype.removeRecordFromOwn = function(record, idx) { - if (!this.members.has(record)) { - return; - } - this._super$removeRecordFromOwn(record, idx); - let manyArray = this.getManyArray(); - if (idx !== undefined) { - //TODO(Igor) not used currently, fix - manyArray.currentState.removeAt(idx); - } else { - manyArray.internalRemoveRecords([record]); + removeRecordFromOwn(record, idx) { + if (!this.members.has(record)) { + return; + } + super.removeRecordFromOwn(record, idx); + let manyArray = this.getManyArray(); + if (idx !== undefined) { + //TODO(Igor) not used currently, fix + manyArray.currentState.removeAt(idx); + } else { + manyArray.internalRemoveRecords([record]); + } } -}; -ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) { - assertPolymorphicType(this.record, this.relationshipMeta, record); + notifyRecordRelationshipAdded(record, idx) { + assertPolymorphicType(this.record, this.relationshipMeta, record); - this.record.notifyHasManyAdded(this.key, record, idx); -}; + this.record.notifyHasManyAdded(this.key, record, idx); + } -ManyRelationship.prototype.reload = function() { - let manyArray = this.getManyArray(); - let manyArrayLoadedState = manyArray.get('isLoaded'); + reload() { + let manyArray = this.getManyArray(); + let manyArrayLoadedState = manyArray.get('isLoaded'); - if (this._loadingPromise) { - if (this._loadingPromise.get('isPending')) { - return this._loadingPromise; - } - if (this._loadingPromise.get('isRejected')) { - manyArray.set('isLoaded', manyArrayLoadedState); + if (this._loadingPromise) { + if (this._loadingPromise.get('isPending')) { + return this._loadingPromise; + } + if (this._loadingPromise.get('isRejected')) { + manyArray.set('isLoaded', manyArrayLoadedState); + } } - } - if (this.link) { - this._loadingPromise = promiseManyArray(this.fetchLink(), 'Reload with link'); - return this._loadingPromise; - } else { - this._loadingPromise = promiseManyArray(this.store._scheduleFetchMany(manyArray.currentState).then(() => manyArray), 'Reload with ids'); - return this._loadingPromise; + if (this.link) { + this._loadingPromise = promiseManyArray(this.fetchLink(), 'Reload with link'); + return this._loadingPromise; + } else { + this._loadingPromise = promiseManyArray(this.store._scheduleFetchMany(manyArray.currentState).then(() => manyArray), 'Reload with ids'); + return this._loadingPromise; + } } -}; -ManyRelationship.prototype.computeChanges = function(records) { - var members = this.canonicalMembers; - var recordsToRemove = []; - var length; - var record; - var i; + computeChanges(records) { + var members = this.canonicalMembers; + var recordsToRemove = []; + var length; + var record; + var i; - records = setForArray(records); + records = setForArray(records); - members.forEach(function(member) { - if (records.has(member)) { return; } + members.forEach(function(member) { + if (records.has(member)) { return; } - recordsToRemove.push(member); - }); + recordsToRemove.push(member); + }); - this.removeCanonicalRecords(recordsToRemove); + this.removeCanonicalRecords(recordsToRemove); + + // Using records.toArray() since currently using + // removeRecord can modify length, messing stuff up + // forEach since it directly looks at "length" each + // iteration + records = records.toArray(); + length = records.length; + for (i = 0; i < length; i++) { + record = records[i]; + this.removeCanonicalRecord(record); + this.addCanonicalRecord(record, i); + } + } - // Using records.toArray() since currently using - // removeRecord can modify length, messing stuff up - // forEach since it directly looks at "length" each - // iteration - records = records.toArray(); - length = records.length; - for (i = 0; i < length; i++) { - record = records[i]; - this.removeCanonicalRecord(record); - this.addCanonicalRecord(record, i); + fetchLink() { + return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then((records) => { + if (records.hasOwnProperty('meta')) { + this.updateMeta(records.meta); + } + this.store._backburner.join(() => { + this.updateRecordsFromAdapter(records); + this.getManyArray().set('isLoaded', true); + }); + return this.getManyArray(); + }); } -}; -ManyRelationship.prototype.fetchLink = function() { - return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then((records) => { - if (records.hasOwnProperty('meta')) { - this.updateMeta(records.meta); + findRecords() { + let manyArray = this.getManyArray(); + let array = manyArray.toArray(); + let internalModels = new Array(array.length); + + for (let i = 0; i < array.length; i++) { + internalModels[i] = array[i]._internalModel; } - this.store._backburner.join(() => { - this.updateRecordsFromAdapter(records); - this.getManyArray().set('isLoaded', true); + + //TODO CLEANUP + return this.store.findMany(internalModels).then(() => { + if (!manyArray.get('isDestroyed')) { + //Goes away after the manyArray refactor + manyArray.set('isLoaded', true); + } + return manyArray; }); - return this.getManyArray(); - }); -}; - -ManyRelationship.prototype.findRecords = function() { - let manyArray = this.getManyArray() - let array = manyArray.toArray(); - let internalModels = new Array(array.length); - - for (let i = 0; i < array.length; i++) { - internalModels[i] = array[i]._internalModel; - } - - //TODO CLEANUP - return this.store.findMany(internalModels).then(() => { - if (!manyArray.get('isDestroyed')) { - //Goes away after the manyArray refactor - manyArray.set('isLoaded', true); - } - return manyArray; - }); -}; -ManyRelationship.prototype.notifyHasManyChanged = function() { - this.record.notifyHasManyAdded(this.key); -}; - -ManyRelationship.prototype.getRecords = function() { - //TODO(Igor) sync server here, once our syncing is not stupid - let manyArray = this.getManyArray(); - if (this.isAsync) { - var promise; - if (this.link) { - if (this.hasLoaded) { - promise = this.findRecords(); + } + + notifyHasManyChanged() { + this.record.notifyHasManyAdded(this.key); + } + + getRecords() { + //TODO(Igor) sync server here, once our syncing is not stupid + let manyArray = this.getManyArray(); + if (this.isAsync) { + var promise; + if (this.link) { + if (this.hasLoaded) { + promise = this.findRecords(); + } else { + promise = this.findLink().then(() => this.findRecords()); + } } else { - promise = this.findLink().then(() => this.findRecords()); + promise = this.findRecords(); } + this._loadingPromise = PromiseManyArray.create({ + content: manyArray, + promise: promise + }); + return this._loadingPromise; } else { - promise = this.findRecords(); - } - this._loadingPromise = PromiseManyArray.create({ - content: manyArray, - promise: promise - }); - return this._loadingPromise; - } else { - assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", manyArray.isEvery('isEmpty', false)); + assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", manyArray.isEvery('isEmpty', false)); - //TODO(Igor) WTF DO I DO HERE? - if (!manyArray.get('isDestroyed')) { - manyArray.set('isLoaded', true); + //TODO(Igor) WTF DO I DO HERE? + // TODO @runspired equal WTFs to Igor + if (!manyArray.get('isDestroyed')) { + manyArray.set('isLoaded', true); + } + return manyArray; } - return manyArray; } -}; -ManyRelationship.prototype.updateData = function(data) { - let internalModels = this.store._pushResourceIdentifiers(this, data); - this.updateRecordsFromAdapter(internalModels); -}; + updateData(data) { + let internalModels = this.store._pushResourceIdentifiers(this, data); + this.updateRecordsFromAdapter(internalModels); + } +} function setForArray(array) { var set = new OrderedSet(); diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 7266ef6cb28..e361526bc9d 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -53,35 +53,42 @@ const { 'updateRecordsFromAdapter' ); -export default function Relationship(store, record, inverseKey, relationshipMeta) { - heimdall.increment(newRelationship); - var async = relationshipMeta.options.async; - this.members = new OrderedSet(); - this.canonicalMembers = new OrderedSet(); - this.store = store; - this.key = relationshipMeta.key; - this.inverseKey = inverseKey; - this.record = record; - this.isAsync = typeof async === 'undefined' ? true : async; - this.relationshipMeta = relationshipMeta; - //This probably breaks for polymorphic relationship in complex scenarios, due to - //multiple possible modelNames - this.inverseKeyForImplicit = this.record.constructor.modelName + this.key; - this.linkPromise = null; - this.meta = null; - this.hasData = false; - this.hasLoaded = false; -} +export default class Relationship { + constructor(store, internalModel, inverseKey, relationshipMeta) { + heimdall.increment(newRelationship); + var async = relationshipMeta.options.async; + this.members = new OrderedSet(); + this.canonicalMembers = new OrderedSet(); + this.store = store; + this.key = relationshipMeta.key; + this.inverseKey = inverseKey; + this.internalModel = internalModel; + this.isAsync = typeof async === 'undefined' ? true : async; + this.relationshipMeta = relationshipMeta; + //This probably breaks for polymorphic relationship in complex scenarios, due to + //multiple possible modelNames + this.inverseKeyForImplicit = this.internalModel.modelName + this.key; + this.linkPromise = null; + this.meta = null; + this.hasData = false; + this.hasLoaded = false; + } -Relationship.prototype = { - constructor: Relationship, + // TODO @runspired deprecate this as it was never truly a record instance + get record() { + return this.internalModel; + } - destroy() { }, + get parentType() { + return this.internalModel.modelName; + } + + destroy() { } updateMeta(meta) { heimdall.increment(updateMeta); this.meta = meta; - }, + } clear() { heimdall.increment(clear); @@ -92,12 +99,12 @@ Relationship.prototype = { member = members[0]; this.removeRecord(member); } - }, + } removeRecords(records) { heimdall.increment(removeRecords); records.forEach((record) => this.removeRecord(record)); - }, + } addRecords(records, idx) { heimdall.increment(addRecords); @@ -107,7 +114,7 @@ Relationship.prototype = { idx++; } }); - }, + } addCanonicalRecords(records, idx) { heimdall.increment(addCanonicalRecords); @@ -118,7 +125,7 @@ Relationship.prototype = { this.addCanonicalRecord(records[i]); } } - }, + } addCanonicalRecord(record, idx) { heimdall.increment(addCanonicalRecord); @@ -135,7 +142,7 @@ Relationship.prototype = { } this.flushCanonicalLater(); this.setHasData(true); - }, + } removeCanonicalRecords(records, idx) { heimdall.increment(removeCanonicalRecords); @@ -146,7 +153,7 @@ Relationship.prototype = { this.removeCanonicalRecord(records[i]); } } - }, + } removeCanonicalRecord(record, idx) { heimdall.increment(removeCanonicalRecord); @@ -161,7 +168,7 @@ Relationship.prototype = { } } this.flushCanonicalLater(); - }, + } addRecord(record, idx) { heimdall.increment(addRecord); @@ -179,7 +186,7 @@ Relationship.prototype = { this.record.updateRecordArraysLater(); } this.setHasData(true); - }, + } removeRecord(record) { heimdall.increment(removeRecord); @@ -193,7 +200,7 @@ Relationship.prototype = { } } } - }, + } removeRecordFromInverse(record) { heimdall.increment(removeRecordFromInverse); @@ -202,14 +209,14 @@ Relationship.prototype = { if (inverseRelationship) { inverseRelationship.removeRecordFromOwn(this.record); } - }, + } removeRecordFromOwn(record) { heimdall.increment(removeRecordFromOwn); this.members.delete(record); this.notifyRecordRelationshipRemoved(record); this.record.updateRecordArrays(); - }, + } removeCanonicalRecordFromInverse(record) { heimdall.increment(removeCanonicalRecordFromInverse); @@ -218,13 +225,13 @@ Relationship.prototype = { if (inverseRelationship) { inverseRelationship.removeCanonicalRecordFromOwn(this.record); } - }, + } removeCanonicalRecordFromOwn(record) { heimdall.increment(removeCanonicalRecordFromOwn); this.canonicalMembers.delete(record); this.flushCanonicalLater(); - }, + } flushCanonical() { heimdall.increment(flushCanonical); @@ -232,17 +239,17 @@ Relationship.prototype = { //a hack for not removing new records //TODO remove once we have proper diffing var newRecords = []; - for (var i=0; i this.store._backburner.schedule('syncRelationships', this, this.flushCanonical)); - }, + } updateLink(link) { heimdall.increment(updateLink); @@ -263,7 +270,7 @@ Relationship.prototype = { this.link = link; this.linkPromise = null; this.record.notifyPropertyChange(this.key); - }, + } findLink() { heimdall.increment(findLink); @@ -274,55 +281,55 @@ Relationship.prototype = { this.linkPromise = promise; return promise.then((result) => result); } - }, + } updateRecordsFromAdapter(records) { heimdall.increment(updateRecordsFromAdapter); //TODO(Igor) move this to a proper place //TODO Once we have adapter support, we need to handle updated and canonical changes this.computeChanges(records); - }, + } - notifyRecordRelationshipAdded() { }, - notifyRecordRelationshipRemoved() { }, + notifyRecordRelationshipAdded() { } + notifyRecordRelationshipRemoved() { } /* - `hasData` for a relationship is a flag to indicate if we consider the - content of this relationship "known". Snapshots uses this to tell the - difference between unknown (`undefined`) or empty (`null`). The reason for - this is that we wouldn't want to serialize unknown relationships as `null` - as that might overwrite remote state. - - All relationships for a newly created (`store.createRecord()`) are - considered known (`hasData === true`). + `hasData` for a relationship is a flag to indicate if we consider the + content of this relationship "known". Snapshots uses this to tell the + difference between unknown (`undefined`) or empty (`null`). The reason for + this is that we wouldn't want to serialize unknown relationships as `null` + as that might overwrite remote state. + + All relationships for a newly created (`store.createRecord()`) are + considered known (`hasData === true`). */ setHasData(value) { heimdall.increment(setHasData); this.hasData = value; - }, + } /* - `hasLoaded` is a flag to indicate if we have gotten data from the adapter or - not when the relationship has a link. + `hasLoaded` is a flag to indicate if we have gotten data from the adapter or + not when the relationship has a link. - This is used to be able to tell when to fetch the link and when to return - the local data in scenarios where the local state is considered known - (`hasData === true`). + This is used to be able to tell when to fetch the link and when to return + the local data in scenarios where the local state is considered known + (`hasData === true`). - Updating the link will automatically set `hasLoaded` to `false`. + Updating the link will automatically set `hasLoaded` to `false`. */ setHasLoaded(value) { heimdall.increment(setHasLoaded); this.hasLoaded = value; - }, + } /* - `push` for a relationship allows the store to push a JSON API Relationship - Object onto the relationship. The relationship will then extract and set the - meta, data and links of that relationship. + `push` for a relationship allows the store to push a JSON API Relationship + Object onto the relationship. The relationship will then extract and set the + meta, data and links of that relationship. - `push` use `updateMeta`, `updateData` and `updateLink` to update the state - of the relationship. + `push` use `updateMeta`, `updateData` and `updateLink` to update the state + of the relationship. */ push(payload) { heimdall.increment(push); @@ -348,16 +355,16 @@ Relationship.prototype = { } /* - Data being pushed into the relationship might contain only data or links, - or a combination of both. + Data being pushed into the relationship might contain only data or links, + or a combination of both. - If we got data we want to set both hasData and hasLoaded to true since - this would indicate that we should prefer the local state instead of - trying to fetch the link or call findRecord(). + If we got data we want to set both hasData and hasLoaded to true since + this would indicate that we should prefer the local state instead of + trying to fetch the link or call findRecord(). - If we have no data but a link is present we want to set hasLoaded to false - without modifying the hasData flag. This will ensure we fetch the updated - link next time the relationship is accessed. + If we have no data but a link is present we want to set hasLoaded to false + without modifying the hasData flag. This will ensure we fetch the updated + link next time the relationship is accessed. */ if (hasData) { this.setHasData(true); @@ -365,7 +372,7 @@ Relationship.prototype = { } else if (hasLink) { this.setHasLoaded(false); } - }, + } updateData() {} -}; +} From 80004c4534d05f10b0bb478a37753c1a0b4a51ba Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 30 Nov 2016 07:36:01 +0100 Subject: [PATCH 1723/2527] [FEATURE ds-rollback-attribute] rename ds-reset-attribute As discussed in the ember data weekly meeting, the initial thought of naming the method `resetAttribute` introduces a new verb "reset" into the ember data terminology, which is not ideal. This renames the method to `rollbackAttribute` to be more conistent with the current terminology. --- FEATURES.md | 8 +++---- addon/-private/system/model/internal-model.js | 2 +- addon/-private/system/model/model.js | 8 +++---- config/features.json | 2 +- tests/unit/model-test.js | 22 +++++++++---------- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 2f49b841849..77fd5be66b8 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -110,9 +110,9 @@ entry in `config/features.json`. Adds public method for `shouldSerializeHasMany`, used to determine if a `hasMany` relationship can be serialized. -- `ds-reset-attribute` [#4246](https://github.com/emberjs/data/pull/4246) +- `ds-rollback-attribute` [#4246](https://github.com/emberjs/data/pull/4246) - Adds a `resetAttribute` method to models. Similar to `rollbackAttributes`, + Adds a `rollbackAttribute` method to models. Similar to `rollbackAttributes`, but for only a single attribute. ```js @@ -124,10 +124,10 @@ entry in `config/features.json`. lastName: 'Katz' }); - tom.resetAttribute('firstName') // { firstName: 'Tom', lastName: 'Katz' } + tom.rollbackAttribute('firstName') // { firstName: 'Tom', lastName: 'Katz' } tom.get('hasDirtyAttributes') // true - tom.resetAttribute('lastName') // { firstName: 'Tom', lastName: 'Dale' } + tom.rollbackAttribute('lastName') // { firstName: 'Tom', lastName: 'Dale' } tom.get('hasDirtyAttributes') // false ``` diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index a329db3c476..225065a6233 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -1016,7 +1016,7 @@ export default class InternalModel { } } -if (isEnabled('ds-reset-attribute')) { +if (isEnabled('ds-rollback-attribute')) { /* Returns the latest truth for an attribute - the canonical value, or the in-flight value. diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 6fe3fbaf541..c1f7769addd 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1038,7 +1038,7 @@ if (Ember.setOwner) { }); } -if (isEnabled('ds-reset-attribute')) { +if (isEnabled('ds-rollback-attribute')) { Model.reopen({ /** Discards any unsaved changes to the given attribute. @@ -1049,13 +1049,13 @@ if (isEnabled('ds-reset-attribute')) { record.get('name'); // 'Untitled Document' record.set('name', 'Doc 1'); record.get('name'); // 'Doc 1' - record.resetAttribute('name'); + record.rollbackAttribute('name'); record.get('name'); // 'Untitled Document' ``` - @method resetAttribute + @method rollbackAttribute */ - resetAttribute(attributeName) { + rollbackAttribute(attributeName) { if (attributeName in this._internalModel._attributes) { this.set(attributeName, this._internalModel.lastAcknowledgedValue(attributeName)); } diff --git a/config/features.json b/config/features.json index b235af06c91..5aef97f151c 100644 --- a/config/features.json +++ b/config/features.json @@ -5,7 +5,7 @@ "ds-overhaul-references": null, "ds-payload-type-hooks": null, "ds-check-should-serialize-relationships": null, - "ds-reset-attribute": null, + "ds-rollback-attribute": null, "ds-serialize-id": null, "ds-deprecate-store-serialize": true } diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 4bf896805ad..aaf7e0c8a81 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -428,8 +428,8 @@ test("changedAttributes() works while the record is being updated", function(ass }); }); -if (isEnabled('ds-reset-attribute')) { - test("resetAttribute() reverts a single attribute to its canonical value", function(assert) { +if (isEnabled('ds-rollback-attribute')) { + test("rollbackAttribute() reverts a single attribute to its canonical value", function(assert) { assert.expect(5); run(function() { @@ -452,14 +452,14 @@ if (isEnabled('ds-reset-attribute')) { isDrugAddict: false }); assert.equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting property to a new value"); - person.resetAttribute('isDrugAddict'); + person.rollbackAttribute('isDrugAddict'); assert.equal(person.get('isDrugAddict'), true, "The specified attribute is rolled back"); assert.equal(person.get('name'), 'Piper', "Unspecified attributes are not rolled back"); assert.equal(person.get('hasDirtyAttributes'), true, "record with changed attributes is still dirty"); }); }); - test("calling resetAttribute() on an unmodified property has no effect", function(assert) { + test("calling rollbackAttribute() on an unmodified property has no effect", function(assert) { assert.expect(5); run(function() { @@ -479,14 +479,14 @@ if (isEnabled('ds-reset-attribute')) { assert.equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); person.set('name', 'Piper'); assert.equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting property to a new value"); - person.resetAttribute('isDrugAddict'); + person.rollbackAttribute('isDrugAddict'); assert.equal(person.get('isDrugAddict'), true, "The specified attribute does not change value"); assert.equal(person.get('name'), 'Piper', "Unspecified attributes are not rolled back"); assert.equal(person.get('hasDirtyAttributes'), true, "record with changed attributes is still dirty"); }); }); - test("Rolling back the final value with resetAttribute() causes the record to become clean again", function(assert) { + test("Rolling back the final value with rollbackAttribute() causes the record to become clean again", function(assert) { assert.expect(3); run(function() { @@ -506,12 +506,12 @@ if (isEnabled('ds-reset-attribute')) { assert.equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); person.set('isDrugAddict', false); assert.equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting property to a new value"); - person.resetAttribute('isDrugAddict'); + person.rollbackAttribute('isDrugAddict'); assert.equal(person.get('hasDirtyAttributes'), false, "record becomes clean after resetting property to the old value"); }); }); - test("Using resetAttribute on an in-flight record reverts to the latest in-flight value", function(assert) { + test("Using rollbackAttribute on an in-flight record reverts to the latest in-flight value", function(assert) { assert.expect(4); var person, finishSaving; @@ -546,14 +546,14 @@ if (isEnabled('ds-reset-attribute')) { person.set('name', "Tomathy"); assert.equal(person.get('name'), "Tomathy"); - person.resetAttribute('name'); + person.rollbackAttribute('name'); assert.equal(person.get('name'), "Thomas"); finishSaving(); }); }); - test("Saving an in-flight record updates the in-flight value resetAttribute will use", function(assert) { + test("Saving an in-flight record updates the in-flight value rollbackAttribute will use", function(assert) { assert.expect(7); var person, finishSaving; @@ -598,7 +598,7 @@ if (isEnabled('ds-reset-attribute')) { person.set('name', "Tomny"); assert.equal(person.get('name'), "Tomny"); - person.resetAttribute('name'); + person.rollbackAttribute('name'); assert.equal(person.get('name'), 'Tomathy'); finishSaving(); From e9355577032a3bd08402c55fd5651e34fcf5c50f Mon Sep 17 00:00:00 2001 From: pangratz Date: Wed, 30 Nov 2016 17:28:04 +0100 Subject: [PATCH 1724/2527] [FEATURE ds-improved-ajax] Disable feature --- config/features.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/features.json b/config/features.json index b235af06c91..e5075639fa3 100644 --- a/config/features.json +++ b/config/features.json @@ -1,5 +1,5 @@ { - "ds-improved-ajax": true, + "ds-improved-ajax": null, "ds-pushpayload-return": null, "ds-extended-errors": null, "ds-overhaul-references": null, From da58ec5529e255f3b1a5b5f5349e9ec2c55588fc Mon Sep 17 00:00:00 2001 From: Eli Flanagan Date: Wed, 30 Nov 2016 14:29:43 -0500 Subject: [PATCH 1725/2527] update documentation for `resetAttribute` (#4678) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [DOC] make clear that `rollbackAttribute` is feature flagged --- addon/-private/system/model/model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index c840a5562c3..7005c5eecf6 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1046,7 +1046,7 @@ if (Ember.setOwner) { if (isEnabled('ds-rollback-attribute')) { Model.reopen({ /** - Discards any unsaved changes to the given attribute. + Discards any unsaved changes to the given attribute. This feature is not enabled by default. You must enable `ds-rollback-attribute` and be running a canary build. Example From bf3c7f8708b7e86f0bf05c6f56bae6e8c9cdc4a8 Mon Sep 17 00:00:00 2001 From: Dmitriy Makarov Date: Thu, 1 Dec 2016 08:32:39 +0200 Subject: [PATCH 1726/2527] [DOC] Fix typo Remove extra article 'a' --- addon/adapters/rest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 4c0d3c0e50c..8794cd40104 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1005,7 +1005,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { /** Default `handleResponse` implementation uses this hook to decide if the - response is a an invalid error. + response is an invalid error. @since 1.13.0 @method isInvalid From e1621bbf2b6205445bcef2663ad77940e8895f14 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 1 Dec 2016 11:25:55 -0700 Subject: [PATCH 1727/2527] Fixed a typo --- addon/-private/system/model/model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 7005c5eecf6..85e0e053272 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -267,7 +267,7 @@ var Model = Ember.Object.extend(Ember.Evented, { isError: false, /** - If `true` the store is attempting to reload the record form the adapter. + If `true` the store is attempting to reload the record from the adapter. Example From 486aff750bb66b90728029620d6e9e8bdb45c3f7 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 2 Dec 2016 13:52:45 +0100 Subject: [PATCH 1728/2527] [BUGFIX beta] Add blueprints for "ember-cli-mocha >= 0.12.0" --- .../tests/unit/__path__/__test__.js | 16 +++++++++++++ .../tests/unit/__path__/__test__.js | 17 ++++++++++++++ .../tests/unit/__path__/__test__.js | 19 +++++++++++++++ blueprints/test-framework-detector.js | 9 +++++++- .../tests/unit/__path__/__test__.js | 16 +++++++++++++ node-tests/blueprints/adapter-test.js | 22 ++++++++++++++++++ node-tests/blueprints/model-test.js | 22 ++++++++++++++++++ node-tests/blueprints/serializer-test.js | 23 +++++++++++++++++++ node-tests/blueprints/transform-test.js | 22 ++++++++++++++++++ .../helpers/generate-fake-package-manifest.js | 13 +++++++++++ 10 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 blueprints/adapter-test/mocha-0.12-files/tests/unit/__path__/__test__.js create mode 100644 blueprints/model-test/mocha-0.12-files/tests/unit/__path__/__test__.js create mode 100644 blueprints/serializer-test/mocha-0.12-files/tests/unit/__path__/__test__.js create mode 100644 blueprints/transform-test/mocha-0.12-files/tests/unit/__path__/__test__.js create mode 100644 node-tests/helpers/generate-fake-package-manifest.js diff --git a/blueprints/adapter-test/mocha-0.12-files/tests/unit/__path__/__test__.js b/blueprints/adapter-test/mocha-0.12-files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..1eb97b0b43a --- /dev/null +++ b/blueprints/adapter-test/mocha-0.12-files/tests/unit/__path__/__test__.js @@ -0,0 +1,16 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupTest } from 'ember-mocha'; + +describe('<%= friendlyTestDescription %>', function() { + setupTest('adapter:<%= dasherizedModuleName %>', { + // Specify the other units that are required for this test. + // needs: ['serializer:foo'] + }); + + // Replace this with your real tests. + it('exists', function() { + let adapter = this.subject(); + expect(adapter).to.be.ok; + }); +}); diff --git a/blueprints/model-test/mocha-0.12-files/tests/unit/__path__/__test__.js b/blueprints/model-test/mocha-0.12-files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..6850a578f78 --- /dev/null +++ b/blueprints/model-test/mocha-0.12-files/tests/unit/__path__/__test__.js @@ -0,0 +1,17 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupModelTest } from 'ember-mocha'; + +describe('<%= friendlyDescription %>', function() { + setupModelTest('<%= dasherizedModuleName %>', { + // Specify the other units that are required for this test. + <%= typeof needs !== 'undefined' ? needs : '' %> + }); + + // Replace this with your real tests. + it('exists', function() { + let model = this.subject(); + // var store = this.store(); + expect(model).to.be.ok; + }); +}); diff --git a/blueprints/serializer-test/mocha-0.12-files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/mocha-0.12-files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..fd852a5e0d9 --- /dev/null +++ b/blueprints/serializer-test/mocha-0.12-files/tests/unit/__path__/__test__.js @@ -0,0 +1,19 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupModelTest } from 'ember-mocha'; + +describe('<%= friendlyTestDescription %>', function() { + setupModelTest('<%= dasherizedModuleName %>', { + // Specify the other units that are required for this test. + needs: ['serializer:<%= dasherizedModuleName %>'] + }); + + // Replace this with your real tests. + it('serializes records', function() { + let record = this.subject(); + + let serializedRecord = record.serialize(); + + expect(serializedRecord).to.be.ok; + }); +}); diff --git a/blueprints/test-framework-detector.js b/blueprints/test-framework-detector.js index 8f04dca3a60..2f8a2d988f8 100644 --- a/blueprints/test-framework-detector.js +++ b/blueprints/test-framework-detector.js @@ -1,4 +1,6 @@ +var fs = require('fs'); var path = require('path'); +var VersionChecker = require('ember-cli-version-checker'); module.exports = function(blueprint) { blueprint.supportsAddon = function() { @@ -12,7 +14,12 @@ module.exports = function(blueprint) { if ('ember-cli-qunit' in dependencies) { type = 'qunit'; } else if ('ember-cli-mocha' in dependencies) { - type = 'mocha'; + var checker = new VersionChecker({ project: this.project }); + if (fs.existsSync(this.path + '/mocha-0.12-files') && checker.for('ember-cli-mocha', 'npm').satisfies('>=0.12.0')) { + type = 'mocha-0.12'; + } else { + type = 'mocha'; + } } else { this.ui.writeLine('Couldn\'t determine test style - using QUnit'); type = 'qunit'; diff --git a/blueprints/transform-test/mocha-0.12-files/tests/unit/__path__/__test__.js b/blueprints/transform-test/mocha-0.12-files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..fcbe57e5eed --- /dev/null +++ b/blueprints/transform-test/mocha-0.12-files/tests/unit/__path__/__test__.js @@ -0,0 +1,16 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupTest } from 'ember-mocha'; + +describe('<%= friendlyTestDescription %>', function() { + setupTest('transform:<%= dasherizedModuleName %>', { + // Specify the other units that are required for this test. + // needs: ['transform:foo'] + }); + + // Replace this with your real tests. + it('exists', function() { + let transform = this.subject(); + expect(transform).to.be.ok; + }); +}); diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 699abfa1454..d312cbfe341 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -10,6 +10,8 @@ var expect = chai.expect; var SilentError = require('silent-error'); +var generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); + describe('Acceptance: generate and destroy adapter blueprints', function() { setupTestHooks(this); @@ -96,6 +98,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { {name: 'ember-cli-qunit', delete: true}, {name: 'ember-cli-mocha', dev: true} ])) + .then(() => generateFakePackageManifest('ember-cli-mocha', '0.11.0')) .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/unit/adapters/foo-test.js')) .to.contain('import { describeModule, it } from \'ember-mocha\';') @@ -103,4 +106,23 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { .to.contain('expect(adapter).to.be.ok;'); })); }); + + it('adapter-test for mocha v0.12+', function() { + var args = ['adapter-test', 'foo']; + + return emberNew() + .then(() => modifyPackages([ + {name: 'ember-cli-qunit', delete: true}, + {name: 'ember-cli-mocha', dev: true} + ])) + .then(() => generateFakePackageManifest('ember-cli-mocha', '0.12.0')) + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/adapters/foo-test.js')) + .to.contain('import { describe, it } from \'mocha\';') + .to.contain('import { setupTest } from \'ember-mocha\';') + .to.contain('describe(\'Unit | Adapter | foo\', function() {') + .to.contain('setupTest(\'adapter:foo\',') + .to.contain('expect(adapter).to.be.ok;'); + })); + }); }); diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index 70e046f9517..6b57bf5a1fb 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -7,6 +7,8 @@ var modifyPackages = blueprintHelpers.modifyPackages; var chai = require('ember-cli-blueprint-test-helpers/chai'); var expect = chai.expect; +var generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); + describe('Acceptance: generate and destroy model blueprints', function() { setupTestHooks(this); @@ -109,6 +111,7 @@ describe('Acceptance: generate and destroy model blueprints', function() { {name: 'ember-cli-qunit', delete: true}, {name: 'ember-cli-mocha', dev: true} ])) + .then(() => generateFakePackageManifest('ember-cli-mocha', '0.11.0')) .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/unit/models/foo-test.js')) .to.contain('import { describeModel, it } from \'ember-mocha\';') @@ -116,4 +119,23 @@ describe('Acceptance: generate and destroy model blueprints', function() { .to.contain('expect(model).to.be.ok;'); })); }); + + it('model-test for mocha v0.12+', function() { + var args = ['model-test', 'foo']; + + return emberNew() + .then(() => modifyPackages([ + {name: 'ember-cli-qunit', delete: true}, + {name: 'ember-cli-mocha', dev: true} + ])) + .then(() => generateFakePackageManifest('ember-cli-mocha', '0.12.0')) + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/models/foo-test.js')) + .to.contain('import { describe, it } from \'mocha\';') + .to.contain('import { setupModelTest } from \'ember-mocha\';') + .to.contain('describe(\'Unit | Model | foo\', function() {') + .to.contain('setupModelTest(\'foo\',') + .to.contain('expect(model).to.be.ok;'); + })); + }); }); diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index b7eb757e527..016e94eae0f 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -10,6 +10,8 @@ var expect = chai.expect; var SilentError = require('silent-error'); +var generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); + describe('Acceptance: generate and destroy serializer blueprints', function() { setupTestHooks(this); @@ -96,6 +98,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { {name: 'ember-cli-qunit', delete: true}, {name: 'ember-cli-mocha', dev: true} ])) + .then(() => generateFakePackageManifest('ember-cli-mocha', '0.11.0')) .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/unit/serializers/foo-test.js')) .to.contain('import { describeModel, it } from \'ember-mocha\';') @@ -105,4 +108,24 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { .to.contain('expect(serializedRecord).to.be.ok;'); })); }); + + it('serializer-test for mocha v0.12+', function() { + var args = ['serializer-test', 'foo']; + + return emberNew() + .then(() => modifyPackages([ + {name: 'ember-cli-qunit', delete: true}, + {name: 'ember-cli-mocha', dev: true} + ])) + .then(() => generateFakePackageManifest('ember-cli-mocha', '0.12.0')) + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/serializers/foo-test.js')) + .to.contain('import { describe, it } from \'mocha\';') + .to.contain('import { setupModelTest } from \'ember-mocha\';') + .to.contain('describe(\'Unit | Serializer | foo\', function() {') + .to.contain('setupModelTest(\'foo\', {') + .to.contain('needs: [\'serializer:foo\']') + .to.contain('expect(serializedRecord).to.be.ok;'); + })); + }); }); diff --git a/node-tests/blueprints/transform-test.js b/node-tests/blueprints/transform-test.js index cebe88093b6..8d934d7218e 100644 --- a/node-tests/blueprints/transform-test.js +++ b/node-tests/blueprints/transform-test.js @@ -7,6 +7,8 @@ var modifyPackages = blueprintHelpers.modifyPackages; var chai = require('ember-cli-blueprint-test-helpers/chai'); var expect = chai.expect; +var generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); + describe('Acceptance: generate and destroy transform blueprints', function() { setupTestHooks(this); @@ -44,6 +46,7 @@ describe('Acceptance: generate and destroy transform blueprints', function() { {name: 'ember-cli-qunit', delete: true}, {name: 'ember-cli-mocha', dev: true} ])) + .then(() => generateFakePackageManifest('ember-cli-mocha', '0.11.0')) .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/unit/transforms/foo-test.js')) .to.contain('import { describeModule, it } from \'ember-mocha\';') @@ -51,4 +54,23 @@ describe('Acceptance: generate and destroy transform blueprints', function() { .to.contain('expect(transform).to.be.ok;'); })); }); + + it('transform-test for mocha v0.12+', function() { + var args = ['transform-test', 'foo']; + + return emberNew() + .then(() => modifyPackages([ + {name: 'ember-cli-qunit', delete: true}, + {name: 'ember-cli-mocha', dev: true} + ])) + .then(() => generateFakePackageManifest('ember-cli-mocha', '0.12.0')) + .then(() => emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/transforms/foo-test.js')) + .to.contain('import { describe, it } from \'mocha\';') + .to.contain('import { setupTest } from \'ember-mocha\';') + .to.contain('describe(\'Unit | Transform | foo\', function() {') + .to.contain('setupTest(\'transform:foo\',') + .to.contain('expect(transform).to.be.ok;'); + })); + }); }); diff --git a/node-tests/helpers/generate-fake-package-manifest.js b/node-tests/helpers/generate-fake-package-manifest.js new file mode 100644 index 00000000000..d6f92f1f5a9 --- /dev/null +++ b/node-tests/helpers/generate-fake-package-manifest.js @@ -0,0 +1,13 @@ +var fs = require('fs'); + +module.exports = function generateFakePackageManifest(name, version) { + if (!fs.existsSync('node_modules')) { + fs.mkdirSync('node_modules'); + } + if (!fs.existsSync('node_modules/' + name)) { + fs.mkdirSync('node_modules/' + name); + } + fs.writeFileSync('node_modules/' + name + '/package.json', JSON.stringify({ + version: version, + })); +}; From 7558d758f359250a53c90d90c2b78afc3ad178f0 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 5 Dec 2016 16:34:45 -0800 Subject: [PATCH 1729/2527] chore(benchmarks): benchmarks needed to time a few lookups for us to know if we were improving the cost of the lookups --- addon/-private/system/store.js | 5 +++++ addon/-private/system/store/finders.js | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index ff0f2d5fa26..4fe0a558cb1 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1216,12 +1216,17 @@ Store = Service.extend({ assert("You need to pass a model name to the store's query method", isPresent(modelName)); assert("You need to pass a query hash to the store's query method", query); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + + let modelToken = heimdall.start('initial-modelFor-lookup'); let modelClass = this.modelFor(modelName); + heimdall.stop(modelToken); array = array || this.recordArrayManager .createAdapterPopulatedRecordArray(modelClass, query); + let adapterToken = heimdall.start('initial-adapterFor-lookup'); let adapter = this.adapterFor(modelName); + heimdall.stop(adapterToken); assert("You tried to load a query but you have no adapter (for " + modelClass.modelName + ")", adapter); assert("You tried to load a query but your adapter does not implement `query`", typeof adapter.query === 'function'); diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index ecca90fd1cf..a0c9a9e20ab 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -156,7 +156,9 @@ export function _query(adapter, store, typeClass, query, recordArray) { let modelName = typeClass.modelName; let promise = adapter.query(store, typeClass, query, recordArray); + let serializerToken = heimdall.start('initial-serializerFor-lookup'); let serializer = serializerForAdapter(store, adapter, modelName); + heimdall.stop(serializerToken); let label = 'DS: Handle Adapter#query of ' + typeClass; promise = Promise.resolve(promise, label); @@ -165,7 +167,9 @@ export function _query(adapter, store, typeClass, query, recordArray) { return promise.then(adapterPayload => { let internalModels, payload; store._adapterRun(() => { + let normalizeToken = heimdall.start('finders#_query::normalizeResponseHelper'); payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'query'); + heimdall.stop(normalizeToken); internalModels = store._push(payload); }); From 9d88bd0f6b68fcd43dd0f1f8368b1d4b7255c893 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 5 Dec 2016 23:43:38 -0800 Subject: [PATCH 1730/2527] include related record on the complex test --- benchmarks/config.js | 4 ++-- tests/dummy/app/routes/query/route.js | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/benchmarks/config.js b/benchmarks/config.js index 39c1462b2aa..b5cbf311ad3 100644 --- a/benchmarks/config.js +++ b/benchmarks/config.js @@ -8,7 +8,7 @@ module.exports = { // "query?modelName=simple&limit=2", // 2 total // "query?modelName=simple&limit=34", // 34 total // "query?modelName=simple&limit=119", // 119 total - "query?modelName=simple&limit=238", // 238 total + // "query?modelName=simple&limit=238", // 238 total // complex returns 7 total records of 3 model types per count in limit @@ -18,7 +18,7 @@ module.exports = { // "query?modelName=complex&limit=2", // 14 total // "query?modelName=complex&limit=5", // 35 total // "query?modelName=complex&limit=17", // 119 total - // "query?modelName=complex&limit=34", // 238 total + "query?modelName=complex&limit=34&included=foo,baz", // 238 total // heavy returns 17 total records of 5 model types per count in limit diff --git a/tests/dummy/app/routes/query/route.js b/tests/dummy/app/routes/query/route.js index f64fd666cd3..3b85d5b870f 100644 --- a/tests/dummy/app/routes/query/route.js +++ b/tests/dummy/app/routes/query/route.js @@ -13,6 +13,9 @@ export default Route.extend({ }, modelName: { refreshModel: true + }, + included: { + refreshModel: true } }, From b52e4c1b97c85970d892289837b2e9c0f5880eb1 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 5 Dec 2016 15:57:32 -0800 Subject: [PATCH 1731/2527] fix(benchmarks): benchmarks for store.query no longer included record materialization as this is now so lazy that it must be forced, this makes the benchmark force it so that we can continue to measure improvement within materialization --- addon/-private/system/model/internal-model.js | 2 ++ tests/dummy/app/routes/query/route.js | 1 + 2 files changed, 3 insertions(+) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 225065a6233..5f0dde7df16 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -263,6 +263,7 @@ export default class InternalModel { getRecord() { if (!this._record) { heimdall.increment(materializeRecord); + let token = heimdall.start('InternalModel.getRecord'); // lookupFactory should really return an object that creates // instances with the injections applied @@ -285,6 +286,7 @@ export default class InternalModel { this._record = this.modelClass._create(createOptions); this._triggerDeferredTriggers(); + heimdall.stop(token); } return this._record; diff --git a/tests/dummy/app/routes/query/route.js b/tests/dummy/app/routes/query/route.js index 3b85d5b870f..a73cfaf87f0 100644 --- a/tests/dummy/app/routes/query/route.js +++ b/tests/dummy/app/routes/query/route.js @@ -27,6 +27,7 @@ export default Route.extend({ let token = heimdall.start('ember-data'); return this.get('store').query(modelName, params) .then((records) => { + records.toArray(); heimdall.stop(token); window.result = heimdall.toString(); From 7bf380599d21045849cad045f409266ccc3f8356 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Dec 2016 13:50:32 -0800 Subject: [PATCH 1732/2527] Adds a comment explaining why we are forcing materialization of the RecordArray returned by store.query --- tests/dummy/app/routes/query/route.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/dummy/app/routes/query/route.js b/tests/dummy/app/routes/query/route.js index a73cfaf87f0..2bbafccb4c7 100644 --- a/tests/dummy/app/routes/query/route.js +++ b/tests/dummy/app/routes/query/route.js @@ -27,6 +27,10 @@ export default Route.extend({ let token = heimdall.start('ember-data'); return this.get('store').query(modelName, params) .then((records) => { + // RecordArray lazily materializes the records + // We call toArray() to force materialization for benchmarking + // otherwise we would need to consume the RecordArray in our UI + // and clutter our benchmarks and make it harder to time. records.toArray(); heimdall.stop(token); window.result = heimdall.toString(); From 81d7e2dc954945d507bcedbee0e9bcac754c4bf1 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Dec 2016 14:14:00 -0800 Subject: [PATCH 1733/2527] Remove double extend, condense triple reopenClass to single reopenClass --- addon/-private/system/model/model.js | 33 +++++++++++++--------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 85e0e053272..51421551c98 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -30,11 +30,11 @@ function intersection (array1, array2) { return result; } -var RESERVED_MODEL_PROPS = [ +const RESERVED_MODEL_PROPS = [ 'currentState', 'data', 'store' ]; -var retrieveFromCurrentState = computed('currentState', function(key) { +const retrieveFromCurrentState = computed('currentState', function(key) { return get(this._internalModel.currentState, key); }).readOnly(); @@ -51,7 +51,7 @@ var retrieveFromCurrentState = computed('currentState', function(key) { @extends Ember.Object @uses Ember.Evented */ -var Model = Ember.Object.extend(Ember.Evented, { +const Model = Ember.Object.extend(Ember.Evented, { _internalModel: null, store: null, @@ -886,7 +886,7 @@ var Model = Ember.Object.extend(Ember.Evented, { @since 2.5.0 @return {BelongsToReference} reference for this relationship */ - belongsTo: function(name) { + belongsTo(name) { return this._internalModel.referenceFor('belongsTo', name); }, @@ -947,14 +947,21 @@ var Model = Ember.Object.extend(Ember.Evented, { @since 2.5.0 @return {HasManyReference} reference for this relationship */ - hasMany: function(name) { + hasMany(name) { return this._internalModel.referenceFor('hasMany', name); }, setId: Ember.observer('id', function () { this._internalModel.setId(this.get('id')); }) -}); +}, + DebuggerInfoMixin, + BelongsToMixin, + DidDefinePropertyMixin, + RelationshipsInstanceMethodsMixin, + HasManyMixin, + AttrInstanceMethodsMixin +); /** @property data @@ -1022,7 +1029,7 @@ Model.reopenClass({ @static */ modelName: null -}); +}, RelationshipsClassMethodsMixin, AttrClassMethodsMixin); // if `Ember.setOwner` is defined, accessing `this.container` is // deprecated (but functional). In "standard" Ember usage, this @@ -1068,14 +1075,4 @@ if (isEnabled('ds-rollback-attribute')) { }); } - -Model.reopenClass(RelationshipsClassMethodsMixin); -Model.reopenClass(AttrClassMethodsMixin); - -export default Model.extend( - DebuggerInfoMixin, - BelongsToMixin, - DidDefinePropertyMixin, - RelationshipsInstanceMethodsMixin, - HasManyMixin, - AttrInstanceMethodsMixin); +export default Model; From 97f21b7a992b4fa8e1e1b00d72c9f056f0275cb1 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Dec 2016 14:35:25 -0800 Subject: [PATCH 1734/2527] move relationship class methods into the single reopen directly --- addon/-private/system/model/model.js | 469 ++++++++++++++++++++- addon/-private/system/relationships/ext.js | 466 +------------------- 2 files changed, 466 insertions(+), 469 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 51421551c98..f1e4e89db9c 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1,14 +1,15 @@ import Ember from 'ember'; -import { assert, deprecate } from "ember-data/-private/debug"; +import { assert, deprecate, warn } from "ember-data/-private/debug"; import { PromiseObject } from "ember-data/-private/system/promise-proxies"; import Errors from "ember-data/-private/system/model/errors"; import DebuggerInfoMixin from 'ember-data/-private/system/debug/debug-info'; import { BelongsToMixin } from 'ember-data/-private/system/relationships/belongs-to'; import { HasManyMixin } from 'ember-data/-private/system/relationships/has-many'; -import { DidDefinePropertyMixin, RelationshipsClassMethodsMixin, RelationshipsInstanceMethodsMixin } from 'ember-data/-private/system/relationships/ext'; +import { DidDefinePropertyMixin, RelationshipsInstanceMethodsMixin } from 'ember-data/-private/system/relationships/ext'; import { AttrClassMethodsMixin, AttrInstanceMethodsMixin } from 'ember-data/-private/system/model/attr'; import isEnabled from 'ember-data/-private/features'; import RootState from 'ember-data/-private/system/model/states'; +import EmptyObject from "ember-data/-private/system/empty-object"; const { get, @@ -1028,8 +1029,468 @@ Model.reopenClass({ @readonly @static */ - modelName: null -}, RelationshipsClassMethodsMixin, AttrClassMethodsMixin); + modelName: null, + + /* + These class methods below provide relationship + introspection abilities about relationships. + + A note about the computed properties contained here: + + **These properties are effectively sealed once called for the first time.** + To avoid repeatedly doing expensive iteration over a model's fields, these + values are computed once and then cached for the remainder of the runtime of + your application. + + If your application needs to modify a class after its initial definition + (for example, using `reopen()` to add additional attributes), make sure you + do it before using your model with the store, which uses these properties + extensively. + */ + + /** + For a given relationship name, returns the model type of the relationship. + + For example, if you define a model like this: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + comments: DS.hasMany('comment') + }); + ``` + + Calling `store.modelFor('post').typeForRelationship('comments', store)` will return `Comment`. + + @method typeForRelationship + @static + @param {String} name the name of the relationship + @param {store} store an instance of DS.Store + @return {DS.Model} the type of the relationship, or undefined + */ + typeForRelationship(name, store) { + var relationship = get(this, 'relationshipsByName').get(name); + return relationship && store.modelFor(relationship.type); + }, + + inverseMap: Ember.computed(function() { + return new EmptyObject(); + }), + + /** + Find the relationship which is the inverse of the one asked for. + + For example, if you define models like this: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + comments: DS.hasMany('message') + }); + ``` + + ```app/models/message.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + owner: DS.belongsTo('post') + }); + ``` + + store.modelFor('post').inverseFor('comments', store) -> { type: App.Message, name: 'owner', kind: 'belongsTo' } + store.modelFor('message').inverseFor('owner', store) -> { type: App.Post, name: 'comments', kind: 'hasMany' } + + @method inverseFor + @static + @param {String} name the name of the relationship + @param {DS.Store} store + @return {Object} the inverse relationship, or null + */ + inverseFor(name, store) { + var inverseMap = get(this, 'inverseMap'); + if (inverseMap[name]) { + return inverseMap[name]; + } else { + var inverse = this._findInverseFor(name, store); + inverseMap[name] = inverse; + return inverse; + } + }, + + //Calculate the inverse, ignoring the cache + _findInverseFor(name, store) { + + var inverseType = this.typeForRelationship(name, store); + if (!inverseType) { + return null; + } + + var propertyMeta = this.metaForProperty(name); + //If inverse is manually specified to be null, like `comments: DS.hasMany('message', { inverse: null })` + var options = propertyMeta.options; + if (options.inverse === null) { return null; } + + var inverseName, inverseKind, inverse; + + //If inverse is specified manually, return the inverse + if (options.inverse) { + inverseName = options.inverse; + inverse = Ember.get(inverseType, 'relationshipsByName').get(inverseName); + + assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.modelName + + "' model. This is most likely due to a missing attribute on your model definition.", !Ember.isNone(inverse)); + + inverseKind = inverse.kind; + } else { + //No inverse was specified manually, we need to use a heuristic to guess one + if (propertyMeta.type === propertyMeta.parentType.modelName) { + warn(`Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at http://emberjs.com/guides/models/defining-models/#toc_reflexive-relation for how to explicitly specify inverses.`, false, { + id: 'ds.model.reflexive-relationship-without-inverse' + }); + } + + var possibleRelationships = findPossibleInverses(this, inverseType); + + if (possibleRelationships.length === 0) { return null; } + + var filteredRelationships = possibleRelationships.filter((possibleRelationship) => { + var optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options; + return name === optionsForRelationship.inverse; + }); + + assert("You defined the '" + name + "' relationship on " + this + ", but you defined the inverse relationships of type " + + inverseType.toString() + " multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", + filteredRelationships.length < 2); + + if (filteredRelationships.length === 1 ) { + possibleRelationships = filteredRelationships; + } + + assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + + this + " were found on " + inverseType + ". Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", + possibleRelationships.length === 1); + + inverseName = possibleRelationships[0].name; + inverseKind = possibleRelationships[0].kind; + } + + function findPossibleInverses(type, inverseType, relationshipsSoFar) { + var possibleRelationships = relationshipsSoFar || []; + + var relationshipMap = get(inverseType, 'relationships'); + if (!relationshipMap) { return possibleRelationships; } + + var relationships = relationshipMap.get(type.modelName); + + relationships = relationships.filter((relationship) => { + var optionsForRelationship = inverseType.metaForProperty(relationship.name).options; + + if (!optionsForRelationship.inverse) { + return true; + } + + return name === optionsForRelationship.inverse; + }); + + if (relationships) { + possibleRelationships.push.apply(possibleRelationships, relationships); + } + + //Recurse to support polymorphism + if (type.superclass) { + findPossibleInverses(type.superclass, inverseType, possibleRelationships); + } + + return possibleRelationships; + } + + return { + type: inverseType, + name: inverseName, + kind: inverseKind + }; + }, + + /** + The model's relationships as a map, keyed on the type of the + relationship. The value of each entry is an array containing a descriptor + for each relationship with that type, describing the name of the relationship + as well as the type. + + For example, given the following model definition: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + posts: DS.hasMany('post') + }); + ``` + + This computed property would return a map describing these + relationships, like this: + + ```javascript + import Ember from 'ember'; + import Blog from 'app/models/blog'; + import User from 'app/models/user'; + import Post from 'app/models/post'; + + var relationships = Ember.get(Blog, 'relationships'); + relationships.get(User); + //=> [ { name: 'users', kind: 'hasMany' }, + // { name: 'owner', kind: 'belongsTo' } ] + relationships.get(Post); + //=> [ { name: 'posts', kind: 'hasMany' } ] + ``` + + @property relationships + @static + @type Ember.Map + @readOnly + */ + + relationships: relationshipsDescriptor, + + /** + A hash containing lists of the model's relationships, grouped + by the relationship kind. For example, given a model with this + definition: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + + posts: DS.hasMany('post') + }); + ``` + + This property would contain the following: + + ```javascript + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + var relationshipNames = Ember.get(Blog, 'relationshipNames'); + relationshipNames.hasMany; + //=> ['users', 'posts'] + relationshipNames.belongsTo; + //=> ['owner'] + ``` + + @property relationshipNames + @static + @type Object + @readOnly + */ + relationshipNames: Ember.computed(function() { + var names = { + hasMany: [], + belongsTo: [] + }; + + this.eachComputedProperty((name, meta) => { + if (meta.isRelationship) { + names[meta.kind].push(name); + } + }); + + return names; + }), + + /** + An array of types directly related to a model. Each type will be + included once, regardless of the number of relationships it has with + the model. + + For example, given a model with this definition: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + + posts: DS.hasMany('post') + }); + ``` + + This property would contain the following: + + ```javascript + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + var relatedTypes = Ember.get(Blog, 'relatedTypes'); + //=> [ User, Post ] + ``` + + @property relatedTypes + @static + @type Ember.Array + @readOnly + */ + relatedTypes: relatedTypesDescriptor, + + /** + A map whose keys are the relationships of a model and whose values are + relationship descriptors. + + For example, given a model with this + definition: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + + posts: DS.hasMany('post') + }); + ``` + + This property would contain the following: + + ```javascript + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + var relationshipsByName = Ember.get(Blog, 'relationshipsByName'); + relationshipsByName.get('users'); + //=> { key: 'users', kind: 'hasMany', type: 'user', options: Object, isRelationship: true } + relationshipsByName.get('owner'); + //=> { key: 'owner', kind: 'belongsTo', type: 'user', options: Object, isRelationship: true } + ``` + + @property relationshipsByName + @static + @type Ember.Map + @readOnly + */ + relationshipsByName: relationshipsByNameDescriptor, + + /** + A map whose keys are the fields of the model and whose values are strings + describing the kind of the field. A model's fields are the union of all of its + attributes and relationships. + + For example: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + + posts: DS.hasMany('post'), + + title: DS.attr('string') + }); + ``` + + ```js + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + var fields = Ember.get(Blog, 'fields'); + fields.forEach(function(kind, field) { + console.log(field, kind); + }); + + // prints: + // users, hasMany + // owner, belongsTo + // posts, hasMany + // title, attribute + ``` + + @property fields + @static + @type Ember.Map + @readOnly + */ + fields: Ember.computed(function() { + var map = Map.create(); + + this.eachComputedProperty((name, meta) => { + if (meta.isRelationship) { + map.set(name, meta.kind); + } else if (meta.isAttribute) { + map.set(name, 'attribute'); + } + }); + + return map; + }).readOnly(), + + /** + Given a callback, iterates over each of the relationships in the model, + invoking the callback with the name of each relationship and its relationship + descriptor. + + @method eachRelationship + @static + @param {Function} callback the callback to invoke + @param {any} binding the value to which the callback's `this` should be bound + */ + eachRelationship(callback, binding) { + get(this, 'relationshipsByName').forEach((relationship, name) => { + callback.call(binding, name, relationship); + }); + }, + + /** + Given a callback, iterates over each of the types related to a model, + invoking the callback with the related type's class. Each type will be + returned just once, regardless of how many different relationships it has + with a model. + + @method eachRelatedType + @static + @param {Function} callback the callback to invoke + @param {any} binding the value to which the callback's `this` should be bound + */ + eachRelatedType(callback, binding) { + let relationshipTypes = get(this, 'relatedTypes'); + + for (let i = 0; i < relationshipTypes.length; i++) { + let type = relationshipTypes[i]; + callback.call(binding, type); + } + }, + + determineRelationshipType(knownSide, store) { + let knownKey = knownSide.key; + let knownKind = knownSide.kind; + let inverse = this.inverseFor(knownKey, store); + // let key; + let otherKind; + + if (!inverse) { + return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone'; + } + + // key = inverse.name; + otherKind = inverse.kind; + + if (otherKind === 'belongsTo') { + return knownKind === 'belongsTo' ? 'oneToOne' : 'manyToOne'; + } else { + return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany'; + } + } + +}, AttrClassMethodsMixin); // if `Ember.setOwner` is defined, accessing `this.container` is // deprecated (but functional). In "standard" Ember usage, this diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index c99d1a3dfa5..ad2a4c881ce 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -1,10 +1,9 @@ import Ember from 'ember'; -import { assert, warn } from "ember-data/-private/debug"; +import { assert } from "ember-data/-private/debug"; import { typeForRelationshipMeta, relationshipFromMeta } from "ember-data/-private/system/relationship-meta"; -import EmptyObject from "ember-data/-private/system/empty-object"; var get = Ember.get; var Map = Ember.Map; @@ -139,469 +138,6 @@ export const DidDefinePropertyMixin = Ember.Mixin.create({ } }); -/* - These DS.Model extensions add class methods that provide relationship - introspection abilities about relationships. - - A note about the computed properties contained here: - - **These properties are effectively sealed once called for the first time.** - To avoid repeatedly doing expensive iteration over a model's fields, these - values are computed once and then cached for the remainder of the runtime of - your application. - - If your application needs to modify a class after its initial definition - (for example, using `reopen()` to add additional attributes), make sure you - do it before using your model with the store, which uses these properties - extensively. -*/ - -export const RelationshipsClassMethodsMixin = Ember.Mixin.create({ - - /** - For a given relationship name, returns the model type of the relationship. - - For example, if you define a model like this: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - comments: DS.hasMany('comment') - }); - ``` - - Calling `store.modelFor('post').typeForRelationship('comments', store)` will return `Comment`. - - @method typeForRelationship - @static - @param {String} name the name of the relationship - @param {store} store an instance of DS.Store - @return {DS.Model} the type of the relationship, or undefined - */ - typeForRelationship(name, store) { - var relationship = get(this, 'relationshipsByName').get(name); - return relationship && store.modelFor(relationship.type); - }, - - inverseMap: Ember.computed(function() { - return new EmptyObject(); - }), - - /** - Find the relationship which is the inverse of the one asked for. - - For example, if you define models like this: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - comments: DS.hasMany('message') - }); - ``` - - ```app/models/message.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - owner: DS.belongsTo('post') - }); - ``` - - store.modelFor('post').inverseFor('comments', store) -> { type: App.Message, name: 'owner', kind: 'belongsTo' } - store.modelFor('message').inverseFor('owner', store) -> { type: App.Post, name: 'comments', kind: 'hasMany' } - - @method inverseFor - @static - @param {String} name the name of the relationship - @param {DS.Store} store - @return {Object} the inverse relationship, or null - */ - inverseFor(name, store) { - var inverseMap = get(this, 'inverseMap'); - if (inverseMap[name]) { - return inverseMap[name]; - } else { - var inverse = this._findInverseFor(name, store); - inverseMap[name] = inverse; - return inverse; - } - }, - - //Calculate the inverse, ignoring the cache - _findInverseFor(name, store) { - - var inverseType = this.typeForRelationship(name, store); - if (!inverseType) { - return null; - } - - var propertyMeta = this.metaForProperty(name); - //If inverse is manually specified to be null, like `comments: DS.hasMany('message', { inverse: null })` - var options = propertyMeta.options; - if (options.inverse === null) { return null; } - - var inverseName, inverseKind, inverse; - - //If inverse is specified manually, return the inverse - if (options.inverse) { - inverseName = options.inverse; - inverse = Ember.get(inverseType, 'relationshipsByName').get(inverseName); - - assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.modelName + - "' model. This is most likely due to a missing attribute on your model definition.", !Ember.isNone(inverse)); - - inverseKind = inverse.kind; - } else { - //No inverse was specified manually, we need to use a heuristic to guess one - if (propertyMeta.type === propertyMeta.parentType.modelName) { - warn(`Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at http://emberjs.com/guides/models/defining-models/#toc_reflexive-relation for how to explicitly specify inverses.`, false, { - id: 'ds.model.reflexive-relationship-without-inverse' - }); - } - - var possibleRelationships = findPossibleInverses(this, inverseType); - - if (possibleRelationships.length === 0) { return null; } - - var filteredRelationships = possibleRelationships.filter((possibleRelationship) => { - var optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options; - return name === optionsForRelationship.inverse; - }); - - assert("You defined the '" + name + "' relationship on " + this + ", but you defined the inverse relationships of type " + - inverseType.toString() + " multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", - filteredRelationships.length < 2); - - if (filteredRelationships.length === 1 ) { - possibleRelationships = filteredRelationships; - } - - assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + - this + " were found on " + inverseType + ". Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", - possibleRelationships.length === 1); - - inverseName = possibleRelationships[0].name; - inverseKind = possibleRelationships[0].kind; - } - - function findPossibleInverses(type, inverseType, relationshipsSoFar) { - var possibleRelationships = relationshipsSoFar || []; - - var relationshipMap = get(inverseType, 'relationships'); - if (!relationshipMap) { return possibleRelationships; } - - var relationships = relationshipMap.get(type.modelName); - - relationships = relationships.filter((relationship) => { - var optionsForRelationship = inverseType.metaForProperty(relationship.name).options; - - if (!optionsForRelationship.inverse) { - return true; - } - - return name === optionsForRelationship.inverse; - }); - - if (relationships) { - possibleRelationships.push.apply(possibleRelationships, relationships); - } - - //Recurse to support polymorphism - if (type.superclass) { - findPossibleInverses(type.superclass, inverseType, possibleRelationships); - } - - return possibleRelationships; - } - - return { - type: inverseType, - name: inverseName, - kind: inverseKind - }; - }, - - /** - The model's relationships as a map, keyed on the type of the - relationship. The value of each entry is an array containing a descriptor - for each relationship with that type, describing the name of the relationship - as well as the type. - - For example, given the following model definition: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - posts: DS.hasMany('post') - }); - ``` - - This computed property would return a map describing these - relationships, like this: - - ```javascript - import Ember from 'ember'; - import Blog from 'app/models/blog'; - import User from 'app/models/user'; - import Post from 'app/models/post'; - - var relationships = Ember.get(Blog, 'relationships'); - relationships.get(User); - //=> [ { name: 'users', kind: 'hasMany' }, - // { name: 'owner', kind: 'belongsTo' } ] - relationships.get(Post); - //=> [ { name: 'posts', kind: 'hasMany' } ] - ``` - - @property relationships - @static - @type Ember.Map - @readOnly - */ - - relationships: relationshipsDescriptor, - - /** - A hash containing lists of the model's relationships, grouped - by the relationship kind. For example, given a model with this - definition: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - import Ember from 'ember'; - import Blog from 'app/models/blog'; - - var relationshipNames = Ember.get(Blog, 'relationshipNames'); - relationshipNames.hasMany; - //=> ['users', 'posts'] - relationshipNames.belongsTo; - //=> ['owner'] - ``` - - @property relationshipNames - @static - @type Object - @readOnly - */ - relationshipNames: Ember.computed(function() { - var names = { - hasMany: [], - belongsTo: [] - }; - - this.eachComputedProperty((name, meta) => { - if (meta.isRelationship) { - names[meta.kind].push(name); - } - }); - - return names; - }), - - /** - An array of types directly related to a model. Each type will be - included once, regardless of the number of relationships it has with - the model. - - For example, given a model with this definition: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - import Ember from 'ember'; - import Blog from 'app/models/blog'; - - var relatedTypes = Ember.get(Blog, 'relatedTypes'); - //=> [ User, Post ] - ``` - - @property relatedTypes - @static - @type Ember.Array - @readOnly - */ - relatedTypes: relatedTypesDescriptor, - - /** - A map whose keys are the relationships of a model and whose values are - relationship descriptors. - - For example, given a model with this - definition: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - import Ember from 'ember'; - import Blog from 'app/models/blog'; - - var relationshipsByName = Ember.get(Blog, 'relationshipsByName'); - relationshipsByName.get('users'); - //=> { key: 'users', kind: 'hasMany', type: 'user', options: Object, isRelationship: true } - relationshipsByName.get('owner'); - //=> { key: 'owner', kind: 'belongsTo', type: 'user', options: Object, isRelationship: true } - ``` - - @property relationshipsByName - @static - @type Ember.Map - @readOnly - */ - relationshipsByName: relationshipsByNameDescriptor, - - /** - A map whose keys are the fields of the model and whose values are strings - describing the kind of the field. A model's fields are the union of all of its - attributes and relationships. - - For example: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post'), - - title: DS.attr('string') - }); - ``` - - ```js - import Ember from 'ember'; - import Blog from 'app/models/blog'; - - var fields = Ember.get(Blog, 'fields'); - fields.forEach(function(kind, field) { - console.log(field, kind); - }); - - // prints: - // users, hasMany - // owner, belongsTo - // posts, hasMany - // title, attribute - ``` - - @property fields - @static - @type Ember.Map - @readOnly - */ - fields: Ember.computed(function() { - var map = Map.create(); - - this.eachComputedProperty((name, meta) => { - if (meta.isRelationship) { - map.set(name, meta.kind); - } else if (meta.isAttribute) { - map.set(name, 'attribute'); - } - }); - - return map; - }).readOnly(), - - /** - Given a callback, iterates over each of the relationships in the model, - invoking the callback with the name of each relationship and its relationship - descriptor. - - @method eachRelationship - @static - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelationship(callback, binding) { - get(this, 'relationshipsByName').forEach((relationship, name) => { - callback.call(binding, name, relationship); - }); - }, - - /** - Given a callback, iterates over each of the types related to a model, - invoking the callback with the related type's class. Each type will be - returned just once, regardless of how many different relationships it has - with a model. - - @method eachRelatedType - @static - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelatedType(callback, binding) { - let relationshipTypes = get(this, 'relatedTypes'); - - for (let i = 0; i < relationshipTypes.length; i++) { - let type = relationshipTypes[i]; - callback.call(binding, type); - } - }, - - determineRelationshipType(knownSide, store) { - let knownKey = knownSide.key; - let knownKind = knownSide.kind; - let inverse = this.inverseFor(knownKey, store); - // let key; - let otherKind; - - if (!inverse) { - return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone'; - } - - // key = inverse.name; - otherKind = inverse.kind; - - if (otherKind === 'belongsTo') { - return knownKind === 'belongsTo' ? 'oneToOne' : 'manyToOne'; - } else { - return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany'; - } - } - -}); - export const RelationshipsInstanceMethodsMixin = Ember.Mixin.create({ /** Given a callback, iterates over each of the relationships in the model, From 3adb790fc6c75260375357aa88be53ab156cf6d7 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Dec 2016 14:39:06 -0800 Subject: [PATCH 1735/2527] move debug-info mixin into DS.Model directly --- addon/-private/system/debug/debug-info.js | 66 ----------------------- addon/-private/system/model/model.js | 65 +++++++++++++++++++++- 2 files changed, 63 insertions(+), 68 deletions(-) delete mode 100644 addon/-private/system/debug/debug-info.js diff --git a/addon/-private/system/debug/debug-info.js b/addon/-private/system/debug/debug-info.js deleted file mode 100644 index bebc89c38e7..00000000000 --- a/addon/-private/system/debug/debug-info.js +++ /dev/null @@ -1,66 +0,0 @@ -import Ember from "ember"; - -export default Ember.Mixin.create({ - - /** - Provides info about the model for debugging purposes - by grouping the properties into more semantic groups. - - Meant to be used by debugging tools such as the Chrome Ember Extension. - - - Groups all attributes in "Attributes" group. - - Groups all belongsTo relationships in "Belongs To" group. - - Groups all hasMany relationships in "Has Many" group. - - Groups all flags in "Flags" group. - - Flags relationship CPs as expensive properties. - - @method _debugInfo - @for DS.Model - @private - */ - _debugInfo() { - let attributes = ['id']; - let relationships = { }; - let expensiveProperties = []; - - this.eachAttribute((name, meta) => attributes.push(name)); - - let groups = [ - { - name: 'Attributes', - properties: attributes, - expand: true - } - ]; - - this.eachRelationship((name, relationship) => { - let properties = relationships[relationship.kind]; - - if (properties === undefined) { - properties = relationships[relationship.kind] = []; - groups.push({ - name: relationship.name, - properties, - expand: true - }); - } - properties.push(name); - expensiveProperties.push(name); - }); - - groups.push({ - name: 'Flags', - properties: ['isLoaded', 'hasDirtyAttributes', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'] - }); - - return { - propertyInfo: { - // include all other mixins / properties (not just the grouped ones) - includeOtherProperties: true, - groups: groups, - // don't pre-calculate unless cached - expensiveProperties: expensiveProperties - } - }; - } -}); diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index f1e4e89db9c..aeaa312ab20 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -954,9 +954,70 @@ const Model = Ember.Object.extend(Ember.Evented, { setId: Ember.observer('id', function () { this._internalModel.setId(this.get('id')); - }) + }), + + /** + Provides info about the model for debugging purposes + by grouping the properties into more semantic groups. + + Meant to be used by debugging tools such as the Chrome Ember Extension. + + - Groups all attributes in "Attributes" group. + - Groups all belongsTo relationships in "Belongs To" group. + - Groups all hasMany relationships in "Has Many" group. + - Groups all flags in "Flags" group. + - Flags relationship CPs as expensive properties. + + @method _debugInfo + @for DS.Model + @private + */ + _debugInfo() { + let attributes = ['id']; + let relationships = { }; + let expensiveProperties = []; + + this.eachAttribute((name, meta) => attributes.push(name)); + + let groups = [ + { + name: 'Attributes', + properties: attributes, + expand: true + } + ]; + + this.eachRelationship((name, relationship) => { + let properties = relationships[relationship.kind]; + + if (properties === undefined) { + properties = relationships[relationship.kind] = []; + groups.push({ + name: relationship.name, + properties, + expand: true + }); + } + properties.push(name); + expensiveProperties.push(name); + }); + + groups.push({ + name: 'Flags', + properties: ['isLoaded', 'hasDirtyAttributes', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'] + }); + + return { + propertyInfo: { + // include all other mixins / properties (not just the grouped ones) + includeOtherProperties: true, + groups: groups, + // don't pre-calculate unless cached + expensiveProperties: expensiveProperties + } + }; + } }, - DebuggerInfoMixin, BelongsToMixin, DidDefinePropertyMixin, RelationshipsInstanceMethodsMixin, From da438fa3c8432efae022f24b838760128569a09d Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Dec 2016 14:39:49 -0800 Subject: [PATCH 1736/2527] move belongsTo mixin into DS.Model directly --- addon/-private/system/model/model.js | 7 ++++--- addon/-private/system/relationships/belongs-to.js | 10 ---------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index aeaa312ab20..a94d5ac859c 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -2,8 +2,6 @@ import Ember from 'ember'; import { assert, deprecate, warn } from "ember-data/-private/debug"; import { PromiseObject } from "ember-data/-private/system/promise-proxies"; import Errors from "ember-data/-private/system/model/errors"; -import DebuggerInfoMixin from 'ember-data/-private/system/debug/debug-info'; -import { BelongsToMixin } from 'ember-data/-private/system/relationships/belongs-to'; import { HasManyMixin } from 'ember-data/-private/system/relationships/has-many'; import { DidDefinePropertyMixin, RelationshipsInstanceMethodsMixin } from 'ember-data/-private/system/relationships/ext'; import { AttrClassMethodsMixin, AttrInstanceMethodsMixin } from 'ember-data/-private/system/model/attr'; @@ -1016,9 +1014,12 @@ const Model = Ember.Object.extend(Ember.Evented, { expensiveProperties: expensiveProperties } }; + }, + + notifyBelongsToChanged(key) { + this.notifyPropertyChange(key); } }, - BelongsToMixin, DidDefinePropertyMixin, RelationshipsInstanceMethodsMixin, HasManyMixin, diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 15a9d875409..082300fc467 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -133,13 +133,3 @@ export default function belongsTo(modelName, options) { } }).meta(meta); } - -/* - These observers observe all `belongsTo` relationships on the record. See - `relationships/ext` to see how these observers get their dependencies. -*/ -export const BelongsToMixin = Ember.Mixin.create({ - notifyBelongsToChanged(key) { - this.notifyPropertyChange(key); - } -}); From dcf5dab1d03d000f5574e7390bfbcc1a3ac2e749 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Dec 2016 14:41:56 -0800 Subject: [PATCH 1737/2527] move did-define-property mixin into DS.Model directly --- addon/-private/system/model/model.js | 41 ++++++++++++++++++- addon/-private/system/relationships/ext.js | 46 ---------------------- 2 files changed, 40 insertions(+), 47 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index a94d5ac859c..254e6152b03 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -3,7 +3,7 @@ import { assert, deprecate, warn } from "ember-data/-private/debug"; import { PromiseObject } from "ember-data/-private/system/promise-proxies"; import Errors from "ember-data/-private/system/model/errors"; import { HasManyMixin } from 'ember-data/-private/system/relationships/has-many'; -import { DidDefinePropertyMixin, RelationshipsInstanceMethodsMixin } from 'ember-data/-private/system/relationships/ext'; +import { RelationshipsInstanceMethodsMixin } from 'ember-data/-private/system/relationships/ext'; import { AttrClassMethodsMixin, AttrInstanceMethodsMixin } from 'ember-data/-private/system/model/attr'; import isEnabled from 'ember-data/-private/features'; import RootState from 'ember-data/-private/system/model/states'; @@ -1018,6 +1018,45 @@ const Model = Ember.Object.extend(Ember.Evented, { notifyBelongsToChanged(key) { this.notifyPropertyChange(key); + }, + + /** + This Ember.js hook allows an object to be notified when a property + is defined. + + In this case, we use it to be notified when an Ember Data user defines a + belongs-to relationship. In that case, we need to set up observers for + each one, allowing us to track relationship changes and automatically + reflect changes in the inverse has-many array. + + This hook passes the class being set up, as well as the key and value + being defined. So, for example, when the user does this: + + ```javascript + DS.Model.extend({ + parent: DS.belongsTo('user') + }); + ``` + + This hook would be called with "parent" as the key and the computed + property returned by `DS.belongsTo` as the value. + + @method didDefineProperty + @param {Object} proto + @param {String} key + @param {Ember.ComputedProperty} value + */ + didDefineProperty(proto, key, value) { + // Check if the value being set is a computed property. + if (value instanceof Ember.ComputedProperty) { + + // If it is, get the metadata for the relationship. This is + // populated by the `DS.belongsTo` helper when it is creating + // the computed property. + var meta = value.meta(); + + meta.parentType = proto.constructor; + } } }, DidDefinePropertyMixin, diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index ad2a4c881ce..8f089688c33 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -92,52 +92,6 @@ var relationshipsByNameDescriptor = Ember.computed(function() { add support for one-to-many relationships. */ -/** - @class Model - @namespace DS -*/ -export const DidDefinePropertyMixin = Ember.Mixin.create({ - - /** - This Ember.js hook allows an object to be notified when a property - is defined. - - In this case, we use it to be notified when an Ember Data user defines a - belongs-to relationship. In that case, we need to set up observers for - each one, allowing us to track relationship changes and automatically - reflect changes in the inverse has-many array. - - This hook passes the class being set up, as well as the key and value - being defined. So, for example, when the user does this: - - ```javascript - DS.Model.extend({ - parent: DS.belongsTo('user') - }); - ``` - - This hook would be called with "parent" as the key and the computed - property returned by `DS.belongsTo` as the value. - - @method didDefineProperty - @param {Object} proto - @param {String} key - @param {Ember.ComputedProperty} value - */ - didDefineProperty(proto, key, value) { - // Check if the value being set is a computed property. - if (value instanceof Ember.ComputedProperty) { - - // If it is, get the metadata for the relationship. This is - // populated by the `DS.belongsTo` helper when it is creating - // the computed property. - var meta = value.meta(); - - meta.parentType = proto.constructor; - } - } -}); - export const RelationshipsInstanceMethodsMixin = Ember.Mixin.create({ /** Given a callback, iterates over each of the relationships in the model, From 6955418cfb37be24555fcca219c8c6a49834b00a Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Dec 2016 14:44:55 -0800 Subject: [PATCH 1738/2527] move relationship methods into DS.Model directly --- addon/-private/system/model/model.js | 68 +++++++++++++++++++++- addon/-private/system/relationships/ext.js | 63 -------------------- 2 files changed, 65 insertions(+), 66 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 254e6152b03..46e95e3c68c 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -3,7 +3,6 @@ import { assert, deprecate, warn } from "ember-data/-private/debug"; import { PromiseObject } from "ember-data/-private/system/promise-proxies"; import Errors from "ember-data/-private/system/model/errors"; import { HasManyMixin } from 'ember-data/-private/system/relationships/has-many'; -import { RelationshipsInstanceMethodsMixin } from 'ember-data/-private/system/relationships/ext'; import { AttrClassMethodsMixin, AttrInstanceMethodsMixin } from 'ember-data/-private/system/model/attr'; import isEnabled from 'ember-data/-private/features'; import RootState from 'ember-data/-private/system/model/states'; @@ -1057,10 +1056,73 @@ const Model = Ember.Object.extend(Ember.Evented, { meta.parentType = proto.constructor; } + }, + + /** + Given a callback, iterates over each of the relationships in the model, + invoking the callback with the name of each relationship and its relationship + descriptor. + + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(name, descriptor); + ``` + + - `name` the name of the current property in the iteration + - `descriptor` the meta object that describes this relationship + + The relationship descriptor argument is an object with the following properties. + + - **key** String the name of this relationship on the Model + - **kind** String "hasMany" or "belongsTo" + - **options** Object the original options hash passed when the relationship was declared + - **parentType** DS.Model the type of the Model that owns this relationship + - **type** String the type name of the related Model + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. + + Example + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + serialize: function(record, options) { + var json = {}; + + record.eachRelationship(function(name, descriptor) { + if (descriptor.kind === 'hasMany') { + var serializedHasManyName = name.toUpperCase() + '_IDS'; + json[serializedHasManyName] = record.get(name).mapBy('id'); + } + }); + + return json; + } + }); + ``` + + @method eachRelationship + @param {Function} callback the callback to invoke + @param {any} binding the value to which the callback's `this` should be bound + */ + eachRelationship(callback, binding) { + this.constructor.eachRelationship(callback, binding); + }, + + relationshipFor(name) { + return get(this.constructor, 'relationshipsByName').get(name); + }, + + inverseFor(key) { + return this.constructor.inverseFor(key, this.store); } + }, - DidDefinePropertyMixin, - RelationshipsInstanceMethodsMixin, HasManyMixin, AttrInstanceMethodsMixin ); diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 8f089688c33..84be4595106 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -93,68 +93,5 @@ var relationshipsByNameDescriptor = Ember.computed(function() { */ export const RelationshipsInstanceMethodsMixin = Ember.Mixin.create({ - /** - Given a callback, iterates over each of the relationships in the model, - invoking the callback with the name of each relationship and its relationship - descriptor. - - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, descriptor); - ``` - - - `name` the name of the current property in the iteration - - `descriptor` the meta object that describes this relationship - - The relationship descriptor argument is an object with the following properties. - - - **key** String the name of this relationship on the Model - - **kind** String "hasMany" or "belongsTo" - - **options** Object the original options hash passed when the relationship was declared - - **parentType** DS.Model the type of the Model that owns this relationship - - **type** String the type name of the related Model - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - serialize: function(record, options) { - var json = {}; - - record.eachRelationship(function(name, descriptor) { - if (descriptor.kind === 'hasMany') { - var serializedHasManyName = name.toUpperCase() + '_IDS'; - json[serializedHasManyName] = record.get(name).mapBy('id'); - } - }); - - return json; - } - }); - ``` - - @method eachRelationship - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelationship(callback, binding) { - this.constructor.eachRelationship(callback, binding); - }, - - relationshipFor(name) { - return get(this.constructor, 'relationshipsByName').get(name); - }, - - inverseFor(key) { - return this.constructor.inverseFor(key, this.store); - } }); From 5909f8a5f9bc78ff9904411a87f6f3cf51946898 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Dec 2016 14:48:23 -0800 Subject: [PATCH 1739/2527] fix relationship descriptor wiring --- addon/-private/system/model/model.js | 5 +++++ addon/-private/system/relationships/ext.js | 20 +++----------------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 46e95e3c68c..b54f304d761 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -7,6 +7,11 @@ import { AttrClassMethodsMixin, AttrInstanceMethodsMixin } from 'ember-data/-pri import isEnabled from 'ember-data/-private/features'; import RootState from 'ember-data/-private/system/model/states'; import EmptyObject from "ember-data/-private/system/empty-object"; +import { + relationshipsByNameDescriptor, + relatedTypesDescriptor, + relationshipsDescriptor +} from 'ember-data/-private/system/relationships/ext'; const { get, diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 84be4595106..d4042949ec8 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -5,11 +5,10 @@ import { relationshipFromMeta } from "ember-data/-private/system/relationship-meta"; -var get = Ember.get; var Map = Ember.Map; var MapWithDefault = Ember.MapWithDefault; -var relationshipsDescriptor = Ember.computed(function() { +export const relationshipsDescriptor = Ember.computed(function() { if (Ember.testing === true && relationshipsDescriptor._cacheable === true) { relationshipsDescriptor._cacheable = false; } @@ -36,7 +35,7 @@ var relationshipsDescriptor = Ember.computed(function() { return map; }).readOnly(); -var relatedTypesDescriptor = Ember.computed(function() { +export const relatedTypesDescriptor = Ember.computed(function() { if (Ember.testing === true && relatedTypesDescriptor._cacheable === true) { relatedTypesDescriptor._cacheable = false; } @@ -64,7 +63,7 @@ var relatedTypesDescriptor = Ember.computed(function() { return types; }).readOnly(); -var relationshipsByNameDescriptor = Ember.computed(function() { +export const relationshipsByNameDescriptor = Ember.computed(function() { if (Ember.testing === true && relationshipsByNameDescriptor._cacheable === true) { relationshipsByNameDescriptor._cacheable = false; } @@ -82,16 +81,3 @@ var relationshipsByNameDescriptor = Ember.computed(function() { return map; }).readOnly(); - -/** - @module ember-data -*/ - -/* - This file defines several extensions to the base `DS.Model` class that - add support for one-to-many relationships. -*/ - -export const RelationshipsInstanceMethodsMixin = Ember.Mixin.create({ - -}); From 5a99691c6e3c1adfc6b6e8a77ed8816e046b6831 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Dec 2016 14:49:44 -0800 Subject: [PATCH 1740/2527] fix missing Map --- addon/-private/system/model/model.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index b54f304d761..a151217c9c1 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -15,7 +15,8 @@ import { const { get, - computed + computed, + Map } = Ember; /** From afe5fe42fd60c5259d231950865905bd705a9bac Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Dec 2016 17:04:21 -0800 Subject: [PATCH 1741/2527] move hasMany mixin into DS.Model --- addon/-private/system/model/model.js | 15 ++++++++++----- addon/-private/system/relationships/has-many.js | 11 ----------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index a151217c9c1..153304dd112 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -2,7 +2,6 @@ import Ember from 'ember'; import { assert, deprecate, warn } from "ember-data/-private/debug"; import { PromiseObject } from "ember-data/-private/system/promise-proxies"; import Errors from "ember-data/-private/system/model/errors"; -import { HasManyMixin } from 'ember-data/-private/system/relationships/has-many'; import { AttrClassMethodsMixin, AttrInstanceMethodsMixin } from 'ember-data/-private/system/model/attr'; import isEnabled from 'ember-data/-private/features'; import RootState from 'ember-data/-private/system/model/states'; @@ -1126,12 +1125,18 @@ const Model = Ember.Object.extend(Ember.Evented, { inverseFor(key) { return this.constructor.inverseFor(key, this.store); + }, + + notifyHasManyAdded(key) { + //We need to notifyPropertyChange in the adding case because we need to make sure + //we fetch the newly added record in case it is unloaded + //TODO(Igor): Consider whether we could do this only if the record state is unloaded + + //Goes away once hasMany is double promisified + this.notifyPropertyChange(key); } -}, - HasManyMixin, - AttrInstanceMethodsMixin -); +}, AttrInstanceMethodsMixin); /** @property data diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index cd2848cf386..fc82f89bdbf 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -159,14 +159,3 @@ export default function hasMany(type, options) { } }).meta(meta); } - -export const HasManyMixin = Ember.Mixin.create({ - notifyHasManyAdded(key) { - //We need to notifyPropertyChange in the adding case because we need to make sure - //we fetch the newly added record in case it is unloaded - //TODO(Igor): Consider whether we could do this only if the record state is unloaded - - //Goes away once hasMany is double promisified - this.notifyPropertyChange(key); - } -}); From aa5223d9c60e6f12239ceb832389adc1ecffab49 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Dec 2016 17:05:32 -0800 Subject: [PATCH 1742/2527] move attr mixin into DS.Model --- addon/-private/system/model/attr.js | 7 ------- addon/-private/system/model/model.js | 9 ++++++--- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/addon/-private/system/model/attr.js b/addon/-private/system/model/attr.js index e111424e977..edb637dd126 100644 --- a/addon/-private/system/model/attr.js +++ b/addon/-private/system/model/attr.js @@ -217,10 +217,3 @@ export const AttrClassMethodsMixin = Ember.Mixin.create({ }); } }); - - -export const AttrInstanceMethodsMixin = Ember.Mixin.create({ - eachAttribute(callback, binding) { - this.constructor.eachAttribute(callback, binding); - } -}); diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 153304dd112..02835b4524b 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -2,7 +2,7 @@ import Ember from 'ember'; import { assert, deprecate, warn } from "ember-data/-private/debug"; import { PromiseObject } from "ember-data/-private/system/promise-proxies"; import Errors from "ember-data/-private/system/model/errors"; -import { AttrClassMethodsMixin, AttrInstanceMethodsMixin } from 'ember-data/-private/system/model/attr'; +import { AttrClassMethodsMixin } from 'ember-data/-private/system/model/attr'; import isEnabled from 'ember-data/-private/features'; import RootState from 'ember-data/-private/system/model/states'; import EmptyObject from "ember-data/-private/system/empty-object"; @@ -1134,9 +1134,12 @@ const Model = Ember.Object.extend(Ember.Evented, { //Goes away once hasMany is double promisified this.notifyPropertyChange(key); - } + }, -}, AttrInstanceMethodsMixin); + eachAttribute(callback, binding) { + this.constructor.eachAttribute(callback, binding); + } +}); /** @property data From 836d24e93baf5155271e58734695ff5007274623 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Dec 2016 17:06:51 -0800 Subject: [PATCH 1743/2527] move attr class mixin into unified reopenClass --- addon/-private/system/model/attr.js | 219 --------------------------- addon/-private/system/model/model.js | 205 ++++++++++++++++++++++++- 2 files changed, 203 insertions(+), 221 deletions(-) delete mode 100644 addon/-private/system/model/attr.js diff --git a/addon/-private/system/model/attr.js b/addon/-private/system/model/attr.js deleted file mode 100644 index edb637dd126..00000000000 --- a/addon/-private/system/model/attr.js +++ /dev/null @@ -1,219 +0,0 @@ -import Ember from 'ember'; -import { assert } from "ember-data/-private/debug"; - - -var get = Ember.get; -var Map = Ember.Map; - -/** - @module ember-data -*/ - -/** - @class Model - @namespace DS -*/ - -export const AttrClassMethodsMixin = Ember.Mixin.create({ - /** - A map whose keys are the attributes of the model (properties - described by DS.attr) and whose values are the meta object for the - property. - - Example - - ```app/models/person.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - firstName: attr('string'), - lastName: attr('string'), - birthday: attr('date') - }); - ``` - - ```javascript - import Ember from 'ember'; - import Person from 'app/models/person'; - - var attributes = Ember.get(Person, 'attributes') - - attributes.forEach(function(meta, name) { - console.log(name, meta); - }); - - // prints: - // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} - // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} - // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} - ``` - - @property attributes - @static - @type {Ember.Map} - @readOnly - */ - attributes: Ember.computed(function() { - var map = Map.create(); - - this.eachComputedProperty((name, meta) => { - if (meta.isAttribute) { - assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.toString(), name !== 'id'); - - meta.name = name; - map.set(name, meta); - } - }); - - return map; - }).readOnly(), - - /** - A map whose keys are the attributes of the model (properties - described by DS.attr) and whose values are type of transformation - applied to each attribute. This map does not include any - attributes that do not have an transformation type. - - Example - - ```app/models/person.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - firstName: attr(), - lastName: attr('string'), - birthday: attr('date') - }); - ``` - - ```javascript - import Ember from 'ember'; - import Person from 'app/models/person'; - - var transformedAttributes = Ember.get(Person, 'transformedAttributes') - - transformedAttributes.forEach(function(field, type) { - console.log(field, type); - }); - - // prints: - // lastName string - // birthday date - ``` - - @property transformedAttributes - @static - @type {Ember.Map} - @readOnly - */ - transformedAttributes: Ember.computed(function() { - var map = Map.create(); - - this.eachAttribute((key, meta) => { - if (meta.type) { - map.set(key, meta.type); - } - }); - - return map; - }).readOnly(), - - /** - Iterates through the attributes of the model, calling the passed function on each - attribute. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, meta); - ``` - - - `name` the name of the current property in the iteration - - `meta` the meta object for the attribute property in the iteration - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```javascript - import DS from 'ember-data'; - - var Person = DS.Model.extend({ - firstName: attr('string'), - lastName: attr('string'), - birthday: attr('date') - }); - - Person.eachAttribute(function(name, meta) { - console.log(name, meta); - }); - - // prints: - // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} - // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} - // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} - ``` - - @method eachAttribute - @param {Function} callback The callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - @static - */ - eachAttribute(callback, binding) { - get(this, 'attributes').forEach((meta, name) => { - callback.call(binding, name, meta); - }); - }, - - /** - Iterates through the transformedAttributes of the model, calling - the passed function on each attribute. Note the callback will not be - called for any attributes that do not have an transformation type. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, type); - ``` - - - `name` the name of the current property in the iteration - - `type` a string containing the name of the type of transformed - applied to the attribute - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```javascript - import DS from 'ember-data'; - - var Person = DS.Model.extend({ - firstName: attr(), - lastName: attr('string'), - birthday: attr('date') - }); - - Person.eachTransformedAttribute(function(name, type) { - console.log(name, type); - }); - - // prints: - // lastName string - // birthday date - ``` - - @method eachTransformedAttribute - @param {Function} callback The callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - @static - */ - eachTransformedAttribute(callback, binding) { - get(this, 'transformedAttributes').forEach((type, name) => { - callback.call(binding, name, type); - }); - } -}); diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 02835b4524b..af8bcf811d8 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1665,9 +1665,210 @@ Model.reopenClass({ } else { return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany'; } - } + }, + + /** + A map whose keys are the attributes of the model (properties + described by DS.attr) and whose values are the meta object for the + property. + + Example + + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + birthday: attr('date') + }); + ``` + + ```javascript + import Ember from 'ember'; + import Person from 'app/models/person'; + + var attributes = Ember.get(Person, 'attributes') -}, AttrClassMethodsMixin); + attributes.forEach(function(meta, name) { + console.log(name, meta); + }); + + // prints: + // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} + // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} + // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} + ``` + + @property attributes + @static + @type {Ember.Map} + @readOnly + */ + attributes: Ember.computed(function() { + var map = Map.create(); + + this.eachComputedProperty((name, meta) => { + if (meta.isAttribute) { + assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.toString(), name !== 'id'); + + meta.name = name; + map.set(name, meta); + } + }); + + return map; + }).readOnly(), + + /** + A map whose keys are the attributes of the model (properties + described by DS.attr) and whose values are type of transformation + applied to each attribute. This map does not include any + attributes that do not have an transformation type. + + Example + + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + firstName: attr(), + lastName: attr('string'), + birthday: attr('date') + }); + ``` + + ```javascript + import Ember from 'ember'; + import Person from 'app/models/person'; + + var transformedAttributes = Ember.get(Person, 'transformedAttributes') + + transformedAttributes.forEach(function(field, type) { + console.log(field, type); + }); + + // prints: + // lastName string + // birthday date + ``` + + @property transformedAttributes + @static + @type {Ember.Map} + @readOnly + */ + transformedAttributes: Ember.computed(function() { + var map = Map.create(); + + this.eachAttribute((key, meta) => { + if (meta.type) { + map.set(key, meta.type); + } + }); + + return map; + }).readOnly(), + + /** + Iterates through the attributes of the model, calling the passed function on each + attribute. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(name, meta); + ``` + + - `name` the name of the current property in the iteration + - `meta` the meta object for the attribute property in the iteration + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. + + Example + + ```javascript + import DS from 'ember-data'; + + var Person = DS.Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + birthday: attr('date') + }); + + Person.eachAttribute(function(name, meta) { + console.log(name, meta); + }); + + // prints: + // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} + // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} + // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} + ``` + + @method eachAttribute + @param {Function} callback The callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + @static + */ + eachAttribute(callback, binding) { + get(this, 'attributes').forEach((meta, name) => { + callback.call(binding, name, meta); + }); + }, + + /** + Iterates through the transformedAttributes of the model, calling + the passed function on each attribute. Note the callback will not be + called for any attributes that do not have an transformation type. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(name, type); + ``` + + - `name` the name of the current property in the iteration + - `type` a string containing the name of the type of transformed + applied to the attribute + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. + + Example + + ```javascript + import DS from 'ember-data'; + + var Person = DS.Model.extend({ + firstName: attr(), + lastName: attr('string'), + birthday: attr('date') + }); + + Person.eachTransformedAttribute(function(name, type) { + console.log(name, type); + }); + + // prints: + // lastName string + // birthday date + ``` + + @method eachTransformedAttribute + @param {Function} callback The callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + @static + */ + eachTransformedAttribute(callback, binding) { + get(this, 'transformedAttributes').forEach((type, name) => { + callback.call(binding, name, type); + }); + } +}); // if `Ember.setOwner` is defined, accessing `this.container` is // deprecated (but functional). In "standard" Ember usage, this From ed0b83bfd65d4f8431883892b18463aba68ab9ce Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Dec 2016 17:07:32 -0800 Subject: [PATCH 1744/2527] remove forgotten import --- addon/-private/system/model/model.js | 1 - 1 file changed, 1 deletion(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index af8bcf811d8..7a3b8937829 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -2,7 +2,6 @@ import Ember from 'ember'; import { assert, deprecate, warn } from "ember-data/-private/debug"; import { PromiseObject } from "ember-data/-private/system/promise-proxies"; import Errors from "ember-data/-private/system/model/errors"; -import { AttrClassMethodsMixin } from 'ember-data/-private/system/model/attr'; import isEnabled from 'ember-data/-private/features'; import RootState from 'ember-data/-private/system/model/states'; import EmptyObject from "ember-data/-private/system/empty-object"; From 61a962c3cfee4bbbbaeddc16928fd50ab7e9cfb8 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Dec 2016 17:09:25 -0800 Subject: [PATCH 1745/2527] ES6 code cleanup --- addon/-private/system/model/model.js | 126 +++++++++++++-------------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 7a3b8937829..4a0ba389e5f 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -22,7 +22,7 @@ const { */ function intersection (array1, array2) { - var result = []; + let result = []; array1.forEach((element) => { if (array2.indexOf(element) >= 0) { result.push(element); @@ -91,7 +91,7 @@ const Model = Ember.Object.extend(Ember.Evented, { Example ```javascript - var record = store.createRecord('model'); + let record = store.createRecord('model'); record.get('isLoaded'); // true store.findRecord('model', 1).then(function(model) { @@ -113,7 +113,7 @@ const Model = Ember.Object.extend(Ember.Evented, { Example ```javascript - var record = store.createRecord('model'); + let record = store.createRecord('model'); record.get('hasDirtyAttributes'); // true store.findRecord('model', 1).then(function(model) { @@ -140,9 +140,9 @@ const Model = Ember.Object.extend(Ember.Evented, { Example ```javascript - var record = store.createRecord('model'); + let record = store.createRecord('model'); record.get('isSaving'); // false - var promise = record.save(); + let promise = record.save(); record.get('isSaving'); // true promise.then(function() { record.get('isSaving'); // false @@ -165,7 +165,7 @@ const Model = Ember.Object.extend(Ember.Evented, { Example ```javascript - var record = store.createRecord('model'); + let record = store.createRecord('model'); record.get('isDeleted'); // false record.deleteRecord(); @@ -175,7 +175,7 @@ const Model = Ember.Object.extend(Ember.Evented, { record.get('isSaving'); // false // Persisting the deletion - var promise = record.save(); + let promise = record.save(); record.get('isDeleted'); // true record.get('isSaving'); // true @@ -201,7 +201,7 @@ const Model = Ember.Object.extend(Ember.Evented, { Example ```javascript - var record = store.createRecord('model'); + let record = store.createRecord('model'); record.get('isNew'); // true record.save().then(function(model) { @@ -237,7 +237,7 @@ const Model = Ember.Object.extend(Ember.Evented, { Example ```javascript - var record = store.createRecord('model'); + let record = store.createRecord('model'); record.get('dirtyType'); // 'created' ``` @@ -293,7 +293,7 @@ const Model = Ember.Object.extend(Ember.Evented, { attribute. ```javascript - var record = store.createRecord('model'); + let record = store.createRecord('model'); record.get('id'); // null store.findRecord('model', 1).then(function(model) { @@ -420,8 +420,8 @@ const Model = Ember.Object.extend(Ember.Evented, { */ toJSON(options) { // container is for lazy transform lookups - var serializer = this.store.serializerFor('-default'); - var snapshot = this._internalModel.createSnapshot(); + let serializer = this.store.serializerFor('-default'); + let snapshot = this._internalModel.createSnapshot(); return serializer.serialize(snapshot, options); }, @@ -547,7 +547,7 @@ const Model = Ember.Object.extend(Ember.Evented, { export default Ember.Route.extend({ actions: { delete: function() { - var controller = this.controller; + let controller = this.controller; controller.get('model').destroyRecord().then(function() { controller.transitionToRoute('model.index'); }); @@ -601,8 +601,8 @@ const Model = Ember.Object.extend(Ember.Evented, { */ _notifyProperties(keys) { Ember.beginPropertyChanges(); - var key; - for (var i = 0, length = keys.length; i < length; i++) { + let key; + for (let i = 0, length = keys.length; i < length; i++) { key = keys[i]; this.notifyPropertyChange(key); } @@ -631,7 +631,7 @@ const Model = Ember.Object.extend(Ember.Evented, { ``` ```javascript - var mascot = store.createRecord('mascot'); + let mascot = store.createRecord('mascot'); mascot.changedAttributes(); // {} @@ -796,10 +796,10 @@ const Model = Ember.Object.extend(Ember.Evented, { @param {String} name */ trigger(name) { - var length = arguments.length; - var args = new Array(length - 1); + let length = arguments.length; + let args = new Array(length - 1); - for (var i = 1; i < length; i++) { + for (let i = 1; i < length; i++) { args[i - 1] = arguments[i]; } @@ -818,7 +818,7 @@ const Model = Ember.Object.extend(Ember.Evented, { // This is a temporary solution until we refactor DS.Model to not // rely on the data property. willMergeMixin(props) { - var constructor = this.constructor; + let constructor = this.constructor; assert('`' + intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + constructor.toString(), !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0]); assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + constructor.toString(), Object.keys(props).indexOf('id') === -1); }, @@ -839,7 +839,7 @@ const Model = Ember.Object.extend(Ember.Evented, { ``` ```javascript - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, @@ -850,19 +850,19 @@ const Model = Ember.Object.extend(Ember.Evented, { } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); // check if the user relationship is loaded - var isLoaded = userRef.value() !== null; + let isLoaded = userRef.value() !== null; // get the record of the reference (null if not yet available) - var user = userRef.value(); + let user = userRef.value(); // get the identifier of the reference if (userRef.remoteType() === "id") { - var id = userRef.id(); + let id = userRef.id(); } else if (userRef.remoteType() === "link") { - var link = userRef.link(); + let link = userRef.link(); } // load user (via store.findRecord or store.findBelongsTo) @@ -903,7 +903,7 @@ const Model = Ember.Object.extend(Ember.Evented, { comments: DS.hasMany({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, @@ -917,19 +917,19 @@ const Model = Ember.Object.extend(Ember.Evented, { } } }); - var commentsRef = blog.hasMany('comments'); + let commentsRef = blog.hasMany('comments'); // check if the comments are loaded already - var isLoaded = commentsRef.value() !== null; + let isLoaded = commentsRef.value() !== null; // get the records of the reference (null if not yet available) - var comments = commentsRef.value(); + let comments = commentsRef.value(); // get the identifier of the reference if (commentsRef.remoteType() === "ids") { - var ids = commentsRef.ids(); + let ids = commentsRef.ids(); } else if (commentsRef.remoteType() === "link") { - var link = commentsRef.link(); + let link = commentsRef.link(); } // load comments (via store.findMany or store.findHasMany) @@ -1056,7 +1056,7 @@ const Model = Ember.Object.extend(Ember.Evented, { // If it is, get the metadata for the relationship. This is // populated by the `DS.belongsTo` helper when it is creating // the computed property. - var meta = value.meta(); + let meta = value.meta(); meta.parentType = proto.constructor; } @@ -1096,11 +1096,11 @@ const Model = Ember.Object.extend(Ember.Evented, { export default DS.JSONSerializer.extend({ serialize: function(record, options) { - var json = {}; + let json = {}; record.eachRelationship(function(name, descriptor) { if (descriptor.kind === 'hasMany') { - var serializedHasManyName = name.toUpperCase() + '_IDS'; + let serializedHasManyName = name.toUpperCase() + '_IDS'; json[serializedHasManyName] = record.get(name).mapBy('id'); } }); @@ -1194,7 +1194,7 @@ Model.reopenClass({ keys to underscore (instead of dasherized), you might use the following code: ```javascript - export default var PostSerializer = DS.RESTSerializer.extend({ + export default const PostSerializer = DS.RESTSerializer.extend({ payloadKeyFromModelName: function(modelName) { return Ember.String.underscore(modelName); } @@ -1246,7 +1246,7 @@ Model.reopenClass({ @return {DS.Model} the type of the relationship, or undefined */ typeForRelationship(name, store) { - var relationship = get(this, 'relationshipsByName').get(name); + let relationship = get(this, 'relationshipsByName').get(name); return relationship && store.modelFor(relationship.type); }, @@ -1285,11 +1285,11 @@ Model.reopenClass({ @return {Object} the inverse relationship, or null */ inverseFor(name, store) { - var inverseMap = get(this, 'inverseMap'); + let inverseMap = get(this, 'inverseMap'); if (inverseMap[name]) { return inverseMap[name]; } else { - var inverse = this._findInverseFor(name, store); + let inverse = this._findInverseFor(name, store); inverseMap[name] = inverse; return inverse; } @@ -1298,17 +1298,17 @@ Model.reopenClass({ //Calculate the inverse, ignoring the cache _findInverseFor(name, store) { - var inverseType = this.typeForRelationship(name, store); + let inverseType = this.typeForRelationship(name, store); if (!inverseType) { return null; } - var propertyMeta = this.metaForProperty(name); + let propertyMeta = this.metaForProperty(name); //If inverse is manually specified to be null, like `comments: DS.hasMany('message', { inverse: null })` - var options = propertyMeta.options; + let options = propertyMeta.options; if (options.inverse === null) { return null; } - var inverseName, inverseKind, inverse; + let inverseName, inverseKind, inverse; //If inverse is specified manually, return the inverse if (options.inverse) { @@ -1327,12 +1327,12 @@ Model.reopenClass({ }); } - var possibleRelationships = findPossibleInverses(this, inverseType); + let possibleRelationships = findPossibleInverses(this, inverseType); if (possibleRelationships.length === 0) { return null; } - var filteredRelationships = possibleRelationships.filter((possibleRelationship) => { - var optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options; + let filteredRelationships = possibleRelationships.filter((possibleRelationship) => { + let optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options; return name === optionsForRelationship.inverse; }); @@ -1353,15 +1353,15 @@ Model.reopenClass({ } function findPossibleInverses(type, inverseType, relationshipsSoFar) { - var possibleRelationships = relationshipsSoFar || []; + let possibleRelationships = relationshipsSoFar || []; - var relationshipMap = get(inverseType, 'relationships'); + let relationshipMap = get(inverseType, 'relationships'); if (!relationshipMap) { return possibleRelationships; } - var relationships = relationshipMap.get(type.modelName); + let relationships = relationshipMap.get(type.modelName); relationships = relationships.filter((relationship) => { - var optionsForRelationship = inverseType.metaForProperty(relationship.name).options; + let optionsForRelationship = inverseType.metaForProperty(relationship.name).options; if (!optionsForRelationship.inverse) { return true; @@ -1416,7 +1416,7 @@ Model.reopenClass({ import User from 'app/models/user'; import Post from 'app/models/post'; - var relationships = Ember.get(Blog, 'relationships'); + let relationships = Ember.get(Blog, 'relationships'); relationships.get(User); //=> [ { name: 'users', kind: 'hasMany' }, // { name: 'owner', kind: 'belongsTo' } ] @@ -1454,7 +1454,7 @@ Model.reopenClass({ import Ember from 'ember'; import Blog from 'app/models/blog'; - var relationshipNames = Ember.get(Blog, 'relationshipNames'); + let relationshipNames = Ember.get(Blog, 'relationshipNames'); relationshipNames.hasMany; //=> ['users', 'posts'] relationshipNames.belongsTo; @@ -1467,7 +1467,7 @@ Model.reopenClass({ @readOnly */ relationshipNames: Ember.computed(function() { - var names = { + let names = { hasMany: [], belongsTo: [] }; @@ -1505,7 +1505,7 @@ Model.reopenClass({ import Ember from 'ember'; import Blog from 'app/models/blog'; - var relatedTypes = Ember.get(Blog, 'relatedTypes'); + let relatedTypes = Ember.get(Blog, 'relatedTypes'); //=> [ User, Post ] ``` @@ -1540,7 +1540,7 @@ Model.reopenClass({ import Ember from 'ember'; import Blog from 'app/models/blog'; - var relationshipsByName = Ember.get(Blog, 'relationshipsByName'); + let relationshipsByName = Ember.get(Blog, 'relationshipsByName'); relationshipsByName.get('users'); //=> { key: 'users', kind: 'hasMany', type: 'user', options: Object, isRelationship: true } relationshipsByName.get('owner'); @@ -1578,7 +1578,7 @@ Model.reopenClass({ import Ember from 'ember'; import Blog from 'app/models/blog'; - var fields = Ember.get(Blog, 'fields'); + let fields = Ember.get(Blog, 'fields'); fields.forEach(function(kind, field) { console.log(field, kind); }); @@ -1596,7 +1596,7 @@ Model.reopenClass({ @readOnly */ fields: Ember.computed(function() { - var map = Map.create(); + let map = Map.create(); this.eachComputedProperty((name, meta) => { if (meta.isRelationship) { @@ -1687,7 +1687,7 @@ Model.reopenClass({ import Ember from 'ember'; import Person from 'app/models/person'; - var attributes = Ember.get(Person, 'attributes') + let attributes = Ember.get(Person, 'attributes') attributes.forEach(function(meta, name) { console.log(name, meta); @@ -1705,7 +1705,7 @@ Model.reopenClass({ @readOnly */ attributes: Ember.computed(function() { - var map = Map.create(); + let map = Map.create(); this.eachComputedProperty((name, meta) => { if (meta.isAttribute) { @@ -1741,7 +1741,7 @@ Model.reopenClass({ import Ember from 'ember'; import Person from 'app/models/person'; - var transformedAttributes = Ember.get(Person, 'transformedAttributes') + let transformedAttributes = Ember.get(Person, 'transformedAttributes') transformedAttributes.forEach(function(field, type) { console.log(field, type); @@ -1758,7 +1758,7 @@ Model.reopenClass({ @readOnly */ transformedAttributes: Ember.computed(function() { - var map = Map.create(); + let map = Map.create(); this.eachAttribute((key, meta) => { if (meta.type) { @@ -1791,7 +1791,7 @@ Model.reopenClass({ ```javascript import DS from 'ember-data'; - var Person = DS.Model.extend({ + let Person = DS.Model.extend({ firstName: attr('string'), lastName: attr('string'), birthday: attr('date') @@ -1842,7 +1842,7 @@ Model.reopenClass({ ```javascript import DS from 'ember-data'; - var Person = DS.Model.extend({ + let Person = DS.Model.extend({ firstName: attr(), lastName: attr('string'), birthday: attr('date') From 388c475c776860b15be05dc49ad8a883bc834bce Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Thu, 8 Dec 2016 09:35:35 -0500 Subject: [PATCH 1746/2527] Enable the ds-check-should-serialize-relationships feature flag --- config/features.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/features.json b/config/features.json index d0546934b2a..225339b62d7 100644 --- a/config/features.json +++ b/config/features.json @@ -4,7 +4,7 @@ "ds-extended-errors": null, "ds-overhaul-references": null, "ds-payload-type-hooks": null, - "ds-check-should-serialize-relationships": null, + "ds-check-should-serialize-relationships": true, "ds-rollback-attribute": null, "ds-serialize-id": null, "ds-deprecate-store-serialize": true From c2b5fb91befb1fd4168e9b0e6e173299e0af406e Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 5 Dec 2016 22:36:11 -0800 Subject: [PATCH 1747/2527] move run.join usage up to store.push --- addon/-private/system/store.js | 47 ++++++++++++++++------------------ 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 4fe0a558cb1..aa731720de0 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2275,37 +2275,36 @@ Store = Service.extend({ */ _push(data) { let token = heimdall.start('store._push'); - let included = data.included; - let i, length; + let internalModelOrModels = this._backburner.join(() => { + let included = data.included; + let i, length; - if (included) { - for (i = 0, length = included.length; i < length; i++) { - this._pushInternalModel(included[i]); + if (included) { + for (i = 0, length = included.length; i < length; i++) { + this._pushInternalModel(included[i]); + } } - } - if (Array.isArray(data.data)) { - length = data.data.length; - let internalModels = new Array(length); + if (Array.isArray(data.data)) { + length = data.data.length; + let internalModels = new Array(length); - for (i = 0; i < length; i++) { - internalModels[i] = this._pushInternalModel(data.data[i]); + for (i = 0; i < length; i++) { + internalModels[i] = this._pushInternalModel(data.data[i]); + } + return internalModels; } - heimdall.stop(token); - return internalModels; - } - - if (data.data === null) { - heimdall.stop(token); - return null; - } - assert(`Expected an object in the 'data' property in a call to 'push' for ${data.type}, but was ${typeOf(data.data)}`, typeOf(data.data) === 'object'); + if (data.data === null) { + return null; + } - let internalModel = this._pushInternalModel(data.data); + assert(`Expected an object in the 'data' property in a call to 'push' for ${data.type}, but was ${typeOf(data.data)}`, typeOf(data.data) === 'object'); + return this._pushInternalModel(data.data); + }); heimdall.stop(token); - return internalModel; + return internalModelOrModels; }, _hasModelFor(modelName) { @@ -2344,9 +2343,7 @@ Store = Service.extend({ // Actually load the record into the store. let internalModel = this._load(data); - this._backburner.join(() => { - this._backburner.schedule('normalizeRelationships', this, this._setupRelationships, internalModel, data); - }); + this._backburner.schedule('normalizeRelationships', this, this._setupRelationships, internalModel, data); return internalModel; }, From 063b3e500e31a711d81253a893f8668558e86808 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 29 Nov 2016 22:11:06 -0800 Subject: [PATCH 1748/2527] [PERF] use micro-queue --- .../system/relationships/state/create.js | 1 + addon/-private/system/store.js | 101 ++++++++++++------ addon/-private/system/store/common.js | 9 +- addon/-private/system/store/finders.js | 19 ++-- 4 files changed, 83 insertions(+), 47 deletions(-) diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index 6b6c1c67c31..313fc937f54 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -13,6 +13,7 @@ function shouldFindInverse(relationshipMeta) { function createRelationshipFor(internalModel, relationshipMeta, store) { let inverseKey; let inverse = null; + if (shouldFindInverse(relationshipMeta)) { inverse = internalModel.type.inverseFor(relationshipMeta.key, store); } diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index aa731720de0..0154276475e 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -217,11 +217,24 @@ Store = Service.extend({ this.recordArrayManager = RecordArrayManager.create({ store: this }); - this._pendingSave = []; - this._instanceCache = new ContainerInstanceCache(getOwner(this), this); - //Used to keep track of all the find requests that need to be coalesced + /* + Ember Data uses several specialized micro-queues for organizing + and coalescing similar async work. + + These queues are currently controlled by a flush scheduled into + ember-data's custom backburner instance. + */ + // used for coalescing record save requests + this._pendingSave = []; + // used for coalescing relationship setup needs + this._pushedInternalModels = []; + // stores a reference to the flush for relationship setup + this._relationshipFlush = null; + // used to keep track of all the find requests that need to be coalesced this._pendingFetch = MapWithDefault.create({ defaultValue() { return []; } }); + + this._instanceCache = new ContainerInstanceCache(getOwner(this), this); }, /** @@ -1850,25 +1863,27 @@ Store = Service.extend({ let pending = this._pendingSave.slice(); this._pendingSave = []; - pending.forEach((pendingItem) => { + for (let i = 0, j = pending.length; i < j; i++) { + let pendingItem = pending[i]; let snapshot = pendingItem.snapshot; let resolver = pendingItem.resolver; - let record = snapshot._internalModel; - let adapter = this.adapterFor(record.modelClass.modelName); + let internalModel = snapshot._internalModel; + let adapter = this.adapterFor(internalModel.modelClass.modelName); let operation; - if (get(record, 'currentState.stateName') === 'root.deleted.saved') { + if (get(internalModel, 'currentState.stateName') === 'root.deleted.saved') { return resolver.resolve(); - } else if (record.isNew()) { + } else if (internalModel.isNew()) { operation = 'createRecord'; - } else if (record.isDeleted()) { + } else if (internalModel.isDeleted()) { operation = 'deleteRecord'; } else { operation = 'updateRecord'; } resolver.resolve(_commit(adapter, this, operation, snapshot)); - }); + } + }, /** @@ -1891,8 +1906,8 @@ Store = Service.extend({ } if (data) { // normalize relationship IDs into records - this._backburner.schedule('normalizeRelationships', this, this._setupRelationships, internalModel, data); this.updateId(internalModel, data); + this._setupRelationshipsForModel(internalModel, data); } else { assert(`Your ${internalModel.type.modelName} record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, internalModel.id); } @@ -2007,6 +2022,7 @@ Store = Service.extend({ heimdall.increment(_load); let internalModel = this._internalModelForId(data.type, data.id); + // TODO @runspired move this out of here internalModel.setupData(data); this.recordArrayManager.recordDidChange(internalModel); @@ -2266,17 +2282,18 @@ Store = Service.extend({ }, /* - Push some data into the store, without creating materialized records. + Push some data in the form of a json-api document into the store, + without creating materialized records. @method _push @private - @param {Object} data + @param {Object} jsonApiDoc @return {DS.InternalModel|Array} pushed InternalModel(s) */ - _push(data) { + _push(jsonApiDoc) { let token = heimdall.start('store._push'); let internalModelOrModels = this._backburner.join(() => { - let included = data.included; + let included = jsonApiDoc.included; let i, length; if (included) { @@ -2285,23 +2302,23 @@ Store = Service.extend({ } } - if (Array.isArray(data.data)) { - length = data.data.length; + if (Array.isArray(jsonApiDoc.data)) { + length = jsonApiDoc.data.length; let internalModels = new Array(length); for (i = 0; i < length; i++) { - internalModels[i] = this._pushInternalModel(data.data[i]); + internalModels[i] = this._pushInternalModel(jsonApiDoc.data[i]); } return internalModels; } - if (data.data === null) { + if (jsonApiDoc.data === null) { return null; } - assert(`Expected an object in the 'data' property in a call to 'push' for ${data.type}, but was ${typeOf(data.data)}`, typeOf(data.data) === 'object'); + assert(`Expected an object in the 'data' property in a call to 'push' for ${jsonApiDoc.type}, but was ${typeOf(jsonApiDoc.data)}`, typeOf(jsonApiDoc.data) === 'object'); - return this._pushInternalModel(data.data); + return this._pushInternalModel(jsonApiDoc.data); }); heimdall.stop(token); return internalModelOrModels; @@ -2343,17 +2360,32 @@ Store = Service.extend({ // Actually load the record into the store. let internalModel = this._load(data); - this._backburner.schedule('normalizeRelationships', this, this._setupRelationships, internalModel, data); + this._setupRelationshipsForModel(internalModel, data); return internalModel; }, - _setupRelationships(record, data) { + _setupRelationshipsForModel(internalModel, data) { + this._pushedInternalModels.push(internalModel, data); + if (this._relationshipFlush === null) { + this._relationshipFlush = this._backburner.schedule('normalizeRelationships', this, this._setupRelationships); + } + }, + + _setupRelationships() { heimdall.increment(_setupRelationships); - // This will convert relationships specified as IDs into DS.Model instances - // (possibly unloaded) and also create the data structures used to track - // relationships. - setupRelationships(this, record, data); + let pushed = this._pushedInternalModels; + this._pushedInternalModels = []; + this._relationshipFlush = null; + + for (let i = 0, l = pushed.length; i < l; i += 2) { + // This will convert relationships specified as IDs into DS.Model instances + // (possibly unloaded) and also create the data structures used to track + // relationships. + let internalModel = pushed[i]; + let data = pushed[i + 1]; + setupRelationships(this, internalModel, data); + } }, /** @@ -2612,6 +2644,9 @@ Store = Service.extend({ willDestroy() { this._super(...arguments); + this._pushedInternalModels = null; + this._backburner.cancel(this._relationshipFlush); + this._relationshipFlush = null; this.recordArrayManager.destroy(); this._instanceCache.destroy(); @@ -2623,7 +2658,7 @@ Store = Service.extend({ return; } - assert(`A ${relationship.parentType} record was pushed into the store with the value of ${relationship.key} being ${inspect(resourceIdentifier)}, but ${relationship.key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(resourceIdentifier)); + assert(`A ${relationship.record.modelName} record was pushed into the store with the value of ${relationship.key} being ${inspect(resourceIdentifier)}, but ${relationship.key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(resourceIdentifier)); //TODO:Better asserts return this._internalModelForId(resourceIdentifier.type, resourceIdentifier.id); @@ -2634,7 +2669,7 @@ Store = Service.extend({ return; } - assert(`A ${relationship.parentType} record was pushed into the store with the value of ${relationship.key} being '${inspect(resourceIdentifiers)}', but ${relationship.key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(resourceIdentifiers)); + assert(`A ${relationship.record.modelName} record was pushed into the store with the value of ${relationship.key} being '${inspect(resourceIdentifiers)}', but ${relationship.key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(resourceIdentifiers)); let _internalModels = new Array(resourceIdentifiers.length); for (let i = 0; i < resourceIdentifiers.length; i++) { @@ -2674,7 +2709,7 @@ function _commit(adapter, store, operation, snapshot) { if (adapterPayload) { payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, snapshot.id, operation); if (payload.included) { - store.push({ data: payload.included }); + store._push({ data: null, included: payload.included }); } data = payload.data; } @@ -2695,17 +2730,17 @@ function _commit(adapter, store, operation, snapshot) { }, label); } -function setupRelationships(store, record, data) { +function setupRelationships(store, internalModel, data) { if (!data.relationships) { return; } - record.type.eachRelationship((key, descriptor) => { + internalModel.type.eachRelationship((key, descriptor) => { if (!data.relationships[key]) { return; } - let relationship = record._relationships.get(key); + let relationship = internalModel._relationships.get(key); relationship.push(data.relationships[key]); }); } diff --git a/addon/-private/system/store/common.js b/addon/-private/system/store/common.js index 92d61d24e32..8ce2777e417 100644 --- a/addon/-private/system/store/common.js +++ b/addon/-private/system/store/common.js @@ -1,6 +1,8 @@ import Ember from 'ember'; -var get = Ember.get; +const { + get +} = Ember; const { __bind, @@ -12,9 +14,8 @@ const { '_objectIsAlive' ); -export function _bind(fn) { +export function _bind(fn, ...args) { heimdall.increment(__bind); - var args = Array.prototype.slice.call(arguments, 1); return function() { return fn.apply(undefined, args); @@ -23,7 +24,7 @@ export function _bind(fn) { export function _guard(promise, test) { heimdall.increment(__guard); - var guarded = promise['finally'](function() { + let guarded = promise['finally'](function() { if (!test()) { guarded._subscribers.length = 0; } diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index a0c9a9e20ab..38cbc90ef8d 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -43,8 +43,7 @@ export function _find(adapter, store, typeClass, id, internalModel, options) { id: 'ds.store.findRecord.id-mismatch' }); - var internalModel = store._push(payload); - return internalModel; + return store._push(payload); }); }, function(error) { internalModel.notFound(); @@ -180,19 +179,19 @@ export function _query(adapter, store, typeClass, query, recordArray) { }, null, 'DS: Extract payload of query ' + typeClass); } -export function _queryRecord(adapter, store, typeClass, query) { - var modelName = typeClass.modelName; - var promise = adapter.queryRecord(store, typeClass, query); - var serializer = serializerForAdapter(store, adapter, modelName); - var label = "DS: Handle Adapter#queryRecord of " + typeClass; +export function _queryRecord(adapter, store, modelClass, query) { + let modelName = modelClass.modelName; + let promise = adapter.queryRecord(store, modelClass, query); + let serializer = serializerForAdapter(store, adapter, modelName); + let label = `DS: Handle Adapter#queryRecord of ${modelName}`; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - var internalModel; + let internalModel; store._adapterRun(function() { - var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'queryRecord'); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'queryRecord'); assert("Expected the primary data returned by the serializer for a `queryRecord` response to be a single object or null but instead it was an array.", !Array.isArray(payload.data), { id: 'ds.store.queryRecord-array-response' @@ -203,5 +202,5 @@ export function _queryRecord(adapter, store, typeClass, query) { return internalModel; - }, null, "DS: Extract payload of queryRecord " + typeClass); + }, null, "DS: Extract payload of queryRecord " + modelClass); } From 0f112a68cf3051be05137b883d55031679058cad Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 9 Dec 2016 03:10:31 -0800 Subject: [PATCH 1749/2527] store.reloadRecord => store._reloadRecord --- addon/-private/system/model/states.js | 4 ++-- addon/-private/system/store.js | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index d4e88df0bc3..aebb9851384 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -262,7 +262,7 @@ const DirtyState = { }, reloadRecord(internalModel, resolve) { - resolve(internalModel.store.reloadRecord(internalModel)); + resolve(internalModel.store._reloadRecord(internalModel)); }, rolledBack(internalModel) { @@ -565,7 +565,7 @@ const RootState = { }, reloadRecord(internalModel, resolve) { - resolve(internalModel.store.reloadRecord(internalModel)); + resolve(internalModel.store._reloadRecord(internalModel)); }, deleteRecord(internalModel) { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index aa731720de0..27f4f1a8556 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1021,8 +1021,7 @@ Store = Service.extend({ @param {DS.Model} internalModel @return {Promise} promise */ - // TODO @runspired this should be underscored - reloadRecord(internalModel) { + _reloadRecord(internalModel) { let modelName = internalModel.type.modelName; let adapter = this.adapterFor(modelName); let id = internalModel.id; From 661e8ffe57187ff45f75fa100ee42b8a5cf9a55b Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 9 Dec 2016 03:17:36 -0800 Subject: [PATCH 1750/2527] use _push instead of mapping over push result to get internal models --- addon/-private/system/store/finders.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index a0c9a9e20ab..46e2eae3aac 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -94,10 +94,9 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) return promise.then(function(adapterPayload) { assert("You made a `findHasMany` request for a " + internalModel.modelName + "'s `" + relationship.key + "` relationship, using link " + link + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { - var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findHasMany'); - //TODO Use a non record creating push - var records = store.push(payload); - var recordArray = records.map((record) => record._internalModel); + let payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findHasMany'); + let recordArray = store._push(payload); + recordArray.meta = payload.meta; return recordArray; }); From a5a8cd7714555655ae9fb7209b5b87c11aabd1cc Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 17 Nov 2016 14:15:10 -0800 Subject: [PATCH 1751/2527] refactor typeMap => recordMap and refactor to using modelName instead of guid as the class identifier for recordMap --- addon/-private/system/identity-map.js | 49 +++ addon/-private/system/model/internal-model.js | 15 +- addon/-private/system/record-array-manager.js | 142 +++++---- .../adapter-populated-record-array.js | 8 +- .../record-arrays/filtered-record-array.js | 5 +- .../system/record-arrays/record-array.js | 40 +-- addon/-private/system/record-map.js | 134 ++++++++ addon/-private/system/store.js | 301 ++++++++---------- addon/-private/system/store/finders.js | 14 +- .../integration/adapter/rest-adapter-test.js | 4 +- .../integration/client-id-generation-test.js | 3 +- .../integration/record-array-manager-test.js | 12 +- .../adapter-populated-record-array-test.js | 10 +- .../records/collection-save-test.js | 23 +- .../adapter-populated-record-array-test.js | 14 +- .../filtered-record-array-test.js | 20 +- tests/unit/record-arrays/record-array-test.js | 18 +- tests/unit/store/adapter-interop-test.js | 2 +- tests/unit/store/push-test.js | 17 + 19 files changed, 515 insertions(+), 316 deletions(-) create mode 100644 addon/-private/system/identity-map.js create mode 100644 addon/-private/system/record-map.js diff --git a/addon/-private/system/identity-map.js b/addon/-private/system/identity-map.js new file mode 100644 index 00000000000..a54cfd2e2a5 --- /dev/null +++ b/addon/-private/system/identity-map.js @@ -0,0 +1,49 @@ +import RecordMap from './record-map'; + +/** + `IdentityMap` is a custom storage map for records by modelName + used by `DS.Store`. + + @class IdentityMap + @private + */ +export default class IdentityMap { + constructor() { + this._map = Object.create(null); + } + + /** + Retrieves the `RecordMap` for a given modelName, + creating one if one did not already exist. This is + similar to `getWithDefault` or `get` on a `MapWithDefault` + + @method retrieve + @param modelName a previously normalized modelName + @returns {RecordMap} the RecordMap for the given modelName + */ + retrieve(modelName) { + let recordMap = this._map[modelName]; + + if (!recordMap) { + recordMap = this._map[modelName] = new RecordMap(modelName); + } + + return recordMap; + } + + /** + Clears the contents of all known `RecordMaps`, but does + not remove the RecordMap instances. + + @method clear + */ + clear() { + let recordMaps = this._map; + let keys = Object.keys(recordMaps); + + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + recordMaps[key].clear(); + } + } +} diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 5f0dde7df16..8663c3db247 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -87,6 +87,8 @@ const { 'updateChangedAttributes' ); +let InternalModelReferenceId = 1; + /* `InternalModel` is the Model class that we use internally inside Ember Data to represent models. Internal ED methods should only deal with `InternalModel` objects. It is a fast, plain Javascript class. @@ -104,13 +106,13 @@ const { @class InternalModel */ export default class InternalModel { - constructor(modelClass, id, store, data) { + constructor(modelName, id, store, data) { heimdall.increment(new_InternalModel); - this.modelClass = modelClass; this.id = id; + this._internalId = InternalModelReferenceId++; this.store = store; this._data = data || new EmptyObject(); - this.modelName = modelClass.modelName; + this.modelName = modelName; this.dataHasInitialized = false; this._loadingPromise = null; this._recordArrays = undefined; @@ -122,6 +124,7 @@ export default class InternalModel { this.error = null; // caches for lazy getters + this._modelClass = null; this.__deferredTriggers = null; this._references = null; this._recordReference = null; @@ -131,6 +134,10 @@ export default class InternalModel { this.__implicitRelationships = null; } + get modelClass() { + return this._modelClass || (this._modelClass = this.store.modelFor(this.modelName)); + } + get type() { return this.modelClass; } @@ -778,7 +785,7 @@ export default class InternalModel { */ updateRecordArrays() { this._updatingRecordArraysLater = false; - this.store.dataWasUpdated(this.modelClass, this); + this.store._dataWasUpdated(this); } setId(id) { diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index a1196df38a0..15259223d41 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -9,6 +9,7 @@ import { AdapterPopulatedRecordArray } from "ember-data/-private/system/record-arrays"; import OrderedSet from "ember-data/-private/system/ordered-set"; +import { assert } from 'ember-data/-private/debug'; const { get, @@ -72,7 +73,10 @@ export default Ember.Object.extend({ }); this.liveRecordArrays = MapWithDefault.create({ - defaultValue: modelClass => this.createRecordArray(modelClass) + defaultValue: modelName => { + assert(`liveRecordArrays.get expects modelName not modelClass as the param`, typeof modelName === 'string'); + return this.createRecordArray(modelName); + } }); this.changedRecords = []; @@ -86,10 +90,10 @@ export default Ember.Object.extend({ emberRun.schedule('actions', this, this.updateRecordArrays); }, - recordArraysForRecord(record) { + recordArraysForRecord(internalModel) { heimdall.increment(recordArraysForRecord); - record._recordArrays = record._recordArrays || OrderedSet.create(); - return record._recordArrays; + internalModel._recordArrays = internalModel._recordArrays || OrderedSet.create(); + return internalModel._recordArrays; }, /** @@ -117,43 +121,43 @@ export default Ember.Object.extend({ this.changedRecords.length = 0; }, - _recordWasDeleted(record) { + _recordWasDeleted(internalModel) { heimdall.increment(_recordWasDeleted); - let recordArrays = record._recordArrays; + let recordArrays = internalModel._recordArrays; if (!recordArrays) { return; } - recordArrays.forEach(array => array._removeInternalModels([record])); + recordArrays.forEach(array => array._removeInternalModels([internalModel])); - record._recordArrays = null; + internalModel._recordArrays = null; }, - _recordWasChanged(record) { + _recordWasChanged(internalModel) { heimdall.increment(_recordWasChanged); - let typeClass = record.type; - let recordArrays = this.filteredRecordArrays.get(typeClass); + let modelName = internalModel.modelName; + let recordArrays = this.filteredRecordArrays.get(modelName); let filter; recordArrays.forEach(array => { filter = get(array, 'filterFunction'); - this.updateFilterRecordArray(array, filter, typeClass, record); + this.updateFilterRecordArray(array, filter, modelName, internalModel); }); }, //Need to update live arrays on loading - recordWasLoaded(record) { + recordWasLoaded(internalModel) { heimdall.increment(recordWasLoaded); - let typeClass = record.type; - let recordArrays = this.filteredRecordArrays.get(typeClass); + let modelName = internalModel.modelName; + let recordArrays = this.filteredRecordArrays.get(modelName); let filter; recordArrays.forEach(array => { filter = get(array, 'filterFunction'); - this.updateFilterRecordArray(array, filter, typeClass, record); + this.updateFilterRecordArray(array, filter, modelName, internalModel); }); - if (this.liveRecordArrays.has(typeClass)) { - let liveRecordArray = this.liveRecordArrays.get(typeClass); - this._addInternalModelToRecordArray(liveRecordArray, record); + if (this.liveRecordArrays.has(modelName)) { + let liveRecordArray = this.liveRecordArrays.get(modelName); + this._addInternalModelToRecordArray(liveRecordArray, internalModel); } }, @@ -163,10 +167,10 @@ export default Ember.Object.extend({ @method updateFilterRecordArray @param {DS.FilteredRecordArray} array @param {Function} filter - @param {DS.Model} modelClass + @param {String} modelName @param {InternalModel} internalModel */ - updateFilterRecordArray(array, filter, modelClass, internalModel) { + updateFilterRecordArray(array, filter, modelName, internalModel) { heimdall.increment(updateFilterRecordArray); let shouldBeInArray = filter(internalModel.getRecord()); let recordArrays = this.recordArraysForRecord(internalModel); @@ -187,10 +191,11 @@ export default Ember.Object.extend({ } }, - syncLiveRecordArray(array, modelClass) { + syncLiveRecordArray(array, modelName) { + assert(`recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); let hasNoPotentialDeletions = this.changedRecords.length === 0; - let typeMap = this.store.typeMapFor(modelClass); - let hasNoInsertionsOrRemovals = typeMap.records.length === array.length; + let recordMap = this.store._recordMapFor(modelName); + let hasNoInsertionsOrRemovals = recordMap.length === array.length; /* Ideally the recordArrayManager has knowledge of the changes to be applied to @@ -202,13 +207,14 @@ export default Ember.Object.extend({ return; } - this.populateLiveRecordArray(array, modelClass); + this.populateLiveRecordArray(array, modelName); }, - populateLiveRecordArray(array, modelClass) { + populateLiveRecordArray(array, modelName) { + assert(`recordArrayManger.populateLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); heimdall.increment(populateLiveRecordArray); - let typeMap = this.store.typeMapFor(modelClass); - let records = typeMap.records; + let recordMap = this.store._recordMapFor(modelName); + let records = recordMap.records; let record; for (let i = 0; i < records.length; i++) { @@ -229,48 +235,52 @@ export default Ember.Object.extend({ @method updateFilter @param {Array} array - @param {Class} modelClass + @param {String} modelName @param {Function} filter */ - updateFilter(array, modelClass, filter) { + updateFilter(array, modelName, filter) { + assert(`recordArrayManger.updateFilter expects modelName not modelClass as the second param, received ${modelName}`, typeof modelName === 'string'); heimdall.increment(updateFilter); - let typeMap = this.store.typeMapFor(modelClass); - let records = typeMap.records; + let recordMap = this.store._recordMapFor(modelName); + let records = recordMap.records; let record; for (let i = 0; i < records.length; i++) { record = records[i]; if (!record.isDeleted() && !record.isEmpty()) { - this.updateFilterRecordArray(array, filter, modelClass, record); + this.updateFilterRecordArray(array, filter, modelName, record); } } }, /** - Get the `DS.RecordArray` for a type, which contains all loaded records of - given type. + Get the `DS.RecordArray` for a modelName, which contains all loaded records of + given modelName. @method liveRecordArrayFor - @param {Class} typeClass + @param {String} modelName @return {DS.RecordArray} */ - liveRecordArrayFor(typeClass) { + liveRecordArrayFor(modelName) { + assert(`recordArrayManger.liveRecordArrayFor expects modelName not modelClass as the param`, typeof modelName === 'string'); + heimdall.increment(liveRecordArrayFor); - return this.liveRecordArrays.get(typeClass); + return this.liveRecordArrays.get(modelName); }, /** - Create a `DS.RecordArray` for a type. + Create a `DS.RecordArray` for a modelName. @method createRecordArray - @param {Class} modelClass + @param {String} modelName @return {DS.RecordArray} */ - createRecordArray(modelClass) { + createRecordArray(modelName) { + assert(`recordArrayManger.createRecordArray expects modelName not modelClass as the param`, typeof modelName === 'string'); heimdall.increment(createRecordArray); return RecordArray.create({ - type: modelClass, + modelName, content: Ember.A(), store: this.store, isLoaded: true, @@ -279,42 +289,46 @@ export default Ember.Object.extend({ }, /** - Create a `DS.FilteredRecordArray` for a type and register it for updates. + Create a `DS.FilteredRecordArray` for a modelName and register it for updates. @method createFilteredRecordArray - @param {DS.Model} typeClass + @param {String} modelName @param {Function} filter @param {Object} query (optional @return {DS.FilteredRecordArray} */ - createFilteredRecordArray(typeClass, filter, query) { + createFilteredRecordArray(modelName, filter, query) { + assert(`recordArrayManger.createFilteredRecordArray expects modelName not modelClass as the first param, received ${modelName}`, typeof modelName === 'string'); + heimdall.increment(createFilteredRecordArray); let array = FilteredRecordArray.create({ - query: query, - type: typeClass, + query, + modelName, content: Ember.A(), store: this.store, manager: this, filterFunction: filter }); - this.registerFilteredRecordArray(array, typeClass, filter); + this.registerFilteredRecordArray(array, modelName, filter); return array; }, /** - Create a `DS.AdapterPopulatedRecordArray` for a type with given query. + Create a `DS.AdapterPopulatedRecordArray` for a modelName with given query. @method createAdapterPopulatedRecordArray - @param {DS.Model} typeClass + @param {String} modelName @param {Object} query @return {DS.AdapterPopulatedRecordArray} */ - createAdapterPopulatedRecordArray(typeClass, query) { + createAdapterPopulatedRecordArray(modelName, query) { heimdall.increment(createAdapterPopulatedRecordArray); + assert(`recordArrayManger.createAdapterPopulatedRecordArray expects modelName not modelClass as the first param, received ${modelName}`, typeof modelName === 'string'); + let array = AdapterPopulatedRecordArray.create({ - type: typeClass, + modelName, query: query, content: Ember.A(), store: this.store, @@ -327,22 +341,24 @@ export default Ember.Object.extend({ }, /** - Register a RecordArray for a given type to be backed by + Register a RecordArray for a given modelName to be backed by a filter function. This will cause the array to update - automatically when records of that type change attribute + automatically when records of that modelName change attribute values or states. @method registerFilteredRecordArray @param {DS.RecordArray} array - @param {DS.Model} typeClass + @param {String} modelName @param {Function} filter */ - registerFilteredRecordArray(array, typeClass, filter) { + registerFilteredRecordArray(array, modelName, filter) { heimdall.increment(registerFilteredRecordArray); - let recordArrays = this.filteredRecordArrays.get(typeClass); + assert(`recordArrayManger.registerFilteredRecordArray expects modelName not modelClass as the second param, received ${modelName}`, typeof modelName === 'string'); + + let recordArrays = this.filteredRecordArrays.get(modelName); recordArrays.push(array); - this.updateFilter(array, typeClass, filter); + this.updateFilter(array, modelName, filter); }, /** @@ -355,10 +371,10 @@ export default Ember.Object.extend({ unregisterRecordArray(array) { heimdall.increment(unregisterRecordArray); - let typeClass = array.type; + let modelName = array.modelName; // unregister filtered record array - let recordArrays = this.filteredRecordArrays.get(typeClass); + let recordArrays = this.filteredRecordArrays.get(modelName); let removedFromFiltered = remove(recordArrays, array); // remove from adapter populated record array @@ -367,10 +383,10 @@ export default Ember.Object.extend({ if (!removedFromFiltered && !removedFromAdapterPopulated) { // unregister live record array - if (this.liveRecordArrays.has(typeClass)) { - let liveRecordArrayForType = this.liveRecordArrayFor(typeClass); + if (this.liveRecordArrays.has(modelName)) { + let liveRecordArrayForType = this.liveRecordArrayFor(modelName); if (array === liveRecordArrayForType) { - this.liveRecordArrays.delete(typeClass); + this.liveRecordArrays.delete(modelName); } } } diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index 6fa9f24044a..24653246f2c 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -56,16 +56,14 @@ export default RecordArray.extend({ }, replace() { - let type = get(this, 'type').toString(); - throw new Error(`The result of a server query (on ${type}) is immutable.`); + throw new Error(`The result of a server query (on ${this.modelName}) is immutable.`); }, _update() { let store = get(this, 'store'); - let modelName = get(this, 'type.modelName'); let query = get(this, 'query'); - return store._query(modelName, query, this); + return store._query(this.modelName, query, this); }, /** @@ -89,7 +87,7 @@ export default RecordArray.extend({ links: cloneNull(payload.links) }); - internalModels.forEach(record => this.manager.recordArraysForRecord(record).add(this)); + internalModels.forEach(internalModel => this.manager.recordArraysForRecord(internalModel).add(this)); // TODO: should triggering didLoad event be the last action of the runLoop? Ember.run.once(this, 'trigger', 'didLoad'); diff --git a/addon/-private/system/record-arrays/filtered-record-array.js b/addon/-private/system/record-arrays/filtered-record-array.js index ccec9bba3bc..ffc84e5d3ef 100644 --- a/addon/-private/system/record-arrays/filtered-record-array.js +++ b/addon/-private/system/record-arrays/filtered-record-array.js @@ -52,8 +52,7 @@ export default RecordArray.extend({ */ replace() { - let type = get(this, 'type').toString(); - throw new Error(`The result of a client-side filter (on ${type}) is immutable.`); + throw new Error(`The result of a client-side filter (on ${this.modelName}) is immutable.`); }, /** @@ -64,7 +63,7 @@ export default RecordArray.extend({ if (get(this, 'isDestroying') || get(this, 'isDestroyed')) { return; } - get(this, 'manager').updateFilter(this, get(this, 'type'), get(this, 'filterFunction')); + get(this, 'manager').updateFilter(this, this.modelName, get(this, 'filterFunction')); }, updateFilter: Ember.observer('filterFunction', function() { diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index cd05a98023b..4e19330eda4 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -5,11 +5,10 @@ import Ember from 'ember'; import { PromiseArray } from "ember-data/-private/system/promise-proxies"; import SnapshotRecordArray from "ember-data/-private/system/snapshot-record-array"; - -const { get, set, RSVP: { Promise } } = Ember; +const { computed, get, set, RSVP: { Promise } } = Ember; /** - A record array is an array that contains records of a certain type. The record + A record array is an array that contains records of a certain modelName. The record array materializes records as needed when they are retrieved for the first time. You should not create record arrays yourself. Instead, an instance of `DS.RecordArray` or its subclasses will be returned by your application's store @@ -25,14 +24,6 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { init() { this._super(...arguments); - /** - The model type contained by this record array. - - @property type - @type DS.Model - */ - this.type = this.type || null; - /** The array of client ids backing the record array. When a record is requested from the record array, the record @@ -88,10 +79,22 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { }, replace() { - let type = get(this, 'type').toString(); - throw new Error(`The result of a server query (for all ${type} types) is immutable. To modify contents, use toArray()`); + throw new Error(`The result of a server query (for all ${this.modelName} types) is immutable. To modify contents, use toArray()`); }, + /** + The modelClass represented by this record array. + + @property type + @type DS.Model + */ + type: computed.readOnly('modelName', function() { + if (!this.modelName) { + return null; + } + return this.store.modelFor(this.modelName); + }), + /** Retrieves an object from the content by index. @@ -145,10 +148,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { is finished. */ _update() { - let store = get(this, 'store'); - let modelName = get(this, 'type.modelName'); - - return store.findAll(modelName, { reload: true }); + return this.store.findAll(this.modelName, { reload: true }); }, /** @@ -193,9 +193,9 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @return {DS.PromiseArray} promise */ save() { - let promiseLabel = 'DS: RecordArray#save ' + get(this, 'type'); - let promise = Promise.all(this.invoke('save'), promiseLabel). - then(() => this, null, 'DS: RecordArray#save return RecordArray'); + let promiseLabel = `DS: RecordArray#save ${this.modelName}`; + let promise = Promise.all(this.invoke('save'), promiseLabel) + .then(() => this, null, 'DS: RecordArray#save return RecordArray'); return PromiseArray.create({ promise }); }, diff --git a/addon/-private/system/record-map.js b/addon/-private/system/record-map.js new file mode 100644 index 00000000000..7633531f511 --- /dev/null +++ b/addon/-private/system/record-map.js @@ -0,0 +1,134 @@ +import { assert, deprecate } from "ember-data/-private/debug"; +import InternalModel from './model/internal-model'; + +/** + `RecordMap` is a custom storage map for records of a given modelName + used by `IdentityMap`. + + It was extracted from an implicit pojo based "record map" and preserves + that interface while we work towards a more official API. + + @class RecordMap + @private + */ +export default class RecordMap { + constructor(modelName) { + this.modelName = modelName; + this._idToRecord = Object.create(null); + this._records = []; + this._metadata = null; + } + + /** + A "map" of records based on their ID for this modelName + */ + get idToRecord() { + deprecate('Use of RecordMap.idToRecord is deprecated, use RecordMap.get(id) instead.', false, { + id: 'ds.record-map.idToRecord', + until: '2.13' + }); + return this._idToRecord; + } + + /** + * + * @param id + * @returns {InternalModel} + */ + get(id) { + let r = this._idToRecord[id]; + return r; + } + + has(id) { + return !!this._idToRecord[id]; + } + + get length() { + return this._records.length; + } + + set(id, internalModel) { + assert(`You cannot index an internalModel by an empty id'`, id); + assert(`You cannot set an index for an internalModel to something other than an internalModel`, internalModel instanceof InternalModel); + assert(`You cannot set an index for an internalModel that is not in the RecordMap`, this.contains(internalModel)); + assert(`You cannot update the id index of an InternalModel once set. Attempted to update ${id}.`, !this.has(id) || this.get(id) === internalModel); + + this._idToRecord[id] = internalModel; + } + + add(internalModel, id) { + assert(`You cannot re-add an already present InternalModel to the RecordMap.`, !this.contains(internalModel)); + + if (id) { + this._idToRecord[id] = internalModel; + } + + this._records.push(internalModel); + } + + remove(internalModel, id) { + if (id) { + delete this._idToRecord[id]; + } + + let loc = this._records.indexOf(internalModel); + + if (loc !== -1) { + this._records.splice(loc, 1); + } + } + + contains(internalModel) { + return this._records.indexOf(internalModel) !== -1; + } + + /** + An array of all records of this modelName + */ + get records() { + return this._records; + } + + /** + * meta information about records + */ + get metadata() { + return this._metadata || (this._metadata = Object.create(null)); + } + + /** + deprecated (and unsupported) way of accessing modelClass + + @deprecated + */ + get type() { + throw new Error('RecordMap.type is no longer available'); + } + + /** + Destroy all records in the recordMap and wipe metadata. + + @method clear + */ + clear() { + if (this._records) { + let records = this._records; + this._records = []; + let record; + + for (let i = 0; i < records.length; i++) { + record = records[i]; + record.unloadRecord(); + record.destroy(); // maybe within unloadRecord + } + } + + this._metadata = null; + } + + destroy() { + this._store = null; + this._modelClass = null; + } +} diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 809a365dba4..1356eb73a83 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -7,7 +7,7 @@ import Model from 'ember-data/model'; import { instrument, assert, deprecate, warn, runInDebug } from "ember-data/-private/debug"; import normalizeModelName from "ember-data/-private/system/normalize-model-name"; import { InvalidError } from 'ember-data/adapters/errors'; - +import IdentityMap from 'ember-data/-private/system/identity-map'; import { promiseArray, promiseObject @@ -50,7 +50,6 @@ const { ENV, Error: EmberError, get, - guidFor, inspect, isNone, isPresent, @@ -62,7 +61,6 @@ const { typeOf } = Ember; - const { Promise } = RSVP; //Get the materialized model from the internalModel/promise that returns @@ -108,8 +106,7 @@ const { peekAll, peekRecord, serializerFor, - typeMapFor, - typeMapFor_allocate + _recordMapFor } = heimdall.registerMonitor('store', '_generateId', '_internalModelForId', @@ -126,8 +123,7 @@ const { 'peekAll', 'peekRecord', 'serializerFor', - 'typeMapFor', - 'typeMapFor_allocate' + '_recordMapFor' ); /** @@ -213,10 +209,12 @@ Store = Service.extend({ this._super(...arguments); this._backburner = new Backburner(['normalizeRelationships', 'syncRelationships', 'finished']); // internal bookkeeping; not observable - this.typeMaps = {}; this.recordArrayManager = RecordArrayManager.create({ store: this }); + this._identityMap = new IdentityMap(); + this._pendingSave = []; + this._instanceCache = new ContainerInstanceCache(getOwner(this), this); /* Ember Data uses several specialized micro-queues for organizing @@ -342,7 +340,7 @@ Store = Service.extend({ createRecord(modelName, inputProperties) { assert("You need to pass a model name to the store's createRecord method", isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); - let modelClass = this.modelFor(modelName); + let trueModelName = this._classKeyFor(modelName); let properties = copy(inputProperties) || new EmptyObject(); // If the passed properties do not include a primary key, @@ -351,13 +349,13 @@ Store = Service.extend({ // to avoid conflicts. if (isNone(properties.id)) { - properties.id = this._generateId(modelName, properties); + properties.id = this._generateId(trueModelName, properties); } // Coerce ID to a string properties.id = coerceId(properties.id); - let internalModel = this.buildInternalModel(modelClass, properties.id); + let internalModel = this.buildInternalModel(trueModelName, properties.id); let record = internalModel.getRecord(); // Move the record out of its initial `empty` state into @@ -457,24 +455,16 @@ Store = Service.extend({ // The default `model` hook in Ember.Route calls `find(modelName, id)`, // that's why we have to keep this method around even though `findRecord` is // the public way to get a record by modelName and id. - - if (arguments.length === 1) { - assert('Using store.find(type) has been removed. Use store.findAll(type) to retrieve all records for a given type.'); - } - - if (typeOf(id) === 'object') { - assert('Calling store.find() with a query object is no longer supported. Use store.query() instead.'); - } - - if (options) { - assert('Calling store.find(type, id, { preload: preload }) is no longer supported. Use store.findRecord(type, id, { preload: preload }) instead.'); - } - - assert("You need to pass the model name and id to the store's find method", arguments.length === 2); + assert(`Using store.find(type) has been removed. Use store.findAll(modelName) to retrieve all records for a given type.`, arguments.length !== 1); + assert(`Calling store.find() with a query object is no longer supported. Use store.query() instead.`, typeOf(id) !== 'object'); + assert(`Calling store.find(modelName, id, { preload: preload }) is no longer supported. Use store.findRecord(modelName, id, { preload: preload }) instead.`, !options); + assert(`You need to pass the model name and id to the store's find method`, arguments.length === 2); assert("You cannot pass `" + inspect(id) + "` as id to the store's find method", typeOf(id) === 'string' || typeOf(id) === 'number'); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); - return this.findRecord(modelName, id); + let trueModelName = this._classKeyFor(modelName); + + return this.findRecord(trueModelName, id); }, /** @@ -682,16 +672,18 @@ Store = Service.extend({ assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); assert(badIdFormatAssertion, (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id))); - let internalModel = this._internalModelForId(modelName, id); + let trueModelName = this._classKeyFor(modelName); + + let internalModel = this._internalModelForId(trueModelName, id); options = options || {}; - if (!this.hasRecordForId(modelName, id)) { + if (!this.hasRecordForId(trueModelName, id)) { return this._findByInternalModel(internalModel, options); } let fetchedInternalModel = this._findRecord(internalModel, options); - return promiseRecord(fetchedInternalModel, "DS: Store#findRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id')); + return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${trueModelName} with id: ${id}`); }, _findRecord(internalModel, options) { @@ -762,11 +754,13 @@ Store = Service.extend({ assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); let promises = new Array(ids.length); + let trueModelName = this._classKeyFor(modelName); + for (let i = 0; i < ids.length; i++) { - promises[i] = this.findRecord(modelName, ids[i]); + promises[i] = this.findRecord(trueModelName, ids[i]); } - return promiseArray(RSVP.all(promises).then(A, null, "DS: Store#findByIds of " + modelName + " complete")); + return promiseArray(RSVP.all(promises).then(A, null, `DS: Store#findByIds of ${trueModelName} complete`)); }, /** @@ -981,13 +975,15 @@ Store = Service.extend({ ``` @method getReference - @param {String} type + @param {String} modelName @param {String|Integer} id @since 2.5.0 @return {RecordReference} */ - getReference: function(type, id) { - return this._internalModelForId(type, id).recordReference; + getReference(modelName, id) { + let trueModelName = this._classKeyFor(modelName); + + return this._internalModelForId(trueModelName, id).recordReference; }, /** @@ -1015,8 +1011,10 @@ Store = Service.extend({ heimdall.increment(peekRecord); assert("You need to pass a model name to the store's peekRecord method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); - if (this.hasRecordForId(modelName, id)) { - return this._internalModelForId(modelName, id).getRecord(); + let trueModelName = this._classKeyFor(modelName); + + if (this.hasRecordForId(trueModelName, id)) { + return this._internalModelForId(trueModelName, id).getRecord(); } else { return null; } @@ -1068,10 +1066,10 @@ Store = Service.extend({ hasRecordForId(modelName, id) { assert("You need to pass a model name to the store's hasRecordForId method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + let trueModelName = this._classKeyFor(modelName); let trueId = coerceId(id); - let modelClass = this.modelFor(modelName); - let internalModel = this.typeMapFor(modelClass).idToRecord[trueId]; + let internalModel = this._recordMapFor(trueModelName).get(trueId); return !!internalModel && internalModel.isLoaded(); }, @@ -1092,15 +1090,13 @@ Store = Service.extend({ return this._internalModelForId(modelName, id).getRecord(); }, - _internalModelForId(modelName, inputId) { + _internalModelForId(modelName, id) { heimdall.increment(_internalModelForId); - let modelClass = this.modelFor(modelName); - let id = coerceId(inputId); - let idToRecord = this.typeMapFor(modelClass).idToRecord; - let internalModel = idToRecord[id]; + let trueId = coerceId(id); + let internalModel = this._recordMapFor(modelName).get(trueId); - if (!internalModel || !idToRecord[id]) { - internalModel = this.buildInternalModel(modelClass, id); + if (!internalModel) { + internalModel = this.buildInternalModel(modelName, trueId); } return internalModel; @@ -1220,7 +1216,12 @@ Store = Service.extend({ @return {Promise} promise */ query(modelName, query) { - return this._query(modelName, query); + assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); + assert(`You need to pass a query hash to the store's query method`, query); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); + + let trueModelName = this._classKeyFor(modelName); + return this._query(trueModelName, query); }, _query(modelName, query, array) { @@ -1233,14 +1234,13 @@ Store = Service.extend({ let modelClass = this.modelFor(modelName); heimdall.stop(modelToken); - array = array || this.recordArrayManager - .createAdapterPopulatedRecordArray(modelClass, query); + array = array || this.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); let adapterToken = heimdall.start('initial-adapterFor-lookup'); let adapter = this.adapterFor(modelName); heimdall.stop(adapterToken); - assert("You tried to load a query but you have no adapter (for " + modelClass.modelName + ")", adapter); + assert("You tried to load a query but you have no adapter (for " + modelName + ")", adapter); assert("You tried to load a query but your adapter does not implement `query`", typeof adapter.query === 'function'); let pA = promiseArray(_query(adapter, this, modelClass, query, array)); @@ -1347,11 +1347,12 @@ Store = Service.extend({ assert("You need to pass a model name to the store's queryRecord method", isPresent(modelName)); assert("You need to pass a query hash to the store's queryRecord method", query); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + let trueModelName = this._classKeyFor(modelName); - let modelClass = this.modelFor(modelName); - let adapter = this.adapterFor(modelName); + let modelClass = this.modelFor(trueModelName); + let adapter = this.adapterFor(trueModelName); - assert("You tried to make a query but you have no adapter (for " + modelName + ")", adapter); + assert(`You tried to make a query but you have no adapter (for ${trueModelName})`, adapter); assert("You tried to make a query but your adapter does not implement `queryRecord`", typeof adapter.queryRecord === 'function'); return promiseObject(_queryRecord(adapter, this, modelClass, query).then((internalModel) => { @@ -1558,9 +1559,9 @@ Store = Service.extend({ assert("You need to pass a model name to the store's findAll method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); let token = heimdall.start('store.findAll'); - let modelClass = this.modelFor(modelName); - - let fetch = this._fetchAll(modelClass, this.peekAll(modelName), options); + let trueModelName = this._classKeyFor(modelName); + let modelClass = this.modelFor(trueModelName); + let fetch = this._fetchAll(modelClass, this.peekAll(trueModelName), options); instrument(() => { fetch.finally(() => { heimdall.stop(token); }); @@ -1579,10 +1580,11 @@ Store = Service.extend({ _fetchAll(modelClass, array, options) { options = options || {}; - let adapter = this.adapterFor(modelClass.modelName); - let sinceToken = this.typeMapFor(modelClass).metadata.since; + let modelName = modelClass.modelName; + let adapter = this.adapterFor(modelName); + let sinceToken = this._recordMapFor(modelName).metadata.since; - assert("You tried to load all records but you have no adapter (for " + modelClass.modelName + ")", adapter); + assert("You tried to load all records but you have no adapter (for " + modelName + ")", adapter); assert("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function'); if (options.reload) { @@ -1611,12 +1613,12 @@ Store = Service.extend({ /** @method didUpdateAll - @param {DS.Model} modelClass + @param {String} modelName @private */ - didUpdateAll(modelClass) { + didUpdateAll(modelName) { heimdall.increment(didUpdateAll); - let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(modelClass); + let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(modelName); set(liveRecordArray, 'isUpdating', false); }, @@ -1649,10 +1651,10 @@ Store = Service.extend({ heimdall.increment(peekAll); assert("You need to pass a model name to the store's peekAll method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); - let modelClass = this.modelFor(modelName); - let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(modelClass); + let trueModelName = this._classKeyFor(modelName); + let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(trueModelName); - this.recordArrayManager.syncLiveRecordArray(liveRecordArray, modelClass); + this.recordArrayManager.syncLiveRecordArray(liveRecordArray, trueModelName); return liveRecordArray; }, @@ -1675,28 +1677,10 @@ Store = Service.extend({ assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), !modelName || typeof modelName === 'string'); if (arguments.length === 0) { - let typeMaps = this.typeMaps; - let keys = Object.keys(typeMaps); - let types = new Array(keys.length); - - for (let i = 0; i < keys.length; i++) { - types[i] = typeMaps[keys[i]]['type'].modelName; - } - - types.forEach(this.unloadAll, this); + this._identityMap.clear(); } else { - let modelClass = this.modelFor(modelName); - let typeMap = this.typeMapFor(modelClass); - let records = typeMap.records.slice(); - let record; - - for (let i = 0; i < records.length; i++) { - record = records[i]; - record.unloadRecord(); - record.destroy(); // maybe within unloadRecord - } - - typeMap.metadata = new EmptyObject(); + let trueModelName = this._classKeyFor(modelName); + this._recordMapFor(trueModelName).clear(); } }, @@ -1767,24 +1751,24 @@ Store = Service.extend({ let array; let hasQuery = length === 3; + let trueModelName = this._classKeyFor(modelName); + // allow an optional server query if (hasQuery) { - promise = this.query(modelName, query); + promise = this.query(trueModelName, query); } else if (arguments.length === 2) { filter = query; } - modelName = this.modelFor(modelName); - if (hasQuery) { - array = this.recordArrayManager.createFilteredRecordArray(modelName, filter, query); + array = this.recordArrayManager.createFilteredRecordArray(trueModelName, filter, query); } else { - array = this.recordArrayManager.createFilteredRecordArray(modelName, filter); + array = this.recordArrayManager.createFilteredRecordArray(trueModelName, filter); } promise = promise || Promise.resolve(array); - return promiseArray(promise.then(() => array, null, 'DS: Store#filter of ' + modelName)); + return promiseArray(promise.then(() => array, null, `DS: Store#filter of ${trueModelName}`)); }, /** @@ -1815,12 +1799,11 @@ Store = Service.extend({ To avoid thrashing, this method is invoked only once per run loop per record. - @method dataWasUpdated + @method _dataWasUpdated @private - @param {Class} type @param {InternalModel} internalModel */ - dataWasUpdated(type, internalModel) { + _dataWasUpdated(internalModel) { this.recordArrayManager.recordDidChange(internalModel); }, @@ -1959,50 +1942,48 @@ Store = Service.extend({ let id = coerceId(data.id); // ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record) - assert(`'${internalModel.type.modelName}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null)); + assert(`'${internalModel.modelName}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null)); // ID absolutely can't be different than oldID if oldID is not null - assert(`'${internalModel.type.modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, !(oldId !== null && id !== oldId)); + assert(`'${internalModel.modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, !(oldId !== null && id !== oldId)); // ID can be null if oldID is not null (altered ID in response for a record) // however, this is more than likely a developer error. if (oldId !== null && id === null) { - warn(`Your ${internalModel.type.modelName} record was saved to the server, but the response does not have an id.`, !(oldId !== null && id === null)); + warn(`Your ${internalModel.modelName} record was saved to the server, but the response does not have an id.`, !(oldId !== null && id === null)); return; } - this.typeMapFor(internalModel.type).idToRecord[id] = internalModel; + this._recordMapFor(internalModel.modelName).set(id, internalModel); internalModel.setId(id); }, /** - Returns a map of IDs to client IDs for a given type. + Returns the normalized (dasherized) modelName. This method should be used whenever + receiving a modelName in a public method. - @method typeMapFor - @private - @param {DS.Model} modelClass - @return {Object} typeMap - */ - typeMapFor(modelClass) { - heimdall.increment(typeMapFor); - let typeMaps = get(this, 'typeMaps'); - let guid = guidFor(modelClass); - let typeMap = typeMaps[guid]; - - if (typeMap) { return typeMap; } - - heimdall.increment(typeMapFor_allocate); - typeMap = { - idToRecord: new EmptyObject(), - records: [], - metadata: new EmptyObject(), - type: modelClass - }; - typeMaps[guid] = typeMap; + @method _classKeyFor + @param {String} modelName + @returns {String} + @private + */ + _classKeyFor(modelName) { + return normalizeModelName(modelName); + }, + + /** + Returns a map of IDs to client IDs for a given modelName. - return typeMap; + @method _recordMapFor + @private + @param {String} modelName + @return {Object} recordMap + */ + _recordMapFor(modelName) { + heimdall.increment(_recordMapFor); + return this._identityMap.retrieve(modelName); }, // ................ @@ -2014,7 +1995,6 @@ Store = Service.extend({ @method _load @private - @param {(String|DS.Model)} type @param {Object} data */ _load(data) { @@ -2084,15 +2064,20 @@ Store = Service.extend({ assert("You need to pass a model name to the store's modelFor method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); - let factory = this.modelFactoryFor(modelName); + let trueModelName = this._classKeyFor(modelName); + + let factory = this.modelFactoryFor(trueModelName); if (!factory) { //Support looking up mixins as base types for polymorphic relationships - factory = this._modelForMixin(modelName); + factory = this._modelForMixin(trueModelName); } if (!factory) { - throw new EmberError("No model was found for '" + modelName + "'"); + throw new EmberError(`No model was found for '${trueModelName}'`); } - factory.modelName = factory.modelName || normalizeModelName(modelName); + + assert(`'${inspect(factory)}' does not appear to be an ember-data model`, (typeof factory._create === 'function') ); + + factory.modelName = factory.modelName || trueModelName; return factory; }, @@ -2101,11 +2086,10 @@ Store = Service.extend({ heimdall.increment(modelFactoryFor); assert("You need to pass a model name to the store's modelFactoryFor method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); - let normalizedKey = normalizeModelName(modelName); - + let trueModelName = this._classKeyFor(modelName); let owner = getOwner(this); - return owner._lookupFactory('model:' + normalizedKey); + return owner._lookupFactory(`model:${trueModelName}`); }, /** @@ -2344,14 +2328,14 @@ Store = Service.extend({ let unknownAttributes = Object.keys(data.attributes || {}).filter((key) => { return !get(modelClass, 'fields').has(key); }); - let unknownAttributesMessage = `The payload for '${modelClass.modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`; + let unknownAttributesMessage = `The payload for '${modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`; warn(unknownAttributesMessage, unknownAttributes.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); // Check unknown relationships let unknownRelationships = Object.keys(data.relationships || {}).filter((key) => { return !get(modelClass, 'fields').has(key); }); - let unknownRelationshipsMessage = `The payload for '${modelClass.modelName}' contains these unknown relationships: ${unknownRelationships}. Make sure they've been defined in your model.`; + let unknownRelationshipsMessage = `The payload for '${modelName}' contains these unknown relationships: ${unknownRelationships}. Make sure they've been defined in your model.`; warn(unknownRelationshipsMessage, unknownRelationships.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); } }); @@ -2452,7 +2436,8 @@ Store = Service.extend({ } else { payload = inputPayload; assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); - serializer = this.serializerFor(modelName); + let trueModelName = this._classKeyFor(modelName); + serializer = this.serializerFor(trueModelName); } if (isEnabled('ds-pushpayload-return')) { return this._adapterRun(() => { return serializer.pushPayload(this, payload); }); @@ -2484,8 +2469,9 @@ Store = Service.extend({ heimdall.increment(normalize); assert("You need to pass a model name to the store's normalize method", isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); - let serializer = this.serializerFor(modelName); - let model = this.modelFor(modelName); + let trueModelName = this._classKeyFor(modelName); + let serializer = this.serializerFor(trueModelName); + let model = this.modelFor(trueModelName); return serializer.normalize(model, payload); }, @@ -2495,30 +2481,25 @@ Store = Service.extend({ @method buildRecord @private - @param {DS.Model} modelClass + @param {String} modelName @param {String} id @param {Object} data @return {InternalModel} internal model */ - buildInternalModel(modelClass, id, data) { + buildInternalModel(modelName, id, data) { heimdall.increment(buildInternalModel); - let typeMap = this.typeMapFor(modelClass); - let idToRecord = typeMap.idToRecord; - assert(`The id ${id} has already been used with another record for modelClass ${modelClass}.`, !id || !idToRecord[id]); - assert(`'${inspect(modelClass)}' does not appear to be an ember-data model`, (typeof modelClass._create === 'function') ); + assert(`You can no longer pass a modelClass as the first argument to store.buildInternalModel. Pass modelName instead.`, typeof modelName === 'string'); + + let recordMap = this._recordMapFor(modelName); + + assert(`The id ${id} has already been used with another record for modelClass '${modelName}'.`, !id || !recordMap.get(id)); // lookupFactory should really return an object that creates // instances with the injections applied - let internalModel = new InternalModel(modelClass, id, this, data); + let internalModel = new InternalModel(modelName, id, this, data); - // if we're creating an item, this process will be done - // later, once the object has been persisted. - if (id) { - idToRecord[id] = internalModel; - } - - typeMap.records.push(internalModel); + recordMap.add(internalModel, id); return internalModel; }, @@ -2541,18 +2522,12 @@ Store = Service.extend({ @param {InternalModel} internalModel */ _dematerializeRecord(internalModel) { - let modelClass = internalModel.type; - let typeMap = this.typeMapFor(modelClass); + let recordMap = this._recordMapFor(internalModel.modelName); let id = internalModel.id; internalModel.updateRecordArrays(); - if (id) { - delete typeMap.idToRecord[id]; - } - - let loc = typeMap.records.indexOf(internalModel); - typeMap.records.splice(loc, 1); + recordMap.remove(internalModel, id); }, // ...................... @@ -2580,10 +2555,9 @@ Store = Service.extend({ heimdall.increment(adapterFor); assert("You need to pass a model name to the store's adapterFor method", isPresent(modelName)); assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); + let trueModelName = this._classKeyFor(modelName); - let normalizedModelName = normalizeModelName(modelName); - - return this._instanceCache.get('adapter', normalizedModelName); + return this._instanceCache.get('adapter', trueModelName); }, _adapterRun(fn) { @@ -2619,10 +2593,9 @@ Store = Service.extend({ heimdall.increment(serializerFor); assert("You need to pass a model name to the store's serializerFor method", isPresent(modelName)); assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); + let trueModelName = this._classKeyFor(modelName); - let normalizedModelName = normalizeModelName(modelName); - - return this._instanceCache.get('serializer', normalizedModelName); + return this._instanceCache.get('serializer', trueModelName); }, lookupAdapter(name) { @@ -2690,8 +2663,8 @@ function _commit(adapter, store, operation, snapshot) { let internalModel = snapshot._internalModel; let modelName = snapshot.modelName; let modelClass = store.modelFor(modelName); - assert(`You tried to update a record but you have no adapter (for ${modelClass.modelName})`, adapter); - assert(`You tried to update a record but your adapter (for ${modelClass.modelName}) does not implement '${operation}'`, typeof adapter[operation] === 'function'); + assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`, typeof adapter[operation] === 'function'); let promise = adapter[operation](store, modelClass, snapshot); let serializer = serializerForAdapter(store, adapter, modelName); let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index e99c665934b..c157ae5f18e 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -73,8 +73,7 @@ export function _findMany(adapter, store, typeClass, ids, internalModels) { assert("You made a `findMany` request for " + typeClass.modelName + " records with ids " + ids + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { let payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findMany'); - let internalModels = store._push(payload); - return internalModels; + return store._push(payload); }); }, null, "DS: Extract payload of " + typeClass); } @@ -94,10 +93,10 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) assert("You made a `findHasMany` request for a " + internalModel.modelName + "'s `" + relationship.key + "` relationship, using link " + link + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); return store._adapterRun(function() { let payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findHasMany'); - let recordArray = store._push(payload); + let internalModelArray = store._push(payload); - recordArray.meta = payload.meta; - return recordArray; + internalModelArray.meta = payload.meta; + return internalModelArray; }); }, null, "DS: Extract payload of " + internalModel + " : hasMany " + relationship.type); } @@ -121,8 +120,7 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship return null; } - var internalModel = store._push(payload); - return internalModel; + return store._push(payload); }); }, null, "DS: Extract payload of " + internalModel + " : " + relationship.type); } @@ -145,7 +143,7 @@ export function _findAll(adapter, store, typeClass, sinceToken, options) { store._push(payload); }); - store.didUpdateAll(typeClass); + store.didUpdateAll(modelName); return store.peekAll(modelName); }, null, "DS: Extract payload of findAll " + typeClass); } diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index a91d402581f..7262337e2cb 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -557,9 +557,9 @@ test("createRecord - response can contain relationships the client doesn't yet k run(function() { post.save().then(assert.wait(function(post) { assert.equal(post.get('comments.firstObject.post'), post, "the comments are related to the correct post model"); - assert.equal(store.typeMapFor(Post).records.length, 1, "There should only be one post record in the store"); + assert.equal(store._recordMapFor('post').records.length, 1, "There should only be one post record in the store"); - var postRecords = store.typeMapFor(Post).records; + var postRecords = store._recordMapFor('post').records; for (var i = 0; i < postRecords.length; i++) { assert.equal(post, postRecords[i].getRecord(), "The object in the identity map is the same"); } diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index b98a439db50..4d30afcf9f5 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -77,6 +77,7 @@ test("empty string and undefined ids should coerce to null", function(assert) { assert.expect(6); var comment, post; var idCount = 0; + let id = 1; var ids = [undefined, '']; env.adapter.generateIdForRecord = function(passedStore, record) { assert.equal(env.store, passedStore, "store is the first parameter"); @@ -86,7 +87,7 @@ test("empty string and undefined ids should coerce to null", function(assert) { env.adapter.createRecord = function(store, type, record) { assert.equal(typeof get(record, 'id'), 'object', 'correct type'); - return Ember.RSVP.resolve({ id: 1 }); + return Ember.RSVP.resolve({ id: id++ }); }; run(function() { diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index 2b12d21185d..adac8005b36 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -93,10 +93,10 @@ test('destroying the store correctly cleans everything up', function(assert) { person = store.peekRecord('person', 1); }); - let filterd = manager.createFilteredRecordArray(Person, () => true); - let filterd2 = manager.createFilteredRecordArray(Person, () => true); + let filterd = manager.createFilteredRecordArray('person', () => true); + let filterd2 = manager.createFilteredRecordArray('person', () => true); let all = store.peekAll('person'); - let adapterPopulated = manager.createAdapterPopulatedRecordArray(Person, query); + let adapterPopulated = manager.createAdapterPopulatedRecordArray('person', query); let filterdSummary = tap(filterd, 'willDestroy'); let filterd2Summary = tap(filterd2, 'willDestroy'); @@ -117,13 +117,13 @@ test('destroying the store correctly cleans everything up', function(assert) { assert.equal(manager.recordArraysForRecord(internalPersonModel).size, 2, 'expected the person to be a member of 2 recordArrays'); assert.equal(filterd2Summary.called.length, 1); - assert.equal(manager.liveRecordArrays.has(all.type), true); + assert.equal(manager.liveRecordArrays.has('person'), true); Ember.run(all, all.destroy); assert.equal(manager.recordArraysForRecord(internalPersonModel).size, 1, 'expected the person to be a member of 1 recordArrays'); assert.equal(allSummary.called.length, 1); - assert.equal(manager.liveRecordArrays.has(all.type), false); + assert.equal(manager.liveRecordArrays.has('person'), false); Ember.run(manager, manager.destroy); @@ -185,7 +185,7 @@ test('#GH-4041 store#query AdapterPopulatedRecordArrays are removed from their m const query = {}; - let adapterPopulated = manager.createAdapterPopulatedRecordArray(Car, query); + let adapterPopulated = manager.createAdapterPopulatedRecordArray('car', query); run(() => adapterPopulated.destroy()); diff --git a/tests/integration/record-arrays/adapter-populated-record-array-test.js b/tests/integration/record-arrays/adapter-populated-record-array-test.js index 05634db3875..032ae779955 100644 --- a/tests/integration/record-arrays/adapter-populated-record-array-test.js +++ b/tests/integration/record-arrays/adapter-populated-record-array-test.js @@ -33,7 +33,7 @@ module('integration/record-arrays/adapter_populated_record_array - DS.AdapterPop test('when a record is deleted in an adapter populated record array, it should be removed', function(assert) { let recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray(store.modelFor('person'), null); + .createAdapterPopulatedRecordArray('person', null); let payload = { data: [ @@ -74,7 +74,7 @@ test('when a record is deleted in an adapter populated record array, it should b test('stores the metadata off the payload', function(assert) { let recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray(Person, null); + .createAdapterPopulatedRecordArray('person', null); let payload = { data: [ @@ -114,7 +114,7 @@ test('stores the metadata off the payload', function(assert) { test('stores the links off the payload', function(assert) { let recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray(store.modelFor('person'), null); + .createAdapterPopulatedRecordArray('person', null); let payload = { data: [ @@ -154,11 +154,11 @@ test('stores the links off the payload', function(assert) { test('recordArray.replace() throws error', function(assert) { let recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray(Person, null); + .createAdapterPopulatedRecordArray('person', null); assert.throws(() => { recordArray.replace(); - }, Error('The result of a server query (on (subclass of DS.Model)) is immutable.'), 'throws error'); + }, Error('The result of a server query (on person) is immutable.'), 'throws error'); }); test('loadRecord re-syncs internalModels recordArrays', function(assert) { diff --git a/tests/integration/records/collection-save-test.js b/tests/integration/records/collection-save-test.js index 779afd1c4b0..83460722740 100644 --- a/tests/integration/records/collection-save-test.js +++ b/tests/integration/records/collection-save-test.js @@ -24,6 +24,7 @@ module("integration/records/collection_save - Save Collection of Records", { test("Collection will resolve save on success", function(assert) { assert.expect(1); + let id = 1; run(function() { env.store.createRecord('post', { title: 'Hello' }); env.store.createRecord('post', { title: 'World' }); @@ -32,7 +33,7 @@ test("Collection will resolve save on success", function(assert) { var posts = env.store.peekAll('post'); env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ id: 123 }); + return Ember.RSVP.resolve({ id: id++ }); }; run(function() { @@ -70,25 +71,31 @@ test("Retry is allowed in a failure handler", function(assert) { var posts = env.store.peekAll('post'); var count = 0; + let id = 1; env.adapter.createRecord = function(store, type, snapshot) { if (count++ === 0) { return Ember.RSVP.reject(); } else { - return Ember.RSVP.resolve({ id: 123 }); + return Ember.RSVP.resolve({ id: id++ }); } }; env.adapter.updateRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ id: 123 }); + return Ember.RSVP.resolve({ id: snapshot.id }); }; run(function() { - posts.save().then(function() {}, assert.wait(function() { - return posts.save(); - })).then(assert.wait(function(post) { - assert.equal(posts.get('firstObject.id'), '123', "The post ID made it through"); - })); + posts.save() + .then( + function() {}, + assert.wait(function() { return posts.save(); })) + .then( + assert.wait(function(post) { + // the ID here is '2' because the second post saves on the first attempt, + // while the first post saves on the second attempt + assert.equal(posts.get('firstObject.id'), '2', "The post ID made it through"); + })); }); }); diff --git a/tests/unit/record-arrays/adapter-populated-record-array-test.js b/tests/unit/record-arrays/adapter-populated-record-array-test.js index 1c020e44b13..4d1e052a9a0 100644 --- a/tests/unit/record-arrays/adapter-populated-record-array-test.js +++ b/tests/unit/record-arrays/adapter-populated-record-array-test.js @@ -23,10 +23,10 @@ function internalModelFor(record) { } test('default initial state', function(assert) { - let recordArray = AdapterPopulatedRecordArray.create({ type: 'recordType' }); + let recordArray = AdapterPopulatedRecordArray.create({ modelName: 'recordType' }); assert.equal(recordArray.get('isLoaded'), false, 'expected isLoaded to be false'); - assert.equal(recordArray.get('type'), 'recordType'); + assert.equal(recordArray.get('modelName'), 'recordType'); assert.deepEqual(recordArray.get('content'), []); assert.equal(recordArray.get('query'), null); assert.equal(recordArray.get('store'), null); @@ -37,17 +37,17 @@ test('custom initial state', function(assert) { let content = Ember.A([]); let store = {}; let recordArray = AdapterPopulatedRecordArray.create({ - type: 'apple', + modelName: 'apple', isLoaded: true, isUpdating: true, content, store, query: 'some-query', links: 'foo' - }) + }); assert.equal(recordArray.get('isLoaded'), true); assert.equal(recordArray.get('isUpdating'), false); - assert.equal(recordArray.get('type'), 'apple'); + assert.equal(recordArray.get('modelName'), 'apple'); assert.equal(recordArray.get('content'), content); assert.equal(recordArray.get('store'), store); assert.equal(recordArray.get('query'), 'some-query'); @@ -55,7 +55,7 @@ test('custom initial state', function(assert) { }); test('#replace() throws error', function(assert) { - let recordArray = AdapterPopulatedRecordArray.create({ type: 'recordType' }); + let recordArray = AdapterPopulatedRecordArray.create({ modelName: 'recordType' }); assert.throws(() => { recordArray.replace(); @@ -78,7 +78,7 @@ test('#update uses _update enabling query specific behavior', function(assert) { }; let recordArray = AdapterPopulatedRecordArray.create({ - type: { modelName: 'recordType' }, + modelName: 'recordType', store, query: 'some-query' }); diff --git a/tests/unit/record-arrays/filtered-record-array-test.js b/tests/unit/record-arrays/filtered-record-array-test.js index dc9245e3081..8914a617591 100644 --- a/tests/unit/record-arrays/filtered-record-array-test.js +++ b/tests/unit/record-arrays/filtered-record-array-test.js @@ -9,10 +9,10 @@ const { FilteredRecordArray } = DS; module('unit/record-arrays/filtered-record-array - DS.FilteredRecordArray'); test('default initial state', function(assert) { - let recordArray = FilteredRecordArray.create({ type: 'recordType' }); + let recordArray = FilteredRecordArray.create({ modelName: 'recordType' }); assert.equal(get(recordArray, 'isLoaded'), true); - assert.equal(get(recordArray, 'type'), 'recordType'); + assert.equal(get(recordArray, 'modelName'), 'recordType'); assert.equal(get(recordArray, 'content'), null); assert.equal(get(recordArray, 'filterFunction'), null); assert.equal(get(recordArray, 'store'), null); @@ -23,23 +23,23 @@ test('custom initial state', function(assert) { let store = {}; let filterFunction = () => true; let recordArray = FilteredRecordArray.create({ - type: 'apple', + modelName: 'apple', isLoaded: false, // ignored isUpdating: true, content, store, filterFunction - }) + }); assert.equal(get(recordArray, 'isLoaded'), true); assert.equal(get(recordArray, 'isUpdating'), false); // cannot set as default value: - assert.equal(get(recordArray, 'type'), 'apple'); + assert.equal(get(recordArray, 'modelName'), 'apple'); assert.equal(get(recordArray, 'content'), content); assert.equal(get(recordArray, 'store'), store); assert.equal(get(recordArray, 'filterFunction'), filterFunction); }); test('#replace() throws error', function(assert) { - let recordArray = FilteredRecordArray.create({ type: 'recordType' }); + let recordArray = FilteredRecordArray.create({ modelName: 'recordType' }); assert.throws(function() { recordArray.replace(); @@ -51,17 +51,17 @@ test('updateFilter', function(assert) { const updatedFilterFunction = () => true; const manager = { - updateFilter(array, type, filterFunction) { + updateFilter(array, modelName, filterFunction) { didUpdateFilter++; assert.equal(recordArray, array); - assert.equal(type, 'recordType'); + assert.equal(modelName, 'recordType'); assert.equal(filterFunction, updatedFilterFunction); }, unregisterRecordArray() {} }; let recordArray = FilteredRecordArray.create({ - type: 'recordType', + modelName: 'recordType', manager, content: Ember.A() }); @@ -86,4 +86,4 @@ test('updateFilter', function(assert) { }); assert.equal(didUpdateFilter, 0, 'record array manager should not be informed of this change'); -}) +}); diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js index eb4f68a15cf..87af38604ab 100644 --- a/tests/unit/record-arrays/record-array-test.js +++ b/tests/unit/record-arrays/record-array-test.js @@ -8,11 +8,11 @@ const { RecordArray } = DS; module('unit/record-arrays/record-array - DS.RecordArray'); test('default initial state', function(assert) { - let recordArray = RecordArray.create({ type: 'recordType' }); + let recordArray = RecordArray.create({ modelName: 'recordType' }); assert.equal(get(recordArray, 'isLoaded'), false); assert.equal(get(recordArray, 'isUpdating'), false); - assert.equal(get(recordArray, 'type'), 'recordType'); + assert.equal(get(recordArray, 'modelName'), 'recordType'); assert.equal(get(recordArray, 'content'), null); assert.equal(get(recordArray, 'store'), null); }); @@ -21,21 +21,21 @@ test('custom initial state', function(assert) { let content = Ember.A(); let store = {}; let recordArray = RecordArray.create({ - type: 'apple', + modelName: 'apple', isLoaded: true, isUpdating: true, content, store - }) + }); assert.equal(get(recordArray, 'isLoaded'), true); assert.equal(get(recordArray, 'isUpdating'), false); // cannot set as default value: - assert.equal(get(recordArray, 'type'), 'apple'); + assert.equal(get(recordArray, 'modelName'), 'apple'); assert.equal(get(recordArray, 'content'), content); assert.equal(get(recordArray, 'store'), store); }); test('#replace() throws error', function(assert) { - let recordArray = RecordArray.create({ type: 'recordType' }); + let recordArray = RecordArray.create({ modelName: 'recordType' }); assert.throws(function() { recordArray.replace(); @@ -50,7 +50,7 @@ test('#objectAtContent', function(assert) { ]); let recordArray = RecordArray.create({ - type: 'recordType', + modelName: 'recordType', content }); @@ -76,7 +76,7 @@ test('#update', function(assert) { }; let recordArray = RecordArray.create({ - type: { modelName: 'recordType' }, + modelName: 'recordType', store }); @@ -110,7 +110,7 @@ test('#update while updating', function(assert) { }; let recordArray = RecordArray.create({ - type: { modelName: 'recordType' }, + modelName: { modelName: 'recordType' }, store }); diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index 439c903ad4e..c637c921ec7 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -367,7 +367,7 @@ testInDebug("a new record with a specific id can't be created if this id is alre run(function() { store.createRecord('person', { id: 5 }); }); - }, /The id 5 has already been used with another record for modelClass Person/); + }, /The id 5 has already been used with another record for modelClass 'person'/); }); test("an initial data hash can be provided via store.createRecord(type, hash)", function(assert) { diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index c0864e9fb4c..960959dce2e 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -766,6 +766,23 @@ test("_push returns an instance of InternalModel if an object is pushed", functi assert.notOk(pushResult.record, 'InternalModel is not materialized'); }); +test("_push does not require a modelName to resolve to a modelClass", function(assert) { + let originalCall = store.modelFor; + store.modelFor = () => { assert.notOk('modelFor was triggered as a result of a call to store._push'); }; + + run(function() { + store._push({ + data: { + id: 1, + type: 'person' + } + }); + }); + + store.modelFor = originalCall; + assert.ok('We made it'); +}); + test("_push returns an array of InternalModels if an array is pushed", function(assert) { let pushResult; From eaa343512cad429bd326bfe425c5939935fa2ddd Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Sun, 11 Dec 2016 17:56:46 -0800 Subject: [PATCH 1752/2527] fix test --- .../model/relationships/record-array-test.js | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/tests/unit/model/relationships/record-array-test.js b/tests/unit/model/relationships/record-array-test.js index 9ea9f467036..dfb7291f05e 100644 --- a/tests/unit/model/relationships/record-array-test.js +++ b/tests/unit/model/relationships/record-array-test.js @@ -12,16 +12,17 @@ var run = Ember.run; module("unit/model/relationships - RecordArray"); test("updating the content of a RecordArray updates its content", function(assert) { - var Tag = DS.Model.extend({ + let Tag = DS.Model.extend({ name: DS.attr('string') }); - var env = setupStore({ tag: Tag }); - var store = env.store; - var records, tags, internalModel; + let env = setupStore({ tag: Tag }); + let store = env.store; + let tags; + let internalModels; run(function() { - store.push({ + internalModels = store._push({ data: [{ type: 'tag', id: '5', @@ -42,16 +43,18 @@ test("updating the content of a RecordArray updates its content", function(asser } }] }); - records = store.peekAll('tag'); - internalModel = Ember.A(records).mapBy('_internalModel'); - tags = DS.RecordArray.create({ content: Ember.A(internalModel.slice(0, 2)), store: store, type: Tag }); + tags = DS.RecordArray.create({ + content: Ember.A(internalModels.slice(0, 2)), + store: store, + modelName: 'tag' + }); }); - var tag = tags.objectAt(0); + let tag = tags.objectAt(0); assert.equal(get(tag, 'name'), "friendly", "precond - we're working with the right tags"); run(function() { - set(tags, 'content', Ember.A(internalModel.slice(1, 3))); + set(tags, 'content', Ember.A(internalModels.slice(1, 3))); }); tag = tags.objectAt(0); From fe74d89221220be12522307122a2625202a1f0cf Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Sun, 11 Dec 2016 18:14:21 -0800 Subject: [PATCH 1753/2527] fix readOnly --- addon/-private/system/record-arrays/record-array.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index 4e19330eda4..d4db4ba9d70 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -88,12 +88,12 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @property type @type DS.Model */ - type: computed.readOnly('modelName', function() { + type: computed('modelName', function() { if (!this.modelName) { return null; } return this.store.modelFor(this.modelName); - }), + }).readOnly(), /** Retrieves an object from the content by index. From 3475857e7735de320932ae4f130a6cea808dc4bf Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 8 Dec 2016 17:45:40 -0800 Subject: [PATCH 1754/2527] removes store._adapterRun now that _push handles run.join, reducing the number of run loops and closures created. --- addon/-private/system/store.js | 19 ++-- addon/-private/system/store/finders.js | 124 +++++++++++-------------- 2 files changed, 65 insertions(+), 78 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 1356eb73a83..dbe85fc221b 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2440,9 +2440,9 @@ Store = Service.extend({ serializer = this.serializerFor(trueModelName); } if (isEnabled('ds-pushpayload-return')) { - return this._adapterRun(() => { return serializer.pushPayload(this, payload); }); + return serializer.pushPayload(this, payload); } else { - this._adapterRun(() => serializer.pushPayload(this, payload)); + serializer.pushPayload(this, payload); } }, @@ -2560,10 +2560,6 @@ Store = Service.extend({ return this._instanceCache.get('adapter', trueModelName); }, - _adapterRun(fn) { - return this._backburner.run(fn); - }, - // .............................. // . RECORD CHANGE NOTIFICATION . // .............................. @@ -2676,7 +2672,16 @@ function _commit(adapter, store, operation, snapshot) { promise = _guard(promise, _bind(_objectIsAlive, internalModel)); return promise.then((adapterPayload) => { - store._adapterRun(() => { + /* + Note to future spelunkers hoping to optimize. + We rely on this `run` to create a run loop if needed + that `store._push` and `store.didSaveRecord` will both share. + + We use `join` because it is often the case that we + have an outer run loop available still from the first + call to `store._push`; + */ + store._backburner.join(() => { let payload, data; if (adapterPayload) { payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, snapshot.id, operation); diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index c157ae5f18e..8bef9a0876d 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -24,27 +24,25 @@ function payloadIsNotBlank(adapterPayload) { } } -export function _find(adapter, store, typeClass, id, internalModel, options) { +export function _find(adapter, store, modelClass, id, internalModel, options) { var snapshot = internalModel.createSnapshot(options); - var promise = adapter.findRecord(store, typeClass, id, snapshot); + var promise = adapter.findRecord(store, modelClass, id, snapshot); var serializer = serializerForAdapter(store, adapter, internalModel.type.modelName); - var label = "DS: Handle Adapter#findRecord of " + typeClass + " with id: " + id; + var label = "DS: Handle Adapter#findRecord of " + modelClass + " with id: " + id; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - assert("You made a `findRecord` request for a " + typeClass.modelName + " with id " + id + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); - return store._adapterRun(function() { - var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, id, 'findRecord'); - assert('Ember Data expected the primary data returned from a `findRecord` response to be an object but instead it found an array.', !Array.isArray(payload.data)); + assert("You made a `findRecord` request for a " + modelClass.modelName + " with id " + id + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, id, 'findRecord'); + assert('Ember Data expected the primary data returned from a `findRecord` response to be an object but instead it found an array.', !Array.isArray(payload.data)); - warn(`You requested a record of type '${typeClass.modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead http://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, payload.data.id === id, { - id: 'ds.store.findRecord.id-mismatch' - }); - - return store._push(payload); + warn(`You requested a record of type '${modelClass.modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead http://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, payload.data.id === id, { + id: 'ds.store.findRecord.id-mismatch' }); + + return store._push(payload); }, function(error) { internalModel.notFound(); if (internalModel.isEmpty()) { @@ -52,15 +50,15 @@ export function _find(adapter, store, typeClass, id, internalModel, options) { } throw error; - }, "DS: Extract payload of '" + typeClass + "'"); + }, "DS: Extract payload of '" + modelClass + "'"); } -export function _findMany(adapter, store, typeClass, ids, internalModels) { +export function _findMany(adapter, store, modelClass, ids, internalModels) { let snapshots = Ember.A(internalModels).invoke('createSnapshot'); - let promise = adapter.findMany(store, typeClass, ids, snapshots); - let serializer = serializerForAdapter(store, adapter, typeClass.modelName); - let label = "DS: Handle Adapter#findMany of " + typeClass; + let promise = adapter.findMany(store, modelClass, ids, snapshots); + let serializer = serializerForAdapter(store, adapter, modelClass.modelName); + let label = "DS: Handle Adapter#findMany of " + modelClass; if (promise === undefined) { throw new Error('adapter.findMany returned undefined, this was very likely a mistake'); @@ -70,17 +68,15 @@ export function _findMany(adapter, store, typeClass, ids, internalModels) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - assert("You made a `findMany` request for " + typeClass.modelName + " records with ids " + ids + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); - return store._adapterRun(function() { - let payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findMany'); - return store._push(payload); - }); - }, null, "DS: Extract payload of " + typeClass); + assert("You made a `findMany` request for " + modelClass.modelName + " records with ids " + ids + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findMany'); + return store._push(payload); + }, null, "DS: Extract payload of " + modelClass); } export function _findHasMany(adapter, store, internalModel, link, relationship) { var snapshot = internalModel.createSnapshot(); - var typeClass = store.modelFor(relationship.type); + var modelClass = store.modelFor(relationship.type); var promise = adapter.findHasMany(store, snapshot, link, relationship); var serializer = serializerForAdapter(store, adapter, relationship.type); var label = "DS: Handle Adapter#findHasMany of " + internalModel + " : " + relationship.type; @@ -91,19 +87,17 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) return promise.then(function(adapterPayload) { assert("You made a `findHasMany` request for a " + internalModel.modelName + "'s `" + relationship.key + "` relationship, using link " + link + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); - return store._adapterRun(function() { - let payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findHasMany'); - let internalModelArray = store._push(payload); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findHasMany'); + let internalModelArray = store._push(payload); - internalModelArray.meta = payload.meta; - return internalModelArray; - }); + internalModelArray.meta = payload.meta; + return internalModelArray; }, null, "DS: Extract payload of " + internalModel + " : hasMany " + relationship.type); } export function _findBelongsTo(adapter, store, internalModel, link, relationship) { var snapshot = internalModel.createSnapshot(); - var typeClass = store.modelFor(relationship.type); + var modelClass = store.modelFor(relationship.type); var promise = adapter.findBelongsTo(store, snapshot, link, relationship); var serializer = serializerForAdapter(store, adapter, relationship.type); var label = "DS: Handle Adapter#findBelongsTo of " + internalModel + " : " + relationship.type; @@ -113,67 +107,61 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship promise = _guard(promise, _bind(_objectIsAlive, internalModel)); return promise.then(function(adapterPayload) { - return store._adapterRun(function() { - var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findBelongsTo'); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findBelongsTo'); - if (!payload.data) { - return null; - } + if (!payload.data) { + return null; + } - return store._push(payload); - }); + return store._push(payload); }, null, "DS: Extract payload of " + internalModel + " : " + relationship.type); } -export function _findAll(adapter, store, typeClass, sinceToken, options) { - var modelName = typeClass.modelName; +export function _findAll(adapter, store, modelClass, sinceToken, options) { + var modelName = modelClass.modelName; var recordArray = store.peekAll(modelName); var snapshotArray = recordArray._createSnapshot(options); - var promise = adapter.findAll(store, typeClass, sinceToken, snapshotArray); + var promise = adapter.findAll(store, modelClass, sinceToken, snapshotArray); var serializer = serializerForAdapter(store, adapter, modelName); - var label = "DS: Handle Adapter#findAll of " + typeClass; + var label = "DS: Handle Adapter#findAll of " + modelClass; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - assert("You made a `findAll` request for " + typeClass.modelName + " records, but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); - store._adapterRun(function() { - var payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'findAll'); - store._push(payload); - }); + assert("You made a `findAll` request for " + modelClass.modelName + " records, but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findAll'); + store._push(payload); store.didUpdateAll(modelName); + return store.peekAll(modelName); - }, null, "DS: Extract payload of findAll " + typeClass); + }, null, "DS: Extract payload of findAll " + modelClass); } -export function _query(adapter, store, typeClass, query, recordArray) { - let modelName = typeClass.modelName; - let promise = adapter.query(store, typeClass, query, recordArray); +export function _query(adapter, store, modelClass, query, recordArray) { + let modelName = modelClass.modelName; + let promise = adapter.query(store, modelClass, query, recordArray); let serializerToken = heimdall.start('initial-serializerFor-lookup'); let serializer = serializerForAdapter(store, adapter, modelName); heimdall.stop(serializerToken); - let label = 'DS: Handle Adapter#query of ' + typeClass; + let label = 'DS: Handle Adapter#query of ' + modelClass; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(adapterPayload => { - let internalModels, payload; - store._adapterRun(() => { - let normalizeToken = heimdall.start('finders#_query::normalizeResponseHelper'); - payload = normalizeResponseHelper(serializer, store, typeClass, adapterPayload, null, 'query'); - heimdall.stop(normalizeToken); - internalModels = store._push(payload); - }); + let normalizeToken = heimdall.start('finders#_query::normalizeResponseHelper'); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'query'); + heimdall.stop(normalizeToken); + let internalModels = store._push(payload); assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Array.isArray(internalModels)); recordArray._setInternalModels(internalModels, payload); return recordArray; - }, null, 'DS: Extract payload of query ' + typeClass); + }, null, 'DS: Extract payload of query ' + modelName); } export function _queryRecord(adapter, store, modelClass, query) { @@ -186,18 +174,12 @@ export function _queryRecord(adapter, store, modelClass, query) { promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(function(adapterPayload) { - let internalModel; - store._adapterRun(function() { - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'queryRecord'); - - assert("Expected the primary data returned by the serializer for a `queryRecord` response to be a single object or null but instead it was an array.", !Array.isArray(payload.data), { - id: 'ds.store.queryRecord-array-response' - }); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'queryRecord'); - internalModel = store._push(payload); + assert("Expected the primary data returned by the serializer for a `queryRecord` response to be a single object or null but instead it was an array.", !Array.isArray(payload.data), { + id: 'ds.store.queryRecord-array-response' }); - return internalModel; - - }, null, "DS: Extract payload of queryRecord " + modelClass); + return store._push(payload); + }, null, "DS: Extract payload of queryRecord " + modelName); } From 29d6f147d016d915e74943792374c7a4e4a65975 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 9 Dec 2016 02:41:32 -0800 Subject: [PATCH 1755/2527] implements a factory cache for modelFor lookups --- addon/-private/system/model/internal-model.js | 2 +- .../system/record-arrays/record-array.js | 2 +- addon/-private/system/store.js | 53 +++++++++++++------ addon/serializers/json-api.js | 2 +- addon/serializers/rest.js | 2 +- 5 files changed, 40 insertions(+), 21 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 8663c3db247..8e861cc5673 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -135,7 +135,7 @@ export default class InternalModel { } get modelClass() { - return this._modelClass || (this._modelClass = this.store.modelFor(this.modelName)); + return this._modelClass || (this._modelClass = this.store._modelFor(this.modelName)); } get type() { diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index d4db4ba9d70..b4a1e5013ef 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -92,7 +92,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { if (!this.modelName) { return null; } - return this.store.modelFor(this.modelName); + return this.store._modelFor(this.modelName); }).readOnly(), /** diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index dbe85fc221b..8e2852c54ff 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -215,6 +215,7 @@ Store = Service.extend({ this._identityMap = new IdentityMap(); this._pendingSave = []; this._instanceCache = new ContainerInstanceCache(getOwner(this), this); + this._modelClassCache = new EmptyObject(); /* Ember Data uses several specialized micro-queues for organizing @@ -1231,7 +1232,7 @@ Store = Service.extend({ assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); let modelToken = heimdall.start('initial-modelFor-lookup'); - let modelClass = this.modelFor(modelName); + let modelClass = this._modelFor(modelName); heimdall.stop(modelToken); array = array || this.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); @@ -1349,7 +1350,7 @@ Store = Service.extend({ assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); let trueModelName = this._classKeyFor(modelName); - let modelClass = this.modelFor(trueModelName); + let modelClass = this._modelFor(trueModelName); let adapter = this.adapterFor(trueModelName); assert(`You tried to make a query but you have no adapter (for ${trueModelName})`, adapter); @@ -1560,7 +1561,7 @@ Store = Service.extend({ assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); let token = heimdall.start('store.findAll'); let trueModelName = this._classKeyFor(modelName); - let modelClass = this.modelFor(trueModelName); + let modelClass = this._modelFor(trueModelName); let fetch = this._fetchAll(modelClass, this.peekAll(trueModelName), options); instrument(() => { @@ -2023,8 +2024,9 @@ Store = Service.extend({ relationship metadata. Thus, we look up the mixin and create a mock DS.Model, so we can access the relationship CPs of the mixin (`comments`) in this case - */ + @private + */ _modelForMixin(modelName) { heimdall.increment(_modelForMixin); let normalizedModelName = normalizeModelName(modelName); @@ -2060,28 +2062,45 @@ Store = Service.extend({ @return {DS.Model} */ modelFor(modelName) { - heimdall.increment(modelFor); assert("You need to pass a model name to the store's modelFor method", isPresent(modelName)); assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); let trueModelName = this._classKeyFor(modelName); - let factory = this.modelFactoryFor(trueModelName); - if (!factory) { - //Support looking up mixins as base types for polymorphic relationships - factory = this._modelForMixin(trueModelName); - } + return this._modelFor(trueModelName); + }, + + /* + @private + */ + _modelFor(modelName) { + heimdall.increment(modelFor); + let factory = this._modelClassCache[modelName]; + if (!factory) { - throw new EmberError(`No model was found for '${trueModelName}'`); - } + factory = this.modelFactoryFor(modelName); + + if (!factory) { + //Support looking up mixins as base types for polymorphic relationships + factory = this._modelForMixin(modelName); + } + if (!factory) { + throw new EmberError(`No model was found for '${modelName}'`); + } - assert(`'${inspect(factory)}' does not appear to be an ember-data model`, (typeof factory._create === 'function') ); + assert(`'${inspect(factory)}' does not appear to be an ember-data model`, (typeof factory._create === 'function') ); - factory.modelName = factory.modelName || trueModelName; + factory.modelName = factory.modelName || modelName; + + this._modelClassCache[modelName] = factory; + } return factory; }, + /* + @private + */ modelFactoryFor(modelName) { heimdall.increment(modelFactoryFor); assert("You need to pass a model name to the store's modelFactoryFor method", isPresent(modelName)); @@ -2322,7 +2341,7 @@ Store = Service.extend({ // contains unknown attributes or relationships, log a warning. if (ENV.DS_WARN_ON_UNKNOWN_KEYS) { - let modelClass = this.modelFor(modelName); + let modelClass = this._modelFor(modelName); // Check unknown attributes let unknownAttributes = Object.keys(data.attributes || {}).filter((key) => { @@ -2471,7 +2490,7 @@ Store = Service.extend({ assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); let trueModelName = this._classKeyFor(modelName); let serializer = this.serializerFor(trueModelName); - let model = this.modelFor(trueModelName); + let model = this._modelFor(trueModelName); return serializer.normalize(model, payload); }, @@ -2658,7 +2677,7 @@ function defaultSerializer(store) { function _commit(adapter, store, operation, snapshot) { let internalModel = snapshot._internalModel; let modelName = snapshot.modelName; - let modelClass = store.modelFor(modelName); + let modelClass = store._modelFor(modelName); assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter); assert(`You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`, typeof adapter[operation] === 'function'); let promise = adapter[operation](store, modelClass, snapshot); diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 295266c2f55..0655cacae4c 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -237,7 +237,7 @@ const JSONAPISerializer = JSONSerializer.extend({ return null; } - let modelClass = this.store.modelFor(modelName); + let modelClass = this.store._modelFor(modelName); let serializer = this.store.serializerFor(modelName); let { data } = serializer.normalize(modelClass, resourceHash); return data; diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 13864f50cf1..0f11c4db21b 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -183,7 +183,7 @@ var RESTSerializer = JSONSerializer.extend({ included: [] }; - let modelClass = store.modelFor(modelName); + let modelClass = store._modelFor(modelName); let serializer = store.serializerFor(modelName); Ember.makeArray(arrayHash).forEach((hash) => { From 62d58e3a6541972ff29cccc567141bd935b06033 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 13 Dec 2016 17:20:35 -0800 Subject: [PATCH 1756/2527] converts Snapshot to an es6 class instead of using prototype assign --- addon/-private/system/snapshot.js | 330 +++++++++++++++--------------- 1 file changed, 164 insertions(+), 166 deletions(-) diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index cd206d1ade1..b873c4ded10 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -5,7 +5,9 @@ import Ember from 'ember'; import EmptyObject from "ember-data/-private/system/empty-object"; -var get = Ember.get; +const { + get +} = Ember; /** @class Snapshot @@ -14,137 +16,133 @@ var get = Ember.get; @constructor @param {DS.Model} internalModel The model to create a snapshot from */ -export default function Snapshot(internalModel, options = {}) { - this._attributes = new EmptyObject(); - this._belongsToRelationships = new EmptyObject(); - this._belongsToIds = new EmptyObject(); - this._hasManyRelationships = new EmptyObject(); - this._hasManyIds = new EmptyObject(); - - let record = internalModel.getRecord(); - this.record = record; - record.eachAttribute((keyName) => this._attributes[keyName] = get(record, keyName)); - - this.id = internalModel.id; - this._internalModel = internalModel; - this.type = internalModel.type; - this.modelName = internalModel.type.modelName; - - /** - A hash of adapter options - @property adapterOptions - @type {Object} - */ - this.adapterOptions = options.adapterOptions; - this.include = options.include; - - this._changedAttributes = record.changedAttributes(); -} - -Snapshot.prototype = { - constructor: Snapshot, - - /** - The id of the snapshot's underlying record - - Example - - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postSnapshot.id; // => '1' - ``` - - @property id - @type {String} - */ - id: null, - - /** - The underlying record for this snapshot. Can be used to access methods and - properties defined on the record. - - Example - - ```javascript - var json = snapshot.record.toJSON(); - ``` - - @property record - @type {DS.Model} - */ - record: null, - - /** - The type of the underlying record for this snapshot, as a DS.Model. - - @property type - @type {DS.Model} - */ - type: null, - - /** - The name of the type of the underlying record for this snapshot, as a string. - - @property modelName - @type {String} - */ - modelName: null, +export default class Snapshot { + constructor(internalModel, options = {}) { + this._attributes = new EmptyObject(); + this._belongsToRelationships = new EmptyObject(); + this._belongsToIds = new EmptyObject(); + this._hasManyRelationships = new EmptyObject(); + this._hasManyIds = new EmptyObject(); + this._internalModel = internalModel; + + let record = internalModel.getRecord(); + + /** + The underlying record for this snapshot. Can be used to access methods and + properties defined on the record. + + Example + + ```javascript + let json = snapshot.record.toJSON(); + ``` + + @property record + @type {DS.Model} + */ + this.record = record; + record.eachAttribute((keyName) => this._attributes[keyName] = get(record, keyName)); + + /** + The id of the snapshot's underlying record + + Example + + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postSnapshot.id; // => '1' + ``` + + @property id + @type {String} + */ + this.id = internalModel.id; + + /** + A hash of adapter options + @property adapterOptions + @type {Object} + */ + this.adapterOptions = options.adapterOptions; + this.include = options.include; + + /** + The type of the underlying record for this snapshot, as a DS.Model. + + @property type + @type {DS.Model} + */ + // TODO @runspired we should deprecate this in favor of modelClass but only once + // we've cleaned up the internals enough that a public change to follow suite is + // uncontroversial. + this.type = internalModel.modelClass; + + /** + The name of the type of the underlying record for this snapshot, as a string. + + @property modelName + @type {String} + */ + this.modelName = internalModel.modelName; + + this._changedAttributes = record.changedAttributes(); + } /** - Returns the value of an attribute. + Returns the value of an attribute. - Example + Example - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postSnapshot.attr('author'); // => 'Tomster' - postSnapshot.attr('title'); // => 'Ember.js rocks' - ``` + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postSnapshot.attr('author'); // => 'Tomster' + postSnapshot.attr('title'); // => 'Ember.js rocks' + ``` - Note: Values are loaded eagerly and cached when the snapshot is created. + Note: Values are loaded eagerly and cached when the snapshot is created. - @method attr - @param {String} keyName - @return {Object} The attribute value or undefined - */ + @method attr + @param {String} keyName + @return {Object} The attribute value or undefined + */ attr(keyName) { if (keyName in this._attributes) { return this._attributes[keyName]; } throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no attribute named '" + keyName + "' defined."); - }, + } /** - Returns all attributes and their corresponding values. + Returns all attributes and their corresponding values. - Example + Example - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postSnapshot.attributes(); // => { author: 'Tomster', title: 'Ember.js rocks' } - ``` + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postSnapshot.attributes(); // => { author: 'Tomster', title: 'Ember.js rocks' } + ``` - @method attributes - @return {Object} All attributes of the current snapshot - */ + @method attributes + @return {Object} All attributes of the current snapshot + */ attributes() { return Ember.copy(this._attributes); - }, + } /** - Returns all changed attributes and their old and new values. + Returns all changed attributes and their old and new values. - Example + Example - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postModel.set('title', 'Ember.js rocks!'); - postSnapshot.changedAttributes(); // => { title: ['Ember.js rocks', 'Ember.js rocks!'] } - ``` + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postModel.set('title', 'Ember.js rocks!'); + postSnapshot.changedAttributes(); // => { title: ['Ember.js rocks', 'Ember.js rocks!'] } + ``` - @method changedAttributes - @return {Object} All changed attributes of the current snapshot - */ + @method changedAttributes + @return {Object} All changed attributes of the current snapshot + */ changedAttributes() { let changedAttributes = new EmptyObject(); let changedAttributeKeys = Object.keys(this._changedAttributes); @@ -155,47 +153,47 @@ Snapshot.prototype = { } return changedAttributes; - }, + } /** - Returns the current value of a belongsTo relationship. + Returns the current value of a belongsTo relationship. - `belongsTo` takes an optional hash of options as a second parameter, - currently supported options are: + `belongsTo` takes an optional hash of options as a second parameter, + currently supported options are: - `id`: set to `true` if you only want the ID of the related record to be - returned. + returned. - Example + Example - ```javascript - // store.push('post', { id: 1, title: 'Hello World' }); - // store.createRecord('comment', { body: 'Lorem ipsum', post: post }); - commentSnapshot.belongsTo('post'); // => DS.Snapshot - commentSnapshot.belongsTo('post', { id: true }); // => '1' + ```javascript + // store.push('post', { id: 1, title: 'Hello World' }); + // store.createRecord('comment', { body: 'Lorem ipsum', post: post }); + commentSnapshot.belongsTo('post'); // => DS.Snapshot + commentSnapshot.belongsTo('post', { id: true }); // => '1' - // store.push('comment', { id: 1, body: 'Lorem ipsum' }); - commentSnapshot.belongsTo('post'); // => undefined - ``` + // store.push('comment', { id: 1, body: 'Lorem ipsum' }); + commentSnapshot.belongsTo('post'); // => undefined + ``` - Calling `belongsTo` will return a new Snapshot as long as there's any known - data for the relationship available, such as an ID. If the relationship is - known but unset, `belongsTo` will return `null`. If the contents of the - relationship is unknown `belongsTo` will return `undefined`. + Calling `belongsTo` will return a new Snapshot as long as there's any known + data for the relationship available, such as an ID. If the relationship is + known but unset, `belongsTo` will return `null`. If the contents of the + relationship is unknown `belongsTo` will return `undefined`. - Note: Relationships are loaded lazily and cached upon first access. + Note: Relationships are loaded lazily and cached upon first access. - @method belongsTo - @param {String} keyName - @param {Object} [options] - @return {(DS.Snapshot|String|null|undefined)} A snapshot or ID of a known - relationship or null if the relationship is known but unset. undefined - will be returned if the contents of the relationship is unknown. - */ + @method belongsTo + @param {String} keyName + @param {Object} [options] + @return {(DS.Snapshot|String|null|undefined)} A snapshot or ID of a known + relationship or null if the relationship is known but unset. undefined + will be returned if the contents of the relationship is unknown. + */ belongsTo(keyName, options) { - var id = options && options.id; - var relationship, inverseRecord, hasData; - var result; + let id = options && options.id; + let relationship, inverseRecord, hasData; + let result; if (id && keyName in this._belongsToIds) { return this._belongsToIds[keyName]; @@ -232,41 +230,41 @@ Snapshot.prototype = { } return result; - }, + } /** - Returns the current value of a hasMany relationship. + Returns the current value of a hasMany relationship. - `hasMany` takes an optional hash of options as a second parameter, - currently supported options are: + `hasMany` takes an optional hash of options as a second parameter, + currently supported options are: - `ids`: set to `true` if you only want the IDs of the related records to be - returned. + returned. - Example + Example - ```javascript - // store.push('post', { id: 1, title: 'Hello World', comments: [2, 3] }); - postSnapshot.hasMany('comments'); // => [DS.Snapshot, DS.Snapshot] - postSnapshot.hasMany('comments', { ids: true }); // => ['2', '3'] + ```javascript + // store.push('post', { id: 1, title: 'Hello World', comments: [2, 3] }); + postSnapshot.hasMany('comments'); // => [DS.Snapshot, DS.Snapshot] + postSnapshot.hasMany('comments', { ids: true }); // => ['2', '3'] - // store.push('post', { id: 1, title: 'Hello World' }); - postSnapshot.hasMany('comments'); // => undefined - ``` + // store.push('post', { id: 1, title: 'Hello World' }); + postSnapshot.hasMany('comments'); // => undefined + ``` - Note: Relationships are loaded lazily and cached upon first access. + Note: Relationships are loaded lazily and cached upon first access. - @method hasMany - @param {String} keyName - @param {Object} [options] - @return {(Array|undefined)} An array of snapshots or IDs of a known - relationship or an empty array if the relationship is known but unset. - undefined will be returned if the contents of the relationship is unknown. - */ + @method hasMany + @param {String} keyName + @param {Object} [options] + @return {(Array|undefined)} An array of snapshots or IDs of a known + relationship or an empty array if the relationship is known but unset. + undefined will be returned if the contents of the relationship is unknown. + */ hasMany(keyName, options) { - var ids = options && options.ids; - var relationship, members, hasData; - var results; + let ids = options && options.ids; + let relationship, members, hasData; + let results; if (ids && keyName in this._hasManyIds) { return this._hasManyIds[keyName]; @@ -304,7 +302,7 @@ Snapshot.prototype = { } return results; - }, + } /** Iterates through all the attributes of the model, calling the passed @@ -324,7 +322,7 @@ Snapshot.prototype = { */ eachAttribute(callback, binding) { this.record.eachAttribute(callback, binding); - }, + } /** Iterates through all the relationships of the model, calling the passed @@ -344,7 +342,7 @@ Snapshot.prototype = { */ eachRelationship(callback, binding) { this.record.eachRelationship(callback, binding); - }, + } /** @method serialize @@ -354,4 +352,4 @@ Snapshot.prototype = { serialize(options) { return this.record.store.serializerFor(this.modelName).serialize(this, options); } -}; +} From 20c41944594678422ad36855b2c3e134dae00af1 Mon Sep 17 00:00:00 2001 From: pete_the_pete Date: Tue, 13 Dec 2016 21:55:19 -0800 Subject: [PATCH 1757/2527] Updating Contributing to use ember-twiddle --- CONTRIBUTING.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 73da5c282c3..03a3fe6c559 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,13 +25,13 @@ this bug already. 3. Provide JSFiddle or JSBin demo that specifically shows the problem. This demo should be fully operational with the exception of the bug you want to -demonstrate. The more pared down, the better. A preconfigured [JSBin (RESTAdapter)][rest] | [JSBIN (JSONAPIAdapter)][json-api] | -[JSFiddle][2] with mocked requests is available. +demonstrate. The more pared down, the better. A preconfigured [EmberTwiddle (RESTAdapter)][rest] | [EmberTwiddle (JSONAPIAdapter)][json-api] | +[EmberTwiddle][2] with mocked requests is available. -[rest]: http://emberjs.jsbin.com/nunico/1/edit?html,js,output -[json-api]: http://emberjs.jsbin.com/sarobu/1/edit?html,js,output -[2]: http://jsfiddle.net/842xesgc/ +[rest]: https://ember-twiddle.com/aa257da01fe4fde3c1a502538e2e4902/copy +[json-api]: https://ember-twiddle.com/c0beed7d3c0bed65ac8ed018dcc57894/copy +[2]: https://ember-twiddle.com/0e1a24aabb8fa7c1fdd8/copy?fileTreeShown=false&numColumns=2&openFiles=routes.application.js%2Ctemplates.application.hbs 4. If possible, submit a Pull Request with a failing test. Better yet, take a stab at fixing the bug yourself if you can! From 29639343b781a289ba6055001c511603adfe8202 Mon Sep 17 00:00:00 2001 From: Michael Josephson Date: Tue, 3 Jan 2017 17:29:26 +0000 Subject: [PATCH 1758/2527] [DOC] fix a couple of typos in model class docs --- addon/-private/system/model/model.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 4a0ba389e5f..cecaf6ed9d0 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -508,7 +508,7 @@ const Model = Ember.Object.extend(Ember.Evented, { Marks the record as deleted but does not save it. You must call `save` afterwards if you want to persist it. You might use this method if you want to allow the user to still `rollbackAttributes()` - after a delete it was made. + after a delete was made. Example @@ -557,7 +557,7 @@ const Model = Ember.Object.extend(Ember.Evented, { ``` If you pass an object on the `adapterOptions` property of the options - argument it will be passed to you adapter via the snapshot + argument it will be passed to your adapter via the snapshot ```js record.destroyRecord({ adapterOptions: { subscribe: false } }); From 746d74dbb871f4eb5fddf3617c49f8c8ec412d13 Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 6 Jan 2017 13:52:28 +0100 Subject: [PATCH 1759/2527] Removed id in urlForFindAll signature --- addon/-private/adapters/build-url-mixin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index 6fa1315c1e5..8e3f48d973d 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -143,7 +143,7 @@ export default Ember.Mixin.create({ import DS from 'ember-data'; export default DS.JSONAPIAdapter.extend({ - urlForFindAll(id, modelName, snapshot) { + urlForFindAll(modelName, snapshot) { return 'data/comments.json'; } }); From 21c77a12aa00f9c5f6ccd2f7a2ec2bdce8a0610f Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Sun, 8 Jan 2017 22:22:01 +0000 Subject: [PATCH 1760/2527] Fixes failing JSONSerializer test due to Ember.K deprecation --- tests/integration/serializers/json-serializer-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 66e547b7e60..b975ba79e1a 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -279,7 +279,7 @@ test("shouldSerializeHasMany", function(assert) { if (isEnabled("ds-check-should-serialize-relationships")) { testInDebug("_shouldSerializeHasMany deprecation", function(assert) { - env.store.serializerFor("post")._shouldSerializeHasMany = Ember.K; + env.store.serializerFor("post")._shouldSerializeHasMany = function() {}; assert.expectDeprecation(function() { env.store.serializerFor("post").shouldSerializeHasMany(); From 7115c218128ff758f93b62898f96ff80136d0786 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 9 Jan 2017 16:11:57 -0500 Subject: [PATCH 1761/2527] Add 2.11.0 to the changelog --- CHANGELOG.md | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a1fe84af84..82ccda8a940 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,67 @@ ### Master +### Release 2.11.0 (January 9, 2016) +- [#4518](https://github.com/emberjs/data/pull/4518) Update the relationship docs to remove some references to a globals s… +- [#4581](https://github.com/emberjs/data/pull/4581) [DOC] Update descriptions of findRecord() and findAll() +- [#4438](https://github.com/emberjs/data/pull/4438) add `relationship` property to findHasMany RESTAdapter docs +- [#4283](https://github.com/emberjs/data/pull/4283) Add better error messaging for adapters that do not implement createR… +- [#4440](https://github.com/emberjs/data/pull/4440) Add examples to the Serializer API docs +- [#4272](https://github.com/emberjs/data/pull/4272) [BUGFIX beta] Don't unnecessarily materialize records +- [#4562](https://github.com/emberjs/data/pull/4562) [PERF] make internal model lazier +- [#4601](https://github.com/emberjs/data/pull/4601) Naming cleanup +- [#4586](https://github.com/emberjs/data/pull/4586) Remove the ds-boolean-transform-allow-null feature flag +- [#4582](https://github.com/emberjs/data/pull/4582) tidy up integration/filter-test +- [#4585](https://github.com/emberjs/data/pull/4585) Update changelog for the Ember Data 2.9.0 release +- [#4632](https://github.com/emberjs/data/pull/4632) [DOC ds-extended-errors] Add docs for extended errors +- [#4592](https://github.com/emberjs/data/pull/4592) [DOC] Add documentation for query#update() to refresh query +- [#4591](https://github.com/emberjs/data/pull/4591) Cleanup record array manager +- [#4587](https://github.com/emberjs/data/pull/4587) Remove ds-links-in-record-array feature flag +- [#4590](https://github.com/emberjs/data/pull/4590) Fix YUIDoc warnings +- [#4589](https://github.com/emberjs/data/pull/4589) Feat/improved cache +- [#4640](https://github.com/emberjs/data/pull/4640) build ember-data attribute debug info dynamically +- [#4606](https://github.com/emberjs/data/pull/4606) fix(instrumentation): heimdall-query needed bumped to work properly +- [#4599](https://github.com/emberjs/data/pull/4599) Don't warn for 'async: false' relationships with link + data +- [#4594](https://github.com/emberjs/data/pull/4594) Revert "unloadRecord does not remove observers" +- [#4605](https://github.com/emberjs/data/pull/4605) Don't notify belongsTo changes if nothing changed +- [#4597](https://github.com/emberjs/data/pull/4597) Cleanup record array manager +- [#4598](https://github.com/emberjs/data/pull/4598) fix integration/record-array-test setup +- [#4600](https://github.com/emberjs/data/pull/4600) make DS.ManyArray lazy +- [#4603](https://github.com/emberjs/data/pull/4603) [WARNING] Warn when extending JSONAPISerializer with extractMeta +- [#4604](https://github.com/emberjs/data/pull/4604) Warn when findRecord returns a different id than the one requested +- [#4659](https://github.com/emberjs/data/pull/4659) Document the relationship serialized format in the RESTAdapter +- [#4624](https://github.com/emberjs/data/pull/4624) Test assertions when updateRecord & deleteRecord don't exist on adapter +- [#4612](https://github.com/emberjs/data/pull/4612) [DOC] Mark `errorsHashToArray` and `errorsArrayToHash` public +- [#4620](https://github.com/emberjs/data/pull/4620) [FEATURE ds-serialize-id] add serializeId to json-serializer +- [#4613](https://github.com/emberjs/data/pull/4613) Assert that InternalModel is indeed not materialized on store._push +- [#4616](https://github.com/emberjs/data/pull/4616) Assert when original and not normalized key is found in payload +- [#4621](https://github.com/emberjs/data/pull/4621) tidy-up integration/filter-test +- [#4617](https://github.com/emberjs/data/pull/4617) chore(store): cleans up and optimizes code paths around fetching rela… +- [#4607](https://github.com/emberjs/data/pull/4607) Fix dummy app serializer +- [#4609](https://github.com/emberjs/data/pull/4609) [DOC] Improve warning for mismatched id in store.findRecord +- [#4614](https://github.com/emberjs/data/pull/4614) [DOC] Minor changes to addon/serializer.js +- [#4671](https://github.com/emberjs/data/pull/4671) Fix typo in delete-record-test +- [#4645](https://github.com/emberjs/data/pull/4645) cleanup system/many-array +- [#4636](https://github.com/emberjs/data/pull/4636) Add a missing example to the ManyArray api docs +- [#4630](https://github.com/emberjs/data/pull/4630) Updates json-api-mock-server +- [#4644](https://github.com/emberjs/data/pull/4644) [PERF] HasMany doesn't need to inform RecordArrayManager +- [#4629](https://github.com/emberjs/data/pull/4629) [DOC] #4595 revise unloadAll description +- [#4641](https://github.com/emberjs/data/pull/4641) Add API docs for the RecordReference +- [#4639](https://github.com/emberjs/data/pull/4639) Update API docs for BelongsToReference +- [#4643](https://github.com/emberjs/data/pull/4643) [BUGFIX #4649 #4648] +- [#4637](https://github.com/emberjs/data/pull/4637) Simplify Adapter#serialize by using snapshot.serialize() since they d… +- [#4661](https://github.com/emberjs/data/pull/4661) dirty check to prevent liveRecordArrays being rebuilt too often +- [#4665](https://github.com/emberjs/data/pull/4665) Deprecate store.recordIsLoaded +- [#4654](https://github.com/emberjs/data/pull/4654) remove useless private api +- [#4653](https://github.com/emberjs/data/pull/4653) Update the API docs on the JSONAPISerializer +- [#4652](https://github.com/emberjs/data/pull/4652) Improve the API docs for the JSONAPI adapter +- [#4662](https://github.com/emberjs/data/pull/4662) Code Cleanup for store.js +- [#4651](https://github.com/emberjs/data/pull/4651) Add some minor updates to the store documentation +- [#4658](https://github.com/emberjs/data/pull/4658) Test for hasMany array removal on deletion +- [#4669](https://github.com/emberjs/data/pull/4669) fix mock server +- [#4674](https://github.com/emberjs/data/pull/4674) Update `findHasMany` API docs +- [#4680](https://github.com/emberjs/data/pull/4680) Remove unused helper function `normalizeAttributes` + ### Release 2.10.0 (November 28, 2016) - [#4656](https://github.com/emberjs/data/pull/4656) [PERF backport to beta] fix sub-optimal compiler output ([#4655](https://github.com/emberjs/data/pull/4655)) - [#4592](https://github.com/emberjs/data/pull/4592) [DOC] Add documentation for query#update() to refresh query From a3b1a16a64c34120a2d8ffd5886c6c456bba3f74 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 9 Jan 2017 16:12:35 -0500 Subject: [PATCH 1762/2527] Bump canary version to 2.13.0-canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4488091a58d..cf3bfac0c3f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.12.0-canary", + "version": "2.13.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From de618999a9f708b5130f2761d6adaae9ede7d33b Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 9 Jan 2017 16:37:58 -0500 Subject: [PATCH 1763/2527] Clean up some YUIdoc erros --- addon/-private/system/record-arrays/record-array.js | 8 ++++---- addon/-private/system/references/record.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index b4a1e5013ef..66182beeac7 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -233,8 +233,8 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { this._super(...arguments); }, - /** -r @method _createSnapshot + /* + @method _createSnapshot @private */ _createSnapshot(options) { @@ -242,8 +242,8 @@ r @method _createSnapshot return new SnapshotRecordArray(this, this.get('meta'), options); }, - /** -r @method _takeSnapshot + /* + @method _takeSnapshot @private */ _takeSnapshot() { diff --git a/addon/-private/system/references/record.js b/addon/-private/system/references/record.js index 0e0104ea628..0e186104223 100644 --- a/addon/-private/system/references/record.js +++ b/addon/-private/system/references/record.js @@ -85,9 +85,9 @@ RecordReference.prototype.remoteType = function() { }); ``` - @method + @method push @param {Promise|Object} - @returns Promise a promise for the value (record or relationship) + @return Promise a promise for the value (record or relationship) */ RecordReference.prototype.push = function(objectOrPromise) { return Ember.RSVP.resolve(objectOrPromise).then((data) => { From c2abcb1828e4e682e6e4715b2ddd45c935b7d31d Mon Sep 17 00:00:00 2001 From: Olle Jonsson Date: Wed, 11 Jan 2017 17:59:56 +0100 Subject: [PATCH 1764/2527] License: 2017 --- generators/license.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/license.js b/generators/license.js index ba16857cda3..89cb817a845 100644 --- a/generators/license.js +++ b/generators/license.js @@ -1,6 +1,6 @@ /*! * @overview Ember Data - * @copyright Copyright 2011-2016 Tilde Inc. and contributors. + * @copyright Copyright 2011-2017 Tilde Inc. and contributors. * Portions Copyright 2011 LivingSocial Inc. * @license Licensed under MIT license (see license.js) * @version VERSION_STRING_PLACEHOLDER From 7ef8273c68d71ca20fda0a5c2c17aa1fd09a747b Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Tue, 10 Jan 2017 17:08:33 +0000 Subject: [PATCH 1765/2527] Fixes _lookupFactory deprecation for Ember canary --- addon/-private/system/store.js | 26 ++++++++++++++++++++++--- addon/-private/utils.js | 2 +- tests/integration/debug-adapter-test.js | 10 +++++++++- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 183074fc184..3436baa7b89 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2033,8 +2033,15 @@ Store = Service.extend({ // container._registry = 1.11 - 2.0 // container = < 1.11 let owner = getOwner(this); + let mixin; + + if (owner.factoryFor) { + let MaybeMixin = owner.factoryFor(`mixin:${normalizedModelName}`); + mixin = MaybeMixin && MaybeMixin.class; + } else { + mixin = owner._lookupFactory(`mixin:${normalizedModelName}`); + } - let mixin = owner._lookupFactory('mixin:' + normalizedModelName); if (mixin) { //Cache the class as a model owner.register('model:' + normalizedModelName, Model.extend(mixin)); @@ -2107,7 +2114,14 @@ Store = Service.extend({ let trueModelName = this._classKeyFor(modelName); let owner = getOwner(this); - return owner._lookupFactory(`model:${trueModelName}`); + if (owner.factoryFor) { + let MaybeModel = owner.factoryFor(`model:${trueModelName}`); + let MaybeModelFactory = MaybeModel && MaybeModel.class; + + return MaybeModelFactory; + } else { + return owner._lookupFactory(`model:${trueModelName}`); + } }, /** @@ -2326,7 +2340,13 @@ Store = Service.extend({ }, _hasModelFor(modelName) { - return !!getOwner(this)._lookupFactory(`model:${modelName}`); + let owner = getOwner(this); + + if (owner.factoryFor) { + return !!owner.factoryFor(`model:${modelName}`); + } else { + return !!owner._lookupFactory(`model:${modelName}`); + } }, _pushInternalModel(data) { diff --git a/addon/-private/utils.js b/addon/-private/utils.js index c19332bc8cd..e3d6e51985c 100644 --- a/addon/-private/utils.js +++ b/addon/-private/utils.js @@ -16,7 +16,7 @@ function modelHasAttributeOrRelationshipNamedType(modelClass) { ember-container-inject-owner is a new feature in Ember 2.3 that finally provides a public API for looking items up. This function serves as a super simple polyfill to avoid triggering deprecations. -*/ + */ function getOwner(context) { var owner; diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index c152247f3b4..c7c4302bd6f 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -33,9 +33,17 @@ module("DS.DebugAdapter", { store = App.__container__.lookup('service:store'); debugAdapter = App.__container__.lookup('data-adapter:main'); + let klass; + + if (App.__container__.factoryFor) { + klass = App.__container__.factoryFor('model:post').class; + } else { + klass = App.__container__.lookupFactory('model:post'); + } + debugAdapter.reopen({ getModelTypes() { - return Ember.A([{ klass: App.__container__.lookupFactory('model:post'), name: 'post' }]); + return Ember.A([{ klass, name: 'post' }]); } }); }, From bb3328d20610774a8ed878f1d1b65d702b862124 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Thu, 12 Jan 2017 17:32:31 +0000 Subject: [PATCH 1766/2527] Updates code sample to match Guides https://github.com/emberjs/guides/pull/1770 --- addon/adapters/rest.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 8794cd40104..d8c8b560b5c 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -124,8 +124,8 @@ const Promise = Ember.RSVP.Promise; { "people": { "id": 5, - "firstName": "Barack", - "lastName": "Obama", + "firstName": "Zaphod", + "lastName": "Beetlebrox", "occupation": "President" } } From d93b536091902db163d16159a487177950f71ed7 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Thu, 12 Jan 2017 20:39:49 +0000 Subject: [PATCH 1767/2527] Update rest.js --- addon/adapters/rest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index d8c8b560b5c..b6a4e867b7f 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -125,7 +125,7 @@ const Promise = Ember.RSVP.Promise; "people": { "id": 5, "firstName": "Zaphod", - "lastName": "Beetlebrox", + "lastName": "Beeblebrox", "occupation": "President" } } From 06dbc97970dcb6ba57e7072edc807bbe28cb9241 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 12 Jan 2017 18:41:34 -0800 Subject: [PATCH 1768/2527] Simplify Backburner Usage (#4723) * simplify backburner * minor tweaks * fix test * small cleanup --- addon/-private/system/model/internal-model.js | 29 +++---- addon/-private/system/model/states.js | 2 +- addon/-private/system/record-array-manager.js | 56 +++++++++---- .../system/relationships/state/create.js | 15 ++-- .../system/relationships/state/has-many.js | 22 ++---- .../relationships/state/relationship.js | 14 ++-- addon/-private/system/store.js | 78 ++++++++++++------- tests/dummy/app/routes/query/route.js | 2 + tests/unit/store/push-test.js | 27 ++++--- 9 files changed, 144 insertions(+), 101 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 8e861cc5673..df96f1868ea 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -24,7 +24,6 @@ const { inspect, isEmpty, isEqual, - run: emberRun, setOwner, RSVP, RSVP: { Promise } @@ -122,6 +121,7 @@ export default class InternalModel { this._isDestroyed = false; this.isError = false; this.error = null; + this._isUpdatingRecordArrays = false; // caches for lazy getters this._modelClass = null; @@ -376,7 +376,7 @@ export default class InternalModel { } becameReady() { - emberRun.schedule('actions', this.store.recordArrayManager, this.store.recordArrayManager.recordWasLoaded, this); + this.store.recordArrayManager.recordWasLoaded(this); } didInitializeData() { @@ -521,7 +521,7 @@ export default class InternalModel { */ adapterDidDirty() { this.send('becomeDirty'); - this.updateRecordArraysLater(); + this.updateRecordArrays(); } /* @@ -654,7 +654,7 @@ export default class InternalModel { setups[i].setup(this); } - this.updateRecordArraysLater(); + this.updateRecordArrays(); } _unhandledEvent(state, name, context) { @@ -673,7 +673,8 @@ export default class InternalModel { if (this._deferredTriggers.push(args) !== 1) { return; } - emberRun.schedule('actions', this, this._triggerDeferredTriggers); + + this.store._updateInternalModel(this); } _triggerDeferredTriggers() { @@ -784,8 +785,9 @@ export default class InternalModel { @private */ updateRecordArrays() { - this._updatingRecordArraysLater = false; - this.store._dataWasUpdated(this); + if (this._isUpdatingRecordArrays) { return; } + this._isUpdatingRecordArrays = true; + this.store.recordArrayManager.recordDidChange(this); } setId(id) { @@ -843,24 +845,13 @@ export default class InternalModel { this._inFlightAttributes = new EmptyObject(); this.send('didCommit'); - this.updateRecordArraysLater(); + this.updateRecordArrays(); if (!data) { return; } this.record._notifyProperties(changedKeys); } - /* - @method updateRecordArraysLater - @private - */ - updateRecordArraysLater() { - // quick hack (something like this could be pushed into run.once - if (this._updatingRecordArraysLater) { return; } - this._updatingRecordArraysLater = true; - emberRun.schedule('actions', this, this.updateRecordArrays); - } - addErrorMessageToAttribute(attribute, message) { get(this.getRecord(), 'errors')._add(attribute, message); } diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index aebb9851384..ae542b53897 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -180,7 +180,7 @@ function didSetProperty(internalModel, context) { internalModel.send('becomeDirty'); } - internalModel.updateRecordArraysLater(); + internalModel.updateRecordArrays(); } // Implementation notes: diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 15259223d41..b80759d7993 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -21,6 +21,7 @@ const { _addRecordToRecordArray, _recordWasChanged, _recordWasDeleted, + _flushLoadedRecords, array_flatten, array_remove, create, @@ -41,6 +42,7 @@ const { '_addInternalModelToRecordArray', '_recordWasChanged', '_recordWasDeleted', + '_flushLoadedRecords', 'array_fatten', 'array_remove', 'create', @@ -80,12 +82,13 @@ export default Ember.Object.extend({ }); this.changedRecords = []; + this.loadedRecords = []; this._adapterPopulatedRecordArrays = []; }, - recordDidChange(record) { + recordDidChange(internalModel) { heimdall.increment(recordDidChange); - if (this.changedRecords.push(record) !== 1) { return; } + if (this.changedRecords.push(internalModel) !== 1) { return; } emberRun.schedule('actions', this, this.updateRecordArrays); }, @@ -108,17 +111,22 @@ export default Ember.Object.extend({ */ updateRecordArrays() { heimdall.increment(updateRecordArrays); - this.changedRecords.forEach(internalModel => { + let updated = this.changedRecords; + + for (let i = 0, l = updated.length; i < l; i++) { + let internalModel = updated[i]; if (internalModel.isDestroyed || - internalModel.currentState.stateName === 'root.deleted.saved') { + internalModel.currentState.stateName === 'root.deleted.saved') { this._recordWasDeleted(internalModel); } else { this._recordWasChanged(internalModel); } - }); - this.changedRecords.length = 0; + internalModel._isUpdatingRecordArrays = false; + } + + updated.length = 0; }, _recordWasDeleted(internalModel) { @@ -146,19 +154,35 @@ export default Ember.Object.extend({ //Need to update live arrays on loading recordWasLoaded(internalModel) { heimdall.increment(recordWasLoaded); - let modelName = internalModel.modelName; - let recordArrays = this.filteredRecordArrays.get(modelName); - let filter; + if (this.loadedRecords.push(internalModel) !== 1) { return; } - recordArrays.forEach(array => { - filter = get(array, 'filterFunction'); - this.updateFilterRecordArray(array, filter, modelName, internalModel); - }); + emberRun.schedule('actions', this, this._flushLoadedRecords); + }, + + _flushLoadedRecords() { + heimdall.increment(_flushLoadedRecords); + let internalModels = this.loadedRecords; + + for (let i = 0, l = internalModels.length; i < l; i++) { + let internalModel = internalModels[i]; + let modelName = internalModel.modelName; + + let recordArrays = this.filteredRecordArrays.get(modelName); + let filter; - if (this.liveRecordArrays.has(modelName)) { - let liveRecordArray = this.liveRecordArrays.get(modelName); - this._addInternalModelToRecordArray(liveRecordArray, internalModel); + for (let j = 0, rL = recordArrays.length; j < rL; j++) { + let array = recordArrays[j]; + filter = get(array, 'filterFunction'); + this.updateFilterRecordArray(array, filter, modelName, internalModel); + } + + if (this.liveRecordArrays.has(modelName)) { + let liveRecordArray = this.liveRecordArrays.get(modelName); + this._addInternalModelToRecordArray(liveRecordArray, internalModel); + } } + + this.loadedRecords.length = 0; }, /** diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index 53b55c6b9f4..b98e6f3f30b 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -51,13 +51,18 @@ export default class Relationships { get(key) { let relationships = this.initializedRelationships; - let internalModel = this.internalModel; - let relationshipsByName = get(internalModel.type, 'relationshipsByName'); + let relationship = relationships[key]; - if (!relationships[key] && relationshipsByName.get(key)) { - relationships[key] = createRelationshipFor(internalModel, relationshipsByName.get(key), internalModel.store); + if (!relationship) { + let internalModel = this.internalModel; + let relationshipsByName = get(internalModel.type, 'relationshipsByName'); + let rel = relationshipsByName.get(key); + + if (rel) { + relationship = relationships[key] = createRelationshipFor(internalModel, rel, internalModel.store); + } } - return relationships[key]; + return relationship; } } diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 881552024dd..7bfd7aaff89 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -127,30 +127,20 @@ export default class ManyRelationship extends Relationship { } computeChanges(records) { - var members = this.canonicalMembers; - var recordsToRemove = []; - var length; - var record; - var i; - - records = setForArray(records); + let members = this.canonicalMembers; + let recordsToRemove = []; + let recordSet = setForArray(records); members.forEach(function(member) { - if (records.has(member)) { return; } + if (recordSet.has(member)) { return; } recordsToRemove.push(member); }); this.removeCanonicalRecords(recordsToRemove); - // Using records.toArray() since currently using - // removeRecord can modify length, messing stuff up - // forEach since it directly looks at "length" each - // iteration - records = records.toArray(); - length = records.length; - for (i = 0; i < length; i++) { - record = records[i]; + for (let i = 0, l = records.length; i < l; i++) { + let record = records[i]; this.removeCanonicalRecord(record); this.addCanonicalRecord(record, i); } diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index e361526bc9d..eb7fc9b5c34 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -183,7 +183,7 @@ export default class Relationship { } record._implicitRelationships[this.inverseKeyForImplicit].addRecord(this.record); } - this.record.updateRecordArraysLater(); + this.record.updateRecordArrays(); } this.setHasData(true); } @@ -235,18 +235,20 @@ export default class Relationship { flushCanonical() { heimdall.increment(flushCanonical); + let list = this.members.list; this.willSync = false; //a hack for not removing new records //TODO remove once we have proper diffing var newRecords = []; - for (var i = 0; i < this.members.list.length; i++) { - if (this.members.list[i].isNew()) { - newRecords.push(this.members.list[i]); + for (let i = 0; i < list.length; i++) { + if (list[i].isNew()) { + newRecords.push(list[i]); } } + //TODO(Igor) make this less abysmally slow this.members = this.canonicalMembers.copy(); - for (i = 0; i < newRecords.length; i++) { + for (let i = 0; i < newRecords.length; i++) { this.members.add(newRecords[i]); } } @@ -257,7 +259,7 @@ export default class Relationship { return; } this.willSync = true; - this.store._backburner.join(() => this.store._backburner.schedule('syncRelationships', this, this.flushCanonical)); + this.store._updateRelationshipState(this); } updateLink(link) { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 3436baa7b89..945ef6ed36b 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -226,10 +226,13 @@ Store = Service.extend({ */ // used for coalescing record save requests this._pendingSave = []; + // used for coalescing relationship updates + this._updatedRelationships = []; // used for coalescing relationship setup needs this._pushedInternalModels = []; - // stores a reference to the flush for relationship setup - this._relationshipFlush = null; + // used for coalescing internal model updates + this._updatedInternalModels = []; + // used to keep track of all the find requests that need to be coalesced this._pendingFetch = MapWithDefault.create({ defaultValue() { return []; } }); @@ -1789,23 +1792,6 @@ Store = Service.extend({ return this.hasRecordForId(modelName, id); }, - // ............ - // . UPDATING . - // ............ - - /** - If the adapter updates attributes the record will notify - the store to update its membership in any filters. - To avoid thrashing, this method is invoked only once per - run loop per record. - - @method _dataWasUpdated - @private - @param {InternalModel} internalModel - */ - _dataWasUpdated(internalModel) { - this.recordArrayManager.recordDidChange(internalModel); - }, // .............. // . PERSISTING . @@ -2001,7 +1987,6 @@ Store = Service.extend({ heimdall.increment(_load); let internalModel = this._internalModelForId(data.type, data.id); - // TODO @runspired move this out of here internalModel.setupData(data); this.recordArrayManager.recordDidChange(internalModel); @@ -2387,17 +2372,17 @@ Store = Service.extend({ }, _setupRelationshipsForModel(internalModel, data) { - this._pushedInternalModels.push(internalModel, data); - if (this._relationshipFlush === null) { - this._relationshipFlush = this._backburner.schedule('normalizeRelationships', this, this._setupRelationships); + if (this._pushedInternalModels.push(internalModel, data) !== 2) { + return; } + + this._backburner.schedule('normalizeRelationships', this, this._setupRelationships); }, _setupRelationships() { heimdall.increment(_setupRelationships); + let setupToken = heimdall.start('store._setupRelationships'); let pushed = this._pushedInternalModels; - this._pushedInternalModels = []; - this._relationshipFlush = null; for (let i = 0, l = pushed.length; i < l; i += 2) { // This will convert relationships specified as IDs into DS.Model instances @@ -2407,6 +2392,9 @@ Store = Service.extend({ let data = pushed[i + 1]; setupRelationships(this, internalModel, data); } + + pushed.length = 0; + heimdall.stop(setupToken); }, /** @@ -2651,14 +2639,50 @@ Store = Service.extend({ willDestroy() { this._super(...arguments); this._pushedInternalModels = null; - this._backburner.cancel(this._relationshipFlush); - this._relationshipFlush = null; this.recordArrayManager.destroy(); this._instanceCache.destroy(); this.unloadAll(); }, + _updateRelationshipState(relationship) { + if (this._updatedRelationships.push(relationship) !== 1) { + return; + } + + this._backburner.join(() => { + this._backburner.schedule('syncRelationships', this, this._flushUpdatedRelationships); + }); + }, + + _flushUpdatedRelationships() { + let updated = this._updatedRelationships; + + for (let i = 0, l = updated.length; i < l; i++) { + updated[i].flushCanonical(); + } + + updated.length = 0; + }, + + _updateInternalModel(internalModel) { + if (this._updatedInternalModels.push(internalModel) !== 1) { + return; + } + + emberRun.schedule('actions', this, this._flushUpdatedInternalModels); + }, + + _flushUpdatedInternalModels() { + let updated = this._updatedInternalModels; + + for (let i = 0, l = updated.length; i < l; i++) { + updated[i]._triggerDeferredTriggers(); + } + + updated.length = 0; + }, + _pushResourceIdentifier(relationship, resourceIdentifier) { if (isNone(resourceIdentifier)) { return; diff --git a/tests/dummy/app/routes/query/route.js b/tests/dummy/app/routes/query/route.js index 2bbafccb4c7..c6db6f4f49d 100644 --- a/tests/dummy/app/routes/query/route.js +++ b/tests/dummy/app/routes/query/route.js @@ -24,6 +24,8 @@ export default Route.extend({ let modelName = params.modelName; delete params.modelName; + heimdall.enableTimelineFeatures(); + let token = heimdall.start('ember-data'); return this.get('store').query(modelName, params) .then((records) => { diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index 960959dce2e..040eadf2d4b 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -600,20 +600,25 @@ testInDebug('calling push with hasMany relationship the value must be an array', invalidValues.forEach(function(invalidValue) { assert.throws(function() { - run(function() { - store.push({ - data: { - type: 'person', - id: '1', - relationships: { - phoneNumbers: { - data: invalidValue + try { + run(function () { + store.push({ + data: { + type: 'person', + id: '1', + relationships: { + phoneNumbers: { + data: invalidValue + } } } - } + }); }); - }); - }, /must be an array/); + } catch (e) { + store._pushedInternalModels.length = 0; + throw e; + } + }, /must be an array/, `Expect that '${Ember.inspect(invalidValue)}' is not an array`); }); }); From 90d529342e0204a7ca01c8273dad0f0f4644bfa8 Mon Sep 17 00:00:00 2001 From: pete_the_pete Date: Tue, 27 Dec 2016 11:57:25 -0800 Subject: [PATCH 1769/2527] Linter changes for addon, addon/adapters and addon/serializers --- addon/adapters/json-api.js | 25 ++- addon/adapters/rest.js | 172 ++++++++++---------- addon/attr.js | 12 +- addon/serializers/embedded-records-mixin.js | 62 +++---- addon/serializers/json-api.js | 27 ++- addon/serializers/json.js | 71 ++++---- addon/serializers/rest.js | 50 +++--- 7 files changed, 209 insertions(+), 210 deletions(-) diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index 50605632301..9d0d6efccea 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -144,7 +144,7 @@ import { instrument, deprecate } from 'ember-data/-private/debug'; @namespace DS @extends DS.RESTAdapter */ -var JSONAPIAdapter = RESTAdapter.extend({ +const JSONAPIAdapter = RESTAdapter.extend({ defaultSerializer: '-json-api', /** @@ -250,13 +250,13 @@ var JSONAPIAdapter = RESTAdapter.extend({ if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { return this._super(...arguments); } else { - var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); + let url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); return this.ajax(url, 'GET', { data: { filter: { id: ids.join(',') } } }); } }, pathForType(modelName) { - var dasherized = Ember.String.dasherize(modelName); + let dasherized = Ember.String.dasherize(modelName); return Ember.String.pluralize(dasherized); }, @@ -265,13 +265,12 @@ var JSONAPIAdapter = RESTAdapter.extend({ if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { return this._super(...arguments); } else { - var data = {}; - var serializer = store.serializerFor(type.modelName); + let data = {}; + let serializer = store.serializerFor(type.modelName); serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); - var id = snapshot.id; - var url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); + let url = this.buildURL(type.modelName, snapshot.id, snapshot, 'updateRecord'); return this.ajax(url, 'PATCH', { data: data }); } @@ -311,7 +310,7 @@ if (isEnabled('ds-improved-ajax')) { }, dataForRequest(params) { - const { requestType, ids } = params; + let { requestType, ids } = params; if (requestType === 'findMany') { return { @@ -320,9 +319,9 @@ if (isEnabled('ds-improved-ajax')) { } if (requestType === 'updateRecord') { - const { store, type, snapshot } = params; - const data = {}; - const serializer = store.serializerFor(type.modelName); + let { store, type, snapshot } = params; + let data = {}; + let serializer = store.serializerFor(type.modelName); serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); @@ -333,7 +332,7 @@ if (isEnabled('ds-improved-ajax')) { }, headersForRequest() { - const headers = this._super(...arguments) || {}; + let headers = this._super(...arguments) || {}; headers['Accept'] = 'application/vnd.api+json'; @@ -341,7 +340,7 @@ if (isEnabled('ds-improved-ajax')) { }, _requestToJQueryAjaxHash() { - const hash = this._super(...arguments); + let hash = this._super(...arguments); if (hash.contentType) { hash.contentType = 'application/vnd.api+json'; diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index b6a4e867b7f..02146842dec 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -283,7 +283,7 @@ const Promise = Ember.RSVP.Promise; @extends DS.Adapter @uses DS.BuildURLMixin */ -var RESTAdapter = Adapter.extend(BuildURLMixin, { +const RESTAdapter = Adapter.extend(BuildURLMixin, { defaultSerializer: '-rest', /** @@ -312,10 +312,10 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { export default DS.RESTAdapter.extend({ sortQueryParams: function(params) { - var sortedKeys = Object.keys(params).sort().reverse(); - var len = sortedKeys.length, newParams = {}; + let sortedKeys = Object.keys(params).sort().reverse(); + let len = sortedKeys.length, newParams = {}; - for (var i = 0; i < len; i++) { + for (let i = 0; i < len; i++) { newParams[sortedKeys[i]] = params[sortedKeys[i]]; } return newParams; @@ -328,15 +328,15 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Object} */ sortQueryParams(obj) { - var keys = Object.keys(obj); - var len = keys.length; + let keys = Object.keys(obj); + let len = keys.length; if (len < 2) { return obj; } - var newQueryParams = {}; - var sortedKeys = keys.sort(); + let newQueryParams = {}; + let sortedKeys = keys.sort(); - for (var i = 0; i < len; i++) { + for (let i = 0; i < len; i++) { newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]]; } return newQueryParams; @@ -467,15 +467,15 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { */ findRecord(store, type, id, snapshot) { if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - const request = this._requestFor({ + let request = this._requestFor({ store, type, id, snapshot, requestType: 'findRecord' }); return this._makeRequest(request); } else { - const url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); - const query = this.buildQuery(snapshot); + let url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); + let query = this.buildQuery(snapshot); return this.ajax(url, 'GET', { data: query }); } @@ -496,10 +496,10 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findAll(store, type, sinceToken, snapshotRecordArray) { - const query = this.buildQuery(snapshotRecordArray); + let query = this.buildQuery(snapshotRecordArray); if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - const request = this._requestFor({ + let request = this._requestFor({ store, type, sinceToken, query, snapshots: snapshotRecordArray, requestType: 'findAll' @@ -507,7 +507,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { return this._makeRequest(request); } else { - const url = this.buildURL(type.modelName, null, snapshotRecordArray, 'findAll'); + let url = this.buildURL(type.modelName, null, snapshotRecordArray, 'findAll'); if (sinceToken) { query.since = sinceToken; @@ -536,14 +536,14 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { */ query(store, type, query) { if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - const request = this._requestFor({ + let request = this._requestFor({ store, type, query, requestType: 'query' }); return this._makeRequest(request); } else { - var url = this.buildURL(type.modelName, null, null, 'query', query); + let url = this.buildURL(type.modelName, null, null, 'query', query); if (this.sortQueryParams) { query = this.sortQueryParams(query); @@ -573,14 +573,14 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { */ queryRecord(store, type, query) { if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - const request = this._requestFor({ + let request = this._requestFor({ store, type, query, requestType: 'queryRecord' }); return this._makeRequest(request); } else { - var url = this.buildURL(type.modelName, null, null, 'queryRecord', query); + let url = this.buildURL(type.modelName, null, null, 'queryRecord', query); if (this.sortQueryParams) { query = this.sortQueryParams(query); @@ -625,14 +625,14 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { */ findMany(store, type, ids, snapshots) { if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - const request = this._requestFor({ + let request = this._requestFor({ store, type, ids, snapshots, requestType: 'findMany' }); return this._makeRequest(request); } else { - var url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); + let url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); return this.ajax(url, 'GET', { data: { ids: ids } }); } }, @@ -675,15 +675,15 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { */ findHasMany(store, snapshot, url, relationship) { if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - const request = this._requestFor({ + let request = this._requestFor({ store, snapshot, url, relationship, requestType: 'findHasMany' }); return this._makeRequest(request); } else { - var id = snapshot.id; - var type = snapshot.modelName; + let id = snapshot.id; + let type = snapshot.modelName; url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findHasMany')); @@ -728,15 +728,15 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { */ findBelongsTo(store, snapshot, url, relationship) { if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - const request = this._requestFor({ + let request = this._requestFor({ store, snapshot, url, relationship, requestType: 'findBelongsTo' }); return this._makeRequest(request); } else { - var id = snapshot.id; - var type = snapshot.modelName; + let id = snapshot.id; + let type = snapshot.modelName; url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findBelongsTo')); return this.ajax(url, 'GET'); @@ -761,16 +761,16 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { */ createRecord(store, type, snapshot) { if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - const request = this._requestFor({ + let request = this._requestFor({ store, type, snapshot, requestType: 'createRecord' }); return this._makeRequest(request); } else { - var data = {}; - var serializer = store.serializerFor(type.modelName); - var url = this.buildURL(type.modelName, null, snapshot, 'createRecord'); + let data = {}; + let serializer = store.serializerFor(type.modelName); + let url = this.buildURL(type.modelName, null, snapshot, 'createRecord'); serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); @@ -796,20 +796,20 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { */ updateRecord(store, type, snapshot) { if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - const request = this._requestFor({ + let request = this._requestFor({ store, type, snapshot, requestType: 'updateRecord' }); return this._makeRequest(request); } else { - var data = {}; - var serializer = store.serializerFor(type.modelName); + let data = {}; + let serializer = store.serializerFor(type.modelName); serializer.serializeIntoHash(data, type, snapshot); - var id = snapshot.id; - var url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); + let id = snapshot.id; + let url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); return this.ajax(url, "PUT", { data: data }); } @@ -828,30 +828,30 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { */ deleteRecord(store, type, snapshot) { if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - const request = this._requestFor({ + let request = this._requestFor({ store, type, snapshot, requestType: 'deleteRecord' }); return this._makeRequest(request); } else { - var id = snapshot.id; + let id = snapshot.id; return this.ajax(this.buildURL(type.modelName, id, snapshot, 'deleteRecord'), "DELETE"); } }, _stripIDFromURL(store, snapshot) { - var url = this.buildURL(snapshot.modelName, snapshot.id, snapshot); + let url = this.buildURL(snapshot.modelName, snapshot.id, snapshot); - var expandedURL = url.split('/'); + let expandedURL = url.split('/'); // Case when the url is of the format ...something/:id // We are decodeURIComponent-ing the lastSegment because if it represents // the id, it has been encodeURIComponent-ified within `buildURL`. If we // don't do this, then records with id having special characters are not // coalesced correctly (see GH #4190 for the reported bug) - var lastSegment = expandedURL[expandedURL.length - 1]; - var id = snapshot.id; + let lastSegment = expandedURL[expandedURL.length - 1]; + let id = snapshot.id; if (decodeURIComponent(lastSegment) === id) { expandedURL[expandedURL.length - 1] = ""; } else if (endsWith(lastSegment, '?id=' + id)) { @@ -888,22 +888,22 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { loaded separately by `findMany`. */ groupRecordsForFindMany(store, snapshots) { - var groups = MapWithDefault.create({ defaultValue() { return []; } }); - var adapter = this; - var maxURLLength = this.maxURLLength; + let groups = MapWithDefault.create({ defaultValue() { return []; } }); + let adapter = this; + let maxURLLength = this.maxURLLength; snapshots.forEach((snapshot) => { - var baseUrl = adapter._stripIDFromURL(store, snapshot); + let baseUrl = adapter._stripIDFromURL(store, snapshot); groups.get(baseUrl).push(snapshot); }); function splitGroupToFitInUrl(group, maxURLLength, paramNameLength) { - var baseUrl = adapter._stripIDFromURL(store, group[0]); - var idsSize = 0; - var splitGroups = [[]]; + let idsSize = 0; + let baseUrl = adapter._stripIDFromURL(store, group[0]); + let splitGroups = [[]]; group.forEach((snapshot) => { - var additionalLength = encodeURIComponent(snapshot.id).length + paramNameLength; + let additionalLength = encodeURIComponent(snapshot.id).length + paramNameLength; if (baseUrl.length + idsSize + additionalLength >= maxURLLength) { idsSize = 0; splitGroups.push([]); @@ -911,17 +911,17 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { idsSize += additionalLength; - var lastGroupIndex = splitGroups.length - 1; + let lastGroupIndex = splitGroups.length - 1; splitGroups[lastGroupIndex].push(snapshot); }); return splitGroups; } - var groupsArray = []; + let groupsArray = []; groups.forEach((group, key) => { - var paramNameLength = '&ids%5B%5D='.length; - var splitGroups = splitGroupToFitInUrl(group, maxURLLength, paramNameLength); + let paramNameLength = '&ids%5B%5D='.length; + let splitGroups = splitGroupToFitInUrl(group, maxURLLength, paramNameLength); splitGroups.forEach((splitGroup) => groupsArray.push(splitGroup)); }); @@ -1044,29 +1044,29 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { */ ajax(url, type, options) { let token = heimdall.start('adapter.ajax'); - var adapter = this; + let adapter = this; - var requestData = { + let requestData = { url: url, method: type }; return new Promise(function(resolve, reject) { - var hash = adapter.ajaxOptions(url, type, options); + let hash = adapter.ajaxOptions(url, type, options); hash.success = function(payload, textStatus, jqXHR) { heimdall.stop(token); - var response = ajaxSuccess(adapter, jqXHR, payload, requestData); + let response = ajaxSuccess(adapter, jqXHR, payload, requestData); Ember.run.join(null, resolve, response); }; hash.error = function(jqXHR, textStatus, errorThrown) { heimdall.stop(token); - var responseData = { + let responseData = { textStatus, errorThrown }; - var error = ajaxError(adapter, jqXHR, requestData, responseData); + let error = ajaxError(adapter, jqXHR, requestData, responseData); Ember.run.join(null, reject, error); }; @@ -1092,7 +1092,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Object} */ ajaxOptions(url, type, options) { - var hash = options || {}; + let hash = options || {}; hash.url = url; hash.type = type; hash.dataType = 'json'; @@ -1119,7 +1119,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { hash.data = JSON.stringify(hash.data); } - var headers = get(this, 'headers'); + let headers = get(this, 'headers'); if (headers !== undefined) { hash.beforeSend = function (xhr) { Object.keys(headers).forEach((key) => xhr.setRequestHeader(key, headers[key])); @@ -1136,7 +1136,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Object} */ parseErrorResponse(responseText) { - var json = responseText; + let json = responseText; try { json = Ember.$.parseJSON(responseText); @@ -1182,8 +1182,8 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { @return {String} detailed error message */ generatedDetailedMessage: function(status, headers, payload, requestData) { - var shortenedPayload; - var payloadContentType = headers["Content-Type"] || "Empty Content-Type"; + let shortenedPayload; + let payloadContentType = headers["Content-Type"] || "Empty Content-Type"; if (payloadContentType === "text/html" && payload.length > 250) { shortenedPayload = "[Omitted Lengthy HTML]"; @@ -1191,8 +1191,8 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { shortenedPayload = payload; } - var requestDescription = requestData.method + ' ' + requestData.url; - var payloadDescription = 'Payload (' + payloadContentType + ')'; + let requestDescription = requestData.method + ' ' + requestData.url; + let payloadDescription = 'Payload (' + payloadContentType + ')'; return ['Ember Data Request ' + requestDescription + ' returned a ' + status, payloadDescription, @@ -1204,7 +1204,7 @@ var RESTAdapter = Adapter.extend(BuildURLMixin, { let query = {}; if (snapshot) { - const { include } = snapshot; + let { include } = snapshot; if (include) { query.include = include; @@ -1248,13 +1248,13 @@ if (isEnabled('ds-improved-ajax')) { * @return {Object} data */ dataForRequest(params) { - var { store, type, snapshot, requestType, query } = params; + let { store, type, snapshot, requestType, query } = params; // type is not passed to findBelongsTo and findHasMany type = type || (snapshot && snapshot.type); - var serializer = store.serializerFor(type.modelName); - var data = {}; + let serializer = store.serializerFor(type.modelName); + let data = {}; switch (requestType) { case 'createRecord': @@ -1306,7 +1306,7 @@ if (isEnabled('ds-improved-ajax')) { * @return {String} HTTP method */ methodForRequest(params) { - const { requestType } = params; + let { requestType } = params; switch (requestType) { case 'createRecord': return 'POST'; @@ -1326,7 +1326,7 @@ if (isEnabled('ds-improved-ajax')) { * @return {String} URL */ urlForRequest(params) { - var { type, id, ids, snapshot, snapshots, requestType, query } = params; + let { type, id, ids, snapshot, snapshots, requestType, query } = params; // type and id are not passed from updateRecord and deleteRecord, hence they // are defined if not set @@ -1379,10 +1379,10 @@ if (isEnabled('ds-improved-ajax')) { * @return {Object} request object */ _requestFor(params) { - const method = this.methodForRequest(params); - const url = this.urlForRequest(params); - const headers = this.headersForRequest(params); - const data = this.dataForRequest(params); + let method = this.methodForRequest(params); + let url = this.urlForRequest(params); + let headers = this.headersForRequest(params); + let data = this.dataForRequest(params); return { method, url, headers, data }; }, @@ -1396,7 +1396,7 @@ if (isEnabled('ds-improved-ajax')) { * @return {Object} jQuery ajax hash */ _requestToJQueryAjaxHash(request) { - const hash = {}; + let hash = {}; hash.type = request.method; hash.url = request.url; @@ -1412,7 +1412,7 @@ if (isEnabled('ds-improved-ajax')) { } } - var headers = request.headers; + let headers = request.headers; if (headers !== undefined) { hash.beforeSend = function(xhr) { Object.keys(headers).forEach((key) => xhr.setRequestHeader(key, headers[key])); @@ -1432,27 +1432,27 @@ if (isEnabled('ds-improved-ajax')) { */ _makeRequest(request) { let token = heimdall.start('adapter._makeRequest'); - const adapter = this; - const hash = this._requestToJQueryAjaxHash(request); + let adapter = this; + let hash = this._requestToJQueryAjaxHash(request); - const { method, url } = request; - const requestData = { method, url }; + let { method, url } = request; + let requestData = { method, url }; return new Ember.RSVP.Promise((resolve, reject) => { hash.success = function(payload, textStatus, jqXHR) { heimdall.stop(token); - var response = ajaxSuccess(adapter, jqXHR, payload, requestData); + let response = ajaxSuccess(adapter, jqXHR, payload, requestData); Ember.run.join(null, resolve, response); }; hash.error = function(jqXHR, textStatus, errorThrown) { heimdall.stop(token); - var responseData = { + let responseData = { textStatus, errorThrown }; - var error = ajaxError(adapter, jqXHR, requestData, responseData); + let error = ajaxError(adapter, jqXHR, requestData, responseData); Ember.run.join(null, reject, error); }; diff --git a/addon/attr.js b/addon/attr.js index 431cbbb75d5..e29d5713b1b 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -109,7 +109,7 @@ function getValue(record, key) { @namespace @method attr @for DS - @param {String} type the attribute type + @param {String|Object} type the attribute type @param {Object} options a hash of options @return {Attribute} */ @@ -122,7 +122,7 @@ export default function attr(type, options) { options = options || {}; } - var meta = { + let meta = { type: type, isAttribute: true, options: options @@ -130,7 +130,7 @@ export default function attr(type, options) { return Ember.computed({ get(key) { - var internalModel = this._internalModel; + let internalModel = this._internalModel; if (hasValue(internalModel, key)) { return getValue(internalModel, key); } else { @@ -138,9 +138,9 @@ export default function attr(type, options) { } }, set(key, value) { - var internalModel = this._internalModel; - var oldValue = getValue(internalModel, key); - var originalValue; + let internalModel = this._internalModel; + let oldValue = getValue(internalModel, key); + let originalValue; if (value !== oldValue) { // Add the new value to the changed attributes hash; it will get deleted by diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index ad345370fb5..359cefbea63 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -1,9 +1,9 @@ import Ember from 'ember'; import { warn } from "ember-data/-private/debug"; -var get = Ember.get; -var set = Ember.set; -var camelize = Ember.String.camelize; +const get = Ember.get; +const set = Ember.set; +const camelize = Ember.String.camelize; /** ## Using Embedded Records @@ -125,7 +125,7 @@ export default Ember.Mixin.create({ @return {Object} the normalized hash **/ normalize(typeClass, hash, prop) { - var normalizedHash = this._super(typeClass, hash, prop); + let normalizedHash = this._super(typeClass, hash, prop); return this._extractEmbeddedRecords(this, this.store, typeClass, normalizedHash); }, @@ -190,16 +190,16 @@ export default Ember.Mixin.create({ @param {Object} relationship */ serializeBelongsTo(snapshot, json, relationship) { - var attr = relationship.key; + let attr = relationship.key; if (this.noSerializeOptionSpecified(attr)) { this._super(snapshot, json, relationship); return; } - var includeIds = this.hasSerializeIdsOption(attr); - var includeRecords = this.hasSerializeRecordsOption(attr); - var embeddedSnapshot = snapshot.belongsTo(attr); + let includeIds = this.hasSerializeIdsOption(attr); + let includeRecords = this.hasSerializeRecordsOption(attr); + let embeddedSnapshot = snapshot.belongsTo(attr); if (includeIds) { - var serializedKey = this._getMappedKey(relationship.key, snapshot.type); + let serializedKey = this._getMappedKey(relationship.key, snapshot.type); if (serializedKey === relationship.key && this.keyForRelationship) { serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); } @@ -220,7 +220,7 @@ export default Ember.Mixin.create({ _serializeEmbeddedBelongsTo(snapshot, json, relationship) { let embeddedSnapshot = snapshot.belongsTo(relationship.key); - var serializedKey = this._getMappedKey(relationship.key, snapshot.type); + let serializedKey = this._getMappedKey(relationship.key, snapshot.type); if (serializedKey === relationship.key && this.keyForRelationship) { serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); } @@ -373,7 +373,7 @@ export default Ember.Mixin.create({ @param {Object} relationship */ serializeHasMany(snapshot, json, relationship) { - var attr = relationship.key; + let attr = relationship.key; if (this.noSerializeOptionSpecified(attr)) { this._super(snapshot, json, relationship); return; @@ -404,8 +404,8 @@ export default Ember.Mixin.create({ TODO: Make the default in Ember-data 3.0?? */ _serializeHasManyAsIdsAndTypes(snapshot, json, relationship) { - var serializedKey = this.keyForAttribute(relationship.key, 'serialize'); - var hasMany = snapshot.hasMany(relationship.key); + let serializedKey = this.keyForAttribute(relationship.key, 'serialize'); + let hasMany = snapshot.hasMany(relationship.key); json[serializedKey] = Ember.A(hasMany).map(function (recordSnapshot) { // @@ -417,7 +417,7 @@ export default Ember.Mixin.create({ }, _serializeEmbeddedHasMany(snapshot, json, relationship) { - var serializedKey = this._getMappedKey(relationship.key, snapshot.type); + let serializedKey = this._getMappedKey(relationship.key, snapshot.type); if (serializedKey === relationship.key && this.keyForRelationship) { serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); } @@ -467,49 +467,49 @@ export default Ember.Mixin.create({ @param {Object} json */ removeEmbeddedForeignKey(snapshot, embeddedSnapshot, relationship, json) { - if (relationship.kind === 'hasMany') { - return; - } else if (relationship.kind === 'belongsTo') { - var parentRecord = snapshot.type.inverseFor(relationship.key, this.store); + if (relationship.kind === 'belongsTo') { + let parentRecord = snapshot.type.inverseFor(relationship.key, this.store); if (parentRecord) { - var name = parentRecord.name; - var embeddedSerializer = this.store.serializerFor(embeddedSnapshot.modelName); - var parentKey = embeddedSerializer.keyForRelationship(name, parentRecord.kind, 'deserialize'); + let name = parentRecord.name; + let embeddedSerializer = this.store.serializerFor(embeddedSnapshot.modelName); + let parentKey = embeddedSerializer.keyForRelationship(name, parentRecord.kind, 'deserialize'); if (parentKey) { delete json[parentKey]; } } - } + } /*else if (relationship.kind === 'hasMany') { + return; + }*/ }, // checks config for attrs option to embedded (always) - serialize and deserialize hasEmbeddedAlwaysOption(attr) { - var option = this.attrsOption(attr); + let option = this.attrsOption(attr); return option && option.embedded === 'always'; }, // checks config for attrs option to serialize ids hasSerializeRecordsOption(attr) { - var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); - var option = this.attrsOption(attr); + let alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); + let option = this.attrsOption(attr); return alwaysEmbed || (option && (option.serialize === 'records')); }, // checks config for attrs option to serialize records hasSerializeIdsOption(attr) { - var option = this.attrsOption(attr); + let option = this.attrsOption(attr); return option && (option.serialize === 'ids' || option.serialize === 'id'); }, // checks config for attrs option to serialize records as objects containing id and types hasSerializeIdsAndTypesOption(attr) { - var option = this.attrsOption(attr); + let option = this.attrsOption(attr); return option && (option.serialize === 'ids-and-types' || option.serialize === 'id-and-type'); }, // checks config for attrs option to serialize records noSerializeOptionSpecified(attr) { - var option = this.attrsOption(attr); + let option = this.attrsOption(attr); return !(option && (option.serialize || option.embedded)); }, @@ -517,13 +517,13 @@ export default Ember.Mixin.create({ // a defined option object for a resource is treated the same as // `deserialize: 'records'` hasDeserializeRecordsOption(attr) { - var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); - var option = this.attrsOption(attr); + let alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); + let option = this.attrsOption(attr); return alwaysEmbed || (option && option.deserialize === 'records'); }, attrsOption(attr) { - var attrs = this.get('attrs'); + let attrs = this.get('attrs'); return attrs && (attrs[camelize(attr)] || attrs[attr]); }, diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 0655cacae4c..80d2e69b709 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -9,7 +9,7 @@ import normalizeModelName from 'ember-data/-private/system/normalize-model-name' import { pluralize, singularize } from 'ember-inflector'; import isEnabled from 'ember-data/-private/features'; -var dasherize = Ember.String.dasherize; +const dasherize = Ember.String.dasherize; /** Ember Data 2.0 Serializer: @@ -190,8 +190,7 @@ const JSONAPISerializer = JSONSerializer.extend({ relationshipDataHash.type = modelName; } else { - let type = this.modelNameFromPayloadKey(relationshipDataHash.type); - relationshipDataHash.type = type; + relationshipDataHash.type = this.modelNameFromPayloadKey(relationshipDataHash.type); } return relationshipDataHash; @@ -284,7 +283,7 @@ const JSONAPISerializer = JSONSerializer.extend({ }, extractAttributes(modelClass, resourceHash) { - var attributes = {}; + let attributes = {}; if (resourceHash.attributes) { modelClass.eachAttribute((key) => { @@ -510,14 +509,14 @@ const JSONAPISerializer = JSONSerializer.extend({ }, serializeAttribute(snapshot, json, key, attribute) { - const type = attribute.type; + let type = attribute.type; if (this._canSerialize(key)) { json.attributes = json.attributes || {}; let value = snapshot.attr(key); if (type) { - const transform = this.transformFor(type); + let transform = this.transformFor(type); value = transform.serialize(value, attribute.options); } @@ -532,15 +531,15 @@ const JSONAPISerializer = JSONSerializer.extend({ }, serializeBelongsTo(snapshot, json, relationship) { - var key = relationship.key; + let key = relationship.key; if (this._canSerialize(key)) { - var belongsTo = snapshot.belongsTo(key); + let belongsTo = snapshot.belongsTo(key); if (belongsTo !== undefined) { json.relationships = json.relationships || {}; - var payloadKey = this._getMappedKey(key, snapshot.type); + let payloadKey = this._getMappedKey(key, snapshot.type); if (payloadKey === key) { payloadKey = this.keyForRelationship(key, 'belongsTo', 'serialize'); } @@ -577,19 +576,19 @@ const JSONAPISerializer = JSONSerializer.extend({ }, serializeHasMany(snapshot, json, relationship) { - var key = relationship.key; - var shouldSerializeHasMany = '_shouldSerializeHasMany'; + let key = relationship.key; + let shouldSerializeHasMany = '_shouldSerializeHasMany'; if (isEnabled("ds-check-should-serialize-relationships")) { shouldSerializeHasMany = 'shouldSerializeHasMany'; } if (this[shouldSerializeHasMany](snapshot, key, relationship)) { - var hasMany = snapshot.hasMany(key); + let hasMany = snapshot.hasMany(key); if (hasMany !== undefined) { json.relationships = json.relationships || {}; - var payloadKey = this._getMappedKey(key, snapshot.type); + let payloadKey = this._getMappedKey(key, snapshot.type); if (payloadKey === key && this.keyForRelationship) { payloadKey = this.keyForRelationship(key, 'hasMany', 'serialize'); } @@ -743,7 +742,7 @@ if (isEnabled("ds-payload-type-hooks")) { runInDebug(function() { JSONAPISerializer.reopen({ willMergeMixin(props) { - var constructor = this.constructor; + let constructor = this.constructor; warn(`You've defined 'extractMeta' in ${constructor.toString()} which is not used for serializers extending JSONAPISerializer. Read more at http://emberjs.com/api/data/classes/DS.JSONAPISerializer.html#toc_customizing-meta on how to customize meta when using JSON API.`, Ember.isNone(props.extractMeta) || props.extractMeta === JSONSerializer.prototype.extractMeta, { id: 'ds.serializer.json-api.extractMeta' }); diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 02ac2db30d3..ffcb6bcde67 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -12,9 +12,9 @@ import { import { errorsArrayToHash } from "ember-data/adapters/errors"; -var get = Ember.get; -var isNone = Ember.isNone; -var assign = Ember.assign || Ember.merge; +const get = Ember.get; +const isNone = Ember.isNone; +const assign = Ember.assign || Ember.merge; /** Ember Data 2.0 Serializer: @@ -82,7 +82,7 @@ var assign = Ember.assign || Ember.merge; @namespace DS @extends DS.Serializer */ -var JSONSerializer = Serializer.extend({ +const JSONSerializer = Serializer.extend({ /** The `primaryKey` is used when serializing and deserializing @@ -191,8 +191,8 @@ var JSONSerializer = Serializer.extend({ typeClass.eachTransformedAttribute((key, typeClass) => { if (data[key] === undefined) { return; } - var transform = this.transformFor(typeClass); - var transformMeta = attributes.get(key); + let transform = this.transformFor(typeClass); + let transformMeta = attributes.get(key); data[key] = transform.deserialize(data[key], transformMeta.options); }); @@ -556,8 +556,8 @@ var JSONSerializer = Serializer.extend({ @return {String} */ extractId(modelClass, resourceHash) { - var primaryKey = get(this, 'primaryKey'); - var id = resourceHash[primaryKey]; + let primaryKey = get(this, 'primaryKey'); + let id = resourceHash[primaryKey]; return coerceId(id); }, @@ -572,8 +572,8 @@ var JSONSerializer = Serializer.extend({ @return {Object} */ extractAttributes(modelClass, resourceHash) { - var attributeKey; - var attributes = {}; + let attributeKey; + let attributes = {}; modelClass.eachAttribute((key) => { attributeKey = this.keyForAttribute(key, 'deserialize'); @@ -607,7 +607,7 @@ var JSONSerializer = Serializer.extend({ relationshipHash.id = coerceId(relationshipHash.id); } - const modelClass = this.store.modelFor(relationshipModelName); + let modelClass = this.store.modelFor(relationshipModelName); if (relationshipHash.type && !modelHasAttributeOrRelationshipNamedType(modelClass)) { if (isEnabled("ds-payload-type-hooks")) { @@ -728,7 +728,7 @@ var JSONSerializer = Serializer.extend({ @private */ normalizeRelationships(typeClass, hash) { - var payloadKey; + let payloadKey; if (this.keyForRelationship) { typeClass.eachRelationship((key, relationship) => { @@ -747,11 +747,12 @@ var JSONSerializer = Serializer.extend({ @private */ normalizeUsingDeclaredMapping(modelClass, hash) { - var attrs = get(this, 'attrs'); - var normalizedKey, payloadKey, key; + let attrs = get(this, 'attrs'); + let normalizedKey; + let payloadKey; if (attrs) { - for (key in attrs) { + for (let key in attrs) { normalizedKey = payloadKey = this._getMappedKey(key, modelClass); if (hash[payloadKey] === undefined) { continue; } @@ -786,8 +787,8 @@ var JSONSerializer = Serializer.extend({ id: 'ds.serializer.no-mapped-attrs-key' }); - var attrs = get(this, 'attrs'); - var mappedKey; + let attrs = get(this, 'attrs'); + let mappedKey; if (attrs && attrs[key]) { mappedKey = attrs[key]; //We need to account for both the { title: 'post_title' } and @@ -813,7 +814,7 @@ var JSONSerializer = Serializer.extend({ @return {boolean} true if the key can be serialized */ _canSerialize(key) { - var attrs = get(this, 'attrs'); + let attrs = get(this, 'attrs'); return !attrs || !attrs[key] || attrs[key].serialize !== false; }, @@ -829,7 +830,7 @@ var JSONSerializer = Serializer.extend({ @return {boolean} true if the key must be serialized */ _mustSerialize(key) { - var attrs = get(this, 'attrs'); + let attrs = get(this, 'attrs'); return attrs && attrs[key] && attrs[key].serialize === true; }, @@ -866,7 +867,7 @@ var JSONSerializer = Serializer.extend({ @return {boolean} true if the hasMany relationship should be serialized */ _shouldSerializeHasMany(snapshot, key, relationship) { - var relationshipType = snapshot.type.determineRelationshipType(relationship, this.store); + let relationshipType = snapshot.type.determineRelationshipType(relationship, this.store); if (this._mustSerialize(key)) { return true; } @@ -1027,13 +1028,13 @@ var JSONSerializer = Serializer.extend({ @return {Object} json */ serialize(snapshot, options) { - var json = {}; + let json = {}; if (options && options.includeId) { if (isEnabled('ds-serialize-id')) { this.serializeId(snapshot, json, get(this, 'primaryKey')); } else { - var id = snapshot.id; + const id = snapshot.id; if (id) { json[get(this, 'primaryKey')] = id; } @@ -1112,18 +1113,18 @@ var JSONSerializer = Serializer.extend({ @param {Object} attribute */ serializeAttribute(snapshot, json, key, attribute) { - var type = attribute.type; if (this._canSerialize(key)) { - var value = snapshot.attr(key); + let type = attribute.type; + let value = snapshot.attr(key); if (type) { - var transform = this.transformFor(type); + let transform = this.transformFor(type); value = transform.serialize(value, attribute.options); } // if provided, use the mapping provided by `attrs` in // the serializer - var payloadKey = this._getMappedKey(key, snapshot.type); + let payloadKey = this._getMappedKey(key, snapshot.type); if (payloadKey === key && this.keyForAttribute) { payloadKey = this.keyForAttribute(key, 'serialize'); @@ -1161,14 +1162,14 @@ var JSONSerializer = Serializer.extend({ @param {Object} relationship */ serializeBelongsTo(snapshot, json, relationship) { - var key = relationship.key; + let key = relationship.key; if (this._canSerialize(key)) { - var belongsToId = snapshot.belongsTo(key, { id: true }); + let belongsToId = snapshot.belongsTo(key, { id: true }); // if provided, use the mapping provided by `attrs` in // the serializer - var payloadKey = this._getMappedKey(key, snapshot.type); + let payloadKey = this._getMappedKey(key, snapshot.type); if (payloadKey === key && this.keyForRelationship) { payloadKey = this.keyForRelationship(key, "belongsTo", "serialize"); } @@ -1213,18 +1214,18 @@ var JSONSerializer = Serializer.extend({ @param {Object} relationship */ serializeHasMany(snapshot, json, relationship) { - var key = relationship.key; - var shouldSerializeHasMany = '_shouldSerializeHasMany'; + let key = relationship.key; + let shouldSerializeHasMany = '_shouldSerializeHasMany'; if (isEnabled("ds-check-should-serialize-relationships")) { shouldSerializeHasMany = 'shouldSerializeHasMany'; } if (this[shouldSerializeHasMany](snapshot, key, relationship)) { - var hasMany = snapshot.hasMany(key, { ids: true }); + let hasMany = snapshot.hasMany(key, { ids: true }); if (hasMany !== undefined) { // if provided, use the mapping provided by `attrs` in // the serializer - var payloadKey = this._getMappedKey(key, snapshot.type); + let payloadKey = this._getMappedKey(key, snapshot.type); if (payloadKey === key && this.keyForRelationship) { payloadKey = this.keyForRelationship(key, "hasMany", "serialize"); } @@ -1488,7 +1489,7 @@ var JSONSerializer = Serializer.extend({ @return {DS.Transform} transform */ transformFor(attributeType, skipAssertion) { - var transform = getOwner(this).lookup('transform:' + attributeType); + let transform = getOwner(this).lookup('transform:' + attributeType); assert("Unable to find transform for '" + attributeType + "'", skipAssertion || !!transform); @@ -1546,7 +1547,7 @@ if (isEnabled("ds-serialize-id")) { @param {String} primaryKey */ serializeId(snapshot, json, primaryKey) { - var id = snapshot.id; + let id = snapshot.id; if (id) { json[primaryKey] = id; diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 0f11c4db21b..4c8bdb3702f 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -11,7 +11,7 @@ import coerceId from "ember-data/-private/system/coerce-id"; import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; import isEnabled from 'ember-data/-private/features'; -var camelize = Ember.String.camelize; +let camelize = Ember.String.camelize; /** Normally, applications will use the `RESTSerializer` by implementing @@ -55,7 +55,7 @@ var camelize = Ember.String.camelize; @namespace DS @extends DS.JSONSerializer */ -var RESTSerializer = JSONSerializer.extend({ +let RESTSerializer = JSONSerializer.extend({ /** `keyForPolymorphicType` can be used to define a custom key when @@ -83,7 +83,7 @@ var RESTSerializer = JSONSerializer.extend({ @return {String} normalized key */ keyForPolymorphicType(key, typeClass, method) { - var relationshipKey = this.keyForRelationship(key); + let relationshipKey = this.keyForRelationship(key); return `${relationshipKey}Type`; }, @@ -201,7 +201,7 @@ var RESTSerializer = JSONSerializer.extend({ let serializer = primarySerializer; let modelClass = primaryModelClass; - const primaryHasTypeAttribute = modelHasAttributeOrRelationshipNamedType(primaryModelClass); + let primaryHasTypeAttribute = modelHasAttributeOrRelationshipNamedType(primaryModelClass); if (!primaryHasTypeAttribute && hash.type) { // Support polymorphic records in async relationships @@ -254,12 +254,12 @@ var RESTSerializer = JSONSerializer.extend({ documentHash.meta = meta; } - var keys = Object.keys(payload); + let keys = Object.keys(payload); for (let i = 0, length = keys.length; i < length; i++) { let prop = keys[i]; - var modelName = prop; - var forcedSecondary = false; + let modelName = prop; + let forcedSecondary = false; /* If you want to provide sideloaded records of the same type that the @@ -286,7 +286,7 @@ var RESTSerializer = JSONSerializer.extend({ modelName = prop.substr(1); } - var typeName = this.modelNameFromPayloadKey(modelName); + let typeName = this.modelNameFromPayloadKey(modelName); if (!store.modelFactoryFor(typeName)) { warn(this.warnMessageNoModelForKey(modelName, typeName), false, { id: 'ds.serializer.model-for-key-missing' @@ -294,8 +294,8 @@ var RESTSerializer = JSONSerializer.extend({ continue; } - var isPrimary = (!forcedSecondary && this.isPrimaryType(store, typeName, primaryModelClass)); - var value = payload[prop]; + let isPrimary = (!forcedSecondary && this.isPrimaryType(store, typeName, primaryModelClass)); + let value = payload[prop]; if (value === null) { continue; @@ -349,8 +349,8 @@ var RESTSerializer = JSONSerializer.extend({ 2. If it's a newly created record without an ID, the first record in the array */ - var isUpdatedRecord = isPrimary && coerceId(resource.id) === id; - var isFirstCreatedRecord = isPrimary && !id && !documentHash.data; + let isUpdatedRecord = isPrimary && coerceId(resource.id) === id; + let isFirstCreatedRecord = isPrimary && !id && !documentHash.data; if (isFirstCreatedRecord || isUpdatedRecord) { documentHash.data = resource; @@ -373,7 +373,7 @@ var RESTSerializer = JSONSerializer.extend({ }, isPrimaryType(store, typeName, primaryTypeClass) { - var typeClass = store.modelFor(typeName); + let typeClass = store.modelFor(typeName); return typeClass.modelName === primaryTypeClass.modelName; }, @@ -414,16 +414,16 @@ var RESTSerializer = JSONSerializer.extend({ included: [] }; - for (var prop in payload) { - var modelName = this.modelNameFromPayloadKey(prop); + for (let prop in payload) { + let modelName = this.modelNameFromPayloadKey(prop); if (!store.modelFactoryFor(modelName)) { warn(this.warnMessageNoModelForKey(prop, modelName), false, { id: 'ds.serializer.model-for-key-missing' }); continue; } - var type = store.modelFor(modelName); - var typeSerializer = store.serializerFor(type.modelName); + let type = store.modelFor(modelName); + let typeSerializer = store.serializerFor(type.modelName); Ember.makeArray(payload[prop]).forEach((hash) => { let { data, included } = typeSerializer.normalize(type, hash, prop); @@ -686,7 +686,7 @@ var RESTSerializer = JSONSerializer.extend({ @param {Object} options */ serializeIntoHash(hash, typeClass, snapshot, options) { - var normalizedRootKey = this.payloadKeyFromModelName(typeClass.modelName); + let normalizedRootKey = this.payloadKeyFromModelName(typeClass.modelName); hash[normalizedRootKey] = this.serialize(snapshot, options); }, @@ -750,9 +750,9 @@ var RESTSerializer = JSONSerializer.extend({ @param {Object} relationship */ serializePolymorphicType(snapshot, json, relationship) { - var key = relationship.key; - var belongsTo = snapshot.belongsTo(key); - var typeKey = this.keyForPolymorphicType(key, relationship.type, 'serialize'); + let key = relationship.key; + let typeKey = this.keyForPolymorphicType(key, relationship.type, 'serialize'); + let belongsTo = snapshot.belongsTo(key); // old way of getting the key for the polymorphic type key = this.keyForAttribute ? this.keyForAttribute(key, "serialize") : key; @@ -794,7 +794,7 @@ var RESTSerializer = JSONSerializer.extend({ @return {Object} */ extractPolymorphicRelationship(relationshipType, relationshipHash, relationshipOptions) { - var { key, resourceHash, relationshipMeta } = relationshipOptions; + let { key, resourceHash, relationshipMeta } = relationshipOptions; // A polymorphic belongsTo relationship can be present in the payload // either in the form where the `id` and the `type` are given: @@ -813,8 +813,8 @@ var RESTSerializer = JSONSerializer.extend({ // The next code checks if the latter case is present and returns the // corresponding JSON-API representation. The former case is handled within // the base class JSONSerializer. - var isPolymorphic = relationshipMeta.options.polymorphic; - var typeProperty = this.keyForPolymorphicType(key, relationshipType, 'deserialize'); + let isPolymorphic = relationshipMeta.options.polymorphic; + let typeProperty = this.keyForPolymorphicType(key, relationshipType, 'deserialize'); if (isPolymorphic && resourceHash[typeProperty] !== undefined && typeof relationshipHash !== 'object') { @@ -949,7 +949,7 @@ if (isEnabled("ds-payload-type-hooks")) { @method payloadTypeFromModelName @public - @param {String} modelname modelName from the record + @param {String} modelName modelName from the record @return {String} payloadType */ payloadTypeFromModelName(modelName) { From d2b04f465117575d4f36b57e0cb8667c0ede81cf Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 9 Dec 2016 10:44:44 -0800 Subject: [PATCH 1770/2527] es6 RecordArrayManager --- addon/-private/system/model/internal-model.js | 10 ++- addon/-private/system/record-array-manager.js | 63 ++++++++++--------- .../adapter-populated-record-array.js | 5 +- .../system/record-arrays/record-array.js | 4 +- addon/-private/system/store.js | 4 +- tests/dummy/app/routes/query/route.js | 2 - tests/unit/record-arrays/record-array-test.js | 29 ++++++--- 7 files changed, 70 insertions(+), 47 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index df96f1868ea..5bc9e621528 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -5,6 +5,7 @@ import Relationships from "ember-data/-private/system/relationships/state/create import Snapshot from "ember-data/-private/system/snapshot"; import EmptyObject from "ember-data/-private/system/empty-object"; import isEnabled from 'ember-data/-private/features'; +import OrderedSet from "ember-data/-private/system/ordered-set"; import { getOwner @@ -114,7 +115,6 @@ export default class InternalModel { this.modelName = modelName; this.dataHasInitialized = false; this._loadingPromise = null; - this._recordArrays = undefined; this._record = null; this.currentState = RootState.empty; this.isReloading = false; @@ -126,6 +126,7 @@ export default class InternalModel { // caches for lazy getters this._modelClass = null; this.__deferredTriggers = null; + this.__recordArrays = null; this._references = null; this._recordReference = null; this.__inFlightAttributes = null; @@ -149,6 +150,13 @@ export default class InternalModel { return this._recordReference; } + get _recordArrays() { + if (this.__recordArrays === null) { + this.__recordArrays = OrderedSet.create(); + } + return this.__recordArrays; + } + get references() { if (this._references === null) { this._references = new EmptyObject(); diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index b80759d7993..79fc0c02445 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -8,7 +8,6 @@ import { FilteredRecordArray, AdapterPopulatedRecordArray } from "ember-data/-private/system/record-arrays"; -import OrderedSet from "ember-data/-private/system/ordered-set"; import { assert } from 'ember-data/-private/debug'; const { @@ -65,11 +64,13 @@ const { @class RecordArrayManager @namespace DS @private - @extends Ember.Object */ -export default Ember.Object.extend({ - init() { +export default class RecordArrayManager { + constructor(options) { heimdall.increment(create); + this.store = options.store; + this.isDestroying = false; + this.isDestroyed = false; this.filteredRecordArrays = MapWithDefault.create({ defaultValue() { return []; } }); @@ -84,20 +85,20 @@ export default Ember.Object.extend({ this.changedRecords = []; this.loadedRecords = []; this._adapterPopulatedRecordArrays = []; - }, + } recordDidChange(internalModel) { heimdall.increment(recordDidChange); if (this.changedRecords.push(internalModel) !== 1) { return; } emberRun.schedule('actions', this, this.updateRecordArrays); - }, + } recordArraysForRecord(internalModel) { heimdall.increment(recordArraysForRecord); - internalModel._recordArrays = internalModel._recordArrays || OrderedSet.create(); + return internalModel._recordArrays; - }, + } /** This method is invoked whenever data is loaded into the store by the @@ -127,18 +128,18 @@ export default Ember.Object.extend({ } updated.length = 0; - }, + } _recordWasDeleted(internalModel) { heimdall.increment(_recordWasDeleted); - let recordArrays = internalModel._recordArrays; + let recordArrays = internalModel.__recordArrays; if (!recordArrays) { return; } recordArrays.forEach(array => array._removeInternalModels([internalModel])); - internalModel._recordArrays = null; - }, + internalModel.__recordArrays = null; + } _recordWasChanged(internalModel) { heimdall.increment(_recordWasChanged); @@ -149,7 +150,7 @@ export default Ember.Object.extend({ filter = get(array, 'filterFunction'); this.updateFilterRecordArray(array, filter, modelName, internalModel); }); - }, + } //Need to update live arrays on loading recordWasLoaded(internalModel) { @@ -157,7 +158,7 @@ export default Ember.Object.extend({ if (this.loadedRecords.push(internalModel) !== 1) { return; } emberRun.schedule('actions', this, this._flushLoadedRecords); - }, + } _flushLoadedRecords() { heimdall.increment(_flushLoadedRecords); @@ -183,7 +184,7 @@ export default Ember.Object.extend({ } this.loadedRecords.length = 0; - }, + } /** Update an individual filter. @@ -204,7 +205,7 @@ export default Ember.Object.extend({ recordArrays.delete(array); array._removeInternalModels([internalModel]); } - }, + } _addInternalModelToRecordArray(array, internalModel) { heimdall.increment(_addRecordToRecordArray); @@ -213,7 +214,7 @@ export default Ember.Object.extend({ array._pushInternalModels([internalModel]); recordArrays.add(array); } - }, + } syncLiveRecordArray(array, modelName) { assert(`recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); @@ -232,7 +233,7 @@ export default Ember.Object.extend({ } this.populateLiveRecordArray(array, modelName); - }, + } populateLiveRecordArray(array, modelName) { assert(`recordArrayManger.populateLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); @@ -248,7 +249,7 @@ export default Ember.Object.extend({ this._addInternalModelToRecordArray(array, record); } } - }, + } /** This method is invoked if the `filterFunction` property is @@ -276,7 +277,7 @@ export default Ember.Object.extend({ this.updateFilterRecordArray(array, filter, modelName, record); } } - }, + } /** Get the `DS.RecordArray` for a modelName, which contains all loaded records of @@ -291,7 +292,7 @@ export default Ember.Object.extend({ heimdall.increment(liveRecordArrayFor); return this.liveRecordArrays.get(modelName); - }, + } /** Create a `DS.RecordArray` for a modelName. @@ -310,7 +311,7 @@ export default Ember.Object.extend({ isLoaded: true, manager: this }); - }, + } /** Create a `DS.FilteredRecordArray` for a modelName and register it for updates. @@ -337,7 +338,7 @@ export default Ember.Object.extend({ this.registerFilteredRecordArray(array, modelName, filter); return array; - }, + } /** Create a `DS.AdapterPopulatedRecordArray` for a modelName with given query. @@ -362,7 +363,7 @@ export default Ember.Object.extend({ this._adapterPopulatedRecordArrays.push(array); return array; - }, + } /** Register a RecordArray for a given modelName to be backed by @@ -383,7 +384,7 @@ export default Ember.Object.extend({ recordArrays.push(array); this.updateFilter(array, modelName, filter); - }, + } /** Unregister a RecordArray. @@ -414,16 +415,20 @@ export default Ember.Object.extend({ } } } - }, + } willDestroy() { - this._super(...arguments); - this.filteredRecordArrays.forEach(value => flatten(value).forEach(destroy)); this.liveRecordArrays.forEach(destroy); this._adapterPopulatedRecordArrays.forEach(destroy); + this.isDestroyed = true; } -}); + + destroy() { + this.isDestroying = true; + Ember.run.schedule('actions', this, this.willDestroy); + } +} function destroy(entry) { entry.destroy(); diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index 24653246f2c..cbb76b7cd3e 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -87,7 +87,10 @@ export default RecordArray.extend({ links: cloneNull(payload.links) }); - internalModels.forEach(internalModel => this.manager.recordArraysForRecord(internalModel).add(this)); + for (let i = 0, l = internalModels.length; i < l; i++) { + let internalModel = internalModels[i]; + this.manager.recordArraysForRecord(internalModel).add(this) + } // TODO: should triggering didLoad event be the last action of the runLoop? Ember.run.once(this, 'trigger', 'didLoad'); diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index 66182beeac7..a077fcdbfa3 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -202,7 +202,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { _dissociateFromOwnRecords() { this.get('content').forEach(internalModel => { - let recordArrays = internalModel._recordArrays; + let recordArrays = internalModel.__recordArrays; if (recordArrays) { recordArrays.delete(this); @@ -215,7 +215,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @private */ _unregisterFromManager() { - get(this, 'manager').unregisterRecordArray(this); + this.manager.unregisterRecordArray(this); }, willDestroy() { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 945ef6ed36b..2dfa8acbf85 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -209,9 +209,7 @@ Store = Service.extend({ this._super(...arguments); this._backburner = new Backburner(['normalizeRelationships', 'syncRelationships', 'finished']); // internal bookkeeping; not observable - this.recordArrayManager = RecordArrayManager.create({ - store: this - }); + this.recordArrayManager = new RecordArrayManager({ store: this }); this._identityMap = new IdentityMap(); this._pendingSave = []; this._instanceCache = new ContainerInstanceCache(getOwner(this), this); diff --git a/tests/dummy/app/routes/query/route.js b/tests/dummy/app/routes/query/route.js index c6db6f4f49d..2bbafccb4c7 100644 --- a/tests/dummy/app/routes/query/route.js +++ b/tests/dummy/app/routes/query/route.js @@ -24,8 +24,6 @@ export default Route.extend({ let modelName = params.modelName; delete params.modelName; - heimdall.enableTimelineFeatures(); - let token = heimdall.start('ember-data'); return this.get('store').query(modelName, params) .then((records) => { diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js index 87af38604ab..5a36a4b5986 100644 --- a/tests/unit/record-arrays/record-array-test.js +++ b/tests/unit/record-arrays/record-array-test.js @@ -192,14 +192,25 @@ test('#_removeInternalModels', function(assert) { assert.deepEqual(content, [], 'now contains no models'); }); +class FakeInternalModel { + constructor(record) { + this._record = record; + this.__recordArrays = null; + } + + get _recordArrays() { + return this.__recordArrays; + } + + getRecord() { return this._record; } + + createSnapshot() { + return this._record; + } +} + function internalModelFor(record) { - return { - _recordArrays: undefined, - getRecord() { return record; }, - createSnapshot() { - return record; - } - }; + return new FakeInternalModel(record); } test('#save', function(assert) { @@ -237,7 +248,7 @@ test('#destroy', function(assert) { let internalModel1 = internalModelFor(model1); // TODO: this will be removed once we fix ownership related memory leaks. - internalModel1._recordArrays = { + internalModel1.__recordArrays = { delete(array) { didDissociatieFromOwnRecords++; assert.equal(array, recordArray); @@ -308,7 +319,7 @@ test('#destroy', function(assert) { let internalModel1 = internalModelFor(model1); // TODO: this will be removed once we fix ownership related memory leaks. - internalModel1._recordArrays = { + internalModel1.__recordArrays = { delete(array) { didDissociatieFromOwnRecords++; assert.equal(array, recordArray); From 52f2fc4ee673adddf7f4a72e0ce110dfc87aa0fc Mon Sep 17 00:00:00 2001 From: IgorT Date: Sat, 14 Jan 2017 17:25:46 -0800 Subject: [PATCH 1771/2527] Add a yarn lock file --- yarn.lock | 6093 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 6093 insertions(+) create mode 100644 yarn.lock diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000000..fafe1692837 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,6093 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +abbrev@1, abbrev@~1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + +accepts@1.3.3, accepts@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + dependencies: + mime-types "~2.1.11" + negotiator "0.6.1" + +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^3.0.4, acorn@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^4.0.1: + version "4.0.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" + +adm-zip@^0.4.7: + version "0.4.7" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" + +after@0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" + +ajv-keywords@^1.0.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.0.tgz#c11e6859eafff83e0dafc416929472eca946aa2c" + +ajv@^4.1.3, ajv@^4.7.0: + version "4.10.4" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.10.4.tgz#c0974dd00b3464984892d6010aa9c2c945933254" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +alter@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" + dependencies: + stable "~0.1.3" + +amd-name-resolver@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-0.0.5.tgz#76962dac876ed3311b05d29c6a58c14e1ef3304b" + dependencies: + ensure-posix-path "^1.0.1" + +amd-name-resolver@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-0.0.6.tgz#d3e4ba2dfcaab1d820c1be9de947c67828cfe595" + dependencies: + ensure-posix-path "^1.0.1" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-regex@*, ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^0.2.0, ansi-regex@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" + +ansi-styles@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" + +ansi-styles@^2.1.0, ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansicolors@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" + +ansicolors@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" + +ansistyles@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" + +anymatch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + dependencies: + arrify "^1.0.0" + micromatch "^2.1.5" + +aproba@^1.0.3, aproba@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + +archy@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + +are-we-there-yet@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.0 || ^1.1.13" + +argparse@^1.0.7, argparse@~1.0.2: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-index@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-index/-/array-index-1.0.0.tgz#ec56a749ee103e4e08c790b9c353df16055b97f9" + dependencies: + debug "^2.2.0" + es6-symbol "^3.0.2" + +array-to-error@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" + dependencies: + array-to-sentence "^1.1.0" + +array-to-sentence@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +arraybuffer.slice@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asap@^2.0.0, asap@~2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" + +asn1@0.1.11: + version "0.1.11" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assertion-error@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" + +ast-traverse@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" + +ast-types@0.8.12: + version "0.8.12" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" + +ast-types@0.8.15: + version "0.8.15" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" + +ast-types@0.9.2: + version "0.9.2" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.2.tgz#2cc19979d15c655108bf565323b8e7ee38751f6b" + +async-disk-cache@^1.0.0: + version "1.0.9" + resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.0.9.tgz#23bafb823184f463407e474e8d5f87899f72ca63" + dependencies: + debug "^2.1.3" + istextorbinary "2.1.0" + mkdirp "^0.5.0" + rimraf "^2.5.3" + rsvp "^3.0.18" + +async@^1.4.0, async@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + +async@^2.0.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.1.4.tgz#2d2160c7788032e4dd6cbe2502f1f9a2c8f6cde4" + dependencies: + lodash "^4.14.0" + +async@~0.2.6, async@~0.2.9: + version "0.2.10" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + +async@~0.9.0: + version "0.9.2" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +aws-sdk@^2.0.9: + version "2.7.21" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.7.21.tgz#9abc790b3d2498482437172e5948988d4870f94f" + dependencies: + buffer "4.9.1" + crypto-browserify "1.0.9" + jmespath "0.15.0" + querystring "0.2.0" + sax "1.1.5" + url "0.10.3" + uuid "3.0.0" + xml2js "0.4.15" + xmlbuilder "2.6.2" + +aws-sign2@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" + +babel-core@^5.0.0, babel-core@^5.8.22: + version "5.8.38" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" + dependencies: + babel-plugin-constant-folding "^1.0.1" + babel-plugin-dead-code-elimination "^1.0.2" + babel-plugin-eval "^1.0.1" + babel-plugin-inline-environment-variables "^1.0.1" + babel-plugin-jscript "^1.0.4" + babel-plugin-member-expression-literals "^1.0.1" + babel-plugin-property-literals "^1.0.1" + babel-plugin-proto-to-assign "^1.0.3" + babel-plugin-react-constant-elements "^1.0.3" + babel-plugin-react-display-name "^1.0.3" + babel-plugin-remove-console "^1.0.1" + babel-plugin-remove-debugger "^1.0.1" + babel-plugin-runtime "^1.0.7" + babel-plugin-undeclared-variables-check "^1.0.2" + babel-plugin-undefined-to-void "^1.1.6" + babylon "^5.8.38" + bluebird "^2.9.33" + chalk "^1.0.0" + convert-source-map "^1.1.0" + core-js "^1.0.0" + debug "^2.1.1" + detect-indent "^3.0.0" + esutils "^2.0.0" + fs-readdir-recursive "^0.1.0" + globals "^6.4.0" + home-or-tmp "^1.0.0" + is-integer "^1.0.4" + js-tokens "1.0.1" + json5 "^0.4.0" + lodash "^3.10.0" + minimatch "^2.0.3" + output-file-sync "^1.1.0" + path-exists "^1.0.0" + path-is-absolute "^1.0.0" + private "^0.1.6" + regenerator "0.8.40" + regexpu "^1.3.0" + repeating "^1.1.2" + resolve "^1.1.6" + shebang-regex "^1.0.0" + slash "^1.0.0" + source-map "^0.5.0" + source-map-support "^0.2.10" + to-fast-properties "^1.0.0" + trim-right "^1.0.0" + try-resolve "^1.0.0" + +babel-plugin-constant-folding@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" + +babel-plugin-dead-code-elimination@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" + +babel-plugin-eval@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" + +babel-plugin-feature-flags@^0.2.1: + version "0.2.3" + resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.2.3.tgz#81d81ed77bda2014098fa8243abcf03a551cbd4d" + dependencies: + json-stable-stringify "^1.0.1" + +babel-plugin-filter-imports@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.2.1.tgz#784f96a892f2f7ed2ccf0955688bd8916cd2e212" + dependencies: + json-stable-stringify "^1.0.1" + +babel-plugin-htmlbars-inline-precompile@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.1.0.tgz#b784723bd1f108796b56faf9f1c05eb5ca442983" + +babel-plugin-inline-environment-variables@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" + +babel-plugin-jscript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" + +babel-plugin-member-expression-literals@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" + +babel-plugin-property-literals@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" + +babel-plugin-proto-to-assign@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" + dependencies: + lodash "^3.9.3" + +babel-plugin-react-constant-elements@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" + +babel-plugin-react-display-name@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" + +babel-plugin-remove-console@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" + +babel-plugin-remove-debugger@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" + +babel-plugin-runtime@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" + +babel-plugin-undeclared-variables-check@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" + dependencies: + leven "^1.0.2" + +babel-plugin-undefined-to-void@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" + +babel5-plugin-strip-class-callcheck@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/babel5-plugin-strip-class-callcheck/-/babel5-plugin-strip-class-callcheck-5.1.0.tgz#77d4a40c8614d367b8a21a53908159806dba5f91" + +babel5-plugin-strip-heimdall@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/babel5-plugin-strip-heimdall/-/babel5-plugin-strip-heimdall-5.0.2.tgz#e1fe191c34de79686564d50a86f4217b8df629c1" + +babylon@^5.8.38: + version "5.8.38" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" + +backbone@^1.1.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" + dependencies: + underscore ">=1.8.3" + +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + +balanced-match@^0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + +base64-js@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + +base64id@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" + +basic-auth@~1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.0.4.tgz#030935b01de7c9b94a824b29f3fccb750d3a5290" + +bcrypt-pbkdf@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4" + dependencies: + tweetnacl "^0.14.3" + +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + dependencies: + callsite "1.0.0" + +"binaryextensions@1 || 2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.0.0.tgz#e597d1a7a6a3558a2d1c7241a16c99965e6aa40f" + +bl@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" + dependencies: + readable-stream "~2.0.5" + +blank-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" + +blob@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird@^2.9.33: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" + +bluebird@^3.1.1, bluebird@^3.4.6: + version "3.4.7" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + +body-parser@^1.15.2: + version "1.15.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.15.2.tgz#d7578cf4f1d11d5f6ea804cef35dc7a7ff6dae67" + dependencies: + bytes "2.4.0" + content-type "~1.0.2" + debug "~2.2.0" + depd "~1.1.0" + http-errors "~1.5.0" + iconv-lite "0.4.13" + on-finished "~2.3.0" + qs "6.2.0" + raw-body "~2.1.7" + type-is "~1.6.13" + +body@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" + dependencies: + continuable-cache "^0.3.1" + error "^7.0.0" + raw-body "~1.1.0" + safe-json-parse "~1.0.1" + +boom@0.4.x: + version "0.4.2" + resolved "https://registry.yarnpkg.com/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" + dependencies: + hoek "0.9.x" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +bower-config@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.0.tgz#16c38c1135f8071c19f25938d61b0d8cbf18d3f1" + dependencies: + graceful-fs "^4.1.3" + mout "^1.0.0" + optimist "^0.6.1" + osenv "^0.1.3" + untildify "^2.1.0" + +bower-endpoint-parser@0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" + +bower@^1.3.12, bower@^1.6.5: + version "1.8.0" + resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a" + +brace-expansion@^1.0.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" + dependencies: + balanced-match "^0.4.1" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +breakable@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" + +broccoli-asset-rev@^2.4.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/broccoli-asset-rev/-/broccoli-asset-rev-2.5.0.tgz#f5f66eac962bf9f086286921f0eaeaab6d00d819" + dependencies: + broccoli-asset-rewrite "^1.1.0" + broccoli-filter "^1.2.2" + json-stable-stringify "^1.0.0" + matcher-collection "^1.0.1" + rsvp "^3.0.6" + +broccoli-asset-rewrite@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" + dependencies: + broccoli-filter "^1.2.3" + +broccoli-babel-transpiler@^5.4.5, broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.0: + version "5.6.2" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.6.2.tgz#958c72e43575b2f0a862a5096dba1ce1ebc7d74d" + dependencies: + babel-core "^5.0.0" + broccoli-funnel "^1.0.0" + broccoli-merge-trees "^1.0.0" + broccoli-persistent-filter "^1.0.1" + clone "^0.2.0" + hash-for-dep "^1.0.2" + json-stable-stringify "^1.0.0" + +broccoli-brocfile-loader@^0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/broccoli-brocfile-loader/-/broccoli-brocfile-loader-0.18.0.tgz#2e86021c805c34ffc8d29a2fb721cf273e819e4b" + dependencies: + findup-sync "^0.4.2" + +broccoli-builder@^0.18.0: + version "0.18.3" + resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.3.tgz#9d2c90558e7f4d1118ae6e938c63b35da00dd38f" + dependencies: + heimdalljs "^0.2.0" + promise-map-series "^0.2.1" + quick-temp "^0.1.2" + rimraf "^2.2.8" + rsvp "^3.0.17" + silent-error "^1.0.1" + +broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" + dependencies: + broccoli-kitchen-sink-helpers "^0.2.5" + broccoli-plugin "1.1.0" + debug "^2.1.1" + rimraf "^2.2.8" + rsvp "^3.0.17" + walk-sync "^0.2.5" + +broccoli-caching-writer@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-plugin "^1.2.1" + debug "^2.1.1" + rimraf "^2.2.8" + rsvp "^3.0.17" + walk-sync "^0.3.0" + +broccoli-caching-writer@~2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" + dependencies: + broccoli-kitchen-sink-helpers "^0.2.5" + broccoli-plugin "1.1.0" + debug "^2.1.1" + lodash-node "^3.2.0" + rimraf "^2.2.8" + rsvp "^3.0.17" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" + +broccoli-clean-css@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" + dependencies: + broccoli-persistent-filter "^1.1.6" + clean-css-promise "^0.1.0" + inline-source-map-comment "^1.0.5" + json-stable-stringify "^1.0.0" + +broccoli-concat@0.0.13: + version "0.0.13" + resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-0.0.13.tgz#b1805c33537adf7dca1b33b6a6516f225a00468f" + dependencies: + broccoli-kitchen-sink-helpers "^0.2.4" + broccoli-writer "^0.1.1" + glob "^4.3.1" + js-string-escape "~1.0.0" + mkdirp "^0.5.0" + quick-temp "~0.1.2" + +broccoli-concat@^2.2.0: + version "2.3.8" + resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-2.3.8.tgz#590cdcc021bb905b6c121d87c2d1d57df44a2a48" + dependencies: + broccoli-caching-writer "^2.3.1" + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-stew "^1.3.3" + fast-sourcemap-concat "^1.0.1" + fs-extra "^0.30.0" + lodash.merge "^4.3.0" + lodash.omit "^4.1.0" + lodash.uniq "^4.2.0" + +broccoli-concat@^3.0.4: + version "3.0.5" + resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.0.5.tgz#306fb47e7caa23ec726391fe8b584765946eb52e" + dependencies: + broccoli-caching-writer "^3.0.0" + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-stew "^1.3.3" + fast-sourcemap-concat "^1.0.1" + fs-extra "^0.30.0" + lodash.merge "^4.3.0" + lodash.omit "^4.1.0" + lodash.uniq "^4.2.0" + mkdirp "^0.5.1" + +broccoli-config-loader@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/broccoli-config-loader/-/broccoli-config-loader-1.0.0.tgz#c3cf5ecfaffc04338c6f1d5d38dc36baeaa131ba" + dependencies: + broccoli-caching-writer "^2.0.4" + +broccoli-config-replace@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-plugin "^1.2.0" + debug "^2.2.0" + fs-extra "^0.24.0" + +broccoli-file-creator@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" + dependencies: + broccoli-kitchen-sink-helpers "~0.2.0" + broccoli-plugin "^1.1.0" + broccoli-writer "~0.1.1" + mkdirp "^0.5.1" + rsvp "~3.0.6" + symlink-or-copy "^1.0.1" + +broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: + version "1.2.4" + resolved "https://registry.yarnpkg.com/broccoli-filter/-/broccoli-filter-1.2.4.tgz#409afb94b9a3a6da9fac8134e91e205f40cc7330" + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-plugin "^1.0.0" + copy-dereference "^1.0.0" + debug "^2.2.0" + mkdirp "^0.5.1" + promise-map-series "^0.2.1" + rsvp "^3.0.18" + symlink-or-copy "^1.0.1" + walk-sync "^0.3.1" + +broccoli-funnel-reducer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" + +broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6: + version "1.1.0" + resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.1.0.tgz#dfb91a37c902456456de4a40a1881948d65b27d9" + dependencies: + array-equal "^1.0.0" + blank-object "^1.0.1" + broccoli-plugin "^1.3.0" + debug "^2.2.0" + exists-sync "0.0.4" + fast-ordered-set "^1.0.0" + fs-tree-diff "^0.5.3" + heimdalljs "^0.2.0" + minimatch "^3.0.0" + mkdirp "^0.5.0" + path-posix "^1.0.0" + rimraf "^2.4.3" + symlink-or-copy "^1.0.0" + walk-sync "^0.3.1" + +broccoli-kitchen-sink-helpers@^0.2.4, broccoli-kitchen-sink-helpers@^0.2.5, broccoli-kitchen-sink-helpers@~0.2.0: + version "0.2.9" + resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" + dependencies: + glob "^5.0.10" + mkdirp "^0.5.1" + +broccoli-kitchen-sink-helpers@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" + dependencies: + glob "^5.0.10" + mkdirp "^0.5.1" + +broccoli-lint-eslint@^2.0.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/broccoli-lint-eslint/-/broccoli-lint-eslint-2.7.0.tgz#a2d905d02b397a90ae82439f283c459ef819f140" + dependencies: + broccoli-persistent-filter "^1.2.0" + escape-string-regexp "^1.0.5" + eslint "^2.13.0" + js-string-escape "^1.0.1" + json-stable-stringify "^1.0.1" + md5-hex "^1.2.1" + +broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^1.1.3: + version "1.2.1" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.1.tgz#16a7494ed56dbe61611f6c2d4817cfbaad2a3055" + dependencies: + broccoli-plugin "^1.3.0" + can-symlink "^1.0.0" + fast-ordered-set "^1.0.2" + fs-tree-diff "^0.5.4" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + rimraf "^2.4.3" + symlink-or-copy "^1.0.0" + +broccoli-merge-trees@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-0.2.4.tgz#1936f63bb09e24246b1e91d8c53162c0f7b24c3c" + dependencies: + broccoli-plugin "^1.0.0" + debug "^2.2.0" + symlink-or-copy "^1.0.0" + +broccoli-middleware@^0.18.1: + version "0.18.1" + resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-0.18.1.tgz#bf525581c2deb652c425942b18580f76d3748122" + dependencies: + handlebars "^4.0.4" + mime "^1.2.11" + +broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0: + version "1.2.13" + resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.2.13.tgz#61368669e2b8f35238fdd38a2a896597e4a1c821" + dependencies: + async-disk-cache "^1.0.0" + blank-object "^1.0.1" + broccoli-plugin "^1.0.0" + fs-tree-diff "^0.5.2" + hash-for-dep "^1.0.2" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + md5-hex "^1.0.2" + mkdirp "^0.5.1" + promise-map-series "^0.2.1" + rsvp "^3.0.18" + symlink-or-copy "^1.0.1" + walk-sync "^0.3.1" + +broccoli-plugin@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" + dependencies: + promise-map-series "^0.2.1" + quick-temp "^0.1.3" + rimraf "^2.3.4" + symlink-or-copy "^1.0.1" + +broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" + dependencies: + promise-map-series "^0.2.1" + quick-temp "^0.1.3" + rimraf "^2.3.4" + symlink-or-copy "^1.1.8" + +broccoli-slow-trees@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" + dependencies: + heimdalljs "^0.2.1" + +broccoli-source@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" + +broccoli-sri-hash@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" + dependencies: + broccoli-caching-writer "^2.2.0" + mkdirp "^0.5.1" + rsvp "^3.1.0" + sri-toolbox "^0.2.0" + symlink-or-copy "^1.0.1" + +broccoli-stew@^1.0.1, broccoli-stew@^1.2.0, broccoli-stew@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-1.4.0.tgz#1bdb0a1804d62a419d190abc26acb3c91878154d" + dependencies: + broccoli-funnel "^1.0.1" + broccoli-merge-trees "^1.0.0" + broccoli-persistent-filter "^1.1.6" + chalk "^1.1.3" + debug "^2.1.0" + ensure-posix-path "^1.0.1" + fs-extra "^0.30.0" + minimatch "^3.0.2" + resolve "^1.1.6" + rsvp "^3.0.16" + walk-sync "^0.3.0" + +broccoli-string-replace@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/broccoli-string-replace/-/broccoli-string-replace-0.1.1.tgz#e560d20db3569a336043110b4048210fa6f1478b" + dependencies: + broccoli-persistent-filter "^1.1.5" + minimatch "^2.0.8" + +broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.1.tgz#9fd2e87f1c177b11a758e73c3a11d6a03d90d086" + dependencies: + broccoli-plugin "^1.2.1" + debug "^2.2.0" + lodash.merge "^4.5.1" + matcher-collection "^1.0.0" + mkdirp "^0.5.0" + source-map-url "^0.3.0" + symlink-or-copy "^1.0.1" + uglify-js "^2.7.0" + walk-sync "^0.1.3" + +broccoli-writer@^0.1.1, broccoli-writer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/broccoli-writer/-/broccoli-writer-0.1.1.tgz#d4d71aa8f2afbc67a3866b91a2da79084b96ab2d" + dependencies: + quick-temp "^0.1.0" + rsvp "^3.0.6" + +broccoli-yuidoc@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/broccoli-yuidoc/-/broccoli-yuidoc-2.1.0.tgz#d208d5c056e421a51f0c7701e938229e7e85c2e6" + dependencies: + broccoli-caching-writer "~2.0.1" + broccoli-merge-trees "~0.2.3" + merge "~1.2.0" + rsvp "~3.1.0" + yuidocjs "~0.9.0" + +bser@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" + dependencies: + node-int64 "^0.4.0" + +buffer-shims@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + +buffer@4.9.1: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +builtins@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-0.0.7.tgz#355219cd6cf18dbe7c01cc7fd2dce765cfdc549a" + +bytes@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" + +bytes@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" + +bytes@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +camelcase@^1.0.2, camelcase@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + +can-symlink@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" + dependencies: + tmp "0.0.28" + +capture-exit@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.1.0.tgz#d931b32b11c2bd20ae57f34af0c1eb2c18781626" + dependencies: + rsvp "^3.3.3" + +cardinal@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-0.5.0.tgz#00d5f661dbd4aabfdf7d41ce48a5a59bca35a291" + dependencies: + ansicolors "~0.2.1" + redeyed "~0.5.0" + +cardinal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" + dependencies: + ansicolors "~0.2.1" + redeyed "~1.0.0" + +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chai-as-promised@^5.1.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-5.3.0.tgz#09d7a402908aa70dfdbead53e5853fc79d3ef21c" + +chai-as-promised@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" + dependencies: + check-error "^1.0.2" + +chai-files@^1.0.0, chai-files@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" + dependencies: + assertion-error "^1.0.1" + +chai@^3.3.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" + dependencies: + assertion-error "^1.0.1" + deep-eql "^0.1.3" + type-detect "^1.0.0" + +chalk@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" + dependencies: + ansi-styles "^1.1.0" + escape-string-regexp "^1.0.0" + has-ansi "^0.1.0" + strip-ansi "^0.3.0" + supports-color "^0.2.0" + +chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +charm@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" + dependencies: + inherits "^2.0.1" + +check-error@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + +chownr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +chrome-debugging-client@^0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/chrome-debugging-client/-/chrome-debugging-client-0.2.4.tgz#2ae3fbfcbf0536cbbd4d12e6373b271e3bcfc468" + dependencies: + mktemp "^0.4.0" + rimraf "^2.5.1" + ws "^1.0.1" + +circular-json@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + +clean-base-url@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" + +clean-css-promise@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" + dependencies: + array-to-error "^1.0.0" + clean-css "^3.4.5" + pinkie-promise "^2.0.0" + +clean-css@^3.4.5: + version "3.4.23" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.23.tgz#604fbbca24c12feb59b02f00b84f1fb7ded6d001" + dependencies: + commander "2.8.x" + source-map "0.4.x" + +cli-cursor@^1.0.1, cli-cursor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + +cli-spinners@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" + +cli-table2@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" + dependencies: + lodash "^3.10.1" + string-width "^1.0.1" + optionalDependencies: + colors "^1.1.2" + +cli-table@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + dependencies: + colors "1.0.3" + +cli-usage@^0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/cli-usage/-/cli-usage-0.1.4.tgz#7c01e0dc706c234b39c933838c8e20b2175776e2" + dependencies: + marked "^0.3.6" + marked-terminal "^1.6.2" + +cli-width@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +clone@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" + +clone@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" + +clone@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.0.tgz#9c715bfbd39aa197c8ee0f8e65c3912ba34f8cd6" + +cmd-shim@~2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb" + dependencies: + graceful-fs "^4.1.2" + mkdirp "~0.5.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +colors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + +colors@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + +colors@~0.6.0-1: + version "0.6.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" + +columnify@~1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" + dependencies: + strip-ansi "^3.0.0" + wcwidth "^1.0.0" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +combined-stream@~0.0.4: + version "0.0.7" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" + dependencies: + delayed-stream "0.0.5" + +commander@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" + +commander@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" + +commander@2.8.x: + version "2.8.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + dependencies: + graceful-readlink ">= 1.0.0" + +commander@^2.5.0, commander@^2.6.0, commander@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +commander@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" + +commoner@~0.10.3: + version "0.10.8" + resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" + dependencies: + commander "^2.5.0" + detective "^4.3.1" + glob "^5.0.15" + graceful-fs "^4.1.2" + iconv-lite "^0.4.5" + mkdirp "^0.5.0" + private "^0.1.6" + q "^1.1.2" + recast "^0.11.17" + +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + +component-emitter@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" + +component-emitter@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + +compressible@~2.0.8: + version "2.0.9" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.9.tgz#6daab4e2b599c2770dd9e21e7a891b1c5a755425" + dependencies: + mime-db ">= 1.24.0 < 2" + +compression@^1.4.4: + version "1.6.2" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" + dependencies: + accepts "~1.3.3" + bytes "2.3.0" + compressible "~2.0.8" + debug "~2.2.0" + on-headers "~1.0.1" + vary "~1.1.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@1.5.0, concat-stream@^1.4.6, concat-stream@^1.4.7: + version "1.5.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" + dependencies: + inherits "~2.0.1" + readable-stream "~2.0.0" + typedarray "~0.0.5" + +concat-stream@^1.5.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +config-chain@~1.1.10: + version "1.1.11" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2" + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +configstore@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" + dependencies: + dot-prop "^3.0.0" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + object-assign "^4.0.1" + os-tmpdir "^1.0.0" + osenv "^0.1.0" + uuid "^2.0.1" + write-file-atomic "^1.1.2" + xdg-basedir "^2.0.0" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +consolidate@^0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" + dependencies: + bluebird "^3.1.1" + +content-disposition@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b" + +content-type@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + +continuable-cache@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" + +convert-source-map@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +copy-dereference@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" + +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + +core-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" + +core-object@^2.0.2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/core-object/-/core-object-2.1.1.tgz#4b7a5f1edefcb1e6d0dcb58eab1b9f90bfc666a8" + dependencies: + chalk "^1.1.3" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cross-spawn@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.0.1.tgz#a3bbb302db2297cbea3c04edf36941f4613aa399" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cryptiles@0.2.x: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" + dependencies: + boom "0.4.x" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +crypto-browserify@1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" + +ctype@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" + +d@^0.1.1, d@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" + dependencies: + es5-ext "~0.10.2" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +debug@0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" + +debug@2.2.0, debug@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +debug@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" + dependencies: + ms "0.7.2" + +debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" + dependencies: + ms "0.7.2" + +debuglog@*, debuglog@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" + +decamelize@^1.0.0, decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +deep-eql@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" + dependencies: + type-detect "0.1.1" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + dependencies: + clone "^1.0.2" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +defs@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" + dependencies: + alter "~0.2.0" + ast-traverse "~0.1.1" + breakable "~1.0.0" + esprima-fb "~15001.1001.0-dev-harmony-fb" + simple-fmt "~0.1.0" + simple-is "~0.2.0" + stringmap "~0.2.2" + stringset "~0.2.1" + tryor "~0.1.2" + yargs "~3.27.0" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +delayed-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-file@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" + dependencies: + fs-exists-sync "^0.1.0" + +detect-indent@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" + dependencies: + get-stdin "^4.0.1" + minimist "^1.1.0" + repeating "^1.1.0" + +detective@^4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/detective/-/detective-4.3.2.tgz#77697e2e7947ac3fe7c8e26a6d6f115235afa91c" + dependencies: + acorn "^3.1.0" + defined "^1.0.0" + +dezalgo@^1.0.0, dezalgo@^1.0.1, dezalgo@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + dependencies: + asap "^2.0.0" + wrappy "1" + +diff@1.4.0, diff@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" + +doctrine@^1.2.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +dot-prop@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" + dependencies: + is-obj "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +editions@^1.1.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" + +editor@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +ember-ajax@^2.0.1: + version "2.5.3" + resolved "https://registry.yarnpkg.com/ember-ajax/-/ember-ajax-2.5.3.tgz#02dded6c132290edd47ee9862a7a8821c6919dad" + dependencies: + ember-cli-babel "^5.1.5" + +ember-cli-app-version@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-1.0.1.tgz#d135eba75f30e791d8a5e5844f1251dcbcc40438" + dependencies: + ember-cli-babel "^5.1.6" + ember-cli-htmlbars "^1.0.0" + git-repo-version "0.3.0" + +ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.1.7, ember-cli-babel@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-5.2.1.tgz#14a1a7b3ae9e9f1284f7bcdb142eb53bd0b1b5bd" + dependencies: + broccoli-babel-transpiler "^5.6.0" + broccoli-funnel "^1.0.0" + clone "^2.0.0" + ember-cli-version-checker "^1.0.2" + resolve "^1.1.2" + +ember-cli-blueprint-test-helpers@0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" + dependencies: + chai "^3.3.0" + chai-as-promised "^5.1.0" + chai-files "^1.0.0" + debug "^2.2.0" + ember-cli-internal-test-helpers "^0.8.1" + exists-sync "0.0.3" + findup "^0.1.5" + fs-extra "^0.26.7" + tmp-sync "^1.0.0" + walk-sync "^0.2.5" + +ember-cli-broccoli-sane-watcher@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.0.4.tgz#f43f42f75b7509c212fb926cd9aea86ae19264c6" + dependencies: + broccoli-slow-trees "^3.0.1" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + rsvp "^3.0.18" + sane "^1.1.1" + +ember-cli-dependency-checker@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ember-cli-dependency-checker/-/ember-cli-dependency-checker-1.3.0.tgz#f0e8cb7f0f43c1e560494eaa9372804e7a088a2a" + dependencies: + chalk "^0.5.1" + is-git-url "0.2.0" + semver "^4.1.0" + +ember-cli-eslint@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ember-cli-eslint/-/ember-cli-eslint-1.3.0.tgz#8a7eda0d7e6a00c5a5a823f59664932d6429a8f1" + dependencies: + broccoli-lint-eslint "^2.0.0" + ember-cli-babel "^5.1.5" + js-string-escape "^1.0.0" + +ember-cli-get-component-path-option@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" + +ember-cli-get-dependency-depth@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" + +ember-cli-htmlbars-inline-precompile@^0.3.1: + version "0.3.6" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.3.6.tgz#4095fe423f93102724c0725e4dd1a31f25e24de5" + dependencies: + babel-plugin-htmlbars-inline-precompile "^0.1.0" + ember-cli-babel "^5.1.3" + ember-cli-htmlbars "^1.0.0" + hash-for-dep "^1.0.2" + +ember-cli-htmlbars@^1.0.0, ember-cli-htmlbars@^1.0.3: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-1.1.1.tgz#8776cf59796dac8f32e8625fc6d1ea45ffa55de1" + dependencies: + broccoli-persistent-filter "^1.0.3" + ember-cli-version-checker "^1.0.2" + hash-for-dep "^1.0.2" + json-stable-stringify "^1.0.0" + strip-bom "^2.0.0" + +ember-cli-inject-live-reload@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.4.1.tgz#ddadb9a346c5ed694ec0f9e11f49994eacafd277" + +ember-cli-internal-test-helpers@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.8.3.tgz#e9b7db67f3fda4db736d1a319a282c04beada495" + dependencies: + chai "^3.3.0" + chai-as-promised "^6.0.0" + chai-files "^1.1.0" + chalk "^1.1.1" + configstore "^2.0.0" + debug "^2.2.0" + exists-sync "0.0.3" + fs-extra "^0.30.0" + lodash "^4.0.0" + rsvp "^3.0.17" + symlink-or-copy "^1.0.1" + through "^2.3.8" + walk-sync "^0.3.1" + +ember-cli-is-package-missing@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" + +ember-cli-legacy-blueprints@^0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.4.tgz#83d6c005ac0e39750ff9dd45cd1b78cf697150c6" + dependencies: + chalk "^1.1.1" + ember-cli-get-component-path-option "^1.0.0" + ember-cli-get-dependency-depth "^1.0.0" + ember-cli-is-package-missing "^1.0.0" + ember-cli-lodash-subset "^1.0.7" + ember-cli-normalize-entity-name "^1.0.0" + ember-cli-path-utils "^1.0.0" + ember-cli-string-utils "^1.0.0" + ember-cli-test-info "^1.0.0" + ember-cli-valid-component-name "^1.0.0" + ember-cli-version-checker "^1.1.7" + ember-router-generator "^1.0.0" + exists-sync "0.0.3" + fs-extra "^0.24.0" + inflection "^1.7.1" + rsvp "^3.0.17" + silent-error "^1.0.0" + +ember-cli-lodash-subset@^1.0.11, ember-cli-lodash-subset@^1.0.7: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.11.tgz#0149eef9c0c3505ba44ed202f8d034ddbbfb2826" + +ember-cli-normalize-entity-name@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" + dependencies: + silent-error "^1.0.0" + +ember-cli-path-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" + +ember-cli-preprocess-registry@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.0.0.tgz#5a7e6a4048a895856c8a54ed145cf92153b2ab96" + dependencies: + broccoli-clean-css "^1.1.0" + broccoli-funnel "^1.0.0" + broccoli-merge-trees "^1.0.0" + debug "^2.2.0" + exists-sync "0.0.3" + lodash "^4.5.0" + process-relative-require "^1.0.0" + silent-error "^1.0.0" + +ember-cli-pretender@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/ember-cli-pretender/-/ember-cli-pretender-0.6.0.tgz#7525ffa3081b8ba7b0791f24f1f229d83e87bd1e" + +ember-cli-qunit@^2.1.0: + version "2.2.5" + resolved "https://registry.yarnpkg.com/ember-cli-qunit/-/ember-cli-qunit-2.2.5.tgz#c8a2bf4e018e674089388d07d63adf1a3f270b74" + dependencies: + broccoli-babel-transpiler "^5.5.0" + broccoli-concat "^2.2.0" + broccoli-funnel "^1.0.1" + broccoli-merge-trees "^1.1.0" + ember-cli-babel "^5.1.5" + ember-cli-version-checker "^1.1.4" + ember-qunit "^0.4.18" + qunit-notifications "^0.1.1" + qunitjs "^1.20.0" + resolve "^1.1.6" + rsvp "^3.2.1" + +ember-cli-release@^0.2.9: + version "0.2.9" + resolved "https://registry.yarnpkg.com/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" + dependencies: + chalk "^1.0.0" + git-tools "^0.1.4" + make-array "^0.1.2" + merge "^1.2.0" + moment-timezone "^0.3.0" + nopt "^3.0.3" + rsvp "^3.0.17" + semver "^4.3.1" + silent-error "^1.0.0" + +ember-cli-sri@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" + dependencies: + broccoli-sri-hash "^2.1.0" + +ember-cli-string-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.0.0.tgz#d07b17d0b6223c42e09bfb835ee2b8466ec9b88e" + +ember-cli-test-info@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" + dependencies: + ember-cli-string-utils "^1.0.0" + +ember-cli-test-loader@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ember-cli-test-loader/-/ember-cli-test-loader-1.1.1.tgz#333311209b18185d0e0e95f918349da10cacf0b1" + dependencies: + ember-cli-babel "^5.2.1" + +ember-cli-uglify@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ember-cli-uglify/-/ember-cli-uglify-1.2.0.tgz#3208c32b54bc2783056e8bb0d5cfe9bbaf17ffb2" + dependencies: + broccoli-uglify-sourcemap "^1.0.0" + +ember-cli-valid-component-name@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" + dependencies: + silent-error "^1.0.0" + +ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-1.2.0.tgz#caa286b77d1b485df5d2f62c67a6f19aa8b582c4" + dependencies: + semver "^5.3.0" + +ember-cli@^2.8.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-2.10.0.tgz#3aefd56a207f60be1ba120aeacd41e7e7a9383d8" + dependencies: + amd-name-resolver "0.0.6" + bower "^1.3.12" + bower-config "^1.3.0" + bower-endpoint-parser "0.2.2" + broccoli-babel-transpiler "^5.4.5" + broccoli-brocfile-loader "^0.18.0" + broccoli-builder "^0.18.0" + broccoli-concat "^3.0.4" + broccoli-config-loader "^1.0.0" + broccoli-config-replace "^1.1.2" + broccoli-funnel "^1.0.6" + broccoli-funnel-reducer "^1.0.0" + broccoli-merge-trees "^1.1.3" + broccoli-middleware "^0.18.1" + broccoli-source "^1.1.0" + broccoli-stew "^1.2.0" + capture-exit "^1.0.4" + chalk "^1.1.3" + clean-base-url "^1.0.0" + compression "^1.4.4" + configstore "^2.0.0" + core-object "^2.0.2" + diff "^1.3.1" + ember-cli-broccoli-sane-watcher "^2.0.3" + ember-cli-get-component-path-option "^1.0.0" + ember-cli-is-package-missing "^1.0.0" + ember-cli-legacy-blueprints "^0.1.2" + ember-cli-lodash-subset "^1.0.11" + ember-cli-normalize-entity-name "^1.0.0" + ember-cli-preprocess-registry "^3.0.0" + ember-cli-string-utils "^1.0.0" + ember-try "^0.2.6" + escape-string-regexp "^1.0.3" + exists-sync "0.0.3" + exit "^0.1.2" + express "^4.12.3" + filesize "^3.1.3" + find-up "^1.1.2" + fs-extra "0.30.0" + fs-tree-diff "^0.5.2" + get-caller-file "^1.0.0" + git-repo-info "^1.0.4" + glob "7.1.1" + heimdalljs-fs-monitor "^0.0.3" + heimdalljs-logger "^0.1.7" + http-proxy "^1.9.0" + inflection "^1.7.0" + inquirer "^1.2.1" + is-git-url "^0.2.0" + isbinaryfile "^3.0.0" + js-yaml "^3.6.1" + leek "0.0.23" + lodash.template "^4.2.5" + markdown-it "8.0.0" + markdown-it-terminal "0.0.4" + minimatch "^3.0.0" + morgan "^1.5.2" + node-modules-path "^1.0.0" + node-uuid "^1.4.3" + nopt "^3.0.1" + npm "3.10.8" + npm-package-arg "^4.1.1" + ora "^0.2.0" + portfinder "^1.0.7" + promise-map-series "^0.2.1" + quick-temp "0.1.6" + resolve "^1.1.6" + rsvp "^3.3.3" + sane "^1.1.1" + semver "^5.1.1" + silent-error "^1.0.0" + sort-package-json "^1.4.0" + symlink-or-copy "^1.0.1" + temp "0.8.3" + testem "^1.8.1" + through "^2.3.6" + tiny-lr "^1.0.3" + tree-sync "^1.1.4" + walk-sync "^0.3.0" + yam "0.0.22" + +ember-dev@emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed: + version "0.0.0" + resolved "https://codeload.github.com/emberjs/ember-dev/tar.gz/bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed" + dependencies: + ember-cli-babel "^5.0.0" + +ember-disable-prototype-extensions@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.0.tgz#86081c8cf6741f26e4b89e2b004f761174313e01" + dependencies: + ember-cli-babel "^5.1.5" + +ember-disable-proxy-controllers@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" + dependencies: + ember-cli-babel "^5.0.0" + +ember-export-application-global@^1.0.5: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ember-export-application-global/-/ember-export-application-global-1.1.1.tgz#f257d5271268932a89d7392679ce4db89d7154af" + dependencies: + ember-cli-babel "^5.1.10" + +ember-inflector@^1.9.4: + version "1.11.0" + resolved "https://registry.yarnpkg.com/ember-inflector/-/ember-inflector-1.11.0.tgz#99baae18e2bee53cfa97d8db1d739280289a174f" + dependencies: + ember-cli-babel "^5.1.7" + +ember-load-initializers@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/ember-load-initializers/-/ember-load-initializers-0.5.1.tgz#76e3db23c111dbdcd3ae6f687036bf0b56be0cbe" + +ember-publisher@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" + dependencies: + aws-sdk "^2.0.9" + +ember-qunit@^0.4.18: + version "0.4.22" + resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-0.4.22.tgz#bc389798e1a4a933f542863025e2fb91d856da49" + dependencies: + ember-test-helpers "^0.5.32" + +ember-resolver@^2.0.3: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-2.1.1.tgz#5e4c1fffe9f5f48fc2194ad7592274ed0cd74f72" + dependencies: + ember-cli-babel "^5.1.6" + ember-cli-version-checker "^1.1.6" + +ember-router-generator@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.2.tgz#62dac1f63e873553e6d4c7e32da6589e577bcf63" + dependencies: + recast "^0.11.3" + +ember-runtime-enumerable-includes-polyfill@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-1.0.4.tgz#16a7612e347a2edf07da8b2f2f09dbfee70deba0" + dependencies: + ember-cli-babel "^5.1.6" + ember-cli-version-checker "^1.1.6" + +ember-test-helpers@^0.5.32: + version "0.5.34" + resolved "https://registry.yarnpkg.com/ember-test-helpers/-/ember-test-helpers-0.5.34.tgz#c8439108d1cba1d7d838c212208a5c4061471b83" + dependencies: + klassy "^0.1.3" + +ember-try-config@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ember-try-config/-/ember-try-config-2.1.0.tgz#e0e156229a542346a58ee6f6ad605104c98edfe0" + dependencies: + lodash "^4.6.1" + node-fetch "^1.3.3" + rsvp "^3.2.1" + semver "^5.1.0" + +ember-try@^0.2.6: + version "0.2.8" + resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.8.tgz#5f135d23d83561dc8dfb4a4d998420b69b740acd" + dependencies: + chalk "^1.0.0" + cli-table2 "^0.2.0" + core-object "^1.1.0" + debug "^2.2.0" + ember-cli-babel "^5.1.3" + ember-cli-version-checker "^1.1.6" + ember-try-config "^2.0.1" + extend "^3.0.0" + fs-extra "^0.26.0" + promise-map-series "^0.2.1" + resolve "^1.1.6" + rimraf "^2.3.2" + rsvp "^3.0.17" + semver "^5.1.0" + sync-exec "^0.6.2" + +ember-watson@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" + dependencies: + babel-core "^5.8.22" + chalk "^1.0.0" + commander "^2.6.0" + exists-sync "0.0.3" + inflected "^1.1.6" + recast "^0.10.29" + walk-sync "^0.1.3" + +encodeurl@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + +engine.io-client@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.0.tgz#7b730e4127414087596d9be3c88d2bc5fdb6cf5c" + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "2.3.3" + engine.io-parser "1.3.1" + has-cors "1.1.0" + indexof "0.0.1" + parsejson "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + ws "1.1.1" + xmlhttprequest-ssl "1.5.3" + yeast "0.1.2" + +engine.io-parser@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" + dependencies: + after "0.8.1" + arraybuffer.slice "0.0.6" + base64-arraybuffer "0.1.5" + blob "0.0.4" + has-binary "0.1.6" + wtf-8 "1.0.0" + +engine.io@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" + dependencies: + accepts "1.3.3" + base64id "0.1.0" + cookie "0.3.1" + debug "2.3.3" + engine.io-parser "1.3.1" + ws "1.1.1" + +ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" + +entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + +error-ex@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.0.tgz#e67b43f3e82c96ea3a584ffee0b9fc3325d802d9" + dependencies: + is-arrayish "^0.2.1" + +error@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" + dependencies: + string-template "~0.2.1" + xtend "~4.0.0" + +es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: + version "0.10.12" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" + dependencies: + es6-iterator "2" + es6-symbol "~3.1" + +es6-iterator@2: + version "2.0.0" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" + dependencies: + d "^0.1.1" + es5-ext "^0.10.7" + es6-symbol "3" + +es6-map@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-iterator "2" + es6-set "~0.1.3" + es6-symbol "~3.1.0" + event-emitter "~0.3.4" + +es6-promise@~4.0.3: + version "4.0.5" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" + +es6-set@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-iterator "2" + es6-symbol "3" + event-emitter "~0.3.4" + +es6-symbol@3, es6-symbol@^3.0.2, es6-symbol@~3.1, es6-symbol@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + +es6-weak-map@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" + dependencies: + d "^0.1.1" + es5-ext "^0.10.8" + es6-iterator "2" + es6-symbol "3" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" + +escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escope@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + dependencies: + es6-map "^0.1.3" + es6-weak-map "^2.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint@^2.13.0: + version "2.13.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" + dependencies: + chalk "^1.1.3" + concat-stream "^1.4.6" + debug "^2.1.1" + doctrine "^1.2.2" + es6-map "^0.1.3" + escope "^3.6.0" + espree "^3.1.6" + estraverse "^4.2.0" + esutils "^2.0.2" + file-entry-cache "^1.1.1" + glob "^7.0.3" + globals "^9.2.0" + ignore "^3.1.2" + imurmurhash "^0.1.4" + inquirer "^0.12.0" + is-my-json-valid "^2.10.0" + is-resolvable "^1.0.0" + js-yaml "^3.5.1" + json-stable-stringify "^1.0.0" + levn "^0.3.0" + lodash "^4.0.0" + mkdirp "^0.5.0" + optionator "^0.8.1" + path-is-absolute "^1.0.0" + path-is-inside "^1.0.1" + pluralize "^1.2.1" + progress "^1.1.8" + require-uncached "^1.0.2" + shelljs "^0.6.0" + strip-json-comments "~1.0.1" + table "^3.7.8" + text-table "~0.2.0" + user-home "^2.0.0" + +espree@^3.1.6: + version "3.3.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.3.2.tgz#dbf3fadeb4ecb4d4778303e50103b3d36c88b89c" + dependencies: + acorn "^4.0.1" + acorn-jsx "^3.0.0" + +esprima-fb@~12001.1.0-dev-harmony-fb: + version "12001.1.0-dev-harmony-fb" + resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-12001.1.0-dev-harmony-fb.tgz#d84400384ba95ce2678c617ad24a7f40808da915" + +esprima-fb@~15001.1001.0-dev-harmony-fb: + version "15001.1001.0-dev-harmony-fb" + resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" + +esprima@^1.2.2: + version "1.2.5" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" + +esprima@^2.6.0: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +esprima@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" + +esprima@~3.1.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + +esprimaq@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" + +esrecurse@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + dependencies: + estraverse "~4.1.0" + object-assign "^4.0.1" + +estraverse@^4.1.1, estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +estraverse@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" + +esutils@^2.0.0, esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@~1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" + +event-emitter@~0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" + dependencies: + d "~0.1.1" + es5-ext "~0.10.7" + +eventemitter3@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" + +events-to-array@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.0.2.tgz#b3484465534fe4ff66fbdd1a83b777713ba404aa" + +exec-sh@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" + dependencies: + merge "^1.1.3" + +exists-sync@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" + +exists-sync@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" + +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +expand-tilde@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" + dependencies: + os-homedir "^1.0.1" + +express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: + version "4.14.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.14.0.tgz#c1ee3f42cdc891fb3dc650a8922d51ec847d0d66" + dependencies: + accepts "~1.3.3" + array-flatten "1.1.1" + content-disposition "0.5.1" + content-type "~1.0.2" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "~2.2.0" + depd "~1.1.0" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.7.0" + finalhandler "0.5.0" + fresh "0.3.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.1" + path-to-regexp "0.1.7" + proxy-addr "~1.1.2" + qs "6.2.0" + range-parser "~1.2.0" + send "0.14.1" + serve-static "~1.11.1" + type-is "~1.6.13" + utils-merge "1.0.0" + vary "~1.1.0" + +extend@^3.0.0, extend@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + +external-editor@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" + dependencies: + extend "^3.0.0" + spawn-sync "^1.0.15" + tmp "^0.0.29" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extract-zip@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4" + dependencies: + concat-stream "1.5.0" + debug "0.7.4" + mkdirp "0.5.0" + yauzl "2.4.1" + +extsprintf@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + +fake-xml-http-request@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-1.4.0.tgz#6481c727a0eae9c420bae229dcdfc5369c4b5477" + +faker@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/faker/-/faker-3.1.0.tgz#0f908faf4e6ec02524e54a57e432c5c013e08c9f" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" + dependencies: + blank-object "^1.0.1" + +fast-sourcemap-concat@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fast-sourcemap-concat/-/fast-sourcemap-concat-1.1.0.tgz#a800767abed5eda02e67238ec063a709be61f9d4" + dependencies: + chalk "^0.5.1" + debug "^2.2.0" + fs-extra "^0.30.0" + memory-streams "^0.1.0" + mkdirp "^0.5.0" + rsvp "^3.0.14" + source-map "^0.4.2" + source-map-url "^0.3.0" + +faye-websocket@~0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + dependencies: + websocket-driver ">=0.5.1" + +fb-watchman@^1.8.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.0.tgz#6f268f1f347a6b3c875d1e89da7e1ed79adfc0ec" + dependencies: + bser "^1.0.2" + +fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + dependencies: + pend "~1.2.0" + +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +file-entry-cache@^1.1.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +filename-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + +filesize@^3.1.3: + version "3.3.0" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.3.0.tgz#53149ea3460e3b2e024962a51648aa572cf98122" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +finalhandler@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.0.tgz#e9508abece9b6dba871a6942a1d7911b91911ac7" + dependencies: + debug "~2.2.0" + escape-html "~1.0.3" + on-finished "~2.3.0" + statuses "~1.3.0" + unpipe "~1.0.0" + +find-up@^1.0.0, find-up@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +findup-sync@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" + dependencies: + detect-file "^0.1.0" + is-glob "^2.0.1" + micromatch "^2.3.7" + resolve-dir "^0.1.0" + +findup@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" + dependencies: + colors "~0.6.0-1" + commander "~2.1.0" + +fireworm@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" + dependencies: + async "~0.2.9" + is-type "0.0.1" + lodash.debounce "^3.1.1" + lodash.flatten "^3.0.2" + minimatch "^3.0.2" + +flat-cache@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" + dependencies: + circular-json "^0.3.1" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + +for-in@^0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" + +for-own@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" + dependencies: + for-in "^0.1.5" + +forever-agent@~0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~0.1.0: + version "0.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" + dependencies: + async "~0.9.0" + combined-stream "~0.0.4" + mime "~1.2.11" + +form-data@~1.0.0-rc4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" + dependencies: + async "^2.0.1" + combined-stream "^1.0.5" + mime-types "^2.1.11" + +form-data@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +forwarded@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" + +fresh@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" + +fs-exists-sync@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + +fs-extra@0.30.0, fs-extra@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-extra@^0.24.0: + version "0.24.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-extra@^0.26.0, fs-extra@^0.26.7: + version "0.26.7" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-extra@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + +fs-readdir-recursive@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" + +fs-sync@^0.2.4: + version "0.2.6" + resolved "https://registry.yarnpkg.com/fs-sync/-/fs-sync-0.2.6.tgz#657116c12b95ac9a36c51a850066c9ee6441fe06" + dependencies: + glob "~4.0.4" + iconv-lite "~0.2.10" + lodash "~1.2.1" + mkdirp "~0.3.5" + rimraf "~2.1.4" + +fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-0.5.6.tgz#342665749e8dca406800b672268c8f5073f3e623" + dependencies: + heimdalljs-logger "^0.1.7" + object-assign "^4.1.0" + path-posix "^1.0.0" + symlink-or-copy "^1.1.8" + +fs-vacuum@~1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/fs-vacuum/-/fs-vacuum-1.2.9.tgz#4f90193ab8ea02890995bcd4e804659a5d366b2d" + dependencies: + graceful-fs "^4.1.2" + path-is-inside "^1.0.1" + rimraf "^2.5.2" + +fs-write-stream-atomic@~1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.8.tgz#e49aaddf288f87d46ff9e882f216a13abc40778b" + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fstream-ignore@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream-npm@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fstream-npm/-/fstream-npm-1.2.0.tgz#d2c3c89101346982d64e57091c38487bda916fce" + dependencies: + fstream-ignore "^1.0.0" + inherits "2" + +fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +gauge@~2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.6.0.tgz#d35301ad18e96902b4751dcbbe40f4218b942a46" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-color "^0.1.7" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gauge@~2.7.1: + version "2.7.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + supports-color "^0.2.0" + wide-align "^1.1.0" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +get-caller-file@^1.0.0, get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + +getpass@^0.1.1: + version "0.1.6" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + dependencies: + assert-plus "^1.0.0" + +git-repo-info@^1.0.4, git-repo-info@^1.1.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.4.0.tgz#ed210221defd3fdefce8b16ac61985cabe242e4a" + +git-repo-version@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-0.3.0.tgz#c9b97d0d21c4357d669dc1269c2b6a75da6cc0e9" + dependencies: + git-repo-info "^1.0.4" + +git-tools@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" + dependencies: + spawnback "~1.0.0" + +github@^0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/github/-/github-0.2.4.tgz#24fa7f0e13fa11b946af91134c51982a91ce538b" + dependencies: + mime "^1.2.11" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" + dependencies: + graceful-fs "~2.0.0" + inherits "2" + minimatch "~0.2.11" + +glob@5.0.13, glob@^5.0.10: + version "5.0.13" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "^2.0.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^4.3.1, glob@^4.3.2: + version "4.5.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "^2.0.1" + once "^1.3.0" + +glob@^5.0.15: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^6.0.0: + version "6.0.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@~4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-4.0.6.tgz#695c50bdd4e2fb5c5d370b091f388d3707e291a7" + dependencies: + graceful-fs "^3.0.2" + inherits "2" + minimatch "^1.0.0" + once "^1.3.0" + +glob@~7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-modules@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" + dependencies: + global-prefix "^0.1.4" + is-windows "^0.2.0" + +global-prefix@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" + dependencies: + homedir-polyfill "^1.0.0" + ini "^1.3.4" + is-windows "^0.2.0" + which "^1.2.12" + +globals@^6.4.0: + version "6.4.1" + resolved "https://registry.yarnpkg.com/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" + +globals@^9.2.0: + version "9.14.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +graceful-fs@^3.0.2: + version "3.0.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" + dependencies: + natives "^1.1.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.6: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +graceful-fs@~1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" + +graceful-fs@~2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +growl@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428" + +growly@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + +handlebars@^4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" + dependencies: + async "^1.4.0" + optimist "^0.6.1" + source-map "^0.4.4" + optionalDependencies: + uglify-js "^2.6" + +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + +has-ansi@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" + dependencies: + ansi-regex "^0.2.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-binary@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" + dependencies: + isarray "0.0.1" + +has-binary@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" + dependencies: + isarray "0.0.1" + +has-color@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + +has-unicode@^2.0.0, has-unicode@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +hash-for-dep@^1.0.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.1.2.tgz#e3347ed92960eb0bb53a2c6c2b70e36d75b7cd0c" + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + heimdalljs "^0.2.3" + heimdalljs-logger "^0.1.7" + resolve "^1.1.6" + +hasha@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1" + dependencies: + is-stream "^1.0.1" + pinkie-promise "^2.0.0" + +hawk@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" + dependencies: + boom "0.4.x" + cryptiles "0.2.x" + hoek "0.9.x" + sntp "0.2.x" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +heimdall-query@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" + dependencies: + chalk "^1.1.1" + chrome-debugging-client "^0.2.4" + cli-table "^0.3.1" + lodash "^4.15.0" + plain-text-box-plot "0.0.1" + progress "^1.1.8" + selenium-webdriver "^3.0.0-beta-2" + +heimdalljs-fs-monitor@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.0.3.tgz#468a1afa5d31ba58fb199fcdb5b0007dca69e63d" + dependencies: + heimdalljs "^0.2.0" + +heimdalljs-logger@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.7.tgz#10e340af5c22a811e34522d9b9397675ad589ca4" + dependencies: + debug "^2.2.0" + heimdalljs "^0.2.0" + +heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.3.tgz#35b82a6a4d73541fc4fb88d2fe2b23608fb4f779" + dependencies: + rsvp "~3.2.1" + +heimdalljs@^0.3.0: + version "0.3.2" + resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.3.2.tgz#d19f98cf7c6a7660c2ecbbeaa696db3436227713" + dependencies: + rsvp "~3.2.1" + +hoek@0.9.x: + version "0.9.1" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +home-or-tmp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" + dependencies: + os-tmpdir "^1.0.1" + user-home "^1.1.1" + +homedir-polyfill@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + dependencies: + parse-passwd "^1.0.0" + +hosted-git-info@^2.1.4, hosted-git-info@^2.1.5, hosted-git-info@~2.1.5: + version "2.1.5" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" + +http-errors@~1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" + dependencies: + inherits "2.0.3" + setprototypeof "1.0.2" + statuses ">= 1.3.1 < 2" + +http-proxy@^1.13.1, http-proxy@^1.9.0: + version "1.16.2" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" + dependencies: + eventemitter3 "1.x.x" + requires-port "1.x.x" + +http-signature@~0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" + dependencies: + asn1 "0.1.11" + assert-plus "^0.1.5" + ctype "0.5.3" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +iconv-lite@0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13: + version "0.4.13" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" + +iconv-lite@~0.2.10: + version "0.2.11" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8" + +ieee754@^1.1.4: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + +iferr@^0.1.5, iferr@~0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + +ignore@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" + +imurmurhash@*, imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflected@^1.1.6: + version "1.1.7" + resolved "https://registry.yarnpkg.com/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" + +inflection@^1.7.0, inflection@^1.7.1, inflection@^1.8.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.10.0.tgz#5bffcb1197ad3e81050f8e17e21668087ee9eb2f" + +inflight@^1.0.4, inflight@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +ini@^1.3.4, ini@~1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +init-package-json@~1.9.4: + version "1.9.4" + resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-1.9.4.tgz#b4053d0b40f0cf842a41966937cb3dc0f534e856" + dependencies: + glob "^6.0.0" + npm-package-arg "^4.0.0" + promzard "^0.3.0" + read "~1.0.1" + read-package-json "1 || 2" + semver "2.x || 3.x || 4 || 5" + validate-npm-package-license "^3.0.1" + validate-npm-package-name "^2.0.1" + +inline-source-map-comment@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" + dependencies: + chalk "^1.0.0" + get-stdin "^4.0.1" + minimist "^1.1.1" + sum-up "^1.0.1" + xtend "^4.0.0" + +inquirer@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + dependencies: + ansi-escapes "^1.1.0" + ansi-regex "^2.0.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + figures "^1.3.5" + lodash "^4.3.0" + readline2 "^1.0.1" + run-async "^0.1.0" + rx-lite "^3.1.2" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + +inquirer@^1.2.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918" + dependencies: + ansi-escapes "^1.1.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + external-editor "^1.1.0" + figures "^1.3.5" + lodash "^4.3.0" + mute-stream "0.0.6" + pinkie-promise "^2.0.0" + run-async "^2.2.0" + rx "^4.1.0" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +ipaddr.js@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.1.1.tgz#c791d95f52b29c1247d5df80ada39b8a73647230" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-buffer@^1.0.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-dotfile@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-git-url@0.2.0, is-git-url@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-0.2.0.tgz#b9ce0fb044821c88880213d602db03bdb255da1b" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-integer@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-integer/-/is-integer-1.0.6.tgz#5273819fada880d123e1ac00a938e7172dd8d95e" + dependencies: + is-finite "^1.0.0" + +is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-number@^2.0.2, is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + dependencies: + path-is-inside "^1.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-resolvable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + dependencies: + tryit "^1.0.1" + +is-stream@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-type@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" + dependencies: + core-util-is "~1.0.0" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +is-windows@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isbinaryfile@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" + +isexe@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +istextorbinary@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" + dependencies: + binaryextensions "1 || 2" + editions "^1.1.1" + textextensions "1 || 2" + +jade@0.26.3: + version "0.26.3" + resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" + dependencies: + commander "0.6.1" + mkdirp "0.3.0" + +jju@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jju/-/jju-1.3.0.tgz#dadd9ef01924bc728b03f2f7979bdbd62f7a2aaa" + +jmespath@0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + +jodid25519@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + dependencies: + jsbn "~0.1.0" + +js-string-escape@^1.0.0, js-string-escape@^1.0.1, js-string-escape@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" + +js-tokens@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" + +js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +jsbn@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-api-mock-server@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/json-api-mock-server/-/json-api-mock-server-0.1.1.tgz#00acb22ac58127e87fa9a172159cd8ed558e8106" + dependencies: + body-parser "^1.15.2" + chalk "^1.1.1" + express "^4.14.0" + glob "^7.1.1" + jsonapi-validator "^2.1.1" + object-assign "^4.1.0" + +json-parse-helpfulerror@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz#13f14ce02eed4e981297b64eb9e3b932e2dd13dc" + dependencies: + jju "^1.1.0" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json3@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + +json5@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" + +jsonapi-validator@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/jsonapi-validator/-/jsonapi-validator-2.2.0.tgz#07f9bdb6d118c1e728fa77280605fa9b527f8c66" + dependencies: + ajv "^4.1.3" + yargs "^5.0.0" + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +jsprim@^1.2.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + dependencies: + extsprintf "1.0.2" + json-schema "0.2.3" + verror "1.3.6" + +kew@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" + +kind-of@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" + dependencies: + is-buffer "^1.0.2" + +klassy@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/klassy/-/klassy-0.1.3.tgz#c31d5756d583197d75f582b6e692872be497067f" + +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + optionalDependencies: + graceful-fs "^4.1.9" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +leek@0.0.23: + version "0.0.23" + resolved "https://registry.yarnpkg.com/leek/-/leek-0.0.23.tgz#d44b9f55b27e22902a6603eaeec193f0c301d25f" + dependencies: + debug "^2.1.0" + lodash.assign "^3.2.0" + rsvp "^3.0.21" + +leven@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +linkify-it@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" + dependencies: + uc.micro "^1.0.1" + +linkify-it@~1.2.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" + dependencies: + uc.micro "^1.0.1" + +livereload-js@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +loader.js@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.1.0.tgz#1d0897a62f8b7375d3d9cd1ae6acf798c36c1ffe" + +lockfile@~1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.3.tgz#2638fc39a0331e9cac1a04b71799931c9c50df79" + +lodash-node@^3.2.0: + version "3.10.2" + resolved "https://registry.yarnpkg.com/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" + +lodash._arraycopy@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" + +lodash._arrayeach@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" + +lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._baseclone@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz#303519bf6393fe7e42f34d8b630ef7794e3542b7" + dependencies: + lodash._arraycopy "^3.0.0" + lodash._arrayeach "^3.0.0" + lodash._baseassign "^3.0.0" + lodash._basefor "^3.0.0" + lodash.isarray "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + +lodash._baseflatten@^3.0.0: + version "3.1.4" + resolved "https://registry.yarnpkg.com/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" + dependencies: + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash._basefor@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" + +lodash._baseindexof@*: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" + +lodash._baseuniq@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" + dependencies: + lodash._createset "~4.0.0" + lodash._root "~3.0.0" + +lodash._bindcallback@*, lodash._bindcallback@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + +lodash._cacheindexof@*: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" + +lodash._createassigner@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + dependencies: + lodash._bindcallback "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash.restparam "^3.0.0" + +lodash._createcache@*: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" + dependencies: + lodash._getnative "^3.0.0" + +lodash._createset@~4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" + +lodash._getnative@*, lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + +lodash._reinterpolate@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + +lodash._root@~3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + +lodash.assign@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + dependencies: + lodash._baseassign "^3.0.0" + lodash._createassigner "^3.0.0" + lodash.keys "^3.0.0" + +lodash.assign@^4.1.0, lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + +lodash.assignin@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + +lodash.clonedeep@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz#a0a1e40d82a5ea89ff5b147b8444ed63d92827db" + dependencies: + lodash._baseclone "^3.0.0" + lodash._bindcallback "^3.0.0" + +lodash.clonedeep@^4.4.1, lodash.clonedeep@~4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + +lodash.debounce@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" + dependencies: + lodash._getnative "^3.0.0" + +lodash.find@^4.5.1: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" + +lodash.flatten@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" + dependencies: + lodash._baseflatten "^3.0.0" + lodash._isiterateecall "^3.0.0" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + +lodash.isplainobject@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" + dependencies: + lodash._basefor "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.keysin "^3.0.0" + +lodash.istypedarray@^3.0.0: + version "3.0.6" + resolved "https://registry.yarnpkg.com/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.keysin@^3.0.0: + version "3.0.8" + resolved "https://registry.yarnpkg.com/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" + dependencies: + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.merge@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-3.3.2.tgz#0d90d93ed637b1878437bb3e21601260d7afe994" + dependencies: + lodash._arraycopy "^3.0.0" + lodash._arrayeach "^3.0.0" + lodash._createassigner "^3.0.0" + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + lodash.isplainobject "^3.0.0" + lodash.istypedarray "^3.0.0" + lodash.keys "^3.0.0" + lodash.keysin "^3.0.0" + lodash.toplainobject "^3.0.0" + +lodash.merge@^4.3.0, lodash.merge@^4.4.0, lodash.merge@^4.5.1: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" + +lodash.omit@^4.1.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" + +lodash.restparam@*, lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + +lodash.template@^4.2.5: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" + dependencies: + lodash._reinterpolate "~3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" + dependencies: + lodash._reinterpolate "~3.0.0" + +lodash.toplainobject@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz#28790ad942d293d78aa663a07ecf7f52ca04198d" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keysin "^3.0.0" + +lodash.union@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + +lodash.uniq@^4.2.0, lodash.uniq@~4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + +lodash.without@~4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" + +lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: + version "3.10.1" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.1: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +lodash@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.2.1.tgz#ed47b16e46f06b2b40309b68e9163c17e93ea304" + +lodash@~3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.5.0.tgz#19bb3f4d51278f0b8c818ed145c74ecf9fe40e6d" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +lru-cache@2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + +lru-cache@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" + dependencies: + pseudomap "^1.0.1" + yallist "^2.0.0" + +make-array@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + dependencies: + tmpl "1.0.x" + +markdown-it-terminal@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/markdown-it-terminal/-/markdown-it-terminal-0.0.4.tgz#3f2ce624ba2ca964a78b8b388d605ee330de9ced" + dependencies: + ansi-styles "^2.1.0" + cardinal "^0.5.0" + cli-table "^0.3.1" + lodash.merge "^3.3.2" + markdown-it "^4.4.0" + +markdown-it@8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.0.0.tgz#e66255497a0e409e816fbc67807975f4f26f6f82" + dependencies: + argparse "^1.0.7" + entities "~1.1.1" + linkify-it "^2.0.0" + mdurl "^1.0.1" + uc.micro "^1.0.3" + +markdown-it@^4.3.0, markdown-it@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" + dependencies: + argparse "~1.0.2" + entities "~1.1.1" + linkify-it "~1.2.0" + mdurl "~1.0.0" + uc.micro "^1.0.0" + +marked-terminal@^1.6.2: + version "1.7.0" + resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-1.7.0.tgz#c8c460881c772c7604b64367007ee5f77f125904" + dependencies: + cardinal "^1.0.0" + chalk "^1.1.3" + cli-table "^0.3.1" + lodash.assign "^4.2.0" + node-emoji "^1.4.1" + +marked@^0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7" + +matcher-collection@^1.0.0, matcher-collection@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-1.0.4.tgz#2f66ae0869996f29e43d0b62c83dd1d43e581755" + dependencies: + minimatch "^3.0.2" + +md5-hex@^1.0.2, md5-hex@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" + dependencies: + md5-o-matic "^0.1.1" + +md5-o-matic@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" + +mdn-links@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" + +mdurl@^1.0.1, mdurl@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +memory-streams@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.0.tgz#bec658a71e3f28b0f0c2f1b14501c2db547d5f7a" + dependencies: + readable-stream "~1.0.2" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +merge@^1.1.3, merge@^1.2.0, merge@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^2.1.5, micromatch@^2.3.7: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +"mime-db@>= 1.24.0 < 2", mime-db@~1.25.0: + version "1.25.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392" + +mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: + version "2.1.13" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88" + dependencies: + mime-db "~1.25.0" + +mime-types@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" + +mime@1.3.4, mime@^1.2.11: + version "1.3.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + +mime@~1.2.11: + version "1.2.11" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + +minimatch@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-1.0.0.tgz#e0dd2120b49e1b724ce8d714c520822a9438576d" + dependencies: + lru-cache "2" + sigmund "~1.0.0" + +minimatch@^2.0.1, minimatch@^2.0.3, minimatch@^2.0.8: + version "2.0.10" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" + dependencies: + brace-expansion "^1.0.0" + +minimatch@~0.2.11: + version "0.2.14" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" + dependencies: + lru-cache "2" + sigmund "~1.0.0" + +minimist@0.0.8, minimist@~0.0.1: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.1.0, minimist@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +mkdirp@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" + +mkdirp@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" + dependencies: + minimist "0.0.8" + +mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +mkdirp@~0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" + +mktemp@^0.4.0, mktemp@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" + +mocha-only-detector@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/mocha-only-detector/-/mocha-only-detector-0.0.2.tgz#00f7dde6f949cf68a3cc92bdacff997b87e4b1d1" + dependencies: + esprima "^1.2.2" + esprimaq "^0.0.1" + glob "^4.3.2" + +mocha@2.4.5: + version "2.4.5" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.4.5.tgz#151768dd2875eb51bc8295e9800026e9f2bb398f" + dependencies: + commander "2.3.0" + debug "2.2.0" + diff "1.4.0" + escape-string-regexp "1.0.2" + glob "3.2.3" + growl "1.8.1" + jade "0.26.3" + mkdirp "0.5.1" + supports-color "1.2.0" + +moment-timezone@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" + dependencies: + moment ">= 2.6.0" + +"moment@>= 2.6.0": + version "2.17.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" + +morgan@^1.5.2, morgan@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.7.0.tgz#eb10ca8e50d1abe0f8d3dad5c0201d052d981c62" + dependencies: + basic-auth "~1.0.3" + debug "~2.2.0" + depd "~1.1.0" + on-finished "~2.3.0" + on-headers "~1.0.1" + +mout@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mout/-/mout-1.0.0.tgz#9bdf1d4af57d66d47cb353a6335a3281098e1501" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + +ms@0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + +mustache@^2.2.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" + +mute-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + +mute-stream@0.0.6, mute-stream@~0.0.4: + version "0.0.6" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" + +natives@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +node-emoji@^1.4.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.5.0.tgz#9a0d9fe03fd43afa357d6d8e439aa31e599959b7" + dependencies: + string.prototype.codepointat "^0.2.0" + +node-fetch@^1.3.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + +node-gyp@~3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.4.0.tgz#dda558393b3ecbbe24c9e6b8703c71194c63fa36" + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + minimatch "^3.0.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3" + osenv "0" + path-array "^1.0.0" + request "2" + rimraf "2" + semver "2.x || 3.x || 4 || 5" + tar "^2.0.0" + which "1" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + +node-modules-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" + +node-notifier@^4.3.1: + version "4.6.1" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-4.6.1.tgz#056d14244f3dcc1ceadfe68af9cff0c5473a33f3" + dependencies: + cli-usage "^0.1.1" + growly "^1.2.0" + lodash.clonedeep "^3.0.0" + minimist "^1.1.1" + semver "^5.1.0" + shellwords "^0.1.0" + which "^1.0.5" + +node-uuid@^1.4.3, node-uuid@~1.4.0, node-uuid@~1.4.7: + version "1.4.7" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" + +"nopt@2 || 3", nopt@^3.0.1, nopt@^3.0.3, nopt@~3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +normalize-git-url@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/normalize-git-url/-/normalize-git-url-3.0.2.tgz#8e5f14be0bdaedb73e07200310aa416c27350fc4" + +normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, "normalize-package-data@~1.0.1 || ^2.0.0", normalize-package-data@~2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + +npm-cache-filename@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" + +npm-git-info@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" + +npm-install-checks@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-3.0.0.tgz#d4aecdfd51a53e3723b7b2f93b2ee28e307bc0d7" + dependencies: + semver "^2.3.0 || 3.x || 4 || 5" + +"npm-package-arg@^3.0.0 || ^4.0.0", npm-package-arg@^4.0.0, npm-package-arg@^4.1.1, npm-package-arg@~4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-4.2.0.tgz#809bc61cabf54bd5ff94f6165c89ba8ee88c115c" + dependencies: + hosted-git-info "^2.1.5" + semver "^5.1.0" + +npm-registry-client@~7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/npm-registry-client/-/npm-registry-client-7.2.1.tgz#c792266b088cc313f8525e7e35248626c723db75" + dependencies: + concat-stream "^1.5.2" + graceful-fs "^4.1.6" + normalize-package-data "~1.0.1 || ^2.0.0" + npm-package-arg "^3.0.0 || ^4.0.0" + once "^1.3.3" + request "^2.74.0" + retry "^0.10.0" + semver "2 >=2.2.1 || 3.x || 4 || 5" + slide "^1.1.3" + optionalDependencies: + npmlog "~2.0.0 || ~3.1.0" + +npm-user-validate@~0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-0.1.5.tgz#52465d50c2d20294a57125b996baedbf56c5004b" + +npm@3.10.8: + version "3.10.8" + resolved "https://registry.yarnpkg.com/npm/-/npm-3.10.8.tgz#8f76ff8c6da04b61dd371d554ce40a0b8916c15e" + dependencies: + abbrev "~1.0.9" + ansicolors "~0.3.2" + ansistyles "~0.1.3" + aproba "~1.0.4" + archy "~1.0.0" + asap "~2.0.4" + chownr "~1.0.1" + cmd-shim "~2.0.2" + columnify "~1.5.4" + config-chain "~1.1.10" + dezalgo "~1.0.3" + editor "~1.0.0" + fs-vacuum "~1.2.9" + fs-write-stream-atomic "~1.0.8" + fstream "~1.0.10" + fstream-npm "~1.2.0" + glob "~7.0.6" + graceful-fs "~4.1.6" + has-unicode "~2.0.1" + hosted-git-info "~2.1.5" + iferr "~0.1.5" + inflight "~1.0.5" + inherits "~2.0.3" + ini "~1.3.4" + init-package-json "~1.9.4" + lockfile "~1.0.1" + lodash._baseuniq "~4.6.0" + lodash.clonedeep "~4.5.0" + lodash.union "~4.6.0" + lodash.uniq "~4.5.0" + lodash.without "~4.4.0" + mkdirp "~0.5.1" + node-gyp "~3.4.0" + nopt "~3.0.6" + normalize-git-url "~3.0.2" + normalize-package-data "~2.3.5" + npm-cache-filename "~1.0.2" + npm-install-checks "~3.0.0" + npm-package-arg "~4.2.0" + npm-registry-client "~7.2.1" + npm-user-validate "~0.1.5" + npmlog "~4.0.0" + once "~1.4.0" + opener "~1.4.1" + osenv "~0.1.3" + path-is-inside "~1.0.1" + read "~1.0.7" + read-cmd-shim "~1.0.1" + read-installed "~4.0.3" + read-package-json "~2.0.4" + read-package-tree "~5.1.5" + readable-stream "~2.1.5" + realize-package-specifier "~3.0.3" + request "~2.74.0" + retry "~0.10.0" + rimraf "~2.5.4" + semver "~5.3.0" + sha "~2.0.1" + slide "~1.1.6" + sorted-object "~2.0.0" + strip-ansi "~3.0.1" + tar "~2.2.1" + text-table "~0.2.0" + uid-number "0.0.6" + umask "~1.1.0" + unique-filename "~1.1.0" + unpipe "~1.0.0" + validate-npm-package-name "~2.2.2" + which "~1.2.11" + wrappy "~1.0.2" + write-file-atomic "~1.2.0" + +"npmlog@0 || 1 || 2 || 3", "npmlog@~2.0.0 || ~3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-3.1.2.tgz#2d46fa874337af9498a2f12bb43d8d0be4a36873" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.6.0" + set-blocking "~2.0.0" + +npmlog@^4.0.0, npmlog@~4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.1" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" + +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@4.1.0, object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + +once@^1.3.0, once@^1.3.3, once@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +opener@~1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.2.tgz#b32582080042af8680c389a499175b4c54fff523" + +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + +optionator@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +options@>=0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" + +ora@^0.2.0: + version "0.2.3" + resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" + dependencies: + chalk "^1.1.1" + cli-cursor "^1.0.2" + cli-spinners "^0.1.2" + object-assign "^4.0.1" + +os-homedir@^1.0.0, os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + +os-shim@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@0, osenv@^0.1.0, osenv@^0.1.3, osenv@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +output-file-sync@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + +parsejson@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" + dependencies: + better-assert "~1.0.0" + +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + dependencies: + better-assert "~1.0.0" + +parseurl@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + +path-array@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271" + dependencies: + array-index "^1.0.0" + +path-exists@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1, path-is-inside@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-posix@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + +phantomjs-prebuilt@^2.1.12: + version "2.1.14" + resolved "https://registry.yarnpkg.com/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz#d53d311fcfb7d1d08ddb24014558f1188c516da0" + dependencies: + es6-promise "~4.0.3" + extract-zip "~1.5.0" + fs-extra "~1.0.0" + hasha "~2.2.0" + kew "~0.7.0" + progress "~1.1.8" + request "~2.79.0" + request-progress "~2.0.1" + which "~1.2.10" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +plain-text-box-plot@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/plain-text-box-plot/-/plain-text-box-plot-0.0.1.tgz#d3b2e53071ea6706972318565761242f779c04b8" + +pluralize@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + +portfinder@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.10.tgz#7a4de9d98553c315da6f1e1ed05138eeb2d16bb8" + dependencies: + async "^1.5.2" + debug "^2.2.0" + mkdirp "0.5.x" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +pretender@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.0.0.tgz#9137c38718b4d89814478b7f208f70d3e441a0e9" + dependencies: + fake-xml-http-request "^1.3.0" + route-recognizer "^0.1.9" + +printf@^0.2.3: + version "0.2.5" + resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" + +private@^0.1.6, private@~0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process-relative-require@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" + dependencies: + node-modules-path "^1.0.0" + +progress@^1.1.8, progress@~1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + +promise-map-series@^0.2.1: + version "0.2.3" + resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" + dependencies: + rsvp "^3.0.14" + +promzard@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" + dependencies: + read "1" + +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + +proxy-addr@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.2.tgz#b4cc5f22610d9535824c123aef9d3cf73c40ba37" + dependencies: + forwarded "~0.1.0" + ipaddr.js "1.1.1" + +pseudomap@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +q@^1.1.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" + +qs@6.2.0, qs@^6.2.0, qs@~6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" + +qs@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" + +qs@~6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +quick-temp@0.1.6, quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@~0.1.2: + version "0.1.6" + resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.6.tgz#a6242a15cba9f9cdbd341287b5c569e318eec307" + dependencies: + mktemp "~0.4.0" + rimraf "~2.2.6" + underscore.string "~2.3.3" + +qunit-notifications@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/qunit-notifications/-/qunit-notifications-0.1.1.tgz#3001afc6a6a77dfbd962ccbcddde12dec5286c09" + +qunitjs@^1.20.0: + version "1.23.1" + resolved "https://registry.yarnpkg.com/qunitjs/-/qunitjs-1.23.1.tgz#1971cf97ac9be01a64d2315508d2e48e6fd4e719" + +randomatic@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + dependencies: + is-number "^2.0.2" + kind-of "^3.0.2" + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +raw-body@~1.1.0: + version "1.1.7" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + dependencies: + bytes "1" + string_decoder "0.10" + +raw-body@~2.1.7: + version "2.1.7" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" + dependencies: + bytes "2.4.0" + iconv-lite "0.4.13" + unpipe "1.0.0" + +read-cmd-shim@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b" + dependencies: + graceful-fs "^4.1.2" + +read-installed@~4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" + dependencies: + debuglog "^1.0.1" + read-package-json "^2.0.0" + readdir-scoped-modules "^1.0.0" + semver "2 || 3 || 4 || 5" + slide "~1.1.3" + util-extend "^1.0.1" + optionalDependencies: + graceful-fs "^4.1.2" + +"read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.0.4.tgz#61ed1b2256ea438d8008895090be84b8e799c853" + dependencies: + glob "^6.0.0" + json-parse-helpfulerror "^1.0.2" + normalize-package-data "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.2" + +read-package-tree@~5.1.5: + version "5.1.5" + resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.1.5.tgz#ace7e6381c7684f970aaa98fc7c5d2b666addab6" + dependencies: + debuglog "^1.0.1" + dezalgo "^1.0.0" + once "^1.3.0" + read-package-json "^2.0.0" + readdir-scoped-modules "^1.0.0" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +read@1, read@~1.0.1, read@~1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" + dependencies: + mute-stream "~0.0.4" + +"readable-stream@1 || 2", readable-stream@^2, readable-stream@^2.0.2, readable-stream@~2.1.5: + version "2.1.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@~1.0.2: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@~2.0.0, readable-stream@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" + dependencies: + debuglog "^1.0.1" + dezalgo "^1.0.0" + graceful-fs "^4.1.2" + once "^1.3.0" + +readline2@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + mute-stream "0.0.5" + +realize-package-specifier@~3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/realize-package-specifier/-/realize-package-specifier-3.0.3.tgz#d0def882952b8de3f67eba5e91199661271f41f4" + dependencies: + dezalgo "^1.0.1" + npm-package-arg "^4.1.1" + +recast@0.10.33: + version "0.10.33" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" + dependencies: + ast-types "0.8.12" + esprima-fb "~15001.1001.0-dev-harmony-fb" + private "~0.1.5" + source-map "~0.5.0" + +recast@^0.10.10, recast@^0.10.29: + version "0.10.43" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" + dependencies: + ast-types "0.8.15" + esprima-fb "~15001.1001.0-dev-harmony-fb" + private "~0.1.5" + source-map "~0.5.0" + +recast@^0.11.17, recast@^0.11.3: + version "0.11.18" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.18.tgz#07af6257ca769868815209401d4d60eef1b5b947" + dependencies: + ast-types "0.9.2" + esprima "~3.1.0" + private "~0.1.5" + source-map "~0.5.0" + +redeyed@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-0.5.0.tgz#7ab000e60ee3875ac115d29edb32c1403c6c25d1" + dependencies: + esprima-fb "~12001.1.0-dev-harmony-fb" + +redeyed@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" + dependencies: + esprima "~3.0.0" + +regenerate@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + +regenerator@0.8.40: + version "0.8.40" + resolved "https://registry.yarnpkg.com/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" + dependencies: + commoner "~0.10.3" + defs "~1.1.0" + esprima-fb "~15001.1001.0-dev-harmony-fb" + private "~0.1.5" + recast "0.10.33" + through "~2.3.8" + +regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + +regexpu@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" + dependencies: + esprima "^2.6.0" + recast "^0.10.10" + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^1.1.0, repeating@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" + dependencies: + is-finite "^1.0.0" + +request-progress@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" + dependencies: + throttleit "^1.0.0" + +request@2, request@^2.74.0, request@~2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + +request@~2.40.0: + version "2.40.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" + dependencies: + forever-agent "~0.5.0" + json-stringify-safe "~5.0.0" + mime-types "~1.0.1" + node-uuid "~1.4.0" + qs "~1.0.0" + optionalDependencies: + aws-sign2 "~0.5.0" + form-data "~0.1.0" + hawk "1.1.1" + http-signature "~0.10.0" + oauth-sign "~0.3.0" + stringstream "~0.0.4" + tough-cookie ">=0.12.0" + tunnel-agent "~0.4.0" + +request@~2.74.0: + version "2.74.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.74.0.tgz#7693ca768bbb0ea5c8ce08c084a45efa05b892ab" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + bl "~1.1.2" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~1.0.0-rc4" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + node-uuid "~1.4.7" + oauth-sign "~0.8.1" + qs "~6.2.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +require-uncached@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +requires-port@1.x.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + +resolve-dir@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" + dependencies: + expand-tilde "^1.2.2" + global-modules "^0.2.3" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve@^1.1.2, resolve@^1.1.6: + version "1.2.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + +retry@^0.10.0, retry@~0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@2, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@~2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + dependencies: + glob "^7.0.5" + +rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" + dependencies: + glob "^7.0.0" + +rimraf@~2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.1.4.tgz#5a6eb62eeda068f51ede50f29b3e5cd22f3d9bb2" + optionalDependencies: + graceful-fs "~1" + +rimraf@~2.2.6: + version "2.2.8" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + +route-recognizer@^0.1.9: + version "0.1.11" + resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" + +rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.6, rsvp@^3.2.1, rsvp@~3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + +rsvp@^3.0.14, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.3.3.tgz#34633caaf8bc66ceff4be3c2e1dffd032538a813" + +rsvp@~3.0.6: + version "3.0.21" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" + +rsvp@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" + +run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + dependencies: + once "^1.3.0" + +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + dependencies: + is-promise "^2.1.0" + +rx-lite@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + +rx@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + +safe-json-parse@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" + +sane@^1.1.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-1.5.0.tgz#a4adeae764d048621ecb27d5f9ecf513101939f3" + dependencies: + anymatch "^1.3.0" + exec-sh "^0.2.0" + fb-watchman "^1.8.0" + minimatch "^3.0.2" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.10.0" + +sax@1.1.5, sax@>=0.6.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.5.tgz#1da50a8d00cdecd59405659f5ff85349fe773743" + +selenium-webdriver@^3.0.0-beta-2: + version "3.0.1" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz#a2dea5da4a97f6672e89e7ca7276cefa365147a7" + dependencies: + adm-zip "^0.4.7" + rimraf "^2.5.4" + tmp "0.0.30" + xml2js "^0.4.17" + +"semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0, semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +semver@^4.1.0, semver@^4.3.1: + version "4.3.6" + resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + +send@0.14.1: + version "0.14.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.14.1.tgz#a954984325392f51532a7760760e459598c89f7a" + dependencies: + debug "~2.2.0" + depd "~1.1.0" + destroy "~1.0.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.7.0" + fresh "0.3.0" + http-errors "~1.5.0" + mime "1.3.4" + ms "0.7.1" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.3.0" + +serve-static@~1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.1.tgz#d6cce7693505f733c759de57befc1af76c0f0805" + dependencies: + encodeurl "~1.0.1" + escape-html "~1.0.3" + parseurl "~1.3.1" + send "0.14.1" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +setprototypeof@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" + +sha@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae" + dependencies: + graceful-fs "^4.1.2" + readable-stream "^2.0.2" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +shelljs@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" + +shellwords@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14" + +sigmund@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +silent-error@^1.0.0, silent-error@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/silent-error/-/silent-error-1.0.1.tgz#71b7d503d1c6f94882b51b56be879b113cb4822c" + dependencies: + debug "^2.2.0" + +simple-fmt@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" + +simple-is@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + +slide@^1.1.3, slide@^1.1.5, slide@~1.1.3, slide@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + +sntp@0.2.x: + version "0.2.4" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" + dependencies: + hoek "0.9.x" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +socket.io-adapter@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" + dependencies: + debug "2.3.3" + socket.io-parser "2.3.1" + +socket.io-client@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" + dependencies: + backo2 "1.0.2" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "2.3.3" + engine.io-client "1.8.0" + 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" + +socket.io-parser@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" + dependencies: + component-emitter "1.1.2" + debug "2.2.0" + isarray "0.0.1" + json3 "3.3.2" + +socket.io@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" + dependencies: + debug "2.3.3" + engine.io "1.8.0" + has-binary "0.1.7" + object-assign "4.1.0" + socket.io-adapter "0.5.0" + socket.io-client "1.6.0" + socket.io-parser "2.3.1" + +sort-object-keys@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" + +sort-package-json@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.4.0.tgz#1a80e1770f32f8b23769699f2400cf053f27ef63" + dependencies: + sort-object-keys "^1.1.1" + +sorted-object@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/sorted-object/-/sorted-object-2.0.1.tgz#7d631f4bd3a798a24af1dffcfbfe83337a5df5fc" + +source-map-support@^0.2.10: + version "0.2.10" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" + dependencies: + source-map "0.1.32" + +source-map-url@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" + +source-map@0.1.32: + version "0.1.32" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" + dependencies: + amdefine ">=0.0.4" + +source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.0, source-map@~0.5.0, source-map@~0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +spawn-args@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" + +spawn-sync@^1.0.15: + version "1.0.15" + resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + dependencies: + concat-stream "^1.4.7" + os-shim "^0.1.2" + +spawnback@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" + +spdx-correct@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + dependencies: + spdx-license-ids "^1.0.2" + +spdx-expression-parse@~1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + +spdx-license-ids@^1.0.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sri-toolbox@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" + +sshpk@^1.7.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.2.tgz#d5a804ce22695515638e798dbe23273de070a5fa" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jodid25519 "^1.0.0" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +stable@~0.1.3: + version "0.1.5" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.5.tgz#08232f60c732e9890784b5bed0734f8b32a887b9" + +"statuses@>= 1.3.1 < 2", statuses@~1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + +string-template@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^3.0.0" + +string.prototype.codepointat@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.0.tgz#6b26e9bd3afcaa7be3b4269b526de1b82000ac78" + +string_decoder@0.10, string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +stringmap@~0.2.2: + version "0.2.2" + resolved "http://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" + +stringset@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" + +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" + dependencies: + ansi-regex "^0.2.1" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1, strip-ansi@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-json-comments@~1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + +styled_string@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" + +sum-up@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" + dependencies: + chalk "^1.0.0" + +supports-color@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" + +supports-color@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" + +sync-exec@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105" + +table@^3.7.8: + version "3.8.3" + resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + dependencies: + ajv "^4.7.0" + ajv-keywords "^1.0.0" + chalk "^1.1.1" + lodash "^4.0.0" + slice-ansi "0.0.4" + string-width "^2.0.0" + +tap-parser@^3.0.2: + version "3.0.5" + resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-3.0.5.tgz#b947f69e0b3e53d4b92011f6cc552e16dadc7ec9" + dependencies: + events-to-array "^1.0.1" + js-yaml "^3.2.7" + optionalDependencies: + readable-stream "^2" + +tar@^2.0.0, tar@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +temp@0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" + dependencies: + os-tmpdir "^1.0.0" + rimraf "~2.2.6" + +testem@^1.8.1: + version "1.14.2" + resolved "https://registry.yarnpkg.com/testem/-/testem-1.14.2.tgz#0c29f82e99cebf51c1a5808e57a922b9624075af" + dependencies: + backbone "^1.1.2" + bluebird "^3.4.6" + charm "^1.0.0" + commander "^2.6.0" + consolidate "^0.14.0" + cross-spawn "^5.0.0" + express "^4.10.7" + fireworm "^0.7.0" + glob "^7.0.4" + http-proxy "^1.13.1" + js-yaml "^3.2.5" + lodash.assignin "^4.1.0" + lodash.clonedeep "^4.4.1" + lodash.find "^4.5.1" + mkdirp "^0.5.1" + mustache "^2.2.1" + node-notifier "^4.3.1" + npmlog "^4.0.0" + printf "^0.2.3" + rimraf "^2.4.4" + socket.io "1.6.0" + spawn-args "^0.2.0" + styled_string "0.0.1" + tap-parser "^3.0.2" + xmldom "^0.1.19" + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +"textextensions@1 || 2": + version "2.0.1" + resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.0.1.tgz#be8cf22d65379c151319f88f0335ad8f667abdca" + +throttleit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" + +through@^2.3.6, through@^2.3.8, through@~2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +tiny-lr@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.0.3.tgz#386731170ce521263a9d337f769ee8f11e88eb04" + dependencies: + body "^5.1.0" + debug "~2.2.0" + faye-websocket "~0.10.0" + livereload-js "^2.2.2" + object-assign "^4.1.0" + qs "^6.2.0" + +tmp-sync@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/tmp-sync/-/tmp-sync-1.1.0.tgz#2b38ec94b094ed2515ec02a9aee1f51dd2c9023f" + dependencies: + fs-sync "^0.2.4" + osenv "^0.1.0" + +tmp@0.0.28: + version "0.0.28" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" + dependencies: + os-tmpdir "~1.0.1" + +tmp@0.0.30: + version "0.0.30" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + dependencies: + os-tmpdir "~1.0.1" + +tmp@^0.0.29: + version "0.0.29" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" + dependencies: + os-tmpdir "~1.0.1" + +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + +to-fast-properties@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + +tough-cookie@>=0.12.0, tough-cookie@~2.3.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + dependencies: + punycode "^1.4.1" + +tree-sync@^1.1.4: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" + dependencies: + debug "^2.2.0" + fs-tree-diff "^0.5.6" + mkdirp "^0.5.1" + quick-temp "^0.1.5" + walk-sync "^0.2.7" + +trim-right@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +try-resolve@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" + +tryit@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + +tryor@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" + +tunnel-agent@~0.4.0, tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +type-detect@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" + +type-detect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" + +type-is@~1.6.13: + version "1.6.14" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.13" + +typedarray@^0.0.6, typedarray@~0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" + +uglify-js@^2.6, uglify-js@^2.7.0: + version "2.7.5" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" + dependencies: + async "~0.2.6" + source-map "~0.5.1" + uglify-to-browserify "~1.0.0" + yargs "~3.10.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uid-number@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +ultron@1.0.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" + +umask@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" + +underscore.string@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" + +underscore@>=1.8.3: + version "1.8.3" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + +unique-filename@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + dependencies: + imurmurhash "^0.1.4" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +untildify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" + dependencies: + os-homedir "^1.0.0" + +url@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + +user-home@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + dependencies: + os-homedir "^1.0.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util-extend@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" + +utils-merge@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + +uuid@3.0.0, uuid@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" + +uuid@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" + +validate-npm-package-license@*, validate-npm-package-license@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + dependencies: + spdx-correct "~1.0.0" + spdx-expression-parse "~1.0.0" + +validate-npm-package-name@^2.0.1, validate-npm-package-name@~2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-2.2.2.tgz#f65695b22f7324442019a3c7fa39a6e7fd299085" + dependencies: + builtins "0.0.7" + +vary@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" + +verror@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + dependencies: + extsprintf "1.0.2" + +walk-sync@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" + +walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" + dependencies: + ensure-posix-path "^1.0.0" + matcher-collection "^1.0.0" + +walk-sync@^0.3.0, walk-sync@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.1.tgz#558a16aeac8c0db59c028b73c66f397684ece465" + dependencies: + ensure-posix-path "^1.0.0" + matcher-collection "^1.0.0" + +walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + dependencies: + makeerror "1.0.x" + +watch@~0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" + +wcwidth@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + dependencies: + defaults "^1.0.3" + +websocket-driver@>=0.5.1: + version "0.6.5" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" + dependencies: + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + +which@1, which@^1.0.5, which@^1.2.12, which@^1.2.9, which@~1.2.10, which@~1.2.11: + version "1.2.12" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" + dependencies: + isexe "^1.1.1" + +wide-align@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + dependencies: + string-width "^1.0.1" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +window-size@^0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" + +window-size@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1, wrappy@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^1.1.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + slide "^1.1.5" + +write-file-atomic@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.2.0.tgz#14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab" + dependencies: + graceful-fs "^4.1.2" + imurmurhash "^0.1.4" + slide "^1.1.5" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + +ws@1.1.1, ws@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" + dependencies: + options ">=0.0.5" + ultron "1.0.x" + +wtf-8@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" + +xdg-basedir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" + dependencies: + os-homedir "^1.0.0" + +xml2js@0.4.15: + version "0.4.15" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.15.tgz#95cd03ff2dd144ec28bc6273bf2b2890c581ad0c" + dependencies: + sax ">=0.6.0" + xmlbuilder ">=2.4.6" + +xml2js@^0.4.17: + version "0.4.17" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" + dependencies: + sax ">=0.6.0" + xmlbuilder "^4.1.0" + +xmlbuilder@2.6.2, xmlbuilder@>=2.4.6: + version "2.6.2" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-2.6.2.tgz#f916f6d10d45dc171b1be2e6e673fb6e0cc35d0a" + dependencies: + lodash "~3.5.0" + +xmlbuilder@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" + dependencies: + lodash "^4.0.0" + +xmldom@^0.1.19: + version "0.1.27" + resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" + +xmlhttprequest-ssl@1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" + +xtend@^4.0.0, xtend@~4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +y18n@^3.2.0, y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yallist@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.0.0.tgz#306c543835f09ee1a4cb23b7bce9ab341c91cdd4" + +yam@0.0.22: + version "0.0.22" + resolved "https://registry.yarnpkg.com/yam/-/yam-0.0.22.tgz#38a76cb79a19284d9206ed49031e359a1340bd06" + dependencies: + fs-extra "^0.30.0" + lodash.merge "^4.4.0" + +yargs-parser@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-3.2.0.tgz#5081355d19d9d0c8c5d81ada908cb4e6d186664f" + dependencies: + camelcase "^3.0.0" + lodash.assign "^4.1.0" + +yargs@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-5.0.0.tgz#3355144977d05757dbb86d6e38ec056123b3a66e" + dependencies: + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + lodash.assign "^4.2.0" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + window-size "^0.2.0" + y18n "^3.2.1" + yargs-parser "^3.2.0" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" + +yargs@~3.27.0: + version "3.27.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" + dependencies: + camelcase "^1.2.1" + cliui "^2.1.0" + decamelize "^1.0.0" + os-locale "^1.4.0" + window-size "^0.1.2" + y18n "^3.2.0" + +yauzl@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" + dependencies: + fd-slicer "~1.0.1" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + +yui@^3.18.1: + version "3.18.1" + resolved "https://registry.yarnpkg.com/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" + dependencies: + request "~2.40.0" + +yuidocjs@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/yuidocjs/-/yuidocjs-0.9.0.tgz#d2ff2b37cadf30e3d45385c58f5003e5a83f2723" + dependencies: + express "^4.13.1" + graceful-fs "^4.1.2" + markdown-it "^4.3.0" + mdn-links "^0.1.0" + minimatch "^2.0.8" + rimraf "^2.4.1" + yui "^3.18.1" From 2f18405a4785486f3bd7c865ca1096ea44e2c184 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Wed, 19 Oct 2016 07:45:20 -0700 Subject: [PATCH 1772/2527] Free up `internalModel`s `internalModel`s need to stay around as long as they're connected to a live record via relationships. Once an entire subgraph is removed however, we can free all of it. Also add a couple of "late private" fields to `internalModel`'s constructor for shape preservation. Finally - Add a lot of `toString`s to test classes, as a debugging convenience. - Minor test cleanup Includes work from @igort, @sly7-7 and @pangratz [Fix #3296] [Supercede #3301] --- addon/-private/system/model/internal-model.js | 183 +++++++++++-- addon/-private/system/model/model.js | 8 - addon/-private/system/model/states.js | 10 - addon/-private/system/record-array-manager.js | 11 +- addon/-private/system/record-map.js | 1 - .../system/relationships/state/belongs-to.js | 12 +- .../system/relationships/state/has-many.js | 10 + .../relationships/state/relationship.js | 32 ++- addon/-private/system/store.js | 6 +- tests/integration/adapter/find-all-test.js | 1 + .../integration/records/delete-record-test.js | 2 + tests/integration/records/load-test.js | 9 +- .../integration/records/rematerialize-test.js | 245 ++++++++++++++++++ tests/integration/records/unload-test.js | 200 ++++++++------ .../relationships/has-many-test.js | 15 +- .../relationships/many-to-many-test.js | 2 +- .../relationships/one-to-many-test.js | 2 +- tests/integration/store-test.js | 5 +- tests/unit/many-array-test.js | 4 +- tests/unit/model/rollback-attributes-test.js | 1 + tests/unit/store/unload-test.js | 72 +++-- 21 files changed, 647 insertions(+), 184 deletions(-) create mode 100644 tests/integration/records/rematerialize-test.js diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 5bc9e621528..878c749c4f6 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -59,6 +59,16 @@ function extractPivotName(name) { ); } +function areAllModelsUnloaded(internalModels) { + for (let i=0; i { + if (this._relationships.has(key)) { + let relationship = this._relationships.get(key); + let localRelationships = relationship.members.toArray(); + let serverRelationships = relationship.canonicalMembers.toArray(); + + array = array.concat(localRelationships, serverRelationships); + } + }); + return array; + } + + + /** + Computes the set of internal models reachable from this internal model. + + Reachability is determined over the relationship graph (ie a graph where + nodes are internal models and edges are belongs to or has many + relationships). + + @return {Array} An array including `this` and all internal models reachable + from `this`. + */ + _allRelatedInternalModels() { + let array = []; + let queue = []; + let bfsId = nextBfsId++; + queue.push(this); + this._bfsId = bfsId; + while (queue.length > 0) { + let node = queue.shift(); + array.push(node); + let related = node._directlyRelatedInternalModels(); + for (let i=0; i { + if (this._relationships.has(name)) { + let rel = this._relationships.get(name); + rel.destroy(); + } + }); + Object.keys(this._implicitRelationships).forEach((key) => { + this._implicitRelationships[key].destroy(); + }); + } + /* When a find request is triggered on the store, the user can optionally pass in attributes and relationships to be preloaded. These are meant to behave as if they diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index cecaf6ed9d0..da32cd604bc 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -807,14 +807,6 @@ const Model = Ember.Object.extend(Ember.Evented, { this._super(...arguments); }, - willDestroy() { - //TODO Move! - this._super(...arguments); - this._internalModel.clearRelationships(); - this._internalModel.recordObjectWillDestroy(); - //TODO should we set internalModel to null here? - }, - // This is a temporary solution until we refactor DS.Model to not // rely on the data property. willMergeMixin(props) { diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index ae542b53897..0843589314c 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -459,10 +459,6 @@ const RootState = { // you out of the in-flight state. rolledBack() { }, unloadRecord(internalModel) { - // clear relationships before moving to deleted state - // otherwise it fails - internalModel.clearRelationships(); - internalModel.transitionTo('deleted.saved'); }, propertyWasReset() { }, @@ -573,10 +569,6 @@ const RootState = { }, unloadRecord(internalModel) { - // clear relationships before moving to deleted state - // otherwise it fails - internalModel.clearRelationships(); - internalModel.transitionTo('deleted.saved'); }, didCommit() {}, @@ -680,8 +672,6 @@ const RootState = { setup(internalModel) { internalModel.clearRelationships(); - var store = internalModel.store; - store._dematerializeRecord(internalModel); }, invokeLifecycleCallbacks(internalModel) { diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 79fc0c02445..0df3350f4a1 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -117,8 +117,15 @@ export default class RecordArrayManager { for (let i = 0, l = updated.length; i < l; i++) { let internalModel = updated[i]; - if (internalModel.isDestroyed || - internalModel.currentState.stateName === 'root.deleted.saved') { + // During dematerialization we don't want to rematerialize the record. + // recordWasDeleted can cause other records to rematerialize because it + // removes the internal model from the array and Ember arrays will always + // `objectAt(0)` and `objectAt(len -1)` to check whether `firstObject` or + // `lastObject` have changed. When this happens we don't want those + // models to rematerialize their records. + if (internalModel._isDematerializing || + internalModel.isDestroyed || + internalModel.currentState.stateName === 'root.deleted.saved') { this._recordWasDeleted(internalModel); } else { this._recordWasChanged(internalModel); diff --git a/addon/-private/system/record-map.js b/addon/-private/system/record-map.js index 7633531f511..d91756214e9 100644 --- a/addon/-private/system/record-map.js +++ b/addon/-private/system/record-map.js @@ -120,7 +120,6 @@ export default class RecordMap { for (let i = 0; i < records.length; i++) { record = records[i]; record.unloadRecord(); - record.destroy(); // maybe within unloadRecord } } diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 2b6089d828a..7f4b2dbf1ac 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -46,6 +46,10 @@ export default class BelongsToRelationship extends Relationship { super.addCanonicalRecord(newRecord); } + inverseDidDematerialize() { + this.notifyBelongsToChanged(); + } + flushCanonical() { //temporary fix to not remove newly created records if server returned null. //TODO remove once we have proper diffing @@ -54,7 +58,7 @@ export default class BelongsToRelationship extends Relationship { } if (this.inverseRecord !== this.canonicalState) { this.inverseRecord = this.canonicalState; - this.internalModel.notifyBelongsToChanged(this.key); + this.notifyBelongsToChanged(); } super.flushCanonical(); @@ -71,7 +75,7 @@ export default class BelongsToRelationship extends Relationship { this.inverseRecord = newRecord; super.addRecord(newRecord); - this.internalModel.notifyBelongsToChanged(this.key); + this.notifyBelongsToChanged(); } setRecordPromise(newPromise) { @@ -84,6 +88,10 @@ export default class BelongsToRelationship extends Relationship { if (!this.members.has(record)) { return;} this.inverseRecord = null; super.removeRecordFromOwn(record); + this.notifyBelongsToChanged(); + } + + notifyBelongsToChanged() { this.internalModel.notifyBelongsToChanged(this.key); } diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 7bfd7aaff89..6cda156f3cf 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -30,8 +30,10 @@ export default class ManyRelationship extends Relationship { } destroy() { + super.destroy(); if (this._manyArray) { this._manyArray.destroy(); + this._manyArray = null; } } @@ -54,6 +56,14 @@ export default class ManyRelationship extends Relationship { super.addCanonicalRecord(record, idx); } + inverseDidDematerialize() { + if (this._manyArray) { + this._manyArray.destroy(); + this._manyArray = null; + } + this.notifyHasManyChanged(); + } + addRecord(record, idx) { if (this.members.has(record)) { return; diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index eb7fc9b5c34..44c1367644b 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -83,7 +83,26 @@ export default class Relationship { return this.internalModel.modelName; } - destroy() { } + destroy() { + if (!this.inverseKey) { return; } + + let allMembers = + // we actually want a union of members and canonicalMembers + // they should be disjoint but currently are not due to a bug + this.members.toArray().concat(this.canonicalMembers.toArray()); + + allMembers.forEach(inverseInternalModel => { + let relationship = inverseInternalModel._relationships.get(this.inverseKey); + // TODO: there is always a relationship in this case; this guard exists + // because there are tests that fail in teardown after putting things in + // invalid state + if (relationship) { + relationship.inverseDidDematerialize(); + } + }); + } + + inverseDidDematerialize() {} updateMeta(meta) { heimdall.increment(updateMeta); @@ -92,13 +111,18 @@ export default class Relationship { clear() { heimdall.increment(clear); - var members = this.members.list; - var member; + let members = this.members.list; while (members.length > 0) { - member = members[0]; + let member = members[0]; this.removeRecord(member); } + + let canonicalMembers = this.canonicalMembers.list; + while (canonicalMembers.length > 0) { + let member = canonicalMembers[0]; + this.removeCanonicalRecord(member); + } } removeRecords(records) { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 2dfa8acbf85..64b62c0f602 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2541,16 +2541,14 @@ Store = Service.extend({ When a record is destroyed, this un-indexes it and removes it from any record arrays so it can be GCed. - @method _dematerializeRecord + @method _removeFromIdMap @private @param {InternalModel} internalModel */ - _dematerializeRecord(internalModel) { + _removeFromIdMap(internalModel) { let recordMap = this._recordMapFor(internalModel.modelName); let id = internalModel.id; - internalModel.updateRecordArrays(); - recordMap.remove(internalModel, id); }, diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index b9ba670bbe6..cc4a081bc53 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -19,6 +19,7 @@ module("integration/adapter/find_all - Finding All Records of a Type", { firstName: attr('string'), lastName: attr('string') }); + Person.reopenClass({ toString() { return 'Person'; } }); allRecords = null; diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index 78d90206222..f877e09ca28 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -17,6 +17,7 @@ module("integration/deletedRecord - Deleting Records", { Person = DS.Model.extend({ name: attr('string') }); + Person.toString = () => { return 'Person'; }; env = setupStore({ person: Person @@ -78,6 +79,7 @@ test('deleting a record that is part of a hasMany removes it from the hasMany re const Group = DS.Model.extend({ people: DS.hasMany('person', { inverse: null, async: false }) }); + Group.toString = () => { return 'Group'; } env.adapter.deleteRecord = function() { return Ember.RSVP.Promise.resolve(); diff --git a/tests/integration/records/load-test.js b/tests/integration/records/load-test.js index d3e4b96b2fe..02e070c0c1c 100644 --- a/tests/integration/records/load-test.js +++ b/tests/integration/records/load-test.js @@ -25,19 +25,14 @@ module("integration/load - Loading Records", { } }); -test("When loading a record fails, the isLoading is set to false", function(assert) { +test("When loading a record fails, the record is not left behind", function(assert) { env.adapter.findRecord = function(store, type, id, snapshot) { return Ember.RSVP.reject(); }; run(function() { env.store.findRecord('post', 1).then(null, assert.wait(function() { - // store.recordForId is private, but there is currently no other way to - // get the specific record instance, since it is not passed to this - // rejection handler - var post = env.store.recordForId('post', 1); - - assert.equal(post.get("isLoading"), false, "post is not loading anymore"); + assert.equal(env.store.hasRecordForId('post', 1), false); })); }); }); diff --git a/tests/integration/records/rematerialize-test.js b/tests/integration/records/rematerialize-test.js new file mode 100644 index 00000000000..9780a60750a --- /dev/null +++ b/tests/integration/records/rematerialize-test.js @@ -0,0 +1,245 @@ +/*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(adam|bob|dudu)" }]*/ + +import setupStore from 'dummy/tests/helpers/store'; +import Ember from 'ember'; + +import {module, test} from 'qunit'; + +import DS from 'ember-data'; + +let attr = DS.attr; +let belongsTo = DS.belongsTo; +let hasMany = DS.hasMany; +let run = Ember.run; +let env; + +let Person = DS.Model.extend({ + name: attr('string'), + cars: hasMany('car', { async: false }), + boats: hasMany('boat', { async: true }) +}); +Person.reopenClass({ toString() { return 'Person'; } }); + +let Group = DS.Model.extend({ + people: hasMany('person', { async: false }) +}); +Group.reopenClass({ toString() { return 'Group'; } }); + +let Car = DS.Model.extend({ + make: attr('string'), + model: attr('string'), + person: belongsTo('person', { async: false }) +}); +Car.reopenClass({ toString() { return 'Car'; } }); + +let Boat = DS.Model.extend({ + name: attr('string'), + person: belongsTo('person', { async: false }) +}); +Boat.toString = function() { return 'Boat'; }; + +module("integration/unload - Unloading Records", { + beforeEach() { + env = setupStore({ + adapter: DS.JSONAPIAdapter, + person: Person, + car: Car, + group: Group, + boat: Boat + }); + }, + + afterEach() { + Ember.run(function() { + env.container.destroy(); + }); + } +}); + +test("a sync belongs to relationship to an unloaded record can restore that record", function(assert) { + let adam, bob; + + // disable background reloading so we do not re-create the relationship. + env.adapter.shouldBackgroundReloadRecord = () => false; + + run(function() { + env.store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + }, + relationships: { + cars: { + data: [ + { type: 'car', id: '1' } + ] + } + } + } + }); + adam = env.store.peekRecord('person', 1); + }); + + run(function() { + env.store.push({ + data: { + type: 'car', + id: '1', + attributes: { + make: "Lotus", + model: "Exige" + }, + relationships: { + person: { + data: { type: 'person', id: '1' } + } + } + } + }); + bob = env.store.peekRecord('car', 1); + }); + + let person = env.store.peekRecord('person', 1); + assert.equal(person.get('cars.length'), 1, 'The inital length of cars is correct'); + + assert.equal(env.store.hasRecordForId('person', 1), true, 'The person is in the store'); + assert.equal(env.store._recordMapFor('person').has(1), true, 'The person internalModel is loaded'); + + run(function() { + person.unloadRecord(); + }); + + assert.equal(env.store.hasRecordForId('person', 1), false, 'The person is unloaded'); + assert.equal(env.store._recordMapFor('person').has(1), true, 'The person internalModel is retained'); + + run(() => { + env.store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + }, + relationships: { + cars: { + data: [ + { type: 'car', id: '1' } + ] + } + } + } + }); + }); + + let rematerializedPerson = bob.get('person'); + assert.equal(rematerializedPerson.get('id'), '1'); + // the person is rematerialized; the previous person is *not* re-used + assert.notEqual(rematerializedPerson, adam, 'the person is rematerialized, not recycled'); +}); + +test("an async has many relationship to an unloaded record can restore that record", function(assert) { + assert.expect(13); + + // disable background reloading so we do not re-create the relationship. + env.adapter.shouldBackgroundReloadRecord = () => false; + + env.adapter.findRecord = function() { + assert.ok('adapter called'); + return Ember.RSVP.Promise.resolve({ + data: { + type: 'boat', + id: '1', + attributes: { + name: "Boaty McBoatface" + }, + relationships: { + person: { + data: { type: 'person', id: '1' } + } + } + } + }); + } + + run(function() { + env.store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + }, + relationships: { + boats: { + data: [ + { type: 'boat', id: '2' }, + { type: 'boat', id: '1' } + ] + } + } + } + }); + }); + + run(function() { + env.store.push({ + data: [{ + type: 'boat', + id: '2', + attributes: { + name: 'Some other boat' + }, + relationships: { + person: { + data: { type: 'person', id: '1' } + } + } + }, { + type: 'boat', + id: '1', + attributes: { + name: 'Boaty McBoatface' + }, + relationships: { + person: { + data: { type: 'person', id: '1' } + } + } + }] + }); + }); + + let adam = env.store.peekRecord('person', 1); + let boaty = env.store.peekRecord('boat', 1); + + assert.equal(env.store.hasRecordForId('person', 1), true, 'The person is in the store'); + assert.equal(env.store._recordMapFor('person').has(1), true, 'The person internalModel is loaded'); + assert.equal(env.store.hasRecordForId('boat', 1), true, 'The boat is in the store'); + assert.equal(env.store._recordMapFor('boat').has(1), true, 'The boat internalModel is loaded'); + + let boats = run(() => { + return adam.get('boats'); + }); + + assert.equal(boats.get('length'), 2, 'Before unloading boats.length is correct'); + + run(function() { + boaty.unloadRecord(); + }); + + assert.equal(env.store.hasRecordForId('boat', 1), false, 'The boat is unloaded'); + assert.equal(env.store._recordMapFor('boat').has(1), true, 'The boat internalModel is retained'); + + let rematerializedBoaty = run(() => { + return rematerializedBoaty = adam.get('boats').objectAt(1); + }); + + assert.equal(adam.get('boats.length'), 2, 'boats.length correct after rematerialization'); + assert.equal(rematerializedBoaty.get('id'), '1'); + assert.notEqual(rematerializedBoaty, boaty, 'the boat is rematerialized, not recycled'); + + assert.equal(env.store.hasRecordForId('boat', 1), true, 'The boat is loaded'); + assert.equal(env.store._recordMapFor('boat').has(1), true, 'The boat internalModel is retained'); +}); diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index b97a79797cc..63e8e616055 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -7,33 +7,45 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var attr = DS.attr; -var belongsTo = DS.belongsTo; -var hasMany = DS.hasMany; -var run = Ember.run; -var env; +let attr = DS.attr; +let belongsTo = DS.belongsTo; +let hasMany = DS.hasMany; +let run = Ember.run; +let env; -var Person = DS.Model.extend({ +let Person = DS.Model.extend({ name: attr('string'), - cars: hasMany('car', { async: false }) + cars: hasMany('car', { async: false }), + boats: hasMany('boat', { async: true }) }); +Person.reopenClass({ toString() { return 'Person'; } }); -var Group = DS.Model.extend({ +let Group = DS.Model.extend({ people: hasMany('person', { async: false }) }); +Group.reopenClass({ toString() { return 'Group'; } }); -var Car = DS.Model.extend({ +let Car = DS.Model.extend({ make: attr('string'), model: attr('string'), person: belongsTo('person', { async: false }) }); +Car.reopenClass({ toString() { return 'Car'; } }); + +let Boat = DS.Model.extend({ + name: attr('string'), + person: belongsTo('person', { async: false }) +}); +Boat.toString = function() { return 'Boat'; }; module("integration/unload - Unloading Records", { beforeEach() { env = setupStore({ + adapter: DS.JSONAPIAdapter, person: Person, car: Car, - group: Group + group: Group, + boat: Boat }); }, @@ -45,7 +57,7 @@ module("integration/unload - Unloading Records", { }); test("can unload a single record", function(assert) { - var adam; + let adam; run(function() { env.store.push({ data: { @@ -59,17 +71,21 @@ test("can unload a single record", function(assert) { adam = env.store.peekRecord('person', 1); }); + assert.equal(env.store.peekAll('person').get('length'), 1, 'one person record loaded'); + assert.equal(env.store._recordMapFor('person').length, 1, 'one person internalModel loaded'); + Ember.run(function() { adam.unloadRecord(); }); - assert.equal(env.store.peekAll('person').get('length'), 0); + assert.equal(env.store.peekAll('person').get('length'), 0, 'no person records'); + assert.equal(env.store._recordMapFor('person').length, 0, 'no person internalModels'); }); test("can unload all records for a given type", function(assert) { - assert.expect(2); + assert.expect(8); - var adam, bob, dudu; + let adam, bob, dudu; run(function() { env.store.push({ data: [{ @@ -107,18 +123,25 @@ test("can unload all records for a given type", function(assert) { dudu = bob = env.store.peekRecord('car', 1); }); + assert.equal(env.store.peekAll('person').get('length'), 2, 'two person records loaded'); + assert.equal(env.store._recordMapFor('person').length, 2, 'two person internalModels loaded'); + assert.equal(env.store.peekAll('car').get('length'), 1, 'one car record loaded'); + assert.equal(env.store._recordMapFor('car').length, 1, 'one car internalModel loaded'); + Ember.run(function() { env.store.unloadAll('person'); }); assert.equal(env.store.peekAll('person').get('length'), 0); assert.equal(env.store.peekAll('car').get('length'), 1); + assert.equal(env.store._recordMapFor('person').length, 0, 'zero person internalModels loaded'); + assert.equal(env.store._recordMapFor('car').length, 1, 'one car internalModel loaded'); }); test("can unload all records", function(assert) { - assert.expect(2); + assert.expect(8); - var adam, bob, dudu; + let adam, bob, dudu; run(function() { env.store.push({ data: [{ @@ -156,16 +179,25 @@ test("can unload all records", function(assert) { dudu = bob = env.store.peekRecord('car', 1); }); + assert.equal(env.store.peekAll('person').get('length'), 2, 'two person records loaded'); + assert.equal(env.store._recordMapFor('person').length, 2, 'two person internalModels loaded'); + assert.equal(env.store.peekAll('car').get('length'), 1, 'one car record loaded'); + assert.equal(env.store._recordMapFor('car').length, 1, 'one car internalModel loaded'); + Ember.run(function() { env.store.unloadAll(); }); assert.equal(env.store.peekAll('person').get('length'), 0); assert.equal(env.store.peekAll('car').get('length'), 0); + assert.equal(env.store._recordMapFor('person').length, 0, 'zero person internalModels loaded'); + assert.equal(env.store._recordMapFor('car').length, 0, 'zero car internalModels loaded'); }); test("removes findAllCache after unloading all records", function(assert) { - var adam, bob; + assert.expect(4); + + let adam, bob; run(function() { env.store.push({ data: [{ @@ -186,16 +218,20 @@ test("removes findAllCache after unloading all records", function(assert) { bob = env.store.peekRecord('person', 2); }); + assert.equal(env.store.peekAll('person').get('length'), 2, 'two person records loaded'); + assert.equal(env.store._recordMapFor('person').length, 2, 'two person internalModels loaded'); + Ember.run(function() { env.store.peekAll('person'); env.store.unloadAll('person'); }); - assert.equal(env.store.peekAll('person').get('length'), 0); + assert.equal(env.store.peekAll('person').get('length'), 0, 'zero person records loaded'); + assert.equal(env.store._recordMapFor('person').length, 0, 'zero person internalModels loaded'); }); test("unloading all records also updates record array from peekAll()", function(assert) { - var adam, bob; + let adam, bob; run(function() { env.store.push({ data: [{ @@ -215,52 +251,48 @@ test("unloading all records also updates record array from peekAll()", function( adam = env.store.peekRecord('person', 1); bob = env.store.peekRecord('person', 2); }); - var all = env.store.peekAll('person'); + let all = env.store.peekAll('person'); assert.equal(all.get('length'), 2); + Ember.run(function() { env.store.unloadAll('person'); }); - assert.equal(all.get('length'), 0); }); - -test("unloading a record also clears its relationship", function(assert) { - var adam, bob; - - // disable background reloading so we do not re-create the relationship. +test('unloading a disconnected subgraph clears the relevant internal models', function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { env.store.push({ data: { type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' + name: 'Could be Anybody' }, relationships: { cars: { data: [ - { type: 'car', id: '1' } + { type: 'car', id: '1' }, + { type: 'car', id: '2' } ] } } } }); - adam = env.store.peekRecord('person', 1); }); - run(function() { + run(() => { env.store.push({ data: { type: 'car', id: '1', attributes: { - make: "Lotus", - model: "Exige" + make: 'Nissan', + model: 'Altima' }, relationships: { person: { @@ -269,66 +301,70 @@ test("unloading a record also clears its relationship", function(assert) { } } }); - bob = env.store.peekRecord('car', 1); }); - run(function() { - env.store.findRecord('person', 1).then(function(person) { - assert.equal(person.get('cars.length'), 1, 'The inital length of cars is correct'); - - run(function() { - person.unloadRecord(); - }); - - assert.equal(person.get('cars.length'), undefined); - }); - }); -}); - -test("unloading a record also clears the implicit inverse relationships", function(assert) { - var adam, bob; - // disable background reloading so we do not re-create the relationship. - env.adapter.shouldBackgroundReloadRecord = () => false; - - run(function() { + run(() => { env.store.push({ data: { - type: 'person', - id: '1', + type: 'car', + id: '2', attributes: { - name: 'Adam Sunderland' - } - } - }); - adam = env.store.peekRecord('person', 1); - }); - - run(function() { - env.store.push({ - data: { - type: 'group', - id: '1', + make: 'Tesla', + model: 'S' + }, relationships: { - people: { - data: [ - { type: 'person', id: '1' } - ] + person: { + data: { type: 'person', id: '1' } } } } }); - bob = env.store.peekRecord('group', 1); }); - run(function() { - env.store.findRecord('group', 1).then(function(group) { - assert.equal(group.get('people.length'), 1, 'The inital length of people is correct'); - var person = env.store.peekRecord('person', 1); - run(function() { - person.unloadRecord(); - }); - - assert.equal(group.get('people.length'), 0, 'Person was removed from the people array'); - }); + assert.equal( + env.store._recordMapFor('person').records.length, + 1, + 'one person record is loaded' + ); + assert.equal( + env.store._recordMapFor('car').records.length, + 2, + 'two car records are loaded' + ); + assert.equal(env.store.hasRecordForId('person', 1), true); + assert.equal(env.store.hasRecordForId('car', 1), true); + assert.equal(env.store.hasRecordForId('car', 2), true); + + let checkOrphanCalls = 0; + let cleanupOrphanCalls = 0; + + function countOrphanCalls(record) { + let origCheck = record._internalModel._checkForOrphanedInternalModels; + let origCleanup = record._internalModel._cleanupOrphanedInternalModels; + + record._internalModel._checkForOrphanedInternalModels = function () { + ++checkOrphanCalls; + return origCheck.apply(record._internalModel, arguments); + }; + + record._internalModel._cleanupOrphanedInternalModels = function () { + ++cleanupOrphanCalls; + return origCleanup.apply(record._internalModel, arguments); + }; + } + countOrphanCalls(env.store.peekRecord('person', 1)); + countOrphanCalls(env.store.peekRecord('car', 1)); + countOrphanCalls(env.store.peekRecord('car', 2)); + + run(() => { + env.store.peekRecord('person', 1).unloadRecord(); + env.store.peekRecord('car', 1).unloadRecord(); + env.store.peekRecord('car', 2).unloadRecord(); }); + + assert.equal(env.store._recordMapFor('person').records.length, 0); + assert.equal(env.store._recordMapFor('car').records.length, 0); + + assert.equal(checkOrphanCalls, 3, 'each internalModel checks for cleanup'); + assert.equal(cleanupOrphanCalls, 1, 'cleanup only happens once'); }); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index bf49959d009..74592311f49 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -29,44 +29,53 @@ module("integration/relationships/has_many - Has-Many Relationships", { Contact = DS.Model.extend({ user: belongsTo('user', { async: false }) }); + Contact.reopenClass({ toString: () => 'Contact' }); Email = Contact.extend({ email: attr('string') }); + Email.reopenClass({ toString: () => 'Email' }); Phone = Contact.extend({ number: attr('string') }); + Phone.reopenClass({ toString: () => 'Phone' }); Message = DS.Model.extend({ user: belongsTo('user', { async: false }), created_at: attr('date') }); + Message.reopenClass({ toString: () => 'Message' }); Post = Message.extend({ title: attr('string'), comments: hasMany('comment', { async: false }) }); + Post.reopenClass({ toString: () => 'Post' }); Comment = Message.extend({ body: DS.attr('string'), message: DS.belongsTo('post', { polymorphic: true, async: true }) }); + Comment.reopenClass({ toString: () => 'Comment' }); Book = DS.Model.extend({ title: attr(), chapters: hasMany('chapter', { async: true }) }); + Book.reopenClass({ toString: () => 'Book' }); Chapter = DS.Model.extend({ title: attr(), pages: hasMany('page', { async: false }) }); + Chapter.reopenClass({ toString: () => 'Chapter' }); Page = DS.Model.extend({ number: attr('number'), chapter: belongsTo('chapter', { async: false }) }); + Page.reopenClass({ toString: () => 'Page' }); env = setupStore({ user: User, @@ -2197,10 +2206,12 @@ test("adding and removing records from hasMany relationship #2666", function(ass var Post = DS.Model.extend({ comments: DS.hasMany('comment', { async: true }) }); + Post.reopenClass({ toString: () => 'Post' }); var Comment = DS.Model.extend({ post: DS.belongsTo('post', { async: false }) }); + Comment.reopenClass({ toString: () => 'Comment' }); env = setupStore({ post: Post, @@ -2776,7 +2787,7 @@ test("unloading and reloading a record with hasMany relationship - #3084", funct user = env.store.peekRecord('user', 'user-1'); - assert.equal(get(user, 'messages.firstObject.id'), 'message-1'); - assert.equal(get(message, 'user.id'), 'user-1'); + assert.equal(get(user, 'messages.firstObject.id'), 'message-1', 'user points to message'); + assert.equal(get(message, 'user.id'), 'user-1', 'message points to user'); }); }); diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index f133d1bea4e..9b000618661 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -525,7 +525,7 @@ test("Deleting a record that has a hasMany relationship removes it from the othe user.rollbackAttributes(); }); assert.equal(account.get('users.length'), 0, 'Users got removed'); - assert.equal(user.get('accounts.length'), undefined, 'Accounts got rolledback correctly'); + assert.equal(user.get('accounts.length'), 0, 'Accounts got rolledback correctly'); }); diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index 6225205f555..59a5f5feb7e 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -1449,6 +1449,6 @@ test("Rollbacking attributes of a created record works correctly when the belong user.get('accounts').pushObject(account); }); run(user, 'rollbackAttributes'); - assert.equal(user.get('accounts.length'), undefined, "User does not have the account anymore"); + assert.equal(user.get('accounts.length'), 0, "User does not have the account anymore"); assert.equal(account.get('user'), null, 'Account does not have the user anymore'); }); diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 176de164571..c5767002db5 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -13,6 +13,7 @@ var Person = DS.Model.extend({ name: DS.attr('string'), cars: DS.hasMany('car', { async: false }) }); +Person.reopenClass({ toString: () => 'Person' }); var run = Ember.run; @@ -21,6 +22,7 @@ var Car = DS.Model.extend({ model: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); +Car.reopenClass({ toString: () => 'Car' }); function initializeStore(adapter) { env = setupStore({ @@ -195,11 +197,8 @@ test("destroying the store correctly cleans everything up", function(assert) { assert.equal(car.get('person'), person, "expected car's person to be the correct person"); assert.equal(person.get('cars.firstObject'), car, " expected persons cars's firstRecord to be the correct car"); - Ember.run(person, person.destroy); Ember.run(store, 'destroy'); - assert.equal(car.get('person'), null, "expected car.person to no longer be present"); - assert.equal(personWillDestroy.called.length, 1, 'expected person to have recieved willDestroy once'); assert.equal(carWillDestroy.called.length, 1, 'expected car to recieve willDestroy once'); assert.equal(carsWillDestroy.called.length, 1, 'expected cars to recieve willDestroy once'); diff --git a/tests/unit/many-array-test.js b/tests/unit/many-array-test.js index cd2fd323cf5..115efadbb04 100644 --- a/tests/unit/many-array-test.js +++ b/tests/unit/many-array-test.js @@ -19,11 +19,13 @@ module("unit/many_array - DS.ManyArray", { title: attr('string'), tags: hasMany('tag', { async: false }) }); + Post.reopenClass({ toString: () => 'Post'}); Tag = DS.Model.extend({ name: attr('string'), post: belongsTo('post', { async: false }) }); + Tag.reopenClass({ toString: () => 'Tag'}); env = setupStore({ post: Post, @@ -88,7 +90,7 @@ test("manyArray.save() calls save() on all records", function(assert) { }); test("manyArray trigger arrayContentChange functions with the correct values", function(assert) { - assert.expect(12); + assert.expect(6); var willChangeStartIdx; var willChangeRemoveAmt; var willChangeAddAmt; diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index 9c58865b958..178e4499607 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -15,6 +15,7 @@ module("unit/model/rollbackAttributes - model.rollbackAttributes()", { firstName: DS.attr(), lastName: DS.attr() }); + Person.reopenClass({ toString() { return 'Person'; } }); env = setupStore({ person: Person }); store = env.store; diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index 9bcd77696c5..fc6a4875be6 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -17,6 +17,8 @@ module("unit/store/unload - Store unloading records", { title: DS.attr('string'), wasFetched: DS.attr('boolean') }); + Record.reopenClass({ toString: () => 'Record'}); + store = createStore({ adapter: DS.Adapter.extend({ findRecord(store, type, id, snapshot) { @@ -47,26 +49,25 @@ testInDebug("unload a dirty record asserts", function(assert) { } }); - store.findRecord('record', 1).then(function(record) { - record.set('title', 'toto2'); - record._internalModel.send('willCommit'); + let record = store.peekRecord('record', 1); + record.set('title', 'toto2'); + record._internalModel.send('willCommit'); - assert.equal(get(record, 'hasDirtyAttributes'), true, "record is dirty"); + assert.equal(get(record, 'hasDirtyAttributes'), true, "record is dirty"); - assert.expectAssertion(function() { - record.unloadRecord(); - }, "You can only unload a record which is not inFlight. `" + record._internalModel.toString() + "`", "can not unload dirty record"); + assert.expectAssertion(function() { + record.unloadRecord(); + }, "You can only unload a record which is not inFlight. `" + record._internalModel.toString() + "`", "can not unload dirty record"); - // force back into safe to unload mode. - run(function() { - record._internalModel.transitionTo('deleted.saved'); - }); + // force back into safe to unload mode. + run(function() { + record._internalModel.transitionTo('deleted.saved'); }); }); }); -test("unload a record", function(assert) { - assert.expect(5); +test('unload a record', function(assert) { + assert.expect(2); run(function() { store.push({ @@ -80,15 +81,11 @@ test("unload a record", function(assert) { }); store.findRecord('record', 1).then(function(record) { assert.equal(get(record, 'id'), 1, "found record with id 1"); - assert.equal(get(record, 'hasDirtyAttributes'), false, "record is not dirty"); run(function() { store.unloadRecord(record); }); - assert.equal(get(record, 'hasDirtyAttributes'), false, "record is not dirty"); - assert.equal(get(record, 'isDeleted'), true, "record is deleted"); - tryToFind = false; return store.findRecord('record', 1).then(function() { assert.equal(tryToFind, true, "not found record with id 1"); @@ -103,22 +100,23 @@ module("DS.Store - unload record with relationships"); test("can commit store after unload record with relationships", function(assert) { assert.expect(1); - var like, product; - - var Brand = DS.Model.extend({ + let Brand = DS.Model.extend({ name: DS.attr('string') }); + Brand.reopenClass({ toString: () => 'Brand'}); - var Product = DS.Model.extend({ + let Product = DS.Model.extend({ description: DS.attr('string'), brand: DS.belongsTo('brand', { async: false }) }); + Product.reopenClass({ toString: () => 'Product'}); - var Like = DS.Model.extend({ + let Like = DS.Model.extend({ product: DS.belongsTo('product', { async: false }) }); + Like.reopenClass({ toString: () => 'Like'}); - var store = createStore({ + let store = createStore({ adapter: DS.Adapter.extend({ findRecord(store, type, id, snapshot) { return Ember.RSVP.resolve({ id: 1, description: 'cuisinart', brand: 1 }); @@ -131,9 +129,8 @@ test("can commit store after unload record with relationships", function(assert) product: Product, like: Like }); - var asyncRecords; - run(function() { + return run(() => { store.push({ data: [{ type: 'brand', @@ -155,20 +152,17 @@ test("can commit store after unload record with relationships", function(assert) }] }); - asyncRecords = Ember.RSVP.hash({ - brand: store.findRecord('brand', 1), - product: store.findRecord('product', 1) - }); - asyncRecords.then(function(records) { - like = store.createRecord('like', { id: 1, product: product }); - records.like = like.save(); - return Ember.RSVP.hash(records); - }).then(function(records) { - store.unloadRecord(records.product); - return store.findRecord('product', 1); - }).then(function(product) { - assert.equal(product.get('description'), 'cuisinart', "The record was unloaded and the adapter's `findRecord` was called"); - store.destroy(); + let product = store.peekRecord('product', 1); + let like = store.createRecord('like', { id: 1, product: product }); + + return like.save(); + }).then(() => { + return run(() => { + store.unloadRecord(store.peekRecord('product', 1)); }); + }).then(() => { + return store.findRecord('product', 1); + }).then((product) => { + assert.equal(product.get('description'), 'cuisinart', "The record was unloaded and the adapter's `findRecord` was called"); }); }); From c41d1e85386c6322356845bbb12540492cbc1c13 Mon Sep 17 00:00:00 2001 From: pete_the_pete Date: Tue, 27 Dec 2016 22:45:38 -0800 Subject: [PATCH 1773/2527] [CLEANUP Beta] Linter changes for addon/-private/system --- addon/-private/system/clone-null.js | 4 +- addon/-private/system/debug/debug-adapter.js | 37 +++++++------- addon/-private/system/empty-object.js | 2 +- addon/-private/system/many-array.js | 12 ++--- addon/-private/system/model/errors.js | 18 +++---- addon/-private/system/ordered-set.js | 12 ++--- addon/-private/system/promise-proxies.js | 6 +-- .../-private/system/references/belongs-to.js | 48 +++++++++---------- addon/-private/system/references/has-many.js | 48 +++++++++---------- addon/-private/system/references/record.js | 16 +++---- addon/-private/system/relationship-meta.js | 2 +- .../system/relationships/belongs-to.js | 4 +- addon/-private/system/relationships/ext.js | 16 +++---- .../-private/system/relationships/has-many.js | 6 +-- .../system/relationships/state/belongs-to.js | 6 +-- .../relationships/state/relationship.js | 14 +++--- addon/-private/system/store/finders.js | 42 ++++++++-------- addon/-private/system/store/serializers.js | 2 +- 18 files changed, 147 insertions(+), 148 deletions(-) diff --git a/addon/-private/system/clone-null.js b/addon/-private/system/clone-null.js index 96d37b9e44a..ad6d64b1062 100644 --- a/addon/-private/system/clone-null.js +++ b/addon/-private/system/clone-null.js @@ -1,7 +1,7 @@ import EmptyObject from "ember-data/-private/system/empty-object"; export default function cloneNull(source) { - var clone = new EmptyObject(); - for (var key in source) { + let clone = new EmptyObject(); + for (let key in source) { clone[key] = source[key]; } return clone; diff --git a/addon/-private/system/debug/debug-adapter.js b/addon/-private/system/debug/debug-adapter.js index 6d9c62f4aca..2c11012e74b 100644 --- a/addon/-private/system/debug/debug-adapter.js +++ b/addon/-private/system/debug/debug-adapter.js @@ -3,9 +3,9 @@ */ import Ember from 'ember'; import Model from "ember-data/model"; -var get = Ember.get; -var capitalize = Ember.String.capitalize; -var underscore = Ember.String.underscore; +const get = Ember.get; +const capitalize = Ember.String.capitalize; +const underscore = Ember.String.underscore; const { assert } = Ember; /* @@ -30,15 +30,15 @@ export default Ember.DataAdapter.extend({ }, columnsForType(typeClass) { - var columns = [{ + let columns = [{ name: 'id', desc: 'Id' }]; - var count = 0; - var self = this; + let count = 0; + let self = this; get(typeClass, 'attributes').forEach((meta, name) => { if (count++ > self.attributeLimit) { return false; } - var desc = capitalize(underscore(name).replace('_', ' ')); + let desc = capitalize(underscore(name).replace('_', ' ')); columns.push({ name: name, desc: desc }); }); return columns; @@ -60,22 +60,21 @@ export default Ember.DataAdapter.extend({ }, getRecordColumnValues(record) { - var count = 0; - var columnValues = { id: get(record, 'id') }; + let count = 0; + let columnValues = { id: get(record, 'id') }; record.eachAttribute((key) => { if (count++ > this.attributeLimit) { return false; } - var value = get(record, key); - columnValues[key] = value; + columnValues[key] = get(record, key); }); return columnValues; }, getRecordKeywords(record) { - var keywords = []; - var keys = Ember.A(['id']); + let keywords = []; + let keys = Ember.A(['id']); record.eachAttribute((key) => keys.push(key)); keys.forEach((key) => keywords.push(get(record, key))); return keywords; @@ -90,7 +89,7 @@ export default Ember.DataAdapter.extend({ }, getRecordColor(record) { - var color = 'black'; + let color = 'black'; if (record.get('isNew')) { color = 'green'; } else if (record.get('hasDirtyAttributes')) { @@ -100,14 +99,14 @@ export default Ember.DataAdapter.extend({ }, observeRecord(record, recordUpdated) { - var releaseMethods = Ember.A(); - var keysToObserve = Ember.A(['id', 'isNew', 'hasDirtyAttributes']); + let releaseMethods = Ember.A(); + let keysToObserve = Ember.A(['id', 'isNew', 'hasDirtyAttributes']); record.eachAttribute((key) => keysToObserve.push(key)); - var adapter = this; + let adapter = this; keysToObserve.forEach(function(key) { - var handler = function() { + let handler = function() { recordUpdated(adapter.wrapRecord(record)); }; Ember.addObserver(record, key, handler); @@ -116,7 +115,7 @@ export default Ember.DataAdapter.extend({ }); }); - var release = function() { + let release = function() { releaseMethods.forEach((fn) => fn()); }; diff --git a/addon/-private/system/empty-object.js b/addon/-private/system/empty-object.js index f90e0d3b125..2c526a15b02 100644 --- a/addon/-private/system/empty-object.js +++ b/addon/-private/system/empty-object.js @@ -3,7 +3,7 @@ // when you're treating the object instances as arbitrary dictionaries // and don't want your keys colliding with build-in methods on the // default object prototype. -var proto = Object.create(null, { +const proto = Object.create(null, { // without this, we will always still end up with (new // EmptyObject()).constructor === Object constructor: { diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 53b4383b18b..1b7f3564e2d 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -211,7 +211,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { @private */ loadingRecordsCount(count) { - this.loadingRecordsCount = count; + this._loadingRecordsCount = count; }, /** @@ -219,8 +219,8 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { @private */ loadedRecord() { - this.loadingRecordsCount--; - if (this.loadingRecordsCount === 0) { + this._loadingRecordsCount--; + if (this._loadingRecordsCount === 0) { set(this, 'isLoaded', true); this.trigger('didLoad'); } @@ -290,9 +290,9 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { @return {DS.Model} record */ createRecord(hash) { - var store = get(this, 'store'); - var type = get(this, 'type'); - var record; + let store = get(this, 'store'); + let type = get(this, 'type'); + let record; assert(`You cannot add '${type.modelName}' records to this polymorphic relationship.`, !get(this, 'isPolymorphic')); record = store.createRecord(type.modelName, hash); diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index 5a7c656597d..a04ddde200a 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -1,12 +1,12 @@ import Ember from 'ember'; import { deprecate, warn } from "ember-data/-private/debug"; -var get = Ember.get; -var set = Ember.set; -var isEmpty = Ember.isEmpty; -var makeArray = Ember.makeArray; +const get = Ember.get; +const set = Ember.set; +const isEmpty = Ember.isEmpty; +const makeArray = Ember.makeArray; -var MapWithDefault = Ember.MapWithDefault; +const MapWithDefault = Ember.MapWithDefault; /** @module ember-data @@ -32,7 +32,7 @@ var MapWithDefault = Ember.MapWithDefault; And you attempted to save a record that did not validate on the backend: ```javascript - var user = store.createRecord('user', { + let user = store.createRecord('user', { username: 'tomster', email: 'invalidEmail' }); @@ -137,7 +137,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { Returns errors for a given attribute ```javascript - var user = store.createRecord('user', { + let user = store.createRecord('user', { username: 'tomster', email: 'invalidEmail' }); @@ -186,7 +186,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @private */ unknownProperty(attribute) { - var errors = this.errorsFor(attribute); + let errors = this.errorsFor(attribute); if (isEmpty(errors)) { return null; } return errors; }, @@ -228,7 +228,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { id: 'ds.errors.add' }); - var wasEmpty = get(this, 'isEmpty'); + let wasEmpty = get(this, 'isEmpty'); this._add(attribute, messages); diff --git a/addon/-private/system/ordered-set.js b/addon/-private/system/ordered-set.js index d09a1451871..766f722a0a3 100644 --- a/addon/-private/system/ordered-set.js +++ b/addon/-private/system/ordered-set.js @@ -1,14 +1,14 @@ import Ember from 'ember'; -var EmberOrderedSet = Ember.OrderedSet; -var guidFor = Ember.guidFor; +const EmberOrderedSet = Ember.OrderedSet; +const guidFor = Ember.guidFor; export default function OrderedSet() { this._super$constructor(); } OrderedSet.create = function() { - var Constructor = this; + let Constructor = this; return new Constructor(); }; @@ -17,9 +17,9 @@ OrderedSet.prototype.constructor = OrderedSet; OrderedSet.prototype._super$constructor = EmberOrderedSet; OrderedSet.prototype.addWithIndex = function(obj, idx) { - var guid = guidFor(obj); - var presenceSet = this.presenceSet; - var list = this.list; + let guid = guidFor(obj); + let presenceSet = this.presenceSet; + let list = this.list; if (presenceSet[guid] === true) { return; diff --git a/addon/-private/system/promise-proxies.js b/addon/-private/system/promise-proxies.js index 83c503b558b..6fc3f9a8e8f 100644 --- a/addon/-private/system/promise-proxies.js +++ b/addon/-private/system/promise-proxies.js @@ -16,7 +16,7 @@ const { get , RSVP: { Promise }} = Ember; Example ```javascript - var promiseArray = DS.PromiseArray.create({ + let promiseArray = DS.PromiseArray.create({ promise: $.getJSON('/some/remote/data.json') }); @@ -47,7 +47,7 @@ export const PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin); Example ```javascript - var promiseObject = DS.PromiseObject.create({ + let promiseObject = DS.PromiseObject.create({ promise: $.getJSON('/some/remote/data.json') }); @@ -63,7 +63,7 @@ export const PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin); @extends Ember.ObjectProxy @uses Ember.PromiseProxyMixin */ -export const PromiseObject = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin); +export let PromiseObject = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin); export function promiseObject(promise, label) { return PromiseObject.create({ diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 81dd48abb86..d9ad4acccd2 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -15,7 +15,7 @@ import { assertPolymorphicType, deprecate } from "ember-data/-private/debug"; @namespace DS @extends DS.Reference */ -var BelongsToReference = function(store, parentInternalModel, belongsToRelationship) { +const BelongsToReference = function(store, parentInternalModel, belongsToRelationship) { this._super$constructor(store, parentInternalModel); this.belongsToRelationship = belongsToRelationship; this.type = belongsToRelationship.relationshipMeta.type; @@ -41,7 +41,7 @@ BelongsToReference.prototype._super$constructor = Reference; user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ type: 'blog', id: 1, relationships: { @@ -50,13 +50,13 @@ BelongsToReference.prototype._super$constructor = Reference; } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); // get the identifier of the reference if (userRef.remoteType() === "id") { - var id = userRef.id(); + let id = userRef.id(); } else if (userRef.remoteType() === "link") { - var link = userRef.link(); + let link = userRef.link(); } ``` @@ -86,7 +86,7 @@ BelongsToReference.prototype.remoteType = function() { user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, @@ -97,11 +97,11 @@ BelongsToReference.prototype.remoteType = function() { } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); // get the identifier of the reference if (userRef.remoteType() === "id") { - var id = userRef.id(); + let id = userRef.id(); } ``` @@ -109,7 +109,7 @@ BelongsToReference.prototype.remoteType = function() { @return {String} The id of the record in this belongsTo relationship. */ BelongsToReference.prototype.id = function() { - var inverseRecord = this.belongsToRelationship.inverseRecord; + let inverseRecord = this.belongsToRelationship.inverseRecord; return inverseRecord && inverseRecord.id; }; @@ -125,7 +125,7 @@ BelongsToReference.prototype.id = function() { user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, @@ -138,11 +138,11 @@ BelongsToReference.prototype.id = function() { } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); // get the identifier of the reference if (userRef.remoteType() === "link") { - var link = userRef.link(); + let link = userRef.link(); } ``` @@ -164,7 +164,7 @@ BelongsToReference.prototype.link = function() { user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, @@ -183,7 +183,7 @@ BelongsToReference.prototype.link = function() { } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); userRef.meta() // { lastUpdated: 1458014400000 } ``` @@ -208,7 +208,7 @@ BelongsToReference.prototype.meta = function() { user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, @@ -219,7 +219,7 @@ BelongsToReference.prototype.meta = function() { } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); // provide data for reference userRef.push({ @@ -241,7 +241,7 @@ BelongsToReference.prototype.meta = function() { */ BelongsToReference.prototype.push = function(objectOrPromise) { return Ember.RSVP.resolve(objectOrPromise).then((data) => { - var record; + let record; if (data instanceof Model) { if (isEnabled('ds-overhaul-references')) { @@ -278,7 +278,7 @@ BelongsToReference.prototype.push = function(objectOrPromise) { user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, @@ -289,7 +289,7 @@ BelongsToReference.prototype.push = function(objectOrPromise) { } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); userRef.value(); // null @@ -312,7 +312,7 @@ BelongsToReference.prototype.push = function(objectOrPromise) { @return {DS.Model} the record in this relationship */ BelongsToReference.prototype.value = function() { - var inverseRecord = this.belongsToRelationship.inverseRecord; + let inverseRecord = this.belongsToRelationship.inverseRecord; if (inverseRecord && inverseRecord.isLoaded()) { return inverseRecord.getRecord(); @@ -334,7 +334,7 @@ BelongsToReference.prototype.value = function() { user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, @@ -345,7 +345,7 @@ BelongsToReference.prototype.value = function() { } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); userRef.value(); // null @@ -382,7 +382,7 @@ BelongsToReference.prototype.load = function() { user: DS.belongsTo({ async: true }) }); - var blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, @@ -393,7 +393,7 @@ BelongsToReference.prototype.load = function() { } } }); - var userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); userRef.reload().then(function(user) { userRef.value() === user diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index a92d9dca0c2..31b6ccbd03c 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -20,7 +20,7 @@ const { @class HasManyReference @namespace DS */ -var HasManyReference = function(store, parentInternalModel, hasManyRelationship) { +const HasManyReference = function(store, parentInternalModel, hasManyRelationship) { this._super$constructor(store, parentInternalModel); this.hasManyRelationship = hasManyRelationship; this.type = hasManyRelationship.relationshipMeta.type; @@ -47,7 +47,7 @@ HasManyReference.prototype._super$constructor = Reference; ``` ```javascript - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, @@ -59,13 +59,13 @@ HasManyReference.prototype._super$constructor = Reference; } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); // get the identifier of the reference if (commentsRef.remoteType() === "ids") { - var ids = commentsRef.ids(); + let ids = commentsRef.ids(); } else if (commentsRef.remoteType() === "link") { - var link = commentsRef.link(); + let link = commentsRef.link(); } ``` @@ -93,7 +93,7 @@ HasManyReference.prototype.remoteType = function() { ``` ```javascript - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, @@ -107,7 +107,7 @@ HasManyReference.prototype.remoteType = function() { } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); commentsRef.link(); // '/posts/1/comments' ``` @@ -131,7 +131,7 @@ HasManyReference.prototype.link = function() { ``` ```javascript - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, @@ -143,7 +143,7 @@ HasManyReference.prototype.link = function() { } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); commentsRef.ids(); // ['1'] ``` @@ -172,7 +172,7 @@ HasManyReference.prototype.ids = function() { ``` ```javascript - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, @@ -191,7 +191,7 @@ HasManyReference.prototype.ids = function() { } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); commentsRef.meta(); // { count: 10 } ``` @@ -217,7 +217,7 @@ HasManyReference.prototype.meta = function() { ``` ``` - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, @@ -229,7 +229,7 @@ HasManyReference.prototype.meta = function() { } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); commentsRef.ids(); // ['1'] @@ -247,7 +247,7 @@ HasManyReference.prototype.meta = function() { */ HasManyReference.prototype.push = function(objectOrPromise) { return resolve(objectOrPromise).then((payload) => { - var array = payload; + let array = payload; if (isEnabled("ds-overhaul-references")) { deprecate("HasManyReference#push(array) is deprecated. Push a JSON-API document instead.", !Array.isArray(payload), { @@ -276,10 +276,10 @@ HasManyReference.prototype.push = function(objectOrPromise) { let internalModels; if (useLegacyArrayPush) { internalModels = array.map((obj) => { - var record = this.store.push(obj); + let record = this.store.push(obj); runInDebug(() => { - var relationshipMeta = this.hasManyRelationship.relationshipMeta; + let relationshipMeta = this.hasManyRelationship.relationshipMeta; assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel); }); @@ -291,7 +291,7 @@ HasManyReference.prototype.push = function(objectOrPromise) { runInDebug(() => { internalModels.forEach((internalModel) => { - var relationshipMeta = this.hasManyRelationship.relationshipMeta; + let relationshipMeta = this.hasManyRelationship.relationshipMeta; assertPolymorphicType(this.internalModel, relationshipMeta, internalModel); }); }); @@ -304,7 +304,7 @@ HasManyReference.prototype.push = function(objectOrPromise) { }; HasManyReference.prototype._isLoaded = function() { - var hasData = get(this.hasManyRelationship, 'hasData'); + let hasData = get(this.hasManyRelationship, 'hasData'); if (!hasData) { return false; } @@ -332,7 +332,7 @@ HasManyReference.prototype._isLoaded = function() { ``` ```javascript - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, @@ -344,7 +344,7 @@ HasManyReference.prototype._isLoaded = function() { } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); post.get('comments').then(function(comments) { commentsRef.value() === comments @@ -376,7 +376,7 @@ HasManyReference.prototype.value = function() { ``` ```javascript - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, @@ -388,7 +388,7 @@ HasManyReference.prototype.value = function() { } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); commentsRef.load().then(function(comments) { //... @@ -419,7 +419,7 @@ HasManyReference.prototype.load = function() { ``` ```javascript - var post = store.push({ + let post = store.push({ data: { type: 'post', id: 1, @@ -431,7 +431,7 @@ HasManyReference.prototype.load = function() { } }); - var commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); commentsRef.reload().then(function(comments) { //... diff --git a/addon/-private/system/references/record.js b/addon/-private/system/references/record.js index 0e186104223..0b10d44d176 100644 --- a/addon/-private/system/references/record.js +++ b/addon/-private/system/references/record.js @@ -8,7 +8,7 @@ import Reference from './reference'; @class RecordReference @namespace DS */ -var RecordReference = function(store, internalModel) { +const RecordReference = function(store, internalModel) { this._super$constructor(store, internalModel); this.type = internalModel.modelName; this._id = internalModel.id; @@ -27,7 +27,7 @@ RecordReference.prototype._super$constructor = Reference; Example ```javascript - var userRef = store.getReference('user', 1); + let userRef = store.getReference('user', 1); userRef.id(); // '1' ``` @@ -47,7 +47,7 @@ RecordReference.prototype.id = function() { Example ```javascript - var userRef = store.getReference('user', 1); + const userRef = store.getReference('user', 1); userRef.remoteType(); // 'identity' ``` @@ -77,7 +77,7 @@ RecordReference.prototype.remoteType = function() { Example ```javascript - var userRef = store.getReference('user', 1); + let userRef = store.getReference('user', 1); // provide data for reference userRef.push({ data: { id: 1, username: "@user" }}).then(function(user) { @@ -103,7 +103,7 @@ RecordReference.prototype.push = function(objectOrPromise) { Example ```javascript - var userRef = store.getReference('user', 1); + let userRef = store.getReference('user', 1); userRef.value(); // user ``` @@ -122,7 +122,7 @@ RecordReference.prototype.value = function() { Example ```javascript - var userRef = store.getReference('user', 1); + let userRef = store.getReference('user', 1); // load user (via store.find) userRef.load().then(...) @@ -142,7 +142,7 @@ RecordReference.prototype.load = function() { Example ```javascript - var userRef = store.getReference('user', 1); + let userRef = store.getReference('user', 1); // or trigger a reload userRef.reload().then(...) @@ -152,7 +152,7 @@ RecordReference.prototype.load = function() { @return {Promise} the record for this RecordReference */ RecordReference.prototype.reload = function() { - var record = this.value(); + let record = this.value(); if (record) { return record.reload(); } diff --git a/addon/-private/system/relationship-meta.js b/addon/-private/system/relationship-meta.js index 356a155c120..1c3ca070cb1 100644 --- a/addon/-private/system/relationship-meta.js +++ b/addon/-private/system/relationship-meta.js @@ -2,7 +2,7 @@ import {singularize} from 'ember-inflector'; import normalizeModelName from 'ember-data/-private/system/normalize-model-name'; export function typeForRelationshipMeta(meta) { - var modelName; + let modelName; modelName = meta.type || meta.key; if (meta.kind === 'hasMany') { diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 082300fc467..7d3e045d9fc 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -75,7 +75,7 @@ import normalizeModelName from "ember-data/-private/system/normalize-model-name" @return {Ember.computed} relationship */ export default function belongsTo(modelName, options) { - var opts, userEnteredModelName; + let opts, userEnteredModelName; if (typeof modelName === 'object') { opts = modelName; userEnteredModelName = undefined; @@ -92,7 +92,7 @@ export default function belongsTo(modelName, options) { opts = opts || {}; - var meta = { + let meta = { type: userEnteredModelName, isRelationship: true, options: opts, diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index d4042949ec8..64ba8b236dc 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -5,15 +5,15 @@ import { relationshipFromMeta } from "ember-data/-private/system/relationship-meta"; -var Map = Ember.Map; -var MapWithDefault = Ember.MapWithDefault; +const Map = Ember.Map; +const MapWithDefault = Ember.MapWithDefault; export const relationshipsDescriptor = Ember.computed(function() { if (Ember.testing === true && relationshipsDescriptor._cacheable === true) { relationshipsDescriptor._cacheable = false; } - var map = new MapWithDefault({ + let map = new MapWithDefault({ defaultValue() { return []; } }); @@ -23,7 +23,7 @@ export const relationshipsDescriptor = Ember.computed(function() { // it to the map. if (meta.isRelationship) { meta.key = name; - var relationshipsForType = map.get(typeForRelationshipMeta(meta)); + let relationshipsForType = map.get(typeForRelationshipMeta(meta)); relationshipsForType.push({ name: name, @@ -40,8 +40,8 @@ export const relatedTypesDescriptor = Ember.computed(function() { relatedTypesDescriptor._cacheable = false; } - var modelName; - var types = Ember.A(); + let modelName; + let types = Ember.A(); // Loop through each computed property on the class, // and create an array of the unique types involved @@ -68,12 +68,12 @@ export const relationshipsByNameDescriptor = Ember.computed(function() { relationshipsByNameDescriptor._cacheable = false; } - var map = Map.create(); + let map = Map.create(); this.eachComputedProperty((name, meta) => { if (meta.isRelationship) { meta.key = name; - var relationship = relationshipFromMeta(meta); + let relationship = relationshipFromMeta(meta); relationship.type = typeForRelationshipMeta(meta); map.set(name, relationship); } diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index fc82f89bdbf..235281a8fdc 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -132,7 +132,7 @@ export default function hasMany(type, options) { // the relationship. This is used for introspection and // serialization. Note that `key` is populated lazily // the first time the CP is called. - var meta = { + let meta = { type: type, isRelationship: true, options: options, @@ -143,7 +143,7 @@ export default function hasMany(type, options) { return Ember.computed({ get(key) { - var relationship = this._internalModel._relationships.get(key); + let relationship = this._internalModel._relationships.get(key); return relationship.getRecords(); }, set(key, records) { @@ -152,7 +152,7 @@ export default function hasMany(type, options) { return Ember.A(records).every((record) => record.hasOwnProperty('_internalModel') === true); })()); - var relationship = this._internalModel._relationships.get(key); + let relationship = this._internalModel._relationships.get(key); relationship.clear(); relationship.addRecords(Ember.A(records).mapBy('_internalModel')); return relationship.getRecords(); diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 7f4b2dbf1ac..417d3243af3 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -79,7 +79,7 @@ export default class BelongsToRelationship extends Relationship { } setRecordPromise(newPromise) { - var content = newPromise.get && newPromise.get('content'); + let content = newPromise.get && newPromise.get('content'); assert("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); this.setRecord(content ? content._internalModel : content); } @@ -121,7 +121,7 @@ export default class BelongsToRelationship extends Relationship { getRecord() { //TODO(Igor) flushCanonical here once our syncing is not stupid if (this.isAsync) { - var promise; + let promise; if (this.link) { if (this.hasLoaded) { promise = this.findRecord(); @@ -140,7 +140,7 @@ export default class BelongsToRelationship extends Relationship { if (this.inverseRecord === null) { return null; } - var toReturn = this.inverseRecord.getRecord(); + let toReturn = this.inverseRecord.getRecord(); assert("You looked up the '" + this.key + "' relationship on a '" + this.internalModel.modelName + "' with id " + this.internalModel.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); return toReturn; } diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 44c1367644b..87d9d7161a9 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -56,7 +56,7 @@ const { export default class Relationship { constructor(store, internalModel, inverseKey, relationshipMeta) { heimdall.increment(newRelationship); - var async = relationshipMeta.options.async; + let async = relationshipMeta.options.async; this.members = new OrderedSet(); this.canonicalMembers = new OrderedSet(); this.store = store; @@ -142,7 +142,7 @@ export default class Relationship { addCanonicalRecords(records, idx) { heimdall.increment(addCanonicalRecords); - for (var i=0; i result); } diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 8bef9a0876d..54b64f4db25 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -14,7 +14,7 @@ import { serializerForAdapter } from "ember-data/-private/system/store/serializers"; -var Promise = Ember.RSVP.Promise; +const Promise = Ember.RSVP.Promise; function payloadIsNotBlank(adapterPayload) { if (Array.isArray(adapterPayload)) { @@ -25,10 +25,10 @@ function payloadIsNotBlank(adapterPayload) { } export function _find(adapter, store, modelClass, id, internalModel, options) { - var snapshot = internalModel.createSnapshot(options); - var promise = adapter.findRecord(store, modelClass, id, snapshot); - var serializer = serializerForAdapter(store, adapter, internalModel.type.modelName); - var label = "DS: Handle Adapter#findRecord of " + modelClass + " with id: " + id; + let snapshot = internalModel.createSnapshot(options); + let promise = adapter.findRecord(store, modelClass, id, snapshot); + let serializer = serializerForAdapter(store, adapter, internalModel.type.modelName); + let label = "DS: Handle Adapter#findRecord of " + modelClass + " with id: " + id; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); @@ -75,11 +75,11 @@ export function _findMany(adapter, store, modelClass, ids, internalModels) { } export function _findHasMany(adapter, store, internalModel, link, relationship) { - var snapshot = internalModel.createSnapshot(); - var modelClass = store.modelFor(relationship.type); - var promise = adapter.findHasMany(store, snapshot, link, relationship); - var serializer = serializerForAdapter(store, adapter, relationship.type); - var label = "DS: Handle Adapter#findHasMany of " + internalModel + " : " + relationship.type; + let snapshot = internalModel.createSnapshot(); + let modelClass = store.modelFor(relationship.type); + let promise = adapter.findHasMany(store, snapshot, link, relationship); + let serializer = serializerForAdapter(store, adapter, relationship.type); + let label = "DS: Handle Adapter#findHasMany of " + internalModel + " : " + relationship.type; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); @@ -96,11 +96,11 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) } export function _findBelongsTo(adapter, store, internalModel, link, relationship) { - var snapshot = internalModel.createSnapshot(); - var modelClass = store.modelFor(relationship.type); - var promise = adapter.findBelongsTo(store, snapshot, link, relationship); - var serializer = serializerForAdapter(store, adapter, relationship.type); - var label = "DS: Handle Adapter#findBelongsTo of " + internalModel + " : " + relationship.type; + let snapshot = internalModel.createSnapshot(); + let modelClass = store.modelFor(relationship.type); + let promise = adapter.findBelongsTo(store, snapshot, link, relationship); + let serializer = serializerForAdapter(store, adapter, relationship.type); + let label = "DS: Handle Adapter#findBelongsTo of " + internalModel + " : " + relationship.type; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); @@ -118,12 +118,12 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship } export function _findAll(adapter, store, modelClass, sinceToken, options) { - var modelName = modelClass.modelName; - var recordArray = store.peekAll(modelName); - var snapshotArray = recordArray._createSnapshot(options); - var promise = adapter.findAll(store, modelClass, sinceToken, snapshotArray); - var serializer = serializerForAdapter(store, adapter, modelName); - var label = "DS: Handle Adapter#findAll of " + modelClass; + let modelName = modelClass.modelName; + let recordArray = store.peekAll(modelName); + let snapshotArray = recordArray._createSnapshot(options); + let promise = adapter.findAll(store, modelClass, sinceToken, snapshotArray); + let serializer = serializerForAdapter(store, adapter, modelName); + let label = "DS: Handle Adapter#findAll of " + modelClass; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); diff --git a/addon/-private/system/store/serializers.js b/addon/-private/system/store/serializers.js index f0e9453bfb5..2bd18cdcfc7 100644 --- a/addon/-private/system/store/serializers.js +++ b/addon/-private/system/store/serializers.js @@ -1,5 +1,5 @@ export function serializerForAdapter(store, adapter, type) { - var serializer = adapter.serializer; + let serializer = adapter.serializer; if (serializer === undefined) { serializer = store.serializerFor(type); From 3003393c7e9d15b0f2bd9ab918f391a030ddc622 Mon Sep 17 00:00:00 2001 From: Scott Batson Date: Thu, 19 Jan 2017 16:17:53 -0500 Subject: [PATCH 1774/2527] [DOC] - add bower install to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5bb734d6836..155214ba023 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,8 @@ See [CONTRIBUTING.md](https://github.com/emberjs/data/blob/master/CONTRIBUTING.m 3. Run `npm install` inside the project root to install the JS dependencies. +4. Run `bower install` inside the project root to install Ember dependencies. + ### In Your Browser 1. To start the development server, run `npm start`. From 3620bc189c918949ee218b76610369bfbd38c78a Mon Sep 17 00:00:00 2001 From: Ryan LaBouve Date: Mon, 23 Jan 2017 07:49:34 -0600 Subject: [PATCH 1775/2527] Document cache/request behavior of `query` #4733 (#4763) * Document cache/request behavior of `query` #4733 * Update on PR feedback --- addon/-private/system/store.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 64b62c0f602..77b84db1745 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1171,6 +1171,8 @@ Store = Service.extend({ This method delegates a query to the adapter. This is the one place where adapter-level semantics are exposed to the application. + Each time this method is called a new request is made through the adapter. + Exposing queries this way seems preferable to creating an abstract query language for all server-side queries, and then require all adapters to implement them. From 0c26d2df8c1baf7cb5099c3fe5ae90d1feade681 Mon Sep 17 00:00:00 2001 From: Mateusz Nowak Date: Mon, 23 Jan 2017 15:08:05 +0100 Subject: [PATCH 1776/2527] Update deprecate arguments (#4760) * Update deprecate arguments According to docs (https://github.com/emberjs/ember.js/blob/v2.10.0/packages/ember-debug/lib/deprecate.js#L97) ember deprecate requires 3 arguments. * Update store.js --- addon/-private/system/store.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 77b84db1745..bd4586396ff 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1785,7 +1785,7 @@ Store = Service.extend({ @return {boolean} */ recordIsLoaded(modelName, id) { - deprecate(`Use of recordIsLoaded is deprecated, use hasRecordForId instead.`, { + deprecate(`Use of recordIsLoaded is deprecated, use hasRecordForId instead.`, false, { id: 'ds.store.recordIsLoaded', until: '3.0' }); @@ -2619,7 +2619,7 @@ Store = Service.extend({ }, lookupAdapter(name) { - deprecate(`Use of lookupAdapter is deprecated, use adapterFor instead.`, { + deprecate(`Use of lookupAdapter is deprecated, use adapterFor instead.`, false, { id: 'ds.store.lookupAdapter', until: '3.0' }); @@ -2627,7 +2627,7 @@ Store = Service.extend({ }, lookupSerializer(name) { - deprecate(`Use of lookupSerializer is deprecated, use serializerFor instead.`, { + deprecate(`Use of lookupSerializer is deprecated, use serializerFor instead.`, false, { id: 'ds.store.lookupSerializer', until: '3.0' }); From 0b35b6464d22f79be945e55f953878ef9907ea5c Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Tue, 24 Jan 2017 11:18:54 -0500 Subject: [PATCH 1777/2527] [DOC] Update store.unloadRecord description See https://github.com/emberjs/data/pull/4765 for reference --- addon/-private/system/store.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index bd4586396ff..276533fa9c8 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -423,8 +423,8 @@ Store = Service.extend({ }, /** - For symmetry, a record can be unloaded via the store. Only - non-dirty records can be unloaded. + For symmetry, a record can be unloaded via the store. + This will cause the record to be destroyed and freed up for garbage collection. Example From 693a254034a3cd1f84fbda80292401c23f91cddf Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Tue, 24 Jan 2017 11:40:29 -0500 Subject: [PATCH 1778/2527] [DOC] Make model.unloadRecord public (#4765) * [DOC] Make model.unloadRecord public `store.unloadRecord` says that it's there for symmetry, meaning the model should have a similar public method. * Tweak second sentence --- addon/-private/system/model/model.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index da32cd604bc..0b10dcd856a 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -587,8 +587,9 @@ const Model = Ember.Object.extend(Ember.Evented, { }, /** + Unloads the record from the store. This will cause the record to be destroyed and freed up for garbage collection. + @method unloadRecord - @private */ unloadRecord() { if (this.isDestroyed) { return; } From bf21fb62e7e93314930c45ac693a9d332561c3a4 Mon Sep 17 00:00:00 2001 From: pete_the_pete Date: Tue, 27 Dec 2016 20:33:57 -0800 Subject: [PATCH 1779/2527] Linter changes for addon/-private (not private/system) --- addon/-private/adapters/build-url-mixin.js | 18 +++++++++--------- addon/-private/ext/date.js | 10 +++++----- .../-private/initializers/store-injections.js | 2 +- addon/-private/initializers/store.js | 2 +- .../initialize-store-service.js | 2 +- addon/-private/transforms/boolean.js | 2 +- addon/-private/transforms/date.js | 2 +- addon/-private/transforms/number.js | 6 +++--- addon/-private/transforms/string.js | 2 +- addon/-private/utils.js | 4 ++-- 10 files changed, 25 insertions(+), 25 deletions(-) diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index 8e3f48d973d..7b5433ffe3b 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -1,6 +1,6 @@ import Ember from 'ember'; -var get = Ember.get; +const get = Ember.get; /** @@ -86,10 +86,10 @@ export default Ember.Mixin.create({ @return {String} url */ _buildURL(modelName, id) { - var url = []; - var host = get(this, 'host'); - var prefix = this.urlPrefix(); - var path; + let path; + let url = []; + let host = get(this, 'host'); + let prefix = this.urlPrefix(); if (modelName) { path = this.pathForType(modelName); @@ -378,8 +378,8 @@ export default Ember.Mixin.create({ @return {String} urlPrefix */ urlPrefix(path, parentURL) { - var host = get(this, 'host'); - var namespace = get(this, 'namespace'); + let host = get(this, 'host'); + let namespace = get(this, 'namespace'); if (!host || host === '/') { host = ''; @@ -401,7 +401,7 @@ export default Ember.Mixin.create({ } // No path provided - var url = []; + let url = []; if (host) { url.push(host); } if (namespace) { url.push(namespace); } return url.join('/'); @@ -434,7 +434,7 @@ export default Ember.Mixin.create({ @return {String} path **/ pathForType(modelName) { - var camelized = Ember.String.camelize(modelName); + let camelized = Ember.String.camelize(modelName); return Ember.String.pluralize(camelized); } }); diff --git a/addon/-private/ext/date.js b/addon/-private/ext/date.js index 4067a45f769..b15e6a371c2 100644 --- a/addon/-private/ext/date.js +++ b/addon/-private/ext/date.js @@ -20,12 +20,12 @@ import { deprecate } from 'ember-data/-private/debug'; */ Ember.Date = Ember.Date || {}; -var origParse = Date.parse; -var numericKeys = [1, 4, 5, 6, 7, 10, 11]; +const origParse = Date.parse; +const numericKeys = [1, 4, 5, 6, 7, 10, 11]; export const parseDate = function (date) { - var timestamp, struct; - var minutesOffset = 0; + let timestamp, struct; + let minutesOffset = 0; // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string // before falling back to any implementation-specific date parsing, so that’s what we do, even if native @@ -33,7 +33,7 @@ export const parseDate = function (date) { // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?:(\d{2}))?)?)?$/.exec(date))) { // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC - for (var i = 0, k; (k = numericKeys[i]); ++i) { + for (let i = 0, k; (k = numericKeys[i]); ++i) { struct[k] = +struct[k] || 0; } diff --git a/addon/-private/initializers/store-injections.js b/addon/-private/initializers/store-injections.js index 70af3500aea..e36c0461b2d 100644 --- a/addon/-private/initializers/store-injections.js +++ b/addon/-private/initializers/store-injections.js @@ -8,7 +8,7 @@ export default function initializeStoreInjections(registry) { // registry.injection for Ember < 2.1.0 // application.inject for Ember 2.1.0+ - var inject = registry.inject || registry.injection; + let inject = registry.inject || registry.injection; inject.call(registry, 'controller', 'store', 'service:store'); inject.call(registry, 'route', 'store', 'service:store'); inject.call(registry, 'data-adapter', 'store', 'service:store'); diff --git a/addon/-private/initializers/store.js b/addon/-private/initializers/store.js index 95d737fa974..2857e62c443 100644 --- a/addon/-private/initializers/store.js +++ b/addon/-private/initializers/store.js @@ -22,7 +22,7 @@ function has(applicationOrRegistry, fullName) { export default function initializeStore(registry) { // registry.optionsForType for Ember < 2.1.0 // application.registerOptionsForType for Ember 2.1.0+ - var registerOptionsForType = registry.registerOptionsForType || registry.optionsForType; + let registerOptionsForType = registry.registerOptionsForType || registry.optionsForType; registerOptionsForType.call(registry, 'serializer', { singleton: false }); registerOptionsForType.call(registry, 'adapter', { singleton: false }); diff --git a/addon/-private/instance-initializers/initialize-store-service.js b/addon/-private/instance-initializers/initialize-store-service.js index b2d9fa1ec99..16a27c9947a 100644 --- a/addon/-private/instance-initializers/initialize-store-service.js +++ b/addon/-private/instance-initializers/initialize-store-service.js @@ -6,7 +6,7 @@ @param {Ember.ApplicationInstance} applicationOrRegistry */ export default function initializeStoreService(application) { - var container = application.lookup ? application : application.container; + let container = application.lookup ? application : application.container; // Eagerly generate the store so defaultStore is populated. container.lookup('service:store'); } diff --git a/addon/-private/transforms/boolean.js b/addon/-private/transforms/boolean.js index c1c8fc656a7..8c914ce0806 100644 --- a/addon/-private/transforms/boolean.js +++ b/addon/-private/transforms/boolean.js @@ -41,7 +41,7 @@ const { isNone } = Ember; */ export default Transform.extend({ deserialize(serialized, options) { - var type = typeof serialized; + let type = typeof serialized; if (isNone(serialized) && options.allowNull === true) { return null; diff --git a/addon/-private/transforms/date.js b/addon/-private/transforms/date.js index b0cb5ac29b2..a6043baed04 100644 --- a/addon/-private/transforms/date.js +++ b/addon/-private/transforms/date.js @@ -25,7 +25,7 @@ import Transform from "ember-data/transform"; export default Transform.extend({ deserialize(serialized) { - var type = typeof serialized; + let type = typeof serialized; if (type === "string") { return new Date(parseDate(serialized)); diff --git a/addon/-private/transforms/number.js b/addon/-private/transforms/number.js index 96ae62e3ca2..eed6fdd885f 100644 --- a/addon/-private/transforms/number.js +++ b/addon/-private/transforms/number.js @@ -1,7 +1,7 @@ import Ember from 'ember'; import Transform from "ember-data/transform"; -var empty = Ember.isEmpty; +const empty = Ember.isEmpty; function isNumber(value) { return value === value && value !== Infinity && value !== -Infinity; @@ -31,7 +31,7 @@ function isNumber(value) { */ export default Transform.extend({ deserialize(serialized) { - var transformed; + let transformed; if (empty(serialized)) { return null; @@ -43,7 +43,7 @@ export default Transform.extend({ }, serialize(deserialized) { - var transformed; + let transformed; if (empty(deserialized)) { return null; diff --git a/addon/-private/transforms/string.js b/addon/-private/transforms/string.js index 671139d5809..6da8a713445 100644 --- a/addon/-private/transforms/string.js +++ b/addon/-private/transforms/string.js @@ -1,7 +1,7 @@ import Ember from 'ember'; import Transform from "ember-data/transform"; -var none = Ember.isNone; +const none = Ember.isNone; /** The `DS.StringTransform` class is used to serialize and deserialize diff --git a/addon/-private/utils.js b/addon/-private/utils.js index e3d6e51985c..8d66823c908 100644 --- a/addon/-private/utils.js +++ b/addon/-private/utils.js @@ -18,7 +18,7 @@ function modelHasAttributeOrRelationshipNamedType(modelClass) { triggering deprecations. */ function getOwner(context) { - var owner; + let owner; if (Ember.getOwner) { owner = Ember.getOwner(context); @@ -32,7 +32,7 @@ function getOwner(context) { // `owner` is a container, we are just making this work owner._lookupFactory = owner.lookupFactory; owner.register = function() { - var registry = owner.registry || owner._registry || owner; + let registry = owner.registry || owner._registry || owner; return registry.register(...arguments); }; From bb4fedb24d32ab832a7726fe6abaa2d8f7505365 Mon Sep 17 00:00:00 2001 From: Garrick Date: Tue, 24 Jan 2017 17:40:14 -0800 Subject: [PATCH 1780/2527] [DOC release] Add missing docs for `preload` option. Add spaceing. --- addon/-private/system/store.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index bd4586396ff..5bae239f386 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -495,6 +495,27 @@ Store = Service.extend({ store, it depends on the reload behavior _when_ the returned promise resolves. + ### Preloading + + You can optionally `preload` specific attributes and relationships that you know of + by passing them via the passed `options`. + + For example, if your Ember route looks like `/posts/1/comments/2` and your API route + for the comment also looks like `/posts/1/comments/2` if you want to fetch the comment + without fetching the post you can pass in the post to the `findRecord` call: + + ```javascript + store.findRecord('comment', 2, { preload: { post: 1 } }); + ``` + + If you have access to the post model you can also pass the model itself: + + ```javascript + store.findRecord('post', 1).then(function (myPostModel) { + store.findRecord('comment', 2, { post: myPostModel }); + }); + ``` + ### Reloading The reload behavior is configured either via the passed `options` hash or From 73b02dc0b3c0e9134127d0d4a1b7c913f6e38a52 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Thu, 26 Jan 2017 13:22:49 -0500 Subject: [PATCH 1781/2527] [DOC] Shorthand method syntax, quotes, and cleanup --- addon/-private/system/store.js | 58 +++++++++++++++++----------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 9241f7b108b..dada27674df 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -319,7 +319,7 @@ Store = Service.extend({ ```js store.createRecord('post', { - title: "Rails is omakase" + title: 'Rails is omakase' }); ``` @@ -328,7 +328,7 @@ Store = Service.extend({ ```js let user = this.store.peekRecord('user', 1); store.createRecord('post', { - title: "Rails is omakase", + title: 'Rails is omakase', user: user }); ``` @@ -409,7 +409,7 @@ Store = Service.extend({ ```javascript let post = store.createRecord('post', { - title: "Rails is omakase" + title: 'Rails is omakase' }); store.deleteRecord(post); @@ -484,7 +484,7 @@ Store = Service.extend({ import Ember from 'ember'; export default Ember.Route.extend({ - model: function(params) { + model(params) { return this.store.findRecord('post', params.post_id); } }); @@ -543,7 +543,7 @@ Store = Service.extend({ // } // ] store.findRecord('post', 1, { reload: true }).then(function(post) { - post.get("revision"); // 2 + post.get('revision'); // 2 }); ``` @@ -604,7 +604,7 @@ Store = Service.extend({ import Ember from 'ember'; export default Ember.Route.extend({ - model: function(params) { + model(params) { return this.store.findRecord('post', params.post_id, { backgroundReload: false }); } }); @@ -617,7 +617,7 @@ Store = Service.extend({ import Ember from 'ember'; export default Ember.Route.extend({ - model: function(params) { + model(params) { return this.store.findRecord('post', params.post_id, { adapterOptions: { subscribe: false } }); @@ -629,7 +629,7 @@ Store = Service.extend({ import MyCustomAdapter from './custom-adapter'; export default MyCustomAdapter.extend({ - findRecord: function(store, type, id, snapshot) { + findRecord(store, type, id, snapshot) { if (snapshot.adapterOptions.subscribe) { // ... } @@ -658,8 +658,8 @@ Store = Service.extend({ import Ember from 'ember'; export default Ember.Route.extend({ - model: function(params) { - return this.store.findRecord('post', params.post_id, {include: 'comments'}); + model(params) { + return this.store.findRecord('post', params.post_id, { include: 'comments' }); } }); @@ -676,8 +676,8 @@ Store = Service.extend({ import Ember from 'ember'; export default Ember.Route.extend({ - model: function(params) { - return this.store.findRecord('post', params.post_id, {include: 'comments,comments.author'}); + model(params) { + return this.store.findRecord('post', params.post_id, { include: 'comments,comments.author' }); } }); @@ -981,7 +981,7 @@ Store = Service.extend({ let user = userRef.value(); // get the identifier of the reference - if (userRef.remoteType() === "id") { + if (userRef.remoteType() === 'id') { let id = userRef.id(); } @@ -992,8 +992,8 @@ Store = Service.extend({ userRef.reload().then(...) // provide data for reference - userRef.push({ id: 1, username: "@user" }).then(function(user) { - userRef.value() === user; + userRef.push({ id: 1, username: '@user' }).then(function(user) { + userRef.value() === user; }); ``` @@ -1077,8 +1077,8 @@ Store = Service.extend({ ```javascript store.hasRecordForId('post', 1); // false store.findRecord('post', 1).then(function() { - store.hasRecordForId('post', 1); // true - }); + store.hasRecordForId('post', 1); // true + }); ``` @method hasRecordForId @@ -1309,11 +1309,11 @@ Store = Service.extend({ The request is made through the adapters' `queryRecord`: ```app/adapters/user.js - import DS from "ember-data"; + import DS from 'ember-data'; export default DS.Adapter.extend({ queryRecord(modelName, query) { - return Ember.$.getJSON("/api/current_user"); + return Ember.$.getJSON('/api/current_user'); } }); ``` @@ -1401,7 +1401,7 @@ Store = Service.extend({ import Ember from 'ember'; export default Ember.Route.extend({ - model: function(params) { + model(params) { return this.store.findAll('author'); } }); @@ -1433,7 +1433,7 @@ Store = Service.extend({ // } // ] store.findAll('author', { reload: true }).then(function(authors) { - authors.getEach("id"); // ['first', 'second'] + authors.getEach('id'); // ['first', 'second'] }); ``` @@ -1494,7 +1494,7 @@ Store = Service.extend({ import Ember from 'ember'; export default Ember.Route.extend({ - model: function() { + model() { return this.store.findAll('post', { backgroundReload: false }); } }); @@ -1507,7 +1507,7 @@ Store = Service.extend({ import Ember from 'ember'; export default Ember.Route.extend({ - model: function(params) { + model(params) { return this.store.findAll('post', { adapterOptions: { subscribe: false } }); @@ -1519,7 +1519,7 @@ Store = Service.extend({ import MyCustomAdapter from './custom-adapter'; export default MyCustomAdapter.extend({ - findAll: function(store, type, sinceToken, snapshotRecordArray) { + findAll(store, type, sinceToken, snapshotRecordArray) { if (snapshotRecordArray.adapterOptions.subscribe) { // ... } @@ -1549,8 +1549,8 @@ Store = Service.extend({ import Ember from 'ember'; export default Ember.Route.extend({ - model: function() { - return this.store.findAll('post', {include: 'comments'}); + model() { + return this.store.findAll('post', { include: 'comments' }); } }); @@ -1564,8 +1564,8 @@ Store = Service.extend({ import Ember from 'ember'; export default Ember.Route.extend({ - model: function() { - return this.store.findAll('post', {include: 'comments,comments.author'}); + model() { + return this.store.findAll('post', { include: 'comments,comments.author' }); } }); @@ -2019,7 +2019,7 @@ Store = Service.extend({ In case someone defined a relationship to a mixin, for example: ``` let Comment = DS.Model.extend({ - owner: belongsTo('commentable'. { polymorphic: true}) + owner: belongsTo('commentable'. { polymorphic: true }) }); let Commentable = Ember.Mixin.create({ comments: hasMany('comment') From f0be0cf0d7b9a70846d944e0ff37737de8fe71ba Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Thu, 26 Jan 2017 14:57:39 -0500 Subject: [PATCH 1782/2527] [DOC] Shorthand method fixes in adapter --- addon/adapter.js | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/addon/adapter.js b/addon/adapter.js index 9999a596a68..cce08002544 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -97,8 +97,7 @@ export default Ember.Object.extend({ import DS from 'ember-data'; export default DS.Adapter.extend({ - findRecord: function(store, type, id, snapshot) { - + findRecord(store, type, id, snapshot) { return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.getJSON(`/${type.modelName}/${id}`).then(function(data) { resolve(data); @@ -128,7 +127,7 @@ export default Ember.Object.extend({ import DS from 'ember-data'; export default DS.Adapter.extend({ - findAll: function(store, type, sinceToken) { + findAll(store, type, sinceToken) { var query = { since: sinceToken }; return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { @@ -159,7 +158,7 @@ export default Ember.Object.extend({ import DS from 'ember-data'; export default DS.Adapter.extend({ - query: function(store, type, query) { + query(store, type, query) { return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { resolve(data); @@ -197,7 +196,7 @@ export default Ember.Object.extend({ import Ember from 'ember'; export default DS.Adapter.extend(DS.BuildURLMixin, { - queryRecord: function(store, type, query) { + queryRecord(store, type, query) { return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { resolve(data); @@ -236,7 +235,7 @@ export default Ember.Object.extend({ import { v4 } from 'uuid'; export default DS.Adapter.extend({ - generateIdForRecord: function(store, inputProperties) { + generateIdForRecord(store, inputProperties) { return v4(); } }); @@ -260,7 +259,7 @@ export default Ember.Object.extend({ import DS from 'ember-data'; export default DS.Adapter.extend({ - createRecord: function(store, type, snapshot) { + createRecord(store, type, snapshot) { var data = this.serialize(snapshot, { includeId: true }); var url = `/${type.modelName}`; @@ -290,7 +289,7 @@ export default Ember.Object.extend({ import DS from 'ember-data'; export default DS.Adapter.extend({ - createRecord: function(store, type, snapshot) { + createRecord(store, type, snapshot) { var data = this.serialize(snapshot, { includeId: true }); return new Ember.RSVP.Promise(function(resolve, reject) { @@ -338,7 +337,7 @@ export default Ember.Object.extend({ import DS from 'ember-data'; export default DS.Adapter.extend({ - updateRecord: function(store, type, snapshot) { + updateRecord(store, type, snapshot) { var data = this.serialize(snapshot, { includeId: true }); var id = snapshot.id; @@ -379,7 +378,7 @@ export default Ember.Object.extend({ import DS from 'ember-data'; export default DS.Adapter.extend({ - deleteRecord: function(store, type, snapshot) { + deleteRecord(store, type, snapshot) { var data = this.serialize(snapshot, { includeId: true }); var id = snapshot.id; @@ -490,7 +489,7 @@ export default Ember.Object.extend({ write: ```javascript - shouldReloadRecord: function(store, ticketSnapshot) { + shouldReloadRecord(store, ticketSnapshot) { var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt'), 'minutes'); if (timeDiff > 20) { return true; @@ -538,7 +537,7 @@ export default Ember.Object.extend({ write: ```javascript - shouldReloadAll: function(store, snapshotArray) { + shouldReloadAll(store, snapshotArray) { var snapshots = snapshotArray.snapshots(); return snapshots.any(function(ticketSnapshot) { @@ -592,7 +591,7 @@ export default Ember.Object.extend({ `shouldBackgroundReloadRecord` as follows: ```javascript - shouldBackgroundReloadRecord: function(store, snapshot) { + shouldBackgroundReloadRecord(store, snapshot) { var connection = window.navigator.connection; if (connection === 'cellular' || connection === 'none') { return false; @@ -631,7 +630,7 @@ export default Ember.Object.extend({ `shouldBackgroundReloadAll` as follows: ```javascript - shouldBackgroundReloadAll: function(store, snapshotArray) { + shouldBackgroundReloadAll(store, snapshotArray) { var connection = window.navigator.connection; if (connection === 'cellular' || connection === 'none') { return false; From a8933f8c9040c1311afdac4da235c82cc6f274a9 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Thu, 26 Jan 2017 14:58:53 -0500 Subject: [PATCH 1783/2527] [DOC] shorthand methods for transform --- addon/transform.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/addon/transform.js b/addon/transform.js index 4e7457229a4..a751d90fc5d 100644 --- a/addon/transform.js +++ b/addon/transform.js @@ -14,10 +14,11 @@ import Ember from 'ember'; // Converts centigrade in the JSON to fahrenheit in the app export default DS.Transform.extend({ - deserialize: function(serialized, options) { + deserialize(serialized, options) { return (serialized * 1.8) + 32; }, - serialize: function(deserialized, options) { + + serialize(deserialized, options) { return (deserialized - 32) / 1.8; } }); @@ -40,11 +41,11 @@ import Ember from 'ember'; ```app/transforms/markdown.js export default DS.Transform.extend({ - serialize: function (deserialized, options) { + serialize(deserialized, options) { return deserialized.raw; }, - deserialize: function (serialized, options) { + deserialize(serialized, options) { var markdownOptions = options.markdown || {}; return marked(serialized, markdownOptions); @@ -74,7 +75,7 @@ export default Ember.Object.extend({ Example ```javascript - serialize: function(deserialized, options) { + serialize(deserialized, options) { return Ember.isEmpty(deserialized) ? null : Number(deserialized); } ``` @@ -93,7 +94,7 @@ export default Ember.Object.extend({ Example ```javascript - deserialize: function(serialized, options) { + deserialize(serialized, options) { return empty(serialized) ? null : Number(serialized); } ``` From f13d0ffe76b7b86c507735e5348923abd9090532 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Thu, 26 Jan 2017 15:00:16 -0500 Subject: [PATCH 1784/2527] [DOC] shorthand method fixes for serializer --- addon/serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/serializer.js b/addon/serializer.js index d15cf4d9acf..136692d1375 100644 --- a/addon/serializer.js +++ b/addon/serializer.js @@ -35,7 +35,7 @@ export default Ember.Object.extend({ ```js Serializer.extend({ - extractRelationship: function(relationshipModelName, relationshipHash) { + extractRelationship(relationshipModelName, relationshipHash) { var modelClass = this.store.modelFor(relationshipModelName); var relationshipSerializer = this.store.serializerFor(relationshipModelName); return relationshipSerializer.normalize(modelClass, relationshipHash); From a9917ff5a8260642387a889bcbff310f1f48ae29 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Thu, 26 Jan 2017 15:01:24 -0500 Subject: [PATCH 1785/2527] [DOC] shorthand method in attr --- addon/attr.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/attr.js b/addon/attr.js index e29d5713b1b..9380d1e370e 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -92,7 +92,7 @@ function getValue(record, key) { ```app/transforms/text.js export default DS.Transform.extend({ - serialize: function(value, options) { + serialize(value, options) { if (options.uppercase) { return value.toUpperCase(); } @@ -100,7 +100,7 @@ function getValue(record, key) { return value; }, - deserialize: function(value) { + deserialize(value) { return value; } }) From 3506441354dc849369a3168f03b47793c94c8422 Mon Sep 17 00:00:00 2001 From: Tom Lagier Date: Thu, 26 Jan 2017 12:02:18 -0800 Subject: [PATCH 1786/2527] [BUGFIX beta] Ensure ISO-8601 regex correctly matches timestamps (#4771) * [BUGFIX beta] Ensure ISO-8601 regex correctly matches timestamps with a timezone offset * Wrap Date prototype stubbing in try/finally to ensure it always reverts after tests complete --- addon/-private/ext/date.js | 2 +- tests/unit/transform/date-test.js | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/addon/-private/ext/date.js b/addon/-private/ext/date.js index b15e6a371c2..947341c1b8e 100644 --- a/addon/-private/ext/date.js +++ b/addon/-private/ext/date.js @@ -31,7 +31,7 @@ export const parseDate = function (date) { // before falling back to any implementation-specific date parsing, so that’s what we do, even if native // implementations could be faster // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm - if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?:(\d{2}))?)?)?$/.exec(date))) { + if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2}):?(?:(\d{2}))?)?)?$/.exec(date))) { // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC for (let i = 0, k; (k = numericKeys[i]); ++i) { struct[k] = +struct[k] || 0; diff --git a/tests/unit/transform/date-test.js b/tests/unit/transform/date-test.js index 6c4a94223ea..bedd2ef009d 100644 --- a/tests/unit/transform/date-test.js +++ b/tests/unit/transform/date-test.js @@ -46,9 +46,22 @@ test("#deserialize with different offset formats", function(assert) { var dateStringColon = '2013-03-15T23:22:00.000+00:00'; var dateStringShortOffset = '2016-12-02T17:30:00.000+00'; - assert.equal(transform.deserialize(dateString).getTime(), 1053817200000); - assert.equal(transform.deserialize(dateStringShortOffset).getTime(), 1480699800000); - assert.equal(transform.deserialize(dateStringColon).getTime(), 1363389720000); + assert.expect(6); + + var _dateUTC = Date.UTC; + + try { + Date.UTC = function () { + assert.equal(arguments.length, 7); + return _dateUTC.apply(this, [].slice.call(arguments)); + }; + + assert.equal(transform.deserialize(dateString).getTime(), 1053817200000); + assert.equal(transform.deserialize(dateStringShortOffset).getTime(), 1480699800000); + assert.equal(transform.deserialize(dateStringColon).getTime(), 1363389720000); + } finally { + Date.UTC = _dateUTC; + } }); testInDebug('Ember.Date.parse has been deprecated', function(assert) { From 23d6cdca49d34144f9644d2d1adb49ebc8eb7319 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Thu, 26 Jan 2017 15:19:51 -0500 Subject: [PATCH 1787/2527] Fix whitespace --- addon/transform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/transform.js b/addon/transform.js index a751d90fc5d..a13cc3fe527 100644 --- a/addon/transform.js +++ b/addon/transform.js @@ -17,7 +17,7 @@ import Ember from 'ember'; deserialize(serialized, options) { return (serialized * 1.8) + 32; }, - + serialize(deserialized, options) { return (deserialized - 32) / 1.8; } From 081a69f29f7a26a8c0dd546f703a6f2d21e56d1e Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Thu, 26 Jan 2017 15:28:57 -0500 Subject: [PATCH 1788/2527] [DOC] shorthand method and quotes/semicolons for serializers/json --- addon/serializers/json.js | 48 ++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index ffcb6bcde67..5008f6a53d4 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -506,8 +506,9 @@ const JSONSerializer = Serializer.extend({ import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - normalize: function(typeClass, hash) { + normalize(typeClass, hash) { var fields = Ember.get(typeClass, 'fields'); + fields.forEach(function(field) { var payloadField = Ember.String.underscore(field); if (field === payloadField) { return; } @@ -515,6 +516,7 @@ const JSONSerializer = Serializer.extend({ hash[field] = hash[payloadField]; delete hash[payloadField]; }); + return this._super.apply(this, arguments); } }); @@ -935,12 +937,12 @@ const JSONSerializer = Serializer.extend({ import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - serialize: function(snapshot, options) { + serialize(snapshot, options) { var json = { POST_TTL: snapshot.attr('title'), POST_BDY: snapshot.attr('body'), POST_CMS: snapshot.hasMany('comments', { ids: true }) - } + }; if (options.includeId) { json.POST_ID_ = snapshot.id; @@ -961,12 +963,12 @@ const JSONSerializer = Serializer.extend({ import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - serialize: function(snapshot, options) { + serialize(snapshot, options) { var json = {}; snapshot.eachAttribute(function(name) { json[serverAttributeName(name)] = snapshot.attr(name); - }) + }); snapshot.eachRelationship(function(name, relationship) { if (relationship.kind === 'hasMany') { @@ -1011,8 +1013,8 @@ const JSONSerializer = Serializer.extend({ import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - serialize: function(snapshot, options) { - var json = this._super.apply(this, arguments); + serialize(snapshot, options) { + var json = this._super(...arguments); json.subject = json.title; delete json.title; @@ -1070,7 +1072,7 @@ const JSONSerializer = Serializer.extend({ import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - serializeIntoHash: function(data, type, snapshot, options) { + serializeIntoHash(data, type, snapshot, options) { var root = Ember.String.decamelize(type.modelName); data[root] = this.serialize(snapshot, options); } @@ -1099,7 +1101,7 @@ const JSONSerializer = Serializer.extend({ import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - serializeAttribute: function(snapshot, json, key, attributes) { + serializeAttribute(snapshot, json, key, attributes) { json.attributes = json.attributes || {}; this._super(snapshot, json.attributes, key, attributes); } @@ -1144,9 +1146,8 @@ const JSONSerializer = Serializer.extend({ import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - serializeBelongsTo: function(snapshot, json, relationship) { + serializeBelongsTo(snapshot, json, relationship) { var key = relationship.key; - var belongsTo = snapshot.belongsTo(key); key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo", "serialize") : key; @@ -1197,12 +1198,12 @@ const JSONSerializer = Serializer.extend({ import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - serializeHasMany: function(snapshot, json, relationship) { + serializeHasMany(snapshot, json, relationship) { var key = relationship.key; if (key === 'comments') { return; } else { - this._super.apply(this, arguments); + this._super(...arguments); } } }); @@ -1248,15 +1249,16 @@ const JSONSerializer = Serializer.extend({ import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - serializePolymorphicType: function(snapshot, json, relationship) { - var key = relationship.key, - belongsTo = snapshot.belongsTo(key); - key = this.keyForAttribute ? this.keyForAttribute(key, "serialize") : key; + serializePolymorphicType(snapshot, json, relationship) { + var key = relationship.key; + var belongsTo = snapshot.belongsTo(key); + + key = this.keyForAttribute ? this.keyForAttribute(key, 'serialize') : key; if (Ember.isNone(belongsTo)) { - json[key + "_type"] = null; + json[key + '_type'] = null; } else { - json[key + "_type"] = belongsTo.modelName; + json[key + '_type'] = belongsTo.modelName; } } }); @@ -1280,7 +1282,7 @@ const JSONSerializer = Serializer.extend({ import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - extractMeta: function(store, typeClass, payload) { + extractMeta(store, typeClass, payload) { if (payload && payload.hasOwnProperty('_pagination')) { let meta = payload._pagination; delete payload._pagination; @@ -1371,7 +1373,7 @@ const JSONSerializer = Serializer.extend({ import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - extractErrors: function(store, typeClass, payload, id) { + extractErrors(store, typeClass, payload, id) { if (payload && typeof payload === 'object' && payload._problems) { payload = payload._problems; this.normalizeErrors(typeClass, payload); @@ -1424,7 +1426,7 @@ const JSONSerializer = Serializer.extend({ import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - keyForAttribute: function(attr, method) { + keyForAttribute(attr, method) { return Ember.String.underscore(attr).toUpperCase(); } }); @@ -1450,7 +1452,7 @@ const JSONSerializer = Serializer.extend({ import DS from 'ember-data'; export default DS.JSONSerializer.extend({ - keyForRelationship: function(key, relationship, method) { + keyForRelationship(key, relationship, method) { return 'rel_' + Ember.String.underscore(key); } }); From a69c71990b9939180a6f5b5c117a14226edf755b Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Thu, 26 Jan 2017 15:32:14 -0500 Subject: [PATCH 1789/2527] [DOC] shorthand method and quotes fro serializers/rest --- addon/serializers/rest.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 4c8bdb3702f..8e90eed5330 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -40,7 +40,7 @@ let camelize = Ember.String.camelize; import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - keyForAttribute: function(attr, method) { + keyForAttribute(attr, method) { return Ember.String.underscore(attr).toUpperCase(); } }); @@ -68,7 +68,7 @@ let RESTSerializer = JSONSerializer.extend({ import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - keyForPolymorphicType: function(key, relationship) { + keyForPolymorphicType(key, relationship) { var relationshipKey = this.keyForRelationship(key); return 'type-' + relationshipKey; @@ -477,7 +477,7 @@ let RESTSerializer = JSONSerializer.extend({ import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - modelNameFromPayloadKey: function(payloadKey) { + modelNameFromPayloadKey(payloadKey) { if (payloadKey === 'blog/post') { return this._super(payloadKey.replace('blog/', '')); } else { @@ -564,12 +564,12 @@ let RESTSerializer = JSONSerializer.extend({ import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - serialize: function(snapshot, options) { + serialize(snapshot, options) { var json = { POST_TTL: snapshot.attr('title'), POST_BDY: snapshot.attr('body'), POST_CMS: snapshot.hasMany('comments', { ids: true }) - } + }; if (options.includeId) { json.POST_ID_ = snapshot.id; @@ -590,12 +590,12 @@ let RESTSerializer = JSONSerializer.extend({ import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - serialize: function(snapshot, options) { + serialize(snapshot, options) { var json = {}; snapshot.eachAttribute(function(name) { json[serverAttributeName(name)] = snapshot.attr(name); - }) + }); snapshot.eachRelationship(function(name, relationship) { if (relationship.kind === 'hasMany') { @@ -640,7 +640,7 @@ let RESTSerializer = JSONSerializer.extend({ import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - serialize: function(snapshot, options) { + serialize(snapshot, options) { var json = this._super(snapshot, options); json.subject = json.title; @@ -672,7 +672,7 @@ let RESTSerializer = JSONSerializer.extend({ import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - serializeIntoHash: function(data, type, record, options) { + serializeIntoHash(data, type, record, options) { var root = Ember.String.decamelize(type.modelName); data[root] = this.serialize(record, options); } @@ -713,7 +713,7 @@ let RESTSerializer = JSONSerializer.extend({ import DS from 'ember-data'; export default DS.RESTSerializer.extend({ - payloadKeyFromModelName: function(modelName) { + payloadKeyFromModelName(modelName) { return Ember.String.dasherize(modelName); } }); @@ -934,7 +934,7 @@ if (isEnabled("ds-payload-type-hooks")) { export default DS.RESTSerializer.extend({ payloadTypeFromModelName(modelName) { - return "api::v1::" + modelName; + return 'api::v1::' + modelName; } }); ``` From f0a0a4bcdcd525c8bdaae53278f3e29e205335ca Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Thu, 26 Jan 2017 15:34:55 -0500 Subject: [PATCH 1790/2527] [DOC] shorthand methods and quotes for adapter errors --- addon/adapters/errors.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/addon/adapters/errors.js b/addon/adapters/errors.js index 5594ccd8920..03b1fd6e38d 100644 --- a/addon/adapters/errors.js +++ b/addon/adapters/errors.js @@ -151,7 +151,7 @@ if (extendedErrorsEnabled) { import DS from 'ember-data'; export default DS.RESTAdapter.extend({ - updateRecord: function() { + updateRecord() { // Fictional adapter that always rejects return Ember.RSVP.reject(new DS.InvalidError([ { @@ -347,9 +347,9 @@ export const ServerError = extendedErrorsEnabled ? const { errorsHashToArray } = DS; let errors = { - base: "Invalid attributes on saving this record", - name: "Must be present", - age: ["Must be present", "Must be a number"] + base: 'Invalid attributes on saving this record', + name: 'Must be present', + age: ['Must be present', 'Must be a number'] }; let errorsArray = errorsHashToArray(errors); @@ -421,19 +421,19 @@ export function errorsHashToArray(errors) { let errorsArray = [ { - title: "Invalid Attribute", - detail: "Must be present", - source: { pointer: "/data/attributes/name" } + title: 'Invalid Attribute', + detail: 'Must be present', + source: { pointer: '/data/attributes/name' } }, { - title: "Invalid Attribute", - detail: "Must be present", - source: { pointer: "/data/attributes/age" } + title: 'Invalid Attribute', + detail: 'Must be present', + source: { pointer: '/data/attributes/age' } }, { - title: "Invalid Attribute", - detail: "Must be a number", - source: { pointer: "/data/attributes/age" } + title: 'Invalid Attribute', + detail: 'Must be a number', + source: { pointer: '/data/attributes/age' } } ]; From 7b7043eeb6c0666fddd01b67890eb717dc604283 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Thu, 26 Jan 2017 15:39:21 -0500 Subject: [PATCH 1791/2527] [DOC] shorthand methods for rest adapter --- addon/adapters/rest.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 02146842dec..ae2e29a448c 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -234,8 +234,8 @@ const Promise = Ember.RSVP.Promise; export default DS.RESTAdapter.extend({ headers: { - "API_KEY": "secret key", - "ANOTHER_HEADER": "Some header value" + 'API_KEY': 'secret key', + 'ANOTHER_HEADER': 'Some header value' } }); ``` @@ -250,8 +250,8 @@ const Promise = Ember.RSVP.Promise; export default DS.RESTAdapter.extend({ headers: Ember.computed('session.authToken', function() { return { - "API_KEY": this.get("session.authToken"), - "ANOTHER_HEADER": "Some header value" + 'API_KEY': this.get('session.authToken'), + 'ANOTHER_HEADER': 'Some header value' }; }) }); @@ -270,8 +270,8 @@ const Promise = Ember.RSVP.Promise; export default DS.RESTAdapter.extend({ headers: Ember.computed(function() { return { - "API_KEY": Ember.get(document.cookie.match(/apiKey\=([^;]*)/), "1"), - "ANOTHER_HEADER": "Some header value" + 'API_KEY': Ember.get(document.cookie.match(/apiKey\=([^;]*)/), '1'), + 'ANOTHER_HEADER': 'Some header value' }; }).volatile() }); @@ -293,7 +293,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { For example: ```js - store.query('posts', { sort: 'price', category: 'pets' }); + store.query('posts', { sort: 'price', category: 'pets' }); ``` will generate a requests like this `/posts?category=pets&sort=price`, even if the @@ -311,13 +311,14 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { import DS from 'ember-data'; export default DS.RESTAdapter.extend({ - sortQueryParams: function(params) { + sortQueryParams(params) { let sortedKeys = Object.keys(params).sort().reverse(); let len = sortedKeys.length, newParams = {}; for (let i = 0; i < len; i++) { newParams[sortedKeys[i]] = params[sortedKeys[i]]; } + return newParams; } }); @@ -438,8 +439,8 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { export default DS.RESTAdapter.extend({ headers: { - "API_KEY": "secret key", - "ANOTHER_HEADER": "Some header value" + 'API_KEY': 'secret key', + 'ANOTHER_HEADER': 'Some header value' } }); ``` From ec605d58a996e96140370dc87b5d79cf9aed6acf Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Thu, 26 Jan 2017 15:48:25 -0500 Subject: [PATCH 1792/2527] Fix whitespace --- addon/serializers/json.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 5008f6a53d4..9cef92dbf53 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -508,7 +508,7 @@ const JSONSerializer = Serializer.extend({ export default DS.JSONSerializer.extend({ normalize(typeClass, hash) { var fields = Ember.get(typeClass, 'fields'); - + fields.forEach(function(field) { var payloadField = Ember.String.underscore(field); if (field === payloadField) { return; } @@ -516,7 +516,7 @@ const JSONSerializer = Serializer.extend({ hash[field] = hash[payloadField]; delete hash[payloadField]; }); - + return this._super.apply(this, arguments); } }); From 146e555757160e3181cb8602d45f66a51578361d Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Fri, 27 Jan 2017 08:50:44 -0500 Subject: [PATCH 1793/2527] remove whitespace --- addon/adapters/rest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index ae2e29a448c..ef2ca394321 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -318,7 +318,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { for (let i = 0; i < len; i++) { newParams[sortedKeys[i]] = params[sortedKeys[i]]; } - + return newParams; } }); From 0d1ac1bdd6a09efb06fd15c36e9cb3d88296f1a6 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Fri, 27 Jan 2017 08:51:55 -0500 Subject: [PATCH 1794/2527] fix whitespace --- addon/serializers/json.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 9cef92dbf53..b24c22cb1b2 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1252,7 +1252,7 @@ const JSONSerializer = Serializer.extend({ serializePolymorphicType(snapshot, json, relationship) { var key = relationship.key; var belongsTo = snapshot.belongsTo(key); - + key = this.keyForAttribute ? this.keyForAttribute(key, 'serialize') : key; if (Ember.isNone(belongsTo)) { From dc1a68cdb29c21fbdb5fc912921bebcb72ee2f05 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Fri, 27 Jan 2017 13:05:27 -0500 Subject: [PATCH 1795/2527] [DOC] shorthand methods and quotes for json-api serializer (#4778) * [DOC] shorthand methods and quotes for json-api serializer * Update example paths * Revert destructure --- addon/serializers/json-api.js | 48 ++++++++++++++++------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 80d2e69b709..707b8c41e65 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -24,30 +24,28 @@ const dasherize = Ember.String.dasherize; This serializer normalizes a JSON API payload that looks like: - ```js - - // models/player.js - import DS from "ember-data"; - - export default DS.Model.extend({ - name: DS.attr(), - skill: DS.attr(), - gamesPlayed: DS.attr(), - club: DS.belongsTo('club') - }); + ```app/models/player.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + name: DS.attr('string'), + skill: DS.attr('string'), + gamesPlayed: DS.attr('number'), + club: DS.belongsTo('club') + }); + ``` - // models/club.js - import DS from "ember-data"; + ```app/models/club.js + import DS from 'ember-data'; - export default DS.Model.extend({ - name: DS.attr(), - location: DS.attr(), - players: DS.hasMany('player') - }); + export default DS.Model.extend({ + name: DS.attr('string'), + location: DS.attr('string'), + players: DS.hasMany('player') + }); ``` ```js - { "data": [ { @@ -104,7 +102,6 @@ const dasherize = Ember.String.dasherize; ```app/serializers/application.js export default JSONAPISerializer.extend({ - normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) { let normalizedDocument = this._super(...arguments); @@ -122,7 +119,6 @@ const dasherize = Ember.String.dasherize; return normalizedRelationship; } - }); ``` @@ -439,7 +435,7 @@ const JSONAPISerializer = JSONSerializer.extend({ import DS from 'ember-data'; export default DS.JSONAPISerializer.extend({ - keyForAttribute: function(attr, method) { + keyForAttribute(attr, method) { return Ember.String.dasherize(attr).toUpperCase(); } }); @@ -469,7 +465,7 @@ const JSONAPISerializer = JSONSerializer.extend({ import DS from 'ember-data'; export default DS.JSONAPISerializer.extend({ - keyForRelationship: function(key, relationship, method) { + keyForRelationship(key, relationship, method) { return Ember.String.underscore(key); } }); @@ -653,7 +649,7 @@ if (isEnabled("ds-payload-type-hooks")) { `post` model should be used: ```app/serializers/application.js - import DS from "ember-data"; + import DS from 'ember-data'; export default DS.JSONAPISerializer.extend({ modelNameFromPayloadType(payloadType) { @@ -701,11 +697,11 @@ if (isEnabled("ds-payload-type-hooks")) { namespaces model name for the `post` should be used: ```app/serializers/application.js - import DS from "ember-data"; + import DS from 'ember-data'; export default JSONAPISerializer.extend({ payloadTypeFromModelName(modelName) { - return "api::v1::" + modelName; + return 'api::v1::' + modelName; } }); ``` From 7e2c45bbfa494d5389328cc6dd3162e493a7e871 Mon Sep 17 00:00:00 2001 From: pete_the_pete Date: Tue, 24 Jan 2017 21:07:51 -0800 Subject: [PATCH 1796/2527] Updating gitignore Updating gitignore to remove idea --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 11c4f19a7f7..d7b48a542b4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ bundle tmp/ tests/source/ dist/ -.idea *.iml benchmarks/results/*.json From caceb095b3d67ef048b6b1db88de282bbd4d0069 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 3 Feb 2017 08:36:58 -0500 Subject: [PATCH 1797/2527] Do not access container if Ember.getOwner exists. Fixes broken tests on master --- addon/-private/utils.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/addon/-private/utils.js b/addon/-private/utils.js index 8d66823c908..138835394ed 100644 --- a/addon/-private/utils.js +++ b/addon/-private/utils.js @@ -22,9 +22,7 @@ function getOwner(context) { if (Ember.getOwner) { owner = Ember.getOwner(context); - } - - if (!owner && context.container) { + } else if (context.container) { owner = context.container; } From de30c86b64e0306c2cdfd327e4bbecb989333912 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 3 Feb 2017 09:52:07 -0500 Subject: [PATCH 1798/2527] Add a test for #4770 --- .../relationships/has-many-test.js | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 74592311f49..08fe3b7b7eb 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -2791,3 +2791,65 @@ test("unloading and reloading a record with hasMany relationship - #3084", funct assert.equal(get(message, 'user.id'), 'user-1', 'message points to user'); }); }); + +test("deleted records should stay deleted", function(assert) { + var user; + var message; + + env.adapter.deleteRecord = function(store, type, id) { + return null; + }; + + run(function() { + env.store.push({ + data: [{ + type: 'user', + id: 'user-1', + attributes: { + name: 'Adolfo Builes' + }, + relationships: { + messages: { + data: [ + { type: 'message', id: 'message-1' }, + { type: 'message', id: 'message-2' } + ] + } + } + }, { + type: 'message', + id: 'message-1' + }, { + type: 'message', + id: 'message-2' + }] + }); + + user = env.store.peekRecord('user', 'user-1'); + message = env.store.peekRecord('message', 'message-1'); + + assert.equal(get(user, 'messages.length'), 2); + }); + + run(function() { + message.destroyRecord() + }); + + run(function() { + // a new message is added to the user should not resurrected the + // deleted message + env.store.push({ + data: [{ + type: 'message', + id: 'message-3', + relationships: { + user: { + data: { type: 'user', id: 'user-1' } + } + } + }] + }); + + assert.equal(get(user, 'messages.length'), 2, 'user should have 2 message since 1 was deleted'); + }); +}); From e9704ca5efa6e5bd8e0ca9e1b4014c9a33db386e Mon Sep 17 00:00:00 2001 From: Chad Bibler Date: Sun, 5 Feb 2017 15:51:46 -0600 Subject: [PATCH 1799/2527] Fix spelling error in documentation --- addon/-private/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index dada27674df..05607be6bfa 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1016,7 +1016,7 @@ Store = Service.extend({ otherwise it will return `null`. A record is available if it has been fetched earlier, or pushed manually into the store. - _Note: This is an synchronous method and does not return a promise._ + _Note: This is a synchronous method and does not return a promise._ ```js let post = store.peekRecord('post', 1); From ff4e5c6a9a344c0f1c23ad422f845fec45b5b69b Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Wed, 8 Feb 2017 22:11:15 -0500 Subject: [PATCH 1800/2527] Enable `ds-extended-errors` feature --- config/features.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/features.json b/config/features.json index 225339b62d7..9ebda80bd91 100644 --- a/config/features.json +++ b/config/features.json @@ -1,7 +1,7 @@ { "ds-improved-ajax": null, "ds-pushpayload-return": null, - "ds-extended-errors": null, + "ds-extended-errors": true, "ds-overhaul-references": null, "ds-payload-type-hooks": null, "ds-check-should-serialize-relationships": true, From 6bef088b940942c9460e79b4dd51a8e75214723b Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Fri, 10 Feb 2017 11:13:04 -0500 Subject: [PATCH 1801/2527] [DOC] Cleanup example code in attr --- addon/attr.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/addon/attr.js b/addon/attr.js index 9380d1e370e..9b5a094f422 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -72,9 +72,11 @@ function getValue(record, key) { export default DS.Model.extend({ username: attr('string'), email: attr('string'), - settings: attr({defaultValue: function() { - return {}; - }}) + settings: attr({ + defaultValue() { + return {}; + } + }) }); ``` @@ -83,6 +85,8 @@ function getValue(record, key) { transformation and adapt the corresponding value, based on the config: ```app/models/post.js + import DS from 'ember-data'; + export default DS.Model.extend({ text: DS.attr('text', { uppercase: true @@ -91,6 +95,8 @@ function getValue(record, key) { ``` ```app/transforms/text.js + import DS from 'ember-data'; + export default DS.Transform.extend({ serialize(value, options) { if (options.uppercase) { From 40017561a7453b3c4d1b6e50e949b333faa801c9 Mon Sep 17 00:00:00 2001 From: Ilya Radchenko Date: Fri, 10 Feb 2017 11:21:08 -0500 Subject: [PATCH 1802/2527] [DOC] Add Ember imports and use lets in adapter examples --- addon/adapter.js | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/addon/adapter.js b/addon/adapter.js index cce08002544..64b4e8c6be6 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -94,6 +94,7 @@ export default Ember.Object.extend({ Here is an example `findRecord` implementation: ```app/adapters/application.js + import Ember from 'ember'; import DS from 'ember-data'; export default DS.Adapter.extend({ @@ -124,11 +125,13 @@ export default Ember.Object.extend({ Example ```app/adapters/application.js + import Ember from 'ember'; import DS from 'ember-data'; export default DS.Adapter.extend({ findAll(store, type, sinceToken) { - var query = { since: sinceToken }; + let query = { since: sinceToken }; + return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { resolve(data); @@ -155,6 +158,7 @@ export default Ember.Object.extend({ Example ```app/adapters/application.js + import Ember from 'ember'; import DS from 'ember-data'; export default DS.Adapter.extend({ @@ -192,8 +196,8 @@ export default Ember.Object.extend({ Example ```app/adapters/application.js - import DS from 'ember-data'; import Ember from 'ember'; + import DS from 'ember-data'; export default DS.Adapter.extend(DS.BuildURLMixin, { queryRecord(store, type, query) { @@ -260,8 +264,8 @@ export default Ember.Object.extend({ export default DS.Adapter.extend({ createRecord(store, type, snapshot) { - var data = this.serialize(snapshot, { includeId: true }); - var url = `/${type.modelName}`; + let data = this.serialize(snapshot, { includeId: true }); + let url = `/${type.modelName}`; // ... } @@ -286,11 +290,12 @@ export default Ember.Object.extend({ Example ```app/adapters/application.js + import Ember from 'ember'; import DS from 'ember-data'; export default DS.Adapter.extend({ createRecord(store, type, snapshot) { - var data = this.serialize(snapshot, { includeId: true }); + let data = this.serialize(snapshot, { includeId: true }); return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.ajax({ @@ -334,12 +339,13 @@ export default Ember.Object.extend({ Example ```app/adapters/application.js + import Ember from 'ember'; import DS from 'ember-data'; export default DS.Adapter.extend({ updateRecord(store, type, snapshot) { - var data = this.serialize(snapshot, { includeId: true }); - var id = snapshot.id; + let data = this.serialize(snapshot, { includeId: true }); + let id = snapshot.id; return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.ajax({ @@ -375,12 +381,13 @@ export default Ember.Object.extend({ Example ```app/adapters/application.js + import Ember from 'ember'; import DS from 'ember-data'; export default DS.Adapter.extend({ deleteRecord(store, type, snapshot) { - var data = this.serialize(snapshot, { includeId: true }); - var id = snapshot.id; + let data = this.serialize(snapshot, { includeId: true }); + let id = snapshot.id; return new Ember.RSVP.Promise(function(resolve, reject) { Ember.$.ajax({ @@ -424,6 +431,7 @@ export default Ember.Object.extend({ is true. ```app/adapters/application.js + import Ember from 'ember'; import DS from 'ember-data'; export default DS.Adapter.extend({ @@ -490,7 +498,9 @@ export default Ember.Object.extend({ ```javascript shouldReloadRecord(store, ticketSnapshot) { - var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt'), 'minutes'); + let lastAccessedAt = ticketSnapshot.attr('lastAccessedAt'); + let timeDiff = moment().diff(lastAccessedAt, 'minutes'); + if (timeDiff > 20) { return true; } else { @@ -538,10 +548,12 @@ export default Ember.Object.extend({ ```javascript shouldReloadAll(store, snapshotArray) { - var snapshots = snapshotArray.snapshots(); + let snapshots = snapshotArray.snapshots(); + + return snapshots.any((ticketSnapshot) => { + let lastAccessedAt = ticketSnapshot.attr('lastAccessedAt'); + let timeDiff = moment().diff(lastAccessedAt, 'minutes'); - return snapshots.any(function(ticketSnapshot) { - var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt'), 'minutes'); if (timeDiff > 20) { return true; } else { @@ -592,7 +604,8 @@ export default Ember.Object.extend({ ```javascript shouldBackgroundReloadRecord(store, snapshot) { - var connection = window.navigator.connection; + let connection = window.navigator.connection; + if (connection === 'cellular' || connection === 'none') { return false; } else { @@ -631,7 +644,8 @@ export default Ember.Object.extend({ ```javascript shouldBackgroundReloadAll(store, snapshotArray) { - var connection = window.navigator.connection; + let connection = window.navigator.connection; + if (connection === 'cellular' || connection === 'none') { return false; } else { From 20c5e29739e87fa43236c15f67cdb57ebcbb5775 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 16 Feb 2017 14:08:19 -0800 Subject: [PATCH 1803/2527] =?UTF-8?q?Don=E2=80=99t=20redefine=20findPossib?= =?UTF-8?q?leInverses=20for=20each=20=5FfindInverseFor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addon/-private/system/model/model.js | 61 ++++++++++++++-------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 0b10dcd856a..d066ba0620e 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -21,6 +21,35 @@ const { @module ember-data */ + +function findPossibleInverses(type, inverseType, name, relationshipsSoFar) { + let possibleRelationships = relationshipsSoFar || []; + + let relationshipMap = get(inverseType, 'relationships'); + if (!relationshipMap) { return possibleRelationships; } + + let relationships = relationshipMap.get(type.modelName).filter(relationship => { + let optionsForRelationship = inverseType.metaForProperty(relationship.name).options; + + if (!optionsForRelationship.inverse) { + return true; + } + + return name === optionsForRelationship.inverse; + }); + + if (relationships) { + possibleRelationships.push.apply(possibleRelationships, relationships); + } + + //Recurse to support polymorphism + if (type.superclass) { + findPossibleInverses(type.superclass, inverseType, name, possibleRelationships); + } + + return possibleRelationships; +} + function intersection (array1, array2) { let result = []; array1.forEach((element) => { @@ -1320,7 +1349,7 @@ Model.reopenClass({ }); } - let possibleRelationships = findPossibleInverses(this, inverseType); + let possibleRelationships = findPossibleInverses(this, inverseType, name); if (possibleRelationships.length === 0) { return null; } @@ -1345,36 +1374,6 @@ Model.reopenClass({ inverseKind = possibleRelationships[0].kind; } - function findPossibleInverses(type, inverseType, relationshipsSoFar) { - let possibleRelationships = relationshipsSoFar || []; - - let relationshipMap = get(inverseType, 'relationships'); - if (!relationshipMap) { return possibleRelationships; } - - let relationships = relationshipMap.get(type.modelName); - - relationships = relationships.filter((relationship) => { - let optionsForRelationship = inverseType.metaForProperty(relationship.name).options; - - if (!optionsForRelationship.inverse) { - return true; - } - - return name === optionsForRelationship.inverse; - }); - - if (relationships) { - possibleRelationships.push.apply(possibleRelationships, relationships); - } - - //Recurse to support polymorphism - if (type.superclass) { - findPossibleInverses(type.superclass, inverseType, possibleRelationships); - } - - return possibleRelationships; - } - return { type: inverseType, name: inverseName, From aa75fab9e2e52d7661261299b6b4e9c7dffe7610 Mon Sep 17 00:00:00 2001 From: Matt Thouvenot Date: Sat, 18 Feb 2017 12:57:23 -0600 Subject: [PATCH 1804/2527] Added missing DS references to DS.Model implementation examples --- addon/-private/system/model/errors.js | 4 ++-- addon/-private/system/model/model.js | 28 +++++++++++++-------------- addon/attr.js | 6 +++--- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index a04ddde200a..f85f8895c3a 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -25,8 +25,8 @@ const MapWithDefault = Ember.MapWithDefault; import DS from 'ember-data'; export default DS.Model.extend({ - username: attr('string'), - email: attr('string') + username: DS.attr('string'), + email: DS.attr('string') }); ``` And you attempted to save a record that did not validate on the backend: diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index d066ba0620e..3c8f7087319 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -653,8 +653,8 @@ const Model = Ember.Object.extend(Ember.Evented, { import DS from 'ember-data'; export default DS.Model.extend({ - name: attr('string'), - isAdmin: attr('boolean', { + name: DS.attr('string'), + isAdmin: DS.attr('boolean', { defaultValue: false }) }); @@ -1669,9 +1669,9 @@ Model.reopenClass({ import DS from 'ember-data'; export default DS.Model.extend({ - firstName: attr('string'), - lastName: attr('string'), - birthday: attr('date') + firstName: DS.attr('string'), + lastName: DS.attr('string'), + birthday: DS.attr('date') }); ``` @@ -1723,9 +1723,9 @@ Model.reopenClass({ import DS from 'ember-data'; export default DS.Model.extend({ - firstName: attr(), - lastName: attr('string'), - birthday: attr('date') + firstName: DS.attr(), + lastName: DS.attr('string'), + birthday: DS.attr('date') }); ``` @@ -1784,9 +1784,9 @@ Model.reopenClass({ import DS from 'ember-data'; let Person = DS.Model.extend({ - firstName: attr('string'), - lastName: attr('string'), - birthday: attr('date') + firstName: DS.attr('string'), + lastName: DS.attr('string'), + birthday: DS.attr('date') }); Person.eachAttribute(function(name, meta) { @@ -1835,9 +1835,9 @@ Model.reopenClass({ import DS from 'ember-data'; let Person = DS.Model.extend({ - firstName: attr(), - lastName: attr('string'), - birthday: attr('date') + firstName: DS.attr(), + lastName: DS.attr('string'), + birthday: DS.attr('date') }); Person.eachTransformedAttribute(function(name, type) { diff --git a/addon/attr.js b/addon/attr.js index 9b5a094f422..2c232aac2f7 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -70,9 +70,9 @@ function getValue(record, key) { import DS from 'ember-data'; export default DS.Model.extend({ - username: attr('string'), - email: attr('string'), - settings: attr({ + username: DS.attr('string'), + email: DS.attr('string'), + settings: DS.attr({ defaultValue() { return {}; } From 9aa6f091dd8a0f34a9ec767123db693d642a65dd Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 20 Feb 2017 09:30:04 -0500 Subject: [PATCH 1805/2527] Avoid mutating model factory in _modelForMixin. With the upcoming `factory-for` work it is likely that mutating the result of `modelFactoryFor` will throw an error. This is a minor refactoring to avoid needing to mutate the return value (since we can simply do the work before registering). --- addon/-private/system/store.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 05607be6bfa..0b08e271f66 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2049,16 +2049,17 @@ Store = Service.extend({ } if (mixin) { + let ModelForMixin = Model.extend(mixin); + ModelForMixin.reopenClass({ + __isMixin: true, + __mixin: mixin + }); + //Cache the class as a model - owner.register('model:' + normalizedModelName, Model.extend(mixin)); - } - let factory = this.modelFactoryFor(normalizedModelName); - if (factory) { - factory.__isMixin = true; - factory.__mixin = mixin; + owner.register('model:' + normalizedModelName, ModelForMixin); } - return factory; + return this.modelFactoryFor(normalizedModelName); }, /** From c2ca0688513b29cebb7fb193276ebe66d53e11e6 Mon Sep 17 00:00:00 2001 From: sly7-7 Date: Tue, 21 Feb 2017 11:49:36 +0100 Subject: [PATCH 1806/2527] bump ember-cli --- bower.json | 9 +-------- package.json | 32 +++++++++++++++++--------------- server/.jshintrc | 3 --- tests/index.html | 2 +- 4 files changed, 19 insertions(+), 27 deletions(-) delete mode 100644 server/.jshintrc diff --git a/bower.json b/bower.json index 18ac48e998c..c55b4668708 100644 --- a/bower.json +++ b/bower.json @@ -1,12 +1,5 @@ { "name": "ember-data", "license": "MIT", - "dependencies": { - "ember": "components/ember#release", - "ember-cli-shims": "0.1.1", - "pretender": "^0.12.0" - }, - "resolutions": { - "ember": "release" - } + "dependencies": {} } diff --git a/package.json b/package.json index cf3bfac0c3f..9523251ca3f 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,6 @@ "bower": "bower install", "production": "ember build --environment=production" }, - "engines": { - "node": ">= 0.10.0" - }, "author": "", "license": "MIT", "dependencies": { @@ -32,7 +29,7 @@ "broccoli-file-creator": "^1.0.0", "broccoli-merge-trees": "^1.0.0", "chalk": "^1.1.1", - "ember-cli-babel": "^5.1.6", + "ember-cli-babel": "^5.1.7", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.0.0", "ember-cli-test-info": "^1.0.0", @@ -49,26 +46,27 @@ }, "devDependencies": { "bower": "^1.6.5", - "broccoli-asset-rev": "^2.4.2", + "broccoli-asset-rev": "^2.4.5", "broccoli-concat": "0.0.13", "broccoli-funnel": "^1.0.0", "broccoli-stew": "^1.0.1", "broccoli-string-replace": "^0.1.1", "broccoli-uglify-sourcemap": "^1.0.1", "broccoli-yuidoc": "^2.1.0", - "ember-ajax": "^2.0.1", - "ember-cli": "^2.8.0", - "ember-cli-app-version": "^1.0.0", + "ember-ajax": "^2.4.1", + "ember-cli": "^2.11.1", + "ember-cli-app-version": "^2.0.0", "ember-cli-blueprint-test-helpers": "0.11.0", - "ember-cli-dependency-checker": "^1.2.0", + "ember-cli-dependency-checker": "^1.3.0", "ember-cli-eslint": "1.3.0", - "ember-cli-htmlbars": "^1.0.3", - "ember-cli-htmlbars-inline-precompile": "^0.3.1", - "ember-cli-inject-live-reload": "^1.4.0", + "ember-cli-htmlbars": "^1.1.1", + "ember-cli-htmlbars-inline-precompile": "^0.3.6", + "ember-cli-inject-live-reload": "^1.4.1", "ember-cli-internal-test-helpers": "^0.8.1", - "ember-cli-pretender": "0.6.0", + "ember-cli-pretender": "^1.0.1", "ember-cli-qunit": "^2.1.0", "ember-cli-release": "^0.2.9", + "ember-cli-shims": "^1.0.2", "ember-cli-sri": "^2.1.0", "ember-cli-test-loader": "^1.1.0", "ember-cli-uglify": "^1.2.0", @@ -76,9 +74,10 @@ "ember-disable-prototype-extensions": "^1.1.0", "ember-disable-proxy-controllers": "^1.0.0", "ember-export-application-global": "^1.0.5", - "ember-load-initializers": "^0.5.1", + "ember-load-initializers": "^0.6.0", "ember-publisher": "0.0.7", "ember-resolver": "^2.0.3", + "ember-source": "~2.11.0", "ember-watson": "^0.7.0", "express": "^4.14.0", "faker": "^3.1.0", @@ -86,7 +85,7 @@ "glob": "5.0.13", "heimdall-query": "^0.0.5", "json-api-mock-server": "0.1.1", - "loader.js": "^4.0.1", + "loader.js": "^4.0.10", "mocha": "2.4.5", "mocha-only-detector": "0.0.2", "morgan": "^1.7.0", @@ -98,6 +97,9 @@ "peerDependencies": { "ember-inflector": "^1.9.4" }, + "engines": { + "node": ">= 0.12.0" + }, "keywords": [ "ember-addon" ], diff --git a/server/.jshintrc b/server/.jshintrc deleted file mode 100644 index c1f2978bcf7..00000000000 --- a/server/.jshintrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "node": true -} diff --git a/tests/index.html b/tests/index.html index f7ff652109d..5209b852321 100644 --- a/tests/index.html +++ b/tests/index.html @@ -21,7 +21,7 @@ {{content-for "body"}} {{content-for "test-body"}} - + From e2f35a79fae1e732a16f42d26e53277c7f228fc0 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 21 Feb 2017 16:19:46 -0800 Subject: [PATCH 1807/2527] upgrade broccoli-concat (#4811) --- package.json | 2 +- yarn.lock | 363 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 214 insertions(+), 151 deletions(-) diff --git a/package.json b/package.json index 9523251ca3f..957693fb5e7 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "devDependencies": { "bower": "^1.6.5", "broccoli-asset-rev": "^2.4.5", - "broccoli-concat": "0.0.13", + "broccoli-concat": "^3.2.2", "broccoli-funnel": "^1.0.0", "broccoli-stew": "^1.0.1", "broccoli-string-replace": "^0.1.1", diff --git a/yarn.lock b/yarn.lock index fafe1692837..a2445c41281 100644 --- a/yarn.lock +++ b/yarn.lock @@ -80,14 +80,14 @@ ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" -ansi-regex@*, ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + ansi-styles@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" @@ -585,9 +585,9 @@ breakable@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" -broccoli-asset-rev@^2.4.2: +broccoli-asset-rev@^2.4.5: version "2.5.0" - resolved "https://registry.yarnpkg.com/broccoli-asset-rev/-/broccoli-asset-rev-2.5.0.tgz#f5f66eac962bf9f086286921f0eaeaab6d00d819" + resolved "https://registry.npmjs.org/broccoli-asset-rev/-/broccoli-asset-rev-2.5.0.tgz#f5f66eac962bf9f086286921f0eaeaab6d00d819" dependencies: broccoli-asset-rewrite "^1.1.0" broccoli-filter "^1.2.2" @@ -641,17 +641,6 @@ broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching rsvp "^3.0.17" walk-sync "^0.2.5" -broccoli-caching-writer@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" - dependencies: - broccoli-kitchen-sink-helpers "^0.3.1" - broccoli-plugin "^1.2.1" - debug "^2.1.1" - rimraf "^2.2.8" - rsvp "^3.0.17" - walk-sync "^0.3.0" - broccoli-caching-writer@~2.0.1: version "2.0.4" resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" @@ -674,17 +663,6 @@ broccoli-clean-css@^1.1.0: inline-source-map-comment "^1.0.5" json-stable-stringify "^1.0.0" -broccoli-concat@0.0.13: - version "0.0.13" - resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-0.0.13.tgz#b1805c33537adf7dca1b33b6a6516f225a00468f" - dependencies: - broccoli-kitchen-sink-helpers "^0.2.4" - broccoli-writer "^0.1.1" - glob "^4.3.1" - js-string-escape "~1.0.0" - mkdirp "^0.5.0" - quick-temp "~0.1.2" - broccoli-concat@^2.2.0: version "2.3.8" resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-2.3.8.tgz#590cdcc021bb905b6c121d87c2d1d57df44a2a48" @@ -698,19 +676,22 @@ broccoli-concat@^2.2.0: lodash.omit "^4.1.0" lodash.uniq "^4.2.0" -broccoli-concat@^3.0.4: - version "3.0.5" - resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.0.5.tgz#306fb47e7caa23ec726391fe8b584765946eb52e" +broccoli-concat@^3.0.4, broccoli-concat@^3.2.2: + version "3.2.2" + resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" dependencies: - broccoli-caching-writer "^3.0.0" broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-plugin "^1.3.0" broccoli-stew "^1.3.3" + ensure-posix-path "^1.0.2" fast-sourcemap-concat "^1.0.1" - fs-extra "^0.30.0" + find-index "^1.1.0" + fs-extra "^1.0.0" + fs-tree-diff "^0.5.6" lodash.merge "^4.3.0" lodash.omit "^4.1.0" lodash.uniq "^4.2.0" - mkdirp "^0.5.1" + walk-sync "^0.3.1" broccoli-config-loader@^1.0.0: version "1.0.0" @@ -756,7 +737,7 @@ broccoli-funnel-reducer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" -broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6: +broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli-funnel@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.1.0.tgz#dfb91a37c902456456de4a40a1881948d65b27d9" dependencies: @@ -775,7 +756,7 @@ broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6: symlink-or-copy "^1.0.0" walk-sync "^0.3.1" -broccoli-kitchen-sink-helpers@^0.2.4, broccoli-kitchen-sink-helpers@^0.2.5, broccoli-kitchen-sink-helpers@~0.2.0: +broccoli-kitchen-sink-helpers@^0.2.5, broccoli-kitchen-sink-helpers@~0.2.0: version "0.2.9" resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" dependencies: @@ -800,7 +781,7 @@ broccoli-lint-eslint@^2.0.0: json-stable-stringify "^1.0.1" md5-hex "^1.2.1" -broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^1.1.3: +broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^1.1.3, broccoli-merge-trees@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.1.tgz#16a7494ed56dbe61611f6c2d4817cfbaad2a3055" dependencies: @@ -921,7 +902,7 @@ broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: uglify-js "^2.7.0" walk-sync "^0.1.3" -broccoli-writer@^0.1.1, broccoli-writer@~0.1.1: +broccoli-writer@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/broccoli-writer/-/broccoli-writer-0.1.1.tgz#d4d71aa8f2afbc67a3866b91a2da79084b96ab2d" dependencies: @@ -1004,9 +985,9 @@ can-symlink@^1.0.0: dependencies: tmp "0.0.28" -capture-exit@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.1.0.tgz#d931b32b11c2bd20ae57f34af0c1eb2c18781626" +capture-exit@^1.0.7: + version "1.2.0" + resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" dependencies: rsvp "^3.3.3" @@ -1309,7 +1290,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@1.5.0, concat-stream@^1.4.6, concat-stream@^1.4.7: +concat-stream@1.5.0, concat-stream@^1.4.6: version "1.5.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" dependencies: @@ -1317,7 +1298,7 @@ concat-stream@1.5.0, concat-stream@^1.4.6, concat-stream@^1.4.7: readable-stream "~2.0.0" typedarray "~0.0.5" -concat-stream@^1.5.2: +concat-stream@^1.4.7, concat-stream@^1.5.2: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -1350,6 +1331,15 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" +console-ui@^1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/console-ui/-/console-ui-1.0.3.tgz#31c524461b63422769f9e89c173495d91393721c" + dependencies: + chalk "^1.1.3" + inquirer "^1.2.3" + ora "^0.2.0" + through "^2.3.8" + consolidate@^0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" @@ -1402,6 +1392,13 @@ core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" +cross-spawn-async@^2.1.1: + version "2.2.5" + resolved "https://registry.npmjs.org/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc" + dependencies: + lru-cache "^4.0.0" + which "^1.2.8" + cross-spawn@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.0.1.tgz#a3bbb302db2297cbea3c04edf36941f4613aa399" @@ -1464,7 +1461,7 @@ debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: dependencies: ms "0.7.2" -debuglog@*, debuglog@^1.0.1: +debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -1602,19 +1599,19 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -ember-ajax@^2.0.1: - version "2.5.3" - resolved "https://registry.yarnpkg.com/ember-ajax/-/ember-ajax-2.5.3.tgz#02dded6c132290edd47ee9862a7a8821c6919dad" +ember-ajax@^2.4.1: + version "2.5.5" + resolved "https://registry.npmjs.org/ember-ajax/-/ember-ajax-2.5.5.tgz#9b59e415997012bc0f91cb302d3cf0db941e38ab" dependencies: ember-cli-babel "^5.1.5" -ember-cli-app-version@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-1.0.1.tgz#d135eba75f30e791d8a5e5844f1251dcbcc40438" +ember-cli-app-version@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/ember-cli-app-version/-/ember-cli-app-version-2.0.1.tgz#64cbe581a9abaf98afd60e9cf60fdec460766c9b" dependencies: ember-cli-babel "^5.1.6" ember-cli-htmlbars "^1.0.0" - git-repo-version "0.3.0" + git-repo-version "0.4.1" ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.1.7, ember-cli-babel@^5.2.1: version "5.2.1" @@ -1651,9 +1648,9 @@ ember-cli-broccoli-sane-watcher@^2.0.3: rsvp "^3.0.18" sane "^1.1.1" -ember-cli-dependency-checker@^1.2.0: +ember-cli-dependency-checker@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/ember-cli-dependency-checker/-/ember-cli-dependency-checker-1.3.0.tgz#f0e8cb7f0f43c1e560494eaa9372804e7a088a2a" + resolved "https://registry.npmjs.org/ember-cli-dependency-checker/-/ember-cli-dependency-checker-1.3.0.tgz#f0e8cb7f0f43c1e560494eaa9372804e7a088a2a" dependencies: chalk "^0.5.1" is-git-url "0.2.0" @@ -1675,16 +1672,16 @@ ember-cli-get-dependency-depth@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" -ember-cli-htmlbars-inline-precompile@^0.3.1: +ember-cli-htmlbars-inline-precompile@^0.3.6: version "0.3.6" - resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.3.6.tgz#4095fe423f93102724c0725e4dd1a31f25e24de5" + resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.3.6.tgz#4095fe423f93102724c0725e4dd1a31f25e24de5" dependencies: babel-plugin-htmlbars-inline-precompile "^0.1.0" ember-cli-babel "^5.1.3" ember-cli-htmlbars "^1.0.0" hash-for-dep "^1.0.2" -ember-cli-htmlbars@^1.0.0, ember-cli-htmlbars@^1.0.3: +ember-cli-htmlbars@^1.0.0, ember-cli-htmlbars@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-1.1.1.tgz#8776cf59796dac8f32e8625fc6d1ea45ffa55de1" dependencies: @@ -1694,9 +1691,9 @@ ember-cli-htmlbars@^1.0.0, ember-cli-htmlbars@^1.0.3: json-stable-stringify "^1.0.0" strip-bom "^2.0.0" -ember-cli-inject-live-reload@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.4.1.tgz#ddadb9a346c5ed694ec0f9e11f49994eacafd277" +ember-cli-inject-live-reload@^1.4.1: + version "1.6.1" + resolved "https://registry.npmjs.org/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.6.1.tgz#82b8f5be454815a75e7f6d42c9ce0bc883a914a3" ember-cli-internal-test-helpers@^0.8.1: version "0.8.3" @@ -1769,9 +1766,14 @@ ember-cli-preprocess-registry@^3.0.0: process-relative-require "^1.0.0" silent-error "^1.0.0" -ember-cli-pretender@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/ember-cli-pretender/-/ember-cli-pretender-0.6.0.tgz#7525ffa3081b8ba7b0791f24f1f229d83e87bd1e" +ember-cli-pretender@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-1.0.1.tgz#35540babddef6f2778e91c627d190c73505103cd" + dependencies: + broccoli-funnel "^1.1.0" + broccoli-merge-trees "^1.2.1" + pretender "^1.4.2" + resolve "^1.2.0" ember-cli-qunit@^2.1.0: version "2.2.5" @@ -1803,6 +1805,14 @@ ember-cli-release@^0.2.9: semver "^4.3.1" silent-error "^1.0.0" +ember-cli-shims@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/ember-cli-shims/-/ember-cli-shims-1.0.2.tgz#e2ec1b6687f94df1b68cc0aa66c1d690d9ded02c" + dependencies: + ember-cli-babel "^5.2.1" + ember-cli-version-checker "^1.2.0" + silent-error "^1.0.1" + ember-cli-sri@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" @@ -1837,15 +1847,15 @@ ember-cli-valid-component-name@^1.0.0: dependencies: silent-error "^1.0.0" -ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7: +ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7, ember-cli-version-checker@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-1.2.0.tgz#caa286b77d1b485df5d2f62c67a6f19aa8b582c4" dependencies: semver "^5.3.0" -ember-cli@^2.8.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-2.10.0.tgz#3aefd56a207f60be1ba120aeacd41e7e7a9383d8" +ember-cli@^2.11.1: + version "2.11.1" + resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.11.1.tgz#519f93ee944e0a092e77da81027400a692c5b7d3" dependencies: amd-name-resolver "0.0.6" bower "^1.3.12" @@ -1863,11 +1873,12 @@ ember-cli@^2.8.0: broccoli-middleware "^0.18.1" broccoli-source "^1.1.0" broccoli-stew "^1.2.0" - capture-exit "^1.0.4" + capture-exit "^1.0.7" chalk "^1.1.3" clean-base-url "^1.0.0" compression "^1.4.4" configstore "^2.0.0" + console-ui "^1.0.2" core-object "^2.0.2" diff "^1.3.1" ember-cli-broccoli-sane-watcher "^2.0.3" @@ -1880,36 +1891,34 @@ ember-cli@^2.8.0: ember-cli-string-utils "^1.0.0" ember-try "^0.2.6" escape-string-regexp "^1.0.3" - exists-sync "0.0.3" + execa "^0.4.0" + exists-sync "0.0.4" exit "^0.1.2" express "^4.12.3" filesize "^3.1.3" find-up "^1.1.2" - fs-extra "0.30.0" + fs-extra "1.0.0" fs-tree-diff "^0.5.2" get-caller-file "^1.0.0" git-repo-info "^1.0.4" glob "7.1.1" - heimdalljs-fs-monitor "^0.0.3" + heimdalljs-fs-monitor "^0.1.0" heimdalljs-logger "^0.1.7" http-proxy "^1.9.0" inflection "^1.7.0" - inquirer "^1.2.1" is-git-url "^0.2.0" isbinaryfile "^3.0.0" js-yaml "^3.6.1" - leek "0.0.23" + leek "0.0.24" lodash.template "^4.2.5" - markdown-it "8.0.0" + markdown-it "8.1.0" markdown-it-terminal "0.0.4" minimatch "^3.0.0" morgan "^1.5.2" node-modules-path "^1.0.0" - node-uuid "^1.4.3" nopt "^3.0.1" npm "3.10.8" npm-package-arg "^4.1.1" - ora "^0.2.0" portfinder "^1.0.7" promise-map-series "^0.2.1" quick-temp "0.1.6" @@ -1922,9 +1931,9 @@ ember-cli@^2.8.0: symlink-or-copy "^1.0.1" temp "0.8.3" testem "^1.8.1" - through "^2.3.6" tiny-lr "^1.0.3" tree-sync "^1.1.4" + uuid "^3.0.0" walk-sync "^0.3.0" yam "0.0.22" @@ -1958,9 +1967,11 @@ ember-inflector@^1.9.4: dependencies: ember-cli-babel "^5.1.7" -ember-load-initializers@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/ember-load-initializers/-/ember-load-initializers-0.5.1.tgz#76e3db23c111dbdcd3ae6f687036bf0b56be0cbe" +ember-load-initializers@^0.6.0: + version "0.6.3" + resolved "https://registry.npmjs.org/ember-load-initializers/-/ember-load-initializers-0.6.3.tgz#f47396ad271ba77294068c98f992a5f19705441a" + dependencies: + ember-cli-babel "^5.1.6" ember-publisher@0.0.7: version "0.0.7" @@ -1994,6 +2005,23 @@ ember-runtime-enumerable-includes-polyfill@^1.0.0: ember-cli-babel "^5.1.6" ember-cli-version-checker "^1.1.6" +ember-source@~2.11.0: + version "2.11.2" + resolved "https://registry.npmjs.org/ember-source/-/ember-source-2.11.2.tgz#07239925dc8fc2a8377bdf43210c42093e8fc4ae" + dependencies: + broccoli-stew "^1.2.0" + ember-cli-get-component-path-option "^1.0.0" + ember-cli-normalize-entity-name "^1.0.0" + ember-cli-path-utils "^1.0.0" + ember-cli-string-utils "^1.0.0" + ember-cli-test-info "^1.0.0" + ember-cli-valid-component-name "^1.0.0" + ember-cli-version-checker "^1.1.7" + jquery "^3.1.1" + resolve "^1.1.7" + rsvp "^3.3.3" + simple-dom "^0.3.0" + ember-test-helpers@^0.5.32: version "0.5.34" resolved "https://registry.yarnpkg.com/ember-test-helpers/-/ember-test-helpers-0.5.34.tgz#c8439108d1cba1d7d838c212208a5c4061471b83" @@ -2090,7 +2118,7 @@ engine.io@1.8.0: engine.io-parser "1.3.1" ws "1.1.1" -ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1: +ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" @@ -2305,6 +2333,17 @@ exec-sh@^0.2.0: dependencies: merge "^1.1.3" +execa@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/execa/-/execa-0.4.0.tgz#4eb6467a36a095fabb2970ff9d5e3fb7bce6ebc3" + dependencies: + cross-spawn-async "^2.1.1" + is-stream "^1.1.0" + npm-run-path "^1.0.0" + object-assign "^4.0.1" + path-key "^1.0.0" + strip-eof "^1.0.0" + exists-sync@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" @@ -2401,7 +2440,7 @@ extsprintf@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" -fake-xml-http-request@^1.3.0: +fake-xml-http-request@^1.3.0, fake-xml-http-request@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-1.4.0.tgz#6481c727a0eae9c420bae229dcdfc5369c4b5477" @@ -2492,6 +2531,10 @@ finalhandler@0.5.0: statuses "~1.3.0" unpipe "~1.0.0" +find-index@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" + find-up@^1.0.0, find-up@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" @@ -2588,15 +2631,13 @@ fs-exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" -fs-extra@0.30.0, fs-extra@^0.30.0: - version "0.30.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" +fs-extra@1.0.0, fs-extra@^1.0.0, fs-extra@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" fs-extra@^0.24.0: version "0.24.0" @@ -2617,13 +2658,15 @@ fs-extra@^0.26.0, fs-extra@^0.26.7: path-is-absolute "^1.0.0" rimraf "^2.2.8" -fs-extra@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" +fs-extra@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" fs-readdir-recursive@^0.1.0: version "0.1.2" @@ -2749,11 +2792,15 @@ git-repo-info@^1.0.4, git-repo-info@^1.1.2: version "1.4.0" resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.4.0.tgz#ed210221defd3fdefce8b16ac61985cabe242e4a" -git-repo-version@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-0.3.0.tgz#c9b97d0d21c4357d669dc1269c2b6a75da6cc0e9" +git-repo-info@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.2.0.tgz#43d8513e04a24dd441330a2f7c6655a709fdbaf2" + +git-repo-version@0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/git-repo-version/-/git-repo-version-0.4.1.tgz#75fab9a0a4ec8470755b0eea7fdaa6f9d41453bf" dependencies: - git-repo-info "^1.0.4" + git-repo-info "~1.2.0" git-tools@^0.1.4: version "0.1.4" @@ -2809,7 +2856,7 @@ glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.1: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^4.3.1, glob@^4.3.2: +glob@^4.3.2: version "4.5.3" resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" dependencies: @@ -3024,11 +3071,12 @@ heimdall-query@^0.0.5: progress "^1.1.8" selenium-webdriver "^3.0.0-beta-2" -heimdalljs-fs-monitor@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.0.3.tgz#468a1afa5d31ba58fb199fcdb5b0007dca69e63d" +heimdalljs-fs-monitor@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.1.0.tgz#d404a65688c6714c485469ed3495da4853440272" dependencies: heimdalljs "^0.2.0" + heimdalljs-logger "^0.1.7" heimdalljs-logger@^0.1.7: version "0.1.7" @@ -3125,7 +3173,7 @@ ignore@^3.1.2: version "3.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" -imurmurhash@*, imurmurhash@^0.1.4: +imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -3197,9 +3245,9 @@ inquirer@^0.12.0: strip-ansi "^3.0.0" through "^2.3.6" -inquirer@^1.2.1: +inquirer@^1.2.3: version "1.2.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918" dependencies: ansi-escapes "^1.1.0" chalk "^1.0.0" @@ -3345,7 +3393,7 @@ is-resolvable@^1.0.0: dependencies: tryit "^1.0.1" -is-stream@^1.0.1: +is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -3422,7 +3470,11 @@ jodid25519@^1.0.0: dependencies: jsbn "~0.1.0" -js-string-escape@^1.0.0, js-string-escape@^1.0.1, js-string-escape@~1.0.0: +jquery@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/jquery/-/jquery-3.1.1.tgz#347c1c21c7e004115e0a4da32cece041fad3c8a3" + +js-string-escape@^1.0.0, js-string-escape@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" @@ -3543,9 +3595,9 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" -leek@0.0.23: - version "0.0.23" - resolved "https://registry.yarnpkg.com/leek/-/leek-0.0.23.tgz#d44b9f55b27e22902a6603eaeec193f0c301d25f" +leek@0.0.24: + version "0.0.24" + resolved "https://registry.npmjs.org/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" dependencies: debug "^2.1.0" lodash.assign "^3.2.0" @@ -3588,9 +3640,9 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -loader.js@^4.0.1: +loader.js@^4.0.10: version "4.1.0" - resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.1.0.tgz#1d0897a62f8b7375d3d9cd1ae6acf798c36c1ffe" + resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.1.0.tgz#1d0897a62f8b7375d3d9cd1ae6acf798c36c1ffe" lockfile@~1.0.1: version "1.0.3" @@ -3641,10 +3693,6 @@ lodash._basefor@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" -lodash._baseindexof@*: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" - lodash._baseuniq@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" @@ -3652,14 +3700,10 @@ lodash._baseuniq@~4.6.0: lodash._createset "~4.0.0" lodash._root "~3.0.0" -lodash._bindcallback@*, lodash._bindcallback@^3.0.0: +lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" -lodash._cacheindexof@*: - version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" - lodash._createassigner@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" @@ -3668,17 +3712,11 @@ lodash._createassigner@^3.0.0: lodash._isiterateecall "^3.0.0" lodash.restparam "^3.0.0" -lodash._createcache@*: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" - dependencies: - lodash._getnative "^3.0.0" - lodash._createset@~4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" -lodash._getnative@*, lodash._getnative@^3.0.0: +lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" @@ -3797,7 +3835,7 @@ lodash.omit@^4.1.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" -lodash.restparam@*, lodash.restparam@^3.0.0: +lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" @@ -3857,7 +3895,7 @@ lru-cache@2: version "2.7.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" -lru-cache@^4.0.1: +lru-cache@^4.0.0, lru-cache@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" dependencies: @@ -3884,9 +3922,9 @@ markdown-it-terminal@0.0.4: lodash.merge "^3.3.2" markdown-it "^4.4.0" -markdown-it@8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.0.0.tgz#e66255497a0e409e816fbc67807975f4f26f6f82" +markdown-it@8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-8.1.0.tgz#38902d4e7bac2260c073eb67be623211fbb2c2e3" dependencies: argparse "^1.0.7" entities "~1.1.1" @@ -4120,11 +4158,11 @@ mustache@^2.2.1: version "2.3.0" resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" -mute-stream@0.0.5: +mute-stream@0.0.5, mute-stream@~0.0.4: version "0.0.5" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" -mute-stream@0.0.6, mute-stream@~0.0.4: +mute-stream@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" @@ -4188,7 +4226,7 @@ node-notifier@^4.3.1: shellwords "^0.1.0" which "^1.0.5" -node-uuid@^1.4.3, node-uuid@~1.4.0, node-uuid@~1.4.7: +node-uuid@~1.4.0, node-uuid@~1.4.7: version "1.4.7" resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" @@ -4252,6 +4290,12 @@ npm-registry-client@~7.2.1: optionalDependencies: npmlog "~2.0.0 || ~3.1.0" +npm-run-path@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-1.0.0.tgz#f5c32bf595fe81ae927daec52e82f8b000ac3c8f" + dependencies: + path-key "^1.0.0" + npm-user-validate@~0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-0.1.5.tgz#52465d50c2d20294a57125b996baedbf56c5004b" @@ -4530,6 +4574,10 @@ path-is-inside@^1.0.1, path-is-inside@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" +path-key@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/path-key/-/path-key-1.0.0.tgz#5d53d578019646c0d68800db4e146e6bdc2ac7af" + path-posix@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" @@ -4609,6 +4657,13 @@ pretender@1.0.0: fake-xml-http-request "^1.3.0" route-recognizer "^0.1.9" +pretender@^1.4.2: + version "1.4.2" + resolved "https://registry.npmjs.org/pretender/-/pretender-1.4.2.tgz#dde9995dfdf75b28a3dd7a73cde2f9f612e5e8f4" + dependencies: + fake-xml-http-request "^1.4.0" + route-recognizer "^0.2.3" + printf@^0.2.3: version "0.2.5" resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" @@ -4670,23 +4725,23 @@ q@^1.1.2: version "1.4.1" resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" -qs@6.2.0, qs@^6.2.0, qs@~6.2.0: +qs@6.2.0, qs@~6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" +qs@^6.2.0, qs@~6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" + qs@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" -qs@~6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" - querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" -quick-temp@0.1.6, quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@~0.1.2: +quick-temp@0.1.6, quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5: version "0.1.6" resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.6.tgz#a6242a15cba9f9cdbd341287b5c569e318eec307" dependencies: @@ -4832,7 +4887,7 @@ readable-stream@~2.0.0, readable-stream@~2.0.5: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: +readdir-scoped-modules@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" dependencies: @@ -5057,7 +5112,7 @@ resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" -resolve@^1.1.2, resolve@^1.1.6: +resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c" @@ -5078,13 +5133,13 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@~2.5.4: +rimraf@2, rimraf@^2.3.2, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@~2.5.4: version "2.5.4" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" dependencies: glob "^7.0.5" -rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.5.1: +rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: @@ -5104,11 +5159,15 @@ route-recognizer@^0.1.9: version "0.1.11" resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" -rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.6, rsvp@^3.2.1, rsvp@~3.2.1: +route-recognizer@^0.2.3: + version "0.2.10" + resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" + +rsvp@3.2.1, rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@~3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" -rsvp@^3.0.14, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3: +rsvp@^3.0.21, rsvp@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.3.3.tgz#34633caaf8bc66ceff4be3c2e1dffd032538a813" @@ -5251,6 +5310,10 @@ silent-error@^1.0.0, silent-error@^1.0.1: dependencies: debug "^2.2.0" +simple-dom@^0.3.0: + version "0.3.2" + resolved "https://registry.npmjs.org/simple-dom/-/simple-dom-0.3.2.tgz#0663d10f1556f1500551d518f56e3aba0871371d" + simple-fmt@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" @@ -5484,6 +5547,10 @@ strip-bom@^2.0.0: dependencies: is-utf8 "^0.2.0" +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + strip-json-comments@~1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" @@ -5808,7 +5875,7 @@ uuid@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" -validate-npm-package-license@*, validate-npm-package-license@^3.0.1: +validate-npm-package-license@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" dependencies: @@ -5879,7 +5946,7 @@ which-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" -which@1, which@^1.0.5, which@^1.2.12, which@^1.2.9, which@~1.2.10, which@~1.2.11: +which@1, which@^1.0.5, which@^1.2.12, which@^1.2.8, which@^1.2.9, which@~1.2.10, which@~1.2.11: version "1.2.12" resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" dependencies: @@ -5903,14 +5970,10 @@ window-size@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" -wordwrap@0.0.2: +wordwrap@0.0.2, wordwrap@~0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" From 314ae0bbdea4e2e451c93db067b60291961e2b95 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 21 Feb 2017 14:21:48 -0800 Subject: [PATCH 1808/2527] [Fixes #4807] realize class + factory seperation *note: this combined with embers factoryFor makes `MODEL_FACTORY_INJECTIONS` irrelevant.* --- addon/-private/system/model/internal-model.js | 2 +- addon/-private/system/model/model.js | 29 +- addon/-private/system/store.js | 23 +- tests/integration/injection-test.js | 76 + tests/unit/model-test.js | 2 +- yarn.lock | 2312 ++++++++--------- 6 files changed, 1238 insertions(+), 1206 deletions(-) create mode 100644 tests/integration/injection-test.js diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 878c749c4f6..43fef0b646e 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -330,7 +330,7 @@ export default class InternalModel { createOptions.container = this.store.container; } - this._record = this.modelClass._create(createOptions); + this._record = this.store.modelFactoryFor(this.modelName).create(createOptions); this._triggerDeferredTriggers(); heimdall.stop(token); diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 3c8f7087319..038483cc541 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -10,6 +10,7 @@ import { relatedTypesDescriptor, relationshipsDescriptor } from 'ember-data/-private/system/relationships/ext'; +import { runInDebug } from 'ember-data/-private/debug'; const { get, @@ -21,7 +22,6 @@ const { @module ember-data */ - function findPossibleInverses(type, inverseType, name, relationshipsSoFar) { let possibleRelationships = relationshipsSoFar || []; @@ -1173,17 +1173,20 @@ Object.defineProperty(Model.prototype, 'data', { } }); -Model.reopenClass({ - /** - Alias DS.Model's `create` method to `_create`. This allows us to create DS.Model - instances from within the store, but if end users accidentally call `create()` - (instead of `createRecord()`), we can raise an error. +runInDebug(function() { + Model.reopen({ + init() { + this._super(...arguments); - @method _create - @private - @static - */ - _create: Model.create, + if (!this._internalModel) { + throw new Ember.Error('You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.'); + } + } + }); +}); + +Model.reopenClass({ + isModel: true, /** Override the class' `create()` method to raise an error. This @@ -1196,10 +1199,6 @@ Model.reopenClass({ @private @static */ - create() { - throw new Ember.Error("You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set."); - }, - /** Represents the model's class name as a string. This can be used to look up the model through DS.Store's modelFor method. diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 0b08e271f66..e0ca26417f7 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2087,6 +2087,12 @@ Store = Service.extend({ @private */ _modelFor(modelName) { + let maybeFactory = this._modelFactoryFor(modelName); + // for factorFor factory/class split + return maybeFactory.class ? maybeFactory.class : maybeFactory; + }, + + _modelFactoryFor(modelName) { heimdall.increment(modelFor); let factory = this._modelClassCache[modelName]; @@ -2101,9 +2107,13 @@ Store = Service.extend({ throw new EmberError(`No model was found for '${modelName}'`); } - assert(`'${inspect(factory)}' does not appear to be an ember-data model`, (typeof factory._create === 'function') ); + // interopt with the future + let klass = getOwner(this).factoryFor ? factory.class : factory; + + assert(`'${inspect(klass)}' does not appear to be an ember-data model`, klass.isModel); - factory.modelName = factory.modelName || modelName; + // TODO: deprecate this + klass.modelName = klass.modelName || modelName; this._modelClassCache[modelName] = factory; } @@ -2116,16 +2126,13 @@ Store = Service.extend({ */ modelFactoryFor(modelName) { heimdall.increment(modelFactoryFor); - assert("You need to pass a model name to the store's modelFactoryFor method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + assert(`You need to pass a model name to the store's modelFactoryFor method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); let trueModelName = this._classKeyFor(modelName); let owner = getOwner(this); if (owner.factoryFor) { - let MaybeModel = owner.factoryFor(`model:${trueModelName}`); - let MaybeModelFactory = MaybeModel && MaybeModel.class; - - return MaybeModelFactory; + return owner.factoryFor(`model:${trueModelName}`); } else { return owner._lookupFactory(`model:${trueModelName}`); } diff --git a/tests/integration/injection-test.js b/tests/integration/injection-test.js new file mode 100644 index 00000000000..e010029bb33 --- /dev/null +++ b/tests/integration/injection-test.js @@ -0,0 +1,76 @@ +import setupStore from 'dummy/tests/helpers/store'; +import Ember from 'ember'; +import DS from 'ember-data'; +import { module, test } from 'qunit'; + +let env, originalFactoryFor, originalMODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS; +const { run } = Ember; + +const factory = { + isFactory: true, + class: { + isModel: true, + _create() { } + } +}; + +module('integration/injection factoryFor enabled', { + setup() { + env = setupStore(); + + originalFactoryFor = Ember.getOwner(env.store).factoryFor; + + Ember.getOwner(env.store).factoryFor = function(name) { + return factory; + }; + }, + + teardown() { + Ember.getOwner(env.store).factoryFor = originalFactoryFor; + + run(env.store, 'destroy'); + } +}); + +test('modelFactoryFor', function(assert) { + const modelFactory = env.store.modelFactoryFor('super-villain'); + + assert.equal(modelFactory, factory, 'expected the factory itself to be returned'); +}); + +test('modelFor', function(assert) { + const modelFactory = env.store.modelFor('super-villain'); + + assert.equal(modelFactory, factory.class, 'expected the factory itself to be returned'); + + // TODO: we should deprecate this next line. Resolved state on the class is fraught with peril + assert.equal(modelFactory.modelName, 'super-villain', 'expected the factory itself to be returned'); +}); + +module('integration/injection eager injections', { + setup() { + Ember.MODEL_FACTORY_INJECTIONS = true; + env = setupStore(); + + env.registry.injection('model:foo', 'apple', 'service:apple'); + env.registry.register('model:foo', DS.Model); + env.registry.register('service:apple', Ember.Object.extend({ isService: true })); + // container injection + }, + + teardown() { + // can be removed once we no longer support ember versions without lookupFactory + Ember.MODEL_FACTORY_INJECTIONS = originalMODEL_FACTORY_INJECTIONS; + + run(env.store, 'destroy'); + } +}); + +test('did inject', function(assert) { + let foo = run(() => env.store.createRecord('foo')); + let apple = foo.get('apple'); + let Apple = env.registry.registrations['service:apple']; + + assert.ok(apple, `'model:foo' instance should have an 'apple' property`); + assert.ok(apple instanceof Apple, `'model:foo'.apple should be an instance of 'service:apple'`); +}); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index aaf7e0c8a81..6e0e8b1b434 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -15,7 +15,7 @@ var run = Ember.run; var Person, store, env; -module("unit/model - DS.Model", { +module('unit/model - DS.Model', { beforeEach() { Person = DS.Model.extend({ name: DS.attr('string'), diff --git a/yarn.lock b/yarn.lock index a2445c41281..c7f827a2a4f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,53 +2,57 @@ # yarn lockfile v1 -abbrev@1, abbrev@~1.0.9: +abbrev@1: + version "1.1.0" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" + +abbrev@~1.0.9: version "1.0.9" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" accepts@1.3.3, accepts@~1.3.3: version "1.3.3" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" dependencies: mime-types "~2.1.11" negotiator "0.6.1" acorn-jsx@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" dependencies: acorn "^3.0.4" +acorn@4.0.4: + version "4.0.4" + resolved "https://registry.npmjs.org/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" + acorn@^3.0.4, acorn@^3.1.0: version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - -acorn@^4.0.1: - version "4.0.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" + resolved "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" adm-zip@^0.4.7: version "0.4.7" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" + resolved "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" after@0.8.1: version "0.8.1" - resolved "https://registry.yarnpkg.com/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" + resolved "https://registry.npmjs.org/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" ajv-keywords@^1.0.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.0.tgz#c11e6859eafff83e0dafc416929472eca946aa2c" + version "1.5.1" + resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" ajv@^4.1.3, ajv@^4.7.0: - version "4.10.4" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.10.4.tgz#c0974dd00b3464984892d6010aa9c2c945933254" + version "4.11.3" + resolved "https://registry.npmjs.org/ajv/-/ajv-4.11.3.tgz#ce30bdb90d1254f762c75af915fb3a63e7183d22" dependencies: co "^4.6.0" json-stable-stringify "^1.0.1" align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" - resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + resolved "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" dependencies: kind-of "^3.0.2" longest "^1.0.1" @@ -56,190 +60,180 @@ align-text@^0.1.1, align-text@^0.1.3: alter@~0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" + resolved "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" dependencies: stable "~0.1.3" amd-name-resolver@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-0.0.5.tgz#76962dac876ed3311b05d29c6a58c14e1ef3304b" + resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.5.tgz#76962dac876ed3311b05d29c6a58c14e1ef3304b" dependencies: ensure-posix-path "^1.0.1" amd-name-resolver@0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-0.0.6.tgz#d3e4ba2dfcaab1d820c1be9de947c67828cfe595" + resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.6.tgz#d3e4ba2dfcaab1d820c1be9de947c67828cfe595" dependencies: ensure-posix-path "^1.0.1" amdefine@>=0.0.4: version "1.0.1" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" ansi-escapes@^1.1.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-regex@*, ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" ansi-styles@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" ansi-styles@^2.1.0, ansi-styles@^2.2.1: version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" ansicolors@~0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" + resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" ansicolors@~0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" + resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" ansistyles@~0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" + resolved "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" anymatch@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" dependencies: arrify "^1.0.0" micromatch "^2.1.5" aproba@^1.0.3, aproba@~1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" archy@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + resolved "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" are-we-there-yet@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" dependencies: delegates "^1.0.0" readable-stream "^2.0.0 || ^1.1.13" argparse@^1.0.7, argparse@~1.0.2: version "1.0.9" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" dependencies: sprintf-js "~1.0.2" arr-diff@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" dependencies: arr-flatten "^1.0.1" arr-flatten@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" array-equal@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + resolved "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" array-flatten@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" array-index@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/array-index/-/array-index-1.0.0.tgz#ec56a749ee103e4e08c790b9c353df16055b97f9" + resolved "https://registry.npmjs.org/array-index/-/array-index-1.0.0.tgz#ec56a749ee103e4e08c790b9c353df16055b97f9" dependencies: debug "^2.2.0" es6-symbol "^3.0.2" -array-to-error@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" - dependencies: - array-to-sentence "^1.1.0" - -array-to-sentence@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" - array-union@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" dependencies: array-uniq "^1.0.1" array-uniq@^1.0.1: version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" array-unique@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" arraybuffer.slice@0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" + resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" arrify@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" asap@^2.0.0, asap@~2.0.4: version "2.0.5" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" + resolved "https://registry.npmjs.org/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" asn1@0.1.11: version "0.1.11" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" asn1@~0.2.3: version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" assert-plus@^0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" assert-plus@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" assert-plus@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" assertion-error@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" + resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" ast-traverse@~0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" + resolved "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" ast-types@0.8.12: version "0.8.12" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" ast-types@0.8.15: version "0.8.15" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" -ast-types@0.9.2: - version "0.9.2" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.2.tgz#2cc19979d15c655108bf565323b8e7ee38751f6b" +ast-types@0.9.5: + version "0.9.5" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.9.5.tgz#1a660a09945dbceb1f9c9cbb715002617424e04a" async-disk-cache@^1.0.0: version "1.0.9" - resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.0.9.tgz#23bafb823184f463407e474e8d5f87899f72ca63" + resolved "https://registry.npmjs.org/async-disk-cache/-/async-disk-cache-1.0.9.tgz#23bafb823184f463407e474e8d5f87899f72ca63" dependencies: debug "^2.1.3" istextorbinary "2.1.0" @@ -249,29 +243,29 @@ async-disk-cache@^1.0.0: async@^1.4.0, async@^1.5.2: version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" async@^2.0.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/async/-/async-2.1.4.tgz#2d2160c7788032e4dd6cbe2502f1f9a2c8f6cde4" + version "2.1.5" + resolved "https://registry.npmjs.org/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" dependencies: lodash "^4.14.0" async@~0.2.6, async@~0.2.9: version "0.2.10" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + resolved "https://registry.npmjs.org/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" async@~0.9.0: version "0.9.2" - resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" aws-sdk@^2.0.9: - version "2.7.21" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.7.21.tgz#9abc790b3d2498482437172e5948988d4870f94f" + version "2.17.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.17.0.tgz#b60351f37a77f04e5441fa900b0aea6df027aae3" dependencies: buffer "4.9.1" crypto-browserify "1.0.9" @@ -285,19 +279,19 @@ aws-sdk@^2.0.9: aws-sign2@~0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" aws-sign2@~0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" aws4@^1.2.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" + version "1.6.0" + resolved "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" babel-core@^5.0.0, babel-core@^5.8.22: version "5.8.38" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" + resolved "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" dependencies: babel-plugin-constant-folding "^1.0.1" babel-plugin-dead-code-elimination "^1.0.2" @@ -348,188 +342,188 @@ babel-core@^5.0.0, babel-core@^5.8.22: babel-plugin-constant-folding@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" + resolved "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" babel-plugin-dead-code-elimination@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" + resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" babel-plugin-eval@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" + resolved "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" babel-plugin-feature-flags@^0.2.1: version "0.2.3" - resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.2.3.tgz#81d81ed77bda2014098fa8243abcf03a551cbd4d" + resolved "https://registry.npmjs.org/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.2.3.tgz#81d81ed77bda2014098fa8243abcf03a551cbd4d" dependencies: json-stable-stringify "^1.0.1" babel-plugin-filter-imports@^0.2.0: version "0.2.1" - resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.2.1.tgz#784f96a892f2f7ed2ccf0955688bd8916cd2e212" + resolved "https://registry.npmjs.org/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.2.1.tgz#784f96a892f2f7ed2ccf0955688bd8916cd2e212" dependencies: json-stable-stringify "^1.0.1" babel-plugin-htmlbars-inline-precompile@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.1.0.tgz#b784723bd1f108796b56faf9f1c05eb5ca442983" + resolved "https://registry.npmjs.org/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.1.0.tgz#b784723bd1f108796b56faf9f1c05eb5ca442983" babel-plugin-inline-environment-variables@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" + resolved "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" babel-plugin-jscript@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" + resolved "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" babel-plugin-member-expression-literals@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" + resolved "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" babel-plugin-property-literals@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" + resolved "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" babel-plugin-proto-to-assign@^1.0.3: version "1.0.4" - resolved "https://registry.yarnpkg.com/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" + resolved "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" dependencies: lodash "^3.9.3" babel-plugin-react-constant-elements@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" + resolved "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" babel-plugin-react-display-name@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" + resolved "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" babel-plugin-remove-console@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" + resolved "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" babel-plugin-remove-debugger@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" + resolved "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" babel-plugin-runtime@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" + resolved "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" babel-plugin-undeclared-variables-check@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" + resolved "https://registry.npmjs.org/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" dependencies: leven "^1.0.2" babel-plugin-undefined-to-void@^1.1.6: version "1.1.6" - resolved "https://registry.yarnpkg.com/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" + resolved "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" babel5-plugin-strip-class-callcheck@^5.1.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/babel5-plugin-strip-class-callcheck/-/babel5-plugin-strip-class-callcheck-5.1.0.tgz#77d4a40c8614d367b8a21a53908159806dba5f91" + resolved "https://registry.npmjs.org/babel5-plugin-strip-class-callcheck/-/babel5-plugin-strip-class-callcheck-5.1.0.tgz#77d4a40c8614d367b8a21a53908159806dba5f91" babel5-plugin-strip-heimdall@^5.0.2: version "5.0.2" - resolved "https://registry.yarnpkg.com/babel5-plugin-strip-heimdall/-/babel5-plugin-strip-heimdall-5.0.2.tgz#e1fe191c34de79686564d50a86f4217b8df629c1" + resolved "https://registry.npmjs.org/babel5-plugin-strip-heimdall/-/babel5-plugin-strip-heimdall-5.0.2.tgz#e1fe191c34de79686564d50a86f4217b8df629c1" babylon@^5.8.38: version "5.8.38" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" + resolved "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" backbone@^1.1.2: version "1.3.3" - resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" + resolved "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" dependencies: underscore ">=1.8.3" backo2@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" balanced-match@^0.4.1: version "0.4.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" base64-arraybuffer@0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" base64-js@^1.0.2: version "1.2.0" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" base64id@0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" + resolved "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" -basic-auth@~1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.0.4.tgz#030935b01de7c9b94a824b29f3fccb750d3a5290" +basic-auth@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" bcrypt-pbkdf@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4" + version "1.0.1" + resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" dependencies: tweetnacl "^0.14.3" better-assert@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + resolved "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" dependencies: callsite "1.0.0" "binaryextensions@1 || 2": version "2.0.0" - resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.0.0.tgz#e597d1a7a6a3558a2d1c7241a16c99965e6aa40f" + resolved "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.0.0.tgz#e597d1a7a6a3558a2d1c7241a16c99965e6aa40f" bl@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" + resolved "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" dependencies: readable-stream "~2.0.5" blank-object@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" + resolved "https://registry.npmjs.org/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" blob@0.0.4: version "0.0.4" - resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" + resolved "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" block-stream@*: version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + resolved "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" dependencies: inherits "~2.0.0" bluebird@^2.9.33: version "2.11.0" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" bluebird@^3.1.1, bluebird@^3.4.6: version "3.4.7" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" body-parser@^1.15.2: - version "1.15.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.15.2.tgz#d7578cf4f1d11d5f6ea804cef35dc7a7ff6dae67" + version "1.16.1" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.16.1.tgz#51540d045adfa7a0c6995a014bb6b1ed9b802329" dependencies: bytes "2.4.0" content-type "~1.0.2" - debug "~2.2.0" + debug "2.6.1" depd "~1.1.0" - http-errors "~1.5.0" - iconv-lite "0.4.13" + http-errors "~1.5.1" + iconv-lite "0.4.15" on-finished "~2.3.0" - qs "6.2.0" - raw-body "~2.1.7" - type-is "~1.6.13" + qs "6.2.1" + raw-body "~2.2.0" + type-is "~1.6.14" body@^5.1.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" + resolved "https://registry.npmjs.org/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" dependencies: continuable-cache "^0.3.1" error "^7.0.0" @@ -538,19 +532,19 @@ body@^5.1.0: boom@0.4.x: version "0.4.2" - resolved "https://registry.yarnpkg.com/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" + resolved "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" dependencies: hoek "0.9.x" boom@2.x.x: version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + resolved "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" dependencies: hoek "2.x.x" bower-config@^1.3.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.0.tgz#16c38c1135f8071c19f25938d61b0d8cbf18d3f1" + resolved "https://registry.npmjs.org/bower-config/-/bower-config-1.4.0.tgz#16c38c1135f8071c19f25938d61b0d8cbf18d3f1" dependencies: graceful-fs "^4.1.3" mout "^1.0.0" @@ -560,22 +554,22 @@ bower-config@^1.3.0: bower-endpoint-parser@0.2.2: version "0.2.2" - resolved "https://registry.yarnpkg.com/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" + resolved "https://registry.npmjs.org/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" bower@^1.3.12, bower@^1.6.5: version "1.8.0" - resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a" + resolved "https://registry.npmjs.org/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a" brace-expansion@^1.0.0: version "1.1.6" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" dependencies: balanced-match "^0.4.1" concat-map "0.0.1" braces@^1.8.2: version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + resolved "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" dependencies: expand-range "^1.8.1" preserve "^0.2.0" @@ -583,7 +577,7 @@ braces@^1.8.2: breakable@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" + resolved "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" broccoli-asset-rev@^2.4.5: version "2.5.0" @@ -597,13 +591,13 @@ broccoli-asset-rev@^2.4.5: broccoli-asset-rewrite@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" + resolved "https://registry.npmjs.org/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" dependencies: broccoli-filter "^1.2.3" -broccoli-babel-transpiler@^5.4.5, broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.0: +broccoli-babel-transpiler@^5.4.5, broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: version "5.6.2" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.6.2.tgz#958c72e43575b2f0a862a5096dba1ce1ebc7d74d" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.6.2.tgz#958c72e43575b2f0a862a5096dba1ce1ebc7d74d" dependencies: babel-core "^5.0.0" broccoli-funnel "^1.0.0" @@ -615,13 +609,13 @@ broccoli-babel-transpiler@^5.4.5, broccoli-babel-transpiler@^5.5.0, broccoli-bab broccoli-brocfile-loader@^0.18.0: version "0.18.0" - resolved "https://registry.yarnpkg.com/broccoli-brocfile-loader/-/broccoli-brocfile-loader-0.18.0.tgz#2e86021c805c34ffc8d29a2fb721cf273e819e4b" + resolved "https://registry.npmjs.org/broccoli-brocfile-loader/-/broccoli-brocfile-loader-0.18.0.tgz#2e86021c805c34ffc8d29a2fb721cf273e819e4b" dependencies: findup-sync "^0.4.2" broccoli-builder@^0.18.0: - version "0.18.3" - resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.3.tgz#9d2c90558e7f4d1118ae6e938c63b35da00dd38f" + version "0.18.4" + resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.4.tgz#abc6db2c07d214454918e2997ea87441b69b69d3" dependencies: heimdalljs "^0.2.0" promise-map-series "^0.2.1" @@ -632,7 +626,7 @@ broccoli-builder@^0.18.0: broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" @@ -643,7 +637,7 @@ broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching broccoli-caching-writer@~2.0.1: version "2.0.4" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" @@ -654,18 +648,18 @@ broccoli-caching-writer@~2.0.1: symlink-or-copy "^1.0.0" walk-sync "^0.2.0" -broccoli-clean-css@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" +broccoli-clean-css@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/broccoli-clean-css/-/broccoli-clean-css-2.0.0.tgz#c0794384c5a9d7de5b03223b8b3f6c6bd3b9241c" dependencies: - broccoli-persistent-filter "^1.1.6" - clean-css-promise "^0.1.0" - inline-source-map-comment "^1.0.5" - json-stable-stringify "^1.0.0" + broccoli-persistent-filter "^1.2.13" + clean-css-promise "^2.0.1" + json-stable-stringify "^1.0.1" + source-map-to-comment "^1.1.0" broccoli-concat@^2.2.0: version "2.3.8" - resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-2.3.8.tgz#590cdcc021bb905b6c121d87c2d1d57df44a2a48" + resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-2.3.8.tgz#590cdcc021bb905b6c121d87c2d1d57df44a2a48" dependencies: broccoli-caching-writer "^2.3.1" broccoli-kitchen-sink-helpers "^0.3.1" @@ -695,13 +689,13 @@ broccoli-concat@^3.0.4, broccoli-concat@^3.2.2: broccoli-config-loader@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/broccoli-config-loader/-/broccoli-config-loader-1.0.0.tgz#c3cf5ecfaffc04338c6f1d5d38dc36baeaa131ba" + resolved "https://registry.npmjs.org/broccoli-config-loader/-/broccoli-config-loader-1.0.0.tgz#c3cf5ecfaffc04338c6f1d5d38dc36baeaa131ba" dependencies: broccoli-caching-writer "^2.0.4" broccoli-config-replace@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" + resolved "https://registry.npmjs.org/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.0" @@ -710,7 +704,7 @@ broccoli-config-replace@^1.1.2: broccoli-file-creator@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" + resolved "https://registry.npmjs.org/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" dependencies: broccoli-kitchen-sink-helpers "~0.2.0" broccoli-plugin "^1.1.0" @@ -721,7 +715,7 @@ broccoli-file-creator@^1.0.0: broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: version "1.2.4" - resolved "https://registry.yarnpkg.com/broccoli-filter/-/broccoli-filter-1.2.4.tgz#409afb94b9a3a6da9fac8134e91e205f40cc7330" + resolved "https://registry.npmjs.org/broccoli-filter/-/broccoli-filter-1.2.4.tgz#409afb94b9a3a6da9fac8134e91e205f40cc7330" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.0.0" @@ -735,11 +729,11 @@ broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: broccoli-funnel-reducer@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" + resolved "https://registry.npmjs.org/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli-funnel@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.1.0.tgz#dfb91a37c902456456de4a40a1881948d65b27d9" + resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.1.0.tgz#dfb91a37c902456456de4a40a1881948d65b27d9" dependencies: array-equal "^1.0.0" blank-object "^1.0.1" @@ -758,21 +752,21 @@ broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli broccoli-kitchen-sink-helpers@^0.2.5, broccoli-kitchen-sink-helpers@~0.2.0: version "0.2.9" - resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" + resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" dependencies: glob "^5.0.10" mkdirp "^0.5.1" broccoli-kitchen-sink-helpers@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" + resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" dependencies: glob "^5.0.10" mkdirp "^0.5.1" broccoli-lint-eslint@^2.0.0: version "2.7.0" - resolved "https://registry.yarnpkg.com/broccoli-lint-eslint/-/broccoli-lint-eslint-2.7.0.tgz#a2d905d02b397a90ae82439f283c459ef819f140" + resolved "https://registry.npmjs.org/broccoli-lint-eslint/-/broccoli-lint-eslint-2.7.0.tgz#a2d905d02b397a90ae82439f283c459ef819f140" dependencies: broccoli-persistent-filter "^1.2.0" escape-string-regexp "^1.0.5" @@ -783,7 +777,7 @@ broccoli-lint-eslint@^2.0.0: broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^1.1.3, broccoli-merge-trees@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.1.tgz#16a7494ed56dbe61611f6c2d4817cfbaad2a3055" + resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.2.1.tgz#16a7494ed56dbe61611f6c2d4817cfbaad2a3055" dependencies: broccoli-plugin "^1.3.0" can-symlink "^1.0.0" @@ -796,7 +790,7 @@ broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^ broccoli-merge-trees@~0.2.3: version "0.2.4" - resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-0.2.4.tgz#1936f63bb09e24246b1e91d8c53162c0f7b24c3c" + resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-0.2.4.tgz#1936f63bb09e24246b1e91d8c53162c0f7b24c3c" dependencies: broccoli-plugin "^1.0.0" debug "^2.2.0" @@ -804,14 +798,14 @@ broccoli-merge-trees@~0.2.3: broccoli-middleware@^0.18.1: version "0.18.1" - resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-0.18.1.tgz#bf525581c2deb652c425942b18580f76d3748122" + resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-0.18.1.tgz#bf525581c2deb652c425942b18580f76d3748122" dependencies: handlebars "^4.0.4" mime "^1.2.11" -broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0: +broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0, broccoli-persistent-filter@^1.2.13: version "1.2.13" - resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.2.13.tgz#61368669e2b8f35238fdd38a2a896597e4a1c821" + resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.2.13.tgz#61368669e2b8f35238fdd38a2a896597e4a1c821" dependencies: async-disk-cache "^1.0.0" blank-object "^1.0.1" @@ -829,7 +823,7 @@ broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-p broccoli-plugin@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" + resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -838,7 +832,7 @@ broccoli-plugin@1.1.0: broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" + resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -847,17 +841,17 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli broccoli-slow-trees@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" + resolved "https://registry.npmjs.org/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" dependencies: heimdalljs "^0.2.1" broccoli-source@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" + resolved "https://registry.npmjs.org/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" broccoli-sri-hash@^2.1.0: version "2.1.2" - resolved "https://registry.yarnpkg.com/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" + resolved "https://registry.npmjs.org/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" dependencies: broccoli-caching-writer "^2.2.0" mkdirp "^0.5.1" @@ -867,7 +861,7 @@ broccoli-sri-hash@^2.1.0: broccoli-stew@^1.0.1, broccoli-stew@^1.2.0, broccoli-stew@^1.3.3: version "1.4.0" - resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-1.4.0.tgz#1bdb0a1804d62a419d190abc26acb3c91878154d" + resolved "https://registry.npmjs.org/broccoli-stew/-/broccoli-stew-1.4.0.tgz#1bdb0a1804d62a419d190abc26acb3c91878154d" dependencies: broccoli-funnel "^1.0.1" broccoli-merge-trees "^1.0.0" @@ -882,15 +876,15 @@ broccoli-stew@^1.0.1, broccoli-stew@^1.2.0, broccoli-stew@^1.3.3: walk-sync "^0.3.0" broccoli-string-replace@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/broccoli-string-replace/-/broccoli-string-replace-0.1.1.tgz#e560d20db3569a336043110b4048210fa6f1478b" + version "0.1.2" + resolved "https://registry.npmjs.org/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" dependencies: broccoli-persistent-filter "^1.1.5" - minimatch "^2.0.8" + minimatch "^3.0.3" broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.1.tgz#9fd2e87f1c177b11a758e73c3a11d6a03d90d086" + resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.1.tgz#9fd2e87f1c177b11a758e73c3a11d6a03d90d086" dependencies: broccoli-plugin "^1.2.1" debug "^2.2.0" @@ -904,14 +898,14 @@ broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: broccoli-writer@~0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/broccoli-writer/-/broccoli-writer-0.1.1.tgz#d4d71aa8f2afbc67a3866b91a2da79084b96ab2d" + resolved "https://registry.npmjs.org/broccoli-writer/-/broccoli-writer-0.1.1.tgz#d4d71aa8f2afbc67a3866b91a2da79084b96ab2d" dependencies: quick-temp "^0.1.0" rsvp "^3.0.6" broccoli-yuidoc@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/broccoli-yuidoc/-/broccoli-yuidoc-2.1.0.tgz#d208d5c056e421a51f0c7701e938229e7e85c2e6" + resolved "https://registry.npmjs.org/broccoli-yuidoc/-/broccoli-yuidoc-2.1.0.tgz#d208d5c056e421a51f0c7701e938229e7e85c2e6" dependencies: broccoli-caching-writer "~2.0.1" broccoli-merge-trees "~0.2.3" @@ -919,19 +913,19 @@ broccoli-yuidoc@^2.1.0: rsvp "~3.1.0" yuidocjs "~0.9.0" -bser@^1.0.2: +bser@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" + resolved "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" dependencies: node-int64 "^0.4.0" buffer-shims@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + resolved "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" buffer@4.9.1: version "4.9.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -939,49 +933,49 @@ buffer@4.9.1: builtin-modules@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" builtins@0.0.7: version "0.0.7" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-0.0.7.tgz#355219cd6cf18dbe7c01cc7fd2dce765cfdc549a" + resolved "https://registry.npmjs.org/builtins/-/builtins-0.0.7.tgz#355219cd6cf18dbe7c01cc7fd2dce765cfdc549a" bytes@1: version "1.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" + resolved "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" bytes@2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" + resolved "https://registry.npmjs.org/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" bytes@2.4.0: version "2.4.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" + resolved "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" caller-path@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + resolved "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" dependencies: callsites "^0.2.0" callsite@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + resolved "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" callsites@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + resolved "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" camelcase@^1.0.2, camelcase@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" camelcase@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" can-symlink@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" + resolved "https://registry.npmjs.org/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" dependencies: tmp "0.0.28" @@ -993,48 +987,41 @@ capture-exit@^1.0.7: cardinal@^0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-0.5.0.tgz#00d5f661dbd4aabfdf7d41ce48a5a59bca35a291" + resolved "https://registry.npmjs.org/cardinal/-/cardinal-0.5.0.tgz#00d5f661dbd4aabfdf7d41ce48a5a59bca35a291" dependencies: ansicolors "~0.2.1" redeyed "~0.5.0" -cardinal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" - dependencies: - ansicolors "~0.2.1" - redeyed "~1.0.0" - caseless@~0.11.0: version "0.11.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + resolved "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" center-align@^0.1.1: version "0.1.3" - resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + resolved "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" dependencies: align-text "^0.1.3" lazy-cache "^1.0.3" chai-as-promised@^5.1.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-5.3.0.tgz#09d7a402908aa70dfdbead53e5853fc79d3ef21c" + resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-5.3.0.tgz#09d7a402908aa70dfdbead53e5853fc79d3ef21c" chai-as-promised@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" + resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" dependencies: check-error "^1.0.2" chai-files@^1.0.0, chai-files@^1.1.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" + resolved "https://registry.npmjs.org/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" dependencies: assertion-error "^1.0.1" chai@^3.3.0: version "3.5.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" + resolved "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" dependencies: assertion-error "^1.0.1" deep-eql "^0.1.3" @@ -1042,7 +1029,7 @@ chai@^3.3.0: chalk@^0.5.1: version "0.5.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" + resolved "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" dependencies: ansi-styles "^1.1.0" escape-string-regexp "^1.0.0" @@ -1052,7 +1039,7 @@ chalk@^0.5.1: chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -1062,21 +1049,21 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: charm@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" + resolved "https://registry.npmjs.org/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" dependencies: inherits "^2.0.1" check-error@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" chownr@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" chrome-debugging-client@^0.2.4: version "0.2.4" - resolved "https://registry.yarnpkg.com/chrome-debugging-client/-/chrome-debugging-client-0.2.4.tgz#2ae3fbfcbf0536cbbd4d12e6373b271e3bcfc468" + resolved "https://registry.npmjs.org/chrome-debugging-client/-/chrome-debugging-client-0.2.4.tgz#2ae3fbfcbf0536cbbd4d12e6373b271e3bcfc468" dependencies: mktemp "^0.4.0" rimraf "^2.5.1" @@ -1084,40 +1071,37 @@ chrome-debugging-client@^0.2.4: circular-json@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" clean-base-url@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" + resolved "https://registry.npmjs.org/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" -clean-css-promise@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" +clean-css-promise@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/clean-css-promise/-/clean-css-promise-2.0.1.tgz#ee0f784e1f2dbd37351f9e1dbd2be524a3b80973" dependencies: - array-to-error "^1.0.0" - clean-css "^3.4.5" - pinkie-promise "^2.0.0" + clean-css "^4.0.4" -clean-css@^3.4.5: - version "3.4.23" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.23.tgz#604fbbca24c12feb59b02f00b84f1fb7ded6d001" +clean-css@^4.0.4: + version "4.0.7" + resolved "https://registry.npmjs.org/clean-css/-/clean-css-4.0.7.tgz#d8fa8b4d87a125f38fa3d64afc59abfc68ba7790" dependencies: - commander "2.8.x" - source-map "0.4.x" + source-map "0.5.x" cli-cursor@^1.0.1, cli-cursor@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" dependencies: restore-cursor "^1.0.1" cli-spinners@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" + resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" cli-table2@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" + resolved "https://registry.npmjs.org/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" dependencies: lodash "^3.10.1" string-width "^1.0.1" @@ -1126,24 +1110,17 @@ cli-table2@^0.2.0: cli-table@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + resolved "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" dependencies: colors "1.0.3" -cli-usage@^0.1.1: - version "0.1.4" - resolved "https://registry.yarnpkg.com/cli-usage/-/cli-usage-0.1.4.tgz#7c01e0dc706c234b39c933838c8e20b2175776e2" - dependencies: - marked "^0.3.6" - marked-terminal "^1.6.2" - cli-width@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" cliui@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + resolved "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" dependencies: center-align "^0.1.1" right-align "^0.1.1" @@ -1151,7 +1128,7 @@ cliui@^2.1.0: cliui@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + resolved "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" @@ -1159,89 +1136,83 @@ cliui@^3.2.0: clone@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" + resolved "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" clone@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" + resolved "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" clone@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.0.tgz#9c715bfbd39aa197c8ee0f8e65c3912ba34f8cd6" + resolved "https://registry.npmjs.org/clone/-/clone-2.1.0.tgz#9c715bfbd39aa197c8ee0f8e65c3912ba34f8cd6" cmd-shim@~2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb" + resolved "https://registry.npmjs.org/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb" dependencies: graceful-fs "^4.1.2" mkdirp "~0.5.0" co@^4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" code-point-at@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" colors@1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" colors@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + resolved "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" colors@~0.6.0-1: version "0.6.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" + resolved "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" columnify@~1.5.4: version "1.5.4" - resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" + resolved "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" dependencies: strip-ansi "^3.0.0" wcwidth "^1.0.0" combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" dependencies: delayed-stream "~1.0.0" combined-stream@~0.0.4: version "0.0.7" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" dependencies: delayed-stream "0.0.5" commander@0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" + resolved "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" commander@2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" - -commander@2.8.x: - version "2.8.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" - dependencies: - graceful-readlink ">= 1.0.0" + resolved "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" commander@^2.5.0, commander@^2.6.0, commander@^2.9.0: version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + resolved "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" dependencies: graceful-readlink ">= 1.0.0" commander@~2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" + resolved "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" commoner@~0.10.3: version "0.10.8" - resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" + resolved "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" dependencies: commander "^2.5.0" detective "^4.3.1" @@ -1255,29 +1226,29 @@ commoner@~0.10.3: component-bind@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + resolved "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" component-emitter@1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" + resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" component-emitter@1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" component-inherit@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + resolved "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" compressible@~2.0.8: version "2.0.9" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.9.tgz#6daab4e2b599c2770dd9e21e7a891b1c5a755425" + resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.9.tgz#6daab4e2b599c2770dd9e21e7a891b1c5a755425" dependencies: mime-db ">= 1.24.0 < 2" compression@^1.4.4: version "1.6.2" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" + resolved "https://registry.npmjs.org/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" dependencies: accepts "~1.3.3" bytes "2.3.0" @@ -1288,11 +1259,11 @@ compression@^1.4.4: concat-map@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" concat-stream@1.5.0, concat-stream@^1.4.6: version "1.5.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" dependencies: inherits "~2.0.1" readable-stream "~2.0.0" @@ -1300,7 +1271,7 @@ concat-stream@1.5.0, concat-stream@^1.4.6: concat-stream@^1.4.7, concat-stream@^1.5.2: version "1.6.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: inherits "^2.0.3" readable-stream "^2.2.2" @@ -1308,14 +1279,14 @@ concat-stream@^1.4.7, concat-stream@^1.5.2: config-chain@~1.1.10: version "1.1.11" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2" + resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2" dependencies: ini "^1.3.4" proto-list "~1.2.1" configstore@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" + resolved "https://registry.npmjs.org/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" dependencies: dot-prop "^3.0.0" graceful-fs "^4.1.2" @@ -1329,7 +1300,7 @@ configstore@^2.0.0: console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" console-ui@^1.0.2: version "1.0.3" @@ -1342,55 +1313,55 @@ console-ui@^1.0.2: consolidate@^0.14.0: version "0.14.5" - resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" + resolved "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" dependencies: bluebird "^3.1.1" -content-disposition@0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b" +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" content-type@~1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" continuable-cache@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" + resolved "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" convert-source-map@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" + version "1.4.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.4.0.tgz#e3dad195bf61bfe13a7a3c73e9876ec14a0268f3" cookie-signature@1.0.6: version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" cookie@0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" copy-dereference@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" + resolved "https://registry.npmjs.org/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" core-js@^1.0.0: version "1.2.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + resolved "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" core-object@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" + resolved "https://registry.npmjs.org/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" core-object@^2.0.2: version "2.1.1" - resolved "https://registry.yarnpkg.com/core-object/-/core-object-2.1.1.tgz#4b7a5f1edefcb1e6d0dcb58eab1b9f90bfc666a8" + resolved "https://registry.npmjs.org/core-object/-/core-object-2.1.1.tgz#4b7a5f1edefcb1e6d0dcb58eab1b9f90bfc666a8" dependencies: chalk "^1.1.3" core-util-is@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" cross-spawn-async@^2.1.1: version "2.2.5" @@ -1401,7 +1372,7 @@ cross-spawn-async@^2.1.1: cross-spawn@^5.0.0: version "5.0.1" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.0.1.tgz#a3bbb302db2297cbea3c04edf36941f4613aa399" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.0.1.tgz#a3bbb302db2297cbea3c04edf36941f4613aa399" dependencies: lru-cache "^4.0.1" shebang-command "^1.2.0" @@ -1409,89 +1380,89 @@ cross-spawn@^5.0.0: cryptiles@0.2.x: version "0.2.2" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" + resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" dependencies: boom "0.4.x" cryptiles@2.x.x: version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" dependencies: boom "2.x.x" crypto-browserify@1.0.9: version "1.0.9" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" + resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" ctype@0.5.3: version "0.5.3" - resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" + resolved "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" d@^0.1.1, d@~0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" + resolved "https://registry.npmjs.org/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" dependencies: es5-ext "~0.10.2" dashdash@^1.12.0: version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" dependencies: assert-plus "^1.0.0" debug@0.7.4: version "0.7.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" + resolved "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" debug@2.2.0, debug@~2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + resolved "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" dependencies: ms "0.7.1" debug@2.3.3: version "2.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" + resolved "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" dependencies: ms "0.7.2" -debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" +debug@2.6.1, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: + version "2.6.1" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" dependencies: ms "0.7.2" -debuglog@^1.0.1: +debuglog@*, debuglog@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" + resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" deep-eql@^0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" + resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" dependencies: type-detect "0.1.1" deep-is@~0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" defaults@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" dependencies: clone "^1.0.2" defined@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + resolved "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" defs@~1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" + resolved "https://registry.npmjs.org/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" dependencies: alter "~0.2.0" ast-traverse "~0.1.1" @@ -1506,7 +1477,7 @@ defs@~1.1.0: del@^2.0.2: version "2.2.2" - resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + resolved "https://registry.npmjs.org/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" dependencies: globby "^5.0.0" is-path-cwd "^1.0.0" @@ -1518,33 +1489,33 @@ del@^2.0.2: delayed-stream@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" delegates@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" depd@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" destroy@~1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" detect-file@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" + resolved "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" dependencies: fs-exists-sync "^0.1.0" detect-indent@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" dependencies: get-stdin "^4.0.1" minimist "^1.1.0" @@ -1552,52 +1523,52 @@ detect-indent@^3.0.0: detective@^4.3.1: version "4.3.2" - resolved "https://registry.yarnpkg.com/detective/-/detective-4.3.2.tgz#77697e2e7947ac3fe7c8e26a6d6f115235afa91c" + resolved "https://registry.npmjs.org/detective/-/detective-4.3.2.tgz#77697e2e7947ac3fe7c8e26a6d6f115235afa91c" dependencies: acorn "^3.1.0" defined "^1.0.0" dezalgo@^1.0.0, dezalgo@^1.0.1, dezalgo@~1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + resolved "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" dependencies: asap "^2.0.0" wrappy "1" diff@1.4.0, diff@^1.3.1: version "1.4.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" + resolved "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" doctrine@^1.2.2: version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" dependencies: esutils "^2.0.2" isarray "^1.0.0" dot-prop@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" dependencies: is-obj "^1.0.0" ecc-jsbn@~0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" dependencies: jsbn "~0.1.0" editions@^1.1.1: version "1.3.3" - resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" + resolved "https://registry.npmjs.org/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" editor@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" + resolved "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" ee-first@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" ember-ajax@^2.4.1: version "2.5.5" @@ -1614,10 +1585,10 @@ ember-cli-app-version@^2.0.0: git-repo-version "0.4.1" ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.1.7, ember-cli-babel@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-5.2.1.tgz#14a1a7b3ae9e9f1284f7bcdb142eb53bd0b1b5bd" + version "5.2.4" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" dependencies: - broccoli-babel-transpiler "^5.6.0" + broccoli-babel-transpiler "^5.6.2" broccoli-funnel "^1.0.0" clone "^2.0.0" ember-cli-version-checker "^1.0.2" @@ -1625,7 +1596,7 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-c ember-cli-blueprint-test-helpers@0.11.0: version "0.11.0" - resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" + resolved "https://registry.npmjs.org/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" dependencies: chai "^3.3.0" chai-as-promised "^5.1.0" @@ -1640,7 +1611,7 @@ ember-cli-blueprint-test-helpers@0.11.0: ember-cli-broccoli-sane-watcher@^2.0.3: version "2.0.4" - resolved "https://registry.yarnpkg.com/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.0.4.tgz#f43f42f75b7509c212fb926cd9aea86ae19264c6" + resolved "https://registry.npmjs.org/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.0.4.tgz#f43f42f75b7509c212fb926cd9aea86ae19264c6" dependencies: broccoli-slow-trees "^3.0.1" heimdalljs "^0.2.1" @@ -1658,7 +1629,7 @@ ember-cli-dependency-checker@^1.3.0: ember-cli-eslint@1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/ember-cli-eslint/-/ember-cli-eslint-1.3.0.tgz#8a7eda0d7e6a00c5a5a823f59664932d6429a8f1" + resolved "https://registry.npmjs.org/ember-cli-eslint/-/ember-cli-eslint-1.3.0.tgz#8a7eda0d7e6a00c5a5a823f59664932d6429a8f1" dependencies: broccoli-lint-eslint "^2.0.0" ember-cli-babel "^5.1.5" @@ -1666,11 +1637,11 @@ ember-cli-eslint@1.3.0: ember-cli-get-component-path-option@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" + resolved "https://registry.npmjs.org/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" ember-cli-get-dependency-depth@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" + resolved "https://registry.npmjs.org/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" ember-cli-htmlbars-inline-precompile@^0.3.6: version "0.3.6" @@ -1683,7 +1654,7 @@ ember-cli-htmlbars-inline-precompile@^0.3.6: ember-cli-htmlbars@^1.0.0, ember-cli-htmlbars@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-1.1.1.tgz#8776cf59796dac8f32e8625fc6d1ea45ffa55de1" + resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-1.1.1.tgz#8776cf59796dac8f32e8625fc6d1ea45ffa55de1" dependencies: broccoli-persistent-filter "^1.0.3" ember-cli-version-checker "^1.0.2" @@ -1697,7 +1668,7 @@ ember-cli-inject-live-reload@^1.4.1: ember-cli-internal-test-helpers@^0.8.1: version "0.8.3" - resolved "https://registry.yarnpkg.com/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.8.3.tgz#e9b7db67f3fda4db736d1a319a282c04beada495" + resolved "https://registry.npmjs.org/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.8.3.tgz#e9b7db67f3fda4db736d1a319a282c04beada495" dependencies: chai "^3.3.0" chai-as-promised "^6.0.0" @@ -1715,11 +1686,11 @@ ember-cli-internal-test-helpers@^0.8.1: ember-cli-is-package-missing@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" + resolved "https://registry.npmjs.org/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" ember-cli-legacy-blueprints@^0.1.2: version "0.1.4" - resolved "https://registry.yarnpkg.com/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.4.tgz#83d6c005ac0e39750ff9dd45cd1b78cf697150c6" + resolved "https://registry.npmjs.org/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.4.tgz#83d6c005ac0e39750ff9dd45cd1b78cf697150c6" dependencies: chalk "^1.1.1" ember-cli-get-component-path-option "^1.0.0" @@ -1740,29 +1711,29 @@ ember-cli-legacy-blueprints@^0.1.2: silent-error "^1.0.0" ember-cli-lodash-subset@^1.0.11, ember-cli-lodash-subset@^1.0.7: - version "1.0.11" - resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.11.tgz#0149eef9c0c3505ba44ed202f8d034ddbbfb2826" + version "1.0.12" + resolved "https://registry.npmjs.org/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" ember-cli-normalize-entity-name@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" + resolved "https://registry.npmjs.org/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" dependencies: silent-error "^1.0.0" ember-cli-path-utils@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" + resolved "https://registry.npmjs.org/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" ember-cli-preprocess-registry@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.0.0.tgz#5a7e6a4048a895856c8a54ed145cf92153b2ab96" + version "3.1.0" + resolved "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.0.tgz#9e4ca277b5ee5f31a57b5b06174d94e3dadbf9f3" dependencies: - broccoli-clean-css "^1.1.0" + broccoli-clean-css "^2.0.0" broccoli-funnel "^1.0.0" broccoli-merge-trees "^1.0.0" debug "^2.2.0" + ember-cli-lodash-subset "^1.0.7" exists-sync "0.0.3" - lodash "^4.5.0" process-relative-require "^1.0.0" silent-error "^1.0.0" @@ -1777,7 +1748,7 @@ ember-cli-pretender@^1.0.1: ember-cli-qunit@^2.1.0: version "2.2.5" - resolved "https://registry.yarnpkg.com/ember-cli-qunit/-/ember-cli-qunit-2.2.5.tgz#c8a2bf4e018e674089388d07d63adf1a3f270b74" + resolved "https://registry.npmjs.org/ember-cli-qunit/-/ember-cli-qunit-2.2.5.tgz#c8a2bf4e018e674089388d07d63adf1a3f270b74" dependencies: broccoli-babel-transpiler "^5.5.0" broccoli-concat "^2.2.0" @@ -1793,7 +1764,7 @@ ember-cli-qunit@^2.1.0: ember-cli-release@^0.2.9: version "0.2.9" - resolved "https://registry.yarnpkg.com/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" + resolved "https://registry.npmjs.org/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" dependencies: chalk "^1.0.0" git-tools "^0.1.4" @@ -1815,41 +1786,41 @@ ember-cli-shims@^1.0.2: ember-cli-sri@^2.1.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" + resolved "https://registry.npmjs.org/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" dependencies: broccoli-sri-hash "^2.1.0" ember-cli-string-utils@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.0.0.tgz#d07b17d0b6223c42e09bfb835ee2b8466ec9b88e" + version "1.1.0" + resolved "https://registry.npmjs.org/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" ember-cli-test-info@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" + resolved "https://registry.npmjs.org/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" dependencies: ember-cli-string-utils "^1.0.0" ember-cli-test-loader@^1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-test-loader/-/ember-cli-test-loader-1.1.1.tgz#333311209b18185d0e0e95f918349da10cacf0b1" + resolved "https://registry.npmjs.org/ember-cli-test-loader/-/ember-cli-test-loader-1.1.1.tgz#333311209b18185d0e0e95f918349da10cacf0b1" dependencies: ember-cli-babel "^5.2.1" ember-cli-uglify@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/ember-cli-uglify/-/ember-cli-uglify-1.2.0.tgz#3208c32b54bc2783056e8bb0d5cfe9bbaf17ffb2" + resolved "https://registry.npmjs.org/ember-cli-uglify/-/ember-cli-uglify-1.2.0.tgz#3208c32b54bc2783056e8bb0d5cfe9bbaf17ffb2" dependencies: broccoli-uglify-sourcemap "^1.0.0" ember-cli-valid-component-name@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" + resolved "https://registry.npmjs.org/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" dependencies: silent-error "^1.0.0" ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7, ember-cli-version-checker@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-1.2.0.tgz#caa286b77d1b485df5d2f62c67a6f19aa8b582c4" + resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.2.0.tgz#caa286b77d1b485df5d2f62c67a6f19aa8b582c4" dependencies: semver "^5.3.0" @@ -1945,25 +1916,25 @@ ember-dev@emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed: ember-disable-prototype-extensions@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.0.tgz#86081c8cf6741f26e4b89e2b004f761174313e01" + resolved "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.0.tgz#86081c8cf6741f26e4b89e2b004f761174313e01" dependencies: ember-cli-babel "^5.1.5" ember-disable-proxy-controllers@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" + resolved "https://registry.npmjs.org/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" dependencies: ember-cli-babel "^5.0.0" ember-export-application-global@^1.0.5: version "1.1.1" - resolved "https://registry.yarnpkg.com/ember-export-application-global/-/ember-export-application-global-1.1.1.tgz#f257d5271268932a89d7392679ce4db89d7154af" + resolved "https://registry.npmjs.org/ember-export-application-global/-/ember-export-application-global-1.1.1.tgz#f257d5271268932a89d7392679ce4db89d7154af" dependencies: ember-cli-babel "^5.1.10" ember-inflector@^1.9.4: version "1.11.0" - resolved "https://registry.yarnpkg.com/ember-inflector/-/ember-inflector-1.11.0.tgz#99baae18e2bee53cfa97d8db1d739280289a174f" + resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-1.11.0.tgz#99baae18e2bee53cfa97d8db1d739280289a174f" dependencies: ember-cli-babel "^5.1.7" @@ -1975,32 +1946,32 @@ ember-load-initializers@^0.6.0: ember-publisher@0.0.7: version "0.0.7" - resolved "https://registry.yarnpkg.com/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" + resolved "https://registry.npmjs.org/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" dependencies: aws-sdk "^2.0.9" ember-qunit@^0.4.18: version "0.4.22" - resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-0.4.22.tgz#bc389798e1a4a933f542863025e2fb91d856da49" + resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-0.4.22.tgz#bc389798e1a4a933f542863025e2fb91d856da49" dependencies: ember-test-helpers "^0.5.32" ember-resolver@^2.0.3: version "2.1.1" - resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-2.1.1.tgz#5e4c1fffe9f5f48fc2194ad7592274ed0cd74f72" + resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-2.1.1.tgz#5e4c1fffe9f5f48fc2194ad7592274ed0cd74f72" dependencies: ember-cli-babel "^5.1.6" ember-cli-version-checker "^1.1.6" ember-router-generator@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.2.tgz#62dac1f63e873553e6d4c7e32da6589e577bcf63" + version "1.2.3" + resolved "https://registry.npmjs.org/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" dependencies: recast "^0.11.3" ember-runtime-enumerable-includes-polyfill@^1.0.0: version "1.0.4" - resolved "https://registry.yarnpkg.com/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-1.0.4.tgz#16a7612e347a2edf07da8b2f2f09dbfee70deba0" + resolved "https://registry.npmjs.org/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-1.0.4.tgz#16a7612e347a2edf07da8b2f2f09dbfee70deba0" dependencies: ember-cli-babel "^5.1.6" ember-cli-version-checker "^1.1.6" @@ -2024,13 +1995,13 @@ ember-source@~2.11.0: ember-test-helpers@^0.5.32: version "0.5.34" - resolved "https://registry.yarnpkg.com/ember-test-helpers/-/ember-test-helpers-0.5.34.tgz#c8439108d1cba1d7d838c212208a5c4061471b83" + resolved "https://registry.npmjs.org/ember-test-helpers/-/ember-test-helpers-0.5.34.tgz#c8439108d1cba1d7d838c212208a5c4061471b83" dependencies: klassy "^0.1.3" ember-try-config@^2.0.1: version "2.1.0" - resolved "https://registry.yarnpkg.com/ember-try-config/-/ember-try-config-2.1.0.tgz#e0e156229a542346a58ee6f6ad605104c98edfe0" + resolved "https://registry.npmjs.org/ember-try-config/-/ember-try-config-2.1.0.tgz#e0e156229a542346a58ee6f6ad605104c98edfe0" dependencies: lodash "^4.6.1" node-fetch "^1.3.3" @@ -2038,8 +2009,8 @@ ember-try-config@^2.0.1: semver "^5.1.0" ember-try@^0.2.6: - version "0.2.8" - resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.8.tgz#5f135d23d83561dc8dfb4a4d998420b69b740acd" + version "0.2.10" + resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.10.tgz#8a11191fe8e5a45fb94b3bfdb0dc57d71899f16c" dependencies: chalk "^1.0.0" cli-table2 "^0.2.0" @@ -2059,7 +2030,7 @@ ember-try@^0.2.6: ember-watson@^0.7.0: version "0.7.0" - resolved "https://registry.yarnpkg.com/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" + resolved "https://registry.npmjs.org/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" dependencies: babel-core "^5.8.22" chalk "^1.0.0" @@ -2071,17 +2042,17 @@ ember-watson@^0.7.0: encodeurl@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" encoding@^0.1.11: version "0.1.12" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" dependencies: iconv-lite "~0.4.13" engine.io-client@1.8.0: version "1.8.0" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.0.tgz#7b730e4127414087596d9be3c88d2bc5fdb6cf5c" + resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.0.tgz#7b730e4127414087596d9be3c88d2bc5fdb6cf5c" dependencies: component-emitter "1.2.1" component-inherit "0.0.3" @@ -2098,7 +2069,7 @@ engine.io-client@1.8.0: engine.io-parser@1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" + resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" dependencies: after "0.8.1" arraybuffer.slice "0.0.6" @@ -2109,7 +2080,7 @@ engine.io-parser@1.3.1: engine.io@1.8.0: version "1.8.0" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" + resolved "https://registry.npmjs.org/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" dependencies: accepts "1.3.3" base64id "0.1.0" @@ -2120,35 +2091,35 @@ engine.io@1.8.0: ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" + resolved "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" entities@~1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + resolved "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" error-ex@^1.2.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.0.tgz#e67b43f3e82c96ea3a584ffee0b9fc3325d802d9" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz#e67b43f3e82c96ea3a584ffee0b9fc3325d802d9" dependencies: is-arrayish "^0.2.1" error@^7.0.0: version "7.0.2" - resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" + resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" dependencies: string-template "~0.2.1" xtend "~4.0.0" es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: version "0.10.12" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" + resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" dependencies: es6-iterator "2" es6-symbol "~3.1" es6-iterator@2: version "2.0.0" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" + resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" dependencies: d "^0.1.1" es5-ext "^0.10.7" @@ -2156,7 +2127,7 @@ es6-iterator@2: es6-map@^0.1.3: version "0.1.4" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" + resolved "https://registry.npmjs.org/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" dependencies: d "~0.1.1" es5-ext "~0.10.11" @@ -2167,11 +2138,11 @@ es6-map@^0.1.3: es6-promise@~4.0.3: version "4.0.5" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" + resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" es6-set@~0.1.3: version "0.1.4" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" + resolved "https://registry.npmjs.org/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" dependencies: d "~0.1.1" es5-ext "~0.10.11" @@ -2181,14 +2152,14 @@ es6-set@~0.1.3: es6-symbol@3, es6-symbol@^3.0.2, es6-symbol@~3.1, es6-symbol@~3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" + resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" dependencies: d "~0.1.1" es5-ext "~0.10.11" es6-weak-map@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" + resolved "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" dependencies: d "^0.1.1" es5-ext "^0.10.8" @@ -2197,19 +2168,19 @@ es6-weak-map@^2.0.1: escape-html@~1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" escape-string-regexp@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" escope@^3.6.0: version "3.6.0" - resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + resolved "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" dependencies: es6-map "^0.1.3" es6-weak-map "^2.0.1" @@ -2218,7 +2189,7 @@ escope@^3.6.0: eslint@^2.13.0: version "2.13.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" + resolved "https://registry.npmjs.org/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" dependencies: chalk "^1.1.3" concat-stream "^1.4.6" @@ -2255,81 +2226,77 @@ eslint@^2.13.0: user-home "^2.0.0" espree@^3.1.6: - version "3.3.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.3.2.tgz#dbf3fadeb4ecb4d4778303e50103b3d36c88b89c" + version "3.4.0" + resolved "https://registry.npmjs.org/espree/-/espree-3.4.0.tgz#41656fa5628e042878025ef467e78f125cb86e1d" dependencies: - acorn "^4.0.1" + acorn "4.0.4" acorn-jsx "^3.0.0" esprima-fb@~12001.1.0-dev-harmony-fb: version "12001.1.0-dev-harmony-fb" - resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-12001.1.0-dev-harmony-fb.tgz#d84400384ba95ce2678c617ad24a7f40808da915" + resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-12001.1.0-dev-harmony-fb.tgz#d84400384ba95ce2678c617ad24a7f40808da915" esprima-fb@~15001.1001.0-dev-harmony-fb: version "15001.1001.0-dev-harmony-fb" - resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" + resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" esprima@^1.2.2: version "1.2.5" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" + resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" esprima@^2.6.0: version "2.7.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" - -esprima@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" + resolved "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" -esprima@~3.1.0: +esprima@^3.1.1, esprima@~3.1.0: version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + resolved "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" esprimaq@^0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" + resolved "https://registry.npmjs.org/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" esrecurse@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" dependencies: estraverse "~4.1.0" object-assign "^4.0.1" estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" estraverse@~4.1.0: version "4.1.1" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" etag@~1.7.0: version "1.7.0" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" + resolved "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" event-emitter@~0.3.4: version "0.3.4" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" + resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" dependencies: d "~0.1.1" es5-ext "~0.10.7" eventemitter3@1.x.x: version "1.2.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" events-to-array@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.0.2.tgz#b3484465534fe4ff66fbdd1a83b777713ba404aa" + resolved "https://registry.npmjs.org/events-to-array/-/events-to-array-1.0.2.tgz#b3484465534fe4ff66fbdd1a83b777713ba404aa" exec-sh@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" + resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" dependencies: merge "^1.1.3" @@ -2346,45 +2313,45 @@ execa@^0.4.0: exists-sync@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" + resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" exists-sync@0.0.4: version "0.0.4" - resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" + resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" exit-hook@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" exit@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" expand-brackets@^0.1.4: version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" dependencies: is-posix-bracket "^0.1.0" expand-range@^1.8.1: version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + resolved "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" dependencies: fill-range "^2.1.0" expand-tilde@^1.2.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" + resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" dependencies: os-homedir "^1.0.1" express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: - version "4.14.0" - resolved "https://registry.yarnpkg.com/express/-/express-4.14.0.tgz#c1ee3f42cdc891fb3dc650a8922d51ec847d0d66" + version "4.14.1" + resolved "https://registry.npmjs.org/express/-/express-4.14.1.tgz#646c237f766f148c2120aff073817b9e4d7e0d33" dependencies: accepts "~1.3.3" array-flatten "1.1.1" - content-disposition "0.5.1" + content-disposition "0.5.2" content-type "~1.0.2" cookie "0.3.1" cookie-signature "1.0.6" @@ -2393,29 +2360,29 @@ express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: encodeurl "~1.0.1" escape-html "~1.0.3" etag "~1.7.0" - finalhandler "0.5.0" + finalhandler "0.5.1" fresh "0.3.0" merge-descriptors "1.0.1" methods "~1.1.2" on-finished "~2.3.0" parseurl "~1.3.1" path-to-regexp "0.1.7" - proxy-addr "~1.1.2" + proxy-addr "~1.1.3" qs "6.2.0" range-parser "~1.2.0" - send "0.14.1" - serve-static "~1.11.1" - type-is "~1.6.13" + send "0.14.2" + serve-static "~1.11.2" + type-is "~1.6.14" utils-merge "1.0.0" vary "~1.1.0" extend@^3.0.0, extend@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + resolved "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" external-editor@^1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" + resolved "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" dependencies: extend "^3.0.0" spawn-sync "^1.0.15" @@ -2423,13 +2390,13 @@ external-editor@^1.1.0: extglob@^0.3.1: version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + resolved "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" dependencies: is-extglob "^1.0.0" extract-zip@~1.5.0: version "1.5.0" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4" + resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4" dependencies: concat-stream "1.5.0" debug "0.7.4" @@ -2438,29 +2405,29 @@ extract-zip@~1.5.0: extsprintf@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" fake-xml-http-request@^1.3.0, fake-xml-http-request@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-1.4.0.tgz#6481c727a0eae9c420bae229dcdfc5369c4b5477" + resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-1.4.0.tgz#6481c727a0eae9c420bae229dcdfc5369c4b5477" faker@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/faker/-/faker-3.1.0.tgz#0f908faf4e6ec02524e54a57e432c5c013e08c9f" + resolved "https://registry.npmjs.org/faker/-/faker-3.1.0.tgz#0f908faf4e6ec02524e54a57e432c5c013e08c9f" fast-levenshtein@~2.0.4: version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" + resolved "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" dependencies: blank-object "^1.0.1" fast-sourcemap-concat@^1.0.1: version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-sourcemap-concat/-/fast-sourcemap-concat-1.1.0.tgz#a800767abed5eda02e67238ec063a709be61f9d4" + resolved "https://registry.npmjs.org/fast-sourcemap-concat/-/fast-sourcemap-concat-1.1.0.tgz#a800767abed5eda02e67238ec063a709be61f9d4" dependencies: chalk "^0.5.1" debug "^2.2.0" @@ -2473,47 +2440,47 @@ fast-sourcemap-concat@^1.0.1: faye-websocket@~0.10.0: version "0.10.0" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" dependencies: websocket-driver ">=0.5.1" fb-watchman@^1.8.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.0.tgz#6f268f1f347a6b3c875d1e89da7e1ed79adfc0ec" + version "1.9.2" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383" dependencies: - bser "^1.0.2" + bser "1.0.2" fd-slicer@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" dependencies: pend "~1.2.0" figures@^1.3.5: version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + resolved "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" dependencies: escape-string-regexp "^1.0.5" object-assign "^4.1.0" file-entry-cache@^1.1.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" dependencies: flat-cache "^1.2.1" object-assign "^4.0.1" filename-regex@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + resolved "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" filesize@^3.1.3: - version "3.3.0" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.3.0.tgz#53149ea3460e3b2e024962a51648aa572cf98122" + version "3.5.4" + resolved "https://registry.npmjs.org/filesize/-/filesize-3.5.4.tgz#742fc7fb6aef4ee3878682600c22f840731e1fda" fill-range@^2.1.0: version "2.2.3" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" dependencies: is-number "^2.1.0" isobject "^2.0.0" @@ -2521,14 +2488,14 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" -finalhandler@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.0.tgz#e9508abece9b6dba871a6942a1d7911b91911ac7" +finalhandler@0.5.1: + version "0.5.1" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.1.tgz#2c400d8d4530935bc232549c5fa385ec07de6fcd" dependencies: debug "~2.2.0" escape-html "~1.0.3" on-finished "~2.3.0" - statuses "~1.3.0" + statuses "~1.3.1" unpipe "~1.0.0" find-index@^1.1.0: @@ -2537,14 +2504,14 @@ find-index@^1.1.0: find-up@^1.0.0, find-up@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" findup-sync@^0.4.2: version "0.4.3" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" + resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" dependencies: detect-file "^0.1.0" is-glob "^2.0.1" @@ -2553,14 +2520,14 @@ findup-sync@^0.4.2: findup@^0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" + resolved "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" dependencies: colors "~0.6.0-1" commander "~2.1.0" fireworm@^0.7.0: version "0.7.1" - resolved "https://registry.yarnpkg.com/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" + resolved "https://registry.npmjs.org/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" dependencies: async "~0.2.9" is-type "0.0.1" @@ -2570,7 +2537,7 @@ fireworm@^0.7.0: flat-cache@^1.2.1: version "1.2.2" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" dependencies: circular-json "^0.3.1" del "^2.0.2" @@ -2579,25 +2546,25 @@ flat-cache@^1.2.1: for-in@^0.1.5: version "0.1.6" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" + resolved "https://registry.npmjs.org/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" for-own@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" + resolved "https://registry.npmjs.org/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" dependencies: for-in "^0.1.5" forever-agent@~0.5.0: version "0.5.2" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" forever-agent@~0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" form-data@~0.1.0: version "0.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" + resolved "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" dependencies: async "~0.9.0" combined-stream "~0.0.4" @@ -2605,7 +2572,7 @@ form-data@~0.1.0: form-data@~1.0.0-rc4: version "1.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" + resolved "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" dependencies: async "^2.0.1" combined-stream "^1.0.5" @@ -2613,7 +2580,7 @@ form-data@~1.0.0-rc4: form-data@~2.1.1: version "2.1.2" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" + resolved "https://registry.npmjs.org/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" dependencies: asynckit "^0.4.0" combined-stream "^1.0.5" @@ -2621,19 +2588,19 @@ form-data@~2.1.1: forwarded@~0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" fresh@0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" fs-exists-sync@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + resolved "http://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" fs-extra@1.0.0, fs-extra@^1.0.0, fs-extra@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -2641,7 +2608,7 @@ fs-extra@1.0.0, fs-extra@^1.0.0, fs-extra@~1.0.0: fs-extra@^0.24.0: version "0.24.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -2650,7 +2617,7 @@ fs-extra@^0.24.0: fs-extra@^0.26.0, fs-extra@^0.26.7: version "0.26.7" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -2660,7 +2627,7 @@ fs-extra@^0.26.0, fs-extra@^0.26.7: fs-extra@^0.30.0: version "0.30.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -2670,11 +2637,11 @@ fs-extra@^0.30.0: fs-readdir-recursive@^0.1.0: version "0.1.2" - resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" + resolved "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" fs-sync@^0.2.4: version "0.2.6" - resolved "https://registry.yarnpkg.com/fs-sync/-/fs-sync-0.2.6.tgz#657116c12b95ac9a36c51a850066c9ee6441fe06" + resolved "https://registry.npmjs.org/fs-sync/-/fs-sync-0.2.6.tgz#657116c12b95ac9a36c51a850066c9ee6441fe06" dependencies: glob "~4.0.4" iconv-lite "~0.2.10" @@ -2684,7 +2651,7 @@ fs-sync@^0.2.4: fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6: version "0.5.6" - resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-0.5.6.tgz#342665749e8dca406800b672268c8f5073f3e623" + resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.6.tgz#342665749e8dca406800b672268c8f5073f3e623" dependencies: heimdalljs-logger "^0.1.7" object-assign "^4.1.0" @@ -2693,7 +2660,7 @@ fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5 fs-vacuum@~1.2.9: version "1.2.9" - resolved "https://registry.yarnpkg.com/fs-vacuum/-/fs-vacuum-1.2.9.tgz#4f90193ab8ea02890995bcd4e804659a5d366b2d" + resolved "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.9.tgz#4f90193ab8ea02890995bcd4e804659a5d366b2d" dependencies: graceful-fs "^4.1.2" path-is-inside "^1.0.1" @@ -2701,7 +2668,7 @@ fs-vacuum@~1.2.9: fs-write-stream-atomic@~1.0.8: version "1.0.8" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.8.tgz#e49aaddf288f87d46ff9e882f216a13abc40778b" + resolved "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.8.tgz#e49aaddf288f87d46ff9e882f216a13abc40778b" dependencies: graceful-fs "^4.1.2" iferr "^0.1.5" @@ -2710,11 +2677,11 @@ fs-write-stream-atomic@~1.0.8: fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" fstream-ignore@^1.0.0: version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + resolved "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" dependencies: fstream "^1.0.0" inherits "2" @@ -2722,14 +2689,14 @@ fstream-ignore@^1.0.0: fstream-npm@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/fstream-npm/-/fstream-npm-1.2.0.tgz#d2c3c89101346982d64e57091c38487bda916fce" + resolved "https://registry.npmjs.org/fstream-npm/-/fstream-npm-1.2.0.tgz#d2c3c89101346982d64e57091c38487bda916fce" dependencies: fstream-ignore "^1.0.0" inherits "2" fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: version "1.0.10" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" + resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" dependencies: graceful-fs "^4.1.2" inherits "~2.0.0" @@ -2738,7 +2705,7 @@ fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: gauge@~2.6.0: version "2.6.0" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.6.0.tgz#d35301ad18e96902b4751dcbbe40f4218b942a46" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.6.0.tgz#d35301ad18e96902b4751dcbbe40f4218b942a46" dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -2751,8 +2718,8 @@ gauge@~2.6.0: wide-align "^1.1.0" gauge@~2.7.1: - version "2.7.2" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774" + version "2.7.3" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09" dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -2761,36 +2728,35 @@ gauge@~2.7.1: signal-exit "^3.0.0" string-width "^1.0.1" strip-ansi "^3.0.1" - supports-color "^0.2.0" wide-align "^1.1.0" generate-function@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + resolved "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" generate-object-property@^1.1.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + resolved "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" dependencies: is-property "^1.0.0" get-caller-file@^1.0.0, get-caller-file@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" get-stdin@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" getpass@^0.1.1: version "0.1.6" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" dependencies: assert-plus "^1.0.0" git-repo-info@^1.0.4, git-repo-info@^1.1.2: - version "1.4.0" - resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.4.0.tgz#ed210221defd3fdefce8b16ac61985cabe242e4a" + version "1.4.1" + resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" git-repo-info@~1.2.0: version "1.2.0" @@ -2804,32 +2770,32 @@ git-repo-version@0.4.1: git-tools@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" + resolved "https://registry.npmjs.org/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" dependencies: spawnback "~1.0.0" github@^0.2.4: version "0.2.4" - resolved "https://registry.yarnpkg.com/github/-/github-0.2.4.tgz#24fa7f0e13fa11b946af91134c51982a91ce538b" + resolved "https://registry.npmjs.org/github/-/github-0.2.4.tgz#24fa7f0e13fa11b946af91134c51982a91ce538b" dependencies: mime "^1.2.11" glob-base@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + resolved "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" dependencies: glob-parent "^2.0.0" is-glob "^2.0.0" glob-parent@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" dependencies: is-glob "^2.0.0" glob@3.2.3: version "3.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" + resolved "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" dependencies: graceful-fs "~2.0.0" inherits "2" @@ -2837,7 +2803,7 @@ glob@3.2.3: glob@5.0.13, glob@^5.0.10: version "5.0.13" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" + resolved "https://registry.npmjs.org/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" dependencies: inflight "^1.0.4" inherits "2" @@ -2847,7 +2813,7 @@ glob@5.0.13, glob@^5.0.10: glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.1: version "7.1.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -2858,7 +2824,7 @@ glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.1: glob@^4.3.2: version "4.5.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" + resolved "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" dependencies: inflight "^1.0.4" inherits "2" @@ -2867,7 +2833,7 @@ glob@^4.3.2: glob@^5.0.15: version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: inflight "^1.0.4" inherits "2" @@ -2877,7 +2843,7 @@ glob@^5.0.15: glob@^6.0.0: version "6.0.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + resolved "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" dependencies: inflight "^1.0.4" inherits "2" @@ -2887,7 +2853,7 @@ glob@^6.0.0: glob@~4.0.4: version "4.0.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-4.0.6.tgz#695c50bdd4e2fb5c5d370b091f388d3707e291a7" + resolved "https://registry.npmjs.org/glob/-/glob-4.0.6.tgz#695c50bdd4e2fb5c5d370b091f388d3707e291a7" dependencies: graceful-fs "^3.0.2" inherits "2" @@ -2896,7 +2862,7 @@ glob@~4.0.4: glob@~7.0.6: version "7.0.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" + resolved "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -2907,14 +2873,14 @@ glob@~7.0.6: global-modules@^0.2.3: version "0.2.3" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" + resolved "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" dependencies: global-prefix "^0.1.4" is-windows "^0.2.0" global-prefix@^0.1.4: version "0.1.5" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" + resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" dependencies: homedir-polyfill "^1.0.0" ini "^1.3.4" @@ -2923,15 +2889,15 @@ global-prefix@^0.1.4: globals@^6.4.0: version "6.4.1" - resolved "https://registry.yarnpkg.com/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" + resolved "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" globals@^9.2.0: - version "9.14.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" + version "9.16.0" + resolved "https://registry.npmjs.org/globals/-/globals-9.16.0.tgz#63e903658171ec2d9f51b1d31de5e2b8dc01fb80" globby@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + resolved "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" dependencies: array-union "^1.0.1" arrify "^1.0.0" @@ -2942,37 +2908,37 @@ globby@^5.0.0: graceful-fs@^3.0.2: version "3.0.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" dependencies: natives "^1.1.0" graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.6: version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" graceful-fs@~1: version "1.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" graceful-fs@~2.0.0: version "2.0.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" "graceful-readlink@>= 1.0.0": version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + resolved "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" growl@1.8.1: version "1.8.1" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428" + resolved "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428" -growly@^1.2.0: +growly@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" handlebars@^4.0.4: version "4.0.6" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" + resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" dependencies: async "^1.4.0" optimist "^0.6.1" @@ -2982,7 +2948,7 @@ handlebars@^4.0.4: har-validator@~2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" dependencies: chalk "^1.1.1" commander "^2.9.0" @@ -2991,43 +2957,43 @@ har-validator@~2.0.6: has-ansi@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" + resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" dependencies: ansi-regex "^0.2.0" has-ansi@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" dependencies: ansi-regex "^2.0.0" has-binary@0.1.6: version "0.1.6" - resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" + resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" dependencies: isarray "0.0.1" has-binary@0.1.7: version "0.1.7" - resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" + resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" dependencies: isarray "0.0.1" has-color@^0.1.7: version "0.1.7" - resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" + resolved "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" has-cors@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + resolved "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" has-unicode@^2.0.0, has-unicode@~2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" hash-for-dep@^1.0.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.1.2.tgz#e3347ed92960eb0bb53a2c6c2b70e36d75b7cd0c" + resolved "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.1.2.tgz#e3347ed92960eb0bb53a2c6c2b70e36d75b7cd0c" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" heimdalljs "^0.2.3" @@ -3036,14 +3002,14 @@ hash-for-dep@^1.0.2: hasha@~2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1" + resolved "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1" dependencies: is-stream "^1.0.1" pinkie-promise "^2.0.0" hawk@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" + resolved "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" dependencies: boom "0.4.x" cryptiles "0.2.x" @@ -3052,7 +3018,7 @@ hawk@1.1.1: hawk@~3.1.3: version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + resolved "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" dependencies: boom "2.x.x" cryptiles "2.x.x" @@ -3061,7 +3027,7 @@ hawk@~3.1.3: heimdall-query@^0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" + resolved "https://registry.npmjs.org/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" dependencies: chalk "^1.1.1" chrome-debugging-client "^0.2.4" @@ -3079,52 +3045,56 @@ heimdalljs-fs-monitor@^0.1.0: heimdalljs-logger "^0.1.7" heimdalljs-logger@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.7.tgz#10e340af5c22a811e34522d9b9397675ad589ca4" + version "0.1.8" + resolved "https://registry.npmjs.org/heimdalljs-logger/-/heimdalljs-logger-0.1.8.tgz#82abb55e53eefc0e5654ddf521b82926e50fcd95" dependencies: debug "^2.2.0" heimdalljs "^0.2.0" heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3: version "0.2.3" - resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.3.tgz#35b82a6a4d73541fc4fb88d2fe2b23608fb4f779" + resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.2.3.tgz#35b82a6a4d73541fc4fb88d2fe2b23608fb4f779" dependencies: rsvp "~3.2.1" heimdalljs@^0.3.0: version "0.3.2" - resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.3.2.tgz#d19f98cf7c6a7660c2ecbbeaa696db3436227713" + resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.3.2.tgz#d19f98cf7c6a7660c2ecbbeaa696db3436227713" dependencies: rsvp "~3.2.1" hoek@0.9.x: version "0.9.1" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" + resolved "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" hoek@2.x.x: version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + resolved "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" home-or-tmp@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" + resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" dependencies: os-tmpdir "^1.0.1" user-home "^1.1.1" homedir-polyfill@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" dependencies: parse-passwd "^1.0.0" -hosted-git-info@^2.1.4, hosted-git-info@^2.1.5, hosted-git-info@~2.1.5: +hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: + version "2.2.0" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.2.0.tgz#7a0d097863d886c0fabbdcd37bf1758d8becf8a5" + +hosted-git-info@~2.1.5: version "2.1.5" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" -http-errors@~1.5.0: +http-errors@~1.5.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" dependencies: inherits "2.0.3" setprototypeof "1.0.2" @@ -3132,14 +3102,14 @@ http-errors@~1.5.0: http-proxy@^1.13.1, http-proxy@^1.9.0: version "1.16.2" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" + resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" dependencies: eventemitter3 "1.x.x" requires-port "1.x.x" http-signature@~0.10.0: version "0.10.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" dependencies: asn1 "0.1.11" assert-plus "^0.1.5" @@ -3147,66 +3117,66 @@ http-signature@~0.10.0: http-signature@~1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" dependencies: assert-plus "^0.2.0" jsprim "^1.2.2" sshpk "^1.7.0" -iconv-lite@0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13: - version "0.4.13" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" +iconv-lite@0.4.15, iconv-lite@^0.4.5, iconv-lite@~0.4.13: + version "0.4.15" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" iconv-lite@~0.2.10: version "0.2.11" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8" ieee754@^1.1.4: version "1.1.8" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" iferr@^0.1.5, iferr@~0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + resolved "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" ignore@^3.1.2: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" + version "3.2.4" + resolved "https://registry.npmjs.org/ignore/-/ignore-3.2.4.tgz#4055e03596729a8fabe45a43c100ad5ed815c4e8" -imurmurhash@^0.1.4: +imurmurhash@*, imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" indexof@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" inflected@^1.1.6: version "1.1.7" - resolved "https://registry.yarnpkg.com/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" + resolved "https://registry.npmjs.org/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" inflection@^1.7.0, inflection@^1.7.1, inflection@^1.8.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.10.0.tgz#5bffcb1197ad3e81050f8e17e21668087ee9eb2f" + version "1.12.0" + resolved "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" inflight@^1.0.4, inflight@~1.0.5: version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" dependencies: once "^1.3.0" wrappy "1" inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" ini@^1.3.4, ini@~1.3.4: version "1.3.4" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" init-package-json@~1.9.4: version "1.9.4" - resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-1.9.4.tgz#b4053d0b40f0cf842a41966937cb3dc0f534e856" + resolved "https://registry.npmjs.org/init-package-json/-/init-package-json-1.9.4.tgz#b4053d0b40f0cf842a41966937cb3dc0f534e856" dependencies: glob "^6.0.0" npm-package-arg "^4.0.0" @@ -3217,19 +3187,9 @@ init-package-json@~1.9.4: validate-npm-package-license "^3.0.1" validate-npm-package-name "^2.0.1" -inline-source-map-comment@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" - dependencies: - chalk "^1.0.0" - get-stdin "^4.0.1" - minimist "^1.1.1" - sum-up "^1.0.1" - xtend "^4.0.0" - inquirer@^0.12.0: version "0.12.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" dependencies: ansi-escapes "^1.1.0" ansi-regex "^2.0.0" @@ -3266,79 +3226,79 @@ inquirer@^1.2.3: invert-kv@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" -ipaddr.js@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.1.1.tgz#c791d95f52b29c1247d5df80ada39b8a73647230" +ipaddr.js@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.2.0.tgz#8aba49c9192799585bdd643e0ccb50e8ae777ba4" is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" is-buffer@^1.0.2: version "1.1.4" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" is-builtin-module@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" dependencies: builtin-modules "^1.0.0" is-dotfile@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + resolved "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" is-equal-shallow@^0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + resolved "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" dependencies: is-primitive "^2.0.0" is-extendable@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" is-extglob@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" is-finite@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + resolved "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" is-git-url@0.2.0, is-git-url@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-0.2.0.tgz#b9ce0fb044821c88880213d602db03bdb255da1b" + resolved "https://registry.npmjs.org/is-git-url/-/is-git-url-0.2.0.tgz#b9ce0fb044821c88880213d602db03bdb255da1b" is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" dependencies: is-extglob "^1.0.0" is-integer@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/is-integer/-/is-integer-1.0.6.tgz#5273819fada880d123e1ac00a938e7172dd8d95e" + resolved "https://registry.npmjs.org/is-integer/-/is-integer-1.0.6.tgz#5273819fada880d123e1ac00a938e7172dd8d95e" dependencies: is-finite "^1.0.0" is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: version "2.15.0" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" + resolved "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" dependencies: generate-function "^2.0.0" generate-object-property "^1.1.0" @@ -3347,103 +3307,103 @@ is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: is-number@^2.0.2, is-number@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + resolved "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" dependencies: kind-of "^3.0.2" is-obj@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" is-path-cwd@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" is-path-in-cwd@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + resolved "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" dependencies: is-path-inside "^1.0.0" is-path-inside@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" dependencies: path-is-inside "^1.0.1" is-posix-bracket@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + resolved "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" is-primitive@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + resolved "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" is-promise@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" is-property@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + resolved "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" is-resolvable@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" dependencies: tryit "^1.0.1" is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" is-type@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" + resolved "https://registry.npmjs.org/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" dependencies: core-util-is "~1.0.0" is-typedarray@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" is-utf8@^0.2.0: version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" is-windows@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" + resolved "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" isarray@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" isbinaryfile@^3.0.0: version "3.0.2" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" + resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" isexe@^1.1.1: version "1.1.2" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" + resolved "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" isobject@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" dependencies: isarray "1.0.0" isstream@~0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" istextorbinary@2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" + resolved "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" dependencies: binaryextensions "1 || 2" editions "^1.1.1" @@ -3451,22 +3411,22 @@ istextorbinary@2.1.0: jade@0.26.3: version "0.26.3" - resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" + resolved "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" dependencies: commander "0.6.1" mkdirp "0.3.0" jju@^1.1.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/jju/-/jju-1.3.0.tgz#dadd9ef01924bc728b03f2f7979bdbd62f7a2aaa" + resolved "https://registry.npmjs.org/jju/-/jju-1.3.0.tgz#dadd9ef01924bc728b03f2f7979bdbd62f7a2aaa" jmespath@0.15.0: version "0.15.0" - resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" jodid25519@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + resolved "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" dependencies: jsbn "~0.1.0" @@ -3476,30 +3436,30 @@ jquery@^3.1.1: js-string-escape@^1.0.0, js-string-escape@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" + resolved "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" js-tokens@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: - version "3.7.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" + version "3.8.1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.1.tgz#782ba50200be7b9e5a8537001b7804db3ad02628" dependencies: argparse "^1.0.7" - esprima "^2.6.0" + esprima "^3.1.1" jsbn@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" + version "0.1.1" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" jsesc@~0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" json-api-mock-server@0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/json-api-mock-server/-/json-api-mock-server-0.1.1.tgz#00acb22ac58127e87fa9a172159cd8ed558e8106" + resolved "https://registry.npmjs.org/json-api-mock-server/-/json-api-mock-server-0.1.1.tgz#00acb22ac58127e87fa9a172159cd8ed558e8106" dependencies: body-parser "^1.15.2" chalk "^1.1.1" @@ -3510,56 +3470,56 @@ json-api-mock-server@0.1.1: json-parse-helpfulerror@^1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz#13f14ce02eed4e981297b64eb9e3b932e2dd13dc" + resolved "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz#13f14ce02eed4e981297b64eb9e3b932e2dd13dc" dependencies: jju "^1.1.0" json-schema@0.2.3: version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: jsonify "~0.0.0" json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" json3@3.3.2: version "3.3.2" - resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + resolved "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" json5@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" + resolved "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" jsonapi-validator@^2.1.1: version "2.2.0" - resolved "https://registry.yarnpkg.com/jsonapi-validator/-/jsonapi-validator-2.2.0.tgz#07f9bdb6d118c1e728fa77280605fa9b527f8c66" + resolved "https://registry.npmjs.org/jsonapi-validator/-/jsonapi-validator-2.2.0.tgz#07f9bdb6d118c1e728fa77280605fa9b527f8c66" dependencies: ajv "^4.1.3" yargs "^5.0.0" jsonfile@^2.1.0: version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" optionalDependencies: graceful-fs "^4.1.6" jsonify@~0.0.0: version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" jsonpointer@^4.0.0: version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" jsprim@^1.2.2: version "1.3.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" dependencies: extsprintf "1.0.2" json-schema "0.2.3" @@ -3567,31 +3527,31 @@ jsprim@^1.2.2: kew@~0.7.0: version "0.7.0" - resolved "https://registry.yarnpkg.com/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" + resolved "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" kind-of@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" dependencies: is-buffer "^1.0.2" klassy@^0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/klassy/-/klassy-0.1.3.tgz#c31d5756d583197d75f582b6e692872be497067f" + resolved "https://registry.npmjs.org/klassy/-/klassy-0.1.3.tgz#c31d5756d583197d75f582b6e692872be497067f" klaw@^1.0.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + resolved "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" optionalDependencies: graceful-fs "^4.1.9" lazy-cache@^1.0.3: version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" lcid@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + resolved "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" dependencies: invert-kv "^1.0.0" @@ -3605,34 +3565,34 @@ leek@0.0.24: leven@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" + resolved "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" levn@^0.3.0, levn@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" linkify-it@^2.0.0: version "2.0.3" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" dependencies: uc.micro "^1.0.1" linkify-it@~1.2.0: version "1.2.4" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" dependencies: uc.micro "^1.0.1" livereload-js@^2.2.2: version "2.2.2" - resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" + resolved "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" load-json-file@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -3646,95 +3606,98 @@ loader.js@^4.0.10: lockfile@~1.0.1: version "1.0.3" - resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.3.tgz#2638fc39a0331e9cac1a04b71799931c9c50df79" + resolved "https://registry.npmjs.org/lockfile/-/lockfile-1.0.3.tgz#2638fc39a0331e9cac1a04b71799931c9c50df79" lodash-node@^3.2.0: version "3.10.2" - resolved "https://registry.yarnpkg.com/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" + resolved "https://registry.npmjs.org/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" lodash._arraycopy@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" + resolved "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" lodash._arrayeach@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" + resolved "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" lodash._baseassign@^3.0.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + resolved "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" dependencies: lodash._basecopy "^3.0.0" lodash.keys "^3.0.0" -lodash._baseclone@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz#303519bf6393fe7e42f34d8b630ef7794e3542b7" - dependencies: - lodash._arraycopy "^3.0.0" - lodash._arrayeach "^3.0.0" - lodash._baseassign "^3.0.0" - lodash._basefor "^3.0.0" - lodash.isarray "^3.0.0" - lodash.keys "^3.0.0" - lodash._basecopy@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + resolved "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" lodash._baseflatten@^3.0.0: version "3.1.4" - resolved "https://registry.yarnpkg.com/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" + resolved "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" dependencies: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" lodash._basefor@^3.0.0: version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" + resolved "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" + +lodash._baseindexof@*: + version "3.1.0" + resolved "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" lodash._baseuniq@~4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" + resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" dependencies: lodash._createset "~4.0.0" lodash._root "~3.0.0" -lodash._bindcallback@^3.0.0: +lodash._bindcallback@*, lodash._bindcallback@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + +lodash._cacheindexof@*: + version "3.0.2" + resolved "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" lodash._createassigner@^3.0.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + resolved "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" dependencies: lodash._bindcallback "^3.0.0" lodash._isiterateecall "^3.0.0" lodash.restparam "^3.0.0" +lodash._createcache@*: + version "3.1.2" + resolved "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" + dependencies: + lodash._getnative "^3.0.0" + lodash._createset@~4.0.0: version "4.0.3" - resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" + resolved "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" -lodash._getnative@^3.0.0: +lodash._getnative@*, lodash._getnative@^3.0.0: version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" lodash._isiterateecall@^3.0.0: version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + resolved "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" lodash._reinterpolate@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" lodash._root@~3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + resolved "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" lodash.assign@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" dependencies: lodash._baseassign "^3.0.0" lodash._createassigner "^3.0.0" @@ -3742,51 +3705,44 @@ lodash.assign@^3.2.0: lodash.assign@^4.1.0, lodash.assign@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" lodash.assignin@^4.1.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" - -lodash.clonedeep@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz#a0a1e40d82a5ea89ff5b147b8444ed63d92827db" - dependencies: - lodash._baseclone "^3.0.0" - lodash._bindcallback "^3.0.0" + resolved "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" lodash.clonedeep@^4.4.1, lodash.clonedeep@~4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" lodash.debounce@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" + resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" dependencies: lodash._getnative "^3.0.0" lodash.find@^4.5.1: version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" + resolved "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" lodash.flatten@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" + resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" dependencies: lodash._baseflatten "^3.0.0" lodash._isiterateecall "^3.0.0" lodash.isarguments@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" lodash.isarray@^3.0.0: version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" lodash.isplainobject@^3.0.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" + resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" dependencies: lodash._basefor "^3.0.0" lodash.isarguments "^3.0.0" @@ -3794,11 +3750,11 @@ lodash.isplainobject@^3.0.0: lodash.istypedarray@^3.0.0: version "3.0.6" - resolved "https://registry.yarnpkg.com/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" + resolved "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" lodash.keys@^3.0.0: version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" dependencies: lodash._getnative "^3.0.0" lodash.isarguments "^3.0.0" @@ -3806,14 +3762,14 @@ lodash.keys@^3.0.0: lodash.keysin@^3.0.0: version "3.0.8" - resolved "https://registry.yarnpkg.com/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" + resolved "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" dependencies: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" lodash.merge@^3.3.2: version "3.3.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-3.3.2.tgz#0d90d93ed637b1878437bb3e21601260d7afe994" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz#0d90d93ed637b1878437bb3e21601260d7afe994" dependencies: lodash._arraycopy "^3.0.0" lodash._arrayeach "^3.0.0" @@ -3829,92 +3785,92 @@ lodash.merge@^3.3.2: lodash.merge@^4.3.0, lodash.merge@^4.4.0, lodash.merge@^4.5.1: version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" lodash.omit@^4.1.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" + resolved "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" -lodash.restparam@^3.0.0: +lodash.restparam@*, lodash.restparam@^3.0.0: version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" lodash.template@^4.2.5: version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" + resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings "^4.0.0" lodash.templatesettings@^4.0.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" + resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" dependencies: lodash._reinterpolate "~3.0.0" lodash.toplainobject@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz#28790ad942d293d78aa663a07ecf7f52ca04198d" + resolved "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz#28790ad942d293d78aa663a07ecf7f52ca04198d" dependencies: lodash._basecopy "^3.0.0" lodash.keysin "^3.0.0" lodash.union@~4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" lodash.uniq@^4.2.0, lodash.uniq@~4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" lodash.without@~4.4.0: version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" + resolved "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.1: +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.3.0, lodash@^4.6.1: version "4.17.4" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" lodash@~1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.2.1.tgz#ed47b16e46f06b2b40309b68e9163c17e93ea304" + resolved "https://registry.npmjs.org/lodash/-/lodash-1.2.1.tgz#ed47b16e46f06b2b40309b68e9163c17e93ea304" lodash@~3.5.0: version "3.5.0" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.5.0.tgz#19bb3f4d51278f0b8c818ed145c74ecf9fe40e6d" + resolved "https://registry.npmjs.org/lodash/-/lodash-3.5.0.tgz#19bb3f4d51278f0b8c818ed145c74ecf9fe40e6d" longest@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" lru-cache@2: version "2.7.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" lru-cache@^4.0.0, lru-cache@^4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" dependencies: pseudomap "^1.0.1" yallist "^2.0.0" make-array@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" + resolved "https://registry.npmjs.org/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" makeerror@1.0.x: version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" dependencies: tmpl "1.0.x" markdown-it-terminal@0.0.4: version "0.0.4" - resolved "https://registry.yarnpkg.com/markdown-it-terminal/-/markdown-it-terminal-0.0.4.tgz#3f2ce624ba2ca964a78b8b388d605ee330de9ced" + resolved "https://registry.npmjs.org/markdown-it-terminal/-/markdown-it-terminal-0.0.4.tgz#3f2ce624ba2ca964a78b8b388d605ee330de9ced" dependencies: ansi-styles "^2.1.0" cardinal "^0.5.0" @@ -3934,7 +3890,7 @@ markdown-it@8.1.0: markdown-it@^4.3.0, markdown-it@^4.4.0: version "4.4.0" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" dependencies: argparse "~1.0.2" entities "~1.1.1" @@ -3942,69 +3898,55 @@ markdown-it@^4.3.0, markdown-it@^4.4.0: mdurl "~1.0.0" uc.micro "^1.0.0" -marked-terminal@^1.6.2: - version "1.7.0" - resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-1.7.0.tgz#c8c460881c772c7604b64367007ee5f77f125904" - dependencies: - cardinal "^1.0.0" - chalk "^1.1.3" - cli-table "^0.3.1" - lodash.assign "^4.2.0" - node-emoji "^1.4.1" - -marked@^0.3.6: - version "0.3.6" - resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7" - matcher-collection@^1.0.0, matcher-collection@^1.0.1: version "1.0.4" - resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-1.0.4.tgz#2f66ae0869996f29e43d0b62c83dd1d43e581755" + resolved "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.4.tgz#2f66ae0869996f29e43d0b62c83dd1d43e581755" dependencies: minimatch "^3.0.2" md5-hex@^1.0.2, md5-hex@^1.2.1: version "1.3.0" - resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" + resolved "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" dependencies: md5-o-matic "^0.1.1" md5-o-matic@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" + resolved "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" mdn-links@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" + resolved "https://registry.npmjs.org/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" mdurl@^1.0.1, mdurl@~1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + resolved "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" media-typer@0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" memory-streams@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.0.tgz#bec658a71e3f28b0f0c2f1b14501c2db547d5f7a" + version "0.1.1" + resolved "https://registry.npmjs.org/memory-streams/-/memory-streams-0.1.1.tgz#ed561f0ba1f649396459c76683819fa1a97d488d" dependencies: readable-stream "~1.0.2" merge-descriptors@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" merge@^1.1.3, merge@^1.2.0, merge@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + resolved "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" methods@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" micromatch@^2.1.5, micromatch@^2.3.7: version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" dependencies: arr-diff "^2.0.0" array-unique "^0.2.1" @@ -4020,89 +3962,89 @@ micromatch@^2.1.5, micromatch@^2.3.7: parse-glob "^3.0.4" regex-cache "^0.4.2" -"mime-db@>= 1.24.0 < 2", mime-db@~1.25.0: - version "1.25.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392" +"mime-db@>= 1.24.0 < 2", mime-db@~1.26.0: + version "1.26.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: - version "2.1.13" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88" + version "2.1.14" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" dependencies: - mime-db "~1.25.0" + mime-db "~1.26.0" mime-types@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" mime@1.3.4, mime@^1.2.11: version "1.3.4" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + resolved "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" mime@~1.2.11: version "1.2.11" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + resolved "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2: +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" dependencies: brace-expansion "^1.0.0" minimatch@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-1.0.0.tgz#e0dd2120b49e1b724ce8d714c520822a9438576d" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz#e0dd2120b49e1b724ce8d714c520822a9438576d" dependencies: lru-cache "2" sigmund "~1.0.0" minimatch@^2.0.1, minimatch@^2.0.3, minimatch@^2.0.8: version "2.0.10" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" dependencies: brace-expansion "^1.0.0" minimatch@~0.2.11: version "0.2.14" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" dependencies: lru-cache "2" sigmund "~1.0.0" minimist@0.0.8, minimist@~0.0.1: version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" minimist@^1.1.0, minimist@^1.1.1: version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" mkdirp@0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" mkdirp@0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" dependencies: minimist "0.0.8" mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" mkdirp@~0.3.5: version "0.3.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" mktemp@^0.4.0, mktemp@~0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" + resolved "https://registry.npmjs.org/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" mocha-only-detector@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/mocha-only-detector/-/mocha-only-detector-0.0.2.tgz#00f7dde6f949cf68a3cc92bdacff997b87e4b1d1" + resolved "https://registry.npmjs.org/mocha-only-detector/-/mocha-only-detector-0.0.2.tgz#00f7dde6f949cf68a3cc92bdacff997b87e4b1d1" dependencies: esprima "^1.2.2" esprimaq "^0.0.1" @@ -4110,7 +4052,7 @@ mocha-only-detector@0.0.2: mocha@2.4.5: version "2.4.5" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.4.5.tgz#151768dd2875eb51bc8295e9800026e9f2bb398f" + resolved "https://registry.npmjs.org/mocha/-/mocha-2.4.5.tgz#151768dd2875eb51bc8295e9800026e9f2bb398f" dependencies: commander "2.3.0" debug "2.2.0" @@ -4124,72 +4066,66 @@ mocha@2.4.5: moment-timezone@^0.3.0: version "0.3.1" - resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" + resolved "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" dependencies: moment ">= 2.6.0" "moment@>= 2.6.0": version "2.17.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" + resolved "https://registry.npmjs.org/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" morgan@^1.5.2, morgan@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.7.0.tgz#eb10ca8e50d1abe0f8d3dad5c0201d052d981c62" + version "1.8.1" + resolved "https://registry.npmjs.org/morgan/-/morgan-1.8.1.tgz#f93023d3887bd27b78dfd6023cea7892ee27a4b1" dependencies: - basic-auth "~1.0.3" - debug "~2.2.0" + basic-auth "~1.1.0" + debug "2.6.1" depd "~1.1.0" on-finished "~2.3.0" on-headers "~1.0.1" mout@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/mout/-/mout-1.0.0.tgz#9bdf1d4af57d66d47cb353a6335a3281098e1501" + resolved "https://registry.npmjs.org/mout/-/mout-1.0.0.tgz#9bdf1d4af57d66d47cb353a6335a3281098e1501" ms@0.7.1: version "0.7.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + resolved "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" ms@0.7.2: version "0.7.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + resolved "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" mustache@^2.2.1: version "2.3.0" - resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" + resolved "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" -mute-stream@0.0.5, mute-stream@~0.0.4: +mute-stream@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" -mute-stream@0.0.6: +mute-stream@0.0.6, mute-stream@~0.0.4: version "0.0.6" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" natives@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31" + resolved "https://registry.npmjs.org/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31" negotiator@0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" - -node-emoji@^1.4.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.5.0.tgz#9a0d9fe03fd43afa357d6d8e439aa31e599959b7" - dependencies: - string.prototype.codepointat "^0.2.0" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" node-fetch@^1.3.3: version "1.6.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" dependencies: encoding "^0.1.11" is-stream "^1.0.1" node-gyp@~3.4.0: version "3.4.0" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.4.0.tgz#dda558393b3ecbbe24c9e6b8703c71194c63fa36" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-3.4.0.tgz#dda558393b3ecbbe24c9e6b8703c71194c63fa36" dependencies: fstream "^1.0.0" glob "^7.0.3" @@ -4208,41 +4144,38 @@ node-gyp@~3.4.0: node-int64@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" node-modules-path@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" + resolved "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" -node-notifier@^4.3.1: - version "4.6.1" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-4.6.1.tgz#056d14244f3dcc1ceadfe68af9cff0c5473a33f3" +node-notifier@^5.0.1: + version "5.0.2" + resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-5.0.2.tgz#4438449fe69e321f941cef943986b0797032701b" dependencies: - cli-usage "^0.1.1" - growly "^1.2.0" - lodash.clonedeep "^3.0.0" - minimist "^1.1.1" - semver "^5.1.0" + growly "^1.3.0" + semver "^5.3.0" shellwords "^0.1.0" - which "^1.0.5" + which "^1.2.12" node-uuid@~1.4.0, node-uuid@~1.4.7: version "1.4.7" - resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" + resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" "nopt@2 || 3", nopt@^3.0.1, nopt@^3.0.3, nopt@~3.0.6: version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: abbrev "1" normalize-git-url@~3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/normalize-git-url/-/normalize-git-url-3.0.2.tgz#8e5f14be0bdaedb73e07200310aa416c27350fc4" + resolved "https://registry.npmjs.org/normalize-git-url/-/normalize-git-url-3.0.2.tgz#8e5f14be0bdaedb73e07200310aa416c27350fc4" normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, "normalize-package-data@~1.0.1 || ^2.0.0", normalize-package-data@~2.3.5: version "2.3.5" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -4251,32 +4184,32 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, "normalize-package normalize-path@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" npm-cache-filename@~1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" + resolved "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" npm-git-info@^1.0.0: version "1.0.3" - resolved "https://registry.yarnpkg.com/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" + resolved "https://registry.npmjs.org/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" npm-install-checks@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-3.0.0.tgz#d4aecdfd51a53e3723b7b2f93b2ee28e307bc0d7" + resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-3.0.0.tgz#d4aecdfd51a53e3723b7b2f93b2ee28e307bc0d7" dependencies: semver "^2.3.0 || 3.x || 4 || 5" "npm-package-arg@^3.0.0 || ^4.0.0", npm-package-arg@^4.0.0, npm-package-arg@^4.1.1, npm-package-arg@~4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-4.2.0.tgz#809bc61cabf54bd5ff94f6165c89ba8ee88c115c" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.2.0.tgz#809bc61cabf54bd5ff94f6165c89ba8ee88c115c" dependencies: hosted-git-info "^2.1.5" semver "^5.1.0" npm-registry-client@~7.2.1: version "7.2.1" - resolved "https://registry.yarnpkg.com/npm-registry-client/-/npm-registry-client-7.2.1.tgz#c792266b088cc313f8525e7e35248626c723db75" + resolved "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-7.2.1.tgz#c792266b088cc313f8525e7e35248626c723db75" dependencies: concat-stream "^1.5.2" graceful-fs "^4.1.6" @@ -4298,11 +4231,11 @@ npm-run-path@^1.0.0: npm-user-validate@~0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-0.1.5.tgz#52465d50c2d20294a57125b996baedbf56c5004b" + resolved "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-0.1.5.tgz#52465d50c2d20294a57125b996baedbf56c5004b" npm@3.10.8: version "3.10.8" - resolved "https://registry.yarnpkg.com/npm/-/npm-3.10.8.tgz#8f76ff8c6da04b61dd371d554ce40a0b8916c15e" + resolved "https://registry.npmjs.org/npm/-/npm-3.10.8.tgz#8f76ff8c6da04b61dd371d554ce40a0b8916c15e" dependencies: abbrev "~1.0.9" ansicolors "~0.3.2" @@ -4378,7 +4311,7 @@ npm@3.10.8: "npmlog@0 || 1 || 2 || 3", "npmlog@~2.0.0 || ~3.1.0": version "3.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-3.1.2.tgz#2d46fa874337af9498a2f12bb43d8d0be4a36873" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-3.1.2.tgz#2d46fa874337af9498a2f12bb43d8d0be4a36873" dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" @@ -4387,7 +4320,7 @@ npm@3.10.8: npmlog@^4.0.0, npmlog@~4.0.0: version "4.0.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" @@ -4396,65 +4329,69 @@ npmlog@^4.0.0, npmlog@~4.0.0: number-is-nan@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" oauth-sign@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" oauth-sign@~0.8.1: version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@4.1.0, object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" object-component@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + resolved "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" object.omit@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + resolved "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" dependencies: for-own "^0.1.4" is-extendable "^0.1.1" on-finished@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" dependencies: ee-first "1.1.1" on-headers@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" once@^1.3.0, once@^1.3.3, once@~1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" onetime@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + resolved "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" opener@~1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.2.tgz#b32582080042af8680c389a499175b4c54fff523" + version "1.4.3" + resolved "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" optimist@^0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + resolved "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" dependencies: minimist "~0.0.1" wordwrap "~0.0.2" optionator@^0.8.1: version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: deep-is "~0.1.3" fast-levenshtein "~2.0.4" @@ -4465,11 +4402,11 @@ optionator@^0.8.1: options@>=0.0.5: version "0.0.6" - resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" + resolved "https://registry.npmjs.org/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" ora@^0.2.0: version "0.2.3" - resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" + resolved "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" dependencies: chalk "^1.1.1" cli-cursor "^1.0.2" @@ -4478,32 +4415,32 @@ ora@^0.2.0: os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" os-locale@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + resolved "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" dependencies: lcid "^1.0.0" os-shim@^0.1.2: version "0.1.3" - resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + resolved "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" osenv@0, osenv@^0.1.0, osenv@^0.1.3, osenv@~0.1.3: version "0.1.4" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" output-file-sync@^1.1.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + resolved "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" dependencies: graceful-fs "^4.1.4" mkdirp "^0.5.1" @@ -4511,7 +4448,7 @@ output-file-sync@^1.1.0: parse-glob@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + resolved "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" dependencies: glob-base "^0.3.0" is-dotfile "^1.0.0" @@ -4520,59 +4457,59 @@ parse-glob@^3.0.4: parse-json@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" dependencies: error-ex "^1.2.0" parse-passwd@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" parsejson@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" + resolved "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" dependencies: better-assert "~1.0.0" parseqs@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + resolved "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" dependencies: better-assert "~1.0.0" parseuri@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + resolved "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" dependencies: better-assert "~1.0.0" parseurl@~1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" path-array@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271" + resolved "https://registry.npmjs.org/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271" dependencies: array-index "^1.0.0" path-exists@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" path-exists@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" dependencies: pinkie-promise "^2.0.0" path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" path-is-inside@^1.0.1, path-is-inside@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" path-key@^1.0.0: version "1.0.0" @@ -4580,15 +4517,15 @@ path-key@^1.0.0: path-posix@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + resolved "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" path-to-regexp@0.1.7: version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" path-type@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" dependencies: graceful-fs "^4.1.2" pify "^2.0.0" @@ -4596,11 +4533,11 @@ path-type@^1.0.0: pend@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" phantomjs-prebuilt@^2.1.12: version "2.1.14" - resolved "https://registry.yarnpkg.com/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz#d53d311fcfb7d1d08ddb24014558f1188c516da0" + resolved "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz#d53d311fcfb7d1d08ddb24014558f1188c516da0" dependencies: es6-promise "~4.0.3" extract-zip "~1.5.0" @@ -4614,29 +4551,29 @@ phantomjs-prebuilt@^2.1.12: pify@^2.0.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" pinkie-promise@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" plain-text-box-plot@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/plain-text-box-plot/-/plain-text-box-plot-0.0.1.tgz#d3b2e53071ea6706972318565761242f779c04b8" + resolved "https://registry.npmjs.org/plain-text-box-plot/-/plain-text-box-plot-0.0.1.tgz#d3b2e53071ea6706972318565761242f779c04b8" pluralize@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + resolved "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" portfinder@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.10.tgz#7a4de9d98553c315da6f1e1ed05138eeb2d16bb8" + version "1.0.13" + resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" dependencies: async "^1.5.2" debug "^2.2.0" @@ -4644,15 +4581,15 @@ portfinder@^1.0.7: prelude-ls@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" preserve@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + resolved "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" pretender@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.0.0.tgz#9137c38718b4d89814478b7f208f70d3e441a0e9" + resolved "https://registry.npmjs.org/pretender/-/pretender-1.0.0.tgz#9137c38718b4d89814478b7f208f70d3e441a0e9" dependencies: fake-xml-http-request "^1.3.0" route-recognizer "^0.1.9" @@ -4666,84 +4603,88 @@ pretender@^1.4.2: printf@^0.2.3: version "0.2.5" - resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" + resolved "https://registry.npmjs.org/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" private@^0.1.6, private@~0.1.5: - version "0.1.6" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1" + version "0.1.7" + resolved "https://registry.npmjs.org/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" process-nextick-args@~1.0.6: version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" process-relative-require@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" + resolved "https://registry.npmjs.org/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" dependencies: node-modules-path "^1.0.0" progress@^1.1.8, progress@~1.1.8: version "1.1.8" - resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + resolved "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" promise-map-series@^0.2.1: version "0.2.3" - resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" + resolved "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" dependencies: rsvp "^3.0.14" promzard@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" + resolved "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" dependencies: read "1" proto-list@~1.2.1: version "1.2.4" - resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" -proxy-addr@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.2.tgz#b4cc5f22610d9535824c123aef9d3cf73c40ba37" +proxy-addr@~1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.3.tgz#dc97502f5722e888467b3fa2297a7b1ff47df074" dependencies: forwarded "~0.1.0" - ipaddr.js "1.1.1" + ipaddr.js "1.2.0" pseudomap@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" punycode@1.3.2: version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" punycode@^1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" q@^1.1.2: version "1.4.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" + resolved "https://registry.npmjs.org/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" -qs@6.2.0, qs@~6.2.0: +qs@6.2.0: version "6.2.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" + resolved "https://registry.npmjs.org/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" + +qs@6.2.1, qs@~6.2.0: + version "6.2.1" + resolved "https://registry.npmjs.org/qs/-/qs-6.2.1.tgz#ce03c5ff0935bc1d9d69a9f14cbd18e568d67625" qs@^6.2.0, qs@~6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" + version "6.3.1" + resolved "https://registry.npmjs.org/qs/-/qs-6.3.1.tgz#918c0b3bcd36679772baf135b1acb4c1651ed79d" qs@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" + resolved "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" querystring@0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" quick-temp@0.1.6, quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5: version "0.1.6" - resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.6.tgz#a6242a15cba9f9cdbd341287b5c569e318eec307" + resolved "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.6.tgz#a6242a15cba9f9cdbd341287b5c569e318eec307" dependencies: mktemp "~0.4.0" rimraf "~2.2.6" @@ -4751,47 +4692,47 @@ quick-temp@0.1.6, quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick qunit-notifications@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/qunit-notifications/-/qunit-notifications-0.1.1.tgz#3001afc6a6a77dfbd962ccbcddde12dec5286c09" + resolved "https://registry.npmjs.org/qunit-notifications/-/qunit-notifications-0.1.1.tgz#3001afc6a6a77dfbd962ccbcddde12dec5286c09" qunitjs@^1.20.0: version "1.23.1" - resolved "https://registry.yarnpkg.com/qunitjs/-/qunitjs-1.23.1.tgz#1971cf97ac9be01a64d2315508d2e48e6fd4e719" + resolved "https://registry.npmjs.org/qunitjs/-/qunitjs-1.23.1.tgz#1971cf97ac9be01a64d2315508d2e48e6fd4e719" randomatic@^1.1.3: version "1.1.6" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + resolved "https://registry.npmjs.org/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" dependencies: is-number "^2.0.2" kind-of "^3.0.2" range-parser@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" raw-body@~1.1.0: version "1.1.7" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" dependencies: bytes "1" string_decoder "0.10" -raw-body@~2.1.7: - version "2.1.7" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" +raw-body@~2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" dependencies: bytes "2.4.0" - iconv-lite "0.4.13" + iconv-lite "0.4.15" unpipe "1.0.0" read-cmd-shim@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b" + resolved "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b" dependencies: graceful-fs "^4.1.2" read-installed@~4.0.3: version "4.0.3" - resolved "https://registry.yarnpkg.com/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" + resolved "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" dependencies: debuglog "^1.0.1" read-package-json "^2.0.0" @@ -4804,7 +4745,7 @@ read-installed@~4.0.3: "read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@~2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.0.4.tgz#61ed1b2256ea438d8008895090be84b8e799c853" + resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-2.0.4.tgz#61ed1b2256ea438d8008895090be84b8e799c853" dependencies: glob "^6.0.0" json-parse-helpfulerror "^1.0.2" @@ -4814,7 +4755,7 @@ read-installed@~4.0.3: read-package-tree@~5.1.5: version "5.1.5" - resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.1.5.tgz#ace7e6381c7684f970aaa98fc7c5d2b666addab6" + resolved "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.1.5.tgz#ace7e6381c7684f970aaa98fc7c5d2b666addab6" dependencies: debuglog "^1.0.1" dezalgo "^1.0.0" @@ -4824,14 +4765,14 @@ read-package-tree@~5.1.5: read-pkg-up@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" dependencies: find-up "^1.0.0" read-pkg "^1.0.0" read-pkg@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" @@ -4839,13 +4780,13 @@ read-pkg@^1.0.0: read@1, read@~1.0.1, read@~1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" + resolved "https://registry.npmjs.org/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@^2, readable-stream@^2.0.2, readable-stream@~2.1.5: +"readable-stream@1 || 2", readable-stream@^2, readable-stream@~2.1.5: version "2.1.5" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" dependencies: buffer-shims "^1.0.0" core-util-is "~1.0.0" @@ -4855,9 +4796,9 @@ read@1, read@~1.0.1, read@~1.0.7: string_decoder "~0.10.x" util-deprecate "~1.0.1" -"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" +"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.2.2: + version "2.2.3" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.3.tgz#9cf49463985df016c8ae8813097a9293a9b33729" dependencies: buffer-shims "^1.0.0" core-util-is "~1.0.0" @@ -4869,7 +4810,7 @@ read@1, read@~1.0.1, read@~1.0.7: readable-stream@~1.0.2: version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -4878,7 +4819,7 @@ readable-stream@~1.0.2: readable-stream@~2.0.0, readable-stream@~2.0.5: version "2.0.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -4887,9 +4828,9 @@ readable-stream@~2.0.0, readable-stream@~2.0.5: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readdir-scoped-modules@^1.0.0: +readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" + resolved "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" dependencies: debuglog "^1.0.1" dezalgo "^1.0.0" @@ -4898,7 +4839,7 @@ readdir-scoped-modules@^1.0.0: readline2@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + resolved "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -4906,14 +4847,14 @@ readline2@^1.0.1: realize-package-specifier@~3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/realize-package-specifier/-/realize-package-specifier-3.0.3.tgz#d0def882952b8de3f67eba5e91199661271f41f4" + resolved "https://registry.npmjs.org/realize-package-specifier/-/realize-package-specifier-3.0.3.tgz#d0def882952b8de3f67eba5e91199661271f41f4" dependencies: dezalgo "^1.0.1" npm-package-arg "^4.1.1" recast@0.10.33: version "0.10.33" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" + resolved "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" dependencies: ast-types "0.8.12" esprima-fb "~15001.1001.0-dev-harmony-fb" @@ -4922,7 +4863,7 @@ recast@0.10.33: recast@^0.10.10, recast@^0.10.29: version "0.10.43" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" + resolved "https://registry.npmjs.org/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" dependencies: ast-types "0.8.15" esprima-fb "~15001.1001.0-dev-harmony-fb" @@ -4930,33 +4871,27 @@ recast@^0.10.10, recast@^0.10.29: source-map "~0.5.0" recast@^0.11.17, recast@^0.11.3: - version "0.11.18" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.18.tgz#07af6257ca769868815209401d4d60eef1b5b947" + version "0.11.22" + resolved "https://registry.npmjs.org/recast/-/recast-0.11.22.tgz#dedeb18fb001a2bbc6ac34475fda53dfe3d47dfa" dependencies: - ast-types "0.9.2" + ast-types "0.9.5" esprima "~3.1.0" private "~0.1.5" source-map "~0.5.0" redeyed@~0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-0.5.0.tgz#7ab000e60ee3875ac115d29edb32c1403c6c25d1" + resolved "https://registry.npmjs.org/redeyed/-/redeyed-0.5.0.tgz#7ab000e60ee3875ac115d29edb32c1403c6c25d1" dependencies: esprima-fb "~12001.1.0-dev-harmony-fb" -redeyed@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" - dependencies: - esprima "~3.0.0" - regenerate@^1.2.1: version "1.3.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" regenerator@0.8.40: version "0.8.40" - resolved "https://registry.yarnpkg.com/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" + resolved "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" dependencies: commoner "~0.10.3" defs "~1.1.0" @@ -4967,14 +4902,14 @@ regenerator@0.8.40: regex-cache@^0.4.2: version "0.4.3" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + resolved "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" dependencies: is-equal-shallow "^0.1.3" is-primitive "^2.0.0" regexpu@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" + resolved "https://registry.npmjs.org/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" dependencies: esprima "^2.6.0" recast "^0.10.10" @@ -4984,37 +4919,37 @@ regexpu@^1.3.0: regjsgen@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" regjsparser@^0.1.4: version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" dependencies: jsesc "~0.5.0" repeat-element@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" repeat-string@^1.5.2: version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" repeating@^1.1.0, repeating@^1.1.2: version "1.1.3" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" + resolved "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" dependencies: is-finite "^1.0.0" request-progress@~2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" + resolved "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" dependencies: throttleit "^1.0.0" request@2, request@^2.74.0, request@~2.79.0: version "2.79.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + resolved "https://registry.npmjs.org/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" dependencies: aws-sign2 "~0.6.0" aws4 "^1.2.1" @@ -5039,7 +4974,7 @@ request@2, request@^2.74.0, request@~2.79.0: request@~2.40.0: version "2.40.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" + resolved "https://registry.npmjs.org/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" dependencies: forever-agent "~0.5.0" json-stringify-safe "~5.0.0" @@ -5058,7 +4993,7 @@ request@~2.40.0: request@~2.74.0: version "2.74.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.74.0.tgz#7693ca768bbb0ea5c8ce08c084a45efa05b892ab" + resolved "https://registry.npmjs.org/request/-/request-2.74.0.tgz#7693ca768bbb0ea5c8ce08c084a45efa05b892ab" dependencies: aws-sign2 "~0.6.0" aws4 "^1.2.1" @@ -5084,128 +5019,134 @@ request@~2.74.0: require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" require-main-filename@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" require-uncached@^1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + resolved "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" dependencies: caller-path "^0.1.0" resolve-from "^1.0.0" requires-port@1.x.x: version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" resolve-dir@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" + resolved "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" dependencies: expand-tilde "^1.2.2" global-modules "^0.2.3" resolve-from@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c" restore-cursor@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" dependencies: exit-hook "^1.0.0" onetime "^1.0.0" retry@^0.10.0, retry@~0.10.0: version "0.10.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" + resolved "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" right-align@^0.1.1: version "0.1.3" - resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + resolved "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.3.2, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@~2.5.4: - version "2.5.4" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" +rimraf@2, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4: + version "2.6.0" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.0.tgz#89b8a0fe432b9ff9ec9a925a00b6cdb3a91bbada" dependencies: glob "^7.0.5" -rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.5.1: +rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3: version "2.5.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" rimraf@~2.1.4: version "2.1.4" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.1.4.tgz#5a6eb62eeda068f51ede50f29b3e5cd22f3d9bb2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.1.4.tgz#5a6eb62eeda068f51ede50f29b3e5cd22f3d9bb2" optionalDependencies: graceful-fs "~1" rimraf@~2.2.6: version "2.2.8" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + +rimraf@~2.5.4: + version "2.5.4" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + dependencies: + glob "^7.0.5" route-recognizer@^0.1.9: version "0.1.11" - resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" + resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" route-recognizer@^0.2.3: version "0.2.10" resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" -rsvp@3.2.1, rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@~3.2.1: +rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.6, rsvp@^3.2.1, rsvp@~3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" -rsvp@^3.0.21, rsvp@^3.3.3: +rsvp@^3.0.14, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3: version "3.3.3" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.3.3.tgz#34633caaf8bc66ceff4be3c2e1dffd032538a813" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.3.3.tgz#34633caaf8bc66ceff4be3c2e1dffd032538a813" rsvp@~3.0.6: version "3.0.21" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" rsvp@~3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" run-async@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + resolved "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" dependencies: once "^1.3.0" run-async@^2.2.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + resolved "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" dependencies: is-promise "^2.1.0" rx-lite@^3.1.2: version "3.1.2" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + resolved "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" rx@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + resolved "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" safe-json-parse@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" + resolved "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" sane@^1.1.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-1.5.0.tgz#a4adeae764d048621ecb27d5f9ecf513101939f3" + version "1.6.0" + resolved "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz#9610c452307a135d29c1fdfe2547034180c46775" dependencies: anymatch "^1.3.0" exec-sh "^0.2.0" @@ -5217,11 +5158,11 @@ sane@^1.1.1: sax@1.1.5, sax@>=0.6.0: version "1.1.5" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.5.tgz#1da50a8d00cdecd59405659f5ff85349fe773743" + resolved "https://registry.npmjs.org/sax/-/sax-1.1.5.tgz#1da50a8d00cdecd59405659f5ff85349fe773743" selenium-webdriver@^3.0.0-beta-2: - version "3.0.1" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz#a2dea5da4a97f6672e89e7ca7276cefa365147a7" + version "3.1.0" + resolved "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.1.0.tgz#d76182940cfb991edf4bc1c28318f4e7bc7730df" dependencies: adm-zip "^0.4.7" rimraf "^2.5.4" @@ -5230,15 +5171,15 @@ selenium-webdriver@^3.0.0-beta-2: "semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0, semver@~5.3.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + resolved "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" semver@^4.1.0, semver@^4.3.1: version "4.3.6" - resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + resolved "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" -send@0.14.1: - version "0.14.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.14.1.tgz#a954984325392f51532a7760760e459598c89f7a" +send@0.14.2: + version "0.14.2" + resolved "https://registry.npmjs.org/send/-/send-0.14.2.tgz#39b0438b3f510be5dc6f667a11f71689368cdeef" dependencies: debug "~2.2.0" depd "~1.1.0" @@ -5247,66 +5188,66 @@ send@0.14.1: escape-html "~1.0.3" etag "~1.7.0" fresh "0.3.0" - http-errors "~1.5.0" + http-errors "~1.5.1" mime "1.3.4" - ms "0.7.1" + ms "0.7.2" on-finished "~2.3.0" range-parser "~1.2.0" - statuses "~1.3.0" + statuses "~1.3.1" -serve-static@~1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.1.tgz#d6cce7693505f733c759de57befc1af76c0f0805" +serve-static@~1.11.2: + version "1.11.2" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.11.2.tgz#2cf9889bd4435a320cc36895c9aa57bd662e6ac7" dependencies: encodeurl "~1.0.1" escape-html "~1.0.3" parseurl "~1.3.1" - send "0.14.1" + send "0.14.2" set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" setprototypeof@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" sha@~2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae" + resolved "https://registry.npmjs.org/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae" dependencies: graceful-fs "^4.1.2" readable-stream "^2.0.2" shebang-command@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" shelljs@^0.6.0: version "0.6.1" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" + resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" shellwords@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14" + resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14" sigmund@~1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + resolved "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" signal-exit@^3.0.0: version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" silent-error@^1.0.0, silent-error@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/silent-error/-/silent-error-1.0.1.tgz#71b7d503d1c6f94882b51b56be879b113cb4822c" + resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.0.1.tgz#71b7d503d1c6f94882b51b56be879b113cb4822c" dependencies: debug "^2.2.0" @@ -5316,46 +5257,46 @@ simple-dom@^0.3.0: simple-fmt@~0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" + resolved "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" simple-is@~0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" + resolved "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" slash@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" slice-ansi@0.0.4: version "0.0.4" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" slide@^1.1.3, slide@^1.1.5, slide@~1.1.3, slide@~1.1.6: version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" sntp@0.2.x: version "0.2.4" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" + resolved "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" dependencies: hoek "0.9.x" sntp@1.x.x: version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + resolved "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" dependencies: hoek "2.x.x" socket.io-adapter@0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" + resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" dependencies: debug "2.3.3" socket.io-parser "2.3.1" socket.io-client@1.6.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" + resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" dependencies: backo2 "1.0.2" component-bind "1.0.0" @@ -5371,7 +5312,7 @@ socket.io-client@1.6.0: socket.io-parser@2.3.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" + resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" dependencies: component-emitter "1.1.2" debug "2.2.0" @@ -5380,7 +5321,7 @@ socket.io-parser@2.3.1: socket.io@1.6.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" + resolved "https://registry.npmjs.org/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" dependencies: debug "2.3.3" engine.io "1.8.0" @@ -5392,84 +5333,88 @@ socket.io@1.6.0: sort-object-keys@^1.1.1: version "1.1.2" - resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" + resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" sort-package-json@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.4.0.tgz#1a80e1770f32f8b23769699f2400cf053f27ef63" + version "1.5.0" + resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.5.0.tgz#d71ec7d13fc4d5f26bd87835676097fa6775206e" dependencies: sort-object-keys "^1.1.1" sorted-object@~2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/sorted-object/-/sorted-object-2.0.1.tgz#7d631f4bd3a798a24af1dffcfbfe83337a5df5fc" + resolved "https://registry.npmjs.org/sorted-object/-/sorted-object-2.0.1.tgz#7d631f4bd3a798a24af1dffcfbfe83337a5df5fc" source-map-support@^0.2.10: version "0.2.10" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" dependencies: source-map "0.1.32" +source-map-to-comment@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/source-map-to-comment/-/source-map-to-comment-1.1.0.tgz#e518c40bc7399b2e23c8e331a11635a97750e9c3" + source-map-url@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" + resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" source-map@0.1.32: version "0.1.32" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" dependencies: amdefine ">=0.0.4" -source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: +source-map@0.5.x, source-map@^0.5.0, source-map@~0.5.0, source-map@~0.5.1: + version "0.5.6" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +source-map@^0.4.2, source-map@^0.4.4: version "0.4.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: amdefine ">=0.0.4" -source-map@^0.5.0, source-map@~0.5.0, source-map@~0.5.1: - version "0.5.6" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" - spawn-args@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" + resolved "https://registry.npmjs.org/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" spawn-sync@^1.0.15: version "1.0.15" - resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + resolved "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" dependencies: concat-stream "^1.4.7" os-shim "^0.1.2" spawnback@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" + resolved "https://registry.npmjs.org/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" spdx-correct@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" dependencies: spdx-license-ids "^1.0.2" spdx-expression-parse@~1.0.0: version "1.0.4" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" spdx-license-ids@^1.0.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" sri-toolbox@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" + resolved "https://registry.npmjs.org/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" sshpk@^1.7.0: version "1.10.2" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.2.tgz#d5a804ce22695515638e798dbe23273de070a5fa" + resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.10.2.tgz#d5a804ce22695515638e798dbe23273de070a5fa" dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -5484,19 +5429,19 @@ sshpk@^1.7.0: stable@~0.1.3: version "0.1.5" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.5.tgz#08232f60c732e9890784b5bed0734f8b32a887b9" + resolved "https://registry.npmjs.org/stable/-/stable-0.1.5.tgz#08232f60c732e9890784b5bed0734f8b32a887b9" -"statuses@>= 1.3.1 < 2", statuses@~1.3.0: +"statuses@>= 1.3.1 < 2", statuses@~1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" string-template@~0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -5504,18 +5449,14 @@ string-width@^1.0.1, string-width@^1.0.2: string-width@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + resolved "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^3.0.0" -string.prototype.codepointat@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.0.tgz#6b26e9bd3afcaa7be3b4269b526de1b82000ac78" - string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" stringmap@~0.2.2: version "0.2.2" @@ -5523,27 +5464,27 @@ stringmap@~0.2.2: stringset@~0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" + resolved "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" stringstream@~0.0.4: version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + resolved "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" strip-ansi@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" dependencies: ansi-regex "^0.2.1" strip-ansi@^3.0.0, strip-ansi@^3.0.1, strip-ansi@~3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: ansi-regex "^2.0.0" strip-bom@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" dependencies: is-utf8 "^0.2.0" @@ -5553,41 +5494,35 @@ strip-eof@^1.0.0: strip-json-comments@~1.0.1: version "1.0.4" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" styled_string@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" - -sum-up@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" - dependencies: - chalk "^1.0.0" + resolved "https://registry.npmjs.org/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" supports-color@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" supports-color@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" supports-color@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: version "1.1.8" - resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" + resolved "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" sync-exec@^0.6.2: version "0.6.2" - resolved "https://registry.yarnpkg.com/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105" + resolved "https://registry.npmjs.org/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105" table@^3.7.8: version "3.8.3" - resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + resolved "https://registry.npmjs.org/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" dependencies: ajv "^4.7.0" ajv-keywords "^1.0.0" @@ -5596,9 +5531,9 @@ table@^3.7.8: slice-ansi "0.0.4" string-width "^2.0.0" -tap-parser@^3.0.2: - version "3.0.5" - resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-3.0.5.tgz#b947f69e0b3e53d4b92011f6cc552e16dadc7ec9" +tap-parser@^5.1.0: + version "5.3.3" + resolved "https://registry.npmjs.org/tap-parser/-/tap-parser-5.3.3.tgz#53ec8a90f275d6fff43f169e56a679502a741185" dependencies: events-to-array "^1.0.1" js-yaml "^3.2.7" @@ -5607,7 +5542,7 @@ tap-parser@^3.0.2: tar@^2.0.0, tar@~2.2.1: version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + resolved "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" dependencies: block-stream "*" fstream "^1.0.2" @@ -5615,14 +5550,14 @@ tar@^2.0.0, tar@~2.2.1: temp@0.8.3: version "0.8.3" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" + resolved "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" dependencies: os-tmpdir "^1.0.0" rimraf "~2.2.6" testem@^1.8.1: - version "1.14.2" - resolved "https://registry.yarnpkg.com/testem/-/testem-1.14.2.tgz#0c29f82e99cebf51c1a5808e57a922b9624075af" + version "1.15.0" + resolved "https://registry.npmjs.org/testem/-/testem-1.15.0.tgz#2e3a9e7ac29f16a20f718eb0c4b12e7a44900675" dependencies: backbone "^1.1.2" bluebird "^3.4.6" @@ -5640,35 +5575,35 @@ testem@^1.8.1: lodash.find "^4.5.1" mkdirp "^0.5.1" mustache "^2.2.1" - node-notifier "^4.3.1" + node-notifier "^5.0.1" npmlog "^4.0.0" printf "^0.2.3" rimraf "^2.4.4" socket.io "1.6.0" spawn-args "^0.2.0" styled_string "0.0.1" - tap-parser "^3.0.2" + tap-parser "^5.1.0" xmldom "^0.1.19" text-table@~0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" "textextensions@1 || 2": version "2.0.1" - resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.0.1.tgz#be8cf22d65379c151319f88f0335ad8f667abdca" + resolved "https://registry.npmjs.org/textextensions/-/textextensions-2.0.1.tgz#be8cf22d65379c151319f88f0335ad8f667abdca" throttleit@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" + resolved "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" through@^2.3.6, through@^2.3.8, through@~2.3.8: version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" tiny-lr@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.0.3.tgz#386731170ce521263a9d337f769ee8f11e88eb04" + resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.0.3.tgz#386731170ce521263a9d337f769ee8f11e88eb04" dependencies: body "^5.1.0" debug "~2.2.0" @@ -5679,50 +5614,50 @@ tiny-lr@^1.0.3: tmp-sync@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/tmp-sync/-/tmp-sync-1.1.0.tgz#2b38ec94b094ed2515ec02a9aee1f51dd2c9023f" + resolved "https://registry.npmjs.org/tmp-sync/-/tmp-sync-1.1.0.tgz#2b38ec94b094ed2515ec02a9aee1f51dd2c9023f" dependencies: fs-sync "^0.2.4" osenv "^0.1.0" tmp@0.0.28: version "0.0.28" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" dependencies: os-tmpdir "~1.0.1" tmp@0.0.30: version "0.0.30" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" dependencies: os-tmpdir "~1.0.1" tmp@^0.0.29: version "0.0.29" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" dependencies: os-tmpdir "~1.0.1" tmpl@1.0.x: version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" to-array@0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + resolved "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" to-fast-properties@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" tough-cookie@>=0.12.0, tough-cookie@~2.3.0: version "2.3.2" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" dependencies: punycode "^1.4.1" tree-sync@^1.1.4: version "1.2.2" - resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" + resolved "https://registry.npmjs.org/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" dependencies: debug "^2.2.0" fs-tree-diff "^0.5.6" @@ -5732,60 +5667,60 @@ tree-sync@^1.1.4: trim-right@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" try-resolve@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" + resolved "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" tryit@^1.0.1: version "1.0.3" - resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + resolved "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" tryor@~0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" + resolved "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" tunnel-agent@~0.4.0, tunnel-agent@~0.4.1: version "0.4.3" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" type-check@~0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" dependencies: prelude-ls "~1.1.2" type-detect@0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" type-detect@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" -type-is@~1.6.13: +type-is@~1.6.14: version "1.6.14" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" dependencies: media-typer "0.3.0" mime-types "~2.1.13" typedarray@^0.0.6, typedarray@~0.0.5: version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" + resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" uglify-js@^2.6, uglify-js@^2.7.0: version "2.7.5" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" + resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" dependencies: async "~0.2.6" source-map "~0.5.1" @@ -5794,204 +5729,212 @@ uglify-js@^2.6, uglify-js@^2.7.0: uglify-to-browserify@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + resolved "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" uid-number@0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" ultron@1.0.x: version "1.0.2" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" + resolved "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" umask@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" + resolved "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" underscore.string@~2.3.3: version "2.3.3" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" + resolved "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" underscore@>=1.8.3: version "1.8.3" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + resolved "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" unique-filename@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" + resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" dependencies: unique-slug "^2.0.0" unique-slug@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" dependencies: imurmurhash "^0.1.4" unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" untildify@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" + resolved "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" dependencies: os-homedir "^1.0.0" url@0.10.3: version "0.10.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + resolved "https://registry.npmjs.org/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" dependencies: punycode "1.3.2" querystring "0.2.0" user-home@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + resolved "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" user-home@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + resolved "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" dependencies: os-homedir "^1.0.0" util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" util-extend@^1.0.1: version "1.0.3" - resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" + resolved "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" utils-merge@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" -uuid@3.0.0, uuid@^3.0.0: +uuid@3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" uuid@^2.0.1: version "2.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" + resolved "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" + +uuid@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" -validate-npm-package-license@^3.0.1: +validate-npm-package-license@*, validate-npm-package-license@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" dependencies: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" validate-npm-package-name@^2.0.1, validate-npm-package-name@~2.2.2: version "2.2.2" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-2.2.2.tgz#f65695b22f7324442019a3c7fa39a6e7fd299085" + resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-2.2.2.tgz#f65695b22f7324442019a3c7fa39a6e7fd299085" dependencies: builtins "0.0.7" vary@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" verror@1.3.6: version "1.3.6" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + resolved "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" dependencies: extsprintf "1.0.2" walk-sync@^0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: version "0.2.7" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" walk-sync@^0.3.0, walk-sync@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.1.tgz#558a16aeac8c0db59c028b73c66f397684ece465" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.1.tgz#558a16aeac8c0db59c028b73c66f397684ece465" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" walker@~1.0.5: version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" dependencies: makeerror "1.0.x" watch@~0.10.0: version "0.10.0" - resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" + resolved "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" wcwidth@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" dependencies: defaults "^1.0.3" websocket-driver@>=0.5.1: version "0.6.5" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" + resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" dependencies: websocket-extensions ">=0.1.1" websocket-extensions@>=0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" + resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" which-module@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + resolved "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" -which@1, which@^1.0.5, which@^1.2.12, which@^1.2.8, which@^1.2.9, which@~1.2.10, which@~1.2.11: +which@1, which@^1.2.12, which@^1.2.8, which@^1.2.9, which@~1.2.10, which@~1.2.11: version "1.2.12" - resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" + resolved "https://registry.npmjs.org/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" dependencies: isexe "^1.1.1" wide-align@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" dependencies: string-width "^1.0.1" window-size@0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" window-size@^0.1.2: version "0.1.4" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" + resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" window-size@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + resolved "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" -wordwrap@0.0.2, wordwrap@~0.0.2: +wordwrap@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" wordwrap@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" wrap-ansi@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" wrappy@1, wrappy@~1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" write-file-atomic@^1.1.2: version "1.3.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -5999,7 +5942,7 @@ write-file-atomic@^1.1.2: write-file-atomic@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.2.0.tgz#14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.2.0.tgz#14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab" dependencies: graceful-fs "^4.1.2" imurmurhash "^0.1.4" @@ -6007,90 +5950,97 @@ write-file-atomic@~1.2.0: write@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + resolved "https://registry.npmjs.org/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" dependencies: mkdirp "^0.5.1" -ws@1.1.1, ws@^1.0.1: +ws@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" + resolved "https://registry.npmjs.org/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" + dependencies: + options ">=0.0.5" + ultron "1.0.x" + +ws@^1.0.1: + version "1.1.2" + resolved "https://registry.npmjs.org/ws/-/ws-1.1.2.tgz#8a244fa052401e08c9886cf44a85189e1fd4067f" dependencies: options ">=0.0.5" ultron "1.0.x" wtf-8@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" + resolved "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" xdg-basedir@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" + resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" dependencies: os-homedir "^1.0.0" xml2js@0.4.15: version "0.4.15" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.15.tgz#95cd03ff2dd144ec28bc6273bf2b2890c581ad0c" + resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.15.tgz#95cd03ff2dd144ec28bc6273bf2b2890c581ad0c" dependencies: sax ">=0.6.0" xmlbuilder ">=2.4.6" xml2js@^0.4.17: version "0.4.17" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" + resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" dependencies: sax ">=0.6.0" xmlbuilder "^4.1.0" xmlbuilder@2.6.2, xmlbuilder@>=2.4.6: version "2.6.2" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-2.6.2.tgz#f916f6d10d45dc171b1be2e6e673fb6e0cc35d0a" + resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-2.6.2.tgz#f916f6d10d45dc171b1be2e6e673fb6e0cc35d0a" dependencies: lodash "~3.5.0" xmlbuilder@^4.1.0: version "4.2.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" + resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" dependencies: lodash "^4.0.0" xmldom@^0.1.19: version "0.1.27" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" + resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" xmlhttprequest-ssl@1.5.3: version "1.5.3" - resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" + resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" xtend@^4.0.0, xtend@~4.0.0: version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" y18n@^3.2.0, y18n@^3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" yallist@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.0.0.tgz#306c543835f09ee1a4cb23b7bce9ab341c91cdd4" + resolved "https://registry.npmjs.org/yallist/-/yallist-2.0.0.tgz#306c543835f09ee1a4cb23b7bce9ab341c91cdd4" yam@0.0.22: version "0.0.22" - resolved "https://registry.yarnpkg.com/yam/-/yam-0.0.22.tgz#38a76cb79a19284d9206ed49031e359a1340bd06" + resolved "https://registry.npmjs.org/yam/-/yam-0.0.22.tgz#38a76cb79a19284d9206ed49031e359a1340bd06" dependencies: fs-extra "^0.30.0" lodash.merge "^4.4.0" yargs-parser@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-3.2.0.tgz#5081355d19d9d0c8c5d81ada908cb4e6d186664f" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-3.2.0.tgz#5081355d19d9d0c8c5d81ada908cb4e6d186664f" dependencies: camelcase "^3.0.0" lodash.assign "^4.1.0" yargs@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-5.0.0.tgz#3355144977d05757dbb86d6e38ec056123b3a66e" + resolved "https://registry.npmjs.org/yargs/-/yargs-5.0.0.tgz#3355144977d05757dbb86d6e38ec056123b3a66e" dependencies: cliui "^3.2.0" decamelize "^1.1.1" @@ -6109,7 +6059,7 @@ yargs@^5.0.0: yargs@~3.10.0: version "3.10.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + resolved "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" dependencies: camelcase "^1.0.2" cliui "^2.1.0" @@ -6118,7 +6068,7 @@ yargs@~3.10.0: yargs@~3.27.0: version "3.27.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" + resolved "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" dependencies: camelcase "^1.2.1" cliui "^2.1.0" @@ -6129,23 +6079,23 @@ yargs@~3.27.0: yauzl@2.4.1: version "2.4.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" + resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" dependencies: fd-slicer "~1.0.1" yeast@0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + resolved "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" yui@^3.18.1: version "3.18.1" - resolved "https://registry.yarnpkg.com/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" + resolved "https://registry.npmjs.org/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" dependencies: request "~2.40.0" yuidocjs@~0.9.0: version "0.9.0" - resolved "https://registry.yarnpkg.com/yuidocjs/-/yuidocjs-0.9.0.tgz#d2ff2b37cadf30e3d45385c58f5003e5a83f2723" + resolved "https://registry.npmjs.org/yuidocjs/-/yuidocjs-0.9.0.tgz#d2ff2b37cadf30e3d45385c58f5003e5a83f2723" dependencies: express "^4.13.1" graceful-fs "^4.1.2" From 11e1347be3beb46cb917a1f42fba7817f5937523 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 22 Feb 2017 12:35:53 -0800 Subject: [PATCH 1809/2527] misc cleanup (#4813) * avoid needly internalModel -> type conversion, when the information is already present on the internalModel * make asserts more consistent (ES6 interpolation etc) * rename trueModelName to normalizedModelName --- addon/-private/system/store.js | 268 +++++++++--------- addon/-private/system/store/finders.js | 65 ++--- addon/-private/system/store/serializers.js | 4 +- tests/integration/adapter/find-all-test.js | 2 +- tests/integration/adapter/find-test.js | 8 +- .../integration/adapter/rest-adapter-test.js | 2 +- tests/integration/store-test.js | 4 +- 7 files changed, 179 insertions(+), 174 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index e0ca26417f7..b77283a8bbb 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -340,9 +340,9 @@ Store = Service.extend({ @return {DS.Model} record */ createRecord(modelName, inputProperties) { - assert("You need to pass a model name to the store's createRecord method", isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); - let trueModelName = this._classKeyFor(modelName); + assert(`You need to pass a model name to the store's createRecord method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = this._classKeyFor(modelName); let properties = copy(inputProperties) || new EmptyObject(); // If the passed properties do not include a primary key, @@ -351,13 +351,13 @@ Store = Service.extend({ // to avoid conflicts. if (isNone(properties.id)) { - properties.id = this._generateId(trueModelName, properties); + properties.id = this._generateId(normalizedModelName, properties); } // Coerce ID to a string properties.id = coerceId(properties.id); - let internalModel = this.buildInternalModel(trueModelName, properties.id); + let internalModel = this.buildInternalModel(normalizedModelName, properties.id); let record = internalModel.getRecord(); // Move the record out of its initial `empty` state into @@ -458,15 +458,15 @@ Store = Service.extend({ // that's why we have to keep this method around even though `findRecord` is // the public way to get a record by modelName and id. assert(`Using store.find(type) has been removed. Use store.findAll(modelName) to retrieve all records for a given type.`, arguments.length !== 1); - assert(`Calling store.find() with a query object is no longer supported. Use store.query() instead.`, typeOf(id) !== 'object'); assert(`Calling store.find(modelName, id, { preload: preload }) is no longer supported. Use store.findRecord(modelName, id, { preload: preload }) instead.`, !options); assert(`You need to pass the model name and id to the store's find method`, arguments.length === 2); - assert("You cannot pass `" + inspect(id) + "` as id to the store's find method", typeOf(id) === 'string' || typeOf(id) === 'number'); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + assert(`You cannot pass '${id}' as id to the store's find method`, typeof id === 'string' || typeof id === 'number'); + assert(`Calling store.find() with a query object is no longer supported. Use store.query() instead.`, typeof id !== 'object'); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let trueModelName = this._classKeyFor(modelName); + let normalizedModelName = this._classKeyFor(modelName); - return this.findRecord(trueModelName, id); + return this.findRecord(normalizedModelName, id); }, /** @@ -691,22 +691,22 @@ Store = Service.extend({ @return {Promise} promise */ findRecord(modelName, id, options) { - assert("You need to pass a model name to the store's findRecord method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + assert(`You need to pass a model name to the store's findRecord method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); assert(badIdFormatAssertion, (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id))); - let trueModelName = this._classKeyFor(modelName); + let normalizedModelName = this._classKeyFor(modelName); - let internalModel = this._internalModelForId(trueModelName, id); + let internalModel = this._internalModelForId(normalizedModelName, id); options = options || {}; - if (!this.hasRecordForId(trueModelName, id)) { + if (!this.hasRecordForId(normalizedModelName, id)) { return this._findByInternalModel(internalModel, options); } let fetchedInternalModel = this._findRecord(internalModel, options); - return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${trueModelName} with id: ${id}`); + return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${normalizedModelName} with id: ${id}`); }, _findRecord(internalModel, options) { @@ -746,7 +746,7 @@ Store = Service.extend({ let fetchedInternalModel = this._findEmptyInternalModel(internalModel, options); - return promiseRecord(fetchedInternalModel, "DS: Store#findRecord " + internalModel.typeKey + " with id: " + get(internalModel, 'id')); + return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${internalModel.modelName} with id: ${internalModel.id}`); }, _findEmptyInternalModel(internalModel, options) { @@ -773,17 +773,18 @@ Store = Service.extend({ @return {Promise} promise */ findByIds(modelName, ids) { - assert("You need to pass a model name to the store's findByIds method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + assert(`You need to pass a model name to the store's findByIds method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let promises = new Array(ids.length); - let trueModelName = this._classKeyFor(modelName); + let normalizedModelName = this._classKeyFor(modelName); for (let i = 0; i < ids.length; i++) { - promises[i] = this.findRecord(trueModelName, ids[i]); + promises[i] = this.findRecord(normalizedModelName, ids[i]); } - return promiseArray(RSVP.all(promises).then(A, null, `DS: Store#findByIds of ${trueModelName} complete`)); + return promiseArray(RSVP.all(promises).then(A, null, `DS: Store#findByIds of ${normalizedModelName} complete`)); }, /** @@ -797,14 +798,13 @@ Store = Service.extend({ @return {Promise} promise */ _fetchRecord(internalModel, options) { - let modelClass = internalModel.type; - let id = internalModel.id; - let adapter = this.adapterFor(modelClass.modelName); + let modelName = internalModel.modelName; + let adapter = this.adapterFor(modelName); - assert("You tried to find a record but you have no adapter (for " + modelClass.modelName + ")", adapter); - assert("You tried to find a record but your adapter (for " + modelClass.modelName + ") does not implement 'findRecord'", typeof adapter.findRecord === 'function'); + assert(`You tried to find a record but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to find a record but your adapter (for ${modelName}) does not implement 'findRecord'`, typeof adapter.findRecord === 'function'); - return _find(adapter, this, modelClass, id, internalModel, options); + return _find(adapter, this, internalModel.type, internalModel.id, internalModel, options); }, _scheduleFetchMany(internalModels) { @@ -820,13 +820,15 @@ Store = Service.extend({ _scheduleFetch(internalModel, options) { if (internalModel._loadingPromise) { return internalModel._loadingPromise; } - let modelClass = internalModel.type; - let resolver = RSVP.defer('Fetching ' + modelClass.modelName + ' with id: ' + internalModel.id); + let { id, modelName } = internalModel; + let resolver = RSVP.defer(`Fetching ${modelName}' with id: ${id}`); let pendingFetchItem = { internalModel, resolver, options }; + + let modelClass = internalModel.type; // TODO: is this needed? let promise = resolver.promise; internalModel.loadingData(promise); @@ -1004,9 +1006,9 @@ Store = Service.extend({ @return {RecordReference} */ getReference(modelName, id) { - let trueModelName = this._classKeyFor(modelName); + let normalizedModelName = this._classKeyFor(modelName); - return this._internalModelForId(trueModelName, id).recordReference; + return this._internalModelForId(normalizedModelName, id).recordReference; }, /** @@ -1032,12 +1034,12 @@ Store = Service.extend({ */ peekRecord(modelName, id) { heimdall.increment(peekRecord); - assert("You need to pass a model name to the store's peekRecord method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); - let trueModelName = this._classKeyFor(modelName); + assert(`You need to pass a model name to the store's peekRecord method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = this._classKeyFor(modelName); - if (this.hasRecordForId(trueModelName, id)) { - return this._internalModelForId(trueModelName, id).getRecord(); + if (this.hasRecordForId(normalizedModelName, id)) { + return this._internalModelForId(normalizedModelName, id).getRecord(); } else { return null; } @@ -1056,13 +1058,12 @@ Store = Service.extend({ @return {Promise} promise */ _reloadRecord(internalModel) { - let modelName = internalModel.type.modelName; + let { id, modelName } = internalModel; let adapter = this.adapterFor(modelName); - let id = internalModel.id; - assert("You cannot reload a record without an ID", id); - assert("You tried to reload a record but you have no adapter (for " + modelName + ")", adapter); - assert("You tried to reload a record but your adapter does not implement `findRecord`", typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); + assert(`You cannot reload a record without an ID`, id); + assert(`You tried to reload a record but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to reload a record but your adapter does not implement 'findRecord'`, typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); return this._scheduleFetch(internalModel); }, @@ -1087,12 +1088,13 @@ Store = Service.extend({ @return {Boolean} */ hasRecordForId(modelName, id) { - assert("You need to pass a model name to the store's hasRecordForId method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); - let trueModelName = this._classKeyFor(modelName); + assert(`You need to pass a model name to the store's hasRecordForId method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let normalizedModelName = this._classKeyFor(modelName); let trueId = coerceId(id); - let internalModel = this._recordMapFor(trueModelName).get(trueId); + let internalModel = this._recordMapFor(normalizedModelName).get(trueId); return !!internalModel && internalModel.isLoaded(); }, @@ -1108,8 +1110,9 @@ Store = Service.extend({ @return {DS.Model} record */ recordForId(modelName, id) { - assert("You need to pass a model name to the store's recordForId method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + assert(`You need to pass a model name to the store's recordForId method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + return this._internalModelForId(modelName, id).getRecord(); }, @@ -1157,35 +1160,35 @@ Store = Service.extend({ @method findHasMany @private - @param {DS.Model} owner + @param {InternalModel} internalModel @param {any} link @param {(Relationship)} relationship @return {Promise} promise */ - findHasMany(owner, link, relationship) { - let adapter = this.adapterFor(owner.type.modelName); + findHasMany(internalModel, link, relationship) { + let adapter = this.adapterFor(internalModel.modelName); - assert("You tried to load a hasMany relationship but you have no adapter (for " + owner.type + ")", adapter); - assert("You tried to load a hasMany relationship from a specified `link` in the original payload but your adapter does not implement `findHasMany`", typeof adapter.findHasMany === 'function'); + assert(`You tried to load a hasMany relationship but you have no adapter (for ${internalModel.modelName})`, adapter); + assert(`You tried to load a hasMany relationship from a specified 'link' in the original payload but your adapter does not implement 'findHasMany'`, typeof adapter.findHasMany === 'function'); - return _findHasMany(adapter, this, owner, link, relationship); + return _findHasMany(adapter, this, internalModel, link, relationship); }, /** @method findBelongsTo @private - @param {DS.Model} owner + @param {InternalModel} internalModel @param {any} link @param {Relationship} relationship @return {Promise} promise */ - findBelongsTo(owner, link, relationship) { - let adapter = this.adapterFor(owner.type.modelName); + findBelongsTo(internalModel, link, relationship) { + let adapter = this.adapterFor(internalModel.modelName); - assert("You tried to load a belongsTo relationship but you have no adapter (for " + owner.type + ")", adapter); - assert("You tried to load a belongsTo relationship from a specified `link` in the original payload but your adapter does not implement `findBelongsTo`", typeof adapter.findBelongsTo === 'function'); + assert(`You tried to load a belongsTo relationship but you have no adapter (for ${internalModel.modelName})`, adapter); + assert(`You tried to load a belongsTo relationship from a specified 'link' in the original payload but your adapter does not implement 'findBelongsTo'`, typeof adapter.findBelongsTo === 'function'); - return _findBelongsTo(adapter, this, owner, link, relationship); + return _findBelongsTo(adapter, this, internalModel, link, relationship); }, /** @@ -1243,17 +1246,17 @@ Store = Service.extend({ query(modelName, query) { assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); assert(`You need to pass a query hash to the store's query method`, query); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let trueModelName = this._classKeyFor(modelName); - return this._query(trueModelName, query); + let normalizedModelName = this._classKeyFor(modelName); + return this._query(normalizedModelName, query); }, _query(modelName, query, array) { let token = heimdall.start('store._query'); - assert("You need to pass a model name to the store's query method", isPresent(modelName)); - assert("You need to pass a query hash to the store's query method", query); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); + assert(`You need to pass a query hash to the store's query method`, query); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); let modelToken = heimdall.start('initial-modelFor-lookup'); let modelClass = this._modelFor(modelName); @@ -1265,8 +1268,8 @@ Store = Service.extend({ let adapter = this.adapterFor(modelName); heimdall.stop(adapterToken); - assert("You tried to load a query but you have no adapter (for " + modelName + ")", adapter); - assert("You tried to load a query but your adapter does not implement `query`", typeof adapter.query === 'function'); + assert(`You tried to load a query but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to load a query but your adapter does not implement 'query'`, typeof adapter.query === 'function'); let pA = promiseArray(_query(adapter, this, modelClass, query, array)); instrument(() => { @@ -1369,16 +1372,17 @@ Store = Service.extend({ @return {Promise} promise which resolves with the found record or `null` */ queryRecord(modelName, query) { - assert("You need to pass a model name to the store's queryRecord method", isPresent(modelName)); - assert("You need to pass a query hash to the store's queryRecord method", query); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); - let trueModelName = this._classKeyFor(modelName); + assert(`You need to pass a model name to the store's queryRecord method`, isPresent(modelName)); + assert(`You need to pass a query hash to the store's queryRecord method`, query); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let normalizedModelName = this._classKeyFor(modelName); - let modelClass = this._modelFor(trueModelName); - let adapter = this.adapterFor(trueModelName); + let modelClass = this._modelFor(normalizedModelName); + let adapter = this.adapterFor(normalizedModelName); - assert(`You tried to make a query but you have no adapter (for ${trueModelName})`, adapter); - assert("You tried to make a query but your adapter does not implement `queryRecord`", typeof adapter.queryRecord === 'function'); + assert(`You tried to make a query but you have no adapter (for ${normalizedModelName})`, adapter); + assert(`You tried to make a query but your adapter does not implement 'queryRecord'`, typeof adapter.queryRecord === 'function'); return promiseObject(_queryRecord(adapter, this, modelClass, query).then((internalModel) => { // the promise returned by store.queryRecord is expected to resolve with @@ -1580,12 +1584,13 @@ Store = Service.extend({ @return {Promise} promise */ findAll(modelName, options) { - assert("You need to pass a model name to the store's findAll method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + assert(`You need to pass a model name to the store's findAll method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let token = heimdall.start('store.findAll'); - let trueModelName = this._classKeyFor(modelName); - let modelClass = this._modelFor(trueModelName); - let fetch = this._fetchAll(modelClass, this.peekAll(trueModelName), options); + let normalizedModelName = this._classKeyFor(modelName); + let modelClass = this._modelFor(normalizedModelName); + let fetch = this._fetchAll(modelClass, this.peekAll(normalizedModelName), options); instrument(() => { fetch.finally(() => { heimdall.stop(token); }); @@ -1608,8 +1613,8 @@ Store = Service.extend({ let adapter = this.adapterFor(modelName); let sinceToken = this._recordMapFor(modelName).metadata.since; - assert("You tried to load all records but you have no adapter (for " + modelName + ")", adapter); - assert("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function'); + assert(`You tried to load all records but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to load all records but your adapter does not implement 'findAll'`, typeof adapter.findAll === 'function'); if (options.reload) { set(array, 'isUpdating', true); @@ -1673,12 +1678,12 @@ Store = Service.extend({ */ peekAll(modelName) { heimdall.increment(peekAll); - assert("You need to pass a model name to the store's peekAll method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); - let trueModelName = this._classKeyFor(modelName); - let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(trueModelName); + assert(`You need to pass a model name to the store's peekAll method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = this._classKeyFor(modelName); + let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(normalizedModelName); - this.recordArrayManager.syncLiveRecordArray(liveRecordArray, trueModelName); + this.recordArrayManager.syncLiveRecordArray(liveRecordArray, normalizedModelName); return liveRecordArray; }, @@ -1698,13 +1703,13 @@ Store = Service.extend({ @param {String} modelName */ unloadAll(modelName) { - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), !modelName || typeof modelName === 'string'); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, !modelName || typeof modelName === 'string'); if (arguments.length === 0) { this._identityMap.clear(); } else { - let trueModelName = this._classKeyFor(modelName); - this._recordMapFor(trueModelName).clear(); + let normalizedModelName = this._classKeyFor(modelName); + this._recordMapFor(normalizedModelName).clear(); } }, @@ -1763,8 +1768,8 @@ Store = Service.extend({ @deprecated */ filter(modelName, query, filter) { - assert("You need to pass a model name to the store's filter method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + assert(`You need to pass a model name to the store's filter method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); if (!ENV.ENABLE_DS_FILTER) { assert('The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', false); @@ -1775,24 +1780,24 @@ Store = Service.extend({ let array; let hasQuery = length === 3; - let trueModelName = this._classKeyFor(modelName); + let normalizedModelName = this._classKeyFor(modelName); // allow an optional server query if (hasQuery) { - promise = this.query(trueModelName, query); + promise = this.query(normalizedModelName, query); } else if (arguments.length === 2) { filter = query; } if (hasQuery) { - array = this.recordArrayManager.createFilteredRecordArray(trueModelName, filter, query); + array = this.recordArrayManager.createFilteredRecordArray(normalizedModelName, filter, query); } else { - array = this.recordArrayManager.createFilteredRecordArray(trueModelName, filter); + array = this.recordArrayManager.createFilteredRecordArray(normalizedModelName, filter); } promise = promise || Promise.resolve(array); - return promiseArray(promise.then(() => array, null, `DS: Store#filter of ${trueModelName}`)); + return promiseArray(promise.then(() => array, null, `DS: Store#filter of ${normalizedModelName}`)); }, /** @@ -1857,10 +1862,10 @@ Store = Service.extend({ let snapshot = pendingItem.snapshot; let resolver = pendingItem.resolver; let internalModel = snapshot._internalModel; - let adapter = this.adapterFor(internalModel.modelClass.modelName); + let adapter = this.adapterFor(internalModel.modelName); let operation; - if (get(internalModel, 'currentState.stateName') === 'root.deleted.saved') { + if (internalModel.currentState.stateName === 'root.deleted.saved') { return resolver.resolve(); } else if (internalModel.isNew()) { operation = 'createRecord'; @@ -1898,7 +1903,7 @@ Store = Service.extend({ this.updateId(internalModel, data); this._setupRelationshipsForModel(internalModel, data); } else { - assert(`Your ${internalModel.type.modelName} record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, internalModel.id); + assert(`Your ${internalModel.modelName} record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, internalModel.id); } //We first make sure the primary data has been updated @@ -1946,18 +1951,19 @@ Store = Service.extend({ */ updateId(internalModel, data) { let oldId = internalModel.id; + let modelName = internalModel.modelName; let id = coerceId(data.id); // ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record) - assert(`'${internalModel.modelName}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null)); + assert(`'${modelName}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null)); // ID absolutely can't be different than oldID if oldID is not null - assert(`'${internalModel.modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, !(oldId !== null && id !== oldId)); + assert(`'${modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, !(oldId !== null && id !== oldId)); // ID can be null if oldID is not null (altered ID in response for a record) // however, this is more than likely a developer error. if (oldId !== null && id === null) { - warn(`Your ${internalModel.modelName} record was saved to the server, but the response does not have an id.`, !(oldId !== null && id === null)); + warn(`Your ${modelName} record was saved to the server, but the response does not have an id.`, !(oldId !== null && id === null)); return; } @@ -2032,9 +2038,8 @@ Store = Service.extend({ @private */ - _modelForMixin(modelName) { + _modelForMixin(normalizedModelName) { heimdall.increment(_modelForMixin); - let normalizedModelName = normalizeModelName(modelName); // container.registry = 2.1 // container._registry = 1.11 - 2.0 // container = < 1.11 @@ -2075,12 +2080,12 @@ Store = Service.extend({ @return {DS.Model} */ modelFor(modelName) { - assert("You need to pass a model name to the store's modelFor method", isPresent(modelName)); - assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ inspect(modelName), typeof modelName === 'string'); + assert(`You need to pass a model name to the store's modelFor method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let trueModelName = this._classKeyFor(modelName); + let normalizedModelName = this._classKeyFor(modelName); - return this._modelFor(trueModelName); + return this._modelFor(normalizedModelName); }, /* @@ -2128,13 +2133,14 @@ Store = Service.extend({ heimdall.increment(modelFactoryFor); assert(`You need to pass a model name to the store's modelFactoryFor method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let trueModelName = this._classKeyFor(modelName); + + let normalizedModelName = this._classKeyFor(modelName); let owner = getOwner(this); if (owner.factoryFor) { - return owner.factoryFor(`model:${trueModelName}`); + return owner.factoryFor(`model:${normalizedModelName}`); } else { - return owner._lookupFactory(`model:${trueModelName}`); + return owner._lookupFactory(`model:${normalizedModelName}`); } }, @@ -2293,9 +2299,7 @@ Store = Service.extend({ let pushed = this._push(data); if (Array.isArray(pushed)) { - let records = pushed.map(function(internalModel) { - return internalModel.getRecord(); - }); + let records = pushed.map(internalModel => internalModel.getRecord()); heimdall.stop(token); return records; } @@ -2487,12 +2491,12 @@ Store = Service.extend({ if (!inputPayload) { payload = modelName; serializer = defaultSerializer(this); - assert("You cannot use `store#pushPayload` without a modelName unless your default serializer defines `pushPayload`", typeof serializer.pushPayload === 'function'); + assert(`You cannot use 'store#pushPayload' without a modelName unless your default serializer defines 'pushPayload'`, typeof serializer.pushPayload === 'function'); } else { payload = inputPayload; - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); - let trueModelName = this._classKeyFor(modelName); - serializer = this.serializerFor(trueModelName); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = this._classKeyFor(modelName); + serializer = this.serializerFor(normalizedModelName); } if (isEnabled('ds-pushpayload-return')) { return serializer.pushPayload(this, payload); @@ -2522,11 +2526,11 @@ Store = Service.extend({ */ normalize(modelName, payload) { heimdall.increment(normalize); - assert("You need to pass a model name to the store's normalize method", isPresent(modelName)); + assert(`You need to pass a model name to the store's normalize method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); - let trueModelName = this._classKeyFor(modelName); - let serializer = this.serializerFor(trueModelName); - let model = this._modelFor(trueModelName); + let normalizedModelName = this._classKeyFor(modelName); + let serializer = this.serializerFor(normalizedModelName); + let model = this._modelFor(normalizedModelName); return serializer.normalize(model, payload); }, @@ -2606,11 +2610,11 @@ Store = Service.extend({ */ adapterFor(modelName) { heimdall.increment(adapterFor); - assert("You need to pass a model name to the store's adapterFor method", isPresent(modelName)); - assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); - let trueModelName = this._classKeyFor(modelName); + assert(`You need to pass a model name to the store's adapterFor method`, isPresent(modelName)); + assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = this._classKeyFor(modelName); - return this._instanceCache.get('adapter', trueModelName); + return this._instanceCache.get('adapter', normalizedModelName); }, // .............................. @@ -2640,11 +2644,11 @@ Store = Service.extend({ */ serializerFor(modelName) { heimdall.increment(serializerFor); - assert("You need to pass a model name to the store's serializerFor method", isPresent(modelName)); - assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); - let trueModelName = this._classKeyFor(modelName); + assert(`You need to pass a model name to the store's serializerFor method`, isPresent(modelName)); + assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = this._classKeyFor(modelName); - return this._instanceCache.get('serializer', trueModelName); + return this._instanceCache.get('serializer', normalizedModelName); }, lookupAdapter(name) { diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 54b64f4db25..10b79a0b1f3 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -14,7 +14,7 @@ import { serializerForAdapter } from "ember-data/-private/system/store/serializers"; -const Promise = Ember.RSVP.Promise; +const { Promise } = Ember.RSVP; function payloadIsNotBlank(adapterPayload) { if (Array.isArray(adapterPayload)) { @@ -26,39 +26,40 @@ function payloadIsNotBlank(adapterPayload) { export function _find(adapter, store, modelClass, id, internalModel, options) { let snapshot = internalModel.createSnapshot(options); + let { modelName } = internalModel; let promise = adapter.findRecord(store, modelClass, id, snapshot); - let serializer = serializerForAdapter(store, adapter, internalModel.type.modelName); - let label = "DS: Handle Adapter#findRecord of " + modelClass + " with id: " + id; + let serializer = serializerForAdapter(store, adapter, modelName); + let label = `DS: Handle Adapter#findRecord of '${modelName}' with id: '${id}'`; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); - return promise.then(function(adapterPayload) { - assert("You made a `findRecord` request for a " + modelClass.modelName + " with id " + id + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + return promise.then(adapterPayload => { + assert(`You made a 'findRecord' request for a '${modelName}' with id '${id}', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, id, 'findRecord'); - assert('Ember Data expected the primary data returned from a `findRecord` response to be an object but instead it found an array.', !Array.isArray(payload.data)); + assert(`Ember Data expected the primary data returned from a 'findRecord' response to be an object but instead it found an array.`, !Array.isArray(payload.data)); - warn(`You requested a record of type '${modelClass.modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead http://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, payload.data.id === id, { + warn(`You requested a record of type '${modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead http://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, payload.data.id === id, { id: 'ds.store.findRecord.id-mismatch' }); return store._push(payload); - }, function(error) { + }, error => { internalModel.notFound(); if (internalModel.isEmpty()) { internalModel.unloadRecord(); } throw error; - }, "DS: Extract payload of '" + modelClass + "'"); + }, `DS: Extract payload of '${modelName}'`); } - export function _findMany(adapter, store, modelClass, ids, internalModels) { let snapshots = Ember.A(internalModels).invoke('createSnapshot'); + let { modelName } = modelClass; // TODO: pass in modelName, or something let promise = adapter.findMany(store, modelClass, ids, snapshots); - let serializer = serializerForAdapter(store, adapter, modelClass.modelName); - let label = "DS: Handle Adapter#findMany of " + modelClass; + let serializer = serializerForAdapter(store, adapter, modelName); + let label = `DS: Handle Adapter#findMany of '${modelName}'`; if (promise === undefined) { throw new Error('adapter.findMany returned undefined, this was very likely a mistake'); @@ -67,11 +68,11 @@ export function _findMany(adapter, store, modelClass, ids, internalModels) { promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); - return promise.then(function(adapterPayload) { - assert("You made a `findMany` request for " + modelClass.modelName + " records with ids " + ids + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + return promise.then(adapterPayload => { + assert(`You made a 'findMany' request for '${modelName}' records with ids '[${ids}]', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findMany'); return store._push(payload); - }, null, "DS: Extract payload of " + modelClass); + }, null, `DS: Extract payload of ${modelName}`); } export function _findHasMany(adapter, store, internalModel, link, relationship) { @@ -79,20 +80,20 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) let modelClass = store.modelFor(relationship.type); let promise = adapter.findHasMany(store, snapshot, link, relationship); let serializer = serializerForAdapter(store, adapter, relationship.type); - let label = "DS: Handle Adapter#findHasMany of " + internalModel + " : " + relationship.type; + let label = `DS: Handle Adapter#findHasMany of '${internalModel.modelName}' : '${relationship.type}'`; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); promise = _guard(promise, _bind(_objectIsAlive, internalModel)); - return promise.then(function(adapterPayload) { - assert("You made a `findHasMany` request for a " + internalModel.modelName + "'s `" + relationship.key + "` relationship, using link " + link + ", but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + return promise.then(adapterPayload => { + assert(`You made a 'findHasMany' request for a ${internalModel.modelName}'s '${relationship.key}' relationship, using link '${link}' , but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findHasMany'); let internalModelArray = store._push(payload); internalModelArray.meta = payload.meta; return internalModelArray; - }, null, "DS: Extract payload of " + internalModel + " : hasMany " + relationship.type); + }, null, `DS: Extract payload of '${internalModel.modelName}' : hasMany '${relationship.type}'`); } export function _findBelongsTo(adapter, store, internalModel, link, relationship) { @@ -100,13 +101,13 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship let modelClass = store.modelFor(relationship.type); let promise = adapter.findBelongsTo(store, snapshot, link, relationship); let serializer = serializerForAdapter(store, adapter, relationship.type); - let label = "DS: Handle Adapter#findBelongsTo of " + internalModel + " : " + relationship.type; + let label = `DS: Handle Adapter#findBelongsTo of ${internalModel.modelName} : ${relationship.type}`; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); promise = _guard(promise, _bind(_objectIsAlive, internalModel)); - return promise.then(function(adapterPayload) { + return promise.then(adapterPayload => { let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findBelongsTo'); if (!payload.data) { @@ -114,11 +115,11 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship } return store._push(payload); - }, null, "DS: Extract payload of " + internalModel + " : " + relationship.type); + }, null, `DS: Extract payload of ${internalModel.modelName} : ${relationship.type}`); } export function _findAll(adapter, store, modelClass, sinceToken, options) { - let modelName = modelClass.modelName; + let modelName = modelClass.modelName; // TODO: pass in modelName let recordArray = store.peekAll(modelName); let snapshotArray = recordArray._createSnapshot(options); let promise = adapter.findAll(store, modelClass, sinceToken, snapshotArray); @@ -128,25 +129,25 @@ export function _findAll(adapter, store, modelClass, sinceToken, options) { promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); - return promise.then(function(adapterPayload) { - assert("You made a `findAll` request for " + modelClass.modelName + " records, but the adapter's response did not have any data", payloadIsNotBlank(adapterPayload)); + return promise.then(adapterPayload => { + assert(`You made a 'findAll' request for '${modelName}' records, but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findAll'); store._push(payload); store.didUpdateAll(modelName); return store.peekAll(modelName); - }, null, "DS: Extract payload of findAll " + modelClass); + }, null, 'DS: Extract payload of findAll ${modelName}'); } export function _query(adapter, store, modelClass, query, recordArray) { - let modelName = modelClass.modelName; + let modelName = modelClass.modelName; // TODO: name yo let promise = adapter.query(store, modelClass, query, recordArray); let serializerToken = heimdall.start('initial-serializerFor-lookup'); let serializer = serializerForAdapter(store, adapter, modelName); heimdall.stop(serializerToken); - let label = 'DS: Handle Adapter#query of ' + modelClass; + let label = `DS: Handle Adapter#query of ${modelClass}`; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); @@ -161,7 +162,7 @@ export function _query(adapter, store, modelClass, query, recordArray) { recordArray._setInternalModels(internalModels, payload); return recordArray; - }, null, 'DS: Extract payload of query ' + modelName); + }, null, `DS: Extract payload of query ${modelName}`); } export function _queryRecord(adapter, store, modelClass, query) { @@ -173,13 +174,13 @@ export function _queryRecord(adapter, store, modelClass, query) { promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); - return promise.then(function(adapterPayload) { + return promise.then(adapterPayload => { let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'queryRecord'); - assert("Expected the primary data returned by the serializer for a `queryRecord` response to be a single object or null but instead it was an array.", !Array.isArray(payload.data), { + assert(`Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array.`, !Array.isArray(payload.data), { id: 'ds.store.queryRecord-array-response' }); return store._push(payload); - }, null, "DS: Extract payload of queryRecord " + modelName); + }, null, `DS: Extract payload of queryRecord ${modelName}`); } diff --git a/addon/-private/system/store/serializers.js b/addon/-private/system/store/serializers.js index 2bd18cdcfc7..71ca0829809 100644 --- a/addon/-private/system/store/serializers.js +++ b/addon/-private/system/store/serializers.js @@ -1,8 +1,8 @@ -export function serializerForAdapter(store, adapter, type) { +export function serializerForAdapter(store, adapter, modelName) { let serializer = adapter.serializer; if (serializer === undefined) { - serializer = store.serializerFor(type); + serializer = store.serializerFor(modelName); } if (serializer === null || serializer === undefined) { diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index cc4a081bc53..8c476cf7a67 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -151,7 +151,7 @@ testInDebug('When all records are requested, assert the payload is not blank', ( assert.expectAssertion(() => { run(() => store.findAll('person')); - }, /You made a `findAll` request for person records, but the adapter's response did not have any data/); + }, /You made a 'findAll' request for 'person' records, but the adapter's response did not have any data/); }); test("isUpdating is true while records are fetched", function(assert) { diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 0028b1ce0f3..8e6b7f97e08 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -33,11 +33,11 @@ module("integration/adapter/find - Finding Records", { testInDebug("It raises an assertion when `undefined` is passed as id (#1705)", (assert) => { assert.expectAssertion(() => { store.find('person', undefined); - }, "You cannot pass `undefined` as id to the store's find method"); + }, `You cannot pass 'undefined' as id to the store's find method`); assert.expectAssertion(() => { store.find('person', null); - }, "You cannot pass `null` as id to the store's find method"); + }, `You cannot pass 'null' as id to the store's find method`); }); test("When a single record is requested, the adapter's find method should be called unless it's loaded.", (assert) => { @@ -138,7 +138,7 @@ testInDebug('When a single record is requested, and the payload is blank', (asse assert.expectAssertion(() => { run(() => store.findRecord('person', 'the-id')); - }, /You made a `findRecord` request for a person with id the-id, but the adapter's response did not have any data/); + }, /You made a 'findRecord' request for a 'person' with id 'the-id', but the adapter's response did not have any data/); }); testInDebug('When multiple records are requested, and the payload is blank', (assert) => { @@ -152,7 +152,7 @@ testInDebug('When multiple records are requested, and the payload is blank', (as store.findRecord('person', '1'); store.findRecord('person', '2'); }); - }, /You made a `findMany` request for person records with ids 1,2, but the adapter's response did not have any data/); + }, /You made a 'findMany' request for 'person' records with ids '\[1,2\]', but the adapter's response did not have any data/); }); testInDebug("warns when returned record has different id", function(assert) { diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 7262337e2cb..96b60b35552 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1801,7 +1801,7 @@ test("findHasMany - passes buildURL the requestType", function(assert) { -test("findMany - returning sideloaded data loads the data", function(assert) { +test("findMany - returning sideloaded data loads the data (with JSONApi Links)", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index c5767002db5..7506ba42f50 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -871,7 +871,7 @@ testInDebug('store#findRecord that returns an array should assert', assert => { run(function() { store.findRecord('car', 1); }); - }, /expected the primary data returned from a `findRecord` response to be an object but instead it found an array/); + }, /expected the primary data returned from a 'findRecord' response to be an object but instead it found an array/); }); testInDebug('store#didSaveRecord should assert when the response to a save does not include the id', function(assert) { @@ -910,7 +910,7 @@ testInDebug('store#queryRecord should assert when normalized payload of adapter run(function() { store.queryRecord('car', {}); }); - }, /Expected the primary data returned by the serializer for a `queryRecord` response to be a single object or null but instead it was an array./); + }, /Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array./); }); From 575e608f1c3f7ec5558a69eec4415f868f055c3d Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 22 Feb 2017 12:27:54 -0800 Subject: [PATCH 1810/2527] remove store._classKeyFor, invoke imported normalizeModelName directly --- addon/-private/system/store.js | 52 +++++++++++++--------------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b77283a8bbb..064884f7b5c 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -342,7 +342,7 @@ Store = Service.extend({ createRecord(modelName, inputProperties) { assert(`You need to pass a model name to the store's createRecord method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); let properties = copy(inputProperties) || new EmptyObject(); // If the passed properties do not include a primary key, @@ -464,7 +464,7 @@ Store = Service.extend({ assert(`Calling store.find() with a query object is no longer supported. Use store.query() instead.`, typeof id !== 'object'); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); return this.findRecord(normalizedModelName, id); }, @@ -695,7 +695,7 @@ Store = Service.extend({ assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); assert(badIdFormatAssertion, (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id))); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); let internalModel = this._internalModelForId(normalizedModelName, id); options = options || {}; @@ -778,7 +778,7 @@ Store = Service.extend({ let promises = new Array(ids.length); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); for (let i = 0; i < ids.length; i++) { promises[i] = this.findRecord(normalizedModelName, ids[i]); @@ -1006,7 +1006,7 @@ Store = Service.extend({ @return {RecordReference} */ getReference(modelName, id) { - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); return this._internalModelForId(normalizedModelName, id).recordReference; }, @@ -1036,7 +1036,7 @@ Store = Service.extend({ heimdall.increment(peekRecord); assert(`You need to pass a model name to the store's peekRecord method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); if (this.hasRecordForId(normalizedModelName, id)) { return this._internalModelForId(normalizedModelName, id).getRecord(); @@ -1091,7 +1091,7 @@ Store = Service.extend({ assert(`You need to pass a model name to the store's hasRecordForId method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); let trueId = coerceId(id); let internalModel = this._recordMapFor(normalizedModelName).get(trueId); @@ -1248,7 +1248,7 @@ Store = Service.extend({ assert(`You need to pass a query hash to the store's query method`, query); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); return this._query(normalizedModelName, query); }, @@ -1376,7 +1376,7 @@ Store = Service.extend({ assert(`You need to pass a query hash to the store's queryRecord method`, query); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); let modelClass = this._modelFor(normalizedModelName); let adapter = this.adapterFor(normalizedModelName); @@ -1588,7 +1588,7 @@ Store = Service.extend({ assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); let token = heimdall.start('store.findAll'); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); let modelClass = this._modelFor(normalizedModelName); let fetch = this._fetchAll(modelClass, this.peekAll(normalizedModelName), options); @@ -1680,7 +1680,7 @@ Store = Service.extend({ heimdall.increment(peekAll); assert(`You need to pass a model name to the store's peekAll method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(normalizedModelName); this.recordArrayManager.syncLiveRecordArray(liveRecordArray, normalizedModelName); @@ -1708,7 +1708,7 @@ Store = Service.extend({ if (arguments.length === 0) { this._identityMap.clear(); } else { - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); this._recordMapFor(normalizedModelName).clear(); } }, @@ -1780,7 +1780,7 @@ Store = Service.extend({ let array; let hasQuery = length === 3; - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); // allow an optional server query if (hasQuery) { @@ -1972,20 +1972,6 @@ Store = Service.extend({ internalModel.setId(id); }, - /** - Returns the normalized (dasherized) modelName. This method should be used whenever - receiving a modelName in a public method. - - - @method _classKeyFor - @param {String} modelName - @returns {String} - @private - */ - _classKeyFor(modelName) { - return normalizeModelName(modelName); - }, - /** Returns a map of IDs to client IDs for a given modelName. @@ -2083,7 +2069,7 @@ Store = Service.extend({ assert(`You need to pass a model name to the store's modelFor method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); return this._modelFor(normalizedModelName); }, @@ -2134,7 +2120,7 @@ Store = Service.extend({ assert(`You need to pass a model name to the store's modelFactoryFor method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); let owner = getOwner(this); if (owner.factoryFor) { @@ -2495,7 +2481,7 @@ Store = Service.extend({ } else { payload = inputPayload; assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); serializer = this.serializerFor(normalizedModelName); } if (isEnabled('ds-pushpayload-return')) { @@ -2528,7 +2514,7 @@ Store = Service.extend({ heimdall.increment(normalize); assert(`You need to pass a model name to the store's normalize method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); let serializer = this.serializerFor(normalizedModelName); let model = this._modelFor(normalizedModelName); return serializer.normalize(model, payload); @@ -2612,7 +2598,7 @@ Store = Service.extend({ heimdall.increment(adapterFor); assert(`You need to pass a model name to the store's adapterFor method`, isPresent(modelName)); assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); return this._instanceCache.get('adapter', normalizedModelName); }, @@ -2646,7 +2632,7 @@ Store = Service.extend({ heimdall.increment(serializerFor); assert(`You need to pass a model name to the store's serializerFor method`, isPresent(modelName)); assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = this._classKeyFor(modelName); + let normalizedModelName = normalizeModelName(modelName); return this._instanceCache.get('serializer', normalizedModelName); }, From cdb400593b76095970323826bdd30b6901bc2d6f Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 22 Feb 2017 12:29:18 -0800 Subject: [PATCH 1811/2527] improve name of cache of modelFactories --- addon/-private/system/store.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 064884f7b5c..12dd141791b 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -213,7 +213,7 @@ Store = Service.extend({ this._identityMap = new IdentityMap(); this._pendingSave = []; this._instanceCache = new ContainerInstanceCache(getOwner(this), this); - this._modelClassCache = new EmptyObject(); + this._modelFactoryCache = new EmptyObject(); /* Ember Data uses several specialized micro-queues for organizing @@ -2085,7 +2085,7 @@ Store = Service.extend({ _modelFactoryFor(modelName) { heimdall.increment(modelFor); - let factory = this._modelClassCache[modelName]; + let factory = this._modelFactoryCache[modelName]; if (!factory) { factory = this.modelFactoryFor(modelName); @@ -2106,7 +2106,7 @@ Store = Service.extend({ // TODO: deprecate this klass.modelName = klass.modelName || modelName; - this._modelClassCache[modelName] = factory; + this._modelFactoryCache[modelName] = factory; } return factory; From 86c539630d9c34445a9ee5e913134c06db23452f Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 22 Feb 2017 12:29:34 -0800 Subject: [PATCH 1812/2527] use default arg --- addon/-private/system/store.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 12dd141791b..e6176010681 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -737,9 +737,7 @@ Store = Service.extend({ return Promise.resolve(internalModel); }, - _findByInternalModel(internalModel, options) { - options = options || {}; - + _findByInternalModel(internalModel, options = {}) { if (options.preload) { internalModel.preloadData(options.preload); } From 9b8a752561f6cfdcd78762d79207a97885c1bf0f Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 22 Feb 2017 12:30:04 -0800 Subject: [PATCH 1813/2527] =?UTF-8?q?don=E2=80=99t=20unnecessarily=20reify?= =?UTF-8?q?=20the=20modelClass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addon/-private/system/store.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index e6176010681..304f03eb555 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -716,8 +716,7 @@ Store = Service.extend({ } let snapshot = internalModel.createSnapshot(options); - let modelClass = internalModel.type; - let adapter = this.adapterFor(modelClass.modelName); + let adapter = this.adapterFor(internalModel.modelName); // Refetch the record if the adapter thinks the record is stale if (adapter.shouldReloadRecord(this, snapshot)) { From be959c92b422a1257ff3b946c545f375cf9b7636 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 22 Feb 2017 12:58:27 -0800 Subject: [PATCH 1814/2527] make _scheduleFetch no longer depend on a reified modelClass * push modelClass lookups to places where for compat they are still needed (finders invoking adapters) --- addon/-private/system/store.js | 9 ++++----- addon/-private/system/store/finders.js | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 304f03eb555..a0331dde22a 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -825,11 +825,10 @@ Store = Service.extend({ options }; - let modelClass = internalModel.type; // TODO: is this needed? let promise = resolver.promise; internalModel.loadingData(promise); - this._pendingFetch.get(modelClass).push(pendingFetchItem); + this._pendingFetch.get(modelName).push(pendingFetchItem); emberRun.scheduleOnce('afterRender', this, this.flushAllPendingFetches); @@ -845,9 +844,9 @@ Store = Service.extend({ this._pendingFetch.clear(); }, - _flushPendingFetchForType(pendingFetchItems, modelClass) { + _flushPendingFetchForType(pendingFetchItems, modelName) { let store = this; - let adapter = store.adapterFor(modelClass.modelName); + let adapter = store.adapterFor(modelName); let shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; let totalItems = pendingFetchItems.length; let internalModels = new Array(totalItems); @@ -944,7 +943,7 @@ Store = Service.extend({ } if (totalInGroup > 1) { - _findMany(adapter, store, modelClass, ids, groupedInternalModels) + _findMany(adapter, store, modelName, ids, groupedInternalModels) .then(function(foundInternalModels) { handleFoundRecords(foundInternalModels, groupedInternalModels); }) diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 10b79a0b1f3..0a61bf64e3a 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -54,9 +54,9 @@ export function _find(adapter, store, modelClass, id, internalModel, options) { }, `DS: Extract payload of '${modelName}'`); } -export function _findMany(adapter, store, modelClass, ids, internalModels) { +export function _findMany(adapter, store, modelName, ids, internalModels) { let snapshots = Ember.A(internalModels).invoke('createSnapshot'); - let { modelName } = modelClass; // TODO: pass in modelName, or something + let modelClass = store.modelFor(modelName); // `adapter.findMany` gets the modelClass still let promise = adapter.findMany(store, modelClass, ids, snapshots); let serializer = serializerForAdapter(store, adapter, modelName); let label = `DS: Handle Adapter#findMany of '${modelName}'`; From 2bdd30a7676b11b70a6ea1e385776ac513beb24a Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 22 Feb 2017 13:00:26 -0800 Subject: [PATCH 1815/2527] =?UTF-8?q?Remove=20store=E2=80=99s=20dependence?= =?UTF-8?q?=20on=20reified=20modelClass=E2=80=99s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit push modelClass lookups to places where for compat they are needed: * finders * adapters * store’s internal _commit method * some debug mode only code --- addon/-private/system/store.js | 22 ++++++++-------------- addon/-private/system/store/finders.js | 12 ++++++------ 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index a0331dde22a..605e1e0a129 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1255,7 +1255,6 @@ Store = Service.extend({ assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); let modelToken = heimdall.start('initial-modelFor-lookup'); - let modelClass = this._modelFor(modelName); heimdall.stop(modelToken); array = array || this.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); @@ -1267,7 +1266,7 @@ Store = Service.extend({ assert(`You tried to load a query but you have no adapter (for ${modelName})`, adapter); assert(`You tried to load a query but your adapter does not implement 'query'`, typeof adapter.query === 'function'); - let pA = promiseArray(_query(adapter, this, modelClass, query, array)); + let pA = promiseArray(_query(adapter, this, modelName, query, array)); instrument(() => { pA.finally(() => { heimdall.stop(token); }); }); @@ -1374,13 +1373,12 @@ Store = Service.extend({ let normalizedModelName = normalizeModelName(modelName); - let modelClass = this._modelFor(normalizedModelName); let adapter = this.adapterFor(normalizedModelName); assert(`You tried to make a query but you have no adapter (for ${normalizedModelName})`, adapter); assert(`You tried to make a query but your adapter does not implement 'queryRecord'`, typeof adapter.queryRecord === 'function'); - return promiseObject(_queryRecord(adapter, this, modelClass, query).then((internalModel) => { + return promiseObject(_queryRecord(adapter, this, modelName, query).then(internalModel => { // the promise returned by store.queryRecord is expected to resolve with // an instance of DS.Model if (internalModel) { @@ -1585,8 +1583,7 @@ Store = Service.extend({ let token = heimdall.start('store.findAll'); let normalizedModelName = normalizeModelName(modelName); - let modelClass = this._modelFor(normalizedModelName); - let fetch = this._fetchAll(modelClass, this.peekAll(normalizedModelName), options); + let fetch = this._fetchAll(normalizedModelName, this.peekAll(normalizedModelName), options); instrument(() => { fetch.finally(() => { heimdall.stop(token); }); @@ -1598,14 +1595,11 @@ Store = Service.extend({ /** @method _fetchAll @private - @param {DS.Model} modelClass + @param {DS.Model} modelName @param {DS.RecordArray} array @return {Promise} promise */ - _fetchAll(modelClass, array, options) { - options = options || {}; - - let modelName = modelClass.modelName; + _fetchAll(modelName, array, options = {}) { let adapter = this.adapterFor(modelName); let sinceToken = this._recordMapFor(modelName).metadata.since; @@ -1614,14 +1608,14 @@ Store = Service.extend({ if (options.reload) { set(array, 'isUpdating', true); - return promiseArray(_findAll(adapter, this, modelClass, sinceToken, options)); + return promiseArray(_findAll(adapter, this, modelName, sinceToken, options)); } let snapshotArray = array._createSnapshot(options); if (adapter.shouldReloadAll(this, snapshotArray)) { set(array, 'isUpdating', true); - return promiseArray(_findAll(adapter, this, modelClass, sinceToken, options)); + return promiseArray(_findAll(adapter, this, modelName, sinceToken, options)); } if (options.backgroundReload === false) { @@ -1630,7 +1624,7 @@ Store = Service.extend({ if (options.backgroundReload || adapter.shouldBackgroundReloadAll(this, snapshotArray)) { set(array, 'isUpdating', true); - _findAll(adapter, this, modelClass, sinceToken, options); + _findAll(adapter, this, modelName, sinceToken, options); } return promiseArray(Promise.resolve(array)); diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 0a61bf64e3a..addbfe15c57 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -118,8 +118,8 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship }, null, `DS: Extract payload of ${internalModel.modelName} : ${relationship.type}`); } -export function _findAll(adapter, store, modelClass, sinceToken, options) { - let modelName = modelClass.modelName; // TODO: pass in modelName +export function _findAll(adapter, store, modelName, sinceToken, options) { + let modelClass = store.modelFor(modelName); // adapter.findAll depends on the class let recordArray = store.peekAll(modelName); let snapshotArray = recordArray._createSnapshot(options); let promise = adapter.findAll(store, modelClass, sinceToken, snapshotArray); @@ -140,8 +140,8 @@ export function _findAll(adapter, store, modelClass, sinceToken, options) { }, null, 'DS: Extract payload of findAll ${modelName}'); } -export function _query(adapter, store, modelClass, query, recordArray) { - let modelName = modelClass.modelName; // TODO: name yo +export function _query(adapter, store, modelName, query, recordArray) { + let modelClass = store.modelFor(modelName); // adapter.query needs the class let promise = adapter.query(store, modelClass, query, recordArray); let serializerToken = heimdall.start('initial-serializerFor-lookup'); @@ -165,8 +165,8 @@ export function _query(adapter, store, modelClass, query, recordArray) { }, null, `DS: Extract payload of query ${modelName}`); } -export function _queryRecord(adapter, store, modelClass, query) { - let modelName = modelClass.modelName; +export function _queryRecord(adapter, store, modelName, query) { + let modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class let promise = adapter.queryRecord(store, modelClass, query); let serializer = serializerForAdapter(store, adapter, modelName); let label = `DS: Handle Adapter#queryRecord of ${modelName}`; From 4bb9053cb98033d398c296ebec9acb0250ee242a Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 23 Feb 2017 14:39:39 -0800 Subject: [PATCH 1816/2527] remove more unneeded class reification --- addon/-private/debug.js | 5 +++-- addon/-private/system/relationships/state/relationship.js | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/addon/-private/debug.js b/addon/-private/debug.js index 8eb19b48d56..bc045e9053f 100644 --- a/addon/-private/debug.js +++ b/addon/-private/debug.js @@ -67,8 +67,9 @@ export function assertPolymorphicType(parentInternalModel, relationshipMeta, add let addedModelName = addedInternalModel.modelName; let parentModelName = parentInternalModel.modelName; let key = relationshipMeta.key; - let relationshipClass = parentInternalModel.store.modelFor(relationshipMeta.type); - let assertionMessage = `You cannot add a record of modelClass '${addedModelName}' to the '${parentModelName}.${key}' relationship (only '${relationshipClass.modelName}' allowed)`; + let relationshipModelName = relationshipMeta.type; + let relationshipClass = parentInternalModel.store.modelFor(relationshipModelName); + let assertionMessage = `You cannot add a record of modelClass '${addedModelName}' to the '${parentModelName}.${key}' relationship (only '${relationshipModelName}' allowed)`; assert(assertionMessage, checkPolymorphic(relationshipClass, addedInternalModel.modelClass)); } diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 87d9d7161a9..15afbf5d223 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -288,10 +288,10 @@ export default class Relationship { updateLink(link) { heimdall.increment(updateLink); - warn(`You pushed a record of type '${this.record.type.modelName}' with a relationship '${this.key}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, this.isAsync || this.hasData , { + warn(`You pushed a record of type '${this.record.modelName}' with a relationship '${this.key}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, this.isAsync || this.hasData , { id: 'ds.store.push-link-for-sync-relationship' }); - assert("You have pushed a record of type '" + this.record.type.modelName + "' with '" + this.key + "' as a link, but the value of that link is not a string.", typeof link === 'string' || link === null); + assert("You have pushed a record of type '" + this.record.modelName + "' with '" + this.key + "' as a link, but the value of that link is not a string.", typeof link === 'string' || link === null); this.link = link; this.linkPromise = null; From 02af6085172ae30fbd48421a218879cdf4c513bb Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Sat, 25 Feb 2017 22:42:33 -0500 Subject: [PATCH 1817/2527] Pull in loader.js from the dist directory instead of the lib directory (#4824) --- lib/javascripts.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/javascripts.js b/lib/javascripts.js index ba28882c876..1e54bc75a7f 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -29,7 +29,7 @@ function makeStrippedBuild(packageName, tree) { } function collapse(tree, outputFileName) { - var loaderDir = path.join(__dirname, '..', 'node_modules', 'loader.js', 'lib', 'loader'); + var loaderDir = path.join(__dirname, '..', 'node_modules', 'loader.js', 'dist', 'loader'); var loader = new Funnel(loaderDir, { include: ['loader.js'] }); diff --git a/package.json b/package.json index 957693fb5e7..490a9870a37 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "glob": "5.0.13", "heimdall-query": "^0.0.5", "json-api-mock-server": "0.1.1", - "loader.js": "^4.0.10", + "loader.js": "^4.2.2", "mocha": "2.4.5", "mocha-only-detector": "0.0.2", "morgan": "^1.7.0", From d8f6c4df5df743fce9deb40772acdbbd02f9ee7b Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Sat, 25 Feb 2017 09:57:33 -0800 Subject: [PATCH 1818/2527] [BUGFIX] ensure all of DS is initialized together MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * DS object will always present fully. Today during initialization it remains partially initializers for a period (missing everything from https://github.com/emberjs/data/blob/master/addon/index.js#L91-L154) * this also fixes the (unknown mixin) stuff for all DS classes Although this does force the entire DS namespaces to be initialized immediately. This shouldn’t cause a performance issue, as it the full namespace was always initialized, just in two phases. --- app/initializers/ember-data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/initializers/ember-data.js b/app/initializers/ember-data.js index af05b1c36e4..2694ebad115 100644 --- a/app/initializers/ember-data.js +++ b/app/initializers/ember-data.js @@ -1,5 +1,5 @@ import setupContainer from 'ember-data/setup-container'; -import 'ember-data/-private/core'; +import 'ember-data/index'; /* From 33d2b4d06d500172831ad5fc20372f1a2b4de1be Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Tue, 28 Feb 2017 00:12:14 -0500 Subject: [PATCH 1819/2527] Update the changelog script to support prs that are squashed via github UI (#4779) --- bin/changelog | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bin/changelog b/bin/changelog index 9b5b65dd16f..cff84b3dcbc 100755 --- a/bin/changelog +++ b/bin/changelog @@ -53,11 +53,11 @@ function getCommitMessage(commitInfo) { function processPages(res) { var contributions = res.commits.filter(function(commitInfo) { var message = commitInfo.commit.message; - - return message.indexOf('Merge pull request #') > -1 || message.indexOf('cherry picked from') > -1; + return message.indexOf('Merge pull request #') > -1 || message.indexOf('cherry picked from') > -1 || message.match(/\(#\d+\)\n/) }).map(function(commitInfo) { var message = getCommitMessage(commitInfo); var match = message.match(/#(\d+) from (.*)\//); + var squashMatch = message.match(/#(\d+)\)\n/) var result = { sha: commitInfo.sha }; @@ -65,8 +65,11 @@ function processPages(res) { if (match) { var numAndAuthor = match.slice(1, 3); - result.number =numAndAuthor[0]; + result.number = numAndAuthor[0]; result.title = message.split('\n\n')[1]; + } else if (squashMatch) { + result.number = squashMatch[1]; + result.title = message.split('\n\n')[0]; } else { result.title = message.split('\n\n')[0]; } From 6253707f363f32eacce70e7719652ae2afcf2b88 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 27 Feb 2017 21:24:57 -0800 Subject: [PATCH 1820/2527] =?UTF-8?q?don=E2=80=99t=20create=20extra=20inte?= =?UTF-8?q?rnal=20promise=20objects?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * findMany already returns Promise.all (which unwraps) --- addon/-private/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 605e1e0a129..cf8f38403b8 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1136,7 +1136,7 @@ Store = Service.extend({ let finds = new Array(internalModels.length); for (let i = 0; i < internalModels.length; i++) { - finds[i] = this._findByInternalModel(internalModels[i]); + finds[i] = this._findEmptyInternalModel(internalModels[i]); } return Promise.all(finds); From a6f14ecafaf94071aed3c22eb83e96804d1bfa5e Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 28 Feb 2017 19:31:12 -0800 Subject: [PATCH 1821/2527] only schedule flushAllPendingFetches once per pendingFetch flush (#4829) --- addon/-private/system/store.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index cf8f38403b8..7d2e6d3824f 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -67,12 +67,11 @@ const { Promise } = RSVP; //an internal model and return it in a promiseObject. Useful for returning //from find methods function promiseRecord(internalModelPromise, label) { - let toReturn = internalModelPromise.then((internalModel) => internalModel.getRecord()); + let toReturn = internalModelPromise.then(internalModel => internalModel.getRecord()); return promiseObject(toReturn, label); } - let Store; // Implementors Note: @@ -815,7 +814,9 @@ Store = Service.extend({ }, _scheduleFetch(internalModel, options) { - if (internalModel._loadingPromise) { return internalModel._loadingPromise; } + if (internalModel._loadingPromise) { + return internalModel._loadingPromise; + } let { id, modelName } = internalModel; let resolver = RSVP.defer(`Fetching ${modelName}' with id: ${id}`); @@ -828,9 +829,11 @@ Store = Service.extend({ let promise = resolver.promise; internalModel.loadingData(promise); - this._pendingFetch.get(modelName).push(pendingFetchItem); + if (this._pendingFetch.size === 0) { + emberRun.schedule('afterRender', this, this.flushAllPendingFetches); + } - emberRun.scheduleOnce('afterRender', this, this.flushAllPendingFetches); + this._pendingFetch.get(modelName).push(pendingFetchItem); return promise; }, From 3bd0c5d97d6ff0532e97a1a756d8b83a5c0e0db8 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 1 Mar 2017 13:54:18 -0800 Subject: [PATCH 1822/2527] =?UTF-8?q?remove=20isPrimaryType=E2=80=99s=20re?= =?UTF-8?q?liance=20on=20modelName=20(#4832)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * when interacting with a user-provided modelName, always be sure to normalize it. --- addon/-private/system/store.js | 1 + addon/serializers/rest.js | 5 ++--- .../serializers/rest-serializer-test.js | 15 ++++++++++---- tests/unit/store/has-model-for-test.js | 20 +++++++++++++++++++ 4 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 tests/unit/store/has-model-for-test.js diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 7d2e6d3824f..3d3a3907394 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2338,6 +2338,7 @@ Store = Service.extend({ _hasModelFor(modelName) { let owner = getOwner(this); + modelName = normalizeModelName(modelName); if (owner.factoryFor) { return !!owner.factoryFor(`model:${modelName}`); diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 8e90eed5330..8db235614d5 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -183,7 +183,7 @@ let RESTSerializer = JSONSerializer.extend({ included: [] }; - let modelClass = store._modelFor(modelName); + let modelClass = store.modelFor(modelName); let serializer = store.serializerFor(modelName); Ember.makeArray(arrayHash).forEach((hash) => { @@ -373,8 +373,7 @@ let RESTSerializer = JSONSerializer.extend({ }, isPrimaryType(store, typeName, primaryTypeClass) { - let typeClass = store.modelFor(typeName); - return typeClass.modelName === primaryTypeClass.modelName; + return store.modelFor(typeName) === primaryTypeClass; }, /** diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index fd99b33fa8a..a5c37866c56 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -109,8 +109,17 @@ test("normalizeResponse with custom modelNameFromPayloadKey", function(assert) { }; var jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }], - super_villains: [{ id: "1", firstName: "Tom", lastName: "Dale", homePlanet: "1" }] + home_planets: [{ + id: "1", + name: "Umber", + superVillains: [1] + }], + super_villains: [{ + id: "1", + firstName: "Tom", + lastName: "Dale", + homePlanet: "1" + }] }; var array; @@ -277,7 +286,6 @@ test("serialize polymorphicType", function(assert) { }); test("serialize polymorphicType with decamelized modelName", function(assert) { - YellowMinion.modelName = 'yellow-minion'; var tom, ray; run(function() { tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); @@ -529,7 +537,6 @@ test("serializeIntoHash", function(assert) { }); test("serializeIntoHash with decamelized modelName", function(assert) { - HomePlanet.modelName = 'home-planet'; run(function() { league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); }); diff --git a/tests/unit/store/has-model-for-test.js b/tests/unit/store/has-model-for-test.js new file mode 100644 index 00000000000..0cd5dd127a5 --- /dev/null +++ b/tests/unit/store/has-model-for-test.js @@ -0,0 +1,20 @@ +import {createStore} from 'dummy/tests/helpers/store'; +import {module, test} from 'qunit'; +import DS from 'ember-data'; + +let store; + +module('unit/store/has-model-For', { + beforeEach() { + store = createStore({ + adapter: DS.Adapter.extend(), + 'one-foo': DS.Model.extend({}), + 'two-foo': DS.Model.extend({}) + }); + } +}); + +test(`hasModelFor correctly normalizes`, function(assert) { + assert.equal(store._hasModelFor('oneFoo'), true); + assert.equal(store._hasModelFor('twoFoo'). true); +}); From 7f590d8111fae8453a5ea9cad004922ce4a873f9 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 1 Mar 2017 13:54:28 -0800 Subject: [PATCH 1823/2527] Cleanup things and stuff (#4831) * cleanup test-helpers * cleanup test/unit/model-test.js * consistent promise/run-loop usage * let/const * misc consistency * cleanup test/unit/modules-test.js * cleanup test/unit/promise-proxies-test.js * cleanup test/unit/states-test.js * cleanup test/unit/utils-test.js * cleanup tests/unit/transform/string * cleanup tests/unit/transform/number * cleanup tests/unit/transform/date * cleanup tests/unit/transform/boolean * cleanup tests/unit/transform/unload * cleanup tests/unit/transform/seralizer-for * cleanup tests/unit/store/seralize * cleanup tests/unit/store/unload * cleanup tests/unit/store/debug * cleanup tests/unit/adapter-errors * cleanup tests/unit/store/push * cleanup tests/unit/store/peek * cleanup tests/unit/store/model-for * cleanup tests/unit/store/lookup * cleanup tests/unit/store/has-record-for-id * cleanup tests/unit/store/asserts * cleanup tests/unit/store/create-record * cleanup tests/unit/store/adapter-interop * Consistent cleanup of updateRecord --- tests/helpers/async.js | 21 +- tests/helpers/custom-adapter.js | 6 +- tests/helpers/setup-ember-dev.js | 10 +- tests/helpers/store.js | 8 +- tests/helpers/test-in-debug.js | 4 +- tests/test-helper.js | 26 +- tests/unit/adapter-errors-test.js | 93 +- tests/unit/debug-test.js | 48 +- tests/unit/many-array-test.js | 232 ++--- tests/unit/model-test.js | 980 ++++++++++----------- tests/unit/modules-test.js | 58 +- tests/unit/promise-proxies-test.js | 18 +- tests/unit/states-test.js | 123 ++- tests/unit/store/adapter-interop-test.js | 162 ++-- tests/unit/store/asserts-test.js | 8 +- tests/unit/store/create-record-test.js | 75 +- tests/unit/store/has-record-for-id-test.js | 20 +- tests/unit/store/lookup-test.js | 5 +- tests/unit/store/model-for-test.js | 34 +- tests/unit/store/peek-record-test.js | 18 +- tests/unit/store/push-test.js | 513 +++++------ tests/unit/store/serialize-test.js | 5 +- tests/unit/store/serializer-for-test.js | 28 +- tests/unit/store/unload-test.js | 126 ++- tests/unit/transform/boolean-test.js | 28 +- tests/unit/transform/date-test.js | 41 +- tests/unit/transform/number-test.js | 12 +- tests/unit/transform/string-test.js | 18 +- tests/unit/utils-test.js | 40 +- 29 files changed, 1404 insertions(+), 1356 deletions(-) diff --git a/tests/helpers/async.js b/tests/helpers/async.js index 0beedd41849..75f10b9960d 100644 --- a/tests/helpers/async.js +++ b/tests/helpers/async.js @@ -3,7 +3,7 @@ import Ember from 'ember'; export function wait(callback, timeout) { let done = this.async(); - var timer = setTimeout(() => { + let timer = setTimeout(() => { this.ok(false, "Timeout was reached"); done(); }, timeout || 200); @@ -11,12 +11,10 @@ export function wait(callback, timeout) { return function() { window.clearTimeout(timer); - var args = arguments; - var result; + let args = arguments; + let result; try { - result = Ember.run(function() { - return callback.apply(this, args); - }); + result = Ember.run(() => callback.apply(this, args)); } finally { done(); } @@ -25,14 +23,15 @@ export function wait(callback, timeout) { } export function asyncEqual(a, b, message) { - return Ember.RSVP.all([Ember.RSVP.resolve(a), Ember.RSVP.resolve(b)]).then(this.wait((array) => { + return Ember.RSVP.all([ + Ember.RSVP.resolve(a), + Ember.RSVP.resolve(b) + ]).then(this.wait((array) => { this.push(array[0] === array[1], array[0], array[1], message); })); } -export function invokeAsync(callback, timeout) { - timeout = timeout || 1; - - setTimeout(this.wait(callback, timeout+100), timeout); +export function invokeAsync(callback, timeout = 1) { + setTimeout(this.wait(callback, timeout + 100), timeout); } diff --git a/tests/helpers/custom-adapter.js b/tests/helpers/custom-adapter.js index 9272e8d1bbe..99ca0eaa207 100644 --- a/tests/helpers/custom-adapter.js +++ b/tests/helpers/custom-adapter.js @@ -1,14 +1,12 @@ import Ember from 'ember'; - import DS from 'ember-data'; - export default function(env, adapterDefinition) { - var adapter = adapterDefinition; + let adapter = adapterDefinition; if (!DS.Adapter.detect(adapterDefinition)) { adapter = DS.Adapter.extend(adapterDefinition); } - var store = env.store; + let store = env.store; env.registry.register('adapter:-custom', adapter); Ember.run(() => store.set('adapter', '-custom')); } diff --git a/tests/helpers/setup-ember-dev.js b/tests/helpers/setup-ember-dev.js index 703c9c4dac6..bfa724ff2c5 100644 --- a/tests/helpers/setup-ember-dev.js +++ b/tests/helpers/setup-ember-dev.js @@ -5,7 +5,7 @@ import EmberTestHelpers from "ember-dev/test-helper/index"; const AVAILABLE_ASSERTIONS = ['expectAssertion', 'expectDeprecation', 'expectNoDeprecation', 'expectWarning', 'expectNoWarning', 'ignoreDeprecation']; // Maintain backwards compatiblity with older versions of ember. -var emberDebugModule; +let emberDebugModule; if (Ember.__loader && Ember.__loader.registry && Ember.__loader.registry["ember-metal/debug"]) { emberDebugModule = Ember.__loader.require('ember-metal/debug'); } @@ -26,7 +26,7 @@ function setDebugFunction(name, func) { } } -var originalModule = QUnit.module; +const originalModule = QUnit.module; /** * We patch QUnit.module here so we can setup and teardown the helpers from @@ -37,14 +37,14 @@ var originalModule = QUnit.module; * make the corresponding test fail. */ QUnit.module = function(name, options = {}) { - var testHelpers = new EmberTestHelpers({ + let testHelpers = new EmberTestHelpers({ Ember, getDebugFunction, setDebugFunction }); - var originalBeforeEach = options.beforeEach || function() { }; - var originalAfterEach = options.afterEach || function() { }; + let originalBeforeEach = options.beforeEach || function() { }; + let originalAfterEach = options.afterEach || function() { }; options.beforeEach = function(assert) { testHelpers.reset(); diff --git a/tests/helpers/store.js b/tests/helpers/store.js index 4b87186e428..4948ab027f9 100644 --- a/tests/helpers/store.js +++ b/tests/helpers/store.js @@ -3,8 +3,8 @@ import DS from 'ember-data'; import Owner from './owner'; export default function setupStore(options) { - var container, registry, owner; - var env = {}; + let container, registry, owner; + let env = {}; options = options || {}; if (Ember.Registry) { @@ -29,7 +29,7 @@ export default function setupStore(options) { } }; - var adapter = env.adapter = (options.adapter || '-default'); + let adapter = env.adapter = (options.adapter || '-default'); delete options.adapter; if (typeof adapter !== 'string') { @@ -37,7 +37,7 @@ export default function setupStore(options) { adapter = '-ember-data-test-custom'; } - for (var prop in options) { + for (let prop in options) { registry.register('model:' + Ember.String.dasherize(prop), options[prop]); } diff --git a/tests/helpers/test-in-debug.js b/tests/helpers/test-in-debug.js index d8bdd45a595..810896035f5 100644 --- a/tests/helpers/test-in-debug.js +++ b/tests/helpers/test-in-debug.js @@ -4,9 +4,7 @@ import { test, skip } from 'qunit'; export default function testInDebug() { let isDebug = false; - runInDebug(function() { - isDebug = true; - }); + runInDebug(() => isDebug = true); if (isDebug) { test(...arguments); diff --git a/tests/test-helper.js b/tests/test-helper.js index 3e26b1b29d4..a05079eb995 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -17,9 +17,15 @@ setResolver(resolver); loadInitializers(Ember.Application, 'dummy'); const { assert } = QUnit; +const transforms = { + boolean: DS.BooleanTransform.create(), + date: DS.DateTransform.create(), + number: DS.NumberTransform.create(), + string: DS.StringTransform.create() +}; -QUnit.begin(function() { - Ember.RSVP.configure('onerror', function(reason) { +QUnit.begin(() => { + Ember.RSVP.configure('onerror', reason => { // only print error messages if they're exceptions; // otherwise, let a future turn of the event loop // handle the error. @@ -29,13 +35,6 @@ QUnit.begin(function() { } }); - var transforms = { - 'boolean': DS.BooleanTransform.create(), - 'date': DS.DateTransform.create(), - 'number': DS.NumberTransform.create(), - 'string': DS.StringTransform.create() - }; - // Prevent all tests involving serialization to require a container DS.JSONSerializer.reopen({ transformFor(attributeType) { @@ -49,8 +48,8 @@ assert.wait = wait; assert.asyncEqual = asyncEqual; assert.invokeAsync = invokeAsync; assert.assertClean = function(promise) { - return promise.then(this.wait((record) => { - this.equal(record.get('hasDirtyAttributes'), false, "The record is now clean"); + return promise.then(this.wait(record => { + this.equal(record.get('hasDirtyAttributes'), false, 'The record is now clean'); return record; })); }; @@ -64,4 +63,7 @@ assert.without = function(array, item) { }; QUnit.config.testTimeout = 2000; -QUnit.config.urlConfig.push({ id: 'enableoptionalfeatures', label: "Enable Opt Features" }); +QUnit.config.urlConfig.push({ + id: 'enableoptionalfeatures', + label: 'Enable Opt Features' +}); diff --git a/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js index ca275677e33..03198a589a9 100644 --- a/tests/unit/adapter-errors-test.js +++ b/tests/unit/adapter-errors-test.js @@ -1,39 +1,43 @@ import Ember from 'ember'; -import isEnabled from "ember-data/-private/features"; +import isEnabled from 'ember-data/-private/features'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; -module("unit/adapter-errors - DS.AdapterError"); +module('unit/adapter-errors - DS.AdapterError'); + +test('DS.AdapterError', function(assert) { + let error = new DS.AdapterError(); -test("DS.AdapterError", function(assert) { - var error = new DS.AdapterError(); assert.ok(error instanceof Error); assert.ok(error instanceof Ember.Error); assert.ok(error.isAdapterError); assert.equal(error.message, 'Adapter operation failed'); }); -test("DS.InvalidError", function(assert) { - var error = new DS.InvalidError(); +test('DS.InvalidError', function(assert) { + let error = new DS.InvalidError(); + assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); assert.ok(error.isAdapterError); assert.equal(error.message, 'The adapter rejected the commit because it was invalid'); }); -test("DS.TimeoutError", function(assert) { - var error = new DS.TimeoutError(); +test('DS.TimeoutError', function(assert) { + let error = new DS.TimeoutError(); + assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); assert.ok(error.isAdapterError); assert.equal(error.message, 'The adapter operation timed out'); }); -test("DS.AbortError", function(assert) { - var error = new DS.AbortError(); +test('DS.AbortError', function(assert) { + let error = new DS.AbortError(); + assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); assert.ok(error.isAdapterError); @@ -41,68 +45,75 @@ test("DS.AbortError", function(assert) { }); if (isEnabled('ds-extended-errors')) { - test("DS.UnauthorizedError", function(assert) { - var error = new DS.UnauthorizedError(); + test('DS.UnauthorizedError', function(assert) { + let error = new DS.UnauthorizedError(); + assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); assert.ok(error.isAdapterError); assert.equal(error.message, 'The adapter operation is unauthorized'); }); - test("DS.ForbiddenError", function(assert) { - var error = new DS.ForbiddenError(); + test('DS.ForbiddenError', function(assert) { + let error = new DS.ForbiddenError(); + assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); assert.ok(error.isAdapterError); assert.equal(error.message, 'The adapter operation is forbidden'); }); - test("DS.NotFoundError", function(assert) { - var error = new DS.NotFoundError(); + test('DS.NotFoundError', function(assert) { + let error = new DS.NotFoundError(); + assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); assert.ok(error.isAdapterError); assert.equal(error.message, 'The adapter could not find the resource'); }); - test("DS.ConflictError", function(assert) { - var error = new DS.ConflictError(); + test('DS.ConflictError', function(assert) { + let error = new DS.ConflictError(); + assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); assert.ok(error.isAdapterError); assert.equal(error.message, 'The adapter operation failed due to a conflict'); }); - test("DS.ServerError", function(assert) { - var error = new DS.ServerError(); + test('DS.ServerError', function(assert) { + let error = new DS.ServerError(); + assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); assert.ok(error.isAdapterError); assert.equal(error.message, 'The adapter operation failed due to a server error'); }); - test("CustomAdapterError", function(assert) { - var CustomAdapterError = DS.AdapterError.extend(); - var error = new CustomAdapterError(); + test('CustomAdapterError', function(assert) { + let CustomAdapterError = DS.AdapterError.extend(); + let error = new CustomAdapterError(); + assert.ok(error instanceof Error); assert.ok(error instanceof DS.AdapterError); assert.ok(error.isAdapterError); assert.equal(error.message, 'Adapter operation failed'); }); - test("CustomAdapterError with default message", function(assert) { - var CustomAdapterError = DS.AdapterError.extend({ message: 'custom error!' }); - var error = new CustomAdapterError(); + test('CustomAdapterError with default message', function(assert) { + let CustomAdapterError = DS.AdapterError.extend({ message: 'custom error!' }); + let error = new CustomAdapterError(); + assert.equal(error.message, 'custom error!'); }); } -var errorsHash = { +const errorsHash = { name: ['is invalid', 'must be a string'], age: ['must be a number'] }; -var errorsArray = [ +const errorsArray = [ { title: 'Invalid Attribute', detail: 'is invalid', @@ -120,11 +131,11 @@ var errorsArray = [ } ]; -var errorsPrimaryHash = { +const errorsPrimaryHash = { base: ['is invalid', 'error message'] }; -var errorsPrimaryArray = [ +const errorsPrimaryArray = [ { title: 'Invalid Document', detail: 'is invalid', @@ -137,23 +148,23 @@ var errorsPrimaryArray = [ } ]; -test("errorsHashToArray", function(assert) { - var result = DS.errorsHashToArray(errorsHash); +test('errorsHashToArray', function(assert) { + let result = DS.errorsHashToArray(errorsHash); assert.deepEqual(result, errorsArray); }); -test("errorsHashToArray for primary data object", function(assert) { - var result = DS.errorsHashToArray(errorsPrimaryHash); +test('errorsHashToArray for primary data object', function(assert) { + let result = DS.errorsHashToArray(errorsPrimaryHash); assert.deepEqual(result, errorsPrimaryArray); }); -test("errorsArrayToHash", function(assert) { - var result = DS.errorsArrayToHash(errorsArray); +test('errorsArrayToHash', function(assert) { + let result = DS.errorsArrayToHash(errorsArray); assert.deepEqual(result, errorsHash); }); -test("errorsArrayToHash without trailing slash", function(assert) { - var result = DS.errorsArrayToHash([ +test('errorsArrayToHash without trailing slash', function(assert) { + let result = DS.errorsArrayToHash([ { detail: 'error message', source: { pointer: 'data/attributes/name' } @@ -162,12 +173,12 @@ test("errorsArrayToHash without trailing slash", function(assert) { assert.deepEqual(result, { name: ['error message'] }); }); -test("errorsArrayToHash for primary data object", function(assert) { - var result = DS.errorsArrayToHash(errorsPrimaryArray); +test('errorsArrayToHash for primary data object', function(assert) { + let result = DS.errorsArrayToHash(errorsPrimaryArray); assert.deepEqual(result, errorsPrimaryHash); }); -testInDebug("DS.InvalidError will normalize errors hash will assert", function(assert) { +testInDebug('DS.InvalidError will normalize errors hash will assert', function(assert) { assert.expectAssertion(function() { new DS.InvalidError({ name: ['is invalid'] }); }, /expects json-api formatted errors/); diff --git a/tests/unit/debug-test.js b/tests/unit/debug-test.js index 81d828113ea..4a0121fdee5 100644 --- a/tests/unit/debug-test.js +++ b/tests/unit/debug-test.js @@ -5,41 +5,38 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var run = Ember.run; +const { run } = Ember; -var TestAdapter = DS.Adapter.extend(); +const TestAdapter = DS.Adapter.extend(); -module("Debug"); +module('Debug'); -test("_debugInfo groups the attributes and relationships correctly", function(assert) { - var MaritalStatus = DS.Model.extend({ +test('_debugInfo groups the attributes and relationships correctly', function(assert) { + const MaritalStatus = DS.Model.extend({ name: DS.attr('string') }); - var Post = DS.Model.extend({ + const Post = DS.Model.extend({ title: DS.attr('string') }); - var User = DS.Model.extend({ + const User = DS.Model.extend({ name: DS.attr('string'), isDrugAddict: DS.attr('boolean'), maritalStatus: DS.belongsTo('marital-status', { async: false }), posts: DS.hasMany('post', { async: false }) }); - var store = createStore({ + let store = createStore({ adapter: TestAdapter.extend(), maritalStatus: MaritalStatus, post: Post, user: User }); - var record; - run(function() { - record = store.createRecord('user'); - }); + let record = run(() => store.createRecord('user')); - var propertyInfo = record._debugInfo().propertyInfo; + let propertyInfo = record._debugInfo().propertyInfo; assert.equal(propertyInfo.groups.length, 4); assert.deepEqual(propertyInfo.groups[0].properties, ['id', 'name', 'isDrugAddict']); @@ -48,27 +45,27 @@ test("_debugInfo groups the attributes and relationships correctly", function(as }); -test("_debugInfo supports arbitray relationship types", function(assert) { - let MaritalStatus = DS.Model.extend({ +test('_debugInfo supports arbitray relationship types', function(assert) { + const MaritalStatus = DS.Model.extend({ name: DS.attr('string') }); - let Post = DS.Model.extend({ + const Post = DS.Model.extend({ title: DS.attr('string') }); - let User = DS.Model.extend({ + const User = DS.Model.extend({ name: DS.attr('string'), isDrugAddict: DS.attr('boolean'), maritalStatus: DS.belongsTo('marital-status', { async: false }), posts: Ember.computed(() => [1, 2, 3] ) - .readOnly().meta({ - options: { inverse: null }, - isRelationship: true, - kind: 'customRelationship', - name: 'Custom Relationship', - type: 'post' - }) + .readOnly().meta({ + options: { inverse: null }, + isRelationship: true, + kind: 'customRelationship', + name: 'Custom Relationship', + type: 'post' + }) }); let store = createStore({ @@ -125,6 +122,5 @@ test("_debugInfo supports arbitray relationship types", function(assert) { 'maritalStatus', 'posts' ] - } - ) + }) }); diff --git a/tests/unit/many-array-test.js b/tests/unit/many-array-test.js index 115efadbb04..81aac0bf170 100644 --- a/tests/unit/many-array-test.js +++ b/tests/unit/many-array-test.js @@ -5,165 +5,187 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var env, store; -var attr = DS.attr; -var hasMany = DS.hasMany; -var belongsTo = DS.belongsTo; -var run = Ember.run; +let env, store, Post, Tag; -var Post, Tag; +const { attr, hasMany, belongsTo } = DS; +const { run } = Ember; -module("unit/many_array - DS.ManyArray", { +module('unit/many_array - DS.ManyArray', { beforeEach() { Post = DS.Model.extend({ title: attr('string'), tags: hasMany('tag', { async: false }) }); - Post.reopenClass({ toString: () => 'Post'}); + + Post.reopenClass({ + toString() { + return 'Post'; + } + }); Tag = DS.Model.extend({ name: attr('string'), post: belongsTo('post', { async: false }) }); - Tag.reopenClass({ toString: () => 'Tag'}); + + Tag.reopenClass({ + toString() { + return 'Tag'; + } + }); env = setupStore({ post: Post, tag: Tag }); + store = env.store; }, afterEach() { - run(function() { - store.destroy(); - }); + run(store, 'destroy'); } }); -test("manyArray.save() calls save() on all records", function(assert) { +test('manyArray.save() calls save() on all records', function(assert) { assert.expect(3); - run(function() { - Tag.reopen({ - save() { - assert.ok(true, 'record.save() was called'); - return Ember.RSVP.resolve(); - } - }); + Tag.reopen({ + save() { + assert.ok(true, 'record.save() was called'); + return Ember.RSVP.resolve(); + } + }); + return run(() => { store.push({ - data: [{ - type: 'tag', - id: '1', - attributes: { - name: 'Ember.js' - } - }, { - type: 'tag', - id: '2', - attributes: { - name: 'Tomster' - } - }, { - type: 'post', - id: '3', - attributes: { - title: 'A framework for creating ambitious web applications' + data: [ + { + type: 'tag', + id: '1', + attributes: { + name: 'Ember.js' + } }, - relationships: { - tags: { - data: [ - { type: 'tag', id: '1' }, - { type: 'tag', id: '2' } - ] + { + type: 'tag', + id: '2', + attributes: { + name: 'Tomster' } - } - }] + }, + { + type: 'post', + id: '3', + attributes: { + title: 'A framework for creating ambitious web applications' + }, + relationships: { + tags: { + data: [ + { type: 'tag', id: '1' }, + { type: 'tag', id: '2' } + ] + } + } + }] }); - var post = store.peekRecord('post', 3); - post.get('tags').save().then(function() { + let post = store.peekRecord('post', 3); + + return post.get('tags').save().then(() => { assert.ok(true, 'manyArray.save() promise resolved'); }); }); }); -test("manyArray trigger arrayContentChange functions with the correct values", function(assert) { +test('manyArray trigger arrayContentChange functions with the correct values', function(assert) { assert.expect(6); - var willChangeStartIdx; - var willChangeRemoveAmt; - var willChangeAddAmt; - var originalArrayContentWillChange = DS.ManyArray.prototype.arrayContentWillChange; - var originalArrayContentDidChange = DS.ManyArray.prototype.arrayContentDidChange; + + let willChangeStartIdx; + let willChangeRemoveAmt; + let willChangeAddAmt; + + let originalArrayContentWillChange = DS.ManyArray.prototype.arrayContentWillChange; + let originalArrayContentDidChange = DS.ManyArray.prototype.arrayContentDidChange; DS.ManyArray.reopen({ arrayContentWillChange(startIdx, removeAmt, addAmt) { willChangeStartIdx = startIdx; willChangeRemoveAmt = removeAmt; willChangeAddAmt = addAmt; - return this._super.apply(this, arguments); + + return this._super(...arguments); }, arrayContentDidChange(startIdx, removeAmt, addAmt) { assert.equal(startIdx, willChangeStartIdx, 'WillChange and DidChange startIdx should match'); assert.equal(removeAmt, willChangeRemoveAmt, 'WillChange and DidChange removeAmt should match'); assert.equal(addAmt, willChangeAddAmt, 'WillChange and DidChange addAmt should match'); - return this._super.apply(this, arguments); + + return this._super(...arguments); } }); - run(function() { - store.push({ - data: [{ - type: 'tag', - id: '1', - attributes: { - name: 'Ember.js' - } - }, { - type: 'tag', - id: '2', - attributes: { - name: 'Tomster' - } - }, { - type: 'post', - id: '3', - attributes: { - title: 'A framework for creating ambitious web applications' - }, - relationships: { - tags: { - data: [ - { type: 'tag', id: '1' } - ] - } - } - }] - }); - store.peekRecord('post', 3).get('tags'); - - store.push({ - data: { - type: 'post', - id: '3', - attributes: { - title: 'A framework for creating ambitious web applications' - }, - relationships: { - tags: { - data: [ - { type: 'tag', id: '1' }, - { type: 'tag', id: '2' } - ] + try { + run(() => { + store.push({ + data: [ + { + type: 'tag', + id: '1', + attributes: { + name: 'Ember.js' + } + }, + { + type: 'tag', + id: '2', + attributes: { + name: 'Tomster' + } + }, + { + type: 'post', + id: '3', + attributes: { + title: 'A framework for creating ambitious web applications' + }, + relationships: { + tags: { + data: [ + { type: 'tag', id: '1' } + ] + } + } + } + ] + }); + + store.peekRecord('post', 3).get('tags'); + + store.push({ + data: { + type: 'post', + id: '3', + attributes: { + title: 'A framework for creating ambitious web applications' + }, + relationships: { + tags: { + data: [ + { type: 'tag', id: '1' }, + { type: 'tag', id: '2' } + ] + } } } - } + }); }); - }); - DS.ManyArray.reopen({ - arrayContentWillChange: originalArrayContentWillChange, - arrayContentDidChange: originalArrayContentDidChange - }); + } finally { + DS.ManyArray.reopen({ + arrayContentWillChange: originalArrayContentWillChange, + arrayContentDidChange: originalArrayContentDidChange + }); + } }); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 6e0e8b1b434..263c0eae4ca 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -8,12 +8,9 @@ import isEnabled from 'ember-data/-private/features'; import { parseDate } from "ember-data/-private/ext/date"; const AssertionPrototype = QUnit.assert; +const { get, set, run } = Ember; -var get = Ember.get; -var set = Ember.set; -var run = Ember.run; - -var Person, store, env; +let Person, store, env; module('unit/model - DS.Model', { beforeEach() { @@ -29,28 +26,25 @@ module('unit/model - DS.Model', { }, afterEach() { - run(function() { - store.destroy(); - }); - Person = null; - store = null; + run(() => store.destroy()); } }); -test("can have a property set on it", function(assert) { - var record; - run(function() { - record = store.createRecord('person'); +test('can have a property set on it', function(assert) { + let record = run(() => { + let record = store.createRecord('person'); set(record, 'name', 'bar'); + return record; }); - assert.equal(get(record, 'name'), 'bar', "property was set on the record"); + assert.equal(get(record, 'name'), 'bar', 'property was set on the record'); }); -test("setting a property on a record that has not changed does not cause it to become dirty", function(assert) { +test('setting a property on a record that has not changed does not cause it to become dirty', function(assert) { assert.expect(2); env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + + return run(() => { store.push({ data: { type: 'person', @@ -62,22 +56,22 @@ test("setting a property on a record that has not changed does not cause it to b } }); - store.findRecord('person', 1).then(function(person) { - assert.equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); + return store.findRecord('person', 1).then(person => { + assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); person.set('name', "Peter"); person.set('isDrugAddict', true); - assert.equal(person.get('hasDirtyAttributes'), false, "record does not become dirty after setting property to old value"); + assert.equal(person.get('hasDirtyAttributes'), false, 'record does not become dirty after setting property to old value'); }); }); }); -test("resetting a property on a record cause it to become clean again", function(assert) { +test('resetting a property on a record cause it to become clean again', function(assert) { assert.expect(3); env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + return run(() => { store.push({ data: { type: 'person', @@ -88,29 +82,25 @@ test("resetting a property on a record cause it to become clean again", function } } }); - store.findRecord('person', 1).then(function(person) { - assert.equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); + + return store.findRecord('person', 1).then(person => { + assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); person.set('isDrugAddict', false); - assert.equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting property to a new value"); + assert.equal(person.get('hasDirtyAttributes'), true, 'record becomes dirty after setting property to a new value'); person.set('isDrugAddict', true); - assert.equal(person.get('hasDirtyAttributes'), false, "record becomes clean after resetting property to the old value"); + assert.equal(person.get('hasDirtyAttributes'), false, 'record becomes clean after resetting property to the old value'); }); }); }); -test("resetting a property to the current in-flight value causes it to become clean when the save completes", function(assert) { +test('resetting a property to the current in-flight value causes it to become clean when the save completes', function(assert) { assert.expect(4); - var person, finishSaving; - env.adapter.updateRecord = function(store, type, snapshot) { - // Make sure the save is async - return new Ember.RSVP.Promise(function(resolve, reject) { - finishSaving = resolve; - }); + return Ember.RSVP.Promise.resolve() }; - run(function() { + return run(() => { store.push({ data: { type: 'person', @@ -120,34 +110,31 @@ test("resetting a property to the current in-flight value causes it to become cl } } }); - person = store.peekRecord('person', 1); + + let person = store.peekRecord('person', 1); person.set('name', "Thomas"); - person.save(); - }); + let saving = person.save() - run(function() { - assert.equal(person.get('name'), "Thomas"); + assert.equal(person.get('name'), 'Thomas'); person.set('name', 'Tomathy'); - assert.equal(person.get('name'), "Tomathy"); + assert.equal(person.get('name'), 'Tomathy'); person.set('name', 'Thomas'); - assert.equal(person.get('name'), "Thomas"); - - finishSaving(); - }); + assert.equal(person.get('name'), 'Thomas'); - run(function() { - assert.equal(person.get('hasDirtyAttributes'), false, "The person is now clean"); + return saving.then(() => { + assert.equal(person.get('hasDirtyAttributes'), false, 'The person is now clean'); + }); }); }); -test("a record becomes clean again only if all changed properties are reset", function(assert) { +test('a record becomes clean again only if all changed properties are reset', function(assert) { assert.expect(5); env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + return run(() => { store.push({ data: { type: 'person', @@ -158,33 +145,35 @@ test("a record becomes clean again only if all changed properties are reset", fu } } }); - store.findRecord('person', 1).then(function(person) { - assert.equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); + + return store.findRecord('person', 1).then(person => { + assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); person.set('isDrugAddict', false); - assert.equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting one property to a new value"); + assert.equal(person.get('hasDirtyAttributes'), true, 'record becomes dirty after setting one property to a new value'); person.set('name', 'Mark'); - assert.equal(person.get('hasDirtyAttributes'), true, "record stays dirty after setting another property to a new value"); + assert.equal(person.get('hasDirtyAttributes'), true, 'record stays dirty after setting another property to a new value'); person.set('isDrugAddict', true); - assert.equal(person.get('hasDirtyAttributes'), true, "record stays dirty after resetting only one property to the old value"); + assert.equal(person.get('hasDirtyAttributes'), true, 'record stays dirty after resetting only one property to the old value'); person.set('name', 'Peter'); assert.equal(person.get('hasDirtyAttributes'), false, "record becomes clean after resetting both properties to the old value"); }); }); }); -test("a record reports its unique id via the `id` property", function(assert) { +test('a record reports its unique id via the `id` property', function(assert) { assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + return run(() => { store.push({ data: { type: 'person', id: '1' } }); - store.findRecord('person', 1).then(function(record) { - assert.equal(get(record, 'id'), 1, "reports id as id by default"); + + return store.findRecord('person', 1).then(record => { + assert.equal(get(record, 'id'), 1, 'reports id as id by default'); }); }); }); @@ -193,31 +182,32 @@ test("a record's id is included in its toString representation", function(assert assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + return run(() => { store.push({ data: { type: 'person', id: '1' } }); - store.findRecord('person', 1).then(function(record) { - assert.equal(record.toString(), '<(subclass of DS.Model):'+Ember.guidFor(record)+':1>', "reports id in toString"); + + return store.findRecord('person', 1).then(record => { + assert.equal(record.toString(), `<(subclass of DS.Model):${Ember.guidFor(record)}:1>`, 'reports id in toString'); }); }); }); -testInDebug("trying to set an `id` attribute should raise", function(assert) { +testInDebug('trying to set an `id` attribute should raise', function(assert) { Person = DS.Model.extend({ id: DS.attr('number'), name: DS.attr('string') }); - var store = createStore({ + const store = createStore({ person: Person }); - assert.expectAssertion(function() { - run(function() { + assert.expectAssertion(() => { + run(() => { store.push({ data: { type: 'person', @@ -232,16 +222,16 @@ testInDebug("trying to set an `id` attribute should raise", function(assert) { }, /You may not set `id`/); }); -test("a collision of a record's id with object function's name", function(assert) { +test(`a collision of a record's id with object function's name`, function(assert) { assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; - var hasWatchMethod = Object.prototype.watch; + let hasWatchMethod = Object.prototype.watch; try { if (!hasWatchMethod) { Object.prototype.watch = function() {}; } - run(function() { + return run(() => { store.push({ data: { type: 'person', @@ -249,8 +239,8 @@ test("a collision of a record's id with object function's name", function(assert } }); - store.findRecord('person', 'watch').then(function(record) { - assert.equal(get(record, 'id'), 'watch', "record is successfully created and could be found by its id"); + return store.findRecord('person', 'watch').then(record => { + assert.equal(get(record, 'id'), 'watch', 'record is successfully created and could be found by its id'); }); }); } finally { @@ -260,48 +250,48 @@ test("a collision of a record's id with object function's name", function(assert } }); -/* -test("it should use `_internalModel` and not `internalModel` to store its internalModel", function() { - expect(1); - - run(function() { - store.push('person', { id: 1 }); - - store.findRecord(Person, 1).then(function(record) { - equal(record.get('_internalModel'), undefined, "doesn't shadow internalModel key"); +test('it should use `_internalModel` and not `internalModel` to store its internalModel', function(assert) { + run(() => { + store.push({ + data: { + type: 'person', + id: 1, + attributes: {} + } }); + + assert.equal(store.peekRecord('person', 1).get('internalModel'), undefined, `doesn't shadow internalModel key`); }); }); -*/ -test("it should cache attributes", function(assert) { +test('it should cache attributes', function(assert) { assert.expect(2); - var Post = DS.Model.extend({ + const Post = DS.Model.extend({ updatedAt: DS.attr('string') }); - var store = createStore({ + const store = createStore({ post: Post }); - var dateString = "Sat, 31 Dec 2011 00:08:16 GMT"; - var date = new Date(dateString); + let dateString = 'Sat, 31 Dec 2011 00:08:16 GMT'; + let date = new Date(dateString); - run(function() { + return run(() => { store.push({ data: { type: 'post', id: '1' } }); - store.findRecord('post', 1).then(function(record) { - run(function() { - record.set('updatedAt', date); - }); - assert.deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); - assert.strictEqual(get(record, 'updatedAt'), get(record, 'updatedAt'), "second get still returns the same object"); - }).finally(function() { + + return store.findRecord('post', 1).then(record => { + record.set('updatedAt', date); + + assert.deepEqual(date, get(record, 'updatedAt'), 'setting a date returns the same date'); + assert.strictEqual(get(record, 'updatedAt'), get(record, 'updatedAt'), 'second get still returns the same object'); + }).finally(() => { run(store, 'destroy'); }); }); @@ -310,20 +300,17 @@ test("it should cache attributes", function(assert) { test("changedAttributes() return correct values", function(assert) { assert.expect(4); - var Mascot = DS.Model.extend({ + const Mascot = DS.Model.extend({ name: DS.attr('string'), likes: DS.attr('string'), isMascot: DS.attr('boolean') }); - var store = createStore({ + let store = createStore({ mascot: Mascot }); - var mascot; - - - run(function() { + let mascot = run(() => { store.push({ data: { type: 'mascot', @@ -334,84 +321,99 @@ test("changedAttributes() return correct values", function(assert) { } } }); - mascot = store.peekRecord('mascot', 1); + + return store.peekRecord('mascot', 1); }); assert.equal(Object.keys(mascot.changedAttributes()).length, 0, 'there are no initial changes'); - run(function() { + run(() => { mascot.set('name', 'Tomster'); // new value mascot.set('likes', 'Ember.js'); // changed value mascot.set('isMascot', true); // same value }); - var changedAttributes = mascot.changedAttributes(); + + let changedAttributes = mascot.changedAttributes(); + assert.deepEqual(changedAttributes.name, [undefined, 'Tomster']); assert.deepEqual(changedAttributes.likes, ['JavaScript', 'Ember.js']); - run(function() { - mascot.rollbackAttributes(); - }); + run(() => mascot.rollbackAttributes()); + assert.equal(Object.keys(mascot.changedAttributes()).length, 0, 'after rollback attributes there are no changes'); }); function toObj(obj) { // https://github.com/jquery/qunit/issues/851 - var result = Object.create(null); - for (var key in obj) { + let result = Object.create(null); + for (let key in obj) { result[key] = obj[key]; } return result; } -test("changedAttributes() works while the record is being saved", function(assert) { +test('changedAttributes() works while the record is being saved', function(assert) { assert.expect(1); - var cat; - var adapter = DS.Adapter.extend({ + + let cat; + const Adapter = DS.Adapter.extend({ createRecord(store, model, snapshot) { assert.deepEqual(toObj(cat.changedAttributes()), { name: [undefined, 'Argon'], - likes: [undefined, 'Cheese'] }); + likes: [undefined, 'Cheese'] + }); + return { id: 1 }; } }); - var Mascot = DS.Model.extend({ + + const Mascot = DS.Model.extend({ name: DS.attr('string'), likes: DS.attr('string'), isMascot: DS.attr('boolean') }); - var store = createStore({ + let store = createStore({ mascot: Mascot, - adapter: adapter + adapter: Adapter }); - run(function() { + return run(() => { cat = store.createRecord('mascot'); - cat.setProperties({ name: 'Argon', likes: 'Cheese' }); - cat.save(); + cat.setProperties({ + name: 'Argon', + likes: 'Cheese' + }); + + return cat.save(); }); }); -test("changedAttributes() works while the record is being updated", function(assert) { +test('changedAttributes() works while the record is being updated', function(assert) { assert.expect(1); - var cat; - var adapter = DS.Adapter.extend({ + let cat; + const Adapter = DS.Adapter.extend({ updateRecord(store, model, snapshot) { - assert.deepEqual(toObj(cat.changedAttributes()), { name: ['Argon', 'Helia'], likes: ['Cheese', 'Mussels'] }); + assert.deepEqual(toObj(cat.changedAttributes()), { + name: ['Argon', 'Helia'], + likes: ['Cheese', 'Mussels'] + }); + return { id: '1', type: 'mascot' }; } }); - var Mascot = DS.Model.extend({ + + const Mascot = DS.Model.extend({ name: DS.attr('string'), likes: DS.attr('string'), isMascot: DS.attr('boolean') }); - var store = createStore({ + let store = createStore({ mascot: Mascot, - adapter: adapter + adapter: Adapter }); - run(function() { + return run(() => { store.push({ data: { type: 'mascot', @@ -422,17 +424,21 @@ test("changedAttributes() works while the record is being updated", function(ass } } }); + cat = store.peekRecord('mascot', 1); - cat.setProperties({ name: 'Helia', likes: 'Mussels' }); - cat.save(); + cat.setProperties({ + name: 'Helia', + likes: 'Mussels' + }); + return cat.save(); }); }); if (isEnabled('ds-rollback-attribute')) { - test("rollbackAttribute() reverts a single attribute to its canonical value", function(assert) { + test('rollbackAttribute() reverts a single attribute to its canonical value', function(assert) { assert.expect(5); - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -446,23 +452,23 @@ if (isEnabled('ds-rollback-attribute')) { let person = store.peekRecord('person', 1); - assert.equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); + assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); person.setProperties({ name: 'Piper', isDrugAddict: false }); - assert.equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting property to a new value"); + assert.equal(person.get('hasDirtyAttributes'), true, 'record becomes dirty after setting property to a new value'); person.rollbackAttribute('isDrugAddict'); - assert.equal(person.get('isDrugAddict'), true, "The specified attribute is rolled back"); - assert.equal(person.get('name'), 'Piper', "Unspecified attributes are not rolled back"); - assert.equal(person.get('hasDirtyAttributes'), true, "record with changed attributes is still dirty"); + assert.equal(person.get('isDrugAddict'), true, 'The specified attribute is rolled back'); + assert.equal(person.get('name'), 'Piper', 'Unspecified attributes are not rolled back'); + assert.equal(person.get('hasDirtyAttributes'), true, 'record with changed attributes is still dirty'); }); }); - test("calling rollbackAttribute() on an unmodified property has no effect", function(assert) { + test('calling rollbackAttribute() on an unmodified property has no effect', function(assert) { assert.expect(5); - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -476,20 +482,20 @@ if (isEnabled('ds-rollback-attribute')) { let person = store.peekRecord('person', 1); - assert.equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); + assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); person.set('name', 'Piper'); - assert.equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting property to a new value"); + assert.equal(person.get('hasDirtyAttributes'), true, 'record becomes dirty after setting property to a new value'); person.rollbackAttribute('isDrugAddict'); - assert.equal(person.get('isDrugAddict'), true, "The specified attribute does not change value"); - assert.equal(person.get('name'), 'Piper', "Unspecified attributes are not rolled back"); - assert.equal(person.get('hasDirtyAttributes'), true, "record with changed attributes is still dirty"); + assert.equal(person.get('isDrugAddict'), true, 'The specified attribute does not change value'); + assert.equal(person.get('name'), 'Piper', 'Unspecified attributes are not rolled back'); + assert.equal(person.get('hasDirtyAttributes'), true, 'record with changed attributes is still dirty'); }); }); - test("Rolling back the final value with rollbackAttribute() causes the record to become clean again", function(assert) { + test('Rolling back the final value with rollbackAttribute() causes the record to become clean again', function(assert) { assert.expect(3); - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -503,27 +509,25 @@ if (isEnabled('ds-rollback-attribute')) { let person = store.peekRecord('person', 1); - assert.equal(person.get('hasDirtyAttributes'), false, "precond - person record should not be dirty"); + assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); person.set('isDrugAddict', false); - assert.equal(person.get('hasDirtyAttributes'), true, "record becomes dirty after setting property to a new value"); + assert.equal(person.get('hasDirtyAttributes'), true, 'record becomes dirty after setting property to a new value'); person.rollbackAttribute('isDrugAddict'); - assert.equal(person.get('hasDirtyAttributes'), false, "record becomes clean after resetting property to the old value"); + assert.equal(person.get('hasDirtyAttributes'), false, 'record becomes clean after resetting property to the old value'); }); }); - test("Using rollbackAttribute on an in-flight record reverts to the latest in-flight value", function(assert) { + test('Using rollbackAttribute on an in-flight record reverts to the latest in-flight value', function(assert) { assert.expect(4); - var person, finishSaving; + let person; // Make sure the save is async env.adapter.updateRecord = function(store, type, snapshot) { - return new Ember.RSVP.Promise(function(resolve, reject) { - finishSaving = resolve; - }); + return Ember.RSVP.resolve(); }; - run(function() { + return run(() => { store.push({ data: { type: 'person', @@ -534,38 +538,35 @@ if (isEnabled('ds-rollback-attribute')) { } }); person = store.peekRecord('person', 1); - person.set('name', "Thomas"); + person.set('name', 'Thomas'); - person.save(); - }); + let saving = person.save(); - run(function() { assert.equal(person.get('isSaving'), true); - assert.equal(person.get('name'), "Thomas"); + assert.equal(person.get('name'), 'Thomas'); - person.set('name', "Tomathy"); - assert.equal(person.get('name'), "Tomathy"); + person.set('name', 'Tomathy'); + assert.equal(person.get('name'), 'Tomathy'); person.rollbackAttribute('name'); - assert.equal(person.get('name'), "Thomas"); + assert.equal(person.get('name'), 'Thomas'); - finishSaving(); + return saving; }); }); - test("Saving an in-flight record updates the in-flight value rollbackAttribute will use", function(assert) { + test('Saving an in-flight record updates the in-flight value rollbackAttribute will use', function(assert) { assert.expect(7); - var person, finishSaving; + let person, finishSaving; + let updateRecordPromise = new Ember.RSVP.Promise(resolve => finishSaving = resolve); // Make sure the save is async env.adapter.updateRecord = function(store, type, snapshot) { - return new Ember.RSVP.Promise(function(resolve, reject) { - finishSaving = resolve; - }); + return updateRecordPromise; }; - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -575,94 +576,92 @@ if (isEnabled('ds-rollback-attribute')) { } } }); + person = store.peekRecord('person', 1); - person.set('name', "Thomas"); + }); - person.save(); + let saving = []; + + run(() => { + person.set('name', 'Thomas'); + saving.push(person.save()); }); - run(function() { + run(() => { assert.equal(person.get('isSaving'), true); - assert.equal(person.get('name'), "Thomas"); + assert.equal(person.get('name'), 'Thomas'); - person.set('name', "Tomathy"); - assert.equal(person.get('name'), "Tomathy"); + person.set('name', 'Tomathy'); + assert.equal(person.get('name'), 'Tomathy'); - person.save(); + saving.push(person.save()); }); - run(function() { + run(() => { assert.equal(person.get('isSaving'), true); assert.equal(person.get('name'), "Tomathy"); person.set('name', "Tomny"); - assert.equal(person.get('name'), "Tomny"); + assert.equal(person.get('name'), 'Tomny'); person.rollbackAttribute('name'); assert.equal(person.get('name'), 'Tomathy'); finishSaving(); }); + + return Ember.RSVP.Promise.all(saving); }); } test("a DS.Model does not require an attribute type", function(assert) { - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr() }); - var store = createStore({ + let store = createStore({ tag: Tag }); - var tag; + let tag = run(() => store.createRecord('tag', { name: "test" })); - run(function() { - tag = store.createRecord('tag', { name: "test" }); - }); - - assert.equal(get(tag, 'name'), "test", "the value is persisted"); + assert.equal(get(tag, 'name'), 'test', 'the value is persisted'); }); -test("a DS.Model can have a defaultValue without an attribute type", function(assert) { - var Tag = DS.Model.extend({ +test('a DS.Model can have a defaultValue without an attribute type', function(assert) { + const Tag = DS.Model.extend({ name: DS.attr({ defaultValue: "unknown" }) }); - var store = createStore({ + let store = createStore({ tag: Tag }); - var tag; - run(function() { - tag = store.createRecord('tag'); - }); + let tag = run(() => store.createRecord('tag')); - assert.equal(get(tag, 'name'), "unknown", "the default value is found"); + assert.equal(get(tag, 'name'), 'unknown', 'the default value is found'); }); -testInDebug("Calling attr() throws a warning", function(assert) { +testInDebug('Calling attr() throws a warning', function(assert) { assert.expect(1); - run(function() { - var person = store.createRecord('person', { id: 1, name: 'TomHuda' }); + let person = run(() => store.createRecord('person', { id: 1, name: 'TomHuda' })); - assert.throws(function() { - person.attr(); - }, /The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected/, "attr() throws a warning"); - }); + assert.throws(() => { + person.attr(); + }, /The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected/, 'attr() throws a warning'); }); -test("supports pushedData in root.deleted.uncommitted", function(assert) { - var record; - var hash = { +test('supports pushedData in root.deleted.uncommitted', function(assert) { + let hash = { data: { type: 'person', id: '1' } }; - run(function() { - record = store.push(hash); + + run(() => { + let record = store.push(hash); record.deleteRecord(); store.push(hash); assert.equal(get(record, 'currentState.stateName'), 'root.deleted.uncommitted', @@ -670,243 +669,235 @@ test("supports pushedData in root.deleted.uncommitted", function(assert) { }); }); -test("currentState is accessible when the record is created", function(assert) { - var record; - var hash = { +test('currentState is accessible when the record is created', function(assert) { + let hash = { data: { type: 'person', id: '1' } }; - run(function() { - record = store.push(hash); + + run(() => { + let record = store.push(hash); assert.equal(get(record, 'currentState.stateName'), 'root.loaded.saved', - 'records pushed into the store start in the loaded state'); + 'records pushed into the store start in the loaded state'); }); }); -module("unit/model - DS.Model updating", { +module('unit/model - DS.Model updating', { beforeEach() { - Person = DS.Model.extend({ name: DS.attr('string') }); + Person = DS.Model.extend({ + name: DS.attr('string') + }); + env = setupStore({ person: Person }); + store = env.store; - run(function() { + run(() => { store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Scumbag Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Scumbag Katz' - } - }, { - type: 'person', - id: '3', - attributes: { - name: 'Scumbag Bryn' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale' + } + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz' + } + }, + { + type: 'person', + id: '3', + attributes: { + name: 'Scumbag Bryn' + } + }] }); }); }, + afterEach() { - run(function() { - store.destroy(); - Person = null; - store = null; - }); + run(store, 'destroy'); } }); -test("a DS.Model can update its attributes", function(assert) { +test('a DS.Model can update its attributes', function(assert) { assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { - store.findRecord('person', 2).then(function(person) { - set(person, 'name', "Brohuda Katz"); - assert.equal(get(person, 'name'), "Brohuda Katz", "setting took hold"); + return run(() => { + return store.findRecord('person', 2).then(person => { + set(person, 'name', 'Brohuda Katz'); + assert.equal(get(person, 'name'), 'Brohuda Katz', 'setting took hold'); }); }); }); -test("a DS.Model can have a defaultValue", function(assert) { - var Tag = DS.Model.extend({ - name: DS.attr('string', { defaultValue: "unknown" }) +test('a DS.Model can have a defaultValue', function(assert) { + const Tag = DS.Model.extend({ + name: DS.attr('string', { defaultValue: 'unknown' }) }); - var tag; - var store = createStore({ + let store = createStore({ tag: Tag }); - run(function() { - tag = store.createRecord('tag'); - }); + let tag = run(() => store.createRecord('tag')); - assert.equal(get(tag, 'name'), "unknown", "the default value is found"); + assert.equal(get(tag, 'name'), 'unknown', 'the default value is found'); - run(function() { - set(tag, 'name', null); - }); + run(() => set(tag, 'name', null)); - assert.equal(get(tag, 'name'), null, "null doesn't shadow defaultValue"); + assert.equal(get(tag, 'name'), null, `null doesn't shadow defaultValue`); }); -test("a DS.model can define 'setUnknownProperty'", function(assert) { - var tag; - var Tag = DS.Model.extend({ - name: DS.attr("string"), +test(`a DS.model can define 'setUnknownProperty'`, function(assert) { + const Tag = DS.Model.extend({ + name: DS.attr('string'), setUnknownProperty(key, value) { - if (key === "title") { - this.set("name", value); + if (key === 'title') { + this.set('name', value); } } }); - var store = createStore({ + let store = createStore({ tag: Tag }); - run(function() { + let tag = run(() => { tag = store.createRecord('tag', { name: "old" }); - set(tag, "title", "new"); + set(tag, 'title', 'new'); + + return tag; }); - assert.equal(get(tag, "name"), "new", "setUnknownProperty not triggered"); + assert.equal(get(tag, 'name'), 'new', 'setUnknownProperty not triggered'); }); -test("a defaultValue for an attribute can be a function", function(assert) { - var Tag = DS.Model.extend({ +test('a defaultValue for an attribute can be a function', function(assert) { + const Tag = DS.Model.extend({ createdAt: DS.attr('string', { defaultValue() { - return "le default value"; + return 'le default value'; } }) }); - var tag; - var store = createStore({ + let store = createStore({ tag: Tag }); - run(function() { - tag = store.createRecord('tag'); + run(() => { + let tag = store.createRecord('tag'); + assert.equal(get(tag, 'createdAt'), 'le default value', 'the defaultValue function is evaluated'); }); - assert.equal(get(tag, 'createdAt'), "le default value", "the defaultValue function is evaluated"); }); -test("a defaultValue function gets the record, options, and key", function(assert) { +test('a defaultValue function gets the record, options, and key', function(assert) { assert.expect(2); - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ createdAt: DS.attr('string', { defaultValue(record, options, key) { - assert.deepEqual(record, tag, "the record is passed in properly"); - assert.equal(key, 'createdAt', "the attribute being defaulted is passed in properly"); - return "le default value"; + assert.deepEqual(record, tag, 'the record is passed in properly'); + assert.equal(key, 'createdAt', 'the attribute being defaulted is passed in properly'); + return 'le default value'; } }) }); - var store = createStore({ + let store = createStore({ tag: Tag }); - var tag; - run(function() { - tag = store.createRecord('tag'); - }); + let tag = run(() => store.createRecord('tag')); get(tag, 'createdAt'); }); -testInDebug("a complex object defaultValue is deprecated ", function(assert) { - var Tag = DS.Model.extend({ +testInDebug('a complex object defaultValue is deprecated', function(assert) { + const Tag = DS.Model.extend({ tagInfo: DS.attr({ defaultValue: [] }) }); - var tag; - var store = createStore({ + let store = createStore({ tag: Tag }); - run(function() { - tag = store.createRecord('tag'); - }); - assert.expectDeprecation(function() { + let tag = run(() => store.createRecord('tag')); + + assert.expectDeprecation(() => { get(tag, 'tagInfo'); }, /Non primitive defaultValues are deprecated/); }); -testInDebug("a null defaultValue is not deprecated", function(assert) { - var Tag = DS.Model.extend({ +testInDebug('a null defaultValue is not deprecated', function(assert) { + const Tag = DS.Model.extend({ tagInfo: DS.attr({ defaultValue: null }) }); - var tag; - var store = createStore({ + let store = createStore({ tag: Tag }); - run(function() { - tag = store.createRecord('tag'); - }); + let tag = run(() => store.createRecord('tag')); + assert.expectNoDeprecation(); assert.equal(get(tag, 'tagInfo'), null); }); -test("setting a property to undefined on a newly created record should not impact the current state", function(assert) { - var Tag = DS.Model.extend({ +test('setting a property to undefined on a newly created record should not impact the current state', function(assert) { + const Tag = DS.Model.extend({ name: DS.attr('string') }); - var store = createStore({ + let store = createStore({ tag: Tag }); - var tag; - - run(function() { + let tag = run(() => { tag = store.createRecord('tag'); + set(tag, 'name', 'testing'); set(tag, 'name', undefined); + + return tag; }); - assert.equal(get(tag, 'currentState.stateName'), "root.loaded.created.uncommitted"); - run(function() { - tag = store.createRecord('tag', { name: undefined }); - }); + assert.equal(get(tag, 'currentState.stateName'), 'root.loaded.created.uncommitted'); - assert.equal(get(tag, 'currentState.stateName'), "root.loaded.created.uncommitted"); + tag = run(() => store.createRecord('tag', { name: undefined })); + + assert.equal(get(tag, 'currentState.stateName'), 'root.loaded.created.uncommitted'); }); // NOTE: this is a 'backdoor' test that ensures internal consistency, and should be // thrown out if/when the current `_attributes` hash logic is removed. -test("setting a property back to its original value removes the property from the `_attributes` hash", function(assert) { +test('setting a property back to its original value removes the property from the `_attributes` hash', function(assert) { assert.expect(3); env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { - store.findRecord('person', 1).then(function(person) { - assert.equal(person._internalModel._attributes.name, undefined, "the `_attributes` hash is clean"); + return run(() => { + return store.findRecord('person', 1).then(person => { + assert.equal(person._internalModel._attributes.name, undefined, 'the `_attributes` hash is clean'); - set(person, 'name', "Niceguy Dale"); + set(person, 'name', 'Niceguy Dale'); - assert.equal(person._internalModel._attributes.name, "Niceguy Dale", "the `_attributes` hash contains the changed value"); + assert.equal(person._internalModel._attributes.name, 'Niceguy Dale', 'the `_attributes` hash contains the changed value'); - set(person, 'name', "Scumbag Dale"); + set(person, 'name', 'Scumbag Dale'); - assert.equal(person._internalModel._attributes.name, undefined, "the `_attributes` hash is reset"); + assert.equal(person._internalModel._attributes.name, undefined, 'the `_attributes` hash is reset'); }); }); }); @@ -919,40 +910,40 @@ module("unit/model - with a simple Person model", { store = createStore({ person: Person }); - run(function() { + + run(() => { store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Scumbag Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Scumbag Katz' - } - }, { - type: 'person', - id: '3', - attributes: { - name: 'Scumbag Bryn' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale' + } + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz' + } + }, + { + type: 'person', + id: '3', + attributes: { + name: 'Scumbag Bryn' + } + }] }); }); }, afterEach() { - run(function() { - store.destroy(); - Person = null; - store = null; - }); + run(store, 'destroy'); } }); -test("can ask if record with a given id is loaded", function(assert) { +test('can ask if record with a given id is loaded', function(assert) { assert.equal(store.hasRecordForId('person', 1), true, 'should have person with id 1'); assert.equal(store.hasRecordForId('person', 1), true, 'should have person with id 1'); assert.equal(store.hasRecordForId('person', 4), false, 'should not have person with id 4'); @@ -960,73 +951,52 @@ test("can ask if record with a given id is loaded", function(assert) { }); test("a listener can be added to a record", function(assert) { - var count = 0; - var F = function() { count++; }; - var record; + let count = 0; + let F = function() { count++; }; - run(function() { - record = store.createRecord('person'); - }); + let record = run(() => store.createRecord('person')); record.on('event!', F); - run(function() { - record.trigger('event!'); - }); + run(() => record.trigger('event!')); - assert.equal(count, 1, "the event was triggered"); + assert.equal(count, 1, 'the event was triggered'); - run(function() { - record.trigger('event!'); - }); + run(() => record.trigger('event!')); - assert.equal(count, 2, "the event was triggered"); + assert.equal(count, 2, 'the event was triggered'); }); -test("when an event is triggered on a record the method with the same name is invoked with arguments", function(assert) { - var count = 0; - var F = function() { count++; }; - var record; - - run(function() { - record = store.createRecord('person'); - }); +test('when an event is triggered on a record the method with the same name is invoked with arguments', function(assert) { + let count = 0; + let F = function() { count++; }; + let record = run(() => store.createRecord('person')); record.eventNamedMethod = F; - run(function() { - record.trigger('eventNamedMethod'); - }); + run(() => record.trigger('eventNamedMethod')); assert.equal(count, 1, "the corresponding method was called"); }); -test("when a method is invoked from an event with the same name the arguments are passed through", function(assert) { - var eventMethodArgs = null; - var F = function() { - eventMethodArgs = arguments; - }; - var record; - - run(function() { - record = store.createRecord('person'); - }); +test('when a method is invoked from an event with the same name the arguments are passed through', function(assert) { + let eventMethodArgs = null; + let F = function() { eventMethodArgs = arguments; }; + let record = run(() => store.createRecord('person')); record.eventThatTriggersMethod = F; - run(function() { - record.trigger('eventThatTriggersMethod', 1, 2); - }); + run(() => record.trigger('eventThatTriggersMethod', 1, 2)); assert.equal(eventMethodArgs[0], 1); assert.equal(eventMethodArgs[1], 2); }); AssertionPrototype.converts = function converts(type, provided, expected, options = {}) { - var Model = DS.Model.extend({ + const Model = DS.Model.extend({ name: DS.attr(type, options) }); - var registry, container; + let registry, container; if (Ember.Registry) { registry = new Ember.Registry(); container = registry.container(); @@ -1034,13 +1004,18 @@ AssertionPrototype.converts = function converts(type, provided, expected, option container = new Ember.Container(); registry = container; } - var testStore = createStore({ model: Model }); + + let testStore = createStore({ + model: Model + }); run(() => { testStore.push(testStore.normalize('model', { id: 1, name: provided })); testStore.push(testStore.normalize('model', { id: 2 })); - var record = testStore.peekRecord('model', 1); - this.deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); + + let record = testStore.peekRecord('model', 1); + + this.deepEqual(get(record, 'name'), expected, type + ' coerces ' + provided + ' to ' + expected); }); // See: Github issue #421 @@ -1050,11 +1025,11 @@ AssertionPrototype.converts = function converts(type, provided, expected, option }; AssertionPrototype.convertsFromServer = function convertsFromServer(type, provided, expected) { - var Model = DS.Model.extend({ + const Model = DS.Model.extend({ name: DS.attr(type) }); - var registry, container; + let registry, container; if (Ember.Registry) { registry = new Ember.Registry(); container = registry.container(); @@ -1062,61 +1037,66 @@ AssertionPrototype.convertsFromServer = function convertsFromServer(type, provid container = new Ember.Container(); registry = container; } - var testStore = createStore({ + let testStore = createStore({ model: Model, adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord: () => false + shouldBackgroundReloadRecord() { return false; } }) }); - run(() => { - testStore.push(testStore.normalize('model', { id: "1", name: provided })); - testStore.findRecord('model', 1).then((record) => { - this.deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); + return run(() => { + testStore.push(testStore.normalize('model', { + id: '1', + name: provided + })); + + return testStore.findRecord('model', 1).then(record => { + this.deepEqual(get(record, 'name'), expected, type + ' coerces ' + provided + ' to ' + expected); }); }); }; AssertionPrototype.convertsWhenSet = function(type, provided, expected) { - var Model = DS.Model.extend({ + const Model = DS.Model.extend({ name: DS.attr(type) }); - var testStore = createStore({ + let testStore = createStore({ model: Model, adapter: DS.Adapter.extend({ shouldBackgroundReloadRecord: () => false }) }); - run(() => { + return run(() => { testStore.push({ data: { type: 'model', id: '2' } }); - testStore.findRecord('model', 2).then((record) => { + + return testStore.findRecord('model', 2).then(record => { set(record, 'name', provided); - this.deepEqual(record.serialize().name, expected, type + " saves " + provided + " as " + expected); + this.deepEqual(record.serialize().name, expected, type + ' saves ' + provided + ' as ' + expected); }); }); }; -test("a DS.Model can describe String attributes", function(assert) { +test('a DS.Model can describe String attributes', function(assert) { assert.expect(4); - assert.converts('string', "Scumbag Tom", "Scumbag Tom"); - assert.converts('string', 1, "1"); - assert.converts('string', "", ""); + assert.converts('string', 'Scumbag Tom', 'Scumbag Tom'); + assert.converts('string', 1, '1'); + assert.converts('string', '', ''); assert.converts('string', null, null); }); -test("a DS.Model can describe Number attributes", function(assert) { +test('a DS.Model can describe Number attributes', function(assert) { assert.expect(8); - assert.converts('number', "1", 1); - assert.converts('number', "0", 0); + assert.converts('number', '1', 1); + assert.converts('number', '0', 0); assert.converts('number', 1, 1); assert.converts('number', 0, 0); assert.converts('number', "", null); @@ -1125,8 +1105,8 @@ test("a DS.Model can describe Number attributes", function(assert) { assert.converts('number', false, 0); }); -test("a DS.Model can describe Boolean attributes", function(assert) { - assert.converts('boolean', "1", true); +test('a DS.Model can describe Boolean attributes', function(assert) { + assert.converts('boolean', '1', true); assert.converts('boolean', "", false); assert.converts('boolean', 1, true); assert.converts('boolean', 0, false); @@ -1141,157 +1121,155 @@ test("a DS.Model can describe Boolean attributes", function(assert) { assert.converts('boolean', false, false); }); -test("a DS.Model can describe Date attributes", function(assert) { +test('a DS.Model can describe Date attributes', function(assert) { assert.expect(5); assert.converts('date', null, null); assert.converts('date', undefined, undefined); - var dateString = "2011-12-31T00:08:16.000Z"; - var date = new Date(parseDate(dateString)); + let dateString = '2011-12-31T00:08:16.000Z'; + let date = new Date(parseDate(dateString)); - - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ updatedAt: DS.attr('date') }); - var store = createStore({ + let store = createStore({ person: Person, adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord: () => false + shouldBackgroundReloadRecord() { return false; } }) }); - run(function() { + return run(() => { store.push({ data: { type: 'person', id: '1' } }); - store.findRecord('person', 1).then(function(record) { - run(function() { - record.set('updatedAt', date); - }); - assert.deepEqual(date, get(record, 'updatedAt'), "setting a date returns the same date"); + + return store.findRecord('person', 1).then(record => { + record.set('updatedAt', date); + assert.deepEqual(date, get(record, 'updatedAt'), 'setting a date returns the same date'); }); + }).then(() => { + assert.convertsFromServer('date', dateString, date); + assert.convertsWhenSet('date', date, dateString); }); - assert.convertsFromServer('date', dateString, date); - assert.convertsWhenSet('date', date, dateString); }); -testInDebug("don't allow setting", function(assert) { - var Person = DS.Model.extend(); - var record; +testInDebug(`don't allow setting`, function(assert) { + const Person = DS.Model.extend(); - var store = createStore({ + let store = createStore({ person: Person }); - run(function() { - record = store.createRecord('person'); - }); + let record = run(() => store.createRecord('person')); - assert.throws(function() { - run(function() { + assert.throws(() => { + run(() => { record.set('isLoaded', true); }); - }, "raised error when trying to set an unsettable record"); + }, 'raised error when trying to set an unsettable record'); }); -test("ensure model exits loading state, materializes data and fulfills promise only after data is available", function(assert) { +test('ensure model exits loading state, materializes data and fulfills promise only after data is available', function(assert) { assert.expect(2); - var store = createStore({ + let store = createStore({ adapter: DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: "John" }); + return Ember.RSVP.resolve({ + id: 1, + name: 'John' + }); } }), person: Person }); - run(function() { - store.findRecord('person', 1).then(function(person) { + return run(() => { + return store.findRecord('person', 1).then(person => { assert.equal(get(person, 'currentState.stateName'), 'root.loaded.saved', 'model is in loaded state'); assert.equal(get(person, 'isLoaded'), true, 'model is loaded'); }); }); }); -test("A DS.Model can be JSONified", function(assert) { - var Person = DS.Model.extend({ +test('A DS.Model can be JSONified', function(assert) { + const Person = DS.Model.extend({ name: DS.attr('string') }); - var store = createStore({ person: Person }); - var record; + let store = createStore({ person: Person }); + let record = run(() => store.createRecord('person', { name: 'TomHuda' })); - run(function() { - record = store.createRecord('person', { name: "TomHuda" }); - }); - assert.deepEqual(record.toJSON(), { name: "TomHuda" }); + assert.deepEqual(record.toJSON(), { name: 'TomHuda' }); }); -testInDebug("A subclass of DS.Model can not use the `data` property", function(assert) { - var Person = DS.Model.extend({ +testInDebug('A subclass of DS.Model can not use the `data` property', function(assert) { + const Person = DS.Model.extend({ data: DS.attr('string'), name: DS.attr('string') }); - var store = createStore({ person: Person }); + let store = createStore({ person: Person }); - assert.expectAssertion(function() { - run(function() { - store.createRecord('person', { name: "TomHuda" }); + assert.expectAssertion(() => { + run(() => { + store.createRecord('person', { name: 'TomHuda' }); }); }, /`data` is a reserved property name on DS.Model objects/); }); -testInDebug("A subclass of DS.Model can not use the `store` property", function(assert) { - var Retailer = DS.Model.extend({ +testInDebug('A subclass of DS.Model can not use the `store` property', function(assert) { + const Retailer = DS.Model.extend({ store: DS.attr(), name: DS.attr() }); - var store = createStore({ retailer: Retailer }); + let store = createStore({ retailer: Retailer }); - assert.expectAssertion(function() { - run(function() { - store.createRecord('retailer', { name: "Buy n Large" }); + assert.expectAssertion(() => { + run(() => { + store.createRecord('retailer', { name: 'Buy n Large' }); }); }, /`store` is a reserved property name on DS.Model objects/); }); -testInDebug("A subclass of DS.Model can not use reserved properties", function(assert) { +testInDebug('A subclass of DS.Model can not use reserved properties', function(assert) { assert.expect(3); [ 'currentState', 'data', 'store' - ].forEach(function(reservedProperty) { - var invalidExtendObject = {}; + ].forEach(reservedProperty => { + let invalidExtendObject = {}; invalidExtendObject[reservedProperty] = DS.attr(); - var Post = DS.Model.extend(invalidExtendObject); + const Post = DS.Model.extend(invalidExtendObject); - var store = createStore({ post: Post }); + let store = createStore({ post: Post }); - assert.expectAssertion(function() { - run(function() { + assert.expectAssertion(() => { + run(() => { store.createRecord('post', {}); }); }, /is a reserved property name on DS.Model objects/); }); }); -test("Pushing a record into the store should transition it to the loaded state", function(assert) { - var Person = DS.Model.extend({ +test('Pushing a record into the store should transition it to the loaded state', function(assert) { + const Person = DS.Model.extend({ name: DS.attr('string') }); - var store = createStore({ person: Person }); + let store = createStore({ person: Person }); + + run(() => { + let person = store.createRecord('person', { id: 1, name: 'TomHuda' }); - run(function() { - var person = store.createRecord('person', { id: 1, name: 'TomHuda' }); assert.equal(person.get('isNew'), true, 'createRecord should put records into the new state'); + store.push({ data: { type: 'person', @@ -1301,45 +1279,47 @@ test("Pushing a record into the store should transition it to the loaded state", } } }); + assert.equal(person.get('isNew'), false, 'push should put records into the loaded state'); }); }); -testInDebug("A subclass of DS.Model throws an error when calling create() directly", function(assert) { - assert.throws(function() { +testInDebug('A subclass of DS.Model throws an error when calling create() directly', function(assert) { + assert.throws(() => { Person.create(); - }, /You should not call `create` on a model/, "Throws an error when calling create() on model"); + }, /You should not call `create` on a model/, 'Throws an error when calling create() on model'); }); test('toJSON looks up the JSONSerializer using the store instead of using JSONSerializer.create', function(assert) { - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ posts: DS.hasMany('post', { async: false }) }); - var Post = DS.Model.extend({ + const Post = DS.Model.extend({ person: DS.belongsTo('person', { async: false }) }); - var env = setupStore({ + let env = setupStore({ person: Person, post: Post }); - var store = env.store; + let { store } = env; - var person, json; // Loading the person without explicitly // loading its relationships seems to trigger the // original bug where `this.store` was not // present on the serializer due to using .create // instead of `store.serializerFor`. - run(() => { - person = store.push({ + let person = run(() => { + return store.push({ data: { type: 'person', id: '1' } }); }); - var errorThrown = false; + + let errorThrown = false; + let json; try { json = run(person, 'toJSON'); } catch (e) { @@ -1353,36 +1333,36 @@ test('toJSON looks up the JSONSerializer using the store instead of using JSONSe test('accessing attributes in the initializer should not throw an error', function(assert) { assert.expect(1); - var Person = DS.Model.extend({ + + const Person = DS.Model.extend({ name: DS.attr('string'), init() { - this._super.apply(this, arguments); + this._super(...arguments); assert.ok(!this.get('name')); } }); - var env = setupStore({ + let { store } = setupStore({ person: Person }); - var store = env.store; run(() => store.createRecord('person')); }); test('setting the id after model creation should correctly update the id', function(assert) { assert.expect(2); - var Person = DS.Model.extend({ + + const Person = DS.Model.extend({ name: DS.attr('string') }); - var env = setupStore({ + let { store } = setupStore({ person: Person }); - var store = env.store; - run(function () { - var person = store.createRecord('person'); + run(() => { + let person = store.createRecord('person'); assert.equal(person.get('id'), null, 'initial created model id should be null'); @@ -1394,17 +1374,18 @@ test('setting the id after model creation should correctly update the id', funct test('updating the id with store.updateId should correctly when the id property is watched', function(assert) { assert.expect(2); - var Person = DS.Model.extend({ + + const Person = DS.Model.extend({ name: DS.attr('string'), idComputed: Ember.computed('id', function() {}) }); - var env = setupStore({ + let { store } = setupStore({ person: Person }); - var store = env.store; - run(function () { - var person = store.createRecord('person'); + + run(() => { + let person = store.createRecord('person'); person.get('idComputed'); assert.equal(person.get('id'), null, 'initial created model id should be null'); @@ -1417,17 +1398,18 @@ test('updating the id with store.updateId should correctly when the id property test('accessing the model id without the get function should work when id is watched', function(assert) { assert.expect(2); - var Person = DS.Model.extend({ + + const Person = DS.Model.extend({ name: DS.attr('string'), idComputed: Ember.computed('id', function() {}) }); - var env = setupStore({ + let { store } = setupStore({ person: Person }); - var store = env.store; - run(function () { - var person = store.createRecord('person'); + + run(() => { + let person = store.createRecord('person'); person.get('idComputed'); assert.equal(person.get('id'), null, 'initial created model id should be null'); diff --git a/tests/unit/modules-test.js b/tests/unit/modules-test.js index b8a087dbc3c..e25b06233dc 100644 --- a/tests/unit/modules-test.js +++ b/tests/unit/modules-test.js @@ -1,86 +1,86 @@ import { module, test } from 'qunit'; -import Transform from "ember-data/transform"; +import Transform from 'ember-data/transform'; -import Adapter from "ember-data/adapter"; -import JSONAPIAdapter from "ember-data/adapters/json-api"; -import RESTAdapter from "ember-data/adapters/rest"; +import Adapter from 'ember-data/adapter'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import RESTAdapter from 'ember-data/adapters/rest'; -import Store from "ember-data/store"; +import Store from 'ember-data/store'; -import Model from "ember-data/model"; -import attr from "ember-data/attr"; -import { belongsTo, hasMany } from "ember-data/relationships"; +import Model from 'ember-data/model'; +import attr from 'ember-data/attr'; +import { belongsTo, hasMany } from 'ember-data/relationships'; -import Serializer from "ember-data/serializer"; -import JSONSerializer from "ember-data/serializers/json"; -import JSONAPISerializer from "ember-data/serializers/json-api"; -import RESTSerializer from "ember-data/serializers/rest"; -import EmbeddedRecordsMixin from "ember-data/serializers/embedded-records-mixin"; +import Serializer from 'ember-data/serializer'; +import JSONSerializer from 'ember-data/serializers/json'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; +import RESTSerializer from 'ember-data/serializers/rest'; +import EmbeddedRecordsMixin from 'ember-data/serializers/embedded-records-mixin'; import { AdapterError, InvalidError, TimeoutError, AbortError -} from "ember-data/adapters/errors"; +} from 'ember-data/adapters/errors'; -module("unit/modules - public modules"); +module('unit/modules - public modules'); -test("ember-data/transform", function(assert) { +test('ember-data/transform', function(assert) { assert.ok(Transform); }); -test("ember-data/adapter", function(assert) { +test('ember-data/adapter', function(assert) { assert.ok(Adapter); }); -test("ember-data/adapters/json-api", function(assert) { +test('ember-data/adapters/json-api', function(assert) { assert.ok(JSONAPIAdapter); }); -test("ember-data/adapters/rest", function(assert) { +test('ember-data/adapters/rest', function(assert) { assert.ok(RESTAdapter); }); -test("ember-data/attr", function(assert) { +test('ember-data/attr', function(assert) { assert.ok(attr); }); -test("ember-data/relationships", function(assert) { +test('ember-data/relationships', function(assert) { assert.ok(belongsTo); assert.ok(hasMany); }); -test("ember-data/store", function(assert) { +test('ember-data/store', function(assert) { assert.ok(Store); }); -test("ember-data/model", function(assert) { +test('ember-data/model', function(assert) { assert.ok(Model); }); -test("ember-data/mixins/embedded-records", function(assert) { +test('ember-data/mixins/embedded-records', function(assert) { assert.ok(EmbeddedRecordsMixin); }); -test("ember-data/serializer", function(assert) { +test('ember-data/serializer', function(assert) { assert.ok(Serializer); }); -test("ember-data/serializers/json-api", function(assert) { +test('ember-data/serializers/json-api', function(assert) { assert.ok(JSONAPISerializer); }); -test("ember-data/serializers/json", function(assert) { +test('ember-data/serializers/json', function(assert) { assert.ok(JSONSerializer); }); -test("ember-data/serializers/rest", function(assert) { +test('ember-data/serializers/rest', function(assert) { assert.ok(RESTSerializer); }); -test("ember-data/adapters/errors", function(assert) { +test('ember-data/adapters/errors', function(assert) { assert.ok(AdapterError); assert.ok(InvalidError); assert.ok(TimeoutError); diff --git a/tests/unit/promise-proxies-test.js b/tests/unit/promise-proxies-test.js index 5b4e272b302..0c63df1188b 100644 --- a/tests/unit/promise-proxies-test.js +++ b/tests/unit/promise-proxies-test.js @@ -9,23 +9,17 @@ module('PromiseManyArray'); test('.reload should NOT leak the internal promise, rather return another promiseArray', function(assert) { assert.expect(2); - var content = Ember.A(); + let content = Ember.A(); - content.reload = function() { - return Ember.RSVP.Promise.resolve(content); - }; + content.reload = () => Ember.RSVP.Promise.resolve(content); - var array = DS.PromiseManyArray.create({ + let array = DS.PromiseManyArray.create({ content: content }); - Ember.run(function() { - var reloaded = array.reload(); + let reloaded = array.reload(); - assert.ok(reloaded instanceof DS.PromiseManyArray); + assert.ok(reloaded instanceof DS.PromiseManyArray); - reloaded.then(function(value) { - assert.equal(content, value); - }); - }); + return reloaded.then(value => assert.equal(content, value)); }); diff --git a/tests/unit/states-test.js b/tests/unit/states-test.js index a46274c5524..abfbb1e3c94 100644 --- a/tests/unit/states-test.js +++ b/tests/unit/states-test.js @@ -3,93 +3,92 @@ import QUnit, {module, test} from 'qunit'; import DS from 'ember-data'; const { assert } = QUnit; +const { get } = Ember; -var get = Ember.get; +let rootState, stateName; -var rootState, stateName; - -module("unit/states - Flags for record states", { +module('unit/states - Flags for record states', { beforeEach() { rootState = DS.RootState; } }); assert.flagIsTrue = function flagIsTrue(flag) { - this.equal(get(rootState, stateName + "." + flag), true, stateName + "." + flag + " should be true"); + this.equal(get(rootState, stateName + '.' + flag), true, stateName + '.' + flag + ' should be true'); }; assert.flagIsFalse = function flagIsFalse(flag) { - this.equal(get(rootState, stateName + "." + flag), false, stateName + "." + flag + " should be false"); + this.equal(get(rootState, stateName + '.' + flag), false, stateName + '.' + flag + ' should be false'); }; -test("the empty state", function(assert) { - stateName = "empty"; - assert.flagIsFalse("isLoading"); - assert.flagIsFalse("isLoaded"); - assert.flagIsFalse("isDirty"); - assert.flagIsFalse("isSaving"); - assert.flagIsFalse("isDeleted"); +test('the empty state', function(assert) { + stateName = 'empty'; + assert.flagIsFalse('isLoading'); + assert.flagIsFalse('isLoaded'); + assert.flagIsFalse('isDirty'); + assert.flagIsFalse('isSaving'); + assert.flagIsFalse('isDeleted'); }); -test("the loading state", function(assert) { - stateName = "loading"; - assert.flagIsTrue("isLoading"); - assert.flagIsFalse("isLoaded"); - assert.flagIsFalse("isDirty"); - assert.flagIsFalse("isSaving"); - assert.flagIsFalse("isDeleted"); +test('the loading state', function(assert) { + stateName = 'loading'; + assert.flagIsTrue('isLoading'); + assert.flagIsFalse('isLoaded'); + assert.flagIsFalse('isDirty'); + assert.flagIsFalse('isSaving'); + assert.flagIsFalse('isDeleted'); }); -test("the loaded state", function(assert) { - stateName = "loaded"; - assert.flagIsFalse("isLoading"); - assert.flagIsTrue("isLoaded"); - assert.flagIsFalse("isDirty"); - assert.flagIsFalse("isSaving"); - assert.flagIsFalse("isDeleted"); +test('the loaded state', function(assert) { + stateName = 'loaded'; + assert.flagIsFalse('isLoading'); + assert.flagIsTrue('isLoaded'); + assert.flagIsFalse('isDirty'); + assert.flagIsFalse('isSaving'); + assert.flagIsFalse('isDeleted'); }); -test("the updated state", function(assert) { - stateName = "loaded.updated"; - assert.flagIsFalse("isLoading"); - assert.flagIsTrue("isLoaded"); - assert.flagIsTrue("isDirty"); - assert.flagIsFalse("isSaving"); - assert.flagIsFalse("isDeleted"); +test('the updated state', function(assert) { + stateName = 'loaded.updated'; + assert.flagIsFalse('isLoading'); + assert.flagIsTrue('isLoaded'); + assert.flagIsTrue('isDirty'); + assert.flagIsFalse('isSaving'); + assert.flagIsFalse('isDeleted'); }); -test("the saving state", function(assert) { - stateName = "loaded.updated.inFlight"; - assert.flagIsFalse("isLoading"); - assert.flagIsTrue("isLoaded"); - assert.flagIsTrue("isDirty"); - assert.flagIsTrue("isSaving"); - assert.flagIsFalse("isDeleted"); +test('the saving state', function(assert) { + stateName = 'loaded.updated.inFlight'; + assert.flagIsFalse('isLoading'); + assert.flagIsTrue('isLoaded'); + assert.flagIsTrue('isDirty'); + assert.flagIsTrue('isSaving'); + assert.flagIsFalse('isDeleted'); }); -test("the deleted state", function(assert) { - stateName = "deleted"; - assert.flagIsFalse("isLoading"); - assert.flagIsTrue("isLoaded"); - assert.flagIsTrue("isDirty"); - assert.flagIsFalse("isSaving"); - assert.flagIsTrue("isDeleted"); +test('the deleted state', function(assert) { + stateName = 'deleted'; + assert.flagIsFalse('isLoading'); + assert.flagIsTrue('isLoaded'); + assert.flagIsTrue('isDirty'); + assert.flagIsFalse('isSaving'); + assert.flagIsTrue('isDeleted'); }); -test("the deleted.saving state", function(assert) { - stateName = "deleted.inFlight"; - assert.flagIsFalse("isLoading"); - assert.flagIsTrue("isLoaded"); - assert.flagIsTrue("isDirty"); - assert.flagIsTrue("isSaving"); - assert.flagIsTrue("isDeleted"); +test('the deleted.saving state', function(assert) { + stateName = 'deleted.inFlight'; + assert.flagIsFalse('isLoading'); + assert.flagIsTrue('isLoaded'); + assert.flagIsTrue('isDirty'); + assert.flagIsTrue('isSaving'); + assert.flagIsTrue('isDeleted'); }); -test("the deleted.saved state", function(assert) { - stateName = "deleted.saved"; - assert.flagIsFalse("isLoading"); - assert.flagIsTrue("isLoaded"); - assert.flagIsFalse("isDirty"); - assert.flagIsFalse("isSaving"); - assert.flagIsTrue("isDeleted"); +test('the deleted.saved state', function(assert) { + stateName = 'deleted.saved'; + assert.flagIsFalse('isLoading'); + assert.flagIsTrue('isLoaded'); + assert.flagIsFalse('isDirty'); + assert.flagIsFalse('isSaving'); + assert.flagIsTrue('isDeleted'); }); diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index c637c921ec7..e1e251d87b8 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -7,27 +7,26 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var get = Ember.get; -var set = Ember.set; -var resolve = Ember.RSVP.resolve; -var TestAdapter, store, person, oldFilterEnabled; -var run = Ember.run; +const { get, set , run } = Ember; +const resolve = Ember.RSVP.resolve; +let TestAdapter, store, person, oldFilterEnabled; -module("unit/store/adapter-interop - DS.Store working with a DS.Adapter", { +module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', { beforeEach() { TestAdapter = DS.Adapter.extend(); oldFilterEnabled = Ember.ENV.ENABLE_DS_FILTER; Ember.ENV.ENABLE_DS_FILTER = false; }, + afterEach() { - run(function() { + run(() => { if (store) { store.destroy(); } Ember.ENV.ENABLE_DS_FILTER = oldFilterEnabled; }); } }); -test("Adapter can be set as a factory", function(assert) { +test('Adapter can be set as a factory', function(assert) { store = createStore({ adapter: TestAdapter }); assert.ok(store.get('defaultAdapter') instanceof TestAdapter); @@ -48,11 +47,11 @@ testInDebug('Adapter can not be set as an instance', function(assert) { assert.expectAssertion(() => store.get('defaultAdapter')); }); -test("Calling Store#find invokes its adapter#find", function(assert) { +test('Calling Store#find invokes its adapter#find', function(assert) { assert.expect(5); - let done = assert.async(); - var adapter = TestAdapter.extend({ + let currentStore; + const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { assert.ok(true, "Adapter#find was called"); assert.equal(store, currentStore, "Adapter#find was called with the right store"); @@ -60,120 +59,135 @@ test("Calling Store#find invokes its adapter#find", function(assert) { assert.equal(id, 1, "Adapter#find was called with the id passed into Store#find"); assert.equal(snapshot.id, '1', "Adapter#find was called with the record created from Store#find"); - return Ember.RSVP.resolve({ id: 1 }); + return Ember.RSVP.resolve({ + id: 1 + }); } }); - var currentType = DS.Model.extend(); - var currentStore = createStore({ adapter: adapter, test: currentType }); - + const Type = DS.Model.extend(); - run(function() { - currentStore.findRecord('test', 1).finally(done); + currentStore = createStore({ + adapter: Adapter, + test: Type }); + + return run(() => currentStore.findRecord('test', 1)); }); -test("Calling Store#findRecord multiple times coalesces the calls into a adapter#findMany call", function(assert) { +test('Calling Store#findRecord multiple times coalesces the calls into a adapter#findMany call', function(assert) { assert.expect(2); - let done = assert.async(); - var adapter = TestAdapter.extend({ + const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { - assert.ok(false, "Adapter#findRecord was not called"); + assert.ok(false, 'Adapter#findRecord was not called'); }, findMany(store, type, ids, snapshots) { - assert.ok(true, "Adapter#findMany was called"); - assert.deepEqual(ids, ["1","2"], 'Correct ids were passed in to findMany'); + assert.ok(true, 'Adapter#findMany was called'); + assert.deepEqual(ids, ['1','2'], 'Correct ids were passed in to findMany'); return Ember.RSVP.resolve([{ id: 1 }, { id: 2 }]); }, coalesceFindRequests: true }); - var currentType = DS.Model.extend(); - var currentStore = createStore({ adapter: adapter, test: currentType }); + const Type = DS.Model.extend(); + let store = createStore({ + adapter: Adapter, + test: Type + }); - run(function() { - let promises = [ - currentStore.findRecord('test', 1), - currentStore.findRecord('test', 2) - ]; - Ember.RSVP.all(promises).finally(done); + return run(() => { + return Ember.RSVP.all([ + store.findRecord('test', 1), + store.findRecord('test', 2) + ]); }); }); -test("Returning a promise from `findRecord` asynchronously loads data", function(assert) { +test('Returning a promise from `findRecord` asynchronously loads data', function(assert) { assert.expect(1); - var adapter = TestAdapter.extend({ + const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { return resolve({ id: 1, name: "Scumbag Dale" }); } }); - var currentType = DS.Model.extend({ + const Type = DS.Model.extend({ name: DS.attr('string') }); - var currentStore = createStore({ adapter: adapter, test: currentType }); - run(function() { - currentStore.findRecord('test', 1).then(assert.wait(function(object) { - assert.strictEqual(get(object, 'name'), "Scumbag Dale", "the data was pushed"); - })); + let store = createStore({ + adapter: Adapter, + test: Type + }); + + return run(() => { + return store.findRecord('test', 1).then(object => { + assert.strictEqual(get(object, 'name'), 'Scumbag Dale', 'the data was pushed'); + }); }); }); -test("IDs provided as numbers are coerced to strings", function(assert) { +test('IDs provided as numbers are coerced to strings', function(assert) { assert.expect(5); - var adapter = TestAdapter.extend({ + const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { - assert.equal(typeof id, 'string', "id has been normalized to a string"); - return resolve({ id, name: "Scumbag Sylvain" }); + assert.equal(typeof id, 'string', 'id has been normalized to a string'); + return resolve({ id, name: 'Scumbag Sylvain' }); } }); - var currentType = DS.Model.extend({ + const Type = DS.Model.extend({ name: DS.attr('string') }); - var currentStore = createStore({ adapter: adapter, test: currentType }); - run(function() { - currentStore.findRecord('test', 1).then(assert.wait(function(object) { - assert.equal(typeof object.get('id'), 'string', "id was coerced to a string"); - run(function() { - currentStore.push({ + let store = createStore({ + adapter: Adapter, + test: Type + }); + + return run(() => { + return store.findRecord('test', 1).then(object => { + assert.equal(typeof object.get('id'), 'string', 'id was coerced to a string'); + run(() => { + store.push({ data: { type: 'test', id: '2', attributes: { - name: "Scumbag Sam Saffron" + name: 'Scumbag Sam Saffron' } } }); }); - return currentStore.findRecord('test', 2); - })).then(assert.wait(function(object) { - assert.ok(object, "object was found"); - assert.equal(typeof object.get('id'), 'string', "id is a string despite being supplied and searched for as a number"); - })); + + return store.findRecord('test', 2); + }).then(object => { + assert.ok(object, 'object was found'); + assert.equal(typeof object.get('id'), 'string', 'id is a string despite being supplied and searched for as a number'); + }); }); }); -test("can load data for the same record if it is not dirty", function(assert) { +test('can load data for the same record if it is not dirty', function(assert) { assert.expect(3); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var store = createStore({ + let store = createStore({ person: Person, adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord: () => false + shouldBackgroundReloadRecord() { + return false; + } }) }); - run(function() { + return run(() => { store.push({ data: { type: 'person', @@ -184,37 +198,25 @@ test("can load data for the same record if it is not dirty", function(assert) { } }); - store.findRecord('person', 1).then(assert.wait(function(tom) { - assert.equal(get(tom, 'hasDirtyAttributes'), false, "precond - record is not dirty"); - assert.equal(get(tom, 'name'), "Tom Dale", "returns the correct name"); + return store.findRecord('person', 1).then(tom => { + assert.equal(get(tom, 'hasDirtyAttributes'), false, 'precond - record is not dirty'); + assert.equal(get(tom, 'name'), 'Tom Dale', 'returns the correct name'); store.push({ data: { type: 'person', id: '1', attributes: { - name: "Captain Underpants" + name: 'Captain Underpants' } } }); - assert.equal(get(tom, 'name'), "Captain Underpants", "updated record with new date"); - })); + assert.equal(get(tom, 'name'), 'Captain Underpants', 'updated record with new date'); + }); }); }); -/* -test("DS.Store loads individual records without explicit IDs with a custom primaryKey", function() { - var store = DS.Store.create(); - var Person = DS.Model.extend({ name: DS.attr('string'), primaryKey: 'key' }); - - store.load(Person, { key: 1, name: "Tom Dale" }); - - var tom = store.findRecord(Person, 1); - equal(get(tom, 'name'), "Tom Dale", "the person was successfully loaded for the given ID"); -}); -*/ - -test("loadMany takes an optional Object and passes it on to the Adapter", function(assert) { +test('loadMany takes an optional Object and passes it on to the Adapter', function(assert) { assert.expect(2); var passedQuery = { page: 1 }; diff --git a/tests/unit/store/asserts-test.js b/tests/unit/store/asserts-test.js index 49c3dd01fa4..5ebaaa5203c 100644 --- a/tests/unit/store/asserts-test.js +++ b/tests/unit/store/asserts-test.js @@ -2,7 +2,7 @@ import {module} from 'qunit'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {createStore} from 'dummy/tests/helpers/store'; -module("unit/store/asserts - DS.Store methods produce useful assertion messages"); +module('unit/store/asserts - DS.Store methods produce useful assertion messages'); const MODEL_NAME_METHODS = [ 'createRecord', @@ -23,12 +23,12 @@ const MODEL_NAME_METHODS = [ 'serializerFor' ]; -testInDebug("Calling Store methods with no modelName asserts", function(assert) { +testInDebug('Calling Store methods with no modelName asserts', function(assert) { assert.expect(MODEL_NAME_METHODS.length); let store = createStore(); - MODEL_NAME_METHODS.forEach(function(methodName) { - assert.expectAssertion(function() { + MODEL_NAME_METHODS.forEach(methodName =>{ + assert.expectAssertion(() => { store[methodName](null); }, new RegExp(`You need to pass a model name to the store's ${methodName} method`)); }); diff --git a/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js index 6c9b25bef39..2d6c4014c81 100644 --- a/tests/unit/store/create-record-test.js +++ b/tests/unit/store/create-record-test.js @@ -4,10 +4,10 @@ import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; -var store, Record, Storage; -var run = Ember.run; +let store, Record, Storage; +const { run } = Ember; -module("unit/store/createRecord - Store creating records", { +module('unit/store/createRecord - Store creating records', { beforeEach() { Record = DS.Model.extend({ title: DS.attr('string') @@ -26,60 +26,65 @@ module("unit/store/createRecord - Store creating records", { } }); -test("doesn't modify passed in properties hash", function(assert) { - var attributes = { foo: 'bar' }; - run(function() { +test(`doesn't modify passed in properties hash`, function(assert) { + let attributes = { foo: 'bar' }; + + run(() => { store.createRecord('record', attributes); store.createRecord('record', attributes); }); - assert.deepEqual(attributes, { foo: 'bar' }, "The properties hash is not modified"); + assert.deepEqual(attributes, { foo: 'bar' }, 'The properties hash is not modified'); }); -test("allow passing relationships as well as attributes", function(assert) { - var records, storage; - run(function() { +test('allow passing relationships as well as attributes', function(assert) { + let records, storage; + + run(() => { store.push({ - data: [{ - type: 'record', - id: '1', - attributes: { - title: "it's a beautiful day" - } - }, { - type: 'record', - id: '2', - attributes: { - title: "it's a beautiful day" + data: [ + { + type: 'record', + id: '1', + attributes: { + title: "it's a beautiful day" + } + }, + { + type: 'record', + id: '2', + attributes: { + title: "it's a beautiful day" + } } - }] + ] }); + records = store.peekAll('record'); storage = store.createRecord('storage', { name: 'Great store', records: records }); }); - assert.equal(storage.get('name'), 'Great store', "The attribute is well defined"); - assert.equal(storage.get('records').findBy('id', '1'), Ember.A(records).findBy('id', '1'), "Defined relationships are allowed in createRecord"); - assert.equal(storage.get('records').findBy('id', '2'), Ember.A(records).findBy('id', '2'), "Defined relationships are allowed in createRecord"); + assert.equal(storage.get('name'), 'Great store', 'The attribute is well defined'); + assert.equal(storage.get('records').findBy('id', '1'), Ember.A(records).findBy('id', '1'), 'Defined relationships are allowed in createRecord'); + assert.equal(storage.get('records').findBy('id', '2'), Ember.A(records).findBy('id', '2'), 'Defined relationships are allowed in createRecord'); }); -module("unit/store/createRecord - Store with models by dash", { +module('unit/store/createRecord - Store with models by dash', { beforeEach() { - var env = setupStore({ - someThing: DS.Model.extend({ foo: DS.attr('string') }) + let env = setupStore({ + someThing: DS.Model.extend({ + foo: DS.attr('string') + }) }); store = env.store; } }); -test("creating a record by dasherize string finds the model", function(assert) { - var attributes = { foo: 'bar' }; - var record; +test('creating a record by dasherize string finds the model', function(assert) { + let attributes = { foo: 'bar' }; - run(function() { - record = store.createRecord('some-thing', attributes); - }); + let record = run(() => store.createRecord('some-thing', attributes)); - assert.equal(record.get('foo'), attributes.foo, "The record is created"); + assert.equal(record.get('foo'), attributes.foo, 'The record is created'); assert.equal(store.modelFor('some-thing').modelName, 'some-thing'); }); diff --git a/tests/unit/store/has-record-for-id-test.js b/tests/unit/store/has-record-for-id-test.js index 2350f72c176..4d288bf5ae1 100644 --- a/tests/unit/store/has-record-for-id-test.js +++ b/tests/unit/store/has-record-for-id-test.js @@ -5,13 +5,11 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var env, store, Person, PhoneNumber; -var attr = DS.attr; -var hasMany = DS.hasMany; -var belongsTo = DS.belongsTo; -var run = Ember.run; +let env, store, Person, PhoneNumber; +const { attr, hasMany, belongsTo } = DS; +const { run } = Ember; -module("unit/store/hasRecordForId - Store hasRecordForId", { +module('unit/store/hasRecordForId - Store hasRecordForId', { beforeEach() { Person = DS.Model.extend({ @@ -27,7 +25,7 @@ module("unit/store/hasRecordForId - Store hasRecordForId", { env = setupStore({ person: Person, - "phone-number": PhoneNumber + 'phone-number': PhoneNumber }); store = env.store; @@ -39,9 +37,9 @@ module("unit/store/hasRecordForId - Store hasRecordForId", { } }); -test("hasRecordForId should return false for records in the empty state ", function(assert) { +test('hasRecordForId should return false for records in the empty state ', function(assert) { - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -65,8 +63,8 @@ test("hasRecordForId should return false for records in the empty state ", funct }); }); -test("hasRecordForId should return true for records in the loaded state ", function(assert) { - run(function() { +test('hasRecordForId should return true for records in the loaded state ', function(assert) { + run(() => { store.push({ data: { type: 'person', diff --git a/tests/unit/store/lookup-test.js b/tests/unit/store/lookup-test.js index a8820d59174..b5e7a450ce5 100644 --- a/tests/unit/store/lookup-test.js +++ b/tests/unit/store/lookup-test.js @@ -5,8 +5,8 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var store, env, applicationAdapter, applicationSerializer, Person; -const run = Ember.run; +let store, env, applicationAdapter, applicationSerializer, Person; +const { run } = Ember; function resetStore() { if (store) { @@ -139,4 +139,3 @@ test('serializer lookup order', (assert) => { assert.ok(personSerializer.get('customThingy'), 'uses the person serializer before any fallbacks if it is defined'); }); - diff --git a/tests/unit/store/model-for-test.js b/tests/unit/store/model-for-test.js index d6d7130f7ee..6b337200da1 100644 --- a/tests/unit/store/model-for-test.js +++ b/tests/unit/store/model-for-test.js @@ -5,19 +5,16 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var container, store, registry; +let container, store, registry, env; -var camelize = Ember.String.camelize; -var dasherize = Ember.String.dasherize; +const { camelize, dasherize } = Ember.String; +const { run } = Ember; -var run = Ember.run; -var env; - -module("unit/store/model_for - DS.Store#modelFor", { +module('unit/store/model_for - DS.Store#modelFor', { beforeEach() { env = setupStore({ blogPost: DS.Model.extend(), - "blog.post": DS.Model.extend() + 'blog.post': DS.Model.extend() }); store = env.store; container = env.container; @@ -25,32 +22,29 @@ module("unit/store/model_for - DS.Store#modelFor", { }, afterEach() { - run(function() { + run(() => { container.destroy(); store.destroy(); }); } }); -test("when fetching factory from string, sets a normalized key as modelName", function(assert) { - env.replaceContainerNormalize(function(key) { - return dasherize(camelize(key)); - }); +test('when fetching factory from string, sets a normalized key as modelName', function(assert) { + env.replaceContainerNormalize(key => dasherize(camelize(key))); assert.equal(registry.normalize('some.post'), 'some-post', 'precond - container camelizes'); - assert.equal(store.modelFor("blog.post").modelName, "blog.post", "modelName is normalized to dasherized"); + assert.equal(store.modelFor('blog.post').modelName, 'blog.post', 'modelName is normalized to dasherized'); }); -test("when fetching factory from string and dashing normalizer, sets a normalized key as modelName", function(assert) { - env.replaceContainerNormalize(function(key) { - return dasherize(camelize(key)); - }); +test('when fetching factory from string and dashing normalizer, sets a normalized key as modelName', function(assert) { + env.replaceContainerNormalize(key => dasherize(camelize(key))); + assert.equal(registry.normalize('some.post'), 'some-post', 'precond - container dasherizes'); assert.equal(store.modelFor("blog.post").modelName, "blog.post", "modelName is normalized to dasherized"); }); -test("when fetching something that doesn't exist, throws error", function(assert) { - assert.throws(function() { +test(`when fetching something that doesn't exist, throws error`, function(assert) { + assert.throws(() => { store.modelFor('wild-stuff'); }, /No model was found/); }); diff --git a/tests/unit/store/peek-record-test.js b/tests/unit/store/peek-record-test.js index 2c38ed3b86c..490ee94fe00 100644 --- a/tests/unit/store/peek-record-test.js +++ b/tests/unit/store/peek-record-test.js @@ -5,17 +5,17 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var env, store, Person; -var run = Ember.run; +let env, store, Person; +const { run } = Ember; -module("unit/store/peekRecord - Store peekRecord", { +module('unit/store/peekRecord - Store peekRecord', { beforeEach() { - Person = DS.Model.extend(); env = setupStore({ person: Person }); + store = env.store; }, @@ -24,9 +24,9 @@ module("unit/store/peekRecord - Store peekRecord", { } }); -test("peekRecord should return the record if it is in the store ", function(assert) { - run(function() { - var person = store.push({ +test('peekRecord should return the record if it is in the store ', function(assert) { + run(() => { + let person = store.push({ data: { type: 'person', id: '1' @@ -36,8 +36,8 @@ test("peekRecord should return the record if it is in the store ", function(asse }); }); -test("peekRecord should return null if the record is not in the store ", function(assert) { - run(function() { +test('peekRecord should return null if the record is not in the store ', function(assert) { + run(() => { assert.equal(null, store.peekRecord('person', 1), 'peekRecord returns null if the corresponding record is not in the store'); }); }); diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index 040eadf2d4b..b725de1c3d2 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -8,13 +8,11 @@ import DS from 'ember-data'; import isEnabled from 'ember-data/-private/features'; -var env, store, Person, PhoneNumber, Post; -var attr = DS.attr; -var hasMany = DS.hasMany; -var belongsTo = DS.belongsTo; -var run = Ember.run; +let env, store, Person, PhoneNumber, Post; +const { attr, hasMany, belongsTo } = DS; +const { run } = Ember; -module("unit/store/push - DS.Store#push", { +module('unit/store/push - DS.Store#push', { beforeEach() { Person = DS.Model.extend({ firstName: attr('string'), @@ -43,17 +41,13 @@ module("unit/store/push - DS.Store#push", { }, afterEach() { - run(function() { - store.destroy(); - }); + run(store, 'destroy'); } }); test('Changed attributes are reset when matching data is pushed', function(assert) { - var person; - - run(function() { - person = store.push({ + let person = run(() => { + return store.push({ data: { type: 'person', id: 1, @@ -67,16 +61,14 @@ test('Changed attributes are reset when matching data is pushed', function(asser assert.equal(person.get('firstName'), 'original first name'); assert.equal(person.get('currentState.stateName'), 'root.loaded.saved'); - run(function() { - person.set('firstName', 'updated first name'); - }); + run(() => person.set('firstName', 'updated first name')); assert.equal(person.get('firstName'), 'updated first name'); assert.equal(person.get('lastName'), undefined); assert.equal(person.get('currentState.stateName'), 'root.loaded.updated.uncommitted'); assert.deepEqual(person.changedAttributes().firstName, ['original first name', 'updated first name']); - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -93,12 +85,12 @@ test('Changed attributes are reset when matching data is pushed', function(asser assert.ok(!person.changedAttributes().firstName); }); -test("Calling push with a normalized hash returns a record", function(assert) { +test('Calling push with a normalized hash returns a record', function(assert) { assert.expect(2); env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { - var person = store.push({ + return run(() => { + let person = store.push({ data: { type: 'person', id: 'wat', @@ -108,8 +100,9 @@ test("Calling push with a normalized hash returns a record", function(assert) { } } }); - store.findRecord('person', 'wat').then(function(foundPerson) { - assert.equal(foundPerson, person, "record returned via load() is the same as the record returned from findRecord()"); + + return store.findRecord('person', 'wat').then(foundPerson => { + assert.equal(foundPerson, person, 'record returned via load() is the same as the record returned from findRecord()'); assert.deepEqual(foundPerson.getProperties('id', 'firstName', 'lastName'), { id: 'wat', firstName: 'Yehuda', @@ -119,14 +112,14 @@ test("Calling push with a normalized hash returns a record", function(assert) { }); }); -test("Supplying a model class for `push` is the same as supplying a string", function(assert) { +test('Supplying a model class for `push` is the same as supplying a string', function(assert) { assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; - var Programmer = Person.extend(); + const Programmer = Person.extend(); env.registry.register('model:programmer', Programmer); - run(function() { + return run(() => { store.push({ data: { type: 'programmer', @@ -138,7 +131,7 @@ test("Supplying a model class for `push` is the same as supplying a string", fun } }); - store.findRecord('programmer', 'wat').then(function(foundProgrammer) { + return store.findRecord('programmer', 'wat').then(foundProgrammer => { assert.deepEqual(foundProgrammer.getProperties('id', 'firstName', 'lastName'), { id: 'wat', firstName: 'Yehuda', @@ -148,16 +141,23 @@ test("Supplying a model class for `push` is the same as supplying a string", fun }); }); -test("Calling push triggers `didLoad` even if the record hasn't been requested from the adapter", function(assert) { +test(`Calling push triggers 'didLoad' even if the record hasn't been requested from the adapter`, function(assert) { assert.expect(1); - Person.reopen({ - didLoad: assert.wait(function() { - assert.ok(true, "The didLoad callback was called"); - }) + let didLoad = new Ember.RSVP.Promise((resolve, reject) => { + Person.reopen({ + didLoad() { + try { + assert.ok(true, 'The didLoad callback was called'); + resolve(); + } catch (e) { + reject(e); + } + } + }); }); - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -169,13 +169,15 @@ test("Calling push triggers `didLoad` even if the record hasn't been requested f } }); }); + + return didLoad; }); -test("Calling push with partial records updates just those attributes", function(assert) { +test('Calling push with partial records updates just those attributes', function(assert) { assert.expect(2); env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + return run(() => { store.push({ data: { type: 'person', @@ -186,7 +188,8 @@ test("Calling push with partial records updates just those attributes", function } } }); - var person = store.peekRecord('person', 'wat'); + + let person = store.peekRecord('person', 'wat'); store.push({ data: { @@ -198,8 +201,8 @@ test("Calling push with partial records updates just those attributes", function } }); - store.findRecord('person', 'wat').then(function(foundPerson) { - assert.equal(foundPerson, person, "record returned via load() is the same as the record returned from findRecord()"); + return store.findRecord('person', 'wat').then(foundPerson => { + assert.equal(foundPerson, person, 'record returned via load() is the same as the record returned from findRecord()'); assert.deepEqual(foundPerson.getProperties('id', 'firstName', 'lastName'), { id: 'wat', firstName: 'Yehuda', @@ -209,11 +212,11 @@ test("Calling push with partial records updates just those attributes", function }); }); -test("Calling push on normalize allows partial updates with raw JSON", function(assert) { +test('Calling push on normalize allows partial updates with raw JSON', function(assert) { env.registry.register('serializer:person', DS.RESTSerializer); - var person; + let person; - run(function() { + run(() => { person = store.push({ data: { type: 'person', @@ -231,19 +234,22 @@ test("Calling push on normalize allows partial updates with raw JSON", function( })); }); - assert.equal(person.get('firstName'), "Jacquie", "you can push raw JSON into the store"); - assert.equal(person.get('lastName'), "Jackson", "existing fields are untouched"); + assert.equal(person.get('firstName'), 'Jacquie', 'you can push raw JSON into the store'); + assert.equal(person.get('lastName'), 'Jackson', 'existing fields are untouched'); }); -test("Calling push with a normalized hash containing IDs of related records returns a record", function(assert) { +test('Calling push with a normalized hash containing IDs of related records returns a record', function(assert) { assert.expect(1); Person.reopen({ - phoneNumbers: hasMany('phone-number', { async: true }) + phoneNumbers: + hasMany('phone-number', { + async: true + }) }); env.adapter.findRecord = function(store, type, id) { - if (id === "1") { + if (id === '1') { return Ember.RSVP.resolve({ id: 1, number: '5551212', @@ -259,33 +265,36 @@ test("Calling push with a normalized hash containing IDs of related records retu }); } }; - var person; - run(function() { - person = store.push(store.normalize('person', { + return run(() => { + let person = store.push(store.normalize('person', { id: 'wat', firstName: 'John', lastName: 'Smith', phoneNumbers: ["1", "2"] })); - person.get('phoneNumbers').then(function(phoneNumbers) { - assert.deepEqual(phoneNumbers.map(function(item) { + + return person.get('phoneNumbers').then(phoneNumbers => { + assert.deepEqual(phoneNumbers.map(item => { return item.getProperties('id', 'number', 'person'); - }), [{ - id: "1", - number: '5551212', - person: person - }, { - id: "2", - number: '5552121', - person: person - }]); + }), [ + { + id: '1', + number: '5551212', + person: person + }, + { + id: '2', + number: '5552121', + person: person + } + ]); }); }); }); -test("Calling pushPayload allows pushing raw JSON", function(assert) { - run(function() { +test('Calling pushPayload allows pushing raw JSON', function(assert) { + run(() => { store.pushPayload('post', { posts: [{ id: '1', @@ -294,176 +303,184 @@ test("Calling pushPayload allows pushing raw JSON", function(assert) { }); }); - var post = store.peekRecord('post', 1); + let post = store.peekRecord('post', 1); - assert.equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); + assert.equal(post.get('postTitle'), 'Ember rocks', 'you can push raw JSON into the store'); - run(function() { + run(() => { store.pushPayload('post', { posts: [{ id: '1', - postTitle: "Ember rocks (updated)" + postTitle: 'Ember rocks (updated)' }] }); }); - assert.equal(post.get('postTitle'), "Ember rocks (updated)", "You can update data in the store"); + assert.equal(post.get('postTitle'), 'Ember rocks (updated)', 'You can update data in the store'); }); -test("Calling pushPayload allows pushing singular payload properties", function(assert) { - run(function() { +test('Calling pushPayload allows pushing singular payload properties', function(assert) { + run(() => { store.pushPayload('post', { post: { id: '1', - postTitle: "Ember rocks" + postTitle: 'Ember rocks' } }); }); - var post = store.peekRecord('post', 1); + let post = store.peekRecord('post', 1); - assert.equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); + assert.equal(post.get('postTitle'), 'Ember rocks', 'you can push raw JSON into the store'); - run(function() { + run(() => { store.pushPayload('post', { post: { id: '1', - postTitle: "Ember rocks (updated)" + postTitle: 'Ember rocks (updated)' } }); }); - assert.equal(post.get('postTitle'), "Ember rocks (updated)", "You can update data in the store"); + assert.equal(post.get('postTitle'), 'Ember rocks (updated)', 'You can update data in the store'); }); -test("Calling pushPayload should use the type's serializer for normalizing", function(assert) { +test(`Calling pushPayload should use the type's serializer for normalizing`, function(assert) { assert.expect(4); + env.registry.register('serializer:post', DS.RESTSerializer.extend({ - normalize(store, payload) { - assert.ok(true, "normalized is called on Post serializer"); - return this._super(store, payload); + normalize() { + assert.ok(true, 'normalized is called on Post serializer'); + return this._super(...arguments); } })); + env.registry.register('serializer:person', DS.RESTSerializer.extend({ - normalize(store, payload) { - assert.ok(true, "normalized is called on Person serializer"); - return this._super(store, payload); + normalize() { + assert.ok(true, 'normalized is called on Person serializer'); + return this._super(...arguments); } })); - run(function() { + run(() => { store.pushPayload('post', { - posts: [{ - id: 1, - postTitle: "Ember rocks" - }], - people: [{ - id: 2, - firstName: "Yehuda" - }] + posts: [ + { + id: 1, + postTitle: 'Ember rocks' + } + ], + people: [ + { + id: 2, + firstName: 'Yehuda' + } + ] }); }); - var post = store.peekRecord('post', 1); + let post = store.peekRecord('post', 1); - assert.equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); + assert.equal(post.get('postTitle'), 'Ember rocks', 'you can push raw JSON into the store'); - var person = store.peekRecord('person', 2); + let person = store.peekRecord('person', 2); - assert.equal(person.get('firstName'), "Yehuda", "you can push raw JSON into the store"); + assert.equal(person.get('firstName'), 'Yehuda', 'you can push raw JSON into the store'); }); -test("Calling pushPayload without a type uses application serializer's pushPayload method", function(assert) { +test(`Calling pushPayload without a type uses application serializer's pushPayload method`, function(assert) { assert.expect(1); env.registry.register('serializer:application', DS.RESTSerializer.extend({ - pushPayload(store, payload) { - assert.ok(true, "pushPayload is called on Application serializer"); - return this._super(store, payload); + pushPayload() { + assert.ok(true, `pushPayload is called on Application serializer`); + return this._super(...arguments); } })); - run(function() { + run(() => { store.pushPayload({ - posts: [{ id: '1', postTitle: "Ember rocks" }] + posts: [{ id: '1', postTitle: 'Ember rocks' }] }); }); }); -test("Calling pushPayload without a type should use a model's serializer when normalizing", function(assert) { +test(`Calling pushPayload without a type should use a model's serializer when normalizing`, function(assert) { assert.expect(4); env.registry.register('serializer:post', DS.RESTSerializer.extend({ - normalize(store, payload) { - assert.ok(true, "normalized is called on Post serializer"); - return this._super(store, payload); + normalize() { + assert.ok(true, 'normalized is called on Post serializer'); + return this._super(...arguments); } })); env.registry.register('serializer:application', DS.RESTSerializer.extend({ - normalize(store, payload) { - assert.ok(true, "normalized is called on Application serializer"); - return this._super(store, payload); + normalize() { + assert.ok(true, 'normalized is called on Application serializer'); + return this._super(...arguments); } })); - run(function() { + run(() => { store.pushPayload({ - posts: [{ - id: '1', - postTitle: "Ember rocks" - }], - people: [{ - id: '2', - firstName: 'Yehuda' - }] + posts: [ + { + id: '1', + postTitle: 'Ember rocks' + } + ], + people: [ + { + id: '2', + firstName: 'Yehuda' + } + ] }); }); var post = store.peekRecord('post', 1); - assert.equal(post.get('postTitle'), "Ember rocks", "you can push raw JSON into the store"); + assert.equal(post.get('postTitle'), 'Ember rocks', 'you can push raw JSON into the store'); var person = store.peekRecord('person', 2); - assert.equal(person.get('firstName'), "Yehuda", "you can push raw JSON into the store"); + assert.equal(person.get('firstName'), 'Yehuda', 'you can push raw JSON into the store'); }); -test("Calling pushPayload allows partial updates with raw JSON", function(assert) { +test('Calling pushPayload allows partial updates with raw JSON', function(assert) { env.registry.register('serializer:person', DS.RESTSerializer); - var person; - - run(function() { + run(() => { store.pushPayload('person', { people: [{ id: '1', - firstName: "Robert", - lastName: "Jackson" + firstName: 'Robert', + lastName: 'Jackson' }] }); }); - person = store.peekRecord('person', 1); + let person = store.peekRecord('person', 1); - assert.equal(person.get('firstName'), "Robert", "you can push raw JSON into the store"); - assert.equal(person.get('lastName'), "Jackson", "you can push raw JSON into the store"); + assert.equal(person.get('firstName'), 'Robert', 'you can push raw JSON into the store'); + assert.equal(person.get('lastName'), 'Jackson', 'you can push raw JSON into the store'); - run(function() { + run(() => { store.pushPayload('person', { people: [{ id: '1', - firstName: "Jacquie" + firstName: 'Jacquie' }] }); }); - assert.equal(person.get('firstName'), "Jacquie", "you can push raw JSON into the store"); - assert.equal(person.get('lastName'), "Jackson", "existing fields are untouched"); + assert.equal(person.get('firstName'), 'Jacquie', 'you can push raw JSON into the store'); + assert.equal(person.get('lastName'), 'Jackson', 'existing fields are untouched'); }); test('calling push without data argument as an object raises an error', function(assert) { - var invalidValues = [ + let invalidValues = [ null, 1, 'string', @@ -474,9 +491,9 @@ test('calling push without data argument as an object raises an error', function assert.expect(invalidValues.length); - invalidValues.forEach(function(invalidValue) { - assert.throws(function() { - run(function() { + invalidValues.forEach((invalidValue) => { + assert.throws(() => { + run(() => { store.push('person', invalidValue); }); }, /object/); @@ -488,8 +505,8 @@ testInDebug('Calling push with a link for a non async relationship should warn i phoneNumbers: hasMany('phone-number', { async: false }) }); - assert.expectWarning(function() { - run(function() { + assert.expectWarning(() => { + run(() => { store.push({ data: { type: 'person', @@ -512,8 +529,8 @@ testInDebug('Calling push with a link for a non async relationship should not wa phoneNumbers: hasMany('phone-number', { async: false }) }); - assert.expectNoWarning(function() { - run(function() { + assert.expectNoWarning(() => { + run(() => { store.push({ data: { type: 'person', @@ -536,9 +553,8 @@ testInDebug('Calling push with a link for a non async relationship should not wa }); testInDebug('Calling push with an unknown model name throws an assertion error', function(assert) { - - assert.expectAssertion(function() { - run(function() { + assert.expectAssertion(() => { + run(() => { store.push({ data: { id: '1', @@ -554,7 +570,7 @@ test('Calling push with a link containing an object', function(assert) { phoneNumbers: hasMany('phone-number', { async: true }) }); - run(function() { + run(() => { store.push(store.normalize('person', { id: '1', firstName: 'Tan', @@ -566,13 +582,13 @@ test('Calling push with a link containing an object', function(assert) { })); }); - var person = store.peekRecord('person', 1); + let person = store.peekRecord('person', 1); - assert.equal(person.get('firstName'), "Tan", "you can use links containing an object"); + assert.equal(person.get('firstName'), 'Tan', 'you can use links containing an object'); }); test('Calling push with a link containing the value null', function(assert) { - run(function() { + run(() => { store.push(store.normalize('person', { id: '1', firstName: 'Tan', @@ -582,13 +598,13 @@ test('Calling push with a link containing the value null', function(assert) { })); }); - var person = store.peekRecord('person', 1); + let person = store.peekRecord('person', 1); - assert.equal(person.get('firstName'), "Tan", "you can use links that contain null as a value"); + assert.equal(person.get('firstName'), 'Tan', 'you can use links that contain null as a value'); }); testInDebug('calling push with hasMany relationship the value must be an array', function(assert) { - var invalidValues = [ + let invalidValues = [ 1, 'string', Ember.Object.create(), @@ -598,10 +614,10 @@ testInDebug('calling push with hasMany relationship the value must be an array', assert.expect(invalidValues.length); - invalidValues.forEach(function(invalidValue) { - assert.throws(function() { + invalidValues.forEach(invalidValue => { + assert.throws(() => { try { - run(function () { + run(() => { store.push({ data: { type: 'person', @@ -623,7 +639,7 @@ testInDebug('calling push with hasMany relationship the value must be an array', }); testInDebug('calling push with missing or invalid `id` throws assertion error', function(assert) { - var invalidValues = [ + let invalidValues = [ {}, { id: null }, { id: '' } @@ -631,9 +647,9 @@ testInDebug('calling push with missing or invalid `id` throws assertion error', assert.expect(invalidValues.length); - invalidValues.forEach(function(invalidValue) { - assert.throws(function() { - run(function() { + invalidValues.forEach(invalidValue => { + assert.throws(() => { + run(() => { store.push({ data: invalidValue }); @@ -643,8 +659,8 @@ testInDebug('calling push with missing or invalid `id` throws assertion error', }); testInDebug('calling push with belongsTo relationship the value must not be an array', function(assert) { - assert.throws(function() { - run(function() { + assert.throws(() => { + run(() => { store.push({ data: { type: 'phone-number', @@ -660,12 +676,12 @@ testInDebug('calling push with belongsTo relationship the value must not be an a }, /must not be an array/); }); -testInDebug("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown attributes", function(assert) { - run(function() { - var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; +testInDebug('Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown attributes', function(assert) { + run(() => { + let originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; try { Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; - assert.expectWarning(function() { + assert.expectWarning(() => { store.push({ data: { type: 'person', @@ -677,19 +693,19 @@ testInDebug("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown a } } }); - }, "The payload for 'person' contains these unknown attributes: emailAddress,isMascot. Make sure they've been defined in your model."); + }, `The payload for 'person' contains these unknown attributes: emailAddress,isMascot. Make sure they've been defined in your model.`); } finally { Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = originalFlagValue; } }); }); -testInDebug("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown relationships", function(assert) { - run(function() { +testInDebug('Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown relationships', function(assert) { + run(() => { var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; try { Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; - assert.expectWarning(function() { + assert.expectWarning(() => { store.push({ data: { type: 'person', @@ -701,16 +717,16 @@ testInDebug("Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown r } } }); - }, "The payload for 'person' contains these unknown relationships: emailAddresses,mascots. Make sure they've been defined in your model."); + }, `The payload for 'person' contains these unknown relationships: emailAddresses,mascots. Make sure they've been defined in your model.`); } finally { Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = originalFlagValue; } }); }); -testInDebug("Calling push with unknown keys should not warn by default", function(assert) { - assert.expectNoWarning(function() { - run(function() { +testInDebug('Calling push with unknown keys should not warn by default', function(assert) { + assert.expectNoWarning(() => { + run(() => { store.push({ data: { type: 'person', @@ -730,35 +746,33 @@ if (isEnabled('ds-pushpayload-return')) { test("Calling pushPayload returns records", function(assert) { env.registry.register('serializer:person', DS.RESTSerializer); - var people; - - run(function() { - people = store.pushPayload('person', { + let people = run(() => { + return store.pushPayload('person', { people: [{ id: '1', - firstName: "Robert", - lastName: "Jackson" + firstName: 'Robert', + lastName: 'Jackson' }, { id: '2', - firstName: "Matthew", - lastName: "Beale" + firstName: 'Matthew', + lastName: 'Beale' }] }); }); - assert.equal(people.length, 2, "both records were returned by `store.pushPayload`"); + assert.equal(people.length, 2, 'both records were returned by `store.pushPayload`'); - assert.equal(people[0].get('firstName'), "Robert", "pushPayload returns pushed records"); - assert.equal(people[0].get('lastName'), "Jackson", "pushPayload returns pushed records"); - assert.equal(people[1].get('firstName'), "Matthew", "pushPayload returns pushed records"); - assert.equal(people[1].get('lastName'), "Beale", "pushPayload returns pushed records"); + assert.equal(people[0].get('firstName'), 'Robert', 'pushPayload returns pushed records'); + assert.equal(people[0].get('lastName'), 'Jackson', 'pushPayload returns pushed records'); + assert.equal(people[1].get('firstName'), 'Matthew', 'pushPayload returns pushed records'); + assert.equal(people[1].get('lastName'), 'Beale', 'pushPayload returns pushed records'); }); } -test("_push returns an instance of InternalModel if an object is pushed", function(assert) { +test('_push returns an instance of InternalModel if an object is pushed', function(assert) { let pushResult; - run(function() { + run(() => { pushResult = store._push({ data: { id: 1, @@ -771,11 +785,13 @@ test("_push returns an instance of InternalModel if an object is pushed", functi assert.notOk(pushResult.record, 'InternalModel is not materialized'); }); -test("_push does not require a modelName to resolve to a modelClass", function(assert) { +test('_push does not require a modelName to resolve to a modelClass', function(assert) { let originalCall = store.modelFor; - store.modelFor = () => { assert.notOk('modelFor was triggered as a result of a call to store._push'); }; + store.modelFor = function() { + assert.notOk('modelFor was triggered as a result of a call to store._push'); + }; - run(function() { + run(() => { store._push({ data: { id: 1, @@ -788,10 +804,10 @@ test("_push does not require a modelName to resolve to a modelClass", function(a assert.ok('We made it'); }); -test("_push returns an array of InternalModels if an array is pushed", function(assert) { +test('_push returns an array of InternalModels if an array is pushed', function(assert) { let pushResult; - run(function() { + run(() => { pushResult = store._push({ data: [{ id: 1, @@ -806,10 +822,10 @@ test("_push returns an array of InternalModels if an array is pushed", function( }); -test("_push returns null if no data is pushed", function(assert) { +test('_push returns null if no data is pushed', function(assert) { let pushResult; - run(function() { + run(() => { pushResult = store._push({ data: null }); @@ -818,14 +834,14 @@ test("_push returns null if no data is pushed", function(assert) { assert.strictEqual(pushResult, null); }); -module("unit/store/push - DS.Store#push with JSON-API", { +module('unit/store/push - DS.Store#push with JSON-API', { beforeEach() { - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), cars: DS.hasMany('car', { async: false }) }); - var Car = DS.Model.extend({ + const Car = DS.Model.extend({ make: DS.attr('string'), model: DS.attr('string'), person: DS.belongsTo('person', { async: false }) @@ -836,87 +852,92 @@ module("unit/store/push - DS.Store#push with JSON-API", { car: Car, person: Person }); - store = env.store; + store = env.store; }, afterEach() { - run(function() { - store.destroy(); - }); + run(store, 'destroy'); } }); - -test("Should support pushing multiple models into the store", function(assert) { +test('Should support pushing multiple models into the store', function(assert) { assert.expect(2); - run(function() { + run(() => { store.push({ - data: [{ - type: 'person', - id: 1, - attributes: { - name: 'Tom Dale' - } - }, { - type: 'person', - id: 2, - attributes: { - name: "Tomster" - } - }] + data: [ + { + type: 'person', + id: 1, + attributes: { + name: 'Tom Dale' + } + }, + { + type: 'person', + id: 2, + attributes: { + name: "Tomster" + } + }] }); }); - var tom = store.peekRecord('person', 1); + let tom = store.peekRecord('person', 1); assert.equal(tom.get('name'), 'Tom Dale', 'Tom should be in the store'); - var tomster = store.peekRecord('person', 2); + let tomster = store.peekRecord('person', 2); assert.equal(tomster.get('name'), 'Tomster', 'Tomster should be in the store'); }); -test("Should support pushing included models into the store", function(assert) { +test('Should support pushing included models into the store', function(assert) { assert.expect(2); - run(function() { + run(() => { store.push({ - data: [{ - type: 'person', - id: 1, - attributes: { - name: 'Tomster' - }, - relationships: { - cars: [{ - data: { - type: 'person', id: 1 - } - }] + data: [ + { + type: 'person', + id: 1, + attributes: { + name: 'Tomster' + }, + relationships: { + cars: [ + { + data: { + type: 'person', id: 1 + } + } + ] + } } - }], - included: [{ - type: 'car', - id: 1, - attributes: { - make: 'Dodge', - model: 'Neon' - }, - relationships: { - person: { - data: { - id: 1, type: 'person' + ], + included: [ + { + type: 'car', + id: 1, + attributes: { + make: 'Dodge', + model: 'Neon' + }, + relationships: { + person: { + data: { + id: 1, type: 'person' + } } } } - }] + ] }); }); - var tomster = store.peekRecord('person', 1); + let tomster = store.peekRecord('person', 1); assert.equal(tomster.get('name'), 'Tomster', 'Tomster should be in the store'); - var car = store.peekRecord('car', 1); + let car = store.peekRecord('car', 1); assert.equal(car.get('model'), 'Neon', 'Tomster\'s car should be in the store'); }); diff --git a/tests/unit/store/serialize-test.js b/tests/unit/store/serialize-test.js index b90c64a0eea..231f076a81c 100644 --- a/tests/unit/store/serialize-test.js +++ b/tests/unit/store/serialize-test.js @@ -16,7 +16,7 @@ if (isEnabled('ds-deprecate-store-serialize')) { person: Model.extend({ firstName: attr() }) }); - run(function() { + run(() => { let person = store.push({ data: { type: 'person', @@ -26,7 +26,8 @@ if (isEnabled('ds-deprecate-store-serialize')) { } } }); - assert.expectDeprecation("Use of store.serialize is deprecated, use record.serialize instead."); + + assert.expectDeprecation('Use of store.serialize is deprecated, use record.serialize instead.'); store.serialize(person); }); diff --git a/tests/unit/store/serializer-for-test.js b/tests/unit/store/serializer-for-test.js index 701e85b3a65..6206ffd4b8c 100644 --- a/tests/unit/store/serializer-for-test.js +++ b/tests/unit/store/serializer-for-test.js @@ -6,10 +6,10 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var container, store, registry, Person; -var run = Ember.run; +let container, store, registry, Person; +const { run } = Ember; -module("unit/store/serializer_for - DS.Store#serializerFor", { +module('unit/store/serializer_for - DS.Store#serializerFor', { beforeEach() { Person = DS.Model.extend({}); var env = setupStore({ person: Person }); @@ -19,35 +19,35 @@ module("unit/store/serializer_for - DS.Store#serializerFor", { }, afterEach() { - run(function() { + run(() => { container.destroy(); store.destroy(); }); } }); -test("Calling serializerFor looks up 'serializer:' from the container", function(assert) { - var PersonSerializer = DS.JSONSerializer.extend(); +test('Calling serializerFor looks up `serializer:` from the container', function(assert) { + const PersonSerializer = DS.JSONSerializer.extend(); registry.register('serializer:person', PersonSerializer); - assert.ok(store.serializerFor('person') instanceof PersonSerializer, "serializer returned from serializerFor is an instance of the registered Serializer class"); + assert.ok(store.serializerFor('person') instanceof PersonSerializer, 'serializer returned from serializerFor is an instance of the registered Serializer class'); }); -test("Calling serializerFor with a type that has not been registered looks up the default ApplicationSerializer", function(assert) { - var ApplicationSerializer = DS.JSONSerializer.extend(); +test('Calling serializerFor with a type that has not been registered looks up the default ApplicationSerializer', function(assert) { + const ApplicationSerializer = DS.JSONSerializer.extend(); registry.register('serializer:application', ApplicationSerializer); - assert.ok(store.serializerFor('person') instanceof ApplicationSerializer, "serializer returned from serializerFor is an instance of ApplicationSerializer"); + assert.ok(store.serializerFor('person') instanceof ApplicationSerializer, 'serializer returned from serializerFor is an instance of ApplicationSerializer'); }); -test("Calling serializerFor with a type that has not been registered and in an application that does not have an ApplicationSerializer looks up the default Ember Data serializer", function(assert) { - assert.ok(store.serializerFor('person') instanceof DS.JSONSerializer, "serializer returned from serializerFor is an instance of DS.JSONSerializer"); +test('Calling serializerFor with a type that has not been registered and in an application that does not have an ApplicationSerializer looks up the default Ember Data serializer', function(assert) { + assert.ok(store.serializerFor('person') instanceof DS.JSONSerializer, 'serializer returned from serializerFor is an instance of DS.JSONSerializer'); }); -testInDebug("Calling serializerFor with a model class should assert", function(assert) { - assert.expectAssertion(function() { +testInDebug('Calling serializerFor with a model class should assert', function(assert) { + assert.expectAssertion(() => { store.serializerFor(Person); }, /Passing classes to store.serializerFor has been removed/); }); diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index fc6a4875be6..3e711eca777 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -6,18 +6,22 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var get = Ember.get; -var run = Ember.run; -var store, tryToFind, Record; +const { get, run } = Ember; +let store, tryToFind, Record; -module("unit/store/unload - Store unloading records", { +module('unit/store/unload - Store unloading records', { beforeEach() { Record = DS.Model.extend({ title: DS.attr('string'), wasFetched: DS.attr('boolean') }); - Record.reopenClass({ toString: () => 'Record'}); + + Record.reopenClass({ + toString() { + return 'Record'; + } + }); store = createStore({ adapter: DS.Adapter.extend({ @@ -26,6 +30,7 @@ module("unit/store/unload - Store unloading records", { return Ember.RSVP.resolve({ id: id, wasFetched: true }); } }), + record: Record }); }, @@ -35,10 +40,10 @@ module("unit/store/unload - Store unloading records", { } }); -testInDebug("unload a dirty record asserts", function(assert) { +testInDebug('unload a dirty record asserts', function(assert) { assert.expect(2); - run(function() { + run(() => { store.push({ data: { type: 'record', @@ -50,6 +55,7 @@ testInDebug("unload a dirty record asserts", function(assert) { }); let record = store.peekRecord('record', 1); + record.set('title', 'toto2'); record._internalModel.send('willCommit'); @@ -57,10 +63,10 @@ testInDebug("unload a dirty record asserts", function(assert) { assert.expectAssertion(function() { record.unloadRecord(); - }, "You can only unload a record which is not inFlight. `" + record._internalModel.toString() + "`", "can not unload dirty record"); + }, 'You can only unload a record which is not inFlight. `' + record._internalModel.toString() + '`', 'can not unload dirty record'); // force back into safe to unload mode. - run(function() { + run(() => { record._internalModel.transitionTo('deleted.saved'); }); }); @@ -69,7 +75,7 @@ testInDebug("unload a dirty record asserts", function(assert) { test('unload a record', function(assert) { assert.expect(2); - run(function() { + return run(() => { store.push({ data: { type: 'record', @@ -79,16 +85,16 @@ test('unload a record', function(assert) { } } }); - store.findRecord('record', 1).then(function(record) { - assert.equal(get(record, 'id'), 1, "found record with id 1"); - run(function() { - store.unloadRecord(record); - }); + return store.findRecord('record', 1).then(record => { + assert.equal(get(record, 'id'), 1, 'found record with id 1'); + + run(() => store.unloadRecord(record)); tryToFind = false; - return store.findRecord('record', 1).then(function() { - assert.equal(tryToFind, true, "not found record with id 1"); + + return store.findRecord('record', 1).then(() => { + assert.equal(tryToFind, true, 'not found record with id 1'); }); }); }); @@ -96,31 +102,54 @@ test('unload a record', function(assert) { module("DS.Store - unload record with relationships"); - -test("can commit store after unload record with relationships", function(assert) { +test('can commit store after unload record with relationships', function(assert) { assert.expect(1); - let Brand = DS.Model.extend({ + const Brand = DS.Model.extend({ name: DS.attr('string') }); - Brand.reopenClass({ toString: () => 'Brand'}); - let Product = DS.Model.extend({ + Brand.reopenClass({ + toString() { + return 'Brand'; + } + }); + + const Product = DS.Model.extend({ description: DS.attr('string'), - brand: DS.belongsTo('brand', { async: false }) + brand: DS.belongsTo('brand', { + async: false + }) }); - Product.reopenClass({ toString: () => 'Product'}); - let Like = DS.Model.extend({ - product: DS.belongsTo('product', { async: false }) + Product.reopenClass({ + toString() { + return 'Product'; + } + }); + + const Like = DS.Model.extend({ + product: DS.belongsTo('product', { + async: false + }) + }); + + Like.reopenClass({ + toString() { + return 'Like'; + } }); - Like.reopenClass({ toString: () => 'Like'}); let store = createStore({ adapter: DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, description: 'cuisinart', brand: 1 }); + return Ember.RSVP.resolve({ + id: 1, + description: 'cuisinart', + brand: 1 + }); }, + createRecord(store, type, snapshot) { return Ember.RSVP.resolve(); } @@ -132,24 +161,26 @@ test("can commit store after unload record with relationships", function(assert) return run(() => { store.push({ - data: [{ - type: 'brand', - id: '1', - attributes: { - name: 'EmberJS' - } - }, { - type: 'product', - id: '1', - attributes: { - description: 'toto' + data: [ + { + type: 'brand', + id: '1', + attributes: { + name: 'EmberJS' + } }, - relationships: { - brand: { - data: { type: 'brand', id: '1' } + { + type: 'product', + id: '1', + attributes: { + description: 'toto' + }, + relationships: { + brand: { + data: { type: 'brand', id: '1' } + } } - } - }] + }] }); let product = store.peekRecord('product', 1); @@ -157,12 +188,11 @@ test("can commit store after unload record with relationships", function(assert) return like.save(); }).then(() => { - return run(() => { - store.unloadRecord(store.peekRecord('product', 1)); - }); + // TODO: this is strange, future travelers please address + Ember.run(() => store.unloadRecord(store.peekRecord('product', 1))); }).then(() => { return store.findRecord('product', 1); - }).then((product) => { + }).then(product => { assert.equal(product.get('description'), 'cuisinart', "The record was unloaded and the adapter's `findRecord` was called"); }); }); diff --git a/tests/unit/transform/boolean-test.js b/tests/unit/transform/boolean-test.js index 7f57d5fc52e..4c2ae3c5b40 100644 --- a/tests/unit/transform/boolean-test.js +++ b/tests/unit/transform/boolean-test.js @@ -2,10 +2,10 @@ import DS from 'ember-data'; import {module, test} from 'qunit'; -module("unit/transform - DS.BooleanTransform"); +module('unit/transform - DS.BooleanTransform'); test("#serialize", function(assert) { - var transform = new DS.BooleanTransform(); + let transform = new DS.BooleanTransform(); assert.equal(transform.serialize(null, { allowNull: true }), null); assert.equal(transform.serialize(undefined, { allowNull: true }), null); @@ -20,8 +20,8 @@ test("#serialize", function(assert) { assert.equal(transform.serialize(false), false); }); -test("#deserialize", function(assert) { - var transform = new DS.BooleanTransform(); +test('#deserialize', function(assert) { + let transform = new DS.BooleanTransform(); assert.equal(transform.deserialize(null, { allowNull: true }), null); assert.equal(transform.deserialize(undefined, { allowNull: true }), null); @@ -35,18 +35,18 @@ test("#deserialize", function(assert) { assert.equal(transform.deserialize(true), true); assert.equal(transform.deserialize(false), false); - assert.equal(transform.deserialize("true"), true); - assert.equal(transform.deserialize("TRUE"), true); - assert.equal(transform.deserialize("false"), false); - assert.equal(transform.deserialize("FALSE"), false); + assert.equal(transform.deserialize('true'), true); + assert.equal(transform.deserialize('TRUE'), true); + assert.equal(transform.deserialize('false'), false); + assert.equal(transform.deserialize('FALSE'), false); - assert.equal(transform.deserialize("t"), true); - assert.equal(transform.deserialize("T"), true); - assert.equal(transform.deserialize("f"), false); - assert.equal(transform.deserialize("F"), false); + assert.equal(transform.deserialize('t'), true); + assert.equal(transform.deserialize('T'), true); + assert.equal(transform.deserialize('f'), false); + assert.equal(transform.deserialize('F'), false); - assert.equal(transform.deserialize("1"), true); - assert.equal(transform.deserialize("0"), false); + assert.equal(transform.deserialize('1'), true); + assert.equal(transform.deserialize('0'), false); assert.equal(transform.deserialize(1), true); assert.equal(transform.deserialize(2), false); diff --git a/tests/unit/transform/date-test.js b/tests/unit/transform/date-test.js index bedd2ef009d..f87823afc23 100644 --- a/tests/unit/transform/date-test.js +++ b/tests/unit/transform/date-test.js @@ -4,27 +4,26 @@ import DS from 'ember-data'; import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import { parseDate } from "ember-data/-private/ext/date"; +import { parseDate } from 'ember-data/-private/ext/date'; -module("unit/transform - DS.DateTransform"); +module('unit/transform - DS.DateTransform'); -var dateString = "2015-01-01T00:00:00.000Z"; -var dateInMillis = parseDate(dateString); -var date = new Date(dateInMillis); -var run = Ember.run; +let dateString = '2015-01-01T00:00:00.000Z'; +let dateInMillis = parseDate(dateString); +let date = new Date(dateInMillis); -test("#serialize", function(assert) { - var transform = new DS.DateTransform(); +test('#serialize', function(assert) { + let transform = new DS.DateTransform(); assert.equal(transform.serialize(null), null); assert.equal(transform.serialize(undefined), null); - assert.equal(transform.serialize(new Date("invalid")), null); + assert.equal(transform.serialize(new Date('invalid')), null); assert.equal(transform.serialize(date), dateString); }); -test("#deserialize", function(assert) { - var transform = new DS.DateTransform(); +test('#deserialize', function(assert) { + let transform = new DS.DateTransform(); // from String assert.equal(transform.deserialize(dateString).toISOString(), dateString); @@ -40,15 +39,15 @@ test("#deserialize", function(assert) { assert.equal(transform.deserialize(undefined), null); }); -test("#deserialize with different offset formats", function(assert) { - var transform = new DS.DateTransform(); - var dateString = '2003-05-24T23:00:00.000+0000'; - var dateStringColon = '2013-03-15T23:22:00.000+00:00'; - var dateStringShortOffset = '2016-12-02T17:30:00.000+00'; +test('#deserialize with different offset formats', function(assert) { + let transform = new DS.DateTransform(); + let dateString = '2003-05-24T23:00:00.000+0000'; + let dateStringColon = '2013-03-15T23:22:00.000+00:00'; + let dateStringShortOffset = '2016-12-02T17:30:00.000+00'; assert.expect(6); - var _dateUTC = Date.UTC; + let _dateUTC = Date.UTC; try { Date.UTC = function () { @@ -65,9 +64,7 @@ test("#deserialize with different offset formats", function(assert) { }); testInDebug('Ember.Date.parse has been deprecated', function(assert) { - run(function() { - assert.expectDeprecation(function() { - Ember.Date.parse(dateString); - }, /Ember.Date.parse is deprecated/); - }); + assert.expectDeprecation(() => { + Ember.Date.parse(dateString); + }, /Ember.Date.parse is deprecated/); }); diff --git a/tests/unit/transform/number-test.js b/tests/unit/transform/number-test.js index 60ad23db792..17d3e47d381 100644 --- a/tests/unit/transform/number-test.js +++ b/tests/unit/transform/number-test.js @@ -2,10 +2,10 @@ import DS from 'ember-data'; import {module, test} from 'qunit'; -module("unit/transform - DS.NumberTransform"); +module('unit/transform - DS.NumberTransform'); -test("#serialize", function(assert) { - var transform = new DS.NumberTransform(); +test('#serialize', function(assert) { + let transform = new DS.NumberTransform(); assert.equal(transform.serialize(null), null); assert.equal(transform.serialize(undefined), null); @@ -17,12 +17,12 @@ test("#serialize", function(assert) { assert.equal(transform.serialize(-Infinity), null); }); -test("#deserialize", function(assert) { - var transform = new DS.NumberTransform(); +test('#deserialize', function(assert) { + let transform = new DS.NumberTransform(); assert.equal(transform.deserialize(null), null); assert.equal(transform.deserialize(undefined), null); - assert.equal(transform.deserialize("1.1"), 1.1); + assert.equal(transform.deserialize('1.1'), 1.1); assert.equal(transform.deserialize(1.1), 1.1); assert.equal(transform.deserialize(new Number(1.1)), 1.1); assert.equal(transform.deserialize(NaN), null); diff --git a/tests/unit/transform/string-test.js b/tests/unit/transform/string-test.js index 75175e20ae6..713d97f7f64 100644 --- a/tests/unit/transform/string-test.js +++ b/tests/unit/transform/string-test.js @@ -2,24 +2,24 @@ import DS from 'ember-data'; import {module, test} from 'qunit'; -module("unit/transform - DS.StringTransform"); +module('unit/transform - DS.StringTransform'); -test("#serialize", function(assert) { - var transform = new DS.StringTransform(); +test('#serialize', function(assert) { + let transform = new DS.StringTransform(); assert.equal(transform.serialize(null), null); assert.equal(transform.serialize(undefined), null); - assert.equal(transform.serialize("foo"), "foo"); - assert.equal(transform.serialize(1), "1"); + assert.equal(transform.serialize('foo'), 'foo'); + assert.equal(transform.serialize(1), '1'); }); -test("#deserialize", function(assert) { - var transform = new DS.StringTransform(); +test('#deserialize', function(assert) { + let transform = new DS.StringTransform(); assert.equal(transform.deserialize(null), null); assert.equal(transform.deserialize(undefined), null); - assert.equal(transform.deserialize("foo"), "foo"); - assert.equal(transform.deserialize(1), "1"); + assert.equal(transform.deserialize('foo'), 'foo'); + assert.equal(transform.deserialize(1), '1'); }); diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index c9bee2a87ff..9dabb38e3dd 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -7,12 +7,12 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; import Model from 'ember-data/model'; -import { assertPolymorphicType } from "ember-data/-private/debug"; -import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; +import { assertPolymorphicType } from 'ember-data/-private/debug'; +import { modelHasAttributeOrRelationshipNamedType } from 'ember-data/-private/utils'; -var env, User, Message, Post, Person, Video, Medium; +let env, User, Message, Post, Person, Video, Medium; -module("unit/utils", { +module('unit/utils', { beforeEach() { Person = Model.extend(); User = Model.extend({ @@ -43,10 +43,10 @@ module("unit/utils", { } }); -testInDebug("assertPolymorphicType works for subclasses", function(assert) { - var user, post, person; +testInDebug('assertPolymorphicType works for subclasses', function(assert) { + let user, post, person; - Ember.run(function() { + Ember.run(() => { env.store.push({ data: [{ type: 'user', @@ -70,7 +70,7 @@ testInDebug("assertPolymorphicType works for subclasses", function(assert) { person = env.store.peekRecord('person', 1); }); - var relationship = user.relationshipFor('messages'); + let relationship = user.relationshipFor('messages'); user = user._internalModel; post = post._internalModel; person = person._internalModel; @@ -78,22 +78,22 @@ testInDebug("assertPolymorphicType works for subclasses", function(assert) { try { assertPolymorphicType(user, relationship, post); } catch (e) { - assert.ok(false, "should not throw an error"); + assert.ok(false, 'should not throw an error'); } - assert.expectAssertion(function() { + assert.expectAssertion(() => { assertPolymorphicType(user, relationship, person); }, "You cannot add a record of modelClass 'person' to the 'user.messages' relationship (only 'message' allowed)"); }); -test("modelHasAttributeOrRelationshipNamedType", function(assert) { - var ModelWithTypeAttribute = Model.extend({ +test('modelHasAttributeOrRelationshipNamedType', function(assert) { + let ModelWithTypeAttribute = Model.extend({ type: DS.attr() }); - var ModelWithTypeBelongsTo = Model.extend({ + let ModelWithTypeBelongsTo = Model.extend({ type: DS.belongsTo() }); - var ModelWithTypeHasMany = Model.extend({ + let ModelWithTypeHasMany = Model.extend({ type: DS.hasMany() }); @@ -104,10 +104,10 @@ test("modelHasAttributeOrRelationshipNamedType", function(assert) { assert.equal(modelHasAttributeOrRelationshipNamedType(ModelWithTypeHasMany), true); }); -testInDebug("assertPolymorphicType works for mixins", function(assert) { - var post, video, person; +testInDebug('assertPolymorphicType works for mixins', function(assert) { + let post, video, person; - Ember.run(function() { + Ember.run(() => { env.store.push({ data: [{ type: 'post', @@ -125,7 +125,7 @@ testInDebug("assertPolymorphicType works for mixins", function(assert) { person = env.store.peekRecord('person', 1); }); - var relationship = post.relationshipFor('medias'); + let relationship = post.relationshipFor('medias'); post = post._internalModel; video = video._internalModel; person = person._internalModel; @@ -133,10 +133,10 @@ testInDebug("assertPolymorphicType works for mixins", function(assert) { try { assertPolymorphicType(post, relationship, video); } catch (e) { - assert.ok(false, "should not throw an error"); + assert.ok(false, 'should not throw an error'); } - assert.expectAssertion(function() { + assert.expectAssertion(() => { assertPolymorphicType(post, relationship, person); }, "You cannot add a record of modelClass 'person' to the 'post.medias' relationship (only 'medium' allowed)"); }); From 1a752f4e5d06e646e506cd92add94950aff6fe8a Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 3 Mar 2017 10:28:22 -0800 Subject: [PATCH 1824/2527] cleanup + reject with useful reasons * es6 cleanup * promise cleanup * remove dangling promises / errors * throw useful error message when a payload does not include an expected record instead of `undefined` --- addon/-private/system/store.js | 5 +- .../integration/adapter/rest-adapter-test.js | 14 +- tests/unit/store/adapter-interop-test.js | 673 +++++++++--------- 3 files changed, 341 insertions(+), 351 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 3d3a3907394..b3a22b81cc1 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -906,10 +906,11 @@ Store = Service.extend({ function rejectInternalModels(internalModels, error) { for (let i = 0, l = internalModels.length; i < l; i++) { - let pair = seeking[internalModels[i].id]; + let internalModel = internalModels[i]; + let pair = seeking[internalModel.id]; if (pair) { - pair.resolver.reject(error); + pair.resolver.reject(error || new Error(`Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.`)); } } } diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 96b60b35552..33bbc8d5a7b 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1947,10 +1947,10 @@ testInDebug('coalesceFindRequests assert.warns if the expected records are not r adapter.coalesceFindRequests = true; ajaxResponse({ comments: [{ id: 1 }] }); - var post; - assert.expectWarning(function() { - run(function() { + let wait; + assert.expectWarning(() => { + run(() => { store.push({ data: { type: 'post', @@ -1967,9 +1967,13 @@ testInDebug('coalesceFindRequests assert.warns if the expected records are not r } }); - post = store.peekRecord('post', 2); - post.get('comments'); + let post = store.peekRecord('post', 2); + wait = post.get('comments').catch(e => { + assert.equal(e.message, `Expected: '' to be present in the adapter provided payload, but it was not found.`) + }) }); + + return wait; }, /expected to find records with the following ids in the adapter response but they were missing: \[2,3\]/); }); diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index e1e251d87b8..f027f73af76 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -9,7 +9,7 @@ import DS from 'ember-data'; const { get, set , run } = Ember; const resolve = Ember.RSVP.resolve; -let TestAdapter, store, person, oldFilterEnabled; +let TestAdapter, store, oldFilterEnabled; module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', { beforeEach() { @@ -219,76 +219,73 @@ test('can load data for the same record if it is not dirty', function(assert) { test('loadMany takes an optional Object and passes it on to the Adapter', function(assert) { assert.expect(2); - var passedQuery = { page: 1 }; + let passedQuery = { page: 1 }; - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var adapter = TestAdapter.extend({ + const Adapter = TestAdapter.extend({ query(store, type, query) { assert.equal(type, store.modelFor('person'), 'The type was Person'); - assert.equal(query, passedQuery, "The query was passed in"); + assert.equal(query, passedQuery, 'The query was passed in'); return Ember.RSVP.resolve([]); } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, person: Person }); - run(function() { - store.query('person', passedQuery); - }); + run(() => store.query('person', passedQuery)); }); -test("Find with query calls the correct normalizeResponse", function(assert) { - var passedQuery = { page: 1 }; +test('Find with query calls the correct normalizeResponse', function(assert) { + let passedQuery = { page: 1 }; - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var adapter = TestAdapter.extend({ + const Adapter = TestAdapter.extend({ query(store, type, query) { return Ember.RSVP.resolve([]); } }); - var callCount = 0; + let callCount = 0; - var ApplicationSerializer = DS.JSONSerializer.extend({ + const ApplicationSerializer = DS.JSONSerializer.extend({ normalizeQueryResponse() { callCount++; return this._super(...arguments); } }); - var env = setupStore({ - adapter: adapter, + let env = setupStore({ + adapter: Adapter, person: Person }); - var store = env.store; + + let { store } = env; env.registry.register('serializer:application', ApplicationSerializer); - run(function() { - store.query('person', passedQuery); - }); + run(() => store.query('person', passedQuery)); assert.equal(callCount, 1, 'normalizeQueryResponse was called'); }); -test("peekAll(type) returns a record array of all records of a specific type", function(assert) { - var Person = DS.Model.extend({ +test('peekAll(type) returns a record array of all records of a specific type', function(assert) { + const Person = DS.Model.extend({ name: DS.attr('string') }); - var store = createStore({ + let store = createStore({ person: Person }); - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -300,54 +297,50 @@ test("peekAll(type) returns a record array of all records of a specific type", f }); }); - var results = store.peekAll('person'); - assert.equal(get(results, 'length'), 1, "record array should have the original object"); - assert.equal(get(results.objectAt(0), 'name'), "Tom Dale", "record has the correct information"); + let results = store.peekAll('person'); - run(function() { + assert.equal(get(results, 'length'), 1, 'record array should have the original object'); + assert.equal(get(results.objectAt(0), 'name'), 'Tom Dale', 'record has the correct information'); + + run(() => { store.push({ data: { type: 'person', id: '2', attributes: { - name: "Yehuda Katz" + name: 'Yehuda Katz' } } }); }); - assert.equal(get(results, 'length'), 2, "record array should have the new object"); - assert.equal(get(results.objectAt(1), 'name'), "Yehuda Katz", "record has the correct information"); - assert.strictEqual(results, store.peekAll('person'), "subsequent calls to peekAll return the same recordArray)"); + assert.equal(get(results, 'length'), 2, 'record array should have the new object'); + assert.equal(get(results.objectAt(1), 'name'), 'Yehuda Katz', 'record has the correct information'); + + assert.strictEqual(results, store.peekAll('person'), 'subsequent calls to peekAll return the same recordArray)'); }); -test("a new record of a particular type is created via store.createRecord(type)", function(assert) { - var Person = DS.Model.extend({ +test('a new record of a particular type is created via store.createRecord(type)', function(assert) { + const Person = DS.Model.extend({ name: DS.attr('string') }); - var person; - - var store = createStore({ + let store = createStore({ person: Person }); - run(function() { - person = store.createRecord('person'); - }); + let person = run(() => store.createRecord('person')); - assert.equal(get(person, 'isLoaded'), true, "A newly created record is loaded"); - assert.equal(get(person, 'isNew'), true, "A newly created record is new"); - assert.equal(get(person, 'hasDirtyAttributes'), true, "A newly created record is dirty"); + assert.equal(get(person, 'isLoaded'), true, 'A newly created record is loaded'); + assert.equal(get(person, 'isNew'), true, 'A newly created record is new'); + assert.equal(get(person, 'hasDirtyAttributes'), true, 'A newly created record is dirty'); - run(function() { - set(person, 'name', "Braaahm Dale"); - }); + run(() => set(person, 'name', 'Braaahm Dale')); - assert.equal(get(person, 'name'), "Braaahm Dale", "Even if no hash is supplied, `set` still worked"); + assert.equal(get(person, 'name'), 'Braaahm Dale', 'Even if no hash is supplied, `set` still worked'); }); testInDebug("a new record with a specific id can't be created if this id is already used in the store", function(assert) { - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); @@ -357,110 +350,106 @@ testInDebug("a new record with a specific id can't be created if this id is alre } }); - var store = createStore({ + let store = createStore({ person: Person }); - run(function() { - store.createRecord('person', { id: 5 }); - }); + run(() => store.createRecord('person', { id: 5 })); - assert.expectAssertion(function() { - run(function() { + assert.expectAssertion(() => { + run(() => { store.createRecord('person', { id: 5 }); }); }, /The id 5 has already been used with another record for modelClass 'person'/); }); -test("an initial data hash can be provided via store.createRecord(type, hash)", function(assert) { - var Person = DS.Model.extend({ +test('an initial data hash can be provided via store.createRecord(type, hash)', function(assert) { + const Person = DS.Model.extend({ name: DS.attr('string') }); - var store = createStore({ + let store = createStore({ person: Person }); - run(function() { - person = store.createRecord('person', { name: "Brohuda Katz" }); - }); + let person = run(() => store.createRecord('person', { name: 'Brohuda Katz' })); - assert.equal(get(person, 'isLoaded'), true, "A newly created record is loaded"); - assert.equal(get(person, 'isNew'), true, "A newly created record is new"); - assert.equal(get(person, 'hasDirtyAttributes'), true, "A newly created record is dirty"); + assert.equal(get(person, 'isLoaded'), true, 'A newly created record is loaded'); + assert.equal(get(person, 'isNew'), true, 'A newly created record is new'); + assert.equal(get(person, 'hasDirtyAttributes'), true, 'A newly created record is dirty'); - assert.equal(get(person, 'name'), "Brohuda Katz", "The initial data hash is provided"); + assert.equal(get(person, 'name'), 'Brohuda Katz', 'The initial data hash is provided'); }); test("if an id is supplied in the initial data hash, it can be looked up using `store.find`", function(assert) { assert.expect(1); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var store = createStore({ + + let store = createStore({ person: Person, adapter: DS.Adapter.extend({ shouldBackgroundReloadRecord: () => false }) }); - var person; - run(function() { - person = store.createRecord('person', { id: 1, name: "Brohuda Katz" }); - store.findRecord('person', 1).then(assert.wait(function(again) { - assert.strictEqual(person, again, "the store returns the loaded object"); - })); + return run(() => { + let person = store.createRecord('person', { id: 1, name: 'Brohuda Katz' }); + + return store.findRecord('person', 1).then(again => { + assert.strictEqual(person, again, 'the store returns the loaded object'); + }); }); }); test("initial values of attributes can be passed in as the third argument to find", function(assert) { assert.expect(1); - var adapter = TestAdapter.extend({ + const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.attr('name'), 'Test', 'Preloaded attribtue set'); - return Ember.RSVP.resolve({ id: '1', name: 'Test' }); + return { id: '1', name: 'Test' }; } }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, test: Person }); - run(function() { - store.findRecord('test', 1, { preload: { name: 'Test' } }); - }); + return run(() => store.findRecord('test', 1, { preload: { name: 'Test' } })); }); -test("initial values of belongsTo can be passed in as the third argument to find as records", function(assert) { +test('initial values of belongsTo can be passed in as the third argument to find as records', function(assert) { assert.expect(1); - var adapter = TestAdapter.extend({ + + const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.belongsTo('friend').attr('name'), 'Tom', 'Preloaded belongsTo set'); - return new Ember.RSVP.Promise(function() {}); + return { id }; } }); - var env = setupStore({ - adapter: adapter + let env = setupStore({ + adapter: Adapter }); - var store = env.store; - var Person = DS.Model.extend({ + let { store } = env; + + const Person = DS.Model.extend({ name: DS.attr('string'), friend: DS.belongsTo('person', { inverse: null, async: true }) }); env.registry.register('model:person', Person); - var tom; - run(function() { + return run(() => { store.push({ data: { type: 'person', @@ -470,64 +459,67 @@ test("initial values of belongsTo can be passed in as the third argument to find } } }); - tom = store.peekRecord('person', 2); - store.findRecord('person', 1, { preload: { friend: tom } }); + + let tom = store.peekRecord('person', 2); + return store.findRecord('person', 1, { preload: { friend: tom } }); }); }); -test("initial values of belongsTo can be passed in as the third argument to find as ids", function(assert) { +test('initial values of belongsTo can be passed in as the third argument to find as ids', function(assert) { assert.expect(1); - var adapter = TestAdapter.extend({ + const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { - return Ember.RSVP.Promise.resolve({ id: id }); + return { id }; } }); - var env = setupStore({ - adapter: adapter + let env = setupStore({ + adapter: Adapter + }); - var store = env.store; + let { store } = env; - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), friend: DS.belongsTo('person', { async: true, inverse: null }) }); env.registry.register('model:person', Person); - run(function() { - store.findRecord('person', 1, { preload: { friend: 2 } }).then(assert.wait(function() { - store.peekRecord('person', 1).get('friend').then(assert.wait(function(friend) { + return run(() => { + return store.findRecord('person', 1, { preload: { friend: 2 } }).then(() => { + return store.peekRecord('person', 1).get('friend').then(friend => { assert.equal(friend.get('id'), '2', 'Preloaded belongsTo set'); - })); - })); + }); + }); }); }); -test("initial values of hasMany can be passed in as the third argument to find as records", function(assert) { +test('initial values of hasMany can be passed in as the third argument to find as records', function(assert) { assert.expect(1); - var adapter = TestAdapter.extend({ + + const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.hasMany('friends')[0].attr('name'), 'Tom', 'Preloaded hasMany set'); - return new Ember.RSVP.Promise(function() {}); + return { id, type }; } }); - var env = setupStore({ - adapter: adapter + let env = setupStore({ + adapter: Adapter }); - var store = env.store; - var Person = DS.Model.extend({ + let { store } = env; + + const Person = DS.Model.extend({ name: DS.attr('string'), friends: DS.hasMany('person', { inverse: null, async: true }) }); env.registry.register('model:person', Person); - var tom; - run(function() { + return run(() => { store.push({ data: { type: 'person', @@ -537,142 +529,134 @@ test("initial values of hasMany can be passed in as the third argument to find a } } }); - tom = store.peekRecord('person', 2); - store.findRecord('person', 1, { preload: { friends: [tom] } }); + + let tom = store.peekRecord('person', 2); + return store.findRecord('person', 1, { preload: { friends: [tom] } }); }); }); -test("initial values of hasMany can be passed in as the third argument to find as ids", function(assert) { +test('initial values of hasMany can be passed in as the third argument to find as ids', function(assert) { assert.expect(1); - var adapter = TestAdapter.extend({ + const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.hasMany('friends')[0].id, '2', 'Preloaded hasMany set'); - return Ember.RSVP.resolve({ id: id }); + return { id }; } }); - var env = setupStore({ - adapter: adapter + let env = setupStore({ + adapter: Adapter }); - var store = env.store; + let { store } = env; - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), friends: DS.hasMany('person', { async: true, inverse: null }) }); env.registry.register('model:person', Person); - run(function() { - store.findRecord('person', 1, { preload: { friends: [2] } }); - }); + return run(() => store.findRecord('person', 1, { preload: { friends: [2] } })); }); -test("records should have their ids updated when the adapter returns the id data", function(assert) { +test('records should have their ids updated when the adapter returns the id data', function(assert) { assert.expect(2); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var idCounter = 1; - var adapter = TestAdapter.extend({ + let idCounter = 1; + const Adapter = TestAdapter.extend({ createRecord(store, type, snapshot) { - return Ember.RSVP.resolve({ name: snapshot.attr('name'), id: idCounter++ }); + return { + name: snapshot.attr('name'), + id: idCounter++ + }; } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, person: Person }); - var people = store.peekAll('person'); - var tom, yehuda; + let people = store.peekAll('person'); + let tom, yehuda; - run(function() { + run(() => { tom = store.createRecord('person', { name: 'Tom Dale' }); yehuda = store.createRecord('person', { name: 'Yehuda Katz' }); }); - run(function() { - Ember.RSVP.all([tom.save(), yehuda.save()]).then(assert.wait(function() { - people.forEach(function(person, index) { - assert.equal(person.get('id'), index + 1, "The record's id should be correct."); + return run(() => { + return Ember.RSVP.all([ + tom.save(), + yehuda.save() + ]).then(() => { + people.forEach((person, index) => { + assert.equal(person.get('id'), index + 1, `The record's id should be correct.`); }); - })); + }); }); }); -test("store.fetchMany should always return a promise", function(assert) { +test('store.fetchMany should always return a promise', function(assert) { assert.expect(3); - var Person = DS.Model.extend(); - var store = createStore({ + const Person = DS.Model.extend(); + let store = createStore({ adapter: TestAdapter.extend(), person: Person }); - run(function() { - store.createRecord('person'); - }); - var records = []; - var results; - run(function() { - results = store._scheduleFetchMany(records); - }); - assert.ok(results, "A call to store._scheduleFetchMany() should return a result"); - assert.ok(results.then, "A call to store._scheduleFetchMany() should return a promise"); + run(() => store.createRecord('person')); + + let records = []; + let results = run(() => store._scheduleFetchMany(records)); - results.then(assert.wait(function(returnedRecords) { - assert.deepEqual(returnedRecords, [], "The correct records are returned"); - })); + assert.ok(results, 'A call to store._scheduleFetchMany() should return a result'); + assert.ok(results.then, 'A call to store._scheduleFetchMany() should return a promise'); + + return results.then(returnedRecords => { + assert.deepEqual(returnedRecords, [], 'The correct records are returned'); + }); }); -test("store._scheduleFetchMany should not resolve until all the records are resolved", function(assert) { +test('store._scheduleFetchMany should not resolve until all the records are resolved', function(assert) { assert.expect(1); - var Person = DS.Model.extend(); - var Phone = DS.Model.extend(); + const Person = DS.Model.extend(); + const Phone = DS.Model.extend(); - var adapter = TestAdapter.extend({ + const adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { - var wait = 5; - - var record = { id: id }; + let record = { id: id }; - return new Ember.RSVP.Promise(function(resolve, reject) { - run.later(function() { - resolve(record); - }, wait); + return new Ember.RSVP.Promise(resolve => { + run.later(() => resolve(record), 5); }); }, findMany(store, type, ids, snapshots) { - var wait = 15; + let records = ids.map(id => ( { id }) ); - var records = ids.map(function(id) { - return { id: id }; - }); - - return new Ember.RSVP.Promise(function(resolve, reject) { - run.later(function() { + return new Ember.RSVP.Promise(resolve => { + run.later(() => { resolve(records); - }, wait); + }, 15); }); } }); - var store = createStore({ + let store = createStore({ adapter: adapter, test: Person, phone: Phone }); - run(function() { - store.createRecord('test'); - }); + run(() => store.createRecord('test')); let internalModels = [ store._internalModelForId('test', 10), @@ -680,21 +664,21 @@ test("store._scheduleFetchMany should not resolve until all the records are reso store._internalModelForId('phone', 21) ]; - run(function() { - store._scheduleFetchMany(internalModels).then(assert.wait(function() { - var unloadedRecords = Ember.A(internalModels.map(r => r.record)).filterBy('isEmpty'); + return run(() => { + return store._scheduleFetchMany(internalModels).then(() => { + let unloadedRecords = Ember.A(internalModels.map(r => r.record)).filterBy('isEmpty'); assert.equal(get(unloadedRecords, 'length'), 0, 'All unloaded records should be loaded'); - })); + }); }); }); -test("the store calls adapter.findMany according to groupings returned by adapter.groupRecordsForFindMany", function(assert) { +test('the store calls adapter.findMany according to groupings returned by adapter.groupRecordsForFindMany', function(assert) { assert.expect(3); - var Person = DS.Model.extend(); + const Person = DS.Model.extend(); - var adapter = TestAdapter.extend({ + const Adapter = TestAdapter.extend({ groupRecordsForFindMany(store, snapshots) { return [ [snapshots[0]], @@ -703,49 +687,45 @@ test("the store calls adapter.findMany according to groupings returned by adapte }, findRecord(store, type, id, snapshot) { - assert.equal(id, "10", "The first group is passed to find"); - return Ember.RSVP.resolve({ id: id }); + assert.equal(id, '10', 'The first group is passed to find'); + return { id }; }, findMany(store, type, ids, snapshots) { - var records = ids.map(function(id) { - return { id: id }; - }); + let records = ids.map(id => ({ id })); - assert.deepEqual(ids, ["20", "21"], "The second group is passed to findMany"); + assert.deepEqual(ids, ['20', '21'], 'The second group is passed to findMany'); - return new Ember.RSVP.Promise(function(resolve, reject) { - resolve(records); - }); + return records; } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, test: Person }); - var internalModels = [ + let internalModels = [ store._internalModelForId('test', 10), store._internalModelForId('test', 20), store._internalModelForId('test', 21) ]; - run(function() { - store._scheduleFetchMany(internalModels).then(assert.wait(function() { - var ids = Ember.A(internalModels).mapBy('id'); - assert.deepEqual(ids, ["10", "20", "21"], "The promise fulfills with the records"); - })); + return run(() => { + return store._scheduleFetchMany(internalModels).then(() => { + let ids = internalModels.map(x => x.id ) + assert.deepEqual(ids, ['10', '20', '21'], 'The promise fulfills with the records'); + }); }); }); -test("the promise returned by `_scheduleFetch`, when it resolves, does not depend on the promises returned to other calls to `_scheduleFetch` that are in the same run loop, but different groups", function(assert) { +test('the promise returned by `_scheduleFetch`, when it resolves, does not depend on the promises returned to other calls to `_scheduleFetch` that are in the same run loop, but different groups', function(assert) { assert.expect(2); - var Person = DS.Model.extend(); - var davidResolved = false; + let davidResolved = false; - var adapter = TestAdapter.extend({ + const Person = DS.Model.extend(); + const Adapter = TestAdapter.extend({ groupRecordsForFindMany(store, snapshots) { return [ [snapshots[0]], @@ -754,7 +734,7 @@ test("the promise returned by `_scheduleFetch`, when it resolves, does not depen }, findRecord(store, type, id, snapshot) { - var record = { id: id }; + let record = { id }; return new Ember.RSVP.Promise(function(resolve, reject) { if (id === 'igor') { @@ -769,32 +749,35 @@ test("the promise returned by `_scheduleFetch`, when it resolves, does not depen } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, test: Person }); - run(function () { - var davidPromise = store.findRecord('test', 'david'); - var igorPromise = store.findRecord('test', 'igor'); + return run(() => { + let david = store.findRecord('test', 'david'); + let igor = store.findRecord('test', 'igor'); + let wait = []; - igorPromise.then(assert.wait(function () { - assert.equal(davidResolved, false, "Igor did not need to wait for David"); + wait.push(igor.then(() => { + assert.equal(davidResolved, false, 'Igor did not need to wait for David'); })); - davidPromise.then(assert.wait(function () { - assert.equal(davidResolved, true, "David resolved"); + wait.push(david.then(() => { + assert.equal(davidResolved, true, 'David resolved'); })); + + return Ember.RSVP.all(wait); }); }); -test("the promise returned by `_scheduleFetch`, when it rejects, does not depend on the promises returned to other calls to `_scheduleFetch` that are in the same run loop, but different groups", function(assert) { +test('the promise returned by `_scheduleFetch`, when it rejects, does not depend on the promises returned to other calls to `_scheduleFetch` that are in the same run loop, but different groups', function(assert) { assert.expect(2); - var Person = DS.Model.extend(); - var davidResolved = false; + let davidResolved = false; - var adapter = TestAdapter.extend({ + const Person = DS.Model.extend(); + const Adapter = TestAdapter.extend({ groupRecordsForFindMany(store, snapshots) { return [ [snapshots[0]], @@ -803,13 +786,13 @@ test("the promise returned by `_scheduleFetch`, when it rejects, does not depend }, findRecord(store, type, id, snapshot) { - var record = { id: id }; + let record = { id }; - return new Ember.RSVP.Promise(function(resolve, reject) { + return new Ember.RSVP.Promise((resolve, reject) => { if (id === 'igor') { reject(record); } else { - run.later(function () { + run.later(() => { davidResolved = true; resolve(record); }, 5); @@ -818,103 +801,101 @@ test("the promise returned by `_scheduleFetch`, when it rejects, does not depend } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, test: Person }); - run(function () { - var davidPromise = store.findRecord('test', 'david'); - var igorPromise = store.findRecord('test', 'igor'); + return run(() => { + let david = store.findRecord('test', 'david'); + let igor = store.findRecord('test', 'igor'); + let wait = []; - igorPromise.then(null, assert.wait(function () { - assert.equal(davidResolved, false, "Igor did not need to wait for David"); + wait.push(igor.catch(() => { + assert.equal(davidResolved, false, 'Igor did not need to wait for David'); })); - davidPromise.then(assert.wait(function () { - assert.equal(davidResolved, true, "David resolved"); + wait.push(david.then(() => { + assert.equal(davidResolved, true, 'David resolved'); })); + + return Ember.RSVP.Promise.all(wait); }); }); -testInDebug("store._fetchRecord reject records that were not found, even when those requests were coalesced with records that were found", function(assert) { +testInDebug('store._fetchRecord reject records that were not found, even when those requests were coalesced with records that were found', function(assert) { assert.expect(3); - var Person = DS.Model.extend(); + const Person = DS.Model.extend(); - var adapter = TestAdapter.extend({ + const Adapter = TestAdapter.extend({ findMany(store, type, ids, snapshots) { - var records = ids.map(function(id) { - return { id: id }; - }); - - return new Ember.RSVP.Promise(function(resolve, reject) { - resolve([ - records[0] - ]); - }); + let records = ids.map((id) => ({ id })); + return [records[0]]; } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, test: Person }); - assert.expectWarning(function() { - run(function () { - var davidPromise = store.findRecord('test', 'david'); - var igorPromise = store.findRecord('test', 'igor'); - - davidPromise.then(function () { - assert.ok(true, "David resolved"); - }); + let wait = []; + assert.expectWarning(() => { + run(() => { + let david = store.findRecord('test', 'david'); + let igor = store.findRecord('test', 'igor'); - igorPromise.then(null, function () { - assert.ok(true, "Igor rejected"); - }); + wait.push(david.then(() => assert.ok(true, 'David resolved'))); + wait.push(igor.catch(() => assert.ok(true, 'Igor rejected'))); }); }, /expected to find records with the following ids/); + + return Ember.RSVP.Promise.all(wait); }); -testInDebug("store._fetchRecord warns when records are missing", function(assert) { - var Person = DS.Model.extend(); +testInDebug('store._fetchRecord warns when records are missing', function(assert) { + const Person = DS.Model.extend(); - var adapter = TestAdapter.extend({ + const Adapter = TestAdapter.extend({ findMany(store, type, ids, snapshots) { - var records = ids.map(function(id) { - return { id: id }; - }); + let records = ids.map(id => ({ id })).filter(({ id }) => id === 'david'); - return new Ember.RSVP.Promise(function(resolve, reject) { - resolve([ - records[0] - ]); - }); + return [records[0]]; } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, test: Person }); - assert.expectWarning(function() { - run(function () { - store.findRecord('test', 'david'); - store.findRecord('test', 'igor'); + let wait = []; + let igorDidReject = true; + + assert.expectWarning(() => { + run(() => { + wait.push(store.findRecord('test', 'david')); + wait.push(store.findRecord('test', 'igor').catch(e => { + igorDidReject = true; + assert.equal(e.message, `Expected: '' to be present in the adapter provided payload, but it was not found.`); + })); }); }, /expected to find records with the following ids in the adapter response but they were missing/); + + return Ember.RSVP.Promise.all(wait).then(() => { + assert.ok(igorDidReject, 'expected rejection that could not be found in the payload, but no such rejection occured'); + }); }); -test("store should not call shouldReloadRecord when the record is not in the store", function(assert) { +test('store should not call shouldReloadRecord when the record is not in the store', function(assert) { assert.expect(1); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var TestAdapter = DS.Adapter.extend({ + const TestAdapter = DS.Adapter.extend({ shouldReloadRecord(store, type, id, snapshot) { assert.ok(false, 'shouldReloadRecord should not be called when the record is not loaded'); return false; @@ -925,29 +906,29 @@ test("store should not call shouldReloadRecord when the record is not in the sto } }); - store = createStore({ + let store = createStore({ adapter: TestAdapter, person: Person }); - run(function() { - store.findRecord('person', 1); - }); + return run(() => store.findRecord('person', 1)); }); -test("store should not reload record when shouldReloadRecord returns false", function(assert) { +test('store should not reload record when shouldReloadRecord returns false', function(assert) { assert.expect(1); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var TestAdapter = DS.Adapter.extend({ + const TestAdapter = DS.Adapter.extend({ shouldReloadRecord(store, type, id, snapshot) { assert.ok(true, 'shouldReloadRecord should be called when the record is in the store'); return false; }, - shouldBackgroundReloadRecord: () => false, + shouldBackgroundReloadRecord() { + return false; + }, findRecord() { assert.ok(false, 'find should not be called when shouldReloadRecord returns false'); } @@ -958,25 +939,26 @@ test("store should not reload record when shouldReloadRecord returns false", fun person: Person }); - run(function() { + return run(() => { store.push({ data: { type: 'person', id: '1' } }); - store.findRecord('person', 1); + + return store.findRecord('person', 1); }); }); -test("store should reload record when shouldReloadRecord returns true", function(assert) { +test('store should reload record when shouldReloadRecord returns true', function(assert) { assert.expect(3); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var TestAdapter = DS.Adapter.extend({ + const TestAdapter = DS.Adapter.extend({ shouldReloadRecord(store, type, id, snapshot) { assert.ok(true, 'shouldReloadRecord should be called when the record is in the store'); return true; @@ -992,27 +974,28 @@ test("store should reload record when shouldReloadRecord returns true", function person: Person }); - run(function() { + return run(() => { store.push({ data: { type: 'person', id: '1' } }); - store.findRecord('person', 1).then(function(record) { + + return store.findRecord('person', 1).then(record => { assert.equal(record.get('name'), 'Tom'); }); }); }); -test("store should not call shouldBackgroundReloadRecord when the store is already loading the record", function(assert) { +test('store should not call shouldBackgroundReloadRecord when the store is already loading the record', function(assert) { assert.expect(2); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var TestAdapter = DS.Adapter.extend({ + const TestAdapter = DS.Adapter.extend({ shouldReloadRecord(store, type, id, snapshot) { return true; }, @@ -1030,27 +1013,28 @@ test("store should not call shouldBackgroundReloadRecord when the store is alrea person: Person }); - run(function() { + return run(() => { store.push({ data: { type: 'person', id: '1' } }); - store.findRecord('person', 1).then(function(record) { + + return store.findRecord('person', 1).then(record => { assert.equal(record.get('name'), 'Tom'); }); }); }); -test("store should not reload a record when `shouldBackgroundReloadRecord` is false", function(assert) { +test('store should not reload a record when `shouldBackgroundReloadRecord` is false', function(assert) { assert.expect(2); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var TestAdapter = DS.Adapter.extend({ + const TestAdapter = DS.Adapter.extend({ shouldBackgroundReloadRecord(store, type, id, snapshot) { assert.ok(true, 'shouldBackgroundReloadRecord is called when record is loaded form the cache'); return false; @@ -1066,28 +1050,29 @@ test("store should not reload a record when `shouldBackgroundReloadRecord` is fa person: Person }); - run(function() { + return run(() => { store.push({ data: { type: 'person', id: '1' } }); - store.findRecord('person', 1).then(function(record) { + + return store.findRecord('person', 1).then(record => { assert.equal(record.get('name'), undefined); }); }); }); -test("store should reload the record in the background when `shouldBackgroundReloadRecord` is true", function(assert) { +test('store should reload the record in the background when `shouldBackgroundReloadRecord` is true', function(assert) { assert.expect(4); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var TestAdapter = DS.Adapter.extend({ + const TestAdapter = DS.Adapter.extend({ shouldBackgroundReloadRecord(store, type, id, snapshot) { assert.ok(true, 'shouldBackgroundReloadRecord is called when record is loaded form the cache'); return true; @@ -1103,29 +1088,32 @@ test("store should reload the record in the background when `shouldBackgroundRel person: Person }); - run(function() { + let done = run(() => { store.push({ data: { type: 'person', id: '1' } }); - store.findRecord('person', 1).then(function(record) { + + return store.findRecord('person', 1).then(record => { assert.equal(record.get('name'), undefined); }); }); assert.equal(store.peekRecord('person', 1).get('name'), 'Tom'); + + return done; }); -test("store should not reload record array when shouldReloadAll returns false", function(assert) { +test('store should not reload record array when shouldReloadAll returns false', function(assert) { assert.expect(1); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var TestAdapter = DS.Adapter.extend({ + const TestAdapter = DS.Adapter.extend({ shouldReloadAll(store, snapshot) { assert.ok(true, 'shouldReloadAll should be called when the record is in the store'); return false; @@ -1143,19 +1131,17 @@ test("store should not reload record array when shouldReloadAll returns false", person: Person }); - run(function() { - store.findAll('person'); - }); + return run(() => store.findAll('person')); }); -test("store should reload all records when shouldReloadAll returns true", function(assert) { +test('store should reload all records when shouldReloadAll returns true', function(assert) { assert.expect(3); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var TestAdapter = DS.Adapter.extend({ + const TestAdapter = DS.Adapter.extend({ shouldReloadAll(store, type, id, snapshot) { assert.ok(true, 'shouldReloadAll should be called when the record is in the store'); return true; @@ -1171,21 +1157,21 @@ test("store should reload all records when shouldReloadAll returns true", functi person: Person }); - run(function() { - store.findAll('person').then(function(records) { + return run(() => { + return store.findAll('person').then(records => { assert.equal(records.get('firstObject.name'), 'Tom'); }); }); }); -test("store should not call shouldBackgroundReloadAll when the store is already loading all records", function(assert) { +test('store should not call shouldBackgroundReloadAll when the store is already loading all records', function(assert) { assert.expect(2); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var TestAdapter = DS.Adapter.extend({ + const TestAdapter = DS.Adapter.extend({ shouldReloadAll(store, type, id, snapshot) { return true; }, @@ -1203,21 +1189,21 @@ test("store should not call shouldBackgroundReloadAll when the store is already person: Person }); - run(function() { - store.findAll('person').then(function(records) { + return run(() => { + return store.findAll('person').then(records => { assert.equal(records.get('firstObject.name'), 'Tom'); }); }); }); -test("store should not reload all records when `shouldBackgroundReloadAll` is false", function(assert) { +test('store should not reload all records when `shouldBackgroundReloadAll` is false', function(assert) { assert.expect(3); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var TestAdapter = DS.Adapter.extend({ + const TestAdapter = DS.Adapter.extend({ shouldReloadAll(store, type, id, snapshot) { assert.ok(true, 'shouldReloadAll is called when record is loaded form the cache'); return false; @@ -1237,22 +1223,22 @@ test("store should not reload all records when `shouldBackgroundReloadAll` is fa person: Person }); - run(function() { - store.findAll('person').then(function(records) { + return run(() => { + return store.findAll('person').then(records => { assert.equal(records.get('firstObject'), undefined); }); }); }); -test("store should reload all records in the background when `shouldBackgroundReloadAll` is true", function(assert) { +test('store should reload all records in the background when `shouldBackgroundReloadAll` is true', function(assert) { assert.expect(5); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); - var TestAdapter = DS.Adapter.extend({ + const TestAdapter = DS.Adapter.extend({ shouldReloadAll() { assert.ok(true, 'shouldReloadAll is called'); return false; @@ -1272,19 +1258,21 @@ test("store should reload all records in the background when `shouldBackgroundRe person: Person }); - run(function() { - store.findAll('person').then(function(records) { + let done = run(() => { + return store.findAll('person').then(records => { assert.equal(records.get('firstObject.name'), undefined); }); }); assert.equal(store.peekRecord('person', 1).get('name'), 'Tom'); + + return done; }); -testInDebug("store should assert of the user tries to call store.filter", function(assert) { +testInDebug('store should assert of the user tries to call store.filter', function(assert) { assert.expect(1); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); @@ -1292,16 +1280,13 @@ testInDebug("store should assert of the user tries to call store.filter", functi person: Person }); - assert.expectAssertion(function() { - run(function() { - store.filter('person', {}); - }); + assert.expectAssertion(() => { + run(() => store.filter('person', {})); }, /The filter API has been moved to a plugin/); }); - testInDebug("Calling adapterFor with a model class should assert", function(assert) { - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); @@ -1309,7 +1294,7 @@ testInDebug("Calling adapterFor with a model class should assert", function(asse person: Person }); - assert.expectAssertion(function() { + assert.expectAssertion(() => { store.adapterFor(Person); }, /Passing classes to store.adapterFor has been removed/); }); From d06767873f83464884fdefcdad2509748a3abe8c Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 3 Mar 2017 16:16:33 -0800 Subject: [PATCH 1825/2527] Stefs cleanup (#4837) * cleanup tests/unit/model/merge-test * cleanup test/unit/model/relationships * cleanup test/unit/model/rollback-attributes * cleanup test/unit/record-arrays/filtered-record-array * cleanup test/unit/record-arrays/record-array * cleanup tests/unit/model/lifecycle-callbacks * cleanup tests/unit/model/errors * cleanup tests/unit/model/relationships/record-array * cleanup tests/unit/model/relationships/has-many * cleanup tests/unit/model/relationships/belongs-to * cleanup tests/unit/model/lifecycle-callbacks * cleanup tests/unit/adapters/rest-adapter/* * cleanup test/unit/adapters/json-api-adapter/ajax * cleanup test/unit/adapters/build-url-mixin/path-for-type --- .../build-url-mixin/path-for-type-test.js | 18 +- .../adapters/json-api-adapter/ajax-test.js | 42 +- tests/unit/adapters/rest-adapter/ajax-test.js | 85 ++-- .../adapters/rest-adapter/build-query-test.js | 8 +- .../rest-adapter/detailed-message-test.js | 31 +- .../group-records-for-find-many-test.js | 68 ++-- tests/unit/model/errors-test.js | 22 +- tests/unit/model/lifecycle-callbacks-test.js | 241 ++++++------ tests/unit/model/merge-test.js | 219 +++++------ tests/unit/model/relationships-test.js | 23 +- .../model/relationships/belongs-to-test.js | 274 +++++++------ .../unit/model/relationships/has-many-test.js | 369 +++++++++--------- .../model/relationships/record-array-test.js | 48 ++- tests/unit/model/rollback-attributes-test.js | 294 +++++++------- .../filtered-record-array-test.js | 2 +- tests/unit/record-arrays/record-array-test.js | 3 +- 16 files changed, 850 insertions(+), 897 deletions(-) diff --git a/tests/unit/adapters/build-url-mixin/path-for-type-test.js b/tests/unit/adapters/build-url-mixin/path-for-type-test.js index f6861ac4cd6..a3c07356423 100644 --- a/tests/unit/adapters/build-url-mixin/path-for-type-test.js +++ b/tests/unit/adapters/build-url-mixin/path-for-type-test.js @@ -1,39 +1,45 @@ import setupStore from 'dummy/tests/helpers/store'; import DS from 'ember-data'; +import Ember from 'ember'; import {module, test} from 'qunit'; -var env, adapter; +let env, adapter; +let { run } = Ember; module("unit/adapters/build-url-mixin/path-for-type - DS.BuildURLMixin#pathForType", { beforeEach() { // test for overriden pathForType methods which return null path values - var customPathForType = { + let customPathForType = { pathForType(type) { if (type === 'rootModel') { return ''; } return this._super(type); } }; - var Adapter = DS.Adapter.extend(DS.BuildURLMixin, customPathForType); + let Adapter = DS.Adapter.extend(DS.BuildURLMixin, customPathForType); env = setupStore({ adapter: Adapter }); adapter = env.adapter; + }, + + afterEach() { + run(env.container, 'destroy'); } }); test('pathForType - works with camelized types', function(assert) { - assert.equal(adapter.pathForType('superUser'), "superUsers"); + assert.equal(adapter.pathForType('superUser'), 'superUsers'); }); test('pathForType - works with dasherized types', function(assert) { - assert.equal(adapter.pathForType('super-user'), "superUsers"); + assert.equal(adapter.pathForType('super-user'), 'superUsers'); }); test('pathForType - works with underscored types', function(assert) { - assert.equal(adapter.pathForType('super_user'), "superUsers"); + assert.equal(adapter.pathForType('super_user'), 'superUsers'); }); diff --git a/tests/unit/adapters/json-api-adapter/ajax-test.js b/tests/unit/adapters/json-api-adapter/ajax-test.js index 992e4adeb69..4d2044a6077 100644 --- a/tests/unit/adapters/json-api-adapter/ajax-test.js +++ b/tests/unit/adapters/json-api-adapter/ajax-test.js @@ -5,8 +5,8 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var Person, Place, store, adapter, env; -var run = Ember.run; +let Person, Place, store, adapter, env; +const { run } = Ember; module("unit/adapters/json-api-adapter/ajax - building requests", { beforeEach() { @@ -18,19 +18,19 @@ module("unit/adapters/json-api-adapter/ajax - building requests", { }, afterEach() { - run(function() { + run(() => { store.destroy(); env.container.destroy(); }); } }); -test("ajaxOptions() adds Accept when no other headers exist", function(assert) { - var url = 'example.com'; - var type = 'GET'; - var ajaxOptions = adapter.ajaxOptions(url, type, {}); - var receivedHeaders = []; - var fakeXHR = { +test('ajaxOptions() adds Accept when no other headers exist', function(assert) { + let url = 'example.com'; + let type = 'GET'; + let ajaxOptions = adapter.ajaxOptions(url, type, {}); + let receivedHeaders = []; + let fakeXHR = { setRequestHeader(key, value) { receivedHeaders.push([key, value]); } @@ -39,13 +39,13 @@ test("ajaxOptions() adds Accept when no other headers exist", function(assert) { assert.deepEqual(receivedHeaders, [['Accept', 'application/vnd.api+json']], 'headers assigned'); }); -test("ajaxOptions() adds Accept header to existing headers", function(assert) { +test('ajaxOptions() adds Accept header to existing headers', function(assert) { adapter.headers = { 'Other-key': 'Other Value' }; - var url = 'example.com'; - var type = 'GET'; - var ajaxOptions = adapter.ajaxOptions(url, type, {}); - var receivedHeaders = []; - var fakeXHR = { + let url = 'example.com'; + let type = 'GET'; + let ajaxOptions = adapter.ajaxOptions(url, type, {}); + let receivedHeaders = []; + let fakeXHR = { setRequestHeader(key, value) { receivedHeaders.push([key, value]); } @@ -54,15 +54,15 @@ test("ajaxOptions() adds Accept header to existing headers", function(assert) { assert.deepEqual(receivedHeaders, [['Accept', 'application/vnd.api+json'], ['Other-key', 'Other Value']], 'headers assigned'); }); -test("ajaxOptions() adds Accept header to existing computed properties headers", function(assert) { +test('ajaxOptions() adds Accept header to existing computed properties headers', function(assert) { adapter.headers = Ember.computed(function() { return { 'Other-key': 'Other Value' }; }); - var url = 'example.com'; - var type = 'GET'; - var ajaxOptions = adapter.ajaxOptions(url, type, {}); - var receivedHeaders = []; - var fakeXHR = { + let url = 'example.com'; + let type = 'GET'; + let ajaxOptions = adapter.ajaxOptions(url, type, {}); + let receivedHeaders = []; + let fakeXHR = { setRequestHeader(key, value) { receivedHeaders.push([key, value]); } diff --git a/tests/unit/adapters/rest-adapter/ajax-test.js b/tests/unit/adapters/rest-adapter/ajax-test.js index 1dc80a2c662..b3196c504c3 100644 --- a/tests/unit/adapters/rest-adapter/ajax-test.js +++ b/tests/unit/adapters/rest-adapter/ajax-test.js @@ -7,9 +7,9 @@ import DS from 'ember-data'; import isEnabled from 'ember-data/-private/features'; var Person, Place, store, adapter, env; -var run = Ember.run; +const { run } = Ember; -module("unit/adapters/rest-adapter/ajax - building requests", { +module('unit/adapters/rest-adapter/ajax - building requests', { beforeEach() { Person = { modelName: 'person' }; Place = { modelName: 'place' }; @@ -19,45 +19,48 @@ module("unit/adapters/rest-adapter/ajax - building requests", { }, afterEach() { - run(function() { + run(() => { store.destroy(); env.container.destroy(); }); } }); -test("When an id is searched, the correct url should be generated", function(assert) { +test('When an id is searched, the correct url should be generated', function(assert) { assert.expect(2); - var count = 0; + + let count = 0; if (isEnabled('ds-improved-ajax')) { adapter._makeRequest = function(request) { - if (count === 0) { assert.equal(request.url, '/people/1', "should create the correct url"); } - if (count === 1) { assert.equal(request.url, '/places/1', "should create the correct url"); } + if (count === 0) { assert.equal(request.url, '/people/1', 'should create the correct url'); } + if (count === 1) { assert.equal(request.url, '/places/1', 'should create the correct url'); } count++; return Ember.RSVP.resolve(); }; } else { adapter.ajax = function(url, method) { - if (count === 0) { assert.equal(url, '/people/1', "should create the correct url"); } - if (count === 1) { assert.equal(url, '/places/1', "should create the correct url"); } + if (count === 0) { assert.equal(url, '/people/1', 'should create the correct url'); } + if (count === 1) { assert.equal(url, '/places/1', 'should create the correct url'); } count++; return Ember.RSVP.resolve(); }; } - run(function() { - adapter.findRecord(store, Person, 1, {}); - adapter.findRecord(store, Place, 1, {}); + return run(() => { + return Ember.RSVP.Promise.all([ + adapter.findRecord(store, Person, 1, {}), + adapter.findRecord(store, Place, 1, {}) + ]) }); }); -test("id's should be sanatized", function(assert) { +test(`id's should be sanatized`, function(assert) { assert.expect(1); if (isEnabled('ds-improved-ajax')) { adapter._makeRequest = function(request) { - assert.equal(request.url, '/people/..%2Fplace%2F1', "should create the correct url"); + assert.equal(request.url, '/people/..%2Fplace%2F1', `should create the correct url`); return Ember.RSVP.resolve(); }; } else { @@ -66,30 +69,36 @@ test("id's should be sanatized", function(assert) { return Ember.RSVP.resolve(); }; } - run(function() { - adapter.findRecord(store, Person, '../place/1', {}); - }); + + return run(() => adapter.findRecord(store, Person, '../place/1', {})); }); -test("ajaxOptions() headers are set", function(assert) { - adapter.headers = { 'Content-Type': 'application/json', 'Other-key': 'Other Value' }; - var url = 'example.com'; - var type = 'GET'; - var ajaxOptions = adapter.ajaxOptions(url, type, {}); - var receivedHeaders = []; - var fakeXHR = { +test('ajaxOptions() headers are set', function(assert) { + adapter.headers = { + 'Content-Type': 'application/json', + 'Other-key': 'Other Value' + }; + + let url = 'example.com'; + let type = 'GET'; + let ajaxOptions = adapter.ajaxOptions(url, type, {}); + let receivedHeaders = []; + let fakeXHR = { setRequestHeader(key, value) { receivedHeaders.push([key, value]); } }; ajaxOptions.beforeSend(fakeXHR); - assert.deepEqual(receivedHeaders, [['Content-Type', 'application/json'], ['Other-key', 'Other Value']], 'headers assigned'); + assert.deepEqual(receivedHeaders, [ + ['Content-Type', 'application/json'], + ['Other-key', 'Other Value'] + ], 'headers assigned'); }); -test("ajaxOptions() do not serializes data when GET", function(assert) { - var url = 'example.com'; - var type = 'GET'; - var ajaxOptions = adapter.ajaxOptions(url, type, { data: { key: 'value' } }); +test('ajaxOptions() do not serializes data when GET', function(assert) { + let url = 'example.com'; + let type = 'GET'; + let ajaxOptions = adapter.ajaxOptions(url, type, { data: { key: 'value' } }); assert.deepEqual(ajaxOptions, { context: adapter, @@ -102,13 +111,13 @@ test("ajaxOptions() do not serializes data when GET", function(assert) { }); }); -test("ajaxOptions() serializes data when not GET", function(assert) { - var url = 'example.com'; - var type = 'POST'; - var ajaxOptions = adapter.ajaxOptions(url, type, { data: { key: 'value' } }); +test('ajaxOptions() serializes data when not GET', function(assert) { + let url = 'example.com'; + let type = 'POST'; + let ajaxOptions = adapter.ajaxOptions(url, type, { data: { key: 'value' } }); assert.deepEqual(ajaxOptions, { - contentType: "application/json; charset=utf-8", + contentType: 'application/json; charset=utf-8', context: adapter, data: '{"key":"value"}', dataType: 'json', @@ -117,10 +126,10 @@ test("ajaxOptions() serializes data when not GET", function(assert) { }); }); -test("ajaxOptions() empty data", function(assert) { - var url = 'example.com'; - var type = 'POST'; - var ajaxOptions = adapter.ajaxOptions(url, type, {}); +test('ajaxOptions() empty data', function(assert) { + let url = 'example.com'; + let type = 'POST'; + let ajaxOptions = adapter.ajaxOptions(url, type, {}); assert.deepEqual(ajaxOptions, { context: adapter, diff --git a/tests/unit/adapters/rest-adapter/build-query-test.js b/tests/unit/adapters/rest-adapter/build-query-test.js index ca991cc1ea9..f8b6f64f5f7 100644 --- a/tests/unit/adapters/rest-adapter/build-query-test.js +++ b/tests/unit/adapters/rest-adapter/build-query-test.js @@ -1,9 +1,9 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; -module("unit/adapters/rest-adapter/build-query - building queries"); +module('unit/adapters/rest-adapter/build-query - building queries'); -test("buildQuery() returns an empty query when snapshot has no query params", function(assert) { +test('buildQuery() returns an empty query when snapshot has no query params', function(assert) { const adapter = DS.RESTAdapter.create(); const snapshotStub = {}; @@ -12,14 +12,14 @@ test("buildQuery() returns an empty query when snapshot has no query params", fu assert.deepEqual(query, {}, 'query is empty'); }); -test("buildQuery - doesn't fail without a snapshot", function(assert) { +test(`buildQuery - doesn't fail without a snapshot`, function(assert) { const adapter = DS.RESTAdapter.create(); const query = adapter.buildQuery(); assert.deepEqual(query, {}, 'returns an empty query'); }); -test("buildQuery() returns query with `include` from snapshot", function(assert) { +test('buildQuery() returns query with `include` from snapshot', function(assert) { const adapter = DS.RESTAdapter.create(); const snapshotStub = { include: 'comments' }; diff --git a/tests/unit/adapters/rest-adapter/detailed-message-test.js b/tests/unit/adapters/rest-adapter/detailed-message-test.js index 0078b54f1a0..946a510b7ca 100644 --- a/tests/unit/adapters/rest-adapter/detailed-message-test.js +++ b/tests/unit/adapters/rest-adapter/detailed-message-test.js @@ -6,16 +6,14 @@ import DS from 'ember-data'; let adapter, env; -module("unit/adapters/rest_adapter/detailed_message_test - DS.RESTAdapter#generatedDetailedMessage", { - +module('unit/adapters/rest_adapter/detailed_message_test - DS.RESTAdapter#generatedDetailedMessage', { beforeEach() { env = setupStore({ adapter: DS.RESTAdapter }); adapter = env.adapter; } - }); -test("generating a wonderfully friendly error message should work", (assert) => { +test('generating a wonderfully friendly error message should work', function(assert) { assert.expect(1); let friendlyMessage = adapter.generatedDetailedMessage( @@ -28,24 +26,27 @@ test("generating a wonderfully friendly error message should work", (assert) => } ); - assert.equal(friendlyMessage, ["Ember Data Request GET /teapots/testing returned a 418", - "Payload (text/plain)", - "I'm a little teapot, short and stout"].join("\n")); + assert.equal(friendlyMessage, [ + 'Ember Data Request GET /teapots/testing returned a 418', + 'Payload (text/plain)', + `I'm a little teapot, short and stout` + ].join('\n')); }); -test("generating a friendly error message with a missing content-type header should work", (assert) => { - +test('generating a friendly error message with a missing content-type header should work', function(assert) { let friendlyMessage = adapter.generatedDetailedMessage( 418, {}, - "I'm a little teapot, short and stout", + `I'm a little teapot, short and stout`, { - url: "/teapots/testing", - method: "GET" + url: '/teapots/testing', + method: 'GET' } ); - assert.equal(friendlyMessage, ["Ember Data Request GET /teapots/testing returned a 418", - "Payload (Empty Content-Type)", - "I'm a little teapot, short and stout"].join("\n")); + assert.equal(friendlyMessage, [ + 'Ember Data Request GET /teapots/testing returned a 418', + 'Payload (Empty Content-Type)', + `I'm a little teapot, short and stout` + ].join('\n')); }); diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 00748933f4d..7a586ccf58f 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -6,21 +6,22 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; import isEnabled from 'ember-data/-private/features'; -var GroupsAdapter, Store; -var maxLength = -1; -var lengths = Ember.A([]); -var requests; +let GroupsAdapter, store, requests; +let maxLength; +let lengths; -module("unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAdapter#groupRecordsForFindMany", { +module('unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAdapter#groupRecordsForFindMany', { beforeEach() { + maxLength = -1; requests = []; + lengths = []; GroupsAdapter = DS.RESTAdapter.extend({ coalesceFindRequests: true, findRecord(store, type, id, snapshot) { - return Ember.RSVP.Promise.resolve({ id: id }); + return { id }; } }); @@ -32,17 +33,15 @@ module("unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda ids: request.data.ids }); - var queryString = request.data.ids.map(function(i) { + let queryString = request.data.ids.map(i => { return encodeURIComponent('ids[]') + '=' + encodeURIComponent(i); }).join('&'); - var fullUrl = request.url + '?' + queryString; + let fullUrl = request.url + '?' + queryString; maxLength = this.get('maxURLLength'); lengths.push(fullUrl.length); - var testRecords = request.data.ids.map(function(id) { - return { id: id }; - }); + let testRecords = request.data.ids.map(id => ({ id })); return Ember.RSVP.Promise.resolve({ 'testRecords' : testRecords }); } }); @@ -54,70 +53,61 @@ module("unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda ids: options.data.ids }); - var queryString = options.data.ids.map(function(i) { + let queryString = options.data.ids.map(i => { return encodeURIComponent('ids[]') + '=' + encodeURIComponent(i); }).join('&'); - var fullUrl = url + '?' + queryString; + let fullUrl = url + '?' + queryString; maxLength = this.get('maxURLLength'); lengths.push(fullUrl.length); - var testRecords = options.data.ids.map(function(id) { - return { id: id }; - }); + let testRecords = options.data.ids.map(id => ({ id })); return Ember.RSVP.Promise.resolve({ 'testRecords' : testRecords }); } }); } - Store = createStore({ + store = createStore({ adapter: GroupsAdapter, testRecord: DS.Model.extend() }); - }, - afterEach() { - requests = null; + Ember.run(store, 'destroy'); } }); test('groupRecordsForFindMany - findMany', function(assert) { - - Ember.run(function() { + let wait = []; + Ember.run(() => { for (var i = 1; i <= 1024; i++) { - Store.findRecord('testRecord', i); + wait.push(store.findRecord('testRecord', i)); } }); - assert.ok(lengths.every(function(len) { - return len <= maxLength; - }), "Some URLs are longer than " + maxLength + " chars"); - + assert.ok(lengths.every(len => len <= maxLength), `Some URLs are longer than ${maxLength} chars`); + return Ember.RSVP.Promise.all(wait); }); test('groupRecordsForFindMany works for encodeURIComponent-ified ids', function(assert) { - Ember.run(function() { - Store.findRecord('testRecord', 'my-id:1'); - Store.findRecord('testRecord', 'my-id:2'); + let wait = []; + Ember.run(() => { + wait.push(store.findRecord('testRecord', 'my-id:1')); + wait.push(store.findRecord('testRecord', 'my-id:2')); }); assert.equal(requests.length, 1); assert.equal(requests[0].url, '/testRecords'); assert.deepEqual(requests[0].ids, ['my-id:1', 'my-id:2']); + + return Ember.RSVP.Promise.all(wait); }); test('_stripIDFromURL works with id being encoded - #4190', function(assert) { - let record; - Ember.run(function() { - record = Store.createRecord('testRecord', { - id: "id:123" - }); - }); - - let adapter = Store.adapterFor('testRecord'); + let record = Ember.run(() => store.createRecord('testRecord', { id: "id:123" })); + let adapter = store.adapterFor('testRecord'); let snapshot = record._internalModel.createSnapshot(); - let strippedUrl = adapter._stripIDFromURL(Store, snapshot); + let strippedUrl = adapter._stripIDFromURL(store, snapshot); assert.equal(strippedUrl, '/testRecords/'); }); diff --git a/tests/unit/model/errors-test.js b/tests/unit/model/errors-test.js index b1efef07942..d51d4246090 100644 --- a/tests/unit/model/errors-test.js +++ b/tests/unit/model/errors-test.js @@ -4,14 +4,11 @@ import testInDebug from 'dummy/tests/helpers/test-in-debug'; const AssertPrototype = QUnit.assert; -var errors; +let errors; -module("unit/model/errors", { +module('unit/model/errors', { beforeEach() { errors = DS.Errors.create(); - }, - - afterEach() { } }); @@ -39,8 +36,9 @@ AssertPrototype.unexpectedSend = function unexpectedSend(eventName) { this.ok(false, 'unexpected send : ' + eventName); }.bind(AssertPrototype); -testInDebug("add error", function(assert) { +testInDebug('add error', function(assert) { assert.expect(10); + errors.trigger = assert.becameInvalid; updateErrors(() => errors.add('firstName', 'error')); errors.trigger = assert.unexpectedSend; @@ -54,8 +52,9 @@ testInDebug("add error", function(assert) { assert.equal(errors.get('length'), 4, 'it has 4 errors'); }); -testInDebug("get error", function(assert) { +testInDebug('get error', function(assert) { assert.expect(11); + assert.ok(errors.get('firstObject') === undefined, 'returns undefined'); errors.trigger = assert.becameInvalid; updateErrors(() => errors.add('firstName', 'error')); @@ -77,8 +76,9 @@ testInDebug("get error", function(assert) { assert.deepEqual(errors.get('messages'), ['error', 'error2', 'error3']); }); -testInDebug("remove error", function(assert) { +testInDebug('remove error', function(assert) { assert.expect(8); + errors.trigger = assert.becameInvalid; updateErrors(() => errors.add('firstName', 'error')); errors.trigger = assert.becameValid; @@ -90,8 +90,9 @@ testInDebug("remove error", function(assert) { updateErrors(() => errors.remove('firstName')); }); -testInDebug("remove same errors from different attributes", function(assert) { +testInDebug('remove same errors from different attributes', function(assert) { assert.expect(9); + errors.trigger = assert.becameInvalid; updateErrors(() => errors.add('firstName', 'error')); updateErrors(() => errors.add('lastName', 'error')); @@ -104,8 +105,9 @@ testInDebug("remove same errors from different attributes", function(assert) { assert.ok(errors.get('isEmpty'), 'it is empty'); }); -testInDebug("clear errors", function(assert) { +testInDebug('clear errors', function(assert) { assert.expect(8); + errors.trigger = assert.becameInvalid; updateErrors(() => errors.add('firstName', ['error', 'error1'])); assert.equal(errors.get('length'), 2, 'it has 2 errors'); diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index 04b0fb8ae2c..c7dbd9fa820 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -5,329 +5,308 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var get = Ember.get; -var run = Ember.run; +const { get, run } = Ember; -module("unit/model/lifecycle_callbacks - Lifecycle Callbacks"); +module('unit/model/lifecycle_callbacks - Lifecycle Callbacks'); -test("a record receives a didLoad callback when it has finished loading", function(assert) { +test('a record receives a didLoad callback when it has finished loading', function(assert) { assert.expect(3); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr(), didLoad() { - assert.ok("The didLoad callback was called"); + assert.ok('The didLoad callback was called'); } }); - var adapter = DS.Adapter.extend({ + const Adapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: "Foo" }); + return { id: 1, name: 'Foo' }; } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, person: Person }); - run(function() { - store.findRecord('person', 1).then(function(person) { - assert.equal(person.get('id'), "1", "The person's ID is available"); - assert.equal(person.get('name'), "Foo", "The person's properties are available"); + return run(() => { + return store.findRecord('person', 1).then(person => { + assert.equal(person.get('id'), '1', `The person's ID is available`); + assert.equal(person.get('name'), 'Foo', `The person's properties are availablez`); }); }); }); -test("TEMPORARY: a record receives a didLoad callback once it materializes if it wasn't materialized when loaded", function(assert) { +test(`TEMPORARY: a record receives a didLoad callback once it materializes if it wasn't materialized when loaded`, function(assert) { assert.expect(2); - var didLoadCalled = 0; - var Person = DS.Model.extend({ + let didLoadCalled = 0; + const Person = DS.Model.extend({ name: DS.attr(), didLoad() { didLoadCalled++; } }); - var store = createStore({ + let store = createStore({ person: Person }); - run(function() { + run(() => { store._pushInternalModel({ id: 1, type: 'person' }); assert.equal(didLoadCalled, 0, "didLoad was not called"); }); - run(function() { - store.peekRecord('person', 1); - }); - run(function() { - assert.equal(didLoadCalled, 1, "didLoad was called"); - }); + run(() => store.peekRecord('person', 1)); + assert.equal(didLoadCalled, 1, "didLoad was called"); }); -test("a record receives a didUpdate callback when it has finished updating", function(assert) { +test('a record receives a didUpdate callback when it has finished updating', function(assert) { assert.expect(5); - var callCount = 0; + let callCount = 0; - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ bar: DS.attr('string'), name: DS.attr('string'), didUpdate() { callCount++; - assert.equal(get(this, 'isSaving'), false, "record should be saving"); - assert.equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); + assert.equal(get(this, 'isSaving'), false, 'record should be saving'); + assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); } }); - var adapter = DS.Adapter.extend({ + const Adapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: "Foo" }); + return { id: 1, name: 'Foo' }; }, updateRecord(store, type, snapshot) { - assert.equal(callCount, 0, "didUpdate callback was not called until didSaveRecord is called"); + assert.equal(callCount, 0, 'didUpdate callback was not called until didSaveRecord is called'); return Ember.RSVP.resolve(); } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, person: Person }); - var asyncPerson; - run(function() { - asyncPerson = store.findRecord('person', 1); - }); - assert.equal(callCount, 0, "precond - didUpdate callback was not called yet"); + let asyncPerson = run(() => store.findRecord('person', 1)); + + assert.equal(callCount, 0, 'precond - didUpdate callback was not called yet'); - run(function() { - asyncPerson.then(function(person) { - return run(function() { + return run(() => { + return asyncPerson.then(person => { + return run(() => { person.set('bar', "Bar"); return person.save(); }); - }).then(function() { - assert.equal(callCount, 1, "didUpdate called after update"); + }).then(() => { + assert.equal(callCount, 1, 'didUpdate called after update'); }); }); }); -test("a record receives a didCreate callback when it has finished updating", function(assert) { +test('a record receives a didCreate callback when it has finished updating', function(assert) { assert.expect(5); - var callCount = 0; + let callCount = 0; - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ didCreate() { callCount++; - assert.equal(get(this, 'isSaving'), false, "record should not be saving"); - assert.equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); + assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); + assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); } }); - var adapter = DS.Adapter.extend({ + const Adapter = DS.Adapter.extend({ createRecord(store, type, snapshot) { - assert.equal(callCount, 0, "didCreate callback was not called until didSaveRecord is called"); + assert.equal(callCount, 0, 'didCreate callback was not called until didSaveRecord is called'); return Ember.RSVP.resolve(); } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, person: Person }); - assert.equal(callCount, 0, "precond - didCreate callback was not called yet"); - var person; - - run(function() { - person = store.createRecord('person', { id: 69, name: "Newt Gingrich" }); - }); + assert.equal(callCount, 0, 'precond - didCreate callback was not called yet'); + let person = run(() => store.createRecord('person', { id: 69, name: 'Newt Gingrich' })); - run(function() { - person.save().then(function() { - assert.equal(callCount, 1, "didCreate called after commit"); + return run(() => { + return person.save().then(() => { + assert.equal(callCount, 1, 'didCreate called after commit'); }); }); }); -test("a record receives a didDelete callback when it has finished deleting", function(assert) { +test('a record receives a didDelete callback when it has finished deleting', function(assert) { assert.expect(5); - var callCount = 0; + let callCount = 0; - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ bar: DS.attr('string'), name: DS.attr('string'), didDelete() { callCount++; - assert.equal(get(this, 'isSaving'), false, "record should not be saving"); - assert.equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); + assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); + assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); } }); - var adapter = DS.Adapter.extend({ + const Adapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: "Foo" }); + return { id: 1, name: 'Foo' }; }, deleteRecord(store, type, snapshot) { - assert.equal(callCount, 0, "didDelete callback was not called until didSaveRecord is called"); + assert.equal(callCount, 0, 'didDelete callback was not called until didSaveRecord is called'); return Ember.RSVP.resolve(); } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, person: Person }); - var asyncPerson; - - run(function() { - asyncPerson = store.findRecord('person', 1); - }); + let asyncPerson = run(() => store.findRecord('person', 1)); - assert.equal(callCount, 0, "precond - didDelete callback was not called yet"); + assert.equal(callCount, 0, 'precond - didDelete callback was not called yet'); - run(function() { - asyncPerson.then(function(person) { - return run(function() { + return run(() => { + return asyncPerson.then(person => { + return run(() => { person.deleteRecord(); return person.save(); }); - }).then(function() { - assert.equal(callCount, 1, "didDelete called after delete"); + }).then(() => { + assert.equal(callCount, 1, 'didDelete called after delete'); }); }); }); -test("an uncommited record also receives a didDelete callback when it is deleted", function(assert) { +test('an uncommited record also receives a didDelete callback when it is deleted', function(assert) { assert.expect(4); - var callCount = 0; + let callCount = 0; - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ bar: DS.attr('string'), name: DS.attr('string'), didDelete() { callCount++; - assert.equal(get(this, 'isSaving'), false, "record should not be saving"); - assert.equal(get(this, 'hasDirtyAttributes'), false, "record should not be dirty"); + assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); + assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); } }); - var store = createStore({ + let store = createStore({ adapter: DS.Adapter.extend(), person: Person }); - var person; - run(function() { - person = store.createRecord('person', { name: 'Tomster' }); - }); + let person = run(() => store.createRecord('person', { name: 'Tomster' })); - assert.equal(callCount, 0, "precond - didDelete callback was not called yet"); + assert.equal(callCount, 0, 'precond - didDelete callback was not called yet'); - run(function() { - person.deleteRecord(); - }); + run(() => person.deleteRecord()); - assert.equal(callCount, 1, "didDelete called after delete"); + assert.equal(callCount, 1, 'didDelete called after delete'); }); -test("a record receives a becameInvalid callback when it became invalid", function(assert) { - assert.expect(5); +test('a record receives a becameInvalid callback when it became invalid', function(assert) { + assert.expect(8); - var callCount = 0; + let callCount = 0; - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ bar: DS.attr('string'), name: DS.attr('string'), becameInvalid() { callCount++; - assert.equal(get(this, 'isSaving'), false, "record should not be saving"); - assert.equal(get(this, 'hasDirtyAttributes'), true, "record should be dirty"); + assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); + assert.equal(get(this, 'hasDirtyAttributes'), true, 'record should be dirty'); } }); - var adapter = DS.Adapter.extend({ + const Adapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: "Foo" }); + return { id: 1, name: "Foo" }; }, updateRecord(store, type, snapshot) { - assert.equal(callCount, 0, "becameInvalid callback was not called until recordWasInvalid is called"); + assert.equal(callCount, 0, 'becameInvalid callback was not called until recordWasInvalid is called'); return Ember.RSVP.reject(new DS.InvalidError([ { - title: "Invalid Attribute", - detail: "error", + title: 'Invalid Attribute', + detail: 'error', source: { - pointer: "/data/attributes/bar" + pointer: '/data/attributes/bar' } } ])); } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, person: Person }); - var asyncPerson; - run(function() { - asyncPerson = store.findRecord('person', 1); - }); - assert.equal(callCount, 0, "precond - becameInvalid callback was not called yet"); + let asyncPerson = run(() => store.findRecord('person', 1)); + assert.equal(callCount, 0, 'precond - becameInvalid callback was not called yet'); // Make sure that the error handler has a chance to attach before // save fails. - run(function() { - asyncPerson.then(function(person) { - return run(function() { - person.set('bar', "Bar"); + return run(() => { + return asyncPerson.then(person => { + return run(() => { + person.set('bar', 'Bar'); return person.save(); }); - }).then(null, function() { - assert.equal(callCount, 1, "becameInvalid called after invalidating"); + }).catch(reason => { + assert.ok(reason.isAdapterError, 'reason should have been an adapter error'); + assert.equal(reason.errors.length, 1, 'reason should have one error'); + assert.equal(reason.errors[0].title, 'Invalid Attribute'); + assert.equal(callCount, 1, 'becameInvalid called after invalidating'); }); }); }); -test("an ID of 0 is allowed", function(assert) { - - var Person = DS.Model.extend({ +test('an ID of 0 is allowed', function(assert) { + const Person = DS.Model.extend({ name: DS.attr('string') }); - var store = createStore({ + let store = createStore({ person: Person }); - run(function() { + run(() => { store.push({ data: { type: 'person', id: '0', attributes: { - name: "Tom Dale" + name: 'Tom Dale' } } }); }); - assert.equal(store.peekAll('person').objectAt(0).get('name'), "Tom Dale", "found record with id 0"); + assert.equal(store.peekAll('person').objectAt(0).get('name'), 'Tom Dale', 'found record with id 0'); }); diff --git a/tests/unit/model/merge-test.js b/tests/unit/model/merge-test.js index 11ae3cd9a03..26e93f8aac1 100644 --- a/tests/unit/model/merge-test.js +++ b/tests/unit/model/merge-test.js @@ -5,10 +5,10 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var Person; -var run = Ember.run; +let Person; +const { run } = Ember; -module("unit/model/merge - Merging", { +module('unit/model/merge - Merging', { beforeEach() { Person = DS.Model.extend({ name: DS.attr(), @@ -17,43 +17,41 @@ module("unit/model/merge - Merging", { } }); -test("When a record is in flight, changes can be made", function(assert) { +test('When a record is in flight, changes can be made', function(assert) { assert.expect(3); - var adapter = DS.Adapter.extend({ + const Adapter = DS.Adapter.extend({ createRecord(store, type, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: "Tom Dale" }); + return { id: 1, name: 'Tom Dale' }; } }); - var person; - var store = createStore({ - adapter: adapter, + + let store = createStore({ + adapter: Adapter, person: Person }); - run(function() { - person = store.createRecord('person', { name: "Tom Dale" }); - }); + let person = run(() => store.createRecord('person', { name: 'Tom Dale' })); // Make sure saving isn't resolved synchronously - run(function() { - var promise = person.save(); + return run(() => { + let save = person.save(); - assert.equal(person.get('name'), "Tom Dale"); + assert.equal(person.get('name'), 'Tom Dale'); - person.set('name', "Thomas Dale"); + person.set('name', 'Thomas Dale'); - promise.then(function(person) { - assert.equal(person.get('hasDirtyAttributes'), true, "The person is still dirty"); - assert.equal(person.get('name'), "Thomas Dale", "The changes made still apply"); + return save.then(person => { + assert.equal(person.get('hasDirtyAttributes'), true, 'The person is still dirty'); + assert.equal(person.get('name'), 'Thomas Dale', 'The changes made still apply'); }); }); }); -test("Make sure snapshot is created at save time not at flush time", function(assert) { +test('Make sure snapshot is created at save time not at flush time', function(assert) { assert.expect(5); - var adapter = DS.Adapter.extend({ + const Adapter = DS.Adapter.extend({ updateRecord(store, type, snapshot) { assert.equal(snapshot.attr('name'), 'Thomas Dale'); @@ -61,10 +59,10 @@ test("Make sure snapshot is created at save time not at flush time", function(as } }); - var store = createStore({ adapter: adapter, person: Person }); - var person; + let store = createStore({ adapter: Adapter, person: Person }); - run(function() { + let person; + run(() => { person = store.push({ data: { type: 'person', @@ -74,44 +72,44 @@ test("Make sure snapshot is created at save time not at flush time", function(as } } }); - person.set('name', "Thomas Dale"); + person.set('name', 'Thomas Dale'); }); - run(function() { - var promise = person.save(); + return run(() => { + let promise = person.save(); - assert.equal(person.get('name'), "Thomas Dale"); + assert.equal(person.get('name'), 'Thomas Dale'); - person.set('name', "Tomasz Dale"); + person.set('name', 'Tomasz Dale'); - assert.equal(person.get('name'), "Tomasz Dale", "the local changes applied on top"); + assert.equal(person.get('name'), 'Tomasz Dale', 'the local changes applied on top'); - promise.then(assert.wait(function(person) { - assert.equal(person.get('hasDirtyAttributes'), true, "The person is still dirty"); - assert.equal(person.get('name'), "Tomasz Dale", "The local changes apply"); - })); + return promise.then(person => { + assert.equal(person.get('hasDirtyAttributes'), true, 'The person is still dirty'); + assert.equal(person.get('name'), "Tomasz Dale", 'The local changes apply'); + }); }); }); test("When a record is in flight, pushes are applied underneath the in flight changes", function(assert) { assert.expect(6); - var adapter = DS.Adapter.extend({ + const Adapter = DS.Adapter.extend({ updateRecord(store, type, snapshot) { // Make sure saving isn't resolved synchronously - return new Ember.RSVP.Promise(function(resolve, reject) { - run.next(null, resolve, { id: 1, name: "Senor Thomas Dale, Esq.", city: "Portland" }); + return new Ember.RSVP.Promise(resolve => { + run.next(null, resolve, { id: 1, name: 'Senor Thomas Dale, Esq.', city: 'Portland' }); }); } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, person: Person }); - var person; + let person; - run(function() { + run(() => { person = store.push({ data: { type: 'person', @@ -121,15 +119,15 @@ test("When a record is in flight, pushes are applied underneath the in flight ch } } }); - person.set('name', "Thomas Dale"); + person.set('name', 'Thomas Dale'); }); - run(function() { + return run(() => { var promise = person.save(); - assert.equal(person.get('name'), "Thomas Dale"); + assert.equal(person.get('name'), 'Thomas Dale'); - person.set('name', "Tomasz Dale"); + person.set('name', 'Tomasz Dale'); store.push({ data: { @@ -142,43 +140,43 @@ test("When a record is in flight, pushes are applied underneath the in flight ch } }); - assert.equal(person.get('name'), "Tomasz Dale", "the local changes applied on top"); - assert.equal(person.get('city'), "PDX", "the pushed change is available"); + assert.equal(person.get('name'), 'Tomasz Dale', 'the local changes applied on top'); + assert.equal(person.get('city'), 'PDX', 'the pushed change is available'); - promise.then(assert.wait(function(person) { - assert.equal(person.get('hasDirtyAttributes'), true, "The person is still dirty"); - assert.equal(person.get('name'), "Tomasz Dale", "The local changes apply"); - assert.equal(person.get('city'), "Portland", "The updates from the server apply on top of the previous pushes"); - })); + return promise.then(person => { + assert.equal(person.get('hasDirtyAttributes'), true, 'The person is still dirty'); + assert.equal(person.get('name'), 'Tomasz Dale', 'The local changes apply'); + assert.equal(person.get('city'), 'Portland', 'The updates from the server apply on top of the previous pushes'); + }); }); }); -test("When a record is dirty, pushes are overridden by local changes", function(assert) { - var store = createStore({ +test('When a record is dirty, pushes are overridden by local changes', function(assert) { + let store = createStore({ adapter: DS.Adapter, person: Person }); - var person; + let person; - run(function() { + run(() => { person = store.push({ data: { type: 'person', id: '1', attributes: { - name: "Tom Dale", - city: "San Francisco" + name: 'Tom Dale', + city: 'San Francisco' } } }); - person.set('name', "Tomasz Dale"); + person.set('name', 'Tomasz Dale'); }); - assert.equal(person.get('hasDirtyAttributes'), true, "the person is currently dirty"); - assert.equal(person.get('name'), "Tomasz Dale", "the update was effective"); - assert.equal(person.get('city'), "San Francisco", "the original data applies"); + assert.equal(person.get('hasDirtyAttributes'), true, 'the person is currently dirty'); + assert.equal(person.get('name'), 'Tomasz Dale', 'the update was effective'); + assert.equal(person.get('city'), 'San Francisco', 'the original data applies'); - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -191,124 +189,123 @@ test("When a record is dirty, pushes are overridden by local changes", function( }); }); - assert.equal(person.get('hasDirtyAttributes'), true, "the local changes are reapplied"); - assert.equal(person.get('name'), "Tomasz Dale", "the local changes are reapplied"); - assert.equal(person.get('city'), "Portland", "if there are no local changes, the new data applied"); + assert.equal(person.get('hasDirtyAttributes'), true, 'the local changes are reapplied'); + assert.equal(person.get('name'), 'Tomasz Dale', 'the local changes are reapplied'); + assert.equal(person.get('city'), 'Portland', 'if there are no local changes, the new data applied'); }); -test("When a record is invalid, pushes are overridden by local changes", function(assert) { - var store = createStore({ +test('When a record is invalid, pushes are overridden by local changes', function(assert) { + let store = createStore({ adapter: DS.Adapter, person: Person }); - var person; + let person; - run(function() { + run(() => { person = store.push({ data: { type: 'person', id: '1', attributes: { - name: "Brendan McLoughlin", - city: "Boston" + name: 'Brendan McLoughlin', + city: 'Boston' } } }); - person.set('name', "Brondan McLoughlin"); + person.set('name', 'Brondan McLoughlin'); person.send('becameInvalid'); }); - assert.equal(person.get('hasDirtyAttributes'), true, "the person is currently dirty"); - assert.equal(person.get('isValid'), false, "the person is currently invalid"); - assert.equal(person.get('name'), "Brondan McLoughlin", "the update was effective"); - assert.equal(person.get('city'), "Boston", "the original data applies"); + assert.equal(person.get('hasDirtyAttributes'), true, 'the person is currently dirty'); + assert.equal(person.get('isValid'), false, 'the person is currently invalid'); + assert.equal(person.get('name'), 'Brondan McLoughlin', 'the update was effective'); + assert.equal(person.get('city'), 'Boston', 'the original data applies'); - run(function() { + run(() => { store.push({ data: { type: 'person', id: '1', attributes: { - name: "bmac", - city: "Prague" + name: 'bmac', + city: 'Prague' } } }); }); - assert.equal(person.get('hasDirtyAttributes'), true, "the local changes are reapplied"); - assert.equal(person.get('isValid'), false, "record is still invalid"); - assert.equal(person.get('name'), "Brondan McLoughlin", "the local changes are reapplied"); - assert.equal(person.get('city'), "Prague", "if there are no local changes, the new data applied"); + assert.equal(person.get('hasDirtyAttributes'), true, 'the local changes are reapplied'); + assert.equal(person.get('isValid'), false, 'record is still invalid'); + assert.equal(person.get('name'), 'Brondan McLoughlin', 'the local changes are reapplied'); + assert.equal(person.get('city'), 'Prague', 'if there are no local changes, the new data applied'); }); -test("A record with no changes can still be saved", function(assert) { +test('A record with no changes can still be saved', function(assert) { assert.expect(1); - var adapter = DS.Adapter.extend({ + const Adapter = DS.Adapter.extend({ updateRecord(store, type, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: "Thomas Dale" }); + return { id: 1, name: 'Thomas Dale' }; } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, person: Person }); - var person; - - run(function() { - person = store.push({ + let person = run(() => { + return store.push({ data: { type: 'person', id: '1', attributeS: { - name: "Tom Dale" + name: 'Tom Dale' } } }); }); - run(function() { - person.save().then(function() { - assert.equal(person.get('name'), "Thomas Dale", "the updates occurred"); + return run(() => { + return person.save().then(() => { + assert.equal(person.get('name'), 'Thomas Dale', 'the updates occurred'); }); }); }); -test("A dirty record can be reloaded", function(assert) { +test('A dirty record can be reloaded', function(assert) { assert.expect(3); - var adapter = DS.Adapter.extend({ + const Adapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: "Thomas Dale", city: "Portland" }); + return { id: 1, name: 'Thomas Dale', city: 'Portland' }; } }); - var store = createStore({ - adapter: adapter, + let store = createStore({ + adapter: Adapter, person: Person }); - var person; - run(function() { + let person; + + run(() => { person = store.push({ data: { type: 'person', id: '1', attributes: { - name: "Tom Dale" + name: 'Tom Dale' } } }); - person.set('name', "Tomasz Dale"); + person.set('name', 'Tomasz Dale'); }); - run(function() { - person.reload().then(function() { - assert.equal(person.get('hasDirtyAttributes'), true, "the person is dirty"); - assert.equal(person.get('name'), "Tomasz Dale", "the local changes remain"); - assert.equal(person.get('city'), "Portland", "the new changes apply"); + return run(() => { + return person.reload().then(() => { + assert.equal(person.get('hasDirtyAttributes'), true, 'the person is dirty'); + assert.equal(person.get('name'), "Tomasz Dale", 'the local changes remain'); + assert.equal(person.get('city'), "Portland", 'the new changes apply'); }); }); }); diff --git a/tests/unit/model/relationships-test.js b/tests/unit/model/relationships-test.js index f229c451c14..0d437b51b59 100644 --- a/tests/unit/model/relationships-test.js +++ b/tests/unit/model/relationships-test.js @@ -5,11 +5,10 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var get = Ember.get; -var run = Ember.run; -var Occupation, Person, store; +const { get, run } = Ember; +let Occupation, Person, store; -module("unit/model/relationships - DS.Model", { +module('unit/model/relationships - DS.Model', { beforeEach() { Occupation = DS.Model.extend(); @@ -28,13 +27,13 @@ module("unit/model/relationships - DS.Model", { } }); -test("exposes a hash of the relationships on a model", function(assert) { - run(function() { +test('exposes a hash of the relationships on a model', function(assert) { + run(() => { store.createRecord('person'); store.createRecord('occupation'); }); - var relationships = get(Person, 'relationships'); + let relationships = get(Person, 'relationships'); assert.deepEqual(relationships.get('person'), [ { name: "people", kind: "hasMany" }, { name: "parent", kind: "belongsTo" } @@ -44,17 +43,15 @@ test("exposes a hash of the relationships on a model", function(assert) { ]); }); -test("relationshipNames a hash of the relationships on a model with type as a key", function(assert) { +test('relationshipNames a hash of the relationships on a model with type as a key', function(assert) { assert.deepEqual(get(Person, 'relationshipNames'), { hasMany: ['occupations', 'people'], belongsTo: ["parent"] }); }); -test("eachRelatedType() iterates over relations without duplication", function(assert) { - var relations = []; +test('eachRelatedType() iterates over relations without duplication', function(assert) { + let relations = []; - Person.eachRelatedType(function(modelName) { - relations.push(modelName); - }); + Person.eachRelatedType(modelName => relations.push(modelName)); assert.deepEqual(relations, ['occupation', 'person']); }); diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index b852b37aa37..70ebf242983 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -6,29 +6,29 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var get = Ember.get; -var run = Ember.run; +const { get, run } = Ember; -module("unit/model/relationships - DS.belongsTo"); +module('unit/model/relationships - DS.belongsTo'); -test("belongsTo lazily loads relationships as needed", function(assert) { +test('belongsTo lazily loads relationships as needed', function(assert) { assert.expect(5); - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string'), people: DS.hasMany('person', { async: false }) }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tag: DS.belongsTo('tag', { async: false }) }); - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: [{ type: 'tag', @@ -63,68 +63,68 @@ test("belongsTo lazily loads relationships as needed", function(assert) { }); }); - run(function() { - store.findRecord('person', 1).then(assert.wait(function(person) { - assert.equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + return run(() => { + return store.findRecord('person', 1).then(person => { + assert.equal(get(person, 'name'), 'Tom Dale', 'precond - retrieves person record from store'); - assert.equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); - assert.equal(get(person, 'tag.name'), "friendly", "the tag shuld have name"); + assert.equal(get(person, 'tag') instanceof Tag, true, 'the tag property should return a tag'); + assert.equal(get(person, 'tag.name'), 'friendly', 'the tag shuld have name'); - assert.strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); - assert.asyncEqual(get(person, 'tag'), store.findRecord('tag', 5), "relationship object is the same as object retrieved directly"); - })); + assert.strictEqual(get(person, 'tag'), get(person, 'tag'), 'the returned object is always the same'); + assert.asyncEqual(get(person, 'tag'), store.findRecord('tag', 5), 'relationship object is the same as object retrieved directly'); + }); }); }); -test("async belongsTo relationships work when the data hash has not been loaded", function(assert) { +test('async belongsTo relationships work when the data hash has not been loaded', function(assert) { assert.expect(5); - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string') }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tag: DS.belongsTo('tag', { async: true }) }); - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; env.adapter.findRecord = function(store, type, id, snapshot) { if (type === Person) { - assert.equal(id, 1, "id should be 1"); + assert.equal(id, 1, 'id should be 1'); - return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", tag: 2 }); + return { id: 1, name: 'Tom Dale', tag: 2 }; } else if (type === Tag) { - assert.equal(id, 2, "id should be 2"); + assert.equal(id, 2, 'id should be 2'); - return Ember.RSVP.resolve({ id: 2, name: "friendly" }); + return { id: 2, name: 'friendly' }; } }; - run(function() { - store.findRecord('person', 1).then(assert.wait(function(person) { - assert.equal(get(person, 'name'), "Tom Dale", "The person is now populated"); + return run(() => { + return store.findRecord('person', 1).then(person => { + assert.equal(get(person, 'name'), 'Tom Dale', 'The person is now populated'); - return run(function() { + return run(() => { return get(person, 'tag'); }); - })).then(assert.wait(function(tag) { - assert.equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); - assert.equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); - })); + }).then(tag => { + assert.equal(get(tag, 'name'), 'friendly', 'Tom Dale is now friendly'); + assert.equal(get(tag, 'isLoaded'), true, 'Tom Dale is now loaded'); + }); }); }); -test("async belongsTo relationships work when the data hash has already been loaded", function(assert) { +test('async belongsTo relationships work when the data hash has already been loaded', function(assert) { assert.expect(3); - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string') }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tag: DS.belongsTo('tag', { async: true }) }); @@ -132,7 +132,7 @@ test("async belongsTo relationships work when the data hash has already been loa var env = setupStore({ tag: Tag, person: Person }); var store = env.store; - run(function() { + run(() => { store.push({ data: [{ type: 'tag', @@ -155,25 +155,25 @@ test("async belongsTo relationships work when the data hash has already been loa }); }); - run(function() { - var person = store.peekRecord('person', 1); - assert.equal(get(person, 'name'), "Tom Dale", "The person is now populated"); - return run(function() { + return run(() => { + let person = store.peekRecord('person', 1); + assert.equal(get(person, 'name'), 'Tom Dale', 'The person is now populated'); + return run(() => { return get(person, 'tag'); - }).then(assert.wait(function(tag) { - assert.equal(get(tag, 'name'), "friendly", "Tom Dale is now friendly"); - assert.equal(get(tag, 'isLoaded'), true, "Tom Dale is now loaded"); - })); + }).then(tag => { + assert.equal(get(tag, 'name'), 'friendly', 'Tom Dale is now friendly'); + assert.equal(get(tag, 'isLoaded'), true, 'Tom Dale is now loaded'); + }); }); }); -test("when response to saving a belongsTo is a success but includes changes that reset the users change", function(assert) { - var Tag = DS.Model.extend(); - var User = DS.Model.extend({ tag: DS.belongsTo() }); - var env = setupStore({ user: User, tag: Tag }); - var store = env.store; +test('when response to saving a belongsTo is a success but includes changes that reset the users change', function(assert) { + const Tag = DS.Model.extend(); + const User = DS.Model.extend({ tag: DS.belongsTo() }); + let env = setupStore({ user: User, tag: Tag }); + let { store } = env; - run(function() { + run(() => { store.push({ data: [ { type: 'user', @@ -192,9 +192,7 @@ test("when response to saving a belongsTo is a success but includes changes that let user = store.peekRecord('user', '1'); - run(function() { - user.set('tag', store.peekRecord('tag', '2')); - }); + run(() => user.set('tag', store.peekRecord('tag', '2'))); env.adapter.updateRecord = function() { return { @@ -204,64 +202,65 @@ test("when response to saving a belongsTo is a success but includes changes that }; }; - run(function() { - user.save().then(assert.wait(function(user) { + return run(() => { + return user.save().then(user => { assert.equal(user.get('tag.id'), '1', 'expected new server state to be applied'); - })); + }); }); }); -test("calling createRecord and passing in an undefined value for a relationship should be treated as if null", function(assert) { +test('calling createRecord and passing in an undefined value for a relationship should be treated as if null', function(assert) { assert.expect(1); - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tag: DS.belongsTo('tag', { async: false }) }); - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { - store.createRecord('person', { id: 1, tag: undefined }); - }); + run(() => store.createRecord('person', { id: 1, tag: undefined })); - run(function() { - store.findRecord('person', 1).then(assert.wait(function(person) { - assert.strictEqual(person.get('tag'), null, "undefined values should return null relationships"); - })); + return run(() => { + return store.findRecord('person', 1).then(person => { + assert.strictEqual(person.get('tag'), null, 'undefined values should return null relationships'); + }); }); }); -test("When finding a hasMany relationship the inverse belongsTo relationship is available immediately", function(assert) { - var Occupation = DS.Model.extend({ +test('When finding a hasMany relationship the inverse belongsTo relationship is available immediately', function(assert) { + const Occupation = DS.Model.extend({ description: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), occupations: DS.hasMany('occupation', { async: true }) }); - var env = setupStore({ occupation: Occupation, person: Person }); - var store = env.store; + let env = setupStore({ occupation: Occupation, person: Person }); + let { store } = env; env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.findMany = function(store, type, ids, snapshots) { assert.equal(snapshots[0].belongsTo('person').id, '1'); - return Ember.RSVP.resolve([{ id: 5, description: "fifth" }, { id: 2, description: "second" }]); + return [ + { id: 5, description: "fifth" }, + { id: 2, description: "second" } + ]; }; env.adapter.coalesceFindRequests = true; - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -281,43 +280,43 @@ test("When finding a hasMany relationship the inverse belongsTo relationship is }); }); - run(function() { - store.findRecord('person', 1).then(assert.wait(function(person) { - assert.equal(get(person, 'isLoaded'), true, "isLoaded should be true"); - assert.equal(get(person, 'name'), "Tom Dale", "the person is still Tom Dale"); + return run(() => { + return store.findRecord('person', 1).then(person => { + assert.equal(get(person, 'isLoaded'), true, 'isLoaded should be true'); + assert.equal(get(person, 'name'), 'Tom Dale', 'the person is still Tom Dale'); return get(person, 'occupations'); - })).then(assert.wait(function(occupations) { - assert.equal(get(occupations, 'length'), 2, "the list of occupations should have the correct length"); + }).then(occupations => { + assert.equal(get(occupations, 'length'), 2, 'the list of occupations should have the correct length'); - assert.equal(get(occupations.objectAt(0), 'description'), "fifth", "the occupation is the fifth"); - assert.equal(get(occupations.objectAt(0), 'isLoaded'), true, "the occupation is now loaded"); - })); + assert.equal(get(occupations.objectAt(0), 'description'), 'fifth', 'the occupation is the fifth'); + assert.equal(get(occupations.objectAt(0), 'isLoaded'), true, 'the occupation is now loaded'); + }); }); }); -test("When finding a belongsTo relationship the inverse belongsTo relationship is available immediately", function(assert) { +test('When finding a belongsTo relationship the inverse belongsTo relationship is available immediately', function(assert) { assert.expect(1); - var Occupation = DS.Model.extend({ + const Occupation = DS.Model.extend({ description: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), occupation: DS.belongsTo('occupation', { async: true }) }); - var env = setupStore({ occupation: Occupation, person: Person }); - var store = env.store; + let env = setupStore({ occupation: Occupation, person: Person }); + let store = env.store; env.adapter.findRecord = function(store, type, id, snapshot) { assert.equal(snapshot.belongsTo('person').id, '1'); - return Ember.RSVP.resolve({ id: 5, description: "fifth" }); + return { id: 5, description: 'fifth' }; }; - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -334,30 +333,28 @@ test("When finding a belongsTo relationship the inverse belongsTo relationship i }); }); - run(function() { - store.peekRecord('person', 1).get('occupation'); - }); + run(() => store.peekRecord('person', 1).get('occupation')); }); -test("belongsTo supports relationships to models with id 0", function(assert) { +test('belongsTo supports relationships to models with id 0', function(assert) { assert.expect(5); - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string'), people: DS.hasMany('person', { async: false }) }); - Tag.toString = function() { return "Tag"; }; - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tag: DS.belongsTo('tag', { async: false }) }); - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; + let env = setupStore({ tag: Tag, person: Person }); + let store = env.store; + env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: [{ type: 'tag', @@ -392,34 +389,35 @@ test("belongsTo supports relationships to models with id 0", function(assert) { }); }); - run(function() { - store.findRecord('person', 1).then(assert.wait(function(person) { - assert.equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + return run(() => { + return store.findRecord('person', 1).then(person => { + assert.equal(get(person, 'name'), 'Tom Dale', 'precond - retrieves person record from store'); - assert.equal(get(person, 'tag') instanceof Tag, true, "the tag property should return a tag"); - assert.equal(get(person, 'tag.name'), "friendly", "the tag should have name"); + assert.equal(get(person, 'tag') instanceof Tag, true, 'the tag property should return a tag'); + assert.equal(get(person, 'tag.name'), "friendly", 'the tag should have name'); - assert.strictEqual(get(person, 'tag'), get(person, 'tag'), "the returned object is always the same"); - assert.asyncEqual(get(person, 'tag'), store.findRecord('tag', 0), "relationship object is the same as object retrieved directly"); - })); + assert.strictEqual(get(person, 'tag'), get(person, 'tag'), 'the returned object is always the same'); + assert.asyncEqual(get(person, 'tag'), store.findRecord('tag', 0), 'relationship object is the same as object retrieved directly'); + }); }); }); -testInDebug("belongsTo gives a warning when provided with a serialize option", function(assert) { - var Hobby = DS.Model.extend({ +testInDebug('belongsTo gives a warning when provided with a serialize option', function(assert) { + const Hobby = DS.Model.extend({ name: DS.attr('string') }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), hobby: DS.belongsTo('hobby', { serialize: true, async: true }) }); - var env = setupStore({ hobby: Hobby, person: Person }); - var store = env.store; + let env = setupStore({ hobby: Hobby, person: Person }); + let store = env.store; + env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: [{ type: 'hobby', @@ -448,30 +446,31 @@ testInDebug("belongsTo gives a warning when provided with a serialize option", f }); }); - run(function() { - store.findRecord('person', 1).then(assert.wait(function(person) { - assert.expectWarning(function() { + return run(() => { + return store.findRecord('person', 1).then(person =>{ + assert.expectWarning(() => { get(person, 'hobby'); }, /You provided a serialize option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.Serializer and it's implementations/); - })); + }); }); }); testInDebug("belongsTo gives a warning when provided with an embedded option", function(assert) { - var Hobby = DS.Model.extend({ + const Hobby = DS.Model.extend({ name: DS.attr('string') }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), hobby: DS.belongsTo('hobby', { embedded: true, async: true }) }); - var env = setupStore({ hobby: Hobby, person: Person }); - var store = env.store; + let env = setupStore({ hobby: Hobby, person: Person }); + let { store } = env; + env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: [{ type: 'hobby', @@ -500,32 +499,31 @@ testInDebug("belongsTo gives a warning when provided with an embedded option", f }); }); - run(function() { - store.findRecord('person', 1).then(assert.wait(function(person) { - assert.expectWarning(function() { + return run(() => { + return store.findRecord('person', 1).then(person => { + assert.expectWarning(() => { get(person, 'hobby'); }, /You provided an embedded option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin/); - })); + }); }); }); -test("DS.belongsTo should be async by default", function(assert) { - var Tag = DS.Model.extend({ +test('DS.belongsTo should be async by default', function(assert) { + const Tag = DS.Model.extend({ name: DS.attr('string'), people: DS.hasMany('person', { async: false }) }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tag: DS.belongsTo('tag') }); - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; - + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; - run(function() { - var person = store.createRecord('person'); + run(() => { + let person = store.createRecord('person'); assert.ok(person.get('tag') instanceof DS.PromiseObject, 'tag should be an async relationship'); }); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 57bf2f9dabb..aecadcc1a17 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -6,31 +6,29 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var get = Ember.get; -var run = Ember.run; -var env; +const { get, run } = Ember; +let env; -module("unit/model/relationships - DS.hasMany", { +module('unit/model/relationships - DS.hasMany', { beforeEach() { env = setupStore(); } }); -test("hasMany handles pre-loaded relationships", function(assert) { - let done = assert.async(); +test('hasMany handles pre-loaded relationships', function(assert) { assert.expect(13); - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); - var Pet = DS.Model.extend({ + const Pet = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tags: DS.hasMany('tag', { async: false }), pets: DS.hasMany('pet', { async: false }) @@ -42,16 +40,16 @@ test("hasMany handles pre-loaded relationships", function(assert) { env.adapter.findRecord = function(store, type, id, snapshot) { if (type === Tag && id === '12') { - return Ember.RSVP.resolve({ id: 12, name: "oohlala" }); + return { id: 12, name: 'oohlala' }; } else { - assert.ok(false, "findRecord() should not be called with these values"); + assert.ok(false, 'findRecord() should not be called with these values'); } }; env.adapter.shouldBackgroundReloadRecord = () => false; - var store = env.store; + let { store } = env; - run(function() { + run(() => { store.push({ data: [{ type: 'tag', @@ -113,15 +111,15 @@ test("hasMany handles pre-loaded relationships", function(assert) { }); }); - run(function() { - store.findRecord('person', 1).then(function(person) { - assert.equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); + return run(() => { + return store.findRecord('person', 1).then(person => { + assert.equal(get(person, 'name'), 'Tom Dale', 'precond - retrieves person record from store'); - var tags = get(person, 'tags'); - assert.equal(get(tags, 'length'), 1, "the list of tags should have the correct length"); - assert.equal(get(tags.objectAt(0), 'name'), "friendly", "the first tag should be a Tag"); + let tags = get(person, 'tags'); + assert.equal(get(tags, 'length'), 1, 'the list of tags should have the correct length'); + assert.equal(get(tags.objectAt(0), 'name'), 'friendly', 'the first tag should be a Tag'); - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -141,13 +139,13 @@ test("hasMany handles pre-loaded relationships", function(assert) { }); }); - assert.equal(tags, get(person, 'tags'), "a relationship returns the same object every time"); - assert.equal(get(get(person, 'tags'), 'length'), 2, "the length is updated after new data is loaded"); + assert.equal(tags, get(person, 'tags'), 'a relationship returns the same object every time'); + assert.equal(get(get(person, 'tags'), 'length'), 2, 'the length is updated after new data is loaded'); - assert.strictEqual(get(person, 'tags').objectAt(0), get(person, 'tags').objectAt(0), "the returned object is always the same"); - assert.asyncEqual(get(person, 'tags').objectAt(0), store.findRecord('tag', 5), "relationship objects are the same as objects retrieved directly"); + assert.strictEqual(get(person, 'tags').objectAt(0), get(person, 'tags').objectAt(0), 'the returned object is always the same'); + assert.equal(get(person, 'tags').objectAt(0), store.peekRecord('tag', 5), 'relationship objects are the same as objects retrieved directly'); - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -160,10 +158,10 @@ test("hasMany handles pre-loaded relationships", function(assert) { }); return store.findRecord('person', 3); - }).then(function(kselden) { - assert.equal(get(get(kselden, 'tags'), 'length'), 0, "a relationship that has not been supplied returns an empty array"); + }).then(kselden => { + assert.equal(get(get(kselden, 'tags'), 'length'), 0, 'a relationship that has not been supplied returns an empty array'); - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -182,14 +180,14 @@ test("hasMany handles pre-loaded relationships", function(assert) { }); }); return store.findRecord('person', 4); - }).then(function(cyvid) { - assert.equal(get(cyvid, 'name'), "Cyvid Hamluck", "precond - retrieves person record from store"); + }).then(cyvid => { + assert.equal(get(cyvid, 'name'), 'Cyvid Hamluck', 'precond - retrieves person record from store'); - var pets = get(cyvid, 'pets'); - assert.equal(get(pets, 'length'), 1, "the list of pets should have the correct length"); - assert.equal(get(pets.objectAt(0), 'name'), "fluffy", "the first pet should be correct"); + let pets = get(cyvid, 'pets'); + assert.equal(get(pets, 'length'), 1, 'the list of pets should have the correct length'); + assert.equal(get(pets.objectAt(0), 'name'), 'fluffy', 'the first pet should be correct'); - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -209,27 +207,26 @@ test("hasMany handles pre-loaded relationships", function(assert) { }); }); - assert.equal(pets, get(cyvid, 'pets'), "a relationship returns the same object every time"); - assert.equal(get(get(cyvid, 'pets'), 'length'), 2, "the length is updated after new data is loaded"); - done(); + assert.equal(pets, get(cyvid, 'pets'), 'a relationship returns the same object every time'); + assert.equal(get(get(cyvid, 'pets'), 'length'), 2, 'the length is updated after new data is loaded'); }); }); }); -test("hasMany lazily loads async relationships", function(assert) { +test('hasMany lazily loads async relationships', function(assert) { assert.expect(5); - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); - var Pet = DS.Model.extend({ + const Pet = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tags: DS.hasMany('tag', { async: true }), pets: DS.hasMany('pet', { async: false }) @@ -241,16 +238,16 @@ test("hasMany lazily loads async relationships", function(assert) { env.adapter.findRecord = function(store, type, id, snapshot) { if (type === Tag && id === '12') { - return Ember.RSVP.resolve({ id: 12, name: "oohlala" }); + return { id: 12, name: 'oohlala' }; } else { - assert.ok(false, "findRecord() should not be called with these values"); + assert.ok(false, 'findRecord() should not be called with these values'); } }; env.adapter.shouldBackgroundReloadRecord = () => false; - var store = env.store; + let { store } = env; - run(function() { + run(() => { store.push({ data: [{ type: 'tag', @@ -312,120 +309,114 @@ test("hasMany lazily loads async relationships", function(assert) { }); }); - var wycats; - - run(function() { + return run(() =>{ + let wycats; store.findRecord('person', 2).then(function(person) { wycats = person; - assert.equal(get(wycats, 'name'), "Yehuda Katz", "precond - retrieves person record from store"); + assert.equal(get(wycats, 'name'), 'Yehuda Katz', 'precond - retrieves person record from store'); return Ember.RSVP.hash({ - wycats: wycats, + wycats, tags: wycats.get('tags') }); - }).then(function(records) { - assert.equal(get(records.tags, 'length'), 1, "the list of tags should have the correct length"); - assert.equal(get(records.tags.objectAt(0), 'name'), "oohlala", "the first tag should be a Tag"); + }).then(records => { + assert.equal(get(records.tags, 'length'), 1, 'the list of tags should have the correct length'); + assert.equal(get(records.tags.objectAt(0), 'name'), 'oohlala', 'the first tag should be a Tag'); - assert.strictEqual(records.tags.objectAt(0), records.tags.objectAt(0), "the returned object is always the same"); - assert.asyncEqual(records.tags.objectAt(0), store.findRecord('tag', 12), "relationship objects are the same as objects retrieved directly"); + assert.strictEqual(records.tags.objectAt(0), records.tags.objectAt(0), 'the returned object is always the same'); + assert.equal(records.tags.objectAt(0), store.peekRecord('tag', 12), 'relationship objects are the same as objects retrieved directly'); return get(wycats, 'tags'); - }).then(function(tags) { - var newTag; - run(function() { - newTag = store.createRecord('tag'); - tags.pushObject(newTag); - }); + }).then(tags => { + let newTag = store.createRecord('tag'); + tags.pushObject(newTag); }); }); }); -test("should be able to retrieve the type for a hasMany relationship without specifying a type from its metadata", function(assert) { - var Tag = DS.Model.extend({}); +test('should be able to retrieve the type for a hasMany relationship without specifying a type from its metadata', function(assert) { + const Tag = DS.Model.extend({}); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ tags: DS.hasMany('tag', { async: false }) }); - var env = setupStore({ + let env = setupStore({ tag: Tag, person: Person }); - assert.equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, "returns the relationship type"); + assert.equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, 'returns the relationship type'); }); -test("should be able to retrieve the type for a hasMany relationship specified using a string from its metadata", function(assert) { - var Tag = DS.Model.extend({}); +test('should be able to retrieve the type for a hasMany relationship specified using a string from its metadata', function(assert) { + const Tag = DS.Model.extend({}); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ tags: DS.hasMany('tag', { async: false }) }); - var env = setupStore({ + let env = setupStore({ tag: Tag, person: Person }); - assert.equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, "returns the relationship type"); + assert.equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, 'returns the relationship type'); }); -test("should be able to retrieve the type for a belongsTo relationship without specifying a type from its metadata", function(assert) { - var Tag = DS.Model.extend({}); +test('should be able to retrieve the type for a belongsTo relationship without specifying a type from its metadata', function(assert) { + const Tag = DS.Model.extend({}); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ tag: DS.belongsTo('tag', { async: false }) }); - var env = setupStore({ + let env = setupStore({ tag: Tag, person: Person }); - assert.equal(env.store.modelFor('person').typeForRelationship('tag', env.store), Tag, "returns the relationship type"); + assert.equal(env.store.modelFor('person').typeForRelationship('tag', env.store), Tag, 'returns the relationship type'); }); -test("should be able to retrieve the type for a belongsTo relationship specified using a string from its metadata", function(assert) { - var Tag = DS.Model.extend({ +test('should be able to retrieve the type for a belongsTo relationship specified using a string from its metadata', function(assert) { + const Tag = DS.Model.extend({ name: DS.attr('string') }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ tags: DS.belongsTo('tag', { async: false }) }); - var env = setupStore({ + let env = setupStore({ tag: Tag, person: Person }); - assert.equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, "returns the relationship type"); + assert.equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, 'returns the relationship type'); }); -test("relationships work when declared with a string path", function(assert) { +test('relationships work when declared with a string path', function(assert) { assert.expect(2); - window.App = {}; - - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tags: DS.hasMany('tag', { async: false }) }); - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string') }); - var env = setupStore({ + let env = setupStore({ person: Person, tag: Tag }); env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { env.store.push({ data: [{ type: 'tag', @@ -463,82 +454,83 @@ test("relationships work when declared with a string path", function(assert) { }); }); - run(function() { - env.store.findRecord('person', 1).then(function(person) { - assert.equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - assert.equal(get(person, 'tags.length'), 2, "the list of tags should have the correct length"); + return run(() => { + return env.store.findRecord('person', 1).then(person => { + assert.equal(get(person, 'name'), 'Tom Dale', 'precond - retrieves person record from store'); + assert.equal(get(person, 'tags.length'), 2, 'the list of tags should have the correct length'); }); }); }); -test("hasMany relationships work when the data hash has not been loaded", function(assert) { +test('hasMany relationships work when the data hash has not been loaded', function(assert) { assert.expect(8); - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tags: DS.hasMany('tag', { async: true }) }); - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; env.adapter.coalesceFindRequests = true; env.adapter.findMany = function(store, type, ids, snapshots) { - assert.equal(type, Tag, "type should be Tag"); - assert.deepEqual(ids, ['5', '2'], "ids should be 5 and 2"); + assert.equal(type, Tag, 'type should be Tag'); + assert.deepEqual(ids, ['5', '2'], 'ids should be 5 and 2'); - return Ember.RSVP.resolve([{ id: 5, name: "friendly" }, { id: 2, name: "smarmy" }]); + return [ + { id: 5, name: 'friendly' }, + { id: 2, name: 'smarmy' } + ]; }; env.adapter.findRecord = function(store, type, id, snapshot) { - assert.equal(type, Person, "type should be Person"); - assert.equal(id, 1, "id should be 1"); + assert.equal(type, Person, 'type should be Person'); + assert.equal(id, 1, 'id should be 1'); - return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", tags: [5, 2] }); + return { id: 1, name: 'Tom Dale', tags: [5, 2] }; }; - run(function() { - store.findRecord('person', 1).then(function(person) { - assert.equal(get(person, 'name'), "Tom Dale", "The person is now populated"); + return run(() => { + return store.findRecord('person', 1).then(person => { + assert.equal(get(person, 'name'), 'Tom Dale', 'The person is now populated'); - return run(function() { - return person.get('tags'); - }); - }).then(function(tags) { - assert.equal(get(tags, 'length'), 2, "the tags object still exists"); - assert.equal(get(tags.objectAt(0), 'name'), "friendly", "Tom Dale is now friendly"); - assert.equal(get(tags.objectAt(0), 'isLoaded'), true, "Tom Dale is now loaded"); + return run(() => person.get('tags')); + }).then(tags => { + assert.equal(get(tags, 'length'), 2, 'the tags object still exists'); + assert.equal(get(tags.objectAt(0), 'name'), 'friendly', 'Tom Dale is now friendly'); + assert.equal(get(tags.objectAt(0), 'isLoaded'), true, 'Tom Dale is now loaded'); }); }); }); -test("it is possible to add a new item to a relationship", function(assert) { +test('it is possible to add a new item to a relationship', function(assert) { assert.expect(2); - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string'), people: DS.belongsTo('person', { async: false }) }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tags: DS.hasMany('tag', { async: false }) }); - var env = setupStore({ + let env = setupStore({ tag: Tag, person: Person }); env.adapter.shouldBackgroundReloadRecord = () => false; - var store = env.store; + let { store } = env; - run(function() { + run(() => { store.push({ data: [{ type: 'person', @@ -563,37 +555,37 @@ test("it is possible to add a new item to a relationship", function(assert) { }); }); - run(function() { - store.findRecord('person', 1).then(function(person) { - var tag = get(person, 'tags').objectAt(0); + return run(() => { + return store.findRecord('person', 1).then(person =>{ + let tag = get(person, 'tags').objectAt(0); - assert.equal(get(tag, 'name'), "ember", "precond - relationships work"); + assert.equal(get(tag, 'name'), 'ember', 'precond - relationships work'); - tag = store.createRecord('tag', { name: "js" }); + tag = store.createRecord('tag', { name: 'js' }); get(person, 'tags').pushObject(tag); - assert.equal(get(person, 'tags').objectAt(1), tag, "newly added relationship works"); + assert.equal(get(person, 'tags').objectAt(1), tag, 'newly added relationship works'); }); }); }); -test("possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)", function(assert) { +test('possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)', function(assert) { assert.expect(2); - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tags: DS.hasMany('tag', { async: false }) }); - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; - run(function() { + run(() => { store.push({ data: [{ type: 'person', @@ -637,9 +629,9 @@ test("possible to replace items in a relationship using setObjects w/ Ember Enum }); }); - var tom, sylvain; + let tom, sylvain; - run(function() { + run(() => { tom = store.peekRecord('person', '1'); sylvain = store.peekRecord('person', '2'); // Test that since sylvain.get('tags') instanceof DS.ManyArray, @@ -651,24 +643,25 @@ test("possible to replace items in a relationship using setObjects w/ Ember Enum assert.equal(tom.get('tags.firstObject'), store.peekRecord('tag', 2)); }); -test("it is possible to remove an item from a relationship", function(assert) { +test('it is possible to remove an item from a relationship', function(assert) { assert.expect(2); - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tags: DS.hasMany('tag', { async: false }) }); - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: [{ type: 'person', @@ -693,37 +686,35 @@ test("it is possible to remove an item from a relationship", function(assert) { }); }); - run(function() { - store.findRecord('person', 1).then(assert.wait(function(person) { - var tag = get(person, 'tags').objectAt(0); + return run(() => { + return store.findRecord('person', 1).then(person => { + let tag = get(person, 'tags').objectAt(0); - assert.equal(get(tag, 'name'), "ember", "precond - relationships work"); + assert.equal(get(tag, 'name'), 'ember', 'precond - relationships work'); - run(function() { - get(person, 'tags').removeObject(tag); - }); + run(() => get(person, 'tags').removeObject(tag)); - assert.equal(get(person, 'tags.length'), 0, "object is removed from the relationship"); - })); + assert.equal(get(person, 'tags.length'), 0, 'object is removed from the relationship'); + }); }); }); -test("it is possible to add an item to a relationship, remove it, then add it again", function(assert) { - var Tag = DS.Model.extend({ +test('it is possible to add an item to a relationship, remove it, then add it again', function(assert) { + const Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tags: DS.hasMany('tag', { async: false }) }); - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; - var person, tag1, tag2, tag3, tags; + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + let person, tag1, tag2, tag3, tags; - run(function() { + run(() => { person = store.createRecord('person'); tag1 = store.createRecord('tag'); tag2 = store.createRecord('tag'); @@ -737,41 +728,40 @@ test("it is possible to add an item to a relationship, remove it, then add it ag assert.equal(tags.objectAt(0), tag1); assert.equal(tags.objectAt(1), tag3); - assert.equal(get(person, 'tags.length'), 2, "object is removed from the relationship"); + assert.equal(get(person, 'tags.length'), 2, 'object is removed from the relationship'); - run(function() { + run(() => { tags.insertAt(0, tag2); }); - assert.equal(get(person, 'tags.length'), 3, "object is added back to the relationship"); + assert.equal(get(person, 'tags.length'), 3, 'object is added back to the relationship'); assert.equal(tags.objectAt(0), tag2); assert.equal(tags.objectAt(1), tag1); assert.equal(tags.objectAt(2), tag3); }); test("DS.hasMany is async by default", function(assert) { - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string'), people: DS.hasMany('person') }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tag: DS.belongsTo('tag', { async: false }) }); - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; + let { store } = setupStore({ tag: Tag, person: Person }); - run(function() { - var tag = store.createRecord('tag'); + run(() => { + let tag = store.createRecord('tag'); assert.ok(tag.get('people') instanceof DS.PromiseArray, 'people should be an async relationship'); }); }); -test("DS.ManyArray is lazy", function(assert) { +test('DS.ManyArray is lazy', function(assert) { let peopleDidChange = 0; - let Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string'), people: DS.hasMany('person'), peopleDidChange: Ember.observer('people', function() { @@ -779,22 +769,23 @@ test("DS.ManyArray is lazy", function(assert) { }) }); - let Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tag: DS.belongsTo('tag', { async: false }) }); let env = setupStore({ tag: Tag, person: Person }); - let tag = run(function() { - return env.store.createRecord('tag'); - }); + let tag = run(() => env.store.createRecord('tag')); let hasManyRelationship = tag.hasMany('people').hasManyRelationship; + assert.ok(!hasManyRelationship._manyArray); - run(function() { + + run(() => { assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (before access)'); tag.get('people'); assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (sync after access)'); }); + assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (after access, but after the current run loop)'); assert.ok(hasManyRelationship._manyArray instanceof DS.ManyArray); @@ -807,34 +798,34 @@ test("DS.ManyArray is lazy", function(assert) { }); }); -testInDebug("throws assertion if of not set with an array", function(assert) { - var Person = DS.Model.extend(); - var Tag = DS.Model.extend({ +testInDebug('throws assertion if of not set with an array', function(assert) { + const Person = DS.Model.extend(); + const Tag = DS.Model.extend({ people: DS.hasMany('person') }); - var env = setupStore({ tag: Tag, person: Person }); - var tag, person; + let { store }= setupStore({ tag: Tag, person: Person }); + let tag, person; - run(function() { - tag = env.store.createRecord('tag'); - person = env.store.createRecord('person'); + run(() => { + tag = store.createRecord('tag'); + person = store.createRecord('person'); }); - run(function() { - assert.expectAssertion(function() { + run(() => { + assert.expectAssertion(() => { tag.set('people', person); }, /You must pass an array of records to set a hasMany relationship/); }); }); -testInDebug("checks if passed array only contains instances of DS.Model", function(assert) { - var Person = DS.Model.extend(); - var Tag = DS.Model.extend({ +testInDebug('checks if passed array only contains instances of DS.Model', function(assert) { + const Person = DS.Model.extend(); + const Tag = DS.Model.extend({ people: DS.hasMany('person') }); - var env = setupStore({ tag: Tag, person: Person }); + let env = setupStore({ tag: Tag, person: Person }); env.adapter.findRecord = function() { return { @@ -843,15 +834,15 @@ testInDebug("checks if passed array only contains instances of DS.Model", functi }; }; - var tag, person; + let tag, person; - run(function() { + run(() => { tag = env.store.createRecord('tag'); person = env.store.findRecord('person', 1); }); - run(function() { - assert.expectAssertion(function() { + run(() => { + assert.expectAssertion(() => { tag.set('people', [person]); }, /All elements of a hasMany relationship must be instances of DS.Model/); }); diff --git a/tests/unit/model/relationships/record-array-test.js b/tests/unit/model/relationships/record-array-test.js index dfb7291f05e..dafc81f7271 100644 --- a/tests/unit/model/relationships/record-array-test.js +++ b/tests/unit/model/relationships/record-array-test.js @@ -5,13 +5,11 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var get = Ember.get; -var set = Ember.set; -var run = Ember.run; +const { get, set, run } = Ember; -module("unit/model/relationships - RecordArray"); +module('unit/model/relationships - RecordArray'); -test("updating the content of a RecordArray updates its content", function(assert) { +test('updating the content of a RecordArray updates its content', function(assert) { let Tag = DS.Model.extend({ name: DS.attr('string') }); @@ -21,7 +19,7 @@ test("updating the content of a RecordArray updates its content", function(asser let tags; let internalModels; - run(function() { + run(() => { internalModels = store._push({ data: [{ type: 'tag', @@ -51,53 +49,51 @@ test("updating the content of a RecordArray updates its content", function(asser }); let tag = tags.objectAt(0); - assert.equal(get(tag, 'name'), "friendly", "precond - we're working with the right tags"); + assert.equal(get(tag, 'name'), 'friendly', `precond - we're working with the right tags`); - run(function() { - set(tags, 'content', Ember.A(internalModels.slice(1, 3))); - }); + run(() => set(tags, 'content', Ember.A(internalModels.slice(1, 3)))); tag = tags.objectAt(0); - assert.equal(get(tag, 'name'), "smarmy", "the lookup was updated"); + assert.equal(get(tag, 'name'), 'smarmy', 'the lookup was updated'); }); -test("can create child record from a hasMany relationship", function(assert) { +test('can create child record from a hasMany relationship', function(assert) { assert.expect(3); - var Tag = DS.Model.extend({ + const Tag = DS.Model.extend({ name: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string'), tags: DS.hasMany('tag', { async: false }) }); - var env = setupStore({ tag: Tag, person: Person }); - var store = env.store; + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: { type: 'person', id: '1', attributes: { - name: "Tom Dale" + name: 'Tom Dale' } } }); }); - run(function() { - store.findRecord('person', 1).then(assert.wait(function(person) { - person.get("tags").createRecord({ name: "cool" }); + return run(() => { + return store.findRecord('person', 1).then(person => { + person.get('tags').createRecord({ name: 'cool' }); - assert.equal(get(person, 'name'), "Tom Dale", "precond - retrieves person record from store"); - assert.equal(get(person, 'tags.length'), 1, "tag is added to the parent record"); - assert.equal(get(person, 'tags').objectAt(0).get("name"), "cool", "tag values are passed along"); - })); + assert.equal(get(person, 'name'), 'Tom Dale', 'precond - retrieves person record from store'); + assert.equal(get(person, 'tags.length'), 1, 'tag is added to the parent record'); + assert.equal(get(person, 'tags').objectAt(0).get('name'), 'cool', 'tag values are passed along'); + }); }); }); - diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index 178e4499607..5313a48ad7a 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -6,10 +6,10 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; import isEnabled from 'ember-data/-private/features'; -var env, store, Person, Dog; -var run = Ember.run; +let env, store, Person; +const { run } = Ember; -module("unit/model/rollbackAttributes - model.rollbackAttributes()", { +module('unit/model/rollbackAttributes - model.rollbackAttributes()', { beforeEach() { Person = DS.Model.extend({ firstName: DS.attr(), @@ -22,9 +22,8 @@ module("unit/model/rollbackAttributes - model.rollbackAttributes()", { } }); -test("changes to attributes can be rolled back", function(assert) { - var person; - run(function() { +test('changes to attributes can be rolled back', function(assert) { + let person = run(() => { store.push({ data: { type: 'person', @@ -37,54 +36,49 @@ test("changes to attributes can be rolled back", function(assert) { }); person = store.peekRecord('person', 1); person.set('firstName', "Thomas"); + return person; }); assert.equal(person.get('firstName'), "Thomas"); - run(function() { - person.rollbackAttributes(); - }); + run(() => person.rollbackAttributes()); assert.equal(person.get('firstName'), "Tom"); assert.equal(person.get('hasDirtyAttributes'), false); }); -test("changes to unassigned attributes can be rolled back", function(assert) { - var person; - run(function() { +test('changes to unassigned attributes can be rolled back', function(assert) { + let person = run(() => { store.push({ data: { type: 'person', id: '1', attributes: { - lastName: "Dale" + lastName: 'Dale' } } }); person = store.peekRecord('person', 1); person.set('firstName', "Thomas"); + + return person; }); assert.equal(person.get('firstName'), "Thomas"); - run(function() { - person.rollbackAttributes(); - }); + run(() => person.rollbackAttributes()); assert.equal(person.get('firstName'), undefined); assert.equal(person.get('hasDirtyAttributes'), false); }); -test("changes to attributes made after a record is in-flight only rolls back the local changes", function(assert) { +test('changes to attributes made after a record is in-flight only rolls back the local changes', function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { // Make sure the save is async - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.run.later(null, resolve, 15); - }); + return new Ember.RSVP.Promise(resolve => Ember.run.later(null, resolve, 15)); }; - var person; - run(function() { + let person = run(() => { store.push({ data: { type: 'person', @@ -95,12 +89,15 @@ test("changes to attributes made after a record is in-flight only rolls back the } } }); - person = store.peekRecord('person', 1); + + let person = store.peekRecord('person', 1); person.set('firstName', "Thomas"); + + return person; }); - Ember.run(function() { - var saving = person.save(); + return run(() => { + let saving = person.save(); assert.equal(person.get('firstName'), "Thomas"); @@ -114,9 +111,9 @@ test("changes to attributes made after a record is in-flight only rolls back the assert.equal(person.get('lastName'), "Dale"); assert.equal(person.get('isSaving'), true); - saving.then(assert.wait(function() { - assert.equal(person.get('hasDirtyAttributes'), false, "The person is now clean"); - })); + return saving.then(() => { + assert.equal(person.get('hasDirtyAttributes'), false, 'The person is now clean'); + }); }); }); @@ -124,9 +121,8 @@ test("a record's changes can be made if it fails to save", function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { return Ember.RSVP.reject(); }; - var person; - run(function() { + let person = run(() => { store.push({ data: { type: 'person', @@ -137,8 +133,11 @@ test("a record's changes can be made if it fails to save", function(assert) { } } }); - person = store.peekRecord('person', 1); + + let person = store.peekRecord('person', 1); person.set('firstName', "Thomas"); + + return person; }); assert.deepEqual(person.changedAttributes().firstName, ["Tom", "Thomas"]); @@ -157,14 +156,15 @@ test("a record's changes can be made if it fails to save", function(assert) { }); }); -test("a deleted record's attributes can be rollbacked if it fails to save, record arrays are updated accordingly", function(assert) { +test(`a deleted record's attributes can be rollbacked if it fails to save, record arrays are updated accordingly`, function(assert) { assert.expect(8); env.adapter.deleteRecord = function(store, type, snapshot) { return Ember.RSVP.reject(); }; - var person, people; - run(function() { + let person, people; + + run(() => { store.push({ data: { type: 'person', @@ -179,55 +179,47 @@ test("a deleted record's attributes can be rollbacked if it fails to save, recor people = store.peekAll('person'); }); - run(function() { - person.deleteRecord(); - }); - assert.equal(people.get('length'), 1, "a deleted record appears in record array until it is saved"); - assert.equal(people.objectAt(0), person, "a deleted record appears in record array until it is saved"); + run(() => person.deleteRecord()); - run(function() { - person.save().then(null, function() { + assert.equal(people.get('length'), 1, 'a deleted record appears in record array until it is saved'); + assert.equal(people.objectAt(0), person, 'a deleted record appears in record array until it is saved'); + + return run(() => { + return person.save().catch(() => { assert.equal(person.get('isError'), true); assert.equal(person.get('isDeleted'), true); - run(function() { - person.rollbackAttributes(); - }); + run(() => person.rollbackAttributes()); assert.equal(person.get('isDeleted'), false); assert.equal(person.get('isError'), false); - assert.equal(person.get('hasDirtyAttributes'), false, "must be not dirty"); - }).then(function() { - assert.equal(people.get('length'), 1, "the underlying record array is updated accordingly in an asynchronous way"); + assert.equal(person.get('hasDirtyAttributes'), false, 'must be not dirty'); + }).then(() => { + assert.equal(people.get('length'), 1, 'the underlying record array is updated accordingly in an asynchronous way'); }); }); }); -test("new record's attributes can be rollbacked", function(assert) { - var person; - - run(function() { - person = store.createRecord('person', { id: 1 }); - }); +test(`new record's attributes can be rollbacked`, function(assert) { + let person = run(() => store.createRecord('person', { id: 1 })); - assert.equal(person.get('isNew'), true, "must be new"); - assert.equal(person.get('hasDirtyAttributes'), true, "must be dirty"); + assert.equal(person.get('isNew'), true, 'must be new'); + assert.equal(person.get('hasDirtyAttributes'), true, 'must be dirty'); Ember.run(person, 'rollbackAttributes'); - assert.equal(person.get('isNew'), false, "must not be new"); - assert.equal(person.get('hasDirtyAttributes'), false, "must not be dirty"); - assert.equal(person.get('isDeleted'), true, "must be deleted"); + assert.equal(person.get('isNew'), false, 'must not be new'); + assert.equal(person.get('hasDirtyAttributes'), false, 'must not be dirty'); + assert.equal(person.get('isDeleted'), true, 'must be deleted'); }); -test("invalid new record's attributes can be rollbacked", function(assert) { - var person; - var error = new DS.InvalidError([ +test(`invalid new record's attributes can be rollbacked`, function(assert) { + let error = new DS.InvalidError([ { detail: 'is invalid', source: { pointer: 'data/attributes/name' } } ]); - var adapter; + let adapter; if (isEnabled('ds-improved-ajax')) { adapter = DS.RESTAdapter.extend({ _makeRequest() { @@ -244,40 +236,38 @@ test("invalid new record's attributes can be rollbacked", function(assert) { env = setupStore({ person: Person, adapter: adapter }); - run(function() { - person = env.store.createRecord('person', { id: 1 }); - }); + let person = run(() => env.store.createRecord('person', { id: 1 })); - assert.equal(person.get('isNew'), true, "must be new"); - assert.equal(person.get('hasDirtyAttributes'), true, "must be dirty"); + assert.equal(person.get('isNew'), true, 'must be new'); + assert.equal(person.get('hasDirtyAttributes'), true, 'must be dirty'); - run(function() { - person.save().then(null, assert.wait(function() { + return run(() => { + return person.save().catch(reason => { + assert.equal(error, reason); assert.equal(person.get('isValid'), false); person.rollbackAttributes(); - assert.equal(person.get('isNew'), false, "must not be new"); - assert.equal(person.get('hasDirtyAttributes'), false, "must not be dirty"); - assert.equal(person.get('isDeleted'), true, "must be deleted"); - })); + assert.equal(person.get('isNew'), false, 'must not be new'); + assert.equal(person.get('hasDirtyAttributes'), false, 'must not be dirty'); + assert.equal(person.get('isDeleted'), true, 'must be deleted'); + }); }); }); -test("invalid record's attributes can be rollbacked after multiple failed calls - #3677", function(assert) { - var person; +test(`invalid record's attributes can be rollbacked after multiple failed calls - #3677`, function(assert) { - var adapter; + let adapter; if (isEnabled('ds-improved-ajax')) { adapter = DS.RESTAdapter.extend({ _makeRequest() { - var error = new DS.InvalidError(); + let error = new DS.InvalidError(); return Ember.RSVP.reject(error); } }); } else { adapter = DS.RESTAdapter.extend({ ajax(url, type, hash) { - var error = new DS.InvalidError(); + let error = new DS.InvalidError(); return Ember.RSVP.reject(error); } }); @@ -285,7 +275,8 @@ test("invalid record's attributes can be rollbacked after multiple failed calls env = setupStore({ person: Person, adapter: adapter }); - run(function() { + let person; + run(() => { person = env.store.push({ data: { type: 'person', @@ -299,27 +290,27 @@ test("invalid record's attributes can be rollbacked after multiple failed calls person.set('firstName', 'updated name'); }); - run(function() { - assert.equal(person.get('firstName'), 'updated name', "precondition: firstName is changed"); + return run(() => { + assert.equal(person.get('firstName'), 'updated name', 'precondition: firstName is changed'); - person.save().then(null, assert.wait(function() { - assert.equal(person.get('hasDirtyAttributes'), true, "has dirty attributes"); - assert.equal(person.get('firstName'), 'updated name', "firstName is still changed"); + return person.save().catch(() => { + assert.equal(person.get('hasDirtyAttributes'), true, 'has dirty attributes'); + assert.equal(person.get('firstName'), 'updated name', 'firstName is still changed'); return person.save(); - })).then(null, assert.wait(function() { + }).catch(() => { person.rollbackAttributes(); - assert.equal(person.get('hasDirtyAttributes'), false, "has no dirty attributes"); - assert.equal(person.get('firstName'), 'original name', "after rollbackAttributes() firstName has the original value"); - })); + assert.equal(person.get('hasDirtyAttributes'), false, 'has no dirty attributes'); + assert.equal(person.get('firstName'), 'original name', 'after rollbackAttributes() firstName has the original value'); + }); }); }); -test("deleted record's attributes can be rollbacked", function(assert) { - var person, people; +test(`deleted record's attributes can be rollbacked`, function(assert) { + let person, people; - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -331,33 +322,32 @@ test("deleted record's attributes can be rollbacked", function(assert) { person.deleteRecord(); }); - assert.equal(people.get('length'), 1, "a deleted record appears in the record array until it is saved"); - assert.equal(people.objectAt(0), person, "a deleted record appears in the record array until it is saved"); + assert.equal(people.get('length'), 1, 'a deleted record appears in the record array until it is saved'); + assert.equal(people.objectAt(0), person, 'a deleted record appears in the record array until it is saved'); - assert.equal(person.get('isDeleted'), true, "must be deleted"); + assert.equal(person.get('isDeleted'), true, 'must be deleted'); - run(function() { - person.rollbackAttributes(); - }); - assert.equal(people.get('length'), 1, "the rollbacked record should appear again in the record array"); - assert.equal(person.get('isDeleted'), false, "must not be deleted"); - assert.equal(person.get('hasDirtyAttributes'), false, "must not be dirty"); + run(() => person.rollbackAttributes()); + + assert.equal(people.get('length'), 1, 'the rollbacked record should appear again in the record array'); + assert.equal(person.get('isDeleted'), false, 'must not be deleted'); + assert.equal(person.get('hasDirtyAttributes'), false, 'must not be dirty'); }); test("invalid record's attributes can be rollbacked", function(assert) { - assert.expect(10); - Dog = DS.Model.extend({ + assert.expect(11); + const Dog = DS.Model.extend({ name: DS.attr() }); - var error = new DS.InvalidError([ + let error = new DS.InvalidError([ { detail: 'is invalid', source: { pointer: 'data/attributes/name' } } ]); - var adapter; + let adapter; if (isEnabled('ds-improved-ajax')) { adapter = DS.RESTAdapter.extend({ _makeRequest() { @@ -374,8 +364,8 @@ test("invalid record's attributes can be rollbacked", function(assert) { env = setupStore({ dog: Dog, adapter: adapter }); - var dog; - run(function() { + let dog; + run(() => { env.store.push({ data: { type: 'dog', @@ -389,7 +379,7 @@ test("invalid record's attributes can be rollbacked", function(assert) { dog.set('name', "is a dwarf planet"); }); - run(function() { + return run(() => { Ember.addObserver(dog, 'errors.name', function() { assert.ok(true, 'errors.name did change'); }); @@ -403,32 +393,34 @@ test("invalid record's attributes can be rollbacked", function(assert) { } }); - dog.save().then(null, assert.wait(function() { + return dog.save().catch(reason => { + assert.equal(reason, error); + dog.rollbackAttributes(); - assert.equal(dog.get('hasDirtyAttributes'), false, "must not be dirty"); - assert.equal(dog.get('name'), "Pluto"); + assert.equal(dog.get('hasDirtyAttributes'), false, 'must not be dirty'); + assert.equal(dog.get('name'), 'Pluto'); assert.ok(Ember.isEmpty(dog.get('errors.name'))); assert.ok(dog.get('isValid')); - })); + }); }); }); -test("invalid record's attributes rolled back to correct state after set", function(assert) { - assert.expect(13); - Dog = DS.Model.extend({ +test(`invalid record's attributes rolled back to correct state after set`, function(assert) { + assert.expect(14); + const Dog = DS.Model.extend({ name: DS.attr(), breed: DS.attr() }); - var error = new DS.InvalidError([ + let error = new DS.InvalidError([ { detail: 'is invalid', source: { pointer: 'data/attributes/name' } } ]); - var adapter; + let adapter; if (isEnabled('ds-improved-ajax')) { adapter = DS.RESTAdapter.extend({ _makeRequest() { @@ -444,8 +436,8 @@ test("invalid record's attributes rolled back to correct state after set", funct } env = setupStore({ dog: Dog, adapter: adapter }); - var dog; - run(function() { + let dog; + run(() => { env.store.push({ data: { type: 'dog', @@ -461,50 +453,47 @@ test("invalid record's attributes rolled back to correct state after set", funct dog.set('breed', 'planet'); }); - run(function() { + return run(() => { Ember.addObserver(dog, 'errors.name', function() { assert.ok(true, 'errors.name did change'); }); - dog.save().then(null, assert.wait(function() { - assert.equal(dog.get('name'), "is a dwarf planet"); - assert.equal(dog.get('breed'), "planet"); + return dog.save().catch(reason => { + assert.equal(reason, error); + assert.equal(dog.get('name'), 'is a dwarf planet'); + assert.equal(dog.get('breed'), 'planet'); assert.ok(Ember.isPresent(dog.get('errors.name'))); assert.equal(dog.get('errors.name.length'), 1); - run(function() { - dog.set('name', 'Seymour Asses'); - }); + run(() => dog.set('name', 'Seymour Asses')); - assert.equal(dog.get('name'), "Seymour Asses"); - assert.equal(dog.get('breed'), "planet"); + assert.equal(dog.get('name'), 'Seymour Asses'); + assert.equal(dog.get('breed'), 'planet'); - run(function() { - dog.rollbackAttributes(); - }); + run(() => dog.rollbackAttributes()); - assert.equal(dog.get('name'), "Pluto"); - assert.equal(dog.get('breed'), "Disney"); - assert.equal(dog.get('hasDirtyAttributes'), false, "must not be dirty"); + assert.equal(dog.get('name'), 'Pluto'); + assert.equal(dog.get('breed'), 'Disney'); + assert.equal(dog.get('hasDirtyAttributes'), false, 'must not be dirty'); assert.ok(Ember.isEmpty(dog.get('errors.name'))); assert.ok(dog.get('isValid')); - })); + }); }); }); -test("when destroying a record setup the record state to invalid, the record's attributes can be rollbacked", function(assert) { - Dog = DS.Model.extend({ +test(`when destroying a record setup the record state to invalid, the record's attributes can be rollbacked`, function(assert) { + const Dog = DS.Model.extend({ name: DS.attr() }); - var error = new DS.InvalidError([ + let error = new DS.InvalidError([ { detail: 'is invalid', source: { pointer: 'data/attributes/name' } } ]); - var adapter; + let adapter; if (isEnabled('ds-improved-ajax')) { adapter = DS.RESTAdapter.extend({ _makeRequest() { @@ -520,8 +509,7 @@ test("when destroying a record setup the record state to invalid, the record's a } env = setupStore({ dog: Dog, adapter: adapter }); - var dog; - run(function() { + let dog = run(() => { env.store.push({ data: { type: 'dog', @@ -531,24 +519,24 @@ test("when destroying a record setup the record state to invalid, the record's a } } }); - dog = env.store.peekRecord('dog', 1); + return env.store.peekRecord('dog', 1); }); - run(function() { - dog.destroyRecord().then(null, assert.wait(function() { - + return run(() => { + return dog.destroyRecord().catch(reason => { + assert.equal(reason, error); - assert.equal(dog.get('isError'), false, "must not be error"); - assert.equal(dog.get('isDeleted'), true, "must be deleted"); - assert.equal(dog.get('isValid'), false, "must not be valid"); - assert.ok(dog.get('errors.length') > 0, "must have errors"); + assert.equal(dog.get('isError'), false, 'must not be error'); + assert.equal(dog.get('isDeleted'), true, 'must be deleted'); + assert.equal(dog.get('isValid'), false, 'must not be valid'); + assert.ok(dog.get('errors.length') > 0, 'must have errors'); dog.rollbackAttributes(); - assert.equal(dog.get('isError'), false, "must not be error after `rollbackAttributes`"); - assert.equal(dog.get('isDeleted'), false, "must not be deleted after `rollbackAttributes`"); - assert.equal(dog.get('isValid'), true, "must be valid after `rollbackAttributes`"); - assert.ok(dog.get('errors.length') === 0, "must not have errors"); - })); + assert.equal(dog.get('isError'), false, 'must not be error after `rollbackAttributes`'); + assert.equal(dog.get('isDeleted'), false, 'must not be deleted after `rollbackAttributes`'); + assert.equal(dog.get('isValid'), true, 'must be valid after `rollbackAttributes`'); + assert.ok(dog.get('errors.length') === 0, 'must not have errors'); + }) }); }); diff --git a/tests/unit/record-arrays/filtered-record-array-test.js b/tests/unit/record-arrays/filtered-record-array-test.js index 8914a617591..afa43b570f1 100644 --- a/tests/unit/record-arrays/filtered-record-array-test.js +++ b/tests/unit/record-arrays/filtered-record-array-test.js @@ -41,7 +41,7 @@ test('custom initial state', function(assert) { test('#replace() throws error', function(assert) { let recordArray = FilteredRecordArray.create({ modelName: 'recordType' }); - assert.throws(function() { + assert.throws(() => { recordArray.replace(); }, Error('The result of a client-side filter (on recordType) is immutable.'), 'throws error'); }); diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js index 5a36a4b5986..b11f0eb6487 100644 --- a/tests/unit/record-arrays/record-array-test.js +++ b/tests/unit/record-arrays/record-array-test.js @@ -37,7 +37,7 @@ test('custom initial state', function(assert) { test('#replace() throws error', function(assert) { let recordArray = RecordArray.create({ modelName: 'recordType' }); - assert.throws(function() { + assert.throws(() => { recordArray.replace(); }, Error('The result of a server query (for all recordType types) is immutable. To modify contents, use toArray()'), 'throws error'); }); @@ -61,7 +61,6 @@ test('#objectAtContent', function(assert) { assert.equal(recordArray.objectAtContent(3), undefined); }); - test('#update', function(assert) { let findAllCalled = 0; let deferred = RSVP.defer(); From 730b484eff9a2194809407dde8e96e41e2e1527a Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 3 Mar 2017 16:51:10 -0800 Subject: [PATCH 1826/2527] Stefs cleanup (and some test suite memory leak fixes) (#4838) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * cleanup tests/unit/model/lifecycle-callbacks * cleanup tests/unit/model/lifecycle-callbacks * Fix funky memory leak AssertionPrototype.prototype extensions in this file, where causing `let testStore` to be retained… * fix memory leak (in test) reopen introduced a mixin which was retained, and who’s new methods retained the current tests `env`. This more accurately patches the methods in-question. Future work should re-evaluate this test, and consider a simpler approach * Fix test leak: QUnit.assert.payloadError now is uninstalled. * prevent app from leaking across tests --- tests/integration/debug-adapter-test.js | 7 +- .../store/json-api-validation-test.js | 43 ++++--- tests/unit/many-array-test.js | 46 ++++--- tests/unit/model-test.js | 119 +++++++++--------- 4 files changed, 109 insertions(+), 106 deletions(-) diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index c7c4302bd6f..76730a7ae13 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -8,10 +8,12 @@ var App, store, debugAdapter; var get = Ember.get; var run = Ember.run; -module("DS.DebugAdapter", { +module('DS.DebugAdapter', { beforeEach() { Ember.run(function() { - App = Ember.Application.create(); + App = Ember.Application.extend({ + toString() { return 'debug-app'; } + }).create(); App.StoreService = DS.Store.extend({}); @@ -49,6 +51,7 @@ module("DS.DebugAdapter", { }, afterEach() { run(App, App.destroy); + App = store = null; } }); diff --git a/tests/integration/store/json-api-validation-test.js b/tests/integration/store/json-api-validation-test.js index 0f5d7638763..b4015274c5c 100644 --- a/tests/integration/store/json-api-validation-test.js +++ b/tests/integration/store/json-api-validation-test.js @@ -7,8 +7,30 @@ import DS from 'ember-data'; var Person, store, env; var run = Ember.run; +function payloadError(payload, expectedError) { + env.registry.register('serializer:person', DS.Serializer.extend({ + normalizeResponse(store, type, pld) { + return pld; + } + })); + env.registry.register('adapter:person', DS.Adapter.extend({ + findRecord() { + return Ember.RSVP.resolve(payload); + } + })); + this.throws(function () { + run(function() { + store.findRecord('person', 1); + }); + }, expectedError, `Payload ${JSON.stringify(payload)} should throw error ${expectedError}`); + env.registry.unregister('serializer:person'); + env.registry.unregister('adapter:person'); +} + module("integration/store/json-validation", { beforeEach() { + QUnit.assert.payloadError = payloadError; + Person = DS.Model.extend({ updatedAt: DS.attr('string'), name: DS.attr('string'), @@ -23,6 +45,7 @@ module("integration/store/json-validation", { }, afterEach() { + QUnit.assert.payloadError = null run(store, 'destroy'); } }); @@ -109,26 +132,6 @@ testInDebug("when normalizeResponse returns a document with both data and errors }, /cannot both be present/); }); -QUnit.assert.payloadError = function payloadError(payload, expectedError) { - env.registry.register('serializer:person', DS.Serializer.extend({ - normalizeResponse(store, type, pld) { - return pld; - } - })); - env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord() { - return Ember.RSVP.resolve(payload); - } - })); - this.throws(function () { - run(function() { - store.findRecord('person', 1); - }); - }, expectedError, `Payload ${JSON.stringify(payload)} should throw error ${expectedError}`); - env.registry.unregister('serializer:person'); - env.registry.unregister('adapter:person'); -}; - testInDebug("normalizeResponse 'data' cannot be undefined, a number, a string or a boolean", function(assert) { assert.payloadError({ data: undefined }, /data must be/); diff --git a/tests/unit/many-array-test.js b/tests/unit/many-array-test.js index 81aac0bf170..5ddca06ed74 100644 --- a/tests/unit/many-array-test.js +++ b/tests/unit/many-array-test.js @@ -106,25 +106,26 @@ test('manyArray trigger arrayContentChange functions with the correct values', f let willChangeRemoveAmt; let willChangeAddAmt; - let originalArrayContentWillChange = DS.ManyArray.prototype.arrayContentWillChange; - let originalArrayContentDidChange = DS.ManyArray.prototype.arrayContentDidChange; - - DS.ManyArray.reopen({ - arrayContentWillChange(startIdx, removeAmt, addAmt) { - willChangeStartIdx = startIdx; - willChangeRemoveAmt = removeAmt; - willChangeAddAmt = addAmt; - - return this._super(...arguments); - }, - arrayContentDidChange(startIdx, removeAmt, addAmt) { - assert.equal(startIdx, willChangeStartIdx, 'WillChange and DidChange startIdx should match'); - assert.equal(removeAmt, willChangeRemoveAmt, 'WillChange and DidChange removeAmt should match'); - assert.equal(addAmt, willChangeAddAmt, 'WillChange and DidChange addAmt should match'); - - return this._super(...arguments); - } - }); + let originalArrayContentWillChange = DS.ManyArray.proto().arrayContentWillChange; + let originalArrayContentDidChange = DS.ManyArray.proto().arrayContentDidChange; + + // override DS.ManyArray temp (cleanup occures in afterTest); + + DS.ManyArray.proto().arrayContentWillChange = function(startIdx, removeAmt, addAmt) { + willChangeStartIdx = startIdx; + willChangeRemoveAmt = removeAmt; + willChangeAddAmt = addAmt; + + return originalArrayContentWillChange.apply(this, arguments); + }; + + DS.ManyArray.proto().arrayContentDidChange = function(startIdx, removeAmt, addAmt) { + assert.equal(startIdx, willChangeStartIdx, 'WillChange and DidChange startIdx should match'); + assert.equal(removeAmt, willChangeRemoveAmt, 'WillChange and DidChange removeAmt should match'); + assert.equal(addAmt, willChangeAddAmt, 'WillChange and DidChange addAmt should match'); + + return originalArrayContentDidChange.apply(this, arguments); + }; try { run(() => { @@ -181,11 +182,8 @@ test('manyArray trigger arrayContentChange functions with the correct values', f } }); }); - } finally { - DS.ManyArray.reopen({ - arrayContentWillChange: originalArrayContentWillChange, - arrayContentDidChange: originalArrayContentDidChange - }); + DS.ManyArray.proto().arrayContentWillChange = originalArrayContentWillChange; + DS.ManyArray.proto().arrayContentDidChange = originalArrayContentDidChange; } }); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 263c0eae4ca..e3c92e6ff97 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -2,12 +2,11 @@ import {createStore} from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import QUnit, {module, test} from 'qunit'; +import {module, test} from 'qunit'; import DS from 'ember-data'; import isEnabled from 'ember-data/-private/features'; import { parseDate } from "ember-data/-private/ext/date"; -const AssertionPrototype = QUnit.assert; const { get, set, run } = Ember; let Person, store, env; @@ -991,7 +990,7 @@ test('when a method is invoked from an event with the same name the arguments ar assert.equal(eventMethodArgs[1], 2); }); -AssertionPrototype.converts = function converts(type, provided, expected, options = {}) { +function converts(assert, type, provided, expected, options = {}) { const Model = DS.Model.extend({ name: DS.attr(type, options) }); @@ -1015,16 +1014,16 @@ AssertionPrototype.converts = function converts(type, provided, expected, option let record = testStore.peekRecord('model', 1); - this.deepEqual(get(record, 'name'), expected, type + ' coerces ' + provided + ' to ' + expected); + assert.deepEqual(get(record, 'name'), expected, type + ' coerces ' + provided + ' to ' + expected); }); // See: Github issue #421 // record = testStore.find(Model, 2); // set(record, 'name', provided); // deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); -}; +} -AssertionPrototype.convertsFromServer = function convertsFromServer(type, provided, expected) { +function convertsFromServer(assert, type, provided, expected) { const Model = DS.Model.extend({ name: DS.attr(type) }); @@ -1051,81 +1050,54 @@ AssertionPrototype.convertsFromServer = function convertsFromServer(type, provid })); return testStore.findRecord('model', 1).then(record => { - this.deepEqual(get(record, 'name'), expected, type + ' coerces ' + provided + ' to ' + expected); - }); - }); -}; - -AssertionPrototype.convertsWhenSet = function(type, provided, expected) { - const Model = DS.Model.extend({ - name: DS.attr(type) - }); - - let testStore = createStore({ - model: Model, - adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord: () => false - }) - }); - - return run(() => { - testStore.push({ - data: { - type: 'model', - id: '2' - } - }); - - return testStore.findRecord('model', 2).then(record => { - set(record, 'name', provided); - this.deepEqual(record.serialize().name, expected, type + ' saves ' + provided + ' as ' + expected); + assert.deepEqual(get(record, 'name'), expected, type + ' coerces ' + provided + ' to ' + expected); }); }); -}; +} test('a DS.Model can describe String attributes', function(assert) { assert.expect(4); - assert.converts('string', 'Scumbag Tom', 'Scumbag Tom'); - assert.converts('string', 1, '1'); - assert.converts('string', '', ''); - assert.converts('string', null, null); + converts(assert, 'string', 'Scumbag Tom', 'Scumbag Tom'); + converts(assert, 'string', 1, '1'); + converts(assert, 'string', '', ''); + converts(assert, 'string', null, null); }); test('a DS.Model can describe Number attributes', function(assert) { assert.expect(8); - assert.converts('number', '1', 1); - assert.converts('number', '0', 0); - assert.converts('number', 1, 1); - assert.converts('number', 0, 0); - assert.converts('number', "", null); - assert.converts('number', null, null); - assert.converts('number', true, 1); - assert.converts('number', false, 0); + converts(assert, 'number', '1', 1); + converts(assert, 'number', '0', 0); + converts(assert, 'number', 1, 1); + converts(assert, 'number', 0, 0); + converts(assert, 'number', "", null); + converts(assert, 'number', null, null); + converts(assert, 'number', true, 1); + converts(assert, 'number', false, 0); }); test('a DS.Model can describe Boolean attributes', function(assert) { - assert.converts('boolean', '1', true); - assert.converts('boolean', "", false); - assert.converts('boolean', 1, true); - assert.converts('boolean', 0, false); + converts(assert, 'boolean', '1', true); + converts(assert, 'boolean', "", false); + converts(assert, 'boolean', 1, true); + converts(assert, 'boolean', 0, false); - assert.converts('boolean', null, null, { allowNull: true }); + converts(assert, 'boolean', null, null, { allowNull: true }); - assert.converts('boolean', null, false, { allowNull: false }); + converts(assert, 'boolean', null, false, { allowNull: false }); - assert.converts('boolean', null, false); + converts(assert, 'boolean', null, false); - assert.converts('boolean', true, true); - assert.converts('boolean', false, false); + converts(assert, 'boolean', true, true); + converts(assert, 'boolean', false, false); }); test('a DS.Model can describe Date attributes', function(assert) { assert.expect(5); - assert.converts('date', null, null); - assert.converts('date', undefined, undefined); + converts(assert, 'date', null, null); + converts(assert, 'date', undefined, undefined); let dateString = '2011-12-31T00:08:16.000Z'; let date = new Date(parseDate(dateString)); @@ -1154,11 +1126,38 @@ test('a DS.Model can describe Date attributes', function(assert) { assert.deepEqual(date, get(record, 'updatedAt'), 'setting a date returns the same date'); }); }).then(() => { - assert.convertsFromServer('date', dateString, date); - assert.convertsWhenSet('date', date, dateString); + convertsFromServer(assert, 'date', dateString, date); + convertsWhenSet(assert, 'date', date, dateString); }); }); +function convertsWhenSet(assert, type, provided, expected) { + let testStore = createStore({ + model: DS.Model.extend({ + name: DS.attr(type) + }), + adapter: DS.Adapter.extend({ + shouldBackgroundReloadRecord() { + return false; + } + }) + }); + + return run(() => { + testStore.push({ + data: { + type: 'model', + id: '2' + } + }); + + return testStore.findRecord('model', 2).then(record => { + set(record, 'name', provided); + assert.deepEqual(record.serialize().name, expected, type + ' saves ' + provided + ' as ' + expected); + }); + }); +} + testInDebug(`don't allow setting`, function(assert) { const Person = DS.Model.extend(); From 2219c3957afd75f2102c5dc511bf9f8530515e7a Mon Sep 17 00:00:00 2001 From: Ryunosuke Sato Date: Tue, 7 Mar 2017 01:06:05 +0900 Subject: [PATCH 1827/2527] [DOC] Fix markup for example code of `DS.Model#inverseFor` --- addon/-private/system/model/model.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 038483cc541..fb8fb992d12 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1296,8 +1296,10 @@ Model.reopenClass({ }); ``` - store.modelFor('post').inverseFor('comments', store) -> { type: App.Message, name: 'owner', kind: 'belongsTo' } - store.modelFor('message').inverseFor('owner', store) -> { type: App.Post, name: 'comments', kind: 'hasMany' } + ``` js + store.modelFor('post').inverseFor('comments', store) // { type: App.Message, name: 'owner', kind: 'belongsTo' } + store.modelFor('message').inverseFor('owner', store) // { type: App.Post, name: 'comments', kind: 'hasMany' } + ``` @method inverseFor @static From ac354276d1e342784c3d54ba74dd1d60eeadc180 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 7 Mar 2017 21:16:29 -0800 Subject: [PATCH 1828/2527] Cleanup (#4841) * cleanup system/relationship/has-many * cleanup system/relationships/state/relationship * cleanup system/relationship/state/has-many --- .../-private/system/relationships/has-many.js | 24 +++++++++---------- .../system/relationships/state/has-many.js | 20 ++++++++-------- .../relationships/state/relationship.js | 10 ++++---- .../relationships/has-many-test.js | 11 ++++----- 4 files changed, 32 insertions(+), 33 deletions(-) diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index 235281a8fdc..9d0514d72da 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -2,11 +2,12 @@ @module ember-data */ - import Ember from 'ember'; -import { assert } from "ember-data/-private/debug"; -import normalizeModelName from "ember-data/-private/system/normalize-model-name"; -import isArrayLike from "ember-data/-private/system/is-array-like"; +import { assert } from 'ember-data/-private/debug'; +import normalizeModelName from 'ember-data/-private/system/normalize-model-name'; +import isArrayLike from 'ember-data/-private/system/is-array-like'; + +const { get } = Ember; /** `DS.hasMany` is used to define One-To-Many and Many-To-Many @@ -79,7 +80,7 @@ import isArrayLike from "ember-data/-private/system/is-array-like"; the `post` relationship on the inverse because post is the only relationship to that model. - However, sometimes you may have multiple `belongsTo`/`hasManys` for the + However, sometimes you may have multiple `belongsTo`/`hasMany` for the same type. You can specify which property on the related model is the inverse using `DS.hasMany`'s `inverse` option: @@ -120,7 +121,7 @@ export default function hasMany(type, options) { type = undefined; } - assert("The first argument to DS.hasMany must be a string representing a model type key, not an instance of " + Ember.inspect(type) + ". E.g., to define a relation to the Comment model, use DS.hasMany('comment')", typeof type === 'string' || typeof type === 'undefined'); + assert(`The first argument to DS.hasMany must be a string representing a model type key, not an instance of ${Ember.inspect(type)}. E.g., to define a relation to the Comment model, use DS.hasMany('comment')`, typeof type === 'string' || typeof type === 'undefined'); options = options || {}; @@ -133,9 +134,9 @@ export default function hasMany(type, options) { // serialization. Note that `key` is populated lazily // the first time the CP is called. let meta = { - type: type, + type, + options, isRelationship: true, - options: options, kind: 'hasMany', name: 'Has Many', key: null @@ -143,18 +144,17 @@ export default function hasMany(type, options) { return Ember.computed({ get(key) { - let relationship = this._internalModel._relationships.get(key); - return relationship.getRecords(); + return this._internalModel._relationships.get(key).getRecords(); }, set(key, records) { - assert("You must pass an array of records to set a hasMany relationship", isArrayLike(records)); + assert(`You must pass an array of records to set a hasMany relationship`, isArrayLike(records)); assert(`All elements of a hasMany relationship must be instances of DS.Model, you passed ${Ember.inspect(records)}`, (function() { return Ember.A(records).every((record) => record.hasOwnProperty('_internalModel') === true); })()); let relationship = this._internalModel._relationships.get(key); relationship.clear(); - relationship.addRecords(Ember.A(records).mapBy('_internalModel')); + relationship.addRecords(records.map(record => get(record, '_internalModel'))); return relationship.getRecords(); } }).meta(meta); diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 6cda156f3cf..571abc7f948 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -1,10 +1,10 @@ -import { assert } from "ember-data/-private/debug"; -import { PromiseManyArray, promiseManyArray } from "ember-data/-private/system/promise-proxies"; -import Relationship from "ember-data/-private/system/relationships/state/relationship"; -import OrderedSet from "ember-data/-private/system/ordered-set"; -import ManyArray from "ember-data/-private/system/many-array"; +import { assert } from 'ember-data/-private/debug'; +import { PromiseManyArray, promiseManyArray } from 'ember-data/-private/system/promise-proxies'; +import Relationship from 'ember-data/-private/system/relationships/state/relationship'; +import OrderedSet from 'ember-data/-private/system/ordered-set'; +import ManyArray from 'ember-data/-private/system/many-array'; -import { assertPolymorphicType } from "ember-data/-private/debug"; +import { assertPolymorphicType } from 'ember-data/-private/debug'; export default class ManyRelationship extends Relationship { constructor(store, record, inverseKey, relationshipMeta) { @@ -74,7 +74,7 @@ export default class ManyRelationship extends Relationship { } removeCanonicalRecordFromOwn(record, idx) { - var i = idx; + let i = idx; if (!this.canonicalMembers.has(record)) { return; } @@ -141,7 +141,7 @@ export default class ManyRelationship extends Relationship { let recordsToRemove = []; let recordSet = setForArray(records); - members.forEach(function(member) { + members.forEach(member => { if (recordSet.has(member)) { return; } recordsToRemove.push(member); @@ -157,7 +157,7 @@ export default class ManyRelationship extends Relationship { } fetchLink() { - return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then((records) => { + return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(records => { if (records.hasOwnProperty('meta')) { this.updateMeta(records.meta); } @@ -212,7 +212,7 @@ export default class ManyRelationship extends Relationship { }); return this._loadingPromise; } else { - assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", manyArray.isEvery('isEmpty', false)); + assert(`You looked up the '${this.key}' relationship on a '${this.record.type.modelName}' with id ${this.record.id} but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async ('DS.hasMany({ async: true })')`, manyArray.isEvery('isEmpty', false)); //TODO(Igor) WTF DO I DO HERE? // TODO @runspired equal WTFs to Igor diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 15afbf5d223..a4487b2977b 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -1,7 +1,7 @@ /* global heimdall */ -import { assert, warn } from "ember-data/-private/debug"; -import OrderedSet from "ember-data/-private/system/ordered-set"; -import _normalizeLink from "ember-data/-private/system/normalize-link"; +import { assert, warn } from 'ember-data/-private/debug'; +import OrderedSet from 'ember-data/-private/system/ordered-set'; +import _normalizeLink from 'ember-data/-private/system/normalize-link'; const { addCanonicalRecord, @@ -132,7 +132,7 @@ export default class Relationship { addRecords(records, idx) { heimdall.increment(addRecords); - records.forEach((record) => { + records.forEach(record => { this.addRecord(record, idx); if (idx !== undefined) { idx++; @@ -291,7 +291,7 @@ export default class Relationship { warn(`You pushed a record of type '${this.record.modelName}' with a relationship '${this.key}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, this.isAsync || this.hasData , { id: 'ds.store.push-link-for-sync-relationship' }); - assert("You have pushed a record of type '" + this.record.modelName + "' with '" + this.key + "' as a link, but the value of that link is not a string.", typeof link === 'string' || link === null); + assert(`You have pushed a record of type '${this.record.modelName}' with '${this.key}' as a link, but the value of that link is not a string.`, typeof link === 'string' || link === null); this.link = link; this.linkPromise = null; diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 08fe3b7b7eb..d94d7015689 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1620,9 +1620,8 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the }); }); -testInDebug("A sync hasMany errors out if there are unlaoded records in it", function(assert) { - var post; - run(function() { +testInDebug('A sync hasMany errors out if there are unlaoded records in it', function(assert) { + let post = run(() => { env.store.push({ data: { type: 'post', @@ -1637,12 +1636,12 @@ testInDebug("A sync hasMany errors out if there are unlaoded records in it", fun } } }); - post = env.store.peekRecord('post', 1); + return env.store.peekRecord('post', 1); }); - assert.expectAssertion(function() { + assert.expectAssertion(() => { run(post, 'get', 'comments'); - }, /You looked up the 'comments' relationship on a 'post' with id 1 but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async \(`DS.hasMany\({ async: true }\)`\)/); + }, /You looked up the 'comments' relationship on a 'post' with id 1 but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async \('DS.hasMany\({ async: true }\)'\)/); }); test("If reordered hasMany data has been pushed to the store, the many array reflects the ordering change - sync", function(assert) { From 8fa3ea7dfbf92d3566dbb8599ef4a57649c3af80 Mon Sep 17 00:00:00 2001 From: k-fish Date: Wed, 8 Mar 2017 02:47:19 -0500 Subject: [PATCH 1829/2527] [DOC release] Add note to embedded records mixin (#4719) As mentioned in https://github.com/emberjs/data/issues/4575, the fact that embedded records rely on their own serializer can cause some confusion when using different serializers inside an application. --- addon/serializers/embedded-records-mixin.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 359cefbea63..a63d3fecf0f 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -13,6 +13,8 @@ const camelize = Ember.String.camelize; To set up embedded records, include the mixin when extending a serializer, then define and configure embedded (model) relationships. + Note that embedded records will serialize with the serializer for their model instead of the serializer in which they are defined. + Below is an example of a per-type serializer (`post` type). ```app/serializers/post.js From a90de0deb86d0243ee34a462537aaa17b1b0eb55 Mon Sep 17 00:00:00 2001 From: Maarten Parmentier Date: Wed, 8 Mar 2017 08:52:17 +0100 Subject: [PATCH 1830/2527] Fixed modelFor documentation. Look up model's class name (#4693) * Fixed modelFor documentation. Look up model's class name ```Represents the model's class name as a string. This can be used to look up the model's class name through DS.Store's modelFor method.``` This is wrong and should be `model's class name` since you don't look up the actual model but the name. * wrap DS.Store in fences --- addon/-private/system/model/model.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index fb8fb992d12..b3ff3f082a5 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1200,8 +1200,8 @@ Model.reopenClass({ @static */ /** - Represents the model's class name as a string. This can be used to look up the model through - DS.Store's modelFor method. + Represents the model's class name as a string. This can be used to look up the model's class name through + `DS.Store`'s modelFor method. `modelName` is generated for you by Ember Data. It will be a lowercased, dasherized string. For example: From 1e9bf996f0e41a8e7250607bac6a6318cce74d22 Mon Sep 17 00:00:00 2001 From: Pete Date: Wed, 8 Mar 2017 00:10:49 -0800 Subject: [PATCH 1831/2527] Converting imports to relative paths for better IDE/Editor integration (#4700) --- addon/-private/initializers/store.js | 6 +-- addon/-private/initializers/transforms.js | 2 +- addon/-private/system/clone-null.js | 2 +- addon/-private/system/debug.js | 2 +- addon/-private/system/debug/debug-adapter.js | 5 +- addon/-private/system/many-array.js | 4 +- addon/-private/system/model.js | 8 +-- addon/-private/system/model/internal-model.js | 14 ++--- addon/-private/system/model/model.js | 12 ++--- addon/-private/system/promise-proxies.js | 2 +- addon/-private/system/record-array-manager.js | 2 +- addon/-private/system/record-arrays.js | 6 +-- .../adapter-populated-record-array.js | 4 +- .../record-arrays/filtered-record-array.js | 2 +- .../system/record-arrays/record-array.js | 5 +- .../-private/system/references/belongs-to.js | 2 +- addon/-private/system/references/has-many.js | 2 +- addon/-private/system/relationship-meta.js | 2 +- .../system/relationships/belongs-to.js | 2 +- addon/-private/system/relationships/ext.js | 2 +- .../-private/system/relationships/has-many.js | 6 +-- .../system/relationships/state/belongs-to.js | 11 ++-- .../system/relationships/state/create.js | 6 +-- .../system/relationships/state/has-many.js | 12 ++--- .../relationships/state/relationship.js | 4 +- addon/-private/system/snapshot.js | 2 +- addon/-private/system/store.js | 43 ++++++++------- .../system/store/container-instance-cache.js | 2 +- addon/-private/transforms/boolean.js | 2 +- addon/-private/transforms/date.js | 2 +- addon/-private/transforms/number.js | 2 +- addon/-private/transforms/string.js | 2 +- .../-private/utils/parse-response-headers.js | 2 +- addon/adapters/errors.js | 4 +- addon/adapters/json-api.js | 4 +- addon/adapters/rest.js | 10 ++-- addon/index.js | 52 +++++++++---------- addon/model.js | 2 +- addon/relationships.js | 4 +- addon/serializers/json-api.js | 8 +-- addon/serializers/json.js | 14 ++--- addon/serializers/rest.js | 16 +++--- addon/setup-container.js | 8 +-- addon/store.js | 2 +- 44 files changed, 156 insertions(+), 150 deletions(-) diff --git a/addon/-private/initializers/store.js b/addon/-private/initializers/store.js index 2857e62c443..d322211f833 100644 --- a/addon/-private/initializers/store.js +++ b/addon/-private/initializers/store.js @@ -1,6 +1,6 @@ -import Store from "ember-data/-private/system/store"; -import { JSONAPISerializer, JSONSerializer, RESTSerializer } from "ember-data/-private/serializers"; -import { JSONAPIAdapter, RESTAdapter } from "ember-data/-private/adapters"; +import Store from "../system/store"; +import { JSONAPISerializer, JSONSerializer, RESTSerializer } from "../serializers"; +import { JSONAPIAdapter, RESTAdapter } from "../adapters"; function has(applicationOrRegistry, fullName) { if (applicationOrRegistry.has) { diff --git a/addon/-private/initializers/transforms.js b/addon/-private/initializers/transforms.js index 57c1df9395f..8e55b693b11 100644 --- a/addon/-private/initializers/transforms.js +++ b/addon/-private/initializers/transforms.js @@ -3,7 +3,7 @@ import { DateTransform, StringTransform, NumberTransform -} from "ember-data/-private/transforms"; +} from "../transforms"; /* Configures a registry for use with Ember-Data diff --git a/addon/-private/system/clone-null.js b/addon/-private/system/clone-null.js index ad6d64b1062..97210f5353c 100644 --- a/addon/-private/system/clone-null.js +++ b/addon/-private/system/clone-null.js @@ -1,4 +1,4 @@ -import EmptyObject from "ember-data/-private/system/empty-object"; +import EmptyObject from "./empty-object"; export default function cloneNull(source) { let clone = new EmptyObject(); for (let key in source) { diff --git a/addon/-private/system/debug.js b/addon/-private/system/debug.js index 8e605cb4b9a..bda6db7c0f3 100644 --- a/addon/-private/system/debug.js +++ b/addon/-private/system/debug.js @@ -2,6 +2,6 @@ @module ember-data */ -import DebugAdapter from "ember-data/-private/system/debug/debug-adapter"; +import DebugAdapter from "./debug/debug-adapter"; export default DebugAdapter; diff --git a/addon/-private/system/debug/debug-adapter.js b/addon/-private/system/debug/debug-adapter.js index 2c11012e74b..9df2fabf50d 100644 --- a/addon/-private/system/debug/debug-adapter.js +++ b/addon/-private/system/debug/debug-adapter.js @@ -2,11 +2,10 @@ @module ember-data */ import Ember from 'ember'; -import Model from "ember-data/model"; -const get = Ember.get; +import Model from "../../../model"; const capitalize = Ember.String.capitalize; const underscore = Ember.String.underscore; -const { assert } = Ember; +const { assert, get } = Ember; /* Extend `Ember.DataAdapter` with ED specific code. diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 1b7f3564e2d..a66fb45d916 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -3,8 +3,8 @@ */ import Ember from 'ember'; import { assert } from "ember-data/-private/debug"; -import { PromiseArray } from "ember-data/-private/system/promise-proxies"; -import { _objectIsAlive } from "ember-data/-private/system/store/common"; +import { PromiseArray } from "./promise-proxies"; +import { _objectIsAlive } from "./store/common"; const { get, set } = Ember; diff --git a/addon/-private/system/model.js b/addon/-private/system/model.js index 70b928f6b9b..8342e25b1b4 100644 --- a/addon/-private/system/model.js +++ b/addon/-private/system/model.js @@ -2,10 +2,10 @@ @module ember-data */ -import Model from "ember-data/-private/system/model/model"; -import attr from "ember-data/attr"; -import RootState from "ember-data/-private/system/model/states"; -import Errors from "ember-data/-private/system/model/errors"; +import Model from "./model/model"; +import attr from "../../attr"; +import RootState from "./model/states"; +import Errors from "./model/errors"; export { RootState, diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 43fef0b646e..57553a38934 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -1,11 +1,11 @@ import Ember from 'ember'; import { assert, runInDebug } from "ember-data/-private/debug"; -import RootState from "ember-data/-private/system/model/states"; -import Relationships from "ember-data/-private/system/relationships/state/create"; -import Snapshot from "ember-data/-private/system/snapshot"; -import EmptyObject from "ember-data/-private/system/empty-object"; -import isEnabled from 'ember-data/-private/features'; -import OrderedSet from "ember-data/-private/system/ordered-set"; +import RootState from "./states"; +import Relationships from "../relationships/state/create"; +import Snapshot from "../snapshot"; +import EmptyObject from "../empty-object"; +import isEnabled from '../../features'; +import OrderedSet from "../ordered-set"; import { getOwner @@ -15,7 +15,7 @@ import { RecordReference, BelongsToReference, HasManyReference -} from "ember-data/-private/system/references"; +} from "../references"; const { get, diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index b3ff3f082a5..73335d61734 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1,15 +1,15 @@ import Ember from 'ember'; import { assert, deprecate, warn } from "ember-data/-private/debug"; -import { PromiseObject } from "ember-data/-private/system/promise-proxies"; -import Errors from "ember-data/-private/system/model/errors"; -import isEnabled from 'ember-data/-private/features'; -import RootState from 'ember-data/-private/system/model/states'; -import EmptyObject from "ember-data/-private/system/empty-object"; +import { PromiseObject } from "../promise-proxies"; +import Errors from "../model/errors"; +import isEnabled from '../../features'; +import RootState from '../model/states'; +import EmptyObject from "../empty-object"; import { relationshipsByNameDescriptor, relatedTypesDescriptor, relationshipsDescriptor -} from 'ember-data/-private/system/relationships/ext'; +} from '../relationships/ext'; import { runInDebug } from 'ember-data/-private/debug'; const { diff --git a/addon/-private/system/promise-proxies.js b/addon/-private/system/promise-proxies.js index 6fc3f9a8e8f..64309f69681 100644 --- a/addon/-private/system/promise-proxies.js +++ b/addon/-private/system/promise-proxies.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert } from "ember-data/-private/debug"; +import { assert } from "../debug"; const { get , RSVP: { Promise }} = Ember; diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 0df3350f4a1..a52868d0ac2 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -7,7 +7,7 @@ import { RecordArray, FilteredRecordArray, AdapterPopulatedRecordArray -} from "ember-data/-private/system/record-arrays"; +} from "./record-arrays"; import { assert } from 'ember-data/-private/debug'; const { diff --git a/addon/-private/system/record-arrays.js b/addon/-private/system/record-arrays.js index d2811b17ee7..e5dd1375283 100644 --- a/addon/-private/system/record-arrays.js +++ b/addon/-private/system/record-arrays.js @@ -2,9 +2,9 @@ @module ember-data */ -import RecordArray from "ember-data/-private/system/record-arrays/record-array"; -import FilteredRecordArray from "ember-data/-private/system/record-arrays/filtered-record-array"; -import AdapterPopulatedRecordArray from "ember-data/-private/system/record-arrays/adapter-populated-record-array"; +import RecordArray from "./record-arrays/record-array"; +import FilteredRecordArray from "./record-arrays/filtered-record-array"; +import AdapterPopulatedRecordArray from "./record-arrays/adapter-populated-record-array"; export { RecordArray, diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index cbb76b7cd3e..78869b879a4 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -1,6 +1,6 @@ import Ember from 'ember'; -import RecordArray from "ember-data/-private/system/record-arrays/record-array"; -import cloneNull from "ember-data/-private/system/clone-null"; +import RecordArray from "./record-array"; +import cloneNull from "../clone-null"; /** @module ember-data diff --git a/addon/-private/system/record-arrays/filtered-record-array.js b/addon/-private/system/record-arrays/filtered-record-array.js index ffc84e5d3ef..3fb9eaac50f 100644 --- a/addon/-private/system/record-arrays/filtered-record-array.js +++ b/addon/-private/system/record-arrays/filtered-record-array.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import RecordArray from "ember-data/-private/system/record-arrays/record-array"; +import RecordArray from "./record-array"; /** @module ember-data diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index a077fcdbfa3..34dcf3cfc6f 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -3,8 +3,9 @@ */ import Ember from 'ember'; -import { PromiseArray } from "ember-data/-private/system/promise-proxies"; -import SnapshotRecordArray from "ember-data/-private/system/snapshot-record-array"; +import { PromiseArray } from "../promise-proxies"; +import SnapshotRecordArray from "../snapshot-record-array"; + const { computed, get, set, RSVP: { Promise } } = Ember; /** diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index d9ad4acccd2..7d54cf1ee66 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -2,7 +2,7 @@ import Model from 'ember-data/model'; import Ember from 'ember'; import Reference from './reference'; -import isEnabled from 'ember-data/-private/features'; +import isEnabled from '../../features'; import { assertPolymorphicType, deprecate } from "ember-data/-private/debug"; diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 31b6ccbd03c..a833b544948 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -6,7 +6,7 @@ import { runInDebug } from 'ember-data/-private/debug'; -import isEnabled from 'ember-data/-private/features'; +import isEnabled from '../../features'; const { RSVP: { resolve }, diff --git a/addon/-private/system/relationship-meta.js b/addon/-private/system/relationship-meta.js index 1c3ca070cb1..d1b00745fdd 100644 --- a/addon/-private/system/relationship-meta.js +++ b/addon/-private/system/relationship-meta.js @@ -1,5 +1,5 @@ import {singularize} from 'ember-inflector'; -import normalizeModelName from 'ember-data/-private/system/normalize-model-name'; +import normalizeModelName from './normalize-model-name'; export function typeForRelationshipMeta(meta) { let modelName; diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 7d3e045d9fc..7a444304e3c 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -1,6 +1,6 @@ import Ember from 'ember'; import { assert, warn } from "ember-data/-private/debug"; -import normalizeModelName from "ember-data/-private/system/normalize-model-name"; +import normalizeModelName from "../normalize-model-name"; /** `DS.belongsTo` is used to define One-To-One and One-To-Many diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 64ba8b236dc..152469606a4 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -3,7 +3,7 @@ import { assert } from "ember-data/-private/debug"; import { typeForRelationshipMeta, relationshipFromMeta -} from "ember-data/-private/system/relationship-meta"; +} from "../relationship-meta"; const Map = Ember.Map; const MapWithDefault = Ember.MapWithDefault; diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index 9d0514d72da..76a4ed396f6 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -3,9 +3,9 @@ */ import Ember from 'ember'; -import { assert } from 'ember-data/-private/debug'; -import normalizeModelName from 'ember-data/-private/system/normalize-model-name'; -import isArrayLike from 'ember-data/-private/system/is-array-like'; +import { assert } from "ember-data/-private/debug"; +import normalizeModelName from "../normalize-model-name"; +import isArrayLike from "../is-array-like"; const { get } = Ember; diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 417d3243af3..03f19299ecc 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -1,11 +1,12 @@ import Ember from 'ember'; -import { assert } from "ember-data/-private/debug"; +import { + assertPolymorphicType, + assert +} from "ember-data/-private/debug"; import { PromiseObject -} from "ember-data/-private/system/promise-proxies"; - -import { assertPolymorphicType } from "ember-data/-private/debug"; -import Relationship from "ember-data/-private/system/relationships/state/relationship"; +} from "../../promise-proxies"; +import Relationship from "./relationship"; export default class BelongsToRelationship extends Relationship { constructor(store, internalModel, inverseKey, relationshipMeta) { diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index b98e6f3f30b..1e7756b0329 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -1,7 +1,7 @@ import Ember from 'ember'; -import ManyRelationship from "ember-data/-private/system/relationships/state/has-many"; -import BelongsToRelationship from "ember-data/-private/system/relationships/state/belongs-to"; -import EmptyObject from "ember-data/-private/system/empty-object"; +import ManyRelationship from "./has-many"; +import BelongsToRelationship from "./belongs-to"; +import EmptyObject from "../../empty-object"; import { runInDebug } from 'ember-data/-private/debug'; const { get } = Ember; diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 571abc7f948..075483887b1 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -1,10 +1,8 @@ -import { assert } from 'ember-data/-private/debug'; -import { PromiseManyArray, promiseManyArray } from 'ember-data/-private/system/promise-proxies'; -import Relationship from 'ember-data/-private/system/relationships/state/relationship'; -import OrderedSet from 'ember-data/-private/system/ordered-set'; -import ManyArray from 'ember-data/-private/system/many-array'; - -import { assertPolymorphicType } from 'ember-data/-private/debug'; +import { assert, assertPolymorphicType } from "ember-data/-private/debug"; +import { PromiseManyArray, promiseManyArray } from "../../promise-proxies"; +import Relationship from "./relationship"; +import OrderedSet from "../../ordered-set"; +import ManyArray from "../../many-array"; export default class ManyRelationship extends Relationship { constructor(store, record, inverseKey, relationshipMeta) { diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index a4487b2977b..46b77713eae 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -1,7 +1,7 @@ /* global heimdall */ import { assert, warn } from 'ember-data/-private/debug'; -import OrderedSet from 'ember-data/-private/system/ordered-set'; -import _normalizeLink from 'ember-data/-private/system/normalize-link'; +import OrderedSet from '../../ordered-set'; +import _normalizeLink from '../../normalize-link'; const { addCanonicalRecord, diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index 161496cc2fa..0403458b2aa 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -3,7 +3,7 @@ */ import Ember from 'ember'; -import EmptyObject from "ember-data/-private/system/empty-object"; +import EmptyObject from "./empty-object"; const { get diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b3a22b81cc1..1135f443ed8 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -3,24 +3,31 @@ */ import Ember from 'ember'; -import Model from 'ember-data/model'; -import { instrument, assert, deprecate, warn, runInDebug } from "ember-data/-private/debug"; -import normalizeModelName from "ember-data/-private/system/normalize-model-name"; -import { InvalidError } from 'ember-data/adapters/errors'; -import IdentityMap from 'ember-data/-private/system/identity-map'; +import { + instrument, + assert, + deprecate, + warn, + runInDebug +} from "ember-data/-private/debug"; +import Model from '../../model'; +import normalizeModelName from "./normalize-model-name"; +import { InvalidError } from '../../adapters/errors'; +import IdentityMap from './identity-map'; + import { promiseArray, promiseObject -} from "ember-data/-private/system/promise-proxies"; +} from "./promise-proxies"; import { _bind, _guard, _objectIsAlive -} from "ember-data/-private/system/store/common"; +} from "./store/common"; -import { normalizeResponseHelper } from "ember-data/-private/system/store/serializer-response"; -import { serializerForAdapter } from "ember-data/-private/system/store/serializers"; +import { normalizeResponseHelper } from "./store/serializer-response"; +import { serializerForAdapter } from "./store/serializers"; import { _find, @@ -30,15 +37,15 @@ import { _findAll, _query, _queryRecord -} from "ember-data/-private/system/store/finders"; - -import { getOwner } from 'ember-data/-private/utils'; -import coerceId from "ember-data/-private/system/coerce-id"; -import RecordArrayManager from "ember-data/-private/system/record-array-manager"; -import ContainerInstanceCache from 'ember-data/-private/system/store/container-instance-cache'; -import InternalModel from "ember-data/-private/system/model/internal-model"; -import EmptyObject from "ember-data/-private/system/empty-object"; -import isEnabled from 'ember-data/-private/features'; +} from "./store/finders"; + +import { getOwner } from '../utils'; +import coerceId from "./coerce-id"; +import RecordArrayManager from "./record-array-manager"; +import ContainerInstanceCache from './store/container-instance-cache'; +import InternalModel from "./model/internal-model"; +import EmptyObject from "./empty-object"; +import isEnabled from '../features'; export let badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; diff --git a/addon/-private/system/store/container-instance-cache.js b/addon/-private/system/store/container-instance-cache.js index 08c8cf1e0c0..ff3edfe0cb2 100644 --- a/addon/-private/system/store/container-instance-cache.js +++ b/addon/-private/system/store/container-instance-cache.js @@ -1,6 +1,6 @@ /* global heimdall */ import Ember from 'ember'; -import EmptyObject from "ember-data/-private/system/empty-object"; +import EmptyObject from "../empty-object"; const { set } = Ember; const { diff --git a/addon/-private/transforms/boolean.js b/addon/-private/transforms/boolean.js index 8c914ce0806..7150f1aade5 100644 --- a/addon/-private/transforms/boolean.js +++ b/addon/-private/transforms/boolean.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import Transform from "ember-data/transform"; +import Transform from "../../transform"; const { isNone } = Ember; diff --git a/addon/-private/transforms/date.js b/addon/-private/transforms/date.js index a6043baed04..beb9f34999b 100644 --- a/addon/-private/transforms/date.js +++ b/addon/-private/transforms/date.js @@ -1,4 +1,4 @@ -import { parseDate } from "ember-data/-private/ext/date"; +import { parseDate } from "../ext/date"; /** The `DS.DateTransform` class is used to serialize and deserialize diff --git a/addon/-private/transforms/number.js b/addon/-private/transforms/number.js index eed6fdd885f..b5628aff688 100644 --- a/addon/-private/transforms/number.js +++ b/addon/-private/transforms/number.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import Transform from "ember-data/transform"; +import Transform from "../../transform"; const empty = Ember.isEmpty; diff --git a/addon/-private/transforms/string.js b/addon/-private/transforms/string.js index 6da8a713445..2d8e7b779b6 100644 --- a/addon/-private/transforms/string.js +++ b/addon/-private/transforms/string.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import Transform from "ember-data/transform"; +import Transform from "../../transform"; const none = Ember.isNone; diff --git a/addon/-private/utils/parse-response-headers.js b/addon/-private/utils/parse-response-headers.js index 18112552d6b..5f420d595c0 100644 --- a/addon/-private/utils/parse-response-headers.js +++ b/addon/-private/utils/parse-response-headers.js @@ -1,4 +1,4 @@ -import EmptyObject from 'ember-data/-private/system/empty-object'; +import EmptyObject from '../system/empty-object'; const CLRF = '\u000d\u000a'; diff --git a/addon/adapters/errors.js b/addon/adapters/errors.js index 03b1fd6e38d..df26fae02cc 100644 --- a/addon/adapters/errors.js +++ b/addon/adapters/errors.js @@ -1,6 +1,6 @@ import Ember from 'ember'; -import {assert} from 'ember-data/-private/debug'; -import isEnabled from "ember-data/-private/features"; +import { assert } from 'ember-data/-private/debug'; +import isEnabled from '../-private/features'; const EmberError = Ember.Error; diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index 9d0d6efccea..d2f417be537 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -4,8 +4,8 @@ */ import Ember from 'ember'; -import RESTAdapter from "ember-data/adapters/rest"; -import isEnabled from 'ember-data/-private/features'; +import RESTAdapter from "./rest"; +import isEnabled from '../-private/features'; import { instrument, deprecate } from 'ember-data/-private/debug'; /** diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index ef2ca394321..473f30874a9 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -4,7 +4,7 @@ */ import Ember from 'ember'; -import Adapter from "ember-data/adapter"; +import Adapter from "../adapter"; import { AdapterError, InvalidError, @@ -15,11 +15,11 @@ import { ServerError, TimeoutError, AbortError -} from 'ember-data/adapters/errors'; -import BuildURLMixin from "ember-data/-private/adapters/build-url-mixin"; -import isEnabled from 'ember-data/-private/features'; +} from './errors'; +import BuildURLMixin from "../-private/adapters/build-url-mixin"; +import isEnabled from '../-private/features'; import { instrument, runInDebug, warn, deprecate } from 'ember-data/-private/debug'; -import parseResponseHeaders from 'ember-data/-private/utils/parse-response-headers'; +import parseResponseHeaders from '../-private/utils/parse-response-headers'; const { MapWithDefault, diff --git a/addon/index.js b/addon/index.js index a07ed371bee..247ca924b5f 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,7 +1,7 @@ import Ember from "ember"; import { deprecate } from "ember-data/-private/debug"; -import isEnabled from "ember-data/-private/features"; -import global from "ember-data/-private/global"; +import isEnabled from "./-private/features"; +import global from "./-private/global"; /** Ember Data @@ -15,30 +15,30 @@ if (Ember.VERSION.match(/^1\.([0-9]|1[0-2])\./)) { ". Please upgrade your version of Ember, then upgrade Ember Data."); } -import DS from "ember-data/-private/core"; +import DS from "./-private/core"; -import normalizeModelName from "ember-data/-private/system/normalize-model-name"; +import normalizeModelName from "./-private/system/normalize-model-name"; -import InternalModel from "ember-data/-private/system/model/internal-model"; +import InternalModel from "./-private/system/model/internal-model"; import { PromiseArray, PromiseObject, PromiseManyArray -} from "ember-data/-private/system/promise-proxies"; +} from "./-private/system/promise-proxies"; import { Store -} from "ember-data/-private/system/store"; +} from "./-private/system/store"; import { Errors, RootState, attr -} from "ember-data/-private/system/model"; -import Model from "ember-data/model"; -import Snapshot from "ember-data/-private/system/snapshot"; -import Adapter from "ember-data/adapter"; -import Serializer from "ember-data/serializer"; -import DebugAdapter from "ember-data/-private/system/debug"; +} from "./-private/system/model"; +import Model from "./model"; +import Snapshot from "./-private/system/snapshot"; +import Adapter from "./adapter"; +import Serializer from "./serializer"; +import DebugAdapter from "ember-data/-private/debug"; import { AdapterError, @@ -52,27 +52,27 @@ import { AbortError, errorsHashToArray, errorsArrayToHash -} from "ember-data/adapters/errors"; +} from "./adapters/errors"; import { RecordArray, FilteredRecordArray, AdapterPopulatedRecordArray -} from "ember-data/-private/system/record-arrays"; -import ManyArray from "ember-data/-private/system/many-array"; -import RecordArrayManager from "ember-data/-private/system/record-array-manager"; +} from "./-private/system/record-arrays"; +import ManyArray from "./-private/system/many-array"; +import RecordArrayManager from "./-private/system/record-array-manager"; import { JSONAPIAdapter, RESTAdapter -} from "ember-data/-private/adapters"; -import BuildURLMixin from "ember-data/-private/adapters/build-url-mixin"; +} from "./-private/adapters"; +import BuildURLMixin from "./-private/adapters/build-url-mixin"; import { JSONAPISerializer, JSONSerializer, RESTSerializer -} from "ember-data/-private/serializers"; +} from "./-private/serializers"; import "ember-inflector"; -import EmbeddedRecordsMixin from "ember-data/serializers/embedded-records-mixin"; +import EmbeddedRecordsMixin from "./serializers/embedded-records-mixin"; import { Transform, @@ -80,13 +80,13 @@ import { NumberTransform, StringTransform, BooleanTransform -} from "ember-data/-private/transforms"; +} from "./-private/transforms"; -import {hasMany, belongsTo} from "ember-data/relationships"; -import setupContainer from "ember-data/setup-container"; -import initializeStoreService from 'ember-data/-private/instance-initializers/initialize-store-service'; +import {hasMany, belongsTo} from "./relationships"; +import setupContainer from "./setup-container"; +import initializeStoreService from './-private/instance-initializers/initialize-store-service'; -import Relationship from "ember-data/-private/system/relationships/state/relationship"; +import Relationship from "./-private/system/relationships/state/relationship"; DS.Store = Store; DS.PromiseArray = PromiseArray; diff --git a/addon/model.js b/addon/model.js index b0c7b811b47..58f2e051350 100644 --- a/addon/model.js +++ b/addon/model.js @@ -1,3 +1,3 @@ -import Model from "ember-data/-private/system/model"; +import Model from "./-private/system/model"; export default Model; diff --git a/addon/relationships.js b/addon/relationships.js index e642287c6d8..d0ace3b4140 100644 --- a/addon/relationships.js +++ b/addon/relationships.js @@ -2,8 +2,8 @@ @module ember-data */ -import belongsTo from "ember-data/-private/system/relationships/belongs-to"; -import hasMany from "ember-data/-private/system/relationships/has-many"; +import belongsTo from "./-private/system/relationships/belongs-to"; +import hasMany from "./-private/system/relationships/has-many"; export { belongsTo, diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 707b8c41e65..ec8ffb69c90 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -3,11 +3,11 @@ */ import Ember from 'ember'; -import { assert, deprecate, runInDebug, warn } from 'ember-data/-private/debug'; -import JSONSerializer from 'ember-data/serializers/json'; -import normalizeModelName from 'ember-data/-private/system/normalize-model-name'; import { pluralize, singularize } from 'ember-inflector'; -import isEnabled from 'ember-data/-private/features'; +import { assert, deprecate, runInDebug, warn } from 'ember-data/-private/debug'; +import JSONSerializer from './json'; +import normalizeModelName from '../-private/system/normalize-model-name'; +import isEnabled from '../-private/features'; const dasherize = Ember.String.dasherize; diff --git a/addon/serializers/json.js b/addon/serializers/json.js index b24c22cb1b2..2c4cf4013b8 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1,16 +1,16 @@ import Ember from 'ember'; import { assert, deprecate, warn } from 'ember-data/-private/debug'; -import Serializer from "ember-data/serializer"; -import coerceId from "ember-data/-private/system/coerce-id"; -import normalizeModelName from "ember-data/-private/system/normalize-model-name"; -import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; -import isEnabled from 'ember-data/-private/features'; +import Serializer from "../serializer"; +import coerceId from "../-private/system/coerce-id"; +import normalizeModelName from "../-private/system/normalize-model-name"; +import { modelHasAttributeOrRelationshipNamedType } from "../-private/utils"; +import isEnabled from '../-private/features'; import { getOwner -} from 'ember-data/-private/utils'; +} from '../-private/utils'; -import { errorsArrayToHash } from "ember-data/adapters/errors"; +import { errorsArrayToHash } from "../adapters/errors"; const get = Ember.get; const isNone = Ember.isNone; diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 8db235614d5..9e44a7d58d1 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -3,13 +3,13 @@ */ import Ember from 'ember'; +import { singularize } from "ember-inflector"; import { assert, deprecate, runInDebug, warn } from "ember-data/-private/debug"; -import JSONSerializer from "ember-data/serializers/json"; -import normalizeModelName from "ember-data/-private/system/normalize-model-name"; -import {singularize} from "ember-inflector"; -import coerceId from "ember-data/-private/system/coerce-id"; -import { modelHasAttributeOrRelationshipNamedType } from "ember-data/-private/utils"; -import isEnabled from 'ember-data/-private/features'; +import JSONSerializer from "../serializers/json"; +import normalizeModelName from "../-private/system/normalize-model-name"; +import coerceId from "../-private/system/coerce-id"; +import { modelHasAttributeOrRelationshipNamedType } from "../-private/utils"; +import isEnabled from '../-private/features'; let camelize = Ember.String.camelize; @@ -879,7 +879,7 @@ if (isEnabled("ds-payload-type-hooks")) { `administrator` model should be used: ```app/serializers/application.js - import DS from "ember-data"; + import DS from 'ember-data'; export default DS.RESTSerializer.extend({ modelNameFromPayloadType(payloadType) { @@ -929,7 +929,7 @@ if (isEnabled("ds-payload-type-hooks")) { namespaces model name for the `administrator` should be used: ```app/serializers/application.js - import DS from "ember-data"; + import DS from 'ember-data'; export default DS.RESTSerializer.extend({ payloadTypeFromModelName(modelName) { diff --git a/addon/setup-container.js b/addon/setup-container.js index 937ddb9a876..34dbf7a9dce 100644 --- a/addon/setup-container.js +++ b/addon/setup-container.js @@ -1,7 +1,7 @@ -import initializeStore from 'ember-data/-private/initializers/store'; -import initializeTransforms from 'ember-data/-private/initializers/transforms'; -import initializeStoreInjections from 'ember-data/-private/initializers/store-injections'; -import initializeDataAdapter from 'ember-data/-private/initializers/data-adapter'; +import initializeStore from './-private/initializers/store'; +import initializeTransforms from './-private/initializers/transforms'; +import initializeStoreInjections from './-private/initializers/store-injections'; +import initializeDataAdapter from './-private/initializers/data-adapter'; export default function setupContainer(application) { initializeDataAdapter(application); diff --git a/addon/store.js b/addon/store.js index 12ac8ed7591..d752c46bc30 100644 --- a/addon/store.js +++ b/addon/store.js @@ -1,3 +1,3 @@ -import Store from "ember-data/-private/system/store"; +import Store from "./-private/system/store"; export default Store; From 83f1308e1a75524faaadf59ffa9a6df5bf26f308 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 8 Mar 2017 00:14:15 -0800 Subject: [PATCH 1832/2527] tidy-up many-arrays (#4843) --- addon/-private/system/many-array.js | 7 +++--- addon/-private/system/references/has-many.js | 6 ++--- .../system/relationships/state/has-many.js | 23 ++++++++----------- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index a66fb45d916..52ae27b0ca5 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -133,12 +133,11 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { }, objectAt(index) { + let object = this.currentState[index]; //Ember observers such as 'firstObject', 'lastObject' might do out of bounds accesses - if (!this.currentState[index]) { - return undefined; - } + if (object === undefined) { return; } - return this.currentState[index].getRecord(); + return object.getRecord(); }, flushCanonical(isInitialized = true) { diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index a833b544948..895c709c56b 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -299,7 +299,7 @@ HasManyReference.prototype.push = function(objectOrPromise) { this.hasManyRelationship.computeChanges(internalModels); - return this.hasManyRelationship.getManyArray(); + return this.hasManyRelationship.manyArray; }); }; @@ -356,7 +356,7 @@ HasManyReference.prototype._isLoaded = function() { */ HasManyReference.prototype.value = function() { if (this._isLoaded()) { - return this.hasManyRelationship.getManyArray(); + return this.hasManyRelationship.manyArray; } return null; @@ -404,7 +404,7 @@ HasManyReference.prototype.load = function() { return this.hasManyRelationship.getRecords(); } - return resolve(this.hasManyRelationship.getManyArray()); + return resolve(this.hasManyRelationship.manyArray); }; /** diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 075483887b1..73610a7efee 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -12,7 +12,7 @@ export default class ManyRelationship extends Relationship { this.isPolymorphic = relationshipMeta.options.polymorphic; } - getManyArray() { + get manyArray() { if (!this._manyArray) { this._manyArray = ManyArray.create({ canonicalState: this.canonicalState, @@ -68,7 +68,7 @@ export default class ManyRelationship extends Relationship { } super.addRecord(record, idx); // make lazy later - this.getManyArray().internalAddRecords([record], idx); + this.manyArray.internalAddRecords([record], idx); } removeCanonicalRecordFromOwn(record, idx) { @@ -97,7 +97,7 @@ export default class ManyRelationship extends Relationship { return; } super.removeRecordFromOwn(record, idx); - let manyArray = this.getManyArray(); + let manyArray = this.manyArray; if (idx !== undefined) { //TODO(Igor) not used currently, fix manyArray.currentState.removeAt(idx); @@ -113,7 +113,7 @@ export default class ManyRelationship extends Relationship { } reload() { - let manyArray = this.getManyArray(); + let manyArray = this.manyArray; let manyArrayLoadedState = manyArray.get('isLoaded'); if (this._loadingPromise) { @@ -161,20 +161,15 @@ export default class ManyRelationship extends Relationship { } this.store._backburner.join(() => { this.updateRecordsFromAdapter(records); - this.getManyArray().set('isLoaded', true); + this.manyArray.set('isLoaded', true); }); - return this.getManyArray(); + return this.manyArray; }); } findRecords() { - let manyArray = this.getManyArray(); - let array = manyArray.toArray(); - let internalModels = new Array(array.length); - - for (let i = 0; i < array.length; i++) { - internalModels[i] = array[i]._internalModel; - } + let manyArray = this.manyArray; + let internalModels = manyArray.currentState; //TODO CLEANUP return this.store.findMany(internalModels).then(() => { @@ -192,7 +187,7 @@ export default class ManyRelationship extends Relationship { getRecords() { //TODO(Igor) sync server here, once our syncing is not stupid - let manyArray = this.getManyArray(); + let manyArray = this.manyArray; if (this.isAsync) { var promise; if (this.link) { From 1ea0b6f7aff4859d645d3474a1f90fc77358c6b9 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 8 Mar 2017 08:07:34 -0800 Subject: [PATCH 1833/2527] remove un-needed Ember.A --- addon/-private/system/many-array.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 52ae27b0ca5..cef59cc6862 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -128,7 +128,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { */ this.relationship = this.relationship || null; - this.currentState = Ember.A([]); + this.currentState = []; this.flushCanonical(false); }, From 904e412c1f6ae6e87580abcbbe617ceb4b07d873 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 8 Mar 2017 09:53:36 -0800 Subject: [PATCH 1834/2527] Stable has many promise proxy (#4842) * correctly shape has-many * [fixes #4826] make async DS.hasMany promises stable --- addon/-private/system/promise-proxies.js | 6 +- .../system/relationships/state/has-many.js | 51 ++++++++--- .../unit/model/relationships/has-many-test.js | 56 ++++++++++++ tests/unit/promise-proxies-test.js | 91 ++++++++++++++++++- 4 files changed, 183 insertions(+), 21 deletions(-) diff --git a/addon/-private/system/promise-proxies.js b/addon/-private/system/promise-proxies.js index 64309f69681..b11351afb63 100644 --- a/addon/-private/system/promise-proxies.js +++ b/addon/-private/system/promise-proxies.js @@ -103,11 +103,9 @@ export function proxyToContent(method) { export const PromiseManyArray = PromiseArray.extend({ reload() { - //I don't think this should ever happen right now, but worth guarding if we refactor the async relationships assert('You are trying to reload an async manyArray before it has been created', get(this, 'content')); - return PromiseManyArray.create({ - promise: get(this, 'content').reload() - }); + this.set('promise', this.get('content').reload()) + return this; }, createRecord: proxyToContent('createRecord'), diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 73610a7efee..c073c7c7edf 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -1,8 +1,8 @@ -import { assert, assertPolymorphicType } from "ember-data/-private/debug"; -import { PromiseManyArray, promiseManyArray } from "../../promise-proxies"; -import Relationship from "./relationship"; -import OrderedSet from "../../ordered-set"; -import ManyArray from "../../many-array"; +import { assert, assertPolymorphicType } from 'ember-data/-private/debug'; +import { PromiseManyArray } from '../../promise-proxies'; +import Relationship from './relationship'; +import OrderedSet from '../../ordered-set'; +import ManyArray from '../../many-array'; export default class ManyRelationship extends Relationship { constructor(store, record, inverseKey, relationshipMeta) { @@ -10,6 +10,25 @@ export default class ManyRelationship extends Relationship { this.belongsToType = relationshipMeta.type; this.canonicalState = []; this.isPolymorphic = relationshipMeta.options.polymorphic; + this._manyArray = null; + this.__loadingPromise = null; + } + + get _loadingPromise() { return this.__loadingPromise; } + _updateLoadingPromise(promise, content) { + if (this.__loadingPromise) { + if (content) { + this.__loadingPromise.set('content', content) + } + this.__loadingPromise.set('promise', promise) + } else { + this.__loadingPromise = new PromiseManyArray({ + promise, + content + }); + } + + return this.__loadingPromise; } get manyArray() { @@ -33,6 +52,10 @@ export default class ManyRelationship extends Relationship { this._manyArray.destroy(); this._manyArray = null; } + + if (this._loadingPromise) { + this._loadingPromise.destroy(); + } } updateMeta(meta) { @@ -125,13 +148,15 @@ export default class ManyRelationship extends Relationship { } } + let promise; if (this.link) { - this._loadingPromise = promiseManyArray(this.fetchLink(), 'Reload with link'); - return this._loadingPromise; + promise = this.fetchLink(); } else { - this._loadingPromise = promiseManyArray(this.store._scheduleFetchMany(manyArray.currentState).then(() => manyArray), 'Reload with ids'); - return this._loadingPromise; + promise = this.store._scheduleFetchMany(manyArray.currentState).then(() => manyArray); } + + this._updateLoadingPromise(promise); + return this._loadingPromise; } computeChanges(records) { @@ -189,7 +214,7 @@ export default class ManyRelationship extends Relationship { //TODO(Igor) sync server here, once our syncing is not stupid let manyArray = this.manyArray; if (this.isAsync) { - var promise; + let promise; if (this.link) { if (this.hasLoaded) { promise = this.findRecords(); @@ -199,11 +224,7 @@ export default class ManyRelationship extends Relationship { } else { promise = this.findRecords(); } - this._loadingPromise = PromiseManyArray.create({ - content: manyArray, - promise: promise - }); - return this._loadingPromise; + return this._updateLoadingPromise(promise, manyArray); } else { assert(`You looked up the '${this.key}' relationship on a '${this.record.type.modelName}' with id ${this.record.id} but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async ('DS.hasMany({ async: true })')`, manyArray.isEvery('isEmpty', false)); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index aecadcc1a17..ec5a9e5a6da 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -759,6 +759,62 @@ test("DS.hasMany is async by default", function(assert) { }); }); +test('DS.hasMany is stable', function(assert) { + const Tag = DS.Model.extend({ + name: DS.attr('string'), + people: DS.hasMany('person') + }); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: false }) + }); + + let { store } = setupStore({ tag: Tag, person: Person }); + + let tag = run(() => store.createRecord('tag')); + let people = tag.get('people'); + let peopleCached = tag.get('people'); + + assert.equal(people, peopleCached); + + tag.notifyPropertyChange('people'); + let notifiedPeople = tag.get('people'); + + assert.equal(people, notifiedPeople); + + return Ember.RSVP.Promise.all([ + people + ]); +}); + +test('DS.hasMany proxy is destroyed', function(assert) { + const Tag = DS.Model.extend({ + name: DS.attr('string'), + people: DS.hasMany('person') + }); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: false }) + }); + + let { store } = setupStore({ tag: Tag, person: Person }); + + let tag = run(() => store.createRecord('tag')); + let people = tag.get('people'); + + return people.then(() => { + Ember.run(() => { + tag.unloadRecord(); + assert.equal(people.get('isDestroying'), true); + assert.equal(people.get('isDestroyed'), false); + }); + assert.equal(people.get('isDestroying'), true); + assert.equal(people.get('isDestroyed'), true); + }) +}); + test('DS.ManyArray is lazy', function(assert) { let peopleDidChange = 0; const Tag = DS.Model.extend({ diff --git a/tests/unit/promise-proxies-test.js b/tests/unit/promise-proxies-test.js index 0c63df1188b..79d103e882e 100644 --- a/tests/unit/promise-proxies-test.js +++ b/tests/unit/promise-proxies-test.js @@ -13,8 +13,8 @@ test('.reload should NOT leak the internal promise, rather return another promis content.reload = () => Ember.RSVP.Promise.resolve(content); - let array = DS.PromiseManyArray.create({ - content: content + let array = new DS.PromiseManyArray({ + content }); let reloaded = array.reload(); @@ -23,3 +23,90 @@ test('.reload should NOT leak the internal promise, rather return another promis return reloaded.then(value => assert.equal(content, value)); }); + +test('.reload should be stable', function(assert) { + assert.expect(19); + + let content = Ember.A(); + + content.reload = () => Ember.RSVP.Promise.resolve(content); + let promise = Ember.RSVP.Promise.resolve(content); + + let array = new DS.PromiseManyArray({ + promise + }); + + assert.equal(array.get('isRejected'), false, 'should NOT be rejected'); + assert.equal(array.get('isPending'), true, 'should be pending'); + assert.equal(array.get('isSettled'), false, 'should NOT be settled'); + assert.equal(array.get('isFulfilled'), false, 'should NOT be fulfilled'); + + return array.then(() => { + assert.equal(array.get('isRejected'), false, 'should NOT be rejected'); + assert.equal(array.get('isPending'), false, 'should NOT be pending'); + assert.equal(array.get('isSettled'), true, 'should be settled'); + assert.equal(array.get('isFulfilled'), true, 'should be fulfilled'); + + let reloaded = array.reload(); + + assert.equal(array.get('isRejected'), false, 'should NOT be rejected'); + assert.equal(array.get('isPending'), true, 'should be pending'); + assert.equal(array.get('isSettled'), false, 'should NOT be settled'); + assert.equal(array.get('isFulfilled'), false, 'should NOT be fulfilled'); + + assert.ok(reloaded instanceof DS.PromiseManyArray); + assert.equal(reloaded, array); + + return reloaded.then(value => { + assert.equal(array.get('isRejected'), false, 'should NOT be rejected'); + assert.equal(array.get('isPending'), false, 'should NOT be pending'); + assert.equal(array.get('isSettled'), true, 'should be settled'); + assert.equal(array.get('isFulfilled'), true, 'should be fulfilled'); + + assert.equal(content, value); + }); + }); +}); + +test('.set to new promise should be like reload', function(assert) { + assert.expect(18); + + let content = Ember.A([1,2,3]); + + let promise = Ember.RSVP.Promise.resolve(content); + + let array = new DS.PromiseManyArray({ + promise + }); + + assert.equal(array.get('isRejected'), false, 'should NOT be rejected'); + assert.equal(array.get('isPending'), true, 'should be pending'); + assert.equal(array.get('isSettled'), false, 'should NOT be settled'); + assert.equal(array.get('isFulfilled'), false, 'should NOT be fulfilled'); + + return array.then(() => { + assert.equal(array.get('isRejected'), false, 'should NOT be rejected'); + assert.equal(array.get('isPending'), false, 'should NOT be pending'); + assert.equal(array.get('isSettled'), true, 'should be settled'); + assert.equal(array.get('isFulfilled'), true, 'should be fulfilled'); + + array.set('promise', Ember.RSVP.Promise.resolve(content)); + + assert.equal(array.get('isRejected'), false, 'should NOT be rejected'); + assert.equal(array.get('isPending'), true, 'should be pending'); + assert.equal(array.get('isSettled'), false, 'should NOT be settled'); + assert.equal(array.get('isFulfilled'), false, 'should NOT be fulfilled'); + + assert.ok(array instanceof DS.PromiseManyArray); + + return array.then(value => { + assert.equal(array.get('isRejected'), false, 'should NOT be rejected'); + assert.equal(array.get('isPending'), false, 'should NOT be pending'); + assert.equal(array.get('isSettled'), true, 'should be settled'); + assert.equal(array.get('isFulfilled'), true, 'should be fulfilled'); + + assert.equal(content, value); + }); + }); +}); + From e30a97de0e54ce6defbe81e00caee2d532afbbea Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 8 Mar 2017 14:02:02 -0800 Subject: [PATCH 1835/2527] Improve naming around internal constructs (record vs internal model) (#4847) --- addon/-private/system/identity-map.js | 23 ++++--- .../{record-map.js => internal-model-map.js} | 67 +++++++++---------- addon/-private/system/record-array-manager.js | 30 ++++----- addon/-private/system/store.js | 24 +++---- .../integration/adapter/rest-adapter-test.js | 4 +- .../integration/records/rematerialize-test.js | 12 ++-- tests/integration/records/unload-test.js | 32 ++++----- 7 files changed, 95 insertions(+), 97 deletions(-) rename addon/-private/system/{record-map.js => internal-model-map.js} (54%) diff --git a/addon/-private/system/identity-map.js b/addon/-private/system/identity-map.js index a54cfd2e2a5..b272aa8304d 100644 --- a/addon/-private/system/identity-map.js +++ b/addon/-private/system/identity-map.js @@ -1,4 +1,5 @@ -import RecordMap from './record-map'; +import InternalModelMap from './internal-model-map'; + /** `IdentityMap` is a custom storage map for records by modelName @@ -13,37 +14,37 @@ export default class IdentityMap { } /** - Retrieves the `RecordMap` for a given modelName, + Retrieves the `InternalModelMap` for a given modelName, creating one if one did not already exist. This is similar to `getWithDefault` or `get` on a `MapWithDefault` @method retrieve @param modelName a previously normalized modelName - @returns {RecordMap} the RecordMap for the given modelName + @returns {InternalModelMap} the InternalModelMap for the given modelName */ retrieve(modelName) { - let recordMap = this._map[modelName]; + let map = this._map[modelName]; - if (!recordMap) { - recordMap = this._map[modelName] = new RecordMap(modelName); + if (!map) { + map = this._map[modelName] = new InternalModelMap(modelName); } - return recordMap; + return map; } /** Clears the contents of all known `RecordMaps`, but does - not remove the RecordMap instances. + not remove the InternalModelMap instances. @method clear */ clear() { - let recordMaps = this._map; - let keys = Object.keys(recordMaps); + let map = this._map; + let keys = Object.keys(map); for (let i = 0; i < keys.length; i++) { let key = keys[i]; - recordMaps[key].clear(); + map[key].clear(); } } } diff --git a/addon/-private/system/record-map.js b/addon/-private/system/internal-model-map.js similarity index 54% rename from addon/-private/system/record-map.js rename to addon/-private/system/internal-model-map.js index d91756214e9..0ffc3e055a6 100644 --- a/addon/-private/system/record-map.js +++ b/addon/-private/system/internal-model-map.js @@ -2,20 +2,20 @@ import { assert, deprecate } from "ember-data/-private/debug"; import InternalModel from './model/internal-model'; /** - `RecordMap` is a custom storage map for records of a given modelName + `InternalModelMap` is a custom storage map for internalModels of a given modelName used by `IdentityMap`. - It was extracted from an implicit pojo based "record map" and preserves + It was extracted from an implicit pojo based "internalModel map" and preserves that interface while we work towards a more official API. - @class RecordMap + @class InternalModelMap @private */ -export default class RecordMap { +export default class InternalModelMap { constructor(modelName) { this.modelName = modelName; - this._idToRecord = Object.create(null); - this._records = []; + this._idToModel = Object.create(null); + this._models = []; this._metadata = null; } @@ -23,11 +23,11 @@ export default class RecordMap { A "map" of records based on their ID for this modelName */ get idToRecord() { - deprecate('Use of RecordMap.idToRecord is deprecated, use RecordMap.get(id) instead.', false, { + deprecate('Use of InternalModelMap.idToRecord is deprecated, use InternalModelMap.get(id) instead.', false, { id: 'ds.record-map.idToRecord', until: '2.13' }); - return this._idToRecord; + return this._idToModel; } /** @@ -36,62 +36,62 @@ export default class RecordMap { * @returns {InternalModel} */ get(id) { - let r = this._idToRecord[id]; + let r = this._idToModel[id]; return r; } has(id) { - return !!this._idToRecord[id]; + return !!this._idToModel[id]; } get length() { - return this._records.length; + return this._models.length; } set(id, internalModel) { assert(`You cannot index an internalModel by an empty id'`, id); assert(`You cannot set an index for an internalModel to something other than an internalModel`, internalModel instanceof InternalModel); - assert(`You cannot set an index for an internalModel that is not in the RecordMap`, this.contains(internalModel)); + assert(`You cannot set an index for an internalModel that is not in the InternalModelMap`, this.contains(internalModel)); assert(`You cannot update the id index of an InternalModel once set. Attempted to update ${id}.`, !this.has(id) || this.get(id) === internalModel); - this._idToRecord[id] = internalModel; + this._idToModel[id] = internalModel; } add(internalModel, id) { - assert(`You cannot re-add an already present InternalModel to the RecordMap.`, !this.contains(internalModel)); + assert(`You cannot re-add an already present InternalModel to the InternalModelMap.`, !this.contains(internalModel)); if (id) { - this._idToRecord[id] = internalModel; + this._idToModel[id] = internalModel; } - this._records.push(internalModel); + this._models.push(internalModel); } remove(internalModel, id) { if (id) { - delete this._idToRecord[id]; + delete this._idToModel[id]; } - let loc = this._records.indexOf(internalModel); + let loc = this._models.indexOf(internalModel); if (loc !== -1) { - this._records.splice(loc, 1); + this._models.splice(loc, 1); } } contains(internalModel) { - return this._records.indexOf(internalModel) !== -1; + return this._models.indexOf(internalModel) !== -1; } /** - An array of all records of this modelName + An array of all models of this modelName */ - get records() { - return this._records; + get models() { + return this._models; } /** - * meta information about records + * meta information about internalModels */ get metadata() { return this._metadata || (this._metadata = Object.create(null)); @@ -103,23 +103,22 @@ export default class RecordMap { @deprecated */ get type() { - throw new Error('RecordMap.type is no longer available'); + throw new Error('InternalModelMap.type is no longer available'); } /** - Destroy all records in the recordMap and wipe metadata. + Destroy all models in the internalModelTest and wipe metadata. @method clear */ clear() { - if (this._records) { - let records = this._records; - this._records = []; - let record; - - for (let i = 0; i < records.length; i++) { - record = records[i]; - record.unloadRecord(); + if (this._models) { + let models = this._models; + this._models = []; + + for (let i = 0; i < models.length; i++) { + let model = models[i]; + model.unloadRecord(); } } diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index a52868d0ac2..292d4b6ef2f 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -226,8 +226,8 @@ export default class RecordArrayManager { syncLiveRecordArray(array, modelName) { assert(`recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); let hasNoPotentialDeletions = this.changedRecords.length === 0; - let recordMap = this.store._recordMapFor(modelName); - let hasNoInsertionsOrRemovals = recordMap.length === array.length; + let map = this.store._internalModelsFor(modelName); + let hasNoInsertionsOrRemovals = map.length === array.length; /* Ideally the recordArrayManager has knowledge of the changes to be applied to @@ -245,15 +245,14 @@ export default class RecordArrayManager { populateLiveRecordArray(array, modelName) { assert(`recordArrayManger.populateLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); heimdall.increment(populateLiveRecordArray); - let recordMap = this.store._recordMapFor(modelName); - let records = recordMap.records; - let record; + let modelMap = this.store._internalModelsFor(modelName); + let internalModels = modelMap.models; - for (let i = 0; i < records.length; i++) { - record = records[i]; + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; - if (!record.isDeleted() && !record.isEmpty()) { - this._addInternalModelToRecordArray(array, record); + if (!internalModel.isDeleted() && !internalModel.isEmpty()) { + this._addInternalModelToRecordArray(array, internalModel); } } } @@ -273,15 +272,14 @@ export default class RecordArrayManager { updateFilter(array, modelName, filter) { assert(`recordArrayManger.updateFilter expects modelName not modelClass as the second param, received ${modelName}`, typeof modelName === 'string'); heimdall.increment(updateFilter); - let recordMap = this.store._recordMapFor(modelName); - let records = recordMap.records; - let record; + let modelMap = this.store._internalModelsFor(modelName); + let internalModels = modelMap.models; - for (let i = 0; i < records.length; i++) { - record = records[i]; + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; - if (!record.isDeleted() && !record.isEmpty()) { - this.updateFilterRecordArray(array, filter, modelName, record); + if (!internalModel.isDeleted() && !internalModel.isEmpty()) { + this.updateFilterRecordArray(array, filter, modelName, internalModel); } } } diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 1135f443ed8..f57a2f8f4ec 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -112,7 +112,7 @@ const { peekAll, peekRecord, serializerFor, - _recordMapFor + _internalModelsFor } = heimdall.registerMonitor('store', '_generateId', '_internalModelForId', @@ -129,7 +129,7 @@ const { 'peekAll', 'peekRecord', 'serializerFor', - '_recordMapFor' + '_internalModelsFor' ); /** @@ -1101,7 +1101,7 @@ Store = Service.extend({ let normalizedModelName = normalizeModelName(modelName); let trueId = coerceId(id); - let internalModel = this._recordMapFor(normalizedModelName).get(trueId); + let internalModel = this._internalModelsFor(normalizedModelName).get(trueId); return !!internalModel && internalModel.isLoaded(); }, @@ -1126,7 +1126,7 @@ Store = Service.extend({ _internalModelForId(modelName, id) { heimdall.increment(_internalModelForId); let trueId = coerceId(id); - let internalModel = this._recordMapFor(modelName).get(trueId); + let internalModel = this._internalModelsFor(modelName).get(trueId); if (!internalModel) { internalModel = this.buildInternalModel(modelName, trueId); @@ -1612,7 +1612,7 @@ Store = Service.extend({ */ _fetchAll(modelName, array, options = {}) { let adapter = this.adapterFor(modelName); - let sinceToken = this._recordMapFor(modelName).metadata.since; + let sinceToken = this._internalModelsFor(modelName).metadata.since; assert(`You tried to load all records but you have no adapter (for ${modelName})`, adapter); assert(`You tried to load all records but your adapter does not implement 'findAll'`, typeof adapter.findAll === 'function'); @@ -1710,7 +1710,7 @@ Store = Service.extend({ this._identityMap.clear(); } else { let normalizedModelName = normalizeModelName(modelName); - this._recordMapFor(normalizedModelName).clear(); + this._internalModelsFor(normalizedModelName).clear(); } }, @@ -1968,7 +1968,7 @@ Store = Service.extend({ return; } - this._recordMapFor(internalModel.modelName).set(id, internalModel); + this._internalModelsFor(internalModel.modelName).set(id, internalModel); internalModel.setId(id); }, @@ -1976,13 +1976,13 @@ Store = Service.extend({ /** Returns a map of IDs to client IDs for a given modelName. - @method _recordMapFor + @method _internalModelsFor @private @param {String} modelName @return {Object} recordMap */ - _recordMapFor(modelName) { - heimdall.increment(_recordMapFor); + _internalModelsFor(modelName) { + heimdall.increment(_internalModelsFor); return this._identityMap.retrieve(modelName); }, @@ -2538,7 +2538,7 @@ Store = Service.extend({ assert(`You can no longer pass a modelClass as the first argument to store.buildInternalModel. Pass modelName instead.`, typeof modelName === 'string'); - let recordMap = this._recordMapFor(modelName); + let recordMap = this._internalModelsFor(modelName); assert(`The id ${id} has already been used with another record for modelClass '${modelName}'.`, !id || !recordMap.get(id)); @@ -2569,7 +2569,7 @@ Store = Service.extend({ @param {InternalModel} internalModel */ _removeFromIdMap(internalModel) { - let recordMap = this._recordMapFor(internalModel.modelName); + let recordMap = this._internalModelsFor(internalModel.modelName); let id = internalModel.id; recordMap.remove(internalModel, id); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 33bbc8d5a7b..2bbe1374515 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -557,9 +557,9 @@ test("createRecord - response can contain relationships the client doesn't yet k run(function() { post.save().then(assert.wait(function(post) { assert.equal(post.get('comments.firstObject.post'), post, "the comments are related to the correct post model"); - assert.equal(store._recordMapFor('post').records.length, 1, "There should only be one post record in the store"); + assert.equal(store._internalModelsFor('post').models.length, 1, "There should only be one post record in the store"); - var postRecords = store._recordMapFor('post').records; + var postRecords = store._internalModelsFor('post').models; for (var i = 0; i < postRecords.length; i++) { assert.equal(post, postRecords[i].getRecord(), "The object in the identity map is the same"); } diff --git a/tests/integration/records/rematerialize-test.js b/tests/integration/records/rematerialize-test.js index 9780a60750a..c19c6d5063e 100644 --- a/tests/integration/records/rematerialize-test.js +++ b/tests/integration/records/rematerialize-test.js @@ -105,14 +105,14 @@ test("a sync belongs to relationship to an unloaded record can restore that reco assert.equal(person.get('cars.length'), 1, 'The inital length of cars is correct'); assert.equal(env.store.hasRecordForId('person', 1), true, 'The person is in the store'); - assert.equal(env.store._recordMapFor('person').has(1), true, 'The person internalModel is loaded'); + assert.equal(env.store._internalModelsFor('person').has(1), true, 'The person internalModel is loaded'); run(function() { person.unloadRecord(); }); assert.equal(env.store.hasRecordForId('person', 1), false, 'The person is unloaded'); - assert.equal(env.store._recordMapFor('person').has(1), true, 'The person internalModel is retained'); + assert.equal(env.store._internalModelsFor('person').has(1), true, 'The person internalModel is retained'); run(() => { env.store.push({ @@ -215,9 +215,9 @@ test("an async has many relationship to an unloaded record can restore that reco let boaty = env.store.peekRecord('boat', 1); assert.equal(env.store.hasRecordForId('person', 1), true, 'The person is in the store'); - assert.equal(env.store._recordMapFor('person').has(1), true, 'The person internalModel is loaded'); + assert.equal(env.store._internalModelsFor('person').has(1), true, 'The person internalModel is loaded'); assert.equal(env.store.hasRecordForId('boat', 1), true, 'The boat is in the store'); - assert.equal(env.store._recordMapFor('boat').has(1), true, 'The boat internalModel is loaded'); + assert.equal(env.store._internalModelsFor('boat').has(1), true, 'The boat internalModel is loaded'); let boats = run(() => { return adam.get('boats'); @@ -230,7 +230,7 @@ test("an async has many relationship to an unloaded record can restore that reco }); assert.equal(env.store.hasRecordForId('boat', 1), false, 'The boat is unloaded'); - assert.equal(env.store._recordMapFor('boat').has(1), true, 'The boat internalModel is retained'); + assert.equal(env.store._internalModelsFor('boat').has(1), true, 'The boat internalModel is retained'); let rematerializedBoaty = run(() => { return rematerializedBoaty = adam.get('boats').objectAt(1); @@ -241,5 +241,5 @@ test("an async has many relationship to an unloaded record can restore that reco assert.notEqual(rematerializedBoaty, boaty, 'the boat is rematerialized, not recycled'); assert.equal(env.store.hasRecordForId('boat', 1), true, 'The boat is loaded'); - assert.equal(env.store._recordMapFor('boat').has(1), true, 'The boat internalModel is retained'); + assert.equal(env.store._internalModelsFor('boat').has(1), true, 'The boat internalModel is retained'); }); diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 63e8e616055..e3559412e52 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -72,14 +72,14 @@ test("can unload a single record", function(assert) { }); assert.equal(env.store.peekAll('person').get('length'), 1, 'one person record loaded'); - assert.equal(env.store._recordMapFor('person').length, 1, 'one person internalModel loaded'); + assert.equal(env.store._internalModelsFor('person').length, 1, 'one person internalModel loaded'); Ember.run(function() { adam.unloadRecord(); }); assert.equal(env.store.peekAll('person').get('length'), 0, 'no person records'); - assert.equal(env.store._recordMapFor('person').length, 0, 'no person internalModels'); + assert.equal(env.store._internalModelsFor('person').length, 0, 'no person internalModels'); }); test("can unload all records for a given type", function(assert) { @@ -124,9 +124,9 @@ test("can unload all records for a given type", function(assert) { }); assert.equal(env.store.peekAll('person').get('length'), 2, 'two person records loaded'); - assert.equal(env.store._recordMapFor('person').length, 2, 'two person internalModels loaded'); + assert.equal(env.store._internalModelsFor('person').length, 2, 'two person internalModels loaded'); assert.equal(env.store.peekAll('car').get('length'), 1, 'one car record loaded'); - assert.equal(env.store._recordMapFor('car').length, 1, 'one car internalModel loaded'); + assert.equal(env.store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); Ember.run(function() { env.store.unloadAll('person'); @@ -134,8 +134,8 @@ test("can unload all records for a given type", function(assert) { assert.equal(env.store.peekAll('person').get('length'), 0); assert.equal(env.store.peekAll('car').get('length'), 1); - assert.equal(env.store._recordMapFor('person').length, 0, 'zero person internalModels loaded'); - assert.equal(env.store._recordMapFor('car').length, 1, 'one car internalModel loaded'); + assert.equal(env.store._internalModelsFor('person').length, 0, 'zero person internalModels loaded'); + assert.equal(env.store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); }); test("can unload all records", function(assert) { @@ -180,9 +180,9 @@ test("can unload all records", function(assert) { }); assert.equal(env.store.peekAll('person').get('length'), 2, 'two person records loaded'); - assert.equal(env.store._recordMapFor('person').length, 2, 'two person internalModels loaded'); + assert.equal(env.store._internalModelsFor('person').length, 2, 'two person internalModels loaded'); assert.equal(env.store.peekAll('car').get('length'), 1, 'one car record loaded'); - assert.equal(env.store._recordMapFor('car').length, 1, 'one car internalModel loaded'); + assert.equal(env.store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); Ember.run(function() { env.store.unloadAll(); @@ -190,8 +190,8 @@ test("can unload all records", function(assert) { assert.equal(env.store.peekAll('person').get('length'), 0); assert.equal(env.store.peekAll('car').get('length'), 0); - assert.equal(env.store._recordMapFor('person').length, 0, 'zero person internalModels loaded'); - assert.equal(env.store._recordMapFor('car').length, 0, 'zero car internalModels loaded'); + assert.equal(env.store._internalModelsFor('person').length, 0, 'zero person internalModels loaded'); + assert.equal(env.store._internalModelsFor('car').length, 0, 'zero car internalModels loaded'); }); test("removes findAllCache after unloading all records", function(assert) { @@ -219,7 +219,7 @@ test("removes findAllCache after unloading all records", function(assert) { }); assert.equal(env.store.peekAll('person').get('length'), 2, 'two person records loaded'); - assert.equal(env.store._recordMapFor('person').length, 2, 'two person internalModels loaded'); + assert.equal(env.store._internalModelsFor('person').length, 2, 'two person internalModels loaded'); Ember.run(function() { env.store.peekAll('person'); @@ -227,7 +227,7 @@ test("removes findAllCache after unloading all records", function(assert) { }); assert.equal(env.store.peekAll('person').get('length'), 0, 'zero person records loaded'); - assert.equal(env.store._recordMapFor('person').length, 0, 'zero person internalModels loaded'); + assert.equal(env.store._internalModelsFor('person').length, 0, 'zero person internalModels loaded'); }); test("unloading all records also updates record array from peekAll()", function(assert) { @@ -322,12 +322,12 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu }); assert.equal( - env.store._recordMapFor('person').records.length, + env.store._internalModelsFor('person').models.length, 1, 'one person record is loaded' ); assert.equal( - env.store._recordMapFor('car').records.length, + env.store._internalModelsFor('car').models.length, 2, 'two car records are loaded' ); @@ -362,8 +362,8 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu env.store.peekRecord('car', 2).unloadRecord(); }); - assert.equal(env.store._recordMapFor('person').records.length, 0); - assert.equal(env.store._recordMapFor('car').records.length, 0); + assert.equal(env.store._internalModelsFor('person').models.length, 0); + assert.equal(env.store._internalModelsFor('car').models.length, 0); assert.equal(checkOrphanCalls, 3, 'each internalModel checks for cleanup'); assert.equal(cleanupOrphanCalls, 1, 'cleanup only happens once'); From c53b8f87768e14abba39c15eb811fe0eb9713ee3 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Thu, 9 Mar 2017 16:28:47 -0800 Subject: [PATCH 1836/2527] Don't calculate `_changedKeys` pointlessly (#4851) If the internal model has no record, we won't do anything with the changes, so let's not waste cycles calculating them. --- addon/-private/system/model/internal-model.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 57553a38934..ea025758679 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -518,9 +518,15 @@ export default class InternalModel { setupData(data) { heimdall.increment(setupData); - let changedKeys = this._changedKeys(data.attributes); + let changedKeys; + + if (this.hasRecord) { + changedKeys = this._changedKeys(data.attributes); + } + assign(this._data, data.attributes); this.pushedData(); + if (this.hasRecord) { this.record._notifyProperties(changedKeys); } From 03440c14e14ab7923ae2ed7db8fbbec6d3fa89e6 Mon Sep 17 00:00:00 2001 From: Bryan Date: Fri, 10 Mar 2017 01:23:00 +0000 Subject: [PATCH 1837/2527] Optimise has many notifications (#4850) * optimise has-many notifications * bring in line with master * bring in line with master * exit flushCanonical early if not alive * add test for non contiguous change * niggles * jshint fix --- addon/-private/system/diff-array.js | 58 ++ addon/-private/system/many-array.js | 37 +- .../records/relationship-changes-test.js | 855 +++++++++++++++++- tests/unit/diff-array-test.js | 488 ++++++++++ 4 files changed, 1417 insertions(+), 21 deletions(-) create mode 100644 addon/-private/system/diff-array.js create mode 100644 tests/unit/diff-array-test.js diff --git a/addon/-private/system/diff-array.js b/addon/-private/system/diff-array.js new file mode 100644 index 00000000000..5c0c2fb8868 --- /dev/null +++ b/addon/-private/system/diff-array.js @@ -0,0 +1,58 @@ +/** + @namespace + @method diff-array + @for DS + @param {Array} oldArray the old array + @param {Array} newArray the new array + @return {hash} { + firstChangeIndex: , // null if no change + addedCount: , // 0 if no change + removedCount: // 0 if no change + } +*/ +export default function diffArray(oldArray, newArray) { + const oldLength = oldArray.length; + const newLength = newArray.length; + + const shortestLength = Math.min(oldLength, newLength); + let firstChangeIndex = null; // null signifies no changes + + // find the first change + for (let i=0; i internalModel.isNew() && toSet.indexOf(internalModel) === -1 ); toSet = toSet.concat(newRecords); - let oldLength = this.length; - this.arrayContentWillChange(0, this.length, toSet.length); - // It’s possible the parent side of the relationship may have been unloaded by this point - if (_objectIsAlive(this)) { - this.set('length', toSet.length); - } - this.currentState = toSet; - this.arrayContentDidChange(0, oldLength, this.length); - if (isInitialized) { - //TODO Figure out to notify only on additions and maybe only if unloaded - this.relationship.notifyHasManyChanged(); + // diff to find changes + let diff = diffArray(this.currentState, toSet); + + if (diff.firstChangeIndex !== null) { // it's null if no change found + // we found a change + this.arrayContentWillChange(diff.firstChangeIndex, diff.removedCount, diff.addedCount); + this.set('length', toSet.length); + this.currentState = toSet; + this.arrayContentDidChange(diff.firstChangeIndex, diff.removedCount, diff.addedCount); + if (isInitialized && diff.addedCount > 0) { + //notify only on additions + //TODO only notify if unloaded + this.relationship.notifyHasManyChanged(); + } } }, @@ -289,12 +297,11 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { @return {DS.Model} record */ createRecord(hash) { - let store = get(this, 'store'); - let type = get(this, 'type'); - let record; + const store = get(this, 'store'); + const type = get(this, 'type'); assert(`You cannot add '${type.modelName}' records to this polymorphic relationship.`, !get(this, 'isPolymorphic')); - record = store.createRecord(type.modelName, hash); + let record = store.createRecord(type.modelName, hash); this.pushObject(record); return record; diff --git a/tests/integration/records/relationship-changes-test.js b/tests/integration/records/relationship-changes-test.js index b798556bf84..54fc3486573 100644 --- a/tests/integration/records/relationship-changes-test.js +++ b/tests/integration/records/relationship-changes-test.js @@ -1,10 +1,13 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; + import DS from 'ember-data'; import { module, test } from 'qunit'; -const { run } = Ember; -const { attr, belongsTo, Model } = DS; +const { run, get, set, computed } = Ember; +const { attr, belongsTo, hasMany, Model } = DS; + +let env, store; const Author = Model.extend({ name: attr('string') @@ -14,29 +17,869 @@ const Post = Model.extend({ author: belongsTo() }); -let env; +const Person = DS.Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + siblings: hasMany('person') +}); + +const sibling1 = { + type: 'person', + id: '1', + attributes: { + firstName: 'Dogzn', + lastName: 'Katz' + } +}; + +const sibling1Ref = { + type: 'person', + id: '1' +}; + +const sibling2 = { + type: 'person', + id: '2', + attributes: { + firstName: 'Katzn', + lastName: 'Dogz' + } +}; + +const sibling2Ref = { + type: 'person', + id: '2' +}; + +const sibling3 = { + type: 'person', + id: '3', + attributes: { + firstName: 'Snakezn', + lastName: 'Ladderz' + } +}; + +const sibling3Ref = { + type: 'person', + id: '3' +}; + +const sibling4 = { + type: 'person', + id: '4', + attributes: { + firstName: 'Hamsterzn', + lastName: 'Gerbilz' + } +}; + +const sibling4Ref = { + type: 'person', + id: '4' +}; + +const sibling5 = { + type: 'person', + id: '5', + attributes: { + firstName: 'Donkeyzn', + lastName: 'Llamaz' + } +}; + +const sibling5Ref = { + type: 'person', + id: '5' +}; module('integration/records/relationship-changes - Relationship changes', { beforeEach() { env = setupStore({ + person: Person, author: Author, post: Post }); + store = env.store; }, afterEach() { - run(function() { + run(() => { env.container.destroy(); }); } }); +test('Calling push with relationship triggers observers once if the relationship was empty and is added to', function(assert) { + assert.expect(1); + let person = null; + let observerCount = 0; + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [] + } + } + } + }); + person = store.peekRecord('person', 'wat'); + }); + + run(() => { + person.addObserver('siblings.[]', function() { + observerCount++; + }); + // prime the pump + person.get('siblings'); + }); + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + }, + relationships: { + siblings: { + data: [sibling1Ref] + } + } + }, + included: [ + sibling1 + ] + }); + }); + + run(() => { + assert.ok(observerCount >= 1, 'siblings observer should be triggered at least once'); + }); +}); + +test('Calling push with relationship recalculates computed alias property if the relationship was empty and is added to', function(assert) { + assert.expect(1); + + let Obj = Ember.Object.extend({ + person: null, + siblings: computed.alias('person.siblings') + }); + + const obj = Obj.create(); + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [] + } + } + } + }); + set(obj, 'person', store.peekRecord('person', 'wat')); + }); + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + }, + relationships: { + siblings: { + data: [sibling1Ref] + } + } + }, + included: [ + sibling1 + ] + }); + }); + + run(() => { + let cpResult = get(obj, 'siblings').toArray(); + assert.equal(cpResult.length, 1, 'siblings cp should have recalculated'); + obj.destroy(); + }); +}); + +test('Calling push with relationship recalculates computed alias property to firstObject if the relationship was empty and is added to', function(assert) { + assert.expect(1); + + let Obj = Ember.Object.extend({ + person: null, + firstSibling: computed.alias('person.siblings.firstObject') + }); + + const obj = Obj.create(); + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [] + } + } + } + }); + set(obj, 'person', store.peekRecord('person', 'wat')); + }); + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + }, + relationships: { + siblings: { + data: [sibling1Ref] + } + } + }, + included: [ + sibling1 + ] + }); + }); + + run(() => { + let cpResult = get(obj, 'firstSibling'); + assert.equal(get(cpResult, 'id'), 1, 'siblings cp should have recalculated'); + obj.destroy(); + }); +}); + +test('Calling push with relationship triggers observers once if the relationship was not empty and was added to', function(assert) { + assert.expect(1); + let person = null; + let observerCount = 0; + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [sibling1Ref] + } + } + }, + included: [ + sibling1 + ] + }); + person = store.peekRecord('person', 'wat'); + }); + + run(() => { + person.addObserver('siblings.[]', function() { + observerCount++; + }); + // prime the pump + person.get('siblings'); + }); + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + }, + relationships: { + siblings: { + data: [sibling1Ref, sibling2Ref] + } + } + }, + included: [ + sibling2 + ] + }); + }); + + run(() => { + assert.ok(observerCount >= 1, 'siblings observer should be triggered at least once'); + }); +}); + +test('Calling push with relationship triggers observers once if the relationship was made shorter', function(assert) { + assert.expect(1); + let person = null; + let observerCount = 0; + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [sibling1Ref] + } + } + }, + included: [ + sibling1 + ] + }); + person = store.peekRecord('person', 'wat'); + }); + + run(() => { + person.addObserver('siblings.[]', function() { + observerCount++; + }); + // prime the pump + person.get('siblings'); + }); + + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + }, + relationships: { + siblings: { + data: [] + } + } + }, + included: [] + }); + }); + + run(() => { + assert.ok(observerCount >= 1, 'siblings observer should be triggered at least once'); + }); +}); + +test('Calling push with relationship triggers observers once if the relationship was reordered', function(assert) { + assert.expect(1); + let person = null; + let observerCount = 0; + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [sibling1Ref, sibling2Ref] + } + } + }, + included: [ + sibling1, + sibling2 + ] + + }); + person = store.peekRecord('person', 'wat'); + }); + + run(() => { + person.addObserver('siblings.[]', function() { + observerCount++; + }); + // prime the pump + person.get('siblings'); + }); + + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + }, + relationships: { + siblings: { + data: [sibling2Ref, sibling1Ref] + } + } + }, + included: [] + }); + }); + + run(() => { + assert.ok(observerCount >= 1, 'siblings observer should be triggered at least once'); + }); +}); + +test('Calling push with relationship does not trigger observers if the relationship was not changed', function(assert) { + assert.expect(1); + let person = null; + let observerCount = 0; + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [sibling1Ref] + } + } + }, + included: [ + sibling1 + ] + + }); + person = store.peekRecord('person', 'wat'); + }); + + run(() => { + // prime the pump + person.get('siblings'); + person.addObserver('siblings.[]', function() { + observerCount++; + }); + }); + + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + }, + relationships: { + siblings: { + data: [sibling1Ref] + } + } + }, + included: [] + }); + }); + + run(() => { + assert.equal(observerCount, 0, 'siblings observer should not be triggered'); + }); +}); + +test('Calling push with relationship triggers willChange and didChange with detail when appending', function(assert) { + let person = null; + let willChangeCount = 0; + let didChangeCount = 0; + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [sibling1Ref] + } + } + }, + included: [ + sibling1 + ] + + }); + person = store.peekRecord('person', 'wat'); + + this.arrayWillChange = (array, start, removing, adding) => { + willChangeCount++; + assert.equal(start, 1); + assert.equal(removing, 0); + assert.equal(adding, 1); + }; + this.arrayDidChange = (array, start, removed, added) => { + didChangeCount++; + assert.equal(start, 1); + assert.equal(removed, 0); + assert.equal(added, 1); + }; + + person.get('siblings') + .then(siblings => { + siblings.addArrayObserver(this); + }); + }); + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + }, + relationships: { + siblings: { + data: [sibling1Ref, sibling2Ref] + } + } + }, + included: [ + sibling2 + ] + }); + }); + + run(() => { + assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); + assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); + }); +}); + +test('Calling push with relationship triggers willChange and didChange with detail when truncating', function(assert) { + let person = null; + let willChangeCount = 0; + let didChangeCount = 0; + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [sibling1Ref, sibling2Ref] + } + } + }, + included: [ + sibling1, sibling2 + ] + + }); + person = store.peekRecord('person', 'wat'); + + this.arrayWillChange = (array, start, removing, adding) => { + willChangeCount++; + assert.equal(start, 1); + assert.equal(removing, 1); + assert.equal(adding, 0); + }; + this.arrayDidChange = (array, start, removed, added) => { + didChangeCount++; + assert.equal(start, 1); + assert.equal(removed, 1); + assert.equal(added, 0); + }; + + person.get('siblings') + .then(siblings => { + siblings.addArrayObserver(this); + }); + + }); + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + }, + relationships: { + siblings: { + data: [sibling1Ref] + } + } + }, + included: [] + }); + }); + + run(() => { + assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); + assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); + }); +}); + +test('Calling push with relationship triggers willChange and didChange with detail when inserting at front', function(assert) { + let person = null; + let willChangeCount = 0; + let didChangeCount = 0; + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [sibling2Ref] + } + } + }, + included: [ + sibling2 + ] + + }); + person = store.peekRecord('person', 'wat'); + + this.arrayWillChange = (array, start, removing, adding) => { + willChangeCount++; + assert.equal(start, 0); + assert.equal(removing, 0); + assert.equal(adding, 1); + }; + this.arrayDidChange = (array, start, removed, added) => { + didChangeCount++; + assert.equal(start, 0); + assert.equal(removed, 0); + assert.equal(added, 1); + }; + + person.get('siblings') + .then(siblings => { + siblings.addArrayObserver(this); + }); + + }); + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + }, + relationships: { + siblings: { + data: [sibling1Ref, sibling2Ref] + } + } + }, + included: [ + sibling2 + ] + }); + }); + + run(() => { + assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); + assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); + }); +}); + +test('Calling push with relationship triggers willChange and didChange with detail when inserting in middle', function(assert) { + let person = null; + let willChangeCount = 0; + let didChangeCount = 0; + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [sibling1Ref, sibling3Ref] + } + } + }, + included: [ + sibling1, + sibling3 + ] + + }); + person = store.peekRecord('person', 'wat'); + + this.arrayWillChange = (array, start, removing, adding) => { + willChangeCount++; + assert.equal(start, 1); + assert.equal(removing, 0); + assert.equal(adding, 1); + }; + this.arrayDidChange = (array, start, removed, added) => { + didChangeCount++; + assert.equal(start, 1); + assert.equal(removed, 0); + assert.equal(added, 1); + }; + + person.get('siblings') + .then(siblings => { + siblings.addArrayObserver(this); + }); + + }); + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + }, + relationships: { + siblings: { + data: [sibling1Ref, sibling2Ref, sibling3Ref] + } + } + }, + included: [ + sibling2 + ] + }); + }); + + run(() => { + assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); + assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); + }); +}); + +test('Calling push with relationship triggers willChange and didChange with detail when replacing different length in middle', function(assert) { + let person = null; + let willChangeCount = 0; + let didChangeCount = 0; + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [sibling1Ref, sibling2Ref, sibling3Ref] + } + } + }, + included: [ + sibling1, + sibling2, + sibling3 + ] + + }); + person = store.peekRecord('person', 'wat'); + + this.arrayWillChange = (array, start, removing, adding) => { + willChangeCount++; + assert.equal(start, 1); + assert.equal(removing, 1); + assert.equal(adding, 2); + }; + + this.arrayDidChange = (array, start, removed, added) => { + didChangeCount++; + assert.equal(start, 1); + assert.equal(removed, 1); + assert.equal(added, 2); + }; + + person.get('siblings') + .then(siblings => { + siblings.addArrayObserver(this); + }); + + }); + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + }, + relationships: { + siblings: { + data: [sibling1Ref, sibling4Ref, sibling5Ref, sibling3Ref] + } + } + }, + included: [ + sibling4, + sibling5 + ] + }); + }); + + run(() => { + assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); + assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); + }); +}); + test('Calling push with updated belongsTo relationship trigger observer', function(assert) { assert.expect(1); let observerCount = 0; - run(function() { + run(() => { let post = env.store.push({ data: { type: 'post', @@ -74,7 +917,7 @@ test('Calling push with same belongsTo relationship does not trigger observer', let observerCount = 0; - run(function() { + run(() => { let post = env.store.push({ data: { type: 'post', diff --git a/tests/unit/diff-array-test.js b/tests/unit/diff-array-test.js new file mode 100644 index 00000000000..893bfe469c6 --- /dev/null +++ b/tests/unit/diff-array-test.js @@ -0,0 +1,488 @@ +import {module, test} from 'qunit'; + +import diffArray from 'ember-data/-private/system/diff-array'; + +module('unit/diff-array Diff Array tests', { +}); + +const a = "aaa"; +const b = "bbb"; +const c = "ccc"; +const d = "ddd"; +const e = "eee"; +const f = "fff"; +const g = "ggg"; +const h = "hhh"; +const w = "www"; +const x = "xxx"; +const y = "yyy"; +const z = "zzz"; + +test('diff array returns no change given two empty arrays', function(assert) { + const result = diffArray([], []); + assert.equal(result.firstChangeIndex, null); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 0); +}); + +test('diff array returns no change given two identical arrays length 1', function(assert) { + const result = diffArray([a], [a]); + assert.equal(result.firstChangeIndex, null); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 0); +}); + +test('diff array returns no change given two identical arrays length 3', function(assert) { + const result = diffArray([a,b,c], [a,b,c]); + assert.equal(result.firstChangeIndex, null); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 0); +}); + +test('diff array returns correctly given one appended item with old length 0', function(assert) { + const result = diffArray([], [a]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 0); +}); + +test('diff array returns correctly given one appended item with old length 1', function(assert) { + const result = diffArray([a], [a,b]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 0); +}); + +test('diff array returns correctly given one appended item with old length 2', function(assert) { + const result = diffArray([a,b], [a,b,c]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 0); +}); + +test('diff array returns correctly given 3 appended items with old length 0', function(assert) { + const result = diffArray([], [a,b,c]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 0); +}); + +test('diff array returns correctly given 3 appended items with old length 1', function(assert) { + const result = diffArray([a], [a,b,c,d]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 0); +}); + +test('diff array returns correctly given 3 appended items with old length 2', function(assert) { + const result = diffArray([a,b], [a,b,c,d,e]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 0); +}); + +test('diff array returns correctly given one item removed from end with old length 1', function(assert) { + const result = diffArray([a], []); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given one item removed from end with old length 2', function(assert) { + const result = diffArray([a,b], [a]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given one item removed from end with old length 3', function(assert) { + const result = diffArray([a,b,c], [a,b]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given 3 items removed from end with old length 3', function(assert) { + const result = diffArray([a,b,c], []); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given 3 items removed from end with old length 4', function(assert) { + const result = diffArray([a,b,c,d], [a]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given 3 items removed from end with old length 5', function(assert) { + const result = diffArray([a,b,c,d,e], [a,b]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given one item removed from beginning with old length 2', function(assert) { + const result = diffArray([a,b], [b]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given one item removed from beginning with old length 3', function(assert) { + const result = diffArray([a,b,c], [b,c]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given 3 items removed from beginning with old length 4', function(assert) { + const result = diffArray([a,b,c,d], [d]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given 3 items removed from beginning with old length 5', function(assert) { + const result = diffArray([a,b,c,d,e], [d,e]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given one item removed from middle with old length 3', function(assert) { + const result = diffArray([a,b,c], [a,c]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given one item removed from middle with old length 5', function(assert) { + const result = diffArray([a,b,c,d,e], [a,b,d,e]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given 3 items removed from middle with old length 5', function(assert) { + const result = diffArray([a,b,c,d,e], [a,e]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given 3 items removed from middle with old length 7', function(assert) { + const result = diffArray([a,b,c,d,e,f,g], [a,b,f,g]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 0); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given one item added to middle with old length 2', function(assert) { + const result = diffArray([a,c], [a,b,c]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 0); +}); + +test('diff array returns correctly given one item added to middle with old length 4', function(assert) { + const result = diffArray([a,b,d,e], [a,b,c,d,e]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 0); +}); + +test('diff array returns correctly given 3 items added to middle with old length 2', function(assert) { + const result = diffArray([a,e], [a,b,c,d,e]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 0); +}); + +test('diff array returns correctly given 3 items added to middle with old length 4', function(assert) { + const result = diffArray([a,b,f,g], [a,b,c,d,e,f,g]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 0); +}); + +test('diff array returns correctly given complete replacement with length 1', function(assert) { + const result = diffArray([a], [b]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given complete replacement with length 3', function(assert) { + const result = diffArray([a,b,c], [x,y,z]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given complete replacement with longer length', function(assert) { + const result = diffArray([a,b], [x,y,z]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 2); +}); + +test('diff array returns correctly given one item replaced in middle with old length 3', function(assert) { + const result = diffArray([a,b,c], [a,x,c]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given one item replaced in middle with old length 5', function(assert) { + const result = diffArray([a,b,c,d,e], [a,b,x,d,e]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given 3 items replaced in middle with old length 5', function(assert) { + const result = diffArray([a,b,c,d,e], [a,x,y,z,e]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given 3 items replaced in middle with old length 7', function(assert) { + const result = diffArray([a,b,c,d,e,f,g], [a,b,x,y,z,f,g]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given one item replaced at beginning with old length 2', function(assert) { + const result = diffArray([a,b], [x,b]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given one item replaced at beginning with old length 3', function(assert) { + const result = diffArray([a,b,c], [x,b,c]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given 3 items replaced at beginning with old length 4', function(assert) { + const result = diffArray([a,b,c,d], [x,y,z,d]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given 3 items replaced at beginning with old length 6', function(assert) { + const result = diffArray([a,b,c,d,e,f], [x,y,z,d,e,f]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given one item replaced at end with old length 2', function(assert) { + const result = diffArray([a,b], [a,x]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given one item replaced at end with old length 3', function(assert) { + const result = diffArray([a,b,c], [a,b,x]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given 3 items replaced at end with old length 4', function(assert) { + const result = diffArray([a,b,c,d], [a,x,y,z]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given 3 items replaced at end with old length 6', function(assert) { + const result = diffArray([a,b,c,d,e,f], [a,b,c,x,y,z]); + assert.equal(result.firstChangeIndex, 3); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given one item replaced with two in middle with old length 3', function(assert) { + const result = diffArray([a,b,c], [a,x,y,c]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 2); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given one item replaced with two in middle with old length 5', function(assert) { + const result = diffArray([a,b,c,d,e], [a,b,x,y,d,e]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 2); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given 3 items replaced with 4 in middle with old length 5', function(assert) { + const result = diffArray([a,b,c,d,e], [a,w,x,y,z,e]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 4); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given 3 items replaced with 4 in middle with old length 7', function(assert) { + const result = diffArray([a,b,c,d,e,f,g], [a,b,w,x,y,z,f,g]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 4); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given one item replaced with two at beginning with old length 2', function(assert) { + const result = diffArray([a,b], [x,y,b]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 2); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given one item replaced with two at beginning with old length 3', function(assert) { + const result = diffArray([a,b,c], [x,y,b,c]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 2); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given 3 items replaced with 4 at beginning with old length 4', function(assert) { + const result = diffArray([a,b,c,d], [w,x,y,z,d]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 4); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given 3 items replaced with 4 at beginning with old length 6', function(assert) { + const result = diffArray([a,b,c,d,e,f], [w,x,y,z,d,e,f]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 4); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given one item replaced with two at end with old length 2', function(assert) { + const result = diffArray([a,b], [a,x,y]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 2); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given one item replaced with two at end with old length 3', function(assert) { + const result = diffArray([a,b,c], [a,b,x,y]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 2); + assert.equal(result.removedCount, 1); +}); + +test('diff array returns correctly given 3 items replaced with 4 at end with old length 4', function(assert) { + const result = diffArray([a,b,c,d], [a,w,x,y,z]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 4); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given 3 items replaced with 4 at end with old length 6', function(assert) { + const result = diffArray([a,b,c,d,e,f], [a,b,c,w,x,y,z]); + assert.equal(result.firstChangeIndex, 3); + assert.equal(result.addedCount, 4); + assert.equal(result.removedCount, 3); +}); + +test('diff array returns correctly given two items replaced with one in middle with old length 4', function(assert) { + const result = diffArray([a,b,c,d], [a,x,d]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 2); +}); + +test('diff array returns correctly given two items replaced with one in middle with old length 6', function(assert) { + const result = diffArray([a,b,c,d,e,f], [a,b,x,e,f]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 2); +}); + +test('diff array returns correctly given 4 items replaced with 3 in middle with old length 6', function(assert) { + const result = diffArray([a,b,c,d,e,f], [a,x,y,z,f]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 4); +}); + +test('diff array returns correctly given 4 items replaced with 3 in middle with old length 8', function(assert) { + const result = diffArray([a,b,c,d,e,f,g,h], [a,b,x,y,z,g,h]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 4); +}); + +test('diff array returns correctly given two items replaced with one at beginning with old length 3', function(assert) { + const result = diffArray([a,b,c], [x,c]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 2); +}); + +test('diff array returns correctly given two items replaced with one at beginning with old length 4', function(assert) { + const result = diffArray([a,b,c,d], [x,c,d]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 2); +}); + +test('diff array returns correctly given 4 items replaced with 3 at beginning with old length 5', function(assert) { + const result = diffArray([a,b,c,d,e], [x,y,z,e]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 4); +}); + +test('diff array returns correctly given 4 items replaced with 3 at beginning with old length 6', function(assert) { + const result = diffArray([a,b,c,d,e,f], [x,y,z,e,f]); + assert.equal(result.firstChangeIndex, 0); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 4); +}); + +test('diff array returns correctly given two items replaced with one at end with old length 3', function(assert) { + const result = diffArray([a,b,c], [a,x]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 2); +}); + +test('diff array returns correctly given two items replaced with one at end with old length 4', function(assert) { + const result = diffArray([a,b,c,d], [a,b,x]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 1); + assert.equal(result.removedCount, 2); +}); + +test('diff array returns correctly given 4 items replaced with 3 at end with old length 5', function(assert) { + const result = diffArray([a,b,c,d,e], [a,x,y,z]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 4); +}); + +test('diff array returns correctly given 4 items replaced with 3 at end with old length 6', function(assert) { + const result = diffArray([a,b,c,d,e,f], [a,b,x,y,z]); + assert.equal(result.firstChangeIndex, 2); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 4); +}); + +test('diff array returns correctly given non-contiguous insertion', function(assert) { + const result = diffArray([a,c,e], [a,b,c,d,e]); + assert.equal(result.firstChangeIndex, 1); + assert.equal(result.addedCount, 3); + assert.equal(result.removedCount, 1); +}); From c7a37e9ac3d8bfc3d497a4974324dabab8302717 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 13 Mar 2017 09:25:23 -0400 Subject: [PATCH 1838/2527] Update the changelog for the Ember Data 2.12.0 release --- CHANGELOG.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82ccda8a940..0e6d614041f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,40 @@ ### Master +### Release 2.12.0 (March 13, 2017) +- [#4805](https://github.com/emberjs/data/pull/4805) Don’t redefine findPossibleInverses for each _findInverseFor +- [#4808](https://github.com/emberjs/data/pull/4808) Avoid mutating model factory in _modelForMixin. +- [#4810](https://github.com/emberjs/data/pull/4810) [Fixes #4807] realize class + factory seperation +- [#4743](https://github.com/emberjs/data/pull/4743) [BUGFIX canary] Fix _lookupFactory deprecation for Ember canary +- [#4765](https://github.com/emberjs/data/pull/4765) [DOC] Make model.unloadRecord public (#4765) +- [#4792](https://github.com/emberjs/data/pull/4792) [BUGFIX beta] revert deletion of filter that removed deleted model… +- [#4789](https://github.com/emberjs/data/pull/4789) Do not access container if Ember.getOwner exists. +- [#4760](https://github.com/emberjs/data/pull/4760) Update deprecate arguments (#4760) +- [#4698](https://github.com/emberjs/data/pull/4698) [FIX backburner] Avoids spinning up unnecessary run loops via run.join +- [#4638](https://github.com/emberjs/data/pull/4638) Update the API docs for snapshots +- [#4705](https://github.com/emberjs/data/pull/4705) Underscores the already private store.reloadRecord method +- [#4663](https://github.com/emberjs/data/pull/4663) Silence warnings and deprecations in the console during tests +- [#4642](https://github.com/emberjs/data/pull/4642) Add API docs for the HasManyReference +- [#4706](https://github.com/emberjs/data/pull/4706) Improved performance for findHasMany finder +- [#4684](https://github.com/emberjs/data/pull/4684) Modernizes relationship containers +- [#4664](https://github.com/emberjs/data/pull/4664) Upgraded IdentityMap and RecordMap +- [#4668](https://github.com/emberjs/data/pull/4668) [PERF] use micro-queue +- [#4699](https://github.com/emberjs/data/pull/4699) include related record on the complex test +- [#4688](https://github.com/emberjs/data/pull/4688) Fixed a typo +- [#4685](https://github.com/emberjs/data/pull/4685) [FEATURE ds-rollback-attribute] rename ds-reset-attribute +- [#4686](https://github.com/emberjs/data/pull/4686) [FEATURE ds-improved-ajax] Disable feature +- [#4704](https://github.com/emberjs/data/pull/4704) Factory cache +- [#4696](https://github.com/emberjs/data/pull/4696) fix(benchmarks): benchmarks for store.query no longer included record… +- [#4691](https://github.com/emberjs/data/pull/4691) [BUGFIX beta] Add blueprints for "ember-cli-mocha >= 0.12.0" +- [#4697](https://github.com/emberjs/data/pull/4697) chore(benchmarks): benchmarks needed to time a few lookups for us to … +- [#4701](https://github.com/emberjs/data/pull/4701) [PERF] flatten DS.Model to avoid multi-extend, expensive reopens, and extra mixin detection +- [#4702](https://github.com/emberjs/data/pull/4702) Enable the ds-check-should-serialize-relationships feature flag +- [#4703](https://github.com/emberjs/data/pull/4703) Removes store._adapterRun +- [#4716](https://github.com/emberjs/data/pull/4716) [DOC canary] Updating CONTRIBUTING.md to use ember-twiddle as examples +- [#4718](https://github.com/emberjs/data/pull/4718) [BUGFIX beta] Inverse null relationships should throw if model doesn't exist 3 +- [#4734](https://github.com/emberjs/data/pull/4734) [DOC] fix a couple of typos in model class docs +- [#4739](https://github.com/emberjs/data/pull/4739) Removed id in urlForFindAll signature + ### Release 2.11.0 (January 9, 2016) - [#4518](https://github.com/emberjs/data/pull/4518) Update the relationship docs to remove some references to a globals s… - [#4581](https://github.com/emberjs/data/pull/4581) [DOC] Update descriptions of findRecord() and findAll() From 069fef113221f1b7d20c7e45d9079a7208fb8667 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 13 Mar 2017 10:13:02 -0400 Subject: [PATCH 1839/2527] Bump version to 2.14.0-canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 490a9870a37..aa1b3625051 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.13.0-canary", + "version": "2.14.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From 7715a63e3d44bee24ce00f6444d04b0a83d93d03 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 13 Mar 2017 22:32:08 -0700 Subject: [PATCH 1840/2527] [PERF] let GUID_KEYS just be set on the model instances (#4858) --- addon/-private/system/model/model.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 73335d61734..6f4f125fce7 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -85,6 +85,9 @@ const retrieveFromCurrentState = computed('currentState', function(key) { const Model = Ember.Object.extend(Ember.Evented, { _internalModel: null, store: null, + __defineNonEnumerable(property) { + this[property.name] = property.descriptor.value; + }, /** If this property is `true` the record is in the `empty` From 09bd826da705f84f1e28b1674cd9e2e4684aff6a Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 13 Mar 2017 22:41:31 -0700 Subject: [PATCH 1841/2527] [Fixes #4853] use Object.create(null) directly (#4854) --- addon/-private/system/clone-null.js | 3 +- addon/-private/system/model/internal-model.js | 33 +++++++++---------- addon/-private/system/model/model.js | 3 +- .../system/relationships/state/create.js | 3 +- addon/-private/system/snapshot.js | 13 ++++---- addon/-private/system/store.js | 9 +++-- .../system/store/container-instance-cache.js | 5 ++- .../-private/utils/parse-response-headers.js | 4 +-- .../unit/utils/parse-response-headers-test.js | 3 +- 9 files changed, 33 insertions(+), 43 deletions(-) diff --git a/addon/-private/system/clone-null.js b/addon/-private/system/clone-null.js index 97210f5353c..9972c430fef 100644 --- a/addon/-private/system/clone-null.js +++ b/addon/-private/system/clone-null.js @@ -1,6 +1,5 @@ -import EmptyObject from "./empty-object"; export default function cloneNull(source) { - let clone = new EmptyObject(); + let clone = Object.create(null); for (let key in source) { clone[key] = source[key]; } diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index ea025758679..6d101ac1365 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -3,7 +3,6 @@ import { assert, runInDebug } from "ember-data/-private/debug"; import RootState from "./states"; import Relationships from "../relationships/state/create"; import Snapshot from "../snapshot"; -import EmptyObject from "../empty-object"; import isEnabled from '../../features'; import OrderedSet from "../ordered-set"; @@ -42,10 +41,10 @@ const assign = Ember.assign || Ember.merge; and setups. It may also be faster to do a two level cache (from: { to }) instead of caching based on a key that adds the two together. */ -const TransitionChainMap = new EmptyObject(); +const TransitionChainMap = Object.create(null); -const _extractPivotNameCache = new EmptyObject(); -const _splitOnDotCache = new EmptyObject(); +const _extractPivotNameCache = Object.create(null); +const _splitOnDotCache = Object.create(null); function splitOnDot(name) { return _splitOnDotCache[name] || ( @@ -180,7 +179,7 @@ export default class InternalModel { get references() { if (this._references === null) { - this._references = new EmptyObject(); + this._references = Object.create(null); } return this._references; } @@ -194,7 +193,7 @@ export default class InternalModel { get _attributes() { if (this.__attributes === null) { - this.__attributes = new EmptyObject(); + this.__attributes = Object.create(null); } return this.__attributes; } @@ -213,7 +212,7 @@ export default class InternalModel { get _inFlightAttributes() { if (this.__inFlightAttributes === null) { - this.__inFlightAttributes = new EmptyObject(); + this.__inFlightAttributes = Object.create(null); } return this.__inFlightAttributes; } @@ -224,7 +223,7 @@ export default class InternalModel { get _data() { if (this.__data === null) { - this.__data = new EmptyObject(); + this.__data = Object.create(null); } return this.__data; } @@ -262,7 +261,7 @@ export default class InternalModel { */ get _implicitRelationships() { if (this.__implicitRelationships === null) { - this.__implicitRelationships = new EmptyObject(); + this.__implicitRelationships = Object.create(null); } return this.__implicitRelationships; } @@ -598,7 +597,7 @@ export default class InternalModel { flushChangedAttributes() { heimdall.increment(flushChangedAttributes); this._inFlightAttributes = this._attributes; - this._attributes = new EmptyObject(); + this._attributes = Object.create(null); } hasChangedAttributes() { @@ -647,7 +646,7 @@ export default class InternalModel { let currentData = this._attributes; let inFlightData = this._inFlightAttributes; let newData = assign(copy(inFlightData), currentData); - let diffData = new EmptyObject(); + let diffData = Object.create(null); let newDataKeys = Object.keys(newData); for (let i = 0, length = newDataKeys.length; i < length; i++) { @@ -719,10 +718,10 @@ export default class InternalModel { rollbackAttributes() { let dirtyKeys = Object.keys(this._attributes); - this._attributes = new EmptyObject(); + this._attributes = Object.create(null); if (get(this, 'isError')) { - this._inFlightAttributes = new EmptyObject(); + this._inFlightAttributes = Object.create(null); this.didCleanError(); } @@ -739,7 +738,7 @@ export default class InternalModel { } if (this.isValid()) { - this._inFlightAttributes = new EmptyObject(); + this._inFlightAttributes = Object.create(null); } this.send('rolledBack'); @@ -1005,7 +1004,7 @@ export default class InternalModel { assign(this._data, data); } - this._inFlightAttributes = new EmptyObject(); + this._inFlightAttributes = Object.create(null); this.send('didCommit'); this.updateRecordArrays(); @@ -1071,7 +1070,7 @@ export default class InternalModel { attrs[keys[i]] = this._inFlightAttributes[keys[i]]; } } - this._inFlightAttributes = new EmptyObject(); + this._inFlightAttributes = Object.create(null); } /* @@ -1124,7 +1123,7 @@ export default class InternalModel { let length = keys.length; let attrs = this._attributes; - original = assign(new EmptyObject(), this._data); + original = assign(Object.create(null), this._data); original = assign(original, this._inFlightAttributes); for (i = 0; i < length; i++) { diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 6f4f125fce7..e947ac94f53 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -4,7 +4,6 @@ import { PromiseObject } from "../promise-proxies"; import Errors from "../model/errors"; import isEnabled from '../../features'; import RootState from '../model/states'; -import EmptyObject from "../empty-object"; import { relationshipsByNameDescriptor, relatedTypesDescriptor, @@ -1275,7 +1274,7 @@ Model.reopenClass({ }, inverseMap: Ember.computed(function() { - return new EmptyObject(); + return Object.create(null); }), /** diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index 1e7756b0329..f97bcb72776 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -1,7 +1,6 @@ import Ember from 'ember'; import ManyRelationship from "./has-many"; import BelongsToRelationship from "./belongs-to"; -import EmptyObject from "../../empty-object"; import { runInDebug } from 'ember-data/-private/debug'; const { get } = Ember; @@ -37,7 +36,7 @@ function createRelationshipFor(internalModel, relationshipMeta, store) { export default class Relationships { constructor(internalModel) { this.internalModel = internalModel; - this.initializedRelationships = new EmptyObject(); + this.initializedRelationships = Object.create(null); } // TODO @runspired deprecate this as it was never truly a record instance diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index 0403458b2aa..fde441e26e8 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -3,7 +3,6 @@ */ import Ember from 'ember'; -import EmptyObject from "./empty-object"; const { get @@ -18,11 +17,11 @@ const { */ export default class Snapshot { constructor(internalModel, options = {}) { - this._attributes = new EmptyObject(); - this._belongsToRelationships = new EmptyObject(); - this._belongsToIds = new EmptyObject(); - this._hasManyRelationships = new EmptyObject(); - this._hasManyIds = new EmptyObject(); + this._attributes = Object.create(null); + this._belongsToRelationships = Object.create(null); + this._belongsToIds = Object.create(null); + this._hasManyRelationships = Object.create(null); + this._hasManyIds = Object.create(null); this._internalModel = internalModel; let record = internalModel.getRecord(); @@ -144,7 +143,7 @@ export default class Snapshot { @return {Object} All changed attributes of the current snapshot */ changedAttributes() { - let changedAttributes = new EmptyObject(); + let changedAttributes = Object.create(null); let changedAttributeKeys = Object.keys(this._changedAttributes); for (let i=0, length = changedAttributeKeys.length; i < length; i++) { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index f57a2f8f4ec..445e883d2fa 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -44,7 +44,6 @@ import coerceId from "./coerce-id"; import RecordArrayManager from "./record-array-manager"; import ContainerInstanceCache from './store/container-instance-cache'; import InternalModel from "./model/internal-model"; -import EmptyObject from "./empty-object"; import isEnabled from '../features'; export let badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; @@ -219,7 +218,7 @@ Store = Service.extend({ this._identityMap = new IdentityMap(); this._pendingSave = []; this._instanceCache = new ContainerInstanceCache(getOwner(this), this); - this._modelFactoryCache = new EmptyObject(); + this._modelFactoryCache = Object.create(null); /* Ember Data uses several specialized micro-queues for organizing @@ -349,7 +348,7 @@ Store = Service.extend({ assert(`You need to pass a model name to the store's createRecord method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); let normalizedModelName = normalizeModelName(modelName); - let properties = copy(inputProperties) || new EmptyObject(); + let properties = copy(inputProperties) || Object.create(null); // If the passed properties do not include a primary key, // give the adapter an opportunity to generate one. Typically, @@ -860,7 +859,7 @@ Store = Service.extend({ let shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; let totalItems = pendingFetchItems.length; let internalModels = new Array(totalItems); - let seeking = new EmptyObject(); + let seeking = Object.create(null); for (let i = 0; i < totalItems; i++) { let pendingItem = pendingFetchItems[i]; @@ -880,7 +879,7 @@ Store = Service.extend({ function handleFoundRecords(foundInternalModels, expectedInternalModels) { // resolve found records - let found = new EmptyObject(); + let found = Object.create(null); for (let i = 0, l = foundInternalModels.length; i < l; i++) { let internalModel = foundInternalModels[i]; let pair = seeking[internalModel.id]; diff --git a/addon/-private/system/store/container-instance-cache.js b/addon/-private/system/store/container-instance-cache.js index ff3edfe0cb2..a1ce4262579 100644 --- a/addon/-private/system/store/container-instance-cache.js +++ b/addon/-private/system/store/container-instance-cache.js @@ -1,6 +1,5 @@ /* global heimdall */ import Ember from 'ember'; -import EmptyObject from "../empty-object"; const { set } = Ember; const { @@ -37,8 +36,8 @@ export default class ContainerInstanceCache { this._owner = owner; this._store = store; this._namespaces = { - adapter: new EmptyObject(), - serializer: new EmptyObject() + adapter: Object.create(null), + serializer: Object.create(null) }; } diff --git a/addon/-private/utils/parse-response-headers.js b/addon/-private/utils/parse-response-headers.js index 5f420d595c0..b63512e3ae9 100644 --- a/addon/-private/utils/parse-response-headers.js +++ b/addon/-private/utils/parse-response-headers.js @@ -1,9 +1,7 @@ -import EmptyObject from '../system/empty-object'; - const CLRF = '\u000d\u000a'; export default function parseResponseHeaders(headersString) { - let headers = new EmptyObject(); + let headers = Object.create(null); if (!headersString) { return headers; diff --git a/tests/unit/utils/parse-response-headers-test.js b/tests/unit/utils/parse-response-headers-test.js index 98adef7bd14..c313713b293 100644 --- a/tests/unit/utils/parse-response-headers-test.js +++ b/tests/unit/utils/parse-response-headers-test.js @@ -1,4 +1,3 @@ -import EmptyObject from 'ember-data/-private/system/empty-object'; import parseResponseHeaders from 'ember-data/-private/utils/parse-response-headers'; import { module, test } from 'qunit'; @@ -9,7 +8,7 @@ module('unit/adapters/parse-response-headers'); test('returns an EmptyObject when headersString is undefined', function(assert) { let headers = parseResponseHeaders(undefined); - assert.deepEqual(headers, new EmptyObject(), 'EmptyObject is returned'); + assert.deepEqual(headers, Object.create(null), 'EmptyObject is returned'); }); test('header parsing', function(assert) { From 6f56ebdd35423197f9df5dae8ba05455333e12f8 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 14 Mar 2017 11:45:31 -0400 Subject: [PATCH 1842/2527] Update yarn.lock (no real changes, just syncing with changes in package.json). --- yarn.lock | 2308 +++++++++++++++++++++++++++-------------------------- 1 file changed, 1197 insertions(+), 1111 deletions(-) diff --git a/yarn.lock b/yarn.lock index c7f827a2a4f..f06f9d62910 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,57 +2,77 @@ # yarn lockfile v1 +"@types/node@*", "@types/node@^7.0.5": + version "7.0.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.8.tgz#25e4dd804b630c916ae671233e6d71f6ce18124a" + +"@types/rimraf@^0.0.28": + version "0.0.28" + resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06" + +"@types/tape@^4.2.29": + version "4.2.29" + resolved "https://registry.yarnpkg.com/@types/tape/-/tape-4.2.29.tgz#14cf2eb49bf852407eaaefdc53773eb90b32cf56" + dependencies: + "@types/node" "*" + +"@types/ws@^0.0.38": + version "0.0.38" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-0.0.38.tgz#42106fff4b422ca956734e29f0d73a6d893194d3" + dependencies: + "@types/node" "*" + abbrev@1: version "1.1.0" - resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" abbrev@~1.0.9: version "1.0.9" - resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" accepts@1.3.3, accepts@~1.3.3: version "1.3.3" - resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" dependencies: mime-types "~2.1.11" negotiator "0.6.1" acorn-jsx@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" dependencies: acorn "^3.0.4" -acorn@4.0.4: +acorn@4.0.4, acorn@^4.0.3: version "4.0.4" - resolved "https://registry.npmjs.org/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" -acorn@^3.0.4, acorn@^3.1.0: +acorn@^3.0.4: version "3.3.0" - resolved "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" adm-zip@^0.4.7: version "0.4.7" - resolved "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" after@0.8.1: version "0.8.1" - resolved "https://registry.npmjs.org/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" ajv-keywords@^1.0.0: version "1.5.1" - resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" ajv@^4.1.3, ajv@^4.7.0: - version "4.11.3" - resolved "https://registry.npmjs.org/ajv/-/ajv-4.11.3.tgz#ce30bdb90d1254f762c75af915fb3a63e7183d22" + version "4.11.5" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd" dependencies: co "^4.6.0" json-stable-stringify "^1.0.1" align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" - resolved "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" dependencies: kind-of "^3.0.2" longest "^1.0.1" @@ -60,212 +80,224 @@ align-text@^0.1.1, align-text@^0.1.3: alter@~0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" + resolved "https://registry.yarnpkg.com/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" dependencies: stable "~0.1.3" amd-name-resolver@0.0.5: version "0.0.5" - resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.5.tgz#76962dac876ed3311b05d29c6a58c14e1ef3304b" + resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-0.0.5.tgz#76962dac876ed3311b05d29c6a58c14e1ef3304b" dependencies: ensure-posix-path "^1.0.1" amd-name-resolver@0.0.6: version "0.0.6" - resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.6.tgz#d3e4ba2dfcaab1d820c1be9de947c67828cfe595" + resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-0.0.6.tgz#d3e4ba2dfcaab1d820c1be9de947c67828cfe595" dependencies: ensure-posix-path "^1.0.1" amdefine@>=0.0.4: version "1.0.1" - resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" ansi-escapes@^1.1.0: version "1.4.0" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" ansi-regex@*, ansi-regex@^2.0.0: version "2.1.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" ansi-styles@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" ansi-styles@^2.1.0, ansi-styles@^2.2.1: version "2.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" ansicolors@~0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" ansicolors@~0.3.2: version "0.3.2" - resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" ansistyles@~0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" + resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" anymatch@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" dependencies: arrify "^1.0.0" micromatch "^2.1.5" aproba@^1.0.3, aproba@~1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" archy@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" are-we-there-yet@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" dependencies: delegates "^1.0.0" readable-stream "^2.0.0 || ^1.1.13" argparse@^1.0.7, argparse@~1.0.2: version "1.0.9" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" dependencies: sprintf-js "~1.0.2" arr-diff@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" dependencies: arr-flatten "^1.0.1" arr-flatten@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" array-equal@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" array-flatten@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" array-index@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/array-index/-/array-index-1.0.0.tgz#ec56a749ee103e4e08c790b9c353df16055b97f9" + resolved "https://registry.yarnpkg.com/array-index/-/array-index-1.0.0.tgz#ec56a749ee103e4e08c790b9c353df16055b97f9" dependencies: debug "^2.2.0" es6-symbol "^3.0.2" +array-to-error@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" + dependencies: + array-to-sentence "^1.1.0" + +array-to-sentence@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" + array-union@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" dependencies: array-uniq "^1.0.1" array-uniq@^1.0.1: version "1.0.3" - resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" array-unique@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" arraybuffer.slice@0.0.6: version "0.0.6" - resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" arrify@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" asap@^2.0.0, asap@~2.0.4: version "2.0.5" - resolved "https://registry.npmjs.org/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" asn1@0.1.11: version "0.1.11" - resolved "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" asn1@~0.2.3: version "0.2.3" - resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" assert-plus@^0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" assert-plus@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - -assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" assertion-error@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" ast-traverse@~0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" + resolved "https://registry.yarnpkg.com/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" ast-types@0.8.12: version "0.8.12" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" ast-types@0.8.15: version "0.8.15" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" -ast-types@0.9.5: - version "0.9.5" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.9.5.tgz#1a660a09945dbceb1f9c9cbb715002617424e04a" +ast-types@0.9.6: + version "0.9.6" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" async-disk-cache@^1.0.0: - version "1.0.9" - resolved "https://registry.npmjs.org/async-disk-cache/-/async-disk-cache-1.0.9.tgz#23bafb823184f463407e474e8d5f87899f72ca63" + version "1.2.1" + resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.2.1.tgz#982d0b9861cae6b54adf53ea38fdf2c2c85a5692" dependencies: debug "^2.1.3" + heimdalljs "^0.2.3" istextorbinary "2.1.0" mkdirp "^0.5.0" rimraf "^2.5.3" rsvp "^3.0.18" + username "^2.3.0" async@^1.4.0, async@^1.5.2: version "1.5.2" - resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" async@^2.0.1: version "2.1.5" - resolved "https://registry.npmjs.org/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" + resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" dependencies: lodash "^4.14.0" -async@~0.2.6, async@~0.2.9: +async@~0.2.9: version "0.2.10" - resolved "https://registry.npmjs.org/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" async@~0.9.0: version "0.9.2" - resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" aws-sdk@^2.0.9: - version "2.17.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.17.0.tgz#b60351f37a77f04e5441fa900b0aea6df027aae3" + version "2.28.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.28.0.tgz#0b7628c5d48820187332c5a30835945c41f84f46" dependencies: buffer "4.9.1" crypto-browserify "1.0.9" @@ -279,19 +311,19 @@ aws-sdk@^2.0.9: aws-sign2@~0.5.0: version "0.5.0" - resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" aws-sign2@~0.6.0: version "0.6.0" - resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" aws4@^1.2.1: version "1.6.0" - resolved "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" babel-core@^5.0.0, babel-core@^5.8.22: version "5.8.38" - resolved "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" dependencies: babel-plugin-constant-folding "^1.0.1" babel-plugin-dead-code-elimination "^1.0.2" @@ -342,188 +374,188 @@ babel-core@^5.0.0, babel-core@^5.8.22: babel-plugin-constant-folding@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" + resolved "https://registry.yarnpkg.com/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" babel-plugin-dead-code-elimination@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" + resolved "https://registry.yarnpkg.com/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" babel-plugin-eval@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" + resolved "https://registry.yarnpkg.com/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" babel-plugin-feature-flags@^0.2.1: version "0.2.3" - resolved "https://registry.npmjs.org/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.2.3.tgz#81d81ed77bda2014098fa8243abcf03a551cbd4d" + resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.2.3.tgz#81d81ed77bda2014098fa8243abcf03a551cbd4d" dependencies: json-stable-stringify "^1.0.1" babel-plugin-filter-imports@^0.2.0: version "0.2.1" - resolved "https://registry.npmjs.org/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.2.1.tgz#784f96a892f2f7ed2ccf0955688bd8916cd2e212" + resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.2.1.tgz#784f96a892f2f7ed2ccf0955688bd8916cd2e212" dependencies: json-stable-stringify "^1.0.1" babel-plugin-htmlbars-inline-precompile@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.1.0.tgz#b784723bd1f108796b56faf9f1c05eb5ca442983" + resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.1.0.tgz#b784723bd1f108796b56faf9f1c05eb5ca442983" babel-plugin-inline-environment-variables@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" + resolved "https://registry.yarnpkg.com/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" babel-plugin-jscript@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" + resolved "https://registry.yarnpkg.com/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" babel-plugin-member-expression-literals@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" + resolved "https://registry.yarnpkg.com/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" babel-plugin-property-literals@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" + resolved "https://registry.yarnpkg.com/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" babel-plugin-proto-to-assign@^1.0.3: version "1.0.4" - resolved "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" + resolved "https://registry.yarnpkg.com/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" dependencies: lodash "^3.9.3" babel-plugin-react-constant-elements@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" + resolved "https://registry.yarnpkg.com/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" babel-plugin-react-display-name@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" + resolved "https://registry.yarnpkg.com/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" babel-plugin-remove-console@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" + resolved "https://registry.yarnpkg.com/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" babel-plugin-remove-debugger@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" + resolved "https://registry.yarnpkg.com/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" babel-plugin-runtime@^1.0.7: version "1.0.7" - resolved "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" + resolved "https://registry.yarnpkg.com/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" babel-plugin-undeclared-variables-check@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" + resolved "https://registry.yarnpkg.com/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" dependencies: leven "^1.0.2" babel-plugin-undefined-to-void@^1.1.6: version "1.1.6" - resolved "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" + resolved "https://registry.yarnpkg.com/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" babel5-plugin-strip-class-callcheck@^5.1.0: version "5.1.0" - resolved "https://registry.npmjs.org/babel5-plugin-strip-class-callcheck/-/babel5-plugin-strip-class-callcheck-5.1.0.tgz#77d4a40c8614d367b8a21a53908159806dba5f91" + resolved "https://registry.yarnpkg.com/babel5-plugin-strip-class-callcheck/-/babel5-plugin-strip-class-callcheck-5.1.0.tgz#77d4a40c8614d367b8a21a53908159806dba5f91" babel5-plugin-strip-heimdall@^5.0.2: version "5.0.2" - resolved "https://registry.npmjs.org/babel5-plugin-strip-heimdall/-/babel5-plugin-strip-heimdall-5.0.2.tgz#e1fe191c34de79686564d50a86f4217b8df629c1" + resolved "https://registry.yarnpkg.com/babel5-plugin-strip-heimdall/-/babel5-plugin-strip-heimdall-5.0.2.tgz#e1fe191c34de79686564d50a86f4217b8df629c1" babylon@^5.8.38: version "5.8.38" - resolved "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" backbone@^1.1.2: version "1.3.3" - resolved "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" + resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" dependencies: underscore ">=1.8.3" backo2@1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" balanced-match@^0.4.1: version "0.4.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" base64-arraybuffer@0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" base64-js@^1.0.2: version "1.2.0" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" base64id@0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" basic-auth@~1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" bcrypt-pbkdf@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" dependencies: tweetnacl "^0.14.3" better-assert@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" dependencies: callsite "1.0.0" "binaryextensions@1 || 2": version "2.0.0" - resolved "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.0.0.tgz#e597d1a7a6a3558a2d1c7241a16c99965e6aa40f" + resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.0.0.tgz#e597d1a7a6a3558a2d1c7241a16c99965e6aa40f" bl@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" dependencies: readable-stream "~2.0.5" blank-object@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" + resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" blob@0.0.4: version "0.0.4" - resolved "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" block-stream@*: version "0.0.9" - resolved "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" dependencies: inherits "~2.0.0" bluebird@^2.9.33: version "2.11.0" - resolved "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" bluebird@^3.1.1, bluebird@^3.4.6: - version "3.4.7" - resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + version "3.5.0" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" body-parser@^1.15.2: - version "1.16.1" - resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.16.1.tgz#51540d045adfa7a0c6995a014bb6b1ed9b802329" + version "1.17.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.17.1.tgz#75b3bc98ddd6e7e0d8ffe750dfaca5c66993fa47" dependencies: bytes "2.4.0" content-type "~1.0.2" debug "2.6.1" depd "~1.1.0" - http-errors "~1.5.1" + http-errors "~1.6.1" iconv-lite "0.4.15" on-finished "~2.3.0" - qs "6.2.1" + qs "6.4.0" raw-body "~2.2.0" type-is "~1.6.14" body@^5.1.0: version "5.1.0" - resolved "https://registry.npmjs.org/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" + resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" dependencies: continuable-cache "^0.3.1" error "^7.0.0" @@ -532,19 +564,19 @@ body@^5.1.0: boom@0.4.x: version "0.4.2" - resolved "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" + resolved "https://registry.yarnpkg.com/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" dependencies: hoek "0.9.x" boom@2.x.x: version "2.10.1" - resolved "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" dependencies: hoek "2.x.x" bower-config@^1.3.0: version "1.4.0" - resolved "https://registry.npmjs.org/bower-config/-/bower-config-1.4.0.tgz#16c38c1135f8071c19f25938d61b0d8cbf18d3f1" + resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.0.tgz#16c38c1135f8071c19f25938d61b0d8cbf18d3f1" dependencies: graceful-fs "^4.1.3" mout "^1.0.0" @@ -554,22 +586,22 @@ bower-config@^1.3.0: bower-endpoint-parser@0.2.2: version "0.2.2" - resolved "https://registry.npmjs.org/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" + resolved "https://registry.yarnpkg.com/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" bower@^1.3.12, bower@^1.6.5: version "1.8.0" - resolved "https://registry.npmjs.org/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a" + resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a" brace-expansion@^1.0.0: version "1.1.6" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" dependencies: balanced-match "^0.4.1" concat-map "0.0.1" braces@^1.8.2: version "1.8.5" - resolved "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" dependencies: expand-range "^1.8.1" preserve "^0.2.0" @@ -577,11 +609,11 @@ braces@^1.8.2: breakable@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" + resolved "https://registry.yarnpkg.com/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" broccoli-asset-rev@^2.4.5: version "2.5.0" - resolved "https://registry.npmjs.org/broccoli-asset-rev/-/broccoli-asset-rev-2.5.0.tgz#f5f66eac962bf9f086286921f0eaeaab6d00d819" + resolved "https://registry.yarnpkg.com/broccoli-asset-rev/-/broccoli-asset-rev-2.5.0.tgz#f5f66eac962bf9f086286921f0eaeaab6d00d819" dependencies: broccoli-asset-rewrite "^1.1.0" broccoli-filter "^1.2.2" @@ -591,13 +623,13 @@ broccoli-asset-rev@^2.4.5: broccoli-asset-rewrite@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" + resolved "https://registry.yarnpkg.com/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" dependencies: broccoli-filter "^1.2.3" broccoli-babel-transpiler@^5.4.5, broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: version "5.6.2" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.6.2.tgz#958c72e43575b2f0a862a5096dba1ce1ebc7d74d" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.6.2.tgz#958c72e43575b2f0a862a5096dba1ce1ebc7d74d" dependencies: babel-core "^5.0.0" broccoli-funnel "^1.0.0" @@ -609,13 +641,13 @@ broccoli-babel-transpiler@^5.4.5, broccoli-babel-transpiler@^5.5.0, broccoli-bab broccoli-brocfile-loader@^0.18.0: version "0.18.0" - resolved "https://registry.npmjs.org/broccoli-brocfile-loader/-/broccoli-brocfile-loader-0.18.0.tgz#2e86021c805c34ffc8d29a2fb721cf273e819e4b" + resolved "https://registry.yarnpkg.com/broccoli-brocfile-loader/-/broccoli-brocfile-loader-0.18.0.tgz#2e86021c805c34ffc8d29a2fb721cf273e819e4b" dependencies: findup-sync "^0.4.2" broccoli-builder@^0.18.0: version "0.18.4" - resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.4.tgz#abc6db2c07d214454918e2997ea87441b69b69d3" + resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.4.tgz#abc6db2c07d214454918e2997ea87441b69b69d3" dependencies: heimdalljs "^0.2.0" promise-map-series "^0.2.1" @@ -626,7 +658,7 @@ broccoli-builder@^0.18.0: broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: version "2.3.1" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" @@ -637,7 +669,7 @@ broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching broccoli-caching-writer@~2.0.1: version "2.0.4" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" @@ -648,18 +680,18 @@ broccoli-caching-writer@~2.0.1: symlink-or-copy "^1.0.0" walk-sync "^0.2.0" -broccoli-clean-css@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/broccoli-clean-css/-/broccoli-clean-css-2.0.0.tgz#c0794384c5a9d7de5b03223b8b3f6c6bd3b9241c" +broccoli-clean-css@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" dependencies: - broccoli-persistent-filter "^1.2.13" - clean-css-promise "^2.0.1" - json-stable-stringify "^1.0.1" - source-map-to-comment "^1.1.0" + broccoli-persistent-filter "^1.1.6" + clean-css-promise "^0.1.0" + inline-source-map-comment "^1.0.5" + json-stable-stringify "^1.0.0" broccoli-concat@^2.2.0: version "2.3.8" - resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-2.3.8.tgz#590cdcc021bb905b6c121d87c2d1d57df44a2a48" + resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-2.3.8.tgz#590cdcc021bb905b6c121d87c2d1d57df44a2a48" dependencies: broccoli-caching-writer "^2.3.1" broccoli-kitchen-sink-helpers "^0.3.1" @@ -672,7 +704,7 @@ broccoli-concat@^2.2.0: broccoli-concat@^3.0.4, broccoli-concat@^3.2.2: version "3.2.2" - resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" + resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.3.0" @@ -689,13 +721,13 @@ broccoli-concat@^3.0.4, broccoli-concat@^3.2.2: broccoli-config-loader@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/broccoli-config-loader/-/broccoli-config-loader-1.0.0.tgz#c3cf5ecfaffc04338c6f1d5d38dc36baeaa131ba" + resolved "https://registry.yarnpkg.com/broccoli-config-loader/-/broccoli-config-loader-1.0.0.tgz#c3cf5ecfaffc04338c6f1d5d38dc36baeaa131ba" dependencies: broccoli-caching-writer "^2.0.4" broccoli-config-replace@^1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" + resolved "https://registry.yarnpkg.com/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.0" @@ -704,7 +736,7 @@ broccoli-config-replace@^1.1.2: broccoli-file-creator@^1.0.0: version "1.1.1" - resolved "https://registry.npmjs.org/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" + resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" dependencies: broccoli-kitchen-sink-helpers "~0.2.0" broccoli-plugin "^1.1.0" @@ -715,7 +747,7 @@ broccoli-file-creator@^1.0.0: broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: version "1.2.4" - resolved "https://registry.npmjs.org/broccoli-filter/-/broccoli-filter-1.2.4.tgz#409afb94b9a3a6da9fac8134e91e205f40cc7330" + resolved "https://registry.yarnpkg.com/broccoli-filter/-/broccoli-filter-1.2.4.tgz#409afb94b9a3a6da9fac8134e91e205f40cc7330" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.0.0" @@ -729,11 +761,11 @@ broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: broccoli-funnel-reducer@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" + resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli-funnel@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.1.0.tgz#dfb91a37c902456456de4a40a1881948d65b27d9" + resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.1.0.tgz#dfb91a37c902456456de4a40a1881948d65b27d9" dependencies: array-equal "^1.0.0" blank-object "^1.0.1" @@ -752,21 +784,21 @@ broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli broccoli-kitchen-sink-helpers@^0.2.5, broccoli-kitchen-sink-helpers@~0.2.0: version "0.2.9" - resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" + resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" dependencies: glob "^5.0.10" mkdirp "^0.5.1" broccoli-kitchen-sink-helpers@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" + resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" dependencies: glob "^5.0.10" mkdirp "^0.5.1" broccoli-lint-eslint@^2.0.0: version "2.7.0" - resolved "https://registry.npmjs.org/broccoli-lint-eslint/-/broccoli-lint-eslint-2.7.0.tgz#a2d905d02b397a90ae82439f283c459ef819f140" + resolved "https://registry.yarnpkg.com/broccoli-lint-eslint/-/broccoli-lint-eslint-2.7.0.tgz#a2d905d02b397a90ae82439f283c459ef819f140" dependencies: broccoli-persistent-filter "^1.2.0" escape-string-regexp "^1.0.5" @@ -775,9 +807,9 @@ broccoli-lint-eslint@^2.0.0: json-stable-stringify "^1.0.1" md5-hex "^1.2.1" -broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^1.1.3, broccoli-merge-trees@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.2.1.tgz#16a7494ed56dbe61611f6c2d4817cfbaad2a3055" +broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^1.1.3, broccoli-merge-trees@^1.1.4, broccoli-merge-trees@^1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" dependencies: broccoli-plugin "^1.3.0" can-symlink "^1.0.0" @@ -790,7 +822,7 @@ broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^ broccoli-merge-trees@~0.2.3: version "0.2.4" - resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-0.2.4.tgz#1936f63bb09e24246b1e91d8c53162c0f7b24c3c" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-0.2.4.tgz#1936f63bb09e24246b1e91d8c53162c0f7b24c3c" dependencies: broccoli-plugin "^1.0.0" debug "^2.2.0" @@ -798,14 +830,14 @@ broccoli-merge-trees@~0.2.3: broccoli-middleware@^0.18.1: version "0.18.1" - resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-0.18.1.tgz#bf525581c2deb652c425942b18580f76d3748122" + resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-0.18.1.tgz#bf525581c2deb652c425942b18580f76d3748122" dependencies: handlebars "^4.0.4" mime "^1.2.11" -broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0, broccoli-persistent-filter@^1.2.13: +broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0: version "1.2.13" - resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.2.13.tgz#61368669e2b8f35238fdd38a2a896597e4a1c821" + resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.2.13.tgz#61368669e2b8f35238fdd38a2a896597e4a1c821" dependencies: async-disk-cache "^1.0.0" blank-object "^1.0.1" @@ -823,7 +855,7 @@ broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-p broccoli-plugin@1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -832,7 +864,7 @@ broccoli-plugin@1.1.0: broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -841,17 +873,17 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli broccoli-slow-trees@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" + resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" dependencies: heimdalljs "^0.2.1" broccoli-source@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" + resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" broccoli-sri-hash@^2.1.0: version "2.1.2" - resolved "https://registry.npmjs.org/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" + resolved "https://registry.yarnpkg.com/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" dependencies: broccoli-caching-writer "^2.2.0" mkdirp "^0.5.1" @@ -861,7 +893,7 @@ broccoli-sri-hash@^2.1.0: broccoli-stew@^1.0.1, broccoli-stew@^1.2.0, broccoli-stew@^1.3.3: version "1.4.0" - resolved "https://registry.npmjs.org/broccoli-stew/-/broccoli-stew-1.4.0.tgz#1bdb0a1804d62a419d190abc26acb3c91878154d" + resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-1.4.0.tgz#1bdb0a1804d62a419d190abc26acb3c91878154d" dependencies: broccoli-funnel "^1.0.1" broccoli-merge-trees "^1.0.0" @@ -877,14 +909,14 @@ broccoli-stew@^1.0.1, broccoli-stew@^1.2.0, broccoli-stew@^1.3.3: broccoli-string-replace@^0.1.1: version "0.1.2" - resolved "https://registry.npmjs.org/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" + resolved "https://registry.yarnpkg.com/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" dependencies: broccoli-persistent-filter "^1.1.5" minimatch "^3.0.3" broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: version "1.5.1" - resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.1.tgz#9fd2e87f1c177b11a758e73c3a11d6a03d90d086" + resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.1.tgz#9fd2e87f1c177b11a758e73c3a11d6a03d90d086" dependencies: broccoli-plugin "^1.2.1" debug "^2.2.0" @@ -898,14 +930,14 @@ broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: broccoli-writer@~0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/broccoli-writer/-/broccoli-writer-0.1.1.tgz#d4d71aa8f2afbc67a3866b91a2da79084b96ab2d" + resolved "https://registry.yarnpkg.com/broccoli-writer/-/broccoli-writer-0.1.1.tgz#d4d71aa8f2afbc67a3866b91a2da79084b96ab2d" dependencies: quick-temp "^0.1.0" rsvp "^3.0.6" broccoli-yuidoc@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/broccoli-yuidoc/-/broccoli-yuidoc-2.1.0.tgz#d208d5c056e421a51f0c7701e938229e7e85c2e6" + resolved "https://registry.yarnpkg.com/broccoli-yuidoc/-/broccoli-yuidoc-2.1.0.tgz#d208d5c056e421a51f0c7701e938229e7e85c2e6" dependencies: broccoli-caching-writer "~2.0.1" broccoli-merge-trees "~0.2.3" @@ -915,17 +947,17 @@ broccoli-yuidoc@^2.1.0: bser@1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" + resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" dependencies: node-int64 "^0.4.0" buffer-shims@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" buffer@4.9.1: version "4.9.1" - resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -933,95 +965,99 @@ buffer@4.9.1: builtin-modules@^1.0.0: version "1.1.1" - resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" builtins@0.0.7: version "0.0.7" - resolved "https://registry.npmjs.org/builtins/-/builtins-0.0.7.tgz#355219cd6cf18dbe7c01cc7fd2dce765cfdc549a" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-0.0.7.tgz#355219cd6cf18dbe7c01cc7fd2dce765cfdc549a" + +builtins@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" bytes@1: version "1.0.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" bytes@2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" bytes@2.4.0: version "2.4.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" caller-path@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" dependencies: callsites "^0.2.0" callsite@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" callsites@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" camelcase@^1.0.2, camelcase@^1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" camelcase@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" can-symlink@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" + resolved "https://registry.yarnpkg.com/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" dependencies: tmp "0.0.28" capture-exit@^1.0.7: version "1.2.0" - resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" dependencies: rsvp "^3.3.3" cardinal@^0.5.0: version "0.5.0" - resolved "https://registry.npmjs.org/cardinal/-/cardinal-0.5.0.tgz#00d5f661dbd4aabfdf7d41ce48a5a59bca35a291" + resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-0.5.0.tgz#00d5f661dbd4aabfdf7d41ce48a5a59bca35a291" dependencies: ansicolors "~0.2.1" redeyed "~0.5.0" caseless@~0.11.0: version "0.11.0" - resolved "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" center-align@^0.1.1: version "0.1.3" - resolved "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" dependencies: align-text "^0.1.3" lazy-cache "^1.0.3" chai-as-promised@^5.1.0: version "5.3.0" - resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-5.3.0.tgz#09d7a402908aa70dfdbead53e5853fc79d3ef21c" + resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-5.3.0.tgz#09d7a402908aa70dfdbead53e5853fc79d3ef21c" chai-as-promised@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" + resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" dependencies: check-error "^1.0.2" chai-files@^1.0.0, chai-files@^1.1.0: version "1.4.0" - resolved "https://registry.npmjs.org/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" + resolved "https://registry.yarnpkg.com/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" dependencies: assertion-error "^1.0.1" chai@^3.3.0: version "3.5.0" - resolved "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" + resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" dependencies: assertion-error "^1.0.1" deep-eql "^0.1.3" @@ -1029,7 +1065,7 @@ chai@^3.3.0: chalk@^0.5.1: version "0.5.1" - resolved "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" dependencies: ansi-styles "^1.1.0" escape-string-regexp "^1.0.0" @@ -1039,7 +1075,7 @@ chalk@^0.5.1: chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" - resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -1049,59 +1085,66 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: charm@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" + resolved "https://registry.yarnpkg.com/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" dependencies: inherits "^2.0.1" check-error@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" chownr@~1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" chrome-debugging-client@^0.2.4: - version "0.2.4" - resolved "https://registry.npmjs.org/chrome-debugging-client/-/chrome-debugging-client-0.2.4.tgz#2ae3fbfcbf0536cbbd4d12e6373b271e3bcfc468" + version "0.2.5" + resolved "https://registry.yarnpkg.com/chrome-debugging-client/-/chrome-debugging-client-0.2.5.tgz#b8e1a6c37283323b6ff5d60525f6ea1fc8899fbd" dependencies: + "@types/node" "^7.0.5" + "@types/rimraf" "^0.0.28" + "@types/tape" "^4.2.29" + "@types/ws" "^0.0.38" mktemp "^0.4.0" rimraf "^2.5.1" ws "^1.0.1" circular-json@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" clean-base-url@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" + resolved "https://registry.yarnpkg.com/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" -clean-css-promise@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/clean-css-promise/-/clean-css-promise-2.0.1.tgz#ee0f784e1f2dbd37351f9e1dbd2be524a3b80973" +clean-css-promise@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" dependencies: - clean-css "^4.0.4" + array-to-error "^1.0.0" + clean-css "^3.4.5" + pinkie-promise "^2.0.0" -clean-css@^4.0.4: - version "4.0.7" - resolved "https://registry.npmjs.org/clean-css/-/clean-css-4.0.7.tgz#d8fa8b4d87a125f38fa3d64afc59abfc68ba7790" +clean-css@^3.4.5: + version "3.4.25" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.25.tgz#9e9a52d5c1e6bc5123e1b2783fa65fe958946ede" dependencies: - source-map "0.5.x" + commander "2.8.x" + source-map "0.4.x" cli-cursor@^1.0.1, cli-cursor@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" dependencies: restore-cursor "^1.0.1" cli-spinners@^0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" cli-table2@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" + resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" dependencies: lodash "^3.10.1" string-width "^1.0.1" @@ -1110,17 +1153,17 @@ cli-table2@^0.2.0: cli-table@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" dependencies: colors "1.0.3" cli-width@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" cliui@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" dependencies: center-align "^0.1.1" right-align "^0.1.1" @@ -1128,7 +1171,7 @@ cliui@^2.1.0: cliui@^3.2.0: version "3.2.0" - resolved "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" @@ -1136,83 +1179,89 @@ cliui@^3.2.0: clone@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" + resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" clone@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" clone@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/clone/-/clone-2.1.0.tgz#9c715bfbd39aa197c8ee0f8e65c3912ba34f8cd6" + version "2.1.1" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" cmd-shim@~2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb" + resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb" dependencies: graceful-fs "^4.1.2" mkdirp "~0.5.0" co@^4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" code-point-at@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" colors@1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" colors@^1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" colors@~0.6.0-1: version "0.6.2" - resolved "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" + resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" columnify@~1.5.4: version "1.5.4" - resolved "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" + resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" dependencies: strip-ansi "^3.0.0" wcwidth "^1.0.0" combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" dependencies: delayed-stream "~1.0.0" combined-stream@~0.0.4: version "0.0.7" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" dependencies: delayed-stream "0.0.5" commander@0.6.1: version "0.6.1" - resolved "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" + resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" commander@2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" + +commander@2.8.x: + version "2.8.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + dependencies: + graceful-readlink ">= 1.0.0" commander@^2.5.0, commander@^2.6.0, commander@^2.9.0: version "2.9.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" dependencies: graceful-readlink ">= 1.0.0" commander@~2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" commoner@~0.10.3: version "0.10.8" - resolved "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" + resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" dependencies: commander "^2.5.0" detective "^4.3.1" @@ -1226,29 +1275,29 @@ commoner@~0.10.3: component-bind@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" component-emitter@1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" component-emitter@1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" component-inherit@0.0.3: version "0.0.3" - resolved "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" compressible@~2.0.8: version "2.0.9" - resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.9.tgz#6daab4e2b599c2770dd9e21e7a891b1c5a755425" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.9.tgz#6daab4e2b599c2770dd9e21e7a891b1c5a755425" dependencies: mime-db ">= 1.24.0 < 2" compression@^1.4.4: version "1.6.2" - resolved "https://registry.npmjs.org/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" dependencies: accepts "~1.3.3" bytes "2.3.0" @@ -1259,11 +1308,11 @@ compression@^1.4.4: concat-map@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" concat-stream@1.5.0, concat-stream@^1.4.6: version "1.5.0" - resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" dependencies: inherits "~2.0.1" readable-stream "~2.0.0" @@ -1271,7 +1320,7 @@ concat-stream@1.5.0, concat-stream@^1.4.6: concat-stream@^1.4.7, concat-stream@^1.5.2: version "1.6.0" - resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: inherits "^2.0.3" readable-stream "^2.2.2" @@ -1279,14 +1328,14 @@ concat-stream@^1.4.7, concat-stream@^1.5.2: config-chain@~1.1.10: version "1.1.11" - resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2" dependencies: ini "^1.3.4" proto-list "~1.2.1" configstore@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" dependencies: dot-prop "^3.0.0" graceful-fs "^4.1.2" @@ -1300,11 +1349,11 @@ configstore@^2.0.0: console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" console-ui@^1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/console-ui/-/console-ui-1.0.3.tgz#31c524461b63422769f9e89c173495d91393721c" + resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-1.0.3.tgz#31c524461b63422769f9e89c173495d91393721c" dependencies: chalk "^1.1.3" inquirer "^1.2.3" @@ -1313,66 +1362,66 @@ console-ui@^1.0.2: consolidate@^0.14.0: version "0.14.5" - resolved "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" + resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" dependencies: bluebird "^3.1.1" content-disposition@0.5.2: version "0.5.2" - resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" content-type@~1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" continuable-cache@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" + resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" convert-source-map@^1.1.0: version "1.4.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.4.0.tgz#e3dad195bf61bfe13a7a3c73e9876ec14a0268f3" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.4.0.tgz#e3dad195bf61bfe13a7a3c73e9876ec14a0268f3" cookie-signature@1.0.6: version "1.0.6" - resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" cookie@0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" copy-dereference@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" + resolved "https://registry.yarnpkg.com/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" core-js@^1.0.0: version "1.2.7" - resolved "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" core-object@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" + resolved "https://registry.yarnpkg.com/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" core-object@^2.0.2: version "2.1.1" - resolved "https://registry.npmjs.org/core-object/-/core-object-2.1.1.tgz#4b7a5f1edefcb1e6d0dcb58eab1b9f90bfc666a8" + resolved "https://registry.yarnpkg.com/core-object/-/core-object-2.1.1.tgz#4b7a5f1edefcb1e6d0dcb58eab1b9f90bfc666a8" dependencies: chalk "^1.1.3" core-util-is@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" cross-spawn-async@^2.1.1: version "2.2.5" - resolved "https://registry.npmjs.org/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc" + resolved "https://registry.yarnpkg.com/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc" dependencies: lru-cache "^4.0.0" which "^1.2.8" cross-spawn@^5.0.0: - version "5.0.1" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.0.1.tgz#a3bbb302db2297cbea3c04edf36941f4613aa399" + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: lru-cache "^4.0.1" shebang-command "^1.2.0" @@ -1380,89 +1429,95 @@ cross-spawn@^5.0.0: cryptiles@0.2.x: version "0.2.2" - resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" dependencies: boom "0.4.x" cryptiles@2.x.x: version "2.0.5" - resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" dependencies: boom "2.x.x" crypto-browserify@1.0.9: version "1.0.9" - resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" ctype@0.5.3: version "0.5.3" - resolved "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" + resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" d@^0.1.1, d@~0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" + resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" dependencies: es5-ext "~0.10.2" dashdash@^1.12.0: version "1.14.1" - resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" dependencies: assert-plus "^1.0.0" debug@0.7.4: version "0.7.4" - resolved "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" + resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" debug@2.2.0, debug@~2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" dependencies: ms "0.7.1" debug@2.3.3: version "2.3.3" - resolved "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" dependencies: ms "0.7.2" -debug@2.6.1, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: +debug@2.6.1: version "2.6.1" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" + dependencies: + ms "0.7.2" + +debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" dependencies: ms "0.7.2" debuglog@*, debuglog@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" + resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" - resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" deep-eql@^0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" dependencies: type-detect "0.1.1" deep-is@~0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" defaults@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" dependencies: clone "^1.0.2" defined@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" defs@~1.1.0: version "1.1.1" - resolved "https://registry.npmjs.org/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" + resolved "https://registry.yarnpkg.com/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" dependencies: alter "~0.2.0" ast-traverse "~0.1.1" @@ -1477,7 +1532,7 @@ defs@~1.1.0: del@^2.0.2: version "2.2.2" - resolved "https://registry.npmjs.org/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" dependencies: globby "^5.0.0" is-path-cwd "^1.0.0" @@ -1489,96 +1544,96 @@ del@^2.0.2: delayed-stream@0.0.5: version "0.0.5" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" delegates@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" -depd@~1.1.0: +depd@1.1.0, depd@~1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" destroy@~1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" detect-file@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" dependencies: fs-exists-sync "^0.1.0" detect-indent@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" dependencies: get-stdin "^4.0.1" minimist "^1.1.0" repeating "^1.1.0" detective@^4.3.1: - version "4.3.2" - resolved "https://registry.npmjs.org/detective/-/detective-4.3.2.tgz#77697e2e7947ac3fe7c8e26a6d6f115235afa91c" + version "4.5.0" + resolved "https://registry.yarnpkg.com/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" dependencies: - acorn "^3.1.0" + acorn "^4.0.3" defined "^1.0.0" dezalgo@^1.0.0, dezalgo@^1.0.1, dezalgo@~1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" dependencies: asap "^2.0.0" wrappy "1" diff@1.4.0, diff@^1.3.1: version "1.4.0" - resolved "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" + resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" doctrine@^1.2.2: version "1.5.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" dependencies: esutils "^2.0.2" isarray "^1.0.0" dot-prop@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" dependencies: is-obj "^1.0.0" ecc-jsbn@~0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" dependencies: jsbn "~0.1.0" editions@^1.1.1: version "1.3.3" - resolved "https://registry.npmjs.org/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" + resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" editor@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" + resolved "https://registry.yarnpkg.com/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" ee-first@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" ember-ajax@^2.4.1: - version "2.5.5" - resolved "https://registry.npmjs.org/ember-ajax/-/ember-ajax-2.5.5.tgz#9b59e415997012bc0f91cb302d3cf0db941e38ab" + version "2.5.6" + resolved "https://registry.yarnpkg.com/ember-ajax/-/ember-ajax-2.5.6.tgz#a75f743ccf1b95e979a5cf96013b3dba8fa625e4" dependencies: ember-cli-babel "^5.1.5" ember-cli-app-version@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/ember-cli-app-version/-/ember-cli-app-version-2.0.1.tgz#64cbe581a9abaf98afd60e9cf60fdec460766c9b" + version "2.0.2" + resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-2.0.2.tgz#aaeede608e92fae6c2e11f63d28a373c1cc3f070" dependencies: ember-cli-babel "^5.1.6" ember-cli-htmlbars "^1.0.0" @@ -1586,7 +1641,7 @@ ember-cli-app-version@^2.0.0: ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.1.7, ember-cli-babel@^5.2.1: version "5.2.4" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" dependencies: broccoli-babel-transpiler "^5.6.2" broccoli-funnel "^1.0.0" @@ -1596,7 +1651,7 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-c ember-cli-blueprint-test-helpers@0.11.0: version "0.11.0" - resolved "https://registry.npmjs.org/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" + resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" dependencies: chai "^3.3.0" chai-as-promised "^5.1.0" @@ -1611,7 +1666,7 @@ ember-cli-blueprint-test-helpers@0.11.0: ember-cli-broccoli-sane-watcher@^2.0.3: version "2.0.4" - resolved "https://registry.npmjs.org/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.0.4.tgz#f43f42f75b7509c212fb926cd9aea86ae19264c6" + resolved "https://registry.yarnpkg.com/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.0.4.tgz#f43f42f75b7509c212fb926cd9aea86ae19264c6" dependencies: broccoli-slow-trees "^3.0.1" heimdalljs "^0.2.1" @@ -1621,7 +1676,7 @@ ember-cli-broccoli-sane-watcher@^2.0.3: ember-cli-dependency-checker@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/ember-cli-dependency-checker/-/ember-cli-dependency-checker-1.3.0.tgz#f0e8cb7f0f43c1e560494eaa9372804e7a088a2a" + resolved "https://registry.yarnpkg.com/ember-cli-dependency-checker/-/ember-cli-dependency-checker-1.3.0.tgz#f0e8cb7f0f43c1e560494eaa9372804e7a088a2a" dependencies: chalk "^0.5.1" is-git-url "0.2.0" @@ -1629,7 +1684,7 @@ ember-cli-dependency-checker@^1.3.0: ember-cli-eslint@1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/ember-cli-eslint/-/ember-cli-eslint-1.3.0.tgz#8a7eda0d7e6a00c5a5a823f59664932d6429a8f1" + resolved "https://registry.yarnpkg.com/ember-cli-eslint/-/ember-cli-eslint-1.3.0.tgz#8a7eda0d7e6a00c5a5a823f59664932d6429a8f1" dependencies: broccoli-lint-eslint "^2.0.0" ember-cli-babel "^5.1.5" @@ -1637,15 +1692,15 @@ ember-cli-eslint@1.3.0: ember-cli-get-component-path-option@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" + resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" ember-cli-get-dependency-depth@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" + resolved "https://registry.yarnpkg.com/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" ember-cli-htmlbars-inline-precompile@^0.3.6: version "0.3.6" - resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.3.6.tgz#4095fe423f93102724c0725e4dd1a31f25e24de5" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.3.6.tgz#4095fe423f93102724c0725e4dd1a31f25e24de5" dependencies: babel-plugin-htmlbars-inline-precompile "^0.1.0" ember-cli-babel "^5.1.3" @@ -1654,7 +1709,7 @@ ember-cli-htmlbars-inline-precompile@^0.3.6: ember-cli-htmlbars@^1.0.0, ember-cli-htmlbars@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-1.1.1.tgz#8776cf59796dac8f32e8625fc6d1ea45ffa55de1" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-1.1.1.tgz#8776cf59796dac8f32e8625fc6d1ea45ffa55de1" dependencies: broccoli-persistent-filter "^1.0.3" ember-cli-version-checker "^1.0.2" @@ -1664,11 +1719,11 @@ ember-cli-htmlbars@^1.0.0, ember-cli-htmlbars@^1.1.1: ember-cli-inject-live-reload@^1.4.1: version "1.6.1" - resolved "https://registry.npmjs.org/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.6.1.tgz#82b8f5be454815a75e7f6d42c9ce0bc883a914a3" + resolved "https://registry.yarnpkg.com/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.6.1.tgz#82b8f5be454815a75e7f6d42c9ce0bc883a914a3" ember-cli-internal-test-helpers@^0.8.1: version "0.8.3" - resolved "https://registry.npmjs.org/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.8.3.tgz#e9b7db67f3fda4db736d1a319a282c04beada495" + resolved "https://registry.yarnpkg.com/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.8.3.tgz#e9b7db67f3fda4db736d1a319a282c04beada495" dependencies: chai "^3.3.0" chai-as-promised "^6.0.0" @@ -1686,11 +1741,11 @@ ember-cli-internal-test-helpers@^0.8.1: ember-cli-is-package-missing@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" + resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" ember-cli-legacy-blueprints@^0.1.2: version "0.1.4" - resolved "https://registry.npmjs.org/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.4.tgz#83d6c005ac0e39750ff9dd45cd1b78cf697150c6" + resolved "https://registry.yarnpkg.com/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.4.tgz#83d6c005ac0e39750ff9dd45cd1b78cf697150c6" dependencies: chalk "^1.1.1" ember-cli-get-component-path-option "^1.0.0" @@ -1712,23 +1767,23 @@ ember-cli-legacy-blueprints@^0.1.2: ember-cli-lodash-subset@^1.0.11, ember-cli-lodash-subset@^1.0.7: version "1.0.12" - resolved "https://registry.npmjs.org/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" + resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" ember-cli-normalize-entity-name@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" + resolved "https://registry.yarnpkg.com/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" dependencies: silent-error "^1.0.0" ember-cli-path-utils@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" + resolved "https://registry.yarnpkg.com/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" ember-cli-preprocess-registry@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.0.tgz#9e4ca277b5ee5f31a57b5b06174d94e3dadbf9f3" + version "3.1.1" + resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.1.tgz#38456c21c4d2b64945850cf9ec68db6ba769288a" dependencies: - broccoli-clean-css "^2.0.0" + broccoli-clean-css "^1.1.0" broccoli-funnel "^1.0.0" broccoli-merge-trees "^1.0.0" debug "^2.2.0" @@ -1739,7 +1794,7 @@ ember-cli-preprocess-registry@^3.0.0: ember-cli-pretender@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-1.0.1.tgz#35540babddef6f2778e91c627d190c73505103cd" + resolved "https://registry.yarnpkg.com/ember-cli-pretender/-/ember-cli-pretender-1.0.1.tgz#35540babddef6f2778e91c627d190c73505103cd" dependencies: broccoli-funnel "^1.1.0" broccoli-merge-trees "^1.2.1" @@ -1747,8 +1802,8 @@ ember-cli-pretender@^1.0.1: resolve "^1.2.0" ember-cli-qunit@^2.1.0: - version "2.2.5" - resolved "https://registry.npmjs.org/ember-cli-qunit/-/ember-cli-qunit-2.2.5.tgz#c8a2bf4e018e674089388d07d63adf1a3f270b74" + version "2.2.6" + resolved "https://registry.yarnpkg.com/ember-cli-qunit/-/ember-cli-qunit-2.2.6.tgz#d802174724edd59b61ffdd0581fceb3236014dd1" dependencies: broccoli-babel-transpiler "^5.5.0" broccoli-concat "^2.2.0" @@ -1764,7 +1819,7 @@ ember-cli-qunit@^2.1.0: ember-cli-release@^0.2.9: version "0.2.9" - resolved "https://registry.npmjs.org/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" + resolved "https://registry.yarnpkg.com/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" dependencies: chalk "^1.0.0" git-tools "^0.1.4" @@ -1778,7 +1833,7 @@ ember-cli-release@^0.2.9: ember-cli-shims@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/ember-cli-shims/-/ember-cli-shims-1.0.2.tgz#e2ec1b6687f94df1b68cc0aa66c1d690d9ded02c" + resolved "https://registry.yarnpkg.com/ember-cli-shims/-/ember-cli-shims-1.0.2.tgz#e2ec1b6687f94df1b68cc0aa66c1d690d9ded02c" dependencies: ember-cli-babel "^5.2.1" ember-cli-version-checker "^1.2.0" @@ -1786,47 +1841,47 @@ ember-cli-shims@^1.0.2: ember-cli-sri@^2.1.0: version "2.1.1" - resolved "https://registry.npmjs.org/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" + resolved "https://registry.yarnpkg.com/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" dependencies: broccoli-sri-hash "^2.1.0" ember-cli-string-utils@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" + resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" ember-cli-test-info@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" + resolved "https://registry.yarnpkg.com/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" dependencies: ember-cli-string-utils "^1.0.0" ember-cli-test-loader@^1.1.0: version "1.1.1" - resolved "https://registry.npmjs.org/ember-cli-test-loader/-/ember-cli-test-loader-1.1.1.tgz#333311209b18185d0e0e95f918349da10cacf0b1" + resolved "https://registry.yarnpkg.com/ember-cli-test-loader/-/ember-cli-test-loader-1.1.1.tgz#333311209b18185d0e0e95f918349da10cacf0b1" dependencies: ember-cli-babel "^5.2.1" ember-cli-uglify@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/ember-cli-uglify/-/ember-cli-uglify-1.2.0.tgz#3208c32b54bc2783056e8bb0d5cfe9bbaf17ffb2" + resolved "https://registry.yarnpkg.com/ember-cli-uglify/-/ember-cli-uglify-1.2.0.tgz#3208c32b54bc2783056e8bb0d5cfe9bbaf17ffb2" dependencies: broccoli-uglify-sourcemap "^1.0.0" ember-cli-valid-component-name@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" + resolved "https://registry.yarnpkg.com/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" dependencies: silent-error "^1.0.0" ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7, ember-cli-version-checker@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.2.0.tgz#caa286b77d1b485df5d2f62c67a6f19aa8b582c4" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-1.2.0.tgz#caa286b77d1b485df5d2f62c67a6f19aa8b582c4" dependencies: semver "^5.3.0" ember-cli@^2.11.1: version "2.11.1" - resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.11.1.tgz#519f93ee944e0a092e77da81027400a692c5b7d3" + resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-2.11.1.tgz#519f93ee944e0a092e77da81027400a692c5b7d3" dependencies: amd-name-resolver "0.0.6" bower "^1.3.12" @@ -1916,71 +1971,72 @@ ember-dev@emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed: ember-disable-prototype-extensions@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.0.tgz#86081c8cf6741f26e4b89e2b004f761174313e01" + resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.0.tgz#86081c8cf6741f26e4b89e2b004f761174313e01" dependencies: ember-cli-babel "^5.1.5" ember-disable-proxy-controllers@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" + resolved "https://registry.yarnpkg.com/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" dependencies: ember-cli-babel "^5.0.0" ember-export-application-global@^1.0.5: version "1.1.1" - resolved "https://registry.npmjs.org/ember-export-application-global/-/ember-export-application-global-1.1.1.tgz#f257d5271268932a89d7392679ce4db89d7154af" + resolved "https://registry.yarnpkg.com/ember-export-application-global/-/ember-export-application-global-1.1.1.tgz#f257d5271268932a89d7392679ce4db89d7154af" dependencies: ember-cli-babel "^5.1.10" ember-inflector@^1.9.4: version "1.11.0" - resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-1.11.0.tgz#99baae18e2bee53cfa97d8db1d739280289a174f" + resolved "https://registry.yarnpkg.com/ember-inflector/-/ember-inflector-1.11.0.tgz#99baae18e2bee53cfa97d8db1d739280289a174f" dependencies: ember-cli-babel "^5.1.7" ember-load-initializers@^0.6.0: version "0.6.3" - resolved "https://registry.npmjs.org/ember-load-initializers/-/ember-load-initializers-0.6.3.tgz#f47396ad271ba77294068c98f992a5f19705441a" + resolved "https://registry.yarnpkg.com/ember-load-initializers/-/ember-load-initializers-0.6.3.tgz#f47396ad271ba77294068c98f992a5f19705441a" dependencies: ember-cli-babel "^5.1.6" ember-publisher@0.0.7: version "0.0.7" - resolved "https://registry.npmjs.org/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" + resolved "https://registry.yarnpkg.com/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" dependencies: aws-sdk "^2.0.9" ember-qunit@^0.4.18: version "0.4.22" - resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-0.4.22.tgz#bc389798e1a4a933f542863025e2fb91d856da49" + resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-0.4.22.tgz#bc389798e1a4a933f542863025e2fb91d856da49" dependencies: ember-test-helpers "^0.5.32" ember-resolver@^2.0.3: version "2.1.1" - resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-2.1.1.tgz#5e4c1fffe9f5f48fc2194ad7592274ed0cd74f72" + resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-2.1.1.tgz#5e4c1fffe9f5f48fc2194ad7592274ed0cd74f72" dependencies: ember-cli-babel "^5.1.6" ember-cli-version-checker "^1.1.6" ember-router-generator@^1.0.0: version "1.2.3" - resolved "https://registry.npmjs.org/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" + resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" dependencies: recast "^0.11.3" ember-runtime-enumerable-includes-polyfill@^1.0.0: version "1.0.4" - resolved "https://registry.npmjs.org/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-1.0.4.tgz#16a7612e347a2edf07da8b2f2f09dbfee70deba0" + resolved "https://registry.yarnpkg.com/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-1.0.4.tgz#16a7612e347a2edf07da8b2f2f09dbfee70deba0" dependencies: ember-cli-babel "^5.1.6" ember-cli-version-checker "^1.1.6" ember-source@~2.11.0: - version "2.11.2" - resolved "https://registry.npmjs.org/ember-source/-/ember-source-2.11.2.tgz#07239925dc8fc2a8377bdf43210c42093e8fc4ae" + version "2.11.3" + resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-2.11.3.tgz#12c50cc2b4a7f8ae8c5daa3a72fb09415476c510" dependencies: - broccoli-stew "^1.2.0" + broccoli-funnel "^1.0.6" + broccoli-merge-trees "^1.1.4" ember-cli-get-component-path-option "^1.0.0" ember-cli-normalize-entity-name "^1.0.0" ember-cli-path-utils "^1.0.0" @@ -1990,18 +2046,18 @@ ember-source@~2.11.0: ember-cli-version-checker "^1.1.7" jquery "^3.1.1" resolve "^1.1.7" - rsvp "^3.3.3" + rsvp "^3.4.0" simple-dom "^0.3.0" ember-test-helpers@^0.5.32: version "0.5.34" - resolved "https://registry.npmjs.org/ember-test-helpers/-/ember-test-helpers-0.5.34.tgz#c8439108d1cba1d7d838c212208a5c4061471b83" + resolved "https://registry.yarnpkg.com/ember-test-helpers/-/ember-test-helpers-0.5.34.tgz#c8439108d1cba1d7d838c212208a5c4061471b83" dependencies: klassy "^0.1.3" ember-try-config@^2.0.1: version "2.1.0" - resolved "https://registry.npmjs.org/ember-try-config/-/ember-try-config-2.1.0.tgz#e0e156229a542346a58ee6f6ad605104c98edfe0" + resolved "https://registry.yarnpkg.com/ember-try-config/-/ember-try-config-2.1.0.tgz#e0e156229a542346a58ee6f6ad605104c98edfe0" dependencies: lodash "^4.6.1" node-fetch "^1.3.3" @@ -2010,7 +2066,7 @@ ember-try-config@^2.0.1: ember-try@^0.2.6: version "0.2.10" - resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.10.tgz#8a11191fe8e5a45fb94b3bfdb0dc57d71899f16c" + resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.10.tgz#8a11191fe8e5a45fb94b3bfdb0dc57d71899f16c" dependencies: chalk "^1.0.0" cli-table2 "^0.2.0" @@ -2030,7 +2086,7 @@ ember-try@^0.2.6: ember-watson@^0.7.0: version "0.7.0" - resolved "https://registry.npmjs.org/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" + resolved "https://registry.yarnpkg.com/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" dependencies: babel-core "^5.8.22" chalk "^1.0.0" @@ -2042,17 +2098,17 @@ ember-watson@^0.7.0: encodeurl@~1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" encoding@^0.1.11: version "0.1.12" - resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" dependencies: iconv-lite "~0.4.13" engine.io-client@1.8.0: version "1.8.0" - resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.0.tgz#7b730e4127414087596d9be3c88d2bc5fdb6cf5c" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.0.tgz#7b730e4127414087596d9be3c88d2bc5fdb6cf5c" dependencies: component-emitter "1.2.1" component-inherit "0.0.3" @@ -2069,7 +2125,7 @@ engine.io-client@1.8.0: engine.io-parser@1.3.1: version "1.3.1" - resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" dependencies: after "0.8.1" arraybuffer.slice "0.0.6" @@ -2080,7 +2136,7 @@ engine.io-parser@1.3.1: engine.io@1.8.0: version "1.8.0" - resolved "https://registry.npmjs.org/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" dependencies: accepts "1.3.3" base64id "0.1.0" @@ -2091,35 +2147,35 @@ engine.io@1.8.0: ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" + resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" entities@~1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" error-ex@^1.2.0: - version "1.3.0" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz#e67b43f3e82c96ea3a584ffee0b9fc3325d802d9" + version "1.3.1" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" dependencies: is-arrayish "^0.2.1" error@^7.0.0: version "7.0.2" - resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" + resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" dependencies: string-template "~0.2.1" xtend "~4.0.0" es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: - version "0.10.12" - resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" + version "0.10.13" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.13.tgz#a390ab717bde1ce3b4cbaeabe23ca8fbddcb06f6" dependencies: es6-iterator "2" es6-symbol "~3.1" es6-iterator@2: version "2.0.0" - resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" dependencies: d "^0.1.1" es5-ext "^0.10.7" @@ -2127,7 +2183,7 @@ es6-iterator@2: es6-map@^0.1.3: version "0.1.4" - resolved "https://registry.npmjs.org/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" dependencies: d "~0.1.1" es5-ext "~0.10.11" @@ -2138,11 +2194,11 @@ es6-map@^0.1.3: es6-promise@~4.0.3: version "4.0.5" - resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" es6-set@~0.1.3: version "0.1.4" - resolved "https://registry.npmjs.org/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" dependencies: d "~0.1.1" es5-ext "~0.10.11" @@ -2152,14 +2208,14 @@ es6-set@~0.1.3: es6-symbol@3, es6-symbol@^3.0.2, es6-symbol@~3.1, es6-symbol@~3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" dependencies: d "~0.1.1" es5-ext "~0.10.11" es6-weak-map@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" dependencies: d "^0.1.1" es5-ext "^0.10.8" @@ -2168,19 +2224,19 @@ es6-weak-map@^2.0.1: escape-html@~1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" escape-string-regexp@1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" escope@^3.6.0: version "3.6.0" - resolved "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" dependencies: es6-map "^0.1.3" es6-weak-map "^2.0.1" @@ -2189,7 +2245,7 @@ escope@^3.6.0: eslint@^2.13.0: version "2.13.1" - resolved "https://registry.npmjs.org/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" dependencies: chalk "^1.1.3" concat-stream "^1.4.6" @@ -2227,82 +2283,82 @@ eslint@^2.13.0: espree@^3.1.6: version "3.4.0" - resolved "https://registry.npmjs.org/espree/-/espree-3.4.0.tgz#41656fa5628e042878025ef467e78f125cb86e1d" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.0.tgz#41656fa5628e042878025ef467e78f125cb86e1d" dependencies: acorn "4.0.4" acorn-jsx "^3.0.0" esprima-fb@~12001.1.0-dev-harmony-fb: version "12001.1.0-dev-harmony-fb" - resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-12001.1.0-dev-harmony-fb.tgz#d84400384ba95ce2678c617ad24a7f40808da915" + resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-12001.1.0-dev-harmony-fb.tgz#d84400384ba95ce2678c617ad24a7f40808da915" esprima-fb@~15001.1001.0-dev-harmony-fb: version "15001.1001.0-dev-harmony-fb" - resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" + resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" esprima@^1.2.2: version "1.2.5" - resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" esprima@^2.6.0: version "2.7.3" - resolved "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" esprima@^3.1.1, esprima@~3.1.0: version "3.1.3" - resolved "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" esprimaq@^0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" + resolved "https://registry.yarnpkg.com/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" esrecurse@^4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" dependencies: estraverse "~4.1.0" object-assign "^4.0.1" estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" estraverse@~4.1.0: version "4.1.1" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" -etag@~1.7.0: - version "1.7.0" - resolved "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" +etag@~1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" event-emitter@~0.3.4: version "0.3.4" - resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" dependencies: d "~0.1.1" es5-ext "~0.10.7" eventemitter3@1.x.x: version "1.2.0" - resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" events-to-array@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/events-to-array/-/events-to-array-1.0.2.tgz#b3484465534fe4ff66fbdd1a83b777713ba404aa" + resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.0.2.tgz#b3484465534fe4ff66fbdd1a83b777713ba404aa" exec-sh@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" dependencies: merge "^1.1.3" execa@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/execa/-/execa-0.4.0.tgz#4eb6467a36a095fabb2970ff9d5e3fb7bce6ebc3" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.4.0.tgz#4eb6467a36a095fabb2970ff9d5e3fb7bce6ebc3" dependencies: cross-spawn-async "^2.1.1" is-stream "^1.1.0" @@ -2313,41 +2369,41 @@ execa@^0.4.0: exists-sync@0.0.3: version "0.0.3" - resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" + resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" exists-sync@0.0.4: version "0.0.4" - resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" + resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" exit-hook@^1.0.0: version "1.1.1" - resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" exit@^0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" expand-brackets@^0.1.4: version "0.1.5" - resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" dependencies: is-posix-bracket "^0.1.0" expand-range@^1.8.1: version "1.8.2" - resolved "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" dependencies: fill-range "^2.1.0" expand-tilde@^1.2.2: version "1.2.2" - resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" dependencies: os-homedir "^1.0.1" express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: - version "4.14.1" - resolved "https://registry.npmjs.org/express/-/express-4.14.1.tgz#646c237f766f148c2120aff073817b9e4d7e0d33" + version "4.15.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35" dependencies: accepts "~1.3.3" array-flatten "1.1.1" @@ -2355,34 +2411,36 @@ express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: content-type "~1.0.2" cookie "0.3.1" cookie-signature "1.0.6" - debug "~2.2.0" + debug "2.6.1" depd "~1.1.0" encodeurl "~1.0.1" escape-html "~1.0.3" - etag "~1.7.0" - finalhandler "0.5.1" - fresh "0.3.0" + etag "~1.8.0" + finalhandler "~1.0.0" + fresh "0.5.0" merge-descriptors "1.0.1" methods "~1.1.2" on-finished "~2.3.0" parseurl "~1.3.1" path-to-regexp "0.1.7" proxy-addr "~1.1.3" - qs "6.2.0" + qs "6.4.0" range-parser "~1.2.0" - send "0.14.2" - serve-static "~1.11.2" + send "0.15.1" + serve-static "1.12.1" + setprototypeof "1.0.3" + statuses "~1.3.1" type-is "~1.6.14" utils-merge "1.0.0" vary "~1.1.0" extend@^3.0.0, extend@~3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" external-editor@^1.1.0: version "1.1.1" - resolved "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" dependencies: extend "^3.0.0" spawn-sync "^1.0.15" @@ -2390,13 +2448,13 @@ external-editor@^1.1.0: extglob@^0.3.1: version "0.3.2" - resolved "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" dependencies: is-extglob "^1.0.0" extract-zip@~1.5.0: version "1.5.0" - resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4" dependencies: concat-stream "1.5.0" debug "0.7.4" @@ -2405,29 +2463,29 @@ extract-zip@~1.5.0: extsprintf@1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" fake-xml-http-request@^1.3.0, fake-xml-http-request@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-1.4.0.tgz#6481c727a0eae9c420bae229dcdfc5369c4b5477" + resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-1.4.0.tgz#6481c727a0eae9c420bae229dcdfc5369c4b5477" faker@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/faker/-/faker-3.1.0.tgz#0f908faf4e6ec02524e54a57e432c5c013e08c9f" + resolved "https://registry.yarnpkg.com/faker/-/faker-3.1.0.tgz#0f908faf4e6ec02524e54a57e432c5c013e08c9f" fast-levenshtein@~2.0.4: version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" + resolved "https://registry.yarnpkg.com/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" dependencies: blank-object "^1.0.1" fast-sourcemap-concat@^1.0.1: version "1.1.0" - resolved "https://registry.npmjs.org/fast-sourcemap-concat/-/fast-sourcemap-concat-1.1.0.tgz#a800767abed5eda02e67238ec063a709be61f9d4" + resolved "https://registry.yarnpkg.com/fast-sourcemap-concat/-/fast-sourcemap-concat-1.1.0.tgz#a800767abed5eda02e67238ec063a709be61f9d4" dependencies: chalk "^0.5.1" debug "^2.2.0" @@ -2440,47 +2498,47 @@ fast-sourcemap-concat@^1.0.1: faye-websocket@~0.10.0: version "0.10.0" - resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" dependencies: websocket-driver ">=0.5.1" fb-watchman@^1.8.0: version "1.9.2" - resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383" dependencies: bser "1.0.2" fd-slicer@~1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" dependencies: pend "~1.2.0" figures@^1.3.5: version "1.7.0" - resolved "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" dependencies: escape-string-regexp "^1.0.5" object-assign "^4.1.0" file-entry-cache@^1.1.1: version "1.3.1" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" dependencies: flat-cache "^1.2.1" object-assign "^4.0.1" filename-regex@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" filesize@^3.1.3: - version "3.5.4" - resolved "https://registry.npmjs.org/filesize/-/filesize-3.5.4.tgz#742fc7fb6aef4ee3878682600c22f840731e1fda" + version "3.5.6" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.6.tgz#5fd98f3eac94ec9516ef8ed5782fad84a01a0a1a" fill-range@^2.1.0: version "2.2.3" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" dependencies: is-number "^2.1.0" isobject "^2.0.0" @@ -2488,30 +2546,32 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" -finalhandler@0.5.1: - version "0.5.1" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.1.tgz#2c400d8d4530935bc232549c5fa385ec07de6fcd" +finalhandler@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.0.tgz#b5691c2c0912092f18ac23e9416bde5cd7dc6755" dependencies: - debug "~2.2.0" + debug "2.6.1" + encodeurl "~1.0.1" escape-html "~1.0.3" on-finished "~2.3.0" + parseurl "~1.3.1" statuses "~1.3.1" unpipe "~1.0.0" find-index@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" + resolved "https://registry.yarnpkg.com/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" find-up@^1.0.0, find-up@^1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" findup-sync@^0.4.2: version "0.4.3" - resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" dependencies: detect-file "^0.1.0" is-glob "^2.0.1" @@ -2520,14 +2580,14 @@ findup-sync@^0.4.2: findup@^0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" + resolved "https://registry.yarnpkg.com/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" dependencies: colors "~0.6.0-1" commander "~2.1.0" fireworm@^0.7.0: version "0.7.1" - resolved "https://registry.npmjs.org/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" + resolved "https://registry.yarnpkg.com/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" dependencies: async "~0.2.9" is-type "0.0.1" @@ -2537,34 +2597,34 @@ fireworm@^0.7.0: flat-cache@^1.2.1: version "1.2.2" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" dependencies: circular-json "^0.3.1" del "^2.0.2" graceful-fs "^4.1.2" write "^0.2.1" -for-in@^0.1.5: - version "0.1.6" - resolved "https://registry.npmjs.org/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" +for-in@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" for-own@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" dependencies: - for-in "^0.1.5" + for-in "^1.0.1" forever-agent@~0.5.0: version "0.5.2" - resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" forever-agent@~0.6.1: version "0.6.1" - resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" form-data@~0.1.0: version "0.1.4" - resolved "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" dependencies: async "~0.9.0" combined-stream "~0.0.4" @@ -2572,7 +2632,7 @@ form-data@~0.1.0: form-data@~1.0.0-rc4: version "1.0.1" - resolved "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" dependencies: async "^2.0.1" combined-stream "^1.0.5" @@ -2580,7 +2640,7 @@ form-data@~1.0.0-rc4: form-data@~2.1.1: version "2.1.2" - resolved "https://registry.npmjs.org/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" dependencies: asynckit "^0.4.0" combined-stream "^1.0.5" @@ -2588,19 +2648,19 @@ form-data@~2.1.1: forwarded@~0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" -fresh@0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" +fresh@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" fs-exists-sync@^0.1.0: version "0.1.0" - resolved "http://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" fs-extra@1.0.0, fs-extra@^1.0.0, fs-extra@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -2608,7 +2668,7 @@ fs-extra@1.0.0, fs-extra@^1.0.0, fs-extra@~1.0.0: fs-extra@^0.24.0: version "0.24.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -2617,7 +2677,7 @@ fs-extra@^0.24.0: fs-extra@^0.26.0, fs-extra@^0.26.7: version "0.26.7" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -2627,7 +2687,7 @@ fs-extra@^0.26.0, fs-extra@^0.26.7: fs-extra@^0.30.0: version "0.30.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -2637,11 +2697,11 @@ fs-extra@^0.30.0: fs-readdir-recursive@^0.1.0: version "0.1.2" - resolved "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" fs-sync@^0.2.4: version "0.2.6" - resolved "https://registry.npmjs.org/fs-sync/-/fs-sync-0.2.6.tgz#657116c12b95ac9a36c51a850066c9ee6441fe06" + resolved "https://registry.yarnpkg.com/fs-sync/-/fs-sync-0.2.6.tgz#657116c12b95ac9a36c51a850066c9ee6441fe06" dependencies: glob "~4.0.4" iconv-lite "~0.2.10" @@ -2651,7 +2711,7 @@ fs-sync@^0.2.4: fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6: version "0.5.6" - resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.6.tgz#342665749e8dca406800b672268c8f5073f3e623" + resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-0.5.6.tgz#342665749e8dca406800b672268c8f5073f3e623" dependencies: heimdalljs-logger "^0.1.7" object-assign "^4.1.0" @@ -2659,16 +2719,16 @@ fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5 symlink-or-copy "^1.1.8" fs-vacuum@~1.2.9: - version "1.2.9" - resolved "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.9.tgz#4f90193ab8ea02890995bcd4e804659a5d366b2d" + version "1.2.10" + resolved "https://registry.yarnpkg.com/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36" dependencies: graceful-fs "^4.1.2" path-is-inside "^1.0.1" rimraf "^2.5.2" fs-write-stream-atomic@~1.0.8: - version "1.0.8" - resolved "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.8.tgz#e49aaddf288f87d46ff9e882f216a13abc40778b" + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" dependencies: graceful-fs "^4.1.2" iferr "^0.1.5" @@ -2677,11 +2737,11 @@ fs-write-stream-atomic@~1.0.8: fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" fstream-ignore@^1.0.0: version "1.0.5" - resolved "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" dependencies: fstream "^1.0.0" inherits "2" @@ -2689,14 +2749,14 @@ fstream-ignore@^1.0.0: fstream-npm@~1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/fstream-npm/-/fstream-npm-1.2.0.tgz#d2c3c89101346982d64e57091c38487bda916fce" + resolved "https://registry.yarnpkg.com/fstream-npm/-/fstream-npm-1.2.0.tgz#d2c3c89101346982d64e57091c38487bda916fce" dependencies: fstream-ignore "^1.0.0" inherits "2" fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: - version "1.0.10" - resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" dependencies: graceful-fs "^4.1.2" inherits "~2.0.0" @@ -2705,7 +2765,7 @@ fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: gauge@~2.6.0: version "2.6.0" - resolved "https://registry.npmjs.org/gauge/-/gauge-2.6.0.tgz#d35301ad18e96902b4751dcbbe40f4218b942a46" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.6.0.tgz#d35301ad18e96902b4751dcbbe40f4218b942a46" dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -2719,7 +2779,7 @@ gauge@~2.6.0: gauge@~2.7.1: version "2.7.3" - resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09" dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -2732,70 +2792,70 @@ gauge@~2.7.1: generate-function@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" generate-object-property@^1.1.0: version "1.2.0" - resolved "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" dependencies: is-property "^1.0.0" get-caller-file@^1.0.0, get-caller-file@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" get-stdin@^4.0.1: version "4.0.1" - resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" getpass@^0.1.1: version "0.1.6" - resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" dependencies: assert-plus "^1.0.0" git-repo-info@^1.0.4, git-repo-info@^1.1.2: version "1.4.1" - resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" + resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" git-repo-info@~1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.2.0.tgz#43d8513e04a24dd441330a2f7c6655a709fdbaf2" + resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.2.0.tgz#43d8513e04a24dd441330a2f7c6655a709fdbaf2" git-repo-version@0.4.1: version "0.4.1" - resolved "https://registry.npmjs.org/git-repo-version/-/git-repo-version-0.4.1.tgz#75fab9a0a4ec8470755b0eea7fdaa6f9d41453bf" + resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-0.4.1.tgz#75fab9a0a4ec8470755b0eea7fdaa6f9d41453bf" dependencies: git-repo-info "~1.2.0" git-tools@^0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" + resolved "https://registry.yarnpkg.com/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" dependencies: spawnback "~1.0.0" github@^0.2.4: version "0.2.4" - resolved "https://registry.npmjs.org/github/-/github-0.2.4.tgz#24fa7f0e13fa11b946af91134c51982a91ce538b" + resolved "https://registry.yarnpkg.com/github/-/github-0.2.4.tgz#24fa7f0e13fa11b946af91134c51982a91ce538b" dependencies: mime "^1.2.11" glob-base@^0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" dependencies: glob-parent "^2.0.0" is-glob "^2.0.0" glob-parent@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" dependencies: is-glob "^2.0.0" glob@3.2.3: version "3.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" + resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" dependencies: graceful-fs "~2.0.0" inherits "2" @@ -2803,7 +2863,7 @@ glob@3.2.3: glob@5.0.13, glob@^5.0.10: version "5.0.13" - resolved "https://registry.npmjs.org/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" dependencies: inflight "^1.0.4" inherits "2" @@ -2813,7 +2873,7 @@ glob@5.0.13, glob@^5.0.10: glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.1: version "7.1.1" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -2824,7 +2884,7 @@ glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.1: glob@^4.3.2: version "4.5.3" - resolved "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" + resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" dependencies: inflight "^1.0.4" inherits "2" @@ -2833,17 +2893,7 @@ glob@^4.3.2: glob@^5.0.15: version "5.0.15" - resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^6.0.0: - version "6.0.4" - resolved "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: inflight "^1.0.4" inherits "2" @@ -2853,7 +2903,7 @@ glob@^6.0.0: glob@~4.0.4: version "4.0.6" - resolved "https://registry.npmjs.org/glob/-/glob-4.0.6.tgz#695c50bdd4e2fb5c5d370b091f388d3707e291a7" + resolved "https://registry.yarnpkg.com/glob/-/glob-4.0.6.tgz#695c50bdd4e2fb5c5d370b091f388d3707e291a7" dependencies: graceful-fs "^3.0.2" inherits "2" @@ -2862,7 +2912,7 @@ glob@~4.0.4: glob@~7.0.6: version "7.0.6" - resolved "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -2873,14 +2923,14 @@ glob@~7.0.6: global-modules@^0.2.3: version "0.2.3" - resolved "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" dependencies: global-prefix "^0.1.4" is-windows "^0.2.0" global-prefix@^0.1.4: version "0.1.5" - resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" dependencies: homedir-polyfill "^1.0.0" ini "^1.3.4" @@ -2889,15 +2939,15 @@ global-prefix@^0.1.4: globals@^6.4.0: version "6.4.1" - resolved "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" + resolved "https://registry.yarnpkg.com/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" globals@^9.2.0: version "9.16.0" - resolved "https://registry.npmjs.org/globals/-/globals-9.16.0.tgz#63e903658171ec2d9f51b1d31de5e2b8dc01fb80" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.16.0.tgz#63e903658171ec2d9f51b1d31de5e2b8dc01fb80" globby@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" dependencies: array-union "^1.0.1" arrify "^1.0.0" @@ -2908,37 +2958,37 @@ globby@^5.0.0: graceful-fs@^3.0.2: version "3.0.11" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" dependencies: natives "^1.1.0" graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.6: version "4.1.11" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" graceful-fs@~1: version "1.2.3" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" graceful-fs@~2.0.0: version "2.0.3" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" "graceful-readlink@>= 1.0.0": version "1.0.1" - resolved "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" growl@1.8.1: version "1.8.1" - resolved "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428" growly@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" handlebars@^4.0.4: version "4.0.6" - resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" dependencies: async "^1.4.0" optimist "^0.6.1" @@ -2948,7 +2998,7 @@ handlebars@^4.0.4: har-validator@~2.0.6: version "2.0.6" - resolved "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" dependencies: chalk "^1.1.1" commander "^2.9.0" @@ -2957,43 +3007,43 @@ har-validator@~2.0.6: has-ansi@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" dependencies: ansi-regex "^0.2.0" has-ansi@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" dependencies: ansi-regex "^2.0.0" has-binary@0.1.6: version "0.1.6" - resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" + resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" dependencies: isarray "0.0.1" has-binary@0.1.7: version "0.1.7" - resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" + resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" dependencies: isarray "0.0.1" has-color@^0.1.7: version "0.1.7" - resolved "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" + resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" has-cors@1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" has-unicode@^2.0.0, has-unicode@~2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" hash-for-dep@^1.0.2: version "1.1.2" - resolved "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.1.2.tgz#e3347ed92960eb0bb53a2c6c2b70e36d75b7cd0c" + resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.1.2.tgz#e3347ed92960eb0bb53a2c6c2b70e36d75b7cd0c" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" heimdalljs "^0.2.3" @@ -3002,14 +3052,14 @@ hash-for-dep@^1.0.2: hasha@~2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1" + resolved "https://registry.yarnpkg.com/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1" dependencies: is-stream "^1.0.1" pinkie-promise "^2.0.0" hawk@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" dependencies: boom "0.4.x" cryptiles "0.2.x" @@ -3018,7 +3068,7 @@ hawk@1.1.1: hawk@~3.1.3: version "3.1.3" - resolved "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" dependencies: boom "2.x.x" cryptiles "2.x.x" @@ -3027,7 +3077,7 @@ hawk@~3.1.3: heimdall-query@^0.0.5: version "0.0.5" - resolved "https://registry.npmjs.org/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" + resolved "https://registry.yarnpkg.com/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" dependencies: chalk "^1.1.1" chrome-debugging-client "^0.2.4" @@ -3039,77 +3089,78 @@ heimdall-query@^0.0.5: heimdalljs-fs-monitor@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.1.0.tgz#d404a65688c6714c485469ed3495da4853440272" + resolved "https://registry.yarnpkg.com/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.1.0.tgz#d404a65688c6714c485469ed3495da4853440272" dependencies: heimdalljs "^0.2.0" heimdalljs-logger "^0.1.7" heimdalljs-logger@^0.1.7: version "0.1.8" - resolved "https://registry.npmjs.org/heimdalljs-logger/-/heimdalljs-logger-0.1.8.tgz#82abb55e53eefc0e5654ddf521b82926e50fcd95" + resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.8.tgz#82abb55e53eefc0e5654ddf521b82926e50fcd95" dependencies: debug "^2.2.0" heimdalljs "^0.2.0" heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3: version "0.2.3" - resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.2.3.tgz#35b82a6a4d73541fc4fb88d2fe2b23608fb4f779" + resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.3.tgz#35b82a6a4d73541fc4fb88d2fe2b23608fb4f779" dependencies: rsvp "~3.2.1" heimdalljs@^0.3.0: version "0.3.2" - resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.3.2.tgz#d19f98cf7c6a7660c2ecbbeaa696db3436227713" + resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.3.2.tgz#d19f98cf7c6a7660c2ecbbeaa696db3436227713" dependencies: rsvp "~3.2.1" hoek@0.9.x: version "0.9.1" - resolved "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" hoek@2.x.x: version "2.16.3" - resolved "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" home-or-tmp@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" dependencies: os-tmpdir "^1.0.1" user-home "^1.1.1" homedir-polyfill@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" dependencies: parse-passwd "^1.0.0" hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: version "2.2.0" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.2.0.tgz#7a0d097863d886c0fabbdcd37bf1758d8becf8a5" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.2.0.tgz#7a0d097863d886c0fabbdcd37bf1758d8becf8a5" hosted-git-info@~2.1.5: version "2.1.5" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" -http-errors@~1.5.1: - version "1.5.1" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" +http-errors@~1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257" dependencies: + depd "1.1.0" inherits "2.0.3" - setprototypeof "1.0.2" + setprototypeof "1.0.3" statuses ">= 1.3.1 < 2" http-proxy@^1.13.1, http-proxy@^1.9.0: version "1.16.2" - resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" dependencies: eventemitter3 "1.x.x" requires-port "1.x.x" http-signature@~0.10.0: version "0.10.1" - resolved "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" dependencies: asn1 "0.1.11" assert-plus "^0.1.5" @@ -3117,7 +3168,7 @@ http-signature@~0.10.0: http-signature@~1.1.0: version "1.1.1" - resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" dependencies: assert-plus "^0.2.0" jsprim "^1.2.2" @@ -3125,71 +3176,81 @@ http-signature@~1.1.0: iconv-lite@0.4.15, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.15" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" iconv-lite@~0.2.10: version "0.2.11" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8" ieee754@^1.1.4: version "1.1.8" - resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" iferr@^0.1.5, iferr@~0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" ignore@^3.1.2: version "3.2.4" - resolved "https://registry.npmjs.org/ignore/-/ignore-3.2.4.tgz#4055e03596729a8fabe45a43c100ad5ed815c4e8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.4.tgz#4055e03596729a8fabe45a43c100ad5ed815c4e8" imurmurhash@*, imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" indexof@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" inflected@^1.1.6: version "1.1.7" - resolved "https://registry.npmjs.org/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" + resolved "https://registry.yarnpkg.com/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" inflection@^1.7.0, inflection@^1.7.1, inflection@^1.8.0: version "1.12.0" - resolved "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" inflight@^1.0.4, inflight@~1.0.5: version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" dependencies: once "^1.3.0" wrappy "1" inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" ini@^1.3.4, ini@~1.3.4: version "1.3.4" - resolved "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" init-package-json@~1.9.4: - version "1.9.4" - resolved "https://registry.npmjs.org/init-package-json/-/init-package-json-1.9.4.tgz#b4053d0b40f0cf842a41966937cb3dc0f534e856" + version "1.9.5" + resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-1.9.5.tgz#7d4d64a264dc76c1f1f557cbbe824978bf10cd09" dependencies: - glob "^6.0.0" + glob "^7.1.1" npm-package-arg "^4.0.0" promzard "^0.3.0" read "~1.0.1" read-package-json "1 || 2" semver "2.x || 3.x || 4 || 5" validate-npm-package-license "^3.0.1" - validate-npm-package-name "^2.0.1" + validate-npm-package-name "^3.0.0" + +inline-source-map-comment@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" + dependencies: + chalk "^1.0.0" + get-stdin "^4.0.1" + minimist "^1.1.1" + sum-up "^1.0.1" + xtend "^4.0.0" inquirer@^0.12.0: version "0.12.0" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" dependencies: ansi-escapes "^1.1.0" ansi-regex "^2.0.0" @@ -3207,7 +3268,7 @@ inquirer@^0.12.0: inquirer@^1.2.3: version "1.2.3" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918" dependencies: ansi-escapes "^1.1.0" chalk "^1.0.0" @@ -3226,79 +3287,79 @@ inquirer@^1.2.3: invert-kv@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" ipaddr.js@1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.2.0.tgz#8aba49c9192799585bdd643e0ccb50e8ae777ba4" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.2.0.tgz#8aba49c9192799585bdd643e0ccb50e8ae777ba4" is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" is-buffer@^1.0.2: - version "1.1.4" - resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" is-builtin-module@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" dependencies: builtin-modules "^1.0.0" is-dotfile@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" is-equal-shallow@^0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" dependencies: is-primitive "^2.0.0" is-extendable@^0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" is-extglob@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" is-finite@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" is-git-url@0.2.0, is-git-url@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/is-git-url/-/is-git-url-0.2.0.tgz#b9ce0fb044821c88880213d602db03bdb255da1b" + resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-0.2.0.tgz#b9ce0fb044821c88880213d602db03bdb255da1b" is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" dependencies: is-extglob "^1.0.0" is-integer@^1.0.4: version "1.0.6" - resolved "https://registry.npmjs.org/is-integer/-/is-integer-1.0.6.tgz#5273819fada880d123e1ac00a938e7172dd8d95e" + resolved "https://registry.yarnpkg.com/is-integer/-/is-integer-1.0.6.tgz#5273819fada880d123e1ac00a938e7172dd8d95e" dependencies: is-finite "^1.0.0" is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: - version "2.15.0" - resolved "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" + version "2.16.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" dependencies: generate-function "^2.0.0" generate-object-property "^1.1.0" @@ -3307,103 +3368,103 @@ is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: is-number@^2.0.2, is-number@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" dependencies: kind-of "^3.0.2" is-obj@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" is-path-cwd@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" is-path-in-cwd@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" dependencies: is-path-inside "^1.0.0" is-path-inside@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" dependencies: path-is-inside "^1.0.1" is-posix-bracket@^0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" is-primitive@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" is-promise@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" is-property@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" is-resolvable@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" dependencies: tryit "^1.0.1" is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" is-type@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" + resolved "https://registry.yarnpkg.com/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" dependencies: core-util-is "~1.0.0" is-typedarray@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" is-utf8@^0.2.0: version "0.2.1" - resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" is-windows@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" isarray@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" isbinaryfile@^3.0.0: version "3.0.2" - resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" isexe@^1.1.1: version "1.1.2" - resolved "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" isobject@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" dependencies: isarray "1.0.0" isstream@~0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" istextorbinary@2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" + resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" dependencies: binaryextensions "1 || 2" editions "^1.1.1" @@ -3411,55 +3472,55 @@ istextorbinary@2.1.0: jade@0.26.3: version "0.26.3" - resolved "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" + resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" dependencies: commander "0.6.1" mkdirp "0.3.0" jju@^1.1.0: version "1.3.0" - resolved "https://registry.npmjs.org/jju/-/jju-1.3.0.tgz#dadd9ef01924bc728b03f2f7979bdbd62f7a2aaa" + resolved "https://registry.yarnpkg.com/jju/-/jju-1.3.0.tgz#dadd9ef01924bc728b03f2f7979bdbd62f7a2aaa" jmespath@0.15.0: version "0.15.0" - resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" jodid25519@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" dependencies: jsbn "~0.1.0" jquery@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/jquery/-/jquery-3.1.1.tgz#347c1c21c7e004115e0a4da32cece041fad3c8a3" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.1.1.tgz#347c1c21c7e004115e0a4da32cece041fad3c8a3" js-string-escape@^1.0.0, js-string-escape@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" + resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" js-tokens@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: - version "3.8.1" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.1.tgz#782ba50200be7b9e5a8537001b7804db3ad02628" + version "3.8.2" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.2.tgz#02d3e2c0f6beab20248d412c352203827d786721" dependencies: argparse "^1.0.7" esprima "^3.1.1" jsbn@~0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" jsesc@~0.5.0: version "0.5.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" json-api-mock-server@0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/json-api-mock-server/-/json-api-mock-server-0.1.1.tgz#00acb22ac58127e87fa9a172159cd8ed558e8106" + resolved "https://registry.yarnpkg.com/json-api-mock-server/-/json-api-mock-server-0.1.1.tgz#00acb22ac58127e87fa9a172159cd8ed558e8106" dependencies: body-parser "^1.15.2" chalk "^1.1.1" @@ -3470,94 +3531,95 @@ json-api-mock-server@0.1.1: json-parse-helpfulerror@^1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz#13f14ce02eed4e981297b64eb9e3b932e2dd13dc" + resolved "https://registry.yarnpkg.com/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz#13f14ce02eed4e981297b64eb9e3b932e2dd13dc" dependencies: jju "^1.1.0" json-schema@0.2.3: version "0.2.3" - resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: jsonify "~0.0.0" json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" json3@3.3.2: version "3.3.2" - resolved "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" json5@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" jsonapi-validator@^2.1.1: version "2.2.0" - resolved "https://registry.npmjs.org/jsonapi-validator/-/jsonapi-validator-2.2.0.tgz#07f9bdb6d118c1e728fa77280605fa9b527f8c66" + resolved "https://registry.yarnpkg.com/jsonapi-validator/-/jsonapi-validator-2.2.0.tgz#07f9bdb6d118c1e728fa77280605fa9b527f8c66" dependencies: ajv "^4.1.3" yargs "^5.0.0" jsonfile@^2.1.0: version "2.4.0" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" optionalDependencies: graceful-fs "^4.1.6" jsonify@~0.0.0: version "0.0.0" - resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" jsonpointer@^4.0.0: version "4.0.1" - resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" jsprim@^1.2.2: - version "1.3.1" - resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + version "1.4.0" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" dependencies: + assert-plus "1.0.0" extsprintf "1.0.2" json-schema "0.2.3" verror "1.3.6" kew@~0.7.0: version "0.7.0" - resolved "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" + resolved "https://registry.yarnpkg.com/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" kind-of@^3.0.2: version "3.1.0" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" dependencies: is-buffer "^1.0.2" klassy@^0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/klassy/-/klassy-0.1.3.tgz#c31d5756d583197d75f582b6e692872be497067f" + resolved "https://registry.yarnpkg.com/klassy/-/klassy-0.1.3.tgz#c31d5756d583197d75f582b6e692872be497067f" klaw@^1.0.0: version "1.3.1" - resolved "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" optionalDependencies: graceful-fs "^4.1.9" lazy-cache@^1.0.3: version "1.0.4" - resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" lcid@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" dependencies: invert-kv "^1.0.0" leek@0.0.24: version "0.0.24" - resolved "https://registry.npmjs.org/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" + resolved "https://registry.yarnpkg.com/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" dependencies: debug "^2.1.0" lodash.assign "^3.2.0" @@ -3565,34 +3627,34 @@ leek@0.0.24: leven@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" + resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" levn@^0.3.0, levn@~0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" linkify-it@^2.0.0: version "2.0.3" - resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" dependencies: uc.micro "^1.0.1" linkify-it@~1.2.0: version "1.2.4" - resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" dependencies: uc.micro "^1.0.1" livereload-js@^2.2.2: version "2.2.2" - resolved "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" + resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" load-json-file@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -3600,70 +3662,70 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -loader.js@^4.0.10: - version "4.1.0" - resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.1.0.tgz#1d0897a62f8b7375d3d9cd1ae6acf798c36c1ffe" +loader.js@^4.2.2: + version "4.2.3" + resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.2.3.tgz#845228877aa5317209e41f6c00d9bab36a6a4808" lockfile@~1.0.1: version "1.0.3" - resolved "https://registry.npmjs.org/lockfile/-/lockfile-1.0.3.tgz#2638fc39a0331e9cac1a04b71799931c9c50df79" + resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.3.tgz#2638fc39a0331e9cac1a04b71799931c9c50df79" lodash-node@^3.2.0: version "3.10.2" - resolved "https://registry.npmjs.org/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" + resolved "https://registry.yarnpkg.com/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" lodash._arraycopy@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" + resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" lodash._arrayeach@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" + resolved "https://registry.yarnpkg.com/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" lodash._baseassign@^3.0.0: version "3.2.0" - resolved "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" dependencies: lodash._basecopy "^3.0.0" lodash.keys "^3.0.0" lodash._basecopy@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" lodash._baseflatten@^3.0.0: version "3.1.4" - resolved "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" + resolved "https://registry.yarnpkg.com/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" dependencies: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" lodash._basefor@^3.0.0: version "3.0.3" - resolved "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" + resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" lodash._baseindexof@*: version "3.1.0" - resolved "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" + resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" lodash._baseuniq@~4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" + resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" dependencies: lodash._createset "~4.0.0" lodash._root "~3.0.0" lodash._bindcallback@*, lodash._bindcallback@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" lodash._cacheindexof@*: version "3.0.2" - resolved "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" + resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" lodash._createassigner@^3.0.0: version "3.1.1" - resolved "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" dependencies: lodash._bindcallback "^3.0.0" lodash._isiterateecall "^3.0.0" @@ -3671,33 +3733,33 @@ lodash._createassigner@^3.0.0: lodash._createcache@*: version "3.1.2" - resolved "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" + resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" dependencies: lodash._getnative "^3.0.0" lodash._createset@~4.0.0: version "4.0.3" - resolved "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" + resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" lodash._getnative@*, lodash._getnative@^3.0.0: version "3.9.1" - resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" lodash._isiterateecall@^3.0.0: version "3.0.9" - resolved "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" lodash._reinterpolate@~3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" lodash._root@~3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" lodash.assign@^3.2.0: version "3.2.0" - resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" dependencies: lodash._baseassign "^3.0.0" lodash._createassigner "^3.0.0" @@ -3705,44 +3767,44 @@ lodash.assign@^3.2.0: lodash.assign@^4.1.0, lodash.assign@^4.2.0: version "4.2.0" - resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" lodash.assignin@^4.1.0: version "4.2.0" - resolved "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" lodash.clonedeep@^4.4.1, lodash.clonedeep@~4.5.0: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" lodash.debounce@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" dependencies: lodash._getnative "^3.0.0" lodash.find@^4.5.1: version "4.6.0" - resolved "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" + resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" lodash.flatten@^3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" dependencies: lodash._baseflatten "^3.0.0" lodash._isiterateecall "^3.0.0" lodash.isarguments@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" lodash.isarray@^3.0.0: version "3.0.4" - resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" lodash.isplainobject@^3.0.0: version "3.2.0" - resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" dependencies: lodash._basefor "^3.0.0" lodash.isarguments "^3.0.0" @@ -3750,11 +3812,11 @@ lodash.isplainobject@^3.0.0: lodash.istypedarray@^3.0.0: version "3.0.6" - resolved "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" + resolved "https://registry.yarnpkg.com/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" lodash.keys@^3.0.0: version "3.1.2" - resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" dependencies: lodash._getnative "^3.0.0" lodash.isarguments "^3.0.0" @@ -3762,14 +3824,14 @@ lodash.keys@^3.0.0: lodash.keysin@^3.0.0: version "3.0.8" - resolved "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" + resolved "https://registry.yarnpkg.com/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" dependencies: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" lodash.merge@^3.3.2: version "3.3.2" - resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz#0d90d93ed637b1878437bb3e21601260d7afe994" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-3.3.2.tgz#0d90d93ed637b1878437bb3e21601260d7afe994" dependencies: lodash._arraycopy "^3.0.0" lodash._arrayeach "^3.0.0" @@ -3785,92 +3847,92 @@ lodash.merge@^3.3.2: lodash.merge@^4.3.0, lodash.merge@^4.4.0, lodash.merge@^4.5.1: version "4.6.0" - resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" lodash.omit@^4.1.0: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" + resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" lodash.restparam@*, lodash.restparam@^3.0.0: version "3.6.1" - resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" lodash.template@^4.2.5: version "4.4.0" - resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings "^4.0.0" lodash.templatesettings@^4.0.0: version "4.1.0" - resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" dependencies: lodash._reinterpolate "~3.0.0" lodash.toplainobject@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz#28790ad942d293d78aa663a07ecf7f52ca04198d" + resolved "https://registry.yarnpkg.com/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz#28790ad942d293d78aa663a07ecf7f52ca04198d" dependencies: lodash._basecopy "^3.0.0" lodash.keysin "^3.0.0" lodash.union@~4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" lodash.uniq@^4.2.0, lodash.uniq@~4.5.0: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" lodash.without@~4.4.0: version "4.4.0" - resolved "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" + resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" - resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.3.0, lodash@^4.6.1: version "4.17.4" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" lodash@~1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/lodash/-/lodash-1.2.1.tgz#ed47b16e46f06b2b40309b68e9163c17e93ea304" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.2.1.tgz#ed47b16e46f06b2b40309b68e9163c17e93ea304" lodash@~3.5.0: version "3.5.0" - resolved "https://registry.npmjs.org/lodash/-/lodash-3.5.0.tgz#19bb3f4d51278f0b8c818ed145c74ecf9fe40e6d" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.5.0.tgz#19bb3f4d51278f0b8c818ed145c74ecf9fe40e6d" longest@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" lru-cache@2: version "2.7.3" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" lru-cache@^4.0.0, lru-cache@^4.0.1: version "4.0.2" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" dependencies: pseudomap "^1.0.1" yallist "^2.0.0" make-array@^0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" + resolved "https://registry.yarnpkg.com/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" makeerror@1.0.x: version "1.0.11" - resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" dependencies: tmpl "1.0.x" markdown-it-terminal@0.0.4: version "0.0.4" - resolved "https://registry.npmjs.org/markdown-it-terminal/-/markdown-it-terminal-0.0.4.tgz#3f2ce624ba2ca964a78b8b388d605ee330de9ced" + resolved "https://registry.yarnpkg.com/markdown-it-terminal/-/markdown-it-terminal-0.0.4.tgz#3f2ce624ba2ca964a78b8b388d605ee330de9ced" dependencies: ansi-styles "^2.1.0" cardinal "^0.5.0" @@ -3880,7 +3942,7 @@ markdown-it-terminal@0.0.4: markdown-it@8.1.0: version "8.1.0" - resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-8.1.0.tgz#38902d4e7bac2260c073eb67be623211fbb2c2e3" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.1.0.tgz#38902d4e7bac2260c073eb67be623211fbb2c2e3" dependencies: argparse "^1.0.7" entities "~1.1.1" @@ -3890,7 +3952,7 @@ markdown-it@8.1.0: markdown-it@^4.3.0, markdown-it@^4.4.0: version "4.4.0" - resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" dependencies: argparse "~1.0.2" entities "~1.1.1" @@ -3900,53 +3962,57 @@ markdown-it@^4.3.0, markdown-it@^4.4.0: matcher-collection@^1.0.0, matcher-collection@^1.0.1: version "1.0.4" - resolved "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.4.tgz#2f66ae0869996f29e43d0b62c83dd1d43e581755" + resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-1.0.4.tgz#2f66ae0869996f29e43d0b62c83dd1d43e581755" dependencies: minimatch "^3.0.2" md5-hex@^1.0.2, md5-hex@^1.2.1: version "1.3.0" - resolved "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" + resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" dependencies: md5-o-matic "^0.1.1" md5-o-matic@^0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" + resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" mdn-links@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" + resolved "https://registry.yarnpkg.com/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" mdurl@^1.0.1, mdurl@~1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" media-typer@0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" -memory-streams@^0.1.0: +mem@^0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/memory-streams/-/memory-streams-0.1.1.tgz#ed561f0ba1f649396459c76683819fa1a97d488d" + resolved "https://registry.yarnpkg.com/mem/-/mem-0.1.1.tgz#24df988c3102b03c074c1b296239c5b2e6647825" + +memory-streams@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.2.tgz#273ff777ab60fec599b116355255282cca2c50c2" dependencies: readable-stream "~1.0.2" merge-descriptors@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" merge@^1.1.3, merge@^1.2.0, merge@~1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" methods@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" micromatch@^2.1.5, micromatch@^2.3.7: version "2.3.11" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" dependencies: arr-diff "^2.0.0" array-unique "^0.2.1" @@ -3964,87 +4030,87 @@ micromatch@^2.1.5, micromatch@^2.3.7: "mime-db@>= 1.24.0 < 2", mime-db@~1.26.0: version "1.26.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: version "2.1.14" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" dependencies: mime-db "~1.26.0" mime-types@~1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" mime@1.3.4, mime@^1.2.11: version "1.3.4" - resolved "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" mime@~1.2.11: version "1.2.11" - resolved "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" "minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3: version "3.0.3" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" dependencies: brace-expansion "^1.0.0" minimatch@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz#e0dd2120b49e1b724ce8d714c520822a9438576d" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-1.0.0.tgz#e0dd2120b49e1b724ce8d714c520822a9438576d" dependencies: lru-cache "2" sigmund "~1.0.0" minimatch@^2.0.1, minimatch@^2.0.3, minimatch@^2.0.8: version "2.0.10" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" dependencies: brace-expansion "^1.0.0" minimatch@~0.2.11: version "0.2.14" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" dependencies: lru-cache "2" sigmund "~1.0.0" minimist@0.0.8, minimist@~0.0.1: version "0.0.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" minimist@^1.1.0, minimist@^1.1.1: version "1.2.0" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" mkdirp@0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" mkdirp@0.5.0: version "0.5.0" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" dependencies: minimist "0.0.8" mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" mkdirp@~0.3.5: version "0.3.5" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" mktemp@^0.4.0, mktemp@~0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" + resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" mocha-only-detector@0.0.2: version "0.0.2" - resolved "https://registry.npmjs.org/mocha-only-detector/-/mocha-only-detector-0.0.2.tgz#00f7dde6f949cf68a3cc92bdacff997b87e4b1d1" + resolved "https://registry.yarnpkg.com/mocha-only-detector/-/mocha-only-detector-0.0.2.tgz#00f7dde6f949cf68a3cc92bdacff997b87e4b1d1" dependencies: esprima "^1.2.2" esprimaq "^0.0.1" @@ -4052,7 +4118,7 @@ mocha-only-detector@0.0.2: mocha@2.4.5: version "2.4.5" - resolved "https://registry.npmjs.org/mocha/-/mocha-2.4.5.tgz#151768dd2875eb51bc8295e9800026e9f2bb398f" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.4.5.tgz#151768dd2875eb51bc8295e9800026e9f2bb398f" dependencies: commander "2.3.0" debug "2.2.0" @@ -4066,17 +4132,17 @@ mocha@2.4.5: moment-timezone@^0.3.0: version "0.3.1" - resolved "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" + resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" dependencies: moment ">= 2.6.0" "moment@>= 2.6.0": version "2.17.1" - resolved "https://registry.npmjs.org/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" morgan@^1.5.2, morgan@^1.7.0: version "1.8.1" - resolved "https://registry.npmjs.org/morgan/-/morgan-1.8.1.tgz#f93023d3887bd27b78dfd6023cea7892ee27a4b1" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.8.1.tgz#f93023d3887bd27b78dfd6023cea7892ee27a4b1" dependencies: basic-auth "~1.1.0" debug "2.6.1" @@ -4086,46 +4152,46 @@ morgan@^1.5.2, morgan@^1.7.0: mout@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/mout/-/mout-1.0.0.tgz#9bdf1d4af57d66d47cb353a6335a3281098e1501" + resolved "https://registry.yarnpkg.com/mout/-/mout-1.0.0.tgz#9bdf1d4af57d66d47cb353a6335a3281098e1501" ms@0.7.1: version "0.7.1" - resolved "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" ms@0.7.2: version "0.7.2" - resolved "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" mustache@^2.2.1: version "2.3.0" - resolved "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" + resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" mute-stream@0.0.5: version "0.0.5" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" mute-stream@0.0.6, mute-stream@~0.0.4: version "0.0.6" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" natives@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31" + resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31" negotiator@0.6.1: version "0.6.1" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" node-fetch@^1.3.3: version "1.6.3" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" dependencies: encoding "^0.1.11" is-stream "^1.0.1" node-gyp@~3.4.0: version "3.4.0" - resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-3.4.0.tgz#dda558393b3ecbbe24c9e6b8703c71194c63fa36" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.4.0.tgz#dda558393b3ecbbe24c9e6b8703c71194c63fa36" dependencies: fstream "^1.0.0" glob "^7.0.3" @@ -4144,15 +4210,15 @@ node-gyp@~3.4.0: node-int64@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" node-modules-path@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" + resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" node-notifier@^5.0.1: version "5.0.2" - resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-5.0.2.tgz#4438449fe69e321f941cef943986b0797032701b" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.0.2.tgz#4438449fe69e321f941cef943986b0797032701b" dependencies: growly "^1.3.0" semver "^5.3.0" @@ -4161,21 +4227,21 @@ node-notifier@^5.0.1: node-uuid@~1.4.0, node-uuid@~1.4.7: version "1.4.7" - resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" "nopt@2 || 3", nopt@^3.0.1, nopt@^3.0.3, nopt@~3.0.6: version "3.0.6" - resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: abbrev "1" normalize-git-url@~3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/normalize-git-url/-/normalize-git-url-3.0.2.tgz#8e5f14be0bdaedb73e07200310aa416c27350fc4" + resolved "https://registry.yarnpkg.com/normalize-git-url/-/normalize-git-url-3.0.2.tgz#8e5f14be0bdaedb73e07200310aa416c27350fc4" normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, "normalize-package-data@~1.0.1 || ^2.0.0", normalize-package-data@~2.3.5: - version "2.3.5" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" + version "2.3.6" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff" dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -4184,32 +4250,32 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, "normalize-package normalize-path@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" npm-cache-filename@~1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" + resolved "https://registry.yarnpkg.com/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" npm-git-info@^1.0.0: version "1.0.3" - resolved "https://registry.npmjs.org/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" + resolved "https://registry.yarnpkg.com/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" npm-install-checks@~3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-3.0.0.tgz#d4aecdfd51a53e3723b7b2f93b2ee28e307bc0d7" + resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-3.0.0.tgz#d4aecdfd51a53e3723b7b2f93b2ee28e307bc0d7" dependencies: semver "^2.3.0 || 3.x || 4 || 5" "npm-package-arg@^3.0.0 || ^4.0.0", npm-package-arg@^4.0.0, npm-package-arg@^4.1.1, npm-package-arg@~4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.2.0.tgz#809bc61cabf54bd5ff94f6165c89ba8ee88c115c" + version "4.2.1" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" dependencies: hosted-git-info "^2.1.5" semver "^5.1.0" npm-registry-client@~7.2.1: version "7.2.1" - resolved "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-7.2.1.tgz#c792266b088cc313f8525e7e35248626c723db75" + resolved "https://registry.yarnpkg.com/npm-registry-client/-/npm-registry-client-7.2.1.tgz#c792266b088cc313f8525e7e35248626c723db75" dependencies: concat-stream "^1.5.2" graceful-fs "^4.1.6" @@ -4225,17 +4291,17 @@ npm-registry-client@~7.2.1: npm-run-path@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-1.0.0.tgz#f5c32bf595fe81ae927daec52e82f8b000ac3c8f" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-1.0.0.tgz#f5c32bf595fe81ae927daec52e82f8b000ac3c8f" dependencies: path-key "^1.0.0" npm-user-validate@~0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-0.1.5.tgz#52465d50c2d20294a57125b996baedbf56c5004b" + resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-0.1.5.tgz#52465d50c2d20294a57125b996baedbf56c5004b" npm@3.10.8: version "3.10.8" - resolved "https://registry.npmjs.org/npm/-/npm-3.10.8.tgz#8f76ff8c6da04b61dd371d554ce40a0b8916c15e" + resolved "https://registry.yarnpkg.com/npm/-/npm-3.10.8.tgz#8f76ff8c6da04b61dd371d554ce40a0b8916c15e" dependencies: abbrev "~1.0.9" ansicolors "~0.3.2" @@ -4311,7 +4377,7 @@ npm@3.10.8: "npmlog@0 || 1 || 2 || 3", "npmlog@~2.0.0 || ~3.1.0": version "3.1.2" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-3.1.2.tgz#2d46fa874337af9498a2f12bb43d8d0be4a36873" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-3.1.2.tgz#2d46fa874337af9498a2f12bb43d8d0be4a36873" dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" @@ -4320,7 +4386,7 @@ npm@3.10.8: npmlog@^4.0.0, npmlog@~4.0.0: version "4.0.2" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" @@ -4329,69 +4395,69 @@ npmlog@^4.0.0, npmlog@~4.0.0: number-is-nan@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" oauth-sign@~0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" oauth-sign@~0.8.1: version "0.8.2" - resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" object-assign@4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" object-component@0.0.3: version "0.0.3" - resolved "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" object.omit@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" dependencies: for-own "^0.1.4" is-extendable "^0.1.1" on-finished@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" dependencies: ee-first "1.1.1" on-headers@~1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" once@^1.3.0, once@^1.3.3, once@~1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" onetime@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" opener@~1.4.1: version "1.4.3" - resolved "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" optimist@^0.6.1: version "0.6.1" - resolved "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" dependencies: minimist "~0.0.1" wordwrap "~0.0.2" optionator@^0.8.1: version "0.8.2" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: deep-is "~0.1.3" fast-levenshtein "~2.0.4" @@ -4402,11 +4468,11 @@ optionator@^0.8.1: options@>=0.0.5: version "0.0.6" - resolved "https://registry.npmjs.org/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" + resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" ora@^0.2.0: version "0.2.3" - resolved "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" + resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" dependencies: chalk "^1.1.1" cli-cursor "^1.0.2" @@ -4415,32 +4481,32 @@ ora@^0.2.0: os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" os-locale@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" dependencies: lcid "^1.0.0" os-shim@^0.1.2: version "0.1.3" - resolved "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" osenv@0, osenv@^0.1.0, osenv@^0.1.3, osenv@~0.1.3: version "0.1.4" - resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" output-file-sync@^1.1.0: version "1.1.2" - resolved "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" dependencies: graceful-fs "^4.1.4" mkdirp "^0.5.1" @@ -4448,7 +4514,7 @@ output-file-sync@^1.1.0: parse-glob@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" dependencies: glob-base "^0.3.0" is-dotfile "^1.0.0" @@ -4457,75 +4523,79 @@ parse-glob@^3.0.4: parse-json@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" dependencies: error-ex "^1.2.0" parse-passwd@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" parsejson@0.0.3: version "0.0.3" - resolved "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" + resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" dependencies: better-assert "~1.0.0" parseqs@0.0.5: version "0.0.5" - resolved "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" dependencies: better-assert "~1.0.0" parseuri@0.0.5: version "0.0.5" - resolved "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" dependencies: better-assert "~1.0.0" parseurl@~1.3.1: version "1.3.1" - resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" path-array@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271" + resolved "https://registry.yarnpkg.com/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271" dependencies: array-index "^1.0.0" path-exists@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" path-exists@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" dependencies: pinkie-promise "^2.0.0" path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" path-is-inside@^1.0.1, path-is-inside@~1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" path-key@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/path-key/-/path-key-1.0.0.tgz#5d53d578019646c0d68800db4e146e6bdc2ac7af" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-1.0.0.tgz#5d53d578019646c0d68800db4e146e6bdc2ac7af" + +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" path-posix@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" path-to-regexp@0.1.7: version "0.1.7" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" path-type@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" dependencies: graceful-fs "^4.1.2" pify "^2.0.0" @@ -4533,11 +4603,11 @@ path-type@^1.0.0: pend@~1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" phantomjs-prebuilt@^2.1.12: version "2.1.14" - resolved "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz#d53d311fcfb7d1d08ddb24014558f1188c516da0" + resolved "https://registry.yarnpkg.com/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz#d53d311fcfb7d1d08ddb24014558f1188c516da0" dependencies: es6-promise "~4.0.3" extract-zip "~1.5.0" @@ -4551,29 +4621,29 @@ phantomjs-prebuilt@^2.1.12: pify@^2.0.0: version "2.3.0" - resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" pinkie-promise@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" - resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" plain-text-box-plot@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/plain-text-box-plot/-/plain-text-box-plot-0.0.1.tgz#d3b2e53071ea6706972318565761242f779c04b8" + resolved "https://registry.yarnpkg.com/plain-text-box-plot/-/plain-text-box-plot-0.0.1.tgz#d3b2e53071ea6706972318565761242f779c04b8" pluralize@^1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" portfinder@^1.0.7: version "1.0.13" - resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" dependencies: async "^1.5.2" debug "^2.2.0" @@ -4581,110 +4651,110 @@ portfinder@^1.0.7: prelude-ls@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" preserve@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" pretender@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/pretender/-/pretender-1.0.0.tgz#9137c38718b4d89814478b7f208f70d3e441a0e9" + resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.0.0.tgz#9137c38718b4d89814478b7f208f70d3e441a0e9" dependencies: fake-xml-http-request "^1.3.0" route-recognizer "^0.1.9" pretender@^1.4.2: version "1.4.2" - resolved "https://registry.npmjs.org/pretender/-/pretender-1.4.2.tgz#dde9995dfdf75b28a3dd7a73cde2f9f612e5e8f4" + resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.4.2.tgz#dde9995dfdf75b28a3dd7a73cde2f9f612e5e8f4" dependencies: fake-xml-http-request "^1.4.0" route-recognizer "^0.2.3" printf@^0.2.3: version "0.2.5" - resolved "https://registry.npmjs.org/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" + resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" private@^0.1.6, private@~0.1.5: version "0.1.7" - resolved "https://registry.npmjs.org/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" process-nextick-args@~1.0.6: version "1.0.7" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" process-relative-require@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" + resolved "https://registry.yarnpkg.com/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" dependencies: node-modules-path "^1.0.0" progress@^1.1.8, progress@~1.1.8: version "1.1.8" - resolved "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" promise-map-series@^0.2.1: version "0.2.3" - resolved "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" + resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" dependencies: rsvp "^3.0.14" promzard@^0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" + resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" dependencies: read "1" proto-list@~1.2.1: version "1.2.4" - resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" proxy-addr@~1.1.3: version "1.1.3" - resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.3.tgz#dc97502f5722e888467b3fa2297a7b1ff47df074" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.3.tgz#dc97502f5722e888467b3fa2297a7b1ff47df074" dependencies: forwarded "~0.1.0" ipaddr.js "1.2.0" pseudomap@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" punycode@1.3.2: version "1.3.2" - resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" punycode@^1.4.1: version "1.4.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" q@^1.1.2: version "1.4.1" - resolved "https://registry.npmjs.org/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" - -qs@6.2.0: - version "6.2.0" - resolved "https://registry.npmjs.org/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b" + resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" -qs@6.2.1, qs@~6.2.0: - version "6.2.1" - resolved "https://registry.npmjs.org/qs/-/qs-6.2.1.tgz#ce03c5ff0935bc1d9d69a9f14cbd18e568d67625" - -qs@^6.2.0, qs@~6.3.0: - version "6.3.1" - resolved "https://registry.npmjs.org/qs/-/qs-6.3.1.tgz#918c0b3bcd36679772baf135b1acb4c1651ed79d" +qs@6.4.0, qs@^6.2.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" qs@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" + resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" + +qs@~6.2.0: + version "6.2.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.3.tgz#1cfcb25c10a9b2b483053ff39f5dfc9233908cfe" + +qs@~6.3.0: + version "6.3.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" querystring@0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" quick-temp@0.1.6, quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5: version "0.1.6" - resolved "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.6.tgz#a6242a15cba9f9cdbd341287b5c569e318eec307" + resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.6.tgz#a6242a15cba9f9cdbd341287b5c569e318eec307" dependencies: mktemp "~0.4.0" rimraf "~2.2.6" @@ -4692,33 +4762,33 @@ quick-temp@0.1.6, quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick qunit-notifications@^0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/qunit-notifications/-/qunit-notifications-0.1.1.tgz#3001afc6a6a77dfbd962ccbcddde12dec5286c09" + resolved "https://registry.yarnpkg.com/qunit-notifications/-/qunit-notifications-0.1.1.tgz#3001afc6a6a77dfbd962ccbcddde12dec5286c09" qunitjs@^1.20.0: version "1.23.1" - resolved "https://registry.npmjs.org/qunitjs/-/qunitjs-1.23.1.tgz#1971cf97ac9be01a64d2315508d2e48e6fd4e719" + resolved "https://registry.yarnpkg.com/qunitjs/-/qunitjs-1.23.1.tgz#1971cf97ac9be01a64d2315508d2e48e6fd4e719" randomatic@^1.1.3: version "1.1.6" - resolved "https://registry.npmjs.org/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" dependencies: is-number "^2.0.2" kind-of "^3.0.2" range-parser@~1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" raw-body@~1.1.0: version "1.1.7" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" dependencies: bytes "1" string_decoder "0.10" raw-body@~2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" dependencies: bytes "2.4.0" iconv-lite "0.4.15" @@ -4726,13 +4796,13 @@ raw-body@~2.2.0: read-cmd-shim@~1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b" + resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b" dependencies: graceful-fs "^4.1.2" read-installed@~4.0.3: version "4.0.3" - resolved "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" + resolved "https://registry.yarnpkg.com/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" dependencies: debuglog "^1.0.1" read-package-json "^2.0.0" @@ -4744,10 +4814,10 @@ read-installed@~4.0.3: graceful-fs "^4.1.2" "read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@~2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-2.0.4.tgz#61ed1b2256ea438d8008895090be84b8e799c853" + version "2.0.5" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.0.5.tgz#f93a64e641529df68a08c64de46389e8a3f88845" dependencies: - glob "^6.0.0" + glob "^7.1.1" json-parse-helpfulerror "^1.0.2" normalize-package-data "^2.0.0" optionalDependencies: @@ -4755,7 +4825,7 @@ read-installed@~4.0.3: read-package-tree@~5.1.5: version "5.1.5" - resolved "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.1.5.tgz#ace7e6381c7684f970aaa98fc7c5d2b666addab6" + resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.1.5.tgz#ace7e6381c7684f970aaa98fc7c5d2b666addab6" dependencies: debuglog "^1.0.1" dezalgo "^1.0.0" @@ -4765,14 +4835,14 @@ read-package-tree@~5.1.5: read-pkg-up@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" dependencies: find-up "^1.0.0" read-pkg "^1.0.0" read-pkg@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" @@ -4780,13 +4850,13 @@ read-pkg@^1.0.0: read@1, read@~1.0.1, read@~1.0.7: version "1.0.7" - resolved "https://registry.npmjs.org/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" + resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@^2, readable-stream@~2.1.5: +"readable-stream@1 || 2", "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@~2.1.5: version "2.1.5" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" dependencies: buffer-shims "^1.0.0" core-util-is "~1.0.0" @@ -4796,11 +4866,10 @@ read@1, read@~1.0.1, read@~1.0.7: string_decoder "~0.10.x" util-deprecate "~1.0.1" -"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.2.2: - version "2.2.3" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.3.tgz#9cf49463985df016c8ae8813097a9293a9b33729" +readable-stream@^2, readable-stream@~2.0.0, readable-stream@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" dependencies: - buffer-shims "^1.0.0" core-util-is "~1.0.0" inherits "~2.0.1" isarray "~1.0.0" @@ -4808,29 +4877,30 @@ read@1, read@~1.0.1, read@~1.0.7: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readable-stream@~1.0.2: - version "1.0.34" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" +readable-stream@^2.2.2: + version "2.2.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.5.tgz#a0b187304e05bab01a4ce2b4cc9c607d5aa1d606" dependencies: + buffer-shims "^1.0.0" core-util-is "~1.0.0" inherits "~2.0.1" - isarray "0.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" string_decoder "~0.10.x" + util-deprecate "~1.0.1" -readable-stream@~2.0.0, readable-stream@~2.0.5: - version "2.0.6" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" +readable-stream@~1.0.2: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" + isarray "0.0.1" string_decoder "~0.10.x" - util-deprecate "~1.0.1" readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" + resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" dependencies: debuglog "^1.0.1" dezalgo "^1.0.0" @@ -4839,7 +4909,7 @@ readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: readline2@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -4847,14 +4917,14 @@ readline2@^1.0.1: realize-package-specifier@~3.0.3: version "3.0.3" - resolved "https://registry.npmjs.org/realize-package-specifier/-/realize-package-specifier-3.0.3.tgz#d0def882952b8de3f67eba5e91199661271f41f4" + resolved "https://registry.yarnpkg.com/realize-package-specifier/-/realize-package-specifier-3.0.3.tgz#d0def882952b8de3f67eba5e91199661271f41f4" dependencies: dezalgo "^1.0.1" npm-package-arg "^4.1.1" recast@0.10.33: version "0.10.33" - resolved "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" dependencies: ast-types "0.8.12" esprima-fb "~15001.1001.0-dev-harmony-fb" @@ -4863,7 +4933,7 @@ recast@0.10.33: recast@^0.10.10, recast@^0.10.29: version "0.10.43" - resolved "https://registry.npmjs.org/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" dependencies: ast-types "0.8.15" esprima-fb "~15001.1001.0-dev-harmony-fb" @@ -4871,27 +4941,27 @@ recast@^0.10.10, recast@^0.10.29: source-map "~0.5.0" recast@^0.11.17, recast@^0.11.3: - version "0.11.22" - resolved "https://registry.npmjs.org/recast/-/recast-0.11.22.tgz#dedeb18fb001a2bbc6ac34475fda53dfe3d47dfa" + version "0.11.23" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" dependencies: - ast-types "0.9.5" + ast-types "0.9.6" esprima "~3.1.0" private "~0.1.5" source-map "~0.5.0" redeyed@~0.5.0: version "0.5.0" - resolved "https://registry.npmjs.org/redeyed/-/redeyed-0.5.0.tgz#7ab000e60ee3875ac115d29edb32c1403c6c25d1" + resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-0.5.0.tgz#7ab000e60ee3875ac115d29edb32c1403c6c25d1" dependencies: esprima-fb "~12001.1.0-dev-harmony-fb" regenerate@^1.2.1: version "1.3.2" - resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" regenerator@0.8.40: version "0.8.40" - resolved "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" + resolved "https://registry.yarnpkg.com/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" dependencies: commoner "~0.10.3" defs "~1.1.0" @@ -4902,14 +4972,14 @@ regenerator@0.8.40: regex-cache@^0.4.2: version "0.4.3" - resolved "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" dependencies: is-equal-shallow "^0.1.3" is-primitive "^2.0.0" regexpu@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" + resolved "https://registry.yarnpkg.com/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" dependencies: esprima "^2.6.0" recast "^0.10.10" @@ -4919,37 +4989,37 @@ regexpu@^1.3.0: regjsgen@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" regjsparser@^0.1.4: version "0.1.5" - resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" dependencies: jsesc "~0.5.0" repeat-element@^1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" repeat-string@^1.5.2: version "1.6.1" - resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" repeating@^1.1.0, repeating@^1.1.2: version "1.1.3" - resolved "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" dependencies: is-finite "^1.0.0" request-progress@~2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" + resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" dependencies: throttleit "^1.0.0" request@2, request@^2.74.0, request@~2.79.0: version "2.79.0" - resolved "https://registry.npmjs.org/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" dependencies: aws-sign2 "~0.6.0" aws4 "^1.2.1" @@ -4974,7 +5044,7 @@ request@2, request@^2.74.0, request@~2.79.0: request@~2.40.0: version "2.40.0" - resolved "https://registry.npmjs.org/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" + resolved "https://registry.yarnpkg.com/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" dependencies: forever-agent "~0.5.0" json-stringify-safe "~5.0.0" @@ -4993,7 +5063,7 @@ request@~2.40.0: request@~2.74.0: version "2.74.0" - resolved "https://registry.npmjs.org/request/-/request-2.74.0.tgz#7693ca768bbb0ea5c8ce08c084a45efa05b892ab" + resolved "https://registry.yarnpkg.com/request/-/request-2.74.0.tgz#7693ca768bbb0ea5c8ce08c084a45efa05b892ab" dependencies: aws-sign2 "~0.6.0" aws4 "^1.2.1" @@ -5019,134 +5089,136 @@ request@~2.74.0: require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" require-main-filename@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" require-uncached@^1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" dependencies: caller-path "^0.1.0" resolve-from "^1.0.0" requires-port@1.x.x: version "1.0.0" - resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" resolve-dir@^0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" dependencies: expand-tilde "^1.2.2" global-modules "^0.2.3" resolve-from@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c" + version "1.3.2" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235" + dependencies: + path-parse "^1.0.5" restore-cursor@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" dependencies: exit-hook "^1.0.0" onetime "^1.0.0" retry@^0.10.0, retry@~0.10.0: version "0.10.1" - resolved "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" right-align@^0.1.1: version "0.1.3" - resolved "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4: - version "2.6.0" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.0.tgz#89b8a0fe432b9ff9ec9a925a00b6cdb3a91bbada" +rimraf@2, rimraf@^2.3.2, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4: + version "2.6.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: glob "^7.0.5" -rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3: +rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.5.1: version "2.5.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" rimraf@~2.1.4: version "2.1.4" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.1.4.tgz#5a6eb62eeda068f51ede50f29b3e5cd22f3d9bb2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.1.4.tgz#5a6eb62eeda068f51ede50f29b3e5cd22f3d9bb2" optionalDependencies: graceful-fs "~1" rimraf@~2.2.6: version "2.2.8" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" rimraf@~2.5.4: version "2.5.4" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" dependencies: glob "^7.0.5" route-recognizer@^0.1.9: version "0.1.11" - resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" + resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" route-recognizer@^0.2.3: version "0.2.10" - resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" + resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.6, rsvp@^3.2.1, rsvp@~3.2.1: version "3.2.1" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" -rsvp@^3.0.14, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3: - version "3.3.3" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.3.3.tgz#34633caaf8bc66ceff4be3c2e1dffd032538a813" +rsvp@^3.0.14, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3, rsvp@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.4.0.tgz#96f397d9c7e294351b3c1456a74b3d0e7542988d" rsvp@~3.0.6: version "3.0.21" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" rsvp@~3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" run-async@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" dependencies: once "^1.3.0" run-async@^2.2.0: version "2.3.0" - resolved "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" dependencies: is-promise "^2.1.0" rx-lite@^3.1.2: version "3.1.2" - resolved "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" rx@^4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" safe-json-parse@~1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" + resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" sane@^1.1.1: version "1.6.0" - resolved "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz#9610c452307a135d29c1fdfe2547034180c46775" + resolved "https://registry.yarnpkg.com/sane/-/sane-1.6.0.tgz#9610c452307a135d29c1fdfe2547034180c46775" dependencies: anymatch "^1.3.0" exec-sh "^0.2.0" @@ -5158,11 +5230,11 @@ sane@^1.1.1: sax@1.1.5, sax@>=0.6.0: version "1.1.5" - resolved "https://registry.npmjs.org/sax/-/sax-1.1.5.tgz#1da50a8d00cdecd59405659f5ff85349fe773743" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.5.tgz#1da50a8d00cdecd59405659f5ff85349fe773743" selenium-webdriver@^3.0.0-beta-2: - version "3.1.0" - resolved "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.1.0.tgz#d76182940cfb991edf4bc1c28318f4e7bc7730df" + version "3.3.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.3.0.tgz#f14d9b04cee9495d4284d22105b189b8305ccca1" dependencies: adm-zip "^0.4.7" rimraf "^2.5.4" @@ -5171,132 +5243,132 @@ selenium-webdriver@^3.0.0-beta-2: "semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0, semver@~5.3.0: version "5.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" semver@^4.1.0, semver@^4.3.1: version "4.3.6" - resolved "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" -send@0.14.2: - version "0.14.2" - resolved "https://registry.npmjs.org/send/-/send-0.14.2.tgz#39b0438b3f510be5dc6f667a11f71689368cdeef" +send@0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" dependencies: - debug "~2.2.0" + debug "2.6.1" depd "~1.1.0" destroy "~1.0.4" encodeurl "~1.0.1" escape-html "~1.0.3" - etag "~1.7.0" - fresh "0.3.0" - http-errors "~1.5.1" + etag "~1.8.0" + fresh "0.5.0" + http-errors "~1.6.1" mime "1.3.4" ms "0.7.2" on-finished "~2.3.0" range-parser "~1.2.0" statuses "~1.3.1" -serve-static@~1.11.2: - version "1.11.2" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.11.2.tgz#2cf9889bd4435a320cc36895c9aa57bd662e6ac7" +serve-static@1.12.1: + version "1.12.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039" dependencies: encodeurl "~1.0.1" escape-html "~1.0.3" parseurl "~1.3.1" - send "0.14.2" + send "0.15.1" set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" -setprototypeof@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" +setprototypeof@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" sha@~2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae" + resolved "https://registry.yarnpkg.com/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae" dependencies: graceful-fs "^4.1.2" readable-stream "^2.0.2" shebang-command@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" shelljs@^0.6.0: version "0.6.1" - resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" shellwords@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14" sigmund@~1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" signal-exit@^3.0.0: version "3.0.2" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" silent-error@^1.0.0, silent-error@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.0.1.tgz#71b7d503d1c6f94882b51b56be879b113cb4822c" + resolved "https://registry.yarnpkg.com/silent-error/-/silent-error-1.0.1.tgz#71b7d503d1c6f94882b51b56be879b113cb4822c" dependencies: debug "^2.2.0" simple-dom@^0.3.0: version "0.3.2" - resolved "https://registry.npmjs.org/simple-dom/-/simple-dom-0.3.2.tgz#0663d10f1556f1500551d518f56e3aba0871371d" + resolved "https://registry.yarnpkg.com/simple-dom/-/simple-dom-0.3.2.tgz#0663d10f1556f1500551d518f56e3aba0871371d" simple-fmt@~0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" + resolved "https://registry.yarnpkg.com/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" simple-is@~0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" + resolved "https://registry.yarnpkg.com/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" slash@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" slice-ansi@0.0.4: version "0.0.4" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" slide@^1.1.3, slide@^1.1.5, slide@~1.1.3, slide@~1.1.6: version "1.1.6" - resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" sntp@0.2.x: version "0.2.4" - resolved "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" dependencies: hoek "0.9.x" sntp@1.x.x: version "1.0.9" - resolved "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" dependencies: hoek "2.x.x" socket.io-adapter@0.5.0: version "0.5.0" - resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" dependencies: debug "2.3.3" socket.io-parser "2.3.1" socket.io-client@1.6.0: version "1.6.0" - resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" dependencies: backo2 "1.0.2" component-bind "1.0.0" @@ -5312,7 +5384,7 @@ socket.io-client@1.6.0: socket.io-parser@2.3.1: version "2.3.1" - resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" dependencies: component-emitter "1.1.2" debug "2.2.0" @@ -5321,7 +5393,7 @@ socket.io-parser@2.3.1: socket.io@1.6.0: version "1.6.0" - resolved "https://registry.npmjs.org/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" dependencies: debug "2.3.3" engine.io "1.8.0" @@ -5333,88 +5405,84 @@ socket.io@1.6.0: sort-object-keys@^1.1.1: version "1.1.2" - resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" + resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" sort-package-json@^1.4.0: version "1.5.0" - resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.5.0.tgz#d71ec7d13fc4d5f26bd87835676097fa6775206e" + resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.5.0.tgz#d71ec7d13fc4d5f26bd87835676097fa6775206e" dependencies: sort-object-keys "^1.1.1" sorted-object@~2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/sorted-object/-/sorted-object-2.0.1.tgz#7d631f4bd3a798a24af1dffcfbfe83337a5df5fc" + resolved "https://registry.yarnpkg.com/sorted-object/-/sorted-object-2.0.1.tgz#7d631f4bd3a798a24af1dffcfbfe83337a5df5fc" source-map-support@^0.2.10: version "0.2.10" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" dependencies: source-map "0.1.32" -source-map-to-comment@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/source-map-to-comment/-/source-map-to-comment-1.1.0.tgz#e518c40bc7399b2e23c8e331a11635a97750e9c3" - source-map-url@^0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" source-map@0.1.32: version "0.1.32" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" dependencies: amdefine ">=0.0.4" -source-map@0.5.x, source-map@^0.5.0, source-map@~0.5.0, source-map@~0.5.1: - version "0.5.6" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" - -source-map@^0.4.2, source-map@^0.4.4: +source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: version "0.4.4" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: amdefine ">=0.0.4" +source-map@^0.5.0, source-map@~0.5.0, source-map@~0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + spawn-args@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" + resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" spawn-sync@^1.0.15: version "1.0.15" - resolved "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" dependencies: concat-stream "^1.4.7" os-shim "^0.1.2" spawnback@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" + resolved "https://registry.yarnpkg.com/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" spdx-correct@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" dependencies: spdx-license-ids "^1.0.2" spdx-expression-parse@~1.0.0: version "1.0.4" - resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" spdx-license-ids@^1.0.2: version "1.2.2" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" sri-toolbox@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" + resolved "https://registry.yarnpkg.com/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" sshpk@^1.7.0: - version "1.10.2" - resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.10.2.tgz#d5a804ce22695515638e798dbe23273de070a5fa" + version "1.11.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77" dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -5429,19 +5497,19 @@ sshpk@^1.7.0: stable@~0.1.3: version "0.1.5" - resolved "https://registry.npmjs.org/stable/-/stable-0.1.5.tgz#08232f60c732e9890784b5bed0734f8b32a887b9" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.5.tgz#08232f60c732e9890784b5bed0734f8b32a887b9" "statuses@>= 1.3.1 < 2", statuses@~1.3.1: version "1.3.1" - resolved "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" string-template@~0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -5449,80 +5517,86 @@ string-width@^1.0.1, string-width@^1.0.2: string-width@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^3.0.0" string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" stringmap@~0.2.2: version "0.2.2" - resolved "http://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" + resolved "https://registry.yarnpkg.com/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" stringset@~0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" + resolved "https://registry.yarnpkg.com/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" stringstream@~0.0.4: version "0.0.5" - resolved "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" strip-ansi@^0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" dependencies: ansi-regex "^0.2.1" strip-ansi@^3.0.0, strip-ansi@^3.0.1, strip-ansi@~3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: ansi-regex "^2.0.0" strip-bom@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" dependencies: is-utf8 "^0.2.0" strip-eof@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" strip-json-comments@~1.0.1: version "1.0.4" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" styled_string@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" + resolved "https://registry.yarnpkg.com/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" + +sum-up@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" + dependencies: + chalk "^1.0.0" supports-color@1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" supports-color@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" supports-color@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: version "1.1.8" - resolved "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" + resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" sync-exec@^0.6.2: version "0.6.2" - resolved "https://registry.npmjs.org/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105" + resolved "https://registry.yarnpkg.com/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105" table@^3.7.8: version "3.8.3" - resolved "https://registry.npmjs.org/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" dependencies: ajv "^4.7.0" ajv-keywords "^1.0.0" @@ -5533,7 +5607,7 @@ table@^3.7.8: tap-parser@^5.1.0: version "5.3.3" - resolved "https://registry.npmjs.org/tap-parser/-/tap-parser-5.3.3.tgz#53ec8a90f275d6fff43f169e56a679502a741185" + resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-5.3.3.tgz#53ec8a90f275d6fff43f169e56a679502a741185" dependencies: events-to-array "^1.0.1" js-yaml "^3.2.7" @@ -5542,7 +5616,7 @@ tap-parser@^5.1.0: tar@^2.0.0, tar@~2.2.1: version "2.2.1" - resolved "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" dependencies: block-stream "*" fstream "^1.0.2" @@ -5550,14 +5624,14 @@ tar@^2.0.0, tar@~2.2.1: temp@0.8.3: version "0.8.3" - resolved "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" + resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" dependencies: os-tmpdir "^1.0.0" rimraf "~2.2.6" testem@^1.8.1: version "1.15.0" - resolved "https://registry.npmjs.org/testem/-/testem-1.15.0.tgz#2e3a9e7ac29f16a20f718eb0c4b12e7a44900675" + resolved "https://registry.yarnpkg.com/testem/-/testem-1.15.0.tgz#2e3a9e7ac29f16a20f718eb0c4b12e7a44900675" dependencies: backbone "^1.1.2" bluebird "^3.4.6" @@ -5587,23 +5661,23 @@ testem@^1.8.1: text-table@~0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" "textextensions@1 || 2": version "2.0.1" - resolved "https://registry.npmjs.org/textextensions/-/textextensions-2.0.1.tgz#be8cf22d65379c151319f88f0335ad8f667abdca" + resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.0.1.tgz#be8cf22d65379c151319f88f0335ad8f667abdca" throttleit@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" + resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" through@^2.3.6, through@^2.3.8, through@~2.3.8: version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" tiny-lr@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.0.3.tgz#386731170ce521263a9d337f769ee8f11e88eb04" + resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.0.3.tgz#386731170ce521263a9d337f769ee8f11e88eb04" dependencies: body "^5.1.0" debug "~2.2.0" @@ -5614,50 +5688,50 @@ tiny-lr@^1.0.3: tmp-sync@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/tmp-sync/-/tmp-sync-1.1.0.tgz#2b38ec94b094ed2515ec02a9aee1f51dd2c9023f" + resolved "https://registry.yarnpkg.com/tmp-sync/-/tmp-sync-1.1.0.tgz#2b38ec94b094ed2515ec02a9aee1f51dd2c9023f" dependencies: fs-sync "^0.2.4" osenv "^0.1.0" tmp@0.0.28: version "0.0.28" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" dependencies: os-tmpdir "~1.0.1" tmp@0.0.30: version "0.0.30" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" dependencies: os-tmpdir "~1.0.1" tmp@^0.0.29: version "0.0.29" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" dependencies: os-tmpdir "~1.0.1" tmpl@1.0.x: version "1.0.4" - resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" to-array@0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" to-fast-properties@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" tough-cookie@>=0.12.0, tough-cookie@~2.3.0: version "2.3.2" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" dependencies: punycode "^1.4.1" tree-sync@^1.1.4: version "1.2.2" - resolved "https://registry.npmjs.org/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" + resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" dependencies: debug "^2.2.0" fs-tree-diff "^0.5.6" @@ -5667,274 +5741,286 @@ tree-sync@^1.1.4: trim-right@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" try-resolve@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" + resolved "https://registry.yarnpkg.com/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" tryit@^1.0.1: version "1.0.3" - resolved "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" tryor@~0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" + resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" tunnel-agent@~0.4.0, tunnel-agent@~0.4.1: version "0.4.3" - resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" - resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" type-check@~0.3.2: version "0.3.2" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" dependencies: prelude-ls "~1.1.2" type-detect@0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" type-detect@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" type-is@~1.6.14: version "1.6.14" - resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" dependencies: media-typer "0.3.0" mime-types "~2.1.13" typedarray@^0.0.6, typedarray@~0.0.5: version "0.0.6" - resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" uglify-js@^2.6, uglify-js@^2.7.0: - version "2.7.5" - resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" + version "2.8.12" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.12.tgz#8a50f5d482243650b7108f6080aa3a6afe2a6c55" dependencies: - async "~0.2.6" source-map "~0.5.1" uglify-to-browserify "~1.0.0" yargs "~3.10.0" uglify-to-browserify@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" uid-number@0.0.6: version "0.0.6" - resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" ultron@1.0.x: version "1.0.2" - resolved "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" umask@~1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" + resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" underscore.string@~2.3.3: version "2.3.3" - resolved "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" underscore@>=1.8.3: version "1.8.3" - resolved "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" unique-filename@~1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" dependencies: unique-slug "^2.0.0" unique-slug@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" dependencies: imurmurhash "^0.1.4" unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" untildify@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" dependencies: os-homedir "^1.0.0" url@0.10.3: version "0.10.3" - resolved "https://registry.npmjs.org/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" dependencies: punycode "1.3.2" querystring "0.2.0" user-home@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" user-home@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" dependencies: os-homedir "^1.0.0" +username@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/username/-/username-2.3.0.tgz#ba37dd53ac7d6225e77730fdd79244f1fc058e1e" + dependencies: + execa "^0.4.0" + mem "^0.1.0" + util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" util-extend@^1.0.1: version "1.0.3" - resolved "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" + resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" utils-merge@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" uuid@3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" uuid@^2.0.1: version "2.0.3" - resolved "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" uuid@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" validate-npm-package-license@*, validate-npm-package-license@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" dependencies: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" -validate-npm-package-name@^2.0.1, validate-npm-package-name@~2.2.2: +validate-npm-package-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + dependencies: + builtins "^1.0.3" + +validate-npm-package-name@~2.2.2: version "2.2.2" - resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-2.2.2.tgz#f65695b22f7324442019a3c7fa39a6e7fd299085" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-2.2.2.tgz#f65695b22f7324442019a3c7fa39a6e7fd299085" dependencies: builtins "0.0.7" vary@~1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" verror@1.3.6: version "1.3.6" - resolved "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" dependencies: extsprintf "1.0.2" walk-sync@^0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: version "0.2.7" - resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" walk-sync@^0.3.0, walk-sync@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.1.tgz#558a16aeac8c0db59c028b73c66f397684ece465" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.1.tgz#558a16aeac8c0db59c028b73c66f397684ece465" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" walker@~1.0.5: version "1.0.7" - resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" dependencies: makeerror "1.0.x" watch@~0.10.0: version "0.10.0" - resolved "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" wcwidth@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" dependencies: defaults "^1.0.3" websocket-driver@>=0.5.1: version "0.6.5" - resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" dependencies: websocket-extensions ">=0.1.1" websocket-extensions@>=0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" which-module@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" which@1, which@^1.2.12, which@^1.2.8, which@^1.2.9, which@~1.2.10, which@~1.2.11: version "1.2.12" - resolved "https://registry.npmjs.org/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" dependencies: isexe "^1.1.1" wide-align@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" dependencies: string-width "^1.0.1" window-size@0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" window-size@^0.1.2: version "0.1.4" - resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" window-size@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" wordwrap@0.0.2: version "0.0.2" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" wordwrap@~0.0.2: version "0.0.3" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" wordwrap@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" wrap-ansi@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" wrappy@1, wrappy@~1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" write-file-atomic@^1.1.2: version "1.3.1" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -5942,7 +6028,7 @@ write-file-atomic@^1.1.2: write-file-atomic@~1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.2.0.tgz#14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.2.0.tgz#14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab" dependencies: graceful-fs "^4.1.2" imurmurhash "^0.1.4" @@ -5950,97 +6036,97 @@ write-file-atomic@~1.2.0: write@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" dependencies: mkdirp "^0.5.1" ws@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" dependencies: options ">=0.0.5" ultron "1.0.x" ws@^1.0.1: - version "1.1.2" - resolved "https://registry.npmjs.org/ws/-/ws-1.1.2.tgz#8a244fa052401e08c9886cf44a85189e1fd4067f" + version "1.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" dependencies: options ">=0.0.5" ultron "1.0.x" wtf-8@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" + resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" xdg-basedir@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" dependencies: os-homedir "^1.0.0" xml2js@0.4.15: version "0.4.15" - resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.15.tgz#95cd03ff2dd144ec28bc6273bf2b2890c581ad0c" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.15.tgz#95cd03ff2dd144ec28bc6273bf2b2890c581ad0c" dependencies: sax ">=0.6.0" xmlbuilder ">=2.4.6" xml2js@^0.4.17: version "0.4.17" - resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" dependencies: sax ">=0.6.0" xmlbuilder "^4.1.0" -xmlbuilder@2.6.2, xmlbuilder@>=2.4.6: +xmlbuilder@2.6.2: version "2.6.2" - resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-2.6.2.tgz#f916f6d10d45dc171b1be2e6e673fb6e0cc35d0a" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-2.6.2.tgz#f916f6d10d45dc171b1be2e6e673fb6e0cc35d0a" dependencies: lodash "~3.5.0" -xmlbuilder@^4.1.0: +xmlbuilder@>=2.4.6, xmlbuilder@^4.1.0: version "4.2.1" - resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" dependencies: lodash "^4.0.0" xmldom@^0.1.19: version "0.1.27" - resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" + resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" xmlhttprequest-ssl@1.5.3: version "1.5.3" - resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" xtend@^4.0.0, xtend@~4.0.0: version "4.0.1" - resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" y18n@^3.2.0, y18n@^3.2.1: version "3.2.1" - resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" yallist@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-2.0.0.tgz#306c543835f09ee1a4cb23b7bce9ab341c91cdd4" + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" yam@0.0.22: version "0.0.22" - resolved "https://registry.npmjs.org/yam/-/yam-0.0.22.tgz#38a76cb79a19284d9206ed49031e359a1340bd06" + resolved "https://registry.yarnpkg.com/yam/-/yam-0.0.22.tgz#38a76cb79a19284d9206ed49031e359a1340bd06" dependencies: fs-extra "^0.30.0" lodash.merge "^4.4.0" yargs-parser@^3.2.0: version "3.2.0" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-3.2.0.tgz#5081355d19d9d0c8c5d81ada908cb4e6d186664f" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-3.2.0.tgz#5081355d19d9d0c8c5d81ada908cb4e6d186664f" dependencies: camelcase "^3.0.0" lodash.assign "^4.1.0" yargs@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-5.0.0.tgz#3355144977d05757dbb86d6e38ec056123b3a66e" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-5.0.0.tgz#3355144977d05757dbb86d6e38ec056123b3a66e" dependencies: cliui "^3.2.0" decamelize "^1.1.1" @@ -6059,7 +6145,7 @@ yargs@^5.0.0: yargs@~3.10.0: version "3.10.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" dependencies: camelcase "^1.0.2" cliui "^2.1.0" @@ -6068,7 +6154,7 @@ yargs@~3.10.0: yargs@~3.27.0: version "3.27.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" dependencies: camelcase "^1.2.1" cliui "^2.1.0" @@ -6079,23 +6165,23 @@ yargs@~3.27.0: yauzl@2.4.1: version "2.4.1" - resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" dependencies: fd-slicer "~1.0.1" yeast@0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" yui@^3.18.1: version "3.18.1" - resolved "https://registry.npmjs.org/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" + resolved "https://registry.yarnpkg.com/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" dependencies: request "~2.40.0" yuidocjs@~0.9.0: version "0.9.0" - resolved "https://registry.npmjs.org/yuidocjs/-/yuidocjs-0.9.0.tgz#d2ff2b37cadf30e3d45385c58f5003e5a83f2723" + resolved "https://registry.yarnpkg.com/yuidocjs/-/yuidocjs-0.9.0.tgz#d2ff2b37cadf30e3d45385c58f5003e5a83f2723" dependencies: express "^4.13.1" graceful-fs "^4.1.2" From 4cf156b3f09007def590eaf8e6e378e7b473f35c Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 14 Mar 2017 13:12:57 -0400 Subject: [PATCH 1843/2527] Refactor the detection / warnings around ember-cli-shims. (#4860) I picked this back up today and got pretty confused by the conditionals here. I found that rewriting them with variable names actually helped my understanding quite a bit. --- index.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 1b484898905..df571c44366 100644 --- a/index.js +++ b/index.js @@ -58,6 +58,10 @@ module.exports = { return; } + var hasShims = !!shims; + var shimsHasEmberDataShims = hasShims && shims.satisfies('< 0.1.0'); + var emberDataNPMWithShimsIncluded = semver.satisfies(version, '^2.3.0-beta.3'); + if (bowerDeps['ember-data']) { this._warn('Please remove `ember-data` from `bower.json`. As of Ember Data 2.3.0, only the NPM package is needed. If you need an ' + 'earlier version of ember-data (< 2.3.0), you can leave this unchanged for now, but we strongly suggest you upgrade your version of Ember Data ' + @@ -65,18 +69,19 @@ module.exports = { this._forceBowerUsage = true; var emberDataBower = checker.for('ember-data', 'bower'); + var emberDataBowerWithShimsIncluded = emberDataBower.satisifies('>= 2.3.0-beta.3'); - if (shims && shims.version && !shims.satisfies('< 0.1.0') && emberDataBower.satisfies('< 2.3.0-beta.3')) { + if (hasShims && !shimsHasEmberDataShims && !emberDataBowerWithShimsIncluded) { throw new SilentError('Using a version of ember-cli-shims greater than or equal to 0.1.0 will cause errors while loading Ember Data < 2.3.0-beta.3 Please update ember-cli-shims from ' + shims.version + ' to 0.0.6'); } - if (shims && shims.version && !shims.satisfies('>= 0.1.0') && emberDataBower.satisfies('>= 2.3.0-beta.3')) { + if (hasShims && shimsHasEmberDataShims && !emberDataBowerWithShimsIncluded) { throw new SilentError('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3.0-beta.3+. Please update ember-cli-shims from ' + shims.version + ' to 0.1.0.'); } } else { // NPM only, but ember-cli-shims does not match - if (shims && shims.version && !shims.satisfies('>= 0.1.0') && semver.satisfies(version, '^2.3.0-beta.3')) { + if (hasShims && shimsHasEmberDataShims && emberDataNPMWithShimsIncluded) { throw new SilentError('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3.0-beta.3+. Please update ember-cli-shims from ' + shims.version + ' to 0.1.0.'); } } From e44824cd97de7988ebd13ef31c7ac132993eec5d Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 14 Mar 2017 11:45:14 -0700 Subject: [PATCH 1844/2527] [PERF] Batch RecordArrays (#4849) --- addon/-private/system/model/internal-model.js | 18 +- addon/-private/system/record-array-manager.js | 260 +++++++++--------- .../adapter-populated-record-array.js | 3 +- .../system/record-arrays/record-array.js | 2 +- addon/-private/system/store/finders.js | 2 +- .../dummy/app/routes/application/template.hbs | 8 + tests/dummy/app/routes/index/template.hbs | 5 - tests/integration/adapter/find-all-test.js | 18 +- tests/integration/debug-adapter-test.js | 17 +- tests/integration/filter-test.js | 8 +- .../integration/record-array-manager-test.js | 115 +++++++- tests/integration/record-array-test.js | 22 +- tests/unit/debug-test.js | 1 - .../adapter-populated-record-array-test.js | 70 ++--- 14 files changed, 330 insertions(+), 219 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 6d101ac1365..a2e86f1caab 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -126,7 +126,7 @@ export default class InternalModel { this._record = null; this._isDestroyed = false; this.isError = false; - this._isUpdatingRecordArrays = false; + this._isUpdatingRecordArrays = false; // used by the recordArrayManager // During dematerialization we don't want to rematerialize the record. The // reason this might happen is that dematerialization removes records from @@ -266,6 +266,20 @@ export default class InternalModel { return this.__implicitRelationships; } + isHiddenFromRecordArrays() { + // During dematerialization we don't want to rematerialize the record. + // recordWasDeleted can cause other records to rematerialize because it + // removes the internal model from the array and Ember arrays will always + // `objectAt(0)` and `objectAt(len -1)` to check whether `firstObject` or + // `lastObject` have changed. When this happens we don't want those + // models to rematerialize their records. + + return this._isDematerializing || + this.isDestroyed || + this.currentState.stateName === 'root.deleted.saved' || + this.isEmpty(); + } + isEmpty() { return this.currentState.isEmpty; } @@ -947,8 +961,6 @@ export default class InternalModel { @private */ updateRecordArrays() { - if (this._isUpdatingRecordArrays) { return; } - this._isUpdatingRecordArrays = true; this.store.recordArrayManager.recordDidChange(this); } diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 292d4b6ef2f..0d422ea4437 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -17,10 +17,7 @@ const { } = Ember; const { - _addRecordToRecordArray, - _recordWasChanged, - _recordWasDeleted, - _flushLoadedRecords, + _flush, array_flatten, array_remove, create, @@ -29,19 +26,13 @@ const { createRecordArray, liveRecordArrayFor, populateLiveRecordArray, - recordArraysForRecord, recordDidChange, - recordWasLoaded, registerFilteredRecordArray, unregisterRecordArray, updateFilter, - updateFilterRecordArray, - updateRecordArrays + updateFilterRecordArray } = heimdall.registerMonitor('recordArrayManager', - '_addInternalModelToRecordArray', - '_recordWasChanged', - '_recordWasDeleted', - '_flushLoadedRecords', + '_flush', 'array_fatten', 'array_remove', 'create', @@ -50,14 +41,11 @@ const { 'createRecordArray', 'liveRecordArrayFor', 'populateLiveRecordArray', - 'recordArraysForRecord', 'recordDidChange', - 'recordWasLoaded', 'registerFilteredRecordArray', 'unregisterRecordArray', 'updateFilter', - 'updateFilterRecordArray', - 'updateRecordArrays' + 'updateFilterRecordArray' ); /** @@ -82,152 +70,166 @@ export default class RecordArrayManager { } }); - this.changedRecords = []; - this.loadedRecords = []; + this._pending = Object.create(null); this._adapterPopulatedRecordArrays = []; } recordDidChange(internalModel) { - heimdall.increment(recordDidChange); - if (this.changedRecords.push(internalModel) !== 1) { return; } - - emberRun.schedule('actions', this, this.updateRecordArrays); + // TODO: change name + // TODO: track that it was also a change + this.internalModelDidChange(internalModel); } - recordArraysForRecord(internalModel) { - heimdall.increment(recordArraysForRecord); - - return internalModel._recordArrays; + recordWasLoaded(internalModel) { + // TODO: change name + // TODO: track that it was also that it was first loaded + this.internalModelDidChange(internalModel); } - /** - This method is invoked whenever data is loaded into the store by the - adapter or updated by the adapter, or when a record has changed. + internalModelDidChange(internalModel) { + heimdall.increment(recordDidChange); - It updates all record arrays that a record belongs to. + let modelName = internalModel.modelName; - To avoid thrashing, it only runs at most once per run loop. + if (internalModel._pendingRecordArrayManagerFlush) { + return; + } - @method updateRecordArrays - */ - updateRecordArrays() { - heimdall.increment(updateRecordArrays); - let updated = this.changedRecords; - - for (let i = 0, l = updated.length; i < l; i++) { - let internalModel = updated[i]; - - // During dematerialization we don't want to rematerialize the record. - // recordWasDeleted can cause other records to rematerialize because it - // removes the internal model from the array and Ember arrays will always - // `objectAt(0)` and `objectAt(len -1)` to check whether `firstObject` or - // `lastObject` have changed. When this happens we don't want those - // models to rematerialize their records. - if (internalModel._isDematerializing || - internalModel.isDestroyed || - internalModel.currentState.stateName === 'root.deleted.saved') { - this._recordWasDeleted(internalModel); - } else { - this._recordWasChanged(internalModel); - } + internalModel._pendingRecordArrayManagerFlush = true - internalModel._isUpdatingRecordArrays = false; + let pending = this._pending; + let models = pending[modelName] = pending[modelName] || []; + if (models.push(internalModel) !== 1) { + return; } - updated.length = 0; + emberRun.schedule('actions', this, this._flush); } - _recordWasDeleted(internalModel) { - heimdall.increment(_recordWasDeleted); - let recordArrays = internalModel.__recordArrays; + _flush() { + heimdall.increment(_flush); - if (!recordArrays) { return; } + let pending = this._pending; + this._pending = Object.create(null); + let modelsToRemove = []; - recordArrays.forEach(array => array._removeInternalModels([internalModel])); + Object.keys(pending).forEach(modelName => { + let internalModels = pending[modelName]; - internalModel.__recordArrays = null; - } + internalModels.forEach(internalModel => { + // mark internalModels, so they can once again be processed by the + // recordArrayManager + internalModel._pendingRecordArrayManagerFlush = false; + // build up a set of models to ensure we have purged correctly; + if (internalModel.isHiddenFromRecordArrays()) { + modelsToRemove.push(internalModel); + } + }); - _recordWasChanged(internalModel) { - heimdall.increment(_recordWasChanged); - let modelName = internalModel.modelName; - let recordArrays = this.filteredRecordArrays.get(modelName); - let filter; - recordArrays.forEach(array => { - filter = get(array, 'filterFunction'); - this.updateFilterRecordArray(array, filter, modelName, internalModel); - }); - } + // process filteredRecordArrays + if (this.filteredRecordArrays.has(modelName)) { + let recordArrays = this.filteredRecordArrays.get(modelName); + for (let i = 0; i < recordArrays.length; i++) { + this.updateFilterRecordArray(recordArrays[i], modelName, internalModels); + } + } - //Need to update live arrays on loading - recordWasLoaded(internalModel) { - heimdall.increment(recordWasLoaded); - if (this.loadedRecords.push(internalModel) !== 1) { return; } + // TODO: skip if it only changed + // process liveRecordArrays + if (this.liveRecordArrays.has(modelName)) { + this.updateLiveRecordArray(modelName, internalModels); + } - emberRun.schedule('actions', this, this._flushLoadedRecords); + // process adapterPopulatedRecordArrays + if (modelsToRemove.length > 0) { + this.removeFromAdapterPopulatedRecordArrays(modelsToRemove); + } + }); } - _flushLoadedRecords() { - heimdall.increment(_flushLoadedRecords); - let internalModels = this.loadedRecords; + updateLiveRecordArray(modelName, internalModels) { + let array = this.liveRecordArrays.get(modelName); - for (let i = 0, l = internalModels.length; i < l; i++) { - let internalModel = internalModels[i]; - let modelName = internalModel.modelName; + let modelsToAdd = []; + let modelsToRemove = []; - let recordArrays = this.filteredRecordArrays.get(modelName); - let filter; + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; + let isDeleted = internalModel.isHiddenFromRecordArrays(); + let recordArrays = internalModel._recordArrays; - for (let j = 0, rL = recordArrays.length; j < rL; j++) { - let array = recordArrays[j]; - filter = get(array, 'filterFunction'); - this.updateFilterRecordArray(array, filter, modelName, internalModel); + if (!isDeleted && !internalModel.isEmpty()) { + if (!recordArrays.has(array)) { + modelsToAdd.push(internalModel); + recordArrays.add(array); + } } - if (this.liveRecordArrays.has(modelName)) { - let liveRecordArray = this.liveRecordArrays.get(modelName); - this._addInternalModelToRecordArray(liveRecordArray, internalModel); + if (isDeleted) { + modelsToRemove.push(internalModel); + recordArrays.delete(array) } } - this.loadedRecords.length = 0; + if (modelsToAdd.length > 0) { array._pushInternalModels(modelsToAdd); } + if (modelsToRemove.length > 0) { array._removeInternalModels(modelsToRemove); } + } + + removeFromAdapterPopulatedRecordArrays(internalModels) { + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; + let list = internalModel._recordArrays.list; + + for (let j = 0; j < list.length; j++) { + // TODO: group by arrays, so we can batch remove + list[j]._removeInternalModels([internalModel]); + } + + internalModel._recordArrays.clear(); + } } /** Update an individual filter. + @private @method updateFilterRecordArray @param {DS.FilteredRecordArray} array - @param {Function} filter @param {String} modelName - @param {InternalModel} internalModel + @param {Array} internalModels */ - updateFilterRecordArray(array, filter, modelName, internalModel) { + updateFilterRecordArray(array, modelName, internalModels) { heimdall.increment(updateFilterRecordArray); - let shouldBeInArray = filter(internalModel.getRecord()); - let recordArrays = this.recordArraysForRecord(internalModel); - if (shouldBeInArray) { - this._addInternalModelToRecordArray(array, internalModel); - } else { - recordArrays.delete(array); - array._removeInternalModels([internalModel]); - } - } - _addInternalModelToRecordArray(array, internalModel) { - heimdall.increment(_addRecordToRecordArray); - let recordArrays = this.recordArraysForRecord(internalModel); - if (!recordArrays.has(array)) { - array._pushInternalModels([internalModel]); - recordArrays.add(array); + let filter = get(array, 'filterFunction'); + + let shouldBeInAdded = []; + let shouldBeRemoved = []; + + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; + if (internalModel.isHiddenFromRecordArrays() === false && + filter(internalModel.getRecord())) { + if (internalModel._recordArrays.has(array)) { continue; } + shouldBeInAdded.push(internalModel); + internalModel._recordArrays.add(array); + } else { + if (internalModel._recordArrays.delete(array)) { + shouldBeRemoved.push(internalModel); + } + } } + + if (shouldBeInAdded.length > 0) { array._pushInternalModels(shouldBeInAdded); } + if (shouldBeRemoved.length > 0) { array._removeInternalModels(shouldBeRemoved); } } + // TODO: remove, utilize existing flush code but make it flush sync based on 1 modelName syncLiveRecordArray(array, modelName) { assert(`recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); - let hasNoPotentialDeletions = this.changedRecords.length === 0; + let hasNoPotentialDeletions = Object.keys(this._pending).length === 0; let map = this.store._internalModelsFor(modelName); - let hasNoInsertionsOrRemovals = map.length === array.length; + let hasNoInsertionsOrRemovals = get(map, 'length') === get(array, 'length'); /* Ideally the recordArrayManager has knowledge of the changes to be applied to @@ -239,22 +241,28 @@ export default class RecordArrayManager { return; } - this.populateLiveRecordArray(array, modelName); + this.populateLiveRecordArray(array, map.models); } - populateLiveRecordArray(array, modelName) { - assert(`recordArrayManger.populateLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); + // TODO: remove, when syncLiveRecordArray is removed + populateLiveRecordArray(array, internalModels) { heimdall.increment(populateLiveRecordArray); - let modelMap = this.store._internalModelsFor(modelName); - let internalModels = modelMap.models; + let modelsToAdd = []; for (let i = 0; i < internalModels.length; i++) { let internalModel = internalModels[i]; - if (!internalModel.isDeleted() && !internalModel.isEmpty()) { - this._addInternalModelToRecordArray(array, internalModel); + if (!internalModel.isHiddenFromRecordArrays()) { + let recordArrays = internalModel._recordArrays; + + if (!recordArrays.has(array)) { + modelsToAdd.push(internalModel); + recordArrays.add(array); + } } } + + array._pushInternalModels(modelsToAdd); } /** @@ -275,13 +283,7 @@ export default class RecordArrayManager { let modelMap = this.store._internalModelsFor(modelName); let internalModels = modelMap.models; - for (let i = 0; i < internalModels.length; i++) { - let internalModel = internalModels[i]; - - if (!internalModel.isDeleted() && !internalModel.isEmpty()) { - this.updateFilterRecordArray(array, filter, modelName, internalModel); - } - } + this.updateFilterRecordArray(array, filter, internalModels); } /** @@ -385,9 +387,7 @@ export default class RecordArrayManager { heimdall.increment(registerFilteredRecordArray); assert(`recordArrayManger.registerFilteredRecordArray expects modelName not modelClass as the second param, received ${modelName}`, typeof modelName === 'string'); - let recordArrays = this.filteredRecordArrays.get(modelName); - recordArrays.push(array); - + this.filteredRecordArrays.get(modelName).push(array); this.updateFilter(array, modelName, filter); } diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index 78869b879a4..9000fd1ebf3 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -89,7 +89,8 @@ export default RecordArray.extend({ for (let i = 0, l = internalModels.length; i < l; i++) { let internalModel = internalModels[i]; - this.manager.recordArraysForRecord(internalModel).add(this) + + internalModel._recordArrays.add(this); } // TODO: should triggering didLoad event be the last action of the runLoop? diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index 34dcf3cfc6f..0b2d42a82d5 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -155,7 +155,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { /** Adds an internal model to the `RecordArray` without duplicates - @method addInternalModel + @method _pushInternalModels @private @param {InternalModel} internalModel */ diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index addbfe15c57..8cdd6726b17 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -136,7 +136,7 @@ export function _findAll(adapter, store, modelName, sinceToken, options) { store._push(payload); store.didUpdateAll(modelName); - return store.peekAll(modelName); + return recordArray; }, null, 'DS: Extract payload of findAll ${modelName}'); } diff --git a/tests/dummy/app/routes/application/template.hbs b/tests/dummy/app/routes/application/template.hbs index cecd031c69b..fc7f4ae93b2 100644 --- a/tests/dummy/app/routes/application/template.hbs +++ b/tests/dummy/app/routes/application/template.hbs @@ -1,2 +1,10 @@

      Ember Data Performance Test Suite

      +
        +
      • + Tests +
      • +
      • + {{#link-to 'query'}}Query{{/link-to}} +
      • +
      {{outlet}} diff --git a/tests/dummy/app/routes/index/template.hbs b/tests/dummy/app/routes/index/template.hbs index f1b8bec2631..e69de29bb2d 100644 --- a/tests/dummy/app/routes/index/template.hbs +++ b/tests/dummy/app/routes/index/template.hbs @@ -1,5 +0,0 @@ -
        -
      • - {{#link-to 'query'}}Query{{/link-to}} -
      • -
      \ No newline at end of file diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index 8c476cf7a67..ce836f680ac 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -49,20 +49,16 @@ test("When all records for a type are requested, the store should call the adapt } })); - let allRecords; - - run(() => { - store.findAll('person').then((all) => { - allRecords = all; + return run(() => { + return store.findAll('person').then((all) => { + let allRecords = all; assert.equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); assert.equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); - }); - }); - run(() => { - store.findAll('person').then((all) => { - // Only one record array per type should ever be created (identity map) - assert.strictEqual(allRecords, all, "the same record array is returned every time all records of a type are requested"); + return store.findAll('person').then((all) => { + // Only one record array per type should ever be created (identity map) + assert.strictEqual(allRecords, all, "the same record array is returned every time all records of a type are requested"); + }); }); }); }); diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index 76730a7ae13..b1d01a2ce72 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -4,9 +4,8 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var App, store, debugAdapter; -var get = Ember.get; -var run = Ember.run; +let App, store, debugAdapter; +const { get, run } = Ember; module('DS.DebugAdapter', { beforeEach() { @@ -55,23 +54,23 @@ module('DS.DebugAdapter', { } }); -test("Watching Model Types", function(assert) { +test('Watching Model Types', function(assert) { assert.expect(5); - var added = function(types) { + function added(types) { assert.equal(types.length, 1); assert.equal(types[0].name, 'post'); assert.equal(types[0].count, 0); assert.strictEqual(types[0].object, store.modelFor('post')); - }; + } - var updated = function(types) { + function updated(types) { assert.equal(types[0].count, 1); - }; + } debugAdapter.watchModelTypes(added, updated); - run(function() { + run(() => { store.push({ data: { type: 'post', diff --git a/tests/integration/filter-test.js b/tests/integration/filter-test.js index de0aa5ba646..8ac10a0d18d 100644 --- a/tests/integration/filter-test.js +++ b/tests/integration/filter-test.js @@ -238,8 +238,8 @@ test('a Record Array can update its filter', function(assert) { return Ember.RSVP.hash(asyncData).then(records => { assert.contains(recordArray, records.dale); assert.contains(recordArray, records.katz); - assert.without(recordArray, records.bryn); - assert.without(recordArray, dickens); + assert.without(recordArray, dickens); + assert.without(recordArray, records.bryn); run(() => { recordArray.set('filterFunction', hash => { @@ -378,8 +378,8 @@ test('a Record Array can update its filter and notify array observers', function }); assert.equal(didChangeAdded, 2, 'one item is added when going back'); - assert.equal(recordArray.objectAt(didChangeIdx).get('name'), 'Scumbag Demon'); - assert.equal(recordArray.objectAt(didChangeIdx-1).get('name'), 'Scumbag Dale'); + assert.equal(recordArray.objectAt(didChangeIdx).get('name'), 'Scumbag Dale'); + assert.equal(recordArray.objectAt(didChangeIdx+1).get('name'), 'Scumbag Demon'); }); }); }); diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index adac8005b36..31a622ad94c 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -110,24 +110,24 @@ test('destroying the store correctly cleans everything up', function(assert) { assert.equal(allSummary.called.length, 0); assert.equal(adapterPopulatedSummary.called.length, 0); - assert.equal(manager.recordArraysForRecord(internalPersonModel).size, 3, 'expected the person to be a member of 3 recordArrays'); + assert.equal(internalPersonModel._recordArrays.size, 3, 'expected the person to be a member of 3 recordArrays'); Ember.run(filterd2, filterd2.destroy); - assert.equal(manager.recordArraysForRecord(internalPersonModel).size, 2, 'expected the person to be a member of 2 recordArrays'); + assert.equal(internalPersonModel._recordArrays.size, 2, 'expected the person to be a member of 2 recordArrays'); assert.equal(filterd2Summary.called.length, 1); assert.equal(manager.liveRecordArrays.has('person'), true); Ember.run(all, all.destroy); - assert.equal(manager.recordArraysForRecord(internalPersonModel).size, 1, 'expected the person to be a member of 1 recordArrays'); + assert.equal(internalPersonModel._recordArrays.size, 1, 'expected the person to be a member of 1 recordArrays'); assert.equal(allSummary.called.length, 1); assert.equal(manager.liveRecordArrays.has('person'), false); Ember.run(manager, manager.destroy); - assert.equal(manager.recordArraysForRecord(internalPersonModel).size, 0, 'expected the person to be a member of no recordArrays'); + assert.equal(internalPersonModel._recordArrays.size, 0, 'expected the person to be a member of no recordArrays'); assert.equal(filterdSummary.called.length, 1); assert.equal(filterd2Summary.called.length, 1); assert.equal(allSummary.called.length, 1); @@ -135,10 +135,12 @@ test('destroying the store correctly cleans everything up', function(assert) { }); test('Should not filter a store.peekAll() array when a record property is changed', function(assert) { - let populateLiveRecordArray = tap(store.recordArrayManager, 'populateLiveRecordArray'); + let updateLiveRecordArray = tap(store.recordArrayManager, 'updateLiveRecordArray'); let updateFilterRecordArray = tap(store.recordArrayManager, 'updateFilterRecordArray'); - store.peekAll('car'); + let cars = store.peekAll('car'); + + assert.deepEqual(cars.toArray(), []); let car = run(() => { store.push({ @@ -160,15 +162,112 @@ test('Should not filter a store.peekAll() array when a record property is change return store.peekRecord('car', 1); }); - assert.equal(populateLiveRecordArray.called.length, 1); + assert.deepEqual(cars.toArray(), [car]); + + assert.equal(updateLiveRecordArray.called.length, 1); assert.equal(updateFilterRecordArray.called.length, 0); run(() => car.set('model', 'Mini')); - assert.equal(populateLiveRecordArray.called.length, 1); + assert.deepEqual(cars.toArray(), [car]); + + // TODO: differentiate between change + add/remove so we can skip non-filtered record arrays + assert.equal(updateLiveRecordArray.called.length, 2); assert.equal(updateFilterRecordArray.called.length, 0); }); +test('batch liveRecordArray changes', function(assert) { + let cars = store.peekAll('car'); + let arrayContentWillChangeCount = 0; + + cars.arrayContentWillChange = function(startIndex, removeCount, addedCount) { + arrayContentWillChangeCount++; + assert.equal(startIndex, 0, 'expected 0 startIndex'); + assert.equal(removeCount, 0, 'expected 0 removed'); + assert.equal(addedCount, 2, 'expected 2 added'); + }; + + assert.deepEqual(cars.toArray(), []); + assert.equal(arrayContentWillChangeCount, 0, 'expected NO arrayChangeEvents yet'); + + run(() => { + store.push({ + data: [ + { + type: 'car', + id: '1', + attributes: { + make: 'BMC', + model: 'Mini Cooper' + } + }, + { + type: 'car', + id: '2', + attributes: { + make: 'Jeep', + model: 'Wrangler' + } + } + ] + }); + }); + + assert.equal(arrayContentWillChangeCount, 1, 'expected ONE array change event'); + + assert.deepEqual(cars.toArray(), [ + store.peekRecord('car', 1), + store.peekRecord('car', 2) + ]); + + run(() => store.peekRecord('car', 1).set('model', 'Mini')); + + assert.equal(arrayContentWillChangeCount, 1, 'expected ONE array change event'); + + cars.arrayContentWillChange = function(startIndex, removeCount, addedCount) { + arrayContentWillChangeCount++; + assert.equal(startIndex, 2, 'expected a start index of TWO'); + assert.equal(removeCount, 0, 'expected no removes'); + assert.equal(addedCount, 1, 'expected ONE add'); + }; + + arrayContentWillChangeCount = 0; + + run(() => { + store.push({ + data: [ + { + type: 'car', + id: 2, // this ID is already present, array wont need to change + attributes: { + make: 'Tesla', + model: 'S' + } + } + ] + }); + }); + + assert.equal(arrayContentWillChangeCount, 0, 'expected NO array change events'); + + run(() => { + store.push({ + data: [ + { + type: 'car', + id: 3, + attributes: { + make: 'Tesla', + model: 'S' + } + } + ] + }); + }); + + assert.equal(arrayContentWillChangeCount, 1, 'expected ONE array change event'); +}); + test('#GH-4041 store#query AdapterPopulatedRecordArrays are removed from their managers instead of retained when #destroy is called', function(assert) { run(() => { store.push({ diff --git a/tests/integration/record-array-test.js b/tests/integration/record-array-test.js index 1bf129bbf37..cd801ced50b 100644 --- a/tests/integration/record-array-test.js +++ b/tests/integration/record-array-test.js @@ -341,31 +341,27 @@ test('a newly created record is removed from a record array when it is deleted', tag: Tag }); let recordArray = store.peekAll('person'); - let scumbag; - - run(function() { - scumbag = store.createRecord('person', { - name: "Scumbag Dale" + let scumbag = run(() => { + return store.createRecord('person', { + name: 'Scumbag Dale' }); }); - assert.equal(get(recordArray, 'length'), 1, "precond - record array already has the first created item"); + assert.equal(get(recordArray, 'length'), 1, 'precond - record array already has the first created item'); // guarantee coalescence - Ember.run(function() { + Ember.run(() => { store.createRecord('person', { name: 'p1' }); store.createRecord('person', { name: 'p2' }); store.createRecord('person', { name: 'p3' }); }); - assert.equal(get(recordArray, 'length'), 4, "precond - record array has the created item"); - assert.equal(recordArray.objectAt(0), scumbag, "item at index 0 is record with id 1"); + assert.equal(get(recordArray, 'length'), 4, 'precond - record array has the created item'); + assert.equal(recordArray.objectAt(0), scumbag, 'item at index 0 is record with id 1'); - run(function() { - scumbag.deleteRecord(); - }); + run(() => scumbag.deleteRecord()); - assert.equal(get(recordArray, 'length'), 3, "record array still has the created item"); + assert.equal(get(recordArray, 'length'), 3, 'record array still has the created item'); }); test("a record array returns undefined when asking for a member outside of its content Array's range", function(assert) { diff --git a/tests/unit/debug-test.js b/tests/unit/debug-test.js index 4a0121fdee5..e399e13d7c9 100644 --- a/tests/unit/debug-test.js +++ b/tests/unit/debug-test.js @@ -44,7 +44,6 @@ test('_debugInfo groups the attributes and relationships correctly', function(as assert.deepEqual(propertyInfo.groups[2].properties, ['posts']); }); - test('_debugInfo supports arbitray relationship types', function(assert) { const MaritalStatus = DS.Model.extend({ name: DS.attr('string') diff --git a/tests/unit/record-arrays/adapter-populated-record-array-test.js b/tests/unit/record-arrays/adapter-populated-record-array-test.js index 4d1e052a9a0..bea0d34070b 100644 --- a/tests/unit/record-arrays/adapter-populated-record-array-test.js +++ b/tests/unit/record-arrays/adapter-populated-record-array-test.js @@ -104,25 +104,21 @@ test('#update uses _update enabling query specific behavior', function(assert) { // TODO: is this method required, i suspect store._query should be refactor so this is not needed test('#_setInternalModels', function(assert) { let didAddRecord = 0; - const manager = { - recordArraysForRecord(record) { - return { - add(array) { - didAddRecord++; - assert.equal(array, recordArray); - } - } - } - }; + function add(array) { + didAddRecord++; + assert.equal(array, recordArray); + } let recordArray = AdapterPopulatedRecordArray.create({ - query: 'some-query', - manager + query: 'some-query' }); let model1 = internalModelFor({ id: 1 }); let model2 = internalModelFor({ id: 2 }); + model1._recordArrays = { add }; + model2._recordArrays = { add }; + assert.equal(didAddRecord, 0, 'no records should have been added yet'); let didLoad = 0; @@ -160,29 +156,29 @@ test('change events when receiving a new query payload', function(assert) { let contentDidChange = 0; let didAddRecord = 0; - const manager = { - recordArraysForRecord(record) { - return { - add(array) { - didAddRecord++; - assert.equal(array, recordArray); - }, - delete(array) { - assert.equal(array, recordArray); - } - }; - } - }; + function add(array) { + didAddRecord++; + assert.equal(array, recordArray); + } + + function del(array) { + assert.equal(array, recordArray); + } let recordArray = AdapterPopulatedRecordArray.create({ - query: 'some-query', - manager + query: 'some-query' }); + let model1 = internalModelFor({ id: '1', name: 'Scumbag Dale' }); + let model2 = internalModelFor({ id: '2', name: 'Scumbag Katz' }) + + model1._recordArrays = { add, delete: del }; + model2._recordArrays = { add, delete: del }; + run(() => { recordArray._setInternalModels([ - internalModelFor({ id: '1', name: 'Scumbag Dale' }), - internalModelFor({ id: '2', name: 'Scumbag Katz' }) + model1, + model2 ], {}); }); @@ -216,11 +212,17 @@ test('change events when receiving a new query payload', function(assert) { contentDidChange = 0; didAddRecord = 0; + let model3 = internalModelFor({ id: '3', name: 'Scumbag Penner' }); + let model4 = internalModelFor({ id: '4', name: 'Scumbag Hamilton' }); + + model3._recordArrays = { add, delete: del }; + model4._recordArrays = { add, delete: del }; + run(() => { // re-query recordArray._setInternalModels([ - internalModelFor({ id: '3', name: 'Scumbag Penner' }), - internalModelFor({ id: '4', name: 'Scumbag Hamilton' }) + model3, + model4 ], {}); }); @@ -254,9 +256,13 @@ test('change events when receiving a new query payload', function(assert) { assert.equal(arrayDidChange, 0, 'record array should not yet have omitted a change event'); assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); + let model5 = internalModelFor({ id: '3', name: 'Scumbag Penner' }) + + model5._recordArrays = { add, delete: del }; + run(() => { recordArray._setInternalModels([ - internalModelFor({ id: '3', name: 'Scumbag Penner' }) + model5 ], {}); }); From 2edaf160a8a437cc989b2e6c980cc9c7d525c2c2 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 15 Mar 2017 14:27:15 -0700 Subject: [PATCH 1845/2527] Tidy up parse-reponse-headers (#4863) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This aims to avoid the following overhead: * forEach + closure * [field, …value] doesn’t really transpile nicely More aggressive approach is possible, maybe someone else has time :) --- .../-private/utils/parse-response-headers.js | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/addon/-private/utils/parse-response-headers.js b/addon/-private/utils/parse-response-headers.js index b63512e3ae9..34d853a4040 100644 --- a/addon/-private/utils/parse-response-headers.js +++ b/addon/-private/utils/parse-response-headers.js @@ -8,17 +8,29 @@ export default function parseResponseHeaders(headersString) { } let headerPairs = headersString.split(CLRF); + for (let i = 0; i < headerPairs.length; i++) { + let header = headerPairs[i]; + let j = 0; + let foundSep = false; - headerPairs.forEach((header) => { - let [field, ...value] = header.split(':'); + for (; j < header.length; j++) { + if (header.charCodeAt(j) === 58 /* ':' */) { + foundSep = true; + break; + } + } + + if (foundSep === false) { + break; + } - field = field.trim(); - value = value.join(':').trim(); + let field = header.substring(0, j).trim(); + let value = header.substring(j + 1, header.length).trim(); if (value) { headers[field] = value; } - }); + } return headers; } From bf2be7fb8628d2432da1b0131ab4dc8c4e9ad515 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 15 Mar 2017 18:07:03 -0700 Subject: [PATCH 1846/2527] make ES6.Classes loose (#4864) * makes profiling easier (methods are not called value) * appears to be a slight performance improvement (although not the motivator) --- index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/index.js b/index.js index df571c44366..5a6c99f3d09 100644 --- a/index.js +++ b/index.js @@ -124,6 +124,7 @@ module.exports = { this.options.babel = this.options.babel || {}; add(this.options.babel, 'blacklist', ['es6.modules', 'useStrict']); + add(this.options.babel, 'loose', ['es6.classes']); add(this.options.babel, 'plugins', require('./lib/stripped-build-plugins')(process.env.EMBER_ENV)); this._hasSetupBabelOptions = true; From 4fe677fee87b81602b914d28bbd94b9b9123daa2 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 15 Mar 2017 19:21:29 -0700 Subject: [PATCH 1847/2527] =?UTF-8?q?don=E2=80=99t=20schedule=20internalMo?= =?UTF-8?q?dels=20for=20relationship=20setup=20if=20there=20is=20not=20rel?= =?UTF-8?q?ationship=20data=20(#4866)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addon/-private/system/store.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 445e883d2fa..4accea042b7 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2392,6 +2392,10 @@ Store = Service.extend({ }, _setupRelationshipsForModel(internalModel, data) { + if (data.relationships === undefined) { + return; + } + if (this._pushedInternalModels.push(internalModel, data) !== 2) { return; } @@ -2788,10 +2792,6 @@ function _commit(adapter, store, operation, snapshot) { } function setupRelationships(store, internalModel, data) { - if (!data.relationships) { - return; - } - internalModel.type.eachRelationship((key, descriptor) => { if (!data.relationships[key]) { return; From 42d3c0871ac94aded3f0cdb5235b5e27303b74c9 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 15 Mar 2017 19:42:19 -0700 Subject: [PATCH 1848/2527] =?UTF-8?q?don=E2=80=99t=20allocate=20InternalMo?= =?UTF-8?q?del.=5F=5Fattributes=20eagerly=20by=20mistake=20(#4867)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addon/-private/system/model/internal-model.js | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index a2e86f1caab..99ecea607db 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -611,12 +611,12 @@ export default class InternalModel { flushChangedAttributes() { heimdall.increment(flushChangedAttributes); this._inFlightAttributes = this._attributes; - this._attributes = Object.create(null); + this._attributes = null; } hasChangedAttributes() { heimdall.increment(hasChangedAttributes); - return Object.keys(this._attributes).length > 0; + return this.__attributes !== null && Object.keys(this.__attributes).length > 0; } /* @@ -730,12 +730,15 @@ export default class InternalModel { } rollbackAttributes() { - let dirtyKeys = Object.keys(this._attributes); + let dirtyKeys; + if (this.hasChangedAttributes()) { + dirtyKeys = Object.keys(this._attributes); + this._attributes = null; + } - this._attributes = Object.create(null); if (get(this, 'isError')) { - this._inFlightAttributes = Object.create(null); + this._inFlightAttributes = null; this.didCleanError(); } @@ -752,12 +755,14 @@ export default class InternalModel { } if (this.isValid()) { - this._inFlightAttributes = Object.create(null); + this._inFlightAttributes = null; } this.send('rolledBack'); - this.record._notifyProperties(dirtyKeys); + if (dirtyKeys && dirtyKeys.length > 0) { + this.record._notifyProperties(dirtyKeys); + } } /* @@ -1016,7 +1021,7 @@ export default class InternalModel { assign(this._data, data); } - this._inFlightAttributes = Object.create(null); + this._inFlightAttributes = null; this.send('didCommit'); this.updateRecordArrays(); @@ -1076,13 +1081,15 @@ export default class InternalModel { _saveWasRejected() { let keys = Object.keys(this._inFlightAttributes); - let attrs = this._attributes; - for (let i=0; i < keys.length; i++) { - if (attrs[keys[i]] === undefined) { - attrs[keys[i]] = this._inFlightAttributes[keys[i]]; + if (keys.length > 0) { + let attrs = this._attributes; + for (let i=0; i < keys.length; i++) { + if (attrs[keys[i]] === undefined) { + attrs[keys[i]] = this._inFlightAttributes[keys[i]]; + } } } - this._inFlightAttributes = Object.create(null); + this._inFlightAttributes = null; } /* @@ -1133,7 +1140,11 @@ export default class InternalModel { let original, i, value, key; let keys = Object.keys(updates); let length = keys.length; - let attrs = this._attributes; + let hasAttrs = this.hasChangedAttributes(); + let attrs; + if (hasAttrs) { + attrs= this._attributes; + } original = assign(Object.create(null), this._data); original = assign(original, this._inFlightAttributes); @@ -1146,7 +1157,7 @@ export default class InternalModel { // this attributes. We never override this value when merging // updates from the backend so we should not sent a change // notification if the server value differs from the original. - if (attrs[key] !== undefined) { + if (hasAttrs === true && attrs[key] !== undefined) { continue; } From 13bbb8c06472410f4653257987c62d8ccf71fa63 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 15 Mar 2017 19:41:44 -0700 Subject: [PATCH 1849/2527] [PERF] make filtered/liveRecord array storage a simple Object.create(null) --- addon/-private/system/record-array-manager.js | 56 +++++++++++-------- .../integration/record-array-manager-test.js | 4 +- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 0d422ea4437..2515337a1f6 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -12,7 +12,6 @@ import { assert } from 'ember-data/-private/debug'; const { get, - MapWithDefault, run: emberRun } = Ember; @@ -25,6 +24,7 @@ const { createFilteredRecordArray, createRecordArray, liveRecordArrayFor, + filteredRecordArraysFor, populateLiveRecordArray, recordDidChange, registerFilteredRecordArray, @@ -40,6 +40,7 @@ const { 'createFilteredRecordArray', 'createRecordArray', 'liveRecordArrayFor', + 'filteredRecordArraysFor', 'populateLiveRecordArray', 'recordDidChange', 'registerFilteredRecordArray', @@ -59,17 +60,8 @@ export default class RecordArrayManager { this.store = options.store; this.isDestroying = false; this.isDestroyed = false; - this.filteredRecordArrays = MapWithDefault.create({ - defaultValue() { return []; } - }); - - this.liveRecordArrays = MapWithDefault.create({ - defaultValue: modelName => { - assert(`liveRecordArrays.get expects modelName not modelClass as the param`, typeof modelName === 'string'); - return this.createRecordArray(modelName); - } - }); - + this._filteredRecordArrays = Object.create(null); + this._liveRecordArrays = Object.create(null); this._pending = Object.create(null); this._adapterPopulatedRecordArrays = []; } @@ -127,8 +119,8 @@ export default class RecordArrayManager { }); // process filteredRecordArrays - if (this.filteredRecordArrays.has(modelName)) { - let recordArrays = this.filteredRecordArrays.get(modelName); + if (this._filteredRecordArrays[modelName]) { + let recordArrays = this.filteredRecordArraysFor(modelName); for (let i = 0; i < recordArrays.length; i++) { this.updateFilterRecordArray(recordArrays[i], modelName, internalModels); } @@ -136,7 +128,7 @@ export default class RecordArrayManager { // TODO: skip if it only changed // process liveRecordArrays - if (this.liveRecordArrays.has(modelName)) { + if (this._liveRecordArrays[modelName]) { this.updateLiveRecordArray(modelName, internalModels); } @@ -148,7 +140,7 @@ export default class RecordArrayManager { } updateLiveRecordArray(modelName, internalModels) { - let array = this.liveRecordArrays.get(modelName); + let array = this.liveRecordArrayFor(modelName); let modelsToAdd = []; let modelsToRemove = []; @@ -298,9 +290,25 @@ export default class RecordArrayManager { assert(`recordArrayManger.liveRecordArrayFor expects modelName not modelClass as the param`, typeof modelName === 'string'); heimdall.increment(liveRecordArrayFor); - return this.liveRecordArrays.get(modelName); + + return this._liveRecordArrays[modelName] || (this._liveRecordArrays[modelName] = this.createRecordArray(modelName)) } + /** + Get the `DS.RecordArray` for a modelName, which contains all loaded records of + given modelName. + + @method filteredRecordArraysFor + @param {String} modelName + @return {DS.RecordArray} + */ + filteredRecordArraysFor(modelName) { + assert(`recordArrayManger.filteredRecordArraysFor expects modelName not modelClass as the param`, typeof modelName === 'string'); + + heimdall.increment(filteredRecordArraysFor); + + return this._filteredRecordArrays[modelName] || (this._filteredRecordArrays[modelName] = []); + } /** Create a `DS.RecordArray` for a modelName. @@ -387,7 +395,7 @@ export default class RecordArrayManager { heimdall.increment(registerFilteredRecordArray); assert(`recordArrayManger.registerFilteredRecordArray expects modelName not modelClass as the second param, received ${modelName}`, typeof modelName === 'string'); - this.filteredRecordArrays.get(modelName).push(array); + this.filteredRecordArraysFor(modelName).push(array); this.updateFilter(array, modelName, filter); } @@ -404,7 +412,7 @@ export default class RecordArrayManager { let modelName = array.modelName; // unregister filtered record array - let recordArrays = this.filteredRecordArrays.get(modelName); + let recordArrays = this.filteredRecordArraysFor(modelName); let removedFromFiltered = remove(recordArrays, array); // remove from adapter populated record array @@ -412,19 +420,19 @@ export default class RecordArrayManager { if (!removedFromFiltered && !removedFromAdapterPopulated) { + let liveRecordArrayForType = this._liveRecordArrays[modelName]; // unregister live record array - if (this.liveRecordArrays.has(modelName)) { - let liveRecordArrayForType = this.liveRecordArrayFor(modelName); + if (liveRecordArrayForType) { if (array === liveRecordArrayForType) { - this.liveRecordArrays.delete(modelName); + delete this._liveRecordArrays[modelName]; } } } } willDestroy() { - this.filteredRecordArrays.forEach(value => flatten(value).forEach(destroy)); - this.liveRecordArrays.forEach(destroy); + Object.keys(this._filteredRecordArrays).forEach(modelName => flatten(this._filteredRecordArrays[modelName]).forEach(destroy)); + Object.keys(this._liveRecordArrays).forEach(modelName => this._liveRecordArrays[modelName].destroy()); this._adapterPopulatedRecordArrays.forEach(destroy); this.isDestroyed = true; } diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index 31a622ad94c..6d9a42ed787 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -117,13 +117,13 @@ test('destroying the store correctly cleans everything up', function(assert) { assert.equal(internalPersonModel._recordArrays.size, 2, 'expected the person to be a member of 2 recordArrays'); assert.equal(filterd2Summary.called.length, 1); - assert.equal(manager.liveRecordArrays.has('person'), true); + assert.equal('person' in manager._liveRecordArrays, true); Ember.run(all, all.destroy); assert.equal(internalPersonModel._recordArrays.size, 1, 'expected the person to be a member of 1 recordArrays'); assert.equal(allSummary.called.length, 1); - assert.equal(manager.liveRecordArrays.has('person'), false); + assert.equal('person' in manager._liveRecordArrays, false); Ember.run(manager, manager.destroy); From 96c147b6460d92e3be575e5afc4d3c0cf87a77df Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 15 Mar 2017 19:52:54 -0700 Subject: [PATCH 1850/2527] remove forEach + closure overhead --- addon/-private/system/record-array-manager.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 2515337a1f6..5c66acca765 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -105,10 +105,10 @@ export default class RecordArrayManager { this._pending = Object.create(null); let modelsToRemove = []; - Object.keys(pending).forEach(modelName => { + for (let modelName in pending) { let internalModels = pending[modelName]; - - internalModels.forEach(internalModel => { + for (let j = 0; j < internalModels.length; j++) { + let internalModel = internalModels[j]; // mark internalModels, so they can once again be processed by the // recordArrayManager internalModel._pendingRecordArrayManagerFlush = false; @@ -116,7 +116,7 @@ export default class RecordArrayManager { if (internalModel.isHiddenFromRecordArrays()) { modelsToRemove.push(internalModel); } - }); + } // process filteredRecordArrays if (this._filteredRecordArrays[modelName]) { @@ -136,7 +136,7 @@ export default class RecordArrayManager { if (modelsToRemove.length > 0) { this.removeFromAdapterPopulatedRecordArrays(modelsToRemove); } - }); + } } updateLiveRecordArray(modelName, internalModels) { From 8b7d19ff0f67668722a28cfab7e6cc8bba032fbc Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 15 Mar 2017 23:55:32 -0700 Subject: [PATCH 1851/2527] =?UTF-8?q?don=E2=80=99t=20constantly=20go=20thr?= =?UTF-8?q?ough=20accessors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addon/-private/system/model/internal-model.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 99ecea607db..01331e33a69 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -854,11 +854,14 @@ export default class InternalModel { if (!this.hasRecord) { return; } - for (let i = 0, l= this._deferredTriggers.length; i Date: Wed, 15 Mar 2017 23:56:39 -0700 Subject: [PATCH 1852/2527] =?UTF-8?q?Don=E2=80=99t=20invoke=20hooks=20that?= =?UTF-8?q?=20have=20no=20functionality?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * tryInvoke needed to invoke these empty methods, merely because they exists * those method had to be super wrapped --- addon/-private/system/model/model.js | 30 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index e947ac94f53..9592b7e56c7 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -463,56 +463,56 @@ const Model = Ember.Object.extend(Ember.Evented, { @event ready */ - ready() {}, + ready: null, /** Fired when the record is loaded from the server. @event didLoad */ - didLoad() {}, + didLoad: null, /** Fired when the record is updated. @event didUpdate */ - didUpdate() {}, + didUpdate: null, /** Fired when a new record is commited to the server. @event didCreate */ - didCreate() {}, + didCreate: null, /** Fired when the record is deleted. @event didDelete */ - didDelete() {}, + didDelete: null, /** Fired when the record becomes invalid. @event becameInvalid */ - becameInvalid() {}, + becameInvalid: null, /** Fired when the record enters the error state. @event becameError */ - becameError() {}, + becameError: null, /** Fired when the record is rolled back. @event rolledBack */ - rolledBack() {}, + rolledBack: null, //TODO Do we want to deprecate these? /** @@ -828,14 +828,18 @@ const Model = Ember.Object.extend(Ember.Evented, { @param {String} name */ trigger(name) { - let length = arguments.length; - let args = new Array(length - 1); + let fn = this[name]; - for (let i = 1; i < length; i++) { - args[i - 1] = arguments[i]; + if (typeof fn === 'function') { + let length = arguments.length; + let args = new Array(length - 1); + + for (let i = 1; i < length; i++) { + args[i - 1] = arguments[i]; + } + fn.apply(this, args) } - Ember.tryInvoke(this, name, args); this._super(...arguments); }, From d7d77b6542ca0a3e505283e6a1835b9201352164 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Thu, 16 Mar 2017 10:25:14 -0700 Subject: [PATCH 1853/2527] More record -> internalModel fixes Within many-array --- addon/-private/system/many-array.js | 12 +++++----- .../-private/system/relationships/has-many.js | 2 +- .../system/relationships/state/has-many.js | 4 ++-- .../relationships/state/relationship.js | 22 +++++++++---------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index fe134d36b63..edf6309027e 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -150,13 +150,13 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { //a hack for not removing new records //TODO remove once we have proper diffing - let newRecords = this.currentState.filter( + let newInternalModels = this.currentState.filter( // only add new records which are not yet in the canonical state of this // relationship (a new record can be in the canonical state if it has // been 'acknowleged' to be in the relationship via a store.push) (internalModel) => internalModel.isNew() && toSet.indexOf(internalModel) === -1 ); - toSet = toSet.concat(newRecords); + toSet = toSet.concat(newInternalModels); // diff to find changes let diff = diffArray(this.currentState, toSet); @@ -186,7 +186,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { }, //TODO(Igor) optimize - internalRemoveRecords(records) { + internalRemoveInternalModels(records) { for (let i=0; i < records.length; i++) { let index = this.currentState.indexOf(records[i]); this.internalReplace(index, 1); @@ -194,7 +194,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { }, //TODO(Igor) optimize - internalAddRecords(records, idx) { + internalAddInternalModels(records, idx) { if (idx === undefined) { idx = this.currentState.length; } @@ -205,10 +205,10 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { let records; if (amt > 0) { records = this.currentState.slice(idx, idx+amt); - this.get('relationship').removeRecords(records); + this.get('relationship').removeInternalModels(records); } if (objects) { - this.get('relationship').addRecords(objects.map(obj => obj._internalModel), idx); + this.get('relationship').addInternalModels(objects.map(obj => obj._internalModel), idx); } }, diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index 76a4ed396f6..89e4570254a 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -154,7 +154,7 @@ export default function hasMany(type, options) { let relationship = this._internalModel._relationships.get(key); relationship.clear(); - relationship.addRecords(records.map(record => get(record, '_internalModel'))); + relationship.addInternalModels(records.map(record => get(record, '_internalModel'))); return relationship.getRecords(); } }).meta(meta); diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index c073c7c7edf..857b98e3df2 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -91,7 +91,7 @@ export default class ManyRelationship extends Relationship { } super.addRecord(record, idx); // make lazy later - this.manyArray.internalAddRecords([record], idx); + this.manyArray.internalAddInternalModels([record], idx); } removeCanonicalRecordFromOwn(record, idx) { @@ -125,7 +125,7 @@ export default class ManyRelationship extends Relationship { //TODO(Igor) not used currently, fix manyArray.currentState.removeAt(idx); } else { - manyArray.internalRemoveRecords([record]); + manyArray.internalRemoveInternalModels([record]); } } diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 46b77713eae..0ca94f9d134 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -7,7 +7,7 @@ const { addCanonicalRecord, addCanonicalRecords, addRecord, - addRecords, + addInternalModels, clear, findLink, flushCanonical, @@ -21,7 +21,7 @@ const { removeRecord, removeRecordFromInverse, removeRecordFromOwn, - removeRecords, + removeInternalModels, setHasData, setHasLoaded, updateLink, @@ -31,7 +31,7 @@ const { 'addCanonicalRecord', 'addCanonicalRecords', 'addRecord', - 'addRecords', + 'addInternalModels', 'clear', 'findLink', 'flushCanonical', @@ -45,7 +45,7 @@ const { 'removeRecord', 'removeRecordFromInverse', 'removeRecordFromOwn', - 'removeRecords', + 'removeInternalModels', 'setHasData', 'setHasLoaded', 'updateLink', @@ -125,15 +125,15 @@ export default class Relationship { } } - removeRecords(records) { - heimdall.increment(removeRecords); - records.forEach((record) => this.removeRecord(record)); + removeInternalModels(internalModels) { + heimdall.increment(removeInternalModels); + internalModels.forEach((intenralModel) => this.removeRecord(intenralModel)); } - addRecords(records, idx) { - heimdall.increment(addRecords); - records.forEach(record => { - this.addRecord(record, idx); + addInternalModels(internalModels, idx) { + heimdall.increment(addInternalModels); + internalModels.forEach(internalModel => { + this.addRecord(internalModel, idx); if (idx !== undefined) { idx++; } From cb73961dc0afc4d09f93730fb77a289c94dbbad4 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Thu, 16 Mar 2017 10:51:05 -0700 Subject: [PATCH 1854/2527] Remove dead code The last call site of this private code was removed in 4de331554a02bd1a8f8c3f37cb78f2ea92f2467f. --- addon/-private/system/many-array.js | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index fe134d36b63..c8e71c7335d 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -7,7 +7,7 @@ import { PromiseArray } from "./promise-proxies"; import { _objectIsAlive } from "./store/common"; import diffArray from './diff-array'; -const { get, set } = Ember; +const { get } = Ember; /** A `ManyArray` is a `MutableArray` that represents the contents of a has-many @@ -212,27 +212,6 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { } }, - /** - @method loadingRecordsCount - @param {Number} count - @private - */ - loadingRecordsCount(count) { - this._loadingRecordsCount = count; - }, - - /** - @method loadedRecord - @private - */ - loadedRecord() { - this._loadingRecordsCount--; - if (this._loadingRecordsCount === 0) { - set(this, 'isLoaded', true); - this.trigger('didLoad'); - } - }, - /** Reloads all of the records in the manyArray. If the manyArray holds a relationship that was originally fetched using a links url From db3823f8dfbe98277387a1d0fa03d8750249711d Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 16 Mar 2017 20:37:40 -0700 Subject: [PATCH 1855/2527] [BUGFIX] ensure the globals build has the correct context in the iife. --- lib/javascripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/javascripts.js b/lib/javascripts.js index 1e54bc75a7f..b87e31d3dc1 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -52,7 +52,7 @@ function collapse(tree, outputFileName) { inputFiles: ['license.js', 'loader.js', '**/*.js'], outputFile: '/' + outputFileName, header: '(function(){ \n"use strict";\n', - footer: '\nrequire("ember-data");\nrequire("ember-load-initializers")["default"](Ember.Application, "ember-data");\n' + dsGlobal + '})();\n' + emberDataShims + footer: '\nrequire("ember-data");\nrequire("ember-load-initializers")["default"](Ember.Application, "ember-data");\n' + dsGlobal + '})(this);\n' + emberDataShims }); } From ba7f4622171f38754407b0cea96f06a810789822 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 17 Mar 2017 08:40:26 -0400 Subject: [PATCH 1856/2527] Fix tests in release branch RE: factoryFor. (#4878) * Update test suite to test 2.4 and 2.8 LTS's. * Ensure factoryFor related tests pass on release branch. Adds various conditionals and updates assertions to match expectations for each of 1.13, 2.4, 2.8, and 2.12. --- config/ember-try.js | 43 +++++++++++++++++++++ tests/integration/injection-test.js | 58 ++++++++++++++++++++++------- 2 files changed, 87 insertions(+), 14 deletions(-) diff --git a/config/ember-try.js b/config/ember-try.js index 982d2b5417f..ac28bfc3075 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -16,6 +16,37 @@ module.exports = { resolutions: { 'ember': '1.13.13' } + }, + npm: { + 'ember-source': null + } + }, + { + name: 'ember-2-4', + bower: { + dependencies: { + 'ember': '~2.4.0' + }, + resolutions: { + 'ember': '~2.4.0' + } + }, + npm: { + 'ember-source': null + } + }, + { + name: 'ember-2-8', + bower: { + dependencies: { + 'ember': '~2.8.0' + }, + resolutions: { + 'ember': '~2.8.0' + } + }, + npm: { + 'ember-source': null } }, { @@ -27,6 +58,9 @@ module.exports = { resolutions: { 'ember': 'release' } + }, + npm: { + 'ember-source': null } }, { @@ -38,6 +72,9 @@ module.exports = { resolutions: { 'ember': 'beta' } + }, + npm: { + 'ember-source': null } }, { @@ -49,6 +86,9 @@ module.exports = { resolutions: { 'ember': 'canary' } + }, + npm: { + 'ember-source': null } }, { @@ -60,6 +100,9 @@ module.exports = { resolutions: { 'ember': 'alpha' } + }, + npm: { + 'ember-source': null } } ] diff --git a/tests/integration/injection-test.js b/tests/integration/injection-test.js index e010029bb33..c24c4bdacbe 100644 --- a/tests/integration/injection-test.js +++ b/tests/integration/injection-test.js @@ -3,30 +3,60 @@ import Ember from 'ember'; import DS from 'ember-data'; import { module, test } from 'qunit'; -let env, originalFactoryFor, originalMODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS; +let env, hasFactoryFor, originalLookupFactory, originalOwnerLookupFactory, originalFactoryFor; +let originalMODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS; const { run } = Ember; +const model = { + isModel: true, + _create() { } +}; const factory = { - isFactory: true, - class: { - isModel: true, - _create() { } - } + class: model }; module('integration/injection factoryFor enabled', { setup() { env = setupStore(); - originalFactoryFor = Ember.getOwner(env.store).factoryFor; - - Ember.getOwner(env.store).factoryFor = function(name) { - return factory; - }; + if (Ember.getOwner) { + let owner = Ember.getOwner(env.store); + + hasFactoryFor = !!owner.factoryFor; + originalFactoryFor = owner.factoryFor; + originalOwnerLookupFactory = owner._lookupFactory; + + if (originalFactoryFor) { + owner.factoryFor = function(/* name */) { + return factory; + }; + } else { + // Ember 2.3 - Ember 2.11 + originalOwnerLookupFactory = owner._lookupFactory; + owner._lookupFactory = function() { + return model; + }; + } + } else { + originalLookupFactory = env.store.container.lookupFactory; + env.store.container.lookupFactory = function() { + return model; + }; + } }, teardown() { - Ember.getOwner(env.store).factoryFor = originalFactoryFor; + if (Ember.getOwner) { + let owner = Ember.getOwner(env.store); + + if (owner.factoryFor) { + owner.factoryFor = originalFactoryFor; + } else { + owner._lookupFactory = originalOwnerLookupFactory; + } + } else { + env.store.container.lookupFactory = originalLookupFactory; + } run(env.store, 'destroy'); } @@ -35,13 +65,13 @@ module('integration/injection factoryFor enabled', { test('modelFactoryFor', function(assert) { const modelFactory = env.store.modelFactoryFor('super-villain'); - assert.equal(modelFactory, factory, 'expected the factory itself to be returned'); + assert.equal(modelFactory, hasFactoryFor ? factory : model, 'expected the factory itself to be returned'); }); test('modelFor', function(assert) { const modelFactory = env.store.modelFor('super-villain'); - assert.equal(modelFactory, factory.class, 'expected the factory itself to be returned'); + assert.equal(modelFactory, model, 'expected the factory itself to be returned'); // TODO: we should deprecate this next line. Resolved state on the class is fraught with peril assert.equal(modelFactory.modelName, 'super-villain', 'expected the factory itself to be returned'); From b5a1c0d82ca8a293c74f3947d5fa853e48cb4904 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 16 Mar 2017 23:16:35 -0700 Subject: [PATCH 1857/2527] ensure context is applied --- lib/javascripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/javascripts.js b/lib/javascripts.js index b87e31d3dc1..5d855477c77 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -52,7 +52,7 @@ function collapse(tree, outputFileName) { inputFiles: ['license.js', 'loader.js', '**/*.js'], outputFile: '/' + outputFileName, header: '(function(){ \n"use strict";\n', - footer: '\nrequire("ember-data");\nrequire("ember-load-initializers")["default"](Ember.Application, "ember-data");\n' + dsGlobal + '})(this);\n' + emberDataShims + footer: '\nrequire("ember-data");\nrequire("ember-load-initializers")["default"](Ember.Application, "ember-data");\n' + dsGlobal + '}).call(this);\n' + emberDataShims }); } From 074d8c6d4553d479fffab23e30d234f33d156ee3 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 17 Mar 2017 17:11:39 -0400 Subject: [PATCH 1858/2527] Update changelog for the Ember Data 2.12.1 release --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e6d614041f..f693e3ed69b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ### Master +### Release 2.12.1 (March 17, 2017) +- [#4875](https://github.com/emberjs/data/pull/4875) [BUGFIX release] ensure the globals build has the correct context in the iife. +- [#4881](https://github.com/emberjs/data/pull/4881) Fix injection-test on the release branch + ### Release 2.12.0 (March 13, 2017) - [#4805](https://github.com/emberjs/data/pull/4805) Don’t redefine findPossibleInverses for each _findInverseFor - [#4808](https://github.com/emberjs/data/pull/4808) Avoid mutating model factory in _modelForMixin. From 82dca9a5485b4b79c4ca48f6e784680f054593b3 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Wed, 8 Mar 2017 09:14:22 -0800 Subject: [PATCH 1859/2527] strip assert with --instrument --- lib/stripped-build-plugins.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 478622b780a..b1d42c44730 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -44,7 +44,7 @@ module.exports = function(environment) { console.warn('NOT STRIPPING HEIMDALL'); } - if (environment === 'production') { + if (environment === 'production' || process.env.INSTRUMENT_HEIMDALL !== 'false') { uniqueAdd(filteredImports, 'ember-data/-private/debug', [ 'assert', 'assertPolymorphicType', From f0453ea614aa8f79192ea1fa3f54bed9efa02ac8 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Tue, 7 Mar 2017 17:18:33 -0800 Subject: [PATCH 1860/2527] Update query perf tests - add option for expanding relationships - make eager materialize materialize included as well --- server/scenarios/default.js | 2 +- tests/dummy/app/models/baz.js | 2 +- .../dummy/app/routes/application/template.hbs | 18 +++++- tests/dummy/app/routes/query/controller.js | 7 ++- tests/dummy/app/routes/query/route.js | 57 ++++++++++++++++--- tests/dummy/app/routes/query/template.hbs | 2 +- tests/dummy/app/serializers/application.js | 4 +- 7 files changed, 76 insertions(+), 16 deletions(-) diff --git a/server/scenarios/default.js b/server/scenarios/default.js index 930772c8dea..d84ed006106 100644 --- a/server/scenarios/default.js +++ b/server/scenarios/default.js @@ -1,6 +1,6 @@ module.exports = function(store) { store.seed('simple', 10000); // 240 - store.seed('complex', 35); + store.seed('complex', 400); store.seed('heavy', 14); }; diff --git a/tests/dummy/app/models/baz.js b/tests/dummy/app/models/baz.js index fbb4ff990fb..168267544cf 100644 --- a/tests/dummy/app/models/baz.js +++ b/tests/dummy/app/models/baz.js @@ -10,5 +10,5 @@ export default Model.extend({ name: attr(), description: attr(), complex: belongsTo('complex', { inverse: 'baz', async: false }), - heavyFoo: belongsTo('heavy-foo', { inverse: 'heavyBaz', async: false }) + heavyFoo: belongsTo('heavy-foo', { inverse: 'baz', async: false }) }); diff --git a/tests/dummy/app/routes/application/template.hbs b/tests/dummy/app/routes/application/template.hbs index fc7f4ae93b2..525fbd3f0fb 100644 --- a/tests/dummy/app/routes/application/template.hbs +++ b/tests/dummy/app/routes/application/template.hbs @@ -1,4 +1,4 @@ -

      Ember Data Performance Test Suite

      +

      {{#link-to 'index'}}Ember Data Performance Test Suite{{/link-to}}

      • Tests @@ -6,5 +6,21 @@
      • {{#link-to 'query'}}Query{{/link-to}}
      • +
      • + {{#link-to 'query' (query-params + modelName='complex' + limit=400 + included='foo,baz' + eagerRelationships=false) + }}2800 models, lazy relationship{{/link-to}} +
      • +
      • + {{#link-to 'query' (query-params + modelName='complex' + limit=400 + included='foo,baz' + eagerRelationships=true) + }}2800 models, eager relationship{{/link-to}} +
      {{outlet}} diff --git a/tests/dummy/app/routes/query/controller.js b/tests/dummy/app/routes/query/controller.js index c182a851873..433dfb32b26 100644 --- a/tests/dummy/app/routes/query/controller.js +++ b/tests/dummy/app/routes/query/controller.js @@ -5,7 +5,10 @@ const { } = Ember; export default Controller.extend({ - queryParams: ['limit', 'modelName'], + queryParams: ['limit', 'modelName', 'included', 'eagerMaterialize', 'eagerRelationships'], limit: 240, - modelName: 'simple' + included: '', + modelName: 'simple', + eagerMaterialize: true, + eagerRelationships: false }); diff --git a/tests/dummy/app/routes/query/route.js b/tests/dummy/app/routes/query/route.js index 2bbafccb4c7..0587d04f38d 100644 --- a/tests/dummy/app/routes/query/route.js +++ b/tests/dummy/app/routes/query/route.js @@ -6,7 +6,6 @@ const { } = Ember; export default Route.extend({ - queryParams: { limit: { refreshModel: true @@ -16,6 +15,12 @@ export default Route.extend({ }, included: { refreshModel: true + }, + eagerMaterialize: { + refreshModel: true + }, + eagerRelationships: { + refreshModel: true } }, @@ -24,18 +29,54 @@ export default Route.extend({ let modelName = params.modelName; delete params.modelName; + let store = this.get('store'); let token = heimdall.start('ember-data'); - return this.get('store').query(modelName, params) + return store.query(modelName, params) .then((records) => { - // RecordArray lazily materializes the records - // We call toArray() to force materialization for benchmarking - // otherwise we would need to consume the RecordArray in our UI - // and clutter our benchmarks and make it harder to time. - records.toArray(); + let modelNames = [modelName, ...params.included.split(',')]; + let recordArrays = null; + + if (params.eagerMaterialize || params.eagerRelationships) { + recordArrays = getRecordArrays(store, ...modelNames); + // RecordArray lazily materializes the records + // We call toArray() to force materialization for benchmarking + // otherwise we would need to consume the RecordArray in our UI + // and clutter our benchmarks and make it harder to time. + materializeRecords(...recordArrays); + } + if (params.eagerRelationships) { + expandAllRelationships(...recordArrays); + } + heimdall.stop(token); - window.result = heimdall.toString(); + self.result = heimdall.toString(); return records; }); } }); + +function getRecordArrays(store, ...modelNames) { + return modelNames.map(modelName => store.peekAll(modelName)); +} + +function materializeRecords(...recordArrays) { + recordArrays.forEach(records => records.toArray()); +} + +function expandAllRelationships(...recordArrays) { + recordArrays.forEach(expandRelationships); +} + + +function expandRelationships(records, seen) { + let obj = records.objectAt(0); + if (!obj) { return; } + + records.objectAt(0).eachRelationship(rel => { + records.forEach(record => { + record._internalModel._relationships.get(rel); + }); + }); +} + diff --git a/tests/dummy/app/routes/query/template.hbs b/tests/dummy/app/routes/query/template.hbs index 31a48f866bf..dc735570a2b 100644 --- a/tests/dummy/app/routes/query/template.hbs +++ b/tests/dummy/app/routes/query/template.hbs @@ -1 +1 @@ -

      Test Complete

      \ No newline at end of file +

      Test Complete

      diff --git a/tests/dummy/app/serializers/application.js b/tests/dummy/app/serializers/application.js index 8ac3fba7ce4..7fb674f33aa 100644 --- a/tests/dummy/app/serializers/application.js +++ b/tests/dummy/app/serializers/application.js @@ -1,7 +1,7 @@ import DS from 'ember-data'; export default DS.JSONAPISerializer.extend({ - keyForRelationship(key) { - return key; + normalizeResponse(store, modelClass, payload, id, requestType) { + return payload; } }); From a38f408202ef8fdc4d9b944956fc17945a69cd25 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Thu, 16 Mar 2017 09:51:08 -0700 Subject: [PATCH 1861/2527] Reify relationships lazily The goal here is to do as little work as we can with relationship payloads until the relationship is actually accessed. In an extreme case, where many relationship payloads are pushed, but no relationships are accessed, all we want to do is stash the payload. --- addon/-private/system/model/internal-model.js | 6 +- addon/-private/system/model/model.js | 20 +- .../relationship-payloads-manager.js | 228 ++++++ .../relationships/relationship-payloads.js | 359 ++++++++++ .../system/relationships/state/create.js | 12 +- .../relationships/state/relationship.js | 35 +- addon/-private/system/store.js | 94 ++- .../records/relationship-changes-test.js | 9 +- .../integration/records/rematerialize-test.js | 6 +- tests/integration/records/unload-test.js | 53 +- .../relationships/has-many-test.js | 11 +- .../inverse-relationships-test.js | 20 +- .../relationships/many-to-many-test.js | 3 +- .../unit/model/relationships/has-many-test.js | 39 + .../relationship-payload-manager-test.js | 678 ++++++++++++++++++ .../relationship-payloads-test.js | 148 ++++ 16 files changed, 1683 insertions(+), 38 deletions(-) create mode 100644 addon/-private/system/relationships/relationship-payloads-manager.js create mode 100644 addon/-private/system/relationships/relationship-payloads.js create mode 100644 tests/unit/system/relationships/relationship-payload-manager-test.js create mode 100644 tests/unit/system/relationships/relationship-payloads-test.js diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 01331e33a69..c30b9b13c39 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -517,7 +517,7 @@ export default class InternalModel { destroy() { assert("Cannot destroy an internalModel while its record is materialized", !this.record || this.record.get('isDestroyed') || this.record.get('isDestroying')); - this.store._removeFromIdMap(this); + this.store._internalModelDestroyed(this); this._isDestroyed = true; } @@ -531,6 +531,8 @@ export default class InternalModel { setupData(data) { heimdall.increment(setupData); + this.store._internalModelDidReceiveRelationshipData(this.modelName, this.id, data.relationships); + let changedKeys; if (this.hasRecord) { @@ -1013,6 +1015,8 @@ export default class InternalModel { */ adapterDidCommit(data) { if (data) { + this.store._internalModelDidReceiveRelationshipData(this.modelName, this.id, data.relationships); + data = data.attributes; } diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 9592b7e56c7..43168b2cb7d 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1315,12 +1315,24 @@ Model.reopenClass({ */ inverseFor(name, store) { let inverseMap = get(this, 'inverseMap'); - if (inverseMap[name]) { + if (inverseMap[name] !== undefined) { return inverseMap[name]; } else { - let inverse = this._findInverseFor(name, store); - inverseMap[name] = inverse; - return inverse; + let relationship = get(this, 'relationshipsByName').get(name); + if (!relationship) { + inverseMap[name] = null; + return null; + } + + let options = relationship.options; + if (options && options.inverse === null) { + // populate the cache with a miss entry so we can skip getting and going + // through `relationshipsByName` + inverseMap[name] = null; + return null; + } + + return inverseMap[name] = this._findInverseFor(name, store); } }, diff --git a/addon/-private/system/relationships/relationship-payloads-manager.js b/addon/-private/system/relationships/relationship-payloads-manager.js new file mode 100644 index 00000000000..60f939e3dfb --- /dev/null +++ b/addon/-private/system/relationships/relationship-payloads-manager.js @@ -0,0 +1,228 @@ +import Ember from 'ember'; +import RelationshipPayloads from './relationship-payloads'; + +const get = Ember.get; + +/** + Manages relationship payloads for a given store, for uninitialized + relationships. Acts as a single source of truth (of payloads) for both sides + of an uninitialized relationship so they can agree on the most up-to-date + payload received without needing too much eager processing when those payloads + are pushed into the store. + + This minimizes the work spent on relationships that are never initialized. + + Once relationships are initialized, their state is managed in a relationship + state object (eg BelongsToRelationship or ManyRelationship). + + + @example + + let relationshipPayloadsManager = new RelationshipPayloadsManager(store); + + const User = DS.Model.extend({ + hobbies: DS.hasMany('hobby') + }); + + const Hobby = DS.Model.extend({ + user: DS.belongsTo('user') + }); + + let userPayload = { + data: { + id: 1, + type: 'user', + relationships: { + hobbies: { + data: [{ + id: 2, + type: 'hobby' + }] + } + } + }, + }; + relationshipPayloadsManager.push('user', 1, userPayload.data.relationships); + + relationshipPayloadsManager.get('hobby', 2, 'user') === { + { + data: { + id: 1, + type: 'user' + } + } + } + + @private + @class RelationshipPayloadsManager +*/ +export default class RelationshipPayloadsManager { + constructor(store) { + this._store = store; + // cache of `RelationshipPayload`s + this._cache = Object.create(null); + } + + /** + Find the payload for the given relationship of the given model. + + Returns the payload for the given relationship, whether raw or computed from + the payload of the inverse relationship. + + @example + + relationshipPayloadsManager.get('hobby', 2, 'user') === { + { + data: { + id: 1, + type: 'user' + } + } + } + + @method + */ + get(modelName, id, relationshipName) { + let modelClass = this._store._modelFor(modelName); + let relationshipsByName = get(modelClass, 'relationshipsByName'); + let relationshipPayloads = this._getRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName, false); + return relationshipPayloads && relationshipPayloads.get(modelName, id, relationshipName); + } + + /** + Push a model's relationships payload into this cache. + + @example + + let userPayload = { + data: { + id: 1, + type: 'user', + relationships: { + hobbies: { + data: [{ + id: 2, + type: 'hobby' + }] + } + } + }, + }; + relationshipPayloadsManager.push('user', 1, userPayload.data.relationships); + + @method + */ + push(modelName, id, relationshipsData) { + if (!relationshipsData) { return; } + + let modelClass = this._store._modelFor(modelName); + let relationshipsByName = get(modelClass, 'relationshipsByName'); + Object.keys(relationshipsData).forEach(key => { + let relationshipPayloads = this._getRelationshipPayloads(modelName, key, modelClass, relationshipsByName, true); + if (relationshipPayloads) { + relationshipPayloads.push(modelName, id, key, relationshipsData[key]); + } + }); + } + + /** + Unload a model's relationships payload. + + @method + */ + unload(modelName, id) { + let modelClass = this._store._modelFor(modelName); + let relationshipsByName = get(modelClass, 'relationshipsByName'); + relationshipsByName.forEach((_, relationshipName) => { + let relationshipPayloads = this._getRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName, false); + if (relationshipPayloads) { + relationshipPayloads.unload(modelName, id, relationshipName); + } + }); + } + + /** + Find the RelationshipPayloads object for the given relationship. The same + RelationshipPayloads object is returned for either side of a relationship. + + @example + + const User = DS.Model.extend({ + hobbies: DS.hasMany('hobby') + }); + + const Hobby = DS.Model.extend({ + user: DS.belongsTo('user') + }); + + relationshipPayloads.get('user', 'hobbies') === relationshipPayloads.get('hobby', 'user'); + + The signature has a somewhat large arity to avoid extra work, such as + a) string maipulation & allocation with `modelName` and + `relationshipName` + b) repeatedly getting `relationshipsByName` via `Ember.get` + + + @private + @method + */ + _getRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName, init) { + if (!relationshipsByName.has(relationshipName)) { return; } + + let key = `${modelName}:${relationshipName}`; + if (!this._cache[key] && init) { + return this._initializeRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName); + } + + return this._cache[key]; + } + + /** + Create the `RelationshipsPayload` for the relationship `modelName`, `relationshipName`, and its inverse. + + @private + @method + */ + _initializeRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName) { + let relationshipMeta = relationshipsByName.get(relationshipName); + let inverseMeta = modelClass.inverseFor(relationshipName, this._store); + + let inverseModelName; + let inverseRelationshipName; + let inverseRelationshipMeta; + + // figure out the inverse relationship; we need two things + // a) the inverse model name + //- b) the name of the inverse relationship + if (inverseMeta) { + inverseRelationshipName = inverseMeta.name + inverseModelName = relationshipMeta.type; + inverseRelationshipMeta = get(inverseMeta.type, 'relationshipsByName').get(inverseRelationshipName); + } else { + // relationship has no inverse + inverseModelName = inverseRelationshipName = ''; + inverseRelationshipMeta = null; + } + + let lhsKey = `${modelName}:${relationshipName}`; + let rhsKey = `${inverseModelName}:${inverseRelationshipName}`; + + // populate the cache for both sides of the relationship, as they both use + // the same `RelationshipPayloads`. + // + // This works out better than creating a single common key, because to + // compute that key we would need to do work to look up the inverse + // + return this._cache[lhsKey] = + this._cache[rhsKey] = + new RelationshipPayloads( + this._store, + modelName, + relationshipName, + relationshipMeta, + inverseModelName, + inverseRelationshipName, + inverseRelationshipMeta + ); + } +} diff --git a/addon/-private/system/relationships/relationship-payloads.js b/addon/-private/system/relationships/relationship-payloads.js new file mode 100644 index 00000000000..65a1b0810eb --- /dev/null +++ b/addon/-private/system/relationships/relationship-payloads.js @@ -0,0 +1,359 @@ +import { assert } from '../../debug'; + +/** + Manages the payloads for both sides of a single relationship, across all model + instances. + + For example, with + + const User = DS.Model.extend({ + hobbies: DS.hasMany('hobby') + }); + + const Hobby = DS.Model.extend({ + user: DS.belongsTo('user') + }); + + let relationshipPayloads = new RelationshipPayloads('user', 'hobbies', 'hobby', 'user'); + + let userPayload = { + data: { + id: 1, + type: 'user', + relationships: { + hobbies: { + data: [{ + id: 2, + type: 'hobby', + }] + } + } + } + }; + + // here we expect the payload of the individual relationship + relationshipPayloads.push('user', 1, 'hobbies', userPayload.data.relationships.hobbies); + + relationshipPayloads.get('user', 1, 'hobbies'); + relationshipPayloads.get('hobby', 2, 'user'); + + @class RelationshipPayloads + @private +*/ +export default class RelationshipPayloads { + constructor(store, modelName, relationshipName, relationshipMeta, inverseModelName, inverseRelationshipName, inverseRelationshipMeta) { + this._store = store; + + this._lhsModelName = modelName; + this._lhsRelationshipName = relationshipName; + this._lhsRelationshipMeta = relationshipMeta; + + this._rhsModelName = inverseModelName; + this._rhsRelationshipName = inverseRelationshipName; + this._rhsRelationshipMeta = inverseRelationshipMeta; + + // a map of id -> payloads for the left hand side of the relationship. + this._lhsPayloads = Object.create(null); + if (modelName !== inverseModelName || relationshipName !== inverseRelationshipName) { + // The common case of a non-reflexive relationship, or a reflexive + // relationship whose inverse is not itself + this._rhsPayloads = Object.create(null); + this._isReflexive = false; + } else { + // Edge case when we have a reflexive relationship to itself + // eg user hasMany friends inverse friends + // + // In this case there aren't really two sides to the relationship, but + // we set `_rhsPayloads = _lhsPayloads` to make things easier to reason + // about + this._rhsPayloads = this._lhsPayloads; + this._isReflexive = true; + } + + // When we push relationship payloads, just stash them in a queue until + // somebody actually asks for one of them. + // + // This is a queue of the relationship payloads that have been pushed for + // either side of this relationship + this._pendingPayloads = []; + } + + /** + Get the payload for the relationship of an individual record. + + This might return the raw payload as pushed into the store, or one computed + from the payload of the inverse relationship. + + @method + */ + get(modelName, id, relationshipName) { + this._flushPending(); + + if (this._isLHS(modelName, relationshipName)) { + return this._lhsPayloads[id]; + } else { + assert(`${modelName}:${relationshipName} is not either side of this relationship, ${this._lhsModelName}:${this._lhsRelationshipName}<->${this._rhsModelName}:${this._rhsRelationshipName}`, this._isRHS(modelName, relationshipName)); + return this._rhsPayloads[id]; + } + } + + /** + Push a relationship payload for an individual record. + + This will make the payload available later for both this relationship and its inverse. + + @method + */ + push(modelName, id, relationshipName, relationshipData) { + this._pendingPayloads.push([modelName, id, relationshipName, relationshipData]); + } + + /** + Unload the relationship payload for an individual record. + + This does not unload the inverse relationship payload. + + @method + */ + unload(modelName, id, relationshipName) { + this._flushPending(); + + if (this._isLHS(modelName, relationshipName)) { + delete this._lhsPayloads[id]; + } else { + assert(`${modelName}:${relationshipName} is not either side of this relationship, ${this._lhsModelName}:${this._lhsRelationshipName}<->${this._rhsModelName}:${this._rhsRelationshipName}`, this._isRHS(modelName, relationshipName)); + delete this._rhsPayloads[id]; + } + } + + /** + @return {boolean} true iff `modelName` and `relationshipName` refer to the + left hand side of this relationship, as opposed to the right hand side. + + @method + */ + _isLHS(modelName, relationshipName) { + return modelName === this._lhsModelName && relationshipName === this._lhsRelationshipName; + } + + /** + @return {boolean} true iff `modelName` and `relationshipName` refer to the + right hand side of this relationship, as opposed to the left hand side. + + @method + */ + _isRHS(modelName, relationshipName) { + return modelName === this._rhsModelName && relationshipName === this._rhsRelationshipName; + } + + _flushPending() { + if (this._pendingPayloads.length === 0) { return; } + + let payloadsToBeProcessed = this._pendingPayloads.splice(0, this._pendingPayloads.length); + for (let i=0; i${this._rhsModelName}:${this._rhsRelationshipName}`, this._isRHS(modelName, relationshipName)); + previousPayload = this._rhsPayloads[id]; + idToPayloads = this._rhsPayloads; + inverseIdToPayloads = this._lhsPayloads; + inverseIsMany = this._lhsRelationshipIsMany; + } + + // actually flush this individual payload + // + // We remove the previous inverse before populating our current one + // because we may have multiple payloads for the same relationship, in + // which case the last one wins. + // + // eg if user hasMany helicopters, and helicopter belongsTo user and we see + // + // [{ + // data: { + // id: 1, + // type: 'helicopter', + // relationships: { + // user: { + // id: 2, + // type: 'user' + // } + // } + // } + // }, { + // data: { + // id: 1, + // type: 'helicopter', + // relationships: { + // user: { + // id: 4, + // type: 'user' + // } + // } + // } + // }] + // + // Then we will initially have set user:2 as having helicopter:1, which we + // need to remove before adding helicopter:1 to user:4 + // + this._removeInverse(id, previousPayload, inverseIdToPayloads); + idToPayloads[id] = relationshipData; + this._populateInverse(relationshipData, inverseRelationshipData, inverseIdToPayloads, inverseIsMany); + } + } + + /** + Populate the inverse relationship for `relationshipData`. + + If `relationshipData` is an array (eg because the relationship is hasMany) + this means populate each inverse, otherwise populate only the single + inverse. + + @private + @method + */ + _populateInverse(relationshipData, inversePayload, inverseIdToPayloads, inverseIsMany) { + if (!relationshipData.data) { + // This id doesn't have an inverse, eg a belongsTo with a payload + // { data: null }, so there's nothing to populate + return; + } + + if (Array.isArray(relationshipData.data)) { + for (let i=0; i.friends = [{ id: 1, type: 'user' }] + return; + } + + let existingPayload = inverseIdToPayloads[inverseId]; + let existingData = existingPayload && existingPayload.data; + + if (existingData) { + // There already is an inverse, either add or overwrite depehnding on + // whether the inverse is a many relationship or not + // + if (Array.isArray(existingData)) { + existingData.push(inversePayload.data); + } else { + inverseIdToPayloads[inverseId] = inversePayload; + } + } else { + // first time we're populating the inverse side + // + if (inverseIsMany) { + inverseIdToPayloads[inverseId] = { + data: [inversePayload.data] + } + } else { + inverseIdToPayloads[inverseId] = inversePayload; + } + } + } + + get _lhsRelationshipIsMany() { + return this._lhsRelationshipMeta && this._lhsRelationshipMeta.kind === 'hasMany'; + } + + get _rhsRelationshipIsMany() { + return this._rhsRelationshipMeta && this._rhsRelationshipMeta.kind === 'hasMany'; + } + + /** + Remove the relationship in `previousPayload` from its inverse(s), because + this relationship payload has just been updated (eg because the same + relationship had multiple payloads pushed before the relationship was + initialized). + + @method + */ + _removeInverse(id, previousPayload, inverseIdToPayloads) { + let data = previousPayload && previousPayload.data; + if (!data) { + // either this is the first time we've seen a payload for this id, or its + // previous payload indicated that it had no inverse, eg a belongsTo + // relationship with payload { data: null } + // + // In either case there's nothing that needs to be removed from the + // inverse map of payloads + return; + } + + if (Array.isArray(data)) { + // TODO: diff rather than removeall addall? + for (let i=0; i x.id !== id); + } else { + inversePayloads[inverseId] = { + data: null + }; + } + } +} + diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index f97bcb72776..b411e0134c7 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -51,14 +51,20 @@ export default class Relationships { get(key) { let relationships = this.initializedRelationships; let relationship = relationships[key]; + let internalModel = this.internalModel; if (!relationship) { - let internalModel = this.internalModel; let relationshipsByName = get(internalModel.type, 'relationshipsByName'); let rel = relationshipsByName.get(key); - if (rel) { - relationship = relationships[key] = createRelationshipFor(internalModel, rel, internalModel.store); + if (!rel) { return undefined; } + + let relationshipPayload = internalModel.store._relationshipsPayloads.get(internalModel.modelName, internalModel.id, key); + + relationship = relationships[key] = createRelationshipFor(internalModel, rel, internalModel.store); + + if (relationshipPayload) { + relationship.push(relationshipPayload); } } diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 0ca94f9d134..0fc803ef7f6 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -57,6 +57,7 @@ export default class Relationship { constructor(store, internalModel, inverseKey, relationshipMeta) { heimdall.increment(newRelationship); let async = relationshipMeta.options.async; + let polymorphic = relationshipMeta.options.polymorphic; this.members = new OrderedSet(); this.canonicalMembers = new OrderedSet(); this.store = store; @@ -64,6 +65,7 @@ export default class Relationship { this.inverseKey = inverseKey; this.internalModel = internalModel; this.isAsync = typeof async === 'undefined' ? true : async; + this.isPolymorphic = typeof polymorphic === 'undefined' ? true : polymorphic; this.relationshipMeta = relationshipMeta; //This probably breaks for polymorphic relationship in complex scenarios, due to //multiple possible modelNames @@ -155,19 +157,36 @@ export default class Relationship { heimdall.increment(addCanonicalRecord); if (!this.canonicalMembers.has(record)) { this.canonicalMembers.add(record); - if (this.inverseKey) { - record._relationships.get(this.inverseKey).addCanonicalRecord(this.record); - } else { - if (!record._implicitRelationships[this.inverseKeyForImplicit]) { - record._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, record, this.key, { options: {} }); - } - record._implicitRelationships[this.inverseKeyForImplicit].addCanonicalRecord(this.record); - } + this.setupInverseRelationship(record); } this.flushCanonicalLater(); this.setHasData(true); } + setupInverseRelationship(internalModel) { + if (this.inverseKey) { + let relationships = internalModel._relationships; + let relationshipExisted = relationships.has(this.inverseKey); + let relationship = relationships.get(this.inverseKey); + if (relationshipExisted || this.isPolymorphic) { + // if we have only just initialized the inverse relationship, then it + // already has this.internalModel in its canonicalMembers, so skip the + // unnecessary work. The exception to this is polymorphic + // relationships whose members are determined by their inverse, as those + // relationships cannot efficiently find their inverse payloads. + relationship.addCanonicalRecord(this.internalModel); + } + } else { + let relationships = internalModel._implicitRelationships; + let relationship = relationships[this.inverseKeyForImplicit]; + if (!relationship) { + relationship = relationships[this.inverseKeyForImplicit] = + new Relationship(this.store, internalModel, this.key, { options: {} }); + } + relationship.addCanonicalRecord(this.internalModel); + } + } + removeCanonicalRecords(records, idx) { heimdall.increment(removeCanonicalRecords); for (let i=0; i { - if (!data.relationships[key]) { +function isInverseRelationshipInitialized(store, internalModel, data, key, modelNameToInverseMap) { + let relationshipData = data.relationships[key].data; + + if (!relationshipData) { + // can't check inverse for eg { comments: { links: { related: URL }}} + return false; + } + + let inverseMap = modelNameToInverseMap[internalModel.modelName] + if (!inverseMap) { + inverseMap = modelNameToInverseMap[internalModel.modelName] = get(internalModel.type, 'inverseMap'); + } + let inverseRelationshipMetadata = inverseMap[key]; + if (inverseRelationshipMetadata === undefined) { + inverseRelationshipMetadata = internalModel.type.inverseFor(key, store); + } + + if (!inverseRelationshipMetadata) { + return false; + } + + let { name: inverseRelationshipName } = inverseRelationshipMetadata; + + if (Array.isArray(relationshipData)) { + for (let i=0; i { + if (!data.relationships[relationshipName]) { return; } - let relationship = internalModel._relationships.get(key); - relationship.push(data.relationships[key]); + let relationshipRequiresNotification = relationships.has(relationshipName) || + isInverseRelationshipInitialized(store, internalModel, data, relationshipName, modelNameToInverseMap); + + if (relationshipRequiresNotification) { + let relationshipData = data.relationships[relationshipName]; + relationships.get(relationshipName).push(relationshipData); + } + + // in debug, assert payload validity eagerly + runInDebug(() => { + let relationshipMeta = get(internalModel.type, 'relationshipsByName').get(relationshipName); + let relationshipData = data.relationships[relationshipName]; + if (!relationshipData || !relationshipMeta) { + return; + } + + if (relationshipData.links) { + let isAsync = relationshipMeta.options && relationshipMeta.options.async !== false; + warn(`You pushed a record of type '${internalModel.type.modelName}' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, isAsync || relationshipData.data , { + id: 'ds.store.push-link-for-sync-relationship' + }); + } else if (relationshipData.data) { + if (relationshipMeta.kind === 'belongsTo') { + assert(`A ${internalModel.type.modelName} record was pushed into the store with the value of ${relationshipName} being ${inspect(relationshipData.data)}, but ${relationshipName} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(relationshipData.data)); + } else if (relationshipMeta.kind === 'hasMany') { + assert(`A ${internalModel.type.modelName} record was pushed into the store with the value of ${relationshipName} being '${inspect(relationshipData.data)}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(relationshipData.data)); + } + } + }); }); } diff --git a/tests/integration/records/relationship-changes-test.js b/tests/integration/records/relationship-changes-test.js index 54fc3486573..c0cdd002795 100644 --- a/tests/integration/records/relationship-changes-test.js +++ b/tests/integration/records/relationship-changes-test.js @@ -889,9 +889,16 @@ test('Calling push with updated belongsTo relationship trigger observer', functi data: { type: 'author', id: '2' } } } - } + }, + included: [{ + id: 2, + type: 'author' + }] }); + // as with all cps, observers don't fire if the cp isn't lazy. + post.get('author'); + post.addObserver('author', function() { observerCount++; }); diff --git a/tests/integration/records/rematerialize-test.js b/tests/integration/records/rematerialize-test.js index c19c6d5063e..743db76a36b 100644 --- a/tests/integration/records/rematerialize-test.js +++ b/tests/integration/records/rematerialize-test.js @@ -38,7 +38,7 @@ let Boat = DS.Model.extend({ }); Boat.toString = function() { return 'Boat'; }; -module("integration/unload - Unloading Records", { +module("integration/unload - Rematerializing Unloaded Records", { beforeEach() { env = setupStore({ adapter: DS.JSONAPIAdapter, @@ -135,12 +135,13 @@ test("a sync belongs to relationship to an unloaded record can restore that reco let rematerializedPerson = bob.get('person'); assert.equal(rematerializedPerson.get('id'), '1'); + assert.equal(rematerializedPerson.get('name'), 'Adam Sunderland'); // the person is rematerialized; the previous person is *not* re-used assert.notEqual(rematerializedPerson, adam, 'the person is rematerialized, not recycled'); }); test("an async has many relationship to an unloaded record can restore that record", function(assert) { - assert.expect(13); + assert.expect(14); // disable background reloading so we do not re-create the relationship. env.adapter.shouldBackgroundReloadRecord = () => false; @@ -238,6 +239,7 @@ test("an async has many relationship to an unloaded record can restore that reco assert.equal(adam.get('boats.length'), 2, 'boats.length correct after rematerialization'); assert.equal(rematerializedBoaty.get('id'), '1'); + assert.equal(rematerializedBoaty.get('name'), 'Boaty McBoatface'); assert.notEqual(rematerializedBoaty, boaty, 'the boat is rematerialized, not recycled'); assert.equal(env.store.hasRecordForId('boat', 1), true, 'The boat is loaded'); diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index e3559412e52..038436c76e5 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -65,25 +65,48 @@ test("can unload a single record", function(assert) { id: '1', attributes: { name: 'Adam Sunderland' + }, + relationships: { + cars: { + data: [{ + id: 1, + type: 'car' + }] + }, + boats: { + data: [{ + id: 2, + type: 'boat' + }] + } } } }); adam = env.store.peekRecord('person', 1); }); + assert.equal(env.store.peekAll('person').get('length'), 1, 'one person record loaded'); assert.equal(env.store._internalModelsFor('person').length, 1, 'one person internalModel loaded'); + let relPayloads = env.store._relationshipsPayloads; + + assert.equal(relPayloads.get('person', 1, 'cars').data.length, 1, 'one car relationship payload is cached'); + assert.equal(relPayloads.get('person', 1, 'boats').data.length, 1, 'one boat relationship payload is cached'); + Ember.run(function() { adam.unloadRecord(); }); assert.equal(env.store.peekAll('person').get('length'), 0, 'no person records'); assert.equal(env.store._internalModelsFor('person').length, 0, 'no person internalModels'); + + assert.equal(relPayloads.get('person', 1, 'cars'), null, 'no car relationship payload is cached'); + assert.equal(relPayloads.get('person', 1, 'boats'), null, 'no boat relationship payload is cached'); }); test("can unload all records for a given type", function(assert) { - assert.expect(8); + assert.expect(11); let adam, bob, dudu; run(function() { @@ -128,6 +151,10 @@ test("can unload all records for a given type", function(assert) { assert.equal(env.store.peekAll('car').get('length'), 1, 'one car record loaded'); assert.equal(env.store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); + let relPayloads = env.store._relationshipsPayloads; + + assert.equal(relPayloads.get('car', 1, 'person').data.id, 1, 'car - person payload is loaded'); + Ember.run(function() { env.store.unloadAll('person'); }); @@ -136,6 +163,21 @@ test("can unload all records for a given type", function(assert) { assert.equal(env.store.peekAll('car').get('length'), 1); assert.equal(env.store._internalModelsFor('person').length, 0, 'zero person internalModels loaded'); assert.equal(env.store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); + + Ember.run(function() { + env.store.push({ + data: { + id: 1, + type: 'person', + attributes: { + name: 'Richard II' + } + } + }); + }); + + assert.equal(env.store.peekRecord('car', 1).get('person.id'), '1', 'Inverse can load relationship after the record is unloaded'); + assert.equal(env.store.peekRecord('car', 1).get('person.name'), 'Richard II', 'Inverse can load relationship after the record is unloaded'); }); test("can unload all records", function(assert) { @@ -335,6 +377,10 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu assert.equal(env.store.hasRecordForId('car', 1), true); assert.equal(env.store.hasRecordForId('car', 2), true); + let relPayloads = env.store._relationshipsPayloads; + + assert.equal(relPayloads.get('person', 1, 'cars').data.length, 2, 'person - cars relationship payload loaded'); + let checkOrphanCalls = 0; let cleanupOrphanCalls = 0; @@ -356,6 +402,9 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu countOrphanCalls(env.store.peekRecord('car', 1)); countOrphanCalls(env.store.peekRecord('car', 2)); + // make sure relationships are initialized + env.store.peekRecord('person', 1).get('cars'); + run(() => { env.store.peekRecord('person', 1).unloadRecord(); env.store.peekRecord('car', 1).unloadRecord(); @@ -367,4 +416,6 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu assert.equal(checkOrphanCalls, 3, 'each internalModel checks for cleanup'); assert.equal(cleanupOrphanCalls, 1, 'cleanup only happens once'); + + assert.equal(relPayloads.get('person', 1, 'cars'), null, 'person - cars relationship payload unloaded'); }); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index d94d7015689..27aa6c40d84 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -25,6 +25,7 @@ module("integration/relationships/has_many - Has-Many Relationships", { messages: hasMany('message', { polymorphic: true, async: false }), contacts: hasMany('user', { inverse: null, async: false }) }); + User.reopenClass({ toString: () => 'User' }); Contact = DS.Model.extend({ user: belongsTo('user', { async: false }) @@ -2125,6 +2126,10 @@ test("Relationship.clear removes all records correctly", function(assert) { }); run(function() { + // unclear what the semantics of clearing a yet to be created relationship + // ought to be. + env.store.peekAll('comment').mapBy('post'); + post._internalModel._relationships.get('comments').clear(); var comments = Ember.A(env.store.peekAll('comment')); assert.deepEqual(comments.mapBy('post'), [null, null, null]); @@ -2849,6 +2854,10 @@ test("deleted records should stay deleted", function(assert) { }] }); - assert.equal(get(user, 'messages.length'), 2, 'user should have 2 message since 1 was deleted'); + assert.deepEqual( + get(user, 'messages').mapBy('id'), + ['message-2', 'message-3'], + 'user should have 2 message since 1 was deleted' + ); }); }); diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index f4b77941448..f60ba2a6f1b 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -463,8 +463,8 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a bel }, /We found no inverse relationships by the name of 'testPost' on the 'user' model/); }); -test("inverseFor is only called when inverse is not null", function(assert) { - assert.expect(2); +test("inverseFor short-circuits when inverse is null", function(assert) { + assert.expect(4); Post = DS.Model.extend({ comments: DS.hasMany('comment', { async: false, inverse: null }) }); @@ -484,20 +484,20 @@ test("inverseFor is only called when inverse is not null", function(assert) { var env = setupStore({ post: Post, comment: Comment, user: User, message: Message }); var store = env.store; - Post.inverseFor = function() { - assert.notOk(true, 'Post model inverseFor is not called'); + Post._findInverseFor = function() { + assert.notOk(true, 'Post model _findInverseFor is not called'); }; - Comment.inverseFor = function() { - assert.notOk(true, 'Comment model inverseFor is not called'); + Comment._findInverseFor = function() { + assert.notOk(true, 'Comment model _findInverseFor is not called'); }; - Message.inverseFor = function() { - assert.ok(true, 'Message model inverseFor is called'); + Message._findInverseFor = function() { + assert.ok(true, 'Message model _findInverseFor is called'); }; - User.inverseFor = function() { - assert.ok(true, 'User model inverseFor is called'); + User._findInverseFor = function() { + assert.ok(true, 'User model _findInverseFor is called'); }; run(function() { diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index 9b000618661..f2549882e8a 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -97,7 +97,8 @@ test("Loading from one hasMany side reflects on the other hasMany side - async", }); }); -test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - sync", function(assert) { + +test("Relationship is available from one hasMany side even if only loaded from the other hasMany side - sync", function(assert) { var account; run(function() { account = store.push({ diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index ec5a9e5a6da..ae97e32759e 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -213,6 +213,45 @@ test('hasMany handles pre-loaded relationships', function(assert) { }); }); +test('hasMany tolerates reflexive self-relationships', function(assert) { + assert.expect(1); + + const Person = DS.Model.extend({ + name: DS.attr(), + trueFriends: DS.hasMany('person', { async: false }) + }); + + let env = setupStore({ person: Person }); + env.adapter.shouldBackgroundReloadRecord = () => false; + + run(() => { + env.store.push({ + data: { + id: '1', + type: 'person', + attributes: { + name: 'Edward II' + }, + relationships: { + trueFriends: { + data: [{ + id: '1', + type: 'person' + }] + } + } + } + }); + }); + + let eddy = env.store.peekRecord('person', 1); + assert.deepEqual( + eddy.get('trueFriends').mapBy('name'), + ['Edward II'], + 'hasMany supports reflexive self-relationships' + ); +}); + test('hasMany lazily loads async relationships', function(assert) { assert.expect(5); diff --git a/tests/unit/system/relationships/relationship-payload-manager-test.js b/tests/unit/system/relationships/relationship-payload-manager-test.js new file mode 100644 index 00000000000..1292923d362 --- /dev/null +++ b/tests/unit/system/relationships/relationship-payload-manager-test.js @@ -0,0 +1,678 @@ +import Ember from 'ember'; +import RelationshipPayloadsManager from 'ember-data/-private/system/relationships/relationship-payloads-manager'; +import DS from 'ember-data'; +import {createStore} from 'dummy/tests/helpers/store'; +import {module, test} from 'qunit'; + +const { get } = Ember; + +module('unit/system/relationships/relationship-payloads-manager', { + beforeEach() { + const User = DS.Model.extend({ + purpose: DS.belongsTo('purpose', { inverse: 'user' }), + hobbies: DS.hasMany('hobby', { inverse: 'user'}), + friends: DS.hasMany('user', { inverse: 'friends' }) + }); + User.toString = () => 'User'; + + const Hobby = DS.Model.extend({ + user: DS.belongsTo('user', { inverse: 'hobbies' }) + }); + Hobby.toString = () => 'Hobby'; + + const Purpose = DS.Model.extend({ + user: DS.belongsTo('user', { inverse: 'purpose' }) + }); + Purpose.toString = () => 'Purpose'; + + let store = this.store = createStore({ + user: User, + Hobby: Hobby, + purpose: Purpose + }); + + this.relationshipPayloadsManager = new RelationshipPayloadsManager(store); + } +}); + + +test('get throws for invalid models', function(assert) { + this.relationshipPayloadsManager._store._modelFor = (name) => { + if (name === 'fish') { + throw new Error('What is fish?'); + } + } + + assert.throws(() => { + this.relationshipPayloadsManager.get('fish', 9, 'hobbies'); + }, /What is fish/); +}); + +test('get returns null for invalid relationships', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + hobbies: { + data: [{ + id: 1, + type: 'hobby' + }] + } + }); + let entry = this.relationshipPayloadsManager.get('user', 2, 'potatoes'); + assert.equal(entry, null, 'nothing returned for invalid relationship'); +}); + +test('get returns null if there are no payloads', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + hobbies: { + data: [{ + id: 1, + type: 'hobby' + }] + } + }); + let entry = this.relationshipPayloadsManager.get('user', 2, 'hobbies'); + assert.equal(entry, null, 'no payloads for user 2'); + + entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); + assert.equal(entry, null, 'no payloads for user 1 purpose'); +}); + +test('get returns direct payloads', function(assert) { + let hobbyPayload = { + data: [{ + id: 1, + type: 'hobby' + }] + }; + let purposePayload = { + data: { + id: 2, + type: 'purpose' + } + }; + let friendsPayload = { + data: [{ + id: 2, + type: 'user' + }, { + id: 3, + type: 'user' + }] + }; + this.relationshipPayloadsManager.push('user', 1, { + hobbies: hobbyPayload, + purpose: purposePayload, + friends: friendsPayload + }); + + let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); + assert.deepEqual(entry, purposePayload, 'direct one-to-one payload loaded'); + + entry = this.relationshipPayloadsManager.get('user', 1, 'hobbies'); + assert.deepEqual(entry, hobbyPayload, 'direct one-to-many payload loaded'); + + entry = this.relationshipPayloadsManager.get('user', 1, 'friends'); + assert.deepEqual(entry, friendsPayload, 'direct many-to-many payload loaded'); +}); + +test('get returns inverse payloads one-to-one', function(assert) { + this.relationshipPayloadsManager.push('purpose', 2, { + user: { + data: { + id: 1, + type: 'user' + } + } + }); + + let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); + assert.deepEqual(entry, { + data: { + id: 2, + type: 'purpose' + } + }, 'inverse one-to-one payload loaded'); +}); + +test('get returns inverse payloads one-to-many', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + hobbies: { + data: [{ + id: 2, + type: 'hobby' + }, { + id: 3, + type: 'hobby' + }] + } + }); + + let entry = this.relationshipPayloadsManager.get('hobby', 2, 'user'); + assert.deepEqual(entry, { + data: { + id: 1, + type: 'user' + } + }, 'inverse one-to-many payload loaded'); + + entry = this.relationshipPayloadsManager.get('hobby', 3, 'user'); + assert.deepEqual(entry, { + data: { + id: 1, + type: 'user' + } + }, 'inverse one-to-many payload loaded'); +}); + +test('get handles inverse payloads that unset one-to-one', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + purpose: { + data: { + id: 2, + type: 'purpose' + } + } + }); + + let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); + assert.deepEqual(entry, { + data: { + id: 2, + type: 'purpose' + } + }, 'user.purpose.id is initially 2'); + + entry = this.relationshipPayloadsManager.get('purpose', 2, 'user'); + assert.deepEqual(entry, { + data: { + id: 1, + type: 'user' + } + }, 'purpose.user.id is initially 1'); + + this.relationshipPayloadsManager.push('purpose', 2, { + user: { + data: null + } + }); + + entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); + assert.deepEqual(entry, { + data: null + }, 'inverse payload unset one-to-one'); +}); + +test('get handles inverse payloads that change one-to-one', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + purpose: { + data: { + id: 2, + type: 'purpose' + } + } + }); + + let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); + assert.deepEqual(entry, { + data: { + id: 2, + type: 'purpose' + } + }, 'user.purpose.id is initially 2'); + + entry = this.relationshipPayloadsManager.get('purpose', 2, 'user'); + assert.deepEqual(entry, { + data: { + id: 1, + type: 'user' + } + }, 'purpose.user.id is initially 1'); + + this.relationshipPayloadsManager.push('purpose', 2, { + user: { + data: { + id: 2, + type: 'user' + } + } + }); + + entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); + assert.deepEqual(entry, { + data: null + }, 'inverse payload unset one-to-one'); + + entry = this.relationshipPayloadsManager.get('user', 2, 'purpose'); + assert.deepEqual(entry, { + data: { + id: 2, + type: 'purpose' + } + }, 'inverse payload changed one-to-one'); +}); + +test('get handles inverse payloads that remove one-to-many', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + hobbies: { + data: [{ + id: 2, + type: 'hobby' + }, { + id: 3, + type: 'hobby' + }] + } + }); + + let entry = this.relationshipPayloadsManager.get('user', 1, 'hobbies'); + assert.deepEqual(entry, { + data: [{ + id: 2, + type: 'hobby' + }, { + id: 3, + type: 'hobby' + }] + }, 'user.hobbies.ids is initially 2,3'); + + entry = this.relationshipPayloadsManager.get('hobby', 2, 'user'); + assert.deepEqual(entry, { + data: { + id: 1, + type: 'user' + } + }, 'hobby(2).user.id is initially 1'); + + entry = this.relationshipPayloadsManager.get('hobby', 3, 'user'); + assert.deepEqual(entry, { + data: { + id: 1, + type: 'user' + } + }, 'hobby(3).user.id is initially 1'); + + this.relationshipPayloadsManager.push('hobby', 2, { + user: { + data: null + } + }); + + entry = this.relationshipPayloadsManager.get('user', 1, 'hobbies'); + assert.deepEqual(entry, { + data: [{ + id: 3, + type: 'hobby' + }] + }, 'inverse payload removes from one-to-many'); +}); + +test('get handles inverse payloads that add one-to-many', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + hobbies: { + data: [{ + id: 2, + type: 'hobby' + }, { + id: 3, + type: 'hobby' + }] + } + }); + + let entry = this.relationshipPayloadsManager.get('user', 1, 'hobbies'); + assert.deepEqual(entry, { + data: [{ + id: 2, + type: 'hobby' + }, { + id: 3, + type: 'hobby' + }] + }, 'user.hobbies.ids is initially 2,3'); + + entry = this.relationshipPayloadsManager.get('hobby', 2, 'user'); + assert.deepEqual(entry, { + data: { + id: 1, + type: 'user' + } + }, 'hobby(2).user.id is initially 1'); + + entry = this.relationshipPayloadsManager.get('hobby', 3, 'user'); + assert.deepEqual(entry, { + data: { + id: 1, + type: 'user' + } + }, 'hobby(3).user.id is initially 1'); + + this.relationshipPayloadsManager.push('hobby', 4, { + user: { + data: { + id: 1, + type: 'user' + } + } + }); + + entry = this.relationshipPayloadsManager.get('user', 1, 'hobbies'); + assert.deepEqual(entry, { + data: [{ + id: 2, + type: 'hobby' + }, { + id: 3, + type: 'hobby' + }, { + id: 4, + type: 'hobby' + }] + }, 'inverse payload adds to one-to-many'); +}); + +test('get handles inverse payloads that remove many-to-many', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + friends: { + data: [{ + id: 2, + type: 'user' + }, { + id: 3, + type: 'user' + }] + } + }); + + let entry = this.relationshipPayloadsManager.get('user', 1, 'friends'); + assert.deepEqual(entry, { + data: [{ + id: 2, + type: 'user' + }, { + id: 3, + type: 'user' + }] + }, 'user.friends.ids is initially 2,3'); + + this.relationshipPayloadsManager.push('user', 3, { + friends: { + data: [] + } + }); + + entry = this.relationshipPayloadsManager.get('user', 1, 'friends'); + assert.deepEqual(entry, { + data: [{ + id: 2, + type: 'user' + }] + }, 'inverse payload removes from many-to-many'); +}); + +test('get handles inverse payloads that add many-to-many', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + friends: { + data: [{ + id: 2, + type: 'user' + }, { + id: 3, + type: 'user' + }] + } + }); + + let entry = this.relationshipPayloadsManager.get('user', 1, 'friends'); + assert.deepEqual(entry, { + data: [{ + id: 2, + type: 'user' + }, { + id: 3, + type: 'user' + }] + }, 'user.friends.ids is initially 2,3'); + + this.relationshipPayloadsManager.push('user', 4, { + friends: { + data: [{ + id: 1, + type: 'user' + }] + } + }); + + entry = this.relationshipPayloadsManager.get('user', 1, 'friends'); + assert.deepEqual(entry, { + data: [{ + id: 2, + type: 'user' + }, { + id: 3, + type: 'user' + }, { + id: 4, + type: 'user' + }] + }, 'inverse payload adds to many-to-many'); +}); + +test('push populates the same RelationshipPayloads for either side of a relationship', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + hobbies: [{ + id: 2, + type: 'hobby' + }] + }); + + let userModel = this.store.modelFor('user'); + + let userPayloads = + this.relationshipPayloadsManager._getRelationshipPayloads( + 'user', + 'hobbies', + userModel, + get(userModel, 'relationshipsByName') + ); + + let hobbyModel = this.store.modelFor('hobby'); + let hobbyPayloads = + this.relationshipPayloadsManager._getRelationshipPayloads( + 'hobby', + 'user', + hobbyModel, + get(hobbyModel, 'relationshipsByName') + ); + + assert.equal(userPayloads, hobbyPayloads, 'both sides of a relationship share a RelationshipPayloads'); +}); + +test('push does not eagerly populate inverse payloads', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + hobbies: { + data: [{ + id: 2, + type: 'hobby' + }] + } + }); + + let userModel = this.store.modelFor('user'); + let relationshipPayloads = + this.relationshipPayloadsManager._getRelationshipPayloads( + 'user', + 'hobbies', + userModel, + get(userModel, 'relationshipsByName') + ); + + assert.deepEqual( + Object.keys(relationshipPayloads._lhsPayloads), + [] , + 'user.hobbies payloads not eagerly populated' + ); + assert.deepEqual( + Object.keys(relationshipPayloads._rhsPayloads), + [] , + 'hobby.user payloads not eagerly populated' + ); + + relationshipPayloads.get('user', 1, 'hobbies'); + + assert.deepEqual( + Object.keys(relationshipPayloads._lhsPayloads), + ['1'] , + 'user.hobbies payloads lazily populated' + ); + assert.deepEqual( + Object.keys(relationshipPayloads._rhsPayloads), + ['2'] , + 'hobby.user payloads lazily populated' + ); +}); + +test('push populates each individual relationship in a payload', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + purpose: { + data: { + id: 3, + type: 'purpose' + } + }, + friends: { + data: [{ + id: 3, + type: 'user' + }] + }, + hobbies: { + data: [{ + id: 2, + type: 'hobby' + }] + } + }); + + let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); + assert.deepEqual(entry, { + data: { + id: 3, + type: 'purpose' + } + }, 'user.purpose is loaded'); + + entry = this.relationshipPayloadsManager.get('user', 1, 'friends'); + assert.deepEqual(entry, { + data: [{ + id: 3, + type: 'user' + }] + }, 'user.friends is loaded'); + + entry = this.relationshipPayloadsManager.get('user', 1, 'hobbies'); + assert.deepEqual(entry, { + data: [{ + id: 2, + type: 'hobby' + }] + }, 'user.hobbies is loaded'); +}); + +test('push ignores invalid relationships in a payload', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + purpose: { + data: { + id: 3, + type: 'purpose' + } + }, + loyalBadgers: { + data: [{ + id: 1, + type: 'badger-obviously' + }, { + id: 2, + type: 'badger-obviously' + }] + } + }); + + let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); + assert.deepEqual(entry, { + data: { + id: 3, + type: 'purpose' + } + }, 'user.purpose is loaded'); +}); + +test('unload unloads payloads that have no inverse', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + purpose: { + data: { + id: 1, + type: 'purpose' + } + } + }); + + let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); + assert.deepEqual(entry, { + data: { + id: 1, + type: 'purpose' + } + }, 'payload is initially loaded'); + + this.relationshipPayloadsManager.unload('user', 1, 'purpose'); + + entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); + assert.equal(entry, null, 'payload is unloaded when inverse is not in store'); +}); + +test('unload unloads only one side of the payload when it has an inverse', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + purpose: { + data: { + id: 1, + type: 'purpose' + } + } + }); + + let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); + assert.deepEqual(entry, { + data: { + id: 1, + type: 'purpose' + } + }, 'payload is initially loaded'); + + this.relationshipPayloadsManager.unload('user', 1, 'purpose'); + + entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); + assert.equal(null, entry, 'payload is unloaded'); + + entry = this.relationshipPayloadsManager.get('purpose', 1, 'user'); + assert.deepEqual(entry, { + data: { + id: 1, + type: 'user' + } + }, 'inverse is retained'); +}); + +test('get can retrieve payloads with self-links in reflexive relationships', function(assert) { + let friendsPayload = { + data: [{ + id: 1, + type: 'user' + }] + }; + this.relationshipPayloadsManager.push('user', 1, { + friends: friendsPayload + }); + + let entry = this.relationshipPayloadsManager.get('user', 1, 'friends'); + assert.deepEqual(entry, friendsPayload, 'self-link in reflexive relationship'); +}); diff --git a/tests/unit/system/relationships/relationship-payloads-test.js b/tests/unit/system/relationships/relationship-payloads-test.js new file mode 100644 index 00000000000..21dd4371748 --- /dev/null +++ b/tests/unit/system/relationships/relationship-payloads-test.js @@ -0,0 +1,148 @@ +import Ember from 'ember'; +import RelationshipPayloadsManager from 'ember-data/-private/system/relationships/relationship-payloads-manager'; +import DS from 'ember-data'; +import {createStore} from 'dummy/tests/helpers/store'; +import {module, test} from 'qunit'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; + +const { get } = Ember; + +module('unit/system/relationships/relationship-payloads', { + beforeEach() { + const User = DS.Model.extend({ + purpose: DS.belongsTo('purpose', { inverse: 'user' }), + hobbies: DS.hasMany('hobby', { inverse: 'user'}), + friends: DS.hasMany('user', { inverse: 'friends' }) + }); + User.toString = () => 'User'; + + const Hobby = DS.Model.extend({ + user: DS.belongsTo('user', { inverse: 'hobbies' }) + }); + Hobby.toString = () => 'Hobby'; + + const Purpose = DS.Model.extend({ + user: DS.belongsTo('user', { inverse: 'purpose' }) + }); + Purpose.toString = () => 'Purpose'; + + let store = this.store = createStore({ + user: User, + Hobby: Hobby, + purpose: Purpose + }); + + this.relationshipPayloadsManager = new RelationshipPayloadsManager(store); + } +}); + +test('_{lhs,rhs}RelationshipIsMany returns true for hasMany relationships', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + purpose: { + data: null + }, + hobbies: { + data: [] + }, + friends: { + data: [] + } + }); + + let userModel = this.store.modelFor('user'); + let relationshipPayloads = + this.relationshipPayloadsManager._getRelationshipPayloads( + 'user', + 'friends', + userModel, + get(userModel, 'relationshipsByName') + ); + + assert.equal(relationshipPayloads._lhsRelationshipIsMany, true, 'lhsRelationshipIsMany'); + assert.equal(relationshipPayloads._rhsRelationshipIsMany, true, 'rhsRelationshipIsMany'); +}); + +test('_{lhs,rhs}RelationshipIsMany returns false for belongsTo relationships', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + purpose: { + data: null + } + }); + + let userModel = this.store.modelFor('user'); + let relationshipPayloads = + this.relationshipPayloadsManager._getRelationshipPayloads( + 'user', + 'purpose', + userModel, + get(userModel, 'relationshipsByName') + ); + + assert.equal(relationshipPayloads._lhsRelationshipIsMany, false, 'purpose:user !isMany'); + assert.equal(relationshipPayloads._rhsRelationshipIsMany, false, 'user:purpose !isMany'); +}); + +testInDebug('get asserts the passed modelName and relationshipName refer to this relationship', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + purpose: { + data: null + } + }); + + let userModel = this.store.modelFor('user'); + let relationshipPayloads = + this.relationshipPayloadsManager._getRelationshipPayloads( + 'user', + 'purpose', + userModel, + get(userModel, 'relationshipsByName') + ); + + assert.expectAssertion(() => { + // relationship is wrong, lhs + relationshipPayloads.get('user', 1, 'favouriteFood'); + }, 'user:favouriteFood is not either side of this relationship, user:purpose<->purpose:user'); + + assert.expectAssertion(() => { + // relationship is wrong, rhs + relationshipPayloads.get('purpose', 1, 'fork'); + }, 'purpose:fork is not either side of this relationship, user:purpose<->purpose:user'); + + assert.expectAssertion(() => { + // model doesn't match either side of the relationship + relationshipPayloads.get('brand-of-catnip', 1, 'purpose'); + }, 'brand-of-catnip:purpose is not either side of this relationship, user:purpose<->purpose:user'); +}); + +testInDebug('unload asserts the passed modelName and relationshipName refer to this relationship', function(assert) { + this.relationshipPayloadsManager.push('user', 1, { + purpose: { + data: null + } + }); + + let userModel = this.store.modelFor('user'); + let relationshipPayloads = + this.relationshipPayloadsManager._getRelationshipPayloads( + 'user', + 'purpose', + userModel, + get(userModel, 'relationshipsByName') + ); + + assert.expectAssertion(() => { + // relationship is wrong, lhs + relationshipPayloads.unload('user', 1, 'favouriteFood'); + }, 'user:favouriteFood is not either side of this relationship, user:purpose<->purpose:user'); + + assert.expectAssertion(() => { + // relationship is wrong, rhs + relationshipPayloads.unload('purpose', 1, 'fork'); + }, 'purpose:fork is not either side of this relationship, user:purpose<->purpose:user'); + + assert.expectAssertion(() => { + // model doesn't match either side of the relationship + relationshipPayloads.unload('brand-of-catnip', 1, 'purpose'); + }, 'brand-of-catnip:purpose is not either side of this relationship, user:purpose<->purpose:user'); +}); + From f8304b23c792a1e74cefb63140e6ee1917cbdfa1 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Thu, 16 Mar 2017 09:51:22 -0700 Subject: [PATCH 1862/2527] Do less work on initial relationship push We don't need to go through `computeChanges`, `flushCqnonical` &c. when initializing relationships. Treating initial payloads the same as updated payloads is costly. --- .../system/relationships/state/belongs-to.js | 20 +++++- .../system/relationships/state/create.js | 2 +- .../system/relationships/state/has-many.js | 18 +++++- .../relationships/state/relationship.js | 6 +- .../model/relationships/belongs-to-test.js | 56 +++++++++++++++++ .../unit/model/relationships/has-many-test.js | 63 +++++++++++++++++++ 6 files changed, 157 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 03f19299ecc..f4925b17398 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -36,6 +36,18 @@ export default class BelongsToRelationship extends Relationship { this.flushCanonicalLater(); } + setInitialCanonicalRecord(record) { + if (!record) { return; } + + // When we initialize a belongsTo relationship, we want to avoid work like + // notifying our internalModel that we've "changed" and excessive thrash on + // setting up inverse relationships + this.canonicalMembers.add(record); + this.members.add(record); + this.inverseRecord = this.canonicalState = record; + this.setupInverseRelationship(record); + } + addCanonicalRecord(newRecord) { if (this.canonicalMembers.has(newRecord)) { return;} @@ -162,8 +174,12 @@ export default class BelongsToRelationship extends Relationship { return this.findRecord(); } - updateData(data) { + updateData(data, initial) { let internalModel = this.store._pushResourceIdentifier(this, data); - this.setCanonicalRecord(internalModel); + if (initial) { + this.setInitialCanonicalRecord(internalModel); + } else { + this.setCanonicalRecord(internalModel); + } } } diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index b411e0134c7..85a766c23b5 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -64,7 +64,7 @@ export default class Relationships { relationship = relationships[key] = createRelationshipFor(internalModel, rel, internalModel.store); if (relationshipPayload) { - relationship.push(relationshipPayload); + relationship.push(relationshipPayload, true); } } diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 857b98e3df2..ddfefc219a3 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -179,6 +179,16 @@ export default class ManyRelationship extends Relationship { } } + setInitialInternalModels(internalModels) { + let args = [0, this.canonicalState.length].concat(internalModels); + this.canonicalState.splice.apply(this.canonicalState, args); + internalModels.forEach(internalModel => { + this.canonicalMembers.add(internalModel); + this.members.add(internalModel); + this.setupInverseRelationship(internalModel); + }); + } + fetchLink() { return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(records => { if (records.hasOwnProperty('meta')) { @@ -237,9 +247,13 @@ export default class ManyRelationship extends Relationship { } } - updateData(data) { + updateData(data, initial) { let internalModels = this.store._pushResourceIdentifiers(this, data); - this.updateRecordsFromAdapter(internalModels); + if (initial) { + this.setInitialInternalModels(internalModels); + } else { + this.updateRecordsFromAdapter(internalModels); + } } } diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 0fc803ef7f6..53ad44c8485 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -376,7 +376,7 @@ export default class Relationship { `push` use `updateMeta`, `updateData` and `updateLink` to update the state of the relationship. */ - push(payload) { + push(payload, initial) { heimdall.increment(push); let hasData = false; @@ -388,14 +388,14 @@ export default class Relationship { if (payload.data !== undefined) { hasData = true; - this.updateData(payload.data); + this.updateData(payload.data, initial); } if (payload.links && payload.links.related) { let relatedLink = _normalizeLink(payload.links.related); if (relatedLink && relatedLink.href && relatedLink.href !== this.link) { hasLink = true; - this.updateLink(relatedLink.href); + this.updateLink(relatedLink.href, initial); } } diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index 70ebf242983..a6c0919dbf2 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -76,6 +76,62 @@ test('belongsTo lazily loads relationships as needed', function(assert) { }); }); +test('belongsTo does not notify when it is initially reified', function(assert) { + assert.expect(1); + + const Tag = DS.Model.extend({ + name: DS.attr('string'), + people: DS.hasMany('person', { async: false }) + }); + Tag.toString = () => 'Tag'; + + const Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: false }) + }); + Person.toString = () => 'Person'; + + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + + env.adapter.shouldBackgroundReloadRecord = () => false; + + run(() => { + store.push({ + data: [{ + type: 'tag', + id: 1, + attributes: { + name: 'whatever' + } + }, { + type: 'person', + id: 2, + attributes: { + name: 'David J. Hamilton' + }, + relationships: { + tag: { + data: { + type: 'tag', + id: '1' + } + } + } + }] + }); + }); + + return run(() => { + let person = store.peekRecord('person', 2); + person.addObserver('tag', () => { + assert.ok(false, 'observer is not called'); + }) + + assert.equal(person.get('tag.name'), 'whatever', 'relationship is correct'); + }); +}); + test('async belongsTo relationships work when the data hash has not been loaded', function(assert) { assert.expect(5); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index ae97e32759e..9ee43d16204 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -213,6 +213,69 @@ test('hasMany handles pre-loaded relationships', function(assert) { }); }); +test('hasMany does not notify when it is initially reified', function(assert) { + assert.expect(1); + + const Tag = DS.Model.extend({ + name: DS.attr('string'), + people: DS.hasMany('person', { async: false }) + }); + Tag.toString = () => 'Tag'; + + const Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: false }) + }); + Person.toString = () => 'Person'; + + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + + env.adapter.shouldBackgroundReloadRecord = () => false; + + run(() => { + store.push({ + data: [{ + type: 'tag', + id: 1, + attributes: { + name: 'whatever' + }, + relationships: { + people: { + data: [{ + id: 2, + type: 'person' + }] + } + } + }, { + type: 'person', + id: 2, + attributes: { + name: 'David J. Hamilton' + } + }] + }); + }); + + return run(() => { + let tag = store.peekRecord('tag', 1); + tag.addObserver('people', () => { + assert.ok(false, 'observer is not called'); + }); + tag.addObserver('people.[]', () => { + assert.ok(false, 'observer is not called'); + }); + + assert.equal( + tag.get('people').mapBy('name'), + 'David J. Hamilton', + 'relationship is correct' + ); + }); +}); + test('hasMany tolerates reflexive self-relationships', function(assert) { assert.expect(1); From 6967d565621c46a05c2d2853764d432998910d7e Mon Sep 17 00:00:00 2001 From: Carlos Quesada Date: Tue, 21 Mar 2017 07:54:22 -0400 Subject: [PATCH 1863/2527] fix readme typo - "First things first" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 155214ba023..5ccebcb641f 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ controllers in your app. ### Defining Your Models -First thing's first: tell Ember Data about the models in your +First things first: tell Ember Data about the models in your application. For example, imagine we're writing a blog reader app. Here's what your model definition would look like if you're using From fffb635c8b9a970ee288000fbac0606b0c04f717 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 14 Mar 2017 12:50:19 -0400 Subject: [PATCH 1864/2527] [BETA] Update dependencies to use babel 6. --- ember-cli-build.js | 9 +- index.js | 11 +- lib/.eslintrc.js | 10 + lib/babel-build.js | 33 +- lib/javascripts.js | 4 +- lib/stripped-build-plugins.js | 25 +- lib/stripped-build.js | 3 +- package.json | 25 +- tests/test-helper.js | 8 +- yarn.lock | 1748 +++++++++++++++++---------------- 10 files changed, 974 insertions(+), 902 deletions(-) create mode 100644 lib/.eslintrc.js diff --git a/ember-cli-build.js b/ember-cli-build.js index 0e697964f0b..c17b7d456eb 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -4,7 +4,7 @@ var merge = require('broccoli-merge-trees'); var Funnel = require('broccoli-funnel'); var globals = require('./lib/globals'); var yuidoc = require('./lib/yuidoc'); -var stripClassCallCheck = require('babel5-plugin-strip-class-callcheck'); +var StripClassCallCheck = require('babel6-plugin-strip-class-callcheck'); var path = require('path'); // allow toggling of heimdall instrumentation @@ -20,10 +20,11 @@ for (var i = 0; i < args.length; i++) { module.exports = function(defaults) { var app = new EmberAddon(defaults, { - babel: { - plugins: [ + // use babel6 options until we are using ember-cli@2.13 + babel6: { + postTransformPlugins: [ // while ember-data strips itself, ember does not currently - { transformer: stripClassCallCheck, position: 'after' } + [StripClassCallCheck] ] } }); diff --git a/index.js b/index.js index 5a6c99f3d09..8265a6e796d 100644 --- a/index.js +++ b/index.js @@ -122,10 +122,13 @@ module.exports = { return; } - this.options.babel = this.options.babel || {}; - add(this.options.babel, 'blacklist', ['es6.modules', 'useStrict']); - add(this.options.babel, 'loose', ['es6.classes']); - add(this.options.babel, 'plugins', require('./lib/stripped-build-plugins')(process.env.EMBER_ENV)); + let customPlugins = require('./lib/stripped-build-plugins')(process.env.EMBER_ENV); + + this.options.babel = { + loose: true, + plugins: customPlugins.plugins, + postTransformPlugins: customPlugins.postTransformPlugins + }; this._hasSetupBabelOptions = true; }, diff --git a/lib/.eslintrc.js b/lib/.eslintrc.js new file mode 100644 index 00000000000..e8efd22a07f --- /dev/null +++ b/lib/.eslintrc.js @@ -0,0 +1,10 @@ +/* global module */ +module.exports = { + parserOptions: { + ecmaVersion: 6, + }, + + env: { + node: true, + } +}; diff --git a/lib/babel-build.js b/lib/babel-build.js index 1135048aee4..b8b0aef6fb8 100644 --- a/lib/babel-build.js +++ b/lib/babel-build.js @@ -6,21 +6,9 @@ function babelOptions(libraryName, _options) { _options = _options || {}; var options = { - whitelist: [ - 'es6.templateLiterals', - 'es6.parameters', - 'es6.arrowFunctions', - 'es6.destructuring', - 'es6.spread', - 'es6.properties.computed', - 'es6.properties.shorthand', - 'es6.blockScoping', - 'es6.constants', - 'es6.modules', - 'es6.classes' - ], + plugins: [], + postTransformPlugins: [], sourceMaps: false, - modules: 'amdStrict', moduleRoot: libraryName, moduleIds: true, // Transforms /index.js files to use their containing directory name @@ -36,6 +24,23 @@ function babelOptions(libraryName, _options) { options[opt] = _options[opt]; }); + options.plugins = options.plugins.concat([ + ['transform-es2015-modules-amd', { noInterop: true, loose: true }], + 'transform-es2015-arrow-functions', + 'transform-es2015-computed-properties', + 'transform-es2015-shorthand-properties', + 'transform-es2015-template-literals', + 'transform-es2015-parameters', + 'transform-es2015-destructuring', + 'transform-es2015-spread', + 'transform-es2015-block-scoping', + 'transform-es2015-constants', + ['transform-es2015-classes', { loose: true }], + ], options.postTransformPlugins).filter(Boolean); + + // this is not a "real" babel option, so we delete it + delete options.postTransformPlugins; + return options; } diff --git a/lib/javascripts.js b/lib/javascripts.js index 5d855477c77..6ba021c6e1d 100644 --- a/lib/javascripts.js +++ b/lib/javascripts.js @@ -48,8 +48,10 @@ function collapse(tree, outputFileName) { var dsGlobal = fs.readFileSync(dsGlobalPath, { encoding: 'utf8' }); var withLoader = merge([tree, loader, license, emberShim]); + return concat(withLoader, { - inputFiles: ['license.js', 'loader.js', '**/*.js'], + headerFiles: ['license.js', 'loader.js'], + inputFiles: ['**/*.js'], outputFile: '/' + outputFileName, header: '(function(){ \n"use strict";\n', footer: '\nrequire("ember-data");\nrequire("ember-load-initializers")["default"](Ember.Application, "ember-data");\n' + dsGlobal + '}).call(this);\n' + emberDataShims diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index b1d42c44730..6538387bc91 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -1,9 +1,8 @@ var fs = require('fs'); -var path = require('path'); -var filterImports = require('babel-plugin-filter-imports'); -var featureFlags = require('babel-plugin-feature-flags'); -var stripHeimdall = require('babel5-plugin-strip-heimdall'); -var stripClassCallCheck = require('babel5-plugin-strip-class-callcheck'); +var FilterImports = require('babel-plugin-filter-imports'); +var FeatureFlags = require('babel-plugin-feature-flags'); +var StripHeimdall = require('babel6-plugin-strip-heimdall'); +var StripClassCallCheck = require('babel6-plugin-strip-class-callcheck'); function uniqueAdd(obj, key, values) { var a = obj[key] = obj[key] || []; @@ -29,22 +28,24 @@ module.exports = function(environment) { // features[feature] = false; // } // } + + var postTransformPlugins = []; var plugins = [ - featureFlags({ + [FeatureFlags, { import: { module: 'ember-data/-private/features' }, features: features - }), - { transformer: stripClassCallCheck, position: 'after' } + }] ]; if (process.env.INSTRUMENT_HEIMDALL === 'false') { - plugins.push(stripHeimdall); + plugins.push([StripHeimdall]); uniqueAdd(filteredImports, 'ember-data/-private/debug', ['instrument']); } else { console.warn('NOT STRIPPING HEIMDALL'); } - if (environment === 'production' || process.env.INSTRUMENT_HEIMDALL !== 'false') { + if (environment === 'production' || process.env.INSTRUMENT_HEIMDALL === 'true') { + postTransformPlugins.push([StripClassCallCheck]); uniqueAdd(filteredImports, 'ember-data/-private/debug', [ 'assert', 'assertPolymorphicType', @@ -56,7 +57,7 @@ module.exports = function(environment) { 'debugSeal' ]); } - plugins.push(filterImports(filteredImports)); + plugins.push([FilterImports, filteredImports]); - return plugins; + return { plugins, postTransformPlugins }; }; diff --git a/lib/stripped-build.js b/lib/stripped-build.js index 3eef7603efa..d59b2677a67 100644 --- a/lib/stripped-build.js +++ b/lib/stripped-build.js @@ -6,8 +6,7 @@ var babelBuild = require('./babel-build'); var strippedBuildPlugins = require('./stripped-build-plugins'); module.exports = function(packageName, tree, environmentBuildingFor) { - var options = {}; - options.plugins = strippedBuildPlugins(environmentBuildingFor); + var options = strippedBuildPlugins(environmentBuildingFor); return babelBuild(packageName, tree, options); }; diff --git a/package.json b/package.json index aa1b3625051..dbc0fccb26d 100644 --- a/package.json +++ b/package.json @@ -21,15 +21,15 @@ "license": "MIT", "dependencies": { "amd-name-resolver": "0.0.5", - "babel-plugin-feature-flags": "^0.2.1", - "babel-plugin-filter-imports": "^0.2.0", - "babel5-plugin-strip-class-callcheck": "^5.1.0", - "babel5-plugin-strip-heimdall": "^5.0.2", - "broccoli-babel-transpiler": "^5.5.0", + "babel-plugin-feature-flags": "^0.3.1", + "babel-plugin-filter-imports": "^0.3.1", + "babel6-plugin-strip-class-callcheck": "^6.0.0", + "babel6-plugin-strip-heimdall": "^6.0.1", + "broccoli-babel-transpiler": "^6.0.0", "broccoli-file-creator": "^1.0.0", "broccoli-merge-trees": "^1.0.0", "chalk": "^1.1.1", - "ember-cli-babel": "^5.1.7", + "ember-cli-babel": "^6.0.0-beta.7", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.0.0", "ember-cli-test-info": "^1.0.0", @@ -45,6 +45,17 @@ "silent-error": "^1.0.0" }, "devDependencies": { + "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoping": "^6.23.0", + "babel-plugin-transform-es2015-classes": "^6.23.0", + "babel-plugin-transform-es2015-computed-properties": "^6.22.0", + "babel-plugin-transform-es2015-constants": "^6.1.4", + "babel-plugin-transform-es2015-destructuring": "^6.23.0", + "babel-plugin-transform-es2015-modules-amd": "^6.24.0", + "babel-plugin-transform-es2015-parameters": "^6.23.0", + "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", "bower": "^1.6.5", "broccoli-asset-rev": "^2.4.5", "broccoli-concat": "^3.2.2", @@ -60,7 +71,7 @@ "ember-cli-dependency-checker": "^1.3.0", "ember-cli-eslint": "1.3.0", "ember-cli-htmlbars": "^1.1.1", - "ember-cli-htmlbars-inline-precompile": "^0.3.6", + "ember-cli-htmlbars-inline-precompile": "^0.4.0-beta.2", "ember-cli-inject-live-reload": "^1.4.1", "ember-cli-internal-test-helpers": "^0.8.1", "ember-cli-pretender": "^1.0.1", diff --git a/tests/test-helper.js b/tests/test-helper.js index a05079eb995..fd29fcbea65 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -1,4 +1,10 @@ -import 'dummy/tests/helpers/setup-ember-dev'; +/* + babel@6 currently (6.24.0) puts `import 'foo'` (for side effects) at the + end of the module dep list. Unfortunately, for this to work `setup-ember-dev` + must be evaluated before the `qunit` module is evaluated (because we change + `QUnit.module`). + */ +import requiredWorkAroundBabelBug from 'dummy/tests/helpers/setup-ember-dev'; // eslint-disable-line import resolver from './helpers/resolver'; import { setResolver diff --git a/yarn.lock b/yarn.lock index f06f9d62910..bf2465079c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -26,10 +26,6 @@ abbrev@1: version "1.1.0" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" -abbrev@~1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" - accepts@1.3.3, accepts@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" @@ -104,14 +100,14 @@ ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" -ansi-regex@*, ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + ansi-styles@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" @@ -124,14 +120,6 @@ ansicolors@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" -ansicolors@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" - -ansistyles@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" - anymatch@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" @@ -139,13 +127,9 @@ anymatch@^1.3.0: arrify "^1.0.0" micromatch "^2.1.5" -aproba@^1.0.3, aproba@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" - -archy@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" +aproba@^1.0.3: + version "1.1.1" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" are-we-there-yet@~1.1.2: version "1.1.2" @@ -178,13 +162,6 @@ array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" -array-index@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-index/-/array-index-1.0.0.tgz#ec56a749ee103e4e08c790b9c353df16055b97f9" - dependencies: - debug "^2.2.0" - es6-symbol "^3.0.2" - array-to-error@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" @@ -217,10 +194,6 @@ arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" -asap@^2.0.0, asap@~2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" - asn1@0.1.11: version "0.1.11" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" @@ -262,8 +235,8 @@ ast-types@0.9.6: resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" async-disk-cache@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.2.1.tgz#982d0b9861cae6b54adf53ea38fdf2c2c85a5692" + version "1.2.2" + resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.2.2.tgz#3a1ba85e87e28da4200c7fe22643210e28a280fb" dependencies: debug "^2.1.3" heimdalljs "^0.2.3" @@ -271,18 +244,11 @@ async-disk-cache@^1.0.0: mkdirp "^0.5.0" rimraf "^2.5.3" rsvp "^3.0.18" - username "^2.3.0" async@^1.4.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@^2.0.1: - version "2.1.5" - resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" - dependencies: - lodash "^4.14.0" - async@~0.2.9: version "0.2.10" resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" @@ -296,8 +262,8 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" aws-sdk@^2.0.9: - version "2.28.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.28.0.tgz#0b7628c5d48820187332c5a30835945c41f84f46" + version "2.29.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.29.0.tgz#aebf0c90effa4abea426dd59187f51b5ae121684" dependencies: buffer "4.9.1" crypto-browserify "1.0.9" @@ -321,6 +287,14 @@ aws4@^1.2.1: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" +babel-code-frame@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" + dependencies: + chalk "^1.1.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + babel-core@^5.0.0, babel-core@^5.8.22: version "5.8.38" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" @@ -372,6 +346,156 @@ babel-core@^5.0.0, babel-core@^5.8.22: trim-right "^1.0.0" try-resolve "^1.0.0" +babel-core@^6.14.0, babel-core@^6.24.0: + version "6.24.0" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.0.tgz#8f36a0a77f5c155aed6f920b844d23ba56742a02" + dependencies: + babel-code-frame "^6.22.0" + babel-generator "^6.24.0" + babel-helpers "^6.23.0" + babel-messages "^6.23.0" + babel-register "^6.24.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.1" + babel-types "^6.23.0" + babylon "^6.11.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.5.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-is-absolute "^1.0.0" + private "^0.1.6" + slash "^1.0.0" + source-map "^0.5.0" + +babel-generator@^6.24.0: + version "6.24.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.0.tgz#eba270a8cc4ce6e09a61be43465d7c62c1f87c56" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-types "^6.23.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.2.0" + source-map "^0.5.0" + trim-right "^1.0.1" + +babel-helper-builder-binary-assignment-operator-visitor@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.22.0.tgz#29df56be144d81bdeac08262bfa41d2c5e91cdcd" + dependencies: + babel-helper-explode-assignable-expression "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-helper-call-delegate@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.22.0.tgz#119921b56120f17e9dae3f74b4f5cc7bcc1b37ef" + dependencies: + babel-helper-hoist-variables "^6.22.0" + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helper-define-map@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.23.0.tgz#1444f960c9691d69a2ced6a205315f8fd00804e7" + dependencies: + babel-helper-function-name "^6.23.0" + babel-runtime "^6.22.0" + babel-types "^6.23.0" + lodash "^4.2.0" + +babel-helper-explode-assignable-expression@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.22.0.tgz#c97bf76eed3e0bae4048121f2b9dae1a4e7d0478" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helper-function-name@^6.22.0, babel-helper-function-name@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.23.0.tgz#25742d67175c8903dbe4b6cb9d9e1fcb8dcf23a6" + dependencies: + babel-helper-get-function-arity "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" + +babel-helper-get-function-arity@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.22.0.tgz#0beb464ad69dc7347410ac6ade9f03a50634f5ce" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-helper-hoist-variables@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.22.0.tgz#3eacbf731d80705845dd2e9718f600cfb9b4ba72" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-helper-optimise-call-expression@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.23.0.tgz#f3ee7eed355b4282138b33d02b78369e470622f5" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.23.0" + +babel-helper-regex@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.22.0.tgz#79f532be1647b1f0ee3474b5f5c3da58001d247d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + lodash "^4.2.0" + +babel-helper-remap-async-to-generator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.22.0.tgz#2186ae73278ed03b8b15ced089609da981053383" + dependencies: + babel-helper-function-name "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + babel-traverse "^6.22.0" + babel-types "^6.22.0" + +babel-helper-replace-supers@^6.22.0, babel-helper-replace-supers@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.23.0.tgz#eeaf8ad9b58ec4337ca94223bacdca1f8d9b4bfd" + dependencies: + babel-helper-optimise-call-expression "^6.23.0" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" + +babel-helpers@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.23.0" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + babel-plugin-constant-folding@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" @@ -384,21 +508,17 @@ babel-plugin-eval@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" -babel-plugin-feature-flags@^0.2.1: - version "0.2.3" - resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.2.3.tgz#81d81ed77bda2014098fa8243abcf03a551cbd4d" - dependencies: - json-stable-stringify "^1.0.1" +babel-plugin-feature-flags@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" -babel-plugin-filter-imports@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.2.1.tgz#784f96a892f2f7ed2ccf0955688bd8916cd2e212" - dependencies: - json-stable-stringify "^1.0.1" +babel-plugin-filter-imports@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.3.1.tgz#e7859b56886b175dd2616425d277b219e209ea8b" -babel-plugin-htmlbars-inline-precompile@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.1.0.tgz#b784723bd1f108796b56faf9f1c05eb5ca442983" +babel-plugin-htmlbars-inline-precompile@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.3.tgz#cd365e278af409bfa6be7704c4354beee742446b" babel-plugin-inline-environment-variables@^1.0.1: version "1.0.1" @@ -442,6 +562,221 @@ babel-plugin-runtime@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-to-generator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.22.0.tgz#194b6938ec195ad36efc4c33a971acf00d8cd35e" + dependencies: + babel-helper-remap-async-to-generator "^6.22.0" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.23.0.tgz#e48895cf0b375be148cd7c8879b422707a053b51" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" + lodash "^4.2.0" + +babel-plugin-transform-es2015-classes@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.23.0.tgz#49b53f326202a2fd1b3bbaa5e2edd8a4f78643c1" + dependencies: + babel-helper-define-map "^6.23.0" + babel-helper-function-name "^6.23.0" + babel-helper-optimise-call-expression "^6.23.0" + babel-helper-replace-supers "^6.23.0" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.22.0.tgz#7c383e9629bba4820c11b0425bdd6290f7f057e7" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-plugin-transform-es2015-constants@^6.1.4: + version "6.1.4" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-constants/-/babel-plugin-transform-es2015-constants-6.1.4.tgz#e4b8c78fb48ab98b0107f329fab6040e79c35a33" + dependencies: + babel-runtime "^5.0.0" + +babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.22.0.tgz#672397031c21610d72dd2bbb0ba9fb6277e1c36b" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.22.0.tgz#f5fcc8b09093f9a23c76ac3d9e392c3ec4b77104" + dependencies: + babel-helper-function-name "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.0: + version "6.24.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.0.tgz#a1911fb9b7ec7e05a43a63c5995007557bcf6a2e" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.0" + babel-runtime "^6.22.0" + babel-template "^6.22.0" + +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.0: + version "6.24.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.0.tgz#e921aefb72c2cc26cb03d107626156413222134f" + dependencies: + babel-plugin-transform-strict-mode "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-types "^6.23.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.23.0.tgz#ae3469227ffac39b0310d90fec73bfdc4f6317b0" + dependencies: + babel-helper-hoist-variables "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + +babel-plugin-transform-es2015-modules-umd@^6.23.0: + version "6.24.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.0.tgz#fd5fa63521cae8d273927c3958afd7c067733450" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.22.0.tgz#daa60e114a042ea769dd53fe528fc82311eb98fc" + dependencies: + babel-helper-replace-supers "^6.22.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.23.0.tgz#3a2aabb70c8af945d5ce386f1a4250625a83ae3b" + dependencies: + babel-helper-call-delegate "^6.22.0" + babel-helper-get-function-arity "^6.22.0" + babel-runtime "^6.22.0" + babel-template "^6.23.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.22.0.tgz#8ba776e0affaa60bff21e921403b8a652a2ff723" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.22.0.tgz#ab316829e866ee3f4b9eb96939757d19a5bc4593" + dependencies: + babel-helper-regex "^6.22.0" + babel-runtime "^6.22.0" + babel-types "^6.22.0" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.22.0.tgz#8d9cc27e7ee1decfe65454fb986452a04a613d20" + dependencies: + babel-helper-regex "^6.22.0" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.22.0.tgz#d57c8335281918e54ef053118ce6eb108468084d" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.22.0" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.22.0.tgz#65740593a319c44522157538d690b84094617ea6" + dependencies: + regenerator-transform "0.9.8" + +babel-plugin-transform-strict-mode@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.22.0.tgz#e008df01340fdc87e959da65991b7e05970c8c7c" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.22.0" + babel-plugin-undeclared-variables-check@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" @@ -452,18 +787,123 @@ babel-plugin-undefined-to-void@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" -babel5-plugin-strip-class-callcheck@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/babel5-plugin-strip-class-callcheck/-/babel5-plugin-strip-class-callcheck-5.1.0.tgz#77d4a40c8614d367b8a21a53908159806dba5f91" +babel-polyfill@^6.16.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d" + dependencies: + babel-runtime "^6.22.0" + core-js "^2.4.0" + regenerator-runtime "^0.10.0" -babel5-plugin-strip-heimdall@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/babel5-plugin-strip-heimdall/-/babel5-plugin-strip-heimdall-5.0.2.tgz#e1fe191c34de79686564d50a86f4217b8df629c1" +babel-preset-env@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.2.2.tgz#1dbc4d7f8a575691d301f45fa9b2f9698b1e3b92" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^1.4.0" + electron-to-chromium "^1.2.6" + invariant "^2.2.2" + +babel-register@^6.24.0: + version "6.24.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.0.tgz#5e89f8463ba9970356d02eb07dabe3308b080cfd" + dependencies: + babel-core "^6.24.0" + babel-runtime "^6.22.0" + core-js "^2.4.0" + home-or-tmp "^2.0.0" + lodash "^4.2.0" + mkdirp "^0.5.1" + source-map-support "^0.4.2" + +babel-runtime@^5.0.0: + version "5.8.38" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-5.8.38.tgz#1c0b02eb63312f5f087ff20450827b425c9d4c19" + dependencies: + core-js "^1.0.0" + +babel-runtime@^6.18.0, babel-runtime@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + +babel-template@^6.22.0, babel-template@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.23.0" + babel-types "^6.23.0" + babylon "^6.11.0" + lodash "^4.2.0" + +babel-traverse@^6.22.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1: + version "6.23.1" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48" + dependencies: + babel-code-frame "^6.22.0" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-types "^6.23.0" + babylon "^6.15.0" + debug "^2.2.0" + globals "^9.0.0" + invariant "^2.2.0" + lodash "^4.2.0" + +babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf" + dependencies: + babel-runtime "^6.22.0" + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^1.0.1" + +babel6-plugin-strip-class-callcheck@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" + +babel6-plugin-strip-heimdall@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" babylon@^5.8.38: version "5.8.38" resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" +babylon@^6.11.0, babylon@^6.15.0: + version "6.16.1" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3" + backbone@^1.1.2: version "1.3.3" resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" @@ -510,12 +950,6 @@ better-assert@~1.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.0.0.tgz#e597d1a7a6a3558a2d1c7241a16c99965e6aa40f" -bl@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" - dependencies: - readable-stream "~2.0.5" - blank-object@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" @@ -524,12 +958,6 @@ blob@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - dependencies: - inherits "~2.0.0" - bluebird@^2.9.33: version "2.11.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" @@ -588,7 +1016,7 @@ bower-endpoint-parser@0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" -bower@^1.3.12, bower@^1.6.5: +bower@^1.6.5: version "1.8.0" resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a" @@ -627,7 +1055,7 @@ broccoli-asset-rewrite@^1.1.0: dependencies: broccoli-filter "^1.2.3" -broccoli-babel-transpiler@^5.4.5, broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: +broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: version "5.6.2" resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.6.2.tgz#958c72e43575b2f0a862a5096dba1ce1ebc7d74d" dependencies: @@ -639,13 +1067,25 @@ broccoli-babel-transpiler@^5.4.5, broccoli-babel-transpiler@^5.5.0, broccoli-bab hash-for-dep "^1.0.2" json-stable-stringify "^1.0.0" +broccoli-babel-transpiler@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.0.0.tgz#a52c5404bf36236849da503b011fd41fe64a00a2" + dependencies: + babel-core "^6.14.0" + broccoli-funnel "^1.0.0" + broccoli-merge-trees "^1.0.0" + broccoli-persistent-filter "^1.0.1" + clone "^2.0.0" + hash-for-dep "^1.0.2" + json-stable-stringify "^1.0.0" + broccoli-brocfile-loader@^0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/broccoli-brocfile-loader/-/broccoli-brocfile-loader-0.18.0.tgz#2e86021c805c34ffc8d29a2fb721cf273e819e4b" dependencies: findup-sync "^0.4.2" -broccoli-builder@^0.18.0: +broccoli-builder@^0.18.3: version "0.18.4" resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.4.tgz#abc6db2c07d214454918e2997ea87441b69b69d3" dependencies: @@ -656,29 +1096,29 @@ broccoli-builder@^0.18.0: rsvp "^3.0.17" silent-error "^1.0.1" -broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" +broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" + lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - walk-sync "^0.2.5" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" -broccoli-caching-writer@~2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" +broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" - lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - symlink-or-copy "^1.0.0" - walk-sync "^0.2.0" + walk-sync "^0.2.5" broccoli-clean-css@^1.1.0: version "1.1.0" @@ -828,9 +1268,9 @@ broccoli-merge-trees@~0.2.3: debug "^2.2.0" symlink-or-copy "^1.0.0" -broccoli-middleware@^0.18.1: - version "0.18.1" - resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-0.18.1.tgz#bf525581c2deb652c425942b18580f76d3748122" +broccoli-middleware@^1.0.0-beta.8: + version "1.0.0-beta.8" + resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-1.0.0-beta.8.tgz#89cb6a9950ff0cf5bd75071d83d7cd6f6a11a95b" dependencies: handlebars "^4.0.4" mime "^1.2.11" @@ -945,6 +1385,13 @@ broccoli-yuidoc@^2.1.0: rsvp "~3.1.0" yuidocjs "~0.9.0" +browserslist@^1.4.0: + version "1.7.6" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.6.tgz#af98589ce6e7ab09618d29451faacb81220bd3ba" + dependencies: + caniuse-db "^1.0.30000631" + electron-to-chromium "^1.2.5" + bser@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" @@ -967,14 +1414,6 @@ builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" -builtins@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-0.0.7.tgz#355219cd6cf18dbe7c01cc7fd2dce765cfdc549a" - -builtins@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" - bytes@1: version "1.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" @@ -987,6 +1426,12 @@ bytes@2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" +calculate-cache-key-for-tree@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" + dependencies: + json-stable-stringify "^1.0.1" + caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" @@ -1015,7 +1460,11 @@ can-symlink@^1.0.0: dependencies: tmp "0.0.28" -capture-exit@^1.0.7: +caniuse-db@^1.0.30000631: + version "1.0.30000639" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000639.tgz#5982f70a54352adaf8901a772d2c68ca24f501aa" + +capture-exit@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" dependencies: @@ -1073,7 +1522,7 @@ chalk@^0.5.1: strip-ansi "^0.3.0" supports-color "^0.2.0" -chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: +chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -1093,10 +1542,6 @@ check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" -chownr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" - chrome-debugging-client@^0.2.4: version "0.2.5" resolved "https://registry.yarnpkg.com/chrome-debugging-client/-/chrome-debugging-client-0.2.5.tgz#b8e1a6c37283323b6ff5d60525f6ea1fc8899fbd" @@ -1181,21 +1626,10 @@ clone@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" -clone@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" - clone@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" -cmd-shim@~2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb" - dependencies: - graceful-fs "^4.1.2" - mkdirp "~0.5.0" - co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -1216,13 +1650,6 @@ colors@~0.6.0-1: version "0.6.2" resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" -columnify@~1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" - dependencies: - strip-ansi "^3.0.0" - wcwidth "^1.0.0" - combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" @@ -1310,7 +1737,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@1.5.0, concat-stream@^1.4.6: +concat-stream@1.5.0, concat-stream@^1.4.6, concat-stream@^1.4.7: version "1.5.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" dependencies: @@ -1318,21 +1745,6 @@ concat-stream@1.5.0, concat-stream@^1.4.6: readable-stream "~2.0.0" typedarray "~0.0.5" -concat-stream@^1.4.7, concat-stream@^1.5.2: - version "1.6.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" - dependencies: - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -config-chain@~1.1.10: - version "1.1.11" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2" - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - configstore@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" @@ -1398,13 +1810,17 @@ core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" +core-js@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + core-object@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" -core-object@^2.0.2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/core-object/-/core-object-2.1.1.tgz#4b7a5f1edefcb1e6d0dcb58eab1b9f90bfc666a8" +core-object@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/core-object/-/core-object-3.1.0.tgz#f5219fec2a19c40956f1c723d121890c88c5f677" dependencies: chalk "^1.1.3" @@ -1412,14 +1828,7 @@ core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -cross-spawn-async@^2.1.1: - version "2.2.5" - resolved "https://registry.yarnpkg.com/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc" - dependencies: - lru-cache "^4.0.0" - which "^1.2.8" - -cross-spawn@^5.0.0: +cross-spawn@^5.0.0, cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -1447,11 +1856,11 @@ ctype@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" -d@^0.1.1, d@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" +d@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" dependencies: - es5-ext "~0.10.2" + es5-ext "^0.10.9" dashdash@^1.12.0: version "1.14.1" @@ -1487,10 +1896,6 @@ debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: dependencies: ms "0.7.2" -debuglog@*, debuglog@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" - decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -1505,12 +1910,6 @@ deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" -defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - dependencies: - clone "^1.0.2" - defined@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" @@ -1576,6 +1975,12 @@ detect-indent@^3.0.0: minimist "^1.1.0" repeating "^1.1.0" +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + detective@^4.3.1: version "4.5.0" resolved "https://registry.yarnpkg.com/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" @@ -1583,13 +1988,6 @@ detective@^4.3.1: acorn "^4.0.3" defined "^1.0.0" -dezalgo@^1.0.0, dezalgo@^1.0.1, dezalgo@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" - dependencies: - asap "^2.0.0" - wrappy "1" - diff@1.4.0, diff@^1.3.1: version "1.4.0" resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" @@ -1617,14 +2015,14 @@ editions@^1.1.1: version "1.3.3" resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" -editor@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" - ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" +electron-to-chromium@^1.2.5, electron-to-chromium@^1.2.6: + version "1.2.7" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.2.7.tgz#4f748061407e478c76256d04496972b71f647407" + ember-ajax@^2.4.1: version "2.5.6" resolved "https://registry.yarnpkg.com/ember-ajax/-/ember-ajax-2.5.6.tgz#a75f743ccf1b95e979a5cf96013b3dba8fa625e4" @@ -1649,6 +2047,20 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-c ember-cli-version-checker "^1.0.2" resolve "^1.1.2" +ember-cli-babel@^6.0.0-beta.7: + version "6.0.0-beta.7" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.0.0-beta.7.tgz#cb5cd925c7c61b7a46a515e4954c8897227aaee4" + dependencies: + amd-name-resolver "0.0.6" + babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-polyfill "^6.16.0" + babel-preset-env "^1.2.0" + broccoli-babel-transpiler "^6.0.0" + broccoli-funnel "^1.0.0" + broccoli-source "^1.1.0" + clone "^2.0.0" + ember-cli-version-checker "^1.2.0" + ember-cli-blueprint-test-helpers@0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" @@ -1664,7 +2076,7 @@ ember-cli-blueprint-test-helpers@0.11.0: tmp-sync "^1.0.0" walk-sync "^0.2.5" -ember-cli-broccoli-sane-watcher@^2.0.3: +ember-cli-broccoli-sane-watcher@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.0.4.tgz#f43f42f75b7509c212fb926cd9aea86ae19264c6" dependencies: @@ -1698,18 +2110,17 @@ ember-cli-get-dependency-depth@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" -ember-cli-htmlbars-inline-precompile@^0.3.6: - version "0.3.6" - resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.3.6.tgz#4095fe423f93102724c0725e4dd1a31f25e24de5" +ember-cli-htmlbars-inline-precompile@^0.4.0-beta.2: + version "0.4.0-beta.2" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.0-beta.2.tgz#2ecb78ea1aaa14dd75300e3856c10c7e309209f6" dependencies: - babel-plugin-htmlbars-inline-precompile "^0.1.0" - ember-cli-babel "^5.1.3" - ember-cli-htmlbars "^1.0.0" + babel-plugin-htmlbars-inline-precompile "^0.2.3" + ember-cli-version-checker "^1.2.0" hash-for-dep "^1.0.2" ember-cli-htmlbars@^1.0.0, ember-cli-htmlbars@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-1.1.1.tgz#8776cf59796dac8f32e8625fc6d1ea45ffa55de1" + version "1.2.0" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-1.2.0.tgz#327e1a5dda1c85c6fcf8be888f7894b32c3f393b" dependencies: broccoli-persistent-filter "^1.0.3" ember-cli-version-checker "^1.0.2" @@ -1880,34 +2291,34 @@ ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-ve semver "^5.3.0" ember-cli@^2.11.1: - version "2.11.1" - resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-2.11.1.tgz#519f93ee944e0a092e77da81027400a692c5b7d3" + version "2.12.0" + resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-2.12.0.tgz#1dd081ef736570d76600ae6f7dfd043b55ac41f5" dependencies: amd-name-resolver "0.0.6" - bower "^1.3.12" bower-config "^1.3.0" bower-endpoint-parser "0.2.2" - broccoli-babel-transpiler "^5.4.5" + broccoli-babel-transpiler "^5.6.2" broccoli-brocfile-loader "^0.18.0" - broccoli-builder "^0.18.0" + broccoli-builder "^0.18.3" broccoli-concat "^3.0.4" broccoli-config-loader "^1.0.0" broccoli-config-replace "^1.1.2" broccoli-funnel "^1.0.6" broccoli-funnel-reducer "^1.0.0" broccoli-merge-trees "^1.1.3" - broccoli-middleware "^0.18.1" + broccoli-middleware "^1.0.0-beta.8" broccoli-source "^1.1.0" broccoli-stew "^1.2.0" - capture-exit "^1.0.7" + calculate-cache-key-for-tree "^1.0.0" + capture-exit "^1.1.0" chalk "^1.1.3" clean-base-url "^1.0.0" compression "^1.4.4" configstore "^2.0.0" console-ui "^1.0.2" - core-object "^2.0.2" + core-object "^3.0.0" diff "^1.3.1" - ember-cli-broccoli-sane-watcher "^2.0.3" + ember-cli-broccoli-sane-watcher "^2.0.4" ember-cli-get-component-path-option "^1.0.0" ember-cli-is-package-missing "^1.0.0" ember-cli-legacy-blueprints "^0.1.2" @@ -1915,35 +2326,38 @@ ember-cli@^2.11.1: ember-cli-normalize-entity-name "^1.0.0" ember-cli-preprocess-registry "^3.0.0" ember-cli-string-utils "^1.0.0" - ember-try "^0.2.6" + ember-try "^0.2.9" + ensure-posix-path "^1.0.2" escape-string-regexp "^1.0.3" - execa "^0.4.0" + execa "^0.6.0" exists-sync "0.0.4" exit "^0.1.2" express "^4.12.3" filesize "^3.1.3" - find-up "^1.1.2" - fs-extra "1.0.0" + find-up "^2.1.0" + fs-extra "2.0.0" fs-tree-diff "^0.5.2" get-caller-file "^1.0.0" git-repo-info "^1.0.4" glob "7.1.1" + heimdalljs "^0.2.3" heimdalljs-fs-monitor "^0.1.0" + heimdalljs-graph "^0.3.1" heimdalljs-logger "^0.1.7" http-proxy "^1.9.0" inflection "^1.7.0" is-git-url "^0.2.0" isbinaryfile "^3.0.0" js-yaml "^3.6.1" + json-stable-stringify "^1.0.1" leek "0.0.24" lodash.template "^4.2.5" - markdown-it "8.1.0" + markdown-it "^8.2.0" markdown-it-terminal "0.0.4" minimatch "^3.0.0" morgan "^1.5.2" node-modules-path "^1.0.0" - nopt "^3.0.1" - npm "3.10.8" + nopt "^4.0.0" npm-package-arg "^4.1.1" portfinder "^1.0.7" promise-map-series "^0.2.1" @@ -1954,11 +2368,11 @@ ember-cli@^2.11.1: semver "^5.1.1" silent-error "^1.0.0" sort-package-json "^1.4.0" - symlink-or-copy "^1.0.1" + symlink-or-copy "^1.1.8" temp "0.8.3" testem "^1.8.1" tiny-lr "^1.0.3" - tree-sync "^1.1.4" + tree-sync "^1.2.1" uuid "^3.0.0" walk-sync "^0.3.0" yam "0.0.22" @@ -2064,9 +2478,9 @@ ember-try-config@^2.0.1: rsvp "^3.2.1" semver "^5.1.0" -ember-try@^0.2.6: - version "0.2.10" - resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.10.tgz#8a11191fe8e5a45fb94b3bfdb0dc57d71899f16c" +ember-try@^0.2.9: + version "0.2.11" + resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.11.tgz#a793fbfe9c327e6dface808f53262a0b5f69e7b8" dependencies: chalk "^1.0.0" cli-table2 "^0.2.0" @@ -2166,61 +2580,61 @@ error@^7.0.0: string-template "~0.2.1" xtend "~4.0.0" -es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: - version "0.10.13" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.13.tgz#a390ab717bde1ce3b4cbaeabe23ca8fbddcb06f6" +es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: + version "0.10.15" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.15.tgz#c330a5934c1ee21284a7c081a86e5fd937c91ea6" dependencies: es6-iterator "2" es6-symbol "~3.1" -es6-iterator@2: - version "2.0.0" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" +es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" dependencies: - d "^0.1.1" - es5-ext "^0.10.7" - es6-symbol "3" + d "1" + es5-ext "^0.10.14" + es6-symbol "^3.1" es6-map@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" dependencies: - d "~0.1.1" - es5-ext "~0.10.11" - es6-iterator "2" - es6-set "~0.1.3" - es6-symbol "~3.1.0" - event-emitter "~0.3.4" + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-set "~0.1.5" + es6-symbol "~3.1.1" + event-emitter "~0.3.5" es6-promise@~4.0.3: version "4.0.5" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" -es6-set@~0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" +es6-set@~0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" dependencies: - d "~0.1.1" - es5-ext "~0.10.11" - es6-iterator "2" - es6-symbol "3" - event-emitter "~0.3.4" + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-symbol "3.1.1" + event-emitter "~0.3.5" -es6-symbol@3, es6-symbol@^3.0.2, es6-symbol@~3.1, es6-symbol@~3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" +es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" dependencies: - d "~0.1.1" - es5-ext "~0.10.11" + d "1" + es5-ext "~0.10.14" es6-weak-map@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" + version "2.0.2" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" dependencies: - d "^0.1.1" - es5-ext "^0.10.8" - es6-iterator "2" - es6-symbol "3" + d "1" + es5-ext "^0.10.14" + es6-iterator "^2.0.1" + es6-symbol "^3.1.1" escape-html@~1.0.3: version "1.0.3" @@ -2335,12 +2749,12 @@ etag@~1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" -event-emitter@~0.3.4: - version "0.3.4" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" +event-emitter@~0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" dependencies: - d "~0.1.1" - es5-ext "~0.10.7" + d "1" + es5-ext "~0.10.14" eventemitter3@1.x.x: version "1.2.0" @@ -2356,15 +2770,16 @@ exec-sh@^0.2.0: dependencies: merge "^1.1.3" -execa@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.4.0.tgz#4eb6467a36a095fabb2970ff9d5e3fb7bce6ebc3" +execa@^0.6.0: + version "0.6.2" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.6.2.tgz#04e9e38dec6b8e770cf0fb6cf7ef945260c67bbb" dependencies: - cross-spawn-async "^2.1.1" + cross-spawn "^5.0.1" + get-stream "^3.0.0" is-stream "^1.1.0" - npm-run-path "^1.0.0" - object-assign "^4.0.1" - path-key "^1.0.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" strip-eof "^1.0.0" exists-sync@0.0.3: @@ -2562,13 +2977,19 @@ find-index@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" -find-up@^1.0.0, find-up@^1.1.2: +find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + findup-sync@^0.4.2: version "0.4.3" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" @@ -2630,14 +3051,6 @@ form-data@~0.1.0: combined-stream "~0.0.4" mime "~1.2.11" -form-data@~1.0.0-rc4: - version "1.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" - dependencies: - async "^2.0.1" - combined-stream "^1.0.5" - mime-types "^2.1.11" - form-data@~2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" @@ -2658,13 +3071,12 @@ fs-exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" -fs-extra@1.0.0, fs-extra@^1.0.0, fs-extra@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" +fs-extra@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.0.0.tgz#337352bded4a0b714f3eb84de8cea765e9d37600" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" - klaw "^1.0.0" fs-extra@^0.24.0: version "0.24.0" @@ -2695,6 +3107,14 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" +fs-extra@^1.0.0, fs-extra@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + fs-readdir-recursive@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" @@ -2718,65 +3138,10 @@ fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5 path-posix "^1.0.0" symlink-or-copy "^1.1.8" -fs-vacuum@~1.2.9: - version "1.2.10" - resolved "https://registry.yarnpkg.com/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36" - dependencies: - graceful-fs "^4.1.2" - path-is-inside "^1.0.1" - rimraf "^2.5.2" - -fs-write-stream-atomic@~1.0.8: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - dependencies: - graceful-fs "^4.1.2" - iferr "^0.1.5" - imurmurhash "^0.1.4" - readable-stream "1 || 2" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" -fstream-ignore@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" - -fstream-npm@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fstream-npm/-/fstream-npm-1.2.0.tgz#d2c3c89101346982d64e57091c38487bda916fce" - dependencies: - fstream-ignore "^1.0.0" - inherits "2" - -fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" - -gauge@~2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.6.0.tgz#d35301ad18e96902b4751dcbbe40f4218b942a46" - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-color "^0.1.7" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - gauge@~2.7.1: version "2.7.3" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09" @@ -2808,6 +3173,10 @@ get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + getpass@^0.1.1: version "0.1.6" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" @@ -2910,17 +3279,6 @@ glob@~4.0.4: minimatch "^1.0.0" once "^1.3.0" -glob@~7.0.6: - version "7.0.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.2" - once "^1.3.0" - path-is-absolute "^1.0.0" - global-modules@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" @@ -2941,7 +3299,7 @@ globals@^6.4.0: version "6.4.1" resolved "https://registry.yarnpkg.com/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" -globals@^9.2.0: +globals@^9.0.0, globals@^9.2.0: version "9.16.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.16.0.tgz#63e903658171ec2d9f51b1d31de5e2b8dc01fb80" @@ -2962,7 +3320,7 @@ graceful-fs@^3.0.2: dependencies: natives "^1.1.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.6: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -3029,15 +3387,11 @@ has-binary@0.1.7: dependencies: isarray "0.0.1" -has-color@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" - has-cors@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" -has-unicode@^2.0.0, has-unicode@~2.0.1: +has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -3094,6 +3448,10 @@ heimdalljs-fs-monitor@^0.1.0: heimdalljs "^0.2.0" heimdalljs-logger "^0.1.7" +heimdalljs-graph@^0.3.1: + version "0.3.3" + resolved "https://registry.yarnpkg.com/heimdalljs-graph/-/heimdalljs-graph-0.3.3.tgz#ea801dbba659c8d522fe1cb83b2d605726e4918f" + heimdalljs-logger@^0.1.7: version "0.1.8" resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.8.tgz#82abb55e53eefc0e5654ddf521b82926e50fcd95" @@ -3128,6 +3486,13 @@ home-or-tmp@^1.0.0: os-tmpdir "^1.0.1" user-home "^1.1.1" +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + homedir-polyfill@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" @@ -3135,12 +3500,8 @@ homedir-polyfill@^1.0.0: parse-passwd "^1.0.0" hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: - version "2.2.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.2.0.tgz#7a0d097863d886c0fabbdcd37bf1758d8becf8a5" - -hosted-git-info@~2.1.5: - version "2.1.5" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" + version "2.3.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.3.1.tgz#ac439421605f0beb0ea1349de7d8bb28e50be1dd" http-errors@~1.6.1: version "1.6.1" @@ -3186,15 +3547,11 @@ ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" -iferr@^0.1.5, iferr@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - ignore@^3.1.2: - version "3.2.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.4.tgz#4055e03596729a8fabe45a43c100ad5ed815c4e8" + version "3.2.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.6.tgz#26e8da0644be0bb4cb39516f6c79f0e0f4ffe48c" -imurmurhash@*, imurmurhash@^0.1.4: +imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -3210,34 +3567,21 @@ inflection@^1.7.0, inflection@^1.7.1, inflection@^1.8.0: version "1.12.0" resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" -inflight@^1.0.4, inflight@~1.0.5: +inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" dependencies: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" -ini@^1.3.4, ini@~1.3.4: +ini@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" -init-package-json@~1.9.4: - version "1.9.5" - resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-1.9.5.tgz#7d4d64a264dc76c1f1f557cbbe824978bf10cd09" - dependencies: - glob "^7.1.1" - npm-package-arg "^4.0.0" - promzard "^0.3.0" - read "~1.0.1" - read-package-json "1 || 2" - semver "2.x || 3.x || 4 || 5" - validate-npm-package-license "^3.0.1" - validate-npm-package-name "^3.0.0" - inline-source-map-comment@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" @@ -3285,6 +3629,12 @@ inquirer@^1.2.3: strip-ansi "^3.0.0" through "^2.3.6" +invariant@^2.2.0, invariant@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" @@ -3477,10 +3827,6 @@ jade@0.26.3: commander "0.6.1" mkdirp "0.3.0" -jju@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jju/-/jju-1.3.0.tgz#dadd9ef01924bc728b03f2f7979bdbd62f7a2aaa" - jmespath@0.15.0: version "0.15.0" resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" @@ -3492,8 +3838,8 @@ jodid25519@^1.0.0: jsbn "~0.1.0" jquery@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.1.1.tgz#347c1c21c7e004115e0a4da32cece041fad3c8a3" + version "3.2.1" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787" js-string-escape@^1.0.0, js-string-escape@^1.0.1: version "1.0.1" @@ -3503,6 +3849,10 @@ js-tokens@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" +js-tokens@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" + js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: version "3.8.2" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.2.tgz#02d3e2c0f6beab20248d412c352203827d786721" @@ -3514,6 +3864,10 @@ jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" @@ -3529,12 +3883,6 @@ json-api-mock-server@0.1.1: jsonapi-validator "^2.1.1" object-assign "^4.1.0" -json-parse-helpfulerror@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz#13f14ce02eed4e981297b64eb9e3b932e2dd13dc" - dependencies: - jju "^1.1.0" - json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" @@ -3557,6 +3905,10 @@ json5@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" +json5@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + jsonapi-validator@^2.1.1: version "2.2.0" resolved "https://registry.yarnpkg.com/jsonapi-validator/-/jsonapi-validator-2.2.0.tgz#07f9bdb6d118c1e728fa77280605fa9b527f8c66" @@ -3666,9 +4018,12 @@ loader.js@^4.2.2: version "4.2.3" resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.2.3.tgz#845228877aa5317209e41f6c00d9bab36a6a4808" -lockfile@~1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.3.tgz#2638fc39a0331e9cac1a04b71799931c9c50df79" +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" lodash-node@^3.2.0: version "3.10.2" @@ -3704,25 +4059,10 @@ lodash._basefor@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" -lodash._baseindexof@*: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" - -lodash._baseuniq@~4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" - dependencies: - lodash._createset "~4.0.0" - lodash._root "~3.0.0" - -lodash._bindcallback@*, lodash._bindcallback@^3.0.0: +lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" -lodash._cacheindexof@*: - version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" - lodash._createassigner@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" @@ -3731,17 +4071,7 @@ lodash._createassigner@^3.0.0: lodash._isiterateecall "^3.0.0" lodash.restparam "^3.0.0" -lodash._createcache@*: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" - dependencies: - lodash._getnative "^3.0.0" - -lodash._createset@~4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" - -lodash._getnative@*, lodash._getnative@^3.0.0: +lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" @@ -3753,10 +4083,6 @@ lodash._reinterpolate@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" -lodash._root@~3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" - lodash.assign@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" @@ -3773,7 +4099,7 @@ lodash.assignin@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" -lodash.clonedeep@^4.4.1, lodash.clonedeep@~4.5.0: +lodash.clonedeep@^4.4.1: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -3853,7 +4179,7 @@ lodash.omit@^4.1.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" -lodash.restparam@*, lodash.restparam@^3.0.0: +lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" @@ -3877,23 +4203,15 @@ lodash.toplainobject@^3.0.0: lodash._basecopy "^3.0.0" lodash.keysin "^3.0.0" -lodash.union@~4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" - -lodash.uniq@^4.2.0, lodash.uniq@~4.5.0: +lodash.uniq@^4.2.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -lodash.without@~4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" - lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.3.0, lodash@^4.6.1: +lodash@^4.0.0, lodash@^4.15.0, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -3909,11 +4227,17 @@ longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" +loose-envify@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + lru-cache@2: version "2.7.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" -lru-cache@^4.0.0, lru-cache@^4.0.1: +lru-cache@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" dependencies: @@ -3940,16 +4264,6 @@ markdown-it-terminal@0.0.4: lodash.merge "^3.3.2" markdown-it "^4.4.0" -markdown-it@8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.1.0.tgz#38902d4e7bac2260c073eb67be623211fbb2c2e3" - dependencies: - argparse "^1.0.7" - entities "~1.1.1" - linkify-it "^2.0.0" - mdurl "^1.0.1" - uc.micro "^1.0.3" - markdown-it@^4.3.0, markdown-it@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" @@ -3960,6 +4274,16 @@ markdown-it@^4.3.0, markdown-it@^4.4.0: mdurl "~1.0.0" uc.micro "^1.0.0" +markdown-it@^8.2.0: + version "8.3.1" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.3.1.tgz#2f4b622948ccdc193d66f3ca2d43125ac4ac7323" + dependencies: + argparse "^1.0.7" + entities "~1.1.1" + linkify-it "^2.0.0" + mdurl "^1.0.1" + uc.micro "^1.0.3" + matcher-collection@^1.0.0, matcher-collection@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-1.0.4.tgz#2f66ae0869996f29e43d0b62c83dd1d43e581755" @@ -3988,10 +4312,6 @@ media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" -mem@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/mem/-/mem-0.1.1.tgz#24df988c3102b03c074c1b296239c5b2e6647825" - memory-streams@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.2.tgz#273ff777ab60fec599b116355255282cca2c50c2" @@ -4028,11 +4348,15 @@ micromatch@^2.1.5, micromatch@^2.3.7: parse-glob "^3.0.4" regex-cache "^0.4.2" -"mime-db@>= 1.24.0 < 2", mime-db@~1.26.0: +"mime-db@>= 1.24.0 < 2": + version "1.27.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" + +mime-db@~1.26.0: version "1.26.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" -mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: +mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: version "2.1.14" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" dependencies: @@ -4094,7 +4418,7 @@ mkdirp@0.5.0: dependencies: minimist "0.0.8" -mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: @@ -4137,8 +4461,8 @@ moment-timezone@^0.3.0: moment ">= 2.6.0" "moment@>= 2.6.0": - version "2.17.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.17.1.tgz#fed9506063f36b10f066c8b59a144d7faebe1d82" + version "2.18.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.0.tgz#6cfec6a495eca915d02600a67020ed994937252c" morgan@^1.5.2, morgan@^1.7.0: version "1.8.1" @@ -4170,7 +4494,7 @@ mute-stream@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" -mute-stream@0.0.6, mute-stream@~0.0.4: +mute-stream@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" @@ -4189,25 +4513,6 @@ node-fetch@^1.3.3: encoding "^0.1.11" is-stream "^1.0.1" -node-gyp@~3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.4.0.tgz#dda558393b3ecbbe24c9e6b8703c71194c63fa36" - dependencies: - fstream "^1.0.0" - glob "^7.0.3" - graceful-fs "^4.1.2" - minimatch "^3.0.2" - mkdirp "^0.5.0" - nopt "2 || 3" - npmlog "0 || 1 || 2 || 3" - osenv "0" - path-array "^1.0.0" - request "2" - rimraf "2" - semver "2.x || 3.x || 4 || 5" - tar "^2.0.0" - which "1" - node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -4217,29 +4522,32 @@ node-modules-path@^1.0.0: resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" node-notifier@^5.0.1: - version "5.0.2" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.0.2.tgz#4438449fe69e321f941cef943986b0797032701b" + version "5.1.2" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff" dependencies: growly "^1.3.0" semver "^5.3.0" shellwords "^0.1.0" which "^1.2.12" -node-uuid@~1.4.0, node-uuid@~1.4.7: +node-uuid@~1.4.0: version "1.4.7" resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" -"nopt@2 || 3", nopt@^3.0.1, nopt@^3.0.3, nopt@~3.0.6: +nopt@^3.0.3: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: abbrev "1" -normalize-git-url@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/normalize-git-url/-/normalize-git-url-3.0.2.tgz#8e5f14be0bdaedb73e07200310aa416c27350fc4" +nopt@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" -normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, "normalize-package-data@~1.0.1 || ^2.0.0", normalize-package-data@~2.3.5: +normalize-package-data@^2.3.2: version "2.3.6" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff" dependencies: @@ -4252,139 +4560,24 @@ normalize-path@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" -npm-cache-filename@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" - npm-git-info@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" -npm-install-checks@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-3.0.0.tgz#d4aecdfd51a53e3723b7b2f93b2ee28e307bc0d7" - dependencies: - semver "^2.3.0 || 3.x || 4 || 5" - -"npm-package-arg@^3.0.0 || ^4.0.0", npm-package-arg@^4.0.0, npm-package-arg@^4.1.1, npm-package-arg@~4.2.0: +npm-package-arg@^4.1.1: version "4.2.1" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" dependencies: hosted-git-info "^2.1.5" semver "^5.1.0" -npm-registry-client@~7.2.1: - version "7.2.1" - resolved "https://registry.yarnpkg.com/npm-registry-client/-/npm-registry-client-7.2.1.tgz#c792266b088cc313f8525e7e35248626c723db75" - dependencies: - concat-stream "^1.5.2" - graceful-fs "^4.1.6" - normalize-package-data "~1.0.1 || ^2.0.0" - npm-package-arg "^3.0.0 || ^4.0.0" - once "^1.3.3" - request "^2.74.0" - retry "^0.10.0" - semver "2 >=2.2.1 || 3.x || 4 || 5" - slide "^1.1.3" - optionalDependencies: - npmlog "~2.0.0 || ~3.1.0" - -npm-run-path@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-1.0.0.tgz#f5c32bf595fe81ae927daec52e82f8b000ac3c8f" - dependencies: - path-key "^1.0.0" - -npm-user-validate@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-0.1.5.tgz#52465d50c2d20294a57125b996baedbf56c5004b" - -npm@3.10.8: - version "3.10.8" - resolved "https://registry.yarnpkg.com/npm/-/npm-3.10.8.tgz#8f76ff8c6da04b61dd371d554ce40a0b8916c15e" - dependencies: - abbrev "~1.0.9" - ansicolors "~0.3.2" - ansistyles "~0.1.3" - aproba "~1.0.4" - archy "~1.0.0" - asap "~2.0.4" - chownr "~1.0.1" - cmd-shim "~2.0.2" - columnify "~1.5.4" - config-chain "~1.1.10" - dezalgo "~1.0.3" - editor "~1.0.0" - fs-vacuum "~1.2.9" - fs-write-stream-atomic "~1.0.8" - fstream "~1.0.10" - fstream-npm "~1.2.0" - glob "~7.0.6" - graceful-fs "~4.1.6" - has-unicode "~2.0.1" - hosted-git-info "~2.1.5" - iferr "~0.1.5" - inflight "~1.0.5" - inherits "~2.0.3" - ini "~1.3.4" - init-package-json "~1.9.4" - lockfile "~1.0.1" - lodash._baseuniq "~4.6.0" - lodash.clonedeep "~4.5.0" - lodash.union "~4.6.0" - lodash.uniq "~4.5.0" - lodash.without "~4.4.0" - mkdirp "~0.5.1" - node-gyp "~3.4.0" - nopt "~3.0.6" - normalize-git-url "~3.0.2" - normalize-package-data "~2.3.5" - npm-cache-filename "~1.0.2" - npm-install-checks "~3.0.0" - npm-package-arg "~4.2.0" - npm-registry-client "~7.2.1" - npm-user-validate "~0.1.5" - npmlog "~4.0.0" - once "~1.4.0" - opener "~1.4.1" - osenv "~0.1.3" - path-is-inside "~1.0.1" - read "~1.0.7" - read-cmd-shim "~1.0.1" - read-installed "~4.0.3" - read-package-json "~2.0.4" - read-package-tree "~5.1.5" - readable-stream "~2.1.5" - realize-package-specifier "~3.0.3" - request "~2.74.0" - retry "~0.10.0" - rimraf "~2.5.4" - semver "~5.3.0" - sha "~2.0.1" - slide "~1.1.6" - sorted-object "~2.0.0" - strip-ansi "~3.0.1" - tar "~2.2.1" - text-table "~0.2.0" - uid-number "0.0.6" - umask "~1.1.0" - unique-filename "~1.1.0" - unpipe "~1.0.0" - validate-npm-package-name "~2.2.2" - which "~1.2.11" - wrappy "~1.0.2" - write-file-atomic "~1.2.0" - -"npmlog@0 || 1 || 2 || 3", "npmlog@~2.0.0 || ~3.1.0": - version "3.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-3.1.2.tgz#2d46fa874337af9498a2f12bb43d8d0be4a36873" +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.6.0" - set-blocking "~2.0.0" + path-key "^2.0.0" -npmlog@^4.0.0, npmlog@~4.0.0: +npmlog@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" dependencies: @@ -4434,7 +4627,7 @@ on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" -once@^1.3.0, once@^1.3.3, once@~1.4.0: +once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: @@ -4444,10 +4637,6 @@ onetime@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" -opener@~1.4.1: - version "1.4.3" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" - optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" @@ -4497,7 +4686,7 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -osenv@0, osenv@^0.1.0, osenv@^0.1.3, osenv@~0.1.3: +osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" dependencies: @@ -4512,6 +4701,20 @@ output-file-sync@^1.1.0: mkdirp "^0.5.1" object-assign "^4.1.0" +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +p-limit@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -4553,12 +4756,6 @@ parseurl@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" -path-array@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271" - dependencies: - array-index "^1.0.0" - path-exists@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" @@ -4569,17 +4766,21 @@ path-exists@^2.0.0: dependencies: pinkie-promise "^2.0.0" +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-is-inside@^1.0.1, path-is-inside@~1.0.1: +path-is-inside@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" -path-key@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-1.0.0.tgz#5d53d578019646c0d68800db4e146e6bdc2ac7af" +path-key@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" path-parse@^1.0.5: version "1.0.5" @@ -4699,16 +4900,6 @@ promise-map-series@^0.2.1: dependencies: rsvp "^3.0.14" -promzard@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" - dependencies: - read "1" - -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - proxy-addr@~1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.3.tgz#dc97502f5722e888467b3fa2297a7b1ff47df074" @@ -4740,10 +4931,6 @@ qs@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" -qs@~6.2.0: - version "6.2.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.3.tgz#1cfcb25c10a9b2b483053ff39f5dfc9233908cfe" - qs@~6.3.0: version "6.3.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" @@ -4794,45 +4981,6 @@ raw-body@~2.2.0: iconv-lite "0.4.15" unpipe "1.0.0" -read-cmd-shim@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b" - dependencies: - graceful-fs "^4.1.2" - -read-installed@~4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" - dependencies: - debuglog "^1.0.1" - read-package-json "^2.0.0" - readdir-scoped-modules "^1.0.0" - semver "2 || 3 || 4 || 5" - slide "~1.1.3" - util-extend "^1.0.1" - optionalDependencies: - graceful-fs "^4.1.2" - -"read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@~2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.0.5.tgz#f93a64e641529df68a08c64de46389e8a3f88845" - dependencies: - glob "^7.1.1" - json-parse-helpfulerror "^1.0.2" - normalize-package-data "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.2" - -read-package-tree@~5.1.5: - version "5.1.5" - resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.1.5.tgz#ace7e6381c7684f970aaa98fc7c5d2b666addab6" - dependencies: - debuglog "^1.0.1" - dezalgo "^1.0.0" - once "^1.3.0" - read-package-json "^2.0.0" - readdir-scoped-modules "^1.0.0" - read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -4848,15 +4996,9 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -read@1, read@~1.0.1, read@~1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" - dependencies: - mute-stream "~0.0.4" - -"readable-stream@1 || 2", "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@~2.1.5: - version "2.1.5" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" +readable-stream@^2, "readable-stream@^2.0.0 || ^1.1.13": + version "2.2.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.6.tgz#8b43aed76e71483938d12a8d46c6cf1a00b1f816" dependencies: buffer-shims "^1.0.0" core-util-is "~1.0.0" @@ -4866,22 +5008,19 @@ read@1, read@~1.0.1, read@~1.0.7: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readable-stream@^2, readable-stream@~2.0.0, readable-stream@~2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" +readable-stream@~1.0.2: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" + isarray "0.0.1" string_decoder "~0.10.x" - util-deprecate "~1.0.1" -readable-stream@^2.2.2: - version "2.2.5" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.5.tgz#a0b187304e05bab01a4ce2b4cc9c607d5aa1d606" +readable-stream@~2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" dependencies: - buffer-shims "^1.0.0" core-util-is "~1.0.0" inherits "~2.0.1" isarray "~1.0.0" @@ -4889,24 +5028,6 @@ readable-stream@^2.2.2: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readable-stream@~1.0.2: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" - dependencies: - debuglog "^1.0.1" - dezalgo "^1.0.0" - graceful-fs "^4.1.2" - once "^1.3.0" - readline2@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" @@ -4915,13 +5036,6 @@ readline2@^1.0.1: is-fullwidth-code-point "^1.0.0" mute-stream "0.0.5" -realize-package-specifier@~3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/realize-package-specifier/-/realize-package-specifier-3.0.3.tgz#d0def882952b8de3f67eba5e91199661271f41f4" - dependencies: - dezalgo "^1.0.1" - npm-package-arg "^4.1.1" - recast@0.10.33: version "0.10.33" resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" @@ -4959,6 +5073,18 @@ regenerate@^1.2.1: version "1.3.2" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" +regenerator-runtime@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e" + +regenerator-transform@0.9.8: + version "0.9.8" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.8.tgz#0f88bb2bc03932ddb7b6b7312e68078f01026d6c" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + regenerator@0.8.40: version "0.8.40" resolved "https://registry.yarnpkg.com/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" @@ -4977,6 +5103,14 @@ regex-cache@^0.4.2: is-equal-shallow "^0.1.3" is-primitive "^2.0.0" +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + regexpu@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" @@ -5011,37 +5145,18 @@ repeating@^1.1.0, repeating@^1.1.2: dependencies: is-finite "^1.0.0" +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + request-progress@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" dependencies: throttleit "^1.0.0" -request@2, request@^2.74.0, request@~2.79.0: - version "2.79.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.11.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~2.0.6" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - qs "~6.3.0" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" - uuid "^3.0.0" - request@~2.40.0: version "2.40.0" resolved "https://registry.yarnpkg.com/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" @@ -5061,18 +5176,17 @@ request@~2.40.0: tough-cookie ">=0.12.0" tunnel-agent "~0.4.0" -request@~2.74.0: - version "2.74.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.74.0.tgz#7693ca768bbb0ea5c8ce08c084a45efa05b892ab" +request@~2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" dependencies: aws-sign2 "~0.6.0" aws4 "^1.2.1" - bl "~1.1.2" caseless "~0.11.0" combined-stream "~1.0.5" extend "~3.0.0" forever-agent "~0.6.1" - form-data "~1.0.0-rc4" + form-data "~2.1.1" har-validator "~2.0.6" hawk "~3.1.3" http-signature "~1.1.0" @@ -5080,12 +5194,12 @@ request@~2.74.0: isstream "~0.1.2" json-stringify-safe "~5.0.1" mime-types "~2.1.7" - node-uuid "~1.4.7" oauth-sign "~0.8.1" - qs "~6.2.0" + qs "~6.3.0" stringstream "~0.0.4" tough-cookie "~2.3.0" tunnel-agent "~0.4.1" + uuid "^3.0.0" require-directory@^2.1.1: version "2.1.1" @@ -5130,28 +5244,24 @@ restore-cursor@^1.0.1: exit-hook "^1.0.0" onetime "^1.0.0" -retry@^0.10.0, retry@~0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" - right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.3.2, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4: - version "2.6.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" - dependencies: - glob "^7.0.5" - -rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.5.1: +rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" +rimraf@^2.5.3, rimraf@^2.5.4: + version "2.6.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" + dependencies: + glob "^7.0.5" + rimraf@~2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.1.4.tgz#5a6eb62eeda068f51ede50f29b3e5cd22f3d9bb2" @@ -5162,12 +5272,6 @@ rimraf@~2.2.6: version "2.2.8" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" -rimraf@~2.5.4: - version "2.5.4" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" - dependencies: - glob "^7.0.5" - route-recognizer@^0.1.9: version "0.1.11" resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" @@ -5176,13 +5280,13 @@ route-recognizer@^0.2.3: version "0.2.10" resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" -rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.6, rsvp@^3.2.1, rsvp@~3.2.1: +rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.6, rsvp@~3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" -rsvp@^3.0.14, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3, rsvp@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.4.0.tgz#96f397d9c7e294351b3c1456a74b3d0e7542988d" +rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" rsvp@~3.0.6: version "3.0.21" @@ -5241,7 +5345,7 @@ selenium-webdriver@^3.0.0-beta-2: tmp "0.0.30" xml2js "^0.4.17" -"semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0, semver@~5.3.0: +"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" @@ -5284,13 +5388,6 @@ setprototypeof@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" -sha@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae" - dependencies: - graceful-fs "^4.1.2" - readable-stream "^2.0.2" - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -5343,7 +5440,7 @@ slice-ansi@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" -slide@^1.1.3, slide@^1.1.5, slide@~1.1.3, slide@~1.1.6: +slide@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" @@ -5413,16 +5510,18 @@ sort-package-json@^1.4.0: dependencies: sort-object-keys "^1.1.1" -sorted-object@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/sorted-object/-/sorted-object-2.0.1.tgz#7d631f4bd3a798a24af1dffcfbfe83337a5df5fc" - source-map-support@^0.2.10: version "0.2.10" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" dependencies: source-map "0.1.32" +source-map-support@^0.4.2: + version "0.4.14" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef" + dependencies: + source-map "^0.5.6" + source-map-url@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" @@ -5439,7 +5538,7 @@ source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: dependencies: amdefine ">=0.0.4" -source-map@^0.5.0, source-map@~0.5.0, source-map@~0.5.1: +source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: version "0.5.6" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" @@ -5496,8 +5595,8 @@ sshpk@^1.7.0: tweetnacl "~0.14.0" stable@~0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.5.tgz#08232f60c732e9890784b5bed0734f8b32a887b9" + version "0.1.6" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10" "statuses@>= 1.3.1 < 2", statuses@~1.3.1: version "1.3.1" @@ -5544,7 +5643,7 @@ strip-ansi@^0.3.0: dependencies: ansi-regex "^0.2.1" -strip-ansi@^3.0.0, strip-ansi@^3.0.1, strip-ansi@~3.0.1: +strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: @@ -5614,14 +5713,6 @@ tap-parser@^5.1.0: optionalDependencies: readable-stream "^2" -tar@^2.0.0, tar@~2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" - temp@0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" @@ -5719,7 +5810,7 @@ to-array@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" -to-fast-properties@^1.0.0: +to-fast-properties@^1.0.0, to-fast-properties@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" @@ -5729,7 +5820,7 @@ tough-cookie@>=0.12.0, tough-cookie@~2.3.0: dependencies: punycode "^1.4.1" -tree-sync@^1.1.4: +tree-sync@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" dependencies: @@ -5739,7 +5830,7 @@ tree-sync@^1.1.4: quick-temp "^0.1.5" walk-sync "^0.2.7" -trim-right@^1.0.0: +trim-right@^1.0.0, trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" @@ -5784,7 +5875,7 @@ type-is@~1.6.14: media-typer "0.3.0" mime-types "~2.1.13" -typedarray@^0.0.6, typedarray@~0.0.5: +typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -5793,8 +5884,8 @@ uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.3: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" uglify-js@^2.6, uglify-js@^2.7.0: - version "2.8.12" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.12.tgz#8a50f5d482243650b7108f6080aa3a6afe2a6c55" + version "2.8.14" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.14.tgz#25b15d1af39b21752ee33703adbf432e8bc8f77d" dependencies: source-map "~0.5.1" uglify-to-browserify "~1.0.0" @@ -5804,18 +5895,10 @@ uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" -uid-number@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - ultron@1.0.x: version "1.0.2" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" -umask@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" - underscore.string@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" @@ -5824,18 +5907,6 @@ underscore@>=1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" -unique-filename@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.0.tgz#d05f2fe4032560871f30e93cbe735eea201514f3" - dependencies: - unique-slug "^2.0.0" - -unique-slug@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab" - dependencies: - imurmurhash "^0.1.4" - unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -5863,21 +5934,10 @@ user-home@^2.0.0: dependencies: os-homedir "^1.0.0" -username@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/username/-/username-2.3.0.tgz#ba37dd53ac7d6225e77730fdd79244f1fc058e1e" - dependencies: - execa "^0.4.0" - mem "^0.1.0" - util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" -util-extend@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" - utils-merge@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" @@ -5894,28 +5954,16 @@ uuid@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" -validate-npm-package-license@*, validate-npm-package-license@^3.0.1: +validate-npm-package-license@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" dependencies: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" -validate-npm-package-name@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" - dependencies: - builtins "^1.0.3" - -validate-npm-package-name@~2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-2.2.2.tgz#f65695b22f7324442019a3c7fa39a6e7fd299085" - dependencies: - builtins "0.0.7" - vary@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" + version "1.1.1" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" verror@1.3.6: version "1.3.6" @@ -5951,12 +5999,6 @@ watch@~0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" -wcwidth@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - dependencies: - defaults "^1.0.3" - websocket-driver@>=0.5.1: version "0.6.5" resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" @@ -5971,7 +6013,7 @@ which-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" -which@1, which@^1.2.12, which@^1.2.8, which@^1.2.9, which@~1.2.10, which@~1.2.11: +which@^1.2.12, which@^1.2.9, which@~1.2.10: version "1.2.12" resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" dependencies: @@ -6014,7 +6056,7 @@ wrap-ansi@^2.0.0: string-width "^1.0.1" strip-ansi "^3.0.1" -wrappy@1, wrappy@~1.0.2: +wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -6026,14 +6068,6 @@ write-file-atomic@^1.1.2: imurmurhash "^0.1.4" slide "^1.1.5" -write-file-atomic@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.2.0.tgz#14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab" - dependencies: - graceful-fs "^4.1.2" - imurmurhash "^0.1.4" - slide "^1.1.5" - write@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" @@ -6078,13 +6112,13 @@ xml2js@^0.4.17: sax ">=0.6.0" xmlbuilder "^4.1.0" -xmlbuilder@2.6.2: +xmlbuilder@2.6.2, xmlbuilder@>=2.4.6: version "2.6.2" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-2.6.2.tgz#f916f6d10d45dc171b1be2e6e673fb6e0cc35d0a" dependencies: lodash "~3.5.0" -xmlbuilder@>=2.4.6, xmlbuilder@^4.1.0: +xmlbuilder@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" dependencies: From a9f30ef5364b75b08ce33ca7b7deaeaa4cfc6fc5 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Tue, 21 Mar 2017 15:38:14 -0700 Subject: [PATCH 1865/2527] Defer serializer loading There's no need to load serializers if and until the adapter fetch promise resolves. --- addon/-private/system/store/finders.js | 18 +- tests/unit/store/finders-test.js | 285 +++++++++++++++++++++++++ 2 files changed, 294 insertions(+), 9 deletions(-) create mode 100644 tests/unit/store/finders-test.js diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 8cdd6726b17..053dbb92d23 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -28,7 +28,6 @@ export function _find(adapter, store, modelClass, id, internalModel, options) { let snapshot = internalModel.createSnapshot(options); let { modelName } = internalModel; let promise = adapter.findRecord(store, modelClass, id, snapshot); - let serializer = serializerForAdapter(store, adapter, modelName); let label = `DS: Handle Adapter#findRecord of '${modelName}' with id: '${id}'`; promise = Promise.resolve(promise, label); @@ -36,6 +35,7 @@ export function _find(adapter, store, modelClass, id, internalModel, options) { return promise.then(adapterPayload => { assert(`You made a 'findRecord' request for a '${modelName}' with id '${id}', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); + let serializer = serializerForAdapter(store, adapter, modelName); let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, id, 'findRecord'); assert(`Ember Data expected the primary data returned from a 'findRecord' response to be an object but instead it found an array.`, !Array.isArray(payload.data)); @@ -58,7 +58,6 @@ export function _findMany(adapter, store, modelName, ids, internalModels) { let snapshots = Ember.A(internalModels).invoke('createSnapshot'); let modelClass = store.modelFor(modelName); // `adapter.findMany` gets the modelClass still let promise = adapter.findMany(store, modelClass, ids, snapshots); - let serializer = serializerForAdapter(store, adapter, modelName); let label = `DS: Handle Adapter#findMany of '${modelName}'`; if (promise === undefined) { @@ -70,6 +69,7 @@ export function _findMany(adapter, store, modelName, ids, internalModels) { return promise.then(adapterPayload => { assert(`You made a 'findMany' request for '${modelName}' records with ids '[${ids}]', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); + let serializer = serializerForAdapter(store, adapter, modelName); let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findMany'); return store._push(payload); }, null, `DS: Extract payload of ${modelName}`); @@ -79,7 +79,6 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) let snapshot = internalModel.createSnapshot(); let modelClass = store.modelFor(relationship.type); let promise = adapter.findHasMany(store, snapshot, link, relationship); - let serializer = serializerForAdapter(store, adapter, relationship.type); let label = `DS: Handle Adapter#findHasMany of '${internalModel.modelName}' : '${relationship.type}'`; promise = Promise.resolve(promise, label); @@ -88,6 +87,7 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) return promise.then(adapterPayload => { assert(`You made a 'findHasMany' request for a ${internalModel.modelName}'s '${relationship.key}' relationship, using link '${link}' , but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); + let serializer = serializerForAdapter(store, adapter, relationship.type); let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findHasMany'); let internalModelArray = store._push(payload); @@ -100,7 +100,6 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship let snapshot = internalModel.createSnapshot(); let modelClass = store.modelFor(relationship.type); let promise = adapter.findBelongsTo(store, snapshot, link, relationship); - let serializer = serializerForAdapter(store, adapter, relationship.type); let label = `DS: Handle Adapter#findBelongsTo of ${internalModel.modelName} : ${relationship.type}`; promise = Promise.resolve(promise, label); @@ -108,6 +107,7 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship promise = _guard(promise, _bind(_objectIsAlive, internalModel)); return promise.then(adapterPayload => { + let serializer = serializerForAdapter(store, adapter, relationship.type); let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findBelongsTo'); if (!payload.data) { @@ -123,7 +123,6 @@ export function _findAll(adapter, store, modelName, sinceToken, options) { let recordArray = store.peekAll(modelName); let snapshotArray = recordArray._createSnapshot(options); let promise = adapter.findAll(store, modelClass, sinceToken, snapshotArray); - let serializer = serializerForAdapter(store, adapter, modelName); let label = "DS: Handle Adapter#findAll of " + modelClass; promise = Promise.resolve(promise, label); @@ -131,6 +130,7 @@ export function _findAll(adapter, store, modelName, sinceToken, options) { return promise.then(adapterPayload => { assert(`You made a 'findAll' request for '${modelName}' records, but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); + let serializer = serializerForAdapter(store, adapter, modelName); let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findAll'); store._push(payload); @@ -144,15 +144,15 @@ export function _query(adapter, store, modelName, query, recordArray) { let modelClass = store.modelFor(modelName); // adapter.query needs the class let promise = adapter.query(store, modelClass, query, recordArray); - let serializerToken = heimdall.start('initial-serializerFor-lookup'); - let serializer = serializerForAdapter(store, adapter, modelName); - heimdall.stop(serializerToken); let label = `DS: Handle Adapter#query of ${modelClass}`; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(adapterPayload => { + let serializerToken = heimdall.start('initial-serializerFor-lookup'); + let serializer = serializerForAdapter(store, adapter, modelName); + heimdall.stop(serializerToken); let normalizeToken = heimdall.start('finders#_query::normalizeResponseHelper'); let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'query'); heimdall.stop(normalizeToken); @@ -168,13 +168,13 @@ export function _query(adapter, store, modelName, query, recordArray) { export function _queryRecord(adapter, store, modelName, query) { let modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class let promise = adapter.queryRecord(store, modelClass, query); - let serializer = serializerForAdapter(store, adapter, modelName); let label = `DS: Handle Adapter#queryRecord of ${modelName}`; promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(adapterPayload => { + let serializer = serializerForAdapter(store, adapter, modelName); let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'queryRecord'); assert(`Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array.`, !Array.isArray(payload.data), { diff --git a/tests/unit/store/finders-test.js b/tests/unit/store/finders-test.js new file mode 100644 index 00000000000..54df12b39c3 --- /dev/null +++ b/tests/unit/store/finders-test.js @@ -0,0 +1,285 @@ +import setupStore from 'dummy/tests/helpers/store'; +import Ember from 'ember'; + +import {module, test} from 'qunit'; + +const { run } = Ember; +const { defer } = Ember.RSVP; + +import DS from 'ember-data'; + +module('unit/store/finders', { + beforeEach() { + this.Person = DS.Model.extend({ + updatedAt: DS.attr('string'), + name: DS.attr('string'), + firstName: DS.attr('string'), + lastName: DS.attr('string') + }); + + this.Dog = DS.Model.extend({ + name: DS.attr('string') + }); + + this.env = setupStore({ person: this.Person, dog: this.Dog }); + this.store = this.env.store; + this.adapter = this.env.adapter; + }, + + afterEach() { + run(this.env.container, 'destroy'); + } +}); + +test('findRecord does not load a serializer until the adapter promise resolves', function(assert) { + assert.expect(2); + + let deferedFind = defer(); + + this.env.registry.register('adapter:person', DS.Adapter.extend({ + findRecord: () => deferedFind.promise + })); + + let serializerLoaded = false; + let serializerFor = this.store.serializerFor; + this.store.serializerFor = (modelName) => { + if (modelName === 'person') { + serializerLoaded = true; + } + return serializerFor.call(this.store, modelName); + }; + + let storePromise = run(() => this.store.findRecord('person', 1)); + assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); + + return run(() => { + deferedFind.resolve({ id: 1, name: 'John Churchill' }); + return storePromise.then(() => { + assert.equal(true, serializerLoaded, 'serializer is loaded'); + }); + }); +}); + +test('findMany does not load a serializer until the adapter promise resolves', function(assert) { + assert.expect(2); + + let deferedFind = defer(); + + this.env.registry.register('adapter:person', DS.Adapter.extend({ + findMany: () => deferedFind.promise + })); + + let serializerLoaded = false; + let serializerFor = this.store.serializerFor; + this.store.serializerFor = (modelName) => { + if (modelName === 'person') { + serializerLoaded = true; + } + return serializerFor.call(this.store, modelName); + }; + + let storePromise = run(() => { + this.store.findRecord('person', 1) + return this.store.findRecord('person', 2); + }); + assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); + + return run(() => { + deferedFind.resolve([{ id: 1, name: 'John Churchill' }, { id: 2, name: 'Louis Joseph' }]); + return storePromise.then(() => { + assert.equal(true, serializerLoaded, 'serializer is loaded'); + }); + }); +}); + +test('findHasMany does not load a serializer until the adapter promise resolves', function(assert) { + assert.expect(2); + + let deferedFind = defer(); + + this.env.registry.register('adapter:person', DS.Adapter.extend({ + findHasMany: () => deferedFind.promise + })); + + this.Person.reopen({ + dogs: DS.hasMany('dog', { async: true }) + }); + + let serializerLoaded = false; + let serializerFor = this.store.serializerFor; + this.store.serializerFor = (modelName) => { + if (modelName === 'dog') { + serializerLoaded = true; + } + return serializerFor.call(this.store, modelName); + }; + + let storePromise = run(() => { + this.env.store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill' + }, + relationships: { + dogs: { + links: { + related: 'http://exmaple.com/person/1/dogs' + } + } + } + } + }); + + return this.store.peekRecord('person', 1).get('dogs'); + }); + assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); + + return run(() => { + deferedFind.resolve([{ id: 1, name: 'Scooby' }, { id: 2, name: 'Scrappy' }]); + return storePromise.then(() => { + assert.equal(true, serializerLoaded, 'serializer is loaded'); + }); + }); +}); + +test('findBelongsTo does not load a serializer until the adapter promise resolves', function(assert) { + assert.expect(2); + + let deferedFind = defer(); + + this.env.registry.register('adapter:person', DS.Adapter.extend({ + findBelongsTo: () => deferedFind.promise + })); + + this.Person.reopen({ + favoriteDog: DS.belongsTo('dog', { async: true }) + }); + + let serializerLoaded = false; + let serializerFor = this.store.serializerFor; + this.store.serializerFor = (modelName) => { + if (modelName === 'dog') { + serializerLoaded = true; + } + return serializerFor.call(this.store, modelName); + }; + + let storePromise = run(() => { + this.env.store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill' + }, + relationships: { + favoriteDog: { + links: { + related: 'http://exmaple.com/person/1/favorite-dog' + } + } + } + } + }); + + return this.store.peekRecord('person', 1).get('favoriteDog'); + }); + assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); + + return run(() => { + deferedFind.resolve({ id: 1, name: 'Scooby' }); + return storePromise.then(() => { + assert.equal(true, serializerLoaded, 'serializer is loaded'); + }); + }); +}); + +test('findAll does not load a serializer until the adapter promise resolves', function(assert) { + assert.expect(2); + + let deferedFind = defer(); + + this.env.registry.register('adapter:person', DS.Adapter.extend({ + findAll: () => deferedFind.promise + })); + + let serializerLoaded = false; + let serializerFor = this.store.serializerFor; + this.store.serializerFor = (modelName) => { + if (modelName === 'person') { + serializerLoaded = true; + } + return serializerFor.call(this.store, modelName); + }; + + let storePromise = run(() => this.store.findAll('person')); + assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); + + return run(() => { + deferedFind.resolve([{ id: 1, name: 'John Churchill' }]); + return storePromise.then(() => { + assert.equal(true, serializerLoaded, 'serializer is loaded'); + }); + }); +}); + +test('query does not load a serializer until the adapter promise resolves', function(assert) { + assert.expect(2); + + let deferedFind = defer(); + + this.env.registry.register('adapter:person', DS.Adapter.extend({ + query: () => deferedFind.promise + })); + + let serializerLoaded = false; + let serializerFor = this.store.serializerFor; + this.store.serializerFor = (modelName) => { + if (modelName === 'person') { + serializerLoaded = true; + } + return serializerFor.call(this.store, modelName); + }; + + let storePromise = run(() => this.store.query('person', { first_duke_of_marlborough: true })); + assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); + + return run(() => { + deferedFind.resolve([{ id: 1, name: 'John Churchill' }]); + return storePromise.then(() => { + assert.equal(true, serializerLoaded, 'serializer is loaded'); + }); + }); +}); + +test('queryRecord does not load a serializer until the adapter promise resolves', function(assert) { + assert.expect(2); + + let deferedFind = defer(); + + this.env.registry.register('adapter:person', DS.Adapter.extend({ + queryRecord: () => deferedFind.promise + })); + + let serializerLoaded = false; + let serializerFor = this.store.serializerFor; + this.store.serializerFor = (modelName) => { + if (modelName === 'person') { + serializerLoaded = true; + } + return serializerFor.call(this.store, modelName); + }; + + let storePromise = run(() => this.store.queryRecord('person', { first_duke_of_marlborough: true })); + assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); + + return run(() => { + deferedFind.resolve({ id: 1, name: 'John Churchill' }); + return storePromise.then(() => { + assert.equal(true, serializerLoaded, 'serializer is loaded'); + }); + }); +}); + From efc236c44ef971d15d0c75e1c8b5fa45087e62eb Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Tue, 21 Mar 2017 16:10:27 -0700 Subject: [PATCH 1866/2527] Convert SnapshotRecordArray to es6 class --- .../-private/system/snapshot-record-array.js | 241 +++++++++--------- 1 file changed, 122 insertions(+), 119 deletions(-) diff --git a/addon/-private/system/snapshot-record-array.js b/addon/-private/system/snapshot-record-array.js index 652f1bd1906..12413093578 100644 --- a/addon/-private/system/snapshot-record-array.js +++ b/addon/-private/system/snapshot-record-array.js @@ -10,149 +10,152 @@ @param {Array} snapshots An array of snapshots @param {Object} meta */ -export default function SnapshotRecordArray(recordArray, meta, options = {}) { - /** - An array of snapshots - @private - @property _snapshots - @type {Array} - */ - this._snapshots = null; - /** - An array of records - @private - @property _recordArray - @type {Array} - */ - this._recordArray = recordArray; - - /** - Number of records in the array - - Example - - ```app/adapters/post.js - import DS from 'ember-data' - - export default DS.JSONAPIAdapter.extend({ - shouldReloadAll(store, snapshotRecordArray) { - return !snapshotRecordArray.length; - }, - }); - ``` +export default class SnapshotRecordArray { + constructor(recordArray, meta, options = {}) { + /** + An array of snapshots + @private + @property _snapshots + @type {Array} + */ + this._snapshots = null; + + /** + An array of records + @private + @property _recordArray + @type {Array} + */ + this._recordArray = recordArray; + + /** + Number of records in the array + + Example + + ```app/adapters/post.js + import DS from 'ember-data' + + export default DS.JSONAPIAdapter.extend({ + shouldReloadAll(store, snapshotRecordArray) { + return !snapshotRecordArray.length; + }, + }); + ``` + + @property length + @type {Number} + */ + this.length = recordArray.get('length'); + + /** + The type of the underlying records for the snapshots in the array, as a DS.Model + @property type + @type {DS.Model} + */ + this.type = recordArray.get('type'); + + /** + Meta objects for the record array. + + Example + + ```app/adapters/post.js + import DS from 'ember-data' + + export default DS.JSONAPIAdapter.extend({ + shouldReloadAll(store, snapshotRecordArray) { + var lastRequestTime = snapshotRecordArray.meta.lastRequestTime; + var twentyMinutes = 20 * 60 * 1000; + return Date.now() > lastRequestTime + twentyMinutes; + }, + }); + ``` - @property length - @type {Number} - */ - this.length = recordArray.get('length'); + @property meta + @type {Object} + */ + this.meta = meta; - /** - The type of the underlying records for the snapshots in the array, as a DS.Model - @property type - @type {DS.Model} - */ - this.type = recordArray.get('type'); + /** + A hash of adapter options passed into the store method for this request. - /** - Meta objects for the record array. + Example - Example + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; - ```app/adapters/post.js - import DS from 'ember-data' + export default MyCustomAdapter.extend({ + findAll(store, type, sinceToken, snapshotRecordArray) { + if (snapshotRecordArray.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` - export default DS.JSONAPIAdapter.extend({ - shouldReloadAll(store, snapshotRecordArray) { - var lastRequestTime = snapshotRecordArray.meta.lastRequestTime; - var twentyMinutes = 20 * 60 * 1000; - return Date.now() > lastRequestTime + twentyMinutes; - }, - }); - ``` + @property adapterOptions + @type {Object} + */ + this.adapterOptions = options.adapterOptions; - @property meta - @type {Object} - */ - this.meta = meta; + /** + The relationships to include for this request. - /** - A hash of adapter options passed into the store method for this request. + Example - Example + ```app/adapters/application.js + import DS from 'ember-data'; - ```app/adapters/post.js - import MyCustomAdapter from './custom-adapter'; + export default DS.Adapter.extend({ + findAll(store, type, snapshotRecordArray) { + var url = `/${type.modelName}?include=${encodeURIComponent(snapshotRecordArray.include)}`; - export default MyCustomAdapter.extend({ - findAll(store, type, sinceToken, snapshotRecordArray) { - if (snapshotRecordArray.adapterOptions.subscribe) { - // ... + return fetch(url).then((response) => response.json()) } - // ... - } - }); - ``` + }); - @property adapterOptions - @type {Object} - */ - this.adapterOptions = options.adapterOptions; + @property include + @type {String|Array} + */ + this.include = options.include; + } /** - The relationships to include for this request. + Get snapshots of the underlying record array Example - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - findAll(store, type, snapshotRecordArray) { - var url = `/${type.modelName}?include=${encodeURIComponent(snapshotRecordArray.include)}`; + ```app/adapters/post.js + import DS from 'ember-data' - return fetch(url).then((response) => response.json()) + export default DS.JSONAPIAdapter.extend({ + shouldReloadAll(store, snapshotArray) { + var snapshots = snapshotArray.snapshots(); + + return snapshots.any(function(ticketSnapshot) { + var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt'), 'minutes'); + if (timeDiff > 20) { + return true; + } else { + return false; + } + }); } }); + ``` - @property include - @type {String|Array} + @method snapshots + @return {Array} Array of snapshots */ - this.include = options.include; -} - -/** - Get snapshots of the underlying record array - - Example - - ```app/adapters/post.js - import DS from 'ember-data' - - export default DS.JSONAPIAdapter.extend({ - shouldReloadAll(store, snapshotArray) { - var snapshots = snapshotArray.snapshots(); - - return snapshots.any(function(ticketSnapshot) { - var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt'), 'minutes'); - if (timeDiff > 20) { - return true; - } else { - return false; - } - }); + snapshots() { + if (this._snapshots !== null) { + return this._snapshots; } - }); - ``` - @method snapshots - @return {Array} Array of snapshots -*/ -SnapshotRecordArray.prototype.snapshots = function() { - if (this._snapshots !== null) { + this._snapshots = this._recordArray._takeSnapshot(); + return this._snapshots; } - - this._snapshots = this._recordArray._takeSnapshot(); - - return this._snapshots; -}; +} From 3eed2604c4c3894e856e5dee0fea469a494a0353 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Tue, 21 Mar 2017 16:08:57 -0700 Subject: [PATCH 1867/2527] Snapshot.type loads model classes lazily --- .../-private/system/snapshot-record-array.js | 16 ++++++---- addon/-private/system/snapshot.js | 24 +++++++------- tests/integration/snapshot-test.js | 31 +++++++++++++++++++ .../unit/system/snapshot-record-array-test.js | 24 ++++++++++++++ 4 files changed, 78 insertions(+), 17 deletions(-) diff --git a/addon/-private/system/snapshot-record-array.js b/addon/-private/system/snapshot-record-array.js index 12413093578..9afe2408670 100644 --- a/addon/-private/system/snapshot-record-array.js +++ b/addon/-private/system/snapshot-record-array.js @@ -48,12 +48,7 @@ export default class SnapshotRecordArray { */ this.length = recordArray.get('length'); - /** - The type of the underlying records for the snapshots in the array, as a DS.Model - @property type - @type {DS.Model} - */ - this.type = recordArray.get('type'); + this._type = null; /** Meta objects for the record array. @@ -122,6 +117,15 @@ export default class SnapshotRecordArray { this.include = options.include; } + /** + The type of the underlying records for the snapshots in the array, as a DS.Model + @property type + @type {DS.Model} + */ + get type() { + return this._type || (this._type = this._recordArray.get('type')); + } + /** Get snapshots of the underlying record array diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index fde441e26e8..8b9ec54b2a1 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -65,17 +65,6 @@ export default class Snapshot { this.adapterOptions = options.adapterOptions; this.include = options.include; - /** - The type of the underlying record for this snapshot, as a DS.Model. - - @property type - @type {DS.Model} - */ - // TODO @runspired we should deprecate this in favor of modelClass but only once - // we've cleaned up the internals enough that a public change to follow suite is - // uncontroversial. - this.type = internalModel.modelClass; - /** The name of the type of the underlying record for this snapshot, as a string. @@ -87,6 +76,19 @@ export default class Snapshot { this._changedAttributes = record.changedAttributes(); } + /** + The type of the underlying record for this snapshot, as a DS.Model. + + @property type + @type {DS.Model} + */ + get type() { + // TODO @runspired we should deprecate this in favor of modelClass but only once + // we've cleaned up the internals enough that a public change to follow suite is + // uncontroversial. + return this._internalModel.modelClass; + } + /** Returns the value of an attribute. diff --git a/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js index 00fc28db881..6bb11f9e20c 100644 --- a/tests/integration/snapshot-test.js +++ b/tests/integration/snapshot-test.js @@ -75,6 +75,37 @@ test("snapshot.id, snapshot.type and snapshot.modelName returns correctly", func }); }); +test('snapshot.type loads the class lazily', function(assert) { + assert.expect(3); + + let postClassLoaded = false; + let modelFor = env.store._modelFor; + env.store._modelFor = (name) => { + if (name === 'post') { + postClassLoaded = true; + } + return modelFor.call(env.store, name); + }; + + run(function() { + env.store.push({ + data: { + type: 'post', + id: '1', + attributes: { + title: 'Hello World' + } + } + }); + let postInternalModel = env.store._internalModelForId('post', 1); + let snapshot = postInternalModel.createSnapshot(); + + assert.equal(false, postClassLoaded, 'model class is not eagerly loaded'); + assert.equal(snapshot.type, Post, 'type is correct'); + assert.equal(true, postClassLoaded, 'model class is loaded'); + }); +}); + test("snapshot.attr() does not change when record changes", function(assert) { assert.expect(2); diff --git a/tests/unit/system/snapshot-record-array-test.js b/tests/unit/system/snapshot-record-array-test.js index a5ee16b5ea5..7574cb1e83c 100644 --- a/tests/unit/system/snapshot-record-array-test.js +++ b/tests/unit/system/snapshot-record-array-test.js @@ -47,3 +47,27 @@ test('#snapshot', function(assert) { assert.equal(snapshot.snapshots(), snapshotTaken, 'should return the exact same snapshot'); assert.equal(didTakeSnapshot, 1, 'still only one snapshot should have been taken'); }); + +test('SnapshotRecordArray.type loads the class lazily', function(assert) { + let array = Ember.A([1, 2]); + let typeLoaded = false; + + Object.defineProperty(array, 'type', { + get() { + typeLoaded = true; + return 'some type'; + } + }); + + let meta = { }; + let options = { + adapterOptions: 'some options', + include: 'include me' + }; + + let snapshot = new SnapshotRecordArray(array, meta, options); + + assert.equal(false, typeLoaded, 'model class is not eager loaded'); + assert.equal(snapshot.type, 'some type'); + assert.equal(true, typeLoaded, 'model class is loaded'); +}); From 1ac476807cc5032c634ea35383463781cb7bf6a2 Mon Sep 17 00:00:00 2001 From: Ryan LaBouve Date: Mon, 27 Mar 2017 10:40:43 -0700 Subject: [PATCH 1868/2527] Documents the caching behavior of queryRecord --- addon/-private/system/store.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index d20260eeb45..54445414413 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1300,6 +1300,8 @@ Store = Service.extend({ This method can be used when it is certain that the server will return a single object for the primary data. + Each time this method is called a new request is made through the adapter. + Let's assume our API provides an endpoint for the currently logged in user via: From 44ffbff63e4cae33ab519b23d51394645d7ccab1 Mon Sep 17 00:00:00 2001 From: Will Bagby Date: Mon, 27 Mar 2017 13:00:38 -0700 Subject: [PATCH 1869/2527] Ember.warn when ManyArray.objectAt() is underfined --- addon/-private/system/many-array.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 6aa7f000fba..78433bd4e31 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -2,7 +2,7 @@ @module ember-data */ import Ember from 'ember'; -import { assert } from "ember-data/-private/debug"; +import { assert, warn } from "ember-data/-private/debug"; import { PromiseArray } from "./promise-proxies"; import { _objectIsAlive } from "./store/common"; import diffArray from './diff-array'; @@ -136,7 +136,12 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { objectAt(index) { let object = this.currentState[index]; //Ember observers such as 'firstObject', 'lastObject' might do out of bounds accesses - if (object === undefined) { return; } + if (object === undefined) { + warn(`ManyArray#objectAt(index) return undefined for index '${index}'. See https://github.com/emberjs/data/issues/4758`, false, { + id: 'ds.many-array.object-at-undefined' + }); + return; + } return object.getRecord(); }, From 90e3de40855088da272fcfac60565f601b9f9366 Mon Sep 17 00:00:00 2001 From: Sebastian Duque Date: Mon, 27 Mar 2017 14:04:36 -0700 Subject: [PATCH 1870/2527] Fix intenralModel typo --- addon/-private/system/relationships/state/relationship.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 53ad44c8485..d2e07be98cb 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -129,7 +129,7 @@ export default class Relationship { removeInternalModels(internalModels) { heimdall.increment(removeInternalModels); - internalModels.forEach((intenralModel) => this.removeRecord(intenralModel)); + internalModels.forEach((internalModel) => this.removeRecord(internalModel)); } addInternalModels(internalModels, idx) { From 3a5edabb20fbe812057d450a9b84825c024c1ef8 Mon Sep 17 00:00:00 2001 From: jonpitch Date: Mon, 27 Mar 2017 14:05:50 -0700 Subject: [PATCH 1871/2527] updating peekRecord documentation with reference to its counterpart findRecord --- addon/-private/system/store.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index d20260eeb45..4bb7d79eb68 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1026,6 +1026,8 @@ Store = Service.extend({ otherwise it will return `null`. A record is available if it has been fetched earlier, or pushed manually into the store. + See [findRecord](#method_findRecord) if you would like to request this record from the backend. + _Note: This is a synchronous method and does not return a promise._ ```js From 05ded6da0d23fbf86c2abab3fb55150c8e066bf0 Mon Sep 17 00:00:00 2001 From: Sebastian Duque Date: Mon, 27 Mar 2017 15:00:37 -0700 Subject: [PATCH 1872/2527] [DOCUMENTATION] Refer the RFC process for requesting new features --- CONTRIBUTING.md | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 03a3fe6c559..2046b77b2ba 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,25 +40,33 @@ The more information you provide, the easier it is for us to validate that there is a bug and the faster we'll be able to take action. ## Requesting a Feature - -1. Search Issues for similar feature requests. It's possible somebody has -already asked for this feature or provided a pull request that we're still -discussing. +1. Ember and Ember Data have an RFC process for feature requests. To begin the discussion either +[gather feedback](https://github.com/emberjs/rfcs/blob/master/README.md#gathering-feedback-before-submitting) +on the emberjs/rfcs repository. Or, draft an [Ember Data RFC](https://github.com/emberjs/rfcs/pulls?q=is%3Apr+is%3Aopen+label%3Aember-data) + - Use RFC pull request for well formed ideas. + - Use the `ember-data` label on it. + - Use RFC issues to propose a rough idea, basically a great place to test + the waters. 2. Provide a clear and detailed explanation of the feature you want and why it's important to add. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on library for Ember. -3. If the feature is complex, consider writing some initial documentation for -it. If we do end up accepting the feature it will need to be documented and -this will also help us to understand it better ourselves. +3. If the feature is complex, consider writing an Ember RFC document. If we do +end up accepting the feature, the RFC provides the needed documentation for +contributors to develop the feature according the specification accepted by the core team. + +4. After discussing the feature you may choose to attempt a Pull Request. If +you're at all able, start writing some code. We always have more work to do +than time to do it. If you can write some code then that will speed the process +along. -4. Attempt a Pull Request. If you're at all able, start writing some code. We -always have more work to do than time to do it. If you can write some code -then that will speed the process along. +In short, if you have an idea that would be nice to have, create an issue on the +emberjs/rfcs repo and label it as `ember-data`. If you have a question about +requesting a feature, start a discussion at [discuss.emberjs.com](http://discuss.emberjs.com) -### Using Feature Flags +## Using Feature Flags Feature flags allow new features to be tested easily and strips them out of production builds automatically. @@ -112,19 +120,19 @@ production builds automatically. ## Benchmarking -Ember Data is instrumented with [heimdalljs](https://github.com/heimdalljs/heimdalljs-lib) +Ember Data is instrumented with [heimdalljs](https://github.com/heimdalljs/heimdalljs-lib) Top level scenarios for benchmarking are available via the `query` route in the dummy app, and desired scenarios to be run can be configured via `benchmarks/config.js`. - + The scenarios are configured to interop with [heimdall-query](https://github.com/heimdalljs/heimdall-query) for analysis. To run scenarios: 1. Start the dummy app with instrumentation on: `ember s --instrument` - + 2. Configure `benchmarks/config.js` with desired scenarios - + 3. To run both the benchmarks and the analysis: `node ./benchmarks` - + a.) To just collect data (no analysis): `node ./benchmarks/bash-run.js` b.) To just run analysis (w/cached data): `node ./benchmarks/bash-analyze.js` c.) To cache a data set or use a cached data set, all commands accept `-c ./path/to/cache/dir` From df1b031bb1c56aed8b9bde6e647b49c5524ee2ad Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 27 Mar 2017 17:59:34 -0400 Subject: [PATCH 1873/2527] Use node 6 for travis tests --- .travis.yml | 2 +- appveyor.yml | 2 +- yarn.lock | 735 +++++++++++++++++++++++++-------------------------- 3 files changed, 365 insertions(+), 374 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2203a1b3eb4..0467aedc21c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: node_js sudo: false node_js: - - "4" + - "6.9" before_install: - "npm config set spin false" - "npm install -g npm@^2" diff --git a/appveyor.yml b/appveyor.yml index 8b86725066d..706a81149bb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,7 +3,7 @@ # Test against these versions of Node.js. environment: matrix: - - nodejs_version: "4.2" + - nodejs_version: "6.9" # Install scripts. (runs after repo cloning) install: diff --git a/yarn.lock b/yarn.lock index bf2465079c9..d3283e4a174 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1,10 +1,8 @@ # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 - - "@types/node@*", "@types/node@^7.0.5": - version "7.0.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.8.tgz#25e4dd804b630c916ae671233e6d71f6ce18124a" + version "7.0.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.12.tgz#ae5f67a19c15f752148004db07cbbb372e69efc9" "@types/rimraf@^0.0.28": version "0.0.28" @@ -26,7 +24,7 @@ abbrev@1: version "1.1.0" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" -accepts@1.3.3, accepts@~1.3.3: +accepts@~1.3.3, accepts@1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" dependencies: @@ -39,14 +37,18 @@ acorn-jsx@^3.0.0: dependencies: acorn "^3.0.4" -acorn@4.0.4, acorn@^4.0.3: - version "4.0.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" - acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" +acorn@^4.0.3: + version "4.0.11" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0" + +acorn@4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" + adm-zip@^0.4.7: version "0.4.7" resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" @@ -194,17 +196,13 @@ arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" -asn1@0.1.11: - version "0.1.11" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" - asn1@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" +asn1@0.1.11: + version "0.1.11" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" assert-plus@^0.1.5: version "0.1.5" @@ -214,6 +212,10 @@ assert-plus@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" +assert-plus@^1.0.0, assert-plus@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + assertion-error@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" @@ -262,8 +264,8 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" aws-sdk@^2.0.9: - version "2.29.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.29.0.tgz#aebf0c90effa4abea426dd59187f51b5ae121684" + version "2.32.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.32.0.tgz#9fe278b2ec1b12fddd1afeb74439581cdc2e5990" dependencies: buffer "4.9.1" crypto-browserify "1.0.9" @@ -1096,29 +1098,29 @@ broccoli-builder@^0.18.3: rsvp "^3.0.17" silent-error "^1.0.1" -broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" +broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" - lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - symlink-or-copy "^1.0.0" - walk-sync "^0.2.0" + walk-sync "^0.2.5" -broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" +broccoli-caching-writer@~2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" + lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - walk-sync "^0.2.5" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" broccoli-clean-css@^1.1.0: version "1.1.0" @@ -1293,23 +1295,23 @@ broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-p symlink-or-copy "^1.0.1" walk-sync "^0.3.1" -broccoli-plugin@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" +broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" rimraf "^2.3.4" - symlink-or-copy "^1.0.1" + symlink-or-copy "^1.1.8" -broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" +broccoli-plugin@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" rimraf "^2.3.4" - symlink-or-copy "^1.1.8" + symlink-or-copy "^1.0.1" broccoli-slow-trees@^3.0.1: version "3.0.1" @@ -1386,11 +1388,11 @@ broccoli-yuidoc@^2.1.0: yuidocjs "~0.9.0" browserslist@^1.4.0: - version "1.7.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.6.tgz#af98589ce6e7ab09618d29451faacb81220bd3ba" + version "1.7.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" dependencies: - caniuse-db "^1.0.30000631" - electron-to-chromium "^1.2.5" + caniuse-db "^1.0.30000639" + electron-to-chromium "^1.2.7" bser@1.0.2: version "1.0.2" @@ -1460,9 +1462,9 @@ can-symlink@^1.0.0: dependencies: tmp "0.0.28" -caniuse-db@^1.0.30000631: - version "1.0.30000639" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000639.tgz#5982f70a54352adaf8901a772d2c68ca24f501aa" +caniuse-db@^1.0.30000639: + version "1.0.30000641" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000641.tgz#4810fc75fbb3f5b3bd75c2d6a94d894a7c709873" capture-exit@^1.1.0: version "1.2.0" @@ -1587,6 +1589,12 @@ cli-spinners@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" +cli-table@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + dependencies: + colors "1.0.3" + cli-table2@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" @@ -1596,12 +1604,6 @@ cli-table2@^0.2.0: optionalDependencies: colors "^1.1.2" -cli-table@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" - dependencies: - colors "1.0.3" - cli-width@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" @@ -1638,10 +1640,6 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" -colors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - colors@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" @@ -1650,6 +1648,10 @@ colors@~0.6.0-1: version "0.6.2" resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" +colors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" @@ -1662,6 +1664,16 @@ combined-stream@~0.0.4: dependencies: delayed-stream "0.0.5" +commander@^2.5.0, commander@^2.6.0, commander@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +commander@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" + commander@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" @@ -1676,16 +1688,6 @@ commander@2.8.x: dependencies: graceful-readlink ">= 1.0.0" -commander@^2.5.0, commander@^2.6.0, commander@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" - dependencies: - graceful-readlink ">= 1.0.0" - -commander@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" - commoner@~0.10.3: version "0.10.8" resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" @@ -1717,10 +1719,10 @@ component-inherit@0.0.3: resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" compressible@~2.0.8: - version "2.0.9" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.9.tgz#6daab4e2b599c2770dd9e21e7a891b1c5a755425" + version "2.0.10" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.10.tgz#feda1c7f7617912732b29bf8cf26252a20b9eecd" dependencies: - mime-db ">= 1.24.0 < 2" + mime-db ">= 1.27.0 < 2" compression@^1.4.4: version "1.6.2" @@ -1737,7 +1739,15 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@1.5.0, concat-stream@^1.4.6, concat-stream@^1.4.7: +concat-stream@^1.4.6, concat-stream@^1.4.7: + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +concat-stream@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" dependencies: @@ -1868,16 +1878,22 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -debug@0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" +debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" + dependencies: + ms "0.7.2" -debug@2.2.0, debug@~2.2.0: +debug@~2.2.0, debug@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" dependencies: ms "0.7.1" +debug@0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" + debug@2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" @@ -1890,12 +1906,6 @@ debug@2.6.1: dependencies: ms "0.7.2" -debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: - version "2.6.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" - dependencies: - ms "0.7.2" - decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -1941,19 +1951,19 @@ del@^2.0.2: pinkie-promise "^2.0.0" rimraf "^2.2.8" -delayed-stream@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" +delayed-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" + delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" -depd@1.1.0, depd@~1.1.0: +depd@~1.1.0, depd@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" @@ -1988,7 +1998,7 @@ detective@^4.3.1: acorn "^4.0.3" defined "^1.0.0" -diff@1.4.0, diff@^1.3.1: +diff@^1.3.1, diff@1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" @@ -2019,9 +2029,9 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -electron-to-chromium@^1.2.5, electron-to-chromium@^1.2.6: - version "1.2.7" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.2.7.tgz#4f748061407e478c76256d04496972b71f647407" +electron-to-chromium@^1.2.6, electron-to-chromium@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.2.8.tgz#22c2e6200d350da27d6050db7e3f6f85d18cf4ed" ember-ajax@^2.4.1: version "2.5.6" @@ -2048,8 +2058,8 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-c resolve "^1.1.2" ember-cli-babel@^6.0.0-beta.7: - version "6.0.0-beta.7" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.0.0-beta.7.tgz#cb5cd925c7c61b7a46a515e4954c8897227aaee4" + version "6.0.0-beta.9" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.0.0-beta.9.tgz#b597d52f12d4429cd5716b55f749ebf6144b7b16" dependencies: amd-name-resolver "0.0.6" babel-plugin-transform-es2015-modules-amd "^6.24.0" @@ -2243,10 +2253,10 @@ ember-cli-release@^0.2.9: silent-error "^1.0.0" ember-cli-shims@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/ember-cli-shims/-/ember-cli-shims-1.0.2.tgz#e2ec1b6687f94df1b68cc0aa66c1d690d9ded02c" + version "1.1.0" + resolved "https://registry.yarnpkg.com/ember-cli-shims/-/ember-cli-shims-1.1.0.tgz#0e3b8a048be865b4f81cc81d397ff1eeb13f75b6" dependencies: - ember-cli-babel "^5.2.1" + ember-cli-babel "^6.0.0-beta.7" ember-cli-version-checker "^1.2.0" silent-error "^1.0.1" @@ -2291,8 +2301,8 @@ ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-ve semver "^5.3.0" ember-cli@^2.11.1: - version "2.12.0" - resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-2.12.0.tgz#1dd081ef736570d76600ae6f7dfd043b55ac41f5" + version "2.12.1" + resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-2.12.1.tgz#33dd9341677f67f29bc0e286b129877ee15e5bcb" dependencies: amd-name-resolver "0.0.6" bower-config "^1.3.0" @@ -2479,8 +2489,8 @@ ember-try-config@^2.0.1: semver "^5.1.0" ember-try@^0.2.9: - version "0.2.11" - resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.11.tgz#a793fbfe9c327e6dface808f53262a0b5f69e7b8" + version "0.2.13" + resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.13.tgz#3d91f46950a40bba54da0edbbbb30480f83a9fdb" dependencies: chalk "^1.0.0" cli-table2 "^0.2.0" @@ -2587,7 +2597,7 @@ es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: es6-iterator "2" es6-symbol "~3.1" -es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: +es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@2: version "2.0.1" resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" dependencies: @@ -2620,7 +2630,7 @@ es6-set@~0.1.5: es6-symbol "3.1.1" event-emitter "~0.3.5" -es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: +es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1, es6-symbol@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" dependencies: @@ -2640,14 +2650,14 @@ escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" -escape-string-regexp@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" - escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" +escape-string-regexp@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" + escope@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" @@ -2771,8 +2781,8 @@ exec-sh@^0.2.0: merge "^1.1.3" execa@^0.6.0: - version "0.6.2" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.6.2.tgz#04e9e38dec6b8e770cf0fb6cf7ef945260c67bbb" + version "0.6.3" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.6.3.tgz#57b69a594f081759c69e5370f0d17b9cb11658fe" dependencies: cross-spawn "^5.0.1" get-stream "^3.0.0" @@ -2962,10 +2972,10 @@ fill-range@^2.1.0: repeat-string "^1.5.2" finalhandler@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.0.tgz#b5691c2c0912092f18ac23e9416bde5cd7dc6755" + version "1.0.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.1.tgz#bcd15d1689c0e5ed729b6f7f541a6df984117db8" dependencies: - debug "2.6.1" + debug "2.6.3" encodeurl "~1.0.1" escape-html "~1.0.3" on-finished "~2.3.0" @@ -3071,13 +3081,6 @@ fs-exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" -fs-extra@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.0.0.tgz#337352bded4a0b714f3eb84de8cea765e9d37600" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - fs-extra@^0.24.0: version "0.24.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" @@ -3115,19 +3118,26 @@ fs-extra@^1.0.0, fs-extra@~1.0.0: jsonfile "^2.1.0" klaw "^1.0.0" +fs-extra@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.0.0.tgz#337352bded4a0b714f3eb84de8cea765e9d37600" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + fs-readdir-recursive@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" -fs-sync@^0.2.4: - version "0.2.6" - resolved "https://registry.yarnpkg.com/fs-sync/-/fs-sync-0.2.6.tgz#657116c12b95ac9a36c51a850066c9ee6441fe06" +fs-sync@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" dependencies: - glob "~4.0.4" - iconv-lite "~0.2.10" - lodash "~1.2.1" - mkdirp "~0.3.5" - rimraf "~2.1.4" + glob "^7.1.0" + iconv-lite "^0.4.13" + lodash "^4.16.1" + mkdirp "^0.5.1" + rimraf "^2.1.4" fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6: version "0.5.6" @@ -3222,25 +3232,26 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" +glob@^4.3.2: + version "4.5.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" dependencies: - graceful-fs "~2.0.0" + inflight "^1.0.4" inherits "2" - minimatch "~0.2.11" + minimatch "^2.0.1" + once "^1.3.0" -glob@5.0.13, glob@^5.0.10: - version "5.0.13" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" +glob@^5.0.10, glob@^5.0.15: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: inflight "^1.0.4" inherits "2" - minimatch "^2.0.1" + minimatch "2 || 3" once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.1: +glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: @@ -3251,34 +3262,24 @@ glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.1: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^4.3.2: - version "4.5.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" +glob@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" dependencies: - inflight "^1.0.4" + graceful-fs "~2.0.0" inherits "2" - minimatch "^2.0.1" - once "^1.3.0" + minimatch "~0.2.11" -glob@^5.0.15: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" +glob@5.0.13: + version "5.0.13" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" dependencies: inflight "^1.0.4" inherits "2" - minimatch "2 || 3" + minimatch "^2.0.1" once "^1.3.0" path-is-absolute "^1.0.0" -glob@~4.0.4: - version "4.0.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-4.0.6.tgz#695c50bdd4e2fb5c5d370b091f388d3707e291a7" - dependencies: - graceful-fs "^3.0.2" - inherits "2" - minimatch "^1.0.0" - once "^1.3.0" - global-modules@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" @@ -3300,8 +3301,8 @@ globals@^6.4.0: resolved "https://registry.yarnpkg.com/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" globals@^9.0.0, globals@^9.2.0: - version "9.16.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.16.0.tgz#63e903658171ec2d9f51b1d31de5e2b8dc01fb80" + version "9.17.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286" globby@^5.0.0: version "5.0.0" @@ -3314,20 +3315,10 @@ globby@^5.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -graceful-fs@^3.0.2: - version "3.0.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" - dependencies: - natives "^1.1.0" - graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" -graceful-fs@~1: - version "1.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" - graceful-fs@~2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" @@ -3411,15 +3402,6 @@ hasha@~2.2.0: is-stream "^1.0.1" pinkie-promise "^2.0.0" -hawk@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" - dependencies: - boom "0.4.x" - cryptiles "0.2.x" - hoek "0.9.x" - sntp "0.2.x" - hawk@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" @@ -3429,6 +3411,15 @@ hawk@~3.1.3: hoek "2.x.x" sntp "1.x.x" +hawk@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" + dependencies: + boom "0.4.x" + cryptiles "0.2.x" + hoek "0.9.x" + sntp "0.2.x" + heimdall-query@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" @@ -3460,14 +3451,14 @@ heimdalljs-logger@^0.1.7: heimdalljs "^0.2.0" heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.3.tgz#35b82a6a4d73541fc4fb88d2fe2b23608fb4f779" + version "0.2.4" + resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.4.tgz#34ead16eab422c94803065d33abeba1f7b24a910" dependencies: rsvp "~3.2.1" heimdalljs@^0.3.0: - version "0.3.2" - resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.3.2.tgz#d19f98cf7c6a7660c2ecbbeaa696db3436227713" + version "0.3.3" + resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" dependencies: rsvp "~3.2.1" @@ -3500,8 +3491,8 @@ homedir-polyfill@^1.0.0: parse-passwd "^1.0.0" hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: - version "2.3.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.3.1.tgz#ac439421605f0beb0ea1349de7d8bb28e50be1dd" + version "2.4.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.1.tgz#4b0445e41c004a8bd1337773a4ff790ca40318c8" http-errors@~1.6.1: version "1.6.1" @@ -3535,14 +3526,10 @@ http-signature@~1.1.0: jsprim "^1.2.2" sshpk "^1.7.0" -iconv-lite@0.4.15, iconv-lite@^0.4.5, iconv-lite@~0.4.13: +iconv-lite@^0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13, iconv-lite@0.4.15: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" -iconv-lite@~0.2.10: - version "0.2.11" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8" - ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" @@ -3574,7 +3561,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.1: +inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@2, inherits@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -3639,9 +3626,9 @@ invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" -ipaddr.js@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.2.0.tgz#8aba49c9192799585bdd643e0ccb50e8ae777ba4" +ipaddr.js@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec" is-arrayish@^0.2.1: version "0.2.1" @@ -3691,7 +3678,11 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" -is-git-url@0.2.0, is-git-url@^0.2.0: +is-git-url@^0.2.0: + version "0.2.3" + resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-0.2.3.tgz#445200d6fbd6da028fb5e01440d9afc93f3ccb64" + +is-git-url@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-0.2.0.tgz#b9ce0fb044821c88880213d602db03bdb255da1b" @@ -3786,21 +3777,21 @@ is-windows@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" +isarray@^1.0.0, isarray@~1.0.0, isarray@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - isbinaryfile@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" -isexe@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" isobject@^2.0.0: version "2.1.0" @@ -3845,14 +3836,14 @@ js-string-escape@^1.0.0, js-string-escape@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" -js-tokens@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" - js-tokens@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" +js-tokens@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" + js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: version "3.8.2" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.2.tgz#02d3e2c0f6beab20248d412c352203827d786721" @@ -4211,14 +4202,10 @@ lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.15.0, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: +lodash@^4.0.0, lodash@^4.15.0, lodash@^4.16.1, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" -lodash@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.2.1.tgz#ed47b16e46f06b2b40309b68e9163c17e93ea304" - lodash@~3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.5.0.tgz#19bb3f4d51278f0b8c818ed145c74ecf9fe40e6d" @@ -4233,10 +4220,6 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0" -lru-cache@2: - version "2.7.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" - lru-cache@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" @@ -4244,6 +4227,10 @@ lru-cache@^4.0.1: pseudomap "^1.0.1" yallist "^2.0.0" +lru-cache@2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + make-array@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" @@ -4348,25 +4335,21 @@ micromatch@^2.1.5, micromatch@^2.3.7: parse-glob "^3.0.4" regex-cache "^0.4.2" -"mime-db@>= 1.24.0 < 2": +"mime-db@>= 1.27.0 < 2", mime-db@~1.27.0: version "1.27.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" -mime-db@~1.26.0: - version "1.26.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" - mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: - version "2.1.14" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" + version "2.1.15" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" dependencies: - mime-db "~1.26.0" + mime-db "~1.27.0" mime-types@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" -mime@1.3.4, mime@^1.2.11: +mime@^1.2.11, mime@1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" @@ -4374,25 +4357,18 @@ mime@~1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" - dependencies: - brace-expansion "^1.0.0" - -minimatch@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-1.0.0.tgz#e0dd2120b49e1b724ce8d714c520822a9438576d" - dependencies: - lru-cache "2" - sigmund "~1.0.0" - minimatch@^2.0.1, minimatch@^2.0.3, minimatch@^2.0.8: version "2.0.10" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" dependencies: brace-expansion "^1.0.0" +minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, "minimatch@2 || 3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + minimatch@~0.2.11: version "0.2.14" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" @@ -4400,14 +4376,24 @@ minimatch@~0.2.11: lru-cache "2" sigmund "~1.0.0" -minimist@0.0.8, minimist@~0.0.1: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - minimist@^1.1.0, minimist@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@0.5.1, mkdirp@0.5.x: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + mkdirp@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" @@ -4418,16 +4404,6 @@ mkdirp@0.5.0: dependencies: minimist "0.0.8" -mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - -mkdirp@~0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" - mktemp@^0.4.0, mktemp@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" @@ -4461,8 +4437,8 @@ moment-timezone@^0.3.0: moment ">= 2.6.0" "moment@>= 2.6.0": - version "2.18.0" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.0.tgz#6cfec6a495eca915d02600a67020ed994937252c" + version "2.18.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" morgan@^1.5.2, morgan@^1.7.0: version "1.8.1" @@ -4498,10 +4474,6 @@ mute-stream@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" -natives@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31" - negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" @@ -4531,8 +4503,8 @@ node-notifier@^5.0.1: which "^1.2.12" node-uuid@~1.4.0: - version "1.4.7" - resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" + version "1.4.8" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" nopt@^3.0.3: version "3.0.6" @@ -4598,14 +4570,14 @@ oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" - object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" +object-assign@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" @@ -4858,13 +4830,6 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -pretender@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.0.0.tgz#9137c38718b4d89814478b7f208f70d3e441a0e9" - dependencies: - fake-xml-http-request "^1.3.0" - route-recognizer "^0.1.9" - pretender@^1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.4.2.tgz#dde9995dfdf75b28a3dd7a73cde2f9f612e5e8f4" @@ -4872,6 +4837,13 @@ pretender@^1.4.2: fake-xml-http-request "^1.4.0" route-recognizer "^0.2.3" +pretender@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.0.0.tgz#9137c38718b4d89814478b7f208f70d3e441a0e9" + dependencies: + fake-xml-http-request "^1.3.0" + route-recognizer "^0.1.9" + printf@^0.2.3: version "0.2.5" resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" @@ -4901,29 +4873,29 @@ promise-map-series@^0.2.1: rsvp "^3.0.14" proxy-addr@~1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.3.tgz#dc97502f5722e888467b3fa2297a7b1ff47df074" + version "1.1.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" dependencies: forwarded "~0.1.0" - ipaddr.js "1.2.0" + ipaddr.js "1.3.0" pseudomap@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + q@^1.1.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" + version "1.5.0" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" -qs@6.4.0, qs@^6.2.0: +qs@^6.2.0, qs@6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" @@ -4939,7 +4911,15 @@ querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" -quick-temp@0.1.6, quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5: +quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5: + version "0.1.8" + resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" + dependencies: + mktemp "~0.4.0" + rimraf "^2.5.4" + underscore.string "~3.3.4" + +quick-temp@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.6.tgz#a6242a15cba9f9cdbd341287b5c569e318eec307" dependencies: @@ -4996,7 +4976,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^2, "readable-stream@^2.0.0 || ^1.1.13": +readable-stream@^2, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.2.2: version "2.2.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.6.tgz#8b43aed76e71483938d12a8d46c6cf1a00b1f816" dependencies: @@ -5036,15 +5016,6 @@ readline2@^1.0.1: is-fullwidth-code-point "^1.0.0" mute-stream "0.0.5" -recast@0.10.33: - version "0.10.33" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" - dependencies: - ast-types "0.8.12" - esprima-fb "~15001.1001.0-dev-harmony-fb" - private "~0.1.5" - source-map "~0.5.0" - recast@^0.10.10, recast@^0.10.29: version "0.10.43" resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" @@ -5063,6 +5034,15 @@ recast@^0.11.17, recast@^0.11.3: private "~0.1.5" source-map "~0.5.0" +recast@0.10.33: + version "0.10.33" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" + dependencies: + ast-types "0.8.12" + esprima-fb "~15001.1001.0-dev-harmony-fb" + private "~0.1.5" + source-map "~0.5.0" + redeyed@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-0.5.0.tgz#7ab000e60ee3875ac115d29edb32c1403c6c25d1" @@ -5250,28 +5230,22 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" - dependencies: - glob "^7.0.0" - -rimraf@^2.5.3, rimraf@^2.5.4: +rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4: version "2.6.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: glob "^7.0.5" -rimraf@~2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.1.4.tgz#5a6eb62eeda068f51ede50f29b3e5cd22f3d9bb2" - optionalDependencies: - graceful-fs "~1" - rimraf@~2.2.6: version "2.2.8" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" +rimraf@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" + dependencies: + glob "^7.0.0" + route-recognizer@^0.1.9: version "0.1.11" resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" @@ -5280,11 +5254,7 @@ route-recognizer@^0.2.3: version "0.2.10" resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" -rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.6, rsvp@~3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" - -rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: +rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: version "3.5.0" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" @@ -5296,6 +5266,10 @@ rsvp@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" +rsvp@~3.2.1, rsvp@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + run-async@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" @@ -5332,7 +5306,11 @@ sane@^1.1.1: walker "~1.0.5" watch "~0.10.0" -sax@1.1.5, sax@>=0.6.0: +sax@>=0.6.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828" + +sax@1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.5.tgz#1da50a8d00cdecd59405659f5ff85349fe773743" @@ -5345,14 +5323,14 @@ selenium-webdriver@^3.0.0-beta-2: tmp "0.0.30" xml2js "^0.4.17" -"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - semver@^4.1.0, semver@^4.3.1: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" +semver@^5.1.0, semver@^5.1.1, semver@^5.3.0, "semver@2 || 3 || 4 || 5": + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + send@0.15.1: version "0.15.1" resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" @@ -5526,13 +5504,7 @@ source-map-url@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" -source-map@0.1.32: - version "0.1.32" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" - dependencies: - amdefine ">=0.0.4" - -source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: +source-map@^0.4.2, source-map@^0.4.4, source-map@0.4.x: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: @@ -5542,6 +5514,12 @@ source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: version "0.5.6" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" +source-map@0.1.32: + version "0.1.32" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" + dependencies: + amdefine ">=0.0.4" + spawn-args@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" @@ -5571,7 +5549,7 @@ spdx-license-ids@^1.0.2: version "1.2.2" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" -sprintf-js@~1.0.2: +sprintf-js@^1.0.3, sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -5602,6 +5580,10 @@ stable@~0.1.3: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" +string_decoder@~0.10.x, string_decoder@0.10: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + string-template@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" @@ -5621,10 +5603,6 @@ string-width@^2.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^3.0.0" -string_decoder@0.10, string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - stringmap@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" @@ -5673,10 +5651,6 @@ sum-up@^1.0.1: dependencies: chalk "^1.0.0" -supports-color@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" - supports-color@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" @@ -5685,6 +5659,10 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" +supports-color@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" + symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" @@ -5778,12 +5756,18 @@ tiny-lr@^1.0.3: qs "^6.2.0" tmp-sync@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/tmp-sync/-/tmp-sync-1.1.0.tgz#2b38ec94b094ed2515ec02a9aee1f51dd2c9023f" + version "1.1.2" + resolved "https://registry.yarnpkg.com/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" dependencies: - fs-sync "^0.2.4" + fs-sync "^1.0.4" osenv "^0.1.0" +tmp@^0.0.29: + version "0.0.29" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" + dependencies: + os-tmpdir "~1.0.1" + tmp@0.0.28: version "0.0.28" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" @@ -5796,12 +5780,6 @@ tmp@0.0.30: dependencies: os-tmpdir "~1.0.1" -tmp@^0.0.29: - version "0.0.29" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" - dependencies: - os-tmpdir "~1.0.1" - tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -5860,14 +5838,14 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-detect@0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" - type-detect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" +type-detect@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" + type-is@~1.6.14: version "1.6.14" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" @@ -5875,7 +5853,7 @@ type-is@~1.6.14: media-typer "0.3.0" mime-types "~2.1.13" -typedarray@~0.0.5: +typedarray@^0.0.6, typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -5884,12 +5862,13 @@ uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.3: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" uglify-js@^2.6, uglify-js@^2.7.0: - version "2.8.14" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.14.tgz#25b15d1af39b21752ee33703adbf432e8bc8f77d" + version "2.8.16" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.16.tgz#d286190b6eefc6fd65eb0ecac6551e0b0e8839a4" dependencies: source-map "~0.5.1" - uglify-to-browserify "~1.0.0" yargs "~3.10.0" + optionalDependencies: + uglify-to-browserify "~1.0.0" uglify-to-browserify@~1.0.0: version "1.0.2" @@ -5903,11 +5882,18 @@ underscore.string@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" +underscore.string@~3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" + dependencies: + sprintf-js "^1.0.3" + util-deprecate "^1.0.2" + underscore@>=1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" -unpipe@1.0.0, unpipe@~1.0.0: +unpipe@~1.0.0, unpipe@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -5934,7 +5920,7 @@ user-home@^2.0.0: dependencies: os-homedir "^1.0.0" -util-deprecate@~1.0.1: +util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -5942,10 +5928,6 @@ utils-merge@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" -uuid@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" - uuid@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" @@ -5954,6 +5936,10 @@ uuid@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" +uuid@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" + validate-npm-package-license@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" @@ -6014,10 +6000,10 @@ which-module@^1.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" which@^1.2.12, which@^1.2.9, which@~1.2.10: - version "1.2.12" - resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" + version "1.2.14" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" dependencies: - isexe "^1.1.1" + isexe "^2.0.0" wide-align@^1.1.0: version "1.1.0" @@ -6025,10 +6011,6 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.1" -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - window-size@^0.1.2: version "0.1.4" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" @@ -6037,9 +6019,9 @@ window-size@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" wordwrap@~0.0.2: version "0.0.3" @@ -6049,6 +6031,10 @@ wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -6074,16 +6060,16 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" -ws@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" +ws@^1.0.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" dependencies: options ">=0.0.5" ultron "1.0.x" -ws@^1.0.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" +ws@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" dependencies: options ">=0.0.5" ultron "1.0.x" @@ -6098,13 +6084,6 @@ xdg-basedir@^2.0.0: dependencies: os-homedir "^1.0.0" -xml2js@0.4.15: - version "0.4.15" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.15.tgz#95cd03ff2dd144ec28bc6273bf2b2890c581ad0c" - dependencies: - sax ">=0.6.0" - xmlbuilder ">=2.4.6" - xml2js@^0.4.17: version "0.4.17" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" @@ -6112,11 +6091,12 @@ xml2js@^0.4.17: sax ">=0.6.0" xmlbuilder "^4.1.0" -xmlbuilder@2.6.2, xmlbuilder@>=2.4.6: - version "2.6.2" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-2.6.2.tgz#f916f6d10d45dc171b1be2e6e673fb6e0cc35d0a" +xml2js@0.4.15: + version "0.4.15" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.15.tgz#95cd03ff2dd144ec28bc6273bf2b2890c581ad0c" dependencies: - lodash "~3.5.0" + sax ">=0.6.0" + xmlbuilder ">=2.4.6" xmlbuilder@^4.1.0: version "4.2.1" @@ -6124,6 +6104,16 @@ xmlbuilder@^4.1.0: dependencies: lodash "^4.0.0" +xmlbuilder@>=2.4.6: + version "8.2.2" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773" + +xmlbuilder@2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-2.6.2.tgz#f916f6d10d45dc171b1be2e6e673fb6e0cc35d0a" + dependencies: + lodash "~3.5.0" + xmldom@^0.1.19: version "0.1.27" resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" @@ -6224,3 +6214,4 @@ yuidocjs@~0.9.0: minimatch "^2.0.8" rimraf "^2.4.1" yui "^3.18.1" + From 0e9014b6ffc54f8960a75794808314e9791ca238 Mon Sep 17 00:00:00 2001 From: Drew Chandler Date: Mon, 27 Mar 2017 11:29:23 -0700 Subject: [PATCH 1874/2527] Remove unnecessary relationship guard --- addon/-private/system/relationships/state/has-many.js | 4 ++-- addon/-private/system/relationships/state/relationship.js | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index ddfefc219a3..f961954d960 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -89,6 +89,8 @@ export default class ManyRelationship extends Relationship { if (this.members.has(record)) { return; } + + assertPolymorphicType(this.record, this.relationshipMeta, record); super.addRecord(record, idx); // make lazy later this.manyArray.internalAddInternalModels([record], idx); @@ -130,8 +132,6 @@ export default class ManyRelationship extends Relationship { } notifyRecordRelationshipAdded(record, idx) { - assertPolymorphicType(this.record, this.relationshipMeta, record); - this.record.notifyHasManyAdded(this.key, record, idx); } diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 53ad44c8485..0c506170b8b 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -95,12 +95,7 @@ export default class Relationship { allMembers.forEach(inverseInternalModel => { let relationship = inverseInternalModel._relationships.get(this.inverseKey); - // TODO: there is always a relationship in this case; this guard exists - // because there are tests that fail in teardown after putting things in - // invalid state - if (relationship) { - relationship.inverseDidDematerialize(); - } + relationship.inverseDidDematerialize(); }); } From a9f91de7719f563a9f2445812a429d3b95e112d8 Mon Sep 17 00:00:00 2001 From: Sebastian Duque Date: Mon, 27 Mar 2017 13:55:32 -0700 Subject: [PATCH 1875/2527] Rename relationship.relation to removeInverseRelationships --- addon/-private/system/model/internal-model.js | 8 ++++---- addon/-private/system/relationships/state/has-many.js | 4 ++-- addon/-private/system/relationships/state/relationship.js | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index c30b9b13c39..bc3eb539422 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -875,12 +875,12 @@ export default class InternalModel { if (this._relationships.has(name)) { let rel = this._relationships.get(name); rel.clear(); - rel.destroy(); + rel.removeInverseRelationships(); } }); Object.keys(this._implicitRelationships).forEach((key) => { this._implicitRelationships[key].clear(); - this._implicitRelationships[key].destroy(); + this._implicitRelationships[key].removeInverseRelationships(); }); } @@ -888,11 +888,11 @@ export default class InternalModel { this.eachRelationship((name, relationship) => { if (this._relationships.has(name)) { let rel = this._relationships.get(name); - rel.destroy(); + rel.removeInverseRelationships(); } }); Object.keys(this._implicitRelationships).forEach((key) => { - this._implicitRelationships[key].destroy(); + this._implicitRelationships[key].removeInverseRelationships(); }); } diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index ddfefc219a3..6b468f0cd6a 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -46,8 +46,8 @@ export default class ManyRelationship extends Relationship { return this._manyArray; } - destroy() { - super.destroy(); + removeInverseRelationships() { + super.removeInverseRelationships(); if (this._manyArray) { this._manyArray.destroy(); this._manyArray = null; diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index d2e07be98cb..d2f0ab6392b 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -85,7 +85,7 @@ export default class Relationship { return this.internalModel.modelName; } - destroy() { + removeInverseRelationships() { if (!this.inverseKey) { return; } let allMembers = From 6972fd788c1d6008b217c4e4d5029645881d91f0 Mon Sep 17 00:00:00 2001 From: yethon Date: Mon, 27 Mar 2017 12:57:14 -0700 Subject: [PATCH 1876/2527] Deprecate buildInternalModel, add _buildInternalModel. --- addon/-private/system/store.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index d20260eeb45..4d325ca3ad8 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -104,7 +104,7 @@ const { _pushInternalModel, _setupRelationships, adapterFor, - buildInternalModel, + _buildInternalModel, didUpdateAll, modelFactoryFor, modelFor, @@ -121,7 +121,7 @@ const { '_pushInternalModel', '_setupRelationships', 'adapterFor', - 'buildInternalModel', + '_buildInternalModel', 'didUpdateAll', 'modelFactoryFor', 'modelFor', @@ -364,7 +364,7 @@ Store = Service.extend({ // Coerce ID to a string properties.id = coerceId(properties.id); - let internalModel = this.buildInternalModel(normalizedModelName, properties.id); + let internalModel = this._buildInternalModel(normalizedModelName, properties.id); let record = internalModel.getRecord(); // Move the record out of its initial `empty` state into @@ -1130,7 +1130,7 @@ Store = Service.extend({ let internalModel = this._internalModelsFor(modelName).get(trueId); if (!internalModel) { - internalModel = this.buildInternalModel(modelName, trueId); + internalModel = this._buildInternalModel(modelName, trueId); } return internalModel; @@ -2544,17 +2544,17 @@ Store = Service.extend({ Build a brand new record for a given type, ID, and initial data. - @method buildRecord + @method _buildInternalModel @private @param {String} modelName @param {String} id @param {Object} data @return {InternalModel} internal model */ - buildInternalModel(modelName, id, data) { - heimdall.increment(buildInternalModel); + _buildInternalModel(modelName, id, data) { + heimdall.increment(_buildInternalModel); - assert(`You can no longer pass a modelClass as the first argument to store.buildInternalModel. Pass modelName instead.`, typeof modelName === 'string'); + assert(`You can no longer pass a modelClass as the first argument to store._buildInternalModel. Pass modelName instead.`, typeof modelName === 'string'); let recordMap = this._internalModelsFor(modelName); @@ -2569,6 +2569,11 @@ Store = Service.extend({ return internalModel; }, + buildInternalModel(modelName, id, data) { + deprecate('buildInternalModel was documented as private and will be removed in the next version of Ember Data.'); + return this._buildInternalModel(modelName, id, data); + }, + //Called by the state machine to notify the store that the record is ready to be interacted with recordWasLoaded(record) { this.recordArrayManager.recordWasLoaded(record); From 551e39a1ced36a3633969406f970f930cc641a36 Mon Sep 17 00:00:00 2001 From: Esteban Arango Medina Date: Tue, 28 Mar 2017 12:01:12 -0700 Subject: [PATCH 1877/2527] [BUGFIX beta] Removes `get record` from InternalModel. (#4901) * [BUGFIX beta] Removes `get record` from InternalModel. Prefer `getRecord `. Fixes #4756 * Node version for tests. * `getRecord` instead of `_record` on `RecordReference.prototype.value`. --- addon/-private/system/model/internal-model.js | 42 +++++++++---------- addon/-private/system/references/record.js | 4 +- .../system/relationships/state/belongs-to.js | 2 +- tests/unit/store/adapter-interop-test.js | 2 +- 4 files changed, 24 insertions(+), 26 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index bc3eb539422..485acc5b4b1 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -60,7 +60,7 @@ function extractPivotName(name) { function areAllModelsUnloaded(internalModels) { for (let i=0; i 0) { - this.record._notifyProperties(dirtyKeys); + this._record._notifyProperties(dirtyKeys); } } @@ -818,7 +814,7 @@ export default class InternalModel { this.currentState = state; if (this.hasRecord) { - set(this.record, 'currentState', state); + set(this._record, 'currentState', state); } for (i = 0, l = setups.length; i < l; i++) { @@ -857,7 +853,7 @@ export default class InternalModel { return; } let triggers = this._deferredTriggers; - let record = this.record; + let record = this._record; let trigger = record.trigger; for (let i = 0, l= triggers.length; i { return store._scheduleFetchMany(internalModels).then(() => { - let unloadedRecords = Ember.A(internalModels.map(r => r.record)).filterBy('isEmpty'); + let unloadedRecords = Ember.A(internalModels.map(r => r.getRecord())).filterBy('isEmpty'); assert.equal(get(unloadedRecords, 'length'), 0, 'All unloaded records should be loaded'); }); From 25eb2e53e6e8f943f27dc74292d4f4b54d142b34 Mon Sep 17 00:00:00 2001 From: bmac Date: Sun, 26 Mar 2017 19:45:00 -0400 Subject: [PATCH 1878/2527] Add a test to ensure a HasManyReference returns a value when the array is empty --- tests/integration/references/has-many-test.js | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 8419fada0c4..38af4b05fb0 100644 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -538,6 +538,52 @@ test("value() returns the referenced records when all records are loaded", funct }); }); +test("value() returns an empty array when the reference is loaded and empty", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [] + } + } + } + }); + }); + + run(function() { + var personsReference = family.hasMany('persons'); + var records = personsReference.value(); + assert.equal(get(records, 'length'), 0); + }); +}); + +test("_isLoaded() returns an true array when the reference is loaded and empty", function(assert) { + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [] + } + } + } + }); + }); + + run(function() { + var personsReference = family.hasMany('persons'); + var isLoaded = personsReference._isLoaded(); + assert.equal(isLoaded, true); + }); +}); + test("load() fetches the referenced records", function(assert) { var done = assert.async(); From 945ace8fbdb2668d803cc6221df64de35bfe1037 Mon Sep 17 00:00:00 2001 From: yethon Date: Wed, 29 Mar 2017 10:35:02 -0700 Subject: [PATCH 1879/2527] Deprecate didUpdateAll, add _didUpdateAll. --- addon/-private/system/store.js | 15 ++++++++++----- addon/-private/system/store/finders.js | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index fb4f1489ff4..7953b7d5164 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -105,7 +105,7 @@ const { _setupRelationships, adapterFor, _buildInternalModel, - didUpdateAll, + _didUpdateAll, modelFactoryFor, modelFor, normalize, @@ -122,7 +122,7 @@ const { '_setupRelationships', 'adapterFor', '_buildInternalModel', - 'didUpdateAll', + '_didUpdateAll', 'modelFactoryFor', 'modelFor', 'normalize', @@ -1654,17 +1654,22 @@ Store = Service.extend({ }, /** - @method didUpdateAll + @method _didUpdateAll @param {String} modelName @private */ - didUpdateAll(modelName) { - heimdall.increment(didUpdateAll); + _didUpdateAll(modelName) { + heimdall.increment(_didUpdateAll); let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(modelName); set(liveRecordArray, 'isUpdating', false); }, + didUpdateAll(modelName) { + deprecate('didUpdateAll was documented as private and will be removed in the next version of Ember Data.'); + return this._didUpdateAll(modelName); + }, + /** This method returns a filtered array that contains all of the known records for a given type in the store. diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 8cdd6726b17..cdfe9797461 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -134,7 +134,7 @@ export function _findAll(adapter, store, modelName, sinceToken, options) { let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findAll'); store._push(payload); - store.didUpdateAll(modelName); + store._didUpdateAll(modelName); return recordArray; }, null, 'DS: Extract payload of findAll ${modelName}'); From db1e1df317f5d031b407e82c55558a5284a89769 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 30 Mar 2017 15:44:22 -0700 Subject: [PATCH 1880/2527] [BUGFIX] initial-relationship-setup must handle null --- .../system/relationships/state/has-many.js | 16 +++---- .../unit/model/relationships/has-many-test.js | 42 +++++++++++++++++++ 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 6f8e6fa4a72..2aacc494f1d 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -180,13 +180,15 @@ export default class ManyRelationship extends Relationship { } setInitialInternalModels(internalModels) { - let args = [0, this.canonicalState.length].concat(internalModels); - this.canonicalState.splice.apply(this.canonicalState, args); - internalModels.forEach(internalModel => { - this.canonicalMembers.add(internalModel); - this.members.add(internalModel); - this.setupInverseRelationship(internalModel); - }); + if (internalModels && internalModels.length) { + let args = [0, this.canonicalState.length].concat(internalModels); + this.canonicalState.splice.apply(this.canonicalState, args); + internalModels.forEach(internalModel => { + this.canonicalMembers.add(internalModel); + this.members.add(internalModel); + this.setupInverseRelationship(internalModel); + }); + } } fetchLink() { diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 9ee43d16204..d6dbc6ed962 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -276,6 +276,48 @@ test('hasMany does not notify when it is initially reified', function(assert) { }); }); +test('hasMany can be initially reified with null', function(assert) { + assert.expect(1); + + const Tag = DS.Model.extend({ + name: DS.attr('string'), + people: DS.hasMany('person', { async: false }) + }); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: false }) + }); + + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + + env.adapter.shouldBackgroundReloadRecord = () => false; + + run(() => { + store.push({ + data: { + type: 'tag', + id: 1, + attributes: { + name: 'whatever' + }, + relationships: { + people: { + data: null + } + } + } + }); + }); + + return run(() => { + let tag = store.peekRecord('tag', 1); + + assert.equal(tag.get('people.length'), 0, 'relationship is correct'); + }); +}); + test('hasMany tolerates reflexive self-relationships', function(assert) { assert.expect(1); From b13daac133d95f8fad8a38626f2136b117ca3b00 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 30 Mar 2017 15:52:42 -0700 Subject: [PATCH 1881/2527] dont guard length, as that would be a bad state to be in --- .../system/relationships/state/has-many.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 2aacc494f1d..eaa76da4a07 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -180,15 +180,17 @@ export default class ManyRelationship extends Relationship { } setInitialInternalModels(internalModels) { - if (internalModels && internalModels.length) { - let args = [0, this.canonicalState.length].concat(internalModels); - this.canonicalState.splice.apply(this.canonicalState, args); - internalModels.forEach(internalModel => { - this.canonicalMembers.add(internalModel); - this.members.add(internalModel); - this.setupInverseRelationship(internalModel); - }); + if (!internalModels) { + return; } + + let args = [0, this.canonicalState.length].concat(internalModels); + this.canonicalState.splice.apply(this.canonicalState, args); + internalModels.forEach(internalModel => { + this.canonicalMembers.add(internalModel); + this.members.add(internalModel); + this.setupInverseRelationship(internalModel); + }); } fetchLink() { From f74c52d94bdbf6a391c4c76e12915c43218a65aa Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 30 Mar 2017 18:17:57 -0700 Subject: [PATCH 1882/2527] [BUGFIX] partially fix pushing of null onto already materialized array --- .../system/relationships/state/has-many.js | 2 +- .../unit/model/relationships/has-many-test.js | 182 ++++++++++++++++++ 2 files changed, 183 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index eaa76da4a07..d0c6ea040d0 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -159,7 +159,7 @@ export default class ManyRelationship extends Relationship { return this._loadingPromise; } - computeChanges(records) { + computeChanges(records = []) { let members = this.canonicalMembers; let recordsToRemove = []; let recordSet = setForArray(records); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index d6dbc6ed962..d03b98f19b8 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -318,6 +318,188 @@ test('hasMany can be initially reified with null', function(assert) { }); }); +test('hasMany with explicit initial null works even when the inverse was set to not null', function(assert) { + assert.expect(2); + + const Tag = DS.Model.extend({ + name: DS.attr('string'), + people: DS.hasMany('person', { async: false }) + }); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: false }) + }); + + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + + env.adapter.shouldBackgroundReloadRecord = () => false; + + run(() => { + // first we push in data with the relationship + store.push({ + data: { + type: 'person', + id: 1, + attributes: { + name: 'David J. Hamilton' + }, + relationships: { + tag: { + data: { + type: 'tag', + id: 1 + } + } + } + }, + included: [ + { + type: 'tag', + id: 1, + attributes: { + name: 'whatever' + }, + relationships: { + people: { + data: [{ + type: 'person', + id: 1 + }] + } + } + } + ] + }); + + // now we push in data for that record which says it has no relationships + store.push({ + data: { + type: 'tag', + id: 1, + attributes: { + name: 'whatever' + }, + relationships: { + people: { + data: null + } + } + } + }); + }); + + return run(() => { + let tag = store.peekRecord('tag', 1); + let person = store.peekRecord('person', 1); + + assert.equal(person.get('tag'), null, 'relationship is empty'); + assert.equal(tag.get('people.length'), 0, 'relationship is correct'); + }); +}); + +test('hasMany with explicit null works even when the inverse was set to not null', function(assert) { + assert.expect(3); + + const Tag = DS.Model.extend({ + name: DS.attr('string'), + people: DS.hasMany('person', { async: false }) + }); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: false }) + }); + + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + + env.adapter.shouldBackgroundReloadRecord = () => false; + + run(() => { + // first we push in data with the relationship + store.push({ + data: { + type: 'person', + id: 1, + attributes: { + name: 'David J. Hamilton' + }, + relationships: { + tag: { + data: { + type: 'tag', + id: 1 + } + } + } + }, + included: [ + { + type: 'tag', + id: 1, + attributes: { + name: 'whatever' + }, + relationships: { + people: { + data: [{ + type: 'person', + id: 1 + }] + } + } + } + ] + }); + }); + + run(() => { + let person = store.peekRecord('person', 1); + let tag = store.peekRecord('tag', 1); + + assert.equal(person.get('tag'), tag, 'relationship is not empty'); + }); + + run(() => { + // now we push in data for that record which says it has no relationships + store.push({ + data: { + type: 'tag', + id: 1, + attributes: { + name: 'whatever' + }, + relationships: { + people: { + data: null + } + } + } + }); + }); + + return run(() => { + let person = store.peekRecord('person', 1); + let tag = store.peekRecord('tag', 1); + + assert.equal(person.get('tag'), null,'relationship is now empty'); + + /* + TODO this should be asserting `0` however + before pushing null, length is actually secretly out-of-sync with + the canonicalState array, which has duplicated the addCanonicalRecord + leading to length `2`, so when we splice out the record we are left + with length 1. + + This is fixed by the relationship cleanup PR which noticed this churn + and removed it: https://github.com/emberjs/data/pull/4882 + */ + assert.equal(tag.get('people.length'), 1, 'relationship is correct'); + }); +}); + test('hasMany tolerates reflexive self-relationships', function(assert) { assert.expect(1); From f78d498450eebb6f7e3513bbca5116e51a6492a1 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 29 Mar 2017 13:30:25 -0400 Subject: [PATCH 1883/2527] Add a better error message when malformatted JSON API is pushed into the store for a belongs to relationships. --- .../system/relationships/state/belongs-to.js | 1 + .../relationships/belongs-to-test.js | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index f3ca9d5e385..24fe9313e37 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -175,6 +175,7 @@ export default class BelongsToRelationship extends Relationship { } updateData(data, initial) { + assert(`Ember Data expected the data for the ${this.key} relationship on a ${this.internalModel.toString()} to be in a JSON API format and include an \`id\` and \`type\` property but it found ${Ember.inspect(data)}. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || data.id !== undefined && data.type !== undefined); let internalModel = this.store._pushResourceIdentifier(this, data); if (initial) { this.setInitialCanonicalRecord(internalModel); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index b7625e5566f..f2e44830546 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1364,3 +1364,22 @@ test("A belongsTo relationship can be reloaded using a reference if it was fetch }); }); }); + +testInDebug("A belongsTo relationship warns if malformatted data is pushed into the store", function(assert) { + assert.expectAssertion(function() { + run(function() { + let chapter = env.store.push({ + data: { + type: 'chapter', + id: 1, + relationships: { + book: { + data: { id: 1, name: 'The Gallic Wars' } + } + } + } + }); + chapter.get('book'); + }); + }, /expected the data for the book relationship on a to be in a JSON API format/); +}); From 8dd33bc014e99141436cef2c52a2f8f6d6ad30bd Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Thu, 16 Mar 2017 12:54:00 -0700 Subject: [PATCH 1884/2527] Rename record -> internalModel Within relationships state, which now deals almost exclusively with internal models. --- addon/-private/system/model/internal-model.js | 6 +- .../-private/system/references/belongs-to.js | 12 +- .../system/relationships/belongs-to.js | 4 +- .../system/relationships/state/belongs-to.js | 104 +++++----- .../system/relationships/state/has-many.js | 76 +++---- .../relationships/state/relationship.js | 193 +++++++++--------- addon/-private/system/snapshot.js | 10 +- addon/-private/system/store.js | 4 +- .../unit/model/relationships/has-many-test.js | 2 +- 9 files changed, 203 insertions(+), 208 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 485acc5b4b1..02102a4df82 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -941,15 +941,15 @@ export default class InternalModel { //We use the pathway of setting the hasMany as if it came from the adapter //because the user told us that they know this relationships exists already - this._relationships.get(key).updateRecordsFromAdapter(recordsToSet); + this._relationships.get(key).updateInternalModelsFromAdapter(recordsToSet); } _preloadBelongsTo(key, preloadValue, modelClass) { - let recordToSet = this._convertStringOrNumberIntoInternalModel(preloadValue, modelClass); + let internalModelToSet = this._convertStringOrNumberIntoInternalModel(preloadValue, modelClass); //We use the pathway of setting the hasMany as if it came from the adapter //because the user told us that they know this relationships exists already - this._relationships.get(key).setRecord(recordToSet); + this._relationships.get(key).setInternalModel(internalModelToSet); } _convertStringOrNumberIntoInternalModel(value, modelClass) { diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 7d54cf1ee66..c0f1ffb3360 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -109,8 +109,8 @@ BelongsToReference.prototype.remoteType = function() { @return {String} The id of the record in this belongsTo relationship. */ BelongsToReference.prototype.id = function() { - let inverseRecord = this.belongsToRelationship.inverseRecord; - return inverseRecord && inverseRecord.id; + let inverseInternalModel = this.belongsToRelationship.inverseInternalModel; + return inverseInternalModel && inverseInternalModel.id; }; /** @@ -257,7 +257,7 @@ BelongsToReference.prototype.push = function(objectOrPromise) { assertPolymorphicType(this.internalModel, this.belongsToRelationship.relationshipMeta, record._internalModel); - this.belongsToRelationship.setCanonicalRecord(record._internalModel); + this.belongsToRelationship.setCanonicalInternalModel(record._internalModel); return record; }); @@ -312,10 +312,10 @@ BelongsToReference.prototype.push = function(objectOrPromise) { @return {DS.Model} the record in this relationship */ BelongsToReference.prototype.value = function() { - let inverseRecord = this.belongsToRelationship.inverseRecord; + let inverseInternalModel = this.belongsToRelationship.inverseInternalModel; - if (inverseRecord && inverseRecord.isLoaded()) { - return inverseRecord.getRecord(); + if (inverseInternalModel && inverseInternalModel.isLoaded()) { + return inverseInternalModel.getRecord(); } return null; diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 7a444304e3c..65ced641d89 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -124,9 +124,9 @@ export default function belongsTo(modelName, options) { if (value && value.then) { this._internalModel._relationships.get(key).setRecordPromise(value); } else if (value) { - this._internalModel._relationships.get(key).setRecord(value._internalModel); + this._internalModel._relationships.get(key).setInternalModel(value._internalModel); } else { - this._internalModel._relationships.get(key).setRecord(value); + this._internalModel._relationships.get(key).setInternalModel(value); } return this._internalModel._relationships.get(key).getRecord(); diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index f3ca9d5e385..a79af83316d 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -13,50 +13,50 @@ export default class BelongsToRelationship extends Relationship { super(store, internalModel, inverseKey, relationshipMeta); this.internalModel = internalModel; this.key = relationshipMeta.key; - this.inverseRecord = null; + this.inverseInternalModel = null; this.canonicalState = null; } - setRecord(newRecord) { - if (newRecord) { - this.addRecord(newRecord); - } else if (this.inverseRecord) { - this.removeRecord(this.inverseRecord); + setInternalModel(internalModel) { + if (internalModel) { + this.addInternalModel(internalModel); + } else if (this.inverseInternalModel) { + this.removeInternalModel(this.inverseInternalModel); } this.setHasData(true); this.setHasLoaded(true); } - setCanonicalRecord(newRecord) { - if (newRecord) { - this.addCanonicalRecord(newRecord); + setCanonicalInternalModel(internalModel) { + if (internalModel) { + this.addCanonicalInternalModel(internalModel); } else if (this.canonicalState) { - this.removeCanonicalRecord(this.canonicalState); + this.removeCanonicalInternalModel(this.canonicalState); } this.flushCanonicalLater(); } - setInitialCanonicalRecord(record) { - if (!record) { return; } + setInitialCanonicalInternalModel(internalModel) { + if (!internalModel) { return; } // When we initialize a belongsTo relationship, we want to avoid work like // notifying our internalModel that we've "changed" and excessive thrash on // setting up inverse relationships - this.canonicalMembers.add(record); - this.members.add(record); - this.inverseRecord = this.canonicalState = record; - this.setupInverseRelationship(record); + this.canonicalMembers.add(internalModel); + this.members.add(internalModel); + this.inverseInternalModel = this.canonicalState = internalModel; + this.setupInverseRelationship(internalModel); } - addCanonicalRecord(newRecord) { - if (this.canonicalMembers.has(newRecord)) { return;} + addCanonicalInternalModel(internalModel) { + if (this.canonicalMembers.has(internalModel)) { return;} if (this.canonicalState) { - this.removeCanonicalRecord(this.canonicalState); + this.removeCanonicalInternalModel(this.canonicalState); } - this.canonicalState = newRecord; - super.addCanonicalRecord(newRecord); + this.canonicalState = internalModel; + super.addCanonicalInternalModel(internalModel); } inverseDidDematerialize() { @@ -66,41 +66,41 @@ export default class BelongsToRelationship extends Relationship { flushCanonical() { //temporary fix to not remove newly created records if server returned null. //TODO remove once we have proper diffing - if (this.inverseRecord && this.inverseRecord.isNew() && !this.canonicalState) { + if (this.inverseInternalModel && this.inverseInternalModel.isNew() && !this.canonicalState) { return; } - if (this.inverseRecord !== this.canonicalState) { - this.inverseRecord = this.canonicalState; + if (this.inverseInternalModel !== this.canonicalState) { + this.inverseInternalModel = this.canonicalState; this.notifyBelongsToChanged(); } super.flushCanonical(); } - addRecord(newRecord) { - if (this.members.has(newRecord)) { return; } + addInternalModel(internalModel) { + if (this.members.has(internalModel)) { return; } - assertPolymorphicType(this.internalModel, this.relationshipMeta, newRecord); + assertPolymorphicType(this.internalModel, this.relationshipMeta, internalModel); - if (this.inverseRecord) { - this.removeRecord(this.inverseRecord); + if (this.inverseInternalModel) { + this.removeInternalModel(this.inverseInternalModel); } - this.inverseRecord = newRecord; - super.addRecord(newRecord); + this.inverseInternalModel = internalModel; + super.addInternalModel(internalModel); this.notifyBelongsToChanged(); } setRecordPromise(newPromise) { let content = newPromise.get && newPromise.get('content'); assert("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); - this.setRecord(content ? content._internalModel : content); + this.setInternalModel(content ? content._internalModel : content); } - removeRecordFromOwn(record) { - if (!this.members.has(record)) { return;} - this.inverseRecord = null; - super.removeRecordFromOwn(record); + removeInternalModelFromOwn(internalModel) { + if (!this.members.has(internalModel)) { return;} + this.inverseInternalModel = null; + super.removeInternalModelFromOwn(internalModel); this.notifyBelongsToChanged(); } @@ -108,26 +108,26 @@ export default class BelongsToRelationship extends Relationship { this.internalModel.notifyBelongsToChanged(this.key); } - removeCanonicalRecordFromOwn(record) { - if (!this.canonicalMembers.has(record)) { return;} + removeCanonicalInternalModelFromOwn(internalModel) { + if (!this.canonicalMembers.has(internalModel)) { return;} this.canonicalState = null; - super.removeCanonicalRecordFromOwn(record); + super.removeCanonicalInternalModelFromOwn(internalModel); } findRecord() { - if (this.inverseRecord) { - return this.store._findByInternalModel(this.inverseRecord); + if (this.inverseInternalModel) { + return this.store._findByInternalModel(this.inverseInternalModel); } else { return Ember.RSVP.Promise.resolve(null); } } fetchLink() { - return this.store.findBelongsTo(this.internalModel, this.link, this.relationshipMeta).then((record) => { - if (record) { - this.addRecord(record); + return this.store.findBelongsTo(this.internalModel, this.link, this.relationshipMeta).then((internalModel) => { + if (internalModel) { + this.addInternalModel(internalModel); } - return record; + return internalModel; }); } @@ -147,13 +147,13 @@ export default class BelongsToRelationship extends Relationship { return PromiseObject.create({ promise: promise, - content: this.inverseRecord ? this.inverseRecord.getRecord() : null + content: this.inverseInternalModel ? this.inverseInternalModel.getRecord() : null }); } else { - if (this.inverseRecord === null) { + if (this.inverseInternalModel === null) { return null; } - let toReturn = this.inverseRecord.getRecord(); + let toReturn = this.inverseInternalModel.getRecord(); assert("You looked up the '" + this.key + "' relationship on a '" + this.internalModel.modelName + "' with id " + this.internalModel.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); return toReturn; } @@ -167,8 +167,8 @@ export default class BelongsToRelationship extends Relationship { } // reload record, if it is already loaded - if (this.inverseRecord && this.inverseRecord.hasRecord) { - return this.inverseRecord.getRecord().reload(); + if (this.inverseInternalModel && this.inverseInternalModel.hasRecord) { + return this.inverseInternalModel.getRecord().reload(); } return this.findRecord(); @@ -177,9 +177,9 @@ export default class BelongsToRelationship extends Relationship { updateData(data, initial) { let internalModel = this.store._pushResourceIdentifier(this, data); if (initial) { - this.setInitialCanonicalRecord(internalModel); + this.setInitialCanonicalInternalModel(internalModel); } else { - this.setCanonicalRecord(internalModel); + this.setCanonicalInternalModel(internalModel); } } } diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index d0c6ea040d0..f691f1a1bac 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -5,8 +5,8 @@ import OrderedSet from '../../ordered-set'; import ManyArray from '../../many-array'; export default class ManyRelationship extends Relationship { - constructor(store, record, inverseKey, relationshipMeta) { - super(store, record, inverseKey, relationshipMeta); + constructor(store, internalModel, inverseKey, relationshipMeta) { + super(store, internalModel, inverseKey, relationshipMeta); this.belongsToType = relationshipMeta.type; this.canonicalState = []; this.isPolymorphic = relationshipMeta.options.polymorphic; @@ -38,7 +38,7 @@ export default class ManyRelationship extends Relationship { store: this.store, relationship: this, type: this.store.modelFor(this.belongsToType), - record: this.record, + record: this.internalModel, meta: this.meta, isPolymorphic: this.isPolymorphic }); @@ -65,16 +65,16 @@ export default class ManyRelationship extends Relationship { } } - addCanonicalRecord(record, idx) { - if (this.canonicalMembers.has(record)) { + addCanonicalInternalModel(internalModel, idx) { + if (this.canonicalMembers.has(internalModel)) { return; } if (idx !== undefined) { - this.canonicalState.splice(idx, 0, record); + this.canonicalState.splice(idx, 0, internalModel); } else { - this.canonicalState.push(record); + this.canonicalState.push(internalModel); } - super.addCanonicalRecord(record, idx); + super.addCanonicalInternalModel(internalModel, idx); } inverseDidDematerialize() { @@ -85,29 +85,29 @@ export default class ManyRelationship extends Relationship { this.notifyHasManyChanged(); } - addRecord(record, idx) { - if (this.members.has(record)) { + addInternalModel(internalModel, idx) { + if (this.members.has(internalModel)) { return; } - assertPolymorphicType(this.record, this.relationshipMeta, record); - super.addRecord(record, idx); + assertPolymorphicType(this.internalModel, this.relationshipMeta, internalModel); + super.addInternalModel(internalModel, idx); // make lazy later - this.manyArray.internalAddInternalModels([record], idx); + this.manyArray.internalAddInternalModels([internalModel], idx); } - removeCanonicalRecordFromOwn(record, idx) { + removeCanonicalInternalModelFromOwn(internalModel, idx) { let i = idx; - if (!this.canonicalMembers.has(record)) { + if (!this.canonicalMembers.has(internalModel)) { return; } if (i === undefined) { - i = this.canonicalState.indexOf(record); + i = this.canonicalState.indexOf(internalModel); } if (i > -1) { this.canonicalState.splice(i, 1); } - super.removeCanonicalRecordFromOwn(record, idx); + super.removeCanonicalInternalModelFromOwn(internalModel, idx); } flushCanonical() { @@ -117,22 +117,22 @@ export default class ManyRelationship extends Relationship { super.flushCanonical(); } - removeRecordFromOwn(record, idx) { - if (!this.members.has(record)) { + removeInternalModelFromOwn(internalModel, idx) { + if (!this.members.has(internalModel)) { return; } - super.removeRecordFromOwn(record, idx); + super.removeInternalModelFromOwn(internalModel, idx); let manyArray = this.manyArray; if (idx !== undefined) { //TODO(Igor) not used currently, fix manyArray.currentState.removeAt(idx); } else { - manyArray.internalRemoveInternalModels([record]); + manyArray.internalRemoveInternalModels([internalModel]); } } - notifyRecordRelationshipAdded(record, idx) { - this.record.notifyHasManyAdded(this.key, record, idx); + notifyRecordRelationshipAdded(internalModel, idx) { + this.internalModel.notifyHasManyAdded(this.key, internalModel, idx); } reload() { @@ -159,23 +159,23 @@ export default class ManyRelationship extends Relationship { return this._loadingPromise; } - computeChanges(records = []) { + computeChanges(internalModels = []) { let members = this.canonicalMembers; - let recordsToRemove = []; - let recordSet = setForArray(records); + let internalModelsToRemove = []; + let internalModelSet = setForArray(internalModels); members.forEach(member => { - if (recordSet.has(member)) { return; } + if (internalModelSet.has(member)) { return; } - recordsToRemove.push(member); + internalModelsToRemove.push(member); }); - this.removeCanonicalRecords(recordsToRemove); + this.removeCanonicalInternalModels(internalModelsToRemove); - for (let i = 0, l = records.length; i < l; i++) { - let record = records[i]; - this.removeCanonicalRecord(record); - this.addCanonicalRecord(record, i); + for (let i = 0, l = internalModels.length; i < l; i++) { + let internalModel = internalModels[i]; + this.removeCanonicalInternalModel(internalModel); + this.addCanonicalInternalModel(internalModel, i); } } @@ -194,12 +194,12 @@ export default class ManyRelationship extends Relationship { } fetchLink() { - return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(records => { + return this.store.findHasMany(this.internalModel, this.link, this.relationshipMeta).then(records => { if (records.hasOwnProperty('meta')) { this.updateMeta(records.meta); } this.store._backburner.join(() => { - this.updateRecordsFromAdapter(records); + this.updateInternalModelsFromAdapter(records); this.manyArray.set('isLoaded', true); }); return this.manyArray; @@ -221,7 +221,7 @@ export default class ManyRelationship extends Relationship { } notifyHasManyChanged() { - this.record.notifyHasManyAdded(this.key); + this.internalModel.notifyHasManyAdded(this.key); } getRecords() { @@ -240,7 +240,7 @@ export default class ManyRelationship extends Relationship { } return this._updateLoadingPromise(promise, manyArray); } else { - assert(`You looked up the '${this.key}' relationship on a '${this.record.type.modelName}' with id ${this.record.id} but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async ('DS.hasMany({ async: true })')`, manyArray.isEvery('isEmpty', false)); + assert(`You looked up the '${this.key}' relationship on a '${this.internalModel.type.modelName}' with id ${this.internalModel.id} but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async ('DS.hasMany({ async: true })')`, manyArray.isEvery('isEmpty', false)); //TODO(Igor) WTF DO I DO HERE? // TODO @runspired equal WTFs to Igor @@ -256,7 +256,7 @@ export default class ManyRelationship extends Relationship { if (initial) { this.setInitialInternalModels(internalModels); } else { - this.updateRecordsFromAdapter(internalModels); + this.updateInternalModelsFromAdapter(internalModels); } } } diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 0fea51f1ee4..9260dbfc8f6 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -4,9 +4,9 @@ import OrderedSet from '../../ordered-set'; import _normalizeLink from '../../normalize-link'; const { - addCanonicalRecord, - addCanonicalRecords, - addRecord, + addCanonicalInternalModel, + addCanonicalInternalModels, + addInternalModel, addInternalModels, clear, findLink, @@ -14,23 +14,23 @@ const { flushCanonicalLater, newRelationship, push, - removeCanonicalRecord, - removeCanonicalRecordFromInverse, - removeCanonicalRecordFromOwn, - removeCanonicalRecords, - removeRecord, - removeRecordFromInverse, - removeRecordFromOwn, + removeCanonicalInternalModel, + removeCanonicalInternalModelFromInverse, + removeCanonicalInternalModelFromOwn, + removeCanonicalInternalModels, + removeInternalModel, + removeInternalModelFromInverse, + removeInternalModelFromOwn, removeInternalModels, setHasData, setHasLoaded, updateLink, updateMeta, - updateRecordsFromAdapter + updateInternalModelsFromAdapter } = heimdall.registerMonitor('system.relationships.state.relationship', - 'addCanonicalRecord', - 'addCanonicalRecords', - 'addRecord', + 'addCanonicalInternalModel', + 'addCanonicalInternalModels', + 'addInternalModel', 'addInternalModels', 'clear', 'findLink', @@ -38,19 +38,19 @@ const { 'flushCanonicalLater', 'newRelationship', 'push', - 'removeCanonicalRecord', - 'removeCanonicalRecordFromInverse', - 'removeCanonicalRecordFromOwn', - 'removeCanonicalRecords', - 'removeRecord', - 'removeRecordFromInverse', - 'removeRecordFromOwn', + 'removeCanonicalInternalModel', + 'removeCanonicalInternalModelFromInverse', + 'removeCanonicalInternalModelFromOwn', + 'removeCanonicalInternalModels', + 'removeInternalModel', + 'removeInternalModelFromInverse', + 'removeInternalModelFromOwn', 'removeInternalModels', 'setHasData', 'setHasLoaded', 'updateLink', 'updateMeta', - 'updateRecordsFromAdapter' + 'updateInternalModelsFromAdapter' ); export default class Relationship { @@ -76,11 +76,6 @@ export default class Relationship { this.hasLoaded = false; } - // TODO @runspired deprecate this as it was never truly a record instance - get record() { - return this.internalModel; - } - get parentType() { return this.internalModel.modelName; } @@ -112,47 +107,47 @@ export default class Relationship { let members = this.members.list; while (members.length > 0) { let member = members[0]; - this.removeRecord(member); + this.removeInternalModel(member); } let canonicalMembers = this.canonicalMembers.list; while (canonicalMembers.length > 0) { let member = canonicalMembers[0]; - this.removeCanonicalRecord(member); + this.removeCanonicalInternalModel(member); } } removeInternalModels(internalModels) { heimdall.increment(removeInternalModels); - internalModels.forEach((internalModel) => this.removeRecord(internalModel)); + internalModels.forEach((internalModel) => this.removeInternalModel(internalModel)); } addInternalModels(internalModels, idx) { heimdall.increment(addInternalModels); internalModels.forEach(internalModel => { - this.addRecord(internalModel, idx); + this.addInternalModel(internalModel, idx); if (idx !== undefined) { idx++; } }); } - addCanonicalRecords(records, idx) { - heimdall.increment(addCanonicalRecords); - for (let i=0; i Date: Thu, 16 Mar 2017 14:40:51 -0700 Subject: [PATCH 1885/2527] Rename record -> internalModel Within many-array which mostly deals with internal models. --- addon/-private/system/many-array.js | 26 +++++++++---------- .../system/relationships/state/has-many.js | 4 +-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 78433bd4e31..e5f5e48c0a4 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -134,16 +134,16 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { }, objectAt(index) { - let object = this.currentState[index]; + let internalModel = this.currentState[index]; //Ember observers such as 'firstObject', 'lastObject' might do out of bounds accesses - if (object === undefined) { + if (internalModel === undefined) { warn(`ManyArray#objectAt(index) return undefined for index '${index}'. See https://github.com/emberjs/data/issues/4758`, false, { id: 'ds.many-array.object-at-undefined' }); return; } - return object.getRecord(); + return internalModel.getRecord(); }, flushCanonical(isInitialized = true) { @@ -156,8 +156,8 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { //a hack for not removing new records //TODO remove once we have proper diffing let newInternalModels = this.currentState.filter( - // only add new records which are not yet in the canonical state of this - // relationship (a new record can be in the canonical state if it has + // only add new internalModels which are not yet in the canonical state of this + // relationship (a new internalModel can be in the canonical state if it has // been 'acknowleged' to be in the relationship via a store.push) (internalModel) => internalModel.isNew() && toSet.indexOf(internalModel) === -1 ); @@ -191,26 +191,26 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { }, //TODO(Igor) optimize - internalRemoveInternalModels(records) { - for (let i=0; i < records.length; i++) { - let index = this.currentState.indexOf(records[i]); + _removeInternalModels(internalModels) { + for (let i=0; i < internalModels.length; i++) { + let index = this.currentState.indexOf(internalModels[i]); this.internalReplace(index, 1); } }, //TODO(Igor) optimize - internalAddInternalModels(records, idx) { + _addInternalModels(internalModels, idx) { if (idx === undefined) { idx = this.currentState.length; } - this.internalReplace(idx, 0, records); + this.internalReplace(idx, 0, internalModels); }, replace(idx, amt, objects) { - let records; + let internalModels; if (amt > 0) { - records = this.currentState.slice(idx, idx+amt); - this.get('relationship').removeInternalModels(records); + internalModels = this.currentState.slice(idx, idx+amt); + this.get('relationship').removeInternalModels(internalModels); } if (objects) { this.get('relationship').addInternalModels(objects.map(obj => obj._internalModel), idx); diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index f691f1a1bac..55f40d6bd5d 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -93,7 +93,7 @@ export default class ManyRelationship extends Relationship { assertPolymorphicType(this.internalModel, this.relationshipMeta, internalModel); super.addInternalModel(internalModel, idx); // make lazy later - this.manyArray.internalAddInternalModels([internalModel], idx); + this.manyArray._addInternalModels([internalModel], idx); } removeCanonicalInternalModelFromOwn(internalModel, idx) { @@ -127,7 +127,7 @@ export default class ManyRelationship extends Relationship { //TODO(Igor) not used currently, fix manyArray.currentState.removeAt(idx); } else { - manyArray.internalRemoveInternalModels([internalModel]); + manyArray._removeInternalModels([internalModel]); } } From ee826b2481708e20b94e495aff7dce8df4a1bcd4 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 4 Apr 2017 16:40:54 -0700 Subject: [PATCH 1886/2527] [BUGFIX canary] don't prematurely nullify props on the container-instance-cache --- addon/-private/system/store/container-instance-cache.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/store/container-instance-cache.js b/addon/-private/system/store/container-instance-cache.js index a1ce4262579..cc464c7bf54 100644 --- a/addon/-private/system/store/container-instance-cache.js +++ b/addon/-private/system/store/container-instance-cache.js @@ -1,6 +1,6 @@ /* global heimdall */ import Ember from 'ember'; -const { set } = Ember; +const { set, run } = Ember; const { __get, @@ -33,6 +33,8 @@ const { */ export default class ContainerInstanceCache { constructor(owner, store) { + this.isDestroying = false; + this.isDestroyed = false; this._owner = owner; this._store = store; this._namespaces = { @@ -111,11 +113,10 @@ export default class ContainerInstanceCache { } destroy() { + this.isDestroying = true; this.destroyCache(this._namespaces.adapter); this.destroyCache(this._namespaces.serializer); - this._namespaces = null; - this._store = null; - this._owner = null; + this.isDestroyed = true; } toString() { From a5d1cd5cf8ff658be9ee5ac5812ce7932bae79fd Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 4 Apr 2017 18:42:02 -0700 Subject: [PATCH 1887/2527] Revert "Ember.warn when ManyArray.objectAt() is underfined" This reverts commit 44ffbff63e4cae33ab519b23d51394645d7ccab1. More details: https://github.com/emberjs/data/pull/4896#issuecomment-291706797 --- addon/-private/system/many-array.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index e5f5e48c0a4..667ef50033a 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -2,7 +2,7 @@ @module ember-data */ import Ember from 'ember'; -import { assert, warn } from "ember-data/-private/debug"; +import { assert } from "ember-data/-private/debug"; import { PromiseArray } from "./promise-proxies"; import { _objectIsAlive } from "./store/common"; import diffArray from './diff-array'; @@ -135,13 +135,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { objectAt(index) { let internalModel = this.currentState[index]; - //Ember observers such as 'firstObject', 'lastObject' might do out of bounds accesses - if (internalModel === undefined) { - warn(`ManyArray#objectAt(index) return undefined for index '${index}'. See https://github.com/emberjs/data/issues/4758`, false, { - id: 'ds.many-array.object-at-undefined' - }); - return; - } + if (internalModel === undefined) { return; } return internalModel.getRecord(); }, From c2dbde31b70e0d6eac884e195d2b8dbdc6d83b3e Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 4 Apr 2017 18:58:17 -0700 Subject: [PATCH 1888/2527] fix eslint --- addon/-private/system/store/container-instance-cache.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/store/container-instance-cache.js b/addon/-private/system/store/container-instance-cache.js index cc464c7bf54..82768c827ae 100644 --- a/addon/-private/system/store/container-instance-cache.js +++ b/addon/-private/system/store/container-instance-cache.js @@ -1,6 +1,6 @@ /* global heimdall */ import Ember from 'ember'; -const { set, run } = Ember; +const { set } = Ember; const { __get, From 0bbf751be77c32b3d3209ce5aefcd6a2140c3b7a Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Sun, 26 Mar 2017 20:42:04 -0700 Subject: [PATCH 1889/2527] [PERF] single-pass over the initializers array --- .../initialize-store-service.js | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/addon/-private/instance-initializers/initialize-store-service.js b/addon/-private/instance-initializers/initialize-store-service.js index 39cb08d130c..edb54cac9aa 100644 --- a/addon/-private/instance-initializers/initialize-store-service.js +++ b/addon/-private/instance-initializers/initialize-store-service.js @@ -1,4 +1,5 @@ import { deprecate } from 'ember-data/-private/debug'; + /* Configures a registry for use with an Ember-Data store. @@ -7,41 +8,41 @@ import { deprecate } from 'ember-data/-private/debug'; @param {Ember.ApplicationInstance} applicationOrRegistry */ export default function initializeStoreService(application) { - let container = application.lookup ? application : application.container; + const container = application.lookup ? application : application.container; + // Eagerly generate the store so defaultStore is populated. container.lookup('service:store'); - let initializers = application.application.constructor.initializers; - deprecateOldEmberDataInitializers(initializers) + deprecateOldEmberDataInitializers(application.application.constructor.initializers); } - - -let deprecatedInitializerNames = ['data-adapter', 'injectStore', 'transforms', 'store']; +const DEPRECATED_INITIALIZER_NAMES = ['data-adapter', 'injectStore', 'transforms', 'store']; function matchesDeprecatedInititalizer(name) { - return deprecatedInitializerNames.indexOf(name) !== -1; + return DEPRECATED_INITIALIZER_NAMES.indexOf(name) !== -1; } function deprecateOldEmberDataInitializers(initializers) { // collect all of the initializers - let initializersArray = Object.keys(initializers).map(key => initializers[key]); - - // filter out all of the Ember Data initializer. We have some - // deprecated initializers that depend on other deprecated - // initializers which may trigger the deprecation warning - // unintentionally. - let nonEmberDataInitializers = initializersArray.filter((initializer) => { - return !matchesDeprecatedInititalizer(initializer.name) - }) - - nonEmberDataInitializers.forEach(warnForDeprecatedInitializers) + let keys = Object.keys(initializers); + + for (let i = 0; i < keys.length; i++) { + let name = keys[i]; + + // filter out all of the Ember Data initializer. We have some + // deprecated initializers that depend on other deprecated + // initializers which may trigger the deprecation warning + // unintentionally. + if (!matchesDeprecatedInititalizer(name)) { + warnForDeprecatedInitializers(initializers[name]); + } + } } function warnForDeprecatedInitializers(initializer) { - var deprecatedBeforeInitializer = matchesDeprecatedInititalizer(initializer.before) - var deprecatedAfterInitializer = matchesDeprecatedInititalizer(initializer.after) - let deprecatedProp = deprecatedBeforeInitializer ? 'before' : 'after' + let deprecatedBeforeInitializer = matchesDeprecatedInititalizer(initializer.before); + let deprecatedAfterInitializer = matchesDeprecatedInititalizer(initializer.after); + let deprecatedProp = deprecatedBeforeInitializer ? 'before' : 'after'; deprecate( `The initializer \`${initializer[deprecatedProp]}\` has been deprecated. Please update your \`${initializer.name}\` initializer to use use \`${deprecatedProp}: \'ember-data\'\` instead.`, From ff1c2c77124540c13eb73dbc27c6aec60642deea Mon Sep 17 00:00:00 2001 From: Timothy Morey Date: Mon, 10 Apr 2017 17:40:09 -0400 Subject: [PATCH 1890/2527] [DOC] Update the doc of findHasMany to correctly reflect the order of parameters --- addon/adapters/rest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 473f30874a9..d215ac855f2 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -670,8 +670,8 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @method findHasMany @param {DS.Store} store @param {DS.Snapshot} snapshot - @param {Object} relationship meta object describing the relationship @param {String} url + @param {Object} relationship meta object describing the relationship @return {Promise} promise */ findHasMany(store, snapshot, url, relationship) { From 4dcb83d2d557c558c6c1a8cfb4c2825c0351e238 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 11 Apr 2017 22:55:15 -0700 Subject: [PATCH 1891/2527] =?UTF-8?q?[BUGFIX=20release]=20restore=20intern?= =?UTF-8?q?alModels=20GUID=5FKEY=E2=80=99s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addon/-private/system/model/internal-model.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 02102a4df82..0d1c8168491 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -119,7 +119,10 @@ export default class InternalModel { constructor(modelName, id, store, data) { heimdall.increment(new_InternalModel); this.id = id; - this._internalId = InternalModelReferenceId++; + + // this ensure ordered set can quickly identify this as unique + this[Ember.GUID_KEY] = InternalModelReferenceId++ + 'internal-model'; + this.store = store; this.modelName = modelName; this._loadingPromise = null; From c99af930749cd697ab35ab2bab5a1f74137462b2 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Wed, 12 Apr 2017 15:41:21 -0400 Subject: [PATCH 1892/2527] Update the changelog for the Ember Data 2.12.2 release --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f693e3ed69b..9414941d651 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ### Master +### Release 2.12.2 (April 12, 2017) +- [#4922](https://github.com/emberjs/data/pull/4922) [BUGFIX release] restore internalModels GUID_KEY’s +- [#4917](https://github.com/emberjs/data/pull/4917) [BACKPORT 4913] For release + ### Release 2.12.1 (March 17, 2017) - [#4875](https://github.com/emberjs/data/pull/4875) [BUGFIX release] ensure the globals build has the correct context in the iife. - [#4881](https://github.com/emberjs/data/pull/4881) Fix injection-test on the release branch From a2785b2442b824947f59b94f6a2d0399b5dd708f Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 10 Apr 2017 12:13:24 -0700 Subject: [PATCH 1893/2527] Strip unused imports, dead modules, and debug modules from prod builds --- addon/-private/adapters.js | 11 ----- addon/-private/initializers/store.js | 7 +++- addon/-private/serializers.js | 13 ------ addon/-private/system/debug.js | 7 ---- addon/-private/system/empty-object.js | 17 -------- addon/-private/system/store.js | 2 +- addon/index.js | 16 +++----- app/initializers/data-adapter.js | 2 - app/initializers/injectStore.js | 2 - app/initializers/store.js | 2 - app/initializers/transforms.js | 2 - index.js | 23 +++++++++-- lib/stripped-build-plugins.js | 5 +++ lib/transforms/babel-plugin-remove-imports.js | 40 +++++++++++++++++++ .../unit/utils/parse-response-headers-test.js | 4 +- 15 files changed, 78 insertions(+), 75 deletions(-) delete mode 100644 addon/-private/adapters.js delete mode 100644 addon/-private/serializers.js delete mode 100644 addon/-private/system/debug.js delete mode 100644 addon/-private/system/empty-object.js create mode 100644 lib/transforms/babel-plugin-remove-imports.js diff --git a/addon/-private/adapters.js b/addon/-private/adapters.js deleted file mode 100644 index 0b385f6f689..00000000000 --- a/addon/-private/adapters.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - @module ember-data -*/ - -import JSONAPIAdapter from "ember-data/adapters/json-api"; -import RESTAdapter from "ember-data/adapters/rest"; - -export { - JSONAPIAdapter, - RESTAdapter -}; diff --git a/addon/-private/initializers/store.js b/addon/-private/initializers/store.js index d322211f833..7564592bb3b 100644 --- a/addon/-private/initializers/store.js +++ b/addon/-private/initializers/store.js @@ -1,6 +1,9 @@ import Store from "../system/store"; -import { JSONAPISerializer, JSONSerializer, RESTSerializer } from "../serializers"; -import { JSONAPIAdapter, RESTAdapter } from "../adapters"; +import JSONAPISerializer from 'ember-data/serializers/json-api'; +import JSONSerializer from 'ember-data/serializers/json'; +import RESTSerializer from 'ember-data/serializers/rest'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import RESTAdapter from 'ember-data/adapters/rest'; function has(applicationOrRegistry, fullName) { if (applicationOrRegistry.has) { diff --git a/addon/-private/serializers.js b/addon/-private/serializers.js deleted file mode 100644 index d79327d9d15..00000000000 --- a/addon/-private/serializers.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - @module ember-data -*/ - -import JSONAPISerializer from "ember-data/serializers/json-api"; -import JSONSerializer from "ember-data/serializers/json"; -import RESTSerializer from "ember-data/serializers/rest"; - -export { - JSONAPISerializer, - JSONSerializer, - RESTSerializer -}; diff --git a/addon/-private/system/debug.js b/addon/-private/system/debug.js deleted file mode 100644 index bda6db7c0f3..00000000000 --- a/addon/-private/system/debug.js +++ /dev/null @@ -1,7 +0,0 @@ -/** - @module ember-data -*/ - -import DebugAdapter from "./debug/debug-adapter"; - -export default DebugAdapter; diff --git a/addon/-private/system/empty-object.js b/addon/-private/system/empty-object.js deleted file mode 100644 index 2c526a15b02..00000000000 --- a/addon/-private/system/empty-object.js +++ /dev/null @@ -1,17 +0,0 @@ -// This exists because `Object.create(null)` is absurdly slow compared -// to `new EmptyObject()`. In either case, you want a null prototype -// when you're treating the object instances as arbitrary dictionaries -// and don't want your keys colliding with build-in methods on the -// default object prototype. -const proto = Object.create(null, { - // without this, we will always still end up with (new - // EmptyObject()).constructor === Object - constructor: { - value: undefined, - enumerable: false, - writable: true - } -}); - -export default function EmptyObject() {} -EmptyObject.prototype = proto; diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 26685ede5c6..f897e518f23 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -47,7 +47,7 @@ import ContainerInstanceCache from './store/container-instance-cache'; import InternalModel from "./model/internal-model"; import isEnabled from '../features'; -export let badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; +const badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; const { A, diff --git a/addon/index.js b/addon/index.js index 247ca924b5f..adb9a15554e 100644 --- a/addon/index.js +++ b/addon/index.js @@ -38,7 +38,7 @@ import Model from "./model"; import Snapshot from "./-private/system/snapshot"; import Adapter from "./adapter"; import Serializer from "./serializer"; -import DebugAdapter from "ember-data/-private/debug"; +import DebugAdapter from './-private/system/debug/debug-adapter'; import { AdapterError, @@ -61,16 +61,12 @@ import { } from "./-private/system/record-arrays"; import ManyArray from "./-private/system/many-array"; import RecordArrayManager from "./-private/system/record-array-manager"; -import { - JSONAPIAdapter, - RESTAdapter -} from "./-private/adapters"; +import JSONAPIAdapter from './adapters/json-api'; +import RESTAdapter from './adapters/rest'; import BuildURLMixin from "./-private/adapters/build-url-mixin"; -import { - JSONAPISerializer, - JSONSerializer, - RESTSerializer -} from "./-private/serializers"; +import JSONAPISerializer from './serializers/json-api'; +import JSONSerializer from './serializers/json'; +import RESTSerializer from './serializers/rest'; import "ember-inflector"; import EmbeddedRecordsMixin from "./serializers/embedded-records-mixin"; diff --git a/app/initializers/data-adapter.js b/app/initializers/data-adapter.js index f7447138eb8..b4c40cf2445 100644 --- a/app/initializers/data-adapter.js +++ b/app/initializers/data-adapter.js @@ -1,5 +1,3 @@ -import Ember from 'ember'; - /* This initializer is here to keep backwards compatibility with code depending on the `data-adapter` initializer (before Ember Data was an addon). diff --git a/app/initializers/injectStore.js b/app/initializers/injectStore.js index 7494c510b2d..fce063a52e5 100644 --- a/app/initializers/injectStore.js +++ b/app/initializers/injectStore.js @@ -1,5 +1,3 @@ -import Ember from 'ember'; - /* This initializer is here to keep backwards compatibility with code depending on the `injectStore` initializer (before Ember Data was an addon). diff --git a/app/initializers/store.js b/app/initializers/store.js index 5c497439bca..e0884ec74a6 100644 --- a/app/initializers/store.js +++ b/app/initializers/store.js @@ -1,5 +1,3 @@ -import Ember from 'ember'; - /* This initializer is here to keep backwards compatibility with code depending on the `store` initializer (before Ember Data was an addon). diff --git a/app/initializers/transforms.js b/app/initializers/transforms.js index 769e191e518..b666640831b 100644 --- a/app/initializers/transforms.js +++ b/app/initializers/transforms.js @@ -1,5 +1,3 @@ -import Ember from 'ember'; - /* This initializer is here to keep backwards compatibility with code depending on the `transforms` initializer (before Ember Data was an addon). diff --git a/index.js b/index.js index 8265a6e796d..dacf4585167 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,7 @@ var path = require('path'); var SilentError = require('silent-error'); +var Funnel = require('broccoli-funnel'); // allow toggling of heimdall instrumentation var INSTRUMENT_HEIMDALL = false; @@ -14,11 +15,14 @@ for (var i = 0; i < args.length; i++) { break; } } + process.env.INSTRUMENT_HEIMDALL = INSTRUMENT_HEIMDALL; -function add(options, name, array) { - var option = options[name] = options[name] || []; - option.push.apply(option, array); +function isProductionEnv() { + var isProd = /production/.test(process.env.EMBER_ENV); + var isTest = process.env.EMBER_CLI_TEST_COMMAND; + + return isProd && !isTest; } module.exports = { @@ -111,10 +115,21 @@ module.exports = { var version = require('./lib/version'); var merge = require('broccoli-merge-trees'); - return this._super.treeForAddon.call(this, merge([ + var tree = this._super.treeForAddon.call(this, merge([ version(), dir ])); + + if (isProductionEnv()) { + console.log('is prod'); + tree = new Funnel(tree, { + exclude: [ + /-private\/debug\.js/ + ] + }); + } + + return tree; }, _setupBabelOptions: function() { diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 6538387bc91..c13b2a544d6 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -3,6 +3,7 @@ var FilterImports = require('babel-plugin-filter-imports'); var FeatureFlags = require('babel-plugin-feature-flags'); var StripHeimdall = require('babel6-plugin-strip-heimdall'); var StripClassCallCheck = require('babel6-plugin-strip-class-callcheck'); +var StripFilteredImports = require('./transforms/babel-plugin-remove-imports'); function uniqueAdd(obj, key, values) { var a = obj[key] = obj[key] || []; @@ -59,5 +60,9 @@ module.exports = function(environment) { } plugins.push([FilterImports, filteredImports]); + if (environment === 'production') { + plugins.push([StripFilteredImports, 'ember-data/-private/debug']); + } + return { plugins, postTransformPlugins }; }; diff --git a/lib/transforms/babel-plugin-remove-imports.js b/lib/transforms/babel-plugin-remove-imports.js new file mode 100644 index 00000000000..8cff6d51079 --- /dev/null +++ b/lib/transforms/babel-plugin-remove-imports.js @@ -0,0 +1,40 @@ +var path = require('path'); + +function removeImports() { + let importDeclarationsToRemove; + let filteredImports; + + return { + name: 'remove-filtered-imports', + visitor: { + Program: { + enter: function(_, state) { + filteredImports = state.opts instanceof Array ? state.opts : (state.opts ? [state.opts] : []); + importDeclarationsToRemove = []; + }, + exit: function() { + importDeclarationsToRemove.forEach(function(declaration) { + declaration.remove(); + }); + + importDeclarationsToRemove = undefined; + } + }, + + ImportDeclaration: function(path) { + const name = path.node.source.value; + + if (filteredImports.indexOf(name) !== -1) { + importDeclarationsToRemove.push(path); + } + } + + } + }; +} + +removeImports.baseDir = function() { + return path.join(__dirname, '../../'); +}; + +module.exports = removeImports; diff --git a/tests/unit/utils/parse-response-headers-test.js b/tests/unit/utils/parse-response-headers-test.js index c313713b293..f4921c610df 100644 --- a/tests/unit/utils/parse-response-headers-test.js +++ b/tests/unit/utils/parse-response-headers-test.js @@ -5,10 +5,10 @@ const CRLF = '\u000d\u000a'; module('unit/adapters/parse-response-headers'); -test('returns an EmptyObject when headersString is undefined', function(assert) { +test('returns an NULL Object when headersString is undefined', function(assert) { let headers = parseResponseHeaders(undefined); - assert.deepEqual(headers, Object.create(null), 'EmptyObject is returned'); + assert.deepEqual(headers, Object.create(null), 'NULL Object is returned'); }); test('header parsing', function(assert) { From 871ed2fce819d21918ceceacd960941352eb9ac3 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 14 Apr 2017 10:16:43 -0700 Subject: [PATCH 1894/2527] work-around debug stripping issue --- tests/helpers/test-in-debug.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/helpers/test-in-debug.js b/tests/helpers/test-in-debug.js index 810896035f5..9d4bf2e9a89 100644 --- a/tests/helpers/test-in-debug.js +++ b/tests/helpers/test-in-debug.js @@ -1,10 +1,13 @@ -import { runInDebug } from 'ember-data/-private/debug'; +import require from 'require'; import { test, skip } from 'qunit'; export default function testInDebug() { let isDebug = false; - runInDebug(() => isDebug = true); + // TODO: this should be debug-stripped... + if (require.has('ember-data/-private/debug')) { + require('ember-data/-private/debug').runInDebug(() => isDebug = true); + } if (isDebug) { test(...arguments); From 23503f8b4734f60f22c9c636d64ca697600de06a Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 14 Apr 2017 13:17:48 -0700 Subject: [PATCH 1895/2527] [PERF] Model.prototype.didDefineProperty only in dev `meta.parentType` (which is produced by) `didDefineProperty` is only required for development assertions. As development assertions are stripped in prod, this `didDefineProperty` can also be stripped --- addon/-private/system/model/model.js | 85 +++++++++++----------- addon/-private/system/relationship-meta.js | 7 +- addon/-private/system/relationships/ext.js | 4 +- 3 files changed, 52 insertions(+), 44 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 43168b2cb7d..8759eba7147 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1050,46 +1050,6 @@ const Model = Ember.Object.extend(Ember.Evented, { notifyBelongsToChanged(key) { this.notifyPropertyChange(key); }, - - /** - This Ember.js hook allows an object to be notified when a property - is defined. - - In this case, we use it to be notified when an Ember Data user defines a - belongs-to relationship. In that case, we need to set up observers for - each one, allowing us to track relationship changes and automatically - reflect changes in the inverse has-many array. - - This hook passes the class being set up, as well as the key and value - being defined. So, for example, when the user does this: - - ```javascript - DS.Model.extend({ - parent: DS.belongsTo('user') - }); - ``` - - This hook would be called with "parent" as the key and the computed - property returned by `DS.belongsTo` as the value. - - @method didDefineProperty - @param {Object} proto - @param {String} key - @param {Ember.ComputedProperty} value - */ - didDefineProperty(proto, key, value) { - // Check if the value being set is a computed property. - if (value instanceof Ember.ComputedProperty) { - - // If it is, get the metadata for the relationship. This is - // populated by the `DS.belongsTo` helper when it is creating - // the computed property. - let meta = value.meta(); - - meta.parentType = proto.constructor; - } - }, - /** Given a callback, iterates over each of the relationships in the model, invoking the callback with the name of each relationship and its relationship @@ -1362,7 +1322,7 @@ Model.reopenClass({ inverseKind = inverse.kind; } else { //No inverse was specified manually, we need to use a heuristic to guess one - if (propertyMeta.type === propertyMeta.parentType.modelName) { + if (propertyMeta.parentType && propertyMeta.type === propertyMeta.parentType.modelName) { warn(`Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at http://emberjs.com/guides/models/defining-models/#toc_reflexive-relation for how to explicitly specify inverses.`, false, { id: 'ds.model.reflexive-relationship-without-inverse' }); @@ -1924,4 +1884,47 @@ if (isEnabled('ds-rollback-attribute')) { }); } +runInDebug(() => { + Model.reopen({ + /** + This Ember.js hook allows an object to be notified when a property + is defined. + + In this case, we use it to be notified when an Ember Data user defines a + belongs-to relationship. In that case, we need to set up observers for + each one, allowing us to track relationship changes and automatically + reflect changes in the inverse has-many array. + + This hook passes the class being set up, as well as the key and value + being defined. So, for example, when the user does this: + + ```javascript + DS.Model.extend({ + parent: DS.belongsTo('user') + }); + ``` + + This hook would be called with "parent" as the key and the computed + property returned by `DS.belongsTo` as the value. + + @method didDefineProperty + @param {Object} proto + @param {String} key + @param {Ember.ComputedProperty} value + */ + didDefineProperty(proto, key, value) { + // Check if the value being set is a computed property. + if (value instanceof Ember.ComputedProperty) { + + // If it is, get the metadata for the relationship. This is + // populated by the `DS.belongsTo` helper when it is creating + // the computed property. + let meta = value.meta(); + + meta.parentType = proto.constructor; + } + } + }) +}); + export default Model; diff --git a/addon/-private/system/relationship-meta.js b/addon/-private/system/relationship-meta.js index d1b00745fdd..8724fa7d361 100644 --- a/addon/-private/system/relationship-meta.js +++ b/addon/-private/system/relationship-meta.js @@ -1,5 +1,6 @@ import {singularize} from 'ember-inflector'; import normalizeModelName from './normalize-model-name'; +import { runInDebug } from 'ember-data/-private/debug'; export function typeForRelationshipMeta(meta) { let modelName; @@ -12,7 +13,7 @@ export function typeForRelationshipMeta(meta) { } export function relationshipFromMeta(meta) { - return { + let result = { key: meta.key, kind: meta.kind, type: typeForRelationshipMeta(meta), @@ -21,4 +22,8 @@ export function relationshipFromMeta(meta) { parentType: meta.parentType, isRelationship: true }; + + runInDebug(() => result.parentType = meta.parentType); + + return result; } diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 152469606a4..d6c062a5303 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -51,10 +51,10 @@ export const relatedTypesDescriptor = Ember.computed(function() { meta.key = name; modelName = typeForRelationshipMeta(meta); - assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", modelName); + assert(`You specified a hasMany (${meta.type}) on ${meta.parentType} but ${meta.type} was not found.`, modelName); if (!types.includes(modelName)) { - assert("Trying to sideload " + name + " on " + this.toString() + " but the type doesn't exist.", !!modelName); + assert(`Trying to sideload ${name} on ${this.toString()} but the type doesn't exist.`, !!modelName); types.push(modelName); } } From 214fba0019752a141b8539428960266b5f8ce96e Mon Sep 17 00:00:00 2001 From: Kelly Miyashiro Date: Fri, 14 Apr 2017 14:58:44 -0700 Subject: [PATCH 1896/2527] [DOC release] Add missing ` in urlsForFindMany description --- addon/-private/adapters/build-url-mixin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index 7b5433ffe3b..bd3de1ce3e1 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -214,7 +214,7 @@ export default Ember.Mixin.create({ }, /** - Builds a URL for coalesceing multiple `store.findRecord(type, id) + Builds a URL for coalesceing multiple `store.findRecord(type, id)` records into 1 request when the adapter's `coalesceFindRequests` property is true. From 8ccd35b317db2a32794510e46a935ded14c94a09 Mon Sep 17 00:00:00 2001 From: Krati Ahuja Date: Sat, 15 Apr 2017 13:50:19 -0700 Subject: [PATCH 1897/2527] Don't use `let` or `const` It is breaking `ember-cli-fastboot` tests. --- lib/transforms/babel-plugin-remove-imports.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/transforms/babel-plugin-remove-imports.js b/lib/transforms/babel-plugin-remove-imports.js index 8cff6d51079..39838498e58 100644 --- a/lib/transforms/babel-plugin-remove-imports.js +++ b/lib/transforms/babel-plugin-remove-imports.js @@ -1,8 +1,8 @@ var path = require('path'); function removeImports() { - let importDeclarationsToRemove; - let filteredImports; + var importDeclarationsToRemove; + var filteredImports; return { name: 'remove-filtered-imports', @@ -22,7 +22,7 @@ function removeImports() { }, ImportDeclaration: function(path) { - const name = path.node.source.value; + var name = path.node.source.value; if (filteredImports.indexOf(name) !== -1) { importDeclarationsToRemove.push(path); From 76f16a1971723026794e2ab7b80c7167bbf05a7f Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 17 Apr 2017 20:27:15 -0700 Subject: [PATCH 1898/2527] Remove no-longer-working private API usage. [fixes #3936] --- addon/-private/system/relationships/ext.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index d6c062a5303..56148b39e2a 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -64,10 +64,6 @@ export const relatedTypesDescriptor = Ember.computed(function() { }).readOnly(); export const relationshipsByNameDescriptor = Ember.computed(function() { - if (Ember.testing === true && relationshipsByNameDescriptor._cacheable === true) { - relationshipsByNameDescriptor._cacheable = false; - } - let map = Map.create(); this.eachComputedProperty((name, meta) => { From f5e9d622f8ab3d7e38f3cb908e2026e3f6a2917f Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 17 Apr 2017 21:03:46 -0700 Subject: [PATCH 1899/2527] [BUGFIX beta] [fixes #4509] createRecord initializes correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * by the name Model.prototype.init is called, internal model’s data has been loaded * do no emit extra change events during `createRecord` as the attributes are the initial state. --- addon/-private/system/model/internal-model.js | 6 +++++- addon/-private/system/store.js | 10 +-------- tests/unit/model-test.js | 21 +++++++++++++++++++ 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 0d1c8168491..3fdf3d0bd0d 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -319,7 +319,7 @@ export default class InternalModel { return this.currentState.dirtyType; } - getRecord() { + getRecord(properties) { if (!this._record && !this._isDematerializing) { heimdall.increment(materializeRecord); let token = heimdall.start('InternalModel.getRecord'); @@ -335,6 +335,10 @@ export default class InternalModel { adapterError: this.error }; + if (typeof properties === 'object' && properties !== null) { + assign(createOptions, properties); + } + if (setOwner) { // ensure that `getOwner(this)` works inside a model instance setOwner(createOptions, getOwner(this.store)); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index f897e518f23..2ac7e41cdfb 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -365,16 +365,8 @@ Store = Service.extend({ properties.id = coerceId(properties.id); let internalModel = this._buildInternalModel(normalizedModelName, properties.id); - let record = internalModel.getRecord(); - - // Move the record out of its initial `empty` state into - // the `loaded` state. - // TODO @runspired this seems really bad, store should not be changing the state internalModel.loadedData(); - - // Set the properties specified on the record. - // TODO @runspired this is probably why we do the bad thing above - record.setProperties(properties); + let record = internalModel.getRecord(properties); // TODO @runspired this should also be coalesced into some form of internalModel.setState() internalModel.eachRelationship((key, descriptor) => { diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index e3c92e6ff97..297412539a7 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -1329,6 +1329,27 @@ test('toJSON looks up the JSONSerializer using the store instead of using JSONSe assert.deepEqual(json, {}); }); +test('internalModel is ready by `init`', function(assert) { + assert.expect(2); + let nameDidChange = 0; + + const Person = DS.Model.extend({ + name: DS.attr('string'), + + init() { + this._super(...arguments); + this.set('name', 'my-name-set-in-init'); + }, + + nameDidChange: Ember.observer('name', () => nameDidChange++) + }); + + let { store } = setupStore({ person: Person }); + + assert.equal(nameDidChange, 0, 'observer should not trigger on create'); + let person = run(() => store.createRecord('person')); + assert.equal(person.get('name'), 'my-name-set-in-init'); +}); test('accessing attributes in the initializer should not throw an error', function(assert) { assert.expect(1); From b9810d724b46c7efb32b2a2bab70018404d24211 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 18 Apr 2017 13:21:57 -0700 Subject: [PATCH 1900/2527] update yarn.lock --- yarn.lock | 532 +++++++++++++++++++++++++----------------------------- 1 file changed, 247 insertions(+), 285 deletions(-) diff --git a/yarn.lock b/yarn.lock index d3283e4a174..418c5146db0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1,5 +1,7 @@ # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 + + "@types/node@*", "@types/node@^7.0.5": version "7.0.12" resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.12.tgz#ae5f67a19c15f752148004db07cbbb372e69efc9" @@ -24,7 +26,7 @@ abbrev@1: version "1.1.0" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" -accepts@~1.3.3, accepts@1.3.3: +accepts@1.3.3, accepts@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" dependencies: @@ -37,18 +39,14 @@ acorn-jsx@^3.0.0: dependencies: acorn "^3.0.4" +acorn@4.0.4, acorn@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" + acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" -acorn@^4.0.3: - version "4.0.11" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0" - -acorn@4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" - adm-zip@^0.4.7: version "0.4.7" resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" @@ -196,13 +194,17 @@ arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" +asn1@0.1.11: + version "0.1.11" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" + asn1@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" -asn1@0.1.11: - version "0.1.11" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" assert-plus@^0.1.5: version "0.1.5" @@ -212,10 +214,6 @@ assert-plus@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" -assert-plus@^1.0.0, assert-plus@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - assertion-error@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" @@ -1098,29 +1096,29 @@ broccoli-builder@^0.18.3: rsvp "^3.0.17" silent-error "^1.0.1" -broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" +broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" + lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - walk-sync "^0.2.5" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" -broccoli-caching-writer@~2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" +broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" - lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - symlink-or-copy "^1.0.0" - walk-sync "^0.2.0" + walk-sync "^0.2.5" broccoli-clean-css@^1.1.0: version "1.1.0" @@ -1295,23 +1293,23 @@ broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-p symlink-or-copy "^1.0.1" walk-sync "^0.3.1" -broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" +broccoli-plugin@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" rimraf "^2.3.4" - symlink-or-copy "^1.1.8" + symlink-or-copy "^1.0.1" -broccoli-plugin@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" +broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" rimraf "^2.3.4" - symlink-or-copy "^1.0.1" + symlink-or-copy "^1.1.8" broccoli-slow-trees@^3.0.1: version "3.0.1" @@ -1589,12 +1587,6 @@ cli-spinners@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" -cli-table@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" - dependencies: - colors "1.0.3" - cli-table2@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" @@ -1604,6 +1596,12 @@ cli-table2@^0.2.0: optionalDependencies: colors "^1.1.2" +cli-table@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + dependencies: + colors "1.0.3" + cli-width@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" @@ -1640,6 +1638,10 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" +colors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + colors@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" @@ -1648,10 +1650,6 @@ colors@~0.6.0-1: version "0.6.2" resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" -colors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" @@ -1664,16 +1662,6 @@ combined-stream@~0.0.4: dependencies: delayed-stream "0.0.5" -commander@^2.5.0, commander@^2.6.0, commander@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" - dependencies: - graceful-readlink ">= 1.0.0" - -commander@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" - commander@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" @@ -1688,6 +1676,16 @@ commander@2.8.x: dependencies: graceful-readlink ">= 1.0.0" +commander@^2.5.0, commander@^2.6.0, commander@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +commander@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" + commoner@~0.10.3: version "0.10.8" resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" @@ -1739,15 +1737,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.6, concat-stream@^1.4.7: - version "1.6.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" - dependencies: - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -concat-stream@1.5.0: +concat-stream@1.5.0, concat-stream@^1.4.6, concat-stream@^1.4.7: version "1.5.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" dependencies: @@ -1878,22 +1868,16 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" - dependencies: - ms "0.7.2" +debug@0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" -debug@~2.2.0, debug@2.2.0: +debug@2.2.0, debug@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" dependencies: ms "0.7.1" -debug@0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" - debug@2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" @@ -1906,6 +1890,12 @@ debug@2.6.1: dependencies: ms "0.7.2" +debug@2.6.3, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" + dependencies: + ms "0.7.2" + decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -1951,19 +1941,19 @@ del@^2.0.2: pinkie-promise "^2.0.0" rimraf "^2.2.8" -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - delayed-stream@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" -depd@~1.1.0, depd@1.1.0: +depd@1.1.0, depd@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" @@ -1998,7 +1988,7 @@ detective@^4.3.1: acorn "^4.0.3" defined "^1.0.0" -diff@^1.3.1, diff@1.4.0: +diff@1.4.0, diff@^1.3.1: version "1.4.0" resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" @@ -2597,7 +2587,7 @@ es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: es6-iterator "2" es6-symbol "~3.1" -es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@2: +es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" dependencies: @@ -2630,7 +2620,7 @@ es6-set@~0.1.5: es6-symbol "3.1.1" event-emitter "~0.3.5" -es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1, es6-symbol@3.1.1: +es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" dependencies: @@ -2650,14 +2640,14 @@ escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" -escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - escape-string-regexp@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" +escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + escope@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" @@ -3081,6 +3071,13 @@ fs-exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" +fs-extra@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.0.0.tgz#337352bded4a0b714f3eb84de8cea765e9d37600" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + fs-extra@^0.24.0: version "0.24.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" @@ -3118,13 +3115,6 @@ fs-extra@^1.0.0, fs-extra@~1.0.0: jsonfile "^2.1.0" klaw "^1.0.0" -fs-extra@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.0.0.tgz#337352bded4a0b714f3eb84de8cea765e9d37600" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - fs-readdir-recursive@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" @@ -3232,26 +3222,25 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@^4.3.2: - version "4.5.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" +glob@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" dependencies: - inflight "^1.0.4" + graceful-fs "~2.0.0" inherits "2" - minimatch "^2.0.1" - once "^1.3.0" + minimatch "~0.2.11" -glob@^5.0.10, glob@^5.0.15: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" +glob@5.0.13, glob@^5.0.10: + version "5.0.13" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" dependencies: inflight "^1.0.4" inherits "2" - minimatch "2 || 3" + minimatch "^2.0.1" once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@7.1.1: +glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: @@ -3262,21 +3251,22 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, gl once "^1.3.0" path-is-absolute "^1.0.0" -glob@3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" +glob@^4.3.2: + version "4.5.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" dependencies: - graceful-fs "~2.0.0" + inflight "^1.0.4" inherits "2" - minimatch "~0.2.11" + minimatch "^2.0.1" + once "^1.3.0" -glob@5.0.13: - version "5.0.13" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" +glob@^5.0.15: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: inflight "^1.0.4" inherits "2" - minimatch "^2.0.1" + minimatch "2 || 3" once "^1.3.0" path-is-absolute "^1.0.0" @@ -3402,15 +3392,6 @@ hasha@~2.2.0: is-stream "^1.0.1" pinkie-promise "^2.0.0" -hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - hawk@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" @@ -3420,6 +3401,15 @@ hawk@1.1.1: hoek "0.9.x" sntp "0.2.x" +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + heimdall-query@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" @@ -3526,7 +3516,7 @@ http-signature@~1.1.0: jsprim "^1.2.2" sshpk "^1.7.0" -iconv-lite@^0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13, iconv-lite@0.4.15: +iconv-lite@0.4.15, iconv-lite@^0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" @@ -3561,7 +3551,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@2, inherits@2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -3678,14 +3668,14 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" -is-git-url@^0.2.0: - version "0.2.3" - resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-0.2.3.tgz#445200d6fbd6da028fb5e01440d9afc93f3ccb64" - is-git-url@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-0.2.0.tgz#b9ce0fb044821c88880213d602db03bdb255da1b" +is-git-url@^0.2.0: + version "0.2.3" + resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-0.2.3.tgz#445200d6fbd6da028fb5e01440d9afc93f3ccb64" + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -3777,14 +3767,14 @@ is-windows@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" -isarray@^1.0.0, isarray@~1.0.0, isarray@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + isbinaryfile@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" @@ -3836,14 +3826,14 @@ js-string-escape@^1.0.0, js-string-escape@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" -js-tokens@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" - js-tokens@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" +js-tokens@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" + js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: version "3.8.2" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.2.tgz#02d3e2c0f6beab20248d412c352203827d786721" @@ -4220,6 +4210,10 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0" +lru-cache@2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + lru-cache@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" @@ -4227,10 +4221,6 @@ lru-cache@^4.0.1: pseudomap "^1.0.1" yallist "^2.0.0" -lru-cache@2: - version "2.7.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" - make-array@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" @@ -4349,7 +4339,7 @@ mime-types@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" -mime@^1.2.11, mime@1.3.4: +mime@1.3.4, mime@^1.2.11: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" @@ -4357,15 +4347,15 @@ mime@~1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" -minimatch@^2.0.1, minimatch@^2.0.3, minimatch@^2.0.8: - version "2.0.10" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" dependencies: brace-expansion "^1.0.0" -minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, "minimatch@2 || 3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" +minimatch@^2.0.1, minimatch@^2.0.3, minimatch@^2.0.8: + version "2.0.10" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" dependencies: brace-expansion "^1.0.0" @@ -4376,23 +4366,13 @@ minimatch@~0.2.11: lru-cache "2" sigmund "~1.0.0" -minimist@^1.1.0, minimist@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - -minimist@~0.0.1: - version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - -minimist@0.0.8: +minimist@0.0.8, minimist@~0.0.1: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@0.5.1, mkdirp@0.5.x: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" +minimist@^1.1.0, minimist@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" mkdirp@0.3.0: version "0.3.0" @@ -4404,6 +4384,12 @@ mkdirp@0.5.0: dependencies: minimist "0.0.8" +mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + mktemp@^0.4.0, mktemp@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" @@ -4570,14 +4556,14 @@ oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@^4.0.1, object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - object-assign@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" @@ -4830,13 +4816,6 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -pretender@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.4.2.tgz#dde9995dfdf75b28a3dd7a73cde2f9f612e5e8f4" - dependencies: - fake-xml-http-request "^1.4.0" - route-recognizer "^0.2.3" - pretender@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.0.0.tgz#9137c38718b4d89814478b7f208f70d3e441a0e9" @@ -4844,6 +4823,13 @@ pretender@1.0.0: fake-xml-http-request "^1.3.0" route-recognizer "^0.1.9" +pretender@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.4.2.tgz#dde9995dfdf75b28a3dd7a73cde2f9f612e5e8f4" + dependencies: + fake-xml-http-request "^1.4.0" + route-recognizer "^0.2.3" + printf@^0.2.3: version "0.2.5" resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" @@ -4883,19 +4869,19 @@ pseudomap@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + q@^1.1.2: version "1.5.0" resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" -qs@^6.2.0, qs@6.4.0: +qs@6.4.0, qs@^6.2.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" @@ -4911,15 +4897,7 @@ querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" -quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5: - version "0.1.8" - resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" - dependencies: - mktemp "~0.4.0" - rimraf "^2.5.4" - underscore.string "~3.3.4" - -quick-temp@0.1.6: +quick-temp@0.1.6, quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5: version "0.1.6" resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.6.tgz#a6242a15cba9f9cdbd341287b5c569e318eec307" dependencies: @@ -4976,7 +4954,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^2, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.2.2: +readable-stream@^2, "readable-stream@^2.0.0 || ^1.1.13": version "2.2.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.6.tgz#8b43aed76e71483938d12a8d46c6cf1a00b1f816" dependencies: @@ -5016,6 +4994,15 @@ readline2@^1.0.1: is-fullwidth-code-point "^1.0.0" mute-stream "0.0.5" +recast@0.10.33: + version "0.10.33" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" + dependencies: + ast-types "0.8.12" + esprima-fb "~15001.1001.0-dev-harmony-fb" + private "~0.1.5" + source-map "~0.5.0" + recast@^0.10.10, recast@^0.10.29: version "0.10.43" resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" @@ -5034,15 +5021,6 @@ recast@^0.11.17, recast@^0.11.3: private "~0.1.5" source-map "~0.5.0" -recast@0.10.33: - version "0.10.33" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" - dependencies: - ast-types "0.8.12" - esprima-fb "~15001.1001.0-dev-harmony-fb" - private "~0.1.5" - source-map "~0.5.0" - redeyed@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-0.5.0.tgz#7ab000e60ee3875ac115d29edb32c1403c6c25d1" @@ -5230,7 +5208,13 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4: +rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" + dependencies: + glob "^7.0.0" + +rimraf@^2.1.4, rimraf@^2.5.3, rimraf@^2.5.4: version "2.6.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: @@ -5240,12 +5224,6 @@ rimraf@~2.2.6: version "2.2.8" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" -rimraf@2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" - dependencies: - glob "^7.0.0" - route-recognizer@^0.1.9: version "0.1.11" resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" @@ -5254,7 +5232,11 @@ route-recognizer@^0.2.3: version "0.2.10" resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" -rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: +rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.6, rsvp@~3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + +rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: version "3.5.0" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" @@ -5266,10 +5248,6 @@ rsvp@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" -rsvp@~3.2.1, rsvp@3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" - run-async@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" @@ -5306,11 +5284,7 @@ sane@^1.1.1: walker "~1.0.5" watch "~0.10.0" -sax@>=0.6.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828" - -sax@1.1.5: +sax@1.1.5, sax@>=0.6.0: version "1.1.5" resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.5.tgz#1da50a8d00cdecd59405659f5ff85349fe773743" @@ -5323,14 +5297,14 @@ selenium-webdriver@^3.0.0-beta-2: tmp "0.0.30" xml2js "^0.4.17" +"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + semver@^4.1.0, semver@^4.3.1: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" -semver@^5.1.0, semver@^5.1.1, semver@^5.3.0, "semver@2 || 3 || 4 || 5": - version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - send@0.15.1: version "0.15.1" resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" @@ -5504,7 +5478,13 @@ source-map-url@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" -source-map@^0.4.2, source-map@^0.4.4, source-map@0.4.x: +source-map@0.1.32: + version "0.1.32" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" + dependencies: + amdefine ">=0.0.4" + +source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: @@ -5514,12 +5494,6 @@ source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: version "0.5.6" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" -source-map@0.1.32: - version "0.1.32" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" - dependencies: - amdefine ">=0.0.4" - spawn-args@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" @@ -5549,7 +5523,7 @@ spdx-license-ids@^1.0.2: version "1.2.2" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" -sprintf-js@^1.0.3, sprintf-js@~1.0.2: +sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -5580,10 +5554,6 @@ stable@~0.1.3: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" -string_decoder@~0.10.x, string_decoder@0.10: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - string-template@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" @@ -5603,6 +5573,10 @@ string-width@^2.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^3.0.0" +string_decoder@0.10, string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + stringmap@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" @@ -5651,6 +5625,10 @@ sum-up@^1.0.1: dependencies: chalk "^1.0.0" +supports-color@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" + supports-color@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" @@ -5659,10 +5637,6 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -supports-color@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" - symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" @@ -5762,12 +5736,6 @@ tmp-sync@^1.0.0: fs-sync "^1.0.4" osenv "^0.1.0" -tmp@^0.0.29: - version "0.0.29" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" - dependencies: - os-tmpdir "~1.0.1" - tmp@0.0.28: version "0.0.28" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" @@ -5780,6 +5748,12 @@ tmp@0.0.30: dependencies: os-tmpdir "~1.0.1" +tmp@^0.0.29: + version "0.0.29" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" + dependencies: + os-tmpdir "~1.0.1" + tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -5838,14 +5812,14 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-detect@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" - type-detect@0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" +type-detect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" + type-is@~1.6.14: version "1.6.14" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" @@ -5853,7 +5827,7 @@ type-is@~1.6.14: media-typer "0.3.0" mime-types "~2.1.13" -typedarray@^0.0.6, typedarray@~0.0.5: +typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -5882,18 +5856,11 @@ underscore.string@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" -underscore.string@~3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" - dependencies: - sprintf-js "^1.0.3" - util-deprecate "^1.0.2" - underscore@>=1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" -unpipe@~1.0.0, unpipe@1.0.0: +unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -5920,7 +5887,7 @@ user-home@^2.0.0: dependencies: os-homedir "^1.0.0" -util-deprecate@^1.0.2, util-deprecate@~1.0.1: +util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -5928,6 +5895,10 @@ utils-merge@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" +uuid@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" + uuid@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" @@ -5936,10 +5907,6 @@ uuid@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" -uuid@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" - validate-npm-package-license@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" @@ -6011,6 +5978,10 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.1" +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + window-size@^0.1.2: version "0.1.4" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" @@ -6019,9 +5990,9 @@ window-size@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" wordwrap@~0.0.2: version "0.0.3" @@ -6031,10 +6002,6 @@ wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -6060,16 +6027,16 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" -ws@^1.0.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" +ws@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" dependencies: options ">=0.0.5" ultron "1.0.x" -ws@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" +ws@^1.0.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" dependencies: options ">=0.0.5" ultron "1.0.x" @@ -6084,6 +6051,13 @@ xdg-basedir@^2.0.0: dependencies: os-homedir "^1.0.0" +xml2js@0.4.15: + version "0.4.15" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.15.tgz#95cd03ff2dd144ec28bc6273bf2b2890c581ad0c" + dependencies: + sax ">=0.6.0" + xmlbuilder ">=2.4.6" + xml2js@^0.4.17: version "0.4.17" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" @@ -6091,12 +6065,11 @@ xml2js@^0.4.17: sax ">=0.6.0" xmlbuilder "^4.1.0" -xml2js@0.4.15: - version "0.4.15" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.15.tgz#95cd03ff2dd144ec28bc6273bf2b2890c581ad0c" +xmlbuilder@2.6.2, xmlbuilder@>=2.4.6: + version "2.6.2" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-2.6.2.tgz#f916f6d10d45dc171b1be2e6e673fb6e0cc35d0a" dependencies: - sax ">=0.6.0" - xmlbuilder ">=2.4.6" + lodash "~3.5.0" xmlbuilder@^4.1.0: version "4.2.1" @@ -6104,16 +6077,6 @@ xmlbuilder@^4.1.0: dependencies: lodash "^4.0.0" -xmlbuilder@>=2.4.6: - version "8.2.2" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773" - -xmlbuilder@2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-2.6.2.tgz#f916f6d10d45dc171b1be2e6e673fb6e0cc35d0a" - dependencies: - lodash "~3.5.0" - xmldom@^0.1.19: version "0.1.27" resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" @@ -6214,4 +6177,3 @@ yuidocjs@~0.9.0: minimatch "^2.0.8" rimraf "^2.4.1" yui "^3.18.1" - From 73f32a833a56d986264c2ddd748334f20417ef9f Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 19 Apr 2017 21:23:56 -0700 Subject: [PATCH 1901/2527] bump github module slightly to work around node-resolve issue (removes about 800ms from ember-cli startup time) actual upstream issue: https://github.com/substack/node-resolve/issues/125 actual upstream PR: https://github.com/substack/node-resolve/pull/126 But we should upgrade anyways. --- package.json | 2 +- yarn.lock | 2445 ++++++++++++++++++++++++++------------------------ 2 files changed, 1250 insertions(+), 1197 deletions(-) diff --git a/package.json b/package.json index dbc0fccb26d..f52a65bb790 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "ember-watson": "^0.7.0", "express": "^4.14.0", "faker": "^3.1.0", - "github": "^0.2.4", + "github": "^1.1.1", "glob": "5.0.13", "heimdall-query": "^0.0.5", "json-api-mock-server": "0.1.1", diff --git a/yarn.lock b/yarn.lock index 418c5146db0..a8b1dc89cd4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,72 +3,83 @@ "@types/node@*", "@types/node@^7.0.5": - version "7.0.12" - resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.12.tgz#ae5f67a19c15f752148004db07cbbb372e69efc9" + version "7.0.13" + resolved "https://registry.npmjs.org/@types/node/-/node-7.0.13.tgz#1b0a53fe9ef9c3a5d061b126cc9b915bca43a3f5" "@types/rimraf@^0.0.28": version "0.0.28" - resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06" + resolved "https://registry.npmjs.org/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06" "@types/tape@^4.2.29": version "4.2.29" - resolved "https://registry.yarnpkg.com/@types/tape/-/tape-4.2.29.tgz#14cf2eb49bf852407eaaefdc53773eb90b32cf56" + resolved "https://registry.npmjs.org/@types/tape/-/tape-4.2.29.tgz#14cf2eb49bf852407eaaefdc53773eb90b32cf56" dependencies: "@types/node" "*" "@types/ws@^0.0.38": version "0.0.38" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-0.0.38.tgz#42106fff4b422ca956734e29f0d73a6d893194d3" + resolved "https://registry.npmjs.org/@types/ws/-/ws-0.0.38.tgz#42106fff4b422ca956734e29f0d73a6d893194d3" dependencies: "@types/node" "*" abbrev@1: version "1.1.0" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" accepts@1.3.3, accepts@~1.3.3: version "1.3.3" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" dependencies: mime-types "~2.1.11" negotiator "0.6.1" acorn-jsx@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" dependencies: acorn "^3.0.4" -acorn@4.0.4, acorn@^4.0.3: - version "4.0.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" - acorn@^3.0.4: version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + resolved "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^4.0.3: + version "4.0.11" + resolved "https://registry.npmjs.org/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0" + +acorn@^5.0.1: + version "5.0.3" + resolved "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d" adm-zip@^0.4.7: version "0.4.7" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" + resolved "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" after@0.8.1: version "0.8.1" - resolved "https://registry.yarnpkg.com/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" + resolved "https://registry.npmjs.org/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" + +agent-base@2: + version "2.0.1" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz#bd8f9e86a8eb221fffa07bd14befd55df142815e" + dependencies: + extend "~3.0.0" + semver "~5.0.1" ajv-keywords@^1.0.0: version "1.5.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" + resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" ajv@^4.1.3, ajv@^4.7.0: - version "4.11.5" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd" + version "4.11.7" + resolved "https://registry.npmjs.org/ajv/-/ajv-4.11.7.tgz#8655a5d86d0824985cc471a1d913fb6729a0ec48" dependencies: co "^4.6.0" json-stable-stringify "^1.0.1" align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" - resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + resolved "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" dependencies: kind-of "^3.0.2" longest "^1.0.1" @@ -76,167 +87,167 @@ align-text@^0.1.1, align-text@^0.1.3: alter@~0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" + resolved "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" dependencies: stable "~0.1.3" amd-name-resolver@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-0.0.5.tgz#76962dac876ed3311b05d29c6a58c14e1ef3304b" + resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.5.tgz#76962dac876ed3311b05d29c6a58c14e1ef3304b" dependencies: ensure-posix-path "^1.0.1" amd-name-resolver@0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-0.0.6.tgz#d3e4ba2dfcaab1d820c1be9de947c67828cfe595" + resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.6.tgz#d3e4ba2dfcaab1d820c1be9de947c67828cfe595" dependencies: ensure-posix-path "^1.0.1" amdefine@>=0.0.4: version "1.0.1" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" ansi-escapes@^1.1.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" ansi-regex@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" ansi-styles@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" ansi-styles@^2.1.0, ansi-styles@^2.2.1: version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" ansicolors@~0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" + resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" anymatch@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" dependencies: arrify "^1.0.0" micromatch "^2.1.5" aproba@^1.0.3: version "1.1.1" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" are-we-there-yet@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" dependencies: delegates "^1.0.0" readable-stream "^2.0.0 || ^1.1.13" argparse@^1.0.7, argparse@~1.0.2: version "1.0.9" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" dependencies: sprintf-js "~1.0.2" arr-diff@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" dependencies: arr-flatten "^1.0.1" arr-flatten@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + version "1.0.3" + resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.3.tgz#a274ed85ac08849b6bd7847c4580745dc51adfb1" array-equal@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + resolved "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" array-flatten@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" array-to-error@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" + resolved "https://registry.npmjs.org/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" dependencies: array-to-sentence "^1.1.0" array-to-sentence@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" + resolved "https://registry.npmjs.org/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" array-union@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" dependencies: array-uniq "^1.0.1" array-uniq@^1.0.1: version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" array-unique@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" arraybuffer.slice@0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" + resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" arrify@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" asn1@0.1.11: version "0.1.11" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" asn1@~0.2.3: version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" assert-plus@^0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" assert-plus@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" assertion-error@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" + resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" ast-traverse@~0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" + resolved "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" ast-types@0.8.12: version "0.8.12" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" ast-types@0.8.15: version "0.8.15" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" ast-types@0.9.6: version "0.9.6" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" async-disk-cache@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.2.2.tgz#3a1ba85e87e28da4200c7fe22643210e28a280fb" + version "1.3.1" + resolved "https://registry.npmjs.org/async-disk-cache/-/async-disk-cache-1.3.1.tgz#3394010d9448b16205b01e0e2e704180805413d3" dependencies: debug "^2.1.3" heimdalljs "^0.2.3" @@ -247,49 +258,49 @@ async-disk-cache@^1.0.0: async@^1.4.0, async@^1.5.2: version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" async@~0.2.9: version "0.2.10" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + resolved "https://registry.npmjs.org/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" async@~0.9.0: version "0.9.2" - resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" aws-sdk@^2.0.9: - version "2.32.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.32.0.tgz#9fe278b2ec1b12fddd1afeb74439581cdc2e5990" + version "2.43.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.43.0.tgz#a5f38099c2e279414e7e09f69719a542d816bdba" dependencies: buffer "4.9.1" crypto-browserify "1.0.9" jmespath "0.15.0" querystring "0.2.0" - sax "1.1.5" + sax "1.2.1" url "0.10.3" - uuid "3.0.0" - xml2js "0.4.15" - xmlbuilder "2.6.2" + uuid "3.0.1" + xml2js "0.4.17" + xmlbuilder "4.2.1" aws-sign2@~0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" aws-sign2@~0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" aws4@^1.2.1: version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + resolved "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" babel-code-frame@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" + resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" dependencies: chalk "^1.1.0" esutils "^2.0.2" @@ -297,7 +308,7 @@ babel-code-frame@^6.22.0: babel-core@^5.0.0, babel-core@^5.8.22: version "5.8.38" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" + resolved "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" dependencies: babel-plugin-constant-folding "^1.0.1" babel-plugin-dead-code-elimination "^1.0.2" @@ -346,19 +357,19 @@ babel-core@^5.0.0, babel-core@^5.8.22: trim-right "^1.0.0" try-resolve "^1.0.0" -babel-core@^6.14.0, babel-core@^6.24.0: - version "6.24.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.0.tgz#8f36a0a77f5c155aed6f920b844d23ba56742a02" +babel-core@^6.14.0, babel-core@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-core/-/babel-core-6.24.1.tgz#8c428564dce1e1f41fb337ec34f4c3b022b5ad83" dependencies: babel-code-frame "^6.22.0" - babel-generator "^6.24.0" - babel-helpers "^6.23.0" + babel-generator "^6.24.1" + babel-helpers "^6.24.1" babel-messages "^6.23.0" - babel-register "^6.24.0" + babel-register "^6.24.1" babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-traverse "^6.23.1" - babel-types "^6.23.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" babylon "^6.11.0" convert-source-map "^1.1.0" debug "^2.1.1" @@ -370,434 +381,434 @@ babel-core@^6.14.0, babel-core@^6.24.0: slash "^1.0.0" source-map "^0.5.0" -babel-generator@^6.24.0: - version "6.24.0" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.0.tgz#eba270a8cc4ce6e09a61be43465d7c62c1f87c56" +babel-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-generator/-/babel-generator-6.24.1.tgz#e715f486c58ded25649d888944d52aa07c5d9497" dependencies: babel-messages "^6.23.0" babel-runtime "^6.22.0" - babel-types "^6.23.0" + babel-types "^6.24.1" detect-indent "^4.0.0" jsesc "^1.3.0" lodash "^4.2.0" source-map "^0.5.0" trim-right "^1.0.1" -babel-helper-builder-binary-assignment-operator-visitor@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.22.0.tgz#29df56be144d81bdeac08262bfa41d2c5e91cdcd" +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" dependencies: - babel-helper-explode-assignable-expression "^6.22.0" + babel-helper-explode-assignable-expression "^6.24.1" babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" -babel-helper-call-delegate@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.22.0.tgz#119921b56120f17e9dae3f74b4f5cc7bcc1b37ef" +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" dependencies: - babel-helper-hoist-variables "^6.22.0" + babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" - babel-traverse "^6.22.0" - babel-types "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" -babel-helper-define-map@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.23.0.tgz#1444f960c9691d69a2ced6a205315f8fd00804e7" +babel-helper-define-map@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.24.1.tgz#7a9747f258d8947d32d515f6aa1c7bd02204a080" dependencies: - babel-helper-function-name "^6.23.0" + babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" - babel-types "^6.23.0" + babel-types "^6.24.1" lodash "^4.2.0" -babel-helper-explode-assignable-expression@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.22.0.tgz#c97bf76eed3e0bae4048121f2b9dae1a4e7d0478" +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" dependencies: babel-runtime "^6.22.0" - babel-traverse "^6.22.0" - babel-types "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" -babel-helper-function-name@^6.22.0, babel-helper-function-name@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.23.0.tgz#25742d67175c8903dbe4b6cb9d9e1fcb8dcf23a6" +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" dependencies: - babel-helper-get-function-arity "^6.22.0" + babel-helper-get-function-arity "^6.24.1" babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-traverse "^6.23.0" - babel-types "^6.23.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" -babel-helper-get-function-arity@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.22.0.tgz#0beb464ad69dc7347410ac6ade9f03a50634f5ce" +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" dependencies: babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" -babel-helper-hoist-variables@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.22.0.tgz#3eacbf731d80705845dd2e9718f600cfb9b4ba72" +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" dependencies: babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" -babel-helper-optimise-call-expression@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.23.0.tgz#f3ee7eed355b4282138b33d02b78369e470622f5" +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" dependencies: babel-runtime "^6.22.0" - babel-types "^6.23.0" + babel-types "^6.24.1" -babel-helper-regex@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.22.0.tgz#79f532be1647b1f0ee3474b5f5c3da58001d247d" +babel-helper-regex@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.24.1.tgz#d36e22fab1008d79d88648e32116868128456ce8" dependencies: babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" lodash "^4.2.0" -babel-helper-remap-async-to-generator@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.22.0.tgz#2186ae73278ed03b8b15ced089609da981053383" +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" dependencies: - babel-helper-function-name "^6.22.0" + babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" - babel-template "^6.22.0" - babel-traverse "^6.22.0" - babel-types "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" -babel-helper-replace-supers@^6.22.0, babel-helper-replace-supers@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.23.0.tgz#eeaf8ad9b58ec4337ca94223bacdca1f8d9b4bfd" +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" dependencies: - babel-helper-optimise-call-expression "^6.23.0" + babel-helper-optimise-call-expression "^6.24.1" babel-messages "^6.23.0" babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-traverse "^6.23.0" - babel-types "^6.23.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" -babel-helpers@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.23.0.tgz#4f8f2e092d0b6a8808a4bde79c27f1e2ecf0d992" +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" dependencies: babel-runtime "^6.22.0" - babel-template "^6.23.0" + babel-template "^6.24.1" babel-messages@^6.23.0: version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + resolved "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" dependencies: babel-runtime "^6.22.0" babel-plugin-check-es2015-constants@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + resolved "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" dependencies: babel-runtime "^6.22.0" babel-plugin-constant-folding@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" + resolved "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" babel-plugin-dead-code-elimination@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" + resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" babel-plugin-eval@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" + resolved "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" babel-plugin-feature-flags@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" + resolved "https://registry.npmjs.org/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" babel-plugin-filter-imports@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.3.1.tgz#e7859b56886b175dd2616425d277b219e209ea8b" + resolved "https://registry.npmjs.org/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.3.1.tgz#e7859b56886b175dd2616425d277b219e209ea8b" babel-plugin-htmlbars-inline-precompile@^0.2.3: version "0.2.3" - resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.3.tgz#cd365e278af409bfa6be7704c4354beee742446b" + resolved "https://registry.npmjs.org/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.3.tgz#cd365e278af409bfa6be7704c4354beee742446b" babel-plugin-inline-environment-variables@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" + resolved "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" babel-plugin-jscript@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" + resolved "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" babel-plugin-member-expression-literals@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" + resolved "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" babel-plugin-property-literals@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" + resolved "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" babel-plugin-proto-to-assign@^1.0.3: version "1.0.4" - resolved "https://registry.yarnpkg.com/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" + resolved "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" dependencies: lodash "^3.9.3" babel-plugin-react-constant-elements@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" + resolved "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" babel-plugin-react-display-name@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" + resolved "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" babel-plugin-remove-console@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" + resolved "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" babel-plugin-remove-debugger@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" + resolved "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" babel-plugin-runtime@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" + resolved "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + resolved "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + resolved "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + resolved "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" babel-plugin-transform-async-to-generator@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.22.0.tgz#194b6938ec195ad36efc4c33a971acf00d8cd35e" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" dependencies: - babel-helper-remap-async-to-generator "^6.22.0" + babel-helper-remap-async-to-generator "^6.24.1" babel-plugin-syntax-async-functions "^6.8.0" babel-runtime "^6.22.0" babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoping@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.23.0.tgz#e48895cf0b375be148cd7c8879b422707a053b51" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz#76c295dc3a4741b1665adfd3167215dcff32a576" dependencies: babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-traverse "^6.23.0" - babel-types "^6.23.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" lodash "^4.2.0" babel-plugin-transform-es2015-classes@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.23.0.tgz#49b53f326202a2fd1b3bbaa5e2edd8a4f78643c1" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" dependencies: - babel-helper-define-map "^6.23.0" - babel-helper-function-name "^6.23.0" - babel-helper-optimise-call-expression "^6.23.0" - babel-helper-replace-supers "^6.23.0" + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" babel-messages "^6.23.0" babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-traverse "^6.23.0" - babel-types "^6.23.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" babel-plugin-transform-es2015-computed-properties@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.22.0.tgz#7c383e9629bba4820c11b0425bdd6290f7f057e7" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" dependencies: babel-runtime "^6.22.0" - babel-template "^6.22.0" + babel-template "^6.24.1" babel-plugin-transform-es2015-constants@^6.1.4: version "6.1.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-constants/-/babel-plugin-transform-es2015-constants-6.1.4.tgz#e4b8c78fb48ab98b0107f329fab6040e79c35a33" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-constants/-/babel-plugin-transform-es2015-constants-6.1.4.tgz#e4b8c78fb48ab98b0107f329fab6040e79c35a33" dependencies: babel-runtime "^5.0.0" babel-plugin-transform-es2015-destructuring@^6.23.0: version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-duplicate-keys@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.22.0.tgz#672397031c21610d72dd2bbb0ba9fb6277e1c36b" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" dependencies: babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" babel-plugin-transform-es2015-for-of@^6.23.0: version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-function-name@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.22.0.tgz#f5fcc8b09093f9a23c76ac3d9e392c3ec4b77104" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" dependencies: - babel-helper-function-name "^6.22.0" + babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" babel-plugin-transform-es2015-literals@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.0: - version "6.24.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.0.tgz#a1911fb9b7ec7e05a43a63c5995007557bcf6a2e" +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" dependencies: - babel-plugin-transform-es2015-modules-commonjs "^6.24.0" + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" babel-runtime "^6.22.0" - babel-template "^6.22.0" + babel-template "^6.24.1" -babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.0: - version "6.24.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.0.tgz#e921aefb72c2cc26cb03d107626156413222134f" +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.1.tgz#d3e310b40ef664a36622200097c6d440298f2bfe" dependencies: - babel-plugin-transform-strict-mode "^6.22.0" + babel-plugin-transform-strict-mode "^6.24.1" babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-types "^6.23.0" + babel-template "^6.24.1" + babel-types "^6.24.1" babel-plugin-transform-es2015-modules-systemjs@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.23.0.tgz#ae3469227ffac39b0310d90fec73bfdc4f6317b0" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" dependencies: - babel-helper-hoist-variables "^6.22.0" + babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" - babel-template "^6.23.0" + babel-template "^6.24.1" babel-plugin-transform-es2015-modules-umd@^6.23.0: - version "6.24.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.0.tgz#fd5fa63521cae8d273927c3958afd7c067733450" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" dependencies: - babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-plugin-transform-es2015-modules-amd "^6.24.1" babel-runtime "^6.22.0" - babel-template "^6.23.0" + babel-template "^6.24.1" babel-plugin-transform-es2015-object-super@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.22.0.tgz#daa60e114a042ea769dd53fe528fc82311eb98fc" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" dependencies: - babel-helper-replace-supers "^6.22.0" + babel-helper-replace-supers "^6.24.1" babel-runtime "^6.22.0" babel-plugin-transform-es2015-parameters@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.23.0.tgz#3a2aabb70c8af945d5ce386f1a4250625a83ae3b" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" dependencies: - babel-helper-call-delegate "^6.22.0" - babel-helper-get-function-arity "^6.22.0" + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-traverse "^6.23.0" - babel-types "^6.23.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" babel-plugin-transform-es2015-shorthand-properties@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.22.0.tgz#8ba776e0affaa60bff21e921403b8a652a2ff723" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" dependencies: babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" babel-plugin-transform-es2015-spread@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-sticky-regex@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.22.0.tgz#ab316829e866ee3f4b9eb96939757d19a5bc4593" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" dependencies: - babel-helper-regex "^6.22.0" + babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" babel-plugin-transform-es2015-template-literals@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-typeof-symbol@^6.23.0: version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-unicode-regex@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.22.0.tgz#8d9cc27e7ee1decfe65454fb986452a04a613d20" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" dependencies: - babel-helper-regex "^6.22.0" + babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" regexpu-core "^2.0.0" babel-plugin-transform-exponentiation-operator@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.22.0.tgz#d57c8335281918e54ef053118ce6eb108468084d" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.22.0" + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" babel-plugin-syntax-exponentiation-operator "^6.8.0" babel-runtime "^6.22.0" babel-plugin-transform-regenerator@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.22.0.tgz#65740593a319c44522157538d690b84094617ea6" + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz#b8da305ad43c3c99b4848e4fe4037b770d23c418" dependencies: - regenerator-transform "0.9.8" + regenerator-transform "0.9.11" -babel-plugin-transform-strict-mode@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.22.0.tgz#e008df01340fdc87e959da65991b7e05970c8c7c" +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" dependencies: babel-runtime "^6.22.0" - babel-types "^6.22.0" + babel-types "^6.24.1" babel-plugin-undeclared-variables-check@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" + resolved "https://registry.npmjs.org/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" dependencies: leven "^1.0.2" babel-plugin-undefined-to-void@^1.1.6: version "1.1.6" - resolved "https://registry.yarnpkg.com/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" + resolved "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" babel-polyfill@^6.16.0: version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d" + resolved "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d" dependencies: babel-runtime "^6.22.0" core-js "^2.4.0" regenerator-runtime "^0.10.0" babel-preset-env@^1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.2.2.tgz#1dbc4d7f8a575691d301f45fa9b2f9698b1e3b92" + version "1.4.0" + resolved "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.4.0.tgz#c8e02a3bcc7792f23cded68e0355b9d4c28f0f7a" dependencies: babel-plugin-check-es2015-constants "^6.22.0" babel-plugin-syntax-trailing-function-commas "^6.22.0" @@ -827,14 +838,13 @@ babel-preset-env@^1.2.0: babel-plugin-transform-exponentiation-operator "^6.22.0" babel-plugin-transform-regenerator "^6.22.0" browserslist "^1.4.0" - electron-to-chromium "^1.2.6" invariant "^2.2.2" -babel-register@^6.24.0: - version "6.24.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.0.tgz#5e89f8463ba9970356d02eb07dabe3308b080cfd" +babel-register@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-register/-/babel-register-6.24.1.tgz#7e10e13a2f71065bdfad5a1787ba45bca6ded75f" dependencies: - babel-core "^6.24.0" + babel-core "^6.24.1" babel-runtime "^6.22.0" core-js "^2.4.0" home-or-tmp "^2.0.0" @@ -844,44 +854,44 @@ babel-register@^6.24.0: babel-runtime@^5.0.0: version "5.8.38" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-5.8.38.tgz#1c0b02eb63312f5f087ff20450827b425c9d4c19" + resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz#1c0b02eb63312f5f087ff20450827b425c9d4c19" dependencies: core-js "^1.0.0" babel-runtime@^6.18.0, babel-runtime@^6.22.0: version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" + resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" dependencies: core-js "^2.4.0" regenerator-runtime "^0.10.0" -babel-template@^6.22.0, babel-template@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638" +babel-template@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-template/-/babel-template-6.24.1.tgz#04ae514f1f93b3a2537f2a0f60a5a45fb8308333" dependencies: babel-runtime "^6.22.0" - babel-traverse "^6.23.0" - babel-types "^6.23.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" babylon "^6.11.0" lodash "^4.2.0" -babel-traverse@^6.22.0, babel-traverse@^6.23.0, babel-traverse@^6.23.1: - version "6.23.1" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.23.1.tgz#d3cb59010ecd06a97d81310065f966b699e14f48" +babel-traverse@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.24.1.tgz#ab36673fd356f9a0948659e7b338d5feadb31695" dependencies: babel-code-frame "^6.22.0" babel-messages "^6.23.0" babel-runtime "^6.22.0" - babel-types "^6.23.0" + babel-types "^6.24.1" babylon "^6.15.0" debug "^2.2.0" globals "^9.0.0" invariant "^2.2.0" lodash "^4.2.0" -babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.23.0.tgz#bb17179d7538bad38cd0c9e115d340f77e7e9acf" +babel-types@^6.19.0, babel-types@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-types/-/babel-types-6.24.1.tgz#a136879dc15b3606bda0d90c1fc74304c2ff0975" dependencies: babel-runtime "^6.22.0" esutils "^2.0.2" @@ -890,85 +900,85 @@ babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.23.0: babel6-plugin-strip-class-callcheck@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" + resolved "https://registry.npmjs.org/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" babel6-plugin-strip-heimdall@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" + resolved "https://registry.npmjs.org/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" babylon@^5.8.38: version "5.8.38" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" + resolved "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" babylon@^6.11.0, babylon@^6.15.0: version "6.16.1" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3" + resolved "https://registry.npmjs.org/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3" backbone@^1.1.2: version "1.3.3" - resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" + resolved "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" dependencies: underscore ">=1.8.3" backo2@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" balanced-match@^0.4.1: version "0.4.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" base64-arraybuffer@0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" base64-js@^1.0.2: version "1.2.0" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" base64id@0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" + resolved "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" basic-auth@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" + resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" bcrypt-pbkdf@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" dependencies: tweetnacl "^0.14.3" better-assert@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + resolved "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" dependencies: callsite "1.0.0" "binaryextensions@1 || 2": version "2.0.0" - resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.0.0.tgz#e597d1a7a6a3558a2d1c7241a16c99965e6aa40f" + resolved "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.0.0.tgz#e597d1a7a6a3558a2d1c7241a16c99965e6aa40f" blank-object@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" + resolved "https://registry.npmjs.org/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" blob@0.0.4: version "0.0.4" - resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" + resolved "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" bluebird@^2.9.33: version "2.11.0" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" bluebird@^3.1.1, bluebird@^3.4.6: version "3.5.0" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" body-parser@^1.15.2: version "1.17.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.17.1.tgz#75b3bc98ddd6e7e0d8ffe750dfaca5c66993fa47" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.17.1.tgz#75b3bc98ddd6e7e0d8ffe750dfaca5c66993fa47" dependencies: bytes "2.4.0" content-type "~1.0.2" @@ -983,7 +993,7 @@ body-parser@^1.15.2: body@^5.1.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" + resolved "https://registry.npmjs.org/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" dependencies: continuable-cache "^0.3.1" error "^7.0.0" @@ -992,19 +1002,19 @@ body@^5.1.0: boom@0.4.x: version "0.4.2" - resolved "https://registry.yarnpkg.com/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" + resolved "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" dependencies: hoek "0.9.x" boom@2.x.x: version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + resolved "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" dependencies: hoek "2.x.x" bower-config@^1.3.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.0.tgz#16c38c1135f8071c19f25938d61b0d8cbf18d3f1" + resolved "https://registry.npmjs.org/bower-config/-/bower-config-1.4.0.tgz#16c38c1135f8071c19f25938d61b0d8cbf18d3f1" dependencies: graceful-fs "^4.1.3" mout "^1.0.0" @@ -1014,22 +1024,22 @@ bower-config@^1.3.0: bower-endpoint-parser@0.2.2: version "0.2.2" - resolved "https://registry.yarnpkg.com/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" + resolved "https://registry.npmjs.org/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" bower@^1.6.5: version "1.8.0" - resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a" + resolved "https://registry.npmjs.org/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a" brace-expansion@^1.0.0: - version "1.1.6" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" + version "1.1.7" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" dependencies: balanced-match "^0.4.1" concat-map "0.0.1" braces@^1.8.2: version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + resolved "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" dependencies: expand-range "^1.8.1" preserve "^0.2.0" @@ -1037,11 +1047,11 @@ braces@^1.8.2: breakable@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" + resolved "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" broccoli-asset-rev@^2.4.5: version "2.5.0" - resolved "https://registry.yarnpkg.com/broccoli-asset-rev/-/broccoli-asset-rev-2.5.0.tgz#f5f66eac962bf9f086286921f0eaeaab6d00d819" + resolved "https://registry.npmjs.org/broccoli-asset-rev/-/broccoli-asset-rev-2.5.0.tgz#f5f66eac962bf9f086286921f0eaeaab6d00d819" dependencies: broccoli-asset-rewrite "^1.1.0" broccoli-filter "^1.2.2" @@ -1051,13 +1061,13 @@ broccoli-asset-rev@^2.4.5: broccoli-asset-rewrite@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" + resolved "https://registry.npmjs.org/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" dependencies: broccoli-filter "^1.2.3" broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: version "5.6.2" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.6.2.tgz#958c72e43575b2f0a862a5096dba1ce1ebc7d74d" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.6.2.tgz#958c72e43575b2f0a862a5096dba1ce1ebc7d74d" dependencies: babel-core "^5.0.0" broccoli-funnel "^1.0.0" @@ -1069,7 +1079,7 @@ broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: broccoli-babel-transpiler@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.0.0.tgz#a52c5404bf36236849da503b011fd41fe64a00a2" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.0.0.tgz#a52c5404bf36236849da503b011fd41fe64a00a2" dependencies: babel-core "^6.14.0" broccoli-funnel "^1.0.0" @@ -1081,13 +1091,13 @@ broccoli-babel-transpiler@^6.0.0: broccoli-brocfile-loader@^0.18.0: version "0.18.0" - resolved "https://registry.yarnpkg.com/broccoli-brocfile-loader/-/broccoli-brocfile-loader-0.18.0.tgz#2e86021c805c34ffc8d29a2fb721cf273e819e4b" + resolved "https://registry.npmjs.org/broccoli-brocfile-loader/-/broccoli-brocfile-loader-0.18.0.tgz#2e86021c805c34ffc8d29a2fb721cf273e819e4b" dependencies: findup-sync "^0.4.2" broccoli-builder@^0.18.3: version "0.18.4" - resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.4.tgz#abc6db2c07d214454918e2997ea87441b69b69d3" + resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.4.tgz#abc6db2c07d214454918e2997ea87441b69b69d3" dependencies: heimdalljs "^0.2.0" promise-map-series "^0.2.1" @@ -1096,33 +1106,33 @@ broccoli-builder@^0.18.3: rsvp "^3.0.17" silent-error "^1.0.1" -broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" +broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" - lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - symlink-or-copy "^1.0.0" - walk-sync "^0.2.0" + walk-sync "^0.2.5" -broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" +broccoli-caching-writer@~2.0.1: + version "2.0.4" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" + lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - walk-sync "^0.2.5" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" broccoli-clean-css@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" + resolved "https://registry.npmjs.org/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" dependencies: broccoli-persistent-filter "^1.1.6" clean-css-promise "^0.1.0" @@ -1131,7 +1141,7 @@ broccoli-clean-css@^1.1.0: broccoli-concat@^2.2.0: version "2.3.8" - resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-2.3.8.tgz#590cdcc021bb905b6c121d87c2d1d57df44a2a48" + resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-2.3.8.tgz#590cdcc021bb905b6c121d87c2d1d57df44a2a48" dependencies: broccoli-caching-writer "^2.3.1" broccoli-kitchen-sink-helpers "^0.3.1" @@ -1144,7 +1154,7 @@ broccoli-concat@^2.2.0: broccoli-concat@^3.0.4, broccoli-concat@^3.2.2: version "3.2.2" - resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" + resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.3.0" @@ -1161,13 +1171,13 @@ broccoli-concat@^3.0.4, broccoli-concat@^3.2.2: broccoli-config-loader@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/broccoli-config-loader/-/broccoli-config-loader-1.0.0.tgz#c3cf5ecfaffc04338c6f1d5d38dc36baeaa131ba" + resolved "https://registry.npmjs.org/broccoli-config-loader/-/broccoli-config-loader-1.0.0.tgz#c3cf5ecfaffc04338c6f1d5d38dc36baeaa131ba" dependencies: broccoli-caching-writer "^2.0.4" broccoli-config-replace@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" + resolved "https://registry.npmjs.org/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.0" @@ -1176,7 +1186,7 @@ broccoli-config-replace@^1.1.2: broccoli-file-creator@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" + resolved "https://registry.npmjs.org/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" dependencies: broccoli-kitchen-sink-helpers "~0.2.0" broccoli-plugin "^1.1.0" @@ -1187,7 +1197,7 @@ broccoli-file-creator@^1.0.0: broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: version "1.2.4" - resolved "https://registry.yarnpkg.com/broccoli-filter/-/broccoli-filter-1.2.4.tgz#409afb94b9a3a6da9fac8134e91e205f40cc7330" + resolved "https://registry.npmjs.org/broccoli-filter/-/broccoli-filter-1.2.4.tgz#409afb94b9a3a6da9fac8134e91e205f40cc7330" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.0.0" @@ -1201,11 +1211,11 @@ broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: broccoli-funnel-reducer@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" + resolved "https://registry.npmjs.org/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli-funnel@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.1.0.tgz#dfb91a37c902456456de4a40a1881948d65b27d9" + version "1.2.0" + resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" dependencies: array-equal "^1.0.0" blank-object "^1.0.1" @@ -1224,21 +1234,21 @@ broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli broccoli-kitchen-sink-helpers@^0.2.5, broccoli-kitchen-sink-helpers@~0.2.0: version "0.2.9" - resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" + resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" dependencies: glob "^5.0.10" mkdirp "^0.5.1" broccoli-kitchen-sink-helpers@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" + resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" dependencies: glob "^5.0.10" mkdirp "^0.5.1" broccoli-lint-eslint@^2.0.0: version "2.7.0" - resolved "https://registry.yarnpkg.com/broccoli-lint-eslint/-/broccoli-lint-eslint-2.7.0.tgz#a2d905d02b397a90ae82439f283c459ef819f140" + resolved "https://registry.npmjs.org/broccoli-lint-eslint/-/broccoli-lint-eslint-2.7.0.tgz#a2d905d02b397a90ae82439f283c459ef819f140" dependencies: broccoli-persistent-filter "^1.2.0" escape-string-regexp "^1.0.5" @@ -1249,7 +1259,7 @@ broccoli-lint-eslint@^2.0.0: broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^1.1.3, broccoli-merge-trees@^1.1.4, broccoli-merge-trees@^1.2.1: version "1.2.4" - resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" + resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" dependencies: broccoli-plugin "^1.3.0" can-symlink "^1.0.0" @@ -1262,7 +1272,7 @@ broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^ broccoli-merge-trees@~0.2.3: version "0.2.4" - resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-0.2.4.tgz#1936f63bb09e24246b1e91d8c53162c0f7b24c3c" + resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-0.2.4.tgz#1936f63bb09e24246b1e91d8c53162c0f7b24c3c" dependencies: broccoli-plugin "^1.0.0" debug "^2.2.0" @@ -1270,14 +1280,14 @@ broccoli-merge-trees@~0.2.3: broccoli-middleware@^1.0.0-beta.8: version "1.0.0-beta.8" - resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-1.0.0-beta.8.tgz#89cb6a9950ff0cf5bd75071d83d7cd6f6a11a95b" + resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-1.0.0-beta.8.tgz#89cb6a9950ff0cf5bd75071d83d7cd6f6a11a95b" dependencies: handlebars "^4.0.4" mime "^1.2.11" broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0: version "1.2.13" - resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.2.13.tgz#61368669e2b8f35238fdd38a2a896597e4a1c821" + resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.2.13.tgz#61368669e2b8f35238fdd38a2a896597e4a1c821" dependencies: async-disk-cache "^1.0.0" blank-object "^1.0.1" @@ -1295,7 +1305,7 @@ broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-p broccoli-plugin@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" + resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -1304,7 +1314,7 @@ broccoli-plugin@1.1.0: broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" + resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -1313,17 +1323,17 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli broccoli-slow-trees@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" + resolved "https://registry.npmjs.org/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" dependencies: heimdalljs "^0.2.1" broccoli-source@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" + resolved "https://registry.npmjs.org/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" broccoli-sri-hash@^2.1.0: version "2.1.2" - resolved "https://registry.yarnpkg.com/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" + resolved "https://registry.npmjs.org/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" dependencies: broccoli-caching-writer "^2.2.0" mkdirp "^0.5.1" @@ -1332,31 +1342,34 @@ broccoli-sri-hash@^2.1.0: symlink-or-copy "^1.0.1" broccoli-stew@^1.0.1, broccoli-stew@^1.2.0, broccoli-stew@^1.3.3: - version "1.4.0" - resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-1.4.0.tgz#1bdb0a1804d62a419d190abc26acb3c91878154d" + version "1.4.2" + resolved "https://registry.npmjs.org/broccoli-stew/-/broccoli-stew-1.4.2.tgz#9ec4062fd7162c6026561a2fbf64558363aff8d6" dependencies: broccoli-funnel "^1.0.1" broccoli-merge-trees "^1.0.0" broccoli-persistent-filter "^1.1.6" + broccoli-plugin "^1.3.0" chalk "^1.1.3" - debug "^2.1.0" + debug "^2.4.0" ensure-posix-path "^1.0.1" - fs-extra "^0.30.0" + fs-extra "^2.0.0" minimatch "^3.0.2" resolve "^1.1.6" rsvp "^3.0.16" + sanitize-filename "^1.5.3" + symlink-or-copy "^1.1.8" walk-sync "^0.3.0" broccoli-string-replace@^0.1.1: version "0.1.2" - resolved "https://registry.yarnpkg.com/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" + resolved "https://registry.npmjs.org/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" dependencies: broccoli-persistent-filter "^1.1.5" minimatch "^3.0.3" broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.1.tgz#9fd2e87f1c177b11a758e73c3a11d6a03d90d086" + version "1.5.2" + resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.2.tgz#04f84ab0db539031fa868ccfa563c9932d50cedb" dependencies: broccoli-plugin "^1.2.1" debug "^2.2.0" @@ -1370,14 +1383,14 @@ broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: broccoli-writer@~0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/broccoli-writer/-/broccoli-writer-0.1.1.tgz#d4d71aa8f2afbc67a3866b91a2da79084b96ab2d" + resolved "https://registry.npmjs.org/broccoli-writer/-/broccoli-writer-0.1.1.tgz#d4d71aa8f2afbc67a3866b91a2da79084b96ab2d" dependencies: quick-temp "^0.1.0" rsvp "^3.0.6" broccoli-yuidoc@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/broccoli-yuidoc/-/broccoli-yuidoc-2.1.0.tgz#d208d5c056e421a51f0c7701e938229e7e85c2e6" + resolved "https://registry.npmjs.org/broccoli-yuidoc/-/broccoli-yuidoc-2.1.0.tgz#d208d5c056e421a51f0c7701e938229e7e85c2e6" dependencies: broccoli-caching-writer "~2.0.1" broccoli-merge-trees "~0.2.3" @@ -1387,24 +1400,24 @@ broccoli-yuidoc@^2.1.0: browserslist@^1.4.0: version "1.7.7" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" dependencies: caniuse-db "^1.0.30000639" electron-to-chromium "^1.2.7" bser@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" + resolved "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" dependencies: node-int64 "^0.4.0" -buffer-shims@^1.0.0: +buffer-shims@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + resolved "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" buffer@4.9.1: version "4.9.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -1412,101 +1425,101 @@ buffer@4.9.1: builtin-modules@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" bytes@1: version "1.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" + resolved "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" bytes@2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" + resolved "https://registry.npmjs.org/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" bytes@2.4.0: version "2.4.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" + resolved "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" calculate-cache-key-for-tree@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" + resolved "https://registry.npmjs.org/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" dependencies: json-stable-stringify "^1.0.1" caller-path@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + resolved "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" dependencies: callsites "^0.2.0" callsite@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + resolved "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" callsites@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + resolved "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" camelcase@^1.0.2, camelcase@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" camelcase@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" can-symlink@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" + resolved "https://registry.npmjs.org/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" dependencies: tmp "0.0.28" caniuse-db@^1.0.30000639: - version "1.0.30000641" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000641.tgz#4810fc75fbb3f5b3bd75c2d6a94d894a7c709873" + version "1.0.30000655" + resolved "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000655.tgz#e40b6287adc938848d6708ef83d65b5f54ac1874" capture-exit@^1.1.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" + resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" dependencies: rsvp "^3.3.3" cardinal@^0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-0.5.0.tgz#00d5f661dbd4aabfdf7d41ce48a5a59bca35a291" + resolved "https://registry.npmjs.org/cardinal/-/cardinal-0.5.0.tgz#00d5f661dbd4aabfdf7d41ce48a5a59bca35a291" dependencies: ansicolors "~0.2.1" redeyed "~0.5.0" caseless@~0.11.0: version "0.11.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + resolved "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" center-align@^0.1.1: version "0.1.3" - resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + resolved "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" dependencies: align-text "^0.1.3" lazy-cache "^1.0.3" chai-as-promised@^5.1.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-5.3.0.tgz#09d7a402908aa70dfdbead53e5853fc79d3ef21c" + resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-5.3.0.tgz#09d7a402908aa70dfdbead53e5853fc79d3ef21c" chai-as-promised@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" + resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" dependencies: check-error "^1.0.2" chai-files@^1.0.0, chai-files@^1.1.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" + resolved "https://registry.npmjs.org/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" dependencies: assertion-error "^1.0.1" chai@^3.3.0: version "3.5.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" + resolved "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" dependencies: assertion-error "^1.0.1" deep-eql "^0.1.3" @@ -1514,7 +1527,7 @@ chai@^3.3.0: chalk@^0.5.1: version "0.5.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" + resolved "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" dependencies: ansi-styles "^1.1.0" escape-string-regexp "^1.0.0" @@ -1524,7 +1537,7 @@ chalk@^0.5.1: chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -1534,17 +1547,17 @@ chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: charm@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" + resolved "https://registry.npmjs.org/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" dependencies: inherits "^2.0.1" check-error@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" chrome-debugging-client@^0.2.4: version "0.2.5" - resolved "https://registry.yarnpkg.com/chrome-debugging-client/-/chrome-debugging-client-0.2.5.tgz#b8e1a6c37283323b6ff5d60525f6ea1fc8899fbd" + resolved "https://registry.npmjs.org/chrome-debugging-client/-/chrome-debugging-client-0.2.5.tgz#b8e1a6c37283323b6ff5d60525f6ea1fc8899fbd" dependencies: "@types/node" "^7.0.5" "@types/rimraf" "^0.0.28" @@ -1556,15 +1569,15 @@ chrome-debugging-client@^0.2.4: circular-json@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" clean-base-url@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" + resolved "https://registry.npmjs.org/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" clean-css-promise@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" + resolved "https://registry.npmjs.org/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" dependencies: array-to-error "^1.0.0" clean-css "^3.4.5" @@ -1572,24 +1585,24 @@ clean-css-promise@^0.1.0: clean-css@^3.4.5: version "3.4.25" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.25.tgz#9e9a52d5c1e6bc5123e1b2783fa65fe958946ede" + resolved "https://registry.npmjs.org/clean-css/-/clean-css-3.4.25.tgz#9e9a52d5c1e6bc5123e1b2783fa65fe958946ede" dependencies: commander "2.8.x" source-map "0.4.x" cli-cursor@^1.0.1, cli-cursor@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" dependencies: restore-cursor "^1.0.1" cli-spinners@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" + resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" cli-table2@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" + resolved "https://registry.npmjs.org/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" dependencies: lodash "^3.10.1" string-width "^1.0.1" @@ -1598,17 +1611,17 @@ cli-table2@^0.2.0: cli-table@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + resolved "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" dependencies: colors "1.0.3" cli-width@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" cliui@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + resolved "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" dependencies: center-align "^0.1.1" right-align "^0.1.1" @@ -1616,7 +1629,7 @@ cliui@^2.1.0: cliui@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + resolved "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" @@ -1624,71 +1637,71 @@ cliui@^3.2.0: clone@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" + resolved "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" clone@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" + resolved "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" co@^4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" code-point-at@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" colors@1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" colors@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + resolved "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" colors@~0.6.0-1: version "0.6.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" + resolved "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" dependencies: delayed-stream "~1.0.0" combined-stream@~0.0.4: version "0.0.7" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" dependencies: delayed-stream "0.0.5" commander@0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" + resolved "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" commander@2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" + resolved "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" commander@2.8.x: version "2.8.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + resolved "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" dependencies: graceful-readlink ">= 1.0.0" commander@^2.5.0, commander@^2.6.0, commander@^2.9.0: version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + resolved "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" dependencies: graceful-readlink ">= 1.0.0" commander@~2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" + resolved "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" commoner@~0.10.3: version "0.10.8" - resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" + resolved "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" dependencies: commander "^2.5.0" detective "^4.3.1" @@ -1702,29 +1715,29 @@ commoner@~0.10.3: component-bind@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + resolved "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" component-emitter@1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" + resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" component-emitter@1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" component-inherit@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + resolved "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" compressible@~2.0.8: version "2.0.10" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.10.tgz#feda1c7f7617912732b29bf8cf26252a20b9eecd" + resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.10.tgz#feda1c7f7617912732b29bf8cf26252a20b9eecd" dependencies: mime-db ">= 1.27.0 < 2" compression@^1.4.4: version "1.6.2" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" + resolved "https://registry.npmjs.org/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" dependencies: accepts "~1.3.3" bytes "2.3.0" @@ -1735,11 +1748,11 @@ compression@^1.4.4: concat-map@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" concat-stream@1.5.0, concat-stream@^1.4.6, concat-stream@^1.4.7: version "1.5.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" dependencies: inherits "~2.0.1" readable-stream "~2.0.0" @@ -1747,7 +1760,7 @@ concat-stream@1.5.0, concat-stream@^1.4.6, concat-stream@^1.4.7: configstore@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" + resolved "https://registry.npmjs.org/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" dependencies: dot-prop "^3.0.0" graceful-fs "^4.1.2" @@ -1761,11 +1774,11 @@ configstore@^2.0.0: console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" console-ui@^1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-1.0.3.tgz#31c524461b63422769f9e89c173495d91393721c" + resolved "https://registry.npmjs.org/console-ui/-/console-ui-1.0.3.tgz#31c524461b63422769f9e89c173495d91393721c" dependencies: chalk "^1.1.3" inquirer "^1.2.3" @@ -1774,63 +1787,63 @@ console-ui@^1.0.2: consolidate@^0.14.0: version "0.14.5" - resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" + resolved "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" dependencies: bluebird "^3.1.1" content-disposition@0.5.2: version "0.5.2" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" content-type@~1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" continuable-cache@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" + resolved "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" convert-source-map@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.4.0.tgz#e3dad195bf61bfe13a7a3c73e9876ec14a0268f3" + version "1.5.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" cookie-signature@1.0.6: version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" cookie@0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" copy-dereference@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" + resolved "https://registry.npmjs.org/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" core-js@^1.0.0: version "1.2.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + resolved "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" core-js@^2.4.0: version "2.4.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + resolved "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" core-object@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" + resolved "https://registry.npmjs.org/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" core-object@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/core-object/-/core-object-3.1.0.tgz#f5219fec2a19c40956f1c723d121890c88c5f677" + resolved "https://registry.npmjs.org/core-object/-/core-object-3.1.0.tgz#f5219fec2a19c40956f1c723d121890c88c5f677" dependencies: chalk "^1.1.3" core-util-is@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -cross-spawn@^5.0.0, cross-spawn@^5.0.1: +cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: lru-cache "^4.0.1" shebang-command "^1.2.0" @@ -1838,85 +1851,85 @@ cross-spawn@^5.0.0, cross-spawn@^5.0.1: cryptiles@0.2.x: version "0.2.2" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" + resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" dependencies: boom "0.4.x" cryptiles@2.x.x: version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" dependencies: boom "2.x.x" crypto-browserify@1.0.9: version "1.0.9" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" + resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" ctype@0.5.3: version "0.5.3" - resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" + resolved "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" d@1: version "1.0.0" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + resolved "https://registry.npmjs.org/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" dependencies: es5-ext "^0.10.9" dashdash@^1.12.0: version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" dependencies: assert-plus "^1.0.0" debug@0.7.4: version "0.7.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" + resolved "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" + +debug@2, debug@2.6.3, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0: + version "2.6.3" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" + dependencies: + ms "0.7.2" debug@2.2.0, debug@~2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + resolved "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" dependencies: ms "0.7.1" debug@2.3.3: version "2.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" + resolved "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" dependencies: ms "0.7.2" debug@2.6.1: version "2.6.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" - dependencies: - ms "0.7.2" - -debug@2.6.3, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: - version "2.6.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" dependencies: ms "0.7.2" decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" deep-eql@^0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" + resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" dependencies: type-detect "0.1.1" deep-is@~0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" defined@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + resolved "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" defs@~1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" + resolved "https://registry.npmjs.org/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" dependencies: alter "~0.2.0" ast-traverse "~0.1.1" @@ -1931,7 +1944,7 @@ defs@~1.1.0: del@^2.0.2: version "2.2.2" - resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + resolved "https://registry.npmjs.org/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" dependencies: globby "^5.0.0" is-path-cwd "^1.0.0" @@ -1943,33 +1956,33 @@ del@^2.0.2: delayed-stream@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" delegates@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" depd@1.1.0, depd@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" destroy@~1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" detect-file@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" + resolved "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" dependencies: fs-exists-sync "^0.1.0" detect-indent@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" dependencies: get-stdin "^4.0.1" minimist "^1.1.0" @@ -1977,61 +1990,61 @@ detect-indent@^3.0.0: detect-indent@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" dependencies: repeating "^2.0.0" detective@^4.3.1: version "4.5.0" - resolved "https://registry.yarnpkg.com/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" + resolved "https://registry.npmjs.org/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" dependencies: acorn "^4.0.3" defined "^1.0.0" diff@1.4.0, diff@^1.3.1: version "1.4.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" + resolved "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" doctrine@^1.2.2: version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" dependencies: esutils "^2.0.2" isarray "^1.0.0" dot-prop@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" dependencies: is-obj "^1.0.0" ecc-jsbn@~0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" dependencies: jsbn "~0.1.0" editions@^1.1.1: version "1.3.3" - resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" + resolved "https://registry.npmjs.org/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" ee-first@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -electron-to-chromium@^1.2.6, electron-to-chromium@^1.2.7: - version "1.2.8" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.2.8.tgz#22c2e6200d350da27d6050db7e3f6f85d18cf4ed" +electron-to-chromium@^1.2.7: + version "1.3.4" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.4.tgz#e51769c0cf550e0cf5aedf6aa2b803a264b3a900" ember-ajax@^2.4.1: version "2.5.6" - resolved "https://registry.yarnpkg.com/ember-ajax/-/ember-ajax-2.5.6.tgz#a75f743ccf1b95e979a5cf96013b3dba8fa625e4" + resolved "https://registry.npmjs.org/ember-ajax/-/ember-ajax-2.5.6.tgz#a75f743ccf1b95e979a5cf96013b3dba8fa625e4" dependencies: ember-cli-babel "^5.1.5" ember-cli-app-version@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-2.0.2.tgz#aaeede608e92fae6c2e11f63d28a373c1cc3f070" + resolved "https://registry.npmjs.org/ember-cli-app-version/-/ember-cli-app-version-2.0.2.tgz#aaeede608e92fae6c2e11f63d28a373c1cc3f070" dependencies: ember-cli-babel "^5.1.6" ember-cli-htmlbars "^1.0.0" @@ -2039,7 +2052,7 @@ ember-cli-app-version@^2.0.0: ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.1.7, ember-cli-babel@^5.2.1: version "5.2.4" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" dependencies: broccoli-babel-transpiler "^5.6.2" broccoli-funnel "^1.0.0" @@ -2048,8 +2061,8 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-c resolve "^1.1.2" ember-cli-babel@^6.0.0-beta.7: - version "6.0.0-beta.9" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.0.0-beta.9.tgz#b597d52f12d4429cd5716b55f749ebf6144b7b16" + version "6.0.0-beta.10" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.0.0-beta.10.tgz#71cc6bef05be99c6e7ea4637c444392014a6b775" dependencies: amd-name-resolver "0.0.6" babel-plugin-transform-es2015-modules-amd "^6.24.0" @@ -2063,7 +2076,7 @@ ember-cli-babel@^6.0.0-beta.7: ember-cli-blueprint-test-helpers@0.11.0: version "0.11.0" - resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" + resolved "https://registry.npmjs.org/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" dependencies: chai "^3.3.0" chai-as-promised "^5.1.0" @@ -2078,7 +2091,7 @@ ember-cli-blueprint-test-helpers@0.11.0: ember-cli-broccoli-sane-watcher@^2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.0.4.tgz#f43f42f75b7509c212fb926cd9aea86ae19264c6" + resolved "https://registry.npmjs.org/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.0.4.tgz#f43f42f75b7509c212fb926cd9aea86ae19264c6" dependencies: broccoli-slow-trees "^3.0.1" heimdalljs "^0.2.1" @@ -2087,16 +2100,16 @@ ember-cli-broccoli-sane-watcher@^2.0.4: sane "^1.1.1" ember-cli-dependency-checker@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/ember-cli-dependency-checker/-/ember-cli-dependency-checker-1.3.0.tgz#f0e8cb7f0f43c1e560494eaa9372804e7a088a2a" + version "1.4.0" + resolved "https://registry.npmjs.org/ember-cli-dependency-checker/-/ember-cli-dependency-checker-1.4.0.tgz#2b13f977e1eea843fc1a21a001be6ca5d4ef1942" dependencies: chalk "^0.5.1" - is-git-url "0.2.0" + is-git-url "^0.2.0" semver "^4.1.0" ember-cli-eslint@1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/ember-cli-eslint/-/ember-cli-eslint-1.3.0.tgz#8a7eda0d7e6a00c5a5a823f59664932d6429a8f1" + resolved "https://registry.npmjs.org/ember-cli-eslint/-/ember-cli-eslint-1.3.0.tgz#8a7eda0d7e6a00c5a5a823f59664932d6429a8f1" dependencies: broccoli-lint-eslint "^2.0.0" ember-cli-babel "^5.1.5" @@ -2104,23 +2117,23 @@ ember-cli-eslint@1.3.0: ember-cli-get-component-path-option@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" + resolved "https://registry.npmjs.org/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" ember-cli-get-dependency-depth@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" + resolved "https://registry.npmjs.org/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" ember-cli-htmlbars-inline-precompile@^0.4.0-beta.2: version "0.4.0-beta.2" - resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.0-beta.2.tgz#2ecb78ea1aaa14dd75300e3856c10c7e309209f6" + resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.0-beta.2.tgz#2ecb78ea1aaa14dd75300e3856c10c7e309209f6" dependencies: babel-plugin-htmlbars-inline-precompile "^0.2.3" ember-cli-version-checker "^1.2.0" hash-for-dep "^1.0.2" ember-cli-htmlbars@^1.0.0, ember-cli-htmlbars@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-1.2.0.tgz#327e1a5dda1c85c6fcf8be888f7894b32c3f393b" + version "1.3.0" + resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-1.3.0.tgz#e090f011239153bf45dab29625f94a46fce205af" dependencies: broccoli-persistent-filter "^1.0.3" ember-cli-version-checker "^1.0.2" @@ -2130,11 +2143,11 @@ ember-cli-htmlbars@^1.0.0, ember-cli-htmlbars@^1.1.1: ember-cli-inject-live-reload@^1.4.1: version "1.6.1" - resolved "https://registry.yarnpkg.com/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.6.1.tgz#82b8f5be454815a75e7f6d42c9ce0bc883a914a3" + resolved "https://registry.npmjs.org/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.6.1.tgz#82b8f5be454815a75e7f6d42c9ce0bc883a914a3" ember-cli-internal-test-helpers@^0.8.1: version "0.8.3" - resolved "https://registry.yarnpkg.com/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.8.3.tgz#e9b7db67f3fda4db736d1a319a282c04beada495" + resolved "https://registry.npmjs.org/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.8.3.tgz#e9b7db67f3fda4db736d1a319a282c04beada495" dependencies: chai "^3.3.0" chai-as-promised "^6.0.0" @@ -2152,11 +2165,11 @@ ember-cli-internal-test-helpers@^0.8.1: ember-cli-is-package-missing@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" + resolved "https://registry.npmjs.org/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" ember-cli-legacy-blueprints@^0.1.2: version "0.1.4" - resolved "https://registry.yarnpkg.com/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.4.tgz#83d6c005ac0e39750ff9dd45cd1b78cf697150c6" + resolved "https://registry.npmjs.org/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.4.tgz#83d6c005ac0e39750ff9dd45cd1b78cf697150c6" dependencies: chalk "^1.1.1" ember-cli-get-component-path-option "^1.0.0" @@ -2178,21 +2191,21 @@ ember-cli-legacy-blueprints@^0.1.2: ember-cli-lodash-subset@^1.0.11, ember-cli-lodash-subset@^1.0.7: version "1.0.12" - resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" + resolved "https://registry.npmjs.org/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" ember-cli-normalize-entity-name@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" + resolved "https://registry.npmjs.org/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" dependencies: silent-error "^1.0.0" ember-cli-path-utils@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" + resolved "https://registry.npmjs.org/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" ember-cli-preprocess-registry@^3.0.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.1.tgz#38456c21c4d2b64945850cf9ec68db6ba769288a" + resolved "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.1.tgz#38456c21c4d2b64945850cf9ec68db6ba769288a" dependencies: broccoli-clean-css "^1.1.0" broccoli-funnel "^1.0.0" @@ -2205,7 +2218,7 @@ ember-cli-preprocess-registry@^3.0.0: ember-cli-pretender@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/ember-cli-pretender/-/ember-cli-pretender-1.0.1.tgz#35540babddef6f2778e91c627d190c73505103cd" + resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-1.0.1.tgz#35540babddef6f2778e91c627d190c73505103cd" dependencies: broccoli-funnel "^1.1.0" broccoli-merge-trees "^1.2.1" @@ -2214,7 +2227,7 @@ ember-cli-pretender@^1.0.1: ember-cli-qunit@^2.1.0: version "2.2.6" - resolved "https://registry.yarnpkg.com/ember-cli-qunit/-/ember-cli-qunit-2.2.6.tgz#d802174724edd59b61ffdd0581fceb3236014dd1" + resolved "https://registry.npmjs.org/ember-cli-qunit/-/ember-cli-qunit-2.2.6.tgz#d802174724edd59b61ffdd0581fceb3236014dd1" dependencies: broccoli-babel-transpiler "^5.5.0" broccoli-concat "^2.2.0" @@ -2230,7 +2243,7 @@ ember-cli-qunit@^2.1.0: ember-cli-release@^0.2.9: version "0.2.9" - resolved "https://registry.yarnpkg.com/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" + resolved "https://registry.npmjs.org/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" dependencies: chalk "^1.0.0" git-tools "^0.1.4" @@ -2244,7 +2257,7 @@ ember-cli-release@^0.2.9: ember-cli-shims@^1.0.2: version "1.1.0" - resolved "https://registry.yarnpkg.com/ember-cli-shims/-/ember-cli-shims-1.1.0.tgz#0e3b8a048be865b4f81cc81d397ff1eeb13f75b6" + resolved "https://registry.npmjs.org/ember-cli-shims/-/ember-cli-shims-1.1.0.tgz#0e3b8a048be865b4f81cc81d397ff1eeb13f75b6" dependencies: ember-cli-babel "^6.0.0-beta.7" ember-cli-version-checker "^1.2.0" @@ -2252,47 +2265,47 @@ ember-cli-shims@^1.0.2: ember-cli-sri@^2.1.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" + resolved "https://registry.npmjs.org/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" dependencies: broccoli-sri-hash "^2.1.0" ember-cli-string-utils@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" + resolved "https://registry.npmjs.org/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" ember-cli-test-info@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" + resolved "https://registry.npmjs.org/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" dependencies: ember-cli-string-utils "^1.0.0" ember-cli-test-loader@^1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-test-loader/-/ember-cli-test-loader-1.1.1.tgz#333311209b18185d0e0e95f918349da10cacf0b1" + resolved "https://registry.npmjs.org/ember-cli-test-loader/-/ember-cli-test-loader-1.1.1.tgz#333311209b18185d0e0e95f918349da10cacf0b1" dependencies: ember-cli-babel "^5.2.1" ember-cli-uglify@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/ember-cli-uglify/-/ember-cli-uglify-1.2.0.tgz#3208c32b54bc2783056e8bb0d5cfe9bbaf17ffb2" + resolved "https://registry.npmjs.org/ember-cli-uglify/-/ember-cli-uglify-1.2.0.tgz#3208c32b54bc2783056e8bb0d5cfe9bbaf17ffb2" dependencies: broccoli-uglify-sourcemap "^1.0.0" ember-cli-valid-component-name@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" + resolved "https://registry.npmjs.org/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" dependencies: silent-error "^1.0.0" ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7, ember-cli-version-checker@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-1.2.0.tgz#caa286b77d1b485df5d2f62c67a6f19aa8b582c4" + resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.2.0.tgz#caa286b77d1b485df5d2f62c67a6f19aa8b582c4" dependencies: semver "^5.3.0" ember-cli@^2.11.1: version "2.12.1" - resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-2.12.1.tgz#33dd9341677f67f29bc0e286b129877ee15e5bcb" + resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.12.1.tgz#33dd9341677f67f29bc0e286b129877ee15e5bcb" dependencies: amd-name-resolver "0.0.6" bower-config "^1.3.0" @@ -2385,69 +2398,69 @@ ember-dev@emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed: ember-disable-prototype-extensions@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.0.tgz#86081c8cf6741f26e4b89e2b004f761174313e01" + resolved "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.0.tgz#86081c8cf6741f26e4b89e2b004f761174313e01" dependencies: ember-cli-babel "^5.1.5" ember-disable-proxy-controllers@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" + resolved "https://registry.npmjs.org/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" dependencies: ember-cli-babel "^5.0.0" ember-export-application-global@^1.0.5: version "1.1.1" - resolved "https://registry.yarnpkg.com/ember-export-application-global/-/ember-export-application-global-1.1.1.tgz#f257d5271268932a89d7392679ce4db89d7154af" + resolved "https://registry.npmjs.org/ember-export-application-global/-/ember-export-application-global-1.1.1.tgz#f257d5271268932a89d7392679ce4db89d7154af" dependencies: ember-cli-babel "^5.1.10" ember-inflector@^1.9.4: - version "1.11.0" - resolved "https://registry.yarnpkg.com/ember-inflector/-/ember-inflector-1.11.0.tgz#99baae18e2bee53cfa97d8db1d739280289a174f" + version "1.12.1" + resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-1.12.1.tgz#d8bd2ca2f327b439720f89923fe614d46b5da1ca" dependencies: ember-cli-babel "^5.1.7" ember-load-initializers@^0.6.0: version "0.6.3" - resolved "https://registry.yarnpkg.com/ember-load-initializers/-/ember-load-initializers-0.6.3.tgz#f47396ad271ba77294068c98f992a5f19705441a" + resolved "https://registry.npmjs.org/ember-load-initializers/-/ember-load-initializers-0.6.3.tgz#f47396ad271ba77294068c98f992a5f19705441a" dependencies: ember-cli-babel "^5.1.6" ember-publisher@0.0.7: version "0.0.7" - resolved "https://registry.yarnpkg.com/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" + resolved "https://registry.npmjs.org/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" dependencies: aws-sdk "^2.0.9" ember-qunit@^0.4.18: - version "0.4.22" - resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-0.4.22.tgz#bc389798e1a4a933f542863025e2fb91d856da49" + version "0.4.24" + resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-0.4.24.tgz#b54cf6688c442d07eacea47c3285879cdd7c2163" dependencies: ember-test-helpers "^0.5.32" ember-resolver@^2.0.3: version "2.1.1" - resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-2.1.1.tgz#5e4c1fffe9f5f48fc2194ad7592274ed0cd74f72" + resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-2.1.1.tgz#5e4c1fffe9f5f48fc2194ad7592274ed0cd74f72" dependencies: ember-cli-babel "^5.1.6" ember-cli-version-checker "^1.1.6" ember-router-generator@^1.0.0: version "1.2.3" - resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" + resolved "https://registry.npmjs.org/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" dependencies: recast "^0.11.3" ember-runtime-enumerable-includes-polyfill@^1.0.0: version "1.0.4" - resolved "https://registry.yarnpkg.com/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-1.0.4.tgz#16a7612e347a2edf07da8b2f2f09dbfee70deba0" + resolved "https://registry.npmjs.org/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-1.0.4.tgz#16a7612e347a2edf07da8b2f2f09dbfee70deba0" dependencies: ember-cli-babel "^5.1.6" ember-cli-version-checker "^1.1.6" ember-source@~2.11.0: version "2.11.3" - resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-2.11.3.tgz#12c50cc2b4a7f8ae8c5daa3a72fb09415476c510" + resolved "https://registry.npmjs.org/ember-source/-/ember-source-2.11.3.tgz#12c50cc2b4a7f8ae8c5daa3a72fb09415476c510" dependencies: broccoli-funnel "^1.0.6" broccoli-merge-trees "^1.1.4" @@ -2465,13 +2478,13 @@ ember-source@~2.11.0: ember-test-helpers@^0.5.32: version "0.5.34" - resolved "https://registry.yarnpkg.com/ember-test-helpers/-/ember-test-helpers-0.5.34.tgz#c8439108d1cba1d7d838c212208a5c4061471b83" + resolved "https://registry.npmjs.org/ember-test-helpers/-/ember-test-helpers-0.5.34.tgz#c8439108d1cba1d7d838c212208a5c4061471b83" dependencies: klassy "^0.1.3" ember-try-config@^2.0.1: version "2.1.0" - resolved "https://registry.yarnpkg.com/ember-try-config/-/ember-try-config-2.1.0.tgz#e0e156229a542346a58ee6f6ad605104c98edfe0" + resolved "https://registry.npmjs.org/ember-try-config/-/ember-try-config-2.1.0.tgz#e0e156229a542346a58ee6f6ad605104c98edfe0" dependencies: lodash "^4.6.1" node-fetch "^1.3.3" @@ -2480,7 +2493,7 @@ ember-try-config@^2.0.1: ember-try@^0.2.9: version "0.2.13" - resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.13.tgz#3d91f46950a40bba54da0edbbbb30480f83a9fdb" + resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.13.tgz#3d91f46950a40bba54da0edbbbb30480f83a9fdb" dependencies: chalk "^1.0.0" cli-table2 "^0.2.0" @@ -2500,7 +2513,7 @@ ember-try@^0.2.9: ember-watson@^0.7.0: version "0.7.0" - resolved "https://registry.yarnpkg.com/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" + resolved "https://registry.npmjs.org/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" dependencies: babel-core "^5.8.22" chalk "^1.0.0" @@ -2512,17 +2525,17 @@ ember-watson@^0.7.0: encodeurl@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" encoding@^0.1.11: version "0.1.12" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" dependencies: iconv-lite "~0.4.13" engine.io-client@1.8.0: version "1.8.0" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.0.tgz#7b730e4127414087596d9be3c88d2bc5fdb6cf5c" + resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.0.tgz#7b730e4127414087596d9be3c88d2bc5fdb6cf5c" dependencies: component-emitter "1.2.1" component-inherit "0.0.3" @@ -2539,7 +2552,7 @@ engine.io-client@1.8.0: engine.io-parser@1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" + resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" dependencies: after "0.8.1" arraybuffer.slice "0.0.6" @@ -2550,7 +2563,7 @@ engine.io-parser@1.3.1: engine.io@1.8.0: version "1.8.0" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" + resolved "https://registry.npmjs.org/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" dependencies: accepts "1.3.3" base64id "0.1.0" @@ -2561,35 +2574,35 @@ engine.io@1.8.0: ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" + resolved "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" entities@~1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + resolved "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" error-ex@^1.2.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" dependencies: is-arrayish "^0.2.1" error@^7.0.0: version "7.0.2" - resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" + resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" dependencies: string-template "~0.2.1" xtend "~4.0.0" es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: version "0.10.15" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.15.tgz#c330a5934c1ee21284a7c081a86e5fd937c91ea6" + resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz#c330a5934c1ee21284a7c081a86e5fd937c91ea6" dependencies: es6-iterator "2" es6-symbol "~3.1" es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" + resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" dependencies: d "1" es5-ext "^0.10.14" @@ -2597,7 +2610,7 @@ es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: es6-map@^0.1.3: version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" + resolved "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" dependencies: d "1" es5-ext "~0.10.14" @@ -2608,11 +2621,11 @@ es6-map@^0.1.3: es6-promise@~4.0.3: version "4.0.5" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" + resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" es6-set@~0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" + resolved "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" dependencies: d "1" es5-ext "~0.10.14" @@ -2622,14 +2635,14 @@ es6-set@~0.1.5: es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" dependencies: d "1" es5-ext "~0.10.14" es6-weak-map@^2.0.1: version "2.0.2" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" + resolved "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" dependencies: d "1" es5-ext "^0.10.14" @@ -2638,19 +2651,19 @@ es6-weak-map@^2.0.1: escape-html@~1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" escape-string-regexp@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" escope@^3.6.0: version "3.6.0" - resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + resolved "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" dependencies: es6-map "^0.1.3" es6-weak-map "^2.0.1" @@ -2659,7 +2672,7 @@ escope@^3.6.0: eslint@^2.13.0: version "2.13.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" + resolved "https://registry.npmjs.org/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" dependencies: chalk "^1.1.3" concat-stream "^1.4.6" @@ -2696,83 +2709,83 @@ eslint@^2.13.0: user-home "^2.0.0" espree@^3.1.6: - version "3.4.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.0.tgz#41656fa5628e042878025ef467e78f125cb86e1d" + version "3.4.1" + resolved "https://registry.npmjs.org/espree/-/espree-3.4.1.tgz#28a83ab4aaed71ed8fe0f5efe61b76a05c13c4d2" dependencies: - acorn "4.0.4" + acorn "^5.0.1" acorn-jsx "^3.0.0" esprima-fb@~12001.1.0-dev-harmony-fb: version "12001.1.0-dev-harmony-fb" - resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-12001.1.0-dev-harmony-fb.tgz#d84400384ba95ce2678c617ad24a7f40808da915" + resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-12001.1.0-dev-harmony-fb.tgz#d84400384ba95ce2678c617ad24a7f40808da915" esprima-fb@~15001.1001.0-dev-harmony-fb: version "15001.1001.0-dev-harmony-fb" - resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" + resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" esprima@^1.2.2: version "1.2.5" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" + resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" esprima@^2.6.0: version "2.7.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + resolved "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" esprima@^3.1.1, esprima@~3.1.0: version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + resolved "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" esprimaq@^0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" + resolved "https://registry.npmjs.org/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" esrecurse@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" dependencies: estraverse "~4.1.0" object-assign "^4.0.1" estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" estraverse@~4.1.0: version "4.1.1" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" etag@~1.8.0: version "1.8.0" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" event-emitter@~0.3.5: version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" dependencies: d "1" es5-ext "~0.10.14" eventemitter3@1.x.x: version "1.2.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" events-to-array@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.0.2.tgz#b3484465534fe4ff66fbdd1a83b777713ba404aa" + version "1.1.2" + resolved "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" exec-sh@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" + resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" dependencies: merge "^1.1.3" execa@^0.6.0: version "0.6.3" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.6.3.tgz#57b69a594f081759c69e5370f0d17b9cb11658fe" + resolved "https://registry.npmjs.org/execa/-/execa-0.6.3.tgz#57b69a594f081759c69e5370f0d17b9cb11658fe" dependencies: cross-spawn "^5.0.1" get-stream "^3.0.0" @@ -2784,41 +2797,41 @@ execa@^0.6.0: exists-sync@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" + resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" exists-sync@0.0.4: version "0.0.4" - resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" + resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" exit-hook@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" exit@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" expand-brackets@^0.1.4: version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" dependencies: is-posix-bracket "^0.1.0" expand-range@^1.8.1: version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + resolved "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" dependencies: fill-range "^2.1.0" expand-tilde@^1.2.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" + resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" dependencies: os-homedir "^1.0.1" express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: version "4.15.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35" + resolved "https://registry.npmjs.org/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35" dependencies: accepts "~1.3.3" array-flatten "1.1.1" @@ -2849,13 +2862,13 @@ express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: utils-merge "1.0.0" vary "~1.1.0" -extend@^3.0.0, extend@~3.0.0: +extend@3, extend@^3.0.0, extend@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + resolved "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" external-editor@^1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" + resolved "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" dependencies: extend "^3.0.0" spawn-sync "^1.0.15" @@ -2863,13 +2876,13 @@ external-editor@^1.1.0: extglob@^0.3.1: version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + resolved "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" dependencies: is-extglob "^1.0.0" extract-zip@~1.5.0: version "1.5.0" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4" + resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4" dependencies: concat-stream "1.5.0" debug "0.7.4" @@ -2878,29 +2891,29 @@ extract-zip@~1.5.0: extsprintf@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" fake-xml-http-request@^1.3.0, fake-xml-http-request@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-1.4.0.tgz#6481c727a0eae9c420bae229dcdfc5369c4b5477" + version "1.5.0" + resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-1.5.0.tgz#d79602a97043d4d8fea671d5d904af38847b451d" faker@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/faker/-/faker-3.1.0.tgz#0f908faf4e6ec02524e54a57e432c5c013e08c9f" + resolved "https://registry.npmjs.org/faker/-/faker-3.1.0.tgz#0f908faf4e6ec02524e54a57e432c5c013e08c9f" fast-levenshtein@~2.0.4: version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" + resolved "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" dependencies: blank-object "^1.0.1" fast-sourcemap-concat@^1.0.1: version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-sourcemap-concat/-/fast-sourcemap-concat-1.1.0.tgz#a800767abed5eda02e67238ec063a709be61f9d4" + resolved "https://registry.npmjs.org/fast-sourcemap-concat/-/fast-sourcemap-concat-1.1.0.tgz#a800767abed5eda02e67238ec063a709be61f9d4" dependencies: chalk "^0.5.1" debug "^2.2.0" @@ -2913,47 +2926,47 @@ fast-sourcemap-concat@^1.0.1: faye-websocket@~0.10.0: version "0.10.0" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" dependencies: websocket-driver ">=0.5.1" fb-watchman@^1.8.0: version "1.9.2" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383" dependencies: bser "1.0.2" fd-slicer@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" dependencies: pend "~1.2.0" figures@^1.3.5: version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + resolved "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" dependencies: escape-string-regexp "^1.0.5" object-assign "^4.1.0" file-entry-cache@^1.1.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" dependencies: flat-cache "^1.2.1" object-assign "^4.0.1" filename-regex@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + resolved "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" filesize@^3.1.3: version "3.5.6" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.6.tgz#5fd98f3eac94ec9516ef8ed5782fad84a01a0a1a" + resolved "https://registry.npmjs.org/filesize/-/filesize-3.5.6.tgz#5fd98f3eac94ec9516ef8ed5782fad84a01a0a1a" fill-range@^2.1.0: version "2.2.3" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" dependencies: is-number "^2.1.0" isobject "^2.0.0" @@ -2963,7 +2976,7 @@ fill-range@^2.1.0: finalhandler@~1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.1.tgz#bcd15d1689c0e5ed729b6f7f541a6df984117db8" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.1.tgz#bcd15d1689c0e5ed729b6f7f541a6df984117db8" dependencies: debug "2.6.3" encodeurl "~1.0.1" @@ -2975,24 +2988,24 @@ finalhandler@~1.0.0: find-index@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" + resolved "https://registry.npmjs.org/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" find-up@^1.0.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" find-up@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" dependencies: locate-path "^2.0.0" findup-sync@^0.4.2: version "0.4.3" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" + resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" dependencies: detect-file "^0.1.0" is-glob "^2.0.1" @@ -3001,14 +3014,14 @@ findup-sync@^0.4.2: findup@^0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" + resolved "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" dependencies: colors "~0.6.0-1" commander "~2.1.0" fireworm@^0.7.0: version "0.7.1" - resolved "https://registry.yarnpkg.com/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" + resolved "https://registry.npmjs.org/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" dependencies: async "~0.2.9" is-type "0.0.1" @@ -3018,42 +3031,49 @@ fireworm@^0.7.0: flat-cache@^1.2.1: version "1.2.2" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" dependencies: circular-json "^0.3.1" del "^2.0.2" graceful-fs "^4.1.2" write "^0.2.1" +follow-redirects@0.0.7: + version "0.0.7" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" + dependencies: + debug "^2.2.0" + stream-consume "^0.1.0" + for-in@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" for-own@^0.1.4: version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + resolved "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" dependencies: for-in "^1.0.1" forever-agent@~0.5.0: version "0.5.2" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" forever-agent@~0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" form-data@~0.1.0: version "0.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" + resolved "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" dependencies: async "~0.9.0" combined-stream "~0.0.4" mime "~1.2.11" form-data@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" + version "2.1.4" + resolved "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" dependencies: asynckit "^0.4.0" combined-stream "^1.0.5" @@ -3061,26 +3081,26 @@ form-data@~2.1.1: forwarded@~0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" fresh@0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" fs-exists-sync@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + resolved "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" fs-extra@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.0.0.tgz#337352bded4a0b714f3eb84de8cea765e9d37600" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-2.0.0.tgz#337352bded4a0b714f3eb84de8cea765e9d37600" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" fs-extra@^0.24.0: version "0.24.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -3089,7 +3109,7 @@ fs-extra@^0.24.0: fs-extra@^0.26.0, fs-extra@^0.26.7: version "0.26.7" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -3099,7 +3119,7 @@ fs-extra@^0.26.0, fs-extra@^0.26.7: fs-extra@^0.30.0: version "0.30.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -3109,19 +3129,26 @@ fs-extra@^0.30.0: fs-extra@^1.0.0, fs-extra@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" klaw "^1.0.0" +fs-extra@^2.0.0: + version "2.1.2" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + fs-readdir-recursive@^0.1.0: version "0.1.2" - resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" + resolved "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" fs-sync@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" + resolved "https://registry.npmjs.org/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" dependencies: glob "^7.1.0" iconv-lite "^0.4.13" @@ -3131,7 +3158,7 @@ fs-sync@^1.0.4: fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6: version "0.5.6" - resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-0.5.6.tgz#342665749e8dca406800b672268c8f5073f3e623" + resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.6.tgz#342665749e8dca406800b672268c8f5073f3e623" dependencies: heimdalljs-logger "^0.1.7" object-assign "^4.1.0" @@ -3140,11 +3167,11 @@ fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5 fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" gauge@~2.7.1: version "2.7.3" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09" dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -3157,74 +3184,76 @@ gauge@~2.7.1: generate-function@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + resolved "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" generate-object-property@^1.1.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + resolved "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" dependencies: is-property "^1.0.0" get-caller-file@^1.0.0, get-caller-file@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" get-stdin@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" get-stream@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" getpass@^0.1.1: version "0.1.6" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" dependencies: assert-plus "^1.0.0" git-repo-info@^1.0.4, git-repo-info@^1.1.2: version "1.4.1" - resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" + resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" git-repo-info@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.2.0.tgz#43d8513e04a24dd441330a2f7c6655a709fdbaf2" + resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.2.0.tgz#43d8513e04a24dd441330a2f7c6655a709fdbaf2" git-repo-version@0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-0.4.1.tgz#75fab9a0a4ec8470755b0eea7fdaa6f9d41453bf" + resolved "https://registry.npmjs.org/git-repo-version/-/git-repo-version-0.4.1.tgz#75fab9a0a4ec8470755b0eea7fdaa6f9d41453bf" dependencies: git-repo-info "~1.2.0" git-tools@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" + resolved "https://registry.npmjs.org/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" dependencies: spawnback "~1.0.0" -github@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/github/-/github-0.2.4.tgz#24fa7f0e13fa11b946af91134c51982a91ce538b" +github@^1.1.1: + version "1.4.0" + resolved "https://registry.npmjs.org/github/-/github-1.4.0.tgz#60aed8f16ffe381a3ca6dc6dba5bdd64445b7856" dependencies: + follow-redirects "0.0.7" + https-proxy-agent "^1.0.0" mime "^1.2.11" glob-base@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + resolved "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" dependencies: glob-parent "^2.0.0" is-glob "^2.0.0" glob-parent@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" dependencies: is-glob "^2.0.0" glob@3.2.3: version "3.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" + resolved "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" dependencies: graceful-fs "~2.0.0" inherits "2" @@ -3232,7 +3261,7 @@ glob@3.2.3: glob@5.0.13, glob@^5.0.10: version "5.0.13" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" + resolved "https://registry.npmjs.org/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" dependencies: inflight "^1.0.4" inherits "2" @@ -3242,7 +3271,7 @@ glob@5.0.13, glob@^5.0.10: glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1: version "7.1.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -3253,7 +3282,7 @@ glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glo glob@^4.3.2: version "4.5.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" + resolved "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" dependencies: inflight "^1.0.4" inherits "2" @@ -3262,7 +3291,7 @@ glob@^4.3.2: glob@^5.0.15: version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: inflight "^1.0.4" inherits "2" @@ -3272,14 +3301,14 @@ glob@^5.0.15: global-modules@^0.2.3: version "0.2.3" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" + resolved "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" dependencies: global-prefix "^0.1.4" is-windows "^0.2.0" global-prefix@^0.1.4: version "0.1.5" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" + resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" dependencies: homedir-polyfill "^1.0.0" ini "^1.3.4" @@ -3288,15 +3317,15 @@ global-prefix@^0.1.4: globals@^6.4.0: version "6.4.1" - resolved "https://registry.yarnpkg.com/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" + resolved "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" globals@^9.0.0, globals@^9.2.0: version "9.17.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286" + resolved "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286" globby@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + resolved "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" dependencies: array-union "^1.0.1" arrify "^1.0.0" @@ -3307,27 +3336,27 @@ globby@^5.0.0: graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" graceful-fs@~2.0.0: version "2.0.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" "graceful-readlink@>= 1.0.0": version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + resolved "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" growl@1.8.1: version "1.8.1" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428" + resolved "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428" growly@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" handlebars@^4.0.4: version "4.0.6" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" + resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" dependencies: async "^1.4.0" optimist "^0.6.1" @@ -3337,7 +3366,7 @@ handlebars@^4.0.4: har-validator@~2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" dependencies: chalk "^1.1.1" commander "^2.9.0" @@ -3346,39 +3375,39 @@ har-validator@~2.0.6: has-ansi@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" + resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" dependencies: ansi-regex "^0.2.0" has-ansi@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" dependencies: ansi-regex "^2.0.0" has-binary@0.1.6: version "0.1.6" - resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" + resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" dependencies: isarray "0.0.1" has-binary@0.1.7: version "0.1.7" - resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" + resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" dependencies: isarray "0.0.1" has-cors@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + resolved "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" has-unicode@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" hash-for-dep@^1.0.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.1.2.tgz#e3347ed92960eb0bb53a2c6c2b70e36d75b7cd0c" + resolved "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.1.2.tgz#e3347ed92960eb0bb53a2c6c2b70e36d75b7cd0c" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" heimdalljs "^0.2.3" @@ -3387,14 +3416,14 @@ hash-for-dep@^1.0.2: hasha@~2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1" + resolved "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1" dependencies: is-stream "^1.0.1" pinkie-promise "^2.0.0" hawk@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" + resolved "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" dependencies: boom "0.4.x" cryptiles "0.2.x" @@ -3403,7 +3432,7 @@ hawk@1.1.1: hawk@~3.1.3: version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + resolved "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" dependencies: boom "2.x.x" cryptiles "2.x.x" @@ -3412,7 +3441,7 @@ hawk@~3.1.3: heimdall-query@^0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" + resolved "https://registry.npmjs.org/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" dependencies: chalk "^1.1.1" chrome-debugging-client "^0.2.4" @@ -3424,69 +3453,69 @@ heimdall-query@^0.0.5: heimdalljs-fs-monitor@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.1.0.tgz#d404a65688c6714c485469ed3495da4853440272" + resolved "https://registry.npmjs.org/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.1.0.tgz#d404a65688c6714c485469ed3495da4853440272" dependencies: heimdalljs "^0.2.0" heimdalljs-logger "^0.1.7" heimdalljs-graph@^0.3.1: version "0.3.3" - resolved "https://registry.yarnpkg.com/heimdalljs-graph/-/heimdalljs-graph-0.3.3.tgz#ea801dbba659c8d522fe1cb83b2d605726e4918f" + resolved "https://registry.npmjs.org/heimdalljs-graph/-/heimdalljs-graph-0.3.3.tgz#ea801dbba659c8d522fe1cb83b2d605726e4918f" heimdalljs-logger@^0.1.7: - version "0.1.8" - resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.8.tgz#82abb55e53eefc0e5654ddf521b82926e50fcd95" + version "0.1.9" + resolved "https://registry.npmjs.org/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz#d76ada4e45b7bb6f786fc9c010a68eb2e2faf176" dependencies: debug "^2.2.0" heimdalljs "^0.2.0" heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3: version "0.2.4" - resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.4.tgz#34ead16eab422c94803065d33abeba1f7b24a910" + resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.2.4.tgz#34ead16eab422c94803065d33abeba1f7b24a910" dependencies: rsvp "~3.2.1" heimdalljs@^0.3.0: version "0.3.3" - resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" + resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" dependencies: rsvp "~3.2.1" hoek@0.9.x: version "0.9.1" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" + resolved "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" hoek@2.x.x: version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + resolved "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" home-or-tmp@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" + resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" dependencies: os-tmpdir "^1.0.1" user-home "^1.1.1" home-or-tmp@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.1" homedir-polyfill@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" dependencies: parse-passwd "^1.0.0" hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: - version "2.4.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.1.tgz#4b0445e41c004a8bd1337773a4ff790ca40318c8" + version "2.4.2" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.4.2.tgz#0076b9f46a270506ddbaaea56496897460612a67" http-errors@~1.6.1: version "1.6.1" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257" dependencies: depd "1.1.0" inherits "2.0.3" @@ -3495,14 +3524,14 @@ http-errors@~1.6.1: http-proxy@^1.13.1, http-proxy@^1.9.0: version "1.16.2" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" + resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" dependencies: eventemitter3 "1.x.x" requires-port "1.x.x" http-signature@~0.10.0: version "0.10.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" dependencies: asn1 "0.1.11" assert-plus "^0.1.5" @@ -3510,58 +3539,66 @@ http-signature@~0.10.0: http-signature@~1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" dependencies: assert-plus "^0.2.0" jsprim "^1.2.2" sshpk "^1.7.0" +https-proxy-agent@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" + dependencies: + agent-base "2" + debug "2" + extend "3" + iconv-lite@0.4.15, iconv-lite@^0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.15" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" ieee754@^1.1.4: version "1.1.8" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" ignore@^3.1.2: - version "3.2.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.6.tgz#26e8da0644be0bb4cb39516f6c79f0e0f4ffe48c" + version "3.2.7" + resolved "https://registry.npmjs.org/ignore/-/ignore-3.2.7.tgz#4810ca5f1d8eca5595213a34b94f2eb4ed926bbd" imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" indexof@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" inflected@^1.1.6: version "1.1.7" - resolved "https://registry.yarnpkg.com/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" + resolved "https://registry.npmjs.org/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" inflection@^1.7.0, inflection@^1.7.1, inflection@^1.8.0: version "1.12.0" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" + resolved "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" inflight@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" dependencies: once "^1.3.0" wrappy "1" inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.1: version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" ini@^1.3.4: version "1.3.4" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" inline-source-map-comment@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" + resolved "https://registry.npmjs.org/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" dependencies: chalk "^1.0.0" get-stdin "^4.0.1" @@ -3571,7 +3608,7 @@ inline-source-map-comment@^1.0.5: inquirer@^0.12.0: version "0.12.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" dependencies: ansi-escapes "^1.1.0" ansi-regex "^2.0.0" @@ -3589,7 +3626,7 @@ inquirer@^0.12.0: inquirer@^1.2.3: version "1.2.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918" dependencies: ansi-escapes "^1.1.0" chalk "^1.0.0" @@ -3608,89 +3645,85 @@ inquirer@^1.2.3: invariant@^2.2.0, invariant@^2.2.2: version "2.2.2" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" dependencies: loose-envify "^1.0.0" invert-kv@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" ipaddr.js@1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec" is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" is-buffer@^1.0.2: version "1.1.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" is-builtin-module@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" dependencies: builtin-modules "^1.0.0" is-dotfile@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + resolved "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" is-equal-shallow@^0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + resolved "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" dependencies: is-primitive "^2.0.0" is-extendable@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" is-extglob@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" is-finite@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + resolved "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - -is-git-url@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-0.2.0.tgz#b9ce0fb044821c88880213d602db03bdb255da1b" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" is-git-url@^0.2.0: version "0.2.3" - resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-0.2.3.tgz#445200d6fbd6da028fb5e01440d9afc93f3ccb64" + resolved "https://registry.npmjs.org/is-git-url/-/is-git-url-0.2.3.tgz#445200d6fbd6da028fb5e01440d9afc93f3ccb64" is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" dependencies: is-extglob "^1.0.0" is-integer@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/is-integer/-/is-integer-1.0.6.tgz#5273819fada880d123e1ac00a938e7172dd8d95e" + resolved "https://registry.npmjs.org/is-integer/-/is-integer-1.0.6.tgz#5273819fada880d123e1ac00a938e7172dd8d95e" dependencies: is-finite "^1.0.0" is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: version "2.16.0" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" + resolved "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" dependencies: generate-function "^2.0.0" generate-object-property "^1.1.0" @@ -3699,103 +3732,103 @@ is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: is-number@^2.0.2, is-number@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + resolved "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" dependencies: kind-of "^3.0.2" is-obj@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" is-path-cwd@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" is-path-in-cwd@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + resolved "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" dependencies: is-path-inside "^1.0.0" is-path-inside@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" dependencies: path-is-inside "^1.0.1" is-posix-bracket@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + resolved "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" is-primitive@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + resolved "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" is-promise@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" is-property@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + resolved "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" is-resolvable@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" dependencies: tryit "^1.0.1" is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" is-type@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" + resolved "https://registry.npmjs.org/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" dependencies: core-util-is "~1.0.0" is-typedarray@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" is-utf8@^0.2.0: version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" is-windows@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" + resolved "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" isarray@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" isbinaryfile@^3.0.0: version "3.0.2" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" + resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" isexe@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" isobject@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" dependencies: isarray "1.0.0" isstream@~0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" istextorbinary@2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" + resolved "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" dependencies: binaryextensions "1 || 2" editions "^1.1.1" @@ -3803,59 +3836,59 @@ istextorbinary@2.1.0: jade@0.26.3: version "0.26.3" - resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" + resolved "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" dependencies: commander "0.6.1" mkdirp "0.3.0" jmespath@0.15.0: version "0.15.0" - resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" jodid25519@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + resolved "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" dependencies: jsbn "~0.1.0" jquery@^3.1.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787" + resolved "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787" js-string-escape@^1.0.0, js-string-escape@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" + resolved "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" js-tokens@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" js-tokens@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: - version "3.8.2" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.2.tgz#02d3e2c0f6beab20248d412c352203827d786721" + version "3.8.3" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766" dependencies: argparse "^1.0.7" esprima "^3.1.1" jsbn@~0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" jsesc@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" jsesc@~0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" json-api-mock-server@0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/json-api-mock-server/-/json-api-mock-server-0.1.1.tgz#00acb22ac58127e87fa9a172159cd8ed558e8106" + resolved "https://registry.npmjs.org/json-api-mock-server/-/json-api-mock-server-0.1.1.tgz#00acb22ac58127e87fa9a172159cd8ed558e8106" dependencies: body-parser "^1.15.2" chalk "^1.1.1" @@ -3866,54 +3899,54 @@ json-api-mock-server@0.1.1: json-schema@0.2.3: version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: jsonify "~0.0.0" json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" json3@3.3.2: version "3.3.2" - resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + resolved "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" json5@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" + resolved "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" json5@^0.5.0: version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + resolved "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" jsonapi-validator@^2.1.1: version "2.2.0" - resolved "https://registry.yarnpkg.com/jsonapi-validator/-/jsonapi-validator-2.2.0.tgz#07f9bdb6d118c1e728fa77280605fa9b527f8c66" + resolved "https://registry.npmjs.org/jsonapi-validator/-/jsonapi-validator-2.2.0.tgz#07f9bdb6d118c1e728fa77280605fa9b527f8c66" dependencies: ajv "^4.1.3" yargs "^5.0.0" jsonfile@^2.1.0: version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" optionalDependencies: graceful-fs "^4.1.6" jsonify@~0.0.0: version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" jsonpointer@^4.0.0: version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" jsprim@^1.2.2: version "1.4.0" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" + resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" dependencies: assert-plus "1.0.0" extsprintf "1.0.2" @@ -3922,37 +3955,37 @@ jsprim@^1.2.2: kew@~0.7.0: version "0.7.0" - resolved "https://registry.yarnpkg.com/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" + resolved "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" kind-of@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" dependencies: is-buffer "^1.0.2" klassy@^0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/klassy/-/klassy-0.1.3.tgz#c31d5756d583197d75f582b6e692872be497067f" + resolved "https://registry.npmjs.org/klassy/-/klassy-0.1.3.tgz#c31d5756d583197d75f582b6e692872be497067f" klaw@^1.0.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + resolved "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" optionalDependencies: graceful-fs "^4.1.9" lazy-cache@^1.0.3: version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" lcid@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + resolved "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" dependencies: invert-kv "^1.0.0" leek@0.0.24: version "0.0.24" - resolved "https://registry.yarnpkg.com/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" + resolved "https://registry.npmjs.org/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" dependencies: debug "^2.1.0" lodash.assign "^3.2.0" @@ -3960,34 +3993,34 @@ leek@0.0.24: leven@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" + resolved "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" levn@^0.3.0, levn@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" linkify-it@^2.0.0: version "2.0.3" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" dependencies: uc.micro "^1.0.1" linkify-it@~1.2.0: version "1.2.4" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" dependencies: uc.micro "^1.0.1" livereload-js@^2.2.2: version "2.2.2" - resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" + resolved "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" load-json-file@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -3996,57 +4029,57 @@ load-json-file@^1.0.0: strip-bom "^2.0.0" loader.js@^4.2.2: - version "4.2.3" - resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.2.3.tgz#845228877aa5317209e41f6c00d9bab36a6a4808" + version "4.3.0" + resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.3.0.tgz#736c13eb8afdf75abd6c2d7b4f7fd40e1105a71f" locate-path@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" dependencies: p-locate "^2.0.0" path-exists "^3.0.0" lodash-node@^3.2.0: version "3.10.2" - resolved "https://registry.yarnpkg.com/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" + resolved "https://registry.npmjs.org/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" lodash._arraycopy@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" + resolved "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" lodash._arrayeach@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" + resolved "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" lodash._baseassign@^3.0.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + resolved "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" dependencies: lodash._basecopy "^3.0.0" lodash.keys "^3.0.0" lodash._basecopy@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + resolved "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" lodash._baseflatten@^3.0.0: version "3.1.4" - resolved "https://registry.yarnpkg.com/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" + resolved "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" dependencies: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" lodash._basefor@^3.0.0: version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" + resolved "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" lodash._bindcallback@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" lodash._createassigner@^3.0.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + resolved "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" dependencies: lodash._bindcallback "^3.0.0" lodash._isiterateecall "^3.0.0" @@ -4054,19 +4087,19 @@ lodash._createassigner@^3.0.0: lodash._getnative@^3.0.0: version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" lodash._isiterateecall@^3.0.0: version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + resolved "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" lodash._reinterpolate@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" lodash.assign@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" dependencies: lodash._baseassign "^3.0.0" lodash._createassigner "^3.0.0" @@ -4074,44 +4107,44 @@ lodash.assign@^3.2.0: lodash.assign@^4.1.0, lodash.assign@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" lodash.assignin@^4.1.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + resolved "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" lodash.clonedeep@^4.4.1: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" lodash.debounce@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" + resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" dependencies: lodash._getnative "^3.0.0" lodash.find@^4.5.1: version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" + resolved "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" lodash.flatten@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" + resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" dependencies: lodash._baseflatten "^3.0.0" lodash._isiterateecall "^3.0.0" lodash.isarguments@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" lodash.isarray@^3.0.0: version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" lodash.isplainobject@^3.0.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" + resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" dependencies: lodash._basefor "^3.0.0" lodash.isarguments "^3.0.0" @@ -4119,11 +4152,11 @@ lodash.isplainobject@^3.0.0: lodash.istypedarray@^3.0.0: version "3.0.6" - resolved "https://registry.yarnpkg.com/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" + resolved "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" lodash.keys@^3.0.0: version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" dependencies: lodash._getnative "^3.0.0" lodash.isarguments "^3.0.0" @@ -4131,14 +4164,14 @@ lodash.keys@^3.0.0: lodash.keysin@^3.0.0: version "3.0.8" - resolved "https://registry.yarnpkg.com/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" + resolved "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" dependencies: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" lodash.merge@^3.3.2: version "3.3.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-3.3.2.tgz#0d90d93ed637b1878437bb3e21601260d7afe994" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz#0d90d93ed637b1878437bb3e21601260d7afe994" dependencies: lodash._arraycopy "^3.0.0" lodash._arrayeach "^3.0.0" @@ -4154,86 +4187,86 @@ lodash.merge@^3.3.2: lodash.merge@^4.3.0, lodash.merge@^4.4.0, lodash.merge@^4.5.1: version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" lodash.omit@^4.1.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" + resolved "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" lodash.restparam@^3.0.0: version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" lodash.template@^4.2.5: version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" + resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings "^4.0.0" lodash.templatesettings@^4.0.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" + resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" dependencies: lodash._reinterpolate "~3.0.0" lodash.toplainobject@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz#28790ad942d293d78aa663a07ecf7f52ca04198d" + resolved "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz#28790ad942d293d78aa663a07ecf7f52ca04198d" dependencies: lodash._basecopy "^3.0.0" lodash.keysin "^3.0.0" lodash.uniq@^4.2.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + +lodash.uniqby@^4.7.0: + version "4.7.0" + resolved "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" lodash@^4.0.0, lodash@^4.15.0, lodash@^4.16.1, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: version "4.17.4" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" - -lodash@~3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.5.0.tgz#19bb3f4d51278f0b8c818ed145c74ecf9fe40e6d" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" longest@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" loose-envify@^1.0.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: js-tokens "^3.0.0" lru-cache@2: version "2.7.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" lru-cache@^4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" dependencies: pseudomap "^1.0.1" yallist "^2.0.0" make-array@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" + resolved "https://registry.npmjs.org/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" makeerror@1.0.x: version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" dependencies: tmpl "1.0.x" markdown-it-terminal@0.0.4: version "0.0.4" - resolved "https://registry.yarnpkg.com/markdown-it-terminal/-/markdown-it-terminal-0.0.4.tgz#3f2ce624ba2ca964a78b8b388d605ee330de9ced" + resolved "https://registry.npmjs.org/markdown-it-terminal/-/markdown-it-terminal-0.0.4.tgz#3f2ce624ba2ca964a78b8b388d605ee330de9ced" dependencies: ansi-styles "^2.1.0" cardinal "^0.5.0" @@ -4243,7 +4276,7 @@ markdown-it-terminal@0.0.4: markdown-it@^4.3.0, markdown-it@^4.4.0: version "4.4.0" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" dependencies: argparse "~1.0.2" entities "~1.1.1" @@ -4253,7 +4286,7 @@ markdown-it@^4.3.0, markdown-it@^4.4.0: markdown-it@^8.2.0: version "8.3.1" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.3.1.tgz#2f4b622948ccdc193d66f3ca2d43125ac4ac7323" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-8.3.1.tgz#2f4b622948ccdc193d66f3ca2d43125ac4ac7323" dependencies: argparse "^1.0.7" entities "~1.1.1" @@ -4263,53 +4296,53 @@ markdown-it@^8.2.0: matcher-collection@^1.0.0, matcher-collection@^1.0.1: version "1.0.4" - resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-1.0.4.tgz#2f66ae0869996f29e43d0b62c83dd1d43e581755" + resolved "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.4.tgz#2f66ae0869996f29e43d0b62c83dd1d43e581755" dependencies: minimatch "^3.0.2" md5-hex@^1.0.2, md5-hex@^1.2.1: version "1.3.0" - resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" + resolved "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" dependencies: md5-o-matic "^0.1.1" md5-o-matic@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" + resolved "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" mdn-links@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" + resolved "https://registry.npmjs.org/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" mdurl@^1.0.1, mdurl@~1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + resolved "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" media-typer@0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" memory-streams@^0.1.0: version "0.1.2" - resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.2.tgz#273ff777ab60fec599b116355255282cca2c50c2" + resolved "https://registry.npmjs.org/memory-streams/-/memory-streams-0.1.2.tgz#273ff777ab60fec599b116355255282cca2c50c2" dependencies: readable-stream "~1.0.2" merge-descriptors@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" merge@^1.1.3, merge@^1.2.0, merge@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + resolved "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" methods@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" micromatch@^2.1.5, micromatch@^2.3.7: version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" dependencies: arr-diff "^2.0.0" array-unique "^0.2.1" @@ -4327,76 +4360,76 @@ micromatch@^2.1.5, micromatch@^2.3.7: "mime-db@>= 1.27.0 < 2", mime-db@~1.27.0: version "1.27.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" -mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: +mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7: version "2.1.15" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" dependencies: mime-db "~1.27.0" mime-types@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" mime@1.3.4, mime@^1.2.11: version "1.3.4" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + resolved "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" mime@~1.2.11: version "1.2.11" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + resolved "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" "minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" dependencies: brace-expansion "^1.0.0" minimatch@^2.0.1, minimatch@^2.0.3, minimatch@^2.0.8: version "2.0.10" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" dependencies: brace-expansion "^1.0.0" minimatch@~0.2.11: version "0.2.14" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" dependencies: lru-cache "2" sigmund "~1.0.0" minimist@0.0.8, minimist@~0.0.1: version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" minimist@^1.1.0, minimist@^1.1.1: version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" mkdirp@0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" mkdirp@0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" dependencies: minimist "0.0.8" mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" mktemp@^0.4.0, mktemp@~0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" + resolved "https://registry.npmjs.org/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" mocha-only-detector@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/mocha-only-detector/-/mocha-only-detector-0.0.2.tgz#00f7dde6f949cf68a3cc92bdacff997b87e4b1d1" + resolved "https://registry.npmjs.org/mocha-only-detector/-/mocha-only-detector-0.0.2.tgz#00f7dde6f949cf68a3cc92bdacff997b87e4b1d1" dependencies: esprima "^1.2.2" esprimaq "^0.0.1" @@ -4404,7 +4437,7 @@ mocha-only-detector@0.0.2: mocha@2.4.5: version "2.4.5" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.4.5.tgz#151768dd2875eb51bc8295e9800026e9f2bb398f" + resolved "https://registry.npmjs.org/mocha/-/mocha-2.4.5.tgz#151768dd2875eb51bc8295e9800026e9f2bb398f" dependencies: commander "2.3.0" debug "2.2.0" @@ -4418,17 +4451,17 @@ mocha@2.4.5: moment-timezone@^0.3.0: version "0.3.1" - resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" + resolved "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" dependencies: moment ">= 2.6.0" "moment@>= 2.6.0": version "2.18.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" + resolved "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" morgan@^1.5.2, morgan@^1.7.0: version "1.8.1" - resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.8.1.tgz#f93023d3887bd27b78dfd6023cea7892ee27a4b1" + resolved "https://registry.npmjs.org/morgan/-/morgan-1.8.1.tgz#f93023d3887bd27b78dfd6023cea7892ee27a4b1" dependencies: basic-auth "~1.1.0" debug "2.6.1" @@ -4438,50 +4471,50 @@ morgan@^1.5.2, morgan@^1.7.0: mout@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/mout/-/mout-1.0.0.tgz#9bdf1d4af57d66d47cb353a6335a3281098e1501" + resolved "https://registry.npmjs.org/mout/-/mout-1.0.0.tgz#9bdf1d4af57d66d47cb353a6335a3281098e1501" ms@0.7.1: version "0.7.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + resolved "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" ms@0.7.2: version "0.7.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + resolved "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" mustache@^2.2.1: version "2.3.0" - resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" + resolved "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" mute-stream@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" mute-stream@0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" negotiator@0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" node-fetch@^1.3.3: version "1.6.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" dependencies: encoding "^0.1.11" is-stream "^1.0.1" node-int64@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" node-modules-path@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" + resolved "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" node-notifier@^5.0.1: version "5.1.2" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff" + resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff" dependencies: growly "^1.3.0" semver "^5.3.0" @@ -4490,24 +4523,24 @@ node-notifier@^5.0.1: node-uuid@~1.4.0: version "1.4.8" - resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" + resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" nopt@^3.0.3: version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: abbrev "1" nopt@^4.0.0: version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" dependencies: abbrev "1" osenv "^0.1.4" normalize-package-data@^2.3.2: version "2.3.6" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff" dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -4515,29 +4548,31 @@ normalize-package-data@^2.3.2: validate-npm-package-license "^3.0.1" normalize-path@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + version "2.1.1" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" npm-git-info@^1.0.0: version "1.0.3" - resolved "https://registry.yarnpkg.com/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" + resolved "https://registry.npmjs.org/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" npm-package-arg@^4.1.1: version "4.2.1" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" dependencies: hosted-git-info "^2.1.5" semver "^5.1.0" npm-run-path@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" dependencies: path-key "^2.0.0" npmlog@^4.0.0: version "4.0.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" @@ -4546,65 +4581,65 @@ npmlog@^4.0.0: number-is-nan@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" oauth-sign@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" oauth-sign@~0.8.1: version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" object-assign@4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" object-component@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + resolved "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" object.omit@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + resolved "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" dependencies: for-own "^0.1.4" is-extendable "^0.1.1" on-finished@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" dependencies: ee-first "1.1.1" on-headers@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" once@^1.3.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" onetime@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + resolved "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" optimist@^0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + resolved "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" dependencies: minimist "~0.0.1" wordwrap "~0.0.2" optionator@^0.8.1: version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: deep-is "~0.1.3" fast-levenshtein "~2.0.4" @@ -4615,11 +4650,11 @@ optionator@^0.8.1: options@>=0.0.5: version "0.0.6" - resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" + resolved "https://registry.npmjs.org/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" ora@^0.2.0: version "0.2.3" - resolved "https://registry.yarnpkg.com/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" + resolved "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" dependencies: chalk "^1.1.1" cli-cursor "^1.0.2" @@ -4628,32 +4663,32 @@ ora@^0.2.0: os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" os-locale@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + resolved "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" dependencies: lcid "^1.0.0" os-shim@^0.1.2: version "0.1.3" - resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + resolved "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" output-file-sync@^1.1.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + resolved "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" dependencies: graceful-fs "^4.1.4" mkdirp "^0.5.1" @@ -4661,21 +4696,21 @@ output-file-sync@^1.1.0: p-finally@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" p-limit@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" p-locate@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" dependencies: p-limit "^1.1.0" parse-glob@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + resolved "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" dependencies: glob-base "^0.3.0" is-dotfile "^1.0.0" @@ -4684,77 +4719,77 @@ parse-glob@^3.0.4: parse-json@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" dependencies: error-ex "^1.2.0" parse-passwd@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" parsejson@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" + resolved "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" dependencies: better-assert "~1.0.0" parseqs@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + resolved "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" dependencies: better-assert "~1.0.0" parseuri@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + resolved "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" dependencies: better-assert "~1.0.0" parseurl@~1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" path-exists@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" path-exists@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" dependencies: pinkie-promise "^2.0.0" path-exists@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" path-is-inside@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" path-key@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" path-parse@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" path-posix@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + resolved "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" path-to-regexp@0.1.7: version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" path-type@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" dependencies: graceful-fs "^4.1.2" pify "^2.0.0" @@ -4762,11 +4797,11 @@ path-type@^1.0.0: pend@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" phantomjs-prebuilt@^2.1.12: version "2.1.14" - resolved "https://registry.yarnpkg.com/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz#d53d311fcfb7d1d08ddb24014558f1188c516da0" + resolved "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz#d53d311fcfb7d1d08ddb24014558f1188c516da0" dependencies: es6-promise "~4.0.3" extract-zip "~1.5.0" @@ -4780,29 +4815,29 @@ phantomjs-prebuilt@^2.1.12: pify@^2.0.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" pinkie-promise@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" plain-text-box-plot@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/plain-text-box-plot/-/plain-text-box-plot-0.0.1.tgz#d3b2e53071ea6706972318565761242f779c04b8" + resolved "https://registry.npmjs.org/plain-text-box-plot/-/plain-text-box-plot-0.0.1.tgz#d3b2e53071ea6706972318565761242f779c04b8" pluralize@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + resolved "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" portfinder@^1.0.7: version "1.0.13" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" + resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" dependencies: async "^1.5.2" debug "^2.2.0" @@ -4810,96 +4845,96 @@ portfinder@^1.0.7: prelude-ls@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" preserve@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + resolved "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" pretender@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.0.0.tgz#9137c38718b4d89814478b7f208f70d3e441a0e9" + resolved "https://registry.npmjs.org/pretender/-/pretender-1.0.0.tgz#9137c38718b4d89814478b7f208f70d3e441a0e9" dependencies: fake-xml-http-request "^1.3.0" route-recognizer "^0.1.9" pretender@^1.4.2: version "1.4.2" - resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.4.2.tgz#dde9995dfdf75b28a3dd7a73cde2f9f612e5e8f4" + resolved "https://registry.npmjs.org/pretender/-/pretender-1.4.2.tgz#dde9995dfdf75b28a3dd7a73cde2f9f612e5e8f4" dependencies: fake-xml-http-request "^1.4.0" route-recognizer "^0.2.3" printf@^0.2.3: version "0.2.5" - resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" + resolved "https://registry.npmjs.org/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" private@^0.1.6, private@~0.1.5: version "0.1.7" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" + resolved "https://registry.npmjs.org/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" process-nextick-args@~1.0.6: version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" process-relative-require@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" + resolved "https://registry.npmjs.org/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" dependencies: node-modules-path "^1.0.0" progress@^1.1.8, progress@~1.1.8: version "1.1.8" - resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + resolved "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" promise-map-series@^0.2.1: version "0.2.3" - resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" + resolved "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" dependencies: rsvp "^3.0.14" proxy-addr@~1.1.3: version "1.1.4" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" dependencies: forwarded "~0.1.0" ipaddr.js "1.3.0" pseudomap@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" punycode@1.3.2: version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" punycode@^1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" q@^1.1.2: version "1.5.0" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" + resolved "https://registry.npmjs.org/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" qs@6.4.0, qs@^6.2.0: version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + resolved "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" qs@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" + resolved "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" qs@~6.3.0: version "6.3.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" + resolved "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" querystring@0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" quick-temp@0.1.6, quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5: version "0.1.6" - resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.6.tgz#a6242a15cba9f9cdbd341287b5c569e318eec307" + resolved "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.6.tgz#a6242a15cba9f9cdbd341287b5c569e318eec307" dependencies: mktemp "~0.4.0" rimraf "~2.2.6" @@ -4907,33 +4942,33 @@ quick-temp@0.1.6, quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick qunit-notifications@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/qunit-notifications/-/qunit-notifications-0.1.1.tgz#3001afc6a6a77dfbd962ccbcddde12dec5286c09" + resolved "https://registry.npmjs.org/qunit-notifications/-/qunit-notifications-0.1.1.tgz#3001afc6a6a77dfbd962ccbcddde12dec5286c09" qunitjs@^1.20.0: version "1.23.1" - resolved "https://registry.yarnpkg.com/qunitjs/-/qunitjs-1.23.1.tgz#1971cf97ac9be01a64d2315508d2e48e6fd4e719" + resolved "https://registry.npmjs.org/qunitjs/-/qunitjs-1.23.1.tgz#1971cf97ac9be01a64d2315508d2e48e6fd4e719" randomatic@^1.1.3: version "1.1.6" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + resolved "https://registry.npmjs.org/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" dependencies: is-number "^2.0.2" kind-of "^3.0.2" range-parser@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" raw-body@~1.1.0: version "1.1.7" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" dependencies: bytes "1" string_decoder "0.10" raw-body@~2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" dependencies: bytes "2.4.0" iconv-lite "0.4.15" @@ -4941,34 +4976,34 @@ raw-body@~2.2.0: read-pkg-up@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" dependencies: find-up "^1.0.0" read-pkg "^1.0.0" read-pkg@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" path-type "^1.0.0" readable-stream@^2, "readable-stream@^2.0.0 || ^1.1.13": - version "2.2.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.6.tgz#8b43aed76e71483938d12a8d46c6cf1a00b1f816" + version "2.2.9" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8" dependencies: - buffer-shims "^1.0.0" + buffer-shims "~1.0.0" core-util-is "~1.0.0" inherits "~2.0.1" isarray "~1.0.0" process-nextick-args "~1.0.6" - string_decoder "~0.10.x" + string_decoder "~1.0.0" util-deprecate "~1.0.1" readable-stream@~1.0.2: version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -4977,7 +5012,7 @@ readable-stream@~1.0.2: readable-stream@~2.0.0: version "2.0.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -4988,7 +5023,7 @@ readable-stream@~2.0.0: readline2@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + resolved "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -4996,7 +5031,7 @@ readline2@^1.0.1: recast@0.10.33: version "0.10.33" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" + resolved "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" dependencies: ast-types "0.8.12" esprima-fb "~15001.1001.0-dev-harmony-fb" @@ -5005,7 +5040,7 @@ recast@0.10.33: recast@^0.10.10, recast@^0.10.29: version "0.10.43" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" + resolved "https://registry.npmjs.org/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" dependencies: ast-types "0.8.15" esprima-fb "~15001.1001.0-dev-harmony-fb" @@ -5014,7 +5049,7 @@ recast@^0.10.10, recast@^0.10.29: recast@^0.11.17, recast@^0.11.3: version "0.11.23" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" + resolved "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" dependencies: ast-types "0.9.6" esprima "~3.1.0" @@ -5023,21 +5058,21 @@ recast@^0.11.17, recast@^0.11.3: redeyed@~0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-0.5.0.tgz#7ab000e60ee3875ac115d29edb32c1403c6c25d1" + resolved "https://registry.npmjs.org/redeyed/-/redeyed-0.5.0.tgz#7ab000e60ee3875ac115d29edb32c1403c6c25d1" dependencies: esprima-fb "~12001.1.0-dev-harmony-fb" regenerate@^1.2.1: version "1.3.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" regenerator-runtime@^0.10.0: version "0.10.3" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e" -regenerator-transform@0.9.8: - version "0.9.8" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.8.tgz#0f88bb2bc03932ddb7b6b7312e68078f01026d6c" +regenerator-transform@0.9.11: + version "0.9.11" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.9.11.tgz#3a7d067520cb7b7176769eb5ff868691befe1283" dependencies: babel-runtime "^6.18.0" babel-types "^6.19.0" @@ -5045,7 +5080,7 @@ regenerator-transform@0.9.8: regenerator@0.8.40: version "0.8.40" - resolved "https://registry.yarnpkg.com/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" + resolved "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" dependencies: commoner "~0.10.3" defs "~1.1.0" @@ -5056,14 +5091,14 @@ regenerator@0.8.40: regex-cache@^0.4.2: version "0.4.3" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + resolved "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" dependencies: is-equal-shallow "^0.1.3" is-primitive "^2.0.0" regexpu-core@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" dependencies: regenerate "^1.2.1" regjsgen "^0.2.0" @@ -5071,7 +5106,7 @@ regexpu-core@^2.0.0: regexpu@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" + resolved "https://registry.npmjs.org/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" dependencies: esprima "^2.6.0" recast "^0.10.10" @@ -5081,43 +5116,47 @@ regexpu@^1.3.0: regjsgen@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" regjsparser@^0.1.4: version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" dependencies: jsesc "~0.5.0" +remove-trailing-separator@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4" + repeat-element@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" repeat-string@^1.5.2: version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" repeating@^1.1.0, repeating@^1.1.2: version "1.1.3" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" + resolved "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" dependencies: is-finite "^1.0.0" repeating@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + resolved "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" dependencies: is-finite "^1.0.0" request-progress@~2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" + resolved "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" dependencies: throttleit "^1.0.0" request@~2.40.0: version "2.40.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" + resolved "https://registry.npmjs.org/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" dependencies: forever-agent "~0.5.0" json-stringify-safe "~5.0.0" @@ -5136,7 +5175,7 @@ request@~2.40.0: request@~2.79.0: version "2.79.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + resolved "https://registry.npmjs.org/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" dependencies: aws-sign2 "~0.6.0" aws4 "^1.2.1" @@ -5161,120 +5200,120 @@ request@~2.79.0: require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" require-main-filename@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" require-uncached@^1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + resolved "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" dependencies: caller-path "^0.1.0" resolve-from "^1.0.0" requires-port@1.x.x: version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" resolve-dir@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" + resolved "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" dependencies: expand-tilde "^1.2.2" global-modules "^0.2.3" resolve-from@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0: version "1.3.2" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235" dependencies: path-parse "^1.0.5" restore-cursor@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" dependencies: exit-hook "^1.0.0" onetime "^1.0.0" right-align@^0.1.1: version "0.1.3" - resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + resolved "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" dependencies: align-text "^0.1.1" rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1: version "2.5.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" rimraf@^2.1.4, rimraf@^2.5.3, rimraf@^2.5.4: version "2.6.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: glob "^7.0.5" rimraf@~2.2.6: version "2.2.8" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" route-recognizer@^0.1.9: version "0.1.11" - resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" + resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" route-recognizer@^0.2.3: version "0.2.10" - resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" + resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.6, rsvp@~3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: version "3.5.0" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" rsvp@~3.0.6: version "3.0.21" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" rsvp@~3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" run-async@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + resolved "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" dependencies: once "^1.3.0" run-async@^2.2.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + resolved "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" dependencies: is-promise "^2.1.0" rx-lite@^3.1.2: version "3.1.2" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + resolved "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" rx@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + resolved "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" safe-json-parse@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" + resolved "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" sane@^1.1.1: version "1.6.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-1.6.0.tgz#9610c452307a135d29c1fdfe2547034180c46775" + resolved "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz#9610c452307a135d29c1fdfe2547034180c46775" dependencies: anymatch "^1.3.0" exec-sh "^0.2.0" @@ -5284,13 +5323,19 @@ sane@^1.1.1: walker "~1.0.5" watch "~0.10.0" -sax@1.1.5, sax@>=0.6.0: - version "1.1.5" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.5.tgz#1da50a8d00cdecd59405659f5ff85349fe773743" +sanitize-filename@^1.5.3: + version "1.6.1" + resolved "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.1.tgz#612da1c96473fa02dccda92dcd5b4ab164a6772a" + dependencies: + truncate-utf8-bytes "^1.0.0" + +sax@1.2.1, sax@>=0.6.0: + version "1.2.1" + resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" selenium-webdriver@^3.0.0-beta-2: version "3.3.0" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.3.0.tgz#f14d9b04cee9495d4284d22105b189b8305ccca1" + resolved "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.3.0.tgz#f14d9b04cee9495d4284d22105b189b8305ccca1" dependencies: adm-zip "^0.4.7" rimraf "^2.5.4" @@ -5299,15 +5344,19 @@ selenium-webdriver@^3.0.0-beta-2: "semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + resolved "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" semver@^4.1.0, semver@^4.3.1: version "4.3.6" - resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + resolved "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + +semver@~5.0.1: + version "5.0.3" + resolved "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" send@0.15.1: version "0.15.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" + resolved "https://registry.npmjs.org/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" dependencies: debug "2.6.1" depd "~1.1.0" @@ -5325,7 +5374,7 @@ send@0.15.1: serve-static@1.12.1: version "1.12.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039" dependencies: encodeurl "~1.0.1" escape-html "~1.0.3" @@ -5334,90 +5383,90 @@ serve-static@1.12.1: set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" setprototypeof@1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" shebang-command@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" shelljs@^0.6.0: version "0.6.1" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" + resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" shellwords@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14" + resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14" sigmund@~1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + resolved "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" signal-exit@^3.0.0: version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" silent-error@^1.0.0, silent-error@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/silent-error/-/silent-error-1.0.1.tgz#71b7d503d1c6f94882b51b56be879b113cb4822c" + resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.0.1.tgz#71b7d503d1c6f94882b51b56be879b113cb4822c" dependencies: debug "^2.2.0" simple-dom@^0.3.0: version "0.3.2" - resolved "https://registry.yarnpkg.com/simple-dom/-/simple-dom-0.3.2.tgz#0663d10f1556f1500551d518f56e3aba0871371d" + resolved "https://registry.npmjs.org/simple-dom/-/simple-dom-0.3.2.tgz#0663d10f1556f1500551d518f56e3aba0871371d" simple-fmt@~0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" + resolved "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" simple-is@~0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" + resolved "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" slash@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" slice-ansi@0.0.4: version "0.0.4" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" slide@^1.1.5: version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" sntp@0.2.x: version "0.2.4" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" + resolved "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" dependencies: hoek "0.9.x" sntp@1.x.x: version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + resolved "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" dependencies: hoek "2.x.x" socket.io-adapter@0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" + resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" dependencies: debug "2.3.3" socket.io-parser "2.3.1" socket.io-client@1.6.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" + resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" dependencies: backo2 "1.0.2" component-bind "1.0.0" @@ -5433,7 +5482,7 @@ socket.io-client@1.6.0: socket.io-parser@2.3.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" + resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" dependencies: component-emitter "1.1.2" debug "2.2.0" @@ -5442,7 +5491,7 @@ socket.io-parser@2.3.1: socket.io@1.6.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" + resolved "https://registry.npmjs.org/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" dependencies: debug "2.3.3" engine.io "1.8.0" @@ -5454,86 +5503,86 @@ socket.io@1.6.0: sort-object-keys@^1.1.1: version "1.1.2" - resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" + resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" sort-package-json@^1.4.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.5.0.tgz#d71ec7d13fc4d5f26bd87835676097fa6775206e" + version "1.6.0" + resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.6.0.tgz#4aaf4d24a13252941e28a80f5a306eb5dcac1ab0" dependencies: sort-object-keys "^1.1.1" source-map-support@^0.2.10: version "0.2.10" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" dependencies: source-map "0.1.32" source-map-support@^0.4.2: version "0.4.14" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef" dependencies: source-map "^0.5.6" source-map-url@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" + resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" source-map@0.1.32: version "0.1.32" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" dependencies: amdefine ">=0.0.4" source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: version "0.4.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: amdefine ">=0.0.4" source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: version "0.5.6" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" spawn-args@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" + resolved "https://registry.npmjs.org/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" spawn-sync@^1.0.15: version "1.0.15" - resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + resolved "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" dependencies: concat-stream "^1.4.7" os-shim "^0.1.2" spawnback@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" + resolved "https://registry.npmjs.org/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" spdx-correct@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" dependencies: spdx-license-ids "^1.0.2" spdx-expression-parse@~1.0.0: version "1.0.4" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" spdx-license-ids@^1.0.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" sri-toolbox@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" + resolved "https://registry.npmjs.org/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" sshpk@^1.7.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77" + version "1.13.0" + resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz#ff2a3e4fd04497555fed97b39a0fd82fafb3a33c" dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -5548,19 +5597,23 @@ sshpk@^1.7.0: stable@~0.1.3: version "0.1.6" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10" + resolved "https://registry.npmjs.org/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10" "statuses@>= 1.3.1 < 2", statuses@~1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + +stream-consume@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" string-template@~0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -5568,86 +5621,92 @@ string-width@^1.0.1, string-width@^1.0.2: string-width@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + resolved "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^3.0.0" string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string_decoder@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.0.tgz#f06f41157b664d86069f84bdbdc9b0d8ab281667" + dependencies: + buffer-shims "~1.0.0" stringmap@~0.2.2: version "0.2.2" - resolved "https://registry.yarnpkg.com/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" + resolved "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" stringset@~0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" + resolved "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" stringstream@~0.0.4: version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + resolved "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" strip-ansi@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" dependencies: ansi-regex "^0.2.1" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: ansi-regex "^2.0.0" strip-bom@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" dependencies: is-utf8 "^0.2.0" strip-eof@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" strip-json-comments@~1.0.1: version "1.0.4" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" styled_string@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" + resolved "https://registry.npmjs.org/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" sum-up@^1.0.1: version "1.0.3" - resolved "https://registry.yarnpkg.com/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" + resolved "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" dependencies: chalk "^1.0.0" supports-color@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" supports-color@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" supports-color@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: version "1.1.8" - resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" + resolved "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" sync-exec@^0.6.2: version "0.6.2" - resolved "https://registry.yarnpkg.com/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105" + resolved "https://registry.npmjs.org/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105" table@^3.7.8: version "3.8.3" - resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + resolved "https://registry.npmjs.org/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" dependencies: ajv "^4.7.0" ajv-keywords "^1.0.0" @@ -5658,7 +5717,7 @@ table@^3.7.8: tap-parser@^5.1.0: version "5.3.3" - resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-5.3.3.tgz#53ec8a90f275d6fff43f169e56a679502a741185" + resolved "https://registry.npmjs.org/tap-parser/-/tap-parser-5.3.3.tgz#53ec8a90f275d6fff43f169e56a679502a741185" dependencies: events-to-array "^1.0.1" js-yaml "^3.2.7" @@ -5667,21 +5726,21 @@ tap-parser@^5.1.0: temp@0.8.3: version "0.8.3" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" + resolved "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" dependencies: os-tmpdir "^1.0.0" rimraf "~2.2.6" testem@^1.8.1: - version "1.15.0" - resolved "https://registry.yarnpkg.com/testem/-/testem-1.15.0.tgz#2e3a9e7ac29f16a20f718eb0c4b12e7a44900675" + version "1.16.0" + resolved "https://registry.npmjs.org/testem/-/testem-1.16.0.tgz#3933040b5d5b5fbdb6a2b1e7032e511b54a05867" dependencies: backbone "^1.1.2" bluebird "^3.4.6" charm "^1.0.0" commander "^2.6.0" consolidate "^0.14.0" - cross-spawn "^5.0.0" + cross-spawn "^5.1.0" express "^4.10.7" fireworm "^0.7.0" glob "^7.0.4" @@ -5690,6 +5749,7 @@ testem@^1.8.1: lodash.assignin "^4.1.0" lodash.clonedeep "^4.4.1" lodash.find "^4.5.1" + lodash.uniqby "^4.7.0" mkdirp "^0.5.1" mustache "^2.2.1" node-notifier "^5.0.1" @@ -5704,23 +5764,23 @@ testem@^1.8.1: text-table@~0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" "textextensions@1 || 2": version "2.0.1" - resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.0.1.tgz#be8cf22d65379c151319f88f0335ad8f667abdca" + resolved "https://registry.npmjs.org/textextensions/-/textextensions-2.0.1.tgz#be8cf22d65379c151319f88f0335ad8f667abdca" throttleit@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" + resolved "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" through@^2.3.6, through@^2.3.8, through@~2.3.8: version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" tiny-lr@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.0.3.tgz#386731170ce521263a9d337f769ee8f11e88eb04" + resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.0.3.tgz#386731170ce521263a9d337f769ee8f11e88eb04" dependencies: body "^5.1.0" debug "~2.2.0" @@ -5731,50 +5791,50 @@ tiny-lr@^1.0.3: tmp-sync@^1.0.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" + resolved "https://registry.npmjs.org/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" dependencies: fs-sync "^1.0.4" osenv "^0.1.0" tmp@0.0.28: version "0.0.28" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" dependencies: os-tmpdir "~1.0.1" tmp@0.0.30: version "0.0.30" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" dependencies: os-tmpdir "~1.0.1" tmp@^0.0.29: version "0.0.29" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" dependencies: os-tmpdir "~1.0.1" tmpl@1.0.x: version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" to-array@0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + resolved "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" to-fast-properties@^1.0.0, to-fast-properties@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" tough-cookie@>=0.12.0, tough-cookie@~2.3.0: version "2.3.2" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" dependencies: punycode "^1.4.1" tree-sync@^1.2.1: version "1.2.2" - resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" + resolved "https://registry.npmjs.org/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" dependencies: debug "^2.2.0" fs-tree-diff "^0.5.6" @@ -5784,60 +5844,66 @@ tree-sync@^1.2.1: trim-right@^1.0.0, trim-right@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +truncate-utf8-bytes@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" + dependencies: + utf8-byte-length "^1.0.1" try-resolve@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" + resolved "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" tryit@^1.0.1: version "1.0.3" - resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + resolved "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" tryor@~0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" + resolved "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" tunnel-agent@~0.4.0, tunnel-agent@~0.4.1: version "0.4.3" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" type-check@~0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" dependencies: prelude-ls "~1.1.2" type-detect@0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" type-detect@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" type-is@~1.6.14: - version "1.6.14" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" + version "1.6.15" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" dependencies: media-typer "0.3.0" - mime-types "~2.1.13" + mime-types "~2.1.15" typedarray@~0.0.5: version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" + resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" uglify-js@^2.6, uglify-js@^2.7.0: - version "2.8.16" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.16.tgz#d286190b6eefc6fd65eb0ecac6551e0b0e8839a4" + version "2.8.22" + resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.22.tgz#d54934778a8da14903fa29a326fb24c0ab51a1a0" dependencies: source-map "~0.5.1" yargs "~3.10.0" @@ -5846,176 +5912,176 @@ uglify-js@^2.6, uglify-js@^2.7.0: uglify-to-browserify@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + resolved "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" ultron@1.0.x: version "1.0.2" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" + resolved "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" underscore.string@~2.3.3: version "2.3.3" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" + resolved "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" underscore@>=1.8.3: version "1.8.3" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + resolved "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" untildify@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" + resolved "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" dependencies: os-homedir "^1.0.0" url@0.10.3: version "0.10.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + resolved "https://registry.npmjs.org/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" dependencies: punycode "1.3.2" querystring "0.2.0" user-home@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + resolved "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" user-home@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + resolved "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" dependencies: os-homedir "^1.0.0" +utf8-byte-length@^1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" + util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" utils-merge@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" -uuid@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" +uuid@3.0.1, uuid@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" uuid@^2.0.1: version "2.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" - -uuid@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" + resolved "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" validate-npm-package-license@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" dependencies: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" vary@~1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" verror@1.3.6: version "1.3.6" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + resolved "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" dependencies: extsprintf "1.0.2" walk-sync@^0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: version "0.2.7" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" walk-sync@^0.3.0, walk-sync@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.1.tgz#558a16aeac8c0db59c028b73c66f397684ece465" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.1.tgz#558a16aeac8c0db59c028b73c66f397684ece465" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" walker@~1.0.5: version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" dependencies: makeerror "1.0.x" watch@~0.10.0: version "0.10.0" - resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" + resolved "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" websocket-driver@>=0.5.1: version "0.6.5" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" + resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" dependencies: websocket-extensions ">=0.1.1" websocket-extensions@>=0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" + resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" which-module@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + resolved "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" which@^1.2.12, which@^1.2.9, which@~1.2.10: version "1.2.14" - resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" + resolved "https://registry.npmjs.org/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" dependencies: isexe "^2.0.0" wide-align@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" dependencies: string-width "^1.0.1" window-size@0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" window-size@^0.1.2: version "0.1.4" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" + resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" window-size@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + resolved "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" wordwrap@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" wordwrap@~0.0.2: version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" wordwrap@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" wrap-ansi@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" write-file-atomic@^1.1.2: version "1.3.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -6023,97 +6089,84 @@ write-file-atomic@^1.1.2: write@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + resolved "https://registry.npmjs.org/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" dependencies: mkdirp "^0.5.1" ws@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" + resolved "https://registry.npmjs.org/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" dependencies: options ">=0.0.5" ultron "1.0.x" ws@^1.0.1: version "1.1.4" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" + resolved "https://registry.npmjs.org/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" dependencies: options ">=0.0.5" ultron "1.0.x" wtf-8@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" + resolved "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" xdg-basedir@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" + resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" dependencies: os-homedir "^1.0.0" -xml2js@0.4.15: - version "0.4.15" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.15.tgz#95cd03ff2dd144ec28bc6273bf2b2890c581ad0c" - dependencies: - sax ">=0.6.0" - xmlbuilder ">=2.4.6" - -xml2js@^0.4.17: +xml2js@0.4.17, xml2js@^0.4.17: version "0.4.17" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" + resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" dependencies: sax ">=0.6.0" xmlbuilder "^4.1.0" -xmlbuilder@2.6.2, xmlbuilder@>=2.4.6: - version "2.6.2" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-2.6.2.tgz#f916f6d10d45dc171b1be2e6e673fb6e0cc35d0a" - dependencies: - lodash "~3.5.0" - -xmlbuilder@^4.1.0: +xmlbuilder@4.2.1, xmlbuilder@^4.1.0: version "4.2.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" + resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" dependencies: lodash "^4.0.0" xmldom@^0.1.19: version "0.1.27" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" + resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" xmlhttprequest-ssl@1.5.3: version "1.5.3" - resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" + resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" xtend@^4.0.0, xtend@~4.0.0: version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" y18n@^3.2.0, y18n@^3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" yallist@^2.0.0: version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" yam@0.0.22: version "0.0.22" - resolved "https://registry.yarnpkg.com/yam/-/yam-0.0.22.tgz#38a76cb79a19284d9206ed49031e359a1340bd06" + resolved "https://registry.npmjs.org/yam/-/yam-0.0.22.tgz#38a76cb79a19284d9206ed49031e359a1340bd06" dependencies: fs-extra "^0.30.0" lodash.merge "^4.4.0" yargs-parser@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-3.2.0.tgz#5081355d19d9d0c8c5d81ada908cb4e6d186664f" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-3.2.0.tgz#5081355d19d9d0c8c5d81ada908cb4e6d186664f" dependencies: camelcase "^3.0.0" lodash.assign "^4.1.0" yargs@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-5.0.0.tgz#3355144977d05757dbb86d6e38ec056123b3a66e" + resolved "https://registry.npmjs.org/yargs/-/yargs-5.0.0.tgz#3355144977d05757dbb86d6e38ec056123b3a66e" dependencies: cliui "^3.2.0" decamelize "^1.1.1" @@ -6132,7 +6185,7 @@ yargs@^5.0.0: yargs@~3.10.0: version "3.10.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + resolved "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" dependencies: camelcase "^1.0.2" cliui "^2.1.0" @@ -6141,7 +6194,7 @@ yargs@~3.10.0: yargs@~3.27.0: version "3.27.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" + resolved "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" dependencies: camelcase "^1.2.1" cliui "^2.1.0" @@ -6152,23 +6205,23 @@ yargs@~3.27.0: yauzl@2.4.1: version "2.4.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" + resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" dependencies: fd-slicer "~1.0.1" yeast@0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + resolved "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" yui@^3.18.1: version "3.18.1" - resolved "https://registry.yarnpkg.com/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" + resolved "https://registry.npmjs.org/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" dependencies: request "~2.40.0" yuidocjs@~0.9.0: version "0.9.0" - resolved "https://registry.yarnpkg.com/yuidocjs/-/yuidocjs-0.9.0.tgz#d2ff2b37cadf30e3d45385c58f5003e5a83f2723" + resolved "https://registry.npmjs.org/yuidocjs/-/yuidocjs-0.9.0.tgz#d2ff2b37cadf30e3d45385c58f5003e5a83f2723" dependencies: express "^4.13.1" graceful-fs "^4.1.2" From 8868360e44783a0dd4bf83af73ef330be80929aa Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sat, 22 Apr 2017 09:06:42 -0400 Subject: [PATCH 1902/2527] [BUGFIX beta] Update dependencies to use Babel 6. In ember-cli@2.13 we intend to ship only one version of babel by default (though having multiple versions does work perfectly fine). These deps have just been released, the only breaking change (to them) was bumping the min engine version to Node 4 which we have already done here. --- package.json | 6 +++--- yarn.lock | 52 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index f52a65bb790..af8765df4f4 100644 --- a/package.json +++ b/package.json @@ -34,8 +34,8 @@ "ember-cli-string-utils": "^1.0.0", "ember-cli-test-info": "^1.0.0", "ember-cli-version-checker": "^1.1.4", - "ember-inflector": "^1.9.4", - "ember-runtime-enumerable-includes-polyfill": "^1.0.0", + "ember-inflector": "^2.0.0", + "ember-runtime-enumerable-includes-polyfill": "^2.0.0", "exists-sync": "0.0.3", "git-repo-info": "^1.1.2", "heimdalljs": "^0.3.0", @@ -106,7 +106,7 @@ "rsvp": "3.2.1" }, "peerDependencies": { - "ember-inflector": "^1.9.4" + "ember-inflector": "^2.0.0" }, "engines": { "node": ">= 0.12.0" diff --git a/yarn.lock b/yarn.lock index a8b1dc89cd4..db38696e2e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1106,29 +1106,29 @@ broccoli-builder@^0.18.3: rsvp "^3.0.17" silent-error "^1.0.1" -broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" +broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.1: + version "2.0.4" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" + lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - walk-sync "^0.2.5" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" -broccoli-caching-writer@~2.0.1: - version "2.0.4" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" +broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" - lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - symlink-or-copy "^1.0.0" - walk-sync "^0.2.0" + walk-sync "^0.2.5" broccoli-clean-css@^1.1.0: version "1.1.0" @@ -2050,7 +2050,7 @@ ember-cli-app-version@^2.0.0: ember-cli-htmlbars "^1.0.0" git-repo-version "0.4.1" -ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.1.7, ember-cli-babel@^5.2.1: +ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.2.1: version "5.2.4" resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" dependencies: @@ -2060,6 +2060,20 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-c ember-cli-version-checker "^1.0.2" resolve "^1.1.2" +ember-cli-babel@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.0.0.tgz#caab075780dca3759982c9f54ea70a9adb1f3550" + dependencies: + amd-name-resolver "0.0.6" + babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-polyfill "^6.16.0" + babel-preset-env "^1.2.0" + broccoli-babel-transpiler "^6.0.0" + broccoli-funnel "^1.0.0" + broccoli-source "^1.1.0" + clone "^2.0.0" + ember-cli-version-checker "^1.2.0" + ember-cli-babel@^6.0.0-beta.7: version "6.0.0-beta.10" resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.0.0-beta.10.tgz#71cc6bef05be99c6e7ea4637c444392014a6b775" @@ -2414,11 +2428,11 @@ ember-export-application-global@^1.0.5: dependencies: ember-cli-babel "^5.1.10" -ember-inflector@^1.9.4: - version "1.12.1" - resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-1.12.1.tgz#d8bd2ca2f327b439720f89923fe614d46b5da1ca" +ember-inflector@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ember-inflector/-/ember-inflector-2.0.0.tgz#ac0870e87c0724bd42cf5ed7ef166c49a296ecfb" dependencies: - ember-cli-babel "^5.1.7" + ember-cli-babel "^6.0.0" ember-load-initializers@^0.6.0: version "0.6.3" @@ -2451,11 +2465,11 @@ ember-router-generator@^1.0.0: dependencies: recast "^0.11.3" -ember-runtime-enumerable-includes-polyfill@^1.0.0: - version "1.0.4" - resolved "https://registry.npmjs.org/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-1.0.4.tgz#16a7612e347a2edf07da8b2f2f09dbfee70deba0" +ember-runtime-enumerable-includes-polyfill@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-2.0.0.tgz#6e9ba118bc909d1d7762de1b03a550d8955308a9" dependencies: - ember-cli-babel "^5.1.6" + ember-cli-babel "^6.0.0" ember-cli-version-checker "^1.1.6" ember-source@~2.11.0: From 29408b7f12ef9e2b488bbd13ce38d7aa2e7760f2 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 13 Apr 2017 21:00:04 -0700 Subject: [PATCH 1903/2527] refactor location of debug helpers to begin unlocking rollup of -private --- addon/{-private/debug.js => -debug/index.js} | 0 addon/-private/ext/date.js | 2 +- .../instance-initializers/initialize-store-service.js | 2 +- addon/-private/system/internal-model-map.js | 2 +- addon/-private/system/many-array.js | 2 +- addon/-private/system/model/errors.js | 2 +- addon/-private/system/model/internal-model.js | 2 +- addon/-private/system/model/model.js | 4 ++-- addon/-private/system/model/states.js | 2 +- addon/-private/system/promise-proxies.js | 2 +- addon/-private/system/record-array-manager.js | 2 +- addon/-private/system/references/belongs-to.js | 2 +- addon/-private/system/references/has-many.js | 2 +- addon/-private/system/relationships/belongs-to.js | 2 +- addon/-private/system/relationships/ext.js | 2 +- addon/-private/system/relationships/has-many.js | 2 +- .../-private/system/relationships/relationship-payloads.js | 2 +- addon/-private/system/relationships/state/belongs-to.js | 2 +- addon/-private/system/relationships/state/create.js | 2 +- addon/-private/system/relationships/state/has-many.js | 2 +- addon/-private/system/relationships/state/relationship.js | 2 +- addon/-private/system/store.js | 2 +- addon/-private/system/store/finders.js | 2 +- addon/-private/system/store/serializer-response.js | 2 +- addon/adapters/errors.js | 2 +- addon/adapters/json-api.js | 2 +- addon/adapters/rest.js | 2 +- addon/attr.js | 2 +- addon/index.js | 2 +- addon/serializers/embedded-records-mixin.js | 2 +- addon/serializers/json-api.js | 2 +- addon/serializers/json.js | 2 +- addon/serializers/rest.js | 2 +- index.js | 3 +-- lib/stripped-build-plugins.js | 6 +++--- tests/helpers/test-in-debug.js | 2 +- tests/unit/utils-test.js | 2 +- 37 files changed, 39 insertions(+), 40 deletions(-) rename addon/{-private/debug.js => -debug/index.js} (100%) diff --git a/addon/-private/debug.js b/addon/-debug/index.js similarity index 100% rename from addon/-private/debug.js rename to addon/-debug/index.js diff --git a/addon/-private/ext/date.js b/addon/-private/ext/date.js index 947341c1b8e..cdcda62b4e4 100644 --- a/addon/-private/ext/date.js +++ b/addon/-private/ext/date.js @@ -3,7 +3,7 @@ */ import Ember from 'ember'; -import { deprecate } from 'ember-data/-private/debug'; +import { deprecate } from 'ember-data/-debug'; /** diff --git a/addon/-private/instance-initializers/initialize-store-service.js b/addon/-private/instance-initializers/initialize-store-service.js index edb54cac9aa..b90651756f0 100644 --- a/addon/-private/instance-initializers/initialize-store-service.js +++ b/addon/-private/instance-initializers/initialize-store-service.js @@ -1,4 +1,4 @@ -import { deprecate } from 'ember-data/-private/debug'; +import { deprecate } from 'ember-data/-debug'; /* Configures a registry for use with an Ember-Data diff --git a/addon/-private/system/internal-model-map.js b/addon/-private/system/internal-model-map.js index 0ffc3e055a6..ea8acc1bed1 100644 --- a/addon/-private/system/internal-model-map.js +++ b/addon/-private/system/internal-model-map.js @@ -1,4 +1,4 @@ -import { assert, deprecate } from "ember-data/-private/debug"; +import { assert, deprecate } from 'ember-data/-debug'; import InternalModel from './model/internal-model'; /** diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 667ef50033a..7aaa74927e4 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -2,7 +2,7 @@ @module ember-data */ import Ember from 'ember'; -import { assert } from "ember-data/-private/debug"; +import { assert } from 'ember-data/-debug'; import { PromiseArray } from "./promise-proxies"; import { _objectIsAlive } from "./store/common"; import diffArray from './diff-array'; diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index f85f8895c3a..a6b1342d852 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { deprecate, warn } from "ember-data/-private/debug"; +import { deprecate, warn } from 'ember-data/-debug'; const get = Ember.get; const set = Ember.set; diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 3fdf3d0bd0d..92d0340b3ea 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert, runInDebug } from "ember-data/-private/debug"; +import { assert, runInDebug } from 'ember-data/-debug'; import RootState from "./states"; import Relationships from "../relationships/state/create"; import Snapshot from "../snapshot"; diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 8759eba7147..6e1c9083f16 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert, deprecate, warn } from "ember-data/-private/debug"; +import { assert, deprecate, warn } from 'ember-data/-debug'; import { PromiseObject } from "../promise-proxies"; import Errors from "../model/errors"; import isEnabled from '../../features'; @@ -9,7 +9,7 @@ import { relatedTypesDescriptor, relationshipsDescriptor } from '../relationships/ext'; -import { runInDebug } from 'ember-data/-private/debug'; +import { runInDebug } from 'ember-data/-debug'; const { get, diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index 0843589314c..4507f5277df 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -1,7 +1,7 @@ /** @module ember-data */ -import { assert } from "ember-data/-private/debug"; +import { assert } from 'ember-data/-debug'; /* This file encapsulates the various states that a record can transition diff --git a/addon/-private/system/promise-proxies.js b/addon/-private/system/promise-proxies.js index b11351afb63..7d63f0d4ea8 100644 --- a/addon/-private/system/promise-proxies.js +++ b/addon/-private/system/promise-proxies.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert } from "../debug"; +import { assert } from 'ember-data/-debug'; const { get , RSVP: { Promise }} = Ember; diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 5c66acca765..6c2a227d892 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -8,7 +8,7 @@ import { FilteredRecordArray, AdapterPopulatedRecordArray } from "./record-arrays"; -import { assert } from 'ember-data/-private/debug'; +import { assert } from 'ember-data/-debug'; const { get, diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index c0f1ffb3360..93a4a62e467 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -3,7 +3,7 @@ import Ember from 'ember'; import Reference from './reference'; import isEnabled from '../../features'; -import { assertPolymorphicType, deprecate } from "ember-data/-private/debug"; +import { assertPolymorphicType, deprecate } from 'ember-data/-debug'; /** diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 895c709c56b..51ca39a73f0 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -4,7 +4,7 @@ import { assertPolymorphicType, deprecate, runInDebug -} from 'ember-data/-private/debug'; +} from 'ember-data/-debug'; import isEnabled from '../../features'; diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 65ced641d89..36338f6c76e 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert, warn } from "ember-data/-private/debug"; +import { assert, warn } from 'ember-data/-debug'; import normalizeModelName from "../normalize-model-name"; /** diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 56148b39e2a..3cc8dc6e424 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert } from "ember-data/-private/debug"; +import { assert } from 'ember-data/-debug'; import { typeForRelationshipMeta, relationshipFromMeta diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index 89e4570254a..45a7a93d9da 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -3,7 +3,7 @@ */ import Ember from 'ember'; -import { assert } from "ember-data/-private/debug"; +import { assert } from 'ember-data/-debug'; import normalizeModelName from "../normalize-model-name"; import isArrayLike from "../is-array-like"; diff --git a/addon/-private/system/relationships/relationship-payloads.js b/addon/-private/system/relationships/relationship-payloads.js index 65a1b0810eb..4925fb115b9 100644 --- a/addon/-private/system/relationships/relationship-payloads.js +++ b/addon/-private/system/relationships/relationship-payloads.js @@ -1,4 +1,4 @@ -import { assert } from '../../debug'; +import { assert } from 'ember-data/-debug'; /** Manages the payloads for both sides of a single relationship, across all model diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index d374a60fb61..cd9c2c01c9d 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -2,7 +2,7 @@ import Ember from 'ember'; import { assertPolymorphicType, assert -} from "ember-data/-private/debug"; +} from 'ember-data/-debug'; import { PromiseObject } from "../../promise-proxies"; diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index 85a766c23b5..051c8e10633 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -1,7 +1,7 @@ import Ember from 'ember'; import ManyRelationship from "./has-many"; import BelongsToRelationship from "./belongs-to"; -import { runInDebug } from 'ember-data/-private/debug'; +import { runInDebug } from 'ember-data/-debug'; const { get } = Ember; diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 55f40d6bd5d..e504c0dcb2c 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -1,4 +1,4 @@ -import { assert, assertPolymorphicType } from 'ember-data/-private/debug'; +import { assert, assertPolymorphicType } from 'ember-data/-debug'; import { PromiseManyArray } from '../../promise-proxies'; import Relationship from './relationship'; import OrderedSet from '../../ordered-set'; diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 9260dbfc8f6..84ebe6771ff 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -1,5 +1,5 @@ /* global heimdall */ -import { assert, warn } from 'ember-data/-private/debug'; +import { assert, warn } from 'ember-data/-debug'; import OrderedSet from '../../ordered-set'; import _normalizeLink from '../../normalize-link'; diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 2ac7e41cdfb..519896e01ab 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -9,7 +9,7 @@ import { deprecate, warn, runInDebug -} from "ember-data/-private/debug"; +} from 'ember-data/-debug'; import Model from '../../model'; import normalizeModelName from "./normalize-model-name"; import { InvalidError } from '../../adapters/errors'; diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 57626324c28..f6a0d0e1914 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert, warn } from "ember-data/-private/debug"; +import { assert, warn } from 'ember-data/-debug'; import { _bind, _guard, diff --git a/addon/-private/system/store/serializer-response.js b/addon/-private/system/store/serializer-response.js index debad488a22..e6f5cafdec6 100644 --- a/addon/-private/system/store/serializer-response.js +++ b/addon/-private/system/store/serializer-response.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert, runInDebug } from "ember-data/-private/debug"; +import { assert, runInDebug } from 'ember-data/-debug'; /* This is a helper method that validates a JSON API top-level document diff --git a/addon/adapters/errors.js b/addon/adapters/errors.js index df26fae02cc..d2df6f10c54 100644 --- a/addon/adapters/errors.js +++ b/addon/adapters/errors.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert } from 'ember-data/-private/debug'; +import { assert } from 'ember-data/-debug'; import isEnabled from '../-private/features'; const EmberError = Ember.Error; diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index d2f417be537..e3c8e3e7515 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -6,7 +6,7 @@ import Ember from 'ember'; import RESTAdapter from "./rest"; import isEnabled from '../-private/features'; -import { instrument, deprecate } from 'ember-data/-private/debug'; +import { instrument, deprecate } from 'ember-data/-debug'; /** The `JSONAPIAdapter` is the default adapter used by Ember Data. It diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index d215ac855f2..69da9732c12 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -18,7 +18,7 @@ import { } from './errors'; import BuildURLMixin from "../-private/adapters/build-url-mixin"; import isEnabled from '../-private/features'; -import { instrument, runInDebug, warn, deprecate } from 'ember-data/-private/debug'; +import { instrument, runInDebug, warn, deprecate } from 'ember-data/-debug'; import parseResponseHeaders from '../-private/utils/parse-response-headers'; const { diff --git a/addon/attr.js b/addon/attr.js index 2c232aac2f7..c130f385e89 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { deprecate } from 'ember-data/-private/debug'; +import { deprecate } from 'ember-data/-debug'; /** @module ember-data diff --git a/addon/index.js b/addon/index.js index adb9a15554e..07b8041ccfa 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,5 +1,5 @@ import Ember from "ember"; -import { deprecate } from "ember-data/-private/debug"; +import { deprecate } from 'ember-data/-debug'; import isEnabled from "./-private/features"; import global from "./-private/global"; diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index a63d3fecf0f..580b202f1d1 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { warn } from "ember-data/-private/debug"; +import { warn } from 'ember-data/-debug'; const get = Ember.get; const set = Ember.set; diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index ec8ffb69c90..16870a1dcf4 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -4,7 +4,7 @@ import Ember from 'ember'; import { pluralize, singularize } from 'ember-inflector'; -import { assert, deprecate, runInDebug, warn } from 'ember-data/-private/debug'; +import { assert, deprecate, runInDebug, warn } from 'ember-data/-debug'; import JSONSerializer from './json'; import normalizeModelName from '../-private/system/normalize-model-name'; import isEnabled from '../-private/features'; diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 2c4cf4013b8..7fd11611b01 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert, deprecate, warn } from 'ember-data/-private/debug'; +import { assert, deprecate, warn } from 'ember-data/-debug'; import Serializer from "../serializer"; import coerceId from "../-private/system/coerce-id"; import normalizeModelName from "../-private/system/normalize-model-name"; diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 9e44a7d58d1..3331217e5be 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -4,7 +4,7 @@ import Ember from 'ember'; import { singularize } from "ember-inflector"; -import { assert, deprecate, runInDebug, warn } from "ember-data/-private/debug"; +import { assert, deprecate, runInDebug, warn } from 'ember-data/-debug'; import JSONSerializer from "../serializers/json"; import normalizeModelName from "../-private/system/normalize-model-name"; import coerceId from "../-private/system/coerce-id"; diff --git a/index.js b/index.js index dacf4585167..55ae7960154 100644 --- a/index.js +++ b/index.js @@ -121,10 +121,9 @@ module.exports = { ])); if (isProductionEnv()) { - console.log('is prod'); tree = new Funnel(tree, { exclude: [ - /-private\/debug\.js/ + /-debug/ ] }); } diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index c13b2a544d6..ce122923a8b 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -40,14 +40,14 @@ module.exports = function(environment) { if (process.env.INSTRUMENT_HEIMDALL === 'false') { plugins.push([StripHeimdall]); - uniqueAdd(filteredImports, 'ember-data/-private/debug', ['instrument']); + uniqueAdd(filteredImports, 'ember-data/-debug', ['instrument']); } else { console.warn('NOT STRIPPING HEIMDALL'); } if (environment === 'production' || process.env.INSTRUMENT_HEIMDALL === 'true') { postTransformPlugins.push([StripClassCallCheck]); - uniqueAdd(filteredImports, 'ember-data/-private/debug', [ + uniqueAdd(filteredImports, 'ember-data/-debug', [ 'assert', 'assertPolymorphicType', 'debug', @@ -61,7 +61,7 @@ module.exports = function(environment) { plugins.push([FilterImports, filteredImports]); if (environment === 'production') { - plugins.push([StripFilteredImports, 'ember-data/-private/debug']); + plugins.push([StripFilteredImports, 'ember-data/-debug']); } return { plugins, postTransformPlugins }; diff --git a/tests/helpers/test-in-debug.js b/tests/helpers/test-in-debug.js index 9d4bf2e9a89..1ca57358ec0 100644 --- a/tests/helpers/test-in-debug.js +++ b/tests/helpers/test-in-debug.js @@ -1,4 +1,4 @@ -import require from 'require'; +import { runInDebug } from 'ember-data/-debug'; import { test, skip } from 'qunit'; export default function testInDebug() { diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index 9dabb38e3dd..c9e0cec84c1 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -7,7 +7,7 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; import Model from 'ember-data/model'; -import { assertPolymorphicType } from 'ember-data/-private/debug'; +import { assertPolymorphicType } from 'ember-data/-debug'; import { modelHasAttributeOrRelationshipNamedType } from 'ember-data/-private/utils'; let env, User, Message, Post, Person, Video, Medium; From fa264472f8c388419d7e02d36bb0bf77bf9087e2 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 13 Apr 2017 21:12:00 -0700 Subject: [PATCH 1904/2527] refactor import/export pattern for model to improve isolation of -private for rollup of -private --- addon/-private/index.js | 3 +++ addon/-private/system/model.js | 16 ---------------- addon/index.js | 6 +++--- addon/model.js | 2 +- 4 files changed, 7 insertions(+), 20 deletions(-) create mode 100644 addon/-private/index.js delete mode 100644 addon/-private/system/model.js diff --git a/addon/-private/index.js b/addon/-private/index.js new file mode 100644 index 00000000000..5f99267e1ac --- /dev/null +++ b/addon/-private/index.js @@ -0,0 +1,3 @@ +export { default as Model } from './system/model/model'; +export { default as RootState } from './system/model/states'; +export { default as Errors } from './system/model/errors'; diff --git a/addon/-private/system/model.js b/addon/-private/system/model.js deleted file mode 100644 index 8342e25b1b4..00000000000 --- a/addon/-private/system/model.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - @module ember-data -*/ - -import Model from "./model/model"; -import attr from "../../attr"; -import RootState from "./model/states"; -import Errors from "./model/errors"; - -export { - RootState, - attr, - Errors -}; - -export default Model; diff --git a/addon/index.js b/addon/index.js index 07b8041ccfa..1cb0833aac5 100644 --- a/addon/index.js +++ b/addon/index.js @@ -32,9 +32,8 @@ import { import { Errors, RootState, - attr -} from "./-private/system/model"; -import Model from "./model"; + Model +} from './-private'; import Snapshot from "./-private/system/snapshot"; import Adapter from "./adapter"; import Serializer from "./serializer"; @@ -83,6 +82,7 @@ import setupContainer from "./setup-container"; import initializeStoreService from './-private/instance-initializers/initialize-store-service'; import Relationship from "./-private/system/relationships/state/relationship"; +import attr from './attr'; DS.Store = Store; DS.PromiseArray = PromiseArray; diff --git a/addon/model.js b/addon/model.js index 58f2e051350..e9666139dae 100644 --- a/addon/model.js +++ b/addon/model.js @@ -1,3 +1,3 @@ -import Model from "./-private/system/model"; +import { Model } from './-private'; export default Model; From f680345c31c5767a445807fbc1358a740de92eb2 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 13 Apr 2017 21:18:35 -0700 Subject: [PATCH 1905/2527] privatize store, core, global, fix privatization of model --- addon/-private/index.js | 7 ++++++- addon/index.js | 37 ++++++++++++++++++------------------- addon/model.js | 4 +--- addon/store.js | 4 +--- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/addon/-private/index.js b/addon/-private/index.js index 5f99267e1ac..fa7f18c810e 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -1,3 +1,8 @@ export { default as Model } from './system/model/model'; -export { default as RootState } from './system/model/states'; export { default as Errors } from './system/model/errors'; +export { default as Store } from './system/store'; +export { default as DS } from './core'; + +// should be private +export { default as RootState } from './system/model/states'; +export { default as global } from './global'; diff --git a/addon/index.js b/addon/index.js index 1cb0833aac5..67d6622abb6 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,7 +1,5 @@ import Ember from "ember"; import { deprecate } from 'ember-data/-debug'; -import isEnabled from "./-private/features"; -import global from "./-private/global"; /** Ember Data @@ -15,29 +13,29 @@ if (Ember.VERSION.match(/^1\.([0-9]|1[0-2])\./)) { ". Please upgrade your version of Ember, then upgrade Ember Data."); } -import DS from "./-private/core"; - import normalizeModelName from "./-private/system/normalize-model-name"; - +import Snapshot from "./-private/system/snapshot"; import InternalModel from "./-private/system/model/internal-model"; +import DebugAdapter from './-private/system/debug/debug-adapter'; +import isEnabled from "./-private/features"; import { PromiseArray, PromiseObject, PromiseManyArray } from "./-private/system/promise-proxies"; + import { - Store -} from "./-private/system/store"; -import { + DS, + global, Errors, RootState, - Model + Model, + Store } from './-private'; -import Snapshot from "./-private/system/snapshot"; + import Adapter from "./adapter"; import Serializer from "./serializer"; -import DebugAdapter from './-private/system/debug/debug-adapter'; import { AdapterError, @@ -53,6 +51,14 @@ import { errorsArrayToHash } from "./adapters/errors"; +import "ember-inflector"; +import JSONAPIAdapter from './adapters/json-api'; +import RESTAdapter from './adapters/rest'; +import JSONAPISerializer from './serializers/json-api'; +import JSONSerializer from './serializers/json'; +import RESTSerializer from './serializers/rest'; +import EmbeddedRecordsMixin from "./serializers/embedded-records-mixin"; + import { RecordArray, FilteredRecordArray, @@ -60,14 +66,7 @@ import { } from "./-private/system/record-arrays"; import ManyArray from "./-private/system/many-array"; import RecordArrayManager from "./-private/system/record-array-manager"; -import JSONAPIAdapter from './adapters/json-api'; -import RESTAdapter from './adapters/rest'; import BuildURLMixin from "./-private/adapters/build-url-mixin"; -import JSONAPISerializer from './serializers/json-api'; -import JSONSerializer from './serializers/json'; -import RESTSerializer from './serializers/rest'; -import "ember-inflector"; -import EmbeddedRecordsMixin from "./serializers/embedded-records-mixin"; import { Transform, @@ -77,7 +76,7 @@ import { BooleanTransform } from "./-private/transforms"; -import {hasMany, belongsTo} from "./relationships"; +import { hasMany, belongsTo } from "./relationships"; import setupContainer from "./setup-container"; import initializeStoreService from './-private/instance-initializers/initialize-store-service'; diff --git a/addon/model.js b/addon/model.js index e9666139dae..455c02b9928 100644 --- a/addon/model.js +++ b/addon/model.js @@ -1,3 +1 @@ -import { Model } from './-private'; - -export default Model; +export { Model as default } from './-private'; diff --git a/addon/store.js b/addon/store.js index d752c46bc30..ae380a10821 100644 --- a/addon/store.js +++ b/addon/store.js @@ -1,3 +1 @@ -import Store from "./-private/system/store"; - -export default Store; +export { Store as default } from './-private'; From e56866abf924aeefc3d3d52b94774987c2cca8d2 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 13 Apr 2017 21:26:58 -0700 Subject: [PATCH 1906/2527] remove excess wiring from transforms --- addon/-private/index.js | 7 +++++++ addon/-private/initializers/transforms.js | 10 ++++------ addon/-private/transforms.js | 13 ------------- addon/index.js | 15 ++++++--------- 4 files changed, 17 insertions(+), 28 deletions(-) delete mode 100644 addon/-private/transforms.js diff --git a/addon/-private/index.js b/addon/-private/index.js index fa7f18c810e..900083189cc 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -1,8 +1,15 @@ +// public export { default as Model } from './system/model/model'; export { default as Errors } from './system/model/errors'; export { default as Store } from './system/store'; export { default as DS } from './core'; +// should be moved into public +export { default as NumberTransform } from './transforms/number'; +export { default as DateTransform } from './transforms/date'; +export { default as StringTransform } from './transforms/string'; +export { default as BooleanTransform } from './transforms/boolean'; + // should be private export { default as RootState } from './system/model/states'; export { default as global } from './global'; diff --git a/addon/-private/initializers/transforms.js b/addon/-private/initializers/transforms.js index 8e55b693b11..29e8e0120d1 100644 --- a/addon/-private/initializers/transforms.js +++ b/addon/-private/initializers/transforms.js @@ -1,9 +1,7 @@ -import { - BooleanTransform, - DateTransform, - StringTransform, - NumberTransform -} from "../transforms"; +import NumberTransform from '../transforms/number'; +import DateTransform from '../transforms/date'; +import StringTransform from '../transforms/string'; +import BooleanTransform from '../transforms/boolean'; /* Configures a registry for use with Ember-Data diff --git a/addon/-private/transforms.js b/addon/-private/transforms.js deleted file mode 100644 index 6658a7a6cea..00000000000 --- a/addon/-private/transforms.js +++ /dev/null @@ -1,13 +0,0 @@ -import Transform from "ember-data/transform"; -import NumberTransform from "ember-data/-private/transforms/number"; -import DateTransform from "ember-data/-private/transforms/date"; -import StringTransform from "ember-data/-private/transforms/string"; -import BooleanTransform from "ember-data/-private/transforms/boolean"; - -export { - Transform, - NumberTransform, - DateTransform, - StringTransform, - BooleanTransform -}; diff --git a/addon/index.js b/addon/index.js index 67d6622abb6..13058b06052 100644 --- a/addon/index.js +++ b/addon/index.js @@ -31,7 +31,11 @@ import { Errors, RootState, Model, - Store + Store, + DateTransform, + NumberTransform, + StringTransform, + BooleanTransform } from './-private'; import Adapter from "./adapter"; @@ -68,14 +72,7 @@ import ManyArray from "./-private/system/many-array"; import RecordArrayManager from "./-private/system/record-array-manager"; import BuildURLMixin from "./-private/adapters/build-url-mixin"; -import { - Transform, - DateTransform, - NumberTransform, - StringTransform, - BooleanTransform -} from "./-private/transforms"; - +import Transform from './transform'; import { hasMany, belongsTo } from "./relationships"; import setupContainer from "./setup-container"; import initializeStoreService from './-private/instance-initializers/initialize-store-service'; From 9c5557c8932232393bff80d741e0b4259133de51 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 13 Apr 2017 21:41:17 -0700 Subject: [PATCH 1907/2527] unwinds 'features' (isEnabled) but hits a cycle --- CONTRIBUTING.md | 6 +-- addon/-private/index.js | 36 ++++++++++++- addon/-private/system/debug/debug-adapter.js | 2 +- addon/adapters/json-api.js | 2 +- addon/adapters/rest.js | 4 +- addon/index.js | 52 +++++++++---------- addon/relationships.js | 10 +--- addon/serializers/json-api.js | 3 +- addon/serializers/json.js | 5 +- addon/serializers/rest.js | 5 +- .../adapter/build-url-mixin-test.js | 2 +- .../adapter/json-api-adapter-test.js | 2 +- .../integration/adapter/rest-adapter-test.js | 2 +- .../integration/references/belongs-to-test.js | 2 +- tests/integration/references/has-many-test.js | 2 +- .../serializers/json-api-serializer-test.js | 2 +- .../serializers/json-serializer-test.js | 2 +- .../serializers/rest-serializer-test.js | 3 +- tests/integration/store-test.js | 2 +- tests/unit/adapter-errors-test.js | 2 +- tests/unit/adapters/rest-adapter/ajax-test.js | 2 +- .../group-records-for-find-many-test.js | 2 +- tests/unit/model-test.js | 2 +- tests/unit/model/rollback-attributes-test.js | 2 +- tests/unit/store/push-test.js | 2 +- tests/unit/store/serialize-test.js | 2 +- 26 files changed, 84 insertions(+), 74 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2046b77b2ba..c35c9bfdfac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -82,11 +82,11 @@ production builds automatically. Give it a default of `null` so it will not be used in production builds. -2. Import `isEnabled` from `ember-data/-private/features`, wrapping any new +2. Import `isEnabled` from `ember-data/-private`, wrapping any new code with your feature: ```js - import isEnabled from 'ember-data/-private/features'; + import { isEnabled } from 'ember-data/-private'; if (isEnabled('ds-mynew-feature')) { // ... any additional code @@ -99,7 +99,7 @@ production builds automatically. feature flag. ```js - import isEnabled from 'ember-data/-private/features'; + import { isEnabled } from 'ember-data/-private'; if (isEnabled('ds-mynew-feature')) { test('test for new feature', function(assert) { diff --git a/addon/-private/index.js b/addon/-private/index.js index 900083189cc..174f5386515 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -3,13 +3,45 @@ export { default as Model } from './system/model/model'; export { default as Errors } from './system/model/errors'; export { default as Store } from './system/store'; export { default as DS } from './core'; +export { default as belongsTo } from './system/relationships/belongs-to'; +export { default as hasMany } from './system/relationships/has-many'; +export { default as BuildURLMixin } from './adapters/build-url-mixin'; +export { default as Snapshot } from './system/snapshot'; -// should be moved into public +// maybe public ? +export { default as normalizeModelName } from './system/normalize-model-name'; +export { modelHasAttributeOrRelationshipNamedType } from './utils'; +export { default as coerceId } from './system/coerce-id'; +export { default as parseResponseHeaders } from './utils/parse-response-headers'; + +// should be moved into public ? export { default as NumberTransform } from './transforms/number'; export { default as DateTransform } from './transforms/date'; export { default as StringTransform } from './transforms/string'; export { default as BooleanTransform } from './transforms/boolean'; -// should be private +// should be private ? export { default as RootState } from './system/model/states'; export { default as global } from './global'; +export { default as isEnabled } from './features'; +export { default as InternalModel } from './system/model/internal-model'; + +export { + PromiseArray, + PromiseObject, + PromiseManyArray +} from './system/promise-proxies'; + +export { + RecordArray, + FilteredRecordArray, + AdapterPopulatedRecordArray +} from './system/record-arrays'; + +export { default as ManyArray } from './system/many-array'; +export { default as RecordArrayManager } from './system/record-array-manager'; +export { default as initializeStoreService } from './instance-initializers/initialize-store-service'; +export { default as Relationship } from './system/relationships/state/relationship'; + +// Should be a different Repo ? +export { default as DebugAdapter } from './system/debug/debug-adapter'; diff --git a/addon/-private/system/debug/debug-adapter.js b/addon/-private/system/debug/debug-adapter.js index 9df2fabf50d..63df01ee251 100644 --- a/addon/-private/system/debug/debug-adapter.js +++ b/addon/-private/system/debug/debug-adapter.js @@ -2,7 +2,7 @@ @module ember-data */ import Ember from 'ember'; -import Model from "../../../model"; +import Model from '../model/model'; const capitalize = Ember.String.capitalize; const underscore = Ember.String.underscore; const { assert, get } = Ember; diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index e3c8e3e7515..6d7eff4c8b5 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -5,7 +5,7 @@ import Ember from 'ember'; import RESTAdapter from "./rest"; -import isEnabled from '../-private/features'; +import { isEnabled } from '../-private'; import { instrument, deprecate } from 'ember-data/-debug'; /** diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 69da9732c12..9757afe7e6e 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -16,10 +16,8 @@ import { TimeoutError, AbortError } from './errors'; -import BuildURLMixin from "../-private/adapters/build-url-mixin"; -import isEnabled from '../-private/features'; +import { parseResponseHeaders, BuildURLMixin, isEnabled } from '../-private'; import { instrument, runInDebug, warn, deprecate } from 'ember-data/-debug'; -import parseResponseHeaders from '../-private/utils/parse-response-headers'; const { MapWithDefault, diff --git a/addon/index.js b/addon/index.js index 13058b06052..369e193b080 100644 --- a/addon/index.js +++ b/addon/index.js @@ -13,34 +13,38 @@ if (Ember.VERSION.match(/^1\.([0-9]|1[0-2])\./)) { ". Please upgrade your version of Ember, then upgrade Ember Data."); } -import normalizeModelName from "./-private/system/normalize-model-name"; -import Snapshot from "./-private/system/snapshot"; import InternalModel from "./-private/system/model/internal-model"; -import DebugAdapter from './-private/system/debug/debug-adapter'; -import isEnabled from "./-private/features"; - -import { - PromiseArray, - PromiseObject, - PromiseManyArray -} from "./-private/system/promise-proxies"; import { + Snapshot, + DebugAdapter, DS, + BuildURLMixin, + belongsTo, + hasMany, global, + isEnabled, Errors, RootState, Model, Store, + normalizeModelName, DateTransform, NumberTransform, StringTransform, - BooleanTransform + BooleanTransform, + PromiseArray, + PromiseObject, + PromiseManyArray, + RecordArray, + FilteredRecordArray, + AdapterPopulatedRecordArray, + ManyArray, + RecordArrayManager, + Relationship, + initializeStoreService } from './-private'; -import Adapter from "./adapter"; -import Serializer from "./serializer"; - import { AdapterError, InvalidError, @@ -56,28 +60,20 @@ import { } from "./adapters/errors"; import "ember-inflector"; +import setupContainer from "./setup-container"; + +import Adapter from "./adapter"; import JSONAPIAdapter from './adapters/json-api'; import RESTAdapter from './adapters/rest'; + +import Serializer from "./serializer"; import JSONAPISerializer from './serializers/json-api'; import JSONSerializer from './serializers/json'; import RESTSerializer from './serializers/rest'; -import EmbeddedRecordsMixin from "./serializers/embedded-records-mixin"; -import { - RecordArray, - FilteredRecordArray, - AdapterPopulatedRecordArray -} from "./-private/system/record-arrays"; -import ManyArray from "./-private/system/many-array"; -import RecordArrayManager from "./-private/system/record-array-manager"; -import BuildURLMixin from "./-private/adapters/build-url-mixin"; +import EmbeddedRecordsMixin from "./serializers/embedded-records-mixin"; import Transform from './transform'; -import { hasMany, belongsTo } from "./relationships"; -import setupContainer from "./setup-container"; -import initializeStoreService from './-private/instance-initializers/initialize-store-service'; - -import Relationship from "./-private/system/relationships/state/relationship"; import attr from './attr'; DS.Store = Store; diff --git a/addon/relationships.js b/addon/relationships.js index d0ace3b4140..571ad7d56b0 100644 --- a/addon/relationships.js +++ b/addon/relationships.js @@ -1,12 +1,4 @@ /** @module ember-data */ - -import belongsTo from "./-private/system/relationships/belongs-to"; -import hasMany from "./-private/system/relationships/has-many"; - -export { - belongsTo, - hasMany -}; - +export { belongsTo, hasMany } from './-private'; diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 16870a1dcf4..e22a6160f73 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -6,8 +6,7 @@ import Ember from 'ember'; import { pluralize, singularize } from 'ember-inflector'; import { assert, deprecate, runInDebug, warn } from 'ember-data/-debug'; import JSONSerializer from './json'; -import normalizeModelName from '../-private/system/normalize-model-name'; -import isEnabled from '../-private/features'; +import { normalizeModelName, isEnabled } from '../-private'; const dasherize = Ember.String.dasherize; diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 7fd11611b01..75965ef4492 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1,10 +1,7 @@ import Ember from 'ember'; import { assert, deprecate, warn } from 'ember-data/-debug'; import Serializer from "../serializer"; -import coerceId from "../-private/system/coerce-id"; -import normalizeModelName from "../-private/system/normalize-model-name"; -import { modelHasAttributeOrRelationshipNamedType } from "../-private/utils"; -import isEnabled from '../-private/features'; +import { coerceId, modelHasAttributeOrRelationshipNamedType, normalizeModelName, isEnabled } from '../-private'; import { getOwner diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 3331217e5be..5f4e3397cb3 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -6,10 +6,7 @@ import Ember from 'ember'; import { singularize } from "ember-inflector"; import { assert, deprecate, runInDebug, warn } from 'ember-data/-debug'; import JSONSerializer from "../serializers/json"; -import normalizeModelName from "../-private/system/normalize-model-name"; -import coerceId from "../-private/system/coerce-id"; -import { modelHasAttributeOrRelationshipNamedType } from "../-private/utils"; -import isEnabled from '../-private/features'; +import { coerceId, modelHasAttributeOrRelationshipNamedType, normalizeModelName, isEnabled } from '../-private'; let camelize = Ember.String.camelize; diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index 7409788f5bc..59a743e6824 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -1,6 +1,6 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; import {module, test} from 'qunit'; diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index 21eb5368526..dcf9ab82661 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -5,7 +5,7 @@ import {module, test} from 'qunit'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; var env, store, adapter; var passedUrl, passedVerb, passedHash; diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 2bbe1374515..ca66a32330c 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -7,7 +7,7 @@ import {module, test} from 'qunit'; import Pretender from "pretender"; import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; var env, store, adapter, Post, Comment, SuperUser; var passedUrl, passedVerb, passedHash; diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index e69b67540e0..af3cc59f451 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -2,7 +2,7 @@ import DS from 'ember-data'; import Ember from 'ember'; import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; import { module, test } from 'qunit'; var get = Ember.get; diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 38af4b05fb0..374747cad17 100644 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -1,7 +1,7 @@ import DS from 'ember-data'; import Ember from 'ember'; import setupStore from 'dummy/tests/helpers/store'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 38efcb85d2b..8c294ba4951 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -4,7 +4,7 @@ import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; import DS from 'ember-data'; diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index b975ba79e1a..c5548b82757 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -1,6 +1,6 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index a5c37866c56..4adc1591bf4 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -3,8 +3,7 @@ import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; - -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; import DS from 'ember-data'; diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 7506ba42f50..4d9266ee147 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -5,7 +5,7 @@ import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; var store, env; diff --git a/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js index 03198a589a9..9e19c9a7c47 100644 --- a/tests/unit/adapter-errors-test.js +++ b/tests/unit/adapter-errors-test.js @@ -1,6 +1,6 @@ import Ember from 'ember'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; diff --git a/tests/unit/adapters/rest-adapter/ajax-test.js b/tests/unit/adapters/rest-adapter/ajax-test.js index b3196c504c3..1bbed398c3c 100644 --- a/tests/unit/adapters/rest-adapter/ajax-test.js +++ b/tests/unit/adapters/rest-adapter/ajax-test.js @@ -4,7 +4,7 @@ import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; var Person, Place, store, adapter, env; const { run } = Ember; diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 7a586ccf58f..5010adbcb10 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -4,7 +4,7 @@ import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; let GroupsAdapter, store, requests; let maxLength; diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 297412539a7..e0acbf69524 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -4,7 +4,7 @@ import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; import { parseDate } from "ember-data/-private/ext/date"; const { get, set, run } = Ember; diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index 5313a48ad7a..b884d133f89 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -4,7 +4,7 @@ import Ember from 'ember'; import {module, test} from 'qunit'; import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; let env, store, Person; const { run } = Ember; diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index b725de1c3d2..a3c51f88660 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -6,7 +6,7 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; let env, store, Person, PhoneNumber, Post; const { attr, hasMany, belongsTo } = DS; diff --git a/tests/unit/store/serialize-test.js b/tests/unit/store/serialize-test.js index 231f076a81c..1967d7ac5ac 100644 --- a/tests/unit/store/serialize-test.js +++ b/tests/unit/store/serialize-test.js @@ -4,7 +4,7 @@ import attr from 'ember-data/attr'; import Model from 'ember-data/model'; import { createStore } from 'dummy/tests/helpers/store'; import Ember from 'ember'; -import isEnabled from 'ember-data/-private/features'; +import { isEnabled } from 'ember-data/-private'; const { run } = Ember; From 24f41209b7ab9978bcdf029e50e3e62564d0b50f Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 14 Apr 2017 01:02:00 -0700 Subject: [PATCH 1908/2527] down to just circular refs and instance initializers --- DEBUG-rollup-tree/-private.js | 13758 ++++++++++++++++ addon/-private/adapters/errors.js | 478 + addon/-private/index.js | 18 +- addon/-private/initializers/data-adapter.js | 12 - .../-private/initializers/store-injections.js | 15 - addon/-private/initializers/store.js | 43 - addon/-private/initializers/transforms.js | 18 - addon/-private/system/model/internal-model.js | 4 +- addon/-private/system/model/model.js | 3 +- .../-private/system/references/belongs-to.js | 2 +- addon/-private/system/store.js | 4 +- addon/-private/system/store/finders.js | 11 +- addon/-private/transforms/boolean.js | 2 +- addon/-private/transforms/date.js | 4 +- addon/-private/transforms/number.js | 2 +- addon/-private/transforms/string.js | 2 +- addon/-private/transforms/transform.js | 108 + addon/adapters/errors.js | 490 +- addon/adapters/rest.js | 6 +- addon/index.js | 13 +- .../initialize-store-service.js | 0 addon/serializers/json.js | 13 +- addon/setup-container.js | 95 +- addon/transform.js | 109 +- app/instance-initializers/ember-data.js | 2 +- index.js | 24 +- tests/unit/transform/date-test.js | 2 +- .../unit/utils/parse-response-headers-test.js | 2 +- 28 files changed, 14519 insertions(+), 721 deletions(-) create mode 100644 DEBUG-rollup-tree/-private.js create mode 100644 addon/-private/adapters/errors.js delete mode 100644 addon/-private/initializers/data-adapter.js delete mode 100644 addon/-private/initializers/store-injections.js delete mode 100644 addon/-private/initializers/store.js delete mode 100644 addon/-private/initializers/transforms.js create mode 100644 addon/-private/transforms/transform.js rename addon/{-private => }/instance-initializers/initialize-store-service.js (100%) diff --git a/DEBUG-rollup-tree/-private.js b/DEBUG-rollup-tree/-private.js new file mode 100644 index 00000000000..9548088ca87 --- /dev/null +++ b/DEBUG-rollup-tree/-private.js @@ -0,0 +1,13758 @@ +import Ember from 'ember'; +import { assert, assertPolymorphicType, deprecate, instrument, runInDebug, warn } from 'ember-data/-debug'; +import { singularize } from 'ember-inflector'; +import { InvalidError } from 'ember-data/adapters/errors'; +import VERSION from 'ember-data/version'; + +const { get: get$1 , RSVP: { Promise }} = Ember; + +/** + A `PromiseArray` is an object that acts like both an `Ember.Array` + and a promise. When the promise is resolved the resulting value + will be set to the `PromiseArray`'s `content` property. This makes + it easy to create data bindings with the `PromiseArray` that will be + updated when the promise resolves. + + For more information see the [Ember.PromiseProxyMixin + documentation](/api/classes/Ember.PromiseProxyMixin.html). + + Example + + ```javascript + let promiseArray = DS.PromiseArray.create({ + promise: $.getJSON('/some/remote/data.json') + }); + + promiseArray.get('length'); // 0 + + promiseArray.then(function() { + promiseArray.get('length'); // 100 + }); + ``` + + @class PromiseArray + @namespace DS + @extends Ember.ArrayProxy + @uses Ember.PromiseProxyMixin +*/ +const PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin); + +/** + A `PromiseObject` is an object that acts like both an `Ember.Object` + and a promise. When the promise is resolved, then the resulting value + will be set to the `PromiseObject`'s `content` property. This makes + it easy to create data bindings with the `PromiseObject` that will + be updated when the promise resolves. + + For more information see the [Ember.PromiseProxyMixin + documentation](/api/classes/Ember.PromiseProxyMixin.html). + + Example + + ```javascript + let promiseObject = DS.PromiseObject.create({ + promise: $.getJSON('/some/remote/data.json') + }); + + promiseObject.get('name'); // null + + promiseObject.then(function() { + promiseObject.get('name'); // 'Tomster' + }); + ``` + + @class PromiseObject + @namespace DS + @extends Ember.ObjectProxy + @uses Ember.PromiseProxyMixin +*/ +let PromiseObject = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin); + +function promiseObject(promise, label) { + return PromiseObject.create({ + promise: Promise.resolve(promise, label) + }); +} + +function promiseArray(promise, label) { + return PromiseArray.create({ + promise: Promise.resolve(promise, label) + }); +} + +/** + A PromiseManyArray is a PromiseArray that also proxies certain method calls + to the underlying manyArray. + Right now we proxy: + + * `reload()` + * `createRecord()` + * `on()` + * `one()` + * `trigger()` + * `off()` + * `has()` + + @class PromiseManyArray + @namespace DS + @extends Ember.ArrayProxy +*/ + +function proxyToContent(method) { + return function() { + return get$1(this, 'content')[method](...arguments); + }; +} + +const PromiseManyArray = PromiseArray.extend({ + reload() { + assert('You are trying to reload an async manyArray before it has been created', get$1(this, 'content')); + this.set('promise', this.get('content').reload()); + return this; + }, + + createRecord: proxyToContent('createRecord'), + + on: proxyToContent('on'), + + one: proxyToContent('one'), + + trigger: proxyToContent('trigger'), + + off: proxyToContent('off'), + + has: proxyToContent('has') +}); + +const get$2 = Ember.get; +const set = Ember.set; +const isEmpty = Ember.isEmpty; +const makeArray = Ember.makeArray; + +const MapWithDefault = Ember.MapWithDefault; + +/** +@module ember-data +*/ + +/** + Holds validation errors for a given record, organized by attribute names. + + Every `DS.Model` has an `errors` property that is an instance of + `DS.Errors`. This can be used to display validation error + messages returned from the server when a `record.save()` rejects. + + For Example, if you had a `User` model that looked like this: + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + username: DS.attr('string'), + email: DS.attr('string') + }); + ``` + And you attempted to save a record that did not validate on the backend: + + ```javascript + let user = store.createRecord('user', { + username: 'tomster', + email: 'invalidEmail' + }); + user.save(); + ``` + + Your backend would be expected to return an error response that described + the problem, so that error messages can be generated on the app. + + API responses will be translated into instances of `DS.Errors` differently, + depending on the specific combination of adapter and serializer used. You + may want to check the documentation or the source code of the libraries + that you are using, to know how they expect errors to be communicated. + + Errors can be displayed to the user by accessing their property name + to get an array of all the error objects for that property. Each + error object is a JavaScript object with two keys: + + - `message` A string containing the error message from the backend + - `attribute` The name of the property associated with this error message + + ```handlebars + + {{#each model.errors.username as |error|}} +
      + {{error.message}} +
      + {{/each}} + + + {{#each model.errors.email as |error|}} +
      + {{error.message}} +
      + {{/each}} + ``` + + You can also access the special `messages` property on the error + object to get an array of all the error strings. + + ```handlebars + {{#each model.errors.messages as |message|}} +
      + {{message}} +
      + {{/each}} + ``` + + @class Errors + @namespace DS + @extends Ember.Object + @uses Ember.Enumerable + @uses Ember.Evented + */ +var Errors = Ember.ArrayProxy.extend(Ember.Evented, { + /** + Register with target handler + + @method registerHandlers + @param {Object} target + @param {Function} becameInvalid + @param {Function} becameValid + @deprecated + */ + registerHandlers(target, becameInvalid, becameValid) { + deprecate( + `Record errors will no longer be evented.`, false, { + id: 'ds.errors.registerHandlers', + until: '3.0.0' + }); + + this._registerHandlers(target, becameInvalid, becameValid); + }, + + + /** + Register with target handler + + @method _registerHandlers + @private + */ + _registerHandlers(target, becameInvalid, becameValid) { + this.on('becameInvalid', target, becameInvalid); + this.on('becameValid', target, becameValid); + }, + + + /** + @property errorsByAttributeName + @type {Ember.MapWithDefault} + @private + */ + errorsByAttributeName: Ember.computed(function() { + return MapWithDefault.create({ + defaultValue() { + return Ember.A(); + } + }); + }), + + /** + Returns errors for a given attribute + + ```javascript + let user = store.createRecord('user', { + username: 'tomster', + email: 'invalidEmail' + }); + user.save().catch(function(){ + user.get('errors').errorsFor('email'); // returns: + // [{attribute: "email", message: "Doesn't look like a valid email."}] + }); + ``` + + @method errorsFor + @param {String} attribute + @return {Array} + */ + errorsFor(attribute) { + return get$2(this, 'errorsByAttributeName').get(attribute); + }, + + /** + An array containing all of the error messages for this + record. This is useful for displaying all errors to the user. + + ```handlebars + {{#each model.errors.messages as |message|}} +
      + {{message}} +
      + {{/each}} + ``` + + @property messages + @type {Array} + */ + messages: Ember.computed.mapBy('content', 'message'), + + /** + @property content + @type {Array} + @private + */ + content: Ember.computed(function() { + return Ember.A(); + }), + + /** + @method unknownProperty + @private + */ + unknownProperty(attribute) { + let errors = this.errorsFor(attribute); + if (isEmpty(errors)) { return null; } + return errors; + }, + + /** + Total number of errors. + + @property length + @type {Number} + @readOnly + */ + + /** + @property isEmpty + @type {Boolean} + @readOnly + */ + isEmpty: Ember.computed.not('length').readOnly(), + + /** + Adds error messages to a given attribute and sends + `becameInvalid` event to the record. + + Example: + + ```javascript + if (!user.get('username') { + user.get('errors').add('username', 'This field is required'); + } + ``` + + @method add + @param {String} attribute + @param {(Array|String)} messages + @deprecated + */ + add(attribute, messages) { + warn(`Interacting with a record errors object will no longer change the record state.`, false, { + id: 'ds.errors.add' + }); + + let wasEmpty = get$2(this, 'isEmpty'); + + this._add(attribute, messages); + + if (wasEmpty && !get$2(this, 'isEmpty')) { + this.trigger('becameInvalid'); + } + }, + + + /** + Adds error messages to a given attribute without sending event. + + @method _add + @private + */ + _add(attribute, messages) { + messages = this._findOrCreateMessages(attribute, messages); + this.addObjects(messages); + get$2(this, 'errorsByAttributeName').get(attribute).addObjects(messages); + + this.notifyPropertyChange(attribute); + }, + + /** + @method _findOrCreateMessages + @private + */ + _findOrCreateMessages(attribute, messages) { + let errors = this.errorsFor(attribute); + let messagesArray = makeArray(messages); + let _messages = new Array(messagesArray.length); + + for (let i = 0; i < messagesArray.length; i++) { + let message = messagesArray[i]; + let err = errors.findBy('message', message); + if (err) { + _messages[i] = err; + } else { + _messages[i] = { + attribute: attribute, + message: message + }; + } + } + + return _messages; + }, + + /** + Removes all error messages from the given attribute and sends + `becameValid` event to the record if there no more errors left. + + Example: + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + email: DS.attr('string'), + twoFactorAuth: DS.attr('boolean'), + phone: DS.attr('string') + }); + ``` + + ```app/routes/user/edit.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + actions: { + save: function(user) { + if (!user.get('twoFactorAuth')) { + user.get('errors').remove('phone'); + } + user.save(); + } + } + }); + ``` + + @method remove + @param {String} attribute + @deprecated + */ + remove(attribute) { + warn(`Interacting with a record errors object will no longer change the record state.`, false, { + id: 'ds.errors.remove' + }); + + if (get$2(this, 'isEmpty')) { return; } + + this._remove(attribute); + + if (get$2(this, 'isEmpty')) { + this.trigger('becameValid'); + } + }, + + /** + Removes all error messages from the given attribute without sending event. + + @method _remove + @private + */ + _remove(attribute) { + if (get$2(this, 'isEmpty')) { return; } + + let content = this.rejectBy('attribute', attribute); + set(this, 'content', content); + get$2(this, 'errorsByAttributeName').delete(attribute); + + this.notifyPropertyChange(attribute); + }, + + /** + Removes all error messages and sends `becameValid` event + to the record. + + Example: + + ```app/routes/user/edit.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + actions: { + retrySave: function(user) { + user.get('errors').clear(); + user.save(); + } + } + }); + ``` + + @method clear + @deprecated + */ + clear() { + warn(`Interacting with a record errors object will no longer change the record state.`, false, { + id: 'ds.errors.clear' + }); + + if (get$2(this, 'isEmpty')) { return; } + + this._clear(); + this.trigger('becameValid'); + }, + + + /** + Removes all error messages. + to the record. + + @method _clear + @private + */ + _clear() { + if (get$2(this, 'isEmpty')) { return; } + + let errorsByAttributeName = get$2(this, 'errorsByAttributeName'); + let attributes = Ember.A(); + + errorsByAttributeName.forEach(function(_, attribute) { + attributes.push(attribute); + }); + + errorsByAttributeName.clear(); + attributes.forEach(function(attribute) { + this.notifyPropertyChange(attribute); + }, this); + + Ember.ArrayProxy.prototype.clear.call(this); + }, + + + /** + Checks if there is error messages for the given attribute. + + ```app/routes/user/edit.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + actions: { + save: function(user) { + if (user.get('errors').has('email')) { + return alert('Please update your email before attempting to save.'); + } + user.save(); + } + } + }); + ``` + + @method has + @param {String} attribute + @return {Boolean} true if there some errors on given attribute + */ + has(attribute) { + return !isEmpty(this.errorsFor(attribute)); + } +}); + +function isEnabled() { + return Ember.FEATURES.isEnabled(...arguments); +} + +/** + @module ember-data +*/ +/* + This file encapsulates the various states that a record can transition + through during its lifecycle. +*/ +/** + ### State + + Each record has a `currentState` property that explicitly tracks what + state a record is in at any given time. For instance, if a record is + newly created and has not yet been sent to the adapter to be saved, + it would be in the `root.loaded.created.uncommitted` state. If a + record has had local modifications made to it that are in the + process of being saved, the record would be in the + `root.loaded.updated.inFlight` state. (This state paths will be + explained in more detail below.) + + Events are sent by the record or its store to the record's + `currentState` property. How the state reacts to these events is + dependent on which state it is in. In some states, certain events + will be invalid and will cause an exception to be raised. + + States are hierarchical and every state is a substate of the + `RootState`. For example, a record can be in the + `root.deleted.uncommitted` state, then transition into the + `root.deleted.inFlight` state. If a child state does not implement + an event handler, the state manager will attempt to invoke the event + on all parent states until the root state is reached. The state + hierarchy of a record is described in terms of a path string. You + can determine a record's current state by getting the state's + `stateName` property: + + ```javascript + record.get('currentState.stateName'); + //=> "root.created.uncommitted" + ``` + + The hierarchy of valid states that ship with ember data looks like + this: + + ```text + * root + * deleted + * saved + * uncommitted + * inFlight + * empty + * loaded + * created + * uncommitted + * inFlight + * saved + * updated + * uncommitted + * inFlight + * loading + ``` + + The `DS.Model` states are themselves stateless. What that means is + that, the hierarchical states that each of *those* points to is a + shared data structure. For performance reasons, instead of each + record getting its own copy of the hierarchy of states, each record + points to this global, immutable shared instance. How does a state + know which record it should be acting on? We pass the record + instance into the state's event handlers as the first argument. + + The record passed as the first parameter is where you should stash + state about the record if needed; you should never store data on the state + object itself. + + ### Events and Flags + + A state may implement zero or more events and flags. + + #### Events + + Events are named functions that are invoked when sent to a record. The + record will first look for a method with the given name on the + current state. If no method is found, it will search the current + state's parent, and then its grandparent, and so on until reaching + the top of the hierarchy. If the root is reached without an event + handler being found, an exception will be raised. This can be very + helpful when debugging new features. + + Here's an example implementation of a state with a `myEvent` event handler: + + ```javascript + aState: DS.State.create({ + myEvent: function(manager, param) { + console.log("Received myEvent with", param); + } + }) + ``` + + To trigger this event: + + ```javascript + record.send('myEvent', 'foo'); + //=> "Received myEvent with foo" + ``` + + Note that an optional parameter can be sent to a record's `send()` method, + which will be passed as the second parameter to the event handler. + + Events should transition to a different state if appropriate. This can be + done by calling the record's `transitionTo()` method with a path to the + desired state. The state manager will attempt to resolve the state path + relative to the current state. If no state is found at that path, it will + attempt to resolve it relative to the current state's parent, and then its + parent, and so on until the root is reached. For example, imagine a hierarchy + like this: + + * created + * uncommitted <-- currentState + * inFlight + * updated + * inFlight + + If we are currently in the `uncommitted` state, calling + `transitionTo('inFlight')` would transition to the `created.inFlight` state, + while calling `transitionTo('updated.inFlight')` would transition to + the `updated.inFlight` state. + + Remember that *only events* should ever cause a state transition. You should + never call `transitionTo()` from outside a state's event handler. If you are + tempted to do so, create a new event and send that to the state manager. + + #### Flags + + Flags are Boolean values that can be used to introspect a record's current + state in a more user-friendly way than examining its state path. For example, + instead of doing this: + + ```javascript + var statePath = record.get('stateManager.currentPath'); + if (statePath === 'created.inFlight') { + doSomething(); + } + ``` + + You can say: + + ```javascript + if (record.get('isNew') && record.get('isSaving')) { + doSomething(); + } + ``` + + If your state does not set a value for a given flag, the value will + be inherited from its parent (or the first place in the state hierarchy + where it is defined). + + The current set of flags are defined below. If you want to add a new flag, + in addition to the area below, you will also need to declare it in the + `DS.Model` class. + + + * [isEmpty](DS.Model.html#property_isEmpty) + * [isLoading](DS.Model.html#property_isLoading) + * [isLoaded](DS.Model.html#property_isLoaded) + * [hasDirtyAttributes](DS.Model.html#property_hasDirtyAttributes) + * [isSaving](DS.Model.html#property_isSaving) + * [isDeleted](DS.Model.html#property_isDeleted) + * [isNew](DS.Model.html#property_isNew) + * [isValid](DS.Model.html#property_isValid) + + @namespace DS + @class RootState +*/ + +function didSetProperty(internalModel, context) { + if (context.value === context.originalValue) { + delete internalModel._attributes[context.name]; + internalModel.send('propertyWasReset', context.name); + } else if (context.value !== context.oldValue) { + internalModel.send('becomeDirty'); + } + + internalModel.updateRecordArrays(); +} + +// Implementation notes: +// +// Each state has a boolean value for all of the following flags: +// +// * isLoaded: The record has a populated `data` property. When a +// record is loaded via `store.find`, `isLoaded` is false +// until the adapter sets it. When a record is created locally, +// its `isLoaded` property is always true. +// * isDirty: The record has local changes that have not yet been +// saved by the adapter. This includes records that have been +// created (but not yet saved) or deleted. +// * isSaving: The record has been committed, but +// the adapter has not yet acknowledged that the changes have +// been persisted to the backend. +// * isDeleted: The record was marked for deletion. When `isDeleted` +// is true and `isDirty` is true, the record is deleted locally +// but the deletion was not yet persisted. When `isSaving` is +// true, the change is in-flight. When both `isDirty` and +// `isSaving` are false, the change has persisted. +// * isNew: The record was created on the client and the adapter +// did not yet report that it was successfully saved. +// * isValid: The adapter did not report any server-side validation +// failures. + +// The dirty state is a abstract state whose functionality is +// shared between the `created` and `updated` states. +// +// The deleted state shares the `isDirty` flag with the +// subclasses of `DirtyState`, but with a very different +// implementation. +// +// Dirty states have three child states: +// +// `uncommitted`: the store has not yet handed off the record +// to be saved. +// `inFlight`: the store has handed off the record to be saved, +// but the adapter has not yet acknowledged success. +// `invalid`: the record has invalid information and cannot be +// sent to the adapter yet. +const DirtyState = { + initialState: 'uncommitted', + + // FLAGS + isDirty: true, + + // SUBSTATES + + // When a record first becomes dirty, it is `uncommitted`. + // This means that there are local pending changes, but they + // have not yet begun to be saved, and are not invalid. + uncommitted: { + // EVENTS + didSetProperty, + + //TODO(Igor) reloading now triggers a + //loadingData event, though it seems fine? + loadingData() { }, + + propertyWasReset(internalModel, name) { + if (!internalModel.hasChangedAttributes()) { internalModel.send('rolledBack'); } + }, + + pushedData(internalModel) { + let token = heimdall.start('stats.uncommitted.pushedData'); + internalModel.updateChangedAttributes(); + + if (!internalModel.hasChangedAttributes()) { + internalModel.transitionTo('loaded.saved'); + } + heimdall.stop(token); + }, + + becomeDirty() {}, + + willCommit(internalModel) { + internalModel.transitionTo('inFlight'); + }, + + reloadRecord(internalModel, resolve) { + resolve(internalModel.store._reloadRecord(internalModel)); + }, + + rolledBack(internalModel) { + internalModel.transitionTo('loaded.saved'); + }, + + becameInvalid(internalModel) { + internalModel.transitionTo('invalid'); + }, + + rollback(internalModel) { + internalModel.rollbackAttributes(); + internalModel.triggerLater('ready'); + } + }, + + // Once a record has been handed off to the adapter to be + // saved, it is in the 'in flight' state. Changes to the + // record cannot be made during this window. + inFlight: { + // FLAGS + isSaving: true, + + // EVENTS + didSetProperty, + becomeDirty() { }, + pushedData() { }, + + unloadRecord: assertAgainstUnloadRecord, + + // TODO: More robust semantics around save-while-in-flight + willCommit() { }, + + didCommit(internalModel) { + internalModel.transitionTo('saved'); + internalModel.send('invokeLifecycleCallbacks', this.dirtyType); + }, + + becameInvalid(internalModel) { + internalModel.transitionTo('invalid'); + internalModel.send('invokeLifecycleCallbacks'); + }, + + becameError(internalModel) { + internalModel.transitionTo('uncommitted'); + internalModel.triggerLater('becameError', internalModel); + } + }, + + // A record is in the `invalid` if the adapter has indicated + // the the record failed server-side invalidations. + invalid: { + // FLAGS + isValid: false, + + // EVENTS + deleteRecord(internalModel) { + internalModel.transitionTo('deleted.uncommitted'); + }, + + didSetProperty(internalModel, context) { + internalModel.removeErrorMessageFromAttribute(context.name); + + didSetProperty(internalModel, context); + + if (!internalModel.hasErrors()) { + this.becameValid(internalModel); + } + }, + + becameInvalid() { }, + becomeDirty() { }, + pushedData() { }, + + willCommit(internalModel) { + internalModel.clearErrorMessages(); + internalModel.transitionTo('inFlight'); + }, + + rolledBack(internalModel) { + internalModel.clearErrorMessages(); + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('ready'); + }, + + becameValid(internalModel) { + internalModel.transitionTo('uncommitted'); + }, + + invokeLifecycleCallbacks(internalModel) { + internalModel.triggerLater('becameInvalid', internalModel); + } + } +}; + +// The created and updated states are created outside the state +// chart so we can reopen their substates and add mixins as +// necessary. + +function deepClone(object) { + const clone = {}; + let value; + + for (let prop in object) { + value = object[prop]; + if (value && typeof value === 'object') { + clone[prop] = deepClone(value); + } else { + clone[prop] = value; + } + } + + return clone; +} + +function mixin(original, hash) { + for (let prop in hash) { + original[prop] = hash[prop]; + } + + return original; +} + +function dirtyState(options) { + var newState = deepClone(DirtyState); + return mixin(newState, options); +} + +const createdState = dirtyState({ + dirtyType: 'created', + // FLAGS + isNew: true +}); + +createdState.invalid.rolledBack = function(internalModel) { + internalModel.transitionTo('deleted.saved'); +}; + +createdState.uncommitted.rolledBack = function(internalModel) { + internalModel.transitionTo('deleted.saved'); +}; + +const updatedState = dirtyState({ + dirtyType: 'updated' +}); + +function createdStateDeleteRecord(internalModel) { + internalModel.transitionTo('deleted.saved'); + internalModel.send('invokeLifecycleCallbacks'); +} + +createdState.uncommitted.deleteRecord = createdStateDeleteRecord; + +createdState.invalid.deleteRecord = createdStateDeleteRecord; + +createdState.uncommitted.rollback = function(internalModel) { + DirtyState.uncommitted.rollback.apply(this, arguments); + internalModel.transitionTo('deleted.saved'); +}; + +createdState.uncommitted.pushedData = function(internalModel) { + internalModel.transitionTo('loaded.updated.uncommitted'); + internalModel.triggerLater('didLoad'); +}; + +createdState.uncommitted.propertyWasReset = function() {}; + +function assertAgainstUnloadRecord(internalModel) { + assert("You can only unload a record which is not inFlight. `" + internalModel + "`", false); +} + +updatedState.inFlight.unloadRecord = assertAgainstUnloadRecord; + +updatedState.uncommitted.deleteRecord = function(internalModel) { + internalModel.transitionTo('deleted.uncommitted'); +}; + +const RootState = { + // FLAGS + isEmpty: false, + isLoading: false, + isLoaded: false, + isDirty: false, + isSaving: false, + isDeleted: false, + isNew: false, + isValid: true, + + // DEFAULT EVENTS + + // Trying to roll back if you're not in the dirty state + // doesn't change your state. For example, if you're in the + // in-flight state, rolling back the record doesn't move + // you out of the in-flight state. + rolledBack() { }, + unloadRecord(internalModel) { + }, + + propertyWasReset() { }, + + // SUBSTATES + + // A record begins its lifecycle in the `empty` state. + // If its data will come from the adapter, it will + // transition into the `loading` state. Otherwise, if + // the record is being created on the client, it will + // transition into the `created` state. + empty: { + isEmpty: true, + + // EVENTS + loadingData(internalModel, promise) { + internalModel._loadingPromise = promise; + internalModel.transitionTo('loading'); + }, + + loadedData(internalModel) { + internalModel.transitionTo('loaded.created.uncommitted'); + internalModel.triggerLater('ready'); + }, + + pushedData(internalModel) { + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('didLoad'); + internalModel.triggerLater('ready'); + } + }, + + // A record enters this state when the store asks + // the adapter for its data. It remains in this state + // until the adapter provides the requested data. + // + // Usually, this process is asynchronous, using an + // XHR to retrieve the data. + loading: { + // FLAGS + isLoading: true, + + exit(internalModel) { + internalModel._loadingPromise = null; + }, + + // EVENTS + pushedData(internalModel) { + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('didLoad'); + internalModel.triggerLater('ready'); + //TODO this seems out of place here + internalModel.didCleanError(); + }, + + becameError(internalModel) { + internalModel.triggerLater('becameError', internalModel); + }, + + notFound(internalModel) { + internalModel.transitionTo('empty'); + } + }, + + // A record enters this state when its data is populated. + // Most of a record's lifecycle is spent inside substates + // of the `loaded` state. + loaded: { + initialState: 'saved', + + // FLAGS + isLoaded: true, + + //TODO(Igor) Reloading now triggers a loadingData event, + //but it should be ok? + loadingData() { }, + + // SUBSTATES + + // If there are no local changes to a record, it remains + // in the `saved` state. + saved: { + setup(internalModel) { + if (internalModel.hasChangedAttributes()) { + internalModel.adapterDidDirty(); + } + }, + + // EVENTS + didSetProperty, + + pushedData() { }, + + becomeDirty(internalModel) { + internalModel.transitionTo('updated.uncommitted'); + }, + + willCommit(internalModel) { + internalModel.transitionTo('updated.inFlight'); + }, + + reloadRecord(internalModel, resolve) { + resolve(internalModel.store._reloadRecord(internalModel)); + }, + + deleteRecord(internalModel) { + internalModel.transitionTo('deleted.uncommitted'); + }, + + unloadRecord(internalModel) { + }, + + didCommit() {}, + + // loaded.saved.notFound would be triggered by a failed + // `reload()` on an unchanged record + notFound() { } + }, + + // A record is in this state after it has been locally + // created but before the adapter has indicated that + // it has been saved. + created: createdState, + + // A record is in this state if it has already been + // saved to the server, but there are new local changes + // that have not yet been saved. + updated: updatedState + }, + + // A record is in this state if it was deleted from the store. + deleted: { + initialState: 'uncommitted', + dirtyType: 'deleted', + + // FLAGS + isDeleted: true, + isLoaded: true, + isDirty: true, + + // TRANSITIONS + setup(internalModel) { + internalModel.updateRecordArrays(); + }, + + // SUBSTATES + + // When a record is deleted, it enters the `start` + // state. It will exit this state when the record + // starts to commit. + uncommitted: { + + // EVENTS + + willCommit(internalModel) { + internalModel.transitionTo('inFlight'); + }, + + rollback(internalModel) { + internalModel.rollbackAttributes(); + internalModel.triggerLater('ready'); + }, + + pushedData() { }, + becomeDirty() { }, + deleteRecord() { }, + + rolledBack(internalModel) { + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('ready'); + } + }, + + // After a record starts committing, but + // before the adapter indicates that the deletion + // has saved to the server, a record is in the + // `inFlight` substate of `deleted`. + inFlight: { + // FLAGS + isSaving: true, + + // EVENTS + + unloadRecord: assertAgainstUnloadRecord, + + // TODO: More robust semantics around save-while-in-flight + willCommit() { }, + didCommit(internalModel) { + internalModel.transitionTo('saved'); + + internalModel.send('invokeLifecycleCallbacks'); + }, + + becameError(internalModel) { + internalModel.transitionTo('uncommitted'); + internalModel.triggerLater('becameError', internalModel); + }, + + becameInvalid(internalModel) { + internalModel.transitionTo('invalid'); + internalModel.triggerLater('becameInvalid', internalModel); + } + }, + + // Once the adapter indicates that the deletion has + // been saved, the record enters the `saved` substate + // of `deleted`. + saved: { + // FLAGS + isDirty: false, + + setup(internalModel) { + internalModel.clearRelationships(); + }, + + invokeLifecycleCallbacks(internalModel) { + internalModel.triggerLater('didDelete', internalModel); + internalModel.triggerLater('didCommit', internalModel); + }, + + willCommit() { }, + didCommit() { } + }, + + invalid: { + isValid: false, + + didSetProperty(internalModel, context) { + internalModel.removeErrorMessageFromAttribute(context.name); + + didSetProperty(internalModel, context); + + if (!internalModel.hasErrors()) { + this.becameValid(internalModel); + } + }, + + becameInvalid() { }, + becomeDirty() { }, + deleteRecord() { }, + willCommit() { }, + + rolledBack(internalModel) { + internalModel.clearErrorMessages(); + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('ready'); + }, + + becameValid(internalModel) { + internalModel.transitionTo('uncommitted'); + } + + } + }, + + invokeLifecycleCallbacks(internalModel, dirtyType) { + if (dirtyType === 'created') { + internalModel.triggerLater('didCreate', internalModel); + } else { + internalModel.triggerLater('didUpdate', internalModel); + } + + internalModel.triggerLater('didCommit', internalModel); + } +}; + +function wireState(object, parent, name) { + // TODO: Use Object.create and copy instead + object = mixin(parent ? Object.create(parent) : {}, object); + object.parentState = parent; + object.stateName = name; + + for (let prop in object) { + if (!object.hasOwnProperty(prop) || prop === 'parentState' || prop === 'stateName') { continue; } + if (typeof object[prop] === 'object') { + object[prop] = wireState(object[prop], object, name + '.' + prop); + } + } + + return object; +} + +var RootState$1 = wireState(RootState, null, 'root'); + +// All modelNames are dasherized internally. Changing this function may +// require changes to other normalization hooks (such as typeForRoot). + +/** + This method normalizes a modelName into the format Ember Data uses + internally. + + @method normalizeModelName + @public + @param {String} modelName + @return {String} normalizedModelName + @for DS +*/ +function normalizeModelName(modelName) { + return Ember.String.dasherize(modelName); +} + +function typeForRelationshipMeta(meta) { + let modelName; + + modelName = meta.type || meta.key; + if (meta.kind === 'hasMany') { + modelName = singularize(normalizeModelName(modelName)); + } + return modelName; +} + +function relationshipFromMeta(meta) { + return { + key: meta.key, + kind: meta.kind, + type: typeForRelationshipMeta(meta), + options: meta.options, + name: meta.name, + parentType: meta.parentType, + isRelationship: true + }; +} + +const Map$1 = Ember.Map; +const MapWithDefault$1 = Ember.MapWithDefault; + +const relationshipsDescriptor = Ember.computed(function() { + if (Ember.testing === true && relationshipsDescriptor._cacheable === true) { + relationshipsDescriptor._cacheable = false; + } + + let map = new MapWithDefault$1({ + defaultValue() { return []; } + }); + + // Loop through each computed property on the class + this.eachComputedProperty((name, meta) => { + // If the computed property is a relationship, add + // it to the map. + if (meta.isRelationship) { + meta.key = name; + let relationshipsForType = map.get(typeForRelationshipMeta(meta)); + + relationshipsForType.push({ + name: name, + kind: meta.kind + }); + } + }); + + return map; +}).readOnly(); + +const relatedTypesDescriptor = Ember.computed(function() { + if (Ember.testing === true && relatedTypesDescriptor._cacheable === true) { + relatedTypesDescriptor._cacheable = false; + } + + let modelName; + let types = Ember.A(); + + // Loop through each computed property on the class, + // and create an array of the unique types involved + // in relationships + this.eachComputedProperty((name, meta) => { + if (meta.isRelationship) { + meta.key = name; + modelName = typeForRelationshipMeta(meta); + + assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", modelName); + + if (!types.includes(modelName)) { + assert("Trying to sideload " + name + " on " + this.toString() + " but the type doesn't exist.", !!modelName); + types.push(modelName); + } + } + }); + + return types; +}).readOnly(); + +const relationshipsByNameDescriptor = Ember.computed(function() { + if (Ember.testing === true && relationshipsByNameDescriptor._cacheable === true) { + relationshipsByNameDescriptor._cacheable = false; + } + + let map = Map$1.create(); + + this.eachComputedProperty((name, meta) => { + if (meta.isRelationship) { + meta.key = name; + let relationship = relationshipFromMeta(meta); + relationship.type = typeForRelationshipMeta(meta); + map.set(name, relationship); + } + }); + + return map; +}).readOnly(); + +const { + get, + computed, + Map +} = Ember; + +/** + @module ember-data +*/ + +function findPossibleInverses(type, inverseType, name, relationshipsSoFar) { + let possibleRelationships = relationshipsSoFar || []; + + let relationshipMap = get(inverseType, 'relationships'); + if (!relationshipMap) { return possibleRelationships; } + + let relationships = relationshipMap.get(type.modelName).filter(relationship => { + let optionsForRelationship = inverseType.metaForProperty(relationship.name).options; + + if (!optionsForRelationship.inverse) { + return true; + } + + return name === optionsForRelationship.inverse; + }); + + if (relationships) { + possibleRelationships.push.apply(possibleRelationships, relationships); + } + + //Recurse to support polymorphism + if (type.superclass) { + findPossibleInverses(type.superclass, inverseType, name, possibleRelationships); + } + + return possibleRelationships; +} + +function intersection (array1, array2) { + let result = []; + array1.forEach((element) => { + if (array2.indexOf(element) >= 0) { + result.push(element); + } + }); + + return result; +} + +const RESERVED_MODEL_PROPS = [ + 'currentState', 'data', 'store' +]; + +const retrieveFromCurrentState = computed('currentState', function(key) { + return get(this._internalModel.currentState, key); +}).readOnly(); + +/** + + The model class that all Ember Data records descend from. + This is the public API of Ember Data models. If you are using Ember Data + in your application, this is the class you should use. + If you are working on Ember Data internals, you most likely want to be dealing + with `InternalModel` + + @class Model + @namespace DS + @extends Ember.Object + @uses Ember.Evented +*/ +const Model = Ember.Object.extend(Ember.Evented, { + _internalModel: null, + store: null, + __defineNonEnumerable(property) { + this[property.name] = property.descriptor.value; + }, + + /** + If this property is `true` the record is in the `empty` + state. Empty is the first state all records enter after they have + been created. Most records created by the store will quickly + transition to the `loading` state if data needs to be fetched from + the server or the `created` state if the record is created on the + client. A record can also enter the empty state if the adapter is + unable to locate the record. + + @property isEmpty + @type {Boolean} + @readOnly + */ + isEmpty: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `loading` state. A + record enters this state when the store asks the adapter for its + data. It remains in this state until the adapter provides the + requested data. + + @property isLoading + @type {Boolean} + @readOnly + */ + isLoading: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `loaded` state. A + record enters this state when its data is populated. Most of a + record's lifecycle is spent inside substates of the `loaded` + state. + + Example + + ```javascript + let record = store.createRecord('model'); + record.get('isLoaded'); // true + + store.findRecord('model', 1).then(function(model) { + model.get('isLoaded'); // true + }); + ``` + + @property isLoaded + @type {Boolean} + @readOnly + */ + isLoaded: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `dirty` state. The + record has local changes that have not yet been saved by the + adapter. This includes records that have been created (but not yet + saved) or deleted. + + Example + + ```javascript + let record = store.createRecord('model'); + record.get('hasDirtyAttributes'); // true + + store.findRecord('model', 1).then(function(model) { + model.get('hasDirtyAttributes'); // false + model.set('foo', 'some value'); + model.get('hasDirtyAttributes'); // true + }); + ``` + + @since 1.13.0 + @property hasDirtyAttributes + @type {Boolean} + @readOnly + */ + hasDirtyAttributes: computed('currentState.isDirty', function() { + return this.get('currentState.isDirty'); + }), + /** + If this property is `true` the record is in the `saving` state. A + record enters the saving state when `save` is called, but the + adapter has not yet acknowledged that the changes have been + persisted to the backend. + + Example + + ```javascript + let record = store.createRecord('model'); + record.get('isSaving'); // false + let promise = record.save(); + record.get('isSaving'); // true + promise.then(function() { + record.get('isSaving'); // false + }); + ``` + + @property isSaving + @type {Boolean} + @readOnly + */ + isSaving: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `deleted` state + and has been marked for deletion. When `isDeleted` is true and + `hasDirtyAttributes` is true, the record is deleted locally but the deletion + was not yet persisted. When `isSaving` is true, the change is + in-flight. When both `hasDirtyAttributes` and `isSaving` are false, the + change has persisted. + + Example + + ```javascript + let record = store.createRecord('model'); + record.get('isDeleted'); // false + record.deleteRecord(); + + // Locally deleted + record.get('isDeleted'); // true + record.get('hasDirtyAttributes'); // true + record.get('isSaving'); // false + + // Persisting the deletion + let promise = record.save(); + record.get('isDeleted'); // true + record.get('isSaving'); // true + + // Deletion Persisted + promise.then(function() { + record.get('isDeleted'); // true + record.get('isSaving'); // false + record.get('hasDirtyAttributes'); // false + }); + ``` + + @property isDeleted + @type {Boolean} + @readOnly + */ + isDeleted: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `new` state. A + record will be in the `new` state when it has been created on the + client and the adapter has not yet report that it was successfully + saved. + + Example + + ```javascript + let record = store.createRecord('model'); + record.get('isNew'); // true + + record.save().then(function(model) { + model.get('isNew'); // false + }); + ``` + + @property isNew + @type {Boolean} + @readOnly + */ + isNew: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `valid` state. + + A record will be in the `valid` state when the adapter did not report any + server-side validation failures. + + @property isValid + @type {Boolean} + @readOnly + */ + isValid: retrieveFromCurrentState, + /** + If the record is in the dirty state this property will report what + kind of change has caused it to move into the dirty + state. Possible values are: + + - `created` The record has been created by the client and not yet saved to the adapter. + - `updated` The record has been updated by the client and not yet saved to the adapter. + - `deleted` The record has been deleted by the client and not yet saved to the adapter. + + Example + + ```javascript + let record = store.createRecord('model'); + record.get('dirtyType'); // 'created' + ``` + + @property dirtyType + @type {String} + @readOnly + */ + dirtyType: retrieveFromCurrentState, + + /** + If `true` the adapter reported that it was unable to save local + changes to the backend for any reason other than a server-side + validation error. + + Example + + ```javascript + record.get('isError'); // false + record.set('foo', 'valid value'); + record.save().then(null, function() { + record.get('isError'); // true + }); + ``` + + @property isError + @type {Boolean} + @readOnly + */ + isError: false, + + /** + If `true` the store is attempting to reload the record from the adapter. + + Example + + ```javascript + record.get('isReloading'); // false + record.reload(); + record.get('isReloading'); // true + ``` + + @property isReloading + @type {Boolean} + @readOnly + */ + isReloading: false, + + /** + All ember models have an id property. This is an identifier + managed by an external source. These are always coerced to be + strings before being used internally. Note when declaring the + attributes for a model it is an error to declare an id + attribute. + + ```javascript + let record = store.createRecord('model'); + record.get('id'); // null + + store.findRecord('model', 1).then(function(model) { + model.get('id'); // '1' + }); + ``` + + @property id + @type {String} + */ + id: null, + + /** + @property currentState + @private + @type {Object} + */ + currentState: RootState$1.empty, + + /** + When the record is in the `invalid` state this object will contain + any errors returned by the adapter. When present the errors hash + contains keys corresponding to the invalid property names + and values which are arrays of Javascript objects with two keys: + + - `message` A string containing the error message from the backend + - `attribute` The name of the property associated with this error message + + ```javascript + record.get('errors.length'); // 0 + record.set('foo', 'invalid value'); + record.save().catch(function() { + record.get('errors').get('foo'); + // [{message: 'foo should be a number.', attribute: 'foo'}] + }); + ``` + + The `errors` property us useful for displaying error messages to + the user. + + ```handlebars + + {{#each model.errors.username as |error|}} +
      + {{error.message}} +
      + {{/each}} + + {{#each model.errors.email as |error|}} +
      + {{error.message}} +
      + {{/each}} + ``` + + + You can also access the special `messages` property on the error + object to get an array of all the error strings. + + ```handlebars + {{#each model.errors.messages as |message|}} +
      + {{message}} +
      + {{/each}} + ``` + + @property errors + @type {DS.Errors} + */ + errors: computed(function() { + let errors = Errors.create(); + + errors._registerHandlers(this._internalModel, + function() { + this.send('becameInvalid'); + }, + function() { + this.send('becameValid'); + }); + return errors; + }).readOnly(), + + /** + This property holds the `DS.AdapterError` object with which + last adapter operation was rejected. + + @property adapterError + @type {DS.AdapterError} + */ + adapterError: null, + + /** + Create a JSON representation of the record, using the serialization + strategy of the store's adapter. + + `serialize` takes an optional hash as a parameter, currently + supported options are: + + - `includeId`: `true` if the record's ID should be included in the + JSON representation. + + @method serialize + @param {Object} options + @return {Object} an object whose values are primitive JSON values only + */ + serialize(options) { + return this._internalModel.createSnapshot().serialize(options); + }, + + /** + Use [DS.JSONSerializer](DS.JSONSerializer.html) to + get the JSON representation of a record. + + `toJSON` takes an optional hash as a parameter, currently + supported options are: + + - `includeId`: `true` if the record's ID should be included in the + JSON representation. + + @method toJSON + @param {Object} options + @return {Object} A JSON representation of the object. + */ + toJSON(options) { + // container is for lazy transform lookups + let serializer = this.store.serializerFor('-default'); + let snapshot = this._internalModel.createSnapshot(); + + return serializer.serialize(snapshot, options); + }, + + /** + Fired when the record is ready to be interacted with, + that is either loaded from the server or created locally. + + @event ready + */ + ready: null, + + /** + Fired when the record is loaded from the server. + + @event didLoad + */ + didLoad: null, + + /** + Fired when the record is updated. + + @event didUpdate + */ + didUpdate: null, + + /** + Fired when a new record is commited to the server. + + @event didCreate + */ + didCreate: null, + + /** + Fired when the record is deleted. + + @event didDelete + */ + didDelete: null, + + /** + Fired when the record becomes invalid. + + @event becameInvalid + */ + becameInvalid: null, + + /** + Fired when the record enters the error state. + + @event becameError + */ + becameError: null, + + /** + Fired when the record is rolled back. + + @event rolledBack + */ + rolledBack: null, + + //TODO Do we want to deprecate these? + /** + @method send + @private + @param {String} name + @param {Object} context + */ + send(name, context) { + return this._internalModel.send(name, context); + }, + + /** + @method transitionTo + @private + @param {String} name + */ + transitionTo(name) { + return this._internalModel.transitionTo(name); + }, + + + /** + Marks the record as deleted but does not save it. You must call + `save` afterwards if you want to persist it. You might use this + method if you want to allow the user to still `rollbackAttributes()` + after a delete was made. + + Example + + ```app/routes/model/delete.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + actions: { + softDelete: function() { + this.controller.get('model').deleteRecord(); + }, + confirm: function() { + this.controller.get('model').save(); + }, + undo: function() { + this.controller.get('model').rollbackAttributes(); + } + } + }); + ``` + + @method deleteRecord + */ + deleteRecord() { + this._internalModel.deleteRecord(); + }, + + /** + Same as `deleteRecord`, but saves the record immediately. + + Example + + ```app/routes/model/delete.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + actions: { + delete: function() { + let controller = this.controller; + controller.get('model').destroyRecord().then(function() { + controller.transitionToRoute('model.index'); + }); + } + } + }); + ``` + + If you pass an object on the `adapterOptions` property of the options + argument it will be passed to your adapter via the snapshot + + ```js + record.destroyRecord({ adapterOptions: { subscribe: false } }); + ``` + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + deleteRecord: function(store, type, snapshot) { + if (snapshot.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + + @method destroyRecord + @param {Object} options + @return {Promise} a promise that will be resolved when the adapter returns + successfully or rejected if the adapter returns with an error. + */ + destroyRecord(options) { + this.deleteRecord(); + return this.save(options); + }, + + /** + Unloads the record from the store. This will cause the record to be destroyed and freed up for garbage collection. + + @method unloadRecord + */ + unloadRecord() { + if (this.isDestroyed) { return; } + this._internalModel.unloadRecord(); + }, + + /** + @method _notifyProperties + @private + */ + _notifyProperties(keys) { + Ember.beginPropertyChanges(); + let key; + for (let i = 0, length = keys.length; i < length; i++) { + key = keys[i]; + this.notifyPropertyChange(key); + } + Ember.endPropertyChanges(); + }, + + /** + Returns an object, whose keys are changed properties, and value is + an [oldProp, newProp] array. + + The array represents the diff of the canonical state with the local state + of the model. Note: if the model is created locally, the canonical state is + empty since the adapter hasn't acknowledged the attributes yet: + + Example + + ```app/models/mascot.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + name: DS.attr('string'), + isAdmin: DS.attr('boolean', { + defaultValue: false + }) + }); + ``` + + ```javascript + let mascot = store.createRecord('mascot'); + + mascot.changedAttributes(); // {} + + mascot.set('name', 'Tomster'); + mascot.changedAttributes(); // { name: [undefined, 'Tomster'] } + + mascot.set('isAdmin', true); + mascot.changedAttributes(); // { isAdmin: [undefined, true], name: [undefined, 'Tomster'] } + + mascot.save().then(function() { + mascot.changedAttributes(); // {} + + mascot.set('isAdmin', false); + mascot.changedAttributes(); // { isAdmin: [true, false] } + }); + ``` + + @method changedAttributes + @return {Object} an object, whose keys are changed properties, + and value is an [oldProp, newProp] array. + */ + changedAttributes() { + return this._internalModel.changedAttributes(); + }, + + //TODO discuss with tomhuda about events/hooks + //Bring back as hooks? + /** + @method adapterWillCommit + @private + adapterWillCommit: function() { + this.send('willCommit'); + }, + + /** + @method adapterDidDirty + @private + adapterDidDirty: function() { + this.send('becomeDirty'); + this.updateRecordArraysLater(); + }, + */ + + /** + If the model `hasDirtyAttributes` this function will discard any unsaved + changes. If the model `isNew` it will be removed from the store. + + Example + + ```javascript + record.get('name'); // 'Untitled Document' + record.set('name', 'Doc 1'); + record.get('name'); // 'Doc 1' + record.rollbackAttributes(); + record.get('name'); // 'Untitled Document' + ``` + + @since 1.13.0 + @method rollbackAttributes + */ + rollbackAttributes() { + this._internalModel.rollbackAttributes(); + }, + + /* + @method _createSnapshot + @private + */ + _createSnapshot() { + return this._internalModel.createSnapshot(); + }, + + toStringExtension() { + return get(this, 'id'); + }, + + /** + Save the record and persist any changes to the record to an + external source via the adapter. + + Example + + ```javascript + record.set('name', 'Tomster'); + record.save().then(function() { + // Success callback + }, function() { + // Error callback + }); + ``` + + If you pass an object on the `adapterOptions` property of the options + argument it will be passed to you adapter via the snapshot + + ```js + record.save({ adapterOptions: { subscribe: false } }); + ``` + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + updateRecord: function(store, type, snapshot) { + if (snapshot.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + + @method save + @param {Object} options + @return {Promise} a promise that will be resolved when the adapter returns + successfully or rejected if the adapter returns with an error. + */ + save(options) { + return PromiseObject.create({ + promise: this._internalModel.save(options).then(() => this) + }); + }, + + /** + Reload the record from the adapter. + + This will only work if the record has already finished loading. + + Example + + ```app/routes/model/view.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + actions: { + reload: function() { + this.controller.get('model').reload().then(function(model) { + // do something with the reloaded model + }); + } + } + }); + ``` + + @method reload + @return {Promise} a promise that will be resolved with the record when the + adapter returns successfully or rejected if the adapter returns + with an error. + */ + reload() { + return PromiseObject.create({ + promise: this._internalModel.reload().then(() => this) + }); + }, + + + /** + Override the default event firing from Ember.Evented to + also call methods with the given name. + + @method trigger + @private + @param {String} name + */ + trigger(name) { + let fn = this[name]; + + if (typeof fn === 'function') { + let length = arguments.length; + let args = new Array(length - 1); + + for (let i = 1; i < length; i++) { + args[i - 1] = arguments[i]; + } + fn.apply(this, args); + } + + this._super(...arguments); + }, + + // This is a temporary solution until we refactor DS.Model to not + // rely on the data property. + willMergeMixin(props) { + let constructor = this.constructor; + assert('`' + intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + constructor.toString(), !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0]); + assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + constructor.toString(), Object.keys(props).indexOf('id') === -1); + }, + + attr() { + assert("The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); + }, + + /** + Get the reference for the specified belongsTo relationship. + + Example + + ```app/models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + ``` + + ```javascript + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + let userRef = blog.belongsTo('user'); + + // check if the user relationship is loaded + let isLoaded = userRef.value() !== null; + + // get the record of the reference (null if not yet available) + let user = userRef.value(); + + // get the identifier of the reference + if (userRef.remoteType() === "id") { + let id = userRef.id(); + } else if (userRef.remoteType() === "link") { + let link = userRef.link(); + } + + // load user (via store.findRecord or store.findBelongsTo) + userRef.load().then(...) + + // or trigger a reload + userRef.reload().then(...) + + // provide data for reference + userRef.push({ + type: 'user', + id: 1, + attributes: { + username: "@user" + } + }).then(function(user) { + userRef.value() === user; + }); + ``` + + @method belongsTo + @param {String} name of the relationship + @since 2.5.0 + @return {BelongsToReference} reference for this relationship + */ + belongsTo(name) { + return this._internalModel.referenceFor('belongsTo', name); + }, + + /** + Get the reference for the specified hasMany relationship. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + comments: { + data: [ + { type: 'comment', id: 1 }, + { type: 'comment', id: 2 } + ] + } + } + } + }); + let commentsRef = blog.hasMany('comments'); + + // check if the comments are loaded already + let isLoaded = commentsRef.value() !== null; + + // get the records of the reference (null if not yet available) + let comments = commentsRef.value(); + + // get the identifier of the reference + if (commentsRef.remoteType() === "ids") { + let ids = commentsRef.ids(); + } else if (commentsRef.remoteType() === "link") { + let link = commentsRef.link(); + } + + // load comments (via store.findMany or store.findHasMany) + commentsRef.load().then(...) + + // or trigger a reload + commentsRef.reload().then(...) + + // provide data for reference + commentsRef.push([{ type: 'comment', id: 1 }, { type: 'comment', id: 2 }]).then(function(comments) { + commentsRef.value() === comments; + }); + ``` + + @method hasMany + @param {String} name of the relationship + @since 2.5.0 + @return {HasManyReference} reference for this relationship + */ + hasMany(name) { + return this._internalModel.referenceFor('hasMany', name); + }, + + setId: Ember.observer('id', function () { + this._internalModel.setId(this.get('id')); + }), + + /** + Provides info about the model for debugging purposes + by grouping the properties into more semantic groups. + + Meant to be used by debugging tools such as the Chrome Ember Extension. + + - Groups all attributes in "Attributes" group. + - Groups all belongsTo relationships in "Belongs To" group. + - Groups all hasMany relationships in "Has Many" group. + - Groups all flags in "Flags" group. + - Flags relationship CPs as expensive properties. + + @method _debugInfo + @for DS.Model + @private + */ + _debugInfo() { + let attributes = ['id']; + let relationships = { }; + let expensiveProperties = []; + + this.eachAttribute((name, meta) => attributes.push(name)); + + let groups = [ + { + name: 'Attributes', + properties: attributes, + expand: true + } + ]; + + this.eachRelationship((name, relationship) => { + let properties = relationships[relationship.kind]; + + if (properties === undefined) { + properties = relationships[relationship.kind] = []; + groups.push({ + name: relationship.name, + properties, + expand: true + }); + } + properties.push(name); + expensiveProperties.push(name); + }); + + groups.push({ + name: 'Flags', + properties: ['isLoaded', 'hasDirtyAttributes', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'] + }); + + return { + propertyInfo: { + // include all other mixins / properties (not just the grouped ones) + includeOtherProperties: true, + groups: groups, + // don't pre-calculate unless cached + expensiveProperties: expensiveProperties + } + }; + }, + + notifyBelongsToChanged(key) { + this.notifyPropertyChange(key); + }, + + /** + This Ember.js hook allows an object to be notified when a property + is defined. + + In this case, we use it to be notified when an Ember Data user defines a + belongs-to relationship. In that case, we need to set up observers for + each one, allowing us to track relationship changes and automatically + reflect changes in the inverse has-many array. + + This hook passes the class being set up, as well as the key and value + being defined. So, for example, when the user does this: + + ```javascript + DS.Model.extend({ + parent: DS.belongsTo('user') + }); + ``` + + This hook would be called with "parent" as the key and the computed + property returned by `DS.belongsTo` as the value. + + @method didDefineProperty + @param {Object} proto + @param {String} key + @param {Ember.ComputedProperty} value + */ + didDefineProperty(proto, key, value) { + // Check if the value being set is a computed property. + if (value instanceof Ember.ComputedProperty) { + + // If it is, get the metadata for the relationship. This is + // populated by the `DS.belongsTo` helper when it is creating + // the computed property. + let meta = value.meta(); + + meta.parentType = proto.constructor; + } + }, + + /** + Given a callback, iterates over each of the relationships in the model, + invoking the callback with the name of each relationship and its relationship + descriptor. + + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(name, descriptor); + ``` + + - `name` the name of the current property in the iteration + - `descriptor` the meta object that describes this relationship + + The relationship descriptor argument is an object with the following properties. + + - **key** String the name of this relationship on the Model + - **kind** String "hasMany" or "belongsTo" + - **options** Object the original options hash passed when the relationship was declared + - **parentType** DS.Model the type of the Model that owns this relationship + - **type** String the type name of the related Model + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. + + Example + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + serialize: function(record, options) { + let json = {}; + + record.eachRelationship(function(name, descriptor) { + if (descriptor.kind === 'hasMany') { + let serializedHasManyName = name.toUpperCase() + '_IDS'; + json[serializedHasManyName] = record.get(name).mapBy('id'); + } + }); + + return json; + } + }); + ``` + + @method eachRelationship + @param {Function} callback the callback to invoke + @param {any} binding the value to which the callback's `this` should be bound + */ + eachRelationship(callback, binding) { + this.constructor.eachRelationship(callback, binding); + }, + + relationshipFor(name) { + return get(this.constructor, 'relationshipsByName').get(name); + }, + + inverseFor(key) { + return this.constructor.inverseFor(key, this.store); + }, + + notifyHasManyAdded(key) { + //We need to notifyPropertyChange in the adding case because we need to make sure + //we fetch the newly added record in case it is unloaded + //TODO(Igor): Consider whether we could do this only if the record state is unloaded + + //Goes away once hasMany is double promisified + this.notifyPropertyChange(key); + }, + + eachAttribute(callback, binding) { + this.constructor.eachAttribute(callback, binding); + } +}); + +/** + @property data + @private + @type {Object} + */ +Object.defineProperty(Model.prototype, 'data', { + get() { + return this._internalModel._data; + } +}); + +runInDebug(function() { + Model.reopen({ + init() { + this._super(...arguments); + + if (!this._internalModel) { + throw new Ember.Error('You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.'); + } + } + }); +}); + +Model.reopenClass({ + isModel: true, + + /** + Override the class' `create()` method to raise an error. This + prevents end users from inadvertently calling `create()` instead + of `createRecord()`. The store is still able to create instances + by calling the `_create()` method. To create an instance of a + `DS.Model` use [store.createRecord](DS.Store.html#method_createRecord). + + @method create + @private + @static + */ + /** + Represents the model's class name as a string. This can be used to look up the model's class name through + `DS.Store`'s modelFor method. + + `modelName` is generated for you by Ember Data. It will be a lowercased, dasherized string. + For example: + + ```javascript + store.modelFor('post').modelName; // 'post' + store.modelFor('blog-post').modelName; // 'blog-post' + ``` + + The most common place you'll want to access `modelName` is in your serializer's `payloadKeyFromModelName` method. For example, to change payload + keys to underscore (instead of dasherized), you might use the following code: + + ```javascript + export default const PostSerializer = DS.RESTSerializer.extend({ + payloadKeyFromModelName: function(modelName) { + return Ember.String.underscore(modelName); + } + }); + ``` + @property modelName + @type String + @readonly + @static + */ + modelName: null, + + /* + These class methods below provide relationship + introspection abilities about relationships. + + A note about the computed properties contained here: + + **These properties are effectively sealed once called for the first time.** + To avoid repeatedly doing expensive iteration over a model's fields, these + values are computed once and then cached for the remainder of the runtime of + your application. + + If your application needs to modify a class after its initial definition + (for example, using `reopen()` to add additional attributes), make sure you + do it before using your model with the store, which uses these properties + extensively. + */ + + /** + For a given relationship name, returns the model type of the relationship. + + For example, if you define a model like this: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + comments: DS.hasMany('comment') + }); + ``` + + Calling `store.modelFor('post').typeForRelationship('comments', store)` will return `Comment`. + + @method typeForRelationship + @static + @param {String} name the name of the relationship + @param {store} store an instance of DS.Store + @return {DS.Model} the type of the relationship, or undefined + */ + typeForRelationship(name, store) { + let relationship = get(this, 'relationshipsByName').get(name); + return relationship && store.modelFor(relationship.type); + }, + + inverseMap: Ember.computed(function() { + return Object.create(null); + }), + + /** + Find the relationship which is the inverse of the one asked for. + + For example, if you define models like this: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + comments: DS.hasMany('message') + }); + ``` + + ```app/models/message.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + owner: DS.belongsTo('post') + }); + ``` + + ``` js + store.modelFor('post').inverseFor('comments', store) // { type: App.Message, name: 'owner', kind: 'belongsTo' } + store.modelFor('message').inverseFor('owner', store) // { type: App.Post, name: 'comments', kind: 'hasMany' } + ``` + + @method inverseFor + @static + @param {String} name the name of the relationship + @param {DS.Store} store + @return {Object} the inverse relationship, or null + */ + inverseFor(name, store) { + let inverseMap = get(this, 'inverseMap'); + if (inverseMap[name] !== undefined) { + return inverseMap[name]; + } else { + let relationship = get(this, 'relationshipsByName').get(name); + if (!relationship) { + inverseMap[name] = null; + return null; + } + + let options = relationship.options; + if (options && options.inverse === null) { + // populate the cache with a miss entry so we can skip getting and going + // through `relationshipsByName` + inverseMap[name] = null; + return null; + } + + return inverseMap[name] = this._findInverseFor(name, store); + } + }, + + //Calculate the inverse, ignoring the cache + _findInverseFor(name, store) { + + let inverseType = this.typeForRelationship(name, store); + if (!inverseType) { + return null; + } + + let propertyMeta = this.metaForProperty(name); + //If inverse is manually specified to be null, like `comments: DS.hasMany('message', { inverse: null })` + let options = propertyMeta.options; + if (options.inverse === null) { return null; } + + let inverseName, inverseKind, inverse; + + //If inverse is specified manually, return the inverse + if (options.inverse) { + inverseName = options.inverse; + inverse = Ember.get(inverseType, 'relationshipsByName').get(inverseName); + + assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.modelName + + "' model. This is most likely due to a missing attribute on your model definition.", !Ember.isNone(inverse)); + + inverseKind = inverse.kind; + } else { + //No inverse was specified manually, we need to use a heuristic to guess one + if (propertyMeta.type === propertyMeta.parentType.modelName) { + warn(`Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at http://emberjs.com/guides/models/defining-models/#toc_reflexive-relation for how to explicitly specify inverses.`, false, { + id: 'ds.model.reflexive-relationship-without-inverse' + }); + } + + let possibleRelationships = findPossibleInverses(this, inverseType, name); + + if (possibleRelationships.length === 0) { return null; } + + let filteredRelationships = possibleRelationships.filter((possibleRelationship) => { + let optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options; + return name === optionsForRelationship.inverse; + }); + + assert("You defined the '" + name + "' relationship on " + this + ", but you defined the inverse relationships of type " + + inverseType.toString() + " multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", + filteredRelationships.length < 2); + + if (filteredRelationships.length === 1 ) { + possibleRelationships = filteredRelationships; + } + + assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + + this + " were found on " + inverseType + ". Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", + possibleRelationships.length === 1); + + inverseName = possibleRelationships[0].name; + inverseKind = possibleRelationships[0].kind; + } + + return { + type: inverseType, + name: inverseName, + kind: inverseKind + }; + }, + + /** + The model's relationships as a map, keyed on the type of the + relationship. The value of each entry is an array containing a descriptor + for each relationship with that type, describing the name of the relationship + as well as the type. + + For example, given the following model definition: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + posts: DS.hasMany('post') + }); + ``` + + This computed property would return a map describing these + relationships, like this: + + ```javascript + import Ember from 'ember'; + import Blog from 'app/models/blog'; + import User from 'app/models/user'; + import Post from 'app/models/post'; + + let relationships = Ember.get(Blog, 'relationships'); + relationships.get(User); + //=> [ { name: 'users', kind: 'hasMany' }, + // { name: 'owner', kind: 'belongsTo' } ] + relationships.get(Post); + //=> [ { name: 'posts', kind: 'hasMany' } ] + ``` + + @property relationships + @static + @type Ember.Map + @readOnly + */ + + relationships: relationshipsDescriptor, + + /** + A hash containing lists of the model's relationships, grouped + by the relationship kind. For example, given a model with this + definition: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + + posts: DS.hasMany('post') + }); + ``` + + This property would contain the following: + + ```javascript + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + let relationshipNames = Ember.get(Blog, 'relationshipNames'); + relationshipNames.hasMany; + //=> ['users', 'posts'] + relationshipNames.belongsTo; + //=> ['owner'] + ``` + + @property relationshipNames + @static + @type Object + @readOnly + */ + relationshipNames: Ember.computed(function() { + let names = { + hasMany: [], + belongsTo: [] + }; + + this.eachComputedProperty((name, meta) => { + if (meta.isRelationship) { + names[meta.kind].push(name); + } + }); + + return names; + }), + + /** + An array of types directly related to a model. Each type will be + included once, regardless of the number of relationships it has with + the model. + + For example, given a model with this definition: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + + posts: DS.hasMany('post') + }); + ``` + + This property would contain the following: + + ```javascript + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + let relatedTypes = Ember.get(Blog, 'relatedTypes'); + //=> [ User, Post ] + ``` + + @property relatedTypes + @static + @type Ember.Array + @readOnly + */ + relatedTypes: relatedTypesDescriptor, + + /** + A map whose keys are the relationships of a model and whose values are + relationship descriptors. + + For example, given a model with this + definition: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + + posts: DS.hasMany('post') + }); + ``` + + This property would contain the following: + + ```javascript + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + let relationshipsByName = Ember.get(Blog, 'relationshipsByName'); + relationshipsByName.get('users'); + //=> { key: 'users', kind: 'hasMany', type: 'user', options: Object, isRelationship: true } + relationshipsByName.get('owner'); + //=> { key: 'owner', kind: 'belongsTo', type: 'user', options: Object, isRelationship: true } + ``` + + @property relationshipsByName + @static + @type Ember.Map + @readOnly + */ + relationshipsByName: relationshipsByNameDescriptor, + + /** + A map whose keys are the fields of the model and whose values are strings + describing the kind of the field. A model's fields are the union of all of its + attributes and relationships. + + For example: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + + posts: DS.hasMany('post'), + + title: DS.attr('string') + }); + ``` + + ```js + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + let fields = Ember.get(Blog, 'fields'); + fields.forEach(function(kind, field) { + console.log(field, kind); + }); + + // prints: + // users, hasMany + // owner, belongsTo + // posts, hasMany + // title, attribute + ``` + + @property fields + @static + @type Ember.Map + @readOnly + */ + fields: Ember.computed(function() { + let map = Map.create(); + + this.eachComputedProperty((name, meta) => { + if (meta.isRelationship) { + map.set(name, meta.kind); + } else if (meta.isAttribute) { + map.set(name, 'attribute'); + } + }); + + return map; + }).readOnly(), + + /** + Given a callback, iterates over each of the relationships in the model, + invoking the callback with the name of each relationship and its relationship + descriptor. + + @method eachRelationship + @static + @param {Function} callback the callback to invoke + @param {any} binding the value to which the callback's `this` should be bound + */ + eachRelationship(callback, binding) { + get(this, 'relationshipsByName').forEach((relationship, name) => { + callback.call(binding, name, relationship); + }); + }, + + /** + Given a callback, iterates over each of the types related to a model, + invoking the callback with the related type's class. Each type will be + returned just once, regardless of how many different relationships it has + with a model. + + @method eachRelatedType + @static + @param {Function} callback the callback to invoke + @param {any} binding the value to which the callback's `this` should be bound + */ + eachRelatedType(callback, binding) { + let relationshipTypes = get(this, 'relatedTypes'); + + for (let i = 0; i < relationshipTypes.length; i++) { + let type = relationshipTypes[i]; + callback.call(binding, type); + } + }, + + determineRelationshipType(knownSide, store) { + let knownKey = knownSide.key; + let knownKind = knownSide.kind; + let inverse = this.inverseFor(knownKey, store); + // let key; + let otherKind; + + if (!inverse) { + return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone'; + } + + // key = inverse.name; + otherKind = inverse.kind; + + if (otherKind === 'belongsTo') { + return knownKind === 'belongsTo' ? 'oneToOne' : 'manyToOne'; + } else { + return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany'; + } + }, + + /** + A map whose keys are the attributes of the model (properties + described by DS.attr) and whose values are the meta object for the + property. + + Example + + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + birthday: DS.attr('date') + }); + ``` + + ```javascript + import Ember from 'ember'; + import Person from 'app/models/person'; + + let attributes = Ember.get(Person, 'attributes') + + attributes.forEach(function(meta, name) { + console.log(name, meta); + }); + + // prints: + // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} + // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} + // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} + ``` + + @property attributes + @static + @type {Ember.Map} + @readOnly + */ + attributes: Ember.computed(function() { + let map = Map.create(); + + this.eachComputedProperty((name, meta) => { + if (meta.isAttribute) { + assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.toString(), name !== 'id'); + + meta.name = name; + map.set(name, meta); + } + }); + + return map; + }).readOnly(), + + /** + A map whose keys are the attributes of the model (properties + described by DS.attr) and whose values are type of transformation + applied to each attribute. This map does not include any + attributes that do not have an transformation type. + + Example + + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + firstName: DS.attr(), + lastName: DS.attr('string'), + birthday: DS.attr('date') + }); + ``` + + ```javascript + import Ember from 'ember'; + import Person from 'app/models/person'; + + let transformedAttributes = Ember.get(Person, 'transformedAttributes') + + transformedAttributes.forEach(function(field, type) { + console.log(field, type); + }); + + // prints: + // lastName string + // birthday date + ``` + + @property transformedAttributes + @static + @type {Ember.Map} + @readOnly + */ + transformedAttributes: Ember.computed(function() { + let map = Map.create(); + + this.eachAttribute((key, meta) => { + if (meta.type) { + map.set(key, meta.type); + } + }); + + return map; + }).readOnly(), + + /** + Iterates through the attributes of the model, calling the passed function on each + attribute. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(name, meta); + ``` + + - `name` the name of the current property in the iteration + - `meta` the meta object for the attribute property in the iteration + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. + + Example + + ```javascript + import DS from 'ember-data'; + + let Person = DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + birthday: DS.attr('date') + }); + + Person.eachAttribute(function(name, meta) { + console.log(name, meta); + }); + + // prints: + // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} + // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} + // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} + ``` + + @method eachAttribute + @param {Function} callback The callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + @static + */ + eachAttribute(callback, binding) { + get(this, 'attributes').forEach((meta, name) => { + callback.call(binding, name, meta); + }); + }, + + /** + Iterates through the transformedAttributes of the model, calling + the passed function on each attribute. Note the callback will not be + called for any attributes that do not have an transformation type. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(name, type); + ``` + + - `name` the name of the current property in the iteration + - `type` a string containing the name of the type of transformed + applied to the attribute + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. + + Example + + ```javascript + import DS from 'ember-data'; + + let Person = DS.Model.extend({ + firstName: DS.attr(), + lastName: DS.attr('string'), + birthday: DS.attr('date') + }); + + Person.eachTransformedAttribute(function(name, type) { + console.log(name, type); + }); + + // prints: + // lastName string + // birthday date + ``` + + @method eachTransformedAttribute + @param {Function} callback The callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + @static + */ + eachTransformedAttribute(callback, binding) { + get(this, 'transformedAttributes').forEach((type, name) => { + callback.call(binding, name, type); + }); + } +}); + +// if `Ember.setOwner` is defined, accessing `this.container` is +// deprecated (but functional). In "standard" Ember usage, this +// deprecation is actually created via an `.extend` of the factory +// inside the container itself, but that only happens on models +// with MODEL_FACTORY_INJECTIONS enabled :( +if (Ember.setOwner) { + Object.defineProperty(Model.prototype, 'container', { + configurable: true, + enumerable: false, + get() { + deprecate('Using the injected `container` is deprecated. Please use the `getOwner` helper instead to access the owner of this object.', + false, + { id: 'ember-application.injected-container', until: '3.0.0' }); + + return this.store.container; + } + }); +} + +if (isEnabled('ds-rollback-attribute')) { + Model.reopen({ + /** + Discards any unsaved changes to the given attribute. This feature is not enabled by default. You must enable `ds-rollback-attribute` and be running a canary build. + + Example + + ```javascript + record.get('name'); // 'Untitled Document' + record.set('name', 'Doc 1'); + record.get('name'); // 'Doc 1' + record.rollbackAttribute('name'); + record.get('name'); // 'Untitled Document' + ``` + + @method rollbackAttribute + */ + rollbackAttribute(attributeName) { + if (attributeName in this._internalModel._attributes) { + this.set(attributeName, this._internalModel.lastAcknowledgedValue(attributeName)); + } + } + }); +} + +const EmberOrderedSet = Ember.OrderedSet; +const guidFor = Ember.guidFor; + +function OrderedSet() { + this._super$constructor(); +} + +OrderedSet.create = function() { + let Constructor = this; + return new Constructor(); +}; + +OrderedSet.prototype = Object.create(EmberOrderedSet.prototype); +OrderedSet.prototype.constructor = OrderedSet; +OrderedSet.prototype._super$constructor = EmberOrderedSet; + +OrderedSet.prototype.addWithIndex = function(obj, idx) { + let guid = guidFor(obj); + let presenceSet = this.presenceSet; + let list = this.list; + + if (presenceSet[guid] === true) { + return; + } + + presenceSet[guid] = true; + + if (idx === undefined || idx === null) { + list.push(obj); + } else { + list.splice(idx, 0, obj); + } + + this.size += 1; + + return this; +}; + +/* + This method normalizes a link to an "links object". If the passed link is + already an object it's returned without any modifications. + + See http://jsonapi.org/format/#document-links for more information. + + @method _normalizeLink + @private + @param {String} link + @return {Object|null} + @for DS +*/ +function _normalizeLink(link) { + switch (typeof link) { + case 'object': return link; + case 'string': return { href: link }; + } + return null; +} + +/* global heimdall */ +const { + addCanonicalInternalModel, + addCanonicalInternalModels, + addInternalModel, + addInternalModels, + clear, + findLink, + flushCanonical, + flushCanonicalLater, + newRelationship, + push, + removeCanonicalInternalModel, + removeCanonicalInternalModelFromInverse, + removeCanonicalInternalModelFromOwn, + removeCanonicalInternalModels, + removeInternalModel, + removeInternalModelFromInverse, + removeInternalModelFromOwn, + removeInternalModels, + setHasData, + setHasLoaded, + updateLink, + updateMeta, + updateInternalModelsFromAdapter +} = heimdall.registerMonitor('system.relationships.state.relationship', + 'addCanonicalInternalModel', + 'addCanonicalInternalModels', + 'addInternalModel', + 'addInternalModels', + 'clear', + 'findLink', + 'flushCanonical', + 'flushCanonicalLater', + 'newRelationship', + 'push', + 'removeCanonicalInternalModel', + 'removeCanonicalInternalModelFromInverse', + 'removeCanonicalInternalModelFromOwn', + 'removeCanonicalInternalModels', + 'removeInternalModel', + 'removeInternalModelFromInverse', + 'removeInternalModelFromOwn', + 'removeInternalModels', + 'setHasData', + 'setHasLoaded', + 'updateLink', + 'updateMeta', + 'updateInternalModelsFromAdapter' +); + +class Relationship { + constructor(store, internalModel, inverseKey, relationshipMeta) { + heimdall.increment(newRelationship); + let async = relationshipMeta.options.async; + let polymorphic = relationshipMeta.options.polymorphic; + this.members = new OrderedSet(); + this.canonicalMembers = new OrderedSet(); + this.store = store; + this.key = relationshipMeta.key; + this.inverseKey = inverseKey; + this.internalModel = internalModel; + this.isAsync = typeof async === 'undefined' ? true : async; + this.isPolymorphic = typeof polymorphic === 'undefined' ? true : polymorphic; + this.relationshipMeta = relationshipMeta; + //This probably breaks for polymorphic relationship in complex scenarios, due to + //multiple possible modelNames + this.inverseKeyForImplicit = this.internalModel.modelName + this.key; + this.linkPromise = null; + this.meta = null; + this.hasData = false; + this.hasLoaded = false; + } + + get parentType() { + return this.internalModel.modelName; + } + + removeInverseRelationships() { + if (!this.inverseKey) { return; } + + let allMembers = + // we actually want a union of members and canonicalMembers + // they should be disjoint but currently are not due to a bug + this.members.toArray().concat(this.canonicalMembers.toArray()); + + allMembers.forEach(inverseInternalModel => { + let relationship = inverseInternalModel._relationships.get(this.inverseKey); + relationship.inverseDidDematerialize(); + }); + } + + inverseDidDematerialize() {} + + updateMeta(meta) { + heimdall.increment(updateMeta); + this.meta = meta; + } + + clear() { + heimdall.increment(clear); + + let members = this.members.list; + while (members.length > 0) { + let member = members[0]; + this.removeInternalModel(member); + } + + let canonicalMembers = this.canonicalMembers.list; + while (canonicalMembers.length > 0) { + let member = canonicalMembers[0]; + this.removeCanonicalInternalModel(member); + } + } + + removeInternalModels(internalModels) { + heimdall.increment(removeInternalModels); + internalModels.forEach((internalModel) => this.removeInternalModel(internalModel)); + } + + addInternalModels(internalModels, idx) { + heimdall.increment(addInternalModels); + internalModels.forEach(internalModel => { + this.addInternalModel(internalModel, idx); + if (idx !== undefined) { + idx++; + } + }); + } + + addCanonicalInternalModels(internalModels, idx) { + heimdall.increment(addCanonicalInternalModels); + for (let i=0; i result); + } + } + + updateInternalModelsFromAdapter(internalModels) { + heimdall.increment(updateInternalModelsFromAdapter); + //TODO(Igor) move this to a proper place + //TODO Once we have adapter support, we need to handle updated and canonical changes + this.computeChanges(internalModels); + } + + notifyRecordRelationshipAdded() { } + notifyRecordRelationshipRemoved() { } + + /* + `hasData` for a relationship is a flag to indicate if we consider the + content of this relationship "known". Snapshots uses this to tell the + difference between unknown (`undefined`) or empty (`null`). The reason for + this is that we wouldn't want to serialize unknown relationships as `null` + as that might overwrite remote state. + + All relationships for a newly created (`store.createRecord()`) are + considered known (`hasData === true`). + */ + setHasData(value) { + heimdall.increment(setHasData); + this.hasData = value; + } + + /* + `hasLoaded` is a flag to indicate if we have gotten data from the adapter or + not when the relationship has a link. + + This is used to be able to tell when to fetch the link and when to return + the local data in scenarios where the local state is considered known + (`hasData === true`). + + Updating the link will automatically set `hasLoaded` to `false`. + */ + setHasLoaded(value) { + heimdall.increment(setHasLoaded); + this.hasLoaded = value; + } + + /* + `push` for a relationship allows the store to push a JSON API Relationship + Object onto the relationship. The relationship will then extract and set the + meta, data and links of that relationship. + + `push` use `updateMeta`, `updateData` and `updateLink` to update the state + of the relationship. + */ + push(payload, initial) { + heimdall.increment(push); + + let hasData = false; + let hasLink = false; + + if (payload.meta) { + this.updateMeta(payload.meta); + } + + if (payload.data !== undefined) { + hasData = true; + this.updateData(payload.data, initial); + } + + if (payload.links && payload.links.related) { + let relatedLink = _normalizeLink(payload.links.related); + if (relatedLink && relatedLink.href && relatedLink.href !== this.link) { + hasLink = true; + this.updateLink(relatedLink.href, initial); + } + } + + /* + Data being pushed into the relationship might contain only data or links, + or a combination of both. + + If we got data we want to set both hasData and hasLoaded to true since + this would indicate that we should prefer the local state instead of + trying to fetch the link or call findRecord(). + + If we have no data but a link is present we want to set hasLoaded to false + without modifying the hasData flag. This will ensure we fetch the updated + link next time the relationship is accessed. + */ + if (hasData) { + this.setHasData(true); + this.setHasLoaded(true); + } else if (hasLink) { + this.setHasLoaded(false); + } + } + + updateData() {} +} + +const { + get: get$7 +} = Ember; + +const { + __bind, + __guard, + __objectIsAlive +} = heimdall.registerMonitor('system.store.common', + '_bind', + '_guard', + '_objectIsAlive' +); + +function _bind(fn, ...args) { + heimdall.increment(__bind); + + return function() { + return fn.apply(undefined, args); + }; +} + +function _guard(promise, test) { + heimdall.increment(__guard); + let guarded = promise['finally'](function() { + if (!test()) { + guarded._subscribers.length = 0; + } + }); + + return guarded; +} + +function _objectIsAlive(object) { + heimdall.increment(__objectIsAlive); + return !(get$7(object, "isDestroyed") || get$7(object, "isDestroying")); +} + +/** + @namespace + @method diff-array + @for DS + @param {Array} oldArray the old array + @param {Array} newArray the new array + @return {hash} { + firstChangeIndex: , // null if no change + addedCount: , // 0 if no change + removedCount: // 0 if no change + } +*/ +function diffArray(oldArray, newArray) { + const oldLength = oldArray.length; + const newLength = newArray.length; + + const shortestLength = Math.min(oldLength, newLength); + let firstChangeIndex = null; // null signifies no changes + + // find the first change + for (let i=0; i 1 + // meta.total => 5 + }); + ``` + + @property {Object} meta + @public + */ + this.meta = this.meta || null; + + /** + `true` if the relationship is polymorphic, `false` otherwise. + + @property {Boolean} isPolymorphic + @private + */ + this.isPolymorphic = this.isPolymorphic || false; + + /** + The relationship which manages this array. + + @property {ManyRelationship} relationship + @private + */ + this.relationship = this.relationship || null; + + this.currentState = []; + this.flushCanonical(false); + }, + + objectAt(index) { + let internalModel = this.currentState[index]; + if (internalModel === undefined) { return; } + + return internalModel.getRecord(); + }, + + flushCanonical(isInitialized = true) { + // It’s possible the parent side of the relationship may have been unloaded by this point + if (!_objectIsAlive(this)) { + return; + } + let toSet = this.canonicalState; + + //a hack for not removing new records + //TODO remove once we have proper diffing + let newInternalModels = this.currentState.filter( + // only add new internalModels which are not yet in the canonical state of this + // relationship (a new internalModel can be in the canonical state if it has + // been 'acknowleged' to be in the relationship via a store.push) + (internalModel) => internalModel.isNew() && toSet.indexOf(internalModel) === -1 + ); + toSet = toSet.concat(newInternalModels); + + // diff to find changes + let diff = diffArray(this.currentState, toSet); + + if (diff.firstChangeIndex !== null) { // it's null if no change found + // we found a change + this.arrayContentWillChange(diff.firstChangeIndex, diff.removedCount, diff.addedCount); + this.set('length', toSet.length); + this.currentState = toSet; + this.arrayContentDidChange(diff.firstChangeIndex, diff.removedCount, diff.addedCount); + if (isInitialized && diff.addedCount > 0) { + //notify only on additions + //TODO only notify if unloaded + this.relationship.notifyHasManyChanged(); + } + } + }, + + internalReplace(idx, amt, objects) { + if (!objects) { + objects = []; + } + this.arrayContentWillChange(idx, amt, objects.length); + this.currentState.splice.apply(this.currentState, [idx, amt].concat(objects)); + this.set('length', this.currentState.length); + this.arrayContentDidChange(idx, amt, objects.length); + }, + + //TODO(Igor) optimize + _removeInternalModels(internalModels) { + for (let i=0; i < internalModels.length; i++) { + let index = this.currentState.indexOf(internalModels[i]); + this.internalReplace(index, 1); + } + }, + + //TODO(Igor) optimize + _addInternalModels(internalModels, idx) { + if (idx === undefined) { + idx = this.currentState.length; + } + this.internalReplace(idx, 0, internalModels); + }, + + replace(idx, amt, objects) { + let internalModels; + if (amt > 0) { + internalModels = this.currentState.slice(idx, idx+amt); + this.get('relationship').removeInternalModels(internalModels); + } + if (objects) { + this.get('relationship').addInternalModels(objects.map(obj => obj._internalModel), idx); + } + }, + + /** + Reloads all of the records in the manyArray. If the manyArray + holds a relationship that was originally fetched using a links url + Ember Data will revisit the original links url to repopulate the + relationship. + + If the manyArray holds the result of a `store.query()` reload will + re-run the original query. + + Example + + ```javascript + var user = store.peekRecord('user', 1) + user.login().then(function() { + user.get('permissions').then(function(permissions) { + return permissions.reload(); + }); + }); + ``` + + @method reload + @public + */ + reload() { + return this.relationship.reload(); + }, + + /** + Saves all of the records in the `ManyArray`. + + Example + + ```javascript + store.findRecord('inbox', 1).then(function(inbox) { + inbox.get('messages').then(function(messages) { + messages.forEach(function(message) { + message.set('isRead', true); + }); + messages.save() + }); + }); + ``` + + @method save + @return {DS.PromiseArray} promise + */ + save() { + let manyArray = this; + let promiseLabel = 'DS: ManyArray#save ' + get$6(this, 'type'); + let promise = Ember.RSVP.all(this.invoke("save"), promiseLabel). + then(() => manyArray, null, 'DS: ManyArray#save return ManyArray'); + + return PromiseArray.create({ promise }); + }, + + /** + Create a child record within the owner + + @method createRecord + @private + @param {Object} hash + @return {DS.Model} record + */ + createRecord(hash) { + const store = get$6(this, 'store'); + const type = get$6(this, 'type'); + + assert(`You cannot add '${type.modelName}' records to this polymorphic relationship.`, !get$6(this, 'isPolymorphic')); + let record = store.createRecord(type.modelName, hash); + this.pushObject(record); + + return record; + } +}); + +class ManyRelationship extends Relationship { + constructor(store, internalModel, inverseKey, relationshipMeta) { + super(store, internalModel, inverseKey, relationshipMeta); + this.belongsToType = relationshipMeta.type; + this.canonicalState = []; + this.isPolymorphic = relationshipMeta.options.polymorphic; + this._manyArray = null; + this.__loadingPromise = null; + } + + get _loadingPromise() { return this.__loadingPromise; } + _updateLoadingPromise(promise, content) { + if (this.__loadingPromise) { + if (content) { + this.__loadingPromise.set('content', content); + } + this.__loadingPromise.set('promise', promise); + } else { + this.__loadingPromise = new PromiseManyArray({ + promise, + content + }); + } + + return this.__loadingPromise; + } + + get manyArray() { + if (!this._manyArray) { + this._manyArray = ManyArray.create({ + canonicalState: this.canonicalState, + store: this.store, + relationship: this, + type: this.store.modelFor(this.belongsToType), + record: this.internalModel, + meta: this.meta, + isPolymorphic: this.isPolymorphic + }); + } + return this._manyArray; + } + + removeInverseRelationships() { + super.removeInverseRelationships(); + if (this._manyArray) { + this._manyArray.destroy(); + this._manyArray = null; + } + + if (this._loadingPromise) { + this._loadingPromise.destroy(); + } + } + + updateMeta(meta) { + super.updateMeta(meta); + if (this._manyArray) { + this._manyArray.set('meta', meta); + } + } + + addCanonicalInternalModel(internalModel, idx) { + if (this.canonicalMembers.has(internalModel)) { + return; + } + if (idx !== undefined) { + this.canonicalState.splice(idx, 0, internalModel); + } else { + this.canonicalState.push(internalModel); + } + super.addCanonicalInternalModel(internalModel, idx); + } + + inverseDidDematerialize() { + if (this._manyArray) { + this._manyArray.destroy(); + this._manyArray = null; + } + this.notifyHasManyChanged(); + } + + addInternalModel(internalModel, idx) { + if (this.members.has(internalModel)) { + return; + } + + assertPolymorphicType(this.internalModel, this.relationshipMeta, internalModel); + super.addInternalModel(internalModel, idx); + // make lazy later + this.manyArray._addInternalModels([internalModel], idx); + } + + removeCanonicalInternalModelFromOwn(internalModel, idx) { + let i = idx; + if (!this.canonicalMembers.has(internalModel)) { + return; + } + if (i === undefined) { + i = this.canonicalState.indexOf(internalModel); + } + if (i > -1) { + this.canonicalState.splice(i, 1); + } + super.removeCanonicalInternalModelFromOwn(internalModel, idx); + } + + flushCanonical() { + if (this._manyArray) { + this._manyArray.flushCanonical(); + } + super.flushCanonical(); + } + + removeInternalModelFromOwn(internalModel, idx) { + if (!this.members.has(internalModel)) { + return; + } + super.removeInternalModelFromOwn(internalModel, idx); + let manyArray = this.manyArray; + if (idx !== undefined) { + //TODO(Igor) not used currently, fix + manyArray.currentState.removeAt(idx); + } else { + manyArray._removeInternalModels([internalModel]); + } + } + + notifyRecordRelationshipAdded(internalModel, idx) { + this.internalModel.notifyHasManyAdded(this.key, internalModel, idx); + } + + reload() { + let manyArray = this.manyArray; + let manyArrayLoadedState = manyArray.get('isLoaded'); + + if (this._loadingPromise) { + if (this._loadingPromise.get('isPending')) { + return this._loadingPromise; + } + if (this._loadingPromise.get('isRejected')) { + manyArray.set('isLoaded', manyArrayLoadedState); + } + } + + let promise; + if (this.link) { + promise = this.fetchLink(); + } else { + promise = this.store._scheduleFetchMany(manyArray.currentState).then(() => manyArray); + } + + this._updateLoadingPromise(promise); + return this._loadingPromise; + } + + computeChanges(internalModels = []) { + let members = this.canonicalMembers; + let internalModelsToRemove = []; + let internalModelSet = setForArray(internalModels); + + members.forEach(member => { + if (internalModelSet.has(member)) { return; } + + internalModelsToRemove.push(member); + }); + + this.removeCanonicalInternalModels(internalModelsToRemove); + + for (let i = 0, l = internalModels.length; i < l; i++) { + let internalModel = internalModels[i]; + this.removeCanonicalInternalModel(internalModel); + this.addCanonicalInternalModel(internalModel, i); + } + } + + setInitialInternalModels(internalModels) { + if (!internalModels) { + return; + } + + let args = [0, this.canonicalState.length].concat(internalModels); + this.canonicalState.splice.apply(this.canonicalState, args); + internalModels.forEach(internalModel => { + this.canonicalMembers.add(internalModel); + this.members.add(internalModel); + this.setupInverseRelationship(internalModel); + }); + } + + fetchLink() { + return this.store.findHasMany(this.internalModel, this.link, this.relationshipMeta).then(records => { + if (records.hasOwnProperty('meta')) { + this.updateMeta(records.meta); + } + this.store._backburner.join(() => { + this.updateInternalModelsFromAdapter(records); + this.manyArray.set('isLoaded', true); + }); + return this.manyArray; + }); + } + + findRecords() { + let manyArray = this.manyArray; + let internalModels = manyArray.currentState; + + //TODO CLEANUP + return this.store.findMany(internalModels).then(() => { + if (!manyArray.get('isDestroyed')) { + //Goes away after the manyArray refactor + manyArray.set('isLoaded', true); + } + return manyArray; + }); + } + + notifyHasManyChanged() { + this.internalModel.notifyHasManyAdded(this.key); + } + + getRecords() { + //TODO(Igor) sync server here, once our syncing is not stupid + let manyArray = this.manyArray; + if (this.isAsync) { + let promise; + if (this.link) { + if (this.hasLoaded) { + promise = this.findRecords(); + } else { + promise = this.findLink().then(() => this.findRecords()); + } + } else { + promise = this.findRecords(); + } + return this._updateLoadingPromise(promise, manyArray); + } else { + assert(`You looked up the '${this.key}' relationship on a '${this.internalModel.type.modelName}' with id ${this.internalModel.id} but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async ('DS.hasMany({ async: true })')`, manyArray.isEvery('isEmpty', false)); + + //TODO(Igor) WTF DO I DO HERE? + // TODO @runspired equal WTFs to Igor + if (!manyArray.get('isDestroyed')) { + manyArray.set('isLoaded', true); + } + return manyArray; + } + } + + updateData(data, initial) { + let internalModels = this.store._pushResourceIdentifiers(this, data); + if (initial) { + this.setInitialInternalModels(internalModels); + } else { + this.updateInternalModelsFromAdapter(internalModels); + } + } +} + +function setForArray(array) { + var set = new OrderedSet(); + + if (array) { + for (var i=0, l=array.length; i { + if (internalModel) { + this.addInternalModel(internalModel); + } + return internalModel; + }); + } + + getRecord() { + //TODO(Igor) flushCanonical here once our syncing is not stupid + if (this.isAsync) { + let promise; + if (this.link) { + if (this.hasLoaded) { + promise = this.findRecord(); + } else { + promise = this.findLink().then(() => this.findRecord()); + } + } else { + promise = this.findRecord(); + } + + return PromiseObject.create({ + promise: promise, + content: this.inverseInternalModel ? this.inverseInternalModel.getRecord() : null + }); + } else { + if (this.inverseInternalModel === null) { + return null; + } + let toReturn = this.inverseInternalModel.getRecord(); + assert("You looked up the '" + this.key + "' relationship on a '" + this.internalModel.modelName + "' with id " + this.internalModel.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); + return toReturn; + } + } + + reload() { + // TODO handle case when reload() is triggered multiple times + + if (this.link) { + return this.fetchLink(); + } + + // reload record, if it is already loaded + if (this.inverseInternalModel && this.inverseInternalModel.hasRecord) { + return this.inverseInternalModel.getRecord().reload(); + } + + return this.findRecord(); + } + + updateData(data, initial) { + assert(`Ember Data expected the data for the ${this.key} relationship on a ${this.internalModel.toString()} to be in a JSON API format and include an \`id\` and \`type\` property but it found ${Ember.inspect(data)}. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || data.id !== undefined && data.type !== undefined); + let internalModel = this.store._pushResourceIdentifier(this, data); + if (initial) { + this.setInitialCanonicalInternalModel(internalModel); + } else { + this.setCanonicalInternalModel(internalModel); + } + } +} + +const { get: get$5 } = Ember; + +function shouldFindInverse(relationshipMeta) { + let options = relationshipMeta.options; + return !(options && options.inverse === null); +} + +function createRelationshipFor(internalModel, relationshipMeta, store) { + let inverseKey; + let inverse = null; + + if (shouldFindInverse(relationshipMeta)) { + inverse = internalModel.type.inverseFor(relationshipMeta.key, store); + } else { + runInDebug(() => { + internalModel.type.typeForRelationship(relationshipMeta.key, store); + }); + } + + if (inverse) { + inverseKey = inverse.name; + } + + if (relationshipMeta.kind === 'hasMany') { + return new ManyRelationship(store, internalModel, inverseKey, relationshipMeta); + } else { + return new BelongsToRelationship(store, internalModel, inverseKey, relationshipMeta); + } +} + +class Relationships { + constructor(internalModel) { + this.internalModel = internalModel; + this.initializedRelationships = Object.create(null); + } + + // TODO @runspired deprecate this as it was never truly a record instance + get record() { + return this.internalModel; + } + + has(key) { + return !!this.initializedRelationships[key]; + } + + get(key) { + let relationships = this.initializedRelationships; + let relationship = relationships[key]; + let internalModel = this.internalModel; + + if (!relationship) { + let relationshipsByName = get$5(internalModel.type, 'relationshipsByName'); + let rel = relationshipsByName.get(key); + + if (!rel) { return undefined; } + + let relationshipPayload = internalModel.store._relationshipsPayloads.get(internalModel.modelName, internalModel.id, key); + + relationship = relationships[key] = createRelationshipFor(internalModel, rel, internalModel.store); + + if (relationshipPayload) { + relationship.push(relationshipPayload, true); + } + } + + return relationship; + } +} + +/** + @module ember-data +*/ + +const { + get: get$8 +} = Ember; + +/** + @class Snapshot + @namespace DS + @private + @constructor + @param {DS.Model} internalModel The model to create a snapshot from +*/ +class Snapshot { + constructor(internalModel, options = {}) { + this._attributes = Object.create(null); + this._belongsToRelationships = Object.create(null); + this._belongsToIds = Object.create(null); + this._hasManyRelationships = Object.create(null); + this._hasManyIds = Object.create(null); + this._internalModel = internalModel; + + let record = internalModel.getRecord(); + + /** + The underlying record for this snapshot. Can be used to access methods and + properties defined on the record. + + Example + + ```javascript + let json = snapshot.record.toJSON(); + ``` + + @property record + @type {DS.Model} + */ + this.record = record; + record.eachAttribute((keyName) => this._attributes[keyName] = get$8(record, keyName)); + + /** + The id of the snapshot's underlying record + + Example + + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postSnapshot.id; // => '1' + ``` + + @property id + @type {String} + */ + this.id = internalModel.id; + + /** + A hash of adapter options + @property adapterOptions + @type {Object} + */ + this.adapterOptions = options.adapterOptions; + this.include = options.include; + + /** + The name of the type of the underlying record for this snapshot, as a string. + + @property modelName + @type {String} + */ + this.modelName = internalModel.modelName; + + this._changedAttributes = record.changedAttributes(); + } + + /** + The type of the underlying record for this snapshot, as a DS.Model. + + @property type + @type {DS.Model} + */ + get type() { + // TODO @runspired we should deprecate this in favor of modelClass but only once + // we've cleaned up the internals enough that a public change to follow suite is + // uncontroversial. + return this._internalModel.modelClass; + } + + /** + Returns the value of an attribute. + + Example + + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postSnapshot.attr('author'); // => 'Tomster' + postSnapshot.attr('title'); // => 'Ember.js rocks' + ``` + + Note: Values are loaded eagerly and cached when the snapshot is created. + + @method attr + @param {String} keyName + @return {Object} The attribute value or undefined + */ + attr(keyName) { + if (keyName in this._attributes) { + return this._attributes[keyName]; + } + throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no attribute named '" + keyName + "' defined."); + } + + /** + Returns all attributes and their corresponding values. + + Example + + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postSnapshot.attributes(); // => { author: 'Tomster', title: 'Ember.js rocks' } + ``` + + @method attributes + @return {Object} All attributes of the current snapshot + */ + attributes() { + return Ember.copy(this._attributes); + } + + /** + Returns all changed attributes and their old and new values. + + Example + + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postModel.set('title', 'Ember.js rocks!'); + postSnapshot.changedAttributes(); // => { title: ['Ember.js rocks', 'Ember.js rocks!'] } + ``` + + @method changedAttributes + @return {Object} All changed attributes of the current snapshot + */ + changedAttributes() { + let changedAttributes = Object.create(null); + let changedAttributeKeys = Object.keys(this._changedAttributes); + + for (let i=0, length = changedAttributeKeys.length; i < length; i++) { + let key = changedAttributeKeys[i]; + changedAttributes[key] = Ember.copy(this._changedAttributes[key]); + } + + return changedAttributes; + } + + /** + Returns the current value of a belongsTo relationship. + + `belongsTo` takes an optional hash of options as a second parameter, + currently supported options are: + + - `id`: set to `true` if you only want the ID of the related record to be + returned. + + Example + + ```javascript + // store.push('post', { id: 1, title: 'Hello World' }); + // store.createRecord('comment', { body: 'Lorem ipsum', post: post }); + commentSnapshot.belongsTo('post'); // => DS.Snapshot + commentSnapshot.belongsTo('post', { id: true }); // => '1' + + // store.push('comment', { id: 1, body: 'Lorem ipsum' }); + commentSnapshot.belongsTo('post'); // => undefined + ``` + + Calling `belongsTo` will return a new Snapshot as long as there's any known + data for the relationship available, such as an ID. If the relationship is + known but unset, `belongsTo` will return `null`. If the contents of the + relationship is unknown `belongsTo` will return `undefined`. + + Note: Relationships are loaded lazily and cached upon first access. + + @method belongsTo + @param {String} keyName + @param {Object} [options] + @return {(DS.Snapshot|String|null|undefined)} A snapshot or ID of a known + relationship or null if the relationship is known but unset. undefined + will be returned if the contents of the relationship is unknown. + */ + belongsTo(keyName, options) { + let id = options && options.id; + let relationship, inverseInternalModel, hasData; + let result; + + if (id && keyName in this._belongsToIds) { + return this._belongsToIds[keyName]; + } + + if (!id && keyName in this._belongsToRelationships) { + return this._belongsToRelationships[keyName]; + } + + relationship = this._internalModel._relationships.get(keyName); + if (!(relationship && relationship.relationshipMeta.kind === 'belongsTo')) { + throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined."); + } + + hasData = get$8(relationship, 'hasData'); + inverseInternalModel = get$8(relationship, 'inverseInternalModel'); + + if (hasData) { + if (inverseInternalModel && !inverseInternalModel.isDeleted()) { + if (id) { + result = get$8(inverseInternalModel, 'id'); + } else { + result = inverseInternalModel.createSnapshot(); + } + } else { + result = null; + } + } + + if (id) { + this._belongsToIds[keyName] = result; + } else { + this._belongsToRelationships[keyName] = result; + } + + return result; + } + + /** + Returns the current value of a hasMany relationship. + + `hasMany` takes an optional hash of options as a second parameter, + currently supported options are: + + - `ids`: set to `true` if you only want the IDs of the related records to be + returned. + + Example + + ```javascript + // store.push('post', { id: 1, title: 'Hello World', comments: [2, 3] }); + postSnapshot.hasMany('comments'); // => [DS.Snapshot, DS.Snapshot] + postSnapshot.hasMany('comments', { ids: true }); // => ['2', '3'] + + // store.push('post', { id: 1, title: 'Hello World' }); + postSnapshot.hasMany('comments'); // => undefined + ``` + + Note: Relationships are loaded lazily and cached upon first access. + + @method hasMany + @param {String} keyName + @param {Object} [options] + @return {(Array|undefined)} An array of snapshots or IDs of a known + relationship or an empty array if the relationship is known but unset. + undefined will be returned if the contents of the relationship is unknown. + */ + hasMany(keyName, options) { + let ids = options && options.ids; + let relationship, members, hasData; + let results; + + if (ids && keyName in this._hasManyIds) { + return this._hasManyIds[keyName]; + } + + if (!ids && keyName in this._hasManyRelationships) { + return this._hasManyRelationships[keyName]; + } + + relationship = this._internalModel._relationships.get(keyName); + if (!(relationship && relationship.relationshipMeta.kind === 'hasMany')) { + throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined."); + } + + hasData = get$8(relationship, 'hasData'); + members = get$8(relationship, 'members'); + + if (hasData) { + results = []; + members.forEach((member) => { + if (!member.isDeleted()) { + if (ids) { + results.push(member.id); + } else { + results.push(member.createSnapshot()); + } + } + }); + } + + if (ids) { + this._hasManyIds[keyName] = results; + } else { + this._hasManyRelationships[keyName] = results; + } + + return results; + } + + /** + Iterates through all the attributes of the model, calling the passed + function on each attribute. + + Example + + ```javascript + snapshot.eachAttribute(function(name, meta) { + // ... + }); + ``` + + @method eachAttribute + @param {Function} callback the callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + */ + eachAttribute(callback, binding) { + this.record.eachAttribute(callback, binding); + } + + /** + Iterates through all the relationships of the model, calling the passed + function on each relationship. + + Example + + ```javascript + snapshot.eachRelationship(function(name, relationship) { + // ... + }); + ``` + + @method eachRelationship + @param {Function} callback the callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + */ + eachRelationship(callback, binding) { + this.record.eachRelationship(callback, binding); + } + + /** + Serializes the snapshot using the serializer for the model. + + Example + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + createRecord(store, type, snapshot) { + var data = snapshot.serialize({ includeId: true }); + var url = `/${type.modelName}`; + + return fetch(url, { + method: 'POST', + body: data, + }).then((response) => response.json()) + } + }); + ``` + + @method serialize + @param {Object} options + @return {Object} an object whose values are primitive JSON values only + */ + serialize(options) { + return this.record.store.serializerFor(this.modelName).serialize(this, options); + } +} + +const get$9 = Ember.get; + +/* + Check if the passed model has a `type` attribute or a relationship named `type`. + + @method modelHasAttributeOrRelationshipNamedType + @param modelClass + */ +function modelHasAttributeOrRelationshipNamedType(modelClass) { + return get$9(modelClass, 'attributes').has('type') || get$9(modelClass, 'relationshipsByName').has('type'); +} + +/* + ember-container-inject-owner is a new feature in Ember 2.3 that finally provides a public + API for looking items up. This function serves as a super simple polyfill to avoid + triggering deprecations. + */ +function getOwner(context) { + let owner; + + if (Ember.getOwner) { + owner = Ember.getOwner(context); + } else if (context.container) { + owner = context.container; + } + + if (owner && owner.lookupFactory && !owner._lookupFactory) { + // `owner` is a container, we are just making this work + owner._lookupFactory = owner.lookupFactory; + owner.register = function() { + let registry = owner.registry || owner._registry || owner; + + return registry.register(...arguments); + }; + } + + return owner; +} + +var Reference = function(store, internalModel) { + this.store = store; + this.internalModel = internalModel; +}; + +Reference.prototype = { + constructor: Reference +}; + +/** + An RecordReference is a low level API that allows users and + addon author to perform meta-operations on a record. + + @class RecordReference + @namespace DS +*/ +const RecordReference = function(store, internalModel) { + this._super$constructor(store, internalModel); + this.type = internalModel.modelName; + this._id = internalModel.id; +}; + +RecordReference.prototype = Object.create(Reference.prototype); +RecordReference.prototype.constructor = RecordReference; +RecordReference.prototype._super$constructor = Reference; + +/** + The `id` of the record that this reference refers to. + + Together, the `type` and `id` properties form a composite key for + the identity map. + + Example + + ```javascript + let userRef = store.getReference('user', 1); + + userRef.id(); // '1' + ``` + + @method id + @return {String} The id of the record. +*/ +RecordReference.prototype.id = function() { + return this._id; +}; + +/** + How the reference will be looked up when it is loaded: Currently + this always return `identity` to signifying that a record will be + loaded by the `type` and `id`. + + Example + + ```javascript + const userRef = store.getReference('user', 1); + + userRef.remoteType(); // 'identity' + ``` + + @method remoteType + @return {String} 'identity' +*/ +RecordReference.prototype.remoteType = function() { + return 'identity'; +}; + +/** + This API allows you to provide a reference with new data. The + simplest usage of this API is similar to `store.push`: you provide a + normalized hash of data and the object represented by the reference + will update. + + If you pass a promise to `push`, Ember Data will not ask the adapter + for the data if another attempt to fetch it is made in the + interim. When the promise resolves, the underlying object is updated + with the new data, and the promise returned by *this function* is resolved + with that object. + + For example, `recordReference.push(promise)` will be resolved with a + record. + + Example + + ```javascript + let userRef = store.getReference('user', 1); + + // provide data for reference + userRef.push({ data: { id: 1, username: "@user" }}).then(function(user) { + userRef.value() === user; + }); + ``` + + @method push + @param {Promise|Object} + @return Promise a promise for the value (record or relationship) +*/ +RecordReference.prototype.push = function(objectOrPromise) { + return Ember.RSVP.resolve(objectOrPromise).then((data) => { + return this.store.push(data); + }); +}; + +/** + If the entity referred to by the reference is already loaded, it is + present as `reference.value`. Otherwise the value returned by this function + is `null`. + + Example + + ```javascript + let userRef = store.getReference('user', 1); + + userRef.value(); // user + ``` + + @method value + @return {DS.Model} the record for this RecordReference +*/ +RecordReference.prototype.value = function() { + if (this.internalModel.hasRecord) { + return this.internalModel.getRecord(); + } +}; + +/** + Triggers a fetch for the backing entity based on its `remoteType` + (see `remoteType` definitions per reference type). + + Example + + ```javascript + let userRef = store.getReference('user', 1); + + // load user (via store.find) + userRef.load().then(...) + ``` + + @method load + @return {Promise} the record for this RecordReference +*/ +RecordReference.prototype.load = function() { + return this.store.findRecord(this.type, this._id); +}; + +/** + Reloads the record if it is already loaded. If the record is not + loaded it will load the record via `store.findRecord` + + Example + + ```javascript + let userRef = store.getReference('user', 1); + + // or trigger a reload + userRef.reload().then(...) + ``` + + @method reload + @return {Promise} the record for this RecordReference +*/ +RecordReference.prototype.reload = function() { + let record = this.value(); + if (record) { + return record.reload(); + } + + return this.load(); +}; + +// TODO import from here because else creates circular +// import Model from 'ember-data/model'; +/** + A BelongsToReference is a low level API that allows users and + addon author to perform meta-operations on a belongs-to + relationship. + + @class BelongsToReference + @namespace DS + @extends DS.Reference +*/ +const BelongsToReference = function(store, parentInternalModel, belongsToRelationship) { + this._super$constructor(store, parentInternalModel); + this.belongsToRelationship = belongsToRelationship; + this.type = belongsToRelationship.relationshipMeta.type; + this.parent = parentInternalModel.recordReference; + + // TODO inverse +}; + +BelongsToReference.prototype = Object.create(Reference.prototype); +BelongsToReference.prototype.constructor = BelongsToReference; +BelongsToReference.prototype._super$constructor = Reference; + +/** + This returns a string that represents how the reference will be + looked up when it is loaded. If the relationship has a link it will + use the "link" otherwise it defaults to "id". + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + }); + let userRef = blog.belongsTo('user'); + + // get the identifier of the reference + if (userRef.remoteType() === "id") { + let id = userRef.id(); + } else if (userRef.remoteType() === "link") { + let link = userRef.link(); + } + ``` + + @method remoteType + @return {String} The name of the remote type. This should either be "link" or "id" +*/ +BelongsToReference.prototype.remoteType = function() { + if (this.belongsToRelationship.link) { + return "link"; + } + + return "id"; +}; + +/** + The `id` of the record that this reference refers to. Together, the + `type()` and `id()` methods form a composite key for the identity + map. This can be used to access the id of an async relationship + without triggering a fetch that would normally happen if you + attempted to use `record.get('relationship.id')`. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + let userRef = blog.belongsTo('user'); + + // get the identifier of the reference + if (userRef.remoteType() === "id") { + let id = userRef.id(); + } + ``` + + @method id + @return {String} The id of the record in this belongsTo relationship. +*/ +BelongsToReference.prototype.id = function() { + let inverseInternalModel = this.belongsToRelationship.inverseInternalModel; + return inverseInternalModel && inverseInternalModel.id; +}; + +/** + The link Ember Data will use to fetch or reload this belongs-to + relationship. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + links: { + related: '/articles/1/author' + } + } + } + } + }); + let userRef = blog.belongsTo('user'); + + // get the identifier of the reference + if (userRef.remoteType() === "link") { + let link = userRef.link(); + } + ``` + + @method link + @return {String} The link Ember Data will use to fetch or reload this belongs-to relationship. +*/ +BelongsToReference.prototype.link = function() { + return this.belongsToRelationship.link; +}; + +/** + The meta data for the belongs-to relationship. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + links: { + related: { + href: '/articles/1/author', + meta: { + lastUpdated: 1458014400000 + } + } + } + } + } + } + }); + + let userRef = blog.belongsTo('user'); + + userRef.meta() // { lastUpdated: 1458014400000 } + ``` + + @method meta + @return {Object} The meta information for the belongs-oo relationship. +*/ +BelongsToReference.prototype.meta = function() { + return this.belongsToRelationship.meta; +}; + +/** + `push` can be used to update the data in the relationship and Ember + Data will treat the new data as the conanical value of this + relationship on the backend. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + let userRef = blog.belongsTo('user'); + + // provide data for reference + userRef.push({ + data: { + type: 'user', + id: 1, + attributes: { + username: "@user" + } + } + }).then(function(user) { + userRef.value() === user; + }); + ``` + + @method push + @param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. + @return {Promise} A promise that resolves with the new value in this belongs-to relationship. +*/ +BelongsToReference.prototype.push = function(objectOrPromise) { + return Ember.RSVP.resolve(objectOrPromise).then((data) => { + let record; + + if (data instanceof Model) { + if (isEnabled('ds-overhaul-references')) { + deprecate("BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead.", false, { + id: 'ds.references.belongs-to.push-record', + until: '3.0' + }); + } + record = data; + } else { + record = this.store.push(data); + } + + assertPolymorphicType(this.internalModel, this.belongsToRelationship.relationshipMeta, record._internalModel); + + this.belongsToRelationship.setCanonicalInternalModel(record._internalModel); + + return record; + }); +}; + +/** + `value()` synchronously returns the current value of the belongs-to + relationship. Unlike `record.get('relationshipName')`, calling + `value()` on a reference does not trigger a fetch if the async + relationship is not yet loaded. If the relationship is not loaded + it will always return `null`. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + let userRef = blog.belongsTo('user'); + + userRef.value(); // null + + // provide data for reference + userRef.push({ + data: { + type: 'user', + id: 1, + attributes: { + username: "@user" + } + } + }).then(function(user) { + userRef.value(); // user + }); + ``` + + @method value + @param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. + @return {DS.Model} the record in this relationship +*/ +BelongsToReference.prototype.value = function() { + let inverseInternalModel = this.belongsToRelationship.inverseInternalModel; + + if (inverseInternalModel && inverseInternalModel.isLoaded()) { + return inverseInternalModel.getRecord(); + } + + return null; +}; + +/** + Loads a record in a belongs to relationship if it is not already + loaded. If the relationship is already loaded this method does not + trigger a new load. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + let userRef = blog.belongsTo('user'); + + userRef.value(); // null + + userRef.load().then(function(user) { + userRef.value() === user + }); + + @method load + @return {Promise} a promise that resolves with the record in this belongs-to relationship. +*/ +BelongsToReference.prototype.load = function() { + if (this.remoteType() === "id") { + return this.belongsToRelationship.getRecord(); + } + + if (this.remoteType() === "link") { + return this.belongsToRelationship.findLink().then((internalModel) => { + return this.value(); + }); + } +}; + +/** + Triggers a reload of the value in this relationship. If the + remoteType is `"link"` Ember Data will use the relationship link to + reload the relationship. Otherwise it will reload the record by its + id. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + let userRef = blog.belongsTo('user'); + + userRef.reload().then(function(user) { + userRef.value() === user + }); + + @method reload + @return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed. +*/ +BelongsToReference.prototype.reload = function() { + return this.belongsToRelationship.reload().then((internalModel) => { + return this.value(); + }); +}; + +const { + RSVP: { resolve }, + get: get$10 +} = Ember; + +/** + A HasManyReference is a low level API that allows users and addon + author to perform meta-operations on a has-many relationship. + + @class HasManyReference + @namespace DS +*/ +const HasManyReference = function(store, parentInternalModel, hasManyRelationship) { + this._super$constructor(store, parentInternalModel); + this.hasManyRelationship = hasManyRelationship; + this.type = hasManyRelationship.relationshipMeta.type; + this.parent = parentInternalModel.recordReference; + + // TODO inverse +}; + +HasManyReference.prototype = Object.create(Reference.prototype); +HasManyReference.prototype.constructor = HasManyReference; +HasManyReference.prototype._super$constructor = Reference; + +/** + This returns a string that represents how the reference will be + looked up when it is loaded. If the relationship has a link it will + use the "link" otherwise it defaults to "id". + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + // get the identifier of the reference + if (commentsRef.remoteType() === "ids") { + let ids = commentsRef.ids(); + } else if (commentsRef.remoteType() === "link") { + let link = commentsRef.link(); + } + ``` + + @method remoteType + @return {String} The name of the remote type. This should either be "link" or "ids" +*/ +HasManyReference.prototype.remoteType = function() { + if (this.hasManyRelationship.link) { + return "link"; + } + + return "ids"; +}; + +/** + The link Ember Data will use to fetch or reload this has-many + relationship. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + links: { + related: '/posts/1/comments' + } + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + commentsRef.link(); // '/posts/1/comments' + ``` + + @method link + @return {String} The link Ember Data will use to fetch or reload this has-many relationship. +*/ +HasManyReference.prototype.link = function() { + return this.hasManyRelationship.link; +}; + +/** + `ids()` returns an array of the record ids in this relationship. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + commentsRef.ids(); // ['1'] + ``` + + @method remoteType + @return {Array} The ids in this has-many relationship +*/ +HasManyReference.prototype.ids = function() { + let members = this.hasManyRelationship.members.toArray(); + + return members.map(function(internalModel) { + return internalModel.id; + }); +}; + +/** + The link Ember Data will use to fetch or reload this has-many + relationship. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + links: { + related: { + href: '/posts/1/comments', + meta: { + count: 10 + } + } + } + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + commentsRef.meta(); // { count: 10 } + ``` + + @method meta + @return {Object} The meta information for the has-many relationship. +*/ +HasManyReference.prototype.meta = function() { + return this.hasManyRelationship.meta; +}; + +/** + `push` can be used to update the data in the relationship and Ember + Data will treat the new data as the canonical value of this + relationship on the backend. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ``` + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + commentsRef.ids(); // ['1'] + + commentsRef.push([ + [{ type: 'comment', id: 2 }], + [{ type: 'comment', id: 3 }], + ]) + + commentsRef.ids(); // ['2', '3'] + ``` + + @method push + @param {Array|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. + @return {DS.ManyArray} +*/ +HasManyReference.prototype.push = function(objectOrPromise) { + return resolve(objectOrPromise).then((payload) => { + let array = payload; + + if (isEnabled("ds-overhaul-references")) { + deprecate("HasManyReference#push(array) is deprecated. Push a JSON-API document instead.", !Array.isArray(payload), { + id: 'ds.references.has-many.push-array', + until: '3.0' + }); + } + + let useLegacyArrayPush = true; + if (typeof payload === "object" && payload.data) { + array = payload.data; + useLegacyArrayPush = array.length && array[0].data; + + if (isEnabled('ds-overhaul-references')) { + deprecate("HasManyReference#push() expects a valid JSON-API document.", !useLegacyArrayPush, { + id: 'ds.references.has-many.push-invalid-json-api', + until: '3.0' + }); + } + } + + if (!isEnabled('ds-overhaul-references')) { + useLegacyArrayPush = true; + } + + let internalModels; + if (useLegacyArrayPush) { + internalModels = array.map((obj) => { + let record = this.store.push(obj); + + runInDebug(() => { + let relationshipMeta = this.hasManyRelationship.relationshipMeta; + assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel); + }); + + return record._internalModel; + }); + } else { + let records = this.store.push(payload); + internalModels = Ember.A(records).mapBy('_internalModel'); + + runInDebug(() => { + internalModels.forEach((internalModel) => { + let relationshipMeta = this.hasManyRelationship.relationshipMeta; + assertPolymorphicType(this.internalModel, relationshipMeta, internalModel); + }); + }); + } + + this.hasManyRelationship.computeChanges(internalModels); + + return this.hasManyRelationship.manyArray; + }); +}; + +HasManyReference.prototype._isLoaded = function() { + let hasData = get$10(this.hasManyRelationship, 'hasData'); + if (!hasData) { + return false; + } + + let members = this.hasManyRelationship.members.toArray(); + + return members.every(function(internalModel) { + return internalModel.isLoaded() === true; + }); +}; + +/** + `value()` sycronously returns the current value of the has-many + relationship. Unlike `record.get('relationshipName')`, calling + `value()` on a reference does not trigger a fetch if the async + relationship is not yet loaded. If the relationship is not loaded + it will always return `null`. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + post.get('comments').then(function(comments) { + commentsRef.value() === comments + }) + ``` + + @method value + @return {DS.ManyArray} +*/ +HasManyReference.prototype.value = function() { + if (this._isLoaded()) { + return this.hasManyRelationship.manyArray; + } + + return null; +}; + +/** + Loads the relationship if it is not already loaded. If the + relationship is already loaded this method does not trigger a new + load. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + commentsRef.load().then(function(comments) { + //... + }); + ``` + + @method load + @return {Promise} a promise that resolves with the ManyArray in + this has-many relationship. +*/ +HasManyReference.prototype.load = function() { + if (!this._isLoaded()) { + return this.hasManyRelationship.getRecords(); + } + + return resolve(this.hasManyRelationship.manyArray); +}; + +/** + Reloads this has-many relationship. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + commentsRef.reload().then(function(comments) { + //... + }); + ``` + + @method reload + @return {Promise} a promise that resolves with the ManyArray in this has-many relationship. +*/ +HasManyReference.prototype.reload = function() { + return this.hasManyRelationship.reload(); +}; + +const { + get: get$4, + set: set$2, + copy: copy$1, + Error: EmberError$1, + inspect: inspect$1, + isEmpty: isEmpty$1, + isEqual, + setOwner, + RSVP: RSVP$1, + RSVP: { Promise: Promise$2 } +} = Ember; + +const assign = Ember.assign || Ember.merge; + +/* + The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached + when transitioning from one state to another, so that future transitions can replay the + transition without needing to walk the state tree, collect these hook calls and determine + the state to transition into. + + A future optimization would be to build a single chained method out of the collected enters + and setups. It may also be faster to do a two level cache (from: { to }) instead of caching based + on a key that adds the two together. + */ +const TransitionChainMap = Object.create(null); + +const _extractPivotNameCache = Object.create(null); +const _splitOnDotCache = Object.create(null); + +function splitOnDot(name) { + return _splitOnDotCache[name] || ( + _splitOnDotCache[name] = name.split('.') + ); +} + +function extractPivotName(name) { + return _extractPivotNameCache[name] || ( + _extractPivotNameCache[name] = splitOnDot(name)[0] + ); +} + +function areAllModelsUnloaded(internalModels) { + for (let i=0; i { + if (this._relationships.has(key)) { + let relationship = this._relationships.get(key); + let localRelationships = relationship.members.toArray(); + let serverRelationships = relationship.canonicalMembers.toArray(); + + array = array.concat(localRelationships, serverRelationships); + } + }); + return array; + } + + + /** + Computes the set of internal models reachable from this internal model. + + Reachability is determined over the relationship graph (ie a graph where + nodes are internal models and edges are belongs to or has many + relationships). + + @return {Array} An array including `this` and all internal models reachable + from `this`. + */ + _allRelatedInternalModels() { + let array = []; + let queue = []; + let bfsId = nextBfsId++; + queue.push(this); + this._bfsId = bfsId; + while (queue.length > 0) { + let node = queue.shift(); + array.push(node); + let related = node._directlyRelatedInternalModels(); + for (let i=0; i 0; + } + + /* + Checks if the attributes which are considered as changed are still + different to the state which is acknowledged by the server. + + This method is needed when data for the internal model is pushed and the + pushed data might acknowledge dirty attributes as confirmed. + + @method updateChangedAttributes + @private + */ + updateChangedAttributes() { + heimdall.increment(updateChangedAttributes); + let changedAttributes = this.changedAttributes(); + let changedAttributeNames = Object.keys(changedAttributes); + let attrs = this._attributes; + + for (let i = 0, length = changedAttributeNames.length; i < length; i++) { + let attribute = changedAttributeNames[i]; + let data = changedAttributes[attribute]; + let oldData = data[0]; + let newData = data[1]; + + if (oldData === newData) { + delete attrs[attribute]; + } + } + } + + /* + Returns an object, whose keys are changed properties, and value is an + [oldProp, newProp] array. + + @method changedAttributes + @private + */ + changedAttributes() { + heimdall.increment(changedAttributes); + let oldData = this._data; + let currentData = this._attributes; + let inFlightData = this._inFlightAttributes; + let newData = assign(copy$1(inFlightData), currentData); + let diffData = Object.create(null); + let newDataKeys = Object.keys(newData); + + for (let i = 0, length = newDataKeys.length; i < length; i++) { + let key = newDataKeys[i]; + diffData[key] = [oldData[key], newData[key]]; + } + + return diffData; + } + + /* + @method adapterWillCommit + @private + */ + adapterWillCommit() { + this.send('willCommit'); + } + + /* + @method adapterDidDirty + @private + */ + adapterDidDirty() { + this.send('becomeDirty'); + this.updateRecordArrays(); + } + + /* + @method send + @private + @param {String} name + @param {Object} context + */ + send(name, context) { + heimdall.increment(send); + let currentState = this.currentState; + + if (!currentState[name]) { + this._unhandledEvent(currentState, name, context); + } + + return currentState[name](this, context); + } + + notifyHasManyAdded(key, record, idx) { + if (this.hasRecord) { + this._record.notifyHasManyAdded(key, record, idx); + } + } + + notifyHasManyRemoved(key, record, idx) { + if (this.hasRecord) { + this._record.notifyHasManyRemoved(key, record, idx); + } + } + + notifyBelongsToChanged(key, record) { + if (this.hasRecord) { + this._record.notifyBelongsToChanged(key, record); + } + } + + notifyPropertyChange(key) { + if (this.hasRecord) { + this._record.notifyPropertyChange(key); + } + } + + rollbackAttributes() { + let dirtyKeys; + if (this.hasChangedAttributes()) { + dirtyKeys = Object.keys(this._attributes); + this._attributes = null; + } + + + if (get$4(this, 'isError')) { + this._inFlightAttributes = null; + this.didCleanError(); + } + + //Eventually rollback will always work for relationships + //For now we support it only out of deleted state, because we + //have an explicit way of knowing when the server acked the relationship change + if (this.isDeleted()) { + //TODO: Should probably move this to the state machine somehow + this.becameReady(); + } + + if (this.isNew()) { + this.clearRelationships(); + } + + if (this.isValid()) { + this._inFlightAttributes = null; + } + + this.send('rolledBack'); + + if (dirtyKeys && dirtyKeys.length > 0) { + this._record._notifyProperties(dirtyKeys); + } + } + + /* + @method transitionTo + @private + @param {String} name + */ + transitionTo(name) { + heimdall.increment(transitionTo); + // POSSIBLE TODO: Remove this code and replace with + // always having direct reference to state objects + + let pivotName = extractPivotName(name); + let state = this.currentState; + let transitionMapId = `${state.stateName}->${name}`; + + do { + if (state.exit) { state.exit(this); } + state = state.parentState; + } while (!state[pivotName]); + + let setups; + let enters; + let i; + let l; + let map = TransitionChainMap[transitionMapId]; + + if (map) { + setups = map.setups; + enters = map.enters; + state = map.state; + } else { + setups = []; + enters = []; + + let path = splitOnDot(name); + + for (i = 0, l = path.length; i < l; i++) { + state = state[path[i]]; + + if (state.enter) { enters.push(state); } + if (state.setup) { setups.push(state); } + } + + TransitionChainMap[transitionMapId] = { setups, enters, state }; + } + + for (i = 0, l = enters.length; i < l; i++) { + enters[i].enter(this); + } + + this.currentState = state; + if (this.hasRecord) { + set$2(this._record, 'currentState', state); + } + + for (i = 0, l = setups.length; i < l; i++) { + setups[i].setup(this); + } + + this.updateRecordArrays(); + } + + _unhandledEvent(state, name, context) { + let errorMessage = "Attempted to handle event `" + name + "` "; + errorMessage += "on " + String(this) + " while in state "; + errorMessage += state.stateName + ". "; + + if (context !== undefined) { + errorMessage += "Called with " + inspect$1(context) + "."; + } + + throw new EmberError$1(errorMessage); + } + + triggerLater(...args) { + if (this._deferredTriggers.push(args) !== 1) { + return; + } + + this.store._updateInternalModel(this); + } + + _triggerDeferredTriggers() { + heimdall.increment(_triggerDeferredTriggers); + //TODO: Before 1.0 we want to remove all the events that happen on the pre materialized record, + //but for now, we queue up all the events triggered before the record was materialized, and flush + //them once we have the record + if (!this.hasRecord) { + return; + } + let triggers = this._deferredTriggers; + let record = this._record; + let trigger = record.trigger; + for (let i = 0, l= triggers.length; i { + if (this._relationships.has(name)) { + let rel = this._relationships.get(name); + rel.clear(); + rel.removeInverseRelationships(); + } + }); + Object.keys(this._implicitRelationships).forEach((key) => { + this._implicitRelationships[key].clear(); + this._implicitRelationships[key].removeInverseRelationships(); + }); + } + + destroyRelationships() { + this.eachRelationship((name, relationship) => { + if (this._relationships.has(name)) { + let rel = this._relationships.get(name); + rel.removeInverseRelationships(); + } + }); + Object.keys(this._implicitRelationships).forEach((key) => { + this._implicitRelationships[key].removeInverseRelationships(); + }); + } + + /* + When a find request is triggered on the store, the user can optionally pass in + attributes and relationships to be preloaded. These are meant to behave as if they + came back from the server, except the user obtained them out of band and is informing + the store of their existence. The most common use case is for supporting client side + nested URLs, such as `/posts/1/comments/2` so the user can do + `store.findRecord('comment', 2, { preload: { post: 1 } })` without having to fetch the post. + + Preloaded data can be attributes and relationships passed in either as IDs or as actual + models. + + @method preloadData + @private + @param {Object} preload + */ + preloadData(preload) { + //TODO(Igor) consider the polymorphic case + Object.keys(preload).forEach((key) => { + let preloadValue = get$4(preload, key); + let relationshipMeta = this.modelClass.metaForProperty(key); + if (relationshipMeta.isRelationship) { + this._preloadRelationship(key, preloadValue); + } else { + this._data[key] = preloadValue; + } + }); + } + + _preloadRelationship(key, preloadValue) { + let relationshipMeta = this.modelClass.metaForProperty(key); + let modelClass = relationshipMeta.type; + if (relationshipMeta.kind === 'hasMany') { + this._preloadHasMany(key, preloadValue, modelClass); + } else { + this._preloadBelongsTo(key, preloadValue, modelClass); + } + } + + _preloadHasMany(key, preloadValue, modelClass) { + assert("You need to pass in an array to set a hasMany property on a record", Array.isArray(preloadValue)); + let recordsToSet = new Array(preloadValue.length); + + for (let i = 0; i < preloadValue.length; i++) { + let recordToPush = preloadValue[i]; + recordsToSet[i] = this._convertStringOrNumberIntoInternalModel(recordToPush, modelClass); + } + + //We use the pathway of setting the hasMany as if it came from the adapter + //because the user told us that they know this relationships exists already + this._relationships.get(key).updateInternalModelsFromAdapter(recordsToSet); + } + + _preloadBelongsTo(key, preloadValue, modelClass) { + let internalModelToSet = this._convertStringOrNumberIntoInternalModel(preloadValue, modelClass); + + //We use the pathway of setting the hasMany as if it came from the adapter + //because the user told us that they know this relationships exists already + this._relationships.get(key).setInternalModel(internalModelToSet); + } + + _convertStringOrNumberIntoInternalModel(value, modelClass) { + if (typeof value === 'string' || typeof value === 'number') { + return this.store._internalModelForId(modelClass, value); + } + if (value._internalModel) { + return value._internalModel; + } + return value; + } + + /* + @method updateRecordArrays + @private + */ + updateRecordArrays() { + this.store.recordArrayManager.recordDidChange(this); + } + + setId(id) { + assert('A record\'s id cannot be changed once it is in the loaded state', this.id === null || this.id === id || this.isNew()); + this.id = id; + if (this._record.get('id') !== id) { + this._record.set('id', id); + } + } + + didError(error) { + this.error = error; + this.isError = true; + + if (this.hasRecord) { + this._record.setProperties({ + isError: true, + adapterError: error + }); + } + } + + didCleanError() { + this.error = null; + this.isError = false; + + if (this.hasRecord) { + this._record.setProperties({ + isError: false, + adapterError: null + }); + } + } + + /* + If the adapter did not return a hash in response to a commit, + merge the changed attributes and relationships into the existing + saved data. + + @method adapterDidCommit + */ + adapterDidCommit(data) { + if (data) { + this.store._internalModelDidReceiveRelationshipData(this.modelName, this.id, data.relationships); + + data = data.attributes; + } + + this.didCleanError(); + let changedKeys = this._changedKeys(data); + + assign(this._data, this._inFlightAttributes); + if (data) { + assign(this._data, data); + } + + this._inFlightAttributes = null; + + this.send('didCommit'); + this.updateRecordArrays(); + + if (!data) { return; } + + this._record._notifyProperties(changedKeys); + } + + addErrorMessageToAttribute(attribute, message) { + get$4(this.getRecord(), 'errors')._add(attribute, message); + } + + removeErrorMessageFromAttribute(attribute) { + get$4(this.getRecord(), 'errors')._remove(attribute); + } + + clearErrorMessages() { + get$4(this.getRecord(), 'errors')._clear(); + } + + hasErrors() { + let errors = get$4(this.getRecord(), 'errors'); + + return !isEmpty$1(errors); + } + + // FOR USE DURING COMMIT PROCESS + + /* + @method adapterDidInvalidate + @private + */ + adapterDidInvalidate(errors) { + let attribute; + + for (attribute in errors) { + if (errors.hasOwnProperty(attribute)) { + this.addErrorMessageToAttribute(attribute, errors[attribute]); + } + } + + this.send('becameInvalid'); + + this._saveWasRejected(); + } + + /* + @method adapterDidError + @private + */ + adapterDidError(error) { + this.send('becameError'); + this.didError(error); + this._saveWasRejected(); + } + + _saveWasRejected() { + let keys = Object.keys(this._inFlightAttributes); + if (keys.length > 0) { + let attrs = this._attributes; + for (let i=0; i < keys.length; i++) { + if (attrs[keys[i]] === undefined) { + attrs[keys[i]] = this._inFlightAttributes[keys[i]]; + } + } + } + this._inFlightAttributes = null; + } + + /* + Ember Data has 3 buckets for storing the value of an attribute on an internalModel. + + `_data` holds all of the attributes that have been acknowledged by + a backend via the adapter. When rollbackAttributes is called on a model all + attributes will revert to the record's state in `_data`. + + `_attributes` holds any change the user has made to an attribute + that has not been acknowledged by the adapter. Any values in + `_attributes` are have priority over values in `_data`. + + `_inFlightAttributes`. When a record is being synced with the + backend the values in `_attributes` are copied to + `_inFlightAttributes`. This way if the backend acknowledges the + save but does not return the new state Ember Data can copy the + values from `_inFlightAttributes` to `_data`. Without having to + worry about changes made to `_attributes` while the save was + happenign. + + + Changed keys builds a list of all of the values that may have been + changed by the backend after a successful save. + + It does this by iterating over each key, value pair in the payload + returned from the server after a save. If the `key` is found in + `_attributes` then the user has a local changed to the attribute + that has not been synced with the server and the key is not + included in the list of changed keys. + + + + If the value, for a key differs from the value in what Ember Data + believes to be the truth about the backend state (A merger of the + `_data` and `_inFlightAttributes` objects where + `_inFlightAttributes` has priority) then that means the backend + has updated the value and the key is added to the list of changed + keys. + + @method _changedKeys + @private + */ + _changedKeys(updates) { + let changedKeys = []; + + if (updates) { + let original, i, value, key; + let keys = Object.keys(updates); + let length = keys.length; + let hasAttrs = this.hasChangedAttributes(); + let attrs; + if (hasAttrs) { + attrs= this._attributes; + } + + original = assign(Object.create(null), this._data); + original = assign(original, this._inFlightAttributes); + + for (i = 0; i < length; i++) { + key = keys[i]; + value = updates[key]; + + // A value in _attributes means the user has a local change to + // this attributes. We never override this value when merging + // updates from the backend so we should not sent a change + // notification if the server value differs from the original. + if (hasAttrs === true && attrs[key] !== undefined) { + continue; + } + + if (!isEqual(original[key], value)) { + changedKeys.push(key); + } + } + } + + return changedKeys; + } + + toString() { + return `<${this.modelName}:${this.id}>`; + } + + referenceFor(kind, name) { + let reference = this.references[name]; + + if (!reference) { + let relationship = this._relationships.get(name); + + runInDebug(() => { + let modelName = this.modelName; + assert(`There is no ${kind} relationship named '${name}' on a model of modelClass '${modelName}'`, relationship); + + let actualRelationshipKind = relationship.relationshipMeta.kind; + assert(`You tried to get the '${name}' relationship on a '${modelName}' via record.${kind}('${name}'), but the relationship is of kind '${actualRelationshipKind}'. Use record.${actualRelationshipKind}('${name}') instead.`, actualRelationshipKind === kind); + }); + + if (kind === "belongsTo") { + reference = new BelongsToReference(this.store, this, relationship); + } else if (kind === "hasMany") { + reference = new HasManyReference(this.store, this, relationship); + } + + this.references[name] = reference; + } + + return reference; + } +} + +if (isEnabled('ds-rollback-attribute')) { + /* + Returns the latest truth for an attribute - the canonical value, or the + in-flight value. + + @method lastAcknowledgedValue + @private + */ + InternalModel.prototype.lastAcknowledgedValue = function lastAcknowledgedValue(key) { + if (key in this._inFlightAttributes) { + return this._inFlightAttributes[key]; + } else { + return this._data[key]; + } + }; +} + +/** + `InternalModelMap` is a custom storage map for internalModels of a given modelName + used by `IdentityMap`. + + It was extracted from an implicit pojo based "internalModel map" and preserves + that interface while we work towards a more official API. + + @class InternalModelMap + @private + */ +class InternalModelMap { + constructor(modelName) { + this.modelName = modelName; + this._idToModel = Object.create(null); + this._models = []; + this._metadata = null; + } + + /** + A "map" of records based on their ID for this modelName + */ + get idToRecord() { + deprecate('Use of InternalModelMap.idToRecord is deprecated, use InternalModelMap.get(id) instead.', false, { + id: 'ds.record-map.idToRecord', + until: '2.13' + }); + return this._idToModel; + } + + /** + * + * @param id + * @returns {InternalModel} + */ + get(id) { + let r = this._idToModel[id]; + return r; + } + + has(id) { + return !!this._idToModel[id]; + } + + get length() { + return this._models.length; + } + + set(id, internalModel) { + assert(`You cannot index an internalModel by an empty id'`, id); + assert(`You cannot set an index for an internalModel to something other than an internalModel`, internalModel instanceof InternalModel); + assert(`You cannot set an index for an internalModel that is not in the InternalModelMap`, this.contains(internalModel)); + assert(`You cannot update the id index of an InternalModel once set. Attempted to update ${id}.`, !this.has(id) || this.get(id) === internalModel); + + this._idToModel[id] = internalModel; + } + + add(internalModel, id) { + assert(`You cannot re-add an already present InternalModel to the InternalModelMap.`, !this.contains(internalModel)); + + if (id) { + this._idToModel[id] = internalModel; + } + + this._models.push(internalModel); + } + + remove(internalModel, id) { + if (id) { + delete this._idToModel[id]; + } + + let loc = this._models.indexOf(internalModel); + + if (loc !== -1) { + this._models.splice(loc, 1); + } + } + + contains(internalModel) { + return this._models.indexOf(internalModel) !== -1; + } + + /** + An array of all models of this modelName + */ + get models() { + return this._models; + } + + /** + * meta information about internalModels + */ + get metadata() { + return this._metadata || (this._metadata = Object.create(null)); + } + + /** + deprecated (and unsupported) way of accessing modelClass + + @deprecated + */ + get type() { + throw new Error('InternalModelMap.type is no longer available'); + } + + /** + Destroy all models in the internalModelTest and wipe metadata. + + @method clear + */ + clear() { + if (this._models) { + let models = this._models; + this._models = []; + + for (let i = 0; i < models.length; i++) { + let model = models[i]; + model.unloadRecord(); + } + } + + this._metadata = null; + } + + destroy() { + this._store = null; + this._modelClass = null; + } +} + +/** + `IdentityMap` is a custom storage map for records by modelName + used by `DS.Store`. + + @class IdentityMap + @private + */ +class IdentityMap { + constructor() { + this._map = Object.create(null); + } + + /** + Retrieves the `InternalModelMap` for a given modelName, + creating one if one did not already exist. This is + similar to `getWithDefault` or `get` on a `MapWithDefault` + + @method retrieve + @param modelName a previously normalized modelName + @returns {InternalModelMap} the InternalModelMap for the given modelName + */ + retrieve(modelName) { + let map = this._map[modelName]; + + if (!map) { + map = this._map[modelName] = new InternalModelMap(modelName); + } + + return map; + } + + /** + Clears the contents of all known `RecordMaps`, but does + not remove the InternalModelMap instances. + + @method clear + */ + clear() { + let map = this._map; + let keys = Object.keys(map); + + for (let i = 0; i < keys.length; i++) { + let key = keys[i]; + map[key].clear(); + } + } +} + +/* + This is a helper method that validates a JSON API top-level document + + The format of a document is described here: + http://jsonapi.org/format/#document-top-level + + @method validateDocumentStructure + @param {Object} doc JSON API document + @return {array} An array of errors found in the document structure +*/ +function validateDocumentStructure(doc) { + let errors = []; + if (!doc || typeof doc !== 'object') { + errors.push('Top level of a JSON API document must be an object'); + } else { + if (!('data' in doc) && + !('errors' in doc) && + !('meta' in doc)) { + errors.push('One or more of the following keys must be present: "data", "errors", "meta".'); + } else { + if (('data' in doc) && ('errors' in doc)) { + errors.push('Top level keys "errors" and "data" cannot both be present in a JSON API document'); + } + } + if ('data' in doc) { + if (!(doc.data === null || Array.isArray(doc.data) || typeof doc.data === 'object')) { + errors.push('data must be null, an object, or an array'); + } + } + if ('meta' in doc) { + if (typeof doc.meta !== 'object') { + errors.push('meta must be an object'); + } + } + if ('errors' in doc) { + if (!Array.isArray(doc.errors)) { + errors.push('errors must be an array'); + } + } + if ('links' in doc) { + if (typeof doc.links !== 'object') { + errors.push('links must be an object'); + } + } + if ('jsonapi' in doc) { + if (typeof doc.jsonapi !== 'object') { + errors.push('jsonapi must be an object'); + } + } + if ('included' in doc) { + if (typeof doc.included !== 'object') { + errors.push('included must be an array'); + } + } + } + + return errors; +} + +/* + This is a helper method that always returns a JSON-API Document. + + @method normalizeResponseHelper + @param {DS.Serializer} serializer + @param {DS.Store} store + @param {subclass of DS.Model} modelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document +*/ +function normalizeResponseHelper(serializer, store, modelClass, payload, id, requestType) { + let normalizedResponse = serializer.normalizeResponse(store, modelClass, payload, id, requestType); + let validationErrors = []; + runInDebug(() => { + validationErrors = validateDocumentStructure(normalizedResponse); + }); + assert(`normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join('\n\t* ')}`, Ember.isEmpty(validationErrors)); + + return normalizedResponse; +} + +function serializerForAdapter(store, adapter, modelName) { + let serializer = adapter.serializer; + + if (serializer === undefined) { + serializer = store.serializerFor(modelName); + } + + if (serializer === null || serializer === undefined) { + serializer = { + extract(store, type, payload) { return payload; } + }; + } + + return serializer; +} + +/** + Manages the payloads for both sides of a single relationship, across all model + instances. + + For example, with + + const User = DS.Model.extend({ + hobbies: DS.hasMany('hobby') + }); + + const Hobby = DS.Model.extend({ + user: DS.belongsTo('user') + }); + + let relationshipPayloads = new RelationshipPayloads('user', 'hobbies', 'hobby', 'user'); + + let userPayload = { + data: { + id: 1, + type: 'user', + relationships: { + hobbies: { + data: [{ + id: 2, + type: 'hobby', + }] + } + } + } + }; + + // here we expect the payload of the individual relationship + relationshipPayloads.push('user', 1, 'hobbies', userPayload.data.relationships.hobbies); + + relationshipPayloads.get('user', 1, 'hobbies'); + relationshipPayloads.get('hobby', 2, 'user'); + + @class RelationshipPayloads + @private +*/ +class RelationshipPayloads { + constructor(store, modelName, relationshipName, relationshipMeta, inverseModelName, inverseRelationshipName, inverseRelationshipMeta) { + this._store = store; + + this._lhsModelName = modelName; + this._lhsRelationshipName = relationshipName; + this._lhsRelationshipMeta = relationshipMeta; + + this._rhsModelName = inverseModelName; + this._rhsRelationshipName = inverseRelationshipName; + this._rhsRelationshipMeta = inverseRelationshipMeta; + + // a map of id -> payloads for the left hand side of the relationship. + this._lhsPayloads = Object.create(null); + if (modelName !== inverseModelName || relationshipName !== inverseRelationshipName) { + // The common case of a non-reflexive relationship, or a reflexive + // relationship whose inverse is not itself + this._rhsPayloads = Object.create(null); + this._isReflexive = false; + } else { + // Edge case when we have a reflexive relationship to itself + // eg user hasMany friends inverse friends + // + // In this case there aren't really two sides to the relationship, but + // we set `_rhsPayloads = _lhsPayloads` to make things easier to reason + // about + this._rhsPayloads = this._lhsPayloads; + this._isReflexive = true; + } + + // When we push relationship payloads, just stash them in a queue until + // somebody actually asks for one of them. + // + // This is a queue of the relationship payloads that have been pushed for + // either side of this relationship + this._pendingPayloads = []; + } + + /** + Get the payload for the relationship of an individual record. + + This might return the raw payload as pushed into the store, or one computed + from the payload of the inverse relationship. + + @method + */ + get(modelName, id, relationshipName) { + this._flushPending(); + + if (this._isLHS(modelName, relationshipName)) { + return this._lhsPayloads[id]; + } else { + assert(`${modelName}:${relationshipName} is not either side of this relationship, ${this._lhsModelName}:${this._lhsRelationshipName}<->${this._rhsModelName}:${this._rhsRelationshipName}`, this._isRHS(modelName, relationshipName)); + return this._rhsPayloads[id]; + } + } + + /** + Push a relationship payload for an individual record. + + This will make the payload available later for both this relationship and its inverse. + + @method + */ + push(modelName, id, relationshipName, relationshipData) { + this._pendingPayloads.push([modelName, id, relationshipName, relationshipData]); + } + + /** + Unload the relationship payload for an individual record. + + This does not unload the inverse relationship payload. + + @method + */ + unload(modelName, id, relationshipName) { + this._flushPending(); + + if (this._isLHS(modelName, relationshipName)) { + delete this._lhsPayloads[id]; + } else { + assert(`${modelName}:${relationshipName} is not either side of this relationship, ${this._lhsModelName}:${this._lhsRelationshipName}<->${this._rhsModelName}:${this._rhsRelationshipName}`, this._isRHS(modelName, relationshipName)); + delete this._rhsPayloads[id]; + } + } + + /** + @return {boolean} true iff `modelName` and `relationshipName` refer to the + left hand side of this relationship, as opposed to the right hand side. + + @method + */ + _isLHS(modelName, relationshipName) { + return modelName === this._lhsModelName && relationshipName === this._lhsRelationshipName; + } + + /** + @return {boolean} true iff `modelName` and `relationshipName` refer to the + right hand side of this relationship, as opposed to the left hand side. + + @method + */ + _isRHS(modelName, relationshipName) { + return modelName === this._rhsModelName && relationshipName === this._rhsRelationshipName; + } + + _flushPending() { + if (this._pendingPayloads.length === 0) { return; } + + let payloadsToBeProcessed = this._pendingPayloads.splice(0, this._pendingPayloads.length); + for (let i=0; i${this._rhsModelName}:${this._rhsRelationshipName}`, this._isRHS(modelName, relationshipName)); + previousPayload = this._rhsPayloads[id]; + idToPayloads = this._rhsPayloads; + inverseIdToPayloads = this._lhsPayloads; + inverseIsMany = this._lhsRelationshipIsMany; + } + + // actually flush this individual payload + // + // We remove the previous inverse before populating our current one + // because we may have multiple payloads for the same relationship, in + // which case the last one wins. + // + // eg if user hasMany helicopters, and helicopter belongsTo user and we see + // + // [{ + // data: { + // id: 1, + // type: 'helicopter', + // relationships: { + // user: { + // id: 2, + // type: 'user' + // } + // } + // } + // }, { + // data: { + // id: 1, + // type: 'helicopter', + // relationships: { + // user: { + // id: 4, + // type: 'user' + // } + // } + // } + // }] + // + // Then we will initially have set user:2 as having helicopter:1, which we + // need to remove before adding helicopter:1 to user:4 + // + this._removeInverse(id, previousPayload, inverseIdToPayloads); + idToPayloads[id] = relationshipData; + this._populateInverse(relationshipData, inverseRelationshipData, inverseIdToPayloads, inverseIsMany); + } + } + + /** + Populate the inverse relationship for `relationshipData`. + + If `relationshipData` is an array (eg because the relationship is hasMany) + this means populate each inverse, otherwise populate only the single + inverse. + + @private + @method + */ + _populateInverse(relationshipData, inversePayload, inverseIdToPayloads, inverseIsMany) { + if (!relationshipData.data) { + // This id doesn't have an inverse, eg a belongsTo with a payload + // { data: null }, so there's nothing to populate + return; + } + + if (Array.isArray(relationshipData.data)) { + for (let i=0; i.friends = [{ id: 1, type: 'user' }] + return; + } + + let existingPayload = inverseIdToPayloads[inverseId]; + let existingData = existingPayload && existingPayload.data; + + if (existingData) { + // There already is an inverse, either add or overwrite depehnding on + // whether the inverse is a many relationship or not + // + if (Array.isArray(existingData)) { + existingData.push(inversePayload.data); + } else { + inverseIdToPayloads[inverseId] = inversePayload; + } + } else { + // first time we're populating the inverse side + // + if (inverseIsMany) { + inverseIdToPayloads[inverseId] = { + data: [inversePayload.data] + }; + } else { + inverseIdToPayloads[inverseId] = inversePayload; + } + } + } + + get _lhsRelationshipIsMany() { + return this._lhsRelationshipMeta && this._lhsRelationshipMeta.kind === 'hasMany'; + } + + get _rhsRelationshipIsMany() { + return this._rhsRelationshipMeta && this._rhsRelationshipMeta.kind === 'hasMany'; + } + + /** + Remove the relationship in `previousPayload` from its inverse(s), because + this relationship payload has just been updated (eg because the same + relationship had multiple payloads pushed before the relationship was + initialized). + + @method + */ + _removeInverse(id, previousPayload, inverseIdToPayloads) { + let data = previousPayload && previousPayload.data; + if (!data) { + // either this is the first time we've seen a payload for this id, or its + // previous payload indicated that it had no inverse, eg a belongsTo + // relationship with payload { data: null } + // + // In either case there's nothing that needs to be removed from the + // inverse map of payloads + return; + } + + if (Array.isArray(data)) { + // TODO: diff rather than removeall addall? + for (let i=0; i x.id !== id); + } else { + inversePayloads[inverseId] = { + data: null + }; + } + } +} + +const get$11 = Ember.get; + +/** + Manages relationship payloads for a given store, for uninitialized + relationships. Acts as a single source of truth (of payloads) for both sides + of an uninitialized relationship so they can agree on the most up-to-date + payload received without needing too much eager processing when those payloads + are pushed into the store. + + This minimizes the work spent on relationships that are never initialized. + + Once relationships are initialized, their state is managed in a relationship + state object (eg BelongsToRelationship or ManyRelationship). + + + @example + + let relationshipPayloadsManager = new RelationshipPayloadsManager(store); + + const User = DS.Model.extend({ + hobbies: DS.hasMany('hobby') + }); + + const Hobby = DS.Model.extend({ + user: DS.belongsTo('user') + }); + + let userPayload = { + data: { + id: 1, + type: 'user', + relationships: { + hobbies: { + data: [{ + id: 2, + type: 'hobby' + }] + } + } + }, + }; + relationshipPayloadsManager.push('user', 1, userPayload.data.relationships); + + relationshipPayloadsManager.get('hobby', 2, 'user') === { + { + data: { + id: 1, + type: 'user' + } + } + } + + @private + @class RelationshipPayloadsManager +*/ +class RelationshipPayloadsManager { + constructor(store) { + this._store = store; + // cache of `RelationshipPayload`s + this._cache = Object.create(null); + } + + /** + Find the payload for the given relationship of the given model. + + Returns the payload for the given relationship, whether raw or computed from + the payload of the inverse relationship. + + @example + + relationshipPayloadsManager.get('hobby', 2, 'user') === { + { + data: { + id: 1, + type: 'user' + } + } + } + + @method + */ + get(modelName, id, relationshipName) { + let modelClass = this._store._modelFor(modelName); + let relationshipsByName = get$11(modelClass, 'relationshipsByName'); + let relationshipPayloads = this._getRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName, false); + return relationshipPayloads && relationshipPayloads.get(modelName, id, relationshipName); + } + + /** + Push a model's relationships payload into this cache. + + @example + + let userPayload = { + data: { + id: 1, + type: 'user', + relationships: { + hobbies: { + data: [{ + id: 2, + type: 'hobby' + }] + } + } + }, + }; + relationshipPayloadsManager.push('user', 1, userPayload.data.relationships); + + @method + */ + push(modelName, id, relationshipsData) { + if (!relationshipsData) { return; } + + let modelClass = this._store._modelFor(modelName); + let relationshipsByName = get$11(modelClass, 'relationshipsByName'); + Object.keys(relationshipsData).forEach(key => { + let relationshipPayloads = this._getRelationshipPayloads(modelName, key, modelClass, relationshipsByName, true); + if (relationshipPayloads) { + relationshipPayloads.push(modelName, id, key, relationshipsData[key]); + } + }); + } + + /** + Unload a model's relationships payload. + + @method + */ + unload(modelName, id) { + let modelClass = this._store._modelFor(modelName); + let relationshipsByName = get$11(modelClass, 'relationshipsByName'); + relationshipsByName.forEach((_, relationshipName) => { + let relationshipPayloads = this._getRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName, false); + if (relationshipPayloads) { + relationshipPayloads.unload(modelName, id, relationshipName); + } + }); + } + + /** + Find the RelationshipPayloads object for the given relationship. The same + RelationshipPayloads object is returned for either side of a relationship. + + @example + + const User = DS.Model.extend({ + hobbies: DS.hasMany('hobby') + }); + + const Hobby = DS.Model.extend({ + user: DS.belongsTo('user') + }); + + relationshipPayloads.get('user', 'hobbies') === relationshipPayloads.get('hobby', 'user'); + + The signature has a somewhat large arity to avoid extra work, such as + a) string maipulation & allocation with `modelName` and + `relationshipName` + b) repeatedly getting `relationshipsByName` via `Ember.get` + + + @private + @method + */ + _getRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName, init) { + if (!relationshipsByName.has(relationshipName)) { return; } + + let key = `${modelName}:${relationshipName}`; + if (!this._cache[key] && init) { + return this._initializeRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName); + } + + return this._cache[key]; + } + + /** + Create the `RelationshipsPayload` for the relationship `modelName`, `relationshipName`, and its inverse. + + @private + @method + */ + _initializeRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName) { + let relationshipMeta = relationshipsByName.get(relationshipName); + let inverseMeta = modelClass.inverseFor(relationshipName, this._store); + + let inverseModelName; + let inverseRelationshipName; + let inverseRelationshipMeta; + + // figure out the inverse relationship; we need two things + // a) the inverse model name + //- b) the name of the inverse relationship + if (inverseMeta) { + inverseRelationshipName = inverseMeta.name; + inverseModelName = relationshipMeta.type; + inverseRelationshipMeta = get$11(inverseMeta.type, 'relationshipsByName').get(inverseRelationshipName); + } else { + // relationship has no inverse + inverseModelName = inverseRelationshipName = ''; + inverseRelationshipMeta = null; + } + + let lhsKey = `${modelName}:${relationshipName}`; + let rhsKey = `${inverseModelName}:${inverseRelationshipName}`; + + // populate the cache for both sides of the relationship, as they both use + // the same `RelationshipPayloads`. + // + // This works out better than creating a single common key, because to + // compute that key we would need to do work to look up the inverse + // + return this._cache[lhsKey] = + this._cache[rhsKey] = + new RelationshipPayloads( + this._store, + modelName, + relationshipName, + relationshipMeta, + inverseModelName, + inverseRelationshipName, + inverseRelationshipMeta + ); + } +} + +const { Promise: Promise$3 } = Ember.RSVP; + +function payloadIsNotBlank(adapterPayload) { + if (Array.isArray(adapterPayload)) { + return true; + } else { + return Object.keys(adapterPayload || {}).length; + } +} + +function _find(adapter, store, modelClass, id, internalModel, options) { + let snapshot = internalModel.createSnapshot(options); + let { modelName } = internalModel; + let promise = adapter.findRecord(store, modelClass, id, snapshot); + let label = `DS: Handle Adapter#findRecord of '${modelName}' with id: '${id}'`; + + promise = Promise$3.resolve(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + + return promise.then(adapterPayload => { + assert(`You made a 'findRecord' request for a '${modelName}' with id '${id}', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, id, 'findRecord'); + assert(`Ember Data expected the primary data returned from a 'findRecord' response to be an object but instead it found an array.`, !Array.isArray(payload.data)); + + warn(`You requested a record of type '${modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead http://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, payload.data.id === id, { + id: 'ds.store.findRecord.id-mismatch' + }); + + return store._push(payload); + }, error => { + internalModel.notFound(); + if (internalModel.isEmpty()) { + internalModel.unloadRecord(); + } + + throw error; + }, `DS: Extract payload of '${modelName}'`); +} + +function _findMany(adapter, store, modelName, ids, internalModels) { + let snapshots = Ember.A(internalModels).invoke('createSnapshot'); + let modelClass = store.modelFor(modelName); // `adapter.findMany` gets the modelClass still + let promise = adapter.findMany(store, modelClass, ids, snapshots); + let label = `DS: Handle Adapter#findMany of '${modelName}'`; + + if (promise === undefined) { + throw new Error('adapter.findMany returned undefined, this was very likely a mistake'); + } + + promise = Promise$3.resolve(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + + return promise.then(adapterPayload => { + assert(`You made a 'findMany' request for '${modelName}' records with ids '[${ids}]', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findMany'); + return store._push(payload); + }, null, `DS: Extract payload of ${modelName}`); +} + +function _findHasMany(adapter, store, internalModel, link, relationship) { + let snapshot = internalModel.createSnapshot(); + let modelClass = store.modelFor(relationship.type); + let promise = adapter.findHasMany(store, snapshot, link, relationship); + let label = `DS: Handle Adapter#findHasMany of '${internalModel.modelName}' : '${relationship.type}'`; + + promise = Promise$3.resolve(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + promise = _guard(promise, _bind(_objectIsAlive, internalModel)); + + return promise.then(adapterPayload => { + assert(`You made a 'findHasMany' request for a ${internalModel.modelName}'s '${relationship.key}' relationship, using link '${link}' , but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); + let serializer = serializerForAdapter(store, adapter, relationship.type); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findHasMany'); + let internalModelArray = store._push(payload); + + internalModelArray.meta = payload.meta; + return internalModelArray; + }, null, `DS: Extract payload of '${internalModel.modelName}' : hasMany '${relationship.type}'`); +} + +function _findBelongsTo(adapter, store, internalModel, link, relationship) { + let snapshot = internalModel.createSnapshot(); + let modelClass = store.modelFor(relationship.type); + let promise = adapter.findBelongsTo(store, snapshot, link, relationship); + let label = `DS: Handle Adapter#findBelongsTo of ${internalModel.modelName} : ${relationship.type}`; + + promise = Promise$3.resolve(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + promise = _guard(promise, _bind(_objectIsAlive, internalModel)); + + return promise.then(adapterPayload => { + let serializer = serializerForAdapter(store, adapter, relationship.type); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findBelongsTo'); + + if (!payload.data) { + return null; + } + + return store._push(payload); + }, null, `DS: Extract payload of ${internalModel.modelName} : ${relationship.type}`); +} + +function _findAll(adapter, store, modelName, sinceToken, options) { + let modelClass = store.modelFor(modelName); // adapter.findAll depends on the class + let recordArray = store.peekAll(modelName); + let snapshotArray = recordArray._createSnapshot(options); + let promise = adapter.findAll(store, modelClass, sinceToken, snapshotArray); + let label = "DS: Handle Adapter#findAll of " + modelClass; + + promise = Promise$3.resolve(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + + return promise.then(adapterPayload => { + assert(`You made a 'findAll' request for '${modelName}' records, but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findAll'); + + store._push(payload); + store._didUpdateAll(modelName); + + return recordArray; + }, null, 'DS: Extract payload of findAll ${modelName}'); +} + +function _query(adapter, store, modelName, query, recordArray) { + let modelClass = store.modelFor(modelName); // adapter.query needs the class + let promise = adapter.query(store, modelClass, query, recordArray); + + let label = `DS: Handle Adapter#query of ${modelClass}`; + + promise = Promise$3.resolve(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + + return promise.then(adapterPayload => { + let serializerToken = heimdall.start('initial-serializerFor-lookup'); + let serializer = serializerForAdapter(store, adapter, modelName); + heimdall.stop(serializerToken); + let normalizeToken = heimdall.start('finders#_query::normalizeResponseHelper'); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'query'); + heimdall.stop(normalizeToken); + let internalModels = store._push(payload); + + assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Array.isArray(internalModels)); + recordArray._setInternalModels(internalModels, payload); + + return recordArray; + }, null, `DS: Extract payload of query ${modelName}`); +} + +function _queryRecord(adapter, store, modelName, query) { + let modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class + let promise = adapter.queryRecord(store, modelClass, query); + let label = `DS: Handle Adapter#queryRecord of ${modelName}`; + + promise = Promise$3.resolve(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + + return promise.then(adapterPayload => { + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'queryRecord'); + + assert(`Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array.`, !Array.isArray(payload.data), { + id: 'ds.store.queryRecord-array-response' + }); + + return store._push(payload); + }, null, `DS: Extract payload of queryRecord ${modelName}`); +} + +// Used by the store to normalize IDs entering the store. Despite the fact +// that developers may provide IDs as numbers (e.g., `store.findRecord('person', 1)`), +// it is important that internally we use strings, since IDs may be serialized +// and lose type information. For example, Ember's router may put a record's +// ID into the URL, and if we later try to deserialize that URL and find the +// corresponding record, we will not know if it is a string or a number. +function coerceId(id) { + return id === null || id === undefined || id === '' ? null : id+''; +} + +/** + @module ember-data +*/ + +/** + @class SnapshotRecordArray + @namespace DS + @private + @constructor + @param {Array} snapshots An array of snapshots + @param {Object} meta +*/ +class SnapshotRecordArray { + constructor(recordArray, meta, options = {}) { + /** + An array of snapshots + @private + @property _snapshots + @type {Array} + */ + this._snapshots = null; + + /** + An array of records + @private + @property _recordArray + @type {Array} + */ + this._recordArray = recordArray; + + /** + Number of records in the array + + Example + + ```app/adapters/post.js + import DS from 'ember-data' + + export default DS.JSONAPIAdapter.extend({ + shouldReloadAll(store, snapshotRecordArray) { + return !snapshotRecordArray.length; + }, + }); + ``` + + @property length + @type {Number} + */ + this.length = recordArray.get('length'); + + this._type = null; + + /** + Meta objects for the record array. + + Example + + ```app/adapters/post.js + import DS from 'ember-data' + + export default DS.JSONAPIAdapter.extend({ + shouldReloadAll(store, snapshotRecordArray) { + var lastRequestTime = snapshotRecordArray.meta.lastRequestTime; + var twentyMinutes = 20 * 60 * 1000; + return Date.now() > lastRequestTime + twentyMinutes; + }, + }); + ``` + + @property meta + @type {Object} + */ + this.meta = meta; + + /** + A hash of adapter options passed into the store method for this request. + + Example + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + findAll(store, type, sinceToken, snapshotRecordArray) { + if (snapshotRecordArray.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + + @property adapterOptions + @type {Object} + */ + this.adapterOptions = options.adapterOptions; + + /** + The relationships to include for this request. + + Example + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + findAll(store, type, snapshotRecordArray) { + var url = `/${type.modelName}?include=${encodeURIComponent(snapshotRecordArray.include)}`; + + return fetch(url).then((response) => response.json()) + } + }); + + @property include + @type {String|Array} + */ + this.include = options.include; + } + + /** + The type of the underlying records for the snapshots in the array, as a DS.Model + @property type + @type {DS.Model} + */ + get type() { + return this._type || (this._type = this._recordArray.get('type')); + } + + /** + Get snapshots of the underlying record array + + Example + + ```app/adapters/post.js + import DS from 'ember-data' + + export default DS.JSONAPIAdapter.extend({ + shouldReloadAll(store, snapshotArray) { + var snapshots = snapshotArray.snapshots(); + + return snapshots.any(function(ticketSnapshot) { + var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt'), 'minutes'); + if (timeDiff > 20) { + return true; + } else { + return false; + } + }); + } + }); + ``` + + @method snapshots + @return {Array} Array of snapshots + */ + snapshots() { + if (this._snapshots !== null) { + return this._snapshots; + } + + this._snapshots = this._recordArray._takeSnapshot(); + + return this._snapshots; + } +} + +/** + @module ember-data +*/ + +const { computed: computed$2, get: get$13, set: set$3, RSVP: { Promise: Promise$4 } } = Ember; + +/** + A record array is an array that contains records of a certain modelName. The record + array materializes records as needed when they are retrieved for the first + time. You should not create record arrays yourself. Instead, an instance of + `DS.RecordArray` or its subclasses will be returned by your application's store + in response to queries. + + @class RecordArray + @namespace DS + @extends Ember.ArrayProxy + @uses Ember.Evented +*/ + +var RecordArray = Ember.ArrayProxy.extend(Ember.Evented, { + init() { + this._super(...arguments); + + /** + The array of client ids backing the record array. When a + record is requested from the record array, the record + for the client id at the same index is materialized, if + necessary, by the store. + + @property content + @private + @type Ember.Array + */ + this.set('content', this.content || null); + + /** + The flag to signal a `RecordArray` is finished loading data. + + Example + + ```javascript + var people = store.peekAll('person'); + people.get('isLoaded'); // true + ``` + + @property isLoaded + @type Boolean + */ + this.isLoaded = this.isLoaded || false; + /** + The flag to signal a `RecordArray` is currently loading data. + + Example + + ```javascript + var people = store.peekAll('person'); + people.get('isUpdating'); // false + people.update(); + people.get('isUpdating'); // true + ``` + + @property isUpdating + @type Boolean + */ + this.isUpdating = false; + + /** + The store that created this record array. + + @property store + @private + @type DS.Store + */ + this.store = this.store || null; + this._updatingPromise = null; + }, + + replace() { + throw new Error(`The result of a server query (for all ${this.modelName} types) is immutable. To modify contents, use toArray()`); + }, + + /** + The modelClass represented by this record array. + + @property type + @type DS.Model + */ + type: computed$2('modelName', function() { + if (!this.modelName) { + return null; + } + return this.store._modelFor(this.modelName); + }).readOnly(), + + /** + Retrieves an object from the content by index. + + @method objectAtContent + @private + @param {Number} index + @return {DS.Model} record + */ + objectAtContent(index) { + let internalModel = get$13(this, 'content').objectAt(index); + return internalModel && internalModel.getRecord(); + }, + + /** + Used to get the latest version of all of the records in this array + from the adapter. + + Example + + ```javascript + var people = store.peekAll('person'); + people.get('isUpdating'); // false + + people.update().then(function() { + people.get('isUpdating'); // false + }); + + people.get('isUpdating'); // true + ``` + + @method update + */ + update() { + if (get$13(this, 'isUpdating')) { return this._updatingPromise; } + + this.set('isUpdating', true); + + let updatingPromise = this._update().finally(() => { + this._updatingPromise = null; + if (this.get('isDestroying') || this.get('isDestroyed')) { return } + this.set('isUpdating', false); + }); + + this._updatingPromise = updatingPromise; + + return updatingPromise; + }, + + /* + Update this RecordArray and return a promise which resolves once the update + is finished. + */ + _update() { + return this.store.findAll(this.modelName, { reload: true }); + }, + + /** + Adds an internal model to the `RecordArray` without duplicates + + @method _pushInternalModels + @private + @param {InternalModel} internalModel + */ + _pushInternalModels(internalModels) { + // pushObjects because the internalModels._recordArrays set was already + // consulted for inclusion, so addObject and its on .contains call is not + // required. + get$13(this, 'content').pushObjects(internalModels); + }, + + /** + Removes an internalModel to the `RecordArray`. + + @method removeInternalModel + @private + @param {InternalModel} internalModel + */ + _removeInternalModels(internalModels) { + get$13(this, 'content').removeObjects(internalModels); + }, + + /** + Saves all of the records in the `RecordArray`. + + Example + + ```javascript + var messages = store.peekAll('message'); + messages.forEach(function(message) { + message.set('hasBeenSeen', true); + }); + messages.save(); + ``` + + @method save + @return {DS.PromiseArray} promise + */ + save() { + let promiseLabel = `DS: RecordArray#save ${this.modelName}`; + let promise = Promise$4.all(this.invoke('save'), promiseLabel) + .then(() => this, null, 'DS: RecordArray#save return RecordArray'); + + return PromiseArray.create({ promise }); + }, + + _dissociateFromOwnRecords() { + this.get('content').forEach(internalModel => { + let recordArrays = internalModel.__recordArrays; + + if (recordArrays) { + recordArrays.delete(this); + } + }); + }, + + /** + @method _unregisterFromManager + @private + */ + _unregisterFromManager() { + this.manager.unregisterRecordArray(this); + }, + + willDestroy() { + this._unregisterFromManager(); + this._dissociateFromOwnRecords(); + // TODO: we should not do work during destroy: + // * when objects are destroyed, they should simply be left to do + // * if logic errors do to this, that logic needs to be more careful during + // teardown (ember provides isDestroying/isDestroyed) for this reason + // * the exception being: if an dominator has a reference to this object, + // and must be informed to release e.g. e.g. removing itself from th + // recordArrayMananger + set$3(this, 'content', null); + set$3(this, 'length', 0); + this._super(...arguments); + }, + + /* + @method _createSnapshot + @private + */ + _createSnapshot(options) { + // this is private for users, but public for ember-data internals + return new SnapshotRecordArray(this, this.get('meta'), options); + }, + + /* + @method _takeSnapshot + @private + */ + _takeSnapshot() { + return get$13(this, 'content').map(internalModel => internalModel.createSnapshot()); + } +}); + +/** + @module ember-data +*/ + +const { get: get$14 } = Ember; + +/** + Represents a list of records whose membership is determined by the + store. As records are created, loaded, or modified, the store + evaluates them to determine if they should be part of the record + array. + + @class FilteredRecordArray + @namespace DS + @extends DS.RecordArray +*/ +var FilteredRecordArray = RecordArray.extend({ + init() { + this._super(...arguments); + + this.set('filterFunction', this.get('filterFunction') || null); + this.isLoaded = true; + }, + /** + The filterFunction is a function used to test records from the store to + determine if they should be part of the record array. + + Example + + ```javascript + var allPeople = store.peekAll('person'); + allPeople.mapBy('name'); // ["Tom Dale", "Yehuda Katz", "Trek Glowacki"] + + var people = store.filter('person', function(person) { + if (person.get('name').match(/Katz$/)) { return true; } + }); + people.mapBy('name'); // ["Yehuda Katz"] + + var notKatzFilter = function(person) { + return !person.get('name').match(/Katz$/); + }; + people.set('filterFunction', notKatzFilter); + people.mapBy('name'); // ["Tom Dale", "Trek Glowacki"] + ``` + + @method filterFunction + @param {DS.Model} record + @return {Boolean} `true` if the record should be in the array + */ + + replace() { + throw new Error(`The result of a client-side filter (on ${this.modelName}) is immutable.`); + }, + + /** + @method updateFilter + @private + */ + _updateFilter() { + if (get$14(this, 'isDestroying') || get$14(this, 'isDestroyed')) { + return; + } + get$14(this, 'manager').updateFilter(this, this.modelName, get$14(this, 'filterFunction')); + }, + + updateFilter: Ember.observer('filterFunction', function() { + Ember.run.once(this, this._updateFilter); + }) +}); + +function cloneNull(source) { + let clone = Object.create(null); + for (let key in source) { + clone[key] = source[key]; + } + return clone; +} + +/** + @module ember-data +*/ + +const { get: get$15 } = Ember; + +/** + Represents an ordered list of records whose order and membership is + determined by the adapter. For example, a query sent to the adapter + may trigger a search on the server, whose results would be loaded + into an instance of the `AdapterPopulatedRecordArray`. + + --- + + If you want to update the array and get the latest records from the + adapter, you can invoke [`update()`](#method_update): + + Example + + ```javascript + // GET /users?isAdmin=true + var admins = store.query('user', { isAdmin: true }); + + admins.then(function() { + console.log(admins.get("length")); // 42 + }); + + // somewhere later in the app code, when new admins have been created + // in the meantime + // + // GET /users?isAdmin=true + admins.update().then(function() { + admins.get('isUpdating'); // false + console.log(admins.get("length")); // 123 + }); + + admins.get('isUpdating'); // true + ``` + + @class AdapterPopulatedRecordArray + @namespace DS + @extends DS.RecordArray +*/ +var AdapterPopulatedRecordArray = RecordArray.extend({ + init() { + // yes we are touching `this` before super, but ArrayProxy has a bug that requires this. + this.set('content', this.get('content') || Ember.A()); + + this._super(...arguments); + this.query = this.query || null; + this.links = null; + }, + + replace() { + throw new Error(`The result of a server query (on ${this.modelName}) is immutable.`); + }, + + _update() { + let store = get$15(this, 'store'); + let query = get$15(this, 'query'); + + return store._query(this.modelName, query, this); + }, + + /** + @method _setInternalModels + @param {Array} internalModels + @param {Object} payload normalized payload + @private + */ + _setInternalModels(internalModels, payload) { + let token = heimdall.start('AdapterPopulatedRecordArray._setInternalModels'); + + // TODO: initial load should not cause change events at all, only + // subsequent. This requires changing the public api of adapter.query, but + // hopefully we can do that soon. + this.get('content').setObjects(internalModels); + + this.setProperties({ + isLoaded: true, + isUpdating: false, + meta: cloneNull(payload.meta), + links: cloneNull(payload.links) + }); + + for (let i = 0, l = internalModels.length; i < l; i++) { + let internalModel = internalModels[i]; + + internalModel._recordArrays.add(this); + } + + // TODO: should triggering didLoad event be the last action of the runLoop? + Ember.run.once(this, 'trigger', 'didLoad'); + heimdall.stop(token); + } +}); + +/** + @module ember-data +*/ + +/** + @module ember-data +*/ + +const { + get: get$12, + run: emberRun$1 +} = Ember; + +const { + _flush, + array_flatten, + array_remove, + create, + createAdapterPopulatedRecordArray, + createFilteredRecordArray, + createRecordArray, + liveRecordArrayFor, + filteredRecordArraysFor, + populateLiveRecordArray, + recordDidChange, + registerFilteredRecordArray, + unregisterRecordArray, + updateFilter, + updateFilterRecordArray +} = heimdall.registerMonitor('recordArrayManager', + '_flush', + 'array_fatten', + 'array_remove', + 'create', + 'createAdapterPopulatedRecordArray', + 'createFilteredRecordArray', + 'createRecordArray', + 'liveRecordArrayFor', + 'filteredRecordArraysFor', + 'populateLiveRecordArray', + 'recordDidChange', + 'registerFilteredRecordArray', + 'unregisterRecordArray', + 'updateFilter', + 'updateFilterRecordArray' +); + +/** + @class RecordArrayManager + @namespace DS + @private +*/ +class RecordArrayManager { + constructor(options) { + heimdall.increment(create); + this.store = options.store; + this.isDestroying = false; + this.isDestroyed = false; + this._filteredRecordArrays = Object.create(null); + this._liveRecordArrays = Object.create(null); + this._pending = Object.create(null); + this._adapterPopulatedRecordArrays = []; + } + + recordDidChange(internalModel) { + // TODO: change name + // TODO: track that it was also a change + this.internalModelDidChange(internalModel); + } + + recordWasLoaded(internalModel) { + // TODO: change name + // TODO: track that it was also that it was first loaded + this.internalModelDidChange(internalModel); + } + + internalModelDidChange(internalModel) { + heimdall.increment(recordDidChange); + + let modelName = internalModel.modelName; + + if (internalModel._pendingRecordArrayManagerFlush) { + return; + } + + internalModel._pendingRecordArrayManagerFlush = true; + + let pending = this._pending; + let models = pending[modelName] = pending[modelName] || []; + if (models.push(internalModel) !== 1) { + return; + } + + emberRun$1.schedule('actions', this, this._flush); + } + + _flush() { + heimdall.increment(_flush); + + let pending = this._pending; + this._pending = Object.create(null); + let modelsToRemove = []; + + for (let modelName in pending) { + let internalModels = pending[modelName]; + for (let j = 0; j < internalModels.length; j++) { + let internalModel = internalModels[j]; + // mark internalModels, so they can once again be processed by the + // recordArrayManager + internalModel._pendingRecordArrayManagerFlush = false; + // build up a set of models to ensure we have purged correctly; + if (internalModel.isHiddenFromRecordArrays()) { + modelsToRemove.push(internalModel); + } + } + + // process filteredRecordArrays + if (this._filteredRecordArrays[modelName]) { + let recordArrays = this.filteredRecordArraysFor(modelName); + for (let i = 0; i < recordArrays.length; i++) { + this.updateFilterRecordArray(recordArrays[i], modelName, internalModels); + } + } + + // TODO: skip if it only changed + // process liveRecordArrays + if (this._liveRecordArrays[modelName]) { + this.updateLiveRecordArray(modelName, internalModels); + } + + // process adapterPopulatedRecordArrays + if (modelsToRemove.length > 0) { + this.removeFromAdapterPopulatedRecordArrays(modelsToRemove); + } + } + } + + updateLiveRecordArray(modelName, internalModels) { + let array = this.liveRecordArrayFor(modelName); + + let modelsToAdd = []; + let modelsToRemove = []; + + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; + let isDeleted = internalModel.isHiddenFromRecordArrays(); + let recordArrays = internalModel._recordArrays; + + if (!isDeleted && !internalModel.isEmpty()) { + if (!recordArrays.has(array)) { + modelsToAdd.push(internalModel); + recordArrays.add(array); + } + } + + if (isDeleted) { + modelsToRemove.push(internalModel); + recordArrays.delete(array); + } + } + + if (modelsToAdd.length > 0) { array._pushInternalModels(modelsToAdd); } + if (modelsToRemove.length > 0) { array._removeInternalModels(modelsToRemove); } + } + + removeFromAdapterPopulatedRecordArrays(internalModels) { + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; + let list = internalModel._recordArrays.list; + + for (let j = 0; j < list.length; j++) { + // TODO: group by arrays, so we can batch remove + list[j]._removeInternalModels([internalModel]); + } + + internalModel._recordArrays.clear(); + } + } + + /** + Update an individual filter. + + @private + @method updateFilterRecordArray + @param {DS.FilteredRecordArray} array + @param {String} modelName + @param {Array} internalModels + */ + updateFilterRecordArray(array, modelName, internalModels) { + heimdall.increment(updateFilterRecordArray); + + let filter = get$12(array, 'filterFunction'); + + let shouldBeInAdded = []; + let shouldBeRemoved = []; + + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; + if (internalModel.isHiddenFromRecordArrays() === false && + filter(internalModel.getRecord())) { + if (internalModel._recordArrays.has(array)) { continue; } + shouldBeInAdded.push(internalModel); + internalModel._recordArrays.add(array); + } else { + if (internalModel._recordArrays.delete(array)) { + shouldBeRemoved.push(internalModel); + } + } + } + + if (shouldBeInAdded.length > 0) { array._pushInternalModels(shouldBeInAdded); } + if (shouldBeRemoved.length > 0) { array._removeInternalModels(shouldBeRemoved); } + } + + // TODO: remove, utilize existing flush code but make it flush sync based on 1 modelName + syncLiveRecordArray(array, modelName) { + assert(`recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); + let hasNoPotentialDeletions = Object.keys(this._pending).length === 0; + let map = this.store._internalModelsFor(modelName); + let hasNoInsertionsOrRemovals = get$12(map, 'length') === get$12(array, 'length'); + + /* + Ideally the recordArrayManager has knowledge of the changes to be applied to + liveRecordArrays, and is capable of strategically flushing those changes and applying + small diffs if desired. However, until we've refactored recordArrayManager, this dirty + check prevents us from unnecessarily wiping out live record arrays returned by peekAll. + */ + if (hasNoPotentialDeletions && hasNoInsertionsOrRemovals) { + return; + } + + this.populateLiveRecordArray(array, map.models); + } + + // TODO: remove, when syncLiveRecordArray is removed + populateLiveRecordArray(array, internalModels) { + heimdall.increment(populateLiveRecordArray); + + let modelsToAdd = []; + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; + + if (!internalModel.isHiddenFromRecordArrays()) { + let recordArrays = internalModel._recordArrays; + + if (!recordArrays.has(array)) { + modelsToAdd.push(internalModel); + recordArrays.add(array); + } + } + } + + array._pushInternalModels(modelsToAdd); + } + + /** + This method is invoked if the `filterFunction` property is + changed on a `DS.FilteredRecordArray`. + + It essentially re-runs the filter from scratch. This same + method is invoked when the filter is created in th first place. + + @method updateFilter + @param {Array} array + @param {String} modelName + @param {Function} filter + */ + updateFilter(array, modelName, filter) { + assert(`recordArrayManger.updateFilter expects modelName not modelClass as the second param, received ${modelName}`, typeof modelName === 'string'); + heimdall.increment(updateFilter); + let modelMap = this.store._internalModelsFor(modelName); + let internalModels = modelMap.models; + + this.updateFilterRecordArray(array, filter, internalModels); + } + + /** + Get the `DS.RecordArray` for a modelName, which contains all loaded records of + given modelName. + + @method liveRecordArrayFor + @param {String} modelName + @return {DS.RecordArray} + */ + liveRecordArrayFor(modelName) { + assert(`recordArrayManger.liveRecordArrayFor expects modelName not modelClass as the param`, typeof modelName === 'string'); + + heimdall.increment(liveRecordArrayFor); + + return this._liveRecordArrays[modelName] || (this._liveRecordArrays[modelName] = this.createRecordArray(modelName)) + } + + /** + Get the `DS.RecordArray` for a modelName, which contains all loaded records of + given modelName. + + @method filteredRecordArraysFor + @param {String} modelName + @return {DS.RecordArray} + */ + filteredRecordArraysFor(modelName) { + assert(`recordArrayManger.filteredRecordArraysFor expects modelName not modelClass as the param`, typeof modelName === 'string'); + + heimdall.increment(filteredRecordArraysFor); + + return this._filteredRecordArrays[modelName] || (this._filteredRecordArrays[modelName] = []); + } + /** + Create a `DS.RecordArray` for a modelName. + + @method createRecordArray + @param {String} modelName + @return {DS.RecordArray} + */ + createRecordArray(modelName) { + assert(`recordArrayManger.createRecordArray expects modelName not modelClass as the param`, typeof modelName === 'string'); + heimdall.increment(createRecordArray); + return RecordArray.create({ + modelName, + content: Ember.A(), + store: this.store, + isLoaded: true, + manager: this + }); + } + + /** + Create a `DS.FilteredRecordArray` for a modelName and register it for updates. + + @method createFilteredRecordArray + @param {String} modelName + @param {Function} filter + @param {Object} query (optional + @return {DS.FilteredRecordArray} + */ + createFilteredRecordArray(modelName, filter, query) { + assert(`recordArrayManger.createFilteredRecordArray expects modelName not modelClass as the first param, received ${modelName}`, typeof modelName === 'string'); + + heimdall.increment(createFilteredRecordArray); + let array = FilteredRecordArray.create({ + query, + modelName, + content: Ember.A(), + store: this.store, + manager: this, + filterFunction: filter + }); + + this.registerFilteredRecordArray(array, modelName, filter); + + return array; + } + + /** + Create a `DS.AdapterPopulatedRecordArray` for a modelName with given query. + + @method createAdapterPopulatedRecordArray + @param {String} modelName + @param {Object} query + @return {DS.AdapterPopulatedRecordArray} + */ + createAdapterPopulatedRecordArray(modelName, query) { + heimdall.increment(createAdapterPopulatedRecordArray); + assert(`recordArrayManger.createAdapterPopulatedRecordArray expects modelName not modelClass as the first param, received ${modelName}`, typeof modelName === 'string'); + + let array = AdapterPopulatedRecordArray.create({ + modelName, + query: query, + content: Ember.A(), + store: this.store, + manager: this + }); + + this._adapterPopulatedRecordArrays.push(array); + + return array; + } + + /** + Register a RecordArray for a given modelName to be backed by + a filter function. This will cause the array to update + automatically when records of that modelName change attribute + values or states. + + @method registerFilteredRecordArray + @param {DS.RecordArray} array + @param {String} modelName + @param {Function} filter + */ + registerFilteredRecordArray(array, modelName, filter) { + heimdall.increment(registerFilteredRecordArray); + assert(`recordArrayManger.registerFilteredRecordArray expects modelName not modelClass as the second param, received ${modelName}`, typeof modelName === 'string'); + + this.filteredRecordArraysFor(modelName).push(array); + this.updateFilter(array, modelName, filter); + } + + /** + Unregister a RecordArray. + So manager will not update this array. + + @method unregisterRecordArray + @param {DS.RecordArray} array + */ + unregisterRecordArray(array) { + heimdall.increment(unregisterRecordArray); + + let modelName = array.modelName; + + // unregister filtered record array + let recordArrays = this.filteredRecordArraysFor(modelName); + let removedFromFiltered = remove(recordArrays, array); + + // remove from adapter populated record array + let removedFromAdapterPopulated = remove(this._adapterPopulatedRecordArrays, array); + + if (!removedFromFiltered && !removedFromAdapterPopulated) { + + let liveRecordArrayForType = this._liveRecordArrays[modelName]; + // unregister live record array + if (liveRecordArrayForType) { + if (array === liveRecordArrayForType) { + delete this._liveRecordArrays[modelName]; + } + } + } + } + + willDestroy() { + Object.keys(this._filteredRecordArrays).forEach(modelName => flatten(this._filteredRecordArrays[modelName]).forEach(destroy)); + Object.keys(this._liveRecordArrays).forEach(modelName => this._liveRecordArrays[modelName].destroy()); + this._adapterPopulatedRecordArrays.forEach(destroy); + this.isDestroyed = true; + } + + destroy() { + this.isDestroying = true; + Ember.run.schedule('actions', this, this.willDestroy); + } +} + +function destroy(entry) { + entry.destroy(); +} + +function flatten(list) { + heimdall.increment(array_flatten); + let length = list.length; + let result = []; + + for (let i = 0; i < length; i++) { + result = result.concat(list[i]); + } + + return result; +} + +function remove(array, item) { + heimdall.increment(array_remove); + let index = array.indexOf(item); + + if (index !== -1) { + array.splice(index, 1); + return true; + } + + return false; +} + +/* global heimdall */ +const { set: set$4 } = Ember; + +const { + __get, + _instanceFor +} = heimdall.registerMonitor('system.store.container-instance-cache', + '__get', + '_instanceFor' +); + +/* + * The `ContainerInstanceCache` serves as a lazy cache for looking up + * instances of serializers and adapters. It has some additional logic for + * finding the 'fallback' adapter or serializer. + * + * The 'fallback' adapter or serializer is an adapter or serializer that is looked up + * when the preferred lookup fails. For example, say you try to look up `adapter:post`, + * but there is no entry (app/adapters/post.js in EmberCLI) for `adapter:post` in the registry. + * + * When an adapter or serializer is unfound, getFallbacks will be invoked with the current namespace + * ('adapter' or 'serializer') and the 'preferredKey' (usually a modelName). The method should return + * an array of keys to check against. + * + * The first entry in the fallbacks array that exists in the container will then be cached for + * `adapter:post`. So, the next time you look up `adapter:post`, you'll get the `adapter:application` + * instance (or whatever the fallback was if `adapter:application` doesn't exist). + * + * @private + * @class ContainerInstanceCache + * +*/ +class ContainerInstanceCache { + constructor(owner, store) { + this.isDestroying = false; + this.isDestroyed = false; + this._owner = owner; + this._store = store; + this._namespaces = { + adapter: Object.create(null), + serializer: Object.create(null) + }; + } + + get(namespace, preferredKey) { + heimdall.increment(__get); + let cache = this._namespaces[namespace]; + + if (cache[preferredKey]) { + return cache[preferredKey]; + } + + let preferredLookupKey = `${namespace}:${preferredKey}`; + + let instance = this._instanceFor(preferredLookupKey) || this._findInstance(namespace, this._fallbacksFor(namespace, preferredKey)); + if (instance) { + cache[preferredKey] = instance; + set$4(instance, 'store', this._store); + } + + return cache[preferredKey]; + } + + _fallbacksFor(namespace, preferredKey) { + if (namespace === 'adapter') { + return ['application', this._store.get('adapter'), '-json-api']; + } + + // serializer + return [ + 'application', + this.get('adapter', preferredKey).get('defaultSerializer'), + '-default' + ]; + } + + _findInstance(namespace, fallbacks) { + let cache = this._namespaces[namespace]; + + for (let i = 0, length = fallbacks.length; i < length; i++) { + let fallback = fallbacks[i]; + + if (cache[fallback]) { + return cache[fallback]; + } + + let lookupKey = `${namespace}:${fallback}`; + let instance = this._instanceFor(lookupKey); + + if (instance) { + cache[fallback] = instance; + return instance; + } + } + } + + _instanceFor(key) { + heimdall.increment(_instanceFor); + return this._owner.lookup(key); + } + + destroyCache(cache) { + let cacheEntries = Object.keys(cache); + + for (let i = 0, length = cacheEntries.length; i < length; i++) { + let cacheKey = cacheEntries[i]; + let cacheEntry = cache[cacheKey]; + if (cacheEntry) { + cacheEntry.destroy(); + } + } + } + + destroy() { + this.isDestroying = true; + this.destroyCache(this._namespaces.adapter); + this.destroyCache(this._namespaces.serializer); + this.isDestroyed = true; + } + + toString() { + return 'ContainerInstanceCache'; + } +} + +/** + @module ember-data +*/ + +const badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; + +const { + A, + _Backburner: Backburner, + computed: computed$1, + copy, + ENV, + Error: EmberError, + get: get$3, + inspect, + isNone, + isPresent, + MapWithDefault: MapWithDefault$2, + run: emberRun, + set: set$1, + RSVP, + Service, + typeOf +} = Ember; + +const { Promise: Promise$1 } = RSVP; + +//Get the materialized model from the internalModel/promise that returns +//an internal model and return it in a promiseObject. Useful for returning +//from find methods +function promiseRecord(internalModelPromise, label) { + let toReturn = internalModelPromise.then(internalModel => internalModel.getRecord()); + + return promiseObject(toReturn, label); +} + +let Store; + +// Implementors Note: +// +// The variables in this file are consistently named according to the following +// scheme: +// +// * +id+ means an identifier managed by an external source, provided inside +// the data provided by that source. These are always coerced to be strings +// before being used internally. +// * +clientId+ means a transient numerical identifier generated at runtime by +// the data store. It is important primarily because newly created objects may +// not yet have an externally generated id. +// * +internalModel+ means a record internalModel object, which holds metadata about a +// record, even if it has not yet been fully materialized. +// * +type+ means a DS.Model. + +const { + _generateId, + _internalModelForId, + _load, + _modelForMixin, + _pushInternalModel, + _setupRelationships, + adapterFor, + _buildInternalModel, + _didUpdateAll, + modelFactoryFor, + modelFor, + normalize, + peekAll, + peekRecord, + serializerFor, + _internalModelsFor +} = heimdall.registerMonitor('store', + '_generateId', + '_internalModelForId', + '_load', + '_modelForMixin', + '_pushInternalModel', + '_setupRelationships', + 'adapterFor', + '_buildInternalModel', + '_didUpdateAll', + 'modelFactoryFor', + 'modelFor', + 'normalize', + 'peekAll', + 'peekRecord', + 'serializerFor', + '_internalModelsFor' +); + +/** + The store contains all of the data for records loaded from the server. + It is also responsible for creating instances of `DS.Model` that wrap + the individual data for a record, so that they can be bound to in your + Handlebars templates. + + Define your application's store like this: + + ```app/services/store.js + import DS from 'ember-data'; + + export default DS.Store.extend({ + }); + ``` + + Most Ember.js applications will only have a single `DS.Store` that is + automatically created by their `Ember.Application`. + + You can retrieve models from the store in several ways. To retrieve a record + for a specific id, use `DS.Store`'s `findRecord()` method: + + ```javascript + store.findRecord('person', 123).then(function (person) { + }); + ``` + + By default, the store will talk to your backend using a standard + REST mechanism. You can customize how the store talks to your + backend by specifying a custom adapter: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + }); + ``` + + You can learn more about writing a custom adapter by reading the `DS.Adapter` + documentation. + + ### Store createRecord() vs. push() vs. pushPayload() + + The store provides multiple ways to create new record objects. They have + some subtle differences in their use which are detailed below: + + [createRecord](#method_createRecord) is used for creating new + records on the client side. This will return a new record in the + `created.uncommitted` state. In order to persist this record to the + backend you will need to call `record.save()`. + + [push](#method_push) is used to notify Ember Data's store of new or + updated records that exist in the backend. This will return a record + in the `loaded.saved` state. The primary use-case for `store#push` is + to notify Ember Data about record updates (full or partial) that happen + outside of the normal adapter methods (for example + [SSE](http://dev.w3.org/html5/eventsource/) or [Web + Sockets](http://www.w3.org/TR/2009/WD-websockets-20091222/)). + + [pushPayload](#method_pushPayload) is a convenience wrapper for + `store#push` that will deserialize payloads if the + Serializer implements a `pushPayload` method. + + Note: When creating a new record using any of the above methods + Ember Data will update `DS.RecordArray`s such as those returned by + `store#peekAll()`, `store#findAll()` or `store#filter()`. This means any + data bindings or computed properties that depend on the RecordArray + will automatically be synced to include the new or updated record + values. + + @class Store + @namespace DS + @extends Ember.Service +*/ +Store = Service.extend({ + + /** + @method init + @private + */ + init() { + this._super(...arguments); + this._backburner = new Backburner(['normalizeRelationships', 'syncRelationships', 'finished']); + // internal bookkeeping; not observable + this.recordArrayManager = new RecordArrayManager({ store: this }); + this._identityMap = new IdentityMap(); + this._pendingSave = []; + this._instanceCache = new ContainerInstanceCache(getOwner(this), this); + this._modelFactoryCache = Object.create(null); + this._relationshipsPayloads = new RelationshipPayloadsManager(this); + + /* + Ember Data uses several specialized micro-queues for organizing + and coalescing similar async work. + + These queues are currently controlled by a flush scheduled into + ember-data's custom backburner instance. + */ + // used for coalescing record save requests + this._pendingSave = []; + // used for coalescing relationship updates + this._updatedRelationships = []; + // used for coalescing relationship setup needs + this._pushedInternalModels = []; + // used for coalescing internal model updates + this._updatedInternalModels = []; + + // used to keep track of all the find requests that need to be coalesced + this._pendingFetch = MapWithDefault$2.create({ defaultValue() { return []; } }); + + this._instanceCache = new ContainerInstanceCache(getOwner(this), this); + }, + + /** + The default adapter to use to communicate to a backend server or + other persistence layer. This will be overridden by an application + adapter if present. + + If you want to specify `app/adapters/custom.js` as a string, do: + + ```js + import DS from 'ember-data'; + + export default DS.Store.extend({ + adapter: 'custom', + }); + ``` + + @property adapter + @default '-json-api' + @type {String} + */ + adapter: '-json-api', + + /** + Returns a JSON representation of the record using a custom + type-specific serializer, if one exists. + + The available options are: + + * `includeId`: `true` if the record's ID should be included in + the JSON representation + + @method serialize + @private + @deprecated + @param {DS.Model} record the record to serialize + @param {Object} options an options hash + */ + serialize(record, options) { + if (isEnabled('ds-deprecate-store-serialize')) { + deprecate('Use of store.serialize is deprecated, use record.serialize instead.', false, { + id: 'ds.store.serialize', + until: '3.0' + }); + } + let snapshot = record._internalModel.createSnapshot(); + return snapshot.serialize(options); + }, + + /** + This property returns the adapter, after resolving a possible + string key. + + If the supplied `adapter` was a class, or a String property + path resolved to a class, this property will instantiate the + class. + + This property is cacheable, so the same instance of a specified + adapter class should be used for the lifetime of the store. + + @property defaultAdapter + @private + @return DS.Adapter + */ + defaultAdapter: computed$1('adapter', function() { + let adapter = get$3(this, 'adapter'); + + assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name', typeof adapter === 'string'); + + return this.adapterFor(adapter); + }), + + // ..................... + // . CREATE NEW RECORD . + // ..................... + + /** + Create a new record in the current store. The properties passed + to this method are set on the newly created record. + + To create a new instance of a `Post`: + + ```js + store.createRecord('post', { + title: 'Rails is omakase' + }); + ``` + + To create a new instance of a `Post` that has a relationship with a `User` record: + + ```js + let user = this.store.peekRecord('user', 1); + store.createRecord('post', { + title: 'Rails is omakase', + user: user + }); + ``` + + @method createRecord + @param {String} modelName + @param {Object} inputProperties a hash of properties to set on the + newly created record. + @return {DS.Model} record + */ + createRecord(modelName, inputProperties) { + assert(`You need to pass a model name to the store's createRecord method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + let properties = copy(inputProperties) || Object.create(null); + + // If the passed properties do not include a primary key, + // give the adapter an opportunity to generate one. Typically, + // client-side ID generators will use something like uuid.js + // to avoid conflicts. + + if (isNone(properties.id)) { + properties.id = this._generateId(normalizedModelName, properties); + } + + // Coerce ID to a string + properties.id = coerceId(properties.id); + + let internalModel = this._buildInternalModel(normalizedModelName, properties.id); + let record = internalModel.getRecord(); + + // Move the record out of its initial `empty` state into + // the `loaded` state. + // TODO @runspired this seems really bad, store should not be changing the state + internalModel.loadedData(); + + // Set the properties specified on the record. + // TODO @runspired this is probably why we do the bad thing above + record.setProperties(properties); + + // TODO @runspired this should also be coalesced into some form of internalModel.setState() + internalModel.eachRelationship((key, descriptor) => { + internalModel._relationships.get(key).setHasData(true); + }); + + return record; + }, + + /** + If possible, this method asks the adapter to generate an ID for + a newly created record. + + @method _generateId + @private + @param {String} modelName + @param {Object} properties from the new record + @return {String} if the adapter can generate one, an ID + */ + _generateId(modelName, properties) { + heimdall.increment(_generateId); + let adapter = this.adapterFor(modelName); + + if (adapter && adapter.generateIdForRecord) { + return adapter.generateIdForRecord(this, modelName, properties); + } + + return null; + }, + + // ................. + // . DELETE RECORD . + // ................. + + /** + For symmetry, a record can be deleted via the store. + + Example + + ```javascript + let post = store.createRecord('post', { + title: 'Rails is omakase' + }); + + store.deleteRecord(post); + ``` + + @method deleteRecord + @param {DS.Model} record + */ + deleteRecord(record) { + record.deleteRecord(); + }, + + /** + For symmetry, a record can be unloaded via the store. + This will cause the record to be destroyed and freed up for garbage collection. + + Example + + ```javascript + store.findRecord('post', 1).then(function(post) { + store.unloadRecord(post); + }); + ``` + + @method unloadRecord + @param {DS.Model} record + */ + unloadRecord(record) { + record.unloadRecord(); + }, + + // ................ + // . FIND RECORDS . + // ................ + + /** + @method find + @param {String} modelName + @param {String|Integer} id + @param {Object} options + @return {Promise} promise + @private + */ + find(modelName, id, options) { + // The default `model` hook in Ember.Route calls `find(modelName, id)`, + // that's why we have to keep this method around even though `findRecord` is + // the public way to get a record by modelName and id. + assert(`Using store.find(type) has been removed. Use store.findAll(modelName) to retrieve all records for a given type.`, arguments.length !== 1); + assert(`Calling store.find(modelName, id, { preload: preload }) is no longer supported. Use store.findRecord(modelName, id, { preload: preload }) instead.`, !options); + assert(`You need to pass the model name and id to the store's find method`, arguments.length === 2); + assert(`You cannot pass '${id}' as id to the store's find method`, typeof id === 'string' || typeof id === 'number'); + assert(`Calling store.find() with a query object is no longer supported. Use store.query() instead.`, typeof id !== 'object'); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let normalizedModelName = normalizeModelName(modelName); + + return this.findRecord(normalizedModelName, id); + }, + + /** + This method returns a record for a given type and id combination. + + The `findRecord` method will always resolve its promise with the same + object for a given type and `id`. + + The `findRecord` method will always return a **promise** that will be + resolved with the record. + + Example + + ```app/routes/post.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model(params) { + return this.store.findRecord('post', params.post_id); + } + }); + ``` + + If the record is not yet available, the store will ask the adapter's `find` + method to find the necessary data. If the record is already present in the + store, it depends on the reload behavior _when_ the returned promise + resolves. + + ### Preloading + + You can optionally `preload` specific attributes and relationships that you know of + by passing them via the passed `options`. + + For example, if your Ember route looks like `/posts/1/comments/2` and your API route + for the comment also looks like `/posts/1/comments/2` if you want to fetch the comment + without fetching the post you can pass in the post to the `findRecord` call: + + ```javascript + store.findRecord('comment', 2, { preload: { post: 1 } }); + ``` + + If you have access to the post model you can also pass the model itself: + + ```javascript + store.findRecord('post', 1).then(function (myPostModel) { + store.findRecord('comment', 2, { post: myPostModel }); + }); + ``` + + ### Reloading + + The reload behavior is configured either via the passed `options` hash or + the result of the adapter's `shouldReloadRecord`. + + If `{ reload: true }` is passed or `adapter.shouldReloadRecord` evaluates + to `true`, then the returned promise resolves once the adapter returns + data, regardless if the requested record is already in the store: + + ```js + store.push({ + data: { + id: 1, + type: 'post', + revision: 1 + } + }); + + // adapter#findRecord resolves with + // [ + // { + // id: 1, + // type: 'post', + // revision: 2 + // } + // ] + store.findRecord('post', 1, { reload: true }).then(function(post) { + post.get('revision'); // 2 + }); + ``` + + If no reload is indicated via the abovementioned ways, then the promise + immediately resolves with the cached version in the store. + + ### Background Reloading + + Optionally, if `adapter.shouldBackgroundReloadRecord` evaluates to `true`, + then a background reload is started, which updates the records' data, once + it is available: + + ```js + // app/adapters/post.js + import ApplicationAdapter from "./application"; + + export default ApplicationAdapter.extend({ + shouldReloadRecord(store, snapshot) { + return false; + }, + + shouldBackgroundReloadRecord(store, snapshot) { + return true; + } + }); + + // ... + + store.push({ + data: { + id: 1, + type: 'post', + revision: 1 + } + }); + + let blogPost = store.findRecord('post', 1).then(function(post) { + post.get('revision'); // 1 + }); + + // later, once adapter#findRecord resolved with + // [ + // { + // id: 1, + // type: 'post', + // revision: 2 + // } + // ] + + blogPost.get('revision'); // 2 + ``` + + If you would like to force or prevent background reloading, you can set a + boolean value for `backgroundReload` in the options object for + `findRecord`. + + ```app/routes/post/edit.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model(params) { + return this.store.findRecord('post', params.post_id, { backgroundReload: false }); + } + }); + ``` + + If you pass an object on the `adapterOptions` property of the options + argument it will be passed to you adapter via the snapshot + + ```app/routes/post/edit.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model(params) { + return this.store.findRecord('post', params.post_id, { + adapterOptions: { subscribe: false } + }); + } + }); + ``` + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + findRecord(store, type, id, snapshot) { + if (snapshot.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + + See [peekRecord](#method_peekRecord) to get the cached version of a record. + + ### Retrieving Related Model Records + + If you use an adapter such as Ember's default + [`JSONAPIAdapter`](http://emberjs.com/api/data/classes/DS.JSONAPIAdapter.html) + that supports the [JSON API specification](http://jsonapi.org/) and if your server + endpoint supports the use of an + ['include' query parameter](http://jsonapi.org/format/#fetching-includes), + you can use `findRecord()` to automatically retrieve additional records related to + the one you request by supplying an `include` parameter in the `options` object. + + For example, given a `post` model that has a `hasMany` relationship with a `comment` + model, when we retrieve a specific post we can have the server also return that post's + comments in the same request: + + ```app/routes/post.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model(params) { + return this.store.findRecord('post', params.post_id, { include: 'comments' }); + } + }); + + ``` + In this case, the post's comments would then be available in your template as + `model.comments`. + + Multiple relationships can be requested using an `include` parameter consisting of a + comma-separated list (without white-space) while nested relationships can be specified + using a dot-separated sequence of relationship names. So to request both the post's + comments and the authors of those comments the request would look like this: + + ```app/routes/post.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model(params) { + return this.store.findRecord('post', params.post_id, { include: 'comments,comments.author' }); + } + }); + + ``` + + @since 1.13.0 + @method findRecord + @param {String} modelName + @param {(String|Integer)} id + @param {Object} options + @return {Promise} promise + */ + findRecord(modelName, id, options) { + assert(`You need to pass a model name to the store's findRecord method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert(badIdFormatAssertion, (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id))); + + let normalizedModelName = normalizeModelName(modelName); + + let internalModel = this._internalModelForId(normalizedModelName, id); + options = options || {}; + + if (!this.hasRecordForId(normalizedModelName, id)) { + return this._findByInternalModel(internalModel, options); + } + + let fetchedInternalModel = this._findRecord(internalModel, options); + + return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${normalizedModelName} with id: ${id}`); + }, + + _findRecord(internalModel, options) { + // Refetch if the reload option is passed + if (options.reload) { + return this._scheduleFetch(internalModel, options); + } + + let snapshot = internalModel.createSnapshot(options); + let adapter = this.adapterFor(internalModel.modelName); + + // Refetch the record if the adapter thinks the record is stale + if (adapter.shouldReloadRecord(this, snapshot)) { + return this._scheduleFetch(internalModel, options); + } + + if (options.backgroundReload === false) { + return Promise$1.resolve(internalModel); + } + + // Trigger the background refetch if backgroundReload option is passed + if (options.backgroundReload || adapter.shouldBackgroundReloadRecord(this, snapshot)) { + this._scheduleFetch(internalModel, options); + } + + // Return the cached record + return Promise$1.resolve(internalModel); + }, + + _findByInternalModel(internalModel, options = {}) { + if (options.preload) { + internalModel.preloadData(options.preload); + } + + let fetchedInternalModel = this._findEmptyInternalModel(internalModel, options); + + return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${internalModel.modelName} with id: ${internalModel.id}`); + }, + + _findEmptyInternalModel(internalModel, options) { + if (internalModel.isEmpty()) { + return this._scheduleFetch(internalModel, options); + } + + //TODO double check about reloading + if (internalModel.isLoading()) { + return internalModel._loadingPromise; + } + + return Promise$1.resolve(internalModel); + }, + + /** + This method makes a series of requests to the adapter's `find` method + and returns a promise that resolves once they are all loaded. + + @private + @method findByIds + @param {String} modelName + @param {Array} ids + @return {Promise} promise + */ + findByIds(modelName, ids) { + assert(`You need to pass a model name to the store's findByIds method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let promises = new Array(ids.length); + + let normalizedModelName = normalizeModelName(modelName); + + for (let i = 0; i < ids.length; i++) { + promises[i] = this.findRecord(normalizedModelName, ids[i]); + } + + return promiseArray(RSVP.all(promises).then(A, null, `DS: Store#findByIds of ${normalizedModelName} complete`)); + }, + + /** + This method is called by `findRecord` if it discovers that a particular + type/id pair hasn't been loaded yet to kick off a request to the + adapter. + + @method _fetchRecord + @private + @param {InternalModel} internalModel model + @return {Promise} promise + */ + _fetchRecord(internalModel, options) { + let modelName = internalModel.modelName; + let adapter = this.adapterFor(modelName); + + assert(`You tried to find a record but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to find a record but your adapter (for ${modelName}) does not implement 'findRecord'`, typeof adapter.findRecord === 'function'); + + return _find(adapter, this, internalModel.type, internalModel.id, internalModel, options); + }, + + _scheduleFetchMany(internalModels) { + let fetches = new Array(internalModels.length); + + for (let i = 0; i < internalModels.length; i++) { + fetches[i] = this._scheduleFetch(internalModels[i]); + } + + return Promise$1.all(fetches); + }, + + _scheduleFetch(internalModel, options) { + if (internalModel._loadingPromise) { + return internalModel._loadingPromise; + } + + let { id, modelName } = internalModel; + let resolver = RSVP.defer(`Fetching ${modelName}' with id: ${id}`); + let pendingFetchItem = { + internalModel, + resolver, + options + }; + + let promise = resolver.promise; + + internalModel.loadingData(promise); + if (this._pendingFetch.size === 0) { + emberRun.schedule('afterRender', this, this.flushAllPendingFetches); + } + + this._pendingFetch.get(modelName).push(pendingFetchItem); + + return promise; + }, + + flushAllPendingFetches() { + if (this.isDestroyed || this.isDestroying) { + return; + } + + this._pendingFetch.forEach(this._flushPendingFetchForType, this); + this._pendingFetch.clear(); + }, + + _flushPendingFetchForType(pendingFetchItems, modelName) { + let store = this; + let adapter = store.adapterFor(modelName); + let shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; + let totalItems = pendingFetchItems.length; + let internalModels = new Array(totalItems); + let seeking = Object.create(null); + + for (let i = 0; i < totalItems; i++) { + let pendingItem = pendingFetchItems[i]; + let internalModel = pendingItem.internalModel; + internalModels[i] = internalModel; + seeking[internalModel.id] = pendingItem; + } + + function _fetchRecord(recordResolverPair) { + let recordFetch = store._fetchRecord( + recordResolverPair.internalModel, + recordResolverPair.options + ); // TODO adapter options + + recordResolverPair.resolver.resolve(recordFetch); + } + + function handleFoundRecords(foundInternalModels, expectedInternalModels) { + // resolve found records + let found = Object.create(null); + for (let i = 0, l = foundInternalModels.length; i < l; i++) { + let internalModel = foundInternalModels[i]; + let pair = seeking[internalModel.id]; + found[internalModel.id] = internalModel; + + if (pair) { + let resolver = pair.resolver; + resolver.resolve(internalModel); + } + } + + // reject missing records + let missingInternalModels = []; + + for (let i = 0, l = expectedInternalModels.length; i < l; i++) { + let internalModel = expectedInternalModels[i]; + + if (!found[internalModel.id]) { + missingInternalModels.push(internalModel); + } + } + + if (missingInternalModels.length) { + warn('Ember Data expected to find records with the following ids in the adapter response but they were missing: ' + inspect(missingInternalModels.map(r => r.id)), false, { + id: 'ds.store.missing-records-from-adapter' + }); + rejectInternalModels(missingInternalModels); + } + } + + function rejectInternalModels(internalModels, error) { + for (let i = 0, l = internalModels.length; i < l; i++) { + let internalModel = internalModels[i]; + let pair = seeking[internalModel.id]; + + if (pair) { + pair.resolver.reject(error || new Error(`Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.`)); + } + } + } + + if (shouldCoalesce) { + // TODO: Improve records => snapshots => records => snapshots + // + // We want to provide records to all store methods and snapshots to all + // adapter methods. To make sure we're doing that we're providing an array + // of snapshots to adapter.groupRecordsForFindMany(), which in turn will + // return grouped snapshots instead of grouped records. + // + // But since the _findMany() finder is a store method we need to get the + // records from the grouped snapshots even though the _findMany() finder + // will once again convert the records to snapshots for adapter.findMany() + let snapshots = new Array(totalItems); + for (let i = 0; i < totalItems; i++) { + snapshots[i] = internalModels[i].createSnapshot(); + } + + let groups = adapter.groupRecordsForFindMany(this, snapshots); + + for (let i = 0, l = groups.length; i < l; i++) { + let group = groups[i]; + let totalInGroup = groups[i].length; + let ids = new Array(totalInGroup); + let groupedInternalModels = new Array(totalInGroup); + + for (let j = 0; j < totalInGroup; j++) { + let internalModel = group[j]._internalModel; + + groupedInternalModels[j] = internalModel; + ids[j] = internalModel.id; + } + + if (totalInGroup > 1) { + _findMany(adapter, store, modelName, ids, groupedInternalModels) + .then(function(foundInternalModels) { + handleFoundRecords(foundInternalModels, groupedInternalModels); + }) + .catch(function(error) { + rejectInternalModels(groupedInternalModels, error); + }); + } else if (ids.length === 1) { + let pair = seeking[groupedInternalModels[0].id]; + _fetchRecord(pair); + } else { + assert("You cannot return an empty array from adapter's method groupRecordsForFindMany", false); + } + } + } else { + for (let i = 0; i < totalItems; i++) { + _fetchRecord(pendingFetchItems[i]); + } + } + }, + + /** + Get the reference for the specified record. + + Example + + ```javascript + let userRef = store.getReference('user', 1); + + // check if the user is loaded + let isLoaded = userRef.value() !== null; + + // get the record of the reference (null if not yet available) + let user = userRef.value(); + + // get the identifier of the reference + if (userRef.remoteType() === 'id') { + let id = userRef.id(); + } + + // load user (via store.find) + userRef.load().then(...) + + // or trigger a reload + userRef.reload().then(...) + + // provide data for reference + userRef.push({ id: 1, username: '@user' }).then(function(user) { + userRef.value() === user; + }); + ``` + + @method getReference + @param {String} modelName + @param {String|Integer} id + @since 2.5.0 + @return {RecordReference} + */ + getReference(modelName, id) { + let normalizedModelName = normalizeModelName(modelName); + + return this._internalModelForId(normalizedModelName, id).recordReference; + }, + + /** + Get a record by a given type and ID without triggering a fetch. + + This method will synchronously return the record if it is available in the store, + otherwise it will return `null`. A record is available if it has been fetched earlier, or + pushed manually into the store. + + See [findRecord](#method_findRecord) if you would like to request this record from the backend. + + _Note: This is a synchronous method and does not return a promise._ + + ```js + let post = store.peekRecord('post', 1); + + post.get('id'); // 1 + ``` + + @since 1.13.0 + @method peekRecord + @param {String} modelName + @param {String|Integer} id + @return {DS.Model|null} record + */ + peekRecord(modelName, id) { + heimdall.increment(peekRecord); + assert(`You need to pass a model name to the store's peekRecord method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + + if (this.hasRecordForId(normalizedModelName, id)) { + return this._internalModelForId(normalizedModelName, id).getRecord(); + } else { + return null; + } + }, + + /** + This method is called by the record's `reload` method. + + This method calls the adapter's `find` method, which returns a promise. When + **that** promise resolves, `reloadRecord` will resolve the promise returned + by the record's `reload`. + + @method reloadRecord + @private + @param {DS.Model} internalModel + @return {Promise} promise + */ + _reloadRecord(internalModel) { + let { id, modelName } = internalModel; + let adapter = this.adapterFor(modelName); + + assert(`You cannot reload a record without an ID`, id); + assert(`You tried to reload a record but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to reload a record but your adapter does not implement 'findRecord'`, typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); + + return this._scheduleFetch(internalModel); + }, + + /** + This method returns true if a record for a given modelName and id is already + loaded in the store. Use this function to know beforehand if a findRecord() + will result in a request or that it will be a cache hit. + + Example + + ```javascript + store.hasRecordForId('post', 1); // false + store.findRecord('post', 1).then(function() { + store.hasRecordForId('post', 1); // true + }); + ``` + + @method hasRecordForId + @param {String} modelName + @param {(String|Integer)} id + @return {Boolean} + */ + hasRecordForId(modelName, id) { + assert(`You need to pass a model name to the store's hasRecordForId method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let normalizedModelName = normalizeModelName(modelName); + + let trueId = coerceId(id); + let internalModel = this._internalModelsFor(normalizedModelName).get(trueId); + + return !!internalModel && internalModel.isLoaded(); + }, + + /** + Returns id record for a given type and ID. If one isn't already loaded, + it builds a new record and leaves it in the `empty` state. + + @method recordForId + @private + @param {String} modelName + @param {(String|Integer)} id + @return {DS.Model} record + */ + recordForId(modelName, id) { + assert(`You need to pass a model name to the store's recordForId method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + return this._internalModelForId(modelName, id).getRecord(); + }, + + _internalModelForId(modelName, id) { + heimdall.increment(_internalModelForId); + let trueId = coerceId(id); + let internalModel = this._internalModelsFor(modelName).get(trueId); + + if (!internalModel) { + internalModel = this._buildInternalModel(modelName, trueId); + } + + return internalModel; + }, + + _internalModelDidReceiveRelationshipData(modelName, id, relationshipData) { + this._relationshipsPayloads.push(modelName, id, relationshipData); + }, + + _internalModelDestroyed(internalModel) { + this._removeFromIdMap(internalModel); + this._relationshipsPayloads.unload(internalModel.modelName, internalModel.id); + }, + + /** + @method findMany + @private + @param {Array} internalModels + @return {Promise} promise + */ + findMany(internalModels) { + let finds = new Array(internalModels.length); + + for (let i = 0; i < internalModels.length; i++) { + finds[i] = this._findEmptyInternalModel(internalModels[i]); + } + + return Promise$1.all(finds); + }, + + + /** + If a relationship was originally populated by the adapter as a link + (as opposed to a list of IDs), this method is called when the + relationship is fetched. + + The link (which is usually a URL) is passed through unchanged, so the + adapter can make whatever request it wants. + + The usual use-case is for the server to register a URL as a link, and + then use that URL in the future to make a request for the relationship. + + @method findHasMany + @private + @param {InternalModel} internalModel + @param {any} link + @param {(Relationship)} relationship + @return {Promise} promise + */ + findHasMany(internalModel, link, relationship) { + let adapter = this.adapterFor(internalModel.modelName); + + assert(`You tried to load a hasMany relationship but you have no adapter (for ${internalModel.modelName})`, adapter); + assert(`You tried to load a hasMany relationship from a specified 'link' in the original payload but your adapter does not implement 'findHasMany'`, typeof adapter.findHasMany === 'function'); + + return _findHasMany(adapter, this, internalModel, link, relationship); + }, + + /** + @method findBelongsTo + @private + @param {InternalModel} internalModel + @param {any} link + @param {Relationship} relationship + @return {Promise} promise + */ + findBelongsTo(internalModel, link, relationship) { + let adapter = this.adapterFor(internalModel.modelName); + + assert(`You tried to load a belongsTo relationship but you have no adapter (for ${internalModel.modelName})`, adapter); + assert(`You tried to load a belongsTo relationship from a specified 'link' in the original payload but your adapter does not implement 'findBelongsTo'`, typeof adapter.findBelongsTo === 'function'); + + return _findBelongsTo(adapter, this, internalModel, link, relationship); + }, + + /** + This method delegates a query to the adapter. This is the one place where + adapter-level semantics are exposed to the application. + + Each time this method is called a new request is made through the adapter. + + Exposing queries this way seems preferable to creating an abstract query + language for all server-side queries, and then require all adapters to + implement them. + + --- + + If you do something like this: + + ```javascript + store.query('person', { page: 1 }); + ``` + + The call made to the server, using a Rails backend, will look something like this: + + ``` + Started GET "/api/v1/person?page=1" + Processing by Api::V1::PersonsController#index as HTML + Parameters: { "page"=>"1" } + ``` + + --- + + If you do something like this: + + ```javascript + store.query('person', { ids: [1, 2, 3] }); + ``` + + The call to the server, using a Rails backend, will look something like this: + + ``` + Started GET "/api/v1/person?ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3" + Processing by Api::V1::PersonsController#index as HTML + Parameters: { "ids" => ["1", "2", "3"] } + ``` + + This method returns a promise, which is resolved with an + [`AdapterPopulatedRecordArray`](http://emberjs.com/api/data/classes/DS.AdapterPopulatedRecordArray.html) + once the server returns. + + @since 1.13.0 + @method query + @param {String} modelName + @param {any} query an opaque query to be used by the adapter + @return {Promise} promise + */ + query(modelName, query) { + assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); + assert(`You need to pass a query hash to the store's query method`, query); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let normalizedModelName = normalizeModelName(modelName); + return this._query(normalizedModelName, query); + }, + + _query(modelName, query, array) { + let token = heimdall.start('store._query'); + assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); + assert(`You need to pass a query hash to the store's query method`, query); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let modelToken = heimdall.start('initial-modelFor-lookup'); + heimdall.stop(modelToken); + + array = array || this.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); + + let adapterToken = heimdall.start('initial-adapterFor-lookup'); + let adapter = this.adapterFor(modelName); + heimdall.stop(adapterToken); + + assert(`You tried to load a query but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to load a query but your adapter does not implement 'query'`, typeof adapter.query === 'function'); + + let pA = promiseArray(_query(adapter, this, modelName, query, array)); + instrument(() => { + pA.finally(() => { heimdall.stop(token); }); + }); + return pA; + }, + + /** + This method makes a request for one record, where the `id` is not known + beforehand (if the `id` is known, use [`findRecord`](#method_findRecord) + instead). + + This method can be used when it is certain that the server will return a + single object for the primary data. + + Each time this method is called a new request is made through the adapter. + + Let's assume our API provides an endpoint for the currently logged in user + via: + + ``` + // GET /api/current_user + { + user: { + id: 1234, + username: 'admin' + } + } + ``` + + Since the specific `id` of the `user` is not known beforehand, we can use + `queryRecord` to get the user: + + ```javascript + store.queryRecord('user', {}).then(function(user) { + let username = user.get('username'); + console.log(`Currently logged in as ${username}`); + }); + ``` + + The request is made through the adapters' `queryRecord`: + + ```app/adapters/user.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + queryRecord(modelName, query) { + return Ember.$.getJSON('/api/current_user'); + } + }); + ``` + + Note: the primary use case for `store.queryRecord` is when a single record + is queried and the `id` is not known beforehand. In all other cases + `store.query` and using the first item of the array is likely the preferred + way: + + ``` + // GET /users?username=unique + { + data: [{ + id: 1234, + type: 'user', + attributes: { + username: "unique" + } + }] + } + ``` + + ```javascript + store.query('user', { username: 'unique' }).then(function(users) { + return users.get('firstObject'); + }).then(function(user) { + let id = user.get('id'); + }); + ``` + + This method returns a promise, which resolves with the found record. + + If the adapter returns no data for the primary data of the payload, then + `queryRecord` resolves with `null`: + + ``` + // GET /users?username=unique + { + data: null + } + ``` + + ```javascript + store.queryRecord('user', { username: 'unique' }).then(function(user) { + console.log(user); // null + }); + ``` + + @since 1.13.0 + @method queryRecord + @param {String} modelName + @param {any} query an opaque query to be used by the adapter + @return {Promise} promise which resolves with the found record or `null` + */ + queryRecord(modelName, query) { + assert(`You need to pass a model name to the store's queryRecord method`, isPresent(modelName)); + assert(`You need to pass a query hash to the store's queryRecord method`, query); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let normalizedModelName = normalizeModelName(modelName); + + let adapter = this.adapterFor(normalizedModelName); + + assert(`You tried to make a query but you have no adapter (for ${normalizedModelName})`, adapter); + assert(`You tried to make a query but your adapter does not implement 'queryRecord'`, typeof adapter.queryRecord === 'function'); + + return promiseObject(_queryRecord(adapter, this, modelName, query).then(internalModel => { + // the promise returned by store.queryRecord is expected to resolve with + // an instance of DS.Model + if (internalModel) { + return internalModel.getRecord(); + } + + return null; + })); + }, + + /** + `findAll` asks the adapter's `findAll` method to find the records for the + given type, and returns a promise which will resolve with all records of + this type present in the store, even if the adapter only returns a subset + of them. + + ```app/routes/authors.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model(params) { + return this.store.findAll('author'); + } + }); + ``` + + _When_ the returned promise resolves depends on the reload behavior, + configured via the passed `options` hash and the result of the adapter's + `shouldReloadAll` method. + + ### Reloading + + If `{ reload: true }` is passed or `adapter.shouldReloadAll` evaluates to + `true`, then the returned promise resolves once the adapter returns data, + regardless if there are already records in the store: + + ```js + store.push({ + data: { + id: 'first', + type: 'author' + } + }); + + // adapter#findAll resolves with + // [ + // { + // id: 'second', + // type: 'author' + // } + // ] + store.findAll('author', { reload: true }).then(function(authors) { + authors.getEach('id'); // ['first', 'second'] + }); + ``` + + If no reload is indicated via the abovementioned ways, then the promise + immediately resolves with all the records currently loaded in the store. + + ### Background Reloading + + Optionally, if `adapter.shouldBackgroundReloadAll` evaluates to `true`, + then a background reload is started. Once this resolves, the array with + which the promise resolves, is updated automatically so it contains all the + records in the store: + + ```js + // app/adapters/application.js + export default DS.Adapter.extend({ + shouldReloadAll(store, snapshotsArray) { + return false; + }, + + shouldBackgroundReloadAll(store, snapshotsArray) { + return true; + } + }); + + // ... + + store.push({ + data: { + id: 'first', + type: 'author' + } + }); + + let allAuthors; + store.findAll('author').then(function(authors) { + authors.getEach('id'); // ['first'] + + allAuthors = authors; + }); + + // later, once adapter#findAll resolved with + // [ + // { + // id: 'second', + // type: 'author' + // } + // ] + + allAuthors.getEach('id'); // ['first', 'second'] + ``` + + If you would like to force or prevent background reloading, you can set a + boolean value for `backgroundReload` in the options object for + `findAll`. + + ```app/routes/post/edit.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model() { + return this.store.findAll('post', { backgroundReload: false }); + } + }); + ``` + + If you pass an object on the `adapterOptions` property of the options + argument it will be passed to you adapter via the `snapshotRecordArray` + + ```app/routes/posts.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model(params) { + return this.store.findAll('post', { + adapterOptions: { subscribe: false } + }); + } + }); + ``` + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + findAll(store, type, sinceToken, snapshotRecordArray) { + if (snapshotRecordArray.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + + See [peekAll](#method_peekAll) to get an array of current records in the + store, without waiting until a reload is finished. + + ### Retrieving Related Model Records + + If you use an adapter such as Ember's default + [`JSONAPIAdapter`](http://emberjs.com/api/data/classes/DS.JSONAPIAdapter.html) + that supports the [JSON API specification](http://jsonapi.org/) and if your server + endpoint supports the use of an + ['include' query parameter](http://jsonapi.org/format/#fetching-includes), + you can use `findAll()` to automatically retrieve additional records related to + those requested by supplying an `include` parameter in the `options` object. + + For example, given a `post` model that has a `hasMany` relationship with a `comment` + model, when we retrieve all of the post records we can have the server also return + all of the posts' comments in the same request: + + ```app/routes/posts.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model() { + return this.store.findAll('post', { include: 'comments' }); + } + }); + + ``` + Multiple relationships can be requested using an `include` parameter consisting of a + comma-separated list (without white-space) while nested relationships can be specified + using a dot-separated sequence of relationship names. So to request both the posts' + comments and the authors of those comments the request would look like this: + + ```app/routes/posts.js + import Ember from 'ember'; + + export default Ember.Route.extend({ + model() { + return this.store.findAll('post', { include: 'comments,comments.author' }); + } + }); + + ``` + + See [query](#method_query) to only get a subset of records from the server. + + @since 1.13.0 + @method findAll + @param {String} modelName + @param {Object} options + @return {Promise} promise + */ + findAll(modelName, options) { + assert(`You need to pass a model name to the store's findAll method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let token = heimdall.start('store.findAll'); + let normalizedModelName = normalizeModelName(modelName); + let fetch = this._fetchAll(normalizedModelName, this.peekAll(normalizedModelName), options); + + instrument(() => { + fetch.finally(() => { heimdall.stop(token); }); + }); + + return fetch; + }, + + /** + @method _fetchAll + @private + @param {DS.Model} modelName + @param {DS.RecordArray} array + @return {Promise} promise + */ + _fetchAll(modelName, array, options = {}) { + let adapter = this.adapterFor(modelName); + let sinceToken = this._internalModelsFor(modelName).metadata.since; + + assert(`You tried to load all records but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to load all records but your adapter does not implement 'findAll'`, typeof adapter.findAll === 'function'); + + if (options.reload) { + set$1(array, 'isUpdating', true); + return promiseArray(_findAll(adapter, this, modelName, sinceToken, options)); + } + + let snapshotArray = array._createSnapshot(options); + + if (adapter.shouldReloadAll(this, snapshotArray)) { + set$1(array, 'isUpdating', true); + return promiseArray(_findAll(adapter, this, modelName, sinceToken, options)); + } + + if (options.backgroundReload === false) { + return promiseArray(Promise$1.resolve(array)); + } + + if (options.backgroundReload || adapter.shouldBackgroundReloadAll(this, snapshotArray)) { + set$1(array, 'isUpdating', true); + _findAll(adapter, this, modelName, sinceToken, options); + } + + return promiseArray(Promise$1.resolve(array)); + }, + + /** + @method _didUpdateAll + @param {String} modelName + @private + */ + _didUpdateAll(modelName) { + heimdall.increment(_didUpdateAll); + let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(modelName); + + set$1(liveRecordArray, 'isUpdating', false); + }, + + didUpdateAll(modelName) { + deprecate('didUpdateAll was documented as private and will be removed in the next version of Ember Data.'); + return this._didUpdateAll(modelName); + }, + + /** + This method returns a filtered array that contains all of the + known records for a given type in the store. + + Note that because it's just a filter, the result will contain any + locally created records of the type, however, it will not make a + request to the backend to retrieve additional records. If you + would like to request all the records from the backend please use + [store.findAll](#method_findAll). + + Also note that multiple calls to `peekAll` for a given type will always + return the same `RecordArray`. + + Example + + ```javascript + let localPosts = store.peekAll('post'); + ``` + + @since 1.13.0 + @method peekAll + @param {String} modelName + @return {DS.RecordArray} + */ + peekAll(modelName) { + heimdall.increment(peekAll); + assert(`You need to pass a model name to the store's peekAll method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(normalizedModelName); + + this.recordArrayManager.syncLiveRecordArray(liveRecordArray, normalizedModelName); + + return liveRecordArray; + }, + + /** + This method unloads all records in the store. + It schedules unloading to happen during the next run loop. + + Optionally you can pass a type which unload all records for a given type. + + ```javascript + store.unloadAll(); + store.unloadAll('post'); + ``` + + @method unloadAll + @param {String} modelName + */ + unloadAll(modelName) { + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, !modelName || typeof modelName === 'string'); + + if (arguments.length === 0) { + this._identityMap.clear(); + } else { + let normalizedModelName = normalizeModelName(modelName); + this._internalModelsFor(normalizedModelName).clear(); + } + }, + + /** + Takes a type and filter function, and returns a live RecordArray that + remains up to date as new records are loaded into the store or created + locally. + + The filter function takes a materialized record, and returns true + if the record should be included in the filter and false if it should + not. + + Example + + ```javascript + store.filter('post', function(post) { + return post.get('unread'); + }); + ``` + + The filter function is called once on all records for the type when + it is created, and then once on each newly loaded or created record. + + If any of a record's properties change, or if it changes state, the + filter function will be invoked again to determine whether it should + still be in the array. + + Optionally you can pass a query, which is the equivalent of calling + [query](#method_query) with that same query, to fetch additional records + from the server. The results returned by the server could then appear + in the filter if they match the filter function. + + The query itself is not used to filter records, it's only sent to your + server for you to be able to do server-side filtering. The filter + function will be applied on the returned results regardless. + + Example + + ```javascript + store.filter('post', { unread: true }, function(post) { + return post.get('unread'); + }).then(function(unreadPosts) { + unreadPosts.get('length'); // 5 + let unreadPost = unreadPosts.objectAt(0); + unreadPost.set('unread', false); + unreadPosts.get('length'); // 4 + }); + ``` + + @method filter + @private + @param {String} modelName + @param {Object} query optional query + @param {Function} filter + @return {DS.PromiseArray} + @deprecated + */ + filter(modelName, query, filter) { + assert(`You need to pass a model name to the store's filter method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + if (!ENV.ENABLE_DS_FILTER) { + assert('The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', false); + } + + let promise; + let length = arguments.length; + let array; + let hasQuery = length === 3; + + let normalizedModelName = normalizeModelName(modelName); + + // allow an optional server query + if (hasQuery) { + promise = this.query(normalizedModelName, query); + } else if (arguments.length === 2) { + filter = query; + } + + if (hasQuery) { + array = this.recordArrayManager.createFilteredRecordArray(normalizedModelName, filter, query); + } else { + array = this.recordArrayManager.createFilteredRecordArray(normalizedModelName, filter); + } + + promise = promise || Promise$1.resolve(array); + + return promiseArray(promise.then(() => array, null, `DS: Store#filter of ${normalizedModelName}`)); + }, + + /** + This method has been deprecated and is an alias for store.hasRecordForId, which should + be used instead. + + @deprecated + @method recordIsLoaded + @param {String} modelName + @param {string} id + @return {boolean} + */ + recordIsLoaded(modelName, id) { + deprecate(`Use of recordIsLoaded is deprecated, use hasRecordForId instead.`, false, { + id: 'ds.store.recordIsLoaded', + until: '3.0' + }); + return this.hasRecordForId(modelName, id); + }, + + + // .............. + // . PERSISTING . + // .............. + + /** + This method is called by `record.save`, and gets passed a + resolver for the promise that `record.save` returns. + + It schedules saving to happen at the end of the run loop. + + @method scheduleSave + @private + @param {InternalModel} internalModel + @param {Resolver} resolver + @param {Object} options + */ + scheduleSave(internalModel, resolver, options) { + let snapshot = internalModel.createSnapshot(options); + internalModel.flushChangedAttributes(); + internalModel.adapterWillCommit(); + this._pendingSave.push({ + snapshot: snapshot, + resolver: resolver + }); + emberRun.once(this, this.flushPendingSave); + }, + + /** + This method is called at the end of the run loop, and + flushes any records passed into `scheduleSave` + + @method flushPendingSave + @private + */ + flushPendingSave() { + let pending = this._pendingSave.slice(); + this._pendingSave = []; + + for (let i = 0, j = pending.length; i < j; i++) { + let pendingItem = pending[i]; + let snapshot = pendingItem.snapshot; + let resolver = pendingItem.resolver; + let internalModel = snapshot._internalModel; + let adapter = this.adapterFor(internalModel.modelName); + let operation; + + if (internalModel.currentState.stateName === 'root.deleted.saved') { + return resolver.resolve(); + } else if (internalModel.isNew()) { + operation = 'createRecord'; + } else if (internalModel.isDeleted()) { + operation = 'deleteRecord'; + } else { + operation = 'updateRecord'; + } + + resolver.resolve(_commit(adapter, this, operation, snapshot)); + } + + }, + + /** + This method is called once the promise returned by an + adapter's `createRecord`, `updateRecord` or `deleteRecord` + is resolved. + + If the data provides a server-generated ID, it will + update the record and the store's indexes. + + @method didSaveRecord + @private + @param {InternalModel} internalModel the in-flight internal model + @param {Object} data optional data (see above) + */ + didSaveRecord(internalModel, dataArg) { + let data; + if (dataArg) { + data = dataArg.data; + } + if (data) { + // normalize relationship IDs into records + this.updateId(internalModel, data); + this._setupRelationshipsForModel(internalModel, data); + } else { + assert(`Your ${internalModel.modelName} record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, internalModel.id); + } + + //We first make sure the primary data has been updated + //TODO try to move notification to the user to the end of the runloop + internalModel.adapterDidCommit(data); + }, + + /** + This method is called once the promise returned by an + adapter's `createRecord`, `updateRecord` or `deleteRecord` + is rejected with a `DS.InvalidError`. + + @method recordWasInvalid + @private + @param {InternalModel} internalModel + @param {Object} errors + */ + recordWasInvalid(internalModel, errors) { + internalModel.adapterDidInvalidate(errors); + }, + + /** + This method is called once the promise returned by an + adapter's `createRecord`, `updateRecord` or `deleteRecord` + is rejected (with anything other than a `DS.InvalidError`). + + @method recordWasError + @private + @param {InternalModel} internalModel + @param {Error} error + */ + recordWasError(internalModel, error) { + internalModel.adapterDidError(error); + }, + + /** + When an adapter's `createRecord`, `updateRecord` or `deleteRecord` + resolves with data, this method extracts the ID from the supplied + data. + + @method updateId + @private + @param {InternalModel} internalModel + @param {Object} data + */ + updateId(internalModel, data) { + let oldId = internalModel.id; + let modelName = internalModel.modelName; + let id = coerceId(data.id); + + // ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record) + assert(`'${modelName}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null)); + + // ID absolutely can't be different than oldID if oldID is not null + assert(`'${modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, !(oldId !== null && id !== oldId)); + + // ID can be null if oldID is not null (altered ID in response for a record) + // however, this is more than likely a developer error. + if (oldId !== null && id === null) { + warn(`Your ${modelName} record was saved to the server, but the response does not have an id.`, !(oldId !== null && id === null)); + return; + } + + this._internalModelsFor(internalModel.modelName).set(id, internalModel); + + internalModel.setId(id); + }, + + /** + Returns a map of IDs to client IDs for a given modelName. + + @method _internalModelsFor + @private + @param {String} modelName + @return {Object} recordMap + */ + _internalModelsFor(modelName) { + heimdall.increment(_internalModelsFor); + return this._identityMap.retrieve(modelName); + }, + + // ................ + // . LOADING DATA . + // ................ + + /** + This internal method is used by `push`. + + @method _load + @private + @param {Object} data + */ + _load(data) { + heimdall.increment(_load); + let internalModel = this._internalModelForId(data.type, data.id); + + internalModel.setupData(data); + + this.recordArrayManager.recordDidChange(internalModel); + + return internalModel; + }, + + /* + In case someone defined a relationship to a mixin, for example: + ``` + let Comment = DS.Model.extend({ + owner: belongsTo('commentable'. { polymorphic: true }) + }); + let Commentable = Ember.Mixin.create({ + comments: hasMany('comment') + }); + ``` + we want to look up a Commentable class which has all the necessary + relationship metadata. Thus, we look up the mixin and create a mock + DS.Model, so we can access the relationship CPs of the mixin (`comments`) + in this case + + @private + */ + _modelForMixin(normalizedModelName) { + heimdall.increment(_modelForMixin); + // container.registry = 2.1 + // container._registry = 1.11 - 2.0 + // container = < 1.11 + let owner = getOwner(this); + let mixin; + + if (owner.factoryFor) { + let MaybeMixin = owner.factoryFor(`mixin:${normalizedModelName}`); + mixin = MaybeMixin && MaybeMixin.class; + } else { + mixin = owner._lookupFactory(`mixin:${normalizedModelName}`); + } + + if (mixin) { + let ModelForMixin = Model.extend(mixin); + ModelForMixin.reopenClass({ + __isMixin: true, + __mixin: mixin + }); + + //Cache the class as a model + owner.register('model:' + normalizedModelName, ModelForMixin); + } + + return this.modelFactoryFor(normalizedModelName); + }, + + /** + Returns the model class for the particular `modelName`. + + The class of a model might be useful if you want to get a list of all the + relationship names of the model, see + [`relationshipNames`](http://emberjs.com/api/data/classes/DS.Model.html#property_relationshipNames) + for example. + + @method modelFor + @param {String} modelName + @return {DS.Model} + */ + modelFor(modelName) { + assert(`You need to pass a model name to the store's modelFor method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let normalizedModelName = normalizeModelName(modelName); + + return this._modelFor(normalizedModelName); + }, + + /* + @private + */ + _modelFor(modelName) { + let maybeFactory = this._modelFactoryFor(modelName); + // for factorFor factory/class split + return maybeFactory.class ? maybeFactory.class : maybeFactory; + }, + + _modelFactoryFor(modelName) { + heimdall.increment(modelFor); + let factory = this._modelFactoryCache[modelName]; + + if (!factory) { + factory = this.modelFactoryFor(modelName); + + if (!factory) { + //Support looking up mixins as base types for polymorphic relationships + factory = this._modelForMixin(modelName); + } + if (!factory) { + throw new EmberError(`No model was found for '${modelName}'`); + } + + // interopt with the future + let klass = getOwner(this).factoryFor ? factory.class : factory; + + assert(`'${inspect(klass)}' does not appear to be an ember-data model`, klass.isModel); + + // TODO: deprecate this + klass.modelName = klass.modelName || modelName; + + this._modelFactoryCache[modelName] = factory; + } + + return factory; + }, + + /* + @private + */ + modelFactoryFor(modelName) { + heimdall.increment(modelFactoryFor); + assert(`You need to pass a model name to the store's modelFactoryFor method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let normalizedModelName = normalizeModelName(modelName); + let owner = getOwner(this); + + if (owner.factoryFor) { + return owner.factoryFor(`model:${normalizedModelName}`); + } else { + return owner._lookupFactory(`model:${normalizedModelName}`); + } + }, + + /** + Push some data for a given type into the store. + + This method expects normalized [JSON API](http://jsonapi.org/) document. This means you have to follow [JSON API specification](http://jsonapi.org/format/) with few minor adjustments: + - record's `type` should always be in singular, dasherized form + - members (properties) should be camelCased + + [Your primary data should be wrapped inside `data` property](http://jsonapi.org/format/#document-top-level): + + ```js + store.push({ + data: { + // primary data for single record of type `Person` + id: '1', + type: 'person', + attributes: { + firstName: 'Daniel', + lastName: 'Kmak' + } + } + }); + ``` + + [Demo.](http://ember-twiddle.com/fb99f18cd3b4d3e2a4c7) + + `data` property can also hold an array (of records): + + ```js + store.push({ + data: [ + // an array of records + { + id: '1', + type: 'person', + attributes: { + firstName: 'Daniel', + lastName: 'Kmak' + } + }, + { + id: '2', + type: 'person', + attributes: { + firstName: 'Tom', + lastName: 'Dale' + } + } + ] + }); + ``` + + [Demo.](http://ember-twiddle.com/69cdbeaa3702159dc355) + + There are some typical properties for `JSONAPI` payload: + * `id` - mandatory, unique record's key + * `type` - mandatory string which matches `model`'s dasherized name in singular form + * `attributes` - object which holds data for record attributes - `DS.attr`'s declared in model + * `relationships` - object which must contain any of the following properties under each relationships' respective key (example path is `relationships.achievements.data`): + - [`links`](http://jsonapi.org/format/#document-links) + - [`data`](http://jsonapi.org/format/#document-resource-object-linkage) - place for primary data + - [`meta`](http://jsonapi.org/format/#document-meta) - object which contains meta-information about relationship + + For this model: + + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + + children: DS.hasMany('person') + }); + ``` + + To represent the children as IDs: + + ```js + { + data: { + id: '1', + type: 'person', + attributes: { + firstName: 'Tom', + lastName: 'Dale' + }, + relationships: { + children: { + data: [ + { + id: '2', + type: 'person' + }, + { + id: '3', + type: 'person' + }, + { + id: '4', + type: 'person' + } + ] + } + } + } + } + ``` + + [Demo.](http://ember-twiddle.com/343e1735e034091f5bde) + + To represent the children relationship as a URL: + + ```js + { + data: { + id: '1', + type: 'person', + attributes: { + firstName: 'Tom', + lastName: 'Dale' + }, + relationships: { + children: { + links: { + related: '/people/1/children' + } + } + } + } + } + ``` + + If you're streaming data or implementing an adapter, make sure + that you have converted the incoming data into this form. The + store's [normalize](#method_normalize) method is a convenience + helper for converting a json payload into the form Ember Data + expects. + + ```js + store.push(store.normalize('person', data)); + ``` + + This method can be used both to push in brand new + records, as well as to update existing records. + + @method push + @param {Object} data + @return {DS.Model|Array} the record(s) that was created or + updated. + */ + push(data) { + let token = heimdall.start('store.push'); + let pushed = this._push(data); + + if (Array.isArray(pushed)) { + let records = pushed.map(internalModel => internalModel.getRecord()); + heimdall.stop(token); + return records; + } + + if (pushed === null) { + heimdall.stop(token); + return null; + } + + let record = pushed.getRecord(); + heimdall.stop(token); + return record; + }, + + /* + Push some data in the form of a json-api document into the store, + without creating materialized records. + + @method _push + @private + @param {Object} jsonApiDoc + @return {DS.InternalModel|Array} pushed InternalModel(s) + */ + _push(jsonApiDoc) { + let token = heimdall.start('store._push'); + let internalModelOrModels = this._backburner.join(() => { + let included = jsonApiDoc.included; + let i, length; + + if (included) { + for (i = 0, length = included.length; i < length; i++) { + this._pushInternalModel(included[i]); + } + } + + if (Array.isArray(jsonApiDoc.data)) { + length = jsonApiDoc.data.length; + let internalModels = new Array(length); + + for (i = 0; i < length; i++) { + internalModels[i] = this._pushInternalModel(jsonApiDoc.data[i]); + } + return internalModels; + } + + if (jsonApiDoc.data === null) { + return null; + } + + assert(`Expected an object in the 'data' property in a call to 'push' for ${jsonApiDoc.type}, but was ${typeOf(jsonApiDoc.data)}`, typeOf(jsonApiDoc.data) === 'object'); + + return this._pushInternalModel(jsonApiDoc.data); + }); + heimdall.stop(token); + return internalModelOrModels; + }, + + _hasModelFor(modelName) { + let owner = getOwner(this); + modelName = normalizeModelName(modelName); + + if (owner.factoryFor) { + return !!owner.factoryFor(`model:${modelName}`); + } else { + return !!owner._lookupFactory(`model:${modelName}`); + } + }, + + _pushInternalModel(data) { + heimdall.increment(_pushInternalModel); + let modelName = data.type; + assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id !== null && data.id !== undefined && data.id !== ''); + assert(`You tried to push data with a type '${modelName}' but no model could be found with that name.`, this._hasModelFor(modelName)); + + runInDebug(() => { + // If ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload + // contains unknown attributes or relationships, log a warning. + + if (ENV.DS_WARN_ON_UNKNOWN_KEYS) { + let modelClass = this._modelFor(modelName); + + // Check unknown attributes + let unknownAttributes = Object.keys(data.attributes || {}).filter((key) => { + return !get$3(modelClass, 'fields').has(key); + }); + let unknownAttributesMessage = `The payload for '${modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`; + warn(unknownAttributesMessage, unknownAttributes.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); + + // Check unknown relationships + let unknownRelationships = Object.keys(data.relationships || {}).filter((key) => { + return !get$3(modelClass, 'fields').has(key); + }); + let unknownRelationshipsMessage = `The payload for '${modelName}' contains these unknown relationships: ${unknownRelationships}. Make sure they've been defined in your model.`; + warn(unknownRelationshipsMessage, unknownRelationships.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); + } + }); + + // Actually load the record into the store. + let internalModel = this._load(data); + + this._setupRelationshipsForModel(internalModel, data); + + return internalModel; + }, + + _setupRelationshipsForModel(internalModel, data) { + if (data.relationships === undefined) { + return; + } + + if (this._pushedInternalModels.push(internalModel, data) !== 2) { + return; + } + + this._backburner.schedule('normalizeRelationships', this, this._setupRelationships); + }, + + _setupRelationships() { + heimdall.increment(_setupRelationships); + let setupToken = heimdall.start('store._setupRelationships'); + let pushed = this._pushedInternalModels; + + // Cache the inverse maps for each modelClass that we visit during this + // payload push. In the common case where we are pushing many more + // instances than types we want to minimize the cost of looking up the + // inverse map and the overhead of Ember.get adds up. + let modelNameToInverseMap = Object.create(null); + + for (let i = 0, l = pushed.length; i < l; i += 2) { + // This will convert relationships specified as IDs into DS.Model instances + // (possibly unloaded) and also create the data structures used to track + // relationships. + let internalModel = pushed[i]; + let data = pushed[i + 1]; + setupRelationships(this, internalModel, data, modelNameToInverseMap); + } + + pushed.length = 0; + heimdall.stop(setupToken); + }, + + /** + Push some raw data into the store. + + This method can be used both to push in brand new + records, as well as to update existing records. You + can push in more than one type of object at once. + All objects should be in the format expected by the + serializer. + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.ActiveModelSerializer; + ``` + + ```js + let pushData = { + posts: [ + { id: 1, post_title: "Great post", comment_ids: [2] } + ], + comments: [ + { id: 2, comment_body: "Insightful comment" } + ] + } + + store.pushPayload(pushData); + ``` + + By default, the data will be deserialized using a default + serializer (the application serializer if it exists). + + Alternatively, `pushPayload` will accept a model type which + will determine which serializer will process the payload. + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.ActiveModelSerializer; + ``` + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer; + ``` + + ```js + store.pushPayload('comment', pushData); // Will use the application serializer + store.pushPayload('post', pushData); // Will use the post serializer + ``` + + @method pushPayload + @param {String} modelName Optionally, a model type used to determine which serializer will be used + @param {Object} inputPayload + */ + pushPayload(modelName, inputPayload) { + let serializer; + let payload; + if (!inputPayload) { + payload = modelName; + serializer = defaultSerializer(this); + assert(`You cannot use 'store#pushPayload' without a modelName unless your default serializer defines 'pushPayload'`, typeof serializer.pushPayload === 'function'); + } else { + payload = inputPayload; + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + serializer = this.serializerFor(normalizedModelName); + } + if (isEnabled('ds-pushpayload-return')) { + return serializer.pushPayload(this, payload); + } else { + serializer.pushPayload(this, payload); + } + }, + + /** + `normalize` converts a json payload into the normalized form that + [push](#method_push) expects. + + Example + + ```js + socket.on('message', function(message) { + let modelName = message.model; + let data = message.data; + store.push(store.normalize(modelName, data)); + }); + ``` + + @method normalize + @param {String} modelName The name of the model type for this payload + @param {Object} payload + @return {Object} The normalized payload + */ + normalize(modelName, payload) { + heimdall.increment(normalize); + assert(`You need to pass a model name to the store's normalize method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + let serializer = this.serializerFor(normalizedModelName); + let model = this._modelFor(normalizedModelName); + return serializer.normalize(model, payload); + }, + + /** + Build a brand new record for a given type, ID, and + initial data. + + @method _buildInternalModel + @private + @param {String} modelName + @param {String} id + @param {Object} data + @return {InternalModel} internal model + */ + _buildInternalModel(modelName, id, data) { + heimdall.increment(_buildInternalModel); + + assert(`You can no longer pass a modelClass as the first argument to store._buildInternalModel. Pass modelName instead.`, typeof modelName === 'string'); + + let recordMap = this._internalModelsFor(modelName); + + assert(`The id ${id} has already been used with another record for modelClass '${modelName}'.`, !id || !recordMap.get(id)); + + // lookupFactory should really return an object that creates + // instances with the injections applied + let internalModel = new InternalModel(modelName, id, this, data); + + recordMap.add(internalModel, id); + + return internalModel; + }, + + buildInternalModel(modelName, id, data) { + deprecate('buildInternalModel was documented as private and will be removed in the next version of Ember Data.'); + return this._buildInternalModel(modelName, id, data); + }, + + //Called by the state machine to notify the store that the record is ready to be interacted with + recordWasLoaded(record) { + this.recordArrayManager.recordWasLoaded(record); + }, + + // ............... + // . DESTRUCTION . + // ............... + + /** + When a record is destroyed, this un-indexes it and + removes it from any record arrays so it can be GCed. + + @method _removeFromIdMap + @private + @param {InternalModel} internalModel + */ + _removeFromIdMap(internalModel) { + let recordMap = this._internalModelsFor(internalModel.modelName); + let id = internalModel.id; + + recordMap.remove(internalModel, id); + }, + + // ...................... + // . PER-TYPE ADAPTERS + // ...................... + + /** + Returns an instance of the adapter for a given type. For + example, `adapterFor('person')` will return an instance of + `App.PersonAdapter`. + + If no `App.PersonAdapter` is found, this method will look + for an `App.ApplicationAdapter` (the default adapter for + your entire application). + + If no `App.ApplicationAdapter` is found, it will return + the value of the `defaultAdapter`. + + @method adapterFor + @public + @param {String} modelName + @return DS.Adapter + */ + adapterFor(modelName) { + heimdall.increment(adapterFor); + assert(`You need to pass a model name to the store's adapterFor method`, isPresent(modelName)); + assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + + return this._instanceCache.get('adapter', normalizedModelName); + }, + + // .............................. + // . RECORD CHANGE NOTIFICATION . + // .............................. + + /** + Returns an instance of the serializer for a given type. For + example, `serializerFor('person')` will return an instance of + `App.PersonSerializer`. + + If no `App.PersonSerializer` is found, this method will look + for an `App.ApplicationSerializer` (the default serializer for + your entire application). + + if no `App.ApplicationSerializer` is found, it will attempt + to get the `defaultSerializer` from the `PersonAdapter` + (`adapterFor('person')`). + + If a serializer cannot be found on the adapter, it will fall back + to an instance of `DS.JSONSerializer`. + + @method serializerFor + @public + @param {String} modelName the record to serialize + @return {DS.Serializer} + */ + serializerFor(modelName) { + heimdall.increment(serializerFor); + assert(`You need to pass a model name to the store's serializerFor method`, isPresent(modelName)); + assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + + return this._instanceCache.get('serializer', normalizedModelName); + }, + + lookupAdapter(name) { + deprecate(`Use of lookupAdapter is deprecated, use adapterFor instead.`, false, { + id: 'ds.store.lookupAdapter', + until: '3.0' + }); + return this.adapterFor(name); + }, + + lookupSerializer(name) { + deprecate(`Use of lookupSerializer is deprecated, use serializerFor instead.`, false, { + id: 'ds.store.lookupSerializer', + until: '3.0' + }); + return this.serializerFor(name); + }, + + willDestroy() { + this._super(...arguments); + this._pushedInternalModels = null; + this.recordArrayManager.destroy(); + this._instanceCache.destroy(); + + this.unloadAll(); + }, + + _updateRelationshipState(relationship) { + if (this._updatedRelationships.push(relationship) !== 1) { + return; + } + + this._backburner.join(() => { + this._backburner.schedule('syncRelationships', this, this._flushUpdatedRelationships); + }); + }, + + _flushUpdatedRelationships() { + let updated = this._updatedRelationships; + + for (let i = 0, l = updated.length; i < l; i++) { + updated[i].flushCanonical(); + } + + updated.length = 0; + }, + + _updateInternalModel(internalModel) { + if (this._updatedInternalModels.push(internalModel) !== 1) { + return; + } + + emberRun.schedule('actions', this, this._flushUpdatedInternalModels); + }, + + _flushUpdatedInternalModels() { + let updated = this._updatedInternalModels; + + for (let i = 0, l = updated.length; i < l; i++) { + updated[i]._triggerDeferredTriggers(); + } + + updated.length = 0; + }, + + _pushResourceIdentifier(relationship, resourceIdentifier) { + if (isNone(resourceIdentifier)) { + return; + } + + assert(`A ${relationship.internalModel.modelName} record was pushed into the store with the value of ${relationship.key} being ${inspect(resourceIdentifier)}, but ${relationship.key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(resourceIdentifier)); + + //TODO:Better asserts + return this._internalModelForId(resourceIdentifier.type, resourceIdentifier.id); + }, + + _pushResourceIdentifiers(relationship, resourceIdentifiers) { + if (isNone(resourceIdentifiers)) { + return; + } + + assert(`A ${relationship.internalModel.modelName} record was pushed into the store with the value of ${relationship.key} being '${inspect(resourceIdentifiers)}', but ${relationship.key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(resourceIdentifiers)); + + let _internalModels = new Array(resourceIdentifiers.length); + for (let i = 0; i < resourceIdentifiers.length; i++) { + _internalModels[i] = this._pushResourceIdentifier(relationship, resourceIdentifiers[i]); + } + return _internalModels; + } +}); + +// Delegation to the adapter and promise management + + + +function defaultSerializer(store) { + return store.serializerFor('application'); +} + +function _commit(adapter, store, operation, snapshot) { + let internalModel = snapshot._internalModel; + let modelName = snapshot.modelName; + let modelClass = store._modelFor(modelName); + assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`, typeof adapter[operation] === 'function'); + let promise = adapter[operation](store, modelClass, snapshot); + let serializer = serializerForAdapter(store, adapter, modelName); + let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; + + assert(`Your adapter's '${operation}' method must return a value, but it returned 'undefined'`, promise !==undefined); + + promise = Promise$1.resolve(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); + promise = _guard(promise, _bind(_objectIsAlive, internalModel)); + + return promise.then((adapterPayload) => { + /* + Note to future spelunkers hoping to optimize. + We rely on this `run` to create a run loop if needed + that `store._push` and `store.didSaveRecord` will both share. + + We use `join` because it is often the case that we + have an outer run loop available still from the first + call to `store._push`; + */ + store._backburner.join(() => { + let payload, data; + if (adapterPayload) { + payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, snapshot.id, operation); + if (payload.included) { + store._push({ data: null, included: payload.included }); + } + data = payload.data; + } + store.didSaveRecord(internalModel, { data }); + }); + + return internalModel; + }, function(error) { + if (error instanceof InvalidError) { + let errors = serializer.extractErrors(store, modelClass, error, snapshot.id); + + store.recordWasInvalid(internalModel, errors); + } else { + store.recordWasError(internalModel, error); + } + + throw error; + }, label); +} + +function isInverseRelationshipInitialized(store, internalModel, data, key, modelNameToInverseMap) { + let relationshipData = data.relationships[key].data; + + if (!relationshipData) { + // can't check inverse for eg { comments: { links: { related: URL }}} + return false; + } + + let inverseMap = modelNameToInverseMap[internalModel.modelName]; + if (!inverseMap) { + inverseMap = modelNameToInverseMap[internalModel.modelName] = get$3(internalModel.type, 'inverseMap'); + } + let inverseRelationshipMetadata = inverseMap[key]; + if (inverseRelationshipMetadata === undefined) { + inverseRelationshipMetadata = internalModel.type.inverseFor(key, store); + } + + if (!inverseRelationshipMetadata) { + return false; + } + + let { name: inverseRelationshipName } = inverseRelationshipMetadata; + + if (Array.isArray(relationshipData)) { + for (let i=0; i { + if (!data.relationships[relationshipName]) { + return; + } + + let relationshipRequiresNotification = relationships.has(relationshipName) || + isInverseRelationshipInitialized(store, internalModel, data, relationshipName, modelNameToInverseMap); + + if (relationshipRequiresNotification) { + let relationshipData = data.relationships[relationshipName]; + relationships.get(relationshipName).push(relationshipData); + } + + // in debug, assert payload validity eagerly + runInDebug(() => { + let relationshipMeta = get$3(internalModel.type, 'relationshipsByName').get(relationshipName); + let relationshipData = data.relationships[relationshipName]; + if (!relationshipData || !relationshipMeta) { + return; + } + + if (relationshipData.links) { + let isAsync = relationshipMeta.options && relationshipMeta.options.async !== false; + warn(`You pushed a record of type '${internalModel.type.modelName}' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, isAsync || relationshipData.data , { + id: 'ds.store.push-link-for-sync-relationship' + }); + } else if (relationshipData.data) { + if (relationshipMeta.kind === 'belongsTo') { + assert(`A ${internalModel.type.modelName} record was pushed into the store with the value of ${relationshipName} being ${inspect(relationshipData.data)}, but ${relationshipName} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(relationshipData.data)); + } else if (relationshipMeta.kind === 'hasMany') { + assert(`A ${internalModel.type.modelName} record was pushed into the store with the value of ${relationshipName} being '${inspect(relationshipData.data)}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(relationshipData.data)); + } + } + }); + }); +} + +var Store$1 = Store; + +/** + @module ember-data +*/ + +/** + All Ember Data classes, methods and functions are defined inside of this namespace. + + @class DS + @static +*/ + +/** + @property VERSION + @type String + @static +*/ +const DS = Ember.Namespace.create({ + VERSION: VERSION, + name: "DS" +}); + +if (Ember.libraries) { + Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); +} + +/** + `DS.belongsTo` is used to define One-To-One and One-To-Many + relationships on a [DS.Model](/api/data/classes/DS.Model.html). + + + `DS.belongsTo` takes an optional hash as a second parameter, currently + supported options are: + + - `async`: A boolean value used to explicitly declare this to be an async relationship. + - `inverse`: A string used to identify the inverse property on a + related model in a One-To-Many relationship. See [Explicit Inverses](#toc_explicit-inverses) + + #### One-To-One + To declare a one-to-one relationship between two models, use + `DS.belongsTo`: + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + profile: DS.belongsTo('profile') + }); + ``` + + ```app/models/profile.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + user: DS.belongsTo('user') + }); + ``` + + #### One-To-Many + To declare a one-to-many relationship between two models, use + `DS.belongsTo` in combination with `DS.hasMany`, like this: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + comments: DS.hasMany('comment') + }); + ``` + + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + post: DS.belongsTo('post') + }); + ``` + + You can avoid passing a string as the first parameter. In that case Ember Data + will infer the type from the key name. + + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + post: DS.belongsTo() + }); + ``` + + will lookup for a Post type. + + @namespace + @method belongsTo + @for DS + @param {String} modelName (optional) type of the relationship + @param {Object} options (optional) a hash of options + @return {Ember.computed} relationship +*/ +function belongsTo(modelName, options) { + let opts, userEnteredModelName; + if (typeof modelName === 'object') { + opts = modelName; + userEnteredModelName = undefined; + } else { + opts = options; + userEnteredModelName = modelName; + } + + if (typeof userEnteredModelName === 'string') { + userEnteredModelName = normalizeModelName(userEnteredModelName); + } + + assert("The first argument to DS.belongsTo must be a string representing a model type key, not an instance of " + Ember.inspect(userEnteredModelName) + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", typeof userEnteredModelName === 'string' || typeof userEnteredModelName === 'undefined'); + + opts = opts || {}; + + let meta = { + type: userEnteredModelName, + isRelationship: true, + options: opts, + kind: 'belongsTo', + name: 'Belongs To', + key: null + }; + + return Ember.computed({ + get(key) { + if (opts.hasOwnProperty('serialize')) { + warn(`You provided a serialize option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.Serializer and it's implementations http://emberjs.com/api/data/classes/DS.Serializer.html`, false, { + id: 'ds.model.serialize-option-in-belongs-to' + }); + } + + if (opts.hasOwnProperty('embedded')) { + warn(`You provided an embedded option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html`, false, { + id: 'ds.model.embedded-option-in-belongs-to' + }); + } + + return this._internalModel._relationships.get(key).getRecord(); + }, + set(key, value) { + if (value === undefined) { + value = null; + } + if (value && value.then) { + this._internalModel._relationships.get(key).setRecordPromise(value); + } else if (value) { + this._internalModel._relationships.get(key).setInternalModel(value._internalModel); + } else { + this._internalModel._relationships.get(key).setInternalModel(value); + } + + return this._internalModel._relationships.get(key).getRecord(); + } + }).meta(meta); +} + +/* + We're using this to detect arrays and "array-like" objects. + + This is a copy of the `isArray` method found in `ember-runtime/utils` as we're + currently unable to import non-exposed modules. + + This method was previously exposed as `Ember.isArray` but since + https://github.com/emberjs/ember.js/pull/11463 `Ember.isArray` is an alias of + `Array.isArray` hence removing the "array-like" part. + */ +function isArrayLike(obj) { + if (!obj || obj.setInterval) { return false; } + if (Array.isArray(obj)) { return true; } + if (Ember.Array.detect(obj)) { return true; } + + let type = Ember.typeOf(obj); + if ('array' === type) { return true; } + if ((obj.length !== undefined) && 'object' === type) { return true; } + return false; +} + +/** + @module ember-data +*/ + +const { get: get$16 } = Ember; + +/** + `DS.hasMany` is used to define One-To-Many and Many-To-Many + relationships on a [DS.Model](/api/data/classes/DS.Model.html). + + `DS.hasMany` takes an optional hash as a second parameter, currently + supported options are: + + - `async`: A boolean value used to explicitly declare this to be an async relationship. + - `inverse`: A string used to identify the inverse property on a related model. + + #### One-To-Many + To declare a one-to-many relationship between two models, use + `DS.belongsTo` in combination with `DS.hasMany`, like this: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + comments: DS.hasMany('comment') + }); + ``` + + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + post: DS.belongsTo('post') + }); + ``` + + #### Many-To-Many + To declare a many-to-many relationship between two models, use + `DS.hasMany`: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + tags: DS.hasMany('tag') + }); + ``` + + ```app/models/tag.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + posts: DS.hasMany('post') + }); + ``` + + You can avoid passing a string as the first parameter. In that case Ember Data + will infer the type from the singularized key name. + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + tags: DS.hasMany() + }); + ``` + + will lookup for a Tag type. + + #### Explicit Inverses + + Ember Data will do its best to discover which relationships map to + one another. In the one-to-many code above, for example, Ember Data + can figure out that changing the `comments` relationship should update + the `post` relationship on the inverse because post is the only + relationship to that model. + + However, sometimes you may have multiple `belongsTo`/`hasMany` for the + same type. You can specify which property on the related model is + the inverse using `DS.hasMany`'s `inverse` option: + + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + onePost: DS.belongsTo('post'), + twoPost: DS.belongsTo('post'), + redPost: DS.belongsTo('post'), + bluePost: DS.belongsTo('post') + }); + ``` + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + comments: DS.hasMany('comment', { + inverse: 'redPost' + }) + }); + ``` + + You can also specify an inverse on a `belongsTo`, which works how + you'd expect. + + @namespace + @method hasMany + @for DS + @param {String} type (optional) type of the relationship + @param {Object} options (optional) a hash of options + @return {Ember.computed} relationship +*/ +function hasMany(type, options) { + if (typeof type === 'object') { + options = type; + type = undefined; + } + + assert(`The first argument to DS.hasMany must be a string representing a model type key, not an instance of ${Ember.inspect(type)}. E.g., to define a relation to the Comment model, use DS.hasMany('comment')`, typeof type === 'string' || typeof type === 'undefined'); + + options = options || {}; + + if (typeof type === 'string') { + type = normalizeModelName(type); + } + + // Metadata about relationships is stored on the meta of + // the relationship. This is used for introspection and + // serialization. Note that `key` is populated lazily + // the first time the CP is called. + let meta = { + type, + options, + isRelationship: true, + kind: 'hasMany', + name: 'Has Many', + key: null + }; + + return Ember.computed({ + get(key) { + return this._internalModel._relationships.get(key).getRecords(); + }, + set(key, records) { + assert(`You must pass an array of records to set a hasMany relationship`, isArrayLike(records)); + assert(`All elements of a hasMany relationship must be instances of DS.Model, you passed ${Ember.inspect(records)}`, (function() { + return Ember.A(records).every((record) => record.hasOwnProperty('_internalModel') === true); + })()); + + let relationship = this._internalModel._relationships.get(key); + relationship.clear(); + relationship.addInternalModels(records.map(record => get$16(record, '_internalModel'))); + return relationship.getRecords(); + } + }).meta(meta); +} + +const get$17 = Ember.get; + +/** + + WARNING: This interface is likely to change in order to accomodate https://github.com/emberjs/rfcs/pull/4 + + ## Using BuildURLMixin + + To use url building, include the mixin when extending an adapter, and call `buildURL` where needed. + The default behaviour is designed for RESTAdapter. + + ### Example + + ```javascript + export default DS.Adapter.extend(BuildURLMixin, { + findRecord: function(store, type, id, snapshot) { + var url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); + return this.ajax(url, 'GET'); + } + }); + ``` + + ### Attributes + + The `host` and `namespace` attributes will be used if defined, and are optional. + + @class BuildURLMixin + @namespace DS +*/ +var buildUrlMixin = Ember.Mixin.create({ + /** + Builds a URL for a given type and optional ID. + + By default, it pluralizes the type's name (for example, 'post' + becomes 'posts' and 'person' becomes 'people'). To override the + pluralization see [pathForType](#method_pathForType). + + If an ID is specified, it adds the ID to the path generated + for the type, separated by a `/`. + + When called by RESTAdapter.findMany() the `id` and `snapshot` parameters + will be arrays of ids and snapshots. + + @method buildURL + @param {String} modelName + @param {(String|Array|Object)} id single id or array of ids or query + @param {(DS.Snapshot|Array)} snapshot single snapshot or array of snapshots + @param {String} requestType + @param {Object} query object of query parameters to send for query requests. + @return {String} url + */ + buildURL(modelName, id, snapshot, requestType, query) { + switch (requestType) { + case 'findRecord': + return this.urlForFindRecord(id, modelName, snapshot); + case 'findAll': + return this.urlForFindAll(modelName, snapshot); + case 'query': + return this.urlForQuery(query, modelName); + case 'queryRecord': + return this.urlForQueryRecord(query, modelName); + case 'findMany': + return this.urlForFindMany(id, modelName, snapshot); + case 'findHasMany': + return this.urlForFindHasMany(id, modelName, snapshot); + case 'findBelongsTo': + return this.urlForFindBelongsTo(id, modelName, snapshot); + case 'createRecord': + return this.urlForCreateRecord(modelName, snapshot); + case 'updateRecord': + return this.urlForUpdateRecord(id, modelName, snapshot); + case 'deleteRecord': + return this.urlForDeleteRecord(id, modelName, snapshot); + default: + return this._buildURL(modelName, id); + } + }, + + /** + @method _buildURL + @private + @param {String} modelName + @param {String} id + @return {String} url + */ + _buildURL(modelName, id) { + let path; + let url = []; + let host = get$17(this, 'host'); + let prefix = this.urlPrefix(); + + if (modelName) { + path = this.pathForType(modelName); + if (path) { url.push(path); } + } + + if (id) { url.push(encodeURIComponent(id)); } + if (prefix) { url.unshift(prefix); } + + url = url.join('/'); + if (!host && url && url.charAt(0) !== '/') { + url = '/' + url; + } + + return url; + }, + + /** + Builds a URL for a `store.findRecord(type, id)` call. + + Example: + + ```app/adapters/user.js + import DS from 'ember-data'; + + export default DS.JSONAPIAdapter.extend({ + urlForFindRecord(id, modelName, snapshot) { + let baseUrl = this.buildURL(); + return `${baseUrl}/users/${snapshot.adapterOptions.user_id}/playlists/${id}`; + } + }); + ``` + + @method urlForFindRecord + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url + + */ + urlForFindRecord(id, modelName, snapshot) { + return this._buildURL(modelName, id); + }, + + /** + Builds a URL for a `store.findAll(type)` call. + + Example: + + ```app/adapters/comment.js + import DS from 'ember-data'; + + export default DS.JSONAPIAdapter.extend({ + urlForFindAll(modelName, snapshot) { + return 'data/comments.json'; + } + }); + ``` + + @method urlForFindAll + @param {String} modelName + @param {DS.SnapshotRecordArray} snapshot + @return {String} url + */ + urlForFindAll(modelName, snapshot) { + return this._buildURL(modelName); + }, + + /** + Builds a URL for a `store.query(type, query)` call. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + host: 'https://api.github.com', + urlForQuery (query, modelName) { + switch(modelName) { + case 'repo': + return `https://api.github.com/orgs/${query.orgId}/repos`; + default: + return this._super(...arguments); + } + } + }); + ``` + + @method urlForQuery + @param {Object} query + @param {String} modelName + @return {String} url + */ + urlForQuery(query, modelName) { + return this._buildURL(modelName); + }, + + /** + Builds a URL for a `store.queryRecord(type, query)` call. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForQueryRecord({ slug }, modelName) { + let baseUrl = this.buildURL(); + return `${baseUrl}/${encodeURIComponent(slug)}`; + } + }); + ``` + + @method urlForQueryRecord + @param {Object} query + @param {String} modelName + @return {String} url + */ + urlForQueryRecord(query, modelName) { + return this._buildURL(modelName); + }, + + /** + Builds a URL for coalesceing multiple `store.findRecord(type, id) + records into 1 request when the adapter's `coalesceFindRequests` + property is true. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForFindMany(ids, modelName) { + let baseUrl = this.buildURL(); + return `${baseUrl}/coalesce`; + } + }); + ``` + + @method urlForFindMany + @param {Array} ids + @param {String} modelName + @param {Array} snapshots + @return {String} url + */ + urlForFindMany(ids, modelName, snapshots) { + return this._buildURL(modelName); + }, + + /** + Builds a URL for fetching a async hasMany relationship when a url + is not provided by the server. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.JSONAPIAdapter.extend({ + urlForFindHasMany(id, modelName, snapshot) { + let baseUrl = this.buildURL(id, modelName); + return `${baseUrl}/relationships`; + } + }); + ``` + + @method urlForFindHasMany + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url + */ + urlForFindHasMany(id, modelName, snapshot) { + return this._buildURL(modelName, id); + }, + + /** + Builds a URL for fetching a async belongsTo relationship when a url + is not provided by the server. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.JSONAPIAdapter.extend({ + urlForFindBelongsTo(id, modelName, snapshot) { + let baseUrl = this.buildURL(id, modelName); + return `${baseUrl}/relationships`; + } + }); + ``` + + @method urlForFindBelongsTo + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url + */ + urlForFindBelongsTo(id, modelName, snapshot) { + return this._buildURL(modelName, id); + }, + + /** + Builds a URL for a `record.save()` call when the record was created + locally using `store.createRecord()`. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForCreateRecord(modelName, snapshot) { + return this._super(...arguments) + '/new'; + } + }); + ``` + + @method urlForCreateRecord + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url + */ + urlForCreateRecord(modelName, snapshot) { + return this._buildURL(modelName); + }, + + /** + Builds a URL for a `record.save()` call when the record has been update locally. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForUpdateRecord(id, modelName, snapshot) { + return `/${id}/feed?access_token=${snapshot.adapterOptions.token}`; + } + }); + ``` + + @method urlForUpdateRecord + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url + */ + urlForUpdateRecord(id, modelName, snapshot) { + return this._buildURL(modelName, id); + }, + + /** + Builds a URL for a `record.save()` call when the record has been deleted locally. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForDeleteRecord(id, modelName, snapshot) { + return this._super(...arguments) + '/destroy'; + } + }); + ``` + + @method urlForDeleteRecord + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url + */ + urlForDeleteRecord(id, modelName, snapshot) { + return this._buildURL(modelName, id); + }, + + /** + @method urlPrefix + @private + @param {String} path + @param {String} parentURL + @return {String} urlPrefix + */ + urlPrefix(path, parentURL) { + let host = get$17(this, 'host'); + let namespace = get$17(this, 'namespace'); + + if (!host || host === '/') { + host = ''; + } + + if (path) { + // Protocol relative url + if (/^\/\//.test(path) || /http(s)?:\/\//.test(path)) { + // Do nothing, the full host is already included. + return path; + + // Absolute path + } else if (path.charAt(0) === '/') { + return `${host}${path}`; + // Relative path + } else { + return `${parentURL}/${path}`; + } + } + + // No path provided + let url = []; + if (host) { url.push(host); } + if (namespace) { url.push(namespace); } + return url.join('/'); + }, + + /** + Determines the pathname for a given type. + + By default, it pluralizes the type's name (for example, + 'post' becomes 'posts' and 'person' becomes 'people'). + + ### Pathname customization + + For example if you have an object LineItem with an + endpoint of "/line_items/". + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + pathForType: function(modelName) { + var decamelized = Ember.String.decamelize(modelName); + return Ember.String.pluralize(decamelized); + } + }); + ``` + + @method pathForType + @param {String} modelName + @return {String} path + **/ + pathForType(modelName) { + let camelized = Ember.String.camelize(modelName); + return Ember.String.pluralize(camelized); + } +}); + +const CLRF = '\u000d\u000a'; + +function parseResponseHeaders(headersString) { + let headers = Object.create(null); + + if (!headersString) { + return headers; + } + + let headerPairs = headersString.split(CLRF); + for (let i = 0; i < headerPairs.length; i++) { + let header = headerPairs[i]; + let j = 0; + let foundSep = false; + + for (; j < header.length; j++) { + if (header.charCodeAt(j) === 58 /* ':' */) { + foundSep = true; + break; + } + } + + if (foundSep === false) { + break; + } + + let field = header.substring(0, j).trim(); + let value = header.substring(j + 1, header.length).trim(); + + if (value) { + headers[field] = value; + } + } + + return headers; +} + +/** + The `DS.Transform` class is used to serialize and deserialize model + attributes when they are saved or loaded from an + adapter. Subclassing `DS.Transform` is useful for creating custom + attributes. All subclasses of `DS.Transform` must implement a + `serialize` and a `deserialize` method. + + Example + + ```app/transforms/temperature.js + import DS from 'ember-data'; + + // Converts centigrade in the JSON to fahrenheit in the app + export default DS.Transform.extend({ + deserialize(serialized, options) { + return (serialized * 1.8) + 32; + }, + + serialize(deserialized, options) { + return (deserialized - 32) / 1.8; + } + }); + ``` + + The options passed into the `DS.attr` function when the attribute is + declared on the model is also available in the transform. + + ```app/models/post.js + export default DS.Model.extend({ + title: DS.attr('string'), + markdown: DS.attr('markdown', { + markdown: { + gfm: false, + sanitize: true + } + }) + }); + ``` + + ```app/transforms/markdown.js + export default DS.Transform.extend({ + serialize(deserialized, options) { + return deserialized.raw; + }, + + deserialize(serialized, options) { + var markdownOptions = options.markdown || {}; + + return marked(serialized, markdownOptions); + } + }); + ``` + + Usage + + ```app/models/requirement.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + name: DS.attr('string'), + temperature: DS.attr('temperature') + }); + ``` + + @class Transform + @namespace DS + */ +var Transform = Ember.Object.extend({ + /** + When given a deserialized value from a record attribute this + method must return the serialized value. + + Example + + ```javascript + serialize(deserialized, options) { + return Ember.isEmpty(deserialized) ? null : Number(deserialized); + } + ``` + + @method serialize + @param deserialized The deserialized value + @param options hash of options passed to `DS.attr` + @return The serialized value + */ + serialize: null, + + /** + When given a serialize value from a JSON object this method must + return the deserialized value for the record attribute. + + Example + + ```javascript + deserialize(serialized, options) { + return empty(serialized) ? null : Number(serialized); + } + ``` + + @method deserialize + @param serialized The serialized value + @param options hash of options passed to `DS.attr` + @return The deserialized value + */ + deserialize: null +}); + +const empty = Ember.isEmpty; + +function isNumber(value) { + return value === value && value !== Infinity && value !== -Infinity; +} + +/** + The `DS.NumberTransform` class is used to serialize and deserialize + numeric attributes on Ember Data record objects. This transform is + used when `number` is passed as the type parameter to the + [DS.attr](../../data#method_attr) function. + + Usage + + ```app/models/score.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + value: DS.attr('number'), + player: DS.belongsTo('player'), + date: DS.attr('date') + }); + ``` + + @class NumberTransform + @extends DS.Transform + @namespace DS + */ +var number = Transform.extend({ + deserialize(serialized) { + let transformed; + + if (empty(serialized)) { + return null; + } else { + transformed = Number(serialized); + + return isNumber(transformed) ? transformed : null; + } + }, + + serialize(deserialized) { + let transformed; + + if (empty(deserialized)) { + return null; + } else { + transformed = Number(deserialized); + + return isNumber(transformed) ? transformed : null; + } + } +}); + +/** + @module ember-data +*/ + +/** + Date.parse with progressive enhancement for ISO 8601 + + © 2011 Colin Snover + + Released under MIT license. + + @class Date + @namespace Ember + @static + @deprecated +*/ +Ember.Date = Ember.Date || {}; + +const origParse = Date.parse; +const numericKeys = [1, 4, 5, 6, 7, 10, 11]; + +const parseDate = function (date) { + let timestamp, struct; + let minutesOffset = 0; + + // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string + // before falling back to any implementation-specific date parsing, so that’s what we do, even if native + // implementations could be faster + // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm + if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2}):?(?:(\d{2}))?)?)?$/.exec(date))) { + // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC + for (let i = 0, k; (k = numericKeys[i]); ++i) { + struct[k] = +struct[k] || 0; + } + + // allow undefined days and months + struct[2] = (+struct[2] || 1) - 1; + struct[3] = +struct[3] || 1; + + if (struct[8] !== 'Z' && struct[9] !== undefined) { + minutesOffset = struct[10] * 60 + struct[11]; + + if (struct[9] === '+') { + minutesOffset = 0 - minutesOffset; + } + } + + timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]); + } else { + timestamp = origParse ? origParse(date) : NaN; + } + + return timestamp; +}; + +Ember.Date.parse = function (date) { + // throw deprecation + deprecate(`Ember.Date.parse is deprecated because Safari 5-, IE8-, and + Firefox 3.6- are no longer supported (see + https://github.com/csnover/js-iso8601 for the history of this issue). + Please use Date.parse instead`, false, { + id: 'ds.ember.date.parse-deprecate', + until: '3.0.0' + }); + + return parseDate(date); +}; + +if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Date) { + deprecate(`Overriding Date.parse with Ember.Date.parse is deprecated. Please set ENV.EmberENV.EXTEND_PROTOTYPES.Date to false in config/environment.js + + +// config/environment.js +ENV = { + EmberENV: { + EXTEND_PROTOTYPES: { + Date: false, + } + } +} +`, false, { + id: 'ds.date.parse-deprecate', + until: '3.0.0' +}); + Date.parse = parseDate; +} + +/** + The `DS.DateTransform` class is used to serialize and deserialize + date attributes on Ember Data record objects. This transform is used + when `date` is passed as the type parameter to the + [DS.attr](../../data#method_attr) function. It uses the [`ISO 8601`](https://en.wikipedia.org/wiki/ISO_8601) + standard. + + ```app/models/score.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + value: DS.attr('number'), + player: DS.belongsTo('player'), + date: DS.attr('date') + }); + ``` + + @class DateTransform + @extends DS.Transform + @namespace DS + */ + +var date = Transform.extend({ + deserialize(serialized) { + let type = typeof serialized; + + if (type === "string") { + return new Date(parseDate(serialized)); + } else if (type === "number") { + return new Date(serialized); + } else if (serialized === null || serialized === undefined) { + // if the value is null return null + // if the value is not present in the data return undefined + return serialized; + } else { + return null; + } + }, + + serialize(date) { + if (date instanceof Date && !isNaN(date)) { + return date.toISOString(); + } else { + return null; + } + } +}); + +const none = Ember.isNone; + +/** + The `DS.StringTransform` class is used to serialize and deserialize + string attributes on Ember Data record objects. This transform is + used when `string` is passed as the type parameter to the + [DS.attr](../../data#method_attr) function. + + Usage + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + isAdmin: DS.attr('boolean'), + name: DS.attr('string'), + email: DS.attr('string') + }); + ``` + + @class StringTransform + @extends DS.Transform + @namespace DS + */ +var string = Transform.extend({ + deserialize(serialized) { + return none(serialized) ? null : String(serialized); + }, + serialize(deserialized) { + return none(deserialized) ? null : String(deserialized); + } +}); + +const { isNone: isNone$1 } = Ember; + +/** + The `DS.BooleanTransform` class is used to serialize and deserialize + boolean attributes on Ember Data record objects. This transform is + used when `boolean` is passed as the type parameter to the + [DS.attr](../../data#method_attr) function. + + Usage + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + isAdmin: DS.attr('boolean'), + name: DS.attr('string'), + email: DS.attr('string') + }); + ``` + + By default the boolean transform only allows for values of `true` or + `false`. You can opt into allowing `null` values for + boolean attributes via `DS.attr('boolean', { allowNull: true })` + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + email: DS.attr('string'), + username: DS.attr('string'), + wantsWeeklyEmail: DS.attr('boolean', { allowNull: true }) + }); + ``` + + @class BooleanTransform + @extends DS.Transform + @namespace DS + */ +var boolean = Transform.extend({ + deserialize(serialized, options) { + let type = typeof serialized; + + if (isNone$1(serialized) && options.allowNull === true) { + return null; + } + + if (type === "boolean") { + return serialized; + } else if (type === "string") { + return serialized.match(/^true$|^t$|^1$/i) !== null; + } else if (type === "number") { + return serialized === 1; + } else { + return false; + } + }, + + serialize(deserialized, options) { + if (isNone$1(deserialized) && options.allowNull === true) { + return null; + } + + return Boolean(deserialized); + } +}); + +/* globals global, window, self */ + +// originally from https://github.com/emberjs/ember.js/blob/c0bd26639f50efd6a03ee5b87035fd200e313b8e/packages/ember-environment/lib/global.js + +// from lodash to catch fake globals +function checkGlobal(value) { + return (value && value.Object === Object) ? value : undefined; +} + +// element ids can ruin global miss checks +function checkElementIdShadowing(value) { + return (value && value.nodeType === undefined) ? value : undefined; +} + +// export real global +var global$1 = checkGlobal(checkElementIdShadowing(typeof global === 'object' && global)) || + checkGlobal(typeof self === 'object' && self) || + checkGlobal(typeof window === 'object' && window) || + new Function('return this')(); // eval outside of strict mode + +/** + @module ember-data +*/ +const capitalize = Ember.String.capitalize; +const underscore = Ember.String.underscore; +const { assert: assert$1, get: get$18 } = Ember; + +/* + Extend `Ember.DataAdapter` with ED specific code. + + @class DebugAdapter + @namespace DS + @extends Ember.DataAdapter + @private +*/ +var debugAdapter = Ember.DataAdapter.extend({ + getFilters() { + return [ + { name: 'isNew', desc: 'New' }, + { name: 'isModified', desc: 'Modified' }, + { name: 'isClean', desc: 'Clean' } + ]; + }, + + detect(typeClass) { + return typeClass !== Model && Model.detect(typeClass); + }, + + columnsForType(typeClass) { + let columns = [{ + name: 'id', + desc: 'Id' + }]; + let count = 0; + let self = this; + get$18(typeClass, 'attributes').forEach((meta, name) => { + if (count++ > self.attributeLimit) { return false; } + let desc = capitalize(underscore(name).replace('_', ' ')); + columns.push({ name: name, desc: desc }); + }); + return columns; + }, + + getRecords(modelClass, modelName) { + if (arguments.length < 2) { + // Legacy Ember.js < 1.13 support + let containerKey = modelClass._debugContainerKey; + if (containerKey) { + let match = containerKey.match(/model:(.*)/); + if (match) { + modelName = match[1]; + } + } + } + assert$1("Cannot find model name. Please upgrade to Ember.js >= 1.13 for Ember Inspector support", !!modelName); + return this.get('store').peekAll(modelName); + }, + + getRecordColumnValues(record) { + let count = 0; + let columnValues = { id: get$18(record, 'id') }; + + record.eachAttribute((key) => { + if (count++ > this.attributeLimit) { + return false; + } + columnValues[key] = get$18(record, key); + }); + return columnValues; + }, + + getRecordKeywords(record) { + let keywords = []; + let keys = Ember.A(['id']); + record.eachAttribute((key) => keys.push(key)); + keys.forEach((key) => keywords.push(get$18(record, key))); + return keywords; + }, + + getRecordFilterValues(record) { + return { + isNew: record.get('isNew'), + isModified: record.get('hasDirtyAttributes') && !record.get('isNew'), + isClean: !record.get('hasDirtyAttributes') + }; + }, + + getRecordColor(record) { + let color = 'black'; + if (record.get('isNew')) { + color = 'green'; + } else if (record.get('hasDirtyAttributes')) { + color = 'blue'; + } + return color; + }, + + observeRecord(record, recordUpdated) { + let releaseMethods = Ember.A(); + let keysToObserve = Ember.A(['id', 'isNew', 'hasDirtyAttributes']); + + record.eachAttribute((key) => keysToObserve.push(key)); + let adapter = this; + + keysToObserve.forEach(function(key) { + let handler = function() { + recordUpdated(adapter.wrapRecord(record)); + }; + Ember.addObserver(record, key, handler); + releaseMethods.push(function() { + Ember.removeObserver(record, key, handler); + }); + }); + + let release = function() { + releaseMethods.forEach((fn) => fn()); + }; + + return release; + } +}); + +// public + +export { Model, Errors, Store$1 as Store, DS, belongsTo, hasMany, buildUrlMixin as BuildURLMixin, Snapshot, normalizeModelName, getOwner, modelHasAttributeOrRelationshipNamedType, coerceId, parseResponseHeaders, Transform, number as NumberTransform, date as DateTransform, string as StringTransform, boolean as BooleanTransform, RootState$1 as RootState, global$1 as global, isEnabled, InternalModel, parseDate, PromiseArray, PromiseObject, PromiseManyArray, RecordArray, FilteredRecordArray, AdapterPopulatedRecordArray, ManyArray, RecordArrayManager, Relationship, debugAdapter as DebugAdapter }; diff --git a/addon/-private/adapters/errors.js b/addon/-private/adapters/errors.js new file mode 100644 index 00000000000..87f1daaa588 --- /dev/null +++ b/addon/-private/adapters/errors.js @@ -0,0 +1,478 @@ +import Ember from 'ember'; +import { assert } from 'ember-data/-debug'; + +import isEnabled from '../features'; + +const EmberError = Ember.Error; + +const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/; +const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/; +const PRIMARY_ATTRIBUTE_KEY = 'base'; + +/** + A `DS.AdapterError` is used by an adapter to signal that an error occurred + during a request to an external API. It indicates a generic error, and + subclasses are used to indicate specific error states. The following + subclasses are provided: + + - `DS.InvalidError` + - `DS.TimeoutError` + - `DS.AbortError` + - `DS.UnauthorizedError` + - `DS.ForbiddenError` + - `DS.NotFoundError` + - `DS.ConflictError` + - `DS.ServerError` + + To create a custom error to signal a specific error state in communicating + with an external API, extend the `DS.AdapterError`. For example if the + external API exclusively used HTTP `503 Service Unavailable` to indicate + it was closed for maintenance: + + ```app/adapters/maintenance-error.js + import DS from 'ember-data'; + + export default DS.AdapterError.extend({ message: "Down for maintenance." }); + ``` + + This error would then be returned by an adapter's `handleResponse` method: + + ```app/adapters/application.js + import DS from 'ember-data'; + import MaintenanceError from './maintenance-error'; + + export default DS.JSONAPIAdapter.extend({ + handleResponse(status) { + if (503 === status) { + return new MaintenanceError(); + } + + return this._super(...arguments); + } + }); + ``` + + And can then be detected in an application and used to send the user to an + `under-maintenance` route: + + ```app/routes/application.js + import Ember from 'ember'; + import MaintenanceError from '../adapters/maintenance-error'; + + export default Ember.Route.extend({ + actions: { + error(error, transition) { + if (error instanceof MaintenanceError) { + this.transitionTo('under-maintenance'); + return; + } + + // ...other error handling logic + } + } + }); + ``` + + @class AdapterError + @namespace DS +*/ +export function AdapterError(errors, message = 'Adapter operation failed') { + this.isAdapterError = true; + EmberError.call(this, message); + + this.errors = errors || [ + { + title: 'Adapter Error', + detail: message + } + ]; +} + +let extendedErrorsEnabled = false; +if (isEnabled('ds-extended-errors')) { + extendedErrorsEnabled = true; +} + +function extendFn(ErrorClass) { + return function({ message: defaultMessage } = {}) { + return extend(ErrorClass, defaultMessage); + }; +} + +function extend(ParentErrorClass, defaultMessage) { + let ErrorClass = function(errors, message) { + assert('`AdapterError` expects json-api formatted errors array.', Array.isArray(errors || [])); + ParentErrorClass.call(this, errors, message || defaultMessage); + }; + ErrorClass.prototype = Object.create(ParentErrorClass.prototype); + + if (extendedErrorsEnabled) { + ErrorClass.extend = extendFn(ErrorClass); + } + + return ErrorClass; +} + +AdapterError.prototype = Object.create(EmberError.prototype); + +if (extendedErrorsEnabled) { + AdapterError.extend = extendFn(AdapterError); +} + +/** + A `DS.InvalidError` is used by an adapter to signal the external API + was unable to process a request because the content was not + semantically correct or meaningful per the API. Usually this means a + record failed some form of server side validation. When a promise + from an adapter is rejected with a `DS.InvalidError` the record will + transition to the `invalid` state and the errors will be set to the + `errors` property on the record. + + For Ember Data to correctly map errors to their corresponding + properties on the model, Ember Data expects each error to be + a valid json-api error object with a `source/pointer` that matches + the property name. For example if you had a Post model that + looked like this. + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + title: DS.attr('string'), + content: DS.attr('string') + }); + ``` + + To show an error from the server related to the `title` and + `content` properties your adapter could return a promise that + rejects with a `DS.InvalidError` object that looks like this: + + ```app/adapters/post.js + import Ember from 'ember'; + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + updateRecord() { + // Fictional adapter that always rejects + return Ember.RSVP.reject(new DS.InvalidError([ + { + detail: 'Must be unique', + source: { pointer: '/data/attributes/title' } + }, + { + detail: 'Must not be blank', + source: { pointer: '/data/attributes/content'} + } + ])); + } + }); + ``` + + Your backend may use different property names for your records the + store will attempt extract and normalize the errors using the + serializer's `extractErrors` method before the errors get added to + the the model. As a result, it is safe for the `InvalidError` to + wrap the error payload unaltered. + + @class InvalidError + @namespace DS +*/ +export const InvalidError = extend(AdapterError, + 'The adapter rejected the commit because it was invalid'); + +/** + A `DS.TimeoutError` is used by an adapter to signal that a request + to the external API has timed out. I.e. no response was received from + the external API within an allowed time period. + + An example use case would be to warn the user to check their internet + connection if an adapter operation has timed out: + + ```app/routes/application.js + import Ember from 'ember'; + import DS from 'ember-data'; + + const { TimeoutError } = DS; + + export default Ember.Route.extend({ + actions: { + error(error, transition) { + if (error instanceof TimeoutError) { + // alert the user + alert('Are you still connected to the internet?'); + return; + } + + // ...other error handling logic + } + } + }); + ``` + + @class TimeoutError + @namespace DS +*/ +export const TimeoutError = extend(AdapterError, + 'The adapter operation timed out'); + +/** + A `DS.AbortError` is used by an adapter to signal that a request to + the external API was aborted. For example, this can occur if the user + navigates away from the current page after a request to the external API + has been initiated but before a response has been received. + + @class AbortError + @namespace DS +*/ +export const AbortError = extend(AdapterError, + 'The adapter operation was aborted'); + +/** + A `DS.UnauthorizedError` equates to a HTTP `401 Unauthorized` response + status. It is used by an adapter to signal that a request to the external + API was rejected because authorization is required and has failed or has not + yet been provided. + + An example use case would be to redirect the user to a log in route if a + request is unauthorized: + + ```app/routes/application.js + import Ember from 'ember'; + import DS from 'ember-data'; + + const { UnauthorizedError } = DS; + + export default Ember.Route.extend({ + actions: { + error(error, transition) { + if (error instanceof UnauthorizedError) { + // go to the sign in route + this.transitionTo('login'); + return; + } + + // ...other error handling logic + } + } + }); + ``` + + @class UnauthorizedError + @namespace DS +*/ +export const UnauthorizedError = extendedErrorsEnabled ? + extend(AdapterError, 'The adapter operation is unauthorized') : null; + +/** + A `DS.ForbiddenError` equates to a HTTP `403 Forbidden` response status. + It is used by an adapter to signal that a request to the external API was + valid but the server is refusing to respond to it. If authorization was + provided and is valid, then the authenticated user does not have the + necessary permissions for the request. + + @class ForbiddenError + @namespace DS +*/ +export const ForbiddenError = extendedErrorsEnabled ? + extend(AdapterError, 'The adapter operation is forbidden') : null; + +/** + A `DS.NotFoundError` equates to a HTTP `404 Not Found` response status. + It is used by an adapter to signal that a request to the external API + was rejected because the resource could not be found on the API. + + An example use case would be to detect if the user has entered a route + for a specific model that does not exist. For example: + + ```app/routes/post.js + import Ember from 'ember'; + import DS from 'ember-data'; + + const { NotFoundError } = DS; + + export default Ember.Route.extend({ + model(params) { + return this.get('store').findRecord('post', params.post_id); + }, + + actions: { + error(error, transition) { + if (error instanceof NotFoundError) { + // redirect to a list of all posts instead + this.transitionTo('posts'); + } else { + // otherwise let the error bubble + return true; + } + } + } + }); + ``` + + @class NotFoundError + @namespace DS +*/ +export const NotFoundError = extendedErrorsEnabled ? + extend(AdapterError, 'The adapter could not find the resource') : null; + +/** + A `DS.ConflictError` equates to a HTTP `409 Conflict` response status. + It is used by an adapter to indicate that the request could not be processed + because of a conflict in the request. An example scenario would be when + creating a record with a client generated id but that id is already known + to the external API. + + @class ConflictError + @namespace DS +*/ +export const ConflictError = extendedErrorsEnabled ? + extend(AdapterError, 'The adapter operation failed due to a conflict') : null; + +/** + A `DS.ServerError` equates to a HTTP `500 Internal Server Error` response + status. It is used by the adapter to indicate that a request has failed + because of an error in the external API. + + @class ServerError + @namespace DS +*/ +export const ServerError = extendedErrorsEnabled ? + extend(AdapterError, 'The adapter operation failed due to a server error') : null; + +/** + Convert an hash of errors into an array with errors in JSON-API format. + + ```javascript + import DS from 'ember-data'; + + const { errorsHashToArray } = DS; + + let errors = { + base: 'Invalid attributes on saving this record', + name: 'Must be present', + age: ['Must be present', 'Must be a number'] + }; + + let errorsArray = errorsHashToArray(errors); + // [ + // { + // title: "Invalid Document", + // detail: "Invalid attributes on saving this record", + // source: { pointer: "/data" } + // }, + // { + // title: "Invalid Attribute", + // detail: "Must be present", + // source: { pointer: "/data/attributes/name" } + // }, + // { + // title: "Invalid Attribute", + // detail: "Must be present", + // source: { pointer: "/data/attributes/age" } + // }, + // { + // title: "Invalid Attribute", + // detail: "Must be a number", + // source: { pointer: "/data/attributes/age" } + // } + // ] + ``` + + @method errorsHashToArray + @public + @namespace + @for DS + @param {Object} errors hash with errors as properties + @return {Array} array of errors in JSON-API format +*/ +export function errorsHashToArray(errors) { + let out = []; + + if (Ember.isPresent(errors)) { + Object.keys(errors).forEach((key) => { + let messages = Ember.makeArray(errors[key]); + for (let i = 0; i < messages.length; i++) { + let title = 'Invalid Attribute'; + let pointer = `/data/attributes/${key}`; + if (key === PRIMARY_ATTRIBUTE_KEY) { + title = 'Invalid Document'; + pointer = `/data`; + } + out.push({ + title: title, + detail: messages[i], + source: { + pointer: pointer + } + }); + } + }); + } + + return out; +} + +/** + Convert an array of errors in JSON-API format into an object. + + ```javascript + import DS from 'ember-data'; + + const { errorsArrayToHash } = DS; + + let errorsArray = [ + { + title: 'Invalid Attribute', + detail: 'Must be present', + source: { pointer: '/data/attributes/name' } + }, + { + title: 'Invalid Attribute', + detail: 'Must be present', + source: { pointer: '/data/attributes/age' } + }, + { + title: 'Invalid Attribute', + detail: 'Must be a number', + source: { pointer: '/data/attributes/age' } + } + ]; + + let errors = errorsArrayToHash(errorsArray); + // { + // "name": ["Must be present"], + // "age": ["Must be present", "must be a number"] + // } + ``` + + @method errorsArrayToHash + @public + @namespace + @for DS + @param {Array} errors array of errors in JSON-API format + @return {Object} +*/ +export function errorsArrayToHash(errors) { + let out = {}; + + if (Ember.isPresent(errors)) { + errors.forEach((error) => { + if (error.source && error.source.pointer) { + let key = error.source.pointer.match(SOURCE_POINTER_REGEXP); + + if (key) { + key = key[2]; + } else if (error.source.pointer.search(SOURCE_POINTER_PRIMARY_REGEXP) !== -1) { + key = PRIMARY_ATTRIBUTE_KEY; + } + + if (key) { + out[key] = out[key] || []; + out[key].push(error.detail || error.title); + } + } + }); + } + + return out; +} diff --git a/addon/-private/index.js b/addon/-private/index.js index 174f5386515..b3e0fb02691 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -7,14 +7,28 @@ export { default as belongsTo } from './system/relationships/belongs-to'; export { default as hasMany } from './system/relationships/has-many'; export { default as BuildURLMixin } from './adapters/build-url-mixin'; export { default as Snapshot } from './system/snapshot'; +export { + AdapterError, + InvalidError, + UnauthorizedError, + ForbiddenError, + NotFoundError, + ConflictError, + ServerError, + TimeoutError, + AbortError, + errorsHashToArray, + errorsArrayToHash +} from './adapters/errors'; // maybe public ? export { default as normalizeModelName } from './system/normalize-model-name'; -export { modelHasAttributeOrRelationshipNamedType } from './utils'; +export { getOwner, modelHasAttributeOrRelationshipNamedType } from './utils'; export { default as coerceId } from './system/coerce-id'; export { default as parseResponseHeaders } from './utils/parse-response-headers'; // should be moved into public ? +export { default as Transform } from './transforms/transform'; export { default as NumberTransform } from './transforms/number'; export { default as DateTransform } from './transforms/date'; export { default as StringTransform } from './transforms/string'; @@ -25,6 +39,7 @@ export { default as RootState } from './system/model/states'; export { default as global } from './global'; export { default as isEnabled } from './features'; export { default as InternalModel } from './system/model/internal-model'; +export { parseDate } from './ext/date'; export { PromiseArray, @@ -40,7 +55,6 @@ export { export { default as ManyArray } from './system/many-array'; export { default as RecordArrayManager } from './system/record-array-manager'; -export { default as initializeStoreService } from './instance-initializers/initialize-store-service'; export { default as Relationship } from './system/relationships/state/relationship'; // Should be a different Repo ? diff --git a/addon/-private/initializers/data-adapter.js b/addon/-private/initializers/data-adapter.js deleted file mode 100644 index 84369679d8c..00000000000 --- a/addon/-private/initializers/data-adapter.js +++ /dev/null @@ -1,12 +0,0 @@ -import DebugAdapter from "ember-data/-private/system/debug/debug-adapter"; - -/* - Configures a registry with injections on Ember applications - for the Ember-Data store. Accepts an optional namespace argument. - - @method initializeDebugAdapter - @param {Ember.Registry} registry -*/ -export default function initializeDebugAdapter(registry) { - registry.register('data-adapter:main', DebugAdapter); -} diff --git a/addon/-private/initializers/store-injections.js b/addon/-private/initializers/store-injections.js deleted file mode 100644 index e36c0461b2d..00000000000 --- a/addon/-private/initializers/store-injections.js +++ /dev/null @@ -1,15 +0,0 @@ -/* - Configures a registry with injections on Ember applications - for the Ember-Data store. Accepts an optional namespace argument. - - @method initializeStoreInjections - @param {Ember.Registry} registry -*/ -export default function initializeStoreInjections(registry) { - // registry.injection for Ember < 2.1.0 - // application.inject for Ember 2.1.0+ - let inject = registry.inject || registry.injection; - inject.call(registry, 'controller', 'store', 'service:store'); - inject.call(registry, 'route', 'store', 'service:store'); - inject.call(registry, 'data-adapter', 'store', 'service:store'); -} diff --git a/addon/-private/initializers/store.js b/addon/-private/initializers/store.js deleted file mode 100644 index 7564592bb3b..00000000000 --- a/addon/-private/initializers/store.js +++ /dev/null @@ -1,43 +0,0 @@ -import Store from "../system/store"; -import JSONAPISerializer from 'ember-data/serializers/json-api'; -import JSONSerializer from 'ember-data/serializers/json'; -import RESTSerializer from 'ember-data/serializers/rest'; -import JSONAPIAdapter from 'ember-data/adapters/json-api'; -import RESTAdapter from 'ember-data/adapters/rest'; - -function has(applicationOrRegistry, fullName) { - if (applicationOrRegistry.has) { - // < 2.1.0 - return applicationOrRegistry.has(fullName); - } else { - // 2.1.0+ - return applicationOrRegistry.hasRegistration(fullName); - } -} - -/* - Configures a registry for use with an Ember-Data - store. Accepts an optional namespace argument. - - @method initializeStore - @param {Ember.Registry} registry -*/ -export default function initializeStore(registry) { - // registry.optionsForType for Ember < 2.1.0 - // application.registerOptionsForType for Ember 2.1.0+ - let registerOptionsForType = registry.registerOptionsForType || registry.optionsForType; - registerOptionsForType.call(registry, 'serializer', { singleton: false }); - registerOptionsForType.call(registry, 'adapter', { singleton: false }); - - registry.register('serializer:-default', JSONSerializer); - registry.register('serializer:-rest', RESTSerializer); - registry.register('adapter:-rest', RESTAdapter); - - registry.register('adapter:-json-api', JSONAPIAdapter); - registry.register('serializer:-json-api', JSONAPISerializer); - - - if (!has(registry, 'service:store')) { - registry.register('service:store', Store); - } -} diff --git a/addon/-private/initializers/transforms.js b/addon/-private/initializers/transforms.js deleted file mode 100644 index 29e8e0120d1..00000000000 --- a/addon/-private/initializers/transforms.js +++ /dev/null @@ -1,18 +0,0 @@ -import NumberTransform from '../transforms/number'; -import DateTransform from '../transforms/date'; -import StringTransform from '../transforms/string'; -import BooleanTransform from '../transforms/boolean'; - -/* - Configures a registry for use with Ember-Data - transforms. - - @method initializeTransforms - @param {Ember.Registry} registry -*/ -export default function initializeTransforms(registry) { - registry.register('transform:boolean', BooleanTransform); - registry.register('transform:date', DateTransform); - registry.register('transform:number', NumberTransform); - registry.register('transform:string', StringTransform); -} diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 92d0340b3ea..93e2e31fea7 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -6,9 +6,7 @@ import Snapshot from "../snapshot"; import isEnabled from '../../features'; import OrderedSet from "../ordered-set"; -import { - getOwner -} from 'ember-data/-private/utils'; +import { getOwner } from '../../utils'; import { RecordReference, diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 6e1c9083f16..f244a433e26 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert, deprecate, warn } from 'ember-data/-debug'; +import { assert, deprecate, warn, runInDebug } from 'ember-data/-debug'; import { PromiseObject } from "../promise-proxies"; import Errors from "../model/errors"; import isEnabled from '../../features'; @@ -9,7 +9,6 @@ import { relatedTypesDescriptor, relationshipsDescriptor } from '../relationships/ext'; -import { runInDebug } from 'ember-data/-debug'; const { get, diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 93a4a62e467..73227b3519d 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -1,4 +1,4 @@ -import Model from 'ember-data/model'; +import Model from '../model/model'; import Ember from 'ember'; import Reference from './reference'; diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 519896e01ab..86e5ec1de76 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -3,6 +3,7 @@ */ import Ember from 'ember'; +import { InvalidError } from '../adapters/errors'; import { instrument, assert, @@ -10,9 +11,8 @@ import { warn, runInDebug } from 'ember-data/-debug'; -import Model from '../../model'; +import Model from './model/model'; import normalizeModelName from "./normalize-model-name"; -import { InvalidError } from '../../adapters/errors'; import IdentityMap from './identity-map'; import { diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index f6a0d0e1914..479d5822461 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -4,15 +4,10 @@ import { _bind, _guard, _objectIsAlive -} from "ember-data/-private/system/store/common"; +} from "./common"; -import { - normalizeResponseHelper -} from "ember-data/-private/system/store/serializer-response"; - -import { - serializerForAdapter -} from "ember-data/-private/system/store/serializers"; +import { normalizeResponseHelper } from "./serializer-response"; +import { serializerForAdapter } from "./serializers"; const { Promise } = Ember.RSVP; diff --git a/addon/-private/transforms/boolean.js b/addon/-private/transforms/boolean.js index 7150f1aade5..51fc34d783a 100644 --- a/addon/-private/transforms/boolean.js +++ b/addon/-private/transforms/boolean.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import Transform from "../../transform"; +import Transform from './transform'; const { isNone } = Ember; diff --git a/addon/-private/transforms/date.js b/addon/-private/transforms/date.js index beb9f34999b..192da27ade2 100644 --- a/addon/-private/transforms/date.js +++ b/addon/-private/transforms/date.js @@ -1,4 +1,5 @@ -import { parseDate } from "../ext/date"; +import Transform from './transform'; +import { parseDate } from '../ext/date'; /** The `DS.DateTransform` class is used to serialize and deserialize @@ -21,7 +22,6 @@ import { parseDate } from "../ext/date"; @extends DS.Transform @namespace DS */ -import Transform from "ember-data/transform"; export default Transform.extend({ deserialize(serialized) { diff --git a/addon/-private/transforms/number.js b/addon/-private/transforms/number.js index b5628aff688..f35dcde9be2 100644 --- a/addon/-private/transforms/number.js +++ b/addon/-private/transforms/number.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import Transform from "../../transform"; +import Transform from './transform'; const empty = Ember.isEmpty; diff --git a/addon/-private/transforms/string.js b/addon/-private/transforms/string.js index 2d8e7b779b6..c687d3499a7 100644 --- a/addon/-private/transforms/string.js +++ b/addon/-private/transforms/string.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import Transform from "../../transform"; +import Transform from './transform'; const none = Ember.isNone; diff --git a/addon/-private/transforms/transform.js b/addon/-private/transforms/transform.js new file mode 100644 index 00000000000..a13cc3fe527 --- /dev/null +++ b/addon/-private/transforms/transform.js @@ -0,0 +1,108 @@ +import Ember from 'ember'; + +/** + The `DS.Transform` class is used to serialize and deserialize model + attributes when they are saved or loaded from an + adapter. Subclassing `DS.Transform` is useful for creating custom + attributes. All subclasses of `DS.Transform` must implement a + `serialize` and a `deserialize` method. + + Example + + ```app/transforms/temperature.js + import DS from 'ember-data'; + + // Converts centigrade in the JSON to fahrenheit in the app + export default DS.Transform.extend({ + deserialize(serialized, options) { + return (serialized * 1.8) + 32; + }, + + serialize(deserialized, options) { + return (deserialized - 32) / 1.8; + } + }); + ``` + + The options passed into the `DS.attr` function when the attribute is + declared on the model is also available in the transform. + + ```app/models/post.js + export default DS.Model.extend({ + title: DS.attr('string'), + markdown: DS.attr('markdown', { + markdown: { + gfm: false, + sanitize: true + } + }) + }); + ``` + + ```app/transforms/markdown.js + export default DS.Transform.extend({ + serialize(deserialized, options) { + return deserialized.raw; + }, + + deserialize(serialized, options) { + var markdownOptions = options.markdown || {}; + + return marked(serialized, markdownOptions); + } + }); + ``` + + Usage + + ```app/models/requirement.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + name: DS.attr('string'), + temperature: DS.attr('temperature') + }); + ``` + + @class Transform + @namespace DS + */ +export default Ember.Object.extend({ + /** + When given a deserialized value from a record attribute this + method must return the serialized value. + + Example + + ```javascript + serialize(deserialized, options) { + return Ember.isEmpty(deserialized) ? null : Number(deserialized); + } + ``` + + @method serialize + @param deserialized The deserialized value + @param options hash of options passed to `DS.attr` + @return The serialized value + */ + serialize: null, + + /** + When given a serialize value from a JSON object this method must + return the deserialized value for the record attribute. + + Example + + ```javascript + deserialize(serialized, options) { + return empty(serialized) ? null : Number(serialized); + } + ``` + + @method deserialize + @param serialized The serialized value + @param options hash of options passed to `DS.attr` + @return The deserialized value + */ + deserialize: null +}); diff --git a/addon/adapters/errors.js b/addon/adapters/errors.js index d2df6f10c54..051e090262c 100644 --- a/addon/adapters/errors.js +++ b/addon/adapters/errors.js @@ -1,477 +1,13 @@ -import Ember from 'ember'; -import { assert } from 'ember-data/-debug'; -import isEnabled from '../-private/features'; - -const EmberError = Ember.Error; - -const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/; -const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/; -const PRIMARY_ATTRIBUTE_KEY = 'base'; - -/** - A `DS.AdapterError` is used by an adapter to signal that an error occurred - during a request to an external API. It indicates a generic error, and - subclasses are used to indicate specific error states. The following - subclasses are provided: - - - `DS.InvalidError` - - `DS.TimeoutError` - - `DS.AbortError` - - `DS.UnauthorizedError` - - `DS.ForbiddenError` - - `DS.NotFoundError` - - `DS.ConflictError` - - `DS.ServerError` - - To create a custom error to signal a specific error state in communicating - with an external API, extend the `DS.AdapterError`. For example if the - external API exclusively used HTTP `503 Service Unavailable` to indicate - it was closed for maintenance: - - ```app/adapters/maintenance-error.js - import DS from 'ember-data'; - - export default DS.AdapterError.extend({ message: "Down for maintenance." }); - ``` - - This error would then be returned by an adapter's `handleResponse` method: - - ```app/adapters/application.js - import DS from 'ember-data'; - import MaintenanceError from './maintenance-error'; - - export default DS.JSONAPIAdapter.extend({ - handleResponse(status) { - if (503 === status) { - return new MaintenanceError(); - } - - return this._super(...arguments); - } - }); - ``` - - And can then be detected in an application and used to send the user to an - `under-maintenance` route: - - ```app/routes/application.js - import Ember from 'ember'; - import MaintenanceError from '../adapters/maintenance-error'; - - export default Ember.Route.extend({ - actions: { - error(error, transition) { - if (error instanceof MaintenanceError) { - this.transitionTo('under-maintenance'); - return; - } - - // ...other error handling logic - } - } - }); - ``` - - @class AdapterError - @namespace DS -*/ -export function AdapterError(errors, message = 'Adapter operation failed') { - this.isAdapterError = true; - EmberError.call(this, message); - - this.errors = errors || [ - { - title: 'Adapter Error', - detail: message - } - ]; -} - -let extendedErrorsEnabled = false; -if (isEnabled('ds-extended-errors')) { - extendedErrorsEnabled = true; -} - -function extendFn(ErrorClass) { - return function({ message: defaultMessage } = {}) { - return extend(ErrorClass, defaultMessage); - }; -} - -function extend(ParentErrorClass, defaultMessage) { - let ErrorClass = function(errors, message) { - assert('`AdapterError` expects json-api formatted errors array.', Array.isArray(errors || [])); - ParentErrorClass.call(this, errors, message || defaultMessage); - }; - ErrorClass.prototype = Object.create(ParentErrorClass.prototype); - - if (extendedErrorsEnabled) { - ErrorClass.extend = extendFn(ErrorClass); - } - - return ErrorClass; -} - -AdapterError.prototype = Object.create(EmberError.prototype); - -if (extendedErrorsEnabled) { - AdapterError.extend = extendFn(AdapterError); -} - -/** - A `DS.InvalidError` is used by an adapter to signal the external API - was unable to process a request because the content was not - semantically correct or meaningful per the API. Usually this means a - record failed some form of server side validation. When a promise - from an adapter is rejected with a `DS.InvalidError` the record will - transition to the `invalid` state and the errors will be set to the - `errors` property on the record. - - For Ember Data to correctly map errors to their corresponding - properties on the model, Ember Data expects each error to be - a valid json-api error object with a `source/pointer` that matches - the property name. For example if you had a Post model that - looked like this. - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - title: DS.attr('string'), - content: DS.attr('string') - }); - ``` - - To show an error from the server related to the `title` and - `content` properties your adapter could return a promise that - rejects with a `DS.InvalidError` object that looks like this: - - ```app/adapters/post.js - import Ember from 'ember'; - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - updateRecord() { - // Fictional adapter that always rejects - return Ember.RSVP.reject(new DS.InvalidError([ - { - detail: 'Must be unique', - source: { pointer: '/data/attributes/title' } - }, - { - detail: 'Must not be blank', - source: { pointer: '/data/attributes/content'} - } - ])); - } - }); - ``` - - Your backend may use different property names for your records the - store will attempt extract and normalize the errors using the - serializer's `extractErrors` method before the errors get added to - the the model. As a result, it is safe for the `InvalidError` to - wrap the error payload unaltered. - - @class InvalidError - @namespace DS -*/ -export const InvalidError = extend(AdapterError, - 'The adapter rejected the commit because it was invalid'); - -/** - A `DS.TimeoutError` is used by an adapter to signal that a request - to the external API has timed out. I.e. no response was received from - the external API within an allowed time period. - - An example use case would be to warn the user to check their internet - connection if an adapter operation has timed out: - - ```app/routes/application.js - import Ember from 'ember'; - import DS from 'ember-data'; - - const { TimeoutError } = DS; - - export default Ember.Route.extend({ - actions: { - error(error, transition) { - if (error instanceof TimeoutError) { - // alert the user - alert('Are you still connected to the internet?'); - return; - } - - // ...other error handling logic - } - } - }); - ``` - - @class TimeoutError - @namespace DS -*/ -export const TimeoutError = extend(AdapterError, - 'The adapter operation timed out'); - -/** - A `DS.AbortError` is used by an adapter to signal that a request to - the external API was aborted. For example, this can occur if the user - navigates away from the current page after a request to the external API - has been initiated but before a response has been received. - - @class AbortError - @namespace DS -*/ -export const AbortError = extend(AdapterError, - 'The adapter operation was aborted'); - -/** - A `DS.UnauthorizedError` equates to a HTTP `401 Unauthorized` response - status. It is used by an adapter to signal that a request to the external - API was rejected because authorization is required and has failed or has not - yet been provided. - - An example use case would be to redirect the user to a log in route if a - request is unauthorized: - - ```app/routes/application.js - import Ember from 'ember'; - import DS from 'ember-data'; - - const { UnauthorizedError } = DS; - - export default Ember.Route.extend({ - actions: { - error(error, transition) { - if (error instanceof UnauthorizedError) { - // go to the sign in route - this.transitionTo('login'); - return; - } - - // ...other error handling logic - } - } - }); - ``` - - @class UnauthorizedError - @namespace DS -*/ -export const UnauthorizedError = extendedErrorsEnabled ? - extend(AdapterError, 'The adapter operation is unauthorized') : null; - -/** - A `DS.ForbiddenError` equates to a HTTP `403 Forbidden` response status. - It is used by an adapter to signal that a request to the external API was - valid but the server is refusing to respond to it. If authorization was - provided and is valid, then the authenticated user does not have the - necessary permissions for the request. - - @class ForbiddenError - @namespace DS -*/ -export const ForbiddenError = extendedErrorsEnabled ? - extend(AdapterError, 'The adapter operation is forbidden') : null; - -/** - A `DS.NotFoundError` equates to a HTTP `404 Not Found` response status. - It is used by an adapter to signal that a request to the external API - was rejected because the resource could not be found on the API. - - An example use case would be to detect if the user has entered a route - for a specific model that does not exist. For example: - - ```app/routes/post.js - import Ember from 'ember'; - import DS from 'ember-data'; - - const { NotFoundError } = DS; - - export default Ember.Route.extend({ - model(params) { - return this.get('store').findRecord('post', params.post_id); - }, - - actions: { - error(error, transition) { - if (error instanceof NotFoundError) { - // redirect to a list of all posts instead - this.transitionTo('posts'); - } else { - // otherwise let the error bubble - return true; - } - } - } - }); - ``` - - @class NotFoundError - @namespace DS -*/ -export const NotFoundError = extendedErrorsEnabled ? - extend(AdapterError, 'The adapter could not find the resource') : null; - -/** - A `DS.ConflictError` equates to a HTTP `409 Conflict` response status. - It is used by an adapter to indicate that the request could not be processed - because of a conflict in the request. An example scenario would be when - creating a record with a client generated id but that id is already known - to the external API. - - @class ConflictError - @namespace DS -*/ -export const ConflictError = extendedErrorsEnabled ? - extend(AdapterError, 'The adapter operation failed due to a conflict') : null; - -/** - A `DS.ServerError` equates to a HTTP `500 Internal Server Error` response - status. It is used by the adapter to indicate that a request has failed - because of an error in the external API. - - @class ServerError - @namespace DS -*/ -export const ServerError = extendedErrorsEnabled ? - extend(AdapterError, 'The adapter operation failed due to a server error') : null; - -/** - Convert an hash of errors into an array with errors in JSON-API format. - - ```javascript - import DS from 'ember-data'; - - const { errorsHashToArray } = DS; - - let errors = { - base: 'Invalid attributes on saving this record', - name: 'Must be present', - age: ['Must be present', 'Must be a number'] - }; - - let errorsArray = errorsHashToArray(errors); - // [ - // { - // title: "Invalid Document", - // detail: "Invalid attributes on saving this record", - // source: { pointer: "/data" } - // }, - // { - // title: "Invalid Attribute", - // detail: "Must be present", - // source: { pointer: "/data/attributes/name" } - // }, - // { - // title: "Invalid Attribute", - // detail: "Must be present", - // source: { pointer: "/data/attributes/age" } - // }, - // { - // title: "Invalid Attribute", - // detail: "Must be a number", - // source: { pointer: "/data/attributes/age" } - // } - // ] - ``` - - @method errorsHashToArray - @public - @namespace - @for DS - @param {Object} errors hash with errors as properties - @return {Array} array of errors in JSON-API format -*/ -export function errorsHashToArray(errors) { - let out = []; - - if (Ember.isPresent(errors)) { - Object.keys(errors).forEach((key) => { - let messages = Ember.makeArray(errors[key]); - for (let i = 0; i < messages.length; i++) { - let title = 'Invalid Attribute'; - let pointer = `/data/attributes/${key}`; - if (key === PRIMARY_ATTRIBUTE_KEY) { - title = 'Invalid Document'; - pointer = `/data`; - } - out.push({ - title: title, - detail: messages[i], - source: { - pointer: pointer - } - }); - } - }); - } - - return out; -} - -/** - Convert an array of errors in JSON-API format into an object. - - ```javascript - import DS from 'ember-data'; - - const { errorsArrayToHash } = DS; - - let errorsArray = [ - { - title: 'Invalid Attribute', - detail: 'Must be present', - source: { pointer: '/data/attributes/name' } - }, - { - title: 'Invalid Attribute', - detail: 'Must be present', - source: { pointer: '/data/attributes/age' } - }, - { - title: 'Invalid Attribute', - detail: 'Must be a number', - source: { pointer: '/data/attributes/age' } - } - ]; - - let errors = errorsArrayToHash(errorsArray); - // { - // "name": ["Must be present"], - // "age": ["Must be present", "must be a number"] - // } - ``` - - @method errorsArrayToHash - @public - @namespace - @for DS - @param {Array} errors array of errors in JSON-API format - @return {Object} -*/ -export function errorsArrayToHash(errors) { - let out = {}; - - if (Ember.isPresent(errors)) { - errors.forEach((error) => { - if (error.source && error.source.pointer) { - let key = error.source.pointer.match(SOURCE_POINTER_REGEXP); - - if (key) { - key = key[2]; - } else if (error.source.pointer.search(SOURCE_POINTER_PRIMARY_REGEXP) !== -1) { - key = PRIMARY_ATTRIBUTE_KEY; - } - - if (key) { - out[key] = out[key] || []; - out[key].push(error.detail || error.title); - } - } - }); - } - - return out; -} +export { + AdapterError, + InvalidError, + UnauthorizedError, + ForbiddenError, + NotFoundError, + ConflictError, + ServerError, + TimeoutError, + AbortError, + errorsHashToArray, + errorsArrayToHash +} from '../-private'; diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 9757afe7e6e..e9f77668727 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -6,6 +6,9 @@ import Ember from 'ember'; import Adapter from "../adapter"; import { + parseResponseHeaders, + BuildURLMixin, + isEnabled, AdapterError, InvalidError, UnauthorizedError, @@ -15,8 +18,7 @@ import { ServerError, TimeoutError, AbortError -} from './errors'; -import { parseResponseHeaders, BuildURLMixin, isEnabled } from '../-private'; +} from '../-private'; import { instrument, runInDebug, warn, deprecate } from 'ember-data/-debug'; const { diff --git a/addon/index.js b/addon/index.js index 369e193b080..e2794028db1 100644 --- a/addon/index.js +++ b/addon/index.js @@ -13,11 +13,10 @@ if (Ember.VERSION.match(/^1\.([0-9]|1[0-2])\./)) { ". Please upgrade your version of Ember, then upgrade Ember Data."); } -import InternalModel from "./-private/system/model/internal-model"; - import { Snapshot, DebugAdapter, + InternalModel, DS, BuildURLMixin, belongsTo, @@ -29,6 +28,7 @@ import { Model, Store, normalizeModelName, + Transform, DateTransform, NumberTransform, StringTransform, @@ -42,10 +42,6 @@ import { ManyArray, RecordArrayManager, Relationship, - initializeStoreService -} from './-private'; - -import { AdapterError, InvalidError, UnauthorizedError, @@ -57,10 +53,11 @@ import { AbortError, errorsHashToArray, errorsArrayToHash -} from "./adapters/errors"; +} from './-private'; import "ember-inflector"; import setupContainer from "./setup-container"; +import initializeStoreService from './instance-initializers/initialize-store-service'; import Adapter from "./adapter"; import JSONAPIAdapter from './adapters/json-api'; @@ -72,8 +69,6 @@ import JSONSerializer from './serializers/json'; import RESTSerializer from './serializers/rest'; import EmbeddedRecordsMixin from "./serializers/embedded-records-mixin"; - -import Transform from './transform'; import attr from './attr'; DS.Store = Store; diff --git a/addon/-private/instance-initializers/initialize-store-service.js b/addon/instance-initializers/initialize-store-service.js similarity index 100% rename from addon/-private/instance-initializers/initialize-store-service.js rename to addon/instance-initializers/initialize-store-service.js diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 75965ef4492..653e77c12b5 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1,13 +1,14 @@ import Ember from 'ember'; import { assert, deprecate, warn } from 'ember-data/-debug'; import Serializer from "../serializer"; -import { coerceId, modelHasAttributeOrRelationshipNamedType, normalizeModelName, isEnabled } from '../-private'; - import { - getOwner -} from '../-private/utils'; - -import { errorsArrayToHash } from "../adapters/errors"; + getOwner, + coerceId, + modelHasAttributeOrRelationshipNamedType, + normalizeModelName, + errorsArrayToHash, + isEnabled +} from '../-private'; const get = Ember.get; const isNone = Ember.isNone; diff --git a/addon/setup-container.js b/addon/setup-container.js index 34dbf7a9dce..d1807fde32f 100644 --- a/addon/setup-container.js +++ b/addon/setup-container.js @@ -1,7 +1,94 @@ -import initializeStore from './-private/initializers/store'; -import initializeTransforms from './-private/initializers/transforms'; -import initializeStoreInjections from './-private/initializers/store-injections'; -import initializeDataAdapter from './-private/initializers/data-adapter'; +import { + DebugAdapter, + Store, + NumberTransform, + DateTransform, + StringTransform, + BooleanTransform +} from './-private'; +import JSONAPISerializer from './serializers/json-api'; +import JSONSerializer from './serializers/json'; +import RESTSerializer from './serializers/rest'; +import JSONAPIAdapter from './adapters/json-api'; +import RESTAdapter from './adapters/rest'; + +function has(applicationOrRegistry, fullName) { + if (applicationOrRegistry.has) { + // < 2.1.0 + return applicationOrRegistry.has(fullName); + } else { + // 2.1.0+ + return applicationOrRegistry.hasRegistration(fullName); + } +} + +/* + Configures a registry for use with an Ember-Data + store. Accepts an optional namespace argument. + + @method initializeStore + @param {Ember.Registry} registry + */ +function initializeStore(registry) { + // registry.optionsForType for Ember < 2.1.0 + // application.registerOptionsForType for Ember 2.1.0+ + let registerOptionsForType = registry.registerOptionsForType || registry.optionsForType; + registerOptionsForType.call(registry, 'serializer', { singleton: false }); + registerOptionsForType.call(registry, 'adapter', { singleton: false }); + + registry.register('serializer:-default', JSONSerializer); + registry.register('serializer:-rest', RESTSerializer); + registry.register('adapter:-rest', RESTAdapter); + + registry.register('adapter:-json-api', JSONAPIAdapter); + registry.register('serializer:-json-api', JSONAPISerializer); + + + if (!has(registry, 'service:store')) { + registry.register('service:store', Store); + } +} + +/* + Configures a registry with injections on Ember applications + for the Ember-Data store. Accepts an optional namespace argument. + + @method initializeDebugAdapter + @param {Ember.Registry} registry + */ +function initializeDataAdapter(registry) { + registry.register('data-adapter:main', DebugAdapter); +} + +/* + Configures a registry with injections on Ember applications + for the Ember-Data store. Accepts an optional namespace argument. + + @method initializeStoreInjections + @param {Ember.Registry} registry + */ +function initializeStoreInjections(registry) { + // registry.injection for Ember < 2.1.0 + // application.inject for Ember 2.1.0+ + let inject = registry.inject || registry.injection; + inject.call(registry, 'controller', 'store', 'service:store'); + inject.call(registry, 'route', 'store', 'service:store'); + inject.call(registry, 'data-adapter', 'store', 'service:store'); +} + +/* + Configures a registry for use with Ember-Data + transforms. + + @method initializeTransforms + @param {Ember.Registry} registry + */ +function initializeTransforms(registry) { + registry.register('transform:boolean', BooleanTransform); + registry.register('transform:date', DateTransform); + registry.register('transform:number', NumberTransform); + registry.register('transform:string', StringTransform); +} export default function setupContainer(application) { initializeDataAdapter(application); diff --git a/addon/transform.js b/addon/transform.js index a13cc3fe527..0d5bdf1934a 100644 --- a/addon/transform.js +++ b/addon/transform.js @@ -1,108 +1 @@ -import Ember from 'ember'; - -/** - The `DS.Transform` class is used to serialize and deserialize model - attributes when they are saved or loaded from an - adapter. Subclassing `DS.Transform` is useful for creating custom - attributes. All subclasses of `DS.Transform` must implement a - `serialize` and a `deserialize` method. - - Example - - ```app/transforms/temperature.js - import DS from 'ember-data'; - - // Converts centigrade in the JSON to fahrenheit in the app - export default DS.Transform.extend({ - deserialize(serialized, options) { - return (serialized * 1.8) + 32; - }, - - serialize(deserialized, options) { - return (deserialized - 32) / 1.8; - } - }); - ``` - - The options passed into the `DS.attr` function when the attribute is - declared on the model is also available in the transform. - - ```app/models/post.js - export default DS.Model.extend({ - title: DS.attr('string'), - markdown: DS.attr('markdown', { - markdown: { - gfm: false, - sanitize: true - } - }) - }); - ``` - - ```app/transforms/markdown.js - export default DS.Transform.extend({ - serialize(deserialized, options) { - return deserialized.raw; - }, - - deserialize(serialized, options) { - var markdownOptions = options.markdown || {}; - - return marked(serialized, markdownOptions); - } - }); - ``` - - Usage - - ```app/models/requirement.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - name: DS.attr('string'), - temperature: DS.attr('temperature') - }); - ``` - - @class Transform - @namespace DS - */ -export default Ember.Object.extend({ - /** - When given a deserialized value from a record attribute this - method must return the serialized value. - - Example - - ```javascript - serialize(deserialized, options) { - return Ember.isEmpty(deserialized) ? null : Number(deserialized); - } - ``` - - @method serialize - @param deserialized The deserialized value - @param options hash of options passed to `DS.attr` - @return The serialized value - */ - serialize: null, - - /** - When given a serialize value from a JSON object this method must - return the deserialized value for the record attribute. - - Example - - ```javascript - deserialize(serialized, options) { - return empty(serialized) ? null : Number(serialized); - } - ``` - - @method deserialize - @param serialized The serialized value - @param options hash of options passed to `DS.attr` - @return The deserialized value - */ - deserialize: null -}); +export { Transform } from './-private'; diff --git a/app/instance-initializers/ember-data.js b/app/instance-initializers/ember-data.js index e5bf74200c8..ef21c3fe50d 100644 --- a/app/instance-initializers/ember-data.js +++ b/app/instance-initializers/ember-data.js @@ -1,4 +1,4 @@ -import initializeStoreService from 'ember-data/-private/instance-initializers/initialize-store-service'; +import initializeStoreService from 'ember-data/instance-initializers/initialize-store-service'; export default { name: "ember-data", diff --git a/index.js b/index.js index 55ae7960154..8df9f74a4b3 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,8 @@ var path = require('path'); var SilentError = require('silent-error'); var Funnel = require('broccoli-funnel'); +var Rollup = require('broccoli-rollup'); +var debug = require('broccoli-stew').debug; // allow toggling of heimdall instrumentation var INSTRUMENT_HEIMDALL = false; @@ -128,7 +130,27 @@ module.exports = { }); } - return tree; + var privateTree = 'addon/-private'; + var publicTree = tree; //new Funnel(tree, { exclude: [ /-private/ ] }); + + privateTree = new Rollup(privateTree, { + rollup: { + entry: 'index.js', + dest: '-private.js', + external: [ + 'ember', + 'ember-inflector', + 'ember-data/version', + 'ember-data/-debug', + 'ember-data/adapters/errors' + ] + // cache: true|false Defaults to true + } + }); + + privateTree = debug(privateTree, { name: 'rollup-tree' }); + + return tree; // merge([publicTree, privateTree]); }, _setupBabelOptions: function() { diff --git a/tests/unit/transform/date-test.js b/tests/unit/transform/date-test.js index f87823afc23..cf61d5d15af 100644 --- a/tests/unit/transform/date-test.js +++ b/tests/unit/transform/date-test.js @@ -4,7 +4,7 @@ import DS from 'ember-data'; import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import { parseDate } from 'ember-data/-private/ext/date'; +import { parseDate } from 'ember-data/-private'; module('unit/transform - DS.DateTransform'); diff --git a/tests/unit/utils/parse-response-headers-test.js b/tests/unit/utils/parse-response-headers-test.js index f4921c610df..b7c246cd284 100644 --- a/tests/unit/utils/parse-response-headers-test.js +++ b/tests/unit/utils/parse-response-headers-test.js @@ -1,4 +1,4 @@ -import parseResponseHeaders from 'ember-data/-private/utils/parse-response-headers'; +import { parseResponseHeaders } from 'ember-data/-private'; import { module, test } from 'qunit'; const CRLF = '\u000d\u000a'; From 1af1e21b006ebeb49457c4c12c6adb1e60398868 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 14 Apr 2017 10:35:21 -0700 Subject: [PATCH 1909/2527] ROLL'em UP --- DEBUG-rollup-tree/-private.js | 13758 ---------------- addon/-private/index.js | 6 + index.js | 33 +- tests/unit/diff-array-test.js | 2 +- tests/unit/model-test.js | 3 +- .../relationship-payload-manager-test.js | 2 +- .../relationship-payloads-test.js | 2 +- .../unit/system/snapshot-record-array-test.js | 2 +- tests/unit/utils-test.js | 2 +- 9 files changed, 28 insertions(+), 13782 deletions(-) delete mode 100644 DEBUG-rollup-tree/-private.js diff --git a/DEBUG-rollup-tree/-private.js b/DEBUG-rollup-tree/-private.js deleted file mode 100644 index 9548088ca87..00000000000 --- a/DEBUG-rollup-tree/-private.js +++ /dev/null @@ -1,13758 +0,0 @@ -import Ember from 'ember'; -import { assert, assertPolymorphicType, deprecate, instrument, runInDebug, warn } from 'ember-data/-debug'; -import { singularize } from 'ember-inflector'; -import { InvalidError } from 'ember-data/adapters/errors'; -import VERSION from 'ember-data/version'; - -const { get: get$1 , RSVP: { Promise }} = Ember; - -/** - A `PromiseArray` is an object that acts like both an `Ember.Array` - and a promise. When the promise is resolved the resulting value - will be set to the `PromiseArray`'s `content` property. This makes - it easy to create data bindings with the `PromiseArray` that will be - updated when the promise resolves. - - For more information see the [Ember.PromiseProxyMixin - documentation](/api/classes/Ember.PromiseProxyMixin.html). - - Example - - ```javascript - let promiseArray = DS.PromiseArray.create({ - promise: $.getJSON('/some/remote/data.json') - }); - - promiseArray.get('length'); // 0 - - promiseArray.then(function() { - promiseArray.get('length'); // 100 - }); - ``` - - @class PromiseArray - @namespace DS - @extends Ember.ArrayProxy - @uses Ember.PromiseProxyMixin -*/ -const PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin); - -/** - A `PromiseObject` is an object that acts like both an `Ember.Object` - and a promise. When the promise is resolved, then the resulting value - will be set to the `PromiseObject`'s `content` property. This makes - it easy to create data bindings with the `PromiseObject` that will - be updated when the promise resolves. - - For more information see the [Ember.PromiseProxyMixin - documentation](/api/classes/Ember.PromiseProxyMixin.html). - - Example - - ```javascript - let promiseObject = DS.PromiseObject.create({ - promise: $.getJSON('/some/remote/data.json') - }); - - promiseObject.get('name'); // null - - promiseObject.then(function() { - promiseObject.get('name'); // 'Tomster' - }); - ``` - - @class PromiseObject - @namespace DS - @extends Ember.ObjectProxy - @uses Ember.PromiseProxyMixin -*/ -let PromiseObject = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin); - -function promiseObject(promise, label) { - return PromiseObject.create({ - promise: Promise.resolve(promise, label) - }); -} - -function promiseArray(promise, label) { - return PromiseArray.create({ - promise: Promise.resolve(promise, label) - }); -} - -/** - A PromiseManyArray is a PromiseArray that also proxies certain method calls - to the underlying manyArray. - Right now we proxy: - - * `reload()` - * `createRecord()` - * `on()` - * `one()` - * `trigger()` - * `off()` - * `has()` - - @class PromiseManyArray - @namespace DS - @extends Ember.ArrayProxy -*/ - -function proxyToContent(method) { - return function() { - return get$1(this, 'content')[method](...arguments); - }; -} - -const PromiseManyArray = PromiseArray.extend({ - reload() { - assert('You are trying to reload an async manyArray before it has been created', get$1(this, 'content')); - this.set('promise', this.get('content').reload()); - return this; - }, - - createRecord: proxyToContent('createRecord'), - - on: proxyToContent('on'), - - one: proxyToContent('one'), - - trigger: proxyToContent('trigger'), - - off: proxyToContent('off'), - - has: proxyToContent('has') -}); - -const get$2 = Ember.get; -const set = Ember.set; -const isEmpty = Ember.isEmpty; -const makeArray = Ember.makeArray; - -const MapWithDefault = Ember.MapWithDefault; - -/** -@module ember-data -*/ - -/** - Holds validation errors for a given record, organized by attribute names. - - Every `DS.Model` has an `errors` property that is an instance of - `DS.Errors`. This can be used to display validation error - messages returned from the server when a `record.save()` rejects. - - For Example, if you had a `User` model that looked like this: - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - username: DS.attr('string'), - email: DS.attr('string') - }); - ``` - And you attempted to save a record that did not validate on the backend: - - ```javascript - let user = store.createRecord('user', { - username: 'tomster', - email: 'invalidEmail' - }); - user.save(); - ``` - - Your backend would be expected to return an error response that described - the problem, so that error messages can be generated on the app. - - API responses will be translated into instances of `DS.Errors` differently, - depending on the specific combination of adapter and serializer used. You - may want to check the documentation or the source code of the libraries - that you are using, to know how they expect errors to be communicated. - - Errors can be displayed to the user by accessing their property name - to get an array of all the error objects for that property. Each - error object is a JavaScript object with two keys: - - - `message` A string containing the error message from the backend - - `attribute` The name of the property associated with this error message - - ```handlebars - - {{#each model.errors.username as |error|}} -
      - {{error.message}} -
      - {{/each}} - - - {{#each model.errors.email as |error|}} -
      - {{error.message}} -
      - {{/each}} - ``` - - You can also access the special `messages` property on the error - object to get an array of all the error strings. - - ```handlebars - {{#each model.errors.messages as |message|}} -
      - {{message}} -
      - {{/each}} - ``` - - @class Errors - @namespace DS - @extends Ember.Object - @uses Ember.Enumerable - @uses Ember.Evented - */ -var Errors = Ember.ArrayProxy.extend(Ember.Evented, { - /** - Register with target handler - - @method registerHandlers - @param {Object} target - @param {Function} becameInvalid - @param {Function} becameValid - @deprecated - */ - registerHandlers(target, becameInvalid, becameValid) { - deprecate( - `Record errors will no longer be evented.`, false, { - id: 'ds.errors.registerHandlers', - until: '3.0.0' - }); - - this._registerHandlers(target, becameInvalid, becameValid); - }, - - - /** - Register with target handler - - @method _registerHandlers - @private - */ - _registerHandlers(target, becameInvalid, becameValid) { - this.on('becameInvalid', target, becameInvalid); - this.on('becameValid', target, becameValid); - }, - - - /** - @property errorsByAttributeName - @type {Ember.MapWithDefault} - @private - */ - errorsByAttributeName: Ember.computed(function() { - return MapWithDefault.create({ - defaultValue() { - return Ember.A(); - } - }); - }), - - /** - Returns errors for a given attribute - - ```javascript - let user = store.createRecord('user', { - username: 'tomster', - email: 'invalidEmail' - }); - user.save().catch(function(){ - user.get('errors').errorsFor('email'); // returns: - // [{attribute: "email", message: "Doesn't look like a valid email."}] - }); - ``` - - @method errorsFor - @param {String} attribute - @return {Array} - */ - errorsFor(attribute) { - return get$2(this, 'errorsByAttributeName').get(attribute); - }, - - /** - An array containing all of the error messages for this - record. This is useful for displaying all errors to the user. - - ```handlebars - {{#each model.errors.messages as |message|}} -
      - {{message}} -
      - {{/each}} - ``` - - @property messages - @type {Array} - */ - messages: Ember.computed.mapBy('content', 'message'), - - /** - @property content - @type {Array} - @private - */ - content: Ember.computed(function() { - return Ember.A(); - }), - - /** - @method unknownProperty - @private - */ - unknownProperty(attribute) { - let errors = this.errorsFor(attribute); - if (isEmpty(errors)) { return null; } - return errors; - }, - - /** - Total number of errors. - - @property length - @type {Number} - @readOnly - */ - - /** - @property isEmpty - @type {Boolean} - @readOnly - */ - isEmpty: Ember.computed.not('length').readOnly(), - - /** - Adds error messages to a given attribute and sends - `becameInvalid` event to the record. - - Example: - - ```javascript - if (!user.get('username') { - user.get('errors').add('username', 'This field is required'); - } - ``` - - @method add - @param {String} attribute - @param {(Array|String)} messages - @deprecated - */ - add(attribute, messages) { - warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.add' - }); - - let wasEmpty = get$2(this, 'isEmpty'); - - this._add(attribute, messages); - - if (wasEmpty && !get$2(this, 'isEmpty')) { - this.trigger('becameInvalid'); - } - }, - - - /** - Adds error messages to a given attribute without sending event. - - @method _add - @private - */ - _add(attribute, messages) { - messages = this._findOrCreateMessages(attribute, messages); - this.addObjects(messages); - get$2(this, 'errorsByAttributeName').get(attribute).addObjects(messages); - - this.notifyPropertyChange(attribute); - }, - - /** - @method _findOrCreateMessages - @private - */ - _findOrCreateMessages(attribute, messages) { - let errors = this.errorsFor(attribute); - let messagesArray = makeArray(messages); - let _messages = new Array(messagesArray.length); - - for (let i = 0; i < messagesArray.length; i++) { - let message = messagesArray[i]; - let err = errors.findBy('message', message); - if (err) { - _messages[i] = err; - } else { - _messages[i] = { - attribute: attribute, - message: message - }; - } - } - - return _messages; - }, - - /** - Removes all error messages from the given attribute and sends - `becameValid` event to the record if there no more errors left. - - Example: - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - email: DS.attr('string'), - twoFactorAuth: DS.attr('boolean'), - phone: DS.attr('string') - }); - ``` - - ```app/routes/user/edit.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - actions: { - save: function(user) { - if (!user.get('twoFactorAuth')) { - user.get('errors').remove('phone'); - } - user.save(); - } - } - }); - ``` - - @method remove - @param {String} attribute - @deprecated - */ - remove(attribute) { - warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.remove' - }); - - if (get$2(this, 'isEmpty')) { return; } - - this._remove(attribute); - - if (get$2(this, 'isEmpty')) { - this.trigger('becameValid'); - } - }, - - /** - Removes all error messages from the given attribute without sending event. - - @method _remove - @private - */ - _remove(attribute) { - if (get$2(this, 'isEmpty')) { return; } - - let content = this.rejectBy('attribute', attribute); - set(this, 'content', content); - get$2(this, 'errorsByAttributeName').delete(attribute); - - this.notifyPropertyChange(attribute); - }, - - /** - Removes all error messages and sends `becameValid` event - to the record. - - Example: - - ```app/routes/user/edit.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - actions: { - retrySave: function(user) { - user.get('errors').clear(); - user.save(); - } - } - }); - ``` - - @method clear - @deprecated - */ - clear() { - warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.clear' - }); - - if (get$2(this, 'isEmpty')) { return; } - - this._clear(); - this.trigger('becameValid'); - }, - - - /** - Removes all error messages. - to the record. - - @method _clear - @private - */ - _clear() { - if (get$2(this, 'isEmpty')) { return; } - - let errorsByAttributeName = get$2(this, 'errorsByAttributeName'); - let attributes = Ember.A(); - - errorsByAttributeName.forEach(function(_, attribute) { - attributes.push(attribute); - }); - - errorsByAttributeName.clear(); - attributes.forEach(function(attribute) { - this.notifyPropertyChange(attribute); - }, this); - - Ember.ArrayProxy.prototype.clear.call(this); - }, - - - /** - Checks if there is error messages for the given attribute. - - ```app/routes/user/edit.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - actions: { - save: function(user) { - if (user.get('errors').has('email')) { - return alert('Please update your email before attempting to save.'); - } - user.save(); - } - } - }); - ``` - - @method has - @param {String} attribute - @return {Boolean} true if there some errors on given attribute - */ - has(attribute) { - return !isEmpty(this.errorsFor(attribute)); - } -}); - -function isEnabled() { - return Ember.FEATURES.isEnabled(...arguments); -} - -/** - @module ember-data -*/ -/* - This file encapsulates the various states that a record can transition - through during its lifecycle. -*/ -/** - ### State - - Each record has a `currentState` property that explicitly tracks what - state a record is in at any given time. For instance, if a record is - newly created and has not yet been sent to the adapter to be saved, - it would be in the `root.loaded.created.uncommitted` state. If a - record has had local modifications made to it that are in the - process of being saved, the record would be in the - `root.loaded.updated.inFlight` state. (This state paths will be - explained in more detail below.) - - Events are sent by the record or its store to the record's - `currentState` property. How the state reacts to these events is - dependent on which state it is in. In some states, certain events - will be invalid and will cause an exception to be raised. - - States are hierarchical and every state is a substate of the - `RootState`. For example, a record can be in the - `root.deleted.uncommitted` state, then transition into the - `root.deleted.inFlight` state. If a child state does not implement - an event handler, the state manager will attempt to invoke the event - on all parent states until the root state is reached. The state - hierarchy of a record is described in terms of a path string. You - can determine a record's current state by getting the state's - `stateName` property: - - ```javascript - record.get('currentState.stateName'); - //=> "root.created.uncommitted" - ``` - - The hierarchy of valid states that ship with ember data looks like - this: - - ```text - * root - * deleted - * saved - * uncommitted - * inFlight - * empty - * loaded - * created - * uncommitted - * inFlight - * saved - * updated - * uncommitted - * inFlight - * loading - ``` - - The `DS.Model` states are themselves stateless. What that means is - that, the hierarchical states that each of *those* points to is a - shared data structure. For performance reasons, instead of each - record getting its own copy of the hierarchy of states, each record - points to this global, immutable shared instance. How does a state - know which record it should be acting on? We pass the record - instance into the state's event handlers as the first argument. - - The record passed as the first parameter is where you should stash - state about the record if needed; you should never store data on the state - object itself. - - ### Events and Flags - - A state may implement zero or more events and flags. - - #### Events - - Events are named functions that are invoked when sent to a record. The - record will first look for a method with the given name on the - current state. If no method is found, it will search the current - state's parent, and then its grandparent, and so on until reaching - the top of the hierarchy. If the root is reached without an event - handler being found, an exception will be raised. This can be very - helpful when debugging new features. - - Here's an example implementation of a state with a `myEvent` event handler: - - ```javascript - aState: DS.State.create({ - myEvent: function(manager, param) { - console.log("Received myEvent with", param); - } - }) - ``` - - To trigger this event: - - ```javascript - record.send('myEvent', 'foo'); - //=> "Received myEvent with foo" - ``` - - Note that an optional parameter can be sent to a record's `send()` method, - which will be passed as the second parameter to the event handler. - - Events should transition to a different state if appropriate. This can be - done by calling the record's `transitionTo()` method with a path to the - desired state. The state manager will attempt to resolve the state path - relative to the current state. If no state is found at that path, it will - attempt to resolve it relative to the current state's parent, and then its - parent, and so on until the root is reached. For example, imagine a hierarchy - like this: - - * created - * uncommitted <-- currentState - * inFlight - * updated - * inFlight - - If we are currently in the `uncommitted` state, calling - `transitionTo('inFlight')` would transition to the `created.inFlight` state, - while calling `transitionTo('updated.inFlight')` would transition to - the `updated.inFlight` state. - - Remember that *only events* should ever cause a state transition. You should - never call `transitionTo()` from outside a state's event handler. If you are - tempted to do so, create a new event and send that to the state manager. - - #### Flags - - Flags are Boolean values that can be used to introspect a record's current - state in a more user-friendly way than examining its state path. For example, - instead of doing this: - - ```javascript - var statePath = record.get('stateManager.currentPath'); - if (statePath === 'created.inFlight') { - doSomething(); - } - ``` - - You can say: - - ```javascript - if (record.get('isNew') && record.get('isSaving')) { - doSomething(); - } - ``` - - If your state does not set a value for a given flag, the value will - be inherited from its parent (or the first place in the state hierarchy - where it is defined). - - The current set of flags are defined below. If you want to add a new flag, - in addition to the area below, you will also need to declare it in the - `DS.Model` class. - - - * [isEmpty](DS.Model.html#property_isEmpty) - * [isLoading](DS.Model.html#property_isLoading) - * [isLoaded](DS.Model.html#property_isLoaded) - * [hasDirtyAttributes](DS.Model.html#property_hasDirtyAttributes) - * [isSaving](DS.Model.html#property_isSaving) - * [isDeleted](DS.Model.html#property_isDeleted) - * [isNew](DS.Model.html#property_isNew) - * [isValid](DS.Model.html#property_isValid) - - @namespace DS - @class RootState -*/ - -function didSetProperty(internalModel, context) { - if (context.value === context.originalValue) { - delete internalModel._attributes[context.name]; - internalModel.send('propertyWasReset', context.name); - } else if (context.value !== context.oldValue) { - internalModel.send('becomeDirty'); - } - - internalModel.updateRecordArrays(); -} - -// Implementation notes: -// -// Each state has a boolean value for all of the following flags: -// -// * isLoaded: The record has a populated `data` property. When a -// record is loaded via `store.find`, `isLoaded` is false -// until the adapter sets it. When a record is created locally, -// its `isLoaded` property is always true. -// * isDirty: The record has local changes that have not yet been -// saved by the adapter. This includes records that have been -// created (but not yet saved) or deleted. -// * isSaving: The record has been committed, but -// the adapter has not yet acknowledged that the changes have -// been persisted to the backend. -// * isDeleted: The record was marked for deletion. When `isDeleted` -// is true and `isDirty` is true, the record is deleted locally -// but the deletion was not yet persisted. When `isSaving` is -// true, the change is in-flight. When both `isDirty` and -// `isSaving` are false, the change has persisted. -// * isNew: The record was created on the client and the adapter -// did not yet report that it was successfully saved. -// * isValid: The adapter did not report any server-side validation -// failures. - -// The dirty state is a abstract state whose functionality is -// shared between the `created` and `updated` states. -// -// The deleted state shares the `isDirty` flag with the -// subclasses of `DirtyState`, but with a very different -// implementation. -// -// Dirty states have three child states: -// -// `uncommitted`: the store has not yet handed off the record -// to be saved. -// `inFlight`: the store has handed off the record to be saved, -// but the adapter has not yet acknowledged success. -// `invalid`: the record has invalid information and cannot be -// sent to the adapter yet. -const DirtyState = { - initialState: 'uncommitted', - - // FLAGS - isDirty: true, - - // SUBSTATES - - // When a record first becomes dirty, it is `uncommitted`. - // This means that there are local pending changes, but they - // have not yet begun to be saved, and are not invalid. - uncommitted: { - // EVENTS - didSetProperty, - - //TODO(Igor) reloading now triggers a - //loadingData event, though it seems fine? - loadingData() { }, - - propertyWasReset(internalModel, name) { - if (!internalModel.hasChangedAttributes()) { internalModel.send('rolledBack'); } - }, - - pushedData(internalModel) { - let token = heimdall.start('stats.uncommitted.pushedData'); - internalModel.updateChangedAttributes(); - - if (!internalModel.hasChangedAttributes()) { - internalModel.transitionTo('loaded.saved'); - } - heimdall.stop(token); - }, - - becomeDirty() {}, - - willCommit(internalModel) { - internalModel.transitionTo('inFlight'); - }, - - reloadRecord(internalModel, resolve) { - resolve(internalModel.store._reloadRecord(internalModel)); - }, - - rolledBack(internalModel) { - internalModel.transitionTo('loaded.saved'); - }, - - becameInvalid(internalModel) { - internalModel.transitionTo('invalid'); - }, - - rollback(internalModel) { - internalModel.rollbackAttributes(); - internalModel.triggerLater('ready'); - } - }, - - // Once a record has been handed off to the adapter to be - // saved, it is in the 'in flight' state. Changes to the - // record cannot be made during this window. - inFlight: { - // FLAGS - isSaving: true, - - // EVENTS - didSetProperty, - becomeDirty() { }, - pushedData() { }, - - unloadRecord: assertAgainstUnloadRecord, - - // TODO: More robust semantics around save-while-in-flight - willCommit() { }, - - didCommit(internalModel) { - internalModel.transitionTo('saved'); - internalModel.send('invokeLifecycleCallbacks', this.dirtyType); - }, - - becameInvalid(internalModel) { - internalModel.transitionTo('invalid'); - internalModel.send('invokeLifecycleCallbacks'); - }, - - becameError(internalModel) { - internalModel.transitionTo('uncommitted'); - internalModel.triggerLater('becameError', internalModel); - } - }, - - // A record is in the `invalid` if the adapter has indicated - // the the record failed server-side invalidations. - invalid: { - // FLAGS - isValid: false, - - // EVENTS - deleteRecord(internalModel) { - internalModel.transitionTo('deleted.uncommitted'); - }, - - didSetProperty(internalModel, context) { - internalModel.removeErrorMessageFromAttribute(context.name); - - didSetProperty(internalModel, context); - - if (!internalModel.hasErrors()) { - this.becameValid(internalModel); - } - }, - - becameInvalid() { }, - becomeDirty() { }, - pushedData() { }, - - willCommit(internalModel) { - internalModel.clearErrorMessages(); - internalModel.transitionTo('inFlight'); - }, - - rolledBack(internalModel) { - internalModel.clearErrorMessages(); - internalModel.transitionTo('loaded.saved'); - internalModel.triggerLater('ready'); - }, - - becameValid(internalModel) { - internalModel.transitionTo('uncommitted'); - }, - - invokeLifecycleCallbacks(internalModel) { - internalModel.triggerLater('becameInvalid', internalModel); - } - } -}; - -// The created and updated states are created outside the state -// chart so we can reopen their substates and add mixins as -// necessary. - -function deepClone(object) { - const clone = {}; - let value; - - for (let prop in object) { - value = object[prop]; - if (value && typeof value === 'object') { - clone[prop] = deepClone(value); - } else { - clone[prop] = value; - } - } - - return clone; -} - -function mixin(original, hash) { - for (let prop in hash) { - original[prop] = hash[prop]; - } - - return original; -} - -function dirtyState(options) { - var newState = deepClone(DirtyState); - return mixin(newState, options); -} - -const createdState = dirtyState({ - dirtyType: 'created', - // FLAGS - isNew: true -}); - -createdState.invalid.rolledBack = function(internalModel) { - internalModel.transitionTo('deleted.saved'); -}; - -createdState.uncommitted.rolledBack = function(internalModel) { - internalModel.transitionTo('deleted.saved'); -}; - -const updatedState = dirtyState({ - dirtyType: 'updated' -}); - -function createdStateDeleteRecord(internalModel) { - internalModel.transitionTo('deleted.saved'); - internalModel.send('invokeLifecycleCallbacks'); -} - -createdState.uncommitted.deleteRecord = createdStateDeleteRecord; - -createdState.invalid.deleteRecord = createdStateDeleteRecord; - -createdState.uncommitted.rollback = function(internalModel) { - DirtyState.uncommitted.rollback.apply(this, arguments); - internalModel.transitionTo('deleted.saved'); -}; - -createdState.uncommitted.pushedData = function(internalModel) { - internalModel.transitionTo('loaded.updated.uncommitted'); - internalModel.triggerLater('didLoad'); -}; - -createdState.uncommitted.propertyWasReset = function() {}; - -function assertAgainstUnloadRecord(internalModel) { - assert("You can only unload a record which is not inFlight. `" + internalModel + "`", false); -} - -updatedState.inFlight.unloadRecord = assertAgainstUnloadRecord; - -updatedState.uncommitted.deleteRecord = function(internalModel) { - internalModel.transitionTo('deleted.uncommitted'); -}; - -const RootState = { - // FLAGS - isEmpty: false, - isLoading: false, - isLoaded: false, - isDirty: false, - isSaving: false, - isDeleted: false, - isNew: false, - isValid: true, - - // DEFAULT EVENTS - - // Trying to roll back if you're not in the dirty state - // doesn't change your state. For example, if you're in the - // in-flight state, rolling back the record doesn't move - // you out of the in-flight state. - rolledBack() { }, - unloadRecord(internalModel) { - }, - - propertyWasReset() { }, - - // SUBSTATES - - // A record begins its lifecycle in the `empty` state. - // If its data will come from the adapter, it will - // transition into the `loading` state. Otherwise, if - // the record is being created on the client, it will - // transition into the `created` state. - empty: { - isEmpty: true, - - // EVENTS - loadingData(internalModel, promise) { - internalModel._loadingPromise = promise; - internalModel.transitionTo('loading'); - }, - - loadedData(internalModel) { - internalModel.transitionTo('loaded.created.uncommitted'); - internalModel.triggerLater('ready'); - }, - - pushedData(internalModel) { - internalModel.transitionTo('loaded.saved'); - internalModel.triggerLater('didLoad'); - internalModel.triggerLater('ready'); - } - }, - - // A record enters this state when the store asks - // the adapter for its data. It remains in this state - // until the adapter provides the requested data. - // - // Usually, this process is asynchronous, using an - // XHR to retrieve the data. - loading: { - // FLAGS - isLoading: true, - - exit(internalModel) { - internalModel._loadingPromise = null; - }, - - // EVENTS - pushedData(internalModel) { - internalModel.transitionTo('loaded.saved'); - internalModel.triggerLater('didLoad'); - internalModel.triggerLater('ready'); - //TODO this seems out of place here - internalModel.didCleanError(); - }, - - becameError(internalModel) { - internalModel.triggerLater('becameError', internalModel); - }, - - notFound(internalModel) { - internalModel.transitionTo('empty'); - } - }, - - // A record enters this state when its data is populated. - // Most of a record's lifecycle is spent inside substates - // of the `loaded` state. - loaded: { - initialState: 'saved', - - // FLAGS - isLoaded: true, - - //TODO(Igor) Reloading now triggers a loadingData event, - //but it should be ok? - loadingData() { }, - - // SUBSTATES - - // If there are no local changes to a record, it remains - // in the `saved` state. - saved: { - setup(internalModel) { - if (internalModel.hasChangedAttributes()) { - internalModel.adapterDidDirty(); - } - }, - - // EVENTS - didSetProperty, - - pushedData() { }, - - becomeDirty(internalModel) { - internalModel.transitionTo('updated.uncommitted'); - }, - - willCommit(internalModel) { - internalModel.transitionTo('updated.inFlight'); - }, - - reloadRecord(internalModel, resolve) { - resolve(internalModel.store._reloadRecord(internalModel)); - }, - - deleteRecord(internalModel) { - internalModel.transitionTo('deleted.uncommitted'); - }, - - unloadRecord(internalModel) { - }, - - didCommit() {}, - - // loaded.saved.notFound would be triggered by a failed - // `reload()` on an unchanged record - notFound() { } - }, - - // A record is in this state after it has been locally - // created but before the adapter has indicated that - // it has been saved. - created: createdState, - - // A record is in this state if it has already been - // saved to the server, but there are new local changes - // that have not yet been saved. - updated: updatedState - }, - - // A record is in this state if it was deleted from the store. - deleted: { - initialState: 'uncommitted', - dirtyType: 'deleted', - - // FLAGS - isDeleted: true, - isLoaded: true, - isDirty: true, - - // TRANSITIONS - setup(internalModel) { - internalModel.updateRecordArrays(); - }, - - // SUBSTATES - - // When a record is deleted, it enters the `start` - // state. It will exit this state when the record - // starts to commit. - uncommitted: { - - // EVENTS - - willCommit(internalModel) { - internalModel.transitionTo('inFlight'); - }, - - rollback(internalModel) { - internalModel.rollbackAttributes(); - internalModel.triggerLater('ready'); - }, - - pushedData() { }, - becomeDirty() { }, - deleteRecord() { }, - - rolledBack(internalModel) { - internalModel.transitionTo('loaded.saved'); - internalModel.triggerLater('ready'); - } - }, - - // After a record starts committing, but - // before the adapter indicates that the deletion - // has saved to the server, a record is in the - // `inFlight` substate of `deleted`. - inFlight: { - // FLAGS - isSaving: true, - - // EVENTS - - unloadRecord: assertAgainstUnloadRecord, - - // TODO: More robust semantics around save-while-in-flight - willCommit() { }, - didCommit(internalModel) { - internalModel.transitionTo('saved'); - - internalModel.send('invokeLifecycleCallbacks'); - }, - - becameError(internalModel) { - internalModel.transitionTo('uncommitted'); - internalModel.triggerLater('becameError', internalModel); - }, - - becameInvalid(internalModel) { - internalModel.transitionTo('invalid'); - internalModel.triggerLater('becameInvalid', internalModel); - } - }, - - // Once the adapter indicates that the deletion has - // been saved, the record enters the `saved` substate - // of `deleted`. - saved: { - // FLAGS - isDirty: false, - - setup(internalModel) { - internalModel.clearRelationships(); - }, - - invokeLifecycleCallbacks(internalModel) { - internalModel.triggerLater('didDelete', internalModel); - internalModel.triggerLater('didCommit', internalModel); - }, - - willCommit() { }, - didCommit() { } - }, - - invalid: { - isValid: false, - - didSetProperty(internalModel, context) { - internalModel.removeErrorMessageFromAttribute(context.name); - - didSetProperty(internalModel, context); - - if (!internalModel.hasErrors()) { - this.becameValid(internalModel); - } - }, - - becameInvalid() { }, - becomeDirty() { }, - deleteRecord() { }, - willCommit() { }, - - rolledBack(internalModel) { - internalModel.clearErrorMessages(); - internalModel.transitionTo('loaded.saved'); - internalModel.triggerLater('ready'); - }, - - becameValid(internalModel) { - internalModel.transitionTo('uncommitted'); - } - - } - }, - - invokeLifecycleCallbacks(internalModel, dirtyType) { - if (dirtyType === 'created') { - internalModel.triggerLater('didCreate', internalModel); - } else { - internalModel.triggerLater('didUpdate', internalModel); - } - - internalModel.triggerLater('didCommit', internalModel); - } -}; - -function wireState(object, parent, name) { - // TODO: Use Object.create and copy instead - object = mixin(parent ? Object.create(parent) : {}, object); - object.parentState = parent; - object.stateName = name; - - for (let prop in object) { - if (!object.hasOwnProperty(prop) || prop === 'parentState' || prop === 'stateName') { continue; } - if (typeof object[prop] === 'object') { - object[prop] = wireState(object[prop], object, name + '.' + prop); - } - } - - return object; -} - -var RootState$1 = wireState(RootState, null, 'root'); - -// All modelNames are dasherized internally. Changing this function may -// require changes to other normalization hooks (such as typeForRoot). - -/** - This method normalizes a modelName into the format Ember Data uses - internally. - - @method normalizeModelName - @public - @param {String} modelName - @return {String} normalizedModelName - @for DS -*/ -function normalizeModelName(modelName) { - return Ember.String.dasherize(modelName); -} - -function typeForRelationshipMeta(meta) { - let modelName; - - modelName = meta.type || meta.key; - if (meta.kind === 'hasMany') { - modelName = singularize(normalizeModelName(modelName)); - } - return modelName; -} - -function relationshipFromMeta(meta) { - return { - key: meta.key, - kind: meta.kind, - type: typeForRelationshipMeta(meta), - options: meta.options, - name: meta.name, - parentType: meta.parentType, - isRelationship: true - }; -} - -const Map$1 = Ember.Map; -const MapWithDefault$1 = Ember.MapWithDefault; - -const relationshipsDescriptor = Ember.computed(function() { - if (Ember.testing === true && relationshipsDescriptor._cacheable === true) { - relationshipsDescriptor._cacheable = false; - } - - let map = new MapWithDefault$1({ - defaultValue() { return []; } - }); - - // Loop through each computed property on the class - this.eachComputedProperty((name, meta) => { - // If the computed property is a relationship, add - // it to the map. - if (meta.isRelationship) { - meta.key = name; - let relationshipsForType = map.get(typeForRelationshipMeta(meta)); - - relationshipsForType.push({ - name: name, - kind: meta.kind - }); - } - }); - - return map; -}).readOnly(); - -const relatedTypesDescriptor = Ember.computed(function() { - if (Ember.testing === true && relatedTypesDescriptor._cacheable === true) { - relatedTypesDescriptor._cacheable = false; - } - - let modelName; - let types = Ember.A(); - - // Loop through each computed property on the class, - // and create an array of the unique types involved - // in relationships - this.eachComputedProperty((name, meta) => { - if (meta.isRelationship) { - meta.key = name; - modelName = typeForRelationshipMeta(meta); - - assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", modelName); - - if (!types.includes(modelName)) { - assert("Trying to sideload " + name + " on " + this.toString() + " but the type doesn't exist.", !!modelName); - types.push(modelName); - } - } - }); - - return types; -}).readOnly(); - -const relationshipsByNameDescriptor = Ember.computed(function() { - if (Ember.testing === true && relationshipsByNameDescriptor._cacheable === true) { - relationshipsByNameDescriptor._cacheable = false; - } - - let map = Map$1.create(); - - this.eachComputedProperty((name, meta) => { - if (meta.isRelationship) { - meta.key = name; - let relationship = relationshipFromMeta(meta); - relationship.type = typeForRelationshipMeta(meta); - map.set(name, relationship); - } - }); - - return map; -}).readOnly(); - -const { - get, - computed, - Map -} = Ember; - -/** - @module ember-data -*/ - -function findPossibleInverses(type, inverseType, name, relationshipsSoFar) { - let possibleRelationships = relationshipsSoFar || []; - - let relationshipMap = get(inverseType, 'relationships'); - if (!relationshipMap) { return possibleRelationships; } - - let relationships = relationshipMap.get(type.modelName).filter(relationship => { - let optionsForRelationship = inverseType.metaForProperty(relationship.name).options; - - if (!optionsForRelationship.inverse) { - return true; - } - - return name === optionsForRelationship.inverse; - }); - - if (relationships) { - possibleRelationships.push.apply(possibleRelationships, relationships); - } - - //Recurse to support polymorphism - if (type.superclass) { - findPossibleInverses(type.superclass, inverseType, name, possibleRelationships); - } - - return possibleRelationships; -} - -function intersection (array1, array2) { - let result = []; - array1.forEach((element) => { - if (array2.indexOf(element) >= 0) { - result.push(element); - } - }); - - return result; -} - -const RESERVED_MODEL_PROPS = [ - 'currentState', 'data', 'store' -]; - -const retrieveFromCurrentState = computed('currentState', function(key) { - return get(this._internalModel.currentState, key); -}).readOnly(); - -/** - - The model class that all Ember Data records descend from. - This is the public API of Ember Data models. If you are using Ember Data - in your application, this is the class you should use. - If you are working on Ember Data internals, you most likely want to be dealing - with `InternalModel` - - @class Model - @namespace DS - @extends Ember.Object - @uses Ember.Evented -*/ -const Model = Ember.Object.extend(Ember.Evented, { - _internalModel: null, - store: null, - __defineNonEnumerable(property) { - this[property.name] = property.descriptor.value; - }, - - /** - If this property is `true` the record is in the `empty` - state. Empty is the first state all records enter after they have - been created. Most records created by the store will quickly - transition to the `loading` state if data needs to be fetched from - the server or the `created` state if the record is created on the - client. A record can also enter the empty state if the adapter is - unable to locate the record. - - @property isEmpty - @type {Boolean} - @readOnly - */ - isEmpty: retrieveFromCurrentState, - /** - If this property is `true` the record is in the `loading` state. A - record enters this state when the store asks the adapter for its - data. It remains in this state until the adapter provides the - requested data. - - @property isLoading - @type {Boolean} - @readOnly - */ - isLoading: retrieveFromCurrentState, - /** - If this property is `true` the record is in the `loaded` state. A - record enters this state when its data is populated. Most of a - record's lifecycle is spent inside substates of the `loaded` - state. - - Example - - ```javascript - let record = store.createRecord('model'); - record.get('isLoaded'); // true - - store.findRecord('model', 1).then(function(model) { - model.get('isLoaded'); // true - }); - ``` - - @property isLoaded - @type {Boolean} - @readOnly - */ - isLoaded: retrieveFromCurrentState, - /** - If this property is `true` the record is in the `dirty` state. The - record has local changes that have not yet been saved by the - adapter. This includes records that have been created (but not yet - saved) or deleted. - - Example - - ```javascript - let record = store.createRecord('model'); - record.get('hasDirtyAttributes'); // true - - store.findRecord('model', 1).then(function(model) { - model.get('hasDirtyAttributes'); // false - model.set('foo', 'some value'); - model.get('hasDirtyAttributes'); // true - }); - ``` - - @since 1.13.0 - @property hasDirtyAttributes - @type {Boolean} - @readOnly - */ - hasDirtyAttributes: computed('currentState.isDirty', function() { - return this.get('currentState.isDirty'); - }), - /** - If this property is `true` the record is in the `saving` state. A - record enters the saving state when `save` is called, but the - adapter has not yet acknowledged that the changes have been - persisted to the backend. - - Example - - ```javascript - let record = store.createRecord('model'); - record.get('isSaving'); // false - let promise = record.save(); - record.get('isSaving'); // true - promise.then(function() { - record.get('isSaving'); // false - }); - ``` - - @property isSaving - @type {Boolean} - @readOnly - */ - isSaving: retrieveFromCurrentState, - /** - If this property is `true` the record is in the `deleted` state - and has been marked for deletion. When `isDeleted` is true and - `hasDirtyAttributes` is true, the record is deleted locally but the deletion - was not yet persisted. When `isSaving` is true, the change is - in-flight. When both `hasDirtyAttributes` and `isSaving` are false, the - change has persisted. - - Example - - ```javascript - let record = store.createRecord('model'); - record.get('isDeleted'); // false - record.deleteRecord(); - - // Locally deleted - record.get('isDeleted'); // true - record.get('hasDirtyAttributes'); // true - record.get('isSaving'); // false - - // Persisting the deletion - let promise = record.save(); - record.get('isDeleted'); // true - record.get('isSaving'); // true - - // Deletion Persisted - promise.then(function() { - record.get('isDeleted'); // true - record.get('isSaving'); // false - record.get('hasDirtyAttributes'); // false - }); - ``` - - @property isDeleted - @type {Boolean} - @readOnly - */ - isDeleted: retrieveFromCurrentState, - /** - If this property is `true` the record is in the `new` state. A - record will be in the `new` state when it has been created on the - client and the adapter has not yet report that it was successfully - saved. - - Example - - ```javascript - let record = store.createRecord('model'); - record.get('isNew'); // true - - record.save().then(function(model) { - model.get('isNew'); // false - }); - ``` - - @property isNew - @type {Boolean} - @readOnly - */ - isNew: retrieveFromCurrentState, - /** - If this property is `true` the record is in the `valid` state. - - A record will be in the `valid` state when the adapter did not report any - server-side validation failures. - - @property isValid - @type {Boolean} - @readOnly - */ - isValid: retrieveFromCurrentState, - /** - If the record is in the dirty state this property will report what - kind of change has caused it to move into the dirty - state. Possible values are: - - - `created` The record has been created by the client and not yet saved to the adapter. - - `updated` The record has been updated by the client and not yet saved to the adapter. - - `deleted` The record has been deleted by the client and not yet saved to the adapter. - - Example - - ```javascript - let record = store.createRecord('model'); - record.get('dirtyType'); // 'created' - ``` - - @property dirtyType - @type {String} - @readOnly - */ - dirtyType: retrieveFromCurrentState, - - /** - If `true` the adapter reported that it was unable to save local - changes to the backend for any reason other than a server-side - validation error. - - Example - - ```javascript - record.get('isError'); // false - record.set('foo', 'valid value'); - record.save().then(null, function() { - record.get('isError'); // true - }); - ``` - - @property isError - @type {Boolean} - @readOnly - */ - isError: false, - - /** - If `true` the store is attempting to reload the record from the adapter. - - Example - - ```javascript - record.get('isReloading'); // false - record.reload(); - record.get('isReloading'); // true - ``` - - @property isReloading - @type {Boolean} - @readOnly - */ - isReloading: false, - - /** - All ember models have an id property. This is an identifier - managed by an external source. These are always coerced to be - strings before being used internally. Note when declaring the - attributes for a model it is an error to declare an id - attribute. - - ```javascript - let record = store.createRecord('model'); - record.get('id'); // null - - store.findRecord('model', 1).then(function(model) { - model.get('id'); // '1' - }); - ``` - - @property id - @type {String} - */ - id: null, - - /** - @property currentState - @private - @type {Object} - */ - currentState: RootState$1.empty, - - /** - When the record is in the `invalid` state this object will contain - any errors returned by the adapter. When present the errors hash - contains keys corresponding to the invalid property names - and values which are arrays of Javascript objects with two keys: - - - `message` A string containing the error message from the backend - - `attribute` The name of the property associated with this error message - - ```javascript - record.get('errors.length'); // 0 - record.set('foo', 'invalid value'); - record.save().catch(function() { - record.get('errors').get('foo'); - // [{message: 'foo should be a number.', attribute: 'foo'}] - }); - ``` - - The `errors` property us useful for displaying error messages to - the user. - - ```handlebars - - {{#each model.errors.username as |error|}} -
      - {{error.message}} -
      - {{/each}} - - {{#each model.errors.email as |error|}} -
      - {{error.message}} -
      - {{/each}} - ``` - - - You can also access the special `messages` property on the error - object to get an array of all the error strings. - - ```handlebars - {{#each model.errors.messages as |message|}} -
      - {{message}} -
      - {{/each}} - ``` - - @property errors - @type {DS.Errors} - */ - errors: computed(function() { - let errors = Errors.create(); - - errors._registerHandlers(this._internalModel, - function() { - this.send('becameInvalid'); - }, - function() { - this.send('becameValid'); - }); - return errors; - }).readOnly(), - - /** - This property holds the `DS.AdapterError` object with which - last adapter operation was rejected. - - @property adapterError - @type {DS.AdapterError} - */ - adapterError: null, - - /** - Create a JSON representation of the record, using the serialization - strategy of the store's adapter. - - `serialize` takes an optional hash as a parameter, currently - supported options are: - - - `includeId`: `true` if the record's ID should be included in the - JSON representation. - - @method serialize - @param {Object} options - @return {Object} an object whose values are primitive JSON values only - */ - serialize(options) { - return this._internalModel.createSnapshot().serialize(options); - }, - - /** - Use [DS.JSONSerializer](DS.JSONSerializer.html) to - get the JSON representation of a record. - - `toJSON` takes an optional hash as a parameter, currently - supported options are: - - - `includeId`: `true` if the record's ID should be included in the - JSON representation. - - @method toJSON - @param {Object} options - @return {Object} A JSON representation of the object. - */ - toJSON(options) { - // container is for lazy transform lookups - let serializer = this.store.serializerFor('-default'); - let snapshot = this._internalModel.createSnapshot(); - - return serializer.serialize(snapshot, options); - }, - - /** - Fired when the record is ready to be interacted with, - that is either loaded from the server or created locally. - - @event ready - */ - ready: null, - - /** - Fired when the record is loaded from the server. - - @event didLoad - */ - didLoad: null, - - /** - Fired when the record is updated. - - @event didUpdate - */ - didUpdate: null, - - /** - Fired when a new record is commited to the server. - - @event didCreate - */ - didCreate: null, - - /** - Fired when the record is deleted. - - @event didDelete - */ - didDelete: null, - - /** - Fired when the record becomes invalid. - - @event becameInvalid - */ - becameInvalid: null, - - /** - Fired when the record enters the error state. - - @event becameError - */ - becameError: null, - - /** - Fired when the record is rolled back. - - @event rolledBack - */ - rolledBack: null, - - //TODO Do we want to deprecate these? - /** - @method send - @private - @param {String} name - @param {Object} context - */ - send(name, context) { - return this._internalModel.send(name, context); - }, - - /** - @method transitionTo - @private - @param {String} name - */ - transitionTo(name) { - return this._internalModel.transitionTo(name); - }, - - - /** - Marks the record as deleted but does not save it. You must call - `save` afterwards if you want to persist it. You might use this - method if you want to allow the user to still `rollbackAttributes()` - after a delete was made. - - Example - - ```app/routes/model/delete.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - actions: { - softDelete: function() { - this.controller.get('model').deleteRecord(); - }, - confirm: function() { - this.controller.get('model').save(); - }, - undo: function() { - this.controller.get('model').rollbackAttributes(); - } - } - }); - ``` - - @method deleteRecord - */ - deleteRecord() { - this._internalModel.deleteRecord(); - }, - - /** - Same as `deleteRecord`, but saves the record immediately. - - Example - - ```app/routes/model/delete.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - actions: { - delete: function() { - let controller = this.controller; - controller.get('model').destroyRecord().then(function() { - controller.transitionToRoute('model.index'); - }); - } - } - }); - ``` - - If you pass an object on the `adapterOptions` property of the options - argument it will be passed to your adapter via the snapshot - - ```js - record.destroyRecord({ adapterOptions: { subscribe: false } }); - ``` - - ```app/adapters/post.js - import MyCustomAdapter from './custom-adapter'; - - export default MyCustomAdapter.extend({ - deleteRecord: function(store, type, snapshot) { - if (snapshot.adapterOptions.subscribe) { - // ... - } - // ... - } - }); - ``` - - @method destroyRecord - @param {Object} options - @return {Promise} a promise that will be resolved when the adapter returns - successfully or rejected if the adapter returns with an error. - */ - destroyRecord(options) { - this.deleteRecord(); - return this.save(options); - }, - - /** - Unloads the record from the store. This will cause the record to be destroyed and freed up for garbage collection. - - @method unloadRecord - */ - unloadRecord() { - if (this.isDestroyed) { return; } - this._internalModel.unloadRecord(); - }, - - /** - @method _notifyProperties - @private - */ - _notifyProperties(keys) { - Ember.beginPropertyChanges(); - let key; - for (let i = 0, length = keys.length; i < length; i++) { - key = keys[i]; - this.notifyPropertyChange(key); - } - Ember.endPropertyChanges(); - }, - - /** - Returns an object, whose keys are changed properties, and value is - an [oldProp, newProp] array. - - The array represents the diff of the canonical state with the local state - of the model. Note: if the model is created locally, the canonical state is - empty since the adapter hasn't acknowledged the attributes yet: - - Example - - ```app/models/mascot.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - name: DS.attr('string'), - isAdmin: DS.attr('boolean', { - defaultValue: false - }) - }); - ``` - - ```javascript - let mascot = store.createRecord('mascot'); - - mascot.changedAttributes(); // {} - - mascot.set('name', 'Tomster'); - mascot.changedAttributes(); // { name: [undefined, 'Tomster'] } - - mascot.set('isAdmin', true); - mascot.changedAttributes(); // { isAdmin: [undefined, true], name: [undefined, 'Tomster'] } - - mascot.save().then(function() { - mascot.changedAttributes(); // {} - - mascot.set('isAdmin', false); - mascot.changedAttributes(); // { isAdmin: [true, false] } - }); - ``` - - @method changedAttributes - @return {Object} an object, whose keys are changed properties, - and value is an [oldProp, newProp] array. - */ - changedAttributes() { - return this._internalModel.changedAttributes(); - }, - - //TODO discuss with tomhuda about events/hooks - //Bring back as hooks? - /** - @method adapterWillCommit - @private - adapterWillCommit: function() { - this.send('willCommit'); - }, - - /** - @method adapterDidDirty - @private - adapterDidDirty: function() { - this.send('becomeDirty'); - this.updateRecordArraysLater(); - }, - */ - - /** - If the model `hasDirtyAttributes` this function will discard any unsaved - changes. If the model `isNew` it will be removed from the store. - - Example - - ```javascript - record.get('name'); // 'Untitled Document' - record.set('name', 'Doc 1'); - record.get('name'); // 'Doc 1' - record.rollbackAttributes(); - record.get('name'); // 'Untitled Document' - ``` - - @since 1.13.0 - @method rollbackAttributes - */ - rollbackAttributes() { - this._internalModel.rollbackAttributes(); - }, - - /* - @method _createSnapshot - @private - */ - _createSnapshot() { - return this._internalModel.createSnapshot(); - }, - - toStringExtension() { - return get(this, 'id'); - }, - - /** - Save the record and persist any changes to the record to an - external source via the adapter. - - Example - - ```javascript - record.set('name', 'Tomster'); - record.save().then(function() { - // Success callback - }, function() { - // Error callback - }); - ``` - - If you pass an object on the `adapterOptions` property of the options - argument it will be passed to you adapter via the snapshot - - ```js - record.save({ adapterOptions: { subscribe: false } }); - ``` - - ```app/adapters/post.js - import MyCustomAdapter from './custom-adapter'; - - export default MyCustomAdapter.extend({ - updateRecord: function(store, type, snapshot) { - if (snapshot.adapterOptions.subscribe) { - // ... - } - // ... - } - }); - ``` - - @method save - @param {Object} options - @return {Promise} a promise that will be resolved when the adapter returns - successfully or rejected if the adapter returns with an error. - */ - save(options) { - return PromiseObject.create({ - promise: this._internalModel.save(options).then(() => this) - }); - }, - - /** - Reload the record from the adapter. - - This will only work if the record has already finished loading. - - Example - - ```app/routes/model/view.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - actions: { - reload: function() { - this.controller.get('model').reload().then(function(model) { - // do something with the reloaded model - }); - } - } - }); - ``` - - @method reload - @return {Promise} a promise that will be resolved with the record when the - adapter returns successfully or rejected if the adapter returns - with an error. - */ - reload() { - return PromiseObject.create({ - promise: this._internalModel.reload().then(() => this) - }); - }, - - - /** - Override the default event firing from Ember.Evented to - also call methods with the given name. - - @method trigger - @private - @param {String} name - */ - trigger(name) { - let fn = this[name]; - - if (typeof fn === 'function') { - let length = arguments.length; - let args = new Array(length - 1); - - for (let i = 1; i < length; i++) { - args[i - 1] = arguments[i]; - } - fn.apply(this, args); - } - - this._super(...arguments); - }, - - // This is a temporary solution until we refactor DS.Model to not - // rely on the data property. - willMergeMixin(props) { - let constructor = this.constructor; - assert('`' + intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + constructor.toString(), !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0]); - assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + constructor.toString(), Object.keys(props).indexOf('id') === -1); - }, - - attr() { - assert("The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); - }, - - /** - Get the reference for the specified belongsTo relationship. - - Example - - ```app/models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - ``` - - ```javascript - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - } - }); - let userRef = blog.belongsTo('user'); - - // check if the user relationship is loaded - let isLoaded = userRef.value() !== null; - - // get the record of the reference (null if not yet available) - let user = userRef.value(); - - // get the identifier of the reference - if (userRef.remoteType() === "id") { - let id = userRef.id(); - } else if (userRef.remoteType() === "link") { - let link = userRef.link(); - } - - // load user (via store.findRecord or store.findBelongsTo) - userRef.load().then(...) - - // or trigger a reload - userRef.reload().then(...) - - // provide data for reference - userRef.push({ - type: 'user', - id: 1, - attributes: { - username: "@user" - } - }).then(function(user) { - userRef.value() === user; - }); - ``` - - @method belongsTo - @param {String} name of the relationship - @since 2.5.0 - @return {BelongsToReference} reference for this relationship - */ - belongsTo(name) { - return this._internalModel.referenceFor('belongsTo', name); - }, - - /** - Get the reference for the specified hasMany relationship. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - comments: { - data: [ - { type: 'comment', id: 1 }, - { type: 'comment', id: 2 } - ] - } - } - } - }); - let commentsRef = blog.hasMany('comments'); - - // check if the comments are loaded already - let isLoaded = commentsRef.value() !== null; - - // get the records of the reference (null if not yet available) - let comments = commentsRef.value(); - - // get the identifier of the reference - if (commentsRef.remoteType() === "ids") { - let ids = commentsRef.ids(); - } else if (commentsRef.remoteType() === "link") { - let link = commentsRef.link(); - } - - // load comments (via store.findMany or store.findHasMany) - commentsRef.load().then(...) - - // or trigger a reload - commentsRef.reload().then(...) - - // provide data for reference - commentsRef.push([{ type: 'comment', id: 1 }, { type: 'comment', id: 2 }]).then(function(comments) { - commentsRef.value() === comments; - }); - ``` - - @method hasMany - @param {String} name of the relationship - @since 2.5.0 - @return {HasManyReference} reference for this relationship - */ - hasMany(name) { - return this._internalModel.referenceFor('hasMany', name); - }, - - setId: Ember.observer('id', function () { - this._internalModel.setId(this.get('id')); - }), - - /** - Provides info about the model for debugging purposes - by grouping the properties into more semantic groups. - - Meant to be used by debugging tools such as the Chrome Ember Extension. - - - Groups all attributes in "Attributes" group. - - Groups all belongsTo relationships in "Belongs To" group. - - Groups all hasMany relationships in "Has Many" group. - - Groups all flags in "Flags" group. - - Flags relationship CPs as expensive properties. - - @method _debugInfo - @for DS.Model - @private - */ - _debugInfo() { - let attributes = ['id']; - let relationships = { }; - let expensiveProperties = []; - - this.eachAttribute((name, meta) => attributes.push(name)); - - let groups = [ - { - name: 'Attributes', - properties: attributes, - expand: true - } - ]; - - this.eachRelationship((name, relationship) => { - let properties = relationships[relationship.kind]; - - if (properties === undefined) { - properties = relationships[relationship.kind] = []; - groups.push({ - name: relationship.name, - properties, - expand: true - }); - } - properties.push(name); - expensiveProperties.push(name); - }); - - groups.push({ - name: 'Flags', - properties: ['isLoaded', 'hasDirtyAttributes', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'] - }); - - return { - propertyInfo: { - // include all other mixins / properties (not just the grouped ones) - includeOtherProperties: true, - groups: groups, - // don't pre-calculate unless cached - expensiveProperties: expensiveProperties - } - }; - }, - - notifyBelongsToChanged(key) { - this.notifyPropertyChange(key); - }, - - /** - This Ember.js hook allows an object to be notified when a property - is defined. - - In this case, we use it to be notified when an Ember Data user defines a - belongs-to relationship. In that case, we need to set up observers for - each one, allowing us to track relationship changes and automatically - reflect changes in the inverse has-many array. - - This hook passes the class being set up, as well as the key and value - being defined. So, for example, when the user does this: - - ```javascript - DS.Model.extend({ - parent: DS.belongsTo('user') - }); - ``` - - This hook would be called with "parent" as the key and the computed - property returned by `DS.belongsTo` as the value. - - @method didDefineProperty - @param {Object} proto - @param {String} key - @param {Ember.ComputedProperty} value - */ - didDefineProperty(proto, key, value) { - // Check if the value being set is a computed property. - if (value instanceof Ember.ComputedProperty) { - - // If it is, get the metadata for the relationship. This is - // populated by the `DS.belongsTo` helper when it is creating - // the computed property. - let meta = value.meta(); - - meta.parentType = proto.constructor; - } - }, - - /** - Given a callback, iterates over each of the relationships in the model, - invoking the callback with the name of each relationship and its relationship - descriptor. - - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, descriptor); - ``` - - - `name` the name of the current property in the iteration - - `descriptor` the meta object that describes this relationship - - The relationship descriptor argument is an object with the following properties. - - - **key** String the name of this relationship on the Model - - **kind** String "hasMany" or "belongsTo" - - **options** Object the original options hash passed when the relationship was declared - - **parentType** DS.Model the type of the Model that owns this relationship - - **type** String the type name of the related Model - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - serialize: function(record, options) { - let json = {}; - - record.eachRelationship(function(name, descriptor) { - if (descriptor.kind === 'hasMany') { - let serializedHasManyName = name.toUpperCase() + '_IDS'; - json[serializedHasManyName] = record.get(name).mapBy('id'); - } - }); - - return json; - } - }); - ``` - - @method eachRelationship - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelationship(callback, binding) { - this.constructor.eachRelationship(callback, binding); - }, - - relationshipFor(name) { - return get(this.constructor, 'relationshipsByName').get(name); - }, - - inverseFor(key) { - return this.constructor.inverseFor(key, this.store); - }, - - notifyHasManyAdded(key) { - //We need to notifyPropertyChange in the adding case because we need to make sure - //we fetch the newly added record in case it is unloaded - //TODO(Igor): Consider whether we could do this only if the record state is unloaded - - //Goes away once hasMany is double promisified - this.notifyPropertyChange(key); - }, - - eachAttribute(callback, binding) { - this.constructor.eachAttribute(callback, binding); - } -}); - -/** - @property data - @private - @type {Object} - */ -Object.defineProperty(Model.prototype, 'data', { - get() { - return this._internalModel._data; - } -}); - -runInDebug(function() { - Model.reopen({ - init() { - this._super(...arguments); - - if (!this._internalModel) { - throw new Ember.Error('You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.'); - } - } - }); -}); - -Model.reopenClass({ - isModel: true, - - /** - Override the class' `create()` method to raise an error. This - prevents end users from inadvertently calling `create()` instead - of `createRecord()`. The store is still able to create instances - by calling the `_create()` method. To create an instance of a - `DS.Model` use [store.createRecord](DS.Store.html#method_createRecord). - - @method create - @private - @static - */ - /** - Represents the model's class name as a string. This can be used to look up the model's class name through - `DS.Store`'s modelFor method. - - `modelName` is generated for you by Ember Data. It will be a lowercased, dasherized string. - For example: - - ```javascript - store.modelFor('post').modelName; // 'post' - store.modelFor('blog-post').modelName; // 'blog-post' - ``` - - The most common place you'll want to access `modelName` is in your serializer's `payloadKeyFromModelName` method. For example, to change payload - keys to underscore (instead of dasherized), you might use the following code: - - ```javascript - export default const PostSerializer = DS.RESTSerializer.extend({ - payloadKeyFromModelName: function(modelName) { - return Ember.String.underscore(modelName); - } - }); - ``` - @property modelName - @type String - @readonly - @static - */ - modelName: null, - - /* - These class methods below provide relationship - introspection abilities about relationships. - - A note about the computed properties contained here: - - **These properties are effectively sealed once called for the first time.** - To avoid repeatedly doing expensive iteration over a model's fields, these - values are computed once and then cached for the remainder of the runtime of - your application. - - If your application needs to modify a class after its initial definition - (for example, using `reopen()` to add additional attributes), make sure you - do it before using your model with the store, which uses these properties - extensively. - */ - - /** - For a given relationship name, returns the model type of the relationship. - - For example, if you define a model like this: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - comments: DS.hasMany('comment') - }); - ``` - - Calling `store.modelFor('post').typeForRelationship('comments', store)` will return `Comment`. - - @method typeForRelationship - @static - @param {String} name the name of the relationship - @param {store} store an instance of DS.Store - @return {DS.Model} the type of the relationship, or undefined - */ - typeForRelationship(name, store) { - let relationship = get(this, 'relationshipsByName').get(name); - return relationship && store.modelFor(relationship.type); - }, - - inverseMap: Ember.computed(function() { - return Object.create(null); - }), - - /** - Find the relationship which is the inverse of the one asked for. - - For example, if you define models like this: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - comments: DS.hasMany('message') - }); - ``` - - ```app/models/message.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - owner: DS.belongsTo('post') - }); - ``` - - ``` js - store.modelFor('post').inverseFor('comments', store) // { type: App.Message, name: 'owner', kind: 'belongsTo' } - store.modelFor('message').inverseFor('owner', store) // { type: App.Post, name: 'comments', kind: 'hasMany' } - ``` - - @method inverseFor - @static - @param {String} name the name of the relationship - @param {DS.Store} store - @return {Object} the inverse relationship, or null - */ - inverseFor(name, store) { - let inverseMap = get(this, 'inverseMap'); - if (inverseMap[name] !== undefined) { - return inverseMap[name]; - } else { - let relationship = get(this, 'relationshipsByName').get(name); - if (!relationship) { - inverseMap[name] = null; - return null; - } - - let options = relationship.options; - if (options && options.inverse === null) { - // populate the cache with a miss entry so we can skip getting and going - // through `relationshipsByName` - inverseMap[name] = null; - return null; - } - - return inverseMap[name] = this._findInverseFor(name, store); - } - }, - - //Calculate the inverse, ignoring the cache - _findInverseFor(name, store) { - - let inverseType = this.typeForRelationship(name, store); - if (!inverseType) { - return null; - } - - let propertyMeta = this.metaForProperty(name); - //If inverse is manually specified to be null, like `comments: DS.hasMany('message', { inverse: null })` - let options = propertyMeta.options; - if (options.inverse === null) { return null; } - - let inverseName, inverseKind, inverse; - - //If inverse is specified manually, return the inverse - if (options.inverse) { - inverseName = options.inverse; - inverse = Ember.get(inverseType, 'relationshipsByName').get(inverseName); - - assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.modelName + - "' model. This is most likely due to a missing attribute on your model definition.", !Ember.isNone(inverse)); - - inverseKind = inverse.kind; - } else { - //No inverse was specified manually, we need to use a heuristic to guess one - if (propertyMeta.type === propertyMeta.parentType.modelName) { - warn(`Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at http://emberjs.com/guides/models/defining-models/#toc_reflexive-relation for how to explicitly specify inverses.`, false, { - id: 'ds.model.reflexive-relationship-without-inverse' - }); - } - - let possibleRelationships = findPossibleInverses(this, inverseType, name); - - if (possibleRelationships.length === 0) { return null; } - - let filteredRelationships = possibleRelationships.filter((possibleRelationship) => { - let optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options; - return name === optionsForRelationship.inverse; - }); - - assert("You defined the '" + name + "' relationship on " + this + ", but you defined the inverse relationships of type " + - inverseType.toString() + " multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", - filteredRelationships.length < 2); - - if (filteredRelationships.length === 1 ) { - possibleRelationships = filteredRelationships; - } - - assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + - this + " were found on " + inverseType + ". Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", - possibleRelationships.length === 1); - - inverseName = possibleRelationships[0].name; - inverseKind = possibleRelationships[0].kind; - } - - return { - type: inverseType, - name: inverseName, - kind: inverseKind - }; - }, - - /** - The model's relationships as a map, keyed on the type of the - relationship. The value of each entry is an array containing a descriptor - for each relationship with that type, describing the name of the relationship - as well as the type. - - For example, given the following model definition: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - posts: DS.hasMany('post') - }); - ``` - - This computed property would return a map describing these - relationships, like this: - - ```javascript - import Ember from 'ember'; - import Blog from 'app/models/blog'; - import User from 'app/models/user'; - import Post from 'app/models/post'; - - let relationships = Ember.get(Blog, 'relationships'); - relationships.get(User); - //=> [ { name: 'users', kind: 'hasMany' }, - // { name: 'owner', kind: 'belongsTo' } ] - relationships.get(Post); - //=> [ { name: 'posts', kind: 'hasMany' } ] - ``` - - @property relationships - @static - @type Ember.Map - @readOnly - */ - - relationships: relationshipsDescriptor, - - /** - A hash containing lists of the model's relationships, grouped - by the relationship kind. For example, given a model with this - definition: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - import Ember from 'ember'; - import Blog from 'app/models/blog'; - - let relationshipNames = Ember.get(Blog, 'relationshipNames'); - relationshipNames.hasMany; - //=> ['users', 'posts'] - relationshipNames.belongsTo; - //=> ['owner'] - ``` - - @property relationshipNames - @static - @type Object - @readOnly - */ - relationshipNames: Ember.computed(function() { - let names = { - hasMany: [], - belongsTo: [] - }; - - this.eachComputedProperty((name, meta) => { - if (meta.isRelationship) { - names[meta.kind].push(name); - } - }); - - return names; - }), - - /** - An array of types directly related to a model. Each type will be - included once, regardless of the number of relationships it has with - the model. - - For example, given a model with this definition: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - import Ember from 'ember'; - import Blog from 'app/models/blog'; - - let relatedTypes = Ember.get(Blog, 'relatedTypes'); - //=> [ User, Post ] - ``` - - @property relatedTypes - @static - @type Ember.Array - @readOnly - */ - relatedTypes: relatedTypesDescriptor, - - /** - A map whose keys are the relationships of a model and whose values are - relationship descriptors. - - For example, given a model with this - definition: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - import Ember from 'ember'; - import Blog from 'app/models/blog'; - - let relationshipsByName = Ember.get(Blog, 'relationshipsByName'); - relationshipsByName.get('users'); - //=> { key: 'users', kind: 'hasMany', type: 'user', options: Object, isRelationship: true } - relationshipsByName.get('owner'); - //=> { key: 'owner', kind: 'belongsTo', type: 'user', options: Object, isRelationship: true } - ``` - - @property relationshipsByName - @static - @type Ember.Map - @readOnly - */ - relationshipsByName: relationshipsByNameDescriptor, - - /** - A map whose keys are the fields of the model and whose values are strings - describing the kind of the field. A model's fields are the union of all of its - attributes and relationships. - - For example: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post'), - - title: DS.attr('string') - }); - ``` - - ```js - import Ember from 'ember'; - import Blog from 'app/models/blog'; - - let fields = Ember.get(Blog, 'fields'); - fields.forEach(function(kind, field) { - console.log(field, kind); - }); - - // prints: - // users, hasMany - // owner, belongsTo - // posts, hasMany - // title, attribute - ``` - - @property fields - @static - @type Ember.Map - @readOnly - */ - fields: Ember.computed(function() { - let map = Map.create(); - - this.eachComputedProperty((name, meta) => { - if (meta.isRelationship) { - map.set(name, meta.kind); - } else if (meta.isAttribute) { - map.set(name, 'attribute'); - } - }); - - return map; - }).readOnly(), - - /** - Given a callback, iterates over each of the relationships in the model, - invoking the callback with the name of each relationship and its relationship - descriptor. - - @method eachRelationship - @static - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelationship(callback, binding) { - get(this, 'relationshipsByName').forEach((relationship, name) => { - callback.call(binding, name, relationship); - }); - }, - - /** - Given a callback, iterates over each of the types related to a model, - invoking the callback with the related type's class. Each type will be - returned just once, regardless of how many different relationships it has - with a model. - - @method eachRelatedType - @static - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelatedType(callback, binding) { - let relationshipTypes = get(this, 'relatedTypes'); - - for (let i = 0; i < relationshipTypes.length; i++) { - let type = relationshipTypes[i]; - callback.call(binding, type); - } - }, - - determineRelationshipType(knownSide, store) { - let knownKey = knownSide.key; - let knownKind = knownSide.kind; - let inverse = this.inverseFor(knownKey, store); - // let key; - let otherKind; - - if (!inverse) { - return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone'; - } - - // key = inverse.name; - otherKind = inverse.kind; - - if (otherKind === 'belongsTo') { - return knownKind === 'belongsTo' ? 'oneToOne' : 'manyToOne'; - } else { - return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany'; - } - }, - - /** - A map whose keys are the attributes of the model (properties - described by DS.attr) and whose values are the meta object for the - property. - - Example - - ```app/models/person.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - birthday: DS.attr('date') - }); - ``` - - ```javascript - import Ember from 'ember'; - import Person from 'app/models/person'; - - let attributes = Ember.get(Person, 'attributes') - - attributes.forEach(function(meta, name) { - console.log(name, meta); - }); - - // prints: - // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} - // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} - // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} - ``` - - @property attributes - @static - @type {Ember.Map} - @readOnly - */ - attributes: Ember.computed(function() { - let map = Map.create(); - - this.eachComputedProperty((name, meta) => { - if (meta.isAttribute) { - assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.toString(), name !== 'id'); - - meta.name = name; - map.set(name, meta); - } - }); - - return map; - }).readOnly(), - - /** - A map whose keys are the attributes of the model (properties - described by DS.attr) and whose values are type of transformation - applied to each attribute. This map does not include any - attributes that do not have an transformation type. - - Example - - ```app/models/person.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - firstName: DS.attr(), - lastName: DS.attr('string'), - birthday: DS.attr('date') - }); - ``` - - ```javascript - import Ember from 'ember'; - import Person from 'app/models/person'; - - let transformedAttributes = Ember.get(Person, 'transformedAttributes') - - transformedAttributes.forEach(function(field, type) { - console.log(field, type); - }); - - // prints: - // lastName string - // birthday date - ``` - - @property transformedAttributes - @static - @type {Ember.Map} - @readOnly - */ - transformedAttributes: Ember.computed(function() { - let map = Map.create(); - - this.eachAttribute((key, meta) => { - if (meta.type) { - map.set(key, meta.type); - } - }); - - return map; - }).readOnly(), - - /** - Iterates through the attributes of the model, calling the passed function on each - attribute. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, meta); - ``` - - - `name` the name of the current property in the iteration - - `meta` the meta object for the attribute property in the iteration - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```javascript - import DS from 'ember-data'; - - let Person = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - birthday: DS.attr('date') - }); - - Person.eachAttribute(function(name, meta) { - console.log(name, meta); - }); - - // prints: - // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} - // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} - // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} - ``` - - @method eachAttribute - @param {Function} callback The callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - @static - */ - eachAttribute(callback, binding) { - get(this, 'attributes').forEach((meta, name) => { - callback.call(binding, name, meta); - }); - }, - - /** - Iterates through the transformedAttributes of the model, calling - the passed function on each attribute. Note the callback will not be - called for any attributes that do not have an transformation type. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, type); - ``` - - - `name` the name of the current property in the iteration - - `type` a string containing the name of the type of transformed - applied to the attribute - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```javascript - import DS from 'ember-data'; - - let Person = DS.Model.extend({ - firstName: DS.attr(), - lastName: DS.attr('string'), - birthday: DS.attr('date') - }); - - Person.eachTransformedAttribute(function(name, type) { - console.log(name, type); - }); - - // prints: - // lastName string - // birthday date - ``` - - @method eachTransformedAttribute - @param {Function} callback The callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - @static - */ - eachTransformedAttribute(callback, binding) { - get(this, 'transformedAttributes').forEach((type, name) => { - callback.call(binding, name, type); - }); - } -}); - -// if `Ember.setOwner` is defined, accessing `this.container` is -// deprecated (but functional). In "standard" Ember usage, this -// deprecation is actually created via an `.extend` of the factory -// inside the container itself, but that only happens on models -// with MODEL_FACTORY_INJECTIONS enabled :( -if (Ember.setOwner) { - Object.defineProperty(Model.prototype, 'container', { - configurable: true, - enumerable: false, - get() { - deprecate('Using the injected `container` is deprecated. Please use the `getOwner` helper instead to access the owner of this object.', - false, - { id: 'ember-application.injected-container', until: '3.0.0' }); - - return this.store.container; - } - }); -} - -if (isEnabled('ds-rollback-attribute')) { - Model.reopen({ - /** - Discards any unsaved changes to the given attribute. This feature is not enabled by default. You must enable `ds-rollback-attribute` and be running a canary build. - - Example - - ```javascript - record.get('name'); // 'Untitled Document' - record.set('name', 'Doc 1'); - record.get('name'); // 'Doc 1' - record.rollbackAttribute('name'); - record.get('name'); // 'Untitled Document' - ``` - - @method rollbackAttribute - */ - rollbackAttribute(attributeName) { - if (attributeName in this._internalModel._attributes) { - this.set(attributeName, this._internalModel.lastAcknowledgedValue(attributeName)); - } - } - }); -} - -const EmberOrderedSet = Ember.OrderedSet; -const guidFor = Ember.guidFor; - -function OrderedSet() { - this._super$constructor(); -} - -OrderedSet.create = function() { - let Constructor = this; - return new Constructor(); -}; - -OrderedSet.prototype = Object.create(EmberOrderedSet.prototype); -OrderedSet.prototype.constructor = OrderedSet; -OrderedSet.prototype._super$constructor = EmberOrderedSet; - -OrderedSet.prototype.addWithIndex = function(obj, idx) { - let guid = guidFor(obj); - let presenceSet = this.presenceSet; - let list = this.list; - - if (presenceSet[guid] === true) { - return; - } - - presenceSet[guid] = true; - - if (idx === undefined || idx === null) { - list.push(obj); - } else { - list.splice(idx, 0, obj); - } - - this.size += 1; - - return this; -}; - -/* - This method normalizes a link to an "links object". If the passed link is - already an object it's returned without any modifications. - - See http://jsonapi.org/format/#document-links for more information. - - @method _normalizeLink - @private - @param {String} link - @return {Object|null} - @for DS -*/ -function _normalizeLink(link) { - switch (typeof link) { - case 'object': return link; - case 'string': return { href: link }; - } - return null; -} - -/* global heimdall */ -const { - addCanonicalInternalModel, - addCanonicalInternalModels, - addInternalModel, - addInternalModels, - clear, - findLink, - flushCanonical, - flushCanonicalLater, - newRelationship, - push, - removeCanonicalInternalModel, - removeCanonicalInternalModelFromInverse, - removeCanonicalInternalModelFromOwn, - removeCanonicalInternalModels, - removeInternalModel, - removeInternalModelFromInverse, - removeInternalModelFromOwn, - removeInternalModels, - setHasData, - setHasLoaded, - updateLink, - updateMeta, - updateInternalModelsFromAdapter -} = heimdall.registerMonitor('system.relationships.state.relationship', - 'addCanonicalInternalModel', - 'addCanonicalInternalModels', - 'addInternalModel', - 'addInternalModels', - 'clear', - 'findLink', - 'flushCanonical', - 'flushCanonicalLater', - 'newRelationship', - 'push', - 'removeCanonicalInternalModel', - 'removeCanonicalInternalModelFromInverse', - 'removeCanonicalInternalModelFromOwn', - 'removeCanonicalInternalModels', - 'removeInternalModel', - 'removeInternalModelFromInverse', - 'removeInternalModelFromOwn', - 'removeInternalModels', - 'setHasData', - 'setHasLoaded', - 'updateLink', - 'updateMeta', - 'updateInternalModelsFromAdapter' -); - -class Relationship { - constructor(store, internalModel, inverseKey, relationshipMeta) { - heimdall.increment(newRelationship); - let async = relationshipMeta.options.async; - let polymorphic = relationshipMeta.options.polymorphic; - this.members = new OrderedSet(); - this.canonicalMembers = new OrderedSet(); - this.store = store; - this.key = relationshipMeta.key; - this.inverseKey = inverseKey; - this.internalModel = internalModel; - this.isAsync = typeof async === 'undefined' ? true : async; - this.isPolymorphic = typeof polymorphic === 'undefined' ? true : polymorphic; - this.relationshipMeta = relationshipMeta; - //This probably breaks for polymorphic relationship in complex scenarios, due to - //multiple possible modelNames - this.inverseKeyForImplicit = this.internalModel.modelName + this.key; - this.linkPromise = null; - this.meta = null; - this.hasData = false; - this.hasLoaded = false; - } - - get parentType() { - return this.internalModel.modelName; - } - - removeInverseRelationships() { - if (!this.inverseKey) { return; } - - let allMembers = - // we actually want a union of members and canonicalMembers - // they should be disjoint but currently are not due to a bug - this.members.toArray().concat(this.canonicalMembers.toArray()); - - allMembers.forEach(inverseInternalModel => { - let relationship = inverseInternalModel._relationships.get(this.inverseKey); - relationship.inverseDidDematerialize(); - }); - } - - inverseDidDematerialize() {} - - updateMeta(meta) { - heimdall.increment(updateMeta); - this.meta = meta; - } - - clear() { - heimdall.increment(clear); - - let members = this.members.list; - while (members.length > 0) { - let member = members[0]; - this.removeInternalModel(member); - } - - let canonicalMembers = this.canonicalMembers.list; - while (canonicalMembers.length > 0) { - let member = canonicalMembers[0]; - this.removeCanonicalInternalModel(member); - } - } - - removeInternalModels(internalModels) { - heimdall.increment(removeInternalModels); - internalModels.forEach((internalModel) => this.removeInternalModel(internalModel)); - } - - addInternalModels(internalModels, idx) { - heimdall.increment(addInternalModels); - internalModels.forEach(internalModel => { - this.addInternalModel(internalModel, idx); - if (idx !== undefined) { - idx++; - } - }); - } - - addCanonicalInternalModels(internalModels, idx) { - heimdall.increment(addCanonicalInternalModels); - for (let i=0; i result); - } - } - - updateInternalModelsFromAdapter(internalModels) { - heimdall.increment(updateInternalModelsFromAdapter); - //TODO(Igor) move this to a proper place - //TODO Once we have adapter support, we need to handle updated and canonical changes - this.computeChanges(internalModels); - } - - notifyRecordRelationshipAdded() { } - notifyRecordRelationshipRemoved() { } - - /* - `hasData` for a relationship is a flag to indicate if we consider the - content of this relationship "known". Snapshots uses this to tell the - difference between unknown (`undefined`) or empty (`null`). The reason for - this is that we wouldn't want to serialize unknown relationships as `null` - as that might overwrite remote state. - - All relationships for a newly created (`store.createRecord()`) are - considered known (`hasData === true`). - */ - setHasData(value) { - heimdall.increment(setHasData); - this.hasData = value; - } - - /* - `hasLoaded` is a flag to indicate if we have gotten data from the adapter or - not when the relationship has a link. - - This is used to be able to tell when to fetch the link and when to return - the local data in scenarios where the local state is considered known - (`hasData === true`). - - Updating the link will automatically set `hasLoaded` to `false`. - */ - setHasLoaded(value) { - heimdall.increment(setHasLoaded); - this.hasLoaded = value; - } - - /* - `push` for a relationship allows the store to push a JSON API Relationship - Object onto the relationship. The relationship will then extract and set the - meta, data and links of that relationship. - - `push` use `updateMeta`, `updateData` and `updateLink` to update the state - of the relationship. - */ - push(payload, initial) { - heimdall.increment(push); - - let hasData = false; - let hasLink = false; - - if (payload.meta) { - this.updateMeta(payload.meta); - } - - if (payload.data !== undefined) { - hasData = true; - this.updateData(payload.data, initial); - } - - if (payload.links && payload.links.related) { - let relatedLink = _normalizeLink(payload.links.related); - if (relatedLink && relatedLink.href && relatedLink.href !== this.link) { - hasLink = true; - this.updateLink(relatedLink.href, initial); - } - } - - /* - Data being pushed into the relationship might contain only data or links, - or a combination of both. - - If we got data we want to set both hasData and hasLoaded to true since - this would indicate that we should prefer the local state instead of - trying to fetch the link or call findRecord(). - - If we have no data but a link is present we want to set hasLoaded to false - without modifying the hasData flag. This will ensure we fetch the updated - link next time the relationship is accessed. - */ - if (hasData) { - this.setHasData(true); - this.setHasLoaded(true); - } else if (hasLink) { - this.setHasLoaded(false); - } - } - - updateData() {} -} - -const { - get: get$7 -} = Ember; - -const { - __bind, - __guard, - __objectIsAlive -} = heimdall.registerMonitor('system.store.common', - '_bind', - '_guard', - '_objectIsAlive' -); - -function _bind(fn, ...args) { - heimdall.increment(__bind); - - return function() { - return fn.apply(undefined, args); - }; -} - -function _guard(promise, test) { - heimdall.increment(__guard); - let guarded = promise['finally'](function() { - if (!test()) { - guarded._subscribers.length = 0; - } - }); - - return guarded; -} - -function _objectIsAlive(object) { - heimdall.increment(__objectIsAlive); - return !(get$7(object, "isDestroyed") || get$7(object, "isDestroying")); -} - -/** - @namespace - @method diff-array - @for DS - @param {Array} oldArray the old array - @param {Array} newArray the new array - @return {hash} { - firstChangeIndex: , // null if no change - addedCount: , // 0 if no change - removedCount: // 0 if no change - } -*/ -function diffArray(oldArray, newArray) { - const oldLength = oldArray.length; - const newLength = newArray.length; - - const shortestLength = Math.min(oldLength, newLength); - let firstChangeIndex = null; // null signifies no changes - - // find the first change - for (let i=0; i 1 - // meta.total => 5 - }); - ``` - - @property {Object} meta - @public - */ - this.meta = this.meta || null; - - /** - `true` if the relationship is polymorphic, `false` otherwise. - - @property {Boolean} isPolymorphic - @private - */ - this.isPolymorphic = this.isPolymorphic || false; - - /** - The relationship which manages this array. - - @property {ManyRelationship} relationship - @private - */ - this.relationship = this.relationship || null; - - this.currentState = []; - this.flushCanonical(false); - }, - - objectAt(index) { - let internalModel = this.currentState[index]; - if (internalModel === undefined) { return; } - - return internalModel.getRecord(); - }, - - flushCanonical(isInitialized = true) { - // It’s possible the parent side of the relationship may have been unloaded by this point - if (!_objectIsAlive(this)) { - return; - } - let toSet = this.canonicalState; - - //a hack for not removing new records - //TODO remove once we have proper diffing - let newInternalModels = this.currentState.filter( - // only add new internalModels which are not yet in the canonical state of this - // relationship (a new internalModel can be in the canonical state if it has - // been 'acknowleged' to be in the relationship via a store.push) - (internalModel) => internalModel.isNew() && toSet.indexOf(internalModel) === -1 - ); - toSet = toSet.concat(newInternalModels); - - // diff to find changes - let diff = diffArray(this.currentState, toSet); - - if (diff.firstChangeIndex !== null) { // it's null if no change found - // we found a change - this.arrayContentWillChange(diff.firstChangeIndex, diff.removedCount, diff.addedCount); - this.set('length', toSet.length); - this.currentState = toSet; - this.arrayContentDidChange(diff.firstChangeIndex, diff.removedCount, diff.addedCount); - if (isInitialized && diff.addedCount > 0) { - //notify only on additions - //TODO only notify if unloaded - this.relationship.notifyHasManyChanged(); - } - } - }, - - internalReplace(idx, amt, objects) { - if (!objects) { - objects = []; - } - this.arrayContentWillChange(idx, amt, objects.length); - this.currentState.splice.apply(this.currentState, [idx, amt].concat(objects)); - this.set('length', this.currentState.length); - this.arrayContentDidChange(idx, amt, objects.length); - }, - - //TODO(Igor) optimize - _removeInternalModels(internalModels) { - for (let i=0; i < internalModels.length; i++) { - let index = this.currentState.indexOf(internalModels[i]); - this.internalReplace(index, 1); - } - }, - - //TODO(Igor) optimize - _addInternalModels(internalModels, idx) { - if (idx === undefined) { - idx = this.currentState.length; - } - this.internalReplace(idx, 0, internalModels); - }, - - replace(idx, amt, objects) { - let internalModels; - if (amt > 0) { - internalModels = this.currentState.slice(idx, idx+amt); - this.get('relationship').removeInternalModels(internalModels); - } - if (objects) { - this.get('relationship').addInternalModels(objects.map(obj => obj._internalModel), idx); - } - }, - - /** - Reloads all of the records in the manyArray. If the manyArray - holds a relationship that was originally fetched using a links url - Ember Data will revisit the original links url to repopulate the - relationship. - - If the manyArray holds the result of a `store.query()` reload will - re-run the original query. - - Example - - ```javascript - var user = store.peekRecord('user', 1) - user.login().then(function() { - user.get('permissions').then(function(permissions) { - return permissions.reload(); - }); - }); - ``` - - @method reload - @public - */ - reload() { - return this.relationship.reload(); - }, - - /** - Saves all of the records in the `ManyArray`. - - Example - - ```javascript - store.findRecord('inbox', 1).then(function(inbox) { - inbox.get('messages').then(function(messages) { - messages.forEach(function(message) { - message.set('isRead', true); - }); - messages.save() - }); - }); - ``` - - @method save - @return {DS.PromiseArray} promise - */ - save() { - let manyArray = this; - let promiseLabel = 'DS: ManyArray#save ' + get$6(this, 'type'); - let promise = Ember.RSVP.all(this.invoke("save"), promiseLabel). - then(() => manyArray, null, 'DS: ManyArray#save return ManyArray'); - - return PromiseArray.create({ promise }); - }, - - /** - Create a child record within the owner - - @method createRecord - @private - @param {Object} hash - @return {DS.Model} record - */ - createRecord(hash) { - const store = get$6(this, 'store'); - const type = get$6(this, 'type'); - - assert(`You cannot add '${type.modelName}' records to this polymorphic relationship.`, !get$6(this, 'isPolymorphic')); - let record = store.createRecord(type.modelName, hash); - this.pushObject(record); - - return record; - } -}); - -class ManyRelationship extends Relationship { - constructor(store, internalModel, inverseKey, relationshipMeta) { - super(store, internalModel, inverseKey, relationshipMeta); - this.belongsToType = relationshipMeta.type; - this.canonicalState = []; - this.isPolymorphic = relationshipMeta.options.polymorphic; - this._manyArray = null; - this.__loadingPromise = null; - } - - get _loadingPromise() { return this.__loadingPromise; } - _updateLoadingPromise(promise, content) { - if (this.__loadingPromise) { - if (content) { - this.__loadingPromise.set('content', content); - } - this.__loadingPromise.set('promise', promise); - } else { - this.__loadingPromise = new PromiseManyArray({ - promise, - content - }); - } - - return this.__loadingPromise; - } - - get manyArray() { - if (!this._manyArray) { - this._manyArray = ManyArray.create({ - canonicalState: this.canonicalState, - store: this.store, - relationship: this, - type: this.store.modelFor(this.belongsToType), - record: this.internalModel, - meta: this.meta, - isPolymorphic: this.isPolymorphic - }); - } - return this._manyArray; - } - - removeInverseRelationships() { - super.removeInverseRelationships(); - if (this._manyArray) { - this._manyArray.destroy(); - this._manyArray = null; - } - - if (this._loadingPromise) { - this._loadingPromise.destroy(); - } - } - - updateMeta(meta) { - super.updateMeta(meta); - if (this._manyArray) { - this._manyArray.set('meta', meta); - } - } - - addCanonicalInternalModel(internalModel, idx) { - if (this.canonicalMembers.has(internalModel)) { - return; - } - if (idx !== undefined) { - this.canonicalState.splice(idx, 0, internalModel); - } else { - this.canonicalState.push(internalModel); - } - super.addCanonicalInternalModel(internalModel, idx); - } - - inverseDidDematerialize() { - if (this._manyArray) { - this._manyArray.destroy(); - this._manyArray = null; - } - this.notifyHasManyChanged(); - } - - addInternalModel(internalModel, idx) { - if (this.members.has(internalModel)) { - return; - } - - assertPolymorphicType(this.internalModel, this.relationshipMeta, internalModel); - super.addInternalModel(internalModel, idx); - // make lazy later - this.manyArray._addInternalModels([internalModel], idx); - } - - removeCanonicalInternalModelFromOwn(internalModel, idx) { - let i = idx; - if (!this.canonicalMembers.has(internalModel)) { - return; - } - if (i === undefined) { - i = this.canonicalState.indexOf(internalModel); - } - if (i > -1) { - this.canonicalState.splice(i, 1); - } - super.removeCanonicalInternalModelFromOwn(internalModel, idx); - } - - flushCanonical() { - if (this._manyArray) { - this._manyArray.flushCanonical(); - } - super.flushCanonical(); - } - - removeInternalModelFromOwn(internalModel, idx) { - if (!this.members.has(internalModel)) { - return; - } - super.removeInternalModelFromOwn(internalModel, idx); - let manyArray = this.manyArray; - if (idx !== undefined) { - //TODO(Igor) not used currently, fix - manyArray.currentState.removeAt(idx); - } else { - manyArray._removeInternalModels([internalModel]); - } - } - - notifyRecordRelationshipAdded(internalModel, idx) { - this.internalModel.notifyHasManyAdded(this.key, internalModel, idx); - } - - reload() { - let manyArray = this.manyArray; - let manyArrayLoadedState = manyArray.get('isLoaded'); - - if (this._loadingPromise) { - if (this._loadingPromise.get('isPending')) { - return this._loadingPromise; - } - if (this._loadingPromise.get('isRejected')) { - manyArray.set('isLoaded', manyArrayLoadedState); - } - } - - let promise; - if (this.link) { - promise = this.fetchLink(); - } else { - promise = this.store._scheduleFetchMany(manyArray.currentState).then(() => manyArray); - } - - this._updateLoadingPromise(promise); - return this._loadingPromise; - } - - computeChanges(internalModels = []) { - let members = this.canonicalMembers; - let internalModelsToRemove = []; - let internalModelSet = setForArray(internalModels); - - members.forEach(member => { - if (internalModelSet.has(member)) { return; } - - internalModelsToRemove.push(member); - }); - - this.removeCanonicalInternalModels(internalModelsToRemove); - - for (let i = 0, l = internalModels.length; i < l; i++) { - let internalModel = internalModels[i]; - this.removeCanonicalInternalModel(internalModel); - this.addCanonicalInternalModel(internalModel, i); - } - } - - setInitialInternalModels(internalModels) { - if (!internalModels) { - return; - } - - let args = [0, this.canonicalState.length].concat(internalModels); - this.canonicalState.splice.apply(this.canonicalState, args); - internalModels.forEach(internalModel => { - this.canonicalMembers.add(internalModel); - this.members.add(internalModel); - this.setupInverseRelationship(internalModel); - }); - } - - fetchLink() { - return this.store.findHasMany(this.internalModel, this.link, this.relationshipMeta).then(records => { - if (records.hasOwnProperty('meta')) { - this.updateMeta(records.meta); - } - this.store._backburner.join(() => { - this.updateInternalModelsFromAdapter(records); - this.manyArray.set('isLoaded', true); - }); - return this.manyArray; - }); - } - - findRecords() { - let manyArray = this.manyArray; - let internalModels = manyArray.currentState; - - //TODO CLEANUP - return this.store.findMany(internalModels).then(() => { - if (!manyArray.get('isDestroyed')) { - //Goes away after the manyArray refactor - manyArray.set('isLoaded', true); - } - return manyArray; - }); - } - - notifyHasManyChanged() { - this.internalModel.notifyHasManyAdded(this.key); - } - - getRecords() { - //TODO(Igor) sync server here, once our syncing is not stupid - let manyArray = this.manyArray; - if (this.isAsync) { - let promise; - if (this.link) { - if (this.hasLoaded) { - promise = this.findRecords(); - } else { - promise = this.findLink().then(() => this.findRecords()); - } - } else { - promise = this.findRecords(); - } - return this._updateLoadingPromise(promise, manyArray); - } else { - assert(`You looked up the '${this.key}' relationship on a '${this.internalModel.type.modelName}' with id ${this.internalModel.id} but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async ('DS.hasMany({ async: true })')`, manyArray.isEvery('isEmpty', false)); - - //TODO(Igor) WTF DO I DO HERE? - // TODO @runspired equal WTFs to Igor - if (!manyArray.get('isDestroyed')) { - manyArray.set('isLoaded', true); - } - return manyArray; - } - } - - updateData(data, initial) { - let internalModels = this.store._pushResourceIdentifiers(this, data); - if (initial) { - this.setInitialInternalModels(internalModels); - } else { - this.updateInternalModelsFromAdapter(internalModels); - } - } -} - -function setForArray(array) { - var set = new OrderedSet(); - - if (array) { - for (var i=0, l=array.length; i { - if (internalModel) { - this.addInternalModel(internalModel); - } - return internalModel; - }); - } - - getRecord() { - //TODO(Igor) flushCanonical here once our syncing is not stupid - if (this.isAsync) { - let promise; - if (this.link) { - if (this.hasLoaded) { - promise = this.findRecord(); - } else { - promise = this.findLink().then(() => this.findRecord()); - } - } else { - promise = this.findRecord(); - } - - return PromiseObject.create({ - promise: promise, - content: this.inverseInternalModel ? this.inverseInternalModel.getRecord() : null - }); - } else { - if (this.inverseInternalModel === null) { - return null; - } - let toReturn = this.inverseInternalModel.getRecord(); - assert("You looked up the '" + this.key + "' relationship on a '" + this.internalModel.modelName + "' with id " + this.internalModel.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); - return toReturn; - } - } - - reload() { - // TODO handle case when reload() is triggered multiple times - - if (this.link) { - return this.fetchLink(); - } - - // reload record, if it is already loaded - if (this.inverseInternalModel && this.inverseInternalModel.hasRecord) { - return this.inverseInternalModel.getRecord().reload(); - } - - return this.findRecord(); - } - - updateData(data, initial) { - assert(`Ember Data expected the data for the ${this.key} relationship on a ${this.internalModel.toString()} to be in a JSON API format and include an \`id\` and \`type\` property but it found ${Ember.inspect(data)}. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || data.id !== undefined && data.type !== undefined); - let internalModel = this.store._pushResourceIdentifier(this, data); - if (initial) { - this.setInitialCanonicalInternalModel(internalModel); - } else { - this.setCanonicalInternalModel(internalModel); - } - } -} - -const { get: get$5 } = Ember; - -function shouldFindInverse(relationshipMeta) { - let options = relationshipMeta.options; - return !(options && options.inverse === null); -} - -function createRelationshipFor(internalModel, relationshipMeta, store) { - let inverseKey; - let inverse = null; - - if (shouldFindInverse(relationshipMeta)) { - inverse = internalModel.type.inverseFor(relationshipMeta.key, store); - } else { - runInDebug(() => { - internalModel.type.typeForRelationship(relationshipMeta.key, store); - }); - } - - if (inverse) { - inverseKey = inverse.name; - } - - if (relationshipMeta.kind === 'hasMany') { - return new ManyRelationship(store, internalModel, inverseKey, relationshipMeta); - } else { - return new BelongsToRelationship(store, internalModel, inverseKey, relationshipMeta); - } -} - -class Relationships { - constructor(internalModel) { - this.internalModel = internalModel; - this.initializedRelationships = Object.create(null); - } - - // TODO @runspired deprecate this as it was never truly a record instance - get record() { - return this.internalModel; - } - - has(key) { - return !!this.initializedRelationships[key]; - } - - get(key) { - let relationships = this.initializedRelationships; - let relationship = relationships[key]; - let internalModel = this.internalModel; - - if (!relationship) { - let relationshipsByName = get$5(internalModel.type, 'relationshipsByName'); - let rel = relationshipsByName.get(key); - - if (!rel) { return undefined; } - - let relationshipPayload = internalModel.store._relationshipsPayloads.get(internalModel.modelName, internalModel.id, key); - - relationship = relationships[key] = createRelationshipFor(internalModel, rel, internalModel.store); - - if (relationshipPayload) { - relationship.push(relationshipPayload, true); - } - } - - return relationship; - } -} - -/** - @module ember-data -*/ - -const { - get: get$8 -} = Ember; - -/** - @class Snapshot - @namespace DS - @private - @constructor - @param {DS.Model} internalModel The model to create a snapshot from -*/ -class Snapshot { - constructor(internalModel, options = {}) { - this._attributes = Object.create(null); - this._belongsToRelationships = Object.create(null); - this._belongsToIds = Object.create(null); - this._hasManyRelationships = Object.create(null); - this._hasManyIds = Object.create(null); - this._internalModel = internalModel; - - let record = internalModel.getRecord(); - - /** - The underlying record for this snapshot. Can be used to access methods and - properties defined on the record. - - Example - - ```javascript - let json = snapshot.record.toJSON(); - ``` - - @property record - @type {DS.Model} - */ - this.record = record; - record.eachAttribute((keyName) => this._attributes[keyName] = get$8(record, keyName)); - - /** - The id of the snapshot's underlying record - - Example - - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postSnapshot.id; // => '1' - ``` - - @property id - @type {String} - */ - this.id = internalModel.id; - - /** - A hash of adapter options - @property adapterOptions - @type {Object} - */ - this.adapterOptions = options.adapterOptions; - this.include = options.include; - - /** - The name of the type of the underlying record for this snapshot, as a string. - - @property modelName - @type {String} - */ - this.modelName = internalModel.modelName; - - this._changedAttributes = record.changedAttributes(); - } - - /** - The type of the underlying record for this snapshot, as a DS.Model. - - @property type - @type {DS.Model} - */ - get type() { - // TODO @runspired we should deprecate this in favor of modelClass but only once - // we've cleaned up the internals enough that a public change to follow suite is - // uncontroversial. - return this._internalModel.modelClass; - } - - /** - Returns the value of an attribute. - - Example - - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postSnapshot.attr('author'); // => 'Tomster' - postSnapshot.attr('title'); // => 'Ember.js rocks' - ``` - - Note: Values are loaded eagerly and cached when the snapshot is created. - - @method attr - @param {String} keyName - @return {Object} The attribute value or undefined - */ - attr(keyName) { - if (keyName in this._attributes) { - return this._attributes[keyName]; - } - throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no attribute named '" + keyName + "' defined."); - } - - /** - Returns all attributes and their corresponding values. - - Example - - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postSnapshot.attributes(); // => { author: 'Tomster', title: 'Ember.js rocks' } - ``` - - @method attributes - @return {Object} All attributes of the current snapshot - */ - attributes() { - return Ember.copy(this._attributes); - } - - /** - Returns all changed attributes and their old and new values. - - Example - - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postModel.set('title', 'Ember.js rocks!'); - postSnapshot.changedAttributes(); // => { title: ['Ember.js rocks', 'Ember.js rocks!'] } - ``` - - @method changedAttributes - @return {Object} All changed attributes of the current snapshot - */ - changedAttributes() { - let changedAttributes = Object.create(null); - let changedAttributeKeys = Object.keys(this._changedAttributes); - - for (let i=0, length = changedAttributeKeys.length; i < length; i++) { - let key = changedAttributeKeys[i]; - changedAttributes[key] = Ember.copy(this._changedAttributes[key]); - } - - return changedAttributes; - } - - /** - Returns the current value of a belongsTo relationship. - - `belongsTo` takes an optional hash of options as a second parameter, - currently supported options are: - - - `id`: set to `true` if you only want the ID of the related record to be - returned. - - Example - - ```javascript - // store.push('post', { id: 1, title: 'Hello World' }); - // store.createRecord('comment', { body: 'Lorem ipsum', post: post }); - commentSnapshot.belongsTo('post'); // => DS.Snapshot - commentSnapshot.belongsTo('post', { id: true }); // => '1' - - // store.push('comment', { id: 1, body: 'Lorem ipsum' }); - commentSnapshot.belongsTo('post'); // => undefined - ``` - - Calling `belongsTo` will return a new Snapshot as long as there's any known - data for the relationship available, such as an ID. If the relationship is - known but unset, `belongsTo` will return `null`. If the contents of the - relationship is unknown `belongsTo` will return `undefined`. - - Note: Relationships are loaded lazily and cached upon first access. - - @method belongsTo - @param {String} keyName - @param {Object} [options] - @return {(DS.Snapshot|String|null|undefined)} A snapshot or ID of a known - relationship or null if the relationship is known but unset. undefined - will be returned if the contents of the relationship is unknown. - */ - belongsTo(keyName, options) { - let id = options && options.id; - let relationship, inverseInternalModel, hasData; - let result; - - if (id && keyName in this._belongsToIds) { - return this._belongsToIds[keyName]; - } - - if (!id && keyName in this._belongsToRelationships) { - return this._belongsToRelationships[keyName]; - } - - relationship = this._internalModel._relationships.get(keyName); - if (!(relationship && relationship.relationshipMeta.kind === 'belongsTo')) { - throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined."); - } - - hasData = get$8(relationship, 'hasData'); - inverseInternalModel = get$8(relationship, 'inverseInternalModel'); - - if (hasData) { - if (inverseInternalModel && !inverseInternalModel.isDeleted()) { - if (id) { - result = get$8(inverseInternalModel, 'id'); - } else { - result = inverseInternalModel.createSnapshot(); - } - } else { - result = null; - } - } - - if (id) { - this._belongsToIds[keyName] = result; - } else { - this._belongsToRelationships[keyName] = result; - } - - return result; - } - - /** - Returns the current value of a hasMany relationship. - - `hasMany` takes an optional hash of options as a second parameter, - currently supported options are: - - - `ids`: set to `true` if you only want the IDs of the related records to be - returned. - - Example - - ```javascript - // store.push('post', { id: 1, title: 'Hello World', comments: [2, 3] }); - postSnapshot.hasMany('comments'); // => [DS.Snapshot, DS.Snapshot] - postSnapshot.hasMany('comments', { ids: true }); // => ['2', '3'] - - // store.push('post', { id: 1, title: 'Hello World' }); - postSnapshot.hasMany('comments'); // => undefined - ``` - - Note: Relationships are loaded lazily and cached upon first access. - - @method hasMany - @param {String} keyName - @param {Object} [options] - @return {(Array|undefined)} An array of snapshots or IDs of a known - relationship or an empty array if the relationship is known but unset. - undefined will be returned if the contents of the relationship is unknown. - */ - hasMany(keyName, options) { - let ids = options && options.ids; - let relationship, members, hasData; - let results; - - if (ids && keyName in this._hasManyIds) { - return this._hasManyIds[keyName]; - } - - if (!ids && keyName in this._hasManyRelationships) { - return this._hasManyRelationships[keyName]; - } - - relationship = this._internalModel._relationships.get(keyName); - if (!(relationship && relationship.relationshipMeta.kind === 'hasMany')) { - throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined."); - } - - hasData = get$8(relationship, 'hasData'); - members = get$8(relationship, 'members'); - - if (hasData) { - results = []; - members.forEach((member) => { - if (!member.isDeleted()) { - if (ids) { - results.push(member.id); - } else { - results.push(member.createSnapshot()); - } - } - }); - } - - if (ids) { - this._hasManyIds[keyName] = results; - } else { - this._hasManyRelationships[keyName] = results; - } - - return results; - } - - /** - Iterates through all the attributes of the model, calling the passed - function on each attribute. - - Example - - ```javascript - snapshot.eachAttribute(function(name, meta) { - // ... - }); - ``` - - @method eachAttribute - @param {Function} callback the callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - */ - eachAttribute(callback, binding) { - this.record.eachAttribute(callback, binding); - } - - /** - Iterates through all the relationships of the model, calling the passed - function on each relationship. - - Example - - ```javascript - snapshot.eachRelationship(function(name, relationship) { - // ... - }); - ``` - - @method eachRelationship - @param {Function} callback the callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - */ - eachRelationship(callback, binding) { - this.record.eachRelationship(callback, binding); - } - - /** - Serializes the snapshot using the serializer for the model. - - Example - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - createRecord(store, type, snapshot) { - var data = snapshot.serialize({ includeId: true }); - var url = `/${type.modelName}`; - - return fetch(url, { - method: 'POST', - body: data, - }).then((response) => response.json()) - } - }); - ``` - - @method serialize - @param {Object} options - @return {Object} an object whose values are primitive JSON values only - */ - serialize(options) { - return this.record.store.serializerFor(this.modelName).serialize(this, options); - } -} - -const get$9 = Ember.get; - -/* - Check if the passed model has a `type` attribute or a relationship named `type`. - - @method modelHasAttributeOrRelationshipNamedType - @param modelClass - */ -function modelHasAttributeOrRelationshipNamedType(modelClass) { - return get$9(modelClass, 'attributes').has('type') || get$9(modelClass, 'relationshipsByName').has('type'); -} - -/* - ember-container-inject-owner is a new feature in Ember 2.3 that finally provides a public - API for looking items up. This function serves as a super simple polyfill to avoid - triggering deprecations. - */ -function getOwner(context) { - let owner; - - if (Ember.getOwner) { - owner = Ember.getOwner(context); - } else if (context.container) { - owner = context.container; - } - - if (owner && owner.lookupFactory && !owner._lookupFactory) { - // `owner` is a container, we are just making this work - owner._lookupFactory = owner.lookupFactory; - owner.register = function() { - let registry = owner.registry || owner._registry || owner; - - return registry.register(...arguments); - }; - } - - return owner; -} - -var Reference = function(store, internalModel) { - this.store = store; - this.internalModel = internalModel; -}; - -Reference.prototype = { - constructor: Reference -}; - -/** - An RecordReference is a low level API that allows users and - addon author to perform meta-operations on a record. - - @class RecordReference - @namespace DS -*/ -const RecordReference = function(store, internalModel) { - this._super$constructor(store, internalModel); - this.type = internalModel.modelName; - this._id = internalModel.id; -}; - -RecordReference.prototype = Object.create(Reference.prototype); -RecordReference.prototype.constructor = RecordReference; -RecordReference.prototype._super$constructor = Reference; - -/** - The `id` of the record that this reference refers to. - - Together, the `type` and `id` properties form a composite key for - the identity map. - - Example - - ```javascript - let userRef = store.getReference('user', 1); - - userRef.id(); // '1' - ``` - - @method id - @return {String} The id of the record. -*/ -RecordReference.prototype.id = function() { - return this._id; -}; - -/** - How the reference will be looked up when it is loaded: Currently - this always return `identity` to signifying that a record will be - loaded by the `type` and `id`. - - Example - - ```javascript - const userRef = store.getReference('user', 1); - - userRef.remoteType(); // 'identity' - ``` - - @method remoteType - @return {String} 'identity' -*/ -RecordReference.prototype.remoteType = function() { - return 'identity'; -}; - -/** - This API allows you to provide a reference with new data. The - simplest usage of this API is similar to `store.push`: you provide a - normalized hash of data and the object represented by the reference - will update. - - If you pass a promise to `push`, Ember Data will not ask the adapter - for the data if another attempt to fetch it is made in the - interim. When the promise resolves, the underlying object is updated - with the new data, and the promise returned by *this function* is resolved - with that object. - - For example, `recordReference.push(promise)` will be resolved with a - record. - - Example - - ```javascript - let userRef = store.getReference('user', 1); - - // provide data for reference - userRef.push({ data: { id: 1, username: "@user" }}).then(function(user) { - userRef.value() === user; - }); - ``` - - @method push - @param {Promise|Object} - @return Promise a promise for the value (record or relationship) -*/ -RecordReference.prototype.push = function(objectOrPromise) { - return Ember.RSVP.resolve(objectOrPromise).then((data) => { - return this.store.push(data); - }); -}; - -/** - If the entity referred to by the reference is already loaded, it is - present as `reference.value`. Otherwise the value returned by this function - is `null`. - - Example - - ```javascript - let userRef = store.getReference('user', 1); - - userRef.value(); // user - ``` - - @method value - @return {DS.Model} the record for this RecordReference -*/ -RecordReference.prototype.value = function() { - if (this.internalModel.hasRecord) { - return this.internalModel.getRecord(); - } -}; - -/** - Triggers a fetch for the backing entity based on its `remoteType` - (see `remoteType` definitions per reference type). - - Example - - ```javascript - let userRef = store.getReference('user', 1); - - // load user (via store.find) - userRef.load().then(...) - ``` - - @method load - @return {Promise} the record for this RecordReference -*/ -RecordReference.prototype.load = function() { - return this.store.findRecord(this.type, this._id); -}; - -/** - Reloads the record if it is already loaded. If the record is not - loaded it will load the record via `store.findRecord` - - Example - - ```javascript - let userRef = store.getReference('user', 1); - - // or trigger a reload - userRef.reload().then(...) - ``` - - @method reload - @return {Promise} the record for this RecordReference -*/ -RecordReference.prototype.reload = function() { - let record = this.value(); - if (record) { - return record.reload(); - } - - return this.load(); -}; - -// TODO import from here because else creates circular -// import Model from 'ember-data/model'; -/** - A BelongsToReference is a low level API that allows users and - addon author to perform meta-operations on a belongs-to - relationship. - - @class BelongsToReference - @namespace DS - @extends DS.Reference -*/ -const BelongsToReference = function(store, parentInternalModel, belongsToRelationship) { - this._super$constructor(store, parentInternalModel); - this.belongsToRelationship = belongsToRelationship; - this.type = belongsToRelationship.relationshipMeta.type; - this.parent = parentInternalModel.recordReference; - - // TODO inverse -}; - -BelongsToReference.prototype = Object.create(Reference.prototype); -BelongsToReference.prototype.constructor = BelongsToReference; -BelongsToReference.prototype._super$constructor = Reference; - -/** - This returns a string that represents how the reference will be - looked up when it is loaded. If the relationship has a link it will - use the "link" otherwise it defaults to "id". - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - }); - let userRef = blog.belongsTo('user'); - - // get the identifier of the reference - if (userRef.remoteType() === "id") { - let id = userRef.id(); - } else if (userRef.remoteType() === "link") { - let link = userRef.link(); - } - ``` - - @method remoteType - @return {String} The name of the remote type. This should either be "link" or "id" -*/ -BelongsToReference.prototype.remoteType = function() { - if (this.belongsToRelationship.link) { - return "link"; - } - - return "id"; -}; - -/** - The `id` of the record that this reference refers to. Together, the - `type()` and `id()` methods form a composite key for the identity - map. This can be used to access the id of an async relationship - without triggering a fetch that would normally happen if you - attempted to use `record.get('relationship.id')`. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - } - }); - let userRef = blog.belongsTo('user'); - - // get the identifier of the reference - if (userRef.remoteType() === "id") { - let id = userRef.id(); - } - ``` - - @method id - @return {String} The id of the record in this belongsTo relationship. -*/ -BelongsToReference.prototype.id = function() { - let inverseInternalModel = this.belongsToRelationship.inverseInternalModel; - return inverseInternalModel && inverseInternalModel.id; -}; - -/** - The link Ember Data will use to fetch or reload this belongs-to - relationship. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - links: { - related: '/articles/1/author' - } - } - } - } - }); - let userRef = blog.belongsTo('user'); - - // get the identifier of the reference - if (userRef.remoteType() === "link") { - let link = userRef.link(); - } - ``` - - @method link - @return {String} The link Ember Data will use to fetch or reload this belongs-to relationship. -*/ -BelongsToReference.prototype.link = function() { - return this.belongsToRelationship.link; -}; - -/** - The meta data for the belongs-to relationship. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - links: { - related: { - href: '/articles/1/author', - meta: { - lastUpdated: 1458014400000 - } - } - } - } - } - } - }); - - let userRef = blog.belongsTo('user'); - - userRef.meta() // { lastUpdated: 1458014400000 } - ``` - - @method meta - @return {Object} The meta information for the belongs-oo relationship. -*/ -BelongsToReference.prototype.meta = function() { - return this.belongsToRelationship.meta; -}; - -/** - `push` can be used to update the data in the relationship and Ember - Data will treat the new data as the conanical value of this - relationship on the backend. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - } - }); - let userRef = blog.belongsTo('user'); - - // provide data for reference - userRef.push({ - data: { - type: 'user', - id: 1, - attributes: { - username: "@user" - } - } - }).then(function(user) { - userRef.value() === user; - }); - ``` - - @method push - @param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. - @return {Promise} A promise that resolves with the new value in this belongs-to relationship. -*/ -BelongsToReference.prototype.push = function(objectOrPromise) { - return Ember.RSVP.resolve(objectOrPromise).then((data) => { - let record; - - if (data instanceof Model) { - if (isEnabled('ds-overhaul-references')) { - deprecate("BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead.", false, { - id: 'ds.references.belongs-to.push-record', - until: '3.0' - }); - } - record = data; - } else { - record = this.store.push(data); - } - - assertPolymorphicType(this.internalModel, this.belongsToRelationship.relationshipMeta, record._internalModel); - - this.belongsToRelationship.setCanonicalInternalModel(record._internalModel); - - return record; - }); -}; - -/** - `value()` synchronously returns the current value of the belongs-to - relationship. Unlike `record.get('relationshipName')`, calling - `value()` on a reference does not trigger a fetch if the async - relationship is not yet loaded. If the relationship is not loaded - it will always return `null`. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - } - }); - let userRef = blog.belongsTo('user'); - - userRef.value(); // null - - // provide data for reference - userRef.push({ - data: { - type: 'user', - id: 1, - attributes: { - username: "@user" - } - } - }).then(function(user) { - userRef.value(); // user - }); - ``` - - @method value - @param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. - @return {DS.Model} the record in this relationship -*/ -BelongsToReference.prototype.value = function() { - let inverseInternalModel = this.belongsToRelationship.inverseInternalModel; - - if (inverseInternalModel && inverseInternalModel.isLoaded()) { - return inverseInternalModel.getRecord(); - } - - return null; -}; - -/** - Loads a record in a belongs to relationship if it is not already - loaded. If the relationship is already loaded this method does not - trigger a new load. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - } - }); - let userRef = blog.belongsTo('user'); - - userRef.value(); // null - - userRef.load().then(function(user) { - userRef.value() === user - }); - - @method load - @return {Promise} a promise that resolves with the record in this belongs-to relationship. -*/ -BelongsToReference.prototype.load = function() { - if (this.remoteType() === "id") { - return this.belongsToRelationship.getRecord(); - } - - if (this.remoteType() === "link") { - return this.belongsToRelationship.findLink().then((internalModel) => { - return this.value(); - }); - } -}; - -/** - Triggers a reload of the value in this relationship. If the - remoteType is `"link"` Ember Data will use the relationship link to - reload the relationship. Otherwise it will reload the record by its - id. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - } - }); - let userRef = blog.belongsTo('user'); - - userRef.reload().then(function(user) { - userRef.value() === user - }); - - @method reload - @return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed. -*/ -BelongsToReference.prototype.reload = function() { - return this.belongsToRelationship.reload().then((internalModel) => { - return this.value(); - }); -}; - -const { - RSVP: { resolve }, - get: get$10 -} = Ember; - -/** - A HasManyReference is a low level API that allows users and addon - author to perform meta-operations on a has-many relationship. - - @class HasManyReference - @namespace DS -*/ -const HasManyReference = function(store, parentInternalModel, hasManyRelationship) { - this._super$constructor(store, parentInternalModel); - this.hasManyRelationship = hasManyRelationship; - this.type = hasManyRelationship.relationshipMeta.type; - this.parent = parentInternalModel.recordReference; - - // TODO inverse -}; - -HasManyReference.prototype = Object.create(Reference.prototype); -HasManyReference.prototype.constructor = HasManyReference; -HasManyReference.prototype._super$constructor = Reference; - -/** - This returns a string that represents how the reference will be - looked up when it is loaded. If the relationship has a link it will - use the "link" otherwise it defaults to "id". - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - // get the identifier of the reference - if (commentsRef.remoteType() === "ids") { - let ids = commentsRef.ids(); - } else if (commentsRef.remoteType() === "link") { - let link = commentsRef.link(); - } - ``` - - @method remoteType - @return {String} The name of the remote type. This should either be "link" or "ids" -*/ -HasManyReference.prototype.remoteType = function() { - if (this.hasManyRelationship.link) { - return "link"; - } - - return "ids"; -}; - -/** - The link Ember Data will use to fetch or reload this has-many - relationship. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - links: { - related: '/posts/1/comments' - } - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - commentsRef.link(); // '/posts/1/comments' - ``` - - @method link - @return {String} The link Ember Data will use to fetch or reload this has-many relationship. -*/ -HasManyReference.prototype.link = function() { - return this.hasManyRelationship.link; -}; - -/** - `ids()` returns an array of the record ids in this relationship. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - commentsRef.ids(); // ['1'] - ``` - - @method remoteType - @return {Array} The ids in this has-many relationship -*/ -HasManyReference.prototype.ids = function() { - let members = this.hasManyRelationship.members.toArray(); - - return members.map(function(internalModel) { - return internalModel.id; - }); -}; - -/** - The link Ember Data will use to fetch or reload this has-many - relationship. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - links: { - related: { - href: '/posts/1/comments', - meta: { - count: 10 - } - } - } - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - commentsRef.meta(); // { count: 10 } - ``` - - @method meta - @return {Object} The meta information for the has-many relationship. -*/ -HasManyReference.prototype.meta = function() { - return this.hasManyRelationship.meta; -}; - -/** - `push` can be used to update the data in the relationship and Ember - Data will treat the new data as the canonical value of this - relationship on the backend. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ``` - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - commentsRef.ids(); // ['1'] - - commentsRef.push([ - [{ type: 'comment', id: 2 }], - [{ type: 'comment', id: 3 }], - ]) - - commentsRef.ids(); // ['2', '3'] - ``` - - @method push - @param {Array|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. - @return {DS.ManyArray} -*/ -HasManyReference.prototype.push = function(objectOrPromise) { - return resolve(objectOrPromise).then((payload) => { - let array = payload; - - if (isEnabled("ds-overhaul-references")) { - deprecate("HasManyReference#push(array) is deprecated. Push a JSON-API document instead.", !Array.isArray(payload), { - id: 'ds.references.has-many.push-array', - until: '3.0' - }); - } - - let useLegacyArrayPush = true; - if (typeof payload === "object" && payload.data) { - array = payload.data; - useLegacyArrayPush = array.length && array[0].data; - - if (isEnabled('ds-overhaul-references')) { - deprecate("HasManyReference#push() expects a valid JSON-API document.", !useLegacyArrayPush, { - id: 'ds.references.has-many.push-invalid-json-api', - until: '3.0' - }); - } - } - - if (!isEnabled('ds-overhaul-references')) { - useLegacyArrayPush = true; - } - - let internalModels; - if (useLegacyArrayPush) { - internalModels = array.map((obj) => { - let record = this.store.push(obj); - - runInDebug(() => { - let relationshipMeta = this.hasManyRelationship.relationshipMeta; - assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel); - }); - - return record._internalModel; - }); - } else { - let records = this.store.push(payload); - internalModels = Ember.A(records).mapBy('_internalModel'); - - runInDebug(() => { - internalModels.forEach((internalModel) => { - let relationshipMeta = this.hasManyRelationship.relationshipMeta; - assertPolymorphicType(this.internalModel, relationshipMeta, internalModel); - }); - }); - } - - this.hasManyRelationship.computeChanges(internalModels); - - return this.hasManyRelationship.manyArray; - }); -}; - -HasManyReference.prototype._isLoaded = function() { - let hasData = get$10(this.hasManyRelationship, 'hasData'); - if (!hasData) { - return false; - } - - let members = this.hasManyRelationship.members.toArray(); - - return members.every(function(internalModel) { - return internalModel.isLoaded() === true; - }); -}; - -/** - `value()` sycronously returns the current value of the has-many - relationship. Unlike `record.get('relationshipName')`, calling - `value()` on a reference does not trigger a fetch if the async - relationship is not yet loaded. If the relationship is not loaded - it will always return `null`. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - post.get('comments').then(function(comments) { - commentsRef.value() === comments - }) - ``` - - @method value - @return {DS.ManyArray} -*/ -HasManyReference.prototype.value = function() { - if (this._isLoaded()) { - return this.hasManyRelationship.manyArray; - } - - return null; -}; - -/** - Loads the relationship if it is not already loaded. If the - relationship is already loaded this method does not trigger a new - load. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - commentsRef.load().then(function(comments) { - //... - }); - ``` - - @method load - @return {Promise} a promise that resolves with the ManyArray in - this has-many relationship. -*/ -HasManyReference.prototype.load = function() { - if (!this._isLoaded()) { - return this.hasManyRelationship.getRecords(); - } - - return resolve(this.hasManyRelationship.manyArray); -}; - -/** - Reloads this has-many relationship. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - commentsRef.reload().then(function(comments) { - //... - }); - ``` - - @method reload - @return {Promise} a promise that resolves with the ManyArray in this has-many relationship. -*/ -HasManyReference.prototype.reload = function() { - return this.hasManyRelationship.reload(); -}; - -const { - get: get$4, - set: set$2, - copy: copy$1, - Error: EmberError$1, - inspect: inspect$1, - isEmpty: isEmpty$1, - isEqual, - setOwner, - RSVP: RSVP$1, - RSVP: { Promise: Promise$2 } -} = Ember; - -const assign = Ember.assign || Ember.merge; - -/* - The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached - when transitioning from one state to another, so that future transitions can replay the - transition without needing to walk the state tree, collect these hook calls and determine - the state to transition into. - - A future optimization would be to build a single chained method out of the collected enters - and setups. It may also be faster to do a two level cache (from: { to }) instead of caching based - on a key that adds the two together. - */ -const TransitionChainMap = Object.create(null); - -const _extractPivotNameCache = Object.create(null); -const _splitOnDotCache = Object.create(null); - -function splitOnDot(name) { - return _splitOnDotCache[name] || ( - _splitOnDotCache[name] = name.split('.') - ); -} - -function extractPivotName(name) { - return _extractPivotNameCache[name] || ( - _extractPivotNameCache[name] = splitOnDot(name)[0] - ); -} - -function areAllModelsUnloaded(internalModels) { - for (let i=0; i { - if (this._relationships.has(key)) { - let relationship = this._relationships.get(key); - let localRelationships = relationship.members.toArray(); - let serverRelationships = relationship.canonicalMembers.toArray(); - - array = array.concat(localRelationships, serverRelationships); - } - }); - return array; - } - - - /** - Computes the set of internal models reachable from this internal model. - - Reachability is determined over the relationship graph (ie a graph where - nodes are internal models and edges are belongs to or has many - relationships). - - @return {Array} An array including `this` and all internal models reachable - from `this`. - */ - _allRelatedInternalModels() { - let array = []; - let queue = []; - let bfsId = nextBfsId++; - queue.push(this); - this._bfsId = bfsId; - while (queue.length > 0) { - let node = queue.shift(); - array.push(node); - let related = node._directlyRelatedInternalModels(); - for (let i=0; i 0; - } - - /* - Checks if the attributes which are considered as changed are still - different to the state which is acknowledged by the server. - - This method is needed when data for the internal model is pushed and the - pushed data might acknowledge dirty attributes as confirmed. - - @method updateChangedAttributes - @private - */ - updateChangedAttributes() { - heimdall.increment(updateChangedAttributes); - let changedAttributes = this.changedAttributes(); - let changedAttributeNames = Object.keys(changedAttributes); - let attrs = this._attributes; - - for (let i = 0, length = changedAttributeNames.length; i < length; i++) { - let attribute = changedAttributeNames[i]; - let data = changedAttributes[attribute]; - let oldData = data[0]; - let newData = data[1]; - - if (oldData === newData) { - delete attrs[attribute]; - } - } - } - - /* - Returns an object, whose keys are changed properties, and value is an - [oldProp, newProp] array. - - @method changedAttributes - @private - */ - changedAttributes() { - heimdall.increment(changedAttributes); - let oldData = this._data; - let currentData = this._attributes; - let inFlightData = this._inFlightAttributes; - let newData = assign(copy$1(inFlightData), currentData); - let diffData = Object.create(null); - let newDataKeys = Object.keys(newData); - - for (let i = 0, length = newDataKeys.length; i < length; i++) { - let key = newDataKeys[i]; - diffData[key] = [oldData[key], newData[key]]; - } - - return diffData; - } - - /* - @method adapterWillCommit - @private - */ - adapterWillCommit() { - this.send('willCommit'); - } - - /* - @method adapterDidDirty - @private - */ - adapterDidDirty() { - this.send('becomeDirty'); - this.updateRecordArrays(); - } - - /* - @method send - @private - @param {String} name - @param {Object} context - */ - send(name, context) { - heimdall.increment(send); - let currentState = this.currentState; - - if (!currentState[name]) { - this._unhandledEvent(currentState, name, context); - } - - return currentState[name](this, context); - } - - notifyHasManyAdded(key, record, idx) { - if (this.hasRecord) { - this._record.notifyHasManyAdded(key, record, idx); - } - } - - notifyHasManyRemoved(key, record, idx) { - if (this.hasRecord) { - this._record.notifyHasManyRemoved(key, record, idx); - } - } - - notifyBelongsToChanged(key, record) { - if (this.hasRecord) { - this._record.notifyBelongsToChanged(key, record); - } - } - - notifyPropertyChange(key) { - if (this.hasRecord) { - this._record.notifyPropertyChange(key); - } - } - - rollbackAttributes() { - let dirtyKeys; - if (this.hasChangedAttributes()) { - dirtyKeys = Object.keys(this._attributes); - this._attributes = null; - } - - - if (get$4(this, 'isError')) { - this._inFlightAttributes = null; - this.didCleanError(); - } - - //Eventually rollback will always work for relationships - //For now we support it only out of deleted state, because we - //have an explicit way of knowing when the server acked the relationship change - if (this.isDeleted()) { - //TODO: Should probably move this to the state machine somehow - this.becameReady(); - } - - if (this.isNew()) { - this.clearRelationships(); - } - - if (this.isValid()) { - this._inFlightAttributes = null; - } - - this.send('rolledBack'); - - if (dirtyKeys && dirtyKeys.length > 0) { - this._record._notifyProperties(dirtyKeys); - } - } - - /* - @method transitionTo - @private - @param {String} name - */ - transitionTo(name) { - heimdall.increment(transitionTo); - // POSSIBLE TODO: Remove this code and replace with - // always having direct reference to state objects - - let pivotName = extractPivotName(name); - let state = this.currentState; - let transitionMapId = `${state.stateName}->${name}`; - - do { - if (state.exit) { state.exit(this); } - state = state.parentState; - } while (!state[pivotName]); - - let setups; - let enters; - let i; - let l; - let map = TransitionChainMap[transitionMapId]; - - if (map) { - setups = map.setups; - enters = map.enters; - state = map.state; - } else { - setups = []; - enters = []; - - let path = splitOnDot(name); - - for (i = 0, l = path.length; i < l; i++) { - state = state[path[i]]; - - if (state.enter) { enters.push(state); } - if (state.setup) { setups.push(state); } - } - - TransitionChainMap[transitionMapId] = { setups, enters, state }; - } - - for (i = 0, l = enters.length; i < l; i++) { - enters[i].enter(this); - } - - this.currentState = state; - if (this.hasRecord) { - set$2(this._record, 'currentState', state); - } - - for (i = 0, l = setups.length; i < l; i++) { - setups[i].setup(this); - } - - this.updateRecordArrays(); - } - - _unhandledEvent(state, name, context) { - let errorMessage = "Attempted to handle event `" + name + "` "; - errorMessage += "on " + String(this) + " while in state "; - errorMessage += state.stateName + ". "; - - if (context !== undefined) { - errorMessage += "Called with " + inspect$1(context) + "."; - } - - throw new EmberError$1(errorMessage); - } - - triggerLater(...args) { - if (this._deferredTriggers.push(args) !== 1) { - return; - } - - this.store._updateInternalModel(this); - } - - _triggerDeferredTriggers() { - heimdall.increment(_triggerDeferredTriggers); - //TODO: Before 1.0 we want to remove all the events that happen on the pre materialized record, - //but for now, we queue up all the events triggered before the record was materialized, and flush - //them once we have the record - if (!this.hasRecord) { - return; - } - let triggers = this._deferredTriggers; - let record = this._record; - let trigger = record.trigger; - for (let i = 0, l= triggers.length; i { - if (this._relationships.has(name)) { - let rel = this._relationships.get(name); - rel.clear(); - rel.removeInverseRelationships(); - } - }); - Object.keys(this._implicitRelationships).forEach((key) => { - this._implicitRelationships[key].clear(); - this._implicitRelationships[key].removeInverseRelationships(); - }); - } - - destroyRelationships() { - this.eachRelationship((name, relationship) => { - if (this._relationships.has(name)) { - let rel = this._relationships.get(name); - rel.removeInverseRelationships(); - } - }); - Object.keys(this._implicitRelationships).forEach((key) => { - this._implicitRelationships[key].removeInverseRelationships(); - }); - } - - /* - When a find request is triggered on the store, the user can optionally pass in - attributes and relationships to be preloaded. These are meant to behave as if they - came back from the server, except the user obtained them out of band and is informing - the store of their existence. The most common use case is for supporting client side - nested URLs, such as `/posts/1/comments/2` so the user can do - `store.findRecord('comment', 2, { preload: { post: 1 } })` without having to fetch the post. - - Preloaded data can be attributes and relationships passed in either as IDs or as actual - models. - - @method preloadData - @private - @param {Object} preload - */ - preloadData(preload) { - //TODO(Igor) consider the polymorphic case - Object.keys(preload).forEach((key) => { - let preloadValue = get$4(preload, key); - let relationshipMeta = this.modelClass.metaForProperty(key); - if (relationshipMeta.isRelationship) { - this._preloadRelationship(key, preloadValue); - } else { - this._data[key] = preloadValue; - } - }); - } - - _preloadRelationship(key, preloadValue) { - let relationshipMeta = this.modelClass.metaForProperty(key); - let modelClass = relationshipMeta.type; - if (relationshipMeta.kind === 'hasMany') { - this._preloadHasMany(key, preloadValue, modelClass); - } else { - this._preloadBelongsTo(key, preloadValue, modelClass); - } - } - - _preloadHasMany(key, preloadValue, modelClass) { - assert("You need to pass in an array to set a hasMany property on a record", Array.isArray(preloadValue)); - let recordsToSet = new Array(preloadValue.length); - - for (let i = 0; i < preloadValue.length; i++) { - let recordToPush = preloadValue[i]; - recordsToSet[i] = this._convertStringOrNumberIntoInternalModel(recordToPush, modelClass); - } - - //We use the pathway of setting the hasMany as if it came from the adapter - //because the user told us that they know this relationships exists already - this._relationships.get(key).updateInternalModelsFromAdapter(recordsToSet); - } - - _preloadBelongsTo(key, preloadValue, modelClass) { - let internalModelToSet = this._convertStringOrNumberIntoInternalModel(preloadValue, modelClass); - - //We use the pathway of setting the hasMany as if it came from the adapter - //because the user told us that they know this relationships exists already - this._relationships.get(key).setInternalModel(internalModelToSet); - } - - _convertStringOrNumberIntoInternalModel(value, modelClass) { - if (typeof value === 'string' || typeof value === 'number') { - return this.store._internalModelForId(modelClass, value); - } - if (value._internalModel) { - return value._internalModel; - } - return value; - } - - /* - @method updateRecordArrays - @private - */ - updateRecordArrays() { - this.store.recordArrayManager.recordDidChange(this); - } - - setId(id) { - assert('A record\'s id cannot be changed once it is in the loaded state', this.id === null || this.id === id || this.isNew()); - this.id = id; - if (this._record.get('id') !== id) { - this._record.set('id', id); - } - } - - didError(error) { - this.error = error; - this.isError = true; - - if (this.hasRecord) { - this._record.setProperties({ - isError: true, - adapterError: error - }); - } - } - - didCleanError() { - this.error = null; - this.isError = false; - - if (this.hasRecord) { - this._record.setProperties({ - isError: false, - adapterError: null - }); - } - } - - /* - If the adapter did not return a hash in response to a commit, - merge the changed attributes and relationships into the existing - saved data. - - @method adapterDidCommit - */ - adapterDidCommit(data) { - if (data) { - this.store._internalModelDidReceiveRelationshipData(this.modelName, this.id, data.relationships); - - data = data.attributes; - } - - this.didCleanError(); - let changedKeys = this._changedKeys(data); - - assign(this._data, this._inFlightAttributes); - if (data) { - assign(this._data, data); - } - - this._inFlightAttributes = null; - - this.send('didCommit'); - this.updateRecordArrays(); - - if (!data) { return; } - - this._record._notifyProperties(changedKeys); - } - - addErrorMessageToAttribute(attribute, message) { - get$4(this.getRecord(), 'errors')._add(attribute, message); - } - - removeErrorMessageFromAttribute(attribute) { - get$4(this.getRecord(), 'errors')._remove(attribute); - } - - clearErrorMessages() { - get$4(this.getRecord(), 'errors')._clear(); - } - - hasErrors() { - let errors = get$4(this.getRecord(), 'errors'); - - return !isEmpty$1(errors); - } - - // FOR USE DURING COMMIT PROCESS - - /* - @method adapterDidInvalidate - @private - */ - adapterDidInvalidate(errors) { - let attribute; - - for (attribute in errors) { - if (errors.hasOwnProperty(attribute)) { - this.addErrorMessageToAttribute(attribute, errors[attribute]); - } - } - - this.send('becameInvalid'); - - this._saveWasRejected(); - } - - /* - @method adapterDidError - @private - */ - adapterDidError(error) { - this.send('becameError'); - this.didError(error); - this._saveWasRejected(); - } - - _saveWasRejected() { - let keys = Object.keys(this._inFlightAttributes); - if (keys.length > 0) { - let attrs = this._attributes; - for (let i=0; i < keys.length; i++) { - if (attrs[keys[i]] === undefined) { - attrs[keys[i]] = this._inFlightAttributes[keys[i]]; - } - } - } - this._inFlightAttributes = null; - } - - /* - Ember Data has 3 buckets for storing the value of an attribute on an internalModel. - - `_data` holds all of the attributes that have been acknowledged by - a backend via the adapter. When rollbackAttributes is called on a model all - attributes will revert to the record's state in `_data`. - - `_attributes` holds any change the user has made to an attribute - that has not been acknowledged by the adapter. Any values in - `_attributes` are have priority over values in `_data`. - - `_inFlightAttributes`. When a record is being synced with the - backend the values in `_attributes` are copied to - `_inFlightAttributes`. This way if the backend acknowledges the - save but does not return the new state Ember Data can copy the - values from `_inFlightAttributes` to `_data`. Without having to - worry about changes made to `_attributes` while the save was - happenign. - - - Changed keys builds a list of all of the values that may have been - changed by the backend after a successful save. - - It does this by iterating over each key, value pair in the payload - returned from the server after a save. If the `key` is found in - `_attributes` then the user has a local changed to the attribute - that has not been synced with the server and the key is not - included in the list of changed keys. - - - - If the value, for a key differs from the value in what Ember Data - believes to be the truth about the backend state (A merger of the - `_data` and `_inFlightAttributes` objects where - `_inFlightAttributes` has priority) then that means the backend - has updated the value and the key is added to the list of changed - keys. - - @method _changedKeys - @private - */ - _changedKeys(updates) { - let changedKeys = []; - - if (updates) { - let original, i, value, key; - let keys = Object.keys(updates); - let length = keys.length; - let hasAttrs = this.hasChangedAttributes(); - let attrs; - if (hasAttrs) { - attrs= this._attributes; - } - - original = assign(Object.create(null), this._data); - original = assign(original, this._inFlightAttributes); - - for (i = 0; i < length; i++) { - key = keys[i]; - value = updates[key]; - - // A value in _attributes means the user has a local change to - // this attributes. We never override this value when merging - // updates from the backend so we should not sent a change - // notification if the server value differs from the original. - if (hasAttrs === true && attrs[key] !== undefined) { - continue; - } - - if (!isEqual(original[key], value)) { - changedKeys.push(key); - } - } - } - - return changedKeys; - } - - toString() { - return `<${this.modelName}:${this.id}>`; - } - - referenceFor(kind, name) { - let reference = this.references[name]; - - if (!reference) { - let relationship = this._relationships.get(name); - - runInDebug(() => { - let modelName = this.modelName; - assert(`There is no ${kind} relationship named '${name}' on a model of modelClass '${modelName}'`, relationship); - - let actualRelationshipKind = relationship.relationshipMeta.kind; - assert(`You tried to get the '${name}' relationship on a '${modelName}' via record.${kind}('${name}'), but the relationship is of kind '${actualRelationshipKind}'. Use record.${actualRelationshipKind}('${name}') instead.`, actualRelationshipKind === kind); - }); - - if (kind === "belongsTo") { - reference = new BelongsToReference(this.store, this, relationship); - } else if (kind === "hasMany") { - reference = new HasManyReference(this.store, this, relationship); - } - - this.references[name] = reference; - } - - return reference; - } -} - -if (isEnabled('ds-rollback-attribute')) { - /* - Returns the latest truth for an attribute - the canonical value, or the - in-flight value. - - @method lastAcknowledgedValue - @private - */ - InternalModel.prototype.lastAcknowledgedValue = function lastAcknowledgedValue(key) { - if (key in this._inFlightAttributes) { - return this._inFlightAttributes[key]; - } else { - return this._data[key]; - } - }; -} - -/** - `InternalModelMap` is a custom storage map for internalModels of a given modelName - used by `IdentityMap`. - - It was extracted from an implicit pojo based "internalModel map" and preserves - that interface while we work towards a more official API. - - @class InternalModelMap - @private - */ -class InternalModelMap { - constructor(modelName) { - this.modelName = modelName; - this._idToModel = Object.create(null); - this._models = []; - this._metadata = null; - } - - /** - A "map" of records based on their ID for this modelName - */ - get idToRecord() { - deprecate('Use of InternalModelMap.idToRecord is deprecated, use InternalModelMap.get(id) instead.', false, { - id: 'ds.record-map.idToRecord', - until: '2.13' - }); - return this._idToModel; - } - - /** - * - * @param id - * @returns {InternalModel} - */ - get(id) { - let r = this._idToModel[id]; - return r; - } - - has(id) { - return !!this._idToModel[id]; - } - - get length() { - return this._models.length; - } - - set(id, internalModel) { - assert(`You cannot index an internalModel by an empty id'`, id); - assert(`You cannot set an index for an internalModel to something other than an internalModel`, internalModel instanceof InternalModel); - assert(`You cannot set an index for an internalModel that is not in the InternalModelMap`, this.contains(internalModel)); - assert(`You cannot update the id index of an InternalModel once set. Attempted to update ${id}.`, !this.has(id) || this.get(id) === internalModel); - - this._idToModel[id] = internalModel; - } - - add(internalModel, id) { - assert(`You cannot re-add an already present InternalModel to the InternalModelMap.`, !this.contains(internalModel)); - - if (id) { - this._idToModel[id] = internalModel; - } - - this._models.push(internalModel); - } - - remove(internalModel, id) { - if (id) { - delete this._idToModel[id]; - } - - let loc = this._models.indexOf(internalModel); - - if (loc !== -1) { - this._models.splice(loc, 1); - } - } - - contains(internalModel) { - return this._models.indexOf(internalModel) !== -1; - } - - /** - An array of all models of this modelName - */ - get models() { - return this._models; - } - - /** - * meta information about internalModels - */ - get metadata() { - return this._metadata || (this._metadata = Object.create(null)); - } - - /** - deprecated (and unsupported) way of accessing modelClass - - @deprecated - */ - get type() { - throw new Error('InternalModelMap.type is no longer available'); - } - - /** - Destroy all models in the internalModelTest and wipe metadata. - - @method clear - */ - clear() { - if (this._models) { - let models = this._models; - this._models = []; - - for (let i = 0; i < models.length; i++) { - let model = models[i]; - model.unloadRecord(); - } - } - - this._metadata = null; - } - - destroy() { - this._store = null; - this._modelClass = null; - } -} - -/** - `IdentityMap` is a custom storage map for records by modelName - used by `DS.Store`. - - @class IdentityMap - @private - */ -class IdentityMap { - constructor() { - this._map = Object.create(null); - } - - /** - Retrieves the `InternalModelMap` for a given modelName, - creating one if one did not already exist. This is - similar to `getWithDefault` or `get` on a `MapWithDefault` - - @method retrieve - @param modelName a previously normalized modelName - @returns {InternalModelMap} the InternalModelMap for the given modelName - */ - retrieve(modelName) { - let map = this._map[modelName]; - - if (!map) { - map = this._map[modelName] = new InternalModelMap(modelName); - } - - return map; - } - - /** - Clears the contents of all known `RecordMaps`, but does - not remove the InternalModelMap instances. - - @method clear - */ - clear() { - let map = this._map; - let keys = Object.keys(map); - - for (let i = 0; i < keys.length; i++) { - let key = keys[i]; - map[key].clear(); - } - } -} - -/* - This is a helper method that validates a JSON API top-level document - - The format of a document is described here: - http://jsonapi.org/format/#document-top-level - - @method validateDocumentStructure - @param {Object} doc JSON API document - @return {array} An array of errors found in the document structure -*/ -function validateDocumentStructure(doc) { - let errors = []; - if (!doc || typeof doc !== 'object') { - errors.push('Top level of a JSON API document must be an object'); - } else { - if (!('data' in doc) && - !('errors' in doc) && - !('meta' in doc)) { - errors.push('One or more of the following keys must be present: "data", "errors", "meta".'); - } else { - if (('data' in doc) && ('errors' in doc)) { - errors.push('Top level keys "errors" and "data" cannot both be present in a JSON API document'); - } - } - if ('data' in doc) { - if (!(doc.data === null || Array.isArray(doc.data) || typeof doc.data === 'object')) { - errors.push('data must be null, an object, or an array'); - } - } - if ('meta' in doc) { - if (typeof doc.meta !== 'object') { - errors.push('meta must be an object'); - } - } - if ('errors' in doc) { - if (!Array.isArray(doc.errors)) { - errors.push('errors must be an array'); - } - } - if ('links' in doc) { - if (typeof doc.links !== 'object') { - errors.push('links must be an object'); - } - } - if ('jsonapi' in doc) { - if (typeof doc.jsonapi !== 'object') { - errors.push('jsonapi must be an object'); - } - } - if ('included' in doc) { - if (typeof doc.included !== 'object') { - errors.push('included must be an array'); - } - } - } - - return errors; -} - -/* - This is a helper method that always returns a JSON-API Document. - - @method normalizeResponseHelper - @param {DS.Serializer} serializer - @param {DS.Store} store - @param {subclass of DS.Model} modelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document -*/ -function normalizeResponseHelper(serializer, store, modelClass, payload, id, requestType) { - let normalizedResponse = serializer.normalizeResponse(store, modelClass, payload, id, requestType); - let validationErrors = []; - runInDebug(() => { - validationErrors = validateDocumentStructure(normalizedResponse); - }); - assert(`normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join('\n\t* ')}`, Ember.isEmpty(validationErrors)); - - return normalizedResponse; -} - -function serializerForAdapter(store, adapter, modelName) { - let serializer = adapter.serializer; - - if (serializer === undefined) { - serializer = store.serializerFor(modelName); - } - - if (serializer === null || serializer === undefined) { - serializer = { - extract(store, type, payload) { return payload; } - }; - } - - return serializer; -} - -/** - Manages the payloads for both sides of a single relationship, across all model - instances. - - For example, with - - const User = DS.Model.extend({ - hobbies: DS.hasMany('hobby') - }); - - const Hobby = DS.Model.extend({ - user: DS.belongsTo('user') - }); - - let relationshipPayloads = new RelationshipPayloads('user', 'hobbies', 'hobby', 'user'); - - let userPayload = { - data: { - id: 1, - type: 'user', - relationships: { - hobbies: { - data: [{ - id: 2, - type: 'hobby', - }] - } - } - } - }; - - // here we expect the payload of the individual relationship - relationshipPayloads.push('user', 1, 'hobbies', userPayload.data.relationships.hobbies); - - relationshipPayloads.get('user', 1, 'hobbies'); - relationshipPayloads.get('hobby', 2, 'user'); - - @class RelationshipPayloads - @private -*/ -class RelationshipPayloads { - constructor(store, modelName, relationshipName, relationshipMeta, inverseModelName, inverseRelationshipName, inverseRelationshipMeta) { - this._store = store; - - this._lhsModelName = modelName; - this._lhsRelationshipName = relationshipName; - this._lhsRelationshipMeta = relationshipMeta; - - this._rhsModelName = inverseModelName; - this._rhsRelationshipName = inverseRelationshipName; - this._rhsRelationshipMeta = inverseRelationshipMeta; - - // a map of id -> payloads for the left hand side of the relationship. - this._lhsPayloads = Object.create(null); - if (modelName !== inverseModelName || relationshipName !== inverseRelationshipName) { - // The common case of a non-reflexive relationship, or a reflexive - // relationship whose inverse is not itself - this._rhsPayloads = Object.create(null); - this._isReflexive = false; - } else { - // Edge case when we have a reflexive relationship to itself - // eg user hasMany friends inverse friends - // - // In this case there aren't really two sides to the relationship, but - // we set `_rhsPayloads = _lhsPayloads` to make things easier to reason - // about - this._rhsPayloads = this._lhsPayloads; - this._isReflexive = true; - } - - // When we push relationship payloads, just stash them in a queue until - // somebody actually asks for one of them. - // - // This is a queue of the relationship payloads that have been pushed for - // either side of this relationship - this._pendingPayloads = []; - } - - /** - Get the payload for the relationship of an individual record. - - This might return the raw payload as pushed into the store, or one computed - from the payload of the inverse relationship. - - @method - */ - get(modelName, id, relationshipName) { - this._flushPending(); - - if (this._isLHS(modelName, relationshipName)) { - return this._lhsPayloads[id]; - } else { - assert(`${modelName}:${relationshipName} is not either side of this relationship, ${this._lhsModelName}:${this._lhsRelationshipName}<->${this._rhsModelName}:${this._rhsRelationshipName}`, this._isRHS(modelName, relationshipName)); - return this._rhsPayloads[id]; - } - } - - /** - Push a relationship payload for an individual record. - - This will make the payload available later for both this relationship and its inverse. - - @method - */ - push(modelName, id, relationshipName, relationshipData) { - this._pendingPayloads.push([modelName, id, relationshipName, relationshipData]); - } - - /** - Unload the relationship payload for an individual record. - - This does not unload the inverse relationship payload. - - @method - */ - unload(modelName, id, relationshipName) { - this._flushPending(); - - if (this._isLHS(modelName, relationshipName)) { - delete this._lhsPayloads[id]; - } else { - assert(`${modelName}:${relationshipName} is not either side of this relationship, ${this._lhsModelName}:${this._lhsRelationshipName}<->${this._rhsModelName}:${this._rhsRelationshipName}`, this._isRHS(modelName, relationshipName)); - delete this._rhsPayloads[id]; - } - } - - /** - @return {boolean} true iff `modelName` and `relationshipName` refer to the - left hand side of this relationship, as opposed to the right hand side. - - @method - */ - _isLHS(modelName, relationshipName) { - return modelName === this._lhsModelName && relationshipName === this._lhsRelationshipName; - } - - /** - @return {boolean} true iff `modelName` and `relationshipName` refer to the - right hand side of this relationship, as opposed to the left hand side. - - @method - */ - _isRHS(modelName, relationshipName) { - return modelName === this._rhsModelName && relationshipName === this._rhsRelationshipName; - } - - _flushPending() { - if (this._pendingPayloads.length === 0) { return; } - - let payloadsToBeProcessed = this._pendingPayloads.splice(0, this._pendingPayloads.length); - for (let i=0; i${this._rhsModelName}:${this._rhsRelationshipName}`, this._isRHS(modelName, relationshipName)); - previousPayload = this._rhsPayloads[id]; - idToPayloads = this._rhsPayloads; - inverseIdToPayloads = this._lhsPayloads; - inverseIsMany = this._lhsRelationshipIsMany; - } - - // actually flush this individual payload - // - // We remove the previous inverse before populating our current one - // because we may have multiple payloads for the same relationship, in - // which case the last one wins. - // - // eg if user hasMany helicopters, and helicopter belongsTo user and we see - // - // [{ - // data: { - // id: 1, - // type: 'helicopter', - // relationships: { - // user: { - // id: 2, - // type: 'user' - // } - // } - // } - // }, { - // data: { - // id: 1, - // type: 'helicopter', - // relationships: { - // user: { - // id: 4, - // type: 'user' - // } - // } - // } - // }] - // - // Then we will initially have set user:2 as having helicopter:1, which we - // need to remove before adding helicopter:1 to user:4 - // - this._removeInverse(id, previousPayload, inverseIdToPayloads); - idToPayloads[id] = relationshipData; - this._populateInverse(relationshipData, inverseRelationshipData, inverseIdToPayloads, inverseIsMany); - } - } - - /** - Populate the inverse relationship for `relationshipData`. - - If `relationshipData` is an array (eg because the relationship is hasMany) - this means populate each inverse, otherwise populate only the single - inverse. - - @private - @method - */ - _populateInverse(relationshipData, inversePayload, inverseIdToPayloads, inverseIsMany) { - if (!relationshipData.data) { - // This id doesn't have an inverse, eg a belongsTo with a payload - // { data: null }, so there's nothing to populate - return; - } - - if (Array.isArray(relationshipData.data)) { - for (let i=0; i.friends = [{ id: 1, type: 'user' }] - return; - } - - let existingPayload = inverseIdToPayloads[inverseId]; - let existingData = existingPayload && existingPayload.data; - - if (existingData) { - // There already is an inverse, either add or overwrite depehnding on - // whether the inverse is a many relationship or not - // - if (Array.isArray(existingData)) { - existingData.push(inversePayload.data); - } else { - inverseIdToPayloads[inverseId] = inversePayload; - } - } else { - // first time we're populating the inverse side - // - if (inverseIsMany) { - inverseIdToPayloads[inverseId] = { - data: [inversePayload.data] - }; - } else { - inverseIdToPayloads[inverseId] = inversePayload; - } - } - } - - get _lhsRelationshipIsMany() { - return this._lhsRelationshipMeta && this._lhsRelationshipMeta.kind === 'hasMany'; - } - - get _rhsRelationshipIsMany() { - return this._rhsRelationshipMeta && this._rhsRelationshipMeta.kind === 'hasMany'; - } - - /** - Remove the relationship in `previousPayload` from its inverse(s), because - this relationship payload has just been updated (eg because the same - relationship had multiple payloads pushed before the relationship was - initialized). - - @method - */ - _removeInverse(id, previousPayload, inverseIdToPayloads) { - let data = previousPayload && previousPayload.data; - if (!data) { - // either this is the first time we've seen a payload for this id, or its - // previous payload indicated that it had no inverse, eg a belongsTo - // relationship with payload { data: null } - // - // In either case there's nothing that needs to be removed from the - // inverse map of payloads - return; - } - - if (Array.isArray(data)) { - // TODO: diff rather than removeall addall? - for (let i=0; i x.id !== id); - } else { - inversePayloads[inverseId] = { - data: null - }; - } - } -} - -const get$11 = Ember.get; - -/** - Manages relationship payloads for a given store, for uninitialized - relationships. Acts as a single source of truth (of payloads) for both sides - of an uninitialized relationship so they can agree on the most up-to-date - payload received without needing too much eager processing when those payloads - are pushed into the store. - - This minimizes the work spent on relationships that are never initialized. - - Once relationships are initialized, their state is managed in a relationship - state object (eg BelongsToRelationship or ManyRelationship). - - - @example - - let relationshipPayloadsManager = new RelationshipPayloadsManager(store); - - const User = DS.Model.extend({ - hobbies: DS.hasMany('hobby') - }); - - const Hobby = DS.Model.extend({ - user: DS.belongsTo('user') - }); - - let userPayload = { - data: { - id: 1, - type: 'user', - relationships: { - hobbies: { - data: [{ - id: 2, - type: 'hobby' - }] - } - } - }, - }; - relationshipPayloadsManager.push('user', 1, userPayload.data.relationships); - - relationshipPayloadsManager.get('hobby', 2, 'user') === { - { - data: { - id: 1, - type: 'user' - } - } - } - - @private - @class RelationshipPayloadsManager -*/ -class RelationshipPayloadsManager { - constructor(store) { - this._store = store; - // cache of `RelationshipPayload`s - this._cache = Object.create(null); - } - - /** - Find the payload for the given relationship of the given model. - - Returns the payload for the given relationship, whether raw or computed from - the payload of the inverse relationship. - - @example - - relationshipPayloadsManager.get('hobby', 2, 'user') === { - { - data: { - id: 1, - type: 'user' - } - } - } - - @method - */ - get(modelName, id, relationshipName) { - let modelClass = this._store._modelFor(modelName); - let relationshipsByName = get$11(modelClass, 'relationshipsByName'); - let relationshipPayloads = this._getRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName, false); - return relationshipPayloads && relationshipPayloads.get(modelName, id, relationshipName); - } - - /** - Push a model's relationships payload into this cache. - - @example - - let userPayload = { - data: { - id: 1, - type: 'user', - relationships: { - hobbies: { - data: [{ - id: 2, - type: 'hobby' - }] - } - } - }, - }; - relationshipPayloadsManager.push('user', 1, userPayload.data.relationships); - - @method - */ - push(modelName, id, relationshipsData) { - if (!relationshipsData) { return; } - - let modelClass = this._store._modelFor(modelName); - let relationshipsByName = get$11(modelClass, 'relationshipsByName'); - Object.keys(relationshipsData).forEach(key => { - let relationshipPayloads = this._getRelationshipPayloads(modelName, key, modelClass, relationshipsByName, true); - if (relationshipPayloads) { - relationshipPayloads.push(modelName, id, key, relationshipsData[key]); - } - }); - } - - /** - Unload a model's relationships payload. - - @method - */ - unload(modelName, id) { - let modelClass = this._store._modelFor(modelName); - let relationshipsByName = get$11(modelClass, 'relationshipsByName'); - relationshipsByName.forEach((_, relationshipName) => { - let relationshipPayloads = this._getRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName, false); - if (relationshipPayloads) { - relationshipPayloads.unload(modelName, id, relationshipName); - } - }); - } - - /** - Find the RelationshipPayloads object for the given relationship. The same - RelationshipPayloads object is returned for either side of a relationship. - - @example - - const User = DS.Model.extend({ - hobbies: DS.hasMany('hobby') - }); - - const Hobby = DS.Model.extend({ - user: DS.belongsTo('user') - }); - - relationshipPayloads.get('user', 'hobbies') === relationshipPayloads.get('hobby', 'user'); - - The signature has a somewhat large arity to avoid extra work, such as - a) string maipulation & allocation with `modelName` and - `relationshipName` - b) repeatedly getting `relationshipsByName` via `Ember.get` - - - @private - @method - */ - _getRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName, init) { - if (!relationshipsByName.has(relationshipName)) { return; } - - let key = `${modelName}:${relationshipName}`; - if (!this._cache[key] && init) { - return this._initializeRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName); - } - - return this._cache[key]; - } - - /** - Create the `RelationshipsPayload` for the relationship `modelName`, `relationshipName`, and its inverse. - - @private - @method - */ - _initializeRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName) { - let relationshipMeta = relationshipsByName.get(relationshipName); - let inverseMeta = modelClass.inverseFor(relationshipName, this._store); - - let inverseModelName; - let inverseRelationshipName; - let inverseRelationshipMeta; - - // figure out the inverse relationship; we need two things - // a) the inverse model name - //- b) the name of the inverse relationship - if (inverseMeta) { - inverseRelationshipName = inverseMeta.name; - inverseModelName = relationshipMeta.type; - inverseRelationshipMeta = get$11(inverseMeta.type, 'relationshipsByName').get(inverseRelationshipName); - } else { - // relationship has no inverse - inverseModelName = inverseRelationshipName = ''; - inverseRelationshipMeta = null; - } - - let lhsKey = `${modelName}:${relationshipName}`; - let rhsKey = `${inverseModelName}:${inverseRelationshipName}`; - - // populate the cache for both sides of the relationship, as they both use - // the same `RelationshipPayloads`. - // - // This works out better than creating a single common key, because to - // compute that key we would need to do work to look up the inverse - // - return this._cache[lhsKey] = - this._cache[rhsKey] = - new RelationshipPayloads( - this._store, - modelName, - relationshipName, - relationshipMeta, - inverseModelName, - inverseRelationshipName, - inverseRelationshipMeta - ); - } -} - -const { Promise: Promise$3 } = Ember.RSVP; - -function payloadIsNotBlank(adapterPayload) { - if (Array.isArray(adapterPayload)) { - return true; - } else { - return Object.keys(adapterPayload || {}).length; - } -} - -function _find(adapter, store, modelClass, id, internalModel, options) { - let snapshot = internalModel.createSnapshot(options); - let { modelName } = internalModel; - let promise = adapter.findRecord(store, modelClass, id, snapshot); - let label = `DS: Handle Adapter#findRecord of '${modelName}' with id: '${id}'`; - - promise = Promise$3.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); - - return promise.then(adapterPayload => { - assert(`You made a 'findRecord' request for a '${modelName}' with id '${id}', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, id, 'findRecord'); - assert(`Ember Data expected the primary data returned from a 'findRecord' response to be an object but instead it found an array.`, !Array.isArray(payload.data)); - - warn(`You requested a record of type '${modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead http://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, payload.data.id === id, { - id: 'ds.store.findRecord.id-mismatch' - }); - - return store._push(payload); - }, error => { - internalModel.notFound(); - if (internalModel.isEmpty()) { - internalModel.unloadRecord(); - } - - throw error; - }, `DS: Extract payload of '${modelName}'`); -} - -function _findMany(adapter, store, modelName, ids, internalModels) { - let snapshots = Ember.A(internalModels).invoke('createSnapshot'); - let modelClass = store.modelFor(modelName); // `adapter.findMany` gets the modelClass still - let promise = adapter.findMany(store, modelClass, ids, snapshots); - let label = `DS: Handle Adapter#findMany of '${modelName}'`; - - if (promise === undefined) { - throw new Error('adapter.findMany returned undefined, this was very likely a mistake'); - } - - promise = Promise$3.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); - - return promise.then(adapterPayload => { - assert(`You made a 'findMany' request for '${modelName}' records with ids '[${ids}]', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findMany'); - return store._push(payload); - }, null, `DS: Extract payload of ${modelName}`); -} - -function _findHasMany(adapter, store, internalModel, link, relationship) { - let snapshot = internalModel.createSnapshot(); - let modelClass = store.modelFor(relationship.type); - let promise = adapter.findHasMany(store, snapshot, link, relationship); - let label = `DS: Handle Adapter#findHasMany of '${internalModel.modelName}' : '${relationship.type}'`; - - promise = Promise$3.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); - promise = _guard(promise, _bind(_objectIsAlive, internalModel)); - - return promise.then(adapterPayload => { - assert(`You made a 'findHasMany' request for a ${internalModel.modelName}'s '${relationship.key}' relationship, using link '${link}' , but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); - let serializer = serializerForAdapter(store, adapter, relationship.type); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findHasMany'); - let internalModelArray = store._push(payload); - - internalModelArray.meta = payload.meta; - return internalModelArray; - }, null, `DS: Extract payload of '${internalModel.modelName}' : hasMany '${relationship.type}'`); -} - -function _findBelongsTo(adapter, store, internalModel, link, relationship) { - let snapshot = internalModel.createSnapshot(); - let modelClass = store.modelFor(relationship.type); - let promise = adapter.findBelongsTo(store, snapshot, link, relationship); - let label = `DS: Handle Adapter#findBelongsTo of ${internalModel.modelName} : ${relationship.type}`; - - promise = Promise$3.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); - promise = _guard(promise, _bind(_objectIsAlive, internalModel)); - - return promise.then(adapterPayload => { - let serializer = serializerForAdapter(store, adapter, relationship.type); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findBelongsTo'); - - if (!payload.data) { - return null; - } - - return store._push(payload); - }, null, `DS: Extract payload of ${internalModel.modelName} : ${relationship.type}`); -} - -function _findAll(adapter, store, modelName, sinceToken, options) { - let modelClass = store.modelFor(modelName); // adapter.findAll depends on the class - let recordArray = store.peekAll(modelName); - let snapshotArray = recordArray._createSnapshot(options); - let promise = adapter.findAll(store, modelClass, sinceToken, snapshotArray); - let label = "DS: Handle Adapter#findAll of " + modelClass; - - promise = Promise$3.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); - - return promise.then(adapterPayload => { - assert(`You made a 'findAll' request for '${modelName}' records, but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findAll'); - - store._push(payload); - store._didUpdateAll(modelName); - - return recordArray; - }, null, 'DS: Extract payload of findAll ${modelName}'); -} - -function _query(adapter, store, modelName, query, recordArray) { - let modelClass = store.modelFor(modelName); // adapter.query needs the class - let promise = adapter.query(store, modelClass, query, recordArray); - - let label = `DS: Handle Adapter#query of ${modelClass}`; - - promise = Promise$3.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); - - return promise.then(adapterPayload => { - let serializerToken = heimdall.start('initial-serializerFor-lookup'); - let serializer = serializerForAdapter(store, adapter, modelName); - heimdall.stop(serializerToken); - let normalizeToken = heimdall.start('finders#_query::normalizeResponseHelper'); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'query'); - heimdall.stop(normalizeToken); - let internalModels = store._push(payload); - - assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Array.isArray(internalModels)); - recordArray._setInternalModels(internalModels, payload); - - return recordArray; - }, null, `DS: Extract payload of query ${modelName}`); -} - -function _queryRecord(adapter, store, modelName, query) { - let modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class - let promise = adapter.queryRecord(store, modelClass, query); - let label = `DS: Handle Adapter#queryRecord of ${modelName}`; - - promise = Promise$3.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); - - return promise.then(adapterPayload => { - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'queryRecord'); - - assert(`Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array.`, !Array.isArray(payload.data), { - id: 'ds.store.queryRecord-array-response' - }); - - return store._push(payload); - }, null, `DS: Extract payload of queryRecord ${modelName}`); -} - -// Used by the store to normalize IDs entering the store. Despite the fact -// that developers may provide IDs as numbers (e.g., `store.findRecord('person', 1)`), -// it is important that internally we use strings, since IDs may be serialized -// and lose type information. For example, Ember's router may put a record's -// ID into the URL, and if we later try to deserialize that URL and find the -// corresponding record, we will not know if it is a string or a number. -function coerceId(id) { - return id === null || id === undefined || id === '' ? null : id+''; -} - -/** - @module ember-data -*/ - -/** - @class SnapshotRecordArray - @namespace DS - @private - @constructor - @param {Array} snapshots An array of snapshots - @param {Object} meta -*/ -class SnapshotRecordArray { - constructor(recordArray, meta, options = {}) { - /** - An array of snapshots - @private - @property _snapshots - @type {Array} - */ - this._snapshots = null; - - /** - An array of records - @private - @property _recordArray - @type {Array} - */ - this._recordArray = recordArray; - - /** - Number of records in the array - - Example - - ```app/adapters/post.js - import DS from 'ember-data' - - export default DS.JSONAPIAdapter.extend({ - shouldReloadAll(store, snapshotRecordArray) { - return !snapshotRecordArray.length; - }, - }); - ``` - - @property length - @type {Number} - */ - this.length = recordArray.get('length'); - - this._type = null; - - /** - Meta objects for the record array. - - Example - - ```app/adapters/post.js - import DS from 'ember-data' - - export default DS.JSONAPIAdapter.extend({ - shouldReloadAll(store, snapshotRecordArray) { - var lastRequestTime = snapshotRecordArray.meta.lastRequestTime; - var twentyMinutes = 20 * 60 * 1000; - return Date.now() > lastRequestTime + twentyMinutes; - }, - }); - ``` - - @property meta - @type {Object} - */ - this.meta = meta; - - /** - A hash of adapter options passed into the store method for this request. - - Example - - ```app/adapters/post.js - import MyCustomAdapter from './custom-adapter'; - - export default MyCustomAdapter.extend({ - findAll(store, type, sinceToken, snapshotRecordArray) { - if (snapshotRecordArray.adapterOptions.subscribe) { - // ... - } - // ... - } - }); - ``` - - @property adapterOptions - @type {Object} - */ - this.adapterOptions = options.adapterOptions; - - /** - The relationships to include for this request. - - Example - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - findAll(store, type, snapshotRecordArray) { - var url = `/${type.modelName}?include=${encodeURIComponent(snapshotRecordArray.include)}`; - - return fetch(url).then((response) => response.json()) - } - }); - - @property include - @type {String|Array} - */ - this.include = options.include; - } - - /** - The type of the underlying records for the snapshots in the array, as a DS.Model - @property type - @type {DS.Model} - */ - get type() { - return this._type || (this._type = this._recordArray.get('type')); - } - - /** - Get snapshots of the underlying record array - - Example - - ```app/adapters/post.js - import DS from 'ember-data' - - export default DS.JSONAPIAdapter.extend({ - shouldReloadAll(store, snapshotArray) { - var snapshots = snapshotArray.snapshots(); - - return snapshots.any(function(ticketSnapshot) { - var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt'), 'minutes'); - if (timeDiff > 20) { - return true; - } else { - return false; - } - }); - } - }); - ``` - - @method snapshots - @return {Array} Array of snapshots - */ - snapshots() { - if (this._snapshots !== null) { - return this._snapshots; - } - - this._snapshots = this._recordArray._takeSnapshot(); - - return this._snapshots; - } -} - -/** - @module ember-data -*/ - -const { computed: computed$2, get: get$13, set: set$3, RSVP: { Promise: Promise$4 } } = Ember; - -/** - A record array is an array that contains records of a certain modelName. The record - array materializes records as needed when they are retrieved for the first - time. You should not create record arrays yourself. Instead, an instance of - `DS.RecordArray` or its subclasses will be returned by your application's store - in response to queries. - - @class RecordArray - @namespace DS - @extends Ember.ArrayProxy - @uses Ember.Evented -*/ - -var RecordArray = Ember.ArrayProxy.extend(Ember.Evented, { - init() { - this._super(...arguments); - - /** - The array of client ids backing the record array. When a - record is requested from the record array, the record - for the client id at the same index is materialized, if - necessary, by the store. - - @property content - @private - @type Ember.Array - */ - this.set('content', this.content || null); - - /** - The flag to signal a `RecordArray` is finished loading data. - - Example - - ```javascript - var people = store.peekAll('person'); - people.get('isLoaded'); // true - ``` - - @property isLoaded - @type Boolean - */ - this.isLoaded = this.isLoaded || false; - /** - The flag to signal a `RecordArray` is currently loading data. - - Example - - ```javascript - var people = store.peekAll('person'); - people.get('isUpdating'); // false - people.update(); - people.get('isUpdating'); // true - ``` - - @property isUpdating - @type Boolean - */ - this.isUpdating = false; - - /** - The store that created this record array. - - @property store - @private - @type DS.Store - */ - this.store = this.store || null; - this._updatingPromise = null; - }, - - replace() { - throw new Error(`The result of a server query (for all ${this.modelName} types) is immutable. To modify contents, use toArray()`); - }, - - /** - The modelClass represented by this record array. - - @property type - @type DS.Model - */ - type: computed$2('modelName', function() { - if (!this.modelName) { - return null; - } - return this.store._modelFor(this.modelName); - }).readOnly(), - - /** - Retrieves an object from the content by index. - - @method objectAtContent - @private - @param {Number} index - @return {DS.Model} record - */ - objectAtContent(index) { - let internalModel = get$13(this, 'content').objectAt(index); - return internalModel && internalModel.getRecord(); - }, - - /** - Used to get the latest version of all of the records in this array - from the adapter. - - Example - - ```javascript - var people = store.peekAll('person'); - people.get('isUpdating'); // false - - people.update().then(function() { - people.get('isUpdating'); // false - }); - - people.get('isUpdating'); // true - ``` - - @method update - */ - update() { - if (get$13(this, 'isUpdating')) { return this._updatingPromise; } - - this.set('isUpdating', true); - - let updatingPromise = this._update().finally(() => { - this._updatingPromise = null; - if (this.get('isDestroying') || this.get('isDestroyed')) { return } - this.set('isUpdating', false); - }); - - this._updatingPromise = updatingPromise; - - return updatingPromise; - }, - - /* - Update this RecordArray and return a promise which resolves once the update - is finished. - */ - _update() { - return this.store.findAll(this.modelName, { reload: true }); - }, - - /** - Adds an internal model to the `RecordArray` without duplicates - - @method _pushInternalModels - @private - @param {InternalModel} internalModel - */ - _pushInternalModels(internalModels) { - // pushObjects because the internalModels._recordArrays set was already - // consulted for inclusion, so addObject and its on .contains call is not - // required. - get$13(this, 'content').pushObjects(internalModels); - }, - - /** - Removes an internalModel to the `RecordArray`. - - @method removeInternalModel - @private - @param {InternalModel} internalModel - */ - _removeInternalModels(internalModels) { - get$13(this, 'content').removeObjects(internalModels); - }, - - /** - Saves all of the records in the `RecordArray`. - - Example - - ```javascript - var messages = store.peekAll('message'); - messages.forEach(function(message) { - message.set('hasBeenSeen', true); - }); - messages.save(); - ``` - - @method save - @return {DS.PromiseArray} promise - */ - save() { - let promiseLabel = `DS: RecordArray#save ${this.modelName}`; - let promise = Promise$4.all(this.invoke('save'), promiseLabel) - .then(() => this, null, 'DS: RecordArray#save return RecordArray'); - - return PromiseArray.create({ promise }); - }, - - _dissociateFromOwnRecords() { - this.get('content').forEach(internalModel => { - let recordArrays = internalModel.__recordArrays; - - if (recordArrays) { - recordArrays.delete(this); - } - }); - }, - - /** - @method _unregisterFromManager - @private - */ - _unregisterFromManager() { - this.manager.unregisterRecordArray(this); - }, - - willDestroy() { - this._unregisterFromManager(); - this._dissociateFromOwnRecords(); - // TODO: we should not do work during destroy: - // * when objects are destroyed, they should simply be left to do - // * if logic errors do to this, that logic needs to be more careful during - // teardown (ember provides isDestroying/isDestroyed) for this reason - // * the exception being: if an dominator has a reference to this object, - // and must be informed to release e.g. e.g. removing itself from th - // recordArrayMananger - set$3(this, 'content', null); - set$3(this, 'length', 0); - this._super(...arguments); - }, - - /* - @method _createSnapshot - @private - */ - _createSnapshot(options) { - // this is private for users, but public for ember-data internals - return new SnapshotRecordArray(this, this.get('meta'), options); - }, - - /* - @method _takeSnapshot - @private - */ - _takeSnapshot() { - return get$13(this, 'content').map(internalModel => internalModel.createSnapshot()); - } -}); - -/** - @module ember-data -*/ - -const { get: get$14 } = Ember; - -/** - Represents a list of records whose membership is determined by the - store. As records are created, loaded, or modified, the store - evaluates them to determine if they should be part of the record - array. - - @class FilteredRecordArray - @namespace DS - @extends DS.RecordArray -*/ -var FilteredRecordArray = RecordArray.extend({ - init() { - this._super(...arguments); - - this.set('filterFunction', this.get('filterFunction') || null); - this.isLoaded = true; - }, - /** - The filterFunction is a function used to test records from the store to - determine if they should be part of the record array. - - Example - - ```javascript - var allPeople = store.peekAll('person'); - allPeople.mapBy('name'); // ["Tom Dale", "Yehuda Katz", "Trek Glowacki"] - - var people = store.filter('person', function(person) { - if (person.get('name').match(/Katz$/)) { return true; } - }); - people.mapBy('name'); // ["Yehuda Katz"] - - var notKatzFilter = function(person) { - return !person.get('name').match(/Katz$/); - }; - people.set('filterFunction', notKatzFilter); - people.mapBy('name'); // ["Tom Dale", "Trek Glowacki"] - ``` - - @method filterFunction - @param {DS.Model} record - @return {Boolean} `true` if the record should be in the array - */ - - replace() { - throw new Error(`The result of a client-side filter (on ${this.modelName}) is immutable.`); - }, - - /** - @method updateFilter - @private - */ - _updateFilter() { - if (get$14(this, 'isDestroying') || get$14(this, 'isDestroyed')) { - return; - } - get$14(this, 'manager').updateFilter(this, this.modelName, get$14(this, 'filterFunction')); - }, - - updateFilter: Ember.observer('filterFunction', function() { - Ember.run.once(this, this._updateFilter); - }) -}); - -function cloneNull(source) { - let clone = Object.create(null); - for (let key in source) { - clone[key] = source[key]; - } - return clone; -} - -/** - @module ember-data -*/ - -const { get: get$15 } = Ember; - -/** - Represents an ordered list of records whose order and membership is - determined by the adapter. For example, a query sent to the adapter - may trigger a search on the server, whose results would be loaded - into an instance of the `AdapterPopulatedRecordArray`. - - --- - - If you want to update the array and get the latest records from the - adapter, you can invoke [`update()`](#method_update): - - Example - - ```javascript - // GET /users?isAdmin=true - var admins = store.query('user', { isAdmin: true }); - - admins.then(function() { - console.log(admins.get("length")); // 42 - }); - - // somewhere later in the app code, when new admins have been created - // in the meantime - // - // GET /users?isAdmin=true - admins.update().then(function() { - admins.get('isUpdating'); // false - console.log(admins.get("length")); // 123 - }); - - admins.get('isUpdating'); // true - ``` - - @class AdapterPopulatedRecordArray - @namespace DS - @extends DS.RecordArray -*/ -var AdapterPopulatedRecordArray = RecordArray.extend({ - init() { - // yes we are touching `this` before super, but ArrayProxy has a bug that requires this. - this.set('content', this.get('content') || Ember.A()); - - this._super(...arguments); - this.query = this.query || null; - this.links = null; - }, - - replace() { - throw new Error(`The result of a server query (on ${this.modelName}) is immutable.`); - }, - - _update() { - let store = get$15(this, 'store'); - let query = get$15(this, 'query'); - - return store._query(this.modelName, query, this); - }, - - /** - @method _setInternalModels - @param {Array} internalModels - @param {Object} payload normalized payload - @private - */ - _setInternalModels(internalModels, payload) { - let token = heimdall.start('AdapterPopulatedRecordArray._setInternalModels'); - - // TODO: initial load should not cause change events at all, only - // subsequent. This requires changing the public api of adapter.query, but - // hopefully we can do that soon. - this.get('content').setObjects(internalModels); - - this.setProperties({ - isLoaded: true, - isUpdating: false, - meta: cloneNull(payload.meta), - links: cloneNull(payload.links) - }); - - for (let i = 0, l = internalModels.length; i < l; i++) { - let internalModel = internalModels[i]; - - internalModel._recordArrays.add(this); - } - - // TODO: should triggering didLoad event be the last action of the runLoop? - Ember.run.once(this, 'trigger', 'didLoad'); - heimdall.stop(token); - } -}); - -/** - @module ember-data -*/ - -/** - @module ember-data -*/ - -const { - get: get$12, - run: emberRun$1 -} = Ember; - -const { - _flush, - array_flatten, - array_remove, - create, - createAdapterPopulatedRecordArray, - createFilteredRecordArray, - createRecordArray, - liveRecordArrayFor, - filteredRecordArraysFor, - populateLiveRecordArray, - recordDidChange, - registerFilteredRecordArray, - unregisterRecordArray, - updateFilter, - updateFilterRecordArray -} = heimdall.registerMonitor('recordArrayManager', - '_flush', - 'array_fatten', - 'array_remove', - 'create', - 'createAdapterPopulatedRecordArray', - 'createFilteredRecordArray', - 'createRecordArray', - 'liveRecordArrayFor', - 'filteredRecordArraysFor', - 'populateLiveRecordArray', - 'recordDidChange', - 'registerFilteredRecordArray', - 'unregisterRecordArray', - 'updateFilter', - 'updateFilterRecordArray' -); - -/** - @class RecordArrayManager - @namespace DS - @private -*/ -class RecordArrayManager { - constructor(options) { - heimdall.increment(create); - this.store = options.store; - this.isDestroying = false; - this.isDestroyed = false; - this._filteredRecordArrays = Object.create(null); - this._liveRecordArrays = Object.create(null); - this._pending = Object.create(null); - this._adapterPopulatedRecordArrays = []; - } - - recordDidChange(internalModel) { - // TODO: change name - // TODO: track that it was also a change - this.internalModelDidChange(internalModel); - } - - recordWasLoaded(internalModel) { - // TODO: change name - // TODO: track that it was also that it was first loaded - this.internalModelDidChange(internalModel); - } - - internalModelDidChange(internalModel) { - heimdall.increment(recordDidChange); - - let modelName = internalModel.modelName; - - if (internalModel._pendingRecordArrayManagerFlush) { - return; - } - - internalModel._pendingRecordArrayManagerFlush = true; - - let pending = this._pending; - let models = pending[modelName] = pending[modelName] || []; - if (models.push(internalModel) !== 1) { - return; - } - - emberRun$1.schedule('actions', this, this._flush); - } - - _flush() { - heimdall.increment(_flush); - - let pending = this._pending; - this._pending = Object.create(null); - let modelsToRemove = []; - - for (let modelName in pending) { - let internalModels = pending[modelName]; - for (let j = 0; j < internalModels.length; j++) { - let internalModel = internalModels[j]; - // mark internalModels, so they can once again be processed by the - // recordArrayManager - internalModel._pendingRecordArrayManagerFlush = false; - // build up a set of models to ensure we have purged correctly; - if (internalModel.isHiddenFromRecordArrays()) { - modelsToRemove.push(internalModel); - } - } - - // process filteredRecordArrays - if (this._filteredRecordArrays[modelName]) { - let recordArrays = this.filteredRecordArraysFor(modelName); - for (let i = 0; i < recordArrays.length; i++) { - this.updateFilterRecordArray(recordArrays[i], modelName, internalModels); - } - } - - // TODO: skip if it only changed - // process liveRecordArrays - if (this._liveRecordArrays[modelName]) { - this.updateLiveRecordArray(modelName, internalModels); - } - - // process adapterPopulatedRecordArrays - if (modelsToRemove.length > 0) { - this.removeFromAdapterPopulatedRecordArrays(modelsToRemove); - } - } - } - - updateLiveRecordArray(modelName, internalModels) { - let array = this.liveRecordArrayFor(modelName); - - let modelsToAdd = []; - let modelsToRemove = []; - - for (let i = 0; i < internalModels.length; i++) { - let internalModel = internalModels[i]; - let isDeleted = internalModel.isHiddenFromRecordArrays(); - let recordArrays = internalModel._recordArrays; - - if (!isDeleted && !internalModel.isEmpty()) { - if (!recordArrays.has(array)) { - modelsToAdd.push(internalModel); - recordArrays.add(array); - } - } - - if (isDeleted) { - modelsToRemove.push(internalModel); - recordArrays.delete(array); - } - } - - if (modelsToAdd.length > 0) { array._pushInternalModels(modelsToAdd); } - if (modelsToRemove.length > 0) { array._removeInternalModels(modelsToRemove); } - } - - removeFromAdapterPopulatedRecordArrays(internalModels) { - for (let i = 0; i < internalModels.length; i++) { - let internalModel = internalModels[i]; - let list = internalModel._recordArrays.list; - - for (let j = 0; j < list.length; j++) { - // TODO: group by arrays, so we can batch remove - list[j]._removeInternalModels([internalModel]); - } - - internalModel._recordArrays.clear(); - } - } - - /** - Update an individual filter. - - @private - @method updateFilterRecordArray - @param {DS.FilteredRecordArray} array - @param {String} modelName - @param {Array} internalModels - */ - updateFilterRecordArray(array, modelName, internalModels) { - heimdall.increment(updateFilterRecordArray); - - let filter = get$12(array, 'filterFunction'); - - let shouldBeInAdded = []; - let shouldBeRemoved = []; - - for (let i = 0; i < internalModels.length; i++) { - let internalModel = internalModels[i]; - if (internalModel.isHiddenFromRecordArrays() === false && - filter(internalModel.getRecord())) { - if (internalModel._recordArrays.has(array)) { continue; } - shouldBeInAdded.push(internalModel); - internalModel._recordArrays.add(array); - } else { - if (internalModel._recordArrays.delete(array)) { - shouldBeRemoved.push(internalModel); - } - } - } - - if (shouldBeInAdded.length > 0) { array._pushInternalModels(shouldBeInAdded); } - if (shouldBeRemoved.length > 0) { array._removeInternalModels(shouldBeRemoved); } - } - - // TODO: remove, utilize existing flush code but make it flush sync based on 1 modelName - syncLiveRecordArray(array, modelName) { - assert(`recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); - let hasNoPotentialDeletions = Object.keys(this._pending).length === 0; - let map = this.store._internalModelsFor(modelName); - let hasNoInsertionsOrRemovals = get$12(map, 'length') === get$12(array, 'length'); - - /* - Ideally the recordArrayManager has knowledge of the changes to be applied to - liveRecordArrays, and is capable of strategically flushing those changes and applying - small diffs if desired. However, until we've refactored recordArrayManager, this dirty - check prevents us from unnecessarily wiping out live record arrays returned by peekAll. - */ - if (hasNoPotentialDeletions && hasNoInsertionsOrRemovals) { - return; - } - - this.populateLiveRecordArray(array, map.models); - } - - // TODO: remove, when syncLiveRecordArray is removed - populateLiveRecordArray(array, internalModels) { - heimdall.increment(populateLiveRecordArray); - - let modelsToAdd = []; - for (let i = 0; i < internalModels.length; i++) { - let internalModel = internalModels[i]; - - if (!internalModel.isHiddenFromRecordArrays()) { - let recordArrays = internalModel._recordArrays; - - if (!recordArrays.has(array)) { - modelsToAdd.push(internalModel); - recordArrays.add(array); - } - } - } - - array._pushInternalModels(modelsToAdd); - } - - /** - This method is invoked if the `filterFunction` property is - changed on a `DS.FilteredRecordArray`. - - It essentially re-runs the filter from scratch. This same - method is invoked when the filter is created in th first place. - - @method updateFilter - @param {Array} array - @param {String} modelName - @param {Function} filter - */ - updateFilter(array, modelName, filter) { - assert(`recordArrayManger.updateFilter expects modelName not modelClass as the second param, received ${modelName}`, typeof modelName === 'string'); - heimdall.increment(updateFilter); - let modelMap = this.store._internalModelsFor(modelName); - let internalModels = modelMap.models; - - this.updateFilterRecordArray(array, filter, internalModels); - } - - /** - Get the `DS.RecordArray` for a modelName, which contains all loaded records of - given modelName. - - @method liveRecordArrayFor - @param {String} modelName - @return {DS.RecordArray} - */ - liveRecordArrayFor(modelName) { - assert(`recordArrayManger.liveRecordArrayFor expects modelName not modelClass as the param`, typeof modelName === 'string'); - - heimdall.increment(liveRecordArrayFor); - - return this._liveRecordArrays[modelName] || (this._liveRecordArrays[modelName] = this.createRecordArray(modelName)) - } - - /** - Get the `DS.RecordArray` for a modelName, which contains all loaded records of - given modelName. - - @method filteredRecordArraysFor - @param {String} modelName - @return {DS.RecordArray} - */ - filteredRecordArraysFor(modelName) { - assert(`recordArrayManger.filteredRecordArraysFor expects modelName not modelClass as the param`, typeof modelName === 'string'); - - heimdall.increment(filteredRecordArraysFor); - - return this._filteredRecordArrays[modelName] || (this._filteredRecordArrays[modelName] = []); - } - /** - Create a `DS.RecordArray` for a modelName. - - @method createRecordArray - @param {String} modelName - @return {DS.RecordArray} - */ - createRecordArray(modelName) { - assert(`recordArrayManger.createRecordArray expects modelName not modelClass as the param`, typeof modelName === 'string'); - heimdall.increment(createRecordArray); - return RecordArray.create({ - modelName, - content: Ember.A(), - store: this.store, - isLoaded: true, - manager: this - }); - } - - /** - Create a `DS.FilteredRecordArray` for a modelName and register it for updates. - - @method createFilteredRecordArray - @param {String} modelName - @param {Function} filter - @param {Object} query (optional - @return {DS.FilteredRecordArray} - */ - createFilteredRecordArray(modelName, filter, query) { - assert(`recordArrayManger.createFilteredRecordArray expects modelName not modelClass as the first param, received ${modelName}`, typeof modelName === 'string'); - - heimdall.increment(createFilteredRecordArray); - let array = FilteredRecordArray.create({ - query, - modelName, - content: Ember.A(), - store: this.store, - manager: this, - filterFunction: filter - }); - - this.registerFilteredRecordArray(array, modelName, filter); - - return array; - } - - /** - Create a `DS.AdapterPopulatedRecordArray` for a modelName with given query. - - @method createAdapterPopulatedRecordArray - @param {String} modelName - @param {Object} query - @return {DS.AdapterPopulatedRecordArray} - */ - createAdapterPopulatedRecordArray(modelName, query) { - heimdall.increment(createAdapterPopulatedRecordArray); - assert(`recordArrayManger.createAdapterPopulatedRecordArray expects modelName not modelClass as the first param, received ${modelName}`, typeof modelName === 'string'); - - let array = AdapterPopulatedRecordArray.create({ - modelName, - query: query, - content: Ember.A(), - store: this.store, - manager: this - }); - - this._adapterPopulatedRecordArrays.push(array); - - return array; - } - - /** - Register a RecordArray for a given modelName to be backed by - a filter function. This will cause the array to update - automatically when records of that modelName change attribute - values or states. - - @method registerFilteredRecordArray - @param {DS.RecordArray} array - @param {String} modelName - @param {Function} filter - */ - registerFilteredRecordArray(array, modelName, filter) { - heimdall.increment(registerFilteredRecordArray); - assert(`recordArrayManger.registerFilteredRecordArray expects modelName not modelClass as the second param, received ${modelName}`, typeof modelName === 'string'); - - this.filteredRecordArraysFor(modelName).push(array); - this.updateFilter(array, modelName, filter); - } - - /** - Unregister a RecordArray. - So manager will not update this array. - - @method unregisterRecordArray - @param {DS.RecordArray} array - */ - unregisterRecordArray(array) { - heimdall.increment(unregisterRecordArray); - - let modelName = array.modelName; - - // unregister filtered record array - let recordArrays = this.filteredRecordArraysFor(modelName); - let removedFromFiltered = remove(recordArrays, array); - - // remove from adapter populated record array - let removedFromAdapterPopulated = remove(this._adapterPopulatedRecordArrays, array); - - if (!removedFromFiltered && !removedFromAdapterPopulated) { - - let liveRecordArrayForType = this._liveRecordArrays[modelName]; - // unregister live record array - if (liveRecordArrayForType) { - if (array === liveRecordArrayForType) { - delete this._liveRecordArrays[modelName]; - } - } - } - } - - willDestroy() { - Object.keys(this._filteredRecordArrays).forEach(modelName => flatten(this._filteredRecordArrays[modelName]).forEach(destroy)); - Object.keys(this._liveRecordArrays).forEach(modelName => this._liveRecordArrays[modelName].destroy()); - this._adapterPopulatedRecordArrays.forEach(destroy); - this.isDestroyed = true; - } - - destroy() { - this.isDestroying = true; - Ember.run.schedule('actions', this, this.willDestroy); - } -} - -function destroy(entry) { - entry.destroy(); -} - -function flatten(list) { - heimdall.increment(array_flatten); - let length = list.length; - let result = []; - - for (let i = 0; i < length; i++) { - result = result.concat(list[i]); - } - - return result; -} - -function remove(array, item) { - heimdall.increment(array_remove); - let index = array.indexOf(item); - - if (index !== -1) { - array.splice(index, 1); - return true; - } - - return false; -} - -/* global heimdall */ -const { set: set$4 } = Ember; - -const { - __get, - _instanceFor -} = heimdall.registerMonitor('system.store.container-instance-cache', - '__get', - '_instanceFor' -); - -/* - * The `ContainerInstanceCache` serves as a lazy cache for looking up - * instances of serializers and adapters. It has some additional logic for - * finding the 'fallback' adapter or serializer. - * - * The 'fallback' adapter or serializer is an adapter or serializer that is looked up - * when the preferred lookup fails. For example, say you try to look up `adapter:post`, - * but there is no entry (app/adapters/post.js in EmberCLI) for `adapter:post` in the registry. - * - * When an adapter or serializer is unfound, getFallbacks will be invoked with the current namespace - * ('adapter' or 'serializer') and the 'preferredKey' (usually a modelName). The method should return - * an array of keys to check against. - * - * The first entry in the fallbacks array that exists in the container will then be cached for - * `adapter:post`. So, the next time you look up `adapter:post`, you'll get the `adapter:application` - * instance (or whatever the fallback was if `adapter:application` doesn't exist). - * - * @private - * @class ContainerInstanceCache - * -*/ -class ContainerInstanceCache { - constructor(owner, store) { - this.isDestroying = false; - this.isDestroyed = false; - this._owner = owner; - this._store = store; - this._namespaces = { - adapter: Object.create(null), - serializer: Object.create(null) - }; - } - - get(namespace, preferredKey) { - heimdall.increment(__get); - let cache = this._namespaces[namespace]; - - if (cache[preferredKey]) { - return cache[preferredKey]; - } - - let preferredLookupKey = `${namespace}:${preferredKey}`; - - let instance = this._instanceFor(preferredLookupKey) || this._findInstance(namespace, this._fallbacksFor(namespace, preferredKey)); - if (instance) { - cache[preferredKey] = instance; - set$4(instance, 'store', this._store); - } - - return cache[preferredKey]; - } - - _fallbacksFor(namespace, preferredKey) { - if (namespace === 'adapter') { - return ['application', this._store.get('adapter'), '-json-api']; - } - - // serializer - return [ - 'application', - this.get('adapter', preferredKey).get('defaultSerializer'), - '-default' - ]; - } - - _findInstance(namespace, fallbacks) { - let cache = this._namespaces[namespace]; - - for (let i = 0, length = fallbacks.length; i < length; i++) { - let fallback = fallbacks[i]; - - if (cache[fallback]) { - return cache[fallback]; - } - - let lookupKey = `${namespace}:${fallback}`; - let instance = this._instanceFor(lookupKey); - - if (instance) { - cache[fallback] = instance; - return instance; - } - } - } - - _instanceFor(key) { - heimdall.increment(_instanceFor); - return this._owner.lookup(key); - } - - destroyCache(cache) { - let cacheEntries = Object.keys(cache); - - for (let i = 0, length = cacheEntries.length; i < length; i++) { - let cacheKey = cacheEntries[i]; - let cacheEntry = cache[cacheKey]; - if (cacheEntry) { - cacheEntry.destroy(); - } - } - } - - destroy() { - this.isDestroying = true; - this.destroyCache(this._namespaces.adapter); - this.destroyCache(this._namespaces.serializer); - this.isDestroyed = true; - } - - toString() { - return 'ContainerInstanceCache'; - } -} - -/** - @module ember-data -*/ - -const badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; - -const { - A, - _Backburner: Backburner, - computed: computed$1, - copy, - ENV, - Error: EmberError, - get: get$3, - inspect, - isNone, - isPresent, - MapWithDefault: MapWithDefault$2, - run: emberRun, - set: set$1, - RSVP, - Service, - typeOf -} = Ember; - -const { Promise: Promise$1 } = RSVP; - -//Get the materialized model from the internalModel/promise that returns -//an internal model and return it in a promiseObject. Useful for returning -//from find methods -function promiseRecord(internalModelPromise, label) { - let toReturn = internalModelPromise.then(internalModel => internalModel.getRecord()); - - return promiseObject(toReturn, label); -} - -let Store; - -// Implementors Note: -// -// The variables in this file are consistently named according to the following -// scheme: -// -// * +id+ means an identifier managed by an external source, provided inside -// the data provided by that source. These are always coerced to be strings -// before being used internally. -// * +clientId+ means a transient numerical identifier generated at runtime by -// the data store. It is important primarily because newly created objects may -// not yet have an externally generated id. -// * +internalModel+ means a record internalModel object, which holds metadata about a -// record, even if it has not yet been fully materialized. -// * +type+ means a DS.Model. - -const { - _generateId, - _internalModelForId, - _load, - _modelForMixin, - _pushInternalModel, - _setupRelationships, - adapterFor, - _buildInternalModel, - _didUpdateAll, - modelFactoryFor, - modelFor, - normalize, - peekAll, - peekRecord, - serializerFor, - _internalModelsFor -} = heimdall.registerMonitor('store', - '_generateId', - '_internalModelForId', - '_load', - '_modelForMixin', - '_pushInternalModel', - '_setupRelationships', - 'adapterFor', - '_buildInternalModel', - '_didUpdateAll', - 'modelFactoryFor', - 'modelFor', - 'normalize', - 'peekAll', - 'peekRecord', - 'serializerFor', - '_internalModelsFor' -); - -/** - The store contains all of the data for records loaded from the server. - It is also responsible for creating instances of `DS.Model` that wrap - the individual data for a record, so that they can be bound to in your - Handlebars templates. - - Define your application's store like this: - - ```app/services/store.js - import DS from 'ember-data'; - - export default DS.Store.extend({ - }); - ``` - - Most Ember.js applications will only have a single `DS.Store` that is - automatically created by their `Ember.Application`. - - You can retrieve models from the store in several ways. To retrieve a record - for a specific id, use `DS.Store`'s `findRecord()` method: - - ```javascript - store.findRecord('person', 123).then(function (person) { - }); - ``` - - By default, the store will talk to your backend using a standard - REST mechanism. You can customize how the store talks to your - backend by specifying a custom adapter: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - }); - ``` - - You can learn more about writing a custom adapter by reading the `DS.Adapter` - documentation. - - ### Store createRecord() vs. push() vs. pushPayload() - - The store provides multiple ways to create new record objects. They have - some subtle differences in their use which are detailed below: - - [createRecord](#method_createRecord) is used for creating new - records on the client side. This will return a new record in the - `created.uncommitted` state. In order to persist this record to the - backend you will need to call `record.save()`. - - [push](#method_push) is used to notify Ember Data's store of new or - updated records that exist in the backend. This will return a record - in the `loaded.saved` state. The primary use-case for `store#push` is - to notify Ember Data about record updates (full or partial) that happen - outside of the normal adapter methods (for example - [SSE](http://dev.w3.org/html5/eventsource/) or [Web - Sockets](http://www.w3.org/TR/2009/WD-websockets-20091222/)). - - [pushPayload](#method_pushPayload) is a convenience wrapper for - `store#push` that will deserialize payloads if the - Serializer implements a `pushPayload` method. - - Note: When creating a new record using any of the above methods - Ember Data will update `DS.RecordArray`s such as those returned by - `store#peekAll()`, `store#findAll()` or `store#filter()`. This means any - data bindings or computed properties that depend on the RecordArray - will automatically be synced to include the new or updated record - values. - - @class Store - @namespace DS - @extends Ember.Service -*/ -Store = Service.extend({ - - /** - @method init - @private - */ - init() { - this._super(...arguments); - this._backburner = new Backburner(['normalizeRelationships', 'syncRelationships', 'finished']); - // internal bookkeeping; not observable - this.recordArrayManager = new RecordArrayManager({ store: this }); - this._identityMap = new IdentityMap(); - this._pendingSave = []; - this._instanceCache = new ContainerInstanceCache(getOwner(this), this); - this._modelFactoryCache = Object.create(null); - this._relationshipsPayloads = new RelationshipPayloadsManager(this); - - /* - Ember Data uses several specialized micro-queues for organizing - and coalescing similar async work. - - These queues are currently controlled by a flush scheduled into - ember-data's custom backburner instance. - */ - // used for coalescing record save requests - this._pendingSave = []; - // used for coalescing relationship updates - this._updatedRelationships = []; - // used for coalescing relationship setup needs - this._pushedInternalModels = []; - // used for coalescing internal model updates - this._updatedInternalModels = []; - - // used to keep track of all the find requests that need to be coalesced - this._pendingFetch = MapWithDefault$2.create({ defaultValue() { return []; } }); - - this._instanceCache = new ContainerInstanceCache(getOwner(this), this); - }, - - /** - The default adapter to use to communicate to a backend server or - other persistence layer. This will be overridden by an application - adapter if present. - - If you want to specify `app/adapters/custom.js` as a string, do: - - ```js - import DS from 'ember-data'; - - export default DS.Store.extend({ - adapter: 'custom', - }); - ``` - - @property adapter - @default '-json-api' - @type {String} - */ - adapter: '-json-api', - - /** - Returns a JSON representation of the record using a custom - type-specific serializer, if one exists. - - The available options are: - - * `includeId`: `true` if the record's ID should be included in - the JSON representation - - @method serialize - @private - @deprecated - @param {DS.Model} record the record to serialize - @param {Object} options an options hash - */ - serialize(record, options) { - if (isEnabled('ds-deprecate-store-serialize')) { - deprecate('Use of store.serialize is deprecated, use record.serialize instead.', false, { - id: 'ds.store.serialize', - until: '3.0' - }); - } - let snapshot = record._internalModel.createSnapshot(); - return snapshot.serialize(options); - }, - - /** - This property returns the adapter, after resolving a possible - string key. - - If the supplied `adapter` was a class, or a String property - path resolved to a class, this property will instantiate the - class. - - This property is cacheable, so the same instance of a specified - adapter class should be used for the lifetime of the store. - - @property defaultAdapter - @private - @return DS.Adapter - */ - defaultAdapter: computed$1('adapter', function() { - let adapter = get$3(this, 'adapter'); - - assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name', typeof adapter === 'string'); - - return this.adapterFor(adapter); - }), - - // ..................... - // . CREATE NEW RECORD . - // ..................... - - /** - Create a new record in the current store. The properties passed - to this method are set on the newly created record. - - To create a new instance of a `Post`: - - ```js - store.createRecord('post', { - title: 'Rails is omakase' - }); - ``` - - To create a new instance of a `Post` that has a relationship with a `User` record: - - ```js - let user = this.store.peekRecord('user', 1); - store.createRecord('post', { - title: 'Rails is omakase', - user: user - }); - ``` - - @method createRecord - @param {String} modelName - @param {Object} inputProperties a hash of properties to set on the - newly created record. - @return {DS.Model} record - */ - createRecord(modelName, inputProperties) { - assert(`You need to pass a model name to the store's createRecord method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = normalizeModelName(modelName); - let properties = copy(inputProperties) || Object.create(null); - - // If the passed properties do not include a primary key, - // give the adapter an opportunity to generate one. Typically, - // client-side ID generators will use something like uuid.js - // to avoid conflicts. - - if (isNone(properties.id)) { - properties.id = this._generateId(normalizedModelName, properties); - } - - // Coerce ID to a string - properties.id = coerceId(properties.id); - - let internalModel = this._buildInternalModel(normalizedModelName, properties.id); - let record = internalModel.getRecord(); - - // Move the record out of its initial `empty` state into - // the `loaded` state. - // TODO @runspired this seems really bad, store should not be changing the state - internalModel.loadedData(); - - // Set the properties specified on the record. - // TODO @runspired this is probably why we do the bad thing above - record.setProperties(properties); - - // TODO @runspired this should also be coalesced into some form of internalModel.setState() - internalModel.eachRelationship((key, descriptor) => { - internalModel._relationships.get(key).setHasData(true); - }); - - return record; - }, - - /** - If possible, this method asks the adapter to generate an ID for - a newly created record. - - @method _generateId - @private - @param {String} modelName - @param {Object} properties from the new record - @return {String} if the adapter can generate one, an ID - */ - _generateId(modelName, properties) { - heimdall.increment(_generateId); - let adapter = this.adapterFor(modelName); - - if (adapter && adapter.generateIdForRecord) { - return adapter.generateIdForRecord(this, modelName, properties); - } - - return null; - }, - - // ................. - // . DELETE RECORD . - // ................. - - /** - For symmetry, a record can be deleted via the store. - - Example - - ```javascript - let post = store.createRecord('post', { - title: 'Rails is omakase' - }); - - store.deleteRecord(post); - ``` - - @method deleteRecord - @param {DS.Model} record - */ - deleteRecord(record) { - record.deleteRecord(); - }, - - /** - For symmetry, a record can be unloaded via the store. - This will cause the record to be destroyed and freed up for garbage collection. - - Example - - ```javascript - store.findRecord('post', 1).then(function(post) { - store.unloadRecord(post); - }); - ``` - - @method unloadRecord - @param {DS.Model} record - */ - unloadRecord(record) { - record.unloadRecord(); - }, - - // ................ - // . FIND RECORDS . - // ................ - - /** - @method find - @param {String} modelName - @param {String|Integer} id - @param {Object} options - @return {Promise} promise - @private - */ - find(modelName, id, options) { - // The default `model` hook in Ember.Route calls `find(modelName, id)`, - // that's why we have to keep this method around even though `findRecord` is - // the public way to get a record by modelName and id. - assert(`Using store.find(type) has been removed. Use store.findAll(modelName) to retrieve all records for a given type.`, arguments.length !== 1); - assert(`Calling store.find(modelName, id, { preload: preload }) is no longer supported. Use store.findRecord(modelName, id, { preload: preload }) instead.`, !options); - assert(`You need to pass the model name and id to the store's find method`, arguments.length === 2); - assert(`You cannot pass '${id}' as id to the store's find method`, typeof id === 'string' || typeof id === 'number'); - assert(`Calling store.find() with a query object is no longer supported. Use store.query() instead.`, typeof id !== 'object'); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - - let normalizedModelName = normalizeModelName(modelName); - - return this.findRecord(normalizedModelName, id); - }, - - /** - This method returns a record for a given type and id combination. - - The `findRecord` method will always resolve its promise with the same - object for a given type and `id`. - - The `findRecord` method will always return a **promise** that will be - resolved with the record. - - Example - - ```app/routes/post.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - model(params) { - return this.store.findRecord('post', params.post_id); - } - }); - ``` - - If the record is not yet available, the store will ask the adapter's `find` - method to find the necessary data. If the record is already present in the - store, it depends on the reload behavior _when_ the returned promise - resolves. - - ### Preloading - - You can optionally `preload` specific attributes and relationships that you know of - by passing them via the passed `options`. - - For example, if your Ember route looks like `/posts/1/comments/2` and your API route - for the comment also looks like `/posts/1/comments/2` if you want to fetch the comment - without fetching the post you can pass in the post to the `findRecord` call: - - ```javascript - store.findRecord('comment', 2, { preload: { post: 1 } }); - ``` - - If you have access to the post model you can also pass the model itself: - - ```javascript - store.findRecord('post', 1).then(function (myPostModel) { - store.findRecord('comment', 2, { post: myPostModel }); - }); - ``` - - ### Reloading - - The reload behavior is configured either via the passed `options` hash or - the result of the adapter's `shouldReloadRecord`. - - If `{ reload: true }` is passed or `adapter.shouldReloadRecord` evaluates - to `true`, then the returned promise resolves once the adapter returns - data, regardless if the requested record is already in the store: - - ```js - store.push({ - data: { - id: 1, - type: 'post', - revision: 1 - } - }); - - // adapter#findRecord resolves with - // [ - // { - // id: 1, - // type: 'post', - // revision: 2 - // } - // ] - store.findRecord('post', 1, { reload: true }).then(function(post) { - post.get('revision'); // 2 - }); - ``` - - If no reload is indicated via the abovementioned ways, then the promise - immediately resolves with the cached version in the store. - - ### Background Reloading - - Optionally, if `adapter.shouldBackgroundReloadRecord` evaluates to `true`, - then a background reload is started, which updates the records' data, once - it is available: - - ```js - // app/adapters/post.js - import ApplicationAdapter from "./application"; - - export default ApplicationAdapter.extend({ - shouldReloadRecord(store, snapshot) { - return false; - }, - - shouldBackgroundReloadRecord(store, snapshot) { - return true; - } - }); - - // ... - - store.push({ - data: { - id: 1, - type: 'post', - revision: 1 - } - }); - - let blogPost = store.findRecord('post', 1).then(function(post) { - post.get('revision'); // 1 - }); - - // later, once adapter#findRecord resolved with - // [ - // { - // id: 1, - // type: 'post', - // revision: 2 - // } - // ] - - blogPost.get('revision'); // 2 - ``` - - If you would like to force or prevent background reloading, you can set a - boolean value for `backgroundReload` in the options object for - `findRecord`. - - ```app/routes/post/edit.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - model(params) { - return this.store.findRecord('post', params.post_id, { backgroundReload: false }); - } - }); - ``` - - If you pass an object on the `adapterOptions` property of the options - argument it will be passed to you adapter via the snapshot - - ```app/routes/post/edit.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - model(params) { - return this.store.findRecord('post', params.post_id, { - adapterOptions: { subscribe: false } - }); - } - }); - ``` - - ```app/adapters/post.js - import MyCustomAdapter from './custom-adapter'; - - export default MyCustomAdapter.extend({ - findRecord(store, type, id, snapshot) { - if (snapshot.adapterOptions.subscribe) { - // ... - } - // ... - } - }); - ``` - - See [peekRecord](#method_peekRecord) to get the cached version of a record. - - ### Retrieving Related Model Records - - If you use an adapter such as Ember's default - [`JSONAPIAdapter`](http://emberjs.com/api/data/classes/DS.JSONAPIAdapter.html) - that supports the [JSON API specification](http://jsonapi.org/) and if your server - endpoint supports the use of an - ['include' query parameter](http://jsonapi.org/format/#fetching-includes), - you can use `findRecord()` to automatically retrieve additional records related to - the one you request by supplying an `include` parameter in the `options` object. - - For example, given a `post` model that has a `hasMany` relationship with a `comment` - model, when we retrieve a specific post we can have the server also return that post's - comments in the same request: - - ```app/routes/post.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - model(params) { - return this.store.findRecord('post', params.post_id, { include: 'comments' }); - } - }); - - ``` - In this case, the post's comments would then be available in your template as - `model.comments`. - - Multiple relationships can be requested using an `include` parameter consisting of a - comma-separated list (without white-space) while nested relationships can be specified - using a dot-separated sequence of relationship names. So to request both the post's - comments and the authors of those comments the request would look like this: - - ```app/routes/post.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - model(params) { - return this.store.findRecord('post', params.post_id, { include: 'comments,comments.author' }); - } - }); - - ``` - - @since 1.13.0 - @method findRecord - @param {String} modelName - @param {(String|Integer)} id - @param {Object} options - @return {Promise} promise - */ - findRecord(modelName, id, options) { - assert(`You need to pass a model name to the store's findRecord method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - assert(badIdFormatAssertion, (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id))); - - let normalizedModelName = normalizeModelName(modelName); - - let internalModel = this._internalModelForId(normalizedModelName, id); - options = options || {}; - - if (!this.hasRecordForId(normalizedModelName, id)) { - return this._findByInternalModel(internalModel, options); - } - - let fetchedInternalModel = this._findRecord(internalModel, options); - - return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${normalizedModelName} with id: ${id}`); - }, - - _findRecord(internalModel, options) { - // Refetch if the reload option is passed - if (options.reload) { - return this._scheduleFetch(internalModel, options); - } - - let snapshot = internalModel.createSnapshot(options); - let adapter = this.adapterFor(internalModel.modelName); - - // Refetch the record if the adapter thinks the record is stale - if (adapter.shouldReloadRecord(this, snapshot)) { - return this._scheduleFetch(internalModel, options); - } - - if (options.backgroundReload === false) { - return Promise$1.resolve(internalModel); - } - - // Trigger the background refetch if backgroundReload option is passed - if (options.backgroundReload || adapter.shouldBackgroundReloadRecord(this, snapshot)) { - this._scheduleFetch(internalModel, options); - } - - // Return the cached record - return Promise$1.resolve(internalModel); - }, - - _findByInternalModel(internalModel, options = {}) { - if (options.preload) { - internalModel.preloadData(options.preload); - } - - let fetchedInternalModel = this._findEmptyInternalModel(internalModel, options); - - return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${internalModel.modelName} with id: ${internalModel.id}`); - }, - - _findEmptyInternalModel(internalModel, options) { - if (internalModel.isEmpty()) { - return this._scheduleFetch(internalModel, options); - } - - //TODO double check about reloading - if (internalModel.isLoading()) { - return internalModel._loadingPromise; - } - - return Promise$1.resolve(internalModel); - }, - - /** - This method makes a series of requests to the adapter's `find` method - and returns a promise that resolves once they are all loaded. - - @private - @method findByIds - @param {String} modelName - @param {Array} ids - @return {Promise} promise - */ - findByIds(modelName, ids) { - assert(`You need to pass a model name to the store's findByIds method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - - let promises = new Array(ids.length); - - let normalizedModelName = normalizeModelName(modelName); - - for (let i = 0; i < ids.length; i++) { - promises[i] = this.findRecord(normalizedModelName, ids[i]); - } - - return promiseArray(RSVP.all(promises).then(A, null, `DS: Store#findByIds of ${normalizedModelName} complete`)); - }, - - /** - This method is called by `findRecord` if it discovers that a particular - type/id pair hasn't been loaded yet to kick off a request to the - adapter. - - @method _fetchRecord - @private - @param {InternalModel} internalModel model - @return {Promise} promise - */ - _fetchRecord(internalModel, options) { - let modelName = internalModel.modelName; - let adapter = this.adapterFor(modelName); - - assert(`You tried to find a record but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to find a record but your adapter (for ${modelName}) does not implement 'findRecord'`, typeof adapter.findRecord === 'function'); - - return _find(adapter, this, internalModel.type, internalModel.id, internalModel, options); - }, - - _scheduleFetchMany(internalModels) { - let fetches = new Array(internalModels.length); - - for (let i = 0; i < internalModels.length; i++) { - fetches[i] = this._scheduleFetch(internalModels[i]); - } - - return Promise$1.all(fetches); - }, - - _scheduleFetch(internalModel, options) { - if (internalModel._loadingPromise) { - return internalModel._loadingPromise; - } - - let { id, modelName } = internalModel; - let resolver = RSVP.defer(`Fetching ${modelName}' with id: ${id}`); - let pendingFetchItem = { - internalModel, - resolver, - options - }; - - let promise = resolver.promise; - - internalModel.loadingData(promise); - if (this._pendingFetch.size === 0) { - emberRun.schedule('afterRender', this, this.flushAllPendingFetches); - } - - this._pendingFetch.get(modelName).push(pendingFetchItem); - - return promise; - }, - - flushAllPendingFetches() { - if (this.isDestroyed || this.isDestroying) { - return; - } - - this._pendingFetch.forEach(this._flushPendingFetchForType, this); - this._pendingFetch.clear(); - }, - - _flushPendingFetchForType(pendingFetchItems, modelName) { - let store = this; - let adapter = store.adapterFor(modelName); - let shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; - let totalItems = pendingFetchItems.length; - let internalModels = new Array(totalItems); - let seeking = Object.create(null); - - for (let i = 0; i < totalItems; i++) { - let pendingItem = pendingFetchItems[i]; - let internalModel = pendingItem.internalModel; - internalModels[i] = internalModel; - seeking[internalModel.id] = pendingItem; - } - - function _fetchRecord(recordResolverPair) { - let recordFetch = store._fetchRecord( - recordResolverPair.internalModel, - recordResolverPair.options - ); // TODO adapter options - - recordResolverPair.resolver.resolve(recordFetch); - } - - function handleFoundRecords(foundInternalModels, expectedInternalModels) { - // resolve found records - let found = Object.create(null); - for (let i = 0, l = foundInternalModels.length; i < l; i++) { - let internalModel = foundInternalModels[i]; - let pair = seeking[internalModel.id]; - found[internalModel.id] = internalModel; - - if (pair) { - let resolver = pair.resolver; - resolver.resolve(internalModel); - } - } - - // reject missing records - let missingInternalModels = []; - - for (let i = 0, l = expectedInternalModels.length; i < l; i++) { - let internalModel = expectedInternalModels[i]; - - if (!found[internalModel.id]) { - missingInternalModels.push(internalModel); - } - } - - if (missingInternalModels.length) { - warn('Ember Data expected to find records with the following ids in the adapter response but they were missing: ' + inspect(missingInternalModels.map(r => r.id)), false, { - id: 'ds.store.missing-records-from-adapter' - }); - rejectInternalModels(missingInternalModels); - } - } - - function rejectInternalModels(internalModels, error) { - for (let i = 0, l = internalModels.length; i < l; i++) { - let internalModel = internalModels[i]; - let pair = seeking[internalModel.id]; - - if (pair) { - pair.resolver.reject(error || new Error(`Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.`)); - } - } - } - - if (shouldCoalesce) { - // TODO: Improve records => snapshots => records => snapshots - // - // We want to provide records to all store methods and snapshots to all - // adapter methods. To make sure we're doing that we're providing an array - // of snapshots to adapter.groupRecordsForFindMany(), which in turn will - // return grouped snapshots instead of grouped records. - // - // But since the _findMany() finder is a store method we need to get the - // records from the grouped snapshots even though the _findMany() finder - // will once again convert the records to snapshots for adapter.findMany() - let snapshots = new Array(totalItems); - for (let i = 0; i < totalItems; i++) { - snapshots[i] = internalModels[i].createSnapshot(); - } - - let groups = adapter.groupRecordsForFindMany(this, snapshots); - - for (let i = 0, l = groups.length; i < l; i++) { - let group = groups[i]; - let totalInGroup = groups[i].length; - let ids = new Array(totalInGroup); - let groupedInternalModels = new Array(totalInGroup); - - for (let j = 0; j < totalInGroup; j++) { - let internalModel = group[j]._internalModel; - - groupedInternalModels[j] = internalModel; - ids[j] = internalModel.id; - } - - if (totalInGroup > 1) { - _findMany(adapter, store, modelName, ids, groupedInternalModels) - .then(function(foundInternalModels) { - handleFoundRecords(foundInternalModels, groupedInternalModels); - }) - .catch(function(error) { - rejectInternalModels(groupedInternalModels, error); - }); - } else if (ids.length === 1) { - let pair = seeking[groupedInternalModels[0].id]; - _fetchRecord(pair); - } else { - assert("You cannot return an empty array from adapter's method groupRecordsForFindMany", false); - } - } - } else { - for (let i = 0; i < totalItems; i++) { - _fetchRecord(pendingFetchItems[i]); - } - } - }, - - /** - Get the reference for the specified record. - - Example - - ```javascript - let userRef = store.getReference('user', 1); - - // check if the user is loaded - let isLoaded = userRef.value() !== null; - - // get the record of the reference (null if not yet available) - let user = userRef.value(); - - // get the identifier of the reference - if (userRef.remoteType() === 'id') { - let id = userRef.id(); - } - - // load user (via store.find) - userRef.load().then(...) - - // or trigger a reload - userRef.reload().then(...) - - // provide data for reference - userRef.push({ id: 1, username: '@user' }).then(function(user) { - userRef.value() === user; - }); - ``` - - @method getReference - @param {String} modelName - @param {String|Integer} id - @since 2.5.0 - @return {RecordReference} - */ - getReference(modelName, id) { - let normalizedModelName = normalizeModelName(modelName); - - return this._internalModelForId(normalizedModelName, id).recordReference; - }, - - /** - Get a record by a given type and ID without triggering a fetch. - - This method will synchronously return the record if it is available in the store, - otherwise it will return `null`. A record is available if it has been fetched earlier, or - pushed manually into the store. - - See [findRecord](#method_findRecord) if you would like to request this record from the backend. - - _Note: This is a synchronous method and does not return a promise._ - - ```js - let post = store.peekRecord('post', 1); - - post.get('id'); // 1 - ``` - - @since 1.13.0 - @method peekRecord - @param {String} modelName - @param {String|Integer} id - @return {DS.Model|null} record - */ - peekRecord(modelName, id) { - heimdall.increment(peekRecord); - assert(`You need to pass a model name to the store's peekRecord method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = normalizeModelName(modelName); - - if (this.hasRecordForId(normalizedModelName, id)) { - return this._internalModelForId(normalizedModelName, id).getRecord(); - } else { - return null; - } - }, - - /** - This method is called by the record's `reload` method. - - This method calls the adapter's `find` method, which returns a promise. When - **that** promise resolves, `reloadRecord` will resolve the promise returned - by the record's `reload`. - - @method reloadRecord - @private - @param {DS.Model} internalModel - @return {Promise} promise - */ - _reloadRecord(internalModel) { - let { id, modelName } = internalModel; - let adapter = this.adapterFor(modelName); - - assert(`You cannot reload a record without an ID`, id); - assert(`You tried to reload a record but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to reload a record but your adapter does not implement 'findRecord'`, typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); - - return this._scheduleFetch(internalModel); - }, - - /** - This method returns true if a record for a given modelName and id is already - loaded in the store. Use this function to know beforehand if a findRecord() - will result in a request or that it will be a cache hit. - - Example - - ```javascript - store.hasRecordForId('post', 1); // false - store.findRecord('post', 1).then(function() { - store.hasRecordForId('post', 1); // true - }); - ``` - - @method hasRecordForId - @param {String} modelName - @param {(String|Integer)} id - @return {Boolean} - */ - hasRecordForId(modelName, id) { - assert(`You need to pass a model name to the store's hasRecordForId method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - - let normalizedModelName = normalizeModelName(modelName); - - let trueId = coerceId(id); - let internalModel = this._internalModelsFor(normalizedModelName).get(trueId); - - return !!internalModel && internalModel.isLoaded(); - }, - - /** - Returns id record for a given type and ID. If one isn't already loaded, - it builds a new record and leaves it in the `empty` state. - - @method recordForId - @private - @param {String} modelName - @param {(String|Integer)} id - @return {DS.Model} record - */ - recordForId(modelName, id) { - assert(`You need to pass a model name to the store's recordForId method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - - return this._internalModelForId(modelName, id).getRecord(); - }, - - _internalModelForId(modelName, id) { - heimdall.increment(_internalModelForId); - let trueId = coerceId(id); - let internalModel = this._internalModelsFor(modelName).get(trueId); - - if (!internalModel) { - internalModel = this._buildInternalModel(modelName, trueId); - } - - return internalModel; - }, - - _internalModelDidReceiveRelationshipData(modelName, id, relationshipData) { - this._relationshipsPayloads.push(modelName, id, relationshipData); - }, - - _internalModelDestroyed(internalModel) { - this._removeFromIdMap(internalModel); - this._relationshipsPayloads.unload(internalModel.modelName, internalModel.id); - }, - - /** - @method findMany - @private - @param {Array} internalModels - @return {Promise} promise - */ - findMany(internalModels) { - let finds = new Array(internalModels.length); - - for (let i = 0; i < internalModels.length; i++) { - finds[i] = this._findEmptyInternalModel(internalModels[i]); - } - - return Promise$1.all(finds); - }, - - - /** - If a relationship was originally populated by the adapter as a link - (as opposed to a list of IDs), this method is called when the - relationship is fetched. - - The link (which is usually a URL) is passed through unchanged, so the - adapter can make whatever request it wants. - - The usual use-case is for the server to register a URL as a link, and - then use that URL in the future to make a request for the relationship. - - @method findHasMany - @private - @param {InternalModel} internalModel - @param {any} link - @param {(Relationship)} relationship - @return {Promise} promise - */ - findHasMany(internalModel, link, relationship) { - let adapter = this.adapterFor(internalModel.modelName); - - assert(`You tried to load a hasMany relationship but you have no adapter (for ${internalModel.modelName})`, adapter); - assert(`You tried to load a hasMany relationship from a specified 'link' in the original payload but your adapter does not implement 'findHasMany'`, typeof adapter.findHasMany === 'function'); - - return _findHasMany(adapter, this, internalModel, link, relationship); - }, - - /** - @method findBelongsTo - @private - @param {InternalModel} internalModel - @param {any} link - @param {Relationship} relationship - @return {Promise} promise - */ - findBelongsTo(internalModel, link, relationship) { - let adapter = this.adapterFor(internalModel.modelName); - - assert(`You tried to load a belongsTo relationship but you have no adapter (for ${internalModel.modelName})`, adapter); - assert(`You tried to load a belongsTo relationship from a specified 'link' in the original payload but your adapter does not implement 'findBelongsTo'`, typeof adapter.findBelongsTo === 'function'); - - return _findBelongsTo(adapter, this, internalModel, link, relationship); - }, - - /** - This method delegates a query to the adapter. This is the one place where - adapter-level semantics are exposed to the application. - - Each time this method is called a new request is made through the adapter. - - Exposing queries this way seems preferable to creating an abstract query - language for all server-side queries, and then require all adapters to - implement them. - - --- - - If you do something like this: - - ```javascript - store.query('person', { page: 1 }); - ``` - - The call made to the server, using a Rails backend, will look something like this: - - ``` - Started GET "/api/v1/person?page=1" - Processing by Api::V1::PersonsController#index as HTML - Parameters: { "page"=>"1" } - ``` - - --- - - If you do something like this: - - ```javascript - store.query('person', { ids: [1, 2, 3] }); - ``` - - The call to the server, using a Rails backend, will look something like this: - - ``` - Started GET "/api/v1/person?ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3" - Processing by Api::V1::PersonsController#index as HTML - Parameters: { "ids" => ["1", "2", "3"] } - ``` - - This method returns a promise, which is resolved with an - [`AdapterPopulatedRecordArray`](http://emberjs.com/api/data/classes/DS.AdapterPopulatedRecordArray.html) - once the server returns. - - @since 1.13.0 - @method query - @param {String} modelName - @param {any} query an opaque query to be used by the adapter - @return {Promise} promise - */ - query(modelName, query) { - assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); - assert(`You need to pass a query hash to the store's query method`, query); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - - let normalizedModelName = normalizeModelName(modelName); - return this._query(normalizedModelName, query); - }, - - _query(modelName, query, array) { - let token = heimdall.start('store._query'); - assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); - assert(`You need to pass a query hash to the store's query method`, query); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - - let modelToken = heimdall.start('initial-modelFor-lookup'); - heimdall.stop(modelToken); - - array = array || this.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); - - let adapterToken = heimdall.start('initial-adapterFor-lookup'); - let adapter = this.adapterFor(modelName); - heimdall.stop(adapterToken); - - assert(`You tried to load a query but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to load a query but your adapter does not implement 'query'`, typeof adapter.query === 'function'); - - let pA = promiseArray(_query(adapter, this, modelName, query, array)); - instrument(() => { - pA.finally(() => { heimdall.stop(token); }); - }); - return pA; - }, - - /** - This method makes a request for one record, where the `id` is not known - beforehand (if the `id` is known, use [`findRecord`](#method_findRecord) - instead). - - This method can be used when it is certain that the server will return a - single object for the primary data. - - Each time this method is called a new request is made through the adapter. - - Let's assume our API provides an endpoint for the currently logged in user - via: - - ``` - // GET /api/current_user - { - user: { - id: 1234, - username: 'admin' - } - } - ``` - - Since the specific `id` of the `user` is not known beforehand, we can use - `queryRecord` to get the user: - - ```javascript - store.queryRecord('user', {}).then(function(user) { - let username = user.get('username'); - console.log(`Currently logged in as ${username}`); - }); - ``` - - The request is made through the adapters' `queryRecord`: - - ```app/adapters/user.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - queryRecord(modelName, query) { - return Ember.$.getJSON('/api/current_user'); - } - }); - ``` - - Note: the primary use case for `store.queryRecord` is when a single record - is queried and the `id` is not known beforehand. In all other cases - `store.query` and using the first item of the array is likely the preferred - way: - - ``` - // GET /users?username=unique - { - data: [{ - id: 1234, - type: 'user', - attributes: { - username: "unique" - } - }] - } - ``` - - ```javascript - store.query('user', { username: 'unique' }).then(function(users) { - return users.get('firstObject'); - }).then(function(user) { - let id = user.get('id'); - }); - ``` - - This method returns a promise, which resolves with the found record. - - If the adapter returns no data for the primary data of the payload, then - `queryRecord` resolves with `null`: - - ``` - // GET /users?username=unique - { - data: null - } - ``` - - ```javascript - store.queryRecord('user', { username: 'unique' }).then(function(user) { - console.log(user); // null - }); - ``` - - @since 1.13.0 - @method queryRecord - @param {String} modelName - @param {any} query an opaque query to be used by the adapter - @return {Promise} promise which resolves with the found record or `null` - */ - queryRecord(modelName, query) { - assert(`You need to pass a model name to the store's queryRecord method`, isPresent(modelName)); - assert(`You need to pass a query hash to the store's queryRecord method`, query); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - - let normalizedModelName = normalizeModelName(modelName); - - let adapter = this.adapterFor(normalizedModelName); - - assert(`You tried to make a query but you have no adapter (for ${normalizedModelName})`, adapter); - assert(`You tried to make a query but your adapter does not implement 'queryRecord'`, typeof adapter.queryRecord === 'function'); - - return promiseObject(_queryRecord(adapter, this, modelName, query).then(internalModel => { - // the promise returned by store.queryRecord is expected to resolve with - // an instance of DS.Model - if (internalModel) { - return internalModel.getRecord(); - } - - return null; - })); - }, - - /** - `findAll` asks the adapter's `findAll` method to find the records for the - given type, and returns a promise which will resolve with all records of - this type present in the store, even if the adapter only returns a subset - of them. - - ```app/routes/authors.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - model(params) { - return this.store.findAll('author'); - } - }); - ``` - - _When_ the returned promise resolves depends on the reload behavior, - configured via the passed `options` hash and the result of the adapter's - `shouldReloadAll` method. - - ### Reloading - - If `{ reload: true }` is passed or `adapter.shouldReloadAll` evaluates to - `true`, then the returned promise resolves once the adapter returns data, - regardless if there are already records in the store: - - ```js - store.push({ - data: { - id: 'first', - type: 'author' - } - }); - - // adapter#findAll resolves with - // [ - // { - // id: 'second', - // type: 'author' - // } - // ] - store.findAll('author', { reload: true }).then(function(authors) { - authors.getEach('id'); // ['first', 'second'] - }); - ``` - - If no reload is indicated via the abovementioned ways, then the promise - immediately resolves with all the records currently loaded in the store. - - ### Background Reloading - - Optionally, if `adapter.shouldBackgroundReloadAll` evaluates to `true`, - then a background reload is started. Once this resolves, the array with - which the promise resolves, is updated automatically so it contains all the - records in the store: - - ```js - // app/adapters/application.js - export default DS.Adapter.extend({ - shouldReloadAll(store, snapshotsArray) { - return false; - }, - - shouldBackgroundReloadAll(store, snapshotsArray) { - return true; - } - }); - - // ... - - store.push({ - data: { - id: 'first', - type: 'author' - } - }); - - let allAuthors; - store.findAll('author').then(function(authors) { - authors.getEach('id'); // ['first'] - - allAuthors = authors; - }); - - // later, once adapter#findAll resolved with - // [ - // { - // id: 'second', - // type: 'author' - // } - // ] - - allAuthors.getEach('id'); // ['first', 'second'] - ``` - - If you would like to force or prevent background reloading, you can set a - boolean value for `backgroundReload` in the options object for - `findAll`. - - ```app/routes/post/edit.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - model() { - return this.store.findAll('post', { backgroundReload: false }); - } - }); - ``` - - If you pass an object on the `adapterOptions` property of the options - argument it will be passed to you adapter via the `snapshotRecordArray` - - ```app/routes/posts.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - model(params) { - return this.store.findAll('post', { - adapterOptions: { subscribe: false } - }); - } - }); - ``` - - ```app/adapters/post.js - import MyCustomAdapter from './custom-adapter'; - - export default MyCustomAdapter.extend({ - findAll(store, type, sinceToken, snapshotRecordArray) { - if (snapshotRecordArray.adapterOptions.subscribe) { - // ... - } - // ... - } - }); - ``` - - See [peekAll](#method_peekAll) to get an array of current records in the - store, without waiting until a reload is finished. - - ### Retrieving Related Model Records - - If you use an adapter such as Ember's default - [`JSONAPIAdapter`](http://emberjs.com/api/data/classes/DS.JSONAPIAdapter.html) - that supports the [JSON API specification](http://jsonapi.org/) and if your server - endpoint supports the use of an - ['include' query parameter](http://jsonapi.org/format/#fetching-includes), - you can use `findAll()` to automatically retrieve additional records related to - those requested by supplying an `include` parameter in the `options` object. - - For example, given a `post` model that has a `hasMany` relationship with a `comment` - model, when we retrieve all of the post records we can have the server also return - all of the posts' comments in the same request: - - ```app/routes/posts.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - model() { - return this.store.findAll('post', { include: 'comments' }); - } - }); - - ``` - Multiple relationships can be requested using an `include` parameter consisting of a - comma-separated list (without white-space) while nested relationships can be specified - using a dot-separated sequence of relationship names. So to request both the posts' - comments and the authors of those comments the request would look like this: - - ```app/routes/posts.js - import Ember from 'ember'; - - export default Ember.Route.extend({ - model() { - return this.store.findAll('post', { include: 'comments,comments.author' }); - } - }); - - ``` - - See [query](#method_query) to only get a subset of records from the server. - - @since 1.13.0 - @method findAll - @param {String} modelName - @param {Object} options - @return {Promise} promise - */ - findAll(modelName, options) { - assert(`You need to pass a model name to the store's findAll method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - - let token = heimdall.start('store.findAll'); - let normalizedModelName = normalizeModelName(modelName); - let fetch = this._fetchAll(normalizedModelName, this.peekAll(normalizedModelName), options); - - instrument(() => { - fetch.finally(() => { heimdall.stop(token); }); - }); - - return fetch; - }, - - /** - @method _fetchAll - @private - @param {DS.Model} modelName - @param {DS.RecordArray} array - @return {Promise} promise - */ - _fetchAll(modelName, array, options = {}) { - let adapter = this.adapterFor(modelName); - let sinceToken = this._internalModelsFor(modelName).metadata.since; - - assert(`You tried to load all records but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to load all records but your adapter does not implement 'findAll'`, typeof adapter.findAll === 'function'); - - if (options.reload) { - set$1(array, 'isUpdating', true); - return promiseArray(_findAll(adapter, this, modelName, sinceToken, options)); - } - - let snapshotArray = array._createSnapshot(options); - - if (adapter.shouldReloadAll(this, snapshotArray)) { - set$1(array, 'isUpdating', true); - return promiseArray(_findAll(adapter, this, modelName, sinceToken, options)); - } - - if (options.backgroundReload === false) { - return promiseArray(Promise$1.resolve(array)); - } - - if (options.backgroundReload || adapter.shouldBackgroundReloadAll(this, snapshotArray)) { - set$1(array, 'isUpdating', true); - _findAll(adapter, this, modelName, sinceToken, options); - } - - return promiseArray(Promise$1.resolve(array)); - }, - - /** - @method _didUpdateAll - @param {String} modelName - @private - */ - _didUpdateAll(modelName) { - heimdall.increment(_didUpdateAll); - let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(modelName); - - set$1(liveRecordArray, 'isUpdating', false); - }, - - didUpdateAll(modelName) { - deprecate('didUpdateAll was documented as private and will be removed in the next version of Ember Data.'); - return this._didUpdateAll(modelName); - }, - - /** - This method returns a filtered array that contains all of the - known records for a given type in the store. - - Note that because it's just a filter, the result will contain any - locally created records of the type, however, it will not make a - request to the backend to retrieve additional records. If you - would like to request all the records from the backend please use - [store.findAll](#method_findAll). - - Also note that multiple calls to `peekAll` for a given type will always - return the same `RecordArray`. - - Example - - ```javascript - let localPosts = store.peekAll('post'); - ``` - - @since 1.13.0 - @method peekAll - @param {String} modelName - @return {DS.RecordArray} - */ - peekAll(modelName) { - heimdall.increment(peekAll); - assert(`You need to pass a model name to the store's peekAll method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = normalizeModelName(modelName); - let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(normalizedModelName); - - this.recordArrayManager.syncLiveRecordArray(liveRecordArray, normalizedModelName); - - return liveRecordArray; - }, - - /** - This method unloads all records in the store. - It schedules unloading to happen during the next run loop. - - Optionally you can pass a type which unload all records for a given type. - - ```javascript - store.unloadAll(); - store.unloadAll('post'); - ``` - - @method unloadAll - @param {String} modelName - */ - unloadAll(modelName) { - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, !modelName || typeof modelName === 'string'); - - if (arguments.length === 0) { - this._identityMap.clear(); - } else { - let normalizedModelName = normalizeModelName(modelName); - this._internalModelsFor(normalizedModelName).clear(); - } - }, - - /** - Takes a type and filter function, and returns a live RecordArray that - remains up to date as new records are loaded into the store or created - locally. - - The filter function takes a materialized record, and returns true - if the record should be included in the filter and false if it should - not. - - Example - - ```javascript - store.filter('post', function(post) { - return post.get('unread'); - }); - ``` - - The filter function is called once on all records for the type when - it is created, and then once on each newly loaded or created record. - - If any of a record's properties change, or if it changes state, the - filter function will be invoked again to determine whether it should - still be in the array. - - Optionally you can pass a query, which is the equivalent of calling - [query](#method_query) with that same query, to fetch additional records - from the server. The results returned by the server could then appear - in the filter if they match the filter function. - - The query itself is not used to filter records, it's only sent to your - server for you to be able to do server-side filtering. The filter - function will be applied on the returned results regardless. - - Example - - ```javascript - store.filter('post', { unread: true }, function(post) { - return post.get('unread'); - }).then(function(unreadPosts) { - unreadPosts.get('length'); // 5 - let unreadPost = unreadPosts.objectAt(0); - unreadPost.set('unread', false); - unreadPosts.get('length'); // 4 - }); - ``` - - @method filter - @private - @param {String} modelName - @param {Object} query optional query - @param {Function} filter - @return {DS.PromiseArray} - @deprecated - */ - filter(modelName, query, filter) { - assert(`You need to pass a model name to the store's filter method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - - if (!ENV.ENABLE_DS_FILTER) { - assert('The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', false); - } - - let promise; - let length = arguments.length; - let array; - let hasQuery = length === 3; - - let normalizedModelName = normalizeModelName(modelName); - - // allow an optional server query - if (hasQuery) { - promise = this.query(normalizedModelName, query); - } else if (arguments.length === 2) { - filter = query; - } - - if (hasQuery) { - array = this.recordArrayManager.createFilteredRecordArray(normalizedModelName, filter, query); - } else { - array = this.recordArrayManager.createFilteredRecordArray(normalizedModelName, filter); - } - - promise = promise || Promise$1.resolve(array); - - return promiseArray(promise.then(() => array, null, `DS: Store#filter of ${normalizedModelName}`)); - }, - - /** - This method has been deprecated and is an alias for store.hasRecordForId, which should - be used instead. - - @deprecated - @method recordIsLoaded - @param {String} modelName - @param {string} id - @return {boolean} - */ - recordIsLoaded(modelName, id) { - deprecate(`Use of recordIsLoaded is deprecated, use hasRecordForId instead.`, false, { - id: 'ds.store.recordIsLoaded', - until: '3.0' - }); - return this.hasRecordForId(modelName, id); - }, - - - // .............. - // . PERSISTING . - // .............. - - /** - This method is called by `record.save`, and gets passed a - resolver for the promise that `record.save` returns. - - It schedules saving to happen at the end of the run loop. - - @method scheduleSave - @private - @param {InternalModel} internalModel - @param {Resolver} resolver - @param {Object} options - */ - scheduleSave(internalModel, resolver, options) { - let snapshot = internalModel.createSnapshot(options); - internalModel.flushChangedAttributes(); - internalModel.adapterWillCommit(); - this._pendingSave.push({ - snapshot: snapshot, - resolver: resolver - }); - emberRun.once(this, this.flushPendingSave); - }, - - /** - This method is called at the end of the run loop, and - flushes any records passed into `scheduleSave` - - @method flushPendingSave - @private - */ - flushPendingSave() { - let pending = this._pendingSave.slice(); - this._pendingSave = []; - - for (let i = 0, j = pending.length; i < j; i++) { - let pendingItem = pending[i]; - let snapshot = pendingItem.snapshot; - let resolver = pendingItem.resolver; - let internalModel = snapshot._internalModel; - let adapter = this.adapterFor(internalModel.modelName); - let operation; - - if (internalModel.currentState.stateName === 'root.deleted.saved') { - return resolver.resolve(); - } else if (internalModel.isNew()) { - operation = 'createRecord'; - } else if (internalModel.isDeleted()) { - operation = 'deleteRecord'; - } else { - operation = 'updateRecord'; - } - - resolver.resolve(_commit(adapter, this, operation, snapshot)); - } - - }, - - /** - This method is called once the promise returned by an - adapter's `createRecord`, `updateRecord` or `deleteRecord` - is resolved. - - If the data provides a server-generated ID, it will - update the record and the store's indexes. - - @method didSaveRecord - @private - @param {InternalModel} internalModel the in-flight internal model - @param {Object} data optional data (see above) - */ - didSaveRecord(internalModel, dataArg) { - let data; - if (dataArg) { - data = dataArg.data; - } - if (data) { - // normalize relationship IDs into records - this.updateId(internalModel, data); - this._setupRelationshipsForModel(internalModel, data); - } else { - assert(`Your ${internalModel.modelName} record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, internalModel.id); - } - - //We first make sure the primary data has been updated - //TODO try to move notification to the user to the end of the runloop - internalModel.adapterDidCommit(data); - }, - - /** - This method is called once the promise returned by an - adapter's `createRecord`, `updateRecord` or `deleteRecord` - is rejected with a `DS.InvalidError`. - - @method recordWasInvalid - @private - @param {InternalModel} internalModel - @param {Object} errors - */ - recordWasInvalid(internalModel, errors) { - internalModel.adapterDidInvalidate(errors); - }, - - /** - This method is called once the promise returned by an - adapter's `createRecord`, `updateRecord` or `deleteRecord` - is rejected (with anything other than a `DS.InvalidError`). - - @method recordWasError - @private - @param {InternalModel} internalModel - @param {Error} error - */ - recordWasError(internalModel, error) { - internalModel.adapterDidError(error); - }, - - /** - When an adapter's `createRecord`, `updateRecord` or `deleteRecord` - resolves with data, this method extracts the ID from the supplied - data. - - @method updateId - @private - @param {InternalModel} internalModel - @param {Object} data - */ - updateId(internalModel, data) { - let oldId = internalModel.id; - let modelName = internalModel.modelName; - let id = coerceId(data.id); - - // ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record) - assert(`'${modelName}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null)); - - // ID absolutely can't be different than oldID if oldID is not null - assert(`'${modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, !(oldId !== null && id !== oldId)); - - // ID can be null if oldID is not null (altered ID in response for a record) - // however, this is more than likely a developer error. - if (oldId !== null && id === null) { - warn(`Your ${modelName} record was saved to the server, but the response does not have an id.`, !(oldId !== null && id === null)); - return; - } - - this._internalModelsFor(internalModel.modelName).set(id, internalModel); - - internalModel.setId(id); - }, - - /** - Returns a map of IDs to client IDs for a given modelName. - - @method _internalModelsFor - @private - @param {String} modelName - @return {Object} recordMap - */ - _internalModelsFor(modelName) { - heimdall.increment(_internalModelsFor); - return this._identityMap.retrieve(modelName); - }, - - // ................ - // . LOADING DATA . - // ................ - - /** - This internal method is used by `push`. - - @method _load - @private - @param {Object} data - */ - _load(data) { - heimdall.increment(_load); - let internalModel = this._internalModelForId(data.type, data.id); - - internalModel.setupData(data); - - this.recordArrayManager.recordDidChange(internalModel); - - return internalModel; - }, - - /* - In case someone defined a relationship to a mixin, for example: - ``` - let Comment = DS.Model.extend({ - owner: belongsTo('commentable'. { polymorphic: true }) - }); - let Commentable = Ember.Mixin.create({ - comments: hasMany('comment') - }); - ``` - we want to look up a Commentable class which has all the necessary - relationship metadata. Thus, we look up the mixin and create a mock - DS.Model, so we can access the relationship CPs of the mixin (`comments`) - in this case - - @private - */ - _modelForMixin(normalizedModelName) { - heimdall.increment(_modelForMixin); - // container.registry = 2.1 - // container._registry = 1.11 - 2.0 - // container = < 1.11 - let owner = getOwner(this); - let mixin; - - if (owner.factoryFor) { - let MaybeMixin = owner.factoryFor(`mixin:${normalizedModelName}`); - mixin = MaybeMixin && MaybeMixin.class; - } else { - mixin = owner._lookupFactory(`mixin:${normalizedModelName}`); - } - - if (mixin) { - let ModelForMixin = Model.extend(mixin); - ModelForMixin.reopenClass({ - __isMixin: true, - __mixin: mixin - }); - - //Cache the class as a model - owner.register('model:' + normalizedModelName, ModelForMixin); - } - - return this.modelFactoryFor(normalizedModelName); - }, - - /** - Returns the model class for the particular `modelName`. - - The class of a model might be useful if you want to get a list of all the - relationship names of the model, see - [`relationshipNames`](http://emberjs.com/api/data/classes/DS.Model.html#property_relationshipNames) - for example. - - @method modelFor - @param {String} modelName - @return {DS.Model} - */ - modelFor(modelName) { - assert(`You need to pass a model name to the store's modelFor method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - - let normalizedModelName = normalizeModelName(modelName); - - return this._modelFor(normalizedModelName); - }, - - /* - @private - */ - _modelFor(modelName) { - let maybeFactory = this._modelFactoryFor(modelName); - // for factorFor factory/class split - return maybeFactory.class ? maybeFactory.class : maybeFactory; - }, - - _modelFactoryFor(modelName) { - heimdall.increment(modelFor); - let factory = this._modelFactoryCache[modelName]; - - if (!factory) { - factory = this.modelFactoryFor(modelName); - - if (!factory) { - //Support looking up mixins as base types for polymorphic relationships - factory = this._modelForMixin(modelName); - } - if (!factory) { - throw new EmberError(`No model was found for '${modelName}'`); - } - - // interopt with the future - let klass = getOwner(this).factoryFor ? factory.class : factory; - - assert(`'${inspect(klass)}' does not appear to be an ember-data model`, klass.isModel); - - // TODO: deprecate this - klass.modelName = klass.modelName || modelName; - - this._modelFactoryCache[modelName] = factory; - } - - return factory; - }, - - /* - @private - */ - modelFactoryFor(modelName) { - heimdall.increment(modelFactoryFor); - assert(`You need to pass a model name to the store's modelFactoryFor method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - - let normalizedModelName = normalizeModelName(modelName); - let owner = getOwner(this); - - if (owner.factoryFor) { - return owner.factoryFor(`model:${normalizedModelName}`); - } else { - return owner._lookupFactory(`model:${normalizedModelName}`); - } - }, - - /** - Push some data for a given type into the store. - - This method expects normalized [JSON API](http://jsonapi.org/) document. This means you have to follow [JSON API specification](http://jsonapi.org/format/) with few minor adjustments: - - record's `type` should always be in singular, dasherized form - - members (properties) should be camelCased - - [Your primary data should be wrapped inside `data` property](http://jsonapi.org/format/#document-top-level): - - ```js - store.push({ - data: { - // primary data for single record of type `Person` - id: '1', - type: 'person', - attributes: { - firstName: 'Daniel', - lastName: 'Kmak' - } - } - }); - ``` - - [Demo.](http://ember-twiddle.com/fb99f18cd3b4d3e2a4c7) - - `data` property can also hold an array (of records): - - ```js - store.push({ - data: [ - // an array of records - { - id: '1', - type: 'person', - attributes: { - firstName: 'Daniel', - lastName: 'Kmak' - } - }, - { - id: '2', - type: 'person', - attributes: { - firstName: 'Tom', - lastName: 'Dale' - } - } - ] - }); - ``` - - [Demo.](http://ember-twiddle.com/69cdbeaa3702159dc355) - - There are some typical properties for `JSONAPI` payload: - * `id` - mandatory, unique record's key - * `type` - mandatory string which matches `model`'s dasherized name in singular form - * `attributes` - object which holds data for record attributes - `DS.attr`'s declared in model - * `relationships` - object which must contain any of the following properties under each relationships' respective key (example path is `relationships.achievements.data`): - - [`links`](http://jsonapi.org/format/#document-links) - - [`data`](http://jsonapi.org/format/#document-resource-object-linkage) - place for primary data - - [`meta`](http://jsonapi.org/format/#document-meta) - object which contains meta-information about relationship - - For this model: - - ```app/models/person.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - - children: DS.hasMany('person') - }); - ``` - - To represent the children as IDs: - - ```js - { - data: { - id: '1', - type: 'person', - attributes: { - firstName: 'Tom', - lastName: 'Dale' - }, - relationships: { - children: { - data: [ - { - id: '2', - type: 'person' - }, - { - id: '3', - type: 'person' - }, - { - id: '4', - type: 'person' - } - ] - } - } - } - } - ``` - - [Demo.](http://ember-twiddle.com/343e1735e034091f5bde) - - To represent the children relationship as a URL: - - ```js - { - data: { - id: '1', - type: 'person', - attributes: { - firstName: 'Tom', - lastName: 'Dale' - }, - relationships: { - children: { - links: { - related: '/people/1/children' - } - } - } - } - } - ``` - - If you're streaming data or implementing an adapter, make sure - that you have converted the incoming data into this form. The - store's [normalize](#method_normalize) method is a convenience - helper for converting a json payload into the form Ember Data - expects. - - ```js - store.push(store.normalize('person', data)); - ``` - - This method can be used both to push in brand new - records, as well as to update existing records. - - @method push - @param {Object} data - @return {DS.Model|Array} the record(s) that was created or - updated. - */ - push(data) { - let token = heimdall.start('store.push'); - let pushed = this._push(data); - - if (Array.isArray(pushed)) { - let records = pushed.map(internalModel => internalModel.getRecord()); - heimdall.stop(token); - return records; - } - - if (pushed === null) { - heimdall.stop(token); - return null; - } - - let record = pushed.getRecord(); - heimdall.stop(token); - return record; - }, - - /* - Push some data in the form of a json-api document into the store, - without creating materialized records. - - @method _push - @private - @param {Object} jsonApiDoc - @return {DS.InternalModel|Array} pushed InternalModel(s) - */ - _push(jsonApiDoc) { - let token = heimdall.start('store._push'); - let internalModelOrModels = this._backburner.join(() => { - let included = jsonApiDoc.included; - let i, length; - - if (included) { - for (i = 0, length = included.length; i < length; i++) { - this._pushInternalModel(included[i]); - } - } - - if (Array.isArray(jsonApiDoc.data)) { - length = jsonApiDoc.data.length; - let internalModels = new Array(length); - - for (i = 0; i < length; i++) { - internalModels[i] = this._pushInternalModel(jsonApiDoc.data[i]); - } - return internalModels; - } - - if (jsonApiDoc.data === null) { - return null; - } - - assert(`Expected an object in the 'data' property in a call to 'push' for ${jsonApiDoc.type}, but was ${typeOf(jsonApiDoc.data)}`, typeOf(jsonApiDoc.data) === 'object'); - - return this._pushInternalModel(jsonApiDoc.data); - }); - heimdall.stop(token); - return internalModelOrModels; - }, - - _hasModelFor(modelName) { - let owner = getOwner(this); - modelName = normalizeModelName(modelName); - - if (owner.factoryFor) { - return !!owner.factoryFor(`model:${modelName}`); - } else { - return !!owner._lookupFactory(`model:${modelName}`); - } - }, - - _pushInternalModel(data) { - heimdall.increment(_pushInternalModel); - let modelName = data.type; - assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id !== null && data.id !== undefined && data.id !== ''); - assert(`You tried to push data with a type '${modelName}' but no model could be found with that name.`, this._hasModelFor(modelName)); - - runInDebug(() => { - // If ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload - // contains unknown attributes or relationships, log a warning. - - if (ENV.DS_WARN_ON_UNKNOWN_KEYS) { - let modelClass = this._modelFor(modelName); - - // Check unknown attributes - let unknownAttributes = Object.keys(data.attributes || {}).filter((key) => { - return !get$3(modelClass, 'fields').has(key); - }); - let unknownAttributesMessage = `The payload for '${modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`; - warn(unknownAttributesMessage, unknownAttributes.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); - - // Check unknown relationships - let unknownRelationships = Object.keys(data.relationships || {}).filter((key) => { - return !get$3(modelClass, 'fields').has(key); - }); - let unknownRelationshipsMessage = `The payload for '${modelName}' contains these unknown relationships: ${unknownRelationships}. Make sure they've been defined in your model.`; - warn(unknownRelationshipsMessage, unknownRelationships.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); - } - }); - - // Actually load the record into the store. - let internalModel = this._load(data); - - this._setupRelationshipsForModel(internalModel, data); - - return internalModel; - }, - - _setupRelationshipsForModel(internalModel, data) { - if (data.relationships === undefined) { - return; - } - - if (this._pushedInternalModels.push(internalModel, data) !== 2) { - return; - } - - this._backburner.schedule('normalizeRelationships', this, this._setupRelationships); - }, - - _setupRelationships() { - heimdall.increment(_setupRelationships); - let setupToken = heimdall.start('store._setupRelationships'); - let pushed = this._pushedInternalModels; - - // Cache the inverse maps for each modelClass that we visit during this - // payload push. In the common case where we are pushing many more - // instances than types we want to minimize the cost of looking up the - // inverse map and the overhead of Ember.get adds up. - let modelNameToInverseMap = Object.create(null); - - for (let i = 0, l = pushed.length; i < l; i += 2) { - // This will convert relationships specified as IDs into DS.Model instances - // (possibly unloaded) and also create the data structures used to track - // relationships. - let internalModel = pushed[i]; - let data = pushed[i + 1]; - setupRelationships(this, internalModel, data, modelNameToInverseMap); - } - - pushed.length = 0; - heimdall.stop(setupToken); - }, - - /** - Push some raw data into the store. - - This method can be used both to push in brand new - records, as well as to update existing records. You - can push in more than one type of object at once. - All objects should be in the format expected by the - serializer. - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.ActiveModelSerializer; - ``` - - ```js - let pushData = { - posts: [ - { id: 1, post_title: "Great post", comment_ids: [2] } - ], - comments: [ - { id: 2, comment_body: "Insightful comment" } - ] - } - - store.pushPayload(pushData); - ``` - - By default, the data will be deserialized using a default - serializer (the application serializer if it exists). - - Alternatively, `pushPayload` will accept a model type which - will determine which serializer will process the payload. - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.ActiveModelSerializer; - ``` - - ```app/serializers/post.js - import DS from 'ember-data'; - - export default DS.JSONSerializer; - ``` - - ```js - store.pushPayload('comment', pushData); // Will use the application serializer - store.pushPayload('post', pushData); // Will use the post serializer - ``` - - @method pushPayload - @param {String} modelName Optionally, a model type used to determine which serializer will be used - @param {Object} inputPayload - */ - pushPayload(modelName, inputPayload) { - let serializer; - let payload; - if (!inputPayload) { - payload = modelName; - serializer = defaultSerializer(this); - assert(`You cannot use 'store#pushPayload' without a modelName unless your default serializer defines 'pushPayload'`, typeof serializer.pushPayload === 'function'); - } else { - payload = inputPayload; - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = normalizeModelName(modelName); - serializer = this.serializerFor(normalizedModelName); - } - if (isEnabled('ds-pushpayload-return')) { - return serializer.pushPayload(this, payload); - } else { - serializer.pushPayload(this, payload); - } - }, - - /** - `normalize` converts a json payload into the normalized form that - [push](#method_push) expects. - - Example - - ```js - socket.on('message', function(message) { - let modelName = message.model; - let data = message.data; - store.push(store.normalize(modelName, data)); - }); - ``` - - @method normalize - @param {String} modelName The name of the model type for this payload - @param {Object} payload - @return {Object} The normalized payload - */ - normalize(modelName, payload) { - heimdall.increment(normalize); - assert(`You need to pass a model name to the store's normalize method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); - let normalizedModelName = normalizeModelName(modelName); - let serializer = this.serializerFor(normalizedModelName); - let model = this._modelFor(normalizedModelName); - return serializer.normalize(model, payload); - }, - - /** - Build a brand new record for a given type, ID, and - initial data. - - @method _buildInternalModel - @private - @param {String} modelName - @param {String} id - @param {Object} data - @return {InternalModel} internal model - */ - _buildInternalModel(modelName, id, data) { - heimdall.increment(_buildInternalModel); - - assert(`You can no longer pass a modelClass as the first argument to store._buildInternalModel. Pass modelName instead.`, typeof modelName === 'string'); - - let recordMap = this._internalModelsFor(modelName); - - assert(`The id ${id} has already been used with another record for modelClass '${modelName}'.`, !id || !recordMap.get(id)); - - // lookupFactory should really return an object that creates - // instances with the injections applied - let internalModel = new InternalModel(modelName, id, this, data); - - recordMap.add(internalModel, id); - - return internalModel; - }, - - buildInternalModel(modelName, id, data) { - deprecate('buildInternalModel was documented as private and will be removed in the next version of Ember Data.'); - return this._buildInternalModel(modelName, id, data); - }, - - //Called by the state machine to notify the store that the record is ready to be interacted with - recordWasLoaded(record) { - this.recordArrayManager.recordWasLoaded(record); - }, - - // ............... - // . DESTRUCTION . - // ............... - - /** - When a record is destroyed, this un-indexes it and - removes it from any record arrays so it can be GCed. - - @method _removeFromIdMap - @private - @param {InternalModel} internalModel - */ - _removeFromIdMap(internalModel) { - let recordMap = this._internalModelsFor(internalModel.modelName); - let id = internalModel.id; - - recordMap.remove(internalModel, id); - }, - - // ...................... - // . PER-TYPE ADAPTERS - // ...................... - - /** - Returns an instance of the adapter for a given type. For - example, `adapterFor('person')` will return an instance of - `App.PersonAdapter`. - - If no `App.PersonAdapter` is found, this method will look - for an `App.ApplicationAdapter` (the default adapter for - your entire application). - - If no `App.ApplicationAdapter` is found, it will return - the value of the `defaultAdapter`. - - @method adapterFor - @public - @param {String} modelName - @return DS.Adapter - */ - adapterFor(modelName) { - heimdall.increment(adapterFor); - assert(`You need to pass a model name to the store's adapterFor method`, isPresent(modelName)); - assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = normalizeModelName(modelName); - - return this._instanceCache.get('adapter', normalizedModelName); - }, - - // .............................. - // . RECORD CHANGE NOTIFICATION . - // .............................. - - /** - Returns an instance of the serializer for a given type. For - example, `serializerFor('person')` will return an instance of - `App.PersonSerializer`. - - If no `App.PersonSerializer` is found, this method will look - for an `App.ApplicationSerializer` (the default serializer for - your entire application). - - if no `App.ApplicationSerializer` is found, it will attempt - to get the `defaultSerializer` from the `PersonAdapter` - (`adapterFor('person')`). - - If a serializer cannot be found on the adapter, it will fall back - to an instance of `DS.JSONSerializer`. - - @method serializerFor - @public - @param {String} modelName the record to serialize - @return {DS.Serializer} - */ - serializerFor(modelName) { - heimdall.increment(serializerFor); - assert(`You need to pass a model name to the store's serializerFor method`, isPresent(modelName)); - assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = normalizeModelName(modelName); - - return this._instanceCache.get('serializer', normalizedModelName); - }, - - lookupAdapter(name) { - deprecate(`Use of lookupAdapter is deprecated, use adapterFor instead.`, false, { - id: 'ds.store.lookupAdapter', - until: '3.0' - }); - return this.adapterFor(name); - }, - - lookupSerializer(name) { - deprecate(`Use of lookupSerializer is deprecated, use serializerFor instead.`, false, { - id: 'ds.store.lookupSerializer', - until: '3.0' - }); - return this.serializerFor(name); - }, - - willDestroy() { - this._super(...arguments); - this._pushedInternalModels = null; - this.recordArrayManager.destroy(); - this._instanceCache.destroy(); - - this.unloadAll(); - }, - - _updateRelationshipState(relationship) { - if (this._updatedRelationships.push(relationship) !== 1) { - return; - } - - this._backburner.join(() => { - this._backburner.schedule('syncRelationships', this, this._flushUpdatedRelationships); - }); - }, - - _flushUpdatedRelationships() { - let updated = this._updatedRelationships; - - for (let i = 0, l = updated.length; i < l; i++) { - updated[i].flushCanonical(); - } - - updated.length = 0; - }, - - _updateInternalModel(internalModel) { - if (this._updatedInternalModels.push(internalModel) !== 1) { - return; - } - - emberRun.schedule('actions', this, this._flushUpdatedInternalModels); - }, - - _flushUpdatedInternalModels() { - let updated = this._updatedInternalModels; - - for (let i = 0, l = updated.length; i < l; i++) { - updated[i]._triggerDeferredTriggers(); - } - - updated.length = 0; - }, - - _pushResourceIdentifier(relationship, resourceIdentifier) { - if (isNone(resourceIdentifier)) { - return; - } - - assert(`A ${relationship.internalModel.modelName} record was pushed into the store with the value of ${relationship.key} being ${inspect(resourceIdentifier)}, but ${relationship.key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(resourceIdentifier)); - - //TODO:Better asserts - return this._internalModelForId(resourceIdentifier.type, resourceIdentifier.id); - }, - - _pushResourceIdentifiers(relationship, resourceIdentifiers) { - if (isNone(resourceIdentifiers)) { - return; - } - - assert(`A ${relationship.internalModel.modelName} record was pushed into the store with the value of ${relationship.key} being '${inspect(resourceIdentifiers)}', but ${relationship.key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(resourceIdentifiers)); - - let _internalModels = new Array(resourceIdentifiers.length); - for (let i = 0; i < resourceIdentifiers.length; i++) { - _internalModels[i] = this._pushResourceIdentifier(relationship, resourceIdentifiers[i]); - } - return _internalModels; - } -}); - -// Delegation to the adapter and promise management - - - -function defaultSerializer(store) { - return store.serializerFor('application'); -} - -function _commit(adapter, store, operation, snapshot) { - let internalModel = snapshot._internalModel; - let modelName = snapshot.modelName; - let modelClass = store._modelFor(modelName); - assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`, typeof adapter[operation] === 'function'); - let promise = adapter[operation](store, modelClass, snapshot); - let serializer = serializerForAdapter(store, adapter, modelName); - let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; - - assert(`Your adapter's '${operation}' method must return a value, but it returned 'undefined'`, promise !==undefined); - - promise = Promise$1.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); - promise = _guard(promise, _bind(_objectIsAlive, internalModel)); - - return promise.then((adapterPayload) => { - /* - Note to future spelunkers hoping to optimize. - We rely on this `run` to create a run loop if needed - that `store._push` and `store.didSaveRecord` will both share. - - We use `join` because it is often the case that we - have an outer run loop available still from the first - call to `store._push`; - */ - store._backburner.join(() => { - let payload, data; - if (adapterPayload) { - payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, snapshot.id, operation); - if (payload.included) { - store._push({ data: null, included: payload.included }); - } - data = payload.data; - } - store.didSaveRecord(internalModel, { data }); - }); - - return internalModel; - }, function(error) { - if (error instanceof InvalidError) { - let errors = serializer.extractErrors(store, modelClass, error, snapshot.id); - - store.recordWasInvalid(internalModel, errors); - } else { - store.recordWasError(internalModel, error); - } - - throw error; - }, label); -} - -function isInverseRelationshipInitialized(store, internalModel, data, key, modelNameToInverseMap) { - let relationshipData = data.relationships[key].data; - - if (!relationshipData) { - // can't check inverse for eg { comments: { links: { related: URL }}} - return false; - } - - let inverseMap = modelNameToInverseMap[internalModel.modelName]; - if (!inverseMap) { - inverseMap = modelNameToInverseMap[internalModel.modelName] = get$3(internalModel.type, 'inverseMap'); - } - let inverseRelationshipMetadata = inverseMap[key]; - if (inverseRelationshipMetadata === undefined) { - inverseRelationshipMetadata = internalModel.type.inverseFor(key, store); - } - - if (!inverseRelationshipMetadata) { - return false; - } - - let { name: inverseRelationshipName } = inverseRelationshipMetadata; - - if (Array.isArray(relationshipData)) { - for (let i=0; i { - if (!data.relationships[relationshipName]) { - return; - } - - let relationshipRequiresNotification = relationships.has(relationshipName) || - isInverseRelationshipInitialized(store, internalModel, data, relationshipName, modelNameToInverseMap); - - if (relationshipRequiresNotification) { - let relationshipData = data.relationships[relationshipName]; - relationships.get(relationshipName).push(relationshipData); - } - - // in debug, assert payload validity eagerly - runInDebug(() => { - let relationshipMeta = get$3(internalModel.type, 'relationshipsByName').get(relationshipName); - let relationshipData = data.relationships[relationshipName]; - if (!relationshipData || !relationshipMeta) { - return; - } - - if (relationshipData.links) { - let isAsync = relationshipMeta.options && relationshipMeta.options.async !== false; - warn(`You pushed a record of type '${internalModel.type.modelName}' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, isAsync || relationshipData.data , { - id: 'ds.store.push-link-for-sync-relationship' - }); - } else if (relationshipData.data) { - if (relationshipMeta.kind === 'belongsTo') { - assert(`A ${internalModel.type.modelName} record was pushed into the store with the value of ${relationshipName} being ${inspect(relationshipData.data)}, but ${relationshipName} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(relationshipData.data)); - } else if (relationshipMeta.kind === 'hasMany') { - assert(`A ${internalModel.type.modelName} record was pushed into the store with the value of ${relationshipName} being '${inspect(relationshipData.data)}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(relationshipData.data)); - } - } - }); - }); -} - -var Store$1 = Store; - -/** - @module ember-data -*/ - -/** - All Ember Data classes, methods and functions are defined inside of this namespace. - - @class DS - @static -*/ - -/** - @property VERSION - @type String - @static -*/ -const DS = Ember.Namespace.create({ - VERSION: VERSION, - name: "DS" -}); - -if (Ember.libraries) { - Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); -} - -/** - `DS.belongsTo` is used to define One-To-One and One-To-Many - relationships on a [DS.Model](/api/data/classes/DS.Model.html). - - - `DS.belongsTo` takes an optional hash as a second parameter, currently - supported options are: - - - `async`: A boolean value used to explicitly declare this to be an async relationship. - - `inverse`: A string used to identify the inverse property on a - related model in a One-To-Many relationship. See [Explicit Inverses](#toc_explicit-inverses) - - #### One-To-One - To declare a one-to-one relationship between two models, use - `DS.belongsTo`: - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - profile: DS.belongsTo('profile') - }); - ``` - - ```app/models/profile.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - user: DS.belongsTo('user') - }); - ``` - - #### One-To-Many - To declare a one-to-many relationship between two models, use - `DS.belongsTo` in combination with `DS.hasMany`, like this: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - comments: DS.hasMany('comment') - }); - ``` - - ```app/models/comment.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - post: DS.belongsTo('post') - }); - ``` - - You can avoid passing a string as the first parameter. In that case Ember Data - will infer the type from the key name. - - ```app/models/comment.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - post: DS.belongsTo() - }); - ``` - - will lookup for a Post type. - - @namespace - @method belongsTo - @for DS - @param {String} modelName (optional) type of the relationship - @param {Object} options (optional) a hash of options - @return {Ember.computed} relationship -*/ -function belongsTo(modelName, options) { - let opts, userEnteredModelName; - if (typeof modelName === 'object') { - opts = modelName; - userEnteredModelName = undefined; - } else { - opts = options; - userEnteredModelName = modelName; - } - - if (typeof userEnteredModelName === 'string') { - userEnteredModelName = normalizeModelName(userEnteredModelName); - } - - assert("The first argument to DS.belongsTo must be a string representing a model type key, not an instance of " + Ember.inspect(userEnteredModelName) + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", typeof userEnteredModelName === 'string' || typeof userEnteredModelName === 'undefined'); - - opts = opts || {}; - - let meta = { - type: userEnteredModelName, - isRelationship: true, - options: opts, - kind: 'belongsTo', - name: 'Belongs To', - key: null - }; - - return Ember.computed({ - get(key) { - if (opts.hasOwnProperty('serialize')) { - warn(`You provided a serialize option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.Serializer and it's implementations http://emberjs.com/api/data/classes/DS.Serializer.html`, false, { - id: 'ds.model.serialize-option-in-belongs-to' - }); - } - - if (opts.hasOwnProperty('embedded')) { - warn(`You provided an embedded option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html`, false, { - id: 'ds.model.embedded-option-in-belongs-to' - }); - } - - return this._internalModel._relationships.get(key).getRecord(); - }, - set(key, value) { - if (value === undefined) { - value = null; - } - if (value && value.then) { - this._internalModel._relationships.get(key).setRecordPromise(value); - } else if (value) { - this._internalModel._relationships.get(key).setInternalModel(value._internalModel); - } else { - this._internalModel._relationships.get(key).setInternalModel(value); - } - - return this._internalModel._relationships.get(key).getRecord(); - } - }).meta(meta); -} - -/* - We're using this to detect arrays and "array-like" objects. - - This is a copy of the `isArray` method found in `ember-runtime/utils` as we're - currently unable to import non-exposed modules. - - This method was previously exposed as `Ember.isArray` but since - https://github.com/emberjs/ember.js/pull/11463 `Ember.isArray` is an alias of - `Array.isArray` hence removing the "array-like" part. - */ -function isArrayLike(obj) { - if (!obj || obj.setInterval) { return false; } - if (Array.isArray(obj)) { return true; } - if (Ember.Array.detect(obj)) { return true; } - - let type = Ember.typeOf(obj); - if ('array' === type) { return true; } - if ((obj.length !== undefined) && 'object' === type) { return true; } - return false; -} - -/** - @module ember-data -*/ - -const { get: get$16 } = Ember; - -/** - `DS.hasMany` is used to define One-To-Many and Many-To-Many - relationships on a [DS.Model](/api/data/classes/DS.Model.html). - - `DS.hasMany` takes an optional hash as a second parameter, currently - supported options are: - - - `async`: A boolean value used to explicitly declare this to be an async relationship. - - `inverse`: A string used to identify the inverse property on a related model. - - #### One-To-Many - To declare a one-to-many relationship between two models, use - `DS.belongsTo` in combination with `DS.hasMany`, like this: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - comments: DS.hasMany('comment') - }); - ``` - - ```app/models/comment.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - post: DS.belongsTo('post') - }); - ``` - - #### Many-To-Many - To declare a many-to-many relationship between two models, use - `DS.hasMany`: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - tags: DS.hasMany('tag') - }); - ``` - - ```app/models/tag.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - posts: DS.hasMany('post') - }); - ``` - - You can avoid passing a string as the first parameter. In that case Ember Data - will infer the type from the singularized key name. - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - tags: DS.hasMany() - }); - ``` - - will lookup for a Tag type. - - #### Explicit Inverses - - Ember Data will do its best to discover which relationships map to - one another. In the one-to-many code above, for example, Ember Data - can figure out that changing the `comments` relationship should update - the `post` relationship on the inverse because post is the only - relationship to that model. - - However, sometimes you may have multiple `belongsTo`/`hasMany` for the - same type. You can specify which property on the related model is - the inverse using `DS.hasMany`'s `inverse` option: - - ```app/models/comment.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - onePost: DS.belongsTo('post'), - twoPost: DS.belongsTo('post'), - redPost: DS.belongsTo('post'), - bluePost: DS.belongsTo('post') - }); - ``` - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - comments: DS.hasMany('comment', { - inverse: 'redPost' - }) - }); - ``` - - You can also specify an inverse on a `belongsTo`, which works how - you'd expect. - - @namespace - @method hasMany - @for DS - @param {String} type (optional) type of the relationship - @param {Object} options (optional) a hash of options - @return {Ember.computed} relationship -*/ -function hasMany(type, options) { - if (typeof type === 'object') { - options = type; - type = undefined; - } - - assert(`The first argument to DS.hasMany must be a string representing a model type key, not an instance of ${Ember.inspect(type)}. E.g., to define a relation to the Comment model, use DS.hasMany('comment')`, typeof type === 'string' || typeof type === 'undefined'); - - options = options || {}; - - if (typeof type === 'string') { - type = normalizeModelName(type); - } - - // Metadata about relationships is stored on the meta of - // the relationship. This is used for introspection and - // serialization. Note that `key` is populated lazily - // the first time the CP is called. - let meta = { - type, - options, - isRelationship: true, - kind: 'hasMany', - name: 'Has Many', - key: null - }; - - return Ember.computed({ - get(key) { - return this._internalModel._relationships.get(key).getRecords(); - }, - set(key, records) { - assert(`You must pass an array of records to set a hasMany relationship`, isArrayLike(records)); - assert(`All elements of a hasMany relationship must be instances of DS.Model, you passed ${Ember.inspect(records)}`, (function() { - return Ember.A(records).every((record) => record.hasOwnProperty('_internalModel') === true); - })()); - - let relationship = this._internalModel._relationships.get(key); - relationship.clear(); - relationship.addInternalModels(records.map(record => get$16(record, '_internalModel'))); - return relationship.getRecords(); - } - }).meta(meta); -} - -const get$17 = Ember.get; - -/** - - WARNING: This interface is likely to change in order to accomodate https://github.com/emberjs/rfcs/pull/4 - - ## Using BuildURLMixin - - To use url building, include the mixin when extending an adapter, and call `buildURL` where needed. - The default behaviour is designed for RESTAdapter. - - ### Example - - ```javascript - export default DS.Adapter.extend(BuildURLMixin, { - findRecord: function(store, type, id, snapshot) { - var url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); - return this.ajax(url, 'GET'); - } - }); - ``` - - ### Attributes - - The `host` and `namespace` attributes will be used if defined, and are optional. - - @class BuildURLMixin - @namespace DS -*/ -var buildUrlMixin = Ember.Mixin.create({ - /** - Builds a URL for a given type and optional ID. - - By default, it pluralizes the type's name (for example, 'post' - becomes 'posts' and 'person' becomes 'people'). To override the - pluralization see [pathForType](#method_pathForType). - - If an ID is specified, it adds the ID to the path generated - for the type, separated by a `/`. - - When called by RESTAdapter.findMany() the `id` and `snapshot` parameters - will be arrays of ids and snapshots. - - @method buildURL - @param {String} modelName - @param {(String|Array|Object)} id single id or array of ids or query - @param {(DS.Snapshot|Array)} snapshot single snapshot or array of snapshots - @param {String} requestType - @param {Object} query object of query parameters to send for query requests. - @return {String} url - */ - buildURL(modelName, id, snapshot, requestType, query) { - switch (requestType) { - case 'findRecord': - return this.urlForFindRecord(id, modelName, snapshot); - case 'findAll': - return this.urlForFindAll(modelName, snapshot); - case 'query': - return this.urlForQuery(query, modelName); - case 'queryRecord': - return this.urlForQueryRecord(query, modelName); - case 'findMany': - return this.urlForFindMany(id, modelName, snapshot); - case 'findHasMany': - return this.urlForFindHasMany(id, modelName, snapshot); - case 'findBelongsTo': - return this.urlForFindBelongsTo(id, modelName, snapshot); - case 'createRecord': - return this.urlForCreateRecord(modelName, snapshot); - case 'updateRecord': - return this.urlForUpdateRecord(id, modelName, snapshot); - case 'deleteRecord': - return this.urlForDeleteRecord(id, modelName, snapshot); - default: - return this._buildURL(modelName, id); - } - }, - - /** - @method _buildURL - @private - @param {String} modelName - @param {String} id - @return {String} url - */ - _buildURL(modelName, id) { - let path; - let url = []; - let host = get$17(this, 'host'); - let prefix = this.urlPrefix(); - - if (modelName) { - path = this.pathForType(modelName); - if (path) { url.push(path); } - } - - if (id) { url.push(encodeURIComponent(id)); } - if (prefix) { url.unshift(prefix); } - - url = url.join('/'); - if (!host && url && url.charAt(0) !== '/') { - url = '/' + url; - } - - return url; - }, - - /** - Builds a URL for a `store.findRecord(type, id)` call. - - Example: - - ```app/adapters/user.js - import DS from 'ember-data'; - - export default DS.JSONAPIAdapter.extend({ - urlForFindRecord(id, modelName, snapshot) { - let baseUrl = this.buildURL(); - return `${baseUrl}/users/${snapshot.adapterOptions.user_id}/playlists/${id}`; - } - }); - ``` - - @method urlForFindRecord - @param {String} id - @param {String} modelName - @param {DS.Snapshot} snapshot - @return {String} url - - */ - urlForFindRecord(id, modelName, snapshot) { - return this._buildURL(modelName, id); - }, - - /** - Builds a URL for a `store.findAll(type)` call. - - Example: - - ```app/adapters/comment.js - import DS from 'ember-data'; - - export default DS.JSONAPIAdapter.extend({ - urlForFindAll(modelName, snapshot) { - return 'data/comments.json'; - } - }); - ``` - - @method urlForFindAll - @param {String} modelName - @param {DS.SnapshotRecordArray} snapshot - @return {String} url - */ - urlForFindAll(modelName, snapshot) { - return this._buildURL(modelName); - }, - - /** - Builds a URL for a `store.query(type, query)` call. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - host: 'https://api.github.com', - urlForQuery (query, modelName) { - switch(modelName) { - case 'repo': - return `https://api.github.com/orgs/${query.orgId}/repos`; - default: - return this._super(...arguments); - } - } - }); - ``` - - @method urlForQuery - @param {Object} query - @param {String} modelName - @return {String} url - */ - urlForQuery(query, modelName) { - return this._buildURL(modelName); - }, - - /** - Builds a URL for a `store.queryRecord(type, query)` call. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - urlForQueryRecord({ slug }, modelName) { - let baseUrl = this.buildURL(); - return `${baseUrl}/${encodeURIComponent(slug)}`; - } - }); - ``` - - @method urlForQueryRecord - @param {Object} query - @param {String} modelName - @return {String} url - */ - urlForQueryRecord(query, modelName) { - return this._buildURL(modelName); - }, - - /** - Builds a URL for coalesceing multiple `store.findRecord(type, id) - records into 1 request when the adapter's `coalesceFindRequests` - property is true. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - urlForFindMany(ids, modelName) { - let baseUrl = this.buildURL(); - return `${baseUrl}/coalesce`; - } - }); - ``` - - @method urlForFindMany - @param {Array} ids - @param {String} modelName - @param {Array} snapshots - @return {String} url - */ - urlForFindMany(ids, modelName, snapshots) { - return this._buildURL(modelName); - }, - - /** - Builds a URL for fetching a async hasMany relationship when a url - is not provided by the server. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.JSONAPIAdapter.extend({ - urlForFindHasMany(id, modelName, snapshot) { - let baseUrl = this.buildURL(id, modelName); - return `${baseUrl}/relationships`; - } - }); - ``` - - @method urlForFindHasMany - @param {String} id - @param {String} modelName - @param {DS.Snapshot} snapshot - @return {String} url - */ - urlForFindHasMany(id, modelName, snapshot) { - return this._buildURL(modelName, id); - }, - - /** - Builds a URL for fetching a async belongsTo relationship when a url - is not provided by the server. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.JSONAPIAdapter.extend({ - urlForFindBelongsTo(id, modelName, snapshot) { - let baseUrl = this.buildURL(id, modelName); - return `${baseUrl}/relationships`; - } - }); - ``` - - @method urlForFindBelongsTo - @param {String} id - @param {String} modelName - @param {DS.Snapshot} snapshot - @return {String} url - */ - urlForFindBelongsTo(id, modelName, snapshot) { - return this._buildURL(modelName, id); - }, - - /** - Builds a URL for a `record.save()` call when the record was created - locally using `store.createRecord()`. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - urlForCreateRecord(modelName, snapshot) { - return this._super(...arguments) + '/new'; - } - }); - ``` - - @method urlForCreateRecord - @param {String} modelName - @param {DS.Snapshot} snapshot - @return {String} url - */ - urlForCreateRecord(modelName, snapshot) { - return this._buildURL(modelName); - }, - - /** - Builds a URL for a `record.save()` call when the record has been update locally. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - urlForUpdateRecord(id, modelName, snapshot) { - return `/${id}/feed?access_token=${snapshot.adapterOptions.token}`; - } - }); - ``` - - @method urlForUpdateRecord - @param {String} id - @param {String} modelName - @param {DS.Snapshot} snapshot - @return {String} url - */ - urlForUpdateRecord(id, modelName, snapshot) { - return this._buildURL(modelName, id); - }, - - /** - Builds a URL for a `record.save()` call when the record has been deleted locally. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - urlForDeleteRecord(id, modelName, snapshot) { - return this._super(...arguments) + '/destroy'; - } - }); - ``` - - @method urlForDeleteRecord - @param {String} id - @param {String} modelName - @param {DS.Snapshot} snapshot - @return {String} url - */ - urlForDeleteRecord(id, modelName, snapshot) { - return this._buildURL(modelName, id); - }, - - /** - @method urlPrefix - @private - @param {String} path - @param {String} parentURL - @return {String} urlPrefix - */ - urlPrefix(path, parentURL) { - let host = get$17(this, 'host'); - let namespace = get$17(this, 'namespace'); - - if (!host || host === '/') { - host = ''; - } - - if (path) { - // Protocol relative url - if (/^\/\//.test(path) || /http(s)?:\/\//.test(path)) { - // Do nothing, the full host is already included. - return path; - - // Absolute path - } else if (path.charAt(0) === '/') { - return `${host}${path}`; - // Relative path - } else { - return `${parentURL}/${path}`; - } - } - - // No path provided - let url = []; - if (host) { url.push(host); } - if (namespace) { url.push(namespace); } - return url.join('/'); - }, - - /** - Determines the pathname for a given type. - - By default, it pluralizes the type's name (for example, - 'post' becomes 'posts' and 'person' becomes 'people'). - - ### Pathname customization - - For example if you have an object LineItem with an - endpoint of "/line_items/". - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - pathForType: function(modelName) { - var decamelized = Ember.String.decamelize(modelName); - return Ember.String.pluralize(decamelized); - } - }); - ``` - - @method pathForType - @param {String} modelName - @return {String} path - **/ - pathForType(modelName) { - let camelized = Ember.String.camelize(modelName); - return Ember.String.pluralize(camelized); - } -}); - -const CLRF = '\u000d\u000a'; - -function parseResponseHeaders(headersString) { - let headers = Object.create(null); - - if (!headersString) { - return headers; - } - - let headerPairs = headersString.split(CLRF); - for (let i = 0; i < headerPairs.length; i++) { - let header = headerPairs[i]; - let j = 0; - let foundSep = false; - - for (; j < header.length; j++) { - if (header.charCodeAt(j) === 58 /* ':' */) { - foundSep = true; - break; - } - } - - if (foundSep === false) { - break; - } - - let field = header.substring(0, j).trim(); - let value = header.substring(j + 1, header.length).trim(); - - if (value) { - headers[field] = value; - } - } - - return headers; -} - -/** - The `DS.Transform` class is used to serialize and deserialize model - attributes when they are saved or loaded from an - adapter. Subclassing `DS.Transform` is useful for creating custom - attributes. All subclasses of `DS.Transform` must implement a - `serialize` and a `deserialize` method. - - Example - - ```app/transforms/temperature.js - import DS from 'ember-data'; - - // Converts centigrade in the JSON to fahrenheit in the app - export default DS.Transform.extend({ - deserialize(serialized, options) { - return (serialized * 1.8) + 32; - }, - - serialize(deserialized, options) { - return (deserialized - 32) / 1.8; - } - }); - ``` - - The options passed into the `DS.attr` function when the attribute is - declared on the model is also available in the transform. - - ```app/models/post.js - export default DS.Model.extend({ - title: DS.attr('string'), - markdown: DS.attr('markdown', { - markdown: { - gfm: false, - sanitize: true - } - }) - }); - ``` - - ```app/transforms/markdown.js - export default DS.Transform.extend({ - serialize(deserialized, options) { - return deserialized.raw; - }, - - deserialize(serialized, options) { - var markdownOptions = options.markdown || {}; - - return marked(serialized, markdownOptions); - } - }); - ``` - - Usage - - ```app/models/requirement.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - name: DS.attr('string'), - temperature: DS.attr('temperature') - }); - ``` - - @class Transform - @namespace DS - */ -var Transform = Ember.Object.extend({ - /** - When given a deserialized value from a record attribute this - method must return the serialized value. - - Example - - ```javascript - serialize(deserialized, options) { - return Ember.isEmpty(deserialized) ? null : Number(deserialized); - } - ``` - - @method serialize - @param deserialized The deserialized value - @param options hash of options passed to `DS.attr` - @return The serialized value - */ - serialize: null, - - /** - When given a serialize value from a JSON object this method must - return the deserialized value for the record attribute. - - Example - - ```javascript - deserialize(serialized, options) { - return empty(serialized) ? null : Number(serialized); - } - ``` - - @method deserialize - @param serialized The serialized value - @param options hash of options passed to `DS.attr` - @return The deserialized value - */ - deserialize: null -}); - -const empty = Ember.isEmpty; - -function isNumber(value) { - return value === value && value !== Infinity && value !== -Infinity; -} - -/** - The `DS.NumberTransform` class is used to serialize and deserialize - numeric attributes on Ember Data record objects. This transform is - used when `number` is passed as the type parameter to the - [DS.attr](../../data#method_attr) function. - - Usage - - ```app/models/score.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - value: DS.attr('number'), - player: DS.belongsTo('player'), - date: DS.attr('date') - }); - ``` - - @class NumberTransform - @extends DS.Transform - @namespace DS - */ -var number = Transform.extend({ - deserialize(serialized) { - let transformed; - - if (empty(serialized)) { - return null; - } else { - transformed = Number(serialized); - - return isNumber(transformed) ? transformed : null; - } - }, - - serialize(deserialized) { - let transformed; - - if (empty(deserialized)) { - return null; - } else { - transformed = Number(deserialized); - - return isNumber(transformed) ? transformed : null; - } - } -}); - -/** - @module ember-data -*/ - -/** - Date.parse with progressive enhancement for ISO 8601 - - © 2011 Colin Snover - - Released under MIT license. - - @class Date - @namespace Ember - @static - @deprecated -*/ -Ember.Date = Ember.Date || {}; - -const origParse = Date.parse; -const numericKeys = [1, 4, 5, 6, 7, 10, 11]; - -const parseDate = function (date) { - let timestamp, struct; - let minutesOffset = 0; - - // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string - // before falling back to any implementation-specific date parsing, so that’s what we do, even if native - // implementations could be faster - // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm - if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2}):?(?:(\d{2}))?)?)?$/.exec(date))) { - // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC - for (let i = 0, k; (k = numericKeys[i]); ++i) { - struct[k] = +struct[k] || 0; - } - - // allow undefined days and months - struct[2] = (+struct[2] || 1) - 1; - struct[3] = +struct[3] || 1; - - if (struct[8] !== 'Z' && struct[9] !== undefined) { - minutesOffset = struct[10] * 60 + struct[11]; - - if (struct[9] === '+') { - minutesOffset = 0 - minutesOffset; - } - } - - timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]); - } else { - timestamp = origParse ? origParse(date) : NaN; - } - - return timestamp; -}; - -Ember.Date.parse = function (date) { - // throw deprecation - deprecate(`Ember.Date.parse is deprecated because Safari 5-, IE8-, and - Firefox 3.6- are no longer supported (see - https://github.com/csnover/js-iso8601 for the history of this issue). - Please use Date.parse instead`, false, { - id: 'ds.ember.date.parse-deprecate', - until: '3.0.0' - }); - - return parseDate(date); -}; - -if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Date) { - deprecate(`Overriding Date.parse with Ember.Date.parse is deprecated. Please set ENV.EmberENV.EXTEND_PROTOTYPES.Date to false in config/environment.js - - -// config/environment.js -ENV = { - EmberENV: { - EXTEND_PROTOTYPES: { - Date: false, - } - } -} -`, false, { - id: 'ds.date.parse-deprecate', - until: '3.0.0' -}); - Date.parse = parseDate; -} - -/** - The `DS.DateTransform` class is used to serialize and deserialize - date attributes on Ember Data record objects. This transform is used - when `date` is passed as the type parameter to the - [DS.attr](../../data#method_attr) function. It uses the [`ISO 8601`](https://en.wikipedia.org/wiki/ISO_8601) - standard. - - ```app/models/score.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - value: DS.attr('number'), - player: DS.belongsTo('player'), - date: DS.attr('date') - }); - ``` - - @class DateTransform - @extends DS.Transform - @namespace DS - */ - -var date = Transform.extend({ - deserialize(serialized) { - let type = typeof serialized; - - if (type === "string") { - return new Date(parseDate(serialized)); - } else if (type === "number") { - return new Date(serialized); - } else if (serialized === null || serialized === undefined) { - // if the value is null return null - // if the value is not present in the data return undefined - return serialized; - } else { - return null; - } - }, - - serialize(date) { - if (date instanceof Date && !isNaN(date)) { - return date.toISOString(); - } else { - return null; - } - } -}); - -const none = Ember.isNone; - -/** - The `DS.StringTransform` class is used to serialize and deserialize - string attributes on Ember Data record objects. This transform is - used when `string` is passed as the type parameter to the - [DS.attr](../../data#method_attr) function. - - Usage - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - isAdmin: DS.attr('boolean'), - name: DS.attr('string'), - email: DS.attr('string') - }); - ``` - - @class StringTransform - @extends DS.Transform - @namespace DS - */ -var string = Transform.extend({ - deserialize(serialized) { - return none(serialized) ? null : String(serialized); - }, - serialize(deserialized) { - return none(deserialized) ? null : String(deserialized); - } -}); - -const { isNone: isNone$1 } = Ember; - -/** - The `DS.BooleanTransform` class is used to serialize and deserialize - boolean attributes on Ember Data record objects. This transform is - used when `boolean` is passed as the type parameter to the - [DS.attr](../../data#method_attr) function. - - Usage - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - isAdmin: DS.attr('boolean'), - name: DS.attr('string'), - email: DS.attr('string') - }); - ``` - - By default the boolean transform only allows for values of `true` or - `false`. You can opt into allowing `null` values for - boolean attributes via `DS.attr('boolean', { allowNull: true })` - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - email: DS.attr('string'), - username: DS.attr('string'), - wantsWeeklyEmail: DS.attr('boolean', { allowNull: true }) - }); - ``` - - @class BooleanTransform - @extends DS.Transform - @namespace DS - */ -var boolean = Transform.extend({ - deserialize(serialized, options) { - let type = typeof serialized; - - if (isNone$1(serialized) && options.allowNull === true) { - return null; - } - - if (type === "boolean") { - return serialized; - } else if (type === "string") { - return serialized.match(/^true$|^t$|^1$/i) !== null; - } else if (type === "number") { - return serialized === 1; - } else { - return false; - } - }, - - serialize(deserialized, options) { - if (isNone$1(deserialized) && options.allowNull === true) { - return null; - } - - return Boolean(deserialized); - } -}); - -/* globals global, window, self */ - -// originally from https://github.com/emberjs/ember.js/blob/c0bd26639f50efd6a03ee5b87035fd200e313b8e/packages/ember-environment/lib/global.js - -// from lodash to catch fake globals -function checkGlobal(value) { - return (value && value.Object === Object) ? value : undefined; -} - -// element ids can ruin global miss checks -function checkElementIdShadowing(value) { - return (value && value.nodeType === undefined) ? value : undefined; -} - -// export real global -var global$1 = checkGlobal(checkElementIdShadowing(typeof global === 'object' && global)) || - checkGlobal(typeof self === 'object' && self) || - checkGlobal(typeof window === 'object' && window) || - new Function('return this')(); // eval outside of strict mode - -/** - @module ember-data -*/ -const capitalize = Ember.String.capitalize; -const underscore = Ember.String.underscore; -const { assert: assert$1, get: get$18 } = Ember; - -/* - Extend `Ember.DataAdapter` with ED specific code. - - @class DebugAdapter - @namespace DS - @extends Ember.DataAdapter - @private -*/ -var debugAdapter = Ember.DataAdapter.extend({ - getFilters() { - return [ - { name: 'isNew', desc: 'New' }, - { name: 'isModified', desc: 'Modified' }, - { name: 'isClean', desc: 'Clean' } - ]; - }, - - detect(typeClass) { - return typeClass !== Model && Model.detect(typeClass); - }, - - columnsForType(typeClass) { - let columns = [{ - name: 'id', - desc: 'Id' - }]; - let count = 0; - let self = this; - get$18(typeClass, 'attributes').forEach((meta, name) => { - if (count++ > self.attributeLimit) { return false; } - let desc = capitalize(underscore(name).replace('_', ' ')); - columns.push({ name: name, desc: desc }); - }); - return columns; - }, - - getRecords(modelClass, modelName) { - if (arguments.length < 2) { - // Legacy Ember.js < 1.13 support - let containerKey = modelClass._debugContainerKey; - if (containerKey) { - let match = containerKey.match(/model:(.*)/); - if (match) { - modelName = match[1]; - } - } - } - assert$1("Cannot find model name. Please upgrade to Ember.js >= 1.13 for Ember Inspector support", !!modelName); - return this.get('store').peekAll(modelName); - }, - - getRecordColumnValues(record) { - let count = 0; - let columnValues = { id: get$18(record, 'id') }; - - record.eachAttribute((key) => { - if (count++ > this.attributeLimit) { - return false; - } - columnValues[key] = get$18(record, key); - }); - return columnValues; - }, - - getRecordKeywords(record) { - let keywords = []; - let keys = Ember.A(['id']); - record.eachAttribute((key) => keys.push(key)); - keys.forEach((key) => keywords.push(get$18(record, key))); - return keywords; - }, - - getRecordFilterValues(record) { - return { - isNew: record.get('isNew'), - isModified: record.get('hasDirtyAttributes') && !record.get('isNew'), - isClean: !record.get('hasDirtyAttributes') - }; - }, - - getRecordColor(record) { - let color = 'black'; - if (record.get('isNew')) { - color = 'green'; - } else if (record.get('hasDirtyAttributes')) { - color = 'blue'; - } - return color; - }, - - observeRecord(record, recordUpdated) { - let releaseMethods = Ember.A(); - let keysToObserve = Ember.A(['id', 'isNew', 'hasDirtyAttributes']); - - record.eachAttribute((key) => keysToObserve.push(key)); - let adapter = this; - - keysToObserve.forEach(function(key) { - let handler = function() { - recordUpdated(adapter.wrapRecord(record)); - }; - Ember.addObserver(record, key, handler); - releaseMethods.push(function() { - Ember.removeObserver(record, key, handler); - }); - }); - - let release = function() { - releaseMethods.forEach((fn) => fn()); - }; - - return release; - } -}); - -// public - -export { Model, Errors, Store$1 as Store, DS, belongsTo, hasMany, buildUrlMixin as BuildURLMixin, Snapshot, normalizeModelName, getOwner, modelHasAttributeOrRelationshipNamedType, coerceId, parseResponseHeaders, Transform, number as NumberTransform, date as DateTransform, string as StringTransform, boolean as BooleanTransform, RootState$1 as RootState, global$1 as global, isEnabled, InternalModel, parseDate, PromiseArray, PromiseObject, PromiseManyArray, RecordArray, FilteredRecordArray, AdapterPopulatedRecordArray, ManyArray, RecordArrayManager, Relationship, debugAdapter as DebugAdapter }; diff --git a/addon/-private/index.js b/addon/-private/index.js index b3e0fb02691..1e7ecc60d92 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -59,3 +59,9 @@ export { default as Relationship } from './system/relationships/state/relationsh // Should be a different Repo ? export { default as DebugAdapter } from './system/debug/debug-adapter'; + +// Used by tests +export { default as diffArray } from './system/diff-array'; +export { default as RelationshipPayloadsManager } from './system/relationships/relationship-payloads-manager'; +export { default as RelationshipPayloads } from './system/relationships/relationship-payloads'; +export { default as SnapshotRecordArray } from './system/snapshot-record-array'; diff --git a/index.js b/index.js index 8df9f74a4b3..ebc64c6e72e 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,6 @@ var path = require('path'); var SilentError = require('silent-error'); var Funnel = require('broccoli-funnel'); var Rollup = require('broccoli-rollup'); -var debug = require('broccoli-stew').debug; // allow toggling of heimdall instrumentation var INSTRUMENT_HEIMDALL = false; @@ -117,21 +116,10 @@ module.exports = { var version = require('./lib/version'); var merge = require('broccoli-merge-trees'); - var tree = this._super.treeForAddon.call(this, merge([ - version(), - dir - ])); - - if (isProductionEnv()) { - tree = new Funnel(tree, { - exclude: [ - /-debug/ - ] - }); - } - var privateTree = 'addon/-private'; - var publicTree = tree; //new Funnel(tree, { exclude: [ /-private/ ] }); + var publicTree = new Funnel('addon', { + exclude: [ /-private/ ] + }); privateTree = new Rollup(privateTree, { rollup: { @@ -148,9 +136,20 @@ module.exports = { } }); - privateTree = debug(privateTree, { name: 'rollup-tree' }); + var tree = merge([publicTree, privateTree]); - return tree; // merge([publicTree, privateTree]); + if (isProductionEnv()) { + tree = new Funnel(tree, { + exclude: [ + /-debug/ + ] + }); + } + + return this._super.treeForAddon.call(this, merge([ + version(), + tree + ])); }, _setupBabelOptions: function() { diff --git a/tests/unit/diff-array-test.js b/tests/unit/diff-array-test.js index 893bfe469c6..1526cb9f9e5 100644 --- a/tests/unit/diff-array-test.js +++ b/tests/unit/diff-array-test.js @@ -1,6 +1,6 @@ import {module, test} from 'qunit'; -import diffArray from 'ember-data/-private/system/diff-array'; +import { diffArray } from 'ember-data/-private'; module('unit/diff-array Diff Array tests', { }); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index e0acbf69524..6385dcd9592 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -4,8 +4,7 @@ import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; -import { isEnabled } from 'ember-data/-private'; -import { parseDate } from "ember-data/-private/ext/date"; +import { isEnabled, parseDate } from 'ember-data/-private'; const { get, set, run } = Ember; diff --git a/tests/unit/system/relationships/relationship-payload-manager-test.js b/tests/unit/system/relationships/relationship-payload-manager-test.js index 1292923d362..8aa78aafa21 100644 --- a/tests/unit/system/relationships/relationship-payload-manager-test.js +++ b/tests/unit/system/relationships/relationship-payload-manager-test.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import RelationshipPayloadsManager from 'ember-data/-private/system/relationships/relationship-payloads-manager'; +import { RelationshipPayloadsManager } from 'ember-data/-private'; import DS from 'ember-data'; import {createStore} from 'dummy/tests/helpers/store'; import {module, test} from 'qunit'; diff --git a/tests/unit/system/relationships/relationship-payloads-test.js b/tests/unit/system/relationships/relationship-payloads-test.js index 21dd4371748..2ee7e9fb939 100644 --- a/tests/unit/system/relationships/relationship-payloads-test.js +++ b/tests/unit/system/relationships/relationship-payloads-test.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import RelationshipPayloadsManager from 'ember-data/-private/system/relationships/relationship-payloads-manager'; +import { RelationshipPayloadsManager } from 'ember-data/-private'; import DS from 'ember-data'; import {createStore} from 'dummy/tests/helpers/store'; import {module, test} from 'qunit'; diff --git a/tests/unit/system/snapshot-record-array-test.js b/tests/unit/system/snapshot-record-array-test.js index 7574cb1e83c..c33fb225aea 100644 --- a/tests/unit/system/snapshot-record-array-test.js +++ b/tests/unit/system/snapshot-record-array-test.js @@ -1,4 +1,4 @@ -import SnapshotRecordArray from 'ember-data/-private/system/snapshot-record-array'; +import { SnapshotRecordArray } from 'ember-data/-private'; import Ember from 'ember'; import {module, test} from 'qunit'; diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index c9e0cec84c1..4bf54576bec 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -8,7 +8,7 @@ import DS from 'ember-data'; import Model from 'ember-data/model'; import { assertPolymorphicType } from 'ember-data/-debug'; -import { modelHasAttributeOrRelationshipNamedType } from 'ember-data/-private/utils'; +import { modelHasAttributeOrRelationshipNamedType } from 'ember-data/-private'; let env, User, Message, Post, Person, Video, Medium; From f15c67b85e1c3791e81c083f85dbc3372c3a4d35 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 14 Apr 2017 10:54:53 -0700 Subject: [PATCH 1910/2527] fix build --- .gitignore | 2 + addon/-private/system/relationship-meta.js | 2 +- index.js | 92 +++++---- package.json | 7 +- tests/helpers/test-in-debug.js | 6 +- yarn.lock | 205 ++++++++++----------- 6 files changed, 163 insertions(+), 151 deletions(-) diff --git a/.gitignore b/.gitignore index d7b48a542b4..3fa6bc6e064 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ node_modules/ bower_components/ .metadata_never_index npm-debug.log + +DEBUG-* diff --git a/addon/-private/system/relationship-meta.js b/addon/-private/system/relationship-meta.js index 8724fa7d361..b24b56c9e37 100644 --- a/addon/-private/system/relationship-meta.js +++ b/addon/-private/system/relationship-meta.js @@ -1,6 +1,6 @@ import {singularize} from 'ember-inflector'; import normalizeModelName from './normalize-model-name'; -import { runInDebug } from 'ember-data/-private/debug'; +import { runInDebug } from 'ember-data/-debug'; export function typeForRelationshipMeta(meta) { let modelName; diff --git a/index.js b/index.js index ebc64c6e72e..e8c81b05b97 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,10 @@ var path = require('path'); var SilentError = require('silent-error'); var Funnel = require('broccoli-funnel'); var Rollup = require('broccoli-rollup'); +var stew = require('broccoli-stew'); +var Babel = require('broccoli-babel-transpiler'); +var merge = require('broccoli-merge-trees'); +var version = require('./lib/version'); // allow toggling of heimdall instrumentation var INSTRUMENT_HEIMDALL = false; @@ -16,6 +20,9 @@ for (var i = 0; i < args.length; i++) { break; } } +var NOOP_TREE = function(dir ) { + return { inputTree: dir, rebuild: function() { return []; } }; +}; process.env.INSTRUMENT_HEIMDALL = INSTRUMENT_HEIMDALL; @@ -97,73 +104,86 @@ module.exports = { }, treeForApp: function(dir) { - if (this._forceBowerUsage) { - // Fake an empty broccoli tree - return { inputTree: dir, rebuild: function() { return []; } }; - } + if (this._forceBowerUsage) { return NOOP_TREE(dir); } // this._super.treeForApp is undefined in ember-cli (1.13) for some reason. // TODO: investigate why treeForApp isn't on _super return dir; }, - treeForAddon: function(dir) { - if (this._forceBowerUsage) { - // Fakes an empty broccoli tree - return { inputTree: dir, rebuild: function() { return []; } }; - } + treeForAddon: function(tree) { + if (this._forceBowerUsage) { return NOOP_TREE(tree); } + + let babel = this.addons.find(addon => addon.name === 'ember-cli-babel'); + + let treeWithVersion = merge([ + tree, + version() // compile the VERSION into the build + ]); - var version = require('./lib/version'); - var merge = require('broccoli-merge-trees'); + let withPrivate = new Funnel(tree, { include: ['-private/**'] }); + let withoutPrivate = new Funnel(treeWithVersion, { + exclude: [ + '-private', + isProductionEnv() ? '-debug' : false + ].filter(Boolean), - var privateTree = 'addon/-private'; - var publicTree = new Funnel('addon', { - exclude: [ /-private/ ] + destDir: 'ember-data' }); + var privateTree = babel.transpileTree(withPrivate, { + babel: this.buildBabelOptions(), + 'ember-cli-babel': { + compileModules: false + } + }); + + // use the default options + var publicTree = babel.transpileTree(withoutPrivate); + privateTree = new Rollup(privateTree, { rollup: { - entry: 'index.js', - dest: '-private.js', + entry: '-private/index.js', + targets: [ + { dest: '-private.js', format: 'amd', moduleId: 'ember-data/-private' } + ], external: [ 'ember', 'ember-inflector', 'ember-data/version', 'ember-data/-debug', 'ember-data/adapters/errors' - ] + ] // cache: true|false Defaults to true } }); - var tree = merge([publicTree, privateTree]); - - if (isProductionEnv()) { - tree = new Funnel(tree, { - exclude: [ - /-debug/ - ] - }); - } + // the output of treeForAddon is required to be modules/ + publicTree = new Funnel(publicTree, { destDir: 'modules' }); + privateTree = new Funnel(privateTree, { destDir: 'modules' }); - return this._super.treeForAddon.call(this, merge([ - version(), - tree - ])); + return merge([ + publicTree, + privateTree + ]); }, - _setupBabelOptions: function() { - if (this._hasSetupBabelOptions) { - return; - } - + buildBabelOptions() { let customPlugins = require('./lib/stripped-build-plugins')(process.env.EMBER_ENV); - this.options.babel = { + return { loose: true, plugins: customPlugins.plugins, postTransformPlugins: customPlugins.postTransformPlugins }; + }, + + _setupBabelOptions: function() { + if (this._hasSetupBabelOptions) { + return; + } + + this.options.babel = this.buildBabelOptions(); this._hasSetupBabelOptions = true; }, diff --git a/package.json b/package.json index af8765df4f4..e602ff17611 100644 --- a/package.json +++ b/package.json @@ -27,9 +27,11 @@ "babel6-plugin-strip-heimdall": "^6.0.1", "broccoli-babel-transpiler": "^6.0.0", "broccoli-file-creator": "^1.0.0", + "broccoli-funnel": "^1.2.0", "broccoli-merge-trees": "^1.0.0", + "broccoli-rollup": "^1.2.0", "chalk": "^1.1.1", - "ember-cli-babel": "^6.0.0-beta.7", + "ember-cli-babel": "^6.0.0-beta.10", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.0.0", "ember-cli-test-info": "^1.0.0", @@ -59,8 +61,7 @@ "bower": "^1.6.5", "broccoli-asset-rev": "^2.4.5", "broccoli-concat": "^3.2.2", - "broccoli-funnel": "^1.0.0", - "broccoli-stew": "^1.0.1", + "broccoli-stew": "^1.4.2", "broccoli-string-replace": "^0.1.1", "broccoli-uglify-sourcemap": "^1.0.1", "broccoli-yuidoc": "^2.1.0", diff --git a/tests/helpers/test-in-debug.js b/tests/helpers/test-in-debug.js index 1ca57358ec0..a69bbbf6437 100644 --- a/tests/helpers/test-in-debug.js +++ b/tests/helpers/test-in-debug.js @@ -1,12 +1,12 @@ -import { runInDebug } from 'ember-data/-debug'; +import require from 'require'; import { test, skip } from 'qunit'; export default function testInDebug() { let isDebug = false; // TODO: this should be debug-stripped... - if (require.has('ember-data/-private/debug')) { - require('ember-data/-private/debug').runInDebug(() => isDebug = true); + if (require.has('ember-data/-debug')) { + require('ember-data/-debug').runInDebug(() => isDebug = true); } if (isDebug) { diff --git a/yarn.lock b/yarn.lock index db38696e2e2..0b7d81b3651 100644 --- a/yarn.lock +++ b/yarn.lock @@ -143,11 +143,11 @@ aproba@^1.0.3: resolved "https://registry.npmjs.org/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" are-we-there-yet@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + version "1.1.4" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" dependencies: delegates "^1.0.0" - readable-stream "^2.0.0 || ^1.1.13" + readable-stream "^2.0.6" argparse@^1.0.7, argparse@~1.0.2: version "1.0.9" @@ -273,8 +273,8 @@ asynckit@^0.4.0: resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" aws-sdk@^2.0.9: - version "2.43.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.43.0.tgz#a5f38099c2e279414e7e09f69719a542d816bdba" + version "2.45.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.45.0.tgz#045dbd323630170968306dc849d793dbb1e4444d" dependencies: buffer "4.9.1" crypto-browserify "1.0.9" @@ -911,8 +911,8 @@ babylon@^5.8.38: resolved "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" babylon@^6.11.0, babylon@^6.15.0: - version "6.16.1" - resolved "https://registry.npmjs.org/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3" + version "6.17.0" + resolved "https://registry.npmjs.org/babylon/-/babylon-6.17.0.tgz#37da948878488b9c4e3c4038893fa3314b3fc932" backbone@^1.1.2: version "1.3.3" @@ -1106,29 +1106,29 @@ broccoli-builder@^0.18.3: rsvp "^3.0.17" silent-error "^1.0.1" -broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.1: - version "2.0.4" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" +broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" - lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - symlink-or-copy "^1.0.0" - walk-sync "^0.2.0" + walk-sync "^0.2.5" -broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" +broccoli-caching-writer@~2.0.1: + version "2.0.4" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" + lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - walk-sync "^0.2.5" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" broccoli-clean-css@^1.1.0: version "1.1.0" @@ -1213,7 +1213,7 @@ broccoli-funnel-reducer@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" -broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli-funnel@^1.1.0: +broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli-funnel@^1.1.0, broccoli-funnel@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" dependencies: @@ -1321,6 +1321,22 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli rimraf "^2.3.4" symlink-or-copy "^1.1.8" +broccoli-rollup@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/broccoli-rollup/-/broccoli-rollup-1.2.0.tgz#627636c05837d894a85724ef9b7ca04d12b66751" + dependencies: + broccoli-plugin "^1.2.1" + es6-map "^0.1.4" + fs-extra "^0.30.0" + fs-tree-diff "^0.5.2" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + md5-hex "^1.3.0" + node-modules-path "^1.0.1" + rollup "^0.41.4" + symlink-or-copy "^1.1.8" + walk-sync "^0.3.1" + broccoli-slow-trees@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" @@ -1341,7 +1357,7 @@ broccoli-sri-hash@^2.1.0: sri-toolbox "^0.2.0" symlink-or-copy "^1.0.1" -broccoli-stew@^1.0.1, broccoli-stew@^1.2.0, broccoli-stew@^1.3.3: +broccoli-stew@^1.2.0, broccoli-stew@^1.3.3, broccoli-stew@^1.4.2: version "1.4.2" resolved "https://registry.npmjs.org/broccoli-stew/-/broccoli-stew-1.4.2.tgz#9ec4062fd7162c6026561a2fbf64558363aff8d6" dependencies: @@ -1411,10 +1427,6 @@ bser@1.0.2: dependencies: node-int64 "^0.4.0" -buffer-shims@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" - buffer@4.9.1: version "4.9.1" resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" @@ -1474,8 +1486,8 @@ can-symlink@^1.0.0: tmp "0.0.28" caniuse-db@^1.0.30000639: - version "1.0.30000655" - resolved "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000655.tgz#e40b6287adc938848d6708ef83d65b5f54ac1874" + version "1.0.30000660" + resolved "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000660.tgz#d2d57b309dc5a11bb5b46018f51855f7a41efee5" capture-exit@^1.1.0: version "1.2.0" @@ -1885,11 +1897,11 @@ debug@0.7.4: version "0.7.4" resolved "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" -debug@2, debug@2.6.3, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0: - version "2.6.3" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" +debug@2, debug@2.6.4, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0: + version "2.6.4" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0" dependencies: - ms "0.7.2" + ms "0.7.3" debug@2.2.0, debug@~2.2.0: version "2.2.0" @@ -2033,8 +2045,8 @@ ee-first@1.1.1: resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" electron-to-chromium@^1.2.7: - version "1.3.4" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.4.tgz#e51769c0cf550e0cf5aedf6aa2b803a264b3a900" + version "1.3.8" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.8.tgz#b2c8a2c79bb89fbbfd3724d9555e15095b5f5fb6" ember-ajax@^2.4.1: version "2.5.6" @@ -2050,7 +2062,7 @@ ember-cli-app-version@^2.0.0: ember-cli-htmlbars "^1.0.0" git-repo-version "0.4.1" -ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.2.1: +ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.2.1: version "5.2.4" resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" dependencies: @@ -2060,23 +2072,9 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.3, ember-c ember-cli-version-checker "^1.0.2" resolve "^1.1.2" -ember-cli-babel@^6.0.0: +ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.10, ember-cli-babel@^6.0.0-beta.7: version "6.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.0.0.tgz#caab075780dca3759982c9f54ea70a9adb1f3550" - dependencies: - amd-name-resolver "0.0.6" - babel-plugin-transform-es2015-modules-amd "^6.24.0" - babel-polyfill "^6.16.0" - babel-preset-env "^1.2.0" - broccoli-babel-transpiler "^6.0.0" - broccoli-funnel "^1.0.0" - broccoli-source "^1.1.0" - clone "^2.0.0" - ember-cli-version-checker "^1.2.0" - -ember-cli-babel@^6.0.0-beta.7: - version "6.0.0-beta.10" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.0.0-beta.10.tgz#71cc6bef05be99c6e7ea4637c444392014a6b775" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.0.0.tgz#caab075780dca3759982c9f54ea70a9adb1f3550" dependencies: amd-name-resolver "0.0.6" babel-plugin-transform-es2015-modules-amd "^6.24.0" @@ -2138,8 +2136,8 @@ ember-cli-get-dependency-depth@^1.0.0: resolved "https://registry.npmjs.org/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" ember-cli-htmlbars-inline-precompile@^0.4.0-beta.2: - version "0.4.0-beta.2" - resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.0-beta.2.tgz#2ecb78ea1aaa14dd75300e3856c10c7e309209f6" + version "0.4.0" + resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.0.tgz#4a6d2211b804419953104a9231e112dbd2057f3c" dependencies: babel-plugin-htmlbars-inline-precompile "^0.2.3" ember-cli-version-checker "^1.2.0" @@ -2312,14 +2310,14 @@ ember-cli-valid-component-name@^1.0.0: silent-error "^1.0.0" ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7, ember-cli-version-checker@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.2.0.tgz#caa286b77d1b485df5d2f62c67a6f19aa8b582c4" + version "1.3.1" + resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz#0bc2d134c830142da64bf9627a0eded10b61ae72" dependencies: semver "^5.3.0" ember-cli@^2.11.1: - version "2.12.1" - resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.12.1.tgz#33dd9341677f67f29bc0e286b129877ee15e5bcb" + version "2.12.2" + resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.12.2.tgz#eccae6359e5d4e49d509e6391dcdf1961848377a" dependencies: amd-name-resolver "0.0.6" bower-config "^1.3.0" @@ -2430,7 +2428,7 @@ ember-export-application-global@^1.0.5: ember-inflector@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ember-inflector/-/ember-inflector-2.0.0.tgz#ac0870e87c0724bd42cf5ed7ef166c49a296ecfb" + resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-2.0.0.tgz#ac0870e87c0724bd42cf5ed7ef166c49a296ecfb" dependencies: ember-cli-babel "^6.0.0" @@ -2467,7 +2465,7 @@ ember-router-generator@^1.0.0: ember-runtime-enumerable-includes-polyfill@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-2.0.0.tgz#6e9ba118bc909d1d7762de1b03a550d8955308a9" + resolved "https://registry.npmjs.org/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-2.0.0.tgz#6e9ba118bc909d1d7762de1b03a550d8955308a9" dependencies: ember-cli-babel "^6.0.0" ember-cli-version-checker "^1.1.6" @@ -2506,14 +2504,13 @@ ember-try-config@^2.0.1: semver "^5.1.0" ember-try@^0.2.9: - version "0.2.13" - resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.13.tgz#3d91f46950a40bba54da0edbbbb30480f83a9fdb" + version "0.2.14" + resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.14.tgz#d47e8fa38858d5683e47856e24a260b39e9caf4a" dependencies: chalk "^1.0.0" cli-table2 "^0.2.0" core-object "^1.1.0" debug "^2.2.0" - ember-cli-babel "^5.1.3" ember-cli-version-checker "^1.1.6" ember-try-config "^2.0.1" extend "^3.0.0" @@ -2622,7 +2619,7 @@ es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: es5-ext "^0.10.14" es6-symbol "^3.1" -es6-map@^0.1.3: +es6-map@^0.1.3, es6-map@^0.1.4: version "0.1.5" resolved "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" dependencies: @@ -2723,8 +2720,8 @@ eslint@^2.13.0: user-home "^2.0.0" espree@^3.1.6: - version "3.4.1" - resolved "https://registry.npmjs.org/espree/-/espree-3.4.1.tgz#28a83ab4aaed71ed8fe0f5efe61b76a05c13c4d2" + version "3.4.2" + resolved "https://registry.npmjs.org/espree/-/espree-3.4.2.tgz#38dbdedbedc95b8961a1fbf04734a8f6a9c8c592" dependencies: acorn "^5.0.1" acorn-jsx "^3.0.0" @@ -2989,10 +2986,10 @@ fill-range@^2.1.0: repeat-string "^1.5.2" finalhandler@~1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.1.tgz#bcd15d1689c0e5ed729b6f7f541a6df984117db8" + version "1.0.2" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.2.tgz#d0e36f9dbc557f2de14423df6261889e9d60c93a" dependencies: - debug "2.6.3" + debug "2.6.4" encodeurl "~1.0.1" escape-html "~1.0.3" on-finished "~2.3.0" @@ -3184,8 +3181,8 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" gauge@~2.7.1: - version "2.7.3" - resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09" + version "2.7.4" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -4314,7 +4311,7 @@ matcher-collection@^1.0.0, matcher-collection@^1.0.1: dependencies: minimatch "^3.0.2" -md5-hex@^1.0.2, md5-hex@^1.2.1: +md5-hex@^1.0.2, md5-hex@^1.2.1, md5-hex@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" dependencies: @@ -4495,6 +4492,10 @@ ms@0.7.2: version "0.7.2" resolved "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" +ms@0.7.3: + version "0.7.3" + resolved "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff" + mustache@^2.2.1: version "2.3.0" resolved "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" @@ -4522,7 +4523,7 @@ node-int64@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" -node-modules-path@^1.0.0: +node-modules-path@^1.0.0, node-modules-path@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" @@ -4553,8 +4554,8 @@ nopt@^4.0.0: osenv "^0.1.4" normalize-package-data@^2.3.2: - version "2.3.6" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff" + version "2.3.8" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -5003,16 +5004,15 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^2, "readable-stream@^2.0.0 || ^1.1.13": - version "2.2.9" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8" +readable-stream@^2, readable-stream@^2.0.6, readable-stream@~2.0.0: + version "2.0.6" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" dependencies: - buffer-shims "~1.0.0" core-util-is "~1.0.0" inherits "~2.0.1" isarray "~1.0.0" process-nextick-args "~1.0.6" - string_decoder "~1.0.0" + string_decoder "~0.10.x" util-deprecate "~1.0.1" readable-stream@~1.0.2: @@ -5024,17 +5024,6 @@ readable-stream@~1.0.2: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@~2.0.0: - version "2.0.6" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - readline2@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" @@ -5243,8 +5232,8 @@ resolve-from@^1.0.0: resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0: - version "1.3.2" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.3.2.tgz#1f0442c9e0cbb8136e87b9305f932f46c7f28235" + version "1.3.3" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" dependencies: path-parse "^1.0.5" @@ -5261,13 +5250,13 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1: +rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.5.1: version "2.5.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" -rimraf@^2.1.4, rimraf@^2.5.3, rimraf@^2.5.4: +rimraf@^2.1.4, rimraf@^2.3.2, rimraf@^2.4.4, rimraf@^2.5.3, rimraf@^2.5.4: version "2.6.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: @@ -5277,6 +5266,12 @@ rimraf@~2.2.6: version "2.2.8" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" +rollup@^0.41.4: + version "0.41.6" + resolved "https://registry.npmjs.org/rollup/-/rollup-0.41.6.tgz#e0d05497877a398c104d816d2733a718a7a94e2a" + dependencies: + source-map-support "^0.4.0" + route-recognizer@^0.1.9: version "0.1.11" resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" @@ -5285,11 +5280,11 @@ route-recognizer@^0.2.3: version "0.2.10" resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" -rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.6, rsvp@~3.2.1: +rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.6, rsvp@^3.2.1, rsvp@~3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" -rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: +rsvp@^3.0.14, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3, rsvp@^3.4.0: version "3.5.0" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" @@ -5348,8 +5343,8 @@ sax@1.2.1, sax@>=0.6.0: resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" selenium-webdriver@^3.0.0-beta-2: - version "3.3.0" - resolved "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.3.0.tgz#f14d9b04cee9495d4284d22105b189b8305ccca1" + version "3.4.0" + resolved "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.4.0.tgz#151f7445294da6a66c49cc300747a2a17e53c52a" dependencies: adm-zip "^0.4.7" rimraf "^2.5.4" @@ -5520,8 +5515,8 @@ sort-object-keys@^1.1.1: resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" sort-package-json@^1.4.0: - version "1.6.0" - resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.6.0.tgz#4aaf4d24a13252941e28a80f5a306eb5dcac1ab0" + version "1.6.1" + resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.6.1.tgz#2ae463e4f5bb5d803bfdffdb4f92551c8fa66593" dependencies: sort-object-keys "^1.1.1" @@ -5531,7 +5526,7 @@ source-map-support@^0.2.10: dependencies: source-map "0.1.32" -source-map-support@^0.4.2: +source-map-support@^0.4.0, source-map-support@^0.4.2: version "0.4.14" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef" dependencies: @@ -5644,12 +5639,6 @@ string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" -string_decoder@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.0.tgz#f06f41157b664d86069f84bdbdc9b0d8ab281667" - dependencies: - buffer-shims "~1.0.0" - stringmap@~0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" @@ -5781,8 +5770,8 @@ text-table@~0.2.0: resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" "textextensions@1 || 2": - version "2.0.1" - resolved "https://registry.npmjs.org/textextensions/-/textextensions-2.0.1.tgz#be8cf22d65379c151319f88f0335ad8f667abdca" + version "2.1.0" + resolved "https://registry.npmjs.org/textextensions/-/textextensions-2.1.0.tgz#1be0dc2a0dc244d44be8a09af6a85afb93c4dbc3" throttleit@^1.0.0: version "1.0.0" @@ -6094,8 +6083,8 @@ wrappy@1: resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" write-file-atomic@^1.1.2: - version "1.3.1" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" + version "1.3.3" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.3.tgz#831dd22d491bdc135180bb996a0eb3f8bf587791" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" From 07d37dbbfd5a59004d7f38de699f3d6f3844e1bb Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 25 Apr 2017 12:34:46 -0700 Subject: [PATCH 1911/2527] only coerce non-string id's --- addon/-private/system/coerce-id.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/coerce-id.js b/addon/-private/system/coerce-id.js index f15c722c954..8f8c305a98d 100644 --- a/addon/-private/system/coerce-id.js +++ b/addon/-private/system/coerce-id.js @@ -5,5 +5,7 @@ // ID into the URL, and if we later try to deserialize that URL and find the // corresponding record, we will not know if it is a string or a number. export default function coerceId(id) { - return id === null || id === undefined || id === '' ? null : id+''; + if (id === null || id === undefined || id === '') { return null; } + if (typeof id === 'string') { return id; } + return '' + id; } From 2d828d7802a9b1f406f43a478fdd94c0f85abc97 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 25 Apr 2017 13:19:32 -0700 Subject: [PATCH 1912/2527] hash-for-sep only the plugin (not all of ember-data) as this plugin has no dependencies. --- lib/transforms/babel-plugin-remove-imports.js | 2 +- lib/transforms/package.json | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 lib/transforms/package.json diff --git a/lib/transforms/babel-plugin-remove-imports.js b/lib/transforms/babel-plugin-remove-imports.js index 39838498e58..aec7d8852d0 100644 --- a/lib/transforms/babel-plugin-remove-imports.js +++ b/lib/transforms/babel-plugin-remove-imports.js @@ -34,7 +34,7 @@ function removeImports() { } removeImports.baseDir = function() { - return path.join(__dirname, '../../'); + return __dirname; }; module.exports = removeImports; diff --git a/lib/transforms/package.json b/lib/transforms/package.json new file mode 100644 index 00000000000..1f9b1fe9050 --- /dev/null +++ b/lib/transforms/package.json @@ -0,0 +1,3 @@ +{ + "name": "babel-plugin-remove-imports" +} From 14d4627484323f41900f9a5d3619312919f1edf5 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 26 Apr 2017 08:07:28 -0700 Subject: [PATCH 1913/2527] Update route.js --- tests/dummy/app/routes/query/route.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/dummy/app/routes/query/route.js b/tests/dummy/app/routes/query/route.js index 0587d04f38d..552f41f2e0d 100644 --- a/tests/dummy/app/routes/query/route.js +++ b/tests/dummy/app/routes/query/route.js @@ -1,6 +1,16 @@ /* global window, heimdall, console */ import Ember from 'ember'; +// fallback if no-heimdall happens to be present when loading the dummy app +let heimdall = self.heimdall; +if (typeof heimdall !== 'object') { + heimdall = { + start() { }, + stop() { } + }; +} + + const { Route } = Ember; From 7ed1c8a09d0e0737d0b425010bdba9a6715f7c9e Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 26 Apr 2017 10:56:36 -0700 Subject: [PATCH 1914/2527] remove needless change events when creating a liveRecordArray --- addon/-private/system/record-array-manager.js | 169 +++++++++++------- addon/-private/system/store.js | 10 +- .../integration/record-array-manager-test.js | 80 ++++++++- 3 files changed, 177 insertions(+), 82 deletions(-) diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 6c2a227d892..9351cc52485 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -12,6 +12,7 @@ import { assert } from 'ember-data/-debug'; const { get, + set, run: emberRun } = Ember; @@ -25,7 +26,6 @@ const { createRecordArray, liveRecordArrayFor, filteredRecordArraysFor, - populateLiveRecordArray, recordDidChange, registerFilteredRecordArray, unregisterRecordArray, @@ -41,7 +41,6 @@ const { 'createRecordArray', 'liveRecordArrayFor', 'filteredRecordArraysFor', - 'populateLiveRecordArray', 'recordDidChange', 'registerFilteredRecordArray', 'unregisterRecordArray', @@ -126,59 +125,22 @@ export default class RecordArrayManager { } } - // TODO: skip if it only changed - // process liveRecordArrays - if (this._liveRecordArrays[modelName]) { - this.updateLiveRecordArray(modelName, internalModels); + let array = this._liveRecordArrays[modelName]; + if (array) { + // TODO: skip if it only changed + // process liveRecordArrays + this.updateLiveRecordArray(array, internalModels); } // process adapterPopulatedRecordArrays if (modelsToRemove.length > 0) { - this.removeFromAdapterPopulatedRecordArrays(modelsToRemove); + removeFromAdapterPopulatedRecordArrays(modelsToRemove); } } } - updateLiveRecordArray(modelName, internalModels) { - let array = this.liveRecordArrayFor(modelName); - - let modelsToAdd = []; - let modelsToRemove = []; - - for (let i = 0; i < internalModels.length; i++) { - let internalModel = internalModels[i]; - let isDeleted = internalModel.isHiddenFromRecordArrays(); - let recordArrays = internalModel._recordArrays; - - if (!isDeleted && !internalModel.isEmpty()) { - if (!recordArrays.has(array)) { - modelsToAdd.push(internalModel); - recordArrays.add(array); - } - } - - if (isDeleted) { - modelsToRemove.push(internalModel); - recordArrays.delete(array) - } - } - - if (modelsToAdd.length > 0) { array._pushInternalModels(modelsToAdd); } - if (modelsToRemove.length > 0) { array._removeInternalModels(modelsToRemove); } - } - - removeFromAdapterPopulatedRecordArrays(internalModels) { - for (let i = 0; i < internalModels.length; i++) { - let internalModel = internalModels[i]; - let list = internalModel._recordArrays.list; - - for (let j = 0; j < list.length; j++) { - // TODO: group by arrays, so we can batch remove - list[j]._removeInternalModels([internalModel]); - } - - internalModel._recordArrays.clear(); - } + updateLiveRecordArray(array, internalModels) { + return updateLiveRecordArray(array, internalModels); } /** @@ -217,7 +179,7 @@ export default class RecordArrayManager { } // TODO: remove, utilize existing flush code but make it flush sync based on 1 modelName - syncLiveRecordArray(array, modelName) { + _syncLiveRecordArray(array, modelName) { assert(`recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); let hasNoPotentialDeletions = Object.keys(this._pending).length === 0; let map = this.store._internalModelsFor(modelName); @@ -228,29 +190,19 @@ export default class RecordArrayManager { liveRecordArrays, and is capable of strategically flushing those changes and applying small diffs if desired. However, until we've refactored recordArrayManager, this dirty check prevents us from unnecessarily wiping out live record arrays returned by peekAll. - */ + */ if (hasNoPotentialDeletions && hasNoInsertionsOrRemovals) { return; } - this.populateLiveRecordArray(array, map.models); - } - - // TODO: remove, when syncLiveRecordArray is removed - populateLiveRecordArray(array, internalModels) { - heimdall.increment(populateLiveRecordArray); - + let internalModels = this._visibleInternalModelsByType(modelName); let modelsToAdd = []; for (let i = 0; i < internalModels.length; i++) { let internalModel = internalModels[i]; - - if (!internalModel.isHiddenFromRecordArrays()) { - let recordArrays = internalModel._recordArrays; - - if (!recordArrays.has(array)) { - modelsToAdd.push(internalModel); - recordArrays.add(array); - } + let recordArrays = internalModel._recordArrays; + if (recordArrays.has(array) === false) { + recordArrays.add(array); + modelsToAdd.push(internalModel); } } @@ -278,6 +230,13 @@ export default class RecordArrayManager { this.updateFilterRecordArray(array, filter, internalModels); } + _didUpdateAll(modelName) { + let recordArray = this._liveRecordArrays[modelName]; + if (recordArray) { + set(recordArray, 'isUpdating', false); + } + } + /** Get the `DS.RecordArray` for a modelName, which contains all loaded records of given modelName. @@ -291,9 +250,33 @@ export default class RecordArrayManager { heimdall.increment(liveRecordArrayFor); - return this._liveRecordArrays[modelName] || (this._liveRecordArrays[modelName] = this.createRecordArray(modelName)) + let array = this._liveRecordArrays[modelName]; + + if (array) { + // if the array already exists, synchronize + this._syncLiveRecordArray(array, modelName); + } else { + // if the array is being newly created merely create it with its initial + // content already set. This prevents unneeded change events. + let internalModels = this._visibleInternalModelsByType(modelName); + array = this.createRecordArray(modelName, internalModels); + this._liveRecordArrays[modelName] = array; + } + + return array; } + _visibleInternalModelsByType(modelName) { + let all = this.store._internalModelsFor(modelName)._models; + let visible = []; + for (let i = 0; i < all.length; i++) { + let model = all[i]; + if (model.isHiddenFromRecordArrays() === false) { + visible.push(model); + } + } + return visible; + } /** Get the `DS.RecordArray` for a modelName, which contains all loaded records of given modelName. @@ -314,18 +297,28 @@ export default class RecordArrayManager { @method createRecordArray @param {String} modelName + @param {Array} _content (optional|private) @return {DS.RecordArray} */ - createRecordArray(modelName) { + createRecordArray(modelName, content) { assert(`recordArrayManger.createRecordArray expects modelName not modelClass as the param`, typeof modelName === 'string'); heimdall.increment(createRecordArray); - return RecordArray.create({ + + let array = RecordArray.create({ modelName, - content: Ember.A(), + content: Ember.A(content || []), store: this.store, isLoaded: true, manager: this }); + + if (Array.isArray(content)) { + for (let i = 0; i < content.length; i++) { + content[i]._recordArrays.add(array); + } + } + + return array; } /** @@ -470,3 +463,43 @@ function remove(array, item) { return false; } + +function updateLiveRecordArray(array, internalModels) { + let modelsToAdd = []; + let modelsToRemove = []; + + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; + let isDeleted = internalModel.isHiddenFromRecordArrays(); + let recordArrays = internalModel._recordArrays; + + if (!isDeleted && !internalModel.isEmpty()) { + if (!recordArrays.has(array)) { + modelsToAdd.push(internalModel); + recordArrays.add(array); + } + } + + if (isDeleted) { + modelsToRemove.push(internalModel); + recordArrays.delete(array) + } + } + + if (modelsToAdd.length > 0) { array._pushInternalModels(modelsToAdd); } + if (modelsToRemove.length > 0) { array._removeInternalModels(modelsToRemove); } +} + +function removeFromAdapterPopulatedRecordArrays(internalModels) { + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; + let list = internalModel._recordArrays.list; + + for (let j = 0; j < list.length; j++) { + // TODO: group by arrays, so we can batch remove + list[j]._removeInternalModels([internalModel]); + } + + internalModel._recordArrays.clear(); + } +} diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 86e5ec1de76..697f52f6bb5 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1652,9 +1652,7 @@ Store = Service.extend({ */ _didUpdateAll(modelName) { heimdall.increment(_didUpdateAll); - let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(modelName); - - set(liveRecordArray, 'isUpdating', false); + this.recordArrayManager._didUpdateAll(modelName); }, didUpdateAll(modelName) { @@ -1691,11 +1689,7 @@ Store = Service.extend({ assert(`You need to pass a model name to the store's peekAll method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); let normalizedModelName = normalizeModelName(modelName); - let liveRecordArray = this.recordArrayManager.liveRecordArrayFor(normalizedModelName); - - this.recordArrayManager.syncLiveRecordArray(liveRecordArray, normalizedModelName); - - return liveRecordArray; + return this.recordArrayManager.liveRecordArrayFor(normalizedModelName); }, /** diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index 6d9a42ed787..83975e5a1e6 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -162,18 +162,18 @@ test('Should not filter a store.peekAll() array when a record property is change return store.peekRecord('car', 1); }); - assert.deepEqual(cars.toArray(), [car]); + assert.deepEqual(cars.toArray(), [car], 'cars should contain [car]'); - assert.equal(updateLiveRecordArray.called.length, 1); - assert.equal(updateFilterRecordArray.called.length, 0); + assert.equal(updateLiveRecordArray.called.length, 1, 'updateLiveRecordArray should be called 1 time'); + assert.equal(updateFilterRecordArray.called.length, 0, 'updateLiveRecordArray should be called 0 times'); run(() => car.set('model', 'Mini')); - assert.deepEqual(cars.toArray(), [car]); + assert.deepEqual(cars.toArray(), [car], 'cars should contain [car]'); // TODO: differentiate between change + add/remove so we can skip non-filtered record arrays - assert.equal(updateLiveRecordArray.called.length, 2); - assert.equal(updateFilterRecordArray.called.length, 0); + assert.equal(updateLiveRecordArray.called.length, 2, 'updateLiveRecordArray should be called 2 times'); + assert.equal(updateFilterRecordArray.called.length, 0, 'updateFilterRecordArray should be called 0 times'); }); test('batch liveRecordArray changes', function(assert) { @@ -290,3 +290,71 @@ test('#GH-4041 store#query AdapterPopulatedRecordArrays are removed from their m assert.equal(manager._adapterPopulatedRecordArrays.length, 0); }); + +test('createRecordArray', function(assert) { + let recordArray = manager.createRecordArray('foo'); + + assert.equal(recordArray.modelName, 'foo'); + assert.equal(recordArray.isLoaded, true); + assert.equal(recordArray.manager, manager); + assert.deepEqual(recordArray.get('content'), []); + assert.deepEqual(recordArray.toArray(), []); +}); + +test('createRecordArray \w optional content', function(assert) { + let record = {}; + let internalModel = { + _recordArrays: new Ember.OrderedSet(), + getRecord() { + return record; + } + }; + let content = Ember.A([internalModel]); + let recordArray = manager.createRecordArray('foo', content); + + assert.equal(recordArray.modelName, 'foo'); + assert.equal(recordArray.isLoaded, true); + assert.equal(recordArray.manager, manager); + assert.equal(recordArray.get('content'), content); + assert.deepEqual(recordArray.toArray(), [record]); + + assert.deepEqual(internalModel._recordArrays.toArray(), [recordArray]); +}); + +test('liveRecordArrayFor always return the same array for a given type', function(assert) { + assert.equal(manager.liveRecordArrayFor('foo'), manager.liveRecordArrayFor('foo')) +}); + +test('liveRecordArrayFor create with content', function(assert) { + assert.expect(6); + + let createRecordArrayCalled = 0; + let superCreateRecordArray = manager.createRecordArray; + + manager.createRecordArray = function(modelName, internalModels) { + createRecordArrayCalled++; + assert.equal(modelName, 'car'); + assert.equal(internalModels.length, 1); + assert.equal(internalModels[0].id, 1); + return superCreateRecordArray.apply(this, arguments); + }; + + run(() => { + store.push({ + data: { + type: 'car', + id: '1', + attributes: { + make: 'BMC', + model: 'Mini Cooper' + } + } + }); + }); + + assert.equal(createRecordArrayCalled, 0, 'no record array has been created yet'); + manager.liveRecordArrayFor('car'); + assert.equal(createRecordArrayCalled, 1, 'one record array is created'); + manager.liveRecordArrayFor('car'); + assert.equal(createRecordArrayCalled, 1, 'no new record array is created'); +}); From 8c306d6ff581587238f1a88ae6a7724f47ec0068 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 26 Apr 2017 11:37:17 -0700 Subject: [PATCH 1915/2527] when possible, create adapter populated record arrays with there content (rather then add them after, and broadcasting change events) --- addon/-private/system/record-array-manager.js | 45 +++++++++--- .../adapter-populated-record-array.js | 7 +- addon/-private/system/store.js | 2 - addon/-private/system/store/finders.js | 15 +++- .../adapter-populated-record-array-test.js | 69 +++++++++++++++++++ 5 files changed, 118 insertions(+), 20 deletions(-) diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 9351cc52485..d01e30a6a91 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -9,6 +9,7 @@ import { AdapterPopulatedRecordArray } from "./record-arrays"; import { assert } from 'ember-data/-debug'; +import cloneNull from "./clone-null"; const { get, @@ -313,9 +314,7 @@ export default class RecordArrayManager { }); if (Array.isArray(content)) { - for (let i = 0; i < content.length; i++) { - content[i]._recordArrays.add(array); - } + associateWithRecordArray(content, array); } return array; @@ -356,17 +355,34 @@ export default class RecordArrayManager { @param {Object} query @return {DS.AdapterPopulatedRecordArray} */ - createAdapterPopulatedRecordArray(modelName, query) { + createAdapterPopulatedRecordArray(modelName, query, internalModels, payload) { heimdall.increment(createAdapterPopulatedRecordArray); assert(`recordArrayManger.createAdapterPopulatedRecordArray expects modelName not modelClass as the first param, received ${modelName}`, typeof modelName === 'string'); - let array = AdapterPopulatedRecordArray.create({ - modelName, - query: query, - content: Ember.A(), - store: this.store, - manager: this - }); + let array; + if (Array.isArray(internalModels)) { + array = AdapterPopulatedRecordArray.create({ + modelName, + query: query, + content: Ember.A(internalModels), + store: this.store, + manager: this, + isLoaded: true, + isUpdating: false, + meta: cloneNull(payload.meta), + links: cloneNull(payload.links) + }); + + associateWithRecordArray(internalModels, array); + } else { + array = AdapterPopulatedRecordArray.create({ + modelName, + query: query, + content: Ember.A(), + store: this.store, + manager: this + }); + } this._adapterPopulatedRecordArrays.push(array); @@ -503,3 +519,10 @@ function removeFromAdapterPopulatedRecordArrays(internalModels) { internalModel._recordArrays.clear(); } } + +export function associateWithRecordArray(internalModels, array) { + for (let i = 0, l = internalModels.length; i < l; i++) { + let internalModel = internalModels[i]; + internalModel._recordArrays.add(array); + } +} diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index 9000fd1ebf3..240d704ae2b 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -1,6 +1,7 @@ import Ember from 'ember'; import RecordArray from "./record-array"; import cloneNull from "../clone-null"; +import { associateWithRecordArray } from '../record-array-manager'; /** @module ember-data @@ -87,11 +88,7 @@ export default RecordArray.extend({ links: cloneNull(payload.links) }); - for (let i = 0, l = internalModels.length; i < l; i++) { - let internalModel = internalModels[i]; - - internalModel._recordArrays.add(this); - } + associateWithRecordArray(internalModels, this); // TODO: should triggering didLoad event be the last action of the runLoop? Ember.run.once(this, 'trigger', 'didLoad'); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 697f52f6bb5..23e75b200c4 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1270,8 +1270,6 @@ Store = Service.extend({ let modelToken = heimdall.start('initial-modelFor-lookup'); heimdall.stop(modelToken); - array = array || this.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); - let adapterToken = heimdall.start('initial-adapterFor-lookup'); let adapter = this.adapterFor(modelName); heimdall.stop(adapterToken); diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 479d5822461..9d11f927a23 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -137,7 +137,14 @@ export function _findAll(adapter, store, modelName, sinceToken, options) { export function _query(adapter, store, modelName, query, recordArray) { let modelClass = store.modelFor(modelName); // adapter.query needs the class - let promise = adapter.query(store, modelClass, query, recordArray); + + let promise; + if (adapter.query.length > 3) { + recordArray = recordArray || store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); + promise = adapter.query(store, modelClass, query, recordArray); + } else { + promise = adapter.query(store, modelClass, query); + } let label = `DS: Handle Adapter#query of ${modelClass}`; @@ -154,7 +161,11 @@ export function _query(adapter, store, modelName, query, recordArray) { let internalModels = store._push(payload); assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Array.isArray(internalModels)); - recordArray._setInternalModels(internalModels, payload); + if (recordArray) { + recordArray._setInternalModels(internalModels, payload); + } else { + recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query, internalModels, payload); + } return recordArray; }, null, `DS: Extract payload of query ${modelName}`); diff --git a/tests/integration/record-arrays/adapter-populated-record-array-test.js b/tests/integration/record-arrays/adapter-populated-record-array-test.js index 032ae779955..a8304fcb694 100644 --- a/tests/integration/record-arrays/adapter-populated-record-array-test.js +++ b/tests/integration/record-arrays/adapter-populated-record-array-test.js @@ -161,6 +161,75 @@ test('recordArray.replace() throws error', function(assert) { }, Error('The result of a server query (on person) is immutable.'), 'throws error'); }); +test('only pass record array if explicitly in arity', function(assert) { + let env = setupStore({ person: Person }); + let store = env.store; + + let payload = [ + { id: '1', name: 'Scumbag Dale' }, + { id: '2', name: 'Scumbag Katz' } + ]; + + env.adapter.query = function(store, type, query) { + assert.equal(arguments.length, 3); + return payload; + }; + + return store.query('person', { }).then(recordArray => { + env.adapter.query = function(store, type, query, _recordArray) { + assert.equal(arguments.length, 4); + return payload; + }; + return store.query('person', { }); + }); +}); + +test('only pass record array if explicitly in arity', function(assert) { + let env = setupStore({ person: Person }); + let store = env.store; + + let payload = [ + { id: '1', name: 'Scumbag Dale' }, + { id: '2', name: 'Scumbag Katz' } + ]; + + let actualQuery = { }; + + let superCreateAdapterPopulatedRecordArray = store.recordArrayManager.createAdapterPopulatedRecordArray; + + store.recordArrayManager.createStore = function(modelName, query, internalModels, _payload) { + assert.equal(arguments.length === 4); + + assert.equal(modelName, 'person'); + assert.equal(query, actualQuery); + assert.equal(_payload, payload); + assert.equal(internalModels.length, 2); + return superCreateAdapterPopulatedRecordArray.apply(this, arguments); + }; + + env.adapter.query = function(store, type, query) { + assert.equal(arguments.length, 3); + return payload; + }; + + return store.query('person', actualQuery).then(recordArray => { + env.adapter.query = function(store, type, query, _recordArray) { + assert.equal(arguments.length, 4); + return payload; + }; + + store.recordArrayManager.createStore = function(modelName, query) { + assert.equal(arguments.length === 2); + + assert.equal(modelName, 'person'); + assert.equal(query, actualQuery); + return superCreateAdapterPopulatedRecordArray.apply(this, arguments); + }; + + return store.query('person', actualQuery); + }); +}); + test('loadRecord re-syncs internalModels recordArrays', function(assert) { let env = setupStore({ person: Person }); let store = env.store; From 05e95280e11c411177f2fbcb65fd83488d6a9d89 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 26 Apr 2017 13:05:36 -0700 Subject: [PATCH 1916/2527] [SVELTE] Transforms & remove Date.parse polyfill (#4936) * cleanup Date.parse * more cleanup of PR * fix tests * fix phantom * fix phantom --- addon/-private/ext/date.js | 90 ------------------ addon/-private/index.js | 8 -- addon/-private/transforms/date.js | 50 ---------- addon/index.js | 11 ++- addon/setup-container.js | 11 ++- addon/{-private => }/transforms/boolean.js | 0 addon/transforms/date.js | 99 ++++++++++++++++++++ addon/{-private => }/transforms/number.js | 0 addon/{-private => }/transforms/string.js | 0 addon/{-private => }/transforms/transform.js | 0 package.json | 3 +- tests/unit/model-test.js | 4 +- tests/unit/transform/date-test.js | 29 +++--- yarn.lock | 60 +++++++++--- 14 files changed, 171 insertions(+), 194 deletions(-) delete mode 100644 addon/-private/ext/date.js delete mode 100644 addon/-private/transforms/date.js rename addon/{-private => }/transforms/boolean.js (100%) create mode 100644 addon/transforms/date.js rename addon/{-private => }/transforms/number.js (100%) rename addon/{-private => }/transforms/string.js (100%) rename addon/{-private => }/transforms/transform.js (100%) diff --git a/addon/-private/ext/date.js b/addon/-private/ext/date.js deleted file mode 100644 index cdcda62b4e4..00000000000 --- a/addon/-private/ext/date.js +++ /dev/null @@ -1,90 +0,0 @@ -/** - @module ember-data -*/ - -import Ember from 'ember'; -import { deprecate } from 'ember-data/-debug'; - - -/** - Date.parse with progressive enhancement for ISO 8601 - - © 2011 Colin Snover - - Released under MIT license. - - @class Date - @namespace Ember - @static - @deprecated -*/ -Ember.Date = Ember.Date || {}; - -const origParse = Date.parse; -const numericKeys = [1, 4, 5, 6, 7, 10, 11]; - -export const parseDate = function (date) { - let timestamp, struct; - let minutesOffset = 0; - - // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string - // before falling back to any implementation-specific date parsing, so that’s what we do, even if native - // implementations could be faster - // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm - if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2}):?(?:(\d{2}))?)?)?$/.exec(date))) { - // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC - for (let i = 0, k; (k = numericKeys[i]); ++i) { - struct[k] = +struct[k] || 0; - } - - // allow undefined days and months - struct[2] = (+struct[2] || 1) - 1; - struct[3] = +struct[3] || 1; - - if (struct[8] !== 'Z' && struct[9] !== undefined) { - minutesOffset = struct[10] * 60 + struct[11]; - - if (struct[9] === '+') { - minutesOffset = 0 - minutesOffset; - } - } - - timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]); - } else { - timestamp = origParse ? origParse(date) : NaN; - } - - return timestamp; -}; - -Ember.Date.parse = function (date) { - // throw deprecation - deprecate(`Ember.Date.parse is deprecated because Safari 5-, IE8-, and - Firefox 3.6- are no longer supported (see - https://github.com/csnover/js-iso8601 for the history of this issue). - Please use Date.parse instead`, false, { - id: 'ds.ember.date.parse-deprecate', - until: '3.0.0' - }); - - return parseDate(date); -}; - -if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Date) { - deprecate(`Overriding Date.parse with Ember.Date.parse is deprecated. Please set ENV.EmberENV.EXTEND_PROTOTYPES.Date to false in config/environment.js - - -// config/environment.js -ENV = { - EmberENV: { - EXTEND_PROTOTYPES: { - Date: false, - } - } -} -`, false, { - id: 'ds.date.parse-deprecate', - until: '3.0.0' -}); - Date.parse = parseDate; -} diff --git a/addon/-private/index.js b/addon/-private/index.js index 1e7ecc60d92..ba709785c38 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -27,19 +27,11 @@ export { getOwner, modelHasAttributeOrRelationshipNamedType } from './utils'; export { default as coerceId } from './system/coerce-id'; export { default as parseResponseHeaders } from './utils/parse-response-headers'; -// should be moved into public ? -export { default as Transform } from './transforms/transform'; -export { default as NumberTransform } from './transforms/number'; -export { default as DateTransform } from './transforms/date'; -export { default as StringTransform } from './transforms/string'; -export { default as BooleanTransform } from './transforms/boolean'; - // should be private ? export { default as RootState } from './system/model/states'; export { default as global } from './global'; export { default as isEnabled } from './features'; export { default as InternalModel } from './system/model/internal-model'; -export { parseDate } from './ext/date'; export { PromiseArray, diff --git a/addon/-private/transforms/date.js b/addon/-private/transforms/date.js deleted file mode 100644 index 192da27ade2..00000000000 --- a/addon/-private/transforms/date.js +++ /dev/null @@ -1,50 +0,0 @@ -import Transform from './transform'; -import { parseDate } from '../ext/date'; - -/** - The `DS.DateTransform` class is used to serialize and deserialize - date attributes on Ember Data record objects. This transform is used - when `date` is passed as the type parameter to the - [DS.attr](../../data#method_attr) function. It uses the [`ISO 8601`](https://en.wikipedia.org/wiki/ISO_8601) - standard. - - ```app/models/score.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - value: DS.attr('number'), - player: DS.belongsTo('player'), - date: DS.attr('date') - }); - ``` - - @class DateTransform - @extends DS.Transform - @namespace DS - */ - -export default Transform.extend({ - deserialize(serialized) { - let type = typeof serialized; - - if (type === "string") { - return new Date(parseDate(serialized)); - } else if (type === "number") { - return new Date(serialized); - } else if (serialized === null || serialized === undefined) { - // if the value is null return null - // if the value is not present in the data return undefined - return serialized; - } else { - return null; - } - }, - - serialize(date) { - if (date instanceof Date && !isNaN(date)) { - return date.toISOString(); - } else { - return null; - } - } -}); diff --git a/addon/index.js b/addon/index.js index e2794028db1..c8df6d7412c 100644 --- a/addon/index.js +++ b/addon/index.js @@ -28,11 +28,6 @@ import { Model, Store, normalizeModelName, - Transform, - DateTransform, - NumberTransform, - StringTransform, - BooleanTransform, PromiseArray, PromiseObject, PromiseManyArray, @@ -59,6 +54,12 @@ import "ember-inflector"; import setupContainer from "./setup-container"; import initializeStoreService from './instance-initializers/initialize-store-service'; +import Transform from './transforms/transform'; +import NumberTransform from './transforms/number'; +import DateTransform from './transforms/date'; +import StringTransform from './transforms/string'; +import BooleanTransform from './transforms/boolean'; + import Adapter from "./adapter"; import JSONAPIAdapter from './adapters/json-api'; import RESTAdapter from './adapters/rest'; diff --git a/addon/setup-container.js b/addon/setup-container.js index d1807fde32f..686d7b786db 100644 --- a/addon/setup-container.js +++ b/addon/setup-container.js @@ -1,10 +1,6 @@ import { DebugAdapter, - Store, - NumberTransform, - DateTransform, - StringTransform, - BooleanTransform + Store } from './-private'; import JSONAPISerializer from './serializers/json-api'; import JSONSerializer from './serializers/json'; @@ -12,6 +8,11 @@ import RESTSerializer from './serializers/rest'; import JSONAPIAdapter from './adapters/json-api'; import RESTAdapter from './adapters/rest'; +import NumberTransform from './transforms/number'; +import DateTransform from './transforms/date'; +import StringTransform from './transforms/string'; +import BooleanTransform from './transforms/boolean'; + function has(applicationOrRegistry, fullName) { if (applicationOrRegistry.has) { // < 2.1.0 diff --git a/addon/-private/transforms/boolean.js b/addon/transforms/boolean.js similarity index 100% rename from addon/-private/transforms/boolean.js rename to addon/transforms/boolean.js diff --git a/addon/transforms/date.js b/addon/transforms/date.js new file mode 100644 index 00000000000..0ceebb80331 --- /dev/null +++ b/addon/transforms/date.js @@ -0,0 +1,99 @@ +import Transform from './transform'; +import Ember from 'ember'; +import { deprecate } from 'ember-data/-debug'; + +Ember.Date = Ember.Date || {}; + +/** + Date.parse with progressive enhancement for ISO 8601 + + © 2011 Colin Snover + + Released under MIT license. + + @class Date + @namespace Ember + @static + @deprecated + */ +Ember.Date.parse = function(date) { + // throw deprecation + deprecate(`Ember.Date.parse is deprecated because Safari 5-, IE8-, and + Firefox 3.6- are no longer supported (see + https://github.com/csnover/js-iso8601 for the history of this issue). + Please use Date.parse instead`, + false, + { + id: 'ds.ember.date.parse-deprecate', + until: '3.0.0' + }); + + return Date.parse(date); +}; + + +/** + The `DS.DateTransform` class is used to serialize and deserialize + date attributes on Ember Data record objects. This transform is used + when `date` is passed as the type parameter to the + [DS.attr](../../data#method_attr) function. It uses the [`ISO 8601`](https://en.wikipedia.org/wiki/ISO_8601) + standard. + + ```app/models/score.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + value: DS.attr('number'), + player: DS.belongsTo('player'), + date: DS.attr('date') + }); + ``` + + @class DateTransform + @extends DS.Transform + @namespace DS + */ + +export default Transform.extend({ + deserialize(serialized) { + let type = typeof serialized; + + if (type === "string") { + let offset = serialized.indexOf('+'); + + if (offset !== -1 && serialized.length - 3 === offset) { + deprecate(`The ECMA2015 Spec for ISO 8601 dates does not allow for shorthand timezone offsets such as +00. + Ember Data's normalization of date's allowing for this shorthand has been deprecated, please update your API to return + UTC dates formatted with ±hh:mm timezone offsets or implement a custom UTC transform.`, + false, + { + id: 'ds.attr.date.normalize-utc', + until: '3.0.0' + }); + return new Date(`${serialized}:00`); + + // this is a phantom specific bug fix in which +0000 is not supported + } else if (offset !== -1 && serialized.length - 5 === offset) { + offset += 3; + return new Date(serialized.slice(0, offset) + ':' + serialized.slice(offset)); + } + return new Date(serialized); + } else if (type === "number") { + return new Date(serialized) + } else if (serialized === null || serialized === undefined) { + // if the value is null return null + // if the value is not present in the data return undefined + return serialized; + } else { + return null; + } + }, + + serialize(date) { + if (date instanceof Date && !isNaN(date)) { + return date.toISOString(); + } else { + return null; + } + } +}); diff --git a/addon/-private/transforms/number.js b/addon/transforms/number.js similarity index 100% rename from addon/-private/transforms/number.js rename to addon/transforms/number.js diff --git a/addon/-private/transforms/string.js b/addon/transforms/string.js similarity index 100% rename from addon/-private/transforms/string.js rename to addon/transforms/string.js diff --git a/addon/-private/transforms/transform.js b/addon/transforms/transform.js similarity index 100% rename from addon/-private/transforms/transform.js rename to addon/transforms/transform.js diff --git a/package.json b/package.json index e602ff17611..48d66b62d57 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,8 @@ "inflection": "^1.8.0", "npm-git-info": "^1.0.0", "semver": "^5.1.0", - "silent-error": "^1.0.0" + "silent-error": "^1.0.0", + "testem": "1.15.0" }, "devDependencies": { "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 6385dcd9592..1340ea94cc7 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -4,7 +4,7 @@ import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; -import { isEnabled, parseDate } from 'ember-data/-private'; +import { isEnabled } from 'ember-data/-private'; const { get, set, run } = Ember; @@ -1099,7 +1099,7 @@ test('a DS.Model can describe Date attributes', function(assert) { converts(assert, 'date', undefined, undefined); let dateString = '2011-12-31T00:08:16.000Z'; - let date = new Date(parseDate(dateString)); + let date = new Date(dateString); const Person = DS.Model.extend({ updatedAt: DS.attr('date') diff --git a/tests/unit/transform/date-test.js b/tests/unit/transform/date-test.js index cf61d5d15af..46746ced520 100644 --- a/tests/unit/transform/date-test.js +++ b/tests/unit/transform/date-test.js @@ -4,13 +4,12 @@ import DS from 'ember-data'; import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import { parseDate } from 'ember-data/-private'; module('unit/transform - DS.DateTransform'); let dateString = '2015-01-01T00:00:00.000Z'; -let dateInMillis = parseDate(dateString); -let date = new Date(dateInMillis); +let dateInMillis = Date.parse(dateString); +let date = new Date(dateString); test('#serialize', function(assert) { let transform = new DS.DateTransform(); @@ -39,28 +38,22 @@ test('#deserialize', function(assert) { assert.equal(transform.deserialize(undefined), null); }); -test('#deserialize with different offset formats', function(assert) { +testInDebug('#deserialize with different offset formats', function(assert) { let transform = new DS.DateTransform(); let dateString = '2003-05-24T23:00:00.000+0000'; let dateStringColon = '2013-03-15T23:22:00.000+00:00'; let dateStringShortOffset = '2016-12-02T17:30:00.000+00'; - assert.expect(6); + assert.expect(4); - let _dateUTC = Date.UTC; - - try { - Date.UTC = function () { - assert.equal(arguments.length, 7); - return _dateUTC.apply(this, [].slice.call(arguments)); - }; + let deserialized; + assert.expectDeprecation(() => { + deserialized = transform.deserialize(dateStringShortOffset).getTime(); + }, /The ECMA2015 Spec for ISO 8601 dates does not allow for shorthand timezone offsets such as \+00/); - assert.equal(transform.deserialize(dateString).getTime(), 1053817200000); - assert.equal(transform.deserialize(dateStringShortOffset).getTime(), 1480699800000); - assert.equal(transform.deserialize(dateStringColon).getTime(), 1363389720000); - } finally { - Date.UTC = _dateUTC; - } + assert.equal(transform.deserialize(dateString).getTime(), 1053817200000, 'date-strings with no-colon offsets are ok'); + assert.equal(deserialized, 1480699800000, 'This test can be removed once the deprecation is removed'); + assert.equal(transform.deserialize(dateStringColon).getTime(), 1363389720000, 'date-strings with colon offsets are ok'); }); testInDebug('Ember.Date.parse has been deprecated', function(assert) { diff --git a/yarn.lock b/yarn.lock index 0b7d81b3651..f0d65707e4f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1106,29 +1106,29 @@ broccoli-builder@^0.18.3: rsvp "^3.0.17" silent-error "^1.0.1" -broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" +broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.1: + version "2.0.4" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" + lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - walk-sync "^0.2.5" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" -broccoli-caching-writer@~2.0.1: - version "2.0.4" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" +broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" - lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - symlink-or-copy "^1.0.0" - walk-sync "^0.2.0" + walk-sync "^0.2.5" broccoli-clean-css@^1.1.0: version "1.1.0" @@ -1853,7 +1853,7 @@ core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -cross-spawn@^5.0.1, cross-spawn@^5.1.0: +cross-spawn@^5.0.0, cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -5250,13 +5250,13 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.5.1: +rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1: version "2.5.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" -rimraf@^2.1.4, rimraf@^2.3.2, rimraf@^2.4.4, rimraf@^2.5.3, rimraf@^2.5.4: +rimraf@^2.1.4, rimraf@^2.5.3, rimraf@^2.5.4: version "2.6.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: @@ -5280,11 +5280,11 @@ route-recognizer@^0.2.3: version "0.2.10" resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" -rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.6, rsvp@^3.2.1, rsvp@~3.2.1: +rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.6, rsvp@~3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" -rsvp@^3.0.14, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3, rsvp@^3.4.0: +rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: version "3.5.0" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" @@ -5734,6 +5734,36 @@ temp@0.8.3: os-tmpdir "^1.0.0" rimraf "~2.2.6" +testem@1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/testem/-/testem-1.15.0.tgz#2e3a9e7ac29f16a20f718eb0c4b12e7a44900675" + dependencies: + backbone "^1.1.2" + bluebird "^3.4.6" + charm "^1.0.0" + commander "^2.6.0" + consolidate "^0.14.0" + cross-spawn "^5.0.0" + express "^4.10.7" + fireworm "^0.7.0" + glob "^7.0.4" + http-proxy "^1.13.1" + js-yaml "^3.2.5" + lodash.assignin "^4.1.0" + lodash.clonedeep "^4.4.1" + lodash.find "^4.5.1" + mkdirp "^0.5.1" + mustache "^2.2.1" + node-notifier "^5.0.1" + npmlog "^4.0.0" + printf "^0.2.3" + rimraf "^2.4.4" + socket.io "1.6.0" + spawn-args "^0.2.0" + styled_string "0.0.1" + tap-parser "^5.1.0" + xmldom "^0.1.19" + testem@^1.8.1: version "1.16.0" resolved "https://registry.npmjs.org/testem/-/testem-1.16.0.tgz#3933040b5d5b5fbdb6a2b1e7032e511b54a05867" From ca39ec16114d1ff4ae056fb28accb4f23d4cb4e5 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 26 Apr 2017 13:24:30 -0700 Subject: [PATCH 1917/2527] Model#willMergeMixin is a development assertion, remove it for prod builds --- addon/-private/system/model/model.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index f244a433e26..deb5660181f 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -842,14 +842,6 @@ const Model = Ember.Object.extend(Ember.Evented, { this._super(...arguments); }, - // This is a temporary solution until we refactor DS.Model to not - // rely on the data property. - willMergeMixin(props) { - let constructor = this.constructor; - assert('`' + intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + constructor.toString(), !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0]); - assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + constructor.toString(), Object.keys(props).indexOf('id') === -1); - }, - attr() { assert("The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); }, From ea2682f69a65e22d3ca0fa644664ffd9e58d9a45 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 26 Apr 2017 13:24:39 -0700 Subject: [PATCH 1918/2527] tidy up spacing --- addon/-private/system/model/model.js | 50 ++++++++++++++++------------ 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index deb5660181f..e52b14b8a7d 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1877,32 +1877,40 @@ if (isEnabled('ds-rollback-attribute')) { runInDebug(() => { Model.reopen({ - /** - This Ember.js hook allows an object to be notified when a property - is defined. + // This is a temporary solution until we refactor DS.Model to not + // rely on the data property. + willMergeMixin(props) { + let constructor = this.constructor; + assert('`' + intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + constructor.toString(), !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0]); + assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + constructor.toString(), Object.keys(props).indexOf('id') === -1); + }, - In this case, we use it to be notified when an Ember Data user defines a - belongs-to relationship. In that case, we need to set up observers for - each one, allowing us to track relationship changes and automatically - reflect changes in the inverse has-many array. + /** + This Ember.js hook allows an object to be notified when a property + is defined. - This hook passes the class being set up, as well as the key and value - being defined. So, for example, when the user does this: + In this case, we use it to be notified when an Ember Data user defines a + belongs-to relationship. In that case, we need to set up observers for + each one, allowing us to track relationship changes and automatically + reflect changes in the inverse has-many array. - ```javascript - DS.Model.extend({ - parent: DS.belongsTo('user') - }); - ``` + This hook passes the class being set up, as well as the key and value + being defined. So, for example, when the user does this: - This hook would be called with "parent" as the key and the computed - property returned by `DS.belongsTo` as the value. + ```javascript + DS.Model.extend({ + parent: DS.belongsTo('user') + }); + ``` - @method didDefineProperty - @param {Object} proto - @param {String} key - @param {Ember.ComputedProperty} value - */ + This hook would be called with "parent" as the key and the computed + property returned by `DS.belongsTo` as the value. + + @method didDefineProperty + @param {Object} proto + @param {String} key + @param {Ember.ComputedProperty} value + */ didDefineProperty(proto, key, value) { // Check if the value being set is a computed property. if (value instanceof Ember.ComputedProperty) { From 097ad906e9114ae68f9e99f2c4133d5c21be469c Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 26 Apr 2017 14:34:57 -0700 Subject: [PATCH 1919/2527] start guarding against poorly optimized babel output --- addon/-private/system/store.js | 32 +++++++++++++------------ addon/serializers/rest.js | 28 +++++++++++----------- index.js | 5 +++- lib/stripped-build-plugins.js | 7 +++++- package.json | 2 +- yarn.lock | 43 ++++------------------------------ 6 files changed, 46 insertions(+), 71 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 86e5ec1de76..cdadc90e563 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -933,29 +933,31 @@ Store = Service.extend({ let groups = adapter.groupRecordsForFindMany(this, snapshots); - for (let i = 0, l = groups.length; i < l; i++) { - let group = groups[i]; - let totalInGroup = groups[i].length; - let ids = new Array(totalInGroup); - let groupedInternalModels = new Array(totalInGroup); + for (var i = 0, l = groups.length; i < l; i++) { + var group = groups[i]; + var totalInGroup = groups[i].length; + var ids = new Array(totalInGroup); + var groupedInternalModels = new Array(totalInGroup); - for (let j = 0; j < totalInGroup; j++) { - let internalModel = group[j]._internalModel; + for (var j = 0; j < totalInGroup; j++) { + var internalModel = group[j]._internalModel; groupedInternalModels[j] = internalModel; ids[j] = internalModel.id; } if (totalInGroup > 1) { - _findMany(adapter, store, modelName, ids, groupedInternalModels) - .then(function(foundInternalModels) { - handleFoundRecords(foundInternalModels, groupedInternalModels); - }) - .catch(function(error) { - rejectInternalModels(groupedInternalModels, error); - }); + (function(groupedInternalModels) { + _findMany(adapter, store, modelName, ids, groupedInternalModels) + .then(function(foundInternalModels) { + handleFoundRecords(foundInternalModels, groupedInternalModels); + }) + .catch(function(error) { + rejectInternalModels(groupedInternalModels, error); + }); + }(groupedInternalModels)); } else if (ids.length === 1) { - let pair = seeking[groupedInternalModels[0].id]; + var pair = seeking[groupedInternalModels[0].id]; _fetchRecord(pair); } else { assert("You cannot return an empty array from adapter's method groupRecordsForFindMany", false); diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 5f4e3397cb3..0ab46e9f4a3 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -253,10 +253,10 @@ let RESTSerializer = JSONSerializer.extend({ let keys = Object.keys(payload); - for (let i = 0, length = keys.length; i < length; i++) { - let prop = keys[i]; - let modelName = prop; - let forcedSecondary = false; + for (var i = 0, length = keys.length; i < length; i++) { + var prop = keys[i]; + var modelName = prop; + var forcedSecondary = false; /* If you want to provide sideloaded records of the same type that the @@ -283,7 +283,7 @@ let RESTSerializer = JSONSerializer.extend({ modelName = prop.substr(1); } - let typeName = this.modelNameFromPayloadKey(modelName); + var typeName = this.modelNameFromPayloadKey(modelName); if (!store.modelFactoryFor(typeName)) { warn(this.warnMessageNoModelForKey(modelName, typeName), false, { id: 'ds.serializer.model-for-key-missing' @@ -291,8 +291,8 @@ let RESTSerializer = JSONSerializer.extend({ continue; } - let isPrimary = (!forcedSecondary && this.isPrimaryType(store, typeName, primaryModelClass)); - let value = payload[prop]; + var isPrimary = (!forcedSecondary && this.isPrimaryType(store, typeName, primaryModelClass)); + var value = payload[prop]; if (value === null) { continue; @@ -319,7 +319,7 @@ let RESTSerializer = JSONSerializer.extend({ } ``` */ - if (isPrimary && Ember.typeOf(value) !== 'array') { + if (isPrimary && !Array.isArray(value)) { let { data, included } = this._normalizePolymorphicRecord(store, value, prop, primaryModelClass, this); documentHash.data = data; if (included) { @@ -335,7 +335,7 @@ let RESTSerializer = JSONSerializer.extend({ } if (isSingle) { - data.forEach((resource) => { + data.forEach(resource => { /* Figures out if this is the primary record or not. @@ -410,18 +410,18 @@ let RESTSerializer = JSONSerializer.extend({ included: [] }; - for (let prop in payload) { - let modelName = this.modelNameFromPayloadKey(prop); + for (var prop in payload) { + var modelName = this.modelNameFromPayloadKey(prop); if (!store.modelFactoryFor(modelName)) { warn(this.warnMessageNoModelForKey(prop, modelName), false, { id: 'ds.serializer.model-for-key-missing' }); continue; } - let type = store.modelFor(modelName); - let typeSerializer = store.serializerFor(type.modelName); + var type = store.modelFor(modelName); + var typeSerializer = store.serializerFor(type.modelName); - Ember.makeArray(payload[prop]).forEach((hash) => { + Ember.makeArray(payload[prop]).forEach(hash => { let { data, included } = typeSerializer.normalize(type, hash, prop); documentHash.data.push(data); if (included) { diff --git a/index.js b/index.js index e8c81b05b97..ed4474cf9d0 100644 --- a/index.js +++ b/index.js @@ -174,7 +174,10 @@ module.exports = { return { loose: true, plugins: customPlugins.plugins, - postTransformPlugins: customPlugins.postTransformPlugins + postTransformPlugins: customPlugins.postTransformPlugins, + exclude: [ + 'transform-es2015-block-scoping', + ] }; }, diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index ce122923a8b..eb48cbeda6d 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -4,6 +4,7 @@ var FeatureFlags = require('babel-plugin-feature-flags'); var StripHeimdall = require('babel6-plugin-strip-heimdall'); var StripClassCallCheck = require('babel6-plugin-strip-class-callcheck'); var StripFilteredImports = require('./transforms/babel-plugin-remove-imports'); +var TransformBlockScoping = require('babel-plugin-transform-es2015-block-scoping'); function uniqueAdd(obj, key, values) { var a = obj[key] = obj[key] || []; @@ -58,7 +59,11 @@ module.exports = function(environment) { 'debugSeal' ]); } - plugins.push([FilterImports, filteredImports]); + + plugins.push( + [FilterImports, filteredImports], + ['transform-es2015-block-scoping', { 'throwIfClosureRequired': true }] + ); if (environment === 'production') { plugins.push([StripFilteredImports, 'ember-data/-debug']); diff --git a/package.json b/package.json index 48d66b62d57..e13c7e97092 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ }, "devDependencies": { "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.23.0", + "babel-plugin-transform-es2015-block-scoping": "^6.24.1", "babel-plugin-transform-es2015-classes": "^6.23.0", "babel-plugin-transform-es2015-computed-properties": "^6.22.0", "babel-plugin-transform-es2015-constants": "^6.1.4", diff --git a/yarn.lock b/yarn.lock index f0d65707e4f..b7d6d217283 100644 --- a/yarn.lock +++ b/yarn.lock @@ -605,9 +605,9 @@ babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-block-scoping@^6.23.0: +babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz#76c295dc3a4741b1665adfd3167215dcff32a576" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz#76c295dc3a4741b1665adfd3167215dcff32a576" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" @@ -1853,7 +1853,7 @@ core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -cross-spawn@^5.0.0, cross-spawn@^5.0.1, cross-spawn@^5.1.0: +cross-spawn@^5.0.0, cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -4232,10 +4232,6 @@ lodash.uniq@^4.2.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -lodash.uniqby@^4.7.0: - version "4.7.0" - resolved "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" - lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" @@ -5734,7 +5730,7 @@ temp@0.8.3: os-tmpdir "^1.0.0" rimraf "~2.2.6" -testem@1.15.0: +testem@1.15.0, testem@^1.8.1: version "1.15.0" resolved "https://registry.yarnpkg.com/testem/-/testem-1.15.0.tgz#2e3a9e7ac29f16a20f718eb0c4b12e7a44900675" dependencies: @@ -5764,37 +5760,6 @@ testem@1.15.0: tap-parser "^5.1.0" xmldom "^0.1.19" -testem@^1.8.1: - version "1.16.0" - resolved "https://registry.npmjs.org/testem/-/testem-1.16.0.tgz#3933040b5d5b5fbdb6a2b1e7032e511b54a05867" - dependencies: - backbone "^1.1.2" - bluebird "^3.4.6" - charm "^1.0.0" - commander "^2.6.0" - consolidate "^0.14.0" - cross-spawn "^5.1.0" - express "^4.10.7" - fireworm "^0.7.0" - glob "^7.0.4" - http-proxy "^1.13.1" - js-yaml "^3.2.5" - lodash.assignin "^4.1.0" - lodash.clonedeep "^4.4.1" - lodash.find "^4.5.1" - lodash.uniqby "^4.7.0" - mkdirp "^0.5.1" - mustache "^2.2.1" - node-notifier "^5.0.1" - npmlog "^4.0.0" - printf "^0.2.3" - rimraf "^2.4.4" - socket.io "1.6.0" - spawn-args "^0.2.0" - styled_string "0.0.1" - tap-parser "^5.1.0" - xmldom "^0.1.19" - text-table@~0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" From 2090d02d2da41937530c2cafd2fb131c889979d3 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 28 Apr 2017 16:27:30 -0400 Subject: [PATCH 1920/2527] Bump version 2.15.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e13c7e97092..86ff3317782 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.14.0-canary", + "version": "2.15.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From 7e2f78bf78049b5dd42d15d72a4b501ea182d7b7 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 28 Apr 2017 16:29:21 -0400 Subject: [PATCH 1921/2527] Backport 2.13.0 changelog entry to master --- CHANGELOG.md | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9414941d651..48b4e84f8aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,77 @@ ### Master + +### Release 2.13.0 (April 28, 2017) +- [#4860](https://github.com/emberjs/data/pull/4860) Refactor the detection / warnings around ember-cli-shims. +- [#4853](https://github.com/emberjs/data/pull/4853) [Fixes #4853] use Object.create(null) directly +- [#4858](https://github.com/emberjs/data/pull/4858) [PERF] let GUID_KEYS just be set on the model instances +- [#4937](https://github.com/emberjs/data/pull/4937) [BUGFIX beta] Update dependencies to use Babel 6 +- [#4922](https://github.com/emberjs/data/pull/4922) [BUGFIX release] restore internalModels GUID_KEY’s +- [#4916](https://github.com/emberjs/data/pull/4916) [BACKPORT 4913] don't prematurely nullify props on the container-inst… +- [#4862](https://github.com/emberjs/data/pull/4862) [BETA] Update dependencies to use babel 6. +- [#4877](https://github.com/emberjs/data/pull/4877) [BUGFIX beta] ensure the globals build has the correct context in the iife. +- [#4879](https://github.com/emberjs/data/pull/4879) [BUGFIX beta] ensure context is applied in iife +- [#4767](https://github.com/emberjs/data/pull/4767) Updating gitignore to remove .idea +- [#4741](https://github.com/emberjs/data/pull/4741) Clean up some YUIdoc erros +- [#4693](https://github.com/emberjs/data/pull/4693) Fixed modelFor documentation. Look up model's class name (#4693) +- [#4719](https://github.com/emberjs/data/pull/4719) [DOC release] Add note to embedded records mixin (#4719) +- [#4723](https://github.com/emberjs/data/pull/4723) Simplify Backburner Usage (#4723) +- [#4715](https://github.com/emberjs/data/pull/4715) converts Snapshot to an es6 class instead of using prototype assign +- [#4728](https://github.com/emberjs/data/pull/4728) [CLEANUP beta] Linter changes for addon, addon/adapters and addon/serializers +- [#4708](https://github.com/emberjs/data/pull/4708) es6 RecordArrayManager +- [#4657](https://github.com/emberjs/data/pull/4657) Deprecate unused initializers +- [#4593](https://github.com/emberjs/data/pull/4593) Free up `internalModel`s +- [#4729](https://github.com/emberjs/data/pull/4729) [CLEANUP Beta] Linter changes for addon/-private (not -private/system) +- [#4730](https://github.com/emberjs/data/pull/4730) [CLEANUP Beta] Linter changes for addon/-private/system +- [#4799](https://github.com/emberjs/data/pull/4799) [DOC] Add Ember imports and use lets in adapter examples +- [#4760](https://github.com/emberjs/data/pull/4760) Update deprecate arguments (#4760) +- [#4743](https://github.com/emberjs/data/pull/4743) [BUGFIX canary] Fix _lookupFactory deprecation for Ember canary +- [#4747](https://github.com/emberjs/data/pull/4747) Updates code sample to match Guides +- [#4750](https://github.com/emberjs/data/pull/4750) Add a yarn lock file +- [#4745](https://github.com/emberjs/data/pull/4745) License: 2017 +- [#4808](https://github.com/emberjs/data/pull/4808) Avoid mutating model factory in _modelForMixin. +- [#4772](https://github.com/emberjs/data/pull/4772) [DOC] Shorthand method syntax, quotes, and cleanup +- [#4766](https://github.com/emberjs/data/pull/4766) [DOC] Update store.unloadRecord description +- [#4763](https://github.com/emberjs/data/pull/4763) Document cache/request behavior of `query` #4733 (#4763) +- [#4771](https://github.com/emberjs/data/pull/4771) [BUGFIX beta] Ensure ISO-8601 regex correctly matches timestamps (#4771) +- [#4765](https://github.com/emberjs/data/pull/4765) [DOC] Make model.unloadRecord public (#4765) +- [#4762](https://github.com/emberjs/data/pull/4762) [DOC] - add bower install to README +- [#4769](https://github.com/emberjs/data/pull/4769) [DOC release] Add missing docs for `preload` option. +- [#4815](https://github.com/emberjs/data/pull/4815) More Cleanups +- [#4780](https://github.com/emberjs/data/pull/4780) [DOC] shorthand method and quotes/semicolons for serializers/json +- [#4778](https://github.com/emberjs/data/pull/4778) [DOC] shorthand methods and quotes for json-api serializer (#4778) +- [#4775](https://github.com/emberjs/data/pull/4775) [DOC] shorthand methods for transform +- [#4774](https://github.com/emberjs/data/pull/4774) [DOC] Shorthand method fixes in adapter +- [#4776](https://github.com/emberjs/data/pull/4776) [DOC] shorthand method fixes for serializer +- [#4777](https://github.com/emberjs/data/pull/4777) [DOC] shorthand method in attr +- [#4832](https://github.com/emberjs/data/pull/4832) remove isPrimaryType’s reliance on modelName (#4832) +- [#4794](https://github.com/emberjs/data/pull/4794) Fix spelling error in documentation +- [#4782](https://github.com/emberjs/data/pull/4782) [DOC] shorthand methods and quotes for adapter errors +- [#4781](https://github.com/emberjs/data/pull/4781) [DOC] shorthand method and quotes fro serializers/rest +- [#4789](https://github.com/emberjs/data/pull/4789) Do not access container if Ember.getOwner exists. +- [#4790](https://github.com/emberjs/data/pull/4790) Add a test for #4770 +- [#4783](https://github.com/emberjs/data/pull/4783) [DOC] shorthand methods for rest adapter +- [#4837](https://github.com/emberjs/data/pull/4837) Stefs cleanup (#4837) +- [#4810](https://github.com/emberjs/data/pull/4810) [Fixes #4807] realize class + factory seperation +- [#4809](https://github.com/emberjs/data/pull/4809) bump ember-cli +- [#4805](https://github.com/emberjs/data/pull/4805) Don’t redefine findPossibleInverses for each _findInverseFor +- [#4806](https://github.com/emberjs/data/pull/4806) Added missing DS references to DS.Model implementation examples +- [#4798](https://github.com/emberjs/data/pull/4798) [DOC] Cleanup example code in attr +- [#4841](https://github.com/emberjs/data/pull/4841) Cleanup (#4841) +- [#4830](https://github.com/emberjs/data/pull/4830) don’t create extra internal promise objects +- [#4823](https://github.com/emberjs/data/pull/4823) [BUGFIX] ensure all of DS is initialized together +- [#4813](https://github.com/emberjs/data/pull/4813) misc cleanup (#4813) +- [#4818](https://github.com/emberjs/data/pull/4818) remove more unneeded class reification +- [#4831](https://github.com/emberjs/data/pull/4831) Cleanup things and stuff (#4831) +- [#4836](https://github.com/emberjs/data/pull/4836) cleanup + reject with useful reasons +- [#4838](https://github.com/emberjs/data/pull/4838) Stefs cleanup (and some test suite memory leak fixes) (#4838) +- [#4840](https://github.com/emberjs/data/pull/4840) [DOC] Fix markup for example code of `DS.Model#inverseFor` +- [#4842](https://github.com/emberjs/data/pull/4842) Stable has many promise proxy (#4842) +- [#4846](https://github.com/emberjs/data/pull/4846) remove un-needed Ember.A +- [#4850](https://github.com/emberjs/data/pull/4850) Optimise has many notifications (#4850) +- [#4851](https://github.com/emberjs/data/pull/4851) Don't calculate `_changedKeys` pointlessly (#4851) + ### Release 2.12.2 (April 12, 2017) - [#4922](https://github.com/emberjs/data/pull/4922) [BUGFIX release] restore internalModels GUID_KEY’s - [#4917](https://github.com/emberjs/data/pull/4917) [BACKPORT 4913] For release From 2b73e70e6b31e1906356d17d2b327654113c1201 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Sat, 29 Apr 2017 12:53:32 -0700 Subject: [PATCH 1922/2527] [BUGFIX] remove forgotten broccoli-stew import --- index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/index.js b/index.js index ed4474cf9d0..973dbc3a77f 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,6 @@ var path = require('path'); var SilentError = require('silent-error'); var Funnel = require('broccoli-funnel'); var Rollup = require('broccoli-rollup'); -var stew = require('broccoli-stew'); var Babel = require('broccoli-babel-transpiler'); var merge = require('broccoli-merge-trees'); var version = require('./lib/version'); From a7cf5b77a3b156b846e5926de60f047951e9fca4 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Sat, 29 Apr 2017 13:47:49 -0700 Subject: [PATCH 1923/2527] ensure we don't transpile typeof checks poorly --- index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/index.js b/index.js index ed4474cf9d0..ff0ed05d1b2 100644 --- a/index.js +++ b/index.js @@ -177,6 +177,7 @@ module.exports = { postTransformPlugins: customPlugins.postTransformPlugins, exclude: [ 'transform-es2015-block-scoping', + 'transform-es2015-typeof-symbol' ] }; }, From 7de36935d02584e17811bce7587d71255196fc2d Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Sun, 30 Apr 2017 09:36:16 -0700 Subject: [PATCH 1924/2527] show drift --- yarn-error.log | 6390 ++++++++++++++++++++++++++++++++++++++++++++++++ yarn.lock | 330 ++- 2 files changed, 6609 insertions(+), 111 deletions(-) create mode 100644 yarn-error.log diff --git a/yarn-error.log b/yarn-error.log new file mode 100644 index 00000000000..4e717490188 --- /dev/null +++ b/yarn-error.log @@ -0,0 +1,6390 @@ +Arguments: + /Users/cthoburn/.nvm/versions/node/v7.4.0/bin/node /Users/cthoburn/.nvm/versions/node/v7.4.0/bin/yarn upgrade + +PATH: + /Users/cthoburn/.nvm/versions/node/v7.4.0/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/linkedin/bin:/opt/X11/bin:/export/content/linkedin/bin:/Users/cthoburn/.yarn/bin + +Yarn version: + 0.22.0 + +Node version: + 7.4.0 + +Platform: + darwin x64 + +npm manifest: + { + "name": "ember-data", + "version": "2.15.0-canary", + "description": "A data layer for your Ember applications.", + "repository": "git://github.com/emberjs/data.git", + "directories": { + "doc": "doc", + "test": "tests" + }, + "scripts": { + "build": "ember build", + "start": "ember server", + "test": "ember try:testall", + "node-tests": "node node-tests/nodetest-runner.js", + "test:optional-features": "ember test --environment=test-optional-features", + "test:production": "ember test --environment=production", + "bower": "bower install", + "production": "ember build --environment=production" + }, + "author": "", + "license": "MIT", + "dependencies": { + "amd-name-resolver": "0.0.5", + "babel-plugin-feature-flags": "^0.3.1", + "babel-plugin-filter-imports": "^0.3.1", + "babel6-plugin-strip-class-callcheck": "^6.0.0", + "babel6-plugin-strip-heimdall": "^6.0.1", + "broccoli-babel-transpiler": "^6.0.0", + "broccoli-file-creator": "^1.0.0", + "broccoli-funnel": "^1.2.0", + "broccoli-merge-trees": "^1.0.0", + "broccoli-rollup": "^1.2.0", + "chalk": "^1.1.1", + "ember-cli-babel": "^6.0.0-beta.10", + "ember-cli-path-utils": "^1.0.0", + "ember-cli-string-utils": "^1.0.0", + "ember-cli-test-info": "^1.0.0", + "ember-cli-version-checker": "^1.1.4", + "ember-inflector": "^2.0.0", + "ember-runtime-enumerable-includes-polyfill": "^2.0.0", + "exists-sync": "0.0.3", + "git-repo-info": "^1.1.2", + "heimdalljs": "^0.3.0", + "inflection": "^1.8.0", + "npm-git-info": "^1.0.0", + "semver": "^5.1.0", + "silent-error": "^1.0.0", + "testem": "1.15.0" + }, + "devDependencies": { + "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoping": "^6.24.1", + "babel-plugin-transform-es2015-classes": "^6.23.0", + "babel-plugin-transform-es2015-computed-properties": "^6.22.0", + "babel-plugin-transform-es2015-constants": "^6.1.4", + "babel-plugin-transform-es2015-destructuring": "^6.23.0", + "babel-plugin-transform-es2015-modules-amd": "^6.24.0", + "babel-plugin-transform-es2015-parameters": "^6.23.0", + "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", + "bower": "^1.6.5", + "broccoli-asset-rev": "^2.4.5", + "broccoli-concat": "^3.2.2", + "broccoli-stew": "^1.4.2", + "broccoli-string-replace": "^0.1.1", + "broccoli-uglify-sourcemap": "^1.0.1", + "broccoli-yuidoc": "^2.1.0", + "ember-ajax": "^2.4.1", + "ember-cli": "^2.11.1", + "ember-cli-app-version": "^2.0.0", + "ember-cli-blueprint-test-helpers": "0.11.0", + "ember-cli-dependency-checker": "^1.3.0", + "ember-cli-eslint": "1.3.0", + "ember-cli-htmlbars": "^1.1.1", + "ember-cli-htmlbars-inline-precompile": "^0.4.0-beta.2", + "ember-cli-inject-live-reload": "^1.4.1", + "ember-cli-internal-test-helpers": "^0.8.1", + "ember-cli-pretender": "^1.0.1", + "ember-cli-qunit": "^2.1.0", + "ember-cli-release": "^0.2.9", + "ember-cli-shims": "^1.0.2", + "ember-cli-sri": "^2.1.0", + "ember-cli-test-loader": "^1.1.0", + "ember-cli-uglify": "^1.2.0", + "ember-dev": "emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed", + "ember-disable-prototype-extensions": "^1.1.0", + "ember-disable-proxy-controllers": "^1.0.0", + "ember-export-application-global": "^1.0.5", + "ember-load-initializers": "^0.6.0", + "ember-publisher": "0.0.7", + "ember-resolver": "^2.0.3", + "ember-source": "~2.11.0", + "ember-watson": "^0.7.0", + "express": "^4.14.0", + "faker": "^3.1.0", + "github": "^1.1.1", + "glob": "5.0.13", + "heimdall-query": "^0.0.5", + "json-api-mock-server": "0.1.1", + "loader.js": "^4.2.2", + "mocha": "2.4.5", + "mocha-only-detector": "0.0.2", + "morgan": "^1.7.0", + "phantomjs-prebuilt": "^2.1.12", + "pretender": "1.0.0", + "rimraf": "2.5.2", + "rsvp": "3.2.1" + }, + "peerDependencies": { + "ember-inflector": "^2.0.0" + }, + "engines": { + "node": ">= 0.12.0" + }, + "keywords": [ + "ember-addon" + ], + "ember-addon": { + "configPath": "tests/dummy/config", + "paths": [ + "lib/enable-optional-features-via-url" + ], + "after": "ember-cli-mocha" + } + } + +yarn manifest: + No manifest + +Lockfile: + # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + # yarn lockfile v1 + + + "@types/node@*", "@types/node@^7.0.5": + version "7.0.13" + resolved "https://registry.npmjs.org/@types/node/-/node-7.0.13.tgz#1b0a53fe9ef9c3a5d061b126cc9b915bca43a3f5" + + "@types/rimraf@^0.0.28": + version "0.0.28" + resolved "https://registry.npmjs.org/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06" + + "@types/tape@^4.2.29": + version "4.2.29" + resolved "https://registry.npmjs.org/@types/tape/-/tape-4.2.29.tgz#14cf2eb49bf852407eaaefdc53773eb90b32cf56" + dependencies: + "@types/node" "*" + + "@types/ws@^0.0.38": + version "0.0.38" + resolved "https://registry.npmjs.org/@types/ws/-/ws-0.0.38.tgz#42106fff4b422ca956734e29f0d73a6d893194d3" + dependencies: + "@types/node" "*" + + abbrev@1: + version "1.1.0" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" + + accepts@1.3.3, accepts@~1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + dependencies: + mime-types "~2.1.11" + negotiator "0.6.1" + + acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + + acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + + acorn@^4.0.3: + version "4.0.11" + resolved "https://registry.npmjs.org/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0" + + acorn@^5.0.1: + version "5.0.3" + resolved "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d" + + adm-zip@^0.4.7: + version "0.4.7" + resolved "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" + + after@0.8.1: + version "0.8.1" + resolved "https://registry.npmjs.org/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" + + agent-base@2: + version "2.0.1" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz#bd8f9e86a8eb221fffa07bd14befd55df142815e" + dependencies: + extend "~3.0.0" + semver "~5.0.1" + + ajv-keywords@^1.0.0: + version "1.5.1" + resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" + + ajv@^4.1.3, ajv@^4.7.0: + version "4.11.7" + resolved "https://registry.npmjs.org/ajv/-/ajv-4.11.7.tgz#8655a5d86d0824985cc471a1d913fb6729a0ec48" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + + align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + + alter@~0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" + dependencies: + stable "~0.1.3" + + amd-name-resolver@0.0.5: + version "0.0.5" + resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.5.tgz#76962dac876ed3311b05d29c6a58c14e1ef3304b" + dependencies: + ensure-posix-path "^1.0.1" + + amd-name-resolver@0.0.6: + version "0.0.6" + resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.6.tgz#d3e4ba2dfcaab1d820c1be9de947c67828cfe595" + dependencies: + ensure-posix-path "^1.0.1" + + amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + + ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + + ansi-regex@^0.2.0, ansi-regex@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" + + ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + + ansi-styles@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" + + ansi-styles@^2.1.0, ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + + ansicolors@~0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" + + anymatch@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + dependencies: + arrify "^1.0.0" + micromatch "^2.1.5" + + aproba@^1.0.3: + version "1.1.1" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" + + are-we-there-yet@~1.1.2: + version "1.1.4" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + + argparse@^1.0.7, argparse@~1.0.2: + version "1.0.9" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + + arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + + arr-flatten@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.3.tgz#a274ed85ac08849b6bd7847c4580745dc51adfb1" + + array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + + array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + + array-to-error@^1.0.0: + version "1.1.1" + resolved "https://registry.npmjs.org/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" + dependencies: + array-to-sentence "^1.1.0" + + array-to-sentence@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" + + array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + + array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + + array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + + arraybuffer.slice@0.0.6: + version "0.0.6" + resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" + + arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + + asn1@0.1.11: + version "0.1.11" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" + + asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + + assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + + assert-plus@^0.1.5: + version "0.1.5" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" + + assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + + assertion-error@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" + + ast-traverse@~0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" + + ast-types@0.8.12: + version "0.8.12" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" + + ast-types@0.8.15: + version "0.8.15" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" + + ast-types@0.9.6: + version "0.9.6" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" + + async-disk-cache@^1.0.0: + version "1.3.1" + resolved "https://registry.npmjs.org/async-disk-cache/-/async-disk-cache-1.3.1.tgz#3394010d9448b16205b01e0e2e704180805413d3" + dependencies: + debug "^2.1.3" + heimdalljs "^0.2.3" + istextorbinary "2.1.0" + mkdirp "^0.5.0" + rimraf "^2.5.3" + rsvp "^3.0.18" + + async@^1.4.0, async@^1.5.2: + version "1.5.2" + resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + + async@~0.2.9: + version "0.2.10" + resolved "https://registry.npmjs.org/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + + async@~0.9.0: + version "0.9.2" + resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + + asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + + aws-sdk@^2.0.9: + version "2.45.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.45.0.tgz#045dbd323630170968306dc849d793dbb1e4444d" + dependencies: + buffer "4.9.1" + crypto-browserify "1.0.9" + jmespath "0.15.0" + querystring "0.2.0" + sax "1.2.1" + url "0.10.3" + uuid "3.0.1" + xml2js "0.4.17" + xmlbuilder "4.2.1" + + aws-sign2@~0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" + + aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + + aws4@^1.2.1: + version "1.6.0" + resolved "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + + babel-code-frame@^6.22.0: + version "6.22.0" + resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" + dependencies: + chalk "^1.1.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + + babel-core@^5.0.0, babel-core@^5.8.22: + version "5.8.38" + resolved "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" + dependencies: + babel-plugin-constant-folding "^1.0.1" + babel-plugin-dead-code-elimination "^1.0.2" + babel-plugin-eval "^1.0.1" + babel-plugin-inline-environment-variables "^1.0.1" + babel-plugin-jscript "^1.0.4" + babel-plugin-member-expression-literals "^1.0.1" + babel-plugin-property-literals "^1.0.1" + babel-plugin-proto-to-assign "^1.0.3" + babel-plugin-react-constant-elements "^1.0.3" + babel-plugin-react-display-name "^1.0.3" + babel-plugin-remove-console "^1.0.1" + babel-plugin-remove-debugger "^1.0.1" + babel-plugin-runtime "^1.0.7" + babel-plugin-undeclared-variables-check "^1.0.2" + babel-plugin-undefined-to-void "^1.1.6" + babylon "^5.8.38" + bluebird "^2.9.33" + chalk "^1.0.0" + convert-source-map "^1.1.0" + core-js "^1.0.0" + debug "^2.1.1" + detect-indent "^3.0.0" + esutils "^2.0.0" + fs-readdir-recursive "^0.1.0" + globals "^6.4.0" + home-or-tmp "^1.0.0" + is-integer "^1.0.4" + js-tokens "1.0.1" + json5 "^0.4.0" + lodash "^3.10.0" + minimatch "^2.0.3" + output-file-sync "^1.1.0" + path-exists "^1.0.0" + path-is-absolute "^1.0.0" + private "^0.1.6" + regenerator "0.8.40" + regexpu "^1.3.0" + repeating "^1.1.2" + resolve "^1.1.6" + shebang-regex "^1.0.0" + slash "^1.0.0" + source-map "^0.5.0" + source-map-support "^0.2.10" + to-fast-properties "^1.0.0" + trim-right "^1.0.0" + try-resolve "^1.0.0" + + babel-core@^6.14.0, babel-core@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-core/-/babel-core-6.24.1.tgz#8c428564dce1e1f41fb337ec34f4c3b022b5ad83" + dependencies: + babel-code-frame "^6.22.0" + babel-generator "^6.24.1" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + babylon "^6.11.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.5.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-is-absolute "^1.0.0" + private "^0.1.6" + slash "^1.0.0" + source-map "^0.5.0" + + babel-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-generator/-/babel-generator-6.24.1.tgz#e715f486c58ded25649d888944d52aa07c5d9497" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.2.0" + source-map "^0.5.0" + trim-right "^1.0.1" + + babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + + babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + + babel-helper-define-map@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.24.1.tgz#7a9747f258d8947d32d515f6aa1c7bd02204a080" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + lodash "^4.2.0" + + babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + + babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + + babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + + babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + + babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + + babel-helper-regex@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.24.1.tgz#d36e22fab1008d79d88648e32116868128456ce8" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + lodash "^4.2.0" + + babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + + babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + + babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + + babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + + babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + + babel-plugin-constant-folding@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" + + babel-plugin-dead-code-elimination@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" + + babel-plugin-eval@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" + + babel-plugin-feature-flags@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" + + babel-plugin-filter-imports@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.3.1.tgz#e7859b56886b175dd2616425d277b219e209ea8b" + + babel-plugin-htmlbars-inline-precompile@^0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.3.tgz#cd365e278af409bfa6be7704c4354beee742446b" + + babel-plugin-inline-environment-variables@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" + + babel-plugin-jscript@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" + + babel-plugin-member-expression-literals@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" + + babel-plugin-property-literals@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" + + babel-plugin-proto-to-assign@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" + dependencies: + lodash "^3.9.3" + + babel-plugin-react-constant-elements@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" + + babel-plugin-react-display-name@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" + + babel-plugin-remove-console@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" + + babel-plugin-remove-debugger@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" + + babel-plugin-runtime@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" + + babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + + babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + + babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + + babel-plugin-transform-async-to-generator@^6.22.0: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + + babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + + babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + + babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz#76c295dc3a4741b1665adfd3167215dcff32a576" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + lodash "^4.2.0" + + babel-plugin-transform-es2015-classes@^6.23.0: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + + babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + + babel-plugin-transform-es2015-constants@^6.1.4: + version "6.1.4" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-constants/-/babel-plugin-transform-es2015-constants-6.1.4.tgz#e4b8c78fb48ab98b0107f329fab6040e79c35a33" + dependencies: + babel-runtime "^5.0.0" + + babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + + babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + + babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + + babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + + babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + + babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + + babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.1.tgz#d3e310b40ef664a36622200097c6d440298f2bfe" + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-types "^6.24.1" + + babel-plugin-transform-es2015-modules-systemjs@^6.23.0: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + + babel-plugin-transform-es2015-modules-umd@^6.23.0: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + + babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + + babel-plugin-transform-es2015-parameters@^6.23.0: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + + babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + + babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + + babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + + babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + + babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + + babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + + babel-plugin-transform-exponentiation-operator@^6.22.0: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + + babel-plugin-transform-regenerator@^6.22.0: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz#b8da305ad43c3c99b4848e4fe4037b770d23c418" + dependencies: + regenerator-transform "0.9.11" + + babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + + babel-plugin-undeclared-variables-check@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" + dependencies: + leven "^1.0.2" + + babel-plugin-undefined-to-void@^1.1.6: + version "1.1.6" + resolved "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" + + babel-polyfill@^6.16.0: + version "6.23.0" + resolved "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d" + dependencies: + babel-runtime "^6.22.0" + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + + babel-preset-env@^1.2.0: + version "1.4.0" + resolved "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.4.0.tgz#c8e02a3bcc7792f23cded68e0355b9d4c28f0f7a" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^1.4.0" + invariant "^2.2.2" + + babel-register@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-register/-/babel-register-6.24.1.tgz#7e10e13a2f71065bdfad5a1787ba45bca6ded75f" + dependencies: + babel-core "^6.24.1" + babel-runtime "^6.22.0" + core-js "^2.4.0" + home-or-tmp "^2.0.0" + lodash "^4.2.0" + mkdirp "^0.5.1" + source-map-support "^0.4.2" + + babel-runtime@^5.0.0: + version "5.8.38" + resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz#1c0b02eb63312f5f087ff20450827b425c9d4c19" + dependencies: + core-js "^1.0.0" + + babel-runtime@^6.18.0, babel-runtime@^6.22.0: + version "6.23.0" + resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + + babel-template@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-template/-/babel-template-6.24.1.tgz#04ae514f1f93b3a2537f2a0f60a5a45fb8308333" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + babylon "^6.11.0" + lodash "^4.2.0" + + babel-traverse@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.24.1.tgz#ab36673fd356f9a0948659e7b338d5feadb31695" + dependencies: + babel-code-frame "^6.22.0" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + babylon "^6.15.0" + debug "^2.2.0" + globals "^9.0.0" + invariant "^2.2.0" + lodash "^4.2.0" + + babel-types@^6.19.0, babel-types@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-types/-/babel-types-6.24.1.tgz#a136879dc15b3606bda0d90c1fc74304c2ff0975" + dependencies: + babel-runtime "^6.22.0" + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^1.0.1" + + babel6-plugin-strip-class-callcheck@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" + + babel6-plugin-strip-heimdall@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" + + babylon@^5.8.38: + version "5.8.38" + resolved "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" + + babylon@^6.11.0, babylon@^6.15.0: + version "6.17.0" + resolved "https://registry.npmjs.org/babylon/-/babylon-6.17.0.tgz#37da948878488b9c4e3c4038893fa3314b3fc932" + + backbone@^1.1.2: + version "1.3.3" + resolved "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" + dependencies: + underscore ">=1.8.3" + + backo2@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + + balanced-match@^0.4.1: + version "0.4.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + + base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + + base64-js@^1.0.2: + version "1.2.0" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + + base64id@0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" + + basic-auth@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" + + bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + + better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + dependencies: + callsite "1.0.0" + + "binaryextensions@1 || 2": + version "2.0.0" + resolved "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.0.0.tgz#e597d1a7a6a3558a2d1c7241a16c99965e6aa40f" + + blank-object@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" + + blob@0.0.4: + version "0.0.4" + resolved "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" + + bluebird@^2.9.33: + version "2.11.0" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" + + bluebird@^3.1.1, bluebird@^3.4.6: + version "3.5.0" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" + + body-parser@^1.15.2: + version "1.17.1" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.17.1.tgz#75b3bc98ddd6e7e0d8ffe750dfaca5c66993fa47" + dependencies: + bytes "2.4.0" + content-type "~1.0.2" + debug "2.6.1" + depd "~1.1.0" + http-errors "~1.6.1" + iconv-lite "0.4.15" + on-finished "~2.3.0" + qs "6.4.0" + raw-body "~2.2.0" + type-is "~1.6.14" + + body@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" + dependencies: + continuable-cache "^0.3.1" + error "^7.0.0" + raw-body "~1.1.0" + safe-json-parse "~1.0.1" + + boom@0.4.x: + version "0.4.2" + resolved "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" + dependencies: + hoek "0.9.x" + + boom@2.x.x: + version "2.10.1" + resolved "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + + bower-config@^1.3.0: + version "1.4.0" + resolved "https://registry.npmjs.org/bower-config/-/bower-config-1.4.0.tgz#16c38c1135f8071c19f25938d61b0d8cbf18d3f1" + dependencies: + graceful-fs "^4.1.3" + mout "^1.0.0" + optimist "^0.6.1" + osenv "^0.1.3" + untildify "^2.1.0" + + bower-endpoint-parser@0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" + + bower@^1.6.5: + version "1.8.0" + resolved "https://registry.npmjs.org/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a" + + brace-expansion@^1.0.0: + version "1.1.7" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" + dependencies: + balanced-match "^0.4.1" + concat-map "0.0.1" + + braces@^1.8.2: + version "1.8.5" + resolved "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + + breakable@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" + + broccoli-asset-rev@^2.4.5: + version "2.5.0" + resolved "https://registry.npmjs.org/broccoli-asset-rev/-/broccoli-asset-rev-2.5.0.tgz#f5f66eac962bf9f086286921f0eaeaab6d00d819" + dependencies: + broccoli-asset-rewrite "^1.1.0" + broccoli-filter "^1.2.2" + json-stable-stringify "^1.0.0" + matcher-collection "^1.0.1" + rsvp "^3.0.6" + + broccoli-asset-rewrite@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" + dependencies: + broccoli-filter "^1.2.3" + + broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: + version "5.6.2" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.6.2.tgz#958c72e43575b2f0a862a5096dba1ce1ebc7d74d" + dependencies: + babel-core "^5.0.0" + broccoli-funnel "^1.0.0" + broccoli-merge-trees "^1.0.0" + broccoli-persistent-filter "^1.0.1" + clone "^0.2.0" + hash-for-dep "^1.0.2" + json-stable-stringify "^1.0.0" + + broccoli-babel-transpiler@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.0.0.tgz#a52c5404bf36236849da503b011fd41fe64a00a2" + dependencies: + babel-core "^6.14.0" + broccoli-funnel "^1.0.0" + broccoli-merge-trees "^1.0.0" + broccoli-persistent-filter "^1.0.1" + clone "^2.0.0" + hash-for-dep "^1.0.2" + json-stable-stringify "^1.0.0" + + broccoli-brocfile-loader@^0.18.0: + version "0.18.0" + resolved "https://registry.npmjs.org/broccoli-brocfile-loader/-/broccoli-brocfile-loader-0.18.0.tgz#2e86021c805c34ffc8d29a2fb721cf273e819e4b" + dependencies: + findup-sync "^0.4.2" + + broccoli-builder@^0.18.3: + version "0.18.4" + resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.4.tgz#abc6db2c07d214454918e2997ea87441b69b69d3" + dependencies: + heimdalljs "^0.2.0" + promise-map-series "^0.2.1" + quick-temp "^0.1.2" + rimraf "^2.2.8" + rsvp "^3.0.17" + silent-error "^1.0.1" + + broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.1: + version "2.0.4" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" + dependencies: + broccoli-kitchen-sink-helpers "^0.2.5" + broccoli-plugin "1.1.0" + debug "^2.1.1" + lodash-node "^3.2.0" + rimraf "^2.2.8" + rsvp "^3.0.17" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" + + broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" + dependencies: + broccoli-kitchen-sink-helpers "^0.2.5" + broccoli-plugin "1.1.0" + debug "^2.1.1" + rimraf "^2.2.8" + rsvp "^3.0.17" + walk-sync "^0.2.5" + + broccoli-clean-css@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" + dependencies: + broccoli-persistent-filter "^1.1.6" + clean-css-promise "^0.1.0" + inline-source-map-comment "^1.0.5" + json-stable-stringify "^1.0.0" + + broccoli-concat@^2.2.0: + version "2.3.8" + resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-2.3.8.tgz#590cdcc021bb905b6c121d87c2d1d57df44a2a48" + dependencies: + broccoli-caching-writer "^2.3.1" + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-stew "^1.3.3" + fast-sourcemap-concat "^1.0.1" + fs-extra "^0.30.0" + lodash.merge "^4.3.0" + lodash.omit "^4.1.0" + lodash.uniq "^4.2.0" + + broccoli-concat@^3.0.4, broccoli-concat@^3.2.2: + version "3.2.2" + resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-plugin "^1.3.0" + broccoli-stew "^1.3.3" + ensure-posix-path "^1.0.2" + fast-sourcemap-concat "^1.0.1" + find-index "^1.1.0" + fs-extra "^1.0.0" + fs-tree-diff "^0.5.6" + lodash.merge "^4.3.0" + lodash.omit "^4.1.0" + lodash.uniq "^4.2.0" + walk-sync "^0.3.1" + + broccoli-config-loader@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/broccoli-config-loader/-/broccoli-config-loader-1.0.0.tgz#c3cf5ecfaffc04338c6f1d5d38dc36baeaa131ba" + dependencies: + broccoli-caching-writer "^2.0.4" + + broccoli-config-replace@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-plugin "^1.2.0" + debug "^2.2.0" + fs-extra "^0.24.0" + + broccoli-file-creator@^1.0.0: + version "1.1.1" + resolved "https://registry.npmjs.org/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" + dependencies: + broccoli-kitchen-sink-helpers "~0.2.0" + broccoli-plugin "^1.1.0" + broccoli-writer "~0.1.1" + mkdirp "^0.5.1" + rsvp "~3.0.6" + symlink-or-copy "^1.0.1" + + broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: + version "1.2.4" + resolved "https://registry.npmjs.org/broccoli-filter/-/broccoli-filter-1.2.4.tgz#409afb94b9a3a6da9fac8134e91e205f40cc7330" + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-plugin "^1.0.0" + copy-dereference "^1.0.0" + debug "^2.2.0" + mkdirp "^0.5.1" + promise-map-series "^0.2.1" + rsvp "^3.0.18" + symlink-or-copy "^1.0.1" + walk-sync "^0.3.1" + + broccoli-funnel-reducer@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" + + broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli-funnel@^1.1.0, broccoli-funnel@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" + dependencies: + array-equal "^1.0.0" + blank-object "^1.0.1" + broccoli-plugin "^1.3.0" + debug "^2.2.0" + exists-sync "0.0.4" + fast-ordered-set "^1.0.0" + fs-tree-diff "^0.5.3" + heimdalljs "^0.2.0" + minimatch "^3.0.0" + mkdirp "^0.5.0" + path-posix "^1.0.0" + rimraf "^2.4.3" + symlink-or-copy "^1.0.0" + walk-sync "^0.3.1" + + broccoli-kitchen-sink-helpers@^0.2.5, broccoli-kitchen-sink-helpers@~0.2.0: + version "0.2.9" + resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" + dependencies: + glob "^5.0.10" + mkdirp "^0.5.1" + + broccoli-kitchen-sink-helpers@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" + dependencies: + glob "^5.0.10" + mkdirp "^0.5.1" + + broccoli-lint-eslint@^2.0.0: + version "2.7.0" + resolved "https://registry.npmjs.org/broccoli-lint-eslint/-/broccoli-lint-eslint-2.7.0.tgz#a2d905d02b397a90ae82439f283c459ef819f140" + dependencies: + broccoli-persistent-filter "^1.2.0" + escape-string-regexp "^1.0.5" + eslint "^2.13.0" + js-string-escape "^1.0.1" + json-stable-stringify "^1.0.1" + md5-hex "^1.2.1" + + broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^1.1.3, broccoli-merge-trees@^1.1.4, broccoli-merge-trees@^1.2.1: + version "1.2.4" + resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" + dependencies: + broccoli-plugin "^1.3.0" + can-symlink "^1.0.0" + fast-ordered-set "^1.0.2" + fs-tree-diff "^0.5.4" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + rimraf "^2.4.3" + symlink-or-copy "^1.0.0" + + broccoli-merge-trees@~0.2.3: + version "0.2.4" + resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-0.2.4.tgz#1936f63bb09e24246b1e91d8c53162c0f7b24c3c" + dependencies: + broccoli-plugin "^1.0.0" + debug "^2.2.0" + symlink-or-copy "^1.0.0" + + broccoli-middleware@^1.0.0-beta.8: + version "1.0.0-beta.8" + resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-1.0.0-beta.8.tgz#89cb6a9950ff0cf5bd75071d83d7cd6f6a11a95b" + dependencies: + handlebars "^4.0.4" + mime "^1.2.11" + + broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0: + version "1.2.13" + resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.2.13.tgz#61368669e2b8f35238fdd38a2a896597e4a1c821" + dependencies: + async-disk-cache "^1.0.0" + blank-object "^1.0.1" + broccoli-plugin "^1.0.0" + fs-tree-diff "^0.5.2" + hash-for-dep "^1.0.2" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + md5-hex "^1.0.2" + mkdirp "^0.5.1" + promise-map-series "^0.2.1" + rsvp "^3.0.18" + symlink-or-copy "^1.0.1" + walk-sync "^0.3.1" + + broccoli-plugin@1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" + dependencies: + promise-map-series "^0.2.1" + quick-temp "^0.1.3" + rimraf "^2.3.4" + symlink-or-copy "^1.0.1" + + broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" + dependencies: + promise-map-series "^0.2.1" + quick-temp "^0.1.3" + rimraf "^2.3.4" + symlink-or-copy "^1.1.8" + + broccoli-rollup@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/broccoli-rollup/-/broccoli-rollup-1.2.0.tgz#627636c05837d894a85724ef9b7ca04d12b66751" + dependencies: + broccoli-plugin "^1.2.1" + es6-map "^0.1.4" + fs-extra "^0.30.0" + fs-tree-diff "^0.5.2" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + md5-hex "^1.3.0" + node-modules-path "^1.0.1" + rollup "^0.41.4" + symlink-or-copy "^1.1.8" + walk-sync "^0.3.1" + + broccoli-slow-trees@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" + dependencies: + heimdalljs "^0.2.1" + + broccoli-source@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" + + broccoli-sri-hash@^2.1.0: + version "2.1.2" + resolved "https://registry.npmjs.org/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" + dependencies: + broccoli-caching-writer "^2.2.0" + mkdirp "^0.5.1" + rsvp "^3.1.0" + sri-toolbox "^0.2.0" + symlink-or-copy "^1.0.1" + + broccoli-stew@^1.2.0, broccoli-stew@^1.3.3, broccoli-stew@^1.4.2: + version "1.4.2" + resolved "https://registry.npmjs.org/broccoli-stew/-/broccoli-stew-1.4.2.tgz#9ec4062fd7162c6026561a2fbf64558363aff8d6" + dependencies: + broccoli-funnel "^1.0.1" + broccoli-merge-trees "^1.0.0" + broccoli-persistent-filter "^1.1.6" + broccoli-plugin "^1.3.0" + chalk "^1.1.3" + debug "^2.4.0" + ensure-posix-path "^1.0.1" + fs-extra "^2.0.0" + minimatch "^3.0.2" + resolve "^1.1.6" + rsvp "^3.0.16" + sanitize-filename "^1.5.3" + symlink-or-copy "^1.1.8" + walk-sync "^0.3.0" + + broccoli-string-replace@^0.1.1: + version "0.1.2" + resolved "https://registry.npmjs.org/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" + dependencies: + broccoli-persistent-filter "^1.1.5" + minimatch "^3.0.3" + + broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: + version "1.5.2" + resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.2.tgz#04f84ab0db539031fa868ccfa563c9932d50cedb" + dependencies: + broccoli-plugin "^1.2.1" + debug "^2.2.0" + lodash.merge "^4.5.1" + matcher-collection "^1.0.0" + mkdirp "^0.5.0" + source-map-url "^0.3.0" + symlink-or-copy "^1.0.1" + uglify-js "^2.7.0" + walk-sync "^0.1.3" + + broccoli-writer@~0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/broccoli-writer/-/broccoli-writer-0.1.1.tgz#d4d71aa8f2afbc67a3866b91a2da79084b96ab2d" + dependencies: + quick-temp "^0.1.0" + rsvp "^3.0.6" + + broccoli-yuidoc@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/broccoli-yuidoc/-/broccoli-yuidoc-2.1.0.tgz#d208d5c056e421a51f0c7701e938229e7e85c2e6" + dependencies: + broccoli-caching-writer "~2.0.1" + broccoli-merge-trees "~0.2.3" + merge "~1.2.0" + rsvp "~3.1.0" + yuidocjs "~0.9.0" + + browserslist@^1.4.0: + version "1.7.7" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" + dependencies: + caniuse-db "^1.0.30000639" + electron-to-chromium "^1.2.7" + + bser@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" + dependencies: + node-int64 "^0.4.0" + + buffer@4.9.1: + version "4.9.1" + resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + + builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + + bytes@1: + version "1.0.0" + resolved "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" + + bytes@2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" + + bytes@2.4.0: + version "2.4.0" + resolved "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" + + calculate-cache-key-for-tree@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" + dependencies: + json-stable-stringify "^1.0.1" + + caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + + callsite@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + + callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + + camelcase@^1.0.2, camelcase@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + + camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + + can-symlink@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" + dependencies: + tmp "0.0.28" + + caniuse-db@^1.0.30000639: + version "1.0.30000660" + resolved "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000660.tgz#d2d57b309dc5a11bb5b46018f51855f7a41efee5" + + capture-exit@^1.1.0: + version "1.2.0" + resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" + dependencies: + rsvp "^3.3.3" + + cardinal@^0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/cardinal/-/cardinal-0.5.0.tgz#00d5f661dbd4aabfdf7d41ce48a5a59bca35a291" + dependencies: + ansicolors "~0.2.1" + redeyed "~0.5.0" + + caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + + center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + + chai-as-promised@^5.1.0: + version "5.3.0" + resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-5.3.0.tgz#09d7a402908aa70dfdbead53e5853fc79d3ef21c" + + chai-as-promised@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" + dependencies: + check-error "^1.0.2" + + chai-files@^1.0.0, chai-files@^1.1.0: + version "1.4.0" + resolved "https://registry.npmjs.org/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" + dependencies: + assertion-error "^1.0.1" + + chai@^3.3.0: + version "3.5.0" + resolved "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" + dependencies: + assertion-error "^1.0.1" + deep-eql "^0.1.3" + type-detect "^1.0.0" + + chalk@^0.5.1: + version "0.5.1" + resolved "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" + dependencies: + ansi-styles "^1.1.0" + escape-string-regexp "^1.0.0" + has-ansi "^0.1.0" + strip-ansi "^0.3.0" + supports-color "^0.2.0" + + chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + + charm@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" + dependencies: + inherits "^2.0.1" + + check-error@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + + chrome-debugging-client@^0.2.4: + version "0.2.5" + resolved "https://registry.npmjs.org/chrome-debugging-client/-/chrome-debugging-client-0.2.5.tgz#b8e1a6c37283323b6ff5d60525f6ea1fc8899fbd" + dependencies: + "@types/node" "^7.0.5" + "@types/rimraf" "^0.0.28" + "@types/tape" "^4.2.29" + "@types/ws" "^0.0.38" + mktemp "^0.4.0" + rimraf "^2.5.1" + ws "^1.0.1" + + circular-json@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + + clean-base-url@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" + + clean-css-promise@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" + dependencies: + array-to-error "^1.0.0" + clean-css "^3.4.5" + pinkie-promise "^2.0.0" + + clean-css@^3.4.5: + version "3.4.25" + resolved "https://registry.npmjs.org/clean-css/-/clean-css-3.4.25.tgz#9e9a52d5c1e6bc5123e1b2783fa65fe958946ede" + dependencies: + commander "2.8.x" + source-map "0.4.x" + + cli-cursor@^1.0.1, cli-cursor@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + + cli-spinners@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" + + cli-table2@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" + dependencies: + lodash "^3.10.1" + string-width "^1.0.1" + optionalDependencies: + colors "^1.1.2" + + cli-table@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + dependencies: + colors "1.0.3" + + cli-width@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + + cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + + cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + + clone@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" + + clone@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" + + co@^4.6.0: + version "4.6.0" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + + code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + + colors@1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + + colors@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + + colors@~0.6.0-1: + version "0.6.2" + resolved "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" + + combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + + combined-stream@~0.0.4: + version "0.0.7" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" + dependencies: + delayed-stream "0.0.5" + + commander@0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" + + commander@2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" + + commander@2.8.x: + version "2.8.1" + resolved "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + dependencies: + graceful-readlink ">= 1.0.0" + + commander@^2.5.0, commander@^2.6.0, commander@^2.9.0: + version "2.9.0" + resolved "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + + commander@~2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" + + commoner@~0.10.3: + version "0.10.8" + resolved "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" + dependencies: + commander "^2.5.0" + detective "^4.3.1" + glob "^5.0.15" + graceful-fs "^4.1.2" + iconv-lite "^0.4.5" + mkdirp "^0.5.0" + private "^0.1.6" + q "^1.1.2" + recast "^0.11.17" + + component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + + component-emitter@1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" + + component-emitter@1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + + component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + + compressible@~2.0.8: + version "2.0.10" + resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.10.tgz#feda1c7f7617912732b29bf8cf26252a20b9eecd" + dependencies: + mime-db ">= 1.27.0 < 2" + + compression@^1.4.4: + version "1.6.2" + resolved "https://registry.npmjs.org/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" + dependencies: + accepts "~1.3.3" + bytes "2.3.0" + compressible "~2.0.8" + debug "~2.2.0" + on-headers "~1.0.1" + vary "~1.1.0" + + concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + + concat-stream@1.5.0, concat-stream@^1.4.6, concat-stream@^1.4.7: + version "1.5.0" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" + dependencies: + inherits "~2.0.1" + readable-stream "~2.0.0" + typedarray "~0.0.5" + + configstore@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" + dependencies: + dot-prop "^3.0.0" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + object-assign "^4.0.1" + os-tmpdir "^1.0.0" + osenv "^0.1.0" + uuid "^2.0.1" + write-file-atomic "^1.1.2" + xdg-basedir "^2.0.0" + + console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + + console-ui@^1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/console-ui/-/console-ui-1.0.3.tgz#31c524461b63422769f9e89c173495d91393721c" + dependencies: + chalk "^1.1.3" + inquirer "^1.2.3" + ora "^0.2.0" + through "^2.3.8" + + consolidate@^0.14.0: + version "0.14.5" + resolved "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" + dependencies: + bluebird "^3.1.1" + + content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + + content-type@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + + continuable-cache@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" + + convert-source-map@^1.1.0: + version "1.5.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" + + cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + + cookie@0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + + copy-dereference@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" + + core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + + core-js@^2.4.0: + version "2.4.1" + resolved "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + + core-object@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" + + core-object@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/core-object/-/core-object-3.1.0.tgz#f5219fec2a19c40956f1c723d121890c88c5f677" + dependencies: + chalk "^1.1.3" + + core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + + cross-spawn@^5.0.0, cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + + cryptiles@0.2.x: + version "0.2.2" + resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" + dependencies: + boom "0.4.x" + + cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + + crypto-browserify@1.0.9: + version "1.0.9" + resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" + + ctype@0.5.3: + version "0.5.3" + resolved "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" + + d@1: + version "1.0.0" + resolved "https://registry.npmjs.org/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + dependencies: + es5-ext "^0.10.9" + + dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + + debug@0.7.4: + version "0.7.4" + resolved "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" + + debug@2, debug@2.6.4, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0: + version "2.6.4" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0" + dependencies: + ms "0.7.3" + + debug@2.2.0, debug@~2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + + debug@2.3.3: + version "2.3.3" + resolved "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" + dependencies: + ms "0.7.2" + + debug@2.6.1: + version "2.6.1" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" + dependencies: + ms "0.7.2" + + decamelize@^1.0.0, decamelize@^1.1.1: + version "1.2.0" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + + deep-eql@^0.1.3: + version "0.1.3" + resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" + dependencies: + type-detect "0.1.1" + + deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + + defined@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + + defs@~1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" + dependencies: + alter "~0.2.0" + ast-traverse "~0.1.1" + breakable "~1.0.0" + esprima-fb "~15001.1001.0-dev-harmony-fb" + simple-fmt "~0.1.0" + simple-is "~0.2.0" + stringmap "~0.2.2" + stringset "~0.2.1" + tryor "~0.1.2" + yargs "~3.27.0" + + del@^2.0.2: + version "2.2.2" + resolved "https://registry.npmjs.org/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + + delayed-stream@0.0.5: + version "0.0.5" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" + + delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + + delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + + depd@1.1.0, depd@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + + destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + + detect-file@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" + dependencies: + fs-exists-sync "^0.1.0" + + detect-indent@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" + dependencies: + get-stdin "^4.0.1" + minimist "^1.1.0" + repeating "^1.1.0" + + detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + + detective@^4.3.1: + version "4.5.0" + resolved "https://registry.npmjs.org/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" + dependencies: + acorn "^4.0.3" + defined "^1.0.0" + + diff@1.4.0, diff@^1.3.1: + version "1.4.0" + resolved "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" + + doctrine@^1.2.2: + version "1.5.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + + dot-prop@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" + dependencies: + is-obj "^1.0.0" + + ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + + editions@^1.1.1: + version "1.3.3" + resolved "https://registry.npmjs.org/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" + + ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + + electron-to-chromium@^1.2.7: + version "1.3.8" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.8.tgz#b2c8a2c79bb89fbbfd3724d9555e15095b5f5fb6" + + ember-ajax@^2.4.1: + version "2.5.6" + resolved "https://registry.npmjs.org/ember-ajax/-/ember-ajax-2.5.6.tgz#a75f743ccf1b95e979a5cf96013b3dba8fa625e4" + dependencies: + ember-cli-babel "^5.1.5" + + ember-cli-app-version@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/ember-cli-app-version/-/ember-cli-app-version-2.0.2.tgz#aaeede608e92fae6c2e11f63d28a373c1cc3f070" + dependencies: + ember-cli-babel "^5.1.6" + ember-cli-htmlbars "^1.0.0" + git-repo-version "0.4.1" + + ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.2.1: + version "5.2.4" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" + dependencies: + broccoli-babel-transpiler "^5.6.2" + broccoli-funnel "^1.0.0" + clone "^2.0.0" + ember-cli-version-checker "^1.0.2" + resolve "^1.1.2" + + ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.10, ember-cli-babel@^6.0.0-beta.7: + version "6.0.0" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.0.0.tgz#caab075780dca3759982c9f54ea70a9adb1f3550" + dependencies: + amd-name-resolver "0.0.6" + babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-polyfill "^6.16.0" + babel-preset-env "^1.2.0" + broccoli-babel-transpiler "^6.0.0" + broccoli-funnel "^1.0.0" + broccoli-source "^1.1.0" + clone "^2.0.0" + ember-cli-version-checker "^1.2.0" + + ember-cli-blueprint-test-helpers@0.11.0: + version "0.11.0" + resolved "https://registry.npmjs.org/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" + dependencies: + chai "^3.3.0" + chai-as-promised "^5.1.0" + chai-files "^1.0.0" + debug "^2.2.0" + ember-cli-internal-test-helpers "^0.8.1" + exists-sync "0.0.3" + findup "^0.1.5" + fs-extra "^0.26.7" + tmp-sync "^1.0.0" + walk-sync "^0.2.5" + + ember-cli-broccoli-sane-watcher@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.0.4.tgz#f43f42f75b7509c212fb926cd9aea86ae19264c6" + dependencies: + broccoli-slow-trees "^3.0.1" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + rsvp "^3.0.18" + sane "^1.1.1" + + ember-cli-dependency-checker@^1.3.0: + version "1.4.0" + resolved "https://registry.npmjs.org/ember-cli-dependency-checker/-/ember-cli-dependency-checker-1.4.0.tgz#2b13f977e1eea843fc1a21a001be6ca5d4ef1942" + dependencies: + chalk "^0.5.1" + is-git-url "^0.2.0" + semver "^4.1.0" + + ember-cli-eslint@1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/ember-cli-eslint/-/ember-cli-eslint-1.3.0.tgz#8a7eda0d7e6a00c5a5a823f59664932d6429a8f1" + dependencies: + broccoli-lint-eslint "^2.0.0" + ember-cli-babel "^5.1.5" + js-string-escape "^1.0.0" + + ember-cli-get-component-path-option@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" + + ember-cli-get-dependency-depth@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" + + ember-cli-htmlbars-inline-precompile@^0.4.0-beta.2: + version "0.4.0" + resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.0.tgz#4a6d2211b804419953104a9231e112dbd2057f3c" + dependencies: + babel-plugin-htmlbars-inline-precompile "^0.2.3" + ember-cli-version-checker "^1.2.0" + hash-for-dep "^1.0.2" + + ember-cli-htmlbars@^1.0.0, ember-cli-htmlbars@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-1.3.0.tgz#e090f011239153bf45dab29625f94a46fce205af" + dependencies: + broccoli-persistent-filter "^1.0.3" + ember-cli-version-checker "^1.0.2" + hash-for-dep "^1.0.2" + json-stable-stringify "^1.0.0" + strip-bom "^2.0.0" + + ember-cli-inject-live-reload@^1.4.1: + version "1.6.1" + resolved "https://registry.npmjs.org/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.6.1.tgz#82b8f5be454815a75e7f6d42c9ce0bc883a914a3" + + ember-cli-internal-test-helpers@^0.8.1: + version "0.8.3" + resolved "https://registry.npmjs.org/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.8.3.tgz#e9b7db67f3fda4db736d1a319a282c04beada495" + dependencies: + chai "^3.3.0" + chai-as-promised "^6.0.0" + chai-files "^1.1.0" + chalk "^1.1.1" + configstore "^2.0.0" + debug "^2.2.0" + exists-sync "0.0.3" + fs-extra "^0.30.0" + lodash "^4.0.0" + rsvp "^3.0.17" + symlink-or-copy "^1.0.1" + through "^2.3.8" + walk-sync "^0.3.1" + + ember-cli-is-package-missing@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" + + ember-cli-legacy-blueprints@^0.1.2: + version "0.1.4" + resolved "https://registry.npmjs.org/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.4.tgz#83d6c005ac0e39750ff9dd45cd1b78cf697150c6" + dependencies: + chalk "^1.1.1" + ember-cli-get-component-path-option "^1.0.0" + ember-cli-get-dependency-depth "^1.0.0" + ember-cli-is-package-missing "^1.0.0" + ember-cli-lodash-subset "^1.0.7" + ember-cli-normalize-entity-name "^1.0.0" + ember-cli-path-utils "^1.0.0" + ember-cli-string-utils "^1.0.0" + ember-cli-test-info "^1.0.0" + ember-cli-valid-component-name "^1.0.0" + ember-cli-version-checker "^1.1.7" + ember-router-generator "^1.0.0" + exists-sync "0.0.3" + fs-extra "^0.24.0" + inflection "^1.7.1" + rsvp "^3.0.17" + silent-error "^1.0.0" + + ember-cli-lodash-subset@^1.0.11, ember-cli-lodash-subset@^1.0.7: + version "1.0.12" + resolved "https://registry.npmjs.org/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" + + ember-cli-normalize-entity-name@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" + dependencies: + silent-error "^1.0.0" + + ember-cli-path-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" + + ember-cli-preprocess-registry@^3.0.0: + version "3.1.1" + resolved "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.1.tgz#38456c21c4d2b64945850cf9ec68db6ba769288a" + dependencies: + broccoli-clean-css "^1.1.0" + broccoli-funnel "^1.0.0" + broccoli-merge-trees "^1.0.0" + debug "^2.2.0" + ember-cli-lodash-subset "^1.0.7" + exists-sync "0.0.3" + process-relative-require "^1.0.0" + silent-error "^1.0.0" + + ember-cli-pretender@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-1.0.1.tgz#35540babddef6f2778e91c627d190c73505103cd" + dependencies: + broccoli-funnel "^1.1.0" + broccoli-merge-trees "^1.2.1" + pretender "^1.4.2" + resolve "^1.2.0" + + ember-cli-qunit@^2.1.0: + version "2.2.6" + resolved "https://registry.npmjs.org/ember-cli-qunit/-/ember-cli-qunit-2.2.6.tgz#d802174724edd59b61ffdd0581fceb3236014dd1" + dependencies: + broccoli-babel-transpiler "^5.5.0" + broccoli-concat "^2.2.0" + broccoli-funnel "^1.0.1" + broccoli-merge-trees "^1.1.0" + ember-cli-babel "^5.1.5" + ember-cli-version-checker "^1.1.4" + ember-qunit "^0.4.18" + qunit-notifications "^0.1.1" + qunitjs "^1.20.0" + resolve "^1.1.6" + rsvp "^3.2.1" + + ember-cli-release@^0.2.9: + version "0.2.9" + resolved "https://registry.npmjs.org/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" + dependencies: + chalk "^1.0.0" + git-tools "^0.1.4" + make-array "^0.1.2" + merge "^1.2.0" + moment-timezone "^0.3.0" + nopt "^3.0.3" + rsvp "^3.0.17" + semver "^4.3.1" + silent-error "^1.0.0" + + ember-cli-shims@^1.0.2: + version "1.1.0" + resolved "https://registry.npmjs.org/ember-cli-shims/-/ember-cli-shims-1.1.0.tgz#0e3b8a048be865b4f81cc81d397ff1eeb13f75b6" + dependencies: + ember-cli-babel "^6.0.0-beta.7" + ember-cli-version-checker "^1.2.0" + silent-error "^1.0.1" + + ember-cli-sri@^2.1.0: + version "2.1.1" + resolved "https://registry.npmjs.org/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" + dependencies: + broccoli-sri-hash "^2.1.0" + + ember-cli-string-utils@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" + + ember-cli-test-info@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" + dependencies: + ember-cli-string-utils "^1.0.0" + + ember-cli-test-loader@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/ember-cli-test-loader/-/ember-cli-test-loader-1.1.1.tgz#333311209b18185d0e0e95f918349da10cacf0b1" + dependencies: + ember-cli-babel "^5.2.1" + + ember-cli-uglify@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/ember-cli-uglify/-/ember-cli-uglify-1.2.0.tgz#3208c32b54bc2783056e8bb0d5cfe9bbaf17ffb2" + dependencies: + broccoli-uglify-sourcemap "^1.0.0" + + ember-cli-valid-component-name@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" + dependencies: + silent-error "^1.0.0" + + ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7, ember-cli-version-checker@^1.2.0: + version "1.3.1" + resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz#0bc2d134c830142da64bf9627a0eded10b61ae72" + dependencies: + semver "^5.3.0" + + ember-cli@^2.11.1: + version "2.12.2" + resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.12.2.tgz#eccae6359e5d4e49d509e6391dcdf1961848377a" + dependencies: + amd-name-resolver "0.0.6" + bower-config "^1.3.0" + bower-endpoint-parser "0.2.2" + broccoli-babel-transpiler "^5.6.2" + broccoli-brocfile-loader "^0.18.0" + broccoli-builder "^0.18.3" + broccoli-concat "^3.0.4" + broccoli-config-loader "^1.0.0" + broccoli-config-replace "^1.1.2" + broccoli-funnel "^1.0.6" + broccoli-funnel-reducer "^1.0.0" + broccoli-merge-trees "^1.1.3" + broccoli-middleware "^1.0.0-beta.8" + broccoli-source "^1.1.0" + broccoli-stew "^1.2.0" + calculate-cache-key-for-tree "^1.0.0" + capture-exit "^1.1.0" + chalk "^1.1.3" + clean-base-url "^1.0.0" + compression "^1.4.4" + configstore "^2.0.0" + console-ui "^1.0.2" + core-object "^3.0.0" + diff "^1.3.1" + ember-cli-broccoli-sane-watcher "^2.0.4" + ember-cli-get-component-path-option "^1.0.0" + ember-cli-is-package-missing "^1.0.0" + ember-cli-legacy-blueprints "^0.1.2" + ember-cli-lodash-subset "^1.0.11" + ember-cli-normalize-entity-name "^1.0.0" + ember-cli-preprocess-registry "^3.0.0" + ember-cli-string-utils "^1.0.0" + ember-try "^0.2.9" + ensure-posix-path "^1.0.2" + escape-string-regexp "^1.0.3" + execa "^0.6.0" + exists-sync "0.0.4" + exit "^0.1.2" + express "^4.12.3" + filesize "^3.1.3" + find-up "^2.1.0" + fs-extra "2.0.0" + fs-tree-diff "^0.5.2" + get-caller-file "^1.0.0" + git-repo-info "^1.0.4" + glob "7.1.1" + heimdalljs "^0.2.3" + heimdalljs-fs-monitor "^0.1.0" + heimdalljs-graph "^0.3.1" + heimdalljs-logger "^0.1.7" + http-proxy "^1.9.0" + inflection "^1.7.0" + is-git-url "^0.2.0" + isbinaryfile "^3.0.0" + js-yaml "^3.6.1" + json-stable-stringify "^1.0.1" + leek "0.0.24" + lodash.template "^4.2.5" + markdown-it "^8.2.0" + markdown-it-terminal "0.0.4" + minimatch "^3.0.0" + morgan "^1.5.2" + node-modules-path "^1.0.0" + nopt "^4.0.0" + npm-package-arg "^4.1.1" + portfinder "^1.0.7" + promise-map-series "^0.2.1" + quick-temp "0.1.6" + resolve "^1.1.6" + rsvp "^3.3.3" + sane "^1.1.1" + semver "^5.1.1" + silent-error "^1.0.0" + sort-package-json "^1.4.0" + symlink-or-copy "^1.1.8" + temp "0.8.3" + testem "^1.8.1" + tiny-lr "^1.0.3" + tree-sync "^1.2.1" + uuid "^3.0.0" + walk-sync "^0.3.0" + yam "0.0.22" + + ember-dev@emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed: + version "0.0.0" + resolved "https://codeload.github.com/emberjs/ember-dev/tar.gz/bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed" + dependencies: + ember-cli-babel "^5.0.0" + + ember-disable-prototype-extensions@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.0.tgz#86081c8cf6741f26e4b89e2b004f761174313e01" + dependencies: + ember-cli-babel "^5.1.5" + + ember-disable-proxy-controllers@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" + dependencies: + ember-cli-babel "^5.0.0" + + ember-export-application-global@^1.0.5: + version "1.1.1" + resolved "https://registry.npmjs.org/ember-export-application-global/-/ember-export-application-global-1.1.1.tgz#f257d5271268932a89d7392679ce4db89d7154af" + dependencies: + ember-cli-babel "^5.1.10" + + ember-inflector@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-2.0.0.tgz#ac0870e87c0724bd42cf5ed7ef166c49a296ecfb" + dependencies: + ember-cli-babel "^6.0.0" + + ember-load-initializers@^0.6.0: + version "0.6.3" + resolved "https://registry.npmjs.org/ember-load-initializers/-/ember-load-initializers-0.6.3.tgz#f47396ad271ba77294068c98f992a5f19705441a" + dependencies: + ember-cli-babel "^5.1.6" + + ember-publisher@0.0.7: + version "0.0.7" + resolved "https://registry.npmjs.org/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" + dependencies: + aws-sdk "^2.0.9" + + ember-qunit@^0.4.18: + version "0.4.24" + resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-0.4.24.tgz#b54cf6688c442d07eacea47c3285879cdd7c2163" + dependencies: + ember-test-helpers "^0.5.32" + + ember-resolver@^2.0.3: + version "2.1.1" + resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-2.1.1.tgz#5e4c1fffe9f5f48fc2194ad7592274ed0cd74f72" + dependencies: + ember-cli-babel "^5.1.6" + ember-cli-version-checker "^1.1.6" + + ember-router-generator@^1.0.0: + version "1.2.3" + resolved "https://registry.npmjs.org/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" + dependencies: + recast "^0.11.3" + + ember-runtime-enumerable-includes-polyfill@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-2.0.0.tgz#6e9ba118bc909d1d7762de1b03a550d8955308a9" + dependencies: + ember-cli-babel "^6.0.0" + ember-cli-version-checker "^1.1.6" + + ember-source@~2.11.0: + version "2.11.3" + resolved "https://registry.npmjs.org/ember-source/-/ember-source-2.11.3.tgz#12c50cc2b4a7f8ae8c5daa3a72fb09415476c510" + dependencies: + broccoli-funnel "^1.0.6" + broccoli-merge-trees "^1.1.4" + ember-cli-get-component-path-option "^1.0.0" + ember-cli-normalize-entity-name "^1.0.0" + ember-cli-path-utils "^1.0.0" + ember-cli-string-utils "^1.0.0" + ember-cli-test-info "^1.0.0" + ember-cli-valid-component-name "^1.0.0" + ember-cli-version-checker "^1.1.7" + jquery "^3.1.1" + resolve "^1.1.7" + rsvp "^3.4.0" + simple-dom "^0.3.0" + + ember-test-helpers@^0.5.32: + version "0.5.34" + resolved "https://registry.npmjs.org/ember-test-helpers/-/ember-test-helpers-0.5.34.tgz#c8439108d1cba1d7d838c212208a5c4061471b83" + dependencies: + klassy "^0.1.3" + + ember-try-config@^2.0.1: + version "2.1.0" + resolved "https://registry.npmjs.org/ember-try-config/-/ember-try-config-2.1.0.tgz#e0e156229a542346a58ee6f6ad605104c98edfe0" + dependencies: + lodash "^4.6.1" + node-fetch "^1.3.3" + rsvp "^3.2.1" + semver "^5.1.0" + + ember-try@^0.2.9: + version "0.2.14" + resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.14.tgz#d47e8fa38858d5683e47856e24a260b39e9caf4a" + dependencies: + chalk "^1.0.0" + cli-table2 "^0.2.0" + core-object "^1.1.0" + debug "^2.2.0" + ember-cli-version-checker "^1.1.6" + ember-try-config "^2.0.1" + extend "^3.0.0" + fs-extra "^0.26.0" + promise-map-series "^0.2.1" + resolve "^1.1.6" + rimraf "^2.3.2" + rsvp "^3.0.17" + semver "^5.1.0" + sync-exec "^0.6.2" + + ember-watson@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" + dependencies: + babel-core "^5.8.22" + chalk "^1.0.0" + commander "^2.6.0" + exists-sync "0.0.3" + inflected "^1.1.6" + recast "^0.10.29" + walk-sync "^0.1.3" + + encodeurl@~1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + + encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + + engine.io-client@1.8.0: + version "1.8.0" + resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.0.tgz#7b730e4127414087596d9be3c88d2bc5fdb6cf5c" + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "2.3.3" + engine.io-parser "1.3.1" + has-cors "1.1.0" + indexof "0.0.1" + parsejson "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + ws "1.1.1" + xmlhttprequest-ssl "1.5.3" + yeast "0.1.2" + + engine.io-parser@1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" + dependencies: + after "0.8.1" + arraybuffer.slice "0.0.6" + base64-arraybuffer "0.1.5" + blob "0.0.4" + has-binary "0.1.6" + wtf-8 "1.0.0" + + engine.io@1.8.0: + version "1.8.0" + resolved "https://registry.npmjs.org/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" + dependencies: + accepts "1.3.3" + base64id "0.1.0" + cookie "0.3.1" + debug "2.3.3" + engine.io-parser "1.3.1" + ws "1.1.1" + + ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" + + entities@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + + error-ex@^1.2.0: + version "1.3.1" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + dependencies: + is-arrayish "^0.2.1" + + error@^7.0.0: + version "7.0.2" + resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" + dependencies: + string-template "~0.2.1" + xtend "~4.0.0" + + es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: + version "0.10.15" + resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz#c330a5934c1ee21284a7c081a86e5fd937c91ea6" + dependencies: + es6-iterator "2" + es6-symbol "~3.1" + + es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" + dependencies: + d "1" + es5-ext "^0.10.14" + es6-symbol "^3.1" + + es6-map@^0.1.3, es6-map@^0.1.4: + version "0.1.5" + resolved "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-set "~0.1.5" + es6-symbol "~3.1.1" + event-emitter "~0.3.5" + + es6-promise@~4.0.3: + version "4.0.5" + resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" + + es6-set@~0.1.5: + version "0.1.5" + resolved "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-symbol "3.1.1" + event-emitter "~0.3.5" + + es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + dependencies: + d "1" + es5-ext "~0.10.14" + + es6-weak-map@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" + dependencies: + d "1" + es5-ext "^0.10.14" + es6-iterator "^2.0.1" + es6-symbol "^3.1.1" + + escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + + escape-string-regexp@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" + + escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + + escope@^3.6.0: + version "3.6.0" + resolved "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + dependencies: + es6-map "^0.1.3" + es6-weak-map "^2.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + + eslint@^2.13.0: + version "2.13.1" + resolved "https://registry.npmjs.org/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" + dependencies: + chalk "^1.1.3" + concat-stream "^1.4.6" + debug "^2.1.1" + doctrine "^1.2.2" + es6-map "^0.1.3" + escope "^3.6.0" + espree "^3.1.6" + estraverse "^4.2.0" + esutils "^2.0.2" + file-entry-cache "^1.1.1" + glob "^7.0.3" + globals "^9.2.0" + ignore "^3.1.2" + imurmurhash "^0.1.4" + inquirer "^0.12.0" + is-my-json-valid "^2.10.0" + is-resolvable "^1.0.0" + js-yaml "^3.5.1" + json-stable-stringify "^1.0.0" + levn "^0.3.0" + lodash "^4.0.0" + mkdirp "^0.5.0" + optionator "^0.8.1" + path-is-absolute "^1.0.0" + path-is-inside "^1.0.1" + pluralize "^1.2.1" + progress "^1.1.8" + require-uncached "^1.0.2" + shelljs "^0.6.0" + strip-json-comments "~1.0.1" + table "^3.7.8" + text-table "~0.2.0" + user-home "^2.0.0" + + espree@^3.1.6: + version "3.4.2" + resolved "https://registry.npmjs.org/espree/-/espree-3.4.2.tgz#38dbdedbedc95b8961a1fbf04734a8f6a9c8c592" + dependencies: + acorn "^5.0.1" + acorn-jsx "^3.0.0" + + esprima-fb@~12001.1.0-dev-harmony-fb: + version "12001.1.0-dev-harmony-fb" + resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-12001.1.0-dev-harmony-fb.tgz#d84400384ba95ce2678c617ad24a7f40808da915" + + esprima-fb@~15001.1001.0-dev-harmony-fb: + version "15001.1001.0-dev-harmony-fb" + resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" + + esprima@^1.2.2: + version "1.2.5" + resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" + + esprima@^2.6.0: + version "2.7.3" + resolved "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + + esprima@^3.1.1, esprima@~3.1.0: + version "3.1.3" + resolved "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + + esprimaq@^0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" + + esrecurse@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + dependencies: + estraverse "~4.1.0" + object-assign "^4.0.1" + + estraverse@^4.1.1, estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + + estraverse@~4.1.0: + version "4.1.1" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" + + esutils@^2.0.0, esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + + etag@~1.8.0: + version "1.8.0" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" + + event-emitter@~0.3.5: + version "0.3.5" + resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + dependencies: + d "1" + es5-ext "~0.10.14" + + eventemitter3@1.x.x: + version "1.2.0" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" + + events-to-array@^1.0.1: + version "1.1.2" + resolved "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" + + exec-sh@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" + dependencies: + merge "^1.1.3" + + execa@^0.6.0: + version "0.6.3" + resolved "https://registry.npmjs.org/execa/-/execa-0.6.3.tgz#57b69a594f081759c69e5370f0d17b9cb11658fe" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + + exists-sync@0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" + + exists-sync@0.0.4: + version "0.0.4" + resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" + + exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + + exit@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + + expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + + expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + + expand-tilde@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" + dependencies: + os-homedir "^1.0.1" + + express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: + version "4.15.2" + resolved "https://registry.npmjs.org/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35" + dependencies: + accepts "~1.3.3" + array-flatten "1.1.1" + content-disposition "0.5.2" + content-type "~1.0.2" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.1" + depd "~1.1.0" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.8.0" + finalhandler "~1.0.0" + fresh "0.5.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.1" + path-to-regexp "0.1.7" + proxy-addr "~1.1.3" + qs "6.4.0" + range-parser "~1.2.0" + send "0.15.1" + serve-static "1.12.1" + setprototypeof "1.0.3" + statuses "~1.3.1" + type-is "~1.6.14" + utils-merge "1.0.0" + vary "~1.1.0" + + extend@3, extend@^3.0.0, extend@~3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + + external-editor@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" + dependencies: + extend "^3.0.0" + spawn-sync "^1.0.15" + tmp "^0.0.29" + + extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + + extract-zip@~1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4" + dependencies: + concat-stream "1.5.0" + debug "0.7.4" + mkdirp "0.5.0" + yauzl "2.4.1" + + extsprintf@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + + fake-xml-http-request@^1.3.0, fake-xml-http-request@^1.4.0: + version "1.5.0" + resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-1.5.0.tgz#d79602a97043d4d8fea671d5d904af38847b451d" + + faker@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/faker/-/faker-3.1.0.tgz#0f908faf4e6ec02524e54a57e432c5c013e08c9f" + + fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + + fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" + dependencies: + blank-object "^1.0.1" + + fast-sourcemap-concat@^1.0.1: + version "1.1.0" + resolved "https://registry.npmjs.org/fast-sourcemap-concat/-/fast-sourcemap-concat-1.1.0.tgz#a800767abed5eda02e67238ec063a709be61f9d4" + dependencies: + chalk "^0.5.1" + debug "^2.2.0" + fs-extra "^0.30.0" + memory-streams "^0.1.0" + mkdirp "^0.5.0" + rsvp "^3.0.14" + source-map "^0.4.2" + source-map-url "^0.3.0" + + faye-websocket@~0.10.0: + version "0.10.0" + resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + dependencies: + websocket-driver ">=0.5.1" + + fb-watchman@^1.8.0: + version "1.9.2" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383" + dependencies: + bser "1.0.2" + + fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + dependencies: + pend "~1.2.0" + + figures@^1.3.5: + version "1.7.0" + resolved "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + + file-entry-cache@^1.1.1: + version "1.3.1" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + + filename-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + + filesize@^3.1.3: + version "3.5.6" + resolved "https://registry.npmjs.org/filesize/-/filesize-3.5.6.tgz#5fd98f3eac94ec9516ef8ed5782fad84a01a0a1a" + + fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + + finalhandler@~1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.2.tgz#d0e36f9dbc557f2de14423df6261889e9d60c93a" + dependencies: + debug "2.6.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.1" + statuses "~1.3.1" + unpipe "~1.0.0" + + find-index@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" + + find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + + find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + + findup-sync@^0.4.2: + version "0.4.3" + resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" + dependencies: + detect-file "^0.1.0" + is-glob "^2.0.1" + micromatch "^2.3.7" + resolve-dir "^0.1.0" + + findup@^0.1.5: + version "0.1.5" + resolved "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" + dependencies: + colors "~0.6.0-1" + commander "~2.1.0" + + fireworm@^0.7.0: + version "0.7.1" + resolved "https://registry.npmjs.org/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" + dependencies: + async "~0.2.9" + is-type "0.0.1" + lodash.debounce "^3.1.1" + lodash.flatten "^3.0.2" + minimatch "^3.0.2" + + flat-cache@^1.2.1: + version "1.2.2" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" + dependencies: + circular-json "^0.3.1" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + + follow-redirects@0.0.7: + version "0.0.7" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" + dependencies: + debug "^2.2.0" + stream-consume "^0.1.0" + + for-in@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + + for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + + forever-agent@~0.5.0: + version "0.5.2" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" + + forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + + form-data@~0.1.0: + version "0.1.4" + resolved "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" + dependencies: + async "~0.9.0" + combined-stream "~0.0.4" + mime "~1.2.11" + + form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + + forwarded@~0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" + + fresh@0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" + + fs-exists-sync@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + + fs-extra@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-2.0.0.tgz#337352bded4a0b714f3eb84de8cea765e9d37600" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + + fs-extra@^0.24.0: + version "0.24.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + + fs-extra@^0.26.0, fs-extra@^0.26.7: + version "0.26.7" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + + fs-extra@^0.30.0: + version "0.30.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + + fs-extra@^1.0.0, fs-extra@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + + fs-extra@^2.0.0: + version "2.1.2" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + + fs-readdir-recursive@^0.1.0: + version "0.1.2" + resolved "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" + + fs-sync@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" + dependencies: + glob "^7.1.0" + iconv-lite "^0.4.13" + lodash "^4.16.1" + mkdirp "^0.5.1" + rimraf "^2.1.4" + + fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6: + version "0.5.6" + resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.6.tgz#342665749e8dca406800b672268c8f5073f3e623" + dependencies: + heimdalljs-logger "^0.1.7" + object-assign "^4.1.0" + path-posix "^1.0.0" + symlink-or-copy "^1.1.8" + + fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + + gauge@~2.7.1: + version "2.7.4" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + + generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + + generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + + get-caller-file@^1.0.0, get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + + get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + + get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + + getpass@^0.1.1: + version "0.1.6" + resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + dependencies: + assert-plus "^1.0.0" + + git-repo-info@^1.0.4, git-repo-info@^1.1.2: + version "1.4.1" + resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" + + git-repo-info@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.2.0.tgz#43d8513e04a24dd441330a2f7c6655a709fdbaf2" + + git-repo-version@0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/git-repo-version/-/git-repo-version-0.4.1.tgz#75fab9a0a4ec8470755b0eea7fdaa6f9d41453bf" + dependencies: + git-repo-info "~1.2.0" + + git-tools@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" + dependencies: + spawnback "~1.0.0" + + github@^1.1.1: + version "1.4.0" + resolved "https://registry.npmjs.org/github/-/github-1.4.0.tgz#60aed8f16ffe381a3ca6dc6dba5bdd64445b7856" + dependencies: + follow-redirects "0.0.7" + https-proxy-agent "^1.0.0" + mime "^1.2.11" + + glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + + glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + + glob@3.2.3: + version "3.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" + dependencies: + graceful-fs "~2.0.0" + inherits "2" + minimatch "~0.2.11" + + glob@5.0.13, glob@^5.0.10: + version "5.0.13" + resolved "https://registry.npmjs.org/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "^2.0.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + + glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + + glob@^4.3.2: + version "4.5.3" + resolved "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "^2.0.1" + once "^1.3.0" + + glob@^5.0.15: + version "5.0.15" + resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + + global-modules@^0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" + dependencies: + global-prefix "^0.1.4" + is-windows "^0.2.0" + + global-prefix@^0.1.4: + version "0.1.5" + resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" + dependencies: + homedir-polyfill "^1.0.0" + ini "^1.3.4" + is-windows "^0.2.0" + which "^1.2.12" + + globals@^6.4.0: + version "6.4.1" + resolved "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" + + globals@^9.0.0, globals@^9.2.0: + version "9.17.0" + resolved "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286" + + globby@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + + graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: + version "4.1.11" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + + graceful-fs@~2.0.0: + version "2.0.3" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" + + "graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + + growl@1.8.1: + version "1.8.1" + resolved "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428" + + growly@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + + handlebars@^4.0.4: + version "4.0.6" + resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" + dependencies: + async "^1.4.0" + optimist "^0.6.1" + source-map "^0.4.4" + optionalDependencies: + uglify-js "^2.6" + + har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + + has-ansi@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" + dependencies: + ansi-regex "^0.2.0" + + has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + + has-binary@0.1.6: + version "0.1.6" + resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" + dependencies: + isarray "0.0.1" + + has-binary@0.1.7: + version "0.1.7" + resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" + dependencies: + isarray "0.0.1" + + has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + + has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + + hash-for-dep@^1.0.2: + version "1.1.2" + resolved "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.1.2.tgz#e3347ed92960eb0bb53a2c6c2b70e36d75b7cd0c" + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + heimdalljs "^0.2.3" + heimdalljs-logger "^0.1.7" + resolve "^1.1.6" + + hasha@~2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1" + dependencies: + is-stream "^1.0.1" + pinkie-promise "^2.0.0" + + hawk@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" + dependencies: + boom "0.4.x" + cryptiles "0.2.x" + hoek "0.9.x" + sntp "0.2.x" + + hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + + heimdall-query@^0.0.5: + version "0.0.5" + resolved "https://registry.npmjs.org/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" + dependencies: + chalk "^1.1.1" + chrome-debugging-client "^0.2.4" + cli-table "^0.3.1" + lodash "^4.15.0" + plain-text-box-plot "0.0.1" + progress "^1.1.8" + selenium-webdriver "^3.0.0-beta-2" + + heimdalljs-fs-monitor@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.1.0.tgz#d404a65688c6714c485469ed3495da4853440272" + dependencies: + heimdalljs "^0.2.0" + heimdalljs-logger "^0.1.7" + + heimdalljs-graph@^0.3.1: + version "0.3.3" + resolved "https://registry.npmjs.org/heimdalljs-graph/-/heimdalljs-graph-0.3.3.tgz#ea801dbba659c8d522fe1cb83b2d605726e4918f" + + heimdalljs-logger@^0.1.7: + version "0.1.9" + resolved "https://registry.npmjs.org/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz#d76ada4e45b7bb6f786fc9c010a68eb2e2faf176" + dependencies: + debug "^2.2.0" + heimdalljs "^0.2.0" + + heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3: + version "0.2.4" + resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.2.4.tgz#34ead16eab422c94803065d33abeba1f7b24a910" + dependencies: + rsvp "~3.2.1" + + heimdalljs@^0.3.0: + version "0.3.3" + resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" + dependencies: + rsvp "~3.2.1" + + hoek@0.9.x: + version "0.9.1" + resolved "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" + + hoek@2.x.x: + version "2.16.3" + resolved "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + + home-or-tmp@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" + dependencies: + os-tmpdir "^1.0.1" + user-home "^1.1.1" + + home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + + homedir-polyfill@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + dependencies: + parse-passwd "^1.0.0" + + hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: + version "2.4.2" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.4.2.tgz#0076b9f46a270506ddbaaea56496897460612a67" + + http-errors@~1.6.1: + version "1.6.1" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257" + dependencies: + depd "1.1.0" + inherits "2.0.3" + setprototypeof "1.0.3" + statuses ">= 1.3.1 < 2" + + http-proxy@^1.13.1, http-proxy@^1.9.0: + version "1.16.2" + resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" + dependencies: + eventemitter3 "1.x.x" + requires-port "1.x.x" + + http-signature@~0.10.0: + version "0.10.1" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" + dependencies: + asn1 "0.1.11" + assert-plus "^0.1.5" + ctype "0.5.3" + + http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + + https-proxy-agent@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" + dependencies: + agent-base "2" + debug "2" + extend "3" + + iconv-lite@0.4.15, iconv-lite@^0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13: + version "0.4.15" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" + + ieee754@^1.1.4: + version "1.1.8" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + + ignore@^3.1.2: + version "3.2.7" + resolved "https://registry.npmjs.org/ignore/-/ignore-3.2.7.tgz#4810ca5f1d8eca5595213a34b94f2eb4ed926bbd" + + imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + + indexof@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + + inflected@^1.1.6: + version "1.1.7" + resolved "https://registry.npmjs.org/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" + + inflection@^1.7.0, inflection@^1.7.1, inflection@^1.8.0: + version "1.12.0" + resolved "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" + + inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + + inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.1: + version "2.0.3" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + + ini@^1.3.4: + version "1.3.4" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + + inline-source-map-comment@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" + dependencies: + chalk "^1.0.0" + get-stdin "^4.0.1" + minimist "^1.1.1" + sum-up "^1.0.1" + xtend "^4.0.0" + + inquirer@^0.12.0: + version "0.12.0" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + dependencies: + ansi-escapes "^1.1.0" + ansi-regex "^2.0.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + figures "^1.3.5" + lodash "^4.3.0" + readline2 "^1.0.1" + run-async "^0.1.0" + rx-lite "^3.1.2" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + + inquirer@^1.2.3: + version "1.2.3" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918" + dependencies: + ansi-escapes "^1.1.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + external-editor "^1.1.0" + figures "^1.3.5" + lodash "^4.3.0" + mute-stream "0.0.6" + pinkie-promise "^2.0.0" + run-async "^2.2.0" + rx "^4.1.0" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + + invariant@^2.2.0, invariant@^2.2.2: + version "2.2.2" + resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + + invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + + ipaddr.js@1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec" + + is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + + is-buffer@^1.0.2: + version "1.1.5" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" + + is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + + is-dotfile@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + + is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + + is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + + is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + + is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + + is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + + is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + + is-git-url@^0.2.0: + version "0.2.3" + resolved "https://registry.npmjs.org/is-git-url/-/is-git-url-0.2.3.tgz#445200d6fbd6da028fb5e01440d9afc93f3ccb64" + + is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + + is-integer@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/is-integer/-/is-integer-1.0.6.tgz#5273819fada880d123e1ac00a938e7172dd8d95e" + dependencies: + is-finite "^1.0.0" + + is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: + version "2.16.0" + resolved "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + + is-number@^2.0.2, is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + + is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + + is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + + is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + + is-path-inside@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + dependencies: + path-is-inside "^1.0.1" + + is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + + is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + + is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + + is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + + is-resolvable@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + dependencies: + tryit "^1.0.1" + + is-stream@^1.0.1, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + + is-type@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" + dependencies: + core-util-is "~1.0.0" + + is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + + is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + + is-windows@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" + + isarray@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + + isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + + isbinaryfile@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" + + isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + + isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + + isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + + istextorbinary@2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" + dependencies: + binaryextensions "1 || 2" + editions "^1.1.1" + textextensions "1 || 2" + + jade@0.26.3: + version "0.26.3" + resolved "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" + dependencies: + commander "0.6.1" + mkdirp "0.3.0" + + jmespath@0.15.0: + version "0.15.0" + resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + + jodid25519@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + dependencies: + jsbn "~0.1.0" + + jquery@^3.1.1: + version "3.2.1" + resolved "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787" + + js-string-escape@^1.0.0, js-string-escape@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" + + js-tokens@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" + + js-tokens@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" + + js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: + version "3.8.3" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766" + dependencies: + argparse "^1.0.7" + esprima "^3.1.1" + + jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + + jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + + jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + + json-api-mock-server@0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/json-api-mock-server/-/json-api-mock-server-0.1.1.tgz#00acb22ac58127e87fa9a172159cd8ed558e8106" + dependencies: + body-parser "^1.15.2" + chalk "^1.1.1" + express "^4.14.0" + glob "^7.1.1" + jsonapi-validator "^2.1.1" + object-assign "^4.1.0" + + json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + + json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + + json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + + json3@3.3.2: + version "3.3.2" + resolved "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + + json5@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" + + json5@^0.5.0: + version "0.5.1" + resolved "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + + jsonapi-validator@^2.1.1: + version "2.2.0" + resolved "https://registry.npmjs.org/jsonapi-validator/-/jsonapi-validator-2.2.0.tgz#07f9bdb6d118c1e728fa77280605fa9b527f8c66" + dependencies: + ajv "^4.1.3" + yargs "^5.0.0" + + jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + optionalDependencies: + graceful-fs "^4.1.6" + + jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + + jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + + jsprim@^1.2.2: + version "1.4.0" + resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" + dependencies: + assert-plus "1.0.0" + extsprintf "1.0.2" + json-schema "0.2.3" + verror "1.3.6" + + kew@~0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" + + kind-of@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" + dependencies: + is-buffer "^1.0.2" + + klassy@^0.1.3: + version "0.1.3" + resolved "https://registry.npmjs.org/klassy/-/klassy-0.1.3.tgz#c31d5756d583197d75f582b6e692872be497067f" + + klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + optionalDependencies: + graceful-fs "^4.1.9" + + lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + + lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + + leek@0.0.24: + version "0.0.24" + resolved "https://registry.npmjs.org/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" + dependencies: + debug "^2.1.0" + lodash.assign "^3.2.0" + rsvp "^3.0.21" + + leven@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" + + levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + + linkify-it@^2.0.0: + version "2.0.3" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" + dependencies: + uc.micro "^1.0.1" + + linkify-it@~1.2.0: + version "1.2.4" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" + dependencies: + uc.micro "^1.0.1" + + livereload-js@^2.2.2: + version "2.2.2" + resolved "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" + + load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + + loader.js@^4.2.2: + version "4.3.0" + resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.3.0.tgz#736c13eb8afdf75abd6c2d7b4f7fd40e1105a71f" + + locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + + lodash-node@^3.2.0: + version "3.10.2" + resolved "https://registry.npmjs.org/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" + + lodash._arraycopy@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" + + lodash._arrayeach@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" + + lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + + lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + + lodash._baseflatten@^3.0.0: + version "3.1.4" + resolved "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" + dependencies: + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + + lodash._basefor@^3.0.0: + version "3.0.3" + resolved "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" + + lodash._bindcallback@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + + lodash._createassigner@^3.0.0: + version "3.1.1" + resolved "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + dependencies: + lodash._bindcallback "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash.restparam "^3.0.0" + + lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + + lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + + lodash._reinterpolate@~3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + + lodash.assign@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + dependencies: + lodash._baseassign "^3.0.0" + lodash._createassigner "^3.0.0" + lodash.keys "^3.0.0" + + lodash.assign@^4.1.0, lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + + lodash.assignin@^4.1.0: + version "4.2.0" + resolved "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + + lodash.clonedeep@^4.4.1: + version "4.5.0" + resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + + lodash.debounce@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" + dependencies: + lodash._getnative "^3.0.0" + + lodash.find@^4.5.1: + version "4.6.0" + resolved "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" + + lodash.flatten@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" + dependencies: + lodash._baseflatten "^3.0.0" + lodash._isiterateecall "^3.0.0" + + lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + + lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + + lodash.isplainobject@^3.0.0: + version "3.2.0" + resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" + dependencies: + lodash._basefor "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.keysin "^3.0.0" + + lodash.istypedarray@^3.0.0: + version "3.0.6" + resolved "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" + + lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + + lodash.keysin@^3.0.0: + version "3.0.8" + resolved "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" + dependencies: + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + + lodash.merge@^3.3.2: + version "3.3.2" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz#0d90d93ed637b1878437bb3e21601260d7afe994" + dependencies: + lodash._arraycopy "^3.0.0" + lodash._arrayeach "^3.0.0" + lodash._createassigner "^3.0.0" + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + lodash.isplainobject "^3.0.0" + lodash.istypedarray "^3.0.0" + lodash.keys "^3.0.0" + lodash.keysin "^3.0.0" + lodash.toplainobject "^3.0.0" + + lodash.merge@^4.3.0, lodash.merge@^4.4.0, lodash.merge@^4.5.1: + version "4.6.0" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" + + lodash.omit@^4.1.0: + version "4.5.0" + resolved "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" + + lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + + lodash.template@^4.2.5: + version "4.4.0" + resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" + dependencies: + lodash._reinterpolate "~3.0.0" + lodash.templatesettings "^4.0.0" + + lodash.templatesettings@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" + dependencies: + lodash._reinterpolate "~3.0.0" + + lodash.toplainobject@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz#28790ad942d293d78aa663a07ecf7f52ca04198d" + dependencies: + lodash._basecopy "^3.0.0" + lodash.keysin "^3.0.0" + + lodash.uniq@^4.2.0: + version "4.5.0" + resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + + lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: + version "3.10.1" + resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + + lodash@^4.0.0, lodash@^4.15.0, lodash@^4.16.1, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: + version "4.17.4" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + + longest@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + + loose-envify@^1.0.0: + version "1.3.1" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + + lru-cache@2: + version "2.7.3" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + + lru-cache@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" + dependencies: + pseudomap "^1.0.1" + yallist "^2.0.0" + + make-array@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" + + makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + dependencies: + tmpl "1.0.x" + + markdown-it-terminal@0.0.4: + version "0.0.4" + resolved "https://registry.npmjs.org/markdown-it-terminal/-/markdown-it-terminal-0.0.4.tgz#3f2ce624ba2ca964a78b8b388d605ee330de9ced" + dependencies: + ansi-styles "^2.1.0" + cardinal "^0.5.0" + cli-table "^0.3.1" + lodash.merge "^3.3.2" + markdown-it "^4.4.0" + + markdown-it@^4.3.0, markdown-it@^4.4.0: + version "4.4.0" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" + dependencies: + argparse "~1.0.2" + entities "~1.1.1" + linkify-it "~1.2.0" + mdurl "~1.0.0" + uc.micro "^1.0.0" + + markdown-it@^8.2.0: + version "8.3.1" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-8.3.1.tgz#2f4b622948ccdc193d66f3ca2d43125ac4ac7323" + dependencies: + argparse "^1.0.7" + entities "~1.1.1" + linkify-it "^2.0.0" + mdurl "^1.0.1" + uc.micro "^1.0.3" + + matcher-collection@^1.0.0, matcher-collection@^1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.4.tgz#2f66ae0869996f29e43d0b62c83dd1d43e581755" + dependencies: + minimatch "^3.0.2" + + md5-hex@^1.0.2, md5-hex@^1.2.1, md5-hex@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" + dependencies: + md5-o-matic "^0.1.1" + + md5-o-matic@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" + + mdn-links@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" + + mdurl@^1.0.1, mdurl@~1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + + media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + + memory-streams@^0.1.0: + version "0.1.2" + resolved "https://registry.npmjs.org/memory-streams/-/memory-streams-0.1.2.tgz#273ff777ab60fec599b116355255282cca2c50c2" + dependencies: + readable-stream "~1.0.2" + + merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + + merge@^1.1.3, merge@^1.2.0, merge@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + + methods@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + + micromatch@^2.1.5, micromatch@^2.3.7: + version "2.3.11" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + + "mime-db@>= 1.27.0 < 2", mime-db@~1.27.0: + version "1.27.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" + + mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7: + version "2.1.15" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" + dependencies: + mime-db "~1.27.0" + + mime-types@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" + + mime@1.3.4, mime@^1.2.11: + version "1.3.4" + resolved "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + + mime@~1.2.11: + version "1.2.11" + resolved "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + + "minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + + minimatch@^2.0.1, minimatch@^2.0.3, minimatch@^2.0.8: + version "2.0.10" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" + dependencies: + brace-expansion "^1.0.0" + + minimatch@~0.2.11: + version "0.2.14" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" + dependencies: + lru-cache "2" + sigmund "~1.0.0" + + minimist@0.0.8, minimist@~0.0.1: + version "0.0.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + + minimist@^1.1.0, minimist@^1.1.1: + version "1.2.0" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + + mkdirp@0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" + + mkdirp@0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" + dependencies: + minimist "0.0.8" + + mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + + mktemp@^0.4.0, mktemp@~0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" + + mocha-only-detector@0.0.2: + version "0.0.2" + resolved "https://registry.npmjs.org/mocha-only-detector/-/mocha-only-detector-0.0.2.tgz#00f7dde6f949cf68a3cc92bdacff997b87e4b1d1" + dependencies: + esprima "^1.2.2" + esprimaq "^0.0.1" + glob "^4.3.2" + + mocha@2.4.5: + version "2.4.5" + resolved "https://registry.npmjs.org/mocha/-/mocha-2.4.5.tgz#151768dd2875eb51bc8295e9800026e9f2bb398f" + dependencies: + commander "2.3.0" + debug "2.2.0" + diff "1.4.0" + escape-string-regexp "1.0.2" + glob "3.2.3" + growl "1.8.1" + jade "0.26.3" + mkdirp "0.5.1" + supports-color "1.2.0" + + moment-timezone@^0.3.0: + version "0.3.1" + resolved "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" + dependencies: + moment ">= 2.6.0" + + "moment@>= 2.6.0": + version "2.18.1" + resolved "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" + + morgan@^1.5.2, morgan@^1.7.0: + version "1.8.1" + resolved "https://registry.npmjs.org/morgan/-/morgan-1.8.1.tgz#f93023d3887bd27b78dfd6023cea7892ee27a4b1" + dependencies: + basic-auth "~1.1.0" + debug "2.6.1" + depd "~1.1.0" + on-finished "~2.3.0" + on-headers "~1.0.1" + + mout@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/mout/-/mout-1.0.0.tgz#9bdf1d4af57d66d47cb353a6335a3281098e1501" + + ms@0.7.1: + version "0.7.1" + resolved "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + + ms@0.7.2: + version "0.7.2" + resolved "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + + ms@0.7.3: + version "0.7.3" + resolved "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff" + + mustache@^2.2.1: + version "2.3.0" + resolved "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" + + mute-stream@0.0.5: + version "0.0.5" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + + mute-stream@0.0.6: + version "0.0.6" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" + + negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + + node-fetch@^1.3.3: + version "1.6.3" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + + node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + + node-modules-path@^1.0.0, node-modules-path@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" + + node-notifier@^5.0.1: + version "5.1.2" + resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff" + dependencies: + growly "^1.3.0" + semver "^5.3.0" + shellwords "^0.1.0" + which "^1.2.12" + + node-uuid@~1.4.0: + version "1.4.8" + resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" + + nopt@^3.0.3: + version "3.0.6" + resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + + nopt@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + + normalize-package-data@^2.3.2: + version "2.3.8" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + + normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + + npm-git-info@^1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" + + npm-package-arg@^4.1.1: + version "4.2.1" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" + dependencies: + hosted-git-info "^2.1.5" + semver "^5.1.0" + + npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + + npmlog@^4.0.0: + version "4.0.2" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.1" + set-blocking "~2.0.0" + + number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + + oauth-sign@~0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" + + oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + + object-assign@4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + + object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + + object-component@0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + + object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + + on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + + on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + + once@^1.3.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + + onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + + optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + + optionator@^0.8.1: + version "0.8.2" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + + options@>=0.0.5: + version "0.0.6" + resolved "https://registry.npmjs.org/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" + + ora@^0.2.0: + version "0.2.3" + resolved "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" + dependencies: + chalk "^1.1.1" + cli-cursor "^1.0.2" + cli-spinners "^0.1.2" + object-assign "^4.0.1" + + os-homedir@^1.0.0, os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + + os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + + os-shim@^0.1.2: + version "0.1.3" + resolved "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + + os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + + osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + + output-file-sync@^1.1.0: + version "1.1.2" + resolved "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + + p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + + p-limit@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" + + p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + + parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + + parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + + parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + + parsejson@0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" + dependencies: + better-assert "~1.0.0" + + parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + dependencies: + better-assert "~1.0.0" + + parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + dependencies: + better-assert "~1.0.0" + + parseurl@~1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + + path-exists@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" + + path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + + path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + + path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + + path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + + path-key@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + + path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + + path-posix@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + + path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + + path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + + pend@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + + phantomjs-prebuilt@^2.1.12: + version "2.1.14" + resolved "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz#d53d311fcfb7d1d08ddb24014558f1188c516da0" + dependencies: + es6-promise "~4.0.3" + extract-zip "~1.5.0" + fs-extra "~1.0.0" + hasha "~2.2.0" + kew "~0.7.0" + progress "~1.1.8" + request "~2.79.0" + request-progress "~2.0.1" + which "~1.2.10" + + pify@^2.0.0: + version "2.3.0" + resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + + pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + + pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + + plain-text-box-plot@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/plain-text-box-plot/-/plain-text-box-plot-0.0.1.tgz#d3b2e53071ea6706972318565761242f779c04b8" + + pluralize@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + + portfinder@^1.0.7: + version "1.0.13" + resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" + dependencies: + async "^1.5.2" + debug "^2.2.0" + mkdirp "0.5.x" + + prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + + preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + + pretender@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/pretender/-/pretender-1.0.0.tgz#9137c38718b4d89814478b7f208f70d3e441a0e9" + dependencies: + fake-xml-http-request "^1.3.0" + route-recognizer "^0.1.9" + + pretender@^1.4.2: + version "1.4.2" + resolved "https://registry.npmjs.org/pretender/-/pretender-1.4.2.tgz#dde9995dfdf75b28a3dd7a73cde2f9f612e5e8f4" + dependencies: + fake-xml-http-request "^1.4.0" + route-recognizer "^0.2.3" + + printf@^0.2.3: + version "0.2.5" + resolved "https://registry.npmjs.org/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" + + private@^0.1.6, private@~0.1.5: + version "0.1.7" + resolved "https://registry.npmjs.org/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" + + process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + + process-relative-require@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" + dependencies: + node-modules-path "^1.0.0" + + progress@^1.1.8, progress@~1.1.8: + version "1.1.8" + resolved "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + + promise-map-series@^0.2.1: + version "0.2.3" + resolved "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" + dependencies: + rsvp "^3.0.14" + + proxy-addr@~1.1.3: + version "1.1.4" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" + dependencies: + forwarded "~0.1.0" + ipaddr.js "1.3.0" + + pseudomap@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + + punycode@1.3.2: + version "1.3.2" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + + punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + + q@^1.1.2: + version "1.5.0" + resolved "https://registry.npmjs.org/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" + + qs@6.4.0, qs@^6.2.0: + version "6.4.0" + resolved "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + + qs@~1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" + + qs@~6.3.0: + version "6.3.2" + resolved "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" + + querystring@0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + + quick-temp@0.1.6, quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5: + version "0.1.6" + resolved "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.6.tgz#a6242a15cba9f9cdbd341287b5c569e318eec307" + dependencies: + mktemp "~0.4.0" + rimraf "~2.2.6" + underscore.string "~2.3.3" + + qunit-notifications@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/qunit-notifications/-/qunit-notifications-0.1.1.tgz#3001afc6a6a77dfbd962ccbcddde12dec5286c09" + + qunitjs@^1.20.0: + version "1.23.1" + resolved "https://registry.npmjs.org/qunitjs/-/qunitjs-1.23.1.tgz#1971cf97ac9be01a64d2315508d2e48e6fd4e719" + + randomatic@^1.1.3: + version "1.1.6" + resolved "https://registry.npmjs.org/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + dependencies: + is-number "^2.0.2" + kind-of "^3.0.2" + + range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + + raw-body@~1.1.0: + version "1.1.7" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + dependencies: + bytes "1" + string_decoder "0.10" + + raw-body@~2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" + dependencies: + bytes "2.4.0" + iconv-lite "0.4.15" + unpipe "1.0.0" + + read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + + read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + + readable-stream@^2, readable-stream@^2.0.6, readable-stream@~2.0.0: + version "2.0.6" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + + readable-stream@~1.0.2: + version "1.0.34" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + + readline2@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + mute-stream "0.0.5" + + recast@0.10.33: + version "0.10.33" + resolved "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" + dependencies: + ast-types "0.8.12" + esprima-fb "~15001.1001.0-dev-harmony-fb" + private "~0.1.5" + source-map "~0.5.0" + + recast@^0.10.10, recast@^0.10.29: + version "0.10.43" + resolved "https://registry.npmjs.org/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" + dependencies: + ast-types "0.8.15" + esprima-fb "~15001.1001.0-dev-harmony-fb" + private "~0.1.5" + source-map "~0.5.0" + + recast@^0.11.17, recast@^0.11.3: + version "0.11.23" + resolved "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" + dependencies: + ast-types "0.9.6" + esprima "~3.1.0" + private "~0.1.5" + source-map "~0.5.0" + + redeyed@~0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/redeyed/-/redeyed-0.5.0.tgz#7ab000e60ee3875ac115d29edb32c1403c6c25d1" + dependencies: + esprima-fb "~12001.1.0-dev-harmony-fb" + + regenerate@^1.2.1: + version "1.3.2" + resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + + regenerator-runtime@^0.10.0: + version "0.10.3" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e" + + regenerator-transform@0.9.11: + version "0.9.11" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.9.11.tgz#3a7d067520cb7b7176769eb5ff868691befe1283" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + + regenerator@0.8.40: + version "0.8.40" + resolved "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" + dependencies: + commoner "~0.10.3" + defs "~1.1.0" + esprima-fb "~15001.1001.0-dev-harmony-fb" + private "~0.1.5" + recast "0.10.33" + through "~2.3.8" + + regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + + regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + + regexpu@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" + dependencies: + esprima "^2.6.0" + recast "^0.10.10" + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + + regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + + regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + + remove-trailing-separator@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4" + + repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + + repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + + repeating@^1.1.0, repeating@^1.1.2: + version "1.1.3" + resolved "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" + dependencies: + is-finite "^1.0.0" + + repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + + request-progress@~2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" + dependencies: + throttleit "^1.0.0" + + request@~2.40.0: + version "2.40.0" + resolved "https://registry.npmjs.org/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" + dependencies: + forever-agent "~0.5.0" + json-stringify-safe "~5.0.0" + mime-types "~1.0.1" + node-uuid "~1.4.0" + qs "~1.0.0" + optionalDependencies: + aws-sign2 "~0.5.0" + form-data "~0.1.0" + hawk "1.1.1" + http-signature "~0.10.0" + oauth-sign "~0.3.0" + stringstream "~0.0.4" + tough-cookie ">=0.12.0" + tunnel-agent "~0.4.0" + + request@~2.79.0: + version "2.79.0" + resolved "https://registry.npmjs.org/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + + require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + + require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + + require-uncached@^1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + + requires-port@1.x.x: + version "1.0.0" + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + + resolve-dir@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" + dependencies: + expand-tilde "^1.2.2" + global-modules "^0.2.3" + + resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + + resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0: + version "1.3.3" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" + dependencies: + path-parse "^1.0.5" + + restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + + right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + + rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1: + version "2.5.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" + dependencies: + glob "^7.0.0" + + rimraf@^2.1.4, rimraf@^2.5.3, rimraf@^2.5.4: + version "2.6.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" + dependencies: + glob "^7.0.5" + + rimraf@~2.2.6: + version "2.2.8" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + + rollup@^0.41.4: + version "0.41.6" + resolved "https://registry.npmjs.org/rollup/-/rollup-0.41.6.tgz#e0d05497877a398c104d816d2733a718a7a94e2a" + dependencies: + source-map-support "^0.4.0" + + route-recognizer@^0.1.9: + version "0.1.11" + resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" + + route-recognizer@^0.2.3: + version "0.2.10" + resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" + + rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.6, rsvp@~3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + + rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: + version "3.5.0" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" + + rsvp@~3.0.6: + version "3.0.21" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" + + rsvp@~3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" + + run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + dependencies: + once "^1.3.0" + + run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + dependencies: + is-promise "^2.1.0" + + rx-lite@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + + rx@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + + safe-json-parse@~1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" + + sane@^1.1.1: + version "1.6.0" + resolved "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz#9610c452307a135d29c1fdfe2547034180c46775" + dependencies: + anymatch "^1.3.0" + exec-sh "^0.2.0" + fb-watchman "^1.8.0" + minimatch "^3.0.2" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.10.0" + + sanitize-filename@^1.5.3: + version "1.6.1" + resolved "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.1.tgz#612da1c96473fa02dccda92dcd5b4ab164a6772a" + dependencies: + truncate-utf8-bytes "^1.0.0" + + sax@1.2.1, sax@>=0.6.0: + version "1.2.1" + resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + + selenium-webdriver@^3.0.0-beta-2: + version "3.4.0" + resolved "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.4.0.tgz#151f7445294da6a66c49cc300747a2a17e53c52a" + dependencies: + adm-zip "^0.4.7" + rimraf "^2.5.4" + tmp "0.0.30" + xml2js "^0.4.17" + + "semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + + semver@^4.1.0, semver@^4.3.1: + version "4.3.6" + resolved "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + + semver@~5.0.1: + version "5.0.3" + resolved "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" + + send@0.15.1: + version "0.15.1" + resolved "https://registry.npmjs.org/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" + dependencies: + debug "2.6.1" + depd "~1.1.0" + destroy "~1.0.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.8.0" + fresh "0.5.0" + http-errors "~1.6.1" + mime "1.3.4" + ms "0.7.2" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.3.1" + + serve-static@1.12.1: + version "1.12.1" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039" + dependencies: + encodeurl "~1.0.1" + escape-html "~1.0.3" + parseurl "~1.3.1" + send "0.15.1" + + set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + + setprototypeof@1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + + shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + + shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + + shelljs@^0.6.0: + version "0.6.1" + resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" + + shellwords@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14" + + sigmund@~1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + + signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + + silent-error@^1.0.0, silent-error@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.0.1.tgz#71b7d503d1c6f94882b51b56be879b113cb4822c" + dependencies: + debug "^2.2.0" + + simple-dom@^0.3.0: + version "0.3.2" + resolved "https://registry.npmjs.org/simple-dom/-/simple-dom-0.3.2.tgz#0663d10f1556f1500551d518f56e3aba0871371d" + + simple-fmt@~0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" + + simple-is@~0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" + + slash@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + + slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + + slide@^1.1.5: + version "1.1.6" + resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + + sntp@0.2.x: + version "0.2.4" + resolved "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" + dependencies: + hoek "0.9.x" + + sntp@1.x.x: + version "1.0.9" + resolved "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + + socket.io-adapter@0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" + dependencies: + debug "2.3.3" + socket.io-parser "2.3.1" + + socket.io-client@1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" + dependencies: + backo2 "1.0.2" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "2.3.3" + engine.io-client "1.8.0" + 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" + + socket.io-parser@2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" + dependencies: + component-emitter "1.1.2" + debug "2.2.0" + isarray "0.0.1" + json3 "3.3.2" + + socket.io@1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" + dependencies: + debug "2.3.3" + engine.io "1.8.0" + has-binary "0.1.7" + object-assign "4.1.0" + socket.io-adapter "0.5.0" + socket.io-client "1.6.0" + socket.io-parser "2.3.1" + + sort-object-keys@^1.1.1: + version "1.1.2" + resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" + + sort-package-json@^1.4.0: + version "1.6.1" + resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.6.1.tgz#2ae463e4f5bb5d803bfdffdb4f92551c8fa66593" + dependencies: + sort-object-keys "^1.1.1" + + source-map-support@^0.2.10: + version "0.2.10" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" + dependencies: + source-map "0.1.32" + + source-map-support@^0.4.0, source-map-support@^0.4.2: + version "0.4.14" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef" + dependencies: + source-map "^0.5.6" + + source-map-url@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" + + source-map@0.1.32: + version "0.1.32" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" + dependencies: + amdefine ">=0.0.4" + + source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: + version "0.4.4" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + + source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: + version "0.5.6" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + + spawn-args@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" + + spawn-sync@^1.0.15: + version "1.0.15" + resolved "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + dependencies: + concat-stream "^1.4.7" + os-shim "^0.1.2" + + spawnback@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" + + spdx-correct@~1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + dependencies: + spdx-license-ids "^1.0.2" + + spdx-expression-parse@~1.0.0: + version "1.0.4" + resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + + spdx-license-ids@^1.0.2: + version "1.2.2" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + + sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + + sri-toolbox@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" + + sshpk@^1.7.0: + version "1.13.0" + resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz#ff2a3e4fd04497555fed97b39a0fd82fafb3a33c" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jodid25519 "^1.0.0" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + + stable@~0.1.3: + version "0.1.6" + resolved "https://registry.npmjs.org/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10" + + "statuses@>= 1.3.1 < 2", statuses@~1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + + stream-consume@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" + + string-template@~0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + + string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + + string-width@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^3.0.0" + + string_decoder@0.10, string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + + stringmap@~0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" + + stringset@~0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" + + stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + + strip-ansi@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" + dependencies: + ansi-regex "^0.2.1" + + strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + + strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + + strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + + strip-json-comments@~1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + + styled_string@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" + + sum-up@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" + dependencies: + chalk "^1.0.0" + + supports-color@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" + + supports-color@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + + supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + + symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: + version "1.1.8" + resolved "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" + + sync-exec@^0.6.2: + version "0.6.2" + resolved "https://registry.npmjs.org/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105" + + table@^3.7.8: + version "3.8.3" + resolved "https://registry.npmjs.org/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + dependencies: + ajv "^4.7.0" + ajv-keywords "^1.0.0" + chalk "^1.1.1" + lodash "^4.0.0" + slice-ansi "0.0.4" + string-width "^2.0.0" + + tap-parser@^5.1.0: + version "5.3.3" + resolved "https://registry.npmjs.org/tap-parser/-/tap-parser-5.3.3.tgz#53ec8a90f275d6fff43f169e56a679502a741185" + dependencies: + events-to-array "^1.0.1" + js-yaml "^3.2.7" + optionalDependencies: + readable-stream "^2" + + temp@0.8.3: + version "0.8.3" + resolved "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" + dependencies: + os-tmpdir "^1.0.0" + rimraf "~2.2.6" + + testem@1.15.0, testem@^1.8.1: + version "1.15.0" + resolved "https://registry.yarnpkg.com/testem/-/testem-1.15.0.tgz#2e3a9e7ac29f16a20f718eb0c4b12e7a44900675" + dependencies: + backbone "^1.1.2" + bluebird "^3.4.6" + charm "^1.0.0" + commander "^2.6.0" + consolidate "^0.14.0" + cross-spawn "^5.0.0" + express "^4.10.7" + fireworm "^0.7.0" + glob "^7.0.4" + http-proxy "^1.13.1" + js-yaml "^3.2.5" + lodash.assignin "^4.1.0" + lodash.clonedeep "^4.4.1" + lodash.find "^4.5.1" + mkdirp "^0.5.1" + mustache "^2.2.1" + node-notifier "^5.0.1" + npmlog "^4.0.0" + printf "^0.2.3" + rimraf "^2.4.4" + socket.io "1.6.0" + spawn-args "^0.2.0" + styled_string "0.0.1" + tap-parser "^5.1.0" + xmldom "^0.1.19" + + text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + + "textextensions@1 || 2": + version "2.1.0" + resolved "https://registry.npmjs.org/textextensions/-/textextensions-2.1.0.tgz#1be0dc2a0dc244d44be8a09af6a85afb93c4dbc3" + + throttleit@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" + + through@^2.3.6, through@^2.3.8, through@~2.3.8: + version "2.3.8" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + + tiny-lr@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.0.3.tgz#386731170ce521263a9d337f769ee8f11e88eb04" + dependencies: + body "^5.1.0" + debug "~2.2.0" + faye-websocket "~0.10.0" + livereload-js "^2.2.2" + object-assign "^4.1.0" + qs "^6.2.0" + + tmp-sync@^1.0.0: + version "1.1.2" + resolved "https://registry.npmjs.org/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" + dependencies: + fs-sync "^1.0.4" + osenv "^0.1.0" + + tmp@0.0.28: + version "0.0.28" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" + dependencies: + os-tmpdir "~1.0.1" + + tmp@0.0.30: + version "0.0.30" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + dependencies: + os-tmpdir "~1.0.1" + + tmp@^0.0.29: + version "0.0.29" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" + dependencies: + os-tmpdir "~1.0.1" + + tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + + to-array@0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + + to-fast-properties@^1.0.0, to-fast-properties@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + + tough-cookie@>=0.12.0, tough-cookie@~2.3.0: + version "2.3.2" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + dependencies: + punycode "^1.4.1" + + tree-sync@^1.2.1: + version "1.2.2" + resolved "https://registry.npmjs.org/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" + dependencies: + debug "^2.2.0" + fs-tree-diff "^0.5.6" + mkdirp "^0.5.1" + quick-temp "^0.1.5" + walk-sync "^0.2.7" + + trim-right@^1.0.0, trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + + truncate-utf8-bytes@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" + dependencies: + utf8-byte-length "^1.0.1" + + try-resolve@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" + + tryit@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + + tryor@~0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" + + tunnel-agent@~0.4.0, tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + + tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + + type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + + type-detect@0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" + + type-detect@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" + + type-is@~1.6.14: + version "1.6.15" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.15" + + typedarray@~0.0.5: + version "0.0.6" + resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + + uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" + + uglify-js@^2.6, uglify-js@^2.7.0: + version "2.8.22" + resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.22.tgz#d54934778a8da14903fa29a326fb24c0ab51a1a0" + dependencies: + source-map "~0.5.1" + yargs "~3.10.0" + optionalDependencies: + uglify-to-browserify "~1.0.0" + + uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + + ultron@1.0.x: + version "1.0.2" + resolved "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" + + underscore.string@~2.3.3: + version "2.3.3" + resolved "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" + + underscore@>=1.8.3: + version "1.8.3" + resolved "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + + unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + + untildify@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" + dependencies: + os-homedir "^1.0.0" + + url@0.10.3: + version "0.10.3" + resolved "https://registry.npmjs.org/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + + user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + + user-home@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + dependencies: + os-homedir "^1.0.0" + + utf8-byte-length@^1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" + + util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + + utils-merge@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + + uuid@3.0.1, uuid@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" + + uuid@^2.0.1: + version "2.0.3" + resolved "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" + + validate-npm-package-license@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + dependencies: + spdx-correct "~1.0.0" + spdx-expression-parse "~1.0.0" + + vary@~1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" + + verror@1.3.6: + version "1.3.6" + resolved "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + dependencies: + extsprintf "1.0.2" + + walk-sync@^0.1.3: + version "0.1.3" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" + + walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: + version "0.2.7" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" + dependencies: + ensure-posix-path "^1.0.0" + matcher-collection "^1.0.0" + + walk-sync@^0.3.0, walk-sync@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.1.tgz#558a16aeac8c0db59c028b73c66f397684ece465" + dependencies: + ensure-posix-path "^1.0.0" + matcher-collection "^1.0.0" + + walker@~1.0.5: + version "1.0.7" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + dependencies: + makeerror "1.0.x" + + watch@~0.10.0: + version "0.10.0" + resolved "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" + + websocket-driver@>=0.5.1: + version "0.6.5" + resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" + dependencies: + websocket-extensions ">=0.1.1" + + websocket-extensions@>=0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" + + which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + + which@^1.2.12, which@^1.2.9, which@~1.2.10: + version "1.2.14" + resolved "https://registry.npmjs.org/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" + dependencies: + isexe "^2.0.0" + + wide-align@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + dependencies: + string-width "^1.0.1" + + window-size@0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + + window-size@^0.1.2: + version "0.1.4" + resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" + + window-size@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + + wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + + wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + + wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + + wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + + wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + + write-file-atomic@^1.1.2: + version "1.3.3" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.3.tgz#831dd22d491bdc135180bb996a0eb3f8bf587791" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + slide "^1.1.5" + + write@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + + ws@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" + dependencies: + options ">=0.0.5" + ultron "1.0.x" + + ws@^1.0.1: + version "1.1.4" + resolved "https://registry.npmjs.org/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" + dependencies: + options ">=0.0.5" + ultron "1.0.x" + + wtf-8@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" + + xdg-basedir@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" + dependencies: + os-homedir "^1.0.0" + + xml2js@0.4.17, xml2js@^0.4.17: + version "0.4.17" + resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" + dependencies: + sax ">=0.6.0" + xmlbuilder "^4.1.0" + + xmlbuilder@4.2.1, xmlbuilder@^4.1.0: + version "4.2.1" + resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" + dependencies: + lodash "^4.0.0" + + xmldom@^0.1.19: + version "0.1.27" + resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" + + xmlhttprequest-ssl@1.5.3: + version "1.5.3" + resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" + + xtend@^4.0.0, xtend@~4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + + y18n@^3.2.0, y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + + yallist@^2.0.0: + version "2.1.2" + resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + + yam@0.0.22: + version "0.0.22" + resolved "https://registry.npmjs.org/yam/-/yam-0.0.22.tgz#38a76cb79a19284d9206ed49031e359a1340bd06" + dependencies: + fs-extra "^0.30.0" + lodash.merge "^4.4.0" + + yargs-parser@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-3.2.0.tgz#5081355d19d9d0c8c5d81ada908cb4e6d186664f" + dependencies: + camelcase "^3.0.0" + lodash.assign "^4.1.0" + + yargs@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/yargs/-/yargs-5.0.0.tgz#3355144977d05757dbb86d6e38ec056123b3a66e" + dependencies: + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + lodash.assign "^4.2.0" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + window-size "^0.2.0" + y18n "^3.2.1" + yargs-parser "^3.2.0" + + yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" + + yargs@~3.27.0: + version "3.27.0" + resolved "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" + dependencies: + camelcase "^1.2.1" + cliui "^2.1.0" + decamelize "^1.0.0" + os-locale "^1.4.0" + window-size "^0.1.2" + y18n "^3.2.0" + + yauzl@2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" + dependencies: + fd-slicer "~1.0.1" + + yeast@0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + + yui@^3.18.1: + version "3.18.1" + resolved "https://registry.npmjs.org/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" + dependencies: + request "~2.40.0" + + yuidocjs@~0.9.0: + version "0.9.0" + resolved "https://registry.npmjs.org/yuidocjs/-/yuidocjs-0.9.0.tgz#d2ff2b37cadf30e3d45385c58f5003e5a83f2723" + dependencies: + express "^4.13.1" + graceful-fs "^4.1.2" + markdown-it "^4.3.0" + mdn-links "^0.1.0" + minimatch "^2.0.8" + rimraf "^2.4.1" + yui "^3.18.1" + +Trace: + Error: registry.npmjs.org/amd-name-resolver: Invalid URI "registry.npmjs.org/amd-name-resolver" + at Request.init (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/node_modules/request/request.js:276:31) + at new Request (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/node_modules/request/request.js:130:8) + at request (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/node_modules/request/index.js:54:10) + at RequestManager.execute (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/lib/util/request-manager.js:354:17) + at RequestManager.shiftQueue (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/lib/util/request-manager.js:381:10) + at Promise (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/lib/util/request-manager.js:166:12) + at RequestManager.request (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/lib/util/request-manager.js:164:21) + at NpmRegistry.request (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/lib/registries/npm-registry.js:111:32) + at /Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/lib/resolvers/registries/npm-resolver.js:111:54 + at Generator.next () diff --git a/yarn.lock b/yarn.lock index b7d6d217283..21934e0002a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,8 +3,8 @@ "@types/node@*", "@types/node@^7.0.5": - version "7.0.13" - resolved "https://registry.npmjs.org/@types/node/-/node-7.0.13.tgz#1b0a53fe9ef9c3a5d061b126cc9b915bca43a3f5" + version "7.0.14" + resolved "https://registry.npmjs.org/@types/node/-/node-7.0.14.tgz#1470fa002a113316ac9d9ad163fc738c7a0de2a4" "@types/rimraf@^0.0.28": version "0.0.28" @@ -71,8 +71,8 @@ ajv-keywords@^1.0.0: resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" ajv@^4.1.3, ajv@^4.7.0: - version "4.11.7" - resolved "https://registry.npmjs.org/ajv/-/ajv-4.11.7.tgz#8655a5d86d0824985cc471a1d913fb6729a0ec48" + version "4.11.8" + resolved "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" dependencies: co "^4.6.0" json-stable-stringify "^1.0.1" @@ -245,7 +245,7 @@ ast-types@0.9.6: version "0.9.6" resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" -async-disk-cache@^1.0.0: +async-disk-cache@^1.2.1: version "1.3.1" resolved "https://registry.npmjs.org/async-disk-cache/-/async-disk-cache-1.3.1.tgz#3394010d9448b16205b01e0e2e704180805413d3" dependencies: @@ -273,8 +273,8 @@ asynckit@^0.4.0: resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" aws-sdk@^2.0.9: - version "2.45.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.45.0.tgz#045dbd323630170968306dc849d793dbb1e4444d" + version "2.48.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.48.0.tgz#c89bbdbd71fdd33457cd65c46c4080e4e44b2702" dependencies: buffer "4.9.1" crypto-browserify "1.0.9" @@ -515,6 +515,12 @@ babel-plugin-dead-code-elimination@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" +babel-plugin-debug-macros@^0.1.6: + version "0.1.7" + resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.7.tgz#69f5a3dc7d72f781354f18c611a3b007bb223511" + dependencies: + semver "^5.3.0" + babel-plugin-eval@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" @@ -607,7 +613,7 @@ babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz#76c295dc3a4741b1665adfd3167215dcff32a576" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz#76c295dc3a4741b1665adfd3167215dcff32a576" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" @@ -1065,6 +1071,18 @@ broccoli-asset-rewrite@^1.1.0: dependencies: broccoli-filter "^1.2.3" +broccoli-babel-transpiler@6.0.0-alpha.3: + version "6.0.0-alpha.3" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.0.0-alpha.3.tgz#4c46c800753242cc4109c44700db63dc3862d7d0" + dependencies: + babel-core "^6.14.0" + broccoli-funnel "^1.0.0" + broccoli-merge-trees "^1.0.0" + broccoli-persistent-filter "^1.0.1" + clone "^2.0.0" + hash-for-dep "^1.0.2" + json-stable-stringify "^1.0.0" + broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: version "5.6.2" resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.6.2.tgz#958c72e43575b2f0a862a5096dba1ce1ebc7d74d" @@ -1106,29 +1124,29 @@ broccoli-builder@^0.18.3: rsvp "^3.0.17" silent-error "^1.0.1" -broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.1: - version "2.0.4" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" +broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" - lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - symlink-or-copy "^1.0.0" - walk-sync "^0.2.0" + walk-sync "^0.2.5" -broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" +broccoli-caching-writer@~2.0.1: + version "2.0.4" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" + lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - walk-sync "^0.2.5" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" broccoli-clean-css@^1.1.0: version "1.1.0" @@ -1152,7 +1170,7 @@ broccoli-concat@^2.2.0: lodash.omit "^4.1.0" lodash.uniq "^4.2.0" -broccoli-concat@^3.0.4, broccoli-concat@^3.2.2: +broccoli-concat@^3.2.2: version "3.2.2" resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" dependencies: @@ -1257,7 +1275,7 @@ broccoli-lint-eslint@^2.0.0: json-stable-stringify "^1.0.1" md5-hex "^1.2.1" -broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^1.1.3, broccoli-merge-trees@^1.1.4, broccoli-merge-trees@^1.2.1: +broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^1.1.4, broccoli-merge-trees@^1.2.1: version "1.2.4" resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" dependencies: @@ -1270,6 +1288,13 @@ broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^ rimraf "^2.4.3" symlink-or-copy "^1.0.0" +broccoli-merge-trees@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-2.0.0.tgz#10aea46dd5cebcc8b8f7d5a54f0a84a4f0bb90b9" + dependencies: + broccoli-plugin "^1.3.0" + merge-trees "^1.0.1" + broccoli-merge-trees@~0.2.3: version "0.2.4" resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-0.2.4.tgz#1936f63bb09e24246b1e91d8c53162c0f7b24c3c" @@ -1286,11 +1311,10 @@ broccoli-middleware@^1.0.0-beta.8: mime "^1.2.11" broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0: - version "1.2.13" - resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.2.13.tgz#61368669e2b8f35238fdd38a2a896597e4a1c821" + version "1.3.1" + resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.3.1.tgz#d02556a135c77dfb859bba7844bc3539be7168e1" dependencies: - async-disk-cache "^1.0.0" - blank-object "^1.0.1" + async-disk-cache "^1.2.1" broccoli-plugin "^1.0.0" fs-tree-diff "^0.5.2" hash-for-dep "^1.0.2" @@ -1299,6 +1323,7 @@ broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-p md5-hex "^1.0.2" mkdirp "^0.5.1" promise-map-series "^0.2.1" + rimraf "^2.6.1" rsvp "^3.0.18" symlink-or-copy "^1.0.1" walk-sync "^0.3.1" @@ -1427,6 +1452,10 @@ bser@1.0.2: dependencies: node-int64 "^0.4.0" +buffer-shims@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + buffer@4.9.1: version "4.9.1" resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" @@ -1439,6 +1468,10 @@ builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" +builtins@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + bytes@1: version "1.0.0" resolved "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" @@ -1486,8 +1519,8 @@ can-symlink@^1.0.0: tmp "0.0.28" caniuse-db@^1.0.30000639: - version "1.0.30000660" - resolved "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000660.tgz#d2d57b309dc5a11bb5b46018f51855f7a41efee5" + version "1.0.30000664" + resolved "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000664.tgz#e16316e5fdabb9c7209b2bf0744ffc8a14201f22" capture-exit@^1.1.0: version "1.2.0" @@ -1784,6 +1817,17 @@ configstore@^2.0.0: write-file-atomic "^1.1.2" xdg-basedir "^2.0.0" +configstore@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/configstore/-/configstore-3.0.0.tgz#e1b8669c1803ccc50b545e92f8e6e79aa80e0196" + dependencies: + dot-prop "^4.1.0" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + unique-string "^1.0.0" + write-file-atomic "^1.1.2" + xdg-basedir "^3.0.0" + console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" @@ -1877,6 +1921,10 @@ crypto-browserify@1.0.9: version "1.0.9" resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" +crypto-random-string@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + ctype@0.5.3: version "0.5.3" resolved "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" @@ -1897,9 +1945,9 @@ debug@0.7.4: version "0.7.4" resolved "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" -debug@2, debug@2.6.4, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0: - version "2.6.4" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0" +debug@2, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0: + version "2.6.6" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz#a9fa6fbe9ca43cf1e79f73b75c0189cbb7d6db5a" dependencies: ms "0.7.3" @@ -1921,6 +1969,12 @@ debug@2.6.1: dependencies: ms "0.7.2" +debug@2.6.4: + version "2.6.4" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0" + dependencies: + ms "0.7.3" + decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2013,10 +2067,14 @@ detective@^4.3.1: acorn "^4.0.3" defined "^1.0.0" -diff@1.4.0, diff@^1.3.1: +diff@1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" +diff@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" + doctrine@^1.2.2: version "1.5.0" resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" @@ -2030,6 +2088,12 @@ dot-prop@^3.0.0: dependencies: is-obj "^1.0.0" +dot-prop@^4.1.0: + version "4.1.1" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-4.1.1.tgz#a8493f0b7b5eeec82525b5c7587fa7de7ca859c1" + dependencies: + is-obj "^1.0.0" + ecc-jsbn@~0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" @@ -2073,10 +2137,11 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-c resolve "^1.1.2" ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.10, ember-cli-babel@^6.0.0-beta.7: - version "6.0.0" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.0.0.tgz#caab075780dca3759982c9f54ea70a9adb1f3550" + version "6.1.0" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.1.0.tgz#d9c83a7d0c67cc8a3ccb9bd082971c3593e54fad" dependencies: amd-name-resolver "0.0.6" + babel-plugin-debug-macros "^0.1.6" babel-plugin-transform-es2015-modules-amd "^6.24.0" babel-polyfill "^6.16.0" babel-preset-env "^1.2.0" @@ -2215,7 +2280,7 @@ ember-cli-path-utils@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" -ember-cli-preprocess-registry@^3.0.0: +ember-cli-preprocess-registry@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.1.tgz#38456c21c4d2b64945850cf9ec68db6ba769288a" dependencies: @@ -2316,21 +2381,22 @@ ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-ve semver "^5.3.0" ember-cli@^2.11.1: - version "2.12.2" - resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.12.2.tgz#eccae6359e5d4e49d509e6391dcdf1961848377a" + version "2.13.0" + resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.13.0.tgz#c80d06ff8e16a47b0b2e5fbdb8761feebca86368" dependencies: amd-name-resolver "0.0.6" + babel-plugin-transform-es2015-modules-amd "^6.24.0" bower-config "^1.3.0" bower-endpoint-parser "0.2.2" - broccoli-babel-transpiler "^5.6.2" + broccoli-babel-transpiler "6.0.0-alpha.3" broccoli-brocfile-loader "^0.18.0" broccoli-builder "^0.18.3" - broccoli-concat "^3.0.4" + broccoli-concat "^3.2.2" broccoli-config-loader "^1.0.0" broccoli-config-replace "^1.1.2" broccoli-funnel "^1.0.6" broccoli-funnel-reducer "^1.0.0" - broccoli-merge-trees "^1.1.3" + broccoli-merge-trees "^2.0.0" broccoli-middleware "^1.0.0-beta.8" broccoli-source "^1.1.0" broccoli-stew "^1.2.0" @@ -2339,19 +2405,19 @@ ember-cli@^2.11.1: chalk "^1.1.3" clean-base-url "^1.0.0" compression "^1.4.4" - configstore "^2.0.0" + configstore "^3.0.0" console-ui "^1.0.2" core-object "^3.0.0" - diff "^1.3.1" + diff "^3.2.0" ember-cli-broccoli-sane-watcher "^2.0.4" ember-cli-get-component-path-option "^1.0.0" ember-cli-is-package-missing "^1.0.0" ember-cli-legacy-blueprints "^0.1.2" ember-cli-lodash-subset "^1.0.11" ember-cli-normalize-entity-name "^1.0.0" - ember-cli-preprocess-registry "^3.0.0" + ember-cli-preprocess-registry "^3.1.0" ember-cli-string-utils "^1.0.0" - ember-try "^0.2.9" + ember-try "^0.2.14" ensure-posix-path "^1.0.2" escape-string-regexp "^1.0.3" execa "^0.6.0" @@ -2363,7 +2429,7 @@ ember-cli@^2.11.1: fs-extra "2.0.0" fs-tree-diff "^0.5.2" get-caller-file "^1.0.0" - git-repo-info "^1.0.4" + git-repo-info "^1.4.1" glob "7.1.1" heimdalljs "^0.2.3" heimdalljs-fs-monitor "^0.1.0" @@ -2377,28 +2443,29 @@ ember-cli@^2.11.1: json-stable-stringify "^1.0.1" leek "0.0.24" lodash.template "^4.2.5" - markdown-it "^8.2.0" + markdown-it "^8.3.0" markdown-it-terminal "0.0.4" minimatch "^3.0.0" - morgan "^1.5.2" + morgan "^1.8.1" node-modules-path "^1.0.0" - nopt "^4.0.0" + nopt "^3.0.6" npm-package-arg "^4.1.1" portfinder "^1.0.7" promise-map-series "^0.2.1" - quick-temp "0.1.6" - resolve "^1.1.6" + quick-temp "^0.1.8" + resolve "^1.3.0" rsvp "^3.3.3" - sane "^1.1.1" + sane "^1.6.0" semver "^5.1.1" silent-error "^1.0.0" sort-package-json "^1.4.0" symlink-or-copy "^1.1.8" temp "0.8.3" - testem "^1.8.1" + testem "^1.15.0" tiny-lr "^1.0.3" tree-sync "^1.2.1" uuid "^3.0.0" + validate-npm-package-name "^3.0.0" walk-sync "^0.3.0" yam "0.0.22" @@ -2503,7 +2570,7 @@ ember-try-config@^2.0.1: rsvp "^3.2.1" semver "^5.1.0" -ember-try@^0.2.9: +ember-try@^0.2.14: version "0.2.14" resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.14.tgz#d47e8fa38858d5683e47856e24a260b39e9caf4a" dependencies: @@ -2874,8 +2941,8 @@ express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: vary "~1.1.0" extend@3, extend@^3.0.0, extend@~3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + version "3.0.1" + resolved "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" external-editor@^1.1.0: version "1.1.1" @@ -2968,12 +3035,12 @@ file-entry-cache@^1.1.1: object-assign "^4.0.1" filename-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + version "2.0.1" + resolved "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" filesize@^3.1.3: - version "3.5.6" - resolved "https://registry.npmjs.org/filesize/-/filesize-3.5.6.tgz#5fd98f3eac94ec9516ef8ed5782fad84a01a0a1a" + version "3.5.9" + resolved "https://registry.npmjs.org/filesize/-/filesize-3.5.9.tgz#9e3dd8a9b124f5b2f1fb2ee9cd13a86c707bb222" fill-range@^2.1.0: version "2.2.3" @@ -3216,12 +3283,12 @@ get-stream@^3.0.0: resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" getpass@^0.1.1: - version "0.1.6" - resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + version "0.1.7" + resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" dependencies: assert-plus "^1.0.0" -git-repo-info@^1.0.4, git-repo-info@^1.1.2: +git-repo-info@^1.1.2, git-repo-info@^1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" @@ -3366,8 +3433,8 @@ growly@^1.3.0: resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" handlebars@^4.0.4: - version "4.0.6" - resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" + version "4.0.7" + resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.7.tgz#e97325aeb8ea0b9e12b9c4dd73c4c312ad0ede59" dependencies: async "^1.4.0" optimist "^0.6.1" @@ -3672,7 +3739,7 @@ is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" -is-buffer@^1.0.2: +is-buffer@^1.1.5: version "1.1.5" resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" @@ -3969,10 +4036,10 @@ kew@~0.7.0: resolved "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" kind-of@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" + version "3.2.0" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz#b58abe4d5c044ad33726a8c1525b48cf891bff07" dependencies: - is-buffer "^1.0.2" + is-buffer "^1.1.5" klassy@^0.1.3: version "0.1.3" @@ -4291,7 +4358,7 @@ markdown-it@^4.3.0, markdown-it@^4.4.0: mdurl "~1.0.0" uc.micro "^1.0.0" -markdown-it@^8.2.0: +markdown-it@^8.3.0: version "8.3.1" resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-8.3.1.tgz#2f4b622948ccdc193d66f3ca2d43125ac4ac7323" dependencies: @@ -4339,6 +4406,17 @@ merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" +merge-trees@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/merge-trees/-/merge-trees-1.0.1.tgz#ccbe674569787f9def17fd46e6525f5700bbd23e" + dependencies: + can-symlink "^1.0.0" + fs-tree-diff "^0.5.4" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + rimraf "^2.4.3" + symlink-or-copy "^1.0.0" + merge@^1.1.3, merge@^1.2.0, merge@~1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" @@ -4466,7 +4544,7 @@ moment-timezone@^0.3.0: version "2.18.1" resolved "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" -morgan@^1.5.2, morgan@^1.7.0: +morgan@^1.7.0, morgan@^1.8.1: version "1.8.1" resolved "https://registry.npmjs.org/morgan/-/morgan-1.8.1.tgz#f93023d3887bd27b78dfd6023cea7892ee27a4b1" dependencies: @@ -4536,19 +4614,12 @@ node-uuid@~1.4.0: version "1.4.8" resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" -nopt@^3.0.3: +nopt@^3.0.3, nopt@^3.0.6: version "3.0.6" resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: abbrev "1" -nopt@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - dependencies: - abbrev "1" - osenv "^0.1.4" - normalize-package-data@^2.3.2: version "2.3.8" resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" @@ -4690,7 +4761,7 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4: +osenv@^0.1.0, osenv@^0.1.3: version "0.1.4" resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" dependencies: @@ -4927,7 +4998,7 @@ q@^1.1.2: version "1.5.0" resolved "https://registry.npmjs.org/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" -qs@6.4.0, qs@^6.2.0: +qs@6.4.0, qs@^6.4.0: version "6.4.0" resolved "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" @@ -4943,13 +5014,13 @@ querystring@0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" -quick-temp@0.1.6, quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5: - version "0.1.6" - resolved "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.6.tgz#a6242a15cba9f9cdbd341287b5c569e318eec307" +quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: + version "0.1.8" + resolved "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" dependencies: mktemp "~0.4.0" - rimraf "~2.2.6" - underscore.string "~2.3.3" + rimraf "^2.5.4" + underscore.string "~3.3.4" qunit-notifications@^0.1.1: version "0.1.1" @@ -5000,15 +5071,16 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^2, readable-stream@^2.0.6, readable-stream@~2.0.0: - version "2.0.6" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" +readable-stream@^2, readable-stream@^2.0.6: + version "2.2.9" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8" dependencies: + buffer-shims "~1.0.0" core-util-is "~1.0.0" inherits "~2.0.1" isarray "~1.0.0" process-nextick-args "~1.0.6" - string_decoder "~0.10.x" + string_decoder "~1.0.0" util-deprecate "~1.0.1" readable-stream@~1.0.2: @@ -5020,6 +5092,17 @@ readable-stream@~1.0.2: isarray "0.0.1" string_decoder "~0.10.x" +readable-stream@~2.0.0: + version "2.0.6" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + readline2@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" @@ -5066,8 +5149,8 @@ regenerate@^1.2.1: resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" regenerator-runtime@^0.10.0: - version "0.10.3" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e" + version "0.10.5" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" regenerator-transform@0.9.11: version "0.9.11" @@ -5227,7 +5310,7 @@ resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" -resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0: +resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.0: version "1.3.3" resolved "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" dependencies: @@ -5246,13 +5329,13 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1: +rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.4, rimraf@^2.4.3, rimraf@^2.4.4: version "2.5.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" -rimraf@^2.1.4, rimraf@^2.5.3, rimraf@^2.5.4: +rimraf@^2.1.4, rimraf@^2.3.2, rimraf@^2.4.1, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: version "2.6.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: @@ -5276,11 +5359,11 @@ route-recognizer@^0.2.3: version "0.2.10" resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" -rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.6, rsvp@~3.2.1: +rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.6, rsvp@^3.2.1, rsvp@~3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" -rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: +rsvp@^3.0.14, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3, rsvp@^3.4.0: version "3.5.0" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" @@ -5316,7 +5399,7 @@ safe-json-parse@~1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" -sane@^1.1.1: +sane@^1.1.1, sane@^1.6.0: version "1.6.0" resolved "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz#9610c452307a135d29c1fdfe2547034180c46775" dependencies: @@ -5523,8 +5606,8 @@ source-map-support@^0.2.10: source-map "0.1.32" source-map-support@^0.4.0, source-map-support@^0.4.2: - version "0.4.14" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef" + version "0.4.15" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" dependencies: source-map "^0.5.6" @@ -5577,7 +5660,7 @@ spdx-license-ids@^1.0.2: version "1.2.2" resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" -sprintf-js@~1.0.2: +sprintf-js@^1.0.3, sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -5635,6 +5718,12 @@ string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" +string_decoder@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.0.tgz#f06f41157b664d86069f84bdbdc9b0d8ab281667" + dependencies: + buffer-shims "~1.0.0" + stringmap@~0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" @@ -5730,9 +5819,9 @@ temp@0.8.3: os-tmpdir "^1.0.0" rimraf "~2.2.6" -testem@1.15.0, testem@^1.8.1: +testem@1.15.0, testem@^1.15.0: version "1.15.0" - resolved "https://registry.yarnpkg.com/testem/-/testem-1.15.0.tgz#2e3a9e7ac29f16a20f718eb0c4b12e7a44900675" + resolved "https://registry.npmjs.org/testem/-/testem-1.15.0.tgz#2e3a9e7ac29f16a20f718eb0c4b12e7a44900675" dependencies: backbone "^1.1.2" bluebird "^3.4.6" @@ -5777,15 +5866,15 @@ through@^2.3.6, through@^2.3.8, through@~2.3.8: resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" tiny-lr@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.0.3.tgz#386731170ce521263a9d337f769ee8f11e88eb04" + version "1.0.4" + resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.0.4.tgz#d13becf37f8b7e963320f5743298e3e934c7329a" dependencies: body "^5.1.0" debug "~2.2.0" faye-websocket "~0.10.0" livereload-js "^2.2.2" object-assign "^4.1.0" - qs "^6.2.0" + qs "^6.4.0" tmp-sync@^1.0.0: version "1.1.2" @@ -5821,8 +5910,8 @@ to-array@0.1.4: resolved "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" to-fast-properties@^1.0.0, to-fast-properties@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + version "1.0.3" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" tough-cookie@>=0.12.0, tough-cookie@~2.3.0: version "2.3.2" @@ -5916,14 +6005,23 @@ ultron@1.0.x: version "1.0.2" resolved "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" -underscore.string@~2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" +underscore.string@~3.3.4: + version "3.3.4" + resolved "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" + dependencies: + sprintf-js "^1.0.3" + util-deprecate "^1.0.2" underscore@>=1.8.3: version "1.8.3" resolved "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + dependencies: + crypto-random-string "^1.0.0" + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -5955,7 +6053,7 @@ utf8-byte-length@^1.0.1: version "1.0.4" resolved "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" -util-deprecate@~1.0.1: +util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -5978,6 +6076,12 @@ validate-npm-package-license@^3.0.1: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" +validate-npm-package-name@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + dependencies: + builtins "^1.0.3" + vary@~1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" @@ -6078,8 +6182,8 @@ wrappy@1: resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" write-file-atomic@^1.1.2: - version "1.3.3" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.3.tgz#831dd22d491bdc135180bb996a0eb3f8bf587791" + version "1.3.4" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -6115,6 +6219,10 @@ xdg-basedir@^2.0.0: dependencies: os-homedir "^1.0.0" +xdg-basedir@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + xml2js@0.4.17, xml2js@^0.4.17: version "0.4.17" resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" From 8bd124bbfa96657fedd35c9c0a350b193d3ad19b Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Sun, 30 Apr 2017 09:36:38 -0700 Subject: [PATCH 1925/2527] remove error log --- yarn-error.log | 6390 ------------------------------------------------ 1 file changed, 6390 deletions(-) delete mode 100644 yarn-error.log diff --git a/yarn-error.log b/yarn-error.log deleted file mode 100644 index 4e717490188..00000000000 --- a/yarn-error.log +++ /dev/null @@ -1,6390 +0,0 @@ -Arguments: - /Users/cthoburn/.nvm/versions/node/v7.4.0/bin/node /Users/cthoburn/.nvm/versions/node/v7.4.0/bin/yarn upgrade - -PATH: - /Users/cthoburn/.nvm/versions/node/v7.4.0/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/linkedin/bin:/opt/X11/bin:/export/content/linkedin/bin:/Users/cthoburn/.yarn/bin - -Yarn version: - 0.22.0 - -Node version: - 7.4.0 - -Platform: - darwin x64 - -npm manifest: - { - "name": "ember-data", - "version": "2.15.0-canary", - "description": "A data layer for your Ember applications.", - "repository": "git://github.com/emberjs/data.git", - "directories": { - "doc": "doc", - "test": "tests" - }, - "scripts": { - "build": "ember build", - "start": "ember server", - "test": "ember try:testall", - "node-tests": "node node-tests/nodetest-runner.js", - "test:optional-features": "ember test --environment=test-optional-features", - "test:production": "ember test --environment=production", - "bower": "bower install", - "production": "ember build --environment=production" - }, - "author": "", - "license": "MIT", - "dependencies": { - "amd-name-resolver": "0.0.5", - "babel-plugin-feature-flags": "^0.3.1", - "babel-plugin-filter-imports": "^0.3.1", - "babel6-plugin-strip-class-callcheck": "^6.0.0", - "babel6-plugin-strip-heimdall": "^6.0.1", - "broccoli-babel-transpiler": "^6.0.0", - "broccoli-file-creator": "^1.0.0", - "broccoli-funnel": "^1.2.0", - "broccoli-merge-trees": "^1.0.0", - "broccoli-rollup": "^1.2.0", - "chalk": "^1.1.1", - "ember-cli-babel": "^6.0.0-beta.10", - "ember-cli-path-utils": "^1.0.0", - "ember-cli-string-utils": "^1.0.0", - "ember-cli-test-info": "^1.0.0", - "ember-cli-version-checker": "^1.1.4", - "ember-inflector": "^2.0.0", - "ember-runtime-enumerable-includes-polyfill": "^2.0.0", - "exists-sync": "0.0.3", - "git-repo-info": "^1.1.2", - "heimdalljs": "^0.3.0", - "inflection": "^1.8.0", - "npm-git-info": "^1.0.0", - "semver": "^5.1.0", - "silent-error": "^1.0.0", - "testem": "1.15.0" - }, - "devDependencies": { - "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.24.1", - "babel-plugin-transform-es2015-classes": "^6.23.0", - "babel-plugin-transform-es2015-computed-properties": "^6.22.0", - "babel-plugin-transform-es2015-constants": "^6.1.4", - "babel-plugin-transform-es2015-destructuring": "^6.23.0", - "babel-plugin-transform-es2015-modules-amd": "^6.24.0", - "babel-plugin-transform-es2015-parameters": "^6.23.0", - "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "bower": "^1.6.5", - "broccoli-asset-rev": "^2.4.5", - "broccoli-concat": "^3.2.2", - "broccoli-stew": "^1.4.2", - "broccoli-string-replace": "^0.1.1", - "broccoli-uglify-sourcemap": "^1.0.1", - "broccoli-yuidoc": "^2.1.0", - "ember-ajax": "^2.4.1", - "ember-cli": "^2.11.1", - "ember-cli-app-version": "^2.0.0", - "ember-cli-blueprint-test-helpers": "0.11.0", - "ember-cli-dependency-checker": "^1.3.0", - "ember-cli-eslint": "1.3.0", - "ember-cli-htmlbars": "^1.1.1", - "ember-cli-htmlbars-inline-precompile": "^0.4.0-beta.2", - "ember-cli-inject-live-reload": "^1.4.1", - "ember-cli-internal-test-helpers": "^0.8.1", - "ember-cli-pretender": "^1.0.1", - "ember-cli-qunit": "^2.1.0", - "ember-cli-release": "^0.2.9", - "ember-cli-shims": "^1.0.2", - "ember-cli-sri": "^2.1.0", - "ember-cli-test-loader": "^1.1.0", - "ember-cli-uglify": "^1.2.0", - "ember-dev": "emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed", - "ember-disable-prototype-extensions": "^1.1.0", - "ember-disable-proxy-controllers": "^1.0.0", - "ember-export-application-global": "^1.0.5", - "ember-load-initializers": "^0.6.0", - "ember-publisher": "0.0.7", - "ember-resolver": "^2.0.3", - "ember-source": "~2.11.0", - "ember-watson": "^0.7.0", - "express": "^4.14.0", - "faker": "^3.1.0", - "github": "^1.1.1", - "glob": "5.0.13", - "heimdall-query": "^0.0.5", - "json-api-mock-server": "0.1.1", - "loader.js": "^4.2.2", - "mocha": "2.4.5", - "mocha-only-detector": "0.0.2", - "morgan": "^1.7.0", - "phantomjs-prebuilt": "^2.1.12", - "pretender": "1.0.0", - "rimraf": "2.5.2", - "rsvp": "3.2.1" - }, - "peerDependencies": { - "ember-inflector": "^2.0.0" - }, - "engines": { - "node": ">= 0.12.0" - }, - "keywords": [ - "ember-addon" - ], - "ember-addon": { - "configPath": "tests/dummy/config", - "paths": [ - "lib/enable-optional-features-via-url" - ], - "after": "ember-cli-mocha" - } - } - -yarn manifest: - No manifest - -Lockfile: - # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. - # yarn lockfile v1 - - - "@types/node@*", "@types/node@^7.0.5": - version "7.0.13" - resolved "https://registry.npmjs.org/@types/node/-/node-7.0.13.tgz#1b0a53fe9ef9c3a5d061b126cc9b915bca43a3f5" - - "@types/rimraf@^0.0.28": - version "0.0.28" - resolved "https://registry.npmjs.org/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06" - - "@types/tape@^4.2.29": - version "4.2.29" - resolved "https://registry.npmjs.org/@types/tape/-/tape-4.2.29.tgz#14cf2eb49bf852407eaaefdc53773eb90b32cf56" - dependencies: - "@types/node" "*" - - "@types/ws@^0.0.38": - version "0.0.38" - resolved "https://registry.npmjs.org/@types/ws/-/ws-0.0.38.tgz#42106fff4b422ca956734e29f0d73a6d893194d3" - dependencies: - "@types/node" "*" - - abbrev@1: - version "1.1.0" - resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" - - accepts@1.3.3, accepts@~1.3.3: - version "1.3.3" - resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" - dependencies: - mime-types "~2.1.11" - negotiator "0.6.1" - - acorn-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" - dependencies: - acorn "^3.0.4" - - acorn@^3.0.4: - version "3.3.0" - resolved "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - - acorn@^4.0.3: - version "4.0.11" - resolved "https://registry.npmjs.org/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0" - - acorn@^5.0.1: - version "5.0.3" - resolved "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d" - - adm-zip@^0.4.7: - version "0.4.7" - resolved "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" - - after@0.8.1: - version "0.8.1" - resolved "https://registry.npmjs.org/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" - - agent-base@2: - version "2.0.1" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz#bd8f9e86a8eb221fffa07bd14befd55df142815e" - dependencies: - extend "~3.0.0" - semver "~5.0.1" - - ajv-keywords@^1.0.0: - version "1.5.1" - resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" - - ajv@^4.1.3, ajv@^4.7.0: - version "4.11.7" - resolved "https://registry.npmjs.org/ajv/-/ajv-4.11.7.tgz#8655a5d86d0824985cc471a1d913fb6729a0ec48" - dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" - - align-text@^0.1.1, align-text@^0.1.3: - version "0.1.4" - resolved "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" - dependencies: - kind-of "^3.0.2" - longest "^1.0.1" - repeat-string "^1.5.2" - - alter@~0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" - dependencies: - stable "~0.1.3" - - amd-name-resolver@0.0.5: - version "0.0.5" - resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.5.tgz#76962dac876ed3311b05d29c6a58c14e1ef3304b" - dependencies: - ensure-posix-path "^1.0.1" - - amd-name-resolver@0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.6.tgz#d3e4ba2dfcaab1d820c1be9de947c67828cfe595" - dependencies: - ensure-posix-path "^1.0.1" - - amdefine@>=0.0.4: - version "1.0.1" - resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - - ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - - ansi-regex@^0.2.0, ansi-regex@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" - - ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - - ansi-styles@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" - - ansi-styles@^2.1.0, ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - - ansicolors@~0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" - - anymatch@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" - dependencies: - arrify "^1.0.0" - micromatch "^2.1.5" - - aproba@^1.0.3: - version "1.1.1" - resolved "https://registry.npmjs.org/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" - - are-we-there-yet@~1.1.2: - version "1.1.4" - resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - - argparse@^1.0.7, argparse@~1.0.2: - version "1.0.9" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" - dependencies: - sprintf-js "~1.0.2" - - arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - dependencies: - arr-flatten "^1.0.1" - - arr-flatten@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.3.tgz#a274ed85ac08849b6bd7847c4580745dc51adfb1" - - array-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" - - array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - - array-to-error@^1.0.0: - version "1.1.1" - resolved "https://registry.npmjs.org/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" - dependencies: - array-to-sentence "^1.1.0" - - array-to-sentence@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" - - array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - dependencies: - array-uniq "^1.0.1" - - array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - - array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - - arraybuffer.slice@0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" - - arrify@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - - asn1@0.1.11: - version "0.1.11" - resolved "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" - - asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - - assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - - assert-plus@^0.1.5: - version "0.1.5" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" - - assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - - assertion-error@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" - - ast-traverse@~0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" - - ast-types@0.8.12: - version "0.8.12" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" - - ast-types@0.8.15: - version "0.8.15" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" - - ast-types@0.9.6: - version "0.9.6" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" - - async-disk-cache@^1.0.0: - version "1.3.1" - resolved "https://registry.npmjs.org/async-disk-cache/-/async-disk-cache-1.3.1.tgz#3394010d9448b16205b01e0e2e704180805413d3" - dependencies: - debug "^2.1.3" - heimdalljs "^0.2.3" - istextorbinary "2.1.0" - mkdirp "^0.5.0" - rimraf "^2.5.3" - rsvp "^3.0.18" - - async@^1.4.0, async@^1.5.2: - version "1.5.2" - resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - - async@~0.2.9: - version "0.2.10" - resolved "https://registry.npmjs.org/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" - - async@~0.9.0: - version "0.9.2" - resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" - - asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - - aws-sdk@^2.0.9: - version "2.45.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.45.0.tgz#045dbd323630170968306dc849d793dbb1e4444d" - dependencies: - buffer "4.9.1" - crypto-browserify "1.0.9" - jmespath "0.15.0" - querystring "0.2.0" - sax "1.2.1" - url "0.10.3" - uuid "3.0.1" - xml2js "0.4.17" - xmlbuilder "4.2.1" - - aws-sign2@~0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" - - aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - - aws4@^1.2.1: - version "1.6.0" - resolved "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" - - babel-code-frame@^6.22.0: - version "6.22.0" - resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" - dependencies: - chalk "^1.1.0" - esutils "^2.0.2" - js-tokens "^3.0.0" - - babel-core@^5.0.0, babel-core@^5.8.22: - version "5.8.38" - resolved "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" - dependencies: - babel-plugin-constant-folding "^1.0.1" - babel-plugin-dead-code-elimination "^1.0.2" - babel-plugin-eval "^1.0.1" - babel-plugin-inline-environment-variables "^1.0.1" - babel-plugin-jscript "^1.0.4" - babel-plugin-member-expression-literals "^1.0.1" - babel-plugin-property-literals "^1.0.1" - babel-plugin-proto-to-assign "^1.0.3" - babel-plugin-react-constant-elements "^1.0.3" - babel-plugin-react-display-name "^1.0.3" - babel-plugin-remove-console "^1.0.1" - babel-plugin-remove-debugger "^1.0.1" - babel-plugin-runtime "^1.0.7" - babel-plugin-undeclared-variables-check "^1.0.2" - babel-plugin-undefined-to-void "^1.1.6" - babylon "^5.8.38" - bluebird "^2.9.33" - chalk "^1.0.0" - convert-source-map "^1.1.0" - core-js "^1.0.0" - debug "^2.1.1" - detect-indent "^3.0.0" - esutils "^2.0.0" - fs-readdir-recursive "^0.1.0" - globals "^6.4.0" - home-or-tmp "^1.0.0" - is-integer "^1.0.4" - js-tokens "1.0.1" - json5 "^0.4.0" - lodash "^3.10.0" - minimatch "^2.0.3" - output-file-sync "^1.1.0" - path-exists "^1.0.0" - path-is-absolute "^1.0.0" - private "^0.1.6" - regenerator "0.8.40" - regexpu "^1.3.0" - repeating "^1.1.2" - resolve "^1.1.6" - shebang-regex "^1.0.0" - slash "^1.0.0" - source-map "^0.5.0" - source-map-support "^0.2.10" - to-fast-properties "^1.0.0" - trim-right "^1.0.0" - try-resolve "^1.0.0" - - babel-core@^6.14.0, babel-core@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-core/-/babel-core-6.24.1.tgz#8c428564dce1e1f41fb337ec34f4c3b022b5ad83" - dependencies: - babel-code-frame "^6.22.0" - babel-generator "^6.24.1" - babel-helpers "^6.24.1" - babel-messages "^6.23.0" - babel-register "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - babylon "^6.11.0" - convert-source-map "^1.1.0" - debug "^2.1.1" - json5 "^0.5.0" - lodash "^4.2.0" - minimatch "^3.0.2" - path-is-absolute "^1.0.0" - private "^0.1.6" - slash "^1.0.0" - source-map "^0.5.0" - - babel-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-generator/-/babel-generator-6.24.1.tgz#e715f486c58ded25649d888944d52aa07c5d9497" - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.2.0" - source-map "^0.5.0" - trim-right "^1.0.1" - - babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" - dependencies: - babel-helper-explode-assignable-expression "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - - babel-helper-call-delegate@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - - babel-helper-define-map@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.24.1.tgz#7a9747f258d8947d32d515f6aa1c7bd02204a080" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - lodash "^4.2.0" - - babel-helper-explode-assignable-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - - babel-helper-function-name@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" - dependencies: - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - - babel-helper-get-function-arity@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - - babel-helper-hoist-variables@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - - babel-helper-optimise-call-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - - babel-helper-regex@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.24.1.tgz#d36e22fab1008d79d88648e32116868128456ce8" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - lodash "^4.2.0" - - babel-helper-remap-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - - babel-helper-replace-supers@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" - dependencies: - babel-helper-optimise-call-expression "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - - babel-helpers@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - - babel-messages@^6.23.0: - version "6.23.0" - resolved "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - dependencies: - babel-runtime "^6.22.0" - - babel-plugin-check-es2015-constants@^6.22.0: - version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" - dependencies: - babel-runtime "^6.22.0" - - babel-plugin-constant-folding@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" - - babel-plugin-dead-code-elimination@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" - - babel-plugin-eval@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" - - babel-plugin-feature-flags@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" - - babel-plugin-filter-imports@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.3.1.tgz#e7859b56886b175dd2616425d277b219e209ea8b" - - babel-plugin-htmlbars-inline-precompile@^0.2.3: - version "0.2.3" - resolved "https://registry.npmjs.org/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.3.tgz#cd365e278af409bfa6be7704c4354beee742446b" - - babel-plugin-inline-environment-variables@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" - - babel-plugin-jscript@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" - - babel-plugin-member-expression-literals@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" - - babel-plugin-property-literals@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" - - babel-plugin-proto-to-assign@^1.0.3: - version "1.0.4" - resolved "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" - dependencies: - lodash "^3.9.3" - - babel-plugin-react-constant-elements@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" - - babel-plugin-react-display-name@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" - - babel-plugin-remove-console@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" - - babel-plugin-remove-debugger@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" - - babel-plugin-runtime@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" - - babel-plugin-syntax-async-functions@^6.8.0: - version "6.13.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" - - babel-plugin-syntax-exponentiation-operator@^6.8.0: - version "6.13.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" - - babel-plugin-syntax-trailing-function-commas@^6.22.0: - version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" - - babel-plugin-transform-async-to-generator@^6.22.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-functions "^6.8.0" - babel-runtime "^6.22.0" - - babel-plugin-transform-es2015-arrow-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" - dependencies: - babel-runtime "^6.22.0" - - babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" - dependencies: - babel-runtime "^6.22.0" - - babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz#76c295dc3a4741b1665adfd3167215dcff32a576" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - lodash "^4.2.0" - - babel-plugin-transform-es2015-classes@^6.23.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" - dependencies: - babel-helper-define-map "^6.24.1" - babel-helper-function-name "^6.24.1" - babel-helper-optimise-call-expression "^6.24.1" - babel-helper-replace-supers "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - - babel-plugin-transform-es2015-computed-properties@^6.22.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - - babel-plugin-transform-es2015-constants@^6.1.4: - version "6.1.4" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-constants/-/babel-plugin-transform-es2015-constants-6.1.4.tgz#e4b8c78fb48ab98b0107f329fab6040e79c35a33" - dependencies: - babel-runtime "^5.0.0" - - babel-plugin-transform-es2015-destructuring@^6.23.0: - version "6.23.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" - dependencies: - babel-runtime "^6.22.0" - - babel-plugin-transform-es2015-duplicate-keys@^6.22.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - - babel-plugin-transform-es2015-for-of@^6.23.0: - version "6.23.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" - dependencies: - babel-runtime "^6.22.0" - - babel-plugin-transform-es2015-function-name@^6.22.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - - babel-plugin-transform-es2015-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" - dependencies: - babel-runtime "^6.22.0" - - babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" - dependencies: - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - - babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.1.tgz#d3e310b40ef664a36622200097c6d440298f2bfe" - dependencies: - babel-plugin-transform-strict-mode "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-types "^6.24.1" - - babel-plugin-transform-es2015-modules-systemjs@^6.23.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - - babel-plugin-transform-es2015-modules-umd@^6.23.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" - dependencies: - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - - babel-plugin-transform-es2015-object-super@^6.22.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" - dependencies: - babel-helper-replace-supers "^6.24.1" - babel-runtime "^6.22.0" - - babel-plugin-transform-es2015-parameters@^6.23.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" - dependencies: - babel-helper-call-delegate "^6.24.1" - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - - babel-plugin-transform-es2015-shorthand-properties@^6.22.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - - babel-plugin-transform-es2015-spread@^6.22.0: - version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" - dependencies: - babel-runtime "^6.22.0" - - babel-plugin-transform-es2015-sticky-regex@^6.22.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - - babel-plugin-transform-es2015-template-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" - dependencies: - babel-runtime "^6.22.0" - - babel-plugin-transform-es2015-typeof-symbol@^6.23.0: - version "6.23.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" - dependencies: - babel-runtime "^6.22.0" - - babel-plugin-transform-es2015-unicode-regex@^6.22.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - regexpu-core "^2.0.0" - - babel-plugin-transform-exponentiation-operator@^6.22.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" - dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" - babel-plugin-syntax-exponentiation-operator "^6.8.0" - babel-runtime "^6.22.0" - - babel-plugin-transform-regenerator@^6.22.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz#b8da305ad43c3c99b4848e4fe4037b770d23c418" - dependencies: - regenerator-transform "0.9.11" - - babel-plugin-transform-strict-mode@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - - babel-plugin-undeclared-variables-check@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" - dependencies: - leven "^1.0.2" - - babel-plugin-undefined-to-void@^1.1.6: - version "1.1.6" - resolved "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" - - babel-polyfill@^6.16.0: - version "6.23.0" - resolved "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d" - dependencies: - babel-runtime "^6.22.0" - core-js "^2.4.0" - regenerator-runtime "^0.10.0" - - babel-preset-env@^1.2.0: - version "1.4.0" - resolved "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.4.0.tgz#c8e02a3bcc7792f23cded68e0355b9d4c28f0f7a" - dependencies: - babel-plugin-check-es2015-constants "^6.22.0" - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-to-generator "^6.22.0" - babel-plugin-transform-es2015-arrow-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.23.0" - babel-plugin-transform-es2015-classes "^6.23.0" - babel-plugin-transform-es2015-computed-properties "^6.22.0" - babel-plugin-transform-es2015-destructuring "^6.23.0" - babel-plugin-transform-es2015-duplicate-keys "^6.22.0" - babel-plugin-transform-es2015-for-of "^6.23.0" - babel-plugin-transform-es2015-function-name "^6.22.0" - babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.22.0" - babel-plugin-transform-es2015-modules-commonjs "^6.23.0" - babel-plugin-transform-es2015-modules-systemjs "^6.23.0" - babel-plugin-transform-es2015-modules-umd "^6.23.0" - babel-plugin-transform-es2015-object-super "^6.22.0" - babel-plugin-transform-es2015-parameters "^6.23.0" - babel-plugin-transform-es2015-shorthand-properties "^6.22.0" - babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.22.0" - babel-plugin-transform-es2015-template-literals "^6.22.0" - babel-plugin-transform-es2015-typeof-symbol "^6.23.0" - babel-plugin-transform-es2015-unicode-regex "^6.22.0" - babel-plugin-transform-exponentiation-operator "^6.22.0" - babel-plugin-transform-regenerator "^6.22.0" - browserslist "^1.4.0" - invariant "^2.2.2" - - babel-register@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-register/-/babel-register-6.24.1.tgz#7e10e13a2f71065bdfad5a1787ba45bca6ded75f" - dependencies: - babel-core "^6.24.1" - babel-runtime "^6.22.0" - core-js "^2.4.0" - home-or-tmp "^2.0.0" - lodash "^4.2.0" - mkdirp "^0.5.1" - source-map-support "^0.4.2" - - babel-runtime@^5.0.0: - version "5.8.38" - resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz#1c0b02eb63312f5f087ff20450827b425c9d4c19" - dependencies: - core-js "^1.0.0" - - babel-runtime@^6.18.0, babel-runtime@^6.22.0: - version "6.23.0" - resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.10.0" - - babel-template@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-template/-/babel-template-6.24.1.tgz#04ae514f1f93b3a2537f2a0f60a5a45fb8308333" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - babylon "^6.11.0" - lodash "^4.2.0" - - babel-traverse@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.24.1.tgz#ab36673fd356f9a0948659e7b338d5feadb31695" - dependencies: - babel-code-frame "^6.22.0" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - babylon "^6.15.0" - debug "^2.2.0" - globals "^9.0.0" - invariant "^2.2.0" - lodash "^4.2.0" - - babel-types@^6.19.0, babel-types@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-types/-/babel-types-6.24.1.tgz#a136879dc15b3606bda0d90c1fc74304c2ff0975" - dependencies: - babel-runtime "^6.22.0" - esutils "^2.0.2" - lodash "^4.2.0" - to-fast-properties "^1.0.1" - - babel6-plugin-strip-class-callcheck@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" - - babel6-plugin-strip-heimdall@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" - - babylon@^5.8.38: - version "5.8.38" - resolved "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" - - babylon@^6.11.0, babylon@^6.15.0: - version "6.17.0" - resolved "https://registry.npmjs.org/babylon/-/babylon-6.17.0.tgz#37da948878488b9c4e3c4038893fa3314b3fc932" - - backbone@^1.1.2: - version "1.3.3" - resolved "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" - dependencies: - underscore ">=1.8.3" - - backo2@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" - - balanced-match@^0.4.1: - version "0.4.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" - - base64-arraybuffer@0.1.5: - version "0.1.5" - resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" - - base64-js@^1.0.2: - version "1.2.0" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" - - base64id@0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" - - basic-auth@~1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" - - bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - dependencies: - tweetnacl "^0.14.3" - - better-assert@~1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" - dependencies: - callsite "1.0.0" - - "binaryextensions@1 || 2": - version "2.0.0" - resolved "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.0.0.tgz#e597d1a7a6a3558a2d1c7241a16c99965e6aa40f" - - blank-object@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" - - blob@0.0.4: - version "0.0.4" - resolved "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" - - bluebird@^2.9.33: - version "2.11.0" - resolved "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" - - bluebird@^3.1.1, bluebird@^3.4.6: - version "3.5.0" - resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" - - body-parser@^1.15.2: - version "1.17.1" - resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.17.1.tgz#75b3bc98ddd6e7e0d8ffe750dfaca5c66993fa47" - dependencies: - bytes "2.4.0" - content-type "~1.0.2" - debug "2.6.1" - depd "~1.1.0" - http-errors "~1.6.1" - iconv-lite "0.4.15" - on-finished "~2.3.0" - qs "6.4.0" - raw-body "~2.2.0" - type-is "~1.6.14" - - body@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" - dependencies: - continuable-cache "^0.3.1" - error "^7.0.0" - raw-body "~1.1.0" - safe-json-parse "~1.0.1" - - boom@0.4.x: - version "0.4.2" - resolved "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" - dependencies: - hoek "0.9.x" - - boom@2.x.x: - version "2.10.1" - resolved "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - dependencies: - hoek "2.x.x" - - bower-config@^1.3.0: - version "1.4.0" - resolved "https://registry.npmjs.org/bower-config/-/bower-config-1.4.0.tgz#16c38c1135f8071c19f25938d61b0d8cbf18d3f1" - dependencies: - graceful-fs "^4.1.3" - mout "^1.0.0" - optimist "^0.6.1" - osenv "^0.1.3" - untildify "^2.1.0" - - bower-endpoint-parser@0.2.2: - version "0.2.2" - resolved "https://registry.npmjs.org/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" - - bower@^1.6.5: - version "1.8.0" - resolved "https://registry.npmjs.org/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a" - - brace-expansion@^1.0.0: - version "1.1.7" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" - dependencies: - balanced-match "^0.4.1" - concat-map "0.0.1" - - braces@^1.8.2: - version "1.8.5" - resolved "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - - breakable@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" - - broccoli-asset-rev@^2.4.5: - version "2.5.0" - resolved "https://registry.npmjs.org/broccoli-asset-rev/-/broccoli-asset-rev-2.5.0.tgz#f5f66eac962bf9f086286921f0eaeaab6d00d819" - dependencies: - broccoli-asset-rewrite "^1.1.0" - broccoli-filter "^1.2.2" - json-stable-stringify "^1.0.0" - matcher-collection "^1.0.1" - rsvp "^3.0.6" - - broccoli-asset-rewrite@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" - dependencies: - broccoli-filter "^1.2.3" - - broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: - version "5.6.2" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.6.2.tgz#958c72e43575b2f0a862a5096dba1ce1ebc7d74d" - dependencies: - babel-core "^5.0.0" - broccoli-funnel "^1.0.0" - broccoli-merge-trees "^1.0.0" - broccoli-persistent-filter "^1.0.1" - clone "^0.2.0" - hash-for-dep "^1.0.2" - json-stable-stringify "^1.0.0" - - broccoli-babel-transpiler@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.0.0.tgz#a52c5404bf36236849da503b011fd41fe64a00a2" - dependencies: - babel-core "^6.14.0" - broccoli-funnel "^1.0.0" - broccoli-merge-trees "^1.0.0" - broccoli-persistent-filter "^1.0.1" - clone "^2.0.0" - hash-for-dep "^1.0.2" - json-stable-stringify "^1.0.0" - - broccoli-brocfile-loader@^0.18.0: - version "0.18.0" - resolved "https://registry.npmjs.org/broccoli-brocfile-loader/-/broccoli-brocfile-loader-0.18.0.tgz#2e86021c805c34ffc8d29a2fb721cf273e819e4b" - dependencies: - findup-sync "^0.4.2" - - broccoli-builder@^0.18.3: - version "0.18.4" - resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.4.tgz#abc6db2c07d214454918e2997ea87441b69b69d3" - dependencies: - heimdalljs "^0.2.0" - promise-map-series "^0.2.1" - quick-temp "^0.1.2" - rimraf "^2.2.8" - rsvp "^3.0.17" - silent-error "^1.0.1" - - broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.1: - version "2.0.4" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" - dependencies: - broccoli-kitchen-sink-helpers "^0.2.5" - broccoli-plugin "1.1.0" - debug "^2.1.1" - lodash-node "^3.2.0" - rimraf "^2.2.8" - rsvp "^3.0.17" - symlink-or-copy "^1.0.0" - walk-sync "^0.2.0" - - broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" - dependencies: - broccoli-kitchen-sink-helpers "^0.2.5" - broccoli-plugin "1.1.0" - debug "^2.1.1" - rimraf "^2.2.8" - rsvp "^3.0.17" - walk-sync "^0.2.5" - - broccoli-clean-css@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" - dependencies: - broccoli-persistent-filter "^1.1.6" - clean-css-promise "^0.1.0" - inline-source-map-comment "^1.0.5" - json-stable-stringify "^1.0.0" - - broccoli-concat@^2.2.0: - version "2.3.8" - resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-2.3.8.tgz#590cdcc021bb905b6c121d87c2d1d57df44a2a48" - dependencies: - broccoli-caching-writer "^2.3.1" - broccoli-kitchen-sink-helpers "^0.3.1" - broccoli-stew "^1.3.3" - fast-sourcemap-concat "^1.0.1" - fs-extra "^0.30.0" - lodash.merge "^4.3.0" - lodash.omit "^4.1.0" - lodash.uniq "^4.2.0" - - broccoli-concat@^3.0.4, broccoli-concat@^3.2.2: - version "3.2.2" - resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" - dependencies: - broccoli-kitchen-sink-helpers "^0.3.1" - broccoli-plugin "^1.3.0" - broccoli-stew "^1.3.3" - ensure-posix-path "^1.0.2" - fast-sourcemap-concat "^1.0.1" - find-index "^1.1.0" - fs-extra "^1.0.0" - fs-tree-diff "^0.5.6" - lodash.merge "^4.3.0" - lodash.omit "^4.1.0" - lodash.uniq "^4.2.0" - walk-sync "^0.3.1" - - broccoli-config-loader@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/broccoli-config-loader/-/broccoli-config-loader-1.0.0.tgz#c3cf5ecfaffc04338c6f1d5d38dc36baeaa131ba" - dependencies: - broccoli-caching-writer "^2.0.4" - - broccoli-config-replace@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" - dependencies: - broccoli-kitchen-sink-helpers "^0.3.1" - broccoli-plugin "^1.2.0" - debug "^2.2.0" - fs-extra "^0.24.0" - - broccoli-file-creator@^1.0.0: - version "1.1.1" - resolved "https://registry.npmjs.org/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" - dependencies: - broccoli-kitchen-sink-helpers "~0.2.0" - broccoli-plugin "^1.1.0" - broccoli-writer "~0.1.1" - mkdirp "^0.5.1" - rsvp "~3.0.6" - symlink-or-copy "^1.0.1" - - broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: - version "1.2.4" - resolved "https://registry.npmjs.org/broccoli-filter/-/broccoli-filter-1.2.4.tgz#409afb94b9a3a6da9fac8134e91e205f40cc7330" - dependencies: - broccoli-kitchen-sink-helpers "^0.3.1" - broccoli-plugin "^1.0.0" - copy-dereference "^1.0.0" - debug "^2.2.0" - mkdirp "^0.5.1" - promise-map-series "^0.2.1" - rsvp "^3.0.18" - symlink-or-copy "^1.0.1" - walk-sync "^0.3.1" - - broccoli-funnel-reducer@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" - - broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli-funnel@^1.1.0, broccoli-funnel@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" - dependencies: - array-equal "^1.0.0" - blank-object "^1.0.1" - broccoli-plugin "^1.3.0" - debug "^2.2.0" - exists-sync "0.0.4" - fast-ordered-set "^1.0.0" - fs-tree-diff "^0.5.3" - heimdalljs "^0.2.0" - minimatch "^3.0.0" - mkdirp "^0.5.0" - path-posix "^1.0.0" - rimraf "^2.4.3" - symlink-or-copy "^1.0.0" - walk-sync "^0.3.1" - - broccoli-kitchen-sink-helpers@^0.2.5, broccoli-kitchen-sink-helpers@~0.2.0: - version "0.2.9" - resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" - dependencies: - glob "^5.0.10" - mkdirp "^0.5.1" - - broccoli-kitchen-sink-helpers@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" - dependencies: - glob "^5.0.10" - mkdirp "^0.5.1" - - broccoli-lint-eslint@^2.0.0: - version "2.7.0" - resolved "https://registry.npmjs.org/broccoli-lint-eslint/-/broccoli-lint-eslint-2.7.0.tgz#a2d905d02b397a90ae82439f283c459ef819f140" - dependencies: - broccoli-persistent-filter "^1.2.0" - escape-string-regexp "^1.0.5" - eslint "^2.13.0" - js-string-escape "^1.0.1" - json-stable-stringify "^1.0.1" - md5-hex "^1.2.1" - - broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^1.1.3, broccoli-merge-trees@^1.1.4, broccoli-merge-trees@^1.2.1: - version "1.2.4" - resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" - dependencies: - broccoli-plugin "^1.3.0" - can-symlink "^1.0.0" - fast-ordered-set "^1.0.2" - fs-tree-diff "^0.5.4" - heimdalljs "^0.2.1" - heimdalljs-logger "^0.1.7" - rimraf "^2.4.3" - symlink-or-copy "^1.0.0" - - broccoli-merge-trees@~0.2.3: - version "0.2.4" - resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-0.2.4.tgz#1936f63bb09e24246b1e91d8c53162c0f7b24c3c" - dependencies: - broccoli-plugin "^1.0.0" - debug "^2.2.0" - symlink-or-copy "^1.0.0" - - broccoli-middleware@^1.0.0-beta.8: - version "1.0.0-beta.8" - resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-1.0.0-beta.8.tgz#89cb6a9950ff0cf5bd75071d83d7cd6f6a11a95b" - dependencies: - handlebars "^4.0.4" - mime "^1.2.11" - - broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0: - version "1.2.13" - resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.2.13.tgz#61368669e2b8f35238fdd38a2a896597e4a1c821" - dependencies: - async-disk-cache "^1.0.0" - blank-object "^1.0.1" - broccoli-plugin "^1.0.0" - fs-tree-diff "^0.5.2" - hash-for-dep "^1.0.2" - heimdalljs "^0.2.1" - heimdalljs-logger "^0.1.7" - md5-hex "^1.0.2" - mkdirp "^0.5.1" - promise-map-series "^0.2.1" - rsvp "^3.0.18" - symlink-or-copy "^1.0.1" - walk-sync "^0.3.1" - - broccoli-plugin@1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" - dependencies: - promise-map-series "^0.2.1" - quick-temp "^0.1.3" - rimraf "^2.3.4" - symlink-or-copy "^1.0.1" - - broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" - dependencies: - promise-map-series "^0.2.1" - quick-temp "^0.1.3" - rimraf "^2.3.4" - symlink-or-copy "^1.1.8" - - broccoli-rollup@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/broccoli-rollup/-/broccoli-rollup-1.2.0.tgz#627636c05837d894a85724ef9b7ca04d12b66751" - dependencies: - broccoli-plugin "^1.2.1" - es6-map "^0.1.4" - fs-extra "^0.30.0" - fs-tree-diff "^0.5.2" - heimdalljs "^0.2.1" - heimdalljs-logger "^0.1.7" - md5-hex "^1.3.0" - node-modules-path "^1.0.1" - rollup "^0.41.4" - symlink-or-copy "^1.1.8" - walk-sync "^0.3.1" - - broccoli-slow-trees@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" - dependencies: - heimdalljs "^0.2.1" - - broccoli-source@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" - - broccoli-sri-hash@^2.1.0: - version "2.1.2" - resolved "https://registry.npmjs.org/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" - dependencies: - broccoli-caching-writer "^2.2.0" - mkdirp "^0.5.1" - rsvp "^3.1.0" - sri-toolbox "^0.2.0" - symlink-or-copy "^1.0.1" - - broccoli-stew@^1.2.0, broccoli-stew@^1.3.3, broccoli-stew@^1.4.2: - version "1.4.2" - resolved "https://registry.npmjs.org/broccoli-stew/-/broccoli-stew-1.4.2.tgz#9ec4062fd7162c6026561a2fbf64558363aff8d6" - dependencies: - broccoli-funnel "^1.0.1" - broccoli-merge-trees "^1.0.0" - broccoli-persistent-filter "^1.1.6" - broccoli-plugin "^1.3.0" - chalk "^1.1.3" - debug "^2.4.0" - ensure-posix-path "^1.0.1" - fs-extra "^2.0.0" - minimatch "^3.0.2" - resolve "^1.1.6" - rsvp "^3.0.16" - sanitize-filename "^1.5.3" - symlink-or-copy "^1.1.8" - walk-sync "^0.3.0" - - broccoli-string-replace@^0.1.1: - version "0.1.2" - resolved "https://registry.npmjs.org/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" - dependencies: - broccoli-persistent-filter "^1.1.5" - minimatch "^3.0.3" - - broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: - version "1.5.2" - resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.2.tgz#04f84ab0db539031fa868ccfa563c9932d50cedb" - dependencies: - broccoli-plugin "^1.2.1" - debug "^2.2.0" - lodash.merge "^4.5.1" - matcher-collection "^1.0.0" - mkdirp "^0.5.0" - source-map-url "^0.3.0" - symlink-or-copy "^1.0.1" - uglify-js "^2.7.0" - walk-sync "^0.1.3" - - broccoli-writer@~0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/broccoli-writer/-/broccoli-writer-0.1.1.tgz#d4d71aa8f2afbc67a3866b91a2da79084b96ab2d" - dependencies: - quick-temp "^0.1.0" - rsvp "^3.0.6" - - broccoli-yuidoc@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/broccoli-yuidoc/-/broccoli-yuidoc-2.1.0.tgz#d208d5c056e421a51f0c7701e938229e7e85c2e6" - dependencies: - broccoli-caching-writer "~2.0.1" - broccoli-merge-trees "~0.2.3" - merge "~1.2.0" - rsvp "~3.1.0" - yuidocjs "~0.9.0" - - browserslist@^1.4.0: - version "1.7.7" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" - dependencies: - caniuse-db "^1.0.30000639" - electron-to-chromium "^1.2.7" - - bser@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" - dependencies: - node-int64 "^0.4.0" - - buffer@4.9.1: - version "4.9.1" - resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - - builtin-modules@^1.0.0: - version "1.1.1" - resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - - bytes@1: - version "1.0.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" - - bytes@2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" - - bytes@2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" - - calculate-cache-key-for-tree@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" - dependencies: - json-stable-stringify "^1.0.1" - - caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - dependencies: - callsites "^0.2.0" - - callsite@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" - - callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - - camelcase@^1.0.2, camelcase@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" - - camelcase@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" - - can-symlink@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" - dependencies: - tmp "0.0.28" - - caniuse-db@^1.0.30000639: - version "1.0.30000660" - resolved "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000660.tgz#d2d57b309dc5a11bb5b46018f51855f7a41efee5" - - capture-exit@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" - dependencies: - rsvp "^3.3.3" - - cardinal@^0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/cardinal/-/cardinal-0.5.0.tgz#00d5f661dbd4aabfdf7d41ce48a5a59bca35a291" - dependencies: - ansicolors "~0.2.1" - redeyed "~0.5.0" - - caseless@~0.11.0: - version "0.11.0" - resolved "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" - - center-align@^0.1.1: - version "0.1.3" - resolved "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" - dependencies: - align-text "^0.1.3" - lazy-cache "^1.0.3" - - chai-as-promised@^5.1.0: - version "5.3.0" - resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-5.3.0.tgz#09d7a402908aa70dfdbead53e5853fc79d3ef21c" - - chai-as-promised@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" - dependencies: - check-error "^1.0.2" - - chai-files@^1.0.0, chai-files@^1.1.0: - version "1.4.0" - resolved "https://registry.npmjs.org/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" - dependencies: - assertion-error "^1.0.1" - - chai@^3.3.0: - version "3.5.0" - resolved "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" - dependencies: - assertion-error "^1.0.1" - deep-eql "^0.1.3" - type-detect "^1.0.0" - - chalk@^0.5.1: - version "0.5.1" - resolved "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" - dependencies: - ansi-styles "^1.1.0" - escape-string-regexp "^1.0.0" - has-ansi "^0.1.0" - strip-ansi "^0.3.0" - supports-color "^0.2.0" - - chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - - charm@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" - dependencies: - inherits "^2.0.1" - - check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - - chrome-debugging-client@^0.2.4: - version "0.2.5" - resolved "https://registry.npmjs.org/chrome-debugging-client/-/chrome-debugging-client-0.2.5.tgz#b8e1a6c37283323b6ff5d60525f6ea1fc8899fbd" - dependencies: - "@types/node" "^7.0.5" - "@types/rimraf" "^0.0.28" - "@types/tape" "^4.2.29" - "@types/ws" "^0.0.38" - mktemp "^0.4.0" - rimraf "^2.5.1" - ws "^1.0.1" - - circular-json@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" - - clean-base-url@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" - - clean-css-promise@^0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" - dependencies: - array-to-error "^1.0.0" - clean-css "^3.4.5" - pinkie-promise "^2.0.0" - - clean-css@^3.4.5: - version "3.4.25" - resolved "https://registry.npmjs.org/clean-css/-/clean-css-3.4.25.tgz#9e9a52d5c1e6bc5123e1b2783fa65fe958946ede" - dependencies: - commander "2.8.x" - source-map "0.4.x" - - cli-cursor@^1.0.1, cli-cursor@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - dependencies: - restore-cursor "^1.0.1" - - cli-spinners@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" - - cli-table2@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" - dependencies: - lodash "^3.10.1" - string-width "^1.0.1" - optionalDependencies: - colors "^1.1.2" - - cli-table@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" - dependencies: - colors "1.0.3" - - cli-width@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" - - cliui@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" - dependencies: - center-align "^0.1.1" - right-align "^0.1.1" - wordwrap "0.0.2" - - cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - - clone@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" - - clone@^2.0.0: - version "2.1.1" - resolved "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" - - co@^4.6.0: - version "4.6.0" - resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - - code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - - colors@1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - - colors@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" - - colors@~0.6.0-1: - version "0.6.2" - resolved "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" - - combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" - dependencies: - delayed-stream "~1.0.0" - - combined-stream@~0.0.4: - version "0.0.7" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" - dependencies: - delayed-stream "0.0.5" - - commander@0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" - - commander@2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" - - commander@2.8.x: - version "2.8.1" - resolved "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" - dependencies: - graceful-readlink ">= 1.0.0" - - commander@^2.5.0, commander@^2.6.0, commander@^2.9.0: - version "2.9.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" - dependencies: - graceful-readlink ">= 1.0.0" - - commander@~2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" - - commoner@~0.10.3: - version "0.10.8" - resolved "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" - dependencies: - commander "^2.5.0" - detective "^4.3.1" - glob "^5.0.15" - graceful-fs "^4.1.2" - iconv-lite "^0.4.5" - mkdirp "^0.5.0" - private "^0.1.6" - q "^1.1.2" - recast "^0.11.17" - - component-bind@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" - - component-emitter@1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" - - component-emitter@1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" - - component-inherit@0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" - - compressible@~2.0.8: - version "2.0.10" - resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.10.tgz#feda1c7f7617912732b29bf8cf26252a20b9eecd" - dependencies: - mime-db ">= 1.27.0 < 2" - - compression@^1.4.4: - version "1.6.2" - resolved "https://registry.npmjs.org/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" - dependencies: - accepts "~1.3.3" - bytes "2.3.0" - compressible "~2.0.8" - debug "~2.2.0" - on-headers "~1.0.1" - vary "~1.1.0" - - concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - - concat-stream@1.5.0, concat-stream@^1.4.6, concat-stream@^1.4.7: - version "1.5.0" - resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" - dependencies: - inherits "~2.0.1" - readable-stream "~2.0.0" - typedarray "~0.0.5" - - configstore@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" - dependencies: - dot-prop "^3.0.0" - graceful-fs "^4.1.2" - mkdirp "^0.5.0" - object-assign "^4.0.1" - os-tmpdir "^1.0.0" - osenv "^0.1.0" - uuid "^2.0.1" - write-file-atomic "^1.1.2" - xdg-basedir "^2.0.0" - - console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - - console-ui@^1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/console-ui/-/console-ui-1.0.3.tgz#31c524461b63422769f9e89c173495d91393721c" - dependencies: - chalk "^1.1.3" - inquirer "^1.2.3" - ora "^0.2.0" - through "^2.3.8" - - consolidate@^0.14.0: - version "0.14.5" - resolved "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" - dependencies: - bluebird "^3.1.1" - - content-disposition@0.5.2: - version "0.5.2" - resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" - - content-type@~1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" - - continuable-cache@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" - - convert-source-map@^1.1.0: - version "1.5.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" - - cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - - cookie@0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" - - copy-dereference@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" - - core-js@^1.0.0: - version "1.2.7" - resolved "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" - - core-js@^2.4.0: - version "2.4.1" - resolved "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" - - core-object@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" - - core-object@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/core-object/-/core-object-3.1.0.tgz#f5219fec2a19c40956f1c723d121890c88c5f677" - dependencies: - chalk "^1.1.3" - - core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - - cross-spawn@^5.0.0, cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - - cryptiles@0.2.x: - version "0.2.2" - resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" - dependencies: - boom "0.4.x" - - cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - dependencies: - boom "2.x.x" - - crypto-browserify@1.0.9: - version "1.0.9" - resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" - - ctype@0.5.3: - version "0.5.3" - resolved "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" - - d@1: - version "1.0.0" - resolved "https://registry.npmjs.org/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" - dependencies: - es5-ext "^0.10.9" - - dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" - - debug@0.7.4: - version "0.7.4" - resolved "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" - - debug@2, debug@2.6.4, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0: - version "2.6.4" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0" - dependencies: - ms "0.7.3" - - debug@2.2.0, debug@~2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" - dependencies: - ms "0.7.1" - - debug@2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" - dependencies: - ms "0.7.2" - - debug@2.6.1: - version "2.6.1" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" - dependencies: - ms "0.7.2" - - decamelize@^1.0.0, decamelize@^1.1.1: - version "1.2.0" - resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - - deep-eql@^0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" - dependencies: - type-detect "0.1.1" - - deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - - defined@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - - defs@~1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" - dependencies: - alter "~0.2.0" - ast-traverse "~0.1.1" - breakable "~1.0.0" - esprima-fb "~15001.1001.0-dev-harmony-fb" - simple-fmt "~0.1.0" - simple-is "~0.2.0" - stringmap "~0.2.2" - stringset "~0.2.1" - tryor "~0.1.2" - yargs "~3.27.0" - - del@^2.0.2: - version "2.2.2" - resolved "https://registry.npmjs.org/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" - dependencies: - globby "^5.0.0" - is-path-cwd "^1.0.0" - is-path-in-cwd "^1.0.0" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - rimraf "^2.2.8" - - delayed-stream@0.0.5: - version "0.0.5" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" - - delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - - delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - - depd@1.1.0, depd@~1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" - - destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - - detect-file@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" - dependencies: - fs-exists-sync "^0.1.0" - - detect-indent@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" - dependencies: - get-stdin "^4.0.1" - minimist "^1.1.0" - repeating "^1.1.0" - - detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - dependencies: - repeating "^2.0.0" - - detective@^4.3.1: - version "4.5.0" - resolved "https://registry.npmjs.org/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" - dependencies: - acorn "^4.0.3" - defined "^1.0.0" - - diff@1.4.0, diff@^1.3.1: - version "1.4.0" - resolved "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" - - doctrine@^1.2.2: - version "1.5.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - - dot-prop@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" - dependencies: - is-obj "^1.0.0" - - ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - dependencies: - jsbn "~0.1.0" - - editions@^1.1.1: - version "1.3.3" - resolved "https://registry.npmjs.org/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" - - ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - - electron-to-chromium@^1.2.7: - version "1.3.8" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.8.tgz#b2c8a2c79bb89fbbfd3724d9555e15095b5f5fb6" - - ember-ajax@^2.4.1: - version "2.5.6" - resolved "https://registry.npmjs.org/ember-ajax/-/ember-ajax-2.5.6.tgz#a75f743ccf1b95e979a5cf96013b3dba8fa625e4" - dependencies: - ember-cli-babel "^5.1.5" - - ember-cli-app-version@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/ember-cli-app-version/-/ember-cli-app-version-2.0.2.tgz#aaeede608e92fae6c2e11f63d28a373c1cc3f070" - dependencies: - ember-cli-babel "^5.1.6" - ember-cli-htmlbars "^1.0.0" - git-repo-version "0.4.1" - - ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.2.1: - version "5.2.4" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" - dependencies: - broccoli-babel-transpiler "^5.6.2" - broccoli-funnel "^1.0.0" - clone "^2.0.0" - ember-cli-version-checker "^1.0.2" - resolve "^1.1.2" - - ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.10, ember-cli-babel@^6.0.0-beta.7: - version "6.0.0" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.0.0.tgz#caab075780dca3759982c9f54ea70a9adb1f3550" - dependencies: - amd-name-resolver "0.0.6" - babel-plugin-transform-es2015-modules-amd "^6.24.0" - babel-polyfill "^6.16.0" - babel-preset-env "^1.2.0" - broccoli-babel-transpiler "^6.0.0" - broccoli-funnel "^1.0.0" - broccoli-source "^1.1.0" - clone "^2.0.0" - ember-cli-version-checker "^1.2.0" - - ember-cli-blueprint-test-helpers@0.11.0: - version "0.11.0" - resolved "https://registry.npmjs.org/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" - dependencies: - chai "^3.3.0" - chai-as-promised "^5.1.0" - chai-files "^1.0.0" - debug "^2.2.0" - ember-cli-internal-test-helpers "^0.8.1" - exists-sync "0.0.3" - findup "^0.1.5" - fs-extra "^0.26.7" - tmp-sync "^1.0.0" - walk-sync "^0.2.5" - - ember-cli-broccoli-sane-watcher@^2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.0.4.tgz#f43f42f75b7509c212fb926cd9aea86ae19264c6" - dependencies: - broccoli-slow-trees "^3.0.1" - heimdalljs "^0.2.1" - heimdalljs-logger "^0.1.7" - rsvp "^3.0.18" - sane "^1.1.1" - - ember-cli-dependency-checker@^1.3.0: - version "1.4.0" - resolved "https://registry.npmjs.org/ember-cli-dependency-checker/-/ember-cli-dependency-checker-1.4.0.tgz#2b13f977e1eea843fc1a21a001be6ca5d4ef1942" - dependencies: - chalk "^0.5.1" - is-git-url "^0.2.0" - semver "^4.1.0" - - ember-cli-eslint@1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/ember-cli-eslint/-/ember-cli-eslint-1.3.0.tgz#8a7eda0d7e6a00c5a5a823f59664932d6429a8f1" - dependencies: - broccoli-lint-eslint "^2.0.0" - ember-cli-babel "^5.1.5" - js-string-escape "^1.0.0" - - ember-cli-get-component-path-option@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" - - ember-cli-get-dependency-depth@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" - - ember-cli-htmlbars-inline-precompile@^0.4.0-beta.2: - version "0.4.0" - resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.0.tgz#4a6d2211b804419953104a9231e112dbd2057f3c" - dependencies: - babel-plugin-htmlbars-inline-precompile "^0.2.3" - ember-cli-version-checker "^1.2.0" - hash-for-dep "^1.0.2" - - ember-cli-htmlbars@^1.0.0, ember-cli-htmlbars@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-1.3.0.tgz#e090f011239153bf45dab29625f94a46fce205af" - dependencies: - broccoli-persistent-filter "^1.0.3" - ember-cli-version-checker "^1.0.2" - hash-for-dep "^1.0.2" - json-stable-stringify "^1.0.0" - strip-bom "^2.0.0" - - ember-cli-inject-live-reload@^1.4.1: - version "1.6.1" - resolved "https://registry.npmjs.org/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.6.1.tgz#82b8f5be454815a75e7f6d42c9ce0bc883a914a3" - - ember-cli-internal-test-helpers@^0.8.1: - version "0.8.3" - resolved "https://registry.npmjs.org/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.8.3.tgz#e9b7db67f3fda4db736d1a319a282c04beada495" - dependencies: - chai "^3.3.0" - chai-as-promised "^6.0.0" - chai-files "^1.1.0" - chalk "^1.1.1" - configstore "^2.0.0" - debug "^2.2.0" - exists-sync "0.0.3" - fs-extra "^0.30.0" - lodash "^4.0.0" - rsvp "^3.0.17" - symlink-or-copy "^1.0.1" - through "^2.3.8" - walk-sync "^0.3.1" - - ember-cli-is-package-missing@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" - - ember-cli-legacy-blueprints@^0.1.2: - version "0.1.4" - resolved "https://registry.npmjs.org/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.4.tgz#83d6c005ac0e39750ff9dd45cd1b78cf697150c6" - dependencies: - chalk "^1.1.1" - ember-cli-get-component-path-option "^1.0.0" - ember-cli-get-dependency-depth "^1.0.0" - ember-cli-is-package-missing "^1.0.0" - ember-cli-lodash-subset "^1.0.7" - ember-cli-normalize-entity-name "^1.0.0" - ember-cli-path-utils "^1.0.0" - ember-cli-string-utils "^1.0.0" - ember-cli-test-info "^1.0.0" - ember-cli-valid-component-name "^1.0.0" - ember-cli-version-checker "^1.1.7" - ember-router-generator "^1.0.0" - exists-sync "0.0.3" - fs-extra "^0.24.0" - inflection "^1.7.1" - rsvp "^3.0.17" - silent-error "^1.0.0" - - ember-cli-lodash-subset@^1.0.11, ember-cli-lodash-subset@^1.0.7: - version "1.0.12" - resolved "https://registry.npmjs.org/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" - - ember-cli-normalize-entity-name@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" - dependencies: - silent-error "^1.0.0" - - ember-cli-path-utils@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" - - ember-cli-preprocess-registry@^3.0.0: - version "3.1.1" - resolved "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.1.tgz#38456c21c4d2b64945850cf9ec68db6ba769288a" - dependencies: - broccoli-clean-css "^1.1.0" - broccoli-funnel "^1.0.0" - broccoli-merge-trees "^1.0.0" - debug "^2.2.0" - ember-cli-lodash-subset "^1.0.7" - exists-sync "0.0.3" - process-relative-require "^1.0.0" - silent-error "^1.0.0" - - ember-cli-pretender@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-1.0.1.tgz#35540babddef6f2778e91c627d190c73505103cd" - dependencies: - broccoli-funnel "^1.1.0" - broccoli-merge-trees "^1.2.1" - pretender "^1.4.2" - resolve "^1.2.0" - - ember-cli-qunit@^2.1.0: - version "2.2.6" - resolved "https://registry.npmjs.org/ember-cli-qunit/-/ember-cli-qunit-2.2.6.tgz#d802174724edd59b61ffdd0581fceb3236014dd1" - dependencies: - broccoli-babel-transpiler "^5.5.0" - broccoli-concat "^2.2.0" - broccoli-funnel "^1.0.1" - broccoli-merge-trees "^1.1.0" - ember-cli-babel "^5.1.5" - ember-cli-version-checker "^1.1.4" - ember-qunit "^0.4.18" - qunit-notifications "^0.1.1" - qunitjs "^1.20.0" - resolve "^1.1.6" - rsvp "^3.2.1" - - ember-cli-release@^0.2.9: - version "0.2.9" - resolved "https://registry.npmjs.org/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" - dependencies: - chalk "^1.0.0" - git-tools "^0.1.4" - make-array "^0.1.2" - merge "^1.2.0" - moment-timezone "^0.3.0" - nopt "^3.0.3" - rsvp "^3.0.17" - semver "^4.3.1" - silent-error "^1.0.0" - - ember-cli-shims@^1.0.2: - version "1.1.0" - resolved "https://registry.npmjs.org/ember-cli-shims/-/ember-cli-shims-1.1.0.tgz#0e3b8a048be865b4f81cc81d397ff1eeb13f75b6" - dependencies: - ember-cli-babel "^6.0.0-beta.7" - ember-cli-version-checker "^1.2.0" - silent-error "^1.0.1" - - ember-cli-sri@^2.1.0: - version "2.1.1" - resolved "https://registry.npmjs.org/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" - dependencies: - broccoli-sri-hash "^2.1.0" - - ember-cli-string-utils@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" - - ember-cli-test-info@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" - dependencies: - ember-cli-string-utils "^1.0.0" - - ember-cli-test-loader@^1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/ember-cli-test-loader/-/ember-cli-test-loader-1.1.1.tgz#333311209b18185d0e0e95f918349da10cacf0b1" - dependencies: - ember-cli-babel "^5.2.1" - - ember-cli-uglify@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/ember-cli-uglify/-/ember-cli-uglify-1.2.0.tgz#3208c32b54bc2783056e8bb0d5cfe9bbaf17ffb2" - dependencies: - broccoli-uglify-sourcemap "^1.0.0" - - ember-cli-valid-component-name@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" - dependencies: - silent-error "^1.0.0" - - ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7, ember-cli-version-checker@^1.2.0: - version "1.3.1" - resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz#0bc2d134c830142da64bf9627a0eded10b61ae72" - dependencies: - semver "^5.3.0" - - ember-cli@^2.11.1: - version "2.12.2" - resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.12.2.tgz#eccae6359e5d4e49d509e6391dcdf1961848377a" - dependencies: - amd-name-resolver "0.0.6" - bower-config "^1.3.0" - bower-endpoint-parser "0.2.2" - broccoli-babel-transpiler "^5.6.2" - broccoli-brocfile-loader "^0.18.0" - broccoli-builder "^0.18.3" - broccoli-concat "^3.0.4" - broccoli-config-loader "^1.0.0" - broccoli-config-replace "^1.1.2" - broccoli-funnel "^1.0.6" - broccoli-funnel-reducer "^1.0.0" - broccoli-merge-trees "^1.1.3" - broccoli-middleware "^1.0.0-beta.8" - broccoli-source "^1.1.0" - broccoli-stew "^1.2.0" - calculate-cache-key-for-tree "^1.0.0" - capture-exit "^1.1.0" - chalk "^1.1.3" - clean-base-url "^1.0.0" - compression "^1.4.4" - configstore "^2.0.0" - console-ui "^1.0.2" - core-object "^3.0.0" - diff "^1.3.1" - ember-cli-broccoli-sane-watcher "^2.0.4" - ember-cli-get-component-path-option "^1.0.0" - ember-cli-is-package-missing "^1.0.0" - ember-cli-legacy-blueprints "^0.1.2" - ember-cli-lodash-subset "^1.0.11" - ember-cli-normalize-entity-name "^1.0.0" - ember-cli-preprocess-registry "^3.0.0" - ember-cli-string-utils "^1.0.0" - ember-try "^0.2.9" - ensure-posix-path "^1.0.2" - escape-string-regexp "^1.0.3" - execa "^0.6.0" - exists-sync "0.0.4" - exit "^0.1.2" - express "^4.12.3" - filesize "^3.1.3" - find-up "^2.1.0" - fs-extra "2.0.0" - fs-tree-diff "^0.5.2" - get-caller-file "^1.0.0" - git-repo-info "^1.0.4" - glob "7.1.1" - heimdalljs "^0.2.3" - heimdalljs-fs-monitor "^0.1.0" - heimdalljs-graph "^0.3.1" - heimdalljs-logger "^0.1.7" - http-proxy "^1.9.0" - inflection "^1.7.0" - is-git-url "^0.2.0" - isbinaryfile "^3.0.0" - js-yaml "^3.6.1" - json-stable-stringify "^1.0.1" - leek "0.0.24" - lodash.template "^4.2.5" - markdown-it "^8.2.0" - markdown-it-terminal "0.0.4" - minimatch "^3.0.0" - morgan "^1.5.2" - node-modules-path "^1.0.0" - nopt "^4.0.0" - npm-package-arg "^4.1.1" - portfinder "^1.0.7" - promise-map-series "^0.2.1" - quick-temp "0.1.6" - resolve "^1.1.6" - rsvp "^3.3.3" - sane "^1.1.1" - semver "^5.1.1" - silent-error "^1.0.0" - sort-package-json "^1.4.0" - symlink-or-copy "^1.1.8" - temp "0.8.3" - testem "^1.8.1" - tiny-lr "^1.0.3" - tree-sync "^1.2.1" - uuid "^3.0.0" - walk-sync "^0.3.0" - yam "0.0.22" - - ember-dev@emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed: - version "0.0.0" - resolved "https://codeload.github.com/emberjs/ember-dev/tar.gz/bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed" - dependencies: - ember-cli-babel "^5.0.0" - - ember-disable-prototype-extensions@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.0.tgz#86081c8cf6741f26e4b89e2b004f761174313e01" - dependencies: - ember-cli-babel "^5.1.5" - - ember-disable-proxy-controllers@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" - dependencies: - ember-cli-babel "^5.0.0" - - ember-export-application-global@^1.0.5: - version "1.1.1" - resolved "https://registry.npmjs.org/ember-export-application-global/-/ember-export-application-global-1.1.1.tgz#f257d5271268932a89d7392679ce4db89d7154af" - dependencies: - ember-cli-babel "^5.1.10" - - ember-inflector@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-2.0.0.tgz#ac0870e87c0724bd42cf5ed7ef166c49a296ecfb" - dependencies: - ember-cli-babel "^6.0.0" - - ember-load-initializers@^0.6.0: - version "0.6.3" - resolved "https://registry.npmjs.org/ember-load-initializers/-/ember-load-initializers-0.6.3.tgz#f47396ad271ba77294068c98f992a5f19705441a" - dependencies: - ember-cli-babel "^5.1.6" - - ember-publisher@0.0.7: - version "0.0.7" - resolved "https://registry.npmjs.org/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" - dependencies: - aws-sdk "^2.0.9" - - ember-qunit@^0.4.18: - version "0.4.24" - resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-0.4.24.tgz#b54cf6688c442d07eacea47c3285879cdd7c2163" - dependencies: - ember-test-helpers "^0.5.32" - - ember-resolver@^2.0.3: - version "2.1.1" - resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-2.1.1.tgz#5e4c1fffe9f5f48fc2194ad7592274ed0cd74f72" - dependencies: - ember-cli-babel "^5.1.6" - ember-cli-version-checker "^1.1.6" - - ember-router-generator@^1.0.0: - version "1.2.3" - resolved "https://registry.npmjs.org/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" - dependencies: - recast "^0.11.3" - - ember-runtime-enumerable-includes-polyfill@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-2.0.0.tgz#6e9ba118bc909d1d7762de1b03a550d8955308a9" - dependencies: - ember-cli-babel "^6.0.0" - ember-cli-version-checker "^1.1.6" - - ember-source@~2.11.0: - version "2.11.3" - resolved "https://registry.npmjs.org/ember-source/-/ember-source-2.11.3.tgz#12c50cc2b4a7f8ae8c5daa3a72fb09415476c510" - dependencies: - broccoli-funnel "^1.0.6" - broccoli-merge-trees "^1.1.4" - ember-cli-get-component-path-option "^1.0.0" - ember-cli-normalize-entity-name "^1.0.0" - ember-cli-path-utils "^1.0.0" - ember-cli-string-utils "^1.0.0" - ember-cli-test-info "^1.0.0" - ember-cli-valid-component-name "^1.0.0" - ember-cli-version-checker "^1.1.7" - jquery "^3.1.1" - resolve "^1.1.7" - rsvp "^3.4.0" - simple-dom "^0.3.0" - - ember-test-helpers@^0.5.32: - version "0.5.34" - resolved "https://registry.npmjs.org/ember-test-helpers/-/ember-test-helpers-0.5.34.tgz#c8439108d1cba1d7d838c212208a5c4061471b83" - dependencies: - klassy "^0.1.3" - - ember-try-config@^2.0.1: - version "2.1.0" - resolved "https://registry.npmjs.org/ember-try-config/-/ember-try-config-2.1.0.tgz#e0e156229a542346a58ee6f6ad605104c98edfe0" - dependencies: - lodash "^4.6.1" - node-fetch "^1.3.3" - rsvp "^3.2.1" - semver "^5.1.0" - - ember-try@^0.2.9: - version "0.2.14" - resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.14.tgz#d47e8fa38858d5683e47856e24a260b39e9caf4a" - dependencies: - chalk "^1.0.0" - cli-table2 "^0.2.0" - core-object "^1.1.0" - debug "^2.2.0" - ember-cli-version-checker "^1.1.6" - ember-try-config "^2.0.1" - extend "^3.0.0" - fs-extra "^0.26.0" - promise-map-series "^0.2.1" - resolve "^1.1.6" - rimraf "^2.3.2" - rsvp "^3.0.17" - semver "^5.1.0" - sync-exec "^0.6.2" - - ember-watson@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" - dependencies: - babel-core "^5.8.22" - chalk "^1.0.0" - commander "^2.6.0" - exists-sync "0.0.3" - inflected "^1.1.6" - recast "^0.10.29" - walk-sync "^0.1.3" - - encodeurl@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" - - encoding@^0.1.11: - version "0.1.12" - resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" - dependencies: - iconv-lite "~0.4.13" - - engine.io-client@1.8.0: - version "1.8.0" - resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.0.tgz#7b730e4127414087596d9be3c88d2bc5fdb6cf5c" - dependencies: - component-emitter "1.2.1" - component-inherit "0.0.3" - debug "2.3.3" - engine.io-parser "1.3.1" - has-cors "1.1.0" - indexof "0.0.1" - parsejson "0.0.3" - parseqs "0.0.5" - parseuri "0.0.5" - ws "1.1.1" - xmlhttprequest-ssl "1.5.3" - yeast "0.1.2" - - engine.io-parser@1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" - dependencies: - after "0.8.1" - arraybuffer.slice "0.0.6" - base64-arraybuffer "0.1.5" - blob "0.0.4" - has-binary "0.1.6" - wtf-8 "1.0.0" - - engine.io@1.8.0: - version "1.8.0" - resolved "https://registry.npmjs.org/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" - dependencies: - accepts "1.3.3" - base64id "0.1.0" - cookie "0.3.1" - debug "2.3.3" - engine.io-parser "1.3.1" - ws "1.1.1" - - ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" - - entities@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" - - error-ex@^1.2.0: - version "1.3.1" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" - dependencies: - is-arrayish "^0.2.1" - - error@^7.0.0: - version "7.0.2" - resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" - dependencies: - string-template "~0.2.1" - xtend "~4.0.0" - - es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.15" - resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz#c330a5934c1ee21284a7c081a86e5fd937c91ea6" - dependencies: - es6-iterator "2" - es6-symbol "~3.1" - - es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" - dependencies: - d "1" - es5-ext "^0.10.14" - es6-symbol "^3.1" - - es6-map@^0.1.3, es6-map@^0.1.4: - version "0.1.5" - resolved "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-set "~0.1.5" - es6-symbol "~3.1.1" - event-emitter "~0.3.5" - - es6-promise@~4.0.3: - version "4.0.5" - resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" - - es6-set@~0.1.5: - version "0.1.5" - resolved "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-symbol "3.1.1" - event-emitter "~0.3.5" - - es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" - dependencies: - d "1" - es5-ext "~0.10.14" - - es6-weak-map@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" - dependencies: - d "1" - es5-ext "^0.10.14" - es6-iterator "^2.0.1" - es6-symbol "^3.1.1" - - escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - - escape-string-regexp@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" - - escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - - escope@^3.6.0: - version "3.6.0" - resolved "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" - dependencies: - es6-map "^0.1.3" - es6-weak-map "^2.0.1" - esrecurse "^4.1.0" - estraverse "^4.1.1" - - eslint@^2.13.0: - version "2.13.1" - resolved "https://registry.npmjs.org/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" - dependencies: - chalk "^1.1.3" - concat-stream "^1.4.6" - debug "^2.1.1" - doctrine "^1.2.2" - es6-map "^0.1.3" - escope "^3.6.0" - espree "^3.1.6" - estraverse "^4.2.0" - esutils "^2.0.2" - file-entry-cache "^1.1.1" - glob "^7.0.3" - globals "^9.2.0" - ignore "^3.1.2" - imurmurhash "^0.1.4" - inquirer "^0.12.0" - is-my-json-valid "^2.10.0" - is-resolvable "^1.0.0" - js-yaml "^3.5.1" - json-stable-stringify "^1.0.0" - levn "^0.3.0" - lodash "^4.0.0" - mkdirp "^0.5.0" - optionator "^0.8.1" - path-is-absolute "^1.0.0" - path-is-inside "^1.0.1" - pluralize "^1.2.1" - progress "^1.1.8" - require-uncached "^1.0.2" - shelljs "^0.6.0" - strip-json-comments "~1.0.1" - table "^3.7.8" - text-table "~0.2.0" - user-home "^2.0.0" - - espree@^3.1.6: - version "3.4.2" - resolved "https://registry.npmjs.org/espree/-/espree-3.4.2.tgz#38dbdedbedc95b8961a1fbf04734a8f6a9c8c592" - dependencies: - acorn "^5.0.1" - acorn-jsx "^3.0.0" - - esprima-fb@~12001.1.0-dev-harmony-fb: - version "12001.1.0-dev-harmony-fb" - resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-12001.1.0-dev-harmony-fb.tgz#d84400384ba95ce2678c617ad24a7f40808da915" - - esprima-fb@~15001.1001.0-dev-harmony-fb: - version "15001.1001.0-dev-harmony-fb" - resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" - - esprima@^1.2.2: - version "1.2.5" - resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" - - esprima@^2.6.0: - version "2.7.3" - resolved "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" - - esprima@^3.1.1, esprima@~3.1.0: - version "3.1.3" - resolved "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - - esprimaq@^0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" - - esrecurse@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" - dependencies: - estraverse "~4.1.0" - object-assign "^4.0.1" - - estraverse@^4.1.1, estraverse@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - - estraverse@~4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" - - esutils@^2.0.0, esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - - etag@~1.8.0: - version "1.8.0" - resolved "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" - - event-emitter@~0.3.5: - version "0.3.5" - resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - dependencies: - d "1" - es5-ext "~0.10.14" - - eventemitter3@1.x.x: - version "1.2.0" - resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" - - events-to-array@^1.0.1: - version "1.1.2" - resolved "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" - - exec-sh@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" - dependencies: - merge "^1.1.3" - - execa@^0.6.0: - version "0.6.3" - resolved "https://registry.npmjs.org/execa/-/execa-0.6.3.tgz#57b69a594f081759c69e5370f0d17b9cb11658fe" - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - - exists-sync@0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" - - exists-sync@0.0.4: - version "0.0.4" - resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" - - exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - - exit@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - - expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - dependencies: - is-posix-bracket "^0.1.0" - - expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - dependencies: - fill-range "^2.1.0" - - expand-tilde@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" - dependencies: - os-homedir "^1.0.1" - - express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: - version "4.15.2" - resolved "https://registry.npmjs.org/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35" - dependencies: - accepts "~1.3.3" - array-flatten "1.1.1" - content-disposition "0.5.2" - content-type "~1.0.2" - cookie "0.3.1" - cookie-signature "1.0.6" - debug "2.6.1" - depd "~1.1.0" - encodeurl "~1.0.1" - escape-html "~1.0.3" - etag "~1.8.0" - finalhandler "~1.0.0" - fresh "0.5.0" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.1" - path-to-regexp "0.1.7" - proxy-addr "~1.1.3" - qs "6.4.0" - range-parser "~1.2.0" - send "0.15.1" - serve-static "1.12.1" - setprototypeof "1.0.3" - statuses "~1.3.1" - type-is "~1.6.14" - utils-merge "1.0.0" - vary "~1.1.0" - - extend@3, extend@^3.0.0, extend@~3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" - - external-editor@^1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" - dependencies: - extend "^3.0.0" - spawn-sync "^1.0.15" - tmp "^0.0.29" - - extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - dependencies: - is-extglob "^1.0.0" - - extract-zip@~1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4" - dependencies: - concat-stream "1.5.0" - debug "0.7.4" - mkdirp "0.5.0" - yauzl "2.4.1" - - extsprintf@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" - - fake-xml-http-request@^1.3.0, fake-xml-http-request@^1.4.0: - version "1.5.0" - resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-1.5.0.tgz#d79602a97043d4d8fea671d5d904af38847b451d" - - faker@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/faker/-/faker-3.1.0.tgz#0f908faf4e6ec02524e54a57e432c5c013e08c9f" - - fast-levenshtein@~2.0.4: - version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - - fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" - dependencies: - blank-object "^1.0.1" - - fast-sourcemap-concat@^1.0.1: - version "1.1.0" - resolved "https://registry.npmjs.org/fast-sourcemap-concat/-/fast-sourcemap-concat-1.1.0.tgz#a800767abed5eda02e67238ec063a709be61f9d4" - dependencies: - chalk "^0.5.1" - debug "^2.2.0" - fs-extra "^0.30.0" - memory-streams "^0.1.0" - mkdirp "^0.5.0" - rsvp "^3.0.14" - source-map "^0.4.2" - source-map-url "^0.3.0" - - faye-websocket@~0.10.0: - version "0.10.0" - resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" - dependencies: - websocket-driver ">=0.5.1" - - fb-watchman@^1.8.0: - version "1.9.2" - resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383" - dependencies: - bser "1.0.2" - - fd-slicer@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" - dependencies: - pend "~1.2.0" - - figures@^1.3.5: - version "1.7.0" - resolved "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - - file-entry-cache@^1.1.1: - version "1.3.1" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" - dependencies: - flat-cache "^1.2.1" - object-assign "^4.0.1" - - filename-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" - - filesize@^3.1.3: - version "3.5.6" - resolved "https://registry.npmjs.org/filesize/-/filesize-3.5.6.tgz#5fd98f3eac94ec9516ef8ed5782fad84a01a0a1a" - - fill-range@^2.1.0: - version "2.2.3" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^1.1.3" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - - finalhandler@~1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.2.tgz#d0e36f9dbc557f2de14423df6261889e9d60c93a" - dependencies: - debug "2.6.4" - encodeurl "~1.0.1" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.1" - statuses "~1.3.1" - unpipe "~1.0.0" - - find-index@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" - - find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - - find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - dependencies: - locate-path "^2.0.0" - - findup-sync@^0.4.2: - version "0.4.3" - resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" - dependencies: - detect-file "^0.1.0" - is-glob "^2.0.1" - micromatch "^2.3.7" - resolve-dir "^0.1.0" - - findup@^0.1.5: - version "0.1.5" - resolved "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" - dependencies: - colors "~0.6.0-1" - commander "~2.1.0" - - fireworm@^0.7.0: - version "0.7.1" - resolved "https://registry.npmjs.org/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" - dependencies: - async "~0.2.9" - is-type "0.0.1" - lodash.debounce "^3.1.1" - lodash.flatten "^3.0.2" - minimatch "^3.0.2" - - flat-cache@^1.2.1: - version "1.2.2" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" - dependencies: - circular-json "^0.3.1" - del "^2.0.2" - graceful-fs "^4.1.2" - write "^0.2.1" - - follow-redirects@0.0.7: - version "0.0.7" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" - dependencies: - debug "^2.2.0" - stream-consume "^0.1.0" - - for-in@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - - for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - dependencies: - for-in "^1.0.1" - - forever-agent@~0.5.0: - version "0.5.2" - resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" - - forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - - form-data@~0.1.0: - version "0.1.4" - resolved "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" - dependencies: - async "~0.9.0" - combined-stream "~0.0.4" - mime "~1.2.11" - - form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - - forwarded@~0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" - - fresh@0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" - - fs-exists-sync@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" - - fs-extra@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-2.0.0.tgz#337352bded4a0b714f3eb84de8cea765e9d37600" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - - fs-extra@^0.24.0: - version "0.24.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - - fs-extra@^0.26.0, fs-extra@^0.26.7: - version "0.26.7" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - - fs-extra@^0.30.0: - version "0.30.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - - fs-extra@^1.0.0, fs-extra@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - - fs-extra@^2.0.0: - version "2.1.2" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - - fs-readdir-recursive@^0.1.0: - version "0.1.2" - resolved "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" - - fs-sync@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" - dependencies: - glob "^7.1.0" - iconv-lite "^0.4.13" - lodash "^4.16.1" - mkdirp "^0.5.1" - rimraf "^2.1.4" - - fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6: - version "0.5.6" - resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.6.tgz#342665749e8dca406800b672268c8f5073f3e623" - dependencies: - heimdalljs-logger "^0.1.7" - object-assign "^4.1.0" - path-posix "^1.0.0" - symlink-or-copy "^1.1.8" - - fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - - gauge@~2.7.1: - version "2.7.4" - resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - - generate-function@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" - - generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - dependencies: - is-property "^1.0.0" - - get-caller-file@^1.0.0, get-caller-file@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" - - get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - - get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - - getpass@^0.1.1: - version "0.1.6" - resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" - dependencies: - assert-plus "^1.0.0" - - git-repo-info@^1.0.4, git-repo-info@^1.1.2: - version "1.4.1" - resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" - - git-repo-info@~1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.2.0.tgz#43d8513e04a24dd441330a2f7c6655a709fdbaf2" - - git-repo-version@0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/git-repo-version/-/git-repo-version-0.4.1.tgz#75fab9a0a4ec8470755b0eea7fdaa6f9d41453bf" - dependencies: - git-repo-info "~1.2.0" - - git-tools@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" - dependencies: - spawnback "~1.0.0" - - github@^1.1.1: - version "1.4.0" - resolved "https://registry.npmjs.org/github/-/github-1.4.0.tgz#60aed8f16ffe381a3ca6dc6dba5bdd64445b7856" - dependencies: - follow-redirects "0.0.7" - https-proxy-agent "^1.0.0" - mime "^1.2.11" - - glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - - glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - dependencies: - is-glob "^2.0.0" - - glob@3.2.3: - version "3.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" - dependencies: - graceful-fs "~2.0.0" - inherits "2" - minimatch "~0.2.11" - - glob@5.0.13, glob@^5.0.10: - version "5.0.13" - resolved "https://registry.npmjs.org/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "^2.0.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - - glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1: - version "7.1.1" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.2" - once "^1.3.0" - path-is-absolute "^1.0.0" - - glob@^4.3.2: - version "4.5.3" - resolved "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "^2.0.1" - once "^1.3.0" - - glob@^5.0.15: - version "5.0.15" - resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - - global-modules@^0.2.3: - version "0.2.3" - resolved "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" - dependencies: - global-prefix "^0.1.4" - is-windows "^0.2.0" - - global-prefix@^0.1.4: - version "0.1.5" - resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" - dependencies: - homedir-polyfill "^1.0.0" - ini "^1.3.4" - is-windows "^0.2.0" - which "^1.2.12" - - globals@^6.4.0: - version "6.4.1" - resolved "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" - - globals@^9.0.0, globals@^9.2.0: - version "9.17.0" - resolved "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286" - - globby@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" - dependencies: - array-union "^1.0.1" - arrify "^1.0.0" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - - graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: - version "4.1.11" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - - graceful-fs@~2.0.0: - version "2.0.3" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" - - "graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - - growl@1.8.1: - version "1.8.1" - resolved "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428" - - growly@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - - handlebars@^4.0.4: - version "4.0.6" - resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" - dependencies: - async "^1.4.0" - optimist "^0.6.1" - source-map "^0.4.4" - optionalDependencies: - uglify-js "^2.6" - - har-validator@~2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" - dependencies: - chalk "^1.1.1" - commander "^2.9.0" - is-my-json-valid "^2.12.4" - pinkie-promise "^2.0.0" - - has-ansi@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" - dependencies: - ansi-regex "^0.2.0" - - has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - dependencies: - ansi-regex "^2.0.0" - - has-binary@0.1.6: - version "0.1.6" - resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" - dependencies: - isarray "0.0.1" - - has-binary@0.1.7: - version "0.1.7" - resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" - dependencies: - isarray "0.0.1" - - has-cors@1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" - - has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - - hash-for-dep@^1.0.2: - version "1.1.2" - resolved "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.1.2.tgz#e3347ed92960eb0bb53a2c6c2b70e36d75b7cd0c" - dependencies: - broccoli-kitchen-sink-helpers "^0.3.1" - heimdalljs "^0.2.3" - heimdalljs-logger "^0.1.7" - resolve "^1.1.6" - - hasha@~2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1" - dependencies: - is-stream "^1.0.1" - pinkie-promise "^2.0.0" - - hawk@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" - dependencies: - boom "0.4.x" - cryptiles "0.2.x" - hoek "0.9.x" - sntp "0.2.x" - - hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - - heimdall-query@^0.0.5: - version "0.0.5" - resolved "https://registry.npmjs.org/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" - dependencies: - chalk "^1.1.1" - chrome-debugging-client "^0.2.4" - cli-table "^0.3.1" - lodash "^4.15.0" - plain-text-box-plot "0.0.1" - progress "^1.1.8" - selenium-webdriver "^3.0.0-beta-2" - - heimdalljs-fs-monitor@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.1.0.tgz#d404a65688c6714c485469ed3495da4853440272" - dependencies: - heimdalljs "^0.2.0" - heimdalljs-logger "^0.1.7" - - heimdalljs-graph@^0.3.1: - version "0.3.3" - resolved "https://registry.npmjs.org/heimdalljs-graph/-/heimdalljs-graph-0.3.3.tgz#ea801dbba659c8d522fe1cb83b2d605726e4918f" - - heimdalljs-logger@^0.1.7: - version "0.1.9" - resolved "https://registry.npmjs.org/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz#d76ada4e45b7bb6f786fc9c010a68eb2e2faf176" - dependencies: - debug "^2.2.0" - heimdalljs "^0.2.0" - - heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3: - version "0.2.4" - resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.2.4.tgz#34ead16eab422c94803065d33abeba1f7b24a910" - dependencies: - rsvp "~3.2.1" - - heimdalljs@^0.3.0: - version "0.3.3" - resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" - dependencies: - rsvp "~3.2.1" - - hoek@0.9.x: - version "0.9.1" - resolved "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" - - hoek@2.x.x: - version "2.16.3" - resolved "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - - home-or-tmp@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" - dependencies: - os-tmpdir "^1.0.1" - user-home "^1.1.1" - - home-or-tmp@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.1" - - homedir-polyfill@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" - dependencies: - parse-passwd "^1.0.0" - - hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: - version "2.4.2" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.4.2.tgz#0076b9f46a270506ddbaaea56496897460612a67" - - http-errors@~1.6.1: - version "1.6.1" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257" - dependencies: - depd "1.1.0" - inherits "2.0.3" - setprototypeof "1.0.3" - statuses ">= 1.3.1 < 2" - - http-proxy@^1.13.1, http-proxy@^1.9.0: - version "1.16.2" - resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" - dependencies: - eventemitter3 "1.x.x" - requires-port "1.x.x" - - http-signature@~0.10.0: - version "0.10.1" - resolved "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" - dependencies: - asn1 "0.1.11" - assert-plus "^0.1.5" - ctype "0.5.3" - - http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - - https-proxy-agent@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" - dependencies: - agent-base "2" - debug "2" - extend "3" - - iconv-lite@0.4.15, iconv-lite@^0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13: - version "0.4.15" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" - - ieee754@^1.1.4: - version "1.1.8" - resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" - - ignore@^3.1.2: - version "3.2.7" - resolved "https://registry.npmjs.org/ignore/-/ignore-3.2.7.tgz#4810ca5f1d8eca5595213a34b94f2eb4ed926bbd" - - imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - - indexof@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" - - inflected@^1.1.6: - version "1.1.7" - resolved "https://registry.npmjs.org/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" - - inflection@^1.7.0, inflection@^1.7.1, inflection@^1.8.0: - version "1.12.0" - resolved "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" - - inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - - inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.1: - version "2.0.3" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - - ini@^1.3.4: - version "1.3.4" - resolved "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" - - inline-source-map-comment@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" - dependencies: - chalk "^1.0.0" - get-stdin "^4.0.1" - minimist "^1.1.1" - sum-up "^1.0.1" - xtend "^4.0.0" - - inquirer@^0.12.0: - version "0.12.0" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" - dependencies: - ansi-escapes "^1.1.0" - ansi-regex "^2.0.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" - cli-width "^2.0.0" - figures "^1.3.5" - lodash "^4.3.0" - readline2 "^1.0.1" - run-async "^0.1.0" - rx-lite "^3.1.2" - string-width "^1.0.1" - strip-ansi "^3.0.0" - through "^2.3.6" - - inquirer@^1.2.3: - version "1.2.3" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918" - dependencies: - ansi-escapes "^1.1.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" - cli-width "^2.0.0" - external-editor "^1.1.0" - figures "^1.3.5" - lodash "^4.3.0" - mute-stream "0.0.6" - pinkie-promise "^2.0.0" - run-async "^2.2.0" - rx "^4.1.0" - string-width "^1.0.1" - strip-ansi "^3.0.0" - through "^2.3.6" - - invariant@^2.2.0, invariant@^2.2.2: - version "2.2.2" - resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" - dependencies: - loose-envify "^1.0.0" - - invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - - ipaddr.js@1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec" - - is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - - is-buffer@^1.0.2: - version "1.1.5" - resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" - - is-builtin-module@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - dependencies: - builtin-modules "^1.0.0" - - is-dotfile@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" - - is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - dependencies: - is-primitive "^2.0.0" - - is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - - is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - - is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - dependencies: - number-is-nan "^1.0.0" - - is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - dependencies: - number-is-nan "^1.0.0" - - is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - - is-git-url@^0.2.0: - version "0.2.3" - resolved "https://registry.npmjs.org/is-git-url/-/is-git-url-0.2.3.tgz#445200d6fbd6da028fb5e01440d9afc93f3ccb64" - - is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - dependencies: - is-extglob "^1.0.0" - - is-integer@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/is-integer/-/is-integer-1.0.6.tgz#5273819fada880d123e1ac00a938e7172dd8d95e" - dependencies: - is-finite "^1.0.0" - - is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: - version "2.16.0" - resolved "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - - is-number@^2.0.2, is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - dependencies: - kind-of "^3.0.2" - - is-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - - is-path-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" - - is-path-in-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" - dependencies: - is-path-inside "^1.0.0" - - is-path-inside@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" - dependencies: - path-is-inside "^1.0.1" - - is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - - is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - - is-promise@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - - is-property@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - - is-resolvable@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" - dependencies: - tryit "^1.0.1" - - is-stream@^1.0.1, is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - - is-type@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" - dependencies: - core-util-is "~1.0.0" - - is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - - is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - - is-windows@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" - - isarray@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - - isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - - isbinaryfile@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" - - isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - - isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - dependencies: - isarray "1.0.0" - - isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - - istextorbinary@2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" - dependencies: - binaryextensions "1 || 2" - editions "^1.1.1" - textextensions "1 || 2" - - jade@0.26.3: - version "0.26.3" - resolved "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" - dependencies: - commander "0.6.1" - mkdirp "0.3.0" - - jmespath@0.15.0: - version "0.15.0" - resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" - - jodid25519@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" - dependencies: - jsbn "~0.1.0" - - jquery@^3.1.1: - version "3.2.1" - resolved "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787" - - js-string-escape@^1.0.0, js-string-escape@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" - - js-tokens@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" - - js-tokens@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" - - js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: - version "3.8.3" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766" - dependencies: - argparse "^1.0.7" - esprima "^3.1.1" - - jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - - jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - - jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - - json-api-mock-server@0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/json-api-mock-server/-/json-api-mock-server-0.1.1.tgz#00acb22ac58127e87fa9a172159cd8ed558e8106" - dependencies: - body-parser "^1.15.2" - chalk "^1.1.1" - express "^4.14.0" - glob "^7.1.1" - jsonapi-validator "^2.1.1" - object-assign "^4.1.0" - - json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - - json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - - json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - - json3@3.3.2: - version "3.3.2" - resolved "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" - - json5@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" - - json5@^0.5.0: - version "0.5.1" - resolved "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - - jsonapi-validator@^2.1.1: - version "2.2.0" - resolved "https://registry.npmjs.org/jsonapi-validator/-/jsonapi-validator-2.2.0.tgz#07f9bdb6d118c1e728fa77280605fa9b527f8c66" - dependencies: - ajv "^4.1.3" - yargs "^5.0.0" - - jsonfile@^2.1.0: - version "2.4.0" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - optionalDependencies: - graceful-fs "^4.1.6" - - jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - - jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - - jsprim@^1.2.2: - version "1.4.0" - resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" - dependencies: - assert-plus "1.0.0" - extsprintf "1.0.2" - json-schema "0.2.3" - verror "1.3.6" - - kew@~0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" - - kind-of@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" - dependencies: - is-buffer "^1.0.2" - - klassy@^0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/klassy/-/klassy-0.1.3.tgz#c31d5756d583197d75f582b6e692872be497067f" - - klaw@^1.0.0: - version "1.3.1" - resolved "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - optionalDependencies: - graceful-fs "^4.1.9" - - lazy-cache@^1.0.3: - version "1.0.4" - resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" - - lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - dependencies: - invert-kv "^1.0.0" - - leek@0.0.24: - version "0.0.24" - resolved "https://registry.npmjs.org/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" - dependencies: - debug "^2.1.0" - lodash.assign "^3.2.0" - rsvp "^3.0.21" - - leven@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" - - levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - - linkify-it@^2.0.0: - version "2.0.3" - resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" - dependencies: - uc.micro "^1.0.1" - - linkify-it@~1.2.0: - version "1.2.4" - resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" - dependencies: - uc.micro "^1.0.1" - - livereload-js@^2.2.2: - version "2.2.2" - resolved "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" - - load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - - loader.js@^4.2.2: - version "4.3.0" - resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.3.0.tgz#736c13eb8afdf75abd6c2d7b4f7fd40e1105a71f" - - locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - - lodash-node@^3.2.0: - version "3.10.2" - resolved "https://registry.npmjs.org/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" - - lodash._arraycopy@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" - - lodash._arrayeach@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" - - lodash._baseassign@^3.0.0: - version "3.2.0" - resolved "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" - dependencies: - lodash._basecopy "^3.0.0" - lodash.keys "^3.0.0" - - lodash._basecopy@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" - - lodash._baseflatten@^3.0.0: - version "3.1.4" - resolved "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" - dependencies: - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - - lodash._basefor@^3.0.0: - version "3.0.3" - resolved "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" - - lodash._bindcallback@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" - - lodash._createassigner@^3.0.0: - version "3.1.1" - resolved "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" - dependencies: - lodash._bindcallback "^3.0.0" - lodash._isiterateecall "^3.0.0" - lodash.restparam "^3.0.0" - - lodash._getnative@^3.0.0: - version "3.9.1" - resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - - lodash._isiterateecall@^3.0.0: - version "3.0.9" - resolved "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" - - lodash._reinterpolate@~3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - - lodash.assign@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" - dependencies: - lodash._baseassign "^3.0.0" - lodash._createassigner "^3.0.0" - lodash.keys "^3.0.0" - - lodash.assign@^4.1.0, lodash.assign@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" - - lodash.assignin@^4.1.0: - version "4.2.0" - resolved "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" - - lodash.clonedeep@^4.4.1: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - - lodash.debounce@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" - dependencies: - lodash._getnative "^3.0.0" - - lodash.find@^4.5.1: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" - - lodash.flatten@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" - dependencies: - lodash._baseflatten "^3.0.0" - lodash._isiterateecall "^3.0.0" - - lodash.isarguments@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - - lodash.isarray@^3.0.0: - version "3.0.4" - resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" - - lodash.isplainobject@^3.0.0: - version "3.2.0" - resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" - dependencies: - lodash._basefor "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.keysin "^3.0.0" - - lodash.istypedarray@^3.0.0: - version "3.0.6" - resolved "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" - - lodash.keys@^3.0.0: - version "3.1.2" - resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" - dependencies: - lodash._getnative "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - - lodash.keysin@^3.0.0: - version "3.0.8" - resolved "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" - dependencies: - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - - lodash.merge@^3.3.2: - version "3.3.2" - resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz#0d90d93ed637b1878437bb3e21601260d7afe994" - dependencies: - lodash._arraycopy "^3.0.0" - lodash._arrayeach "^3.0.0" - lodash._createassigner "^3.0.0" - lodash._getnative "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - lodash.isplainobject "^3.0.0" - lodash.istypedarray "^3.0.0" - lodash.keys "^3.0.0" - lodash.keysin "^3.0.0" - lodash.toplainobject "^3.0.0" - - lodash.merge@^4.3.0, lodash.merge@^4.4.0, lodash.merge@^4.5.1: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" - - lodash.omit@^4.1.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" - - lodash.restparam@^3.0.0: - version "3.6.1" - resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" - - lodash.template@^4.2.5: - version "4.4.0" - resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" - dependencies: - lodash._reinterpolate "~3.0.0" - lodash.templatesettings "^4.0.0" - - lodash.templatesettings@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" - dependencies: - lodash._reinterpolate "~3.0.0" - - lodash.toplainobject@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz#28790ad942d293d78aa663a07ecf7f52ca04198d" - dependencies: - lodash._basecopy "^3.0.0" - lodash.keysin "^3.0.0" - - lodash.uniq@^4.2.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - - lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: - version "3.10.1" - resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" - - lodash@^4.0.0, lodash@^4.15.0, lodash@^4.16.1, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: - version "4.17.4" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" - - longest@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" - - loose-envify@^1.0.0: - version "1.3.1" - resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" - dependencies: - js-tokens "^3.0.0" - - lru-cache@2: - version "2.7.3" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" - - lru-cache@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" - dependencies: - pseudomap "^1.0.1" - yallist "^2.0.0" - - make-array@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" - - makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" - dependencies: - tmpl "1.0.x" - - markdown-it-terminal@0.0.4: - version "0.0.4" - resolved "https://registry.npmjs.org/markdown-it-terminal/-/markdown-it-terminal-0.0.4.tgz#3f2ce624ba2ca964a78b8b388d605ee330de9ced" - dependencies: - ansi-styles "^2.1.0" - cardinal "^0.5.0" - cli-table "^0.3.1" - lodash.merge "^3.3.2" - markdown-it "^4.4.0" - - markdown-it@^4.3.0, markdown-it@^4.4.0: - version "4.4.0" - resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" - dependencies: - argparse "~1.0.2" - entities "~1.1.1" - linkify-it "~1.2.0" - mdurl "~1.0.0" - uc.micro "^1.0.0" - - markdown-it@^8.2.0: - version "8.3.1" - resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-8.3.1.tgz#2f4b622948ccdc193d66f3ca2d43125ac4ac7323" - dependencies: - argparse "^1.0.7" - entities "~1.1.1" - linkify-it "^2.0.0" - mdurl "^1.0.1" - uc.micro "^1.0.3" - - matcher-collection@^1.0.0, matcher-collection@^1.0.1: - version "1.0.4" - resolved "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.4.tgz#2f66ae0869996f29e43d0b62c83dd1d43e581755" - dependencies: - minimatch "^3.0.2" - - md5-hex@^1.0.2, md5-hex@^1.2.1, md5-hex@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" - dependencies: - md5-o-matic "^0.1.1" - - md5-o-matic@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" - - mdn-links@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" - - mdurl@^1.0.1, mdurl@~1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" - - media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - - memory-streams@^0.1.0: - version "0.1.2" - resolved "https://registry.npmjs.org/memory-streams/-/memory-streams-0.1.2.tgz#273ff777ab60fec599b116355255282cca2c50c2" - dependencies: - readable-stream "~1.0.2" - - merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - - merge@^1.1.3, merge@^1.2.0, merge@~1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" - - methods@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - - micromatch@^2.1.5, micromatch@^2.3.7: - version "2.3.11" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - - "mime-db@>= 1.27.0 < 2", mime-db@~1.27.0: - version "1.27.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" - - mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7: - version "2.1.15" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" - dependencies: - mime-db "~1.27.0" - - mime-types@~1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" - - mime@1.3.4, mime@^1.2.11: - version "1.3.4" - resolved "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" - - mime@~1.2.11: - version "1.2.11" - resolved "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" - - "minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" - dependencies: - brace-expansion "^1.0.0" - - minimatch@^2.0.1, minimatch@^2.0.3, minimatch@^2.0.8: - version "2.0.10" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" - dependencies: - brace-expansion "^1.0.0" - - minimatch@~0.2.11: - version "0.2.14" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" - dependencies: - lru-cache "2" - sigmund "~1.0.0" - - minimist@0.0.8, minimist@~0.0.1: - version "0.0.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - - minimist@^1.1.0, minimist@^1.1.1: - version "1.2.0" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - - mkdirp@0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" - - mkdirp@0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" - dependencies: - minimist "0.0.8" - - mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - - mktemp@^0.4.0, mktemp@~0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" - - mocha-only-detector@0.0.2: - version "0.0.2" - resolved "https://registry.npmjs.org/mocha-only-detector/-/mocha-only-detector-0.0.2.tgz#00f7dde6f949cf68a3cc92bdacff997b87e4b1d1" - dependencies: - esprima "^1.2.2" - esprimaq "^0.0.1" - glob "^4.3.2" - - mocha@2.4.5: - version "2.4.5" - resolved "https://registry.npmjs.org/mocha/-/mocha-2.4.5.tgz#151768dd2875eb51bc8295e9800026e9f2bb398f" - dependencies: - commander "2.3.0" - debug "2.2.0" - diff "1.4.0" - escape-string-regexp "1.0.2" - glob "3.2.3" - growl "1.8.1" - jade "0.26.3" - mkdirp "0.5.1" - supports-color "1.2.0" - - moment-timezone@^0.3.0: - version "0.3.1" - resolved "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" - dependencies: - moment ">= 2.6.0" - - "moment@>= 2.6.0": - version "2.18.1" - resolved "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" - - morgan@^1.5.2, morgan@^1.7.0: - version "1.8.1" - resolved "https://registry.npmjs.org/morgan/-/morgan-1.8.1.tgz#f93023d3887bd27b78dfd6023cea7892ee27a4b1" - dependencies: - basic-auth "~1.1.0" - debug "2.6.1" - depd "~1.1.0" - on-finished "~2.3.0" - on-headers "~1.0.1" - - mout@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/mout/-/mout-1.0.0.tgz#9bdf1d4af57d66d47cb353a6335a3281098e1501" - - ms@0.7.1: - version "0.7.1" - resolved "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" - - ms@0.7.2: - version "0.7.2" - resolved "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" - - ms@0.7.3: - version "0.7.3" - resolved "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff" - - mustache@^2.2.1: - version "2.3.0" - resolved "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" - - mute-stream@0.0.5: - version "0.0.5" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" - - mute-stream@0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" - - negotiator@0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" - - node-fetch@^1.3.3: - version "1.6.3" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" - - node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - - node-modules-path@^1.0.0, node-modules-path@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" - - node-notifier@^5.0.1: - version "5.1.2" - resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff" - dependencies: - growly "^1.3.0" - semver "^5.3.0" - shellwords "^0.1.0" - which "^1.2.12" - - node-uuid@~1.4.0: - version "1.4.8" - resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" - - nopt@^3.0.3: - version "3.0.6" - resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - dependencies: - abbrev "1" - - nopt@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - dependencies: - abbrev "1" - osenv "^0.1.4" - - normalize-package-data@^2.3.2: - version "2.3.8" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" - dependencies: - hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - - normalize-path@^2.0.1: - version "2.1.1" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - dependencies: - remove-trailing-separator "^1.0.1" - - npm-git-info@^1.0.0: - version "1.0.3" - resolved "https://registry.npmjs.org/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" - - npm-package-arg@^4.1.1: - version "4.2.1" - resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" - dependencies: - hosted-git-info "^2.1.5" - semver "^5.1.0" - - npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - dependencies: - path-key "^2.0.0" - - npmlog@^4.0.0: - version "4.0.2" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.1" - set-blocking "~2.0.0" - - number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - - oauth-sign@~0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" - - oauth-sign@~0.8.1: - version "0.8.2" - resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - - object-assign@4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" - - object-assign@^4.0.1, object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - - object-component@0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" - - object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - - on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - dependencies: - ee-first "1.1.1" - - on-headers@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" - - once@^1.3.0: - version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - - onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - - optimist@^0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - - optionator@^0.8.1: - version "0.8.2" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" - - options@>=0.0.5: - version "0.0.6" - resolved "https://registry.npmjs.org/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" - - ora@^0.2.0: - version "0.2.3" - resolved "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" - dependencies: - chalk "^1.1.1" - cli-cursor "^1.0.2" - cli-spinners "^0.1.2" - object-assign "^4.0.1" - - os-homedir@^1.0.0, os-homedir@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - - os-locale@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" - dependencies: - lcid "^1.0.0" - - os-shim@^0.1.2: - version "0.1.3" - resolved "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" - - os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - - osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - - output-file-sync@^1.1.0: - version "1.1.2" - resolved "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" - dependencies: - graceful-fs "^4.1.4" - mkdirp "^0.5.1" - object-assign "^4.1.0" - - p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - - p-limit@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" - - p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - dependencies: - p-limit "^1.1.0" - - parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - - parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - dependencies: - error-ex "^1.2.0" - - parse-passwd@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" - - parsejson@0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" - dependencies: - better-assert "~1.0.0" - - parseqs@0.0.5: - version "0.0.5" - resolved "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" - dependencies: - better-assert "~1.0.0" - - parseuri@0.0.5: - version "0.0.5" - resolved "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" - dependencies: - better-assert "~1.0.0" - - parseurl@~1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" - - path-exists@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" - - path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - dependencies: - pinkie-promise "^2.0.0" - - path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - - path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - - path-is-inside@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - - path-key@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - - path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" - - path-posix@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" - - path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - - path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - - pend@~1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - - phantomjs-prebuilt@^2.1.12: - version "2.1.14" - resolved "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz#d53d311fcfb7d1d08ddb24014558f1188c516da0" - dependencies: - es6-promise "~4.0.3" - extract-zip "~1.5.0" - fs-extra "~1.0.0" - hasha "~2.2.0" - kew "~0.7.0" - progress "~1.1.8" - request "~2.79.0" - request-progress "~2.0.1" - which "~1.2.10" - - pify@^2.0.0: - version "2.3.0" - resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - - pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - dependencies: - pinkie "^2.0.0" - - pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - - plain-text-box-plot@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/plain-text-box-plot/-/plain-text-box-plot-0.0.1.tgz#d3b2e53071ea6706972318565761242f779c04b8" - - pluralize@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" - - portfinder@^1.0.7: - version "1.0.13" - resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" - dependencies: - async "^1.5.2" - debug "^2.2.0" - mkdirp "0.5.x" - - prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - - preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - - pretender@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/pretender/-/pretender-1.0.0.tgz#9137c38718b4d89814478b7f208f70d3e441a0e9" - dependencies: - fake-xml-http-request "^1.3.0" - route-recognizer "^0.1.9" - - pretender@^1.4.2: - version "1.4.2" - resolved "https://registry.npmjs.org/pretender/-/pretender-1.4.2.tgz#dde9995dfdf75b28a3dd7a73cde2f9f612e5e8f4" - dependencies: - fake-xml-http-request "^1.4.0" - route-recognizer "^0.2.3" - - printf@^0.2.3: - version "0.2.5" - resolved "https://registry.npmjs.org/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" - - private@^0.1.6, private@~0.1.5: - version "0.1.7" - resolved "https://registry.npmjs.org/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" - - process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - - process-relative-require@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" - dependencies: - node-modules-path "^1.0.0" - - progress@^1.1.8, progress@~1.1.8: - version "1.1.8" - resolved "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" - - promise-map-series@^0.2.1: - version "0.2.3" - resolved "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" - dependencies: - rsvp "^3.0.14" - - proxy-addr@~1.1.3: - version "1.1.4" - resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" - dependencies: - forwarded "~0.1.0" - ipaddr.js "1.3.0" - - pseudomap@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - - punycode@1.3.2: - version "1.3.2" - resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - - punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - - q@^1.1.2: - version "1.5.0" - resolved "https://registry.npmjs.org/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" - - qs@6.4.0, qs@^6.2.0: - version "6.4.0" - resolved "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" - - qs@~1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" - - qs@~6.3.0: - version "6.3.2" - resolved "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" - - querystring@0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - - quick-temp@0.1.6, quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5: - version "0.1.6" - resolved "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.6.tgz#a6242a15cba9f9cdbd341287b5c569e318eec307" - dependencies: - mktemp "~0.4.0" - rimraf "~2.2.6" - underscore.string "~2.3.3" - - qunit-notifications@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/qunit-notifications/-/qunit-notifications-0.1.1.tgz#3001afc6a6a77dfbd962ccbcddde12dec5286c09" - - qunitjs@^1.20.0: - version "1.23.1" - resolved "https://registry.npmjs.org/qunitjs/-/qunitjs-1.23.1.tgz#1971cf97ac9be01a64d2315508d2e48e6fd4e719" - - randomatic@^1.1.3: - version "1.1.6" - resolved "https://registry.npmjs.org/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" - dependencies: - is-number "^2.0.2" - kind-of "^3.0.2" - - range-parser@~1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - - raw-body@~1.1.0: - version "1.1.7" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" - dependencies: - bytes "1" - string_decoder "0.10" - - raw-body@~2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" - dependencies: - bytes "2.4.0" - iconv-lite "0.4.15" - unpipe "1.0.0" - - read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - - read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - - readable-stream@^2, readable-stream@^2.0.6, readable-stream@~2.0.0: - version "2.0.6" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - - readable-stream@~1.0.2: - version "1.0.34" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - - readline2@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - mute-stream "0.0.5" - - recast@0.10.33: - version "0.10.33" - resolved "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" - dependencies: - ast-types "0.8.12" - esprima-fb "~15001.1001.0-dev-harmony-fb" - private "~0.1.5" - source-map "~0.5.0" - - recast@^0.10.10, recast@^0.10.29: - version "0.10.43" - resolved "https://registry.npmjs.org/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" - dependencies: - ast-types "0.8.15" - esprima-fb "~15001.1001.0-dev-harmony-fb" - private "~0.1.5" - source-map "~0.5.0" - - recast@^0.11.17, recast@^0.11.3: - version "0.11.23" - resolved "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" - dependencies: - ast-types "0.9.6" - esprima "~3.1.0" - private "~0.1.5" - source-map "~0.5.0" - - redeyed@~0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/redeyed/-/redeyed-0.5.0.tgz#7ab000e60ee3875ac115d29edb32c1403c6c25d1" - dependencies: - esprima-fb "~12001.1.0-dev-harmony-fb" - - regenerate@^1.2.1: - version "1.3.2" - resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" - - regenerator-runtime@^0.10.0: - version "0.10.3" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e" - - regenerator-transform@0.9.11: - version "0.9.11" - resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.9.11.tgz#3a7d067520cb7b7176769eb5ff868691befe1283" - dependencies: - babel-runtime "^6.18.0" - babel-types "^6.19.0" - private "^0.1.6" - - regenerator@0.8.40: - version "0.8.40" - resolved "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" - dependencies: - commoner "~0.10.3" - defs "~1.1.0" - esprima-fb "~15001.1001.0-dev-harmony-fb" - private "~0.1.5" - recast "0.10.33" - through "~2.3.8" - - regex-cache@^0.4.2: - version "0.4.3" - resolved "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" - dependencies: - is-equal-shallow "^0.1.3" - is-primitive "^2.0.0" - - regexpu-core@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - - regexpu@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" - dependencies: - esprima "^2.6.0" - recast "^0.10.10" - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - - regjsgen@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - - regjsparser@^0.1.4: - version "0.1.5" - resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - dependencies: - jsesc "~0.5.0" - - remove-trailing-separator@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4" - - repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" - - repeat-string@^1.5.2: - version "1.6.1" - resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - - repeating@^1.1.0, repeating@^1.1.2: - version "1.1.3" - resolved "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" - dependencies: - is-finite "^1.0.0" - - repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - dependencies: - is-finite "^1.0.0" - - request-progress@~2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" - dependencies: - throttleit "^1.0.0" - - request@~2.40.0: - version "2.40.0" - resolved "https://registry.npmjs.org/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" - dependencies: - forever-agent "~0.5.0" - json-stringify-safe "~5.0.0" - mime-types "~1.0.1" - node-uuid "~1.4.0" - qs "~1.0.0" - optionalDependencies: - aws-sign2 "~0.5.0" - form-data "~0.1.0" - hawk "1.1.1" - http-signature "~0.10.0" - oauth-sign "~0.3.0" - stringstream "~0.0.4" - tough-cookie ">=0.12.0" - tunnel-agent "~0.4.0" - - request@~2.79.0: - version "2.79.0" - resolved "https://registry.npmjs.org/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.11.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~2.0.6" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - qs "~6.3.0" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" - uuid "^3.0.0" - - require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - - require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - - require-uncached@^1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" - - requires-port@1.x.x: - version "1.0.0" - resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - - resolve-dir@^0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" - dependencies: - expand-tilde "^1.2.2" - global-modules "^0.2.3" - - resolve-from@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - - resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0: - version "1.3.3" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" - dependencies: - path-parse "^1.0.5" - - restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - - right-align@^0.1.1: - version "0.1.3" - resolved "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" - dependencies: - align-text "^0.1.1" - - rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1: - version "2.5.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" - dependencies: - glob "^7.0.0" - - rimraf@^2.1.4, rimraf@^2.5.3, rimraf@^2.5.4: - version "2.6.1" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" - dependencies: - glob "^7.0.5" - - rimraf@~2.2.6: - version "2.2.8" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" - - rollup@^0.41.4: - version "0.41.6" - resolved "https://registry.npmjs.org/rollup/-/rollup-0.41.6.tgz#e0d05497877a398c104d816d2733a718a7a94e2a" - dependencies: - source-map-support "^0.4.0" - - route-recognizer@^0.1.9: - version "0.1.11" - resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" - - route-recognizer@^0.2.3: - version "0.2.10" - resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" - - rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.6, rsvp@~3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" - - rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: - version "3.5.0" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" - - rsvp@~3.0.6: - version "3.0.21" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" - - rsvp@~3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" - - run-async@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" - dependencies: - once "^1.3.0" - - run-async@^2.2.0: - version "2.3.0" - resolved "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - dependencies: - is-promise "^2.1.0" - - rx-lite@^3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" - - rx@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" - - safe-json-parse@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" - - sane@^1.1.1: - version "1.6.0" - resolved "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz#9610c452307a135d29c1fdfe2547034180c46775" - dependencies: - anymatch "^1.3.0" - exec-sh "^0.2.0" - fb-watchman "^1.8.0" - minimatch "^3.0.2" - minimist "^1.1.1" - walker "~1.0.5" - watch "~0.10.0" - - sanitize-filename@^1.5.3: - version "1.6.1" - resolved "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.1.tgz#612da1c96473fa02dccda92dcd5b4ab164a6772a" - dependencies: - truncate-utf8-bytes "^1.0.0" - - sax@1.2.1, sax@>=0.6.0: - version "1.2.1" - resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" - - selenium-webdriver@^3.0.0-beta-2: - version "3.4.0" - resolved "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.4.0.tgz#151f7445294da6a66c49cc300747a2a17e53c52a" - dependencies: - adm-zip "^0.4.7" - rimraf "^2.5.4" - tmp "0.0.30" - xml2js "^0.4.17" - - "semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0: - version "5.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - - semver@^4.1.0, semver@^4.3.1: - version "4.3.6" - resolved "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" - - semver@~5.0.1: - version "5.0.3" - resolved "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" - - send@0.15.1: - version "0.15.1" - resolved "https://registry.npmjs.org/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" - dependencies: - debug "2.6.1" - depd "~1.1.0" - destroy "~1.0.4" - encodeurl "~1.0.1" - escape-html "~1.0.3" - etag "~1.8.0" - fresh "0.5.0" - http-errors "~1.6.1" - mime "1.3.4" - ms "0.7.2" - on-finished "~2.3.0" - range-parser "~1.2.0" - statuses "~1.3.1" - - serve-static@1.12.1: - version "1.12.1" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039" - dependencies: - encodeurl "~1.0.1" - escape-html "~1.0.3" - parseurl "~1.3.1" - send "0.15.1" - - set-blocking@^2.0.0, set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - - setprototypeof@1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" - - shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - dependencies: - shebang-regex "^1.0.0" - - shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - - shelljs@^0.6.0: - version "0.6.1" - resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" - - shellwords@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14" - - sigmund@~1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" - - signal-exit@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - - silent-error@^1.0.0, silent-error@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.0.1.tgz#71b7d503d1c6f94882b51b56be879b113cb4822c" - dependencies: - debug "^2.2.0" - - simple-dom@^0.3.0: - version "0.3.2" - resolved "https://registry.npmjs.org/simple-dom/-/simple-dom-0.3.2.tgz#0663d10f1556f1500551d518f56e3aba0871371d" - - simple-fmt@~0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" - - simple-is@~0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" - - slash@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - - slice-ansi@0.0.4: - version "0.0.4" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" - - slide@^1.1.5: - version "1.1.6" - resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - - sntp@0.2.x: - version "0.2.4" - resolved "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" - dependencies: - hoek "0.9.x" - - sntp@1.x.x: - version "1.0.9" - resolved "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - dependencies: - hoek "2.x.x" - - socket.io-adapter@0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" - dependencies: - debug "2.3.3" - socket.io-parser "2.3.1" - - socket.io-client@1.6.0: - version "1.6.0" - resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" - dependencies: - backo2 "1.0.2" - component-bind "1.0.0" - component-emitter "1.2.1" - debug "2.3.3" - engine.io-client "1.8.0" - 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" - - socket.io-parser@2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" - dependencies: - component-emitter "1.1.2" - debug "2.2.0" - isarray "0.0.1" - json3 "3.3.2" - - socket.io@1.6.0: - version "1.6.0" - resolved "https://registry.npmjs.org/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" - dependencies: - debug "2.3.3" - engine.io "1.8.0" - has-binary "0.1.7" - object-assign "4.1.0" - socket.io-adapter "0.5.0" - socket.io-client "1.6.0" - socket.io-parser "2.3.1" - - sort-object-keys@^1.1.1: - version "1.1.2" - resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" - - sort-package-json@^1.4.0: - version "1.6.1" - resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.6.1.tgz#2ae463e4f5bb5d803bfdffdb4f92551c8fa66593" - dependencies: - sort-object-keys "^1.1.1" - - source-map-support@^0.2.10: - version "0.2.10" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" - dependencies: - source-map "0.1.32" - - source-map-support@^0.4.0, source-map-support@^0.4.2: - version "0.4.14" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef" - dependencies: - source-map "^0.5.6" - - source-map-url@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" - - source-map@0.1.32: - version "0.1.32" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" - dependencies: - amdefine ">=0.0.4" - - source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: - version "0.4.4" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" - dependencies: - amdefine ">=0.0.4" - - source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: - version "0.5.6" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" - - spawn-args@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" - - spawn-sync@^1.0.15: - version "1.0.15" - resolved "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" - dependencies: - concat-stream "^1.4.7" - os-shim "^0.1.2" - - spawnback@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" - - spdx-correct@~1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" - dependencies: - spdx-license-ids "^1.0.2" - - spdx-expression-parse@~1.0.0: - version "1.0.4" - resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" - - spdx-license-ids@^1.0.2: - version "1.2.2" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" - - sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - - sri-toolbox@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" - - sshpk@^1.7.0: - version "1.13.0" - resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz#ff2a3e4fd04497555fed97b39a0fd82fafb3a33c" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jodid25519 "^1.0.0" - jsbn "~0.1.0" - tweetnacl "~0.14.0" - - stable@~0.1.3: - version "0.1.6" - resolved "https://registry.npmjs.org/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10" - - "statuses@>= 1.3.1 < 2", statuses@~1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" - - stream-consume@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" - - string-template@~0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" - - string-width@^1.0.1, string-width@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - - string-width@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^3.0.0" - - string_decoder@0.10, string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - - stringmap@~0.2.2: - version "0.2.2" - resolved "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" - - stringset@~0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" - - stringstream@~0.0.4: - version "0.0.5" - resolved "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - - strip-ansi@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" - dependencies: - ansi-regex "^0.2.1" - - strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - - strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - dependencies: - is-utf8 "^0.2.0" - - strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - - strip-json-comments@~1.0.1: - version "1.0.4" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" - - styled_string@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" - - sum-up@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" - dependencies: - chalk "^1.0.0" - - supports-color@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" - - supports-color@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" - - supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - - symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: - version "1.1.8" - resolved "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" - - sync-exec@^0.6.2: - version "0.6.2" - resolved "https://registry.npmjs.org/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105" - - table@^3.7.8: - version "3.8.3" - resolved "https://registry.npmjs.org/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" - dependencies: - ajv "^4.7.0" - ajv-keywords "^1.0.0" - chalk "^1.1.1" - lodash "^4.0.0" - slice-ansi "0.0.4" - string-width "^2.0.0" - - tap-parser@^5.1.0: - version "5.3.3" - resolved "https://registry.npmjs.org/tap-parser/-/tap-parser-5.3.3.tgz#53ec8a90f275d6fff43f169e56a679502a741185" - dependencies: - events-to-array "^1.0.1" - js-yaml "^3.2.7" - optionalDependencies: - readable-stream "^2" - - temp@0.8.3: - version "0.8.3" - resolved "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" - dependencies: - os-tmpdir "^1.0.0" - rimraf "~2.2.6" - - testem@1.15.0, testem@^1.8.1: - version "1.15.0" - resolved "https://registry.yarnpkg.com/testem/-/testem-1.15.0.tgz#2e3a9e7ac29f16a20f718eb0c4b12e7a44900675" - dependencies: - backbone "^1.1.2" - bluebird "^3.4.6" - charm "^1.0.0" - commander "^2.6.0" - consolidate "^0.14.0" - cross-spawn "^5.0.0" - express "^4.10.7" - fireworm "^0.7.0" - glob "^7.0.4" - http-proxy "^1.13.1" - js-yaml "^3.2.5" - lodash.assignin "^4.1.0" - lodash.clonedeep "^4.4.1" - lodash.find "^4.5.1" - mkdirp "^0.5.1" - mustache "^2.2.1" - node-notifier "^5.0.1" - npmlog "^4.0.0" - printf "^0.2.3" - rimraf "^2.4.4" - socket.io "1.6.0" - spawn-args "^0.2.0" - styled_string "0.0.1" - tap-parser "^5.1.0" - xmldom "^0.1.19" - - text-table@~0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - - "textextensions@1 || 2": - version "2.1.0" - resolved "https://registry.npmjs.org/textextensions/-/textextensions-2.1.0.tgz#1be0dc2a0dc244d44be8a09af6a85afb93c4dbc3" - - throttleit@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" - - through@^2.3.6, through@^2.3.8, through@~2.3.8: - version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - - tiny-lr@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.0.3.tgz#386731170ce521263a9d337f769ee8f11e88eb04" - dependencies: - body "^5.1.0" - debug "~2.2.0" - faye-websocket "~0.10.0" - livereload-js "^2.2.2" - object-assign "^4.1.0" - qs "^6.2.0" - - tmp-sync@^1.0.0: - version "1.1.2" - resolved "https://registry.npmjs.org/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" - dependencies: - fs-sync "^1.0.4" - osenv "^0.1.0" - - tmp@0.0.28: - version "0.0.28" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" - dependencies: - os-tmpdir "~1.0.1" - - tmp@0.0.30: - version "0.0.30" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" - dependencies: - os-tmpdir "~1.0.1" - - tmp@^0.0.29: - version "0.0.29" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" - dependencies: - os-tmpdir "~1.0.1" - - tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" - - to-array@0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" - - to-fast-properties@^1.0.0, to-fast-properties@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" - - tough-cookie@>=0.12.0, tough-cookie@~2.3.0: - version "2.3.2" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" - dependencies: - punycode "^1.4.1" - - tree-sync@^1.2.1: - version "1.2.2" - resolved "https://registry.npmjs.org/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" - dependencies: - debug "^2.2.0" - fs-tree-diff "^0.5.6" - mkdirp "^0.5.1" - quick-temp "^0.1.5" - walk-sync "^0.2.7" - - trim-right@^1.0.0, trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - - truncate-utf8-bytes@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" - dependencies: - utf8-byte-length "^1.0.1" - - try-resolve@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" - - tryit@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" - - tryor@~0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" - - tunnel-agent@~0.4.0, tunnel-agent@~0.4.1: - version "0.4.3" - resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" - - tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - - type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - dependencies: - prelude-ls "~1.1.2" - - type-detect@0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" - - type-detect@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" - - type-is@~1.6.14: - version "1.6.15" - resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" - dependencies: - media-typer "0.3.0" - mime-types "~2.1.15" - - typedarray@~0.0.5: - version "0.0.6" - resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - - uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" - - uglify-js@^2.6, uglify-js@^2.7.0: - version "2.8.22" - resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.22.tgz#d54934778a8da14903fa29a326fb24c0ab51a1a0" - dependencies: - source-map "~0.5.1" - yargs "~3.10.0" - optionalDependencies: - uglify-to-browserify "~1.0.0" - - uglify-to-browserify@~1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" - - ultron@1.0.x: - version "1.0.2" - resolved "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" - - underscore.string@~2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz#71c08bf6b428b1133f37e78fa3a21c82f7329b0d" - - underscore@>=1.8.3: - version "1.8.3" - resolved "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" - - unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - - untildify@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" - dependencies: - os-homedir "^1.0.0" - - url@0.10.3: - version "0.10.3" - resolved "https://registry.npmjs.org/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" - dependencies: - punycode "1.3.2" - querystring "0.2.0" - - user-home@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" - - user-home@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" - dependencies: - os-homedir "^1.0.0" - - utf8-byte-length@^1.0.1: - version "1.0.4" - resolved "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" - - util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - - utils-merge@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" - - uuid@3.0.1, uuid@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" - - uuid@^2.0.1: - version "2.0.3" - resolved "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" - - validate-npm-package-license@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" - dependencies: - spdx-correct "~1.0.0" - spdx-expression-parse "~1.0.0" - - vary@~1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" - - verror@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" - dependencies: - extsprintf "1.0.2" - - walk-sync@^0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" - - walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: - version "0.2.7" - resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" - dependencies: - ensure-posix-path "^1.0.0" - matcher-collection "^1.0.0" - - walk-sync@^0.3.0, walk-sync@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.1.tgz#558a16aeac8c0db59c028b73c66f397684ece465" - dependencies: - ensure-posix-path "^1.0.0" - matcher-collection "^1.0.0" - - walker@~1.0.5: - version "1.0.7" - resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" - dependencies: - makeerror "1.0.x" - - watch@~0.10.0: - version "0.10.0" - resolved "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" - - websocket-driver@>=0.5.1: - version "0.6.5" - resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" - dependencies: - websocket-extensions ">=0.1.1" - - websocket-extensions@>=0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" - - which-module@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" - - which@^1.2.12, which@^1.2.9, which@~1.2.10: - version "1.2.14" - resolved "https://registry.npmjs.org/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" - dependencies: - isexe "^2.0.0" - - wide-align@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" - dependencies: - string-width "^1.0.1" - - window-size@0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - - window-size@^0.1.2: - version "0.1.4" - resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" - - window-size@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" - - wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - - wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - - wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - - wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - - wrappy@1: - version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - - write-file-atomic@^1.1.2: - version "1.3.3" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.3.tgz#831dd22d491bdc135180bb996a0eb3f8bf587791" - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - slide "^1.1.5" - - write@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" - dependencies: - mkdirp "^0.5.1" - - ws@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" - dependencies: - options ">=0.0.5" - ultron "1.0.x" - - ws@^1.0.1: - version "1.1.4" - resolved "https://registry.npmjs.org/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" - dependencies: - options ">=0.0.5" - ultron "1.0.x" - - wtf-8@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" - - xdg-basedir@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" - dependencies: - os-homedir "^1.0.0" - - xml2js@0.4.17, xml2js@^0.4.17: - version "0.4.17" - resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" - dependencies: - sax ">=0.6.0" - xmlbuilder "^4.1.0" - - xmlbuilder@4.2.1, xmlbuilder@^4.1.0: - version "4.2.1" - resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" - dependencies: - lodash "^4.0.0" - - xmldom@^0.1.19: - version "0.1.27" - resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" - - xmlhttprequest-ssl@1.5.3: - version "1.5.3" - resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" - - xtend@^4.0.0, xtend@~4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - - y18n@^3.2.0, y18n@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - - yallist@^2.0.0: - version "2.1.2" - resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - - yam@0.0.22: - version "0.0.22" - resolved "https://registry.npmjs.org/yam/-/yam-0.0.22.tgz#38a76cb79a19284d9206ed49031e359a1340bd06" - dependencies: - fs-extra "^0.30.0" - lodash.merge "^4.4.0" - - yargs-parser@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-3.2.0.tgz#5081355d19d9d0c8c5d81ada908cb4e6d186664f" - dependencies: - camelcase "^3.0.0" - lodash.assign "^4.1.0" - - yargs@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-5.0.0.tgz#3355144977d05757dbb86d6e38ec056123b3a66e" - dependencies: - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - lodash.assign "^4.2.0" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^1.0.2" - which-module "^1.0.0" - window-size "^0.2.0" - y18n "^3.2.1" - yargs-parser "^3.2.0" - - yargs@~3.10.0: - version "3.10.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" - dependencies: - camelcase "^1.0.2" - cliui "^2.1.0" - decamelize "^1.0.0" - window-size "0.1.0" - - yargs@~3.27.0: - version "3.27.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" - dependencies: - camelcase "^1.2.1" - cliui "^2.1.0" - decamelize "^1.0.0" - os-locale "^1.4.0" - window-size "^0.1.2" - y18n "^3.2.0" - - yauzl@2.4.1: - version "2.4.1" - resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" - dependencies: - fd-slicer "~1.0.1" - - yeast@0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" - - yui@^3.18.1: - version "3.18.1" - resolved "https://registry.npmjs.org/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" - dependencies: - request "~2.40.0" - - yuidocjs@~0.9.0: - version "0.9.0" - resolved "https://registry.npmjs.org/yuidocjs/-/yuidocjs-0.9.0.tgz#d2ff2b37cadf30e3d45385c58f5003e5a83f2723" - dependencies: - express "^4.13.1" - graceful-fs "^4.1.2" - markdown-it "^4.3.0" - mdn-links "^0.1.0" - minimatch "^2.0.8" - rimraf "^2.4.1" - yui "^3.18.1" - -Trace: - Error: registry.npmjs.org/amd-name-resolver: Invalid URI "registry.npmjs.org/amd-name-resolver" - at Request.init (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/node_modules/request/request.js:276:31) - at new Request (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/node_modules/request/request.js:130:8) - at request (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/node_modules/request/index.js:54:10) - at RequestManager.execute (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/lib/util/request-manager.js:354:17) - at RequestManager.shiftQueue (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/lib/util/request-manager.js:381:10) - at Promise (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/lib/util/request-manager.js:166:12) - at RequestManager.request (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/lib/util/request-manager.js:164:21) - at NpmRegistry.request (/Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/lib/registries/npm-registry.js:111:32) - at /Users/cthoburn/.nvm/versions/node/v7.4.0/lib/node_modules/yarn/lib/resolvers/registries/npm-resolver.js:111:54 - at Generator.next () From 35aa5a2eb7a4753ba7235740cd052fca4c9f0c27 Mon Sep 17 00:00:00 2001 From: Balint Erdi Date: Tue, 2 May 2017 17:11:08 +0200 Subject: [PATCH 1926/2527] Fix typo: expect multiple s/methods/records back --- addon/serializers/json.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 653e77c12b5..641c7fc6b61 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -70,7 +70,7 @@ const assign = Ember.assign || Ember.merge; - `normalizeResponse` - entry method to the serializer. - `normalizeCreateRecordResponse` - a `normalizeResponse` for a specific operation is called. - `normalizeSingleResponse`|`normalizeArrayResponse` - for methods like `createRecord` we expect - a single record back, while for methods like `findAll` we expect multiple methods back. + a single record back, while for methods like `findAll` we expect multiple records back. - `normalize` - `normalizeArray` iterates and calls `normalize` for each of its records while `normalizeSingle` calls it once. This is the method you most likely want to subclass. - `extractId` | `extractAttributes` | `extractRelationships` - `normalize` delegates to these methods to From ef681614ab39a336ffb9d21d07c1ae3f281939f9 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 2 May 2017 20:10:22 -0400 Subject: [PATCH 1927/2527] [BUGFIX beta] Skip test which doesn't play nicely with the latest ember-cli and is failing on master This is a temporary change to unblock Ember Data See https://github.com/ember-cli/ember-cli/pull/7019 for a more long term fix --- node-tests/blueprints/adapter-test.js | 2 +- node-tests/blueprints/serializer-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index d312cbfe341..6acb989b33d 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -58,7 +58,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { })); }); - it('adapter throws when --base-class is same as name', function() { + xit('adapter throws when --base-class is same as name', function() { var args = ['adapter', 'foo', '--base-class=foo']; return emberNew() diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index 016e94eae0f..9cee0241e7e 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -58,7 +58,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { })); }); - it('serializer throws when --base-class is same as name', function() { + xit('serializer throws when --base-class is same as name', function() { var args = ['serializer', 'foo', '--base-class=foo']; return emberNew() From a65179199a3c08fe34154373108315fc1b3684fe Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 1 May 2017 11:09:00 -0400 Subject: [PATCH 1928/2527] Update ember-cli-babel@6.1.0. --- package.json | 2 +- yarn.lock | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 86ff3317782..a57c10f95a5 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "broccoli-merge-trees": "^1.0.0", "broccoli-rollup": "^1.2.0", "chalk": "^1.1.1", - "ember-cli-babel": "^6.0.0-beta.10", + "ember-cli-babel": "^6.1.0", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.0.0", "ember-cli-test-info": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 21934e0002a..73a7fbde6c0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2151,6 +2151,21 @@ ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.10, ember-cli-babel@^6.0.0-b clone "^2.0.0" ember-cli-version-checker "^1.2.0" +ember-cli-babel@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.1.0.tgz#d9c83a7d0c67cc8a3ccb9bd082971c3593e54fad" + dependencies: + amd-name-resolver "0.0.6" + babel-plugin-debug-macros "^0.1.6" + babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-polyfill "^6.16.0" + babel-preset-env "^1.2.0" + broccoli-babel-transpiler "^6.0.0" + broccoli-funnel "^1.0.0" + broccoli-source "^1.1.0" + clone "^2.0.0" + ember-cli-version-checker "^1.2.0" + ember-cli-blueprint-test-helpers@0.11.0: version "0.11.0" resolved "https://registry.npmjs.org/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" From 6ec617e4890cf5f46abfda7b71f5164658dcc24d Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 1 May 2017 12:10:33 -0400 Subject: [PATCH 1929/2527] Update to use built-in debug code stripping functionality. This functionality is now baked into ember-cli-babel (as of 6.1.0). --- addon/-debug/index.js | 80 +++++++------------ addon/-private/adapters/errors.js | 2 +- addon/-private/system/internal-model-map.js | 2 +- addon/-private/system/many-array.js | 2 +- addon/-private/system/model/errors.js | 2 +- addon/-private/system/model/internal-model.js | 7 +- addon/-private/system/model/model.js | 13 +-- addon/-private/system/model/states.js | 2 +- addon/-private/system/promise-proxies.js | 2 +- addon/-private/system/record-array-manager.js | 2 +- .../-private/system/references/belongs-to.js | 4 +- addon/-private/system/references/has-many.js | 16 ++-- addon/-private/system/relationship-meta.js | 6 +- .../system/relationships/belongs-to.js | 2 +- addon/-private/system/relationships/ext.js | 2 +- .../-private/system/relationships/has-many.js | 2 +- .../relationships/relationship-payloads.js | 3 +- .../system/relationships/state/belongs-to.js | 4 +- .../system/relationships/state/create.js | 8 +- .../system/relationships/state/has-many.js | 3 +- .../relationships/state/relationship.js | 2 +- addon/-private/system/store.js | 20 ++--- addon/-private/system/store/finders.js | 2 +- .../system/store/serializer-response.js | 7 +- addon/adapters/json-api.js | 3 +- addon/adapters/rest.js | 9 ++- addon/attr.js | 2 +- addon/index.js | 2 +- .../initialize-store-service.js | 2 +- addon/serializers/embedded-records-mixin.js | 2 +- addon/serializers/json-api.js | 16 ++-- addon/serializers/json.js | 2 +- addon/serializers/rest.js | 12 +-- addon/transforms/date.js | 2 +- lib/babel-build.js | 25 ++++++ lib/stripped-build-plugins.js | 11 +-- package.json | 1 + tests/helpers/test-in-debug.js | 11 +-- yarn.lock | 19 +---- 39 files changed, 150 insertions(+), 164 deletions(-) diff --git a/addon/-debug/index.js b/addon/-debug/index.js index bc045e9053f..2dd3d1911ea 100644 --- a/addon/-debug/index.js +++ b/addon/-debug/index.js @@ -1,49 +1,11 @@ import Ember from 'ember'; - -export function assert() { - return Ember.assert(...arguments); -} - -export function debug() { - return Ember.debug(...arguments); -} - -export function deprecate() { - return Ember.deprecate(...arguments); -} - -export function info() { - return Ember.info(...arguments); -} - -export function runInDebug() { - return Ember.runInDebug(...arguments); -} +import { assert } from '@ember/debug'; +import { DEBUG } from '@glimmer/env'; export function instrument(method) { return method(); } -export function warn() { - return Ember.warn(...arguments); -} - -export function debugSeal() { - return Ember.debugSeal(...arguments); -} - -function checkPolymorphic(modelClass, addedModelClass) { - if (modelClass.__isMixin) { - //TODO Need to do this in order to support mixins, should convert to public api - //once it exists in Ember - return modelClass.__mixin.detect(addedModelClass.PrototypeMixin); - } - if (Ember.MODEL_FACTORY_INJECTIONS) { - modelClass = modelClass.superclass; - } - return modelClass.detect(addedModelClass); -} - /* Assert that `addedRecord` has a valid type so it can be added to the relationship of the `record`. @@ -63,13 +25,31 @@ function checkPolymorphic(modelClass, addedModelClass) { @param {InternalModel} addedRecord record which should be added/set for the relationship */ -export function assertPolymorphicType(parentInternalModel, relationshipMeta, addedInternalModel) { - let addedModelName = addedInternalModel.modelName; - let parentModelName = parentInternalModel.modelName; - let key = relationshipMeta.key; - let relationshipModelName = relationshipMeta.type; - let relationshipClass = parentInternalModel.store.modelFor(relationshipModelName); - let assertionMessage = `You cannot add a record of modelClass '${addedModelName}' to the '${parentModelName}.${key}' relationship (only '${relationshipModelName}' allowed)`; - - assert(assertionMessage, checkPolymorphic(relationshipClass, addedInternalModel.modelClass)); -} +let assertPolymorphicType; + +if (DEBUG) { + let checkPolymorphic = function checkPolymorphic(modelClass, addedModelClass) { + if (modelClass.__isMixin) { + //TODO Need to do this in order to support mixins, should convert to public api + //once it exists in Ember + return modelClass.__mixin.detect(addedModelClass.PrototypeMixin); + } + if (Ember.MODEL_FACTORY_INJECTIONS) { + modelClass = modelClass.superclass; + } + return modelClass.detect(addedModelClass); + }; + + assertPolymorphicType = function assertPolymorphicType(parentInternalModel, relationshipMeta, addedInternalModel) { + let addedModelName = addedInternalModel.modelName; + let parentModelName = parentInternalModel.modelName; + let key = relationshipMeta.key; + let relationshipModelName = relationshipMeta.type; + let relationshipClass = parentInternalModel.store.modelFor(relationshipModelName); + let assertionMessage = `You cannot add a record of modelClass '${addedModelName}' to the '${parentModelName}.${key}' relationship (only '${relationshipModelName}' allowed)`; + + assert(assertionMessage, checkPolymorphic(relationshipClass, addedInternalModel.modelClass)); + }; +} + +export { assertPolymorphicType } diff --git a/addon/-private/adapters/errors.js b/addon/-private/adapters/errors.js index 87f1daaa588..085df8d7892 100644 --- a/addon/-private/adapters/errors.js +++ b/addon/-private/adapters/errors.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert } from 'ember-data/-debug'; +import { assert } from '@ember/debug'; import isEnabled from '../features'; diff --git a/addon/-private/system/internal-model-map.js b/addon/-private/system/internal-model-map.js index ea8acc1bed1..80a10ed9c57 100644 --- a/addon/-private/system/internal-model-map.js +++ b/addon/-private/system/internal-model-map.js @@ -1,4 +1,4 @@ -import { assert, deprecate } from 'ember-data/-debug'; +import { assert, deprecate } from '@ember/debug'; import InternalModel from './model/internal-model'; /** diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 7aaa74927e4..569263e1f5e 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -2,7 +2,7 @@ @module ember-data */ import Ember from 'ember'; -import { assert } from 'ember-data/-debug'; +import { assert } from '@ember/debug'; import { PromiseArray } from "./promise-proxies"; import { _objectIsAlive } from "./store/common"; import diffArray from './diff-array'; diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index a6b1342d852..9642e8eee16 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { deprecate, warn } from 'ember-data/-debug'; +import { deprecate, warn } from '@ember/debug'; const get = Ember.get; const set = Ember.set; diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 93e2e31fea7..4460d103e3f 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -1,5 +1,6 @@ import Ember from 'ember'; -import { assert, runInDebug } from 'ember-data/-debug'; +import { DEBUG } from '@glimmer/env'; +import { assert } from '@ember/debug'; import RootState from "./states"; import Relationships from "../relationships/state/create"; import Snapshot from "../snapshot"; @@ -1188,13 +1189,13 @@ export default class InternalModel { if (!reference) { let relationship = this._relationships.get(name); - runInDebug(() => { + if (DEBUG) { let modelName = this.modelName; assert(`There is no ${kind} relationship named '${name}' on a model of modelClass '${modelName}'`, relationship); let actualRelationshipKind = relationship.relationshipMeta.kind; assert(`You tried to get the '${name}' relationship on a '${modelName}' via record.${kind}('${name}'), but the relationship is of kind '${actualRelationshipKind}'. Use record.${actualRelationshipKind}('${name}') instead.`, actualRelationshipKind === kind); - }); + } if (kind === "belongsTo") { reference = new BelongsToReference(this.store, this, relationship); diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index e52b14b8a7d..17c9466f3a6 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1,5 +1,6 @@ import Ember from 'ember'; -import { assert, deprecate, warn, runInDebug } from 'ember-data/-debug'; +import { DEBUG } from '@glimmer/env'; +import { assert, deprecate, warn } from '@ember/debug'; import { PromiseObject } from "../promise-proxies"; import Errors from "../model/errors"; import isEnabled from '../../features'; @@ -1130,7 +1131,7 @@ Object.defineProperty(Model.prototype, 'data', { } }); -runInDebug(function() { +if (DEBUG) { Model.reopen({ init() { this._super(...arguments); @@ -1140,7 +1141,7 @@ runInDebug(function() { } } }); -}); +} Model.reopenClass({ isModel: true, @@ -1875,7 +1876,7 @@ if (isEnabled('ds-rollback-attribute')) { }); } -runInDebug(() => { +if (DEBUG) { Model.reopen({ // This is a temporary solution until we refactor DS.Model to not // rely on the data property. @@ -1923,7 +1924,7 @@ runInDebug(() => { meta.parentType = proto.constructor; } } - }) -}); + }); +} export default Model; diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index 4507f5277df..b14e9843b81 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -1,7 +1,7 @@ /** @module ember-data */ -import { assert } from 'ember-data/-debug'; +import { assert } from '@ember/debug'; /* This file encapsulates the various states that a record can transition diff --git a/addon/-private/system/promise-proxies.js b/addon/-private/system/promise-proxies.js index 7d63f0d4ea8..6999a9c991c 100644 --- a/addon/-private/system/promise-proxies.js +++ b/addon/-private/system/promise-proxies.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert } from 'ember-data/-debug'; +import { assert } from '@ember/debug'; const { get , RSVP: { Promise }} = Ember; diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 6c2a227d892..2804e27d7c2 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -8,7 +8,7 @@ import { FilteredRecordArray, AdapterPopulatedRecordArray } from "./record-arrays"; -import { assert } from 'ember-data/-debug'; +import { assert } from '@ember/debug'; const { get, diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 73227b3519d..4f41f272389 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -3,8 +3,8 @@ import Ember from 'ember'; import Reference from './reference'; import isEnabled from '../../features'; -import { assertPolymorphicType, deprecate } from 'ember-data/-debug'; - +import { deprecate } from '@ember/debug'; +import { assertPolymorphicType } from 'ember-data/-debug'; /** A BelongsToReference is a low level API that allows users and diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 51ca39a73f0..09da13aa653 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -1,10 +1,8 @@ import Ember from 'ember'; import Reference from './reference'; -import { - assertPolymorphicType, - deprecate, - runInDebug -} from 'ember-data/-debug'; +import { DEBUG } from '@glimmer/env'; +import { deprecate } from '@ember/debug'; +import { assertPolymorphicType } from 'ember-data/-debug'; import isEnabled from '../../features'; @@ -278,10 +276,10 @@ HasManyReference.prototype.push = function(objectOrPromise) { internalModels = array.map((obj) => { let record = this.store.push(obj); - runInDebug(() => { + if (DEBUG) { let relationshipMeta = this.hasManyRelationship.relationshipMeta; assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel); - }); + } return record._internalModel; }); @@ -289,12 +287,12 @@ HasManyReference.prototype.push = function(objectOrPromise) { let records = this.store.push(payload); internalModels = Ember.A(records).mapBy('_internalModel'); - runInDebug(() => { + if (DEBUG) { internalModels.forEach((internalModel) => { let relationshipMeta = this.hasManyRelationship.relationshipMeta; assertPolymorphicType(this.internalModel, relationshipMeta, internalModel); }); - }); + } } this.hasManyRelationship.computeChanges(internalModels); diff --git a/addon/-private/system/relationship-meta.js b/addon/-private/system/relationship-meta.js index b24b56c9e37..bb9763ae145 100644 --- a/addon/-private/system/relationship-meta.js +++ b/addon/-private/system/relationship-meta.js @@ -1,6 +1,6 @@ import {singularize} from 'ember-inflector'; import normalizeModelName from './normalize-model-name'; -import { runInDebug } from 'ember-data/-debug'; +import { DEBUG } from '@glimmer/env'; export function typeForRelationshipMeta(meta) { let modelName; @@ -23,7 +23,9 @@ export function relationshipFromMeta(meta) { isRelationship: true }; - runInDebug(() => result.parentType = meta.parentType); + if (DEBUG) { + result.parentType = meta.parentType; + } return result; } diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 36338f6c76e..13f2dc20389 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert, warn } from 'ember-data/-debug'; +import { assert, warn } from '@ember/debug'; import normalizeModelName from "../normalize-model-name"; /** diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 3cc8dc6e424..528930717a6 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert } from 'ember-data/-debug'; +import { assert } from '@ember/debug'; import { typeForRelationshipMeta, relationshipFromMeta diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index 45a7a93d9da..7327331aaf5 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -3,7 +3,7 @@ */ import Ember from 'ember'; -import { assert } from 'ember-data/-debug'; +import { assert } from '@ember/debug'; import normalizeModelName from "../normalize-model-name"; import isArrayLike from "../is-array-like"; diff --git a/addon/-private/system/relationships/relationship-payloads.js b/addon/-private/system/relationships/relationship-payloads.js index 4925fb115b9..ee9626c8683 100644 --- a/addon/-private/system/relationships/relationship-payloads.js +++ b/addon/-private/system/relationships/relationship-payloads.js @@ -1,4 +1,4 @@ -import { assert } from 'ember-data/-debug'; +import { assert } from '@ember/debug'; /** Manages the payloads for both sides of a single relationship, across all model @@ -356,4 +356,3 @@ export default class RelationshipPayloads { } } } - diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index cd9c2c01c9d..2959d13c25c 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -1,8 +1,8 @@ import Ember from 'ember'; import { - assertPolymorphicType, assert -} from 'ember-data/-debug'; +} from '@ember/debug'; +import { assertPolymorphicType } from 'ember-data/-debug'; import { PromiseObject } from "../../promise-proxies"; diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index 051c8e10633..f0fe88c7cbc 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -1,7 +1,7 @@ import Ember from 'ember'; import ManyRelationship from "./has-many"; import BelongsToRelationship from "./belongs-to"; -import { runInDebug } from 'ember-data/-debug'; +import { DEBUG } from '@glimmer/env'; const { get } = Ember; @@ -16,10 +16,8 @@ function createRelationshipFor(internalModel, relationshipMeta, store) { if (shouldFindInverse(relationshipMeta)) { inverse = internalModel.type.inverseFor(relationshipMeta.key, store); - } else { - runInDebug(() => { - internalModel.type.typeForRelationship(relationshipMeta.key, store); - }); + } else if (DEBUG) { + internalModel.type.typeForRelationship(relationshipMeta.key, store); } if (inverse) { diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index e504c0dcb2c..170011cd561 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -1,4 +1,5 @@ -import { assert, assertPolymorphicType } from 'ember-data/-debug'; +import { assert } from '@ember/debug'; +import { assertPolymorphicType } from 'ember-data/-debug'; import { PromiseManyArray } from '../../promise-proxies'; import Relationship from './relationship'; import OrderedSet from '../../ordered-set'; diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 84ebe6771ff..aa9313692da 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -1,5 +1,5 @@ /* global heimdall */ -import { assert, warn } from 'ember-data/-debug'; +import { assert, warn } from '@ember/debug'; import OrderedSet from '../../ordered-set'; import _normalizeLink from '../../normalize-link'; diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index cdadc90e563..c020529bea5 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -4,13 +4,13 @@ import Ember from 'ember'; import { InvalidError } from '../adapters/errors'; +import { instrument } from 'ember-data/-debug'; import { - instrument, assert, deprecate, - warn, - runInDebug -} from 'ember-data/-debug'; + warn +} from '@ember/debug'; +import { DEBUG } from '@glimmer/env'; import Model from './model/model'; import normalizeModelName from "./normalize-model-name"; import IdentityMap from './identity-map'; @@ -1660,7 +1660,7 @@ Store = Service.extend({ }, didUpdateAll(modelName) { - deprecate('didUpdateAll was documented as private and will be removed in the next version of Ember Data.'); + deprecate('didUpdateAll was documented as private and will be removed in the next version of Ember Data.', false, { id: 'ember-data.didUpdateAll', until: '2.17.0' }); return this._didUpdateAll(modelName); }, @@ -2372,7 +2372,7 @@ Store = Service.extend({ assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id !== null && data.id !== undefined && data.id !== ''); assert(`You tried to push data with a type '${modelName}' but no model could be found with that name.`, this._hasModelFor(modelName)); - runInDebug(() => { + if (DEBUG) { // If ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload // contains unknown attributes or relationships, log a warning. @@ -2393,7 +2393,7 @@ Store = Service.extend({ let unknownRelationshipsMessage = `The payload for '${modelName}' contains these unknown relationships: ${unknownRelationships}. Make sure they've been defined in your model.`; warn(unknownRelationshipsMessage, unknownRelationships.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); } - }); + } // Actually load the record into the store. let internalModel = this._load(data); @@ -2573,7 +2573,7 @@ Store = Service.extend({ }, buildInternalModel(modelName, id, data) { - deprecate('buildInternalModel was documented as private and will be removed in the next version of Ember Data.'); + deprecate('buildInternalModel was documented as private and will be removed in the next version of Ember Data.', false, { id: 'ember-data.buildInternalModel', until: '2.17.0' }); return this._buildInternalModel(modelName, id, data); }, @@ -2869,7 +2869,7 @@ function setupRelationships(store, internalModel, data, modelNameToInverseMap) { } // in debug, assert payload validity eagerly - runInDebug(() => { + if (DEBUG) { let relationshipMeta = get(internalModel.type, 'relationshipsByName').get(relationshipName); let relationshipData = data.relationships[relationshipName]; if (!relationshipData || !relationshipMeta) { @@ -2888,7 +2888,7 @@ function setupRelationships(store, internalModel, data, modelNameToInverseMap) { assert(`A ${internalModel.type.modelName} record was pushed into the store with the value of ${relationshipName} being '${inspect(relationshipData.data)}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(relationshipData.data)); } } - }); + } }); } diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 479d5822461..1ab2d7cf4d5 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert, warn } from 'ember-data/-debug'; +import { assert, warn } from '@ember/debug'; import { _bind, _guard, diff --git a/addon/-private/system/store/serializer-response.js b/addon/-private/system/store/serializer-response.js index e6f5cafdec6..1a264253d49 100644 --- a/addon/-private/system/store/serializer-response.js +++ b/addon/-private/system/store/serializer-response.js @@ -1,5 +1,6 @@ import Ember from 'ember'; -import { assert, runInDebug } from 'ember-data/-debug'; +import { assert } from '@ember/debug'; +import { DEBUG } from '@glimmer/env'; /* This is a helper method that validates a JSON API top-level document @@ -75,9 +76,9 @@ export function validateDocumentStructure(doc) { export function normalizeResponseHelper(serializer, store, modelClass, payload, id, requestType) { let normalizedResponse = serializer.normalizeResponse(store, modelClass, payload, id, requestType); let validationErrors = []; - runInDebug(() => { + if (DEBUG) { validationErrors = validateDocumentStructure(normalizedResponse); - }); + } assert(`normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join('\n\t* ')}`, Ember.isEmpty(validationErrors)); return normalizedResponse; diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index 6d7eff4c8b5..144e15caa69 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -6,7 +6,8 @@ import Ember from 'ember'; import RESTAdapter from "./rest"; import { isEnabled } from '../-private'; -import { instrument, deprecate } from 'ember-data/-debug'; +import { deprecate } from '@ember/debug'; +import { instrument } from 'ember-data/-debug'; /** The `JSONAPIAdapter` is the default adapter used by Ember Data. It diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index e9f77668727..534e948cdeb 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -19,7 +19,10 @@ import { TimeoutError, AbortError } from '../-private'; -import { instrument, runInDebug, warn, deprecate } from 'ember-data/-debug'; +import { instrument } from 'ember-data/-debug'; +import { warn, deprecate } from '@ember/debug'; +import { DEBUG } from '@glimmer/env'; + const { MapWithDefault, @@ -1502,13 +1505,13 @@ function ajaxSuccess(adapter, jqXHR, payload, requestData) { } function ajaxError(adapter, jqXHR, requestData, responseData) { - runInDebug(function() { + if (DEBUG) { let message = `The server returned an empty string for ${requestData.method} ${requestData.url}, which cannot be parsed into a valid JSON. Return either null or {}.`; let validJSONString = !(responseData.textStatus === "parsererror" && jqXHR.responseText === ""); warn(message, validJSONString, { id: 'ds.adapter.returned-empty-string-as-JSON' }); - }); + } let error; diff --git a/addon/attr.js b/addon/attr.js index c130f385e89..e2695837c53 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { deprecate } from 'ember-data/-debug'; +import { deprecate } from '@ember/debug'; /** @module ember-data diff --git a/addon/index.js b/addon/index.js index c8df6d7412c..db1ed47ba1f 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,5 +1,5 @@ import Ember from "ember"; -import { deprecate } from 'ember-data/-debug'; +import { deprecate } from '@ember/debug'; /** Ember Data diff --git a/addon/instance-initializers/initialize-store-service.js b/addon/instance-initializers/initialize-store-service.js index b90651756f0..a3199a68d85 100644 --- a/addon/instance-initializers/initialize-store-service.js +++ b/addon/instance-initializers/initialize-store-service.js @@ -1,4 +1,4 @@ -import { deprecate } from 'ember-data/-debug'; +import { deprecate } from '@ember/debug'; /* Configures a registry for use with an Ember-Data diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 580b202f1d1..b082dec85eb 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { warn } from 'ember-data/-debug'; +import { warn } from '@ember/debug'; const get = Ember.get; const set = Ember.set; diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index e22a6160f73..678766c36dc 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -4,7 +4,9 @@ import Ember from 'ember'; import { pluralize, singularize } from 'ember-inflector'; -import { assert, deprecate, runInDebug, warn } from 'ember-data/-debug'; +import { assert, deprecate, warn } from '@ember/debug'; +import { DEBUG } from '@glimmer/env'; + import JSONSerializer from './json'; import { normalizeModelName, isEnabled } from '../-private'; @@ -286,11 +288,11 @@ const JSONAPISerializer = JSONSerializer.extend({ if (resourceHash.attributes[attributeKey] !== undefined) { attributes[key] = resourceHash.attributes[attributeKey]; } - runInDebug(() => { + if (DEBUG) { if (resourceHash.attributes[attributeKey] === undefined && resourceHash.attributes[key] !== undefined) { assert(`Your payload for '${modelClass.modelName}' contains '${key}', but your serializer is setup to look for '${attributeKey}'. This is most likely because Ember Data's JSON API serializer dasherizes attribute keys by default. You should subclass JSONAPISerializer and implement 'keyForAttribute(key) { return key; }' to prevent Ember Data from customizing your attribute keys.`, false); } - }); + } }); } @@ -329,11 +331,11 @@ const JSONAPISerializer = JSONSerializer.extend({ relationships[key] = this.extractRelationship(relationshipHash); } - runInDebug(() => { + if (DEBUG) { if (resourceHash.relationships[relationshipKey] === undefined && resourceHash.relationships[key] !== undefined) { assert(`Your payload for '${modelClass.modelName}' contains '${key}', but your serializer is setup to look for '${relationshipKey}'. This is most likely because Ember Data's JSON API serializer dasherizes relationship keys by default. You should subclass JSONAPISerializer and implement 'keyForRelationship(key) { return key; }' to prevent Ember Data from customizing your relationship keys.`, false); } - }); + } }); } @@ -734,7 +736,7 @@ if (isEnabled("ds-payload-type-hooks")) { } -runInDebug(function() { +if (DEBUG) { JSONAPISerializer.reopen({ willMergeMixin(props) { let constructor = this.constructor; @@ -752,6 +754,6 @@ runInDebug(function() { return `Encountered a resource object with type "${originalType}", but no model was found for model name "${modelName}" (resolved model name using '${this.constructor.toString()}.${usedLookup}("${originalType}")').`; } }); -}); +} export default JSONAPISerializer; diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 641c7fc6b61..f624bd43f1f 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import { assert, deprecate, warn } from 'ember-data/-debug'; +import { assert, deprecate, warn } from '@ember/debug'; import Serializer from "../serializer"; import { getOwner, diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 0ab46e9f4a3..57c9b7e2824 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -4,7 +4,9 @@ import Ember from 'ember'; import { singularize } from "ember-inflector"; -import { assert, deprecate, runInDebug, warn } from 'ember-data/-debug'; +import { assert, deprecate, warn } from '@ember/debug'; +import { DEBUG } from '@glimmer/env'; + import JSONSerializer from "../serializers/json"; import { coerceId, modelHasAttributeOrRelationshipNamedType, normalizeModelName, isEnabled } from '../-private'; @@ -298,7 +300,7 @@ let RESTSerializer = JSONSerializer.extend({ continue; } - runInDebug(function() { + if (DEBUG) { let isQueryRecordAnArray = requestType === 'queryRecord' && isPrimary && Array.isArray(value); let message = "The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record."; @@ -306,7 +308,7 @@ let RESTSerializer = JSONSerializer.extend({ id: 'ds.serializer.rest.queryRecord-array-response', until: '3.0' }); - }); + } /* Support primary data as an object instead of an array. @@ -972,12 +974,12 @@ if (isEnabled("ds-payload-type-hooks")) { } -runInDebug(function() { +if (DEBUG) { RESTSerializer.reopen({ warnMessageNoModelForKey(prop, typeKey) { return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + typeKey + '" (resolved model name using ' + this.constructor.toString() + '.modelNameFromPayloadKey("' + prop + '"))'; } }); -}); +} export default RESTSerializer; diff --git a/addon/transforms/date.js b/addon/transforms/date.js index 0ceebb80331..98152339160 100644 --- a/addon/transforms/date.js +++ b/addon/transforms/date.js @@ -1,6 +1,6 @@ import Transform from './transform'; import Ember from 'ember'; -import { deprecate } from 'ember-data/-debug'; +import { deprecate } from '@ember/debug'; Ember.Date = Ember.Date || {}; diff --git a/lib/babel-build.js b/lib/babel-build.js index b8b0aef6fb8..4cfbfc0dce7 100644 --- a/lib/babel-build.js +++ b/lib/babel-build.js @@ -1,7 +1,31 @@ +'use strict'; + var babel = require('broccoli-babel-transpiler'); var path = require('path'); var moduleResolve = require('amd-name-resolver').moduleResolve; +function getDebugMacroPlugins() { + const DebugMacros = require('babel-plugin-debug-macros').default; + const isProduction = process.env.EMBER_ENV === 'production'; + + let options = { + envFlags: { + source: '@glimmer/env', + flags: { DEBUG: !isProduction, CI: !!process.env.CI } + }, + + externalizeHelpers: { + global: 'Ember' + }, + + debugTools: { + source: '@ember/debug' + } + }; + + return [DebugMacros, options]; +} + function babelOptions(libraryName, _options) { _options = _options || {}; @@ -25,6 +49,7 @@ function babelOptions(libraryName, _options) { }); options.plugins = options.plugins.concat([ + getDebugMacroPlugins(), ['transform-es2015-modules-amd', { noInterop: true, loose: true }], 'transform-es2015-arrow-functions', 'transform-es2015-computed-properties', diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index eb48cbeda6d..af4310c6d25 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -49,20 +49,13 @@ module.exports = function(environment) { if (environment === 'production' || process.env.INSTRUMENT_HEIMDALL === 'true') { postTransformPlugins.push([StripClassCallCheck]); uniqueAdd(filteredImports, 'ember-data/-debug', [ - 'assert', - 'assertPolymorphicType', - 'debug', - 'deprecate', - 'info', - 'runInDebug', - 'warn', - 'debugSeal' + 'assertPolymorphicType' ]); } plugins.push( [FilterImports, filteredImports], - ['transform-es2015-block-scoping', { 'throwIfClosureRequired': true }] + [TransformBlockScoping, { 'throwIfClosureRequired': true }] ); if (environment === 'production') { diff --git a/package.json b/package.json index a57c10f95a5..2e7b7c109e3 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "testem": "1.15.0" }, "devDependencies": { + "babel-plugin-debug-macros": "^0.1.7", "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", "babel-plugin-transform-es2015-block-scoping": "^6.24.1", "babel-plugin-transform-es2015-classes": "^6.23.0", diff --git a/tests/helpers/test-in-debug.js b/tests/helpers/test-in-debug.js index a69bbbf6437..949b64daac2 100644 --- a/tests/helpers/test-in-debug.js +++ b/tests/helpers/test-in-debug.js @@ -1,15 +1,8 @@ -import require from 'require'; +import { DEBUG } from '@glimmer/env'; import { test, skip } from 'qunit'; export default function testInDebug() { - let isDebug = false; - - // TODO: this should be debug-stripped... - if (require.has('ember-data/-debug')) { - require('ember-data/-debug').runInDebug(() => isDebug = true); - } - - if (isDebug) { + if (DEBUG) { test(...arguments); } else { skip(...arguments); diff --git a/yarn.lock b/yarn.lock index 73a7fbde6c0..6b0f48b4047 100644 --- a/yarn.lock +++ b/yarn.lock @@ -515,7 +515,7 @@ babel-plugin-dead-code-elimination@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" -babel-plugin-debug-macros@^0.1.6: +babel-plugin-debug-macros@^0.1.6, babel-plugin-debug-macros@^0.1.7: version "0.1.7" resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.7.tgz#69f5a3dc7d72f781354f18c611a3b007bb223511" dependencies: @@ -2136,22 +2136,7 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-c ember-cli-version-checker "^1.0.2" resolve "^1.1.2" -ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.10, ember-cli-babel@^6.0.0-beta.7: - version "6.1.0" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.1.0.tgz#d9c83a7d0c67cc8a3ccb9bd082971c3593e54fad" - dependencies: - amd-name-resolver "0.0.6" - babel-plugin-debug-macros "^0.1.6" - babel-plugin-transform-es2015-modules-amd "^6.24.0" - babel-polyfill "^6.16.0" - babel-preset-env "^1.2.0" - broccoli-babel-transpiler "^6.0.0" - broccoli-funnel "^1.0.0" - broccoli-source "^1.1.0" - clone "^2.0.0" - ember-cli-version-checker "^1.2.0" - -ember-cli-babel@^6.1.0: +ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.1.0.tgz#d9c83a7d0c67cc8a3ccb9bd082971c3593e54fad" dependencies: From 631883226e938f04b1087d88957e84604bbd9109 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 4 May 2017 09:28:47 -0400 Subject: [PATCH 1930/2527] [BUGFIX beta] Ensure Engines can boot without error. The argument passed into `instance-initializers` is _either_ an `Ember.ApplicationInstance` instance _or_ a `Ember.EngineInstance` instance. The `.application` property is only present on `Ember.ApplicationInstance`'s. This change adds some inline comments around the various conditionals and swaps the logic to use `instance.base` when present and avoid erroring if neither `.base` or `.application` is present. --- .../initialize-store-service.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/addon/instance-initializers/initialize-store-service.js b/addon/instance-initializers/initialize-store-service.js index a3199a68d85..4e319ba76b5 100644 --- a/addon/instance-initializers/initialize-store-service.js +++ b/addon/instance-initializers/initialize-store-service.js @@ -5,15 +5,20 @@ import { deprecate } from '@ember/debug'; store. @method initializeStoreService - @param {Ember.ApplicationInstance} applicationOrRegistry + @param {Ember.ApplicationInstance | Ember.EngineInstance} instance */ -export default function initializeStoreService(application) { - const container = application.lookup ? application : application.container; +export default function initializeStoreService(instance) { + // instance.lookup supports Ember 2.1 and higher + // instance.container supports Ember 1.11 - 2.0 + const container = instance.lookup ? instance : instance.container; // Eagerly generate the store so defaultStore is populated. container.lookup('service:store'); - deprecateOldEmberDataInitializers(application.application.constructor.initializers); + // In Ember 2.4+ instance.base is the `Ember.Application` or `Ember.Engine` instance + // In Ember 1.11 - 2.3 we fallback to `instance.application` + let base = instance.base || instance.application; + deprecateOldEmberDataInitializers(base.constructor.initializers); } const DEPRECATED_INITIALIZER_NAMES = ['data-adapter', 'injectStore', 'transforms', 'store']; From e8c265a024d0ac54847a4f410311082ba8c972bd Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 4 May 2017 10:05:43 -0400 Subject: [PATCH 1931/2527] Ensure initializer deprecation related code is stripped in production builds. --- .../initialize-store-service.js | 75 ++++++++++--------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/addon/instance-initializers/initialize-store-service.js b/addon/instance-initializers/initialize-store-service.js index 4e319ba76b5..8c03288b54e 100644 --- a/addon/instance-initializers/initialize-store-service.js +++ b/addon/instance-initializers/initialize-store-service.js @@ -1,4 +1,7 @@ import { deprecate } from '@ember/debug'; +import { DEBUG } from '@glimmer/env'; + +let deprecateOldEmberDataInitializers; /* Configures a registry for use with an Ember-Data @@ -15,45 +18,49 @@ export default function initializeStoreService(instance) { // Eagerly generate the store so defaultStore is populated. container.lookup('service:store'); - // In Ember 2.4+ instance.base is the `Ember.Application` or `Ember.Engine` instance - // In Ember 1.11 - 2.3 we fallback to `instance.application` - let base = instance.base || instance.application; - deprecateOldEmberDataInitializers(base.constructor.initializers); + if (DEBUG) { + // In Ember 2.4+ instance.base is the `Ember.Application` or `Ember.Engine` instance + // In Ember 1.11 - 2.3 we fallback to `instance.application` + let base = instance.base || instance.application; + deprecateOldEmberDataInitializers(base.constructor.initializers); + } } -const DEPRECATED_INITIALIZER_NAMES = ['data-adapter', 'injectStore', 'transforms', 'store']; +if (DEBUG) { + const DEPRECATED_INITIALIZER_NAMES = ['data-adapter', 'injectStore', 'transforms', 'store']; -function matchesDeprecatedInititalizer(name) { - return DEPRECATED_INITIALIZER_NAMES.indexOf(name) !== -1; -} + let matchesDeprecatedInititalizer = function matchesDeprecatedInititalizer(name) { + return DEPRECATED_INITIALIZER_NAMES.indexOf(name) !== -1; + }; -function deprecateOldEmberDataInitializers(initializers) { - // collect all of the initializers - let keys = Object.keys(initializers); + let warnForDeprecatedInitializers = function warnForDeprecatedInitializers(initializer) { + let deprecatedBeforeInitializer = matchesDeprecatedInititalizer(initializer.before); + let deprecatedAfterInitializer = matchesDeprecatedInititalizer(initializer.after); + let deprecatedProp = deprecatedBeforeInitializer ? 'before' : 'after'; - for (let i = 0; i < keys.length; i++) { - let name = keys[i]; + deprecate( + `The initializer \`${initializer[deprecatedProp]}\` has been deprecated. Please update your \`${initializer.name}\` initializer to use use \`${deprecatedProp}: \'ember-data\'\` instead.`, + !(deprecatedBeforeInitializer || deprecatedAfterInitializer), + { + id: 'ds.deprecated-initializers', + until: '3.0.0' + }); + }; - // filter out all of the Ember Data initializer. We have some - // deprecated initializers that depend on other deprecated - // initializers which may trigger the deprecation warning - // unintentionally. - if (!matchesDeprecatedInititalizer(name)) { - warnForDeprecatedInitializers(initializers[name]); - } - } -} + deprecateOldEmberDataInitializers = function deprecateOldEmberDataInitializers(initializers) { + // collect all of the initializers + let keys = Object.keys(initializers); -function warnForDeprecatedInitializers(initializer) { - let deprecatedBeforeInitializer = matchesDeprecatedInititalizer(initializer.before); - let deprecatedAfterInitializer = matchesDeprecatedInititalizer(initializer.after); - let deprecatedProp = deprecatedBeforeInitializer ? 'before' : 'after'; - - deprecate( - `The initializer \`${initializer[deprecatedProp]}\` has been deprecated. Please update your \`${initializer.name}\` initializer to use use \`${deprecatedProp}: \'ember-data\'\` instead.`, - !(deprecatedBeforeInitializer || deprecatedAfterInitializer), - { - id: 'ds.deprecated-initializers', - until: '3.0.0' - }) + for (let i = 0; i < keys.length; i++) { + let name = keys[i]; + + // filter out all of the Ember Data initializer. We have some + // deprecated initializers that depend on other deprecated + // initializers which may trigger the deprecation warning + // unintentionally. + if (!matchesDeprecatedInititalizer(name)) { + warnForDeprecatedInitializers(initializers[name]); + } + } + }; } From c6eab0167f7e0f5a6d40ac61577a627f35a7dbf2 Mon Sep 17 00:00:00 2001 From: Ashley Ellis Pierce Date: Thu, 4 May 2017 11:18:42 -0400 Subject: [PATCH 1932/2527] Fix typo in function call --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 32ca4327b78..30eccdf9c0e 100644 --- a/index.js +++ b/index.js @@ -80,7 +80,7 @@ module.exports = { this._forceBowerUsage = true; var emberDataBower = checker.for('ember-data', 'bower'); - var emberDataBowerWithShimsIncluded = emberDataBower.satisifies('>= 2.3.0-beta.3'); + var emberDataBowerWithShimsIncluded = emberDataBower.satisfies('>= 2.3.0-beta.3'); if (hasShims && !shimsHasEmberDataShims && !emberDataBowerWithShimsIncluded) { throw new SilentError('Using a version of ember-cli-shims greater than or equal to 0.1.0 will cause errors while loading Ember Data < 2.3.0-beta.3 Please update ember-cli-shims from ' + shims.version + ' to 0.0.6'); From 80916050a369d65dc4864ad5beb4184f2604c172 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 5 May 2017 13:03:19 -0400 Subject: [PATCH 1933/2527] Update changelog for the 2.13.1 release --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48b4e84f8aa..8ad8ff02686 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ### Master +### Release 2.13.1 (May 5, 2017) +- [#4965](https://github.com/emberjs/data/pull/4965) [BUGFIX beta] Skip test which doesn't play nicely with the latest em… +- [#4970](https://github.com/emberjs/data/pull/4970) [BUGFIX release] Ensure Engines can boot without error. ### Release 2.13.0 (April 28, 2017) - [#4860](https://github.com/emberjs/data/pull/4860) Refactor the detection / warnings around ember-cli-shims. From 595dfd8517c0b904f5c8624e8c1b8f5529656299 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 9 May 2017 10:00:31 -0700 Subject: [PATCH 1934/2527] Update adapter-populated-record-array-test.js --- .../record-arrays/adapter-populated-record-array-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/record-arrays/adapter-populated-record-array-test.js b/tests/integration/record-arrays/adapter-populated-record-array-test.js index a8304fcb694..ce0273964b4 100644 --- a/tests/integration/record-arrays/adapter-populated-record-array-test.js +++ b/tests/integration/record-arrays/adapter-populated-record-array-test.js @@ -161,7 +161,7 @@ test('recordArray.replace() throws error', function(assert) { }, Error('The result of a server query (on person) is immutable.'), 'throws error'); }); -test('only pass record array if explicitly in arity', function(assert) { +test('pass record array to adapter.query based on arity', function(assert) { let env = setupStore({ person: Person }); let store = env.store; @@ -184,7 +184,7 @@ test('only pass record array if explicitly in arity', function(assert) { }); }); -test('only pass record array if explicitly in arity', function(assert) { +test('pass record array to adapter.query based on arity', function(assert) { let env = setupStore({ person: Person }); let store = env.store; From a27245cd4954b4718650cd3ae7ffee654efcefed Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 10 May 2017 17:30:48 -0400 Subject: [PATCH 1935/2527] Lock ember-cli-htmlbars to 1.3.0 to get the build passing again --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2e7b7c109e3..3728d84d529 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "ember-cli-blueprint-test-helpers": "0.11.0", "ember-cli-dependency-checker": "^1.3.0", "ember-cli-eslint": "1.3.0", - "ember-cli-htmlbars": "^1.1.1", + "ember-cli-htmlbars": "1.3.0", "ember-cli-htmlbars-inline-precompile": "^0.4.0-beta.2", "ember-cli-inject-live-reload": "^1.4.1", "ember-cli-internal-test-helpers": "^0.8.1", From 1fe6bf36940dcd164b27c0b1ab6675358013f80a Mon Sep 17 00:00:00 2001 From: Cory Date: Thu, 11 May 2017 15:06:44 -0400 Subject: [PATCH 1936/2527] [DOC release] Docs for has-many, belongs-to ref meta Change the description of the DS.HasManyReference.meta Fix a typo in return description for DS.BelongsToReference.meta --- addon/-private/system/references/belongs-to.js | 2 +- addon/-private/system/references/has-many.js | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 4f41f272389..e81a5b0a6af 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -189,7 +189,7 @@ BelongsToReference.prototype.link = function() { ``` @method meta - @return {Object} The meta information for the belongs-oo relationship. + @return {Object} The meta information for the belongs-to relationship. */ BelongsToReference.prototype.meta = function() { return this.belongsToRelationship.meta; diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 09da13aa653..67e6d43bd30 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -158,8 +158,7 @@ HasManyReference.prototype.ids = function() { }; /** - The link Ember Data will use to fetch or reload this has-many - relationship. + The meta data for the has-many relationship. Example From cff44028b356e4aab8a73b4759a3ac6ca4b4415a Mon Sep 17 00:00:00 2001 From: Cory Date: Thu, 11 May 2017 15:14:20 -0400 Subject: [PATCH 1937/2527] [DOC release] Document DS.HasManyReference.ids The existing inline doc incorrectly marks the method name as `remoteType`. --- addon/-private/system/references/has-many.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 09da13aa653..c67c2868b69 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -146,7 +146,7 @@ HasManyReference.prototype.link = function() { commentsRef.ids(); // ['1'] ``` - @method remoteType + @method ids @return {Array} The ids in this has-many relationship */ HasManyReference.prototype.ids = function() { From fcc7d76e7faf96dfd8113d8d1364433c5805a4c3 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 11 May 2017 15:12:36 -0700 Subject: [PATCH 1938/2527] update ember-cli-htmlbars --- package.json | 4 +-- yarn.lock | 69 ++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index 2e7b7c109e3..f3635514233 100644 --- a/package.json +++ b/package.json @@ -73,8 +73,8 @@ "ember-cli-blueprint-test-helpers": "0.11.0", "ember-cli-dependency-checker": "^1.3.0", "ember-cli-eslint": "1.3.0", - "ember-cli-htmlbars": "^1.1.1", - "ember-cli-htmlbars-inline-precompile": "^0.4.0-beta.2", + "ember-cli-htmlbars": "^2.0.1", + "ember-cli-htmlbars-inline-precompile": "^0.4.3", "ember-cli-inject-live-reload": "^1.4.1", "ember-cli-internal-test-helpers": "^0.8.1", "ember-cli-pretender": "^1.0.1", diff --git a/yarn.lock b/yarn.lock index 6b0f48b4047..204f6b4deae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1124,29 +1124,29 @@ broccoli-builder@^0.18.3: rsvp "^3.0.17" silent-error "^1.0.1" -broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" +broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.1: + version "2.0.4" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" + lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - walk-sync "^0.2.5" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" -broccoli-caching-writer@~2.0.1: - version "2.0.4" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" +broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" - lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - symlink-or-copy "^1.0.0" - walk-sync "^0.2.0" + walk-sync "^0.2.5" broccoli-clean-css@^1.1.0: version "1.1.0" @@ -2200,15 +2200,16 @@ ember-cli-get-dependency-depth@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" -ember-cli-htmlbars-inline-precompile@^0.4.0-beta.2: - version "0.4.0" - resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.0.tgz#4a6d2211b804419953104a9231e112dbd2057f3c" +ember-cli-htmlbars-inline-precompile@^0.4.3: + version "0.4.3" + resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.3.tgz#4123f507fea6c59ba4c272ef7e713a6d55ba06c9" dependencies: babel-plugin-htmlbars-inline-precompile "^0.2.3" - ember-cli-version-checker "^1.2.0" + ember-cli-version-checker "^2.0.0" hash-for-dep "^1.0.2" + silent-error "^1.1.0" -ember-cli-htmlbars@^1.0.0, ember-cli-htmlbars@^1.1.1: +ember-cli-htmlbars@^1.0.0: version "1.3.0" resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-1.3.0.tgz#e090f011239153bf45dab29625f94a46fce205af" dependencies: @@ -2218,6 +2219,15 @@ ember-cli-htmlbars@^1.0.0, ember-cli-htmlbars@^1.1.1: json-stable-stringify "^1.0.0" strip-bom "^2.0.0" +ember-cli-htmlbars@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-2.0.1.tgz#e1e333c7ef4cc546c67734996541fd94ca4423ca" + dependencies: + broccoli-persistent-filter "^1.0.3" + hash-for-dep "^1.0.2" + json-stable-stringify "^1.0.0" + strip-bom "^3.0.0" + ember-cli-inject-live-reload@^1.4.1: version "1.6.1" resolved "https://registry.npmjs.org/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.6.1.tgz#82b8f5be454815a75e7f6d42c9ce0bc883a914a3" @@ -2380,6 +2390,13 @@ ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-ve dependencies: semver "^5.3.0" +ember-cli-version-checker@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-2.0.0.tgz#e1f7d8e4cdcd752ac35f1611e4daa8836db4c4c7" + dependencies: + resolve "^1.3.3" + semver "^5.3.0" + ember-cli@^2.11.1: version "2.13.0" resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.13.0.tgz#c80d06ff8e16a47b0b2e5fbdb8761feebca86368" @@ -5310,7 +5327,7 @@ resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" -resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.0: +resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" dependencies: @@ -5329,13 +5346,13 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.4, rimraf@^2.4.3, rimraf@^2.4.4: +rimraf@2.5.2, rimraf@^2.4.3, rimraf@^2.4.4: version "2.5.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" -rimraf@^2.1.4, rimraf@^2.3.2, rimraf@^2.4.1, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: +rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: version "2.6.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: @@ -5359,11 +5376,11 @@ route-recognizer@^0.2.3: version "0.2.10" resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" -rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.6, rsvp@^3.2.1, rsvp@~3.2.1: +rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.6, rsvp@~3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" -rsvp@^3.0.14, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3, rsvp@^3.4.0: +rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: version "3.5.0" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" @@ -5503,12 +5520,18 @@ signal-exit@^3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" -silent-error@^1.0.0, silent-error@^1.0.1: +silent-error@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.0.1.tgz#71b7d503d1c6f94882b51b56be879b113cb4822c" dependencies: debug "^2.2.0" +silent-error@^1.0.1, silent-error@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.1.0.tgz#2209706f1c850a9f1d10d0d840918b46f26e1bc9" + dependencies: + debug "^2.2.0" + simple-dom@^0.3.0: version "0.3.2" resolved "https://registry.npmjs.org/simple-dom/-/simple-dom-0.3.2.tgz#0663d10f1556f1500551d518f56e3aba0871371d" @@ -5754,6 +5777,10 @@ strip-bom@^2.0.0: dependencies: is-utf8 "^0.2.0" +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" From b4c7a48f59b4318a7a9a76b7b5e53c0a0d195688 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 12 May 2017 14:14:42 -0700 Subject: [PATCH 1939/2527] yarn in travis --- .travis.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0467aedc21c..5adafb1c5b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,13 +2,13 @@ language: node_js sudo: false node_js: - - "6.9" -before_install: - - "npm config set spin false" - - "npm install -g npm@^2" + - "7" + +cache: + yarn: true install: - - npm install --no-optional + - npm install - ./node_modules/.bin/bower install script: - ./bin/lint-features @@ -17,7 +17,7 @@ script: - npm run-script test:production - npm run-script node-tests after_success: - - npm run-script production + - yarn run production - "./bin/publish-builds" env: global: From 2c55a732a3bdede02b41d4e36350427ff9f05977 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 12 May 2017 14:18:59 -0700 Subject: [PATCH 1940/2527] switch appveyor to prefer yarn --- appveyor.yml | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 706a81149bb..272a4d317c1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,7 +3,11 @@ # Test against these versions of Node.js. environment: matrix: - - nodejs_version: "6.9" + - nodejs_version: "7" + +cache: + - '%LOCALAPPDATA%\Yarn' + - '%APPDATA%\Roaming\bower' # Install scripts. (runs after repo cloning) install: @@ -14,21 +18,19 @@ install: - set path=%path%;C:\ProgramData\chocolatey\lib\PhantomJS\tools\ # Typical npm stuff. - md C:\nc - - npm install -g npm@^2 + - appveyor-retry npm install -g npm@^3 + - appveyor-retry yarn # Workaround https://github.com/npm/npm/wiki/Troubleshooting#upgrading-on-windows - - set PATH=%APPDATA%\npm;%PATH% - - npm config set cache C:\nc - - npm version - - npm install --no-optional - - npm run bower + - yarn version + - yarn run bower # Post-install test scripts. test_script: # Output useful info for debugging. - npm version - - cmd: npm run test - - cmd: npm run test:optional-features - - cmd: npm run test:production - - cmd: npm run node-tests + - cmd: yarn run test + - cmd: yarn run test:optional-features + - cmd: yarn run test:production + - cmd: yarn run node-tests # Don't actually build. build: off From 410fa36f20fddf15106874a41c64cc48fed11817 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 15 May 2017 10:49:26 -0700 Subject: [PATCH 1941/2527] update to yarn --- .travis.yml | 11 ++++++----- appveyor.yml | 5 +---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5adafb1c5b3..7e1a36cfec7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,14 +8,15 @@ cache: yarn: true install: - - npm install + - yarn + - yarn global add phantomjs-prebuilt - ./node_modules/.bin/bower install script: - ./bin/lint-features - - npm run-script test - - npm run-script test:optional-features - - npm run-script test:production - - npm run-script node-tests + - yarn run test + - yarn run test:optional-features + - yarn run test:production + - yarn run node-tests after_success: - yarn run production - "./bin/publish-builds" diff --git a/appveyor.yml b/appveyor.yml index 272a4d317c1..913d6ace70b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -18,15 +18,12 @@ install: - set path=%path%;C:\ProgramData\chocolatey\lib\PhantomJS\tools\ # Typical npm stuff. - md C:\nc - - appveyor-retry npm install -g npm@^3 - - appveyor-retry yarn + - appveyor-retry yarn install # Workaround https://github.com/npm/npm/wiki/Troubleshooting#upgrading-on-windows - - yarn version - yarn run bower # Post-install test scripts. test_script: # Output useful info for debugging. - - npm version - cmd: yarn run test - cmd: yarn run test:optional-features - cmd: yarn run test:production From a36a44ff207a3167b0582ce20c15810126ef3676 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 15 May 2017 21:08:54 -0700 Subject: [PATCH 1942/2527] such travis --- .travis.yml | 9 ++++++++- package.json | 1 - 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7e1a36cfec7..d6beab2f203 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,17 @@ node_js: cache: yarn: true +before_install: + - "export PATH=$PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64/bin:$PATH" + - "if [ $(phantomjs --version) != '2.1.1' ]; then rm -rf $PWD/travis_phantomjs; mkdir -p $PWD/travis_phantomjs; fi" + - "if [ $(phantomjs --version) != '2.1.1' ]; then wget https://assets.membergetmember.co/software/phantomjs-2.1.1-linux-x86_64.tar.bz2 -O $PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64.tar.bz2; fi" + - "if [ $(phantomjs --version) != '2.1.1' ]; then tar -xvf $PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64.tar.bz2 -C $PWD/travis_phantomjs; fi" + - "phantomjs --version" + install: - yarn - - yarn global add phantomjs-prebuilt - ./node_modules/.bin/bower install + script: - ./bin/lint-features - yarn run test diff --git a/package.json b/package.json index f3635514233..f448b91cc8c 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,6 @@ "mocha": "2.4.5", "mocha-only-detector": "0.0.2", "morgan": "^1.7.0", - "phantomjs-prebuilt": "^2.1.12", "pretender": "1.0.0", "rimraf": "2.5.2", "rsvp": "3.2.1" From ad9382c11d6f55b7e008f11be12e868dbae0275a Mon Sep 17 00:00:00 2001 From: Ryunosuke Sato Date: Sat, 13 May 2017 00:31:51 +0900 Subject: [PATCH 1943/2527] [DOC release] Fix doc for `diffArray` - Fix method name from `diff-array` to `diffArray` - This is not a public method --- addon/-private/system/diff-array.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/diff-array.js b/addon/-private/system/diff-array.js index 5c0c2fb8868..ae28e8e35b3 100644 --- a/addon/-private/system/diff-array.js +++ b/addon/-private/system/diff-array.js @@ -1,7 +1,7 @@ /** @namespace - @method diff-array - @for DS + @method diffArray + @private @param {Array} oldArray the old array @param {Array} newArray the new array @return {hash} { From 96a920863946cc6a0878ebe9d836a66e372a8984 Mon Sep 17 00:00:00 2001 From: Wesley Workman Date: Tue, 30 May 2017 08:33:20 -0400 Subject: [PATCH 1944/2527] [BUGFIX BETA] Added `system/store/container-instance-cache` to the -private export file --- addon/-private/index.js | 4 +++- tests/unit/private-test.js | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tests/unit/private-test.js diff --git a/addon/-private/index.js b/addon/-private/index.js index ba709785c38..c6ecf77b842 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -28,10 +28,12 @@ export { default as coerceId } from './system/coerce-id'; export { default as parseResponseHeaders } from './utils/parse-response-headers'; // should be private ? -export { default as RootState } from './system/model/states'; export { default as global } from './global'; export { default as isEnabled } from './features'; +// `ember-data-model-fragments` relies on `RootState`, `InternalModel` and `ContainerInstanceCache` +export { default as RootState } from './system/model/states'; export { default as InternalModel } from './system/model/internal-model'; +export { default as ContainerInstanceCache } from './system/store/container-instance-cache'; export { PromiseArray, diff --git a/tests/unit/private-test.js b/tests/unit/private-test.js new file mode 100644 index 00000000000..bd42b3a33b2 --- /dev/null +++ b/tests/unit/private-test.js @@ -0,0 +1,16 @@ +import { module, test } from 'qunit'; +import { ContainerInstanceCache, InternalModel, RootState } from 'ember-data/-private'; + +module('-private'); + +test('`ContainerInstanceCache` is accessible via private import', function(assert) { + assert.ok(!!ContainerInstanceCache); +}); + +test('`InternalModel` is accessible via private import', function(assert) { + assert.ok(!!InternalModel); +}); + +test('`RootState` is accessible via private import', function(assert) { + assert.ok(!!RootState); +}); From f79d398feedf0a620480b98e57a4fbd20bf3e595 Mon Sep 17 00:00:00 2001 From: Wesley Workman Date: Fri, 9 Jun 2017 13:33:14 -0400 Subject: [PATCH 1945/2527] [BUGFIX BETA]: Fixed export regression. `ember-data/transform` to be export using `default`. --- addon/transform.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/transform.js b/addon/transform.js index 0d5bdf1934a..efd07599fb0 100644 --- a/addon/transform.js +++ b/addon/transform.js @@ -1 +1 @@ -export { Transform } from './-private'; +export { default } from './transforms/transform'; From 56b170b9b66d2ca59a27d5d09ac0e403ee252afa Mon Sep 17 00:00:00 2001 From: bekzod Date: Sun, 11 Jun 2017 16:46:30 +0500 Subject: [PATCH 1946/2527] cleanup `index.js` and drop `0.12` node --- index.js | 74 ++++++++++++++++++++++++++-------------------------- package.json | 2 +- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/index.js b/index.js index 30eccdf9c0e..e89578dd8bf 100644 --- a/index.js +++ b/index.js @@ -1,33 +1,34 @@ /* eslint-env node */ 'use strict'; -var path = require('path'); -var SilentError = require('silent-error'); -var Funnel = require('broccoli-funnel'); -var Rollup = require('broccoli-rollup'); -var Babel = require('broccoli-babel-transpiler'); -var merge = require('broccoli-merge-trees'); -var version = require('./lib/version'); +const path = require('path'); +const SilentError = require('silent-error'); +const Funnel = require('broccoli-funnel'); +const Rollup = require('broccoli-rollup'); +const Babel = require('broccoli-babel-transpiler'); +const merge = require('broccoli-merge-trees'); +const semver = require('semver'); +const version = require('./lib/version'); // allow toggling of heimdall instrumentation -var INSTRUMENT_HEIMDALL = false; -var args = process.argv; +let INSTRUMENT_HEIMDALL = false; +let args = process.argv; -for (var i = 0; i < args.length; i++) { +for (let i = 1; i < args.length; i++) { if (args[i] === '--instrument') { INSTRUMENT_HEIMDALL = true; break; } } -var NOOP_TREE = function(dir ) { - return { inputTree: dir, rebuild: function() { return []; } }; +const NOOP_TREE = function(dir) { + return { inputTree: dir, rebuild() { return []; } }; }; process.env.INSTRUMENT_HEIMDALL = INSTRUMENT_HEIMDALL; function isProductionEnv() { - var isProd = /production/.test(process.env.EMBER_ENV); - var isTest = process.env.EMBER_CLI_TEST_COMMAND; + let isProd = /production/.test(process.env.EMBER_ENV); + let isTest = process.env.EMBER_CLI_TEST_COMMAND; return isProd && !isTest; } @@ -35,9 +36,9 @@ function isProductionEnv() { module.exports = { name: 'ember-data', - _warn: function(message) { - var chalk = require('chalk'); - var warning = chalk.yellow('WARNING: ' + message); + _warn(message) { + let chalk = require('chalk'); + let warning = chalk.yellow('WARNING: ' + message); if (this.ui && this.ui.writeWarnLine) { this.ui.writeWarnLine(message); @@ -48,20 +49,19 @@ module.exports = { } }, - init: function() { + init() { this._super.init && this._super.init.apply(this, arguments); - var bowerDeps = this.project.bowerDependencies(); + let bowerDeps = this.project.bowerDependencies(); - var VersionChecker = require('ember-cli-version-checker'); - var options = this.options = this.options || {}; + let VersionChecker = require('ember-cli-version-checker'); + let options = this.options = this.options || {}; - var checker = new VersionChecker(this); + let checker = new VersionChecker(this); // prevent errors when ember-cli-shims is no longer required - var shims = bowerDeps['ember-cli-shims'] && checker.for('ember-cli-shims', 'bower'); + let shims = bowerDeps['ember-cli-shims'] && checker.for('ember-cli-shims', 'bower'); - var semver = require('semver'); - var version = require('./package').version; + let version = require('./package').version; if (process.env.EMBER_DATA_SKIP_VERSION_CHECKING_DO_NOT_USE_THIS_ENV_VARIABLE) { // Skip for node tests as we can't currently override the version of ember-cli-shims @@ -69,9 +69,9 @@ module.exports = { return; } - var hasShims = !!shims; - var shimsHasEmberDataShims = hasShims && shims.satisfies('< 0.1.0'); - var emberDataNPMWithShimsIncluded = semver.satisfies(version, '^2.3.0-beta.3'); + let hasShims = !!shims; + let shimsHasEmberDataShims = hasShims && shims.satisfies('< 0.1.0'); + let emberDataNPMWithShimsIncluded = semver.satisfies(version, '^2.3.0-beta.3'); if (bowerDeps['ember-data']) { this._warn('Please remove `ember-data` from `bower.json`. As of Ember Data 2.3.0, only the NPM package is needed. If you need an ' + @@ -79,8 +79,8 @@ module.exports = { 'as soon as possible.'); this._forceBowerUsage = true; - var emberDataBower = checker.for('ember-data', 'bower'); - var emberDataBowerWithShimsIncluded = emberDataBower.satisfies('>= 2.3.0-beta.3'); + let emberDataBower = checker.for('ember-data', 'bower'); + let emberDataBowerWithShimsIncluded = emberDataBower.satisfies('>= 2.3.0-beta.3'); if (hasShims && !shimsHasEmberDataShims && !emberDataBowerWithShimsIncluded) { throw new SilentError('Using a version of ember-cli-shims greater than or equal to 0.1.0 will cause errors while loading Ember Data < 2.3.0-beta.3 Please update ember-cli-shims from ' + shims.version + ' to 0.0.6'); @@ -98,11 +98,11 @@ module.exports = { } }, - blueprintsPath: function() { + blueprintsPath() { return path.join(__dirname, 'blueprints'); }, - treeForApp: function(dir) { + treeForApp(dir) { if (this._forceBowerUsage) { return NOOP_TREE(dir); } // this._super.treeForApp is undefined in ember-cli (1.13) for some reason. @@ -110,7 +110,7 @@ module.exports = { return dir; }, - treeForAddon: function(tree) { + treeForAddon(tree) { if (this._forceBowerUsage) { return NOOP_TREE(tree); } let babel = this.addons.find(addon => addon.name === 'ember-cli-babel'); @@ -130,7 +130,7 @@ module.exports = { destDir: 'ember-data' }); - var privateTree = babel.transpileTree(withPrivate, { + let privateTree = babel.transpileTree(withPrivate, { babel: this.buildBabelOptions(), 'ember-cli-babel': { compileModules: false @@ -138,7 +138,7 @@ module.exports = { }); // use the default options - var publicTree = babel.transpileTree(withoutPrivate); + let publicTree = babel.transpileTree(withoutPrivate); privateTree = new Rollup(privateTree, { rollup: { @@ -181,7 +181,7 @@ module.exports = { }; }, - _setupBabelOptions: function() { + _setupBabelOptions() { if (this._hasSetupBabelOptions) { return; } @@ -191,7 +191,7 @@ module.exports = { this._hasSetupBabelOptions = true; }, - included: function(app) { + included(app) { this._super.included.apply(this, arguments); this._setupBabelOptions(); diff --git a/package.json b/package.json index f448b91cc8c..d8c115eb908 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "ember-inflector": "^2.0.0" }, "engines": { - "node": ">= 0.12.0" + "node": ">= 4.0.0" }, "keywords": [ "ember-addon" From 012372cd4a229f91bba319a66a38c183929db8d2 Mon Sep 17 00:00:00 2001 From: Lisa Backer Date: Tue, 13 Jun 2017 10:20:11 -0400 Subject: [PATCH 1947/2527] Change setupStore helper default serializer to JSONAPISerializer #4754 (#5003) * Change setupStore helper default serializer to JSONAPISerializer #4754 * Update test per review feedback --- tests/helpers/store.js | 5 +- tests/integration/adapter/find-all-test.js | 20 +- tests/integration/adapter/find-test.js | 29 +- tests/integration/adapter/queries-test.js | 27 +- .../adapter/record-persistence-test.js | 12 +- .../integration/adapter/store-adapter-test.js | 119 +++-- .../integration/client-id-generation-test.js | 2 +- tests/integration/filter-test.js | 117 +++- tests/integration/lifecycle-hooks-test.js | 2 +- tests/integration/record-array-test.js | 21 +- .../adapter-populated-record-array-test.js | 48 +- .../records/collection-save-test.js | 6 +- .../records/property-changes-test.js | 2 +- tests/integration/records/reload-test.js | 55 +- tests/integration/records/save-test.js | 4 +- .../integration/references/belongs-to-test.js | 30 +- tests/integration/references/has-many-test.js | 18 +- tests/integration/references/record-test.js | 32 +- .../relationships/belongs-to-test.js | 179 +++++-- .../relationships/has-many-test.js | 500 ++++++++++++------ .../relationships/one-to-one-test.js | 4 +- .../serializers/json-api-serializer-test.js | 2 +- .../serializers/json-serializer-test.js | 35 +- .../serializers/rest-serializer-test.js | 11 + tests/integration/snapshot-test.js | 18 +- tests/integration/store-test.js | 7 +- tests/integration/store/query-record-test.js | 2 +- tests/unit/model-test.js | 20 +- tests/unit/model/lifecycle-callbacks-test.js | 8 +- tests/unit/model/merge-test.js | 8 +- .../model/relationships/belongs-to-test.js | 29 +- .../unit/model/relationships/has-many-test.js | 29 +- tests/unit/store/adapter-interop-test.js | 84 +-- tests/unit/store/finders-test.js | 14 +- tests/unit/store/push-test.js | 63 ++- tests/unit/store/unload-test.js | 13 +- 36 files changed, 1093 insertions(+), 482 deletions(-) diff --git a/tests/helpers/store.js b/tests/helpers/store.js index 4948ab027f9..d76792e08be 100644 --- a/tests/helpers/store.js +++ b/tests/helpers/store.js @@ -49,13 +49,12 @@ export default function setupStore(options) { registry.optionsForType('adapter', { singleton: false }); registry.register('adapter:-default', DS.Adapter); - registry.register('serializer:-default', DS.JSONSerializer); + registry.register('serializer:-default', DS.JSONAPISerializer); + registry.register('serializer:-json', DS.JSONSerializer); registry.register('serializer:-rest', DS.RESTSerializer); registry.register('adapter:-rest', DS.RESTAdapter); - registry.register('adapter:-json-api', DS.JSONAPIAdapter); - registry.register('serializer:-json-api', DS.JSONAPISerializer); env.restSerializer = container.lookup('serializer:-rest'); env.store = container.lookup('service:store'); diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index ce836f680ac..914a4652e9d 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -45,7 +45,13 @@ test("When all records for a type are requested, the store should call the adapt // this will get called twice assert.ok(true, "the adapter's findAll method should be invoked"); - return resolve([{ id: 1, name: "Braaaahm Dale" }]); + return resolve({ data: [{ + id: 1, + type: 'person', + attributes: { + name: "Braaaahm Dale" + } + }]}); } })); @@ -75,7 +81,13 @@ test("When all records for a type are requested, a rejection should reject the p if (count++ === 0) { return reject(); } else { - return resolve([{ id: 1, name: "Braaaahm Dale" }]); + return resolve({ data: [{ + id: 1, + type: 'person', + attributes: { + name: "Braaaahm Dale" + } + }]}); } } })); @@ -185,7 +197,7 @@ test("isUpdating is true while records are fetched", function(assert) { assert.equal(persons.get("isUpdating"), true); - findAllDeferred.resolve([{ id: 2 }]); + findAllDeferred.resolve({ data: [{ id: 2, type: 'person' }] }); }); test("isUpdating is true while records are fetched in the background", function(assert) { @@ -223,7 +235,7 @@ test("isUpdating is true while records are fetched in the background", function( assert.equal(persons.get("isUpdating"), true); run(function() { - findAllDeferred.resolve([{ id: 2 }]); + findAllDeferred.resolve({ data: [{ id: 2, type: 'person' }] }); }); run(function() { diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 8e6b7f97e08..2dd54dfb1ee 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -51,7 +51,15 @@ test("When a single record is requested, the adapter's find method should be cal assert.equal(count, 0, "the find method is only called once"); count++; - return { id: 1, name: "Braaaahm Dale" }; + return { + data: { + id: 1, + type: "person", + attributes: { + name: "Braaaahm Dale" + } + } + }; } })); @@ -101,7 +109,14 @@ test("When a single record is requested multiple times, all .findRecord() calls })); }); - run(() => deferred.resolve({ id: 1, name: "Braaaahm Dale" })); + run(() => deferred.resolve({ + data: { + id: 1, + type: "person", + attributes: { + name: "Braaaahm Dale" + } + }})); }); test("When a single record is requested, and the promise is rejected, .findRecord() is rejected.", (assert) => { @@ -158,7 +173,15 @@ testInDebug('When multiple records are requested, and the payload is blank', (as testInDebug("warns when returned record has different id", function(assert) { env.registry.register('adapter:person', DS.Adapter.extend({ findRecord() { - return { id: 1, name: "Braaaahm Dale" }; + return { + data: { + id: 1, + type: "person", + attributes: { + name: "Braaaahm Dale" + } + } + }; } })); diff --git a/tests/integration/adapter/queries-test.js b/tests/integration/adapter/queries-test.js index fcc354a5196..7797127e98c 100644 --- a/tests/integration/adapter/queries-test.js +++ b/tests/integration/adapter/queries-test.js @@ -45,8 +45,25 @@ test("When a query is made, the adapter should receive a record array it can pop adapter.query = function(store, type, query, recordArray) { assert.equal(type, Person, "the query method is called with the correct type"); - return Ember.RSVP.resolve([{ id: 1, name: "Peter Wagenet" }, { id: 2, name: "Brohuda Katz" }]); - }; + return Ember.RSVP.resolve({ + data: [ + { + id: 1, + type: 'person', + attributes: { + name: "Peter Wagenet" + } + }, + { + id: 2, + type: "person", + attributes: { + name: "Brohuda Katz" + } + } + ] + }); + } store.query('person', { page: 1 }).then(assert.wait(function(queryResults) { assert.equal(get(queryResults, 'length'), 2, "the record array has a length of 2 after the results are loaded"); @@ -59,7 +76,7 @@ test("When a query is made, the adapter should receive a record array it can pop test("a query can be updated via `update()`", function(assert) { adapter.query = function() { - return Ember.RSVP.resolve([{ id: 'first' }]); + return Ember.RSVP.resolve({ data: [{ id: 'first', type: 'person' }] }); }; run(function() { @@ -70,7 +87,7 @@ test("a query can be updated via `update()`", function(assert) { adapter.query = function() { assert.ok('query is called a second time'); - return Ember.RSVP.resolve([{ id: 'second' }]); + return Ember.RSVP.resolve({data: [{ id: 'second', type: 'person' }] }); }; let updateQuery = query.update(); @@ -96,7 +113,7 @@ testInDebug("The store asserts when query is made and the adapter responses with adapter.query = function(store, type, query, recordArray) { assert.equal(type, Person, "the query method is called with the correct type"); - return Ember.RSVP.resolve({ people: { id: 1, name: "Peter Wagenet" } }); + return Ember.RSVP.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Peter Wagenet" } }] }); }; assert.expectAssertion(function() { diff --git a/tests/integration/adapter/record-persistence-test.js b/tests/integration/adapter/record-persistence-test.js index 289976dac5f..3a4091bd5e3 100644 --- a/tests/integration/adapter/record-persistence-test.js +++ b/tests/integration/adapter/record-persistence-test.js @@ -78,7 +78,7 @@ test("When a store is committed, the adapter's `commit` method should be called assert.equal(type, Person, "the type is correct"); assert.equal(snapshot.record, tom, "the record is correct"); - return Ember.RSVP.resolve({ id: 1, name: "Tom Dale" }); + return Ember.RSVP.resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale" } } }); }; run(function() { @@ -92,7 +92,7 @@ test("After a created record has been assigned an ID, finding a record by that I var tom; env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: "Tom Dale" }); + return Ember.RSVP.resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale" } } }); }; run(function() { @@ -178,9 +178,9 @@ test("An adapter can notify the store that records were updated by calling `didS test("An adapter can notify the store that records were updated and provide new data by calling `didSaveRecords`.", function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { if (snapshot.id === "1") { - return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", updatedAt: "now" }); + return Ember.RSVP.resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale", "updated-at": "now" } } }); } else if (snapshot.id === "2") { - return Ember.RSVP.resolve({ id: 2, name: "Yehuda Katz", updatedAt: "now!" }); + return Ember.RSVP.resolve({ data: { id: 2, type: "person", attributes: { name: "Yehuda Katz", "updated-at": "now!" } } }); } }; @@ -249,9 +249,9 @@ test("An adapter can notify the store that a record was updated and provide new env.adapter.updateRecord = function(store, type, snapshot) { switch (snapshot.id) { case "1": - return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", updatedAt: "now" }); + return Ember.RSVP.resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale", "updated-at": "now" } } }); case "2": - return Ember.RSVP.resolve({ id: 2, name: "Yehuda Katz", updatedAt: "now!" }); + return Ember.RSVP.resolve({ data: { id: 2, type: "person", attributes: { name: "Yehuda Katz", "updated-at": "now!" } } }); } }; diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 3348ca6a9ca..fe114a08d69 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -58,13 +58,23 @@ module("integration/adapter/store-adapter - DS.Store and DS.Adapter integration test("Records loaded multiple times and retrieved in recordArray are ready to send state events", function(assert) { adapter.query = function(store, type, query, recordArray) { - return Ember.RSVP.resolve([{ - id: 1, - name: "Mickael Ramírez" - }, { - id: 2, - name: "Johny Fontana" - }]); + return Ember.RSVP.resolve({ + data: [ + { + id: 1, + type: "person", + attributes: { + name: "Mickael Ramírez" + } + }, { + id: 2, + type: "person", + attributes: { + name: "Johny Fontana" + } + } + ] + }); }; run(store, 'query', 'person', { q: 'bla' }).then(assert.wait(function(people) { @@ -99,11 +109,17 @@ test("by default, createRecords calls createRecord once per record", function(as } var hash = snapshot.attributes(); - hash.id = count; - hash.updatedAt = "now"; + var recordId = count; + hash['updated-at'] = "now"; count++; - return Ember.RSVP.resolve(hash); + return Ember.RSVP.resolve({ + data: { + id: recordId, + type: "person", + attributes: hash + } + }); }; var tom, yehuda; @@ -206,10 +222,10 @@ test("calling store.didSaveRecord can provide an optional hash", function(assert count++; if (count === 1) { assert.equal(snapshot.attr('name'), "Tom Dale"); - return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", updatedAt: "now" }); + return Ember.RSVP.resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale", "updated-at": "now" } } }); } else if (count === 2) { assert.equal(snapshot.attr('name'), "Yehuda Katz"); - return Ember.RSVP.resolve({ id: 2, name: "Yehuda Katz", updatedAt: "now!" }); + return Ember.RSVP.resolve({ data: { id: 2, type: "person", attributes: { name: "Yehuda Katz", "updated-at": "now!" } } }); } else { assert.ok(false, "should not get here"); } @@ -866,7 +882,7 @@ test("can be created after the DS.Store", function(assert) { adapter.findRecord = function(store, type, id, snapshot) { assert.equal(type, Person, "the type is correct"); - return Ember.RSVP.resolve({ id: 1 }); + return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); }; run(function() { @@ -877,10 +893,24 @@ test("can be created after the DS.Store", function(assert) { test("the filter method can optionally take a server query as well", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.query = function(store, type, query, array) { - return Ember.RSVP.resolve([ - { id: 1, name: "Yehuda Katz" }, - { id: 2, name: "Tom Dale" } - ]); + return Ember.RSVP.resolve({ + data: [ + { + id: 1, + type: "person", + attributes: { + name: "Yehuda Katz" + } + }, + { + id: 2, + type: "person", + attributes: { + name: "Tom Dale" + } + } + ] + }); }; var asyncFilter = store.filter('person', { page: 1 }, function(data) { @@ -916,7 +946,18 @@ test("relationships returned via `commit` do not trigger additional findManys", }); adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: "Tom Dale", dogs: [1] }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: "person", + attributes: { name: "Tom Dale" }, + relationships: { + dogs: { + data: [{ id: 1, type: "dog" }] + } + } + } + }); }; adapter.updateRecord = function(store, type, snapshot) { @@ -946,7 +987,7 @@ test("relationships returned via `commit` do not trigger additional findManys", }] }); - resolve({ id: 1, name: "Scruffy" }); + resolve({ data: { id: 1, type: "dog", attributes: { name: "Scruffy" } } }); }); }; @@ -977,7 +1018,7 @@ test("relationships don't get reset if the links is the same", function(assert) adapter.findHasMany = function(store, snapshot, link, relationship) { assert.ok(count++ === 0, "findHasMany is only called once"); - return Ember.RSVP.resolve([{ id: 1, name: "Scruffy" }]); + return Ember.RSVP.resolve({ data: [{ id: 1, type: "dog", attributes: { name: "Scruffy" } }] }); }; run(function() { @@ -1036,10 +1077,18 @@ test("async hasMany always returns a promise", function(assert) { }); adapter.createRecord = function(store, type, snapshot) { - var hash = { name: "Tom Dale" }; - hash.dogs = []; - hash.id = 1; - return Ember.RSVP.resolve(hash); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: "person", + attributes: { + name: "Tom Dale" + }, + relationships: { + dogs: [] + } + } + }); }; var tom; @@ -1137,7 +1186,7 @@ test("findRecord receives a snapshot", function(assert) { adapter.findRecord = function(store, type, id, snapshot) { assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); - return Ember.RSVP.resolve({ id: 1 }); + return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); }; run(function() { @@ -1156,7 +1205,7 @@ test("findMany receives an array of snapshots", function(assert) { adapter.findMany = function(store, type, ids, snapshots) { assert.ok(snapshots[0] instanceof DS.Snapshot, "snapshots[0] is an instance of DS.Snapshot"); assert.ok(snapshots[1] instanceof DS.Snapshot, "snapshots[1] is an instance of DS.Snapshot"); - return Ember.RSVP.resolve([{ id: 2 }, { id: 3 }]); + return Ember.RSVP.resolve({ data: [{ id: 2, type: "dog" }, { id: 3, type: "dog" }] }); }; var person; @@ -1193,7 +1242,7 @@ test("findHasMany receives a snapshot", function(assert) { env.adapter.findHasMany = function(store, snapshot, link, relationship) { assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); - return Ember.RSVP.resolve([{ id: 2 }, { id: 3 }]); + return Ember.RSVP.resolve({ data: [{ id: 2, type: "dog" }, { id: 3, type: "dog" }] }); }; var person; @@ -1229,7 +1278,7 @@ test("findBelongsTo receives a snapshot", function(assert) { env.adapter.findBelongsTo = assert.wait(function(store, snapshot, link, relationship) { assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); - return Ember.RSVP.resolve({ id: 2 }); + return Ember.RSVP.resolve({ data: { id: 2, type: "dog" } }); }); var person; @@ -1261,7 +1310,7 @@ test("record.save should pass adapterOptions to the updateRecord method", functi env.adapter.updateRecord = assert.wait(function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); - return Ember.RSVP.resolve({ id: 1 }); + return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); }); run(function() { @@ -1284,7 +1333,7 @@ test("record.save should pass adapterOptions to the createRecord method", functi env.adapter.createRecord = assert.wait(function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); - return Ember.RSVP.resolve({ id: 1 }); + return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); }); run(function() { @@ -1298,7 +1347,7 @@ test("record.save should pass adapterOptions to the deleteRecord method", functi env.adapter.deleteRecord = assert.wait(function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); - return Ember.RSVP.resolve({ id: 1 }); + return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); }); run(function() { @@ -1322,7 +1371,7 @@ test("store.findRecord should pass adapterOptions to adapter.findRecord", functi env.adapter.findRecord = assert.wait(function(store, type, id, snapshot) { assert.deepEqual(snapshot.adapterOptions, { query: { embed: true } }); - return Ember.RSVP.resolve({ id: 1 }); + return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); }); run(function() { @@ -1335,7 +1384,7 @@ test("store.findRecord should pass 'include' to adapter.findRecord", function(as env.adapter.findRecord = assert.wait((store, type, id, snapshot) => { assert.equal(snapshot.include, 'books', 'include passed to adapter.findRecord'); - return Ember.RSVP.resolve({ id: 1 }); + return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); }); run(() => store.findRecord('person', 1, { include: 'books' })); @@ -1347,7 +1396,7 @@ test("store.findAll should pass adapterOptions to the adapter.findAll method", f env.adapter.findAll = assert.wait(function(store, type, sinceToken, arraySnapshot) { var adapterOptions = arraySnapshot.adapterOptions; assert.deepEqual(adapterOptions, { query: { embed: true } }); - return Ember.RSVP.resolve([{ id: 1 }]); + return Ember.RSVP.resolve({ data: [{ id: 1, type: "person" }] }); }); run(function() { @@ -1360,7 +1409,7 @@ test("store.findAll should pass 'include' to adapter.findAll", function(assert) env.adapter.findAll = assert.wait((store, type, sinceToken, arraySnapshot) => { assert.equal(arraySnapshot.include, 'books', 'include passed to adapter.findAll'); - return Ember.RSVP.resolve([{ id: 1 }]); + return Ember.RSVP.resolve({ data: [{ id: 1, type: "person" }] }); }); run(() => store.findAll('person', { include: 'books' })); diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index 4d30afcf9f5..f55d93c95b7 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -87,7 +87,7 @@ test("empty string and undefined ids should coerce to null", function(assert) { env.adapter.createRecord = function(store, type, record) { assert.equal(typeof get(record, 'id'), 'object', 'correct type'); - return Ember.RSVP.resolve({ id: id++ }); + return Ember.RSVP.resolve({ data: { id: id++, type: type.modelName } }); }; run(function() { diff --git a/tests/integration/filter-test.js b/tests/integration/filter-test.js index 8ac10a0d18d..9670af43167 100644 --- a/tests/integration/filter-test.js +++ b/tests/integration/filter-test.js @@ -449,12 +449,17 @@ test('a filter created after a record is already loaded works', function(assert) test('filter with query persists query on the resulting filteredRecordArray', function(assert) { customAdapter(env, DS.Adapter.extend({ query(store, type, id) { - return [ - { - id: id, - name: 'Tom Dale' - } - ]; + return { + data: [ + { + id: id, + type: 'person', + attributes: { + name: 'Tom Dale' + } + } + ] + }; } })); @@ -473,8 +478,13 @@ test('it is possible to filter by state flags', function(assert) { customAdapter(env, DS.Adapter.extend({ findRecord(store, type, id, snapshot) { return { - id, - name: 'Tom Dale' + data: { + id, + type: 'person', + attributes: { + name: 'Tom Dale' + } + } }; } })); @@ -504,7 +514,7 @@ test('it is possible to filter by state flags', function(assert) { test('it is possible to filter loaded records by dirtiness', function(assert) { customAdapter(env, DS.Adapter.extend({ updateRecord(type, model, snapshot) { - return { id: snapshot.id }; + return { data: { id: snapshot.id, type: model.modelName } }; }, shouldBackgroundReloadRecord() { return false; @@ -544,7 +554,13 @@ test('it is possible to filter created records by dirtiness', function(assert) { run(() => { customAdapter(env, DS.Adapter.extend({ createRecord(type, model, snapshot) { - return Ember.merge(Ember.merge({}, snapshot._attributes), { id: snapshot.id} ) + return { + data: { + id: snapshot.id, + type: model.modelName, + attributes: snapshot._attributes + } + } }, shouldBackgroundReloadRecord() { return false; } })); @@ -574,8 +590,13 @@ test('it is possible to filter created records by isReloading', function(assert) customAdapter(env, DS.Adapter.extend({ findRecord(store, type, id, snapshot) { return { - id: 1, - name: 'Tom Dalle' + data: { + id: 1, + type: 'person', + attributes: { + name: 'Tom Dalle' + } + } }; } })); @@ -644,8 +665,13 @@ test('a Record Array can update its filter after server-side updates one record' setup(assert, { updateRecord(store, type, snapshot) { return { - id: 1, - name: 'Scumbag Server-side Dale' + data: { + id: 1, + type: 'person', + attributes: { + name: 'Scumbag Server-side Dale' + } + } }; }, shouldBackgroundReloadRecord() { return false; } @@ -664,13 +690,23 @@ test('a Record Array can update its filter after server-side updates multiple re switch (snapshot.id) { case '1': return { - id: 1, - name: 'Scumbag Server-side Dale' + data: { + id: 1, + type: 'person', + attributes: { + name: 'Scumbag Server-side Dale' + } + } }; case '2': return { - id: 2, - name: 'Scumbag Server-side Katz' + data: { + id: 2, + type: 'person', + attributes: { + name: 'Scumbag Server-side Katz' + } + } }; } }, @@ -688,8 +724,13 @@ test('a Record Array can update its filter after server-side creates one record' setup(assert, { createRecord(store, type, snapshot) { return { - id: 4, - name: 'Scumbag Server-side Tim' + data: { + id: 4, + type: 'person', + attributes: { + name: 'Scumbag Server-side Tim' + } + } }; } }); @@ -707,13 +748,23 @@ test('a Record Array can update its filter after server-side creates multiple re switch (snapshot.attr('name')) { case 'Client-side Mike': return { - id: 4, - name: 'Scumbag Server-side Mike' + data: { + id: 4, + type: 'person', + attributes: { + name: 'Scumbag Server-side Mike' + } + } }; case 'Client-side David': return { - id: 5, - name: 'Scumbag Server-side David' + data: { + id: 5, + type: 'person', + attributes: { + name: 'Scumbag Server-side David' + } + } }; } } @@ -732,13 +783,23 @@ test('a Record Array can update its filter after server-side creates multiple re switch (snapshot.attr('name')) { case 'Client-side Mike': return { - id: 4, - name: 'Scumbag Server-side Mike' + data: { + id: 4, + type: 'person', + attributes: { + name: 'Scumbag Server-side Mike' + } + } }; case 'Client-side David': return { - id: 5, - name: 'Scumbag Server-side David' + data: { + id: 5, + type: 'person', + attributes: { + name: 'Scumbag Server-side David' + } + } }; } } diff --git a/tests/integration/lifecycle-hooks-test.js b/tests/integration/lifecycle-hooks-test.js index 35ad90e0823..69f06b8143b 100644 --- a/tests/integration/lifecycle-hooks-test.js +++ b/tests/integration/lifecycle-hooks-test.js @@ -31,7 +31,7 @@ test("When the adapter acknowledges that a record has been created, a `didCreate assert.expect(3); env.adapter.createRecord = function(store, type, snapshot) { - return resolve({ id: 99, name: "Yehuda Katz" }); + return resolve({ data: { id: 99, type: "person", attributes: { name: "Yehuda Katz" } } }); }; var person; diff --git a/tests/integration/record-array-test.js b/tests/integration/record-array-test.js index cd801ced50b..ed45e4e21d5 100644 --- a/tests/integration/record-array-test.js +++ b/tests/integration/record-array-test.js @@ -8,7 +8,7 @@ import DS from 'ember-data'; const { get, run, RSVP: { Promise }} = Ember; -let array; +let results; const Person = DS.Model.extend({ name: DS.attr('string'), @@ -25,11 +25,13 @@ const Tool = DS.Model.extend({ module('unit/record_array - DS.RecordArray', { beforeEach() { - array = Ember.A([ - { id: '1', name: 'Scumbag Dale' }, - { id: '2', name: 'Scumbag Katz' }, - { id: '3', name: 'Scumbag Bryn' } - ]); + results = { + data: [ + { id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }, + { id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } }, + { id: '3', type: 'person', attributes: { name: 'Scumbag Bryn' } } + ] + }; } }); @@ -74,8 +76,9 @@ test('a record array is backed by records', function(assert) { return run(() => { return store.findByIds('person', [1,2,3]).then(records => { - for (let i=0, l = get(array, 'length'); i { diff --git a/tests/integration/record-arrays/adapter-populated-record-array-test.js b/tests/integration/record-arrays/adapter-populated-record-array-test.js index ce0273964b4..6264ed285e2 100644 --- a/tests/integration/record-arrays/adapter-populated-record-array-test.js +++ b/tests/integration/record-arrays/adapter-populated-record-array-test.js @@ -165,10 +165,12 @@ test('pass record array to adapter.query based on arity', function(assert) { let env = setupStore({ person: Person }); let store = env.store; - let payload = [ - { id: '1', name: 'Scumbag Dale' }, - { id: '2', name: 'Scumbag Katz' } - ]; + let payload = { + data: [ + { id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }, + { id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } } + ] + }; env.adapter.query = function(store, type, query) { assert.equal(arguments.length, 3); @@ -188,10 +190,12 @@ test('pass record array to adapter.query based on arity', function(assert) { let env = setupStore({ person: Person }); let store = env.store; - let payload = [ - { id: '1', name: 'Scumbag Dale' }, - { id: '2', name: 'Scumbag Katz' } - ]; + let payload = { + data: [ + { id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }, + { id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } } + ] + }; let actualQuery = { }; @@ -234,10 +238,12 @@ test('loadRecord re-syncs internalModels recordArrays', function(assert) { let env = setupStore({ person: Person }); let store = env.store; - let payload = [ - { id: '1', name: 'Scumbag Dale' }, - { id: '2', name: 'Scumbag Katz' } - ]; + let payload = { + data: [ + { id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }, + { id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } } + ] + }; env.adapter.query = function(store, type, query, recordArray) { return payload; @@ -247,10 +253,12 @@ test('loadRecord re-syncs internalModels recordArrays', function(assert) { return recordArray.update().then(recordArray => { assert.deepEqual(recordArray.getEach('name'), ['Scumbag Dale', 'Scumbag Katz'], 'expected query to contain specific records'); - payload = [ - { id: '1', name: 'Scumbag Dale' }, - { id: '3', name: 'Scumbag Penner' } - ]; + payload = { + data: [ + { id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }, + { id: '3', type: 'person', attributes: { name: 'Scumbag Penner' } } + ] + }; return recordArray.update(); }).then(recordArray => { @@ -265,17 +273,17 @@ test('when an adapter populated record gets updated the array contents are also let filteredPromise, filteredArr, findPromise, findArray; let env = setupStore({ person: Person }); let store = env.store; - let array = [{ id: '1', name: 'Scumbag Dale' }]; + let array = [{ id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }]; // resemble server side filtering env.adapter.query = function(store, type, query, recordArray) { - return array.slice(query.slice); + return { data: array.slice(query.slice) }; }; // implement findAll to further test that query updates won't muddle // with the non-query record arrays env.adapter.findAll = function(store, type, sinceToken) { - return array.slice(0); + return { data: array.slice(0) }; }; run(() => { @@ -298,7 +306,7 @@ test('when an adapter populated record gets updated the array contents are also // a new element gets pushed in record array run(() => { - array.push({ id: '2', name: 'Scumbag Katz' }); + array.push({ id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } }); filteredArr.update().then(() => { assert.equal(filteredArr.get('length'), 1, 'The new record is returned and added in adapter populated array'); assert.equal(filteredArr.get('isUpdating'), false, 'Record array isUpdating state updated'); diff --git a/tests/integration/records/collection-save-test.js b/tests/integration/records/collection-save-test.js index 83460722740..2ea23b0b647 100644 --- a/tests/integration/records/collection-save-test.js +++ b/tests/integration/records/collection-save-test.js @@ -33,7 +33,7 @@ test("Collection will resolve save on success", function(assert) { var posts = env.store.peekAll('post'); env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ id: id++ }); + return Ember.RSVP.resolve({ data: { id: id++ , type: 'post' } }); }; run(function() { @@ -77,12 +77,12 @@ test("Retry is allowed in a failure handler", function(assert) { if (count++ === 0) { return Ember.RSVP.reject(); } else { - return Ember.RSVP.resolve({ id: id++ }); + return Ember.RSVP.resolve({ data: { id: id++, type: 'post' } }); } }; env.adapter.updateRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ id: snapshot.id }); + return Ember.RSVP.resolve({ data: { id: snapshot.id, type: 'post' } }); }; run(function() { diff --git a/tests/integration/records/property-changes-test.js b/tests/integration/records/property-changes-test.js index 55c688c85bf..a6374c7ce7d 100644 --- a/tests/integration/records/property-changes-test.js +++ b/tests/integration/records/property-changes-test.js @@ -115,7 +115,7 @@ test('Saving a record trigger observers for locally changed attributes with the var person; env.adapter.updateRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ id: 'wat', lastName: 'Katz' }); + return Ember.RSVP.resolve({ data: { id: 'wat', type: 'person', attributes: { 'last-name': 'Katz' } } }); }; run(function() { diff --git a/tests/integration/records/reload-test.js b/tests/integration/records/reload-test.js index c5aedf2f05c..76bc76b4b36 100644 --- a/tests/integration/records/reload-test.js +++ b/tests/integration/records/reload-test.js @@ -33,10 +33,10 @@ test("When a single record is requested, the adapter's find method should be cal env.adapter.findRecord = function(store, type, id, snapshot) { if (count === 0) { count++; - return Ember.RSVP.resolve({ id: id, name: "Tom Dale" }); + return Ember.RSVP.resolve({ data: { id: id, type: 'person', attributes: { name: "Tom Dale" } } }); } else if (count === 1) { count++; - return Ember.RSVP.resolve({ id: id, name: "Braaaahm Dale" }); + return Ember.RSVP.resolve({ data: { id: id, type: 'person', attributes: { name: "Braaaahm Dale" } } }); } else { assert.ok(false, "Should not get here"); } @@ -77,7 +77,7 @@ test("When a record is reloaded and fails, it can try again", function(assert) { if (count++ === 0) { return Ember.RSVP.reject(); } else { - return Ember.RSVP.resolve({ id: 1, name: "Thomas Dale" }); + return Ember.RSVP.resolve({ data: { id: 1, type: 'person', attributes: { name: "Thomas Dale" } } }); } }; @@ -96,19 +96,20 @@ test("When a record is reloaded and fails, it can try again", function(assert) { }); test("When a record is loaded a second time, isLoaded stays true", function(assert) { + let record = { + data: { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale' + } + } + }; env.adapter.findRecord = function(store, type, id, snapshot) { - return { id: 1, name: "Tom Dale" }; + return record; }; run(function() { - env.store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' - } - } - }); + env.store.push(record); }); run(function() { @@ -117,15 +118,7 @@ test("When a record is loaded a second time, isLoaded stays true", function(asse person.addObserver('isLoaded', isLoadedDidChange); // Reload the record - env.store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' - } - } - }); + env.store.push(record); assert.equal(get(person, 'isLoaded'), true, "The person is still loaded after load"); @@ -154,9 +147,23 @@ test("When a record is reloaded, its async hasMany relationships still work", fu env.adapter.findRecord = function(store, type, id, snapshot) { switch (type.modelName) { case 'person': - return Ember.RSVP.resolve({ id: 1, name: "Tom", tags: [1, 2] }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'person', + attributes: { name: "Tom" }, + relationships: { + tags: { + data: [ + { id: 1, type: 'tag' }, + { id: 2, type: 'tag' } + ] + } + } + } + }); case 'tag': - return Ember.RSVP.resolve({ id: id, name: tags[id] }); + return Ember.RSVP.resolve({ data: { id: id, type: 'tag', attributes: { name: tags[id] } } }); } }; diff --git a/tests/integration/records/save-test.js b/tests/integration/records/save-test.js index 99125f1413a..397906fba22 100644 --- a/tests/integration/records/save-test.js +++ b/tests/integration/records/save-test.js @@ -40,7 +40,7 @@ test("Will resolve save on success", function(assert) { // `save` returns a PromiseObject which allows to call get on it assert.equal(saved.get('id'), undefined); - deferred.resolve({ id: 123 }); + deferred.resolve({ data: { id: 123, type: 'post' } }); saved.then(function(model) { assert.ok(true, 'save operation was resolved'); assert.equal(saved.get('id'), 123); @@ -82,7 +82,7 @@ test("Retry is allowed in a failure handler", function(assert) { if (count++ === 0) { return Ember.RSVP.reject(error); } else { - return Ember.RSVP.resolve({ id: 123 }); + return Ember.RSVP.resolve({ data: { id: 123, type: 'post' } }); } }; diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index af3cc59f451..9ba234c1ff8 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -410,7 +410,11 @@ test("load() fetches the record", function(assert) { env.adapter.findRecord = function(store, type, id) { return Ember.RSVP.resolve({ - id: 1, name: "Coreleone" + data: { + id: 1, + type: 'family', + attributes: { name: "Coreleone" } + } }); }; @@ -447,7 +451,11 @@ test("load() fetches link when remoteType is link", function(assert) { assert.equal(link, "/families/1"); return Ember.RSVP.resolve({ - id: 1, name: "Coreleone" + data: { + id: 1, + type: 'family', + attributes: { name: "Coreleone" } + } }); }; @@ -487,7 +495,11 @@ test("reload() - loads the record when not yet loaded", function(assert) { assert.equal(count, 1); return Ember.RSVP.resolve({ - id: 1, name: "Coreleone" + data: { + id: 1, + type: 'family', + attributes: { name: "Coreleone" } + } }); }; @@ -526,7 +538,11 @@ test("reload() - reloads the record when already loaded", function(assert) { assert.equal(count, 1); return Ember.RSVP.resolve({ - id: 1, name: "Coreleone" + data: { + id: 1, + type: 'family', + attributes: { name: "Coreleone" } + } }); }; @@ -569,7 +585,11 @@ test("reload() - uses link to reload record", function(assert) { assert.equal(link, "/families/1"); return Ember.RSVP.resolve({ - id: 1, name: "Coreleone" + data: { + id: 1, + type: 'family', + attributes: { name: "Coreleone" } + } }); }; diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 374747cad17..a2ad4339254 100644 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -588,7 +588,7 @@ test("load() fetches the referenced records", function(assert) { var done = assert.async(); env.adapter.findMany = function(store, type, id) { - return Ember.RSVP.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); + return Ember.RSVP.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito" } }, { id: 2, type: 'person', attributes: { name: "Michael" } }] }); }; var family; @@ -629,7 +629,7 @@ test("load() fetches link when remoteType is link", function(assert) { env.adapter.findHasMany = function(store, snapshot, link) { assert.equal(link, "/families/1/persons"); - return Ember.RSVP.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); + return Ember.RSVP.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito" } }, { id: 2, type: 'person', attributes: { name: "Michael" } }] }); }; var family; @@ -703,7 +703,7 @@ test("load() - only a single find is triggered", function(assert) { }); run(function() { - deferred.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); + deferred.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito" } }, { id: 2, type: 'person', attributes: { name: "Michael" } }] }); }); run(function() { @@ -719,10 +719,7 @@ test("reload()", function(assert) { var done = assert.async(); env.adapter.findMany = function(store, type, id) { - return Ember.RSVP.resolve([ - { id: 1, name: "Vito Coreleone" }, - { id: 2, name: "Michael Coreleone" } - ]); + return Ember.RSVP.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito Coreleone" } }, { id: 2, type: 'person', attributes: { name: "Michael Coreleone" } }] }); }; var family; @@ -768,12 +765,9 @@ test("reload() fetches link when remoteType is link", function(assert) { assert.equal(link, "/families/1/persons"); if (count === 1) { - return Ember.RSVP.resolve([{ id: 1, name: "Vito" }, { id: 2, name: "Michael" }]); + return Ember.RSVP.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito" } }, { id: 2, type: 'person', attributes: { name: "Michael" } }] }); } else { - return Ember.RSVP.resolve([ - { id: 1, name: "Vito Coreleone" }, - { id: 2, name: "Michael Coreleone" } - ]); + return Ember.RSVP.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito Coreleone" } }, { id: 2, type: 'person', attributes: { name: "Michael Coreleone" } }] }); } }; diff --git a/tests/integration/references/record-test.js b/tests/integration/references/record-test.js index 7f66074d8f4..d29d547e093 100644 --- a/tests/integration/references/record-test.js +++ b/tests/integration/references/record-test.js @@ -122,7 +122,13 @@ test("load() fetches the record", function(assert) { env.adapter.findRecord = function(store, type, id) { return Ember.RSVP.resolve({ - id: 1, name: "Vito" + data: { + id: 1, + type: 'person', + attributes: { + name: 'Vito' + } + } }); }; @@ -162,7 +168,13 @@ test("load() only a single find is triggered", function(assert) { run(function() { deferred.resolve({ - id: 1, name: "Vito" + data: { + id: 1, + type: 'person', + attributes: { + name: 'Vito' + } + } }); }); @@ -184,7 +196,13 @@ test("reload() loads the record if not yet loaded", function(assert) { assert.equal(count, 1); return Ember.RSVP.resolve({ - id: 1, name: "Vito Coreleone" + data: { + id: 1, + type: 'person', + attributes: { + name: 'Vito Coreleone' + } + } }); }; @@ -204,7 +222,13 @@ test("reload() fetches the record", function(assert) { env.adapter.findRecord = function(store, type, id) { return Ember.RSVP.resolve({ - id: 1, name: "Vito Coreleone" + data: { + id: 1, + type: 'person', + attributes: { + name: 'Vito Coreleone' + } + } }); }; diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index f2e44830546..7cc2b0c9fbf 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -67,7 +67,7 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { env.registry.optionsForType('serializer', { singleton: false }); env.registry.optionsForType('adapter', { singleton: false }); - env.registry.register('serializer:user', DS.JSONSerializer.extend({ + env.registry.register('serializer:user', DS.JSONAPISerializer.extend({ attrs: { favouriteMessage: { embedded: 'always' } } @@ -102,7 +102,10 @@ test("The store can materialize a non loaded monomorphic belongsTo association", env.adapter.findRecord = function(store, type, id, snapshot) { assert.ok(true, "The adapter's find method should be called"); return Ember.RSVP.resolve({ - id + data: { + id, + type: snapshot.modelName + } }); }; @@ -280,8 +283,8 @@ test("The store can serialize a polymorphic belongsTo association", function(ass store.findRecord('comment', 2).then(function(comment) { var serialized = comment.serialize({ includeId: true }); - assert.equal(serialized['message'], 1); - assert.equal(serialized['message_type'], 'post'); + assert.equal(serialized.data.relationships.message.data.id, 1); + assert.equal(serialized.data.relationships.message.data.type, 'posts'); }); }); }); @@ -325,7 +328,17 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to assert.equal(relationship.key, 'group'); assert.equal(link, "/people/1/group"); - return Ember.RSVP.resolve({ id: 1, people: [1] }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'group', + relationships: { + people: { + data: [{ id: 1, type: 'person' }] + } + } + } + }); }); run(function() { @@ -374,7 +387,7 @@ test('A record with an async belongsTo relationship always returns a promise for }; env.adapter.findBelongsTo = assert.wait(function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ id: 1 }); + return Ember.RSVP.resolve({ data: { id: 1, type: 'seat' } }); }); run(function() { @@ -426,7 +439,7 @@ test("A record with an async belongsTo relationship returning null should resolv }; env.adapter.findBelongsTo = assert.wait(function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve(null); + return Ember.RSVP.resolve({ data: null }); }); env.store.findRecord('person', '1').then(assert.wait(function(person) { @@ -716,10 +729,22 @@ test("Destroying a record with an unloaded aync belongsTo association does not f assert.ok(snapshot.record instanceof type); assert.equal(snapshot.id, 1, 'should first post'); return { - id: '1', - title: null, - created_at: null, - user: "2" + data: { + id: '1', + type: 'post', + attributes: { + title: null, + 'created-at': null + }, + relationships: { + user: { + data: { + id: '2', + type: 'user' + } + } + } + } }; }; @@ -852,7 +877,16 @@ test("belongsTo hasData async loaded", function(assert) { }); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: 'The Greatest Book', author: 2 }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'book', + attributes: { name: 'The Greatest Book' }, + relationships: { + author: { data: { id: 2, type: 'author'} } + } + } + }); }; run(function() { @@ -867,7 +901,16 @@ test("belongsTo hasData sync loaded", function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: 'The Greatest Book', author: 2 }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'book', + attributes: { name: 'The Greatest Book' }, + relationships: { + author: { data: { id: 2, type: 'author'} } + } + } + }); }; run(function() { @@ -886,7 +929,16 @@ test("belongsTo hasData async not loaded", function(assert) { }); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: 'The Greatest Book', links: { author: 'author' } }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'book', + attributes: { name: 'The Greatest Book' }, + relationships: { + author: { links: { related: 'author'} } + } + } + }); }; run(function() { @@ -901,8 +953,14 @@ test("belongsTo hasData sync not loaded", function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: 'The Greatest Book' }); - }; + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'book', + attributes: { name: 'The Greatest Book' } + } + }); + } run(function() { store.findRecord('book', 1).then(function(book) { @@ -991,9 +1049,13 @@ test("Related link should be fetched when no local data is present", function(as env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { assert.equal(url, 'author', 'url is correct'); assert.ok(true, "The adapter's findBelongsTo method should be called"); - return Ember.RSVP.resolve( - { id: 1, name: 'This is author' } - ); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'author', + attributes: { name: 'This is author' } + } + }); }; run(function() { @@ -1028,7 +1090,13 @@ test("Local data should take precedence over related link", function(assert) { }; env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, name: 'This is author' }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'author', + attributes: { name: 'This is author' } + } + }); }; run(function() { @@ -1062,9 +1130,13 @@ test("New related link should take precedence over local data", function(assert) env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { assert.equal(url, 'author-new-link', 'url is correct'); assert.ok(true, "The adapter's findBelongsTo method should be called"); - return Ember.RSVP.resolve( - { id: 1, name: 'This is author' } - ); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'author', + attributes: { name: 'This is author' } + } + }); }; env.adapter.findRecord = function(store, type, id, snapshot) { @@ -1117,9 +1189,13 @@ test("Updated related link should take precedence over local data", function(ass env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { assert.equal(url, 'author-updated-link', 'url is correct'); assert.ok(true, "The adapter's findBelongsTo method should be called"); - return Ember.RSVP.resolve( - { id: 1, name: 'This is updated author' } - ); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'author', + attributes: { name: 'This is updated author' } + } + }); }; env.adapter.findRecord = function(store, type, id, snapshot) { @@ -1244,13 +1320,26 @@ test("A belongsTo relationship can be reloaded using the reference if it was fet env.adapter.findRecord = function() { return Ember.RSVP.resolve({ - id: 1, - links: { book: '/books/1' } + data: { + id: 1, + type: 'chapter', + relationships: { + book: { + links: { related: '/books/1' } + } + } + } }); }; env.adapter.findBelongsTo = function() { - return Ember.RSVP.resolve({ id: 1, name: "book title" }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'book', + attributes: { name: "book title" } + } + }); }; run(function() { @@ -1263,7 +1352,13 @@ test("A belongsTo relationship can be reloaded using the reference if it was fet assert.equal(book.get('name'), "book title"); env.adapter.findBelongsTo = function() { - return Ember.RSVP.resolve({ id: 1, name: "updated book title" }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'book', + attributes: { name: "updated book title" } + } + }); }; return chapter.belongsTo('book').reload(); @@ -1307,7 +1402,13 @@ test("A sync belongsTo relationship can be reloaded using a reference if it was }); env.adapter.findRecord = function() { - return Ember.RSVP.resolve({ id: 1, name: "updated book title" }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'book', + attributes: { name: 'updated book title' } + } + }); }; run(function() { @@ -1345,7 +1446,13 @@ test("A belongsTo relationship can be reloaded using a reference if it was fetch }); env.adapter.findRecord = function() { - return Ember.RSVP.resolve({ id: 1, name: "book title" }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'book', + attributes: { name: "book title" } + } + }); }; run(function() { @@ -1353,7 +1460,13 @@ test("A belongsTo relationship can be reloaded using a reference if it was fetch assert.equal(book.get('name'), "book title"); env.adapter.findRecord = function() { - return Ember.RSVP.resolve({ id: 1, name: "updated book title" }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'book', + attributes: { name: "updated book title" } + } + }); }; return chapter.belongsTo('book').reload(); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 27aa6c40d84..b7534447b16 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -102,27 +102,29 @@ module("integration/relationships/has_many - Has-Many Relationships", { test("When a hasMany relationship is accessed, the adapter's findMany method should not be called if all the records in the relationship are already loaded", function(assert) { assert.expect(0); + let postData = { + type: 'post', + id: '1', + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' } + ] + } + } + }; + env.adapter.findMany = function(store, type, ids, snapshots) { assert.ok(false, "The adapter's find method should not be called"); }; env.adapter.findRecord = function(store, type, ids, snapshots) { - return { id: 1, comments: [1] }; + return { data: postData }; }; run(function() { env.store.push({ - data: { - type: 'post', - id: '1', - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' } - ] - } - } - }, + data: postData, included: [{ type: 'comment', id: '1' @@ -137,35 +139,39 @@ test("When a hasMany relationship is accessed, the adapter's findMany method sho test("adapter.findMany only gets unique IDs even if duplicate IDs are present in the hasMany relationship", function(assert) { assert.expect(2); + let bookData = { + type: 'book', + id: '1', + relationships: { + chapters: { + data: [ + { type: 'chapter', id: '2' }, + { type: 'chapter', id: '3' }, + { type: 'chapter', id: '3' } + ] + } + } + }; + env.adapter.findMany = function(store, type, ids, snapshots) { assert.equal(type, Chapter, 'type passed to adapter.findMany is correct'); assert.deepEqual(ids, ['2', '3'], 'ids passed to adapter.findMany are unique'); - return Ember.RSVP.resolve([ - { id: 2, title: 'Chapter One' }, - { id: 3, title: 'Chapter Two' } - ]); + return Ember.RSVP.resolve({ + data: [ + { id: 2, type: 'chapter', attributes: { title: 'Chapter One' } }, + { id: 3, type: 'chapter', attributes: { title: 'Chapter Two' } } + ] + }); }; env.adapter.findRecord = function(store, type, ids, snapshots) { - return { id: 1, chapters: [2, 3, 3] }; + return { data: bookData }; }; run(function() { env.store.push({ - data: { - type: 'book', - id: '1', - relationships: { - chapters: { - data: [ - { type: 'chapter', id: '2' }, - { type: 'chapter', id: '3' }, - { type: 'chapter', id: '3' } - ] - } - } - } + data: bookData }); env.store.findRecord('book', 1).then(function(book) { return book.get('chapters'); @@ -188,8 +194,21 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi assert.equal(type, Post, "find type was Post"); assert.equal(id, "1", "find id was 1"); - return Ember.RSVP.resolve({ id: 1, links: { comments: "/posts/1/comments" } }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'post', + relationships: { + comments: { + links: { + related: "/posts/1/comments" + } + } + } + } + }); }; + //({ id: 1, links: { comments: "/posts/1/comments" } }); env.adapter.findMany = function(store, type, ids, snapshots) { throw new Error("Adapter's findMany should not be called"); @@ -199,10 +218,12 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); assert.equal(relationship.type, "comment", "relationship was passed correctly"); - return Ember.RSVP.resolve([ - { id: 1, body: "First" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: "First" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ] + }); }; run(function() { @@ -251,10 +272,12 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ assert.equal(count, 1, "findHasMany has only been called once"); return new Ember.RSVP.Promise(function(resolve, reject) { setTimeout(function() { - var value = [ - { id: 1, body: "First" }, - { id: 2, body: "Second" } - ]; + var value = { + data: [ + { id: 1, type: 'comment', attributes: { body: "First" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ] + }; resolve(value); }, 100); }); @@ -294,10 +317,12 @@ test("A hasMany backed by a link remains a promise after a record has been added }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve([ - { id: 1, body: "First" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: "First" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ] + }); }; var post; run(function() { @@ -347,14 +372,19 @@ test("A hasMany updated link should not remove new children", function(assert) { }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve([]); + return Ember.RSVP.resolve({ data: [] }); }; env.adapter.createRecord = function(store, snapshot, link, relationship) { return Ember.RSVP.resolve({ - id: 1, - links: { - comments: '/some/link' + data: { + id: 1, + type: 'post', + relationships: { + comments: { + links: { related: '/some/link' } + } + } } }); }; @@ -388,14 +418,21 @@ test("A hasMany updated link should not remove new children when the parent reco }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve([{ id: 5, body: 'hello' }]); + return Ember.RSVP.resolve({ data: [ + { id: 5, type: 'comment', attributes: { body: 'hello' } } + ]}); }; env.adapter.createRecord = function(store, snapshot, link, relationship) { return Ember.RSVP.resolve({ - id: 1, - links: { - comments: '/some/link' + data: { + id: 1, + type: 'post', + relationships: { + comments: { + links: { related: '/some/link' } + } + } } }); }; @@ -430,9 +467,7 @@ test("A hasMany relationship doesn't contain duplicate children, after the canon }); env.adapter.createRecord = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ - id: 1 - }); + return Ember.RSVP.resolve({ data: { id: 1, type: 'post' } }); }; run(function() { @@ -498,7 +533,17 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func assert.equal(type, Post, "find type was Post"); assert.equal(id, "1", "find id was 1"); - return Ember.RSVP.resolve({ id: 1, links: { comments: "/posts/1/comments" } }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'post', + relationships: { + comments: { + links: { related: "/posts/1/comments" } + } + } + } + }); }; env.adapter.findHasMany = function(store, snapshot, link, relationship) { @@ -506,10 +551,10 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func assert.equal(relationship.key, 'comments', "findHasMany relationship key was comments"); assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); - return Ember.RSVP.resolve([ - { id: 1, body: "First" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "First" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ]}); }; run(function() { @@ -524,11 +569,11 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func assert.equal(relationship.key, 'comments', "findHasMany relationship key was comments"); assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); - return Ember.RSVP.resolve([ - { id: 1, body: "First" }, - { id: 2, body: "Second" }, - { id: 3, body: "Thirds" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "First" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } }, + { id: 3, type: 'comment', attributes: { body: "Thirds" } } + ]}); }; return comments.reload(); @@ -547,7 +592,20 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu assert.equal(type, Post, "find type was Post"); assert.equal(id, "1", "find id was 1"); - return Ember.RSVP.resolve({ id: 1, comments: [1, 2] }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'post', + relationships: { + comments: { + data: [ + { id: 1, type: 'comment' }, + { id: 2, type: 'comment' } + ] + } + } + } + }); }; run(function() { @@ -573,10 +631,10 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu assert.equal(comments.get('length'), 2, "comments have a length of 2"); env.adapter.findMany = function(store, type, ids, snapshots) { - return Ember.RSVP.resolve([ - { id: 1, body: "FirstUpdated" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ]}); }; return comments.reload(); @@ -595,14 +653,24 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio assert.equal(type, Post, "find type was Post"); assert.equal(id, "1", "find id was 1"); - return Ember.RSVP.resolve({ id: 1, comments: [1,2] }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'post', + relationships: { + comments: { + data: [{ id: 1, type: 'comment' }, { id: 2, type: 'comment' }] + } + } + } + }); }; env.adapter.findMany = function(store, type, ids, snapshots) { - return Ember.RSVP.resolve([ - { id: 1, body: "First" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "First" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ]}); }; run(function() { @@ -613,10 +681,10 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio assert.equal(comments.get('length'), 2, "comments have 2 length"); env.adapter.findMany = function(store, type, ids, snapshots) { - return Ember.RSVP.resolve([ - { id: 1, body: "FirstUpdated" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ]}); }; return comments.reload(); @@ -634,7 +702,17 @@ test("A hasMany relationship can be reloaded even if it failed at the first time }); env.adapter.findRecord = function(store, type, id) { - return Ember.RSVP.resolve({ id: 1, links: { comments: "/posts/1/comments" } }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'post', + relationships: { + comments: { + links: { related: "/posts/1/comments" } + } + } + } + }); }; var loadingCount = -1; @@ -643,10 +721,10 @@ test("A hasMany relationship can be reloaded even if it failed at the first time if (loadingCount % 2 === 0) { return Ember.RSVP.reject(); } else { - return Ember.RSVP.resolve([ - { id: 1, body: "FirstUpdated" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ]}); } }; run(function() { @@ -679,16 +757,26 @@ test("A hasMany relationship can be directly reloaded if it was fetched via link assert.equal(type, Post, "find type was Post"); assert.equal(id, "1", "find id was 1"); - return Ember.RSVP.resolve({ id: 1, links: { comments: "/posts/1/comments" } }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'post', + relationships: { + comments: { + links: { related: "/posts/1/comments" } + } + } + } + }); }; env.adapter.findHasMany = function(store, record, link, relationship) { assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); - return Ember.RSVP.resolve([ - { id: 1, body: "FirstUpdated" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ]}); }; run(function() { env.store.findRecord('post', 1).then(function(post) { @@ -710,16 +798,26 @@ test("Has many via links - Calling reload multiple times does not send a new req }); env.adapter.findRecord = function(store, type, id) { - return Ember.RSVP.resolve({ id: 1, links: { comments: "/posts/1/comments" } }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'post', + relationships: { + comments: { + links: { related: "/posts/1/comments" } + } + } + } + }); }; let count = 0; env.adapter.findHasMany = function(store, record, link, relationship) { count++; - return Ember.RSVP.resolve([ - { id: 1, body: "First" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "First" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ]}); }; run(function() { env.store.findRecord('post', 1).then(function(post) { @@ -742,14 +840,24 @@ test("A hasMany relationship can be directly reloaded if it was fetched via ids" assert.equal(type, Post, "find type was Post"); assert.equal(id, "1", "find id was 1"); - return Ember.RSVP.resolve({ id: 1, comments: [1,2] }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'post', + relationships: { + comments: { + data: [{ id: 1, type: 'comment' }, { id: 2, type: 'comment' }] + } + } + } + }); }; env.adapter.findMany = function(store, type, ids, snapshots) { - return Ember.RSVP.resolve([ - { id: 1, body: "FirstUpdated" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ]}); }; run(function() { @@ -772,16 +880,26 @@ test("Has many via ids - Calling reload multiple times does not send a new reque }); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, comments: [1,2] }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'post', + relationships: { + comments: { + data: [{ id: 1, type: 'comment' }, { id: 2, type: 'comment' }] + } + } + } + }); }; let count = 0; env.adapter.findMany = function(store, type, ids, snapshots) { count++; - return Ember.RSVP.resolve([ - { id: 1, body: "FirstUpdated" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ]}); }; run(function() { @@ -804,10 +922,10 @@ test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loa }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve([ - { id: 1, body: "First" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "First" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ]}); }; var post; @@ -848,10 +966,10 @@ test("PromiseArray proxies evented methods to its ManyArray", function(assert) { }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve([ - { id: 1, body: "First" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "First" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ]}); }; var post, comments; @@ -915,16 +1033,16 @@ test("An updated `links` value should invalidate a relationship cache", function assert.equal(relationship.type, "comment", "relationship was passed correctly"); if (link === '/first') { - return Ember.RSVP.resolve([ - { id: 1, body: "First" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "First" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ]}); } else if (link === '/second') { - return Ember.RSVP.resolve([ - { id: 3, body: "Third" }, - { id: 4, body: "Fourth" }, - { id: 5, body: "Fifth" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 3, type: 'comment', attributes: { body: "Third" } }, + { id: 4, type: 'comment', attributes: { body: "Fourth" } }, + { id: 5, type: 'comment', attributes: { body: "Fifth" } } + ]}); } }; var post; @@ -976,28 +1094,30 @@ test("An updated `links` value should invalidate a relationship cache", function test("When a polymorphic hasMany relationship is accessed, the adapter's findMany method should not be called if all the records in the relationship are already loaded", function(assert) { assert.expect(1); + let userData = { + type: 'user', + id: '1', + relationships: { + messages: { + data: [ + { type: 'post', id: '1' }, + { type: 'comment', id: '3' } + ] + } + } + }; + env.adapter.findMany = function(store, type, ids, snapshots) { assert.ok(false, "The adapter's find method should not be called"); }; env.adapter.findRecord = function(store, type, ids, snapshots) { - return { id: 1, messages: [{ id: 1, type: 'post' }, { id: 3, type: 'comment' }] }; + return { data: userData }; }; run(function() { env.store.push({ - data: { - type: 'user', - id: '1', - relationships: { - messages: { - data: [ - { type: 'post', id: '1' }, - { type: 'comment', id: '3' } - ] - } - } - }, + data: userData, included: [{ type: 'post', id: '1' @@ -1023,9 +1143,9 @@ test("When a polymorphic hasMany relationship is accessed, the store can call mu env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.findRecord = function(store, type, id, snapshot) { if (type === Post) { - return Ember.RSVP.resolve({ id: 1 }); + return Ember.RSVP.resolve({ data: { id: 1, type: 'post' } }); } else if (type === Comment) { - return Ember.RSVP.resolve({ id: 3 }); + return Ember.RSVP.resolve({ data: { id: 3, type: 'comment' } }); } }; @@ -1081,7 +1201,17 @@ test("Type can be inferred from the key of a hasMany relationship", function(ass assert.expect(1); env.adapter.findRecord = function(store, type, ids, snapshots) { - return { id: 1, contacts: [1] }; + return { + data: { + id: 1, + type: 'user', + relationships: { + contacts: { + data: [{ id: 1, type: 'contact' }] + } + } + } + }; }; run(function() { @@ -1120,7 +1250,17 @@ test("Type can be inferred from the key of an async hasMany relationship", funct }); env.adapter.findRecord = function(store, type, ids, snapshots) { - return { id: 1, contacts: [1] }; + return { + data: { + id: 1, + type: 'user', + relationships: { + contacts: { + data: [{ id: 1, type: 'contact' }] + } + } + } + }; }; run(function() { @@ -1157,7 +1297,7 @@ test("Polymorphic relationships work with a hasMany whose type is inferred", fun }); env.adapter.findRecord = function(store, type, ids, snapshots) { - return { id: 1 }; + return { data: { id: 1, type: 'user' } }; }; assert.expect(1); @@ -1489,7 +1629,7 @@ test("When a record is saved, its unsaved hasMany records should be kept", funct var post, comment; env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ id: 1 }); + return Ember.RSVP.resolve({ data: { id: 1, type: snapshot.modelName } }); }; run(function () { @@ -1512,9 +1652,9 @@ test("dual non-async HM <-> BT", function(assert) { }); env.adapter.createRecord = function(store, type, snapshot) { - var data = snapshot.record.serialize(); - data.id = 2; - return Ember.RSVP.resolve(data); + var serialized = snapshot.record.serialize(); + serialized.data.id = 2; + return Ember.RSVP.resolve(serialized); }; var post, firstComment; @@ -1568,11 +1708,14 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the }); env.adapter.findMany = function(store, type, ids, snapshots) { - return resolve([{ id: 1, body: 'first' }, { id: 2, body: 'second' }]); + return resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: 'first' } }, + { id: 2, type: 'comment', attributes: { body: 'second' } } + ]}); }; env.adapter.findRecord = function(store, type, id, snapshot) { - return resolve({ id: 3, body: 'third' }); + return resolve({ data: { id: 3, type: 'comment', attributes: { body: 'third' } } }); }; var post; @@ -2304,7 +2447,18 @@ test("hasMany hasData async loaded", function(assert) { }); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, title: 'The Story Begins', pages: [2, 3] }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'chapter', + attributes: { title: 'The Story Begins' }, + relationships: { + pages: { + data: [{ id: 2, type: 'page' }, { id: 3, type: 'page' }] + } + } + } + }); }; run(function() { @@ -2319,7 +2473,18 @@ test("hasMany hasData sync loaded", function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, title: 'The Story Begins', pages: [2, 3] }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'chapter', + attributes: { title: 'The Story Begins' }, + relationships: { + pages: { + data: [{ id: 2, type: 'page' }, { id: 3, type: 'page' }] + } + } + } + }); }; run(function() { @@ -2338,7 +2503,18 @@ test("hasMany hasData async not loaded", function(assert) { }); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, title: 'The Story Begins', links: { pages: 'pages' } }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'chapter', + attributes: { title: 'The Story Begins' }, + relationships: { + pages: { + links: { related: 'pages' } + } + } + } + }); }; run(function() { @@ -2353,7 +2529,13 @@ test("hasMany hasData sync not loaded", function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, title: 'The Story Begins' }); + return Ember.RSVP.resolve({ + data: { + id: 1, + type: 'chapter', + attributes: { title: 'The Story Begins' } + } + }); }; run(function() { @@ -2577,9 +2759,9 @@ test("Related link should be fetched when no local data is present", function(as env.adapter.findHasMany = function(store, snapshot, url, relationship) { assert.equal(url, 'comments', 'url is correct'); assert.ok(true, "The adapter's findHasMany method should be called"); - return Ember.RSVP.resolve([ - { id: 1, body: 'This is comment' } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: 'This is comment' } } + ]}); }; run(function() { @@ -2614,7 +2796,7 @@ test("Local data should take precedence over related link", function(assert) { }; env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ id: 1, body: 'This is comment' }); + return Ember.RSVP.resolve({ data: { id: 1, type: 'comment', attributes: { body: 'This is comment' } } }); }; run(function() { @@ -2650,9 +2832,9 @@ test("Updated related link should take precedence over local data", function(ass env.adapter.findHasMany = function(store, snapshot, url, relationship) { assert.equal(url, 'comments-updated-link', 'url is correct'); assert.ok(true, "The adapter's findHasMany method should be called"); - return Ember.RSVP.resolve([ - { id: 1, body: 'This is comment' } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: 'This is comment' } } + ]}); }; env.adapter.findRecord = function(store, type, id, snapshot) { @@ -2705,10 +2887,10 @@ test("PromiseArray proxies createRecord to its ManyArray before the hasMany is l }); env.adapter.findHasMany = function(store, record, link, relationship) { - return Ember.RSVP.resolve([ - { id: 1, body: "First" }, - { id: 2, body: "Second" } - ]); + return Ember.RSVP.resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "First" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ]}); }; run(function() { diff --git a/tests/integration/relationships/one-to-one-test.js b/tests/integration/relationships/one-to-one-test.js index 1ae4d48eecb..a4b9038aed1 100644 --- a/tests/integration/relationships/one-to-one-test.js +++ b/tests/integration/relationships/one-to-one-test.js @@ -588,13 +588,13 @@ test("Setting a BelongsTo to a promise multiple times is resistant to race condi env.adapter.findRecord = function(store, type, id, snapshot) { if (id === '5') { - return Ember.RSVP.resolve({ id: 5, name: "Igor's friend" }); + return Ember.RSVP.resolve({ data: { id: 5, type: 'user', attributes: { name: "Igor's friend" } } }); } else if (id === '2') { let done = assert.async(); return new Ember.RSVP.Promise(function(resolve, reject) { setTimeout(function() { done(); - resolve({ id: 2, name: "Stanley's friend" }); + resolve({ data: { id: 2, type: 'user', attributes: { name: "Stanley's friend" } } }); }, 1); }); } diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 8c294ba4951..a597ca058c8 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -59,7 +59,7 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', { }); store = env.store; - serializer = store.serializerFor('-json-api'); + serializer = env.serializer; }, afterEach() { diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index c5548b82757..a020766303c 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -7,7 +7,7 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var Post, post, Comment, comment, Favorite, favorite, env; +var Post, post, Comment, comment, Favorite, favorite, env, serializer; var run = Ember.run; module("integration/serializer/json - JSONSerializer", { @@ -31,6 +31,7 @@ module("integration/serializer/json - JSONSerializer", { env.store.modelFor('post'); env.store.modelFor('comment'); env.store.modelFor('favorite'); + serializer = env.store.serializerFor('-json'); }, afterEach() { @@ -44,7 +45,7 @@ test("serialize doesn't include ID when includeId is false", function(assert) { }); var json = {}; - json = env.serializer.serialize(post._createSnapshot(), { includeId: false }); + json = serializer.serialize(post._createSnapshot(), { includeId: false }); assert.deepEqual(json, { title: "Rails is omakase", @@ -59,7 +60,7 @@ test("serialize includes id when includeId is true", function(assert) { }); var json = {}; - json = env.serializer.serialize(post._createSnapshot(), { includeId: true }); + json = serializer.serialize(post._createSnapshot(), { includeId: true }); assert.deepEqual(json, { id: 'test', @@ -76,7 +77,7 @@ if (isEnabled("ds-serialize-id")) { }); var json = {}; - env.serializer.serializeId(post._createSnapshot(), json, 'id'); + serializer.serializeId(post._createSnapshot(), json, 'id'); assert.deepEqual(json, { id: 'test' @@ -134,7 +135,7 @@ test("serializeAttribute", function(assert) { }); var json = {}; - env.serializer.serializeAttribute(post._createSnapshot(), json, "title", { type: "string" }); + serializer.serializeAttribute(post._createSnapshot(), json, "title", { type: "string" }); assert.deepEqual(json, { title: "Rails is omakase" @@ -166,7 +167,7 @@ test("serializeBelongsTo", function(assert) { var json = {}; - env.serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); + serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); assert.deepEqual(json, { post: "1" }); }); @@ -177,7 +178,7 @@ test("serializeBelongsTo with null", function(assert) { }); var json = {}; - env.serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); + serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); assert.deepEqual(json, { post: null @@ -193,7 +194,7 @@ test("async serializeBelongsTo with null", function(assert) { }); var json = {}; - env.serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); + serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); assert.deepEqual(json, { post: null @@ -294,7 +295,7 @@ test("serializeIntoHash", function(assert) { var json = {}; - env.serializer.serializeIntoHash(json, Post, post._createSnapshot()); + serializer.serializeIntoHash(json, Post, post._createSnapshot()); assert.deepEqual(json, { title: "Rails is omakase", @@ -441,6 +442,7 @@ test('Serializer should respect the attrs hash when serializing records', functi }); test('Serializer respects if embedded model has an attribute named "type" - #3726', function(assert) { + env.registry.register("serializer:child", DS.JSONSerializer); env.registry.register("serializer:parent", DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { child: { embedded: 'always' } @@ -476,6 +478,7 @@ test('Serializer respects if embedded model has an attribute named "type" - #372 }); test('Serializer respects if embedded model has a relationship named "type" - #3726', function(assert) { + env.registry.register("serializer:child", DS.JSONSerializer); env.registry.register("serializer:parent", DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { child: { embedded: 'always' } @@ -919,6 +922,7 @@ test('normalizeResponse returns empty `included` payload when relationship is un }); test('normalizeResponse respects `included` items (single response)', function(assert) { + env.registry.register("serializer:comment", DS.JSONSerializer); env.registry.register("serializer:post", DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { comments: { embedded: 'always' } @@ -943,6 +947,7 @@ test('normalizeResponse respects `included` items (single response)', function(a }); test('normalizeResponse respects `included` items (array response)', function(assert) { + env.registry.register("serializer:comment", DS.JSONSerializer); env.registry.register("serializer:post", DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { comments: { embedded: 'always' } @@ -1013,7 +1018,7 @@ test('options are passed to transform for serialization', function(assert) { post = env.store.createRecord('post', { custom: 'value' }); }); - env.serializer.serialize(post._createSnapshot()); + serializer.serialize(post._createSnapshot()); }); test('options are passed to transform for normalization', function(assert) { @@ -1031,7 +1036,7 @@ test('options are passed to transform for normalization', function(assert) { }) }); - env.serializer.normalize(Post, { + serializer.normalize(Post, { custom: 'value' }); }); @@ -1060,7 +1065,7 @@ test('Serializer should respect the attrs hash in links', function(assert) { if (isEnabled("ds-payload-type-hooks")) { test("mapping of model name can be customized via modelNameFromPayloadType", function(assert) { - env.serializer.modelNameFromPayloadType = function(payloadType) { + serializer.modelNameFromPayloadType = function(payloadType) { return payloadType.replace("api::v1::", ""); }; @@ -1074,7 +1079,7 @@ if (isEnabled("ds-payload-type-hooks")) { assert.expectNoDeprecation(); - let normalized = env.serializer.normalizeSingleResponse(env.store, Favorite, jsonHash); + let normalized = serializer.normalizeSingleResponse(env.store, Favorite, jsonHash); assert.deepEqual(normalized, { data: { @@ -1095,7 +1100,7 @@ if (isEnabled("ds-payload-type-hooks")) { }); testInDebug("DEPRECATED - mapping of model name can be customized via modelNameFromPayloadKey", function(assert) { - env.serializer.modelNameFromPayloadKey = function(payloadType) { + serializer.modelNameFromPayloadKey = function(payloadType) { return payloadType.replace("api::v1::", ""); }; @@ -1109,7 +1114,7 @@ if (isEnabled("ds-payload-type-hooks")) { assert.expectDeprecation("You used modelNameFromPayloadKey to customize how a type is normalized. Use modelNameFromPayloadType instead"); - let normalized = env.serializer.normalizeSingleResponse(env.store, Favorite, jsonHash); + let normalized = serializer.normalizeSingleResponse(env.store, Favorite, jsonHash); assert.deepEqual(normalized, { data: { diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 4adc1591bf4..5767f4b7f93 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -106,6 +106,8 @@ test("normalizeResponse with custom modelNameFromPayloadKey", function(assert) { var camelized = Ember.String.camelize(root); return Ember.String.singularize(camelized); }; + env.registry.register('serializer:home-planet', DS.JSONSerializer); + env.registry.register('serializer:super-villain', DS.JSONSerializer); var jsonHash = { home_planets: [{ @@ -201,6 +203,8 @@ testInDebug("normalizeResponse with type and custom modelNameFromPayloadKey", fu testInDebug("normalizeResponse warning with custom modelNameFromPayloadKey", function(assert) { var homePlanet; var oldModelNameFromPayloadKey = env.restSerializer.modelNameFromPayloadKey; + env.registry.register('serializer:super-villain', DS.JSONSerializer); + env.registry.register('serializer:home-planet', DS.JSONSerializer); env.restSerializer.modelNameFromPayloadKey = function(root) { //return some garbage that won"t resolve in the container return "garbage"; @@ -235,6 +239,8 @@ testInDebug("normalizeResponse warning with custom modelNameFromPayloadKey", fun testInDebug("normalizeResponse warning with custom modelNameFromPayloadKey", function(assert) { var homePlanets; + env.registry.register('serializer:super-villain', DS.JSONSerializer); + env.registry.register('serializer:home-planet', DS.JSONSerializer); env.restSerializer.modelNameFromPayloadKey = function(root) { //return some garbage that won"t resolve in the container return "garbage"; @@ -310,6 +316,7 @@ test("serialize polymorphic when associated object is null", function(assert) { test("normalizeResponse loads secondary records with correct serializer", function(assert) { var superVillainNormalizeCount = 0; + env.registry.register('serializer:evil-minion', DS.JSONSerializer); env.registry.register('serializer:super-villain', DS.RESTSerializer.extend({ normalize() { superVillainNormalizeCount++; @@ -347,6 +354,7 @@ test("normalizeResponse returns null if payload contains null", function(assert) test("normalizeResponse loads secondary records with correct serializer", function(assert) { var superVillainNormalizeCount = 0; + env.registry.register('serializer:evil-minion', DS.JSONSerializer); env.registry.register('serializer:super-villain', DS.RESTSerializer.extend({ normalize() { superVillainNormalizeCount++; @@ -776,6 +784,7 @@ test("normalizeResponse can load secondary records of the same type without affe ] }; var array; + env.registry.register('serializer:comment', DS.JSONSerializer); run(function() { array = env.restSerializer.normalizeResponse(env.store, Comment, jsonHash, '1', 'findRecord'); @@ -905,6 +914,7 @@ test('Serializer should respect the attrs hash in links', function(assert) { // https://github.com/emberjs/data/issues/3805 test('normalizes sideloaded single record so that it sideloads correctly - belongsTo - GH-3805', function(assert) { + env.registry.register('serializer:evil-minion', DS.JSONSerializer); env.registry.register("serializer:doomsday-device", DS.RESTSerializer.extend()); let payload = { doomsdayDevice: { @@ -937,6 +947,7 @@ test('normalizes sideloaded single record so that it sideloads correctly - belon // https://github.com/emberjs/data/issues/3805 test('normalizes sideloaded single record so that it sideloads correctly - hasMany - GH-3805', function(assert) { + env.registry.register('serializer:super-villain', DS.JSONSerializer); env.registry.register("serializer:home-planet", DS.RESTSerializer.extend()); let payload = { homePlanet: { diff --git a/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js index 6bb11f9e20c..cf125d7d797 100644 --- a/tests/integration/snapshot-test.js +++ b/tests/integration/snapshot-test.js @@ -372,7 +372,7 @@ test("snapshot.belongsTo() returns a snapshot if relationship link has been fetc assert.expect(2); env.adapter.findBelongsTo = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ id: 1, title: 'Hello World' }); + return Ember.RSVP.resolve({ data: { id: 1, type: 'post', attributes: { title: 'Hello World' } } }); }; run(function() { @@ -804,7 +804,7 @@ test("snapshot.hasMany() returns array of snapshots if relationship link has bee assert.expect(2); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve([{ id: 2, body: 'This is comment' }]); + return Ember.RSVP.resolve({ data: [{ id: 2, type: 'comment', attributes: { body: 'This is comment' } }]}); }; run(function() { @@ -1055,7 +1055,17 @@ test("snapshot.serialize() serializes itself", function(assert) { post.set('title', 'New Title'); - assert.deepEqual(snapshot.serialize(), { author: undefined, title: 'Hello World' }, 'shapshot serializes correctly'); - assert.deepEqual(snapshot.serialize({ includeId: true }), { id: "1", author: undefined, title: 'Hello World' }, 'serialize takes options'); + var expected = { + data: { + attributes: { + author: undefined, + title: 'Hello World' + }, + type: 'posts' + } + }; + assert.deepEqual(snapshot.serialize(), expected, 'shapshot serializes correctly'); + expected.data.id = '1'; + assert.deepEqual(snapshot.serialize({ includeId: true }), expected, 'serialize takes options'); }); }); diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 4d9266ee147..4af6741d664 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -162,10 +162,11 @@ test("destroying the store correctly cleans everything up", function(assert) { }); env.adapter.query = function() { - return [{ + return { data: [{ id: 2, - name: 'Yehuda' - }]; + type: 'person', + attributes: { name: 'Yehuda' } + }]}; }; var adapterPopulatedPeople, filterdPeople; diff --git a/tests/integration/store/query-record-test.js b/tests/integration/store/query-record-test.js index 76376e5792a..a712c6ef5c3 100644 --- a/tests/integration/store/query-record-test.js +++ b/tests/integration/store/query-record-test.js @@ -47,7 +47,7 @@ test("When a record is requested, the adapter's queryRecord method should be cal env.registry.register('adapter:person', DS.Adapter.extend({ queryRecord(store, type, query) { assert.equal(type, Person, "the query method is called with the correct type"); - return Ember.RSVP.resolve({ id: 1, name: "Peter Wagenet" }); + return Ember.RSVP.resolve({ data: { id: 1, type: 'person', attributes: { name: "Peter Wagenet" } } }); } })); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 1340ea94cc7..da70733455d 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -6,7 +6,7 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; import { isEnabled } from 'ember-data/-private'; -const { get, set, run } = Ember; +const { get, getOwner, set, run } = Ember; let Person, store, env; @@ -360,7 +360,7 @@ test('changedAttributes() works while the record is being saved', function(asser likes: [undefined, 'Cheese'] }); - return { id: 1 }; + return { data: { id: 1, type: 'mascot' } }; } }); @@ -396,7 +396,7 @@ test('changedAttributes() works while the record is being updated', function(ass likes: ['Cheese', 'Mussels'] }); - return { id: '1', type: 'mascot' }; + return { data: { id: '1', type: 'mascot' } }; } }); @@ -1006,6 +1006,7 @@ function converts(assert, type, provided, expected, options = {}) { let testStore = createStore({ model: Model }); + getOwner(testStore).register('serializer:model', DS.JSONSerializer); run(() => { testStore.push(testStore.normalize('model', { id: 1, name: provided })); @@ -1041,6 +1042,7 @@ function convertsFromServer(assert, type, provided, expected) { shouldBackgroundReloadRecord() { return false; } }) }); + getOwner(testStore).register('serializer:model', DS.JSONSerializer); return run(() => { testStore.push(testStore.normalize('model', { @@ -1141,6 +1143,7 @@ function convertsWhenSet(assert, type, provided, expected) { } }) }); + getOwner(testStore).register('serializer:model', DS.JSONSerializer); return run(() => { testStore.push({ @@ -1180,8 +1183,11 @@ test('ensure model exits loading state, materializes data and fulfills promise o adapter: DS.Adapter.extend({ findRecord(store, type, id, snapshot) { return Ember.RSVP.resolve({ - id: 1, - name: 'John' + data: { + id: 1, + type: 'person', + attributes: { name: 'John' } + } }); } }), @@ -1204,7 +1210,7 @@ test('A DS.Model can be JSONified', function(assert) { let store = createStore({ person: Person }); let record = run(() => store.createRecord('person', { name: 'TomHuda' })); - assert.deepEqual(record.toJSON(), { name: 'TomHuda' }); + assert.deepEqual(record.toJSON(), { data: { type: 'people', attributes: { name: 'TomHuda' } } }); }); testInDebug('A subclass of DS.Model can not use the `data` property', function(assert) { @@ -1325,7 +1331,7 @@ test('toJSON looks up the JSONSerializer using the store instead of using JSONSe } assert.ok(!errorThrown, 'error not thrown due to missing store'); - assert.deepEqual(json, {}); + assert.deepEqual(json, { data: { type: 'people' }}); }); test('internalModel is ready by `init`', function(assert) { diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index c7dbd9fa820..13257dd728d 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -21,7 +21,7 @@ test('a record receives a didLoad callback when it has finished loading', functi const Adapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return { id: 1, name: 'Foo' }; + return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; } }); @@ -78,7 +78,7 @@ test('a record receives a didUpdate callback when it has finished updating', fun const Adapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return { id: 1, name: 'Foo' }; + return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; }, updateRecord(store, type, snapshot) { @@ -165,7 +165,7 @@ test('a record receives a didDelete callback when it has finished deleting', fun const Adapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return { id: 1, name: 'Foo' }; + return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; }, deleteRecord(store, type, snapshot) { @@ -244,7 +244,7 @@ test('a record receives a becameInvalid callback when it became invalid', functi const Adapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return { id: 1, name: "Foo" }; + return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; }, updateRecord(store, type, snapshot) { diff --git a/tests/unit/model/merge-test.js b/tests/unit/model/merge-test.js index 26e93f8aac1..c2f865dd5d9 100644 --- a/tests/unit/model/merge-test.js +++ b/tests/unit/model/merge-test.js @@ -22,7 +22,7 @@ test('When a record is in flight, changes can be made', function(assert) { const Adapter = DS.Adapter.extend({ createRecord(store, type, snapshot) { - return { id: 1, name: 'Tom Dale' }; + return { data: { id: 1, type: 'person', attributes: { name: 'Tom Dale' } } }; } }); @@ -98,7 +98,7 @@ test("When a record is in flight, pushes are applied underneath the in flight ch updateRecord(store, type, snapshot) { // Make sure saving isn't resolved synchronously return new Ember.RSVP.Promise(resolve => { - run.next(null, resolve, { id: 1, name: 'Senor Thomas Dale, Esq.', city: 'Portland' }); + run.next(null, resolve, { data: { id: 1, type: 'person', attributes: { name: 'Senor Thomas Dale, Esq.', city: 'Portland' } } }); }); } }); @@ -245,7 +245,7 @@ test('A record with no changes can still be saved', function(assert) { const Adapter = DS.Adapter.extend({ updateRecord(store, type, snapshot) { - return { id: 1, name: 'Thomas Dale' }; + return { data: { id: 1, type: 'person', attributes: { name: 'Thomas Dale' } } }; } }); @@ -277,7 +277,7 @@ test('A dirty record can be reloaded', function(assert) { const Adapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return { id: 1, name: 'Thomas Dale', city: 'Portland' }; + return { data: { id: 1, type: 'person', attributes: { name: 'Thomas Dale', city: 'Portland' } } }; } }); diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index a6c0919dbf2..32606b21674 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -151,11 +151,11 @@ test('async belongsTo relationships work when the data hash has not been loaded' if (type === Person) { assert.equal(id, 1, 'id should be 1'); - return { id: 1, name: 'Tom Dale', tag: 2 }; + return { data: { id: 1, type: 'person', attributes: { name: 'Tom Dale' }, relationships: { tag: { data: { id: 2, type: 'tag' } } } } }; } else if (type === Tag) { assert.equal(id, 2, 'id should be 2'); - return { id: 2, name: 'friendly' }; + return { data: { id: 2, type: 'tag', attributes: { name: 'friendly' } } }; } }; @@ -252,9 +252,18 @@ test('when response to saving a belongsTo is a success but includes changes that env.adapter.updateRecord = function() { return { - type: 'user', - id: '1', - tag: { type: 'tag', id: '1' } + data: { + type: 'user', + id: '1', + relationships: { + tag: { + data: { + id: '1', + type: 'tag' + } + } + } + } }; }; @@ -308,10 +317,10 @@ test('When finding a hasMany relationship the inverse belongsTo relationship is env.adapter.findMany = function(store, type, ids, snapshots) { assert.equal(snapshots[0].belongsTo('person').id, '1'); - return [ - { id: 5, description: "fifth" }, - { id: 2, description: "second" } - ]; + return { data: [ + { id: 5, type: 'occupation', attributes: { description: "fifth" } }, + { id: 2, type: 'occupation', attributes: { description: "second" } } + ]}; }; env.adapter.coalesceFindRequests = true; @@ -369,7 +378,7 @@ test('When finding a belongsTo relationship the inverse belongsTo relationship i env.adapter.findRecord = function(store, type, id, snapshot) { assert.equal(snapshot.belongsTo('person').id, '1'); - return { id: 5, description: 'fifth' }; + return { data: { id: 5, type: 'occupation', attributes: { description: 'fifth' } } }; }; run(() => { diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 3fc39968926..b9f3d391d5a 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -564,7 +564,7 @@ test('hasMany lazily loads async relationships', function(assert) { env.adapter.findRecord = function(store, type, id, snapshot) { if (type === Tag && id === '12') { - return { id: 12, name: 'oohlala' }; + return { data: { id: 12, type: 'tag', attributes: { name: 'oohlala' } } }; } else { assert.ok(false, 'findRecord() should not be called with these values'); } @@ -809,17 +809,28 @@ test('hasMany relationships work when the data hash has not been loaded', functi assert.equal(type, Tag, 'type should be Tag'); assert.deepEqual(ids, ['5', '2'], 'ids should be 5 and 2'); - return [ - { id: 5, name: 'friendly' }, - { id: 2, name: 'smarmy' } - ]; + return { data: [ + { id: 5, type: 'tag', attributes: { name: 'friendly' } }, + { id: 2, type: 'tag', attributes: { name: 'smarmy' } } + ]}; }; env.adapter.findRecord = function(store, type, id, snapshot) { assert.equal(type, Person, 'type should be Person'); assert.equal(id, 1, 'id should be 1'); - return { id: 1, name: 'Tom Dale', tags: [5, 2] }; + return { + data: { + id: 1, + type: 'person', + attributes: { name: 'Tom Dale' }, + relationships: { + tags: { + data: [{ id: 5, type: 'tag'}, { id: 2, type: 'tag'}] + } + } + } + }; }; return run(() => { @@ -1211,8 +1222,10 @@ testInDebug('checks if passed array only contains instances of DS.Model', functi env.adapter.findRecord = function() { return { - type: 'person', - id: 1 + data: { + type: 'person', + id: 1 + } }; }; diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index 0ad27eacc61..bd03ce621d8 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -60,7 +60,10 @@ test('Calling Store#find invokes its adapter#find', function(assert) { assert.equal(snapshot.id, '1', "Adapter#find was called with the record created from Store#find"); return Ember.RSVP.resolve({ - id: 1 + data: { + id: 1, + type: 'test' + } }); } }); @@ -85,7 +88,7 @@ test('Calling Store#findRecord multiple times coalesces the calls into a adapter findMany(store, type, ids, snapshots) { assert.ok(true, 'Adapter#findMany was called'); assert.deepEqual(ids, ['1','2'], 'Correct ids were passed in to findMany'); - return Ember.RSVP.resolve([{ id: 1 }, { id: 2 }]); + return Ember.RSVP.resolve({ data: [{ id: 1, type: 'test' }, { id: 2, type: 'test' }] }); }, coalesceFindRequests: true }); @@ -109,7 +112,7 @@ test('Returning a promise from `findRecord` asynchronously loads data', function const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { - return resolve({ id: 1, name: "Scumbag Dale" }); + return resolve({ data: { id: 1, type: 'test', attributes: { name: "Scumbag Dale" } } }); } }); @@ -135,7 +138,7 @@ test('IDs provided as numbers are coerced to strings', function(assert) { const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(typeof id, 'string', 'id has been normalized to a string'); - return resolve({ id, name: 'Scumbag Sylvain' }); + return resolve({ data: { id, type: 'test', attributes: { name: 'Scumbag Sylvain' } } }); } }); @@ -229,7 +232,7 @@ test('loadMany takes an optional Object and passes it on to the Adapter', functi query(store, type, query) { assert.equal(type, store.modelFor('person'), 'The type was Person'); assert.equal(query, passedQuery, 'The query was passed in'); - return Ember.RSVP.resolve([]); + return Ember.RSVP.resolve({ data: [] }); } }); @@ -410,7 +413,7 @@ test("initial values of attributes can be passed in as the third argument to fin const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.attr('name'), 'Test', 'Preloaded attribtue set'); - return { id: '1', name: 'Test' }; + return { data: { id: '1', type: 'test', attributes: { name: 'Test' } } }; } }); @@ -432,7 +435,7 @@ test('initial values of belongsTo can be passed in as the third argument to find const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.belongsTo('friend').attr('name'), 'Tom', 'Preloaded belongsTo set'); - return { id }; + return { data: { id, type: 'person' } }; } }); @@ -470,7 +473,7 @@ test('initial values of belongsTo can be passed in as the third argument to find const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { - return { id }; + return { data: { id, type: 'person' } }; } }); @@ -502,7 +505,7 @@ test('initial values of hasMany can be passed in as the third argument to find a const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.hasMany('friends')[0].attr('name'), 'Tom', 'Preloaded hasMany set'); - return { id, type }; + return { data: { id, type: 'person' } }; } }); @@ -541,7 +544,7 @@ test('initial values of hasMany can be passed in as the third argument to find a const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.hasMany('friends')[0].id, '2', 'Preloaded hasMany set'); - return { id }; + return { data: { id, type: 'person' } }; } }); @@ -571,8 +574,13 @@ test('records should have their ids updated when the adapter returns the id data const Adapter = TestAdapter.extend({ createRecord(store, type, snapshot) { return { - name: snapshot.attr('name'), - id: idCounter++ + data: { + id: idCounter++, + type: 'person', + attributes: { + name: snapshot.attr('name') + } + } }; } }); @@ -632,19 +640,19 @@ test('store._scheduleFetchMany should not resolve until all the records are reso const adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { - let record = { id: id }; + let record = { id, type: type.modelName }; return new Ember.RSVP.Promise(resolve => { - run.later(() => resolve(record), 5); + run.later(() => resolve({ data: record }), 5); }); }, findMany(store, type, ids, snapshots) { - let records = ids.map(id => ( { id }) ); + let records = ids.map(id => ( { id, type: type.modelName }) ); return new Ember.RSVP.Promise(resolve => { run.later(() => { - resolve(records); + resolve({data: records }); }, 15); }); } @@ -688,15 +696,15 @@ test('the store calls adapter.findMany according to groupings returned by adapte findRecord(store, type, id, snapshot) { assert.equal(id, '10', 'The first group is passed to find'); - return { id }; + return { data: { id, type: 'test' } }; }, findMany(store, type, ids, snapshots) { - let records = ids.map(id => ({ id })); + let records = ids.map(id => ({ id, type: 'test' })); assert.deepEqual(ids, ['20', '21'], 'The second group is passed to findMany'); - return records; + return { data: records }; } }); @@ -734,15 +742,15 @@ test('the promise returned by `_scheduleFetch`, when it resolves, does not depen }, findRecord(store, type, id, snapshot) { - let record = { id }; + let record = { id, type: 'test' }; return new Ember.RSVP.Promise(function(resolve, reject) { if (id === 'igor') { - resolve(record); + resolve({ data: record }); } else { run.later(function () { davidResolved = true; - resolve(record); + resolve({ data: record }); }, 5); } }); @@ -786,15 +794,15 @@ test('the promise returned by `_scheduleFetch`, when it rejects, does not depend }, findRecord(store, type, id, snapshot) { - let record = { id }; + let record = { id, type: 'test' }; return new Ember.RSVP.Promise((resolve, reject) => { if (id === 'igor') { - reject(record); + reject({ data: record }); } else { run.later(() => { davidResolved = true; - resolve(record); + resolve({ data: record }); }, 5); } }); @@ -830,8 +838,8 @@ testInDebug('store._fetchRecord reject records that were not found, even when th const Adapter = TestAdapter.extend({ findMany(store, type, ids, snapshots) { - let records = ids.map((id) => ({ id })); - return [records[0]]; + let records = ids.map((id) => ({ id, type: 'test' })); + return { data: [records[0]] }; } }); @@ -859,9 +867,9 @@ testInDebug('store._fetchRecord warns when records are missing', function(assert const Adapter = TestAdapter.extend({ findMany(store, type, ids, snapshots) { - let records = ids.map(id => ({ id })).filter(({ id }) => id === 'david'); + let records = ids.map(id => ({ id, type: 'test' })).filter(({ id }) => id === 'david'); - return [records[0]]; + return {data: [records[0]] }; } }); @@ -902,7 +910,7 @@ test('store should not call shouldReloadRecord when the record is not in the sto }, findRecord() { assert.ok(true, 'find is always called when the record is not in the store'); - return { id: 1 }; + return { data: { id: 1, type: 'person' } }; } }); @@ -965,7 +973,7 @@ test('store should reload record when shouldReloadRecord returns true', function }, findRecord() { assert.ok(true, 'find should not be called when shouldReloadRecord returns false'); - return { id: 1, name: 'Tom' }; + return { data: { id: 1, type: 'person', attributes: { name: 'Tom' } } }; } }); @@ -1004,7 +1012,7 @@ test('store should not call shouldBackgroundReloadRecord when the store is alrea }, findRecord() { assert.ok(true, 'find should be called'); - return { id: 1, name: 'Tom' }; + return { data: { id: 1, type: 'person', attributes: { name: 'Tom' } } }; } }); @@ -1041,7 +1049,7 @@ test('store should not reload a record when `shouldBackgroundReloadRecord` is fa }, findRecord() { assert.ok(false, 'find should not be called'); - return { id: 1, name: 'Tom' }; + return { data: { id: 1, type: 'person', attributes: { name: 'Tom' } } }; } }); @@ -1079,7 +1087,7 @@ test('store should reload the record in the background when `shouldBackgroundRel }, findRecord() { assert.ok(true, 'find should not be called'); - return { id: 1, name: 'Tom' }; + return { data: { id: 1, type: 'person', attributes: { name: 'Tom' } } }; } }); @@ -1148,7 +1156,7 @@ test('store should reload all records when shouldReloadAll returns true', functi }, findAll() { assert.ok(true, 'findAll should be called when shouldReloadAll returns true'); - return [{ id: 1, name: 'Tom' }]; + return { data: [{ id: 1, type: 'person', attributes: { name: 'Tom' } }]}; } }); @@ -1180,7 +1188,7 @@ test('store should not call shouldBackgroundReloadAll when the store is already }, findAll() { assert.ok(true, 'find should be called'); - return [{ id: 1, name: 'Tom' }]; + return { data: [{ id: 1, type: 'person', attributes: { name: 'Tom' } }]}; } }); @@ -1214,7 +1222,7 @@ test('store should not reload all records when `shouldBackgroundReloadAll` is fa }, findAll() { assert.ok(false, 'findAll should not be called'); - return [{ id: 1, name: 'Tom' }]; + return { data: [{ id: 1, type: 'person', attributes: { name: 'Tom' } }] }; } }); @@ -1249,7 +1257,7 @@ test('store should reload all records in the background when `shouldBackgroundRe }, findAll() { assert.ok(true, 'find should not be called'); - return [{ id: 1, name: 'Tom' }]; + return { data: [{ id: 1, type: 'person', attributes: { name: 'Tom' } }] }; } }); diff --git a/tests/unit/store/finders-test.js b/tests/unit/store/finders-test.js index 54df12b39c3..b6d724d305d 100644 --- a/tests/unit/store/finders-test.js +++ b/tests/unit/store/finders-test.js @@ -53,7 +53,7 @@ test('findRecord does not load a serializer until the adapter promise resolves', assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); return run(() => { - deferedFind.resolve({ id: 1, name: 'John Churchill' }); + deferedFind.resolve({ data: { id: 1, type: 'person', attributes: { name: 'John Churchill' } } }); return storePromise.then(() => { assert.equal(true, serializerLoaded, 'serializer is loaded'); }); @@ -85,7 +85,7 @@ test('findMany does not load a serializer until the adapter promise resolves', f assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); return run(() => { - deferedFind.resolve([{ id: 1, name: 'John Churchill' }, { id: 2, name: 'Louis Joseph' }]); + deferedFind.resolve({ data: [{ id: 1, type: 'person', attributes: { name: 'John Churchill' } }, { id: 2, type: 'person', attributes: { name: 'Louis Joseph' } }] }); return storePromise.then(() => { assert.equal(true, serializerLoaded, 'serializer is loaded'); }); @@ -137,7 +137,7 @@ test('findHasMany does not load a serializer until the adapter promise resolves' assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); return run(() => { - deferedFind.resolve([{ id: 1, name: 'Scooby' }, { id: 2, name: 'Scrappy' }]); + deferedFind.resolve({ data: [{ id: 1, type: 'dog', attributes: { name: 'Scooby' } }, { id: 2, type: 'dog', attributes: { name: 'Scrappy' } }] }); return storePromise.then(() => { assert.equal(true, serializerLoaded, 'serializer is loaded'); }); @@ -189,7 +189,7 @@ test('findBelongsTo does not load a serializer until the adapter promise resolve assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); return run(() => { - deferedFind.resolve({ id: 1, name: 'Scooby' }); + deferedFind.resolve({ data: { id: 1, type: 'dog', attributes: { name: 'Scooby' } } }); return storePromise.then(() => { assert.equal(true, serializerLoaded, 'serializer is loaded'); }); @@ -218,7 +218,7 @@ test('findAll does not load a serializer until the adapter promise resolves', fu assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); return run(() => { - deferedFind.resolve([{ id: 1, name: 'John Churchill' }]); + deferedFind.resolve({ data: [{ id: 1, type: 'person', attributes: { name: 'John Churchill' } }] }); return storePromise.then(() => { assert.equal(true, serializerLoaded, 'serializer is loaded'); }); @@ -247,7 +247,7 @@ test('query does not load a serializer until the adapter promise resolves', func assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); return run(() => { - deferedFind.resolve([{ id: 1, name: 'John Churchill' }]); + deferedFind.resolve({ data: [{ id: 1, type: 'person', attributes: { name: 'John Churchill' } }] }); return storePromise.then(() => { assert.equal(true, serializerLoaded, 'serializer is loaded'); }); @@ -276,7 +276,7 @@ test('queryRecord does not load a serializer until the adapter promise resolves' assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); return run(() => { - deferedFind.resolve({ id: 1, name: 'John Churchill' }); + deferedFind.resolve({ data: { id: 1, type: 'person', attributes: { name: 'John Churchill' } } }); return storePromise.then(() => { assert.equal(true, serializerLoaded, 'serializer is loaded'); }); diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index a3c51f88660..e884f3627c0 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -251,17 +251,31 @@ test('Calling push with a normalized hash containing IDs of related records retu env.adapter.findRecord = function(store, type, id) { if (id === '1') { return Ember.RSVP.resolve({ - id: 1, - number: '5551212', - person: 'wat' + data: { + id: 1, + type: 'phone-number', + attributes: { number: '5551212' }, + relationships: { + person: { + data: { id: 'wat', type: 'person' } + } + } + } }); } if (id === "2") { return Ember.RSVP.resolve({ - id: 2, - number: '5552121', - person: 'wat' + data: { + id: 2, + type: 'phone-number', + attributes: { number: '5552121' }, + relationships: { + person: { + data: { id: 'wat', type: 'person' } + } + } + } }); } }; @@ -269,9 +283,16 @@ test('Calling push with a normalized hash containing IDs of related records retu return run(() => { let person = store.push(store.normalize('person', { id: 'wat', - firstName: 'John', - lastName: 'Smith', - phoneNumbers: ["1", "2"] + type: 'person', + attributes: { + 'first-name': 'John', + 'last-name': 'Smith' + }, + relationships: { + 'phone-numbers': { + data: [{ id: 1, type: 'phone-number' }, { id: 2, type: 'phone-number' }] + } + } })); return person.get('phoneNumbers').then(phoneNumbers => { @@ -573,10 +594,13 @@ test('Calling push with a link containing an object', function(assert) { run(() => { store.push(store.normalize('person', { id: '1', - firstName: 'Tan', - links: { - phoneNumbers: { - href: '/api/people/1/phone-numbers' + type: 'person', + attributes: { + 'first-name': 'Tan' + }, + relationships: { + 'phone-numbers': { + links: { related: '/api/people/1/phone-numbers' } } } })); @@ -591,9 +615,16 @@ test('Calling push with a link containing the value null', function(assert) { run(() => { store.push(store.normalize('person', { id: '1', - firstName: 'Tan', - links: { - phoneNumbers: null + type: 'person', + attributes: { + 'first-name': 'Tan' + }, + relationships: { + 'phone-numbers': { + links: { + related: null + } + } } })); }); diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index 3e711eca777..94b22b5faed 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -27,7 +27,7 @@ module('unit/store/unload - Store unloading records', { adapter: DS.Adapter.extend({ findRecord(store, type, id, snapshot) { tryToFind = true; - return Ember.RSVP.resolve({ id: id, wasFetched: true }); + return Ember.RSVP.resolve({ data: { id, type: snapshot.modelName, attributes: { 'was-fetched': true } } }); } }), @@ -144,9 +144,14 @@ test('can commit store after unload record with relationships', function(assert) adapter: DS.Adapter.extend({ findRecord(store, type, id, snapshot) { return Ember.RSVP.resolve({ - id: 1, - description: 'cuisinart', - brand: 1 + data: { + id: 1, + type: snapshot.modelName, + attributes: { + description: 'cuisinart', + brand: 1 + } + } }); }, From d0b64ee1a6db0a0080cd07a212362a13ba8c33e2 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 16 Jun 2017 12:10:46 -0700 Subject: [PATCH 1948/2527] [BUGFIX] fixes an issue with sync dematerialization followed by a findRecord, adds test coverage --- addon/-private/system/model/internal-model.js | 15 +- addon/-private/system/store.js | 4 + tests/integration/records/unload-test.js | 157 ++++++++++++++++++ 3 files changed, 175 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 4460d103e3f..e1cdbd5a9b4 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -24,6 +24,7 @@ const { isEmpty, isEqual, setOwner, + run, RSVP, RSVP: { Promise } } = Ember; @@ -136,6 +137,7 @@ export default class InternalModel { // `objectAt(len - 1)` to test whether or not `firstObject` or `lastObject` // have changed. this._isDematerializing = false; + this._scheduledDestroy = null; this.resetRecord(); @@ -490,11 +492,22 @@ export default class InternalModel { unloadRecord() { this.send('unloadRecord'); this.dematerializeRecord(); - Ember.run.schedule('destroy', this, '_checkForOrphanedInternalModels'); + if (this._scheduledDestroy === null) { + this._scheduledDestroy = run.schedule('destroy', this, '_checkForOrphanedInternalModels'); + } + } + + cancelDestroy() { + assert(`You cannot cancel the destruction of an InternalModel once it has already been destroyed`, !this.isDestroyed); + + this._isDematerializing = false; + run.cancel(this._scheduledDestroy); + this._scheduledDestroy = null; } _checkForOrphanedInternalModels() { this._isDematerializing = false; + this._scheduledDestroy = null; if (this.isDestroyed) { return; } this._cleanupOrphanedInternalModels(); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 3c01a50e429..0c45cae4d15 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1127,6 +1127,10 @@ Store = Service.extend({ if (!internalModel) { internalModel = this._buildInternalModel(modelName, trueId); + } else { + // if we already have an internalModel, we need to ensure any async teardown is cancelled + // since we want it again. + internalModel.cancelDestroy(); } return internalModel; diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 038436c76e5..df15382eda2 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -419,3 +419,160 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu assert.equal(relPayloads.get('person', 1, 'cars'), null, 'person - cars relationship payload unloaded'); }); + + +test("Unloading a record twice only schedules destroy once", function(assert) { + const store = env.store; + let record; + + // populate initial record + run(function() { + record = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + } + } + }); + }); + + const internalModel = record._internalModel; + + run(function() { + store.unloadRecord(record); + store.unloadRecord(record); + internalModel.cancelDestroy(); + }); + + assert.equal(internalModel.isDestroyed, false, 'We cancelled destroy'); +}); + +test("Cancelling destroy leaves the record in the empty state", function(assert) { + const store = env.store; + let record; + + // populate initial record + run(function() { + record = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + } + } + }); + }); + + const internalModel = record._internalModel; + assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded initially'); + + run(function() { + store.unloadRecord(record); + assert.equal(record.isDestroying, true, 'the record is destroying'); + assert.equal(internalModel.isDestroyed, false, 'the internal model is not destroyed'); + assert.equal(internalModel._isDematerializing, true, 'the internal model is dematerializing'); + internalModel.cancelDestroy(); + assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are unloaded after unloadRecord'); + }); + + assert.equal(internalModel.isDestroyed, false, 'the internal model was not destroyed'); + assert.equal(internalModel._isDematerializing, false, 'the internal model is no longer dematerializing'); + assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are still unloaded after unloadRecord'); +}); + +test("after unloading a record, the record can be fetched again immediately", function(assert) { + const store = env.store; + let record; + + // stub findRecord + env.adapter.findRecord = () => { + return Ember.RSVP.Promise.resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + } + } + }); + }; + + // populate initial record + run(function() { + record = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + } + } + }); + }); + + const internalModel = record._internalModel; + assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded initially'); + + // we test that we can sync call unloadRecord followed by findRecord + run(function() { + store.unloadRecord(record); + assert.equal(record.isDestroying, true, 'the record is destroying'); + assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are unloaded after unloadRecord'); + store.findRecord('person', '1'); + }); + + assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded after findRecord'); +}); + + +test("after unloading a record, the record can be fetched again soon there after", function(assert) { + const store = env.store; + let record; + + // stub findRecord + env.adapter.findRecord = () => { + return Ember.RSVP.Promise.resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + } + } + }); + }; + + // populate initial record + run(function() { + record = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + } + } + }); + }); + + let internalModel = record._internalModel; + assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded initially'); + + run(function() { + store.unloadRecord(record); + assert.equal(record.isDestroying, true, 'the record is destroying'); + assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are unloaded after unloadRecord'); + }); + + run(function() { + store.findRecord('person', '1'); + }); + + record = store.peekRecord('person', '1'); + internalModel = record._internalModel; + + assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded after findRecord'); +}); From 23a13a0857a157368696dad8f034109bf4ab1643 Mon Sep 17 00:00:00 2001 From: bmac Date: Sun, 18 Jun 2017 00:18:14 -0400 Subject: [PATCH 1949/2527] Update changelog for the Ember Data 2.13.2 release --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ad8ff02686..af6d9223b19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ### Master +### Release 2.13.2 (June 18, 2017) +- [#5012](https://github.com/emberjs/data/pull/5012) [BUGFIX release] fixes an issue with sync dematerialization followed by a findRecord, adds test coverage + ### Release 2.13.1 (May 5, 2017) - [#4965](https://github.com/emberjs/data/pull/4965) [BUGFIX beta] Skip test which doesn't play nicely with the latest em… - [#4970](https://github.com/emberjs/data/pull/4970) [BUGFIX release] Ensure Engines can boot without error. From a1ca791aca9ae84baa92c24950d700841032b515 Mon Sep 17 00:00:00 2001 From: bmac Date: Sun, 18 Jun 2017 00:25:25 -0400 Subject: [PATCH 1950/2527] Update changelog for the Ember Data 2.14.0 release --- CHANGELOG.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index af6d9223b19..8fda0db2b53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,68 @@ ### Master +### Release 2.14.0 (June 18, 2017) +- [#5013](https://github.com/emberjs/data/pull/5013) [BUGFIX beta] fixes an issue with sync dematerialization followed by a findRecord, adds test coverage +- [#5002](https://github.com/emberjs/data/pull/5002) [BUGFIX BETA] Added `system/store/container-instance-cache` to the -private export file +- [#4959](https://github.com/emberjs/data/pull/4959) [BUGFIX] remove forgotten broccoli-stew import +- [#4965](https://github.com/emberjs/data/pull/4965) [BUGFIX beta] Skip test which doesn't play nicely with the latest em… +- [#4969](https://github.com/emberjs/data/pull/4969) [BUGFIX beta] Ensure Engines can boot without error. +- [#4971](https://github.com/emberjs/data/pull/4971) Fix typo in function call +- [#4885](https://github.com/emberjs/data/pull/4885) Lazy snapshot.type +- [#4855](https://github.com/emberjs/data/pull/4855) Update the changelog for the Ember Data 2.12.0 release +- [#4821](https://github.com/emberjs/data/pull/4821) Pay go setup relationships +- [#4884](https://github.com/emberjs/data/pull/4884) Defer serializer loading +- [#4863](https://github.com/emberjs/data/pull/4863) Tidy up parse-reponse-headers (#4863) +- [#4861](https://github.com/emberjs/data/pull/4861) Update yarn.lock +- [#4862](https://github.com/emberjs/data/pull/4862) Babel 6 +- [#4860](https://github.com/emberjs/data/pull/4860) Refactor the detection / warnings around ember-cli-shims. (#4860) +- [#4913](https://github.com/emberjs/data/pull/4913) [BUGFIX canary] don't prematurely nullify props +- [#4869](https://github.com/emberjs/data/pull/4869) Speed up triggering events +- [#4864](https://github.com/emberjs/data/pull/4864) make ES6.Classes loose (#4864) +- [#4868](https://github.com/emberjs/data/pull/4868) [PERF] make filtered/liveRecord array storage a simple Object.create(… +- [#4909](https://github.com/emberjs/data/pull/4909) Deprecate didUpdateAll, add _didUpdateAll. +- [#4870](https://github.com/emberjs/data/pull/4870) More record -> internalModel fixes +- [#4908](https://github.com/emberjs/data/pull/4908) Add a better error message when malformatted JSON API is pushed into … +- [#4871](https://github.com/emberjs/data/pull/4871) Remove dead code +- [#4891](https://github.com/emberjs/data/pull/4891) Add a test to ensure a HasManyReference returns a value when the arra… +- [#4905](https://github.com/emberjs/data/pull/4905) [DOCUMENTATION] Refer the RFC process for requesting new features +- [#4896](https://github.com/emberjs/data/pull/4896) Ember.warn when ManyArray.objectAt() is undefined +- [#4892](https://github.com/emberjs/data/pull/4892) [DOC] Documents the caching behavior of queryRecord +- [#4900](https://github.com/emberjs/data/pull/4900) [doc] updating peekRecord documentation with reference to its counterpart f… +- [#4893](https://github.com/emberjs/data/pull/4893) Remove unnecessary relationship guard +- [#4897](https://github.com/emberjs/data/pull/4897) Deprecate buildInternalModel, add _buildInternalModel. +- [#4898](https://github.com/emberjs/data/pull/4898) [BUGFIX beta] Rename `relationship.destroy` to `removeInverseRelationships` +- [#4901](https://github.com/emberjs/data/pull/4901) [BUGFIX beta] Removes `get record` from InternalModel. (#4901) +- [#4899](https://github.com/emberjs/data/pull/4899) Fix internalModel typo +- [#4903](https://github.com/emberjs/data/pull/4903) Use node 6 for travis tests +- [#4880](https://github.com/emberjs/data/pull/4880) [BUGFIX canary] ensure context is applied in the iife +- [#4878](https://github.com/emberjs/data/pull/4878) Fix tests in release branch RE: factoryFor. (#4878) +- [#4874](https://github.com/emberjs/data/pull/4874) Rename record[s] -> internalModel[s] +- [#4883](https://github.com/emberjs/data/pull/4883) Fix readme typo - "First things first" +- [#4876](https://github.com/emberjs/data/pull/4876) [BUGFIX canary] ensure the globals build has the correct context in the iife. +- [#4895](https://github.com/emberjs/data/pull/4895) [PERF] single-pass over the initializers array +- [#4931](https://github.com/emberjs/data/pull/4931) [BUGFIX beta] [fixes #4509] createRecord initializes correctly +- [#4914](https://github.com/emberjs/data/pull/4914) Revert "Ember.warn when ManyArray.objectAt() is underfined" +- [#4910](https://github.com/emberjs/data/pull/4910) [BUGFIX] initial-relationship-setup must handle null +- [#4911](https://github.com/emberjs/data/pull/4911) [BUGFIX] partially fix pushing of null onto already materialized array +- [#4935](https://github.com/emberjs/data/pull/4935) bump github module slightly to work around node-resolve issue (remove… +- [#4922](https://github.com/emberjs/data/pull/4922) [BUGFIX release] restore internalModels GUID_KEY’s +- [#4920](https://github.com/emberjs/data/pull/4920) Svelted some our builds a bit (3KB savings) +- [#4919](https://github.com/emberjs/data/pull/4919) [DOC] Fix findHasMany parameter order +- [#4925](https://github.com/emberjs/data/pull/4925) [SVELTE] rollup -private for winnings +- [#4924](https://github.com/emberjs/data/pull/4924) [PERF] Model.prototype.didDefineProperty only in dev +- [#4943](https://github.com/emberjs/data/pull/4943) hash-for-dep only the plugin (not all of ember-data) as this plugin h… +- [#4928](https://github.com/emberjs/data/pull/4928) Don't use `let` or `const` +- [#4926](https://github.com/emberjs/data/pull/4926) [DOC release] Add missing ` in urlsForFindMany description +- [#4930](https://github.com/emberjs/data/pull/4930) Remove no-longer-working private API usage. +- [#4932](https://github.com/emberjs/data/pull/4932) update yarn.lock +- [#4936](https://github.com/emberjs/data/pull/4936) [SVELTE] Transforms & remove Date.parse polyfill (#4936) +- [#4937](https://github.com/emberjs/data/pull/4937) [BUGFIX beta] Update dependencies to use Babel 6. +- [#4941](https://github.com/emberjs/data/pull/4941) only coerce non-string id's +- [#4946](https://github.com/emberjs/data/pull/4946) dummy app routes should work with and without heimdall +- [#4948](https://github.com/emberjs/data/pull/4948) Only will merge mixin in dev +- [#4950](https://github.com/emberjs/data/pull/4950) [PERF] Guard against poorly optimized babel output + ### Release 2.13.2 (June 18, 2017) - [#5012](https://github.com/emberjs/data/pull/5012) [BUGFIX release] fixes an issue with sync dematerialization followed by a findRecord, adds test coverage From ae6250b513c05ccec5a7343376c0acab0205bd78 Mon Sep 17 00:00:00 2001 From: bmac Date: Sun, 18 Jun 2017 09:12:44 -0400 Subject: [PATCH 1951/2527] Bump version on master branch --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d8c115eb908..6d75f7e999d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.15.0-canary", + "version": "2.16.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From 93e4d65b750d26fcd03f729a1f499454a1712b6b Mon Sep 17 00:00:00 2001 From: Simon Ihmig Date: Sun, 18 Jun 2017 22:45:49 +0200 Subject: [PATCH 1952/2527] [BUGFIX beta] Fix flushing of pending saves, that include a deleted record (#4994) Fixes #4993 --- addon/-private/system/store.js | 3 ++- .../integration/records/delete-record-test.js | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 0c45cae4d15..4db47aa8551 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1874,7 +1874,8 @@ Store = Service.extend({ let operation; if (internalModel.currentState.stateName === 'root.deleted.saved') { - return resolver.resolve(); + resolver.resolve(); + continue; } else if (internalModel.isNew()) { operation = 'createRecord'; } else if (internalModel.isDeleted()) { diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index f877e09ca28..a96a7901da6 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -289,3 +289,29 @@ test("Destroying an invalid newly created record should remove it from the store assert.equal(get(record, 'currentState.stateName'), 'root.deleted.saved'); assert.equal(get(store.peekAll('person'), 'length'), 0, 'The new person should be removed from the store'); }); + +test("Will resolve destroy and save in same loop", function(assert) { + let adam, dave; + let promises; + + assert.expect(1); + + env.adapter.createRecord = function() { + assert.ok(true, 'save operation resolves'); + return Ember.RSVP.Promise.resolve({ id: 123 }); + }; + + run(function() { + adam = env.store.createRecord('person', { name: 'Adam Sunderland' }); + dave = env.store.createRecord('person', { name: 'Dave Sunderland' }); + }); + + run(function() { + promises = [ + adam.destroyRecord(), + dave.save() + ]; + }); + + return Ember.RSVP.all(promises); +}); From ac019218465456991119089cf32482f09f3db898 Mon Sep 17 00:00:00 2001 From: Ahmad Suhendri Date: Mon, 19 Jun 2017 17:41:33 +0700 Subject: [PATCH 1953/2527] Use https in references to emberjs website (#4992) --- CHANGELOG.md | 6 +++--- CODE_OF_CONDUCT.md | 2 +- CONTRIBUTING.md | 2 +- FEATURES.md | 2 +- README.md | 8 ++++---- addon/-private/system/model/model.js | 6 +++--- addon/-private/system/relationships/belongs-to.js | 4 ++-- addon/-private/system/store.js | 8 ++++---- addon/-private/system/store/finders.js | 2 +- addon/serializers/json-api.js | 2 +- blueprints/model/index.js | 2 +- tests/integration/inverse-test.js | 2 +- 12 files changed, 23 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fda0db2b53..06f35f52541 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -634,7 +634,7 @@ ### Release 2.3.0 (January 12, 2016) Ember Data 2.3 is now published as and Ember CLI addon in addition to a bower package. -See the [release notes](http://emberjs.com/blog/2016/01/12/ember-data-2-3-released.html#toc_changes-in-ember-data-2-3) +See the [release notes](https://emberjs.com/blog/2016/01/12/ember-data-2-3-released.html#toc_changes-in-ember-data-2-3) for instruction on how to upgrade your Ember CLI project to take advantage of the Ember Data addon. - [#4039](https://github.com/emberjs/data/pull/4039) Replace calls to store.find with store.findRecord @@ -1242,7 +1242,7 @@ post.constructor.typeKey => postSnapshot.typeKey If you need to access the underlying record of a snapshot you can do so by accessing `snapshot.record`. -The full API reference of `DS.Snapshot` can be found [here](http://emberjs.com/api/data/classes/DS.Snapshot.html). +The full API reference of `DS.Snapshot` can be found [here](https://emberjs.com/api/data/classes/DS.Snapshot.html). #### Changes * Do not re-add deleted records to a hasMany relationship @@ -1475,7 +1475,7 @@ to set metadata. ##### `ManyArray`s are no longer `RecordArray`s -[ManyArray](http://emberjs.com/api/data/classes/DS.ManyArray.html), +[ManyArray](https://emberjs.com/api/data/classes/DS.ManyArray.html), the object Ember Data uses to represent `DS.hasMany` relationships has been changed so it no longer extends from `RecordArray`. This means if you were relying on the RecordArray's `content` property to access the diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 98fe2cd0aa8..aa49557b09f 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,7 +2,7 @@ The Ember team and community are committed to everyone having a safe and inclusi **Our Community Guidelines / Code of Conduct can be found here**: -http://emberjs.com/guidelines/ +https://emberjs.com/guidelines/ For a history of updates, see the page history here: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c35c9bfdfac..bea9a49688b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -226,7 +226,7 @@ Documentation commits are tagged as `[DOC channel]` where channel is `canary`, ### Security -Security commits will be tagged as `[SECURITY cve]`. Please do not submit security related PRs without coordinating with the security team. See the [Security Policy](http://emberjs.com/security/) for more information. +Security commits will be tagged as `[SECURITY cve]`. Please do not submit security related PRs without coordinating with the security team. See the [Security Policy](https://emberjs.com/security/) for more information. ### Other diff --git a/FEATURES.md b/FEATURES.md index 77fd5be66b8..19c8a44abdf 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -1,6 +1,6 @@ ## About Features -Please read the [Feature Flag Guide](http://emberjs.com/guides/configuring-ember/feature-flags/) +Please read the [Feature Flag Guide](https://emberjs.com/guides/configuring-ember/feature-flags/) for a detailed explanation. To add a new feature flag or change an existing one, you can add an diff --git a/README.md b/README.md index 5ccebcb641f..5556eb046aa 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,10 @@ bower install ember-data --save ``` The latest passing build from the "master" branch is available on -[http://emberjs.com/builds/#/canary](http://emberjs.com/builds/#/canary). +[https://emberjs.com/builds/#/canary](https://emberjs.com/builds/#/canary). Similarly, the latest passing build from the "beta" branch can be found -on [http://emberjs.com/builds/#/beta](http://emberjs.com/builds/#/beta) +on [https://emberjs.com/builds/#/beta](https://emberjs.com/builds/#/beta) Or build ember-data.js yourself. Clone the repository and run `npm run build:production` after [setup](#setup). You'll find ember-data.js in the `dist` directory. @@ -142,7 +142,7 @@ By default, Ember Data will use the `JSONAPIAdapter`, which adheres to the [JSON To learn more about adapters, including what conventions the various adapters follow and how to build your own, see the Ember.js -Guides: [Customizing Adapters](http://emberjs.com/guides/models/customizing-adapters). +Guides: [Customizing Adapters](https://emberjs.com/guides/models/customizing-adapters). ### Fetching a Collection of Models @@ -167,7 +167,7 @@ promise will be rejected. ### Even More Documentation For much more detail on how to use Ember Data, see the [Ember.js Guides -on models](http://emberjs.com/guides/models/). +on models](https://emberjs.com/guides/models/). # Building Ember Data diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 17c9466f3a6..354bd46cdd9 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1315,7 +1315,7 @@ Model.reopenClass({ } else { //No inverse was specified manually, we need to use a heuristic to guess one if (propertyMeta.parentType && propertyMeta.type === propertyMeta.parentType.modelName) { - warn(`Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at http://emberjs.com/guides/models/defining-models/#toc_reflexive-relation for how to explicitly specify inverses.`, false, { + warn(`Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at https://emberjs.com/guides/models/defining-models/#toc_reflexive-relation for how to explicitly specify inverses.`, false, { id: 'ds.model.reflexive-relationship-without-inverse' }); } @@ -1330,7 +1330,7 @@ Model.reopenClass({ }); assert("You defined the '" + name + "' relationship on " + this + ", but you defined the inverse relationships of type " + - inverseType.toString() + " multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", + inverseType.toString() + " multiple times. Look at https://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", filteredRelationships.length < 2); if (filteredRelationships.length === 1 ) { @@ -1338,7 +1338,7 @@ Model.reopenClass({ } assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + - this + " were found on " + inverseType + ". Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", + this + " were found on " + inverseType + ". Look at https://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", possibleRelationships.length === 1); inverseName = possibleRelationships[0].name; diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 13f2dc20389..445d01ffb4e 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -104,13 +104,13 @@ export default function belongsTo(modelName, options) { return Ember.computed({ get(key) { if (opts.hasOwnProperty('serialize')) { - warn(`You provided a serialize option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.Serializer and it's implementations http://emberjs.com/api/data/classes/DS.Serializer.html`, false, { + warn(`You provided a serialize option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.Serializer and it's implementations https://emberjs.com/api/data/classes/DS.Serializer.html`, false, { id: 'ds.model.serialize-option-in-belongs-to' }); } if (opts.hasOwnProperty('embedded')) { - warn(`You provided an embedded option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html`, false, { + warn(`You provided an embedded option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin https://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html`, false, { id: 'ds.model.embedded-option-in-belongs-to' }); } diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 4db47aa8551..6deb6c86406 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -642,7 +642,7 @@ Store = Service.extend({ ### Retrieving Related Model Records If you use an adapter such as Ember's default - [`JSONAPIAdapter`](http://emberjs.com/api/data/classes/DS.JSONAPIAdapter.html) + [`JSONAPIAdapter`](https://emberjs.com/api/data/classes/DS.JSONAPIAdapter.html) that supports the [JSON API specification](http://jsonapi.org/) and if your server endpoint supports the use of an ['include' query parameter](http://jsonapi.org/format/#fetching-includes), @@ -1249,7 +1249,7 @@ Store = Service.extend({ ``` This method returns a promise, which is resolved with an - [`AdapterPopulatedRecordArray`](http://emberjs.com/api/data/classes/DS.AdapterPopulatedRecordArray.html) + [`AdapterPopulatedRecordArray`](https://emberjs.com/api/data/classes/DS.AdapterPopulatedRecordArray.html) once the server returns. @since 1.13.0 @@ -1551,7 +1551,7 @@ Store = Service.extend({ ### Retrieving Related Model Records If you use an adapter such as Ember's default - [`JSONAPIAdapter`](http://emberjs.com/api/data/classes/DS.JSONAPIAdapter.html) + [`JSONAPIAdapter`](https://emberjs.com/api/data/classes/DS.JSONAPIAdapter.html) that supports the [JSON API specification](http://jsonapi.org/) and if your server endpoint supports the use of an ['include' query parameter](http://jsonapi.org/format/#fetching-includes), @@ -2067,7 +2067,7 @@ Store = Service.extend({ The class of a model might be useful if you want to get a list of all the relationship names of the model, see - [`relationshipNames`](http://emberjs.com/api/data/classes/DS.Model.html#property_relationshipNames) + [`relationshipNames`](https://emberjs.com/api/data/classes/DS.Model.html#property_relationshipNames) for example. @method modelFor diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index ab5a530636b..30c57ffe73f 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -34,7 +34,7 @@ export function _find(adapter, store, modelClass, id, internalModel, options) { let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, id, 'findRecord'); assert(`Ember Data expected the primary data returned from a 'findRecord' response to be an object but instead it found an array.`, !Array.isArray(payload.data)); - warn(`You requested a record of type '${modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead http://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, payload.data.id === id, { + warn(`You requested a record of type '${modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead https://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, payload.data.id === id, { id: 'ds.store.findRecord.id-mismatch' }); diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 678766c36dc..19ca539bb1e 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -740,7 +740,7 @@ if (DEBUG) { JSONAPISerializer.reopen({ willMergeMixin(props) { let constructor = this.constructor; - warn(`You've defined 'extractMeta' in ${constructor.toString()} which is not used for serializers extending JSONAPISerializer. Read more at http://emberjs.com/api/data/classes/DS.JSONAPISerializer.html#toc_customizing-meta on how to customize meta when using JSON API.`, Ember.isNone(props.extractMeta) || props.extractMeta === JSONSerializer.prototype.extractMeta, { + warn(`You've defined 'extractMeta' in ${constructor.toString()} which is not used for serializers extending JSONAPISerializer. Read more at https://emberjs.com/api/data/classes/DS.JSONAPISerializer.html#toc_customizing-meta on how to customize meta when using JSON API.`, Ember.isNone(props.extractMeta) || props.extractMeta === JSONSerializer.prototype.extractMeta, { id: 'ds.serializer.json-api.extractMeta' }); warn('The JSONAPISerializer does not work with the EmbeddedRecordsMixin because the JSON API spec does not describe how to format embedded resources.', !props.isEmbeddedRecordsMixin, { diff --git a/blueprints/model/index.js b/blueprints/model/index.js index 6f19377212c..6f49c9a3a6a 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -70,7 +70,7 @@ function dsAttr(name, type) { return 'DS.hasMany(\'' + name + '\')'; case '': //"If you don't specify the type of the attribute, it will be whatever was provided by the server" - //http://emberjs.com/guides/models/defining-models/ + //https://emberjs.com/guides/models/defining-models/ return 'DS.attr()'; default: return 'DS.attr(\'' + type + '\')'; diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index 1b9a74beb47..a584b3f7c37 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -111,7 +111,7 @@ testInDebug("Errors out if you define 2 inverses to the same model", function(as assert.expectAssertion(function() { User.inverseFor('job', store); - }, "You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses"); + }, "You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times. Look at https://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses"); }); From b1bacb83e243479667d7b0554a51e1190a9df80e Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 22 Jun 2017 14:39:53 -0700 Subject: [PATCH 1954/2527] loosen header parsing slightly --- addon/-private/utils/parse-response-headers.js | 2 +- tests/unit/utils/parse-response-headers-test.js | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/addon/-private/utils/parse-response-headers.js b/addon/-private/utils/parse-response-headers.js index 34d853a4040..3e02ab16fc8 100644 --- a/addon/-private/utils/parse-response-headers.js +++ b/addon/-private/utils/parse-response-headers.js @@ -21,7 +21,7 @@ export default function parseResponseHeaders(headersString) { } if (foundSep === false) { - break; + continue; } let field = header.substring(0, j).trim(); diff --git a/tests/unit/utils/parse-response-headers-test.js b/tests/unit/utils/parse-response-headers-test.js index b7c246cd284..d706a7b91d4 100644 --- a/tests/unit/utils/parse-response-headers-test.js +++ b/tests/unit/utils/parse-response-headers-test.js @@ -52,15 +52,26 @@ test('field-value parsing', function(assert) { assert.equal(headers['value-with-colon'], 'value with: a colon', 'has correct value when value contains a colon'); assert.equal(headers['value-with-trailing-whitespace'], 'banana', 'strips trailing whitespace from field-value'); }); +"\r\nfoo: bar" test('ignores headers that do not contain a colon', function(assert) { let headersString = [ 'Content-Encoding: gzip', - 'I am ignored because I do not contain a colon' + 'I am ignored because I do not contain a colon', + 'apple: pie' ].join(CRLF); let headers = parseResponseHeaders(headersString); assert.deepEqual(headers['Content-Encoding'], 'gzip', 'parses basic header pair'); + assert.deepEqual(headers['apple'], 'pie', 'parses basic header pair'); + assert.equal(Object.keys(headers).length, 2, 'only has the one valid header'); +}); + +test('tollerate extra new-lines', function(assert) { + let headersString = CRLF + 'foo: bar'; + let headers = parseResponseHeaders(headersString); + + assert.deepEqual(headers['foo'], 'bar', 'parses basic header pair'); assert.equal(Object.keys(headers).length, 1, 'only has the one valid header'); }); From 3d8eb090860f1971b0d0f9fc98b7439d204f1d6d Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 22 Jun 2017 14:52:03 -0700 Subject: [PATCH 1955/2527] fix build --- tests/integration/records/delete-record-test.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index a96a7901da6..fe3ab6b3f58 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -298,7 +298,12 @@ test("Will resolve destroy and save in same loop", function(assert) { env.adapter.createRecord = function() { assert.ok(true, 'save operation resolves'); - return Ember.RSVP.Promise.resolve({ id: 123 }); + return Ember.RSVP.Promise.resolve({ + data: { + id: 123, + type: 'person' + } + }); }; run(function() { From 17bf1b77275a764fe605e096b93f0482188ec029 Mon Sep 17 00:00:00 2001 From: Ryunosuke Sato Date: Sun, 25 Jun 2017 05:17:00 +0900 Subject: [PATCH 1956/2527] [BUGFIX release] Fix global build (#5035) The global build of ember-data has been broken since https://github.com/emberjs/data/pull/4823. When `ember-data.js` is loaded, the following error is occured: ``` Uncaught Error: Could not find module `ember-data/index` imported from `ember-data/initializers/ember-data` ``` A reproduction code is just simple: ```

      Hello, Ember!

      ``` The reason of this error is that the broccoli builds the module named "*/index" into `*` for global build. But loader.js couldn't resolve `ember-data/index` as `ember-data`. So the `ember-data/index` module should be to as just `ember-data` to be compatible with NPM package and global. --- app/initializers/ember-data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/initializers/ember-data.js b/app/initializers/ember-data.js index 2694ebad115..ba03dbbc552 100644 --- a/app/initializers/ember-data.js +++ b/app/initializers/ember-data.js @@ -1,5 +1,5 @@ import setupContainer from 'ember-data/setup-container'; -import 'ember-data/index'; +import 'ember-data'; /* From 5cda4009aadd9d1e61a88dad7f54e69150fbba02 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Sat, 24 Jun 2017 13:18:43 -0700 Subject: [PATCH 1957/2527] Ensure `ember-data/-private` module is emitted properly for ember-cli < 2.12. (#5031) ember-cli@2.12 and higher have the addon itself responsible for transpiling modules so that the output of the `treeForAddon` hook is expected to be AMD. Prior versions of ember-cli (i.e. < 2.12) do second pass (that is not possible to disable) to transpile the output of `treeForAddon` **again** (to transpile modules). This commit changes things around leveraging ember-cli-babel@6's built in ability to detect the various ember-cli version scenarios and either transpile `ember-data/-private` down to AMD or not correctly. --- index.js | 22 +- package.json | 3 +- yarn.lock | 984 ++++++++++++++++++--------------------------------- 3 files changed, 370 insertions(+), 639 deletions(-) diff --git a/index.js b/index.js index e89578dd8bf..de266d8599d 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,7 @@ const Babel = require('broccoli-babel-transpiler'); const merge = require('broccoli-merge-trees'); const semver = require('semver'); const version = require('./lib/version'); +const BroccoliDebug = require('broccoli-debug'); // allow toggling of heimdall instrumentation let INSTRUMENT_HEIMDALL = false; @@ -52,6 +53,8 @@ module.exports = { init() { this._super.init && this._super.init.apply(this, arguments); + this.debugTree = BroccoliDebug.buildDebugCallback('ember-data'); + let bowerDeps = this.project.bowerDependencies(); let VersionChecker = require('ember-cli-version-checker'); @@ -113,6 +116,8 @@ module.exports = { treeForAddon(tree) { if (this._forceBowerUsage) { return NOOP_TREE(tree); } + tree = this.debugTree(tree, 'input'); + let babel = this.addons.find(addon => addon.name === 'ember-cli-babel'); let treeWithVersion = merge([ @@ -130,21 +135,25 @@ module.exports = { destDir: 'ember-data' }); - let privateTree = babel.transpileTree(withPrivate, { + let privateTree = babel.transpileTree(this.debugTree(withPrivate, 'babel-private:input'), { babel: this.buildBabelOptions(), 'ember-cli-babel': { compileModules: false } }); + privateTree = this.debugTree(privateTree, 'babel-private:output'); + // use the default options - let publicTree = babel.transpileTree(withoutPrivate); + let publicTree = babel.transpileTree(this.debugTree(withoutPrivate, 'babel-public:input')); + + publicTree = this.debugTree(publicTree, 'babel-public:output'); privateTree = new Rollup(privateTree, { rollup: { entry: '-private/index.js', targets: [ - { dest: '-private.js', format: 'amd', moduleId: 'ember-data/-private' } + { dest: 'ember-data/-private.js', format: babel.shouldCompileModules() ? 'amd' : 'es', moduleId: 'ember-data/-private' } ], external: [ 'ember', @@ -157,14 +166,16 @@ module.exports = { } }); + privateTree = this.debugTree(privateTree, 'rollup-output'); + // the output of treeForAddon is required to be modules/ publicTree = new Funnel(publicTree, { destDir: 'modules' }); privateTree = new Funnel(privateTree, { destDir: 'modules' }); - return merge([ + return this.debugTree(merge([ publicTree, privateTree - ]); + ]), 'final'); }, buildBabelOptions() { @@ -204,3 +215,4 @@ module.exports = { } } }; + diff --git a/package.json b/package.json index 6d75f7e999d..82a89695ffc 100644 --- a/package.json +++ b/package.json @@ -26,12 +26,13 @@ "babel6-plugin-strip-class-callcheck": "^6.0.0", "babel6-plugin-strip-heimdall": "^6.0.1", "broccoli-babel-transpiler": "^6.0.0", + "broccoli-debug": "^0.6.2", "broccoli-file-creator": "^1.0.0", "broccoli-funnel": "^1.2.0", "broccoli-merge-trees": "^1.0.0", "broccoli-rollup": "^1.2.0", "chalk": "^1.1.1", - "ember-cli-babel": "^6.1.0", + "ember-cli-babel": "^6.4.1", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.0.0", "ember-cli-test-info": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 204f6b4deae..9972e81fe64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,16 +3,16 @@ "@types/node@*", "@types/node@^7.0.5": - version "7.0.14" - resolved "https://registry.npmjs.org/@types/node/-/node-7.0.14.tgz#1470fa002a113316ac9d9ad163fc738c7a0de2a4" + version "7.0.32" + resolved "https://registry.npmjs.org/@types/node/-/node-7.0.32.tgz#6afe6c66520a4c316623a14aef123908d01b4bba" "@types/rimraf@^0.0.28": version "0.0.28" resolved "https://registry.npmjs.org/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06" "@types/tape@^4.2.29": - version "4.2.29" - resolved "https://registry.npmjs.org/@types/tape/-/tape-4.2.29.tgz#14cf2eb49bf852407eaaefdc53773eb90b32cf56" + version "4.2.30" + resolved "https://registry.npmjs.org/@types/tape/-/tape-4.2.30.tgz#3c1917c4dfd6f27271b9922772513515bc6c46b4" dependencies: "@types/node" "*" @@ -44,8 +44,8 @@ acorn@^3.0.4: resolved "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" acorn@^4.0.3: - version "4.0.11" - resolved "https://registry.npmjs.org/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0" + version "4.0.13" + resolved "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" acorn@^5.0.1: version "5.0.3" @@ -60,8 +60,8 @@ after@0.8.1: resolved "https://registry.npmjs.org/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" agent-base@2: - version "2.0.1" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz#bd8f9e86a8eb221fffa07bd14befd55df142815e" + version "2.1.1" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" dependencies: extend "~3.0.0" semver "~5.0.1" @@ -139,8 +139,8 @@ anymatch@^1.3.0: micromatch "^2.1.5" aproba@^1.0.3: - version "1.1.1" - resolved "https://registry.npmjs.org/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" + version "1.1.2" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" are-we-there-yet@~1.1.2: version "1.1.4" @@ -209,22 +209,10 @@ asn1@0.1.11: version "0.1.11" resolved "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" -asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - assert-plus@^0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - assertion-error@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" @@ -246,8 +234,8 @@ ast-types@0.9.6: resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" async-disk-cache@^1.2.1: - version "1.3.1" - resolved "https://registry.npmjs.org/async-disk-cache/-/async-disk-cache-1.3.1.tgz#3394010d9448b16205b01e0e2e704180805413d3" + version "1.3.2" + resolved "https://registry.npmjs.org/async-disk-cache/-/async-disk-cache-1.3.2.tgz#ac53d6152843df202c9406e28d774362608d74dd" dependencies: debug "^2.1.3" heimdalljs "^0.2.3" @@ -255,6 +243,7 @@ async-disk-cache@^1.2.1: mkdirp "^0.5.0" rimraf "^2.5.3" rsvp "^3.0.18" + username-sync "1.0.1" async@^1.4.0, async@^1.5.2: version "1.5.2" @@ -268,15 +257,11 @@ async@~0.9.0: version "0.9.2" resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - aws-sdk@^2.0.9: - version "2.48.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.48.0.tgz#c89bbdbd71fdd33457cd65c46c4080e4e44b2702" + version "2.75.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.75.0.tgz#f78802e46f95b7044a094da259057dd8d5d8da17" dependencies: - buffer "4.9.1" + buffer "5.0.6" crypto-browserify "1.0.9" jmespath "0.15.0" querystring "0.2.0" @@ -290,14 +275,6 @@ aws-sign2@~0.5.0: version "0.5.0" resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - -aws4@^1.2.1: - version "1.6.0" - resolved "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" - babel-code-frame@^6.22.0: version "6.22.0" resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" @@ -358,19 +335,19 @@ babel-core@^5.0.0, babel-core@^5.8.22: try-resolve "^1.0.0" babel-core@^6.14.0, babel-core@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-core/-/babel-core-6.24.1.tgz#8c428564dce1e1f41fb337ec34f4c3b022b5ad83" + version "6.25.0" + resolved "https://registry.npmjs.org/babel-core/-/babel-core-6.25.0.tgz#7dd42b0463c742e9d5296deb3ec67a9322dad729" dependencies: babel-code-frame "^6.22.0" - babel-generator "^6.24.1" + babel-generator "^6.25.0" babel-helpers "^6.24.1" babel-messages "^6.23.0" babel-register "^6.24.1" babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - babylon "^6.11.0" + babel-template "^6.25.0" + babel-traverse "^6.25.0" + babel-types "^6.25.0" + babylon "^6.17.2" convert-source-map "^1.1.0" debug "^2.1.1" json5 "^0.5.0" @@ -381,13 +358,13 @@ babel-core@^6.14.0, babel-core@^6.24.1: slash "^1.0.0" source-map "^0.5.0" -babel-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-generator/-/babel-generator-6.24.1.tgz#e715f486c58ded25649d888944d52aa07c5d9497" +babel-generator@^6.25.0: + version "6.25.0" + resolved "https://registry.npmjs.org/babel-generator/-/babel-generator-6.25.0.tgz#33a1af70d5f2890aeb465a4a7793c1df6a9ea9fc" dependencies: babel-messages "^6.23.0" babel-runtime "^6.22.0" - babel-types "^6.24.1" + babel-types "^6.25.0" detect-indent "^4.0.0" jsesc "^1.3.0" lodash "^4.2.0" @@ -515,9 +492,9 @@ babel-plugin-dead-code-elimination@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" -babel-plugin-debug-macros@^0.1.6, babel-plugin-debug-macros@^0.1.7: - version "0.1.7" - resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.7.tgz#69f5a3dc7d72f781354f18c611a3b007bb223511" +babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.7: + version "0.1.10" + resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.10.tgz#dd077ad6e1cc0a8f9bbc6405c561392ebfc9a01c" dependencies: semver "^5.3.0" @@ -812,9 +789,9 @@ babel-polyfill@^6.16.0: core-js "^2.4.0" regenerator-runtime "^0.10.0" -babel-preset-env@^1.2.0: - version "1.4.0" - resolved "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.4.0.tgz#c8e02a3bcc7792f23cded68e0355b9d4c28f0f7a" +babel-preset-env@^1.5.1: + version "1.5.2" + resolved "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.5.2.tgz#cd4ae90a6e94b709f97374b33e5f8b983556adef" dependencies: babel-plugin-check-es2015-constants "^6.22.0" babel-plugin-syntax-trailing-function-commas "^6.22.0" @@ -843,8 +820,9 @@ babel-preset-env@^1.2.0: babel-plugin-transform-es2015-unicode-regex "^6.22.0" babel-plugin-transform-exponentiation-operator "^6.22.0" babel-plugin-transform-regenerator "^6.22.0" - browserslist "^1.4.0" + browserslist "^2.1.2" invariant "^2.2.2" + semver "^5.3.0" babel-register@^6.24.1: version "6.24.1" @@ -871,33 +849,33 @@ babel-runtime@^6.18.0, babel-runtime@^6.22.0: core-js "^2.4.0" regenerator-runtime "^0.10.0" -babel-template@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-template/-/babel-template-6.24.1.tgz#04ae514f1f93b3a2537f2a0f60a5a45fb8308333" +babel-template@^6.24.1, babel-template@^6.25.0: + version "6.25.0" + resolved "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz#665241166b7c2aa4c619d71e192969552b10c071" dependencies: babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - babylon "^6.11.0" + babel-traverse "^6.25.0" + babel-types "^6.25.0" + babylon "^6.17.2" lodash "^4.2.0" -babel-traverse@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.24.1.tgz#ab36673fd356f9a0948659e7b338d5feadb31695" +babel-traverse@^6.24.1, babel-traverse@^6.25.0: + version "6.25.0" + resolved "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz#2257497e2fcd19b89edc13c4c91381f9512496f1" dependencies: babel-code-frame "^6.22.0" babel-messages "^6.23.0" babel-runtime "^6.22.0" - babel-types "^6.24.1" - babylon "^6.15.0" + babel-types "^6.25.0" + babylon "^6.17.2" debug "^2.2.0" globals "^9.0.0" invariant "^2.2.0" lodash "^4.2.0" -babel-types@^6.19.0, babel-types@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-types/-/babel-types-6.24.1.tgz#a136879dc15b3606bda0d90c1fc74304c2ff0975" +babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.25.0: + version "6.25.0" + resolved "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz#70afb248d5660e5d18f811d91c8303b54134a18e" dependencies: babel-runtime "^6.22.0" esutils "^2.0.2" @@ -916,9 +894,9 @@ babylon@^5.8.38: version "5.8.38" resolved "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" -babylon@^6.11.0, babylon@^6.15.0: - version "6.17.0" - resolved "https://registry.npmjs.org/babylon/-/babylon-6.17.0.tgz#37da948878488b9c4e3c4038893fa3314b3fc932" +babylon@^6.17.2: + version "6.17.4" + resolved "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz#3e8b7402b88d22c3423e137a1577883b15ff869a" backbone@^1.1.2: version "1.3.3" @@ -930,17 +908,17 @@ backo2@1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" -balanced-match@^0.4.1: - version "0.4.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" base64-arraybuffer@0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" base64-js@^1.0.2: - version "1.2.0" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + version "1.2.1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" base64id@0.1.0: version "0.1.0" @@ -950,12 +928,6 @@ basic-auth@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" -bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - dependencies: - tweetnacl "^0.14.3" - better-assert@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" @@ -983,19 +955,19 @@ bluebird@^3.1.1, bluebird@^3.4.6: resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" body-parser@^1.15.2: - version "1.17.1" - resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.17.1.tgz#75b3bc98ddd6e7e0d8ffe750dfaca5c66993fa47" + version "1.17.2" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.17.2.tgz#f8892abc8f9e627d42aedafbca66bf5ab99104ee" dependencies: bytes "2.4.0" content-type "~1.0.2" - debug "2.6.1" + debug "2.6.7" depd "~1.1.0" http-errors "~1.6.1" iconv-lite "0.4.15" on-finished "~2.3.0" qs "6.4.0" raw-body "~2.2.0" - type-is "~1.6.14" + type-is "~1.6.15" body@^5.1.0: version "5.1.0" @@ -1012,12 +984,6 @@ boom@0.4.x: dependencies: hoek "0.9.x" -boom@2.x.x: - version "2.10.1" - resolved "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - dependencies: - hoek "2.x.x" - bower-config@^1.3.0: version "1.4.0" resolved "https://registry.npmjs.org/bower-config/-/bower-config-1.4.0.tgz#16c38c1135f8071c19f25938d61b0d8cbf18d3f1" @@ -1032,15 +998,15 @@ bower-endpoint-parser@0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" -bower@^1.6.5: +bower@^1.6.5, bower@^1.8.0: version "1.8.0" resolved "https://registry.npmjs.org/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a" -brace-expansion@^1.0.0: - version "1.1.7" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" +brace-expansion@^1.0.0, brace-expansion@^1.1.7: + version "1.1.8" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" dependencies: - balanced-match "^0.4.1" + balanced-match "^1.0.0" concat-map "0.0.1" braces@^1.8.2: @@ -1071,18 +1037,6 @@ broccoli-asset-rewrite@^1.1.0: dependencies: broccoli-filter "^1.2.3" -broccoli-babel-transpiler@6.0.0-alpha.3: - version "6.0.0-alpha.3" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.0.0-alpha.3.tgz#4c46c800753242cc4109c44700db63dc3862d7d0" - dependencies: - babel-core "^6.14.0" - broccoli-funnel "^1.0.0" - broccoli-merge-trees "^1.0.0" - broccoli-persistent-filter "^1.0.1" - clone "^2.0.0" - hash-for-dep "^1.0.2" - json-stable-stringify "^1.0.0" - broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: version "5.6.2" resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.6.2.tgz#958c72e43575b2f0a862a5096dba1ce1ebc7d74d" @@ -1114,8 +1068,8 @@ broccoli-brocfile-loader@^0.18.0: findup-sync "^0.4.2" broccoli-builder@^0.18.3: - version "0.18.4" - resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.4.tgz#abc6db2c07d214454918e2997ea87441b69b69d3" + version "0.18.5" + resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.5.tgz#fb09687d99b869942e4405a2e4f4499272cfc5f2" dependencies: heimdalljs "^0.2.0" promise-map-series "^0.2.1" @@ -1124,29 +1078,29 @@ broccoli-builder@^0.18.3: rsvp "^3.0.17" silent-error "^1.0.1" -broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.1: - version "2.0.4" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" +broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" - lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - symlink-or-copy "^1.0.0" - walk-sync "^0.2.0" + walk-sync "^0.2.5" -broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" +broccoli-caching-writer@~2.0.1: + version "2.0.4" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" + lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - walk-sync "^0.2.5" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" broccoli-clean-css@^1.1.0: version "1.1.0" @@ -1202,6 +1156,18 @@ broccoli-config-replace@^1.1.2: debug "^2.2.0" fs-extra "^0.24.0" +broccoli-debug@^0.6.1, broccoli-debug@^0.6.2: + version "0.6.2" + resolved "https://registry.npmjs.org/broccoli-debug/-/broccoli-debug-0.6.2.tgz#4c6e89459fc3de7d5d4fc7b77e57f46019f44db1" + dependencies: + broccoli-plugin "^1.2.1" + fs-tree-diff "^0.5.2" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + minimatch "^3.0.3" + symlink-or-copy "^1.1.8" + tree-sync "^1.2.2" + broccoli-file-creator@^1.0.0: version "1.1.1" resolved "https://registry.npmjs.org/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" @@ -1304,8 +1270,8 @@ broccoli-merge-trees@~0.2.3: symlink-or-copy "^1.0.0" broccoli-middleware@^1.0.0-beta.8: - version "1.0.0-beta.8" - resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-1.0.0-beta.8.tgz#89cb6a9950ff0cf5bd75071d83d7cd6f6a11a95b" + version "1.0.0-beta.11" + resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-1.0.0-beta.11.tgz#5f633276c7905d2debf6fb78b18291f560fd4ba1" dependencies: handlebars "^4.0.4" mime "^1.2.11" @@ -1347,8 +1313,8 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli symlink-or-copy "^1.1.8" broccoli-rollup@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/broccoli-rollup/-/broccoli-rollup-1.2.0.tgz#627636c05837d894a85724ef9b7ca04d12b66751" + version "1.3.0" + resolved "https://registry.npmjs.org/broccoli-rollup/-/broccoli-rollup-1.3.0.tgz#43a0a7798555bab54217009eb470a4ff5a056df0" dependencies: broccoli-plugin "^1.2.1" es6-map "^0.1.4" @@ -1383,9 +1349,10 @@ broccoli-sri-hash@^2.1.0: symlink-or-copy "^1.0.1" broccoli-stew@^1.2.0, broccoli-stew@^1.3.3, broccoli-stew@^1.4.2: - version "1.4.2" - resolved "https://registry.npmjs.org/broccoli-stew/-/broccoli-stew-1.4.2.tgz#9ec4062fd7162c6026561a2fbf64558363aff8d6" + version "1.5.0" + resolved "https://registry.npmjs.org/broccoli-stew/-/broccoli-stew-1.5.0.tgz#d7af8c18511dce510e49d308a62e5977f461883c" dependencies: + broccoli-debug "^0.6.1" broccoli-funnel "^1.0.1" broccoli-merge-trees "^1.0.0" broccoli-persistent-filter "^1.1.6" @@ -1397,7 +1364,6 @@ broccoli-stew@^1.2.0, broccoli-stew@^1.3.3, broccoli-stew@^1.4.2: minimatch "^3.0.2" resolve "^1.1.6" rsvp "^3.0.16" - sanitize-filename "^1.5.3" symlink-or-copy "^1.1.8" walk-sync "^0.3.0" @@ -1439,30 +1405,25 @@ broccoli-yuidoc@^2.1.0: rsvp "~3.1.0" yuidocjs "~0.9.0" -browserslist@^1.4.0: - version "1.7.7" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" +browserslist@^2.1.2: + version "2.1.5" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-2.1.5.tgz#e882550df3d1cd6d481c1a3e0038f2baf13a4711" dependencies: - caniuse-db "^1.0.30000639" - electron-to-chromium "^1.2.7" + caniuse-lite "^1.0.30000684" + electron-to-chromium "^1.3.14" -bser@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169" +bser@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" dependencies: node-int64 "^0.4.0" -buffer-shims@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" - -buffer@4.9.1: - version "4.9.1" - resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" +buffer@5.0.6: + version "5.0.6" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.0.6.tgz#2ea669f7eec0b6eda05b08f8b5ff661b28573588" dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" - isarray "^1.0.0" builtin-modules@^1.0.0: version "1.1.1" @@ -1518,9 +1479,9 @@ can-symlink@^1.0.0: dependencies: tmp "0.0.28" -caniuse-db@^1.0.30000639: - version "1.0.30000664" - resolved "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000664.tgz#e16316e5fdabb9c7209b2bf0744ffc8a14201f22" +caniuse-lite@^1.0.30000684: + version "1.0.30000693" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000693.tgz#c9c6298697c71fdf6cb13eefe8aa93926f2f8613" capture-exit@^1.1.0: version "1.2.0" @@ -1535,10 +1496,6 @@ cardinal@^0.5.0: ansicolors "~0.2.1" redeyed "~0.5.0" -caseless@~0.11.0: - version "0.11.0" - resolved "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" - center-align@^0.1.1: version "0.1.3" resolved "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" @@ -1629,8 +1586,8 @@ clean-css-promise@^0.1.0: pinkie-promise "^2.0.0" clean-css@^3.4.5: - version "3.4.25" - resolved "https://registry.npmjs.org/clean-css/-/clean-css-3.4.25.tgz#9e9a52d5c1e6bc5123e1b2783fa65fe958946ede" + version "3.4.27" + resolved "https://registry.npmjs.org/clean-css/-/clean-css-3.4.27.tgz#adef75b31c160ffa5d72f4de67966e2660c1a255" dependencies: commander "2.8.x" source-map "0.4.x" @@ -1708,12 +1665,6 @@ colors@~0.6.0-1: version "0.6.2" resolved "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" -combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" - dependencies: - delayed-stream "~1.0.0" - combined-stream@~0.0.4: version "0.0.7" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" @@ -1734,7 +1685,7 @@ commander@2.8.x: dependencies: graceful-readlink ">= 1.0.0" -commander@^2.5.0, commander@^2.6.0, commander@^2.9.0: +commander@^2.5.0, commander@^2.6.0: version "2.9.0" resolved "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" dependencies: @@ -1795,13 +1746,13 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@1.5.0, concat-stream@^1.4.6, concat-stream@^1.4.7: - version "1.5.0" - resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" +concat-stream@^1.4.6, concat-stream@^1.4.7: + version "1.6.0" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: - inherits "~2.0.1" - readable-stream "~2.0.0" - typedarray "~0.0.5" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" configstore@^2.0.0: version "2.1.0" @@ -1818,14 +1769,14 @@ configstore@^2.0.0: xdg-basedir "^2.0.0" configstore@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/configstore/-/configstore-3.0.0.tgz#e1b8669c1803ccc50b545e92f8e6e79aa80e0196" + version "3.1.0" + resolved "https://registry.npmjs.org/configstore/-/configstore-3.1.0.tgz#45df907073e26dfa1cf4b2d52f5b60545eaa11d1" dependencies: dot-prop "^4.1.0" graceful-fs "^4.1.2" - mkdirp "^0.5.0" + make-dir "^1.0.0" unique-string "^1.0.0" - write-file-atomic "^1.1.2" + write-file-atomic "^2.0.0" xdg-basedir "^3.0.0" console-control-strings@^1.0.0, console-control-strings@~1.1.0: @@ -1888,8 +1839,8 @@ core-object@^1.1.0: resolved "https://registry.npmjs.org/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" core-object@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/core-object/-/core-object-3.1.0.tgz#f5219fec2a19c40956f1c723d121890c88c5f677" + version "3.1.3" + resolved "https://registry.npmjs.org/core-object/-/core-object-3.1.3.tgz#df399b3311bdb0c909e8aae8929fc3c1c4b25880" dependencies: chalk "^1.1.3" @@ -1911,12 +1862,6 @@ cryptiles@0.2.x: dependencies: boom "0.4.x" -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - dependencies: - boom "2.x.x" - crypto-browserify@1.0.9: version "1.0.9" resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" @@ -1935,21 +1880,11 @@ d@1: dependencies: es5-ext "^0.10.9" -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" - -debug@0.7.4: - version "0.7.4" - resolved "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" - -debug@2, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0: - version "2.6.6" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz#a9fa6fbe9ca43cf1e79f73b75c0189cbb7d6db5a" +debug@2, debug@2.6.8, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0, debug@~2.6.7: + version "2.6.8" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" dependencies: - ms "0.7.3" + ms "2.0.0" debug@2.2.0, debug@~2.2.0: version "2.2.0" @@ -1963,17 +1898,11 @@ debug@2.3.3: dependencies: ms "0.7.2" -debug@2.6.1: - version "2.6.1" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" - dependencies: - ms "0.7.2" - -debug@2.6.4: - version "2.6.4" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0" +debug@2.6.7: + version "2.6.7" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e" dependencies: - ms "0.7.3" + ms "2.0.0" decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" @@ -2024,10 +1953,6 @@ delayed-stream@0.0.5: version "0.0.5" resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - delegates@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -2094,12 +2019,6 @@ dot-prop@^4.1.0: dependencies: is-obj "^1.0.0" -ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - dependencies: - jsbn "~0.1.0" - editions@^1.1.1: version "1.3.3" resolved "https://registry.npmjs.org/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" @@ -2108,9 +2027,9 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -electron-to-chromium@^1.2.7: - version "1.3.8" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.8.tgz#b2c8a2c79bb89fbbfd3724d9555e15095b5f5fb6" +electron-to-chromium@^1.3.14: + version "1.3.14" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.14.tgz#64af0f9efd3c3c6acd57d71f83b49ca7ee9c4b43" ember-ajax@^2.4.1: version "2.5.6" @@ -2136,20 +2055,21 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-c ember-cli-version-checker "^1.0.2" resolve "^1.1.2" -ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.1.0.tgz#d9c83a7d0c67cc8a3ccb9bd082971c3593e54fad" +ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.4.1: + version "6.4.1" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.4.1.tgz#785a1c24fe3250eb0776b1ab3cee857863b44542" dependencies: amd-name-resolver "0.0.6" - babel-plugin-debug-macros "^0.1.6" + babel-plugin-debug-macros "^0.1.10" babel-plugin-transform-es2015-modules-amd "^6.24.0" babel-polyfill "^6.16.0" - babel-preset-env "^1.2.0" + babel-preset-env "^1.5.1" broccoli-babel-transpiler "^6.0.0" + broccoli-debug "^0.6.2" broccoli-funnel "^1.0.0" broccoli-source "^1.1.0" clone "^2.0.0" - ember-cli-version-checker "^1.2.0" + ember-cli-version-checker "^2.0.0" ember-cli-blueprint-test-helpers@0.11.0: version "0.11.0" @@ -2210,8 +2130,8 @@ ember-cli-htmlbars-inline-precompile@^0.4.3: silent-error "^1.1.0" ember-cli-htmlbars@^1.0.0: - version "1.3.0" - resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-1.3.0.tgz#e090f011239153bf45dab29625f94a46fce205af" + version "1.3.3" + resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-1.3.3.tgz#06815262c1577736235bd42ce99db559ce5ebfd1" dependencies: broccoli-persistent-filter "^1.0.3" ember-cli-version-checker "^1.0.2" @@ -2220,8 +2140,8 @@ ember-cli-htmlbars@^1.0.0: strip-bom "^2.0.0" ember-cli-htmlbars@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-2.0.1.tgz#e1e333c7ef4cc546c67734996541fd94ca4423ca" + version "2.0.2" + resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-2.0.2.tgz#230a9ace7c3454b3acff2768a50f963813a90c38" dependencies: broccoli-persistent-filter "^1.0.3" hash-for-dep "^1.0.2" @@ -2255,8 +2175,8 @@ ember-cli-is-package-missing@^1.0.0: resolved "https://registry.npmjs.org/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" ember-cli-legacy-blueprints@^0.1.2: - version "0.1.4" - resolved "https://registry.npmjs.org/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.4.tgz#83d6c005ac0e39750ff9dd45cd1b78cf697150c6" + version "0.1.5" + resolved "https://registry.npmjs.org/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.5.tgz#93c15ca242ec5107d62a8af7ec30f6ac538f3ad9" dependencies: chalk "^1.1.1" ember-cli-get-component-path-option "^1.0.0" @@ -2398,14 +2318,14 @@ ember-cli-version-checker@^2.0.0: semver "^5.3.0" ember-cli@^2.11.1: - version "2.13.0" - resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.13.0.tgz#c80d06ff8e16a47b0b2e5fbdb8761feebca86368" + version "2.13.2" + resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.13.2.tgz#a561f08e69b184fa3175f706cced299c0d1684e5" dependencies: amd-name-resolver "0.0.6" babel-plugin-transform-es2015-modules-amd "^6.24.0" bower-config "^1.3.0" bower-endpoint-parser "0.2.2" - broccoli-babel-transpiler "6.0.0-alpha.3" + broccoli-babel-transpiler "^6.0.0" broccoli-brocfile-loader "^0.18.0" broccoli-builder "^0.18.3" broccoli-concat "^3.2.2" @@ -2493,10 +2413,10 @@ ember-dev@emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed: ember-cli-babel "^5.0.0" ember-disable-prototype-extensions@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.0.tgz#86081c8cf6741f26e4b89e2b004f761174313e01" + version "1.1.2" + resolved "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.2.tgz#261cccaf6bf8fbb1836be7bdfe4278f9ab92b873" dependencies: - ember-cli-babel "^5.1.5" + bower "^1.8.0" ember-disable-proxy-controllers@^1.0.0: version "1.0.1" @@ -2511,8 +2431,8 @@ ember-export-application-global@^1.0.5: ember-cli-babel "^5.1.10" ember-inflector@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-2.0.0.tgz#ac0870e87c0724bd42cf5ed7ef166c49a296ecfb" + version "2.0.1" + resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-2.0.1.tgz#e9ac469ffa17992a43276bb1c9b8d87992b10d37" dependencies: ember-cli-babel "^6.0.0" @@ -2588,8 +2508,8 @@ ember-try-config@^2.0.1: semver "^5.1.0" ember-try@^0.2.14: - version "0.2.14" - resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.14.tgz#d47e8fa38858d5683e47856e24a260b39e9caf4a" + version "0.2.15" + resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.15.tgz#559c756058717595babe70068e541625bd5e210a" dependencies: chalk "^1.0.0" cli-table2 "^0.2.0" @@ -2604,7 +2524,6 @@ ember-try@^0.2.14: rimraf "^2.3.2" rsvp "^3.0.17" semver "^5.1.0" - sync-exec "^0.6.2" ember-watson@^0.7.0: version "0.7.0" @@ -2689,8 +2608,8 @@ error@^7.0.0: xtend "~4.0.0" es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.15" - resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.15.tgz#c330a5934c1ee21284a7c081a86e5fd937c91ea6" + version "0.10.23" + resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.23.tgz#7578b51be974207a5487821b56538c224e4e7b38" dependencies: es6-iterator "2" es6-symbol "~3.1" @@ -2714,10 +2633,6 @@ es6-map@^0.1.3, es6-map@^0.1.4: es6-symbol "~3.1.1" event-emitter "~0.3.5" -es6-promise@~4.0.3: - version "4.0.5" - resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz#7882f30adde5b240ccfa7f7d78c548330951ae42" - es6-set@~0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" @@ -2804,8 +2719,8 @@ eslint@^2.13.0: user-home "^2.0.0" espree@^3.1.6: - version "3.4.2" - resolved "https://registry.npmjs.org/espree/-/espree-3.4.2.tgz#38dbdedbedc95b8961a1fbf04734a8f6a9c8c592" + version "3.4.3" + resolved "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz#2910b5ccd49ce893c2ffffaab4fd8b3a31b82374" dependencies: acorn "^5.0.1" acorn-jsx "^3.0.0" @@ -2835,20 +2750,16 @@ esprimaq@^0.0.1: resolved "https://registry.npmjs.org/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" esrecurse@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + version "4.2.0" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" dependencies: - estraverse "~4.1.0" + estraverse "^4.1.0" object-assign "^4.0.1" -estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" -estraverse@~4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" - esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -2925,8 +2836,8 @@ expand-tilde@^1.2.2: os-homedir "^1.0.1" express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: - version "4.15.2" - resolved "https://registry.npmjs.org/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35" + version "4.15.3" + resolved "https://registry.npmjs.org/express/-/express-4.15.3.tgz#bab65d0f03aa80c358408972fc700f916944b662" dependencies: accepts "~1.3.3" array-flatten "1.1.1" @@ -2934,28 +2845,28 @@ express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: content-type "~1.0.2" cookie "0.3.1" cookie-signature "1.0.6" - debug "2.6.1" + debug "2.6.7" depd "~1.1.0" encodeurl "~1.0.1" escape-html "~1.0.3" etag "~1.8.0" - finalhandler "~1.0.0" + finalhandler "~1.0.3" fresh "0.5.0" merge-descriptors "1.0.1" methods "~1.1.2" on-finished "~2.3.0" parseurl "~1.3.1" path-to-regexp "0.1.7" - proxy-addr "~1.1.3" + proxy-addr "~1.1.4" qs "6.4.0" range-parser "~1.2.0" - send "0.15.1" - serve-static "1.12.1" + send "0.15.3" + serve-static "1.12.3" setprototypeof "1.0.3" statuses "~1.3.1" - type-is "~1.6.14" + type-is "~1.6.15" utils-merge "1.0.0" - vary "~1.1.0" + vary "~1.1.1" extend@3, extend@^3.0.0, extend@~3.0.0: version "3.0.1" @@ -2975,19 +2886,6 @@ extglob@^0.3.1: dependencies: is-extglob "^1.0.0" -extract-zip@~1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4" - dependencies: - concat-stream "1.5.0" - debug "0.7.4" - mkdirp "0.5.0" - yauzl "2.4.1" - -extsprintf@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" - fake-xml-http-request@^1.3.0, fake-xml-http-request@^1.4.0: version "1.5.0" resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-1.5.0.tgz#d79602a97043d4d8fea671d5d904af38847b451d" @@ -3025,17 +2923,11 @@ faye-websocket@~0.10.0: dependencies: websocket-driver ">=0.5.1" -fb-watchman@^1.8.0: - version "1.9.2" - resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz#a24cf47827f82d38fb59a69ad70b76e3b6ae7383" - dependencies: - bser "1.0.2" - -fd-slicer@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" +fb-watchman@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" dependencies: - pend "~1.2.0" + bser "^2.0.0" figures@^1.3.5: version "1.7.0" @@ -3056,8 +2948,8 @@ filename-regex@^2.0.0: resolved "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" filesize@^3.1.3: - version "3.5.9" - resolved "https://registry.npmjs.org/filesize/-/filesize-3.5.9.tgz#9e3dd8a9b124f5b2f1fb2ee9cd13a86c707bb222" + version "3.5.10" + resolved "https://registry.npmjs.org/filesize/-/filesize-3.5.10.tgz#fc8fa23ddb4ef9e5e0ab6e1e64f679a24a56761f" fill-range@^2.1.0: version "2.2.3" @@ -3069,11 +2961,11 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" -finalhandler@~1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.2.tgz#d0e36f9dbc557f2de14423df6261889e9d60c93a" +finalhandler@~1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.3.tgz#ef47e77950e999780e86022a560e3217e0d0cc89" dependencies: - debug "2.6.4" + debug "2.6.7" encodeurl "~1.0.1" escape-html "~1.0.3" on-finished "~2.3.0" @@ -3154,10 +3046,6 @@ forever-agent@~0.5.0: version "0.5.2" resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - form-data@~0.1.0: version "0.1.4" resolved "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" @@ -3166,14 +3054,6 @@ form-data@~0.1.0: combined-stream "~0.0.4" mime "~1.2.11" -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - forwarded@~0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" @@ -3222,7 +3102,7 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" -fs-extra@^1.0.0, fs-extra@~1.0.0: +fs-extra@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" dependencies: @@ -3264,7 +3144,7 @@ fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" -gauge@~2.7.1: +gauge@~2.7.3: version "2.7.4" resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" dependencies: @@ -3299,12 +3179,6 @@ get-stream@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" - git-repo-info@^1.1.2, git-repo-info@^1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" @@ -3364,7 +3238,7 @@ glob@5.0.13, glob@^5.0.10: once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1: +glob@7.1.1: version "7.1.1" resolved "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: @@ -3394,6 +3268,17 @@ glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1: + version "7.1.2" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + global-modules@^0.2.3: version "0.2.3" resolved "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" @@ -3415,8 +3300,8 @@ globals@^6.4.0: resolved "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" globals@^9.0.0, globals@^9.2.0: - version "9.17.0" - resolved "https://registry.npmjs.org/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286" + version "9.18.0" + resolved "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" globby@^5.0.0: version "5.0.0" @@ -3450,8 +3335,8 @@ growly@^1.3.0: resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" handlebars@^4.0.4: - version "4.0.7" - resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.7.tgz#e97325aeb8ea0b9e12b9c4dd73c4c312ad0ede59" + version "4.0.10" + resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f" dependencies: async "^1.4.0" optimist "^0.6.1" @@ -3459,15 +3344,6 @@ handlebars@^4.0.4: optionalDependencies: uglify-js "^2.6" -har-validator@~2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" - dependencies: - chalk "^1.1.1" - commander "^2.9.0" - is-my-json-valid "^2.12.4" - pinkie-promise "^2.0.0" - has-ansi@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" @@ -3509,13 +3385,6 @@ hash-for-dep@^1.0.2: heimdalljs-logger "^0.1.7" resolve "^1.1.6" -hasha@~2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1" - dependencies: - is-stream "^1.0.1" - pinkie-promise "^2.0.0" - hawk@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" @@ -3525,15 +3394,6 @@ hawk@1.1.1: hoek "0.9.x" sntp "0.2.x" -hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - heimdall-query@^0.0.5: version "0.0.5" resolved "https://registry.npmjs.org/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" @@ -3565,8 +3425,8 @@ heimdalljs-logger@^0.1.7: heimdalljs "^0.2.0" heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3: - version "0.2.4" - resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.2.4.tgz#34ead16eab422c94803065d33abeba1f7b24a910" + version "0.2.5" + resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.2.5.tgz#6aa54308eee793b642cff9cf94781445f37730ac" dependencies: rsvp "~3.2.1" @@ -3580,10 +3440,6 @@ hoek@0.9.x: version "0.9.1" resolved "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - home-or-tmp@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" @@ -3632,14 +3488,6 @@ http-signature@~0.10.0: assert-plus "^0.1.5" ctype "0.5.3" -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - https-proxy-agent@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" @@ -3657,8 +3505,8 @@ ieee754@^1.1.4: resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" ignore@^3.1.2: - version "3.2.7" - resolved "https://registry.npmjs.org/ignore/-/ignore-3.2.7.tgz#4810ca5f1d8eca5595213a34b94f2eb4ed926bbd" + version "3.3.3" + resolved "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d" imurmurhash@^0.1.4: version "0.1.4" @@ -3683,7 +3531,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.1: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -3767,8 +3615,8 @@ is-builtin-module@^1.0.0: builtin-modules "^1.0.0" is-dotfile@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + version "1.0.3" + resolved "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" is-equal-shallow@^0.1.3: version "0.1.3" @@ -3811,12 +3659,12 @@ is-glob@^2.0.0, is-glob@^2.0.1: is-extglob "^1.0.0" is-integer@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/is-integer/-/is-integer-1.0.6.tgz#5273819fada880d123e1ac00a938e7172dd8d95e" + version "1.0.7" + resolved "https://registry.npmjs.org/is-integer/-/is-integer-1.0.7.tgz#6bde81aacddf78b659b6629d629cadc51a886d5c" dependencies: is-finite "^1.0.0" -is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: +is-my-json-valid@^2.10.0: version "2.16.0" resolved "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" dependencies: @@ -3825,12 +3673,18 @@ is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: jsonpointer "^4.0.0" xtend "^4.0.0" -is-number@^2.0.2, is-number@^2.1.0: +is-number@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" dependencies: kind-of "^3.0.2" +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + is-obj@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" @@ -3883,10 +3737,6 @@ is-type@0.0.1: dependencies: core-util-is "~1.0.0" -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" @@ -3917,10 +3767,6 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - istextorbinary@2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" @@ -3940,12 +3786,6 @@ jmespath@0.15.0: version "0.15.0" resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" -jodid25519@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" - dependencies: - jsbn "~0.1.0" - jquery@^3.1.1: version "3.2.1" resolved "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787" @@ -3963,16 +3803,12 @@ js-tokens@^3.0.0: resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: - version "3.8.3" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766" + version "3.8.4" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6" dependencies: argparse "^1.0.7" esprima "^3.1.1" -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - jsesc@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" @@ -3992,17 +3828,13 @@ json-api-mock-server@0.1.1: jsonapi-validator "^2.1.1" object-assign "^4.1.0" -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: jsonify "~0.0.0" -json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: +json-stringify-safe@~5.0.0: version "5.0.1" resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -4039,22 +3871,15 @@ jsonpointer@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" -jsprim@^1.2.2: - version "1.4.0" - resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" +kind-of@^3.0.2: + version "3.2.2" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" dependencies: - assert-plus "1.0.0" - extsprintf "1.0.2" - json-schema "0.2.3" - verror "1.3.6" - -kew@~0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" + is-buffer "^1.1.5" -kind-of@^3.0.2: - version "3.2.0" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.0.tgz#b58abe4d5c044ad33726a8c1525b48cf891bff07" +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" dependencies: is-buffer "^1.1.5" @@ -4124,8 +3949,8 @@ load-json-file@^1.0.0: strip-bom "^2.0.0" loader.js@^4.2.2: - version "4.3.0" - resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.3.0.tgz#736c13eb8afdf75abd6c2d7b4f7fd40e1105a71f" + version "4.5.0" + resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.5.0.tgz#fa4369702f176410c810605999f79dd590ff3308" locate-path@^2.0.0: version "2.0.0" @@ -4339,16 +4164,22 @@ lru-cache@2: resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" lru-cache@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" + version "4.1.1" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" dependencies: - pseudomap "^1.0.1" - yallist "^2.0.0" + pseudomap "^1.0.2" + yallist "^2.1.2" make-array@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" +make-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-1.0.0.tgz#97a011751e91dd87cfadef58832ebb04936de978" + dependencies: + pify "^2.3.0" + makeerror@1.0.x: version "1.0.11" resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" @@ -4460,33 +4291,41 @@ micromatch@^2.1.5, micromatch@^2.3.7: parse-glob "^3.0.4" regex-cache "^0.4.2" -"mime-db@>= 1.27.0 < 2", mime-db@~1.27.0: +"mime-db@>= 1.27.0 < 2": + version "1.28.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.28.0.tgz#fedd349be06d2865b7fc57d837c6de4f17d7ac3c" + +mime-db@~1.27.0: version "1.27.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" -mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7: +mime-types@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" + +mime-types@~2.1.11, mime-types@~2.1.15: version "2.1.15" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" dependencies: mime-db "~1.27.0" -mime-types@~1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" - -mime@1.3.4, mime@^1.2.11: +mime@1.3.4: version "1.3.4" resolved "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" +mime@^1.2.11: + version "1.3.6" + resolved "https://registry.npmjs.org/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0" + mime@~1.2.11: version "1.2.11" resolved "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: - brace-expansion "^1.0.0" + brace-expansion "^1.1.7" minimatch@^2.0.1, minimatch@^2.0.3, minimatch@^2.0.8: version "2.0.10" @@ -4513,12 +4352,6 @@ mkdirp@0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" -mkdirp@0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" - dependencies: - minimist "0.0.8" - mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -4562,11 +4395,11 @@ moment-timezone@^0.3.0: resolved "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" morgan@^1.7.0, morgan@^1.8.1: - version "1.8.1" - resolved "https://registry.npmjs.org/morgan/-/morgan-1.8.1.tgz#f93023d3887bd27b78dfd6023cea7892ee27a4b1" + version "1.8.2" + resolved "https://registry.npmjs.org/morgan/-/morgan-1.8.2.tgz#784ac7734e4a453a9c6e6e8680a9329275c8b687" dependencies: basic-auth "~1.1.0" - debug "2.6.1" + debug "2.6.8" depd "~1.1.0" on-finished "~2.3.0" on-headers "~1.0.1" @@ -4583,9 +4416,9 @@ ms@0.7.2: version "0.7.2" resolved "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" -ms@0.7.3: - version "0.7.3" - resolved "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff" +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" mustache@^2.2.1: version "2.3.0" @@ -4604,8 +4437,8 @@ negotiator@0.6.1: resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" node-fetch@^1.3.3: - version "1.6.3" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" + version "1.7.1" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz#899cb3d0a3c92f952c47f1b876f4c8aeabd400d5" dependencies: encoding "^0.1.11" is-stream "^1.0.1" @@ -4670,12 +4503,12 @@ npm-run-path@^2.0.0: path-key "^2.0.0" npmlog@^4.0.0: - version "4.0.2" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" + version "4.1.0" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5" dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" - gauge "~2.7.1" + gauge "~2.7.3" set-blocking "~2.0.0" number-is-nan@^1.0.0: @@ -4686,10 +4519,6 @@ oauth-sign@~0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" -oauth-sign@~0.8.1: - version "0.8.2" - resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - object-assign@4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" @@ -4894,25 +4723,7 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - -phantomjs-prebuilt@^2.1.12: - version "2.1.14" - resolved "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.14.tgz#d53d311fcfb7d1d08ddb24014558f1188c516da0" - dependencies: - es6-promise "~4.0.3" - extract-zip "~1.5.0" - fs-extra "~1.0.0" - hasha "~2.2.0" - kew "~0.7.0" - progress "~1.1.8" - request "~2.79.0" - request-progress "~2.0.1" - which "~1.2.10" - -pify@^2.0.0: +pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -4982,7 +4793,7 @@ process-relative-require@^1.0.0: dependencies: node-modules-path "^1.0.0" -progress@^1.1.8, progress@~1.1.8: +progress@^1.1.8: version "1.1.8" resolved "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" @@ -4992,14 +4803,14 @@ promise-map-series@^0.2.1: dependencies: rsvp "^3.0.14" -proxy-addr@~1.1.3: +proxy-addr@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" dependencies: forwarded "~0.1.0" ipaddr.js "1.3.0" -pseudomap@^1.0.1: +pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -5023,10 +4834,6 @@ qs@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" -qs@~6.3.0: - version "6.3.2" - resolved "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" - querystring@0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" @@ -5048,11 +4855,11 @@ qunitjs@^1.20.0: resolved "https://registry.npmjs.org/qunitjs/-/qunitjs-1.23.1.tgz#1971cf97ac9be01a64d2315508d2e48e6fd4e719" randomatic@^1.1.3: - version "1.1.6" - resolved "https://registry.npmjs.org/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + version "1.1.7" + resolved "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" dependencies: - is-number "^2.0.2" - kind-of "^3.0.2" + is-number "^3.0.0" + kind-of "^4.0.0" range-parser@~1.2.0: version "1.2.0" @@ -5088,15 +4895,15 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^2, readable-stream@^2.0.6: - version "2.2.9" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8" +readable-stream@^2, readable-stream@^2.0.6, readable-stream@^2.2.2: + version "2.3.2" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.2.tgz#5a04df05e4f57fe3f0dc68fdd11dc5c97c7e6f4d" dependencies: - buffer-shims "~1.0.0" core-util-is "~1.0.0" - inherits "~2.0.1" + inherits "~2.0.3" isarray "~1.0.0" process-nextick-args "~1.0.6" + safe-buffer "~5.1.0" string_decoder "~1.0.0" util-deprecate "~1.0.1" @@ -5109,17 +4916,6 @@ readable-stream@~1.0.2: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@~2.0.0: - version "2.0.6" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - readline2@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" @@ -5224,8 +5020,8 @@ regjsparser@^0.1.4: jsesc "~0.5.0" remove-trailing-separator@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4" + version "1.0.2" + resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz#69b062d978727ad14dc6b56ba4ab772fd8d70511" repeat-element@^1.1.2: version "1.1.2" @@ -5247,12 +5043,6 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request-progress@~2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" - dependencies: - throttleit "^1.0.0" - request@~2.40.0: version "2.40.0" resolved "https://registry.npmjs.org/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" @@ -5272,31 +5062,6 @@ request@~2.40.0: tough-cookie ">=0.12.0" tunnel-agent "~0.4.0" -request@~2.79.0: - version "2.79.0" - resolved "https://registry.npmjs.org/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.11.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~2.0.6" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - qs "~6.3.0" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" - uuid "^3.0.0" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -5346,13 +5111,13 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2.5.2, rimraf@^2.4.3, rimraf@^2.4.4: +rimraf@2.5.2, rimraf@^2.3.4, rimraf@^2.4.3, rimraf@^2.4.4: version "2.5.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" -rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: +rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.4.1, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: version "2.6.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: @@ -5376,11 +5141,11 @@ route-recognizer@^0.2.3: version "0.2.10" resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" -rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.6, rsvp@~3.2.1: +rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.6, rsvp@^3.2.1, rsvp@~3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" -rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: +rsvp@^3.0.14, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3, rsvp@^3.4.0: version "3.5.0" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" @@ -5412,28 +5177,26 @@ rx@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" +safe-buffer@~5.1.0: + version "5.1.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + safe-json-parse@~1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" sane@^1.1.1, sane@^1.6.0: - version "1.6.0" - resolved "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz#9610c452307a135d29c1fdfe2547034180c46775" + version "1.7.0" + resolved "https://registry.npmjs.org/sane/-/sane-1.7.0.tgz#b3579bccb45c94cf20355cc81124990dfd346e30" dependencies: anymatch "^1.3.0" exec-sh "^0.2.0" - fb-watchman "^1.8.0" + fb-watchman "^2.0.0" minimatch "^3.0.2" minimist "^1.1.1" walker "~1.0.5" watch "~0.10.0" -sanitize-filename@^1.5.3: - version "1.6.1" - resolved "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.1.tgz#612da1c96473fa02dccda92dcd5b4ab164a6772a" - dependencies: - truncate-utf8-bytes "^1.0.0" - sax@1.2.1, sax@>=0.6.0: version "1.2.1" resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" @@ -5459,11 +5222,11 @@ semver@~5.0.1: version "5.0.3" resolved "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" -send@0.15.1: - version "0.15.1" - resolved "https://registry.npmjs.org/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" +send@0.15.3: + version "0.15.3" + resolved "https://registry.npmjs.org/send/-/send-0.15.3.tgz#5013f9f99023df50d1bd9892c19e3defd1d53309" dependencies: - debug "2.6.1" + debug "2.6.7" depd "~1.1.0" destroy "~1.0.4" encodeurl "~1.0.1" @@ -5472,19 +5235,19 @@ send@0.15.1: fresh "0.5.0" http-errors "~1.6.1" mime "1.3.4" - ms "0.7.2" + ms "2.0.0" on-finished "~2.3.0" range-parser "~1.2.0" statuses "~1.3.1" -serve-static@1.12.1: - version "1.12.1" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039" +serve-static@1.12.3: + version "1.12.3" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.12.3.tgz#9f4ba19e2f3030c547f8af99107838ec38d5b1e2" dependencies: encodeurl "~1.0.1" escape-html "~1.0.3" parseurl "~1.3.1" - send "0.15.1" + send "0.15.3" set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" @@ -5520,13 +5283,7 @@ signal-exit@^3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" -silent-error@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.0.1.tgz#71b7d503d1c6f94882b51b56be879b113cb4822c" - dependencies: - debug "^2.2.0" - -silent-error@^1.0.1, silent-error@^1.1.0: +silent-error@^1.0.0, silent-error@^1.0.1, silent-error@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.1.0.tgz#2209706f1c850a9f1d10d0d840918b46f26e1bc9" dependencies: @@ -5562,12 +5319,6 @@ sntp@0.2.x: dependencies: hoek "0.9.x" -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - dependencies: - hoek "2.x.x" - socket.io-adapter@0.5.0: version "0.5.0" resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" @@ -5617,8 +5368,8 @@ sort-object-keys@^1.1.1: resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" sort-package-json@^1.4.0: - version "1.6.1" - resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.6.1.tgz#2ae463e4f5bb5d803bfdffdb4f92551c8fa66593" + version "1.7.0" + resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.7.0.tgz#13b362ff6400c5b4eaa9ba220f9ea7c3d6644b5f" dependencies: sort-object-keys "^1.1.1" @@ -5691,21 +5442,6 @@ sri-toolbox@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" -sshpk@^1.7.0: - version "1.13.0" - resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz#ff2a3e4fd04497555fed97b39a0fd82fafb3a33c" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jodid25519 "^1.0.0" - jsbn "~0.1.0" - tweetnacl "~0.14.0" - stable@~0.1.3: version "0.1.6" resolved "https://registry.npmjs.org/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10" @@ -5742,10 +5478,10 @@ string_decoder@0.10, string_decoder@~0.10.x: resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" string_decoder@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.0.tgz#f06f41157b664d86069f84bdbdc9b0d8ab281667" + version "1.0.3" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" dependencies: - buffer-shims "~1.0.0" + safe-buffer "~5.1.0" stringmap@~0.2.2: version "0.2.2" @@ -5815,10 +5551,6 @@ symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: version "1.1.8" resolved "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" -sync-exec@^0.6.2: - version "0.6.2" - resolved "https://registry.npmjs.org/sync-exec/-/sync-exec-0.6.2.tgz#717d22cc53f0ce1def5594362f3a89a2ebb91105" - table@^3.7.8: version "3.8.3" resolved "https://registry.npmjs.org/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" @@ -5831,8 +5563,8 @@ table@^3.7.8: string-width "^2.0.0" tap-parser@^5.1.0: - version "5.3.3" - resolved "https://registry.npmjs.org/tap-parser/-/tap-parser-5.3.3.tgz#53ec8a90f275d6fff43f169e56a679502a741185" + version "5.4.0" + resolved "https://registry.npmjs.org/tap-parser/-/tap-parser-5.4.0.tgz#6907e89725d7b7fa6ae41ee2c464c3db43188aec" dependencies: events-to-array "^1.0.1" js-yaml "^3.2.7" @@ -5884,20 +5616,16 @@ text-table@~0.2.0: version "2.1.0" resolved "https://registry.npmjs.org/textextensions/-/textextensions-2.1.0.tgz#1be0dc2a0dc244d44be8a09af6a85afb93c4dbc3" -throttleit@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" - through@^2.3.6, through@^2.3.8, through@~2.3.8: version "2.3.8" resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" tiny-lr@^1.0.3: - version "1.0.4" - resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.0.4.tgz#d13becf37f8b7e963320f5743298e3e934c7329a" + version "1.0.5" + resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.0.5.tgz#21f40bf84ebd1f853056680375eef1670c334112" dependencies: body "^5.1.0" - debug "~2.2.0" + debug "~2.6.7" faye-websocket "~0.10.0" livereload-js "^2.2.2" object-assign "^4.1.0" @@ -5940,13 +5668,13 @@ to-fast-properties@^1.0.0, to-fast-properties@^1.0.1: version "1.0.3" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" -tough-cookie@>=0.12.0, tough-cookie@~2.3.0: +tough-cookie@>=0.12.0: version "2.3.2" resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" dependencies: punycode "^1.4.1" -tree-sync@^1.2.1: +tree-sync@^1.2.1, tree-sync@^1.2.2: version "1.2.2" resolved "https://registry.npmjs.org/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" dependencies: @@ -5960,12 +5688,6 @@ trim-right@^1.0.0, trim-right@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" -truncate-utf8-bytes@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" - dependencies: - utf8-byte-length "^1.0.1" - try-resolve@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" @@ -5978,14 +5700,10 @@ tryor@~0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" -tunnel-agent@~0.4.0, tunnel-agent@~0.4.1: +tunnel-agent@~0.4.0: version "0.4.3" resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - type-check@~0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -6000,14 +5718,14 @@ type-detect@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" -type-is@~1.6.14: +type-is@~1.6.15: version "1.6.15" resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" dependencies: media-typer "0.3.0" mime-types "~2.1.15" -typedarray@~0.0.5: +typedarray@^0.0.6: version "0.0.6" resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -6016,8 +5734,8 @@ uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.3: resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" uglify-js@^2.6, uglify-js@^2.7.0: - version "2.8.22" - resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.22.tgz#d54934778a8da14903fa29a326fb24c0ab51a1a0" + version "2.8.29" + resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" dependencies: source-map "~0.5.1" yargs "~3.10.0" @@ -6076,9 +5794,9 @@ user-home@^2.0.0: dependencies: os-homedir "^1.0.0" -utf8-byte-length@^1.0.1: - version "1.0.4" - resolved "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" +username-sync@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/username-sync/-/username-sync-1.0.1.tgz#1cde87eefcf94b8822984d938ba2b797426dae1f" util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" @@ -6088,7 +5806,7 @@ utils-merge@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" -uuid@3.0.1, uuid@^3.0.0: +uuid@3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" @@ -6096,6 +5814,10 @@ uuid@^2.0.1: version "2.0.3" resolved "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" +uuid@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" + validate-npm-package-license@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" @@ -6109,16 +5831,10 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" -vary@~1.1.0: +vary@~1.1.0, vary@~1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" -verror@1.3.6: - version "1.3.6" - resolved "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" - dependencies: - extsprintf "1.0.2" - walk-sync@^0.1.3: version "0.1.3" resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" @@ -6131,8 +5847,8 @@ walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: matcher-collection "^1.0.0" walk-sync@^0.3.0, walk-sync@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.1.tgz#558a16aeac8c0db59c028b73c66f397684ece465" + version "0.3.2" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" @@ -6161,17 +5877,17 @@ which-module@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" -which@^1.2.12, which@^1.2.9, which@~1.2.10: +which@^1.2.12, which@^1.2.9: version "1.2.14" resolved "https://registry.npmjs.org/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" dependencies: isexe "^2.0.0" wide-align@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + version "1.1.2" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" dependencies: - string-width "^1.0.1" + string-width "^1.0.2" window-size@0.1.0: version "0.1.0" @@ -6216,6 +5932,14 @@ write-file-atomic@^1.1.2: imurmurhash "^0.1.4" slide "^1.1.5" +write-file-atomic@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.1.0.tgz#1769f4b551eedce419f0505deae2e26763542d37" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + slide "^1.1.5" + write@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" @@ -6279,7 +6003,7 @@ y18n@^3.2.0, y18n@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" -yallist@^2.0.0: +yallist@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" @@ -6336,12 +6060,6 @@ yargs@~3.27.0: window-size "^0.1.2" y18n "^3.2.0" -yauzl@2.4.1: - version "2.4.1" - resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" - dependencies: - fd-slicer "~1.0.1" - yeast@0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" From d70f2ee7ed69e0ea85dd905524f8d8c858a93a3f Mon Sep 17 00:00:00 2001 From: bekzod Date: Mon, 26 Jun 2017 11:08:39 +0500 Subject: [PATCH 1958/2527] remove deprecated `idToRecord` --- addon/-private/system/identity-map.js | 2 +- addon/-private/system/internal-model-map.js | 38 +++++---------------- 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/addon/-private/system/identity-map.js b/addon/-private/system/identity-map.js index b272aa8304d..68f7cb71783 100644 --- a/addon/-private/system/identity-map.js +++ b/addon/-private/system/identity-map.js @@ -25,7 +25,7 @@ export default class IdentityMap { retrieve(modelName) { let map = this._map[modelName]; - if (!map) { + if (map === undefined) { map = this._map[modelName] = new InternalModelMap(modelName); } diff --git a/addon/-private/system/internal-model-map.js b/addon/-private/system/internal-model-map.js index 80a10ed9c57..310ba87e0d9 100644 --- a/addon/-private/system/internal-model-map.js +++ b/addon/-private/system/internal-model-map.js @@ -1,4 +1,4 @@ -import { assert, deprecate } from '@ember/debug'; +import { assert } from '@ember/debug'; import InternalModel from './model/internal-model'; /** @@ -19,25 +19,13 @@ export default class InternalModelMap { this._metadata = null; } - /** - A "map" of records based on their ID for this modelName - */ - get idToRecord() { - deprecate('Use of InternalModelMap.idToRecord is deprecated, use InternalModelMap.get(id) instead.', false, { - id: 'ds.record-map.idToRecord', - until: '2.13' - }); - return this._idToModel; - } - /** * * @param id * @returns {InternalModel} */ get(id) { - let r = this._idToModel[id]; - return r; + return this._idToModel[id]; } has(id) { @@ -68,9 +56,7 @@ export default class InternalModelMap { } remove(internalModel, id) { - if (id) { - delete this._idToModel[id]; - } + delete this._idToModel[id]; let loc = this._models.indexOf(internalModel); @@ -112,21 +98,15 @@ export default class InternalModelMap { @method clear */ clear() { - if (this._models) { - let models = this._models; - this._models = []; - - for (let i = 0; i < models.length; i++) { - let model = models[i]; - model.unloadRecord(); - } + let models = this._models; + this._models = []; + + for (let i = 0; i < models.length; i++) { + let model = models[i]; + model.unloadRecord(); } this._metadata = null; } - destroy() { - this._store = null; - this._modelClass = null; - } } From b86fe0e7cf295ae9a2e7cb259b32ea993b899368 Mon Sep 17 00:00:00 2001 From: bekzod Date: Mon, 26 Jun 2017 12:41:32 +0500 Subject: [PATCH 1959/2527] use prop destructor for Ember dependencies --- addon/-private/system/model/errors.js | 7 +------ addon/-private/system/record-array-manager.js | 2 +- addon/adapters/rest.js | 14 +++++++------- addon/serializers/embedded-records-mixin.js | 5 ++--- addon/serializers/rest.js | 2 +- 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index 9642e8eee16..42dd3d1c9a3 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -1,12 +1,7 @@ import Ember from 'ember'; import { deprecate, warn } from '@ember/debug'; -const get = Ember.get; -const set = Ember.set; -const isEmpty = Ember.isEmpty; -const makeArray = Ember.makeArray; - -const MapWithDefault = Ember.MapWithDefault; +const { get, set, isEmpty, makeArray, MapWithDefault } = Ember; /** @module ember-data diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index d0bd9783287..bf8e4fbd3d4 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -449,7 +449,7 @@ export default class RecordArrayManager { destroy() { this.isDestroying = true; - Ember.run.schedule('actions', this, this.willDestroy); + emberRun.schedule('actions', this, this.willDestroy); } } diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 534e948cdeb..6ab765533ea 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -23,10 +23,10 @@ import { instrument } from 'ember-data/-debug'; import { warn, deprecate } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; - const { MapWithDefault, - get + get, + run } = Ember; const Promise = Ember.RSVP.Promise; @@ -1061,7 +1061,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { hash.success = function(payload, textStatus, jqXHR) { heimdall.stop(token); let response = ajaxSuccess(adapter, jqXHR, payload, requestData); - Ember.run.join(null, resolve, response); + run.join(null, resolve, response); }; hash.error = function(jqXHR, textStatus, errorThrown) { @@ -1071,7 +1071,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { errorThrown }; let error = ajaxError(adapter, jqXHR, requestData, responseData); - Ember.run.join(null, reject, error); + run.join(null, reject, error); }; adapter._ajaxRequest(hash); @@ -1442,12 +1442,12 @@ if (isEnabled('ds-improved-ajax')) { let { method, url } = request; let requestData = { method, url }; - return new Ember.RSVP.Promise((resolve, reject) => { + return new Promise((resolve, reject) => { hash.success = function(payload, textStatus, jqXHR) { heimdall.stop(token); let response = ajaxSuccess(adapter, jqXHR, payload, requestData); - Ember.run.join(null, resolve, response); + run.join(null, resolve, response); }; hash.error = function(jqXHR, textStatus, errorThrown) { @@ -1457,7 +1457,7 @@ if (isEnabled('ds-improved-ajax')) { errorThrown }; let error = ajaxError(adapter, jqXHR, requestData, responseData); - Ember.run.join(null, reject, error); + run.join(null, reject, error); }; instrument(function() { diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index b082dec85eb..e640b4d5b7e 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -1,9 +1,8 @@ import Ember from 'ember'; import { warn } from '@ember/debug'; -const get = Ember.get; -const set = Ember.set; -const camelize = Ember.String.camelize; +const { get, set } = Ember; +const { camelize } = Ember.String; /** ## Using Embedded Records diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 57c9b7e2824..c85e07c8e16 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -10,7 +10,7 @@ import { DEBUG } from '@glimmer/env'; import JSONSerializer from "../serializers/json"; import { coerceId, modelHasAttributeOrRelationshipNamedType, normalizeModelName, isEnabled } from '../-private'; -let camelize = Ember.String.camelize; +const { camelize } = Ember.String; /** Normally, applications will use the `RESTSerializer` by implementing From 06b2b18234c2e9ba8b95b0c4f558d739f8862eac Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 26 Jun 2017 18:37:14 -0700 Subject: [PATCH 1960/2527] tests for unload + resurrect + remote relationship state --- tests/integration/records/unload-test.js | 102 ++++++++++++++++++++++- 1 file changed, 98 insertions(+), 4 deletions(-) diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index df15382eda2..1b6cc82fc05 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -508,8 +508,28 @@ test("after unloading a record, the record can be fetched again immediately", fu id: '1', attributes: { name: 'Adam Sunderland' + }, + relationships: { + cars: { + data: [ + { + id: 1, + type: 'car' + } + ] + } } - } + }, + included: [ + { + type: 'car', + id: 1, + attributes: { + make: 'jeep', + model: 'wrangler' + } + } + ] }); }); @@ -517,16 +537,90 @@ test("after unloading a record, the record can be fetched again immediately", fu assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded initially'); // we test that we can sync call unloadRecord followed by findRecord - run(function() { + return run(function() { + assert.equal(record.get('cars.firstObject.make'), 'jeep'); store.unloadRecord(record); assert.equal(record.isDestroying, true, 'the record is destroying'); assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are unloaded after unloadRecord'); - store.findRecord('person', '1'); + return store.findRecord('person', '1').then(record => { + assert.equal(record.get('cars.length'), 1); + assert.equal(record._internalModel, internalModel, 'new record, has old internal model'); + assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded after findRecord'); + }) }); - assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded after findRecord'); }); +test("after unloading a record, the record can be fetched again immediately (purge relationship)", function(assert) { + const store = env.store; + let record; + + // stub findRecord + env.adapter.findRecord = () => { + return Ember.RSVP.Promise.resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + }, + relationships: { + cars: { data: null } + } + } + }); + }; + + // populate initial record + run(function() { + record = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + }, + relationships: { + cars: { + data: [ + { + id: 1, + type: 'car' + } + ] + } + } + }, + included: [ + { + type: 'car', + id: 1, + attributes: { + make: 'jeep', + model: 'wrangler' + } + } + ] + }); + }); + + const internalModel = record._internalModel; + assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded initially'); + + // we test that we can sync call unloadRecord followed by findRecord + return run(function() { + assert.equal(record.get('cars.firstObject.make'), 'jeep'); + store.unloadRecord(record); + assert.equal(record.isDestroying, true, 'the record is destroying'); + assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are unloaded after unloadRecord'); + return store.findRecord('person', '1').then(record => { + assert.equal(record.get('cars.length'), 0); + assert.equal(record._internalModel, internalModel, 'new record, has old internal model'); + assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded after findRecord'); + }) + }); + +}); test("after unloading a record, the record can be fetched again soon there after", function(assert) { const store = env.store; From 826971c426052b8b2d6a00eab44dc60c74555c69 Mon Sep 17 00:00:00 2001 From: bekzod Date: Sat, 1 Jul 2017 00:36:26 +0500 Subject: [PATCH 1961/2527] update `ember-resolver` `loader.js` `rsvp` --- package.json | 6 ++--- yarn.lock | 69 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 47 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index 82a89695ffc..e2a3e2da0c8 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "ember-export-application-global": "^1.0.5", "ember-load-initializers": "^0.6.0", "ember-publisher": "0.0.7", - "ember-resolver": "^2.0.3", + "ember-resolver": "^4.1.0", "ember-source": "~2.11.0", "ember-watson": "^0.7.0", "express": "^4.14.0", @@ -100,13 +100,13 @@ "glob": "5.0.13", "heimdall-query": "^0.0.5", "json-api-mock-server": "0.1.1", - "loader.js": "^4.2.2", + "loader.js": "^4.5.0", "mocha": "2.4.5", "mocha-only-detector": "0.0.2", "morgan": "^1.7.0", "pretender": "1.0.0", "rimraf": "2.5.2", - "rsvp": "3.2.1" + "rsvp": "3.6.0" }, "peerDependencies": { "ember-inflector": "^2.0.0" diff --git a/yarn.lock b/yarn.lock index 9972e81fe64..b579e6e486c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,16 @@ # yarn lockfile v1 +"@glimmer/di@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" + +"@glimmer/resolver@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@glimmer/resolver/-/resolver-0.3.1.tgz#41069345b6f41beb0948cc35d8e4aa60adcadfc5" + dependencies: + "@glimmer/di" "^0.2.0" + "@types/node@*", "@types/node@^7.0.5": version "7.0.32" resolved "https://registry.npmjs.org/@types/node/-/node-7.0.32.tgz#6afe6c66520a4c316623a14aef123908d01b4bba" @@ -492,7 +502,7 @@ babel-plugin-dead-code-elimination@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" -babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.7: +babel-plugin-debug-macros@^0.1.1, babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.7: version "0.1.10" resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.10.tgz#dd077ad6e1cc0a8f9bbc6405c561392ebfc9a01c" dependencies: @@ -1078,29 +1088,29 @@ broccoli-builder@^0.18.3: rsvp "^3.0.17" silent-error "^1.0.1" -broccoli-caching-writer@^2.0.4, broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" +broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.1: + version "2.0.4" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" + lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - walk-sync "^0.2.5" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" -broccoli-caching-writer@~2.0.1: - version "2.0.4" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" +broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" - lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - symlink-or-copy "^1.0.0" - walk-sync "^0.2.0" + walk-sync "^0.2.5" broccoli-clean-css@^1.1.0: version "1.1.0" @@ -2454,12 +2464,17 @@ ember-qunit@^0.4.18: dependencies: ember-test-helpers "^0.5.32" -ember-resolver@^2.0.3: - version "2.1.1" - resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-2.1.1.tgz#5e4c1fffe9f5f48fc2194ad7592274ed0cd74f72" +ember-resolver@^4.1.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-4.1.0.tgz#f02aeb2f1f2e944ed47e085412a7b84f759d11df" dependencies: - ember-cli-babel "^5.1.6" + "@glimmer/resolver" "^0.3.0" + babel-plugin-debug-macros "^0.1.1" + broccoli-funnel "^1.1.0" + broccoli-merge-trees "^2.0.0" + ember-cli-babel "^6.0.0-beta.7" ember-cli-version-checker "^1.1.6" + resolve "^1.3.2" ember-router-generator@^1.0.0: version "1.2.3" @@ -3948,9 +3963,9 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -loader.js@^4.2.2: - version "4.5.0" - resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.5.0.tgz#fa4369702f176410c810605999f79dd590ff3308" +loader.js@^4.5.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.5.1.tgz#c15ab15a6b8376bd4fbf7ea56f8d76cc557331da" locate-path@^2.0.0: version "2.0.0" @@ -5092,7 +5107,7 @@ resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" -resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3: +resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.2, resolve@^1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" dependencies: @@ -5111,13 +5126,13 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2.5.2, rimraf@^2.3.4, rimraf@^2.4.3, rimraf@^2.4.4: +rimraf@2.5.2, rimraf@^2.4.3, rimraf@^2.4.4: version "2.5.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" -rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.4.1, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: +rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: version "2.6.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: @@ -5141,14 +5156,18 @@ route-recognizer@^0.2.3: version "0.2.10" resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" -rsvp@3.2.1, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.6, rsvp@^3.2.1, rsvp@~3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" +rsvp@3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.0.tgz#666dfffa715f7e10eef76f4d1e56fb2566fce5c3" -rsvp@^3.0.14, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3, rsvp@^3.4.0: +rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: version "3.5.0" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" +rsvp@^3.0.16, rsvp@^3.0.6, rsvp@~3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + rsvp@~3.0.6: version "3.0.21" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" From a277a1fd014f4b015326f7ab0f199c200f6830f6 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Sun, 2 Jul 2017 14:36:35 -0700 Subject: [PATCH 1962/2527] cleanup --- tests/integration/application-test.js | 69 ++-- .../integration/client-id-generation-test.js | 19 +- tests/integration/inverse-test.js | 13 +- tests/integration/lifecycle-hooks-test.js | 18 +- tests/integration/multiple-stores-test.js | 55 ++-- tests/integration/peek-all-test.js | 15 +- .../polymorphic-belongs-to-test.js | 6 +- .../integration/record-array-manager-test.js | 6 +- tests/integration/record-array-test.js | 5 +- tests/integration/setup-container-test.js | 24 +- tests/integration/snapshot-test.js | 301 +++++++++--------- tests/integration/store-test.js | 216 ++++++------- 12 files changed, 359 insertions(+), 388 deletions(-) diff --git a/tests/integration/application-test.js b/tests/integration/application-test.js index 43316c3bd41..665f14855c4 100644 --- a/tests/integration/application-test.js +++ b/tests/integration/application-test.js @@ -5,13 +5,13 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var run = Ember.run; -var Application = Ember.Application; -var Controller = Ember.Controller; -var Store = DS.Store; -var Namespace = Ember.Namespace; +const run = Ember.run; +const Application = Ember.Application; +const Controller = Ember.Controller; +const Store = DS.Store; +const Namespace = Ember.Namespace; -var app, App, container; +let app, App, container; /* These tests ensure that Ember Data works with Ember.js' application @@ -28,7 +28,7 @@ function lookup(thing) { module("integration/application - Injecting a Custom Store", { beforeEach() { - run(function() { + run(() => { app = Application.create({ StoreService: Store.extend({ isCustom: true }), FooController: Controller.extend(), @@ -48,22 +48,21 @@ module("integration/application - Injecting a Custom Store", { }); test("If a Store property exists on an Ember.Application, it should be instantiated.", function(assert) { - run(function() { + run(() => { assert.ok(getStore().get('isCustom'), "the custom store was instantiated"); }); }); test("If a store is instantiated, it should be made available to each controller.", function(assert) { - var fooController = lookup('controller:foo'); - var isCustom = run(fooController, 'get', 'store.isCustom'); + let fooController = lookup('controller:foo'); + let isCustom = run(fooController, 'get', 'store.isCustom'); assert.ok(isCustom, "the custom store was injected"); }); test("The JSONAPIAdapter is the default adapter when no custom adapter is provided", function(assert) { - run(function() { - var store = getStore(); - - var adapter = store.adapterFor('application'); + run(() => { + let store = getStore(); + let adapter = store.adapterFor('application'); assert.ok(adapter instanceof DS.JSONAPIAdapter, 'default adapter should be the JSONAPIAdapter'); }); @@ -71,7 +70,7 @@ test("The JSONAPIAdapter is the default adapter when no custom adapter is provid module("integration/application - Injecting the Default Store", { beforeEach() { - run(function() { + run(() => { app = Application.create({ FooController: Controller.extend(), BazController: {}, @@ -93,14 +92,14 @@ test("If a Store property exists on an Ember.Application, it should be instantia }); test("If a store is instantiated, it should be made available to each controller.", function(assert) { - run(function() { - var fooController = lookup('controller:foo'); + run(() => { + let fooController = lookup('controller:foo'); assert.ok(fooController.get('store') instanceof DS.Store, "the store was injected"); }); }); test("the DS namespace should be accessible", function(assert) { - run(function() { + run(() => { assert.ok(Namespace.byName('DS') instanceof Namespace, "the DS namespace is accessible"); }); }); @@ -108,7 +107,7 @@ test("the DS namespace should be accessible", function(assert) { if (Ember.inject && Ember.inject.service) { module("integration/application - Using the store as a service", { beforeEach() { - run(function() { + run(() => { app = Application.create({ DoodleService: Ember.Service.extend({ store: Ember.inject.service() }) }); @@ -124,8 +123,8 @@ if (Ember.inject && Ember.inject.service) { }); test("The store can be injected as a service", function(assert) { - run(function() { - var doodleService = lookup('service:doodle'); + run(() => { + let doodleService = lookup('service:doodle'); assert.ok(doodleService.get('store') instanceof Store, "the store can be used as a service"); }); }); @@ -145,14 +144,14 @@ module("integration/application - Attaching initializer", { }); test("ember-data initializer is run", function(assert) { - var ran = false; + let ran = false; App.initializer({ name: "after-ember-data", after: "ember-data", initialize() { ran = true; } }); - run(function() { + run(() => { app = App.create(); }); @@ -161,7 +160,7 @@ test("ember-data initializer is run", function(assert) { test("ember-data initializer does not register the store service when it was already registered", function(assert) { - var AppStore = Store.extend({ + let AppStore = Store.extend({ isCustomStore: true }); @@ -173,26 +172,26 @@ test("ember-data initializer does not register the store service when it was alr } }); - run(function() { + run(() => { app = App.create(); container = app.__container__; }); - var store = getStore(); + let store = getStore(); assert.ok(store && store.get('isCustomStore'), 'ember-data initializer does not overwrite the previous registered service store'); }); testInDebug("store initializer is run (DEPRECATED)", function(assert) { - var ran = false; + let ran = false; App.initializer({ name: "after-store", after: 'store', initialize() { ran = true; } }); - assert.expectDeprecation(function() { - run(function() { + assert.expectDeprecation(() => { + run(() => { app = App.create(); }); }, /The initializer `store` has been deprecated/) @@ -201,15 +200,15 @@ testInDebug("store initializer is run (DEPRECATED)", function(assert) { }); testInDebug("injectStore initializer is run (DEPRECATED)", function(assert) { - var ran = false; + let ran = false; App.initializer({ name: "after-store", after: 'injectStore', initialize() { ran = true; } }); - assert.expectDeprecation(function() { - run(function() { + assert.expectDeprecation(() => { + run(() => { app = App.create(); }); }, /The initializer `injectStore` has been deprecated/) @@ -218,15 +217,15 @@ testInDebug("injectStore initializer is run (DEPRECATED)", function(assert) { }); testInDebug("transforms initializer is run (DEPRECATED)", function(assert) { - var ran = false; + let ran = false; App.initializer({ name: "after-store", after: 'transforms', initialize() { ran = true; } }); - assert.expectDeprecation(function() { - run(function() { + assert.expectDeprecation(() => { + run(() => { app = App.create(); }); }, /The initializer `transforms` has been deprecated/) diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index f55d93c95b7..6fe32283f51 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -5,9 +5,8 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var get = Ember.get; -var Post, Comment, Misc, env; -var run = Ember.run; +const { get, run } = Ember; +let Post, Comment, Misc, env; module("integration/client_id_generation - Client-side ID Generation", { beforeEach() { @@ -38,7 +37,7 @@ module("integration/client_id_generation - Client-side ID Generation", { test("If an adapter implements the `generateIdForRecord` method, the store should be able to assign IDs without saving to the persistence layer.", function(assert) { assert.expect(6); - var idCount = 1; + let idCount = 1; env.adapter.generateIdForRecord = function(passedStore, record) { assert.equal(env.store, passedStore, "store is the first parameter"); @@ -56,7 +55,7 @@ test("If an adapter implements the `generateIdForRecord` method, the store shoul } }; - var comment, post; + let comment, post; run(function() { comment = env.store.createRecord('comment'); post = env.store.createRecord('post'); @@ -75,10 +74,10 @@ test("If an adapter implements the `generateIdForRecord` method, the store shoul test("empty string and undefined ids should coerce to null", function(assert) { assert.expect(6); - var comment, post; - var idCount = 0; + let comment, post; + let idCount = 0; let id = 1; - var ids = [undefined, '']; + let ids = [undefined, '']; env.adapter.generateIdForRecord = function(passedStore, record) { assert.equal(env.store, passedStore, "store is the first parameter"); @@ -90,7 +89,7 @@ test("empty string and undefined ids should coerce to null", function(assert) { return Ember.RSVP.resolve({ data: { id: id++, type: type.modelName } }); }; - run(function() { + run(() => { comment = env.store.createRecord('misc'); post = env.store.createRecord('misc'); }); @@ -100,7 +99,7 @@ test("empty string and undefined ids should coerce to null", function(assert) { // Despite client-generated IDs, calling commit() on the store should still // invoke the adapter's `createRecord` method. - run(function() { + run(() => { comment.save(); post.save(); }); diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index a584b3f7c37..c48bb75eb7a 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -6,11 +6,10 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var env, store, User, Job, ReflexiveModel; +let env, store, User, Job, ReflexiveModel; -var attr = DS.attr; -var belongsTo = DS.belongsTo; -var run = Ember.run; +const { attr, belongsTo } = DS; +const { run } = Ember; function stringify(string) { return function() { return string; }; @@ -109,7 +108,7 @@ testInDebug("Errors out if you define 2 inverses to the same model", function(as job: belongsTo('job', { async: false }) }); - assert.expectAssertion(function() { + assert.expectAssertion(() => { User.inverseFor('job', store); }, "You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times. Look at https://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses"); }); @@ -129,9 +128,9 @@ test("Caches findInverseFor return value", function(assert) { testInDebug("Errors out if you do not define an inverse for a reflexive relationship", function(assert) { //Maybe store is evaluated lazily, so we need this :( - assert.expectWarning(function() { + assert.expectWarning(() => { var reflexiveModel; - run(function() { + run(() => { store.push({ data: { type: 'reflexive-model', diff --git a/tests/integration/lifecycle-hooks-test.js b/tests/integration/lifecycle-hooks-test.js index 69f06b8143b..d74ae1146c6 100644 --- a/tests/integration/lifecycle-hooks-test.js +++ b/tests/integration/lifecycle-hooks-test.js @@ -5,10 +5,10 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var Person, env; -var attr = DS.attr; -var resolve = Ember.RSVP.resolve; -var run = Ember.run; +let Person, env; +const { attr } = DS; +const { run } = Ember; +const { resolve } = Ember.RSVP; module("integration/lifecycle_hooks - Lifecycle Hooks", { beforeEach() { @@ -33,11 +33,8 @@ test("When the adapter acknowledges that a record has been created, a `didCreate env.adapter.createRecord = function(store, type, snapshot) { return resolve({ data: { id: 99, type: "person", attributes: { name: "Yehuda Katz" } } }); }; - var person; - run(function() { - person = env.store.createRecord('person', { name: "Yehuda Katz" }); - }); + let person = run(() => env.store.createRecord('person', { name: "Yehuda Katz" })); person.on('didCreate', function() { assert.equal(this, person, "this is bound to the record"); @@ -55,11 +52,8 @@ test("When the adapter acknowledges that a record has been created without a new env.adapter.createRecord = function(store, type, snapshot) { return Ember.RSVP.resolve(); }; - var person; - run(function() { - person = env.store.createRecord('person', { id: 99, name: "Yehuda Katz" }); - }); + let person = run(() => env.store.createRecord('person', { id: 99, name: "Yehuda Katz" })); person.on('didCreate', function() { assert.equal(this, person, "this is bound to the record"); diff --git a/tests/integration/multiple-stores-test.js b/tests/integration/multiple-stores-test.js index c7708821b92..4edd341eb10 100644 --- a/tests/integration/multiple-stores-test.js +++ b/tests/integration/multiple-stores-test.js @@ -4,9 +4,9 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; -var env; -var SuperVillain, HomePlanet, EvilMinion; -var run = Ember.run; +let env; +let SuperVillain, HomePlanet, EvilMinion; +const { run } = Ember; module("integration/multiple_stores - Multiple Stores Tests", { setup() { @@ -51,28 +51,26 @@ test("should be able to push into multiple stores", function(assert) { shouldBackgroundReloadRecord: () => false })); - var home_planet_main = { id: '1', name: 'Earth' }; - var home_planet_a = { id: '1', name: 'Mars' }; - var home_planet_b = { id: '1', name: 'Saturn' }; + let home_planet_main = { id: '1', name: 'Earth' }; + let home_planet_a = { id: '1', name: 'Mars' }; + let home_planet_b = { id: '1', name: 'Saturn' }; - run(function() { + run(() => { env.store.push(env.store.normalize('home-planet', home_planet_main)); env.store_a.push(env.store_a.normalize('home-planet', home_planet_a)); env.store_b.push(env.store_b.normalize('home-planet', home_planet_b)); }); - run(env.store, 'findRecord', 'home-planet', 1).then(assert.wait(function(homePlanet) { - assert.equal(homePlanet.get('name'), "Earth"); - })); - - run(env.store_a, 'findRecord', 'home-planet', 1).then(assert.wait(function(homePlanet) { - assert.equal(homePlanet.get('name'), "Mars"); - })); - - run(env.store_b, 'findRecord', 'home-planet', 1).then(assert.wait(function(homePlanet) { - assert.equal(homePlanet.get('name'), "Saturn"); - })); + return env.store.findRecord('home-planet', 1).then(homePlanet => { + assert.equal(homePlanet.get('name'), 'Earth'); + return env.store_a.findRecord('homePlanet', 1); + }).then(homePlanet => { + assert.equal(homePlanet.get('name'), 'Mars'); + return env.store_b.findRecord('homePlanet', 1); + }).then(homePlanet => { + assert.equal(homePlanet.get('name'), 'Saturn'); + }); }); test("embedded records should be created in multiple stores", function(assert) { @@ -82,11 +80,11 @@ test("embedded records should be created in multiple stores", function(assert) { } })); - var serializer_main = env.store.serializerFor('home-planet'); - var serializer_a = env.store_a.serializerFor('home-planet'); - var serializer_b = env.store_b.serializerFor('home-planet'); + let serializer_main = env.store.serializerFor('home-planet'); + let serializer_a = env.store_a.serializerFor('home-planet'); + let serializer_b = env.store_b.serializerFor('home-planet'); - var json_hash_main = { + let json_hash_main = { homePlanet: { id: "1", name: "Earth", @@ -97,7 +95,7 @@ test("embedded records should be created in multiple stores", function(assert) { }] } }; - var json_hash_a = { + let json_hash_a = { homePlanet: { id: "1", name: "Mars", @@ -108,7 +106,7 @@ test("embedded records should be created in multiple stores", function(assert) { }] } }; - var json_hash_b = { + let json_hash_b = { homePlanet: { id: "1", name: "Saturn", @@ -119,24 +117,23 @@ test("embedded records should be created in multiple stores", function(assert) { }] } }; - var json_main, json_a, json_b; + let json_main, json_a, json_b; - run(function() { + run(() => { json_main = serializer_main.normalizeResponse(env.store, env.store.modelFor('home-planet'), json_hash_main, 1, 'findRecord'); env.store.push(json_main); assert.equal(env.store.hasRecordForId('super-villain', "1"), true, "superVillain should exist in service:store"); }); - run(function() { + run(() => { json_a = serializer_a.normalizeResponse(env.store_a, env.store_a.modelFor('home-planet'), json_hash_a, 1, 'findRecord'); env.store_a.push(json_a); assert.equal(env.store_a.hasRecordForId("super-villain", "1"), true, "superVillain should exist in store:store-a"); }); - run(function() { + run(() => { json_b = serializer_b.normalizeResponse(env.store_b, env.store_a.modelFor('home-planet'), json_hash_b, 1, 'findRecord'); env.store_b.push(json_b); assert.equal(env.store_b.hasRecordForId("super-villain", "1"), true, "superVillain should exist in store:store-b"); }); - }); diff --git a/tests/integration/peek-all-test.js b/tests/integration/peek-all-test.js index b505d0a8a2e..2f836487f2c 100644 --- a/tests/integration/peek-all-test.js +++ b/tests/integration/peek-all-test.js @@ -5,10 +5,9 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var get = Ember.get; -var run = Ember.run; +const { get, run } = Ember; -var Person, store, array, moreArray; +let Person, store, array, moreArray; module("integration/peek-all - DS.Store#peekAll()", { beforeEach() { @@ -49,14 +48,14 @@ module("integration/peek-all - DS.Store#peekAll()", { }); test("store.peekAll('person') should return all records and should update with new ones", function(assert) { - run(function() { + run(() => { store.push(array); }); - var all = store.peekAll('person'); + let all = store.peekAll('person'); assert.equal(get(all, 'length'), 2); - run(function() { + run(() => { store.push(moreArray); }); @@ -66,7 +65,7 @@ test("store.peekAll('person') should return all records and should update with n test("Calling store.peekAll() multiple times should update immediately inside the runloop", function(assert) { assert.expect(3); - Ember.run(function() { + Ember.run(() => { assert.equal(get(store.peekAll('person'), 'length'), 0, 'should initially be empty'); store.createRecord('person', { name: "Tomster" }); assert.equal(get(store.peekAll('person'), 'length'), 1, 'should contain one person'); @@ -86,7 +85,7 @@ test("Calling store.peekAll() multiple times should update immediately inside th test("Calling store.peekAll() after creating a record should return correct data", function(assert) { assert.expect(1); - Ember.run(function() { + Ember.run(() => { store.createRecord('person', { name: "Tomster" }); assert.equal(get(store.peekAll('person'), 'length'), 1, 'should contain one person'); }); diff --git a/tests/integration/polymorphic-belongs-to-test.js b/tests/integration/polymorphic-belongs-to-test.js index 96ccd3a431c..fc1822d96a7 100644 --- a/tests/integration/polymorphic-belongs-to-test.js +++ b/tests/integration/polymorphic-belongs-to-test.js @@ -130,13 +130,11 @@ test('using store.push with a null value for a payload in relationships sets the } }; - let done = assert.async(); - book.get('author').then((author) => { + return book.get('author').then(author => { assert.equal(author.get('id'), 1); run(() => store.push(payloadThatResetsBelongToRelationship)); return book.get('author'); - }).then((author) => { + }).then(author => { assert.equal(author, null); - done(); }); }); diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index 83975e5a1e6..8e921f1d1a6 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -35,12 +35,12 @@ module('integration/record_array_manager', { }); function tap(obj, methodName, callback) { - var old = obj[methodName]; + let old = obj[methodName]; - var summary = { called: [] }; + let summary = { called: [] }; obj[methodName] = function() { - var result = old.apply(obj, arguments); + let result = old.apply(obj, arguments); if (callback) { callback.apply(obj, arguments); } diff --git a/tests/integration/record-array-test.js b/tests/integration/record-array-test.js index ed45e4e21d5..e784365e397 100644 --- a/tests/integration/record-array-test.js +++ b/tests/integration/record-array-test.js @@ -271,14 +271,13 @@ test('a loaded record is not removed from a record array when it is deleted even scumbag.deleteRecord(); }); - run(function() { + run(() => { assert.equal(tag.get('people.length'), 1, 'record is not removed from the record array'); assert.equal(tag.get('people').objectAt(0), scumbag, 'tag still has the scumbag'); }); }); test("a loaded record is not removed from both the record array and from the belongs to, even if the belongsTo side isn't defined", function(assert) { - let env = setupStore({ tag: Tag, person: Person, @@ -326,7 +325,7 @@ test("a loaded record is not removed from both the record array and from the bel tool = store.peekRecord('tool', 1); }); - run(function() { + run(() => { assert.equal(tag.get('people.length'), 1, 'record is in the record array'); assert.equal(tool.get('person'), scumbag, 'the tool belongs to the record'); }); diff --git a/tests/integration/setup-container-test.js b/tests/integration/setup-container-test.js index 6fabea2a7fe..eaaf937e554 100644 --- a/tests/integration/setup-container-test.js +++ b/tests/integration/setup-container-test.js @@ -4,12 +4,10 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var run = Ember.run; -var Store = DS.Store; -var EmberObject = Ember.Object; -var setupContainer = DS._setupContainer; +const { run, Object: EmberObject } = Ember; +const { Store, _setupContainer: setupContainer } = DS; -var container, registry, application; +let container, registry, application; /* These tests ensure that Ember Data works with Ember.js' container @@ -18,14 +16,12 @@ var container, registry, application; module("integration/setup-container - Setting up a container", { beforeEach() { - run(function() { - application = Ember.Application.create(); - }); + application = run(() => Ember.Application.create()); container = application.__container__; registry = application.__registry__; - var setupContainerArgument; + let setupContainerArgument; if (registry) { setupContainerArgument = application; } else { @@ -37,9 +33,7 @@ module("integration/setup-container - Setting up a container", { }, afterEach() { - run(function() { - application.destroy(); - }); + run(() => application.destroy()); } }); @@ -53,19 +47,19 @@ test("The store should be registered into the container as a service.", function test("If a store is instantiated, it should be made available to each controller.", function(assert) { registry.register('controller:foo', EmberObject.extend({})); - var fooController = container.lookup('controller:foo'); + let fooController = container.lookup('controller:foo'); assert.ok(fooController.get('store') instanceof Store, "the store was injected"); }); test("serializers are not returned as singletons - each lookup should return a different instance", function(assert) { - var serializer1, serializer2; + let serializer1, serializer2; serializer1 = container.lookup('serializer:-rest'); serializer2 = container.lookup('serializer:-rest'); assert.notEqual(serializer1, serializer2); }); test("adapters are not returned as singletons - each lookup should return a different instance", function(assert) { - var adapter1, adapter2; + let adapter1, adapter2; adapter1 = container.lookup('adapter:-rest'); adapter2 = container.lookup('adapter:-rest'); assert.notEqual(adapter1, adapter2); diff --git a/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js index cf125d7d797..992907ef007 100644 --- a/tests/integration/snapshot-test.js +++ b/tests/integration/snapshot-test.js @@ -5,8 +5,8 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var run = Ember.run; -var env, Post, Comment; +const { run } = Ember; +let env, Post, Comment; module("integration/snapshot - DS.Snapshot", { beforeEach() { @@ -27,7 +27,7 @@ module("integration/snapshot - DS.Snapshot", { }, afterEach() { - run(function() { + run(() => { env.store.destroy(); }); } @@ -36,7 +36,7 @@ module("integration/snapshot - DS.Snapshot", { test("record._createSnapshot() returns a snapshot", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -46,8 +46,8 @@ test("record._createSnapshot() returns a snapshot", function(assert) { } } }); - var post = env.store.peekRecord('post', 1); - var snapshot = post._createSnapshot(); + let post = env.store.peekRecord('post', 1); + let snapshot = post._createSnapshot(); assert.ok(snapshot instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); }); @@ -56,7 +56,7 @@ test("record._createSnapshot() returns a snapshot", function(assert) { test("snapshot.id, snapshot.type and snapshot.modelName returns correctly", function(assert) { assert.expect(3); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -66,8 +66,8 @@ test("snapshot.id, snapshot.type and snapshot.modelName returns correctly", func } } }); - var post = env.store.peekRecord('post', 1); - var snapshot = post._createSnapshot(); + let post = env.store.peekRecord('post', 1); + let snapshot = post._createSnapshot(); assert.equal(snapshot.id, '1', 'id is correct'); assert.ok(DS.Model.detect(snapshot.type), 'type is correct'); @@ -87,7 +87,7 @@ test('snapshot.type loads the class lazily', function(assert) { return modelFor.call(env.store, name); }; - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -109,7 +109,7 @@ test('snapshot.type loads the class lazily', function(assert) { test("snapshot.attr() does not change when record changes", function(assert) { assert.expect(2); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -119,8 +119,8 @@ test("snapshot.attr() does not change when record changes", function(assert) { } } }); - var post = env.store.peekRecord('post', 1); - var snapshot = post._createSnapshot(); + let post = env.store.peekRecord('post', 1); + let snapshot = post._createSnapshot(); assert.equal(snapshot.attr('title'), 'Hello World', 'snapshot title is correct'); post.set('title', 'Tomster'); @@ -131,7 +131,7 @@ test("snapshot.attr() does not change when record changes", function(assert) { test("snapshot.attr() throws an error attribute not found", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -141,10 +141,10 @@ test("snapshot.attr() throws an error attribute not found", function(assert) { } } }); - var post = env.store.peekRecord('post', 1); - var snapshot = post._createSnapshot(); + let post = env.store.peekRecord('post', 1); + let snapshot = post._createSnapshot(); - assert.throws(function() { + assert.throws(() => { snapshot.attr('unknown'); }, /has no attribute named 'unknown' defined/, 'attr throws error'); }); @@ -153,7 +153,7 @@ test("snapshot.attr() throws an error attribute not found", function(assert) { test("snapshot.attributes() returns a copy of all attributes for the current snapshot", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -163,10 +163,10 @@ test("snapshot.attributes() returns a copy of all attributes for the current sna } } }); - var post = env.store.peekRecord('post', 1); - var snapshot = post._createSnapshot(); + let post = env.store.peekRecord('post', 1); + let snapshot = post._createSnapshot(); - var attributes = snapshot.attributes(); + let attributes = snapshot.attributes(); assert.deepEqual(attributes, { author: undefined, title: 'Hello World' }, 'attributes are returned correctly'); }); @@ -175,7 +175,7 @@ test("snapshot.attributes() returns a copy of all attributes for the current sna test("snapshot.changedAttributes() returns a copy of all changed attributes for the current snapshot", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -185,11 +185,11 @@ test("snapshot.changedAttributes() returns a copy of all changed attributes for } } }); - var post = env.store.peekRecord('post', 1); + let post = env.store.peekRecord('post', 1); post.set('title', 'Hello World!'); - var snapshot = post._createSnapshot(); + let snapshot = post._createSnapshot(); - var changes = snapshot.changedAttributes(); + let changes = snapshot.changedAttributes(); assert.deepEqual(changes.title, ['Hello World', 'Hello World!'], 'changed attributes are returned correctly'); }); @@ -198,7 +198,7 @@ test("snapshot.changedAttributes() returns a copy of all changed attributes for test("snapshot.belongsTo() returns undefined if relationship is undefined", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: { type: 'comment', @@ -208,9 +208,9 @@ test("snapshot.belongsTo() returns undefined if relationship is undefined", func } } }); - var comment = env.store.peekRecord('comment', 1); - var snapshot = comment._createSnapshot(); - var relationship = snapshot.belongsTo('post'); + let comment = env.store.peekRecord('comment', 1); + let snapshot = comment._createSnapshot(); + let relationship = snapshot.belongsTo('post'); assert.equal(relationship, undefined, 'relationship is undefined'); }); @@ -219,7 +219,7 @@ test("snapshot.belongsTo() returns undefined if relationship is undefined", func test("snapshot.belongsTo() returns null if relationship is unset", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: [{ type: 'post', @@ -240,9 +240,9 @@ test("snapshot.belongsTo() returns null if relationship is unset", function(asse } }] }); - var comment = env.store.peekRecord('comment', 2); - var snapshot = comment._createSnapshot(); - var relationship = snapshot.belongsTo('post'); + let comment = env.store.peekRecord('comment', 2); + let snapshot = comment._createSnapshot(); + let relationship = snapshot.belongsTo('post'); assert.equal(relationship, null, 'relationship is unset'); }); @@ -251,7 +251,7 @@ test("snapshot.belongsTo() returns null if relationship is unset", function(asse test("snapshot.belongsTo() returns a snapshot if relationship is set", function(assert) { assert.expect(3); - run(function() { + run(() => { env.store.push({ data: [{ type: 'post', @@ -272,9 +272,9 @@ test("snapshot.belongsTo() returns a snapshot if relationship is set", function( } }] }); - var comment = env.store.peekRecord('comment', 2); - var snapshot = comment._createSnapshot(); - var relationship = snapshot.belongsTo('post'); + let comment = env.store.peekRecord('comment', 2); + let snapshot = comment._createSnapshot(); + let relationship = snapshot.belongsTo('post'); assert.ok(relationship instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); assert.equal(relationship.id, '1', 'post id is correct'); @@ -285,7 +285,7 @@ test("snapshot.belongsTo() returns a snapshot if relationship is set", function( test("snapshot.belongsTo() returns null if relationship is deleted", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: [{ type: 'post', @@ -306,13 +306,13 @@ test("snapshot.belongsTo() returns null if relationship is deleted", function(as } }] }); - var post = env.store.peekRecord('post', 1); - var comment = env.store.peekRecord('comment', 2); + let post = env.store.peekRecord('post', 1); + let comment = env.store.peekRecord('comment', 2); post.deleteRecord(); - var snapshot = comment._createSnapshot(); - var relationship = snapshot.belongsTo('post'); + let snapshot = comment._createSnapshot(); + let relationship = snapshot.belongsTo('post'); assert.equal(relationship, null, 'relationship unset after deleted'); }); @@ -321,7 +321,7 @@ test("snapshot.belongsTo() returns null if relationship is deleted", function(as test("snapshot.belongsTo() returns undefined if relationship is a link", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: { type: 'comment', @@ -338,9 +338,9 @@ test("snapshot.belongsTo() returns undefined if relationship is a link", functio } } }); - var comment = env.store.peekRecord('comment', 2); - var snapshot = comment._createSnapshot(); - var relationship = snapshot.belongsTo('post'); + let comment = env.store.peekRecord('comment', 2); + let snapshot = comment._createSnapshot(); + let relationship = snapshot.belongsTo('post'); assert.equal(relationship, undefined, 'relationship is undefined'); }); @@ -349,7 +349,7 @@ test("snapshot.belongsTo() returns undefined if relationship is a link", functio test("snapshot.belongsTo() throws error if relation doesn't exist", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -359,10 +359,10 @@ test("snapshot.belongsTo() throws error if relation doesn't exist", function(ass } } }); - var post = env.store.peekRecord('post', 1); - var snapshot = post._createSnapshot(); + let post = env.store.peekRecord('post', 1); + let snapshot = post._createSnapshot(); - assert.throws(function() { + assert.throws(() => { snapshot.belongsTo('unknown'); }, /has no belongsTo relationship named 'unknown'/, 'throws error'); }); @@ -375,7 +375,7 @@ test("snapshot.belongsTo() returns a snapshot if relationship link has been fetc return Ember.RSVP.resolve({ data: { id: 1, type: 'post', attributes: { title: 'Hello World' } } }); }; - run(function() { + return run(() => { env.store.push({ data: { type: 'comment', @@ -392,11 +392,11 @@ test("snapshot.belongsTo() returns a snapshot if relationship link has been fetc } } }); - var comment = env.store.peekRecord('comment', 2); + let comment = env.store.peekRecord('comment', 2); - comment.get('post').then(function(post) { - var snapshot = comment._createSnapshot(); - var relationship = snapshot.belongsTo('post'); + return comment.get('post').then(post => { + let snapshot = comment._createSnapshot(); + let relationship = snapshot.belongsTo('post'); assert.ok(relationship instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); assert.equal(relationship.id, '1', 'post id is correct'); @@ -407,7 +407,7 @@ test("snapshot.belongsTo() returns a snapshot if relationship link has been fetc test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when adding an object to a hasMany relationship", function(assert) { assert.expect(4); - run(function() { + return run(() => { env.store.push({ data: [{ type: 'post', @@ -423,17 +423,17 @@ test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when adding } }] }); - var post = env.store.peekRecord('post', 1); - var comment = env.store.peekRecord('comment', 2); + let post = env.store.peekRecord('post', 1); + let comment = env.store.peekRecord('comment', 2); - post.get('comments').then(function(comments) { + return post.get('comments').then(comments => { comments.addObject(comment); - var postSnapshot = post._createSnapshot(); - var commentSnapshot = comment._createSnapshot(); + let postSnapshot = post._createSnapshot(); + let commentSnapshot = comment._createSnapshot(); - var hasManyRelationship = postSnapshot.hasMany('comments'); - var belongsToRelationship = commentSnapshot.belongsTo('post'); + let hasManyRelationship = postSnapshot.hasMany('comments'); + let belongsToRelationship = commentSnapshot.belongsTo('post'); assert.ok(hasManyRelationship instanceof Array, 'hasMany relationship is an instance of Array'); assert.equal(hasManyRelationship.length, 1, 'hasMany relationship contains related object'); @@ -447,7 +447,7 @@ test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when adding test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when setting an object to a belongsTo relationship", function(assert) { assert.expect(4); - run(function() { + run(() => { env.store.push({ data: [{ type: 'post', @@ -463,16 +463,16 @@ test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when setting } }] }); - var post = env.store.peekRecord('post', 1); - var comment = env.store.peekRecord('comment', 2); + let post = env.store.peekRecord('post', 1); + let comment = env.store.peekRecord('comment', 2); comment.set('post', post); - var postSnapshot = post._createSnapshot(); - var commentSnapshot = comment._createSnapshot(); + let postSnapshot = post._createSnapshot(); + let commentSnapshot = comment._createSnapshot(); - var hasManyRelationship = postSnapshot.hasMany('comments'); - var belongsToRelationship = commentSnapshot.belongsTo('post'); + let hasManyRelationship = postSnapshot.hasMany('comments'); + let belongsToRelationship = commentSnapshot.belongsTo('post'); assert.ok(hasManyRelationship instanceof Array, 'hasMany relationship is an instance of Array'); assert.equal(hasManyRelationship.length, 1, 'hasMany relationship contains related object'); @@ -485,7 +485,7 @@ test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when setting test("snapshot.belongsTo() returns ID if option.id is set", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: [{ type: 'post', @@ -506,9 +506,9 @@ test("snapshot.belongsTo() returns ID if option.id is set", function(assert) { } }] }); - var comment = env.store.peekRecord('comment', 2); - var snapshot = comment._createSnapshot(); - var relationship = snapshot.belongsTo('post', { id: true }); + let comment = env.store.peekRecord('comment', 2); + let snapshot = comment._createSnapshot(); + let relationship = snapshot.belongsTo('post', { id: true }); assert.equal(relationship, '1', 'relationship ID correctly returned'); }); @@ -517,7 +517,7 @@ test("snapshot.belongsTo() returns ID if option.id is set", function(assert) { test("snapshot.belongsTo() returns null if option.id is set but relationship was deleted", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: [{ type: 'post', @@ -538,13 +538,13 @@ test("snapshot.belongsTo() returns null if option.id is set but relationship was } }] }); - var post = env.store.peekRecord('post', 1); - var comment = env.store.peekRecord('comment', 2); + let post = env.store.peekRecord('post', 1); + let comment = env.store.peekRecord('comment', 2); post.deleteRecord(); - var snapshot = comment._createSnapshot(); - var relationship = snapshot.belongsTo('post', { id: true }); + let snapshot = comment._createSnapshot(); + let relationship = snapshot.belongsTo('post', { id: true }); assert.equal(relationship, null, 'relationship unset after deleted'); }); @@ -553,7 +553,7 @@ test("snapshot.belongsTo() returns null if option.id is set but relationship was test("snapshot.hasMany() returns undefined if relationship is undefined", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -563,9 +563,9 @@ test("snapshot.hasMany() returns undefined if relationship is undefined", functi } } }); - var post = env.store.peekRecord('post', 1); - var snapshot = post._createSnapshot(); - var relationship = snapshot.hasMany('comments'); + let post = env.store.peekRecord('post', 1); + let snapshot = post._createSnapshot(); + let relationship = snapshot.hasMany('comments'); assert.equal(relationship, undefined, 'relationship is undefined'); }); @@ -574,7 +574,7 @@ test("snapshot.hasMany() returns undefined if relationship is undefined", functi test("snapshot.hasMany() returns empty array if relationship is empty", function(assert) { assert.expect(2); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -589,9 +589,9 @@ test("snapshot.hasMany() returns empty array if relationship is empty", function } } }); - var post = env.store.peekRecord('post', 1); - var snapshot = post._createSnapshot(); - var relationship = snapshot.hasMany('comments'); + let post = env.store.peekRecord('post', 1); + let snapshot = post._createSnapshot(); + let relationship = snapshot.hasMany('comments'); assert.ok(relationship instanceof Array, 'relationship is an instance of Array'); assert.equal(relationship.length, 0, 'relationship is empty'); @@ -601,7 +601,7 @@ test("snapshot.hasMany() returns empty array if relationship is empty", function test("snapshot.hasMany() returns array of snapshots if relationship is set", function(assert) { assert.expect(5); - run(function() { + run(() => { env.store.push({ data: [{ type: 'comment', @@ -631,14 +631,14 @@ test("snapshot.hasMany() returns array of snapshots if relationship is set", fun } }] }); - var post = env.store.peekRecord('post', 3); - var snapshot = post._createSnapshot(); - var relationship = snapshot.hasMany('comments'); + let post = env.store.peekRecord('post', 3); + let snapshot = post._createSnapshot(); + let relationship = snapshot.hasMany('comments'); assert.ok(relationship instanceof Array, 'relationship is an instance of Array'); assert.equal(relationship.length, 2, 'relationship has two items'); - var relationship1 = relationship[0]; + let relationship1 = relationship[0]; assert.ok(relationship1 instanceof DS.Snapshot, 'relationship item is an instance of DS.Snapshot'); @@ -650,7 +650,7 @@ test("snapshot.hasMany() returns array of snapshots if relationship is set", fun test("snapshot.hasMany() returns empty array if relationship records are deleted", function(assert) { assert.expect(2); - run(function() { + run(() => { env.store.push({ data: [{ type: 'comment', @@ -680,15 +680,15 @@ test("snapshot.hasMany() returns empty array if relationship records are deleted } }] }); - var comment1 = env.store.peekRecord('comment', 1); - var comment2 = env.store.peekRecord('comment', 2); - var post = env.store.peekRecord('post', 3); + let comment1 = env.store.peekRecord('comment', 1); + let comment2 = env.store.peekRecord('comment', 2); + let post = env.store.peekRecord('post', 3); comment1.deleteRecord(); comment2.deleteRecord(); - var snapshot = post._createSnapshot(); - var relationship = snapshot.hasMany('comments'); + let snapshot = post._createSnapshot(); + let relationship = snapshot.hasMany('comments'); assert.ok(relationship instanceof Array, 'relationship is an instance of Array'); assert.equal(relationship.length, 0, 'relationship is empty'); @@ -698,7 +698,7 @@ test("snapshot.hasMany() returns empty array if relationship records are deleted test("snapshot.hasMany() returns array of IDs if option.ids is set", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -716,9 +716,9 @@ test("snapshot.hasMany() returns array of IDs if option.ids is set", function(as } } }); - var post = env.store.peekRecord('post', 1); - var snapshot = post._createSnapshot(); - var relationship = snapshot.hasMany('comments', { ids: true }); + let post = env.store.peekRecord('post', 1); + let snapshot = post._createSnapshot(); + let relationship = snapshot.hasMany('comments', { ids: true }); assert.deepEqual(relationship, ['2', '3'], 'relationship IDs correctly returned'); }); @@ -727,7 +727,7 @@ test("snapshot.hasMany() returns array of IDs if option.ids is set", function(as test("snapshot.hasMany() returns empty array of IDs if option.ids is set but relationship records were deleted", function(assert) { assert.expect(2); - run(function() { + run(() => { env.store.push({ data: [{ type: 'comment', @@ -757,15 +757,15 @@ test("snapshot.hasMany() returns empty array of IDs if option.ids is set but rel } }] }); - var comment1 = env.store.peekRecord('comment', 1); - var comment2 = env.store.peekRecord('comment', 2); - var post = env.store.peekRecord('post', 3); + let comment1 = env.store.peekRecord('comment', 1); + let comment2 = env.store.peekRecord('comment', 2); + let post = env.store.peekRecord('post', 3); comment1.deleteRecord(); comment2.deleteRecord(); - var snapshot = post._createSnapshot(); - var relationship = snapshot.hasMany('comments', { ids: true }); + let snapshot = post._createSnapshot(); + let relationship = snapshot.hasMany('comments', { ids: true }); assert.ok(relationship instanceof Array, 'relationship is an instance of Array'); assert.equal(relationship.length, 0, 'relationship is empty'); @@ -775,7 +775,7 @@ test("snapshot.hasMany() returns empty array of IDs if option.ids is set but rel test("snapshot.hasMany() returns undefined if relationship is a link", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -792,9 +792,9 @@ test("snapshot.hasMany() returns undefined if relationship is a link", function( } } }); - var post = env.store.peekRecord('post', 1); - var snapshot = post._createSnapshot(); - var relationship = snapshot.hasMany('comments'); + let post = env.store.peekRecord('post', 1); + let snapshot = post._createSnapshot(); + let relationship = snapshot.hasMany('comments'); assert.equal(relationship, undefined, 'relationship is undefined'); }); @@ -807,7 +807,7 @@ test("snapshot.hasMany() returns array of snapshots if relationship link has bee return Ember.RSVP.resolve({ data: [{ id: 2, type: 'comment', attributes: { body: 'This is comment' } }]}); }; - run(function() { + return run(() => { env.store.push({ data: { type: 'post', @@ -824,11 +824,12 @@ test("snapshot.hasMany() returns array of snapshots if relationship link has bee } } }); - var post = env.store.peekRecord('post', 1); - post.get('comments').then(function(comments) { - var snapshot = post._createSnapshot(); - var relationship = snapshot.hasMany('comments'); + let post = env.store.peekRecord('post', 1); + + return post.get('comments').then(comments => { + let snapshot = post._createSnapshot(); + let relationship = snapshot.hasMany('comments'); assert.ok(relationship instanceof Array, 'relationship is an instance of Array'); assert.equal(relationship.length, 1, 'relationship has one item'); @@ -839,7 +840,7 @@ test("snapshot.hasMany() returns array of snapshots if relationship link has bee test("snapshot.hasMany() throws error if relation doesn't exist", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -849,10 +850,10 @@ test("snapshot.hasMany() throws error if relation doesn't exist", function(asser } } }); - var post = env.store.peekRecord('post', 1); - var snapshot = post._createSnapshot(); + let post = env.store.peekRecord('post', 1); + let snapshot = post._createSnapshot(); - assert.throws(function() { + assert.throws(() => { snapshot.hasMany('unknown'); }, /has no hasMany relationship named 'unknown'/, 'throws error'); }); @@ -861,7 +862,7 @@ test("snapshot.hasMany() throws error if relation doesn't exist", function(asser test("snapshot.hasMany() respects the order of items in the relationship", function(assert) { assert.expect(3); - run(function() { + run(() => { env.store.push({ data: [{ type: 'comment', @@ -898,14 +899,14 @@ test("snapshot.hasMany() respects the order of items in the relationship", funct } }] }); - var comment3 = env.store.peekRecord('comment', 3); - var post = env.store.peekRecord('post', 4); + let comment3 = env.store.peekRecord('comment', 3); + let post = env.store.peekRecord('post', 4); post.get('comments').removeObject(comment3); post.get('comments').insertAt(0, comment3); - var snapshot = post._createSnapshot(); - var relationship = snapshot.hasMany('comments'); + let snapshot = post._createSnapshot(); + let relationship = snapshot.hasMany('comments'); assert.equal(relationship[0].id, '3', 'order of comment 3 is correct'); assert.equal(relationship[1].id, '1', 'order of comment 1 is correct'); @@ -916,7 +917,7 @@ test("snapshot.hasMany() respects the order of items in the relationship", funct test("snapshot.eachAttribute() proxies to record", function(assert) { assert.expect(1); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -926,13 +927,11 @@ test("snapshot.eachAttribute() proxies to record", function(assert) { } } }); - var post = env.store.peekRecord('post', 1); - var snapshot = post._createSnapshot(); + let post = env.store.peekRecord('post', 1); + let snapshot = post._createSnapshot(); - var attributes = []; - snapshot.eachAttribute(function(name) { - attributes.push(name); - }); + let attributes = []; + snapshot.eachAttribute(name => attributes.push(name)); assert.deepEqual(attributes, ['author', 'title'], 'attributes are iterated correctly'); }); }); @@ -940,15 +939,13 @@ test("snapshot.eachAttribute() proxies to record", function(assert) { test("snapshot.eachRelationship() proxies to record", function(assert) { assert.expect(2); - var getRelationships = function(snapshot) { - var relationships = []; - snapshot.eachRelationship(function(name) { - relationships.push(name); - }); + let getRelationships = function(snapshot) { + let relationships = []; + snapshot.eachRelationship(name => relationships.push(name)); return relationships; }; - run(function() { + run(() => { env.store.push({ data: [{ type: 'comment', @@ -964,9 +961,9 @@ test("snapshot.eachRelationship() proxies to record", function(assert) { } }] }); - var comment = env.store.peekRecord('comment', 1); - var post = env.store.peekRecord('post', 2); - var snapshot; + let comment = env.store.peekRecord('comment', 1); + let post = env.store.peekRecord('post', 2); + let snapshot; snapshot = comment._createSnapshot(); assert.deepEqual(getRelationships(snapshot), ['post'], 'relationships are iterated correctly'); @@ -983,7 +980,7 @@ test("snapshot.belongsTo() does not trigger a call to store._scheduleFetch", fun assert.ok(false, 'store._scheduleFetch should not be called'); }; - run(function() { + run(() => { env.store.push({ data: { type: 'comment', @@ -998,8 +995,8 @@ test("snapshot.belongsTo() does not trigger a call to store._scheduleFetch", fun } } }); - var comment = env.store.peekRecord('comment', 1); - var snapshot = comment._createSnapshot(); + let comment = env.store.peekRecord('comment', 1); + let snapshot = comment._createSnapshot(); snapshot.belongsTo('post'); }); @@ -1012,7 +1009,7 @@ test("snapshot.hasMany() does not trigger a call to store._scheduleFetch", funct assert.ok(false, 'store._scheduleFetch should not be called'); }; - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -1030,8 +1027,8 @@ test("snapshot.hasMany() does not trigger a call to store._scheduleFetch", funct } } }); - var post = env.store.peekRecord('post', 1); - var snapshot = post._createSnapshot(); + let post = env.store.peekRecord('post', 1); + let snapshot = post._createSnapshot(); snapshot.hasMany('comments'); }); @@ -1040,7 +1037,7 @@ test("snapshot.hasMany() does not trigger a call to store._scheduleFetch", funct test("snapshot.serialize() serializes itself", function(assert) { assert.expect(2); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -1050,12 +1047,12 @@ test("snapshot.serialize() serializes itself", function(assert) { } } }); - var post = env.store.peekRecord('post', 1); - var snapshot = post._createSnapshot(); + let post = env.store.peekRecord('post', 1); + let snapshot = post._createSnapshot(); post.set('title', 'New Title'); - var expected = { + let expected = { data: { attributes: { author: undefined, diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 4af6741d664..f3db892465d 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -7,22 +7,31 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; import { isEnabled } from 'ember-data/-private'; -var store, env; +let store, env; -var Person = DS.Model.extend({ +const Person = DS.Model.extend({ name: DS.attr('string'), cars: DS.hasMany('car', { async: false }) }); -Person.reopenClass({ toString: () => 'Person' }); -var run = Ember.run; +Person.reopenClass({ + toString() { + return 'Person' + } +}); -var Car = DS.Model.extend({ +const { run } = Ember; +const Car = DS.Model.extend({ make: DS.attr('string'), model: DS.attr('string'), person: DS.belongsTo('person', { async: false }) }); -Car.reopenClass({ toString: () => 'Car' }); + +Car.reopenClass({ + toString() { + return 'Car'; + } +}); function initializeStore(adapter) { env = setupStore({ @@ -45,12 +54,12 @@ module("integration/store - destroy", { }); function tap(obj, methodName, callback) { - var old = obj[methodName]; + let old = obj[methodName]; - var summary = { called: [] }; + let summary = { called: [] }; obj[methodName] = function() { - var result = old.apply(obj, arguments); + let result = old.apply(obj, arguments); if (callback) { callback.apply(obj, arguments); } @@ -65,10 +74,10 @@ test("destroying record during find doesn't cause error", function(assert) { assert.expect(0); let done = assert.async(); - var TestAdapter = DS.Adapter.extend({ + let TestAdapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.run.next(function() { + return new Ember.RSVP.Promise((resolve, reject) => { + Ember.run.next(() => { store.unloadAll(type.modelName); reject(); }); @@ -78,19 +87,17 @@ test("destroying record during find doesn't cause error", function(assert) { initializeStore(TestAdapter); - var type = "car"; - var id = 1; + let type = "car"; + let id = 1; - run(function() { - store.findRecord(type, id).then(done, done); - }); + return run(() => store.findRecord(type, id).then(done, done)); }); test("find calls do not resolve when the store is destroyed", function(assert) { assert.expect(0); let done = assert.async(); - var TestAdapter = DS.Adapter.extend({ + let TestAdapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { store.destroy(); Ember.RSVP.resolve(null); @@ -100,8 +107,8 @@ test("find calls do not resolve when the store is destroyed", function(assert) { initializeStore(TestAdapter); - var type = "car"; - var id = 1; + let type = "car"; + let id = 1; store.push = function() { Ember.assert("The test should have destroyed the store by now", store.get("isDestroyed")); @@ -109,20 +116,15 @@ test("find calls do not resolve when the store is destroyed", function(assert) { throw new Error("We shouldn't be pushing data into the store when it is destroyed"); }; - run(function() { - store.findRecord(type, id); - }); + run(() => store.findRecord(type, id)); - setTimeout(function() { - done(); - }, 500); + setTimeout(() => done(), 500); }); - test("destroying the store correctly cleans everything up", function(assert) { - var car, person; + let car, person; env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: [{ type: 'car', @@ -155,37 +157,34 @@ test("destroying the store correctly cleans everything up", function(assert) { person = store.peekRecord('person', 1); }); - var personWillDestroy = tap(person, 'willDestroy'); - var carWillDestroy = tap(car, 'willDestroy'); - var carsWillDestroy = run(function() { - return tap(car.get('person.cars'), 'willDestroy'); - }); + let personWillDestroy = tap(person, 'willDestroy'); + let carWillDestroy = tap(car, 'willDestroy'); + let carsWillDestroy = run(() => tap(car.get('person.cars'), 'willDestroy')); env.adapter.query = function() { - return { data: [{ - id: 2, - type: 'person', - attributes: { name: 'Yehuda' } - }]}; + return { + data: [ + { + id: 2, + type: 'person', + attributes: { name: 'Yehuda' } + } + ] + }; }; - var adapterPopulatedPeople, filterdPeople; - run(function() { - adapterPopulatedPeople = store.query('person', { + let adapterPopulatedPeople =run(() => { + return adapterPopulatedPeople = store.query('person', { someCrazy: 'query' }); }); - run(function() { - filterdPeople = store.filter('person', function() { return true; }); - }); + let filterdPeople = run(() => store.filter('person', () => true)); - var filterdPeopleWillDestroy = tap(filterdPeople.get('content'), 'willDestroy'); - var adapterPopulatedPeopleWillDestroy = tap(adapterPopulatedPeople.get('content'), 'willDestroy'); + let filterdPeopleWillDestroy = tap(filterdPeople.get('content'), 'willDestroy'); + let adapterPopulatedPeopleWillDestroy = tap(adapterPopulatedPeople.get('content'), 'willDestroy'); - run(function() { - store.findRecord('person', 2); - }); + run(() => store.findRecord('person', 2)); assert.equal(personWillDestroy.called.length, 0, 'expected person.willDestroy to not have been called'); assert.equal(carWillDestroy.called.length, 0, 'expected car.willDestroy to not have been called'); @@ -219,8 +218,6 @@ function ajaxResponse(value) { } } - - module("integration/store - findRecord"); test("store#findRecord fetches record from server when cached record is not present", function(assert) { @@ -240,8 +237,8 @@ test("store#findRecord fetches record from server when cached record is not pres let cachedRecordIsPresent = store.hasRecordForId('car', 20); assert.ok(!cachedRecordIsPresent, 'Car with id=20 should not exist'); - run(function() { - store.findRecord('car', 20).then(function(car) { + return run(() => { + return store.findRecord('car', 20).then(car => { assert.equal(car.get('make'), 'BMC', 'Car with id=20 is now loaded'); }); }); @@ -252,7 +249,7 @@ test("store#findRecord returns cached record immediately and reloads record in t initializeStore(DS.RESTAdapter.extend()); - run(function() { + run(() => { store.push({ data: { type: 'car', @@ -273,13 +270,13 @@ test("store#findRecord returns cached record immediately and reloads record in t }] }); - run(function() { - store.findRecord('car', 1).then(function(car) { + run(() => { + return store.findRecord('car', 1).then(car => { assert.equal(car.get('model'), 'Mini', 'cached car record is returned'); }); }); - run(function() { + run(() => { let car = store.peekRecord('car', 1); assert.equal(car.get('model'), 'Princess', 'car record was reloaded'); }); @@ -296,7 +293,7 @@ test("store#findRecord { reload: true } ignores cached record and reloads record initializeStore(testAdapter); - run(function() { + run(() => { store.push({ data: { type: 'car', @@ -320,8 +317,8 @@ test("store#findRecord { reload: true } ignores cached record and reloads record let cachedCar = store.peekRecord('car', 1); assert.equal(cachedCar.get('model'), 'Mini', 'cached car has expected model'); - run(function() { - store.findRecord('car', 1, { reload: true }).then(function(car) { + return run(() => { + return store.findRecord('car', 1, { reload: true }).then(car => { assert.equal(car.get('model'), 'Princess', 'cached record ignored, record reloaded via server'); }); }); @@ -465,9 +462,9 @@ testInDebug('store#findRecord call with `id` of type different than non-empty st initializeStore(DS.RESTAdapter.extend()); - run(function() { + run(() => { badValues.map(item => { - assert.expectAssertion(function() { + assert.expectAssertion(() => { store.findRecord('car', item); }, '`id` passed to `findRecord()` has to be non-empty string or number'); }); @@ -496,11 +493,11 @@ test("Using store#findAll with no records triggers a query", function(assert) { }] }); - var cars = store.peekAll('car'); + let cars = store.peekAll('car'); assert.ok(!cars.get('length'), 'There is no cars in the store'); - run(function() { - store.findAll('car').then(function(cars) { + return run(() => { + return store.findAll('car').then(cars => { assert.equal(cars.get('length'), 2, 'Two car were fetched'); }); }); @@ -509,7 +506,7 @@ test("Using store#findAll with no records triggers a query", function(assert) { test("Using store#findAll with existing records performs a query in the background, updating existing records and returning new ones", function(assert) { assert.expect(4); - run(function() { + run(() => { store.push({ data: { type: 'car', @@ -535,21 +532,23 @@ test("Using store#findAll with existing records performs a query in the backgrou }] }); - var cars = store.peekAll('car'); + let cars = store.peekAll('car'); assert.equal(cars.get('length'), 1, 'There is one car in the store'); - run(function() { - store.findAll('car').then(function(cars) { + let waiter = run(() => { + return store.findAll('car').then(cars => { assert.equal(cars.get('length'), 1, 'Store resolves with the existing records'); }); }); - run(function() { - var cars = store.peekAll('car'); + run(() => { + let cars = store.peekAll('car'); assert.equal(cars.get('length'), 2, 'There is 2 cars in the store now'); - var mini = cars.findBy('id', '1'); + let mini = cars.findBy('id', '1'); assert.equal(mini.get('model'), 'New Mini', 'Existing records have been updated'); }); + + return waiter; }); test("store#findAll { backgroundReload: false } skips shouldBackgroundReloadAll, returns cached records & does not reload in the background", function(assert) { @@ -693,8 +692,8 @@ test("store#findAll { backgroundReload: false } is ignored if adapter.shouldRelo assert.equal(cars.get('firstObject.model'), 'Mini', 'correct car is in the store'); }); - run(() => { - store.findAll('car', { backgroundReload: false }).then((cars) => { + return run(() => { + return store.findAll('car', { backgroundReload: false }).then((cars) => { assert.equal(cars.get('length'), 2, 'multiple car records are returned'); assert.equal(cars.get('firstObject.model'), 'New Mini', 'initial car record was updated'); assert.equal(cars.get('lastObject.model'), 'Isetta', 'second car record was loaded'); @@ -705,7 +704,7 @@ test("store#findAll { backgroundReload: false } is ignored if adapter.shouldRelo test("store#findAll should eventually return all known records even if they are not in the adapter response", function(assert) { assert.expect(5); - run(function() { + run(() => { store.push({ data: [{ type: 'car', @@ -733,26 +732,28 @@ test("store#findAll should eventually return all known records even if they are }] }); - var cars = store.peekAll('car'); + let cars = store.peekAll('car'); assert.equal(cars.get('length'), 2, 'There is two cars in the store'); - run(function() { - store.findAll('car').then(function(cars) { + let waiter = run(() => { + return store.findAll('car').then(cars => { assert.equal(cars.get('length'), 2, 'It returns all cars'); - var carsInStore = store.peekAll('car'); + let carsInStore = store.peekAll('car'); assert.equal(carsInStore.get('length'), 2, 'There is 2 cars in the store'); }); }); - run(function() { - var cars = store.peekAll('car'); - var mini = cars.findBy('id', '1'); + run(() => { + let cars = store.peekAll('car'); + let mini = cars.findBy('id', '1'); assert.equal(mini.get('model'), 'New Mini', 'Existing records have been updated'); - var carsInStore = store.peekAll('car'); + let carsInStore = store.peekAll('car'); assert.equal(carsInStore.get('length'), 2, 'There is 2 cars in the store'); }); + + return waiter; }); @@ -767,7 +768,7 @@ test("Using store#fetch on an empty record calls find", function(assert) { }] }); - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -786,11 +787,11 @@ test("Using store#fetch on an empty record calls find", function(assert) { }); }); - var car = store.recordForId('car', 20); + let car = store.recordForId('car', 20); assert.ok(car.get('isEmpty'), 'Car with id=20 should be empty'); - run(function() { - store.findRecord('car', 20, { reload: true }).then(function (car) { + return run(() => { + return store.findRecord('car', 20, { reload: true }).then(car => { assert.equal(car.get('make'), 'BMCW', 'Car with id=20 is now loaded'); }); }); @@ -799,8 +800,8 @@ test("Using store#fetch on an empty record calls find", function(assert) { test("Using store#adapterFor should not throw an error when looking up the application adapter", function(assert) { assert.expect(1); - run(function() { - var applicationAdapter = store.adapterFor('application'); + run(() => { + let applicationAdapter = store.adapterFor('application'); assert.ok(applicationAdapter); }); }); @@ -809,8 +810,8 @@ test("Using store#adapterFor should not throw an error when looking up the appli test("Using store#serializerFor should not throw an error when looking up the application serializer", function(assert) { assert.expect(1); - run(function() { - var applicationSerializer = store.serializerFor('application'); + run(() => { + let applicationSerializer = store.serializerFor('application'); assert.ok(applicationSerializer); }); }); @@ -823,9 +824,9 @@ module("integration/store - deleteRecord", { test("Using store#deleteRecord should mark the model for removal", function(assert) { assert.expect(3); - var person; + let person; - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -840,21 +841,18 @@ test("Using store#deleteRecord should mark the model for removal", function(asse assert.ok(store.hasRecordForId('person', 1), 'expected the record to be in the store'); - var personDeleteRecord = tap(person, 'deleteRecord'); + let personDeleteRecord = tap(person, 'deleteRecord'); - run(function() { - store.deleteRecord(person); - }); + run(() => store.deleteRecord(person)); assert.equal(personDeleteRecord.called.length, 1, 'expected person.deleteRecord to have been called'); assert.ok(person.get('isDeleted'), 'expect person to be isDeleted'); }); - test("Store should accept a null value for `data`", function(assert) { assert.expect(0); - run(function() { + run(() => { store.push({ data: null }); @@ -863,13 +861,13 @@ test("Store should accept a null value for `data`", function(assert) { testInDebug('store#findRecord that returns an array should assert', assert => { initializeStore(DS.JSONAPIAdapter.extend({ - findRecord: function() { + findRecord() { return { data: [] }; } })); - assert.expectAssertion(function() { - run(function() { + assert.expectAssertion(() => { + run(() => { store.findRecord('car', 1); }); }, /expected the primary data returned from a 'findRecord' response to be an object but instead it found an array/); @@ -880,9 +878,9 @@ testInDebug('store#didSaveRecord should assert when the response to a save does return {}; }; - assert.expectAssertion(function() { - run(function() { - var car = store.createRecord('car'); + assert.expectAssertion(() => { + run(() => { + let car = store.createRecord('car'); car.save(); }); }, /Your car record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response./); @@ -907,10 +905,8 @@ testInDebug('store#queryRecord should assert when normalized payload of adapter }; }; - assert.expectAssertion(function() { - run(function() { - store.queryRecord('car', {}); - }); + assert.expectAssertion(() => { + run(() => store.queryRecord('car', {})); }, /Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array./); }); From 336a986a75874d04e591a290ef93f6adfcf7a844 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Sun, 2 Jul 2017 21:29:38 -0700 Subject: [PATCH 1963/2527] more cleanup --- .../adapter/build-url-mixin-test.js | 132 +-- tests/integration/adapter/find-all-test.js | 70 +- tests/integration/adapter/find-test.js | 103 +- .../adapter/json-api-adapter-test.js | 138 ++- tests/integration/adapter/queries-test.js | 28 +- .../adapter/record-persistence-test.js | 131 +-- .../integration/adapter/rest-adapter-test.js | 901 ++++++++---------- tests/integration/adapter/serialize-test.js | 11 +- .../integration/adapter/store-adapter-test.js | 435 +++++---- .../records/collection-save-test.js | 59 +- tests/integration/records/load-test.js | 13 +- .../relationships/belongs-to-test.js | 413 ++++---- .../relationships/has-many-test.js | 451 ++++----- .../relationships/many-to-many-test.js | 158 +-- 14 files changed, 1478 insertions(+), 1565 deletions(-) diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index 59a743e6824..aee911e6f6f 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -6,9 +6,9 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var env, store, adapter, Post, Comment, SuperUser; -var passedUrl; -var run = Ember.run; +let env, store, adapter, Post, Comment, SuperUser; +let passedUrl; +const { run } = Ember; module("integration/adapter/build-url-mixin - BuildURLMixin with RESTAdapter", { beforeEach() { @@ -58,7 +58,7 @@ function ajaxResponse(value) { test('buildURL - with host and namespace', function(assert) { - run(function() { + run(() => { adapter.setProperties({ host: 'http://example.com', namespace: 'api/v1' @@ -67,33 +67,34 @@ test('buildURL - with host and namespace', function(assert) { ajaxResponse({ posts: [{ id: 1 }] }); - run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', 1).then(post => { assert.equal(passedUrl, "http://example.com/api/v1/posts/1"); - })); + }); }); test('buildURL - with relative paths in links', function(assert) { - run(function() { + run(() => { adapter.setProperties({ host: 'http://example.com', namespace: 'api/v1' }); }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); ajaxResponse({ posts: [{ id: 1, links: { comments: 'comments' } }] }); - run(store, 'findRecord', 'post', '1').then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', '1').then(post => { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); - })).then(assert.wait(function (comments) { + }).then(comments => { assert.equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); - })); + }); }); test('buildURL - with absolute paths in links', function(assert) { - run(function() { + run(() => { adapter.setProperties({ host: 'http://example.com', namespace: 'api/v1' @@ -104,17 +105,17 @@ test('buildURL - with absolute paths in links', function(assert) { ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', 1).then(post => { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); - })).then(assert.wait(function (comments) { + }).then(comments => { assert.equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); - })); + }); }); test('buildURL - with absolute paths in links and protocol relative host', function(assert) { - run(function() { + run(() => { adapter.setProperties({ host: '//example.com', namespace: 'api/v1' @@ -125,16 +126,16 @@ test('buildURL - with absolute paths in links and protocol relative host', funct ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', 1).then(post => { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); - })).then(assert.wait(function (comments) { + }).then(comments => { assert.equal(passedUrl, "//example.com/api/v1/posts/1/comments"); - })); + }); }); test('buildURL - with absolute paths in links and host is /', function(assert) { - run(function() { + run(() => { adapter.setProperties({ host: '/', namespace: 'api/v1' @@ -145,12 +146,12 @@ test('buildURL - with absolute paths in links and host is /', function(assert) { ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', 1).then(post => { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); - })).then(assert.wait(function (comments) { + }).then(comments => { assert.equal(passedUrl, '/api/v1/posts/1/comments', 'host stripped out properly'); - })); + }); }); test('buildURL - with full URLs in links', function(assert) { @@ -169,30 +170,30 @@ test('buildURL - with full URLs in links', function(assert) { ] }); - run(function() { - store.findRecord('post', 1).then(assert.wait(function(post) { + return run(() => { + return store.findRecord('post', 1).then(post => { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); - })).then(assert.wait(function (comments) { + }).then(comments => { assert.equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); - })); + }); }); }); test('buildURL - with camelized names', function(assert) { adapter.setProperties({ pathForType(type) { - var decamelized = Ember.String.decamelize(type); + let decamelized = Ember.String.decamelize(type); return Ember.String.underscore(Ember.String.pluralize(decamelized)); } }); ajaxResponse({ superUsers: [{ id: 1 }] }); - run(function() { - store.findRecord('super-user', 1).then(assert.wait(function(post) { + return run(() => { + return store.findRecord('super-user', 1).then(post => { assert.equal(passedUrl, "/super_users/1"); - })); + }); }); }); @@ -204,8 +205,8 @@ test('buildURL - buildURL takes a record from find', function(assert) { ajaxResponse({ comments: [{ id: 1 }] }); - var post; - run(function() { + let post; + run(() => { post = store.push({ data: { type: 'post', @@ -214,10 +215,10 @@ test('buildURL - buildURL takes a record from find', function(assert) { }); }); - run(function() { - store.findRecord('comment', 1, { preload: { post: post } }).then(assert.wait(function(post) { + return run(() => { + return store.findRecord('comment', 1, { preload: { post: post } }).then(post => { assert.equal(passedUrl, "/posts/2/comments/1"); - })); + }); }); }); @@ -234,9 +235,9 @@ test('buildURL - buildURL takes the records from findMany', function(assert) { adapter.coalesceFindRequests = true; ajaxResponse({ comments: [{ id: 1 }, { id: 2 }, { id: 3 }] }); - var post; + let post; - run(function() { + return run(() => { post = store.push({ data: { type: 'post', @@ -252,9 +253,10 @@ test('buildURL - buildURL takes the records from findMany', function(assert) { } } }); - post.get('comments').then(assert.wait(function(post) { + + return post.get('comments').then(post => { assert.equal(passedUrl, "/posts/2/comments/"); - })); + }); }); }); @@ -266,18 +268,18 @@ test('buildURL - buildURL takes a record from create', function(assert) { ajaxResponse({ comments: [{ id: 1 }] }); - run(function() { - var post = store.push({ + return run(() => { + let post = store.push({ data: { type: 'post', id: '2' } }); - var comment = store.createRecord('comment'); + let comment = store.createRecord('comment'); comment.set('post', post); - comment.save().then(assert.wait(function(post) { + return comment.save().then(post => { assert.equal(passedUrl, "/posts/2/comments/"); - })); + }); }); }); @@ -286,8 +288,8 @@ test('buildURL - buildURL takes a record from create to query a resolved async b ajaxResponse({ posts: [{ id: 2 }] }); - run(function() { - store.findRecord('post', 2).then(assert.wait(function(post) { + return run(() => { + store.findRecord('post', 2).then(post => { assert.equal(post.get('id'), 2); adapter.buildURL = function(type, id, snapshot) { @@ -296,13 +298,12 @@ test('buildURL - buildURL takes a record from create to query a resolved async b ajaxResponse({ comments: [{ id: 1 }] }); - var comment = store.createRecord('comment'); + let comment = store.createRecord('comment'); comment.set('post', post); - comment.save().then(assert.wait(function(post) { + return comment.save().then(post => { assert.equal(passedUrl, "/posts/2/comments/"); - })); - - })); + }); + }); }); }); @@ -314,8 +315,8 @@ test('buildURL - buildURL takes a record from update', function(assert) { ajaxResponse({ comments: [{ id: 1 }] }); - var post, comment; - run(function() { + let post, comment; + run(() => { post = store.push({ data: { type: 'post', @@ -330,10 +331,11 @@ test('buildURL - buildURL takes a record from update', function(assert) { }); comment.set('post', post); }); - run(function() { - comment.save().then(assert.wait(function(post) { + + return run(() => { + return comment.save().then(post => { assert.equal(passedUrl, "/posts/2/comments/1"); - })); + }); }); }); @@ -346,8 +348,9 @@ test('buildURL - buildURL takes a record from delete', function(assert) { ajaxResponse({ comments: [{ id: 1 }] }); - var post, comment; - run(function() { + let post, comment; + + run(() => { post = store.push({ data: { type: 'post', @@ -364,15 +367,16 @@ test('buildURL - buildURL takes a record from delete', function(assert) { comment.set('post', post); comment.deleteRecord(); }); - run(function() { - comment.save().then(assert.wait(function(post) { + + return run(() => { + return comment.save().then(post => { assert.equal(passedUrl, "posts/2/comments/1"); - })); + }); }); }); test('buildURL - with absolute namespace', function(assert) { - run(function() { + run(() => { adapter.setProperties({ namespace: '/api/v1' }); @@ -380,7 +384,7 @@ test('buildURL - with absolute namespace', function(assert) { ajaxResponse({ posts: [{ id: 1 }] }); - run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', 1).then(post => { assert.equal(passedUrl, "/api/v1/posts/1"); - })); + }); }); diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index 914a4652e9d..b58f70ca5c9 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -56,12 +56,12 @@ test("When all records for a type are requested, the store should call the adapt })); return run(() => { - return store.findAll('person').then((all) => { + return store.findAll('person').then(all => { let allRecords = all; assert.equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); assert.equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); - return store.findAll('person').then((all) => { + return store.findAll('person').then(all => { // Only one record array per type should ever be created (identity map) assert.strictEqual(allRecords, all, "the same record array is returned every time all records of a type are requested"); }); @@ -92,11 +92,11 @@ test("When all records for a type are requested, a rejection should reject the p } })); - run(() => { - store.findAll('person').then(null, () => { + return run(() => { + return store.findAll('person').catch(() => { assert.ok(true, "The rejection should get here"); return store.findAll('person'); - }).then((all) => { + }).then(all => { assert.equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); assert.equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); }); @@ -163,8 +163,6 @@ testInDebug('When all records are requested, assert the payload is not blank', ( }); test("isUpdating is true while records are fetched", function(assert) { - let done = assert.async(); - let findAllDeferred = Ember.RSVP.defer(); env.registry.register('adapter:person', DS.Adapter.extend({ findAll() { @@ -174,7 +172,7 @@ test("isUpdating is true while records are fetched", function(assert) { shouldReloadAll: () => true })); - run(function() { + run(() => { store.push({ data: [{ type: 'person', @@ -186,34 +184,36 @@ test("isUpdating is true while records are fetched", function(assert) { let persons = store.peekAll('person'); assert.equal(persons.get("length"), 1); - run(function() { - store.findAll('person').then(function(persons) { + let wait = run(() => { + return store.findAll('person').then(persons => { assert.equal(persons.get("isUpdating"), false); assert.equal(persons.get("length"), 2); - - done(); }); }); assert.equal(persons.get("isUpdating"), true); findAllDeferred.resolve({ data: [{ id: 2, type: 'person' }] }); + + return wait; }); test("isUpdating is true while records are fetched in the background", function(assert) { - let done = assert.async(); - let findAllDeferred = Ember.RSVP.defer(); env.registry.register('adapter:person', DS.Adapter.extend({ findAll() { return findAllDeferred.promise; }, - shouldReloadAll: () => false, - shouldBackgroundReloadAll: () => true + shouldReloadAll() { + return false; + }, + shouldBackgroundReloadAll() { + return true; + } })); - run(function() { + run(() => { store.push({ data: [{ type: 'person', @@ -225,25 +225,23 @@ test("isUpdating is true while records are fetched in the background", function( let persons = store.peekAll('person'); assert.equal(persons.get("length"), 1); - run(function() { - store.findAll('person').then(function(persons) { + return run(() => { + return store.findAll('person').then(persons => { assert.equal(persons.get("isUpdating"), true); assert.equal(persons.get("length"), 1, "persons are updated in the background"); }); - }); + }).then(() => { + assert.equal(persons.get("isUpdating"), true); - assert.equal(persons.get("isUpdating"), true); - - run(function() { - findAllDeferred.resolve({ data: [{ id: 2, type: 'person' }] }); - }); - - run(function() { - findAllDeferred.promise.then(function() { - assert.equal(persons.get("isUpdating"), false); - assert.equal(persons.get("length"), 2); + run(() => { + findAllDeferred.resolve({ data: [{ id: 2, type: 'person' }] }); + }); - done(); + return run(() => { + return findAllDeferred.promise.then(() => { + assert.equal(persons.get("isUpdating"), false); + assert.equal(persons.get("length"), 2); + }); }); }); }); @@ -258,7 +256,7 @@ test("isUpdating is false if records are not fetched in the background", functio shouldBackgroundReloadAll: () => false })); - run(function() { + run(() => { store.push({ data: [{ type: 'person', @@ -270,11 +268,11 @@ test("isUpdating is false if records are not fetched in the background", functio let persons = store.peekAll('person'); assert.equal(persons.get("length"), 1); - run(function() { - store.findAll('person').then(function(persons) { + return run(() => { + return store.findAll('person').then(persons => { assert.equal(persons.get("isUpdating"), false); }); + }).then(() => { + assert.equal(persons.get("isUpdating"), false); }); - - assert.equal(persons.get("isUpdating"), false); }); diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 2dd54dfb1ee..17b3225768f 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -6,7 +6,7 @@ import DS from 'ember-data'; const { run } = Ember; const { attr } = DS; -const { reject } = Ember.RSVP; +const { reject, Promise } = Ember.RSVP; let Person, store, env; @@ -30,7 +30,7 @@ module("integration/adapter/find - Finding Records", { } }); -testInDebug("It raises an assertion when `undefined` is passed as id (#1705)", (assert) => { +testInDebug("It raises an assertion when `undefined` is passed as id (#1705)", function(assert) { assert.expectAssertion(() => { store.find('person', undefined); }, `You cannot pass 'undefined' as id to the store's find method`); @@ -40,10 +40,10 @@ testInDebug("It raises an assertion when `undefined` is passed as id (#1705)", ( }, `You cannot pass 'null' as id to the store's find method`); }); -test("When a single record is requested, the adapter's find method should be called unless it's loaded.", (assert) => { +test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function(assert) { assert.expect(2); - var count = 0; + let count = 0; env.registry.register('adapter:person', DS.Adapter.extend({ findRecord(_, type) { @@ -69,84 +69,79 @@ test("When a single record is requested, the adapter's find method should be cal }); }); -test("When a single record is requested multiple times, all .findRecord() calls are resolved after the promise is resolved", (assert) => { - var deferred = Ember.RSVP.defer(); +test("When a single record is requested multiple times, all .findRecord() calls are resolved after the promise is resolved", function(assert) { + let deferred = Ember.RSVP.defer(); env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord: () => deferred.promise + findRecord() { + return deferred.promise; + } })); - run(() => { - store.findRecord('person', 1).then(assert.wait(function(person) { + let requestOne = run(() => { + return store.findRecord('person', 1).then(person => { assert.equal(person.get('id'), "1"); assert.equal(person.get('name'), "Braaaahm Dale"); - - let done = assert.async(); - deferred.promise.then(() => { - assert.ok(true, 'expected deferred.promise to fulfill'); - done(); - }, () => { - assert.ok(false, 'expected deferred.promise to fulfill, but rejected'); - done(); - }); - })); + }); }); - run(() => { - store.findRecord('person', 1).then(assert.wait((post) => { + let requestTwo = run(() => { + return store.findRecord('person', 1).then(post => { assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Braaaahm Dale"); - - let done = assert.async(); - deferred.promise.then(() => { - assert.ok(true, 'expected deferred.promise to fulfill'); - done(); - }, () => { - assert.ok(false, 'expected deferred.promise to fulfill, but rejected'); - done(); - }); - - })); + }); }); - run(() => deferred.resolve({ - data: { - id: 1, - type: "person", - attributes: { - name: "Braaaahm Dale" + run(() => { + deferred.resolve({ + data: { + id: 1, + type: "person", + attributes: { + name: "Braaaahm Dale" + } } - }})); + }); + }); + + return Promise.all([ + requestOne, + requestTwo + ]) }); -test("When a single record is requested, and the promise is rejected, .findRecord() is rejected.", (assert) => { +test("When a single record is requested, and the promise is rejected, .findRecord() is rejected.", function(assert) { env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord: () => reject() + findRecord() { + return reject(); + } })); - run(() => { - store.findRecord('person', 1).then(null, assert.wait(() => { - assert.ok(true, "The rejection handler was called"); - })); + return run(() => { + return store.findRecord('person', 1).catch(() => { + assert.ok(true, 'The rejection handler was called'); + }); }); }); -test("When a single record is requested, and the promise is rejected, the record should be unloaded.", (assert) => { +test("When a single record is requested, and the promise is rejected, the record should be unloaded.", function(assert) { assert.expect(2); env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord: () => reject() + findRecord() { + return reject(); + } })); - run(() => { - store.findRecord('person', 1).then(null, assert.wait((reason) => { + return run(() => { + return store.findRecord('person', 1).catch(reason => { assert.ok(true, "The rejection handler was called"); assert.ok(!store.hasRecordForId('person', 1), "The record has been unloaded"); - })); + }); }); }); -testInDebug('When a single record is requested, and the payload is blank', (assert) => { +testInDebug('When a single record is requested, and the payload is blank', function(assert) { env.registry.register('adapter:person', DS.Adapter.extend({ findRecord: () => Ember.RSVP.resolve({}) })); @@ -156,7 +151,7 @@ testInDebug('When a single record is requested, and the payload is blank', (asse }, /You made a 'findRecord' request for a 'person' with id 'the-id', but the adapter's response did not have any data/); }); -testInDebug('When multiple records are requested, and the payload is blank', (assert) => { +testInDebug('When multiple records are requested, and the payload is blank', function(assert) { env.registry.register('adapter:person', DS.Adapter.extend({ coalesceFindRequests: true, findMany: () => Ember.RSVP.resolve({}) @@ -187,7 +182,5 @@ testInDebug("warns when returned record has different id", function(assert) { assert.expectWarning(/You requested a record of type 'person' with id 'me' but the adapter returned a payload with primary data having an id of '1'/); - run(function() { - env.store.findRecord('person', 'me'); - }); + return run(() => env.store.findRecord('person', 'me')); }); diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index dcf9ab82661..313fc0ee939 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -7,12 +7,12 @@ import testInDebug from 'dummy/tests/helpers/test-in-debug'; import DS from 'ember-data'; import { isEnabled } from 'ember-data/-private'; -var env, store, adapter; -var passedUrl, passedVerb, passedHash; +let env, store, adapter; +let passedUrl, passedVerb, passedHash; -var run = Ember.run; +const { run } = Ember; -var User, Post, Comment, Handle, GithubHandle, TwitterHandle, Company, DevelopmentShop, DesignStudio; +let User, Post, Comment, Handle, GithubHandle, TwitterHandle, Company, DevelopmentShop, DesignStudio; module('integration/adapter/json-api-adapter - JSONAPIAdapter', { beforeEach() { @@ -84,8 +84,8 @@ module('integration/adapter/json-api-adapter - JSONAPIAdapter', { }); function ajaxResponse(responses) { - var counter = 0; - var index; + let counter = 0; + let index; passedUrl = []; passedVerb = []; @@ -127,8 +127,8 @@ test('find a single record', function(assert) { } }]); - run(function() { - store.findRecord('post', 1).then(function(post) { + return run(() => { + return store.findRecord('post', 1).then(post => { assert.equal(passedUrl[0], '/posts/1'); assert.equal(post.get('id'), '1'); @@ -192,8 +192,8 @@ test('find all records with sideloaded relationships', function(assert) { }] }]); - run(function() { - store.findAll('post').then(function(posts) { + return run(() => { + return store.findAll('post').then(posts => { assert.equal(passedUrl[0], '/posts'); assert.equal(posts.get('length'), '2'); @@ -224,8 +224,8 @@ test('find many records', function(assert) { }] }]); - run(function() { - store.query('post', { filter: { id: 1 } }).then(function(posts) { + return run(() => { + return store.query('post', { filter: { id: 1 } }).then(posts => { assert.equal(passedUrl[0], '/posts'); assert.deepEqual(passedHash[0], { data: { filter: { id: 1 } } }); @@ -246,8 +246,8 @@ test('queryRecord - primary data being a single record', function(assert) { } }]); - run(function() { - store.queryRecord('post', {}).then(function(post) { + return run(() => { + return store.queryRecord('post', {}).then(post => { assert.equal(passedUrl[0], '/posts'); assert.equal(post.get('title'), 'Ember.js rocks'); @@ -260,8 +260,8 @@ test('queryRecord - primary data being null', function(assert) { data: null }]); - run(function() { - store.queryRecord('post', {}).then(function(post) { + return run(() => { + return store.queryRecord('post', {}).then(post => { assert.equal(passedUrl[0], '/posts'); assert.strictEqual(post, null); @@ -277,10 +277,8 @@ testInDebug('queryRecord - primary data being an array throws an assertion', fun }] }]); - assert.expectAssertion(function() { - run(function() { - store.queryRecord('post', {}); - }); + assert.expectAssertion(() => { + run(() => store.queryRecord('post', {})); }, "Expected the primary data returned by the serializer for a `queryRecord` response to be a single object but instead it was an array."); }); @@ -313,14 +311,14 @@ test('find a single record with belongsTo link as object { related }', function( } }]); - run(function() { - store.findRecord('post', 1).then(function(post) { + return run(() => { + return store.findRecord('post', 1).then(post => { assert.equal(passedUrl[0], '/posts/1'); assert.equal(post.get('id'), '1'); assert.equal(post.get('title'), 'Ember.js rocks'); - post.get('author').then(function(author) { + return post.get('author').then(author => { assert.equal(passedUrl[1], 'http://example.com/user/2'); assert.equal(author.get('id'), '2'); @@ -358,14 +356,14 @@ test('find a single record with belongsTo link as object { data }', function(ass } }]); - run(function() { - store.findRecord('post', 1).then(function(post) { + return run(() => { + return store.findRecord('post', 1).then(post => { assert.equal(passedUrl[0], '/posts/1'); assert.equal(post.get('id'), '1'); assert.equal(post.get('title'), 'Ember.js rocks'); - post.get('author').then(function(author) { + return post.get('author').then(author => { assert.equal(passedUrl[1], '/users/2'); assert.equal(author.get('id'), '2'); @@ -404,15 +402,15 @@ test('find a single record with belongsTo link as object { data } (polymorphic)' } }]); - run(function() { - store.findRecord('user', 1).then(function(user) { + return run(() => { + return store.findRecord('user', 1).then(user => { assert.equal(passedUrl[0], '/users/1'); assert.equal(user.get('id'), '1'); assert.equal(user.get('firstName'), 'Yehuda'); assert.equal(user.get('lastName'), 'Katz'); - user.get('company').then(function(company) { + return user.get('company').then(company => { assert.equal(passedUrl[1], '/development-shops/2'); assert.equal(company.get('id'), '2'); @@ -449,15 +447,14 @@ test('find a single record with sideloaded belongsTo link as object { data }', f }] }]); - run(function() { - - store.findRecord('post', 1).then(function(post) { + return run(() => { + return store.findRecord('post', 1).then(post => { assert.equal(passedUrl[0], '/posts/1'); assert.equal(post.get('id'), '1'); assert.equal(post.get('title'), 'Ember.js rocks'); - post.get('author').then(function(author) { + return post.get('author').then(author => { assert.equal(passedUrl.length, 1); assert.equal(author.get('id'), '2'); @@ -502,14 +499,14 @@ test('find a single record with hasMany link as object { related }', function(as }] }]); - run(function() { - store.findRecord('post', 1).then(function(post) { + return run(() => { + return store.findRecord('post', 1).then(post => { assert.equal(passedUrl[0], '/posts/1'); assert.equal(post.get('id'), '1'); assert.equal(post.get('title'), 'Ember.js rocks'); - post.get('comments').then(function(comments) { + return post.get('comments').then(comments => { assert.equal(passedUrl[1], 'http://example.com/post/1/comments'); assert.equal(comments.get('length'), 2); @@ -557,14 +554,14 @@ test('find a single record with hasMany link as object { data }', function(asser } }]); - run(function() { - store.findRecord('post', 1).then(function(post) { + return run(() => { + return store.findRecord('post', 1).then(post => { assert.equal(passedUrl[0], '/posts/1'); assert.equal(post.get('id'), '1'); assert.equal(post.get('title'), 'Ember.js rocks'); - post.get('comments').then(function(comments) { + return post.get('comments').then(comments => { assert.equal(passedUrl[1], '/comments/2'); assert.equal(passedUrl[2], '/comments/3'); @@ -614,15 +611,15 @@ test('find a single record with hasMany link as object { data } (polymorphic)', } }]); - run(function() { - store.findRecord('user', 1).then(function(user) { + return run(() => { + return store.findRecord('user', 1).then(user => { assert.equal(passedUrl[0], '/users/1'); assert.equal(user.get('id'), '1'); assert.equal(user.get('firstName'), 'Yehuda'); assert.equal(user.get('lastName'), 'Katz'); - user.get('handles').then(function(handles) { + return user.get('handles').then(handles => { assert.equal(passedUrl[1], '/github-handles/2'); assert.equal(passedUrl[2], '/twitter-handles/3'); @@ -668,14 +665,14 @@ test('find a single record with sideloaded hasMany link as object { data }', fun }] }]); - run(function() { - store.findRecord('post', 1).then(function(post) { + return run(() => { + return store.findRecord('post', 1).then(post => { assert.equal(passedUrl[0], '/posts/1'); assert.equal(post.get('id'), '1'); assert.equal(post.get('title'), 'Ember.js rocks'); - post.get('comments').then(function(comments) { + return post.get('comments').then(comments => { assert.equal(passedUrl.length, 1); assert.equal(comments.get('length'), 2); @@ -721,15 +718,15 @@ test('find a single record with sideloaded hasMany link as object { data } (poly }] }]); - run(function() { - store.findRecord('user', 1).then(function(user) { + return run(() => { + return store.findRecord('user', 1).then(user => { assert.equal(passedUrl[0], '/users/1'); assert.equal(user.get('id'), '1'); assert.equal(user.get('firstName'), 'Yehuda'); assert.equal(user.get('lastName'), 'Katz'); - user.get('handles').then(function(handles) { + return user.get('handles').then(handles => { assert.equal(passedUrl.length, 1); assert.equal(handles.get('length'), 2); @@ -750,9 +747,9 @@ test('create record', function(assert) { } }]); - run(function() { + return run(() => { - var company = store.push({ data: { + let company = store.push({ data: { type: 'company', id: '1', attributes: { @@ -760,7 +757,7 @@ test('create record', function(assert) { } } }); - var githubHandle = store.push({ data: { + let githubHandle = store.push({ data: { type: 'github-handle', id: '2', attributes: { @@ -768,16 +765,16 @@ test('create record', function(assert) { } } }); - var user = store.createRecord('user', { + let user = store.createRecord('user', { firstName: 'Yehuda', lastName: 'Katz', company: company }); - user.get('handles').then(function(handles) { + return user.get('handles').then(handles => { handles.addObject(githubHandle); - user.save().then(function() { + return user.save().then(() => { assert.equal(passedUrl[0], '/users'); assert.equal(passedVerb[0], 'POST'); assert.deepEqual(passedHash[0], { @@ -811,8 +808,8 @@ test('update record', function(assert) { } }]); - run(function() { - var user = store.push({ data: { + return run(() => { + let user = store.push({ data: { type: 'user', id: '1', attributes: { @@ -821,7 +818,7 @@ test('update record', function(assert) { } } }); - var company = store.push({ data: { + let company = store.push({ data: { type: 'company', id: '2', attributes: { @@ -829,7 +826,7 @@ test('update record', function(assert) { } } }); - var githubHandle = store.push({ data: { + let githubHandle = store.push({ data: { type: 'github-handle', id: '3', attributes: { @@ -840,10 +837,10 @@ test('update record', function(assert) { user.set('firstName', 'Yehuda!'); user.set('company', company); - user.get('handles').then(function(handles) { + return user.get('handles').then(handles => { handles.addObject(githubHandle); - user.save().then(function() { + return user.save().then(() => { assert.equal(passedUrl[0], '/users/1'); assert.equal(passedVerb[0], 'PATCH'); assert.deepEqual(passedHash[0], { @@ -864,7 +861,6 @@ test('update record', function(assert) { } }); }); - }); }); }); @@ -885,8 +881,8 @@ test('update record - serialize hasMany', function(assert) { } })); - run(function() { - var user = store.push({ data: { + return run(() => { + let user = store.push({ data: { type: 'user', id: '1', attributes: { @@ -895,7 +891,7 @@ test('update record - serialize hasMany', function(assert) { } } }); - var githubHandle = store.push({ data: { + let githubHandle = store.push({ data: { type: 'github-handle', id: '2', attributes: { @@ -903,7 +899,7 @@ test('update record - serialize hasMany', function(assert) { } } }); - var twitterHandle = store.push({ data: { + let twitterHandle = store.push({ data: { type: 'twitter-handle', id: '3', attributes: { @@ -913,11 +909,11 @@ test('update record - serialize hasMany', function(assert) { user.set('firstName', 'Yehuda!'); - user.get('handles').then(function(handles) { + return user.get('handles').then(handles => { handles.addObject(githubHandle); handles.addObject(twitterHandle); - user.save().then(function() { + return user.save().then(() => { assert.equal(passedUrl[0], '/users/1'); assert.equal(passedVerb[0], 'PATCH'); assert.deepEqual(passedHash[0], { @@ -941,7 +937,6 @@ test('update record - serialize hasMany', function(assert) { } }); }); - }); }); }); @@ -968,12 +963,11 @@ test('fetching a belongsTo relationship link that returns null', function(assert data: null }]); - run(function() { - store.findRecord('post', 1).then(function(post) { + return run(() => { + return store.findRecord('post', 1).then(post => { assert.equal(passedUrl[0], '/posts/1'); return post.get('author'); - - }).then(function(author) { + }).then(author => { assert.equal(passedUrl[1], 'http://example.com/post/1/author'); assert.equal(author, null); }); diff --git a/tests/integration/adapter/queries-test.js b/tests/integration/adapter/queries-test.js index 7797127e98c..fcfed256fb0 100644 --- a/tests/integration/adapter/queries-test.js +++ b/tests/integration/adapter/queries-test.js @@ -6,9 +6,9 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var get = Ember.get; -var Person, env, store, adapter; -var run = Ember.run; +const { get, run } = Ember; + +let Person, env, store, adapter; module("integration/adapter/queries - Queries", { beforeEach() { @@ -30,13 +30,13 @@ module("integration/adapter/queries - Queries", { }); testInDebug("It raises an assertion when no type is passed", function(assert) { - assert.expectAssertion(function() { + assert.expectAssertion(() => { store.query(); }, "You need to pass a model name to the store's query method"); }); testInDebug("It raises an assertion when no query hash is passed", function(assert) { - assert.expectAssertion(function() { + assert.expectAssertion(() => { store.query('person'); }, "You need to pass a query hash to the store's query method"); }); @@ -45,7 +45,7 @@ test("When a query is made, the adapter should receive a record array it can pop adapter.query = function(store, type, query, recordArray) { assert.equal(type, Person, "the query method is called with the correct type"); - return Ember.RSVP.resolve({ + return Ember.RSVP.Promise.resolve({ data: [ { id: 1, @@ -65,13 +65,13 @@ test("When a query is made, the adapter should receive a record array it can pop }); } - store.query('person', { page: 1 }).then(assert.wait(function(queryResults) { + return store.query('person', { page: 1 }).then(queryResults => { assert.equal(get(queryResults, 'length'), 2, "the record array has a length of 2 after the results are loaded"); assert.equal(get(queryResults, 'isLoaded'), true, "the record array's `isLoaded` property should be true"); assert.equal(queryResults.objectAt(0).get('name'), "Peter Wagenet", "the first record is 'Peter Wagenet'"); assert.equal(queryResults.objectAt(1).get('name'), "Brohuda Katz", "the second record is 'Brohuda Katz'"); - })); + }); }); test("a query can be updated via `update()`", function(assert) { @@ -79,8 +79,8 @@ test("a query can be updated via `update()`", function(assert) { return Ember.RSVP.resolve({ data: [{ id: 'first', type: 'person' }] }); }; - run(function() { - store.query('person', {}).then(function(query) { + return run(() => { + return store.query('person', {}).then(query => { assert.equal(query.get('length'), 1); assert.equal(query.get('firstObject.id'), 'first'); assert.equal(query.get('isUpdating'), false); @@ -96,7 +96,7 @@ test("a query can be updated via `update()`", function(assert) { return updateQuery; - }).then(function(query) { + }).then(query => { assert.equal(query.get('length'), 1); assert.equal(query.get('firstObject.id'), 'second'); @@ -116,9 +116,7 @@ testInDebug("The store asserts when query is made and the adapter responses with return Ember.RSVP.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Peter Wagenet" } }] }); }; - assert.expectAssertion(function() { - Ember.run(function() { - store.query('person', { page: 1 }); - }); + assert.expectAssertion(() => { + Ember.run(() => store.query('person', { page: 1 })); }, /The response to store.query is expected to be an array but it was a single record/); }); diff --git a/tests/integration/adapter/record-persistence-test.js b/tests/integration/adapter/record-persistence-test.js index 3a4091bd5e3..ac7047ef8c8 100644 --- a/tests/integration/adapter/record-persistence-test.js +++ b/tests/integration/adapter/record-persistence-test.js @@ -2,17 +2,13 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import {module, test} from 'qunit'; - import DS from 'ember-data'; -var get = Ember.get; -var set = Ember.set; -var attr = DS.attr; -var Person, env, store; -var run = Ember.run; +const { get, set, run, RSVP } = Ember; +const { all, hash } = RSVP; +const { attr } = DS; -var all = Ember.RSVP.all; -var hash = Ember.RSVP.hash; +let Person, env, store; module("integration/adapter/record_persistence - Persisting Records", { beforeEach() { @@ -47,7 +43,7 @@ test("When a store is committed, the adapter's `commit` method should be called return run(Ember.RSVP, 'resolve'); }; - run(function() { + run(() => { env.store.push({ data: { type: 'person', @@ -59,20 +55,20 @@ test("When a store is committed, the adapter's `commit` method should be called }); }); - var tom; + let tom; - run(function() { - env.store.findRecord('person', 1).then(assert.wait(function(person) { + return run(() => { + return env.store.findRecord('person', 1).then(person => { tom = person; set(tom, "name", "Tom Dale"); - tom.save(); - })); + return tom.save(); + }); }); }); test("When a store is committed, the adapter's `commit` method should be called with records that have been created.", function(assert) { assert.expect(2); - var tom; + let tom; env.adapter.createRecord = function(store, type, snapshot) { assert.equal(type, Person, "the type is correct"); @@ -81,26 +77,28 @@ test("When a store is committed, the adapter's `commit` method should be called return Ember.RSVP.resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale" } } }); }; - run(function() { + return run(() => { tom = env.store.createRecord('person', { name: "Tom Dale" }); - tom.save(); + return tom.save(); }); }); test("After a created record has been assigned an ID, finding a record by that ID returns the original record.", function(assert) { assert.expect(1); - var tom; + let tom; env.adapter.createRecord = function(store, type, snapshot) { return Ember.RSVP.resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale" } } }); }; - run(function() { + return run(() => { tom = env.store.createRecord('person', { name: "Tom Dale" }); - tom.save(); + return tom.save(); + }).then(tom => { + return env.store.find('person', 1).then(nextTom => { + assert.equal(tom, nextTom, "the retrieved record is the same as the created record"); + }); }); - - assert.asyncEqual(tom, env.store.findRecord('person', 1), "the retrieved record is the same as the created record"); }); test("when a store is committed, the adapter's `commit` method should be called with records that have been deleted.", function(assert) { @@ -111,9 +109,9 @@ test("when a store is committed, the adapter's `commit` method should be called return run(Ember.RSVP, 'resolve'); }; - var tom; + let tom; - run(function() { + run(() => { env.store.push({ data: { type: 'person', @@ -124,25 +122,26 @@ test("when a store is committed, the adapter's `commit` method should be called } }); }); - env.store.findRecord('person', 1).then(assert.wait(function(person) { + + return env.store.findRecord('person', 1).then(person => { tom = person; tom.deleteRecord(); return tom.save(); - })).then(assert.wait(function(tom) { + }).then(tom => { assert.equal(get(tom, 'isDeleted'), true, "record is marked as deleted"); - })); + }); }); test("An adapter can notify the store that records were updated by calling `didSaveRecords`.", function(assert) { assert.expect(6); - var tom, yehuda; + let tom, yehuda; env.adapter.updateRecord = function(store, type, snapshot) { return Ember.RSVP.resolve(); }; - run(function() { + run(() => { env.store.push({ data: [{ type: 'person', @@ -154,8 +153,11 @@ test("An adapter can notify the store that records were updated by calling `didS }); }); - all([env.store.findRecord('person', 1), env.store.findRecord('person', 2)]) - .then(assert.wait(function(array) { + return all([ + env.store.findRecord('person', 1), + env.store.findRecord('person', 2) + ]) + .then(array => { tom = array[0]; yehuda = array[1]; @@ -165,14 +167,19 @@ test("An adapter can notify the store that records were updated by calling `didS assert.ok(tom.get('hasDirtyAttributes'), "tom is dirty"); assert.ok(yehuda.get('hasDirtyAttributes'), "yehuda is dirty"); - assert.assertClean(tom.save()).then(assert.wait(function(record) { + let savedTom = assert.assertClean(tom.save()).then(record => { assert.equal(record, tom, "The record is correct"); - })); + }); - assert.assertClean(yehuda.save()).then(assert.wait(function(record) { + let savedYehuda = assert.assertClean(yehuda.save()).then(record => { assert.equal(record, yehuda, "The record is correct"); - })); - })); + }); + + return all([ + savedTom, + savedYehuda + ]); + }); }); test("An adapter can notify the store that records were updated and provide new data by calling `didSaveRecords`.", function(assert) { @@ -184,7 +191,7 @@ test("An adapter can notify the store that records were updated and provide new } }; - run(function() { + run(() => { env.store.push({ data: [{ type: 'person', @@ -202,17 +209,23 @@ test("An adapter can notify the store that records were updated and provide new }); }); - hash({ tom: env.store.findRecord('person', 1), yehuda: env.store.findRecord('person', 2) }).then(assert.wait(function(people) { + return hash({ + tom: env.store.findRecord('person', 1), + yehuda: env.store.findRecord('person', 2) + }).then(people => { people.tom.set('name', "Draaaaaahm Dale"); people.yehuda.set('name', "Goy Katz"); - return hash({ tom: people.tom.save(), yehuda: people.yehuda.save() }); - })).then(assert.wait(function(people) { + return hash({ + tom: people.tom.save(), + yehuda: people.yehuda.save() + }); + }).then(people => { assert.equal(people.tom.get('name'), "Tom Dale", "name attribute should reflect value of hash passed to didSaveRecords"); assert.equal(people.tom.get('updatedAt'), "now", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); assert.equal(people.yehuda.get('name'), "Yehuda Katz", "name attribute should reflect value of hash passed to didSaveRecords"); assert.equal(people.yehuda.get('updatedAt'), "now!", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); - })); + }); }); test("An adapter can notify the store that a record was updated by calling `didSaveRecord`.", function(assert) { @@ -220,7 +233,7 @@ test("An adapter can notify the store that a record was updated by calling `didS return Ember.RSVP.resolve(); }; - run(function() { + run(() => { store.push({ data: [{ type: 'person', @@ -232,7 +245,10 @@ test("An adapter can notify the store that a record was updated by calling `didS }); }); - hash({ tom: store.findRecord('person', 1), yehuda: store.findRecord('person', 2) }).then(assert.wait(function(people) { + return hash({ + tom: store.findRecord('person', 1), + yehuda: store.findRecord('person', 2) + }).then(people => { people.tom.set('name', "Tom Dale"); people.yehuda.set('name', "Yehuda Katz"); @@ -241,8 +257,7 @@ test("An adapter can notify the store that a record was updated by calling `didS assert.assertClean(people.tom.save()); assert.assertClean(people.yehuda.save()); - })); - + }); }); test("An adapter can notify the store that a record was updated and provide new data by calling `didSaveRecord`.", function(assert) { @@ -255,7 +270,7 @@ test("An adapter can notify the store that a record was updated and provide new } }; - run(function() { + run(() => { env.store.push({ data: [{ type: 'person', @@ -273,18 +288,23 @@ test("An adapter can notify the store that a record was updated and provide new }); }); - hash({ tom: store.findRecord('person', 1), yehuda: store.findRecord('person', 2) }).then(assert.wait(function(people) { + return hash({ + tom: store.findRecord('person', 1), + yehuda: store.findRecord('person', 2) + }).then(people => { people.tom.set('name', "Draaaaaahm Dale"); people.yehuda.set('name', "Goy Katz"); - return hash({ tom: people.tom.save(), yehuda: people.yehuda.save() }); - })).then(assert.wait(function(people) { + return hash({ + tom: people.tom.save(), + yehuda: people.yehuda.save() + }); + }).then(people => { assert.equal(people.tom.get('name'), "Tom Dale", "name attribute should reflect value of hash passed to didSaveRecords"); assert.equal(people.tom.get('updatedAt'), "now", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); assert.equal(people.yehuda.get('name'), "Yehuda Katz", "name attribute should reflect value of hash passed to didSaveRecords"); assert.equal(people.yehuda.get('updatedAt'), "now!", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); - })); - + }); }); test("An adapter can notify the store that records were deleted by calling `didSaveRecords`.", function(assert) { @@ -292,7 +312,7 @@ test("An adapter can notify the store that records were deleted by calling `didS return Ember.RSVP.resolve(); }; - run(function() { + run(() => { env.store.push({ data: [{ type: 'person', @@ -310,11 +330,14 @@ test("An adapter can notify the store that records were deleted by calling `didS }); }); - hash({ tom: store.findRecord('person', 1), yehuda: store.findRecord('person', 2) }).then(assert.wait(function(people) { + return hash({ + tom: store.findRecord('person', 1), + yehuda: store.findRecord('person', 2) + }).then(people => { people.tom.deleteRecord(); people.yehuda.deleteRecord(); assert.assertClean(people.tom.save()); assert.assertClean(people.yehuda.save()); - })); + }); }); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index ca66a32330c..403b14e4545 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -9,10 +9,11 @@ import Pretender from "pretender"; import DS from 'ember-data'; import { isEnabled } from 'ember-data/-private'; -var env, store, adapter, Post, Comment, SuperUser; -var passedUrl, passedVerb, passedHash; -var run = Ember.run; -var get = Ember.get; +let env, store, adapter, Post, Comment, SuperUser; +let passedUrl, passedVerb, passedHash; +const { run, get } = Ember; +let originalAjax = Ember.$.ajax; +let server; module("integration/adapter/rest_adapter - REST Adapter", { beforeEach() { @@ -37,6 +38,14 @@ module("integration/adapter/rest_adapter - REST Adapter", { adapter = env.adapter; passedUrl = passedVerb = passedHash = null; + }, + afterEach() { + Ember.$.ajax = originalAjax; + + if (server) { + server.shutdown(); + server = null; + } } }); @@ -63,14 +72,14 @@ function ajaxResponse(value) { test("findRecord - basic payload", function(assert) { ajaxResponse({ posts: [{ id: 1, name: "Rails is omakase" }] }); - run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', 1).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.deepEqual(passedHash.data, {}); assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); - })); + }); }); @@ -82,22 +91,22 @@ test("findRecord - passes buildURL a requestType", function(assert) { ajaxResponse({ posts: [{ id: 1, name: "Rails is omakase" }] }); - run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', 1).then(post => { assert.equal(passedUrl, "/findRecord/post/1"); - })); + }); }); test("findRecord - basic payload (with legacy singular name)", function(assert) { ajaxResponse({ post: { id: 1, name: "Rails is omakase" } }); - run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', 1).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.deepEqual(passedHash.data, {}); assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); - })); + }); }); test("findRecord - payload with sideloaded records of the same type", function(assert) { @@ -108,7 +117,7 @@ test("findRecord - payload with sideloaded records of the same type", function(a ] }); - run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', 1).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.deepEqual(passedHash.data, {}); @@ -116,10 +125,10 @@ test("findRecord - payload with sideloaded records of the same type", function(a assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); - var post2 = store.peekRecord('post', 2); + let post2 = store.peekRecord('post', 2); assert.equal(post2.get('id'), "2"); assert.equal(post2.get('name'), "The Parley Letter"); - })); + }); }); test("findRecord - payload with sideloaded records of a different type", function(assert) { @@ -128,7 +137,7 @@ test("findRecord - payload with sideloaded records of a different type", functio comments: [{ id: 1, name: "FIRST" }] }); - run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', 1).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.deepEqual(passedHash.data, {}); @@ -136,10 +145,10 @@ test("findRecord - payload with sideloaded records of a different type", functio assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); - var comment = store.peekRecord('comment', 1); + let comment = store.peekRecord('comment', 1); assert.equal(comment.get('id'), "1"); assert.equal(comment.get('name'), "FIRST"); - })); + }); }); @@ -150,14 +159,14 @@ test("findRecord - payload with an serializer-specified primary key", function(a ajaxResponse({ posts: [{ "_ID_": 1, name: "Rails is omakase" }] }); - run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', 1).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.deepEqual(passedHash.data, {}); assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); - })); + }); }); test("findRecord - payload with a serializer-specified attribute mapping", function(assert) { @@ -174,7 +183,7 @@ test("findRecord - payload with a serializer-specified attribute mapping", funct ajaxResponse({ posts: [{ id: 1, _NAME_: "Rails is omakase", _CREATED_AT_: 2013 }] }); - run(store, 'findRecord', 'post', 1).then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', 1).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.deepEqual(passedHash.data, {}); @@ -182,7 +191,7 @@ test("findRecord - payload with a serializer-specified attribute mapping", funct assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); assert.equal(post.get('createdAt'), 2013); - })); + }); }); test("findRecord - passes `include` as a query parameter to ajax", function(assert) { @@ -190,25 +199,24 @@ test("findRecord - passes `include` as a query parameter to ajax", function(asse post: { id: 1, name: 'Rails is very expensive sushi' } }); - run(store, 'findRecord', 'post', 1, { include: 'comments' }).then(assert.wait(function() { + return run(store, 'findRecord', 'post', 1, { include: 'comments' }).then(() => { assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` parameter sent to adapter.ajax'); - })); + }); }); test("createRecord - an empty payload is a basic success if an id was specified", function(assert) { ajaxResponse(); - var post; - run(function() { - post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); - post.save().then(assert.wait(function(post) { + return run(() => { + let post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); + return post.save().then(post => { assert.equal(passedUrl, "/posts"); assert.equal(passedVerb, "POST"); assert.deepEqual(passedHash.data, { post: { id: "some-uuid", name: "The Parley Letter" } }); assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); assert.equal(post.get('name'), "The Parley Letter", "the post was updated"); - })); + }); }); }); @@ -218,22 +226,22 @@ test("createRecord - passes buildURL the requestType", function(assert) { }; ajaxResponse(); - var post; - run(function() { - post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); - post.save().then(assert.wait(function(post) { + return run(() => { + let post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); + return post.save().then(post => { assert.equal(passedUrl, "/post/createRecord"); - })); + }); }); }); test("createRecord - a payload with a new ID and data applies the updates", function(assert) { ajaxResponse({ posts: [{ id: "1", name: "Dat Parley Letter" }] }); - run(function() { - var post = store.createRecord('post', { name: "The Parley Letter" }); - post.save().then(assert.wait(function(post) { + return run(() => { + let post = store.createRecord('post', { name: "The Parley Letter" }); + + return post.save().then(post => { assert.equal(passedUrl, "/posts"); assert.equal(passedVerb, "POST"); assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); @@ -241,18 +249,18 @@ test("createRecord - a payload with a new ID and data applies the updates", func assert.equal(post.get('id'), "1", "the post has the updated ID"); assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); - })); + }); }); }); test("createRecord - a payload with a new ID and data applies the updates (with legacy singular name)", function(assert) { - var post; + let post; ajaxResponse({ post: { id: "1", name: "Dat Parley Letter" } }); run(function() { post = store.createRecord('post', { name: "The Parley Letter" }); }); - run(post, 'save').then(assert.wait(function(post) { + return run(post, 'save').then(post => { assert.equal(passedUrl, "/posts"); assert.equal(passedVerb, "POST"); assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); @@ -260,17 +268,16 @@ test("createRecord - a payload with a new ID and data applies the updates (with assert.equal(post.get('id'), "1", "the post has the updated ID"); assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); - })); + }); }); test("createRecord - findMany doesn't overwrite owner", function(assert) { ajaxResponse({ comment: { id: "1", name: "Dat Parley Letter", post: 1 } }); - var comment; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -286,29 +293,27 @@ test("createRecord - findMany doesn't overwrite owner", function(assert) { } }); }); - var post = store.peekRecord('post', 1); + let post = store.peekRecord('post', 1); - run(function() { - comment = store.createRecord('comment', { name: "The Parley Letter" }); - }); + let comment = run(() => store.createRecord('comment', { name: "The Parley Letter" })); - run(function() { + run(() => { post.get('comments').pushObject(comment); assert.equal(comment.get('post'), post, "the post has been set correctly"); }); - run(function() { - comment.save().then(assert.wait(function(comment) { + return run(() => { + return comment.save().then(comment => { assert.equal(comment.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); assert.equal(comment.get('name'), "Dat Parley Letter", "the post was updated"); assert.equal(comment.get('post'), post, "the post is still set"); - })); + }); }); }); test("createRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { - var post; + let post; env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_id_', @@ -319,17 +324,17 @@ test("createRecord - a serializer's primary key and attributes are consulted whe ajaxResponse(); - run(function() { + run(() => { post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); }); - run(post, 'save').then(assert.wait(function(post) { + return run(post, 'save').then(post => { assert.deepEqual(passedHash.data, { post: { _id_: 'some-uuid', '_name_': "The Parley Letter" } }); - })); + }); }); test("createRecord - a serializer's attributes are consulted when building the payload if no id is pre-defined", function(assert) { - var post; + let post; env.registry.register('serializer:post', DS.RESTSerializer.extend({ attrs: { name: '_name_' @@ -340,12 +345,12 @@ test("createRecord - a serializer's attributes are consulted when building the p post: { '_name_': "The Parley Letter", id: '1' } }); - run(function() { + return run(() => { post = store.createRecord('post', { name: "The Parley Letter" }); - post.save().then(assert.wait(function(post) { + return post.save().then(post => { assert.deepEqual(passedHash.data, { post: { '_name_': "The Parley Letter" } }); - })); + }); }); }); @@ -362,12 +367,12 @@ test("createRecord - a serializer's attribute mapping takes precedence over keyF ajaxResponse(); - run(function() { - var post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); + return run(() => { + let post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); - post.save().then(assert.wait(function(post) { + return post.save().then(post => { assert.deepEqual(passedHash.data, { post: { 'given_name': "The Parley Letter", id: "some-uuid" } }); - })); + }); }); }); @@ -386,13 +391,13 @@ test("createRecord - a serializer's attribute mapping takes precedence over keyF Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - run(function() { - var post = store.createRecord('post', { id: "a-post-id", name: "The Parley Letter" }); - var comment = store.createRecord('comment', { id: "some-uuid", name: "Letters are fun", post: post }); + return run(() => { + let post = store.createRecord('post', { id: "a-post-id", name: "The Parley Letter" }); + let comment = store.createRecord('comment', { id: "some-uuid", name: "Letters are fun", post: post }); - comment.save().then(assert.wait(function(post) { + return comment.save().then(post => { assert.deepEqual(passedHash.data, { comment: { article: "a-post-id", id: "some-uuid", name: "Letters are fun" } }); - })); + }); }); }); @@ -411,13 +416,13 @@ test("createRecord - a serializer's attribute mapping takes precedence over keyF Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); - run(function() { - var comment = store.createRecord('comment', { id: "a-comment-id", name: "First!" }); - var post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter", comments: [comment] }); + return run(() => { + let comment = store.createRecord('comment', { id: "a-comment-id", name: "First!" }); + let post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter", comments: [comment] }); - post.save().then(assert.wait(function(post) { + return post.save().then(post => { assert.deepEqual(passedHash.data, { post: { opinions: ["a-comment-id"], id: "some-uuid", name: "The Parley Letter" } }); - })); + }); }); }); @@ -451,7 +456,7 @@ test("createRecord - a record on the many side of a hasMany relationship should Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -484,34 +489,31 @@ test("createRecord - a record on the many side of a hasMany relationship should }); }); - var post = store.peekRecord('post', 1); - var commentCount = run(function() { - return post.get('comments.length'); - }); + let post = store.peekRecord('post', 1); + let commentCount = run(() => post.get('comments.length')); assert.equal(commentCount, 1, "the post starts life with a comment"); - run(function() { - var comment = store.createRecord('comment', { name: "Another Comment", post: post }); + return run(() => { + let comment = store.createRecord('comment', { name: "Another Comment", post: post }); - comment.save().then(assert.wait(function(comment) { + return comment.save().then(comment => { assert.equal(comment.get('post'), post, "the comment is related to the post"); - })); - - post.reload().then(assert.wait(function(post) { - assert.equal(post.get('comments.length'), 2, "Post comment count has been updated"); - })); + return post.reload().then(post => { + assert.equal(post.get('comments.length'), 2, "Post comment count has been updated"); + }); + }); }); }); test("createRecord - sideloaded belongsTo relationships are both marked as loaded", function(assert) { assert.expect(4); - var post; + let post; Post.reopen({ comment: DS.belongsTo('comment', { async: false }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - run(function() { + run(() => { post = store.createRecord('post', { name: "man" }); }); @@ -520,13 +522,13 @@ test("createRecord - sideloaded belongsTo relationships are both marked as loade comments: [{ id: 1, post: 1, name: "Comcast is a bargain" }] }); - run(function() { - post.save().then(assert.wait(function(record) { + return run(() => { + return post.save().then(record => { assert.equal(store.peekRecord('post', 1).get('comment.isLoaded'), true, "post's comment isLoaded (via store)"); assert.equal(store.peekRecord('comment', 1).get('post.isLoaded'), true, "comment's post isLoaded (via store)"); assert.equal(record.get('comment.isLoaded'), true, "post's comment isLoaded (via record)"); assert.equal(record.get('comment.post.isLoaded'), true, "post's comment's post isLoaded (via record)"); - })); + }); }); }); @@ -549,38 +551,38 @@ test("createRecord - response can contain relationships the client doesn't yet k Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - var post; - run(function() { + let post; + run(() => { post = store.createRecord('post', { name: "Rails is omakase" }); }); - run(function() { - post.save().then(assert.wait(function(post) { + return run(() => { + return post.save().then(post => { assert.equal(post.get('comments.firstObject.post'), post, "the comments are related to the correct post model"); assert.equal(store._internalModelsFor('post').models.length, 1, "There should only be one post record in the store"); - var postRecords = store._internalModelsFor('post').models; + let postRecords = store._internalModelsFor('post').models; for (var i = 0; i < postRecords.length; i++) { assert.equal(post, postRecords[i].getRecord(), "The object in the identity map is the same"); } - })); + }); }); }); test("createRecord - relationships are not duplicated", function(assert) { - var post, comment; + let post, comment; Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - run(function() { + run(() => { post = store.createRecord('post', { name: "Tomtomhuda" }); comment = store.createRecord('comment', { id: 2, name: "Comment title" }); }); ajaxResponse({ post: [{ id: 1, name: "Rails is omakase", comments: [] }] }); - run(post, 'save').then(assert.wait(function(post) { + return run(post, 'save').then(post => { assert.equal(post.get('comments.length'), 0, "post has 0 comments"); post.get('comments').pushObject(comment); assert.equal(post.get('comments.length'), 1, "post has 1 comment"); @@ -591,13 +593,13 @@ test("createRecord - relationships are not duplicated", function(assert) { }); return post.save(); - })).then(assert.wait(function(post) { + }).then(post => { assert.equal(post.get('comments.length'), 1, "post has 1 comment"); - })); + }); }); test("updateRecord - an empty payload is a basic success", function(assert) { - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -609,19 +611,19 @@ test("updateRecord - an empty payload is a basic success", function(assert) { }); }); - run(function() { - var post = store.peekRecord('post', 1); + return run(() => { + let post = store.peekRecord('post', 1); ajaxResponse(); post.set('name', "The Parley Letter"); - post.save().then(assert.wait(function(post) { + return post.save().then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "PUT"); assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); assert.equal(post.get('name'), "The Parley Letter", "the post was updated"); - })); + }); }); }); @@ -631,7 +633,7 @@ test("updateRecord - passes the requestType to buildURL", function(assert) { }; adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -643,21 +645,21 @@ test("updateRecord - passes the requestType to buildURL", function(assert) { }); }); - run(function() { - store.findRecord('post', 1).then(assert.wait(function(post) { + return run(() => { + return store.findRecord('post', 1).then(post => { ajaxResponse(); post.set('name', "The Parley Letter"); return post.save(); - })).then(assert.wait(function(post) { + }).then(post => { assert.equal(passedUrl, "/posts/1/updateRecord"); - })); + }); }); }); test("updateRecord - a payload with updates applies the updates", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -669,24 +671,24 @@ test("updateRecord - a payload with updates applies the updates", function(asser }); }); - store.findRecord('post', 1).then(assert.wait(function(post) { + return store.findRecord('post', 1).then(post => { ajaxResponse({ posts: [{ id: 1, name: "Dat Parley Letter" }] }); post.set('name', "The Parley Letter"); return post.save(); - })).then(assert.wait(function(post) { + }).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "PUT"); assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); - })); + }); }); test("updateRecord - a payload with updates applies the updates (with legacy singular name)", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -698,30 +700,31 @@ test("updateRecord - a payload with updates applies the updates (with legacy sin }); }); - store.findRecord('post', 1).then(assert.wait(function(post) { + return store.findRecord('post', 1).then(post =>{ ajaxResponse({ post: { id: 1, name: "Dat Parley Letter" } }); post.set('name', "The Parley Letter"); return post.save(); - })).then(assert.wait(function(post) { + }).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "PUT"); assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); - })); + }); }); test("updateRecord - a payload with sideloaded updates pushes the updates", function(assert) { - var post; + let post; ajaxResponse({ posts: [{ id: 1, name: "Dat Parley Letter" }], comments: [{ id: 1, name: "FIRST" }] }); - run(function() { + + return run(() => { post = store.createRecord('post', { name: "The Parley Letter" }); - post.save().then(assert.wait(function(post) { + return post.save().then(post => { assert.equal(passedUrl, "/posts"); assert.equal(passedVerb, "POST"); assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); @@ -730,15 +733,15 @@ test("updateRecord - a payload with sideloaded updates pushes the updates", func assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); - var comment = store.peekRecord('comment', 1); + let comment = store.peekRecord('comment', 1); assert.equal(comment.get('name'), "FIRST", "The comment was sideloaded"); - })); + }); }); }); test("updateRecord - a payload with sideloaded updates pushes the updates", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -750,7 +753,7 @@ test("updateRecord - a payload with sideloaded updates pushes the updates", func }); }); - store.findRecord('post', 1).then(assert.wait(function(post) { + return store.findRecord('post', 1).then(post => { ajaxResponse({ posts: [{ id: 1, name: "Dat Parley Letter" }], comments: [{ id: 1, name: "FIRST" }] @@ -758,7 +761,7 @@ test("updateRecord - a payload with sideloaded updates pushes the updates", func post.set('name', "The Parley Letter"); return post.save(); - })).then(assert.wait(function(post) { + }).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "PUT"); assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); @@ -766,9 +769,9 @@ test("updateRecord - a payload with sideloaded updates pushes the updates", func assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); - var comment = store.peekRecord('comment', 1); + let comment = store.peekRecord('comment', 1); assert.equal(comment.get('name'), "FIRST", "The comment was sideloaded"); - })); + }); }); test("updateRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { @@ -781,7 +784,7 @@ test("updateRecord - a serializer's primary key and attributes are consulted whe } })); - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -790,14 +793,15 @@ test("updateRecord - a serializer's primary key and attributes are consulted whe } }); }); + ajaxResponse(); - store.findRecord('post', 1).then(assert.wait(function(post) { + return store.findRecord('post', 1).then(post => { post.set('name', "The Parley Letter"); return post.save(); - })).then(assert.wait(function(post) { + }).then(post => { assert.deepEqual(passedHash.data, { post: { '_name_': "The Parley Letter" } }); - })); + }); }); test("updateRecord - hasMany relationships faithfully reflect simultaneous adds and removes", function(assert) { @@ -805,7 +809,7 @@ test("updateRecord - hasMany relationships faithfully reflect simultaneous adds Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -841,26 +845,26 @@ test("updateRecord - hasMany relationships faithfully reflect simultaneous adds posts: { id: 1, name: "Not everyone uses Rails", comments: [2] } }); - store.findRecord('comment', 2).then(assert.wait(function() { + return store.findRecord('comment', 2).then(() => { return store.findRecord('post', 1); - })).then(assert.wait(function(post) { - var newComment = store.peekRecord('comment', 2); - var comments = post.get('comments'); + }).then(post => { + let newComment = store.peekRecord('comment', 2); + let comments = post.get('comments'); // Replace the comment with a new one comments.popObject(); comments.pushObject(newComment); return post.save(); - })).then(assert.wait(function(post) { + }).then(post => { assert.equal(post.get('comments.length'), 1, "the post has the correct number of comments"); assert.equal(post.get('comments.firstObject.name'), "Yes. Yes it is.", "the post has the correct comment"); - })); + }); }); test("deleteRecord - an empty payload is a basic success", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -872,19 +876,19 @@ test("deleteRecord - an empty payload is a basic success", function(assert) { }); }); - store.findRecord('post', 1).then(assert.wait(function(post) { + return store.findRecord('post', 1).then(post => { ajaxResponse(); post.deleteRecord(); return post.save(); - })).then(assert.wait(function(post) { + }).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "DELETE"); assert.equal(passedHash, undefined); assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); assert.equal(post.get('isDeleted'), true, "the post is now deleted"); - })); + }); }); test("deleteRecord - passes the requestType to buildURL", function(assert) { @@ -893,7 +897,7 @@ test("deleteRecord - passes the requestType to buildURL", function(assert) { return "/posts/" + id + "/" + requestType; }; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -905,19 +909,19 @@ test("deleteRecord - passes the requestType to buildURL", function(assert) { }); }); - store.findRecord('post', 1).then(assert.wait(function(post) { + return store.findRecord('post', 1).then(post => { ajaxResponse(); post.deleteRecord(); return post.save(); - })).then(assert.wait(function(post) { + }).then(post => { assert.equal(passedUrl, "/posts/1/deleteRecord"); - })); + }); }); test("deleteRecord - a payload with sideloaded updates pushes the updates", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -929,12 +933,12 @@ test("deleteRecord - a payload with sideloaded updates pushes the updates", func }); }); - store.findRecord('post', 1).then(assert.wait(function(post) { + return store.findRecord('post', 1).then(post => { ajaxResponse({ comments: [{ id: 1, name: "FIRST" }] }); post.deleteRecord(); return post.save(); - })).then(assert.wait(function(post) { + }).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "DELETE"); assert.equal(passedHash, undefined); @@ -942,14 +946,14 @@ test("deleteRecord - a payload with sideloaded updates pushes the updates", func assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); assert.equal(post.get('isDeleted'), true, "the post is now deleted"); - var comment = store.peekRecord('comment', 1); + let comment = store.peekRecord('comment', 1); assert.equal(comment.get('name'), "FIRST", "The comment was sideloaded"); - })); + }); }); test("deleteRecord - a payload with sidloaded updates pushes the updates when the original record is omitted", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -961,12 +965,12 @@ test("deleteRecord - a payload with sidloaded updates pushes the updates when th }); }); - store.findRecord('post', 1).then(assert.wait(function(post) { + return store.findRecord('post', 1).then(post => { ajaxResponse({ posts: [{ id: 2, name: "The Parley Letter" }] }); post.deleteRecord(); return post.save(); - })).then(assert.wait(function(post) { + }).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "DELETE"); assert.equal(passedHash, undefined); @@ -974,27 +978,24 @@ test("deleteRecord - a payload with sidloaded updates pushes the updates when th assert.equal(post.get('hasDirtyAttributes'), false, "the original post isn't dirty anymore"); assert.equal(post.get('isDeleted'), true, "the original post is now deleted"); - var newPost = store.peekRecord('post', 2); + let newPost = store.peekRecord('post', 2); assert.equal(newPost.get('name'), "The Parley Letter", "The new post was added to the store"); - })); + }); }); test("deleteRecord - deleting a newly created record should not throw an error", function(assert) { - var post; - run(function() { - post = store.createRecord('post'); - }); + let post = run(() => store.createRecord('post')); - run(function() { + return run(() => { post.deleteRecord(); - post.save().then(assert.wait(function(post) { + return post.save().then(post => { assert.equal(passedUrl, null, "There is no ajax call to delete a record that has never been saved."); assert.equal(passedVerb, null, "There is no ajax call to delete a record that has never been saved."); assert.equal(passedHash, null, "There is no ajax call to delete a record that has never been saved."); assert.equal(post.get('isDeleted'), true, "the post is now deleted"); assert.equal(post.get('isError'), false, "the post is not an error"); - })); + }); }); }); @@ -1006,13 +1007,13 @@ test("findAll - returning an array populates the array", function(assert) { ] }); - store.findAll('post').then(assert.wait(function(posts) { + return store.findAll('post').then(posts => { assert.equal(passedUrl, "/posts"); assert.equal(passedVerb, "GET"); assert.deepEqual(passedHash.data, {}); - var post1 = store.peekRecord('post', 1); - var post2 = store.peekRecord('post', 2); + let post1 = store.peekRecord('post', 1); + let post2 = store.peekRecord('post', 2); assert.deepEqual( post1.getProperties('id', 'name'), @@ -1033,7 +1034,7 @@ test("findAll - returning an array populates the array", function(assert) { [post1, post2], "The correct records are in the array" ); - })); + }); }); @@ -1052,9 +1053,9 @@ test("findAll - passes buildURL the requestType and snapshot", function(assert) ] }); - store.findAll('post', { adapterOptions: adapterOptionsStub }).then(assert.wait(function(posts) { + return store.findAll('post', { adapterOptions: adapterOptionsStub }).then(posts => { assert.equal(passedUrl, "/findAll/posts"); - })); + }); }); test("findAll - passed `include` as a query parameter to ajax", function(assert) { @@ -1062,9 +1063,9 @@ test("findAll - passed `include` as a query parameter to ajax", function(assert) posts: [{ id: 1, name: 'Rails is very expensive sushi' }] }); - run(store, 'findAll', 'post', { include: 'comments' }).then(assert.wait(function() { + return run(store, 'findAll', 'post', { include: 'comments' }).then(() => { assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` params sent to adapter.ajax'); - })); + }); }); test("findAll - returning sideloaded data loads the data", function(assert) { @@ -1075,11 +1076,11 @@ test("findAll - returning sideloaded data loads the data", function(assert) { ], comments: [{ id: 1, name: "FIRST" }] }); - store.findAll('post').then(assert.wait(function(posts) { - var comment = store.peekRecord('comment', 1); + return store.findAll('post').then(posts => { + let comment = store.peekRecord('comment', 1); assert.deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); - })); + }); }); test("findAll - data is normalized through custom serializers", function(assert) { @@ -1095,9 +1096,9 @@ test("findAll - data is normalized through custom serializers", function(assert) ] }); - store.findAll('post').then(assert.wait(function(posts) { - var post1 = store.peekRecord('post', 1); - var post2 = store.peekRecord('post', 2); + return store.findAll('post').then(posts => { + let post1 = store.peekRecord('post', 1); + let post2 = store.peekRecord('post', 2); assert.deepEqual( post1.getProperties('id', 'name'), @@ -1117,7 +1118,7 @@ test("findAll - data is normalized through custom serializers", function(assert) [post1, post2], "The correct records are in the array" ); - })); + }); }); test("query - if `sortQueryParams` option is not provided, query params are sorted alphabetically", function(assert) { @@ -1125,9 +1126,9 @@ test("query - if `sortQueryParams` option is not provided, query params are sort posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(assert.wait(function() { + return store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(() => { assert.deepEqual(Object.keys(passedHash.data), ["in", "order", "params", "wrong"], 'query params are received in alphabetical order'); - })); + }); }); test("query - passes buildURL the requestType", function(assert) { @@ -1139,9 +1140,9 @@ test("query - passes buildURL the requestType", function(assert) { posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(assert.wait(function() { + return store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(() => { assert.equal(passedUrl, '/query/posts'); - })); + }); }); test("query - if `sortQueryParams` is falsey, query params are not sorted at all", function(assert) { @@ -1151,9 +1152,9 @@ test("query - if `sortQueryParams` is falsey, query params are not sorted at all adapter.sortQueryParams = null; - store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(assert.wait(function() { + return store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(() => { assert.deepEqual(Object.keys(passedHash.data), ["params", "in", "wrong", "order"], 'query params are received in their original order'); - })); + }); }); test("query - if `sortQueryParams` is a custom function, query params passed through that function", function(assert) { @@ -1162,9 +1163,9 @@ test("query - if `sortQueryParams` is a custom function, query params passed thr }); adapter.sortQueryParams = function(obj) { - var sortedKeys = Object.keys(obj).sort().reverse(); - var len = sortedKeys.length; - var newQueryParams = {}; + let sortedKeys = Object.keys(obj).sort().reverse(); + let len = sortedKeys.length; + let newQueryParams = {}; for (var i = 0; i < len; i++) { newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]]; @@ -1172,9 +1173,9 @@ test("query - if `sortQueryParams` is a custom function, query params passed thr return newQueryParams; }; - store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(assert.wait(function() { + return store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(() => { assert.deepEqual(Object.keys(passedHash.data), ["wrong", "params", "order", "in"], 'query params are received in reverse alphabetical order'); - })); + }); }); test("query - payload 'meta' is accessible on the record array", function(assert) { @@ -1183,13 +1184,13 @@ test("query - payload 'meta' is accessible on the record array", function(assert posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - store.query('post', { page: 2 }).then(assert.wait(function(posts) { + return store.query('post', { page: 2 }).then(posts => { assert.equal( posts.get('meta.offset'), 5, "Reponse metadata can be accessed with recordArray.meta" ); - })); + }); }); test("query - each record array can have it's own meta object", function(assert) { @@ -1198,7 +1199,7 @@ test("query - each record array can have it's own meta object", function(assert) posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - store.query('post', { page: 2 }).then(assert.wait(function(posts) { + return store.query('post', { page: 2 }).then(posts => { assert.equal( posts.get('meta.offset'), 5, @@ -1208,11 +1209,12 @@ test("query - each record array can have it's own meta object", function(assert) meta: { offset: 1 }, posts: [{ id: 1, name: "Rails is very expensive sushi" }] }); - store.query('post', { page: 1 }).then(assert.wait(function(newPosts) { + + return store.query('post', { page: 1 }).then(newPosts => { assert.equal(newPosts.get('meta.offset'), 1, 'new array has correct metadata'); assert.equal(posts.get('meta.offset'), 5, 'metadata on the old array hasnt been clobbered'); - })); - })); + }); + }); }); @@ -1223,13 +1225,13 @@ test("query - returning an array populates the array", function(assert) { { id: 2, name: "The Parley Letter" }] }); - store.query('post', { page: 1 }).then(assert.wait(function(posts) { + return store.query('post', { page: 1 }).then(posts => { assert.equal(passedUrl, '/posts'); assert.equal(passedVerb, 'GET'); assert.deepEqual(passedHash.data, { page: 1 }); - var post1 = store.peekRecord('post', 1); - var post2 = store.peekRecord('post', 2); + let post1 = store.peekRecord('post', 1); + let post2 = store.peekRecord('post', 2); assert.deepEqual( post1.getProperties('id', 'name'), @@ -1249,7 +1251,7 @@ test("query - returning an array populates the array", function(assert) { [post1, post2], "The correct records are in the array" ); - })); + }); }); test("query - returning sideloaded data loads the data", function(assert) { @@ -1261,11 +1263,11 @@ test("query - returning sideloaded data loads the data", function(assert) { comments: [{ id: 1, name: "FIRST" }] }); - store.query('post', { page: 1 }).then(assert.wait(function(posts) { - var comment = store.peekRecord('comment', 1); + return store.query('post', { page: 1 }).then(posts => { + let comment = store.peekRecord('comment', 1); assert.deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); - })); + }); }); test("query - data is normalized through custom serializers", function(assert) { @@ -1279,9 +1281,9 @@ test("query - data is normalized through custom serializers", function(assert) { { _ID_: 2, _NAME_: "The Parley Letter" }] }); - store.query('post', { page: 1 }).then(assert.wait(function(posts) { - var post1 = store.peekRecord('post', 1); - var post2 = store.peekRecord('post', 2); + return store.query('post', { page: 1 }).then(posts => { + let post1 = store.peekRecord('post', 1); + let post2 = store.peekRecord('post', 2); assert.deepEqual( post1.getProperties('id', 'name'), @@ -1302,15 +1304,15 @@ test("query - data is normalized through custom serializers", function(assert) { [post1, post2], "The correct records are in the array" ); - })); + }); }); test("queryRecord - empty response", function(assert) { ajaxResponse({}); - store.queryRecord('post', { slug: 'ember-js-rocks' }).then(assert.wait(function(post) { + return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { assert.strictEqual(post, null); - })); + }); }); test("queryRecord - primary data being null", function(assert) { @@ -1318,9 +1320,9 @@ test("queryRecord - primary data being null", function(assert) { post: null }); - store.queryRecord('post', { slug: 'ember-js-rocks' }).then(assert.wait(function(post) { + return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { assert.strictEqual(post, null); - })); + }); }); test("queryRecord - primary data being a single object", function(assert) { @@ -1331,9 +1333,9 @@ test("queryRecord - primary data being a single object", function(assert) { } }); - store.queryRecord('post', { slug: 'ember-js-rocks' }).then(assert.wait(function(post) { + return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { assert.deepEqual(post.get('name'), "Ember.js rocks"); - })); + }); }); test("queryRecord - returning sideloaded data loads the data", function(assert) { @@ -1342,11 +1344,11 @@ test("queryRecord - returning sideloaded data loads the data", function(assert) comments: [{ id: 1, name: "FIRST" }] }); - store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(assert.wait(function(post) { - var comment = store.peekRecord('comment', 1); + return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { + let comment = store.peekRecord('comment', 1); assert.deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); - })); + }); }); testInDebug("queryRecord - returning an array picks the first one but saves all records to the store", function(assert) { @@ -1356,46 +1358,34 @@ testInDebug("queryRecord - returning an array picks the first one but saves all assert.expectDeprecation('The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record.'); - run(function() { - store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(assert.wait(function(post) { - var post2 = store.peekRecord('post', 2); + return run(() => { + return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { + let post2 = store.peekRecord('post', 2); assert.deepEqual(post.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }); assert.deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "Ember is js" }); - })); + }); }); }); testInDebug("queryRecord - returning an array is deprecated", function(assert) { - let done = assert.async(); - ajaxResponse({ post: [{ id: 1, name: "Rails is omakase" }, { id: 2, name: "Ember is js" }] }); assert.expectDeprecation('The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record.'); - run(function() { - store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(function() { - done(); - }); - }); + return run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })); }); testInDebug("queryRecord - returning an single object doesn't throw a deprecation", function(assert) { - let done = assert.async(); - ajaxResponse({ post: { id: 1, name: "Rails is omakase" } }); assert.expectNoDeprecation(); - run(function() { - store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(function() { - done(); - }); - }); + return run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })); }); test("queryRecord - data is normalized through custom serializers", function(assert) { @@ -1408,21 +1398,20 @@ test("queryRecord - data is normalized through custom serializers", function(ass post: { _ID_: 1, _NAME_: "Rails is omakase" } }); - store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(assert.wait(function(post) { - + return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { assert.deepEqual( post.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }, "Post 1 is loaded with correct data" ); - })); + }); }); test("findMany - findMany uses a correct URL to access the records", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -1443,7 +1432,7 @@ test("findMany - findMany uses a correct URL to access the records", function(as }); }); - var post = store.peekRecord('post', 1); + let post = store.peekRecord('post', 1); ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1451,10 +1440,11 @@ test("findMany - findMany uses a correct URL to access the records", function(as { id: 3, name: "What is omakase?" } ] }); - run(post, 'get', 'comments').then(assert.wait(function(comments) { + + return run(post, 'get', 'comments').then(comments => { assert.equal(passedUrl, "/comments"); assert.deepEqual(passedHash, { data: { ids: ["1", "2", "3"] } }); - })); + }); }); test("findMany - passes buildURL the requestType", function(assert) { @@ -1465,7 +1455,7 @@ test("findMany - passes buildURL the requestType", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -1486,7 +1476,7 @@ test("findMany - passes buildURL the requestType", function(assert) { }); }); - var post = store.peekRecord('post', 1); + let post = store.peekRecord('post', 1); ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1494,15 +1484,16 @@ test("findMany - passes buildURL the requestType", function(assert) { { id: 3, name: "What is omakase?" } ] }); - run(post, 'get', 'comments').then(assert.wait(function(comments) { + + return run(post, 'get', 'comments').then(comments => { assert.equal(passedUrl, "/findMany/comment"); - })); + }); }); test("findMany - findMany does not coalesce by default", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -1523,7 +1514,7 @@ test("findMany - findMany does not coalesce by default", function(assert) { }); }); - var post = store.peekRecord('post', 1); + let post = store.peekRecord('post', 1); //It's still ok to return this even without coalescing because RESTSerializer supports sideloading ajaxResponse({ comments: [ @@ -1532,10 +1523,11 @@ test("findMany - findMany does not coalesce by default", function(assert) { { id: 3, name: "What is omakase?" } ] }); - run(post, 'get', 'comments').then(assert.wait(function(comments) { + + return run(post, 'get', 'comments').then(comments => { assert.equal(passedUrl, "/comments/3"); assert.deepEqual(passedHash.data, {}); - })); + }); }); test("findMany - returning an array populates the array", function(assert) { @@ -1543,7 +1535,7 @@ test("findMany - returning an array populates the array", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -1564,7 +1556,7 @@ test("findMany - returning an array populates the array", function(assert) { }); }); - store.findRecord('post', 1).then(assert.wait(function(post) { + return store.findRecord('post', 1).then(post => { ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1574,10 +1566,10 @@ test("findMany - returning an array populates the array", function(assert) { }); return post.get('comments'); - })).then(assert.wait(function(comments) { - var comment1 = store.peekRecord('comment', 1); - var comment2 = store.peekRecord('comment', 2); - var comment3 = store.peekRecord('comment', 3); + }).then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); assert.deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); assert.deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); @@ -1588,7 +1580,7 @@ test("findMany - returning an array populates the array", function(assert) { [comment1, comment2, comment3], "The correct records are in the array" ); - })); + }); }); test("findMany - returning sideloaded data loads the data", function(assert) { @@ -1596,7 +1588,7 @@ test("findMany - returning sideloaded data loads the data", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -1617,7 +1609,7 @@ test("findMany - returning sideloaded data loads the data", function(assert) { }); }); - store.findRecord('post', 1).then(assert.wait(function(post) { + return store.findRecord('post', 1).then(post => { ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1629,12 +1621,12 @@ test("findMany - returning sideloaded data loads the data", function(assert) { }); return post.get('comments'); - })).then(assert.wait(function(comments) { - var comment1 = store.peekRecord('comment', 1); - var comment2 = store.peekRecord('comment', 2); - var comment3 = store.peekRecord('comment', 3); - var comment4 = store.peekRecord('comment', 4); - var post2 = store.peekRecord('post', 2); + }).then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); + let comment4 = store.peekRecord('comment', 4); + let post2 = store.peekRecord('post', 2); assert.deepEqual( comments.toArray(), @@ -1644,7 +1636,7 @@ test("findMany - returning sideloaded data loads the data", function(assert) { assert.deepEqual(comment4.getProperties('id', 'name'), { id: "4", name: "Unrelated comment" }); assert.deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "The Parley Letter" }); - })); + }); }); test("findMany - a custom serializer is used if present", function(assert) { @@ -1662,7 +1654,7 @@ test("findMany - a custom serializer is used if present", function(assert) { adapter.coalesceFindRequests = true; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -1683,7 +1675,7 @@ test("findMany - a custom serializer is used if present", function(assert) { }); }); - store.findRecord('post', 1).then(assert.wait(function(post) { + return store.findRecord('post', 1).then(post => { ajaxResponse({ comments: [ { _ID_: 1, _NAME_: "FIRST" }, @@ -1692,24 +1684,24 @@ test("findMany - a custom serializer is used if present", function(assert) { }); return post.get('comments'); - })).then(assert.wait(function(comments) { - var comment1 = store.peekRecord('comment', 1); - var comment2 = store.peekRecord('comment', 2); - var comment3 = store.peekRecord('comment', 3); + }).then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); assert.deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); assert.deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); assert.deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); - })); + }); }); test("findHasMany - returning an array populates the array", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -1728,7 +1720,7 @@ test("findHasMany - returning an array populates the array", function(assert) { }); }); - run(store, 'findRecord', 'post', '1').then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', '1').then(post => { ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1738,21 +1730,21 @@ test("findHasMany - returning an array populates the array", function(assert) { }); return post.get('comments'); - })).then(assert.wait(function(comments) { + }).then(comments => { assert.equal(passedUrl, '/posts/1/comments'); assert.equal(passedVerb, 'GET'); assert.equal(passedHash, undefined); - var comment1 = store.peekRecord('comment', 1); - var comment2 = store.peekRecord('comment', 2); - var comment3 = store.peekRecord('comment', 3); + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); assert.deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); assert.deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); assert.deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); - })); + }); }); test("findHasMany - passes buildURL the requestType", function(assert) { @@ -1765,7 +1757,7 @@ test("findHasMany - passes buildURL the requestType", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -1784,7 +1776,7 @@ test("findHasMany - passes buildURL the requestType", function(assert) { }); }); - run(store, 'findRecord', 'post', '1').then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', '1').then(post => { ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1794,19 +1786,15 @@ test("findHasMany - passes buildURL the requestType", function(assert) { }); return post.get('comments'); - })).then(assert.wait(function(comments) { - // NOOP - })); + }); }); - - test("findMany - returning sideloaded data loads the data (with JSONApi Links)", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -1825,7 +1813,7 @@ test("findMany - returning sideloaded data loads the data (with JSONApi Links)", }); }); - store.findRecord('post', 1).then(assert.wait(function(post) { + return store.findRecord('post', 1).then(post => { ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1836,16 +1824,16 @@ test("findMany - returning sideloaded data loads the data (with JSONApi Links)", }); return post.get('comments'); - })).then(assert.wait(function(comments) { - var comment1 = store.peekRecord('comment', 1); - var comment2 = store.peekRecord('comment', 2); - var comment3 = store.peekRecord('comment', 3); - var post2 = store.peekRecord('post', 2); + }).then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); + let post2 = store.peekRecord('post', 2); assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); assert.deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "The Parley Letter" }); - })); + }); }); test("findMany - a custom serializer is used if present", function(assert) { @@ -1862,7 +1850,7 @@ test("findMany - a custom serializer is used if present", function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -1881,7 +1869,7 @@ test("findMany - a custom serializer is used if present", function(assert) { }); }); - store.findRecord('post', 1).then(assert.wait(function(post) { + return store.findRecord('post', 1).then(post => { ajaxResponse({ comments: [ { _ID_: 1, _NAME_: "FIRST" }, @@ -1890,17 +1878,17 @@ test("findMany - a custom serializer is used if present", function(assert) { ] }); return post.get('comments'); - })).then(assert.wait(function(comments) { - var comment1 = store.peekRecord('comment', 1); - var comment2 = store.peekRecord('comment', 2); - var comment3 = store.peekRecord('comment', 3); + }).then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); assert.deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); assert.deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); assert.deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); - })); + }); }); test('findBelongsTo - passes buildURL the requestType', function(assert) { @@ -1913,7 +1901,7 @@ test('findBelongsTo - passes buildURL the requestType', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: true }) }); - run(function() { + run(() => { store.push({ data: { type: 'comment', @@ -1932,12 +1920,10 @@ test('findBelongsTo - passes buildURL the requestType', function(assert) { }); }); - run(store, 'findRecord', 'comment', 1).then(assert.wait(function(comment) { + return run(store, 'findRecord', 'comment', 1).then(comment => { ajaxResponse({ post: { id: 1, name: 'Rails is omakase' } }); return comment.get('post'); - })).then(assert.wait(function(post) { - // NOOP - })); + }); }); testInDebug('coalesceFindRequests assert.warns if the expected records are not returned in the coalesced request', function(assert) { @@ -2000,8 +1986,8 @@ test('groupRecordsForFindMany groups records based on their url', function(asser return Ember.RSVP.resolve({ comments: [{ id: 2 }, { id: 3 }] }); }; - var post; - run(function() { + let post; + run(() => { store.push({ data: { type: 'post', @@ -2020,9 +2006,7 @@ test('groupRecordsForFindMany groups records based on their url', function(asser post = store.peekRecord('post', 2); }); - run(function() { - post.get('comments'); - }); + run(() => post.get('comments')); }); test('groupRecordsForFindMany groups records correctly when singular URLs are encoded as query params', function(assert) { @@ -2047,9 +2031,9 @@ test('groupRecordsForFindMany groups records correctly when singular URLs are en assert.deepEqual(ids, ['2', '3']); return Ember.RSVP.resolve({ comments: [{ id: 2 }, { id: 3 }] }); }; - var post; + let post; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -2068,9 +2052,7 @@ test('groupRecordsForFindMany groups records correctly when singular URLs are en post = store.peekRecord('post', 2); }); - run(function() { - post.get('comments'); - }); + run(() => post.get('comments')); }); test('normalizeKey - to set up _ids and _id', function(assert) { @@ -2084,10 +2066,10 @@ test('normalizeKey - to set up _ids and _id', function(assert) { keyForRelationship(rel, kind) { if (kind === 'belongsTo') { - var underscored = Ember.String.underscore(rel); + let underscored = Ember.String.underscore(rel); return underscored + '_id'; } else { - var singular = Ember.String.singularize(rel); + let singular = Ember.String.singularize(rel); return Ember.String.underscore(singular) + '_ids'; } } @@ -2132,12 +2114,12 @@ test('normalizeKey - to set up _ids and _id', function(assert) { }] }); - run(function() { - store.findRecord('post', 1).then(assert.wait(function(post) { + return run(() => { + return store.findRecord('post', 1).then(post => { assert.equal(post.get('authorName'), "@d2h"); assert.equal(post.get('author.name'), "D2H"); assert.deepEqual(post.get('comments').mapBy('body'), ["Rails is unagi", "What is omakase?"]); - })); + }); }); }); @@ -2151,10 +2133,11 @@ test('groupRecordsForFindMany splits up calls for large ids', function(assert) { return new Array(n+1).join(character); } - var a2000 = repeatChar('a', 2000); - var b2000 = repeatChar('b', 2000); - var post; - run(function() { + let a2000 = repeatChar('a', 2000); + let b2000 = repeatChar('b', 2000); + let post; + + run(() => { store.push({ data: { type: 'post', @@ -2187,9 +2170,7 @@ test('groupRecordsForFindMany splits up calls for large ids', function(assert) { return Ember.RSVP.reject(); }; - run(function() { - post.get('comments'); - }); + run(() => post.get('comments')); }); test('groupRecordsForFindMany groups calls for small ids', function(assert) { @@ -2202,11 +2183,11 @@ test('groupRecordsForFindMany groups calls for small ids', function(assert) { return new Array(n+1).join(character); } - var a100 = repeatChar('a', 100); - var b100 = repeatChar('b', 100); - var post; + let a100 = repeatChar('a', 100); + let b100 = repeatChar('b', 100); + let post; - run(function() { + run(() => { store.push({ data: { type: 'post', @@ -2236,20 +2217,17 @@ test('groupRecordsForFindMany groups calls for small ids', function(assert) { return Ember.RSVP.resolve({ comments: [{ id: a100 }, { id: b100 }] }); }; - run(function() { - post.get('comments'); - }); + run(() => post.get('comments')); }); test("calls adapter.handleResponse with the jqXHR and json", function(assert) { assert.expect(2); - var originalAjax = Ember.$.ajax; - var jqXHR = { + let jqXHR = { status: 200, getAllResponseHeaders() { return ''; } }; - var data = { + let data = { post: { id: "1", name: "Docker is amazing" @@ -2266,25 +2244,18 @@ test("calls adapter.handleResponse with the jqXHR and json", function(assert) { return json; }; - try { - run(function() { - store.findRecord('post', '1'); - }); - } finally { - Ember.$.ajax = originalAjax; - } + run(() => store.findRecord('post', '1')); }); test('calls handleResponse with jqXHR, jqXHR.responseText, and requestData', function(assert) { assert.expect(4); - var originalAjax = Ember.$.ajax; - var jqXHR = { + let jqXHR = { status: 400, responseText: 'Nope lol', getAllResponseHeaders() { return ''; } }; - var expectedRequestData = { + let expectedRequestData = { method: "GET", url: "/posts/1" }; @@ -2300,24 +2271,17 @@ test('calls handleResponse with jqXHR, jqXHR.responseText, and requestData', fun return new DS.AdapterError('nope!'); }; - try { - run(function() { - store.findRecord('post', '1').catch(function(err) { - assert.ok(err, 'promise rejected'); - }); - }); - } finally { - Ember.$.ajax = originalAjax; - } + return run(() => { + return store.findRecord('post', '1').catch(err => assert.ok(err, 'promise rejected')); + }); }); test("rejects promise if DS.AdapterError is returned from adapter.handleResponse", function(assert) { assert.expect(3); - var originalAjax = Ember.$.ajax; - var jqXHR = { + let jqXHR = { getAllResponseHeaders() { return ''; } }; - var data = { + let data = { something: 'is invalid' }; @@ -2330,20 +2294,17 @@ test("rejects promise if DS.AdapterError is returned from adapter.handleResponse return new DS.AdapterError(json); }; - Ember.run(function() { - store.findRecord('post', '1').then(null, function(reason) { + return Ember.run(() => { + return store.findRecord('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); assert.ok(reason instanceof DS.AdapterError, 'reason should be an instance of DS.AdapterError'); }); }); - - Ember.$.ajax = originalAjax; }); test("gracefully handles exceptions in handleResponse", function(assert) { assert.expect(1); - var originalAjax = Ember.$.ajax; - var jqXHR = { + let jqXHR = { status: 200, getAllResponseHeaders() { return ''; } }; @@ -2356,50 +2317,39 @@ test("gracefully handles exceptions in handleResponse", function(assert) { throw new Error('Unexpected error'); }; - try { - return run(function() { - return store.findRecord('post', '1').catch(function(error) { - assert.ok(true, 'Unexpected error is captured by the promise chain'); - }); - + return run(() => { + return store.findRecord('post', '1').catch(error => { + assert.ok(true, 'Unexpected error is captured by the promise chain'); }); - } finally { - Ember.$.ajax = originalAjax; - } + }); }); test("gracefully handles exceptions in handleResponse where the ajax request errors", function(assert) { assert.expect(1); - var originalAjax = Ember.$.ajax; - var jqXHR = { + let jqXHR = { status: 500, getAllResponseHeaders() { return ''; } }; Ember.$.ajax = function(hash) { - setTimeout(function() { hash.error({}, 'Internal Server Error', jqXHR); }, 1) + setTimeout(() => hash.error({}, 'Internal Server Error', jqXHR) , 1); }; adapter.handleResponse = function(status, headers, json) { throw new Error('Unexpected error'); }; - try { - return run(function() { - return store.findRecord('post', '1').catch(function(error) { - assert.ok(true, 'Unexpected error is captured by the promise chain'); - }); + return run(() => { + return store.findRecord('post', '1').catch(error => { + assert.ok(true, 'Unexpected error is captured by the promise chain'); }); - } finally { - Ember.$.ajax = originalAjax; - } + }); }); test('treats status code 0 as an abort', function(assert) { assert.expect(1); - var originalAjax = Ember.$.ajax; - var jqXHR = { + let jqXHR = { status: 0, getAllResponseHeaders() { return ''; } }; @@ -2412,27 +2362,22 @@ test('treats status code 0 as an abort', function(assert) { assert.ok(false); }; - try { - run(function() { - store.findRecord('post', '1').catch(function(err) { - assert.ok(err instanceof DS.AbortError, 'reason should be an instance of DS.AbortError'); - }); + return run(() => { + return store.findRecord('post', '1').catch(err => { + assert.ok(err instanceof DS.AbortError, 'reason should be an instance of DS.AbortError'); }); - } finally { - Ember.$.ajax = originalAjax; - } + }); }); test('on error appends errorThrown for sanity', function(assert) { assert.expect(2); - var originalAjax = Ember.$.ajax; - var jqXHR = { + let jqXHR = { responseText: 'Nope lol', getAllResponseHeaders() { return ''; } }; - var errorThrown = new Error('nope!'); + let errorThrown = new Error('nope!'); Ember.$.ajax = function(hash) { hash.error(jqXHR, jqXHR.responseText, errorThrown); @@ -2442,25 +2387,20 @@ test('on error appends errorThrown for sanity', function(assert) { assert.ok(false); }; - try { - run(function() { - store.findRecord('post', '1').catch(function(err) { - assert.equal(err, errorThrown); - assert.ok(err, 'promise rejected'); - }); + return run(() => { + return store.findRecord('post', '1').catch(err => { + assert.equal(err, errorThrown); + assert.ok(err, 'promise rejected'); }); - } finally { - Ember.$.ajax = originalAjax; - } + }); }); if (isEnabled('ds-extended-errors')) { test("rejects promise with a specialized subclass of DS.AdapterError if ajax responds with http error codes", function(assert) { assert.expect(10); - var originalAjax = Ember.$.ajax; - var jqXHR = { - getAllResponseHeaders: function() { return ''; } + let jqXHR = { + getAllResponseHeaders() { return ''; } }; Ember.$.ajax = function(hash) { @@ -2468,8 +2408,8 @@ if (isEnabled('ds-extended-errors')) { hash.error(jqXHR, 'error'); }; - Ember.run(function() { - store.find('post', '1').then(null, function(reason) { + Ember.run(() => { + store.find('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); assert.ok(reason instanceof DS.UnauthorizedError, 'reason should be an instance of DS.UnauthorizedError'); }); @@ -2480,8 +2420,8 @@ if (isEnabled('ds-extended-errors')) { hash.error(jqXHR, 'error'); }; - Ember.run(function() { - store.find('post', '1').then(null, function(reason) { + Ember.run(() => { + store.find('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); assert.ok(reason instanceof DS.ForbiddenError, 'reason should be an instance of DS.ForbiddenError'); }); @@ -2492,8 +2432,8 @@ if (isEnabled('ds-extended-errors')) { hash.error(jqXHR, 'error'); }; - Ember.run(function() { - store.find('post', '1').then(null, function(reason) { + Ember.run(() => { + store.find('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); assert.ok(reason instanceof DS.NotFoundError, 'reason should be an instance of DS.NotFoundError'); }); @@ -2504,8 +2444,8 @@ if (isEnabled('ds-extended-errors')) { hash.error(jqXHR, 'error'); }; - Ember.run(function() { - store.find('post', '1').then(null, function(reason) { + Ember.run(() => { + store.find('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); assert.ok(reason instanceof DS.ConflictError, 'reason should be an instance of DS.ConflictError'); }); @@ -2516,96 +2456,77 @@ if (isEnabled('ds-extended-errors')) { hash.error(jqXHR, 'error'); }; - Ember.run(function() { - store.find('post', '1').then(null, function(reason) { + Ember.run(() => { + store.find('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); assert.ok(reason instanceof DS.ServerError, 'reason should be an instance of DS.ServerError'); }); }); - - Ember.$.ajax = originalAjax; }); } test('on error wraps the error string in an DS.AdapterError object', function(assert) { assert.expect(2); - var originalAjax = Ember.$.ajax; - var jqXHR = { + let jqXHR = { responseText: '', getAllResponseHeaders() { return ''; } }; - var errorThrown = 'nope!'; + let errorThrown = 'nope!'; Ember.$.ajax = function(hash) { hash.error(jqXHR, 'error', errorThrown); }; - try { - run(function() { - store.findRecord('post', '1').catch(function(err) { - assert.equal(err.errors[0].detail, errorThrown); - assert.ok(err, 'promise rejected'); - }); + run(() => { + store.findRecord('post', '1').catch(err => { + assert.equal(err.errors[0].detail, errorThrown); + assert.ok(err, 'promise rejected'); }); - } finally { - Ember.$.ajax = originalAjax; - } + }); }); test('error handling includes a detailed message from the server', (assert) => { assert.expect(2); - - let originalAjax = Ember.$.ajax; let jqXHR = { status: 500, responseText: 'An error message, perhaps generated from a backend server!', - getAllResponseHeaders: function() { return 'Content-Type: text/plain'; } + getAllResponseHeaders() { return 'Content-Type: text/plain'; } }; Ember.$.ajax = function(hash) { hash.error(jqXHR, 'error'); }; - try { - run(function() { - store.findRecord('post', '1').catch(function(err) { - assert.equal(err.message, "Ember Data Request GET /posts/1 returned a 500\nPayload (text/plain)\nAn error message, perhaps generated from a backend server!"); - assert.ok(err, 'promise rejected'); - }); + run(() => { + store.findRecord('post', '1').catch(err => { + assert.equal(err.message, "Ember Data Request GET /posts/1 returned a 500\nPayload (text/plain)\nAn error message, perhaps generated from a backend server!"); + assert.ok(err, 'promise rejected'); }); - } finally { - Ember.$.ajax = originalAjax; - } + }); }); test('error handling with a very long HTML-formatted payload truncates the friendly message', (assert) => { assert.expect(2); - let originalAjax = Ember.$.ajax; let jqXHR = { status: 500, responseText: new Array(100).join(""), - getAllResponseHeaders: function() { return 'Content-Type: text/html'; } + getAllResponseHeaders() { return 'Content-Type: text/html'; } }; Ember.$.ajax = function(hash) { hash.error(jqXHR, 'error'); }; - try { - run(function() { - store.findRecord('post', '1').catch(function(err) { - assert.equal(err.message, "Ember Data Request GET /posts/1 returned a 500\nPayload (text/html)\n[Omitted Lengthy HTML]"); - assert.ok(err, 'promise rejected'); - }); + run(() => { + store.findRecord('post', '1').catch(err => { + assert.equal(err.message, "Ember Data Request GET /posts/1 returned a 500\nPayload (text/html)\n[Omitted Lengthy HTML]"); + assert.ok(err, 'promise rejected'); }); - } finally { - Ember.$.ajax = originalAjax; - } - + }); }); test('findAll resolves with a collection of DS.Models, not DS.InternalModels', (assert) => { @@ -2628,13 +2549,12 @@ test('findAll resolves with a collection of DS.Models, not DS.InternalModels', ( ] }); - run(() => { - store.findAll('post').then(assert.wait((posts) => { + return run(() => { + return store.findAll('post').then(posts => { assert.equal(get(posts, 'length'), 3); posts.forEach((post) => assert.ok(post instanceof DS.Model)); - })); + }); }); - }); test("createRecord - sideloaded records are pushed to the store", function(assert) { @@ -2656,12 +2576,13 @@ test("createRecord - sideloaded records are pushed to the store", function(asser name: 'Second comment' }] }); - var post; + let post; - run(function() { + return run(() => { post = store.createRecord('post', { name: 'The Parley Letter' }); - post.save().then(function(post) { - var comments = store.peekAll('comment'); + + return post.save().then(post => { + let comments = store.peekAll('comment'); assert.equal(get(comments, 'length'), 2, 'comments.length is correct'); assert.equal(get(comments, 'firstObject.name'), 'First comment', 'comments.firstObject.name is correct'); @@ -2671,27 +2592,21 @@ test("createRecord - sideloaded records are pushed to the store", function(asser }); testInDebug("warns when an empty response is returned, though a valid stringified JSON is expected", function(assert) { - let done = assert.async(); let server = new Pretender(); server.post('/posts', function() { return [201, { "Content-Type": "application/json" }, ""]; }); - run(function() { - let post = store.createRecord('post'); - let save = post.save(); - - save.then(null, function() { - server.shutdown(); - done(); - }); + return run(() => { + return store.createRecord('post').save(); + }).then(() => { + assert.equal(true, false, 'should not have fulfilled'); + }, reason => { + assert.ok(/JSON/.test(reason.message)); }); - - assert.expectWarning("The server returned an empty string for POST /posts, which cannot be parsed into a valid JSON. Return either null or {}."); }); - if (isEnabled('ds-improved-ajax')) { testInDebug("The RESTAdapter should use `ajax` with a deprecation message when it is overridden by the user.", function(assert) { assert.expect(2) @@ -2701,10 +2616,8 @@ if (isEnabled('ds-improved-ajax')) { return { posts: { id: 1, name: "Rails is omakase" } }; }; - assert.expectDeprecation(function() { - run(function() { - store.findRecord('post', 1); - }); + assert.expectDeprecation(() => { + run(() => store.findRecord('post', 1)); }, /RESTAdapter#ajax has been deprecated/) }); @@ -2713,29 +2626,26 @@ if (isEnabled('ds-improved-ajax')) { assert.expect(2) adapter._ajaxRequest = function(hash) { - var jqXHR = { + let jqXHR = { status: 200, getAllResponseHeaders() { return ''; } }; hash.success({ posts: { id: 1, name: "Rails is omakase" } }, 'OK', jqXHR); } - var oldAjaxOptions = adapter.ajaxOptions; + let oldAjaxOptions = adapter.ajaxOptions; adapter.ajaxOptions = function() { assert.ok(true, 'The ajaxOptions method should be called when it is overridden'); return oldAjaxOptions.apply(this, arguments); }; - assert.expectDeprecation(function() { - run(function() { - store.findRecord('post', 1); - }); + assert.expectDeprecation(() => { + run(() => store.findRecord('post', 1)); }, /RESTAdapter#ajaxOptions has been deprecated/) }); test("_requestToJQueryAjaxHash works correctly for GET requests - GH-4445", function(assert) { - let done = assert.async(); - let server = new Pretender(); + server = new Pretender(); server.get('/posts/1', function(request) { assert.equal(request.url, "/posts/1", "no query param is added to the GET request"); @@ -2743,14 +2653,7 @@ if (isEnabled('ds-improved-ajax')) { return [201, { "Content-Type": "application/json" }, JSON.stringify({ post: { id: 1 } })]; }); - run(function() { - let post = store.findRecord('post', 1); - - post.then(function() { - server.shutdown(); - done(); - }); - }); + return run(() => store.findRecord('post', 1)); }); } diff --git a/tests/integration/adapter/serialize-test.js b/tests/integration/adapter/serialize-test.js index de40aa3182d..fdf961fe740 100644 --- a/tests/integration/adapter/serialize-test.js +++ b/tests/integration/adapter/serialize-test.js @@ -5,12 +5,13 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var run = Ember.run; -var env, store, adapter, serializer; +const { run } = Ember; + +let env, store, adapter, serializer; module("integration/adapter/serialize - DS.Adapter integration test", { beforeEach() { - var Person = DS.Model.extend({ + const Person = DS.Model.extend({ name: DS.attr('string') }); @@ -32,8 +33,8 @@ test("serialize() is delegated to the serializer", function(assert) { assert.deepEqual(options, { foo: 'bar' }); }; - run(function() { - var person = store.createRecord('person'); + run(() => { + let person = store.createRecord('person'); adapter.serialize(person._createSnapshot(), { foo: 'bar' }); }); }); diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index fe114a08d69..85326d8947a 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -19,13 +19,11 @@ import DS from 'ember-data'; the given record or record array changes state appropriately. */ -var get = Ember.get; -var set = Ember.set; -var run = Ember.run; -var Person, Dog, env, store, adapter; +const { get, set, run } = Ember; +let Person, Dog, env, store, adapter; function moveRecordOutOfInFlight(record) { - run(function() { + run(() => { // move record out of the inflight state so the tests can clean up // correctly let { store, _internalModel } = record; @@ -77,11 +75,11 @@ test("Records loaded multiple times and retrieved in recordArray are ready to se }); }; - run(store, 'query', 'person', { q: 'bla' }).then(assert.wait(function(people) { - var people2 = store.query('person', { q: 'bla2' }); + return run(store, 'query', 'person', { q: 'bla' }).then(people => { + let people2 = store.query('person', { q: 'bla2' }); return Ember.RSVP.hash({ people: people, people2: people2 }); - })).then(assert.wait(function(results) { + }).then(results => { assert.equal(results.people2.get('length'), 2, 'return the elements'); assert.ok(results.people2.get('isLoaded'), 'array is loaded'); @@ -90,12 +88,11 @@ test("Records loaded multiple times and retrieved in recordArray are ready to se // delete record will not throw exception person.deleteRecord(); - })); - + }); }); test("by default, createRecords calls createRecord once per record", function(assert) { - var count = 1; + let count = 1; adapter.shouldBackgroundReloadRecord = () => false; adapter.createRecord = function(store, type, snapshot) { assert.equal(type, Person, "the type is correct"); @@ -108,8 +105,8 @@ test("by default, createRecords calls createRecord once per record", function(as assert.ok(false, "should not have invoked more than 2 times"); } - var hash = snapshot.attributes(); - var recordId = count; + let hash = snapshot.attributes(); + let recordId = count; hash['updated-at'] = "now"; count++; @@ -121,21 +118,22 @@ test("by default, createRecords calls createRecord once per record", function(as } }); }; - var tom, yehuda; - run(function() { + let tom, yehuda; + + run(() => { tom = store.createRecord('person', { name: "Tom Dale" }); yehuda = store.createRecord('person', { name: "Yehuda Katz" }); }); - var promise = run(function() { + let promise = run(() => { return Ember.RSVP.hash({ tom: tom.save(), yehuda: yehuda.save() }); }); - promise.then(assert.wait(function(records) { + return promise.then(records => { tom = records.tom; yehuda = records.yehuda; @@ -143,12 +141,11 @@ test("by default, createRecords calls createRecord once per record", function(as assert.asyncEqual(yehuda, store.findRecord('person', 2), "Once an ID is in, findRecord returns the same object"); assert.equal(get(tom, 'updatedAt'), "now", "The new information is received"); assert.equal(get(yehuda, 'updatedAt'), "now", "The new information is received"); - - })); + }); }); test("by default, updateRecords calls updateRecord once per record", function(assert) { - var count = 0; + let count = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { assert.equal(type, Person, "the type is correct"); @@ -168,7 +165,7 @@ test("by default, updateRecords calls updateRecord once per record", function(as return Ember.RSVP.resolve(); }; - run(function() { + run(() => { env.store.push({ data: [{ type: 'person', @@ -186,35 +183,38 @@ test("by default, updateRecords calls updateRecord once per record", function(as }); }); - var promise = run(function() { + let promise = run(() => { return Ember.RSVP.hash({ tom: store.findRecord('person', 1), yehuda: store.findRecord('person', 2) }); }); - promise.then(assert.wait(function(records) { - var tom = records.tom; - var yehuda = records.yehuda; + return promise.then(records => { + let tom = records.tom; + let yehuda = records.yehuda; set(tom, "name", "Tom Dale"); set(yehuda, "name", "Yehuda Katz"); - return Ember.RSVP.hash({ tom: tom.save(), yehuda: yehuda.save() }); - })).then(assert.wait(function(records) { - var tom = records.tom; - var yehuda = records.yehuda; + return Ember.RSVP.hash({ + tom: tom.save(), + yehuda: yehuda.save() + }); + }).then(records => { + let tom = records.tom; + let yehuda = records.yehuda; assert.equal(tom.get('isSaving'), false, "record is no longer saving"); assert.equal(tom.get('isLoaded'), true, "record is loaded"); assert.equal(yehuda.get('isSaving'), false, "record is no longer saving"); assert.equal(yehuda.get('isLoaded'), true, "record is loaded"); - })); + }); }); test("calling store.didSaveRecord can provide an optional hash", function(assert) { - var count = 0; + let count = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { assert.equal(type, Person, "the type is correct"); @@ -231,7 +231,7 @@ test("calling store.didSaveRecord can provide an optional hash", function(assert } }; - run(function() { + run(() => { env.store.push({ data: [{ type: 'person', @@ -249,36 +249,40 @@ test("calling store.didSaveRecord can provide an optional hash", function(assert }); }); - var promise = run(function() { + let promise = run(() => { return Ember.RSVP.hash({ tom: store.findRecord('person', 1), yehuda: store.findRecord('person', 2) }); }); - promise.then(assert.wait(function(records) { - var tom = records.tom; - var yehuda = records.yehuda; + + return promise.then(records => { + let tom = records.tom; + let yehuda = records.yehuda; set(tom, "name", "Tom Dale"); set(yehuda, "name", "Yehuda Katz"); - return Ember.RSVP.hash({ tom: tom.save(), yehuda: yehuda.save() }); - })).then(assert.wait(function(records) { - var tom = records.tom; - var yehuda = records.yehuda; + return Ember.RSVP.hash({ + tom: tom.save(), + yehuda: yehuda.save() + }); + }).then(records => { + let tom = records.tom; + let yehuda = records.yehuda; assert.equal(get(tom, 'hasDirtyAttributes'), false, "the record should not be dirty"); assert.equal(get(tom, 'updatedAt'), "now", "the hash was updated"); assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "the record should not be dirty"); assert.equal(get(yehuda, 'updatedAt'), "now!", "the hash was updated"); - })); + }); }); test("by default, deleteRecord calls deleteRecord once per record", function(assert) { assert.expect(4); - var count = 0; + let count = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.deleteRecord = function(store, type, snapshot) { assert.equal(type, Person, "the type is correct"); @@ -296,7 +300,7 @@ test("by default, deleteRecord calls deleteRecord once per record", function(ass return Ember.RSVP.resolve(); }; - run(function() { + run(() => { env.store.push({ data: [{ type: 'person', @@ -314,29 +318,32 @@ test("by default, deleteRecord calls deleteRecord once per record", function(ass }); }); - var promise = run(function() { + let promise = run(() => { return Ember.RSVP.hash({ tom: store.findRecord('person', 1), yehuda: store.findRecord('person', 2) }); }); - promise.then(assert.wait(function(records) { - var tom = records.tom; - var yehuda = records.yehuda; + return promise.then(records => { + let tom = records.tom; + let yehuda = records.yehuda; tom.deleteRecord(); yehuda.deleteRecord(); - tom.save(); - yehuda.save(); - })); + return Ember.RSVP.Promise.all([ + tom.save(), + yehuda.save() + ]); + }); }); test("by default, destroyRecord calls deleteRecord once per record without requiring .save", function(assert) { assert.expect(4); - var count = 0; + let count = 0; + adapter.shouldBackgroundReloadRecord = () => false; adapter.deleteRecord = function(store, type, snapshot) { assert.equal(type, Person, "the type is correct"); @@ -354,7 +361,7 @@ test("by default, destroyRecord calls deleteRecord once per record without requi return Ember.RSVP.resolve(); }; - run(function() { + run(() => { env.store.push({ data: [{ type: 'person', @@ -372,26 +379,28 @@ test("by default, destroyRecord calls deleteRecord once per record without requi }); }); - var promise = run(function() { + let promise = run(() => { return Ember.RSVP.hash({ tom: store.findRecord('person', 1), yehuda: store.findRecord('person', 2) }); }); - promise.then(assert.wait(function(records) { - var tom = records.tom; - var yehuda = records.yehuda; + return promise.then(records => { + let tom = records.tom; + let yehuda = records.yehuda; - tom.destroyRecord(); - yehuda.destroyRecord(); - })); + return Ember.RSVP.Promise.all([ + tom.destroyRecord(), + yehuda.destroyRecord() + ]); + }); }); test("if an existing model is edited then deleted, deleteRecord is called on the adapter", function(assert) { assert.expect(5); - var count = 0; + let count = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.deleteRecord = function(store, type, snapshot) { count++; @@ -406,7 +415,7 @@ test("if an existing model is edited then deleted, deleteRecord is called on the }; // Load data for a record into the store. - run(function() { + run(() => { env.store.push({ data: { type: 'person', @@ -419,22 +428,22 @@ test("if an existing model is edited then deleted, deleteRecord is called on the }); // Retrieve that loaded record and edit it so it becomes dirty - run(store, 'findRecord', 'person', 'deleted-record').then(assert.wait(function(tom) { + return run(store, 'findRecord', 'person', 'deleted-record').then(tom => { tom.set('name', "Tom Mothereffin' Dale"); assert.equal(get(tom, 'hasDirtyAttributes'), true, "precond - record should be dirty after editing"); tom.deleteRecord(); return tom.save(); - })).then(assert.wait(function(tom) { + }).then(tom => { assert.equal(get(tom, 'hasDirtyAttributes'), false, "record should not be dirty"); assert.equal(get(tom, 'isDeleted'), true, "record should be considered deleted"); - })); + }); }); test("if a deleted record errors, it enters the error state", function(assert) { - var count = 0; - var error = new DS.AdapterError(); + let count = 0; + let error = new DS.AdapterError(); adapter.shouldBackgroundReloadRecord = () => false; adapter.deleteRecord = function(store, type, snapshot) { @@ -445,7 +454,7 @@ test("if a deleted record errors, it enters the error state", function(assert) { } }; - run(function() { + run(() => { env.store.push({ data: { type: 'person', @@ -457,23 +466,22 @@ test("if a deleted record errors, it enters the error state", function(assert) { }); }); - var tom; - - run(function() { - store.findRecord('person', 'deleted-record').then(assert.wait(function(person) { + return run(() => { + let tom; + store.findRecord('person', 'deleted-record').then(person => { tom = person; person.deleteRecord(); return person.save(); - })).then(null, assert.wait(function() { + }).catch(() => { assert.equal(tom.get('isError'), true, "Tom is now errored"); assert.equal(tom.get('adapterError'), error, "error object is exposed"); // this time it succeeds return tom.save(); - })).then(assert.wait(function() { + }).then(() => { assert.equal(tom.get('isError'), false, "Tom is not errored anymore"); assert.equal(tom.get('adapterError'), null, "error object is discarded"); - })); + }); }); }); @@ -496,13 +504,13 @@ test("if a created record is marked as invalid by the server, it enters an error } }; - var yehuda = run(function() { + let yehuda = run(() => { return store.createRecord('person', { id: 1, name: "Yehuda Katz" }); }); // Wrap this in an Ember.run so that all chained async behavior is set up // before flushing any scheduled behavior. - Ember.run(function() { - yehuda.save().then(null, assert.wait(function(error) { + return Ember.run(function() { + return yehuda.save().catch(error => { assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); assert.ok(get(yehuda, 'errors.name'), "The errors.name property exists"); @@ -517,12 +525,12 @@ test("if a created record is marked as invalid by the server, it enters an error assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); return yehuda.save(); - })).then(assert.wait(function(person) { + }).then(person => { assert.strictEqual(person, yehuda, "The promise resolves with the saved record"); assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); assert.equal(get(yehuda, 'isNew'), false, "record is no longer new"); - })); + }); }); }); @@ -543,14 +551,14 @@ test("allows errors on arbitrary properties on create", function(assert) { } }; - var yehuda = run(function () { + let yehuda = run(() => { return store.createRecord('person', { id: 1, name: "Yehuda Katz" }); }); // Wrap this in an Ember.run so that all chained async behavior is set up // before flushing any scheduled behavior. - run(function() { - yehuda.save().then(null, assert.wait(function(error) { + return run(() => { + return yehuda.save().catch(error => { assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); assert.ok(get(yehuda, 'errors.base'), "The errors.base property exists"); assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), [{ attribute: 'base', message: "is a generally unsavoury character" }]); @@ -566,18 +574,18 @@ test("allows errors on arbitrary properties on create", function(assert) { assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); return yehuda.save(); - })).then(assert.wait(function(person) { + }).then(person => { assert.strictEqual(person, yehuda, "The promise resolves with the saved record"); assert.ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), []); assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); assert.equal(get(yehuda, 'isNew'), false, "record is no longer new"); - })); + }); }); }); test("if a created record is marked as invalid by the server, you can attempt the save again", function(assert) { - var saveCount = 0; + let saveCount = 0; adapter.createRecord = function(store, type, snapshot) { assert.equal(type, Person, "the type is correct"); saveCount++; @@ -597,14 +605,14 @@ test("if a created record is marked as invalid by the server, you can attempt th } }; - var yehuda = run(function() { + let yehuda = run(() => { return store.createRecord('person', { id: 1, name: "Yehuda Katz" }); }); // Wrap this in an Ember.run so that all chained async behavior is set up // before flushing any scheduled behavior. - Ember.run(function() { - yehuda.save().then(null, assert.wait(function(reason) { + return Ember.run(() => { + return yehuda.save().catch(reason => { assert.equal(saveCount, 1, "The record has been saved once"); assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); @@ -612,7 +620,7 @@ test("if a created record is marked as invalid by the server, you can attempt th assert.ok(get(yehuda, 'errors.name'), "The errors.name property exists"); assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); return yehuda.save(); - })).then(null, assert.wait(function(reason) { + }).catch(reason => { assert.equal(saveCount, 2, "The record has been saved twice"); assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid"); @@ -621,29 +629,29 @@ test("if a created record is marked as invalid by the server, you can attempt th assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); set(yehuda, 'name', 'Brohuda Brokatz'); return yehuda.save(); - })).then(assert.wait(function(person) { + }).then(person => { assert.equal(saveCount, 3, "The record has been saved thrice"); assert.equal(get(yehuda, 'isValid'), true, "record is valid"); assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is not dirty"); assert.equal(get(yehuda, 'errors.isEmpty'), true, "record has no errors"); - })); + }); }); }); test("if a created record is marked as erred by the server, it enters an error state", function(assert) { - var error = new DS.AdapterError(); + let error = new DS.AdapterError(); adapter.createRecord = function(store, type, snapshot) { return Ember.RSVP.reject(error); }; - Ember.run(function() { - var person = store.createRecord('person', { id: 1, name: "John Doe" }); + return Ember.run(() => { + let person = store.createRecord('person', { id: 1, name: "John Doe" }); - person.save().then(null, assert.wait(function() { + return person.save().catch(() => { assert.ok(get(person, 'isError'), "the record is in the error state"); assert.equal(get(person, 'adapterError'), error, "error object is exposed"); - })); + }); }); }); @@ -667,7 +675,7 @@ test("if an updated record is marked as invalid by the server, it enters an erro } }; - var yehuda = run(function() { + let yehuda = run(() => { env.store.push({ data: { type: 'person', @@ -677,11 +685,12 @@ test("if an updated record is marked as invalid by the server, it enters an erro } } }); + return store.peekRecord('person', 1); }); - return Ember.run(function() { - return store.findRecord('person', 1).then(assert.wait(function(person) { + return Ember.run(() => { + return store.findRecord('person', 1).then(person => { assert.equal(person, yehuda, "The same object is passed through"); assert.equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); @@ -691,7 +700,7 @@ test("if an updated record is marked as invalid by the server, it enters an erro assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); return yehuda.save(); - })).then(null, assert.wait(function(reason) { + }).catch(reason => { assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); @@ -703,14 +712,13 @@ test("if an updated record is marked as invalid by the server, it enters an erro assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); return yehuda.save(); - })).then(assert.wait(function(yehuda) { + }).then(yehuda => { assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is no longer new"); - })); + }); }); }); - test("records can have errors on arbitrary properties after update", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { @@ -729,7 +737,7 @@ test("records can have errors on arbitrary properties after update", function(as } }; - var yehuda = run(function() { + let yehuda = run(() => { env.store.push({ data: { type: 'person', @@ -742,8 +750,8 @@ test("records can have errors on arbitrary properties after update", function(as return store.peekRecord('person', 1); }); - run(function() { - store.findRecord('person', 1).then(assert.wait(function(person) { + return run(() => { + return store.findRecord('person', 1).then(person => { assert.equal(person, yehuda, "The same object is passed through"); assert.equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); @@ -753,7 +761,7 @@ test("records can have errors on arbitrary properties after update", function(as assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); return yehuda.save(); - })).then(null, assert.wait(function(reason) { + }).catch(reason => { assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); assert.ok(get(yehuda, 'errors.base'), "The errors.base property exists"); @@ -767,19 +775,17 @@ test("records can have errors on arbitrary properties after update", function(as assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); return yehuda.save(); - })).then(assert.wait(function(yehuda) { + }).then(yehuda => { assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is no longer new"); assert.ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), []); - })); + }); }); }); - - test("if an updated record is marked as invalid by the server, you can attempt the save again", function(assert) { - var saveCount = 0; + let saveCount = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { assert.equal(type, Person, "the type is correct"); @@ -799,7 +805,7 @@ test("if an updated record is marked as invalid by the server, you can attempt t } }; - var yehuda = run(function() { + let yehuda = run(() => { env.store.push({ data: { type: 'person', @@ -812,8 +818,8 @@ test("if an updated record is marked as invalid by the server, you can attempt t return store.peekRecord('person', 1); }); - Ember.run(function() { - store.findRecord('person', 1).then(assert.wait(function(person) { + return Ember.run(() => { + return store.findRecord('person', 1).then(person => { assert.equal(person, yehuda, "The same object is passed through"); assert.equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); @@ -823,38 +829,37 @@ test("if an updated record is marked as invalid by the server, you can attempt t assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); return yehuda.save(); - })).then(null, assert.wait(function(reason) { + }).catch(reason => { assert.equal(saveCount, 1, "The record has been saved once"); assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); return yehuda.save(); - })).then(null, assert.wait(function(reason) { + }).catch(reason => { assert.equal(saveCount, 2, "The record has been saved twice"); assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); assert.equal(get(yehuda, 'isValid'), false, "record is still invalid"); assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "record is still dirty"); set(yehuda, 'name', 'Brohuda Brokatz'); return yehuda.save(); - })).then(assert.wait(function(person) { + }).then(person => { assert.equal(saveCount, 3, "The record has been saved thrice"); assert.equal(get(yehuda, 'isValid'), true, "record is valid"); assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is not dirty"); assert.equal(get(yehuda, 'errors.isEmpty'), true, "record has no errors"); - })); + }); }); }); - test("if a updated record is marked as erred by the server, it enters an error state", function(assert) { - var error = new DS.AdapterError(); + let error = new DS.AdapterError(); adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { return Ember.RSVP.reject(error); }; - var person = run(function() { + let person = run(() => { env.store.push({ data: { type: 'person', @@ -867,14 +872,14 @@ test("if a updated record is marked as erred by the server, it enters an error s return store.peekRecord('person', 1); }); - run(store, 'findRecord', 'person', 1).then(assert.wait(function(record) { + return run(store, 'findRecord', 'person', 1).then(record => { assert.equal(record, person, "The person was resolved"); person.set('name', "Jonathan Doe"); return person.save(); - })).then(null, assert.wait(function(reason) { + }).catch(reason => { assert.ok(get(person, 'isError'), "the record is in the error state"); assert.equal(get(person, 'adapterError'), error, "error object is exposed"); - })); + }); }); test("can be created after the DS.Store", function(assert) { @@ -885,9 +890,7 @@ test("can be created after the DS.Store", function(assert) { return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); }; - run(function() { - store.findRecord('person', 1); - }); + run(() => store.findRecord('person', 1)); }); test("the filter method can optionally take a server query as well", function(assert) { @@ -913,19 +916,19 @@ test("the filter method can optionally take a server query as well", function(as }); }; - var asyncFilter = store.filter('person', { page: 1 }, function(data) { + let asyncFilter = store.filter('person', { page: 1 }, data => { return data.get('name') === "Tom Dale"; }); - var loadedFilter; + let loadedFilter; - asyncFilter.then(assert.wait(function(filter) { + return asyncFilter.then(filter => { loadedFilter = filter; return store.findRecord('person', 2); - })).then(assert.wait(function(tom) { + }).then(tom => { assert.equal(get(loadedFilter, 'length'), 1, "The filter has an item in it"); assert.deepEqual(loadedFilter.toArray(), [tom], "The filter has a single entry in it"); - })); + }); }); test("relationships returned via `commit` do not trigger additional findManys", function(assert) { @@ -933,7 +936,7 @@ test("relationships returned via `commit` do not trigger additional findManys", dogs: DS.hasMany('dog', { async: false }) }); - run(function() { + run(() => { env.store.push({ data: { type: 'dog', @@ -961,7 +964,7 @@ test("relationships returned via `commit` do not trigger additional findManys", }; adapter.updateRecord = function(store, type, snapshot) { - return new Ember.RSVP.Promise(function(resolve, reject) { + return new Ember.RSVP.Promise((resolve, reject) => { env.store.push({ data: { type: 'person', @@ -995,15 +998,15 @@ test("relationships returned via `commit` do not trigger additional findManys", assert.ok(false, "Should not get here"); }; - run(function() { - store.findRecord('person', 1).then(assert.wait(function(person) { + return run(() => { + store.findRecord('person', 1).then(person => { return Ember.RSVP.hash({ tom: person, dog: store.findRecord('dog', 1) }); - })).then(assert.wait(function(records) { + }).then(records => { records.tom.get('dogs'); return records.dog.save(); - })).then(assert.wait(function(tom) { + }).then(tom => { assert.ok(true, "Tom was saved"); - })); + }); }); }); @@ -1013,7 +1016,7 @@ test("relationships don't get reset if the links is the same", function(assert) dogs: DS.hasMany({ async: true }) }); - var count = 0; + let count = 0; adapter.findHasMany = function(store, snapshot, link, relationship) { assert.ok(count++ === 0, "findHasMany is only called once"); @@ -1021,7 +1024,7 @@ test("relationships don't get reset if the links is the same", function(assert) return Ember.RSVP.resolve({ data: [{ id: 1, type: "dog", attributes: { name: "Scruffy" } }] }); }; - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -1040,13 +1043,13 @@ test("relationships don't get reset if the links is the same", function(assert) }); }); - var tom, dogs; + let tom, dogs; - run(store, 'findRecord', 'person', 1).then(assert.wait(function(person) { + return run(store, 'findRecord', 'person', 1).then(person => { tom = person; dogs = tom.get('dogs'); return dogs; - })).then(assert.wait(function(dogs) { + }).then(dogs => { assert.equal(dogs.get('length'), 1, "The dogs are loaded"); store.push({ data: { @@ -1066,9 +1069,9 @@ test("relationships don't get reset if the links is the same", function(assert) }); assert.ok(tom.get('dogs') instanceof DS.PromiseArray, 'dogs is a promise'); return tom.get('dogs'); - })).then(assert.wait(function(dogs) { + }).then(dogs => { assert.equal(dogs.get('length'), 1, "The same dogs are loaded"); - })); + }); }); test("async hasMany always returns a promise", function(assert) { @@ -1090,20 +1093,17 @@ test("async hasMany always returns a promise", function(assert) { } }); }; - var tom; - run(function() { - tom = store.createRecord('person', { name: "Tom Dale" }); - }); + let tom = run(() => store.createRecord('person', { name: "Tom Dale" })); - run(function() { + run(() => { assert.ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise before save"); }); - run(function() { - tom.save().then(assert.wait(function() { + return run(() => { + return tom.save().then(() => { assert.ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise after save"); - })); + }); }); }); @@ -1117,7 +1117,7 @@ test("createRecord receives a snapshot", function(assert) { var person; - run(function() { + run(() => { person = store.createRecord('person', { name: "Tom Dale", id: 1 }); person.save(); }); @@ -1131,9 +1131,9 @@ test("updateRecord receives a snapshot", function(assert) { return Ember.RSVP.resolve(); }; - var person; + let person; - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -1146,7 +1146,7 @@ test("updateRecord receives a snapshot", function(assert) { person = store.peekRecord('person', 1); }); - run(function() { + run(() => { set(person, "name", "Tomster"); person.save(); }); @@ -1160,9 +1160,9 @@ test("deleteRecord receives a snapshot", function(assert) { return Ember.RSVP.resolve(); }; - var person; + let person; - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -1175,9 +1175,9 @@ test("deleteRecord receives a snapshot", function(assert) { person = store.peekRecord('person', 1); }); - run(function() { + return run(() => { person.deleteRecord(); - person.save(); + return person.save(); }); }); @@ -1189,9 +1189,7 @@ test("findRecord receives a snapshot", function(assert) { return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); }; - run(function() { - store.findRecord('person', 1); - }); + return run(() => store.findRecord('person', 1)); }); test("findMany receives an array of snapshots", function(assert) { @@ -1208,9 +1206,9 @@ test("findMany receives an array of snapshots", function(assert) { return Ember.RSVP.resolve({ data: [{ id: 2, type: "dog" }, { id: 3, type: "dog" }] }); }; - var person; + let person; - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -1228,9 +1226,7 @@ test("findMany receives an array of snapshots", function(assert) { person = store.peekRecord('person', 1); }); - run(function() { - person.get('dogs'); - }); + run(() => person.get('dogs')); }); test("findHasMany receives a snapshot", function(assert) { @@ -1245,9 +1241,9 @@ test("findHasMany receives a snapshot", function(assert) { return Ember.RSVP.resolve({ data: [{ id: 2, type: "dog" }, { id: 3, type: "dog" }] }); }; - var person; + let person; - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -1264,9 +1260,7 @@ test("findHasMany receives a snapshot", function(assert) { person = store.peekRecord('person', 1); }); - run(function() { - person.get('dogs'); - }); + return run(() => person.get('dogs')); }); test("findBelongsTo receives a snapshot", function(assert) { @@ -1276,14 +1270,14 @@ test("findBelongsTo receives a snapshot", function(assert) { dog: DS.belongsTo({ async: true }) }); - env.adapter.findBelongsTo = assert.wait(function(store, snapshot, link, relationship) { + env.adapter.findBelongsTo = function(store, snapshot, link, relationship) { assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); return Ember.RSVP.resolve({ data: { id: 2, type: "dog" } }); - }); + }; - var person; + let person; - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -1300,20 +1294,18 @@ test("findBelongsTo receives a snapshot", function(assert) { person = store.peekRecord('person', 1); }); - run(function() { - person.get('dog'); - }); + return run(() => person.get('dog')); }); test("record.save should pass adapterOptions to the updateRecord method", function(assert) { assert.expect(1); - env.adapter.updateRecord = assert.wait(function(store, type, snapshot) { + env.adapter.updateRecord = function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); - }); + }; - run(function() { + return run(() => { store.push({ data: { type: 'person', @@ -1323,34 +1315,34 @@ test("record.save should pass adapterOptions to the updateRecord method", functi } } }); - var person = store.peekRecord('person', 1); - person.save({ adapterOptions: { subscribe: true } }); + let person = store.peekRecord('person', 1); + return person.save({ adapterOptions: { subscribe: true } }); }); }); test("record.save should pass adapterOptions to the createRecord method", function(assert) { assert.expect(1); - env.adapter.createRecord = assert.wait(function(store, type, snapshot) { + env.adapter.createRecord = function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); - }); + }; - run(function() { - var person = store.createRecord('person', { name: 'Tom' }); - person.save({ adapterOptions: { subscribe: true } }); + return run(() => { + let person = store.createRecord('person', { name: 'Tom' }); + return person.save({ adapterOptions: { subscribe: true } }); }); }); test("record.save should pass adapterOptions to the deleteRecord method", function(assert) { assert.expect(1); - env.adapter.deleteRecord = assert.wait(function(store, type, snapshot) { + env.adapter.deleteRecord = function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); - }); + }; - run(function() { + run(() => { store.push({ data: { type: 'person', @@ -1360,32 +1352,31 @@ test("record.save should pass adapterOptions to the deleteRecord method", functi } } }); - var person = store.peekRecord('person', 1); + let person = store.peekRecord('person', 1); person.destroyRecord({ adapterOptions: { subscribe: true } }); }); }); - test("store.findRecord should pass adapterOptions to adapter.findRecord", function(assert) { assert.expect(1); - env.adapter.findRecord = assert.wait(function(store, type, id, snapshot) { + env.adapter.findRecord = function(store, type, id, snapshot) { assert.deepEqual(snapshot.adapterOptions, { query: { embed: true } }); return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); - }); + }; - run(function() { - store.findRecord('person', 1, { adapterOptions: { query: { embed: true } } }); + return run(() => { + return store.findRecord('person', 1, { adapterOptions: { query: { embed: true } } }); }); }); test("store.findRecord should pass 'include' to adapter.findRecord", function(assert) { assert.expect(1); - env.adapter.findRecord = assert.wait((store, type, id, snapshot) => { + env.adapter.findRecord = (store, type, id, snapshot) => { assert.equal(snapshot.include, 'books', 'include passed to adapter.findRecord'); return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); - }); + }; run(() => store.findRecord('person', 1, { include: 'books' })); }); @@ -1393,35 +1384,35 @@ test("store.findRecord should pass 'include' to adapter.findRecord", function(as test("store.findAll should pass adapterOptions to the adapter.findAll method", function(assert) { assert.expect(1); - env.adapter.findAll = assert.wait(function(store, type, sinceToken, arraySnapshot) { - var adapterOptions = arraySnapshot.adapterOptions; + env.adapter.findAll = function(store, type, sinceToken, arraySnapshot) { + let adapterOptions = arraySnapshot.adapterOptions; assert.deepEqual(adapterOptions, { query: { embed: true } }); return Ember.RSVP.resolve({ data: [{ id: 1, type: "person" }] }); - }); + }; - run(function() { - store.findAll('person', { adapterOptions: { query: { embed: true } } }); + return run(() => { + return store.findAll('person', { adapterOptions: { query: { embed: true } } }); }); }); test("store.findAll should pass 'include' to adapter.findAll", function(assert) { assert.expect(1); - env.adapter.findAll = assert.wait((store, type, sinceToken, arraySnapshot) => { + env.adapter.findAll = function(store, type, sinceToken, arraySnapshot) { assert.equal(arraySnapshot.include, 'books', 'include passed to adapter.findAll'); return Ember.RSVP.resolve({ data: [{ id: 1, type: "person" }] }); - }); + }; run(() => store.findAll('person', { include: 'books' })); }); test("An async hasMany relationship with links should not trigger shouldBackgroundReloadRecord", function(assert) { - var Post = DS.Model.extend({ + const Post = DS.Model.extend({ name: DS.attr("string"), comments: DS.hasMany('comment', { async: true }) }); - var Comment = DS.Model.extend({ + const Comment = DS.Model.extend({ name: DS.attr("string") }); @@ -1455,19 +1446,19 @@ test("An async hasMany relationship with links should not trigger shouldBackgrou store = env.store; - run(store, 'findRecord', 'post', '1').then(assert.wait(function(post) { + return run(store, 'findRecord', 'post', '1').then(post => { return post.get('comments'); - })).then(assert.wait(function(comments) { + }).then(comments => { assert.equal(comments.get('length'), 3); - })); + }); }); testInDebug("There should be a friendly error for if the adapter does not implement createRecord", function(assert) { adapter.createRecord = null; let tom; - assert.expectAssertion(function() { - run(function() { + assert.expectAssertion(() => { + run(() => { tom = store.createRecord('person', { name: "Tom Dale" }); tom.save(); }); @@ -1480,8 +1471,8 @@ testInDebug("There should be a friendly error for if the adapter does not implem adapter.updateRecord = null; let tom; - assert.expectAssertion(function() { - run(function() { + assert.expectAssertion(() => { + run(() => { tom = store.push({ data: { type: 'person', id: 1 } }); tom.save(); }); @@ -1494,8 +1485,8 @@ testInDebug("There should be a friendly error for if the adapter does not implem adapter.deleteRecord = null; let tom; - assert.expectAssertion(function() { - run(function() { + assert.expectAssertion(() => { + run(() => { tom = store.push({ data: { type: 'person', id: 1 } }); tom.deleteRecord(); tom.save(); diff --git a/tests/integration/records/collection-save-test.js b/tests/integration/records/collection-save-test.js index 2ea23b0b647..801275a7321 100644 --- a/tests/integration/records/collection-save-test.js +++ b/tests/integration/records/collection-save-test.js @@ -5,8 +5,9 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var Post, env; -var run = Ember.run; +const { run } = Ember; + +let Post, env; module("integration/records/collection_save - Save Collection of Records", { beforeEach() { @@ -25,52 +26,52 @@ module("integration/records/collection_save - Save Collection of Records", { test("Collection will resolve save on success", function(assert) { assert.expect(1); let id = 1; - run(function() { + run(() => { env.store.createRecord('post', { title: 'Hello' }); env.store.createRecord('post', { title: 'World' }); }); - var posts = env.store.peekAll('post'); + let posts = env.store.peekAll('post'); env.adapter.createRecord = function(store, type, snapshot) { return Ember.RSVP.resolve({ data: { id: id++ , type: 'post' } }); }; - run(function() { - posts.save().then(assert.wait(function() { + return run(() => { + return posts.save().then(() => { assert.ok(true, 'save operation was resolved'); - })); + }); }); }); test("Collection will reject save on error", function(assert) { - run(function() { + run(() => { env.store.createRecord('post', { title: 'Hello' }); env.store.createRecord('post', { title: 'World' }); }); - var posts = env.store.peekAll('post'); + let posts = env.store.peekAll('post'); env.adapter.createRecord = function(store, type, snapshot) { return Ember.RSVP.reject(); }; - run(function() { - posts.save().then(function() {}, assert.wait(function() { + return run(() => { + return posts.save().catch(() => { assert.ok(true, 'save operation was rejected'); - })); + }); }); }); test("Retry is allowed in a failure handler", function(assert) { - run(function() { + run(() => { env.store.createRecord('post', { title: 'Hello' }); env.store.createRecord('post', { title: 'World' }); }); - var posts = env.store.peekAll('post'); + let posts = env.store.peekAll('post'); - var count = 0; + let count = 0; let id = 1; env.adapter.createRecord = function(store, type, snapshot) { @@ -85,35 +86,33 @@ test("Retry is allowed in a failure handler", function(assert) { return Ember.RSVP.resolve({ data: { id: snapshot.id, type: 'post' } }); }; - run(function() { - posts.save() - .then( - function() {}, - assert.wait(function() { return posts.save(); })) - .then( - assert.wait(function(post) { - // the ID here is '2' because the second post saves on the first attempt, - // while the first post saves on the second attempt - assert.equal(posts.get('firstObject.id'), '2', "The post ID made it through"); - })); + return run(() => { + return posts.save() + .catch(() => posts.save()) + .then(post => { + // the ID here is '2' because the second post saves on the first attempt, + // while the first post saves on the second attempt + assert.equal(posts.get('firstObject.id'), '2', "The post ID made it through"); + }); }); }); test("Collection will reject save on invalid", function(assert) { assert.expect(1); - run(function() { + + run(() => { env.store.createRecord('post', { title: 'Hello' }); env.store.createRecord('post', { title: 'World' }); }); - var posts = env.store.peekAll('post'); + let posts = env.store.peekAll('post'); env.adapter.createRecord = function(store, type, snapshot) { return Ember.RSVP.reject({ title: 'invalid' }); }; - Ember.run(function() { - posts.save().then(function() {}, function() { + return Ember.run(() => { + return posts.save().catch(() => { assert.ok(true, 'save operation was rejected'); }); }); diff --git a/tests/integration/records/load-test.js b/tests/integration/records/load-test.js index 02e070c0c1c..eea2c0f7ae4 100644 --- a/tests/integration/records/load-test.js +++ b/tests/integration/records/load-test.js @@ -5,9 +5,10 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var hasMany = DS.hasMany; -var Post, Comment, env; -var run = Ember.run; +const { hasMany } = DS; +const { run } = Ember; + +let Post, Comment, env; module("integration/load - Loading Records", { beforeEach() { @@ -30,9 +31,9 @@ test("When loading a record fails, the record is not left behind", function(asse return Ember.RSVP.reject(); }; - run(function() { - env.store.findRecord('post', 1).then(null, assert.wait(function() { + return run(() => { + return env.store.findRecord('post', 1).catch(() => { assert.equal(env.store.hasRecordForId('post', 1), false); - })); + }); }); }); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 7cc2b0c9fbf..6bad183895c 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -6,14 +6,12 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var env, store, User, Message, Post, Comment, Book, Chapter, Author, NewMessage; -var get = Ember.get; -var run = Ember.run; +const { get, run, RSVP } = Ember; +const { attr, hasMany, belongsTo } = DS; +const { hash } = RSVP; -var attr = DS.attr; -var hasMany = DS.hasMany; -var belongsTo = DS.belongsTo; -var hash = Ember.RSVP.hash; +let env, store, User, Message, Post, Comment, Book, Chapter, Author, NewMessage; +const injectionValue = Ember.MODEL_FACTORY_INJECTIONS; module("integration/relationship/belongs_to Belongs-To Relationships", { beforeEach() { @@ -85,6 +83,7 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { }, afterEach() { + Ember.MODEL_FACTORY_INJECTIONS = injectionValue; run(env.container, 'destroy'); } }); @@ -109,7 +108,7 @@ test("The store can materialize a non loaded monomorphic belongsTo association", }); }; - run(function() { + run(() => { env.store.push({ data: { id: '1', @@ -126,8 +125,8 @@ test("The store can materialize a non loaded monomorphic belongsTo association", }); }); - run(function() { - env.store.findRecord('post', 1).then(function(post) { + return run(() => { + return env.store.findRecord('post', 1).then(post => { post.get('user'); }); }); @@ -136,7 +135,7 @@ test("The store can materialize a non loaded monomorphic belongsTo association", testInDebug("Only a record of the same modelClass can be used with a monomorphic belongsTo relationship", function(assert) { assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { store.push({ data: { id: '1', @@ -152,12 +151,12 @@ testInDebug("Only a record of the same modelClass can be used with a monomorphic }); - run(function() { - hash({ + return run(() => { + return hash({ post: store.findRecord('post', 1), comment: store.findRecord('comment', 2) - }).then(function(records) { - assert.expectAssertion(function() { + }).then(records => { + assert.expectAssertion(() => { records.post.set('user', records.comment); }, /You cannot add a record of modelClass 'comment' to the 'post.user' relationship/); }); @@ -167,7 +166,7 @@ testInDebug("Only a record of the same modelClass can be used with a monomorphic testInDebug("Only a record of the same base modelClass can be used with a polymorphic belongsTo relationship", function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; assert.expect(1); - run(function() { + run(() => { store.push({ data: [{ id: '1', @@ -193,22 +192,22 @@ testInDebug("Only a record of the same base modelClass can be used with a polymo }); - run(function() { - var asyncRecords = hash({ + return run(() => { + let asyncRecords = hash({ user: store.findRecord('user', 3), post: store.findRecord('post', 1), comment: store.findRecord('comment', 1), anotherComment: store.findRecord('comment', 2) }); - asyncRecords.then(function(records) { - var comment = records.comment; + return asyncRecords.then(records => { + let comment = records.comment; comment.set('message', records.anotherComment); comment.set('message', records.post); comment.set('message', null); - assert.expectAssertion(function() { + assert.expectAssertion(() => { comment.set('message', records.user); }, /You cannot add a record of modelClass 'user' to the 'comment.message' relationship \(only 'message' allowed\)/); }); @@ -217,7 +216,7 @@ testInDebug("Only a record of the same base modelClass can be used with a polymo test("The store can load a polymorphic belongsTo association", function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + run(() => { env.store.push({ data: { id: '1', @@ -241,11 +240,11 @@ test("The store can load a polymorphic belongsTo association", function(assert) }); }); - run(function() { - hash({ + return run(() => { + return hash({ message: store.findRecord('post', 1), comment: store.findRecord('comment', 2) - }).then(function(records) { + }).then(records => { assert.equal(records.comment.get('message'), records.message); }); }); @@ -253,19 +252,21 @@ test("The store can load a polymorphic belongsTo association", function(assert) test("The store can serialize a polymorphic belongsTo association", function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; - var serializerInstance = store.serializerFor('comment'); + let serializerInstance = store.serializerFor('comment'); serializerInstance.serializePolymorphicType = function(record, json, relationship) { assert.ok(true, "The serializer's serializePolymorphicType method should be called"); json["message_type"] = "post"; }; - run(function() { + + return run(() => { env.store.push({ data: { id: '1', type: 'post' } }); + env.store.push({ data: { id: '2', @@ -281,8 +282,8 @@ test("The store can serialize a polymorphic belongsTo association", function(ass } }); - store.findRecord('comment', 2).then(function(comment) { - var serialized = comment.serialize({ includeId: true }); + return store.findRecord('comment', 2).then(comment => { + let serialized = comment.serialize({ includeId: true }); assert.equal(serialized.data.relationships.message.data.id, 1); assert.equal(serialized.data.relationships.message.data.type, 'posts'); }); @@ -290,20 +291,19 @@ test("The store can serialize a polymorphic belongsTo association", function(ass }); test("A serializer can materialize a belongsTo as a link that gets sent back to findBelongsTo", function(assert) { - let done = assert.async(); env.adapter.shouldBackgroundReloadRecord = () => false; - var Group = DS.Model.extend({ + let Group = DS.Model.extend({ people: DS.hasMany('person', { async: false }) }); - var Person = DS.Model.extend({ + let Person = DS.Model.extend({ group: DS.belongsTo({ async: true }) }); env.registry.register('model:group', Group); env.registry.register('model:person', Person); - run(function() { + run(() => { store.push({ data: { id: '1', @@ -323,7 +323,7 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to throw new Error("Adapter's find method should not be called"); }; - env.adapter.findBelongsTo = assert.wait(function(store, snapshot, link, relationship) { + env.adapter.findBelongsTo = function(store, snapshot, link, relationship) { assert.equal(relationship.type, 'group'); assert.equal(relationship.key, 'group'); assert.equal(link, "/people/1/group"); @@ -339,34 +339,32 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to } } }); - }); + }; - run(function() { - env.store.findRecord('person', 1).then(function(person) { + return run(() => { + return env.store.findRecord('person', 1).then(person => { return person.get('group'); - }).then(function(group) { + }).then(group => { assert.ok(group instanceof Group, "A group object is loaded"); assert.ok(group.get('id') === '1', 'It is the group we are expecting'); - done(); }); }); }); test('A record with an async belongsTo relationship always returns a promise for that relationship', function(assert) { - let done = assert.async(); env.adapter.shouldBackgroundReloadRecord = () => false; - var Seat = DS.Model.extend({ + let Seat = DS.Model.extend({ person: DS.belongsTo('person', { async: false }) }); - var Person = DS.Model.extend({ + let Person = DS.Model.extend({ seat: DS.belongsTo('seat', { async: true }) }); env.registry.register('model:seat', Seat); env.registry.register('model:person', Person); - run(function() { + run(() => { store.push({ data: { id: '1', @@ -386,18 +384,17 @@ test('A record with an async belongsTo relationship always returns a promise for throw new Error("Adapter's find method should not be called"); }; - env.adapter.findBelongsTo = assert.wait(function(store, snapshot, link, relationship) { + env.adapter.findBelongsTo = function(store, snapshot, link, relationship) { return Ember.RSVP.resolve({ data: { id: 1, type: 'seat' } }); - }); + }; - run(function() { - env.store.findRecord('person', 1).then(function(person) { - person.get('seat').then(function(seat) { + return run(() => { + return env.store.findRecord('person', 1).then(person => { + return person.get('seat').then(seat => { // this assertion fails too // ok(seat.get('person') === person, 'parent relationship should be populated'); seat.set('person', person); assert.ok(person.get('seat').then, 'seat should be a PromiseObject'); - done(); }); }); }); @@ -407,18 +404,18 @@ test("A record with an async belongsTo relationship returning null should resolv assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; - var Group = DS.Model.extend({ + let Group = DS.Model.extend({ people: DS.hasMany('person', { async: false }) }); - var Person = DS.Model.extend({ + let Person = DS.Model.extend({ group: DS.belongsTo({ async: true }) }); env.registry.register('model:group', Group); env.registry.register('model:person', Person); - run(function() { + run(() => { store.push({ data: { id: '1', @@ -438,33 +435,33 @@ test("A record with an async belongsTo relationship returning null should resolv throw new Error("Adapter's find method should not be called"); }; - env.adapter.findBelongsTo = assert.wait(function(store, snapshot, link, relationship) { + env.adapter.findBelongsTo = function(store, snapshot, link, relationship) { return Ember.RSVP.resolve({ data: null }); - }); + }; - env.store.findRecord('person', '1').then(assert.wait(function(person) { + return env.store.findRecord('person', '1').then(person => { return person.get('group'); - })).then(assert.wait(function(group) { + }).then(group => { assert.ok(group === null, "group should be null"); - })); + }); }); test("A record can be created with a resolved belongsTo promise", function(assert) { assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; - var Group = DS.Model.extend({ + let Group = DS.Model.extend({ people: DS.hasMany('person', { async: false }) }); - var Person = DS.Model.extend({ + let Person = DS.Model.extend({ group: DS.belongsTo({ async: true }) }); env.registry.register('model:group', Group); env.registry.register('model:person', Person); - run(function() { + run(() => { store.push({ data: { id: 1, @@ -473,58 +470,42 @@ test("A record can be created with a resolved belongsTo promise", function(asser }); }); - var groupPromise = store.findRecord('group', 1); - groupPromise.then(assert.wait(function(group) { - var person = env.store.createRecord('person', { + let groupPromise = store.findRecord('group', 1); + return groupPromise.then(group => { + let person = env.store.createRecord('person', { group: groupPromise }); assert.equal(person.get('group.content'), group); - })); + }); }); test("polymorphic belongsTo class-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled", function(assert) { assert.expect(1); - var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; - Ember.MODEL_FACTORY_INJECTIONS = true; + run(() => { + let igor = env.store.createRecord('user', { name: 'Igor' }); + let post = env.store.createRecord('post', { title: "Igor's unimaginative blog post" }); - try { - run(function () { - var igor = env.store.createRecord('user', { name: 'Igor' }); - var post = env.store.createRecord('post', { title: "Igor's unimaginative blog post" }); - - igor.set('favouriteMessage', post); + igor.set('favouriteMessage', post); - assert.equal(igor.get('favouriteMessage.title'), "Igor's unimaginative blog post"); - }); - } finally { - Ember.MODEL_FACTORY_INJECTIONS = injectionValue; - } + assert.equal(igor.get('favouriteMessage.title'), "Igor's unimaginative blog post"); + }); }); test("the subclass in a polymorphic belongsTo relationship is an instanceof its superclass", function(assert) { assert.expect(1); - - var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; - Ember.MODEL_FACTORY_INJECTIONS = true; - - try { - run(function () { - var message = env.store.createRecord('message', { id: 1 }); - var comment = env.store.createRecord('comment', { id: 2, message: message }); - assert.ok(comment instanceof Message, 'a comment is an instance of a message'); - }); - - } finally { - Ember.MODEL_FACTORY_INJECTIONS = injectionValue; - } + run(() => { + let message = env.store.createRecord('message', { id: 1 }); + let comment = env.store.createRecord('comment', { id: 2, message: message }); + assert.ok(comment instanceof Message, 'a comment is an instance of a message'); + }); }); test("relationshipsByName does not cache a factory", function(assert) { // The model is loaded up via a container. It has relationshipsByName // called on it. - var modelViaFirstFactory = store.modelFor('user'); + let modelViaFirstFactory = store.modelFor('user'); get(modelViaFirstFactory, 'relationshipsByName'); // An app is reset, or the container otherwise destroyed. @@ -542,26 +523,26 @@ test("relationshipsByName does not cache a factory", function(assert) { store = env.store; // relationshipsByName is called again. - var modelViaSecondFactory = store.modelFor('user'); - var relationshipsByName = get(modelViaSecondFactory, 'relationshipsByName'); - var messageType = relationshipsByName.get('messages').type; + let modelViaSecondFactory = store.modelFor('user'); + let relationshipsByName = get(modelViaSecondFactory, 'relationshipsByName'); + let messageType = relationshipsByName.get('messages').type; // A model is looked up in the store based on a string, via user input - var messageModelFromStore = store.modelFor('message'); + let messageModelFromStore = store.modelFor('message'); // And the model is lookup up internally via the relationship type - var messageModelFromRelationType = store.modelFor(messageType); + let messageModelFromRelationType = store.modelFor(messageType); assert.equal(messageModelFromRelationType, messageModelFromStore, "model factory based on relationship type matches the model based on store.modelFor"); }); test("relationshipsByName is cached in production", function(assert) { - var model = store.modelFor('user'); - var oldTesting = Ember.testing; + let model = store.modelFor('user'); + let oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it //did not get dynamically changed when accessed - var relationshipsByName = model.relationshipsByName; - var oldCacheable = relationshipsByName._cacheable; + let relationshipsByName = model.relationshipsByName; + let oldCacheable = relationshipsByName._cacheable; relationshipsByName._cacheable = true; Ember.testing = false; try { @@ -574,12 +555,12 @@ test("relationshipsByName is cached in production", function(assert) { }); test("relatedTypes is cached in production", function(assert) { - var model = store.modelFor('user'); - var oldTesting = Ember.testing; + let model = store.modelFor('user'); + let oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it //did not get dynamically changed when accessed - var relatedTypes = model.relatedTypes; - var oldCacheable = relatedTypes._cacheable; + let relatedTypes = model.relatedTypes; + let oldCacheable = relatedTypes._cacheable; relatedTypes._cacheable = true; Ember.testing = false; try { @@ -592,12 +573,12 @@ test("relatedTypes is cached in production", function(assert) { }); test("relationships is cached in production", function(assert) { - var model = store.modelFor('user'); - var oldTesting = Ember.testing; + let model = store.modelFor('user'); + let oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it //did not get dynamically changed when accessed - var relationships = model.relationships; - var oldCacheable = relationships._cacheable; + let relationships = model.relationships; + let oldCacheable = relationships._cacheable; relationships._cacheable = true; Ember.testing = false; try { @@ -635,8 +616,8 @@ test("relationship changes shouldn’t cause async fetches", function(assert) { env.store.modelFor('comment').reopen({ post: DS.belongsTo('post', { async: false }) }); - var comment; - run(function() { + let comment; + run(() => { env.store.push({ data: { id: '1', @@ -689,7 +670,7 @@ test("relationship changes shouldn’t cause async fetches", function(assert) { test("Destroying a record with an unloaded aync belongsTo association does not fetch the record", function(assert) { assert.expect(2); - var post; + let post; env.store.modelFor('message').reopen({ user: DS.hasMany('user', { @@ -704,7 +685,7 @@ test("Destroying a record with an unloaded aync belongsTo association does not f }) }); - run(function() { + run(() => { post = env.store.push({ data: { id: '1', @@ -752,8 +733,8 @@ test("Destroying a record with an unloaded aync belongsTo association does not f }); testInDebug("A sync belongsTo errors out if the record is unlaoded", function(assert) { - var message; - run(function() { + let message; + run(() => { message = env.store.push({ data: { id: '1', @@ -771,7 +752,7 @@ testInDebug("A sync belongsTo errors out if the record is unlaoded", function(as }); - assert.expectAssertion(function() { + assert.expectAssertion(() => { message.get('user'); }, /You looked up the 'user' relationship on a 'message' with id 1 but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async \(`DS.belongsTo\({ async: true }\)`\)/); }); @@ -780,8 +761,8 @@ test("Rollbacking attributes for a deleted record restores implicit relationship Book.reopen({ author: DS.belongsTo('author', { async: true }) }); - var book, author; - run(function() { + let book, author; + run(() => { book = env.store.push({ data: { id: '1', @@ -810,18 +791,20 @@ test("Rollbacking attributes for a deleted record restores implicit relationship }); }); - run(function() { + return run(() => { author.deleteRecord(); author.rollbackAttributes(); - book.get('author').then(function(fetchedAuthor) { + + return book.get('author').then(fetchedAuthor => { assert.equal(fetchedAuthor, author, 'Book has an author after rollback attributes'); }); }); }); test("Rollbacking attributes for a deleted record restores implicit relationship - sync", function(assert) { - var book, author; - run(function() { + let book, author; + + run(() => { book = env.store.push({ data: { id: '1', @@ -839,6 +822,7 @@ test("Rollbacking attributes for a deleted record restores implicit relationship } } }); + author = env.store.push({ data: { id: '2', @@ -848,19 +832,20 @@ test("Rollbacking attributes for a deleted record restores implicit relationship } } }); - }); - run(function() { + + run(() =>{ author.deleteRecord(); author.rollbackAttributes(); }); + assert.equal(book.get('author'), author, 'Book has an author after rollback attributes'); }); testInDebug("Passing a model as type to belongsTo should not work", function(assert) { assert.expect(1); - assert.expectAssertion(function() { + assert.expectAssertion(() => { User = DS.Model.extend(); DS.Model.extend({ @@ -889,9 +874,9 @@ test("belongsTo hasData async loaded", function(assert) { }); }; - run(function() { - store.findRecord('book', 1).then(function(book) { - var relationship = book._internalModel._relationships.get('author'); + return run(() => { + return store.findRecord('book', 1).then(book => { + let relationship = book._internalModel._relationships.get('author'); assert.equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -913,9 +898,9 @@ test("belongsTo hasData sync loaded", function(assert) { }); }; - run(function() { - store.findRecord('book', 1).then(function(book) { - var relationship = book._internalModel._relationships.get('author'); + return run(() => { + return store.findRecord('book', 1).then(book => { + let relationship = book._internalModel._relationships.get('author'); assert.equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -941,9 +926,9 @@ test("belongsTo hasData async not loaded", function(assert) { }); }; - run(function() { - store.findRecord('book', 1).then(function(book) { - var relationship = book._internalModel._relationships.get('author'); + return run(() => { + return store.findRecord('book', 1).then(book => { + let relationship = book._internalModel._relationships.get('author'); assert.equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -962,9 +947,9 @@ test("belongsTo hasData sync not loaded", function(assert) { }); } - run(function() { - store.findRecord('book', 1).then(function(book) { - var relationship = book._internalModel._relationships.get('author'); + return run(() => { + return store.findRecord('book', 1).then(book => { + let relationship = book._internalModel._relationships.get('author'); assert.equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -977,9 +962,9 @@ test("belongsTo hasData async created", function(assert) { author: belongsTo('author', { async: true }) }); - run(function() { - var book = store.createRecord('book', { name: 'The Greatest Book' }); - var relationship = book._internalModel._relationships.get('author'); + run(() => { + let book = store.createRecord('book', { name: 'The Greatest Book' }); + let relationship = book._internalModel._relationships.get('author'); assert.equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -987,16 +972,17 @@ test("belongsTo hasData async created", function(assert) { test("belongsTo hasData sync created", function(assert) { assert.expect(1); - run(function() { - var book = store.createRecord('book', { name: 'The Greatest Book' }); - var relationship = book._internalModel._relationships.get('author'); + run(() => { + let book = store.createRecord('book', { name: 'The Greatest Book' }); + let relationship = book._internalModel._relationships.get('author'); assert.equal(relationship.hasData, true, 'relationship has data'); }); }); test("Model's belongsTo relationship should not be created during model creation", function(assert) { - var user; - run(function () { + let user; + + run(() => { user = env.store.push({ data: { id: '1', @@ -1009,8 +995,9 @@ test("Model's belongsTo relationship should not be created during model creation }); test("Model's belongsTo relationship should be created during model creation if relationship passed in constructor", function(assert) { - var user, message; - run(function () { + let user, message; + + run(() => { message = env.store.createRecord('message'); user = env.store.createRecord('user', { name: 'John Doe', @@ -1021,8 +1008,9 @@ test("Model's belongsTo relationship should be created during model creation if }); test("Model's belongsTo relationship should be created during 'set' method", function(assert) { - var user, message; - run(function () { + let user, message; + + run(() => { message = env.store.createRecord('message'); user = env.store.createRecord('user'); user.set('favouriteMessage', message); @@ -1031,8 +1019,9 @@ test("Model's belongsTo relationship should be created during 'set' method", fun }); test("Model's belongsTo relationship should be created during 'get' method", function(assert) { - var user; - run(function () { + let user; + + run(() => { user = env.store.createRecord('user'); user.get('favouriteMessage'); assert.ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); @@ -1058,7 +1047,7 @@ test("Related link should be fetched when no local data is present", function(as }); }; - run(function() { + return run(() => { let book = env.store.push({ data: { type: 'book', @@ -1072,7 +1061,8 @@ test("Related link should be fetched when no local data is present", function(as } } }); - book.get('author').then((author) => { + + return book.get('author').then(author => { assert.equal(author.get('name'), 'This is author', 'author name is correct'); }); }); @@ -1099,7 +1089,7 @@ test("Local data should take precedence over related link", function(assert) { }); }; - run(function() { + return run(() => { let book = env.store.push({ data: { type: 'book', @@ -1114,7 +1104,8 @@ test("Local data should take precedence over related link", function(assert) { } } }); - book.get('author').then((author) => { + + return book.get('author').then(author => { assert.equal(author.get('name'), 'This is author', 'author name is correct'); }); }); @@ -1143,7 +1134,7 @@ test("New related link should take precedence over local data", function(assert) assert.ok(false, "The adapter's findRecord method should not be called"); }; - run(function() { + return run(() => { let book = env.store.push({ data: { type: 'book', @@ -1202,7 +1193,7 @@ test("Updated related link should take precedence over local data", function(ass assert.ok(false, "The adapter's findRecord method should not be called"); }; - run(function() { + return run(() => { let book = env.store.push({ data: { type: 'book', @@ -1225,26 +1216,26 @@ test("Updated related link should take precedence over local data", function(ass }] }); - book.get('author').then((author) => { + return book.get('author').then((author) => { assert.equal(author.get('name'), 'This is author', 'author name is correct'); - }); - - env.store.push({ - data: { - type: 'book', - id: '1', - relationships: { - author: { - links: { - related: 'author-updated-link' + }).then(() => { + env.store.push({ + data: { + type: 'book', + id: '1', + relationships: { + author: { + links: { + related: 'author-updated-link' + } } } } - } - }); + }); - book.get('author').then((author) => { - assert.equal(author.get('name'), 'This is updated author', 'author name is correct'); + return book.get('author').then((author) => { + assert.equal(author.get('name'), 'This is updated author', 'author name is correct'); + }); }); }); }); @@ -1264,7 +1255,7 @@ test("Updated identical related link should not take precedence over local data" assert.ok(false, "The adapter's findRecord method should not be called"); }; - run(function() { + return run(() => { let book = env.store.push({ data: { type: 'book', @@ -1287,33 +1278,32 @@ test("Updated identical related link should not take precedence over local data" }] }); - book.get('author').then((author) => { + return book.get('author').then((author) => { assert.equal(author.get('name'), 'This is author', 'author name is correct'); - }); + }).then(() => { - env.store.push({ - data: { - type: 'book', - id: '1', - relationships: { - author: { - links: { - related: 'author' + env.store.push({ + data: { + type: 'book', + id: '1', + relationships: { + author: { + links: { + related: 'author' + } } } } - } - }); + }); - book.get('author').then((author) => { - assert.equal(author.get('name'), 'This is author', 'author name is correct'); + return book.get('author').then((author) => { + assert.equal(author.get('name'), 'This is author', 'author name is correct'); + }); }); }); }); test("A belongsTo relationship can be reloaded using the reference if it was fetched via link", function(assert) { - var done = assert.async(); - Chapter.reopen({ book: DS.belongsTo({ async: true }) }); @@ -1342,13 +1332,14 @@ test("A belongsTo relationship can be reloaded using the reference if it was fet }); }; - run(function() { - var chapter; - store.findRecord('chapter', 1).then(function(_chapter) { + return run(() => { + let chapter; + + return store.findRecord('chapter', 1).then(_chapter => { chapter = _chapter; return chapter.get('book'); - }).then(function(book) { + }).then(book => { assert.equal(book.get('name'), "book title"); env.adapter.findBelongsTo = function() { @@ -1362,23 +1353,19 @@ test("A belongsTo relationship can be reloaded using the reference if it was fet }; return chapter.belongsTo('book').reload(); - }).then(function(book) { + }).then(book => { assert.equal(book.get('name'), "updated book title"); - - done(); }); }); }); test("A sync belongsTo relationship can be reloaded using a reference if it was fetched via id", function(assert) { - var done = assert.async(); - Chapter.reopen({ book: DS.belongsTo() }); - var chapter; - run(function() { + let chapter; + run(() => { chapter = env.store.push({ data: { type: 'chapter', @@ -1411,27 +1398,23 @@ test("A sync belongsTo relationship can be reloaded using a reference if it was }); }; - run(function() { - var book = chapter.get('book'); + return run(() => { + let book = chapter.get('book'); assert.equal(book.get('name'), "book title"); - chapter.belongsTo('book').reload().then(function(book) { + return chapter.belongsTo('book').reload().then(function(book) { assert.equal(book.get('name'), "updated book title"); - - done(); }); }); }); test("A belongsTo relationship can be reloaded using a reference if it was fetched via id", function(assert) { - var done = assert.async(); - Chapter.reopen({ book: DS.belongsTo({ async: true }) }); - var chapter; - run(function() { + let chapter; + run(() => { chapter = env.store.push({ data: { type: 'chapter', @@ -1455,8 +1438,8 @@ test("A belongsTo relationship can be reloaded using a reference if it was fetch }); }; - run(function() { - chapter.get('book').then(function(book) { + return run(() => { + return chapter.get('book').then(book => { assert.equal(book.get('name'), "book title"); env.adapter.findRecord = function() { @@ -1470,17 +1453,15 @@ test("A belongsTo relationship can be reloaded using a reference if it was fetch }; return chapter.belongsTo('book').reload(); - }).then(function(book) { + }).then(book => { assert.equal(book.get('name'), "updated book title"); - - done(); }); }); }); testInDebug("A belongsTo relationship warns if malformatted data is pushed into the store", function(assert) { - assert.expectAssertion(function() { - run(function() { + assert.expectAssertion(() => { + run(() => { let chapter = env.store.push({ data: { type: 'chapter', diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index b7534447b16..e2915ce39f7 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -8,15 +8,12 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var env, store, User, Contact, Email, Phone, Message, Post, Comment; -var Book, Chapter, Page; -var get = Ember.get; -var resolve = Ember.RSVP.resolve; -var run = Ember.run; +let env, store, User, Contact, Email, Phone, Message, Post, Comment; +let Book, Chapter, Page; -var attr = DS.attr; -var hasMany = DS.hasMany; -var belongsTo = DS.belongsTo; +const { get, run } = Ember; +const { resolve } = Ember.RSVP; +const { attr, hasMany, belongsTo } = DS; module("integration/relationships/has_many - Has-Many Relationships", { beforeEach() { @@ -122,7 +119,7 @@ test("When a hasMany relationship is accessed, the adapter's findMany method sho return { data: postData }; }; - run(function() { + return run(() => { env.store.push({ data: postData, included: [{ @@ -130,7 +127,8 @@ test("When a hasMany relationship is accessed, the adapter's findMany method sho id: '1' }] }); - env.store.findRecord('post', 1).then(function(post) { + + return env.store.findRecord('post', 1).then(post => { return post.get('comments'); }); }); @@ -169,11 +167,12 @@ test("adapter.findMany only gets unique IDs even if duplicate IDs are present in return { data: bookData }; }; - run(function() { + return run(() => { env.store.push({ data: bookData }); - env.store.findRecord('book', 1).then(function(book) { + + return env.store.findRecord('book', 1).then(book => { return book.get('chapters'); }); }); @@ -226,21 +225,20 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi }); }; - run(function() { - env.store.findRecord('post', 1).then(assert.wait(function(post) { + return run(() => { + return env.store.findRecord('post', 1).then(post => { return post.get('comments'); - })).then(assert.wait(function(comments) { + }).then(comments => { assert.equal(comments.get('isLoaded'), true, "comments are loaded"); assert.equal(comments.get('length'), 2, "comments have 2 length"); assert.equal(comments.objectAt(0).get('body'), 'First', "comment loaded successfully"); - })); + }); }); }); test("Accessing a hasMany backed by a link multiple times triggers only one request", function(assert) { assert.expect(2); - let done = assert.async(); - var count = 0; + let count = 0; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -248,9 +246,9 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ Comment.reopen({ message: DS.belongsTo('post', { async: true }) }); - var post; + let post; - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -270,9 +268,9 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ env.adapter.findHasMany = function(store, snapshot, link, relationship) { count++; assert.equal(count, 1, "findHasMany has only been called once"); - return new Ember.RSVP.Promise(function(resolve, reject) { - setTimeout(function() { - var value = { + return new Ember.RSVP.Promise((resolve, reject) => { + setTimeout(() => { + let value = { data: [ { id: 1, type: 'comment', attributes: { body: "First" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } @@ -283,8 +281,9 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ }); }; - var promise1, promise2; - run(function() { + let promise1, promise2; + + run(() => { promise1 = post.get('comments'); //Invalidate the post.comments CP env.store.push({ @@ -300,9 +299,12 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ }); promise2 = post.get('comments'); }); - Ember.RSVP.all([promise1, promise2]).then(function() { + + return Ember.RSVP.all([ + promise1, + promise2 + ]).then(() => { assert.equal(promise1.promise, promise2.promise, "Same promise is returned both times"); - done(); }); }); @@ -324,8 +326,8 @@ test("A hasMany backed by a link remains a promise after a record has been added ] }); }; - var post; - run(function() { + let post; + run(() => { env.store.push({ data: { type: 'post', @@ -342,8 +344,8 @@ test("A hasMany backed by a link remains a promise after a record has been added post = env.store.peekRecord('post', 1); }); - run(function() { - post.get('comments').then(function() { + return run(() => { + return post.get('comments').then(() => { env.store.push({ data: { type: 'comment', @@ -355,7 +357,8 @@ test("A hasMany backed by a link remains a promise after a record has been added } } }); - post.get('comments').then(function() { + + return post.get('comments').then(() => { assert.ok(true, 'Promise was called'); }); }); @@ -389,20 +392,18 @@ test("A hasMany updated link should not remove new children", function(assert) { }); }; - run(function() { - var post = env.store.createRecord('post', {}); + return run(() => { + let post = env.store.createRecord('post', {}); env.store.createRecord('comment', { message: post }); - post.get('comments') - .then(function(comments) { + return post.get('comments') + .then(comments => { assert.equal(comments.get('length'), 1); return post.save(); }) - .then(function() { - return post.get('comments'); - }) - .then(function(comments) { + .then(() => post.get('comments')) + .then(comments => { assert.equal(comments.get('length'), 1); }); }); @@ -437,20 +438,17 @@ test("A hasMany updated link should not remove new children when the parent reco }); }; - run(function() { - var post = env.store.createRecord('post', {}); + return run(() => { + let post = env.store.createRecord('post', {}); env.store.createRecord('comment', { message: post }); - post.get('comments') - .then(function(comments) { + return post.get('comments') + .then(comments => { assert.equal(comments.get('length'), 1); - return post.save(); }) - .then(function() { - return post.get('comments'); - }) - .then(function(comments) { + .then(() =>post.get('comments')) + .then(comments => { assert.equal(comments.get('length'), 2); }); }); @@ -470,21 +468,21 @@ test("A hasMany relationship doesn't contain duplicate children, after the canon return Ember.RSVP.resolve({ data: { id: 1, type: 'post' } }); }; - run(function() { - var post = env.store.createRecord('post', {}); + return run(() => { + let post = env.store.createRecord('post', {}); // create a new comment with id 'local', which is in the 'comments' // relationship of post - var localComment = env.store.createRecord('comment', { id: 'local', message: post }); + let localComment = env.store.createRecord('comment', { id: 'local', message: post }); - post.get('comments') - .then(function(comments) { + return post.get('comments') + .then(comments => { assert.equal(comments.get('length'), 1); assert.equal(localComment.get('isNew'), true); return post.save(); }) - .then(function() { + .then(() => { // Now the post is saved but the locally created comment with the id // 'local' is still in the created state since it hasn't been saved @@ -513,10 +511,8 @@ test("A hasMany relationship doesn't contain duplicate children, after the canon }); }) - .then(function() { - return post.get('comments'); - }) - .then(function(comments) { + .then(() => post.get('comments')) + .then(comments => { assert.equal(comments.get('length'), 1); assert.equal(localComment.get('isNew'), true); }); @@ -626,7 +622,7 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu }); env.store.findRecord('post', '1').then(function(post) { - var comments = post.get('comments'); + let comments = post.get('comments'); assert.equal(comments.get('isLoaded'), true, "comments are loaded"); assert.equal(comments.get('length'), 2, "comments have a length of 2"); @@ -715,7 +711,7 @@ test("A hasMany relationship can be reloaded even if it failed at the first time }); }; - var loadingCount = -1; + let loadingCount = -1; env.adapter.findHasMany = function(store, record, link, relationship) { loadingCount++; if (loadingCount % 2 === 0) { @@ -729,7 +725,7 @@ test("A hasMany relationship can be reloaded even if it failed at the first time }; run(function() { env.store.findRecord('post', 1).then(function(post) { - var comments = post.get('comments'); + let comments = post.get('comments'); return comments.catch(function() { return comments.reload(); }).then(function(manyArray) { @@ -927,7 +923,7 @@ test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loa { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); }; - var post; + let post; run(function() { env.store.push({ @@ -951,7 +947,7 @@ test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loa assert.equal(comments.get('isLoaded'), true, "comments are loaded"); assert.equal(comments.get('length'), 2, "comments have 2 length"); - var newComment = post.get('comments').createRecord({ body: 'Third' }); + let newComment = post.get('comments').createRecord({ body: 'Third' }); assert.equal(newComment.get('body'), 'Third', "new comment is returned"); assert.equal(comments.get('length'), 3, "comments have 3 length, including new record"); }); @@ -971,7 +967,7 @@ test("PromiseArray proxies evented methods to its ManyArray", function(assert) { { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); }; - var post, comments; + let post, comments; run(function() { env.store.push({ @@ -1045,7 +1041,7 @@ test("An updated `links` value should invalidate a relationship cache", function ]}); } }; - var post; + let post; run(function() { env.store.push({ @@ -1130,7 +1126,7 @@ test("When a polymorphic hasMany relationship is accessed, the adapter's findMan run(function() { env.store.findRecord('user', 1).then(function(user) { - var messages = user.get('messages'); + let messages = user.get('messages'); assert.equal(messages.get('length'), 2, "The messages are correctly loaded"); }); }); @@ -1178,13 +1174,13 @@ test("When a polymorphic hasMany relationship is accessed, the store can call mu test("polymorphic hasMany type-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled", function(assert) { assert.expect(1); - var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; + let injectionValue = Ember.MODEL_FACTORY_INJECTIONS; Ember.MODEL_FACTORY_INJECTIONS = true; try { run(function () { - var igor = env.store.createRecord('user', { name: 'Igor' }); - var comment = env.store.createRecord('comment', { body: "Well I thought the title was fine" }); + let igor = env.store.createRecord('user', { name: 'Igor' }); + let comment = env.store.createRecord('comment', { body: "Well I thought the title was fine" }); igor.get('messages').addObject(comment); @@ -1343,7 +1339,7 @@ test("Polymorphic relationships with a hasMany is set up correctly on both sides Post.reopen({ contact: DS.belongsTo('contact', { polymorphic: true, async: false }) }); - var email, post; + let email, post; run(function () { email = env.store.createRecord('email'); @@ -1451,7 +1447,7 @@ testInDebug("Only records of the same base modelClass can be added to a polymorp }] }); }); - var asyncRecords; + let asyncRecords; run(function() { asyncRecords = Ember.RSVP.hash({ @@ -1498,7 +1494,7 @@ test("A record can be removed from a polymorphic association", function(assert) }] }); }); - var asyncRecords; + let asyncRecords; run(function() { asyncRecords = Ember.RSVP.hash({ @@ -1512,7 +1508,7 @@ test("A record can be removed from a polymorphic association", function(assert) }).then(function(records) { assert.equal(records.messages.get('length'), 1, "The user has 1 message"); - var removedObject = records.messages.popObject(); + let removedObject = records.messages.popObject(); assert.equal(removedObject, records.comment, "The message is correctly removed"); assert.equal(records.messages.get('length'), 0, "The user does not have any messages"); @@ -1524,14 +1520,14 @@ test("A record can be removed from a polymorphic association", function(assert) test("When a record is created on the client, its hasMany arrays should be in a loaded state", function(assert) { assert.expect(3); - var post; + let post; run(function() { post = env.store.createRecord('post'); }); assert.ok(get(post, 'isLoaded'), "The post should have isLoaded flag"); - var comments; + let comments; run(function() { comments = get(post, 'comments'); }); @@ -1548,7 +1544,7 @@ test("When a record is created on the client, its async hasMany arrays should be comments: DS.hasMany('comment', { async: true }) }); - var post = run(function() { + let post = run(function() { return env.store.createRecord('post'); }); @@ -1565,7 +1561,7 @@ test("When a record is created on the client, its async hasMany arrays should be test("we can set records SYNC HM relationship", function(assert) { assert.expect(1); - var post = run(function() { + let post = run(function() { return env.store.createRecord('post'); }); run(function() { @@ -1596,7 +1592,7 @@ test("We can set records ASYNC HM relationship", function(assert) { comments: DS.hasMany('comment', { async: true }) }); - var post = run(function() { + let post = run(function() { return env.store.createRecord('post'); }); run(function() { @@ -1618,28 +1614,28 @@ test("We can set records ASYNC HM relationship", function(assert) { post.set('comments', env.store.peekAll('comment')); }); - post.get('comments').then(assert.wait(function(comments) { + return post.get('comments').then(comments => { assert.equal(comments.get('length') , 2, "we can set async HM relationship"); - })); + }); }); test("When a record is saved, its unsaved hasMany records should be kept", function(assert) { assert.expect(1); - var post, comment; + let post, comment; env.adapter.createRecord = function(store, type, snapshot) { return Ember.RSVP.resolve({ data: { id: 1, type: snapshot.modelName } }); }; - run(function () { + return run(() => { post = env.store.createRecord('post'); comment = env.store.createRecord('comment'); post.get('comments').pushObject(comment); - post.save(); + return post.save(); + }).then(() => { + assert.equal(get(post, 'comments.length'), 1, "The unsaved comment should be in the post's comments array"); }); - - assert.equal(get(post, 'comments.length'), 1, "The unsaved comment should be in the post's comments array"); }); test("dual non-async HM <-> BT", function(assert) { @@ -1652,11 +1648,11 @@ test("dual non-async HM <-> BT", function(assert) { }); env.adapter.createRecord = function(store, type, snapshot) { - var serialized = snapshot.record.serialize(); + let serialized = snapshot.record.serialize(); serialized.data.id = 2; return Ember.RSVP.resolve(serialized); }; - var post, firstComment; + let post, firstComment; run(function() { env.store.push({ @@ -1689,9 +1685,9 @@ test("dual non-async HM <-> BT", function(assert) { env.store.createRecord('comment', { post: post }).save().then(function(comment) { - var commentPost = comment.get('post'); - var postComments = comment.get('post.comments'); - var postCommentsLength = comment.get('post.comments.length'); + let commentPost = comment.get('post'); + let postComments = comment.get('post.comments'); + let postCommentsLength = comment.get('post.comments.length'); assert.deepEqual(post, commentPost, 'expect the new comments post, to be the correct post'); assert.ok(postComments, "comments should exist"); @@ -1717,9 +1713,9 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the env.adapter.findRecord = function(store, type, id, snapshot) { return resolve({ data: { id: 3, type: 'comment', attributes: { body: 'third' } } }); }; - var post; + let post; - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -1737,8 +1733,8 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the post = env.store.peekRecord('post', 1); }); - run(function() { - post.get('comments').then(assert.wait(function(fetchedComments) { + return run(() => { + return post.get('comments').then(fetchedComments => { assert.equal(fetchedComments.get('length'), 2, 'comments fetched successfully'); assert.equal(fetchedComments.objectAt(0).get('body'), 'first', 'first comment loaded successfully'); env.store.push({ @@ -1756,11 +1752,12 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the } } }); - post.get('comments').then(assert.wait(function(newlyFetchedComments) { + + return post.get('comments').then(newlyFetchedComments => { assert.equal(newlyFetchedComments.get('length'), 3, 'all three comments fetched successfully'); assert.equal(newlyFetchedComments.objectAt(2).get('body'), 'third', 'third comment loaded successfully'); - })); - })); + }); + }); }); }); @@ -1789,9 +1786,10 @@ testInDebug('A sync hasMany errors out if there are unlaoded records in it', fun }); test("If reordered hasMany data has been pushed to the store, the many array reflects the ordering change - sync", function(assert) { - var comment1, comment2, comment3, comment4; - var post; - run(function() { + let comment1, comment2, comment3, comment4; + let post; + + run(() => { env.store.push({ data: [{ type: 'comment', @@ -1814,7 +1812,7 @@ test("If reordered hasMany data has been pushed to the store, the many array ref comment4 = env.store.peekRecord('comment', 4); }); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -1834,7 +1832,7 @@ test("If reordered hasMany data has been pushed to the store, the many array ref assert.deepEqual(post.get('comments').toArray(), [comment1, comment2], 'Initial ordering is correct'); }); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -1852,7 +1850,7 @@ test("If reordered hasMany data has been pushed to the store, the many array ref }); assert.deepEqual(post.get('comments').toArray(), [comment2, comment1], 'Updated ordering is correct'); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -1869,7 +1867,7 @@ test("If reordered hasMany data has been pushed to the store, the many array ref }); assert.deepEqual(post.get('comments').toArray(), [comment2], 'Updated ordering is correct'); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -1889,7 +1887,7 @@ test("If reordered hasMany data has been pushed to the store, the many array ref }); assert.deepEqual(post.get('comments').toArray(), [comment1, comment2, comment3, comment4], 'Updated ordering is correct'); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -1907,7 +1905,7 @@ test("If reordered hasMany data has been pushed to the store, the many array ref }); assert.deepEqual(post.get('comments').toArray(), [comment4, comment3], 'Updated ordering is correct'); - run(function() { + run(() => { env.store.push({ data: { type: 'post', @@ -1925,12 +1923,14 @@ test("If reordered hasMany data has been pushed to the store, the many array ref } }); }); + assert.deepEqual(post.get('comments').toArray(), [comment4, comment2, comment3, comment1], 'Updated ordering is correct'); }); test("Rollbacking attributes for deleted record restores implicit relationship correctly when the hasMany side has been deleted - async", function(assert) { - var book, chapter; - run(function() { + let book, chapter; + + run(() => { env.store.push({ data: { type: 'book', @@ -1957,20 +1957,23 @@ test("Rollbacking attributes for deleted record restores implicit relationship c book = env.store.peekRecord('book', 1); chapter = env.store.peekRecord('chapter', 2); }); - run(function() { + + run(() => { chapter.deleteRecord(); chapter.rollbackAttributes(); }); - run(function() { - book.get('chapters').then(function(fetchedChapters) { + + return run(() => { + return book.get('chapters').then(fetchedChapters => { assert.equal(fetchedChapters.objectAt(0), chapter, 'Book has a chapter after rollback attributes'); }); }); }); test("Rollbacking attributes for deleted record restores implicit relationship correctly when the hasMany side has been deleted - sync", function(assert) { - var book, chapter; - run(function() { + let book, chapter; + + run(() => { env.store.push({ data: { type: 'book', @@ -1997,11 +2000,13 @@ test("Rollbacking attributes for deleted record restores implicit relationship c book = env.store.peekRecord('book', 1); chapter = env.store.peekRecord('chapter', 2); }); - run(function() { + + run(() => { chapter.deleteRecord(); chapter.rollbackAttributes(); }); - run(function() { + + run(() => { assert.equal(book.get('chapters.firstObject'), chapter, "Book has a chapter after rollback attributes"); }); }); @@ -2010,8 +2015,10 @@ test("Rollbacking attributes for deleted record restores implicit relationship c Page.reopen({ chapter: DS.belongsTo('chapter', { async: true }) }); - var chapter, page; - run(function() { + + let chapter, page; + + run(() => { env.store.push({ data: { type: 'chapter', @@ -2036,20 +2043,22 @@ test("Rollbacking attributes for deleted record restores implicit relationship c chapter = env.store.peekRecord('chapter', 2); page = env.store.peekRecord('page', 3); }); - run(function() { + + run(() => { chapter.deleteRecord(); chapter.rollbackAttributes(); }); - run(function() { - page.get('chapter').then(function(fetchedChapter) { + + return run(() => { + return page.get('chapter').then(fetchedChapter => { assert.equal(fetchedChapter, chapter, 'Page has a chapter after rollback attributes'); }); }); }); test("Rollbacking attributes for deleted record restores implicit relationship correctly when the belongsTo side has been deleted - sync", function(assert) { - var chapter, page; - run(function() { + let chapter, page; + run(() => { env.store.push({ data: { type: 'chapter', @@ -2074,21 +2083,23 @@ test("Rollbacking attributes for deleted record restores implicit relationship c chapter = env.store.peekRecord('chapter', 2); page = env.store.peekRecord('page', 3); }); - run(function() { + + run(() => { chapter.deleteRecord(); chapter.rollbackAttributes(); }); - run(function() { + + run(() => { assert.equal(page.get('chapter'), chapter, "Page has a chapter after rollback attributes"); }); }); test("ManyArray notifies the array observers and flushes bindings when removing", function(assert) { assert.expect(2); - var chapter, page, page2; - var observe = false; + let chapter, page, page2; + let observe = false; - run(function() { + run(() => { env.store.push({ data: [{ type: 'page', @@ -2135,7 +2146,8 @@ test("ManyArray notifies the array observers and flushes bindings when removing" } }); }); - run(function() { + + run(() => { observe = true; page2.set('chapter', null); observe = false; @@ -2144,10 +2156,10 @@ test("ManyArray notifies the array observers and flushes bindings when removing" test("ManyArray notifies the array observers and flushes bindings when adding", function(assert) { assert.expect(2); - var chapter, page, page2; - var observe = false; + let chapter, page, page2; + let observe = false; - run(function() { + run(() => { env.store.push({ data: [{ type: 'page', @@ -2193,7 +2205,8 @@ test("ManyArray notifies the array observers and flushes bindings when adding", } }); }); - run(function() { + + run(() => { observe = true; page2.set('chapter', chapter); observe = false; @@ -2203,7 +2216,7 @@ test("ManyArray notifies the array observers and flushes bindings when adding", testInDebug("Passing a model as type to hasMany should not work", function(assert) { assert.expect(1); - assert.expectAssertion(function() { + assert.expectAssertion(() => { User = DS.Model.extend(); Contact = DS.Model.extend({ @@ -2213,7 +2226,7 @@ testInDebug("Passing a model as type to hasMany should not work", function(asser }); test("Relationship.clear removes all records correctly", function(assert) { - var post; + let post; Comment.reopen({ post: DS.belongsTo('post', { async: false }) @@ -2223,7 +2236,7 @@ test("Relationship.clear removes all records correctly", function(assert) { comments: DS.hasMany('comment', { inverse: 'post', async: false }) }); - run(function() { + run(() => { env.store.push({ data: [{ type: 'post', @@ -2268,13 +2281,13 @@ test("Relationship.clear removes all records correctly", function(assert) { post = env.store.peekRecord('post', 2); }); - run(function() { + run(() => { // unclear what the semantics of clearing a yet to be created relationship // ought to be. env.store.peekAll('comment').mapBy('post'); post._internalModel._relationships.get('comments').clear(); - var comments = Ember.A(env.store.peekAll('comment')); + let comments = Ember.A(env.store.peekAll('comment')); assert.deepEqual(comments.mapBy('post'), [null, null, null]); }); @@ -2282,7 +2295,7 @@ test("Relationship.clear removes all records correctly", function(assert) { test('unloading a record with associated records does not prevent the store from tearing down', function(assert) { - var post; + let post; Comment.reopen({ post: DS.belongsTo('post', { async: false }) @@ -2292,7 +2305,7 @@ test('unloading a record with associated records does not prevent the store from comments: DS.hasMany('comment', { inverse: 'post', async: false }) }); - run(function() { + run(() => { env.store.push({ data: [{ type: 'post', @@ -2336,8 +2349,9 @@ test('unloading a record with associated records does not prevent the store from // because records are being removed) env.store.unloadRecord(post); }); + try { - run(function() { + run(() => { env.store.destroy(); }); assert.ok(true, "store destroyed correctly"); @@ -2348,14 +2362,13 @@ test('unloading a record with associated records does not prevent the store from test("adding and removing records from hasMany relationship #2666", function(assert) { assert.expect(4); - let done = assert.async(); - var Post = DS.Model.extend({ + let Post = DS.Model.extend({ comments: DS.hasMany('comment', { async: true }) }); Post.reopenClass({ toString: () => 'Post' }); - var Comment = DS.Model.extend({ + let Comment = DS.Model.extend({ post: DS.belongsTo('post', { async: false }) }); Comment.reopenClass({ toString: () => 'Comment' }); @@ -2368,7 +2381,7 @@ test("adding and removing records from hasMany relationship #2666", function(ass }) }); - var commentId = 4; + let commentId = 4; env.registry.register('adapter:comment', DS.RESTAdapter.extend({ deleteRecord(record) { return Ember.RSVP.resolve(); @@ -2381,7 +2394,7 @@ test("adding and removing records from hasMany relationship #2666", function(ass } })); - run(function() { + run(() => { env.store.push({ data: [{ type: 'post', @@ -2408,32 +2421,32 @@ test("adding and removing records from hasMany relationship #2666", function(ass }); }); - run(function() { - env.store.findRecord('post', 1).then(function (post) { - var comments = post.get('comments'); + return run(() => { + return env.store.findRecord('post', 1).then(post => { + let comments = post.get('comments'); assert.equal(comments.get('length'), 3, "Initial comments count"); // Add comment #4 - var comment = env.store.createRecord('comment'); + let comment = env.store.createRecord('comment'); comments.addObject(comment); - return comment.save().then(function() { - var comments = post.get('comments'); + + return comment.save().then(() => { + let comments = post.get('comments'); assert.equal(comments.get('length'), 4, "Comments count after first add"); // Delete comment #4 return comments.get('lastObject').destroyRecord(); - }).then(function() { - var comments = post.get('comments'); + }).then(() => { + let comments = post.get('comments'); assert.equal(comments.get('length'), 3, "Comments count after destroy"); // Add another comment #4 - var comment = env.store.createRecord('comment'); + let comment = env.store.createRecord('comment'); comments.addObject(comment); return comment.save(); - }).then(function() { - var comments = post.get('comments'); + }).then(() => { + let comments = post.get('comments'); assert.equal(comments.get('length'), 4, "Comments count after second add"); - done(); }); }); }); @@ -2461,9 +2474,9 @@ test("hasMany hasData async loaded", function(assert) { }); }; - run(function() { - store.findRecord('chapter', 1).then(function(chapter) { - var relationship = chapter._internalModel._relationships.get('pages'); + return run(() => { + return store.findRecord('chapter', 1).then(chapter => { + let relationship = chapter._internalModel._relationships.get('pages'); assert.equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -2487,9 +2500,9 @@ test("hasMany hasData sync loaded", function(assert) { }); }; - run(function() { - store.findRecord('chapter', 1).then(function(chapter) { - var relationship = chapter._internalModel._relationships.get('pages'); + return run(() => { + return store.findRecord('chapter', 1).then(chapter => { + let relationship = chapter._internalModel._relationships.get('pages'); assert.equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -2517,9 +2530,9 @@ test("hasMany hasData async not loaded", function(assert) { }); }; - run(function() { - store.findRecord('chapter', 1).then(function(chapter) { - var relationship = chapter._internalModel._relationships.get('pages'); + return run(() => { + return store.findRecord('chapter', 1).then(chapter => { + let relationship = chapter._internalModel._relationships.get('pages'); assert.equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -2538,9 +2551,9 @@ test("hasMany hasData sync not loaded", function(assert) { }); }; - run(function() { - store.findRecord('chapter', 1).then(function(chapter) { - var relationship = chapter._internalModel._relationships.get('pages'); + return run(() => { + return store.findRecord('chapter', 1).then(chapter => { + let relationship = chapter._internalModel._relationships.get('pages'); assert.equal(relationship.hasData, false, 'relationship does not have data'); }); }); @@ -2553,9 +2566,9 @@ test("hasMany hasData async created", function(assert) { pages: hasMany('pages', { async: true }) }); - run(function() { - var chapter = store.createRecord('chapter', { title: 'The Story Begins' }); - var relationship = chapter._internalModel._relationships.get('pages'); + run(() => { + let chapter = store.createRecord('chapter', { title: 'The Story Begins' }); + let relationship = chapter._internalModel._relationships.get('pages'); assert.equal(relationship.hasData, true, 'relationship has data'); }); }); @@ -2563,16 +2576,16 @@ test("hasMany hasData async created", function(assert) { test("hasMany hasData sync created", function(assert) { assert.expect(1); - run(function() { - var chapter = store.createRecord('chapter', { title: 'The Story Begins' }); - var relationship = chapter._internalModel._relationships.get('pages'); + run(() => { + let chapter = store.createRecord('chapter', { title: 'The Story Begins' }); + let relationship = chapter._internalModel._relationships.get('pages'); assert.equal(relationship.hasData, true, 'relationship has data'); }); }); test("Model's hasMany relationship should not be created during model creation", function(assert) { - var user; - run(function () { + let user; + run(() => { env.store.push({ data: { type: 'user', @@ -2585,8 +2598,8 @@ test("Model's hasMany relationship should not be created during model creation", }); test("Model's belongsTo relationship should be created during 'get' method", function(assert) { - var user; - run(function () { + let user; + run(() => { user = env.store.createRecord('user'); user.get('messages'); assert.ok(user._internalModel._relationships.has('messages'), "Newly created record with relationships in params passed in its constructor should have relationships"); @@ -2595,12 +2608,12 @@ test("Model's belongsTo relationship should be created during 'get' method", fun test("metadata is accessible when pushed as a meta property for a relationship", function(assert) { assert.expect(1); - var book; + let book; env.adapter.findHasMany = function() { return resolve({}); }; - run(function() { + run(() => { env.store.push({ data: { type: 'book', @@ -2623,7 +2636,7 @@ test("metadata is accessible when pushed as a meta property for a relationship", book = env.store.peekRecord('book', 1); }); - run(function() { + run(() => { assert.equal(book._internalModel._relationships.get('chapters').meta.where, 'the lefkada sea', 'meta is there'); }); }); @@ -2644,9 +2657,9 @@ test("metadata is accessible when return from a fetchLink", function(assert) { }); }; - var book; + let book; - run(function() { + run(() => { env.store.push({ data: { type: 'book', @@ -2666,20 +2679,20 @@ test("metadata is accessible when return from a fetchLink", function(assert) { book = env.store.peekRecord('book', 1); }); - run(function() { - book.get('chapters').then(function(chapters) { - var meta = chapters.get('meta'); + return run(() => { + return book.get('chapters').then(chapters => { + let meta = chapters.get('meta'); assert.equal(get(meta, 'foo'), 'bar', 'metadata is available'); }); }); }); test("metadata should be reset between requests", function(assert) { - var counter = 0; + let counter = 0; env.registry.register('serializer:application', DS.RESTSerializer); env.adapter.findHasMany = function() { - var data = { + let data = { meta: { foo: 'bar' }, @@ -2700,9 +2713,9 @@ test("metadata should be reset between requests", function(assert) { return resolve(data); }; - var book1, book2; + let book1, book2; - run(function() { + run(() => { env.store.push({ data: [{ type: 'book', @@ -2736,13 +2749,13 @@ test("metadata should be reset between requests", function(assert) { book2 = env.store.peekRecord('book', 2); }); - run(function() { - book1.get('chapters').then(function(chapters) { - var meta = chapters.get('meta'); + return run(() => { + return book1.get('chapters').then(chapters => { + let meta = chapters.get('meta'); assert.equal(get(meta, 'foo'), 'bar', 'metadata should available'); - book2.get('chapters').then(function(chapters) { - var meta = chapters.get('meta'); + return book2.get('chapters').then(chapters => { + let meta = chapters.get('meta'); assert.equal(meta, undefined, 'metadata should not be available'); }); }); @@ -2764,7 +2777,7 @@ test("Related link should be fetched when no local data is present", function(as ]}); }; - run(function() { + return run(() => { let post = env.store.push({ data: { type: 'post', @@ -2778,7 +2791,8 @@ test("Related link should be fetched when no local data is present", function(as } } }); - post.get('comments').then((comments) => { + + return post.get('comments').then(comments => { assert.equal(comments.get('firstObject.body'), 'This is comment', 'comment body is correct'); }); }); @@ -2799,7 +2813,7 @@ test("Local data should take precedence over related link", function(assert) { return Ember.RSVP.resolve({ data: { id: 1, type: 'comment', attributes: { body: 'This is comment' } } }); }; - run(function() { + return run(() => { let post = env.store.push({ data: { type: 'post', @@ -2816,7 +2830,8 @@ test("Local data should take precedence over related link", function(assert) { } } }); - post.get('comments').then((comments) => { + + return post.get('comments').then(comments => { assert.equal(comments.get('firstObject.body'), 'This is comment', 'comment body is correct'); }); }); @@ -2841,7 +2856,7 @@ test("Updated related link should take precedence over local data", function(ass assert.ok(false, "The adapter's findRecord method should not be called"); }; - run(function() { + return run(() => { let post = env.store.push({ data: { type: 'post', @@ -2873,7 +2888,7 @@ test("Updated related link should take precedence over local data", function(ass } }); - post.get('comments').then((comments) => { + return post.get('comments').then(comments => { assert.equal(comments.get('firstObject.body'), 'This is comment', 'comment body is correct'); }); }); @@ -2893,8 +2908,8 @@ test("PromiseArray proxies createRecord to its ManyArray before the hasMany is l ]}); }; - run(function() { - var post = env.store.push({ + return run(() => { + let post = env.store.push({ data: { type: 'post', id: 1, @@ -2908,19 +2923,19 @@ test("PromiseArray proxies createRecord to its ManyArray before the hasMany is l } }); - var comments = post.get('comments'); + let comments = post.get('comments'); comments.createRecord(); - comments.then(function(comments) { + return comments.then(comments => { assert.equal(comments.get('length'), 3, "comments have 3 length, including new record"); }); }); }); test("unloading and reloading a record with hasMany relationship - #3084", function(assert) { - var user; - var message; + let user; + let message; - run(function() { + run(() => { env.store.push({ data: [{ type: 'user', @@ -2948,11 +2963,11 @@ test("unloading and reloading a record with hasMany relationship - #3084", funct assert.equal(get(message, 'user.id'), 'user-1'); }); - run(function() { + run(() => { env.store.unloadRecord(user); }); - run(function() { + run(() => { // The record is resurrected for some reason. env.store.push({ data: [{ @@ -2979,14 +2994,14 @@ test("unloading and reloading a record with hasMany relationship - #3084", funct }); test("deleted records should stay deleted", function(assert) { - var user; - var message; + let user; + let message; env.adapter.deleteRecord = function(store, type, id) { return null; }; - run(function() { + run(() => { env.store.push({ data: [{ type: 'user', @@ -3017,11 +3032,9 @@ test("deleted records should stay deleted", function(assert) { assert.equal(get(user, 'messages.length'), 2); }); - run(function() { - message.destroyRecord() - }); + run(() => message.destroyRecord()); - run(function() { + run(() => { // a new message is added to the user should not resurrected the // deleted message env.store.push({ diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index f2549882e8a..ae3016fe73f 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -7,11 +7,10 @@ import {module, test} from 'qunit'; import DS from 'ember-data'; -var Account, Topic, User, store, env; -var run = Ember.run; +const { run } = Ember; +const { attr, hasMany } = DS; -var attr = DS.attr; -var hasMany = DS.hasMany; +let Account, Topic, User, store, env; module('integration/relationships/many_to_many_test - ManyToMany relationships', { beforeEach() { @@ -44,9 +43,7 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships', }, afterEach() { - run(function() { - env.container.destroy(); - }); + run(() => env.container.destroy()); } }); @@ -55,7 +52,7 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships', */ test("Loading from one hasMany side reflects on the other hasMany side - async", function(assert) { - run(function() { + run(() => { store.push({ data: { id: '1', @@ -78,7 +75,7 @@ test("Loading from one hasMany side reflects on the other hasMany side - async", }); }); - var topic = run(function() { + let topic = run(() => { return store.push({ data: { id: '2', @@ -90,17 +87,16 @@ test("Loading from one hasMany side reflects on the other hasMany side - async", }); }); - run(function() { - topic.get('users').then(assert.wait(function(fetchedUsers) { + return run(() => { + return topic.get('users').then(fetchedUsers => { assert.equal(fetchedUsers.get('length'), 1, 'User relationship was set up correctly'); - })); + }); }); }); - test("Relationship is available from one hasMany side even if only loaded from the other hasMany side - sync", function(assert) { var account; - run(function() { + run(() => { account = store.push({ data: { id: '2', @@ -129,14 +125,15 @@ test("Relationship is available from one hasMany side even if only loaded from t }); }); - run(function() { + run(() => { assert.equal(account.get('users.length'), 1, 'User relationship was set up correctly'); }); }); test("Fetching a hasMany where a record was removed reflects on the other hasMany side - async", function(assert) { - var user, topic; - run(function() { + let user, topic; + + run(() => { user = store.push({ data: { id: '1', @@ -169,21 +166,22 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan } }); }); - run(function() { - user.get('topics').then(assert.wait(function(fetchedTopics) { + + return run(() => { + return user.get('topics').then(fetchedTopics => { assert.equal(fetchedTopics.get('length'), 0, 'Topics were removed correctly'); assert.equal(fetchedTopics.objectAt(0), null, "Topics can't be fetched"); - topic.get('users').then(assert.wait(function(fetchedUsers) { + return topic.get('users').then(fetchedUsers => { assert.equal(fetchedUsers.get('length'), 0, 'Users were removed correctly'); assert.equal(fetchedUsers.objectAt(0), null, "User can't be fetched"); - })); - })); + }); + }); }); }); test("Fetching a hasMany where a record was removed reflects on the other hasMany side - sync", function(assert) { - var account, user; - run(function() { + let account, user; + run(() => { account = store.push({ data: { id: '2', @@ -226,7 +224,7 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan }); }); - run(function() { + run(() => { assert.equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); assert.equal(account.get('users.length'), 0, 'Users were removed correctly'); }); @@ -238,9 +236,9 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan test("Pushing to a hasMany reflects on the other hasMany side - async", function(assert) { assert.expect(1); - var user, topic; + let user, topic; - run(function() { + run(() => { user = store.push({ data: { id: '1', @@ -266,19 +264,19 @@ test("Pushing to a hasMany reflects on the other hasMany side - async", function }); }); - run(function() { - topic.get('users').then(assert.wait(function(fetchedUsers) { + return run(() => { + return topic.get('users').then(fetchedUsers => { fetchedUsers.pushObject(user); - user.get('topics').then(assert.wait(function(fetchedTopics) { + return user.get('topics').then(fetchedTopics => { assert.equal(fetchedTopics.get('length'), 1, 'User relationship was set up correctly'); - })); - })); + }); + }); }); }); test("Pushing to a hasMany reflects on the other hasMany side - sync", function(assert) { - var account, stanley; - run(function() { + let account, stanley; + run(() => { account = store.push({ data: { id: '2', @@ -300,14 +298,14 @@ test("Pushing to a hasMany reflects on the other hasMany side - sync", function( stanley.get('accounts').pushObject(account); }); - run(function() { + run(() => { assert.equal(account.get('users.length'), 1, 'User relationship was set up correctly'); }); }); test("Removing a record from a hasMany reflects on the other hasMany side - async", function(assert) { - var user, topic; - run(function() { + let user, topic; + run(() => { user = store.push({ data: { id: '1', @@ -336,21 +334,21 @@ test("Removing a record from a hasMany reflects on the other hasMany side - asyn }); }); - run(function() { - user.get('topics').then(assert.wait(function(fetchedTopics) { + return run(() => { + return user.get('topics').then(fetchedTopics => { assert.equal(fetchedTopics.get('length'), 1, 'Topics were setup correctly'); fetchedTopics.removeObject(topic); - topic.get('users').then(assert.wait(function(fetchedUsers) { + return topic.get('users').then(fetchedUsers => { assert.equal(fetchedUsers.get('length'), 0, 'Users were removed correctly'); assert.equal(fetchedUsers.objectAt(0), null, "User can't be fetched"); - })); - })); + }); + }); }); }); test("Removing a record from a hasMany reflects on the other hasMany side - sync", function(assert) { - var account, user; - run(function() { + let account, user; + run(() => { account = store.push({ data: { id: '2', @@ -379,7 +377,7 @@ test("Removing a record from a hasMany reflects on the other hasMany side - sync }); }); - run(function() { + run(() => { assert.equal(account.get('users.length'), 1, 'Users were setup correctly'); account.get('users').removeObject(user); assert.equal(user.get('accounts.length'), 0, 'Accounts were removed correctly'); @@ -392,8 +390,8 @@ test("Removing a record from a hasMany reflects on the other hasMany side - sync */ test("Rollbacking attributes for a deleted record that has a ManyToMany relationship works correctly - async", function(assert) { - var user, topic; - run(function() { + let user, topic; + run(() => { user = store.push({ data: { id: '1', @@ -422,23 +420,30 @@ test("Rollbacking attributes for a deleted record that has a ManyToMany relation }); }); - run(function() { + run(() => { topic.deleteRecord(); topic.rollbackAttributes(); }); - run(function() { - topic.get('users').then(assert.wait(function(fetchedUsers) { + + return run(() => { + let users = topic.get('users').then(fetchedUsers => { assert.equal(fetchedUsers.get('length'), 1, 'Users are still there'); - })); - user.get('topics').then(assert.wait(function(fetchedTopics) { + }); + + let topics = user.get('topics').then(fetchedTopics => { assert.equal(fetchedTopics.get('length'), 1, 'Topic got rollbacked into the user'); - })); + }); + + return Ember.RSVP.Promise.all([ + users, + topics + ]); }); }); test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function(assert) { - var account, user; - run(function() { + let account, user; + run(() => { account = store.push({ data: { id: '2', @@ -467,7 +472,7 @@ test("Deleting a record that has a hasMany relationship removes it from the othe }); }); - run(function() { + run(() => { account.deleteRecord(); account.rollbackAttributes(); assert.equal(account.get('users.length'), 1, 'Users are still there'); @@ -476,8 +481,8 @@ test("Deleting a record that has a hasMany relationship removes it from the othe }); test("Rollbacking attributes for a created record that has a ManyToMany relationship works correctly - async", function(assert) { - var user, topic; - run(function() { + let user, topic; + run(() => { user = store.push({ data: { id: '1', @@ -490,25 +495,33 @@ test("Rollbacking attributes for a created record that has a ManyToMany relation topic = store.createRecord('topic'); }); - run(function() { - user.get('topics').then(assert.wait(function(fetchedTopics) { + + return run(() => { + return user.get('topics').then(fetchedTopics => { fetchedTopics.pushObject(topic); topic.rollbackAttributes(); - topic.get('users').then(assert.wait(function(fetchedUsers) { + + let users = topic.get('users').then(fetchedUsers => { assert.equal(fetchedUsers.get('length'), 0, 'Users got removed'); assert.equal(fetchedUsers.objectAt(0), null, "User can't be fetched"); - })); - user.get('topics').then(assert.wait(function(fetchedTopics) { + }); + + let topics = user.get('topics').then(fetchedTopics => { assert.equal(fetchedTopics.get('length'), 0, 'Topics got removed'); assert.equal(fetchedTopics.objectAt(0), null, "Topic can't be fetched"); - })); - })); + }); + + return Ember.RSVP.Promise.all([ + users, + topics + ]); + }); }); }); test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function(assert) { - var account, user; - run(function() { + let account, user; + run(() => { account = store.push({ data: { id: '2', @@ -521,18 +534,20 @@ test("Deleting a record that has a hasMany relationship removes it from the othe user = store.createRecord('user'); }); - run(function() { + + run(() => { account.get('users').pushObject(user); user.rollbackAttributes(); }); + assert.equal(account.get('users.length'), 0, 'Users got removed'); assert.equal(user.get('accounts.length'), 0, 'Accounts got rolledback correctly'); }); - test("Re-loading a removed record should re add it to the relationship when the removed record is the last one in the relationship", function(assert) { - var account, ada, byron; - run(function() { + let account, ada, byron; + + run(() => { account = store.push({ data: { id: '2', @@ -599,6 +614,5 @@ test("Re-loading a removed record should re add it to the relationship when the }); }); - assert.equal(account.get('users.length'), 2, 'Accounts were updated correctly'); }); From 14dd2ef89270b7a5501bfa84c10316af12c3cacf Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 3 Jul 2017 13:22:14 -0700 Subject: [PATCH 1964/2527] add test for hasMany + addObject + destroyRecord canonical vs currenState --- .../relationships/has-many-test.js | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index e2915ce39f7..f4fba8a436c 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -134,6 +134,88 @@ test("When a hasMany relationship is accessed, the adapter's findMany method sho }); }); +test("hasMany + canonical vs currentState + destroyRecord ", function(assert) { + assert.expect(6); + + let postData = { + type: 'user', + id: '1', + attributes: { + name: 'omg' + }, + relationships: { + contacts: { + data: [ + { + type: 'user', + id: 2 + }, + { + type: 'user', + id: 3 + }, + { + type: 'user', + id: 4 + } + ] + } + } + }; + + run(() => { + env.store.push({ + data: postData, + included: [ + { + type: 'user', + id: 2 + }, + { + type: 'user', + id: 3 + }, + { + type: 'user', + id: 4 + } + ] + }); + }); + + let user = env.store.peekRecord('user', 1); + let contacts = user.get('contacts'); + + env.store.adapterFor('user').deleteRecord = function() { + return { data: { type: 'user', id: 2 } }; + }; + + assert.deepEqual(contacts.map(c => c.get('id')), ['2','3','4'], 'user should have expected contacts'); + + run(() => { + contacts.addObject(env.store.createRecord('user', { id: 5 })); + contacts.addObject(env.store.createRecord('user', { id: 6 })); + contacts.addObject(env.store.createRecord('user', { id: 7 })); + }); + + assert.deepEqual(contacts.map(c => c.get('id')), ['2','3','4','5','6','7'], 'user should have expected contacts'); + + run(() => { + env.store.peekRecord('user', 2).destroyRecord(); + env.store.peekRecord('user', 6).destroyRecord(); + }); + + assert.deepEqual(contacts.map(c => c.get('id')), ['3','4','5','7'], `user's contacts should have expected contacts`); + assert.equal(contacts, user.get('contacts')); + + run(() => { + contacts.addObject(env.store.createRecord('user', { id: 8 })); + }); + + assert.deepEqual(contacts.map(c => c.get('id')), ['3','4','5','7','8'], `user's contacts should have expected contacts`); + assert.equal(contacts, user.get('contacts')); +}); + test("adapter.findMany only gets unique IDs even if duplicate IDs are present in the hasMany relationship", function(assert) { assert.expect(2); From 3667eb926082b9a59e695c2fc3c57355292928e6 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 3 Jul 2017 13:47:02 -0700 Subject: [PATCH 1965/2527] update deps --- yarn.lock | 250 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 150 insertions(+), 100 deletions(-) diff --git a/yarn.lock b/yarn.lock index b579e6e486c..8cbaada73de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4,17 +4,17 @@ "@glimmer/di@^0.2.0": version "0.2.0" - resolved "https://registry.yarnpkg.com/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" + resolved "https://registry.npmjs.org/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" -"@glimmer/resolver@^0.3.0": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@glimmer/resolver/-/resolver-0.3.1.tgz#41069345b6f41beb0948cc35d8e4aa60adcadfc5" +"@glimmer/resolver@0.4.0": + version "0.4.0" + resolved "https://registry.npmjs.org/@glimmer/resolver/-/resolver-0.4.0.tgz#7fe8709342064f144c14c06088d6dc4070ad7d1d" dependencies: "@glimmer/di" "^0.2.0" "@types/node@*", "@types/node@^7.0.5": - version "7.0.32" - resolved "https://registry.npmjs.org/@types/node/-/node-7.0.32.tgz#6afe6c66520a4c316623a14aef123908d01b4bba" + version "7.0.33" + resolved "https://registry.npmjs.org/@types/node/-/node-7.0.33.tgz#ae3c53ad01d7e9d62c7f1a85c5f7500d59b9d25b" "@types/rimraf@^0.0.28": version "0.0.28" @@ -129,6 +129,10 @@ ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + ansi-styles@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" @@ -255,10 +259,22 @@ async-disk-cache@^1.2.1: rsvp "^3.0.18" username-sync "1.0.1" +async-promise-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/async-promise-queue/-/async-promise-queue-1.0.3.tgz#70c9c37635620f894978814b6c65e6e14e2573ee" + dependencies: + async "^2.4.1" + async@^1.4.0, async@^1.5.2: version "1.5.2" resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" +async@^2.4.1: + version "2.5.0" + resolved "https://registry.npmjs.org/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" + dependencies: + lodash "^4.14.0" + async@~0.2.9: version "0.2.10" resolved "https://registry.npmjs.org/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" @@ -268,10 +284,10 @@ async@~0.9.0: resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" aws-sdk@^2.0.9: - version "2.75.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.75.0.tgz#f78802e46f95b7044a094da259057dd8d5d8da17" + version "2.80.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.80.0.tgz#61ced747eb981609483aec53e8d654d3cc9d1435" dependencies: - buffer "5.0.6" + buffer "4.9.1" crypto-browserify "1.0.9" jmespath "0.15.0" querystring "0.2.0" @@ -502,7 +518,7 @@ babel-plugin-dead-code-elimination@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" -babel-plugin-debug-macros@^0.1.1, babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.7: +babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.7: version "0.1.10" resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.10.tgz#dd077ad6e1cc0a8f9bbc6405c561392ebfc9a01c" dependencies: @@ -1048,28 +1064,34 @@ broccoli-asset-rewrite@^1.1.0: broccoli-filter "^1.2.3" broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: - version "5.6.2" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.6.2.tgz#958c72e43575b2f0a862a5096dba1ce1ebc7d74d" + version "5.7.1" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.1.tgz#e10d831faed1c57e37272e4223748ba71a7926d1" dependencies: babel-core "^5.0.0" broccoli-funnel "^1.0.0" broccoli-merge-trees "^1.0.0" - broccoli-persistent-filter "^1.0.1" + broccoli-persistent-filter "^1.4.2" clone "^0.2.0" hash-for-dep "^1.0.2" + heimdalljs-logger "^0.1.7" json-stable-stringify "^1.0.0" + rsvp "^3.5.0" + workerpool "^2.2.1" broccoli-babel-transpiler@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.0.0.tgz#a52c5404bf36236849da503b011fd41fe64a00a2" + version "6.1.1" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.1.1.tgz#938f470e1ddb47047a77ef5e38f34c21de0e85a8" dependencies: babel-core "^6.14.0" broccoli-funnel "^1.0.0" broccoli-merge-trees "^1.0.0" - broccoli-persistent-filter "^1.0.1" + broccoli-persistent-filter "^1.4.0" clone "^2.0.0" hash-for-dep "^1.0.2" + heimdalljs-logger "^0.1.7" json-stable-stringify "^1.0.0" + rsvp "^3.5.0" + workerpool "^2.2.1" broccoli-brocfile-loader@^0.18.0: version "0.18.0" @@ -1078,8 +1100,8 @@ broccoli-brocfile-loader@^0.18.0: findup-sync "^0.4.2" broccoli-builder@^0.18.3: - version "0.18.5" - resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.5.tgz#fb09687d99b869942e4405a2e4f4499272cfc5f2" + version "0.18.8" + resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.8.tgz#fe54694d544c3cdfdb01028e802eeca65749a879" dependencies: heimdalljs "^0.2.0" promise-map-series "^0.2.1" @@ -1088,29 +1110,40 @@ broccoli-builder@^0.18.3: rsvp "^3.0.17" silent-error "^1.0.1" -broccoli-caching-writer@^2.0.4, broccoli-caching-writer@~2.0.1: - version "2.0.4" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" +broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" - lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - symlink-or-copy "^1.0.0" - walk-sync "^0.2.0" + walk-sync "^0.2.5" -broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" +broccoli-caching-writer@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-plugin "^1.2.1" + debug "^2.1.1" + rimraf "^2.2.8" + rsvp "^3.0.17" + walk-sync "^0.3.0" + +broccoli-caching-writer@~2.0.1: + version "2.0.4" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" debug "^2.1.1" + lodash-node "^3.2.0" rimraf "^2.2.8" rsvp "^3.0.17" - walk-sync "^0.2.5" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" broccoli-clean-css@^1.1.0: version "1.1.0" @@ -1152,10 +1185,10 @@ broccoli-concat@^3.2.2: walk-sync "^0.3.1" broccoli-config-loader@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/broccoli-config-loader/-/broccoli-config-loader-1.0.0.tgz#c3cf5ecfaffc04338c6f1d5d38dc36baeaa131ba" + version "1.0.1" + resolved "https://registry.npmjs.org/broccoli-config-loader/-/broccoli-config-loader-1.0.1.tgz#d10aaf8ebc0cb45c1da5baa82720e1d88d28c80a" dependencies: - broccoli-caching-writer "^2.0.4" + broccoli-caching-writer "^3.0.3" broccoli-config-replace@^1.1.2: version "1.1.2" @@ -1280,23 +1313,24 @@ broccoli-merge-trees@~0.2.3: symlink-or-copy "^1.0.0" broccoli-middleware@^1.0.0-beta.8: - version "1.0.0-beta.11" - resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-1.0.0-beta.11.tgz#5f633276c7905d2debf6fb78b18291f560fd4ba1" + version "1.0.0" + resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-1.0.0.tgz#92f4e1fb9a791ea986245a7077f35cc648dab097" dependencies: handlebars "^4.0.4" mime "^1.2.11" -broccoli-persistent-filter@^1.0.1, broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0: - version "1.3.1" - resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.3.1.tgz#d02556a135c77dfb859bba7844bc3539be7168e1" +broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0, broccoli-persistent-filter@^1.4.0, broccoli-persistent-filter@^1.4.2: + version "1.4.2" + resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.2.tgz#17af1278a25ff2556f9d7d23e115accfad3a7ce7" dependencies: async-disk-cache "^1.2.1" + async-promise-queue "^1.0.3" broccoli-plugin "^1.0.0" + crypto "0.0.3" fs-tree-diff "^0.5.2" hash-for-dep "^1.0.2" heimdalljs "^0.2.1" heimdalljs-logger "^0.1.7" - md5-hex "^1.0.2" mkdirp "^0.5.1" promise-map-series "^0.2.1" rimraf "^2.6.1" @@ -1428,12 +1462,13 @@ bser@^2.0.0: dependencies: node-int64 "^0.4.0" -buffer@5.0.6: - version "5.0.6" - resolved "https://registry.npmjs.org/buffer/-/buffer-5.0.6.tgz#2ea669f7eec0b6eda05b08f8b5ff661b28573588" +buffer@4.9.1: + version "4.9.1" + resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" + isarray "^1.0.0" builtin-modules@^1.0.0: version "1.1.1" @@ -1490,8 +1525,8 @@ can-symlink@^1.0.0: tmp "0.0.28" caniuse-lite@^1.0.30000684: - version "1.0.30000693" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000693.tgz#c9c6298697c71fdf6cb13eefe8aa93926f2f8613" + version "1.0.30000696" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000696.tgz#30f2695d2a01a0dfd779a26ab83f4d134b3da5cc" capture-exit@^1.1.0: version "1.2.0" @@ -1696,10 +1731,8 @@ commander@2.8.x: graceful-readlink ">= 1.0.0" commander@^2.5.0, commander@^2.6.0: - version "2.9.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" - dependencies: - graceful-readlink ">= 1.0.0" + version "2.11.0" + resolved "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" commander@~2.1.0: version "2.1.0" @@ -1848,7 +1881,7 @@ core-object@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" -core-object@^3.0.0: +core-object@^3.1.3: version "3.1.3" resolved "https://registry.npmjs.org/core-object/-/core-object-3.1.3.tgz#df399b3311bdb0c909e8aae8929fc3c1c4b25880" dependencies: @@ -1880,6 +1913,10 @@ crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" +crypto@0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/crypto/-/crypto-0.0.3.tgz#470a81b86be4c5ee17acc8207a1f5315ae20dbb0" + ctype@0.5.3: version "0.5.3" resolved "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" @@ -1890,6 +1927,10 @@ d@1: dependencies: es5-ext "^0.10.9" +dag-map@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" + debug@2, debug@2.6.8, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0, debug@~2.6.7: version "2.6.8" resolved "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" @@ -2038,8 +2079,8 @@ ee-first@1.1.1: resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" electron-to-chromium@^1.3.14: - version "1.3.14" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.14.tgz#64af0f9efd3c3c6acd57d71f83b49ca7ee9c4b43" + version "1.3.15" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.15.tgz#08397934891cbcfaebbd18b82a95b5a481138369" ember-ajax@^2.4.1: version "2.5.6" @@ -2065,9 +2106,9 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-c ember-cli-version-checker "^1.0.2" resolve "^1.1.2" -ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.4.1: - version "6.4.1" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.4.1.tgz#785a1c24fe3250eb0776b1ab3cee857863b44542" +ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.3.0, ember-cli-babel@^6.4.1: + version "6.5.1" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.5.1.tgz#37eaab592523938f8d52fc9d30bd0f56fc1c6599" dependencies: amd-name-resolver "0.0.6" babel-plugin-debug-macros "^0.1.10" @@ -2314,7 +2355,7 @@ ember-cli-valid-component-name@^1.0.0: dependencies: silent-error "^1.0.0" -ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7, ember-cli-version-checker@^1.2.0: +ember-cli-version-checker@1.3.1, ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7, ember-cli-version-checker@^1.2.0: version "1.3.1" resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz#0bc2d134c830142da64bf9627a0eded10b61ae72" dependencies: @@ -2328,8 +2369,8 @@ ember-cli-version-checker@^2.0.0: semver "^5.3.0" ember-cli@^2.11.1: - version "2.13.2" - resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.13.2.tgz#a561f08e69b184fa3175f706cced299c0d1684e5" + version "2.13.3" + resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.13.3.tgz#1918500e6280a68be017aca9b69937f6782a24b8" dependencies: amd-name-resolver "0.0.6" babel-plugin-transform-es2015-modules-amd "^6.24.0" @@ -2354,7 +2395,8 @@ ember-cli@^2.11.1: compression "^1.4.4" configstore "^3.0.0" console-ui "^1.0.2" - core-object "^3.0.0" + core-object "^3.1.3" + dag-map "^2.0.2" diff "^3.2.0" ember-cli-broccoli-sane-watcher "^2.0.4" ember-cli-get-component-path-option "^1.0.0" @@ -2364,7 +2406,7 @@ ember-cli@^2.11.1: ember-cli-normalize-entity-name "^1.0.0" ember-cli-preprocess-registry "^3.1.0" ember-cli-string-utils "^1.0.0" - ember-try "^0.2.14" + ember-try "^0.2.15" ensure-posix-path "^1.0.2" escape-string-regexp "^1.0.3" execa "^0.6.0" @@ -2464,17 +2506,17 @@ ember-qunit@^0.4.18: dependencies: ember-test-helpers "^0.5.32" -ember-resolver@^4.1.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-4.1.0.tgz#f02aeb2f1f2e944ed47e085412a7b84f759d11df" +ember-resolver@^4.1.0: + version "4.2.1" + resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-4.2.1.tgz#d8aa7de8444ec9b688aa97a5ddbb58c3b949194b" dependencies: - "@glimmer/resolver" "^0.3.0" - babel-plugin-debug-macros "^0.1.1" + "@glimmer/resolver" "0.4.0" + babel-plugin-debug-macros "^0.1.10" broccoli-funnel "^1.1.0" broccoli-merge-trees "^2.0.0" - ember-cli-babel "^6.0.0-beta.7" - ember-cli-version-checker "^1.1.6" - resolve "^1.3.2" + ember-cli-babel "^6.3.0" + ember-cli-version-checker "1.3.1" + resolve "^1.3.3" ember-router-generator@^1.0.0: version "1.2.3" @@ -2522,7 +2564,7 @@ ember-try-config@^2.0.1: rsvp "^3.2.1" semver "^5.1.0" -ember-try@^0.2.14: +ember-try@^0.2.15: version "0.2.15" resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.15.tgz#559c756058717595babe70068e541625bd5e210a" dependencies: @@ -3476,8 +3518,8 @@ homedir-polyfill@^1.0.0: parse-passwd "^1.0.0" hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: - version "2.4.2" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.4.2.tgz#0076b9f46a270506ddbaaea56496897460612a67" + version "2.5.0" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" http-errors@~1.6.1: version "1.6.1" @@ -3814,8 +3856,8 @@ js-tokens@1.0.1: resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" js-tokens@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" + version "3.0.2" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: version "3.8.4" @@ -3965,7 +4007,7 @@ load-json-file@^1.0.0: loader.js@^4.5.0: version "4.5.1" - resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.5.1.tgz#c15ab15a6b8376bd4fbf7ea56f8d76cc557331da" + resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.5.1.tgz#c15ab15a6b8376bd4fbf7ea56f8d76cc557331da" locate-path@^2.0.0: version "2.0.0" @@ -4160,7 +4202,7 @@ lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.15.0, lodash@^4.16.1, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.16.1, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: version "4.17.4" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -4237,7 +4279,7 @@ matcher-collection@^1.0.0, matcher-collection@^1.0.1: dependencies: minimatch "^3.0.2" -md5-hex@^1.0.2, md5-hex@^1.2.1, md5-hex@^1.3.0: +md5-hex@^1.2.1, md5-hex@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" dependencies: @@ -4486,8 +4528,8 @@ nopt@^3.0.3, nopt@^3.0.6: abbrev "1" normalize-package-data@^2.3.2: - version "2.3.8" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" + version "2.4.0" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -4518,8 +4560,8 @@ npm-run-path@^2.0.0: path-key "^2.0.0" npmlog@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5" + version "4.1.2" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" @@ -4538,7 +4580,7 @@ object-assign@4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" -object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -4911,15 +4953,15 @@ read-pkg@^1.0.0: path-type "^1.0.0" readable-stream@^2, readable-stream@^2.0.6, readable-stream@^2.2.2: - version "2.3.2" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.2.tgz#5a04df05e4f57fe3f0dc68fdd11dc5c97c7e6f4d" + version "2.3.3" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" dependencies: core-util-is "~1.0.0" inherits "~2.0.3" isarray "~1.0.0" process-nextick-args "~1.0.6" - safe-buffer "~5.1.0" - string_decoder "~1.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.0.3" util-deprecate "~1.0.1" readable-stream@~1.0.2: @@ -5107,7 +5149,7 @@ resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" -resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.2, resolve@^1.3.3: +resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" dependencies: @@ -5126,13 +5168,13 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2.5.2, rimraf@^2.4.3, rimraf@^2.4.4: +rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.4, rimraf@^2.4.3, rimraf@^2.4.4: version "2.5.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" -rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: +rimraf@^2.1.4, rimraf@^2.3.2, rimraf@^2.4.1, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: version "2.6.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: @@ -5156,17 +5198,9 @@ route-recognizer@^0.2.3: version "0.2.10" resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" -rsvp@3.6.0: +rsvp@3.6.0, rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0, rsvp@^3.5.0: version "3.6.0" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.0.tgz#666dfffa715f7e10eef76f4d1e56fb2566fce5c3" - -rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0: - version "3.5.0" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.5.0.tgz#a62c573a4ae4e1dfd0697ebc6242e79c681eaa34" - -rsvp@^3.0.16, rsvp@^3.0.6, rsvp@~3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.6.0.tgz#666dfffa715f7e10eef76f4d1e56fb2566fce5c3" rsvp@~3.0.6: version "3.0.21" @@ -5176,6 +5210,10 @@ rsvp@~3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" +rsvp@~3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + run-async@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" @@ -5196,7 +5234,7 @@ rx@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" -safe-buffer@~5.1.0: +safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -5486,17 +5524,17 @@ string-width@^1.0.1, string-width@^1.0.2: strip-ansi "^3.0.0" string-width@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + version "2.1.0" + resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz#030664561fc146c9423ec7d978fe2457437fe6d0" dependencies: is-fullwidth-code-point "^2.0.0" - strip-ansi "^3.0.0" + strip-ansi "^4.0.0" string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" -string_decoder@~1.0.0: +string_decoder@~1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" dependencies: @@ -5526,6 +5564,12 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -5932,6 +5976,12 @@ wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" +workerpool@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/workerpool/-/workerpool-2.2.1.tgz#41ebff11d5859da948fdb2c850b57da69240988a" + dependencies: + object-assign "^4.1.1" + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" From 02c6f269fa9be3f5117feb8b81a78141c3b1412a Mon Sep 17 00:00:00 2001 From: Chris Santero Date: Fri, 7 Jul 2017 14:58:55 -0700 Subject: [PATCH 1966/2527] set hasData even when has-many link returns empty array --- .../system/relationships/state/has-many.js | 1 + tests/integration/references/has-many-test.js | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+) mode change 100644 => 100755 addon/-private/system/relationships/state/has-many.js mode change 100644 => 100755 tests/integration/references/has-many-test.js diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js old mode 100644 new mode 100755 index 170011cd561..89f7e511e68 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -202,6 +202,7 @@ export default class ManyRelationship extends Relationship { this.store._backburner.join(() => { this.updateInternalModelsFromAdapter(records); this.manyArray.set('isLoaded', true); + this.setHasData(true); }); return this.manyArray; }); diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js old mode 100644 new mode 100755 index a2ad4339254..19a756c14de --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -662,6 +662,40 @@ test("load() fetches link when remoteType is link", function(assert) { }); }); +test("load() fetches link when remoteType is link but an empty set of records is returned", function(assert) { + env.adapter.findHasMany = function(store, snapshot, link) { + assert.equal(link, "/families/1/persons"); + + return Ember.RSVP.resolve({ data: [] }); + }; + + let family; + run(() => { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + links: { related: '/families/1/persons' } + } + } + } + }); + }); + + let personsReference = family.hasMany('persons'); + assert.equal(personsReference.remoteType(), "link"); + + return run(() => { + return personsReference.load().then((records) => { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 0); + assert.equal(get(personsReference.value(), 'length'), 0); + }); + }); +}); + test("load() - only a single find is triggered", function(assert) { var done = assert.async(); From 879a8140586d2b25bb70e32ab486144e259830d6 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 10 Jul 2017 15:25:18 -0700 Subject: [PATCH 1967/2527] fix failing tests --- addon/-private/system/model/internal-model.js | 25 +++-- addon/-private/system/model/model.js | 7 ++ .../system/relationships/state/belongs-to.js | 19 ++++ .../system/relationships/state/has-many.js | 25 +++++ .../relationships/state/relationship.js | 25 +++++ .../relationships/has-many-test.js | 4 +- .../unit/model/relationships/has-many-test.js | 94 +++++++++++++++++++ 7 files changed, 191 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index e1cdbd5a9b4..59cb343daa5 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -715,7 +715,7 @@ export default class InternalModel { heimdall.increment(send); let currentState = this.currentState; - if (!currentState[name]) { + if (typeof currentState[name] !== 'function') { this._unhandledEvent(currentState, name, context); } @@ -768,7 +768,7 @@ export default class InternalModel { } if (this.isNew()) { - this.clearRelationships(); + this.clearRelationships(true); } if (this.isValid()) { @@ -885,17 +885,28 @@ export default class InternalModel { @method clearRelationships @private */ - clearRelationships() { + clearRelationships(resetAll = false) { this.eachRelationship((name, relationship) => { if (this._relationships.has(name)) { let rel = this._relationships.get(name); - rel.clear(); - rel.removeInverseRelationships(); + + if (resetAll === true) { + rel.clear(); + rel.removeInverseRelationships(); + } else { + rel.unloadInverseInternalModel(this); + } } }); Object.keys(this._implicitRelationships).forEach((key) => { - this._implicitRelationships[key].clear(); - this._implicitRelationships[key].removeInverseRelationships(); + let rel = this._implicitRelationships[key]; + + if (resetAll === true) { + rel.clear(); + rel.removeInverseRelationships(); + } else { + rel.unloadInverseInternalModel(this); + } }); } diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 354bd46cdd9..522553696ae 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1115,6 +1115,13 @@ const Model = Ember.Object.extend(Ember.Evented, { this.notifyPropertyChange(key); }, + notifyHasManyRemoved(key) { + // We need to notifyPropertyChange in the removing case to flush ui state + // Goes away if we remove/improve the outer PromiseProxy on async relationships + // this.notifyPropertyChange(key); + this.notifyPropertyChange(`${key}.length`); + }, + eachAttribute(callback, binding) { this.constructor.eachAttribute(callback, binding); } diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 2959d13c25c..65e724ef788 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -63,6 +63,25 @@ export default class BelongsToRelationship extends Relationship { this.notifyBelongsToChanged(); } + unloadInverseInternalModelFromOwn(internalModel) { + super.unloadInverseInternalModelFromOwn(internalModel); + let didChange = false; + + if (this.canonicalState === internalModel) { + this.canonicalState = null; + didChange = true; + } + + if (this.inverseInternalModel === internalModel) { + this.inverseInternalModel = this.canonicalState; + didChange = true; + } + + if (didChange === true) { + this.notifyBelongsToChanged(); + } + } + flushCanonical() { //temporary fix to not remove newly created records if server returned null. //TODO remove once we have proper diffing diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 170011cd561..8449cfd1bca 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -111,6 +111,31 @@ export default class ManyRelationship extends Relationship { super.removeCanonicalInternalModelFromOwn(internalModel, idx); } + unloadInverseInternalModelFromOwn(internalModel) { + super.unloadInverseInternalModelFromOwn(internalModel); + + const canonicalIndex = this.canonicalState.indexOf(internalModel); + + if (canonicalIndex !== -1) { + this.canonicalState.splice(canonicalIndex, 1); + } + + const manyArray = this._manyArray; + + if (manyArray) { + const currentState = manyArray.currentState; + const idx = currentState.indexOf(internalModel); + + if (idx !== -1) { + currentState.splice(idx, 1); + manyArray.set('length', currentState.length); + manyArray.notifyPropertyChange('length'); + + this.internalModel.notifyHasManyRemoved(this.key, internalModel, idx); + } + } + } + flushCanonical() { if (this._manyArray) { this._manyArray.flushCanonical(); diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index aa9313692da..984d972bbe4 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -266,6 +266,31 @@ export default class Relationship { this.flushCanonicalLater(); } + unloadInverseInternalModel(internalModel) { + this.unloadInverseInternalModelFromOwn(internalModel); + this.unloadInverseInternalModelFromInverses(internalModel); + } + + unloadInverseInternalModelFromOwn(internalModel) { + this.canonicalMembers.delete(internalModel); + this.members.delete(internalModel); + this.notifyRecordRelationshipRemoved(internalModel); + } + + unloadInverseInternalModelFromInverses(internalModel) { + if (!this.inverseKey) { return; } + + let allMembers = + // we actually want a union of members and canonicalMembers + // they should be disjoint but currently are not due to a bug + this.members.toArray().concat(this.canonicalMembers.toArray()); + + allMembers.forEach(inverseInternalModel => { + let relationship = inverseInternalModel._relationships.get(this.inverseKey); + relationship.unloadInverseInternalModelFromOwn(internalModel); + }); + } + flushCanonical() { heimdall.increment(flushCanonical); let list = this.members.list; diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index f4fba8a436c..693617be01f 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -2520,7 +2520,9 @@ test("adding and removing records from hasMany relationship #2666", function(ass return comments.get('lastObject').destroyRecord(); }).then(() => { let comments = post.get('comments'); - assert.equal(comments.get('length'), 3, "Comments count after destroy"); + let length = comments.get('length'); + + assert.equal(length, 3, "Comments count after destroy"); // Add another comment #4 let comment = env.store.createRecord('comment'); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index b9f3d391d5a..14ac1c1b197 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -906,6 +906,100 @@ test('it is possible to add a new item to a relationship', function(assert) { }); }); + +test('new items added to a relationship are not cleared by a delete', function(assert) { + assert.expect(4); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + pets: DS.hasMany('pet', { async: false, inverse: null }) + }); + + const Pet = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person', { async: false, inverse: null }) + }); + + let env = setupStore({ + person: Person, + pet: Pet + }); + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.deleteRecord = () => { + return Ember.RSVP.Promise.resolve({ data: null }); + }; + + let { store } = env; + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn' + }, + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' } + ] + } + } + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shenanigans' + } + }, + { + type: 'pet', + id: '2', + attributes: { + name: 'Rambunctious' + } + }, + { + type: 'pet', + id: '3', + attributes: { + name: 'Rebel' + } + } + ] + }); + }); + + const person = store.peekRecord('person', '1'); + const pets = run(() => person.get('pets')); + + const shen = pets.objectAt(0); + const rambo = store.peekRecord('pet', '2'); + const rebel = store.peekRecord('pet', '3'); + + assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); + assert.equal(get(pets, 'length'), 1, 'precond - relationship has only one pet to start'); + + run(() => { + pets.pushObjects([rambo, rebel]); + }); + + assert.equal(get(pets, 'length'), 3, 'precond2 - relationship now has three pets'); + + run(() => { + shen.destroyRecord({}) + .then(() => { + shen.unloadRecord(); + }); + }); + + assert.equal(get(pets, 'length'), 2, 'relationship now has two pets'); +}); + + test('possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)', function(assert) { assert.expect(2); From 269b1b4b424e14bb40b673039e8d7961e5249e98 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 10 Jul 2017 15:39:01 -0700 Subject: [PATCH 1968/2527] fix async relationships --- addon/-private/system/model/model.js | 4 ++-- addon/-private/system/relationships/state/has-many.js | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 522553696ae..83f611f5f28 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1118,8 +1118,8 @@ const Model = Ember.Object.extend(Ember.Evented, { notifyHasManyRemoved(key) { // We need to notifyPropertyChange in the removing case to flush ui state // Goes away if we remove/improve the outer PromiseProxy on async relationships - // this.notifyPropertyChange(key); - this.notifyPropertyChange(`${key}.length`); + // Notifying `${key}.length` does not work here + this.get(key).notifyPropertyChange('length'); }, eachAttribute(callback, binding) { diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 8449cfd1bca..b0eba02faca 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -128,6 +128,7 @@ export default class ManyRelationship extends Relationship { if (idx !== -1) { currentState.splice(idx, 1); + manyArray.set('length', currentState.length); manyArray.notifyPropertyChange('length'); From b97255546927ab262c0555ec6dd7d95ae12e6cdb Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 10 Jul 2017 15:41:03 -0700 Subject: [PATCH 1969/2527] expand comment --- addon/-private/system/model/model.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 83f611f5f28..37cb5f5ddb5 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1118,7 +1118,8 @@ const Model = Ember.Object.extend(Ember.Evented, { notifyHasManyRemoved(key) { // We need to notifyPropertyChange in the removing case to flush ui state // Goes away if we remove/improve the outer PromiseProxy on async relationships - // Notifying `${key}.length` does not work here + // Notifying `${key}` or `${key}.length` does not work here, notifying `content` + // after `get(key)` also works but this wont always be an async relationship. this.get(key).notifyPropertyChange('length'); }, From 4c3d594c0e0c45efe94776482150e9c69f04c6db Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 10 Jul 2017 16:31:19 -0700 Subject: [PATCH 1970/2527] add additional test coverage --- .../unit/model/relationships/has-many-test.js | 473 +++++++++++++++++- 1 file changed, 471 insertions(+), 2 deletions(-) diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 14ac1c1b197..b7d8e87f9da 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -906,8 +906,7 @@ test('it is possible to add a new item to a relationship', function(assert) { }); }); - -test('new items added to a relationship are not cleared by a delete', function(assert) { +test('new items added to a hasMany relationship are not cleared by a delete', function(assert) { assert.expect(4); const Person = DS.Model.extend({ @@ -999,6 +998,476 @@ test('new items added to a relationship are not cleared by a delete', function(a assert.equal(get(pets, 'length'), 2, 'relationship now has two pets'); }); +test('new items added to an async hasMany relationship are not cleared by a delete', function(assert) { + assert.expect(7); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + pets: DS.hasMany('pet', { async: true, inverse: null }) + }); + + const Pet = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person', { async: false, inverse: null }) + }); + + let env = setupStore({ + person: Person, + pet: Pet + }); + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.deleteRecord = () => { + return Ember.RSVP.Promise.resolve({ data: null }); + }; + + let { store } = env; + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn' + }, + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' } + ] + } + } + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shenanigans' + } + }, + { + type: 'pet', + id: '2', + attributes: { + name: 'Rambunctious' + } + }, + { + type: 'pet', + id: '3', + attributes: { + name: 'Rebel' + } + } + ] + }); + }); + + return run(() => { + const person = store.peekRecord('person', '1'); + const petsProxy = person.get('pets'); + + petsProxy.then((pets) => { + const shen = pets.objectAt(0); + const rambo = store.peekRecord('pet', '2'); + const rebel = store.peekRecord('pet', '3'); + + assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); + assert.equal(get(pets, 'length'), 1, 'precond - relationship has only one pet to start'); + assert.equal(get(petsProxy, 'length'), 1, 'precond - proxy has only one pet to start'); + + run(() => { + pets.pushObjects([rambo, rebel]); + }); + + assert.equal(get(pets, 'length'), 3, 'precond2 - relationship now has three pets'); + assert.equal(get(petsProxy, 'length'), 3, 'precond2 - proxy now reflects three pets'); + + run(() => { + shen.destroyRecord({}) + .then(() => { + shen.unloadRecord(); + }); + }); + + assert.equal(get(pets, 'length'), 2, 'relationship now has two pets'); + assert.equal(get(petsProxy, 'length'), 2, 'proxy now reflects two pets'); + }); + }); +}); + +test('new items added to a belongsTo relationship are not cleared by a delete', function(assert) { + assert.expect(4); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + dog: DS.belongsTo('dog', { async: false, inverse: null }) + }); + + const Dog = DS.Model.extend({ + name: DS.attr('string') + }); + + let env = setupStore({ + person: Person, + dog: Dog + }); + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.deleteRecord = () => { + return Ember.RSVP.Promise.resolve({ data: null }); + }; + + let { store } = env; + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn' + }, + relationships: { + dog: { + data: { type: 'dog', id: '1' } + } + } + }, + included: [ + { + type: 'dog', + id: '1', + attributes: { + name: 'Shenanigans' + } + }, + { + type: 'dog', + id: '2', + attributes: { + name: 'Rambunctious' + } + } + ] + }); + }); + + const person = store.peekRecord('person', '1'); + let dog = run(() => person.get('dog')); + const shen = store.peekRecord('dog', '1'); + const rambo = store.peekRecord('dog', '2'); + + assert.ok(dog === shen, 'precond - the belongsTo points to the correct dog'); + assert.equal(get(dog, 'name'), 'Shenanigans', 'precond - relationships work'); + + run(() => { + person.set('dog', rambo); + }); + + dog = person.get('dog'); + assert.equal(dog, rambo, 'precond2 - relationship was updated'); + + run(() => { + shen.destroyRecord({}) + .then(() => { + shen.unloadRecord(); + }); + }); + + dog = person.get('dog'); + assert.equal(dog, rambo, 'The currentState of the belongsTo was preserved after the delete'); +}); + +test('new items added to an async belongsTo relationship are not cleared by a delete', function(assert) { + assert.expect(4); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + dog: DS.belongsTo('dog', { async: true, inverse: null }) + }); + + const Dog = DS.Model.extend({ + name: DS.attr('string') + }); + + let env = setupStore({ + person: Person, + dog: Dog + }); + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.deleteRecord = () => { + return Ember.RSVP.Promise.resolve({ data: null }); + }; + + let { store } = env; + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn' + }, + relationships: { + dog: { + data: { type: 'dog', id: '1' } + } + } + }, + included: [ + { + type: 'dog', + id: '1', + attributes: { + name: 'Shenanigans' + } + }, + { + type: 'dog', + id: '2', + attributes: { + name: 'Rambunctious' + } + } + ] + }); + }); + + return run(() => { + const person = store.peekRecord('person', '1'); + const shen = store.peekRecord('dog', '1'); + const rambo = store.peekRecord('dog', '2'); + + return person.get('dog').then((dog) => { + assert.ok(dog === shen, 'precond - the belongsTo points to the correct dog'); + assert.equal(get(dog, 'name'), 'Shenanigans', 'precond - relationships work'); + + run(() => { + person.set('dog', rambo); + }); + + dog = person.get('dog.content'); + + assert.ok(dog === rambo, 'precond2 - relationship was updated'); + + run(() => { + shen.destroyRecord({}) + .then(() => { + shen.unloadRecord(); + }); + }); + + dog = person.get('dog.content'); + assert.ok(dog === rambo, 'The currentState of the belongsTo was preserved after the delete'); + }); + }); +}); + +test('deleting an item that is the current state of a belongsTo restores canonicalState', function(assert) { + assert.expect(4); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + dog: DS.belongsTo('dog', { async: false, inverse: null }) + }); + + const Dog = DS.Model.extend({ + name: DS.attr('string') + }); + + let env = setupStore({ + person: Person, + dog: Dog + }); + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.deleteRecord = () => { + return Ember.RSVP.Promise.resolve({ data: null }); + }; + + let { store } = env; + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn' + }, + relationships: { + dog: { + data: { type: 'dog', id: '1' } + } + } + }, + included: [ + { + type: 'dog', + id: '1', + attributes: { + name: 'Shenanigans' + } + }, + { + type: 'dog', + id: '2', + attributes: { + name: 'Rambunctious' + } + } + ] + }); + }); + + const person = store.peekRecord('person', '1'); + let dog = run(() => person.get('dog')); + const shen = store.peekRecord('dog', '1'); + const rambo = store.peekRecord('dog', '2'); + + assert.ok(dog === shen, 'precond - the belongsTo points to the correct dog'); + assert.equal(get(dog, 'name'), 'Shenanigans', 'precond - relationships work'); + + run(() => { + person.set('dog', rambo); + }); + + dog = person.get('dog'); + assert.equal(dog, rambo, 'precond2 - relationship was updated'); + + run(() => { + rambo.destroyRecord({}) + .then(() => { + rambo.unloadRecord(); + }); + }); + + dog = person.get('dog'); + assert.equal(dog, shen, 'The canonical state of the belongsTo was restored after the delete'); +}); + +/* + This test, when passing, affirms that a known limitation of ember-data still exists. + + When pushing new data into the store, ember-data is currently incapable of knowing whether + a relationship has been persisted. In order to update relationship state effectively, ember-data + blindly "flushes canonical" state, removing any `currentState` changes. A delete that sideloads + the parent record's hasMany is a situation in which this limitation will be encountered should other + local changes to the relationship still exist. + */ +test('returning new hasMany relationship info from a delete supplements local state', function(assert) { + assert.expect(5); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + pets: DS.hasMany('pet', { async: false, inverse: null }) + }); + + const Pet = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person', { async: false, inverse: null }) + }); + + let env = setupStore({ + person: Person, + pet: Pet + }); + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.deleteRecord = () => { + return Ember.RSVP.Promise.resolve({ + data: null, + included: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn' + }, + relationships: { + pets: { + data: [ + { type: 'pet', id: '2' } + ] + } + } + } + ] + }); + }; + + let { store } = env; + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn' + }, + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' }, + { type: 'pet', id: '2' } + ] + } + } + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shenanigans' + } + }, + { + type: 'pet', + id: '2', + attributes: { + name: 'Rambunctious' + } + }, + { + type: 'pet', + id: '3', + attributes: { + name: 'Rebel' + } + } + ] + }); + }); + + const person = store.peekRecord('person', '1'); + const pets = run(() => person.get('pets')); + + const shen = store.peekRecord('pet', '1'); + const rambo = store.peekRecord('pet', '2'); + const rebel = store.peekRecord('pet', '3'); + + assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); + assert.equal(get(pets, 'length'), 2, 'precond - relationship has only one pet to start'); + + run(() => { + pets.pushObjects([rebel]); + }); + + assert.equal(get(pets, 'length'), 3, 'precond2 - relationship now has three pets'); + + run(() => { + shen.destroyRecord({}) + .then(() => { + shen.unloadRecord(); + }); + }); + + // were ember-data to now preserve local edits during a relationship push, this would be '2' + assert.equal(get(pets, 'length'), 1, 'relationship now has one pet'); + assert.equal(pets.objectAt(0), rambo, 'the expected pet remains'); +}); test('possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)', function(assert) { assert.expect(2); From 3eb760b800ed64594db5beb26d5b97aa80af4fb2 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 11 Jul 2017 06:30:30 -0700 Subject: [PATCH 1971/2527] =?UTF-8?q?[BUGFIX=20release]=20createRecord=20s?= =?UTF-8?q?hould=20only=20setup=20relationships=20it=20has=20=E2=80=A6=20(?= =?UTF-8?q?#5048)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [BUGFIX release] createRecord should only setup relationships it has data for * update deps --- addon/-private/system/store.js | 4 +- addon/serializers/rest.js | 2 +- tests/helpers/store.js | 6 ++- .../relationships/belongs-to-test.js | 31 ++++++++++-- .../relationships/has-many-test.js | 23 ++++++++- .../inverse-relationships-test.js | 13 ++--- .../serializers/json-serializer-test.js | 49 +++++++++++-------- .../serializers/rest-serializer-test.js | 4 +- yarn.lock | 1 + 9 files changed, 96 insertions(+), 37 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 6deb6c86406..2ed795e43e5 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -370,7 +370,9 @@ Store = Service.extend({ // TODO @runspired this should also be coalesced into some form of internalModel.setState() internalModel.eachRelationship((key, descriptor) => { - internalModel._relationships.get(key).setHasData(true); + if (properties[key] !== undefined) { + internalModel._relationships.get(key).setHasData(true); + } }); return record; diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index c85e07c8e16..761ff6405c7 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -54,7 +54,7 @@ const { camelize } = Ember.String; @namespace DS @extends DS.JSONSerializer */ -let RESTSerializer = JSONSerializer.extend({ +const RESTSerializer = JSONSerializer.extend({ /** `keyForPolymorphicType` can be used to define a custom key when diff --git a/tests/helpers/store.js b/tests/helpers/store.js index d76792e08be..10c9ca862cd 100644 --- a/tests/helpers/store.js +++ b/tests/helpers/store.js @@ -56,9 +56,13 @@ export default function setupStore(options) { registry.register('adapter:-rest', DS.RESTAdapter); registry.register('adapter:-json-api', DS.JSONAPIAdapter); - env.restSerializer = container.lookup('serializer:-rest'); + registry.injection('serializer', 'store', 'service:store'); + env.store = container.lookup('service:store'); + env.restSerializer = container.lookup('serializer:-rest'); + env.restSerializer.store = env.store; env.serializer = env.store.serializerFor('-default'); + env.serializer.store = env.store; env.adapter = env.store.get('defaultAdapter'); return env; diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 6bad183895c..33c04cc267e 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -955,26 +955,49 @@ test("belongsTo hasData sync not loaded", function(assert) { }); }); -test("belongsTo hasData async created", function(assert) { - assert.expect(1); +test("belongsTo hasData NOT created", function(assert) { + assert.expect(2); Book.reopen({ author: belongsTo('author', { async: true }) }); run(() => { + let author = store.createRecord('author'); let book = store.createRecord('book', { name: 'The Greatest Book' }); let relationship = book._internalModel._relationships.get('author'); + + assert.equal(relationship.hasData, false, 'relationship does not have data'); + + book = store.createRecord('book', { + name: 'The Greatest Book', + author + }); + + relationship = book._internalModel._relationships.get('author'); + assert.equal(relationship.hasData, true, 'relationship has data'); }); }); test("belongsTo hasData sync created", function(assert) { - assert.expect(1); + assert.expect(2); run(() => { - let book = store.createRecord('book', { name: 'The Greatest Book' }); + let author = store.createRecord('author'); + let book = store.createRecord('book', { + name: 'The Greatest Book' + }); + let relationship = book._internalModel._relationships.get('author'); + assert.equal(relationship.hasData, false, 'relationship does not have data'); + + book = store.createRecord('book', { + name: 'The Greatest Book', + author + }); + + relationship = book._internalModel._relationships.get('author'); assert.equal(relationship.hasData, true, 'relationship has data'); }); }); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index f4fba8a436c..9431753f66d 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -2642,7 +2642,7 @@ test("hasMany hasData sync not loaded", function(assert) { }); test("hasMany hasData async created", function(assert) { - assert.expect(1); + assert.expect(2); Chapter.reopen({ pages: hasMany('pages', { async: true }) @@ -2650,17 +2650,36 @@ test("hasMany hasData async created", function(assert) { run(() => { let chapter = store.createRecord('chapter', { title: 'The Story Begins' }); + let page = store.createRecord('page'); + let relationship = chapter._internalModel._relationships.get('pages'); + assert.equal(relationship.hasData, false, 'relationship does not have data'); + + chapter = store.createRecord('chapter', { + title: 'The Story Begins', + pages: [page] + }); + + relationship = chapter._internalModel._relationships.get('pages'); assert.equal(relationship.hasData, true, 'relationship has data'); }); }); test("hasMany hasData sync created", function(assert) { - assert.expect(1); + assert.expect(2); run(() => { let chapter = store.createRecord('chapter', { title: 'The Story Begins' }); let relationship = chapter._internalModel._relationships.get('pages'); + + assert.equal(relationship.hasData, false, 'relationship does not have data'); + + chapter = store.createRecord('chapter', { + title: 'The Story Begins', + pages: [store.createRecord('page')] + }); + relationship = chapter._internalModel._relationships.get('pages'); + assert.equal(relationship.hasData, true, 'relationship has data'); }); }); diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index f60ba2a6f1b..99f7f217224 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -600,16 +600,17 @@ test("inverseFor short-circuits when inverse is null", function(assert) { }); }); -testInDebug("Inverse null relationships with models that don't exist throw a nice error", function(assert) { +testInDebug("Inverse null relationships with models that don't exist throw a nice error if trying to use that relationship", function(assert) { User = DS.Model.extend({ post: DS.belongsTo('post', { inverse: null }) }); - var env = setupStore({ user: User }); + let env = setupStore({ user: User }); - assert.throws(function() { - run(function() { - env.store.createRecord('user'); - }); + assert.throws(() => { + run(() => env.store.createRecord('user', { post: {}})); }, /No model was found for 'post'/); + + // but don't error if the relationship is not used + run(() => env.store.createRecord('user', {})); }); diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index a020766303c..8fae94bf3f9 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -40,12 +40,10 @@ module("integration/serializer/json - JSONSerializer", { }); test("serialize doesn't include ID when includeId is false", function(assert) { - run(function() { - post = env.store.createRecord('post', { title: 'Rails is omakase' }); + run(() => { + post = env.store.createRecord('post', { title: 'Rails is omakase', comments: [] }); }); - var json = {}; - - json = serializer.serialize(post._createSnapshot(), { includeId: false }); + let json = serializer.serialize(post._createSnapshot(), { includeId: false }); assert.deepEqual(json, { title: "Rails is omakase", @@ -53,14 +51,26 @@ test("serialize doesn't include ID when includeId is false", function(assert) { }); }); -test("serialize includes id when includeId is true", function(assert) { - run(function() { + +test("serialize doesn't include relationship if not aware of one", function(assert) { + run(() => { post = env.store.createRecord('post', { title: 'Rails is omakase' }); + }); + + let json = serializer.serialize(post._createSnapshot()); + + assert.deepEqual(json, { + title: "Rails is omakase" + }); +}); + +test("serialize includes id when includeId is true", function(assert) { + run(() => { + post = env.store.createRecord('post', { title: 'Rails is omakase', comments: [] }); post.set('id', 'test'); }); - var json = {}; - json = serializer.serialize(post._createSnapshot(), { includeId: true }); + let json = serializer.serialize(post._createSnapshot(), { includeId: true }); assert.deepEqual(json, { id: 'test', @@ -71,12 +81,12 @@ test("serialize includes id when includeId is true", function(assert) { if (isEnabled("ds-serialize-id")) { test("serializeId", function(assert) { - run(function() { + run(() => { post = env.store.createRecord('post'); post.set('id', 'test'); }); - var json = {}; + let json = {}; serializer.serializeId(post._createSnapshot(), json, 'id'); assert.deepEqual(json, { @@ -102,8 +112,7 @@ if (isEnabled("ds-serialize-id")) { assert.deepEqual(json, { id: 'TEST', - title: 'Rails is omakase', - comments: [] + title: 'Rails is omakase' }); }); @@ -122,8 +131,7 @@ if (isEnabled("ds-serialize-id")) { assert.deepEqual(json, { _ID_: 'test', - title: 'Rails is omakase', - comments: [] + title: 'Rails is omakase' }); }); @@ -289,12 +297,11 @@ if (isEnabled("ds-check-should-serialize-relationships")) { } test("serializeIntoHash", function(assert) { - run(function() { - post = env.store.createRecord('post', { title: "Rails is omakase" }); + run(() => { + post = env.store.createRecord('post', { title: "Rails is omakase", comments: [] }); }); - var json = {}; - + let json = {}; serializer.serializeIntoHash(json, Post, post._createSnapshot()); assert.deepEqual(json, { @@ -308,8 +315,8 @@ test("serializePolymorphicType sync", function(assert) { env.registry.register('serializer:comment', DS.JSONSerializer.extend({ serializePolymorphicType(record, json, relationship) { - var key = relationship.key; - var belongsTo = record.belongsTo(key); + let key = relationship.key; + let belongsTo = record.belongsTo(key); json[relationship.key + "TYPE"] = belongsTo.modelName; assert.ok(true, 'serializePolymorphicType is called when serialize a polymorphic belongsTo'); diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 5767f4b7f93..b9b2cb6b60e 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -659,7 +659,9 @@ test('serializeIntoHash uses payloadKeyFromModelName to normalize the payload ro } })); - env.container.lookup('serializer:home-planet').serializeIntoHash(json, HomePlanet, league._createSnapshot()); + let serializer = env.store.serializerFor('home-planet'); + + serializer.serializeIntoHash(json, HomePlanet, league._createSnapshot()); assert.deepEqual(json, { 'home-planet': { diff --git a/yarn.lock b/yarn.lock index 8cbaada73de..a0db93b5e2d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5168,6 +5168,7 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" + rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.4, rimraf@^2.4.3, rimraf@^2.4.4: version "2.5.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" From e9acc1f57ddd59e2efab115f620476665c6442e6 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 11 Jul 2017 07:17:11 -0700 Subject: [PATCH 1972/2527] address feedback from @stefanpenner --- addon/-private/system/model/internal-model.js | 44 ++++++----- addon/-private/system/model/model.js | 8 -- addon/-private/system/model/states.js | 2 +- .../system/relationships/state/belongs-to.js | 4 +- .../system/relationships/state/has-many.js | 14 +--- .../relationships/state/relationship.js | 21 ++---- .../unit/model/relationships/has-many-test.js | 74 +++++++++---------- 7 files changed, 72 insertions(+), 95 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 59cb343daa5..549d1878481 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -715,7 +715,7 @@ export default class InternalModel { heimdall.increment(send); let currentState = this.currentState; - if (typeof currentState[name] !== 'function') { + if (!currentState[name]) { this._unhandledEvent(currentState, name, context); } @@ -728,12 +728,6 @@ export default class InternalModel { } } - notifyHasManyRemoved(key, record, idx) { - if (this.hasRecord) { - this._record.notifyHasManyRemoved(key, record, idx); - } - } - notifyBelongsToChanged(key, record) { if (this.hasRecord) { this._record.notifyBelongsToChanged(key, record); @@ -768,7 +762,7 @@ export default class InternalModel { } if (this.isNew()) { - this.clearRelationships(true); + this.clearRelationships(); } if (this.isValid()) { @@ -885,29 +879,39 @@ export default class InternalModel { @method clearRelationships @private */ - clearRelationships(resetAll = false) { + clearRelationships() { this.eachRelationship((name, relationship) => { if (this._relationships.has(name)) { let rel = this._relationships.get(name); - if (resetAll === true) { - rel.clear(); - rel.removeInverseRelationships(); - } else { - rel.unloadInverseInternalModel(this); - } + rel.clear(); + rel.removeInverseRelationships(); } }); Object.keys(this._implicitRelationships).forEach((key) => { let rel = this._implicitRelationships[key]; - if (resetAll === true) { - rel.clear(); - rel.removeInverseRelationships(); - } else { - rel.unloadInverseInternalModel(this); + rel.clear(); + rel.removeInverseRelationships(); + }); + } + + /* + @method unloadDeletedRecordFromRelationships + */ + unloadDeletedRecordFromRelationships() { + this.eachRelationship((name) => { + if (this._relationships.has(name)) { + let rel = this._relationships.get(name); + + rel.unloadDeletedInverseInternalModel(this); } }); + Object.keys(this._implicitRelationships).forEach((key) => { + let rel = this._implicitRelationships[key]; + + rel.unloadDeletedInverseInternalModel(this); + }); } destroyRelationships() { diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 37cb5f5ddb5..354bd46cdd9 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1115,14 +1115,6 @@ const Model = Ember.Object.extend(Ember.Evented, { this.notifyPropertyChange(key); }, - notifyHasManyRemoved(key) { - // We need to notifyPropertyChange in the removing case to flush ui state - // Goes away if we remove/improve the outer PromiseProxy on async relationships - // Notifying `${key}` or `${key}.length` does not work here, notifying `content` - // after `get(key)` also works but this wont always be an async relationship. - this.get(key).notifyPropertyChange('length'); - }, - eachAttribute(callback, binding) { this.constructor.eachAttribute(callback, binding); } diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index b14e9843b81..a6be3b80a76 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -671,7 +671,7 @@ const RootState = { isDirty: false, setup(internalModel) { - internalModel.clearRelationships(); + internalModel.unloadDeletedRecordFromRelationships(); }, invokeLifecycleCallbacks(internalModel) { diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 65e724ef788..452e70fcc82 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -63,8 +63,8 @@ export default class BelongsToRelationship extends Relationship { this.notifyBelongsToChanged(); } - unloadInverseInternalModelFromOwn(internalModel) { - super.unloadInverseInternalModelFromOwn(internalModel); + unloadDeletedInverseInternalModelFromOwn(internalModel) { + super.unloadDeletedInverseInternalModelFromOwn(internalModel); let didChange = false; if (this.canonicalState === internalModel) { diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index b0eba02faca..5f57ec41344 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -111,8 +111,8 @@ export default class ManyRelationship extends Relationship { super.removeCanonicalInternalModelFromOwn(internalModel, idx); } - unloadInverseInternalModelFromOwn(internalModel) { - super.unloadInverseInternalModelFromOwn(internalModel); + unloadDeletedInverseInternalModelFromOwn(internalModel) { + super.unloadDeletedInverseInternalModelFromOwn(internalModel); const canonicalIndex = this.canonicalState.indexOf(internalModel); @@ -123,16 +123,10 @@ export default class ManyRelationship extends Relationship { const manyArray = this._manyArray; if (manyArray) { - const currentState = manyArray.currentState; - const idx = currentState.indexOf(internalModel); + const idx = manyArray.currentState.indexOf(internalModel); if (idx !== -1) { - currentState.splice(idx, 1); - - manyArray.set('length', currentState.length); - manyArray.notifyPropertyChange('length'); - - this.internalModel.notifyHasManyRemoved(this.key, internalModel, idx); + manyArray.internalReplace(idx, 1); } } } diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 984d972bbe4..16577e84e7d 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -266,18 +266,7 @@ export default class Relationship { this.flushCanonicalLater(); } - unloadInverseInternalModel(internalModel) { - this.unloadInverseInternalModelFromOwn(internalModel); - this.unloadInverseInternalModelFromInverses(internalModel); - } - - unloadInverseInternalModelFromOwn(internalModel) { - this.canonicalMembers.delete(internalModel); - this.members.delete(internalModel); - this.notifyRecordRelationshipRemoved(internalModel); - } - - unloadInverseInternalModelFromInverses(internalModel) { + unloadDeletedInverseInternalModel(internalModel) { if (!this.inverseKey) { return; } let allMembers = @@ -287,10 +276,16 @@ export default class Relationship { allMembers.forEach(inverseInternalModel => { let relationship = inverseInternalModel._relationships.get(this.inverseKey); - relationship.unloadInverseInternalModelFromOwn(internalModel); + relationship.unloadDeletedInverseInternalModelFromOwn(internalModel); }); } + unloadDeletedInverseInternalModelFromOwn(internalModel) { + this.canonicalMembers.delete(internalModel); + this.members.delete(internalModel); + this.notifyRecordRelationshipRemoved(internalModel); + } + flushCanonical() { heimdall.increment(flushCanonical); let list = this.members.list; diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index b7d8e87f9da..134412b320c 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -989,7 +989,7 @@ test('new items added to a hasMany relationship are not cleared by a delete', fu assert.equal(get(pets, 'length'), 3, 'precond2 - relationship now has three pets'); run(() => { - shen.destroyRecord({}) + return shen.destroyRecord({}) .then(() => { shen.unloadRecord(); }); @@ -1066,9 +1066,9 @@ test('new items added to an async hasMany relationship are not cleared by a dele return run(() => { const person = store.peekRecord('person', '1'); - const petsProxy = person.get('pets'); + const petsProxy = run(() => person.get('pets')); - petsProxy.then((pets) => { + return petsProxy.then((pets) => { const shen = pets.objectAt(0); const rambo = store.peekRecord('pet', '2'); const rebel = store.peekRecord('pet', '3'); @@ -1077,22 +1077,18 @@ test('new items added to an async hasMany relationship are not cleared by a dele assert.equal(get(pets, 'length'), 1, 'precond - relationship has only one pet to start'); assert.equal(get(petsProxy, 'length'), 1, 'precond - proxy has only one pet to start'); - run(() => { - pets.pushObjects([rambo, rebel]); - }); + pets.pushObjects([rambo, rebel]); assert.equal(get(pets, 'length'), 3, 'precond2 - relationship now has three pets'); assert.equal(get(petsProxy, 'length'), 3, 'precond2 - proxy now reflects three pets'); - run(() => { - shen.destroyRecord({}) - .then(() => { - shen.unloadRecord(); - }); - }); + return shen.destroyRecord({}) + .then(() => { + shen.unloadRecord(); - assert.equal(get(pets, 'length'), 2, 'relationship now has two pets'); - assert.equal(get(petsProxy, 'length'), 2, 'proxy now reflects two pets'); + assert.equal(get(pets, 'length'), 2, 'relationship now has two pets'); + assert.equal(get(petsProxy, 'length'), 2, 'proxy now reflects two pets'); + }); }); }); }); @@ -1168,15 +1164,15 @@ test('new items added to a belongsTo relationship are not cleared by a delete', dog = person.get('dog'); assert.equal(dog, rambo, 'precond2 - relationship was updated'); - run(() => { - shen.destroyRecord({}) + return run(() => { + return shen.destroyRecord({}) .then(() => { shen.unloadRecord(); + + dog = person.get('dog'); + assert.equal(dog, rambo, 'The currentState of the belongsTo was preserved after the delete'); }); }); - - dog = person.get('dog'); - assert.equal(dog, rambo, 'The currentState of the belongsTo was preserved after the delete'); }); test('new items added to an async belongsTo relationship are not cleared by a delete', function(assert) { @@ -1244,23 +1240,19 @@ test('new items added to an async belongsTo relationship are not cleared by a de assert.ok(dog === shen, 'precond - the belongsTo points to the correct dog'); assert.equal(get(dog, 'name'), 'Shenanigans', 'precond - relationships work'); - run(() => { - person.set('dog', rambo); - }); + person.set('dog', rambo); dog = person.get('dog.content'); assert.ok(dog === rambo, 'precond2 - relationship was updated'); - run(() => { - shen.destroyRecord({}) - .then(() => { - shen.unloadRecord(); - }); - }); + return shen.destroyRecord({}) + .then(() => { + shen.unloadRecord(); - dog = person.get('dog.content'); - assert.ok(dog === rambo, 'The currentState of the belongsTo was preserved after the delete'); + dog = person.get('dog.content'); + assert.ok(dog === rambo, 'The currentState of the belongsTo was preserved after the delete'); + }); }); }); }); @@ -1336,15 +1328,15 @@ test('deleting an item that is the current state of a belongsTo restores canonic dog = person.get('dog'); assert.equal(dog, rambo, 'precond2 - relationship was updated'); - run(() => { - rambo.destroyRecord({}) + return run(() => { + return rambo.destroyRecord({}) .then(() => { rambo.unloadRecord(); + + dog = person.get('dog'); + assert.equal(dog, shen, 'The canonical state of the belongsTo was restored after the delete'); }); }); - - dog = person.get('dog'); - assert.equal(dog, shen, 'The canonical state of the belongsTo was restored after the delete'); }); /* @@ -1457,16 +1449,16 @@ test('returning new hasMany relationship info from a delete supplements local st assert.equal(get(pets, 'length'), 3, 'precond2 - relationship now has three pets'); - run(() => { - shen.destroyRecord({}) + return run(() => { + return shen.destroyRecord({}) .then(() => { shen.unloadRecord(); + + // were ember-data to now preserve local edits during a relationship push, this would be '2' + assert.equal(get(pets, 'length'), 1, 'relationship now has one pet'); + assert.equal(pets.objectAt(0), rambo, 'the expected pet remains'); }); }); - - // were ember-data to now preserve local edits during a relationship push, this would be '2' - assert.equal(get(pets, 'length'), 1, 'relationship now has one pet'); - assert.equal(pets.objectAt(0), rambo, 'the expected pet remains'); }); test('possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)', function(assert) { From 941ca586039ddd6ac970cb9c7d7eee3fd9a96fd0 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 11 Jul 2017 07:24:49 -0700 Subject: [PATCH 1973/2527] fix perf of unloading inverses --- .../relationships/state/relationship.js | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 16577e84e7d..d1410f477de 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -2,6 +2,9 @@ import { assert, warn } from '@ember/debug'; import OrderedSet from '../../ordered-set'; import _normalizeLink from '../../normalize-link'; +import Ember from 'ember'; + +const { guidFor } = Ember; const { addCanonicalInternalModel, @@ -269,15 +272,22 @@ export default class Relationship { unloadDeletedInverseInternalModel(internalModel) { if (!this.inverseKey) { return; } - let allMembers = - // we actually want a union of members and canonicalMembers - // they should be disjoint but currently are not due to a bug - this.members.toArray().concat(this.canonicalMembers.toArray()); + // we actually want a union of members and canonicalMembers + // they should be disjoint but currently are not due to a bug + let seen = Object.create(null); - allMembers.forEach(inverseInternalModel => { - let relationship = inverseInternalModel._relationships.get(this.inverseKey); - relationship.unloadDeletedInverseInternalModelFromOwn(internalModel); - }); + const unload = inverseInternalModel => { + const id = guidFor(inverseInternalModel); + + if (seen[id] === undefined) { + const relationship = inverseInternalModel._relationships.get(this.inverseKey); + relationship.unloadInverseInternalModelFromOwn(internalModel); + seen[id] = true; + } + }; + + this.members.forEach(unload); + this.canonicalMembers(unload); } unloadDeletedInverseInternalModelFromOwn(internalModel) { From 9a72fb5d56553e6dc50ae901da5e0684f15a59fc Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 11 Jul 2017 07:26:59 -0700 Subject: [PATCH 1974/2527] fix typos --- addon/-private/system/model/internal-model.js | 4 ++-- addon/-private/system/relationships/state/relationship.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 549d1878481..6be09d26f25 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -885,14 +885,14 @@ export default class InternalModel { let rel = this._relationships.get(name); rel.clear(); - rel.removeInverseRelationships(); + // rel.removeInverseRelationships(); } }); Object.keys(this._implicitRelationships).forEach((key) => { let rel = this._implicitRelationships[key]; rel.clear(); - rel.removeInverseRelationships(); + // rel.removeInverseRelationships(); }); } diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index d1410f477de..d21f90e164d 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -281,13 +281,13 @@ export default class Relationship { if (seen[id] === undefined) { const relationship = inverseInternalModel._relationships.get(this.inverseKey); - relationship.unloadInverseInternalModelFromOwn(internalModel); + relationship.unloadDeletedInverseInternalModelFromOwn(internalModel); seen[id] = true; } }; this.members.forEach(unload); - this.canonicalMembers(unload); + this.canonicalMembers.forEach(unload); } unloadDeletedInverseInternalModelFromOwn(internalModel) { From cee07bd664a57d5d69ab77ca73afc39b08ccfa0f Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 11 Jul 2017 07:28:47 -0700 Subject: [PATCH 1975/2527] revert accidental code commenting left behind --- addon/-private/system/model/internal-model.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 6be09d26f25..549d1878481 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -885,14 +885,14 @@ export default class InternalModel { let rel = this._relationships.get(name); rel.clear(); - // rel.removeInverseRelationships(); + rel.removeInverseRelationships(); } }); Object.keys(this._implicitRelationships).forEach((key) => { let rel = this._implicitRelationships[key]; rel.clear(); - // rel.removeInverseRelationships(); + rel.removeInverseRelationships(); }); } From 0818c0eef64d0973d9b3c99395549dd48471b24e Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Tue, 11 Jul 2017 10:46:23 -0400 Subject: [PATCH 1976/2527] Update RELEASE.md --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index d68d2f45aa7..d38fc25f0ab 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -20,7 +20,7 @@ STEPS: * Git tag version * `git tag vX.Y.Z-beta.n` * Do a production build. - * `rm -rf node_modules bower_components; npm install; bower install; npm run production` + * `rm -rf node_modules bower_components; yarn install; bower install; npm run production` * Publish to Bower * Commit built globals code to the https://github.com/components/ember-data repo * `cp dist/globals/* ../components-ember-data/` From 94503e613799043bc7f8260ea0f48294a41ac936 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 11 Jul 2017 11:43:54 -0700 Subject: [PATCH 1977/2527] code cleanup to address @dhamilton review --- addon/-private/system/model/internal-model.js | 19 ++++++++++++++----- .../system/relationships/state/belongs-to.js | 4 ++-- .../system/relationships/state/has-many.js | 4 ++-- .../relationships/state/relationship.js | 14 +++++++++++--- 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 549d1878481..10061722baa 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -762,7 +762,7 @@ export default class InternalModel { } if (this.isNew()) { - this.clearRelationships(); + this._resetAllRelationshipsToEmpty(); } if (this.isValid()) { @@ -876,10 +876,14 @@ export default class InternalModel { } /* - @method clearRelationships + This method should only be called by records in the `isNew()` state. + It will completely reset all relationships to an empty state and remove + the record from any associated inverses as well. + + @method _resetAllRelationshipsToEmpty @private */ - clearRelationships() { + _resetAllRelationshipsToEmpty() { this.eachRelationship((name, relationship) => { if (this._relationships.has(name)) { let rel = this._relationships.get(name); @@ -897,20 +901,25 @@ export default class InternalModel { } /* + This method should only be called once the record has been deleted + and that deletion has been persisted. It will remove this record from + any associated relationships. + @method unloadDeletedRecordFromRelationships + @private */ unloadDeletedRecordFromRelationships() { this.eachRelationship((name) => { if (this._relationships.has(name)) { let rel = this._relationships.get(name); - rel.unloadDeletedInverseInternalModel(this); + rel.removeDeletedInternalModelFromInverse(this); } }); Object.keys(this._implicitRelationships).forEach((key) => { let rel = this._implicitRelationships[key]; - rel.unloadDeletedInverseInternalModel(this); + rel.removeDeletedInternalModelFromInverse(this); }); } diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 452e70fcc82..8ae7c9929ab 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -63,8 +63,8 @@ export default class BelongsToRelationship extends Relationship { this.notifyBelongsToChanged(); } - unloadDeletedInverseInternalModelFromOwn(internalModel) { - super.unloadDeletedInverseInternalModelFromOwn(internalModel); + removeDeletedInternalModelFromOwn(internalModel) { + super.removeDeletedInternalModelFromOwn(internalModel); let didChange = false; if (this.canonicalState === internalModel) { diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 5f57ec41344..1c3796e2511 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -111,8 +111,8 @@ export default class ManyRelationship extends Relationship { super.removeCanonicalInternalModelFromOwn(internalModel, idx); } - unloadDeletedInverseInternalModelFromOwn(internalModel) { - super.unloadDeletedInverseInternalModelFromOwn(internalModel); + removeDeletedInternalModelFromOwn(internalModel) { + super.removeDeletedInternalModelFromOwn(internalModel); const canonicalIndex = this.canonicalState.indexOf(internalModel); diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index d21f90e164d..a0d82d6e4d5 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -269,7 +269,15 @@ export default class Relationship { this.flushCanonicalLater(); } - unloadDeletedInverseInternalModel(internalModel) { + /* + Call this method once a record deletion has been persisted + to purge it from both current and canonical state of all + relationships. + + @method removeDeletedInternalModelFromInverse + @private + */ + removeDeletedInternalModelFromInverse(internalModel) { if (!this.inverseKey) { return; } // we actually want a union of members and canonicalMembers @@ -281,7 +289,7 @@ export default class Relationship { if (seen[id] === undefined) { const relationship = inverseInternalModel._relationships.get(this.inverseKey); - relationship.unloadDeletedInverseInternalModelFromOwn(internalModel); + relationship.removeDeletedInternalModelFromOwn(internalModel); seen[id] = true; } }; @@ -290,7 +298,7 @@ export default class Relationship { this.canonicalMembers.forEach(unload); } - unloadDeletedInverseInternalModelFromOwn(internalModel) { + removeDeletedInternalModelFromOwn(internalModel) { this.canonicalMembers.delete(internalModel); this.members.delete(internalModel); this.notifyRecordRelationshipRemoved(internalModel); From 4d7f4e825e467ae6f5291b83885a8e88cdfbd5b9 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 11 Jul 2017 12:15:17 -0700 Subject: [PATCH 1978/2527] address remaining feedback from @hjdivad --- addon/-private/system/model/internal-model.js | 4 +-- .../system/relationships/state/belongs-to.js | 8 +----- .../relationships/state/relationship.js | 3 +- .../unit/model/relationships/has-many-test.js | 28 +++++++++---------- 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 10061722baa..a822c35d1d7 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -913,13 +913,13 @@ export default class InternalModel { if (this._relationships.has(name)) { let rel = this._relationships.get(name); - rel.removeDeletedInternalModelFromInverse(this); + rel.removeDeletedInternalModelFromInverse(); } }); Object.keys(this._implicitRelationships).forEach((key) => { let rel = this._implicitRelationships[key]; - rel.removeDeletedInternalModelFromInverse(this); + rel.removeDeletedInternalModelFromInverse(); }); } diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 8ae7c9929ab..6c498a0f79b 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -65,19 +65,13 @@ export default class BelongsToRelationship extends Relationship { removeDeletedInternalModelFromOwn(internalModel) { super.removeDeletedInternalModelFromOwn(internalModel); - let didChange = false; if (this.canonicalState === internalModel) { this.canonicalState = null; - didChange = true; } if (this.inverseInternalModel === internalModel) { - this.inverseInternalModel = this.canonicalState; - didChange = true; - } - - if (didChange === true) { + this.inverseInternalModel = null; this.notifyBelongsToChanged(); } } diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index a0d82d6e4d5..f6ca784261b 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -277,12 +277,13 @@ export default class Relationship { @method removeDeletedInternalModelFromInverse @private */ - removeDeletedInternalModelFromInverse(internalModel) { + removeDeletedInternalModelFromInverse() { if (!this.inverseKey) { return; } // we actually want a union of members and canonicalMembers // they should be disjoint but currently are not due to a bug let seen = Object.create(null); + const internalModel = this.indernalModel; const unload = inverseInternalModel => { const id = guidFor(inverseInternalModel); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 134412b320c..4098a067102 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -980,13 +980,13 @@ test('new items added to a hasMany relationship are not cleared by a delete', fu const rebel = store.peekRecord('pet', '3'); assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); - assert.equal(get(pets, 'length'), 1, 'precond - relationship has only one pet to start'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['1'], 'precond - relationship has the correct pets to start'); run(() => { pets.pushObjects([rambo, rebel]); }); - assert.equal(get(pets, 'length'), 3, 'precond2 - relationship now has three pets'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2', '3'], 'precond2 - relationship now has the correct three pets'); run(() => { return shen.destroyRecord({}) @@ -995,7 +995,7 @@ test('new items added to a hasMany relationship are not cleared by a delete', fu }); }); - assert.equal(get(pets, 'length'), 2, 'relationship now has two pets'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['2', '3'], 'relationship now has the correct two pets'); }); test('new items added to an async hasMany relationship are not cleared by a delete', function(assert) { @@ -1074,19 +1074,19 @@ test('new items added to an async hasMany relationship are not cleared by a dele const rebel = store.peekRecord('pet', '3'); assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); - assert.equal(get(pets, 'length'), 1, 'precond - relationship has only one pet to start'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['1'], 'precond - relationship has the correct pet to start'); assert.equal(get(petsProxy, 'length'), 1, 'precond - proxy has only one pet to start'); pets.pushObjects([rambo, rebel]); - assert.equal(get(pets, 'length'), 3, 'precond2 - relationship now has three pets'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2', '3'], 'precond2 - relationship now has the correct three pets'); assert.equal(get(petsProxy, 'length'), 3, 'precond2 - proxy now reflects three pets'); return shen.destroyRecord({}) .then(() => { shen.unloadRecord(); - assert.equal(get(pets, 'length'), 2, 'relationship now has two pets'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['2', '3'], 'relationship now has the correct two pets'); assert.equal(get(petsProxy, 'length'), 2, 'proxy now reflects two pets'); }); }); @@ -1257,7 +1257,7 @@ test('new items added to an async belongsTo relationship are not cleared by a de }); }); -test('deleting an item that is the current state of a belongsTo restores canonicalState', function(assert) { +test('deleting an item that is the current state of a belongsTo clears currentState', function(assert) { assert.expect(4); const Person = DS.Model.extend({ @@ -1334,7 +1334,7 @@ test('deleting an item that is the current state of a belongsTo restores canonic rambo.unloadRecord(); dog = person.get('dog'); - assert.equal(dog, shen, 'The canonical state of the belongsTo was restored after the delete'); + assert.equal(dog, null, 'The current state of the belongsTo was clearer'); }); }); }); @@ -1348,8 +1348,8 @@ test('deleting an item that is the current state of a belongsTo restores canonic the parent record's hasMany is a situation in which this limitation will be encountered should other local changes to the relationship still exist. */ -test('returning new hasMany relationship info from a delete supplements local state', function(assert) { - assert.expect(5); +test('[ASSERTS KNOWN LIMITATION STILL EXISTS] returning new hasMany relationship info from a delete clears local state', function(assert) { + assert.expect(4); const Person = DS.Model.extend({ name: DS.attr('string'), @@ -1437,17 +1437,16 @@ test('returning new hasMany relationship info from a delete supplements local st const pets = run(() => person.get('pets')); const shen = store.peekRecord('pet', '1'); - const rambo = store.peekRecord('pet', '2'); const rebel = store.peekRecord('pet', '3'); assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); - assert.equal(get(pets, 'length'), 2, 'precond - relationship has only one pet to start'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2'], 'precond - relationship has the correct pets to start'); run(() => { pets.pushObjects([rebel]); }); - assert.equal(get(pets, 'length'), 3, 'precond2 - relationship now has three pets'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2', '3'], 'precond2 - relationship now has the correct three pets'); return run(() => { return shen.destroyRecord({}) @@ -1455,8 +1454,7 @@ test('returning new hasMany relationship info from a delete supplements local st shen.unloadRecord(); // were ember-data to now preserve local edits during a relationship push, this would be '2' - assert.equal(get(pets, 'length'), 1, 'relationship now has one pet'); - assert.equal(pets.objectAt(0), rambo, 'the expected pet remains'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['2'], 'relationship now has only one pet, we lost the local change'); }); }); }); From 5830358f9c7888ae2819b1e07d84dca1683604df Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 11 Jul 2017 12:50:16 -0700 Subject: [PATCH 1979/2527] fix type --- addon/-private/system/relationships/state/relationship.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index f6ca784261b..67047770292 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -283,7 +283,7 @@ export default class Relationship { // we actually want a union of members and canonicalMembers // they should be disjoint but currently are not due to a bug let seen = Object.create(null); - const internalModel = this.indernalModel; + const internalModel = this.internalModel; const unload = inverseInternalModel => { const id = guidFor(inverseInternalModel); From 995af6362974b7bdc92c6a407212ba221a0e3636 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 12 Jul 2017 07:56:00 -0600 Subject: [PATCH 1980/2527] [DOC] Fixed a typo (#5059) --- addon/-private/system/references/has-many.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 1e503b5df74..9f08a7f5e77 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -314,7 +314,7 @@ HasManyReference.prototype._isLoaded = function() { }; /** - `value()` sycronously returns the current value of the has-many + `value()` synchronously returns the current value of the has-many relationship. Unlike `record.get('relationshipName')`, calling `value()` on a reference does not trigger a fetch if the async relationship is not yet loaded. If the relationship is not loaded From 5c1eb9cfb94610f21786f6b107cf8d7f5b7b9f40 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Wed, 12 Jul 2017 07:59:35 -0700 Subject: [PATCH 1981/2527] Set hasData for preloaded empty hasMany See #5053 for a similar fix in the fetchLink case. See #4845 for the initially reported bug. --- .../relationships/state/relationship.js | 1 + tests/unit/store/adapter-interop-test.js | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index aa9313692da..43cc279a196 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -320,6 +320,7 @@ export default class Relationship { updateInternalModelsFromAdapter(internalModels) { heimdall.increment(updateInternalModelsFromAdapter); + this.setHasData(true); //TODO(Igor) move this to a proper place //TODO Once we have adapter support, we need to handle updated and canonical changes this.computeChanges(internalModels); diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index bd03ce621d8..43c80a267a2 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -563,6 +563,59 @@ test('initial values of hasMany can be passed in as the third argument to find a return run(() => store.findRecord('person', 1, { preload: { friends: [2] } })); }); +test('initial empty values of hasMany can be passed in as the third argument to find as records', function(assert) { + assert.expect(1); + + const Adapter = TestAdapter.extend({ + findRecord(store, type, id, snapshot) { + assert.equal(snapshot.hasMany('friends').length, 0, 'Preloaded hasMany set'); + return { data: { id, type: 'person' } }; + } + }); + + let env = setupStore({ + adapter: Adapter + }); + + let { store } = env; + + const Person = DS.Model.extend({ + name: DS.attr('string'), + friends: DS.hasMany('person', { inverse: null, async: true }) + }); + + env.registry.register('model:person', Person); + + return run(() => { + return store.findRecord('person', 1, { preload: { friends: [] } }); + }); +}); + +test('initial values of hasMany can be passed in as the third argument to find as ids', function(assert) { + assert.expect(1); + + const Adapter = TestAdapter.extend({ + findRecord(store, type, id, snapshot) { + assert.equal(snapshot.hasMany('friends').length, 0, 'Preloaded hasMany set'); + return { data: { id, type: 'person' } }; + } + }); + + let env = setupStore({ + adapter: Adapter + }); + let { store } = env; + + const Person = DS.Model.extend({ + name: DS.attr('string'), + friends: DS.hasMany('person', { async: true, inverse: null }) + }); + + env.registry.register('model:person', Person); + + return run(() => store.findRecord('person', 1, { preload: { friends: [] } })); +}); + test('records should have their ids updated when the adapter returns the id data', function(assert) { assert.expect(2); From e5cdfe48e4ad530d2f43fe2b5f10125628f6da51 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 13 Jul 2017 13:18:46 -0700 Subject: [PATCH 1982/2527] fixup function naming --- addon/-private/system/model/internal-model.js | 4 ++-- addon/-private/system/model/states.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index a822c35d1d7..a018b686897 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -905,10 +905,10 @@ export default class InternalModel { and that deletion has been persisted. It will remove this record from any associated relationships. - @method unloadDeletedRecordFromRelationships + @method removeFromInverseRelationships @private */ - unloadDeletedRecordFromRelationships() { + removeFromInverseRelationships() { this.eachRelationship((name) => { if (this._relationships.has(name)) { let rel = this._relationships.get(name); diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index a6be3b80a76..4977133fefc 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -671,7 +671,7 @@ const RootState = { isDirty: false, setup(internalModel) { - internalModel.unloadDeletedRecordFromRelationships(); + internalModel.removeFromInverseRelationships(); }, invokeLifecycleCallbacks(internalModel) { From b538bbf810ea4697d732b57dc5e7668dd0f2571f Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 13 Jul 2017 18:51:55 -0700 Subject: [PATCH 1983/2527] un-diverge isNew and deletion scenarios --- addon/-private/system/model/internal-model.js | 42 +++++++------------ addon/-private/system/record-array-manager.js | 2 +- .../relationships/state/relationship.js | 1 + 3 files changed, 16 insertions(+), 29 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index a018b686897..aaa0b965241 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -762,7 +762,7 @@ export default class InternalModel { } if (this.isNew()) { - this._resetAllRelationshipsToEmpty(); + this.removeFromInverseRelationships(true); } if (this.isValid()) { @@ -876,50 +876,36 @@ export default class InternalModel { } /* - This method should only be called by records in the `isNew()` state. - It will completely reset all relationships to an empty state and remove - the record from any associated inverses as well. + This method should only be called by records in the `isNew()` state OR once the record + has been deleted and that deletion has been persisted. - @method _resetAllRelationshipsToEmpty - @private - */ - _resetAllRelationshipsToEmpty() { - this.eachRelationship((name, relationship) => { - if (this._relationships.has(name)) { - let rel = this._relationships.get(name); + It will remove this record from any associated relationships. - rel.clear(); - rel.removeInverseRelationships(); - } - }); - Object.keys(this._implicitRelationships).forEach((key) => { - let rel = this._implicitRelationships[key]; - - rel.clear(); - rel.removeInverseRelationships(); - }); - } - - /* - This method should only be called once the record has been deleted - and that deletion has been persisted. It will remove this record from - any associated relationships. + It will completely reset all relationships to an empty state and remove + the record from any associated inverses as well. @method removeFromInverseRelationships + @param {Boolean} isNew whether to unload from the `isNew` perspective @private */ - removeFromInverseRelationships() { + removeFromInverseRelationships(isNew = false) { this.eachRelationship((name) => { if (this._relationships.has(name)) { let rel = this._relationships.get(name); rel.removeDeletedInternalModelFromInverse(); + if (isNew === true) { + rel.clear(); + } } }); Object.keys(this._implicitRelationships).forEach((key) => { let rel = this._implicitRelationships[key]; rel.removeDeletedInternalModelFromInverse(); + if (isNew === true) { + rel.clear(); + } }); } diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index bf8e4fbd3d4..483e7766502 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -88,7 +88,7 @@ export default class RecordArrayManager { return; } - internalModel._pendingRecordArrayManagerFlush = true + internalModel._pendingRecordArrayManagerFlush = true; let pending = this._pending; let models = pending[modelName] = pending[modelName] || []; diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 67047770292..6498bfbab06 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -303,6 +303,7 @@ export default class Relationship { this.canonicalMembers.delete(internalModel); this.members.delete(internalModel); this.notifyRecordRelationshipRemoved(internalModel); + // this.internalModel.updateRecordArrays(); } flushCanonical() { From 348b72fba279ee33d49e367f2af171e7cd114911 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 13 Jul 2017 18:54:21 -0700 Subject: [PATCH 1984/2527] improve code comment --- addon/-private/system/model/internal-model.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index aaa0b965241..fb92a4a6fc0 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -881,8 +881,8 @@ export default class InternalModel { It will remove this record from any associated relationships. - It will completely reset all relationships to an empty state and remove - the record from any associated inverses as well. + If `isNew` is true (default false), it will completely reset all relationships + to an empty state as well. @method removeFromInverseRelationships @param {Boolean} isNew whether to unload from the `isNew` perspective From 02a5a46f03932ae3baa3ed97316a1f9997b3e16a Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 13 Jul 2017 20:07:41 -0700 Subject: [PATCH 1985/2527] remove unused code --- addon/-private/system/relationships/state/relationship.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 6498bfbab06..b49feaef0df 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -250,7 +250,6 @@ export default class Relationship { removeInternalModelFromOwn(internalModel) { heimdall.increment(removeInternalModelFromOwn); this.members.delete(internalModel); - this.notifyRecordRelationshipRemoved(internalModel); this.internalModel.updateRecordArrays(); } @@ -302,8 +301,6 @@ export default class Relationship { removeDeletedInternalModelFromOwn(internalModel) { this.canonicalMembers.delete(internalModel); this.members.delete(internalModel); - this.notifyRecordRelationshipRemoved(internalModel); - // this.internalModel.updateRecordArrays(); } flushCanonical() { @@ -366,7 +363,6 @@ export default class Relationship { } notifyRecordRelationshipAdded() { } - notifyRecordRelationshipRemoved() { } /* `hasData` for a relationship is a flag to indicate if we consider the From 8c3f77dc184644476448f1984722094afd92281f Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 14 Jul 2017 12:16:19 -0700 Subject: [PATCH 1986/2527] final cleanup --- addon/-private/system/model/internal-model.js | 14 ++++++++++---- .../system/relationships/state/belongs-to.js | 4 ++-- .../system/relationships/state/has-many.js | 4 ++-- .../system/relationships/state/relationship.js | 17 ++++++++++++----- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index fb92a4a6fc0..44624909f94 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -881,8 +881,8 @@ export default class InternalModel { It will remove this record from any associated relationships. - If `isNew` is true (default false), it will completely reset all relationships - to an empty state as well. + If `isNew` is true (default false), it will also completely reset all + relationships to an empty state as well. @method removeFromInverseRelationships @param {Boolean} isNew whether to unload from the `isNew` perspective @@ -893,7 +893,7 @@ export default class InternalModel { if (this._relationships.has(name)) { let rel = this._relationships.get(name); - rel.removeDeletedInternalModelFromInverse(); + rel.removeCompletelyFromInverse(); if (isNew === true) { rel.clear(); } @@ -902,13 +902,17 @@ export default class InternalModel { Object.keys(this._implicitRelationships).forEach((key) => { let rel = this._implicitRelationships[key]; - rel.removeDeletedInternalModelFromInverse(); + rel.removeCompletelyFromInverse(); if (isNew === true) { rel.clear(); } }); } + /* + Notify all inverses that this internalModel has been dematerialized + and destroys any ManyArrays. + */ destroyRelationships() { this.eachRelationship((name, relationship) => { if (this._relationships.has(name)) { @@ -992,6 +996,8 @@ export default class InternalModel { } /* + Used to notify the store to update FilteredRecordArray membership. + @method updateRecordArrays @private */ diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 6c498a0f79b..79ab00e7700 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -63,8 +63,8 @@ export default class BelongsToRelationship extends Relationship { this.notifyBelongsToChanged(); } - removeDeletedInternalModelFromOwn(internalModel) { - super.removeDeletedInternalModelFromOwn(internalModel); + removeCompletelyFromOwn(internalModel) { + super.removeCompletelyFromOwn(internalModel); if (this.canonicalState === internalModel) { this.canonicalState = null; diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 1c3796e2511..26399ea94e8 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -111,8 +111,8 @@ export default class ManyRelationship extends Relationship { super.removeCanonicalInternalModelFromOwn(internalModel, idx); } - removeDeletedInternalModelFromOwn(internalModel) { - super.removeDeletedInternalModelFromOwn(internalModel); + removeCompletelyFromOwn(internalModel) { + super.removeCompletelyFromOwn(internalModel); const canonicalIndex = this.canonicalState.indexOf(internalModel); diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index b49feaef0df..20e7ea950f2 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -270,13 +270,13 @@ export default class Relationship { /* Call this method once a record deletion has been persisted - to purge it from both current and canonical state of all + to purge it from BOTH current and canonical state of all relationships. - @method removeDeletedInternalModelFromInverse + @method removeCompletelyFromInverse @private */ - removeDeletedInternalModelFromInverse() { + removeCompletelyFromInverse() { if (!this.inverseKey) { return; } // we actually want a union of members and canonicalMembers @@ -289,7 +289,7 @@ export default class Relationship { if (seen[id] === undefined) { const relationship = inverseInternalModel._relationships.get(this.inverseKey); - relationship.removeDeletedInternalModelFromOwn(internalModel); + relationship.removeCompletelyFromOwn(internalModel); seen[id] = true; } }; @@ -298,9 +298,16 @@ export default class Relationship { this.canonicalMembers.forEach(unload); } - removeDeletedInternalModelFromOwn(internalModel) { + /* + Removes the given internalModel from BOTH canonical AND current state. + + This method is useful when either a deletion or a rollback on a new record + needs to entirely purge itself from an inverse relationship. + */ + removeCompletelyFromOwn(internalModel) { this.canonicalMembers.delete(internalModel); this.members.delete(internalModel); + this.internalModel.updateRecordArrays(); } flushCanonical() { From 16b8a045779a4fd47e8251ab2c6cd4a76ab2824e Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 14 Jul 2017 12:41:58 -0700 Subject: [PATCH 1987/2527] Revert "[BUGFIX] keep local state after a deletion" --- addon/-private/system/model/internal-model.js | 46 +- addon/-private/system/model/states.js | 2 +- addon/-private/system/record-array-manager.js | 2 +- .../system/relationships/state/belongs-to.js | 13 - .../system/relationships/state/has-many.js | 20 - .../relationships/state/relationship.js | 47 +- .../relationships/has-many-test.js | 4 +- .../unit/model/relationships/has-many-test.js | 553 ------------------ 8 files changed, 20 insertions(+), 667 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 44624909f94..e1cdbd5a9b4 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -728,6 +728,12 @@ export default class InternalModel { } } + notifyHasManyRemoved(key, record, idx) { + if (this.hasRecord) { + this._record.notifyHasManyRemoved(key, record, idx); + } + } + notifyBelongsToChanged(key, record) { if (this.hasRecord) { this._record.notifyBelongsToChanged(key, record); @@ -762,7 +768,7 @@ export default class InternalModel { } if (this.isNew()) { - this.removeFromInverseRelationships(true); + this.clearRelationships(); } if (this.isValid()) { @@ -876,43 +882,23 @@ export default class InternalModel { } /* - This method should only be called by records in the `isNew()` state OR once the record - has been deleted and that deletion has been persisted. - - It will remove this record from any associated relationships. - - If `isNew` is true (default false), it will also completely reset all - relationships to an empty state as well. - - @method removeFromInverseRelationships - @param {Boolean} isNew whether to unload from the `isNew` perspective + @method clearRelationships @private - */ - removeFromInverseRelationships(isNew = false) { - this.eachRelationship((name) => { + */ + clearRelationships() { + this.eachRelationship((name, relationship) => { if (this._relationships.has(name)) { let rel = this._relationships.get(name); - - rel.removeCompletelyFromInverse(); - if (isNew === true) { - rel.clear(); - } + rel.clear(); + rel.removeInverseRelationships(); } }); Object.keys(this._implicitRelationships).forEach((key) => { - let rel = this._implicitRelationships[key]; - - rel.removeCompletelyFromInverse(); - if (isNew === true) { - rel.clear(); - } + this._implicitRelationships[key].clear(); + this._implicitRelationships[key].removeInverseRelationships(); }); } - /* - Notify all inverses that this internalModel has been dematerialized - and destroys any ManyArrays. - */ destroyRelationships() { this.eachRelationship((name, relationship) => { if (this._relationships.has(name)) { @@ -996,8 +982,6 @@ export default class InternalModel { } /* - Used to notify the store to update FilteredRecordArray membership. - @method updateRecordArrays @private */ diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index 4977133fefc..b14e9843b81 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -671,7 +671,7 @@ const RootState = { isDirty: false, setup(internalModel) { - internalModel.removeFromInverseRelationships(); + internalModel.clearRelationships(); }, invokeLifecycleCallbacks(internalModel) { diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 483e7766502..bf8e4fbd3d4 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -88,7 +88,7 @@ export default class RecordArrayManager { return; } - internalModel._pendingRecordArrayManagerFlush = true; + internalModel._pendingRecordArrayManagerFlush = true let pending = this._pending; let models = pending[modelName] = pending[modelName] || []; diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 79ab00e7700..2959d13c25c 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -63,19 +63,6 @@ export default class BelongsToRelationship extends Relationship { this.notifyBelongsToChanged(); } - removeCompletelyFromOwn(internalModel) { - super.removeCompletelyFromOwn(internalModel); - - if (this.canonicalState === internalModel) { - this.canonicalState = null; - } - - if (this.inverseInternalModel === internalModel) { - this.inverseInternalModel = null; - this.notifyBelongsToChanged(); - } - } - flushCanonical() { //temporary fix to not remove newly created records if server returned null. //TODO remove once we have proper diffing diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 10cb1e8826a..89f7e511e68 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -111,26 +111,6 @@ export default class ManyRelationship extends Relationship { super.removeCanonicalInternalModelFromOwn(internalModel, idx); } - removeCompletelyFromOwn(internalModel) { - super.removeCompletelyFromOwn(internalModel); - - const canonicalIndex = this.canonicalState.indexOf(internalModel); - - if (canonicalIndex !== -1) { - this.canonicalState.splice(canonicalIndex, 1); - } - - const manyArray = this._manyArray; - - if (manyArray) { - const idx = manyArray.currentState.indexOf(internalModel); - - if (idx !== -1) { - manyArray.internalReplace(idx, 1); - } - } - } - flushCanonical() { if (this._manyArray) { this._manyArray.flushCanonical(); diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 4bf194c2567..43cc279a196 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -2,9 +2,6 @@ import { assert, warn } from '@ember/debug'; import OrderedSet from '../../ordered-set'; import _normalizeLink from '../../normalize-link'; -import Ember from 'ember'; - -const { guidFor } = Ember; const { addCanonicalInternalModel, @@ -250,6 +247,7 @@ export default class Relationship { removeInternalModelFromOwn(internalModel) { heimdall.increment(removeInternalModelFromOwn); this.members.delete(internalModel); + this.notifyRecordRelationshipRemoved(internalModel); this.internalModel.updateRecordArrays(); } @@ -268,48 +266,6 @@ export default class Relationship { this.flushCanonicalLater(); } - /* - Call this method once a record deletion has been persisted - to purge it from BOTH current and canonical state of all - relationships. - - @method removeCompletelyFromInverse - @private - */ - removeCompletelyFromInverse() { - if (!this.inverseKey) { return; } - - // we actually want a union of members and canonicalMembers - // they should be disjoint but currently are not due to a bug - let seen = Object.create(null); - const internalModel = this.internalModel; - - const unload = inverseInternalModel => { - const id = guidFor(inverseInternalModel); - - if (seen[id] === undefined) { - const relationship = inverseInternalModel._relationships.get(this.inverseKey); - relationship.removeCompletelyFromOwn(internalModel); - seen[id] = true; - } - }; - - this.members.forEach(unload); - this.canonicalMembers.forEach(unload); - } - - /* - Removes the given internalModel from BOTH canonical AND current state. - - This method is useful when either a deletion or a rollback on a new record - needs to entirely purge itself from an inverse relationship. - */ - removeCompletelyFromOwn(internalModel) { - this.canonicalMembers.delete(internalModel); - this.members.delete(internalModel); - this.internalModel.updateRecordArrays(); - } - flushCanonical() { heimdall.increment(flushCanonical); let list = this.members.list; @@ -371,6 +327,7 @@ export default class Relationship { } notifyRecordRelationshipAdded() { } + notifyRecordRelationshipRemoved() { } /* `hasData` for a relationship is a flag to indicate if we consider the diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 4fe9e40c68e..9431753f66d 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -2520,9 +2520,7 @@ test("adding and removing records from hasMany relationship #2666", function(ass return comments.get('lastObject').destroyRecord(); }).then(() => { let comments = post.get('comments'); - let length = comments.get('length'); - - assert.equal(length, 3, "Comments count after destroy"); + assert.equal(comments.get('length'), 3, "Comments count after destroy"); // Add another comment #4 let comment = env.store.createRecord('comment'); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 4098a067102..b9f3d391d5a 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -906,559 +906,6 @@ test('it is possible to add a new item to a relationship', function(assert) { }); }); -test('new items added to a hasMany relationship are not cleared by a delete', function(assert) { - assert.expect(4); - - const Person = DS.Model.extend({ - name: DS.attr('string'), - pets: DS.hasMany('pet', { async: false, inverse: null }) - }); - - const Pet = DS.Model.extend({ - name: DS.attr('string'), - person: DS.belongsTo('person', { async: false, inverse: null }) - }); - - let env = setupStore({ - person: Person, - pet: Pet - }); - env.adapter.shouldBackgroundReloadRecord = () => false; - env.adapter.deleteRecord = () => { - return Ember.RSVP.Promise.resolve({ data: null }); - }; - - let { store } = env; - - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Chris Thoburn' - }, - relationships: { - pets: { - data: [ - { type: 'pet', id: '1' } - ] - } - } - }, - included: [ - { - type: 'pet', - id: '1', - attributes: { - name: 'Shenanigans' - } - }, - { - type: 'pet', - id: '2', - attributes: { - name: 'Rambunctious' - } - }, - { - type: 'pet', - id: '3', - attributes: { - name: 'Rebel' - } - } - ] - }); - }); - - const person = store.peekRecord('person', '1'); - const pets = run(() => person.get('pets')); - - const shen = pets.objectAt(0); - const rambo = store.peekRecord('pet', '2'); - const rebel = store.peekRecord('pet', '3'); - - assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); - assert.deepEqual(pets.map(p => get(p, 'id')), ['1'], 'precond - relationship has the correct pets to start'); - - run(() => { - pets.pushObjects([rambo, rebel]); - }); - - assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2', '3'], 'precond2 - relationship now has the correct three pets'); - - run(() => { - return shen.destroyRecord({}) - .then(() => { - shen.unloadRecord(); - }); - }); - - assert.deepEqual(pets.map(p => get(p, 'id')), ['2', '3'], 'relationship now has the correct two pets'); -}); - -test('new items added to an async hasMany relationship are not cleared by a delete', function(assert) { - assert.expect(7); - - const Person = DS.Model.extend({ - name: DS.attr('string'), - pets: DS.hasMany('pet', { async: true, inverse: null }) - }); - - const Pet = DS.Model.extend({ - name: DS.attr('string'), - person: DS.belongsTo('person', { async: false, inverse: null }) - }); - - let env = setupStore({ - person: Person, - pet: Pet - }); - env.adapter.shouldBackgroundReloadRecord = () => false; - env.adapter.deleteRecord = () => { - return Ember.RSVP.Promise.resolve({ data: null }); - }; - - let { store } = env; - - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Chris Thoburn' - }, - relationships: { - pets: { - data: [ - { type: 'pet', id: '1' } - ] - } - } - }, - included: [ - { - type: 'pet', - id: '1', - attributes: { - name: 'Shenanigans' - } - }, - { - type: 'pet', - id: '2', - attributes: { - name: 'Rambunctious' - } - }, - { - type: 'pet', - id: '3', - attributes: { - name: 'Rebel' - } - } - ] - }); - }); - - return run(() => { - const person = store.peekRecord('person', '1'); - const petsProxy = run(() => person.get('pets')); - - return petsProxy.then((pets) => { - const shen = pets.objectAt(0); - const rambo = store.peekRecord('pet', '2'); - const rebel = store.peekRecord('pet', '3'); - - assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); - assert.deepEqual(pets.map(p => get(p, 'id')), ['1'], 'precond - relationship has the correct pet to start'); - assert.equal(get(petsProxy, 'length'), 1, 'precond - proxy has only one pet to start'); - - pets.pushObjects([rambo, rebel]); - - assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2', '3'], 'precond2 - relationship now has the correct three pets'); - assert.equal(get(petsProxy, 'length'), 3, 'precond2 - proxy now reflects three pets'); - - return shen.destroyRecord({}) - .then(() => { - shen.unloadRecord(); - - assert.deepEqual(pets.map(p => get(p, 'id')), ['2', '3'], 'relationship now has the correct two pets'); - assert.equal(get(petsProxy, 'length'), 2, 'proxy now reflects two pets'); - }); - }); - }); -}); - -test('new items added to a belongsTo relationship are not cleared by a delete', function(assert) { - assert.expect(4); - - const Person = DS.Model.extend({ - name: DS.attr('string'), - dog: DS.belongsTo('dog', { async: false, inverse: null }) - }); - - const Dog = DS.Model.extend({ - name: DS.attr('string') - }); - - let env = setupStore({ - person: Person, - dog: Dog - }); - env.adapter.shouldBackgroundReloadRecord = () => false; - env.adapter.deleteRecord = () => { - return Ember.RSVP.Promise.resolve({ data: null }); - }; - - let { store } = env; - - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Chris Thoburn' - }, - relationships: { - dog: { - data: { type: 'dog', id: '1' } - } - } - }, - included: [ - { - type: 'dog', - id: '1', - attributes: { - name: 'Shenanigans' - } - }, - { - type: 'dog', - id: '2', - attributes: { - name: 'Rambunctious' - } - } - ] - }); - }); - - const person = store.peekRecord('person', '1'); - let dog = run(() => person.get('dog')); - const shen = store.peekRecord('dog', '1'); - const rambo = store.peekRecord('dog', '2'); - - assert.ok(dog === shen, 'precond - the belongsTo points to the correct dog'); - assert.equal(get(dog, 'name'), 'Shenanigans', 'precond - relationships work'); - - run(() => { - person.set('dog', rambo); - }); - - dog = person.get('dog'); - assert.equal(dog, rambo, 'precond2 - relationship was updated'); - - return run(() => { - return shen.destroyRecord({}) - .then(() => { - shen.unloadRecord(); - - dog = person.get('dog'); - assert.equal(dog, rambo, 'The currentState of the belongsTo was preserved after the delete'); - }); - }); -}); - -test('new items added to an async belongsTo relationship are not cleared by a delete', function(assert) { - assert.expect(4); - - const Person = DS.Model.extend({ - name: DS.attr('string'), - dog: DS.belongsTo('dog', { async: true, inverse: null }) - }); - - const Dog = DS.Model.extend({ - name: DS.attr('string') - }); - - let env = setupStore({ - person: Person, - dog: Dog - }); - env.adapter.shouldBackgroundReloadRecord = () => false; - env.adapter.deleteRecord = () => { - return Ember.RSVP.Promise.resolve({ data: null }); - }; - - let { store } = env; - - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Chris Thoburn' - }, - relationships: { - dog: { - data: { type: 'dog', id: '1' } - } - } - }, - included: [ - { - type: 'dog', - id: '1', - attributes: { - name: 'Shenanigans' - } - }, - { - type: 'dog', - id: '2', - attributes: { - name: 'Rambunctious' - } - } - ] - }); - }); - - return run(() => { - const person = store.peekRecord('person', '1'); - const shen = store.peekRecord('dog', '1'); - const rambo = store.peekRecord('dog', '2'); - - return person.get('dog').then((dog) => { - assert.ok(dog === shen, 'precond - the belongsTo points to the correct dog'); - assert.equal(get(dog, 'name'), 'Shenanigans', 'precond - relationships work'); - - person.set('dog', rambo); - - dog = person.get('dog.content'); - - assert.ok(dog === rambo, 'precond2 - relationship was updated'); - - return shen.destroyRecord({}) - .then(() => { - shen.unloadRecord(); - - dog = person.get('dog.content'); - assert.ok(dog === rambo, 'The currentState of the belongsTo was preserved after the delete'); - }); - }); - }); -}); - -test('deleting an item that is the current state of a belongsTo clears currentState', function(assert) { - assert.expect(4); - - const Person = DS.Model.extend({ - name: DS.attr('string'), - dog: DS.belongsTo('dog', { async: false, inverse: null }) - }); - - const Dog = DS.Model.extend({ - name: DS.attr('string') - }); - - let env = setupStore({ - person: Person, - dog: Dog - }); - env.adapter.shouldBackgroundReloadRecord = () => false; - env.adapter.deleteRecord = () => { - return Ember.RSVP.Promise.resolve({ data: null }); - }; - - let { store } = env; - - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Chris Thoburn' - }, - relationships: { - dog: { - data: { type: 'dog', id: '1' } - } - } - }, - included: [ - { - type: 'dog', - id: '1', - attributes: { - name: 'Shenanigans' - } - }, - { - type: 'dog', - id: '2', - attributes: { - name: 'Rambunctious' - } - } - ] - }); - }); - - const person = store.peekRecord('person', '1'); - let dog = run(() => person.get('dog')); - const shen = store.peekRecord('dog', '1'); - const rambo = store.peekRecord('dog', '2'); - - assert.ok(dog === shen, 'precond - the belongsTo points to the correct dog'); - assert.equal(get(dog, 'name'), 'Shenanigans', 'precond - relationships work'); - - run(() => { - person.set('dog', rambo); - }); - - dog = person.get('dog'); - assert.equal(dog, rambo, 'precond2 - relationship was updated'); - - return run(() => { - return rambo.destroyRecord({}) - .then(() => { - rambo.unloadRecord(); - - dog = person.get('dog'); - assert.equal(dog, null, 'The current state of the belongsTo was clearer'); - }); - }); -}); - -/* - This test, when passing, affirms that a known limitation of ember-data still exists. - - When pushing new data into the store, ember-data is currently incapable of knowing whether - a relationship has been persisted. In order to update relationship state effectively, ember-data - blindly "flushes canonical" state, removing any `currentState` changes. A delete that sideloads - the parent record's hasMany is a situation in which this limitation will be encountered should other - local changes to the relationship still exist. - */ -test('[ASSERTS KNOWN LIMITATION STILL EXISTS] returning new hasMany relationship info from a delete clears local state', function(assert) { - assert.expect(4); - - const Person = DS.Model.extend({ - name: DS.attr('string'), - pets: DS.hasMany('pet', { async: false, inverse: null }) - }); - - const Pet = DS.Model.extend({ - name: DS.attr('string'), - person: DS.belongsTo('person', { async: false, inverse: null }) - }); - - let env = setupStore({ - person: Person, - pet: Pet - }); - env.adapter.shouldBackgroundReloadRecord = () => false; - env.adapter.deleteRecord = () => { - return Ember.RSVP.Promise.resolve({ - data: null, - included: [ - { - type: 'person', - id: '1', - attributes: { - name: 'Chris Thoburn' - }, - relationships: { - pets: { - data: [ - { type: 'pet', id: '2' } - ] - } - } - } - ] - }); - }; - - let { store } = env; - - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Chris Thoburn' - }, - relationships: { - pets: { - data: [ - { type: 'pet', id: '1' }, - { type: 'pet', id: '2' } - ] - } - } - }, - included: [ - { - type: 'pet', - id: '1', - attributes: { - name: 'Shenanigans' - } - }, - { - type: 'pet', - id: '2', - attributes: { - name: 'Rambunctious' - } - }, - { - type: 'pet', - id: '3', - attributes: { - name: 'Rebel' - } - } - ] - }); - }); - - const person = store.peekRecord('person', '1'); - const pets = run(() => person.get('pets')); - - const shen = store.peekRecord('pet', '1'); - const rebel = store.peekRecord('pet', '3'); - - assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); - assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2'], 'precond - relationship has the correct pets to start'); - - run(() => { - pets.pushObjects([rebel]); - }); - - assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2', '3'], 'precond2 - relationship now has the correct three pets'); - - return run(() => { - return shen.destroyRecord({}) - .then(() => { - shen.unloadRecord(); - - // were ember-data to now preserve local edits during a relationship push, this would be '2' - assert.deepEqual(pets.map(p => get(p, 'id')), ['2'], 'relationship now has only one pet, we lost the local change'); - }); - }); -}); - test('possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)', function(assert) { assert.expect(2); From 8558df6e52916778ca897c11a6f7d9b9a3283afb Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 14 Jul 2017 12:49:01 -0700 Subject: [PATCH 1988/2527] [BUGFIX] Preserve local relationship changes after persisting a deletion when possible. This reverts commit 16b8a045779a4fd47e8251ab2c6cd4a76ab2824e. --- addon/-private/system/model/internal-model.js | 46 +- addon/-private/system/model/states.js | 2 +- addon/-private/system/record-array-manager.js | 2 +- .../system/relationships/state/belongs-to.js | 13 + .../system/relationships/state/has-many.js | 20 + .../relationships/state/relationship.js | 47 +- .../relationships/has-many-test.js | 4 +- .../unit/model/relationships/has-many-test.js | 553 ++++++++++++++++++ 8 files changed, 667 insertions(+), 20 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index e1cdbd5a9b4..44624909f94 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -728,12 +728,6 @@ export default class InternalModel { } } - notifyHasManyRemoved(key, record, idx) { - if (this.hasRecord) { - this._record.notifyHasManyRemoved(key, record, idx); - } - } - notifyBelongsToChanged(key, record) { if (this.hasRecord) { this._record.notifyBelongsToChanged(key, record); @@ -768,7 +762,7 @@ export default class InternalModel { } if (this.isNew()) { - this.clearRelationships(); + this.removeFromInverseRelationships(true); } if (this.isValid()) { @@ -882,23 +876,43 @@ export default class InternalModel { } /* - @method clearRelationships + This method should only be called by records in the `isNew()` state OR once the record + has been deleted and that deletion has been persisted. + + It will remove this record from any associated relationships. + + If `isNew` is true (default false), it will also completely reset all + relationships to an empty state as well. + + @method removeFromInverseRelationships + @param {Boolean} isNew whether to unload from the `isNew` perspective @private - */ - clearRelationships() { - this.eachRelationship((name, relationship) => { + */ + removeFromInverseRelationships(isNew = false) { + this.eachRelationship((name) => { if (this._relationships.has(name)) { let rel = this._relationships.get(name); - rel.clear(); - rel.removeInverseRelationships(); + + rel.removeCompletelyFromInverse(); + if (isNew === true) { + rel.clear(); + } } }); Object.keys(this._implicitRelationships).forEach((key) => { - this._implicitRelationships[key].clear(); - this._implicitRelationships[key].removeInverseRelationships(); + let rel = this._implicitRelationships[key]; + + rel.removeCompletelyFromInverse(); + if (isNew === true) { + rel.clear(); + } }); } + /* + Notify all inverses that this internalModel has been dematerialized + and destroys any ManyArrays. + */ destroyRelationships() { this.eachRelationship((name, relationship) => { if (this._relationships.has(name)) { @@ -982,6 +996,8 @@ export default class InternalModel { } /* + Used to notify the store to update FilteredRecordArray membership. + @method updateRecordArrays @private */ diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index b14e9843b81..4977133fefc 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -671,7 +671,7 @@ const RootState = { isDirty: false, setup(internalModel) { - internalModel.clearRelationships(); + internalModel.removeFromInverseRelationships(); }, invokeLifecycleCallbacks(internalModel) { diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index bf8e4fbd3d4..483e7766502 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -88,7 +88,7 @@ export default class RecordArrayManager { return; } - internalModel._pendingRecordArrayManagerFlush = true + internalModel._pendingRecordArrayManagerFlush = true; let pending = this._pending; let models = pending[modelName] = pending[modelName] || []; diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 2959d13c25c..79ab00e7700 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -63,6 +63,19 @@ export default class BelongsToRelationship extends Relationship { this.notifyBelongsToChanged(); } + removeCompletelyFromOwn(internalModel) { + super.removeCompletelyFromOwn(internalModel); + + if (this.canonicalState === internalModel) { + this.canonicalState = null; + } + + if (this.inverseInternalModel === internalModel) { + this.inverseInternalModel = null; + this.notifyBelongsToChanged(); + } + } + flushCanonical() { //temporary fix to not remove newly created records if server returned null. //TODO remove once we have proper diffing diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 89f7e511e68..10cb1e8826a 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -111,6 +111,26 @@ export default class ManyRelationship extends Relationship { super.removeCanonicalInternalModelFromOwn(internalModel, idx); } + removeCompletelyFromOwn(internalModel) { + super.removeCompletelyFromOwn(internalModel); + + const canonicalIndex = this.canonicalState.indexOf(internalModel); + + if (canonicalIndex !== -1) { + this.canonicalState.splice(canonicalIndex, 1); + } + + const manyArray = this._manyArray; + + if (manyArray) { + const idx = manyArray.currentState.indexOf(internalModel); + + if (idx !== -1) { + manyArray.internalReplace(idx, 1); + } + } + } + flushCanonical() { if (this._manyArray) { this._manyArray.flushCanonical(); diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 43cc279a196..4bf194c2567 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -2,6 +2,9 @@ import { assert, warn } from '@ember/debug'; import OrderedSet from '../../ordered-set'; import _normalizeLink from '../../normalize-link'; +import Ember from 'ember'; + +const { guidFor } = Ember; const { addCanonicalInternalModel, @@ -247,7 +250,6 @@ export default class Relationship { removeInternalModelFromOwn(internalModel) { heimdall.increment(removeInternalModelFromOwn); this.members.delete(internalModel); - this.notifyRecordRelationshipRemoved(internalModel); this.internalModel.updateRecordArrays(); } @@ -266,6 +268,48 @@ export default class Relationship { this.flushCanonicalLater(); } + /* + Call this method once a record deletion has been persisted + to purge it from BOTH current and canonical state of all + relationships. + + @method removeCompletelyFromInverse + @private + */ + removeCompletelyFromInverse() { + if (!this.inverseKey) { return; } + + // we actually want a union of members and canonicalMembers + // they should be disjoint but currently are not due to a bug + let seen = Object.create(null); + const internalModel = this.internalModel; + + const unload = inverseInternalModel => { + const id = guidFor(inverseInternalModel); + + if (seen[id] === undefined) { + const relationship = inverseInternalModel._relationships.get(this.inverseKey); + relationship.removeCompletelyFromOwn(internalModel); + seen[id] = true; + } + }; + + this.members.forEach(unload); + this.canonicalMembers.forEach(unload); + } + + /* + Removes the given internalModel from BOTH canonical AND current state. + + This method is useful when either a deletion or a rollback on a new record + needs to entirely purge itself from an inverse relationship. + */ + removeCompletelyFromOwn(internalModel) { + this.canonicalMembers.delete(internalModel); + this.members.delete(internalModel); + this.internalModel.updateRecordArrays(); + } + flushCanonical() { heimdall.increment(flushCanonical); let list = this.members.list; @@ -327,7 +371,6 @@ export default class Relationship { } notifyRecordRelationshipAdded() { } - notifyRecordRelationshipRemoved() { } /* `hasData` for a relationship is a flag to indicate if we consider the diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 9431753f66d..4fe9e40c68e 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -2520,7 +2520,9 @@ test("adding and removing records from hasMany relationship #2666", function(ass return comments.get('lastObject').destroyRecord(); }).then(() => { let comments = post.get('comments'); - assert.equal(comments.get('length'), 3, "Comments count after destroy"); + let length = comments.get('length'); + + assert.equal(length, 3, "Comments count after destroy"); // Add another comment #4 let comment = env.store.createRecord('comment'); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index b9f3d391d5a..4098a067102 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -906,6 +906,559 @@ test('it is possible to add a new item to a relationship', function(assert) { }); }); +test('new items added to a hasMany relationship are not cleared by a delete', function(assert) { + assert.expect(4); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + pets: DS.hasMany('pet', { async: false, inverse: null }) + }); + + const Pet = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person', { async: false, inverse: null }) + }); + + let env = setupStore({ + person: Person, + pet: Pet + }); + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.deleteRecord = () => { + return Ember.RSVP.Promise.resolve({ data: null }); + }; + + let { store } = env; + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn' + }, + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' } + ] + } + } + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shenanigans' + } + }, + { + type: 'pet', + id: '2', + attributes: { + name: 'Rambunctious' + } + }, + { + type: 'pet', + id: '3', + attributes: { + name: 'Rebel' + } + } + ] + }); + }); + + const person = store.peekRecord('person', '1'); + const pets = run(() => person.get('pets')); + + const shen = pets.objectAt(0); + const rambo = store.peekRecord('pet', '2'); + const rebel = store.peekRecord('pet', '3'); + + assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['1'], 'precond - relationship has the correct pets to start'); + + run(() => { + pets.pushObjects([rambo, rebel]); + }); + + assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2', '3'], 'precond2 - relationship now has the correct three pets'); + + run(() => { + return shen.destroyRecord({}) + .then(() => { + shen.unloadRecord(); + }); + }); + + assert.deepEqual(pets.map(p => get(p, 'id')), ['2', '3'], 'relationship now has the correct two pets'); +}); + +test('new items added to an async hasMany relationship are not cleared by a delete', function(assert) { + assert.expect(7); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + pets: DS.hasMany('pet', { async: true, inverse: null }) + }); + + const Pet = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person', { async: false, inverse: null }) + }); + + let env = setupStore({ + person: Person, + pet: Pet + }); + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.deleteRecord = () => { + return Ember.RSVP.Promise.resolve({ data: null }); + }; + + let { store } = env; + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn' + }, + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' } + ] + } + } + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shenanigans' + } + }, + { + type: 'pet', + id: '2', + attributes: { + name: 'Rambunctious' + } + }, + { + type: 'pet', + id: '3', + attributes: { + name: 'Rebel' + } + } + ] + }); + }); + + return run(() => { + const person = store.peekRecord('person', '1'); + const petsProxy = run(() => person.get('pets')); + + return petsProxy.then((pets) => { + const shen = pets.objectAt(0); + const rambo = store.peekRecord('pet', '2'); + const rebel = store.peekRecord('pet', '3'); + + assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['1'], 'precond - relationship has the correct pet to start'); + assert.equal(get(petsProxy, 'length'), 1, 'precond - proxy has only one pet to start'); + + pets.pushObjects([rambo, rebel]); + + assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2', '3'], 'precond2 - relationship now has the correct three pets'); + assert.equal(get(petsProxy, 'length'), 3, 'precond2 - proxy now reflects three pets'); + + return shen.destroyRecord({}) + .then(() => { + shen.unloadRecord(); + + assert.deepEqual(pets.map(p => get(p, 'id')), ['2', '3'], 'relationship now has the correct two pets'); + assert.equal(get(petsProxy, 'length'), 2, 'proxy now reflects two pets'); + }); + }); + }); +}); + +test('new items added to a belongsTo relationship are not cleared by a delete', function(assert) { + assert.expect(4); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + dog: DS.belongsTo('dog', { async: false, inverse: null }) + }); + + const Dog = DS.Model.extend({ + name: DS.attr('string') + }); + + let env = setupStore({ + person: Person, + dog: Dog + }); + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.deleteRecord = () => { + return Ember.RSVP.Promise.resolve({ data: null }); + }; + + let { store } = env; + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn' + }, + relationships: { + dog: { + data: { type: 'dog', id: '1' } + } + } + }, + included: [ + { + type: 'dog', + id: '1', + attributes: { + name: 'Shenanigans' + } + }, + { + type: 'dog', + id: '2', + attributes: { + name: 'Rambunctious' + } + } + ] + }); + }); + + const person = store.peekRecord('person', '1'); + let dog = run(() => person.get('dog')); + const shen = store.peekRecord('dog', '1'); + const rambo = store.peekRecord('dog', '2'); + + assert.ok(dog === shen, 'precond - the belongsTo points to the correct dog'); + assert.equal(get(dog, 'name'), 'Shenanigans', 'precond - relationships work'); + + run(() => { + person.set('dog', rambo); + }); + + dog = person.get('dog'); + assert.equal(dog, rambo, 'precond2 - relationship was updated'); + + return run(() => { + return shen.destroyRecord({}) + .then(() => { + shen.unloadRecord(); + + dog = person.get('dog'); + assert.equal(dog, rambo, 'The currentState of the belongsTo was preserved after the delete'); + }); + }); +}); + +test('new items added to an async belongsTo relationship are not cleared by a delete', function(assert) { + assert.expect(4); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + dog: DS.belongsTo('dog', { async: true, inverse: null }) + }); + + const Dog = DS.Model.extend({ + name: DS.attr('string') + }); + + let env = setupStore({ + person: Person, + dog: Dog + }); + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.deleteRecord = () => { + return Ember.RSVP.Promise.resolve({ data: null }); + }; + + let { store } = env; + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn' + }, + relationships: { + dog: { + data: { type: 'dog', id: '1' } + } + } + }, + included: [ + { + type: 'dog', + id: '1', + attributes: { + name: 'Shenanigans' + } + }, + { + type: 'dog', + id: '2', + attributes: { + name: 'Rambunctious' + } + } + ] + }); + }); + + return run(() => { + const person = store.peekRecord('person', '1'); + const shen = store.peekRecord('dog', '1'); + const rambo = store.peekRecord('dog', '2'); + + return person.get('dog').then((dog) => { + assert.ok(dog === shen, 'precond - the belongsTo points to the correct dog'); + assert.equal(get(dog, 'name'), 'Shenanigans', 'precond - relationships work'); + + person.set('dog', rambo); + + dog = person.get('dog.content'); + + assert.ok(dog === rambo, 'precond2 - relationship was updated'); + + return shen.destroyRecord({}) + .then(() => { + shen.unloadRecord(); + + dog = person.get('dog.content'); + assert.ok(dog === rambo, 'The currentState of the belongsTo was preserved after the delete'); + }); + }); + }); +}); + +test('deleting an item that is the current state of a belongsTo clears currentState', function(assert) { + assert.expect(4); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + dog: DS.belongsTo('dog', { async: false, inverse: null }) + }); + + const Dog = DS.Model.extend({ + name: DS.attr('string') + }); + + let env = setupStore({ + person: Person, + dog: Dog + }); + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.deleteRecord = () => { + return Ember.RSVP.Promise.resolve({ data: null }); + }; + + let { store } = env; + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn' + }, + relationships: { + dog: { + data: { type: 'dog', id: '1' } + } + } + }, + included: [ + { + type: 'dog', + id: '1', + attributes: { + name: 'Shenanigans' + } + }, + { + type: 'dog', + id: '2', + attributes: { + name: 'Rambunctious' + } + } + ] + }); + }); + + const person = store.peekRecord('person', '1'); + let dog = run(() => person.get('dog')); + const shen = store.peekRecord('dog', '1'); + const rambo = store.peekRecord('dog', '2'); + + assert.ok(dog === shen, 'precond - the belongsTo points to the correct dog'); + assert.equal(get(dog, 'name'), 'Shenanigans', 'precond - relationships work'); + + run(() => { + person.set('dog', rambo); + }); + + dog = person.get('dog'); + assert.equal(dog, rambo, 'precond2 - relationship was updated'); + + return run(() => { + return rambo.destroyRecord({}) + .then(() => { + rambo.unloadRecord(); + + dog = person.get('dog'); + assert.equal(dog, null, 'The current state of the belongsTo was clearer'); + }); + }); +}); + +/* + This test, when passing, affirms that a known limitation of ember-data still exists. + + When pushing new data into the store, ember-data is currently incapable of knowing whether + a relationship has been persisted. In order to update relationship state effectively, ember-data + blindly "flushes canonical" state, removing any `currentState` changes. A delete that sideloads + the parent record's hasMany is a situation in which this limitation will be encountered should other + local changes to the relationship still exist. + */ +test('[ASSERTS KNOWN LIMITATION STILL EXISTS] returning new hasMany relationship info from a delete clears local state', function(assert) { + assert.expect(4); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + pets: DS.hasMany('pet', { async: false, inverse: null }) + }); + + const Pet = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person', { async: false, inverse: null }) + }); + + let env = setupStore({ + person: Person, + pet: Pet + }); + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.deleteRecord = () => { + return Ember.RSVP.Promise.resolve({ + data: null, + included: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn' + }, + relationships: { + pets: { + data: [ + { type: 'pet', id: '2' } + ] + } + } + } + ] + }); + }; + + let { store } = env; + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn' + }, + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' }, + { type: 'pet', id: '2' } + ] + } + } + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shenanigans' + } + }, + { + type: 'pet', + id: '2', + attributes: { + name: 'Rambunctious' + } + }, + { + type: 'pet', + id: '3', + attributes: { + name: 'Rebel' + } + } + ] + }); + }); + + const person = store.peekRecord('person', '1'); + const pets = run(() => person.get('pets')); + + const shen = store.peekRecord('pet', '1'); + const rebel = store.peekRecord('pet', '3'); + + assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2'], 'precond - relationship has the correct pets to start'); + + run(() => { + pets.pushObjects([rebel]); + }); + + assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2', '3'], 'precond2 - relationship now has the correct three pets'); + + return run(() => { + return shen.destroyRecord({}) + .then(() => { + shen.unloadRecord(); + + // were ember-data to now preserve local edits during a relationship push, this would be '2' + assert.deepEqual(pets.map(p => get(p, 'id')), ['2'], 'relationship now has only one pet, we lost the local change'); + }); + }); +}); + test('possible to replace items in a relationship using setObjects w/ Ember Enumerable Array/Object as the argument (GH-2533)', function(assert) { assert.expect(2); From ed88e8c3b37a53efc94b75958840843385fa3c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Bryxi=CC=81?= Date: Sat, 15 Jul 2017 14:49:24 +0100 Subject: [PATCH 1989/2527] Update doc for deprecated function. - store#filter() is now deprecated - Don't suggest it's usage --- addon/-private/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 6deb6c86406..9be8b167c6b 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -196,7 +196,7 @@ const { Note: When creating a new record using any of the above methods Ember Data will update `DS.RecordArray`s such as those returned by - `store#peekAll()`, `store#findAll()` or `store#filter()`. This means any + `store#peekAll()` or `store#findAll()`. This means any data bindings or computed properties that depend on the RecordArray will automatically be synced to include the new or updated record values. From a1d08a24bf36df6d1440711235084ef00aa9fd65 Mon Sep 17 00:00:00 2001 From: bekzod Date: Sun, 16 Jul 2017 14:44:16 +0500 Subject: [PATCH 1990/2527] remove `pretender` and some update deps --- package.json | 7 +++---- yarn.lock | 32 +++++++------------------------- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index e2a3e2da0c8..053120dfe0c 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "author": "", "license": "MIT", "dependencies": { - "amd-name-resolver": "0.0.5", + "amd-name-resolver": "0.0.6", "babel-plugin-feature-flags": "^0.3.1", "babel-plugin-filter-imports": "^0.3.1", "babel6-plugin-strip-class-callcheck": "^6.0.0", @@ -29,7 +29,7 @@ "broccoli-debug": "^0.6.2", "broccoli-file-creator": "^1.0.0", "broccoli-funnel": "^1.2.0", - "broccoli-merge-trees": "^1.0.0", + "broccoli-merge-trees": "^2.0.0", "broccoli-rollup": "^1.2.0", "chalk": "^1.1.1", "ember-cli-babel": "^6.4.1", @@ -70,7 +70,7 @@ "broccoli-yuidoc": "^2.1.0", "ember-ajax": "^2.4.1", "ember-cli": "^2.11.1", - "ember-cli-app-version": "^2.0.0", + "ember-cli-app-version": "^3.0.0", "ember-cli-blueprint-test-helpers": "0.11.0", "ember-cli-dependency-checker": "^1.3.0", "ember-cli-eslint": "1.3.0", @@ -104,7 +104,6 @@ "mocha": "2.4.5", "mocha-only-detector": "0.0.2", "morgan": "^1.7.0", - "pretender": "1.0.0", "rimraf": "2.5.2", "rsvp": "3.6.0" }, diff --git a/yarn.lock b/yarn.lock index a0db93b5e2d..a8b3f5a47cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -101,12 +101,6 @@ alter@~0.2.0: dependencies: stable "~0.1.3" -amd-name-resolver@0.0.5: - version "0.0.5" - resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.5.tgz#76962dac876ed3311b05d29c6a58c14e1ef3304b" - dependencies: - ensure-posix-path "^1.0.1" - amd-name-resolver@0.0.6: version "0.0.6" resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.6.tgz#d3e4ba2dfcaab1d820c1be9de947c67828cfe595" @@ -2088,11 +2082,11 @@ ember-ajax@^2.4.1: dependencies: ember-cli-babel "^5.1.5" -ember-cli-app-version@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/ember-cli-app-version/-/ember-cli-app-version-2.0.2.tgz#aaeede608e92fae6c2e11f63d28a373c1cc3f070" +ember-cli-app-version@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-3.0.0.tgz#d67a33aeec7bd03187fbe72c5663dadec4c3368a" dependencies: - ember-cli-babel "^5.1.6" + ember-cli-babel "^6.0.0-beta.7" ember-cli-htmlbars "^1.0.0" git-repo-version "0.4.1" @@ -2943,7 +2937,7 @@ extglob@^0.3.1: dependencies: is-extglob "^1.0.0" -fake-xml-http-request@^1.3.0, fake-xml-http-request@^1.4.0: +fake-xml-http-request@^1.4.0: version "1.5.0" resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-1.5.0.tgz#d79602a97043d4d8fea671d5d904af38847b451d" @@ -4818,13 +4812,6 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -pretender@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/pretender/-/pretender-1.0.0.tgz#9137c38718b4d89814478b7f208f70d3e441a0e9" - dependencies: - fake-xml-http-request "^1.3.0" - route-recognizer "^0.1.9" - pretender@^1.4.2: version "1.4.2" resolved "https://registry.npmjs.org/pretender/-/pretender-1.4.2.tgz#dde9995dfdf75b28a3dd7a73cde2f9f612e5e8f4" @@ -5168,14 +5155,13 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" - -rimraf@2.5.2, rimraf@^2.2.8, rimraf@^2.3.4, rimraf@^2.4.3, rimraf@^2.4.4: +rimraf@2.5.2, rimraf@^2.4.3, rimraf@^2.4.4: version "2.5.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" -rimraf@^2.1.4, rimraf@^2.3.2, rimraf@^2.4.1, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: +rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: version "2.6.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: @@ -5191,10 +5177,6 @@ rollup@^0.41.4: dependencies: source-map-support "^0.4.0" -route-recognizer@^0.1.9: - version "0.1.11" - resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.1.11.tgz#810d8e5702abb4056d6dcb8e865c5685e7c14eb7" - route-recognizer@^0.2.3: version "0.2.10" resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" From a207c6d86d303d69a65afec130aa25bac06e6a53 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 17 Jul 2017 20:46:50 -0700 Subject: [PATCH 1991/2527] disable node-tests in windows for now --- node-tests/nodetest-runner.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/node-tests/nodetest-runner.js b/node-tests/nodetest-runner.js index 1f81b257c96..4f3fb1b12a6 100644 --- a/node-tests/nodetest-runner.js +++ b/node-tests/nodetest-runner.js @@ -1,5 +1,10 @@ 'use strict'; +if (/^win/.test(require('os').platform())){ + // don't run these tests in windows right now, they don't work + process.exit(0); +} + var glob = require('glob'); var Mocha = require('mocha'); var RSVP = require('rsvp'); From 58ab9130607b9c44a2203b7eb5d13a273e5c57f4 Mon Sep 17 00:00:00 2001 From: Garrett Jensen Date: Wed, 19 Jul 2017 15:41:12 -0400 Subject: [PATCH 1992/2527] unpin testem version --- package.json | 2 +- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 053120dfe0c..a869d3acdd9 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "npm-git-info": "^1.0.0", "semver": "^5.1.0", "silent-error": "^1.0.0", - "testem": "1.15.0" + "testem": "^1.15.0" }, "devDependencies": { "babel-plugin-debug-macros": "^0.1.7", diff --git a/yarn.lock b/yarn.lock index a8b3f5a47cc..aebf82223c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5624,7 +5624,7 @@ temp@0.8.3: os-tmpdir "^1.0.0" rimraf "~2.2.6" -testem@1.15.0, testem@^1.15.0: +testem@^1.15.0: version "1.15.0" resolved "https://registry.npmjs.org/testem/-/testem-1.15.0.tgz#2e3a9e7ac29f16a20f718eb0c4b12e7a44900675" dependencies: From 83721a19f7c568f8ddbd4450800d75890267d888 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 20 Jul 2017 17:13:53 -0700 Subject: [PATCH 1993/2527] [BUGFIX release] fix destroyRecord followed by unloadRecord and implicit inverse relationships --- addon/-private/system/model/internal-model.js | 15 +++-- .../relationships/has-many-test.js | 66 ++++++++++++++++++- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 44624909f94..ccc2ee168ef 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -899,8 +899,12 @@ export default class InternalModel { } } }); - Object.keys(this._implicitRelationships).forEach((key) => { - let rel = this._implicitRelationships[key]; + + let implicitRelationships = this._implicitRelationships; + this.__implicitRelationships = null; + + Object.keys(implicitRelationships).forEach((key) => { + let rel = implicitRelationships[key]; rel.removeCompletelyFromInverse(); if (isNew === true) { @@ -920,8 +924,11 @@ export default class InternalModel { rel.removeInverseRelationships(); } }); - Object.keys(this._implicitRelationships).forEach((key) => { - this._implicitRelationships[key].removeInverseRelationships(); + + let implicitRelationships = this._implicitRelationships; + this.__implicitRelationships = null; + Object.keys(implicitRelationships).forEach((key) => { + implicitRelationships[key].removeInverseRelationships(); }); } diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 4fe9e40c68e..6472ddbdada 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -2372,10 +2372,8 @@ test("Relationship.clear removes all records correctly", function(assert) { let comments = Ember.A(env.store.peekAll('comment')); assert.deepEqual(comments.mapBy('post'), [null, null, null]); }); - }); - test('unloading a record with associated records does not prevent the store from tearing down', function(assert) { let post; @@ -3034,6 +3032,70 @@ test("PromiseArray proxies createRecord to its ManyArray before the hasMany is l }); }); +test("deleteRecord + unloadRecord fun", function(assert) { + User.reopen({ + posts: DS.hasMany('posts', { inverse: null }) + }); + + run(() => { + env.store.push({ + data: [ + { + type: 'user', + id: 'user-1', + attributes: { + name: 'Adolfo Builes' + }, + relationships: { + posts: { + data: [ + { type: 'post', id: 'post-1' }, + { type: 'post', id: 'post-2' }, + { type: 'post', id: 'post-3' }, + { type: 'post', id: 'post-4' }, + { type: 'post', id: 'post-5' } + ] + } + } + }, + { type: 'post', id: 'post-1' }, + { type: 'post', id: 'post-2' }, + { type: 'post', id: 'post-3' }, + { type: 'post', id: 'post-4' }, + { type: 'post', id: 'post-5' } + ] + }); + + let user = env.store.peekRecord('user', 'user-1'); + let posts = user.get('posts'); + + env.store.adapterFor('post').deleteRecord = function() { + // just acknowledge all deletes, but with a noop + return { data: null }; + }; + + assert.deepEqual(posts.map(x => x.get('id')), ['post-1', 'post-2', 'post-3', 'post-4', 'post-5']); + + return run(() => { + return env.store.peekRecord('post', 'post-2').destroyRecord().then(record => { + return env.store.unloadRecord(record); + }); + }).then(() => { + assert.deepEqual(posts.map(x => x.get('id')), ['post-1', 'post-3', 'post-4', 'post-5']); + return env.store.peekRecord('post', 'post-3').destroyRecord().then(record => { + return env.store.unloadRecord(record); + }); + }).then(() => { + assert.deepEqual(posts.map(x => x.get('id')), ['post-1', 'post-4', 'post-5']); + return env.store.peekRecord('post', 'post-4').destroyRecord().then(record => { + return env.store.unloadRecord(record); + }); + }).then(() => { + assert.deepEqual(posts.map(x => x.get('id')), ['post-1', 'post-5']); + }); + }); +}); + test("unloading and reloading a record with hasMany relationship - #3084", function(assert) { let user; let message; From d92e45cc38afcc28fd27d3c56cfc2edf7228d6ab Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 21 Jul 2017 15:39:06 +0200 Subject: [PATCH 1994/2527] Convert "babel-plugin-transform-es2015-block-scoping" from dev to prod dep (#5081) (cherry picked from commit 25a10a8339aff55072b4cd2a933496dc11fe6469) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a869d3acdd9..c03413799a4 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "amd-name-resolver": "0.0.6", "babel-plugin-feature-flags": "^0.3.1", "babel-plugin-filter-imports": "^0.3.1", + "babel-plugin-transform-es2015-block-scoping": "^6.24.1", "babel6-plugin-strip-class-callcheck": "^6.0.0", "babel6-plugin-strip-heimdall": "^6.0.1", "broccoli-babel-transpiler": "^6.0.0", @@ -51,7 +52,6 @@ "devDependencies": { "babel-plugin-debug-macros": "^0.1.7", "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.24.1", "babel-plugin-transform-es2015-classes": "^6.23.0", "babel-plugin-transform-es2015-computed-properties": "^6.22.0", "babel-plugin-transform-es2015-constants": "^6.1.4", From c1f4cb5b0b26cb097bdae65ee053dc83493e67fb Mon Sep 17 00:00:00 2001 From: Michael Stewart Date: Mon, 24 Jul 2017 10:30:11 -0700 Subject: [PATCH 1995/2527] Bump `amd-name-resolver` version to enable parallel babel transpile --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c03413799a4..7150226bca7 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "author": "", "license": "MIT", "dependencies": { - "amd-name-resolver": "0.0.6", + "amd-name-resolver": "0.0.7", "babel-plugin-feature-flags": "^0.3.1", "babel-plugin-filter-imports": "^0.3.1", "babel-plugin-transform-es2015-block-scoping": "^6.24.1", From c27883f53d7f1edba3796cbc649de92ed1646963 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Sun, 23 Jul 2017 21:54:18 -0700 Subject: [PATCH 1996/2527] [BUGFIX release] handle dupe relationship entries If a relationship was setup with duplicate entries, it would enter an invalid state. Specifically, this.canonicalMembers and this.canonicalState would be out of sync. Resulting in some sad things. This was most likely introduced by https://github.com/emberjs/data/commit/f8304b23c792a1e74cefb63140e6ee1917cbdfa1#commitcomment-23256408 --- .../system/relationships/state/has-many.js | 18 +++- .../unit/model/relationships/has-many-test.js | 91 ++++++++++++++++--- 2 files changed, 92 insertions(+), 17 deletions(-) diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 10cb1e8826a..d165c979ae0 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -201,17 +201,25 @@ export default class ManyRelationship extends Relationship { } setInitialInternalModels(internalModels) { - if (!internalModels) { + if (Array.isArray(internalModels) === false || internalModels.length === 0) { return; } - let args = [0, this.canonicalState.length].concat(internalModels); - this.canonicalState.splice.apply(this.canonicalState, args); - internalModels.forEach(internalModel => { + let forCanonical = []; + + for (let i = 0; i< internalModels.length; i++) { + let internalModel = internalModels[i]; + if (this.canonicalMembers.has(internalModel)) { + continue; + } + + forCanonical.push(internalModel); this.canonicalMembers.add(internalModel); this.members.add(internalModel); this.setupInverseRelationship(internalModel); - }); + } + + this.canonicalState.splice(0, this.canonicalState.length, ...forCanonical); } fetchLink() { diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 4098a067102..d2672e7a23c 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -399,6 +399,84 @@ test('hasMany with explicit initial null works even when the inverse was set to }); }); +test('hasMany with duplicates from payload', function(assert) { + assert.expect(1); + + const Tag = DS.Model.extend({ + name: DS.attr('string'), + people: DS.hasMany('person', { async: false }) + }); + + Tag.reopenClass({ + toString() { + return 'tag'; + } + }); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: false }) + }); + + Person.reopenClass({ + toString() { + return 'person'; + } + }); + + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + + run(() => { + // first we push in data with the relationship + store.push({ + data: { + type: 'person', + id: 1, + attributes: { + name: 'David J. Hamilton' + }, + relationships: { + tag: { + data: { + type: 'tag', + id: 1 + } + } + } + }, + included: [ + { + type: 'tag', + id: 1, + attributes: { + name: 'whatever' + }, + relationships: { + people: { + data: [ + { + type: 'person', + id: 1 + }, + { + type: 'person', + id: 1 + } + ] + } + } + } + ] + }); + }); + + run(() => { + let tag = store.peekRecord('tag', 1); + assert.equal(tag.get('people.length'), 1, 'relationship does not contain duplicates'); + }); +}); + test('hasMany with explicit null works even when the inverse was set to not null', function(assert) { assert.expect(3); @@ -485,18 +563,7 @@ test('hasMany with explicit null works even when the inverse was set to not null let tag = store.peekRecord('tag', 1); assert.equal(person.get('tag'), null,'relationship is now empty'); - - /* - TODO this should be asserting `0` however - before pushing null, length is actually secretly out-of-sync with - the canonicalState array, which has duplicated the addCanonicalRecord - leading to length `2`, so when we splice out the record we are left - with length 1. - - This is fixed by the relationship cleanup PR which noticed this churn - and removed it: https://github.com/emberjs/data/pull/4882 - */ - assert.equal(tag.get('people.length'), 1, 'relationship is correct'); + assert.equal(tag.get('people.length'), 0, 'relationship is correct'); }); }); From 568b05bda5814cd8898c23818feffe8d199b9eec Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 3 Jul 2017 13:40:03 -0700 Subject: [PATCH 1997/2527] add test for hasMany + addObject + unloadRecord --- .../relationships/has-many-test.js | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 6472ddbdada..05924439bbd 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -216,6 +216,88 @@ test("hasMany + canonical vs currentState + destroyRecord ", function(assert) { assert.equal(contacts, user.get('contacts')); }); +test("hasMany + canonical vs currentState + unloadRecord", function(assert) { + assert.expect(6); + + let postData = { + type: 'user', + id: '1', + attributes: { + name: 'omg' + }, + relationships: { + contacts: { + data: [ + { + type: 'user', + id: 2 + }, + { + type: 'user', + id: 3 + }, + { + type: 'user', + id: 4 + } + ] + } + } + }; + + run(() => { + env.store.push({ + data: postData, + included: [ + { + type: 'user', + id: 2 + }, + { + type: 'user', + id: 3 + }, + { + type: 'user', + id: 4 + } + ] + }); + }); + + let user = env.store.peekRecord('user', 1); + let contacts = user.get('contacts'); + + env.store.adapterFor('user').deleteRecord = function() { + return { data: { type: 'user', id: 2 } }; + }; + + assert.deepEqual(contacts.map(c => c.get('id')), ['2','3','4'], 'user should have expected contacts'); + + run(() => { + contacts.addObject(env.store.createRecord('user', { id: 5 })); + contacts.addObject(env.store.createRecord('user', { id: 6 })); + contacts.addObject(env.store.createRecord('user', { id: 7 })); + }); + + assert.deepEqual(contacts.map(c => c.get('id')), ['2','3','4','5','6','7'], 'user should have expected contacts'); + + run(() => { + env.store.peekRecord('user', 2).unloadRecord(); + env.store.peekRecord('user', 6).unloadRecord(); + }); + + assert.deepEqual(contacts.map(c => c.get('id')), ['2','3','4','5','6','7'], `user's contacts should have expected contacts`); + assert.equal(contacts, user.get('contacts')); + + run(() => { + contacts.addObject(env.store.createRecord('user', { id: 8 })); + }); + + assert.deepEqual(contacts.map(c => c.get('id')), ['2','3','4','5','6','7','8'], `user's contacts should have expected contacts`); + assert.equal(contacts, user.get('contacts')); +}); + test("adapter.findMany only gets unique IDs even if duplicate IDs are present in the hasMany relationship", function(assert) { assert.expect(2); From 658b4020651024b4fb36cc6ef36aad89963175f1 Mon Sep 17 00:00:00 2001 From: Kevin Gao Date: Mon, 15 May 2017 21:33:48 -0700 Subject: [PATCH 1998/2527] Add test for removing and unloading a record from a hasMany relationship --- .../relationships/has-many-test.js | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 05924439bbd..c75749abe5a 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1949,6 +1949,37 @@ testInDebug('A sync hasMany errors out if there are unlaoded records in it', fun }, /You looked up the 'comments' relationship on a 'post' with id 1 but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async \('DS.hasMany\({ async: true }\)'\)/); }); +testInDebug('After removing and unloading a record, a hasMany relationship should still be valid', function(assert) { + const post = run(() => { + env.store.push({ + data: { + type: 'post', + id: '1', + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' } + ] + } + } + }, + included: [ + { type: 'comment', id: '1' } + ] + }); + const post = env.store.peekRecord('post', 1); + const comments = post.get('comments'); + const comment = comments.objectAt(0); + comments.removeObject(comment); + env.store.unloadRecord(comment); + assert.equal(comments.get('length'), 0); + return post; + }); + + // Explicitly re-get comments + assert.equal(run(post, 'get', 'comments.length'), 0); +}); + test("If reordered hasMany data has been pushed to the store, the many array reflects the ordering change - sync", function(assert) { let comment1, comment2, comment3, comment4; let post; From 3f39ac4c2836a16cd0f413cba43d0f1ed99e36cb Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 24 Jul 2017 20:34:57 -0700 Subject: [PATCH 1999/2527] [BUGFIX release] relationship [x, y] should not break on x.unloadRecord() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For an async relationship [x, y] with x.unloadRecord(), now adjusts only the relationship’s currentState, leaving that relationship’s canonical state alone, ensuring the existing client-side delete semantics are preserved. But when that relationship is reloaded, the canonicalState consulted. For sync relationship [x, y] with x.unloadRecord(), both currentState and canonical state are updated. This is to mirror the client-side delete semantics. But since we cannot reload a sync relationship we must assume this to be the new canonical state and rely on subsequent `push` or `adapterPayloads` or manual `store.push` to update. This aims to: * [FIX] hasMany arrays never contain dematerialized records (so they no longer become broken) * [FIX] using unloadRecord as a type of client side delete is restored * [PRESERVE] the garbage collector pass to cleanup orphaned models * [PRESERVE] second access to a relationship which did contain an unloadRecord to cause a reload note: if both sides of a relationships are unloaded, the above doesn’t apply. This is largely just when members of a loaded relationship are themselves unloaded. [fixes #4986 #5052 #4987 #4996] --- addon/-private/system/model/internal-model.js | 48 ++++++---- .../system/relationships/state/create.js | 7 ++ .../system/relationships/state/has-many.js | 14 +++ .../relationships/state/relationship.js | 14 ++- .../integration/records/rematerialize-test.js | 91 +++++++++---------- .../relationships/has-many-test.js | 6 +- tests/integration/store-test.js | 2 +- .../unit/model/relationships/has-many-test.js | 80 ++++++++++++++-- 8 files changed, 183 insertions(+), 79 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index ccc2ee168ef..3f8f8ad3c94 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -431,14 +431,10 @@ export default class InternalModel { */ _directlyRelatedInternalModels() { let array = []; - this.type.eachRelationship((key, relationship) => { - if (this._relationships.has(key)) { - let relationship = this._relationships.get(key); - let localRelationships = relationship.members.toArray(); - let serverRelationships = relationship.canonicalMembers.toArray(); - - array = array.concat(localRelationships, serverRelationships); - } + this._relationships.forEach((name, rel) => { + let local = rel.members.toArray(); + let server = rel.canonicalMembers.toArray(); + array = array.concat(local, server); }); return array; } @@ -492,6 +488,7 @@ export default class InternalModel { unloadRecord() { this.send('unloadRecord'); this.dematerializeRecord(); + if (this._scheduledDestroy === null) { this._scheduledDestroy = run.schedule('destroy', this, '_checkForOrphanedInternalModels'); } @@ -511,6 +508,7 @@ export default class InternalModel { if (this.isDestroyed) { return; } this._cleanupOrphanedInternalModels(); + } _cleanupOrphanedInternalModels() { @@ -533,6 +531,9 @@ export default class InternalModel { assert("Cannot destroy an internalModel while its record is materialized", !this._record || this._record.get('isDestroyed') || this._record.get('isDestroying')); this.store._internalModelDestroyed(this); + + this._relationships.forEach((name, rel) => rel.destroy()); + this._isDestroyed = true; } @@ -889,14 +890,10 @@ export default class InternalModel { @private */ removeFromInverseRelationships(isNew = false) { - this.eachRelationship((name) => { - if (this._relationships.has(name)) { - let rel = this._relationships.get(name); - - rel.removeCompletelyFromInverse(); - if (isNew === true) { - rel.clear(); - } + this._relationships.forEach((name, rel) => { + rel.removeCompletelyFromInverse(); + if (isNew === true) { + rel.clear(); } }); @@ -918,17 +915,28 @@ export default class InternalModel { and destroys any ManyArrays. */ destroyRelationships() { - this.eachRelationship((name, relationship) => { - if (this._relationships.has(name)) { - let rel = this._relationships.get(name); + this._relationships.forEach((name, rel) => { + if (rel._inverseIsAsync()) { + rel.removeInternalModelFromInverse(this); rel.removeInverseRelationships(); + } else { + rel.removeCompletelyFromInverse(); } }); let implicitRelationships = this._implicitRelationships; this.__implicitRelationships = null; Object.keys(implicitRelationships).forEach((key) => { - implicitRelationships[key].removeInverseRelationships(); + let rel = implicitRelationships[key]; + + if (rel._inverseIsAsync()) { + rel.removeInternalModelFromInverse(this); + rel.removeInverseRelationships(); + } else { + rel.removeCompletelyFromInverse(); + } + + rel.destroy(); }); } diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index f0fe88c7cbc..0acc2b86adf 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -46,6 +46,13 @@ export default class Relationships { return !!this.initializedRelationships[key]; } + forEach(cb) { + let rels = this.initializedRelationships; + Object.keys(rels).forEach(name => { + cb(name, rels[name]); + }); + } + get(key) { let relationships = this.initializedRelationships; let relationship = relationships[key]; diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 10cb1e8826a..135c660f3f5 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -281,6 +281,20 @@ export default class ManyRelationship extends Relationship { this.updateInternalModelsFromAdapter(internalModels); } } + + destroy() { + super.destroy(); + let manyArray = this._manyArray; + if (manyArray) { + manyArray.destroy(); + } + + let proxy = this.__loadingPromise; + + if (proxy) { + proxy.destroy(); + } + } } function setForArray(array) { diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 4bf194c2567..8a6893c4f79 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -83,6 +83,13 @@ export default class Relationship { return this.internalModel.modelName; } + _inverseIsAsync() { + if (!this.inverseKey || !this.inverseInternalModel) { + return false; + } + return this.inverseInternalModel._relationships.get(this.inverseKey).isAsync; + } + removeInverseRelationships() { if (!this.inverseKey) { return; } @@ -174,7 +181,7 @@ export default class Relationship { let relationship = relationships[this.inverseKeyForImplicit]; if (!relationship) { relationship = relationships[this.inverseKeyForImplicit] = - new Relationship(this.store, internalModel, this.key, { options: {} }); + new Relationship(this.store, internalModel, this.key, { options: { async: this.isAsync } }); } relationship.addCanonicalInternalModel(this.internalModel); } @@ -215,7 +222,7 @@ export default class Relationship { internalModel._relationships.get(this.inverseKey).addInternalModel(this.internalModel); } else { if (!internalModel._implicitRelationships[this.inverseKeyForImplicit]) { - internalModel._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, internalModel, this.key, { options: {} }); + internalModel._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, internalModel, this.key, { options: { async: this.isAsync } }); } internalModel._implicitRelationships[this.inverseKeyForImplicit].addInternalModel(this.internalModel); } @@ -454,4 +461,7 @@ export default class Relationship { } updateData() {} + + destroy() { + } } diff --git a/tests/integration/records/rematerialize-test.js b/tests/integration/records/rematerialize-test.js index 743db76a36b..b7a71c0be8f 100644 --- a/tests/integration/records/rematerialize-test.js +++ b/tests/integration/records/rematerialize-test.js @@ -146,22 +146,47 @@ test("an async has many relationship to an unloaded record can restore that reco // disable background reloading so we do not re-create the relationship. env.adapter.shouldBackgroundReloadRecord = () => false; - env.adapter.findRecord = function() { - assert.ok('adapter called'); - return Ember.RSVP.Promise.resolve({ - data: { - type: 'boat', - id: '1', - attributes: { - name: "Boaty McBoatface" - }, - relationships: { - person: { - data: { type: 'person', id: '1' } - } - } + const BOAT_ONE = { + type: 'boat', + id: '1', + attributes: { + name: "Boaty McBoatface" + }, + relationships: { + person: { + data: { type: 'person', id: '1' } } - }); + } + }; + + const BOAT_TWO = { + type: 'boat', + id: '2', + attributes: { + name: 'Some other boat' + }, + relationships: { + person: { + data: { type: 'person', id: '1' } + } + } + }; + + env.adapter.findRecord = function(store, model, param) { + assert.ok('adapter called'); + + let data; + if (param === '1') { + data = BOAT_ONE; + } else if (param === '1') { + data = BOAT_TWO; + } else { + throw new Error(`404: no such boat with id=${param}`); + } + + return { + data + }; } run(function() { @@ -186,29 +211,7 @@ test("an async has many relationship to an unloaded record can restore that reco run(function() { env.store.push({ - data: [{ - type: 'boat', - id: '2', - attributes: { - name: 'Some other boat' - }, - relationships: { - person: { - data: { type: 'person', id: '1' } - } - } - }, { - type: 'boat', - id: '1', - attributes: { - name: 'Boaty McBoatface' - }, - relationships: { - person: { - data: { type: 'person', id: '1' } - } - } - }] + data: [BOAT_ONE, BOAT_TWO] }); }); @@ -220,22 +223,16 @@ test("an async has many relationship to an unloaded record can restore that reco assert.equal(env.store.hasRecordForId('boat', 1), true, 'The boat is in the store'); assert.equal(env.store._internalModelsFor('boat').has(1), true, 'The boat internalModel is loaded'); - let boats = run(() => { - return adam.get('boats'); - }); + let boats = run(() => adam.get('boats')); assert.equal(boats.get('length'), 2, 'Before unloading boats.length is correct'); - run(function() { - boaty.unloadRecord(); - }); + run(() => boaty.unloadRecord()); assert.equal(env.store.hasRecordForId('boat', 1), false, 'The boat is unloaded'); assert.equal(env.store._internalModelsFor('boat').has(1), true, 'The boat internalModel is retained'); - let rematerializedBoaty = run(() => { - return rematerializedBoaty = adam.get('boats').objectAt(1); - }); + let rematerializedBoaty = run(() => adam.get('boats')).objectAt(0); assert.equal(adam.get('boats.length'), 2, 'boats.length correct after rematerialization'); assert.equal(rematerializedBoaty.get('id'), '1'); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index c75749abe5a..9ea2db8778d 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -287,14 +287,14 @@ test("hasMany + canonical vs currentState + unloadRecord", function(assert) { env.store.peekRecord('user', 6).unloadRecord(); }); - assert.deepEqual(contacts.map(c => c.get('id')), ['2','3','4','5','6','7'], `user's contacts should have expected contacts`); + assert.deepEqual(contacts.map(c => c.get('id')), ['3','4','5','7'], `user's contacts should have expected contacts`); assert.equal(contacts, user.get('contacts')); run(() => { contacts.addObject(env.store.createRecord('user', { id: 8 })); }); - assert.deepEqual(contacts.map(c => c.get('id')), ['2','3','4','5','6','7','8'], `user's contacts should have expected contacts`); + assert.deepEqual(contacts.map(c => c.get('id')), ['3','4','5','7','8'], `user's contacts should have expected contacts`); assert.equal(contacts, user.get('contacts')); }); @@ -1949,7 +1949,7 @@ testInDebug('A sync hasMany errors out if there are unlaoded records in it', fun }, /You looked up the 'comments' relationship on a 'post' with id 1 but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async \('DS.hasMany\({ async: true }\)'\)/); }); -testInDebug('After removing and unloading a record, a hasMany relationship should still be valid', function(assert) { +test('After removing and unloading a record, a hasMany relationship should still be valid', function(assert) { const post = run(() => { env.store.push({ data: { diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index f3db892465d..03abfe1b4b6 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -201,7 +201,7 @@ test("destroying the store correctly cleans everything up", function(assert) { assert.equal(personWillDestroy.called.length, 1, 'expected person to have recieved willDestroy once'); assert.equal(carWillDestroy.called.length, 1, 'expected car to recieve willDestroy once'); - assert.equal(carsWillDestroy.called.length, 1, 'expected cars to recieve willDestroy once'); + assert.equal(carsWillDestroy.called.length, 1, 'expected person.cars to recieve willDestroy once'); assert.equal(adapterPopulatedPeopleWillDestroy.called.length, 1, 'expected adapterPopulatedPeople to recieve willDestroy once'); assert.equal(filterdPeopleWillDestroy.called.length, 1, 'expected filterdPeople.willDestroy to have been called once'); }); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 4098a067102..405395cf94f 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -1339,6 +1339,71 @@ test('deleting an item that is the current state of a belongsTo clears currentSt }); }); +test('hasMany.firstObject.unloadRecord should not break that hasMany', function(assert) { + const Person = DS.Model.extend({ + cars: DS.hasMany('car', { async: false }), + name: DS.attr() + }); + + Person.reopenClass({ + toString() { + return 'person'; + } + }); + + const Car = DS.Model.extend({ + name: DS.attr() + }); + + Car.reopenClass({ + toString() { + return 'car'; + } + }); + + let env = setupStore({ + person: Person, + car: Car + }); + + run(() => { + env.store.push({ + data: [ + { + type: 'person', + id: 1, + attributes: { + name: 'marvin' + }, + relationships: { + cars: { + data: [ + { type: 'car', id: 1 }, + { type: 'car', id: 2 } + ] + } + } + }, + { type: 'car', id: 1, attributes: { name: 'a' } }, + { type: 'car', id: 2, attributes: { name: 'b' } } + ] + }) + }); + + let person = env.store.peekRecord('person', 1); + let cars = person.get('cars'); + + assert.equal(cars.get('length'), 2); + + run(() => { + cars.get('firstObject').unloadRecord(); + assert.equal(cars.get('length'), 1); // unload now.. + assert.equal(person.get('cars.length'), 1); // unload now.. + }); + + assert.equal(cars.get('length'), 1); // unload now.. + assert.equal(person.get('cars.length'), 1); // unload now.. +}); /* This test, when passing, affirms that a known limitation of ember-data still exists. @@ -1692,16 +1757,19 @@ test('DS.hasMany proxy is destroyed', function(assert) { let { store } = setupStore({ tag: Tag, person: Person }); let tag = run(() => store.createRecord('tag')); - let people = tag.get('people'); + let peopleProxy = tag.get('people'); - return people.then(() => { + return peopleProxy.then(people => { Ember.run(() => { tag.unloadRecord(); - assert.equal(people.get('isDestroying'), true); - assert.equal(people.get('isDestroyed'), false); + assert.equal(people.isDestroying, false, 'people is NOT destroying sync after unloadRecord'); + assert.equal(people.isDestroyed, false, 'people is NOT destroyed sync after unloadRecord'); + assert.equal(peopleProxy.isDestroying, false, 'peopleProxy is destroying sync after unloadRecord'); + assert.equal(peopleProxy.isDestroyed, false, 'peopleProxy is NOT YET destroyed sync after unloadRecord'); }); - assert.equal(people.get('isDestroying'), true); - assert.equal(people.get('isDestroyed'), true); + + assert.equal(peopleProxy.isDestroying, true, 'peopleProxy is destroying after the run post unloadRecord'); + assert.equal(peopleProxy.isDestroyed, true, 'peopleProxy is destroyed after the run post unloadRecord'); }) }); From e19de57845623d11cacb42875c49ea49bc380404 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 27 Jul 2017 12:35:18 -0700 Subject: [PATCH 2000/2527] [BUGFIX release] restore unloadRecord + createRecord MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following should be possible: ```js const record = store.find(‘record’, 1); record.unloadRecord(); store.createRecord(‘record’, 1); ``` before this commit, the `createRecord` would fail, as the `record` would not yet be fully unloaded, and its ID would still be reserved. --- addon/-private/system/model/internal-model.js | 22 +++++++++++++++++++ addon/-private/system/store.js | 14 +++++++++--- tests/unit/store/unload-test.js | 12 ++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index ccc2ee168ef..d6b3c1e1496 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -497,6 +497,10 @@ export default class InternalModel { } } + hasScheduledDestroy() { + return !!this._scheduledDestroy; + } + cancelDestroy() { assert(`You cannot cancel the destruction of an InternalModel once it has already been destroyed`, !this.isDestroyed); @@ -505,6 +509,24 @@ export default class InternalModel { this._scheduledDestroy = null; } + // typically, we prefer to async destroy this lets us batch cleanup work. + // Unfortunately, some scenarios where that is not possible. Such as: + // + // ```js + // const record = store.find(‘record’, 1); + // record.unloadRecord(); + // store.createRecord(‘record’, 1); + // ``` + // + // In those scenarios, we make that model's cleanup work, sync. + // + destroySync() { + if (this._isDematerializing) { + this.cancelDestroy(); + } + this._checkForOrphanedInternalModels(); + } + _checkForOrphanedInternalModels() { this._isDematerializing = false; this._scheduledDestroy = null; diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b4b03db0235..b93e7f5b9aa 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2558,15 +2558,23 @@ Store = Service.extend({ assert(`You can no longer pass a modelClass as the first argument to store._buildInternalModel. Pass modelName instead.`, typeof modelName === 'string'); - let recordMap = this._internalModelsFor(modelName); + let internalModels = this._internalModelsFor(modelName); + let existingInternalModel = internalModels.get(id); - assert(`The id ${id} has already been used with another record for modelClass '${modelName}'.`, !id || !recordMap.get(id)); + if (existingInternalModel && existingInternalModel.hasScheduledDestroy()) { + // unloadRecord is async, if one attempts to unload + then sync create, + // we must ensure the unload is complete before starting the create + existingInternalModel.destroySync(); + existingInternalModel = null; + } + + assert(`The id ${id} has already been used with another record for modelClass '${modelName}'.`, !existingInternalModel); // lookupFactory should really return an object that creates // instances with the injections applied let internalModel = new InternalModel(modelName, id, this, data); - recordMap.add(internalModel, id); + internalModels.add(internalModel, id); return internalModel; }, diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index 94b22b5faed..f0bfe1240a0 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -100,6 +100,18 @@ test('unload a record', function(assert) { }); }); +test('unload followed by create of the same type + id', function(assert) { + let record = run(() => store.createRecord('record', { id: 1 })); + + assert.ok(store.recordForId('record', 1) === record, 'record should exactly equal'); + + return run(() => { + record.unloadRecord(); + let createdRecord = store.createRecord('record', { id: 1 }); + assert.ok(record !== createdRecord, 'newly created record is fresh (and was created)'); + }); +}); + module("DS.Store - unload record with relationships"); test('can commit store after unload record with relationships', function(assert) { From 1514d3125ac8078a31503293d7ca59724ffd43d8 Mon Sep 17 00:00:00 2001 From: Eli Flanagan Date: Fri, 28 Jul 2017 15:48:10 -0400 Subject: [PATCH 2001/2527] fix instructions for build command --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5556eb046aa..3a3e042845c 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ The latest passing build from the "master" branch is available on Similarly, the latest passing build from the "beta" branch can be found on [https://emberjs.com/builds/#/beta](https://emberjs.com/builds/#/beta) -Or build ember-data.js yourself. Clone the repository and run `npm run build:production` +Or build ember-data.js yourself. Clone the repository and run `npm run production` after [setup](#setup). You'll find ember-data.js in the `dist` directory. #### Internet Explorer 8 From c7fca21a3814d5da720eb37ee7debd3b4a0daf2f Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 28 Jul 2017 18:44:48 -0700 Subject: [PATCH 2002/2527] [BUGFIX release] unloadRecord + findRecord + orphaned relationships --- addon/-private/system/model/internal-model.js | 5 + addon/-private/system/store.js | 15 +-- tests/integration/records/unload-test.js | 115 ++++++++++++++---- 3 files changed, 103 insertions(+), 32 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 4b449b1b339..3fbe60771d4 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -522,6 +522,11 @@ export default class InternalModel { this.cancelDestroy(); } this._checkForOrphanedInternalModels(); + if (this.isDestroyed || this.isDestroying) { return; } + + // just in-case we are not one of the orphaned, we should still + // still destroy ourselves + this.destroy(); } _checkForOrphanedInternalModels() { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b93e7f5b9aa..ac30e54c1cc 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1127,15 +1127,16 @@ Store = Service.extend({ let trueId = coerceId(id); let internalModel = this._internalModelsFor(modelName).get(trueId); - if (!internalModel) { - internalModel = this._buildInternalModel(modelName, trueId); + if (internalModel) { + if (internalModel.hasScheduledDestroy()) { + internalModel.destroySync(); + return this._buildInternalModel(modelName, trueId); + } else { + return internalModel; + } } else { - // if we already have an internalModel, we need to ensure any async teardown is cancelled - // since we want it again. - internalModel.cancelDestroy(); + return this._buildInternalModel(modelName, trueId); } - - return internalModel; }, _internalModelDidReceiveRelationshipData(modelName, id, relationshipData) { diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 1b6cc82fc05..c850cccf0fe 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -16,7 +16,8 @@ let env; let Person = DS.Model.extend({ name: attr('string'), cars: hasMany('car', { async: false }), - boats: hasMany('boat', { async: true }) + boats: hasMany('boat', { async: true }), + bike: belongsTo('boat', { async: false, inverse: null }) }); Person.reopenClass({ toString() { return 'Person'; } }); @@ -38,6 +39,11 @@ let Boat = DS.Model.extend({ }); Boat.toString = function() { return 'Boat'; }; +let Bike = DS.Model.extend({ + name: DS.attr() +}); +Bike.toString = function() { return 'Bike'; }; + module("integration/unload - Unloading Records", { beforeEach() { env = setupStore({ @@ -45,7 +51,8 @@ module("integration/unload - Unloading Records", { person: Person, car: Car, group: Group, - boat: Boat + boat: Boat, + bike: Bike }); }, @@ -485,11 +492,10 @@ test("Cancelling destroy leaves the record in the empty state", function(assert) test("after unloading a record, the record can be fetched again immediately", function(assert) { const store = env.store; - let record; // stub findRecord env.adapter.findRecord = () => { - return Ember.RSVP.Promise.resolve({ + return { data: { type: 'person', id: '1', @@ -497,12 +503,12 @@ test("after unloading a record, the record can be fetched again immediately", fu name: 'Adam Sunderland' } } - }); + }; }; // populate initial record - run(function() { - record = store.push({ + let record = run(() => { + return store.push({ data: { type: 'person', id: '1', @@ -537,27 +543,23 @@ test("after unloading a record, the record can be fetched again immediately", fu assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded initially'); // we test that we can sync call unloadRecord followed by findRecord - return run(function() { - assert.equal(record.get('cars.firstObject.make'), 'jeep'); + return run(() => { store.unloadRecord(record); assert.equal(record.isDestroying, true, 'the record is destroying'); assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are unloaded after unloadRecord'); - return store.findRecord('person', '1').then(record => { - assert.equal(record.get('cars.length'), 1); - assert.equal(record._internalModel, internalModel, 'new record, has old internal model'); - assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded after findRecord'); - }) + return store.findRecord('person', '1').then(newRecord => { + assert.equal(internalModel.currentState.stateName, 'root.empty', 'the old internalModel is discarded'); + assert.equal(newRecord._internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded after findRecord'); + }); }); - }); test("after unloading a record, the record can be fetched again immediately (purge relationship)", function(assert) { const store = env.store; - let record; // stub findRecord env.adapter.findRecord = () => { - return Ember.RSVP.Promise.resolve({ + return { data: { type: 'person', id: '1', @@ -568,12 +570,12 @@ test("after unloading a record, the record can be fetched again immediately (pur cars: { data: null } } } - }); + }; }; // populate initial record - run(function() { - record = store.push({ + let record = run(() => { + return store.push({ data: { type: 'person', id: '1', @@ -608,18 +610,81 @@ test("after unloading a record, the record can be fetched again immediately (pur assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded initially'); // we test that we can sync call unloadRecord followed by findRecord - return run(function() { + return run(() => { assert.equal(record.get('cars.firstObject.make'), 'jeep'); store.unloadRecord(record); assert.equal(record.isDestroying, true, 'the record is destroying'); - assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are unloaded after unloadRecord'); + assert.equal(internalModel.currentState.stateName, 'root.empty', 'Expected the previous internal model tobe unloaded'); + return store.findRecord('person', '1').then(record => { assert.equal(record.get('cars.length'), 0); - assert.equal(record._internalModel, internalModel, 'new record, has old internal model'); - assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded after findRecord'); - }) + assert.equal(internalModel.currentState.stateName, 'root.empty', 'Expected the previous internal model to STILL be unloaded'); + assert.equal(record._internalModel.currentState.stateName, 'root.loaded.saved', 'Expected the NEW internal model to be loaded'); + }); + }); +}); + +test("after unloading a record, the record can be fetched again immediately (with relationships)", function(assert) { + const store = env.store; + // stub findRecord + env.adapter.findRecord = () => { + return { + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + } + } + }; + }; + + // populate initial record + let record = run(() => { + return store.push({ + data: { + type: 'person', + id: '1', + relationships: { + bike: { + data: { type: 'bike', id: '1' } + } + } + }, + + included: [ + { + id: '1', + type: 'bike', + attributes: { + name: 'mr bike' + } + } + ] + }); + }); + + const internalModel = record._internalModel; + assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded initially'); + + assert.equal(record.get('bike.name'), 'mr bike'); + + // we test that we can sync call unloadRecord followed by findRecord + let wait = run(() => { + store.unloadRecord(record); + assert.equal(record.isDestroying, true, 'the record is destroying'); + assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); + assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are unloaded after unloadRecord'); + let wait = store.findRecord('person', '1').then(newRecord => { + assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); + assert.ok(newRecord.get('bike') === null, 'the newRecord should NOT have had a bike'); + }); + assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); + return wait; }); + assert.equal(record.isDestroyed, true, 'the record IS destroyed'); + return wait; }); test("after unloading a record, the record can be fetched again soon there after", function(assert) { From 489aae74f945d6030e88ecf53abe209836556261 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 8 Aug 2017 15:10:54 -0600 Subject: [PATCH 2003/2527] [DOC release] Fixes code blocks for api viewer --- addon/-private/system/references/belongs-to.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index e81a5b0a6af..30098086870 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -352,6 +352,7 @@ BelongsToReference.prototype.value = function() { userRef.load().then(function(user) { userRef.value() === user }); + ``` @method load @return {Promise} a promise that resolves with the record in this belongs-to relationship. @@ -398,6 +399,7 @@ BelongsToReference.prototype.load = function() { userRef.reload().then(function(user) { userRef.value() === user }); + ``` @method reload @return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed. From 0f5f95e33802698605197ae5e921270b996665f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Mu=C3=B1oz?= Date: Wed, 9 Aug 2017 19:39:29 -0400 Subject: [PATCH 2004/2527] [BUGFIX release] Don't notify relationships with links during initialization --- .../relationships/state/relationship.js | 7 ++-- addon/-private/system/store.js | 2 +- .../relationships/belongs-to-test.js | 35 +++++++++++++++++++ .../relationships/has-many-test.js | 31 ++++++++++++++++ 4 files changed, 72 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 8a6893c4f79..2d1792d9877 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -346,7 +346,7 @@ export default class Relationship { this.store._updateRelationshipState(this); } - updateLink(link) { + updateLink(link, initial) { heimdall.increment(updateLink); warn(`You pushed a record of type '${this.internalModel.modelName}' with a relationship '${this.key}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, this.isAsync || this.hasData , { id: 'ds.store.push-link-for-sync-relationship' @@ -355,7 +355,10 @@ export default class Relationship { this.link = link; this.linkPromise = null; - this.internalModel.notifyPropertyChange(this.key); + + if (!initial) { + this.internalModel.notifyPropertyChange(this.key); + } } findLink() { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index ac30e54c1cc..1c39f680e80 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2873,7 +2873,7 @@ function setupRelationships(store, internalModel, data, modelNameToInverseMap) { if (relationshipRequiresNotification) { let relationshipData = data.relationships[relationshipName]; - relationships.get(relationshipName).push(relationshipData); + relationships.get(relationshipName).push(relationshipData, false); } // in debug, assert payload validity eagerly diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 33c04cc267e..88fa6b08f0e 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1500,3 +1500,38 @@ testInDebug("A belongsTo relationship warns if malformatted data is pushed into }); }, /expected the data for the book relationship on a to be in a JSON API format/); }); + +test("belongsTo relationship with links doesn't trigger extra change notifications - #4942", function(assert) { + Chapter.reopen({ + book: DS.belongsTo({ async: true }) + }); + + run(() => { + env.store.push({ + data: { + type: 'chapter', + id: '1', + relationships: { + book: { + data: { type: 'book', id: '1' }, + links: { related: '/chapter/1/book' } + } + } + }, + included: [{ type: 'book', id: '1' }] + }); + }); + + let chapter = env.store.peekRecord('chapter', '1'); + let count = 0; + + chapter.addObserver('book', () => { + count++; + }); + + run(() => { + chapter.get('book'); + }); + + assert.equal(count, 0); +}); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 9ea2db8778d..e359df81d27 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -3334,3 +3334,34 @@ test("deleted records should stay deleted", function(assert) { ); }); }); + +test("hasMany relationship with links doesn't trigger extra change notifications - #4942", function(assert) { + run(() => { + env.store.push({ + data: { + type: 'book', + id: '1', + relationships: { + chapters: { + data: [{ type: 'chapter', id: '1' }], + links: { related: '/book/1/chapters' } + } + } + }, + included: [{ type: 'chapter', id: '1' }] + }); + }); + + let book = env.store.peekRecord('book', '1'); + let count = 0; + + book.addObserver('chapters', () => { + count++; + }); + + run(() => { + book.get('chapters'); + }); + + assert.equal(count, 0); +}); From 59bf5cb06d229c4b6e83a28332102162e85140c9 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 1 Aug 2017 10:25:17 -0400 Subject: [PATCH 2005/2527] [BUGFIX beta] Implement `cacheKeyForTree` hook. This hook was added in [ember-cli/rfcs#90](https://github.com/ember-cli/rfcs/blob/master/complete/0090-addon-tree-caching.md), and essentially guarantees that a given tree returned by an addon is considered stable (or not). In the case of Ember Data, we do not have different tree output based on our parent (project or addon). Specifically, this implementation allows both an app _and_ a lazy engine to depend on `ember-data` without duplicating the `ember-data` assets in both the `assets/vendor.js` and `engine-dist//assets/engine-vendor.js`. --- index.js | 6 +++++- package.json | 1 + yarn.lock | 6 ++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index de266d8599d..533c4c1c69b 100644 --- a/index.js +++ b/index.js @@ -10,6 +10,7 @@ const merge = require('broccoli-merge-trees'); const semver = require('semver'); const version = require('./lib/version'); const BroccoliDebug = require('broccoli-debug'); +const calculateCacheKeyForTree = require('calculate-cache-key-for-tree'); // allow toggling of heimdall instrumentation let INSTRUMENT_HEIMDALL = false; @@ -213,6 +214,9 @@ module.exports = { production: app.bowerDirectory + '/ember-data/ember-data.prod.js' }); } + }, + + cacheKeyForTree(treeType) { + return calculateCacheKeyForTree(treeType, this); } }; - diff --git a/package.json b/package.json index 7150226bca7..5d40e736268 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "broccoli-funnel": "^1.2.0", "broccoli-merge-trees": "^2.0.0", "broccoli-rollup": "^1.2.0", + "calculate-cache-key-for-tree": "^1.1.0", "chalk": "^1.1.1", "ember-cli-babel": "^6.4.1", "ember-cli-path-utils": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index aebf82223c6..7a7783e870c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1490,6 +1490,12 @@ calculate-cache-key-for-tree@^1.0.0: dependencies: json-stable-stringify "^1.0.1" +calculate-cache-key-for-tree@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" + dependencies: + json-stable-stringify "^1.0.1" + caller-path@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" From 49a66fe3b10bdddb5b53ff7912b209eecb808e03 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 13 Aug 2017 09:44:47 -0400 Subject: [PATCH 2006/2527] Ensure CI has latest yarn. The bizarre failures on CI are related to the super old Yarn version in use on the Trusty arch (0.17.5), and seem to randomly fail based on which CI image a build runs on (super frustratingly :P ). This updates our Travis config to ensure the latest yarn is installed (and also updates the mechansim we use to get phantom so that it works across both Trusty and Precise images). --- .travis.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index d6beab2f203..eae503cb0af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ --- language: node_js sudo: false +dist: trusty node_js: - "7" @@ -8,14 +9,13 @@ cache: yarn: true before_install: - - "export PATH=$PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64/bin:$PATH" - - "if [ $(phantomjs --version) != '2.1.1' ]; then rm -rf $PWD/travis_phantomjs; mkdir -p $PWD/travis_phantomjs; fi" - - "if [ $(phantomjs --version) != '2.1.1' ]; then wget https://assets.membergetmember.co/software/phantomjs-2.1.1-linux-x86_64.tar.bz2 -O $PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64.tar.bz2; fi" - - "if [ $(phantomjs --version) != '2.1.1' ]; then tar -xvf $PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64.tar.bz2 -C $PWD/travis_phantomjs; fi" - - "phantomjs --version" + - curl -o- -L https://yarnpkg.com/install.sh | bash + - export PATH=$HOME/.yarn/bin:$PATH + - yarn global add phantomjs-prebuilt + - phantomjs --version install: - - yarn + - yarn install --no-lockfile --no-interactive - ./node_modules/.bin/bower install script: From 968cdf56acb1b57e7604b77abcead6f55344a1f1 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 13 Aug 2017 09:54:06 -0400 Subject: [PATCH 2007/2527] Remove Bower dependency and related files. --- .bowerrc | 4 ---- .travis.yml | 1 - appveyor.yml | 2 -- bower.json | 5 ----- package.json | 2 -- 5 files changed, 14 deletions(-) delete mode 100644 .bowerrc delete mode 100644 bower.json diff --git a/.bowerrc b/.bowerrc deleted file mode 100644 index 869443b22d5..00000000000 --- a/.bowerrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "directory": "bower_components", - "interactive": false -} diff --git a/.travis.yml b/.travis.yml index d6beab2f203..cf8981d4851 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,6 @@ before_install: install: - yarn - - ./node_modules/.bin/bower install script: - ./bin/lint-features diff --git a/appveyor.yml b/appveyor.yml index 913d6ace70b..63705cde3e1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,8 +19,6 @@ install: # Typical npm stuff. - md C:\nc - appveyor-retry yarn install - # Workaround https://github.com/npm/npm/wiki/Troubleshooting#upgrading-on-windows - - yarn run bower # Post-install test scripts. test_script: # Output useful info for debugging. diff --git a/bower.json b/bower.json deleted file mode 100644 index c55b4668708..00000000000 --- a/bower.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "ember-data", - "license": "MIT", - "dependencies": {} -} diff --git a/package.json b/package.json index 7150226bca7..dda7942c095 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,6 @@ "node-tests": "node node-tests/nodetest-runner.js", "test:optional-features": "ember test --environment=test-optional-features", "test:production": "ember test --environment=production", - "bower": "bower install", "production": "ember build --environment=production" }, "author": "", @@ -61,7 +60,6 @@ "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", "babel-plugin-transform-es2015-spread": "^6.22.0", "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "bower": "^1.6.5", "broccoli-asset-rev": "^2.4.5", "broccoli-concat": "^3.2.2", "broccoli-stew": "^1.4.2", From 7245c9ee650352ee8b408a833f3c5075e0f636af Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 13 Aug 2017 12:43:07 -0400 Subject: [PATCH 2008/2527] Ensure we are properly testing multiple Ember versions. Prior to this commit (since c2ca068) we were only testing ember-source@2.11. Even though we had a `config/ember-try.js` with many scenarios, none of them properly removed the `ember-source` version (even though ba7f46221 was specifically trying to do this :sob:). The fundamental issue here is: * `ember-try` supports removing packages, but requires that you specify them in the `dependencies` or `devDependencies` objects. Since my changes in ba7f46221 added `"ember-source": null` to the root of the `npm` config it was completely ignored :disappointed:. * `ember-source` emits a warning to the console when it is present **and** the bower package for `ember` is in use. Unfortunately, this warning is a bit misleading (it doesn't tell you that the `ember-source` from `npm` will always win). The `ember-source` addon should be updated to throw an error when this misconfiguration is detected. * `ember-cli` will **always** use `ember-source` if it is present, and completely ignore whatever is in `bower.json`. IMHO, this default was not correct and `ember-cli` should have done the same thing that `ember-data` did during its migration from bower to `npm`: if both packages are present default to `bower.json` version with a warning. --- config/ember-try.js | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/config/ember-try.js b/config/ember-try.js index ac28bfc3075..08aa1b9a0d0 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -3,9 +3,8 @@ module.exports = { scenarios: [ { name: 'default', - bower: { - dependencies: { } - } + bower: { }, + npm: { } }, { name: 'ember-1-13', @@ -18,7 +17,9 @@ module.exports = { } }, npm: { - 'ember-source': null + devDependencies: { + 'ember-source': null + } } }, { @@ -32,7 +33,9 @@ module.exports = { } }, npm: { - 'ember-source': null + devDependencies: { + 'ember-source': null + } } }, { @@ -46,7 +49,9 @@ module.exports = { } }, npm: { - 'ember-source': null + devDependencies: { + 'ember-source': null + } } }, { @@ -60,7 +65,9 @@ module.exports = { } }, npm: { - 'ember-source': null + devDependencies: { + 'ember-source': null + } } }, { @@ -74,7 +81,9 @@ module.exports = { } }, npm: { - 'ember-source': null + devDependencies: { + 'ember-source': null + } } }, { @@ -88,7 +97,9 @@ module.exports = { } }, npm: { - 'ember-source': null + devDependencies: { + 'ember-source': null + } } }, { @@ -102,7 +113,9 @@ module.exports = { } }, npm: { - 'ember-source': null + devDependencies: { + 'ember-source': null + } } } ] From d5ca408ba5c43114b18485d55d7498dc50190157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20K=C3=A4ufl?= Date: Mon, 14 Aug 2017 15:51:00 +0200 Subject: [PATCH 2009/2527] [BUGFIX release] Failing test for #5125 and attempted fix --- addon/-private/system/store.js | 29 ++++++++++++++++-------- tests/integration/records/unload-test.js | 28 +++++++++++++++++++++++ 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 1c39f680e80..b7b53774bc6 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1979,6 +1979,11 @@ Store = Service.extend({ return; } + let existingInternalModel = this._existingInternalModelForId(modelName, id); + + assert(`'${modelName}' was saved to the server, but the response returned the new id '${id}', which has already been used with another record.'`, + isNone(existingInternalModel) || existingInternalModel === internalModel); + this._internalModelsFor(internalModel.modelName).set(id, internalModel); internalModel.setId(id); @@ -2559,15 +2564,7 @@ Store = Service.extend({ assert(`You can no longer pass a modelClass as the first argument to store._buildInternalModel. Pass modelName instead.`, typeof modelName === 'string'); - let internalModels = this._internalModelsFor(modelName); - let existingInternalModel = internalModels.get(id); - - if (existingInternalModel && existingInternalModel.hasScheduledDestroy()) { - // unloadRecord is async, if one attempts to unload + then sync create, - // we must ensure the unload is complete before starting the create - existingInternalModel.destroySync(); - existingInternalModel = null; - } + let existingInternalModel = this._existingInternalModelForId(modelName, id); assert(`The id ${id} has already been used with another record for modelClass '${modelName}'.`, !existingInternalModel); @@ -2575,11 +2572,23 @@ Store = Service.extend({ // instances with the injections applied let internalModel = new InternalModel(modelName, id, this, data); - internalModels.add(internalModel, id); + this._internalModelsFor(modelName).add(internalModel, id); return internalModel; }, + _existingInternalModelForId(modelName, id) { + let internalModel = this._internalModelsFor(modelName).get(id); + + if (internalModel && internalModel.hasScheduledDestroy()) { + // unloadRecord is async, if one attempts to unload + then sync create, + // we must ensure the unload is complete before starting the create + internalModel.destroySync(); + internalModel = null; + } + return internalModel; + }, + buildInternalModel(modelName, id, data) { deprecate('buildInternalModel was documented as private and will be removed in the next version of Ember Data.', false, { id: 'ember-data.buildInternalModel', until: '2.17.0' }); return this._buildInternalModel(modelName, id, data); diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index c850cccf0fe..117d9bb994f 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -735,3 +735,31 @@ test("after unloading a record, the record can be fetched again soon there after assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded after findRecord'); }); + +test('after unloading a record, the record can be saved again immediately', function (assert) { + assert.expect(0); + + const store = env.store; + const data = { + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + } + } + }; + + env.adapter.createRecord = () => Ember.RSVP.Promise.resolve(data); + + run(() => { + // add an initial record with id '1' to the store + store.push(data); + + // unload the initial record + store.peekRecord('person', '1').unloadRecord(); + + // create a new record that will again get id '1' from the backend + store.createRecord('person').save(); + }); +}); From a8127473431de89a231c301d2d07940ce723666e Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 15 Aug 2017 11:05:12 -0700 Subject: [PATCH 2010/2527] Merge pull request #5128 from emberjs/pr-5127 Avoid MODEL_FACTORY_INJECTION deprecations in tests on Ember >= 2.14. --- .bowerrc | 4 ---- .travis.yml | 13 ++++++------- appveyor.yml | 2 -- bower.json | 5 ----- index.js | 6 +++++- package.json | 3 +-- tests/dummy/app/app.js | 6 +----- tests/helpers/model-factory-injection.js | 14 ++++++++++++++ tests/integration/injection-test.js | 9 ++++++--- .../integration/relationships/belongs-to-test.js | 2 -- tests/integration/relationships/has-many-test.js | 9 ++++++--- .../polymorphic-mixins-belongs-to-test.js | 15 +++++++++------ .../polymorphic-mixins-has-many-test.js | 16 +++++++++------- yarn.lock | 6 ++++++ 14 files changed, 63 insertions(+), 47 deletions(-) delete mode 100644 .bowerrc delete mode 100644 bower.json create mode 100644 tests/helpers/model-factory-injection.js diff --git a/.bowerrc b/.bowerrc deleted file mode 100644 index 869443b22d5..00000000000 --- a/.bowerrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "directory": "bower_components", - "interactive": false -} diff --git a/.travis.yml b/.travis.yml index d6beab2f203..1ddf26fbbf4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ --- language: node_js sudo: false +dist: trusty node_js: - "7" @@ -8,15 +9,13 @@ cache: yarn: true before_install: - - "export PATH=$PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64/bin:$PATH" - - "if [ $(phantomjs --version) != '2.1.1' ]; then rm -rf $PWD/travis_phantomjs; mkdir -p $PWD/travis_phantomjs; fi" - - "if [ $(phantomjs --version) != '2.1.1' ]; then wget https://assets.membergetmember.co/software/phantomjs-2.1.1-linux-x86_64.tar.bz2 -O $PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64.tar.bz2; fi" - - "if [ $(phantomjs --version) != '2.1.1' ]; then tar -xvf $PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64.tar.bz2 -C $PWD/travis_phantomjs; fi" - - "phantomjs --version" + - curl -o- -L https://yarnpkg.com/install.sh | bash + - export PATH=$HOME/.yarn/bin:$PATH + - yarn global add phantomjs-prebuilt + - phantomjs --version install: - - yarn - - ./node_modules/.bin/bower install + - yarn install --no-lockfile --no-interactive script: - ./bin/lint-features diff --git a/appveyor.yml b/appveyor.yml index 913d6ace70b..63705cde3e1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,8 +19,6 @@ install: # Typical npm stuff. - md C:\nc - appveyor-retry yarn install - # Workaround https://github.com/npm/npm/wiki/Troubleshooting#upgrading-on-windows - - yarn run bower # Post-install test scripts. test_script: # Output useful info for debugging. diff --git a/bower.json b/bower.json deleted file mode 100644 index c55b4668708..00000000000 --- a/bower.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "ember-data", - "license": "MIT", - "dependencies": {} -} diff --git a/index.js b/index.js index de266d8599d..533c4c1c69b 100644 --- a/index.js +++ b/index.js @@ -10,6 +10,7 @@ const merge = require('broccoli-merge-trees'); const semver = require('semver'); const version = require('./lib/version'); const BroccoliDebug = require('broccoli-debug'); +const calculateCacheKeyForTree = require('calculate-cache-key-for-tree'); // allow toggling of heimdall instrumentation let INSTRUMENT_HEIMDALL = false; @@ -213,6 +214,9 @@ module.exports = { production: app.bowerDirectory + '/ember-data/ember-data.prod.js' }); } + }, + + cacheKeyForTree(treeType) { + return calculateCacheKeyForTree(treeType, this); } }; - diff --git a/package.json b/package.json index 7150226bca7..e5ae5e843e0 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,6 @@ "node-tests": "node node-tests/nodetest-runner.js", "test:optional-features": "ember test --environment=test-optional-features", "test:production": "ember test --environment=production", - "bower": "bower install", "production": "ember build --environment=production" }, "author": "", @@ -32,6 +31,7 @@ "broccoli-funnel": "^1.2.0", "broccoli-merge-trees": "^2.0.0", "broccoli-rollup": "^1.2.0", + "calculate-cache-key-for-tree": "^1.1.0", "chalk": "^1.1.1", "ember-cli-babel": "^6.4.1", "ember-cli-path-utils": "^1.0.0", @@ -61,7 +61,6 @@ "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", "babel-plugin-transform-es2015-spread": "^6.22.0", "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "bower": "^1.6.5", "broccoli-asset-rev": "^2.4.5", "broccoli-concat": "^3.2.2", "broccoli-stew": "^1.4.2", diff --git a/tests/dummy/app/app.js b/tests/dummy/app/app.js index 831ad6106dd..c15f9359323 100644 --- a/tests/dummy/app/app.js +++ b/tests/dummy/app/app.js @@ -3,11 +3,7 @@ import Resolver from './resolver'; import loadInitializers from 'ember-load-initializers'; import config from './config/environment'; -let App; - -Ember.MODEL_FACTORY_INJECTIONS = true; - -App = Ember.Application.extend({ +const App = Ember.Application.extend({ modulePrefix: config.modulePrefix, podModulePrefix: config.podModulePrefix, Resolver diff --git a/tests/helpers/model-factory-injection.js b/tests/helpers/model-factory-injection.js new file mode 100644 index 00000000000..aad65f95ade --- /dev/null +++ b/tests/helpers/model-factory-injection.js @@ -0,0 +1,14 @@ +import Ember from 'ember'; +import hasEmberVersion from 'ember-test-helpers/has-ember-version'; + +let ORIGINAL_MODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS; + +export function setup(value = true) { + if (!hasEmberVersion(2, 14)) { + Ember.MODEL_FACTORY_INJECTIONS = value; + } +} + +export function reset() { + setup(ORIGINAL_MODEL_FACTORY_INJECTIONS); +} diff --git a/tests/integration/injection-test.js b/tests/integration/injection-test.js index c24c4bdacbe..dfbc603ff05 100644 --- a/tests/integration/injection-test.js +++ b/tests/integration/injection-test.js @@ -1,10 +1,13 @@ +import { + setup as setupModelFactoryInjections, + reset as resetModelFactoryInjections +} from 'dummy/tests/helpers/model-factory-injection'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import DS from 'ember-data'; import { module, test } from 'qunit'; let env, hasFactoryFor, originalLookupFactory, originalOwnerLookupFactory, originalFactoryFor; -let originalMODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS; const { run } = Ember; const model = { @@ -79,7 +82,7 @@ test('modelFor', function(assert) { module('integration/injection eager injections', { setup() { - Ember.MODEL_FACTORY_INJECTIONS = true; + setupModelFactoryInjections(); env = setupStore(); env.registry.injection('model:foo', 'apple', 'service:apple'); @@ -90,7 +93,7 @@ module('integration/injection eager injections', { teardown() { // can be removed once we no longer support ember versions without lookupFactory - Ember.MODEL_FACTORY_INJECTIONS = originalMODEL_FACTORY_INJECTIONS; + resetModelFactoryInjections(); run(env.store, 'destroy'); } diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 88fa6b08f0e..9eb75ce1f09 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -11,7 +11,6 @@ const { attr, hasMany, belongsTo } = DS; const { hash } = RSVP; let env, store, User, Message, Post, Comment, Book, Chapter, Author, NewMessage; -const injectionValue = Ember.MODEL_FACTORY_INJECTIONS; module("integration/relationship/belongs_to Belongs-To Relationships", { beforeEach() { @@ -83,7 +82,6 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { }, afterEach() { - Ember.MODEL_FACTORY_INJECTIONS = injectionValue; run(env.container, 'destroy'); } }); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index e359df81d27..0db8908dd08 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1,5 +1,9 @@ /*eslint no-unused-vars: ["error", { "args": "none", "varsIgnorePattern": "(page)" }]*/ +import { + setup as setupModelFactoryInjections, + reset as resetModelFactoryInjections +} from 'dummy/tests/helpers/model-factory-injection'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; @@ -1338,8 +1342,7 @@ test("When a polymorphic hasMany relationship is accessed, the store can call mu test("polymorphic hasMany type-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled", function(assert) { assert.expect(1); - let injectionValue = Ember.MODEL_FACTORY_INJECTIONS; - Ember.MODEL_FACTORY_INJECTIONS = true; + setupModelFactoryInjections(); try { run(function () { @@ -1351,7 +1354,7 @@ test("polymorphic hasMany type-checks check the superclass when MODEL_FACTORY_IN assert.equal(igor.get('messages.firstObject.body'), "Well I thought the title was fine"); }); } finally { - Ember.MODEL_FACTORY_INJECTIONS = injectionValue; + resetModelFactoryInjections(); } }); diff --git a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index 9439b60d168..f62f41e22d1 100644 --- a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -1,3 +1,8 @@ +import { + setup as setupModelFactoryInjections, + reset as resetModelFactoryInjections +} from 'dummy/tests/helpers/model-factory-injection'; + import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; @@ -155,8 +160,7 @@ testInDebug("Setting the polymorphic belongsTo with an object that does not impl test("Setting the polymorphic belongsTo gets propagated to the inverse side - model injections true", function(assert) { assert.expect(2); - var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; - Ember.MODEL_FACTORY_INJECTIONS = true; + setupModelFactoryInjections(); try { var user, video; @@ -190,13 +194,12 @@ test("Setting the polymorphic belongsTo gets propagated to the inverse side - mo }); }); } finally { - Ember.MODEL_FACTORY_INJECTIONS = injectionValue; + resetModelFactoryInjections(); } }); testInDebug("Setting the polymorphic belongsTo with an object that does not implement the mixin errors out - model injections true", function(assert) { - var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; - Ember.MODEL_FACTORY_INJECTIONS = true; + setupModelFactoryInjections(); try { var user, video; @@ -226,6 +229,6 @@ testInDebug("Setting the polymorphic belongsTo with an object that does not impl }, /You cannot add a record of modelClass 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); }); } finally { - Ember.MODEL_FACTORY_INJECTIONS = injectionValue; + resetModelFactoryInjections(); } }); diff --git a/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js index 9141b088522..8993ad3f8c4 100644 --- a/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -1,3 +1,8 @@ +import { + setup as setupModelFactoryInjections, + reset as resetModelFactoryInjections +} from 'dummy/tests/helpers/model-factory-injection'; + import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; @@ -170,8 +175,7 @@ testInDebug("Pushing a an object that does not implement the mixin to the mixin }); test("Pushing to the hasMany reflects the change on the belongsTo side - model injections true", function(assert) { - var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; - Ember.MODEL_FACTORY_INJECTIONS = true; + setupModelFactoryInjections(); try { var user, video; @@ -209,7 +213,7 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - model i }); }); } finally { - Ember.MODEL_FACTORY_INJECTIONS = injectionValue; + resetModelFactoryInjections(); } }); @@ -217,8 +221,7 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - model i Local edits */ testInDebug("Pushing a an object that does not implement the mixin to the mixin accepting array errors out - model injections true", function(assert) { - var injectionValue = Ember.MODEL_FACTORY_INJECTIONS; - Ember.MODEL_FACTORY_INJECTIONS = true; + setupModelFactoryInjections(); try { var user,notMessage; @@ -255,7 +258,6 @@ testInDebug("Pushing a an object that does not implement the mixin to the mixin }); }); } finally { - Ember.MODEL_FACTORY_INJECTIONS = injectionValue; + resetModelFactoryInjections(); } }); - diff --git a/yarn.lock b/yarn.lock index aebf82223c6..7a7783e870c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1490,6 +1490,12 @@ calculate-cache-key-for-tree@^1.0.0: dependencies: json-stable-stringify "^1.0.1" +calculate-cache-key-for-tree@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" + dependencies: + json-stable-stringify "^1.0.1" + caller-path@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" From 1fd5397a9bb7a5fcf66c2ff2b59aae057d4f4b03 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 15 Aug 2017 15:48:43 -0700 Subject: [PATCH 2011/2527] Ensure we cleanup change event observer --- .../records/relationship-changes-test.js | 175 +++++++++--------- 1 file changed, 84 insertions(+), 91 deletions(-) diff --git a/tests/integration/records/relationship-changes-test.js b/tests/integration/records/relationship-changes-test.js index c0cdd002795..bcba2658048 100644 --- a/tests/integration/records/relationship-changes-test.js +++ b/tests/integration/records/relationship-changes-test.js @@ -513,10 +513,25 @@ test('Calling push with relationship does not trigger observers if the relations }); test('Calling push with relationship triggers willChange and didChange with detail when appending', function(assert) { - let person = null; let willChangeCount = 0; let didChangeCount = 0; + let observer = { + arrayWillChange(array, start, removing, adding) { + willChangeCount++; + assert.equal(start, 1, 'willChange.start'); + assert.equal(removing, 0, 'willChange.removing'); + assert.equal(adding, 1, 'willChange.adding'); + }, + + arrayDidChange(array, start, removed, added) { + didChangeCount++; + assert.equal(start, 1, 'didChange.start'); + assert.equal(removed, 0, 'didChange.removed'); + assert.equal(added, 1, 'didChange.added'); + } + }; + run(() => { store.push({ data: { @@ -537,26 +552,13 @@ test('Calling push with relationship triggers willChange and didChange with deta ] }); - person = store.peekRecord('person', 'wat'); + }); - this.arrayWillChange = (array, start, removing, adding) => { - willChangeCount++; - assert.equal(start, 1); - assert.equal(removing, 0); - assert.equal(adding, 1); - }; - this.arrayDidChange = (array, start, removed, added) => { - didChangeCount++; - assert.equal(start, 1); - assert.equal(removed, 0); - assert.equal(added, 1); - }; - person.get('siblings') - .then(siblings => { - siblings.addArrayObserver(this); - }); - }); + let person = store.peekRecord('person', 'wat'); + let siblings = run(() => person.get('siblings')); + + siblings.addArrayObserver(observer); run(() => { store.push({ @@ -577,14 +579,13 @@ test('Calling push with relationship triggers willChange and didChange with deta }); }); - run(() => { - assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); - assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); - }); + assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); + assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); + + siblings.removeArrayObserver(observer); }); test('Calling push with relationship triggers willChange and didChange with detail when truncating', function(assert) { - let person = null; let willChangeCount = 0; let didChangeCount = 0; @@ -606,29 +607,29 @@ test('Calling push with relationship triggers willChange and didChange with deta included: [ sibling1, sibling2 ] - }); - person = store.peekRecord('person', 'wat'); + }); + + let person = store.peekRecord('person', 'wat'); + let siblings = run(() => person.get('siblings')); - this.arrayWillChange = (array, start, removing, adding) => { + let observer = { + arrayWillChange(array, start, removing, adding) { willChangeCount++; assert.equal(start, 1); assert.equal(removing, 1); assert.equal(adding, 0); - }; - this.arrayDidChange = (array, start, removed, added) => { + }, + + arrayDidChange(array, start, removed, added) { didChangeCount++; assert.equal(start, 1); assert.equal(removed, 1); assert.equal(added, 0); - }; - - person.get('siblings') - .then(siblings => { - siblings.addArrayObserver(this); - }); + } + }; - }); + siblings.addArrayObserver(observer); run(() => { store.push({ @@ -647,14 +648,13 @@ test('Calling push with relationship triggers willChange and didChange with deta }); }); - run(() => { - assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); - assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); - }); + assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); + assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); + + siblings.removeArrayObserver(observer); }); test('Calling push with relationship triggers willChange and didChange with detail when inserting at front', function(assert) { - let person = null; let willChangeCount = 0; let didChangeCount = 0; @@ -676,29 +676,28 @@ test('Calling push with relationship triggers willChange and didChange with deta included: [ sibling2 ] - }); - person = store.peekRecord('person', 'wat'); + }); + let person = store.peekRecord('person', 'wat'); - this.arrayWillChange = (array, start, removing, adding) => { + let observer = { + arrayWillChange(array, start, removing, adding) { willChangeCount++; assert.equal(start, 0); assert.equal(removing, 0); assert.equal(adding, 1); - }; - this.arrayDidChange = (array, start, removed, added) => { + }, + + arrayDidChange(array, start, removed, added) { didChangeCount++; assert.equal(start, 0); assert.equal(removed, 0); assert.equal(added, 1); - }; - - person.get('siblings') - .then(siblings => { - siblings.addArrayObserver(this); - }); + } + }; - }); + let siblings = run(() => person.get('siblings')); + siblings.addArrayObserver(observer); run(() => { store.push({ @@ -719,14 +718,13 @@ test('Calling push with relationship triggers willChange and didChange with deta }); }); - run(() => { - assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); - assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); - }); + assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); + assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); + + siblings.removeArrayObserver(observer); }); test('Calling push with relationship triggers willChange and didChange with detail when inserting in middle', function(assert) { - let person = null; let willChangeCount = 0; let didChangeCount = 0; @@ -751,27 +749,25 @@ test('Calling push with relationship triggers willChange and didChange with deta ] }); - person = store.peekRecord('person', 'wat'); - - this.arrayWillChange = (array, start, removing, adding) => { + }); + let person = store.peekRecord('person', 'wat'); + let observer = { + arrayWillChange(array, start, removing, adding) { willChangeCount++; assert.equal(start, 1); assert.equal(removing, 0); assert.equal(adding, 1); - }; - this.arrayDidChange = (array, start, removed, added) => { + }, + arrayDidChange(array, start, removed, added) { didChangeCount++; assert.equal(start, 1); assert.equal(removed, 0); assert.equal(added, 1); - }; + } + }; - person.get('siblings') - .then(siblings => { - siblings.addArrayObserver(this); - }); - - }); + let siblings = run(() => person.get('siblings')); + siblings.addArrayObserver(observer); run(() => { store.push({ @@ -792,14 +788,13 @@ test('Calling push with relationship triggers willChange and didChange with deta }); }); - run(() => { - assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); - assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); - }); + assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); + assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); + + siblings.removeArrayObserver(observer); }); test('Calling push with relationship triggers willChange and didChange with detail when replacing different length in middle', function(assert) { - let person = null; let willChangeCount = 0; let didChangeCount = 0; @@ -823,30 +818,28 @@ test('Calling push with relationship triggers willChange and didChange with deta sibling2, sibling3 ] - }); - person = store.peekRecord('person', 'wat'); + }); - this.arrayWillChange = (array, start, removing, adding) => { + let person = store.peekRecord('person', 'wat'); + let observer = { + arrayWillChange(array, start, removing, adding) { willChangeCount++; assert.equal(start, 1); assert.equal(removing, 1); assert.equal(adding, 2); - }; + }, - this.arrayDidChange = (array, start, removed, added) => { + arrayDidChange(array, start, removed, added) { didChangeCount++; assert.equal(start, 1); assert.equal(removed, 1); assert.equal(added, 2); - }; - - person.get('siblings') - .then(siblings => { - siblings.addArrayObserver(this); - }); + } + }; - }); + let siblings = run(() => person.get('siblings')); + siblings.addArrayObserver(observer); run(() => { store.push({ @@ -868,10 +861,10 @@ test('Calling push with relationship triggers willChange and didChange with deta }); }); - run(() => { - assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); - assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); - }); + assert.equal(willChangeCount, 1, 'willChange observer should be triggered once'); + assert.equal(didChangeCount, 1, 'didChange observer should be triggered once'); + + siblings.removeArrayObserver(observer); }); test('Calling push with updated belongsTo relationship trigger observer', function(assert) { From 9ddb1bc22bd0c2d0a97ef890ebb9beac1e4bc50a Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 15 Aug 2017 22:31:54 -0700 Subject: [PATCH 2012/2527] =?UTF-8?q?Fix=201.13.x=20(schedule=20doesn?= =?UTF-8?q?=E2=80=99t=20return=20yet)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addon/-private/system/model/internal-model.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 3fbe60771d4..f8f1f498c9f 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -490,7 +490,11 @@ export default class InternalModel { this.dematerializeRecord(); if (this._scheduledDestroy === null) { - this._scheduledDestroy = run.schedule('destroy', this, '_checkForOrphanedInternalModels'); + // TODO: use run.schedule once we drop 1.13 + if (!Ember.run.currentRunLoop) { + assert('You have turned on testing mode, which disabled the run-loop\'s autorun.\n You will need to wrap any code with asynchronous side-effects in a run', Ember.testing); + } + this._scheduledDestroy = Ember.run.backburner.schedule('destroy', this, '_checkForOrphanedInternalModels') } } From 4abc02ccb6517bbf4214e59430be784454e215d7 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 15 Aug 2017 22:32:19 -0700 Subject: [PATCH 2013/2527] fix 1.13.x, PromisemManyArray requires .create --- addon/-private/system/relationships/state/has-many.js | 2 +- tests/unit/promise-proxies-test.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 63a27484034..5bea9d4ad02 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -23,7 +23,7 @@ export default class ManyRelationship extends Relationship { } this.__loadingPromise.set('promise', promise) } else { - this.__loadingPromise = new PromiseManyArray({ + this.__loadingPromise = PromiseManyArray.create({ promise, content }); diff --git a/tests/unit/promise-proxies-test.js b/tests/unit/promise-proxies-test.js index 79d103e882e..93a94a76ab2 100644 --- a/tests/unit/promise-proxies-test.js +++ b/tests/unit/promise-proxies-test.js @@ -13,7 +13,7 @@ test('.reload should NOT leak the internal promise, rather return another promis content.reload = () => Ember.RSVP.Promise.resolve(content); - let array = new DS.PromiseManyArray({ + let array = DS.PromiseManyArray.create({ content }); @@ -32,7 +32,7 @@ test('.reload should be stable', function(assert) { content.reload = () => Ember.RSVP.Promise.resolve(content); let promise = Ember.RSVP.Promise.resolve(content); - let array = new DS.PromiseManyArray({ + let array = DS.PromiseManyArray.create({ promise }); @@ -75,7 +75,7 @@ test('.set to new promise should be like reload', function(assert) { let promise = Ember.RSVP.Promise.resolve(content); - let array = new DS.PromiseManyArray({ + let array = DS.PromiseManyArray.create({ promise }); From d67158e165ea45d983a7fc051917f89cdf756ee6 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 16 Aug 2017 09:42:28 -0700 Subject: [PATCH 2014/2527] fix model-factory-injection helper --- tests/helpers/model-factory-injection.js | 10 ++++++++-- tests/integration/relationships/belongs-to-test.js | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/helpers/model-factory-injection.js b/tests/helpers/model-factory-injection.js index aad65f95ade..1a364a43163 100644 --- a/tests/helpers/model-factory-injection.js +++ b/tests/helpers/model-factory-injection.js @@ -1,9 +1,15 @@ import Ember from 'ember'; import hasEmberVersion from 'ember-test-helpers/has-ember-version'; -let ORIGINAL_MODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS; +const ORIGINAL_MODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS; + +export function setup(value) { + if (arguments.length > 0) { + value = arguments[0]; + } else { + value = true; + } -export function setup(value = true) { if (!hasEmberVersion(2, 14)) { Ember.MODEL_FACTORY_INJECTIONS = value; } diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 9eb75ce1f09..4926a77f273 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -2,6 +2,10 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import { + setup as setupModelFactoryInjections, + reset as resetModelFactoryInjection +} from 'dummy/tests/helpers/model-factory-injection'; import {module, test} from 'qunit'; import DS from 'ember-data'; @@ -82,6 +86,7 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { }, afterEach() { + resetModelFactoryInjection(); run(env.container, 'destroy'); } }); @@ -491,6 +496,7 @@ test("polymorphic belongsTo class-checks check the superclass when MODEL_FACTORY }); test("the subclass in a polymorphic belongsTo relationship is an instanceof its superclass", function(assert) { + setupModelFactoryInjections(false); assert.expect(1); run(() => { let message = env.store.createRecord('message', { id: 1 }); From 82d616cef2c0ba34c0158a47a8126e3d76eba398 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 16 Aug 2017 10:09:59 -0700 Subject: [PATCH 2015/2527] Fix 1.13-x --- addon/-private/utils.js | 5 ++++- tests/unit/model-test.js | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/addon/-private/utils.js b/addon/-private/utils.js index 138835394ed..a60adb144c5 100644 --- a/addon/-private/utils.js +++ b/addon/-private/utils.js @@ -28,7 +28,10 @@ function getOwner(context) { if (owner && owner.lookupFactory && !owner._lookupFactory) { // `owner` is a container, we are just making this work - owner._lookupFactory = owner.lookupFactory; + owner._lookupFactory = function() { + return owner.lookupFactory(...arguments); + } + owner.register = function() { let registry = owner.registry || owner._registry || owner; diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index da70733455d..eb4fe34d6c7 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -5,8 +5,9 @@ import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; import DS from 'ember-data'; import { isEnabled } from 'ember-data/-private'; +import { getOwner } from 'ember-data/-private'; -const { get, getOwner, set, run } = Ember; +const { get, set, run } = Ember; let Person, store, env; From bc930ff85b948e96eaf23edd6a74004695b60edd Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Wed, 16 Aug 2017 14:53:28 +0100 Subject: [PATCH 2016/2527] Replace Ember.String.{pluralize,singularize} with ember-inflector imports --- addon/-private/adapters/build-url-mixin.js | 6 ++++-- addon/adapters/json-api.js | 3 ++- addon/serializers/json.js | 3 ++- tests/integration/adapter/build-url-mixin-test.js | 3 ++- tests/integration/adapter/rest-adapter-test.js | 3 ++- tests/integration/serializers/rest-serializer-test.js | 5 +++-- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index bd3de1ce3e1..0273992da8c 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -1,4 +1,5 @@ import Ember from 'ember'; +import { pluralize } from 'ember-inflector'; const get = Ember.get; @@ -420,11 +421,12 @@ export default Ember.Mixin.create({ ```app/adapters/application.js import DS from 'ember-data'; + import { pluralize } from 'ember-inflector'; export default DS.RESTAdapter.extend({ pathForType: function(modelName) { var decamelized = Ember.String.decamelize(modelName); - return Ember.String.pluralize(decamelized); + return pluralize(decamelized); } }); ``` @@ -435,6 +437,6 @@ export default Ember.Mixin.create({ **/ pathForType(modelName) { let camelized = Ember.String.camelize(modelName); - return Ember.String.pluralize(camelized); + return pluralize(camelized); } }); diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index 144e15caa69..48610dec134 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -4,6 +4,7 @@ */ import Ember from 'ember'; +import { pluralize } from 'ember-inflector'; import RESTAdapter from "./rest"; import { isEnabled } from '../-private'; import { deprecate } from '@ember/debug'; @@ -258,7 +259,7 @@ const JSONAPIAdapter = RESTAdapter.extend({ pathForType(modelName) { let dasherized = Ember.String.dasherize(modelName); - return Ember.String.pluralize(dasherized); + return pluralize(dasherized); }, // TODO: Remove this once we have a better way to override HTTP verbs. diff --git a/addon/serializers/json.js b/addon/serializers/json.js index f624bd43f1f..8547a42f886 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -959,6 +959,7 @@ const JSONSerializer = Serializer.extend({ ```app/serializers/application.js import DS from 'ember-data'; + import { singularize } from 'ember-inflector'; export default DS.JSONSerializer.extend({ serialize(snapshot, options) { @@ -987,7 +988,7 @@ const JSONSerializer = Serializer.extend({ } function serverHasManyName(name) { - return serverAttributeName(name.singularize()) + "_IDS"; + return serverAttributeName(singularize(name)) + "_IDS"; } ``` diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index aee911e6f6f..f3adddc18f2 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -1,5 +1,6 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import { pluralize } from 'ember-inflector'; import { isEnabled } from 'ember-data/-private'; import {module, test} from 'qunit'; @@ -184,7 +185,7 @@ test('buildURL - with camelized names', function(assert) { adapter.setProperties({ pathForType(type) { let decamelized = Ember.String.decamelize(type); - return Ember.String.underscore(Ember.String.pluralize(decamelized)); + return Ember.String.underscore(pluralize(decamelized)); } }); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 403b14e4545..7f36d338b6a 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1,5 +1,6 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import { singularize } from 'ember-inflector'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; @@ -2069,7 +2070,7 @@ test('normalizeKey - to set up _ids and _id', function(assert) { let underscored = Ember.String.underscore(rel); return underscored + '_id'; } else { - let singular = Ember.String.singularize(rel); + let singular = singularize(rel); return Ember.String.underscore(singular) + '_ids'; } } diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index b9b2cb6b60e..5f3f912d072 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -1,5 +1,6 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; +import { singularize } from 'ember-inflector'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; @@ -104,7 +105,7 @@ test("normalizeResponse with custom modelNameFromPayloadKey", function(assert) { env.restSerializer.modelNameFromPayloadKey = function(root) { var camelized = Ember.String.camelize(root); - return Ember.String.singularize(camelized); + return singularize(camelized); }; env.registry.register('serializer:home-planet', DS.JSONSerializer); env.registry.register('serializer:super-villain', DS.JSONSerializer); @@ -256,7 +257,7 @@ testInDebug("normalizeResponse warning with custom modelNameFromPayloadKey", fun // should not warn if a model is found. env.restSerializer.modelNameFromPayloadKey = function(root) { - return Ember.String.camelize(Ember.String.singularize(root)); + return Ember.String.camelize(singularize(root)); }; jsonHash = { From 3509e0b05ab9f4a59cb9ea799e3d299c66061fa4 Mon Sep 17 00:00:00 2001 From: azuby Date: Fri, 18 Aug 2017 17:48:17 -0700 Subject: [PATCH 2017/2527] [DOC release] Improve save method documentation --- addon/-private/system/model/model.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 354bd46cdd9..6fadc64cea9 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -755,8 +755,8 @@ const Model = Ember.Object.extend(Ember.Evented, { }); ``` - If you pass an object on the `adapterOptions` property of the options - argument it will be passed to you adapter via the snapshot + If you pass an object using the `adapterOptions` property of the options + argument it will be passed to your adapter via the snapshot. ```js record.save({ adapterOptions: { subscribe: false } }); From 744080120a0a7b75520e1b79a3563d97ff46b839 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Tue, 22 Aug 2017 20:49:19 +0100 Subject: [PATCH 2018/2527] Import Inflector instead of relying on Ember namespace --- tests/integration/serializers/rest-serializer-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 5f3f912d072..46d69e47abf 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -1,6 +1,6 @@ import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; -import { singularize } from 'ember-inflector'; +import Inflector, { singularize } from 'ember-inflector'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; @@ -75,7 +75,7 @@ module("integration/serializer/rest - RESTSerializer", { test("modelNameFromPayloadKey returns always same modelName even for uncountable multi words keys", function(assert) { assert.expect(2); - Ember.Inflector.inflector.uncountable('words'); + Inflector.inflector.uncountable('words'); var expectedModelName = 'multi-words'; assert.equal(env.restSerializer.modelNameFromPayloadKey('multi_words'), expectedModelName); assert.equal(env.restSerializer.modelNameFromPayloadKey('multi-words'), expectedModelName); From 4b5fe5eae4377bd04391892dc992c1eca19689e7 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Wed, 23 Aug 2017 13:06:48 -0700 Subject: [PATCH 2019/2527] [BUGFIX release] Load many2many relationships correctly When a many2many relationship exists and more than one related item is included in the relationship ensure that both sides load completely. This issue was introduced in e430edee24591afa562167c6f5775b61d1031b75 --- .../system/relationships/state/has-many.js | 5 +- .../unit/model/relationships/has-many-test.js | 130 ++++++++++++++++++ 2 files changed, 131 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 5bea9d4ad02..2062e8ba11c 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -205,21 +205,18 @@ export default class ManyRelationship extends Relationship { return; } - let forCanonical = []; - for (let i = 0; i< internalModels.length; i++) { let internalModel = internalModels[i]; if (this.canonicalMembers.has(internalModel)) { continue; } - forCanonical.push(internalModel); this.canonicalMembers.add(internalModel); this.members.add(internalModel); this.setupInverseRelationship(internalModel); } - this.canonicalState.splice(0, this.canonicalState.length, ...forCanonical); + this.canonicalState = this.canonicalMembers.toArray(); } fetchLink() { diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 05bfe05a6e4..1aac40c7181 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -477,6 +477,136 @@ test('hasMany with duplicates from payload', function(assert) { }); }); +test('many2many loads both sides #5140', function(assert) { + assert.expect(3); + + const Tag = DS.Model.extend({ + name: DS.attr('string'), + people: DS.hasMany('person', { async: false }) + }); + + Tag.reopenClass({ + toString() { + return 'tag'; + } + }); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + tags: DS.hasMany('tags', { async: false }) + }); + + Person.reopenClass({ + toString() { + return 'person'; + } + }); + + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + + run(() => { + // first we push in data with the relationship + store.push({ + data: [ + { + type: 'person', + id: 1, + attributes: { + name: 'David J. Hamilton' + }, + relationships: { + tags: [{ + data: { + type: 'tag', + id: 1 + } + }, + { + data: { + type: 'tag', + id: 2 + } + }] + } + }, + { + type: 'person', + id: 2, + attributes: { + name: 'Gerald Dempsey Posey' + }, + relationships: { + tags: [{ + data: { + type: 'tag', + id: 1 + } + }, + { + data: { + type: 'tag', + id: 2 + } + }] + } + }, + { + type: 'tag', + id: 1, + attributes: { + name: 'whatever' + }, + relationships: { + people: { + data: [ + { + type: 'person', + id: 1 + }, + { + type: 'person', + id: 2 + } + ] + } + } + }, + { + type: 'tag', + id: 2, + attributes: { + name: 'nothing' + }, + relationships: { + people: { + data: [ + { + type: 'person', + id: 1 + }, + { + type: 'person', + id: 2 + } + ] + } + } + } + ] + }); + }); + + run(() => { + let tag = store.peekRecord('tag', 1); + assert.equal(tag.get('people.length'), 2, 'relationship does contain all data'); + let person1 = store.peekRecord('person', 1); + assert.equal(person1.get('tags.length'), 2, 'relationship does contain all data'); + let person2 = store.peekRecord('person', 2); + assert.equal(person2.get('tags.length'), 2, 'relationship does contain all data'); + }); +}); + test('hasMany with explicit null works even when the inverse was set to not null', function(assert) { assert.expect(3); From 00634847195a952978728930ddee06fe4aab9125 Mon Sep 17 00:00:00 2001 From: Nick Anderson Date: Sun, 13 Aug 2017 13:24:09 -0700 Subject: [PATCH 2020/2527] [BUGFIX release] fix relationship merging When relationship information is merged, the newest information should win. Unfortunately prior to this PR, relationship containing only `link` information, would mistakenly purge any existing `data` information on that relationship. 1. Update One ```js { data: { /* existing data */ }, Link: { /* existing data */ }, } ``` 2. Update Two ```js { Link: { /* new data */ }, } ``` Previously resulted in: ```js { link: { /* new data */ }, data: null // oops } ``` But now (correctly) results in: ```js { link: { /* new data */ }, data: { /* existing data */ } } ``` --- .../relationships/relationship-payloads.js | 8 +- .../relationships/nested-relationship-test.js | 148 ++++++++++++++++++ 2 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 tests/integration/relationships/nested-relationship-test.js diff --git a/addon/-private/system/relationships/relationship-payloads.js b/addon/-private/system/relationships/relationship-payloads.js index ee9626c8683..d0815007048 100644 --- a/addon/-private/system/relationships/relationship-payloads.js +++ b/addon/-private/system/relationships/relationship-payloads.js @@ -220,7 +220,13 @@ export default class RelationshipPayloads { // Then we will initially have set user:2 as having helicopter:1, which we // need to remove before adding helicopter:1 to user:4 // - this._removeInverse(id, previousPayload, inverseIdToPayloads); + // only remove relationship information before adding if there is relationshipData.data + // * null is considered new information "empty", and it should win + // * undefined is NOT considered new information, we should keep original state + // * anything else is considered new information, and it should win + if (relationshipData.data !== undefined) { + this._removeInverse(id, previousPayload, inverseIdToPayloads); + } idToPayloads[id] = relationshipData; this._populateInverse(relationshipData, inverseRelationshipData, inverseIdToPayloads, inverseIsMany); } diff --git a/tests/integration/relationships/nested-relationship-test.js b/tests/integration/relationships/nested-relationship-test.js new file mode 100644 index 00000000000..425a48701ec --- /dev/null +++ b/tests/integration/relationships/nested-relationship-test.js @@ -0,0 +1,148 @@ +import setupStore from 'dummy/tests/helpers/store'; +import Ember from 'ember'; + +import {module, test} from 'qunit'; + +import DS from 'ember-data'; + +const { get, run } = Ember; +const { attr, hasMany, belongsTo } = DS; + +let env, store, serializer, Elder, MiddleAger, Kid; + +module('integration/relationships/nested_relationships_test - Nested relationships', { + beforeEach() { + Elder = DS.Model.extend({ + name: attr('string'), + middleAgers: hasMany('middle-ager') + }); + + MiddleAger = DS.Model.extend({ + name: attr('string'), + elder: belongsTo('elder'), + kids: hasMany('kid') + }); + + Kid = DS.Model.extend({ + name: attr('string'), + middleAger: belongsTo('middle-ager') + }); + + env = setupStore({ + elder: Elder, + 'middle-ager': MiddleAger, + kid: Kid, + adapter: DS.JSONAPIAdapter + }); + + store = env.store; + serializer = env.serializer; + }, + + afterEach() { + run(env.container, 'destroy'); + } +}); + +/* + Server loading tests +*/ + +test('Sideloaded nested relationships load correctly', function(assert) { + run(() => { + serializer.pushPayload(store, { + data: [ + { + id: '1', + type: 'kids', + links: { + self: '/kids/1' + }, + attributes: { + name: 'Kid 1' + }, + relationships: { + 'middle-ager': { + links: { + self: '/kids/1/relationships/middle-ager', + related: '/kids/1/middle-ager' + }, + data:{ + type: 'middle-agers', + id: '1' + } + } + } + } + ], + included: [ + { + id: '1', + type: 'middle-agers', + links: { + self: '/middle-ager/1' + }, + attributes: { + name: 'Middle Ager 1' + }, + relationships: { + elder: { + links: { + self: '/middle-agers/1/relationships/elder', + related: '/middle-agers/1/elder' + }, + data: { + type: 'elders', + id: '1' + } + }, + kids: { + links: { + self: '/middle-agers/1/relationships/kids', + related: '/middle-agers/1/kids' + } + } + } + }, + + { + id: '1', + type: 'elders', + links: { + self: '/elders/1' + }, + attributes: { + name: 'Elder 1' + }, + relationships: { + 'middle-agers': { + links: { + self: '/elders/1/relationships/middle-agers', + related: '/elders/1/middle-agers' + } + } + } + } + ] + }); + }); + + return run(() => { + let kid = store.peekRecord('kid', 1); + + return kid.get('middleAger').then(middleAger => { + assert.ok(middleAger, 'MiddleAger relationship was set up correctly'); + + let middleAgerName = get(middleAger, 'name'); + assert.equal(middleAgerName, 'Middle Ager 1', 'MiddleAger name is there'); + assert.ok(middleAger.get('kids').includes(kid)); + + return middleAger.get('elder').then(elder => { + assert.notEqual(elder, null, 'Elder relationship was set up correctly'); + let elderName = get(elder, 'name'); + assert.equal(elderName, 'Elder 1', 'Elder name is there'); + }); + }); + }); +}); + From 19d3dd5cdc6aa095f2bab84e5cc5dfd6848183d2 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 24 Aug 2017 17:20:31 -0700 Subject: [PATCH 2021/2527] [BUGFIX release] Enumerate relationships provided, not all on a given schema --- addon/-private/system/store.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b7b53774bc6..cfbf226e152 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2429,9 +2429,10 @@ Store = Service.extend({ // payload push. In the common case where we are pushing many more // instances than types we want to minimize the cost of looking up the // inverse map and the overhead of Ember.get adds up. - let modelNameToInverseMap = Object.create(null); + let modelNameToInverseMap; for (let i = 0, l = pushed.length; i < l; i += 2) { + modelNameToInverseMap = modelNameToInverseMap || Object.create(null); // This will convert relationships specified as IDs into DS.Model instances // (possibly unloaded) and also create the data structures used to track // relationships. @@ -2870,13 +2871,8 @@ function isInverseRelationshipInitialized(store, internalModel, data, key, model } function setupRelationships(store, internalModel, data, modelNameToInverseMap) { - let relationships = internalModel._relationships; - - internalModel.type.eachRelationship(relationshipName => { - if (!data.relationships[relationshipName]) { - return; - } - + Object.keys(data.relationships).forEach(relationshipName => { + let relationships = internalModel._relationships; let relationshipRequiresNotification = relationships.has(relationshipName) || isInverseRelationshipInitialized(store, internalModel, data, relationshipName, modelNameToInverseMap); From 01113a01c4831e31cd502ce26d6c10cbeb917487 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 24 Aug 2017 20:07:43 -0700 Subject: [PATCH 2022/2527] [CLEANUP] PERF prevent duplicate recordArrayManager signals on push of a new record * if the record is new, ensure only 1 recordWasLoaded is called (after setup) * if the record is existing, ensure only 1 recordDidChange is called (after setup) * decouple InternalModel slightly more from recordArrayManager * remove now defunct code --- addon/-private/system/model/internal-model.js | 22 ------------------- addon/-private/system/store.js | 8 ++++++- 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index f8f1f498c9f..8306b216820 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -358,7 +358,6 @@ export default class InternalModel { resetRecord() { this._record = null; - this.dataHasInitialized = false; this.isReloading = false; this.error = null; this.currentState = RootState.empty; @@ -592,18 +591,6 @@ export default class InternalModel { if (this.hasRecord) { this._record._notifyProperties(changedKeys); } - this.didInitializeData(); - } - - becameReady() { - this.store.recordArrayManager.recordWasLoaded(this); - } - - didInitializeData() { - if (!this.dataHasInitialized) { - this.becameReady(); - this.dataHasInitialized = true; - } } get isDestroyed() { @@ -638,7 +625,6 @@ export default class InternalModel { */ loadedData() { this.send('loadedData'); - this.didInitializeData(); } /* @@ -785,14 +771,6 @@ export default class InternalModel { this.didCleanError(); } - //Eventually rollback will always work for relationships - //For now we support it only out of deleted state, because we - //have an explicit way of knowing when the server acked the relationship change - if (this.isDeleted()) { - //TODO: Should probably move this to the state machine somehow - this.becameReady(); - } - if (this.isNew()) { this.removeFromInverseRelationships(true); } diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b7b53774bc6..0ab4f67f9c2 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2017,9 +2017,15 @@ Store = Service.extend({ heimdall.increment(_load); let internalModel = this._internalModelForId(data.type, data.id); + let isUpdate = internalModel.currentState.isEmpty === false; + internalModel.setupData(data); - this.recordArrayManager.recordDidChange(internalModel); + if (isUpdate) { + this.recordArrayManager.recordDidChange(internalModel); + } else { + this.recordArrayManager.recordWasLoaded(internalModel); + } return internalModel; }, From 5f5d5d17ed5adab3f2d56a2f8c50a1161a870d17 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Fri, 25 Aug 2017 05:43:36 -0700 Subject: [PATCH 2023/2527] [BUGFIX release] ensure inverse async HasMany is correctly maintained In order to ensure symmetry between async and sync relationships, on destroy/unload of a record we must remove it from existing hasManys Prior to this it appears in the inverse async case accidentally removed the inverse of the inverse which is wrong, and may also not exist at that name. How this manifests --- addon/-private/system/model/internal-model.js | 31 ++++++++----------- .../relationships/state/relationship.js | 7 +++-- .../integration/records/rematerialize-test.js | 23 +++++++------- yarn.lock | 16 +++++----- 4 files changed, 36 insertions(+), 41 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index f8f1f498c9f..62f27deec0b 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -68,6 +68,14 @@ function areAllModelsUnloaded(internalModels) { return true; } +function destroyRelationship(rel) { + if (rel._inverseIsAsync()) { + rel.removeInternalModelFromInverse(rel.inverseInternalModel); + rel.removeInverseRelationships(); + } else { + rel.removeCompletelyFromInverse(); + } +} // this (and all heimdall instrumentation) will be stripped by a babel transform // https://github.com/heimdalljs/babel5-plugin-strip-heimdall const { @@ -432,9 +440,7 @@ export default class InternalModel { _directlyRelatedInternalModels() { let array = []; this._relationships.forEach((name, rel) => { - let local = rel.members.toArray(); - let server = rel.canonicalMembers.toArray(); - array = array.concat(local, server); + array = array.concat(rel.members.list, rel.canonicalMembers.list); }); return array; } @@ -486,6 +492,7 @@ export default class InternalModel { once all models that refer to it via some relationship are also unloaded. */ unloadRecord() { + if (this.isDestroyed) { return; } this.send('unloadRecord'); this.dematerializeRecord(); @@ -539,7 +546,6 @@ export default class InternalModel { if (this.isDestroyed) { return; } this._cleanupOrphanedInternalModels(); - } _cleanupOrphanedInternalModels() { @@ -946,26 +952,15 @@ export default class InternalModel { and destroys any ManyArrays. */ destroyRelationships() { - this._relationships.forEach((name, rel) => { - if (rel._inverseIsAsync()) { - rel.removeInternalModelFromInverse(this); - rel.removeInverseRelationships(); - } else { - rel.removeCompletelyFromInverse(); - } - }); + let relationships = this._relationships; + relationships.forEach((name, rel) => destroyRelationship(rel)); let implicitRelationships = this._implicitRelationships; this.__implicitRelationships = null; Object.keys(implicitRelationships).forEach((key) => { let rel = implicitRelationships[key]; - if (rel._inverseIsAsync()) { - rel.removeInternalModelFromInverse(this); - rel.removeInverseRelationships(); - } else { - rel.removeCompletelyFromInverse(); - } + destroyRelationship(rel); rel.destroy(); }); diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 2d1792d9877..140d997d3ca 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -96,12 +96,13 @@ export default class Relationship { let allMembers = // we actually want a union of members and canonicalMembers // they should be disjoint but currently are not due to a bug - this.members.toArray().concat(this.canonicalMembers.toArray()); + this.members.list.concat(this.canonicalMembers.list); - allMembers.forEach(inverseInternalModel => { + for (let i = 0; i < allMembers.length; i++) { + let inverseInternalModel = allMembers[i]; let relationship = inverseInternalModel._relationships.get(this.inverseKey); relationship.inverseDidDematerialize(); - }); + } } inverseDidDematerialize() {} diff --git a/tests/integration/records/rematerialize-test.js b/tests/integration/records/rematerialize-test.js index b7a71c0be8f..d3aa5a738a4 100644 --- a/tests/integration/records/rematerialize-test.js +++ b/tests/integration/records/rematerialize-test.js @@ -57,12 +57,10 @@ module("integration/unload - Rematerializing Unloaded Records", { }); test("a sync belongs to relationship to an unloaded record can restore that record", function(assert) { - let adam, bob; - // disable background reloading so we do not re-create the relationship. env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { + let adam = run(() => { env.store.push({ data: { type: 'person', @@ -79,10 +77,11 @@ test("a sync belongs to relationship to an unloaded record can restore that reco } } }); - adam = env.store.peekRecord('person', 1); + + return env.store.peekRecord('person', 1); }); - run(function() { + let bob = run(() => { env.store.push({ data: { type: 'car', @@ -98,7 +97,8 @@ test("a sync belongs to relationship to an unloaded record can restore that reco } } }); - bob = env.store.peekRecord('car', 1); + + return env.store.peekRecord('car', 1); }); let person = env.store.peekRecord('person', 1); @@ -107,9 +107,7 @@ test("a sync belongs to relationship to an unloaded record can restore that reco assert.equal(env.store.hasRecordForId('person', 1), true, 'The person is in the store'); assert.equal(env.store._internalModelsFor('person').has(1), true, 'The person internalModel is loaded'); - run(function() { - person.unloadRecord(); - }); + run(() => person.unloadRecord()); assert.equal(env.store.hasRecordForId('person', 1), false, 'The person is unloaded'); assert.equal(env.store._internalModelsFor('person').has(1), true, 'The person internalModel is retained'); @@ -141,7 +139,7 @@ test("a sync belongs to relationship to an unloaded record can restore that reco }); test("an async has many relationship to an unloaded record can restore that record", function(assert) { - assert.expect(14); + assert.expect(15); // disable background reloading so we do not re-create the relationship. env.adapter.shouldBackgroundReloadRecord = () => false; @@ -189,7 +187,7 @@ test("an async has many relationship to an unloaded record can restore that reco }; } - run(function() { + run(() => { env.store.push({ data: { type: 'person', @@ -209,7 +207,7 @@ test("an async has many relationship to an unloaded record can restore that reco }); }); - run(function() { + run(() => { env.store.push({ data: [BOAT_ONE, BOAT_TWO] }); @@ -228,6 +226,7 @@ test("an async has many relationship to an unloaded record can restore that reco assert.equal(boats.get('length'), 2, 'Before unloading boats.length is correct'); run(() => boaty.unloadRecord()); + assert.equal(boats.get('length'), 1, 'after unloading boats.length is correct'); assert.equal(env.store.hasRecordForId('boat', 1), false, 'The boat is unloaded'); assert.equal(env.store._internalModelsFor('boat').has(1), true, 'The boat internalModel is retained'); diff --git a/yarn.lock b/yarn.lock index 7a7783e870c..9b557f2fb2b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -107,6 +107,12 @@ amd-name-resolver@0.0.6: dependencies: ensure-posix-path "^1.0.1" +amd-name-resolver@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-0.0.7.tgz#814301adfe8a2f109f6e84d5e935196efb669615" + dependencies: + ensure-posix-path "^1.0.1" + amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -1018,7 +1024,7 @@ bower-endpoint-parser@0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" -bower@^1.6.5, bower@^1.8.0: +bower@^1.8.0: version "1.8.0" resolved "https://registry.npmjs.org/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a" @@ -1484,13 +1490,7 @@ bytes@2.4.0: version "2.4.0" resolved "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" -calculate-cache-key-for-tree@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" - dependencies: - json-stable-stringify "^1.0.1" - -calculate-cache-key-for-tree@^1.1.0: +calculate-cache-key-for-tree@^1.0.0, calculate-cache-key-for-tree@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" dependencies: From 22b51549b873ce9c1479f82fadec4c35fc3a01b7 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Fri, 1 Sep 2017 12:40:32 +0100 Subject: [PATCH 2024/2527] Update RELEASE.md --- RELEASE.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index d38fc25f0ab..0c8a092bb0e 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -34,11 +34,6 @@ STEPS: * Edit [lastRelease, futureVersion and date](https://github.com/emberjs/website/blob/master/source/javascripts/app/builds/app.js#L238-L241) values for the release channel we are releasing. * Commit updated `javascripts/app/builds/app.js` file * `rake deploy` -* Website API docs (This step does not happen for beta releases) - * `cd ../website` - * `rake generate_ember_data_docs` - * Commit updated `data/data_api.yml` file - * `rake deploy` * Write a Release Blog Post (Does not happen for beta releases) * Commits since last release: `git log --oneline release..beta | wc -l`. * Contributors since last release: `git shortlog -s -n release...beta | wc -l` From 17e8b1a074912209c56e83d28c46e1cd1c085ba0 Mon Sep 17 00:00:00 2001 From: Cory Date: Wed, 6 Sep 2017 15:56:29 -0400 Subject: [PATCH 2025/2527] [DOC] Update README build step script name Changes step 3 of "Building Ember Data" to instruct using the npm script "production" rather than "build:production", which doesn't exist. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a3e042845c..7402797c180 100644 --- a/README.md +++ b/README.md @@ -173,7 +173,7 @@ on models](https://emberjs.com/guides/models/). 1. Ensure that [Node.js](http://nodejs.org/) is installed. 2. Run `npm install` to ensure the required dependencies are installed. -3. Run `npm run build:production` to build Ember Data. The builds will be placed in the `dist/` directory. +3. Run `npm run production` to build Ember Data. The builds will be placed in the `dist/` directory. # Contribution From b8a409cd88681e4a6ce46e1f8b125c209fb8cb8b Mon Sep 17 00:00:00 2001 From: Cory Date: Wed, 6 Sep 2017 16:05:18 -0400 Subject: [PATCH 2026/2527] [DOC] Remove mention of `bower install` from README Update README to remove mention of installing bower and running `bower install`. --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 3a3e042845c..1ad64af970b 100644 --- a/README.md +++ b/README.md @@ -185,12 +185,10 @@ See [CONTRIBUTING.md](https://github.com/emberjs/data/blob/master/CONTRIBUTING.m 1. Install Node.js from http://nodejs.org or your favorite package manager. -2. Install Ember CLI and bower. `npm install -g ember-cli bower` +2. Install Ember CLI. `npm install -g ember-cli` 3. Run `npm install` inside the project root to install the JS dependencies. -4. Run `bower install` inside the project root to install Ember dependencies. - ### In Your Browser 1. To start the development server, run `npm start`. From c16766d83f956ce12e6bc081172bc71dae8f0b1a Mon Sep 17 00:00:00 2001 From: Cory Forsyth Date: Wed, 13 Sep 2017 16:09:55 -0400 Subject: [PATCH 2027/2527] [DOC] Remove parameter from BelongsToReference.value `BelongsToReference.prototype.value` does not appear to actually take any parameters. --- addon/-private/system/references/belongs-to.js | 1 - 1 file changed, 1 deletion(-) diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 30098086870..3bf43446082 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -308,7 +308,6 @@ BelongsToReference.prototype.push = function(objectOrPromise) { ``` @method value - @param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. @return {DS.Model} the record in this relationship */ BelongsToReference.prototype.value = function() { From f3bfad8d7df3cedda9e8fb61f072763da73beee5 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 14 Sep 2017 11:28:22 -0700 Subject: [PATCH 2028/2527] resolve #5019 --- lib/stripped-build-plugins.js | 5 +- lib/transforms/babel-plugin-remove-imports.js | 43 +- .../unit/babel-plugin-remove-imports-test.js | 108 ++ package.json | 3 + yarn.lock | 1405 ++++++++++------- 5 files changed, 1016 insertions(+), 548 deletions(-) create mode 100644 node-tests/unit/babel-plugin-remove-imports-test.js diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index af4310c6d25..f5011b4621d 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -55,12 +55,9 @@ module.exports = function(environment) { plugins.push( [FilterImports, filteredImports], + [StripFilteredImports, filteredImports], [TransformBlockScoping, { 'throwIfClosureRequired': true }] ); - if (environment === 'production') { - plugins.push([StripFilteredImports, 'ember-data/-debug']); - } - return { plugins, postTransformPlugins }; }; diff --git a/lib/transforms/babel-plugin-remove-imports.js b/lib/transforms/babel-plugin-remove-imports.js index aec7d8852d0..f112df29877 100644 --- a/lib/transforms/babel-plugin-remove-imports.js +++ b/lib/transforms/babel-plugin-remove-imports.js @@ -1,15 +1,15 @@ -var path = require('path'); - -function removeImports() { +function PluginRemoveFilteredImports() { var importDeclarationsToRemove; var filteredImports; + var filteredImportNames; return { name: 'remove-filtered-imports', visitor: { Program: { enter: function(_, state) { - filteredImports = state.opts instanceof Array ? state.opts : (state.opts ? [state.opts] : []); + filteredImports = state.opts || {}; + filteredImportNames = Object.keys(filteredImports); importDeclarationsToRemove = []; }, exit: function() { @@ -24,8 +24,35 @@ function removeImports() { ImportDeclaration: function(path) { var name = path.node.source.value; - if (filteredImports.indexOf(name) !== -1) { - importDeclarationsToRemove.push(path); + if (filteredImportNames.indexOf(name) !== -1) { + if (filteredImports[name] === true || filteredImports[name] === '*') { + importDeclarationsToRemove.push(path); + } else { + let removables = []; + let imports = path.node.specifiers; + const hasSpecifiers = imports.length > 0; + + for (let i = 0; i < imports.length; i++) { + if (imports[i].type === 'ImportNamespaceSpecifier') { + continue; + } + + let specifier = imports[i].imported; + + if (filteredImports[name].indexOf(specifier.name) !== -1) { + removables.push(imports[i]); + } + } + + if (hasSpecifiers && removables.length === imports.length) { + importDeclarationsToRemove.push(path); + } else { + for (let i = 0; i < removables.length; i++) { + let index = imports.indexOf(removables[i]); + imports.splice(index, 1); + } + } + } } } @@ -33,8 +60,8 @@ function removeImports() { }; } -removeImports.baseDir = function() { +PluginRemoveFilteredImports.baseDir = function() { return __dirname; }; -module.exports = removeImports; +module.exports = PluginRemoveFilteredImports; diff --git a/node-tests/unit/babel-plugin-remove-imports-test.js b/node-tests/unit/babel-plugin-remove-imports-test.js new file mode 100644 index 00000000000..d39d15f72b7 --- /dev/null +++ b/node-tests/unit/babel-plugin-remove-imports-test.js @@ -0,0 +1,108 @@ +const BroccoliTestHelper = require('broccoli-test-helper'); +const co = require('co'); +const Babel = require('broccoli-babel-transpiler'); +const chai = require('ember-cli-blueprint-test-helpers/chai'); +const stripIndent = require('common-tags').stripIndent; +const StripFilteredImports = require('../../lib/transforms/babel-plugin-remove-imports'); + +const { expect } = chai; +const createTempDir = BroccoliTestHelper.createTempDir; +const createBuilder = BroccoliTestHelper.createBuilder; + +function stripNewlines(str) { + return str.replace(/[\r\n]/g, ''); +} + +describe('Unit: babel-plugin-remove-filtered-imports', function() { + let plugins, pluginOptions; + let input, output; + + function transform(code) { + return co.wrap(function* () { + input.write({ 'test.js': code }); + let babel = new Babel(input.path(), { + plugins + }); + + output = createBuilder(babel); + + yield output.build(); + + const transpiled = output.read(); + + return stripNewlines(transpiled['test.js']); + })(); + } + + beforeEach(co.wrap(function* () { + pluginOptions = {}; + + plugins = [ + [StripFilteredImports, pluginOptions] + ]; + + input = yield createTempDir(); + })); + + afterEach(co.wrap(function* () { + if (input) { + yield input.dispose(); + } + if (output) { + yield output.dispose(); + } + + input = output = undefined; + })); + + it('Returns a plugin', function() { + let plugin = StripFilteredImports(); + + expect(plugin).to.be.ok; + }); + + it('Does not alter a file if no imports are meant to be filtered', co.wrap(function*() { + const input = stripIndent` + import Foo from 'bar'; + import { baz } from 'none'; + import * as drinks from 'drinks'; + import 'bem'; + `; + const result = yield transform(input); + + expect(result).to.equal(stripNewlines(input)); + })); + + it('Properly strips desired imports and specifiers', co.wrap(function*() { + const input = stripIndent` + import Foo from 'bar'; + import { bit } from 'wow'; + import { baz, bell } from 'none'; + import { foo } from 'happy'; + import * as drinks from 'drinks'; + import * as dranks from 'dranks'; + import 'bem'; + import 'bosh'; + import 'bell'; + `; + + pluginOptions.none = ['baz']; + pluginOptions.bar = true; + pluginOptions.drinks = '*'; + pluginOptions.wow = ['bit']; + pluginOptions.bem = ['biz']; + pluginOptions.bosh = '*'; + pluginOptions.dranks = ['bex']; + pluginOptions.bell = true; + + const expectedOutput = stripNewlines(stripIndent` + import { bell } from 'none'; + import { foo } from 'happy'; + import * as dranks from 'dranks'; + import 'bem'; + `); + const result = yield transform(input); + + expect(result).to.equal(expectedOutput); + })); +}); diff --git a/package.json b/package.json index e5ae5e843e0..c5dfb496c2f 100644 --- a/package.json +++ b/package.json @@ -31,8 +31,11 @@ "broccoli-funnel": "^1.2.0", "broccoli-merge-trees": "^2.0.0", "broccoli-rollup": "^1.2.0", + "broccoli-test-helper": "^1.2.0", "calculate-cache-key-for-tree": "^1.1.0", "chalk": "^1.1.1", + "co": "^4.6.0", + "common-tags": "^1.4.0", "ember-cli-babel": "^6.4.1", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 9b557f2fb2b..43ea953398d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6,15 +6,15 @@ version "0.2.0" resolved "https://registry.npmjs.org/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" -"@glimmer/resolver@0.4.0": - version "0.4.0" - resolved "https://registry.npmjs.org/@glimmer/resolver/-/resolver-0.4.0.tgz#7fe8709342064f144c14c06088d6dc4070ad7d1d" +"@glimmer/resolver@^0.4.1": + version "0.4.1" + resolved "https://registry.npmjs.org/@glimmer/resolver/-/resolver-0.4.1.tgz#cd9644572c556e7e799de1cf8eff2b999cf5b878" dependencies: "@glimmer/di" "^0.2.0" "@types/node@*", "@types/node@^7.0.5": - version "7.0.33" - resolved "https://registry.npmjs.org/@types/node/-/node-7.0.33.tgz#ae3c53ad01d7e9d62c7f1a85c5f7500d59b9d25b" + version "7.0.43" + resolved "https://registry.npmjs.org/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c" "@types/rimraf@^0.0.28": version "0.0.28" @@ -36,13 +36,20 @@ abbrev@1: version "1.1.0" resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" -accepts@1.3.3, accepts@~1.3.3: +accepts@1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" dependencies: mime-types "~2.1.11" negotiator "0.6.1" +accepts@~1.3.3: + version "1.3.4" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" + dependencies: + mime-types "~2.1.16" + negotiator "0.6.1" + acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" @@ -57,13 +64,9 @@ acorn@^4.0.3: version "4.0.13" resolved "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" -acorn@^5.0.1: - version "5.0.3" - resolved "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d" - -adm-zip@^0.4.7: - version "0.4.7" - resolved "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" +acorn@^5.1.1: + version "5.1.2" + resolved "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" after@0.8.1: version "0.8.1" @@ -101,15 +104,9 @@ alter@~0.2.0: dependencies: stable "~0.1.3" -amd-name-resolver@0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.6.tgz#d3e4ba2dfcaab1d820c1be9de947c67828cfe595" - dependencies: - ensure-posix-path "^1.0.1" - amd-name-resolver@0.0.7: version "0.0.7" - resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-0.0.7.tgz#814301adfe8a2f109f6e84d5e935196efb669615" + resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.7.tgz#814301adfe8a2f109f6e84d5e935196efb669615" dependencies: ensure-posix-path "^1.0.1" @@ -137,20 +134,26 @@ ansi-styles@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" -ansi-styles@^2.1.0, ansi-styles@^2.2.1: +ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" +ansi-styles@^3.0.0, ansi-styles@^3.1.0: + version "3.2.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" + dependencies: + color-convert "^1.9.0" + ansicolors@~0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" anymatch@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + version "1.3.2" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" dependencies: - arrify "^1.0.0" micromatch "^2.1.5" + normalize-path "^2.0.0" aproba@^1.0.3: version "1.1.2" @@ -176,8 +179,8 @@ arr-diff@^2.0.0: arr-flatten "^1.0.1" arr-flatten@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.3.tgz#a274ed85ac08849b6bd7847c4580745dc51adfb1" + version "1.1.0" + resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" array-equal@^1.0.0: version "1.0.0" @@ -260,10 +263,11 @@ async-disk-cache@^1.2.1: username-sync "1.0.1" async-promise-queue@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/async-promise-queue/-/async-promise-queue-1.0.3.tgz#70c9c37635620f894978814b6c65e6e14e2573ee" + version "1.0.4" + resolved "https://registry.npmjs.org/async-promise-queue/-/async-promise-queue-1.0.4.tgz#308baafbc74aff66a0bb6e7f4a18d4fe8434440c" dependencies: async "^2.4.1" + debug "^2.6.8" async@^1.4.0, async@^1.5.2: version "1.5.2" @@ -284,11 +288,12 @@ async@~0.9.0: resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" aws-sdk@^2.0.9: - version "2.80.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.80.0.tgz#61ced747eb981609483aec53e8d654d3cc9d1435" + version "2.115.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.115.0.tgz#8373d7636cc412a04c333b27b1d211f478f276fa" dependencies: buffer "4.9.1" crypto-browserify "1.0.9" + events "^1.1.1" jmespath "0.15.0" querystring "0.2.0" sax "1.2.1" @@ -301,13 +306,13 @@ aws-sign2@~0.5.0: version "0.5.0" resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" -babel-code-frame@^6.22.0: - version "6.22.0" - resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" +babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: - chalk "^1.1.0" + chalk "^1.1.3" esutils "^2.0.2" - js-tokens "^3.0.0" + js-tokens "^3.0.2" babel-core@^5.0.0, babel-core@^5.8.22: version "5.8.38" @@ -360,41 +365,41 @@ babel-core@^5.0.0, babel-core@^5.8.22: trim-right "^1.0.0" try-resolve "^1.0.0" -babel-core@^6.14.0, babel-core@^6.24.1: - version "6.25.0" - resolved "https://registry.npmjs.org/babel-core/-/babel-core-6.25.0.tgz#7dd42b0463c742e9d5296deb3ec67a9322dad729" +babel-core@^6.14.0, babel-core@^6.26.0: + version "6.26.0" + resolved "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" dependencies: - babel-code-frame "^6.22.0" - babel-generator "^6.25.0" + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" babel-helpers "^6.24.1" babel-messages "^6.23.0" - babel-register "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.25.0" - babel-traverse "^6.25.0" - babel-types "^6.25.0" - babylon "^6.17.2" - convert-source-map "^1.1.0" - debug "^2.1.1" - json5 "^0.5.0" - lodash "^4.2.0" - minimatch "^3.0.2" - path-is-absolute "^1.0.0" - private "^0.1.6" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.0" + debug "^2.6.8" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.7" slash "^1.0.0" - source-map "^0.5.0" + source-map "^0.5.6" -babel-generator@^6.25.0: - version "6.25.0" - resolved "https://registry.npmjs.org/babel-generator/-/babel-generator-6.25.0.tgz#33a1af70d5f2890aeb465a4a7793c1df6a9ea9fc" +babel-generator@^6.26.0: + version "6.26.0" + resolved "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5" dependencies: babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-types "^6.25.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" detect-indent "^4.0.0" jsesc "^1.3.0" - lodash "^4.2.0" - source-map "^0.5.0" + lodash "^4.17.4" + source-map "^0.5.6" trim-right "^1.0.1" babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: @@ -415,13 +420,13 @@ babel-helper-call-delegate@^6.24.1: babel-types "^6.24.1" babel-helper-define-map@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.24.1.tgz#7a9747f258d8947d32d515f6aa1c7bd02204a080" + version "6.26.0" + resolved "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" dependencies: babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - lodash "^4.2.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" babel-helper-explode-assignable-expression@^6.24.1: version "6.24.1" @@ -463,12 +468,12 @@ babel-helper-optimise-call-expression@^6.24.1: babel-types "^6.24.1" babel-helper-regex@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.24.1.tgz#d36e22fab1008d79d88648e32116868128456ce8" + version "6.26.0" + resolved "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - lodash "^4.2.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" babel-helper-remap-async-to-generator@^6.24.1: version "6.24.1" @@ -518,12 +523,18 @@ babel-plugin-dead-code-elimination@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" -babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.7: - version "0.1.10" - resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.10.tgz#dd077ad6e1cc0a8f9bbc6405c561392ebfc9a01c" +babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.11, babel-plugin-debug-macros@^0.1.7: + version "0.1.11" + resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" dependencies: semver "^5.3.0" +babel-plugin-ember-modules-api-polyfill@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.0.1.tgz#baaf26dcebe2ed1de120021bc42be29f520497b3" + dependencies: + ember-rfc176-data "^0.2.7" + babel-plugin-eval@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" @@ -615,14 +626,14 @@ babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz#76c295dc3a4741b1665adfd3167215dcff32a576" + version "6.26.0" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - lodash "^4.2.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" babel-plugin-transform-es2015-classes@^6.23.0: version "6.24.1" @@ -693,13 +704,13 @@ babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015 babel-template "^6.24.1" babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.1.tgz#d3e310b40ef664a36622200097c6d440298f2bfe" + version "6.26.0" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" dependencies: babel-plugin-transform-strict-mode "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-types "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" babel-plugin-transform-es2015-modules-systemjs@^6.23.0: version "6.24.1" @@ -785,10 +796,10 @@ babel-plugin-transform-exponentiation-operator@^6.22.0: babel-runtime "^6.22.0" babel-plugin-transform-regenerator@^6.22.0: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz#b8da305ad43c3c99b4848e4fe4037b770d23c418" + version "6.26.0" + resolved "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" dependencies: - regenerator-transform "0.9.11" + regenerator-transform "^0.10.0" babel-plugin-transform-strict-mode@^6.24.1: version "6.24.1" @@ -808,16 +819,16 @@ babel-plugin-undefined-to-void@^1.1.6: resolved "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" babel-polyfill@^6.16.0: - version "6.23.0" - resolved "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d" + version "6.26.0" + resolved "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" dependencies: - babel-runtime "^6.22.0" - core-js "^2.4.0" - regenerator-runtime "^0.10.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + regenerator-runtime "^0.10.5" babel-preset-env@^1.5.1: - version "1.5.2" - resolved "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.5.2.tgz#cd4ae90a6e94b709f97374b33e5f8b983556adef" + version "1.6.0" + resolved "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.6.0.tgz#2de1c782a780a0a5d605d199c957596da43c44e4" dependencies: babel-plugin-check-es2015-constants "^6.22.0" babel-plugin-syntax-trailing-function-commas "^6.22.0" @@ -850,17 +861,17 @@ babel-preset-env@^1.5.1: invariant "^2.2.2" semver "^5.3.0" -babel-register@^6.24.1: - version "6.24.1" - resolved "https://registry.npmjs.org/babel-register/-/babel-register-6.24.1.tgz#7e10e13a2f71065bdfad5a1787ba45bca6ded75f" +babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" dependencies: - babel-core "^6.24.1" - babel-runtime "^6.22.0" - core-js "^2.4.0" + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" home-or-tmp "^2.0.0" - lodash "^4.2.0" + lodash "^4.17.4" mkdirp "^0.5.1" - source-map-support "^0.4.2" + source-map-support "^0.4.15" babel-runtime@^5.0.0: version "5.8.38" @@ -868,45 +879,45 @@ babel-runtime@^5.0.0: dependencies: core-js "^1.0.0" -babel-runtime@^6.18.0, babel-runtime@^6.22.0: - version "6.23.0" - resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" +babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: core-js "^2.4.0" - regenerator-runtime "^0.10.0" + regenerator-runtime "^0.11.0" -babel-template@^6.24.1, babel-template@^6.25.0: - version "6.25.0" - resolved "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz#665241166b7c2aa4c619d71e192969552b10c071" +babel-template@^6.24.1, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.25.0" - babel-types "^6.25.0" - babylon "^6.17.2" - lodash "^4.2.0" + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" -babel-traverse@^6.24.1, babel-traverse@^6.25.0: - version "6.25.0" - resolved "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz#2257497e2fcd19b89edc13c4c91381f9512496f1" +babel-traverse@^6.24.1, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" dependencies: - babel-code-frame "^6.22.0" + babel-code-frame "^6.26.0" babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-types "^6.25.0" - babylon "^6.17.2" - debug "^2.2.0" - globals "^9.0.0" - invariant "^2.2.0" - lodash "^4.2.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" -babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.25.0: - version "6.25.0" - resolved "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz#70afb248d5660e5d18f811d91c8303b54134a18e" +babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" dependencies: - babel-runtime "^6.22.0" + babel-runtime "^6.26.0" esutils "^2.0.2" - lodash "^4.2.0" - to-fast-properties "^1.0.1" + lodash "^4.17.4" + to-fast-properties "^1.0.3" babel6-plugin-strip-class-callcheck@^6.0.0: version "6.0.0" @@ -920,9 +931,9 @@ babylon@^5.8.38: version "5.8.38" resolved "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" -babylon@^6.17.2: - version "6.17.4" - resolved "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz#3e8b7402b88d22c3423e137a1577883b15ff869a" +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" backbone@^1.1.2: version "1.3.3" @@ -981,18 +992,18 @@ bluebird@^3.1.1, bluebird@^3.4.6: resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" body-parser@^1.15.2: - version "1.17.2" - resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.17.2.tgz#f8892abc8f9e627d42aedafbca66bf5ab99104ee" + version "1.18.1" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.18.1.tgz#9c1629370bcfd42917f30641a2dcbe2ec50d4c26" dependencies: - bytes "2.4.0" - content-type "~1.0.2" - debug "2.6.7" - depd "~1.1.0" - http-errors "~1.6.1" - iconv-lite "0.4.15" + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.8" + depd "~1.1.1" + http-errors "~1.6.2" + iconv-lite "0.4.19" on-finished "~2.3.0" - qs "6.4.0" - raw-body "~2.2.0" + qs "6.5.1" + raw-body "2.3.2" type-is "~1.6.15" body@^5.1.0: @@ -1011,8 +1022,8 @@ boom@0.4.x: hoek "0.9.x" bower-config@^1.3.0: - version "1.4.0" - resolved "https://registry.npmjs.org/bower-config/-/bower-config-1.4.0.tgz#16c38c1135f8071c19f25938d61b0d8cbf18d3f1" + version "1.4.1" + resolved "https://registry.npmjs.org/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc" dependencies: graceful-fs "^4.1.3" mout "^1.0.0" @@ -1024,10 +1035,6 @@ bower-endpoint-parser@0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" -bower@^1.8.0: - version "1.8.0" - resolved "https://registry.npmjs.org/bower/-/bower-1.8.0.tgz#55dbebef0ad9155382d9e9d3e497c1372345b44a" - brace-expansion@^1.0.0, brace-expansion@^1.1.7: version "1.1.8" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" @@ -1048,13 +1055,13 @@ breakable@~1.0.0: resolved "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" broccoli-asset-rev@^2.4.5: - version "2.5.0" - resolved "https://registry.npmjs.org/broccoli-asset-rev/-/broccoli-asset-rev-2.5.0.tgz#f5f66eac962bf9f086286921f0eaeaab6d00d819" + version "2.6.0" + resolved "https://registry.npmjs.org/broccoli-asset-rev/-/broccoli-asset-rev-2.6.0.tgz#0633fc3a0b2ba0c2c1d56fa9feb7b331fc83be6d" dependencies: broccoli-asset-rewrite "^1.1.0" broccoli-filter "^1.2.2" json-stable-stringify "^1.0.0" - matcher-collection "^1.0.1" + minimatch "^3.0.4" rsvp "^3.0.6" broccoli-asset-rewrite@^1.1.0: @@ -1064,8 +1071,8 @@ broccoli-asset-rewrite@^1.1.0: broccoli-filter "^1.2.3" broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: - version "5.7.1" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.1.tgz#e10d831faed1c57e37272e4223748ba71a7926d1" + version "5.7.2" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.2.tgz#756c30544775144e984333b7115f42c916ba08e0" dependencies: babel-core "^5.0.0" broccoli-funnel "^1.0.0" @@ -1078,9 +1085,9 @@ broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: rsvp "^3.5.0" workerpool "^2.2.1" -broccoli-babel-transpiler@^6.0.0: - version "6.1.1" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.1.1.tgz#938f470e1ddb47047a77ef5e38f34c21de0e85a8" +broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2: + version "6.1.2" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.1.2.tgz#26019c045b5ea3e44cfef62821302f9bd483cabd" dependencies: babel-core "^6.14.0" broccoli-funnel "^1.0.0" @@ -1099,7 +1106,7 @@ broccoli-brocfile-loader@^0.18.0: dependencies: findup-sync "^0.4.2" -broccoli-builder@^0.18.3: +broccoli-builder@^0.18.8: version "0.18.8" resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.8.tgz#fe54694d544c3cdfdb01028e802eeca65749a879" dependencies: @@ -1200,8 +1207,8 @@ broccoli-config-replace@^1.1.2: fs-extra "^0.24.0" broccoli-debug@^0.6.1, broccoli-debug@^0.6.2: - version "0.6.2" - resolved "https://registry.npmjs.org/broccoli-debug/-/broccoli-debug-0.6.2.tgz#4c6e89459fc3de7d5d4fc7b77e57f46019f44db1" + version "0.6.3" + resolved "https://registry.npmjs.org/broccoli-debug/-/broccoli-debug-0.6.3.tgz#1f33bb0eacb5db81366f0492524c82b1217eb578" dependencies: broccoli-plugin "^1.2.1" fs-tree-diff "^0.5.2" @@ -1312,21 +1319,24 @@ broccoli-merge-trees@~0.2.3: debug "^2.2.0" symlink-or-copy "^1.0.0" -broccoli-middleware@^1.0.0-beta.8: +broccoli-middleware@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-1.0.0.tgz#92f4e1fb9a791ea986245a7077f35cc648dab097" dependencies: handlebars "^4.0.4" mime "^1.2.11" +broccoli-node-info@1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" + broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0, broccoli-persistent-filter@^1.4.0, broccoli-persistent-filter@^1.4.2: - version "1.4.2" - resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.2.tgz#17af1278a25ff2556f9d7d23e115accfad3a7ce7" + version "1.4.3" + resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz#3511bc52fc53740cda51621f58a28152d9911bc1" dependencies: async-disk-cache "^1.2.1" async-promise-queue "^1.0.3" broccoli-plugin "^1.0.0" - crypto "0.0.3" fs-tree-diff "^0.5.2" hash-for-dep "^1.0.2" heimdalljs "^0.2.1" @@ -1372,7 +1382,7 @@ broccoli-rollup@^1.2.0: symlink-or-copy "^1.1.8" walk-sync "^0.3.1" -broccoli-slow-trees@^3.0.1: +broccoli-slow-trees@3.0.1, broccoli-slow-trees@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" dependencies: @@ -1418,6 +1428,17 @@ broccoli-string-replace@^0.1.1: broccoli-persistent-filter "^1.1.5" minimatch "^3.0.3" +broccoli-test-helper@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/broccoli-test-helper/-/broccoli-test-helper-1.2.0.tgz#d01005d8611fd73ebe1b29552bf052ff59badfb4" + dependencies: + broccoli "^1.1.0" + fixturify "^0.3.2" + fs-tree-diff "^0.5.6" + mktemp "^0.4.0" + rimraf "^2.5.4" + walk-sync "^0.3.1" + broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: version "1.5.2" resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.2.tgz#04f84ab0db539031fa868ccfa563c9932d50cedb" @@ -1449,12 +1470,32 @@ broccoli-yuidoc@^2.1.0: rsvp "~3.1.0" yuidocjs "~0.9.0" +broccoli@^1.1.0: + version "1.1.3" + resolved "https://registry.npmjs.org/broccoli/-/broccoli-1.1.3.tgz#98405e86b7b0e6c268fb8302a006d834d17ed292" + dependencies: + broccoli-node-info "1.1.0" + broccoli-slow-trees "3.0.1" + broccoli-source "^1.1.0" + commander "^2.5.0" + connect "^3.3.3" + copy-dereference "^1.0.0" + findup-sync "^1.0.0" + handlebars "^4.0.4" + heimdalljs-logger "^0.1.7" + mime "^1.2.11" + rimraf "^2.4.3" + rsvp "^3.5.0" + sane "^1.4.1" + tmp "0.0.31" + underscore.string "^3.2.2" + browserslist@^2.1.2: - version "2.1.5" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-2.1.5.tgz#e882550df3d1cd6d481c1a3e0038f2baf13a4711" + version "2.4.0" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-2.4.0.tgz#693ee93d01e66468a6348da5498e011f578f87f8" dependencies: - caniuse-lite "^1.0.30000684" - electron-to-chromium "^1.3.14" + caniuse-lite "^1.0.30000718" + electron-to-chromium "^1.3.18" bser@^2.0.0: version "2.0.0" @@ -1482,17 +1523,17 @@ bytes@1: version "1.0.0" resolved "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" -bytes@2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-2.3.0.tgz#d5b680a165b6201739acb611542aabc2d8ceb070" +bytes@2.5.0: + version "2.5.0" + resolved "https://registry.npmjs.org/bytes/-/bytes-2.5.0.tgz#4c9423ea2d252c270c41b2bdefeff9bb6b62c06a" -bytes@2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" calculate-cache-key-for-tree@^1.0.0, calculate-cache-key-for-tree@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" + resolved "https://registry.npmjs.org/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" dependencies: json-stable-stringify "^1.0.1" @@ -1524,9 +1565,9 @@ can-symlink@^1.0.0: dependencies: tmp "0.0.28" -caniuse-lite@^1.0.30000684: - version "1.0.30000696" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000696.tgz#30f2695d2a01a0dfd779a26ab83f4d134b3da5cc" +caniuse-lite@^1.0.30000718: + version "1.0.30000727" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000727.tgz#20c895768398ded5f98a4beab4a76c285def41d2" capture-exit@^1.1.0: version "1.2.0" @@ -1534,12 +1575,12 @@ capture-exit@^1.1.0: dependencies: rsvp "^3.3.3" -cardinal@^0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/cardinal/-/cardinal-0.5.0.tgz#00d5f661dbd4aabfdf7d41ce48a5a59bca35a291" +cardinal@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" dependencies: ansicolors "~0.2.1" - redeyed "~0.5.0" + redeyed "~1.0.0" center-align@^0.1.1: version "0.1.3" @@ -1582,7 +1623,7 @@ chalk@^0.5.1: strip-ansi "^0.3.0" supports-color "^0.2.0" -chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: +chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -1592,6 +1633,14 @@ chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" +chalk@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" + dependencies: + ansi-styles "^3.1.0" + escape-string-regexp "^1.0.5" + supports-color "^4.0.0" + charm@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" @@ -1615,8 +1664,8 @@ chrome-debugging-client@^0.2.4: ws "^1.0.1" circular-json@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + version "0.3.3" + resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" clean-base-url@^1.0.0: version "1.0.0" @@ -1631,8 +1680,8 @@ clean-css-promise@^0.1.0: pinkie-promise "^2.0.0" clean-css@^3.4.5: - version "3.4.27" - resolved "https://registry.npmjs.org/clean-css/-/clean-css-3.4.27.tgz#adef75b31c160ffa5d72f4de67966e2660c1a255" + version "3.4.28" + resolved "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" dependencies: commander "2.8.x" source-map "0.4.x" @@ -1663,8 +1712,8 @@ cli-table@^0.3.1: colors "1.0.3" cli-width@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + version "2.2.0" + resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" cliui@^2.1.0: version "2.1.0" @@ -1698,6 +1747,16 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" +color-convert@^1.9.0: + version "1.9.0" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" + dependencies: + color-name "^1.1.1" + +color-name@^1.1.1: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + colors@1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" @@ -1738,6 +1797,12 @@ commander@~2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" +common-tags@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/common-tags/-/common-tags-1.4.0.tgz#1187be4f3d4cf0c0427d43f74eef1f73501614c0" + dependencies: + babel-runtime "^6.18.0" + commoner@~0.10.3: version "0.10.8" resolved "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" @@ -1768,22 +1833,23 @@ component-inherit@0.0.3: version "0.0.3" resolved "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" -compressible@~2.0.8: - version "2.0.10" - resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.10.tgz#feda1c7f7617912732b29bf8cf26252a20b9eecd" +compressible@~2.0.10: + version "2.0.11" + resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.11.tgz#16718a75de283ed8e604041625a2064586797d8a" dependencies: - mime-db ">= 1.27.0 < 2" + mime-db ">= 1.29.0 < 2" compression@^1.4.4: - version "1.6.2" - resolved "https://registry.npmjs.org/compression/-/compression-1.6.2.tgz#cceb121ecc9d09c52d7ad0c3350ea93ddd402bc3" + version "1.7.0" + resolved "https://registry.npmjs.org/compression/-/compression-1.7.0.tgz#030c9f198f1643a057d776a738e922da4373012d" dependencies: accepts "~1.3.3" - bytes "2.3.0" - compressible "~2.0.8" - debug "~2.2.0" + bytes "2.5.0" + compressible "~2.0.10" + debug "2.6.8" on-headers "~1.0.1" - vary "~1.1.0" + safe-buffer "5.1.1" + vary "~1.1.1" concat-map@0.0.1: version "0.0.1" @@ -1812,8 +1878,8 @@ configstore@^2.0.0: xdg-basedir "^2.0.0" configstore@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/configstore/-/configstore-3.1.0.tgz#45df907073e26dfa1cf4b2d52f5b60545eaa11d1" + version "3.1.1" + resolved "https://registry.npmjs.org/configstore/-/configstore-3.1.1.tgz#094ee662ab83fad9917678de114faaea8fcdca90" dependencies: dot-prop "^4.1.0" graceful-fs "^4.1.2" @@ -1822,6 +1888,15 @@ configstore@^3.0.0: write-file-atomic "^2.0.0" xdg-basedir "^3.0.0" +connect@^3.3.3: + version "3.6.3" + resolved "https://registry.npmjs.org/connect/-/connect-3.6.3.tgz#f7320d46a25b4be7b483a2236517f24b1e27e301" + dependencies: + debug "2.6.8" + finalhandler "1.0.4" + parseurl "~1.3.1" + utils-merge "1.0.0" + console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" @@ -1845,15 +1920,15 @@ content-disposition@0.5.2: version "0.5.2" resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" -content-type@~1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" +content-type@~1.0.2, content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" continuable-cache@^0.3.1: version "0.3.1" resolved "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" -convert-source-map@^1.1.0: +convert-source-map@^1.1.0, convert-source-map@^1.5.0: version "1.5.0" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" @@ -1873,25 +1948,29 @@ core-js@^1.0.0: version "1.2.7" resolved "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" -core-js@^2.4.0: - version "2.4.1" - resolved "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" +core-js@^2.4.0, core-js@^2.5.0: + version "2.5.1" + resolved "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" + +core-js@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" core-object@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" core-object@^3.1.3: - version "3.1.3" - resolved "https://registry.npmjs.org/core-object/-/core-object-3.1.3.tgz#df399b3311bdb0c909e8aae8929fc3c1c4b25880" + version "3.1.5" + resolved "https://registry.npmjs.org/core-object/-/core-object-3.1.5.tgz#fa627b87502adc98045e44678e9a8ec3b9c0d2a9" dependencies: - chalk "^1.1.3" + chalk "^2.0.0" core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -cross-spawn@^5.0.0, cross-spawn@^5.0.1: +cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -1913,10 +1992,6 @@ crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" -crypto@0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/crypto/-/crypto-0.0.3.tgz#470a81b86be4c5ee17acc8207a1f5315ae20dbb0" - ctype@0.5.3: version "0.5.3" resolved "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" @@ -1931,13 +2006,13 @@ dag-map@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" -debug@2, debug@2.6.8, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0, debug@~2.6.7: +debug@2, debug@2.6.8, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0, debug@^2.6.8, debug@~2.6.7: version "2.6.8" resolved "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" dependencies: ms "2.0.0" -debug@2.2.0, debug@~2.2.0: +debug@2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" dependencies: @@ -1949,12 +2024,6 @@ debug@2.3.3: dependencies: ms "0.7.2" -debug@2.6.7: - version "2.6.7" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e" - dependencies: - ms "2.0.0" - decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -1965,6 +2034,10 @@ deep-eql@^0.1.3: dependencies: type-detect "0.1.1" +deep-freeze@^0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz#3a0b0005de18672819dfd38cd31f91179c893e84" + deep-is@~0.1.3: version "0.1.3" resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -2008,9 +2081,9 @@ delegates@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" -depd@1.1.0, depd@~1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" +depd@1.1.1, depd@~1.1.0, depd@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" destroy@~1.0.4: version "1.0.4" @@ -2048,8 +2121,8 @@ diff@1.4.0: resolved "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" diff@^3.2.0: - version "3.2.0" - resolved "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" + version "3.3.1" + resolved "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" doctrine@^1.2.2: version "1.5.0" @@ -2065,8 +2138,8 @@ dot-prop@^3.0.0: is-obj "^1.0.0" dot-prop@^4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-4.1.1.tgz#a8493f0b7b5eeec82525b5c7587fa7de7ca859c1" + version "4.2.0" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" dependencies: is-obj "^1.0.0" @@ -2078,9 +2151,9 @@ ee-first@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -electron-to-chromium@^1.3.14: - version "1.3.15" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.15.tgz#08397934891cbcfaebbd18b82a95b5a481138369" +electron-to-chromium@^1.3.18: + version "1.3.21" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.21.tgz#a967ebdcfe8ed0083fc244d1894022a8e8113ea2" ember-ajax@^2.4.1: version "2.5.6" @@ -2089,11 +2162,10 @@ ember-ajax@^2.4.1: ember-cli-babel "^5.1.5" ember-cli-app-version@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-3.0.0.tgz#d67a33aeec7bd03187fbe72c5663dadec4c3368a" + version "3.1.0" + resolved "https://registry.npmjs.org/ember-cli-app-version/-/ember-cli-app-version-3.1.0.tgz#074b0330581a7b8ab094ff07fefb34e0d0254bfd" dependencies: - ember-cli-babel "^6.0.0-beta.7" - ember-cli-htmlbars "^1.0.0" + ember-cli-babel "^6.8.0" git-repo-version "0.4.1" ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.2.1: @@ -2106,16 +2178,17 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-c ember-cli-version-checker "^1.0.2" resolve "^1.1.2" -ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.3.0, ember-cli-babel@^6.4.1: - version "6.5.1" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.5.1.tgz#37eaab592523938f8d52fc9d30bd0f56fc1c6599" +ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.4.1, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1: + version "6.8.2" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.8.2.tgz#eac2785964f4743f4c815cd53c6288f00cc087d7" dependencies: - amd-name-resolver "0.0.6" - babel-plugin-debug-macros "^0.1.10" + amd-name-resolver "0.0.7" + babel-plugin-debug-macros "^0.1.11" + babel-plugin-ember-modules-api-polyfill "^2.0.1" babel-plugin-transform-es2015-modules-amd "^6.24.0" babel-polyfill "^6.16.0" babel-preset-env "^1.5.1" - broccoli-babel-transpiler "^6.0.0" + broccoli-babel-transpiler "^6.1.2" broccoli-debug "^0.6.2" broccoli-funnel "^1.0.0" broccoli-source "^1.1.0" @@ -2172,27 +2245,17 @@ ember-cli-get-dependency-depth@^1.0.0: resolved "https://registry.npmjs.org/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" ember-cli-htmlbars-inline-precompile@^0.4.3: - version "0.4.3" - resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.3.tgz#4123f507fea6c59ba4c272ef7e713a6d55ba06c9" + version "0.4.4" + resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.4.tgz#24a7617152630d64a047e553b72e00963a4f8d73" dependencies: babel-plugin-htmlbars-inline-precompile "^0.2.3" ember-cli-version-checker "^2.0.0" hash-for-dep "^1.0.2" silent-error "^1.1.0" -ember-cli-htmlbars@^1.0.0: - version "1.3.3" - resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-1.3.3.tgz#06815262c1577736235bd42ce99db559ce5ebfd1" - dependencies: - broccoli-persistent-filter "^1.0.3" - ember-cli-version-checker "^1.0.2" - hash-for-dep "^1.0.2" - json-stable-stringify "^1.0.0" - strip-bom "^2.0.0" - ember-cli-htmlbars@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-2.0.2.tgz#230a9ace7c3454b3acff2768a50f963813a90c38" + version "2.0.3" + resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-2.0.3.tgz#e116e1500dba12f29c94b05b9ec90f52cb8bb042" dependencies: broccoli-persistent-filter "^1.0.3" hash-for-dep "^1.0.2" @@ -2200,8 +2263,8 @@ ember-cli-htmlbars@^2.0.1: strip-bom "^3.0.0" ember-cli-inject-live-reload@^1.4.1: - version "1.6.1" - resolved "https://registry.npmjs.org/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.6.1.tgz#82b8f5be454815a75e7f6d42c9ce0bc883a914a3" + version "1.7.0" + resolved "https://registry.npmjs.org/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.7.0.tgz#af94336e015336127dfb98080ad442bb233e37ed" ember-cli-internal-test-helpers@^0.8.1: version "0.8.3" @@ -2355,7 +2418,7 @@ ember-cli-valid-component-name@^1.0.0: dependencies: silent-error "^1.0.0" -ember-cli-version-checker@1.3.1, ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7, ember-cli-version-checker@^1.2.0: +ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7, ember-cli-version-checker@^1.2.0: version "1.3.1" resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz#0bc2d134c830142da64bf9627a0eded10b61ae72" dependencies: @@ -2369,23 +2432,23 @@ ember-cli-version-checker@^2.0.0: semver "^5.3.0" ember-cli@^2.11.1: - version "2.13.3" - resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.13.3.tgz#1918500e6280a68be017aca9b69937f6782a24b8" + version "2.15.1" + resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.15.1.tgz#773add3cc18e5068f1c5f43a77544efa2712e47b" dependencies: - amd-name-resolver "0.0.6" + amd-name-resolver "0.0.7" babel-plugin-transform-es2015-modules-amd "^6.24.0" bower-config "^1.3.0" bower-endpoint-parser "0.2.2" broccoli-babel-transpiler "^6.0.0" broccoli-brocfile-loader "^0.18.0" - broccoli-builder "^0.18.3" + broccoli-builder "^0.18.8" broccoli-concat "^3.2.2" broccoli-config-loader "^1.0.0" broccoli-config-replace "^1.1.2" broccoli-funnel "^1.0.6" broccoli-funnel-reducer "^1.0.0" broccoli-merge-trees "^2.0.0" - broccoli-middleware "^1.0.0-beta.8" + broccoli-middleware "^1.0.0" broccoli-source "^1.1.0" broccoli-stew "^1.2.0" calculate-cache-key-for-tree "^1.0.0" @@ -2397,9 +2460,9 @@ ember-cli@^2.11.1: console-ui "^1.0.2" core-object "^3.1.3" dag-map "^2.0.2" + deep-freeze "^0.0.1" diff "^3.2.0" ember-cli-broccoli-sane-watcher "^2.0.4" - ember-cli-get-component-path-option "^1.0.0" ember-cli-is-package-missing "^1.0.0" ember-cli-legacy-blueprints "^0.1.2" ember-cli-lodash-subset "^1.0.11" @@ -2408,14 +2471,13 @@ ember-cli@^2.11.1: ember-cli-string-utils "^1.0.0" ember-try "^0.2.15" ensure-posix-path "^1.0.2" - escape-string-regexp "^1.0.3" - execa "^0.6.0" + execa "^0.7.0" exists-sync "0.0.4" exit "^0.1.2" express "^4.12.3" filesize "^3.1.3" find-up "^2.1.0" - fs-extra "2.0.0" + fs-extra "^3.0.0" fs-tree-diff "^0.5.2" get-caller-file "^1.0.0" git-repo-info "^1.4.1" @@ -2426,14 +2488,14 @@ ember-cli@^2.11.1: heimdalljs-logger "^0.1.7" http-proxy "^1.9.0" inflection "^1.7.0" - is-git-url "^0.2.0" + is-git-url "^1.0.0" isbinaryfile "^3.0.0" js-yaml "^3.6.1" json-stable-stringify "^1.0.1" leek "0.0.24" lodash.template "^4.2.5" markdown-it "^8.3.0" - markdown-it-terminal "0.0.4" + markdown-it-terminal "0.1.0" minimatch "^3.0.0" morgan "^1.8.1" node-modules-path "^1.0.0" @@ -2450,7 +2512,7 @@ ember-cli@^2.11.1: sort-package-json "^1.4.0" symlink-or-copy "^1.1.8" temp "0.8.3" - testem "^1.15.0" + testem "^1.18.0" tiny-lr "^1.0.3" tree-sync "^1.2.1" uuid "^3.0.0" @@ -2465,10 +2527,8 @@ ember-dev@emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed: ember-cli-babel "^5.0.0" ember-disable-prototype-extensions@^1.1.0: - version "1.1.2" - resolved "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.2.tgz#261cccaf6bf8fbb1836be7bdfe4278f9ab92b873" - dependencies: - bower "^1.8.0" + version "1.1.3" + resolved "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" ember-disable-proxy-controllers@^1.0.0: version "1.0.1" @@ -2507,17 +2567,21 @@ ember-qunit@^0.4.18: ember-test-helpers "^0.5.32" ember-resolver@^4.1.0: - version "4.2.1" - resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-4.2.1.tgz#d8aa7de8444ec9b688aa97a5ddbb58c3b949194b" + version "4.5.0" + resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-4.5.0.tgz#9248bf534dfc197fafe3118fff538d436078bf99" dependencies: - "@glimmer/resolver" "0.4.0" + "@glimmer/resolver" "^0.4.1" babel-plugin-debug-macros "^0.1.10" broccoli-funnel "^1.1.0" broccoli-merge-trees "^2.0.0" - ember-cli-babel "^6.3.0" - ember-cli-version-checker "1.3.1" + ember-cli-babel "^6.8.1" + ember-cli-version-checker "^2.0.0" resolve "^1.3.3" +ember-rfc176-data@^0.2.7: + version "0.2.7" + resolved "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.2.7.tgz#bd355bc9b473e08096b518784170a23388bc973b" + ember-router-generator@^1.0.0: version "1.2.3" resolved "https://registry.npmjs.org/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" @@ -2565,8 +2629,8 @@ ember-try-config@^2.0.1: semver "^5.1.0" ember-try@^0.2.15: - version "0.2.15" - resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.15.tgz#559c756058717595babe70068e541625bd5e210a" + version "0.2.17" + resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.17.tgz#0ffff687630291b4cf94f5b196e728c1a92d8aec" dependencies: chalk "^1.0.0" cli-table2 "^0.2.0" @@ -2665,8 +2729,8 @@ error@^7.0.0: xtend "~4.0.0" es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.23" - resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.23.tgz#7578b51be974207a5487821b56538c224e4e7b38" + version "0.10.30" + resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.30.tgz#7141a16836697dbabfaaaeee41495ce29f52c939" dependencies: es6-iterator "2" es6-symbol "~3.1" @@ -2690,6 +2754,10 @@ es6-map@^0.1.3, es6-map@^0.1.4: es6-symbol "~3.1.1" event-emitter "~0.3.5" +es6-promise@~3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" + es6-set@~0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" @@ -2724,7 +2792,7 @@ escape-string-regexp@1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" -escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -2776,16 +2844,12 @@ eslint@^2.13.0: user-home "^2.0.0" espree@^3.1.6: - version "3.4.3" - resolved "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz#2910b5ccd49ce893c2ffffaab4fd8b3a31b82374" + version "3.5.0" + resolved "https://registry.npmjs.org/espree/-/espree-3.5.0.tgz#98358625bdd055861ea27e2867ea729faf463d8d" dependencies: - acorn "^5.0.1" + acorn "^5.1.1" acorn-jsx "^3.0.0" -esprima-fb@~12001.1.0-dev-harmony-fb: - version "12001.1.0-dev-harmony-fb" - resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-12001.1.0-dev-harmony-fb.tgz#d84400384ba95ce2678c617ad24a7f40808da915" - esprima-fb@~15001.1001.0-dev-harmony-fb: version "15001.1001.0-dev-harmony-fb" resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" @@ -2798,7 +2862,15 @@ esprima@^2.6.0: version "2.7.3" resolved "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" -esprima@^3.1.1, esprima@~3.1.0: +esprima@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + +esprima@~3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" + +esprima@~3.1.0: version "3.1.3" resolved "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" @@ -2822,8 +2894,8 @@ esutils@^2.0.0, esutils@^2.0.2: resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" etag@~1.8.0: - version "1.8.0" - resolved "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" + version "1.8.1" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" event-emitter@~0.3.5: version "0.3.5" @@ -2840,15 +2912,19 @@ events-to-array@^1.0.1: version "1.1.2" resolved "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" +events@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + exec-sh@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" + version "0.2.1" + resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" dependencies: merge "^1.1.3" -execa@^0.6.0: - version "0.6.3" - resolved "https://registry.npmjs.org/execa/-/execa-0.6.3.tgz#57b69a594f081759c69e5370f0d17b9cb11658fe" +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" dependencies: cross-spawn "^5.0.1" get-stream "^3.0.0" @@ -2893,8 +2969,8 @@ expand-tilde@^1.2.2: os-homedir "^1.0.1" express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: - version "4.15.3" - resolved "https://registry.npmjs.org/express/-/express-4.15.3.tgz#bab65d0f03aa80c358408972fc700f916944b662" + version "4.15.4" + resolved "https://registry.npmjs.org/express/-/express-4.15.4.tgz#032e2253489cf8fce02666beca3d11ed7a2daed1" dependencies: accepts "~1.3.3" array-flatten "1.1.1" @@ -2902,23 +2978,23 @@ express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: content-type "~1.0.2" cookie "0.3.1" cookie-signature "1.0.6" - debug "2.6.7" - depd "~1.1.0" + debug "2.6.8" + depd "~1.1.1" encodeurl "~1.0.1" escape-html "~1.0.3" etag "~1.8.0" - finalhandler "~1.0.3" + finalhandler "~1.0.4" fresh "0.5.0" merge-descriptors "1.0.1" methods "~1.1.2" on-finished "~2.3.0" parseurl "~1.3.1" path-to-regexp "0.1.7" - proxy-addr "~1.1.4" - qs "6.4.0" + proxy-addr "~1.1.5" + qs "6.5.0" range-parser "~1.2.0" - send "0.15.3" - serve-static "1.12.3" + send "0.15.4" + serve-static "1.12.4" setprototypeof "1.0.3" statuses "~1.3.1" type-is "~1.6.15" @@ -2943,9 +3019,9 @@ extglob@^0.3.1: dependencies: is-extglob "^1.0.0" -fake-xml-http-request@^1.4.0: - version "1.5.0" - resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-1.5.0.tgz#d79602a97043d4d8fea671d5d904af38847b451d" +fake-xml-http-request@^1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-1.6.0.tgz#bd0ac79ae3e2660098282048a12c730a6f64d550" faker@^3.1.0: version "3.1.0" @@ -2962,17 +3038,18 @@ fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: blank-object "^1.0.1" fast-sourcemap-concat@^1.0.1: - version "1.1.0" - resolved "https://registry.npmjs.org/fast-sourcemap-concat/-/fast-sourcemap-concat-1.1.0.tgz#a800767abed5eda02e67238ec063a709be61f9d4" + version "1.2.3" + resolved "https://registry.npmjs.org/fast-sourcemap-concat/-/fast-sourcemap-concat-1.2.3.tgz#22f14e92d739e37920334376ec8433bf675eaa04" dependencies: chalk "^0.5.1" - debug "^2.2.0" fs-extra "^0.30.0" + heimdalljs-logger "^0.1.7" memory-streams "^0.1.0" mkdirp "^0.5.0" rsvp "^3.0.14" source-map "^0.4.2" source-map-url "^0.3.0" + sourcemap-validator "^1.0.5" faye-websocket@~0.10.0: version "0.10.0" @@ -3018,11 +3095,11 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" -finalhandler@~1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.3.tgz#ef47e77950e999780e86022a560e3217e0d0cc89" +finalhandler@1.0.4, finalhandler@~1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.4.tgz#18574f2e7c4b98b8ae3b230c21f201f31bdb3fb7" dependencies: - debug "2.6.7" + debug "2.6.8" encodeurl "~1.0.1" escape-html "~1.0.3" on-finished "~2.3.0" @@ -3056,6 +3133,15 @@ findup-sync@^0.4.2: micromatch "^2.3.7" resolve-dir "^0.1.0" +findup-sync@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-1.0.0.tgz#6f7e4b57b6ee3a4037b4414eaedea3f58f71e0ec" + dependencies: + detect-file "^0.1.0" + is-glob "^2.0.1" + micromatch "^2.3.7" + resolve-dir "^0.1.0" + findup@^0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" @@ -3073,6 +3159,12 @@ fireworm@^0.7.0: lodash.flatten "^3.0.2" minimatch "^3.0.2" +fixturify@^0.3.2: + version "0.3.3" + resolved "https://registry.npmjs.org/fixturify/-/fixturify-0.3.3.tgz#842eaa120564c9881e099ed06dc082a81e97fa71" + dependencies: + fs-extra "^0.30.0" + flat-cache@^1.2.1: version "1.2.2" resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" @@ -3112,8 +3204,8 @@ form-data@~0.1.0: mime "~1.2.11" forwarded@~0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" + version "0.1.1" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.1.tgz#8a4e30c640b05395399a3549c730257728048961" fresh@0.5.0: version "0.5.0" @@ -3123,13 +3215,6 @@ fs-exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" -fs-extra@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-2.0.0.tgz#337352bded4a0b714f3eb84de8cea765e9d37600" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - fs-extra@^0.24.0: version "0.24.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" @@ -3174,6 +3259,14 @@ fs-extra@^2.0.0: graceful-fs "^4.1.2" jsonfile "^2.1.0" +fs-extra@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^3.0.0" + universalify "^0.1.0" + fs-readdir-recursive@^0.1.0: version "0.1.2" resolved "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" @@ -3356,7 +3449,7 @@ globals@^6.4.0: version "6.4.1" resolved "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" -globals@^9.0.0, globals@^9.2.0: +globals@^9.18.0, globals@^9.2.0: version "9.18.0" resolved "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -3429,18 +3522,22 @@ has-cors@1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" hash-for-dep@^1.0.2: - version "1.1.2" - resolved "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.1.2.tgz#e3347ed92960eb0bb53a2c6c2b70e36d75b7cd0c" + version "1.2.0" + resolved "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.2.0.tgz#3bdb883aef0d34e82097ef2f7109b1b401cada6b" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" heimdalljs "^0.2.3" heimdalljs-logger "^0.1.7" - resolve "^1.1.6" + resolve "^1.4.0" hawk@1.1.1: version "1.1.1" @@ -3521,15 +3618,19 @@ hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: version "2.5.0" resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" -http-errors@~1.6.1: - version "1.6.1" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257" +http-errors@1.6.2, http-errors@~1.6.2: + version "1.6.2" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" dependencies: - depd "1.1.0" + depd "1.1.1" inherits "2.0.3" setprototypeof "1.0.3" statuses ">= 1.3.1 < 2" +http-parser-js@>=0.4.0: + version "0.4.6" + resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.6.tgz#195273f58704c452d671076be201329dd341dc55" + http-proxy@^1.13.1, http-proxy@^1.9.0: version "1.16.2" resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" @@ -3553,17 +3654,21 @@ https-proxy-agent@^1.0.0: debug "2" extend "3" -iconv-lite@0.4.15, iconv-lite@^0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13: - version "0.4.15" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" +iconv-lite@0.4.19, iconv-lite@^0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13: + version "0.4.19" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" ieee754@^1.1.4: version "1.1.8" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" ignore@^3.1.2: - version "3.3.3" - resolved "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d" + version "3.3.5" + resolved "https://registry.npmjs.org/ignore/-/ignore-3.3.5.tgz#c4e715455f6073a8d7e5dae72d2fc9d71663dba6" + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" imurmurhash@^0.1.4: version "0.1.4" @@ -3643,7 +3748,7 @@ inquirer@^1.2.3: strip-ansi "^3.0.0" through "^2.3.6" -invariant@^2.2.0, invariant@^2.2.2: +invariant@^2.2.2: version "2.2.2" resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" dependencies: @@ -3653,9 +3758,9 @@ invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" -ipaddr.js@1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec" +ipaddr.js@1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0" is-arrayish@^0.2.1: version "0.2.1" @@ -3709,6 +3814,10 @@ is-git-url@^0.2.0: version "0.2.3" resolved "https://registry.npmjs.org/is-git-url/-/is-git-url-0.2.3.tgz#445200d6fbd6da028fb5e01440d9afc93f3ccb64" +is-git-url@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-git-url/-/is-git-url-1.0.0.tgz#53f684cd143285b52c3244b4e6f28253527af66b" + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -3722,8 +3831,8 @@ is-integer@^1.0.4: is-finite "^1.0.0" is-my-json-valid@^2.10.0: - version "2.16.0" - resolved "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" + version "2.16.1" + resolved "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz#5a846777e2c2620d1e69104e5d3a03b1f6088f11" dependencies: generate-function "^2.0.0" generate-object-property "^1.1.0" @@ -3855,21 +3964,25 @@ js-tokens@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" -js-tokens@^3.0.0: +js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: - version "3.8.4" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6" + version "3.10.0" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" dependencies: argparse "^1.0.7" - esprima "^3.1.1" + esprima "^4.0.0" jsesc@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" +jsesc@~0.3.x: + version "0.3.0" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.3.0.tgz#1bf5ee63b4539fe2e26d0c1e99c240b97a457972" + jsesc@~0.5.0: version "0.5.0" resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" @@ -3903,7 +4016,7 @@ json5@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" -json5@^0.5.0: +json5@^0.5.1: version "0.5.1" resolved "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" @@ -3920,6 +4033,12 @@ jsonfile@^2.1.0: optionalDependencies: graceful-fs "^4.1.6" +jsonfile@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" + optionalDependencies: + graceful-fs "^4.1.6" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -3928,6 +4047,16 @@ jsonpointer@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" +jszip@^3.1.3: + version "3.1.4" + resolved "https://registry.npmjs.org/jszip/-/jszip-3.1.4.tgz#fc323fe41bb1730348d20dd022aa4d8b57cbbcf9" + dependencies: + core-js "~2.3.0" + es6-promise "~3.0.2" + lie "~3.1.0" + pako "~1.0.2" + readable-stream "~2.0.6" + kind-of@^3.0.2: version "3.2.2" resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -3979,6 +4108,12 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +lie@~3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + dependencies: + immediate "~3.0.5" + linkify-it@^2.0.0: version "2.0.3" resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" @@ -4006,8 +4141,8 @@ load-json-file@^1.0.0: strip-bom "^2.0.0" loader.js@^4.5.0: - version "4.5.1" - resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.5.1.tgz#c15ab15a6b8376bd4fbf7ea56f8d76cc557331da" + version "4.6.0" + resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.6.0.tgz#b965663ddbe2d80da482454cb865efe496e93e22" locate-path@^2.0.0: version "2.0.0" @@ -4020,14 +4155,6 @@ lodash-node@^3.2.0: version "3.10.2" resolved "https://registry.npmjs.org/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" -lodash._arraycopy@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" - -lodash._arrayeach@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" - lodash._baseassign@^3.0.0: version "3.2.0" resolved "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" @@ -4035,10 +4162,44 @@ lodash._baseassign@^3.0.0: lodash._basecopy "^3.0.0" lodash.keys "^3.0.0" +lodash._basebind@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._basebind/-/lodash._basebind-2.3.0.tgz#2b5bc452a0e106143b21869f233bdb587417d248" + dependencies: + lodash._basecreate "~2.3.0" + lodash._setbinddata "~2.3.0" + lodash.isobject "~2.3.0" + lodash._basecopy@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" +lodash._basecreate@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz#9b88a86a4dcff7b7f3c61d83a2fcfc0671ec9de0" + dependencies: + lodash._renative "~2.3.0" + lodash.isobject "~2.3.0" + lodash.noop "~2.3.0" + +lodash._basecreatecallback@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz#37b2ab17591a339e988db3259fcd46019d7ac362" + dependencies: + lodash._setbinddata "~2.3.0" + lodash.bind "~2.3.0" + lodash.identity "~2.3.0" + lodash.support "~2.3.0" + +lodash._basecreatewrapper@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz#aa0c61ad96044c3933376131483a9759c3651247" + dependencies: + lodash._basecreate "~2.3.0" + lodash._setbinddata "~2.3.0" + lodash._slice "~2.3.0" + lodash.isobject "~2.3.0" + lodash._baseflatten@^3.0.0: version "3.1.4" resolved "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" @@ -4046,10 +4207,6 @@ lodash._baseflatten@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" -lodash._basefor@^3.0.0: - version "3.0.3" - resolved "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" - lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" @@ -4062,18 +4219,76 @@ lodash._createassigner@^3.0.0: lodash._isiterateecall "^3.0.0" lodash.restparam "^3.0.0" +lodash._createwrapper@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" + dependencies: + lodash._basebind "~2.3.0" + lodash._basecreatewrapper "~2.3.0" + lodash.isfunction "~2.3.0" + +lodash._escapehtmlchar@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.3.0.tgz#d03da6bd82eedf38dc0a5b503d740ecd0e894592" + dependencies: + lodash._htmlescapes "~2.3.0" + +lodash._escapestringchar@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.3.0.tgz#cce73ae60fc6da55d2bf8a0679c23ca2bab149fc" + lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" +lodash._htmlescapes@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._htmlescapes/-/lodash._htmlescapes-2.3.0.tgz#1ca98863cadf1fa1d82c84f35f31e40556a04f3a" + lodash._isiterateecall@^3.0.0: version "3.0.9" resolved "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" +lodash._objecttypes@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz#6a3ea3987dd6eeb8021b2d5c9c303549cc2bae1e" + +lodash._reinterpolate@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-2.3.0.tgz#03ee9d85c0e55cbd590d71608a295bdda51128ec" + lodash._reinterpolate@~3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" +lodash._renative@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._renative/-/lodash._renative-2.3.0.tgz#77d8edd4ced26dd5971f9e15a5f772e4e317fbd3" + +lodash._reunescapedhtml@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.3.0.tgz#db920b55ac7f3ff825939aceb9ba2c231713d24d" + dependencies: + lodash._htmlescapes "~2.3.0" + lodash.keys "~2.3.0" + +lodash._setbinddata@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz#e5610490acd13277d59858d95b5f2727f1508f04" + dependencies: + lodash._renative "~2.3.0" + lodash.noop "~2.3.0" + +lodash._shimkeys@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz#611f93149e3e6c721096b48769ef29537ada8ba9" + dependencies: + lodash._objecttypes "~2.3.0" + +lodash._slice@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash._slice/-/lodash._slice-2.3.0.tgz#147198132859972e4680ca29a5992c855669aa5c" + lodash.assign@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" @@ -4090,6 +4305,14 @@ lodash.assignin@^4.1.0: version "4.2.0" resolved "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" +lodash.bind@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash.bind/-/lodash.bind-2.3.0.tgz#c2a8e18b68e5ecc152e2b168266116fea5b016cc" + dependencies: + lodash._createwrapper "~2.3.0" + lodash._renative "~2.3.0" + lodash._slice "~2.3.0" + lodash.clonedeep@^4.4.1: version "4.5.0" resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -4100,6 +4323,21 @@ lodash.debounce@^3.1.1: dependencies: lodash._getnative "^3.0.0" +lodash.defaults@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-2.3.0.tgz#a832b001f138f3bb9721c2819a2a7cc5ae21ed25" + dependencies: + lodash._objecttypes "~2.3.0" + lodash.keys "~2.3.0" + +lodash.escape@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash.escape/-/lodash.escape-2.3.0.tgz#844c38c58f844e1362ebe96726159b62cf5f2a58" + dependencies: + lodash._escapehtmlchar "~2.3.0" + lodash._reunescapedhtml "~2.3.0" + lodash.keys "~2.3.0" + lodash.find@^4.5.1: version "4.6.0" resolved "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" @@ -4111,6 +4349,25 @@ lodash.flatten@^3.0.2: lodash._baseflatten "^3.0.0" lodash._isiterateecall "^3.0.0" +lodash.foreach@~2.3.x: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-2.3.0.tgz#083404c91e846ee77245fdf9d76519c68b2af168" + dependencies: + lodash._basecreatecallback "~2.3.0" + lodash.forown "~2.3.0" + +lodash.forown@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash.forown/-/lodash.forown-2.3.0.tgz#24fb4aaf800d45fc2dc60bfec3ce04c836a3ad7f" + dependencies: + lodash._basecreatecallback "~2.3.0" + lodash._objecttypes "~2.3.0" + lodash.keys "~2.3.0" + +lodash.identity@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash.identity/-/lodash.identity-2.3.0.tgz#6b01a210c9485355c2a913b48b6711219a173ded" + lodash.isarguments@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" @@ -4119,17 +4376,15 @@ lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" -lodash.isplainobject@^3.0.0: - version "3.2.0" - resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz#9a8238ae16b200432960cd7346512d0123fbf4c5" - dependencies: - lodash._basefor "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.keysin "^3.0.0" +lodash.isfunction@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz#6b2973e47a647cf12e70d676aea13643706e5267" -lodash.istypedarray@^3.0.0: - version "3.0.6" - resolved "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" +lodash.isobject@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.3.0.tgz#2e16d3fc583da9831968953f2d8e6d73434f6799" + dependencies: + lodash._objecttypes "~2.3.0" lodash.keys@^3.0.0: version "3.1.2" @@ -4139,33 +4394,22 @@ lodash.keys@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" -lodash.keysin@^3.0.0: - version "3.0.8" - resolved "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz#22c4493ebbedb1427962a54b445b2c8a767fb47f" - dependencies: - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - -lodash.merge@^3.3.2: - version "3.3.2" - resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz#0d90d93ed637b1878437bb3e21601260d7afe994" +lodash.keys@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.3.0.tgz#b350f4f92caa9f45a4a2ecf018454cf2f28ae253" dependencies: - lodash._arraycopy "^3.0.0" - lodash._arrayeach "^3.0.0" - lodash._createassigner "^3.0.0" - lodash._getnative "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - lodash.isplainobject "^3.0.0" - lodash.istypedarray "^3.0.0" - lodash.keys "^3.0.0" - lodash.keysin "^3.0.0" - lodash.toplainobject "^3.0.0" + lodash._renative "~2.3.0" + lodash._shimkeys "~2.3.0" + lodash.isobject "~2.3.0" -lodash.merge@^4.3.0, lodash.merge@^4.4.0, lodash.merge@^4.5.1: +lodash.merge@^4.3.0, lodash.merge@^4.4.0, lodash.merge@^4.5.1, lodash.merge@^4.6.0: version "4.6.0" resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" +lodash.noop@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash.noop/-/lodash.noop-2.3.0.tgz#3059d628d51bbf937cd2a0b6fc3a7f212a669c2c" + lodash.omit@^4.1.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" @@ -4174,6 +4418,12 @@ lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" +lodash.support@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash.support/-/lodash.support-2.3.0.tgz#7eaf038af4f0d6aab776b44aa6dcfc80334c9bfd" + dependencies: + lodash._renative "~2.3.0" + lodash.template@^4.2.5: version "4.4.0" resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" @@ -4181,28 +4431,50 @@ lodash.template@^4.2.5: lodash._reinterpolate "~3.0.0" lodash.templatesettings "^4.0.0" +lodash.template@~2.3.x: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-2.3.0.tgz#4e3e29c433b4cfea675ec835e6f12391c61fd22b" + dependencies: + lodash._escapestringchar "~2.3.0" + lodash._reinterpolate "~2.3.0" + lodash.defaults "~2.3.0" + lodash.escape "~2.3.0" + lodash.keys "~2.3.0" + lodash.templatesettings "~2.3.0" + lodash.values "~2.3.0" + lodash.templatesettings@^4.0.0: version "4.1.0" resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" dependencies: lodash._reinterpolate "~3.0.0" -lodash.toplainobject@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz#28790ad942d293d78aa663a07ecf7f52ca04198d" +lodash.templatesettings@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-2.3.0.tgz#303d132c342710040d5a18efaa2d572fd03f8cdc" dependencies: - lodash._basecopy "^3.0.0" - lodash.keysin "^3.0.0" + lodash._reinterpolate "~2.3.0" + lodash.escape "~2.3.0" lodash.uniq@^4.2.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" +lodash.uniqby@^4.7.0: + version "4.7.0" + resolved "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" + +lodash.values@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/lodash.values/-/lodash.values-2.3.0.tgz#ca96fbe60a20b0b0ec2ba2ba5fc6a765bd14a3ba" + dependencies: + lodash.keys "~2.3.0" + lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.16.1, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.16.1, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1: version "4.17.4" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -4243,17 +4515,17 @@ makeerror@1.0.x: dependencies: tmpl "1.0.x" -markdown-it-terminal@0.0.4: - version "0.0.4" - resolved "https://registry.npmjs.org/markdown-it-terminal/-/markdown-it-terminal-0.0.4.tgz#3f2ce624ba2ca964a78b8b388d605ee330de9ced" +markdown-it-terminal@0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/markdown-it-terminal/-/markdown-it-terminal-0.1.0.tgz#545abd8dd01c3d62353bfcea71db580b51d22bd9" dependencies: - ansi-styles "^2.1.0" - cardinal "^0.5.0" + ansi-styles "^3.0.0" + cardinal "^1.0.0" cli-table "^0.3.1" - lodash.merge "^3.3.2" - markdown-it "^4.4.0" + lodash.merge "^4.6.0" + markdown-it "^8.3.1" -markdown-it@^4.3.0, markdown-it@^4.4.0: +markdown-it@^4.3.0: version "4.4.0" resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" dependencies: @@ -4263,9 +4535,9 @@ markdown-it@^4.3.0, markdown-it@^4.4.0: mdurl "~1.0.0" uc.micro "^1.0.0" -markdown-it@^8.3.0: - version "8.3.1" - resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-8.3.1.tgz#2f4b622948ccdc193d66f3ca2d43125ac4ac7323" +markdown-it@^8.3.0, markdown-it@^8.3.1: + version "8.4.0" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.0.tgz#e2400881bf171f7018ed1bd9da441dac8af6306d" dependencies: argparse "^1.0.7" entities "~1.1.1" @@ -4273,7 +4545,7 @@ markdown-it@^8.3.0: mdurl "^1.0.1" uc.micro "^1.0.3" -matcher-collection@^1.0.0, matcher-collection@^1.0.1: +matcher-collection@^1.0.0: version "1.0.4" resolved "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.4.tgz#2f66ae0869996f29e43d0b62c83dd1d43e581755" dependencies: @@ -4348,31 +4620,27 @@ micromatch@^2.1.5, micromatch@^2.3.7: parse-glob "^3.0.4" regex-cache "^0.4.2" -"mime-db@>= 1.27.0 < 2": - version "1.28.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.28.0.tgz#fedd349be06d2865b7fc57d837c6de4f17d7ac3c" - -mime-db@~1.27.0: - version "1.27.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" +"mime-db@>= 1.29.0 < 2", mime-db@~1.30.0: + version "1.30.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" mime-types@~1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" -mime-types@~2.1.11, mime-types@~2.1.15: - version "2.1.15" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" +mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.16: + version "2.1.17" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" dependencies: - mime-db "~1.27.0" + mime-db "~1.30.0" mime@1.3.4: version "1.3.4" resolved "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" mime@^1.2.11: - version "1.3.6" - resolved "https://registry.npmjs.org/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0" + version "1.4.0" + resolved "https://registry.npmjs.org/mime/-/mime-1.4.0.tgz#69e9e0db51d44f2a3b56e48b7817d7d137f1a343" mime@~1.2.11: version "1.2.11" @@ -4494,8 +4762,8 @@ negotiator@0.6.1: resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" node-fetch@^1.3.3: - version "1.7.1" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz#899cb3d0a3c92f952c47f1b876f4c8aeabd400d5" + version "1.7.3" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" dependencies: encoding "^0.1.11" is-stream "^1.0.1" @@ -4536,7 +4804,7 @@ normalize-package-data@^2.3.2: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.1: +normalize-path@^2.0.0, normalize-path@^2.0.1: version "2.1.1" resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: @@ -4580,7 +4848,7 @@ object-assign@4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -4693,6 +4961,10 @@ p-locate@^2.0.0: dependencies: p-limit "^1.1.0" +pako@~1.0.2: + version "1.0.6" + resolved "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -4731,8 +5003,8 @@ parseuri@0.0.5: better-assert "~1.0.0" parseurl@~1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + version "1.3.2" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" path-exists@^1.0.0: version "1.0.0" @@ -4748,7 +5020,7 @@ path-exists@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" -path-is-absolute@^1.0.0: +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -4819,17 +5091,17 @@ preserve@^0.2.0: resolved "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" pretender@^1.4.2: - version "1.4.2" - resolved "https://registry.npmjs.org/pretender/-/pretender-1.4.2.tgz#dde9995dfdf75b28a3dd7a73cde2f9f612e5e8f4" + version "1.5.1" + resolved "https://registry.npmjs.org/pretender/-/pretender-1.5.1.tgz#bd9098c03d39c3bc7dcb84a28ee27e096e2e32b8" dependencies: - fake-xml-http-request "^1.4.0" - route-recognizer "^0.2.3" + fake-xml-http-request "^1.6.0" + route-recognizer "^0.3.3" printf@^0.2.3: version "0.2.5" resolved "https://registry.npmjs.org/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" -private@^0.1.6, private@~0.1.5: +private@^0.1.6, private@^0.1.7, private@~0.1.5: version "0.1.7" resolved "https://registry.npmjs.org/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" @@ -4853,12 +5125,12 @@ promise-map-series@^0.2.1: dependencies: rsvp "^3.0.14" -proxy-addr@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" +proxy-addr@~1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz#71c0ee3b102de3f202f3b64f608d173fcba1a918" dependencies: forwarded "~0.1.0" - ipaddr.js "1.3.0" + ipaddr.js "1.4.0" pseudomap@^1.0.2: version "1.0.2" @@ -4876,9 +5148,13 @@ q@^1.1.2: version "1.5.0" resolved "https://registry.npmjs.org/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" -qs@6.4.0, qs@^6.4.0: - version "6.4.0" - resolved "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" +qs@6.5.0, qs@^6.4.0: + version "6.5.0" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz#8d04954d364def3efc55b5a0793e1e2c8b1e6e49" + +qs@6.5.1: + version "6.5.1" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" qs@~1.0.0: version "1.0.2" @@ -4915,6 +5191,15 @@ range-parser@~1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" +raw-body@2.3.2: + version "2.3.2" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" + dependencies: + bytes "3.0.0" + http-errors "1.6.2" + iconv-lite "0.4.19" + unpipe "1.0.0" + raw-body@~1.1.0: version "1.1.7" resolved "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" @@ -4922,14 +5207,6 @@ raw-body@~1.1.0: bytes "1" string_decoder "0.10" -raw-body@~2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" - dependencies: - bytes "2.4.0" - iconv-lite "0.4.15" - unpipe "1.0.0" - read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -4966,6 +5243,17 @@ readable-stream@~1.0.2: isarray "0.0.1" string_decoder "~0.10.x" +readable-stream@~2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + readline2@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" @@ -5001,23 +5289,27 @@ recast@^0.11.17, recast@^0.11.3: private "~0.1.5" source-map "~0.5.0" -redeyed@~0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/redeyed/-/redeyed-0.5.0.tgz#7ab000e60ee3875ac115d29edb32c1403c6c25d1" +redeyed@~1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" dependencies: - esprima-fb "~12001.1.0-dev-harmony-fb" + esprima "~3.0.0" regenerate@^1.2.1: version "1.3.2" resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" -regenerator-runtime@^0.10.0: +regenerator-runtime@^0.10.5: version "0.10.5" resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" -regenerator-transform@0.9.11: - version "0.9.11" - resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.9.11.tgz#3a7d067520cb7b7176769eb5ff868691befe1283" +regenerator-runtime@^0.11.0: + version "0.11.0" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" + +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" dependencies: babel-runtime "^6.18.0" babel-types "^6.19.0" @@ -5035,11 +5327,10 @@ regenerator@0.8.40: through "~2.3.8" regex-cache@^0.4.2: - version "0.4.3" - resolved "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + version "0.4.4" + resolved "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" dependencies: is-equal-shallow "^0.1.3" - is-primitive "^2.0.0" regexpu-core@^2.0.0: version "2.0.0" @@ -5070,8 +5361,8 @@ regjsparser@^0.1.4: jsesc "~0.5.0" remove-trailing-separator@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz#69b062d978727ad14dc6b56ba4ab772fd8d70511" + version "1.1.0" + resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" repeat-element@^1.1.2: version "1.1.2" @@ -5142,9 +5433,9 @@ resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" -resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3: - version "1.3.3" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" +resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" dependencies: path-parse "^1.0.5" @@ -5161,15 +5452,15 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2.5.2, rimraf@^2.4.3, rimraf@^2.4.4: +rimraf@2.5.2, rimraf@^2.4.3: version "2.5.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" -rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: - version "2.6.1" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" +rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: + version "2.6.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: glob "^7.0.5" @@ -5183,9 +5474,9 @@ rollup@^0.41.4: dependencies: source-map-support "^0.4.0" -route-recognizer@^0.2.3: - version "0.2.10" - resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.2.10.tgz#024b2283c2e68d13a7c7f5173a5924645e8902df" +route-recognizer@^0.3.3: + version "0.3.3" + resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" rsvp@3.6.0, rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0, rsvp@^3.5.0: version "3.6.0" @@ -5223,7 +5514,7 @@ rx@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" -safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -5231,7 +5522,7 @@ safe-json-parse@~1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" -sane@^1.1.1, sane@^1.6.0: +sane@^1.1.1, sane@^1.4.1, sane@^1.6.0: version "1.7.0" resolved "https://registry.npmjs.org/sane/-/sane-1.7.0.tgz#b3579bccb45c94cf20355cc81124990dfd346e30" dependencies: @@ -5248,17 +5539,17 @@ sax@1.2.1, sax@>=0.6.0: resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" selenium-webdriver@^3.0.0-beta-2: - version "3.4.0" - resolved "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.4.0.tgz#151f7445294da6a66c49cc300747a2a17e53c52a" + version "3.5.0" + resolved "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.5.0.tgz#9036c82874e6c0f5cbff0a0f18223bc31c99cb77" dependencies: - adm-zip "^0.4.7" + jszip "^3.1.3" rimraf "^2.5.4" tmp "0.0.30" xml2js "^0.4.17" "semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0: - version "5.3.0" - resolved "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + version "5.4.1" + resolved "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" semver@^4.1.0, semver@^4.3.1: version "4.3.6" @@ -5268,32 +5559,32 @@ semver@~5.0.1: version "5.0.3" resolved "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" -send@0.15.3: - version "0.15.3" - resolved "https://registry.npmjs.org/send/-/send-0.15.3.tgz#5013f9f99023df50d1bd9892c19e3defd1d53309" +send@0.15.4: + version "0.15.4" + resolved "https://registry.npmjs.org/send/-/send-0.15.4.tgz#985faa3e284b0273c793364a35c6737bd93905b9" dependencies: - debug "2.6.7" - depd "~1.1.0" + debug "2.6.8" + 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" - http-errors "~1.6.1" + http-errors "~1.6.2" mime "1.3.4" ms "2.0.0" on-finished "~2.3.0" range-parser "~1.2.0" statuses "~1.3.1" -serve-static@1.12.3: - version "1.12.3" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.12.3.tgz#9f4ba19e2f3030c547f8af99107838ec38d5b1e2" +serve-static@1.12.4: + version "1.12.4" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.12.4.tgz#9b6aa98eeb7253c4eedc4c1f6fdbca609901a961" dependencies: encodeurl "~1.0.1" escape-html "~1.0.3" parseurl "~1.3.1" - send "0.15.3" + send "0.15.4" set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" @@ -5318,14 +5609,14 @@ shelljs@^0.6.0: resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" shellwords@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.0.tgz#66afd47b6a12932d9071cbfd98a52e785cd0ba14" + version "0.1.1" + resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" sigmund@~1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" -signal-exit@^3.0.0: +signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -5414,8 +5705,8 @@ sort-object-keys@^1.1.1: resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" sort-package-json@^1.4.0: - version "1.7.0" - resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.7.0.tgz#13b362ff6400c5b4eaa9ba220f9ea7c3d6644b5f" + version "1.7.1" + resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.7.1.tgz#f2e5fbffe8420cc1bb04485f4509f05e73b4c0f2" dependencies: sort-object-keys "^1.1.1" @@ -5425,9 +5716,9 @@ source-map-support@^0.2.10: dependencies: source-map "0.1.32" -source-map-support@^0.4.0, source-map-support@^0.4.2: - version "0.4.15" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" +source-map-support@^0.4.0, source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" dependencies: source-map "^0.5.6" @@ -5435,7 +5726,7 @@ source-map-url@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" -source-map@0.1.32: +source-map@0.1.32, source-map@~0.1.x: version "0.1.32" resolved "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" dependencies: @@ -5448,8 +5739,17 @@ source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: amdefine ">=0.0.4" source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: - version "0.5.6" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + version "0.5.7" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +sourcemap-validator@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/sourcemap-validator/-/sourcemap-validator-1.0.5.tgz#f9b960f48c6469e288a19af305f005da3dc1df3a" + dependencies: + jsesc "~0.3.x" + lodash.foreach "~2.3.x" + lodash.template "~2.3.x" + source-map "~0.1.x" spawn-args@^0.2.0: version "0.2.0" @@ -5480,7 +5780,11 @@ spdx-license-ids@^1.0.2: version "1.2.2" resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" -sprintf-js@^1.0.3, sprintf-js@~1.0.2: +sprintf-js@^1.0.3: + version "1.1.1" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" + +sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -5513,8 +5817,8 @@ string-width@^1.0.1, string-width@^1.0.2: strip-ansi "^3.0.0" string-width@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz#030664561fc146c9423ec7d978fe2457437fe6d0" + version "2.1.1" + resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" @@ -5599,6 +5903,12 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" +supports-color@^4.0.0: + version "4.4.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" + dependencies: + has-flag "^2.0.0" + symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: version "1.1.8" resolved "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" @@ -5630,16 +5940,16 @@ temp@0.8.3: os-tmpdir "^1.0.0" rimraf "~2.2.6" -testem@^1.15.0: - version "1.15.0" - resolved "https://registry.npmjs.org/testem/-/testem-1.15.0.tgz#2e3a9e7ac29f16a20f718eb0c4b12e7a44900675" +testem@^1.15.0, testem@^1.18.0: + version "1.18.4" + resolved "https://registry.npmjs.org/testem/-/testem-1.18.4.tgz#e45fed922bec2f54a616c43f11922598ac97eb41" dependencies: backbone "^1.1.2" bluebird "^3.4.6" charm "^1.0.0" commander "^2.6.0" consolidate "^0.14.0" - cross-spawn "^5.0.0" + cross-spawn "^5.1.0" express "^4.10.7" fireworm "^0.7.0" glob "^7.0.4" @@ -5648,6 +5958,7 @@ testem@^1.15.0: lodash.assignin "^4.1.0" lodash.clonedeep "^4.4.1" lodash.find "^4.5.1" + lodash.uniqby "^4.7.0" mkdirp "^0.5.1" mustache "^2.2.1" node-notifier "^5.0.1" @@ -5702,6 +6013,12 @@ tmp@0.0.30: dependencies: os-tmpdir "~1.0.1" +tmp@0.0.31: + version "0.0.31" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" + dependencies: + os-tmpdir "~1.0.1" + tmp@^0.0.29: version "0.0.29" resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" @@ -5716,7 +6033,7 @@ to-array@0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" -to-fast-properties@^1.0.0, to-fast-properties@^1.0.1: +to-fast-properties@^1.0.0, to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" @@ -5802,7 +6119,7 @@ ultron@1.0.x: version "1.0.2" resolved "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" -underscore.string@~3.3.4: +underscore.string@^3.2.2, underscore.string@~3.3.4: version "3.3.4" resolved "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" dependencies: @@ -5819,6 +6136,10 @@ unique-string@^1.0.0: dependencies: crypto-random-string "^1.0.0" +universalify@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -5883,7 +6204,7 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" -vary@~1.1.0, vary@~1.1.1: +vary@~1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" @@ -5916,22 +6237,23 @@ watch@~0.10.0: resolved "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" websocket-driver@>=0.5.1: - version "0.6.5" - resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" + version "0.7.0" + resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" dependencies: + http-parser-js ">=0.4.0" websocket-extensions ">=0.1.1" websocket-extensions@>=0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" + version "0.1.2" + resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.2.tgz#0e18781de629a18308ce1481650f67ffa2693a5d" which-module@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" which@^1.2.12, which@^1.2.9: - version "1.2.14" - resolved "https://registry.npmjs.org/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" + version "1.3.0" + resolved "https://registry.npmjs.org/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" dependencies: isexe "^2.0.0" @@ -5966,10 +6288,10 @@ wordwrap@~1.0.0: resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" workerpool@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/workerpool/-/workerpool-2.2.1.tgz#41ebff11d5859da948fdb2c850b57da69240988a" + version "2.2.4" + resolved "https://registry.npmjs.org/workerpool/-/workerpool-2.2.4.tgz#c9dbe01e103e92df0e8f55356fc860135fbd43b0" dependencies: - object-assign "^4.1.1" + object-assign "4.1.1" wrap-ansi@^2.0.0: version "2.1.0" @@ -5991,12 +6313,12 @@ write-file-atomic@^1.1.2: slide "^1.1.5" write-file-atomic@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.1.0.tgz#1769f4b551eedce419f0505deae2e26763542d37" + version "2.3.0" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" - slide "^1.1.5" + signal-exit "^3.0.2" write@^0.2.1: version "0.2.1" @@ -6032,19 +6354,30 @@ xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" -xml2js@0.4.17, xml2js@^0.4.17: +xml2js@0.4.17: version "0.4.17" resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" dependencies: sax ">=0.6.0" xmlbuilder "^4.1.0" +xml2js@^0.4.17: + version "0.4.19" + resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + dependencies: + sax ">=0.6.0" + xmlbuilder "~9.0.1" + xmlbuilder@4.2.1, xmlbuilder@^4.1.0: version "4.2.1" resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" dependencies: lodash "^4.0.0" +xmlbuilder@~9.0.1: + version "9.0.4" + resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz#519cb4ca686d005a8420d3496f3f0caeecca580f" + xmldom@^0.1.19: version "0.1.27" resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" From 82b2faa1557b66acff1f0dfd8bfe99332b5999b7 Mon Sep 17 00:00:00 2001 From: Kelly Selden Date: Fri, 15 Sep 2017 13:13:03 -0700 Subject: [PATCH 2029/2527] fix node 4 --- lib/transforms/babel-plugin-remove-imports.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/transforms/babel-plugin-remove-imports.js b/lib/transforms/babel-plugin-remove-imports.js index f112df29877..2b4b92631ab 100644 --- a/lib/transforms/babel-plugin-remove-imports.js +++ b/lib/transforms/babel-plugin-remove-imports.js @@ -1,3 +1,5 @@ +'use strict'; + function PluginRemoveFilteredImports() { var importDeclarationsToRemove; var filteredImports; From 056a1c987401c439d3a5c18fcf40d706e299031b Mon Sep 17 00:00:00 2001 From: Luke Melia Date: Fri, 15 Sep 2017 19:32:20 -0400 Subject: [PATCH 2030/2527] [BUGFIX beta] Ignore included resources without that don't have a corresponding ember-data model When the JSON API serializer encounters a resource with a type that doesn't resolve to one of the application's Ember Data models, it replaces the object with `null` and emits a warning. Prior to this commit, if that `null` was one of the sideloaded (i.e. `included`) resources, the store would throw trying to get the `null`'s type. This commit makes the serializer drops any nulls out of the list of included resources to avoid this problem. To summarize, if your API attempts to include resources that you don't have models for, a warning will be emitted and they will be ignored. Fixes #4568 --- addon/serializers/json-api.js | 8 ++- .../serializers/json-api-serializer-test.js | 65 +++++++++++++++++++ 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 19ca539bb1e..e7cd457bbd0 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -152,11 +152,13 @@ const JSONAPISerializer = JSONSerializer.extend({ } if (Array.isArray(documentHash.included)) { - let ret = new Array(documentHash.included.length); - + let ret = new Array(); for (let i = 0; i < documentHash.included.length; i++) { let included = documentHash.included[i]; - ret[i] = this._normalizeResourceHelper(included); + let normalized = this._normalizeResourceHelper(included); + if (normalized !== null) { // can be null when unknown type is encountered + ret.push(normalized); + } } documentHash.included = ret; diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index a597ca058c8..700432645c9 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -138,6 +138,71 @@ testInDebug('Warns when normalizing an unknown type', function(assert) { }, /Encountered a resource object with type "UnknownType", but no model was found for model name "unknown-type"/); }); +testInDebug('Warns when normalizing payload with unknown type included', function(assert) { + var documentHash = { + data: { + type: 'users', + id: '1', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz' + }, + relationships: { + company: { + data: { type: 'unknown-types', id: '2' } + } + } + }, + included: [{ + type: 'unknown-types', + id: '2', + attributes: { + name: 'WyKittens' + } + }] + }; + + assert.expectWarning(function() { + run(function() { + env.store.serializerFor('user').normalizeResponse(env.store, User, documentHash, '1', 'findRecord'); + }); + }, /Encountered a resource object with type "unknown-types", but no model was found for model name "unknown-type"/); +}); + +testInDebug('Warns but does not fail when pushing payload with unknown type included', function(assert) { + var documentHash = { + data: { + type: 'users', + id: '1', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz' + }, + relationships: { + company: { + data: { type: 'unknown-types', id: '2' } + } + } + }, + included: [{ + type: 'unknown-types', + id: '2', + attributes: { + name: 'WyKittens' + } + }] + }; + + assert.expectWarning(function() { + run(function() { + env.store.pushPayload(documentHash); + }); + }, /Encountered a resource object with type "unknown-types", but no model was found for model name "unknown-type"/); + + var user = store.peekRecord('user', 1); + assert.equal(get(user, 'firstName'), 'Yehuda', 'firstName is correct'); +}); + testInDebug('Warns when normalizing with type missing', function(assert) { var documentHash = { data: { From 2df635418af0fb5901f5c77befef6dd19604bff7 Mon Sep 17 00:00:00 2001 From: Gabriel Grant Date: Mon, 18 Sep 2017 12:59:06 -0700 Subject: [PATCH 2031/2527] [DOCS release] Add missing "relationship" field to RESTAdapter.findBelongsTo docs --- addon/adapters/rest.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 6ab765533ea..9f6811a7b8c 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -728,6 +728,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @param {DS.Store} store @param {DS.Snapshot} snapshot @param {String} url + @param {Object} relationship meta object describing the relationship @return {Promise} promise */ findBelongsTo(store, snapshot, url, relationship) { From 6c5f6ceac1fb7358babe391648c02184b809ecff Mon Sep 17 00:00:00 2001 From: Dave Lowensohn Date: Thu, 21 Sep 2017 09:44:59 -0700 Subject: [PATCH 2032/2527] Update LICENSE through 2017 --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 1db12779883..c8edbcee40c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2011-2016 Tilde, Inc. and contributors. +Copyright (C) 2011-2017 Tilde, Inc. and contributors. Portions Copyright (C) 2011 LivingSocial Inc. Permission is hereby granted, free of charge, to any person obtaining a copy From 5bff176f54eb7e2a337f7b6e6db24a66cfd2bc26 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sat, 29 Jul 2017 18:46:12 -0400 Subject: [PATCH 2033/2527] Remove feature flagging for ds-extended-errors. The feature was enabled in ember-data@2.13, the feature flagging can now be removed. This is a work around to a bug in the feature flagging system used by ember-data, that will need to be fixed on master branch. --- FEATURES.md | 16 --- addon/-private/adapters/errors.js | 31 +---- addon/adapters/rest.js | 28 ++-- addon/index.js | 13 +- config/features.json | 1 - .../integration/adapter/rest-adapter-test.js | 106 +++++++-------- tests/unit/adapter-errors-test.js | 125 +++++++++--------- 7 files changed, 140 insertions(+), 180 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 19c8a44abdf..2d566c89c37 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -22,22 +22,6 @@ entry in `config/features.json`. Enables `pushPayload` to return the model(s) that are created or updated via the internal `store.push`. -- `ds-extended-errors` [#3586](https://github.com/emberjs/data/pull/3586) [#4287](https://github.com/emberjs/data/pull/4287) - - Enables `extend` method on errors. It means you can extend from `DS.AdapterError`. - - ```js - const MyCustomError = DS.AdapterError.extend({ message: "My custom error." }); - ``` - - It will also add a few new errors to rest adapter based on http status. - - * [401] `DS.UnauthorizedError` - * [403] `DS.ForbiddenError` - * [404] `DS.NotFoundError` - * [409] `DS.ConflictError` - * [500] `DS.ServerError` - - `ds-payload-type-hooks` [#4318](https://github.com/emberjs/data/pull/4318) Adds two new hooks `modelNameFromPayloadType` and `payloadTypeFromModelName` diff --git a/addon/-private/adapters/errors.js b/addon/-private/adapters/errors.js index 085df8d7892..aa0c35a43a3 100644 --- a/addon/-private/adapters/errors.js +++ b/addon/-private/adapters/errors.js @@ -1,8 +1,6 @@ import Ember from 'ember'; import { assert } from '@ember/debug'; -import isEnabled from '../features'; - const EmberError = Ember.Error; const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/; @@ -88,11 +86,6 @@ export function AdapterError(errors, message = 'Adapter operation failed') { ]; } -let extendedErrorsEnabled = false; -if (isEnabled('ds-extended-errors')) { - extendedErrorsEnabled = true; -} - function extendFn(ErrorClass) { return function({ message: defaultMessage } = {}) { return extend(ErrorClass, defaultMessage); @@ -105,19 +98,14 @@ function extend(ParentErrorClass, defaultMessage) { ParentErrorClass.call(this, errors, message || defaultMessage); }; ErrorClass.prototype = Object.create(ParentErrorClass.prototype); - - if (extendedErrorsEnabled) { - ErrorClass.extend = extendFn(ErrorClass); - } + ErrorClass.extend = extendFn(ErrorClass); return ErrorClass; } AdapterError.prototype = Object.create(EmberError.prototype); -if (extendedErrorsEnabled) { - AdapterError.extend = extendFn(AdapterError); -} +AdapterError.extend = extendFn(AdapterError); /** A `DS.InvalidError` is used by an adapter to signal the external API @@ -260,8 +248,7 @@ export const AbortError = extend(AdapterError, @class UnauthorizedError @namespace DS */ -export const UnauthorizedError = extendedErrorsEnabled ? - extend(AdapterError, 'The adapter operation is unauthorized') : null; +export const UnauthorizedError = extend(AdapterError, 'The adapter operation is unauthorized'); /** A `DS.ForbiddenError` equates to a HTTP `403 Forbidden` response status. @@ -273,8 +260,7 @@ export const UnauthorizedError = extendedErrorsEnabled ? @class ForbiddenError @namespace DS */ -export const ForbiddenError = extendedErrorsEnabled ? - extend(AdapterError, 'The adapter operation is forbidden') : null; +export const ForbiddenError = extend(AdapterError, 'The adapter operation is forbidden'); /** A `DS.NotFoundError` equates to a HTTP `404 Not Found` response status. @@ -312,8 +298,7 @@ export const ForbiddenError = extendedErrorsEnabled ? @class NotFoundError @namespace DS */ -export const NotFoundError = extendedErrorsEnabled ? - extend(AdapterError, 'The adapter could not find the resource') : null; +export const NotFoundError = extend(AdapterError, 'The adapter could not find the resource'); /** A `DS.ConflictError` equates to a HTTP `409 Conflict` response status. @@ -325,8 +310,7 @@ export const NotFoundError = extendedErrorsEnabled ? @class ConflictError @namespace DS */ -export const ConflictError = extendedErrorsEnabled ? - extend(AdapterError, 'The adapter operation failed due to a conflict') : null; +export const ConflictError = extend(AdapterError, 'The adapter operation failed due to a conflict'); /** A `DS.ServerError` equates to a HTTP `500 Internal Server Error` response @@ -336,8 +320,7 @@ export const ConflictError = extendedErrorsEnabled ? @class ServerError @namespace DS */ -export const ServerError = extendedErrorsEnabled ? - extend(AdapterError, 'The adapter operation failed due to a server error') : null; +export const ServerError = extend(AdapterError, 'The adapter operation failed due to a server error'); /** Convert an hash of errors into an array with errors in JSON-API format. diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 9f6811a7b8c..b58f870b6a4 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -973,21 +973,19 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { let errors = this.normalizeErrorResponse(status, headers, payload); let detailedMessage = this.generatedDetailedMessage(status, headers, payload, requestData); - if (isEnabled('ds-extended-errors')) { - switch (status) { - case 401: - return new UnauthorizedError(errors, detailedMessage); - case 403: - return new ForbiddenError(errors, detailedMessage); - case 404: - return new NotFoundError(errors, detailedMessage); - case 409: - return new ConflictError(errors, detailedMessage); - default: - if (status >= 500) { - return new ServerError(errors, detailedMessage); - } - } + switch (status) { + case 401: + return new UnauthorizedError(errors, detailedMessage); + case 403: + return new ForbiddenError(errors, detailedMessage); + case 404: + return new NotFoundError(errors, detailedMessage); + case 409: + return new ConflictError(errors, detailedMessage); + default: + if (status >= 500) { + return new ServerError(errors, detailedMessage); + } } return new AdapterError(errors, detailedMessage); diff --git a/addon/index.js b/addon/index.js index db1ed47ba1f..a6c0497d9d9 100644 --- a/addon/index.js +++ b/addon/index.js @@ -22,7 +22,6 @@ import { belongsTo, hasMany, global, - isEnabled, Errors, RootState, Model, @@ -93,13 +92,11 @@ DS.InvalidError = InvalidError; DS.TimeoutError = TimeoutError; DS.AbortError = AbortError; -if (isEnabled('ds-extended-errors')) { - DS.UnauthorizedError = UnauthorizedError; - DS.ForbiddenError = ForbiddenError; - DS.NotFoundError = NotFoundError; - DS.ConflictError = ConflictError; - DS.ServerError = ServerError; -} +DS.UnauthorizedError = UnauthorizedError; +DS.ForbiddenError = ForbiddenError; +DS.NotFoundError = NotFoundError; +DS.ConflictError = ConflictError; +DS.ServerError = ServerError; DS.errorsHashToArray = errorsHashToArray; DS.errorsArrayToHash = errorsArrayToHash; diff --git a/config/features.json b/config/features.json index 9ebda80bd91..ecff8f33518 100644 --- a/config/features.json +++ b/config/features.json @@ -1,7 +1,6 @@ { "ds-improved-ajax": null, "ds-pushpayload-return": null, - "ds-extended-errors": true, "ds-overhaul-references": null, "ds-payload-type-hooks": null, "ds-check-should-serialize-relationships": true, diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 7f36d338b6a..4b24d0b7254 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -2396,75 +2396,77 @@ test('on error appends errorThrown for sanity', function(assert) { }); }); -if (isEnabled('ds-extended-errors')) { - test("rejects promise with a specialized subclass of DS.AdapterError if ajax responds with http error codes", function(assert) { - assert.expect(10); +test("rejects promise with a specialized subclass of DS.AdapterError if ajax responds with http error codes", function(assert) { + assert.expect(10); - let jqXHR = { - getAllResponseHeaders() { return ''; } - }; + let jqXHR = { + getAllResponseHeaders() { return ''; } + }; + let originalAjax = Ember.$.ajax; - Ember.$.ajax = function(hash) { - jqXHR.status = 401; - hash.error(jqXHR, 'error'); - }; + Ember.$.ajax = function(hash) { + jqXHR.status = 401; + hash.error(jqXHR, 'error'); + }; - Ember.run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.UnauthorizedError, 'reason should be an instance of DS.UnauthorizedError'); - }); + Ember.run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.UnauthorizedError, 'reason should be an instance of DS.UnauthorizedError'); }); + }); - Ember.$.ajax = function(hash) { - jqXHR.status = 403; - hash.error(jqXHR, 'error'); - }; + Ember.$.ajax = function(hash) { + jqXHR.status = 403; + hash.error(jqXHR, 'error'); + }; - Ember.run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.ForbiddenError, 'reason should be an instance of DS.ForbiddenError'); - }); + Ember.run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.ForbiddenError, 'reason should be an instance of DS.ForbiddenError'); }); + }); - Ember.$.ajax = function(hash) { - jqXHR.status = 404; - hash.error(jqXHR, 'error'); - }; + Ember.$.ajax = function(hash) { + jqXHR.status = 404; + hash.error(jqXHR, 'error'); + }; - Ember.run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.NotFoundError, 'reason should be an instance of DS.NotFoundError'); - }); + Ember.run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.NotFoundError, 'reason should be an instance of DS.NotFoundError'); }); + }); - Ember.$.ajax = function(hash) { - jqXHR.status = 409; - hash.error(jqXHR, 'error'); - }; + Ember.$.ajax = function(hash) { + jqXHR.status = 409; + hash.error(jqXHR, 'error'); + }; - Ember.run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.ConflictError, 'reason should be an instance of DS.ConflictError'); - }); + Ember.run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.ConflictError, 'reason should be an instance of DS.ConflictError'); }); + }); - Ember.$.ajax = function(hash) { - jqXHR.status = 500; - hash.error(jqXHR, 'error'); - }; + Ember.$.ajax = function(hash) { + jqXHR.status = 500; + hash.error(jqXHR, 'error'); + }; - Ember.run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.ServerError, 'reason should be an instance of DS.ServerError'); - }); + Ember.run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.ServerError, 'reason should be an instance of DS.ServerError'); }); + }); -} + + Ember.$.ajax = originalAjax; +}); test('on error wraps the error string in an DS.AdapterError object', function(assert) { assert.expect(2); diff --git a/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js index 9e19c9a7c47..91dda1d0e7a 100644 --- a/tests/unit/adapter-errors-test.js +++ b/tests/unit/adapter-errors-test.js @@ -1,6 +1,5 @@ import Ember from 'ember'; -import { isEnabled } from 'ember-data/-private'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import {module, test} from 'qunit'; @@ -44,69 +43,67 @@ test('DS.AbortError', function(assert) { assert.equal(error.message, 'The adapter operation was aborted'); }); -if (isEnabled('ds-extended-errors')) { - test('DS.UnauthorizedError', function(assert) { - let error = new DS.UnauthorizedError(); - - assert.ok(error instanceof Error); - assert.ok(error instanceof DS.AdapterError); - assert.ok(error.isAdapterError); - assert.equal(error.message, 'The adapter operation is unauthorized'); - }); - - test('DS.ForbiddenError', function(assert) { - let error = new DS.ForbiddenError(); - - assert.ok(error instanceof Error); - assert.ok(error instanceof DS.AdapterError); - assert.ok(error.isAdapterError); - assert.equal(error.message, 'The adapter operation is forbidden'); - }); - - test('DS.NotFoundError', function(assert) { - let error = new DS.NotFoundError(); - - assert.ok(error instanceof Error); - assert.ok(error instanceof DS.AdapterError); - assert.ok(error.isAdapterError); - assert.equal(error.message, 'The adapter could not find the resource'); - }); - - test('DS.ConflictError', function(assert) { - let error = new DS.ConflictError(); - - assert.ok(error instanceof Error); - assert.ok(error instanceof DS.AdapterError); - assert.ok(error.isAdapterError); - assert.equal(error.message, 'The adapter operation failed due to a conflict'); - }); - - test('DS.ServerError', function(assert) { - let error = new DS.ServerError(); - - assert.ok(error instanceof Error); - assert.ok(error instanceof DS.AdapterError); - assert.ok(error.isAdapterError); - assert.equal(error.message, 'The adapter operation failed due to a server error'); - }); - - test('CustomAdapterError', function(assert) { - let CustomAdapterError = DS.AdapterError.extend(); - let error = new CustomAdapterError(); - - assert.ok(error instanceof Error); - assert.ok(error instanceof DS.AdapterError); - assert.ok(error.isAdapterError); - assert.equal(error.message, 'Adapter operation failed'); - }); - - test('CustomAdapterError with default message', function(assert) { - let CustomAdapterError = DS.AdapterError.extend({ message: 'custom error!' }); - let error = new CustomAdapterError(); - - assert.equal(error.message, 'custom error!'); - }); -} +test('DS.UnauthorizedError', function(assert) { + let error = new DS.UnauthorizedError(); + + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); + assert.equal(error.message, 'The adapter operation is unauthorized'); +}); + +test('DS.ForbiddenError', function(assert) { + let error = new DS.ForbiddenError(); + + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); + assert.equal(error.message, 'The adapter operation is forbidden'); +}); + +test('DS.NotFoundError', function(assert) { + let error = new DS.NotFoundError(); + + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); + assert.equal(error.message, 'The adapter could not find the resource'); +}); + +test('DS.ConflictError', function(assert) { + let error = new DS.ConflictError(); + + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); + assert.equal(error.message, 'The adapter operation failed due to a conflict'); +}); + +test('DS.ServerError', function(assert) { + let error = new DS.ServerError(); + + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); + assert.equal(error.message, 'The adapter operation failed due to a server error'); +}); + +test('CustomAdapterError', function(assert) { + let CustomAdapterError = DS.AdapterError.extend(); + let error = new CustomAdapterError(); + + assert.ok(error instanceof Error); + assert.ok(error instanceof DS.AdapterError); + assert.ok(error.isAdapterError); + assert.equal(error.message, 'Adapter operation failed'); +}); + +test('CustomAdapterError with default message', function(assert) { + let CustomAdapterError = DS.AdapterError.extend({ message: 'custom error!' }); + let error = new CustomAdapterError(); + + assert.equal(error.message, 'custom error!'); +}); const errorsHash = { name: ['is invalid', 'must be a string'], From cb8713d5bb3d8a73dae62be9be0e8198d54731f0 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sun, 1 Oct 2017 13:25:02 -0400 Subject: [PATCH 2034/2527] [BUGFIX beta] Avoid cache related warnings during builds. broccoli-babel-transpiler (which we use by way of ember-cli-babel) requires that all plugins have a `.baseDir` function which broccoli-babel-transpiler uses to ensure that it can properly invalidate the cached output of each transpiled file. If `.baseDir` is not present broccoli-babel-transpiler does the only "safe" thing and completely opts out of this caching system and prints a very loud warning message. This commit ensures that the few custom plugins that we are using are properly setup with a `.baseDir`. --- lib/stripped-build-plugins.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index f5011b4621d..fd79257a18a 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -1,3 +1,4 @@ +var path = require('path'); var fs = require('fs'); var FilterImports = require('babel-plugin-filter-imports'); var FeatureFlags = require('babel-plugin-feature-flags'); @@ -16,6 +17,16 @@ function uniqueAdd(obj, key, values) { } } +function addBaseDir(Plugin) { + let type = typeof Plugin; + + if (type === 'function' && !Plugin.baseDir) { + Plugin.baseDir = () => path.join(__dirname, '..'); + } else if (type === 'object' && Plugin !== null && Plugin.default) { + addBaseDir(Plugin.default); + } +} + module.exports = function(environment) { var featuresJsonPath = __dirname + '/../config/features.json'; var featuresJson = fs.readFileSync(featuresJsonPath, { encoding: 'utf8' }); @@ -59,5 +70,12 @@ module.exports = function(environment) { [TransformBlockScoping, { 'throwIfClosureRequired': true }] ); + // ensures that a `baseDir` property is present on the babel plugins + // that we will be using, this prevents ember-cli-babel/broccoli-babel-transpiler + // from opting out of caching (and printing a giant warning) + plugins.forEach(Plugin => { + addBaseDir(Plugin); + }); + return { plugins, postTransformPlugins }; }; From 572ea33e6c353cbd1183513f94ad01084f12dad9 Mon Sep 17 00:00:00 2001 From: Krati Ahuja Date: Sun, 1 Oct 2017 13:05:05 -0700 Subject: [PATCH 2035/2527] Fix ember-data Node 4.x builds --- lib/stripped-build-plugins.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index fd79257a18a..4565a1d5c2f 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -1,3 +1,5 @@ +'use strict'; + var path = require('path'); var fs = require('fs'); var FilterImports = require('babel-plugin-filter-imports'); From b924c8c4bf5951c9f2156c4fceabc91bf950ed79 Mon Sep 17 00:00:00 2001 From: bekzod Date: Tue, 3 Oct 2017 10:21:48 +0500 Subject: [PATCH 2036/2527] bump rsvp --- package.json | 2 +- yarn.lock | 19 ++++++------------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index c5dfb496c2f..3bb9054e415 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "mocha-only-detector": "0.0.2", "morgan": "^1.7.0", "rimraf": "2.5.2", - "rsvp": "3.6.0" + "rsvp": "4.7.0" }, "peerDependencies": { "ember-inflector": "^2.0.0" diff --git a/yarn.lock b/yarn.lock index 43ea953398d..3599607fed9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5478,7 +5478,11 @@ route-recognizer@^0.3.3: version "0.3.3" resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" -rsvp@3.6.0, rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0, rsvp@^3.5.0: +rsvp@4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.7.0.tgz#dc1b0b1a536f7dec9d2be45e0a12ad4197c9fd96" + +rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0, rsvp@^3.5.0: version "3.6.0" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.6.0.tgz#666dfffa715f7e10eef76f4d1e56fb2566fce5c3" @@ -6354,30 +6358,19 @@ xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" -xml2js@0.4.17: +xml2js@0.4.17, xml2js@^0.4.17: version "0.4.17" resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" dependencies: sax ">=0.6.0" xmlbuilder "^4.1.0" -xml2js@^0.4.17: - version "0.4.19" - resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" - dependencies: - sax ">=0.6.0" - xmlbuilder "~9.0.1" - xmlbuilder@4.2.1, xmlbuilder@^4.1.0: version "4.2.1" resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" dependencies: lodash "^4.0.0" -xmlbuilder@~9.0.1: - version "9.0.4" - resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz#519cb4ca686d005a8420d3496f3f0caeecca580f" - xmldom@^0.1.19: version "0.1.27" resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" From 16fbbd824efa64cb6118b49ff37088f75e73ad69 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 3 Oct 2017 16:27:17 -0400 Subject: [PATCH 2037/2527] Update changelog on master. --- CHANGELOG.md | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06f35f52541..92995ac9ed7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,98 @@ ### Master +### Release 2.15.3 (September 30, 2017) +- [#5195](https://github.com/emberjs/data/pull/5195) Ensure `ember-data/-private` module is emitted properly for ember-cli… + +### Release 2.15.2 (September 28, 2017) +- [#5193](https://github.com/emberjs/data/pull/5193) Remove feature flagging for ds-extended-errors. + +### Release 2.15.1 (September 27, 2017) +- [#5188](https://github.com/emberjs/data/pull/5188) Backport to release + +### Release 2.15.0 (September 1, 2017) + +- [#5132](https://github.com/emberjs/data/pull/5132) [BUGFIX] Fixes saving a record immediately after unloading a record with the same id +- [#5145](https://github.com/emberjs/data/pull/5145) [BUGFIX] Load many2many relationships correctly +- [#5148](https://github.com/emberjs/data/pull/5148) [BUGFIX] Relationships now update properly with new information +- [#5155](https://github.com/emberjs/data/pull/5155) [BUGFIX] Ensure symmetry between async and sync relationships +- [#5098](https://github.com/emberjs/data/pull/5098) {beta} Beta unload and create +- [#5105](https://github.com/emberjs/data/pull/5105) {Beta} forward port +- [#5119](https://github.com/emberjs/data/pull/5119) [BUGFIX release] Don't notify relationships with links during initialization +- [#5033](https://github.com/emberjs/data/pull/5033) loosen header parsing slightly +- [#4965](https://github.com/emberjs/data/pull/4965) [BUGFIX beta] Skip test which doesn't play nicely with the latest em… +- [84041a5f](https://github.com/emberjs/data/commit/84041a5f73b5b2a8f6d6d6475f7aa71d5b83b939) Update RELEASE.md +- [#4959](https://github.com/emberjs/data/pull/4959) [BUGFIX] remove forgotten broccoli-stew import +- [#4947](https://github.com/emberjs/data/pull/4947) remove needless change events when creating a recordArrays +- [#5071](https://github.com/emberjs/data/pull/5071) [BACKPORT] Update doc for deprecated function. +- [#5002](https://github.com/emberjs/data/pull/5002) [BUGFIX BETA] Added `system/store/container-instance-cache` to the -private export +- [#4992](https://github.com/emberjs/data/pull/4992) Use https in references to emberjs website (#4992) +- [#4969](https://github.com/emberjs/data/pull/4969) [BUGFIX beta] Ensure Engines can boot without error. +- [#4971](https://github.com/emberjs/data/pull/4971) Fix typo in function call +- [#5008](https://github.com/emberjs/data/pull/5008) [BUGFIX BETA]: Fixed export regression. `ember-data/transform` to be default. +- [#5022](https://github.com/emberjs/data/pull/5022) Ensure `ember-data/-private` module is emitted properly for ember-cli < 2.12. (#5022) +- [#5031](https://github.com/emberjs/data/pull/5031) Ensure `ember-data/-private` module is emitted properly for ember-cli < 2.12. (#5031) +- [#5068](https://github.com/emberjs/data/pull/5068) [BUGFIX release] Preserve local relationship changes after persisting a delet… +- [#5079](https://github.com/emberjs/data/pull/5079) [BACKPORT 2 release] Release fix unload after destroy +- [#5086](https://github.com/emberjs/data/pull/5086) {release} [BUGFIX release] handle dupe relationship entries +- [#5091](https://github.com/emberjs/data/pull/5091) {release} Bump `amd-name-resolver` version to enable parallel babel transpile +- [#5092](https://github.com/emberjs/data/pull/5092) [BUGFIX release] relationship [x, y] should not break on x.unloadRecord() +- [#5032](https://github.com/emberjs/data/pull/5032) loosen header parsing slightly +- [#5048](https://github.com/emberjs/data/pull/5048) [BUGFIX release] createRecord should only setup relationships it has … (#5048) +- [#4981](https://github.com/emberjs/data/pull/4981) [DOC release] Document DS.HasManyReference.ids +- [#4964](https://github.com/emberjs/data/pull/4964) Fix typo: expect multiple s/methods/records back +- [#4959](https://github.com/emberjs/data/pull/4959) [BUGFIX] remove forgotten broccoli-stew import +- [#4960](https://github.com/emberjs/data/pull/4960) ensure we don't compile typeof checks poorly +- [#4962](https://github.com/emberjs/data/pull/4962) Update to use built-in debug code stripping functionality. +- [#4947](https://github.com/emberjs/data/pull/4947) remove needless change events when creating a recordArrays +- [#4984](https://github.com/emberjs/data/pull/4984) [DOC release] Fix doc for `diffArray` +- [#4971](https://github.com/emberjs/data/pull/4971) Fix typo in function call +- [#4965](https://github.com/emberjs/data/pull/4965) [BUGFIX beta] Skip test which doesn't play nicely with the latest em… +- [#4969](https://github.com/emberjs/data/pull/4969) [BUGFIX beta] Ensure Engines can boot without error. +- [#4978](https://github.com/emberjs/data/pull/4978) Lock ember-cli-htmlbars to 1.3.0 to get the build passing again +- [#4980](https://github.com/emberjs/data/pull/4980) [DOC release] Docs for has-many, belongs-to ref meta +- [#5002](https://github.com/emberjs/data/pull/5002) [BUGFIX BETA] Added `system/store/container-instance-cache` to the -private export +- [#5003](https://github.com/emberjs/data/pull/5003) Change setupStore helper default serializer to JSONAPISerializer #4754 (#5003) +- [#5008](https://github.com/emberjs/data/pull/5008) [BUGFIX BETA]: Fixed export regression. `ember-data/transform` to be default. +- [#5009](https://github.com/emberjs/data/pull/5009) cleanup `index.js` and drop `0.12` node +- [#5011](https://github.com/emberjs/data/pull/5011) Fix and tests for unloadRecord => findRecord issue + +### Release 2.14.10 (August 10, 2017) +- [#5119](https://github.com/emberjs/data/pull/5119) [BUGFIX release] Don't notify relationships with links during initialization + +### Release 2.14.9 (July 29, 2017) +- [#5097](https://github.com/emberjs/data/pull/5102) [BUGFIX release] unloadRecord + findRecord + orphaned relationships + +### Release 2.14.8 (July 28, 2017) +- [#5097](https://github.com/emberjs/data/pull/5097) [BUGFIX release] restore unloadRecord + createRecord + +### Release 2.14.7 (July 25, 2017) +- [#5086](https://github.com/emberjs/data/pull/5086) {release} [BUGFIX release] handle dupe relationship entries +- [#5091](https://github.com/emberjs/data/pull/5091) {release} Bump `amd-name-resolver` version to enable parallel babel transpile +- [#5092](https://github.com/emberjs/data/pull/5092) [BUGFIX release] relationship [x, y] should not break on x.unloadRecord() + +### Release 2.14.6 (July 25, 2017) +- [#5086](https://github.com/emberjs/data/pull/5086) {release} [BUGFIX release] handle dupe relationship entries +- [#5091](https://github.com/emberjs/data/pull/5091) {release} Bump `amd-name-resolver` version to enable parallel babel transpile +- [#5092](https://github.com/emberjs/data/pull/5092) [BUGFIX release] relationship [x, y] should not break on x.unloadRecord() + +### Release 2.14.5 (July 20, 2017) +- [#5031](https://github.com/emberjs/data/pull/5031) Ensure `ember-data/-private` module is emitted properly for ember-cli < 2.12. (#5031) +- [#5079](https://github.com/emberjs/data/pull/5079) [BACKPORT 2 release] Release fix unload after destroy + +### Release 2.14.4 (July 11, 2017) +- [#5048](https://github.com/emberjs/data/pull/5048) [BUGFIX release] createRecord should only setup relationships it has … (#5048) + +### Release 2.14.3 (June 22, 2017) +- [#5033](https://github.com/emberjs/data/pull/5033) loosen header parsing slightly + +### Release 2.14.2 (June 19, 2017) +- [#5022](https://github.com/emberjs/data/pull/5022) Ensure `ember-data/-private` module is emitted properly for ember-cli < 2.12. (#5022) + +### Release 2.14.1 (June 19, 2017) +- [#4994](https://github.com/emberjs/data/pull/4994) [BUGFIX beta] Fix flushing of pending saves, that include a deleted record (#4994) +- [#5008](https://github.com/emberjs/data/pull/5008) [BUGFIX BETA]: Fixed export regression. `ember-data/transform` to be default. + ### Release 2.14.0 (June 18, 2017) - [#5013](https://github.com/emberjs/data/pull/5013) [BUGFIX beta] fixes an issue with sync dematerialization followed by a findRecord, adds test coverage - [#5002](https://github.com/emberjs/data/pull/5002) [BUGFIX BETA] Added `system/store/container-instance-cache` to the -private export file From 0fe2768447d248217c83a2133746bddcb3a999f3 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 3 Oct 2017 16:49:51 -0400 Subject: [PATCH 2038/2527] Bump canary version to 2.18.0-canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c5dfb496c2f..5f0055d9733 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.16.0-canary", + "version": "2.18.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From 75cd959808483ed29173f1b7f036f098568c2ef9 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 3 Oct 2017 16:50:41 -0400 Subject: [PATCH 2039/2527] Add 2.16.0 release notes to changelog --- CHANGELOG.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92995ac9ed7..ba31b385e4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,55 @@ ### Master +### Release 2.16.0 (October 3, 2017) +- [#5192](https://github.com/emberjs/data/pull/5192) Remove feature flagging for ds-extended-errors. +- [#4994](https://github.com/emberjs/data/pull/4994) [BUGFIX beta] Fix flushing of pending saves, that include a deleted record (#4994) +- [#5089](https://github.com/emberjs/data/pull/5089) Bump `amd-name-resolver` version to enable parallel babel transpile +- [#5030](https://github.com/emberjs/data/pull/5030) fix build +- [#5029](https://github.com/emberjs/data/pull/5029) loosen header parsing slightly +- [#5094](https://github.com/emberjs/data/pull/5094) {master} Unload fun +- [#5038](https://github.com/emberjs/data/pull/5038) remove deprecated `idToRecord` and cleanup +- [#5035](https://github.com/emberjs/data/pull/5035) [BUGFIX release] Fix global build (#5035) +- [#5031](https://github.com/emberjs/data/pull/5031) Ensure `ember-data/-private` module is emitted properly for ember-cli < 2.12. (#5031) +- [#5101](https://github.com/emberjs/data/pull/5101) [DOC beta] fix instructions for build command +- [#5047](https://github.com/emberjs/data/pull/5047) cleanup +- [#5039](https://github.com/emberjs/data/pull/5039) use prop destructor for Ember dependencies +- [#5040](https://github.com/emberjs/data/pull/5040) tests for unload + resurrect + remote relationship state +- [#5044](https://github.com/emberjs/data/pull/5044) update `ember-resolver` `loader.js` `rsvp` +- [#5115](https://github.com/emberjs/data/pull/5115) [DOC release] Fixes code blocks for api viewer +- [#5060](https://github.com/emberjs/data/pull/5060) Set hasData for preloaded empty hasMany +- [#5058](https://github.com/emberjs/data/pull/5058) [BUGFIX] keep local state after a deletion +- [#5049](https://github.com/emberjs/data/pull/5049) more cleanup +- [#5051](https://github.com/emberjs/data/pull/5051) add test for hasMany + addObject + destroyRecord +- [#5048](https://github.com/emberjs/data/pull/5048) [BUGFIX release] createRecord should only setup relationships it has … (#5048) +- [#5053](https://github.com/emberjs/data/pull/5053) [BUGFIX] has-many relationship: set hasData when fetching link +- [#5128](https://github.com/emberjs/data/pull/5128) Avoid MODEL_FACTORY_INJECTION deprecations in tests on Ember >= 2.14. +- [#5075](https://github.com/emberjs/data/pull/5075) unpin testem version +- [#5074](https://github.com/emberjs/data/pull/5074) disable node-tests in windows for now +- [#5072](https://github.com/emberjs/data/pull/5072) remove `pretender` and update some deps +- [#5066](https://github.com/emberjs/data/pull/5066) Revert "[BUGFIX] keep local state after a deletion" +- [#5067](https://github.com/emberjs/data/pull/5067) [BUGFIX] Preserve local relationship changes after persisting a delet… +- [#5070](https://github.com/emberjs/data/pull/5070) [DOC release] Update doc for deprecated function. +- [#5130](https://github.com/emberjs/data/pull/5130) Replace Ember.String.{pluralize,singularize} with ember-inflector imports +- [#5099](https://github.com/emberjs/data/pull/5099) {master} forward port +- [#5088](https://github.com/emberjs/data/pull/5088) {MASTER} [BUGFIX release] handle dupe relationship entries +- [#5077](https://github.com/emberjs/data/pull/5077) [BUGFIX release] fix destroyRecord followed by unloadRecord and impli… +- [#5141](https://github.com/emberjs/data/pull/5141) Import Inflector instead of relying on Ember namespace +- [#5110](https://github.com/emberjs/data/pull/5110) [BUGFIX beta] Implement `cacheKeyForTree` hook. +- [#5106](https://github.com/emberjs/data/pull/5106) {forwardport master} +- [#5147](https://github.com/emberjs/data/pull/5147) [BUGFIX release] fix relationship merging +- [#5126](https://github.com/emberjs/data/pull/5126) Failing test for #5125 and attempted fix +- [#5119](https://github.com/emberjs/data/pull/5119) Don't notify relationships with links during initialization +- [#5123](https://github.com/emberjs/data/pull/5123) Ensure we are properly testing multiple Ember versions. +- [#5122](https://github.com/emberjs/data/pull/5122) Remove Bower dependency and related files. +- [#5139](https://github.com/emberjs/data/pull/5139) [DOC release] Improve save method documentation +- [#5144](https://github.com/emberjs/data/pull/5144) [BUGFIX release] Load many2many relationships correctly +- [#5150](https://github.com/emberjs/data/pull/5150) [BUGFIX release] Enumerate relationships provided, not all on a given… +- [#5151](https://github.com/emberjs/data/pull/5151) [CLEANUP] PERF prevent duplicate recordArrayManager signals on push o… +- [#5153](https://github.com/emberjs/data/pull/5153) [BUGFIX release] ensure inverse async HasMany is correctly maintained +- [#5162](https://github.com/emberjs/data/pull/5162) Update RELEASE.md +- [#5192](https://github.com/emberjs/data/pull/5192) Remove feature flagging for ds-extended-errors. + ### Release 2.15.3 (September 30, 2017) - [#5195](https://github.com/emberjs/data/pull/5195) Ensure `ember-data/-private` module is emitted properly for ember-cli… From 70df50907114e2c33a3770b6dc5ba03ddc84d968 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 3 Oct 2017 20:28:59 -0400 Subject: [PATCH 2040/2527] Skip ember try on appveyor --- appveyor.yml | 2 +- package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 63705cde3e1..f3a652aac81 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,7 +22,7 @@ install: # Post-install test scripts. test_script: # Output useful info for debugging. - - cmd: yarn run test + - cmd: yarn run test-appveyor - cmd: yarn run test:optional-features - cmd: yarn run test:production - cmd: yarn run node-tests diff --git a/package.json b/package.json index 5f0055d9733..cb3b87f4bb2 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build": "ember build", "start": "ember server", "test": "ember try:testall", + "test-appveyor": "ember test", "node-tests": "node node-tests/nodetest-runner.js", "test:optional-features": "ember test --environment=test-optional-features", "test:production": "ember test --environment=production", From 51a6fbdae92a8bc8c3afd87f3b393cec705b462a Mon Sep 17 00:00:00 2001 From: Andrey Khomenko Date: Wed, 4 Oct 2017 12:29:16 -0400 Subject: [PATCH 2041/2527] [BUGFIX beta] Fix broccoli-babel-transpiler cache warnings --- lib/stripped-build-plugins.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 4565a1d5c2f..9bd2a6cb1f8 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -75,9 +75,8 @@ module.exports = function(environment) { // ensures that a `baseDir` property is present on the babel plugins // that we will be using, this prevents ember-cli-babel/broccoli-babel-transpiler // from opting out of caching (and printing a giant warning) - plugins.forEach(Plugin => { - addBaseDir(Plugin); - }); + plugins.forEach((pluginWithOptions) => addBaseDir(pluginWithOptions[0])); + return { plugins, postTransformPlugins }; }; From 98e607cfd58d275d9e1c9969296b4ff91e4fdc55 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 4 Oct 2017 16:47:26 -0400 Subject: [PATCH 2042/2527] Update changelog for Ember Data 2.16.1 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba31b385e4d..5dcf5af2003 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ### Master +### Release 2.16.1 (October 4, 2017) +- [#5114](https://github.com/emberjs/data/pull/5114) Make import stripping smarter to resolve #5019 +- [#5197](https://github.com/emberjs/data/pull/5197) Fix ember-data Node 4.x builds +- [#5206](https://github.com/emberjs/data/pull/5206) [BUGFIX beta] Fix broccoli-babel-transpiler cache warnings + ### Release 2.16.0 (October 3, 2017) - [#5192](https://github.com/emberjs/data/pull/5192) Remove feature flagging for ds-extended-errors. - [#4994](https://github.com/emberjs/data/pull/4994) [BUGFIX beta] Fix flushing of pending saves, that include a deleted record (#4994) From 2dd1322f8d11a4581157307c1be5ff976768bcfc Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 6 Oct 2017 15:47:51 -0400 Subject: [PATCH 2043/2527] Do not show feature flag improved-ajax methods in the api docs --- addon/adapters/rest.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index b58f870b6a4..2c61eccddf2 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1242,7 +1242,7 @@ if (isEnabled('ds-improved-ajax')) { RESTAdapter.reopen({ - /** + /* * Get the data (body or query params) for a request. * * @public @@ -1300,7 +1300,7 @@ if (isEnabled('ds-improved-ajax')) { return data; }, - /** + /* * Get the HTTP method for a request. * * @public @@ -1320,7 +1320,7 @@ if (isEnabled('ds-improved-ajax')) { return 'GET'; }, - /** + /* * Get the URL for a request. * * @public @@ -1357,7 +1357,7 @@ if (isEnabled('ds-improved-ajax')) { return this.buildURL(type.modelName, id, snapshot, requestType, query); }, - /** + /* * Get the headers for a request. * * By default the value of the `headers` property of the adapter is @@ -1372,7 +1372,7 @@ if (isEnabled('ds-improved-ajax')) { return this.get('headers'); }, - /** + /* * Get an object which contains all properties for a request which should * be made. * @@ -1390,7 +1390,7 @@ if (isEnabled('ds-improved-ajax')) { return { method, url, headers, data }; }, - /** + /* * Convert a request object into a hash which can be passed to `jQuery.ajax`. * * @private @@ -1425,7 +1425,7 @@ if (isEnabled('ds-improved-ajax')) { return hash; }, - /** + /* * Make a request using `jQuery.ajax`. * * @private From 7ac68adb07ac79c981563c6f0b49150364e6983f Mon Sep 17 00:00:00 2001 From: pangratz Date: Sat, 7 Oct 2017 00:08:25 +0300 Subject: [PATCH 2044/2527] [BUGFIX beta] proxy `meta` on PromiseArray --- addon/-private/system/promise-proxies.js | 5 ++- tests/integration/store/query-test.js | 49 ++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 tests/integration/store/query-test.js diff --git a/addon/-private/system/promise-proxies.js b/addon/-private/system/promise-proxies.js index 6999a9c991c..3c248f87fa7 100644 --- a/addon/-private/system/promise-proxies.js +++ b/addon/-private/system/promise-proxies.js @@ -2,6 +2,7 @@ import Ember from 'ember'; import { assert } from '@ember/debug'; const { get , RSVP: { Promise }} = Ember; +const { computed: { reads } } = Ember; /** A `PromiseArray` is an object that acts like both an `Ember.Array` @@ -32,7 +33,9 @@ const { get , RSVP: { Promise }} = Ember; @extends Ember.ArrayProxy @uses Ember.PromiseProxyMixin */ -export const PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin); +export const PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin, { + meta: reads('content.meta') +}); /** A `PromiseObject` is an object that acts like both an `Ember.Object` diff --git a/tests/integration/store/query-test.js b/tests/integration/store/query-test.js new file mode 100644 index 00000000000..76ddc1b603e --- /dev/null +++ b/tests/integration/store/query-test.js @@ -0,0 +1,49 @@ +import setupStore from 'dummy/tests/helpers/store'; +import Ember from 'ember'; +import RSVP from 'rsvp'; + +import { module, test } from 'qunit'; + +import DS from 'ember-data'; + +var Person, store, env; +var run = Ember.run; + +module("integration/store/query", { + beforeEach() { + Person = DS.Model.extend(); + + env = setupStore({ + person: Person + }); + + store = env.store; + }, + + afterEach() { + run(store, 'destroy'); + } +}); + +test("meta is proxied correctly on the PromiseArray", function(assert) { + let defered = RSVP.defer(); + + env.registry.register('adapter:person', DS.Adapter.extend({ + query(store, type, query) { + return defered.promise; + } + })); + + let result; + run(function() { + result = store.query('person', {}); + }); + + assert.equal(result.get('meta.foo'), undefined); + + run(function() { + defered.resolve({ data: [], meta: { foo: 'bar' } }); + }); + + assert.equal(result.get('meta.foo'), 'bar'); +}); From 4b419d91b3773a4b78412bd963ebbe16cb2423ff Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Mon, 9 Oct 2017 15:46:14 +0100 Subject: [PATCH 2045/2527] Updates addon to adhere to RFC 176 (#5108) * Updates codebase to new Ember modules API based on RFC 176 * bumps ember-cli-babel to latest 6.8 --- MODULE_REPORT.md | 1022 +++++++++++++++++ addon/-private/adapters/build-url-mixin.js | 13 +- addon/-private/adapters/errors.js | 32 +- addon/-private/system/debug/debug-adapter.js | 23 +- addon/-private/system/is-array-like.js | 7 +- addon/-private/system/many-array.js | 12 +- addon/-private/system/model/errors.js | 66 +- addon/-private/system/model/internal-model.js | 44 +- addon/-private/system/model/model.js | 59 +- addon/-private/system/normalize-model-name.js | 4 +- addon/-private/system/ordered-set.js | 2 +- addon/-private/system/promise-proxies.js | 14 +- addon/-private/system/record-array-manager.js | 19 +- .../adapter-populated-record-array.js | 14 +- .../record-arrays/filtered-record-array.js | 13 +- .../system/record-arrays/record-array.js | 10 +- .../-private/system/references/belongs-to.js | 4 +- addon/-private/system/references/has-many.js | 11 +- addon/-private/system/references/record.js | 4 +- addon/-private/system/relationship-meta.js | 2 +- .../system/relationships/belongs-to.js | 8 +- addon/-private/system/relationships/ext.js | 15 +- .../-private/system/relationships/has-many.js | 16 +- .../relationship-payloads-manager.js | 4 +- .../system/relationships/state/belongs-to.js | 10 +- .../system/relationships/state/create.js | 4 +- .../relationships/state/relationship.js | 5 +- addon/-private/system/snapshot.js | 18 +- addon/-private/system/store.js | 112 +- addon/-private/system/store/common.js | 6 +- .../system/store/container-instance-cache.js | 3 +- addon/-private/system/store/finders.js | 7 +- .../system/store/serializer-response.js | 4 +- addon/-private/utils.js | 9 +- addon/adapter.js | 80 +- addon/adapters/json-api.js | 10 +- addon/adapters/rest.js | 32 +- addon/attr.js | 4 +- addon/index.js | 3 +- addon/serializer.js | 4 +- addon/serializers/embedded-records-mixin.js | 17 +- addon/serializers/json-api.js | 56 +- addon/serializers/json.js | 173 +-- addon/serializers/rest.js | 34 +- addon/transforms/boolean.js | 4 +- addon/transforms/number.js | 4 +- addon/transforms/string.js | 4 +- addon/transforms/transform.js | 8 +- app/initializers/ember-data.js | 15 +- lib/babel-build.js | 1 + package.json | 3 +- tests/dummy/app/app.js | 4 +- tests/dummy/app/router.js | 4 +- tests/dummy/app/routes/application/route.js | 4 +- tests/dummy/app/routes/index/route.js | 4 +- tests/dummy/app/routes/query/controller.js | 6 +- tests/dummy/app/routes/query/route.js | 6 +- tests/helpers/async.js | 11 +- tests/helpers/custom-adapter.js | 4 +- tests/helpers/destroy-app.js | 4 +- tests/helpers/module-for-acceptance.js | 4 +- tests/helpers/owner.js | 5 +- tests/helpers/start-app.js | 9 +- tests/helpers/store.js | 3 +- .../adapter/build-url-mixin-test.js | 16 +- tests/integration/adapter/find-all-test.js | 18 +- tests/integration/adapter/find-test.js | 13 +- .../adapter/json-api-adapter-test.js | 11 +- tests/integration/adapter/queries-test.js | 18 +- .../adapter/record-persistence-test.js | 29 +- .../integration/adapter/rest-adapter-test.js | 86 +- tests/integration/adapter/serialize-test.js | 6 +- .../integration/adapter/store-adapter-test.js | 147 ++- tests/integration/application-test.js | 13 +- .../non-dasherized-lookups-test.js | 8 +- .../integration/client-id-generation-test.js | 13 +- tests/integration/debug-adapter-test.js | 22 +- tests/integration/filter-test.js | 16 +- tests/integration/injection-test.js | 15 +- tests/integration/inverse-test.js | 5 +- tests/integration/lifecycle-hooks-test.js | 9 +- tests/integration/multiple-stores-test.js | 3 +- tests/integration/peek-all-test.js | 13 +- .../polymorphic-belongs-to-test.js | 5 +- .../integration/record-array-manager-test.js | 14 +- tests/integration/record-array-test.js | 16 +- .../adapter-populated-record-array-test.js | 8 +- .../records/collection-save-test.js | 21 +- .../integration/records/delete-record-test.js | 32 +- tests/integration/records/error-test.js | 15 +- tests/integration/records/load-test.js | 8 +- .../records/property-changes-test.js | 10 +- .../records/relationship-changes-test.js | 13 +- tests/integration/records/reload-test.js | 20 +- .../integration/records/rematerialize-test.js | 8 +- tests/integration/records/save-test.js | 22 +- tests/integration/records/unload-test.js | 26 +- .../integration/references/belongs-to-test.js | 18 +- tests/integration/references/has-many-test.js | 22 +- tests/integration/references/record-test.js | 16 +- .../relationships/belongs-to-test.js | 42 +- .../relationships/has-many-test.js | 131 ++- .../inverse-relationships-test.js | 7 +- .../relationships/many-to-many-test.js | 14 +- .../relationships/nested-relationship-test.js | 6 +- .../relationships/one-to-many-test.js | 10 +- .../relationships/one-to-one-test.js | 14 +- .../polymorphic-mixins-belongs-to-test.js | 8 +- .../polymorphic-mixins-has-many-test.js | 8 +- .../embedded-records-mixin-test.js | 10 +- .../serializers/json-api-serializer-test.js | 8 +- .../serializers/json-serializer-test.js | 8 +- .../serializers/rest-serializer-test.js | 21 +- tests/integration/setup-container-test.js | 9 +- tests/integration/snapshot-test.js | 10 +- tests/integration/store-test.js | 24 +- .../store/json-api-validation-test.js | 14 +- tests/integration/store/query-record-test.js | 12 +- tests/test-helper.js | 7 +- tests/unit/adapter-errors-test.js | 6 +- .../build-url-mixin/path-for-type-test.js | 5 +- .../adapters/json-api-adapter/ajax-test.js | 8 +- tests/unit/adapters/rest-adapter/ajax-test.js | 18 +- .../rest-adapter/detailed-message-test.js | 2 +- .../group-records-for-find-many-test.js | 23 +- tests/unit/debug-test.js | 11 +- tests/unit/diff-array-test.js | 2 +- tests/unit/many-array-test.js | 8 +- tests/unit/model-test.js | 28 +- tests/unit/model/errors-test.js | 2 +- tests/unit/model/lifecycle-callbacks-test.js | 18 +- tests/unit/model/merge-test.js | 12 +- tests/unit/model/relationships-test.js | 8 +- .../model/relationships/belongs-to-test.js | 7 +- .../unit/model/relationships/has-many-test.js | 33 +- .../model/relationships/record-array-test.js | 12 +- tests/unit/model/rollback-attributes-test.js | 46 +- tests/unit/private-test.js | 6 +- tests/unit/promise-proxies-test.js | 21 +- .../adapter-populated-record-array-test.js | 10 +- .../filtered-record-array-test.js | 15 +- tests/unit/record-arrays/record-array-test.js | 22 +- tests/unit/states-test.js | 5 +- tests/unit/store/adapter-interop-test.js | 44 +- tests/unit/store/asserts-test.js | 4 +- tests/unit/store/create-record-test.js | 12 +- tests/unit/store/finders-test.js | 8 +- tests/unit/store/has-model-for-test.js | 4 +- tests/unit/store/has-record-for-id-test.js | 7 +- tests/unit/store/lookup-test.js | 5 +- tests/unit/store/model-for-test.js | 8 +- tests/unit/store/peek-record-test.js | 7 +- tests/unit/store/push-test.js | 23 +- tests/unit/store/serialize-test.js | 4 +- tests/unit/store/serializer-for-test.js | 5 +- tests/unit/store/unload-test.js | 19 +- .../relationship-payload-manager-test.js | 8 +- .../relationship-payloads-test.js | 8 +- .../unit/system/snapshot-record-array-test.js | 10 +- tests/unit/transform/boolean-test.js | 2 +- tests/unit/transform/date-test.js | 2 +- tests/unit/transform/number-test.js | 2 +- tests/unit/transform/string-test.js | 2 +- tests/unit/utils-test.js | 17 +- yarn.lock | 209 +++- 165 files changed, 2600 insertions(+), 1352 deletions(-) create mode 100644 MODULE_REPORT.md diff --git a/MODULE_REPORT.md b/MODULE_REPORT.md new file mode 100644 index 00000000000..edffb75b083 --- /dev/null +++ b/MODULE_REPORT.md @@ -0,0 +1,1022 @@ +## Module Report +### Unknown Global + +**Global**: `Ember.VERSION` + +**Location**: `addon/index.js` at line 11 + +```js +*/ + +if (Ember.VERSION.match(/^1\.([0-9]|1[0-2])\./)) { + throw new EmberError("Ember Data requires at least Ember 1.13.0, but you have " + + Ember.VERSION + +``` + +### Unknown Global + +**Global**: `Ember.VERSION` + +**Location**: `addon/index.js` at line 13 + +```js +if (Ember.VERSION.match(/^1\.([0-9]|1[0-2])\./)) { + throw new EmberError("Ember Data requires at least Ember 1.13.0, but you have " + + Ember.VERSION + + ". Please upgrade your version of Ember, then upgrade Ember Data."); +} +``` + +### Unknown Global + +**Global**: `Ember.MODEL_FACTORY_INJECTIONS` + +**Location**: `addon/-debug/index.js` at line 37 + +```js + return modelClass.__mixin.detect(addedModelClass.PrototypeMixin); + } + if (Ember.MODEL_FACTORY_INJECTIONS) { + modelClass = modelClass.superclass; + } +``` + +### Unknown Global + +**Global**: `Ember.Namespace` + +**Location**: `addon/-private/core.js` at line 20 + +```js + @static +*/ +const DS = Ember.Namespace.create({ + VERSION: VERSION, + name: "DS" +``` + +### Unknown Global + +**Global**: `Ember.libraries` + +**Location**: `addon/-private/core.js` at line 25 + +```js +}); + +if (Ember.libraries) { + Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); +} +``` + +### Unknown Global + +**Global**: `Ember.libraries` + +**Location**: `addon/-private/core.js` at line 26 + +```js + +if (Ember.libraries) { + Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); +} + +``` + +### Unknown Global + +**Global**: `Ember.FEATURES` + +**Location**: `addon/-private/features.js` at line 4 + +```js + +export default function isEnabled() { + return Ember.FEATURES.isEnabled(...arguments); +} + +``` + +### Unknown Global + +**Global**: `Ember.Date` + +**Location**: `addon/transforms/date.js` at line 5 + +```js +import { deprecate } from '@ember/debug'; + +Ember.Date = Ember.Date || {}; + +/** +``` + +### Unknown Global + +**Global**: `Ember.Date` + +**Location**: `addon/transforms/date.js` at line 5 + +```js +import { deprecate } from '@ember/debug'; + +Ember.Date = Ember.Date || {}; + +/** +``` + +### Unknown Global + +**Global**: `Ember.Date` + +**Location**: `addon/transforms/date.js` at line 19 + +```js + @deprecated + */ +Ember.Date.parse = function(date) { + // throw deprecation + deprecate(`Ember.Date.parse is deprecated because Safari 5-, IE8-, and +``` + +### Unknown Global + +**Global**: `Ember.OrderedSet` + +**Location**: `addon/-private/system/ordered-set.js` at line 4 + +```js +import Ember from 'ember'; + +const EmberOrderedSet = Ember.OrderedSet; + +export default function OrderedSet() { +``` + +### Unknown Global + +**Global**: `Ember.OrderedSet` + +**Location**: `addon/-private/system/ordered-set.js` at line 4 + +```js +import Ember from 'ember'; + +const EmberOrderedSet = Ember.OrderedSet; + +export default function OrderedSet() { +``` + +### Unknown Global + +**Global**: `Ember.ENV` + +**Location**: `tests/unit/store/adapter-interop-test.js` at line 23 + +```js + beforeEach() { + TestAdapter = DS.Adapter.extend(); + oldFilterEnabled = Ember.ENV.ENABLE_DS_FILTER; + Ember.ENV.ENABLE_DS_FILTER = false; + }, +``` + +### Unknown Global + +**Global**: `Ember.ENV` + +**Location**: `tests/unit/store/adapter-interop-test.js` at line 24 + +```js + TestAdapter = DS.Adapter.extend(); + oldFilterEnabled = Ember.ENV.ENABLE_DS_FILTER; + Ember.ENV.ENABLE_DS_FILTER = false; + }, + +``` + +### Unknown Global + +**Global**: `Ember.ENV` + +**Location**: `tests/unit/store/adapter-interop-test.js` at line 30 + +```js + run(() => { + if (store) { store.destroy(); } + Ember.ENV.ENABLE_DS_FILTER = oldFilterEnabled; + }); + } +``` + +### Unknown Global + +**Global**: `Ember.ENV` + +**Location**: `tests/unit/store/push-test.js` at line 715 + +```js +testInDebug('Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown attributes', function(assert) { + run(() => { + let originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; + try { + Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; +``` + +### Unknown Global + +**Global**: `Ember.ENV` + +**Location**: `tests/unit/store/push-test.js` at line 717 + +```js + let originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; + try { + Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; + assert.expectWarning(() => { + store.push({ +``` + +### Unknown Global + +**Global**: `Ember.ENV` + +**Location**: `tests/unit/store/push-test.js` at line 732 + +```js + }, `The payload for 'person' contains these unknown attributes: emailAddress,isMascot. Make sure they've been defined in your model.`); + } finally { + Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = originalFlagValue; + } + }); +``` + +### Unknown Global + +**Global**: `Ember.ENV` + +**Location**: `tests/unit/store/push-test.js` at line 739 + +```js +testInDebug('Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown relationships', function(assert) { + run(() => { + var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; + try { + Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; +``` + +### Unknown Global + +**Global**: `Ember.ENV` + +**Location**: `tests/unit/store/push-test.js` at line 741 + +```js + var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; + try { + Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; + assert.expectWarning(() => { + store.push({ +``` + +### Unknown Global + +**Global**: `Ember.ENV` + +**Location**: `tests/unit/store/push-test.js` at line 756 + +```js + }, `The payload for 'person' contains these unknown relationships: emailAddresses,mascots. Make sure they've been defined in your model.`); + } finally { + Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = originalFlagValue; + } + }); +``` + +### Unknown Global + +**Global**: `Ember.Date` + +**Location**: `tests/unit/transform/date-test.js` at line 61 + +```js +testInDebug('Ember.Date.parse has been deprecated', function(assert) { + assert.expectDeprecation(() => { + Ember.Date.parse(dateString); + }, /Ember.Date.parse is deprecated/); +}); +``` + +### Unknown Global + +**Global**: `Ember.ENV` + +**Location**: `addon/-private/system/store.js` at line 61 + +```js +const { + _Backburner: Backburner, + ENV +} = Ember; + +``` + +### Unknown Global + +**Global**: `Ember._Backburner` + +**Location**: `addon/-private/system/store.js` at line 60 + +```js + +const { + _Backburner: Backburner, + ENV +} = Ember; +``` + +### Unknown Global + +**Global**: `Ember.GUID_KEY` + +**Location**: `addon/-private/system/model/internal-model.js` at line 126 + +```js + + // this ensure ordered set can quickly identify this as unique + this[Ember.GUID_KEY] = InternalModelReferenceId++ + 'internal-model'; + + this.store = store; +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `addon/-private/system/model/internal-model.js` at line 495 + +```js + // TODO: use run.schedule once we drop 1.13 + if (!run.currentRunLoop) { + assert('You have turned on testing mode, which disabled the run-loop\'s autorun.\n You will need to wrap any code with asynchronous side-effects in a run', Ember.testing); + } + this._scheduledDestroy = run.backburner.schedule('destroy', this, '_checkForOrphanedInternalModels') +``` + +### Unknown Global + +**Global**: `Ember.beginPropertyChanges` + +**Location**: `addon/-private/system/model/model.js` at line 640 + +```js + */ + _notifyProperties(keys) { + Ember.beginPropertyChanges(); + let key; + for (let i = 0, length = keys.length; i < length; i++) { +``` + +### Unknown Global + +**Global**: `Ember.endPropertyChanges` + +**Location**: `addon/-private/system/model/model.js` at line 646 + +```js + this.notifyPropertyChange(key); + } + Ember.endPropertyChanges(); + }, + +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `addon/-private/system/relationships/ext.js` at line 13 + +```js + +export const relationshipsDescriptor = computed(function() { + if (Ember.testing === true && relationshipsDescriptor._cacheable === true) { + relationshipsDescriptor._cacheable = false; + } +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `addon/-private/system/relationships/ext.js` at line 40 + +```js + +export const relatedTypesDescriptor = computed(function() { + if (Ember.testing === true && relatedTypesDescriptor._cacheable === true) { + relatedTypesDescriptor._cacheable = false; + } +``` + +### Unknown Global + +**Global**: `Ember.Logger` + +**Location**: `tests/test-helper.js` at line 42 + +```js + // handle the error. + if (reason && reason instanceof Error) { + Ember.Logger.log(reason, reason.stack); + throw reason; + } +``` + +### Unknown Global + +**Global**: `Ember.MODEL_FACTORY_INJECTIONS` + +**Location**: `tests/helpers/model-factory-injection.js` at line 4 + +```js +import hasEmberVersion from 'ember-test-helpers/has-ember-version'; + +const ORIGINAL_MODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS; + +export function setup(value) { +``` + +### Unknown Global + +**Global**: `Ember.MODEL_FACTORY_INJECTIONS` + +**Location**: `tests/helpers/model-factory-injection.js` at line 4 + +```js +import hasEmberVersion from 'ember-test-helpers/has-ember-version'; + +const ORIGINAL_MODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS; + +export function setup(value) { +``` + +### Unknown Global + +**Global**: `Ember.MODEL_FACTORY_INJECTIONS` + +**Location**: `tests/helpers/model-factory-injection.js` at line 14 + +```js + + if (!hasEmberVersion(2, 14)) { + Ember.MODEL_FACTORY_INJECTIONS = value; + } +} +``` + +### Unknown Global + +**Global**: `Ember._RegistryProxyMixin` + +**Location**: `tests/helpers/owner.js` at line 6 + +```js +let Owner; + +if (Ember._RegistryProxyMixin && Ember._ContainerProxyMixin) { + Owner = EmberObject.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin); +} else { +``` + +### Unknown Global + +**Global**: `Ember._ContainerProxyMixin` + +**Location**: `tests/helpers/owner.js` at line 6 + +```js +let Owner; + +if (Ember._RegistryProxyMixin && Ember._ContainerProxyMixin) { + Owner = EmberObject.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin); +} else { +``` + +### Unknown Global + +**Global**: `Ember._RegistryProxyMixin` + +**Location**: `tests/helpers/owner.js` at line 7 + +```js + +if (Ember._RegistryProxyMixin && Ember._ContainerProxyMixin) { + Owner = EmberObject.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin); +} else { + Owner = EmberObject.extend(); +``` + +### Unknown Global + +**Global**: `Ember._ContainerProxyMixin` + +**Location**: `tests/helpers/owner.js` at line 7 + +```js + +if (Ember._RegistryProxyMixin && Ember._ContainerProxyMixin) { + Owner = EmberObject.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin); +} else { + Owner = EmberObject.extend(); +``` + +### Unknown Global + +**Global**: `Ember.__loader` + +**Location**: `tests/helpers/setup-ember-dev.js` at line 9 + +```js +// Maintain backwards compatiblity with older versions of ember. +let emberDebugModule; +if (Ember.__loader && Ember.__loader.registry && Ember.__loader.registry["ember-metal/debug"]) { + emberDebugModule = Ember.__loader.require('ember-metal/debug'); +} +``` + +### Unknown Global + +**Global**: `Ember.__loader` + +**Location**: `tests/helpers/setup-ember-dev.js` at line 9 + +```js +// Maintain backwards compatiblity with older versions of ember. +let emberDebugModule; +if (Ember.__loader && Ember.__loader.registry && Ember.__loader.registry["ember-metal/debug"]) { + emberDebugModule = Ember.__loader.require('ember-metal/debug'); +} +``` + +### Unknown Global + +**Global**: `Ember.__loader` + +**Location**: `tests/helpers/setup-ember-dev.js` at line 9 + +```js +// Maintain backwards compatiblity with older versions of ember. +let emberDebugModule; +if (Ember.__loader && Ember.__loader.registry && Ember.__loader.registry["ember-metal/debug"]) { + emberDebugModule = Ember.__loader.require('ember-metal/debug'); +} +``` + +### Unknown Global + +**Global**: `Ember.__loader` + +**Location**: `tests/helpers/setup-ember-dev.js` at line 10 + +```js +let emberDebugModule; +if (Ember.__loader && Ember.__loader.registry && Ember.__loader.registry["ember-metal/debug"]) { + emberDebugModule = Ember.__loader.require('ember-metal/debug'); +} + +``` + +### Unknown Global + +**Global**: `Ember.name` + +**Location**: `tests/helpers/setup-ember-dev.js` at line 17 + +```js + return emberDebugModule.getDebugFunction(name); + } else { + return Ember[name]; + } +} +``` + +### Unknown Global + +**Global**: `Ember.name` + +**Location**: `tests/helpers/setup-ember-dev.js` at line 25 + +```js + emberDebugModule.setDebugFunction(name, func); + } else { + Ember[name] = func; + } +} +``` + +### Unknown Global + +**Global**: `Ember.Registry` + +**Location**: `tests/helpers/store.js` at line 11 + +```js + options = options || {}; + + if (Ember.Registry) { + registry = env.registry = new Ember.Registry(); + owner = Owner.create({ +``` + +### Unknown Global + +**Global**: `Ember.Registry` + +**Location**: `tests/helpers/store.js` at line 12 + +```js + + if (Ember.Registry) { + registry = env.registry = new Ember.Registry(); + owner = Owner.create({ + __registry__: registry +``` + +### Unknown Global + +**Global**: `Ember.Container` + +**Location**: `tests/helpers/store.js` at line 21 + +```js + owner.__container__ = container; + } else { + container = env.container = new Ember.Container(); + registry = env.registry = container; + } +``` + +### Unknown Global + +**Global**: `Ember.Namespace` + +**Location**: `tests/integration/application-test.js` at line 13 + +```js + +const Store = DS.Store; +const Namespace = Ember.Namespace; + +let app, App, container; +``` + +### Unknown Global + +**Global**: `Ember.Namespace` + +**Location**: `tests/integration/application-test.js` at line 13 + +```js + +const Store = DS.Store; +const Namespace = Ember.Namespace; + +let app, App, container; +``` + +### Unknown Global + +**Global**: `Ember.BOOTED` + +**Location**: `tests/integration/application-test.js` at line 47 + +```js + afterEach() { + run(app, app.destroy); + Ember.BOOTED = false; + } +}); +``` + +### Unknown Global + +**Global**: `Ember.BOOTED` + +**Location**: `tests/integration/application-test.js` at line 87 + +```js + afterEach() { + run(app, 'destroy'); + Ember.BOOTED = false; + } +}); +``` + +### Unknown Global + +**Global**: `Ember.inject` + +**Location**: `tests/integration/application-test.js` at line 108 + +```js +}); + +if (Ember.inject && service) { + module("integration/application - Using the store as a service", { + beforeEach() { +``` + +### Unknown Global + +**Global**: `Ember.BOOTED` + +**Location**: `tests/integration/application-test.js` at line 122 + +```js + afterEach() { + run(app, 'destroy'); + Ember.BOOTED = false; + } + }); +``` + +### Unknown Global + +**Global**: `Ember.BOOTED` + +**Location**: `tests/integration/application-test.js` at line 143 + +```js + run(app, app.destroy); + } + Ember.BOOTED = false; + } +}); +``` + +### Unknown Global + +**Global**: `Ember.OrderedSet` + +**Location**: `tests/integration/record-array-manager-test.js` at line 307 + +```js + let record = {}; + let internalModel = { + _recordArrays: new Ember.OrderedSet(), + getRecord() { + return record; +``` + +### Unknown Global + +**Global**: `Ember.Registry` + +**Location**: `tests/unit/model-test.js` at line 1001 + +```js + + let registry, container; + if (Ember.Registry) { + registry = new Ember.Registry(); + container = registry.container(); +``` + +### Unknown Global + +**Global**: `Ember.Registry` + +**Location**: `tests/unit/model-test.js` at line 1002 + +```js + let registry, container; + if (Ember.Registry) { + registry = new Ember.Registry(); + container = registry.container(); + } else { +``` + +### Unknown Global + +**Global**: `Ember.Container` + +**Location**: `tests/unit/model-test.js` at line 1005 + +```js + container = registry.container(); + } else { + container = new Ember.Container(); + registry = container; + } +``` + +### Unknown Global + +**Global**: `Ember.Registry` + +**Location**: `tests/unit/model-test.js` at line 1035 + +```js + + let registry, container; + if (Ember.Registry) { + registry = new Ember.Registry(); + container = registry.container(); +``` + +### Unknown Global + +**Global**: `Ember.Registry` + +**Location**: `tests/unit/model-test.js` at line 1036 + +```js + let registry, container; + if (Ember.Registry) { + registry = new Ember.Registry(); + container = registry.container(); + } else { +``` + +### Unknown Global + +**Global**: `Ember.Container` + +**Location**: `tests/unit/model-test.js` at line 1039 + +```js + container = registry.container(); + } else { + container = new Ember.Container(); + registry = container; + } +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `tests/integration/relationships/belongs-to-test.js` at line 547 + +```js +test("relationshipsByName is cached in production", function(assert) { + let model = store.modelFor('user'); + let oldTesting = Ember.testing; + //We set the cacheable to true because that is the default state for any CP and then assert that it + //did not get dynamically changed when accessed +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `tests/integration/relationships/belongs-to-test.js` at line 565 + +```js +test("relatedTypes is cached in production", function(assert) { + let model = store.modelFor('user'); + let oldTesting = Ember.testing; + //We set the cacheable to true because that is the default state for any CP and then assert that it + //did not get dynamically changed when accessed +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `tests/integration/relationships/belongs-to-test.js` at line 583 + +```js +test("relationships is cached in production", function(assert) { + let model = store.modelFor('user'); + let oldTesting = Ember.testing; + //We set the cacheable to true because that is the default state for any CP and then assert that it + //did not get dynamically changed when accessed +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `tests/integration/relationships/belongs-to-test.js` at line 547 + +```js +test("relationshipsByName is cached in production", function(assert) { + let model = store.modelFor('user'); + let oldTesting = Ember.testing; + //We set the cacheable to true because that is the default state for any CP and then assert that it + //did not get dynamically changed when accessed +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `tests/integration/relationships/belongs-to-test.js` at line 553 + +```js + let oldCacheable = relationshipsByName._cacheable; + relationshipsByName._cacheable = true; + Ember.testing = false; + try { + assert.equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached'); +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `tests/integration/relationships/belongs-to-test.js` at line 558 + +```js + assert.equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached'); + } finally { + Ember.testing = oldTesting; + relationshipsByName._cacheable = oldCacheable; + } +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `tests/integration/relationships/belongs-to-test.js` at line 565 + +```js +test("relatedTypes is cached in production", function(assert) { + let model = store.modelFor('user'); + let oldTesting = Ember.testing; + //We set the cacheable to true because that is the default state for any CP and then assert that it + //did not get dynamically changed when accessed +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `tests/integration/relationships/belongs-to-test.js` at line 571 + +```js + let oldCacheable = relatedTypes._cacheable; + relatedTypes._cacheable = true; + Ember.testing = false; + try { + assert.equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached'); +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `tests/integration/relationships/belongs-to-test.js` at line 576 + +```js + assert.equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached'); + } finally { + Ember.testing = oldTesting; + relatedTypes._cacheable = oldCacheable; + } +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `tests/integration/relationships/belongs-to-test.js` at line 583 + +```js +test("relationships is cached in production", function(assert) { + let model = store.modelFor('user'); + let oldTesting = Ember.testing; + //We set the cacheable to true because that is the default state for any CP and then assert that it + //did not get dynamically changed when accessed +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `tests/integration/relationships/belongs-to-test.js` at line 589 + +```js + let oldCacheable = relationships._cacheable; + relationships._cacheable = true; + Ember.testing = false; + try { + assert.equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached'); +``` + +### Unknown Global + +**Global**: `Ember.testing` + +**Location**: `tests/integration/relationships/belongs-to-test.js` at line 594 + +```js + assert.equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached'); + } finally { + Ember.testing = oldTesting; + relationships._cacheable = oldCacheable; + } +``` diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index 0273992da8c..52ec93f5452 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -1,8 +1,8 @@ -import Ember from 'ember'; +import { camelize } from '@ember/string'; +import Mixin from '@ember/object/mixin'; +import { get } from '@ember/object'; import { pluralize } from 'ember-inflector'; -const get = Ember.get; - /** WARNING: This interface is likely to change in order to accomodate https://github.com/emberjs/rfcs/pull/4 @@ -30,7 +30,7 @@ const get = Ember.get; @class BuildURLMixin @namespace DS */ -export default Ember.Mixin.create({ +export default Mixin.create({ /** Builds a URL for a given type and optional ID. @@ -421,11 +421,12 @@ export default Ember.Mixin.create({ ```app/adapters/application.js import DS from 'ember-data'; + import { decamelize } from '@ember/string'; import { pluralize } from 'ember-inflector'; export default DS.RESTAdapter.extend({ pathForType: function(modelName) { - var decamelized = Ember.String.decamelize(modelName); + var decamelized = decamelize(modelName); return pluralize(decamelized); } }); @@ -436,7 +437,7 @@ export default Ember.Mixin.create({ @return {String} path **/ pathForType(modelName) { - let camelized = Ember.String.camelize(modelName); + let camelized = camelize(modelName); return pluralize(camelized); } }); diff --git a/addon/-private/adapters/errors.js b/addon/-private/adapters/errors.js index aa0c35a43a3..ec8919818cf 100644 --- a/addon/-private/adapters/errors.js +++ b/addon/-private/adapters/errors.js @@ -1,8 +1,8 @@ -import Ember from 'ember'; +import { makeArray } from '@ember/array'; +import { isPresent } from '@ember/utils'; +import EmberError from '@ember/error'; import { assert } from '@ember/debug'; -const EmberError = Ember.Error; - const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/; const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/; const PRIMARY_ATTRIBUTE_KEY = 'base'; @@ -54,10 +54,10 @@ const PRIMARY_ATTRIBUTE_KEY = 'base'; `under-maintenance` route: ```app/routes/application.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; import MaintenanceError from '../adapters/maintenance-error'; - export default Ember.Route.extend({ + export default Route.extend({ actions: { error(error, transition) { if (error instanceof MaintenanceError) { @@ -136,13 +136,13 @@ AdapterError.extend = extendFn(AdapterError); rejects with a `DS.InvalidError` object that looks like this: ```app/adapters/post.js - import Ember from 'ember'; + import RSVP from 'RSVP'; import DS from 'ember-data'; export default DS.RESTAdapter.extend({ updateRecord() { // Fictional adapter that always rejects - return Ember.RSVP.reject(new DS.InvalidError([ + return RSVP.reject(new DS.InvalidError([ { detail: 'Must be unique', source: { pointer: '/data/attributes/title' } @@ -177,12 +177,12 @@ export const InvalidError = extend(AdapterError, connection if an adapter operation has timed out: ```app/routes/application.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; import DS from 'ember-data'; const { TimeoutError } = DS; - export default Ember.Route.extend({ + export default Route.extend({ actions: { error(error, transition) { if (error instanceof TimeoutError) { @@ -225,12 +225,12 @@ export const AbortError = extend(AdapterError, request is unauthorized: ```app/routes/application.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; import DS from 'ember-data'; const { UnauthorizedError } = DS; - export default Ember.Route.extend({ + export default Route.extend({ actions: { error(error, transition) { if (error instanceof UnauthorizedError) { @@ -271,12 +271,12 @@ export const ForbiddenError = extend(AdapterError, 'The adapter operation is for for a specific model that does not exist. For example: ```app/routes/post.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; import DS from 'ember-data'; const { NotFoundError } = DS; - export default Ember.Route.extend({ + export default Route.extend({ model(params) { return this.get('store').findRecord('post', params.post_id); }, @@ -371,9 +371,9 @@ export const ServerError = extend(AdapterError, 'The adapter operation failed du export function errorsHashToArray(errors) { let out = []; - if (Ember.isPresent(errors)) { + if (isPresent(errors)) { Object.keys(errors).forEach((key) => { - let messages = Ember.makeArray(errors[key]); + let messages = makeArray(errors[key]); for (let i = 0; i < messages.length; i++) { let title = 'Invalid Attribute'; let pointer = `/data/attributes/${key}`; @@ -438,7 +438,7 @@ export function errorsHashToArray(errors) { export function errorsArrayToHash(errors) { let out = {}; - if (Ember.isPresent(errors)) { + if (isPresent(errors)) { errors.forEach((error) => { if (error.source && error.source.pointer) { let key = error.source.pointer.match(SOURCE_POINTER_REGEXP); diff --git a/addon/-private/system/debug/debug-adapter.js b/addon/-private/system/debug/debug-adapter.js index 63df01ee251..abd9f6df50d 100644 --- a/addon/-private/system/debug/debug-adapter.js +++ b/addon/-private/system/debug/debug-adapter.js @@ -1,11 +1,14 @@ /** @module ember-data */ -import Ember from 'ember'; +import { addObserver, removeObserver } from '@ember/object/observers'; + +import { A } from '@ember/array'; +import DataAdapter from '@ember/debug/data-adapter'; +import { capitalize, underscore } from '@ember/string'; +import { assert } from '@ember/debug'; +import { get } from '@ember/object'; import Model from '../model/model'; -const capitalize = Ember.String.capitalize; -const underscore = Ember.String.underscore; -const { assert, get } = Ember; /* Extend `Ember.DataAdapter` with ED specific code. @@ -15,7 +18,7 @@ const { assert, get } = Ember; @extends Ember.DataAdapter @private */ -export default Ember.DataAdapter.extend({ +export default DataAdapter.extend({ getFilters() { return [ { name: 'isNew', desc: 'New' }, @@ -73,7 +76,7 @@ export default Ember.DataAdapter.extend({ getRecordKeywords(record) { let keywords = []; - let keys = Ember.A(['id']); + let keys = A(['id']); record.eachAttribute((key) => keys.push(key)); keys.forEach((key) => keywords.push(get(record, key))); return keywords; @@ -98,8 +101,8 @@ export default Ember.DataAdapter.extend({ }, observeRecord(record, recordUpdated) { - let releaseMethods = Ember.A(); - let keysToObserve = Ember.A(['id', 'isNew', 'hasDirtyAttributes']); + let releaseMethods = A(); + let keysToObserve = A(['id', 'isNew', 'hasDirtyAttributes']); record.eachAttribute((key) => keysToObserve.push(key)); let adapter = this; @@ -108,9 +111,9 @@ export default Ember.DataAdapter.extend({ let handler = function() { recordUpdated(adapter.wrapRecord(record)); }; - Ember.addObserver(record, key, handler); + addObserver(record, key, handler); releaseMethods.push(function() { - Ember.removeObserver(record, key, handler); + removeObserver(record, key, handler); }); }); diff --git a/addon/-private/system/is-array-like.js b/addon/-private/system/is-array-like.js index 3be11dac000..f442e8e9721 100644 --- a/addon/-private/system/is-array-like.js +++ b/addon/-private/system/is-array-like.js @@ -1,4 +1,5 @@ -import Ember from 'ember'; +import { typeOf } from '@ember/utils'; +import EmberArray from '@ember/array'; /* We're using this to detect arrays and "array-like" objects. @@ -13,9 +14,9 @@ import Ember from 'ember'; export default function isArrayLike(obj) { if (!obj || obj.setInterval) { return false; } if (Array.isArray(obj)) { return true; } - if (Ember.Array.detect(obj)) { return true; } + if (EmberArray.detect(obj)) { return true; } - let type = Ember.typeOf(obj); + let type = typeOf(obj); if ('array' === type) { return true; } if ((obj.length !== undefined) && 'object' === type) { return true; } return false; diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 569263e1f5e..7ea140ff392 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -1,14 +1,16 @@ /** @module ember-data */ -import Ember from 'ember'; +import { all } from 'rsvp'; + +import Evented from '@ember/object/evented'; +import MutableArray from '@ember/array/mutable'; +import EmberObject, { get } from '@ember/object'; import { assert } from '@ember/debug'; import { PromiseArray } from "./promise-proxies"; import { _objectIsAlive } from "./store/common"; import diffArray from './diff-array'; -const { get } = Ember; - /** A `ManyArray` is a `MutableArray` that represents the contents of a has-many relationship. @@ -52,7 +54,7 @@ const { get } = Ember; @extends Ember.Object @uses Ember.MutableArray, Ember.Evented */ -export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { +export default EmberObject.extend(MutableArray, Evented, { init() { this._super(...arguments); @@ -260,7 +262,7 @@ export default Ember.Object.extend(Ember.MutableArray, Ember.Evented, { save() { let manyArray = this; let promiseLabel = 'DS: ManyArray#save ' + get(this, 'type'); - let promise = Ember.RSVP.all(this.invoke("save"), promiseLabel). + let promise = all(this.invoke("save"), promiseLabel). then(() => manyArray, null, 'DS: ManyArray#save return ManyArray'); return PromiseArray.create({ promise }); diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index 42dd3d1c9a3..ce959ad44d0 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -1,8 +1,12 @@ -import Ember from 'ember'; +import { mapBy, not } from '@ember/object/computed'; +import Evented from '@ember/object/evented'; +import ArrayProxy from '@ember/array/proxy'; +import { set, get, computed } from '@ember/object'; +import { isEmpty } from '@ember/utils'; +import { makeArray, A } from '@ember/array'; +import MapWithDefault from '@ember/map/with-default'; import { deprecate, warn } from '@ember/debug'; -const { get, set, isEmpty, makeArray, MapWithDefault } = Ember; - /** @module ember-data */ @@ -82,7 +86,7 @@ const { get, set, isEmpty, makeArray, MapWithDefault } = Ember; @uses Ember.Enumerable @uses Ember.Evented */ -export default Ember.ArrayProxy.extend(Ember.Evented, { +export default ArrayProxy.extend(Evented, { /** Register with target handler @@ -120,10 +124,10 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @type {Ember.MapWithDefault} @private */ - errorsByAttributeName: Ember.computed(function() { + errorsByAttributeName: computed(function() { return MapWithDefault.create({ defaultValue() { - return Ember.A(); + return A(); } }); }), @@ -165,15 +169,15 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @property messages @type {Array} */ - messages: Ember.computed.mapBy('content', 'message'), + messages: mapBy('content', 'message'), /** @property content @type {Array} @private */ - content: Ember.computed(function() { - return Ember.A(); + content: computed(function() { + return A(); }), /** @@ -199,7 +203,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { @type {Boolean} @readOnly */ - isEmpty: Ember.computed.not('length').readOnly(), + isEmpty: not('length').readOnly(), /** Adds error messages to a given attribute and sends @@ -289,16 +293,16 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { ``` ```app/routes/user/edit.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ actions: { save: function(user) { - if (!user.get('twoFactorAuth')) { - user.get('errors').remove('phone'); - } - user.save(); - } + if (!user.get('twoFactorAuth')) { + user.get('errors').remove('phone'); + } + user.save(); + } } }); ``` @@ -344,14 +348,14 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { Example: ```app/routes/user/edit.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ actions: { retrySave: function(user) { - user.get('errors').clear(); - user.save(); - } + user.get('errors').clear(); + user.save(); + } } }); ``` @@ -382,7 +386,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { if (get(this, 'isEmpty')) { return; } let errorsByAttributeName = get(this, 'errorsByAttributeName'); - let attributes = Ember.A(); + let attributes = A(); errorsByAttributeName.forEach(function(_, attribute) { attributes.push(attribute); @@ -393,7 +397,7 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { this.notifyPropertyChange(attribute); }, this); - Ember.ArrayProxy.prototype.clear.call(this); + ArrayProxy.prototype.clear.call(this); }, @@ -401,16 +405,16 @@ export default Ember.ArrayProxy.extend(Ember.Evented, { Checks if there is error messages for the given attribute. ```app/routes/user/edit.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ actions: { save: function(user) { - if (user.get('errors').has('email')) { - return alert('Please update your email before attempting to save.'); - } - user.save(); - } + if (user.get('errors').has('email')) { + return alert('Please update your email before attempting to save.'); + } + user.save(); + } } }); ``` diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index acddb749bb5..3a1036e3a88 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -1,6 +1,14 @@ +import { assign, merge } from '@ember/polyfills'; +import { set, get } from '@ember/object'; +import { copy } from '@ember/object/internals'; +import EmberError from '@ember/error'; +import { isEqual, isEmpty } from '@ember/utils'; +import { setOwner } from '@ember/application'; +import { run } from '@ember/runloop'; +import RSVP, { Promise } from 'rsvp'; import Ember from 'ember'; import { DEBUG } from '@glimmer/env'; -import { assert } from '@ember/debug'; +import { assert, inspect } from '@ember/debug'; import RootState from "./states"; import Relationships from "../relationships/state/create"; import Snapshot from "../snapshot"; @@ -15,21 +23,7 @@ import { HasManyReference } from "../references"; -const { - get, - set, - copy, - Error: EmberError, - inspect, - isEmpty, - isEqual, - setOwner, - run, - RSVP, - RSVP: { Promise } -} = Ember; - -const assign = Ember.assign || Ember.merge; +const emberAssign = assign || merge; /* The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached @@ -345,7 +339,7 @@ export default class InternalModel { }; if (typeof properties === 'object' && properties !== null) { - assign(createOptions, properties); + emberAssign(createOptions, properties); } if (setOwner) { @@ -497,10 +491,10 @@ export default class InternalModel { if (this._scheduledDestroy === null) { // TODO: use run.schedule once we drop 1.13 - if (!Ember.run.currentRunLoop) { + if (!run.currentRunLoop) { assert('You have turned on testing mode, which disabled the run-loop\'s autorun.\n You will need to wrap any code with asynchronous side-effects in a run', Ember.testing); } - this._scheduledDestroy = Ember.run.backburner.schedule('destroy', this, '_checkForOrphanedInternalModels') + this._scheduledDestroy = run.backburner.schedule('destroy', this, '_checkForOrphanedInternalModels') } } @@ -591,7 +585,7 @@ export default class InternalModel { changedKeys = this._changedKeys(data.attributes); } - assign(this._data, data.attributes); + emberAssign(this._data, data.attributes); this.pushedData(); if (this.hasRecord) { @@ -700,7 +694,7 @@ export default class InternalModel { let oldData = this._data; let currentData = this._attributes; let inFlightData = this._inFlightAttributes; - let newData = assign(copy(inFlightData), currentData); + let newData = emberAssign(copy(inFlightData), currentData); let diffData = Object.create(null); let newDataKeys = Object.keys(newData); @@ -1073,9 +1067,9 @@ export default class InternalModel { this.didCleanError(); let changedKeys = this._changedKeys(data); - assign(this._data, this._inFlightAttributes); + emberAssign(this._data, this._inFlightAttributes); if (data) { - assign(this._data, data); + emberAssign(this._data, data); } this._inFlightAttributes = null; @@ -1203,8 +1197,8 @@ export default class InternalModel { attrs= this._attributes; } - original = assign(Object.create(null), this._data); - original = assign(original, this._inFlightAttributes); + original = emberAssign(Object.create(null), this._data); + original = emberAssign(original, this._inFlightAttributes); for (i = 0; i < length; i++) { key = keys[i]; diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 6fadc64cea9..04d99e4a602 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1,3 +1,14 @@ +import ComputedProperty from '@ember/object/computed'; +import { setOwner } from '@ember/application'; +import { isNone } from '@ember/utils'; +import EmberError from '@ember/error'; +import Evented from '@ember/object/evented'; +import EmberObject, { + computed, + get, + observer +} from '@ember/object'; +import Map from '@ember/map'; import Ember from 'ember'; import { DEBUG } from '@glimmer/env'; import { assert, deprecate, warn } from '@ember/debug'; @@ -11,12 +22,6 @@ import { relationshipsDescriptor } from '../relationships/ext'; -const { - get, - computed, - Map -} = Ember; - /** @module ember-data */ @@ -81,7 +86,7 @@ const retrieveFromCurrentState = computed('currentState', function(key) { @extends Ember.Object @uses Ember.Evented */ -const Model = Ember.Object.extend(Ember.Evented, { +const Model = EmberObject.extend(Evented, { _internalModel: null, store: null, __defineNonEnumerable(property) { @@ -544,9 +549,9 @@ const Model = Ember.Object.extend(Ember.Evented, { Example ```app/routes/model/delete.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ actions: { softDelete: function() { this.controller.get('model').deleteRecord(); @@ -573,9 +578,9 @@ const Model = Ember.Object.extend(Ember.Evented, { Example ```app/routes/model/delete.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ actions: { delete: function() { let controller = this.controller; @@ -794,9 +799,9 @@ const Model = Ember.Object.extend(Ember.Evented, { Example ```app/routes/model/view.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ actions: { reload: function() { this.controller.get('model').reload().then(function(model) { @@ -973,7 +978,7 @@ const Model = Ember.Object.extend(Ember.Evented, { return this._internalModel.referenceFor('hasMany', name); }, - setId: Ember.observer('id', function () { + setId: observer('id', function () { this._internalModel.setId(this.get('id')); }), @@ -1137,7 +1142,7 @@ if (DEBUG) { this._super(...arguments); if (!this._internalModel) { - throw new Ember.Error('You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.'); + throw new EmberError('You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.'); } } }); @@ -1173,9 +1178,11 @@ Model.reopenClass({ keys to underscore (instead of dasherized), you might use the following code: ```javascript + import { underscore } from '@ember/string'; + export default const PostSerializer = DS.RESTSerializer.extend({ - payloadKeyFromModelName: function(modelName) { - return Ember.String.underscore(modelName); + payloadKeyFromModelName(modelName) { + return underscore(modelName); } }); ``` @@ -1229,7 +1236,7 @@ Model.reopenClass({ return relationship && store.modelFor(relationship.type); }, - inverseMap: Ember.computed(function() { + inverseMap: computed(function() { return Object.create(null); }), @@ -1306,10 +1313,10 @@ Model.reopenClass({ //If inverse is specified manually, return the inverse if (options.inverse) { inverseName = options.inverse; - inverse = Ember.get(inverseType, 'relationshipsByName').get(inverseName); + inverse = get(inverseType, 'relationshipsByName').get(inverseName); assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.modelName + - "' model. This is most likely due to a missing attribute on your model definition.", !Ember.isNone(inverse)); + "' model. This is most likely due to a missing attribute on your model definition.", !isNone(inverse)); inverseKind = inverse.kind; } else { @@ -1429,7 +1436,7 @@ Model.reopenClass({ @type Object @readOnly */ - relationshipNames: Ember.computed(function() { + relationshipNames: computed(function() { let names = { hasMany: [], belongsTo: [] @@ -1558,7 +1565,7 @@ Model.reopenClass({ @type Ember.Map @readOnly */ - fields: Ember.computed(function() { + fields: computed(function() { let map = Map.create(); this.eachComputedProperty((name, meta) => { @@ -1667,7 +1674,7 @@ Model.reopenClass({ @type {Ember.Map} @readOnly */ - attributes: Ember.computed(function() { + attributes: computed(function() { let map = Map.create(); this.eachComputedProperty((name, meta) => { @@ -1720,7 +1727,7 @@ Model.reopenClass({ @type {Ember.Map} @readOnly */ - transformedAttributes: Ember.computed(function() { + transformedAttributes: computed(function() { let map = Map.create(); this.eachAttribute((key, meta) => { @@ -1837,7 +1844,7 @@ Model.reopenClass({ // deprecation is actually created via an `.extend` of the factory // inside the container itself, but that only happens on models // with MODEL_FACTORY_INJECTIONS enabled :( -if (Ember.setOwner) { +if (setOwner) { Object.defineProperty(Model.prototype, 'container', { configurable: true, enumerable: false, @@ -1914,7 +1921,7 @@ if (DEBUG) { */ didDefineProperty(proto, key, value) { // Check if the value being set is a computed property. - if (value instanceof Ember.ComputedProperty) { + if (value instanceof ComputedProperty) { // If it is, get the metadata for the relationship. This is // populated by the `DS.belongsTo` helper when it is creating diff --git a/addon/-private/system/normalize-model-name.js b/addon/-private/system/normalize-model-name.js index f885e5ddd61..7ff61d9841d 100644 --- a/addon/-private/system/normalize-model-name.js +++ b/addon/-private/system/normalize-model-name.js @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import { dasherize } from '@ember/string'; // All modelNames are dasherized internally. Changing this function may // require changes to other normalization hooks (such as typeForRoot). @@ -14,5 +14,5 @@ import Ember from 'ember'; @for DS */ export default function normalizeModelName(modelName) { - return Ember.String.dasherize(modelName); + return dasherize(modelName); } diff --git a/addon/-private/system/ordered-set.js b/addon/-private/system/ordered-set.js index 766f722a0a3..0577ec61664 100644 --- a/addon/-private/system/ordered-set.js +++ b/addon/-private/system/ordered-set.js @@ -1,7 +1,7 @@ +import { guidFor } from '@ember/object/internals'; import Ember from 'ember'; const EmberOrderedSet = Ember.OrderedSet; -const guidFor = Ember.guidFor; export default function OrderedSet() { this._super$constructor(); diff --git a/addon/-private/system/promise-proxies.js b/addon/-private/system/promise-proxies.js index 3c248f87fa7..f2a6bb814a8 100644 --- a/addon/-private/system/promise-proxies.js +++ b/addon/-private/system/promise-proxies.js @@ -1,9 +1,11 @@ -import Ember from 'ember'; +import ObjectProxy from '@ember/object/proxy'; +import PromiseProxyMixin from '@ember/object/promise-proxy-mixin'; +import ArrayProxy from '@ember/array/proxy'; +import { get } from '@ember/object'; +import { reads } from '@ember/object/computed'; +import { Promise } from 'rsvp'; import { assert } from '@ember/debug'; -const { get , RSVP: { Promise }} = Ember; -const { computed: { reads } } = Ember; - /** A `PromiseArray` is an object that acts like both an `Ember.Array` and a promise. When the promise is resolved the resulting value @@ -33,7 +35,7 @@ const { computed: { reads } } = Ember; @extends Ember.ArrayProxy @uses Ember.PromiseProxyMixin */ -export const PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin, { +export const PromiseArray = ArrayProxy.extend(PromiseProxyMixin, { meta: reads('content.meta') }); @@ -66,7 +68,7 @@ export const PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin, { @extends Ember.ObjectProxy @uses Ember.PromiseProxyMixin */ -export let PromiseObject = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin); +export let PromiseObject = ObjectProxy.extend(PromiseProxyMixin); export function promiseObject(promise, label) { return PromiseObject.create({ diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 483e7766502..9802e02ce79 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -2,7 +2,10 @@ @module ember-data */ -import Ember from 'ember'; +import { A } from '@ember/array'; + +import { set, get } from '@ember/object'; +import { run as emberRun } from '@ember/runloop'; import { RecordArray, FilteredRecordArray, @@ -12,12 +15,6 @@ import { import cloneNull from "./clone-null"; import { assert } from '@ember/debug'; -const { - get, - set, - run: emberRun -} = Ember; - const { _flush, array_flatten, @@ -308,7 +305,7 @@ export default class RecordArrayManager { let array = RecordArray.create({ modelName, - content: Ember.A(content || []), + content: A(content || []), store: this.store, isLoaded: true, manager: this @@ -337,7 +334,7 @@ export default class RecordArrayManager { let array = FilteredRecordArray.create({ query, modelName, - content: Ember.A(), + content: A(), store: this.store, manager: this, filterFunction: filter @@ -365,7 +362,7 @@ export default class RecordArrayManager { array = AdapterPopulatedRecordArray.create({ modelName, query: query, - content: Ember.A(internalModels), + content: A(internalModels), store: this.store, manager: this, isLoaded: true, @@ -379,7 +376,7 @@ export default class RecordArrayManager { array = AdapterPopulatedRecordArray.create({ modelName, query: query, - content: Ember.A(), + content: A(), store: this.store, manager: this }); diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index 240d704ae2b..8ef73763c8c 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -1,14 +1,10 @@ -import Ember from 'ember'; +import { once } from '@ember/runloop'; +import { A } from '@ember/array'; +import { get } from '@ember/object'; import RecordArray from "./record-array"; import cloneNull from "../clone-null"; import { associateWithRecordArray } from '../record-array-manager'; -/** - @module ember-data -*/ - -const { get } = Ember; - /** Represents an ordered list of records whose order and membership is determined by the adapter. For example, a query sent to the adapter @@ -49,7 +45,7 @@ const { get } = Ember; export default RecordArray.extend({ init() { // yes we are touching `this` before super, but ArrayProxy has a bug that requires this. - this.set('content', this.get('content') || Ember.A()); + this.set('content', this.get('content') || A()); this._super(...arguments); this.query = this.query || null; @@ -91,7 +87,7 @@ export default RecordArray.extend({ associateWithRecordArray(internalModels, this); // TODO: should triggering didLoad event be the last action of the runLoop? - Ember.run.once(this, 'trigger', 'didLoad'); + once(this, 'trigger', 'didLoad'); heimdall.stop(token); } }); diff --git a/addon/-private/system/record-arrays/filtered-record-array.js b/addon/-private/system/record-arrays/filtered-record-array.js index 3fb9eaac50f..66ab0ff8016 100644 --- a/addon/-private/system/record-arrays/filtered-record-array.js +++ b/addon/-private/system/record-arrays/filtered-record-array.js @@ -1,12 +1,7 @@ -import Ember from 'ember'; +import { once } from '@ember/runloop'; +import { get, observer } from '@ember/object'; import RecordArray from "./record-array"; -/** - @module ember-data -*/ - -const { get } = Ember; - /** Represents a list of records whose membership is determined by the store. As records are created, loaded, or modified, the store @@ -66,7 +61,7 @@ export default RecordArray.extend({ get(this, 'manager').updateFilter(this, this.modelName, get(this, 'filterFunction')); }, - updateFilter: Ember.observer('filterFunction', function() { - Ember.run.once(this, this._updateFilter); + updateFilter: observer('filterFunction', function() { + once(this, this._updateFilter); }) }); diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index 0b2d42a82d5..220e17f01d2 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -2,12 +2,14 @@ @module ember-data */ -import Ember from 'ember'; +import Evented from '@ember/object/evented'; + +import ArrayProxy from '@ember/array/proxy'; +import { set, get, computed } from '@ember/object'; +import { Promise } from 'rsvp'; import { PromiseArray } from "../promise-proxies"; import SnapshotRecordArray from "../snapshot-record-array"; -const { computed, get, set, RSVP: { Promise } } = Ember; - /** A record array is an array that contains records of a certain modelName. The record array materializes records as needed when they are retrieved for the first @@ -21,7 +23,7 @@ const { computed, get, set, RSVP: { Promise } } = Ember; @uses Ember.Evented */ -export default Ember.ArrayProxy.extend(Ember.Evented, { +export default ArrayProxy.extend(Evented, { init() { this._super(...arguments); diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 3bf43446082..7f0deb237ea 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -1,5 +1,5 @@ +import { resolve } from 'rsvp'; import Model from '../model/model'; -import Ember from 'ember'; import Reference from './reference'; import isEnabled from '../../features'; @@ -240,7 +240,7 @@ BelongsToReference.prototype.meta = function() { @return {Promise} A promise that resolves with the new value in this belongs-to relationship. */ BelongsToReference.prototype.push = function(objectOrPromise) { - return Ember.RSVP.resolve(objectOrPromise).then((data) => { + return resolve(objectOrPromise).then((data) => { let record; if (data instanceof Model) { diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 9f08a7f5e77..e60cc5b7f47 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -1,4 +1,6 @@ -import Ember from 'ember'; +import { A } from '@ember/array'; +import { resolve } from 'rsvp'; +import { get } from '@ember/object'; import Reference from './reference'; import { DEBUG } from '@glimmer/env'; import { deprecate } from '@ember/debug'; @@ -6,11 +8,6 @@ import { assertPolymorphicType } from 'ember-data/-debug'; import isEnabled from '../../features'; -const { - RSVP: { resolve }, - get -} = Ember; - /** A HasManyReference is a low level API that allows users and addon author to perform meta-operations on a has-many relationship. @@ -284,7 +281,7 @@ HasManyReference.prototype.push = function(objectOrPromise) { }); } else { let records = this.store.push(payload); - internalModels = Ember.A(records).mapBy('_internalModel'); + internalModels = A(records).mapBy('_internalModel'); if (DEBUG) { internalModels.forEach((internalModel) => { diff --git a/addon/-private/system/references/record.js b/addon/-private/system/references/record.js index 6b2b77b0502..bace8a75d6d 100644 --- a/addon/-private/system/references/record.js +++ b/addon/-private/system/references/record.js @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import { resolve } from 'rsvp'; import Reference from './reference'; /** @@ -90,7 +90,7 @@ RecordReference.prototype.remoteType = function() { @return Promise a promise for the value (record or relationship) */ RecordReference.prototype.push = function(objectOrPromise) { - return Ember.RSVP.resolve(objectOrPromise).then((data) => { + return resolve(objectOrPromise).then((data) => { return this.store.push(data); }); }; diff --git a/addon/-private/system/relationship-meta.js b/addon/-private/system/relationship-meta.js index bb9763ae145..740eff604ee 100644 --- a/addon/-private/system/relationship-meta.js +++ b/addon/-private/system/relationship-meta.js @@ -1,4 +1,4 @@ -import {singularize} from 'ember-inflector'; +import { singularize } from 'ember-inflector'; import normalizeModelName from './normalize-model-name'; import { DEBUG } from '@glimmer/env'; diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 445d01ffb4e..043d468f02d 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -1,5 +1,5 @@ -import Ember from 'ember'; -import { assert, warn } from '@ember/debug'; +import { computed } from '@ember/object'; +import { assert, warn, inspect } from '@ember/debug'; import normalizeModelName from "../normalize-model-name"; /** @@ -88,7 +88,7 @@ export default function belongsTo(modelName, options) { userEnteredModelName = normalizeModelName(userEnteredModelName); } - assert("The first argument to DS.belongsTo must be a string representing a model type key, not an instance of " + Ember.inspect(userEnteredModelName) + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", typeof userEnteredModelName === 'string' || typeof userEnteredModelName === 'undefined'); + assert("The first argument to DS.belongsTo must be a string representing a model type key, not an instance of " + inspect(userEnteredModelName) + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", typeof userEnteredModelName === 'string' || typeof userEnteredModelName === 'undefined'); opts = opts || {}; @@ -101,7 +101,7 @@ export default function belongsTo(modelName, options) { key: null }; - return Ember.computed({ + return computed({ get(key) { if (opts.hasOwnProperty('serialize')) { warn(`You provided a serialize option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.Serializer and it's implementations https://emberjs.com/api/data/classes/DS.Serializer.html`, false, { diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 528930717a6..872d9f0e1f2 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -1,3 +1,7 @@ +import { A } from '@ember/array'; +import { computed } from '@ember/object'; +import MapWithDefault from '@ember/map/with-default'; +import Map from '@ember/map'; import Ember from 'ember'; import { assert } from '@ember/debug'; import { @@ -5,10 +9,7 @@ import { relationshipFromMeta } from "../relationship-meta"; -const Map = Ember.Map; -const MapWithDefault = Ember.MapWithDefault; - -export const relationshipsDescriptor = Ember.computed(function() { +export const relationshipsDescriptor = computed(function() { if (Ember.testing === true && relationshipsDescriptor._cacheable === true) { relationshipsDescriptor._cacheable = false; } @@ -35,13 +36,13 @@ export const relationshipsDescriptor = Ember.computed(function() { return map; }).readOnly(); -export const relatedTypesDescriptor = Ember.computed(function() { +export const relatedTypesDescriptor = computed(function() { if (Ember.testing === true && relatedTypesDescriptor._cacheable === true) { relatedTypesDescriptor._cacheable = false; } let modelName; - let types = Ember.A(); + let types = A(); // Loop through each computed property on the class, // and create an array of the unique types involved @@ -63,7 +64,7 @@ export const relatedTypesDescriptor = Ember.computed(function() { return types; }).readOnly(); -export const relationshipsByNameDescriptor = Ember.computed(function() { +export const relationshipsByNameDescriptor = computed(function() { let map = Map.create(); this.eachComputedProperty((name, meta) => { diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index 7327331aaf5..ed353e3bd27 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -2,13 +2,13 @@ @module ember-data */ -import Ember from 'ember'; -import { assert } from '@ember/debug'; +import { A } from '@ember/array'; + +import { get, computed } from '@ember/object'; +import { assert, inspect } from '@ember/debug'; import normalizeModelName from "../normalize-model-name"; import isArrayLike from "../is-array-like"; -const { get } = Ember; - /** `DS.hasMany` is used to define One-To-Many and Many-To-Many relationships on a [DS.Model](/api/data/classes/DS.Model.html). @@ -121,7 +121,7 @@ export default function hasMany(type, options) { type = undefined; } - assert(`The first argument to DS.hasMany must be a string representing a model type key, not an instance of ${Ember.inspect(type)}. E.g., to define a relation to the Comment model, use DS.hasMany('comment')`, typeof type === 'string' || typeof type === 'undefined'); + assert(`The first argument to DS.hasMany must be a string representing a model type key, not an instance of ${inspect(type)}. E.g., to define a relation to the Comment model, use DS.hasMany('comment')`, typeof type === 'string' || typeof type === 'undefined'); options = options || {}; @@ -142,14 +142,14 @@ export default function hasMany(type, options) { key: null }; - return Ember.computed({ + return computed({ get(key) { return this._internalModel._relationships.get(key).getRecords(); }, set(key, records) { assert(`You must pass an array of records to set a hasMany relationship`, isArrayLike(records)); - assert(`All elements of a hasMany relationship must be instances of DS.Model, you passed ${Ember.inspect(records)}`, (function() { - return Ember.A(records).every((record) => record.hasOwnProperty('_internalModel') === true); + assert(`All elements of a hasMany relationship must be instances of DS.Model, you passed ${inspect(records)}`, (function() { + return A(records).every((record) => record.hasOwnProperty('_internalModel') === true); })()); let relationship = this._internalModel._relationships.get(key); diff --git a/addon/-private/system/relationships/relationship-payloads-manager.js b/addon/-private/system/relationships/relationship-payloads-manager.js index 60f939e3dfb..3bf03430a0b 100644 --- a/addon/-private/system/relationships/relationship-payloads-manager.js +++ b/addon/-private/system/relationships/relationship-payloads-manager.js @@ -1,8 +1,6 @@ -import Ember from 'ember'; +import { get } from '@ember/object'; import RelationshipPayloads from './relationship-payloads'; -const get = Ember.get; - /** Manages relationship payloads for a given store, for uninitialized relationships. Acts as a single source of truth (of payloads) for both sides diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 79ab00e7700..82a4d968856 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -1,7 +1,5 @@ -import Ember from 'ember'; -import { - assert -} from '@ember/debug'; +import { Promise as EmberPromise } from 'rsvp'; +import { assert, inspect } from '@ember/debug'; import { assertPolymorphicType } from 'ember-data/-debug'; import { PromiseObject @@ -131,7 +129,7 @@ export default class BelongsToRelationship extends Relationship { if (this.inverseInternalModel) { return this.store._findByInternalModel(this.inverseInternalModel); } else { - return Ember.RSVP.Promise.resolve(null); + return EmberPromise.resolve(null); } } @@ -188,7 +186,7 @@ export default class BelongsToRelationship extends Relationship { } updateData(data, initial) { - assert(`Ember Data expected the data for the ${this.key} relationship on a ${this.internalModel.toString()} to be in a JSON API format and include an \`id\` and \`type\` property but it found ${Ember.inspect(data)}. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || data.id !== undefined && data.type !== undefined); + assert(`Ember Data expected the data for the ${this.key} relationship on a ${this.internalModel.toString()} to be in a JSON API format and include an \`id\` and \`type\` property but it found ${inspect(data)}. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || data.id !== undefined && data.type !== undefined); let internalModel = this.store._pushResourceIdentifier(this, data); if (initial) { this.setInitialCanonicalInternalModel(internalModel); diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index 0acc2b86adf..1039683f91e 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -1,10 +1,8 @@ -import Ember from 'ember'; +import { get } from '@ember/object'; import ManyRelationship from "./has-many"; import BelongsToRelationship from "./belongs-to"; import { DEBUG } from '@glimmer/env'; -const { get } = Ember; - function shouldFindInverse(relationshipMeta) { let options = relationshipMeta.options; return !(options && options.inverse === null); diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 140d997d3ca..90ce273b424 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -1,10 +1,9 @@ /* global heimdall */ +import { guidFor } from '@ember/object/internals'; + import { assert, warn } from '@ember/debug'; import OrderedSet from '../../ordered-set'; import _normalizeLink from '../../normalize-link'; -import Ember from 'ember'; - -const { guidFor } = Ember; const { addCanonicalInternalModel, diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index 646f79f9148..98f4842d536 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -2,11 +2,11 @@ @module ember-data */ -import Ember from 'ember'; +import { copy } from '@ember/object/internals'; -const { - get -} = Ember; +import { inspect } from '@ember/debug'; +import EmberError from '@ember/error'; +import { get } from '@ember/object'; /** @class Snapshot @@ -110,7 +110,7 @@ export default class Snapshot { if (keyName in this._attributes) { return this._attributes[keyName]; } - throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no attribute named '" + keyName + "' defined."); + throw new EmberError("Model '" + inspect(this.record) + "' has no attribute named '" + keyName + "' defined."); } /** @@ -127,7 +127,7 @@ export default class Snapshot { @return {Object} All attributes of the current snapshot */ attributes() { - return Ember.copy(this._attributes); + return copy(this._attributes); } /** @@ -150,7 +150,7 @@ export default class Snapshot { for (let i=0, length = changedAttributeKeys.length; i < length; i++) { let key = changedAttributeKeys[i]; - changedAttributes[key] = Ember.copy(this._changedAttributes[key]); + changedAttributes[key] = copy(this._changedAttributes[key]); } return changedAttributes; @@ -206,7 +206,7 @@ export default class Snapshot { relationship = this._internalModel._relationships.get(keyName); if (!(relationship && relationship.relationshipMeta.kind === 'belongsTo')) { - throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined."); + throw new EmberError("Model '" + inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined."); } hasData = get(relationship, 'hasData'); @@ -277,7 +277,7 @@ export default class Snapshot { relationship = this._internalModel._relationships.get(keyName); if (!(relationship && relationship.relationshipMeta.kind === 'hasMany')) { - throw new Ember.Error("Model '" + Ember.inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined."); + throw new EmberError("Model '" + inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined."); } hasData = get(relationship, 'hasData'); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 1ff3c878fa0..5c7d57b9117 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2,14 +2,21 @@ @module ember-data */ +import { A } from '@ember/array'; + +import { copy } from '@ember/object/internals'; +import EmberError from '@ember/error'; +import MapWithDefault from '@ember/map/with-default'; +import { run as emberRun } from '@ember/runloop'; +import { set, get, computed } from '@ember/object'; +import RSVP from 'rsvp'; +import Service from '@ember/service'; +import { typeOf, isPresent, isNone } from '@ember/utils'; + import Ember from 'ember'; import { InvalidError } from '../adapters/errors'; import { instrument } from 'ember-data/-debug'; -import { - assert, - deprecate, - warn -} from '@ember/debug'; +import { assert, deprecate, warn, inspect } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; import Model from './model/model'; import normalizeModelName from "./normalize-model-name"; @@ -50,22 +57,8 @@ import isEnabled from '../features'; const badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; const { - A, _Backburner: Backburner, - computed, - copy, - ENV, - Error: EmberError, - get, - inspect, - isNone, - isPresent, - MapWithDefault, - run: emberRun, - set, - RSVP, - Service, - typeOf + ENV } = Ember; const { Promise } = RSVP; @@ -455,7 +448,7 @@ Store = Service.extend({ @private */ find(modelName, id, options) { - // The default `model` hook in Ember.Route calls `find(modelName, id)`, + // The default `model` hook in Route calls `find(modelName, id)`, // that's why we have to keep this method around even though `findRecord` is // the public way to get a record by modelName and id. assert(`Using store.find(type) has been removed. Use store.findAll(modelName) to retrieve all records for a given type.`, arguments.length !== 1); @@ -482,9 +475,9 @@ Store = Service.extend({ Example ```app/routes/post.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ model(params) { return this.store.findRecord('post', params.post_id); } @@ -602,22 +595,22 @@ Store = Service.extend({ `findRecord`. ```app/routes/post/edit.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ model(params) { return this.store.findRecord('post', params.post_id, { backgroundReload: false }); } }); ``` - If you pass an object on the `adapterOptions` property of the options - argument it will be passed to you adapter via the snapshot + If you pass an object on the `adapterOptions` property of the options + argument it will be passed to you adapter via the snapshot ```app/routes/post/edit.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ model(params) { return this.store.findRecord('post', params.post_id, { adapterOptions: { subscribe: false } @@ -656,11 +649,11 @@ Store = Service.extend({ comments in the same request: ```app/routes/post.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ model(params) { - return this.store.findRecord('post', params.post_id, { include: 'comments' }); + return this.store.findRecord('post', params.post_id, { include: 'comments' }); } }); @@ -674,11 +667,11 @@ Store = Service.extend({ comments and the authors of those comments the request would look like this: ```app/routes/post.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ model(params) { - return this.store.findRecord('post', params.post_id, { include: 'comments,comments.author' }); + return this.store.findRecord('post', params.post_id, { include: 'comments,comments.author' }); } }); @@ -1329,11 +1322,12 @@ Store = Service.extend({ The request is made through the adapters' `queryRecord`: ```app/adapters/user.js + import $ from 'jquery'; import DS from 'ember-data'; export default DS.Adapter.extend({ queryRecord(modelName, query) { - return Ember.$.getJSON('/api/current_user'); + return $.getJSON('/api/current_user'); } }); ``` @@ -1418,9 +1412,9 @@ Store = Service.extend({ of them. ```app/routes/authors.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ model(params) { return this.store.findAll('author'); } @@ -1467,8 +1461,8 @@ Store = Service.extend({ which the promise resolves, is updated automatically so it contains all the records in the store: - ```js - // app/adapters/application.js + ```app/adapters/application.js + import DS from 'ember-data'; export default DS.Adapter.extend({ shouldReloadAll(store, snapshotsArray) { return false; @@ -1511,9 +1505,9 @@ Store = Service.extend({ `findAll`. ```app/routes/post/edit.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ model() { return this.store.findAll('post', { backgroundReload: false }); } @@ -1524,9 +1518,9 @@ Store = Service.extend({ argument it will be passed to you adapter via the `snapshotRecordArray` ```app/routes/posts.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ model(params) { return this.store.findAll('post', { adapterOptions: { subscribe: false } @@ -1566,11 +1560,11 @@ Store = Service.extend({ all of the posts' comments in the same request: ```app/routes/posts.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ model() { - return this.store.findAll('post', { include: 'comments' }); + return this.store.findAll('post', { include: 'comments' }); } }); @@ -1581,11 +1575,11 @@ Store = Service.extend({ comments and the authors of those comments the request would look like this: ```app/routes/posts.js - import Ember from 'ember'; + import Route from '@ember/routing/route'; - export default Ember.Route.extend({ + export default Route.extend({ model() { - return this.store.findAll('post', { include: 'comments,comments.author' }); + return this.store.findAll('post', { include: 'comments,comments.author' }); } }); @@ -1700,18 +1694,18 @@ Store = Service.extend({ }, /** - This method unloads all records in the store. - It schedules unloading to happen during the next run loop. + This method unloads all records in the store. + It schedules unloading to happen during the next run loop. - Optionally you can pass a type which unload all records for a given type. + Optionally you can pass a type which unload all records for a given type. - ```javascript - store.unloadAll(); - store.unloadAll('post'); - ``` + ```javascript + store.unloadAll(); + store.unloadAll('post'); + ``` - @method unloadAll - @param {String} modelName + @method unloadAll + @param {String} modelName */ unloadAll(modelName) { assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, !modelName || typeof modelName === 'string'); diff --git a/addon/-private/system/store/common.js b/addon/-private/system/store/common.js index 8ce2777e417..e0548b71467 100644 --- a/addon/-private/system/store/common.js +++ b/addon/-private/system/store/common.js @@ -1,8 +1,4 @@ -import Ember from 'ember'; - -const { - get -} = Ember; +import { get } from '@ember/object'; const { __bind, diff --git a/addon/-private/system/store/container-instance-cache.js b/addon/-private/system/store/container-instance-cache.js index 82768c827ae..ba0311d6cca 100644 --- a/addon/-private/system/store/container-instance-cache.js +++ b/addon/-private/system/store/container-instance-cache.js @@ -1,6 +1,5 @@ /* global heimdall */ -import Ember from 'ember'; -const { set } = Ember; +import { set } from '@ember/object'; const { __get, diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 30c57ffe73f..0103a0084a1 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -1,4 +1,5 @@ -import Ember from 'ember'; +import { A } from '@ember/array'; +import { Promise } from 'rsvp'; import { assert, warn } from '@ember/debug'; import { _bind, @@ -9,8 +10,6 @@ import { import { normalizeResponseHelper } from "./serializer-response"; import { serializerForAdapter } from "./serializers"; -const { Promise } = Ember.RSVP; - function payloadIsNotBlank(adapterPayload) { if (Array.isArray(adapterPayload)) { return true; @@ -50,7 +49,7 @@ export function _find(adapter, store, modelClass, id, internalModel, options) { } export function _findMany(adapter, store, modelName, ids, internalModels) { - let snapshots = Ember.A(internalModels).invoke('createSnapshot'); + let snapshots = A(internalModels).invoke('createSnapshot'); let modelClass = store.modelFor(modelName); // `adapter.findMany` gets the modelClass still let promise = adapter.findMany(store, modelClass, ids, snapshots); let label = `DS: Handle Adapter#findMany of '${modelName}'`; diff --git a/addon/-private/system/store/serializer-response.js b/addon/-private/system/store/serializer-response.js index 1a264253d49..8a75dde9644 100644 --- a/addon/-private/system/store/serializer-response.js +++ b/addon/-private/system/store/serializer-response.js @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import { isEmpty } from '@ember/utils'; import { assert } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; @@ -79,7 +79,7 @@ export function normalizeResponseHelper(serializer, store, modelClass, payload, if (DEBUG) { validationErrors = validateDocumentStructure(normalizedResponse); } - assert(`normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join('\n\t* ')}`, Ember.isEmpty(validationErrors)); + assert(`normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join('\n\t* ')}`, isEmpty(validationErrors)); return normalizedResponse; } diff --git a/addon/-private/utils.js b/addon/-private/utils.js index a60adb144c5..234af6842fa 100644 --- a/addon/-private/utils.js +++ b/addon/-private/utils.js @@ -1,6 +1,5 @@ -import Ember from 'ember'; - -const get = Ember.get; +import { getOwner as emberGetOwner } from '@ember/application'; +import { get } from '@ember/object'; /* Check if the passed model has a `type` attribute or a relationship named `type`. @@ -20,8 +19,8 @@ function modelHasAttributeOrRelationshipNamedType(modelClass) { function getOwner(context) { let owner; - if (Ember.getOwner) { - owner = Ember.getOwner(context); + if (emberGetOwner) { + owner = emberGetOwner(context); } else if (context.container) { owner = context.container; } diff --git a/addon/adapter.js b/addon/adapter.js index 64b4e8c6be6..ed121c640dd 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -2,7 +2,7 @@ @module ember-data */ -import Ember from 'ember'; +import EmberObject from '@ember/object'; /** An adapter is an object that receives requests from a store and @@ -60,7 +60,7 @@ import Ember from 'ember'; @extends Ember.Object */ -export default Ember.Object.extend({ +export default EmberObject.extend({ /** If you would like your adapter to use a custom serializer you can @@ -94,13 +94,14 @@ export default Ember.Object.extend({ Here is an example `findRecord` implementation: ```app/adapters/application.js - import Ember from 'ember'; import DS from 'ember-data'; + import RSVP from 'RSVP'; + import $ from 'jquery'; export default DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.getJSON(`/${type.modelName}/${id}`).then(function(data) { + return new RSVP.Promise(function(resolve, reject) { + $.getJSON(`/${type.modelName}/${id}`).then(function(data) { resolve(data); }, function(jqXHR) { reject(jqXHR); @@ -125,15 +126,16 @@ export default Ember.Object.extend({ Example ```app/adapters/application.js - import Ember from 'ember'; import DS from 'ember-data'; + import RSVP from 'RSVP'; + import $ from 'jquery'; export default DS.Adapter.extend({ findAll(store, type, sinceToken) { let query = { since: sinceToken }; - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { + return new RSVP.Promise(function(resolve, reject) { + $.getJSON(`/${type.modelName}`, query).then(function(data) { resolve(data); }, function(jqXHR) { reject(jqXHR); @@ -158,13 +160,14 @@ export default Ember.Object.extend({ Example ```app/adapters/application.js - import Ember from 'ember'; import DS from 'ember-data'; + import RSVP from 'RSVP'; + import $ from 'jquery'; export default DS.Adapter.extend({ query(store, type, query) { - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { + return new RSVP.Promise(function(resolve, reject) { + $.getJSON(`/${type.modelName}`, query).then(function(data) { resolve(data); }, function(jqXHR) { reject(jqXHR); @@ -196,13 +199,14 @@ export default Ember.Object.extend({ Example ```app/adapters/application.js - import Ember from 'ember'; import DS from 'ember-data'; + import RSVP from 'RSVP'; + import $ from 'jquery'; export default DS.Adapter.extend(DS.BuildURLMixin, { queryRecord(store, type, query) { - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.getJSON(`/${type.modelName}`, query).then(function(data) { + return new RSVP.Promise(function(resolve, reject) { + $.getJSON(`/${type.modelName}`, query).then(function(data) { resolve(data); }, function(jqXHR) { reject(jqXHR); @@ -290,24 +294,26 @@ export default Ember.Object.extend({ Example ```app/adapters/application.js - import Ember from 'ember'; import DS from 'ember-data'; + import { run } from '@ember/runloop'; + import RSVP from 'RSVP'; + import $ from 'jquery'; export default DS.Adapter.extend({ createRecord(store, type, snapshot) { let data = this.serialize(snapshot, { includeId: true }); - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.ajax({ + return new RSVP.Promise(function(resolve, reject) { + $.ajax({ type: 'POST', url: `/${type.modelName}`, dataType: 'json', data: data }).then(function(data) { - Ember.run(null, resolve, data); + run(null, resolve, data); }, function(jqXHR) { jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); + run(null, reject, jqXHR); }); }); } @@ -339,25 +345,27 @@ export default Ember.Object.extend({ Example ```app/adapters/application.js - import Ember from 'ember'; import DS from 'ember-data'; + import { run } from '@ember/runloop'; + import RSVP from 'RSVP'; + import $ from 'jquery'; export default DS.Adapter.extend({ updateRecord(store, type, snapshot) { let data = this.serialize(snapshot, { includeId: true }); let id = snapshot.id; - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.ajax({ + return new RSVP.Promise(function(resolve, reject) { + $.ajax({ type: 'PUT', url: `/${type.modelName}/${id}`, dataType: 'json', data: data }).then(function(data) { - Ember.run(null, resolve, data); + run(null, resolve, data); }, function(jqXHR) { jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); + run(null, reject, jqXHR); }); }); } @@ -381,25 +389,27 @@ export default Ember.Object.extend({ Example ```app/adapters/application.js - import Ember from 'ember'; import DS from 'ember-data'; + import { run } from '@ember/runloop'; + import RSVP from 'RSVP'; + import $ from 'jquery'; export default DS.Adapter.extend({ deleteRecord(store, type, snapshot) { let data = this.serialize(snapshot, { includeId: true }); let id = snapshot.id; - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.ajax({ + return new RSVP.Promise(function(resolve, reject) { + $.ajax({ type: 'DELETE', url: `/${type.modelName}/${id}`, dataType: 'json', data: data }).then(function(data) { - Ember.run(null, resolve, data); + run(null, resolve, data); }, function(jqXHR) { jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); + run(null, reject, jqXHR); }); }); } @@ -431,22 +441,24 @@ export default Ember.Object.extend({ is true. ```app/adapters/application.js - import Ember from 'ember'; import DS from 'ember-data'; + import { run } from '@ember/runloop'; + import RSVP from 'RSVP'; + import $ from 'jquery'; export default DS.Adapter.extend({ findMany(store, type, ids, snapshots) { - return new Ember.RSVP.Promise(function(resolve, reject) { - Ember.$.ajax({ + return new RSVP.Promise(function(resolve, reject) { + $.ajax({ type: 'GET', url: `/${type.modelName}/`, dataType: 'json', data: { filter: { id: ids.join(',') } } }).then(function(data) { - Ember.run(null, resolve, data); + run(null, resolve, data); }, function(jqXHR) { jqXHR.then = null; // tame jQuery's ill mannered promises - Ember.run(null, reject, jqXHR); + run(null, reject, jqXHR); }); }); } diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index 48610dec134..3d6d986a305 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -2,13 +2,13 @@ /** @module ember-data */ - -import Ember from 'ember'; -import { pluralize } from 'ember-inflector'; +import { dasherize } from '@ember/string'; +import $ from 'jquery'; import RESTAdapter from "./rest"; import { isEnabled } from '../-private'; import { deprecate } from '@ember/debug'; import { instrument } from 'ember-data/-debug'; +import { pluralize } from 'ember-inflector'; /** The `JSONAPIAdapter` is the default adapter used by Ember Data. It @@ -170,7 +170,7 @@ const JSONAPIAdapter = RESTAdapter.extend({ let token = heimdall.start('json.parse'); let json; try { - json = Ember.$.parseJSON(payload); + json = $.parseJSON(payload); } catch (e) { json = payload; } @@ -258,7 +258,7 @@ const JSONAPIAdapter = RESTAdapter.extend({ }, pathForType(modelName) { - let dasherized = Ember.String.dasherize(modelName); + let dasherized = dasherize(modelName); return pluralize(dasherized); }, diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 2c61eccddf2..abf5b847218 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -3,7 +3,12 @@ @module ember-data */ -import Ember from 'ember'; +import $ from 'jquery'; + +import { Promise as EmberPromise } from 'rsvp'; +import MapWithDefault from '@ember/map/with-default'; +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; import Adapter from "../adapter"; import { parseResponseHeaders, @@ -23,13 +28,7 @@ import { instrument } from 'ember-data/-debug'; import { warn, deprecate } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; -const { - MapWithDefault, - get, - run -} = Ember; - -const Promise = Ember.RSVP.Promise; +const Promise = EmberPromise; /** The REST adapter allows your store to communicate with an HTTP server by @@ -249,9 +248,10 @@ const Promise = Ember.RSVP.Promise; ```app/adapters/application.js import DS from 'ember-data'; + import { computed } from '@ember/object'; export default DS.RESTAdapter.extend({ - headers: Ember.computed('session.authToken', function() { + headers: computed('session.authToken', function() { return { 'API_KEY': this.get('session.authToken'), 'ANOTHER_HEADER': 'Some header value' @@ -269,11 +269,13 @@ const Promise = Ember.RSVP.Promise; ```app/adapters/application.js import DS from 'ember-data'; + import { get } from '@ember/object'; + import { computed } from '@ember/object'; export default DS.RESTAdapter.extend({ - headers: Ember.computed(function() { + headers: computed(function() { return { - 'API_KEY': Ember.get(document.cookie.match(/apiKey\=([^;]*)/), '1'), + 'API_KEY': get(document.cookie.match(/apiKey\=([^;]*)/), '1'), 'ANOTHER_HEADER': 'Some header value' }; }).volatile() @@ -1083,7 +1085,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @param {Object} options jQuery ajax options to be used for the ajax request */ _ajaxRequest(options) { - Ember.$.ajax(options); + $.ajax(options); }, /** @@ -1107,7 +1109,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { let token = heimdall.start('json.parse'); let json; try { - json = Ember.$.parseJSON(payload); + json = $.parseJSON(payload); } catch (e) { json = payload; } @@ -1142,7 +1144,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { let json = responseText; try { - json = Ember.$.parseJSON(responseText); + json = $.parseJSON(responseText); } catch (e) { // ignored } @@ -1465,7 +1467,7 @@ if (isEnabled('ds-improved-ajax')) { let token = heimdall.start('json.parse'); let json; try { - json = Ember.$.parseJSON(payload); + json = $.parseJSON(payload); } catch (e) { json = payload; } diff --git a/addon/attr.js b/addon/attr.js index e2695837c53..9436a5ac818 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import { computed } from '@ember/object'; import { deprecate } from '@ember/debug'; /** @@ -134,7 +134,7 @@ export default function attr(type, options) { options: options }; - return Ember.computed({ + return computed({ get(key) { let internalModel = this._internalModel; if (hasValue(internalModel, key)) { diff --git a/addon/index.js b/addon/index.js index a6c0497d9d9..9488e79a16f 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,3 +1,4 @@ +import EmberError from '@ember/error'; import Ember from "ember"; import { deprecate } from '@ember/debug'; @@ -8,7 +9,7 @@ import { deprecate } from '@ember/debug'; */ if (Ember.VERSION.match(/^1\.([0-9]|1[0-2])\./)) { - throw new Ember.Error("Ember Data requires at least Ember 1.13.0, but you have " + + throw new EmberError("Ember Data requires at least Ember 1.13.0, but you have " + Ember.VERSION + ". Please upgrade your version of Ember, then upgrade Ember Data."); } diff --git a/addon/serializer.js b/addon/serializer.js index 136692d1375..ebf99eaba7a 100644 --- a/addon/serializer.js +++ b/addon/serializer.js @@ -2,7 +2,7 @@ @module ember-data */ -import Ember from 'ember'; +import EmberObject from '@ember/object'; /** `DS.Serializer` is an abstract base class that you should override in your @@ -24,7 +24,7 @@ import Ember from 'ember'; @extends Ember.Object */ -export default Ember.Object.extend({ +export default EmberObject.extend({ /** The `store` property is the application's `store` that contains diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index e640b4d5b7e..8bd9c347e3c 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -1,9 +1,10 @@ -import Ember from 'ember'; +import { typeOf } from '@ember/utils'; +import { A } from '@ember/array'; +import Mixin from '@ember/object/mixin'; +import { camelize } from '@ember/string'; +import { set, get } from '@ember/object'; import { warn } from '@ember/debug'; -const { get, set } = Ember; -const { camelize } = Ember.String; - /** ## Using Embedded Records @@ -96,7 +97,7 @@ const { camelize } = Ember.String; @class EmbeddedRecordsMixin @namespace DS */ -export default Ember.Mixin.create({ +export default Mixin.create({ /** Normalize the record and recursively normalize/extract all the embedded records @@ -408,7 +409,7 @@ export default Ember.Mixin.create({ let serializedKey = this.keyForAttribute(relationship.key, 'serialize'); let hasMany = snapshot.hasMany(relationship.key); - json[serializedKey] = Ember.A(hasMany).map(function (recordSnapshot) { + json[serializedKey] = A(hasMany).map(function (recordSnapshot) { // // I'm sure I'm being utterly naive here. Propably id is a configurate property and // type too, and the modelName has to be normalized somehow. @@ -426,7 +427,7 @@ export default Ember.Mixin.create({ warn( `The embedded relationship '${serializedKey}' is undefined for '${snapshot.modelName}' with id '${snapshot.id}'. Please include it in your original payload.`, - Ember.typeOf(snapshot.hasMany(relationship.key)) !== 'undefined', + typeOf(snapshot.hasMany(relationship.key)) !== 'undefined', { id: 'ds.serializer.embedded-relationship-undefined' } ); @@ -438,7 +439,7 @@ export default Ember.Mixin.create({ */ _generateSerializedHasMany(snapshot, relationship) { let hasMany = snapshot.hasMany(relationship.key); - let manyArray = Ember.A(hasMany); + let manyArray = A(hasMany); let ret = new Array(manyArray.length); for (let i = 0; i < manyArray.length; i++) { diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index e7cd457bbd0..7703956aa71 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -2,7 +2,9 @@ @module ember-data */ -import Ember from 'ember'; +import { typeOf, isNone } from '@ember/utils'; + +import { dasherize } from '@ember/string'; import { pluralize, singularize } from 'ember-inflector'; import { assert, deprecate, warn } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; @@ -10,8 +12,6 @@ import { DEBUG } from '@glimmer/env'; import JSONSerializer from './json'; import { normalizeModelName, isEnabled } from '../-private'; -const dasherize = Ember.String.dasherize; - /** Ember Data 2.0 Serializer: @@ -138,7 +138,7 @@ const JSONAPISerializer = JSONSerializer.extend({ */ _normalizeDocumentHelper(documentHash) { - if (Ember.typeOf(documentHash.data) === 'object') { + if (typeOf(documentHash.data) === 'object') { documentHash.data = this._normalizeResourceHelper(documentHash.data); } else if (Array.isArray(documentHash.data)) { let ret = new Array(documentHash.data.length); @@ -202,7 +202,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @private */ _normalizeResourceHelper(resourceHash) { - assert(this.warnMessageForUndefinedType(), !Ember.isNone(resourceHash.type), { + assert(this.warnMessageForUndefinedType(), !isNone(resourceHash.type), { id: 'ds.serializer.type-is-undefined' }); @@ -303,7 +303,7 @@ const JSONAPISerializer = JSONSerializer.extend({ extractRelationship(relationshipHash) { - if (Ember.typeOf(relationshipHash.data) === 'object') { + if (typeOf(relationshipHash.data) === 'object') { relationshipHash.data = this._normalizeRelationshipDataHelper(relationshipHash.data); } @@ -424,30 +424,31 @@ const JSONAPISerializer = JSONSerializer.extend({ }, /** - `keyForAttribute` can be used to define rules for how to convert an - attribute name in your model to a key in your JSON. - By default `JSONAPISerializer` follows the format used on the examples of - http://jsonapi.org/format and uses dashes as the word separator in the JSON - attribute keys. + `keyForAttribute` can be used to define rules for how to convert an + attribute name in your model to a key in your JSON. + By default `JSONAPISerializer` follows the format used on the examples of + http://jsonapi.org/format and uses dashes as the word separator in the JSON + attribute keys. - This behaviour can be easily customized by extending this method. + This behaviour can be easily customized by extending this method. - Example + Example - ```app/serializers/application.js - import DS from 'ember-data'; + ```app/serializers/application.js + import DS from 'ember-data'; + import { dasherize } from '@ember/string'; - export default DS.JSONAPISerializer.extend({ - keyForAttribute(attr, method) { - return Ember.String.dasherize(attr).toUpperCase(); - } - }); - ``` + export default DS.JSONAPISerializer.extend({ + keyForAttribute(attr, method) { + return dasherize(attr).toUpperCase(); + } + }); + ``` - @method keyForAttribute - @param {String} key - @param {String} method - @return {String} normalized key + @method keyForAttribute + @param {String} key + @param {String} method + @return {String} normalized key */ keyForAttribute(key, method) { return dasherize(key); @@ -466,10 +467,11 @@ const JSONAPISerializer = JSONSerializer.extend({ ```app/serializers/post.js import DS from 'ember-data'; + import { underscore } from '@ember/string'; export default DS.JSONAPISerializer.extend({ keyForRelationship(key, relationship, method) { - return Ember.String.underscore(key); + return underscore(key); } }); ``` @@ -742,7 +744,7 @@ if (DEBUG) { JSONAPISerializer.reopen({ willMergeMixin(props) { let constructor = this.constructor; - warn(`You've defined 'extractMeta' in ${constructor.toString()} which is not used for serializers extending JSONAPISerializer. Read more at https://emberjs.com/api/data/classes/DS.JSONAPISerializer.html#toc_customizing-meta on how to customize meta when using JSON API.`, Ember.isNone(props.extractMeta) || props.extractMeta === JSONSerializer.prototype.extractMeta, { + warn(`You've defined 'extractMeta' in ${constructor.toString()} which is not used for serializers extending JSONAPISerializer. Read more at https://emberjs.com/api/data/classes/DS.JSONAPISerializer.html#toc_customizing-meta on how to customize meta when using JSON API.`, isNone(props.extractMeta) || props.extractMeta === JSONSerializer.prototype.extractMeta, { id: 'ds.serializer.json-api.extractMeta' }); warn('The JSONAPISerializer does not work with the EmbeddedRecordsMixin because the JSON API spec does not describe how to format embedded resources.', !props.isEmbeddedRecordsMixin, { diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 8547a42f886..1008ca381d7 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1,4 +1,6 @@ -import Ember from 'ember'; +import { assign, merge } from '@ember/polyfills'; +import { isNone, typeOf } from '@ember/utils'; +import { get } from '@ember/object'; import { assert, deprecate, warn } from '@ember/debug'; import Serializer from "../serializer"; import { @@ -10,9 +12,7 @@ import { isEnabled } from '../-private'; -const get = Ember.get; -const isNone = Ember.isNone; -const assign = Ember.assign || Ember.merge; +const emberAssign = assign || merge; /** Ember Data 2.0 Serializer: @@ -458,7 +458,7 @@ const JSONSerializer = Serializer.extend({ let meta = this.extractMeta(store, primaryModelClass, payload); if (meta) { - assert('The `meta` returned from `extractMeta` has to be an object, not "' + Ember.typeOf(meta) + '".', Ember.typeOf(meta) === 'object'); + assert('The `meta` returned from `extractMeta` has to be an object, not "' + typeOf(meta) + '".', typeOf(meta) === 'object'); documentHash.meta = meta; } @@ -502,13 +502,15 @@ const JSONSerializer = Serializer.extend({ ```app/serializers/application.js import DS from 'ember-data'; + import { underscore } from '@ember/string'; + import { get } from '@ember/object'; export default DS.JSONSerializer.extend({ normalize(typeClass, hash) { - var fields = Ember.get(typeClass, 'fields'); + var fields = get(typeClass, 'fields'); fields.forEach(function(field) { - var payloadField = Ember.String.underscore(field); + var payloadField = underscore(field); if (field === payloadField) { return; } hash[field] = hash[payloadField]; @@ -530,7 +532,7 @@ const JSONSerializer = Serializer.extend({ if (resourceHash) { this.normalizeUsingDeclaredMapping(modelClass, resourceHash); - if (Ember.typeOf(resourceHash.links) === 'object') { + if (typeOf(resourceHash.links) === 'object') { this.normalizeUsingDeclaredMapping(modelClass, resourceHash.links); } @@ -596,13 +598,13 @@ const JSONSerializer = Serializer.extend({ @return {Object} */ extractRelationship(relationshipModelName, relationshipHash) { - if (Ember.isNone(relationshipHash)) { return null; } + if (isNone(relationshipHash)) { return null; } /* When `relationshipHash` is an object it usually means that the relationship is polymorphic. It could however also be embedded resources that the EmbeddedRecordsMixin has be able to process. */ - if (Ember.typeOf(relationshipHash) === 'object') { + if (typeOf(relationshipHash) === 'object') { if (relationshipHash.id) { relationshipHash.id = coerceId(relationshipHash.id); } @@ -687,7 +689,7 @@ const JSONSerializer = Serializer.extend({ data = this.extractRelationship(relationshipMeta.type, relationshipHash); } } else if (relationshipMeta.kind === 'hasMany') { - if (!Ember.isNone(relationshipHash)) { + if (!isNone(relationshipHash)) { data = new Array(relationshipHash.length); for (let i = 0, l = relationshipHash.length; i < l; i++) { let item = relationshipHash[i]; @@ -1069,10 +1071,11 @@ const JSONSerializer = Serializer.extend({ ```app/serializers/application.js import DS from 'ember-data'; + import { decamelize } from '@ember/string'; export default DS.RESTSerializer.extend({ serializeIntoHash(data, type, snapshot, options) { - var root = Ember.String.decamelize(type.modelName); + var root = decamelize(type.modelName); data[root] = this.serialize(snapshot, options); } }); @@ -1085,33 +1088,33 @@ const JSONSerializer = Serializer.extend({ @param {Object} options */ serializeIntoHash(hash, typeClass, snapshot, options) { - assign(hash, this.serialize(snapshot, options)); + emberAssign(hash, this.serialize(snapshot, options)); }, /** - `serializeAttribute` can be used to customize how `DS.attr` - properties are serialized + `serializeAttribute` can be used to customize how `DS.attr` + properties are serialized - For example if you wanted to ensure all your attributes were always - serialized as properties on an `attributes` object you could - write: + For example if you wanted to ensure all your attributes were always + serialized as properties on an `attributes` object you could + write: - ```app/serializers/application.js - import DS from 'ember-data'; + ```app/serializers/application.js + import DS from 'ember-data'; - export default DS.JSONSerializer.extend({ - serializeAttribute(snapshot, json, key, attributes) { - json.attributes = json.attributes || {}; - this._super(snapshot, json.attributes, key, attributes); - } - }); - ``` + export default DS.JSONSerializer.extend({ + serializeAttribute(snapshot, json, key, attributes) { + json.attributes = json.attributes || {}; + this._super(snapshot, json.attributes, key, attributes); + } + }); + ``` - @method serializeAttribute - @param {DS.Snapshot} snapshot - @param {Object} json - @param {String} key - @param {Object} attribute + @method serializeAttribute + @param {DS.Snapshot} snapshot + @param {Object} json + @param {String} key + @param {Object} attribute */ serializeAttribute(snapshot, json, key, attribute) { @@ -1136,30 +1139,31 @@ const JSONSerializer = Serializer.extend({ }, /** - `serializeBelongsTo` can be used to customize how `DS.belongsTo` - properties are serialized. + `serializeBelongsTo` can be used to customize how `DS.belongsTo` + properties are serialized. - Example + Example - ```app/serializers/post.js - import DS from 'ember-data'; + ```app/serializers/post.js + import DS from 'ember-data'; + import { isNone } from '@ember/utils'; - export default DS.JSONSerializer.extend({ - serializeBelongsTo(snapshot, json, relationship) { - var key = relationship.key; - var belongsTo = snapshot.belongsTo(key); + export default DS.JSONSerializer.extend({ + serializeBelongsTo(snapshot, json, relationship) { + var key = relationship.key; + var belongsTo = snapshot.belongsTo(key); - key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo", "serialize") : key; + key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo", "serialize") : key; - json[key] = Ember.isNone(belongsTo) ? belongsTo : belongsTo.record.toJSON(); - } - }); - ``` + json[key] = isNone(belongsTo) ? belongsTo : belongsTo.record.toJSON(); + } + }); + ``` - @method serializeBelongsTo - @param {DS.Snapshot} snapshot - @param {Object} json - @param {Object} relationship + @method serializeBelongsTo + @param {DS.Snapshot} snapshot + @param {Object} json + @param {Object} relationship */ serializeBelongsTo(snapshot, json, relationship) { let key = relationship.key; @@ -1246,6 +1250,7 @@ const JSONSerializer = Serializer.extend({ ```app/serializers/comment.js import DS from 'ember-data'; + import { isNone } from '@ember/utils'; export default DS.JSONSerializer.extend({ serializePolymorphicType(snapshot, json, relationship) { @@ -1254,7 +1259,7 @@ const JSONSerializer = Serializer.extend({ key = this.keyForAttribute ? this.keyForAttribute(key, 'serialize') : key; - if (Ember.isNone(belongsTo)) { + if (isNone(belongsTo)) { json[key + '_type'] = null; } else { json[key + '_type'] = belongsTo.modelName; @@ -1416,52 +1421,54 @@ const JSONSerializer = Serializer.extend({ }, /** - `keyForAttribute` can be used to define rules for how to convert an - attribute name in your model to a key in your JSON. + `keyForAttribute` can be used to define rules for how to convert an + attribute name in your model to a key in your JSON. - Example + Example - ```app/serializers/application.js - import DS from 'ember-data'; + ```app/serializers/application.js + import DS from 'ember-data'; + import { underscore } from '@ember/string'; - export default DS.RESTSerializer.extend({ - keyForAttribute(attr, method) { - return Ember.String.underscore(attr).toUpperCase(); - } - }); - ``` + export default DS.RESTSerializer.extend({ + keyForAttribute(attr, method) { + return underscore(attr).toUpperCase(); + } + }); + ``` - @method keyForAttribute - @param {String} key - @param {String} method - @return {String} normalized key + @method keyForAttribute + @param {String} key + @param {String} method + @return {String} normalized key */ keyForAttribute(key, method) { return key; }, /** - `keyForRelationship` can be used to define a custom key when - serializing and deserializing relationship properties. By default - `JSONSerializer` does not provide an implementation of this method. + `keyForRelationship` can be used to define a custom key when + serializing and deserializing relationship properties. By default + `JSONSerializer` does not provide an implementation of this method. - Example + Example - ```app/serializers/post.js - import DS from 'ember-data'; + ```app/serializers/post.js + import DS from 'ember-data'; + import { underscore } from '@ember/string'; - export default DS.JSONSerializer.extend({ - keyForRelationship(key, relationship, method) { - return 'rel_' + Ember.String.underscore(key); - } - }); - ``` + export default DS.JSONSerializer.extend({ + keyForRelationship(key, relationship, method) { + return `rel_${underscore(key)}`; + } + }); + ``` - @method keyForRelationship - @param {String} key - @param {String} typeClass - @param {String} method - @return {String} normalized key + @method keyForRelationship + @param {String} key + @param {String} typeClass + @param {String} method + @return {String} normalized key */ keyForRelationship(key, typeClass, method) { return key; diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 761ff6405c7..f10533fd614 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -2,15 +2,21 @@ @module ember-data */ -import Ember from 'ember'; +import { typeOf, isNone } from '@ember/utils'; + +import { makeArray } from '@ember/array'; +import { camelize } from '@ember/string'; import { singularize } from "ember-inflector"; import { assert, deprecate, warn } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; import JSONSerializer from "../serializers/json"; -import { coerceId, modelHasAttributeOrRelationshipNamedType, normalizeModelName, isEnabled } from '../-private'; - -const { camelize } = Ember.String; +import { + coerceId, + modelHasAttributeOrRelationshipNamedType, + normalizeModelName, + isEnabled +} from '../-private'; /** Normally, applications will use the `RESTSerializer` by implementing @@ -37,10 +43,11 @@ const { camelize } = Ember.String; ```app/serializers/application.js import DS from 'ember-data'; + import { underscore } from '@ember/string'; export default DS.RESTSerializer.extend({ keyForAttribute(attr, method) { - return Ember.String.underscore(attr).toUpperCase(); + return underscore(attr).toUpperCase(); } }); ``` @@ -185,7 +192,7 @@ const RESTSerializer = JSONSerializer.extend({ let modelClass = store.modelFor(modelName); let serializer = store.serializerFor(modelName); - Ember.makeArray(arrayHash).forEach((hash) => { + makeArray(arrayHash).forEach((hash) => { let { data, included } = this._normalizePolymorphicRecord(store, hash, prop, modelClass, serializer); documentHash.data.push(data); if (included) { @@ -249,7 +256,7 @@ const RESTSerializer = JSONSerializer.extend({ let meta = this.extractMeta(store, primaryModelClass, payload); if (meta) { - assert('The `meta` returned from `extractMeta` has to be an object, not "' + Ember.typeOf(meta) + '".', Ember.typeOf(meta) === 'object'); + assert('The `meta` returned from `extractMeta` has to be an object, not "' + typeOf(meta) + '".', typeOf(meta) === 'object'); documentHash.meta = meta; } @@ -423,7 +430,7 @@ const RESTSerializer = JSONSerializer.extend({ var type = store.modelFor(modelName); var typeSerializer = store.serializerFor(type.modelName); - Ember.makeArray(payload[prop]).forEach(hash => { + makeArray(payload[prop]).forEach(hash => { let { data, included } = typeSerializer.normalize(type, hash, prop); documentHash.data.push(data); if (included) { @@ -586,6 +593,7 @@ const RESTSerializer = JSONSerializer.extend({ ```app/serializers/application.js import DS from 'ember-data'; + import { pluralize } from 'ember-inflector'; export default DS.RESTSerializer.extend({ serialize(snapshot, options) { @@ -614,7 +622,7 @@ const RESTSerializer = JSONSerializer.extend({ } function serverHasManyName(name) { - return serverAttributeName(name.singularize()) + "_IDS"; + return serverAttributeName(singularize(name)) + "_IDS"; } ``` @@ -668,10 +676,11 @@ const RESTSerializer = JSONSerializer.extend({ ```app/serializers/application.js import DS from 'ember-data'; + import { decamelize } from '@ember/string'; export default DS.RESTSerializer.extend({ serializeIntoHash(data, type, record, options) { - var root = Ember.String.decamelize(type.modelName); + var root = decamelize(type.modelName); data[root] = this.serialize(record, options); } }); @@ -709,10 +718,11 @@ const RESTSerializer = JSONSerializer.extend({ ```app/serializers/application.js import DS from 'ember-data'; + import { dasherize } from '@ember/string'; export default DS.RESTSerializer.extend({ payloadKeyFromModelName(modelName) { - return Ember.String.dasherize(modelName); + return dasherize(modelName); } }); ``` @@ -770,7 +780,7 @@ const RESTSerializer = JSONSerializer.extend({ typeKey = key; } - if (Ember.isNone(belongsTo)) { + if (isNone(belongsTo)) { json[typeKey] = null; } else { if (isEnabled("ds-payload-type-hooks")) { diff --git a/addon/transforms/boolean.js b/addon/transforms/boolean.js index 51fc34d783a..4dfeb4a834c 100644 --- a/addon/transforms/boolean.js +++ b/addon/transforms/boolean.js @@ -1,8 +1,6 @@ -import Ember from 'ember'; +import { isNone } from '@ember/utils'; import Transform from './transform'; -const { isNone } = Ember; - /** The `DS.BooleanTransform` class is used to serialize and deserialize boolean attributes on Ember Data record objects. This transform is diff --git a/addon/transforms/number.js b/addon/transforms/number.js index f35dcde9be2..4bc294e9d88 100644 --- a/addon/transforms/number.js +++ b/addon/transforms/number.js @@ -1,8 +1,6 @@ -import Ember from 'ember'; +import { isEmpty as empty } from '@ember/utils'; import Transform from './transform'; -const empty = Ember.isEmpty; - function isNumber(value) { return value === value && value !== Infinity && value !== -Infinity; } diff --git a/addon/transforms/string.js b/addon/transforms/string.js index c687d3499a7..2c071006920 100644 --- a/addon/transforms/string.js +++ b/addon/transforms/string.js @@ -1,8 +1,6 @@ -import Ember from 'ember'; +import { isNone as none } from '@ember/utils'; import Transform from './transform'; -const none = Ember.isNone; - /** The `DS.StringTransform` class is used to serialize and deserialize string attributes on Ember Data record objects. This transform is diff --git a/addon/transforms/transform.js b/addon/transforms/transform.js index a13cc3fe527..c04986d1f44 100644 --- a/addon/transforms/transform.js +++ b/addon/transforms/transform.js @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import EmberObject from '@ember/object'; /** The `DS.Transform` class is used to serialize and deserialize model @@ -67,7 +67,7 @@ import Ember from 'ember'; @class Transform @namespace DS */ -export default Ember.Object.extend({ +export default EmberObject.extend({ /** When given a deserialized value from a record attribute this method must return the serialized value. @@ -75,8 +75,10 @@ export default Ember.Object.extend({ Example ```javascript + import { isEmpty } from '@ember/utils'; + serialize(deserialized, options) { - return Ember.isEmpty(deserialized) ? null : Number(deserialized); + return isEmpty(deserialized) ? null : Number(deserialized); } ``` diff --git a/app/initializers/ember-data.js b/app/initializers/ember-data.js index ba03dbbc552..fba3329b260 100644 --- a/app/initializers/ember-data.js +++ b/app/initializers/ember-data.js @@ -15,16 +15,23 @@ import 'ember-data'; For example, imagine an Ember.js application with the following classes: - App.StoreService = DS.Store.extend({ + ```app/services/store.js + import DS from 'ember-data'; + + export default DS.Store.extend({ adapter: 'custom' }); + ``` + + ```app/controllers/posts.js + import { Controller } from '@ember/controller'; - App.PostsController = Ember.Controller.extend({ + export default Controller.extend({ // ... }); - When the application is initialized, `App.ApplicationStore` will automatically be - instantiated, and the instance of `App.PostsController` will have its `store` + When the application is initialized, `ApplicationStore` will automatically be + instantiated, and the instance of `PostsController` will have its `store` property set to that instance. Note that this code will only be run if the `ember-application` package is diff --git a/lib/babel-build.js b/lib/babel-build.js index 4cfbfc0dce7..4f36eadbb90 100644 --- a/lib/babel-build.js +++ b/lib/babel-build.js @@ -50,6 +50,7 @@ function babelOptions(libraryName, _options) { options.plugins = options.plugins.concat([ getDebugMacroPlugins(), + ['ember-modules-api-polyfill', { blacklist: { '@ember/debug': ['assert', 'deprecate', 'warn']} }], ['transform-es2015-modules-amd', { noInterop: true, loose: true }], 'transform-es2015-arrow-functions', 'transform-es2015-computed-properties', diff --git a/package.json b/package.json index c5aa4b71b9e..844a8fe28f5 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "license": "MIT", "dependencies": { "amd-name-resolver": "0.0.7", + "babel-plugin-ember-modules-api-polyfill": "^1.4.2", "babel-plugin-feature-flags": "^0.3.1", "babel-plugin-filter-imports": "^0.3.1", "babel-plugin-transform-es2015-block-scoping": "^6.24.1", @@ -37,7 +38,7 @@ "chalk": "^1.1.1", "co": "^4.6.0", "common-tags": "^1.4.0", - "ember-cli-babel": "^6.4.1", + "ember-cli-babel": "^6.8.2", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.0.0", "ember-cli-test-info": "^1.0.0", diff --git a/tests/dummy/app/app.js b/tests/dummy/app/app.js index c15f9359323..b3b2bd677e0 100644 --- a/tests/dummy/app/app.js +++ b/tests/dummy/app/app.js @@ -1,9 +1,9 @@ -import Ember from 'ember'; +import Application from '@ember/application'; import Resolver from './resolver'; import loadInitializers from 'ember-load-initializers'; import config from './config/environment'; -const App = Ember.Application.extend({ +const App = Application.extend({ modulePrefix: config.modulePrefix, podModulePrefix: config.podModulePrefix, Resolver diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js index 206b248415f..8f3740ce8a6 100644 --- a/tests/dummy/app/router.js +++ b/tests/dummy/app/router.js @@ -1,7 +1,7 @@ -import Ember from 'ember'; +import EmberRouter from '@ember/routing/router'; import config from './config/environment'; -const Router = Ember.Router.extend({ +const Router = EmberRouter.extend({ location: config.locationType, rootURL: config.rootURL }); diff --git a/tests/dummy/app/routes/application/route.js b/tests/dummy/app/routes/application/route.js index 26d9f3124ec..6c74252aa1b 100644 --- a/tests/dummy/app/routes/application/route.js +++ b/tests/dummy/app/routes/application/route.js @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import Route from '@ember/routing/route'; -export default Ember.Route.extend({ +export default Route.extend({ }); diff --git a/tests/dummy/app/routes/index/route.js b/tests/dummy/app/routes/index/route.js index 26d9f3124ec..6c74252aa1b 100644 --- a/tests/dummy/app/routes/index/route.js +++ b/tests/dummy/app/routes/index/route.js @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import Route from '@ember/routing/route'; -export default Ember.Route.extend({ +export default Route.extend({ }); diff --git a/tests/dummy/app/routes/query/controller.js b/tests/dummy/app/routes/query/controller.js index 433dfb32b26..0c416ad7362 100644 --- a/tests/dummy/app/routes/query/controller.js +++ b/tests/dummy/app/routes/query/controller.js @@ -1,8 +1,4 @@ -import Ember from 'ember'; - -const { - Controller -} = Ember; +import Controller from '@ember/controller'; export default Controller.extend({ queryParams: ['limit', 'modelName', 'included', 'eagerMaterialize', 'eagerRelationships'], diff --git a/tests/dummy/app/routes/query/route.js b/tests/dummy/app/routes/query/route.js index 552f41f2e0d..104824bce44 100644 --- a/tests/dummy/app/routes/query/route.js +++ b/tests/dummy/app/routes/query/route.js @@ -1,5 +1,5 @@ /* global window, heimdall, console */ -import Ember from 'ember'; +import Route from '@ember/routing/route'; // fallback if no-heimdall happens to be present when loading the dummy app let heimdall = self.heimdall; @@ -11,10 +11,6 @@ if (typeof heimdall !== 'object') { } -const { - Route -} = Ember; - export default Route.extend({ queryParams: { limit: { diff --git a/tests/helpers/async.js b/tests/helpers/async.js index 75f10b9960d..5a0e787af55 100644 --- a/tests/helpers/async.js +++ b/tests/helpers/async.js @@ -1,4 +1,5 @@ -import Ember from 'ember'; +import { all, resolve } from 'rsvp'; +import { run } from '@ember/runloop'; export function wait(callback, timeout) { let done = this.async(); @@ -14,7 +15,7 @@ export function wait(callback, timeout) { let args = arguments; let result; try { - result = Ember.run(() => callback.apply(this, args)); + result = run(() => callback.apply(this, args)); } finally { done(); } @@ -23,9 +24,9 @@ export function wait(callback, timeout) { } export function asyncEqual(a, b, message) { - return Ember.RSVP.all([ - Ember.RSVP.resolve(a), - Ember.RSVP.resolve(b) + return all([ + resolve(a), + resolve(b) ]).then(this.wait((array) => { this.push(array[0] === array[1], array[0], array[1], message); })); diff --git a/tests/helpers/custom-adapter.js b/tests/helpers/custom-adapter.js index 99ca0eaa207..d5cc031a2f9 100644 --- a/tests/helpers/custom-adapter.js +++ b/tests/helpers/custom-adapter.js @@ -1,4 +1,4 @@ -import Ember from 'ember'; +import { run } from '@ember/runloop'; import DS from 'ember-data'; export default function(env, adapterDefinition) { @@ -8,5 +8,5 @@ export default function(env, adapterDefinition) { } let store = env.store; env.registry.register('adapter:-custom', adapter); - Ember.run(() => store.set('adapter', '-custom')); + run(() => store.set('adapter', '-custom')); } diff --git a/tests/helpers/destroy-app.js b/tests/helpers/destroy-app.js index c3d4d1abb5d..e7f983bd14b 100644 --- a/tests/helpers/destroy-app.js +++ b/tests/helpers/destroy-app.js @@ -1,5 +1,5 @@ -import Ember from 'ember'; +import { run } from '@ember/runloop'; export default function destroyApp(application) { - Ember.run(application, 'destroy'); + run(application, 'destroy'); } diff --git a/tests/helpers/module-for-acceptance.js b/tests/helpers/module-for-acceptance.js index 76996fd0428..0daf9c9a7e2 100644 --- a/tests/helpers/module-for-acceptance.js +++ b/tests/helpers/module-for-acceptance.js @@ -1,10 +1,8 @@ +import { Promise } from 'rsvp'; import { module } from 'qunit'; -import Ember from 'ember'; import startApp from '../helpers/start-app'; import destroyApp from '../helpers/destroy-app'; -const { RSVP: { Promise } } = Ember; - export default function(name, options = {}) { module(name, { beforeEach() { diff --git a/tests/helpers/owner.js b/tests/helpers/owner.js index f4037cda0e4..8b8e3abee97 100644 --- a/tests/helpers/owner.js +++ b/tests/helpers/owner.js @@ -1,11 +1,12 @@ +import EmberObject from '@ember/object'; import Ember from 'ember'; let Owner; if (Ember._RegistryProxyMixin && Ember._ContainerProxyMixin) { - Owner = Ember.Object.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin); + Owner = EmberObject.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin); } else { - Owner = Ember.Object.extend(); + Owner = EmberObject.extend(); } export default Owner; diff --git a/tests/helpers/start-app.js b/tests/helpers/start-app.js index e098f1d5be6..37db37f585e 100644 --- a/tests/helpers/start-app.js +++ b/tests/helpers/start-app.js @@ -1,14 +1,15 @@ -import Ember from 'ember'; +import { run } from '@ember/runloop'; +import { merge } from '@ember/polyfills'; import Application from '../../app'; import config from '../../config/environment'; export default function startApp(attrs) { let application; - let attributes = Ember.merge({}, config.APP); - attributes = Ember.merge(attributes, attrs); // use defaults, but you can override; + let attributes = merge({}, config.APP); + attributes = merge(attributes, attrs); // use defaults, but you can override; - Ember.run(() => { + run(() => { application = Application.create(attributes); application.setupForTesting(); application.injectTestHelpers(); diff --git a/tests/helpers/store.js b/tests/helpers/store.js index 10c9ca862cd..6803fd81b30 100644 --- a/tests/helpers/store.js +++ b/tests/helpers/store.js @@ -1,3 +1,4 @@ +import { dasherize } from '@ember/string'; import Ember from 'ember'; import DS from 'ember-data'; import Owner from './owner'; @@ -38,7 +39,7 @@ export default function setupStore(options) { } for (let prop in options) { - registry.register('model:' + Ember.String.dasherize(prop), options[prop]); + registry.register('model:' + dasherize(prop), options[prop]); } registry.register('service:store', DS.Store.extend({ diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index f3adddc18f2..b550bf85afe 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -1,15 +1,17 @@ +import { decamelize, underscore } from '@ember/string'; +import { copy } from '@ember/object/internals'; +import RSVP from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import { pluralize } from 'ember-inflector'; import { isEnabled } from 'ember-data/-private'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let env, store, adapter, Post, Comment, SuperUser; let passedUrl; -const { run } = Ember; module("integration/adapter/build-url-mixin - BuildURLMixin with RESTAdapter", { beforeEach() { @@ -46,13 +48,13 @@ function ajaxResponse(value) { adapter._makeRequest = function(request) { passedUrl = request.url; - return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); + return run(RSVP, 'resolve', copy(value, true)); }; } else { adapter.ajax = function(url, verb, hash) { passedUrl = url; - return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); + return run(RSVP, 'resolve', copy(value, true)); }; } } @@ -184,8 +186,8 @@ test('buildURL - with full URLs in links', function(assert) { test('buildURL - with camelized names', function(assert) { adapter.setProperties({ pathForType(type) { - let decamelized = Ember.String.decamelize(type); - return Ember.String.underscore(pluralize(decamelized)); + let decamelized = decamelize(type); + return underscore(pluralize(decamelized)); } }); diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index b58f70ca5c9..28ab5e1a574 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -1,13 +1,13 @@ -import {createStore} from 'dummy/tests/helpers/store'; +import { reject, resolve, defer } from 'rsvp'; +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; +import { createStore } from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; const { attr } = DS; -const { get, run } = Ember; -const { resolve, reject } = Ember.RSVP; let Person, store, allRecords, env; @@ -154,7 +154,7 @@ test("When all records for a type are requested, records that are created on the testInDebug('When all records are requested, assert the payload is not blank', (assert) => { env.registry.register('adapter:person', DS.Adapter.extend({ - findAll: () => Ember.RSVP.resolve({}) + findAll: () => resolve({}) })); assert.expectAssertion(() => { @@ -163,7 +163,7 @@ testInDebug('When all records are requested, assert the payload is not blank', ( }); test("isUpdating is true while records are fetched", function(assert) { - let findAllDeferred = Ember.RSVP.defer(); + let findAllDeferred = defer(); env.registry.register('adapter:person', DS.Adapter.extend({ findAll() { return findAllDeferred.promise; @@ -199,7 +199,7 @@ test("isUpdating is true while records are fetched", function(assert) { }); test("isUpdating is true while records are fetched in the background", function(assert) { - let findAllDeferred = Ember.RSVP.defer(); + let findAllDeferred = defer(); env.registry.register('adapter:person', DS.Adapter.extend({ findAll() { return findAllDeferred.promise; @@ -247,7 +247,7 @@ test("isUpdating is true while records are fetched in the background", function( }); test("isUpdating is false if records are not fetched in the background", function(assert) { - let findAllDeferred = Ember.RSVP.defer(); + let findAllDeferred = defer(); env.registry.register('adapter:person', DS.Adapter.extend({ findAll() { return findAllDeferred.promise; diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 17b3225768f..4e5a98e5b14 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -1,12 +1,11 @@ +import { Promise, reject, defer, resolve } from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { run } = Ember; const { attr } = DS; -const { reject, Promise } = Ember.RSVP; let Person, store, env; @@ -70,7 +69,7 @@ test("When a single record is requested, the adapter's find method should be cal }); test("When a single record is requested multiple times, all .findRecord() calls are resolved after the promise is resolved", function(assert) { - let deferred = Ember.RSVP.defer(); + let deferred = defer(); env.registry.register('adapter:person', DS.Adapter.extend({ findRecord() { @@ -143,7 +142,7 @@ test("When a single record is requested, and the promise is rejected, the record testInDebug('When a single record is requested, and the payload is blank', function(assert) { env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord: () => Ember.RSVP.resolve({}) + findRecord: () => resolve({}) })); assert.expectAssertion(() => { @@ -154,7 +153,7 @@ testInDebug('When a single record is requested, and the payload is blank', funct testInDebug('When multiple records are requested, and the payload is blank', function(assert) { env.registry.register('adapter:person', DS.Adapter.extend({ coalesceFindRequests: true, - findMany: () => Ember.RSVP.resolve({}) + findMany: () => resolve({}) })); assert.expectAssertion(() => { diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index 313fc0ee939..acfcbf16fd4 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -1,7 +1,8 @@ +import RSVP from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import DS from 'ember-data'; @@ -10,8 +11,6 @@ import { isEnabled } from 'ember-data/-private'; let env, store, adapter; let passedUrl, passedVerb, passedHash; -const { run } = Ember; - let User, Post, Comment, Handle, GithubHandle, TwitterHandle, Company, DevelopmentShop, DesignStudio; module('integration/adapter/json-api-adapter - JSONAPIAdapter', { @@ -99,7 +98,7 @@ function ajaxResponse(responses) { passedVerb[index] = request.method; passedHash[index] = request.data ? { data: request.data } : undefined; - return run(Ember.RSVP, 'resolve', responses[index]); + return run(RSVP, 'resolve', responses[index]); }; } else { adapter.ajax = function(url, verb, hash) { @@ -109,7 +108,7 @@ function ajaxResponse(responses) { passedVerb[index] = verb; passedHash[index] = hash; - return run(Ember.RSVP, 'resolve', responses[index]); + return run(RSVP, 'resolve', responses[index]); }; } } diff --git a/tests/integration/adapter/queries-test.js b/tests/integration/adapter/queries-test.js index fcfed256fb0..d42574d137f 100644 --- a/tests/integration/adapter/queries-test.js +++ b/tests/integration/adapter/queries-test.js @@ -1,13 +1,13 @@ +import { Promise as EmberPromise, resolve } from 'rsvp'; +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { get, run } = Ember; - let Person, env, store, adapter; module("integration/adapter/queries - Queries", { @@ -45,7 +45,7 @@ test("When a query is made, the adapter should receive a record array it can pop adapter.query = function(store, type, query, recordArray) { assert.equal(type, Person, "the query method is called with the correct type"); - return Ember.RSVP.Promise.resolve({ + return EmberPromise.resolve({ data: [ { id: 1, @@ -76,7 +76,7 @@ test("When a query is made, the adapter should receive a record array it can pop test("a query can be updated via `update()`", function(assert) { adapter.query = function() { - return Ember.RSVP.resolve({ data: [{ id: 'first', type: 'person' }] }); + return resolve({ data: [{ id: 'first', type: 'person' }] }); }; return run(() => { @@ -87,7 +87,7 @@ test("a query can be updated via `update()`", function(assert) { adapter.query = function() { assert.ok('query is called a second time'); - return Ember.RSVP.resolve({data: [{ id: 'second', type: 'person' }] }); + return resolve({data: [{ id: 'second', type: 'person' }] }); }; let updateQuery = query.update(); @@ -113,10 +113,10 @@ testInDebug("The store asserts when query is made and the adapter responses with adapter.query = function(store, type, query, recordArray) { assert.equal(type, Person, "the query method is called with the correct type"); - return Ember.RSVP.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Peter Wagenet" } }] }); + return resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Peter Wagenet" } }] }); }; assert.expectAssertion(() => { - Ember.run(() => store.query('person', { page: 1 })); + run(() => store.query('person', { page: 1 })); }, /The response to store.query is expected to be an array but it was a single record/); }); diff --git a/tests/integration/adapter/record-persistence-test.js b/tests/integration/adapter/record-persistence-test.js index ac7047ef8c8..62da7acd16f 100644 --- a/tests/integration/adapter/record-persistence-test.js +++ b/tests/integration/adapter/record-persistence-test.js @@ -1,10 +1,11 @@ +import { set, get } from '@ember/object'; +import { run } from '@ember/runloop'; +import RSVP, { resolve } from 'rsvp'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { get, set, run, RSVP } = Ember; const { all, hash } = RSVP; const { attr } = DS; @@ -40,7 +41,7 @@ test("When a store is committed, the adapter's `commit` method should be called assert.equal(type, Person, "the type is correct"); assert.equal(snapshot.record, tom, "the record is correct"); - return run(Ember.RSVP, 'resolve'); + return run(RSVP, 'resolve'); }; run(() => { @@ -74,7 +75,7 @@ test("When a store is committed, the adapter's `commit` method should be called assert.equal(type, Person, "the type is correct"); assert.equal(snapshot.record, tom, "the record is correct"); - return Ember.RSVP.resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale" } } }); + return resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale" } } }); }; return run(() => { @@ -88,7 +89,7 @@ test("After a created record has been assigned an ID, finding a record by that I let tom; env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale" } } }); + return resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale" } } }); }; return run(() => { @@ -106,7 +107,7 @@ test("when a store is committed, the adapter's `commit` method should be called assert.equal(type, Person, "the type is correct"); assert.equal(snapshot.record, tom, "the record is correct"); - return run(Ember.RSVP, 'resolve'); + return run(RSVP, 'resolve'); }; let tom; @@ -138,7 +139,7 @@ test("An adapter can notify the store that records were updated by calling `didS let tom, yehuda; env.adapter.updateRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve(); + return resolve(); }; run(() => { @@ -185,9 +186,9 @@ test("An adapter can notify the store that records were updated by calling `didS test("An adapter can notify the store that records were updated and provide new data by calling `didSaveRecords`.", function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { if (snapshot.id === "1") { - return Ember.RSVP.resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale", "updated-at": "now" } } }); + return resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale", "updated-at": "now" } } }); } else if (snapshot.id === "2") { - return Ember.RSVP.resolve({ data: { id: 2, type: "person", attributes: { name: "Yehuda Katz", "updated-at": "now!" } } }); + return resolve({ data: { id: 2, type: "person", attributes: { name: "Yehuda Katz", "updated-at": "now!" } } }); } }; @@ -230,7 +231,7 @@ test("An adapter can notify the store that records were updated and provide new test("An adapter can notify the store that a record was updated by calling `didSaveRecord`.", function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve(); + return resolve(); }; run(() => { @@ -264,9 +265,9 @@ test("An adapter can notify the store that a record was updated and provide new env.adapter.updateRecord = function(store, type, snapshot) { switch (snapshot.id) { case "1": - return Ember.RSVP.resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale", "updated-at": "now" } } }); + return resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale", "updated-at": "now" } } }); case "2": - return Ember.RSVP.resolve({ data: { id: 2, type: "person", attributes: { name: "Yehuda Katz", "updated-at": "now!" } } }); + return resolve({ data: { id: 2, type: "person", attributes: { name: "Yehuda Katz", "updated-at": "now!" } } }); } }; @@ -309,7 +310,7 @@ test("An adapter can notify the store that a record was updated and provide new test("An adapter can notify the store that records were deleted by calling `didSaveRecords`.", function(assert) { env.adapter.deleteRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve(); + return resolve(); }; run(() => { diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 4b24d0b7254..a1095bbf159 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1,9 +1,14 @@ +import { underscore } from '@ember/string'; +import { copy } from '@ember/object/internals'; +import RSVP, { resolve, reject } from 'rsvp'; +import $ from 'jquery'; +import { run } from '@ember/runloop'; +import { get } from '@ember/object'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import { singularize } from 'ember-inflector'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import Pretender from "pretender"; @@ -12,8 +17,7 @@ import { isEnabled } from 'ember-data/-private'; let env, store, adapter, Post, Comment, SuperUser; let passedUrl, passedVerb, passedHash; -const { run, get } = Ember; -let originalAjax = Ember.$.ajax; +let originalAjax = $.ajax; let server; module("integration/adapter/rest_adapter - REST Adapter", { @@ -41,7 +45,7 @@ module("integration/adapter/rest_adapter - REST Adapter", { passedUrl = passedVerb = passedHash = null; }, afterEach() { - Ember.$.ajax = originalAjax; + $.ajax = originalAjax; if (server) { server.shutdown(); @@ -57,7 +61,7 @@ function ajaxResponse(value) { passedVerb = request.method; passedHash = request.data ? { data: request.data } : undefined; - return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); + return run(RSVP, 'resolve', copy(value, true)); }; } else { adapter.ajax = function(url, verb, hash) { @@ -65,7 +69,7 @@ function ajaxResponse(value) { passedVerb = verb; passedHash = hash; - return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); + return run(RSVP, 'resolve', copy(value, true)); }; } } @@ -1979,12 +1983,12 @@ test('groupRecordsForFindMany groups records based on their url', function(asser adapter.findRecord = function(store, type, id, snapshot) { assert.equal(id, '1'); - return Ember.RSVP.resolve({ comments: { id: 1 } }); + return resolve({ comments: { id: 1 } }); }; adapter.findMany = function(store, type, ids, snapshots) { assert.deepEqual(ids, ['2', '3']); - return Ember.RSVP.resolve({ comments: [{ id: 2 }, { id: 3 }] }); + return resolve({ comments: [{ id: 2 }, { id: 3 }] }); }; let post; @@ -2025,12 +2029,12 @@ test('groupRecordsForFindMany groups records correctly when singular URLs are en adapter.findRecord = function(store, type, id, snapshot) { assert.equal(id, '1'); - return Ember.RSVP.resolve({ comments: { id: 1 } }); + return resolve({ comments: { id: 1 } }); }; adapter.findMany = function(store, type, ids, snapshots) { assert.deepEqual(ids, ['2', '3']); - return Ember.RSVP.resolve({ comments: [{ id: 2 }, { id: 3 }] }); + return resolve({ comments: [{ id: 2 }, { id: 3 }] }); }; let post; @@ -2059,7 +2063,7 @@ test('groupRecordsForFindMany groups records correctly when singular URLs are en test('normalizeKey - to set up _ids and _id', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ keyForAttribute(attr) { - return Ember.String.underscore(attr); + return underscore(attr); }, keyForBelongsTo(belongsTo) { @@ -2067,11 +2071,11 @@ test('normalizeKey - to set up _ids and _id', function(assert) { keyForRelationship(rel, kind) { if (kind === 'belongsTo') { - let underscored = Ember.String.underscore(rel); + let underscored = underscore(rel); return underscored + '_id'; } else { let singular = singularize(rel); - return Ember.String.underscore(singular) + '_ids'; + return underscore(singular) + '_ids'; } } })); @@ -2163,12 +2167,12 @@ test('groupRecordsForFindMany splits up calls for large ids', function(assert) { assert.ok(true, "Found " + id); } - return Ember.RSVP.resolve({ comments: { id: id } }); + return resolve({ comments: { id: id } }); }; adapter.findMany = function(store, type, ids, snapshots) { assert.ok(false, "findMany should not be called - we expect 2 calls to find for a2000 and b2000"); - return Ember.RSVP.reject(); + return reject(); }; run(() => post.get('comments')); @@ -2210,12 +2214,12 @@ test('groupRecordsForFindMany groups calls for small ids', function(assert) { adapter.findRecord = function(store, type, id, snapshot) { assert.ok(false, "findRecord should not be called - we expect 1 call to findMany for a100 and b100"); - return Ember.RSVP.reject(); + return reject(); }; adapter.findMany = function(store, type, ids, snapshots) { assert.deepEqual(ids, [a100, b100]); - return Ember.RSVP.resolve({ comments: [{ id: a100 }, { id: b100 }] }); + return resolve({ comments: [{ id: a100 }, { id: b100 }] }); }; run(() => post.get('comments')); @@ -2235,7 +2239,7 @@ test("calls adapter.handleResponse with the jqXHR and json", function(assert) { } }; - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { hash.success(data, 'ok', jqXHR); }; @@ -2261,7 +2265,7 @@ test('calls handleResponse with jqXHR, jqXHR.responseText, and requestData', fun url: "/posts/1" }; - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { hash.error(jqXHR, jqXHR.responseText, 'Bad Request'); }; @@ -2286,7 +2290,7 @@ test("rejects promise if DS.AdapterError is returned from adapter.handleResponse something: 'is invalid' }; - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { hash.success(data, 'ok', jqXHR); }; @@ -2295,7 +2299,7 @@ test("rejects promise if DS.AdapterError is returned from adapter.handleResponse return new DS.AdapterError(json); }; - return Ember.run(() => { + return run(() => { return store.findRecord('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); assert.ok(reason instanceof DS.AdapterError, 'reason should be an instance of DS.AdapterError'); @@ -2310,7 +2314,7 @@ test("gracefully handles exceptions in handleResponse", function(assert) { getAllResponseHeaders() { return ''; } }; - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { setTimeout(function() { hash.success({}, 'ok', jqXHR); }, 1) }; @@ -2332,7 +2336,7 @@ test("gracefully handles exceptions in handleResponse where the ajax request err getAllResponseHeaders() { return ''; } }; - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { setTimeout(() => hash.error({}, 'Internal Server Error', jqXHR) , 1); }; @@ -2355,7 +2359,7 @@ test('treats status code 0 as an abort', function(assert) { getAllResponseHeaders() { return ''; } }; - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { hash.error(jqXHR, 'error'); }; @@ -2380,7 +2384,7 @@ test('on error appends errorThrown for sanity', function(assert) { let errorThrown = new Error('nope!'); - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { hash.error(jqXHR, jqXHR.responseText, errorThrown); }; @@ -2402,62 +2406,62 @@ test("rejects promise with a specialized subclass of DS.AdapterError if ajax res let jqXHR = { getAllResponseHeaders() { return ''; } }; - let originalAjax = Ember.$.ajax; + let originalAjax = $.ajax; - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { jqXHR.status = 401; hash.error(jqXHR, 'error'); }; - Ember.run(() => { + run(() => { store.find('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); assert.ok(reason instanceof DS.UnauthorizedError, 'reason should be an instance of DS.UnauthorizedError'); }); }); - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { jqXHR.status = 403; hash.error(jqXHR, 'error'); }; - Ember.run(() => { + run(() => { store.find('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); assert.ok(reason instanceof DS.ForbiddenError, 'reason should be an instance of DS.ForbiddenError'); }); }); - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { jqXHR.status = 404; hash.error(jqXHR, 'error'); }; - Ember.run(() => { + run(() => { store.find('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); assert.ok(reason instanceof DS.NotFoundError, 'reason should be an instance of DS.NotFoundError'); }); }); - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { jqXHR.status = 409; hash.error(jqXHR, 'error'); }; - Ember.run(() => { + run(() => { store.find('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); assert.ok(reason instanceof DS.ConflictError, 'reason should be an instance of DS.ConflictError'); }); }); - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { jqXHR.status = 500; hash.error(jqXHR, 'error'); }; - Ember.run(() => { + run(() => { store.find('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); assert.ok(reason instanceof DS.ServerError, 'reason should be an instance of DS.ServerError'); @@ -2465,7 +2469,7 @@ test("rejects promise with a specialized subclass of DS.AdapterError if ajax res }); - Ember.$.ajax = originalAjax; + $.ajax = originalAjax; }); test('on error wraps the error string in an DS.AdapterError object', function(assert) { @@ -2478,7 +2482,7 @@ test('on error wraps the error string in an DS.AdapterError object', function(as let errorThrown = 'nope!'; - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { hash.error(jqXHR, 'error', errorThrown); }; @@ -2498,7 +2502,7 @@ test('error handling includes a detailed message from the server', (assert) => { getAllResponseHeaders() { return 'Content-Type: text/plain'; } }; - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { hash.error(jqXHR, 'error'); }; @@ -2520,7 +2524,7 @@ test('error handling with a very long HTML-formatted payload truncates the frien getAllResponseHeaders() { return 'Content-Type: text/html'; } }; - Ember.$.ajax = function(hash) { + $.ajax = function(hash) { hash.error(jqXHR, 'error'); }; diff --git a/tests/integration/adapter/serialize-test.js b/tests/integration/adapter/serialize-test.js index fdf961fe740..1d2a80dc3ed 100644 --- a/tests/integration/adapter/serialize-test.js +++ b/tests/integration/adapter/serialize-test.js @@ -1,12 +1,10 @@ +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { run } = Ember; - let env, store, adapter, serializer; module("integration/adapter/serialize - DS.Adapter integration test", { diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 85326d8947a..ae6c09ecd4d 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -1,25 +1,18 @@ +import { + resolve, + hash, + Promise as EmberPromise, + reject +} from 'rsvp'; +import { set, get } from '@ember/object'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import DS from 'ember-data'; -/* - This is an integration test that tests the communication between a store - and its adapter. - - Typically, when a method is invoked on the store, it calls a related - method on its adapter. The adapter notifies the store that it has - completed the assigned task, either synchronously or asynchronously, - by calling a method on the store. - - These tests ensure that the proper methods get called, and, if applicable, - the given record or record array changes state appropriately. -*/ - -const { get, set, run } = Ember; let Person, Dog, env, store, adapter; function moveRecordOutOfInFlight(record) { @@ -56,7 +49,7 @@ module("integration/adapter/store-adapter - DS.Store and DS.Adapter integration test("Records loaded multiple times and retrieved in recordArray are ready to send state events", function(assert) { adapter.query = function(store, type, query, recordArray) { - return Ember.RSVP.resolve({ + return resolve({ data: [ { id: 1, @@ -78,7 +71,7 @@ test("Records loaded multiple times and retrieved in recordArray are ready to se return run(store, 'query', 'person', { q: 'bla' }).then(people => { let people2 = store.query('person', { q: 'bla2' }); - return Ember.RSVP.hash({ people: people, people2: people2 }); + return hash({ people: people, people2: people2 }); }).then(results => { assert.equal(results.people2.get('length'), 2, 'return the elements'); assert.ok(results.people2.get('isLoaded'), 'array is loaded'); @@ -110,7 +103,7 @@ test("by default, createRecords calls createRecord once per record", function(as hash['updated-at'] = "now"; count++; - return Ember.RSVP.resolve({ + return resolve({ data: { id: recordId, type: "person", @@ -127,7 +120,7 @@ test("by default, createRecords calls createRecord once per record", function(as }); let promise = run(() => { - return Ember.RSVP.hash({ + return hash({ tom: tom.save(), yehuda: yehuda.save() }); @@ -162,7 +155,7 @@ test("by default, updateRecords calls updateRecord once per record", function(as assert.equal(snapshot.record.get('isSaving'), true, "record is saving"); - return Ember.RSVP.resolve(); + return resolve(); }; run(() => { @@ -184,7 +177,7 @@ test("by default, updateRecords calls updateRecord once per record", function(as }); let promise = run(() => { - return Ember.RSVP.hash({ + return hash({ tom: store.findRecord('person', 1), yehuda: store.findRecord('person', 2) }); @@ -197,7 +190,7 @@ test("by default, updateRecords calls updateRecord once per record", function(as set(tom, "name", "Tom Dale"); set(yehuda, "name", "Yehuda Katz"); - return Ember.RSVP.hash({ + return hash({ tom: tom.save(), yehuda: yehuda.save() }); @@ -222,10 +215,10 @@ test("calling store.didSaveRecord can provide an optional hash", function(assert count++; if (count === 1) { assert.equal(snapshot.attr('name'), "Tom Dale"); - return Ember.RSVP.resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale", "updated-at": "now" } } }); + return resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale", "updated-at": "now" } } }); } else if (count === 2) { assert.equal(snapshot.attr('name'), "Yehuda Katz"); - return Ember.RSVP.resolve({ data: { id: 2, type: "person", attributes: { name: "Yehuda Katz", "updated-at": "now!" } } }); + return resolve({ data: { id: 2, type: "person", attributes: { name: "Yehuda Katz", "updated-at": "now!" } } }); } else { assert.ok(false, "should not get here"); } @@ -250,7 +243,7 @@ test("calling store.didSaveRecord can provide an optional hash", function(assert }); let promise = run(() => { - return Ember.RSVP.hash({ + return hash({ tom: store.findRecord('person', 1), yehuda: store.findRecord('person', 2) }); @@ -263,7 +256,7 @@ test("calling store.didSaveRecord can provide an optional hash", function(assert set(tom, "name", "Tom Dale"); set(yehuda, "name", "Yehuda Katz"); - return Ember.RSVP.hash({ + return hash({ tom: tom.save(), yehuda: yehuda.save() }); @@ -297,7 +290,7 @@ test("by default, deleteRecord calls deleteRecord once per record", function(ass count++; - return Ember.RSVP.resolve(); + return resolve(); }; run(() => { @@ -319,7 +312,7 @@ test("by default, deleteRecord calls deleteRecord once per record", function(ass }); let promise = run(() => { - return Ember.RSVP.hash({ + return hash({ tom: store.findRecord('person', 1), yehuda: store.findRecord('person', 2) }); @@ -332,7 +325,7 @@ test("by default, deleteRecord calls deleteRecord once per record", function(ass tom.deleteRecord(); yehuda.deleteRecord(); - return Ember.RSVP.Promise.all([ + return EmberPromise.all([ tom.save(), yehuda.save() ]); @@ -358,7 +351,7 @@ test("by default, destroyRecord calls deleteRecord once per record without requi count++; - return Ember.RSVP.resolve(); + return resolve(); }; run(() => { @@ -380,7 +373,7 @@ test("by default, destroyRecord calls deleteRecord once per record without requi }); let promise = run(() => { - return Ember.RSVP.hash({ + return hash({ tom: store.findRecord('person', 1), yehuda: store.findRecord('person', 2) }); @@ -390,7 +383,7 @@ test("by default, destroyRecord calls deleteRecord once per record without requi let tom = records.tom; let yehuda = records.yehuda; - return Ember.RSVP.Promise.all([ + return EmberPromise.all([ tom.destroyRecord(), yehuda.destroyRecord() ]); @@ -407,7 +400,7 @@ test("if an existing model is edited then deleted, deleteRecord is called on the assert.equal(snapshot.id, 'deleted-record', "should pass correct record to deleteRecord"); assert.equal(count, 1, "should only call deleteRecord method of adapter once"); - return Ember.RSVP.resolve(); + return resolve(); }; adapter.updateRecord = function() { @@ -448,9 +441,9 @@ test("if a deleted record errors, it enters the error state", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.deleteRecord = function(store, type, snapshot) { if (count++ === 0) { - return Ember.RSVP.reject(error); + return reject(error); } else { - return Ember.RSVP.resolve(); + return resolve(); } }; @@ -490,7 +483,7 @@ test("if a created record is marked as invalid by the server, it enters an error assert.equal(type, Person, "the type is correct"); if (snapshot.attr('name').indexOf('Bro') === -1) { - return Ember.RSVP.reject(new DS.InvalidError([ + return reject(new DS.InvalidError([ { title: 'Invalid Attribute', detail: 'common... name requires a "bro"', @@ -500,7 +493,7 @@ test("if a created record is marked as invalid by the server, it enters an error } ])); } else { - return Ember.RSVP.resolve(); + return resolve(); } }; @@ -509,7 +502,7 @@ test("if a created record is marked as invalid by the server, it enters an error }); // Wrap this in an Ember.run so that all chained async behavior is set up // before flushing any scheduled behavior. - return Ember.run(function() { + return run(function() { return yehuda.save().catch(error => { assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); assert.ok(get(yehuda, 'errors.name'), "The errors.name property exists"); @@ -537,7 +530,7 @@ test("if a created record is marked as invalid by the server, it enters an error test("allows errors on arbitrary properties on create", function(assert) { adapter.createRecord = function(store, type, snapshot) { if (snapshot.attr('name').indexOf('Bro') === -1) { - return Ember.RSVP.reject(new DS.InvalidError([ + return reject(new DS.InvalidError([ { title: "Invalid Attribute", detail: "is a generally unsavoury character", @@ -547,7 +540,7 @@ test("allows errors on arbitrary properties on create", function(assert) { } ])); } else { - return Ember.RSVP.resolve(); + return resolve(); } }; @@ -591,7 +584,7 @@ test("if a created record is marked as invalid by the server, you can attempt th saveCount++; if (snapshot.attr('name').indexOf('Bro') === -1) { - return Ember.RSVP.reject(new DS.InvalidError([ + return reject(new DS.InvalidError([ { title: 'Invalid Attribute', detail: 'common... name requires a "bro"', @@ -601,7 +594,7 @@ test("if a created record is marked as invalid by the server, you can attempt th } ])); } else { - return Ember.RSVP.resolve(); + return resolve(); } }; @@ -611,7 +604,7 @@ test("if a created record is marked as invalid by the server, you can attempt th // Wrap this in an Ember.run so that all chained async behavior is set up // before flushing any scheduled behavior. - return Ember.run(() => { + return run(() => { return yehuda.save().catch(reason => { assert.equal(saveCount, 1, "The record has been saved once"); assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); @@ -642,10 +635,10 @@ test("if a created record is marked as erred by the server, it enters an error s let error = new DS.AdapterError(); adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.reject(error); + return reject(error); }; - return Ember.run(() => { + return run(() => { let person = store.createRecord('person', { id: 1, name: "John Doe" }); return person.save().catch(() => { @@ -661,7 +654,7 @@ test("if an updated record is marked as invalid by the server, it enters an erro assert.equal(type, Person, "the type is correct"); if (snapshot.attr('name').indexOf('Bro') === -1) { - return Ember.RSVP.reject(new DS.InvalidError([ + return reject(new DS.InvalidError([ { title: 'Invalid Attribute', detail: 'common... name requires a "bro"', @@ -671,7 +664,7 @@ test("if an updated record is marked as invalid by the server, it enters an erro } ])); } else { - return Ember.RSVP.resolve(); + return resolve(); } }; @@ -689,7 +682,7 @@ test("if an updated record is marked as invalid by the server, it enters an erro return store.peekRecord('person', 1); }); - return Ember.run(() => { + return run(() => { return store.findRecord('person', 1).then(person => { assert.equal(person, yehuda, "The same object is passed through"); @@ -723,7 +716,7 @@ test("records can have errors on arbitrary properties after update", function(as adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { if (snapshot.attr('name').indexOf('Bro') === -1) { - return Ember.RSVP.reject(new DS.InvalidError([ + return reject(new DS.InvalidError([ { title: "Invalid Attribute", detail: "is a generally unsavoury character", @@ -733,7 +726,7 @@ test("records can have errors on arbitrary properties after update", function(as } ])); } else { - return Ember.RSVP.resolve(); + return resolve(); } }; @@ -791,7 +784,7 @@ test("if an updated record is marked as invalid by the server, you can attempt t assert.equal(type, Person, "the type is correct"); saveCount++; if (snapshot.attr('name').indexOf('Bro') === -1) { - return Ember.RSVP.reject(new DS.InvalidError([ + return reject(new DS.InvalidError([ { title: 'Invalid Attribute', detail: 'common... name requires a "bro"', @@ -801,7 +794,7 @@ test("if an updated record is marked as invalid by the server, you can attempt t } ])); } else { - return Ember.RSVP.resolve(); + return resolve(); } }; @@ -818,7 +811,7 @@ test("if an updated record is marked as invalid by the server, you can attempt t return store.peekRecord('person', 1); }); - return Ember.run(() => { + return run(() => { return store.findRecord('person', 1).then(person => { assert.equal(person, yehuda, "The same object is passed through"); @@ -856,7 +849,7 @@ test("if a updated record is marked as erred by the server, it enters an error s adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { - return Ember.RSVP.reject(error); + return reject(error); }; let person = run(() => { @@ -887,7 +880,7 @@ test("can be created after the DS.Store", function(assert) { adapter.findRecord = function(store, type, id, snapshot) { assert.equal(type, Person, "the type is correct"); - return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); + return resolve({ data: { id: 1, type: "person" } }); }; run(() => store.findRecord('person', 1)); @@ -896,7 +889,7 @@ test("can be created after the DS.Store", function(assert) { test("the filter method can optionally take a server query as well", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.query = function(store, type, query, array) { - return Ember.RSVP.resolve({ + return resolve({ data: [ { id: 1, @@ -949,7 +942,7 @@ test("relationships returned via `commit` do not trigger additional findManys", }); adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: "person", @@ -964,7 +957,7 @@ test("relationships returned via `commit` do not trigger additional findManys", }; adapter.updateRecord = function(store, type, snapshot) { - return new Ember.RSVP.Promise((resolve, reject) => { + return new EmberPromise((resolve, reject) => { env.store.push({ data: { type: 'person', @@ -1000,7 +993,7 @@ test("relationships returned via `commit` do not trigger additional findManys", return run(() => { store.findRecord('person', 1).then(person => { - return Ember.RSVP.hash({ tom: person, dog: store.findRecord('dog', 1) }); + return hash({ tom: person, dog: store.findRecord('dog', 1) }); }).then(records => { records.tom.get('dogs'); return records.dog.save(); @@ -1021,7 +1014,7 @@ test("relationships don't get reset if the links is the same", function(assert) adapter.findHasMany = function(store, snapshot, link, relationship) { assert.ok(count++ === 0, "findHasMany is only called once"); - return Ember.RSVP.resolve({ data: [{ id: 1, type: "dog", attributes: { name: "Scruffy" } }] }); + return resolve({ data: [{ id: 1, type: "dog", attributes: { name: "Scruffy" } }] }); }; run(() => { @@ -1080,7 +1073,7 @@ test("async hasMany always returns a promise", function(assert) { }); adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: "person", @@ -1112,7 +1105,7 @@ test("createRecord receives a snapshot", function(assert) { adapter.createRecord = function(store, type, snapshot) { assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); - return Ember.RSVP.resolve(); + return resolve(); }; var person; @@ -1128,7 +1121,7 @@ test("updateRecord receives a snapshot", function(assert) { adapter.updateRecord = function(store, type, snapshot) { assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); - return Ember.RSVP.resolve(); + return resolve(); }; let person; @@ -1157,7 +1150,7 @@ test("deleteRecord receives a snapshot", function(assert) { adapter.deleteRecord = function(store, type, snapshot) { assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); - return Ember.RSVP.resolve(); + return resolve(); }; let person; @@ -1186,7 +1179,7 @@ test("findRecord receives a snapshot", function(assert) { adapter.findRecord = function(store, type, id, snapshot) { assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); - return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); + return resolve({ data: { id: 1, type: "person" } }); }; return run(() => store.findRecord('person', 1)); @@ -1203,7 +1196,7 @@ test("findMany receives an array of snapshots", function(assert) { adapter.findMany = function(store, type, ids, snapshots) { assert.ok(snapshots[0] instanceof DS.Snapshot, "snapshots[0] is an instance of DS.Snapshot"); assert.ok(snapshots[1] instanceof DS.Snapshot, "snapshots[1] is an instance of DS.Snapshot"); - return Ember.RSVP.resolve({ data: [{ id: 2, type: "dog" }, { id: 3, type: "dog" }] }); + return resolve({ data: [{ id: 2, type: "dog" }, { id: 3, type: "dog" }] }); }; let person; @@ -1238,7 +1231,7 @@ test("findHasMany receives a snapshot", function(assert) { env.adapter.findHasMany = function(store, snapshot, link, relationship) { assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); - return Ember.RSVP.resolve({ data: [{ id: 2, type: "dog" }, { id: 3, type: "dog" }] }); + return resolve({ data: [{ id: 2, type: "dog" }, { id: 3, type: "dog" }] }); }; let person; @@ -1272,7 +1265,7 @@ test("findBelongsTo receives a snapshot", function(assert) { env.adapter.findBelongsTo = function(store, snapshot, link, relationship) { assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); - return Ember.RSVP.resolve({ data: { id: 2, type: "dog" } }); + return resolve({ data: { id: 2, type: "dog" } }); }; let person; @@ -1302,7 +1295,7 @@ test("record.save should pass adapterOptions to the updateRecord method", functi env.adapter.updateRecord = function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); - return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); + return resolve({ data: { id: 1, type: "person" } }); }; return run(() => { @@ -1325,7 +1318,7 @@ test("record.save should pass adapterOptions to the createRecord method", functi env.adapter.createRecord = function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); - return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); + return resolve({ data: { id: 1, type: "person" } }); }; return run(() => { @@ -1339,7 +1332,7 @@ test("record.save should pass adapterOptions to the deleteRecord method", functi env.adapter.deleteRecord = function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); - return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); + return resolve({ data: { id: 1, type: "person" } }); }; run(() => { @@ -1362,7 +1355,7 @@ test("store.findRecord should pass adapterOptions to adapter.findRecord", functi env.adapter.findRecord = function(store, type, id, snapshot) { assert.deepEqual(snapshot.adapterOptions, { query: { embed: true } }); - return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); + return resolve({ data: { id: 1, type: "person" } }); }; return run(() => { @@ -1375,7 +1368,7 @@ test("store.findRecord should pass 'include' to adapter.findRecord", function(as env.adapter.findRecord = (store, type, id, snapshot) => { assert.equal(snapshot.include, 'books', 'include passed to adapter.findRecord'); - return Ember.RSVP.resolve({ data: { id: 1, type: "person" } }); + return resolve({ data: { id: 1, type: "person" } }); }; run(() => store.findRecord('person', 1, { include: 'books' })); @@ -1387,7 +1380,7 @@ test("store.findAll should pass adapterOptions to the adapter.findAll method", f env.adapter.findAll = function(store, type, sinceToken, arraySnapshot) { let adapterOptions = arraySnapshot.adapterOptions; assert.deepEqual(adapterOptions, { query: { embed: true } }); - return Ember.RSVP.resolve({ data: [{ id: 1, type: "person" }] }); + return resolve({ data: [{ id: 1, type: "person" }] }); }; return run(() => { @@ -1400,7 +1393,7 @@ test("store.findAll should pass 'include' to adapter.findAll", function(assert) env.adapter.findAll = function(store, type, sinceToken, arraySnapshot) { assert.equal(arraySnapshot.include, 'books', 'include passed to adapter.findAll'); - return Ember.RSVP.resolve({ data: [{ id: 1, type: "person" }] }); + return resolve({ data: [{ id: 1, type: "person" }] }); }; run(() => store.findAll('person', { include: 'books' })); @@ -1430,7 +1423,7 @@ test("An async hasMany relationship with links should not trigger shouldBackgrou }; }, findHasMany() { - return Ember.RSVP.resolve({ + return resolve({ comments: [ { id: 1, name: "FIRST" }, { id: 2, name: "Rails is unagi" }, diff --git a/tests/integration/application-test.js b/tests/integration/application-test.js index 665f14855c4..564097613bd 100644 --- a/tests/integration/application-test.js +++ b/tests/integration/application-test.js @@ -1,13 +1,14 @@ +import Service, { inject as service } from '@ember/service'; +import Controller from '@ember/controller'; +import Application from '@ember/application'; +import { run } from '@ember/runloop'; import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const run = Ember.run; -const Application = Ember.Application; -const Controller = Ember.Controller; const Store = DS.Store; const Namespace = Ember.Namespace; @@ -104,12 +105,12 @@ test("the DS namespace should be accessible", function(assert) { }); }); -if (Ember.inject && Ember.inject.service) { +if (Ember.inject && service) { module("integration/application - Using the store as a service", { beforeEach() { run(() => { app = Application.create({ - DoodleService: Ember.Service.extend({ store: Ember.inject.service() }) + DoodleService: Service.extend({ store: service() }) }); }); diff --git a/tests/integration/backwards-compat/non-dasherized-lookups-test.js b/tests/integration/backwards-compat/non-dasherized-lookups-test.js index 4741ad62c34..9cb4c3a290a 100644 --- a/tests/integration/backwards-compat/non-dasherized-lookups-test.js +++ b/tests/integration/backwards-compat/non-dasherized-lookups-test.js @@ -1,13 +1,11 @@ +import { run } from '@ember/runloop'; +import { get } from '@ember/object'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const get = Ember.get; -const { run } = Ember; - const { JSONAPIAdapter, JSONAPISerializer, diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index 6fe32283f51..62966f4f0d9 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -1,11 +1,12 @@ +import { resolve } from 'rsvp'; +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { get, run } = Ember; let Post, Comment, Misc, env; module("integration/client_id_generation - Client-side ID Generation", { @@ -48,10 +49,10 @@ test("If an adapter implements the `generateIdForRecord` method, the store shoul env.adapter.createRecord = function(store, type, snapshot) { if (type === Comment) { assert.equal(snapshot.id, 'id-1', "Comment passed to `createRecord` has 'id-1' assigned"); - return Ember.RSVP.resolve(); + return resolve(); } else { assert.equal(snapshot.id, 'id-2', "Post passed to `createRecord` has 'id-2' assigned"); - return Ember.RSVP.resolve(); + return resolve(); } }; @@ -86,7 +87,7 @@ test("empty string and undefined ids should coerce to null", function(assert) { env.adapter.createRecord = function(store, type, record) { assert.equal(typeof get(record, 'id'), 'object', 'correct type'); - return Ember.RSVP.resolve({ data: { id: id++, type: type.modelName } }); + return resolve({ data: { id: id++, type: type.modelName } }); }; run(() => { diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index b1d01a2ce72..5833c5506c8 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -1,16 +1,18 @@ -import Ember from 'ember'; +import { A } from '@ember/array'; +import Application from '@ember/application'; +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let App, store, debugAdapter; -const { get, run } = Ember; module('DS.DebugAdapter', { beforeEach() { - Ember.run(function() { - App = Ember.Application.extend({ + run(function() { + App = Application.extend({ toString() { return 'debug-app'; } }).create(); @@ -44,7 +46,7 @@ module('DS.DebugAdapter', { debugAdapter.reopen({ getModelTypes() { - return Ember.A([{ klass, name: 'post' }]); + return A([{ klass, name: 'post' }]); } }); }, @@ -86,7 +88,7 @@ test('Watching Model Types', function(assert) { test("Watching Records", function(assert) { var post, record, addedRecords, updatedRecords, removedIndex, removedCount; - Ember.run(function() { + run(function() { store.push({ data: { type: 'post', @@ -124,11 +126,11 @@ test("Watching Records", function(assert) { assert.deepEqual(record.searchKeywords, ['1', 'Clean Post']); assert.deepEqual(record.color, 'black'); - Ember.run(function() { + run(function() { post = store.findRecord('post', 1); }); - Ember.run(function() { + run(function() { post.set('title', 'Modified Post'); }); @@ -149,7 +151,7 @@ test("Watching Records", function(assert) { assert.deepEqual(record.searchKeywords, ['2', 'New Post']); assert.deepEqual(record.color, 'green'); - Ember.run(post, 'unloadRecord'); + run(post, 'unloadRecord'); assert.equal(removedIndex, 1); assert.equal(removedCount, 1); diff --git a/tests/integration/filter-test.js b/tests/integration/filter-test.js index 9670af43167..fb5a8f38d32 100644 --- a/tests/integration/filter-test.js +++ b/tests/integration/filter-test.js @@ -1,5 +1,7 @@ +import { hash, all } from 'rsvp'; +import { set, get, computed } from '@ember/object'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import { module, test } from 'qunit'; @@ -7,18 +9,12 @@ import DS from 'ember-data'; import customAdapter from 'dummy/tests/helpers/custom-adapter'; -const { - get, - set, - run -} = Ember; - let store, env, data, recordArray; const Person = DS.Model.extend({ name: DS.attr('string'), bestFriend: DS.belongsTo('person', { inverse: null, async: false }), - upperName: Ember.computed('name', function() { + upperName: computed('name', function() { return this.get('name').toUpperCase(); }).readOnly() }); @@ -235,7 +231,7 @@ test('a Record Array can update its filter', function(assert) { } }).then(recordArray => { - return Ember.RSVP.hash(asyncData).then(records => { + return hash(asyncData).then(records => { assert.contains(recordArray, records.dale); assert.contains(recordArray, records.katz); assert.without(recordArray, dickens); @@ -334,7 +330,7 @@ test('a Record Array can update its filter and notify array observers', function }); }); - return Ember.RSVP.all(asyncData).then(() => { + return all(asyncData).then(() => { assert.equal(didChangeRemoved, 1, 'removed one item from array'); didChangeRemoved = 0; diff --git a/tests/integration/injection-test.js b/tests/integration/injection-test.js index dfbc603ff05..aef9d58a9cf 100644 --- a/tests/integration/injection-test.js +++ b/tests/integration/injection-test.js @@ -2,13 +2,14 @@ import { setup as setupModelFactoryInjections, reset as resetModelFactoryInjections } from 'dummy/tests/helpers/model-factory-injection'; +import EmberObject from '@ember/object'; +import { getOwner } from '@ember/application'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import DS from 'ember-data'; import { module, test } from 'qunit'; let env, hasFactoryFor, originalLookupFactory, originalOwnerLookupFactory, originalFactoryFor; -const { run } = Ember; const model = { isModel: true, @@ -22,8 +23,8 @@ module('integration/injection factoryFor enabled', { setup() { env = setupStore(); - if (Ember.getOwner) { - let owner = Ember.getOwner(env.store); + if (getOwner) { + let owner = getOwner(env.store); hasFactoryFor = !!owner.factoryFor; originalFactoryFor = owner.factoryFor; @@ -49,8 +50,8 @@ module('integration/injection factoryFor enabled', { }, teardown() { - if (Ember.getOwner) { - let owner = Ember.getOwner(env.store); + if (getOwner) { + let owner = getOwner(env.store); if (owner.factoryFor) { owner.factoryFor = originalFactoryFor; @@ -87,7 +88,7 @@ module('integration/injection eager injections', { env.registry.injection('model:foo', 'apple', 'service:apple'); env.registry.register('model:foo', DS.Model); - env.registry.register('service:apple', Ember.Object.extend({ isService: true })); + env.registry.register('service:apple', EmberObject.extend({ isService: true })); // container injection }, diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index c48bb75eb7a..d2881b9dd23 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -1,15 +1,14 @@ +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let env, store, User, Job, ReflexiveModel; const { attr, belongsTo } = DS; -const { run } = Ember; function stringify(string) { return function() { return string; }; diff --git a/tests/integration/lifecycle-hooks-test.js b/tests/integration/lifecycle-hooks-test.js index d74ae1146c6..705997b19f5 100644 --- a/tests/integration/lifecycle-hooks-test.js +++ b/tests/integration/lifecycle-hooks-test.js @@ -1,14 +1,13 @@ +import { resolve } from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let Person, env; const { attr } = DS; -const { run } = Ember; -const { resolve } = Ember.RSVP; module("integration/lifecycle_hooks - Lifecycle Hooks", { beforeEach() { @@ -50,7 +49,7 @@ test("When the adapter acknowledges that a record has been created without a new assert.expect(3); env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve(); + return resolve(); }; let person = run(() => env.store.createRecord('person', { id: 99, name: "Yehuda Katz" })); diff --git a/tests/integration/multiple-stores-test.js b/tests/integration/multiple-stores-test.js index 4edd341eb10..bcf1fd59040 100644 --- a/tests/integration/multiple-stores-test.js +++ b/tests/integration/multiple-stores-test.js @@ -1,12 +1,11 @@ +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import { module, test } from 'qunit'; import DS from 'ember-data'; let env; let SuperVillain, HomePlanet, EvilMinion; -const { run } = Ember; module("integration/multiple_stores - Multiple Stores Tests", { setup() { diff --git a/tests/integration/peek-all-test.js b/tests/integration/peek-all-test.js index 2f836487f2c..c023ee7ee96 100644 --- a/tests/integration/peek-all-test.js +++ b/tests/integration/peek-all-test.js @@ -1,12 +1,11 @@ -import {createStore} from 'dummy/tests/helpers/store'; -import Ember from 'ember'; +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; +import { createStore } from 'dummy/tests/helpers/store'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { get, run } = Ember; - let Person, store, array, moreArray; module("integration/peek-all - DS.Store#peekAll()", { @@ -65,7 +64,7 @@ test("store.peekAll('person') should return all records and should update with n test("Calling store.peekAll() multiple times should update immediately inside the runloop", function(assert) { assert.expect(3); - Ember.run(() => { + run(() => { assert.equal(get(store.peekAll('person'), 'length'), 0, 'should initially be empty'); store.createRecord('person', { name: "Tomster" }); assert.equal(get(store.peekAll('person'), 'length'), 1, 'should contain one person'); @@ -85,7 +84,7 @@ test("Calling store.peekAll() multiple times should update immediately inside th test("Calling store.peekAll() after creating a record should return correct data", function(assert) { assert.expect(1); - Ember.run(() => { + run(() => { store.createRecord('person', { name: "Tomster" }); assert.equal(get(store.peekAll('person'), 'length'), 1, 'should contain one person'); }); diff --git a/tests/integration/polymorphic-belongs-to-test.js b/tests/integration/polymorphic-belongs-to-test.js index fc1822d96a7..e2e680f8017 100644 --- a/tests/integration/polymorphic-belongs-to-test.js +++ b/tests/integration/polymorphic-belongs-to-test.js @@ -1,12 +1,11 @@ +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; const { attr, belongsTo } = DS; -const { run } = Ember; let store; diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index 8e921f1d1a6..b78380b3dae 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -1,14 +1,14 @@ +import { A } from '@ember/array'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let store, env, manager; -const { run } = Ember; - const Person = DS.Model.extend({ name: DS.attr('string'), cars: DS.hasMany('car', { async: false }) @@ -112,20 +112,20 @@ test('destroying the store correctly cleans everything up', function(assert) { assert.equal(internalPersonModel._recordArrays.size, 3, 'expected the person to be a member of 3 recordArrays'); - Ember.run(filterd2, filterd2.destroy); + run(filterd2, filterd2.destroy); assert.equal(internalPersonModel._recordArrays.size, 2, 'expected the person to be a member of 2 recordArrays'); assert.equal(filterd2Summary.called.length, 1); assert.equal('person' in manager._liveRecordArrays, true); - Ember.run(all, all.destroy); + run(all, all.destroy); assert.equal(internalPersonModel._recordArrays.size, 1, 'expected the person to be a member of 1 recordArrays'); assert.equal(allSummary.called.length, 1); assert.equal('person' in manager._liveRecordArrays, false); - Ember.run(manager, manager.destroy); + run(manager, manager.destroy); assert.equal(internalPersonModel._recordArrays.size, 0, 'expected the person to be a member of no recordArrays'); assert.equal(filterdSummary.called.length, 1); @@ -309,7 +309,7 @@ test('createRecordArray \w optional content', function(assert) { return record; } }; - let content = Ember.A([internalModel]); + let content = A([internalModel]); let recordArray = manager.createRecordArray('foo', content); assert.equal(recordArray.modelName, 'foo'); diff --git a/tests/integration/record-array-test.js b/tests/integration/record-array-test.js index e784365e397..f311d3ac9e2 100644 --- a/tests/integration/record-array-test.js +++ b/tests/integration/record-array-test.js @@ -1,13 +1,13 @@ -import {createStore} from 'dummy/tests/helpers/store'; +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; +import { Promise, hash } from 'rsvp'; +import { createStore } from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { get, run, RSVP: { Promise }} = Ember; - let results; const Person = DS.Model.extend({ @@ -204,7 +204,7 @@ test('a loaded record is removed from a record array when it is deleted', functi }); return run(() => { - return Ember.RSVP.hash({ + return hash({ scumbag: store.findRecord('person', 1), tag: store.findRecord('tag', 1) }).then(records => { @@ -224,7 +224,7 @@ test('a loaded record is removed from a record array when it is deleted', functi assert.equal(get(recordArray, 'length'), 1, 'record is still in the record array until it is saved'); - Ember.run(scumbag, 'save'); + run(scumbag, 'save'); assert.equal(get(recordArray, 'length'), 0, 'record is removed from the array when it is saved'); }); @@ -352,7 +352,7 @@ test('a newly created record is removed from a record array when it is deleted', assert.equal(get(recordArray, 'length'), 1, 'precond - record array already has the first created item'); // guarantee coalescence - Ember.run(() => { + run(() => { store.createRecord('person', { name: 'p1' }); store.createRecord('person', { name: 'p2' }); store.createRecord('person', { name: 'p3' }); diff --git a/tests/integration/record-arrays/adapter-populated-record-array-test.js b/tests/integration/record-arrays/adapter-populated-record-array-test.js index 6264ed285e2..ed368e67404 100644 --- a/tests/integration/record-arrays/adapter-populated-record-array-test.js +++ b/tests/integration/record-arrays/adapter-populated-record-array-test.js @@ -1,12 +1,12 @@ -import {setupStore, createStore} from 'dummy/tests/helpers/store'; -import Ember from 'ember'; +import { run } from '@ember/runloop'; +import { Promise } from 'rsvp'; +import { setupStore, createStore } from 'dummy/tests/helpers/store'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let store; -const { run, RSVP: { Promise } } = Ember; const Person = DS.Model.extend({ name: DS.attr('string'), diff --git a/tests/integration/records/collection-save-test.js b/tests/integration/records/collection-save-test.js index 801275a7321..ebe56231995 100644 --- a/tests/integration/records/collection-save-test.js +++ b/tests/integration/records/collection-save-test.js @@ -1,12 +1,11 @@ +import { resolve, reject } from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { run } = Ember; - let Post, env; module("integration/records/collection_save - Save Collection of Records", { @@ -34,7 +33,7 @@ test("Collection will resolve save on success", function(assert) { let posts = env.store.peekAll('post'); env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ data: { id: id++ , type: 'post' } }); + return resolve({ data: { id: id++ , type: 'post' } }); }; return run(() => { @@ -53,7 +52,7 @@ test("Collection will reject save on error", function(assert) { let posts = env.store.peekAll('post'); env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.reject(); + return reject(); }; return run(() => { @@ -76,14 +75,14 @@ test("Retry is allowed in a failure handler", function(assert) { env.adapter.createRecord = function(store, type, snapshot) { if (count++ === 0) { - return Ember.RSVP.reject(); + return reject(); } else { - return Ember.RSVP.resolve({ data: { id: id++, type: 'post' } }); + return resolve({ data: { id: id++, type: 'post' } }); } }; env.adapter.updateRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ data: { id: snapshot.id, type: 'post' } }); + return resolve({ data: { id: snapshot.id, type: 'post' } }); }; return run(() => { @@ -108,10 +107,10 @@ test("Collection will reject save on invalid", function(assert) { let posts = env.store.peekAll('post'); env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.reject({ title: 'invalid' }); + return reject({ title: 'invalid' }); }; - return Ember.run(() => { + return run(() => { return posts.save().catch(() => { assert.ok(true, 'save operation was rejected'); }); diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index fe3ab6b3f58..957c3ecc38f 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -1,16 +1,18 @@ /*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(adam|dave|cersei)" }]*/ +import { Promise as EmberPromise, all } from 'rsvp'; + +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; + import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; var attr = DS.attr; var Person, env; -var run = Ember.run; -var get = Ember.get; module("integration/deletedRecord - Deleting Records", { beforeEach() { @@ -25,7 +27,7 @@ module("integration/deletedRecord - Deleting Records", { }, afterEach() { - Ember.run(function() { + run(function() { env.container.destroy(); }); } @@ -35,7 +37,7 @@ test("records should not be removed from record arrays just after deleting, but var adam, dave; env.adapter.deleteRecord = function() { - return Ember.RSVP.Promise.resolve(); + return EmberPromise.resolve(); }; var all; @@ -64,11 +66,11 @@ test("records should not be removed from record arrays just after deleting, but // pre-condition assert.equal(all.get('length'), 2, 'pre-condition: 2 records in array'); - Ember.run(adam, 'deleteRecord'); + run(adam, 'deleteRecord'); assert.equal(all.get('length'), 2, '2 records in array after deleteRecord'); - Ember.run(adam, 'save'); + run(adam, 'save'); assert.equal(all.get('length'), 1, '1 record in array after deleteRecord and save'); }); @@ -82,7 +84,7 @@ test('deleting a record that is part of a hasMany removes it from the hasMany re Group.toString = () => { return 'Group'; } env.adapter.deleteRecord = function() { - return Ember.RSVP.Promise.resolve(); + return EmberPromise.resolve(); }; env.registry.register('model:group', Group); @@ -138,7 +140,7 @@ test("records can be deleted during record array enumeration", function(assert) var adam, dave; env.adapter.deleteRecord = function() { - return Ember.RSVP.Promise.resolve(); + return EmberPromise.resolve(); }; run(function() { @@ -165,7 +167,7 @@ test("records can be deleted during record array enumeration", function(assert) // pre-condition assert.equal(all.get('length'), 2, 'expected 2 records'); - Ember.run(function() { + run(function() { all.forEach(function(record) { record.destroyRecord(); }); @@ -220,7 +222,7 @@ test("Deleting an invalid newly created record should remove it from the store", var store = env.store; env.adapter.createRecord = function() { - return Ember.RSVP.Promise.reject(new DS.InvalidError([ + return EmberPromise.reject(new DS.InvalidError([ { title: 'Invalid Attribute', detail: 'name is invalid', @@ -260,7 +262,7 @@ test("Destroying an invalid newly created record should remove it from the store }; env.adapter.createRecord = function() { - return Ember.RSVP.Promise.reject(new DS.InvalidError([ + return EmberPromise.reject(new DS.InvalidError([ { title: 'Invalid Attribute', detail: 'name is invalid', @@ -298,7 +300,7 @@ test("Will resolve destroy and save in same loop", function(assert) { env.adapter.createRecord = function() { assert.ok(true, 'save operation resolves'); - return Ember.RSVP.Promise.resolve({ + return EmberPromise.resolve({ data: { id: 123, type: 'person' @@ -318,5 +320,5 @@ test("Will resolve destroy and save in same loop", function(assert) { ]; }); - return Ember.RSVP.all(promises); + return all(promises); }); diff --git a/tests/integration/records/error-test.js b/tests/integration/records/error-test.js index a0ca3f3a941..bbe4a4bff4e 100644 --- a/tests/integration/records/error-test.js +++ b/tests/integration/records/error-test.js @@ -1,12 +1,11 @@ -import Ember from 'ember'; -import {module} from 'qunit'; +import { run } from '@ember/runloop'; +import { module } from 'qunit'; import DS from 'ember-data'; import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; var env, store, Person; var attr = DS.attr; -var run = Ember.run; function updateErrors(func) { window.expectWarning(function() { @@ -29,7 +28,7 @@ module('integration/records/error', { }, afterEach: function() { - Ember.run(function() { + run(function() { env.container.destroy(); }); } @@ -52,7 +51,7 @@ testInDebug('adding errors during root.loaded.created.invalid works', function(a return store.peekRecord('person', 'wat'); }); - Ember.run(() => { + run(() => { person.set('firstName', null); person.set('lastName', null); }); @@ -83,7 +82,7 @@ testInDebug('adding errors root.loaded.created.invalid works', function(assert) }); }); - Ember.run(() => { + run(() => { person.set('firstName', null); person.set('lastName', null); }); @@ -112,7 +111,7 @@ testInDebug('adding errors root.loaded.created.invalid works add + remove + add' }); }); - Ember.run(() => { + run(() => { person.set('firstName', null); }); @@ -143,7 +142,7 @@ testInDebug('adding errors root.loaded.created.invalid works add + (remove, add) }); }); - Ember.run(() => { + run(() => { person.set('firstName', null); }); diff --git a/tests/integration/records/load-test.js b/tests/integration/records/load-test.js index eea2c0f7ae4..605e92115c4 100644 --- a/tests/integration/records/load-test.js +++ b/tests/integration/records/load-test.js @@ -1,12 +1,12 @@ +import { reject } from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; const { hasMany } = DS; -const { run } = Ember; let Post, Comment, env; @@ -28,7 +28,7 @@ module("integration/load - Loading Records", { test("When loading a record fails, the record is not left behind", function(assert) { env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.reject(); + return reject(); }; return run(() => { diff --git a/tests/integration/records/property-changes-test.js b/tests/integration/records/property-changes-test.js index a6374c7ce7d..059434d14c8 100644 --- a/tests/integration/records/property-changes-test.js +++ b/tests/integration/records/property-changes-test.js @@ -1,13 +1,13 @@ +import { resolve } from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; var env, store, Person; var attr = DS.attr; -var run = Ember.run; module('integration/records/property-changes - Property changes', { beforeEach() { @@ -23,7 +23,7 @@ module('integration/records/property-changes - Property changes', { }, afterEach() { - Ember.run(function() { + run(function() { env.container.destroy(); }); } @@ -115,7 +115,7 @@ test('Saving a record trigger observers for locally changed attributes with the var person; env.adapter.updateRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ data: { id: 'wat', type: 'person', attributes: { 'last-name': 'Katz' } } }); + return resolve({ data: { id: 'wat', type: 'person', attributes: { 'last-name': 'Katz' } } }); }; run(function() { diff --git a/tests/integration/records/relationship-changes-test.js b/tests/integration/records/relationship-changes-test.js index bcba2658048..5547164a3d2 100644 --- a/tests/integration/records/relationship-changes-test.js +++ b/tests/integration/records/relationship-changes-test.js @@ -1,10 +1,11 @@ +import { alias } from '@ember/object/computed'; +import { run } from '@ember/runloop'; +import EmberObject, { set, get } from '@ember/object'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import DS from 'ember-data'; import { module, test } from 'qunit'; -const { run, get, set, computed } = Ember; const { attr, belongsTo, hasMany, Model } = DS; let env, store; @@ -169,9 +170,9 @@ test('Calling push with relationship triggers observers once if the relationship test('Calling push with relationship recalculates computed alias property if the relationship was empty and is added to', function(assert) { assert.expect(1); - let Obj = Ember.Object.extend({ + let Obj = EmberObject.extend({ person: null, - siblings: computed.alias('person.siblings') + siblings: alias('person.siblings') }); const obj = Obj.create(); @@ -224,9 +225,9 @@ test('Calling push with relationship recalculates computed alias property if the test('Calling push with relationship recalculates computed alias property to firstObject if the relationship was empty and is added to', function(assert) { assert.expect(1); - let Obj = Ember.Object.extend({ + let Obj = EmberObject.extend({ person: null, - firstSibling: computed.alias('person.siblings.firstObject') + firstSibling: alias('person.siblings.firstObject') }); const obj = Obj.create(); diff --git a/tests/integration/records/reload-test.js b/tests/integration/records/reload-test.js index 76bc76b4b36..31ef546fca5 100644 --- a/tests/integration/records/reload-test.js +++ b/tests/integration/records/reload-test.js @@ -1,14 +1,14 @@ +import { resolve, reject } from 'rsvp'; +import { run } from '@ember/runloop'; +import { get } from '@ember/object'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -var get = Ember.get; var attr = DS.attr; var Person, env; -var run = Ember.run; module("integration/reload - Reloading Records", { beforeEach() { @@ -33,10 +33,10 @@ test("When a single record is requested, the adapter's find method should be cal env.adapter.findRecord = function(store, type, id, snapshot) { if (count === 0) { count++; - return Ember.RSVP.resolve({ data: { id: id, type: 'person', attributes: { name: "Tom Dale" } } }); + return resolve({ data: { id: id, type: 'person', attributes: { name: "Tom Dale" } } }); } else if (count === 1) { count++; - return Ember.RSVP.resolve({ data: { id: id, type: 'person', attributes: { name: "Braaaahm Dale" } } }); + return resolve({ data: { id: id, type: 'person', attributes: { name: "Braaaahm Dale" } } }); } else { assert.ok(false, "Should not get here"); } @@ -75,9 +75,9 @@ test("When a record is reloaded and fails, it can try again", function(assert) { env.adapter.findRecord = function(store, type, id, snapshot) { assert.equal(tom.get('isReloading'), true, "Tom is reloading"); if (count++ === 0) { - return Ember.RSVP.reject(); + return reject(); } else { - return Ember.RSVP.resolve({ data: { id: 1, type: 'person', attributes: { name: "Thomas Dale" } } }); + return resolve({ data: { id: 1, type: 'person', attributes: { name: "Thomas Dale" } } }); } }; @@ -147,7 +147,7 @@ test("When a record is reloaded, its async hasMany relationships still work", fu env.adapter.findRecord = function(store, type, id, snapshot) { switch (type.modelName) { case 'person': - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'person', @@ -163,7 +163,7 @@ test("When a record is reloaded, its async hasMany relationships still work", fu } }); case 'tag': - return Ember.RSVP.resolve({ data: { id: id, type: 'tag', attributes: { name: tags[id] } } }); + return resolve({ data: { id: id, type: 'tag', attributes: { name: tags[id] } } }); } }; diff --git a/tests/integration/records/rematerialize-test.js b/tests/integration/records/rematerialize-test.js index d3aa5a738a4..0e7917043b6 100644 --- a/tests/integration/records/rematerialize-test.js +++ b/tests/integration/records/rematerialize-test.js @@ -1,16 +1,16 @@ /*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(adam|bob|dudu)" }]*/ +import { run } from '@ember/runloop'; + import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let attr = DS.attr; let belongsTo = DS.belongsTo; let hasMany = DS.hasMany; -let run = Ember.run; let env; let Person = DS.Model.extend({ @@ -50,7 +50,7 @@ module("integration/unload - Rematerializing Unloaded Records", { }, afterEach() { - Ember.run(function() { + run(function() { env.container.destroy(); }); } diff --git a/tests/integration/records/save-test.js b/tests/integration/records/save-test.js index 397906fba22..562870048a5 100644 --- a/tests/integration/records/save-test.js +++ b/tests/integration/records/save-test.js @@ -1,12 +1,12 @@ +import { defer, reject, resolve } from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; var Post, env; -var run = Ember.run; module("integration/records/save - Save Record", { beforeEach() { @@ -29,7 +29,7 @@ test("Will resolve save on success", function(assert) { post = env.store.createRecord('post', { title: 'toto' }); }); - var deferred = Ember.RSVP.defer(); + var deferred = defer(); env.adapter.createRecord = function(store, type, snapshot) { return deferred.promise; }; @@ -58,7 +58,7 @@ test("Will reject save on error", function(assert) { env.adapter.createRecord = function(store, type, snapshot) { var error = new DS.InvalidError([{ title: 'not valid' }]); - return Ember.RSVP.reject(error); + return reject(error); }; run(function() { @@ -80,9 +80,9 @@ test("Retry is allowed in a failure handler", function(assert) { var error = new DS.InvalidError([{ title: 'not valid' }]); if (count++ === 0) { - return Ember.RSVP.reject(error); + return reject(error); } else { - return Ember.RSVP.resolve({ data: { id: 123, type: 'post' } }); + return resolve({ data: { id: 123, type: 'post' } }); } }; @@ -104,7 +104,7 @@ test("Repeated failed saves keeps the record in uncommited state", function(asse }); env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.reject(); + return reject(); }; run(function() { @@ -136,7 +136,7 @@ test("Repeated failed saves with invalid error marks the record as invalid", fun } ]); - return Ember.RSVP.reject(error); + return reject(error); }; run(function() { @@ -161,7 +161,7 @@ test("Repeated failed saves with invalid error without payload marks the record env.adapter.createRecord = function(store, type, snapshot) { var error = new DS.InvalidError(); - return Ember.RSVP.reject(error); + return reject(error); }; run(function() { @@ -185,7 +185,7 @@ test("Will reject save on invalid", function(assert) { env.adapter.createRecord = function(store, type, snapshot) { var error = new DS.InvalidError([{ title: 'not valid' }]); - return Ember.RSVP.reject(error); + return reject(error); }; run(function() { diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 117d9bb994f..99bb0e83215 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -1,16 +1,18 @@ /*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(adam|bob|dudu)" }]*/ +import { Promise as EmberPromise } from 'rsvp'; + +import { run } from '@ember/runloop'; + import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let attr = DS.attr; let belongsTo = DS.belongsTo; let hasMany = DS.hasMany; -let run = Ember.run; let env; let Person = DS.Model.extend({ @@ -57,7 +59,7 @@ module("integration/unload - Unloading Records", { }, afterEach() { - Ember.run(function() { + run(function() { env.container.destroy(); }); } @@ -101,7 +103,7 @@ test("can unload a single record", function(assert) { assert.equal(relPayloads.get('person', 1, 'cars').data.length, 1, 'one car relationship payload is cached'); assert.equal(relPayloads.get('person', 1, 'boats').data.length, 1, 'one boat relationship payload is cached'); - Ember.run(function() { + run(function() { adam.unloadRecord(); }); @@ -162,7 +164,7 @@ test("can unload all records for a given type", function(assert) { assert.equal(relPayloads.get('car', 1, 'person').data.id, 1, 'car - person payload is loaded'); - Ember.run(function() { + run(function() { env.store.unloadAll('person'); }); @@ -171,7 +173,7 @@ test("can unload all records for a given type", function(assert) { assert.equal(env.store._internalModelsFor('person').length, 0, 'zero person internalModels loaded'); assert.equal(env.store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); - Ember.run(function() { + run(function() { env.store.push({ data: { id: 1, @@ -233,7 +235,7 @@ test("can unload all records", function(assert) { assert.equal(env.store.peekAll('car').get('length'), 1, 'one car record loaded'); assert.equal(env.store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); - Ember.run(function() { + run(function() { env.store.unloadAll(); }); @@ -270,7 +272,7 @@ test("removes findAllCache after unloading all records", function(assert) { assert.equal(env.store.peekAll('person').get('length'), 2, 'two person records loaded'); assert.equal(env.store._internalModelsFor('person').length, 2, 'two person internalModels loaded'); - Ember.run(function() { + run(function() { env.store.peekAll('person'); env.store.unloadAll('person'); }); @@ -305,7 +307,7 @@ test("unloading all records also updates record array from peekAll()", function( assert.equal(all.get('length'), 2); - Ember.run(function() { + run(function() { env.store.unloadAll('person'); }); assert.equal(all.get('length'), 0); @@ -693,7 +695,7 @@ test("after unloading a record, the record can be fetched again soon there after // stub findRecord env.adapter.findRecord = () => { - return Ember.RSVP.Promise.resolve({ + return EmberPromise.resolve({ data: { type: 'person', id: '1', @@ -750,7 +752,7 @@ test('after unloading a record, the record can be saved again immediately', func } }; - env.adapter.createRecord = () => Ember.RSVP.Promise.resolve(data); + env.adapter.createRecord = () => EmberPromise.resolve(data); run(() => { // add an initial record with id '1' to the store diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index 9ba234c1ff8..fab5da5d26e 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -1,12 +1,12 @@ +import { defer, resolve } from 'rsvp'; +import { run } from '@ember/runloop'; +import { get } from '@ember/object'; import DS from 'ember-data'; -import Ember from 'ember'; import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { isEnabled } from 'ember-data/-private'; import { module, test } from 'qunit'; -var get = Ember.get; -var run = Ember.run; var env, Family; module("integration/references/belongs-to", { @@ -248,7 +248,7 @@ test("push(promise)", function(assert) { var done = assert.async(); var push; - var deferred = Ember.RSVP.defer(); + var deferred = defer(); run(function() { var person = env.store.push({ @@ -409,7 +409,7 @@ test("load() fetches the record", function(assert) { var done = assert.async(); env.adapter.findRecord = function(store, type, id) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'family', @@ -450,7 +450,7 @@ test("load() fetches link when remoteType is link", function(assert) { env.adapter.findBelongsTo = function(store, snapshot, link) { assert.equal(link, "/families/1"); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'family', @@ -494,7 +494,7 @@ test("reload() - loads the record when not yet loaded", function(assert) { count++; assert.equal(count, 1); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'family', @@ -537,7 +537,7 @@ test("reload() - reloads the record when already loaded", function(assert) { count++; assert.equal(count, 1); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'family', @@ -584,7 +584,7 @@ test("reload() - uses link to reload record", function(assert) { env.adapter.findBelongsTo = function(store, snapshot, link) { assert.equal(link, "/families/1"); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'family', diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 19a756c14de..3f094b647be 100755 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -1,12 +1,12 @@ +import { defer, resolve } from 'rsvp'; +import { run } from '@ember/runloop'; +import { get } from '@ember/object'; import DS from 'ember-data'; -import Ember from 'ember'; import setupStore from 'dummy/tests/helpers/store'; import { isEnabled } from 'ember-data/-private'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; -var get = Ember.get; -var run = Ember.run; var env, Person; module("integration/references/has-many", { @@ -431,7 +431,7 @@ test("push(promise)", function(assert) { var done = assert.async(); var push; - var deferred = Ember.RSVP.defer(); + var deferred = defer(); run(function() { var family = env.store.push({ @@ -588,7 +588,7 @@ test("load() fetches the referenced records", function(assert) { var done = assert.async(); env.adapter.findMany = function(store, type, id) { - return Ember.RSVP.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito" } }, { id: 2, type: 'person', attributes: { name: "Michael" } }] }); + return resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito" } }, { id: 2, type: 'person', attributes: { name: "Michael" } }] }); }; var family; @@ -629,7 +629,7 @@ test("load() fetches link when remoteType is link", function(assert) { env.adapter.findHasMany = function(store, snapshot, link) { assert.equal(link, "/families/1/persons"); - return Ember.RSVP.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito" } }, { id: 2, type: 'person', attributes: { name: "Michael" } }] }); + return resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito" } }, { id: 2, type: 'person', attributes: { name: "Michael" } }] }); }; var family; @@ -666,7 +666,7 @@ test("load() fetches link when remoteType is link but an empty set of records is env.adapter.findHasMany = function(store, snapshot, link) { assert.equal(link, "/families/1/persons"); - return Ember.RSVP.resolve({ data: [] }); + return resolve({ data: [] }); }; let family; @@ -699,7 +699,7 @@ test("load() fetches link when remoteType is link but an empty set of records is test("load() - only a single find is triggered", function(assert) { var done = assert.async(); - var deferred = Ember.RSVP.defer(); + var deferred = defer(); var count = 0; env.adapter.findMany = function(store, type, id) { @@ -753,7 +753,7 @@ test("reload()", function(assert) { var done = assert.async(); env.adapter.findMany = function(store, type, id) { - return Ember.RSVP.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito Coreleone" } }, { id: 2, type: 'person', attributes: { name: "Michael Coreleone" } }] }); + return resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito Coreleone" } }, { id: 2, type: 'person', attributes: { name: "Michael Coreleone" } }] }); }; var family; @@ -799,9 +799,9 @@ test("reload() fetches link when remoteType is link", function(assert) { assert.equal(link, "/families/1/persons"); if (count === 1) { - return Ember.RSVP.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito" } }, { id: 2, type: 'person', attributes: { name: "Michael" } }] }); + return resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito" } }, { id: 2, type: 'person', attributes: { name: "Michael" } }] }); } else { - return Ember.RSVP.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito Coreleone" } }, { id: 2, type: 'person', attributes: { name: "Michael Coreleone" } }] }); + return resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito Coreleone" } }, { id: 2, type: 'person', attributes: { name: "Michael Coreleone" } }] }); } }; diff --git a/tests/integration/references/record-test.js b/tests/integration/references/record-test.js index d29d547e093..553fd0d4116 100644 --- a/tests/integration/references/record-test.js +++ b/tests/integration/references/record-test.js @@ -1,10 +1,10 @@ +import { defer, resolve } from 'rsvp'; +import { run } from '@ember/runloop'; +import { get } from '@ember/object'; import DS from 'ember-data'; -import Ember from 'ember'; import setupStore from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; -var get = Ember.get; -var run = Ember.run; var env, Person; module("integration/references/record", { @@ -66,7 +66,7 @@ test("push(promise)", function(assert) { var done = assert.async(); var push; - var deferred = Ember.RSVP.defer(); + var deferred = defer(); var recordReference = env.store.getReference('person', 1); run(function() { @@ -121,7 +121,7 @@ test("load() fetches the record", function(assert) { var done = assert.async(); env.adapter.findRecord = function(store, type, id) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'person', @@ -145,7 +145,7 @@ test("load() fetches the record", function(assert) { test("load() only a single find is triggered", function(assert) { var done = assert.async(); - var deferred = Ember.RSVP.defer(); + var deferred = defer(); var count = 0; env.adapter.shouldReloadRecord = function() { return false; }; @@ -195,7 +195,7 @@ test("reload() loads the record if not yet loaded", function(assert) { count++; assert.equal(count, 1); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'person', @@ -221,7 +221,7 @@ test("reload() fetches the record", function(assert) { var done = assert.async(); env.adapter.findRecord = function(store, type, id) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'person', diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 4926a77f273..8e1aeb4d0d9 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1,3 +1,6 @@ +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; +import RSVP, { resolve } from 'rsvp'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; @@ -6,11 +9,10 @@ import { setup as setupModelFactoryInjections, reset as resetModelFactoryInjection } from 'dummy/tests/helpers/model-factory-injection'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { get, run, RSVP } = Ember; const { attr, hasMany, belongsTo } = DS; const { hash } = RSVP; @@ -103,7 +105,7 @@ test("The store can materialize a non loaded monomorphic belongsTo association", env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.findRecord = function(store, type, id, snapshot) { assert.ok(true, "The adapter's find method should be called"); - return Ember.RSVP.resolve({ + return resolve({ data: { id, type: snapshot.modelName @@ -331,7 +333,7 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to assert.equal(relationship.key, 'group'); assert.equal(link, "/people/1/group"); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'group', @@ -388,7 +390,7 @@ test('A record with an async belongsTo relationship always returns a promise for }; env.adapter.findBelongsTo = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ data: { id: 1, type: 'seat' } }); + return resolve({ data: { id: 1, type: 'seat' } }); }; return run(() => { @@ -439,7 +441,7 @@ test("A record with an async belongsTo relationship returning null should resolv }; env.adapter.findBelongsTo = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ data: null }); + return resolve({ data: null }); }; return env.store.findRecord('person', '1').then(person => { @@ -866,7 +868,7 @@ test("belongsTo hasData async loaded", function(assert) { }); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'book', @@ -890,7 +892,7 @@ test("belongsTo hasData sync loaded", function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'book', @@ -918,7 +920,7 @@ test("belongsTo hasData async not loaded", function(assert) { }); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'book', @@ -942,7 +944,7 @@ test("belongsTo hasData sync not loaded", function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'book', @@ -1065,7 +1067,7 @@ test("Related link should be fetched when no local data is present", function(as env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { assert.equal(url, 'author', 'url is correct'); assert.ok(true, "The adapter's findBelongsTo method should be called"); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'author', @@ -1107,7 +1109,7 @@ test("Local data should take precedence over related link", function(assert) { }; env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'author', @@ -1148,7 +1150,7 @@ test("New related link should take precedence over local data", function(assert) env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { assert.equal(url, 'author-new-link', 'url is correct'); assert.ok(true, "The adapter's findBelongsTo method should be called"); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'author', @@ -1207,7 +1209,7 @@ test("Updated related link should take precedence over local data", function(ass env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { assert.equal(url, 'author-updated-link', 'url is correct'); assert.ok(true, "The adapter's findBelongsTo method should be called"); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'author', @@ -1336,7 +1338,7 @@ test("A belongsTo relationship can be reloaded using the reference if it was fet }); env.adapter.findRecord = function() { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'chapter', @@ -1350,7 +1352,7 @@ test("A belongsTo relationship can be reloaded using the reference if it was fet }; env.adapter.findBelongsTo = function() { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'book', @@ -1370,7 +1372,7 @@ test("A belongsTo relationship can be reloaded using the reference if it was fet assert.equal(book.get('name'), "book title"); env.adapter.findBelongsTo = function() { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'book', @@ -1416,7 +1418,7 @@ test("A sync belongsTo relationship can be reloaded using a reference if it was }); env.adapter.findRecord = function() { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'book', @@ -1456,7 +1458,7 @@ test("A belongsTo relationship can be reloaded using a reference if it was fetch }); env.adapter.findRecord = function() { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'book', @@ -1470,7 +1472,7 @@ test("A belongsTo relationship can be reloaded using a reference if it was fetch assert.equal(book.get('name'), "book title"); env.adapter.findRecord = function() { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'book', diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 0db8908dd08..6ce847463cb 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -4,19 +4,28 @@ import { setup as setupModelFactoryInjections, reset as resetModelFactoryInjections } from 'dummy/tests/helpers/model-factory-injection'; +import { A } from '@ember/array'; + +import { + resolve, + Promise as EmberPromise, + all, + reject, + hash +} from 'rsvp'; +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; + import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let env, store, User, Contact, Email, Phone, Message, Post, Comment; let Book, Chapter, Page; -const { get, run } = Ember; -const { resolve } = Ember.RSVP; const { attr, hasMany, belongsTo } = DS; module("integration/relationships/has_many - Has-Many Relationships", { @@ -323,7 +332,7 @@ test("adapter.findMany only gets unique IDs even if duplicate IDs are present in assert.equal(type, Chapter, 'type passed to adapter.findMany is correct'); assert.deepEqual(ids, ['2', '3'], 'ids passed to adapter.findMany are unique'); - return Ember.RSVP.resolve({ + return resolve({ data: [ { id: 2, type: 'chapter', attributes: { title: 'Chapter One' } }, { id: 3, type: 'chapter', attributes: { title: 'Chapter Two' } } @@ -361,7 +370,7 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi assert.equal(type, Post, "find type was Post"); assert.equal(id, "1", "find id was 1"); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'post', @@ -385,7 +394,7 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); assert.equal(relationship.type, "comment", "relationship was passed correctly"); - return Ember.RSVP.resolve({ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "First" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } @@ -436,7 +445,7 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ env.adapter.findHasMany = function(store, snapshot, link, relationship) { count++; assert.equal(count, 1, "findHasMany has only been called once"); - return new Ember.RSVP.Promise((resolve, reject) => { + return new EmberPromise((resolve, reject) => { setTimeout(() => { let value = { data: [ @@ -468,7 +477,7 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ promise2 = post.get('comments'); }); - return Ember.RSVP.all([ + return all([ promise1, promise2 ]).then(() => { @@ -487,7 +496,7 @@ test("A hasMany backed by a link remains a promise after a record has been added }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "First" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } @@ -543,11 +552,11 @@ test("A hasMany updated link should not remove new children", function(assert) { }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ data: [] }); + return resolve({ data: [] }); }; env.adapter.createRecord = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'post', @@ -587,13 +596,13 @@ test("A hasMany updated link should not remove new children when the parent reco }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 5, type: 'comment', attributes: { body: 'hello' } } ]}); }; env.adapter.createRecord = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'post', @@ -633,7 +642,7 @@ test("A hasMany relationship doesn't contain duplicate children, after the canon }); env.adapter.createRecord = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ data: { id: 1, type: 'post' } }); + return resolve({ data: { id: 1, type: 'post' } }); }; return run(() => { @@ -697,7 +706,7 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func assert.equal(type, Post, "find type was Post"); assert.equal(id, "1", "find id was 1"); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'post', @@ -715,7 +724,7 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func assert.equal(relationship.key, 'comments', "findHasMany relationship key was comments"); assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "First" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); @@ -733,7 +742,7 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func assert.equal(relationship.key, 'comments', "findHasMany relationship key was comments"); assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "First" } }, { id: 2, type: 'comment', attributes: { body: "Second" } }, { id: 3, type: 'comment', attributes: { body: "Thirds" } } @@ -756,7 +765,7 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu assert.equal(type, Post, "find type was Post"); assert.equal(id, "1", "find id was 1"); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'post', @@ -795,7 +804,7 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu assert.equal(comments.get('length'), 2, "comments have a length of 2"); env.adapter.findMany = function(store, type, ids, snapshots) { - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); @@ -817,7 +826,7 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio assert.equal(type, Post, "find type was Post"); assert.equal(id, "1", "find id was 1"); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'post', @@ -831,7 +840,7 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio }; env.adapter.findMany = function(store, type, ids, snapshots) { - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "First" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); @@ -845,7 +854,7 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio assert.equal(comments.get('length'), 2, "comments have 2 length"); env.adapter.findMany = function(store, type, ids, snapshots) { - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); @@ -866,7 +875,7 @@ test("A hasMany relationship can be reloaded even if it failed at the first time }); env.adapter.findRecord = function(store, type, id) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'post', @@ -883,9 +892,9 @@ test("A hasMany relationship can be reloaded even if it failed at the first time env.adapter.findHasMany = function(store, record, link, relationship) { loadingCount++; if (loadingCount % 2 === 0) { - return Ember.RSVP.reject(); + return reject(); } else { - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); @@ -921,7 +930,7 @@ test("A hasMany relationship can be directly reloaded if it was fetched via link assert.equal(type, Post, "find type was Post"); assert.equal(id, "1", "find id was 1"); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'post', @@ -937,7 +946,7 @@ test("A hasMany relationship can be directly reloaded if it was fetched via link env.adapter.findHasMany = function(store, record, link, relationship) { assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); @@ -962,7 +971,7 @@ test("Has many via links - Calling reload multiple times does not send a new req }); env.adapter.findRecord = function(store, type, id) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'post', @@ -978,7 +987,7 @@ test("Has many via links - Calling reload multiple times does not send a new req let count = 0; env.adapter.findHasMany = function(store, record, link, relationship) { count++; - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "First" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); @@ -986,7 +995,7 @@ test("Has many via links - Calling reload multiple times does not send a new req run(function() { env.store.findRecord('post', 1).then(function(post) { post.get('comments').then(function(comments) { - Ember.RSVP.all([comments.reload(), comments.reload(), comments.reload()]).then(function(comments) { + all([comments.reload(), comments.reload(), comments.reload()]).then(function(comments) { assert.equal(count, 2, "One request for the original access and only one request for the mulitple reloads"); done(); }); @@ -1004,7 +1013,7 @@ test("A hasMany relationship can be directly reloaded if it was fetched via ids" assert.equal(type, Post, "find type was Post"); assert.equal(id, "1", "find id was 1"); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'post', @@ -1018,7 +1027,7 @@ test("A hasMany relationship can be directly reloaded if it was fetched via ids" }; env.adapter.findMany = function(store, type, ids, snapshots) { - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); @@ -1044,7 +1053,7 @@ test("Has many via ids - Calling reload multiple times does not send a new reque }); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'post', @@ -1060,7 +1069,7 @@ test("Has many via ids - Calling reload multiple times does not send a new reque let count = 0; env.adapter.findMany = function(store, type, ids, snapshots) { count++; - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); @@ -1069,7 +1078,7 @@ test("Has many via ids - Calling reload multiple times does not send a new reque run(function() { env.store.findRecord('post', 1).then(function(post) { post.get('comments').then(function(comments) { - Ember.RSVP.all([comments.reload(), comments.reload(), comments.reload()]).then(function(comments) { + all([comments.reload(), comments.reload(), comments.reload()]).then(function(comments) { assert.equal(count, 2, "One request for the original access and only one request for the mulitple reloads"); done(); }); @@ -1086,7 +1095,7 @@ test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loa }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "First" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); @@ -1130,7 +1139,7 @@ test("PromiseArray proxies evented methods to its ManyArray", function(assert) { }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "First" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); @@ -1197,12 +1206,12 @@ test("An updated `links` value should invalidate a relationship cache", function assert.equal(relationship.type, "comment", "relationship was passed correctly"); if (link === '/first') { - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "First" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); } else if (link === '/second') { - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 3, type: 'comment', attributes: { body: "Third" } }, { id: 4, type: 'comment', attributes: { body: "Fourth" } }, { id: 5, type: 'comment', attributes: { body: "Fifth" } } @@ -1307,9 +1316,9 @@ test("When a polymorphic hasMany relationship is accessed, the store can call mu env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.findRecord = function(store, type, id, snapshot) { if (type === Post) { - return Ember.RSVP.resolve({ data: { id: 1, type: 'post' } }); + return resolve({ data: { id: 1, type: 'post' } }); } else if (type === Comment) { - return Ember.RSVP.resolve({ data: { id: 3, type: 'comment' } }); + return resolve({ data: { id: 3, type: 'comment' } }); } }; @@ -1567,7 +1576,7 @@ testInDebug("Only records of the same type can be added to a monomorphic hasMany }); run(function() { - Ember.RSVP.all([ + all([ env.store.findRecord('post', 1), env.store.findRecord('post', 2) ]).then(function(records) { @@ -1617,7 +1626,7 @@ testInDebug("Only records of the same base modelClass can be added to a polymorp let asyncRecords; run(function() { - asyncRecords = Ember.RSVP.hash({ + asyncRecords = hash({ user: env.store.findRecord('user', 1), anotherUser: env.store.findRecord('user', 2), post: env.store.findRecord('post', 1), @@ -1626,7 +1635,7 @@ testInDebug("Only records of the same base modelClass can be added to a polymorp asyncRecords.then(function(records) { records.messages = records.user.get('messages'); - return Ember.RSVP.hash(records); + return hash(records); }).then(function(records) { records.messages.pushObject(records.post); records.messages.pushObject(records.comment); @@ -1664,14 +1673,14 @@ test("A record can be removed from a polymorphic association", function(assert) let asyncRecords; run(function() { - asyncRecords = Ember.RSVP.hash({ + asyncRecords = hash({ user: env.store.findRecord('user', 1), comment: env.store.findRecord('comment', 3) }); asyncRecords.then(function(records) { records.messages = records.user.get('messages'); - return Ember.RSVP.hash(records); + return hash(records); }).then(function(records) { assert.equal(records.messages.get('length'), 1, "The user has 1 message"); @@ -1792,7 +1801,7 @@ test("When a record is saved, its unsaved hasMany records should be kept", funct let post, comment; env.adapter.createRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve({ data: { id: 1, type: snapshot.modelName } }); + return resolve({ data: { id: 1, type: snapshot.modelName } }); }; return run(() => { @@ -1817,7 +1826,7 @@ test("dual non-async HM <-> BT", function(assert) { env.adapter.createRecord = function(store, type, snapshot) { let serialized = snapshot.record.serialize(); serialized.data.id = 2; - return Ember.RSVP.resolve(serialized); + return resolve(serialized); }; let post, firstComment; @@ -2485,7 +2494,7 @@ test("Relationship.clear removes all records correctly", function(assert) { env.store.peekAll('comment').mapBy('post'); post._internalModel._relationships.get('comments').clear(); - let comments = Ember.A(env.store.peekAll('comment')); + let comments = A(env.store.peekAll('comment')); assert.deepEqual(comments.mapBy('post'), [null, null, null]); }); }); @@ -2580,13 +2589,13 @@ test("adding and removing records from hasMany relationship #2666", function(ass let commentId = 4; env.registry.register('adapter:comment', DS.RESTAdapter.extend({ deleteRecord(record) { - return Ember.RSVP.resolve(); + return resolve(); }, updateRecord(record) { - return Ember.RSVP.resolve(); + return resolve(); }, createRecord() { - return Ember.RSVP.resolve({ comments: { id: commentId++ }}); + return resolve({ comments: { id: commentId++ }}); } })); @@ -2658,7 +2667,7 @@ test("hasMany hasData async loaded", function(assert) { }); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'chapter', @@ -2684,7 +2693,7 @@ test("hasMany hasData sync loaded", function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'chapter', @@ -2714,7 +2723,7 @@ test("hasMany hasData async not loaded", function(assert) { }); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'chapter', @@ -2740,7 +2749,7 @@ test("hasMany hasData sync not loaded", function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'chapter', @@ -2989,7 +2998,7 @@ test("Related link should be fetched when no local data is present", function(as env.adapter.findHasMany = function(store, snapshot, url, relationship) { assert.equal(url, 'comments', 'url is correct'); assert.ok(true, "The adapter's findHasMany method should be called"); - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: 'This is comment' } } ]}); }; @@ -3027,7 +3036,7 @@ test("Local data should take precedence over related link", function(assert) { }; env.adapter.findRecord = function(store, type, id, snapshot) { - return Ember.RSVP.resolve({ data: { id: 1, type: 'comment', attributes: { body: 'This is comment' } } }); + return resolve({ data: { id: 1, type: 'comment', attributes: { body: 'This is comment' } } }); }; return run(() => { @@ -3064,7 +3073,7 @@ test("Updated related link should take precedence over local data", function(ass env.adapter.findHasMany = function(store, snapshot, url, relationship) { assert.equal(url, 'comments-updated-link', 'url is correct'); assert.ok(true, "The adapter's findHasMany method should be called"); - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: 'This is comment' } } ]}); }; @@ -3119,7 +3128,7 @@ test("PromiseArray proxies createRecord to its ManyArray before the hasMany is l }); env.adapter.findHasMany = function(store, record, link, relationship) { - return Ember.RSVP.resolve({ data: [ + return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: "First" } }, { id: 2, type: 'comment', attributes: { body: "Second" } } ]}); diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index 99f7f217224..cb14af74e22 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -1,14 +1,13 @@ -import {createStore} from 'dummy/tests/helpers/store'; +import { run } from '@ember/runloop'; +import { createStore } from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; var Post, Comment, Message, User; -var run = Ember.run; module('integration/relationships/inverse_relationships - Inverse Relationships'); diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index ae3016fe73f..82f0746466e 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -1,13 +1,15 @@ /*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(ada)" }]*/ +import { resolve, Promise as EmberPromise } from 'rsvp'; + +import { run } from '@ember/runloop'; + import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { run } = Ember; const { attr, hasMany } = DS; let Account, Topic, User, store, env; @@ -35,7 +37,7 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships', topic: Topic, account: Account, adapter: DS.Adapter.extend({ - deleteRecord: () => Ember.RSVP.resolve() + deleteRecord: () => resolve() }) }); @@ -434,7 +436,7 @@ test("Rollbacking attributes for a deleted record that has a ManyToMany relation assert.equal(fetchedTopics.get('length'), 1, 'Topic got rollbacked into the user'); }); - return Ember.RSVP.Promise.all([ + return EmberPromise.all([ users, topics ]); @@ -511,7 +513,7 @@ test("Rollbacking attributes for a created record that has a ManyToMany relation assert.equal(fetchedTopics.objectAt(0), null, "Topic can't be fetched"); }); - return Ember.RSVP.Promise.all([ + return EmberPromise.all([ users, topics ]); diff --git a/tests/integration/relationships/nested-relationship-test.js b/tests/integration/relationships/nested-relationship-test.js index 425a48701ec..9ef5d78c4a0 100644 --- a/tests/integration/relationships/nested-relationship-test.js +++ b/tests/integration/relationships/nested-relationship-test.js @@ -1,11 +1,11 @@ +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { get, run } = Ember; const { attr, hasMany, belongsTo } = DS; let env, store, serializer, Elder, MiddleAger, Kid; diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index 59a5f5feb7e..7477cea1d63 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -1,13 +1,13 @@ +import { resolve } from 'rsvp'; +import { run } from '@ember/runloop'; +import { get } from '@ember/object'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; var env, store, User, Message, Account; -var get = Ember.get; -var run = Ember.run; var attr = DS.attr; var hasMany = DS.hasMany; @@ -36,7 +36,7 @@ module('integration/relationships/one_to_many_test - OneToMany relationships', { message: Message, account: Account, adapter: DS.Adapter.extend({ - deleteRecord: () => Ember.RSVP.resolve() + deleteRecord: () => resolve() }) }); diff --git a/tests/integration/relationships/one-to-one-test.js b/tests/integration/relationships/one-to-one-test.js index a4b9038aed1..c65f848b149 100644 --- a/tests/integration/relationships/one-to-one-test.js +++ b/tests/integration/relationships/one-to-one-test.js @@ -1,13 +1,13 @@ +import { resolve, Promise as EmberPromise } from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; var env, store, User, Job; -var run = Ember.run; var attr = DS.attr; var belongsTo = DS.belongsTo; @@ -29,7 +29,7 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', { user: User, job: Job, adapter: DS.Adapter.extend({ - deleteRecord: () => Ember.RSVP.resolve() + deleteRecord: () => resolve() }) }); @@ -532,7 +532,7 @@ testInDebug("Setting a BelongsTo to a promise that didn't come from a relationsh assert.expectAssertion(function() { run(function() { - stanley.set('bestFriend', Ember.RSVP.resolve(igor)); + stanley.set('bestFriend', resolve(igor)); }); }, /You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call./); }); @@ -588,10 +588,10 @@ test("Setting a BelongsTo to a promise multiple times is resistant to race condi env.adapter.findRecord = function(store, type, id, snapshot) { if (id === '5') { - return Ember.RSVP.resolve({ data: { id: 5, type: 'user', attributes: { name: "Igor's friend" } } }); + return resolve({ data: { id: 5, type: 'user', attributes: { name: "Igor's friend" } } }); } else if (id === '2') { let done = assert.async(); - return new Ember.RSVP.Promise(function(resolve, reject) { + return new EmberPromise(function(resolve, reject) { setTimeout(function() { done(); resolve({ data: { id: 2, type: 'user', attributes: { name: "Stanley's friend" } } }); diff --git a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index f62f41e22d1..38e134012fa 100644 --- a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -3,16 +3,16 @@ import { reset as resetModelFactoryInjections } from 'dummy/tests/helpers/model-factory-injection'; +import Mixin from '@ember/object/mixin'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; var env, store, User, Message, Video, NotMessage; -var run = Ember.run; var attr = DS.attr; var belongsTo = DS.belongsTo; @@ -24,7 +24,7 @@ module('integration/relationships/polymorphic_mixins_belongs_to_test - Polymorph bestMessage: belongsTo('message', { async: true, polymorphic: true }) }); - Message = Ember.Mixin.create({ + Message = Mixin.create({ title: attr('string'), user: belongsTo('user', { async: true }) }); diff --git a/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js index 8993ad3f8c4..470e3dfd146 100644 --- a/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -3,16 +3,16 @@ import { reset as resetModelFactoryInjections } from 'dummy/tests/helpers/model-factory-injection'; +import Mixin from '@ember/object/mixin'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; var env, store, User, Message, NotMessage, Video; -var run = Ember.run; var attr = DS.attr; var hasMany = DS.hasMany; @@ -25,7 +25,7 @@ module('integration/relationships/polymorphic_mixins_has_many_test - Polymorphic messages: hasMany('message', { async: true, polymorphic: true }) }); - Message = Ember.Mixin.create({ + Message = Mixin.create({ title: attr('string'), user: belongsTo('user', { async: true }) }); diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index 78ca55ae5ca..fc6a8b3bc26 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -1,15 +1,15 @@ +import { w } from '@ember/string'; +import { run } from '@ember/runloop'; +import { get } from '@ember/object'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -var get = Ember.get; var HomePlanet, SuperVillain, CommanderVillain, NormalMinion, EvilMinion, YellowMinion, RedMinion, SecretLab, SecretWeapon, BatCave, Comment, league, superVillain, commanderVillain, evilMinion, yellowMinion, redMinion, secretWeapon, homePlanet, secretLab, env; -var run = Ember.run; var LightSaber; module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { @@ -2117,7 +2117,7 @@ test("serializing relationships with an embedded and without calls super when no var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, "hasMany") : key; var relationshipType = snapshot.type.determineRelationshipType(relationship); // "manyToOne" not supported in DS.ActiveModelSerializer.prototype.serializeHasMany - var relationshipTypes = Ember.String.w('manyToNone manyToMany manyToOne'); + var relationshipTypes = w('manyToNone manyToMany manyToOne'); if (relationshipTypes.indexOf(relationshipType) > -1) { json[payloadKey] = snapshot.hasMany(key, { ids: true }); } diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 700432645c9..42170fbaa1f 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -1,8 +1,9 @@ +import { run } from '@ember/runloop'; +import { get } from '@ember/object'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import { isEnabled } from 'ember-data/-private'; @@ -10,9 +11,6 @@ import DS from 'ember-data'; var env, store, serializer; -var get = Ember.get; -var run = Ember.run; - var User, Handle, GithubHandle, TwitterHandle, Company, Project; module('integration/serializers/json-api-serializer - JSONAPISerializer', { diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 8fae94bf3f9..1c8172d1a92 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -1,14 +1,14 @@ +import { underscore } from '@ember/string'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import { isEnabled } from 'ember-data/-private'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; var Post, post, Comment, comment, Favorite, favorite, env, serializer; -var run = Ember.run; module("integration/serializer/json - JSONSerializer", { beforeEach() { @@ -400,7 +400,7 @@ test('Serializer should map `attrs` attributes directly when keyForAttribute als post: Post }); env.registry.register("serializer:post", DS.JSONSerializer.extend({ - keyForAttribute: Ember.String.underscore, + keyForAttribute: underscore, attrs: { authorName: 'author_name_key' } diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 46d69e47abf..f2aca2c68ae 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -1,15 +1,14 @@ -import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; +import { camelize, decamelize, dasherize } from '@ember/string'; import Inflector, { singularize } from 'ember-inflector'; - +import { run, bind } from '@ember/runloop'; +import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import { isEnabled } from 'ember-data/-private'; import DS from 'ember-data'; var HomePlanet, league, SuperVillain, EvilMinion, YellowMinion, DoomsdayDevice, Comment, Basket, Container, env; -var run = Ember.run; module("integration/serializer/rest - RESTSerializer", { beforeEach() { @@ -104,7 +103,7 @@ test("normalizeResponse with custom modelNameFromPayloadKey", function(assert) { assert.expect(1); env.restSerializer.modelNameFromPayloadKey = function(root) { - var camelized = Ember.String.camelize(root); + var camelized = camelize(root); return singularize(camelized); }; env.registry.register('serializer:home-planet', DS.JSONSerializer); @@ -215,7 +214,7 @@ testInDebug("normalizeResponse warning with custom modelNameFromPayloadKey", fun home_planet: { id: "1", name: "Umber", superVillains: [1] } }; - assert.expectWarning(Ember.run.bind(null, function() { + assert.expectWarning(bind(null, function() { run(function() { env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, '1', 'findRecord'); }); @@ -257,7 +256,7 @@ testInDebug("normalizeResponse warning with custom modelNameFromPayloadKey", fun // should not warn if a model is found. env.restSerializer.modelNameFromPayloadKey = function(root) { - return Ember.String.camelize(singularize(root)); + return camelize(singularize(root)); }; jsonHash = { @@ -491,7 +490,7 @@ test('normalize should allow for different levels of normalization', function(as superVillain: 'is_super_villain' }, keyForAttribute(attr) { - return Ember.String.decamelize(attr); + return decamelize(attr); } })); @@ -513,7 +512,7 @@ test('normalize should allow for different levels of normalization - attributes' name: 'full_name' }, keyForAttribute(attr) { - return Ember.String.decamelize(attr); + return decamelize(attr); } })); @@ -656,7 +655,7 @@ test('serializeIntoHash uses payloadKeyFromModelName to normalize the payload ro var json = {}; env.registry.register('serializer:home-planet', DS.RESTSerializer.extend({ payloadKeyFromModelName(modelName) { - return Ember.String.dasherize(modelName); + return dasherize(modelName); } })); diff --git a/tests/integration/setup-container-test.js b/tests/integration/setup-container-test.js index eaaf937e554..68286a4caa5 100644 --- a/tests/integration/setup-container-test.js +++ b/tests/integration/setup-container-test.js @@ -1,10 +1,11 @@ -import Ember from 'ember'; +import Application from '@ember/application'; +import { run } from '@ember/runloop'; +import EmberObject from '@ember/object'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { run, Object: EmberObject } = Ember; const { Store, _setupContainer: setupContainer } = DS; let container, registry, application; @@ -16,7 +17,7 @@ let container, registry, application; module("integration/setup-container - Setting up a container", { beforeEach() { - application = run(() => Ember.Application.create()); + application = run(() => Application.create()); container = application.__container__; registry = application.__registry__; diff --git a/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js index 992907ef007..b92963cf6e3 100644 --- a/tests/integration/snapshot-test.js +++ b/tests/integration/snapshot-test.js @@ -1,11 +1,11 @@ +import { resolve } from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { run } = Ember; let env, Post, Comment; module("integration/snapshot - DS.Snapshot", { @@ -372,7 +372,7 @@ test("snapshot.belongsTo() returns a snapshot if relationship link has been fetc assert.expect(2); env.adapter.findBelongsTo = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ data: { id: 1, type: 'post', attributes: { title: 'Hello World' } } }); + return resolve({ data: { id: 1, type: 'post', attributes: { title: 'Hello World' } } }); }; return run(() => { @@ -804,7 +804,7 @@ test("snapshot.hasMany() returns array of snapshots if relationship link has bee assert.expect(2); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return Ember.RSVP.resolve({ data: [{ id: 2, type: 'comment', attributes: { body: 'This is comment' } }]}); + return resolve({ data: [{ id: 2, type: 'comment', attributes: { body: 'This is comment' } }]}); }; return run(() => { diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 03abfe1b4b6..bf33dc85f4e 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -1,8 +1,13 @@ +import { copy } from '@ember/object/internals'; +import RSVP, { + Promise as EmberPromise, + resolve +} from 'rsvp'; +import { run, next } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; import { isEnabled } from 'ember-data/-private'; @@ -20,7 +25,6 @@ Person.reopenClass({ } }); -const { run } = Ember; const Car = DS.Model.extend({ make: DS.attr('string'), model: DS.attr('string'), @@ -76,8 +80,8 @@ test("destroying record during find doesn't cause error", function(assert) { let TestAdapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return new Ember.RSVP.Promise((resolve, reject) => { - Ember.run.next(() => { + return new EmberPromise((resolve, reject) => { + next(() => { store.unloadAll(type.modelName); reject(); }); @@ -100,7 +104,7 @@ test("find calls do not resolve when the store is destroyed", function(assert) { let TestAdapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { store.destroy(); - Ember.RSVP.resolve(null); + resolve(null); } }); @@ -111,7 +115,7 @@ test("find calls do not resolve when the store is destroyed", function(assert) { let id = 1; store.push = function() { - Ember.assert("The test should have destroyed the store by now", store.get("isDestroyed")); + assert("The test should have destroyed the store by now", store.get("isDestroyed")); throw new Error("We shouldn't be pushing data into the store when it is destroyed"); }; @@ -197,7 +201,7 @@ test("destroying the store correctly cleans everything up", function(assert) { assert.equal(car.get('person'), person, "expected car's person to be the correct person"); assert.equal(person.get('cars.firstObject'), car, " expected persons cars's firstRecord to be the correct car"); - Ember.run(store, 'destroy'); + run(store, 'destroy'); assert.equal(personWillDestroy.called.length, 1, 'expected person to have recieved willDestroy once'); assert.equal(carWillDestroy.called.length, 1, 'expected car to recieve willDestroy once'); @@ -209,11 +213,11 @@ test("destroying the store correctly cleans everything up", function(assert) { function ajaxResponse(value) { if (isEnabled('ds-improved-ajax')) { env.adapter._makeRequest = function() { - return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); + return run(RSVP, 'resolve', copy(value, true)); }; } else { env.adapter.ajax = function(url, verb, hash) { - return run(Ember.RSVP, 'resolve', Ember.copy(value, true)); + return run(RSVP, 'resolve', copy(value, true)); }; } } diff --git a/tests/integration/store/json-api-validation-test.js b/tests/integration/store/json-api-validation-test.js index b4015274c5c..47300f88518 100644 --- a/tests/integration/store/json-api-validation-test.js +++ b/tests/integration/store/json-api-validation-test.js @@ -1,11 +1,11 @@ +import { resolve } from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import QUnit, { module } from 'qunit'; import DS from 'ember-data'; var Person, store, env; -var run = Ember.run; function payloadError(payload, expectedError) { env.registry.register('serializer:person', DS.Serializer.extend({ @@ -15,7 +15,7 @@ function payloadError(payload, expectedError) { })); env.registry.register('adapter:person', DS.Adapter.extend({ findRecord() { - return Ember.RSVP.resolve(payload); + return resolve(payload); } })); this.throws(function () { @@ -58,7 +58,7 @@ testInDebug("when normalizeResponse returns undefined (or doesn't return), throw env.registry.register('adapter:person', DS.Adapter.extend({ findRecord() { - return Ember.RSVP.resolve({ data: {} }); + return resolve({ data: {} }); } })); @@ -77,7 +77,7 @@ testInDebug("when normalizeResponse returns null, throws an error", function(ass env.registry.register('adapter:person', DS.Adapter.extend({ findRecord() { - return Ember.RSVP.resolve({ data: {} }); + return resolve({ data: {} }); } })); @@ -97,7 +97,7 @@ testInDebug("when normalizeResponse returns an empty object, throws an error", f env.registry.register('adapter:person', DS.Adapter.extend({ findRecord() { - return Ember.RSVP.resolve({ data: {} }); + return resolve({ data: {} }); } })); @@ -121,7 +121,7 @@ testInDebug("when normalizeResponse returns a document with both data and errors env.registry.register('adapter:person', DS.Adapter.extend({ findRecord() { - return Ember.RSVP.resolve({ data: {} }); + return resolve({ data: {} }); } })); diff --git a/tests/integration/store/query-record-test.js b/tests/integration/store/query-record-test.js index a712c6ef5c3..b83aa9bfa69 100644 --- a/tests/integration/store/query-record-test.js +++ b/tests/integration/store/query-record-test.js @@ -1,13 +1,13 @@ +import { resolve, reject } from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; var Person, store, env; -var run = Ember.run; module("integration/store/query-record - Query one record with a query hash", { beforeEach() { @@ -47,7 +47,7 @@ test("When a record is requested, the adapter's queryRecord method should be cal env.registry.register('adapter:person', DS.Adapter.extend({ queryRecord(store, type, query) { assert.equal(type, Person, "the query method is called with the correct type"); - return Ember.RSVP.resolve({ data: { id: 1, type: 'person', attributes: { name: "Peter Wagenet" } } }); + return resolve({ data: { id: 1, type: 'person', attributes: { name: "Peter Wagenet" } } }); } })); @@ -59,7 +59,7 @@ test("When a record is requested, the adapter's queryRecord method should be cal test("When a record is requested, and the promise is rejected, .queryRecord() is rejected.", function(assert) { env.registry.register('adapter:person', DS.Adapter.extend({ queryRecord(store, type, query) { - return Ember.RSVP.reject(); + return reject(); } })); @@ -82,7 +82,7 @@ test("When a record is requested, the serializer's normalizeQueryRecordResponse env.registry.register('adapter:person', DS.Adapter.extend({ queryRecord(store, type, query) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: '1', type: 'person', diff --git a/tests/test-helper.js b/tests/test-helper.js index fd29fcbea65..31c7459330e 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -4,6 +4,9 @@ must be evaluated before the `qunit` module is evaluated (because we change `QUnit.module`). */ +import RSVP from 'rsvp'; + +import Application from '@ember/application'; import requiredWorkAroundBabelBug from 'dummy/tests/helpers/setup-ember-dev'; // eslint-disable-line import resolver from './helpers/resolver'; import { @@ -20,7 +23,7 @@ import Ember from 'ember'; import loadInitializers from 'ember-load-initializers'; setResolver(resolver); -loadInitializers(Ember.Application, 'dummy'); +loadInitializers(Application, 'dummy'); const { assert } = QUnit; const transforms = { @@ -31,7 +34,7 @@ const transforms = { }; QUnit.begin(() => { - Ember.RSVP.configure('onerror', reason => { + RSVP.configure('onerror', reason => { // only print error messages if they're exceptions; // otherwise, let a future turn of the event loop // handle the error. diff --git a/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js index 91dda1d0e7a..738bec5a131 100644 --- a/tests/unit/adapter-errors-test.js +++ b/tests/unit/adapter-errors-test.js @@ -1,7 +1,7 @@ -import Ember from 'ember'; +import EmberError from '@ember/error'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; @@ -11,7 +11,7 @@ test('DS.AdapterError', function(assert) { let error = new DS.AdapterError(); assert.ok(error instanceof Error); - assert.ok(error instanceof Ember.Error); + assert.ok(error instanceof EmberError); assert.ok(error.isAdapterError); assert.equal(error.message, 'Adapter operation failed'); }); diff --git a/tests/unit/adapters/build-url-mixin/path-for-type-test.js b/tests/unit/adapters/build-url-mixin/path-for-type-test.js index a3c07356423..1302a3bf9ee 100644 --- a/tests/unit/adapters/build-url-mixin/path-for-type-test.js +++ b/tests/unit/adapters/build-url-mixin/path-for-type-test.js @@ -1,11 +1,10 @@ +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; import DS from 'ember-data'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; let env, adapter; -let { run } = Ember; module("unit/adapters/build-url-mixin/path-for-type - DS.BuildURLMixin#pathForType", { beforeEach() { diff --git a/tests/unit/adapters/json-api-adapter/ajax-test.js b/tests/unit/adapters/json-api-adapter/ajax-test.js index 4d2044a6077..c97fd3f1b53 100644 --- a/tests/unit/adapters/json-api-adapter/ajax-test.js +++ b/tests/unit/adapters/json-api-adapter/ajax-test.js @@ -1,12 +1,12 @@ +import { computed } from '@ember/object'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let Person, Place, store, adapter, env; -const { run } = Ember; module("unit/adapters/json-api-adapter/ajax - building requests", { beforeEach() { @@ -55,7 +55,7 @@ test('ajaxOptions() adds Accept header to existing headers', function(assert) { }); test('ajaxOptions() adds Accept header to existing computed properties headers', function(assert) { - adapter.headers = Ember.computed(function() { + adapter.headers = computed(function() { return { 'Other-key': 'Other Value' }; }); let url = 'example.com'; diff --git a/tests/unit/adapters/rest-adapter/ajax-test.js b/tests/unit/adapters/rest-adapter/ajax-test.js index 1bbed398c3c..f7baae4b4c4 100644 --- a/tests/unit/adapters/rest-adapter/ajax-test.js +++ b/tests/unit/adapters/rest-adapter/ajax-test.js @@ -1,13 +1,13 @@ +import { resolve, Promise as EmberPromise } from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; import { isEnabled } from 'ember-data/-private'; var Person, Place, store, adapter, env; -const { run } = Ember; module('unit/adapters/rest-adapter/ajax - building requests', { beforeEach() { @@ -36,22 +36,22 @@ test('When an id is searched, the correct url should be generated', function(ass if (count === 0) { assert.equal(request.url, '/people/1', 'should create the correct url'); } if (count === 1) { assert.equal(request.url, '/places/1', 'should create the correct url'); } count++; - return Ember.RSVP.resolve(); + return resolve(); }; } else { adapter.ajax = function(url, method) { if (count === 0) { assert.equal(url, '/people/1', 'should create the correct url'); } if (count === 1) { assert.equal(url, '/places/1', 'should create the correct url'); } count++; - return Ember.RSVP.resolve(); + return resolve(); }; } return run(() => { - return Ember.RSVP.Promise.all([ + return EmberPromise.all([ adapter.findRecord(store, Person, 1, {}), adapter.findRecord(store, Place, 1, {}) - ]) + ]); }); }); @@ -61,12 +61,12 @@ test(`id's should be sanatized`, function(assert) { if (isEnabled('ds-improved-ajax')) { adapter._makeRequest = function(request) { assert.equal(request.url, '/people/..%2Fplace%2F1', `should create the correct url`); - return Ember.RSVP.resolve(); + return resolve(); }; } else { adapter.ajax = function(url, method) { assert.equal(url, '/people/..%2Fplace%2F1', "should create the correct url"); - return Ember.RSVP.resolve(); + return resolve(); }; } diff --git a/tests/unit/adapters/rest-adapter/detailed-message-test.js b/tests/unit/adapters/rest-adapter/detailed-message-test.js index 946a510b7ca..cef3e9b4c6d 100644 --- a/tests/unit/adapters/rest-adapter/detailed-message-test.js +++ b/tests/unit/adapters/rest-adapter/detailed-message-test.js @@ -1,6 +1,6 @@ import setupStore from 'dummy/tests/helpers/store'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 5010adbcb10..fdcef39969a 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -1,7 +1,8 @@ -import {createStore} from 'dummy/tests/helpers/store'; -import Ember from 'ember'; +import { run } from '@ember/runloop'; +import { Promise as EmberPromise } from 'rsvp'; +import { createStore } from 'dummy/tests/helpers/store'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; import { isEnabled } from 'ember-data/-private'; @@ -42,7 +43,7 @@ module('unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda lengths.push(fullUrl.length); let testRecords = request.data.ids.map(id => ({ id })); - return Ember.RSVP.Promise.resolve({ 'testRecords' : testRecords }); + return EmberPromise.resolve({ 'testRecords' : testRecords }); } }); } else { @@ -62,7 +63,7 @@ module('unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda lengths.push(fullUrl.length); let testRecords = options.data.ids.map(id => ({ id })); - return Ember.RSVP.Promise.resolve({ 'testRecords' : testRecords }); + return EmberPromise.resolve({ 'testRecords' : testRecords }); } }); } @@ -73,25 +74,25 @@ module('unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda }); }, afterEach() { - Ember.run(store, 'destroy'); + run(store, 'destroy'); } }); test('groupRecordsForFindMany - findMany', function(assert) { let wait = []; - Ember.run(() => { + run(() => { for (var i = 1; i <= 1024; i++) { wait.push(store.findRecord('testRecord', i)); } }); assert.ok(lengths.every(len => len <= maxLength), `Some URLs are longer than ${maxLength} chars`); - return Ember.RSVP.Promise.all(wait); + return EmberPromise.all(wait); }); test('groupRecordsForFindMany works for encodeURIComponent-ified ids', function(assert) { let wait = []; - Ember.run(() => { + run(() => { wait.push(store.findRecord('testRecord', 'my-id:1')); wait.push(store.findRecord('testRecord', 'my-id:2')); }); @@ -100,11 +101,11 @@ test('groupRecordsForFindMany works for encodeURIComponent-ified ids', function( assert.equal(requests[0].url, '/testRecords'); assert.deepEqual(requests[0].ids, ['my-id:1', 'my-id:2']); - return Ember.RSVP.Promise.all(wait); + return EmberPromise.all(wait); }); test('_stripIDFromURL works with id being encoded - #4190', function(assert) { - let record = Ember.run(() => store.createRecord('testRecord', { id: "id:123" })); + let record = run(() => store.createRecord('testRecord', { id: "id:123" })); let adapter = store.adapterFor('testRecord'); let snapshot = record._internalModel.createSnapshot(); let strippedUrl = adapter._stripIDFromURL(store, snapshot); diff --git a/tests/unit/debug-test.js b/tests/unit/debug-test.js index e399e13d7c9..5925c8441cc 100644 --- a/tests/unit/debug-test.js +++ b/tests/unit/debug-test.js @@ -1,12 +1,11 @@ -import {createStore} from 'dummy/tests/helpers/store'; -import Ember from 'ember'; +import { computed } from '@ember/object'; +import { run } from '@ember/runloop'; +import { createStore } from 'dummy/tests/helpers/store'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { run } = Ember; - const TestAdapter = DS.Adapter.extend(); module('Debug'); @@ -57,7 +56,7 @@ test('_debugInfo supports arbitray relationship types', function(assert) { name: DS.attr('string'), isDrugAddict: DS.attr('boolean'), maritalStatus: DS.belongsTo('marital-status', { async: false }), - posts: Ember.computed(() => [1, 2, 3] ) + posts: computed(() => [1, 2, 3] ) .readOnly().meta({ options: { inverse: null }, isRelationship: true, diff --git a/tests/unit/diff-array-test.js b/tests/unit/diff-array-test.js index 1526cb9f9e5..9d69b8f1a3d 100644 --- a/tests/unit/diff-array-test.js +++ b/tests/unit/diff-array-test.js @@ -1,4 +1,4 @@ -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import { diffArray } from 'ember-data/-private'; diff --git a/tests/unit/many-array-test.js b/tests/unit/many-array-test.js index 5ddca06ed74..d0f8b141c74 100644 --- a/tests/unit/many-array-test.js +++ b/tests/unit/many-array-test.js @@ -1,14 +1,14 @@ +import { resolve } from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let env, store, Post, Tag; const { attr, hasMany, belongsTo } = DS; -const { run } = Ember; module('unit/many_array - DS.ManyArray', { beforeEach() { @@ -53,7 +53,7 @@ test('manyArray.save() calls save() on all records', function(assert) { Tag.reopen({ save() { assert.ok(true, 'record.save() was called'); - return Ember.RSVP.resolve(); + return resolve(); } }); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index eb4fe34d6c7..d54ca482193 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -1,14 +1,16 @@ -import {createStore} from 'dummy/tests/helpers/store'; +import { guidFor } from '@ember/object/internals'; +import { Promise as EmberPromise, resolve } from 'rsvp'; +import { set, get, observer, computed } from '@ember/object'; +import { run } from '@ember/runloop'; +import { createStore } from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; import { isEnabled } from 'ember-data/-private'; import { getOwner } from 'ember-data/-private'; -const { get, set, run } = Ember; - let Person, store, env; module('unit/model - DS.Model', { @@ -96,7 +98,7 @@ test('resetting a property to the current in-flight value causes it to become cl assert.expect(4); env.adapter.updateRecord = function(store, type, snapshot) { - return Ember.RSVP.Promise.resolve() + return EmberPromise.resolve(); }; return run(() => { @@ -190,7 +192,7 @@ test("a record's id is included in its toString representation", function(assert }); return store.findRecord('person', 1).then(record => { - assert.equal(record.toString(), `<(subclass of DS.Model):${Ember.guidFor(record)}:1>`, 'reports id in toString'); + assert.equal(record.toString(), `<(subclass of DS.Model):${guidFor(record)}:1>`, 'reports id in toString'); }); }); }); @@ -523,7 +525,7 @@ if (isEnabled('ds-rollback-attribute')) { // Make sure the save is async env.adapter.updateRecord = function(store, type, snapshot) { - return Ember.RSVP.resolve(); + return resolve(); }; return run(() => { @@ -558,7 +560,7 @@ if (isEnabled('ds-rollback-attribute')) { assert.expect(7); let person, finishSaving; - let updateRecordPromise = new Ember.RSVP.Promise(resolve => finishSaving = resolve); + let updateRecordPromise = new EmberPromise(resolve => finishSaving = resolve); // Make sure the save is async env.adapter.updateRecord = function(store, type, snapshot) { @@ -609,7 +611,7 @@ if (isEnabled('ds-rollback-attribute')) { finishSaving(); }); - return Ember.RSVP.Promise.all(saving); + return EmberPromise.all(saving); }); } @@ -1183,7 +1185,7 @@ test('ensure model exits loading state, materializes data and fulfills promise o let store = createStore({ adapter: DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'person', @@ -1347,7 +1349,7 @@ test('internalModel is ready by `init`', function(assert) { this.set('name', 'my-name-set-in-init'); }, - nameDidChange: Ember.observer('name', () => nameDidChange++) + nameDidChange: observer('name', () => nameDidChange++) }); let { store } = setupStore({ person: Person }); @@ -1403,7 +1405,7 @@ test('updating the id with store.updateId should correctly when the id property const Person = DS.Model.extend({ name: DS.attr('string'), - idComputed: Ember.computed('id', function() {}) + idComputed: computed('id', function() {}) }); let { store } = setupStore({ @@ -1427,7 +1429,7 @@ test('accessing the model id without the get function should work when id is wat const Person = DS.Model.extend({ name: DS.attr('string'), - idComputed: Ember.computed('id', function() {}) + idComputed: computed('id', function() {}) }); let { store } = setupStore({ diff --git a/tests/unit/model/errors-test.js b/tests/unit/model/errors-test.js index d51d4246090..71374b7d31e 100644 --- a/tests/unit/model/errors-test.js +++ b/tests/unit/model/errors-test.js @@ -1,5 +1,5 @@ import DS from 'ember-data'; -import QUnit, {module} from 'qunit'; +import QUnit, { module } from 'qunit'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; const AssertPrototype = QUnit.assert; diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index 13257dd728d..3ea46df61ba 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -1,12 +1,12 @@ -import {createStore} from 'dummy/tests/helpers/store'; -import Ember from 'ember'; +import { resolve, reject } from 'rsvp'; +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; +import { createStore } from 'dummy/tests/helpers/store'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { get, run } = Ember; - module('unit/model/lifecycle_callbacks - Lifecycle Callbacks'); test('a record receives a didLoad callback when it has finished loading', function(assert) { @@ -84,7 +84,7 @@ test('a record receives a didUpdate callback when it has finished updating', fun updateRecord(store, type, snapshot) { assert.equal(callCount, 0, 'didUpdate callback was not called until didSaveRecord is called'); - return Ember.RSVP.resolve(); + return resolve(); } }); @@ -126,7 +126,7 @@ test('a record receives a didCreate callback when it has finished updating', fun createRecord(store, type, snapshot) { assert.equal(callCount, 0, 'didCreate callback was not called until didSaveRecord is called'); - return Ember.RSVP.resolve(); + return resolve(); } }); @@ -171,7 +171,7 @@ test('a record receives a didDelete callback when it has finished deleting', fun deleteRecord(store, type, snapshot) { assert.equal(callCount, 0, 'didDelete callback was not called until didSaveRecord is called'); - return Ember.RSVP.resolve(); + return resolve(); } }); @@ -250,7 +250,7 @@ test('a record receives a becameInvalid callback when it became invalid', functi updateRecord(store, type, snapshot) { assert.equal(callCount, 0, 'becameInvalid callback was not called until recordWasInvalid is called'); - return Ember.RSVP.reject(new DS.InvalidError([ + return reject(new DS.InvalidError([ { title: 'Invalid Attribute', detail: 'error', diff --git a/tests/unit/model/merge-test.js b/tests/unit/model/merge-test.js index c2f865dd5d9..bac3ef1f41e 100644 --- a/tests/unit/model/merge-test.js +++ b/tests/unit/model/merge-test.js @@ -1,12 +1,12 @@ -import {createStore} from 'dummy/tests/helpers/store'; -import Ember from 'ember'; +import { resolve, Promise as EmberPromise } from 'rsvp'; +import { run } from '@ember/runloop'; +import { createStore } from 'dummy/tests/helpers/store'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let Person; -const { run } = Ember; module('unit/model/merge - Merging', { beforeEach() { @@ -55,7 +55,7 @@ test('Make sure snapshot is created at save time not at flush time', function(as updateRecord(store, type, snapshot) { assert.equal(snapshot.attr('name'), 'Thomas Dale'); - return Ember.RSVP.resolve(); + return resolve(); } }); @@ -97,7 +97,7 @@ test("When a record is in flight, pushes are applied underneath the in flight ch const Adapter = DS.Adapter.extend({ updateRecord(store, type, snapshot) { // Make sure saving isn't resolved synchronously - return new Ember.RSVP.Promise(resolve => { + return new EmberPromise(resolve => { run.next(null, resolve, { data: { id: 1, type: 'person', attributes: { name: 'Senor Thomas Dale, Esq.', city: 'Portland' } } }); }); } diff --git a/tests/unit/model/relationships-test.js b/tests/unit/model/relationships-test.js index 0d437b51b59..3edee836733 100644 --- a/tests/unit/model/relationships-test.js +++ b/tests/unit/model/relationships-test.js @@ -1,11 +1,11 @@ -import {createStore} from 'dummy/tests/helpers/store'; -import Ember from 'ember'; +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; +import { createStore } from 'dummy/tests/helpers/store'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { get, run } = Ember; let Occupation, Person, store; module('unit/model/relationships - DS.Model', { diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index 32606b21674..496558e5ed6 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -1,13 +1,12 @@ +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { get, run } = Ember; - module('unit/model/relationships - DS.belongsTo'); test('belongsTo lazily loads relationships as needed', function(assert) { diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 1aac40c7181..b856b18f73e 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -1,12 +1,13 @@ +import { hash, Promise as EmberPromise } from 'rsvp'; +import { get, observer } from '@ember/object'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { get, run } = Ember; let env; module('unit/model/relationships - DS.hasMany', { @@ -839,7 +840,7 @@ test('hasMany lazily loads async relationships', function(assert) { assert.equal(get(wycats, 'name'), 'Yehuda Katz', 'precond - retrieves person record from store'); - return Ember.RSVP.hash({ + return hash({ wycats, tags: wycats.get('tags') }); @@ -1122,7 +1123,7 @@ test('new items added to a hasMany relationship are not cleared by a delete', fu }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.deleteRecord = () => { - return Ember.RSVP.Promise.resolve({ data: null }); + return EmberPromise.resolve({ data: null }); }; let { store } = env; @@ -1214,7 +1215,7 @@ test('new items added to an async hasMany relationship are not cleared by a dele }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.deleteRecord = () => { - return Ember.RSVP.Promise.resolve({ data: null }); + return EmberPromise.resolve({ data: null }); }; let { store } = env; @@ -1308,7 +1309,7 @@ test('new items added to a belongsTo relationship are not cleared by a delete', }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.deleteRecord = () => { - return Ember.RSVP.Promise.resolve({ data: null }); + return EmberPromise.resolve({ data: null }); }; let { store } = env; @@ -1390,7 +1391,7 @@ test('new items added to an async belongsTo relationship are not cleared by a de }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.deleteRecord = () => { - return Ember.RSVP.Promise.resolve({ data: null }); + return EmberPromise.resolve({ data: null }); }; let { store } = env; @@ -1472,7 +1473,7 @@ test('deleting an item that is the current state of a belongsTo clears currentSt }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.deleteRecord = () => { - return Ember.RSVP.Promise.resolve({ data: null }); + return EmberPromise.resolve({ data: null }); }; let { store } = env; @@ -1629,7 +1630,7 @@ test('[ASSERTS KNOWN LIMITATION STILL EXISTS] returning new hasMany relationship }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.deleteRecord = () => { - return Ember.RSVP.Promise.resolve({ + return EmberPromise.resolve({ data: null, included: [ { @@ -1935,7 +1936,7 @@ test('DS.hasMany is stable', function(assert) { assert.equal(people, notifiedPeople); - return Ember.RSVP.Promise.all([ + return EmberPromise.all([ people ]); }); @@ -1957,7 +1958,7 @@ test('DS.hasMany proxy is destroyed', function(assert) { let peopleProxy = tag.get('people'); return peopleProxy.then(people => { - Ember.run(() => { + run(() => { tag.unloadRecord(); assert.equal(people.isDestroying, false, 'people is NOT destroying sync after unloadRecord'); assert.equal(people.isDestroyed, false, 'people is NOT destroyed sync after unloadRecord'); @@ -1967,7 +1968,7 @@ test('DS.hasMany proxy is destroyed', function(assert) { assert.equal(peopleProxy.isDestroying, true, 'peopleProxy is destroying after the run post unloadRecord'); assert.equal(peopleProxy.isDestroyed, true, 'peopleProxy is destroyed after the run post unloadRecord'); - }) + }); }); test('DS.ManyArray is lazy', function(assert) { @@ -1975,7 +1976,7 @@ test('DS.ManyArray is lazy', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), people: DS.hasMany('person'), - peopleDidChange: Ember.observer('people', function() { + peopleDidChange: observer('people', function() { peopleDidChange++; }) }); @@ -2000,9 +2001,9 @@ test('DS.ManyArray is lazy', function(assert) { assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (after access, but after the current run loop)'); assert.ok(hasManyRelationship._manyArray instanceof DS.ManyArray); - let person = Ember.run(() => env.store.createRecord('person')); + let person = run(() => env.store.createRecord('person')); - Ember.run(() => { + run(() => { assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (before access)'); tag.get('people').addObject(person); assert.equal(peopleDidChange, 1, 'expect people hasMany to have changed exactly once'); diff --git a/tests/unit/model/relationships/record-array-test.js b/tests/unit/model/relationships/record-array-test.js index dafc81f7271..7cdf36da71c 100644 --- a/tests/unit/model/relationships/record-array-test.js +++ b/tests/unit/model/relationships/record-array-test.js @@ -1,12 +1,12 @@ +import { A } from '@ember/array'; +import { set, get } from '@ember/object'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { get, set, run } = Ember; - module('unit/model/relationships - RecordArray'); test('updating the content of a RecordArray updates its content', function(assert) { @@ -42,7 +42,7 @@ test('updating the content of a RecordArray updates its content', function(asser }] }); tags = DS.RecordArray.create({ - content: Ember.A(internalModels.slice(0, 2)), + content: A(internalModels.slice(0, 2)), store: store, modelName: 'tag' }); @@ -51,7 +51,7 @@ test('updating the content of a RecordArray updates its content', function(asser let tag = tags.objectAt(0); assert.equal(get(tag, 'name'), 'friendly', `precond - we're working with the right tags`); - run(() => set(tags, 'content', Ember.A(internalModels.slice(1, 3)))); + run(() => set(tags, 'content', A(internalModels.slice(1, 3)))); tag = tags.objectAt(0); assert.equal(get(tag, 'name'), 'smarmy', 'the lookup was updated'); diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index b884d133f89..985d8f5eb9b 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -1,13 +1,15 @@ +import { isEmpty, isPresent } from '@ember/utils'; +import { addObserver } from '@ember/object/observers'; +import { Promise as EmberPromise, reject } from 'rsvp'; +import { run, later } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; import { isEnabled } from 'ember-data/-private'; let env, store, Person; -const { run } = Ember; module('unit/model/rollbackAttributes - model.rollbackAttributes()', { beforeEach() { @@ -75,7 +77,7 @@ test('changes to unassigned attributes can be rolled back', function(assert) { test('changes to attributes made after a record is in-flight only rolls back the local changes', function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { // Make sure the save is async - return new Ember.RSVP.Promise(resolve => Ember.run.later(null, resolve, 15)); + return new EmberPromise(resolve => later(null, resolve, 15)); }; let person = run(() => { @@ -119,7 +121,7 @@ test('changes to attributes made after a record is in-flight only rolls back the test("a record's changes can be made if it fails to save", function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { - return Ember.RSVP.reject(); + return reject(); }; let person = run(() => { @@ -159,7 +161,7 @@ test("a record's changes can be made if it fails to save", function(assert) { test(`a deleted record's attributes can be rollbacked if it fails to save, record arrays are updated accordingly`, function(assert) { assert.expect(8); env.adapter.deleteRecord = function(store, type, snapshot) { - return Ember.RSVP.reject(); + return reject(); }; let person, people; @@ -204,7 +206,7 @@ test(`new record's attributes can be rollbacked`, function(assert) { assert.equal(person.get('isNew'), true, 'must be new'); assert.equal(person.get('hasDirtyAttributes'), true, 'must be dirty'); - Ember.run(person, 'rollbackAttributes'); + run(person, 'rollbackAttributes'); assert.equal(person.get('isNew'), false, 'must not be new'); assert.equal(person.get('hasDirtyAttributes'), false, 'must not be dirty'); @@ -223,13 +225,13 @@ test(`invalid new record's attributes can be rollbacked`, function(assert) { if (isEnabled('ds-improved-ajax')) { adapter = DS.RESTAdapter.extend({ _makeRequest() { - return Ember.RSVP.reject(error); + return reject(error); } }); } else { adapter = DS.RESTAdapter.extend({ ajax(url, type, hash) { - return Ember.RSVP.reject(error); + return reject(error); } }); } @@ -261,14 +263,14 @@ test(`invalid record's attributes can be rollbacked after multiple failed calls adapter = DS.RESTAdapter.extend({ _makeRequest() { let error = new DS.InvalidError(); - return Ember.RSVP.reject(error); + return reject(error); } }); } else { adapter = DS.RESTAdapter.extend({ ajax(url, type, hash) { let error = new DS.InvalidError(); - return Ember.RSVP.reject(error); + return reject(error); } }); } @@ -351,13 +353,13 @@ test("invalid record's attributes can be rollbacked", function(assert) { if (isEnabled('ds-improved-ajax')) { adapter = DS.RESTAdapter.extend({ _makeRequest() { - return Ember.RSVP.reject(error); + return reject(error); } }); } else { adapter = DS.RESTAdapter.extend({ ajax(url, type, hash) { - return Ember.RSVP.reject(error); + return reject(error); } }); } @@ -380,7 +382,7 @@ test("invalid record's attributes can be rollbacked", function(assert) { }); return run(() => { - Ember.addObserver(dog, 'errors.name', function() { + addObserver(dog, 'errors.name', function() { assert.ok(true, 'errors.name did change'); }); @@ -400,7 +402,7 @@ test("invalid record's attributes can be rollbacked", function(assert) { assert.equal(dog.get('hasDirtyAttributes'), false, 'must not be dirty'); assert.equal(dog.get('name'), 'Pluto'); - assert.ok(Ember.isEmpty(dog.get('errors.name'))); + assert.ok(isEmpty(dog.get('errors.name'))); assert.ok(dog.get('isValid')); }); }); @@ -424,13 +426,13 @@ test(`invalid record's attributes rolled back to correct state after set`, funct if (isEnabled('ds-improved-ajax')) { adapter = DS.RESTAdapter.extend({ _makeRequest() { - return Ember.RSVP.reject(error); + return reject(error); } }); } else { adapter = DS.RESTAdapter.extend({ ajax(url, type, hash) { - return Ember.RSVP.reject(error); + return reject(error); } }); } @@ -454,7 +456,7 @@ test(`invalid record's attributes rolled back to correct state after set`, funct }); return run(() => { - Ember.addObserver(dog, 'errors.name', function() { + addObserver(dog, 'errors.name', function() { assert.ok(true, 'errors.name did change'); }); @@ -462,7 +464,7 @@ test(`invalid record's attributes rolled back to correct state after set`, funct assert.equal(reason, error); assert.equal(dog.get('name'), 'is a dwarf planet'); assert.equal(dog.get('breed'), 'planet'); - assert.ok(Ember.isPresent(dog.get('errors.name'))); + assert.ok(isPresent(dog.get('errors.name'))); assert.equal(dog.get('errors.name.length'), 1); run(() => dog.set('name', 'Seymour Asses')); @@ -475,7 +477,7 @@ test(`invalid record's attributes rolled back to correct state after set`, funct assert.equal(dog.get('name'), 'Pluto'); assert.equal(dog.get('breed'), 'Disney'); assert.equal(dog.get('hasDirtyAttributes'), false, 'must not be dirty'); - assert.ok(Ember.isEmpty(dog.get('errors.name'))); + assert.ok(isEmpty(dog.get('errors.name'))); assert.ok(dog.get('isValid')); }); }); @@ -497,13 +499,13 @@ test(`when destroying a record setup the record state to invalid, the record's a if (isEnabled('ds-improved-ajax')) { adapter = DS.RESTAdapter.extend({ _makeRequest() { - return Ember.RSVP.reject(error); + return reject(error); } }); } else { adapter = DS.RESTAdapter.extend({ ajax(url, type, hash) { - return Ember.RSVP.reject(error); + return reject(error); } }); } diff --git a/tests/unit/private-test.js b/tests/unit/private-test.js index bd42b3a33b2..30e468493ff 100644 --- a/tests/unit/private-test.js +++ b/tests/unit/private-test.js @@ -1,5 +1,9 @@ import { module, test } from 'qunit'; -import { ContainerInstanceCache, InternalModel, RootState } from 'ember-data/-private'; +import { + ContainerInstanceCache, + InternalModel, + RootState +} from 'ember-data/-private'; module('-private'); diff --git a/tests/unit/promise-proxies-test.js b/tests/unit/promise-proxies-test.js index 93a94a76ab2..1e5ab5fee69 100644 --- a/tests/unit/promise-proxies-test.js +++ b/tests/unit/promise-proxies-test.js @@ -1,6 +1,7 @@ -import Ember from 'ember'; +import { Promise as EmberPromise } from 'rsvp'; +import { A } from '@ember/array'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; @@ -9,9 +10,9 @@ module('PromiseManyArray'); test('.reload should NOT leak the internal promise, rather return another promiseArray', function(assert) { assert.expect(2); - let content = Ember.A(); + let content = A(); - content.reload = () => Ember.RSVP.Promise.resolve(content); + content.reload = () => EmberPromise.resolve(content); let array = DS.PromiseManyArray.create({ content @@ -27,10 +28,10 @@ test('.reload should NOT leak the internal promise, rather return another promis test('.reload should be stable', function(assert) { assert.expect(19); - let content = Ember.A(); + let content = A(); - content.reload = () => Ember.RSVP.Promise.resolve(content); - let promise = Ember.RSVP.Promise.resolve(content); + content.reload = () => EmberPromise.resolve(content); + let promise = EmberPromise.resolve(content); let array = DS.PromiseManyArray.create({ promise @@ -71,9 +72,9 @@ test('.reload should be stable', function(assert) { test('.set to new promise should be like reload', function(assert) { assert.expect(18); - let content = Ember.A([1,2,3]); + let content = A([1,2,3]); - let promise = Ember.RSVP.Promise.resolve(content); + let promise = EmberPromise.resolve(content); let array = DS.PromiseManyArray.create({ promise @@ -90,7 +91,7 @@ test('.set to new promise should be like reload', function(assert) { assert.equal(array.get('isSettled'), true, 'should be settled'); assert.equal(array.get('isFulfilled'), true, 'should be fulfilled'); - array.set('promise', Ember.RSVP.Promise.resolve(content)); + array.set('promise', EmberPromise.resolve(content)); assert.equal(array.get('isRejected'), false, 'should NOT be rejected'); assert.equal(array.get('isPending'), true, 'should be pending'); diff --git a/tests/unit/record-arrays/adapter-populated-record-array-test.js b/tests/unit/record-arrays/adapter-populated-record-array-test.js index bea0d34070b..f1ed2a8ce79 100644 --- a/tests/unit/record-arrays/adapter-populated-record-array-test.js +++ b/tests/unit/record-arrays/adapter-populated-record-array-test.js @@ -1,9 +1,9 @@ +import { A } from '@ember/array'; +import RSVP from 'rsvp'; +import { run } from '@ember/runloop'; import DS from 'ember-data'; -import {module, test} from 'qunit'; -import Ember from 'ember'; - -const { RSVP, run } = Ember; +import { module, test } from 'qunit'; const { AdapterPopulatedRecordArray } = DS; module('unit/record-arrays/adapter-populated-record-array - DS.AdapterPopulatedRecordArray'); @@ -34,7 +34,7 @@ test('default initial state', function(assert) { }); test('custom initial state', function(assert) { - let content = Ember.A([]); + let content = A([]); let store = {}; let recordArray = AdapterPopulatedRecordArray.create({ modelName: 'apple', diff --git a/tests/unit/record-arrays/filtered-record-array-test.js b/tests/unit/record-arrays/filtered-record-array-test.js index afa43b570f1..6a388cc70df 100644 --- a/tests/unit/record-arrays/filtered-record-array-test.js +++ b/tests/unit/record-arrays/filtered-record-array-test.js @@ -1,9 +1,10 @@ +import { run } from '@ember/runloop'; +import { A } from '@ember/array'; +import { get } from '@ember/object'; import DS from 'ember-data'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; -const { get } = Ember; const { FilteredRecordArray } = DS; module('unit/record-arrays/filtered-record-array - DS.FilteredRecordArray'); @@ -19,7 +20,7 @@ test('default initial state', function(assert) { }); test('custom initial state', function(assert) { - let content = Ember.A(); + let content = A(); let store = {}; let filterFunction = () => true; let recordArray = FilteredRecordArray.create({ @@ -63,12 +64,12 @@ test('updateFilter', function(assert) { let recordArray = FilteredRecordArray.create({ modelName: 'recordType', manager, - content: Ember.A() + content: A() }); assert.equal(didUpdateFilter, 0, 'no filterFunction should have been changed yet'); - Ember.run(() => { + run(() => { recordArray.set('filterFunction', updatedFilterFunction); assert.equal(didUpdateFilter, 0, 'record array manager should not yet be informed of the filterFunction change'); recordArray.set('filterFunction', updatedFilterFunction); @@ -78,7 +79,7 @@ test('updateFilter', function(assert) { assert.equal(didUpdateFilter, 1, 'record array manager should have been informed once that the array filterFunction has changed'); didUpdateFilter = 0; - Ember.run(() => { + run(() => { recordArray.set('filterFunction', updatedFilterFunction); assert.equal(didUpdateFilter, 0, 'record array manager should not be informed of this change'); recordArray.destroy(); diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js index b11f0eb6487..91bd69c6d7b 100644 --- a/tests/unit/record-arrays/record-array-test.js +++ b/tests/unit/record-arrays/record-array-test.js @@ -1,8 +1,10 @@ +import { A } from '@ember/array'; +import { get } from '@ember/object'; +import RSVP from 'rsvp'; +import { run } from '@ember/runloop'; import DS from 'ember-data'; -import Ember from 'ember'; import { module, test } from 'qunit'; -const { get, RSVP, run } = Ember; const { RecordArray } = DS; module('unit/record-arrays/record-array - DS.RecordArray'); @@ -18,7 +20,7 @@ test('default initial state', function(assert) { }); test('custom initial state', function(assert) { - let content = Ember.A(); + let content = A(); let store = {}; let recordArray = RecordArray.create({ modelName: 'apple', @@ -43,7 +45,7 @@ test('#replace() throws error', function(assert) { }); test('#objectAtContent', function(assert) { - let content = Ember.A([ + let content = A([ { getRecord() { return 'foo'; }}, { getRecord() { return 'bar'; }}, { getRecord() { return 'baz'; }} @@ -137,7 +139,7 @@ test('#update while updating', function(assert) { }); test('#_pushInternalModels', function(assert) { - let content = Ember.A(); + let content = A(); let recordArray = RecordArray.create({ content }); @@ -161,7 +163,7 @@ test('#_pushInternalModels', function(assert) { }); test('#_removeInternalModels', function(assert) { - let content = Ember.A(); + let content = A(); let recordArray = RecordArray.create({ content }); @@ -215,7 +217,7 @@ function internalModelFor(record) { test('#save', function(assert) { let model1 = { save() { model1Saved++; return this;} }; let model2 = { save() { model2Saved++; return this;} }; - let content = Ember.A([ + let content = A([ internalModelFor(model1), internalModelFor(model2) ]); @@ -256,7 +258,7 @@ test('#destroy', function(assert) { // end TODO: let recordArray = RecordArray.create({ - content: Ember.A([internalModel1]), + content: A([internalModel1]), manager: { unregisterRecordArray(_recordArray) { didUnregisterRecordArray++; @@ -293,7 +295,7 @@ test('#_createSnapshot', function(assert) { id: 2 }; - let content = Ember.A([ + let content = A([ internalModelFor(model1), internalModelFor(model2) ]); @@ -327,7 +329,7 @@ test('#destroy', function(assert) { // end TODO: let recordArray = RecordArray.create({ - content: Ember.A([internalModel1]), + content: A([internalModel1]), manager: { unregisterRecordArray(_recordArray) { didUnregisterRecordArray++; diff --git a/tests/unit/states-test.js b/tests/unit/states-test.js index abfbb1e3c94..c655068d54b 100644 --- a/tests/unit/states-test.js +++ b/tests/unit/states-test.js @@ -1,9 +1,8 @@ -import Ember from 'ember'; -import QUnit, {module, test} from 'qunit'; +import { get } from '@ember/object'; +import QUnit, { module, test } from 'qunit'; import DS from 'ember-data'; const { assert } = QUnit; -const { get } = Ember; let rootState, stateName; diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index 43c80a267a2..fc7ba5fb307 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -1,14 +1,20 @@ -import {createStore} from 'dummy/tests/helpers/store'; +import { A } from '@ember/array'; +import { + resolve, + all, + Promise as EmberPromise +} from 'rsvp'; +import { set, get } from '@ember/object'; +import { run } from '@ember/runloop'; +import { createStore } from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { get, set , run } = Ember; -const resolve = Ember.RSVP.resolve; let TestAdapter, store, oldFilterEnabled; module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', { @@ -59,7 +65,7 @@ test('Calling Store#find invokes its adapter#find', function(assert) { assert.equal(id, 1, "Adapter#find was called with the id passed into Store#find"); assert.equal(snapshot.id, '1', "Adapter#find was called with the record created from Store#find"); - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'test' @@ -88,7 +94,7 @@ test('Calling Store#findRecord multiple times coalesces the calls into a adapter findMany(store, type, ids, snapshots) { assert.ok(true, 'Adapter#findMany was called'); assert.deepEqual(ids, ['1','2'], 'Correct ids were passed in to findMany'); - return Ember.RSVP.resolve({ data: [{ id: 1, type: 'test' }, { id: 2, type: 'test' }] }); + return resolve({ data: [{ id: 1, type: 'test' }, { id: 2, type: 'test' }] }); }, coalesceFindRequests: true }); @@ -100,7 +106,7 @@ test('Calling Store#findRecord multiple times coalesces the calls into a adapter }); return run(() => { - return Ember.RSVP.all([ + return all([ store.findRecord('test', 1), store.findRecord('test', 2) ]); @@ -232,7 +238,7 @@ test('loadMany takes an optional Object and passes it on to the Adapter', functi query(store, type, query) { assert.equal(type, store.modelFor('person'), 'The type was Person'); assert.equal(query, passedQuery, 'The query was passed in'); - return Ember.RSVP.resolve({ data: [] }); + return resolve({ data: [] }); } }); @@ -253,7 +259,7 @@ test('Find with query calls the correct normalizeResponse', function(assert) { const Adapter = TestAdapter.extend({ query(store, type, query) { - return Ember.RSVP.resolve([]); + return resolve([]); } }); @@ -652,7 +658,7 @@ test('records should have their ids updated when the adapter returns the id data }); return run(() => { - return Ember.RSVP.all([ + return all([ tom.save(), yehuda.save() ]).then(() => { @@ -695,7 +701,7 @@ test('store._scheduleFetchMany should not resolve until all the records are reso findRecord(store, type, id, snapshot) { let record = { id, type: type.modelName }; - return new Ember.RSVP.Promise(resolve => { + return new EmberPromise(resolve => { run.later(() => resolve({ data: record }), 5); }); }, @@ -703,7 +709,7 @@ test('store._scheduleFetchMany should not resolve until all the records are reso findMany(store, type, ids, snapshots) { let records = ids.map(id => ( { id, type: type.modelName }) ); - return new Ember.RSVP.Promise(resolve => { + return new EmberPromise(resolve => { run.later(() => { resolve({data: records }); }, 15); @@ -727,7 +733,7 @@ test('store._scheduleFetchMany should not resolve until all the records are reso return run(() => { return store._scheduleFetchMany(internalModels).then(() => { - let unloadedRecords = Ember.A(internalModels.map(r => r.getRecord())).filterBy('isEmpty'); + let unloadedRecords = A(internalModels.map(r => r.getRecord())).filterBy('isEmpty'); assert.equal(get(unloadedRecords, 'length'), 0, 'All unloaded records should be loaded'); }); @@ -797,7 +803,7 @@ test('the promise returned by `_scheduleFetch`, when it resolves, does not depen findRecord(store, type, id, snapshot) { let record = { id, type: 'test' }; - return new Ember.RSVP.Promise(function(resolve, reject) { + return new EmberPromise(function(resolve, reject) { if (id === 'igor') { resolve({ data: record }); } else { @@ -828,7 +834,7 @@ test('the promise returned by `_scheduleFetch`, when it resolves, does not depen assert.equal(davidResolved, true, 'David resolved'); })); - return Ember.RSVP.all(wait); + return all(wait); }); }); @@ -849,7 +855,7 @@ test('the promise returned by `_scheduleFetch`, when it rejects, does not depend findRecord(store, type, id, snapshot) { let record = { id, type: 'test' }; - return new Ember.RSVP.Promise((resolve, reject) => { + return new EmberPromise((resolve, reject) => { if (id === 'igor') { reject({ data: record }); } else { @@ -880,7 +886,7 @@ test('the promise returned by `_scheduleFetch`, when it rejects, does not depend assert.equal(davidResolved, true, 'David resolved'); })); - return Ember.RSVP.Promise.all(wait); + return EmberPromise.all(wait); }); }); @@ -912,7 +918,7 @@ testInDebug('store._fetchRecord reject records that were not found, even when th }); }, /expected to find records with the following ids/); - return Ember.RSVP.Promise.all(wait); + return EmberPromise.all(wait); }); testInDebug('store._fetchRecord warns when records are missing', function(assert) { @@ -944,7 +950,7 @@ testInDebug('store._fetchRecord warns when records are missing', function(assert }); }, /expected to find records with the following ids in the adapter response but they were missing/); - return Ember.RSVP.Promise.all(wait).then(() => { + return EmberPromise.all(wait).then(() => { assert.ok(igorDidReject, 'expected rejection that could not be found in the payload, but no such rejection occured'); }); }); diff --git a/tests/unit/store/asserts-test.js b/tests/unit/store/asserts-test.js index 5ebaaa5203c..c84fbb22637 100644 --- a/tests/unit/store/asserts-test.js +++ b/tests/unit/store/asserts-test.js @@ -1,6 +1,6 @@ -import {module} from 'qunit'; +import { module } from 'qunit'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {createStore} from 'dummy/tests/helpers/store'; +import { createStore } from 'dummy/tests/helpers/store'; module('unit/store/asserts - DS.Store methods produce useful assertion messages'); diff --git a/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js index 2d6c4014c81..5fdcc219fa9 100644 --- a/tests/unit/store/create-record-test.js +++ b/tests/unit/store/create-record-test.js @@ -1,11 +1,11 @@ -import {createStore} from 'dummy/tests/helpers/store'; +import { A } from '@ember/array'; +import { run } from '@ember/runloop'; +import { createStore } from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let store, Record, Storage; -const { run } = Ember; module('unit/store/createRecord - Store creating records', { beforeEach() { @@ -65,8 +65,8 @@ test('allow passing relationships as well as attributes', function(assert) { }); assert.equal(storage.get('name'), 'Great store', 'The attribute is well defined'); - assert.equal(storage.get('records').findBy('id', '1'), Ember.A(records).findBy('id', '1'), 'Defined relationships are allowed in createRecord'); - assert.equal(storage.get('records').findBy('id', '2'), Ember.A(records).findBy('id', '2'), 'Defined relationships are allowed in createRecord'); + assert.equal(storage.get('records').findBy('id', '1'), A(records).findBy('id', '1'), 'Defined relationships are allowed in createRecord'); + assert.equal(storage.get('records').findBy('id', '2'), A(records).findBy('id', '2'), 'Defined relationships are allowed in createRecord'); }); module('unit/store/createRecord - Store with models by dash', { diff --git a/tests/unit/store/finders-test.js b/tests/unit/store/finders-test.js index b6d724d305d..9ee8ee9b859 100644 --- a/tests/unit/store/finders-test.js +++ b/tests/unit/store/finders-test.js @@ -1,10 +1,8 @@ +import { defer } from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; - -const { run } = Ember; -const { defer } = Ember.RSVP; +import { module, test } from 'qunit'; import DS from 'ember-data'; diff --git a/tests/unit/store/has-model-for-test.js b/tests/unit/store/has-model-for-test.js index 0cd5dd127a5..0fa53f5a2cd 100644 --- a/tests/unit/store/has-model-for-test.js +++ b/tests/unit/store/has-model-for-test.js @@ -1,5 +1,5 @@ -import {createStore} from 'dummy/tests/helpers/store'; -import {module, test} from 'qunit'; +import { createStore } from 'dummy/tests/helpers/store'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let store; diff --git a/tests/unit/store/has-record-for-id-test.js b/tests/unit/store/has-record-for-id-test.js index 4d288bf5ae1..3aab6feb164 100644 --- a/tests/unit/store/has-record-for-id-test.js +++ b/tests/unit/store/has-record-for-id-test.js @@ -1,13 +1,12 @@ +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let env, store, Person, PhoneNumber; const { attr, hasMany, belongsTo } = DS; -const { run } = Ember; module('unit/store/hasRecordForId - Store hasRecordForId', { beforeEach() { @@ -33,7 +32,7 @@ module('unit/store/hasRecordForId - Store hasRecordForId', { }, afterEach() { - Ember.run(store, 'destroy'); + run(store, 'destroy'); } }); diff --git a/tests/unit/store/lookup-test.js b/tests/unit/store/lookup-test.js index b5e7a450ce5..86a210d279e 100644 --- a/tests/unit/store/lookup-test.js +++ b/tests/unit/store/lookup-test.js @@ -1,12 +1,11 @@ +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let store, env, applicationAdapter, applicationSerializer, Person; -const { run } = Ember; function resetStore() { if (store) { diff --git a/tests/unit/store/model-for-test.js b/tests/unit/store/model-for-test.js index 6b337200da1..0c74eeaeb2c 100644 --- a/tests/unit/store/model-for-test.js +++ b/tests/unit/store/model-for-test.js @@ -1,15 +1,13 @@ +import { run } from '@ember/runloop'; +import { dasherize, camelize } from '@ember/string'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let container, store, registry, env; -const { camelize, dasherize } = Ember.String; -const { run } = Ember; - module('unit/store/model_for - DS.Store#modelFor', { beforeEach() { env = setupStore({ diff --git a/tests/unit/store/peek-record-test.js b/tests/unit/store/peek-record-test.js index 490ee94fe00..1d5ec9433f5 100644 --- a/tests/unit/store/peek-record-test.js +++ b/tests/unit/store/peek-record-test.js @@ -1,12 +1,11 @@ +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let env, store, Person; -const { run } = Ember; module('unit/store/peekRecord - Store peekRecord', { beforeEach() { @@ -20,7 +19,7 @@ module('unit/store/peekRecord - Store peekRecord', { }, afterEach() { - Ember.run(store, 'destroy'); + run(store, 'destroy'); } }); diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index e884f3627c0..a579dd8e7cb 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -1,8 +1,12 @@ +import { inspect } from '@ember/debug'; +import EmberObject from '@ember/object'; +import { Promise as EmberPromise, resolve } from 'rsvp'; +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; @@ -10,7 +14,6 @@ import { isEnabled } from 'ember-data/-private'; let env, store, Person, PhoneNumber, Post; const { attr, hasMany, belongsTo } = DS; -const { run } = Ember; module('unit/store/push - DS.Store#push', { beforeEach() { @@ -144,7 +147,7 @@ test('Supplying a model class for `push` is the same as supplying a string', fun test(`Calling push triggers 'didLoad' even if the record hasn't been requested from the adapter`, function(assert) { assert.expect(1); - let didLoad = new Ember.RSVP.Promise((resolve, reject) => { + let didLoad = new EmberPromise((resolve, reject) => { Person.reopen({ didLoad() { try { @@ -250,7 +253,7 @@ test('Calling push with a normalized hash containing IDs of related records retu env.adapter.findRecord = function(store, type, id) { if (id === '1') { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: 'phone-number', @@ -265,7 +268,7 @@ test('Calling push with a normalized hash containing IDs of related records retu } if (id === "2") { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 2, type: 'phone-number', @@ -505,8 +508,8 @@ test('calling push without data argument as an object raises an error', function null, 1, 'string', - Ember.Object.create(), - Ember.Object.extend(), + EmberObject.create(), + EmberObject.extend(), true ]; @@ -638,8 +641,8 @@ testInDebug('calling push with hasMany relationship the value must be an array', let invalidValues = [ 1, 'string', - Ember.Object.create(), - Ember.Object.extend(), + EmberObject.create(), + EmberObject.extend(), true ]; @@ -665,7 +668,7 @@ testInDebug('calling push with hasMany relationship the value must be an array', store._pushedInternalModels.length = 0; throw e; } - }, /must be an array/, `Expect that '${Ember.inspect(invalidValue)}' is not an array`); + }, /must be an array/, `Expect that '${inspect(invalidValue)}' is not an array`); }); }); diff --git a/tests/unit/store/serialize-test.js b/tests/unit/store/serialize-test.js index 1967d7ac5ac..d92f3b5f488 100644 --- a/tests/unit/store/serialize-test.js +++ b/tests/unit/store/serialize-test.js @@ -1,13 +1,11 @@ +import { run } from '@ember/runloop'; import { module } from 'qunit'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import attr from 'ember-data/attr'; import Model from 'ember-data/model'; import { createStore } from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import { isEnabled } from 'ember-data/-private'; -const { run } = Ember; - if (isEnabled('ds-deprecate-store-serialize')) { module("unit/store/serialize - DS.Store#serialize"); diff --git a/tests/unit/store/serializer-for-test.js b/tests/unit/store/serializer-for-test.js index 6206ffd4b8c..0bebe7a918a 100644 --- a/tests/unit/store/serializer-for-test.js +++ b/tests/unit/store/serializer-for-test.js @@ -1,13 +1,12 @@ +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; let container, store, registry, Person; -const { run } = Ember; module('unit/store/serializer_for - DS.Store#serializerFor', { beforeEach() { diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index f0bfe1240a0..98d88e3f3e0 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -1,12 +1,13 @@ -import {createStore} from 'dummy/tests/helpers/store'; -import Ember from 'ember'; +import { resolve } from 'rsvp'; +import { get } from '@ember/object'; +import { run } from '@ember/runloop'; +import { createStore } from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; -const { get, run } = Ember; let store, tryToFind, Record; module('unit/store/unload - Store unloading records', { @@ -27,7 +28,7 @@ module('unit/store/unload - Store unloading records', { adapter: DS.Adapter.extend({ findRecord(store, type, id, snapshot) { tryToFind = true; - return Ember.RSVP.resolve({ data: { id, type: snapshot.modelName, attributes: { 'was-fetched': true } } }); + return resolve({ data: { id, type: snapshot.modelName, attributes: { 'was-fetched': true } } }); } }), @@ -36,7 +37,7 @@ module('unit/store/unload - Store unloading records', { }, afterEach() { - Ember.run(store, 'destroy'); + run(store, 'destroy'); } }); @@ -155,7 +156,7 @@ test('can commit store after unload record with relationships', function(assert) let store = createStore({ adapter: DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return Ember.RSVP.resolve({ + return resolve({ data: { id: 1, type: snapshot.modelName, @@ -168,7 +169,7 @@ test('can commit store after unload record with relationships', function(assert) }, createRecord(store, type, snapshot) { - return Ember.RSVP.resolve(); + return resolve(); } }), brand: Brand, @@ -206,7 +207,7 @@ test('can commit store after unload record with relationships', function(assert) return like.save(); }).then(() => { // TODO: this is strange, future travelers please address - Ember.run(() => store.unloadRecord(store.peekRecord('product', 1))); + run(() => store.unloadRecord(store.peekRecord('product', 1))); }).then(() => { return store.findRecord('product', 1); }).then(product => { diff --git a/tests/unit/system/relationships/relationship-payload-manager-test.js b/tests/unit/system/relationships/relationship-payload-manager-test.js index 8aa78aafa21..9ade62feb01 100644 --- a/tests/unit/system/relationships/relationship-payload-manager-test.js +++ b/tests/unit/system/relationships/relationship-payload-manager-test.js @@ -1,10 +1,8 @@ -import Ember from 'ember'; +import { get } from '@ember/object'; import { RelationshipPayloadsManager } from 'ember-data/-private'; import DS from 'ember-data'; -import {createStore} from 'dummy/tests/helpers/store'; -import {module, test} from 'qunit'; - -const { get } = Ember; +import { createStore } from 'dummy/tests/helpers/store'; +import { module, test } from 'qunit'; module('unit/system/relationships/relationship-payloads-manager', { beforeEach() { diff --git a/tests/unit/system/relationships/relationship-payloads-test.js b/tests/unit/system/relationships/relationship-payloads-test.js index 2ee7e9fb939..6f7715760d0 100644 --- a/tests/unit/system/relationships/relationship-payloads-test.js +++ b/tests/unit/system/relationships/relationship-payloads-test.js @@ -1,12 +1,10 @@ -import Ember from 'ember'; +import { get } from '@ember/object'; import { RelationshipPayloadsManager } from 'ember-data/-private'; import DS from 'ember-data'; -import {createStore} from 'dummy/tests/helpers/store'; -import {module, test} from 'qunit'; +import { createStore } from 'dummy/tests/helpers/store'; +import { module, test } from 'qunit'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -const { get } = Ember; - module('unit/system/relationships/relationship-payloads', { beforeEach() { const User = DS.Model.extend({ diff --git a/tests/unit/system/snapshot-record-array-test.js b/tests/unit/system/snapshot-record-array-test.js index c33fb225aea..7c8221a428c 100644 --- a/tests/unit/system/snapshot-record-array-test.js +++ b/tests/unit/system/snapshot-record-array-test.js @@ -1,11 +1,11 @@ +import { A } from '@ember/array'; import { SnapshotRecordArray } from 'ember-data/-private'; -import Ember from 'ember'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; module('Unit - snapshot-record-array'); test('constructor', function(assert) { - let array = Ember.A([1, 2]); + let array = A([1, 2]); array.type = 'some type'; let meta = { }; let options = { @@ -23,7 +23,7 @@ test('constructor', function(assert) { }); test('#snapshot', function(assert) { - let array = Ember.A([1, 2]); + let array = A([1, 2]); let didTakeSnapshot = 0; let snapshotTaken = {}; @@ -49,7 +49,7 @@ test('#snapshot', function(assert) { }); test('SnapshotRecordArray.type loads the class lazily', function(assert) { - let array = Ember.A([1, 2]); + let array = A([1, 2]); let typeLoaded = false; Object.defineProperty(array, 'type', { diff --git a/tests/unit/transform/boolean-test.js b/tests/unit/transform/boolean-test.js index 4c2ae3c5b40..02bd4ae73c1 100644 --- a/tests/unit/transform/boolean-test.js +++ b/tests/unit/transform/boolean-test.js @@ -1,6 +1,6 @@ import DS from 'ember-data'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; module('unit/transform - DS.BooleanTransform'); diff --git a/tests/unit/transform/date-test.js b/tests/unit/transform/date-test.js index 46746ced520..330c8ec2469 100644 --- a/tests/unit/transform/date-test.js +++ b/tests/unit/transform/date-test.js @@ -1,4 +1,4 @@ -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; import Ember from 'ember'; diff --git a/tests/unit/transform/number-test.js b/tests/unit/transform/number-test.js index 17d3e47d381..c8a3aba2a7e 100644 --- a/tests/unit/transform/number-test.js +++ b/tests/unit/transform/number-test.js @@ -1,6 +1,6 @@ import DS from 'ember-data'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; module('unit/transform - DS.NumberTransform'); diff --git a/tests/unit/transform/string-test.js b/tests/unit/transform/string-test.js index 713d97f7f64..8aa87545101 100644 --- a/tests/unit/transform/string-test.js +++ b/tests/unit/transform/string-test.js @@ -1,6 +1,6 @@ import DS from 'ember-data'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; module('unit/transform - DS.StringTransform'); diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index 4bf54576bec..573796df4b3 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -1,14 +1,17 @@ +import { run } from '@ember/runloop'; +import Mixin from '@ember/object/mixin'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import {module, test} from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; import Model from 'ember-data/model'; import { assertPolymorphicType } from 'ember-data/-debug'; -import { modelHasAttributeOrRelationshipNamedType } from 'ember-data/-private'; +import { + modelHasAttributeOrRelationshipNamedType +} from 'ember-data/-private'; let env, User, Message, Post, Person, Video, Medium; @@ -24,7 +27,7 @@ module('unit/utils', { medias: DS.hasMany('medium', { async: false }) }); - Medium = Ember.Mixin.create(); + Medium = Mixin.create(); Video = Model.extend(Medium); env = setupStore({ @@ -39,14 +42,14 @@ module('unit/utils', { }, afterEach() { - Ember.run(env.container, 'destroy'); + run(env.container, 'destroy'); } }); testInDebug('assertPolymorphicType works for subclasses', function(assert) { let user, post, person; - Ember.run(() => { + run(() => { env.store.push({ data: [{ type: 'user', @@ -107,7 +110,7 @@ test('modelHasAttributeOrRelationshipNamedType', function(assert) { testInDebug('assertPolymorphicType works for mixins', function(assert) { let post, video, person; - Ember.run(() => { + run(() => { env.store.push({ data: [{ type: 'post', diff --git a/yarn.lock b/yarn.lock index 3599607fed9..20c201b645f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -43,7 +43,7 @@ accepts@1.3.3: mime-types "~2.1.11" negotiator "0.6.1" -accepts@~1.3.3: +accepts@~1.3.3, accepts@~1.3.4: version "1.3.4" resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" dependencies: @@ -104,6 +104,12 @@ alter@~0.2.0: dependencies: stable "~0.1.3" +amd-name-resolver@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-0.0.6.tgz#d3e4ba2dfcaab1d820c1be9de947c67828cfe595" + dependencies: + ensure-posix-path "^1.0.1" + amd-name-resolver@0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.7.tgz#814301adfe8a2f109f6e84d5e935196efb669615" @@ -525,10 +531,16 @@ babel-plugin-dead-code-elimination@^1.0.2: babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.11, babel-plugin-debug-macros@^0.1.7: version "0.1.11" - resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" + resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" dependencies: semver "^5.3.0" +babel-plugin-ember-modules-api-polyfill@^1.4.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-1.6.0.tgz#abd1afa4237b3121cb51222f9bf3283cad8990aa" + dependencies: + ember-rfc176-data "^0.2.0" + babel-plugin-ember-modules-api-polyfill@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.0.1.tgz#baaf26dcebe2ed1de120021bc42be29f520497b3" @@ -965,6 +977,12 @@ basic-auth@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" +basic-auth@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.0.tgz#015db3f353e02e56377755f962742e8981e7bbba" + dependencies: + safe-buffer "5.1.1" + better-assert@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" @@ -991,6 +1009,21 @@ bluebird@^3.1.1, bluebird@^3.4.6: version "3.5.0" resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" +body-parser@1.18.2: + version "1.18.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" + dependencies: + 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" + body-parser@^1.15.2: version "1.18.1" resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.18.1.tgz#9c1629370bcfd42917f30641a2dcbe2ec50d4c26" @@ -2024,6 +2057,12 @@ debug@2.3.3: dependencies: ms "0.7.2" +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2178,7 +2217,23 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-c ember-cli-version-checker "^1.0.2" resolve "^1.1.2" -ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.4.1, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1: +ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.7: + version "6.5.1" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.5.1.tgz#37eaab592523938f8d52fc9d30bd0f56fc1c6599" + dependencies: + amd-name-resolver "0.0.6" + babel-plugin-debug-macros "^0.1.10" + babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-polyfill "^6.16.0" + babel-preset-env "^1.5.1" + broccoli-babel-transpiler "^6.0.0" + broccoli-debug "^0.6.2" + broccoli-funnel "^1.0.0" + broccoli-source "^1.1.0" + clone "^2.0.0" + ember-cli-version-checker "^2.0.0" + +ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1: version "6.8.2" resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.8.2.tgz#eac2785964f4743f4c815cd53c6288f00cc087d7" dependencies: @@ -2195,6 +2250,23 @@ ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.4.1, e clone "^2.0.0" ember-cli-version-checker "^2.0.0" +ember-cli-babel@^6.8.2: + version "6.8.2" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.8.2.tgz#eac2785964f4743f4c815cd53c6288f00cc087d7" + dependencies: + amd-name-resolver "0.0.7" + babel-plugin-debug-macros "^0.1.11" + babel-plugin-ember-modules-api-polyfill "^2.0.1" + babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-polyfill "^6.16.0" + babel-preset-env "^1.5.1" + broccoli-babel-transpiler "^6.1.2" + broccoli-debug "^0.6.2" + broccoli-funnel "^1.0.0" + broccoli-source "^1.1.0" + clone "^2.0.0" + ember-cli-version-checker "^2.0.0" + ember-cli-blueprint-test-helpers@0.11.0: version "0.11.0" resolved "https://registry.npmjs.org/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" @@ -2578,9 +2650,9 @@ ember-resolver@^4.1.0: ember-cli-version-checker "^2.0.0" resolve "^1.3.3" -ember-rfc176-data@^0.2.7: +ember-rfc176-data@^0.2.0, ember-rfc176-data@^0.2.7: version "0.2.7" - resolved "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.2.7.tgz#bd355bc9b473e08096b518784170a23388bc973b" + resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.2.7.tgz#bd355bc9b473e08096b518784170a23388bc973b" ember-router-generator@^1.0.0: version "1.2.3" @@ -2893,7 +2965,7 @@ esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" -etag@~1.8.0: +etag@~1.8.0, etag@~1.8.1: version "1.8.1" resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" @@ -2968,7 +3040,7 @@ expand-tilde@^1.2.2: dependencies: os-homedir "^1.0.1" -express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: +express@^4.10.7, express@^4.12.3, express@^4.13.1: version "4.15.4" resolved "https://registry.npmjs.org/express/-/express-4.15.4.tgz#032e2253489cf8fce02666beca3d11ed7a2daed1" dependencies: @@ -3001,6 +3073,41 @@ express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: utils-merge "1.0.0" vary "~1.1.1" +express@^4.14.0: + version "4.16.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.1.tgz#6b33b560183c9b253b7b62144df33a4654ac9ed0" + dependencies: + accepts "~1.3.4" + array-flatten "1.1.1" + body-parser "1.18.2" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.1" + encodeurl "~1.0.1" + escape-html "~1.0.3" + 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.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.2" + qs "6.5.1" + range-parser "~1.2.0" + 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.1" + vary "~1.1.2" + extend@3, extend@^3.0.0, extend@~3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" @@ -3107,6 +3214,18 @@ finalhandler@1.0.4, finalhandler@~1.0.4: statuses "~1.3.1" unpipe "~1.0.0" +finalhandler@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" + dependencies: + 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" + find-index@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" @@ -3207,10 +3326,18 @@ forwarded@~0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.1.tgz#8a4e30c640b05395399a3549c730257728048961" +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + fresh@0.5.0: version "0.5.0" resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + fs-exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" @@ -3762,6 +3889,10 @@ ipaddr.js@1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0" +ipaddr.js@1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.5.2.tgz#d4b505bde9946987ccf0fc58d9010ff9607e3fa0" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -4638,6 +4769,10 @@ mime@1.3.4: version "1.3.4" resolved "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + mime@^1.2.11: version "1.4.0" resolved "https://registry.npmjs.org/mime/-/mime-1.4.0.tgz#69e9e0db51d44f2a3b56e48b7817d7d137f1a343" @@ -4719,7 +4854,17 @@ moment-timezone@^0.3.0: version "2.18.1" resolved "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" -morgan@^1.7.0, morgan@^1.8.1: +morgan@^1.7.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.0.tgz#d01fa6c65859b76fcf31b3cb53a3821a311d8051" + dependencies: + basic-auth "~2.0.0" + debug "2.6.9" + depd "~1.1.1" + on-finished "~2.3.0" + on-headers "~1.0.1" + +morgan@^1.8.1: version "1.8.2" resolved "https://registry.npmjs.org/morgan/-/morgan-1.8.2.tgz#784ac7734e4a453a9c6e6e8680a9329275c8b687" dependencies: @@ -5002,7 +5147,7 @@ parseuri@0.0.5: dependencies: better-assert "~1.0.0" -parseurl@~1.3.1: +parseurl@~1.3.1, parseurl@~1.3.2: version "1.3.2" resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" @@ -5132,6 +5277,13 @@ proxy-addr@~1.1.5: forwarded "~0.1.0" ipaddr.js "1.4.0" +proxy-addr@~2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec" + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.5.2" + pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -5581,6 +5733,24 @@ send@0.15.4: range-parser "~1.2.0" statuses "~1.3.1" +send@0.16.1: + version "0.16.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" + dependencies: + debug "2.6.9" + depd "~1.1.1" + destroy "~1.0.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.3.1" + serve-static@1.12.4: version "1.12.4" resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.12.4.tgz#9b6aa98eeb7253c4eedc4c1f6fdbca609901a961" @@ -5590,6 +5760,15 @@ serve-static@1.12.4: parseurl "~1.3.1" send "0.15.4" +serve-static@1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.1.tgz#4c57d53404a761d8f2e7c1e8a18a47dbf278a719" + dependencies: + encodeurl "~1.0.1" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.1" + set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -5598,6 +5777,10 @@ setprototypeof@1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -6183,6 +6366,10 @@ utils-merge@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + uuid@3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" @@ -6212,6 +6399,10 @@ vary@~1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + walk-sync@^0.1.3: version "0.1.3" resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" From 5d57a70dbc33d235037697cb6fd23a3d58a5bdf2 Mon Sep 17 00:00:00 2001 From: pangratz Date: Mon, 9 Oct 2017 22:11:25 +0300 Subject: [PATCH 2046/2527] [BUGFIX beta] invalid record becomes loaded when property is reset --- addon/-private/system/model/states.js | 7 +++ tests/unit/model-test.js | 77 +++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index 4977133fefc..66bbc1093eb 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -434,6 +434,13 @@ function assertAgainstUnloadRecord(internalModel) { assert("You can only unload a record which is not inFlight. `" + internalModel + "`", false); } +updatedState.invalid.becameValid = function(internalModel) { + // we're eagerly transition into the loaded.saved state, even though we could + // be still dirty; but the setup hook of the loaded.saved state checks for + // dirty attributes and transitions into the corresponding dirty state + internalModel.transitionTo('loaded.saved'); +}; + updatedState.inFlight.unloadRecord = assertAgainstUnloadRecord; updatedState.uncommitted.deleteRecord = function(internalModel) { diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index d54ca482193..fa4a70938f6 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -161,6 +161,83 @@ test('a record becomes clean again only if all changed properties are reset', fu }); }); +test('an invalid record becomes clean again if changed property is reset', function(assert) { + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.updateRecord = () => { + var error = new DS.InvalidError([{ name: 'not valid' }]); + + return EmberPromise.reject(error); + }; + + return run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Peter', + isDrugAddict: true + } + } + }); + + let person = store.peekRecord('person', 1); + + assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); + person.set('name', 'Wolf'); + assert.equal(person.get('hasDirtyAttributes'), true, 'record becomes dirty after setting one property to a new value'); + + return person.save().catch(() => { + assert.equal(person.get('isValid'), false, 'record is not valid'); + assert.equal(person.get('hasDirtyAttributes'), true, 'record still has dirty attributes'); + + person.set('name', 'Peter'); + + assert.equal(person.get('isValid'), true, 'record is valid after resetting attribute to old value'); + assert.equal(person.get('hasDirtyAttributes'), false, "record becomes clean after resetting property to the old value"); + }); + }); +}); + +test('an invalid record stays dirty if only invalid property is reset', function(assert) { + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.updateRecord = () => { + var error = new DS.InvalidError([{ name: 'not valid' }]); + + return EmberPromise.reject(error); + }; + + return run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Peter', + isDrugAddict: true + } + } + }); + + let person = store.peekRecord('person', 1); + + assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); + person.set('name', 'Wolf'); + person.set('isDrugAddict', false); + assert.equal(person.get('hasDirtyAttributes'), true, 'record becomes dirty after setting one property to a new value'); + + return person.save().catch(() => { + assert.equal(person.get('isValid'), false, 'record is not valid'); + assert.equal(person.get('hasDirtyAttributes'), true, 'record still has dirty attributes'); + + person.set('name', 'Peter'); + + assert.equal(person.get('isValid'), true, 'record is valid after resetting invalid attribute to old value'); + assert.equal(person.get('hasDirtyAttributes'), true, "record still has dirty attributes"); + }); + }); +}); + test('a record reports its unique id via the `id` property', function(assert) { assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; From 8c787b5f5fa4008db6b72dbe72da8e939a869e8e Mon Sep 17 00:00:00 2001 From: Andrey Khomenko Date: Mon, 9 Oct 2017 21:50:26 -0400 Subject: [PATCH 2047/2527] [BUGFIX beta] RecordReference returns null when not yet loaded --- addon/-private/system/references/record.js | 1 + tests/integration/references/record-test.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/references/record.js b/addon/-private/system/references/record.js index bace8a75d6d..9a4cbf43c83 100644 --- a/addon/-private/system/references/record.js +++ b/addon/-private/system/references/record.js @@ -115,6 +115,7 @@ RecordReference.prototype.value = function() { if (this.internalModel.hasRecord) { return this.internalModel.getRecord(); } + return null; }; /** diff --git a/tests/integration/references/record-test.js b/tests/integration/references/record-test.js index 553fd0d4116..3701206cebd 100644 --- a/tests/integration/references/record-test.js +++ b/tests/integration/references/record-test.js @@ -99,7 +99,7 @@ test("push(promise)", function(assert) { test("value() returns null when not yet loaded", function(assert) { var recordReference = env.store.getReference('person', 1); - assert.equal(recordReference.value(), null); + assert.strictEqual(recordReference.value(), null); }); test("value() returns the record when loaded", function(assert) { From 1071c9e1cac3d28662d97ce762cb2fe91144d749 Mon Sep 17 00:00:00 2001 From: Kevin Pfefferle Date: Tue, 10 Oct 2017 10:38:03 -0400 Subject: [PATCH 2048/2527] Remove ember-inflector peer dependency --- package.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/package.json b/package.json index 844a8fe28f5..9ba4565e983 100644 --- a/package.json +++ b/package.json @@ -111,9 +111,6 @@ "rimraf": "2.5.2", "rsvp": "4.7.0" }, - "peerDependencies": { - "ember-inflector": "^2.0.0" - }, "engines": { "node": ">= 4.0.0" }, From 5b4ba0064513029f3a352a296301311c82675671 Mon Sep 17 00:00:00 2001 From: Luke Date: Wed, 11 Oct 2017 17:14:26 -0700 Subject: [PATCH 2049/2527] Fix docs link. (#5221) When rendered, this links to https://www.emberjs.com/api/ember-data/2.15/classes/DS.JSONSerializer.html - which 404's. Correct link doesn't have the `.html`. --- addon/serializer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/serializer.js b/addon/serializer.js index ebf99eaba7a..67f1daf2085 100644 --- a/addon/serializer.js +++ b/addon/serializer.js @@ -17,7 +17,7 @@ import EmberObject from '@ember/object'; * `normalize()` For an example implementation, see - [DS.JSONSerializer](DS.JSONSerializer.html), the included JSON serializer. + [DS.JSONSerializer](DS.JSONSerializer), the included JSON serializer. @class Serializer @namespace DS From c53b4e682b5aacb54d6b714e22a918b51426c2c3 Mon Sep 17 00:00:00 2001 From: bmac Date: Wed, 11 Oct 2017 21:33:39 -0400 Subject: [PATCH 2050/2527] Add missing dependency for travis build --- package.json | 3 +- yarn.lock | 2592 ++++++++++++++++++++++++-------------------------- 2 files changed, 1271 insertions(+), 1324 deletions(-) diff --git a/package.json b/package.json index 844a8fe28f5..d726784a2e6 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,8 @@ "mocha-only-detector": "0.0.2", "morgan": "^1.7.0", "rimraf": "2.5.2", - "rsvp": "4.7.0" + "rsvp": "4.7.0", + "testdouble": "^3.2.6" }, "peerDependencies": { "ember-inflector": "^2.0.0" diff --git a/yarn.lock b/yarn.lock index 20c201b645f..f7728b4c498 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4,95 +4,99 @@ "@glimmer/di@^0.2.0": version "0.2.0" - resolved "https://registry.npmjs.org/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" + resolved "https://registry.yarnpkg.com/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" "@glimmer/resolver@^0.4.1": version "0.4.1" - resolved "https://registry.npmjs.org/@glimmer/resolver/-/resolver-0.4.1.tgz#cd9644572c556e7e799de1cf8eff2b999cf5b878" + resolved "https://registry.yarnpkg.com/@glimmer/resolver/-/resolver-0.4.1.tgz#cd9644572c556e7e799de1cf8eff2b999cf5b878" dependencies: "@glimmer/di" "^0.2.0" -"@types/node@*", "@types/node@^7.0.5": +"@types/node@*": + version "8.0.34" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.34.tgz#55f801fa2ddb2a40dd6dfc15ecfe1dde9c129fe9" + +"@types/node@^7.0.5": version "7.0.43" - resolved "https://registry.npmjs.org/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c" + resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c" "@types/rimraf@^0.0.28": version "0.0.28" - resolved "https://registry.npmjs.org/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06" + resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06" "@types/tape@^4.2.29": version "4.2.30" - resolved "https://registry.npmjs.org/@types/tape/-/tape-4.2.30.tgz#3c1917c4dfd6f27271b9922772513515bc6c46b4" + resolved "https://registry.yarnpkg.com/@types/tape/-/tape-4.2.30.tgz#3c1917c4dfd6f27271b9922772513515bc6c46b4" dependencies: "@types/node" "*" "@types/ws@^0.0.38": version "0.0.38" - resolved "https://registry.npmjs.org/@types/ws/-/ws-0.0.38.tgz#42106fff4b422ca956734e29f0d73a6d893194d3" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-0.0.38.tgz#42106fff4b422ca956734e29f0d73a6d893194d3" dependencies: "@types/node" "*" abbrev@1: - version "1.1.0" - resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" accepts@1.3.3: version "1.3.3" - resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" dependencies: mime-types "~2.1.11" negotiator "0.6.1" -accepts@~1.3.3, accepts@~1.3.4: +accepts@~1.3.4: version "1.3.4" - resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" dependencies: mime-types "~2.1.16" negotiator "0.6.1" acorn-jsx@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" dependencies: acorn "^3.0.4" acorn@^3.0.4: version "3.3.0" - resolved "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" acorn@^4.0.3: version "4.0.13" - resolved "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" acorn@^5.1.1: version "5.1.2" - resolved "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" after@0.8.1: version "0.8.1" - resolved "https://registry.npmjs.org/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" agent-base@2: version "2.1.1" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" dependencies: extend "~3.0.0" semver "~5.0.1" ajv-keywords@^1.0.0: version "1.5.1" - resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" ajv@^4.1.3, ajv@^4.7.0: version "4.11.8" - resolved "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" dependencies: co "^4.6.0" json-stable-stringify "^1.0.1" align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" - resolved "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" dependencies: kind-of "^3.0.2" longest "^1.0.1" @@ -100,165 +104,169 @@ align-text@^0.1.1, align-text@^0.1.3: alter@~0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" + resolved "https://registry.yarnpkg.com/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" dependencies: stable "~0.1.3" -amd-name-resolver@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-0.0.6.tgz#d3e4ba2dfcaab1d820c1be9de947c67828cfe595" +amd-name-resolver@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-0.0.7.tgz#814301adfe8a2f109f6e84d5e935196efb669615" dependencies: ensure-posix-path "^1.0.1" -amd-name-resolver@0.0.7: - version "0.0.7" - resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.7.tgz#814301adfe8a2f109f6e84d5e935196efb669615" +amd-name-resolver@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-1.0.0.tgz#0e593b28d6fa3326ab1798107edaea961046e8d8" dependencies: ensure-posix-path "^1.0.1" amdefine@>=0.0.4: version "1.0.1" - resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" ansi-escapes@^1.1.0: version "1.4.0" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-escapes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" ansi-regex@^2.0.0: version "2.1.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" ansi-regex@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" ansi-styles@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" ansi-styles@^2.2.1: version "2.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" ansi-styles@^3.0.0, ansi-styles@^3.1.0: version "3.2.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" dependencies: color-convert "^1.9.0" ansicolors@~0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" anymatch@^1.3.0: version "1.3.2" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" dependencies: micromatch "^2.1.5" normalize-path "^2.0.0" aproba@^1.0.3: - version "1.1.2" - resolved "https://registry.npmjs.org/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" are-we-there-yet@~1.1.2: version "1.1.4" - resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" dependencies: delegates "^1.0.0" readable-stream "^2.0.6" argparse@^1.0.7, argparse@~1.0.2: version "1.0.9" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" dependencies: sprintf-js "~1.0.2" arr-diff@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" dependencies: arr-flatten "^1.0.1" arr-flatten@^1.0.1: version "1.1.0" - resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" array-equal@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" array-flatten@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" array-to-error@^1.0.0: version "1.1.1" - resolved "https://registry.npmjs.org/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" + resolved "https://registry.yarnpkg.com/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" dependencies: array-to-sentence "^1.1.0" array-to-sentence@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" + resolved "https://registry.yarnpkg.com/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" array-union@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" dependencies: array-uniq "^1.0.1" array-uniq@^1.0.1: version "1.0.3" - resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" array-unique@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" arraybuffer.slice@0.0.6: version "0.0.6" - resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" arrify@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" asn1@0.1.11: version "0.1.11" - resolved "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" assert-plus@^0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" assertion-error@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" ast-traverse@~0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" + resolved "https://registry.yarnpkg.com/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" ast-types@0.8.12: version "0.8.12" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" ast-types@0.8.15: version "0.8.15" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" ast-types@0.9.6: version "0.9.6" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" async-disk-cache@^1.2.1: - version "1.3.2" - resolved "https://registry.npmjs.org/async-disk-cache/-/async-disk-cache-1.3.2.tgz#ac53d6152843df202c9406e28d774362608d74dd" + version "1.3.3" + resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.3.3.tgz#6040486660b370e4051cd9fa9fee275e1fae3728" dependencies: debug "^2.1.3" heimdalljs "^0.2.3" @@ -270,32 +278,32 @@ async-disk-cache@^1.2.1: async-promise-queue@^1.0.3: version "1.0.4" - resolved "https://registry.npmjs.org/async-promise-queue/-/async-promise-queue-1.0.4.tgz#308baafbc74aff66a0bb6e7f4a18d4fe8434440c" + resolved "https://registry.yarnpkg.com/async-promise-queue/-/async-promise-queue-1.0.4.tgz#308baafbc74aff66a0bb6e7f4a18d4fe8434440c" dependencies: async "^2.4.1" debug "^2.6.8" async@^1.4.0, async@^1.5.2: version "1.5.2" - resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" async@^2.4.1: version "2.5.0" - resolved "https://registry.npmjs.org/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" + resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" dependencies: lodash "^4.14.0" async@~0.2.9: version "0.2.10" - resolved "https://registry.npmjs.org/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" async@~0.9.0: version "0.9.2" - resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" aws-sdk@^2.0.9: - version "2.115.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.115.0.tgz#8373d7636cc412a04c333b27b1d211f478f276fa" + version "2.132.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.132.0.tgz#6ece84bf355a6626fc8ba24023809c08ca1ee372" dependencies: buffer "4.9.1" crypto-browserify "1.0.9" @@ -304,17 +312,17 @@ aws-sdk@^2.0.9: querystring "0.2.0" sax "1.2.1" url "0.10.3" - uuid "3.0.1" + uuid "3.1.0" xml2js "0.4.17" xmlbuilder "4.2.1" aws-sign2@~0.5.0: version "0.5.0" - resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" babel-code-frame@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: chalk "^1.1.3" esutils "^2.0.2" @@ -322,7 +330,7 @@ babel-code-frame@^6.26.0: babel-core@^5.0.0, babel-core@^5.8.22: version "5.8.38" - resolved "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" dependencies: babel-plugin-constant-folding "^1.0.1" babel-plugin-dead-code-elimination "^1.0.2" @@ -373,7 +381,7 @@ babel-core@^5.0.0, babel-core@^5.8.22: babel-core@^6.14.0, babel-core@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" dependencies: babel-code-frame "^6.26.0" babel-generator "^6.26.0" @@ -397,7 +405,7 @@ babel-core@^6.14.0, babel-core@^6.26.0: babel-generator@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5" dependencies: babel-messages "^6.23.0" babel-runtime "^6.26.0" @@ -410,7 +418,7 @@ babel-generator@^6.26.0: babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" dependencies: babel-helper-explode-assignable-expression "^6.24.1" babel-runtime "^6.22.0" @@ -418,7 +426,7 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: babel-helper-call-delegate@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" dependencies: babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" @@ -427,7 +435,7 @@ babel-helper-call-delegate@^6.24.1: babel-helper-define-map@^6.24.1: version "6.26.0" - resolved "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.26.0" @@ -436,7 +444,7 @@ babel-helper-define-map@^6.24.1: babel-helper-explode-assignable-expression@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" dependencies: babel-runtime "^6.22.0" babel-traverse "^6.24.1" @@ -444,7 +452,7 @@ babel-helper-explode-assignable-expression@^6.24.1: babel-helper-function-name@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" dependencies: babel-helper-get-function-arity "^6.24.1" babel-runtime "^6.22.0" @@ -454,28 +462,28 @@ babel-helper-function-name@^6.24.1: babel-helper-get-function-arity@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-helper-hoist-variables@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-helper-optimise-call-expression@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-helper-regex@^6.24.1: version "6.26.0" - resolved "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" dependencies: babel-runtime "^6.26.0" babel-types "^6.26.0" @@ -483,7 +491,7 @@ babel-helper-regex@^6.24.1: babel-helper-remap-async-to-generator@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" @@ -493,7 +501,7 @@ babel-helper-remap-async-to-generator@^6.24.1: babel-helper-replace-supers@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" dependencies: babel-helper-optimise-call-expression "^6.24.1" babel-messages "^6.23.0" @@ -504,30 +512,30 @@ babel-helper-replace-supers@^6.24.1: babel-helpers@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" babel-messages@^6.23.0: version "6.23.0" - resolved "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" dependencies: babel-runtime "^6.22.0" babel-plugin-check-es2015-constants@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" dependencies: babel-runtime "^6.22.0" babel-plugin-constant-folding@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" + resolved "https://registry.yarnpkg.com/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" babel-plugin-dead-code-elimination@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" + resolved "https://registry.yarnpkg.com/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.11, babel-plugin-debug-macros@^0.1.7: version "0.1.11" @@ -542,84 +550,84 @@ babel-plugin-ember-modules-api-polyfill@^1.4.2: ember-rfc176-data "^0.2.0" babel-plugin-ember-modules-api-polyfill@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.0.1.tgz#baaf26dcebe2ed1de120021bc42be29f520497b3" + version "2.1.0" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.1.0.tgz#78848cc4fcc2274882a6c15cbb23fefcdc771301" dependencies: - ember-rfc176-data "^0.2.7" + ember-rfc176-data "^0.3.0" babel-plugin-eval@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" + resolved "https://registry.yarnpkg.com/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" babel-plugin-feature-flags@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" + resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" babel-plugin-filter-imports@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.3.1.tgz#e7859b56886b175dd2616425d277b219e209ea8b" + resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.3.1.tgz#e7859b56886b175dd2616425d277b219e209ea8b" babel-plugin-htmlbars-inline-precompile@^0.2.3: version "0.2.3" - resolved "https://registry.npmjs.org/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.3.tgz#cd365e278af409bfa6be7704c4354beee742446b" + resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.3.tgz#cd365e278af409bfa6be7704c4354beee742446b" babel-plugin-inline-environment-variables@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" + resolved "https://registry.yarnpkg.com/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" babel-plugin-jscript@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" + resolved "https://registry.yarnpkg.com/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" babel-plugin-member-expression-literals@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" + resolved "https://registry.yarnpkg.com/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" babel-plugin-property-literals@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" + resolved "https://registry.yarnpkg.com/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" babel-plugin-proto-to-assign@^1.0.3: version "1.0.4" - resolved "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" + resolved "https://registry.yarnpkg.com/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" dependencies: lodash "^3.9.3" babel-plugin-react-constant-elements@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" + resolved "https://registry.yarnpkg.com/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" babel-plugin-react-display-name@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" + resolved "https://registry.yarnpkg.com/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" babel-plugin-remove-console@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" + resolved "https://registry.yarnpkg.com/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" babel-plugin-remove-debugger@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" + resolved "https://registry.yarnpkg.com/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" babel-plugin-runtime@^1.0.7: version "1.0.7" - resolved "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" + resolved "https://registry.yarnpkg.com/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" babel-plugin-transform-async-to-generator@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" dependencies: babel-helper-remap-async-to-generator "^6.24.1" babel-plugin-syntax-async-functions "^6.8.0" @@ -627,19 +635,19 @@ babel-plugin-transform-async-to-generator@^6.22.0: babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1: version "6.26.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" dependencies: babel-runtime "^6.26.0" babel-template "^6.26.0" @@ -649,7 +657,7 @@ babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es20 babel-plugin-transform-es2015-classes@^6.23.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" dependencies: babel-helper-define-map "^6.24.1" babel-helper-function-name "^6.24.1" @@ -663,39 +671,39 @@ babel-plugin-transform-es2015-classes@^6.23.0: babel-plugin-transform-es2015-computed-properties@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" babel-plugin-transform-es2015-constants@^6.1.4: version "6.1.4" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-constants/-/babel-plugin-transform-es2015-constants-6.1.4.tgz#e4b8c78fb48ab98b0107f329fab6040e79c35a33" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-constants/-/babel-plugin-transform-es2015-constants-6.1.4.tgz#e4b8c78fb48ab98b0107f329fab6040e79c35a33" dependencies: babel-runtime "^5.0.0" babel-plugin-transform-es2015-destructuring@^6.23.0: version "6.23.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-duplicate-keys@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-plugin-transform-es2015-for-of@^6.23.0: version "6.23.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-function-name@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" @@ -703,13 +711,13 @@ babel-plugin-transform-es2015-function-name@^6.22.0: babel-plugin-transform-es2015-literals@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" dependencies: babel-plugin-transform-es2015-modules-commonjs "^6.24.1" babel-runtime "^6.22.0" @@ -717,7 +725,7 @@ babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015 babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: version "6.26.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" dependencies: babel-plugin-transform-strict-mode "^6.24.1" babel-runtime "^6.26.0" @@ -726,7 +734,7 @@ babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-e babel-plugin-transform-es2015-modules-systemjs@^6.23.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" dependencies: babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" @@ -734,7 +742,7 @@ babel-plugin-transform-es2015-modules-systemjs@^6.23.0: babel-plugin-transform-es2015-modules-umd@^6.23.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" dependencies: babel-plugin-transform-es2015-modules-amd "^6.24.1" babel-runtime "^6.22.0" @@ -742,14 +750,14 @@ babel-plugin-transform-es2015-modules-umd@^6.23.0: babel-plugin-transform-es2015-object-super@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" dependencies: babel-helper-replace-supers "^6.24.1" babel-runtime "^6.22.0" babel-plugin-transform-es2015-parameters@^6.23.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" dependencies: babel-helper-call-delegate "^6.24.1" babel-helper-get-function-arity "^6.24.1" @@ -760,20 +768,20 @@ babel-plugin-transform-es2015-parameters@^6.23.0: babel-plugin-transform-es2015-shorthand-properties@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-plugin-transform-es2015-spread@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-sticky-regex@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" dependencies: babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" @@ -781,19 +789,19 @@ babel-plugin-transform-es2015-sticky-regex@^6.22.0: babel-plugin-transform-es2015-template-literals@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-typeof-symbol@^6.23.0: version "6.23.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-unicode-regex@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" dependencies: babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" @@ -801,7 +809,7 @@ babel-plugin-transform-es2015-unicode-regex@^6.22.0: babel-plugin-transform-exponentiation-operator@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" dependencies: babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" babel-plugin-syntax-exponentiation-operator "^6.8.0" @@ -809,30 +817,30 @@ babel-plugin-transform-exponentiation-operator@^6.22.0: babel-plugin-transform-regenerator@^6.22.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" dependencies: regenerator-transform "^0.10.0" babel-plugin-transform-strict-mode@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-plugin-undeclared-variables-check@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" + resolved "https://registry.yarnpkg.com/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" dependencies: leven "^1.0.2" babel-plugin-undefined-to-void@^1.1.6: version "1.1.6" - resolved "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" + resolved "https://registry.yarnpkg.com/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" babel-polyfill@^6.16.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" dependencies: babel-runtime "^6.26.0" core-js "^2.5.0" @@ -840,7 +848,7 @@ babel-polyfill@^6.16.0: babel-preset-env@^1.5.1: version "1.6.0" - resolved "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.6.0.tgz#2de1c782a780a0a5d605d199c957596da43c44e4" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.0.tgz#2de1c782a780a0a5d605d199c957596da43c44e4" dependencies: babel-plugin-check-es2015-constants "^6.22.0" babel-plugin-syntax-trailing-function-commas "^6.22.0" @@ -875,7 +883,7 @@ babel-preset-env@^1.5.1: babel-register@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" dependencies: babel-core "^6.26.0" babel-runtime "^6.26.0" @@ -887,20 +895,20 @@ babel-register@^6.26.0: babel-runtime@^5.0.0: version "5.8.38" - resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz#1c0b02eb63312f5f087ff20450827b425c9d4c19" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-5.8.38.tgz#1c0b02eb63312f5f087ff20450827b425c9d4c19" dependencies: core-js "^1.0.0" babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: core-js "^2.4.0" regenerator-runtime "^0.11.0" babel-template@^6.24.1, babel-template@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" dependencies: babel-runtime "^6.26.0" babel-traverse "^6.26.0" @@ -910,7 +918,7 @@ babel-template@^6.24.1, babel-template@^6.26.0: babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" dependencies: babel-code-frame "^6.26.0" babel-messages "^6.23.0" @@ -924,7 +932,7 @@ babel-traverse@^6.24.1, babel-traverse@^6.26.0: babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" dependencies: babel-runtime "^6.26.0" esutils "^2.0.2" @@ -933,49 +941,45 @@ babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: babel6-plugin-strip-class-callcheck@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" + resolved "https://registry.yarnpkg.com/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" babel6-plugin-strip-heimdall@^6.0.1: version "6.0.1" - resolved "https://registry.npmjs.org/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" + resolved "https://registry.yarnpkg.com/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" babylon@^5.8.38: version "5.8.38" - resolved "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" babylon@^6.18.0: version "6.18.0" - resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" backbone@^1.1.2: version "1.3.3" - resolved "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" + resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" dependencies: underscore ">=1.8.3" backo2@1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" balanced-match@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" base64-arraybuffer@0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" base64-js@^1.0.2: version "1.2.1" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" base64id@0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" - -basic-auth@~1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz#45221ee429f7ee1e5035be3f51533f1cdfd29884" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" basic-auth@~2.0.0: version "2.0.0" @@ -985,31 +989,31 @@ basic-auth@~2.0.0: better-assert@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" dependencies: callsite "1.0.0" "binaryextensions@1 || 2": version "2.0.0" - resolved "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.0.0.tgz#e597d1a7a6a3558a2d1c7241a16c99965e6aa40f" + resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.0.0.tgz#e597d1a7a6a3558a2d1c7241a16c99965e6aa40f" blank-object@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" + resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" blob@0.0.4: version "0.0.4" - resolved "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" bluebird@^2.9.33: version "2.11.0" - resolved "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" bluebird@^3.1.1, bluebird@^3.4.6: - version "3.5.0" - resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" -body-parser@1.18.2: +body-parser@1.18.2, body-parser@^1.15.2: version "1.18.2" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" dependencies: @@ -1024,24 +1028,9 @@ body-parser@1.18.2: raw-body "2.3.2" type-is "~1.6.15" -body-parser@^1.15.2: - version "1.18.1" - resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.18.1.tgz#9c1629370bcfd42917f30641a2dcbe2ec50d4c26" - dependencies: - bytes "3.0.0" - content-type "~1.0.4" - debug "2.6.8" - 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" - body@^5.1.0: version "5.1.0" - resolved "https://registry.npmjs.org/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" + resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" dependencies: continuable-cache "^0.3.1" error "^7.0.0" @@ -1050,13 +1039,13 @@ body@^5.1.0: boom@0.4.x: version "0.4.2" - resolved "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" + resolved "https://registry.yarnpkg.com/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" dependencies: hoek "0.9.x" bower-config@^1.3.0: version "1.4.1" - resolved "https://registry.npmjs.org/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc" + resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc" dependencies: graceful-fs "^4.1.3" mout "^1.0.0" @@ -1066,18 +1055,18 @@ bower-config@^1.3.0: bower-endpoint-parser@0.2.2: version "0.2.2" - resolved "https://registry.npmjs.org/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" + resolved "https://registry.yarnpkg.com/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" brace-expansion@^1.0.0, brace-expansion@^1.1.7: version "1.1.8" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" dependencies: balanced-match "^1.0.0" concat-map "0.0.1" braces@^1.8.2: version "1.8.5" - resolved "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" dependencies: expand-range "^1.8.1" preserve "^0.2.0" @@ -1085,11 +1074,11 @@ braces@^1.8.2: breakable@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" + resolved "https://registry.yarnpkg.com/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" broccoli-asset-rev@^2.4.5: version "2.6.0" - resolved "https://registry.npmjs.org/broccoli-asset-rev/-/broccoli-asset-rev-2.6.0.tgz#0633fc3a0b2ba0c2c1d56fa9feb7b331fc83be6d" + resolved "https://registry.yarnpkg.com/broccoli-asset-rev/-/broccoli-asset-rev-2.6.0.tgz#0633fc3a0b2ba0c2c1d56fa9feb7b331fc83be6d" dependencies: broccoli-asset-rewrite "^1.1.0" broccoli-filter "^1.2.2" @@ -1099,13 +1088,13 @@ broccoli-asset-rev@^2.4.5: broccoli-asset-rewrite@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" + resolved "https://registry.yarnpkg.com/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" dependencies: broccoli-filter "^1.2.3" broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: version "5.7.2" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.2.tgz#756c30544775144e984333b7115f42c916ba08e0" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.2.tgz#756c30544775144e984333b7115f42c916ba08e0" dependencies: babel-core "^5.0.0" broccoli-funnel "^1.0.0" @@ -1120,7 +1109,7 @@ broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2: version "6.1.2" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.1.2.tgz#26019c045b5ea3e44cfef62821302f9bd483cabd" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.1.2.tgz#26019c045b5ea3e44cfef62821302f9bd483cabd" dependencies: babel-core "^6.14.0" broccoli-funnel "^1.0.0" @@ -1135,13 +1124,13 @@ broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2: broccoli-brocfile-loader@^0.18.0: version "0.18.0" - resolved "https://registry.npmjs.org/broccoli-brocfile-loader/-/broccoli-brocfile-loader-0.18.0.tgz#2e86021c805c34ffc8d29a2fb721cf273e819e4b" + resolved "https://registry.yarnpkg.com/broccoli-brocfile-loader/-/broccoli-brocfile-loader-0.18.0.tgz#2e86021c805c34ffc8d29a2fb721cf273e819e4b" dependencies: findup-sync "^0.4.2" broccoli-builder@^0.18.8: version "0.18.8" - resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.8.tgz#fe54694d544c3cdfdb01028e802eeca65749a879" + resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.8.tgz#fe54694d544c3cdfdb01028e802eeca65749a879" dependencies: heimdalljs "^0.2.0" promise-map-series "^0.2.1" @@ -1152,7 +1141,7 @@ broccoli-builder@^0.18.8: broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: version "2.3.1" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" @@ -1163,7 +1152,7 @@ broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: broccoli-caching-writer@^3.0.3: version "3.0.3" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.1" @@ -1174,7 +1163,7 @@ broccoli-caching-writer@^3.0.3: broccoli-caching-writer@~2.0.1: version "2.0.4" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" @@ -1187,7 +1176,7 @@ broccoli-caching-writer@~2.0.1: broccoli-clean-css@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" + resolved "https://registry.yarnpkg.com/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" dependencies: broccoli-persistent-filter "^1.1.6" clean-css-promise "^0.1.0" @@ -1196,7 +1185,7 @@ broccoli-clean-css@^1.1.0: broccoli-concat@^2.2.0: version "2.3.8" - resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-2.3.8.tgz#590cdcc021bb905b6c121d87c2d1d57df44a2a48" + resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-2.3.8.tgz#590cdcc021bb905b6c121d87c2d1d57df44a2a48" dependencies: broccoli-caching-writer "^2.3.1" broccoli-kitchen-sink-helpers "^0.3.1" @@ -1209,7 +1198,7 @@ broccoli-concat@^2.2.0: broccoli-concat@^3.2.2: version "3.2.2" - resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" + resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.3.0" @@ -1226,22 +1215,22 @@ broccoli-concat@^3.2.2: broccoli-config-loader@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/broccoli-config-loader/-/broccoli-config-loader-1.0.1.tgz#d10aaf8ebc0cb45c1da5baa82720e1d88d28c80a" + resolved "https://registry.yarnpkg.com/broccoli-config-loader/-/broccoli-config-loader-1.0.1.tgz#d10aaf8ebc0cb45c1da5baa82720e1d88d28c80a" dependencies: broccoli-caching-writer "^3.0.3" broccoli-config-replace@^1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" + resolved "https://registry.yarnpkg.com/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.0" debug "^2.2.0" fs-extra "^0.24.0" -broccoli-debug@^0.6.1, broccoli-debug@^0.6.2: +broccoli-debug@^0.6.1, broccoli-debug@^0.6.2, broccoli-debug@^0.6.3: version "0.6.3" - resolved "https://registry.npmjs.org/broccoli-debug/-/broccoli-debug-0.6.3.tgz#1f33bb0eacb5db81366f0492524c82b1217eb578" + resolved "https://registry.yarnpkg.com/broccoli-debug/-/broccoli-debug-0.6.3.tgz#1f33bb0eacb5db81366f0492524c82b1217eb578" dependencies: broccoli-plugin "^1.2.1" fs-tree-diff "^0.5.2" @@ -1253,7 +1242,7 @@ broccoli-debug@^0.6.1, broccoli-debug@^0.6.2: broccoli-file-creator@^1.0.0: version "1.1.1" - resolved "https://registry.npmjs.org/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" + resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" dependencies: broccoli-kitchen-sink-helpers "~0.2.0" broccoli-plugin "^1.1.0" @@ -1264,7 +1253,7 @@ broccoli-file-creator@^1.0.0: broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: version "1.2.4" - resolved "https://registry.npmjs.org/broccoli-filter/-/broccoli-filter-1.2.4.tgz#409afb94b9a3a6da9fac8134e91e205f40cc7330" + resolved "https://registry.yarnpkg.com/broccoli-filter/-/broccoli-filter-1.2.4.tgz#409afb94b9a3a6da9fac8134e91e205f40cc7330" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.0.0" @@ -1278,11 +1267,11 @@ broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: broccoli-funnel-reducer@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" + resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli-funnel@^1.1.0, broccoli-funnel@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" + resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" dependencies: array-equal "^1.0.0" blank-object "^1.0.1" @@ -1299,23 +1288,41 @@ broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli symlink-or-copy "^1.0.0" walk-sync "^0.3.1" +broccoli-funnel@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-2.0.1.tgz#6823c73b675ef78fffa7ab800f083e768b51d449" + dependencies: + array-equal "^1.0.0" + blank-object "^1.0.1" + broccoli-plugin "^1.3.0" + debug "^2.2.0" + fast-ordered-set "^1.0.0" + fs-tree-diff "^0.5.3" + heimdalljs "^0.2.0" + minimatch "^3.0.0" + mkdirp "^0.5.0" + path-posix "^1.0.0" + rimraf "^2.4.3" + symlink-or-copy "^1.0.0" + walk-sync "^0.3.1" + broccoli-kitchen-sink-helpers@^0.2.5, broccoli-kitchen-sink-helpers@~0.2.0: version "0.2.9" - resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" + resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" dependencies: glob "^5.0.10" mkdirp "^0.5.1" broccoli-kitchen-sink-helpers@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" + resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" dependencies: glob "^5.0.10" mkdirp "^0.5.1" broccoli-lint-eslint@^2.0.0: version "2.7.0" - resolved "https://registry.npmjs.org/broccoli-lint-eslint/-/broccoli-lint-eslint-2.7.0.tgz#a2d905d02b397a90ae82439f283c459ef819f140" + resolved "https://registry.yarnpkg.com/broccoli-lint-eslint/-/broccoli-lint-eslint-2.7.0.tgz#a2d905d02b397a90ae82439f283c459ef819f140" dependencies: broccoli-persistent-filter "^1.2.0" escape-string-regexp "^1.0.5" @@ -1326,7 +1333,7 @@ broccoli-lint-eslint@^2.0.0: broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^1.1.4, broccoli-merge-trees@^1.2.1: version "1.2.4" - resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" dependencies: broccoli-plugin "^1.3.0" can-symlink "^1.0.0" @@ -1339,14 +1346,14 @@ broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^ broccoli-merge-trees@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-2.0.0.tgz#10aea46dd5cebcc8b8f7d5a54f0a84a4f0bb90b9" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-2.0.0.tgz#10aea46dd5cebcc8b8f7d5a54f0a84a4f0bb90b9" dependencies: broccoli-plugin "^1.3.0" merge-trees "^1.0.1" broccoli-merge-trees@~0.2.3: version "0.2.4" - resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-0.2.4.tgz#1936f63bb09e24246b1e91d8c53162c0f7b24c3c" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-0.2.4.tgz#1936f63bb09e24246b1e91d8c53162c0f7b24c3c" dependencies: broccoli-plugin "^1.0.0" debug "^2.2.0" @@ -1354,18 +1361,18 @@ broccoli-merge-trees@~0.2.3: broccoli-middleware@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-1.0.0.tgz#92f4e1fb9a791ea986245a7077f35cc648dab097" + resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-1.0.0.tgz#92f4e1fb9a791ea986245a7077f35cc648dab097" dependencies: handlebars "^4.0.4" mime "^1.2.11" broccoli-node-info@1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" + resolved "https://registry.yarnpkg.com/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0, broccoli-persistent-filter@^1.4.0, broccoli-persistent-filter@^1.4.2: version "1.4.3" - resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz#3511bc52fc53740cda51621f58a28152d9911bc1" + resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz#3511bc52fc53740cda51621f58a28152d9911bc1" dependencies: async-disk-cache "^1.2.1" async-promise-queue "^1.0.3" @@ -1383,7 +1390,7 @@ broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-p broccoli-plugin@1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -1392,7 +1399,7 @@ broccoli-plugin@1.1.0: broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -1401,7 +1408,7 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli broccoli-rollup@^1.2.0: version "1.3.0" - resolved "https://registry.npmjs.org/broccoli-rollup/-/broccoli-rollup-1.3.0.tgz#43a0a7798555bab54217009eb470a4ff5a056df0" + resolved "https://registry.yarnpkg.com/broccoli-rollup/-/broccoli-rollup-1.3.0.tgz#43a0a7798555bab54217009eb470a4ff5a056df0" dependencies: broccoli-plugin "^1.2.1" es6-map "^0.1.4" @@ -1417,17 +1424,17 @@ broccoli-rollup@^1.2.0: broccoli-slow-trees@3.0.1, broccoli-slow-trees@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" + resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" dependencies: heimdalljs "^0.2.1" broccoli-source@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" + resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" broccoli-sri-hash@^2.1.0: version "2.1.2" - resolved "https://registry.npmjs.org/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" + resolved "https://registry.yarnpkg.com/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" dependencies: broccoli-caching-writer "^2.2.0" mkdirp "^0.5.1" @@ -1437,7 +1444,7 @@ broccoli-sri-hash@^2.1.0: broccoli-stew@^1.2.0, broccoli-stew@^1.3.3, broccoli-stew@^1.4.2: version "1.5.0" - resolved "https://registry.npmjs.org/broccoli-stew/-/broccoli-stew-1.5.0.tgz#d7af8c18511dce510e49d308a62e5977f461883c" + resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-1.5.0.tgz#d7af8c18511dce510e49d308a62e5977f461883c" dependencies: broccoli-debug "^0.6.1" broccoli-funnel "^1.0.1" @@ -1456,14 +1463,14 @@ broccoli-stew@^1.2.0, broccoli-stew@^1.3.3, broccoli-stew@^1.4.2: broccoli-string-replace@^0.1.1: version "0.1.2" - resolved "https://registry.npmjs.org/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" + resolved "https://registry.yarnpkg.com/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" dependencies: broccoli-persistent-filter "^1.1.5" minimatch "^3.0.3" broccoli-test-helper@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/broccoli-test-helper/-/broccoli-test-helper-1.2.0.tgz#d01005d8611fd73ebe1b29552bf052ff59badfb4" + resolved "https://registry.yarnpkg.com/broccoli-test-helper/-/broccoli-test-helper-1.2.0.tgz#d01005d8611fd73ebe1b29552bf052ff59badfb4" dependencies: broccoli "^1.1.0" fixturify "^0.3.2" @@ -1474,7 +1481,7 @@ broccoli-test-helper@^1.2.0: broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: version "1.5.2" - resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.2.tgz#04f84ab0db539031fa868ccfa563c9932d50cedb" + resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.2.tgz#04f84ab0db539031fa868ccfa563c9932d50cedb" dependencies: broccoli-plugin "^1.2.1" debug "^2.2.0" @@ -1488,14 +1495,14 @@ broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: broccoli-writer@~0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/broccoli-writer/-/broccoli-writer-0.1.1.tgz#d4d71aa8f2afbc67a3866b91a2da79084b96ab2d" + resolved "https://registry.yarnpkg.com/broccoli-writer/-/broccoli-writer-0.1.1.tgz#d4d71aa8f2afbc67a3866b91a2da79084b96ab2d" dependencies: quick-temp "^0.1.0" rsvp "^3.0.6" broccoli-yuidoc@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/broccoli-yuidoc/-/broccoli-yuidoc-2.1.0.tgz#d208d5c056e421a51f0c7701e938229e7e85c2e6" + resolved "https://registry.yarnpkg.com/broccoli-yuidoc/-/broccoli-yuidoc-2.1.0.tgz#d208d5c056e421a51f0c7701e938229e7e85c2e6" dependencies: broccoli-caching-writer "~2.0.1" broccoli-merge-trees "~0.2.3" @@ -1505,7 +1512,7 @@ broccoli-yuidoc@^2.1.0: broccoli@^1.1.0: version "1.1.3" - resolved "https://registry.npmjs.org/broccoli/-/broccoli-1.1.3.tgz#98405e86b7b0e6c268fb8302a006d834d17ed292" + resolved "https://registry.yarnpkg.com/broccoli/-/broccoli-1.1.3.tgz#98405e86b7b0e6c268fb8302a006d834d17ed292" dependencies: broccoli-node-info "1.1.0" broccoli-slow-trees "3.0.1" @@ -1524,21 +1531,21 @@ broccoli@^1.1.0: underscore.string "^3.2.2" browserslist@^2.1.2: - version "2.4.0" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-2.4.0.tgz#693ee93d01e66468a6348da5498e011f578f87f8" + version "2.5.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.5.1.tgz#68e4bc536bbcc6086d62843a2ffccea8396821c6" dependencies: - caniuse-lite "^1.0.30000718" - electron-to-chromium "^1.3.18" + caniuse-lite "^1.0.30000744" + electron-to-chromium "^1.3.24" bser@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" dependencies: node-int64 "^0.4.0" buffer@4.9.1: version "4.9.1" - resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -1546,101 +1553,97 @@ buffer@4.9.1: builtin-modules@^1.0.0: version "1.1.1" - resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" builtins@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" bytes@1: version "1.0.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" - -bytes@2.5.0: - version "2.5.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-2.5.0.tgz#4c9423ea2d252c270c41b2bdefeff9bb6b62c06a" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" bytes@3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" calculate-cache-key-for-tree@^1.0.0, calculate-cache-key-for-tree@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" + resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" dependencies: json-stable-stringify "^1.0.1" caller-path@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" dependencies: callsites "^0.2.0" callsite@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" callsites@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" camelcase@^1.0.2, camelcase@^1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" camelcase@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" can-symlink@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" + resolved "https://registry.yarnpkg.com/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" dependencies: tmp "0.0.28" -caniuse-lite@^1.0.30000718: - version "1.0.30000727" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000727.tgz#20c895768398ded5f98a4beab4a76c285def41d2" +caniuse-lite@^1.0.30000744: + version "1.0.30000746" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000746.tgz#c64f95a3925cfd30207a308ed76c1ae96ea09ea0" capture-exit@^1.1.0: version "1.2.0" - resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" dependencies: rsvp "^3.3.3" cardinal@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" + resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" dependencies: ansicolors "~0.2.1" redeyed "~1.0.0" center-align@^0.1.1: version "0.1.3" - resolved "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" dependencies: align-text "^0.1.3" lazy-cache "^1.0.3" chai-as-promised@^5.1.0: version "5.3.0" - resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-5.3.0.tgz#09d7a402908aa70dfdbead53e5853fc79d3ef21c" + resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-5.3.0.tgz#09d7a402908aa70dfdbead53e5853fc79d3ef21c" chai-as-promised@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" + resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" dependencies: check-error "^1.0.2" chai-files@^1.0.0, chai-files@^1.1.0: version "1.4.0" - resolved "https://registry.npmjs.org/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" + resolved "https://registry.yarnpkg.com/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" dependencies: assertion-error "^1.0.1" chai@^3.3.0: version "3.5.0" - resolved "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" + resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" dependencies: assertion-error "^1.0.1" deep-eql "^0.1.3" @@ -1648,7 +1651,7 @@ chai@^3.3.0: chalk@^0.5.1: version "0.5.1" - resolved "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" dependencies: ansi-styles "^1.1.0" escape-string-regexp "^1.0.0" @@ -1658,7 +1661,7 @@ chalk@^0.5.1: chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" - resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -1666,9 +1669,9 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" dependencies: ansi-styles "^3.1.0" escape-string-regexp "^1.0.5" @@ -1676,17 +1679,17 @@ chalk@^2.0.0: charm@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" + resolved "https://registry.yarnpkg.com/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" dependencies: inherits "^2.0.1" check-error@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" chrome-debugging-client@^0.2.4: version "0.2.5" - resolved "https://registry.npmjs.org/chrome-debugging-client/-/chrome-debugging-client-0.2.5.tgz#b8e1a6c37283323b6ff5d60525f6ea1fc8899fbd" + resolved "https://registry.yarnpkg.com/chrome-debugging-client/-/chrome-debugging-client-0.2.5.tgz#b8e1a6c37283323b6ff5d60525f6ea1fc8899fbd" dependencies: "@types/node" "^7.0.5" "@types/rimraf" "^0.0.28" @@ -1698,15 +1701,15 @@ chrome-debugging-client@^0.2.4: circular-json@^0.3.1: version "0.3.3" - resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" clean-base-url@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" + resolved "https://registry.yarnpkg.com/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" clean-css-promise@^0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" + resolved "https://registry.yarnpkg.com/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" dependencies: array-to-error "^1.0.0" clean-css "^3.4.5" @@ -1714,24 +1717,30 @@ clean-css-promise@^0.1.0: clean-css@^3.4.5: version "3.4.28" - resolved "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" dependencies: commander "2.8.x" source-map "0.4.x" -cli-cursor@^1.0.1, cli-cursor@^1.0.2: +cli-cursor@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" dependencies: restore-cursor "^1.0.1" -cli-spinners@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz#bb764d88e185fb9e1e6a2a1f19772318f605e31c" +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-spinners@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.1.0.tgz#f1847b168844d917a671eb9d147e3df497c90d06" cli-table2@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" + resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" dependencies: lodash "^3.10.1" string-width "^1.0.1" @@ -1740,17 +1749,17 @@ cli-table2@^0.2.0: cli-table@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" dependencies: colors "1.0.3" cli-width@^2.0.0: version "2.2.0" - resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" cliui@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" dependencies: center-align "^0.1.1" right-align "^0.1.1" @@ -1758,7 +1767,7 @@ cliui@^2.1.0: cliui@^3.2.0: version "3.2.0" - resolved "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" @@ -1766,79 +1775,79 @@ cliui@^3.2.0: clone@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" + resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" clone@^2.0.0: version "2.1.1" - resolved "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" co@^4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" code-point-at@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" color-convert@^1.9.0: version "1.9.0" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" dependencies: color-name "^1.1.1" color-name@^1.1.1: version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" colors@1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" colors@^1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" colors@~0.6.0-1: version "0.6.2" - resolved "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" + resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" combined-stream@~0.0.4: version "0.0.7" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" dependencies: delayed-stream "0.0.5" commander@0.6.1: version "0.6.1" - resolved "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" + resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" commander@2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" commander@2.8.x: version "2.8.1" - resolved "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" dependencies: graceful-readlink ">= 1.0.0" commander@^2.5.0, commander@^2.6.0: version "2.11.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" commander@~2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" common-tags@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/common-tags/-/common-tags-1.4.0.tgz#1187be4f3d4cf0c0427d43f74eef1f73501614c0" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.4.0.tgz#1187be4f3d4cf0c0427d43f74eef1f73501614c0" dependencies: babel-runtime "^6.18.0" commoner@~0.10.3: version "0.10.8" - resolved "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" + resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" dependencies: commander "^2.5.0" detective "^4.3.1" @@ -1852,45 +1861,45 @@ commoner@~0.10.3: component-bind@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" component-emitter@1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" component-emitter@1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" component-inherit@0.0.3: version "0.0.3" - resolved "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" -compressible@~2.0.10: +compressible@~2.0.11: version "2.0.11" - resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.11.tgz#16718a75de283ed8e604041625a2064586797d8a" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.11.tgz#16718a75de283ed8e604041625a2064586797d8a" dependencies: mime-db ">= 1.29.0 < 2" compression@^1.4.4: - version "1.7.0" - resolved "https://registry.npmjs.org/compression/-/compression-1.7.0.tgz#030c9f198f1643a057d776a738e922da4373012d" + version "1.7.1" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.1.tgz#eff2603efc2e22cf86f35d2eb93589f9875373db" dependencies: - accepts "~1.3.3" - bytes "2.5.0" - compressible "~2.0.10" - debug "2.6.8" + accepts "~1.3.4" + bytes "3.0.0" + compressible "~2.0.11" + debug "2.6.9" on-headers "~1.0.1" safe-buffer "5.1.1" - vary "~1.1.1" + vary "~1.1.2" concat-map@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.6, concat-stream@^1.4.7: +concat-stream@^1.4.6: version "1.6.0" - resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: inherits "^2.0.3" readable-stream "^2.2.2" @@ -1898,7 +1907,7 @@ concat-stream@^1.4.6, concat-stream@^1.4.7: configstore@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" dependencies: dot-prop "^3.0.0" graceful-fs "^4.1.2" @@ -1912,7 +1921,7 @@ configstore@^2.0.0: configstore@^3.0.0: version "3.1.1" - resolved "https://registry.npmjs.org/configstore/-/configstore-3.1.1.tgz#094ee662ab83fad9917678de114faaea8fcdca90" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.1.tgz#094ee662ab83fad9917678de114faaea8fcdca90" dependencies: dot-prop "^4.1.0" graceful-fs "^4.1.2" @@ -1922,90 +1931,90 @@ configstore@^3.0.0: xdg-basedir "^3.0.0" connect@^3.3.3: - version "3.6.3" - resolved "https://registry.npmjs.org/connect/-/connect-3.6.3.tgz#f7320d46a25b4be7b483a2236517f24b1e27e301" + version "3.6.5" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.5.tgz#fb8dde7ba0763877d0ec9df9dac0b4b40e72c7da" dependencies: - debug "2.6.8" - finalhandler "1.0.4" - parseurl "~1.3.1" - utils-merge "1.0.0" + debug "2.6.9" + finalhandler "1.0.6" + parseurl "~1.3.2" + utils-merge "1.0.1" console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" -console-ui@^1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/console-ui/-/console-ui-1.0.3.tgz#31c524461b63422769f9e89c173495d91393721c" +console-ui@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-2.0.0.tgz#159ef7d098a491f84705bb69cd63ecec9a367b14" dependencies: - chalk "^1.1.3" - inquirer "^1.2.3" - ora "^0.2.0" + chalk "^2.1.0" + inquirer "^3.2.1" + ora "^1.3.0" through "^2.3.8" consolidate@^0.14.0: version "0.14.5" - resolved "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" + resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" dependencies: bluebird "^3.1.1" content-disposition@0.5.2: version "0.5.2" - resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" -content-type@~1.0.2, content-type@~1.0.4: +content-type@~1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" continuable-cache@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" + resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" convert-source-map@^1.1.0, convert-source-map@^1.5.0: version "1.5.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" cookie-signature@1.0.6: version "1.0.6" - resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" cookie@0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" copy-dereference@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" + resolved "https://registry.yarnpkg.com/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" core-js@^1.0.0: version "1.2.7" - resolved "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" core-js@^2.4.0, core-js@^2.5.0: version "2.5.1" - resolved "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" core-js@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" core-object@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" + resolved "https://registry.yarnpkg.com/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" core-object@^3.1.3: version "3.1.5" - resolved "https://registry.npmjs.org/core-object/-/core-object-3.1.5.tgz#fa627b87502adc98045e44678e9a8ec3b9c0d2a9" + resolved "https://registry.yarnpkg.com/core-object/-/core-object-3.1.5.tgz#fa627b87502adc98045e44678e9a8ec3b9c0d2a9" dependencies: chalk "^2.0.0" core-util-is@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: lru-cache "^4.0.1" shebang-command "^1.2.0" @@ -2013,81 +2022,71 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0: cryptiles@0.2.x: version "0.2.2" - resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" dependencies: boom "0.4.x" crypto-browserify@1.0.9: version "1.0.9" - resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" crypto-random-string@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" ctype@0.5.3: version "0.5.3" - resolved "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" + resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" d@1: version "1.0.0" - resolved "https://registry.npmjs.org/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" dependencies: es5-ext "^0.10.9" dag-map@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" + resolved "https://registry.yarnpkg.com/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" -debug@2, debug@2.6.8, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0, debug@^2.6.8, debug@~2.6.7: - version "2.6.8" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" +debug@2, debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0, debug@^2.6.8, debug@~2.6.7: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: ms "2.0.0" debug@2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" dependencies: ms "0.7.1" debug@2.3.3: version "2.3.3" - resolved "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" dependencies: ms "0.7.2" -debug@2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - dependencies: - ms "2.0.0" - decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" - resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" deep-eql@^0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" dependencies: type-detect "0.1.1" -deep-freeze@^0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/deep-freeze/-/deep-freeze-0.0.1.tgz#3a0b0005de18672819dfd38cd31f91179c893e84" - deep-is@~0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" defined@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" defs@~1.1.0: version "1.1.1" - resolved "https://registry.npmjs.org/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" + resolved "https://registry.yarnpkg.com/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" dependencies: alter "~0.2.0" ast-traverse "~0.1.1" @@ -2102,7 +2101,7 @@ defs@~1.1.0: del@^2.0.2: version "2.2.2" - resolved "https://registry.npmjs.org/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" dependencies: globby "^5.0.0" is-path-cwd "^1.0.0" @@ -2114,29 +2113,29 @@ del@^2.0.2: delayed-stream@0.0.5: version "0.0.5" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" delegates@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" -depd@1.1.1, depd@~1.1.0, depd@~1.1.1: +depd@1.1.1, depd@~1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" destroy@~1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" detect-file@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" dependencies: fs-exists-sync "^0.1.0" detect-indent@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" dependencies: get-stdin "^4.0.1" minimist "^1.1.0" @@ -2144,72 +2143,72 @@ detect-indent@^3.0.0: detect-indent@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" dependencies: repeating "^2.0.0" detective@^4.3.1: version "4.5.0" - resolved "https://registry.npmjs.org/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" + resolved "https://registry.yarnpkg.com/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" dependencies: acorn "^4.0.3" defined "^1.0.0" diff@1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" + resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" diff@^3.2.0: - version "3.3.1" - resolved "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" + version "3.4.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c" doctrine@^1.2.2: version "1.5.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" dependencies: esutils "^2.0.2" isarray "^1.0.0" dot-prop@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" dependencies: is-obj "^1.0.0" dot-prop@^4.1.0: version "4.2.0" - resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" dependencies: is-obj "^1.0.0" editions@^1.1.1: version "1.3.3" - resolved "https://registry.npmjs.org/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" + resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" ee-first@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -electron-to-chromium@^1.3.18: - version "1.3.21" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.21.tgz#a967ebdcfe8ed0083fc244d1894022a8e8113ea2" +electron-to-chromium@^1.3.24: + version "1.3.25" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.25.tgz#453b21009836d0997d86035601ff6cae4791c460" ember-ajax@^2.4.1: version "2.5.6" - resolved "https://registry.npmjs.org/ember-ajax/-/ember-ajax-2.5.6.tgz#a75f743ccf1b95e979a5cf96013b3dba8fa625e4" + resolved "https://registry.yarnpkg.com/ember-ajax/-/ember-ajax-2.5.6.tgz#a75f743ccf1b95e979a5cf96013b3dba8fa625e4" dependencies: ember-cli-babel "^5.1.5" ember-cli-app-version@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/ember-cli-app-version/-/ember-cli-app-version-3.1.0.tgz#074b0330581a7b8ab094ff07fefb34e0d0254bfd" + resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-3.1.0.tgz#074b0330581a7b8ab094ff07fefb34e0d0254bfd" dependencies: ember-cli-babel "^6.8.0" git-repo-version "0.4.1" ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.2.1: version "5.2.4" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" dependencies: broccoli-babel-transpiler "^5.6.2" broccoli-funnel "^1.0.0" @@ -2217,40 +2216,7 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-c ember-cli-version-checker "^1.0.2" resolve "^1.1.2" -ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.7: - version "6.5.1" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.5.1.tgz#37eaab592523938f8d52fc9d30bd0f56fc1c6599" - dependencies: - amd-name-resolver "0.0.6" - babel-plugin-debug-macros "^0.1.10" - babel-plugin-transform-es2015-modules-amd "^6.24.0" - babel-polyfill "^6.16.0" - babel-preset-env "^1.5.1" - broccoli-babel-transpiler "^6.0.0" - broccoli-debug "^0.6.2" - broccoli-funnel "^1.0.0" - broccoli-source "^1.1.0" - clone "^2.0.0" - ember-cli-version-checker "^2.0.0" - -ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1: - version "6.8.2" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.8.2.tgz#eac2785964f4743f4c815cd53c6288f00cc087d7" - dependencies: - amd-name-resolver "0.0.7" - babel-plugin-debug-macros "^0.1.11" - babel-plugin-ember-modules-api-polyfill "^2.0.1" - babel-plugin-transform-es2015-modules-amd "^6.24.0" - babel-polyfill "^6.16.0" - babel-preset-env "^1.5.1" - broccoli-babel-transpiler "^6.1.2" - broccoli-debug "^0.6.2" - broccoli-funnel "^1.0.0" - broccoli-source "^1.1.0" - clone "^2.0.0" - ember-cli-version-checker "^2.0.0" - -ember-cli-babel@^6.8.2: +ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2: version "6.8.2" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.8.2.tgz#eac2785964f4743f4c815cd53c6288f00cc087d7" dependencies: @@ -2269,7 +2235,7 @@ ember-cli-babel@^6.8.2: ember-cli-blueprint-test-helpers@0.11.0: version "0.11.0" - resolved "https://registry.npmjs.org/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" + resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" dependencies: chai "^3.3.0" chai-as-promised "^5.1.0" @@ -2284,7 +2250,7 @@ ember-cli-blueprint-test-helpers@0.11.0: ember-cli-broccoli-sane-watcher@^2.0.4: version "2.0.4" - resolved "https://registry.npmjs.org/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.0.4.tgz#f43f42f75b7509c212fb926cd9aea86ae19264c6" + resolved "https://registry.yarnpkg.com/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.0.4.tgz#f43f42f75b7509c212fb926cd9aea86ae19264c6" dependencies: broccoli-slow-trees "^3.0.1" heimdalljs "^0.2.1" @@ -2294,7 +2260,7 @@ ember-cli-broccoli-sane-watcher@^2.0.4: ember-cli-dependency-checker@^1.3.0: version "1.4.0" - resolved "https://registry.npmjs.org/ember-cli-dependency-checker/-/ember-cli-dependency-checker-1.4.0.tgz#2b13f977e1eea843fc1a21a001be6ca5d4ef1942" + resolved "https://registry.yarnpkg.com/ember-cli-dependency-checker/-/ember-cli-dependency-checker-1.4.0.tgz#2b13f977e1eea843fc1a21a001be6ca5d4ef1942" dependencies: chalk "^0.5.1" is-git-url "^0.2.0" @@ -2302,7 +2268,7 @@ ember-cli-dependency-checker@^1.3.0: ember-cli-eslint@1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/ember-cli-eslint/-/ember-cli-eslint-1.3.0.tgz#8a7eda0d7e6a00c5a5a823f59664932d6429a8f1" + resolved "https://registry.yarnpkg.com/ember-cli-eslint/-/ember-cli-eslint-1.3.0.tgz#8a7eda0d7e6a00c5a5a823f59664932d6429a8f1" dependencies: broccoli-lint-eslint "^2.0.0" ember-cli-babel "^5.1.5" @@ -2310,15 +2276,15 @@ ember-cli-eslint@1.3.0: ember-cli-get-component-path-option@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" + resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" ember-cli-get-dependency-depth@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" + resolved "https://registry.yarnpkg.com/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" ember-cli-htmlbars-inline-precompile@^0.4.3: version "0.4.4" - resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.4.tgz#24a7617152630d64a047e553b72e00963a4f8d73" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.4.tgz#24a7617152630d64a047e553b72e00963a4f8d73" dependencies: babel-plugin-htmlbars-inline-precompile "^0.2.3" ember-cli-version-checker "^2.0.0" @@ -2327,7 +2293,7 @@ ember-cli-htmlbars-inline-precompile@^0.4.3: ember-cli-htmlbars@^2.0.1: version "2.0.3" - resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-2.0.3.tgz#e116e1500dba12f29c94b05b9ec90f52cb8bb042" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-2.0.3.tgz#e116e1500dba12f29c94b05b9ec90f52cb8bb042" dependencies: broccoli-persistent-filter "^1.0.3" hash-for-dep "^1.0.2" @@ -2336,11 +2302,11 @@ ember-cli-htmlbars@^2.0.1: ember-cli-inject-live-reload@^1.4.1: version "1.7.0" - resolved "https://registry.npmjs.org/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.7.0.tgz#af94336e015336127dfb98080ad442bb233e37ed" + resolved "https://registry.yarnpkg.com/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.7.0.tgz#af94336e015336127dfb98080ad442bb233e37ed" ember-cli-internal-test-helpers@^0.8.1: version "0.8.3" - resolved "https://registry.npmjs.org/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.8.3.tgz#e9b7db67f3fda4db736d1a319a282c04beada495" + resolved "https://registry.yarnpkg.com/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.8.3.tgz#e9b7db67f3fda4db736d1a319a282c04beada495" dependencies: chai "^3.3.0" chai-as-promised "^6.0.0" @@ -2358,11 +2324,11 @@ ember-cli-internal-test-helpers@^0.8.1: ember-cli-is-package-missing@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" + resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" ember-cli-legacy-blueprints@^0.1.2: version "0.1.5" - resolved "https://registry.npmjs.org/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.5.tgz#93c15ca242ec5107d62a8af7ec30f6ac538f3ad9" + resolved "https://registry.yarnpkg.com/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.5.tgz#93c15ca242ec5107d62a8af7ec30f6ac538f3ad9" dependencies: chalk "^1.1.1" ember-cli-get-component-path-option "^1.0.0" @@ -2382,23 +2348,27 @@ ember-cli-legacy-blueprints@^0.1.2: rsvp "^3.0.17" silent-error "^1.0.0" -ember-cli-lodash-subset@^1.0.11, ember-cli-lodash-subset@^1.0.7: +ember-cli-lodash-subset@^1.0.7: version "1.0.12" - resolved "https://registry.npmjs.org/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" + resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" + +ember-cli-lodash-subset@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-2.0.1.tgz#20cb68a790fe0fde2488ddfd8efbb7df6fe766f2" ember-cli-normalize-entity-name@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" + resolved "https://registry.yarnpkg.com/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" dependencies: silent-error "^1.0.0" ember-cli-path-utils@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" + resolved "https://registry.yarnpkg.com/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" ember-cli-preprocess-registry@^3.1.0: version "3.1.1" - resolved "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.1.tgz#38456c21c4d2b64945850cf9ec68db6ba769288a" + resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.1.tgz#38456c21c4d2b64945850cf9ec68db6ba769288a" dependencies: broccoli-clean-css "^1.1.0" broccoli-funnel "^1.0.0" @@ -2411,7 +2381,7 @@ ember-cli-preprocess-registry@^3.1.0: ember-cli-pretender@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-1.0.1.tgz#35540babddef6f2778e91c627d190c73505103cd" + resolved "https://registry.yarnpkg.com/ember-cli-pretender/-/ember-cli-pretender-1.0.1.tgz#35540babddef6f2778e91c627d190c73505103cd" dependencies: broccoli-funnel "^1.1.0" broccoli-merge-trees "^1.2.1" @@ -2420,7 +2390,7 @@ ember-cli-pretender@^1.0.1: ember-cli-qunit@^2.1.0: version "2.2.6" - resolved "https://registry.npmjs.org/ember-cli-qunit/-/ember-cli-qunit-2.2.6.tgz#d802174724edd59b61ffdd0581fceb3236014dd1" + resolved "https://registry.yarnpkg.com/ember-cli-qunit/-/ember-cli-qunit-2.2.6.tgz#d802174724edd59b61ffdd0581fceb3236014dd1" dependencies: broccoli-babel-transpiler "^5.5.0" broccoli-concat "^2.2.0" @@ -2436,7 +2406,7 @@ ember-cli-qunit@^2.1.0: ember-cli-release@^0.2.9: version "0.2.9" - resolved "https://registry.npmjs.org/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" + resolved "https://registry.yarnpkg.com/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" dependencies: chalk "^1.0.0" git-tools "^0.1.4" @@ -2450,7 +2420,7 @@ ember-cli-release@^0.2.9: ember-cli-shims@^1.0.2: version "1.1.0" - resolved "https://registry.npmjs.org/ember-cli-shims/-/ember-cli-shims-1.1.0.tgz#0e3b8a048be865b4f81cc81d397ff1eeb13f75b6" + resolved "https://registry.yarnpkg.com/ember-cli-shims/-/ember-cli-shims-1.1.0.tgz#0e3b8a048be865b4f81cc81d397ff1eeb13f75b6" dependencies: ember-cli-babel "^6.0.0-beta.7" ember-cli-version-checker "^1.2.0" @@ -2458,56 +2428,56 @@ ember-cli-shims@^1.0.2: ember-cli-sri@^2.1.0: version "2.1.1" - resolved "https://registry.npmjs.org/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" + resolved "https://registry.yarnpkg.com/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" dependencies: broccoli-sri-hash "^2.1.0" ember-cli-string-utils@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" + resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" ember-cli-test-info@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" + resolved "https://registry.yarnpkg.com/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" dependencies: ember-cli-string-utils "^1.0.0" ember-cli-test-loader@^1.1.0: version "1.1.1" - resolved "https://registry.npmjs.org/ember-cli-test-loader/-/ember-cli-test-loader-1.1.1.tgz#333311209b18185d0e0e95f918349da10cacf0b1" + resolved "https://registry.yarnpkg.com/ember-cli-test-loader/-/ember-cli-test-loader-1.1.1.tgz#333311209b18185d0e0e95f918349da10cacf0b1" dependencies: ember-cli-babel "^5.2.1" ember-cli-uglify@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/ember-cli-uglify/-/ember-cli-uglify-1.2.0.tgz#3208c32b54bc2783056e8bb0d5cfe9bbaf17ffb2" + resolved "https://registry.yarnpkg.com/ember-cli-uglify/-/ember-cli-uglify-1.2.0.tgz#3208c32b54bc2783056e8bb0d5cfe9bbaf17ffb2" dependencies: broccoli-uglify-sourcemap "^1.0.0" ember-cli-valid-component-name@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" + resolved "https://registry.yarnpkg.com/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" dependencies: silent-error "^1.0.0" ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7, ember-cli-version-checker@^1.2.0: version "1.3.1" - resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz#0bc2d134c830142da64bf9627a0eded10b61ae72" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz#0bc2d134c830142da64bf9627a0eded10b61ae72" dependencies: semver "^5.3.0" ember-cli-version-checker@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-2.0.0.tgz#e1f7d8e4cdcd752ac35f1611e4daa8836db4c4c7" + version "2.1.0" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.1.0.tgz#fc79a56032f3717cf844ada7cbdec1a06fedb604" dependencies: resolve "^1.3.3" semver "^5.3.0" ember-cli@^2.11.1: - version "2.15.1" - resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-2.15.1.tgz#773add3cc18e5068f1c5f43a77544efa2712e47b" + version "2.16.2" + resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-2.16.2.tgz#53b922073a8e6f34255a6e0dcb1794a91ba3e1b7" dependencies: - amd-name-resolver "0.0.7" + amd-name-resolver "1.0.0" babel-plugin-transform-es2015-modules-amd "^6.24.0" bower-config "^1.3.0" bower-endpoint-parser "0.2.2" @@ -2517,7 +2487,8 @@ ember-cli@^2.11.1: broccoli-concat "^3.2.2" broccoli-config-loader "^1.0.0" broccoli-config-replace "^1.1.2" - broccoli-funnel "^1.0.6" + broccoli-debug "^0.6.3" + broccoli-funnel "^2.0.0" broccoli-funnel-reducer "^1.0.0" broccoli-merge-trees "^2.0.0" broccoli-middleware "^1.0.0" @@ -2525,31 +2496,30 @@ ember-cli@^2.11.1: broccoli-stew "^1.2.0" calculate-cache-key-for-tree "^1.0.0" capture-exit "^1.1.0" - chalk "^1.1.3" + chalk "^2.0.1" clean-base-url "^1.0.0" compression "^1.4.4" configstore "^3.0.0" - console-ui "^1.0.2" + console-ui "^2.0.0" core-object "^3.1.3" dag-map "^2.0.2" - deep-freeze "^0.0.1" diff "^3.2.0" ember-cli-broccoli-sane-watcher "^2.0.4" ember-cli-is-package-missing "^1.0.0" ember-cli-legacy-blueprints "^0.1.2" - ember-cli-lodash-subset "^1.0.11" + ember-cli-lodash-subset "^2.0.1" ember-cli-normalize-entity-name "^1.0.0" ember-cli-preprocess-registry "^3.1.0" ember-cli-string-utils "^1.0.0" ember-try "^0.2.15" ensure-posix-path "^1.0.2" - execa "^0.7.0" + execa "^0.8.0" exists-sync "0.0.4" exit "^0.1.2" express "^4.12.3" filesize "^3.1.3" find-up "^2.1.0" - fs-extra "^3.0.0" + fs-extra "^4.0.0" fs-tree-diff "^0.5.2" get-caller-file "^1.0.0" git-repo-info "^1.4.1" @@ -2577,7 +2547,7 @@ ember-cli@^2.11.1: promise-map-series "^0.2.1" quick-temp "^0.1.8" resolve "^1.3.0" - rsvp "^3.3.3" + rsvp "^3.6.0" sane "^1.6.0" semver "^5.1.1" silent-error "^1.0.0" @@ -2600,47 +2570,47 @@ ember-dev@emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed: ember-disable-prototype-extensions@^1.1.0: version "1.1.3" - resolved "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" + resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" ember-disable-proxy-controllers@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" + resolved "https://registry.yarnpkg.com/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" dependencies: ember-cli-babel "^5.0.0" ember-export-application-global@^1.0.5: version "1.1.1" - resolved "https://registry.npmjs.org/ember-export-application-global/-/ember-export-application-global-1.1.1.tgz#f257d5271268932a89d7392679ce4db89d7154af" + resolved "https://registry.yarnpkg.com/ember-export-application-global/-/ember-export-application-global-1.1.1.tgz#f257d5271268932a89d7392679ce4db89d7154af" dependencies: ember-cli-babel "^5.1.10" ember-inflector@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-2.0.1.tgz#e9ac469ffa17992a43276bb1c9b8d87992b10d37" + resolved "https://registry.yarnpkg.com/ember-inflector/-/ember-inflector-2.0.1.tgz#e9ac469ffa17992a43276bb1c9b8d87992b10d37" dependencies: ember-cli-babel "^6.0.0" ember-load-initializers@^0.6.0: version "0.6.3" - resolved "https://registry.npmjs.org/ember-load-initializers/-/ember-load-initializers-0.6.3.tgz#f47396ad271ba77294068c98f992a5f19705441a" + resolved "https://registry.yarnpkg.com/ember-load-initializers/-/ember-load-initializers-0.6.3.tgz#f47396ad271ba77294068c98f992a5f19705441a" dependencies: ember-cli-babel "^5.1.6" ember-publisher@0.0.7: version "0.0.7" - resolved "https://registry.npmjs.org/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" + resolved "https://registry.yarnpkg.com/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" dependencies: aws-sdk "^2.0.9" ember-qunit@^0.4.18: version "0.4.24" - resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-0.4.24.tgz#b54cf6688c442d07eacea47c3285879cdd7c2163" + resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-0.4.24.tgz#b54cf6688c442d07eacea47c3285879cdd7c2163" dependencies: ember-test-helpers "^0.5.32" ember-resolver@^4.1.0: version "4.5.0" - resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-4.5.0.tgz#9248bf534dfc197fafe3118fff538d436078bf99" + resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-4.5.0.tgz#9248bf534dfc197fafe3118fff538d436078bf99" dependencies: "@glimmer/resolver" "^0.4.1" babel-plugin-debug-macros "^0.1.10" @@ -2650,26 +2620,30 @@ ember-resolver@^4.1.0: ember-cli-version-checker "^2.0.0" resolve "^1.3.3" -ember-rfc176-data@^0.2.0, ember-rfc176-data@^0.2.7: +ember-rfc176-data@^0.2.0: version "0.2.7" resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.2.7.tgz#bd355bc9b473e08096b518784170a23388bc973b" +ember-rfc176-data@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.0.tgz#6aee728cb521c5f80710990965027b9c320f6f08" + ember-router-generator@^1.0.0: version "1.2.3" - resolved "https://registry.npmjs.org/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" + resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" dependencies: recast "^0.11.3" ember-runtime-enumerable-includes-polyfill@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-2.0.0.tgz#6e9ba118bc909d1d7762de1b03a550d8955308a9" + resolved "https://registry.yarnpkg.com/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-2.0.0.tgz#6e9ba118bc909d1d7762de1b03a550d8955308a9" dependencies: ember-cli-babel "^6.0.0" ember-cli-version-checker "^1.1.6" ember-source@~2.11.0: version "2.11.3" - resolved "https://registry.npmjs.org/ember-source/-/ember-source-2.11.3.tgz#12c50cc2b4a7f8ae8c5daa3a72fb09415476c510" + resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-2.11.3.tgz#12c50cc2b4a7f8ae8c5daa3a72fb09415476c510" dependencies: broccoli-funnel "^1.0.6" broccoli-merge-trees "^1.1.4" @@ -2687,13 +2661,13 @@ ember-source@~2.11.0: ember-test-helpers@^0.5.32: version "0.5.34" - resolved "https://registry.npmjs.org/ember-test-helpers/-/ember-test-helpers-0.5.34.tgz#c8439108d1cba1d7d838c212208a5c4061471b83" + resolved "https://registry.yarnpkg.com/ember-test-helpers/-/ember-test-helpers-0.5.34.tgz#c8439108d1cba1d7d838c212208a5c4061471b83" dependencies: klassy "^0.1.3" ember-try-config@^2.0.1: version "2.1.0" - resolved "https://registry.npmjs.org/ember-try-config/-/ember-try-config-2.1.0.tgz#e0e156229a542346a58ee6f6ad605104c98edfe0" + resolved "https://registry.yarnpkg.com/ember-try-config/-/ember-try-config-2.1.0.tgz#e0e156229a542346a58ee6f6ad605104c98edfe0" dependencies: lodash "^4.6.1" node-fetch "^1.3.3" @@ -2702,7 +2676,7 @@ ember-try-config@^2.0.1: ember-try@^0.2.15: version "0.2.17" - resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.17.tgz#0ffff687630291b4cf94f5b196e728c1a92d8aec" + resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.17.tgz#0ffff687630291b4cf94f5b196e728c1a92d8aec" dependencies: chalk "^1.0.0" cli-table2 "^0.2.0" @@ -2720,7 +2694,7 @@ ember-try@^0.2.15: ember-watson@^0.7.0: version "0.7.0" - resolved "https://registry.npmjs.org/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" + resolved "https://registry.yarnpkg.com/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" dependencies: babel-core "^5.8.22" chalk "^1.0.0" @@ -2732,17 +2706,17 @@ ember-watson@^0.7.0: encodeurl@~1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" encoding@^0.1.11: version "0.1.12" - resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" dependencies: iconv-lite "~0.4.13" engine.io-client@1.8.0: version "1.8.0" - resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.0.tgz#7b730e4127414087596d9be3c88d2bc5fdb6cf5c" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.0.tgz#7b730e4127414087596d9be3c88d2bc5fdb6cf5c" dependencies: component-emitter "1.2.1" component-inherit "0.0.3" @@ -2759,7 +2733,7 @@ engine.io-client@1.8.0: engine.io-parser@1.3.1: version "1.3.1" - resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" dependencies: after "0.8.1" arraybuffer.slice "0.0.6" @@ -2770,7 +2744,7 @@ engine.io-parser@1.3.1: engine.io@1.8.0: version "1.8.0" - resolved "https://registry.npmjs.org/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" dependencies: accepts "1.3.3" base64id "0.1.0" @@ -2781,43 +2755,43 @@ engine.io@1.8.0: ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" + resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" entities@~1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" error-ex@^1.2.0: version "1.3.1" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" dependencies: is-arrayish "^0.2.1" error@^7.0.0: version "7.0.2" - resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" + resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" dependencies: string-template "~0.2.1" xtend "~4.0.0" es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.30" - resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.30.tgz#7141a16836697dbabfaaaeee41495ce29f52c939" + version "0.10.31" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.31.tgz#7bb938c95a7f1b9f728092dc09c41edcc398eefe" dependencies: - es6-iterator "2" - es6-symbol "~3.1" + es6-iterator "~2.0.1" + es6-symbol "~3.1.1" -es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: +es6-iterator@^2.0.1, es6-iterator@~2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" dependencies: d "1" es5-ext "^0.10.14" es6-symbol "^3.1" -es6-map@^0.1.3, es6-map@^0.1.4: +es6-map@^0.1.3, es6-map@^0.1.4, es6-map@^0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" dependencies: d "1" es5-ext "~0.10.14" @@ -2828,11 +2802,11 @@ es6-map@^0.1.3, es6-map@^0.1.4: es6-promise@~3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" es6-set@~0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" dependencies: d "1" es5-ext "~0.10.14" @@ -2840,16 +2814,16 @@ es6-set@~0.1.5: es6-symbol "3.1.1" event-emitter "~0.3.5" -es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: +es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" dependencies: d "1" es5-ext "~0.10.14" es6-weak-map@^2.0.1: version "2.0.2" - resolved "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" dependencies: d "1" es5-ext "^0.10.14" @@ -2858,19 +2832,19 @@ es6-weak-map@^2.0.1: escape-html@~1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" escape-string-regexp@1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" escope@^3.6.0: version "3.6.0" - resolved "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" dependencies: es6-map "^0.1.3" es6-weak-map "^2.0.1" @@ -2879,7 +2853,7 @@ escope@^3.6.0: eslint@^2.13.0: version "2.13.1" - resolved "https://registry.npmjs.org/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" dependencies: chalk "^1.1.3" concat-stream "^1.4.6" @@ -2916,87 +2890,87 @@ eslint@^2.13.0: user-home "^2.0.0" espree@^3.1.6: - version "3.5.0" - resolved "https://registry.npmjs.org/espree/-/espree-3.5.0.tgz#98358625bdd055861ea27e2867ea729faf463d8d" + version "3.5.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.1.tgz#0c988b8ab46db53100a1954ae4ba995ddd27d87e" dependencies: acorn "^5.1.1" acorn-jsx "^3.0.0" esprima-fb@~15001.1001.0-dev-harmony-fb: version "15001.1001.0-dev-harmony-fb" - resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" + resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" esprima@^1.2.2: version "1.2.5" - resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" esprima@^2.6.0: version "2.7.3" - resolved "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" esprima@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" esprima@~3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" esprima@~3.1.0: version "3.1.3" - resolved "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" esprimaq@^0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" + resolved "https://registry.yarnpkg.com/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" esrecurse@^4.1.0: version "4.2.0" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" dependencies: estraverse "^4.1.0" object-assign "^4.0.1" estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" -etag@~1.8.0, etag@~1.8.1: +etag@~1.8.1: version "1.8.1" - resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" event-emitter@~0.3.5: version "0.3.5" - resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" dependencies: d "1" es5-ext "~0.10.14" eventemitter3@1.x.x: version "1.2.0" - resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" events-to-array@^1.0.1: version "1.1.2" - resolved "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" + resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" events@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" exec-sh@^0.2.0: version "0.2.1" - resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" dependencies: merge "^1.1.3" -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" +execa@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" dependencies: cross-spawn "^5.0.1" get-stream "^3.0.0" @@ -3008,74 +2982,41 @@ execa@^0.7.0: exists-sync@0.0.3: version "0.0.3" - resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" + resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" exists-sync@0.0.4: version "0.0.4" - resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" + resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" exit-hook@^1.0.0: version "1.1.1" - resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" exit@^0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" expand-brackets@^0.1.4: version "0.1.5" - resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" dependencies: is-posix-bracket "^0.1.0" expand-range@^1.8.1: version "1.8.2" - resolved "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" dependencies: fill-range "^2.1.0" expand-tilde@^1.2.2: version "1.2.2" - resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" dependencies: os-homedir "^1.0.1" -express@^4.10.7, express@^4.12.3, express@^4.13.1: - version "4.15.4" - resolved "https://registry.npmjs.org/express/-/express-4.15.4.tgz#032e2253489cf8fce02666beca3d11ed7a2daed1" - dependencies: - accepts "~1.3.3" - array-flatten "1.1.1" - content-disposition "0.5.2" - content-type "~1.0.2" - cookie "0.3.1" - cookie-signature "1.0.6" - debug "2.6.8" - 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" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.1" - path-to-regexp "0.1.7" - proxy-addr "~1.1.5" - qs "6.5.0" - range-parser "~1.2.0" - send "0.15.4" - serve-static "1.12.4" - setprototypeof "1.0.3" - statuses "~1.3.1" - type-is "~1.6.15" - utils-merge "1.0.0" - vary "~1.1.1" - -express@^4.14.0: - version "4.16.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.16.1.tgz#6b33b560183c9b253b7b62144df33a4654ac9ed0" +express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: + version "4.16.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" dependencies: accepts "~1.3.4" array-flatten "1.1.1" @@ -3110,43 +3051,43 @@ express@^4.14.0: extend@3, extend@^3.0.0, extend@~3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" -external-editor@^1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" +external-editor@^2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.5.tgz#52c249a3981b9ba187c7cacf5beb50bf1d91a6bc" dependencies: - extend "^3.0.0" - spawn-sync "^1.0.15" - tmp "^0.0.29" + iconv-lite "^0.4.17" + jschardet "^1.4.2" + tmp "^0.0.33" extglob@^0.3.1: version "0.3.2" - resolved "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" dependencies: is-extglob "^1.0.0" fake-xml-http-request@^1.6.0: version "1.6.0" - resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-1.6.0.tgz#bd0ac79ae3e2660098282048a12c730a6f64d550" + resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-1.6.0.tgz#bd0ac79ae3e2660098282048a12c730a6f64d550" faker@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/faker/-/faker-3.1.0.tgz#0f908faf4e6ec02524e54a57e432c5c013e08c9f" + resolved "https://registry.yarnpkg.com/faker/-/faker-3.1.0.tgz#0f908faf4e6ec02524e54a57e432c5c013e08c9f" fast-levenshtein@~2.0.4: version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" + resolved "https://registry.yarnpkg.com/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" dependencies: blank-object "^1.0.1" fast-sourcemap-concat@^1.0.1: version "1.2.3" - resolved "https://registry.npmjs.org/fast-sourcemap-concat/-/fast-sourcemap-concat-1.2.3.tgz#22f14e92d739e37920334376ec8433bf675eaa04" + resolved "https://registry.yarnpkg.com/fast-sourcemap-concat/-/fast-sourcemap-concat-1.2.3.tgz#22f14e92d739e37920334376ec8433bf675eaa04" dependencies: chalk "^0.5.1" fs-extra "^0.30.0" @@ -3160,41 +3101,47 @@ fast-sourcemap-concat@^1.0.1: faye-websocket@~0.10.0: version "0.10.0" - resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" dependencies: websocket-driver ">=0.5.1" fb-watchman@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" dependencies: bser "^2.0.0" figures@^1.3.5: version "1.7.0" - resolved "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" dependencies: escape-string-regexp "^1.0.5" object-assign "^4.1.0" +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + dependencies: + escape-string-regexp "^1.0.5" + file-entry-cache@^1.1.1: version "1.3.1" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" dependencies: flat-cache "^1.2.1" object-assign "^4.0.1" filename-regex@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" filesize@^3.1.3: version "3.5.10" - resolved "https://registry.npmjs.org/filesize/-/filesize-3.5.10.tgz#fc8fa23ddb4ef9e5e0ab6e1e64f679a24a56761f" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.10.tgz#fc8fa23ddb4ef9e5e0ab6e1e64f679a24a56761f" fill-range@^2.1.0: version "2.2.3" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" dependencies: is-number "^2.1.0" isobject "^2.0.0" @@ -3202,15 +3149,15 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" -finalhandler@1.0.4, finalhandler@~1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.4.tgz#18574f2e7c4b98b8ae3b230c21f201f31bdb3fb7" +finalhandler@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.6.tgz#007aea33d1a4d3e42017f624848ad58d212f814f" dependencies: - debug "2.6.8" + debug "2.6.9" encodeurl "~1.0.1" escape-html "~1.0.3" on-finished "~2.3.0" - parseurl "~1.3.1" + parseurl "~1.3.2" statuses "~1.3.1" unpipe "~1.0.0" @@ -3228,24 +3175,24 @@ finalhandler@1.1.0: find-index@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" + resolved "https://registry.yarnpkg.com/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" find-up@^1.0.0: version "1.1.2" - resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" find-up@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" dependencies: locate-path "^2.0.0" findup-sync@^0.4.2: version "0.4.3" - resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" dependencies: detect-file "^0.1.0" is-glob "^2.0.1" @@ -3254,7 +3201,7 @@ findup-sync@^0.4.2: findup-sync@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-1.0.0.tgz#6f7e4b57b6ee3a4037b4414eaedea3f58f71e0ec" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-1.0.0.tgz#6f7e4b57b6ee3a4037b4414eaedea3f58f71e0ec" dependencies: detect-file "^0.1.0" is-glob "^2.0.1" @@ -3263,14 +3210,14 @@ findup-sync@^1.0.0: findup@^0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" + resolved "https://registry.yarnpkg.com/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" dependencies: colors "~0.6.0-1" commander "~2.1.0" fireworm@^0.7.0: version "0.7.1" - resolved "https://registry.npmjs.org/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" + resolved "https://registry.yarnpkg.com/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" dependencies: async "~0.2.9" is-type "0.0.1" @@ -3279,14 +3226,15 @@ fireworm@^0.7.0: minimatch "^3.0.2" fixturify@^0.3.2: - version "0.3.3" - resolved "https://registry.npmjs.org/fixturify/-/fixturify-0.3.3.tgz#842eaa120564c9881e099ed06dc082a81e97fa71" + version "0.3.4" + resolved "https://registry.yarnpkg.com/fixturify/-/fixturify-0.3.4.tgz#c676de404a7f8ee8e64d0b76118e62ec95ab7b25" dependencies: fs-extra "^0.30.0" + matcher-collection "^1.0.4" flat-cache@^1.2.1: - version "1.2.2" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" + version "1.3.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" dependencies: circular-json "^0.3.1" del "^2.0.2" @@ -3295,56 +3243,48 @@ flat-cache@^1.2.1: follow-redirects@0.0.7: version "0.0.7" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" dependencies: debug "^2.2.0" stream-consume "^0.1.0" for-in@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" for-own@^0.1.4: version "0.1.5" - resolved "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" dependencies: for-in "^1.0.1" forever-agent@~0.5.0: version "0.5.2" - resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" form-data@~0.1.0: version "0.1.4" - resolved "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" dependencies: async "~0.9.0" combined-stream "~0.0.4" mime "~1.2.11" -forwarded@~0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.1.tgz#8a4e30c640b05395399a3549c730257728048961" - forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" -fresh@0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" - fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" fs-exists-sync@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" fs-extra@^0.24.0: version "0.24.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -3353,7 +3293,7 @@ fs-extra@^0.24.0: fs-extra@^0.26.0, fs-extra@^0.26.7: version "0.26.7" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -3363,7 +3303,7 @@ fs-extra@^0.26.0, fs-extra@^0.26.7: fs-extra@^0.30.0: version "0.30.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -3373,7 +3313,7 @@ fs-extra@^0.30.0: fs-extra@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -3381,26 +3321,26 @@ fs-extra@^1.0.0: fs-extra@^2.0.0: version "2.1.2" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" -fs-extra@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291" +fs-extra@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b" dependencies: graceful-fs "^4.1.2" - jsonfile "^3.0.0" + jsonfile "^4.0.0" universalify "^0.1.0" fs-readdir-recursive@^0.1.0: version "0.1.2" - resolved "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" fs-sync@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" + resolved "https://registry.yarnpkg.com/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" dependencies: glob "^7.1.0" iconv-lite "^0.4.13" @@ -3410,7 +3350,7 @@ fs-sync@^1.0.4: fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6: version "0.5.6" - resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.6.tgz#342665749e8dca406800b672268c8f5073f3e623" + resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-0.5.6.tgz#342665749e8dca406800b672268c8f5073f3e623" dependencies: heimdalljs-logger "^0.1.7" object-assign "^4.1.0" @@ -3419,11 +3359,11 @@ fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5 fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" gauge@~2.7.3: version "2.7.4" - resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -3436,49 +3376,49 @@ gauge@~2.7.3: generate-function@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" generate-object-property@^1.1.0: version "1.2.0" - resolved "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" dependencies: is-property "^1.0.0" get-caller-file@^1.0.0, get-caller-file@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" get-stdin@^4.0.1: version "4.0.1" - resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" get-stream@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" git-repo-info@^1.1.2, git-repo-info@^1.4.1: version "1.4.1" - resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" + resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" git-repo-info@~1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.2.0.tgz#43d8513e04a24dd441330a2f7c6655a709fdbaf2" + resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.2.0.tgz#43d8513e04a24dd441330a2f7c6655a709fdbaf2" git-repo-version@0.4.1: version "0.4.1" - resolved "https://registry.npmjs.org/git-repo-version/-/git-repo-version-0.4.1.tgz#75fab9a0a4ec8470755b0eea7fdaa6f9d41453bf" + resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-0.4.1.tgz#75fab9a0a4ec8470755b0eea7fdaa6f9d41453bf" dependencies: git-repo-info "~1.2.0" git-tools@^0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" + resolved "https://registry.yarnpkg.com/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" dependencies: spawnback "~1.0.0" github@^1.1.1: version "1.4.0" - resolved "https://registry.npmjs.org/github/-/github-1.4.0.tgz#60aed8f16ffe381a3ca6dc6dba5bdd64445b7856" + resolved "https://registry.yarnpkg.com/github/-/github-1.4.0.tgz#60aed8f16ffe381a3ca6dc6dba5bdd64445b7856" dependencies: follow-redirects "0.0.7" https-proxy-agent "^1.0.0" @@ -3486,28 +3426,28 @@ github@^1.1.1: glob-base@^0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" dependencies: glob-parent "^2.0.0" is-glob "^2.0.0" glob-parent@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" dependencies: is-glob "^2.0.0" glob@3.2.3: version "3.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" + resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" dependencies: graceful-fs "~2.0.0" inherits "2" minimatch "~0.2.11" -glob@5.0.13, glob@^5.0.10: +glob@5.0.13: version "5.0.13" - resolved "https://registry.npmjs.org/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" dependencies: inflight "^1.0.4" inherits "2" @@ -3517,7 +3457,7 @@ glob@5.0.13, glob@^5.0.10: glob@7.1.1: version "7.1.1" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -3528,16 +3468,16 @@ glob@7.1.1: glob@^4.3.2: version "4.5.3" - resolved "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" + resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" dependencies: inflight "^1.0.4" inherits "2" minimatch "^2.0.1" once "^1.3.0" -glob@^5.0.15: +glob@^5.0.10, glob@^5.0.15: version "5.0.15" - resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: inflight "^1.0.4" inherits "2" @@ -3547,7 +3487,7 @@ glob@^5.0.15: glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1: version "7.1.2" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -3558,14 +3498,14 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1: global-modules@^0.2.3: version "0.2.3" - resolved "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" dependencies: global-prefix "^0.1.4" is-windows "^0.2.0" global-prefix@^0.1.4: version "0.1.5" - resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" dependencies: homedir-polyfill "^1.0.0" ini "^1.3.4" @@ -3574,15 +3514,15 @@ global-prefix@^0.1.4: globals@^6.4.0: version "6.4.1" - resolved "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" + resolved "https://registry.yarnpkg.com/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" globals@^9.18.0, globals@^9.2.0: version "9.18.0" - resolved "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" globby@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" dependencies: array-union "^1.0.1" arrify "^1.0.0" @@ -3593,27 +3533,27 @@ globby@^5.0.0: graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" graceful-fs@~2.0.0: version "2.0.3" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" "graceful-readlink@>= 1.0.0": version "1.0.1" - resolved "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" growl@1.8.1: version "1.8.1" - resolved "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428" growly@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" handlebars@^4.0.4: version "4.0.10" - resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f" dependencies: async "^1.4.0" optimist "^0.6.1" @@ -3623,43 +3563,43 @@ handlebars@^4.0.4: has-ansi@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" dependencies: ansi-regex "^0.2.0" has-ansi@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" dependencies: ansi-regex "^2.0.0" has-binary@0.1.6: version "0.1.6" - resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" + resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" dependencies: isarray "0.0.1" has-binary@0.1.7: version "0.1.7" - resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" + resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" dependencies: isarray "0.0.1" has-cors@1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" has-flag@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" has-unicode@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" hash-for-dep@^1.0.2: version "1.2.0" - resolved "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.2.0.tgz#3bdb883aef0d34e82097ef2f7109b1b401cada6b" + resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.2.0.tgz#3bdb883aef0d34e82097ef2f7109b1b401cada6b" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" heimdalljs "^0.2.3" @@ -3668,7 +3608,7 @@ hash-for-dep@^1.0.2: hawk@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" dependencies: boom "0.4.x" cryptiles "0.2.x" @@ -3677,7 +3617,7 @@ hawk@1.1.1: heimdall-query@^0.0.5: version "0.0.5" - resolved "https://registry.npmjs.org/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" + resolved "https://registry.yarnpkg.com/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" dependencies: chalk "^1.1.1" chrome-debugging-client "^0.2.4" @@ -3689,65 +3629,65 @@ heimdall-query@^0.0.5: heimdalljs-fs-monitor@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.1.0.tgz#d404a65688c6714c485469ed3495da4853440272" + resolved "https://registry.yarnpkg.com/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.1.0.tgz#d404a65688c6714c485469ed3495da4853440272" dependencies: heimdalljs "^0.2.0" heimdalljs-logger "^0.1.7" heimdalljs-graph@^0.3.1: version "0.3.3" - resolved "https://registry.npmjs.org/heimdalljs-graph/-/heimdalljs-graph-0.3.3.tgz#ea801dbba659c8d522fe1cb83b2d605726e4918f" + resolved "https://registry.yarnpkg.com/heimdalljs-graph/-/heimdalljs-graph-0.3.3.tgz#ea801dbba659c8d522fe1cb83b2d605726e4918f" heimdalljs-logger@^0.1.7: version "0.1.9" - resolved "https://registry.npmjs.org/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz#d76ada4e45b7bb6f786fc9c010a68eb2e2faf176" + resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz#d76ada4e45b7bb6f786fc9c010a68eb2e2faf176" dependencies: debug "^2.2.0" heimdalljs "^0.2.0" heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3: version "0.2.5" - resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.2.5.tgz#6aa54308eee793b642cff9cf94781445f37730ac" + resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.5.tgz#6aa54308eee793b642cff9cf94781445f37730ac" dependencies: rsvp "~3.2.1" heimdalljs@^0.3.0: version "0.3.3" - resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" + resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" dependencies: rsvp "~3.2.1" hoek@0.9.x: version "0.9.1" - resolved "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" home-or-tmp@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" dependencies: os-tmpdir "^1.0.1" user-home "^1.1.1" home-or-tmp@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.1" homedir-polyfill@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" dependencies: parse-passwd "^1.0.0" hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: version "2.5.0" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" http-errors@1.6.2, http-errors@~1.6.2: version "1.6.2" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" dependencies: depd "1.1.1" inherits "2.0.3" @@ -3755,19 +3695,19 @@ http-errors@1.6.2, http-errors@~1.6.2: statuses ">= 1.3.1 < 2" http-parser-js@>=0.4.0: - version "0.4.6" - resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.6.tgz#195273f58704c452d671076be201329dd341dc55" + version "0.4.9" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.9.tgz#ea1a04fb64adff0242e9974f297dd4c3cad271e1" http-proxy@^1.13.1, http-proxy@^1.9.0: version "1.16.2" - resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" dependencies: eventemitter3 "1.x.x" requires-port "1.x.x" http-signature@~0.10.0: version "0.10.1" - resolved "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" dependencies: asn1 "0.1.11" assert-plus "^0.1.5" @@ -3775,62 +3715,62 @@ http-signature@~0.10.0: https-proxy-agent@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" dependencies: agent-base "2" debug "2" extend "3" -iconv-lite@0.4.19, iconv-lite@^0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13: +iconv-lite@0.4.19, iconv-lite@^0.4.13, iconv-lite@^0.4.17, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.19" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" ieee754@^1.1.4: version "1.1.8" - resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" ignore@^3.1.2: version "3.3.5" - resolved "https://registry.npmjs.org/ignore/-/ignore-3.3.5.tgz#c4e715455f6073a8d7e5dae72d2fc9d71663dba6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.5.tgz#c4e715455f6073a8d7e5dae72d2fc9d71663dba6" immediate@~3.0.5: version "3.0.6" - resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" indexof@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" inflected@^1.1.6: version "1.1.7" - resolved "https://registry.npmjs.org/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" + resolved "https://registry.yarnpkg.com/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" inflection@^1.7.0, inflection@^1.7.1, inflection@^1.8.0: version "1.12.0" - resolved "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" inflight@^1.0.4: version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" dependencies: once "^1.3.0" wrappy "1" inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" ini@^1.3.4: version "1.3.4" - resolved "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" inline-source-map-comment@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" + resolved "https://registry.yarnpkg.com/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" dependencies: chalk "^1.0.0" get-stdin "^4.0.1" @@ -3840,7 +3780,7 @@ inline-source-map-comment@^1.0.5: inquirer@^0.12.0: version "0.12.0" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" dependencies: ansi-escapes "^1.1.0" ansi-regex "^2.0.0" @@ -3856,38 +3796,34 @@ inquirer@^0.12.0: strip-ansi "^3.0.0" through "^2.3.6" -inquirer@^1.2.3: - version "1.2.3" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918" +inquirer@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" dependencies: - ansi-escapes "^1.1.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" cli-width "^2.0.0" - external-editor "^1.1.0" - figures "^1.3.5" + external-editor "^2.0.4" + figures "^2.0.0" lodash "^4.3.0" - mute-stream "0.0.6" - pinkie-promise "^2.0.0" + mute-stream "0.0.7" run-async "^2.2.0" - rx "^4.1.0" - string-width "^1.0.1" - strip-ansi "^3.0.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" through "^2.3.6" invariant@^2.2.2: version "2.2.2" - resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" dependencies: loose-envify "^1.0.0" invert-kv@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - -ipaddr.js@1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz#296aca878a821816e5b85d0a285a99bcff4582f0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" ipaddr.js@1.5.2: version "1.5.2" @@ -3895,75 +3831,75 @@ ipaddr.js@1.5.2: is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" is-buffer@^1.1.5: version "1.1.5" - resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" is-builtin-module@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" dependencies: builtin-modules "^1.0.0" is-dotfile@^1.0.0: version "1.0.3" - resolved "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" is-equal-shallow@^0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" dependencies: is-primitive "^2.0.0" is-extendable@^0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" is-extglob@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" is-finite@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" is-git-url@^0.2.0: version "0.2.3" - resolved "https://registry.npmjs.org/is-git-url/-/is-git-url-0.2.3.tgz#445200d6fbd6da028fb5e01440d9afc93f3ccb64" + resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-0.2.3.tgz#445200d6fbd6da028fb5e01440d9afc93f3ccb64" is-git-url@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-git-url/-/is-git-url-1.0.0.tgz#53f684cd143285b52c3244b4e6f28253527af66b" + resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-1.0.0.tgz#53f684cd143285b52c3244b4e6f28253527af66b" is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" dependencies: is-extglob "^1.0.0" is-integer@^1.0.4: version "1.0.7" - resolved "https://registry.npmjs.org/is-integer/-/is-integer-1.0.7.tgz#6bde81aacddf78b659b6629d629cadc51a886d5c" + resolved "https://registry.yarnpkg.com/is-integer/-/is-integer-1.0.7.tgz#6bde81aacddf78b659b6629d629cadc51a886d5c" dependencies: is-finite "^1.0.0" is-my-json-valid@^2.10.0: version "2.16.1" - resolved "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz#5a846777e2c2620d1e69104e5d3a03b1f6088f11" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz#5a846777e2c2620d1e69104e5d3a03b1f6088f11" dependencies: generate-function "^2.0.0" generate-object-property "^1.1.0" @@ -3972,101 +3908,109 @@ is-my-json-valid@^2.10.0: is-number@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" dependencies: kind-of "^3.0.2" is-number@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" dependencies: kind-of "^3.0.2" is-obj@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" is-path-cwd@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" is-path-in-cwd@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" dependencies: is-path-inside "^1.0.0" is-path-inside@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" dependencies: path-is-inside "^1.0.1" +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + is-posix-bracket@^0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" is-primitive@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" is-promise@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" is-property@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" is-resolvable@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" dependencies: tryit "^1.0.1" is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" is-type@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" + resolved "https://registry.yarnpkg.com/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" dependencies: core-util-is "~1.0.0" is-utf8@^0.2.0: version "0.2.1" - resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" is-windows@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" isarray@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" isbinaryfile@^3.0.0: version "3.0.2" - resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" isexe@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" isobject@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" dependencies: isarray "1.0.0" istextorbinary@2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" + resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" dependencies: binaryextensions "1 || 2" editions "^1.1.1" @@ -4074,53 +4018,57 @@ istextorbinary@2.1.0: jade@0.26.3: version "0.26.3" - resolved "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" + resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" dependencies: commander "0.6.1" mkdirp "0.3.0" jmespath@0.15.0: version "0.15.0" - resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" jquery@^3.1.1: version "3.2.1" - resolved "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787" js-string-escape@^1.0.0, js-string-escape@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" + resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" js-tokens@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: version "3.10.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" dependencies: argparse "^1.0.7" esprima "^4.0.0" +jschardet@^1.4.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.5.1.tgz#c519f629f86b3a5bedba58a88d311309eec097f9" + jsesc@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" jsesc@~0.3.x: version "0.3.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.3.0.tgz#1bf5ee63b4539fe2e26d0c1e99c240b97a457972" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.3.0.tgz#1bf5ee63b4539fe2e26d0c1e99c240b97a457972" jsesc@~0.5.0: version "0.5.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" json-api-mock-server@0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/json-api-mock-server/-/json-api-mock-server-0.1.1.tgz#00acb22ac58127e87fa9a172159cd8ed558e8106" + resolved "https://registry.yarnpkg.com/json-api-mock-server/-/json-api-mock-server-0.1.1.tgz#00acb22ac58127e87fa9a172159cd8ed558e8106" dependencies: body-parser "^1.15.2" chalk "^1.1.1" @@ -4131,56 +4079,56 @@ json-api-mock-server@0.1.1: json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: jsonify "~0.0.0" json-stringify-safe@~5.0.0: version "5.0.1" - resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" json3@3.3.2: version "3.3.2" - resolved "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" json5@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" json5@^0.5.1: version "0.5.1" - resolved "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" jsonapi-validator@^2.1.1: version "2.2.0" - resolved "https://registry.npmjs.org/jsonapi-validator/-/jsonapi-validator-2.2.0.tgz#07f9bdb6d118c1e728fa77280605fa9b527f8c66" + resolved "https://registry.yarnpkg.com/jsonapi-validator/-/jsonapi-validator-2.2.0.tgz#07f9bdb6d118c1e728fa77280605fa9b527f8c66" dependencies: ajv "^4.1.3" yargs "^5.0.0" jsonfile@^2.1.0: version "2.4.0" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" optionalDependencies: graceful-fs "^4.1.6" -jsonfile@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" optionalDependencies: graceful-fs "^4.1.6" jsonify@~0.0.0: version "0.0.0" - resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" jsonpointer@^4.0.0: version "4.0.1" - resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" jszip@^3.1.3: version "3.1.4" - resolved "https://registry.npmjs.org/jszip/-/jszip-3.1.4.tgz#fc323fe41bb1730348d20dd022aa4d8b57cbbcf9" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.1.4.tgz#fc323fe41bb1730348d20dd022aa4d8b57cbbcf9" dependencies: core-js "~2.3.0" es6-promise "~3.0.2" @@ -4190,39 +4138,39 @@ jszip@^3.1.3: kind-of@^3.0.2: version "3.2.2" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" dependencies: is-buffer "^1.1.5" klassy@^0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/klassy/-/klassy-0.1.3.tgz#c31d5756d583197d75f582b6e692872be497067f" + resolved "https://registry.yarnpkg.com/klassy/-/klassy-0.1.3.tgz#c31d5756d583197d75f582b6e692872be497067f" klaw@^1.0.0: version "1.3.1" - resolved "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" optionalDependencies: graceful-fs "^4.1.9" lazy-cache@^1.0.3: version "1.0.4" - resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" lcid@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" dependencies: invert-kv "^1.0.0" leek@0.0.24: version "0.0.24" - resolved "https://registry.npmjs.org/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" + resolved "https://registry.yarnpkg.com/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" dependencies: debug "^2.1.0" lodash.assign "^3.2.0" @@ -4230,40 +4178,40 @@ leek@0.0.24: leven@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" + resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" levn@^0.3.0, levn@~0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" lie@~3.1.0: version "3.1.1" - resolved "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" dependencies: immediate "~3.0.5" linkify-it@^2.0.0: version "2.0.3" - resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" dependencies: uc.micro "^1.0.1" linkify-it@~1.2.0: version "1.2.4" - resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" dependencies: uc.micro "^1.0.1" livereload-js@^2.2.2: version "2.2.2" - resolved "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" + resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" load-json-file@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -4273,29 +4221,29 @@ load-json-file@^1.0.0: loader.js@^4.5.0: version "4.6.0" - resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.6.0.tgz#b965663ddbe2d80da482454cb865efe496e93e22" + resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.6.0.tgz#b965663ddbe2d80da482454cb865efe496e93e22" locate-path@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" dependencies: p-locate "^2.0.0" path-exists "^3.0.0" lodash-node@^3.2.0: version "3.10.2" - resolved "https://registry.npmjs.org/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" + resolved "https://registry.yarnpkg.com/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" lodash._baseassign@^3.0.0: version "3.2.0" - resolved "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" dependencies: lodash._basecopy "^3.0.0" lodash.keys "^3.0.0" lodash._basebind@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._basebind/-/lodash._basebind-2.3.0.tgz#2b5bc452a0e106143b21869f233bdb587417d248" + resolved "https://registry.yarnpkg.com/lodash._basebind/-/lodash._basebind-2.3.0.tgz#2b5bc452a0e106143b21869f233bdb587417d248" dependencies: lodash._basecreate "~2.3.0" lodash._setbinddata "~2.3.0" @@ -4303,11 +4251,11 @@ lodash._basebind@~2.3.0: lodash._basecopy@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" lodash._basecreate@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz#9b88a86a4dcff7b7f3c61d83a2fcfc0671ec9de0" + resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz#9b88a86a4dcff7b7f3c61d83a2fcfc0671ec9de0" dependencies: lodash._renative "~2.3.0" lodash.isobject "~2.3.0" @@ -4315,7 +4263,7 @@ lodash._basecreate@~2.3.0: lodash._basecreatecallback@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz#37b2ab17591a339e988db3259fcd46019d7ac362" + resolved "https://registry.yarnpkg.com/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz#37b2ab17591a339e988db3259fcd46019d7ac362" dependencies: lodash._setbinddata "~2.3.0" lodash.bind "~2.3.0" @@ -4324,7 +4272,7 @@ lodash._basecreatecallback@~2.3.0: lodash._basecreatewrapper@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz#aa0c61ad96044c3933376131483a9759c3651247" + resolved "https://registry.yarnpkg.com/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz#aa0c61ad96044c3933376131483a9759c3651247" dependencies: lodash._basecreate "~2.3.0" lodash._setbinddata "~2.3.0" @@ -4333,18 +4281,18 @@ lodash._basecreatewrapper@~2.3.0: lodash._baseflatten@^3.0.0: version "3.1.4" - resolved "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" + resolved "https://registry.yarnpkg.com/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" dependencies: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" lodash._bindcallback@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" lodash._createassigner@^3.0.0: version "3.1.1" - resolved "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" dependencies: lodash._bindcallback "^3.0.0" lodash._isiterateecall "^3.0.0" @@ -4352,7 +4300,7 @@ lodash._createassigner@^3.0.0: lodash._createwrapper@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" + resolved "https://registry.yarnpkg.com/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" dependencies: lodash._basebind "~2.3.0" lodash._basecreatewrapper "~2.3.0" @@ -4360,69 +4308,69 @@ lodash._createwrapper@~2.3.0: lodash._escapehtmlchar@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.3.0.tgz#d03da6bd82eedf38dc0a5b503d740ecd0e894592" + resolved "https://registry.yarnpkg.com/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.3.0.tgz#d03da6bd82eedf38dc0a5b503d740ecd0e894592" dependencies: lodash._htmlescapes "~2.3.0" lodash._escapestringchar@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.3.0.tgz#cce73ae60fc6da55d2bf8a0679c23ca2bab149fc" + resolved "https://registry.yarnpkg.com/lodash._escapestringchar/-/lodash._escapestringchar-2.3.0.tgz#cce73ae60fc6da55d2bf8a0679c23ca2bab149fc" lodash._getnative@^3.0.0: version "3.9.1" - resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" lodash._htmlescapes@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._htmlescapes/-/lodash._htmlescapes-2.3.0.tgz#1ca98863cadf1fa1d82c84f35f31e40556a04f3a" + resolved "https://registry.yarnpkg.com/lodash._htmlescapes/-/lodash._htmlescapes-2.3.0.tgz#1ca98863cadf1fa1d82c84f35f31e40556a04f3a" lodash._isiterateecall@^3.0.0: version "3.0.9" - resolved "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" lodash._objecttypes@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz#6a3ea3987dd6eeb8021b2d5c9c303549cc2bae1e" + resolved "https://registry.yarnpkg.com/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz#6a3ea3987dd6eeb8021b2d5c9c303549cc2bae1e" lodash._reinterpolate@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-2.3.0.tgz#03ee9d85c0e55cbd590d71608a295bdda51128ec" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-2.3.0.tgz#03ee9d85c0e55cbd590d71608a295bdda51128ec" lodash._reinterpolate@~3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" lodash._renative@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._renative/-/lodash._renative-2.3.0.tgz#77d8edd4ced26dd5971f9e15a5f772e4e317fbd3" + resolved "https://registry.yarnpkg.com/lodash._renative/-/lodash._renative-2.3.0.tgz#77d8edd4ced26dd5971f9e15a5f772e4e317fbd3" lodash._reunescapedhtml@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.3.0.tgz#db920b55ac7f3ff825939aceb9ba2c231713d24d" + resolved "https://registry.yarnpkg.com/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.3.0.tgz#db920b55ac7f3ff825939aceb9ba2c231713d24d" dependencies: lodash._htmlescapes "~2.3.0" lodash.keys "~2.3.0" lodash._setbinddata@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz#e5610490acd13277d59858d95b5f2727f1508f04" + resolved "https://registry.yarnpkg.com/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz#e5610490acd13277d59858d95b5f2727f1508f04" dependencies: lodash._renative "~2.3.0" lodash.noop "~2.3.0" lodash._shimkeys@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz#611f93149e3e6c721096b48769ef29537ada8ba9" + resolved "https://registry.yarnpkg.com/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz#611f93149e3e6c721096b48769ef29537ada8ba9" dependencies: lodash._objecttypes "~2.3.0" lodash._slice@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._slice/-/lodash._slice-2.3.0.tgz#147198132859972e4680ca29a5992c855669aa5c" + resolved "https://registry.yarnpkg.com/lodash._slice/-/lodash._slice-2.3.0.tgz#147198132859972e4680ca29a5992c855669aa5c" lodash.assign@^3.2.0: version "3.2.0" - resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" dependencies: lodash._baseassign "^3.0.0" lodash._createassigner "^3.0.0" @@ -4430,15 +4378,15 @@ lodash.assign@^3.2.0: lodash.assign@^4.1.0, lodash.assign@^4.2.0: version "4.2.0" - resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" lodash.assignin@^4.1.0: version "4.2.0" - resolved "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" lodash.bind@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.bind/-/lodash.bind-2.3.0.tgz#c2a8e18b68e5ecc152e2b168266116fea5b016cc" + resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-2.3.0.tgz#c2a8e18b68e5ecc152e2b168266116fea5b016cc" dependencies: lodash._createwrapper "~2.3.0" lodash._renative "~2.3.0" @@ -4446,24 +4394,24 @@ lodash.bind@~2.3.0: lodash.clonedeep@^4.4.1: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" lodash.debounce@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" dependencies: lodash._getnative "^3.0.0" lodash.defaults@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-2.3.0.tgz#a832b001f138f3bb9721c2819a2a7cc5ae21ed25" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-2.3.0.tgz#a832b001f138f3bb9721c2819a2a7cc5ae21ed25" dependencies: lodash._objecttypes "~2.3.0" lodash.keys "~2.3.0" lodash.escape@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.escape/-/lodash.escape-2.3.0.tgz#844c38c58f844e1362ebe96726159b62cf5f2a58" + resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-2.3.0.tgz#844c38c58f844e1362ebe96726159b62cf5f2a58" dependencies: lodash._escapehtmlchar "~2.3.0" lodash._reunescapedhtml "~2.3.0" @@ -4471,25 +4419,25 @@ lodash.escape@~2.3.0: lodash.find@^4.5.1: version "4.6.0" - resolved "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" + resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" lodash.flatten@^3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" dependencies: lodash._baseflatten "^3.0.0" lodash._isiterateecall "^3.0.0" lodash.foreach@~2.3.x: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-2.3.0.tgz#083404c91e846ee77245fdf9d76519c68b2af168" + resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-2.3.0.tgz#083404c91e846ee77245fdf9d76519c68b2af168" dependencies: lodash._basecreatecallback "~2.3.0" lodash.forown "~2.3.0" lodash.forown@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.forown/-/lodash.forown-2.3.0.tgz#24fb4aaf800d45fc2dc60bfec3ce04c836a3ad7f" + resolved "https://registry.yarnpkg.com/lodash.forown/-/lodash.forown-2.3.0.tgz#24fb4aaf800d45fc2dc60bfec3ce04c836a3ad7f" dependencies: lodash._basecreatecallback "~2.3.0" lodash._objecttypes "~2.3.0" @@ -4497,29 +4445,29 @@ lodash.forown@~2.3.0: lodash.identity@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.identity/-/lodash.identity-2.3.0.tgz#6b01a210c9485355c2a913b48b6711219a173ded" + resolved "https://registry.yarnpkg.com/lodash.identity/-/lodash.identity-2.3.0.tgz#6b01a210c9485355c2a913b48b6711219a173ded" lodash.isarguments@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" lodash.isarray@^3.0.0: version "3.0.4" - resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" lodash.isfunction@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz#6b2973e47a647cf12e70d676aea13643706e5267" + resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz#6b2973e47a647cf12e70d676aea13643706e5267" lodash.isobject@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.3.0.tgz#2e16d3fc583da9831968953f2d8e6d73434f6799" + resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-2.3.0.tgz#2e16d3fc583da9831968953f2d8e6d73434f6799" dependencies: lodash._objecttypes "~2.3.0" lodash.keys@^3.0.0: version "3.1.2" - resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" dependencies: lodash._getnative "^3.0.0" lodash.isarguments "^3.0.0" @@ -4527,7 +4475,7 @@ lodash.keys@^3.0.0: lodash.keys@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.3.0.tgz#b350f4f92caa9f45a4a2ecf018454cf2f28ae253" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-2.3.0.tgz#b350f4f92caa9f45a4a2ecf018454cf2f28ae253" dependencies: lodash._renative "~2.3.0" lodash._shimkeys "~2.3.0" @@ -4535,36 +4483,36 @@ lodash.keys@~2.3.0: lodash.merge@^4.3.0, lodash.merge@^4.4.0, lodash.merge@^4.5.1, lodash.merge@^4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" lodash.noop@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.noop/-/lodash.noop-2.3.0.tgz#3059d628d51bbf937cd2a0b6fc3a7f212a669c2c" + resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-2.3.0.tgz#3059d628d51bbf937cd2a0b6fc3a7f212a669c2c" lodash.omit@^4.1.0: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" + resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" lodash.restparam@^3.0.0: version "3.6.1" - resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" lodash.support@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.support/-/lodash.support-2.3.0.tgz#7eaf038af4f0d6aab776b44aa6dcfc80334c9bfd" + resolved "https://registry.yarnpkg.com/lodash.support/-/lodash.support-2.3.0.tgz#7eaf038af4f0d6aab776b44aa6dcfc80334c9bfd" dependencies: lodash._renative "~2.3.0" lodash.template@^4.2.5: version "4.4.0" - resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings "^4.0.0" lodash.template@~2.3.x: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-2.3.0.tgz#4e3e29c433b4cfea675ec835e6f12391c61fd22b" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-2.3.0.tgz#4e3e29c433b4cfea675ec835e6f12391c61fd22b" dependencies: lodash._escapestringchar "~2.3.0" lodash._reinterpolate "~2.3.0" @@ -4576,79 +4524,85 @@ lodash.template@~2.3.x: lodash.templatesettings@^4.0.0: version "4.1.0" - resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-2.3.0.tgz#303d132c342710040d5a18efaa2d572fd03f8cdc" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-2.3.0.tgz#303d132c342710040d5a18efaa2d572fd03f8cdc" dependencies: lodash._reinterpolate "~2.3.0" lodash.escape "~2.3.0" lodash.uniq@^4.2.0: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" lodash.uniqby@^4.7.0: version "4.7.0" - resolved "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" + resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" lodash.values@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.values/-/lodash.values-2.3.0.tgz#ca96fbe60a20b0b0ec2ba2ba5fc6a765bd14a3ba" + resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-2.3.0.tgz#ca96fbe60a20b0b0ec2ba2ba5fc6a765bd14a3ba" dependencies: lodash.keys "~2.3.0" lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" - resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.16.1, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1: +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.16.1, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1: version "4.17.4" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +log-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" + dependencies: + chalk "^1.0.0" longest@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" loose-envify@^1.0.0: version "1.3.1" - resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: js-tokens "^3.0.0" lru-cache@2: version "2.7.3" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" lru-cache@^4.0.1: version "4.1.1" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" dependencies: pseudomap "^1.0.2" yallist "^2.1.2" make-array@^0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" + resolved "https://registry.yarnpkg.com/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" make-dir@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/make-dir/-/make-dir-1.0.0.tgz#97a011751e91dd87cfadef58832ebb04936de978" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.0.0.tgz#97a011751e91dd87cfadef58832ebb04936de978" dependencies: pify "^2.3.0" makeerror@1.0.x: version "1.0.11" - resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" dependencies: tmpl "1.0.x" markdown-it-terminal@0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/markdown-it-terminal/-/markdown-it-terminal-0.1.0.tgz#545abd8dd01c3d62353bfcea71db580b51d22bd9" + resolved "https://registry.yarnpkg.com/markdown-it-terminal/-/markdown-it-terminal-0.1.0.tgz#545abd8dd01c3d62353bfcea71db580b51d22bd9" dependencies: ansi-styles "^3.0.0" cardinal "^1.0.0" @@ -4658,7 +4612,7 @@ markdown-it-terminal@0.1.0: markdown-it@^4.3.0: version "4.4.0" - resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" dependencies: argparse "~1.0.2" entities "~1.1.1" @@ -4668,7 +4622,7 @@ markdown-it@^4.3.0: markdown-it@^8.3.0, markdown-it@^8.3.1: version "8.4.0" - resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.0.tgz#e2400881bf171f7018ed1bd9da441dac8af6306d" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.0.tgz#e2400881bf171f7018ed1bd9da441dac8af6306d" dependencies: argparse "^1.0.7" entities "~1.1.1" @@ -4676,47 +4630,47 @@ markdown-it@^8.3.0, markdown-it@^8.3.1: mdurl "^1.0.1" uc.micro "^1.0.3" -matcher-collection@^1.0.0: - version "1.0.4" - resolved "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.4.tgz#2f66ae0869996f29e43d0b62c83dd1d43e581755" +matcher-collection@^1.0.0, matcher-collection@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-1.0.5.tgz#2ee095438372cb8884f058234138c05c644ec339" dependencies: minimatch "^3.0.2" md5-hex@^1.2.1, md5-hex@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" + resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" dependencies: md5-o-matic "^0.1.1" md5-o-matic@^0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" + resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" mdn-links@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" + resolved "https://registry.yarnpkg.com/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" mdurl@^1.0.1, mdurl@~1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" media-typer@0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" memory-streams@^0.1.0: version "0.1.2" - resolved "https://registry.npmjs.org/memory-streams/-/memory-streams-0.1.2.tgz#273ff777ab60fec599b116355255282cca2c50c2" + resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.2.tgz#273ff777ab60fec599b116355255282cca2c50c2" dependencies: readable-stream "~1.0.2" merge-descriptors@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" merge-trees@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/merge-trees/-/merge-trees-1.0.1.tgz#ccbe674569787f9def17fd46e6525f5700bbd23e" + resolved "https://registry.yarnpkg.com/merge-trees/-/merge-trees-1.0.1.tgz#ccbe674569787f9def17fd46e6525f5700bbd23e" dependencies: can-symlink "^1.0.0" fs-tree-diff "^0.5.4" @@ -4727,15 +4681,15 @@ merge-trees@^1.0.1: merge@^1.1.3, merge@^1.2.0, merge@~1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" methods@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" micromatch@^2.1.5, micromatch@^2.3.7: version "2.3.11" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" dependencies: arr-diff "^2.0.0" array-unique "^0.2.1" @@ -4753,78 +4707,78 @@ micromatch@^2.1.5, micromatch@^2.3.7: "mime-db@>= 1.29.0 < 2", mime-db@~1.30.0: version "1.30.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" mime-types@~1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.16: version "2.1.17" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" dependencies: mime-db "~1.30.0" -mime@1.3.4: - version "1.3.4" - resolved "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" - -mime@1.4.1: +mime@1.4.1, mime@^1.2.11: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" -mime@^1.2.11: - version "1.4.0" - resolved "https://registry.npmjs.org/mime/-/mime-1.4.0.tgz#69e9e0db51d44f2a3b56e48b7817d7d137f1a343" - mime@~1.2.11: version "1.2.11" - resolved "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + +mimic-fn@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" "minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: brace-expansion "^1.1.7" minimatch@^2.0.1, minimatch@^2.0.3, minimatch@^2.0.8: version "2.0.10" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" dependencies: brace-expansion "^1.0.0" minimatch@~0.2.11: version "0.2.14" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" dependencies: lru-cache "2" sigmund "~1.0.0" -minimist@0.0.8, minimist@~0.0.1: +minimist@0.0.8: version "0.0.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" minimist@^1.1.0, minimist@^1.1.1: version "1.2.0" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" mkdirp@0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" mktemp@^0.4.0, mktemp@~0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" + resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" mocha-only-detector@0.0.2: version "0.0.2" - resolved "https://registry.npmjs.org/mocha-only-detector/-/mocha-only-detector-0.0.2.tgz#00f7dde6f949cf68a3cc92bdacff997b87e4b1d1" + resolved "https://registry.yarnpkg.com/mocha-only-detector/-/mocha-only-detector-0.0.2.tgz#00f7dde6f949cf68a3cc92bdacff997b87e4b1d1" dependencies: esprima "^1.2.2" esprimaq "^0.0.1" @@ -4832,7 +4786,7 @@ mocha-only-detector@0.0.2: mocha@2.4.5: version "2.4.5" - resolved "https://registry.npmjs.org/mocha/-/mocha-2.4.5.tgz#151768dd2875eb51bc8295e9800026e9f2bb398f" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.4.5.tgz#151768dd2875eb51bc8295e9800026e9f2bb398f" dependencies: commander "2.3.0" debug "2.2.0" @@ -4846,15 +4800,15 @@ mocha@2.4.5: moment-timezone@^0.3.0: version "0.3.1" - resolved "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" + resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" dependencies: moment ">= 2.6.0" "moment@>= 2.6.0": - version "2.18.1" - resolved "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" + version "2.19.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.1.tgz#56da1a2d1cbf01d38b7e1afc31c10bcfa1929167" -morgan@^1.7.0: +morgan@^1.7.0, morgan@^1.8.1: version "1.9.0" resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.0.tgz#d01fa6c65859b76fcf31b3cb53a3821a311d8051" dependencies: @@ -4864,66 +4818,56 @@ morgan@^1.7.0: on-finished "~2.3.0" on-headers "~1.0.1" -morgan@^1.8.1: - version "1.8.2" - resolved "https://registry.npmjs.org/morgan/-/morgan-1.8.2.tgz#784ac7734e4a453a9c6e6e8680a9329275c8b687" - dependencies: - basic-auth "~1.1.0" - debug "2.6.8" - depd "~1.1.0" - on-finished "~2.3.0" - on-headers "~1.0.1" - mout@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/mout/-/mout-1.0.0.tgz#9bdf1d4af57d66d47cb353a6335a3281098e1501" + version "1.1.0" + resolved "https://registry.yarnpkg.com/mout/-/mout-1.1.0.tgz#0b29d41e6a80fa9e2d4a5be9d602e1d9d02177f6" ms@0.7.1: version "0.7.1" - resolved "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" ms@0.7.2: version "0.7.2" - resolved "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" ms@2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" mustache@^2.2.1: version "2.3.0" - resolved "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" + resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" mute-stream@0.0.5: version "0.0.5" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" -mute-stream@0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" negotiator@0.6.1: version "0.6.1" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" node-fetch@^1.3.3: version "1.7.3" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" dependencies: encoding "^0.1.11" is-stream "^1.0.1" node-int64@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" node-modules-path@^1.0.0, node-modules-path@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" + resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" node-notifier@^5.0.1: version "5.1.2" - resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff" dependencies: growly "^1.3.0" semver "^5.3.0" @@ -4932,17 +4876,17 @@ node-notifier@^5.0.1: node-uuid@~1.4.0: version "1.4.8" - resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" nopt@^3.0.3, nopt@^3.0.6: version "3.0.6" - resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: abbrev "1" normalize-package-data@^2.3.2: version "2.4.0" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -4951,30 +4895,30 @@ normalize-package-data@^2.3.2: normalize-path@^2.0.0, normalize-path@^2.0.1: version "2.1.1" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: remove-trailing-separator "^1.0.1" npm-git-info@^1.0.0: version "1.0.3" - resolved "https://registry.npmjs.org/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" + resolved "https://registry.yarnpkg.com/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" npm-package-arg@^4.1.1: version "4.2.1" - resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" dependencies: hosted-git-info "^2.1.5" semver "^5.1.0" npm-run-path@^2.0.0: version "2.0.2" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" dependencies: path-key "^2.0.0" npmlog@^4.0.0: version "4.1.2" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" @@ -4983,61 +4927,67 @@ npmlog@^4.0.0: number-is-nan@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" oauth-sign@~0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" object-assign@4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" object-component@0.0.3: version "0.0.3" - resolved "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" object.omit@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" dependencies: for-own "^0.1.4" is-extendable "^0.1.1" on-finished@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" dependencies: ee-first "1.1.1" on-headers@~1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" once@^1.3.0: version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" onetime@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" optimist@^0.6.1: version "0.6.1" - resolved "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" dependencies: minimist "~0.0.1" wordwrap "~0.0.2" optionator@^0.8.1: version "0.8.2" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: deep-is "~0.1.3" fast-levenshtein "~2.0.4" @@ -5048,45 +4998,41 @@ optionator@^0.8.1: options@>=0.0.5: version "0.0.6" - resolved "https://registry.npmjs.org/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" + resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" -ora@^0.2.0: - version "0.2.3" - resolved "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz#37527d220adcd53c39b73571d754156d5db657a4" +ora@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-1.3.0.tgz#80078dd2b92a934af66a3ad72a5b910694ede51a" dependencies: chalk "^1.1.1" - cli-cursor "^1.0.2" - cli-spinners "^0.1.2" - object-assign "^4.0.1" + cli-cursor "^2.1.0" + cli-spinners "^1.0.0" + log-symbols "^1.0.2" os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" os-locale@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" dependencies: lcid "^1.0.0" -os-shim@^0.1.2: - version "0.1.3" - resolved "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" - -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" osenv@^0.1.0, osenv@^0.1.3: version "0.1.4" - resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" output-file-sync@^1.1.0: version "1.1.2" - resolved "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" dependencies: graceful-fs "^4.1.4" mkdirp "^0.5.1" @@ -5094,25 +5040,25 @@ output-file-sync@^1.1.0: p-finally@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" p-limit@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" p-locate@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" dependencies: p-limit "^1.1.0" pako@~1.0.2: version "1.0.6" - resolved "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" parse-glob@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" dependencies: glob-base "^0.3.0" is-dotfile "^1.0.0" @@ -5121,77 +5067,77 @@ parse-glob@^3.0.4: parse-json@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" dependencies: error-ex "^1.2.0" parse-passwd@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" parsejson@0.0.3: version "0.0.3" - resolved "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" + resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" dependencies: better-assert "~1.0.0" parseqs@0.0.5: version "0.0.5" - resolved "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" dependencies: better-assert "~1.0.0" parseuri@0.0.5: version "0.0.5" - resolved "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" dependencies: better-assert "~1.0.0" -parseurl@~1.3.1, parseurl@~1.3.2: +parseurl@~1.3.2: version "1.3.2" - resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" path-exists@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" path-exists@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" dependencies: pinkie-promise "^2.0.0" path-exists@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" path-is-inside@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" path-key@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" path-parse@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" path-posix@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" path-to-regexp@0.1.7: version "0.1.7" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" path-type@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" dependencies: graceful-fs "^4.1.2" pify "^2.0.0" @@ -5199,29 +5145,29 @@ path-type@^1.0.0: pify@^2.0.0, pify@^2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" pinkie-promise@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" - resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" plain-text-box-plot@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/plain-text-box-plot/-/plain-text-box-plot-0.0.1.tgz#d3b2e53071ea6706972318565761242f779c04b8" + resolved "https://registry.yarnpkg.com/plain-text-box-plot/-/plain-text-box-plot-0.0.1.tgz#d3b2e53071ea6706972318565761242f779c04b8" pluralize@^1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" portfinder@^1.0.7: version "1.0.13" - resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" dependencies: async "^1.5.2" debug "^2.2.0" @@ -5229,54 +5175,47 @@ portfinder@^1.0.7: prelude-ls@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" preserve@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" pretender@^1.4.2: - version "1.5.1" - resolved "https://registry.npmjs.org/pretender/-/pretender-1.5.1.tgz#bd9098c03d39c3bc7dcb84a28ee27e096e2e32b8" + version "1.6.0" + resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.6.0.tgz#0bb6dc9622b576772938814bc36f7cf2f86660dd" dependencies: fake-xml-http-request "^1.6.0" route-recognizer "^0.3.3" printf@^0.2.3: version "0.2.5" - resolved "https://registry.npmjs.org/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" + resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" private@^0.1.6, private@^0.1.7, private@~0.1.5: version "0.1.7" - resolved "https://registry.npmjs.org/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" process-nextick-args@~1.0.6: version "1.0.7" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" process-relative-require@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" + resolved "https://registry.yarnpkg.com/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" dependencies: node-modules-path "^1.0.0" progress@^1.1.8: version "1.1.8" - resolved "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" promise-map-series@^0.2.1: version "0.2.3" - resolved "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" + resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" dependencies: rsvp "^3.0.14" -proxy-addr@~1.1.5: - version "1.1.5" - resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz#71c0ee3b102de3f202f3b64f608d173fcba1a918" - dependencies: - forwarded "~0.1.0" - ipaddr.js "1.4.0" - proxy-addr@~2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec" @@ -5286,39 +5225,41 @@ proxy-addr@~2.0.2: pseudomap@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" punycode@1.3.2: version "1.3.2" - resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" punycode@^1.4.1: version "1.4.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" q@^1.1.2: version "1.5.0" - resolved "https://registry.npmjs.org/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" -qs@6.5.0, qs@^6.4.0: - version "6.5.0" - resolved "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz#8d04954d364def3efc55b5a0793e1e2c8b1e6e49" - -qs@6.5.1: +qs@6.5.1, qs@^6.4.0: version "6.5.1" - resolved "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" qs@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" + resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" querystring@0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +quibble@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/quibble/-/quibble-0.5.1.tgz#b7fd1fc0a9c1eea012ac9d71bcb6da8d9a5dc9e9" + dependencies: + lodash "^4.17.2" quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: version "0.1.8" - resolved "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" + resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" dependencies: mktemp "~0.4.0" rimraf "^2.5.4" @@ -5326,26 +5267,26 @@ quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quic qunit-notifications@^0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/qunit-notifications/-/qunit-notifications-0.1.1.tgz#3001afc6a6a77dfbd962ccbcddde12dec5286c09" + resolved "https://registry.yarnpkg.com/qunit-notifications/-/qunit-notifications-0.1.1.tgz#3001afc6a6a77dfbd962ccbcddde12dec5286c09" qunitjs@^1.20.0: version "1.23.1" - resolved "https://registry.npmjs.org/qunitjs/-/qunitjs-1.23.1.tgz#1971cf97ac9be01a64d2315508d2e48e6fd4e719" + resolved "https://registry.yarnpkg.com/qunitjs/-/qunitjs-1.23.1.tgz#1971cf97ac9be01a64d2315508d2e48e6fd4e719" randomatic@^1.1.3: version "1.1.7" - resolved "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" dependencies: is-number "^3.0.0" kind-of "^4.0.0" range-parser@~1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" raw-body@2.3.2: version "2.3.2" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" dependencies: bytes "3.0.0" http-errors "1.6.2" @@ -5354,21 +5295,21 @@ raw-body@2.3.2: raw-body@~1.1.0: version "1.1.7" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" dependencies: bytes "1" string_decoder "0.10" read-pkg-up@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" dependencies: find-up "^1.0.0" read-pkg "^1.0.0" read-pkg@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" @@ -5376,7 +5317,7 @@ read-pkg@^1.0.0: readable-stream@^2, readable-stream@^2.0.6, readable-stream@^2.2.2: version "2.3.3" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -5388,7 +5329,7 @@ readable-stream@^2, readable-stream@^2.0.6, readable-stream@^2.2.2: readable-stream@~1.0.2: version "1.0.34" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -5397,7 +5338,7 @@ readable-stream@~1.0.2: readable-stream@~2.0.6: version "2.0.6" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -5408,7 +5349,7 @@ readable-stream@~2.0.6: readline2@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -5416,7 +5357,7 @@ readline2@^1.0.1: recast@0.10.33: version "0.10.33" - resolved "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" dependencies: ast-types "0.8.12" esprima-fb "~15001.1001.0-dev-harmony-fb" @@ -5425,7 +5366,7 @@ recast@0.10.33: recast@^0.10.10, recast@^0.10.29: version "0.10.43" - resolved "https://registry.npmjs.org/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" dependencies: ast-types "0.8.15" esprima-fb "~15001.1001.0-dev-harmony-fb" @@ -5434,7 +5375,7 @@ recast@^0.10.10, recast@^0.10.29: recast@^0.11.17, recast@^0.11.3: version "0.11.23" - resolved "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" dependencies: ast-types "0.9.6" esprima "~3.1.0" @@ -5443,25 +5384,25 @@ recast@^0.11.17, recast@^0.11.3: redeyed@~1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" + resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" dependencies: esprima "~3.0.0" regenerate@^1.2.1: - version "1.3.2" - resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + version "1.3.3" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" regenerator-runtime@^0.10.5: version "0.10.5" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" regenerator-runtime@^0.11.0: version "0.11.0" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" regenerator-transform@^0.10.0: version "0.10.1" - resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" dependencies: babel-runtime "^6.18.0" babel-types "^6.19.0" @@ -5469,7 +5410,7 @@ regenerator-transform@^0.10.0: regenerator@0.8.40: version "0.8.40" - resolved "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" + resolved "https://registry.yarnpkg.com/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" dependencies: commoner "~0.10.3" defs "~1.1.0" @@ -5480,13 +5421,13 @@ regenerator@0.8.40: regex-cache@^0.4.2: version "0.4.4" - resolved "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" dependencies: is-equal-shallow "^0.1.3" regexpu-core@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" dependencies: regenerate "^1.2.1" regjsgen "^0.2.0" @@ -5494,7 +5435,7 @@ regexpu-core@^2.0.0: regexpu@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" + resolved "https://registry.yarnpkg.com/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" dependencies: esprima "^2.6.0" recast "^0.10.10" @@ -5504,41 +5445,41 @@ regexpu@^1.3.0: regjsgen@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" regjsparser@^0.1.4: version "0.1.5" - resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" dependencies: jsesc "~0.5.0" remove-trailing-separator@^1.0.1: version "1.1.0" - resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" repeat-element@^1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" repeat-string@^1.5.2: version "1.6.1" - resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" repeating@^1.1.0, repeating@^1.1.2: version "1.1.3" - resolved "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" dependencies: is-finite "^1.0.0" repeating@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" dependencies: is-finite "^1.0.0" request@~2.40.0: version "2.40.0" - resolved "https://registry.npmjs.org/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" + resolved "https://registry.yarnpkg.com/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" dependencies: forever-agent "~0.5.0" json-stringify-safe "~5.0.0" @@ -5557,130 +5498,143 @@ request@~2.40.0: require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" require-main-filename@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" require-uncached@^1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" dependencies: caller-path "^0.1.0" resolve-from "^1.0.0" requires-port@1.x.x: version "1.0.0" - resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" resolve-dir@^0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" dependencies: expand-tilde "^1.2.2" global-modules "^0.2.3" resolve-from@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" dependencies: path-parse "^1.0.5" restore-cursor@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" dependencies: exit-hook "^1.0.0" onetime "^1.0.0" +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + right-align@^0.1.1: version "0.1.3" - resolved "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" dependencies: align-text "^0.1.1" -rimraf@2.5.2, rimraf@^2.4.3: +rimraf@2.5.2: version "2.5.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" -rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: +rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: version "2.6.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: glob "^7.0.5" rimraf@~2.2.6: version "2.2.8" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" rollup@^0.41.4: version "0.41.6" - resolved "https://registry.npmjs.org/rollup/-/rollup-0.41.6.tgz#e0d05497877a398c104d816d2733a718a7a94e2a" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.41.6.tgz#e0d05497877a398c104d816d2733a718a7a94e2a" dependencies: source-map-support "^0.4.0" route-recognizer@^0.3.3: version "0.3.3" - resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" + resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" rsvp@4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.7.0.tgz#dc1b0b1a536f7dec9d2be45e0a12ad4197c9fd96" -rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0, rsvp@^3.5.0: - version "3.6.0" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.6.0.tgz#666dfffa715f7e10eef76f4d1e56fb2566fce5c3" +rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0, rsvp@^3.5.0, rsvp@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" rsvp@~3.0.6: version "3.0.21" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" rsvp@~3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" rsvp@~3.2.1: version "3.2.1" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" run-async@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" dependencies: once "^1.3.0" run-async@^2.2.0: version "2.3.0" - resolved "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" dependencies: is-promise "^2.1.0" +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + rx-lite@^3.1.2: version "3.1.2" - resolved "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" - -rx@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" safe-buffer@5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" safe-json-parse@~1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" + resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" sane@^1.1.1, sane@^1.4.1, sane@^1.6.0: version "1.7.0" - resolved "https://registry.npmjs.org/sane/-/sane-1.7.0.tgz#b3579bccb45c94cf20355cc81124990dfd346e30" + resolved "https://registry.yarnpkg.com/sane/-/sane-1.7.0.tgz#b3579bccb45c94cf20355cc81124990dfd346e30" dependencies: anymatch "^1.3.0" exec-sh "^0.2.0" @@ -5690,13 +5644,17 @@ sane@^1.1.1, sane@^1.4.1, sane@^1.6.0: walker "~1.0.5" watch "~0.10.0" -sax@1.2.1, sax@>=0.6.0: +sax@1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + +sax@>=0.6.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" selenium-webdriver@^3.0.0-beta-2: - version "3.5.0" - resolved "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.5.0.tgz#9036c82874e6c0f5cbff0a0f18223bc31c99cb77" + version "3.6.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc" dependencies: jszip "^3.1.3" rimraf "^2.5.4" @@ -5705,33 +5663,15 @@ selenium-webdriver@^3.0.0-beta-2: "semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0: version "5.4.1" - resolved "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" semver@^4.1.0, semver@^4.3.1: version "4.3.6" - resolved "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" semver@~5.0.1: version "5.0.3" - resolved "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" - -send@0.15.4: - version "0.15.4" - resolved "https://registry.npmjs.org/send/-/send-0.15.4.tgz#985faa3e284b0273c793364a35c6737bd93905b9" - dependencies: - debug "2.6.8" - 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" - http-errors "~1.6.2" - mime "1.3.4" - ms "2.0.0" - on-finished "~2.3.0" - range-parser "~1.2.0" - statuses "~1.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" send@0.16.1: version "0.16.1" @@ -5751,15 +5691,6 @@ send@0.16.1: range-parser "~1.2.0" statuses "~1.3.1" -serve-static@1.12.4: - version "1.12.4" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.12.4.tgz#9b6aa98eeb7253c4eedc4c1f6fdbca609901a961" - dependencies: - encodeurl "~1.0.1" - escape-html "~1.0.3" - parseurl "~1.3.1" - send "0.15.4" - serve-static@1.13.1: version "1.13.1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.1.tgz#4c57d53404a761d8f2e7c1e8a18a47dbf278a719" @@ -5771,11 +5702,11 @@ serve-static@1.13.1: set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" setprototypeof@1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" setprototypeof@1.1.0: version "1.1.0" @@ -5783,76 +5714,76 @@ setprototypeof@1.1.0: shebang-command@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" shelljs@^0.6.0: version "0.6.1" - resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" shellwords@^0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" sigmund@~1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" silent-error@^1.0.0, silent-error@^1.0.1, silent-error@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.1.0.tgz#2209706f1c850a9f1d10d0d840918b46f26e1bc9" + resolved "https://registry.yarnpkg.com/silent-error/-/silent-error-1.1.0.tgz#2209706f1c850a9f1d10d0d840918b46f26e1bc9" dependencies: debug "^2.2.0" simple-dom@^0.3.0: version "0.3.2" - resolved "https://registry.npmjs.org/simple-dom/-/simple-dom-0.3.2.tgz#0663d10f1556f1500551d518f56e3aba0871371d" + resolved "https://registry.yarnpkg.com/simple-dom/-/simple-dom-0.3.2.tgz#0663d10f1556f1500551d518f56e3aba0871371d" simple-fmt@~0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" + resolved "https://registry.yarnpkg.com/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" simple-is@~0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" + resolved "https://registry.yarnpkg.com/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" slash@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" slice-ansi@0.0.4: version "0.0.4" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" slide@^1.1.5: version "1.1.6" - resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" sntp@0.2.x: version "0.2.4" - resolved "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" dependencies: hoek "0.9.x" socket.io-adapter@0.5.0: version "0.5.0" - resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" dependencies: debug "2.3.3" socket.io-parser "2.3.1" socket.io-client@1.6.0: version "1.6.0" - resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" dependencies: backo2 "1.0.2" component-bind "1.0.0" @@ -5868,7 +5799,7 @@ socket.io-client@1.6.0: socket.io-parser@2.3.1: version "2.3.1" - resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" dependencies: component-emitter "1.1.2" debug "2.2.0" @@ -5877,7 +5808,7 @@ socket.io-parser@2.3.1: socket.io@1.6.0: version "1.6.0" - resolved "https://registry.npmjs.org/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" dependencies: debug "2.3.3" engine.io "1.8.0" @@ -5889,49 +5820,55 @@ socket.io@1.6.0: sort-object-keys@^1.1.1: version "1.1.2" - resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" + resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" sort-package-json@^1.4.0: version "1.7.1" - resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.7.1.tgz#f2e5fbffe8420cc1bb04485f4509f05e73b4c0f2" + resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.7.1.tgz#f2e5fbffe8420cc1bb04485f4509f05e73b4c0f2" dependencies: sort-object-keys "^1.1.1" source-map-support@^0.2.10: version "0.2.10" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" dependencies: source-map "0.1.32" source-map-support@^0.4.0, source-map-support@^0.4.15: version "0.4.18" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" dependencies: source-map "^0.5.6" source-map-url@^0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" -source-map@0.1.32, source-map@~0.1.x: +source-map@0.1.32: version "0.1.32" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" dependencies: amdefine ">=0.0.4" source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: version "0.4.4" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: amdefine ">=0.0.4" source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: version "0.5.7" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +source-map@~0.1.x: + version "0.1.43" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + dependencies: + amdefine ">=0.0.4" sourcemap-validator@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/sourcemap-validator/-/sourcemap-validator-1.0.5.tgz#f9b960f48c6469e288a19af305f005da3dc1df3a" + version "1.0.6" + resolved "https://registry.yarnpkg.com/sourcemap-validator/-/sourcemap-validator-1.0.6.tgz#abd2f1ecdae6a3c46c2c96c5f256705b2147c9c0" dependencies: jsesc "~0.3.x" lodash.foreach "~2.3.x" @@ -5940,169 +5877,169 @@ sourcemap-validator@^1.0.5: spawn-args@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" - -spawn-sync@^1.0.15: - version "1.0.15" - resolved "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" - dependencies: - concat-stream "^1.4.7" - os-shim "^0.1.2" + resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" spawnback@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" + resolved "https://registry.yarnpkg.com/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" spdx-correct@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" dependencies: spdx-license-ids "^1.0.2" spdx-expression-parse@~1.0.0: version "1.0.4" - resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" spdx-license-ids@^1.0.2: version "1.2.2" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" sprintf-js@^1.0.3: version "1.1.1" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" sri-toolbox@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" + resolved "https://registry.yarnpkg.com/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" stable@~0.1.3: version "0.1.6" - resolved "https://registry.npmjs.org/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10" "statuses@>= 1.3.1 < 2", statuses@~1.3.1: version "1.3.1" - resolved "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" stream-consume@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" + resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" string-template@~0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0: +string-width@^2.0.0, string-width@^2.1.0: version "2.1.1" - resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" string_decoder@~1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" dependencies: safe-buffer "~5.1.0" +stringify-object-es5@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/stringify-object-es5/-/stringify-object-es5-2.5.0.tgz#057c3c9a90a127339bb9d1704a290bb7bd0a1ec5" + dependencies: + is-plain-obj "^1.0.0" + is-regexp "^1.0.0" + stringmap@~0.2.2: version "0.2.2" - resolved "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" + resolved "https://registry.yarnpkg.com/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" stringset@~0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" + resolved "https://registry.yarnpkg.com/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" stringstream@~0.0.4: version "0.0.5" - resolved "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" strip-ansi@^0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" dependencies: ansi-regex "^0.2.1" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: ansi-regex "^2.0.0" strip-ansi@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" dependencies: ansi-regex "^3.0.0" strip-bom@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" dependencies: is-utf8 "^0.2.0" strip-bom@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" strip-eof@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" strip-json-comments@~1.0.1: version "1.0.4" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" styled_string@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" + resolved "https://registry.yarnpkg.com/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" sum-up@^1.0.1: version "1.0.3" - resolved "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" + resolved "https://registry.yarnpkg.com/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" dependencies: chalk "^1.0.0" supports-color@1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" supports-color@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" supports-color@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" supports-color@^4.0.0: version "4.4.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" dependencies: has-flag "^2.0.0" symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: version "1.1.8" - resolved "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" + resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" table@^3.7.8: version "3.8.3" - resolved "https://registry.npmjs.org/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" dependencies: ajv "^4.7.0" ajv-keywords "^1.0.0" @@ -6113,7 +6050,7 @@ table@^3.7.8: tap-parser@^5.1.0: version "5.4.0" - resolved "https://registry.npmjs.org/tap-parser/-/tap-parser-5.4.0.tgz#6907e89725d7b7fa6ae41ee2c464c3db43188aec" + resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-5.4.0.tgz#6907e89725d7b7fa6ae41ee2c464c3db43188aec" dependencies: events-to-array "^1.0.1" js-yaml "^3.2.7" @@ -6122,14 +6059,24 @@ tap-parser@^5.1.0: temp@0.8.3: version "0.8.3" - resolved "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" + resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" dependencies: os-tmpdir "^1.0.0" rimraf "~2.2.6" +testdouble@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/testdouble/-/testdouble-3.2.6.tgz#8fc47149c59f1becc795bf80f02b41de30ea4035" + dependencies: + es6-map "^0.1.5" + lodash "^4.17.4" + quibble "^0.5.1" + resolve "^1.3.3" + stringify-object-es5 "^2.5.0" + testem@^1.15.0, testem@^1.18.0: version "1.18.4" - resolved "https://registry.npmjs.org/testem/-/testem-1.18.4.tgz#e45fed922bec2f54a616c43f11922598ac97eb41" + resolved "https://registry.yarnpkg.com/testem/-/testem-1.18.4.tgz#e45fed922bec2f54a616c43f11922598ac97eb41" dependencies: backbone "^1.1.2" bluebird "^3.4.6" @@ -6160,19 +6107,19 @@ testem@^1.15.0, testem@^1.18.0: text-table@~0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" "textextensions@1 || 2": version "2.1.0" - resolved "https://registry.npmjs.org/textextensions/-/textextensions-2.1.0.tgz#1be0dc2a0dc244d44be8a09af6a85afb93c4dbc3" + resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.1.0.tgz#1be0dc2a0dc244d44be8a09af6a85afb93c4dbc3" through@^2.3.6, through@^2.3.8, through@~2.3.8: version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" tiny-lr@^1.0.3: version "1.0.5" - resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.0.5.tgz#21f40bf84ebd1f853056680375eef1670c334112" + resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.0.5.tgz#21f40bf84ebd1f853056680375eef1670c334112" dependencies: body "^5.1.0" debug "~2.6.7" @@ -6183,56 +6130,56 @@ tiny-lr@^1.0.3: tmp-sync@^1.0.0: version "1.1.2" - resolved "https://registry.npmjs.org/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" + resolved "https://registry.yarnpkg.com/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" dependencies: fs-sync "^1.0.4" osenv "^0.1.0" tmp@0.0.28: version "0.0.28" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" dependencies: os-tmpdir "~1.0.1" tmp@0.0.30: version "0.0.30" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" dependencies: os-tmpdir "~1.0.1" tmp@0.0.31: version "0.0.31" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" dependencies: os-tmpdir "~1.0.1" -tmp@^0.0.29: - version "0.0.29" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" dependencies: - os-tmpdir "~1.0.1" + os-tmpdir "~1.0.2" tmpl@1.0.x: version "1.0.4" - resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" to-array@0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" to-fast-properties@^1.0.0, to-fast-properties@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" tough-cookie@>=0.12.0: - version "2.3.2" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + version "2.3.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" dependencies: punycode "^1.4.1" tree-sync@^1.2.1, tree-sync@^1.2.2: version "1.2.2" - resolved "https://registry.npmjs.org/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" + resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" dependencies: debug "^2.2.0" fs-tree-diff "^0.5.6" @@ -6242,56 +6189,56 @@ tree-sync@^1.2.1, tree-sync@^1.2.2: trim-right@^1.0.0, trim-right@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" try-resolve@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" + resolved "https://registry.yarnpkg.com/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" tryit@^1.0.1: version "1.0.3" - resolved "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" tryor@~0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" + resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" tunnel-agent@~0.4.0: version "0.4.3" - resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" type-check@~0.3.2: version "0.3.2" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" dependencies: prelude-ls "~1.1.2" type-detect@0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" type-detect@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" type-is@~1.6.15: version "1.6.15" - resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" dependencies: media-typer "0.3.0" mime-types "~2.1.15" typedarray@^0.0.6: version "0.0.6" - resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" uglify-js@^2.6, uglify-js@^2.7.0: version "2.8.29" - resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" dependencies: source-map "~0.5.1" yargs "~3.10.0" @@ -6300,208 +6247,196 @@ uglify-js@^2.6, uglify-js@^2.7.0: uglify-to-browserify@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" ultron@1.0.x: version "1.0.2" - resolved "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" underscore.string@^3.2.2, underscore.string@~3.3.4: version "3.3.4" - resolved "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" dependencies: sprintf-js "^1.0.3" util-deprecate "^1.0.2" underscore@>=1.8.3: version "1.8.3" - resolved "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" unique-string@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" dependencies: crypto-random-string "^1.0.0" universalify@^0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" untildify@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" dependencies: os-homedir "^1.0.0" url@0.10.3: version "0.10.3" - resolved "https://registry.npmjs.org/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" dependencies: punycode "1.3.2" querystring "0.2.0" user-home@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" user-home@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" dependencies: os-homedir "^1.0.0" username-sync@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/username-sync/-/username-sync-1.0.1.tgz#1cde87eefcf94b8822984d938ba2b797426dae1f" + resolved "https://registry.yarnpkg.com/username-sync/-/username-sync-1.0.1.tgz#1cde87eefcf94b8822984d938ba2b797426dae1f" util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -utils-merge@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" -uuid@3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" +uuid@3.1.0, uuid@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" uuid@^2.0.1: version "2.0.3" - resolved "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" - -uuid@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" validate-npm-package-license@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" dependencies: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" validate-npm-package-name@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" dependencies: builtins "^1.0.3" -vary@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" - vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" walk-sync@^0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: version "0.2.7" - resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" walk-sync@^0.3.0, walk-sync@^0.3.1: version "0.3.2" - resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" walker@~1.0.5: version "1.0.7" - resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" dependencies: makeerror "1.0.x" watch@~0.10.0: version "0.10.0" - resolved "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" websocket-driver@>=0.5.1: version "0.7.0" - resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" dependencies: http-parser-js ">=0.4.0" websocket-extensions ">=0.1.1" websocket-extensions@>=0.1.1: version "0.1.2" - resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.2.tgz#0e18781de629a18308ce1481650f67ffa2693a5d" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.2.tgz#0e18781de629a18308ce1481650f67ffa2693a5d" which-module@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" which@^1.2.12, which@^1.2.9: version "1.3.0" - resolved "https://registry.npmjs.org/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" dependencies: isexe "^2.0.0" wide-align@^1.1.0: version "1.1.2" - resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" dependencies: string-width "^1.0.2" window-size@0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" window-size@^0.1.2: version "0.1.4" - resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" window-size@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" wordwrap@0.0.2: version "0.0.2" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" wordwrap@~0.0.2: version "0.0.3" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" wordwrap@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" workerpool@^2.2.1: - version "2.2.4" - resolved "https://registry.npmjs.org/workerpool/-/workerpool-2.2.4.tgz#c9dbe01e103e92df0e8f55356fc860135fbd43b0" + version "2.3.0" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-2.3.0.tgz#86c5cbe946b55e7dc9d12b1936c8801a6e2d744d" dependencies: object-assign "4.1.1" wrap-ansi@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" dependencies: string-width "^1.0.1" strip-ansi "^3.0.1" wrappy@1: version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" write-file-atomic@^1.1.2: version "1.3.4" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -6509,7 +6444,7 @@ write-file-atomic@^1.1.2: write-file-atomic@^2.0.0: version "2.3.0" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -6517,88 +6452,99 @@ write-file-atomic@^2.0.0: write@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" dependencies: mkdirp "^0.5.1" ws@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" dependencies: options ">=0.0.5" ultron "1.0.x" ws@^1.0.1: version "1.1.4" - resolved "https://registry.npmjs.org/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" dependencies: options ">=0.0.5" ultron "1.0.x" wtf-8@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" + resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" xdg-basedir@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" dependencies: os-homedir "^1.0.0" xdg-basedir@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" -xml2js@0.4.17, xml2js@^0.4.17: +xml2js@0.4.17: version "0.4.17" - resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" dependencies: sax ">=0.6.0" xmlbuilder "^4.1.0" +xml2js@^0.4.17: + version "0.4.19" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + dependencies: + sax ">=0.6.0" + xmlbuilder "~9.0.1" + xmlbuilder@4.2.1, xmlbuilder@^4.1.0: version "4.2.1" - resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" dependencies: lodash "^4.0.0" +xmlbuilder@~9.0.1: + version "9.0.4" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.4.tgz#519cb4ca686d005a8420d3496f3f0caeecca580f" + xmldom@^0.1.19: version "0.1.27" - resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" + resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" xmlhttprequest-ssl@1.5.3: version "1.5.3" - resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" xtend@^4.0.0, xtend@~4.0.0: version "4.0.1" - resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" y18n@^3.2.0, y18n@^3.2.1: version "3.2.1" - resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" yallist@^2.1.2: version "2.1.2" - resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" yam@0.0.22: version "0.0.22" - resolved "https://registry.npmjs.org/yam/-/yam-0.0.22.tgz#38a76cb79a19284d9206ed49031e359a1340bd06" + resolved "https://registry.yarnpkg.com/yam/-/yam-0.0.22.tgz#38a76cb79a19284d9206ed49031e359a1340bd06" dependencies: fs-extra "^0.30.0" lodash.merge "^4.4.0" yargs-parser@^3.2.0: version "3.2.0" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-3.2.0.tgz#5081355d19d9d0c8c5d81ada908cb4e6d186664f" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-3.2.0.tgz#5081355d19d9d0c8c5d81ada908cb4e6d186664f" dependencies: camelcase "^3.0.0" lodash.assign "^4.1.0" yargs@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-5.0.0.tgz#3355144977d05757dbb86d6e38ec056123b3a66e" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-5.0.0.tgz#3355144977d05757dbb86d6e38ec056123b3a66e" dependencies: cliui "^3.2.0" decamelize "^1.1.1" @@ -6617,7 +6563,7 @@ yargs@^5.0.0: yargs@~3.10.0: version "3.10.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" dependencies: camelcase "^1.0.2" cliui "^2.1.0" @@ -6626,7 +6572,7 @@ yargs@~3.10.0: yargs@~3.27.0: version "3.27.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" dependencies: camelcase "^1.2.1" cliui "^2.1.0" @@ -6637,17 +6583,17 @@ yargs@~3.27.0: yeast@0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" yui@^3.18.1: version "3.18.1" - resolved "https://registry.npmjs.org/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" + resolved "https://registry.yarnpkg.com/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" dependencies: request "~2.40.0" yuidocjs@~0.9.0: version "0.9.0" - resolved "https://registry.npmjs.org/yuidocjs/-/yuidocjs-0.9.0.tgz#d2ff2b37cadf30e3d45385c58f5003e5a83f2723" + resolved "https://registry.yarnpkg.com/yuidocjs/-/yuidocjs-0.9.0.tgz#d2ff2b37cadf30e3d45385c58f5003e5a83f2723" dependencies: express "^4.13.1" graceful-fs "^4.1.2" From 5b336b5858b9c8831f1461ae60ae7bc10baa74ad Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 12 Oct 2017 09:38:30 -0400 Subject: [PATCH 2051/2527] Remove blueprints for Mocha < 0.12. (#5225) * Remove blueprints for Mocha < 0.12. ember-cli-mocha@0.12.0 was released quite some time ago (on 2016-11-23), and by all accounts has been well adopted. Supporting both mocha test blueprints indefinitely is untenable, and now seems like as good a time as any to drop the blueprints for the older syntax. Note: this does *not* remove support for anything, it merely makes it slightly less convienient to create new test files for adapter/model/serializer/transform objects when your application is using Mocha < 0.12. * Update to the latest ember-cli-version-checker. This is unblocked by removing the need to "Fake" the version checker in the blueprint test suite (the way ember-cli-blueprint-test-helpers fakes out ember-cli-version-checker@1 no longer works with ember-cli-version-checker@2). --- .../tests/unit/__path__/__test__.js | 16 ----------- .../tests/unit/__path__/__test__.js | 26 ++++++++--------- .../tests/unit/__path__/__test__.js | 17 ----------- .../tests/unit/__path__/__test__.js | 28 +++++++++---------- .../tests/unit/__path__/__test__.js | 19 ------------- .../tests/unit/__path__/__test__.js | 28 +++++++++---------- blueprints/test-framework-detector.js | 8 +----- .../tests/unit/__path__/__test__.js | 16 ----------- .../tests/unit/__path__/__test__.js | 26 ++++++++--------- node-tests/blueprints/adapter-test.js | 17 ----------- node-tests/blueprints/model-test.js | 17 ----------- node-tests/blueprints/serializer-test.js | 21 +------------- node-tests/blueprints/transform-test.js | 17 ----------- package.json | 2 +- yarn.lock | 2 +- 15 files changed, 54 insertions(+), 206 deletions(-) delete mode 100644 blueprints/adapter-test/mocha-0.12-files/tests/unit/__path__/__test__.js delete mode 100644 blueprints/model-test/mocha-0.12-files/tests/unit/__path__/__test__.js delete mode 100644 blueprints/serializer-test/mocha-0.12-files/tests/unit/__path__/__test__.js delete mode 100644 blueprints/transform-test/mocha-0.12-files/tests/unit/__path__/__test__.js diff --git a/blueprints/adapter-test/mocha-0.12-files/tests/unit/__path__/__test__.js b/blueprints/adapter-test/mocha-0.12-files/tests/unit/__path__/__test__.js deleted file mode 100644 index 1eb97b0b43a..00000000000 --- a/blueprints/adapter-test/mocha-0.12-files/tests/unit/__path__/__test__.js +++ /dev/null @@ -1,16 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; -import { setupTest } from 'ember-mocha'; - -describe('<%= friendlyTestDescription %>', function() { - setupTest('adapter:<%= dasherizedModuleName %>', { - // Specify the other units that are required for this test. - // needs: ['serializer:foo'] - }); - - // Replace this with your real tests. - it('exists', function() { - let adapter = this.subject(); - expect(adapter).to.be.ok; - }); -}); diff --git a/blueprints/adapter-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/adapter-test/mocha-files/tests/unit/__path__/__test__.js index f26b5338dbf..1eb97b0b43a 100644 --- a/blueprints/adapter-test/mocha-files/tests/unit/__path__/__test__.js +++ b/blueprints/adapter-test/mocha-files/tests/unit/__path__/__test__.js @@ -1,18 +1,16 @@ import { expect } from 'chai'; -import { describeModule, it } from 'ember-mocha'; +import { describe, it } from 'mocha'; +import { setupTest } from 'ember-mocha'; -describeModule( - 'adapter:<%= dasherizedModuleName %>', - '<%= friendlyTestDescription %>', - { +describe('<%= friendlyTestDescription %>', function() { + setupTest('adapter:<%= dasherizedModuleName %>', { // Specify the other units that are required for this test. // needs: ['serializer:foo'] - }, - function() { - // Replace this with your real tests. - it('exists', function() { - let adapter = this.subject(); - expect(adapter).to.be.ok; - }); - } -); + }); + + // Replace this with your real tests. + it('exists', function() { + let adapter = this.subject(); + expect(adapter).to.be.ok; + }); +}); diff --git a/blueprints/model-test/mocha-0.12-files/tests/unit/__path__/__test__.js b/blueprints/model-test/mocha-0.12-files/tests/unit/__path__/__test__.js deleted file mode 100644 index 6850a578f78..00000000000 --- a/blueprints/model-test/mocha-0.12-files/tests/unit/__path__/__test__.js +++ /dev/null @@ -1,17 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; -import { setupModelTest } from 'ember-mocha'; - -describe('<%= friendlyDescription %>', function() { - setupModelTest('<%= dasherizedModuleName %>', { - // Specify the other units that are required for this test. - <%= typeof needs !== 'undefined' ? needs : '' %> - }); - - // Replace this with your real tests. - it('exists', function() { - let model = this.subject(); - // var store = this.store(); - expect(model).to.be.ok; - }); -}); diff --git a/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js index b7bf32aa4cd..6850a578f78 100644 --- a/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js +++ b/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js @@ -1,19 +1,17 @@ import { expect } from 'chai'; -import { describeModel, it } from 'ember-mocha'; +import { describe, it } from 'mocha'; +import { setupModelTest } from 'ember-mocha'; -describeModel( - '<%= dasherizedModuleName %>', - '<%= friendlyDescription %>', - { +describe('<%= friendlyDescription %>', function() { + setupModelTest('<%= dasherizedModuleName %>', { // Specify the other units that are required for this test. <%= typeof needs !== 'undefined' ? needs : '' %> - }, - function() { - // Replace this with your real tests. - it('exists', function() { - let model = this.subject(); - // var store = this.store(); - expect(model).to.be.ok; - }); - } -); + }); + + // Replace this with your real tests. + it('exists', function() { + let model = this.subject(); + // var store = this.store(); + expect(model).to.be.ok; + }); +}); diff --git a/blueprints/serializer-test/mocha-0.12-files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/mocha-0.12-files/tests/unit/__path__/__test__.js deleted file mode 100644 index fd852a5e0d9..00000000000 --- a/blueprints/serializer-test/mocha-0.12-files/tests/unit/__path__/__test__.js +++ /dev/null @@ -1,19 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; -import { setupModelTest } from 'ember-mocha'; - -describe('<%= friendlyTestDescription %>', function() { - setupModelTest('<%= dasherizedModuleName %>', { - // Specify the other units that are required for this test. - needs: ['serializer:<%= dasherizedModuleName %>'] - }); - - // Replace this with your real tests. - it('serializes records', function() { - let record = this.subject(); - - let serializedRecord = record.serialize(); - - expect(serializedRecord).to.be.ok; - }); -}); diff --git a/blueprints/serializer-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/mocha-files/tests/unit/__path__/__test__.js index d8112c9884f..fd852a5e0d9 100644 --- a/blueprints/serializer-test/mocha-files/tests/unit/__path__/__test__.js +++ b/blueprints/serializer-test/mocha-files/tests/unit/__path__/__test__.js @@ -1,21 +1,19 @@ import { expect } from 'chai'; -import { describeModel, it } from 'ember-mocha'; +import { describe, it } from 'mocha'; +import { setupModelTest } from 'ember-mocha'; -describeModel( - '<%= dasherizedModuleName %>', - '<%= friendlyTestDescription %>', - { +describe('<%= friendlyTestDescription %>', function() { + setupModelTest('<%= dasherizedModuleName %>', { // Specify the other units that are required for this test. needs: ['serializer:<%= dasherizedModuleName %>'] - }, - function() { - // Replace this with your real tests. - it('serializes records', function() { - let record = this.subject(); + }); - let serializedRecord = record.serialize(); + // Replace this with your real tests. + it('serializes records', function() { + let record = this.subject(); - expect(serializedRecord).to.be.ok; - }); - } -); + let serializedRecord = record.serialize(); + + expect(serializedRecord).to.be.ok; + }); +}); diff --git a/blueprints/test-framework-detector.js b/blueprints/test-framework-detector.js index 2f8a2d988f8..d3b3e77c392 100644 --- a/blueprints/test-framework-detector.js +++ b/blueprints/test-framework-detector.js @@ -1,6 +1,5 @@ var fs = require('fs'); var path = require('path'); -var VersionChecker = require('ember-cli-version-checker'); module.exports = function(blueprint) { blueprint.supportsAddon = function() { @@ -14,12 +13,7 @@ module.exports = function(blueprint) { if ('ember-cli-qunit' in dependencies) { type = 'qunit'; } else if ('ember-cli-mocha' in dependencies) { - var checker = new VersionChecker({ project: this.project }); - if (fs.existsSync(this.path + '/mocha-0.12-files') && checker.for('ember-cli-mocha', 'npm').satisfies('>=0.12.0')) { - type = 'mocha-0.12'; - } else { - type = 'mocha'; - } + type = 'mocha'; } else { this.ui.writeLine('Couldn\'t determine test style - using QUnit'); type = 'qunit'; diff --git a/blueprints/transform-test/mocha-0.12-files/tests/unit/__path__/__test__.js b/blueprints/transform-test/mocha-0.12-files/tests/unit/__path__/__test__.js deleted file mode 100644 index fcbe57e5eed..00000000000 --- a/blueprints/transform-test/mocha-0.12-files/tests/unit/__path__/__test__.js +++ /dev/null @@ -1,16 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; -import { setupTest } from 'ember-mocha'; - -describe('<%= friendlyTestDescription %>', function() { - setupTest('transform:<%= dasherizedModuleName %>', { - // Specify the other units that are required for this test. - // needs: ['transform:foo'] - }); - - // Replace this with your real tests. - it('exists', function() { - let transform = this.subject(); - expect(transform).to.be.ok; - }); -}); diff --git a/blueprints/transform-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/transform-test/mocha-files/tests/unit/__path__/__test__.js index c3d20680218..fcbe57e5eed 100644 --- a/blueprints/transform-test/mocha-files/tests/unit/__path__/__test__.js +++ b/blueprints/transform-test/mocha-files/tests/unit/__path__/__test__.js @@ -1,18 +1,16 @@ import { expect } from 'chai'; -import { describeModule, it } from 'ember-mocha'; +import { describe, it } from 'mocha'; +import { setupTest } from 'ember-mocha'; -describeModule( - 'transform:<%= dasherizedModuleName %>', - '<%= friendlyTestDescription %>', - { +describe('<%= friendlyTestDescription %>', function() { + setupTest('transform:<%= dasherizedModuleName %>', { // Specify the other units that are required for this test. // needs: ['transform:foo'] - }, - function() { - // Replace this with your real tests. - it('exists', function() { - let transform = this.subject(); - expect(transform).to.be.ok; - }); - } -); + }); + + // Replace this with your real tests. + it('exists', function() { + let transform = this.subject(); + expect(transform).to.be.ok; + }); +}); diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 6acb989b33d..38a4d5cc000 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -90,23 +90,6 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { })); }); - it('adapter-test for mocha', function() { - var args = ['adapter-test', 'foo']; - - return emberNew() - .then(() => modifyPackages([ - {name: 'ember-cli-qunit', delete: true}, - {name: 'ember-cli-mocha', dev: true} - ])) - .then(() => generateFakePackageManifest('ember-cli-mocha', '0.11.0')) - .then(() => emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/adapters/foo-test.js')) - .to.contain('import { describeModule, it } from \'ember-mocha\';') - .to.contain('describeModule(\n \'adapter:foo\',') - .to.contain('expect(adapter).to.be.ok;'); - })); - }); - it('adapter-test for mocha v0.12+', function() { var args = ['adapter-test', 'foo']; diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index 6b57bf5a1fb..d0d1eaa8078 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -103,23 +103,6 @@ describe('Acceptance: generate and destroy model blueprints', function() { })); }); - it('model-test for mocha', function() { - var args = ['model-test', 'foo']; - - return emberNew() - .then(() => modifyPackages([ - {name: 'ember-cli-qunit', delete: true}, - {name: 'ember-cli-mocha', dev: true} - ])) - .then(() => generateFakePackageManifest('ember-cli-mocha', '0.11.0')) - .then(() => emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/models/foo-test.js')) - .to.contain('import { describeModel, it } from \'ember-mocha\';') - .to.contain('describeModel(\n \'foo\',') - .to.contain('expect(model).to.be.ok;'); - })); - }); - it('model-test for mocha v0.12+', function() { var args = ['model-test', 'foo']; diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index 9cee0241e7e..5a8b1dff8e4 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -90,26 +90,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { })); }); - it('serializer-test for mocha', function() { - var args = ['serializer-test', 'foo']; - - return emberNew() - .then(() => modifyPackages([ - {name: 'ember-cli-qunit', delete: true}, - {name: 'ember-cli-mocha', dev: true} - ])) - .then(() => generateFakePackageManifest('ember-cli-mocha', '0.11.0')) - .then(() => emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/serializers/foo-test.js')) - .to.contain('import { describeModel, it } from \'ember-mocha\';') - .to.contain('describeModel(\n \'foo\',') - .to.contain('Unit | Serializer | foo') - .to.contain('needs: [\'serializer:foo\']') - .to.contain('expect(serializedRecord).to.be.ok;'); - })); - }); - - it('serializer-test for mocha v0.12+', function() { + it('serializer-test for mocha v0.12+', function() { var args = ['serializer-test', 'foo']; return emberNew() diff --git a/node-tests/blueprints/transform-test.js b/node-tests/blueprints/transform-test.js index 8d934d7218e..bd9a96be7aa 100644 --- a/node-tests/blueprints/transform-test.js +++ b/node-tests/blueprints/transform-test.js @@ -38,23 +38,6 @@ describe('Acceptance: generate and destroy transform blueprints', function() { })); }); - it('transform-test for mocha', function() { - var args = ['transform-test', 'foo']; - - return emberNew() - .then(() => modifyPackages([ - {name: 'ember-cli-qunit', delete: true}, - {name: 'ember-cli-mocha', dev: true} - ])) - .then(() => generateFakePackageManifest('ember-cli-mocha', '0.11.0')) - .then(() => emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/transforms/foo-test.js')) - .to.contain('import { describeModule, it } from \'ember-mocha\';') - .to.contain('describeModule(\n \'transform:foo\',') - .to.contain('expect(transform).to.be.ok;'); - })); - }); - it('transform-test for mocha v0.12+', function() { var args = ['transform-test', 'foo']; diff --git a/package.json b/package.json index d726784a2e6..af560db8dd5 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.0.0", "ember-cli-test-info": "^1.0.0", - "ember-cli-version-checker": "^1.1.4", + "ember-cli-version-checker": "^2.1.0", "ember-inflector": "^2.0.0", "ember-runtime-enumerable-includes-polyfill": "^2.0.0", "exists-sync": "0.0.3", diff --git a/yarn.lock b/yarn.lock index f7728b4c498..c38e1aeccfa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2466,7 +2466,7 @@ ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-ve dependencies: semver "^5.3.0" -ember-cli-version-checker@^2.0.0: +ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.1.0.tgz#fc79a56032f3717cf844ada7cbdec1a06fedb604" dependencies: From f1c685dd2686ae0d49bf86503c04ea6f6b448df9 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 11 Oct 2017 21:20:53 -0400 Subject: [PATCH 2052/2527] [BUGFIX release] Move test only dependencies into devDependencies. Also fixed small issue (which was being squelched by bugs in deps that have been updated here) with a merge (needed to allow overwriting). --- package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index af560db8dd5..03b841fe5a2 100644 --- a/package.json +++ b/package.json @@ -33,11 +33,8 @@ "broccoli-funnel": "^1.2.0", "broccoli-merge-trees": "^2.0.0", "broccoli-rollup": "^1.2.0", - "broccoli-test-helper": "^1.2.0", "calculate-cache-key-for-tree": "^1.1.0", "chalk": "^1.1.1", - "co": "^4.6.0", - "common-tags": "^1.4.0", "ember-cli-babel": "^6.8.2", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.0.0", @@ -51,8 +48,7 @@ "inflection": "^1.8.0", "npm-git-info": "^1.0.0", "semver": "^5.1.0", - "silent-error": "^1.0.0", - "testem": "^1.15.0" + "silent-error": "^1.0.0" }, "devDependencies": { "babel-plugin-debug-macros": "^0.1.7", @@ -70,8 +66,11 @@ "broccoli-concat": "^3.2.2", "broccoli-stew": "^1.4.2", "broccoli-string-replace": "^0.1.1", + "broccoli-test-helper": "^1.2.0", "broccoli-uglify-sourcemap": "^1.0.1", "broccoli-yuidoc": "^2.1.0", + "co": "^4.6.0", + "common-tags": "^1.4.0", "ember-ajax": "^2.4.1", "ember-cli": "^2.11.1", "ember-cli-app-version": "^3.0.0", @@ -110,7 +109,8 @@ "morgan": "^1.7.0", "rimraf": "2.5.2", "rsvp": "4.7.0", - "testdouble": "^3.2.6" + "testdouble": "^3.2.6", + "testem": "^1.15.0" }, "peerDependencies": { "ember-inflector": "^2.0.0" From 6168a107cdc758cf8f98636bf79f2e33260b1f99 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Tue, 17 Oct 2017 10:32:02 +0100 Subject: [PATCH 2053/2527] Update model.js --- addon/-private/system/model/model.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 04d99e4a602..c44dbfeccb9 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -553,14 +553,14 @@ const Model = EmberObject.extend(Evented, { export default Route.extend({ actions: { - softDelete: function() { - this.controller.get('model').deleteRecord(); + softDelete() { + this.get('controller.model').deleteRecord(); }, - confirm: function() { - this.controller.get('model').save(); + confirm() { + this.get('controller.model').save(); }, - undo: function() { - this.controller.get('model').rollbackAttributes(); + undo() { + this.get('controller.model').rollbackAttributes(); } } }); @@ -582,9 +582,8 @@ const Model = EmberObject.extend(Evented, { export default Route.extend({ actions: { - delete: function() { - let controller = this.controller; - controller.get('model').destroyRecord().then(function() { + delete() { + this.get('controller.model').destroyRecord().then(function() { controller.transitionToRoute('model.index'); }); } @@ -603,7 +602,7 @@ const Model = EmberObject.extend(Evented, { import MyCustomAdapter from './custom-adapter'; export default MyCustomAdapter.extend({ - deleteRecord: function(store, type, snapshot) { + deleteRecord(store, type, snapshot) { if (snapshot.adapterOptions.subscribe) { // ... } @@ -771,7 +770,7 @@ const Model = EmberObject.extend(Evented, { import MyCustomAdapter from './custom-adapter'; export default MyCustomAdapter.extend({ - updateRecord: function(store, type, snapshot) { + updateRecord(store, type, snapshot) { if (snapshot.adapterOptions.subscribe) { // ... } @@ -803,7 +802,7 @@ const Model = EmberObject.extend(Evented, { export default Route.extend({ actions: { - reload: function() { + reload() { this.controller.get('model').reload().then(function(model) { // do something with the reloaded model }); From 9cf542b425b7c58aeec03ea29a0f00e262a2a6a1 Mon Sep 17 00:00:00 2001 From: Kelly Selden Date: Wed, 18 Oct 2017 12:31:31 -0700 Subject: [PATCH 2054/2527] add test coverage for more node versions (node 4) (#5210) --- .travis.yml | 11 +- appveyor.yml | 2 +- .../unit/babel-plugin-remove-imports-test.js | 4 +- package.json | 2 +- yarn.lock | 145 +++++++++--------- 5 files changed, 90 insertions(+), 74 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1ddf26fbbf4..a6543656e6a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,16 @@ language: node_js sudo: false dist: trusty node_js: - - "7" + - "4" + - "6" + +# hack to get after_success skipped in node 4 +matrix: + exclude: + - node_js: "4" + include: + - node_js: "4" + after_success: skip cache: yarn: true diff --git a/appveyor.yml b/appveyor.yml index f3a652aac81..5d41989135a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,7 +3,7 @@ # Test against these versions of Node.js. environment: matrix: - - nodejs_version: "7" + - nodejs_version: "4" cache: - '%LOCALAPPDATA%\Yarn' diff --git a/node-tests/unit/babel-plugin-remove-imports-test.js b/node-tests/unit/babel-plugin-remove-imports-test.js index d39d15f72b7..c2816d57c90 100644 --- a/node-tests/unit/babel-plugin-remove-imports-test.js +++ b/node-tests/unit/babel-plugin-remove-imports-test.js @@ -1,3 +1,5 @@ +'use strict'; + const BroccoliTestHelper = require('broccoli-test-helper'); const co = require('co'); const Babel = require('broccoli-babel-transpiler'); @@ -5,7 +7,7 @@ const chai = require('ember-cli-blueprint-test-helpers/chai'); const stripIndent = require('common-tags').stripIndent; const StripFilteredImports = require('../../lib/transforms/babel-plugin-remove-imports'); -const { expect } = chai; +const expect = chai.expect; const createTempDir = BroccoliTestHelper.createTempDir; const createBuilder = BroccoliTestHelper.createBuilder; diff --git a/package.json b/package.json index f69e5837157..9cd4a378519 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "faker": "^3.1.0", "github": "^1.1.1", "glob": "5.0.13", - "heimdall-query": "^0.0.5", + "heimdall-query": "^0.0.8", "json-api-mock-server": "0.1.1", "loader.js": "^4.5.0", "mocha": "2.4.5", diff --git a/yarn.lock b/yarn.lock index c38e1aeccfa..21e7377530c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13,12 +13,12 @@ "@glimmer/di" "^0.2.0" "@types/node@*": - version "8.0.34" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.34.tgz#55f801fa2ddb2a40dd6dfc15ecfe1dde9c129fe9" + version "8.0.44" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.44.tgz#5c39800fda4b76dab39a5f28fda676fc500015ac" "@types/node@^7.0.5": - version "7.0.43" - resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.43.tgz#a187e08495a075f200ca946079c914e1a5fe962c" + version "7.0.44" + resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.44.tgz#20422b3dada536f35bf318ac3e24b8c48200803d" "@types/rimraf@^0.0.28": version "0.0.28" @@ -72,6 +72,10 @@ acorn@^5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" +adm-zip@0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.4.tgz#a61ed5ae6905c3aea58b3a657d25033091052736" + after@0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" @@ -997,6 +1001,10 @@ better-assert@~1.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.0.0.tgz#e597d1a7a6a3558a2d1c7241a16c99965e6aa40f" +bindings@1.2.x, bindings@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11" + blank-object@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" @@ -1551,6 +1559,13 @@ buffer@4.9.1: ieee754 "^1.1.4" isarray "^1.0.0" +bufferutil@1.2.x: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-1.2.1.tgz#37be5d36e1e06492221e68d474b1ac58e510cbd7" + dependencies: + bindings "1.2.x" + nan "^2.0.5" + builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -1994,10 +2009,6 @@ core-js@^2.4.0, core-js@^2.5.0: version "2.5.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" -core-js@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" - core-object@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" @@ -2800,10 +2811,6 @@ es6-map@^0.1.3, es6-map@^0.1.4, es6-map@^0.1.5: es6-symbol "~3.1.1" event-emitter "~0.3.5" -es6-promise@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" - es6-set@~0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" @@ -3615,17 +3622,18 @@ hawk@1.1.1: hoek "0.9.x" sntp "0.2.x" -heimdall-query@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/heimdall-query/-/heimdall-query-0.0.5.tgz#bafac4864793a5fa48f7dee916b64621364690b3" +heimdall-query@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/heimdall-query/-/heimdall-query-0.0.8.tgz#74f01be023690be7d09f92aef747b642fd8bde8e" dependencies: chalk "^1.1.1" chrome-debugging-client "^0.2.4" cli-table "^0.3.1" lodash "^4.15.0" + outliers "0.0.3" plain-text-box-plot "0.0.1" progress "^1.1.8" - selenium-webdriver "^3.0.0-beta-2" + selenium-webdriver "2.48.2" heimdalljs-fs-monitor@^0.1.0: version "0.1.0" @@ -3733,10 +3741,6 @@ ignore@^3.1.2: version "3.3.5" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.5.tgz#c4e715455f6073a8d7e5dae72d2fc9d71663dba6" -immediate@~3.0.5: - version "3.0.6" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" - imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -4126,16 +4130,6 @@ jsonpointer@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" -jszip@^3.1.3: - version "3.1.4" - resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.1.4.tgz#fc323fe41bb1730348d20dd022aa4d8b57cbbcf9" - dependencies: - core-js "~2.3.0" - es6-promise "~3.0.2" - lie "~3.1.0" - pako "~1.0.2" - readable-stream "~2.0.6" - kind-of@^3.0.2: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -4187,12 +4181,6 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -lie@~3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" - dependencies: - immediate "~3.0.5" - linkify-it@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" @@ -4846,6 +4834,14 @@ mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" +nan@^2.0.5: + version "2.7.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46" + +nan@~2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232" + negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" @@ -5030,6 +5026,10 @@ osenv@^0.1.0, osenv@^0.1.3: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +outliers@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/outliers/-/outliers-0.0.3.tgz#4d8329bf25340495b628d3997016525d097dd5b8" + output-file-sync@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" @@ -5052,10 +5052,6 @@ p-locate@^2.0.0: dependencies: p-limit "^1.1.0" -pako@~1.0.2: - version "1.0.6" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" - parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -5336,17 +5332,6 @@ readable-stream@~1.0.2: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - readline2@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" @@ -5644,6 +5629,10 @@ sane@^1.1.1, sane@^1.4.1, sane@^1.6.0: walker "~1.0.5" watch "~0.10.0" +sax@0.6.x: + version "0.6.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-0.6.1.tgz#563b19c7c1de892e09bfc4f2fc30e3c27f0952b9" + sax@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" @@ -5652,14 +5641,15 @@ sax@>=0.6.0: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -selenium-webdriver@^3.0.0-beta-2: - version "3.6.0" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc" +selenium-webdriver@2.48.2: + version "2.48.2" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-2.48.2.tgz#b26a4631430d0a9f36284ee0cfe09676e8f348ca" dependencies: - jszip "^3.1.3" - rimraf "^2.5.4" - tmp "0.0.30" - xml2js "^0.4.17" + adm-zip "0.4.4" + rimraf "^2.2.8" + tmp "0.0.24" + ws "^0.8.0" + xml2js "0.4.4" "semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0: version "5.4.1" @@ -6135,18 +6125,16 @@ tmp-sync@^1.0.0: fs-sync "^1.0.4" osenv "^0.1.0" +tmp@0.0.24: + version "0.0.24" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.24.tgz#d6a5e198d14a9835cc6f2d7c3d9e302428c8cf12" + tmp@0.0.28: version "0.0.28" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" dependencies: os-tmpdir "~1.0.1" -tmp@0.0.30: - version "0.0.30" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" - dependencies: - os-tmpdir "~1.0.1" - tmp@0.0.31: version "0.0.31" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" @@ -6305,6 +6293,13 @@ username-sync@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/username-sync/-/username-sync-1.0.1.tgz#1cde87eefcf94b8822984d938ba2b797426dae1f" +utf-8-validate@1.2.x: + version "1.2.2" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-1.2.2.tgz#8bb871a4741e085c70487ca7acdbd7d6d36029eb" + dependencies: + bindings "~1.2.1" + nan "~2.4.0" + util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -6463,6 +6458,16 @@ ws@1.1.1: options ">=0.0.5" ultron "1.0.x" +ws@^0.8.0: + version "0.8.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-0.8.1.tgz#6b65273b99193c5f067a4cf5809598f777e3b759" + dependencies: + options ">=0.0.5" + ultron "1.0.x" + optionalDependencies: + bufferutil "1.2.x" + utf-8-validate "1.2.x" + ws@^1.0.1: version "1.1.4" resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" @@ -6491,12 +6496,12 @@ xml2js@0.4.17: sax ">=0.6.0" xmlbuilder "^4.1.0" -xml2js@^0.4.17: - version "0.4.19" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" +xml2js@0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.4.tgz#3111010003008ae19240eba17497b57c729c555d" dependencies: - sax ">=0.6.0" - xmlbuilder "~9.0.1" + sax "0.6.x" + xmlbuilder ">=1.0.0" xmlbuilder@4.2.1, xmlbuilder@^4.1.0: version "4.2.1" @@ -6504,7 +6509,7 @@ xmlbuilder@4.2.1, xmlbuilder@^4.1.0: dependencies: lodash "^4.0.0" -xmlbuilder@~9.0.1: +xmlbuilder@>=1.0.0: version "9.0.4" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.4.tgz#519cb4ca686d005a8420d3496f3f0caeecca580f" From f3e1e325c97ab259b5fa5391b0eb736889423d88 Mon Sep 17 00:00:00 2001 From: bmac Date: Sun, 22 Oct 2017 12:15:04 -0400 Subject: [PATCH 2055/2527] Move initialize-store-service.js out of the instance-initializers directory. That directory seems to be suggesting to ember-load-initializers that it is a full initializer object and causing an exception to be thrown in the globals build. Fixes #5118 --- addon/index.js | 2 +- addon/{instance-initializers => }/initialize-store-service.js | 0 app/instance-initializers/ember-data.js | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename addon/{instance-initializers => }/initialize-store-service.js (100%) diff --git a/addon/index.js b/addon/index.js index 9488e79a16f..397f90fb601 100644 --- a/addon/index.js +++ b/addon/index.js @@ -52,7 +52,7 @@ import { import "ember-inflector"; import setupContainer from "./setup-container"; -import initializeStoreService from './instance-initializers/initialize-store-service'; +import initializeStoreService from './initialize-store-service'; import Transform from './transforms/transform'; import NumberTransform from './transforms/number'; diff --git a/addon/instance-initializers/initialize-store-service.js b/addon/initialize-store-service.js similarity index 100% rename from addon/instance-initializers/initialize-store-service.js rename to addon/initialize-store-service.js diff --git a/app/instance-initializers/ember-data.js b/app/instance-initializers/ember-data.js index ef21c3fe50d..50b27f03026 100644 --- a/app/instance-initializers/ember-data.js +++ b/app/instance-initializers/ember-data.js @@ -1,4 +1,4 @@ -import initializeStoreService from 'ember-data/instance-initializers/initialize-store-service'; +import initializeStoreService from 'ember-data/initialize-store-service'; export default { name: "ember-data", From 2ba40b9c793b4df02bd9a486f8eb96cffb1a119a Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Mon, 23 Oct 2017 13:35:10 -0500 Subject: [PATCH 2056/2527] Check if environment is production-like in stripped-build-plugins (#5234) --- lib/stripped-build-plugins.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 9bd2a6cb1f8..45570f1826d 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -59,7 +59,7 @@ module.exports = function(environment) { console.warn('NOT STRIPPING HEIMDALL'); } - if (environment === 'production' || process.env.INSTRUMENT_HEIMDALL === 'true') { + if (/production/.test(environment) || process.env.INSTRUMENT_HEIMDALL === 'true') { postTransformPlugins.push([StripClassCallCheck]); uniqueAdd(filteredImports, 'ember-data/-debug', [ 'assertPolymorphicType' From e4e57811535a4c906a4c51f2f61db870d8d41faa Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 23 Oct 2017 14:54:38 -0400 Subject: [PATCH 2057/2527] Deprecate support for "production like" values in EMBER_ENV --- index.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 533c4c1c69b..cafe40a0fdc 100644 --- a/index.js +++ b/index.js @@ -38,6 +38,13 @@ function isProductionEnv() { module.exports = { name: 'ember-data', + _prodLikeWarning() { + let emberEnv = process.env.EMBER_ENV + if(emberEnv !== 'production' && /production/.test(emberEnv)) { + this._warn(`Production-like values for EMBER_ENV are deprecated (your EMBER_ENV is "${emberEnv}") and support will be removed in Ember Data 4.0.0. If using ember-cli-deploy, please configure your build using 'production'. Otherwise please set your EMBER_ENV to 'production' for production builds.`); + } + }, + _warn(message) { let chalk = require('chalk'); let warning = chalk.yellow('WARNING: ' + message); @@ -53,7 +60,7 @@ module.exports = { init() { this._super.init && this._super.init.apply(this, arguments); - + this._prodLikeWarning(); this.debugTree = BroccoliDebug.buildDebugCallback('ember-data'); let bowerDeps = this.project.bowerDependencies(); From 1166a541aae0b9ac58d6b7e5743df6ce460fea5f Mon Sep 17 00:00:00 2001 From: bek Date: Tue, 24 Oct 2017 19:38:49 +0500 Subject: [PATCH 2058/2527] use `test` instead of `match` and correct regex (#5241) --- addon/-private/system/debug/debug-adapter.js | 2 +- addon/transforms/boolean.js | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/debug/debug-adapter.js b/addon/-private/system/debug/debug-adapter.js index abd9f6df50d..eca07a7d7df 100644 --- a/addon/-private/system/debug/debug-adapter.js +++ b/addon/-private/system/debug/debug-adapter.js @@ -52,7 +52,7 @@ export default DataAdapter.extend({ let containerKey = modelClass._debugContainerKey; if (containerKey) { let match = containerKey.match(/model:(.*)/); - if (match) { + if (match !== null) { modelName = match[1]; } } diff --git a/addon/transforms/boolean.js b/addon/transforms/boolean.js index 4dfeb4a834c..b7d1a5a9b1e 100644 --- a/addon/transforms/boolean.js +++ b/addon/transforms/boolean.js @@ -39,16 +39,15 @@ import Transform from './transform'; */ export default Transform.extend({ deserialize(serialized, options) { - let type = typeof serialized; - if (isNone(serialized) && options.allowNull === true) { return null; } + let type = typeof serialized; if (type === "boolean") { return serialized; } else if (type === "string") { - return serialized.match(/^true$|^t$|^1$/i) !== null; + return /^(true|t|1)$/i.test(serialized); } else if (type === "number") { return serialized === 1; } else { From 2e1c66fcfce28ee13f7f655e853676a2f1792005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Clemens=20M=C3=BCller?= Date: Wed, 25 Oct 2017 21:05:21 +0200 Subject: [PATCH 2059/2527] Update assert against nulls (#5218) * update assertion for meta proxied on AdapterPopulatedRecordArray * use `assert.strictEqual` when comparing against `null` This prevents us being trolled by QUnit, where assert.equal(undefined, null) is not a failing assertion. * use `assert.strictEqual` when comparing against `undefined` This prevents us being trolled by QUnit, where assert.equal(null, undefined) is not a failing assertion. * align test for DateTransform#deserialize(undefined) with implementation --- .../adapter/json-api-adapter-test.js | 2 +- .../integration/adapter/rest-adapter-test.js | 8 ++++---- .../polymorphic-belongs-to-test.js | 4 ++-- tests/integration/records/save-test.js | 2 +- .../inverse-relationships-test.js | 12 +++++------ tests/integration/store/query-test.js | 2 +- tests/unit/diff-array-test.js | 6 +++--- tests/unit/model-test.js | 2 +- tests/unit/model/rollback-attributes-test.js | 2 +- .../adapter-populated-record-array-test.js | 8 ++++---- .../filtered-record-array-test.js | 6 +++--- tests/unit/record-arrays/record-array-test.js | 10 +++++----- tests/unit/store/adapter-interop-test.js | 8 ++++---- tests/unit/store/push-test.js | 2 +- tests/unit/transform/boolean-test.js | 8 ++++---- tests/unit/transform/date-test.js | 12 +++++------ tests/unit/transform/number-test.js | 20 +++++++++---------- tests/unit/transform/string-test.js | 8 ++++---- 18 files changed, 61 insertions(+), 61 deletions(-) diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index acfcbf16fd4..a119c908116 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -968,7 +968,7 @@ test('fetching a belongsTo relationship link that returns null', function(assert return post.get('author'); }).then(author => { assert.equal(passedUrl[1], 'http://example.com/post/1/author'); - assert.equal(author, null); + assert.strictEqual(author, null); }); }); }); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index a1095bbf159..d6466770f52 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -889,7 +889,7 @@ test("deleteRecord - an empty payload is a basic success", function(assert) { }).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "DELETE"); - assert.equal(passedHash, undefined); + assert.strictEqual(passedHash, undefined); assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); assert.equal(post.get('isDeleted'), true, "the post is now deleted"); @@ -946,7 +946,7 @@ test("deleteRecord - a payload with sideloaded updates pushes the updates", func }).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "DELETE"); - assert.equal(passedHash, undefined); + assert.strictEqual(passedHash, undefined); assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); assert.equal(post.get('isDeleted'), true, "the post is now deleted"); @@ -978,7 +978,7 @@ test("deleteRecord - a payload with sidloaded updates pushes the updates when th }).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "DELETE"); - assert.equal(passedHash, undefined); + assert.strictEqual(passedHash, undefined); assert.equal(post.get('hasDirtyAttributes'), false, "the original post isn't dirty anymore"); assert.equal(post.get('isDeleted'), true, "the original post is now deleted"); @@ -1738,7 +1738,7 @@ test("findHasMany - returning an array populates the array", function(assert) { }).then(comments => { assert.equal(passedUrl, '/posts/1/comments'); assert.equal(passedVerb, 'GET'); - assert.equal(passedHash, undefined); + assert.strictEqual(passedHash, undefined); let comment1 = store.peekRecord('comment', 1); let comment2 = store.peekRecord('comment', 2); diff --git a/tests/integration/polymorphic-belongs-to-test.js b/tests/integration/polymorphic-belongs-to-test.js index e2e680f8017..a6272b795a9 100644 --- a/tests/integration/polymorphic-belongs-to-test.js +++ b/tests/integration/polymorphic-belongs-to-test.js @@ -84,7 +84,7 @@ test('using store.push with a null value for a payload in relationships sets the }; run(() => store.push(payloadThatResetsBelongToRelationship)); - assert.equal(book.get('author'), null); + assert.strictEqual(book.get('author'), null); }); test('using store.push with a null value for a payload in relationships sets the Models relationship to null - async relationship', (assert) => { @@ -134,6 +134,6 @@ test('using store.push with a null value for a payload in relationships sets the run(() => store.push(payloadThatResetsBelongToRelationship)); return book.get('author'); }).then(author => { - assert.equal(author, null); + assert.strictEqual(author, null); }); }); diff --git a/tests/integration/records/save-test.js b/tests/integration/records/save-test.js index 562870048a5..4be3a2990e3 100644 --- a/tests/integration/records/save-test.js +++ b/tests/integration/records/save-test.js @@ -38,7 +38,7 @@ test("Will resolve save on success", function(assert) { var saved = post.save(); // `save` returns a PromiseObject which allows to call get on it - assert.equal(saved.get('id'), undefined); + assert.strictEqual(saved.get('id'), undefined); deferred.resolve({ data: { id: 123, type: 'post' } }); saved.then(function(model) { diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index cb14af74e22..bdae33053f5 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -159,14 +159,14 @@ test("When setting a belongsTo, the OneToOne invariant is respected even when ot assert.equal(comment.get('post'), post); assert.equal(post.get('bestComment'), comment); - assert.equal(post2.get('bestComment'), null); + assert.strictEqual(post2.get('bestComment'), null); run(function() { comment.set('post', post2); }); assert.equal(comment.get('post'), post2); - assert.equal(post.get('bestComment'), null); + assert.strictEqual(post.get('bestComment'), null); assert.equal(post2.get('bestComment'), comment); }); @@ -197,14 +197,14 @@ test("When setting a belongsTo, the OneToOne invariant is transitive", function( assert.equal(comment.get('post'), post); assert.equal(post.get('bestComment'), comment); - assert.equal(post2.get('bestComment'), null); + assert.strictEqual(post2.get('bestComment'), null); run(function() { post2.set('bestComment', comment); }); assert.equal(comment.get('post'), post2); - assert.equal(post.get('bestComment'), null); + assert.strictEqual(post.get('bestComment'), null); assert.equal(post2.get('bestComment'), comment); }); @@ -233,13 +233,13 @@ test("When setting a belongsTo, the OneToOne invariant is commutative", function assert.equal(comment.get('post'), post); assert.equal(post.get('bestComment'), comment); - assert.equal(comment2.get('post'), null); + assert.strictEqual(comment2.get('post'), null); run(function() { post.set('bestComment', comment2); }); - assert.equal(comment.get('post'), null); + assert.strictEqual(comment.get('post'), null); assert.equal(post.get('bestComment'), comment2); assert.equal(comment2.get('post'), post); }); diff --git a/tests/integration/store/query-test.js b/tests/integration/store/query-test.js index 76ddc1b603e..257c07944c6 100644 --- a/tests/integration/store/query-test.js +++ b/tests/integration/store/query-test.js @@ -39,7 +39,7 @@ test("meta is proxied correctly on the PromiseArray", function(assert) { result = store.query('person', {}); }); - assert.equal(result.get('meta.foo'), undefined); + assert.notOk(result.get('meta.foo'), 'precond: meta is not yet set'); run(function() { defered.resolve({ data: [], meta: { foo: 'bar' } }); diff --git a/tests/unit/diff-array-test.js b/tests/unit/diff-array-test.js index 9d69b8f1a3d..a226a2ffd07 100644 --- a/tests/unit/diff-array-test.js +++ b/tests/unit/diff-array-test.js @@ -20,21 +20,21 @@ const z = "zzz"; test('diff array returns no change given two empty arrays', function(assert) { const result = diffArray([], []); - assert.equal(result.firstChangeIndex, null); + assert.strictEqual(result.firstChangeIndex, null); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 0); }); test('diff array returns no change given two identical arrays length 1', function(assert) { const result = diffArray([a], [a]); - assert.equal(result.firstChangeIndex, null); + assert.strictEqual(result.firstChangeIndex, null); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 0); }); test('diff array returns no change given two identical arrays length 3', function(assert) { const result = diffArray([a,b,c], [a,b,c]); - assert.equal(result.firstChangeIndex, null); + assert.strictEqual(result.firstChangeIndex, null); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 0); }); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index fa4a70938f6..f243044a77a 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -930,7 +930,7 @@ testInDebug('a null defaultValue is not deprecated', function(assert) { let tag = run(() => store.createRecord('tag')); assert.expectNoDeprecation(); - assert.equal(get(tag, 'tagInfo'), null); + assert.strictEqual(get(tag, 'tagInfo'), null); }); test('setting a property to undefined on a newly created record should not impact the current state', function(assert) { diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index 985d8f5eb9b..403ad8e1910 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -70,7 +70,7 @@ test('changes to unassigned attributes can be rolled back', function(assert) { run(() => person.rollbackAttributes()); - assert.equal(person.get('firstName'), undefined); + assert.strictEqual(person.get('firstName'), undefined); assert.equal(person.get('hasDirtyAttributes'), false); }); diff --git a/tests/unit/record-arrays/adapter-populated-record-array-test.js b/tests/unit/record-arrays/adapter-populated-record-array-test.js index f1ed2a8ce79..164416e87e7 100644 --- a/tests/unit/record-arrays/adapter-populated-record-array-test.js +++ b/tests/unit/record-arrays/adapter-populated-record-array-test.js @@ -28,9 +28,9 @@ test('default initial state', function(assert) { assert.equal(recordArray.get('isLoaded'), false, 'expected isLoaded to be false'); assert.equal(recordArray.get('modelName'), 'recordType'); assert.deepEqual(recordArray.get('content'), []); - assert.equal(recordArray.get('query'), null); - assert.equal(recordArray.get('store'), null); - assert.equal(recordArray.get('links'), null); + assert.strictEqual(recordArray.get('query'), null); + assert.strictEqual(recordArray.get('store'), null); + assert.strictEqual(recordArray.get('links'), null); }); test('custom initial state', function(assert) { @@ -51,7 +51,7 @@ test('custom initial state', function(assert) { assert.equal(recordArray.get('content'), content); assert.equal(recordArray.get('store'), store); assert.equal(recordArray.get('query'), 'some-query'); - assert.equal(recordArray.get('links'), null); + assert.strictEqual(recordArray.get('links'), null); }); test('#replace() throws error', function(assert) { diff --git a/tests/unit/record-arrays/filtered-record-array-test.js b/tests/unit/record-arrays/filtered-record-array-test.js index 6a388cc70df..bf25e22dd88 100644 --- a/tests/unit/record-arrays/filtered-record-array-test.js +++ b/tests/unit/record-arrays/filtered-record-array-test.js @@ -14,9 +14,9 @@ test('default initial state', function(assert) { assert.equal(get(recordArray, 'isLoaded'), true); assert.equal(get(recordArray, 'modelName'), 'recordType'); - assert.equal(get(recordArray, 'content'), null); - assert.equal(get(recordArray, 'filterFunction'), null); - assert.equal(get(recordArray, 'store'), null); + assert.strictEqual(get(recordArray, 'content'), null); + assert.strictEqual(get(recordArray, 'filterFunction'), null); + assert.strictEqual(get(recordArray, 'store'), null); }); test('custom initial state', function(assert) { diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js index 91bd69c6d7b..51fbaeb5f10 100644 --- a/tests/unit/record-arrays/record-array-test.js +++ b/tests/unit/record-arrays/record-array-test.js @@ -15,8 +15,8 @@ test('default initial state', function(assert) { assert.equal(get(recordArray, 'isLoaded'), false); assert.equal(get(recordArray, 'isUpdating'), false); assert.equal(get(recordArray, 'modelName'), 'recordType'); - assert.equal(get(recordArray, 'content'), null); - assert.equal(get(recordArray, 'store'), null); + assert.strictEqual(get(recordArray, 'content'), null); + assert.strictEqual(get(recordArray, 'store'), null); }); test('custom initial state', function(assert) { @@ -60,7 +60,7 @@ test('#objectAtContent', function(assert) { assert.equal(recordArray.objectAtContent(0), 'foo'); assert.equal(recordArray.objectAtContent(1), 'bar'); assert.equal(recordArray.objectAtContent(2), 'baz'); - assert.equal(recordArray.objectAtContent(3), undefined); + assert.strictEqual(recordArray.objectAtContent(3), undefined); }); test('#update', function(assert) { @@ -281,7 +281,7 @@ test('#destroy', function(assert) { assert.equal(didDissociatieFromOwnRecords, 1, 'after destroy, we should have dissociated from own record array'); recordArray.destroy(); - assert.equal(get(recordArray, 'content'), null); + assert.strictEqual(get(recordArray, 'content'), null); assert.equal(get(recordArray, 'length'), 0, 'after destroy we should have no length'); assert.equal(get(recordArray, 'isDestroyed'), true, 'should be destroyed'); }); @@ -352,7 +352,7 @@ test('#destroy', function(assert) { assert.equal(didDissociatieFromOwnRecords, 1, 'after destroy, we should have dissociated from own record array'); recordArray.destroy(); - assert.equal(get(recordArray, 'content'), null); + assert.strictEqual(get(recordArray, 'content'), null); assert.equal(get(recordArray, 'length'), 0, 'after destroy we should have no length'); assert.equal(get(recordArray, 'isDestroyed'), true, 'should be destroyed'); }); diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index fc7ba5fb307..6e64d831a2c 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -1126,7 +1126,7 @@ test('store should not reload a record when `shouldBackgroundReloadRecord` is fa }); return store.findRecord('person', 1).then(record => { - assert.equal(record.get('name'), undefined); + assert.strictEqual(record.get('name'), undefined); }); }); }); @@ -1164,7 +1164,7 @@ test('store should reload the record in the background when `shouldBackgroundRel }); return store.findRecord('person', 1).then(record => { - assert.equal(record.get('name'), undefined); + assert.strictEqual(record.get('name'), undefined); }); }); @@ -1292,7 +1292,7 @@ test('store should not reload all records when `shouldBackgroundReloadAll` is fa return run(() => { return store.findAll('person').then(records => { - assert.equal(records.get('firstObject'), undefined); + assert.strictEqual(records.get('firstObject'), undefined); }); }); }); @@ -1327,7 +1327,7 @@ test('store should reload all records in the background when `shouldBackgroundRe let done = run(() => { return store.findAll('person').then(records => { - assert.equal(records.get('firstObject.name'), undefined); + assert.strictEqual(records.get('firstObject.name'), undefined); }); }); diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index a579dd8e7cb..08667010bb1 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -67,7 +67,7 @@ test('Changed attributes are reset when matching data is pushed', function(asser run(() => person.set('firstName', 'updated first name')); assert.equal(person.get('firstName'), 'updated first name'); - assert.equal(person.get('lastName'), undefined); + assert.strictEqual(person.get('lastName'), undefined); assert.equal(person.get('currentState.stateName'), 'root.loaded.updated.uncommitted'); assert.deepEqual(person.changedAttributes().firstName, ['original first name', 'updated first name']); diff --git a/tests/unit/transform/boolean-test.js b/tests/unit/transform/boolean-test.js index 02bd4ae73c1..ddead45a024 100644 --- a/tests/unit/transform/boolean-test.js +++ b/tests/unit/transform/boolean-test.js @@ -7,8 +7,8 @@ module('unit/transform - DS.BooleanTransform'); test("#serialize", function(assert) { let transform = new DS.BooleanTransform(); - assert.equal(transform.serialize(null, { allowNull: true }), null); - assert.equal(transform.serialize(undefined, { allowNull: true }), null); + assert.strictEqual(transform.serialize(null, { allowNull: true }), null); + assert.strictEqual(transform.serialize(undefined, { allowNull: true }), null); assert.equal(transform.serialize(null, { allowNull: false }), false); assert.equal(transform.serialize(undefined, { allowNull: false }), false); @@ -23,8 +23,8 @@ test("#serialize", function(assert) { test('#deserialize', function(assert) { let transform = new DS.BooleanTransform(); - assert.equal(transform.deserialize(null, { allowNull: true }), null); - assert.equal(transform.deserialize(undefined, { allowNull: true }), null); + assert.strictEqual(transform.deserialize(null, { allowNull: true }), null); + assert.strictEqual(transform.deserialize(undefined, { allowNull: true }), null); assert.equal(transform.deserialize(null, { allowNull: false }), false); assert.equal(transform.deserialize(undefined, { allowNull: false }), false); diff --git a/tests/unit/transform/date-test.js b/tests/unit/transform/date-test.js index 330c8ec2469..558e4444e8d 100644 --- a/tests/unit/transform/date-test.js +++ b/tests/unit/transform/date-test.js @@ -14,9 +14,9 @@ let date = new Date(dateString); test('#serialize', function(assert) { let transform = new DS.DateTransform(); - assert.equal(transform.serialize(null), null); - assert.equal(transform.serialize(undefined), null); - assert.equal(transform.serialize(new Date('invalid')), null); + assert.strictEqual(transform.serialize(null), null); + assert.strictEqual(transform.serialize(undefined), null); + assert.strictEqual(transform.serialize(new Date('invalid')), null); assert.equal(transform.serialize(date), dateString); }); @@ -31,11 +31,11 @@ test('#deserialize', function(assert) { assert.equal(transform.deserialize(dateInMillis).valueOf(), dateInMillis); // from other - assert.equal(transform.deserialize({}), null); + assert.strictEqual(transform.deserialize({}), null); // from none - assert.equal(transform.deserialize(null), null); - assert.equal(transform.deserialize(undefined), null); + assert.strictEqual(transform.deserialize(null), null); + assert.strictEqual(transform.deserialize(undefined), undefined); }); testInDebug('#deserialize with different offset formats', function(assert) { diff --git a/tests/unit/transform/number-test.js b/tests/unit/transform/number-test.js index c8a3aba2a7e..10ed98761b2 100644 --- a/tests/unit/transform/number-test.js +++ b/tests/unit/transform/number-test.js @@ -7,25 +7,25 @@ module('unit/transform - DS.NumberTransform'); test('#serialize', function(assert) { let transform = new DS.NumberTransform(); - assert.equal(transform.serialize(null), null); - assert.equal(transform.serialize(undefined), null); + assert.strictEqual(transform.serialize(null), null); + assert.strictEqual(transform.serialize(undefined), null); assert.equal(transform.serialize("1.1"), 1.1); assert.equal(transform.serialize(1.1), 1.1); assert.equal(transform.serialize(new Number(1.1)), 1.1); - assert.equal(transform.serialize(NaN), null); - assert.equal(transform.serialize(Infinity), null); - assert.equal(transform.serialize(-Infinity), null); + assert.strictEqual(transform.serialize(NaN), null); + assert.strictEqual(transform.serialize(Infinity), null); + assert.strictEqual(transform.serialize(-Infinity), null); }); test('#deserialize', function(assert) { let transform = new DS.NumberTransform(); - assert.equal(transform.deserialize(null), null); - assert.equal(transform.deserialize(undefined), null); + assert.strictEqual(transform.deserialize(null), null); + assert.strictEqual(transform.deserialize(undefined), null); assert.equal(transform.deserialize('1.1'), 1.1); assert.equal(transform.deserialize(1.1), 1.1); assert.equal(transform.deserialize(new Number(1.1)), 1.1); - assert.equal(transform.deserialize(NaN), null); - assert.equal(transform.deserialize(Infinity), null); - assert.equal(transform.deserialize(-Infinity), null); + assert.strictEqual(transform.deserialize(NaN), null); + assert.strictEqual(transform.deserialize(Infinity), null); + assert.strictEqual(transform.deserialize(-Infinity), null); }); diff --git a/tests/unit/transform/string-test.js b/tests/unit/transform/string-test.js index 8aa87545101..c8958d0ecd2 100644 --- a/tests/unit/transform/string-test.js +++ b/tests/unit/transform/string-test.js @@ -7,8 +7,8 @@ module('unit/transform - DS.StringTransform'); test('#serialize', function(assert) { let transform = new DS.StringTransform(); - assert.equal(transform.serialize(null), null); - assert.equal(transform.serialize(undefined), null); + assert.strictEqual(transform.serialize(null), null); + assert.strictEqual(transform.serialize(undefined), null); assert.equal(transform.serialize('foo'), 'foo'); assert.equal(transform.serialize(1), '1'); @@ -17,8 +17,8 @@ test('#serialize', function(assert) { test('#deserialize', function(assert) { let transform = new DS.StringTransform(); - assert.equal(transform.deserialize(null), null); - assert.equal(transform.deserialize(undefined), null); + assert.strictEqual(transform.deserialize(null), null); + assert.strictEqual(transform.deserialize(undefined), null); assert.equal(transform.deserialize('foo'), 'foo'); assert.equal(transform.deserialize(1), '1'); From a6985685d148d3051bf279a8f6c8b341921cf1f5 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Wed, 25 Oct 2017 10:31:51 -0700 Subject: [PATCH 2060/2527] [BUGFIX beta] Normalize model names during `push` Model names are normalized (so eg `store.peekRecord('fooBar',1) === store.peekRecord('foo-bar', 1)`) at most of the store API (`peekRecord`, `findRecord` &c.) but notably absent is `push`. This commit adds back model name normalization to `push`. --- addon/-private/system/store.js | 3 ++- tests/integration/record-array-test.js | 36 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 5c7d57b9117..4253b2d1d3d 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2009,7 +2009,8 @@ Store = Service.extend({ */ _load(data) { heimdall.increment(_load); - let internalModel = this._internalModelForId(data.type, data.id); + let modelName = normalizeModelName(data.type); + let internalModel = this._internalModelForId(modelName, data.id); let isUpdate = internalModel.currentState.isEmpty === false; diff --git a/tests/integration/record-array-test.js b/tests/integration/record-array-test.js index f311d3ac9e2..cf2ec8c1288 100644 --- a/tests/integration/record-array-test.js +++ b/tests/integration/record-array-test.js @@ -119,6 +119,42 @@ test('acts as a live query', function(assert) { assert.equal(get(recordArray, 'lastObject.name'), 'brohuda'); }); +test('acts as a live query (normalized names)', function (assert) { + let store = createStore({ + person: Person, + Person: Person + }); + + let recordArray = store.peekAll('Person'); + + run(() => { + store.push({ + data: { + type: 'Person', + id: '1', + attributes: { + name: 'John Churchill' + } + } + }); + }); + + assert.deepEqual(recordArray.mapBy('name'), ['John Churchill']); + + run(() => { + store.push({ + data: { + type: 'Person', + id: '2', + attributes: { + name: 'Winston Churchill' + } + } + }); + }); + assert.deepEqual(recordArray.mapBy('name'), ['John Churchill', 'Winston Churchill']); +}); + test('stops updating when destroyed', function(assert) { assert.expect(3); From ce606b1b6946a700248f92e35222cca195c8e80e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Duque?= Date: Thu, 26 Oct 2017 19:03:29 +0100 Subject: [PATCH 2061/2527] Fixup DS.Store.pushPayload example (#5243) --- addon/-private/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 4253b2d1d3d..94bb7dee20d 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2493,7 +2493,7 @@ Store = Service.extend({ ``` ```js - store.pushPayload('comment', pushData); // Will use the application serializer + store.pushPayload(pushData); // Will use the application serializer store.pushPayload('post', pushData); // Will use the post serializer ``` From 9e39629a4f02525b86c183c24ca11097e14d525a Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Wed, 1 Nov 2017 19:53:07 -0700 Subject: [PATCH 2062/2527] [BUGFIX beta] Fix client-side delete + resurrection Previously relationships were only cleared for new records. Now they are cleared for destroyed records as well, allowing destroyed records to be pushed back into the store and properly update their inverse relationships. This fixes the public API for client-side delete via an adapter, see #5136. --- addon/-private/system/model/internal-model.js | 16 +--- .../adapter/client-side-delete-test.js | 88 +++++++++++++++++++ 2 files changed, 92 insertions(+), 12 deletions(-) create mode 100644 tests/integration/adapter/client-side-delete-test.js diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 3a1036e3a88..805331e1c97 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -772,7 +772,7 @@ export default class InternalModel { } if (this.isNew()) { - this.removeFromInverseRelationships(true); + this.removeFromInverseRelationships(); } if (this.isValid()) { @@ -891,19 +891,13 @@ export default class InternalModel { It will remove this record from any associated relationships. - If `isNew` is true (default false), it will also completely reset all - relationships to an empty state as well. - @method removeFromInverseRelationships - @param {Boolean} isNew whether to unload from the `isNew` perspective @private */ - removeFromInverseRelationships(isNew = false) { + removeFromInverseRelationships() { this._relationships.forEach((name, rel) => { rel.removeCompletelyFromInverse(); - if (isNew === true) { - rel.clear(); - } + rel.clear(); }); let implicitRelationships = this._implicitRelationships; @@ -913,9 +907,7 @@ export default class InternalModel { let rel = implicitRelationships[key]; rel.removeCompletelyFromInverse(); - if (isNew === true) { - rel.clear(); - } + rel.clear(); }); } diff --git a/tests/integration/adapter/client-side-delete-test.js b/tests/integration/adapter/client-side-delete-test.js new file mode 100644 index 00000000000..38693df8dd5 --- /dev/null +++ b/tests/integration/adapter/client-side-delete-test.js @@ -0,0 +1,88 @@ +import { resolve } from 'rsvp'; +import { run } from '@ember/runloop'; +import setupStore from 'dummy/tests/helpers/store'; + +import { module, test } from 'qunit'; + +import DS from 'ember-data'; + +module('integration/adapter/store-adapter - client-side delete', { + beforeEach() { + this.Bookstore = DS.Model.extend({ + books: DS.hasMany('book', { async: false, inverse: 'bookstore' }) + }); + this.Book = DS.Model.extend({ + bookstore: DS.belongsTo('bookstore', { inverse: 'books' }) + }); + + this.env = setupStore({ + bookstore: this.Bookstore, + book: this.Book + }); + this.store = this.env.store; + this.adapter = this.env.adapter; + }, + + afterEach() { + run(this.env.container, 'destroy'); + } +}); + +test('client-side deleted records can be added back from an inverse', function(assert) { + this.adapter.deleteRecord = function (store, modelClass, snapshot) { + if (snapshot.adapterOptions.clientSideDelete) { + return resolve(); + } + + assert.ok(false, 'unreachable'); + } + + run(() => this.store.push({ + data: { + id: '1', + type: 'bookstore', + relationships: { + books: { + data: [{ + id: '1', type: 'book' + }, { + id: '2', type: 'book' + }] + } + } + }, included: [{ + id: '1', + type: 'book' + }, { + id: '2', + type: 'book' + }] + })); + + let bookstore = this.store.peekRecord('bookstore', '1'); + assert.deepEqual(bookstore.get('books').mapBy('id'), ['1', '2'], 'initial hasmany loaded'); + + let book2 = this.store.peekRecord('book', '2'); + return run(() => book2.destroyRecord({ adapterOptions: { clientSideDelete: true } })).then(() => { + run(() => book2.unloadRecord()); + assert.equal(this.store.hasRecordForId('book', '2'), false, 'book 2 unloaded'); + assert.deepEqual(bookstore.get('books').mapBy('id'), ['1'], 'one book client-side deleted'); + + run(() => this.store.push({ + data: { + id: '2', + type: 'book', + relationships: { + bookstore: { + data: { + id: '1', + type: 'bookstore' + } + } + } + } + })); + + assert.deepEqual(bookstore.get('books').mapBy('id'), ['1', '2'], 'the deleted book (with same id) is pushed back into the store'); + }); +}); From e01b89ade56b8798787e461f479b154c7ab9ae61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Clemens=20M=C3=BCller?= Date: Sat, 4 Nov 2017 21:19:18 +0100 Subject: [PATCH 2063/2527] [BUGFIX beta] setProperties to clear errors works (#5248) --- addon/-private/system/model/errors.js | 1 + tests/integration/records/error-test.js | 41 ++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index ce959ad44d0..7ddbf5f4412 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -339,6 +339,7 @@ export default ArrayProxy.extend(Evented, { get(this, 'errorsByAttributeName').delete(attribute); this.notifyPropertyChange(attribute); + this.notifyPropertyChange('length'); }, /** diff --git a/tests/integration/records/error-test.js b/tests/integration/records/error-test.js index bbe4a4bff4e..faab0e113e1 100644 --- a/tests/integration/records/error-test.js +++ b/tests/integration/records/error-test.js @@ -1,8 +1,9 @@ import { run } from '@ember/runloop'; -import { module } from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import RSVP from 'rsvp'; var env, store, Person; var attr = DS.attr; @@ -166,3 +167,41 @@ testInDebug('adding errors root.loaded.created.invalid works add + (remove, add) { attribute: 'firstName', message: 'is invalid' } ]); }); + +test('using setProperties to clear errors', function(assert) { + env.adapter.reopen({ + createRecord() { + return RSVP.reject(new DS.InvalidError([ + { + detail: 'Must be unique', + source: { pointer: '/data/attributes/first-name' } + }, + { + detail: 'Must not be blank', + source: { pointer: '/data/attributes/last-name'} + } + ])); + } + }); + + return run(() => { + let person = store.createRecord('person'); + + return person.save().then(null, function() { + let errors = person.get('errors'); + + assert.equal(errors.get('length'), 2); + assert.ok(errors.has('firstName')); + assert.ok(errors.has('lastName')); + + person.setProperties({ + firstName: "updated", + lastName: "updated" + }); + + assert.equal(errors.get('length'), 0); + assert.notOk(errors.has('firstName')); + assert.notOk(errors.has('lastName')); + }); + }); +}); From 741f01c9f302dca1a241aedc3605fb83c9faf914 Mon Sep 17 00:00:00 2001 From: sandstrom Date: Mon, 6 Nov 2017 19:33:25 +0100 Subject: [PATCH 2064/2527] [doc] Update links to Ember Guide (#5250) * Update links to Ember Guide * Update inverse-test.js --- addon/-private/system/model/model.js | 6 +++--- tests/integration/inverse-test.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index c44dbfeccb9..521d7425088 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1321,7 +1321,7 @@ Model.reopenClass({ } else { //No inverse was specified manually, we need to use a heuristic to guess one if (propertyMeta.parentType && propertyMeta.type === propertyMeta.parentType.modelName) { - warn(`Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at https://emberjs.com/guides/models/defining-models/#toc_reflexive-relation for how to explicitly specify inverses.`, false, { + warn(`Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at https://guides.emberjs.com/current/models/relationships/#toc_reflexive-relations for how to explicitly specify inverses.`, false, { id: 'ds.model.reflexive-relationship-without-inverse' }); } @@ -1336,7 +1336,7 @@ Model.reopenClass({ }); assert("You defined the '" + name + "' relationship on " + this + ", but you defined the inverse relationships of type " + - inverseType.toString() + " multiple times. Look at https://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", + inverseType.toString() + " multiple times. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses", filteredRelationships.length < 2); if (filteredRelationships.length === 1 ) { @@ -1344,7 +1344,7 @@ Model.reopenClass({ } assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + - this + " were found on " + inverseType + ". Look at https://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", + this + " were found on " + inverseType + ". Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses", possibleRelationships.length === 1); inverseName = possibleRelationships[0].name; diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index d2881b9dd23..2656594cee7 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -109,7 +109,7 @@ testInDebug("Errors out if you define 2 inverses to the same model", function(as assert.expectAssertion(() => { User.inverseFor('job', store); - }, "You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times. Look at https://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses"); + }, /^You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times/i); }); From 6f5d865dd9baf1fb70b79fa813321e8bb77238fa Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Mon, 6 Nov 2017 19:09:23 -0800 Subject: [PATCH 2065/2527] Update changelog for Ember Data 2.17.0-beta.2 [ci skip] --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dcf5af2003..fbf612a5907 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ ### Master +### Release 2.17.0-beta.2 (November 6, 2017) + +- [#5216](https://github.com/emberjs/data/pull/5216) [BUGFIX] setting a property to its previous value clears validation state +- [#5213](https://github.com/emberjs/data/pull/5213) [BUGFIX] `store.query` returns a promise proxy that now proxies `meta` +- [#5242](https://github.com/emberjs/data/pull/5242) [BUGFIX] `store.push` normalizes model names of payloads to match the rest of the store api (eg `store.createRecord`) +- [#5248](https://github.com/emberjs/data/pull/5248) [BUGFIX] `model.setProperties` will now clear `model` errors correctly + +### Release 2.17.0-beta.1 (October 3, 2017) +- No Changes from 2.16.0 + ### Release 2.16.1 (October 4, 2017) - [#5114](https://github.com/emberjs/data/pull/5114) Make import stripping smarter to resolve #5019 - [#5197](https://github.com/emberjs/data/pull/5197) Fix ember-data Node 4.x builds From 624cda03f6e6cd2204b55526915d02c59bc23daf Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 13 Nov 2017 18:59:05 -0700 Subject: [PATCH 2066/2527] [doc] Update urlForFindRecord example --- addon/-private/adapters/build-url-mixin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index 52ec93f5452..2472a83d31a 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -118,7 +118,7 @@ export default Mixin.create({ export default DS.JSONAPIAdapter.extend({ urlForFindRecord(id, modelName, snapshot) { - let baseUrl = this.buildURL(); + let baseUrl = this.buildURL(modelName, id, snapshot); return `${baseUrl}/users/${snapshot.adapterOptions.user_id}/playlists/${id}`; } }); From 1d68d9ab922ce46ad57404ef2f446454c30947ad Mon Sep 17 00:00:00 2001 From: Cory Forsyth Date: Wed, 15 Nov 2017 13:48:20 -0500 Subject: [PATCH 2067/2527] [DOC beta] Assert that both modelName and id are passed to `peekRecord` (#4998) Adds expectAssertion test for the new assertion, as well as an expectAssertion test for the existing assertion that a model name (string) must be passed instead of a model class. --- addon/-private/system/store.js | 1 + tests/unit/store/peek-record-test.js | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 94bb7dee20d..d26f2706876 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1034,6 +1034,7 @@ Store = Service.extend({ peekRecord(modelName, id) { heimdall.increment(peekRecord); assert(`You need to pass a model name to the store's peekRecord method`, isPresent(modelName)); + assert(`You need to pass both a model name and id to the store's peekRecord method`, isPresent(modelName) && isPresent(id)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); let normalizedModelName = normalizeModelName(modelName); diff --git a/tests/unit/store/peek-record-test.js b/tests/unit/store/peek-record-test.js index 1d5ec9433f5..4e92782bdd6 100644 --- a/tests/unit/store/peek-record-test.js +++ b/tests/unit/store/peek-record-test.js @@ -1,5 +1,7 @@ import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; +import Ember from 'ember'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; @@ -40,3 +42,20 @@ test('peekRecord should return null if the record is not in the store ', functio assert.equal(null, store.peekRecord('person', 1), 'peekRecord returns null if the corresponding record is not in the store'); }); }); + +testInDebug('peekRecord should assert if not passed both model name and id', function(assert) { + run(() => { + assert.expectAssertion(() => { + store.peekRecord('my-id'); + }, /You need to pass both a model name and id/); + }); +}); + +testInDebug('peekRecord should assert if passed a model class instead of model name', function(assert) { + run(() => { + assert.expectAssertion(() => { + let modelClass = Ember.Object.extend(); + store.peekRecord(modelClass, 'id'); + }, /Passing classes to store methods has been removed/); + }); +}); From e46b576c621ca5b8c5b92167b9b0edd6176802d8 Mon Sep 17 00:00:00 2001 From: bmac Date: Sun, 19 Nov 2017 10:57:52 -0500 Subject: [PATCH 2068/2527] Update changelog for Ember Data 2.17.0 release --- CHANGELOG.md | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbf612a5907..2bb2307864f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,15 +2,29 @@ ### Master -### Release 2.17.0-beta.2 (November 6, 2017) - -- [#5216](https://github.com/emberjs/data/pull/5216) [BUGFIX] setting a property to its previous value clears validation state -- [#5213](https://github.com/emberjs/data/pull/5213) [BUGFIX] `store.query` returns a promise proxy that now proxies `meta` -- [#5242](https://github.com/emberjs/data/pull/5242) [BUGFIX] `store.push` normalizes model names of payloads to match the rest of the store api (eg `store.createRecord`) -- [#5248](https://github.com/emberjs/data/pull/5248) [BUGFIX] `model.setProperties` will now clear `model` errors correctly - -### Release 2.17.0-beta.1 (October 3, 2017) -- No Changes from 2.16.0 +### Release 2.17.0 (November 19, 2017) +- [#5216](https://github.com/emberjs/data/pull/5216) [BUGFIX beta] invalid record becomes loaded when property is reset +- [#4998](https://github.com/emberjs/data/pull/4998) [DOC beta] Assert that both modelName and id are passed to `peekRecord` (#4998) +- [#5217](https://github.com/emberjs/data/pull/5217) [BUGFIX beta] RecordReference returns null when not yet loaded +- [#5166](https://github.com/emberjs/data/pull/5166) [DOC] Remove mention of `bower install` from README +- [#5114](https://github.com/emberjs/data/pull/5114) Make import stripping smarter to resolve #5019 +- [#5165](https://github.com/emberjs/data/pull/5165) [DOC] Update README build step script name +- [#5212](https://github.com/emberjs/data/pull/5212) Do not show feature flag improved-ajax methods in the api docs +- [#5183](https://github.com/emberjs/data/pull/5183) [DOCS release] Add missing "relationship" field to RESTAdapter.findBelongsTo docs +- [#5176](https://github.com/emberjs/data/pull/5176) fix node 4 +- [#5172](https://github.com/emberjs/data/pull/5172) [DOC] Remove parameter from BelongsToReference.value +- [#5178](https://github.com/emberjs/data/pull/5178) Ignore included resources without that don't have a corresponding ember-data model +- [#5213](https://github.com/emberjs/data/pull/5213) [BUGFIX beta] proxy `meta` on PromiseArray +- [#5197](https://github.com/emberjs/data/pull/5197) Fix ember-data Node 4.x builds +- [#5191](https://github.com/emberjs/data/pull/5191) Remove feature flagging for ds-extended-errors. +- [#5184](https://github.com/emberjs/data/pull/5184) Update LICENSE through 2017 +- [#5196](https://github.com/emberjs/data/pull/5196) [BUGFIX beta] Avoid cache related warnings during builds. +- [#5206](https://github.com/emberjs/data/pull/5206) [BUGFIX beta] Fix broccoli-babel-transpiler cache warnings +- [#5216](https://github.com/emberjs/data/pull/5216) [BUGFIX beta] invalid record becomes loaded when property is reset +- [#5220](https://github.com/emberjs/data/pull/5220) Remove (unnecessary) ember-inflector peer dependency +- [#5223](https://github.com/emberjs/data/pull/5223) [BUGFIX release] Cleanup test only dependencies. +- [#5224](https://github.com/emberjs/data/pull/5224) Add missing dependency for travis build +- [#5232](https://github.com/emberjs/data/pull/5232) Update documentation in model.js ### Release 2.16.1 (October 4, 2017) - [#5114](https://github.com/emberjs/data/pull/5114) Make import stripping smarter to resolve #5019 From dd3cd69462943530039428a0203f7d66beb1bfd0 Mon Sep 17 00:00:00 2001 From: bmac Date: Sun, 19 Nov 2017 10:59:49 -0500 Subject: [PATCH 2069/2527] Bump master version to 3.0.0-canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9cd4a378519..3f1998d0be9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "2.18.0-canary", + "version": "3.0.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From 20810d725450c823b8d9877bead215b29e530264 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 20 Nov 2017 20:16:03 -0800 Subject: [PATCH 2070/2527] [BUGFIX] inverseFor should respect inverse: null --- addon/-private/system/model/model.js | 2 +- .../inverse-relationships-test.js | 34 +++++++++++++++++++ .../serializers/json-serializer-test.js | 12 +++++-- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 521d7425088..cca30e02349 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -35,7 +35,7 @@ function findPossibleInverses(type, inverseType, name, relationshipsSoFar) { let relationships = relationshipMap.get(type.modelName).filter(relationship => { let optionsForRelationship = inverseType.metaForProperty(relationship.name).options; - if (!optionsForRelationship.inverse) { + if (!optionsForRelationship.inverse && optionsForRelationship.inverse !== null) { return true; } diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index bdae33053f5..91641283935 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -7,6 +7,12 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; +let { + Model, + hasMany, + belongsTo +} = DS; + var Post, Comment, Message, User; module('integration/relationships/inverse_relationships - Inverse Relationships'); @@ -65,6 +71,34 @@ test("Inverse relationships can be explicitly nullable", function(assert) { assert.equal(post.inverseFor('participants').name, 'posts', 'Post.participants inverse is User.posts'); }); +test("Null inverses are excluded from potential relationship resolutions", function(assert) { + User = Model.extend(); + + Post = Model.extend({ + lastParticipant: belongsTo('user', { inverse: null, async: false }), + participants: hasMany('user', { async: false }) + }); + + User.reopen({ + posts: hasMany('post', { async: false }) + }); + + let store = createStore({ + user: User, + post: Post + }); + let user, post; + + run(function() { + user = store.createRecord('user'); + post = store.createRecord('post'); + }); + + assert.equal(user.inverseFor('posts').name, 'participants', 'User.posts inverse is Post.participants'); + assert.equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); + assert.equal(post.inverseFor('participants').name, 'posts', 'Post.participants inverse is User.posts'); +}); + test("When a record is added to a has-many relationship, the inverse belongsTo can be set explicitly", function(assert) { Post = DS.Model.extend({ comments: DS.hasMany('comment', { inverse: 'redPost', async: false }) diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 1c8172d1a92..920e6064adf 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -18,10 +18,10 @@ module("integration/serializer/json - JSONSerializer", { }); Comment = DS.Model.extend({ body: DS.attr('string'), - post: DS.belongsTo('post', { async: false }) + post: DS.belongsTo('post', { inverse: null, async: false }) }); Favorite = DS.Model.extend({ - post: DS.belongsTo('post', { async: true, polymorphic: true }) + post: DS.belongsTo('post', { inverse: null, async: true, polymorphic: true }) }); env = setupStore({ post: Post, @@ -237,7 +237,12 @@ test("serializeHasMany respects keyForRelationship", function(assert) { run(function() { post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); - comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post, id: "1" }); + comment = env.store.createRecord('comment', { + body: "Omakase is delicious", + post: post, + id: "1" + }); + post.get('comments').pushObject(comment); }); var json = {}; @@ -635,6 +640,7 @@ test('Serializer respects `serialize: true` on the attrs hash for a `hasMany` pr run(function() { post = env.store.createRecord('post', { title: "Rails is omakase" }); comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + post.get('comments').pushObject(comment); }); var serializer = env.store.serializerFor("post"); From 109a05955372e94f59d7a96fd772c5c9a59c46ae Mon Sep 17 00:00:00 2001 From: Eric Honkanen Date: Fri, 24 Nov 2017 16:02:03 -0800 Subject: [PATCH 2071/2527] Update AdapterPopulatedRecordArray to use links if available otherwise null. (#5263) --- .../system/record-arrays/adapter-populated-record-array.js | 2 +- tests/unit/record-arrays/adapter-populated-record-array-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index 8ef73763c8c..959f61938f8 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -49,7 +49,7 @@ export default RecordArray.extend({ this._super(...arguments); this.query = this.query || null; - this.links = null; + this.links = this.links || null; }, replace() { diff --git a/tests/unit/record-arrays/adapter-populated-record-array-test.js b/tests/unit/record-arrays/adapter-populated-record-array-test.js index 164416e87e7..3bc283652aa 100644 --- a/tests/unit/record-arrays/adapter-populated-record-array-test.js +++ b/tests/unit/record-arrays/adapter-populated-record-array-test.js @@ -51,7 +51,7 @@ test('custom initial state', function(assert) { assert.equal(recordArray.get('content'), content); assert.equal(recordArray.get('store'), store); assert.equal(recordArray.get('query'), 'some-query'); - assert.strictEqual(recordArray.get('links'), null); + assert.strictEqual(recordArray.get('links'), 'foo'); }); test('#replace() throws error', function(assert) { From ed4e45f7ca4a28a478293857442164e295eccf5b Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Sat, 25 Nov 2017 20:08:36 -0500 Subject: [PATCH 2072/2527] Update ember-cli-blueprint-test-helpers fixes #5259 (#5264) --- package.json | 2 +- yarn.lock | 101 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 70 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index 3f1998d0be9..6b1137bdc65 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "ember-ajax": "^2.4.1", "ember-cli": "^2.11.1", "ember-cli-app-version": "^3.0.0", - "ember-cli-blueprint-test-helpers": "0.11.0", + "ember-cli-blueprint-test-helpers": "^0.18.3", "ember-cli-dependency-checker": "^1.3.0", "ember-cli-eslint": "1.3.0", "ember-cli-htmlbars": "^2.0.1", diff --git a/yarn.lock b/yarn.lock index 21e7377530c..2be650ed1ad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1640,16 +1640,18 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chai-as-promised@^5.1.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-5.3.0.tgz#09d7a402908aa70dfdbead53e5853fc79d3ef21c" - chai-as-promised@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" dependencies: check-error "^1.0.2" +chai-as-promised@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" + dependencies: + check-error "^1.0.2" + chai-files@^1.0.0, chai-files@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" @@ -1664,6 +1666,17 @@ chai@^3.3.0: deep-eql "^0.1.3" type-detect "^1.0.0" +chai@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c" + dependencies: + assertion-error "^1.0.1" + check-error "^1.0.1" + deep-eql "^3.0.0" + get-func-name "^2.0.0" + pathval "^1.0.0" + type-detect "^4.0.0" + chalk@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" @@ -1698,7 +1711,7 @@ charm@^1.0.0: dependencies: inherits "^2.0.1" -check-error@^1.0.2: +check-error@^1.0.1, check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" @@ -1822,10 +1835,6 @@ colors@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" -colors@~0.6.0-1: - version "0.6.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" - combined-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" @@ -1850,10 +1859,6 @@ commander@^2.5.0, commander@^2.6.0: version "2.11.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" -commander@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781" - common-tags@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.4.0.tgz#1187be4f3d4cf0c0427d43f74eef1f73501614c0" @@ -2077,6 +2082,12 @@ debug@2.3.3: dependencies: ms "0.7.2" +debug@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2087,6 +2098,12 @@ deep-eql@^0.1.3: dependencies: type-detect "0.1.1" +deep-eql@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + dependencies: + type-detect "^4.0.0" + deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -2244,20 +2261,18 @@ ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.8.0, e clone "^2.0.0" ember-cli-version-checker "^2.0.0" -ember-cli-blueprint-test-helpers@0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.11.0.tgz#252530b7d1e3e93c01526cad08cc6b184a967487" +ember-cli-blueprint-test-helpers@^0.18.3: + version "0.18.3" + resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.18.3.tgz#945c606d855f0263f5e8c03522e4040a74f259cc" dependencies: - chai "^3.3.0" - chai-as-promised "^5.1.0" + chai "^4.1.0" + chai-as-promised "^7.0.0" chai-files "^1.0.0" - debug "^2.2.0" - ember-cli-internal-test-helpers "^0.8.1" - exists-sync "0.0.3" - findup "^0.1.5" - fs-extra "^0.26.7" + debug "^3.0.0" + ember-cli-internal-test-helpers "^0.9.1" + fs-extra "^4.0.0" + testdouble "^3.2.6" tmp-sync "^1.0.0" - walk-sync "^0.2.5" ember-cli-broccoli-sane-watcher@^2.0.4: version "2.0.4" @@ -2333,6 +2348,23 @@ ember-cli-internal-test-helpers@^0.8.1: through "^2.3.8" walk-sync "^0.3.1" +ember-cli-internal-test-helpers@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.9.1.tgz#d54a9124bb6408ceba83f049ba8479f4b96cdd19" + dependencies: + chai "^3.3.0" + chai-as-promised "^6.0.0" + chai-files "^1.1.0" + chalk "^1.1.1" + debug "^2.2.0" + exists-sync "0.0.3" + fs-extra "^0.30.0" + lodash "^4.0.0" + rsvp "^3.0.17" + symlink-or-copy "^1.0.1" + through "^2.3.8" + walk-sync "^0.3.1" + ember-cli-is-package-missing@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" @@ -3215,13 +3247,6 @@ findup-sync@^1.0.0: micromatch "^2.3.7" resolve-dir "^0.1.0" -findup@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb" - dependencies: - colors "~0.6.0-1" - commander "~2.1.0" - fireworm@^0.7.0: version "0.7.1" resolved "https://registry.yarnpkg.com/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" @@ -3298,7 +3323,7 @@ fs-extra@^0.24.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" -fs-extra@^0.26.0, fs-extra@^0.26.7: +fs-extra@^0.26.0: version "0.26.7" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" dependencies: @@ -3395,6 +3420,10 @@ get-caller-file@^1.0.0, get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" +get-func-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" @@ -5139,6 +5168,10 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" +pathval@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" + pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -6209,6 +6242,10 @@ type-detect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" +type-detect@^4.0.0: + version "4.0.5" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.5.tgz#d70e5bc81db6de2a381bcaca0c6e0cbdc7635de2" + type-is@~1.6.15: version "1.6.15" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" From e9f11a4918f03eeb2198f9074d6a306a5d323317 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Mon, 18 Dec 2017 10:53:18 -0500 Subject: [PATCH 2073/2527] Fix the ember-try canary scenario by polyfilling WeakMap (#5281) --- ember-cli-build.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ember-cli-build.js b/ember-cli-build.js index c17b7d456eb..ec588e8a84e 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -26,6 +26,9 @@ module.exports = function(defaults) { // while ember-data strips itself, ember does not currently [StripClassCallCheck] ] + }, + 'ember-cli-babel': { + includePolyfill: true } }); From 860594b54bf4f52223a697dabb7896bbf151e165 Mon Sep 17 00:00:00 2001 From: Todd Jordan Date: Mon, 18 Dec 2017 11:07:09 -0600 Subject: [PATCH 2074/2527] [doc beta]document extractRelationship in json-api.js (#5280) --- addon/serializers/json-api.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 7703956aa71..cbc18bfb6d1 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -301,6 +301,15 @@ const JSONAPISerializer = JSONSerializer.extend({ return attributes; }, + /** + Returns a relationship formatted as a JSON-API "relationship object". + + http://jsonapi.org/format/#document-resource-object-relationships + + @method extractRelationship + @param {Object} relationshipHash + @return {Object} + */ extractRelationship(relationshipHash) { if (typeOf(relationshipHash.data) === 'object') { @@ -321,6 +330,16 @@ const JSONAPISerializer = JSONSerializer.extend({ return relationshipHash; }, + /** + Returns the resource's relationships formatted as a JSON-API "relationships object". + + http://jsonapi.org/format/#document-resource-object-relationships + + @method extractRelationships + @param {Object} modelClass + @param {Object} resourceHash + @return {Object} + */ extractRelationships(modelClass, resourceHash) { let relationships = {}; From 91c533c6bcd642369ada6dc964059451386b2ab4 Mon Sep 17 00:00:00 2001 From: Eli Flanagan Date: Mon, 18 Dec 2017 12:20:52 -0500 Subject: [PATCH 2075/2527] update deprecation references (#5283) --- addon/-private/system/references/belongs-to.js | 2 +- addon/-private/system/references/has-many.js | 4 ++-- addon/serializers/json-api.js | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 7f0deb237ea..0344a931d47 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -247,7 +247,7 @@ BelongsToReference.prototype.push = function(objectOrPromise) { if (isEnabled('ds-overhaul-references')) { deprecate("BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead.", false, { id: 'ds.references.belongs-to.push-record', - until: '3.0' + until: '4.0.0' }); } record = data; diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index e60cc5b7f47..26ac78b45d9 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -246,7 +246,7 @@ HasManyReference.prototype.push = function(objectOrPromise) { if (isEnabled("ds-overhaul-references")) { deprecate("HasManyReference#push(array) is deprecated. Push a JSON-API document instead.", !Array.isArray(payload), { id: 'ds.references.has-many.push-array', - until: '3.0' + until: '4.0.0' }); } @@ -258,7 +258,7 @@ HasManyReference.prototype.push = function(objectOrPromise) { if (isEnabled('ds-overhaul-references')) { deprecate("HasManyReference#push() expects a valid JSON-API document.", !useLegacyArrayPush, { id: 'ds.references.has-many.push-invalid-json-api', - until: '3.0' + until: '4.0.0' }); } } diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index cbc18bfb6d1..132d1d2b94c 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -181,7 +181,7 @@ const JSONAPISerializer = JSONSerializer.extend({ if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { deprecate("You are using modelNameFromPayloadKey to normalize the type for a relationship. This has been deprecated in favor of modelNameFromPayloadType", false, { id: 'ds.json-api-serializer.deprecated-model-name-for-relationship', - until: '3.0.0' + until: '4.0.0' }); modelName = deprecatedModelNameLookup; @@ -217,7 +217,7 @@ const JSONAPISerializer = JSONSerializer.extend({ if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { deprecate("You are using modelNameFromPayloadKey to normalize the type for a resource. This has been deprecated in favor of modelNameFromPayloadType", false, { id: 'ds.json-api-serializer.deprecated-model-name-for-resource', - until: '3.0.0' + until: '4.0.0' }); modelName = deprecatedModelNameLookup; @@ -515,7 +515,7 @@ const JSONAPISerializer = JSONSerializer.extend({ if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { deprecate("You used payloadKeyFromModelName to customize how a type is serialized. Use payloadTypeFromModelName instead.", false, { id: 'ds.json-api-serializer.deprecated-payload-type-for-model', - until: '3.0.0' + until: '4.0.0' }); payloadType = deprecatedPayloadTypeLookup; @@ -575,7 +575,7 @@ const JSONAPISerializer = JSONSerializer.extend({ if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { deprecate("You used payloadKeyFromModelName to serialize type for belongs-to relationship. Use payloadTypeFromModelName instead.", false, { id: 'ds.json-api-serializer.deprecated-payload-type-for-belongs-to', - until: '3.0.0' + until: '4.0.0' }); payloadType = deprecatedPayloadTypeLookup; @@ -627,7 +627,7 @@ const JSONAPISerializer = JSONSerializer.extend({ if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { deprecate("You used payloadKeyFromModelName to serialize type for belongs-to relationship. Use payloadTypeFromModelName instead.", false, { id: 'ds.json-api-serializer.deprecated-payload-type-for-has-many', - until: '3.0.0' + until: '4.0.0' }); payloadType = deprecatedPayloadTypeLookup; From 83124968a6b52150f63b05bab46bd22b3ecddb65 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 18 Dec 2017 13:35:57 -0500 Subject: [PATCH 2076/2527] Remove deprecation messages for old instance initializers --- addon/initialize-store-service.js | 51 -------------------------- app/initializers/data-adapter.js | 12 ------- app/initializers/injectStore.js | 12 ------- app/initializers/store.js | 12 ------- app/initializers/transforms.js | 12 ------- tests/integration/application-test.js | 52 --------------------------- 6 files changed, 151 deletions(-) delete mode 100644 app/initializers/data-adapter.js delete mode 100644 app/initializers/injectStore.js delete mode 100644 app/initializers/store.js delete mode 100644 app/initializers/transforms.js diff --git a/addon/initialize-store-service.js b/addon/initialize-store-service.js index 8c03288b54e..57031dc3530 100644 --- a/addon/initialize-store-service.js +++ b/addon/initialize-store-service.js @@ -1,8 +1,3 @@ -import { deprecate } from '@ember/debug'; -import { DEBUG } from '@glimmer/env'; - -let deprecateOldEmberDataInitializers; - /* Configures a registry for use with an Ember-Data store. @@ -17,50 +12,4 @@ export default function initializeStoreService(instance) { // Eagerly generate the store so defaultStore is populated. container.lookup('service:store'); - - if (DEBUG) { - // In Ember 2.4+ instance.base is the `Ember.Application` or `Ember.Engine` instance - // In Ember 1.11 - 2.3 we fallback to `instance.application` - let base = instance.base || instance.application; - deprecateOldEmberDataInitializers(base.constructor.initializers); - } -} - -if (DEBUG) { - const DEPRECATED_INITIALIZER_NAMES = ['data-adapter', 'injectStore', 'transforms', 'store']; - - let matchesDeprecatedInititalizer = function matchesDeprecatedInititalizer(name) { - return DEPRECATED_INITIALIZER_NAMES.indexOf(name) !== -1; - }; - - let warnForDeprecatedInitializers = function warnForDeprecatedInitializers(initializer) { - let deprecatedBeforeInitializer = matchesDeprecatedInititalizer(initializer.before); - let deprecatedAfterInitializer = matchesDeprecatedInititalizer(initializer.after); - let deprecatedProp = deprecatedBeforeInitializer ? 'before' : 'after'; - - deprecate( - `The initializer \`${initializer[deprecatedProp]}\` has been deprecated. Please update your \`${initializer.name}\` initializer to use use \`${deprecatedProp}: \'ember-data\'\` instead.`, - !(deprecatedBeforeInitializer || deprecatedAfterInitializer), - { - id: 'ds.deprecated-initializers', - until: '3.0.0' - }); - }; - - deprecateOldEmberDataInitializers = function deprecateOldEmberDataInitializers(initializers) { - // collect all of the initializers - let keys = Object.keys(initializers); - - for (let i = 0; i < keys.length; i++) { - let name = keys[i]; - - // filter out all of the Ember Data initializer. We have some - // deprecated initializers that depend on other deprecated - // initializers which may trigger the deprecation warning - // unintentionally. - if (!matchesDeprecatedInititalizer(name)) { - warnForDeprecatedInitializers(initializers[name]); - } - } - }; } diff --git a/app/initializers/data-adapter.js b/app/initializers/data-adapter.js deleted file mode 100644 index b4c40cf2445..00000000000 --- a/app/initializers/data-adapter.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - This initializer is here to keep backwards compatibility with code depending - on the `data-adapter` initializer (before Ember Data was an addon). - - Should be removed for Ember Data 3.x -*/ - -export default { - name: 'data-adapter', - before: 'store', - initialize() {} -}; diff --git a/app/initializers/injectStore.js b/app/initializers/injectStore.js deleted file mode 100644 index fce063a52e5..00000000000 --- a/app/initializers/injectStore.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - This initializer is here to keep backwards compatibility with code depending - on the `injectStore` initializer (before Ember Data was an addon). - - Should be removed for Ember Data 3.x -*/ - -export default { - name: 'injectStore', - before: 'store', - initialize() {} -}; diff --git a/app/initializers/store.js b/app/initializers/store.js deleted file mode 100644 index e0884ec74a6..00000000000 --- a/app/initializers/store.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - This initializer is here to keep backwards compatibility with code depending - on the `store` initializer (before Ember Data was an addon). - - Should be removed for Ember Data 3.x -*/ - -export default { - name: 'store', - after: 'ember-data', - initialize() {} -}; diff --git a/app/initializers/transforms.js b/app/initializers/transforms.js deleted file mode 100644 index b666640831b..00000000000 --- a/app/initializers/transforms.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - This initializer is here to keep backwards compatibility with code depending - on the `transforms` initializer (before Ember Data was an addon). - - Should be removed for Ember Data 3.x -*/ - -export default { - name: 'transforms', - before: 'store', - initialize() {} -}; diff --git a/tests/integration/application-test.js b/tests/integration/application-test.js index 564097613bd..d09499705c7 100644 --- a/tests/integration/application-test.js +++ b/tests/integration/application-test.js @@ -3,7 +3,6 @@ import Controller from '@ember/controller'; import Application from '@ember/application'; import { run } from '@ember/runloop'; import Ember from 'ember'; -import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; @@ -182,54 +181,3 @@ test("ember-data initializer does not register the store service when it was alr assert.ok(store && store.get('isCustomStore'), 'ember-data initializer does not overwrite the previous registered service store'); }); - -testInDebug("store initializer is run (DEPRECATED)", function(assert) { - let ran = false; - App.initializer({ - name: "after-store", - after: 'store', - initialize() { ran = true; } - }); - - assert.expectDeprecation(() => { - run(() => { - app = App.create(); - }); - }, /The initializer `store` has been deprecated/) - - assert.ok(ran, 'store initializer was found'); -}); - -testInDebug("injectStore initializer is run (DEPRECATED)", function(assert) { - let ran = false; - App.initializer({ - name: "after-store", - after: 'injectStore', - initialize() { ran = true; } - }); - - assert.expectDeprecation(() => { - run(() => { - app = App.create(); - }); - }, /The initializer `injectStore` has been deprecated/) - - assert.ok(ran, 'injectStore initializer was found'); -}); - -testInDebug("transforms initializer is run (DEPRECATED)", function(assert) { - let ran = false; - App.initializer({ - name: "after-store", - after: 'transforms', - initialize() { ran = true; } - }); - - assert.expectDeprecation(() => { - run(() => { - app = App.create(); - }); - }, /The initializer `transforms` has been deprecated/) - - assert.ok(ran, 'transforms initializer was found'); -}); From fe17eb3b653fa8dbea4e3619f3c6fb5be835ea0f Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 18 Dec 2017 13:41:14 -0500 Subject: [PATCH 2077/2527] Remove deprecation/support for complex object as defaultValues of DS.attr --- addon/attr.js | 9 +++------ tests/unit/model-test.js | 19 ++----------------- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/addon/attr.js b/addon/attr.js index 9436a5ac818..2a49d22ed64 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -1,5 +1,5 @@ import { computed } from '@ember/object'; -import { deprecate } from '@ember/debug'; +import { assert } from '@ember/debug'; /** @module ember-data @@ -10,11 +10,8 @@ function getDefaultValue(record, options, key) { return options.defaultValue.apply(null, arguments); } else { let defaultValue = options.defaultValue; - deprecate(`Non primitive defaultValues are deprecated because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.`, - typeof defaultValue !== 'object' || defaultValue === null, { - id: 'ds.defaultValue.complex-object', - until: '3.0.0' - }); + assert(`Non primitive defaultValues are not supported because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.`, + typeof defaultValue !== 'object' || defaultValue === null); return defaultValue; } } diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index f243044a77a..f313550ded7 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -913,24 +913,9 @@ testInDebug('a complex object defaultValue is deprecated', function(assert) { let tag = run(() => store.createRecord('tag')); - assert.expectDeprecation(() => { + assert.expectAssertion(() => { get(tag, 'tagInfo'); - }, /Non primitive defaultValues are deprecated/); -}); - -testInDebug('a null defaultValue is not deprecated', function(assert) { - const Tag = DS.Model.extend({ - tagInfo: DS.attr({ defaultValue: null }) - }); - - let store = createStore({ - tag: Tag - }); - - let tag = run(() => store.createRecord('tag')); - - assert.expectNoDeprecation(); - assert.strictEqual(get(tag, 'tagInfo'), null); + }, /Non primitive defaultValues are not supported/); }); test('setting a property to undefined on a newly created record should not impact the current state', function(assert) { From fb08074131b1074cba427d0a9c9ced59ac670407 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 18 Dec 2017 13:51:56 -0500 Subject: [PATCH 2078/2527] Remove date transforms deprecations and support for Ember.Date.parse --- addon/transforms/date.js | 46 +------------------------------ tests/unit/transform/date-test.js | 27 ------------------ 2 files changed, 1 insertion(+), 72 deletions(-) diff --git a/addon/transforms/date.js b/addon/transforms/date.js index 98152339160..e984ca9f448 100644 --- a/addon/transforms/date.js +++ b/addon/transforms/date.js @@ -1,36 +1,4 @@ import Transform from './transform'; -import Ember from 'ember'; -import { deprecate } from '@ember/debug'; - -Ember.Date = Ember.Date || {}; - -/** - Date.parse with progressive enhancement for ISO 8601 - - © 2011 Colin Snover - - Released under MIT license. - - @class Date - @namespace Ember - @static - @deprecated - */ -Ember.Date.parse = function(date) { - // throw deprecation - deprecate(`Ember.Date.parse is deprecated because Safari 5-, IE8-, and - Firefox 3.6- are no longer supported (see - https://github.com/csnover/js-iso8601 for the history of this issue). - Please use Date.parse instead`, - false, - { - id: 'ds.ember.date.parse-deprecate', - until: '3.0.0' - }); - - return Date.parse(date); -}; - /** The `DS.DateTransform` class is used to serialize and deserialize @@ -61,19 +29,7 @@ export default Transform.extend({ if (type === "string") { let offset = serialized.indexOf('+'); - if (offset !== -1 && serialized.length - 3 === offset) { - deprecate(`The ECMA2015 Spec for ISO 8601 dates does not allow for shorthand timezone offsets such as +00. - Ember Data's normalization of date's allowing for this shorthand has been deprecated, please update your API to return - UTC dates formatted with ±hh:mm timezone offsets or implement a custom UTC transform.`, - false, - { - id: 'ds.attr.date.normalize-utc', - until: '3.0.0' - }); - return new Date(`${serialized}:00`); - - // this is a phantom specific bug fix in which +0000 is not supported - } else if (offset !== -1 && serialized.length - 5 === offset) { + if (offset !== -1 && serialized.length - 5 === offset) { offset += 3; return new Date(serialized.slice(0, offset) + ':' + serialized.slice(offset)); } diff --git a/tests/unit/transform/date-test.js b/tests/unit/transform/date-test.js index 558e4444e8d..d145d6046c2 100644 --- a/tests/unit/transform/date-test.js +++ b/tests/unit/transform/date-test.js @@ -1,9 +1,6 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; -import Ember from 'ember'; - -import testInDebug from 'dummy/tests/helpers/test-in-debug'; module('unit/transform - DS.DateTransform'); @@ -37,27 +34,3 @@ test('#deserialize', function(assert) { assert.strictEqual(transform.deserialize(null), null); assert.strictEqual(transform.deserialize(undefined), undefined); }); - -testInDebug('#deserialize with different offset formats', function(assert) { - let transform = new DS.DateTransform(); - let dateString = '2003-05-24T23:00:00.000+0000'; - let dateStringColon = '2013-03-15T23:22:00.000+00:00'; - let dateStringShortOffset = '2016-12-02T17:30:00.000+00'; - - assert.expect(4); - - let deserialized; - assert.expectDeprecation(() => { - deserialized = transform.deserialize(dateStringShortOffset).getTime(); - }, /The ECMA2015 Spec for ISO 8601 dates does not allow for shorthand timezone offsets such as \+00/); - - assert.equal(transform.deserialize(dateString).getTime(), 1053817200000, 'date-strings with no-colon offsets are ok'); - assert.equal(deserialized, 1480699800000, 'This test can be removed once the deprecation is removed'); - assert.equal(transform.deserialize(dateStringColon).getTime(), 1363389720000, 'date-strings with colon offsets are ok'); -}); - -testInDebug('Ember.Date.parse has been deprecated', function(assert) { - assert.expectDeprecation(() => { - Ember.Date.parse(dateString); - }, /Ember.Date.parse is deprecated/); -}); From 8173a037444ec0625b3b9760123d2d2e7a9e160d Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 18 Dec 2017 14:20:38 -0500 Subject: [PATCH 2079/2527] Remove deprecation around shouldSerializeHasMany --- addon/serializers/json-api.js | 6 +--- addon/serializers/json.js | 28 +------------------ config/features.json | 1 - .../serializers/json-serializer-test.js | 10 ------- 4 files changed, 2 insertions(+), 43 deletions(-) diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 132d1d2b94c..6f410fa5881 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -597,12 +597,8 @@ const JSONAPISerializer = JSONSerializer.extend({ serializeHasMany(snapshot, json, relationship) { let key = relationship.key; - let shouldSerializeHasMany = '_shouldSerializeHasMany'; - if (isEnabled("ds-check-should-serialize-relationships")) { - shouldSerializeHasMany = 'shouldSerializeHasMany'; - } - if (this[shouldSerializeHasMany](snapshot, key, relationship)) { + if (this.shouldSerializeHasMany(snapshot, key, relationship)) { let hasMany = snapshot.hasMany(key); if (hasMany !== undefined) { diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 1008ca381d7..1970d21dcb5 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -846,29 +846,7 @@ const JSONSerializer = Serializer.extend({ @param {String} relationshipType @return {boolean} true if the hasMany relationship should be serialized */ - shouldSerializeHasMany(snapshot, key, relationship) { - if ((this._shouldSerializeHasMany !== JSONSerializer.prototype._shouldSerializeHasMany)) { - deprecate('The private method _shouldSerializeHasMany has been promoted to the public API. Please remove the underscore to use the public shouldSerializeHasMany method.', false, { - id: 'ds.serializer.private-should-serialize-has-many', - until: '3.0.0' - }); - } - - return this._shouldSerializeHasMany(snapshot, key, relationship); - }, - - /** - Check if the given hasMany relationship should be serialized - - @method _shouldSerializeHasMany - @private - @param {DS.Snapshot} snapshot - @param {String} key - @param {String} relationshipType - @return {boolean} true if the hasMany relationship should be serialized - */ - _shouldSerializeHasMany(snapshot, key, relationship) { let relationshipType = snapshot.type.determineRelationshipType(relationship, this.store); if (this._mustSerialize(key)) { return true; @@ -1219,12 +1197,8 @@ const JSONSerializer = Serializer.extend({ */ serializeHasMany(snapshot, json, relationship) { let key = relationship.key; - let shouldSerializeHasMany = '_shouldSerializeHasMany'; - if (isEnabled("ds-check-should-serialize-relationships")) { - shouldSerializeHasMany = 'shouldSerializeHasMany'; - } - if (this[shouldSerializeHasMany](snapshot, key, relationship)) { + if (this.shouldSerializeHasMany(snapshot, key, relationship)) { let hasMany = snapshot.hasMany(key, { ids: true }); if (hasMany !== undefined) { // if provided, use the mapping provided by `attrs` in diff --git a/config/features.json b/config/features.json index ecff8f33518..e7bcedaf466 100644 --- a/config/features.json +++ b/config/features.json @@ -3,7 +3,6 @@ "ds-pushpayload-return": null, "ds-overhaul-references": null, "ds-payload-type-hooks": null, - "ds-check-should-serialize-relationships": true, "ds-rollback-attribute": null, "ds-serialize-id": null, "ds-deprecate-store-serialize": true diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 920e6064adf..9e13bef9304 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -291,16 +291,6 @@ test("shouldSerializeHasMany", function(assert) { assert.ok(shouldSerialize, 'shouldSerializeHasMany correctly identifies with hasMany relationship'); }); -if (isEnabled("ds-check-should-serialize-relationships")) { - testInDebug("_shouldSerializeHasMany deprecation", function(assert) { - env.store.serializerFor("post")._shouldSerializeHasMany = function() {}; - - assert.expectDeprecation(function() { - env.store.serializerFor("post").shouldSerializeHasMany(); - }, /_shouldSerializeHasMany has been promoted to the public API/); - }); -} - test("serializeIntoHash", function(assert) { run(() => { post = env.store.createRecord('post', { title: "Rails is omakase", comments: [] }); From c99cb01e42cf02207e392f193d8017b01ffd4a45 Mon Sep 17 00:00:00 2001 From: Eli Flanagan Date: Mon, 18 Dec 2017 14:22:18 -0500 Subject: [PATCH 2080/2527] disable package-lock.json, update docs (#5284) --- .npmrc | 1 + README.md | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 .npmrc diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000000..43c97e719a5 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/README.md b/README.md index f422fe380e9..25e1cc1b282 100644 --- a/README.md +++ b/README.md @@ -171,8 +171,8 @@ on models](https://emberjs.com/guides/models/). # Building Ember Data -1. Ensure that [Node.js](http://nodejs.org/) is installed. -2. Run `npm install` to ensure the required dependencies are installed. +1. Ensure that [Node.js](http://nodejs.org/) and [yarn](https://yarnpkg.com/en/docs/install) are installed. +2. Run `yarn install` to ensure the required dependencies are installed. 3. Run `npm run production` to build Ember Data. The builds will be placed in the `dist/` directory. # Contribution @@ -187,7 +187,7 @@ See [CONTRIBUTING.md](https://github.com/emberjs/data/blob/master/CONTRIBUTING.m 2. Install Ember CLI. `npm install -g ember-cli` -3. Run `npm install` inside the project root to install the JS dependencies. +3. Run `yarn install` inside the project root to install the JS dependencies. ### In Your Browser From baae2432871bd711af5da3a6a98abe653bb993d0 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 18 Dec 2017 14:30:22 -0500 Subject: [PATCH 2081/2527] Remove deprecation and fallback for keyForAttribute when keyForPolymorphicType should be called --- addon/serializers/rest.js | 18 ---------------- .../serializers/rest-serializer-test.js | 21 ------------------- 2 files changed, 39 deletions(-) diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index f10533fd614..fa3dc9e756c 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -762,24 +762,6 @@ const RESTSerializer = JSONSerializer.extend({ let typeKey = this.keyForPolymorphicType(key, relationship.type, 'serialize'); let belongsTo = snapshot.belongsTo(key); - // old way of getting the key for the polymorphic type - key = this.keyForAttribute ? this.keyForAttribute(key, "serialize") : key; - key = `${key}Type`; - - // The old way of serializing the type of a polymorphic record used - // `keyForAttribute`, which is not correct. The next code checks if the old - // way is used and if it differs from the new way of using - // `keyForPolymorphicType`. If this is the case, a deprecation warning is - // logged and the old way is restored (so nothing breaks). - if (key !== typeKey && this.keyForPolymorphicType === RESTSerializer.prototype.keyForPolymorphicType) { - deprecate("The key to serialize the type of a polymorphic record is created via keyForAttribute which has been deprecated. Use the keyForPolymorphicType hook instead.", false, { - id: 'ds.rest-serializer.deprecated-key-for-polymorphic-type', - until: '3.0.0' - }); - - typeKey = key; - } - if (isNone(belongsTo)) { json[typeKey] = null; } else { diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index f2aca2c68ae..8516c28d9e5 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -573,27 +573,6 @@ test('serializeBelongsTo with async polymorphic', function(assert) { assert.deepEqual(json, expected, 'returned JSON is correct'); }); -testInDebug('serializeBelongsTo logs deprecation when old behavior for getting polymorphic type key is used', function(assert) { - var evilMinion, doomsdayDevice; - var json = {}; - var expected = { evilMinion: '1', myCustomKeyType: 'evilMinion' }; - - env.restSerializer.keyForAttribute = function() { - return 'myCustomKey'; - }; - - run(function() { - evilMinion = env.store.createRecord('evil-minion', { id: 1, name: 'Tomster' }); - doomsdayDevice = env.store.createRecord('doomsday-device', { id: 2, name: 'Yehuda', evilMinion: evilMinion }); - }); - - assert.expectDeprecation(function() { - env.restSerializer.serializeBelongsTo(doomsdayDevice._createSnapshot(), json, { key: 'evilMinion', options: { polymorphic: true, async: true } }); - }, "The key to serialize the type of a polymorphic record is created via keyForAttribute which has been deprecated. Use the keyForPolymorphicType hook instead."); - - assert.deepEqual(json, expected, 'returned JSON is correct'); -}); - test('keyForPolymorphicType can be used to overwrite how the type of a polymorphic record is serialized', function(assert) { var evilMinion, doomsdayDevice; var json = {}; From c542f640afaf60bd74dad83225cad82012c9d864 Mon Sep 17 00:00:00 2001 From: Alex Alvarez Date: Tue, 19 Dec 2017 09:26:24 -0500 Subject: [PATCH 2082/2527] cleanup: node-tests cleanup (#5293) * cleanup: testing improvements - model tests * cleanup adapter tests * serializer-tests * transform tests * formatting * Revert changes to test-framework-detector * More formatting * Use strict mode --- .../tests/unit/__path__/__test__.js | 2 +- node-tests/blueprints/adapter-test.js | 53 +++++++++-------- node-tests/blueprints/model-test.js | 58 +++++++++---------- node-tests/blueprints/serializer-test.js | 54 +++++++++-------- node-tests/blueprints/transform-test.js | 35 ++++++----- .../adapter-test/application-default.js | 12 ++++ .../fixtures/adapter-test/foo-default.js | 12 ++++ .../fixtures/adapter-test/foo-mocha-0.12.js | 16 +++++ .../fixtures/model-test/comment-default.js | 12 ++++ node-tests/fixtures/model-test/foo-default.js | 12 ++++ .../fixtures/model-test/foo-mocha-0.12.js | 17 ++++++ .../fixtures/model-test/post-default.js | 12 ++++ .../serializer-test/application-default.js | 15 +++++ .../fixtures/serializer-test/foo-default.js | 15 +++++ .../serializer-test/foo-mocha-0.12.js | 19 ++++++ node-tests/fixtures/transform-test/default.js | 12 ++++ .../fixtures/transform-test/mocha-0.12.js | 16 +++++ node-tests/helpers/fixture.js | 8 +++ 18 files changed, 276 insertions(+), 104 deletions(-) create mode 100644 node-tests/fixtures/adapter-test/application-default.js create mode 100644 node-tests/fixtures/adapter-test/foo-default.js create mode 100644 node-tests/fixtures/adapter-test/foo-mocha-0.12.js create mode 100644 node-tests/fixtures/model-test/comment-default.js create mode 100644 node-tests/fixtures/model-test/foo-default.js create mode 100644 node-tests/fixtures/model-test/foo-mocha-0.12.js create mode 100644 node-tests/fixtures/model-test/post-default.js create mode 100644 node-tests/fixtures/serializer-test/application-default.js create mode 100644 node-tests/fixtures/serializer-test/foo-default.js create mode 100644 node-tests/fixtures/serializer-test/foo-mocha-0.12.js create mode 100644 node-tests/fixtures/transform-test/default.js create mode 100644 node-tests/fixtures/transform-test/mocha-0.12.js create mode 100644 node-tests/helpers/fixture.js diff --git a/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js index 6850a578f78..bf871e251a2 100644 --- a/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js +++ b/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js @@ -5,7 +5,7 @@ import { setupModelTest } from 'ember-mocha'; describe('<%= friendlyDescription %>', function() { setupModelTest('<%= dasherizedModuleName %>', { // Specify the other units that are required for this test. - <%= typeof needs !== 'undefined' ? needs : '' %> + <%= typeof needs !== 'undefined' ? needs : '' %> }); // Replace this with your real tests. diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 38a4d5cc000..3b6f0f98ad1 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -1,22 +1,25 @@ -var blueprintHelpers = require('ember-cli-blueprint-test-helpers/helpers'); -var setupTestHooks = blueprintHelpers.setupTestHooks; -var emberNew = blueprintHelpers.emberNew; -var emberGenerate = blueprintHelpers.emberGenerate; -var emberGenerateDestroy = blueprintHelpers.emberGenerateDestroy; -var modifyPackages = blueprintHelpers.modifyPackages; +'use strict'; -var chai = require('ember-cli-blueprint-test-helpers/chai'); -var expect = chai.expect; +const blueprintHelpers = require('ember-cli-blueprint-test-helpers/helpers'); +const setupTestHooks = blueprintHelpers.setupTestHooks; +const emberNew = blueprintHelpers.emberNew; +const emberGenerate = blueprintHelpers.emberGenerate; +const emberGenerateDestroy = blueprintHelpers.emberGenerateDestroy; +const modifyPackages = blueprintHelpers.modifyPackages; -var SilentError = require('silent-error'); +const chai = require('ember-cli-blueprint-test-helpers/chai'); +const expect = chai.expect; -var generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); +const SilentError = require('silent-error'); + +const generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); +const fixture = require('../helpers/fixture'); describe('Acceptance: generate and destroy adapter blueprints', function() { setupTestHooks(this); it('adapter', function() { - var args = ['adapter', 'foo']; + let args = ['adapter', 'foo']; return emberNew() .then(() => emberGenerateDestroy(args, _file => { @@ -25,12 +28,12 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { .to.contain('export default DS.JSONAPIAdapter.extend({'); expect(_file('tests/unit/adapters/foo-test.js')) - .to.contain('moduleFor(\'adapter:foo\''); + .to.equal(fixture('adapter-test/foo-default.js')); })); }); it('adapter extends application adapter if it exists', function() { - var args = ['adapter', 'foo']; + let args = ['adapter', 'foo']; return emberNew() .then(() => emberGenerate(['adapter', 'application'])) @@ -40,12 +43,12 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { .to.contain('export default ApplicationAdapter.extend({'); expect(_file('tests/unit/adapters/foo-test.js')) - .to.contain('moduleFor(\'adapter:foo\''); + .to.equal(fixture('adapter-test/foo-default.js')); })); }); it('adapter with --base-class', function() { - var args = ['adapter', 'foo', '--base-class=bar']; + let args = ['adapter', 'foo', '--base-class=bar']; return emberNew() .then(() => emberGenerateDestroy(args, _file => { @@ -54,12 +57,12 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { .to.contain('export default BarAdapter.extend({'); expect(_file('tests/unit/adapters/foo-test.js')) - .to.contain('moduleFor(\'adapter:foo\''); + .to.equal(fixture('adapter-test/foo-default.js')); })); }); xit('adapter throws when --base-class is same as name', function() { - var args = ['adapter', 'foo', '--base-class=foo']; + let args = ['adapter', 'foo', '--base-class=foo']; return emberNew() .then(() => expect(emberGenerate(args)) @@ -67,7 +70,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { }); it('adapter when is named "application"', function() { - var args = ['adapter', 'application']; + let args = ['adapter', 'application']; return emberNew() .then(() => emberGenerateDestroy(args, _file => { @@ -76,22 +79,22 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { .to.contain('export default DS.JSONAPIAdapter.extend({'); expect(_file('tests/unit/adapters/application-test.js')) - .to.contain('moduleFor(\'adapter:application\''); + .to.equal(fixture('adapter-test/application-default.js')); })); }); it('adapter-test', function() { - var args = ['adapter-test', 'foo']; + let args = ['adapter-test', 'foo']; return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/unit/adapters/foo-test.js')) - .to.contain('moduleFor(\'adapter:foo\''); + .to.equal(fixture('adapter-test/foo-default.js')); })); }); it('adapter-test for mocha v0.12+', function() { - var args = ['adapter-test', 'foo']; + let args = ['adapter-test', 'foo']; return emberNew() .then(() => modifyPackages([ @@ -101,11 +104,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { .then(() => generateFakePackageManifest('ember-cli-mocha', '0.12.0')) .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/unit/adapters/foo-test.js')) - .to.contain('import { describe, it } from \'mocha\';') - .to.contain('import { setupTest } from \'ember-mocha\';') - .to.contain('describe(\'Unit | Adapter | foo\', function() {') - .to.contain('setupTest(\'adapter:foo\',') - .to.contain('expect(adapter).to.be.ok;'); + .to.equal(fixture('adapter-test/foo-mocha-0.12.js')); })); }); }); diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index d0d1eaa8078..e96a0016a4e 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -1,33 +1,37 @@ -var blueprintHelpers = require('ember-cli-blueprint-test-helpers/helpers'); -var setupTestHooks = blueprintHelpers.setupTestHooks; -var emberNew = blueprintHelpers.emberNew; -var emberGenerateDestroy = blueprintHelpers.emberGenerateDestroy; -var modifyPackages = blueprintHelpers.modifyPackages; +'use strict'; -var chai = require('ember-cli-blueprint-test-helpers/chai'); -var expect = chai.expect; +const blueprintHelpers = require('ember-cli-blueprint-test-helpers/helpers'); +const setupTestHooks = blueprintHelpers.setupTestHooks; +const emberNew = blueprintHelpers.emberNew; +const emberGenerateDestroy = blueprintHelpers.emberGenerateDestroy; +const modifyPackages = blueprintHelpers.modifyPackages; + +const chai = require('ember-cli-blueprint-test-helpers/chai'); +const expect = chai.expect; + +const generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); +const fixture = require('../helpers/fixture'); -var generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); describe('Acceptance: generate and destroy model blueprints', function() { setupTestHooks(this); it('model', function() { - var args = ['model', 'foo']; + let args = ['model', 'foo']; return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/models/foo.js')) .to.contain('import DS from \'ember-data\';') - .to.contain('export default DS.Model.extend(') + .to.contain('export default DS.Model.extend('); expect(_file('tests/unit/models/foo-test.js')) - .to.contain('moduleForModel(\'foo\''); + .to.equal(fixture('model-test/foo-default.js')); })); }); it('model with attrs', function() { - var args = [ + let args = [ 'model', 'foo', 'misc', @@ -52,15 +56,15 @@ describe('Acceptance: generate and destroy model blueprints', function() { .to.contain('someObject: DS.attr(\'object\')') .to.contain('age: DS.attr(\'number\')') .to.contain('name: DS.attr(\'string\')') - .to.contain('customAttr: DS.attr(\'custom-transform\')') + .to.contain('customAttr: DS.attr(\'custom-transform\')'); expect(_file('tests/unit/models/foo-test.js')) - .to.contain('moduleForModel(\'foo\''); + .to.equal(fixture('model-test/foo-default.js')); })); }); it('model with belongsTo', function() { - var args = ['model', 'comment', 'post:belongs-to', 'author:belongs-to:user']; + let args = ['model', 'comment', 'post:belongs-to', 'author:belongs-to:user']; return emberNew() .then(() => emberGenerateDestroy(args, _file => { @@ -68,16 +72,15 @@ describe('Acceptance: generate and destroy model blueprints', function() { .to.contain('import DS from \'ember-data\';') .to.contain('export default DS.Model.extend(') .to.contain('post: DS.belongsTo(\'post\')') - .to.contain('author: DS.belongsTo(\'user\')') + .to.contain('author: DS.belongsTo(\'user\')'); expect(_file('tests/unit/models/comment-test.js')) - .to.contain('moduleForModel(\'comment\'') - .to.contain('needs: [\'model:post\', \'model:user\']'); + .to.equal(fixture('model-test/comment-default.js')); })); }); it('model with hasMany', function() { - var args = ['model', 'post', 'comments:has-many', 'otherComments:has-many:comment']; + let args = ['model', 'post', 'comments:has-many', 'otherComments:has-many:comment']; return emberNew() .then(() => emberGenerateDestroy(args, _file => { @@ -85,26 +88,25 @@ describe('Acceptance: generate and destroy model blueprints', function() { .to.contain('import DS from \'ember-data\';') .to.contain('export default DS.Model.extend(') .to.contain('comments: DS.hasMany(\'comment\')') - .to.contain('otherComments: DS.hasMany(\'comment\')') + .to.contain('otherComments: DS.hasMany(\'comment\')'); expect(_file('tests/unit/models/post-test.js')) - .to.contain('moduleForModel(\'post\'') - .to.contain('needs: [\'model:comment\']'); + .to.equal(fixture('model-test/post-default.js')); })); }); it('model-test', function() { - var args = ['model-test', 'foo']; + let args = ['model-test', 'foo']; return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/unit/models/foo-test.js')) - .to.contain('moduleForModel(\'foo\''); + .to.equal(fixture('model-test/foo-default.js')); })); }); it('model-test for mocha v0.12+', function() { - var args = ['model-test', 'foo']; + let args = ['model-test', 'foo']; return emberNew() .then(() => modifyPackages([ @@ -114,11 +116,7 @@ describe('Acceptance: generate and destroy model blueprints', function() { .then(() => generateFakePackageManifest('ember-cli-mocha', '0.12.0')) .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/unit/models/foo-test.js')) - .to.contain('import { describe, it } from \'mocha\';') - .to.contain('import { setupModelTest } from \'ember-mocha\';') - .to.contain('describe(\'Unit | Model | foo\', function() {') - .to.contain('setupModelTest(\'foo\',') - .to.contain('expect(model).to.be.ok;'); + .to.equal(fixture('model-test/foo-mocha-0.12.js')); })); }); }); diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index 5a8b1dff8e4..b12dc12a174 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -1,22 +1,25 @@ -var blueprintHelpers = require('ember-cli-blueprint-test-helpers/helpers'); -var setupTestHooks = blueprintHelpers.setupTestHooks; -var emberNew = blueprintHelpers.emberNew; -var emberGenerate = blueprintHelpers.emberGenerate; -var emberGenerateDestroy = blueprintHelpers.emberGenerateDestroy; -var modifyPackages = blueprintHelpers.modifyPackages; +'use strict'; -var chai = require('ember-cli-blueprint-test-helpers/chai'); -var expect = chai.expect; +const blueprintHelpers = require('ember-cli-blueprint-test-helpers/helpers'); +const setupTestHooks = blueprintHelpers.setupTestHooks; +const emberNew = blueprintHelpers.emberNew; +const emberGenerate = blueprintHelpers.emberGenerate; +const emberGenerateDestroy = blueprintHelpers.emberGenerateDestroy; +const modifyPackages = blueprintHelpers.modifyPackages; -var SilentError = require('silent-error'); +const chai = require('ember-cli-blueprint-test-helpers/chai'); +const expect = chai.expect; -var generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); +const SilentError = require('silent-error'); + +const generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); +const fixture = require('../helpers/fixture'); describe('Acceptance: generate and destroy serializer blueprints', function() { setupTestHooks(this); it('serializer', function() { - var args = ['serializer', 'foo']; + let args = ['serializer', 'foo']; return emberNew() .then(() => emberGenerateDestroy(args, _file => { @@ -25,12 +28,12 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { .to.contain('export default DS.JSONAPISerializer.extend('); expect(_file('tests/unit/serializers/foo-test.js')) - .to.contain('moduleForModel(\'foo\''); + .to.equal(fixture('serializer-test/foo-default.js')); })); }); it('serializer extends application serializer if it exists', function() { - var args = ['serializer', 'foo']; + let args = ['serializer', 'foo']; return emberNew() .then(() => emberGenerate(['serializer', 'application'])) @@ -40,12 +43,12 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { .to.contain('export default ApplicationSerializer.extend({'); expect(_file('tests/unit/serializers/foo-test.js')) - .to.contain('moduleForModel(\'foo\''); + .to.equal(fixture('serializer-test/foo-default.js')); })); }); it('serializer with --base-class', function() { - var args = ['serializer', 'foo', '--base-class=bar']; + let args = ['serializer', 'foo', '--base-class=bar']; return emberNew() .then(() => emberGenerateDestroy(args, _file => { @@ -54,12 +57,12 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { .to.contain('export default BarSerializer.extend({'); expect(_file('tests/unit/serializers/foo-test.js')) - .to.contain('moduleForModel(\'foo\''); + .to.equal(fixture('serializer-test/foo-default.js')); })); }); xit('serializer throws when --base-class is same as name', function() { - var args = ['serializer', 'foo', '--base-class=foo']; + let args = ['serializer', 'foo', '--base-class=foo']; return emberNew() .then(() => expect(emberGenerate(args)) @@ -67,7 +70,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { }); it('serializer when is named "application"', function() { - var args = ['serializer', 'application']; + let args = ['serializer', 'application']; return emberNew() .then(() => emberGenerateDestroy(args, _file => { @@ -76,22 +79,22 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { .to.contain('export default DS.JSONAPISerializer.extend({'); expect(_file('tests/unit/serializers/application-test.js')) - .to.contain('moduleForModel(\'application\''); + .to.equal(fixture('serializer-test/application-default.js')); })); }); it('serializer-test', function() { - var args = ['serializer-test', 'foo']; + let args = ['serializer-test', 'foo']; return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/unit/serializers/foo-test.js')) - .to.contain('moduleForModel(\'foo\''); + .to.equal(fixture('serializer-test/foo-default.js')); })); }); it('serializer-test for mocha v0.12+', function() { - var args = ['serializer-test', 'foo']; + let args = ['serializer-test', 'foo']; return emberNew() .then(() => modifyPackages([ @@ -101,12 +104,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { .then(() => generateFakePackageManifest('ember-cli-mocha', '0.12.0')) .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/unit/serializers/foo-test.js')) - .to.contain('import { describe, it } from \'mocha\';') - .to.contain('import { setupModelTest } from \'ember-mocha\';') - .to.contain('describe(\'Unit | Serializer | foo\', function() {') - .to.contain('setupModelTest(\'foo\', {') - .to.contain('needs: [\'serializer:foo\']') - .to.contain('expect(serializedRecord).to.be.ok;'); + .to.equal(fixture('serializer-test/foo-mocha-0.12.js')); })); }); }); diff --git a/node-tests/blueprints/transform-test.js b/node-tests/blueprints/transform-test.js index bd9a96be7aa..63783dce24a 100644 --- a/node-tests/blueprints/transform-test.js +++ b/node-tests/blueprints/transform-test.js @@ -1,19 +1,22 @@ -var blueprintHelpers = require('ember-cli-blueprint-test-helpers/helpers'); -var setupTestHooks = blueprintHelpers.setupTestHooks; -var emberNew = blueprintHelpers.emberNew; -var emberGenerateDestroy = blueprintHelpers.emberGenerateDestroy; -var modifyPackages = blueprintHelpers.modifyPackages; +'use strict'; -var chai = require('ember-cli-blueprint-test-helpers/chai'); -var expect = chai.expect; +const blueprintHelpers = require('ember-cli-blueprint-test-helpers/helpers'); +const setupTestHooks = blueprintHelpers.setupTestHooks; +const emberNew = blueprintHelpers.emberNew; +const emberGenerateDestroy = blueprintHelpers.emberGenerateDestroy; +const modifyPackages = blueprintHelpers.modifyPackages; -var generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); +const chai = require('ember-cli-blueprint-test-helpers/chai'); +const expect = chai.expect; + +const generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); +const fixture = require('../helpers/fixture'); describe('Acceptance: generate and destroy transform blueprints', function() { setupTestHooks(this); it('transform', function() { - var args = ['transform', 'foo']; + let args = ['transform', 'foo']; return emberNew() .then(() => emberGenerateDestroy(args, _file => { @@ -24,22 +27,22 @@ describe('Acceptance: generate and destroy transform blueprints', function() { .to.contain('serialize(deserialized) {'); expect(_file('tests/unit/transforms/foo-test.js')) - .to.contain('moduleFor(\'transform:foo\''); + .to.equal(fixture('transform-test/default.js')); })); }); it('transforms-test', function() { - var args = ['transform-test', 'foo']; + let args = ['transform-test', 'foo']; return emberNew() .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/unit/transforms/foo-test.js')) - .to.contain('moduleFor(\'transform:foo\''); + .to.equal(fixture('transform-test/default.js')); })); }); it('transform-test for mocha v0.12+', function() { - var args = ['transform-test', 'foo']; + let args = ['transform-test', 'foo']; return emberNew() .then(() => modifyPackages([ @@ -49,11 +52,7 @@ describe('Acceptance: generate and destroy transform blueprints', function() { .then(() => generateFakePackageManifest('ember-cli-mocha', '0.12.0')) .then(() => emberGenerateDestroy(args, _file => { expect(_file('tests/unit/transforms/foo-test.js')) - .to.contain('import { describe, it } from \'mocha\';') - .to.contain('import { setupTest } from \'ember-mocha\';') - .to.contain('describe(\'Unit | Transform | foo\', function() {') - .to.contain('setupTest(\'transform:foo\',') - .to.contain('expect(transform).to.be.ok;'); + .to.equal(fixture('transform-test/mocha-0.12.js')); })); }); }); diff --git a/node-tests/fixtures/adapter-test/application-default.js b/node-tests/fixtures/adapter-test/application-default.js new file mode 100644 index 00000000000..f0a2101e7a8 --- /dev/null +++ b/node-tests/fixtures/adapter-test/application-default.js @@ -0,0 +1,12 @@ +import { moduleFor, test } from 'ember-qunit'; + +moduleFor('adapter:application', 'Unit | Adapter | application', { + // Specify the other units that are required for this test. + // needs: ['serializer:foo'] +}); + +// Replace this with your real tests. +test('it exists', function(assert) { + let adapter = this.subject(); + assert.ok(adapter); +}); diff --git a/node-tests/fixtures/adapter-test/foo-default.js b/node-tests/fixtures/adapter-test/foo-default.js new file mode 100644 index 00000000000..4ea377cecf3 --- /dev/null +++ b/node-tests/fixtures/adapter-test/foo-default.js @@ -0,0 +1,12 @@ +import { moduleFor, test } from 'ember-qunit'; + +moduleFor('adapter:foo', 'Unit | Adapter | foo', { + // Specify the other units that are required for this test. + // needs: ['serializer:foo'] +}); + +// Replace this with your real tests. +test('it exists', function(assert) { + let adapter = this.subject(); + assert.ok(adapter); +}); diff --git a/node-tests/fixtures/adapter-test/foo-mocha-0.12.js b/node-tests/fixtures/adapter-test/foo-mocha-0.12.js new file mode 100644 index 00000000000..cd217b034b9 --- /dev/null +++ b/node-tests/fixtures/adapter-test/foo-mocha-0.12.js @@ -0,0 +1,16 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupTest } from 'ember-mocha'; + +describe('Unit | Adapter | foo', function() { + setupTest('adapter:foo', { + // Specify the other units that are required for this test. + // needs: ['serializer:foo'] + }); + + // Replace this with your real tests. + it('exists', function() { + let adapter = this.subject(); + expect(adapter).to.be.ok; + }); +}); diff --git a/node-tests/fixtures/model-test/comment-default.js b/node-tests/fixtures/model-test/comment-default.js new file mode 100644 index 00000000000..5a1628a037f --- /dev/null +++ b/node-tests/fixtures/model-test/comment-default.js @@ -0,0 +1,12 @@ +import { moduleForModel, test } from 'ember-qunit'; + +moduleForModel('comment', 'Unit | Model | comment', { + // Specify the other units that are required for this test. + needs: ['model:post', 'model:user'] +}); + +test('it exists', function(assert) { + let model = this.subject(); + // let store = this.store(); + assert.ok(!!model); +}); diff --git a/node-tests/fixtures/model-test/foo-default.js b/node-tests/fixtures/model-test/foo-default.js new file mode 100644 index 00000000000..b75921b883c --- /dev/null +++ b/node-tests/fixtures/model-test/foo-default.js @@ -0,0 +1,12 @@ +import { moduleForModel, test } from 'ember-qunit'; + +moduleForModel('foo', 'Unit | Model | foo', { + // Specify the other units that are required for this test. + needs: [] +}); + +test('it exists', function(assert) { + let model = this.subject(); + // let store = this.store(); + assert.ok(!!model); +}); diff --git a/node-tests/fixtures/model-test/foo-mocha-0.12.js b/node-tests/fixtures/model-test/foo-mocha-0.12.js new file mode 100644 index 00000000000..b324f1c308a --- /dev/null +++ b/node-tests/fixtures/model-test/foo-mocha-0.12.js @@ -0,0 +1,17 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupModelTest } from 'ember-mocha'; + +describe('Unit | Model | foo', function() { + setupModelTest('foo', { + // Specify the other units that are required for this test. + needs: [] + }); + + // Replace this with your real tests. + it('exists', function() { + let model = this.subject(); + // var store = this.store(); + expect(model).to.be.ok; + }); +}); diff --git a/node-tests/fixtures/model-test/post-default.js b/node-tests/fixtures/model-test/post-default.js new file mode 100644 index 00000000000..71c81011693 --- /dev/null +++ b/node-tests/fixtures/model-test/post-default.js @@ -0,0 +1,12 @@ +import { moduleForModel, test } from 'ember-qunit'; + +moduleForModel('post', 'Unit | Model | post', { + // Specify the other units that are required for this test. + needs: ['model:comment'] +}); + +test('it exists', function(assert) { + let model = this.subject(); + // let store = this.store(); + assert.ok(!!model); +}); diff --git a/node-tests/fixtures/serializer-test/application-default.js b/node-tests/fixtures/serializer-test/application-default.js new file mode 100644 index 00000000000..705e9ecedcb --- /dev/null +++ b/node-tests/fixtures/serializer-test/application-default.js @@ -0,0 +1,15 @@ +import { moduleForModel, test } from 'ember-qunit'; + +moduleForModel('application', 'Unit | Serializer | application', { + // Specify the other units that are required for this test. + needs: ['serializer:application'] +}); + +// Replace this with your real tests. +test('it serializes records', function(assert) { + let record = this.subject(); + + let serializedRecord = record.serialize(); + + assert.ok(serializedRecord); +}); diff --git a/node-tests/fixtures/serializer-test/foo-default.js b/node-tests/fixtures/serializer-test/foo-default.js new file mode 100644 index 00000000000..48c11de4a78 --- /dev/null +++ b/node-tests/fixtures/serializer-test/foo-default.js @@ -0,0 +1,15 @@ +import { moduleForModel, test } from 'ember-qunit'; + +moduleForModel('foo', 'Unit | Serializer | foo', { + // Specify the other units that are required for this test. + needs: ['serializer:foo'] +}); + +// Replace this with your real tests. +test('it serializes records', function(assert) { + let record = this.subject(); + + let serializedRecord = record.serialize(); + + assert.ok(serializedRecord); +}); diff --git a/node-tests/fixtures/serializer-test/foo-mocha-0.12.js b/node-tests/fixtures/serializer-test/foo-mocha-0.12.js new file mode 100644 index 00000000000..fbdc7dbe528 --- /dev/null +++ b/node-tests/fixtures/serializer-test/foo-mocha-0.12.js @@ -0,0 +1,19 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupModelTest } from 'ember-mocha'; + +describe('Unit | Serializer | foo', function() { + setupModelTest('foo', { + // Specify the other units that are required for this test. + needs: ['serializer:foo'] + }); + + // Replace this with your real tests. + it('serializes records', function() { + let record = this.subject(); + + let serializedRecord = record.serialize(); + + expect(serializedRecord).to.be.ok; + }); +}); diff --git a/node-tests/fixtures/transform-test/default.js b/node-tests/fixtures/transform-test/default.js new file mode 100644 index 00000000000..4e9dbc2b3e1 --- /dev/null +++ b/node-tests/fixtures/transform-test/default.js @@ -0,0 +1,12 @@ +import { moduleFor, test } from 'ember-qunit'; + +moduleFor('transform:foo', 'Unit | Transform | foo', { + // Specify the other units that are required for this test. + // needs: ['serializer:foo'] +}); + +// Replace this with your real tests. +test('it exists', function(assert) { + let transform = this.subject(); + assert.ok(transform); +}); diff --git a/node-tests/fixtures/transform-test/mocha-0.12.js b/node-tests/fixtures/transform-test/mocha-0.12.js new file mode 100644 index 00000000000..32c3b94a5c9 --- /dev/null +++ b/node-tests/fixtures/transform-test/mocha-0.12.js @@ -0,0 +1,16 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupTest } from 'ember-mocha'; + +describe('Unit | Transform | foo', function() { + setupTest('transform:foo', { + // Specify the other units that are required for this test. + // needs: ['transform:foo'] + }); + + // Replace this with your real tests. + it('exists', function() { + let transform = this.subject(); + expect(transform).to.be.ok; + }); +}); diff --git a/node-tests/helpers/fixture.js b/node-tests/helpers/fixture.js new file mode 100644 index 00000000000..089a8c4a527 --- /dev/null +++ b/node-tests/helpers/fixture.js @@ -0,0 +1,8 @@ +'use strict'; + +const path = require('path'); +const file = require('ember-cli-blueprint-test-helpers/chai').file; + +module.exports = function(filePath) { + return file(path.join(__dirname, '../fixtures', filePath)); +}; From 763c5daa2db7f8405aeaf4e9dc0d76e91fa7b3a7 Mon Sep 17 00:00:00 2001 From: Alex Alvarez Date: Mon, 18 Dec 2017 22:57:40 -0500 Subject: [PATCH 2083/2527] blueprints/transform-test: Add RFC232 variants --- blueprints/test-framework-detector.js | 25 +++++-- .../tests/unit/__path__/__test__.js | 12 ++++ node-tests/blueprints/transform-test.js | 71 ++++++++++++------- node-tests/fixtures/transform-test/rfc232.js | 12 ++++ 4 files changed, 90 insertions(+), 30 deletions(-) create mode 100644 blueprints/transform-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js create mode 100644 node-tests/fixtures/transform-test/rfc232.js diff --git a/blueprints/test-framework-detector.js b/blueprints/test-framework-detector.js index d3b3e77c392..6b7ef9d3a01 100644 --- a/blueprints/test-framework-detector.js +++ b/blueprints/test-framework-detector.js @@ -1,5 +1,8 @@ -var fs = require('fs'); -var path = require('path'); +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const VersionChecker = require('ember-cli-version-checker'); module.exports = function(blueprint) { blueprint.supportsAddon = function() { @@ -7,13 +10,23 @@ module.exports = function(blueprint) { }; blueprint.filesPath = function() { - var type; + let type; + + let dependencies = this.project.dependencies(); + if ('ember-qunit' in dependencies) { + type = 'qunit-rfc-232'; + + } else if ('ember-cli-qunit' in dependencies) { + let checker = new VersionChecker(this.project); + if (fs.existsSync(this.path + '/qunit-rfc-232-files') && checker.for('ember-cli-qunit', 'npm').gte('4.2.0')) { + type = 'qunit-rfc-232'; + } else { + type = 'qunit'; + } - var dependencies = this.project.dependencies(); - if ('ember-cli-qunit' in dependencies) { - type = 'qunit'; } else if ('ember-cli-mocha' in dependencies) { type = 'mocha'; + } else { this.ui.writeLine('Couldn\'t determine test style - using QUnit'); type = 'qunit'; diff --git a/blueprints/transform-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js b/blueprints/transform-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..e4f745717d3 --- /dev/null +++ b/blueprints/transform-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('transform:<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let transform = this.owner.lookup('transform:<%= dasherizedModuleName %>'); + assert.ok(transform); + }); +}); diff --git a/node-tests/blueprints/transform-test.js b/node-tests/blueprints/transform-test.js index 63783dce24a..525c34c4604 100644 --- a/node-tests/blueprints/transform-test.js +++ b/node-tests/blueprints/transform-test.js @@ -15,11 +15,16 @@ const fixture = require('../helpers/fixture'); describe('Acceptance: generate and destroy transform blueprints', function() { setupTestHooks(this); - it('transform', function() { - let args = ['transform', 'foo']; + describe('in app', function() { + beforeEach(function() { + return emberNew(); + }); - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + + it('transform', function() { + let args = ['transform', 'foo']; + + return emberGenerateDestroy(args, _file => { expect(_file('app/transforms/foo.js')) .to.contain('import DS from \'ember-data\';') .to.contain('export default DS.Transform.extend(') @@ -28,31 +33,49 @@ describe('Acceptance: generate and destroy transform blueprints', function() { expect(_file('tests/unit/transforms/foo-test.js')) .to.equal(fixture('transform-test/default.js')); - })); - }); + }); + }); - it('transforms-test', function() { - let args = ['transform-test', 'foo']; + it('transform-test', function() { + let args = ['transform-test', 'foo']; - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('tests/unit/transforms/foo-test.js')) .to.equal(fixture('transform-test/default.js')); - })); - }); + }); + }); - it('transform-test for mocha v0.12+', function() { - let args = ['transform-test', 'foo']; + describe('transform-test with ember-cli-qunit@4.2.0', function() { + beforeEach(function() { + generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + }); - return emberNew() - .then(() => modifyPackages([ - {name: 'ember-cli-qunit', delete: true}, - {name: 'ember-cli-mocha', dev: true} - ])) - .then(() => generateFakePackageManifest('ember-cli-mocha', '0.12.0')) - .then(() => emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/transforms/foo-test.js')) - .to.equal(fixture('transform-test/mocha-0.12.js')); - })); + it('transform-test-test foo', function() { + return emberGenerateDestroy(['transform-test', 'foo'], _file => { + expect(_file('tests/unit/transforms/foo-test.js')) + .to.equal(fixture('transform-test/rfc232.js')); + }); + }); + }); + + + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true } + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('transform-test for mocha v0.12+', function() { + let args = ['transform-test', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/transforms/foo-test.js')) + .to.equal(fixture('transform-test/mocha-0.12.js')); + }); + }); + }); }); }); diff --git a/node-tests/fixtures/transform-test/rfc232.js b/node-tests/fixtures/transform-test/rfc232.js new file mode 100644 index 00000000000..23d10b815cd --- /dev/null +++ b/node-tests/fixtures/transform-test/rfc232.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('transform:foo', 'Unit | Transform | foo', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let transform = this.owner.lookup('transform:foo'); + assert.ok(transform); + }); +}); From 9b95e1b16f928c064d13af7eeda02931e668cdb0 Mon Sep 17 00:00:00 2001 From: Alex Alvarez Date: Wed, 20 Dec 2017 23:56:55 -0500 Subject: [PATCH 2084/2527] blueprints/adapter-test: Add RFC232 variants --- .../tests/unit/__path__/__test__.js | 12 +++ node-tests/blueprints/adapter-test.js | 74 ++++++++++++------- node-tests/fixtures/adapter-test/rfc232.js | 12 +++ 3 files changed, 70 insertions(+), 28 deletions(-) create mode 100644 blueprints/adapter-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js create mode 100644 node-tests/fixtures/adapter-test/rfc232.js diff --git a/blueprints/adapter-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js b/blueprints/adapter-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..320be4804a3 --- /dev/null +++ b/blueprints/adapter-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('adapter:<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let adapter = this.owner.lookup('adapter:<%= dasherizedModuleName %>'); + assert.ok(adapter); + }); +}); diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 3b6f0f98ad1..a4e244cd00b 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -18,25 +18,28 @@ const fixture = require('../helpers/fixture'); describe('Acceptance: generate and destroy adapter blueprints', function() { setupTestHooks(this); + beforeEach(function() { + return emberNew(); + }); + + it('adapter', function() { let args = ['adapter', 'foo']; - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('app/adapters/foo.js')) .to.contain('import DS from \'ember-data\';') .to.contain('export default DS.JSONAPIAdapter.extend({'); expect(_file('tests/unit/adapters/foo-test.js')) .to.equal(fixture('adapter-test/foo-default.js')); - })); + }); }); it('adapter extends application adapter if it exists', function() { let args = ['adapter', 'foo']; - return emberNew() - .then(() => emberGenerate(['adapter', 'application'])) + return emberGenerate(['adapter', 'application']) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/adapters/foo.js')) .to.contain('import ApplicationAdapter from \'./application\';') @@ -50,61 +53,76 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { it('adapter with --base-class', function() { let args = ['adapter', 'foo', '--base-class=bar']; - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('app/adapters/foo.js')) .to.contain('import BarAdapter from \'./bar\';') .to.contain('export default BarAdapter.extend({'); expect(_file('tests/unit/adapters/foo-test.js')) .to.equal(fixture('adapter-test/foo-default.js')); - })); + }); }); xit('adapter throws when --base-class is same as name', function() { let args = ['adapter', 'foo', '--base-class=foo']; - return emberNew() - .then(() => expect(emberGenerate(args)) - .to.be.rejectedWith(SilentError, /Adapters cannot extend from themself/)); + return expect(emberGenerate(args)) + .to.be.rejectedWith(SilentError, /Adapters cannot extend from themself/); }); it('adapter when is named "application"', function() { let args = ['adapter', 'application']; - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('app/adapters/application.js')) .to.contain('import DS from \'ember-data\';') .to.contain('export default DS.JSONAPIAdapter.extend({'); expect(_file('tests/unit/adapters/application-test.js')) .to.equal(fixture('adapter-test/application-default.js')); - })); + }); }); it('adapter-test', function() { let args = ['adapter-test', 'foo']; - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('tests/unit/adapters/foo-test.js')) .to.equal(fixture('adapter-test/foo-default.js')); - })); + }); }); - it('adapter-test for mocha v0.12+', function() { - let args = ['adapter-test', 'foo']; + describe('adapter-test with ember-cli-qunit@4.2.0', function() { + beforeEach(function() { + generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + }); - return emberNew() - .then(() => modifyPackages([ - {name: 'ember-cli-qunit', delete: true}, - {name: 'ember-cli-mocha', dev: true} - ])) - .then(() => generateFakePackageManifest('ember-cli-mocha', '0.12.0')) - .then(() => emberGenerateDestroy(args, _file => { + it('adapter-test-test foo', function() { + return emberGenerateDestroy(['adapter-test', 'foo'], _file => { expect(_file('tests/unit/adapters/foo-test.js')) - .to.equal(fixture('adapter-test/foo-mocha-0.12.js')); - })); + .to.equal(fixture('adapter-test/rfc232.js')); + }); + }); + }); + + + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true } + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('adapter-test for mocha v0.12+', function() { + let args = ['adapter-test', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/adapters/foo-test.js')) + .to.equal(fixture('adapter-test/foo-mocha-0.12.js')); + }); + }); }); + }); diff --git a/node-tests/fixtures/adapter-test/rfc232.js b/node-tests/fixtures/adapter-test/rfc232.js new file mode 100644 index 00000000000..9175c281b2f --- /dev/null +++ b/node-tests/fixtures/adapter-test/rfc232.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('adapter:foo', 'Unit | Adapter | foo', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let adapter = this.owner.lookup('adapter:foo'); + assert.ok(adapter); + }); +}); From ffeb8c099cc3b7f022850c68ad6a7e12e20b9491 Mon Sep 17 00:00:00 2001 From: Alex Alvarez Date: Thu, 21 Dec 2017 00:21:33 -0500 Subject: [PATCH 2085/2527] blueprints/serializer-test: Add RFC232 variants --- .../tests/unit/__path__/__test__.js | 24 ++++++ node-tests/blueprints/serializer-test.js | 73 ++++++++++++------- node-tests/fixtures/serializer-test/rfc232.js | 24 ++++++ 3 files changed, 93 insertions(+), 28 deletions(-) create mode 100644 blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js create mode 100644 node-tests/fixtures/serializer-test/rfc232.js diff --git a/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..5a0396de287 --- /dev/null +++ b/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js @@ -0,0 +1,24 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { run } from '@ember/runloop'; + +module('serializer:<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let serializer = this.owner.factoryFor('serializer:<%= dasherizedModuleName %>').create({ store }); + + assert.ok(serializer); + }); + + test('it serializes records', function(assert) { + let store = this.owner.lookup('service:store'); + let record = run(() => store.createRecord('<%= dasherizedModuleName %>', {})); + + let serializedRecord = record.serialize(); + + assert.ok(serializedRecord); + }); +}); diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index b12dc12a174..76ccf58623c 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -18,25 +18,28 @@ const fixture = require('../helpers/fixture'); describe('Acceptance: generate and destroy serializer blueprints', function() { setupTestHooks(this); + + beforeEach(function() { + return emberNew(); + }); + it('serializer', function() { let args = ['serializer', 'foo']; - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('app/serializers/foo.js')) .to.contain('import DS from \'ember-data\';') .to.contain('export default DS.JSONAPISerializer.extend('); expect(_file('tests/unit/serializers/foo-test.js')) .to.equal(fixture('serializer-test/foo-default.js')); - })); + }); }); it('serializer extends application serializer if it exists', function() { let args = ['serializer', 'foo']; - return emberNew() - .then(() => emberGenerate(['serializer', 'application'])) + return emberGenerate(['serializer', 'application']) .then(() => emberGenerateDestroy(args, _file => { expect(_file('app/serializers/foo.js')) .to.contain('import ApplicationSerializer from \'./application\';') @@ -50,61 +53,75 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { it('serializer with --base-class', function() { let args = ['serializer', 'foo', '--base-class=bar']; - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('app/serializers/foo.js')) .to.contain('import BarSerializer from \'./bar\';') .to.contain('export default BarSerializer.extend({'); expect(_file('tests/unit/serializers/foo-test.js')) .to.equal(fixture('serializer-test/foo-default.js')); - })); + }); }); xit('serializer throws when --base-class is same as name', function() { let args = ['serializer', 'foo', '--base-class=foo']; - return emberNew() - .then(() => expect(emberGenerate(args)) - .to.be.rejectedWith(SilentError, /Serializers cannot extend from themself/)); + return expect(emberGenerate(args)) + .to.be.rejectedWith(SilentError, /Serializers cannot extend from themself/); }); it('serializer when is named "application"', function() { let args = ['serializer', 'application']; - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('app/serializers/application.js')) .to.contain('import DS from \'ember-data\';') .to.contain('export default DS.JSONAPISerializer.extend({'); expect(_file('tests/unit/serializers/application-test.js')) .to.equal(fixture('serializer-test/application-default.js')); - })); + }); }); it('serializer-test', function() { let args = ['serializer-test', 'foo']; - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('tests/unit/serializers/foo-test.js')) .to.equal(fixture('serializer-test/foo-default.js')); - })); + }); }); - it('serializer-test for mocha v0.12+', function() { - let args = ['serializer-test', 'foo']; + describe('serializer-test with ember-cli-qunit@4.2.0', function() { + beforeEach(function() { + generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + }); - return emberNew() - .then(() => modifyPackages([ - {name: 'ember-cli-qunit', delete: true}, - {name: 'ember-cli-mocha', dev: true} - ])) - .then(() => generateFakePackageManifest('ember-cli-mocha', '0.12.0')) - .then(() => emberGenerateDestroy(args, _file => { + it('serializer-test-test foo', function() { + return emberGenerateDestroy(['serializer-test', 'foo'], _file => { expect(_file('tests/unit/serializers/foo-test.js')) - .to.equal(fixture('serializer-test/foo-mocha-0.12.js')); - })); + .to.equal(fixture('serializer-test/rfc232.js')); + }); + }); + }); + + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true } + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('serializer-test for mocha v0.12+', function() { + let args = ['serializer-test', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/serializers/foo-test.js')) + .to.equal(fixture('serializer-test/foo-mocha-0.12.js')); + }); + }); }); + }); diff --git a/node-tests/fixtures/serializer-test/rfc232.js b/node-tests/fixtures/serializer-test/rfc232.js new file mode 100644 index 00000000000..80bee0a011d --- /dev/null +++ b/node-tests/fixtures/serializer-test/rfc232.js @@ -0,0 +1,24 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { run } from '@ember/runloop'; + +module('serializer:foo', 'Unit | Serializer | foo', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let serializer = this.owner.factoryFor('serializer:foo').create({ store }); + + assert.ok(serializer); + }); + + test('it serializes records', function(assert) { + let store = this.owner.lookup('service:store'); + let record = run(() => store.createRecord('foo', {})); + + let serializedRecord = record.serialize(); + + assert.ok(serializedRecord); + }); +}); From 980158aa3f3b5b7052c0406625271ab7b7afcced Mon Sep 17 00:00:00 2001 From: Alex Alvarez Date: Thu, 21 Dec 2017 00:10:12 -0500 Subject: [PATCH 2086/2527] blueprints/model-test: Add RFC232 variants --- blueprints/model-test/index.js | 2 +- .../tests/unit/__path__/__test__.js | 2 +- .../tests/unit/__path__/__test__.js | 2 +- .../tests/unit/__path__/__test__.js | 14 ++++ node-tests/blueprints/model-test.js | 68 ++++++++++++------- node-tests/fixtures/model-test/rfc232.js | 14 ++++ 6 files changed, 74 insertions(+), 28 deletions(-) create mode 100644 blueprints/model-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js create mode 100644 node-tests/fixtures/model-test/rfc232.js diff --git a/blueprints/model-test/index.js b/blueprints/model-test/index.js index 5dc0767032a..d4406a1c08f 100644 --- a/blueprints/model-test/index.js +++ b/blueprints/model-test/index.js @@ -10,7 +10,7 @@ module.exports = useTestFrameworkDetector({ locals: function(options) { var result = ModelBlueprint.locals.apply(this, arguments); - result.friendlyDescription = testInfo.description(options.entity.name, "Unit", "Model"); + result.friendlyTestDescription = testInfo.description(options.entity.name, "Unit", "Model"); return result; } diff --git a/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js index bf871e251a2..b1635f9b803 100644 --- a/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js +++ b/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; import { setupModelTest } from 'ember-mocha'; -describe('<%= friendlyDescription %>', function() { +describe('<%= friendlyTestDescription %>', function() { setupModelTest('<%= dasherizedModuleName %>', { // Specify the other units that are required for this test. <%= typeof needs !== 'undefined' ? needs : '' %> diff --git a/blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js b/blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js index 8f26bfd1b67..d7d880b44a6 100644 --- a/blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js +++ b/blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js @@ -1,6 +1,6 @@ import { moduleForModel, test } from 'ember-qunit'; -moduleForModel('<%= dasherizedModuleName %>', '<%= friendlyDescription %>', { +moduleForModel('<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', { // Specify the other units that are required for this test. <%= typeof needs !== 'undefined' ? needs : '' %> }); diff --git a/blueprints/model-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js b/blueprints/model-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js new file mode 100644 index 00000000000..ea8cc022396 --- /dev/null +++ b/blueprints/model-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js @@ -0,0 +1,14 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { run } from '@ember/runloop'; + +module('model:<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let model = run(() => store.createRecord('<%= dasherizedModuleName %>', {})); + assert.ok(model); + }); +}); diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index e96a0016a4e..53ddf1352ab 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -16,18 +16,22 @@ const fixture = require('../helpers/fixture'); describe('Acceptance: generate and destroy model blueprints', function() { setupTestHooks(this); + beforeEach(function() { + return emberNew(); + }); + + it('model', function() { let args = ['model', 'foo']; - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('app/models/foo.js')) .to.contain('import DS from \'ember-data\';') .to.contain('export default DS.Model.extend('); expect(_file('tests/unit/models/foo-test.js')) .to.equal(fixture('model-test/foo-default.js')); - })); + }); }); it('model with attrs', function() { @@ -44,8 +48,7 @@ describe('Acceptance: generate and destroy model blueprints', function() { 'customAttr:custom-transform' ]; - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('app/models/foo.js')) .to.contain('import DS from \'ember-data\';') .to.contain('export default DS.Model.extend(') @@ -60,14 +63,13 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('tests/unit/models/foo-test.js')) .to.equal(fixture('model-test/foo-default.js')); - })); + }); }); it('model with belongsTo', function() { let args = ['model', 'comment', 'post:belongs-to', 'author:belongs-to:user']; - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('app/models/comment.js')) .to.contain('import DS from \'ember-data\';') .to.contain('export default DS.Model.extend(') @@ -76,14 +78,13 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('tests/unit/models/comment-test.js')) .to.equal(fixture('model-test/comment-default.js')); - })); + }); }); it('model with hasMany', function() { let args = ['model', 'post', 'comments:has-many', 'otherComments:has-many:comment']; - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('app/models/post.js')) .to.contain('import DS from \'ember-data\';') .to.contain('export default DS.Model.extend(') @@ -92,31 +93,48 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('tests/unit/models/post-test.js')) .to.equal(fixture('model-test/post-default.js')); - })); + }); }); it('model-test', function() { let args = ['model-test', 'foo']; - return emberNew() - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('tests/unit/models/foo-test.js')) .to.equal(fixture('model-test/foo-default.js')); - })); + }); }); - it('model-test for mocha v0.12+', function() { - let args = ['model-test', 'foo']; + describe('model-test with ember-cli-qunit@4.2.0', function() { + beforeEach(function() { + generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + }); + + it('model-test-test foo', function() { + return emberGenerateDestroy(['model-test', 'foo'], _file => { + expect(_file('tests/unit/models/foo-test.js')) + .to.equal(fixture('model-test/rfc232.js')); + }); + }); + }); + + + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true } + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('model-test for mocha v0.12+', function() { + let args = ['model-test', 'foo']; - return emberNew() - .then(() => modifyPackages([ - {name: 'ember-cli-qunit', delete: true}, - {name: 'ember-cli-mocha', dev: true} - ])) - .then(() => generateFakePackageManifest('ember-cli-mocha', '0.12.0')) - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('tests/unit/models/foo-test.js')) .to.equal(fixture('model-test/foo-mocha-0.12.js')); - })); + }); + }); }); }); diff --git a/node-tests/fixtures/model-test/rfc232.js b/node-tests/fixtures/model-test/rfc232.js new file mode 100644 index 00000000000..691699db857 --- /dev/null +++ b/node-tests/fixtures/model-test/rfc232.js @@ -0,0 +1,14 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { run } from '@ember/runloop'; + +module('model:foo', 'Unit | Model | foo', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let model = run(() => store.createRecord('foo', {})); + assert.ok(model); + }); +}); From 530ef1f31e58d9c4f789c6117bb8b462c547bf38 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 21 Dec 2017 13:26:52 -0500 Subject: [PATCH 2087/2527] Fixup the RFC232 model-test files. I missed this during review of 980158aa3f3b5b7052c0406625271ab7b7afcced. --- .../qunit-rfc-232-files/tests/unit/__path__/__test__.js | 2 +- node-tests/fixtures/model-test/rfc232.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/blueprints/model-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js b/blueprints/model-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js index ea8cc022396..84dbd712791 100644 --- a/blueprints/model-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js +++ b/blueprints/model-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js @@ -2,7 +2,7 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; import { run } from '@ember/runloop'; -module('model:<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', function(hooks) { +module('<%= friendlyTestDescription %>', function(hooks) { setupTest(hooks); // Replace this with your real tests. diff --git a/node-tests/fixtures/model-test/rfc232.js b/node-tests/fixtures/model-test/rfc232.js index 691699db857..4440fd8539c 100644 --- a/node-tests/fixtures/model-test/rfc232.js +++ b/node-tests/fixtures/model-test/rfc232.js @@ -2,7 +2,7 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; import { run } from '@ember/runloop'; -module('model:foo', 'Unit | Model | foo', function(hooks) { +module('Unit | Model | foo', function(hooks) { setupTest(hooks); // Replace this with your real tests. From 88a59de8b0e33cf0c5e6f42ab83e4dd774873c86 Mon Sep 17 00:00:00 2001 From: Alex Alvarez Date: Thu, 21 Dec 2017 14:33:25 -0500 Subject: [PATCH 2088/2527] Fixup module arguments --- .../qunit-rfc-232-files/tests/unit/__path__/__test__.js | 2 +- node-tests/fixtures/adapter-test/rfc232.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/blueprints/adapter-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js b/blueprints/adapter-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js index 320be4804a3..8fc52439de3 100644 --- a/blueprints/adapter-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js +++ b/blueprints/adapter-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js @@ -1,7 +1,7 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -module('adapter:<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', function(hooks) { +module('<%= friendlyTestDescription %>', function(hooks) { setupTest(hooks); // Replace this with your real tests. diff --git a/node-tests/fixtures/adapter-test/rfc232.js b/node-tests/fixtures/adapter-test/rfc232.js index 9175c281b2f..61b5526f49e 100644 --- a/node-tests/fixtures/adapter-test/rfc232.js +++ b/node-tests/fixtures/adapter-test/rfc232.js @@ -1,7 +1,7 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -module('adapter:foo', 'Unit | Adapter | foo', function(hooks) { +module('Unit | Adapter | foo', function(hooks) { setupTest(hooks); // Replace this with your real tests. From e5443410c3f4dea2019b2803bfbe429ab9034d30 Mon Sep 17 00:00:00 2001 From: Alex Alvarez Date: Thu, 21 Dec 2017 14:34:23 -0500 Subject: [PATCH 2089/2527] Fixup module arguments --- .../qunit-rfc-232-files/tests/unit/__path__/__test__.js | 2 +- node-tests/fixtures/serializer-test/rfc232.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js index 5a0396de287..3cbee777af0 100644 --- a/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js +++ b/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js @@ -2,7 +2,7 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; import { run } from '@ember/runloop'; -module('serializer:<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', function(hooks) { +module('<%= friendlyTestDescription %>', function(hooks) { setupTest(hooks); // Replace this with your real tests. diff --git a/node-tests/fixtures/serializer-test/rfc232.js b/node-tests/fixtures/serializer-test/rfc232.js index 80bee0a011d..3c914973c44 100644 --- a/node-tests/fixtures/serializer-test/rfc232.js +++ b/node-tests/fixtures/serializer-test/rfc232.js @@ -2,7 +2,7 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; import { run } from '@ember/runloop'; -module('serializer:foo', 'Unit | Serializer | foo', function(hooks) { +module('Unit | Serializer | foo', function(hooks) { setupTest(hooks); // Replace this with your real tests. From 02e3c9ee73e908fc489fab6fa56da52467d81271 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 22 Dec 2017 11:44:39 -0500 Subject: [PATCH 2090/2527] Simplify `store.adapterFor` and `store.serializerFor`. Use an inline series of lookups (instead of `ContainerInstanceCache`) --- addon/-private/system/store.js | 77 ++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index d26f2706876..3b24f44f7d2 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -235,6 +235,8 @@ Store = Service.extend({ this._pendingFetch = MapWithDefault.create({ defaultValue() { return []; } }); this._instanceCache = new ContainerInstanceCache(getOwner(this), this); + this._adapterCache = Object.create(null); + this._serializerCache = Object.create(null); }, /** @@ -2648,7 +2650,40 @@ Store = Service.extend({ assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); let normalizedModelName = normalizeModelName(modelName); - return this._instanceCache.get('adapter', normalizedModelName); + let { _adapterCache } = this; + let adapter = _adapterCache[normalizedModelName]; + if (adapter) { return adapter; } + + let owner = getOwner(this); + + adapter = owner.lookup(`adapter:${normalizedModelName}`); + if (adapter !== undefined) { + _adapterCache[normalizedModelName] = adapter; + return adapter; + } + + // no adapter found for the specific model, fallback and check for application adapter + adapter = owner.lookup('adapter:application'); + if (adapter !== undefined) { + _adapterCache[normalizedModelName] = adapter; + return adapter; + } + + // no model specific adapter or application adapter, check for an `adapter` + // property defined on the store + let adapterName = this.get('adapter'); + adapter = owner.lookup(`adapter:${adapterName}`); + if (adapter !== undefined) { + _adapterCache[normalizedModelName] = adapter; + return adapter; + } + + // final fallback, no model specific adapter, no application adapter, no + // `adapter` property on store: use json-api adapter + adapter = owner.lookup('adapter:-json-api'); + _adapterCache[normalizedModelName] = adapter; + + return adapter; }, // .............................. @@ -2682,7 +2717,41 @@ Store = Service.extend({ assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); let normalizedModelName = normalizeModelName(modelName); - return this._instanceCache.get('serializer', normalizedModelName); + let { _serializerCache } = this; + let serializer = _serializerCache[normalizedModelName]; + if (serializer) { return serializer; } + + let owner = getOwner(this); + + serializer = owner.lookup(`serializer:${normalizedModelName}`); + if (serializer !== undefined) { + _serializerCache[normalizedModelName] = serializer; + return serializer; + } + + // no serializer found for the specific model, fallback and check for application serializer + serializer = owner.lookup('serializer:application'); + if (serializer !== undefined) { + _serializerCache[normalizedModelName] = serializer; + return serializer; + } + + // no model specific serializer or application serializer, check for the `defaultSerializer` + // property defined on the adapter + let adapter = this.adapterFor(modelName); + let serializerName = get(adapter, 'defaultSerializer'); + serializer = owner.lookup(`serializer:${serializerName}`); + if (serializer !== undefined) { + _serializerCache[normalizedModelName] = serializer; + return serializer; + } + + // final fallback, no model specific serializer, no application serializer, no + // `serializer` property on store: use json-api serializer + serializer = owner.lookup('serializer:-default'); + _serializerCache[normalizedModelName] = serializer; + + return serializer; }, lookupAdapter(name) { @@ -2705,7 +2774,9 @@ Store = Service.extend({ this._super(...arguments); this._pushedInternalModels = null; this.recordArrayManager.destroy(); - this._instanceCache.destroy(); + + this._adapterCache = null; + this._serializerCache = null; this.unloadAll(); }, From 4c7147d6de5a71707a56b4b990c209596dbc8924 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 22 Dec 2017 11:46:22 -0500 Subject: [PATCH 2091/2527] Automatically inject the store into adapters and serializers. This was previously being done by ContainerInstanceCache (when it would look up an instance, it would always `set(instance, 'store', store)`), but the DI system can already do this for us automatically. This simplifies adapter / serializer testing quite a bit... --- addon/setup-container.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addon/setup-container.js b/addon/setup-container.js index 686d7b786db..082716c64f1 100644 --- a/addon/setup-container.js +++ b/addon/setup-container.js @@ -72,6 +72,8 @@ function initializeStoreInjections(registry) { // registry.injection for Ember < 2.1.0 // application.inject for Ember 2.1.0+ let inject = registry.inject || registry.injection; + inject.call(registry, 'adapter', 'store', 'service:store'); + inject.call(registry, 'serializer', 'store', 'service:store'); inject.call(registry, 'controller', 'store', 'service:store'); inject.call(registry, 'route', 'store', 'service:store'); inject.call(registry, 'data-adapter', 'store', 'service:store'); From fce9eedb8fc7da37c54bba141435505aaa8da96c Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 22 Dec 2017 11:47:40 -0500 Subject: [PATCH 2092/2527] Make `adapter` and `serializer` types singleton. There is no reason to have them be non-singleton since we were already caching in the `ContainerInstanceCache`... --- addon/setup-container.js | 6 ------ tests/helpers/store.js | 2 -- tests/integration/setup-container-test.js | 14 -------------- 3 files changed, 22 deletions(-) diff --git a/addon/setup-container.js b/addon/setup-container.js index 082716c64f1..0c5a16d25a0 100644 --- a/addon/setup-container.js +++ b/addon/setup-container.js @@ -31,12 +31,6 @@ function has(applicationOrRegistry, fullName) { @param {Ember.Registry} registry */ function initializeStore(registry) { - // registry.optionsForType for Ember < 2.1.0 - // application.registerOptionsForType for Ember 2.1.0+ - let registerOptionsForType = registry.registerOptionsForType || registry.optionsForType; - registerOptionsForType.call(registry, 'serializer', { singleton: false }); - registerOptionsForType.call(registry, 'adapter', { singleton: false }); - registry.register('serializer:-default', JSONSerializer); registry.register('serializer:-rest', RESTSerializer); registry.register('adapter:-rest', RESTAdapter); diff --git a/tests/helpers/store.js b/tests/helpers/store.js index 6803fd81b30..c3bc2b24812 100644 --- a/tests/helpers/store.js +++ b/tests/helpers/store.js @@ -46,8 +46,6 @@ export default function setupStore(options) { adapter: adapter })); - registry.optionsForType('serializer', { singleton: false }); - registry.optionsForType('adapter', { singleton: false }); registry.register('adapter:-default', DS.Adapter); registry.register('serializer:-default', DS.JSONAPISerializer); diff --git a/tests/integration/setup-container-test.js b/tests/integration/setup-container-test.js index 68286a4caa5..eb61d686a0b 100644 --- a/tests/integration/setup-container-test.js +++ b/tests/integration/setup-container-test.js @@ -51,17 +51,3 @@ test("If a store is instantiated, it should be made available to each controller let fooController = container.lookup('controller:foo'); assert.ok(fooController.get('store') instanceof Store, "the store was injected"); }); - -test("serializers are not returned as singletons - each lookup should return a different instance", function(assert) { - let serializer1, serializer2; - serializer1 = container.lookup('serializer:-rest'); - serializer2 = container.lookup('serializer:-rest'); - assert.notEqual(serializer1, serializer2); -}); - -test("adapters are not returned as singletons - each lookup should return a different instance", function(assert) { - let adapter1, adapter2; - adapter1 = container.lookup('adapter:-rest'); - adapter2 = container.lookup('adapter:-rest'); - assert.notEqual(adapter1, adapter2); -}); From 950551c6f9d824862cf57779cd72652499650fce Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 22 Dec 2017 11:57:24 -0500 Subject: [PATCH 2093/2527] Remove `ContainerInstanceCache`. --- addon/-private/index.js | 3 +- addon/-private/system/store.js | 3 - .../system/store/container-instance-cache.js | 124 ------------------ tests/unit/private-test.js | 5 - 4 files changed, 1 insertion(+), 134 deletions(-) delete mode 100644 addon/-private/system/store/container-instance-cache.js diff --git a/addon/-private/index.js b/addon/-private/index.js index c6ecf77b842..8ffd4115426 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -30,10 +30,9 @@ export { default as parseResponseHeaders } from './utils/parse-response-headers' // should be private ? export { default as global } from './global'; export { default as isEnabled } from './features'; -// `ember-data-model-fragments` relies on `RootState`, `InternalModel` and `ContainerInstanceCache` +// `ember-data-model-fragments` relies on `RootState` and `InternalModel` export { default as RootState } from './system/model/states'; export { default as InternalModel } from './system/model/internal-model'; -export { default as ContainerInstanceCache } from './system/store/container-instance-cache'; export { PromiseArray, diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 3b24f44f7d2..236288ef6d1 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -50,7 +50,6 @@ import { import { getOwner } from '../utils'; import coerceId from "./coerce-id"; import RecordArrayManager from "./record-array-manager"; -import ContainerInstanceCache from './store/container-instance-cache'; import InternalModel from "./model/internal-model"; import isEnabled from '../features'; @@ -211,7 +210,6 @@ Store = Service.extend({ this.recordArrayManager = new RecordArrayManager({ store: this }); this._identityMap = new IdentityMap(); this._pendingSave = []; - this._instanceCache = new ContainerInstanceCache(getOwner(this), this); this._modelFactoryCache = Object.create(null); this._relationshipsPayloads = new RelationshipPayloadsManager(this); @@ -234,7 +232,6 @@ Store = Service.extend({ // used to keep track of all the find requests that need to be coalesced this._pendingFetch = MapWithDefault.create({ defaultValue() { return []; } }); - this._instanceCache = new ContainerInstanceCache(getOwner(this), this); this._adapterCache = Object.create(null); this._serializerCache = Object.create(null); }, diff --git a/addon/-private/system/store/container-instance-cache.js b/addon/-private/system/store/container-instance-cache.js deleted file mode 100644 index ba0311d6cca..00000000000 --- a/addon/-private/system/store/container-instance-cache.js +++ /dev/null @@ -1,124 +0,0 @@ -/* global heimdall */ -import { set } from '@ember/object'; - -const { - __get, - _instanceFor -} = heimdall.registerMonitor('system.store.container-instance-cache', - '__get', - '_instanceFor' -); - -/* - * The `ContainerInstanceCache` serves as a lazy cache for looking up - * instances of serializers and adapters. It has some additional logic for - * finding the 'fallback' adapter or serializer. - * - * The 'fallback' adapter or serializer is an adapter or serializer that is looked up - * when the preferred lookup fails. For example, say you try to look up `adapter:post`, - * but there is no entry (app/adapters/post.js in EmberCLI) for `adapter:post` in the registry. - * - * When an adapter or serializer is unfound, getFallbacks will be invoked with the current namespace - * ('adapter' or 'serializer') and the 'preferredKey' (usually a modelName). The method should return - * an array of keys to check against. - * - * The first entry in the fallbacks array that exists in the container will then be cached for - * `adapter:post`. So, the next time you look up `adapter:post`, you'll get the `adapter:application` - * instance (or whatever the fallback was if `adapter:application` doesn't exist). - * - * @private - * @class ContainerInstanceCache - * -*/ -export default class ContainerInstanceCache { - constructor(owner, store) { - this.isDestroying = false; - this.isDestroyed = false; - this._owner = owner; - this._store = store; - this._namespaces = { - adapter: Object.create(null), - serializer: Object.create(null) - }; - } - - get(namespace, preferredKey) { - heimdall.increment(__get); - let cache = this._namespaces[namespace]; - - if (cache[preferredKey]) { - return cache[preferredKey]; - } - - let preferredLookupKey = `${namespace}:${preferredKey}`; - - let instance = this._instanceFor(preferredLookupKey) || this._findInstance(namespace, this._fallbacksFor(namespace, preferredKey)); - if (instance) { - cache[preferredKey] = instance; - set(instance, 'store', this._store); - } - - return cache[preferredKey]; - } - - _fallbacksFor(namespace, preferredKey) { - if (namespace === 'adapter') { - return ['application', this._store.get('adapter'), '-json-api']; - } - - // serializer - return [ - 'application', - this.get('adapter', preferredKey).get('defaultSerializer'), - '-default' - ]; - } - - _findInstance(namespace, fallbacks) { - let cache = this._namespaces[namespace]; - - for (let i = 0, length = fallbacks.length; i < length; i++) { - let fallback = fallbacks[i]; - - if (cache[fallback]) { - return cache[fallback]; - } - - let lookupKey = `${namespace}:${fallback}`; - let instance = this._instanceFor(lookupKey); - - if (instance) { - cache[fallback] = instance; - return instance; - } - } - } - - _instanceFor(key) { - heimdall.increment(_instanceFor); - return this._owner.lookup(key); - } - - destroyCache(cache) { - let cacheEntries = Object.keys(cache); - - for (let i = 0, length = cacheEntries.length; i < length; i++) { - let cacheKey = cacheEntries[i]; - let cacheEntry = cache[cacheKey]; - if (cacheEntry) { - cacheEntry.destroy(); - } - } - } - - destroy() { - this.isDestroying = true; - this.destroyCache(this._namespaces.adapter); - this.destroyCache(this._namespaces.serializer); - this.isDestroyed = true; - } - - toString() { - return 'ContainerInstanceCache'; - } -} diff --git a/tests/unit/private-test.js b/tests/unit/private-test.js index 30e468493ff..b2f1c2f3515 100644 --- a/tests/unit/private-test.js +++ b/tests/unit/private-test.js @@ -1,16 +1,11 @@ import { module, test } from 'qunit'; import { - ContainerInstanceCache, InternalModel, RootState } from 'ember-data/-private'; module('-private'); -test('`ContainerInstanceCache` is accessible via private import', function(assert) { - assert.ok(!!ContainerInstanceCache); -}); - test('`InternalModel` is accessible via private import', function(assert) { assert.ok(!!InternalModel); }); From 276d0262b78fc1fd3e1f25fcb2b24e4400740692 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 22 Dec 2017 15:14:40 -0500 Subject: [PATCH 2094/2527] Add a test to ensure multiple stores get unique instances of serializers and adapters --- tests/integration/multiple-stores-test.js | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/integration/multiple-stores-test.js b/tests/integration/multiple-stores-test.js index bcf1fd59040..36bdbcf3c83 100644 --- a/tests/integration/multiple-stores-test.js +++ b/tests/integration/multiple-stores-test.js @@ -1,6 +1,7 @@ import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; +import { get } from '@ember/object'; import DS from 'ember-data'; @@ -136,3 +137,27 @@ test("embedded records should be created in multiple stores", function(assert) { assert.equal(env.store_b.hasRecordForId("super-villain", "1"), true, "superVillain should exist in store:store-b"); }); }); + + +test("each store should have a unique instance of the serializers", function(assert) { + env.registry.register('serializer:home-planet', DS.RESTSerializer.extend({})); + + let serializer_a = env.store_a.serializerFor('home-planet'); + let serializer_b = env.store_b.serializerFor('home-planet'); + + assert.equal(get(serializer_a, 'store'), env.store_a); + assert.equal(get(serializer_b, 'store'), env.store_b); + assert.notEqual(serializer_a, serializer_b); +}); + + +test("each store should have a unique instance of the adapters", function(assert) { + env.registry.register('adapter:home-planet', DS.Adapter.extend({})); + + let adapter_a = env.store_a.adapterFor('home-planet'); + let adapter_b = env.store_b.adapterFor('home-planet'); + + assert.equal(get(adapter_a, 'store'), env.store_a); + assert.equal(get(adapter_b, 'store'), env.store_b); + assert.notEqual(adapter_a, adapter_b); +}); From 15f5bfae6fff5b2148fcd19ccf8e9c546a2b1331 Mon Sep 17 00:00:00 2001 From: Alex Alvarez Date: Mon, 25 Dec 2017 23:18:15 -0500 Subject: [PATCH 2095/2527] Using store.serializerFor API instead of lookup --- .../qunit-rfc-232-files/tests/unit/__path__/__test__.js | 2 +- node-tests/fixtures/serializer-test/rfc232.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js index 3cbee777af0..eb18544d2c7 100644 --- a/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js +++ b/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js @@ -8,7 +8,7 @@ module('<%= friendlyTestDescription %>', function(hooks) { // Replace this with your real tests. test('it exists', function(assert) { let store = this.owner.lookup('service:store'); - let serializer = this.owner.factoryFor('serializer:<%= dasherizedModuleName %>').create({ store }); + let serializer = store.serializerFor('serializer:<%= dasherizedModuleName %>'); assert.ok(serializer); }); diff --git a/node-tests/fixtures/serializer-test/rfc232.js b/node-tests/fixtures/serializer-test/rfc232.js index 3c914973c44..eb94a50b2a4 100644 --- a/node-tests/fixtures/serializer-test/rfc232.js +++ b/node-tests/fixtures/serializer-test/rfc232.js @@ -8,7 +8,7 @@ module('Unit | Serializer | foo', function(hooks) { // Replace this with your real tests. test('it exists', function(assert) { let store = this.owner.lookup('service:store'); - let serializer = this.owner.factoryFor('serializer:foo').create({ store }); + let serializer = store.serializerFor('foo'); assert.ok(serializer); }); From abf5cd305701788dbb7d9bf1d9cb8d237eb39cfe Mon Sep 17 00:00:00 2001 From: Alex Alvarez Date: Mon, 25 Dec 2017 23:54:26 -0500 Subject: [PATCH 2096/2527] fixup test --- .../qunit-rfc-232-files/tests/unit/__path__/__test__.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js index eb18544d2c7..0a72b125520 100644 --- a/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js +++ b/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js @@ -8,7 +8,7 @@ module('<%= friendlyTestDescription %>', function(hooks) { // Replace this with your real tests. test('it exists', function(assert) { let store = this.owner.lookup('service:store'); - let serializer = store.serializerFor('serializer:<%= dasherizedModuleName %>'); + let serializer = store.serializerFor('<%= dasherizedModuleName %>'); assert.ok(serializer); }); From 723c4423b58ba816d7e78ea9f1ed6f0e36fd9b5f Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Thu, 28 Dec 2017 19:53:59 -0500 Subject: [PATCH 2097/2527] Fix tests with Ember Canary (#5303) --- .../relationships/belongs-to-test.js | 21 ++++++++++++++++--- .../relationships/has-many-test.js | 4 ++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 8e1aeb4d0d9..ade65f87a5c 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -542,12 +542,27 @@ test("relationshipsByName does not cache a factory", function(assert) { "model factory based on relationship type matches the model based on store.modelFor"); }); +function getDescriptor(object, key) { + var meta = Ember.meta(object); + var mixins = (meta && meta._mixins) || {}; + for (let klass of Object.values(mixins)) { + if (!klass.properties) { + continue; + } + let descriptor = klass.properties[key]; + if (descriptor) { + return descriptor; + } + } + return object[key]; +} + test("relationshipsByName is cached in production", function(assert) { let model = store.modelFor('user'); let oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it //did not get dynamically changed when accessed - let relationshipsByName = model.relationshipsByName; + let relationshipsByName = getDescriptor(model, 'relationshipsByName'); let oldCacheable = relationshipsByName._cacheable; relationshipsByName._cacheable = true; Ember.testing = false; @@ -565,7 +580,7 @@ test("relatedTypes is cached in production", function(assert) { let oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it //did not get dynamically changed when accessed - let relatedTypes = model.relatedTypes; + let relatedTypes = getDescriptor(model, 'relatedTypes'); let oldCacheable = relatedTypes._cacheable; relatedTypes._cacheable = true; Ember.testing = false; @@ -583,7 +598,7 @@ test("relationships is cached in production", function(assert) { let oldTesting = Ember.testing; //We set the cacheable to true because that is the default state for any CP and then assert that it //did not get dynamically changed when accessed - let relationships = model.relationships; + let relationships = getDescriptor(model, 'relationships'); let oldCacheable = relationships._cacheable; relationships._cacheable = true; Ember.testing = false; diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 6ce847463cb..1f46d79f96b 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -481,8 +481,8 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ promise1, promise2 ]).then(() => { - assert.equal(promise1.promise, promise2.promise, "Same promise is returned both times"); - }); + assert.equal(promise1.get('promise'), promise2.get('promise'), "Same promise is returned both times"); + }) }); test("A hasMany backed by a link remains a promise after a record has been added to it", function(assert) { From 6be99125a8cedede507387f99071adc09d11977a Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 28 Dec 2017 21:12:50 -0500 Subject: [PATCH 2098/2527] Serializers and adapters should be unique per store --- addon/-private/system/store.js | 27 ++++++++++++++----- addon/setup-container.js | 5 ++-- tests/helpers/store.js | 16 ++++++++++- .../non-dasherized-lookups-test.js | 23 +++++++--------- tests/integration/multiple-stores-test.js | 6 ++--- 5 files changed, 51 insertions(+), 26 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 236288ef6d1..40fa112405f 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2655,31 +2655,37 @@ Store = Service.extend({ adapter = owner.lookup(`adapter:${normalizedModelName}`); if (adapter !== undefined) { + set(adapter, 'store', this); _adapterCache[normalizedModelName] = adapter; return adapter; } // no adapter found for the specific model, fallback and check for application adapter - adapter = owner.lookup('adapter:application'); + adapter = _adapterCache.application || owner.lookup('adapter:application'); if (adapter !== undefined) { + set(adapter, 'store', this); _adapterCache[normalizedModelName] = adapter; + _adapterCache.application = adapter; return adapter; } // no model specific adapter or application adapter, check for an `adapter` // property defined on the store let adapterName = this.get('adapter'); - adapter = owner.lookup(`adapter:${adapterName}`); + adapter = _adapterCache[adapterName] || owner.lookup(`adapter:${adapterName}`); if (adapter !== undefined) { + set(adapter, 'store', this); _adapterCache[normalizedModelName] = adapter; + _adapterCache[adapterName] = adapter; return adapter; } // final fallback, no model specific adapter, no application adapter, no // `adapter` property on store: use json-api adapter - adapter = owner.lookup('adapter:-json-api'); + adapter = _adapterCache['-json-api'] || owner.lookup('adapter:-json-api'); + set(adapter, 'store', this); _adapterCache[normalizedModelName] = adapter; - + _adapterCache['-json-api'] = adapter; return adapter; }, @@ -2722,14 +2728,17 @@ Store = Service.extend({ serializer = owner.lookup(`serializer:${normalizedModelName}`); if (serializer !== undefined) { + set(serializer, 'store', this); _serializerCache[normalizedModelName] = serializer; return serializer; } // no serializer found for the specific model, fallback and check for application serializer - serializer = owner.lookup('serializer:application'); + serializer = _serializerCache.application || owner.lookup('serializer:application'); if (serializer !== undefined) { + set(serializer, 'store', this); _serializerCache[normalizedModelName] = serializer; + _serializerCache.application = serializer; return serializer; } @@ -2737,16 +2746,20 @@ Store = Service.extend({ // property defined on the adapter let adapter = this.adapterFor(modelName); let serializerName = get(adapter, 'defaultSerializer'); - serializer = owner.lookup(`serializer:${serializerName}`); + serializer = _serializerCache[serializerName] || owner.lookup(`serializer:${serializerName}`); if (serializer !== undefined) { + set(serializer, 'store', this); _serializerCache[normalizedModelName] = serializer; + _serializerCache[serializerName] = serializer; return serializer; } // final fallback, no model specific serializer, no application serializer, no // `serializer` property on store: use json-api serializer - serializer = owner.lookup('serializer:-default'); + serializer = _serializerCache['-default'] || owner.lookup('serializer:-default'); + set(serializer, 'store', this); _serializerCache[normalizedModelName] = serializer; + _serializerCache['-default'] = serializer; return serializer; }, diff --git a/addon/setup-container.js b/addon/setup-container.js index 0c5a16d25a0..9b78e973ff7 100644 --- a/addon/setup-container.js +++ b/addon/setup-container.js @@ -31,6 +31,9 @@ function has(applicationOrRegistry, fullName) { @param {Ember.Registry} registry */ function initializeStore(registry) { + let registerOptionsForType = registry.registerOptionsForType || registry.optionsForType; + registerOptionsForType.call(registry, 'serializer', { singleton: false }); + registerOptionsForType.call(registry, 'adapter', { singleton: false }); registry.register('serializer:-default', JSONSerializer); registry.register('serializer:-rest', RESTSerializer); registry.register('adapter:-rest', RESTAdapter); @@ -66,8 +69,6 @@ function initializeStoreInjections(registry) { // registry.injection for Ember < 2.1.0 // application.inject for Ember 2.1.0+ let inject = registry.inject || registry.injection; - inject.call(registry, 'adapter', 'store', 'service:store'); - inject.call(registry, 'serializer', 'store', 'service:store'); inject.call(registry, 'controller', 'store', 'service:store'); inject.call(registry, 'route', 'store', 'service:store'); inject.call(registry, 'data-adapter', 'store', 'service:store'); diff --git a/tests/helpers/store.js b/tests/helpers/store.js index c3bc2b24812..2e909241125 100644 --- a/tests/helpers/store.js +++ b/tests/helpers/store.js @@ -46,6 +46,8 @@ export default function setupStore(options) { adapter: adapter })); + registry.optionsForType('serializer', { singleton: false }); + registry.optionsForType('adapter', { singleton: false }); registry.register('adapter:-default', DS.Adapter); registry.register('serializer:-default', DS.JSONAPISerializer); @@ -62,7 +64,19 @@ export default function setupStore(options) { env.restSerializer.store = env.store; env.serializer = env.store.serializerFor('-default'); env.serializer.store = env.store; - env.adapter = env.store.get('defaultAdapter'); + Object.defineProperty(env, 'adapter', { + get() { + if (!this._adapter) { + this._adapter = this.store.adapterFor('application'); + } + return this._adapter; + }, + set(adapter) { + this._adapter = adapter; + }, + enumerable: true, + configurable: true + }); return env; } diff --git a/tests/integration/backwards-compat/non-dasherized-lookups-test.js b/tests/integration/backwards-compat/non-dasherized-lookups-test.js index 9cb4c3a290a..807a1657966 100644 --- a/tests/integration/backwards-compat/non-dasherized-lookups-test.js +++ b/tests/integration/backwards-compat/non-dasherized-lookups-test.js @@ -8,7 +8,6 @@ import DS from 'ember-data'; const { JSONAPIAdapter, - JSONAPISerializer, Model, attr, belongsTo, @@ -23,16 +22,16 @@ module('integration/backwards-compat/non-dasherized-lookups - non dasherized loo name: attr('string') }); - const env = setupStore({ postNote: PostNote }); - const ApplicationAdapter = JSONAPIAdapter.extend({ shouldBackgroundReloadRecord() { return false; } }); - env.registry.register('adapter:application', ApplicationAdapter); - env.registry.register('serializer:application', JSONAPISerializer); + const env = setupStore({ + postNote: PostNote, + adapter: ApplicationAdapter + }); store = env.store; }, @@ -102,20 +101,18 @@ module('integration/backwards-compat/non-dasherized-lookups - non dasherized loo postNotes: hasMany('post_note') }); - const env = setupStore({ - longModelName: LongModelName, - notePost: NotePost, - postNote: PostNote - }); - const ApplicationAdapter = JSONAPIAdapter.extend({ shouldBackgroundReloadRecord() { return false; } }); - env.registry.register('adapter:application', ApplicationAdapter); - env.registry.register('serializer:application', JSONAPISerializer); + const env = setupStore({ + longModelName: LongModelName, + notePost: NotePost, + postNote: PostNote, + adapter: ApplicationAdapter + }); store = env.store; }, diff --git a/tests/integration/multiple-stores-test.js b/tests/integration/multiple-stores-test.js index 36bdbcf3c83..116d953cea6 100644 --- a/tests/integration/multiple-stores-test.js +++ b/tests/integration/multiple-stores-test.js @@ -145,9 +145,9 @@ test("each store should have a unique instance of the serializers", function(ass let serializer_a = env.store_a.serializerFor('home-planet'); let serializer_b = env.store_b.serializerFor('home-planet'); - assert.equal(get(serializer_a, 'store'), env.store_a); - assert.equal(get(serializer_b, 'store'), env.store_b); - assert.notEqual(serializer_a, serializer_b); + assert.equal(get(serializer_a, 'store'), env.store_a, 'serializer_a\'s store prop should be sotre_a'); + assert.equal(get(serializer_b, 'store'), env.store_b, 'serializer_b\'s store prop should be sotre_b'); + assert.notEqual(serializer_a, serializer_b, 'serialier_a and serialier_b should be unique instances'); }); From dfa794a41dea3662c6add35a2d19baa86c38780e Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 29 Dec 2017 14:49:09 -0500 Subject: [PATCH 2099/2527] Simplify the getDescriptor test helper --- tests/helpers/store.js | 3 +++ tests/integration/relationships/belongs-to-test.js | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/helpers/store.js b/tests/helpers/store.js index 2e909241125..5cbea0dd3f8 100644 --- a/tests/helpers/store.js +++ b/tests/helpers/store.js @@ -64,6 +64,9 @@ export default function setupStore(options) { env.restSerializer.store = env.store; env.serializer = env.store.serializerFor('-default'); env.serializer.store = env.store; + // lazily create the adapter method because some tets depend on + // modifiying the adapter in the container after setupStore is + // called Object.defineProperty(env, 'adapter', { get() { if (!this._adapter) { diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index ade65f87a5c..842aff95feb 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -545,7 +545,8 @@ test("relationshipsByName does not cache a factory", function(assert) { function getDescriptor(object, key) { var meta = Ember.meta(object); var mixins = (meta && meta._mixins) || {}; - for (let klass of Object.values(mixins)) { + for (let key in mixins) { + let klass = mixins[key] if (!klass.properties) { continue; } @@ -554,6 +555,8 @@ function getDescriptor(object, key) { return descriptor; } } + // Fallback to grabbing the descriptor off of the object for old + // versions of Ember return object[key]; } From 45428ce0c7e154ccb6dcaf31badff48bfd32a4de Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Fri, 29 Dec 2017 17:01:14 -0500 Subject: [PATCH 2100/2527] Update the changelog for the 2.18 release (#5306) --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bb2307864f..7f945803483 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,29 @@ ### Master +### Release 2.18.0 (December 28, 2017) +- [#5225](https://github.com/emberjs/data/pull/5225) Remove blueprints for Mocha < 0.12. (#5225) +- [#4998](https://github.com/emberjs/data/pull/4998) [DOC beta] Assert that both modelName and id are passed to `peekRecord` (#4998) +- [#5223](https://github.com/emberjs/data/pull/5223) [BUGFIX release] Cleanup test only dependencies. +- [#5200](https://github.com/emberjs/data/pull/5200) bump rsvp +- [#5108](https://github.com/emberjs/data/pull/5108) Updates addon to adhere to RFC 176 (#5108) +- [#5232](https://github.com/emberjs/data/pull/5232) Update documentation in model.js +- [#5203](https://github.com/emberjs/data/pull/5203) Skip ember try on appveyor +- [#5239](https://github.com/emberjs/data/pull/5239) Deprecate support for "production like" values in EMBER_ENV +- [#5213](https://github.com/emberjs/data/pull/5213) [BUGFIX beta] proxy `meta` on PromiseArray +- [#5212](https://github.com/emberjs/data/pull/5212) Do not show feature flag improved-ajax methods in the api docs +- [#5206](https://github.com/emberjs/data/pull/5206) [BUGFIX beta] Fix broccoli-babel-transpiler cache warnings +- [#5216](https://github.com/emberjs/data/pull/5216) [BUGFIX beta] invalid record becomes loaded when property is reset +- [#5217](https://github.com/emberjs/data/pull/5217) [BUGFIX beta] RecordReference returns null when not yet loaded +- [#5218](https://github.com/emberjs/data/pull/5218) Update assert against nulls (#5218) +- [#5220](https://github.com/emberjs/data/pull/5220) Remove (unnecessary) ember-inflector peer dependency +- [#5221](https://github.com/emberjs/data/pull/5221) Fix docs link. (#5221) +- [#5224](https://github.com/emberjs/data/pull/5224) Add missing dependency for travis build +- [#5238](https://github.com/emberjs/data/pull/5238) Move initialize-store-service.js out of the instance-initializers dir… +- [#5242](https://github.com/emberjs/data/pull/5242) [BUGFIX beta] Normalize model names during `push` +- [#5250](https://github.com/emberjs/data/pull/5250) [doc] Update links to Ember Guide (#5250) +- [#5260](https://github.com/emberjs/data/pull/5260) [doc] Update urlForFindRecord example + ### Release 2.17.0 (November 19, 2017) - [#5216](https://github.com/emberjs/data/pull/5216) [BUGFIX beta] invalid record becomes loaded when property is reset - [#4998](https://github.com/emberjs/data/pull/4998) [DOC beta] Assert that both modelName and id are passed to `peekRecord` (#4998) From 5977fc25f02e3d626e9e14cd90fe65fb678f1b20 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 29 Dec 2017 21:30:22 -0500 Subject: [PATCH 2101/2527] Bump version to 3.1.0-canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6b1137bdc65..9371e9fe6d4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "3.0.0-canary", + "version": "3.1.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From 68101c6629efa21d65a276583ced05fce8e06373 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 2 Jan 2018 10:14:25 -0500 Subject: [PATCH 2102/2527] Remove `s3-put` and `cached-npm` scripts. These have not been used for some time and are obsolete (they predate Travis' ability to have `cache:` in `.travis.yml`). --- bin/cached-npm | 55 ------------------------------------- bin/s3-put | 73 -------------------------------------------------- 2 files changed, 128 deletions(-) delete mode 100755 bin/cached-npm delete mode 100755 bin/s3-put diff --git a/bin/cached-npm b/bin/cached-npm deleted file mode 100755 index 5c7795bb9f6..00000000000 --- a/bin/cached-npm +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash -# Usage: cached-npm install -# -# After running `npm`, caches the `node_modules` directory to S3. -# On the next run, restores the cached directory before running `npm`. -# When `package.json` changes, the cache gets rebuilt. -# -# Requirements: -# - package.json -# - TRAVIS_REPO_SLUG -# - TRAVIS_NODE_VERSION -# - S3_BUILD_CACHE_BUCKET -# - script/s3-put -# - npm -# - curl -# -# Author: Mislav Marohnić - -set -e - -compute_md5() { - local output="$(openssl md5)" - echo "${output##* }" -} - -download() { - curl --tcp-nodelay -qsfL "$1" -o "$2" -} - -script_dir=$(dirname "${BASH_SOURCE[0]}") -bundle_path="node_modules npm_cache" -cache_busting_hash="$(compute_md5 < package.json)" -cache_name="npm-${TRAVIS_NODE_VERSION}-${cache_busting_hash}.tgz" -fetch_url="https://${S3_BUILD_CACHE_BUCKET}.s3.amazonaws.com/${TRAVIS_REPO_SLUG}/${cache_name}" - -if download "$fetch_url" "$cache_name"; then - echo "Reusing cached bundle ${cache_name}" - tar xzf "$cache_name" -fi - -NPM_CONFIG_CACHE=./npm_cache npm "$@" - -if [ ! -f "$cache_name" ]; then - if [ -z "$S3_SECRET_ACCESS_KEY" ] || [ -z "$S3_ACCESS_KEY_ID" ] - then - echo "Enviroment variables not set. Exiting..." - exit 0 - fi - - echo "Caching \`${bundle_path}' to S3" - tar czf "$cache_name" $bundle_path - $script_dir/s3-put "$cache_name" "${S3_BUILD_CACHE_BUCKET}:${TRAVIS_REPO_SLUG}/${cache_name}" -fi - -# vim: filetype=sh diff --git a/bin/s3-put b/bin/s3-put deleted file mode 100755 index 4f8a142603b..00000000000 --- a/bin/s3-put +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env bash -# Usage: s3-put [:] [] -# -# Uploads a file to the Amazon S3 service. -# Outputs the URL for the newly uploaded file. -# -# Requirements: -# - S3_ACCESS_KEY_ID -# - S3_SECRET_ACCESS_KEY -# - openssl -# - curl -# -# Author: Mislav Marohnić - -set -e - -authorization() { - local signature="$(string_to_sign | hmac_sha1 | base64)" - echo "AWS ${S3_ACCESS_KEY_ID?}:${signature}" -} - -hmac_sha1() { - openssl dgst -binary -sha1 -hmac "${S3_SECRET_ACCESS_KEY?}" -} - -base64() { - openssl enc -base64 -} - -bin_md5() { - openssl dgst -binary -md5 -} - -string_to_sign() { - echo "$http_method" - echo "$content_md5" - echo "$content_type" - echo "$date" - echo "x-amz-acl:$acl" - printf "/$bucket/$remote_path" -} - -date_string() { - LC_TIME=C date "+%a, %d %h %Y %T %z" -} - -file="$1" -bucket="${2%%:*}" -remote_path="${2#*:}" -content_type="$3" - -if [ -z "$remote_path" ] || [ "$remote_path" = "$bucket" ]; then - remote_path="${file##*/}" -fi - -http_method=PUT -acl="public-read" -content_md5="$(bin_md5 < "$file" | base64)" -date="$(date_string)" - -url="https://$bucket.s3.amazonaws.com/$remote_path" - -curl -qsSf -T "$file" \ - -H "Authorization: $(authorization)" \ - -H "x-amz-acl: $acl" \ - -H "Date: $date" \ - -H "Content-MD5: $content_md5" \ - -H "Content-Type: $content_type" \ - "$url" - -echo "$url" - -# vim: filetype=sh From 7c6448d55efe441e9c62165ecc6bce9114ea4bcb Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Thu, 4 Jan 2018 10:50:26 -0500 Subject: [PATCH 2103/2527] [CLEANUP beta] Remove model.container deprecation (#5309) --- addon/-private/system/model/model.js | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index cca30e02349..9e2dad3953b 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1,5 +1,4 @@ import ComputedProperty from '@ember/object/computed'; -import { setOwner } from '@ember/application'; import { isNone } from '@ember/utils'; import EmberError from '@ember/error'; import Evented from '@ember/object/evented'; @@ -11,7 +10,7 @@ import EmberObject, { import Map from '@ember/map'; import Ember from 'ember'; import { DEBUG } from '@glimmer/env'; -import { assert, deprecate, warn } from '@ember/debug'; +import { assert, warn } from '@ember/debug'; import { PromiseObject } from "../promise-proxies"; import Errors from "../model/errors"; import isEnabled from '../../features'; @@ -1838,25 +1837,6 @@ Model.reopenClass({ } }); -// if `Ember.setOwner` is defined, accessing `this.container` is -// deprecated (but functional). In "standard" Ember usage, this -// deprecation is actually created via an `.extend` of the factory -// inside the container itself, but that only happens on models -// with MODEL_FACTORY_INJECTIONS enabled :( -if (setOwner) { - Object.defineProperty(Model.prototype, 'container', { - configurable: true, - enumerable: false, - get() { - deprecate('Using the injected `container` is deprecated. Please use the `getOwner` helper instead to access the owner of this object.', - false, - { id: 'ember-application.injected-container', until: '3.0.0' }); - - return this.store.container; - } - }); -} - if (isEnabled('ds-rollback-attribute')) { Model.reopen({ /** From 25ebee6a57911542a8b371e904c046f6baffb093 Mon Sep 17 00:00:00 2001 From: Ryan T Date: Tue, 9 Jan 2018 20:10:24 -0500 Subject: [PATCH 2104/2527] Dont serialize new belongsTo records (#5317) * Dont serialize new belongsTo records that do not have an ID * Add a test for nulling out a belognsTo relationship --- addon/serializers/json-api.js | 3 +- .../serializers/json-api-serializer-test.js | 72 +++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 6f410fa5881..02ba82f1acd 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -555,8 +555,9 @@ const JSONAPISerializer = JSONSerializer.extend({ if (this._canSerialize(key)) { let belongsTo = snapshot.belongsTo(key); - if (belongsTo !== undefined) { + let belongsToIsNotNew = belongsTo && belongsTo.record && !belongsTo.record.get('isNew'); + if (belongsTo === null || belongsToIsNotNew) { json.relationships = json.relationships || {}; let payloadKey = this._getMappedKey(key, snapshot.type); diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 42170fbaa1f..75598b45ba5 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -358,6 +358,78 @@ testInDebug('Warns when defining extractMeta()', function(assert) { }, /You've defined 'extractMeta' in/); }); +test('a belongsTo relationship that is not set will not be in the relationships key', function(assert) { + run(function() { + serializer.pushPayload(store, { + data: { + type: 'handles', + id: 1 + } + }); + + let handle = store.peekRecord('handle', 1); + + let serialized = handle.serialize({ includeId: true }); + assert.deepEqual(serialized, { + data: { + type: 'handles', + id: '1' + } + }); + }); +}); + +test('a belongsTo relationship that is set to null will show as null in the relationships key', function(assert) { + run(function() { + serializer.pushPayload(store, { + data: { + type: 'handles', + id: 1 + } + }); + + let handle = store.peekRecord('handle', 1); + handle.set('user', null); + + let serialized = handle.serialize({ includeId: true }); + assert.deepEqual(serialized, { + data: { + type: 'handles', + id: '1', + relationships: { + user: { + data: null + } + } + } + }); + }); +}); + +test('a belongsTo relationship set to a new record will not show in the relationships key', function(assert) { + run(function() { + serializer.pushPayload(store, { + data: { + type: 'handles', + id: 1 + } + }); + + let handle = store.peekRecord('handle', 1); + + let user = store.createRecord('user'); + handle.set('user', user); + + let serialized = handle.serialize({ includeId: true }); + assert.deepEqual(serialized, { + data: { + type: 'handles', + id: '1' + } + }); + }); +}); + testInDebug('JSON warns when combined with EmbeddedRecordsMixin', function(assert) { assert.expectWarning(function() { DS.JSONAPISerializer.extend(DS.EmbeddedRecordsMixin).create(); From 1a56756f043e7ede5d483d848b9a4ebf0d418356 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 9 Jan 2018 21:10:22 -0500 Subject: [PATCH 2105/2527] Clean up a bunch of invalid yuidoc blocks that were causing warnings to print during prod builds --- addon/-private/system/identity-map.js | 2 +- addon/-private/system/internal-model-map.js | 11 ++++++++--- addon/-private/system/model/internal-model.js | 6 +++--- addon/-private/system/references/record.js | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/identity-map.js b/addon/-private/system/identity-map.js index 68f7cb71783..361fffc6e98 100644 --- a/addon/-private/system/identity-map.js +++ b/addon/-private/system/identity-map.js @@ -20,7 +20,7 @@ export default class IdentityMap { @method retrieve @param modelName a previously normalized modelName - @returns {InternalModelMap} the InternalModelMap for the given modelName + @return {InternalModelMap} the InternalModelMap for the given modelName */ retrieve(modelName) { let map = this._map[modelName]; diff --git a/addon/-private/system/internal-model-map.js b/addon/-private/system/internal-model-map.js index 310ba87e0d9..d3f9d180469 100644 --- a/addon/-private/system/internal-model-map.js +++ b/addon/-private/system/internal-model-map.js @@ -20,9 +20,9 @@ export default class InternalModelMap { } /** - * - * @param id - * @returns {InternalModel} + * @method get + * @param id {String} + * @return {InternalModel} */ get(id) { return this._idToModel[id]; @@ -71,6 +71,8 @@ export default class InternalModelMap { /** An array of all models of this modelName + @property models + @type Array */ get models() { return this._models; @@ -78,6 +80,8 @@ export default class InternalModelMap { /** * meta information about internalModels + * @property metadata + * @type Object */ get metadata() { return this._metadata || (this._metadata = Object.create(null)); @@ -86,6 +90,7 @@ export default class InternalModelMap { /** deprecated (and unsupported) way of accessing modelClass + @property type @deprecated */ get type() { diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 805331e1c97..6c5d896dccb 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -423,7 +423,7 @@ export default class InternalModel { }); } - /** + /* Computes the set of internal models reachable from `this` across exactly one relationship. @@ -439,7 +439,7 @@ export default class InternalModel { } - /** + /* Computes the set of internal models reachable from this internal model. Reachability is determined over the relationship graph (ie a graph where @@ -472,7 +472,7 @@ export default class InternalModel { } - /** + /* Unload the record for this internal model. This will cause the record to be destroyed and freed up for garbage collection. It will also do a check for cleaning up internal models. diff --git a/addon/-private/system/references/record.js b/addon/-private/system/references/record.js index 9a4cbf43c83..0583d13832a 100644 --- a/addon/-private/system/references/record.js +++ b/addon/-private/system/references/record.js @@ -86,7 +86,7 @@ RecordReference.prototype.remoteType = function() { ``` @method push - @param {Promise|Object} + @param objectOrPromise {Promise|Object} @return Promise a promise for the value (record or relationship) */ RecordReference.prototype.push = function(objectOrPromise) { From 2575b4a70c8b1898d1f688d6fa19ed08c540ae40 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 9 Jan 2018 22:23:38 -0500 Subject: [PATCH 2106/2527] Stop using deprecated vendor-prefix hook to inject enableoptionalfeatures url check. --- lib/enable-optional-features-via-url/index.js | 19 ++++++++++++++----- tests/index.html | 1 + 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/enable-optional-features-via-url/index.js b/lib/enable-optional-features-via-url/index.js index 968a0373d38..28986444d1c 100644 --- a/lib/enable-optional-features-via-url/index.js +++ b/lib/enable-optional-features-via-url/index.js @@ -12,13 +12,22 @@ module.exports = { the flag to true when there is a `enableoptionalfeatures` query parameter. */ contentFor: function(name) { - if (name === "vendor-prefix") { + if (name === "enable-optional-features") { var array = [ + "", ]; return array.join('\n'); diff --git a/tests/index.html b/tests/index.html index 5209b852321..1f02805e3bf 100644 --- a/tests/index.html +++ b/tests/index.html @@ -20,6 +20,7 @@ {{content-for "body"}} {{content-for "test-body"}} + {{content-for "enable-optional-features"}} From bd40bd4cc563621d73ac6ea583304e6dc6e361fa Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 9 Jan 2018 20:51:24 -0500 Subject: [PATCH 2107/2527] Update some dependencies to clean up some noise when running yarn install --- package.json | 7 ++- yarn.lock | 121 ++++++++++++++++----------------------------------- 2 files changed, 41 insertions(+), 87 deletions(-) diff --git a/package.json b/package.json index 9371e9fe6d4..1fba64b1d27 100644 --- a/package.json +++ b/package.json @@ -68,10 +68,9 @@ "broccoli-string-replace": "^0.1.1", "broccoli-test-helper": "^1.2.0", "broccoli-uglify-sourcemap": "^1.0.1", - "broccoli-yuidoc": "^2.1.0", + "broccoli-yuidoc": "^3.0.0", "co": "^4.6.0", "common-tags": "^1.4.0", - "ember-ajax": "^2.4.1", "ember-cli": "^2.11.1", "ember-cli-app-version": "^3.0.0", "ember-cli-blueprint-test-helpers": "^0.18.3", @@ -100,11 +99,11 @@ "express": "^4.14.0", "faker": "^3.1.0", "github": "^1.1.1", - "glob": "5.0.13", + "glob": "^5.0.13", "heimdall-query": "^0.0.8", "json-api-mock-server": "0.1.1", "loader.js": "^4.5.0", - "mocha": "2.4.5", + "mocha": "^2.4.5", "mocha-only-detector": "0.0.2", "morgan": "^1.7.0", "rimraf": "2.5.2", diff --git a/yarn.lock b/yarn.lock index 2be650ed1ad..0e405441acb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1169,19 +1169,6 @@ broccoli-caching-writer@^3.0.3: rsvp "^3.0.17" walk-sync "^0.3.0" -broccoli-caching-writer@~2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" - dependencies: - broccoli-kitchen-sink-helpers "^0.2.5" - broccoli-plugin "1.1.0" - debug "^2.1.1" - lodash-node "^3.2.0" - rimraf "^2.2.8" - rsvp "^3.0.17" - symlink-or-copy "^1.0.0" - walk-sync "^0.2.0" - broccoli-clean-css@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" @@ -1359,14 +1346,6 @@ broccoli-merge-trees@^2.0.0: broccoli-plugin "^1.3.0" merge-trees "^1.0.1" -broccoli-merge-trees@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-0.2.4.tgz#1936f63bb09e24246b1e91d8c53162c0f7b24c3c" - dependencies: - broccoli-plugin "^1.0.0" - debug "^2.2.0" - symlink-or-copy "^1.0.0" - broccoli-middleware@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-1.0.0.tgz#92f4e1fb9a791ea986245a7077f35cc648dab097" @@ -1508,15 +1487,15 @@ broccoli-writer@~0.1.1: quick-temp "^0.1.0" rsvp "^3.0.6" -broccoli-yuidoc@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/broccoli-yuidoc/-/broccoli-yuidoc-2.1.0.tgz#d208d5c056e421a51f0c7701e938229e7e85c2e6" +broccoli-yuidoc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/broccoli-yuidoc/-/broccoli-yuidoc-3.0.0.tgz#e436588ddfb6ae81ce82d87e894333d0fdd10487" dependencies: - broccoli-caching-writer "~2.0.1" - broccoli-merge-trees "~0.2.3" + broccoli-caching-writer "^3.0.3" + broccoli-merge-trees "^2.0.0" merge "~1.2.0" - rsvp "~3.1.0" - yuidocjs "~0.9.0" + rsvp "^3.5.0" + yuidocjs "^0.10.2" broccoli@^1.1.0: version "1.1.3" @@ -2221,12 +2200,6 @@ electron-to-chromium@^1.3.24: version "1.3.25" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.25.tgz#453b21009836d0997d86035601ff6cae4791c460" -ember-ajax@^2.4.1: - version "2.5.6" - resolved "https://registry.yarnpkg.com/ember-ajax/-/ember-ajax-2.5.6.tgz#a75f743ccf1b95e979a5cf96013b3dba8fa625e4" - dependencies: - ember-cli-babel "^5.1.5" - ember-cli-app-version@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-3.1.0.tgz#074b0330581a7b8ab094ff07fefb34e0d0254bfd" @@ -3473,23 +3446,12 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" - dependencies: - graceful-fs "~2.0.0" - inherits "2" - minimatch "~0.2.11" - -glob@5.0.13: - version "5.0.13" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.13.tgz#0b6ffc3ac64eb90669f723a00a0ebb7281b33f8f" +glob@3.2.11: + version "3.2.11" + resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" dependencies: - inflight "^1.0.4" inherits "2" - minimatch "^2.0.1" - once "^1.3.0" - path-is-absolute "^1.0.0" + minimatch "0.3" glob@7.1.1: version "7.1.1" @@ -3511,7 +3473,7 @@ glob@^4.3.2: minimatch "^2.0.1" once "^1.3.0" -glob@^5.0.10, glob@^5.0.15: +glob@^5.0.10, glob@^5.0.13, glob@^5.0.15: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: @@ -3571,17 +3533,13 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" -graceful-fs@~2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" - "graceful-readlink@>= 1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" -growl@1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.8.1.tgz#4b2dec8d907e93db336624dcec0183502f8c9428" +growl@1.9.2: + version "1.9.2" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" growly@^1.3.0: version "1.3.0" @@ -4247,10 +4205,6 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" -lodash-node@^3.2.0: - version "3.10.2" - resolved "https://registry.yarnpkg.com/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" - lodash._baseassign@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" @@ -4748,25 +4702,25 @@ mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" +minimatch@0.3: + version "0.3.0" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" + dependencies: + lru-cache "2" + sigmund "~1.0.0" + "minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: brace-expansion "^1.1.7" -minimatch@^2.0.1, minimatch@^2.0.3, minimatch@^2.0.8: +minimatch@^2.0.1, minimatch@^2.0.3: version "2.0.10" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" dependencies: brace-expansion "^1.0.0" -minimatch@~0.2.11: - version "0.2.14" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a" - dependencies: - lru-cache "2" - sigmund "~1.0.0" - minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -4801,19 +4755,20 @@ mocha-only-detector@0.0.2: esprimaq "^0.0.1" glob "^4.3.2" -mocha@2.4.5: - version "2.4.5" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.4.5.tgz#151768dd2875eb51bc8295e9800026e9f2bb398f" +mocha@^2.4.5: + version "2.5.3" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58" dependencies: commander "2.3.0" debug "2.2.0" diff "1.4.0" escape-string-regexp "1.0.2" - glob "3.2.3" - growl "1.8.1" + glob "3.2.11" + growl "1.9.2" jade "0.26.3" mkdirp "0.5.1" supports-color "1.2.0" + to-iso-string "0.0.2" moment-timezone@^0.3.0: version "0.3.1" @@ -5608,10 +5563,6 @@ rsvp@~3.0.6: version "3.0.21" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" -rsvp@~3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.1.0.tgz#19d96e71315f3ddbc57c4c62a6db898adb64d791" - rsvp@~3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" @@ -6192,6 +6143,10 @@ to-fast-properties@^1.0.0, to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" +to-iso-string@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" + tough-cookie@>=0.12.0: version "2.3.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" @@ -6374,7 +6329,7 @@ walk-sync@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" -walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: +walk-sync@^0.2.5, walk-sync@^0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" dependencies: @@ -6633,14 +6588,14 @@ yui@^3.18.1: dependencies: request "~2.40.0" -yuidocjs@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/yuidocjs/-/yuidocjs-0.9.0.tgz#d2ff2b37cadf30e3d45385c58f5003e5a83f2723" +yuidocjs@^0.10.2: + version "0.10.2" + resolved "https://registry.yarnpkg.com/yuidocjs/-/yuidocjs-0.10.2.tgz#33924967ce619024cd70ef694e267d2f988f73f6" dependencies: express "^4.13.1" graceful-fs "^4.1.2" markdown-it "^4.3.0" mdn-links "^0.1.0" - minimatch "^2.0.8" + minimatch "^3.0.2" rimraf "^2.4.1" yui "^3.18.1" From 1732cd5beeda795a08fb6f70260fe830699ed454 Mon Sep 17 00:00:00 2001 From: bek Date: Thu, 11 Jan 2018 05:35:11 +0500 Subject: [PATCH 2108/2527] remove redundant `normalizeModelName` (#5319) --- addon/-private/system/store.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 40fa112405f..f1bbb9f1fb7 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -457,9 +457,7 @@ Store = Service.extend({ assert(`Calling store.find() with a query object is no longer supported. Use store.query() instead.`, typeof id !== 'object'); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = normalizeModelName(modelName); - - return this.findRecord(normalizedModelName, id); + return this.findRecord(modelName, id); }, /** From a80709cab096f42cdb6a18a5908311ce7d61c12b Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Wed, 10 Jan 2018 21:23:06 -0500 Subject: [PATCH 2109/2527] [CLEANUP beta] Remove support/deprecation for normalizeHash in 3.0.0 (#5289) --- addon/serializers/rest.js | 10 -- .../serializers/rest-serializer-test.js | 110 ------------------ 2 files changed, 120 deletions(-) diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index fa3dc9e756c..3480b3f9bab 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -160,16 +160,6 @@ const RESTSerializer = JSONSerializer.extend({ @param {String} prop @return {Object} */ - normalize(modelClass, resourceHash, prop) { - if (this.normalizeHash && this.normalizeHash[prop]) { - deprecate('`RESTSerializer.normalizeHash` has been deprecated. Please use `serializer.normalize` to modify the payload of single resources.', false, { - id: 'ds.serializer.normalize-hash-deprecated', - until: '3.0.0' - }); - this.normalizeHash[prop](resourceHash); - } - return this._super(modelClass, resourceHash); - }, /** Normalizes an array of resource payloads and returns a JSON-API Document diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 8516c28d9e5..d83759c327d 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -374,116 +374,6 @@ test("normalizeResponse loads secondary records with correct serializer", functi assert.equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); }); -testInDebug('normalizeHash normalizes specific parts of the payload (DEPRECATED)', function(assert) { - env.registry.register('serializer:application', DS.RESTSerializer.extend({ - normalizeHash: { - homePlanets(hash) { - hash.id = hash._id; - delete hash._id; - return hash; - } - } - })); - - var jsonHash = { - homePlanets: [{ _id: "1", name: "Umber", superVillains: [1] }] - }; - var array; - - run(function() { - assert.expectDeprecation(function() { - array = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); - }, /`RESTSerializer.normalizeHash` has been deprecated/); - }); - - assert.deepEqual(array, { - "data": [{ - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "superVillains": { - "data": [ - { "id": "1", "type": "super-villain" } - ] - } - } - }], - "included": [] - }); - -}); - -testInDebug('normalizeHash has been deprecated', function(assert) { - env.registry.register('serializer:application', DS.RESTSerializer.extend({ - - normalizeHash: { - homePlanets(hash) { - hash.id = hash._id; - delete hash._id; - return hash; - } - } - })); - - var jsonHash = { - homePlanets: [{ _id: "1", name: "Umber", superVillains: [1] }] - }; - - run(function() { - assert.expectDeprecation(function() { - env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); - }, /`RESTSerializer.normalizeHash` has been deprecated/); - }); -}); - - -testInDebug('normalizeHash works with transforms (DEPRECATED)', function(assert) { - env.registry.register('serializer:application', DS.RESTSerializer.extend({ - normalizeHash: { - evilMinions(hash) { - hash.condition = hash._condition; - delete hash._condition; - return hash; - } - } - })); - - env.registry.register('transform:condition', DS.Transform.extend({ - deserialize(serialized) { - if (serialized === 1) { - return "healing"; - } else { - return "unknown"; - } - }, - serialize(deserialized) { - if (deserialized === "healing") { - return 1; - } else { - return 2; - } - } - })); - - EvilMinion.reopen({ condition: DS.attr('condition') }); - - var jsonHash = { - evilMinions: [{ id: "1", name: "Tom Dale", superVillain: 1, _condition: 1 }] - }; - var array; - - run(function() { - assert.expectDeprecation(function() { - array = env.restSerializer.normalizeResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); - }, /`RESTSerializer.normalizeHash` has been deprecated/); - }); - - assert.equal(array.data[0].attributes.condition, "healing"); -}); - test('normalize should allow for different levels of normalization', function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend({ attrs: { From 4c2eca69049eac41c864123a59572608becf165e Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Wed, 10 Jan 2018 21:23:21 -0500 Subject: [PATCH 2110/2527] [CLEANUP beta] Remove support for global DS variable (#5287) --- addon/-private/global.js | 19 ------------------- addon/-private/index.js | 2 -- addon/index.js | 16 ---------------- 3 files changed, 37 deletions(-) delete mode 100644 addon/-private/global.js diff --git a/addon/-private/global.js b/addon/-private/global.js deleted file mode 100644 index be3d0e4a4c1..00000000000 --- a/addon/-private/global.js +++ /dev/null @@ -1,19 +0,0 @@ -/* globals global, window, self */ - -// originally from https://github.com/emberjs/ember.js/blob/c0bd26639f50efd6a03ee5b87035fd200e313b8e/packages/ember-environment/lib/global.js - -// from lodash to catch fake globals -function checkGlobal(value) { - return (value && value.Object === Object) ? value : undefined; -} - -// element ids can ruin global miss checks -function checkElementIdShadowing(value) { - return (value && value.nodeType === undefined) ? value : undefined; -} - -// export real global -export default checkGlobal(checkElementIdShadowing(typeof global === 'object' && global)) || - checkGlobal(typeof self === 'object' && self) || - checkGlobal(typeof window === 'object' && window) || - new Function('return this')(); // eval outside of strict mode diff --git a/addon/-private/index.js b/addon/-private/index.js index 8ffd4115426..0c529fcd05d 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -27,8 +27,6 @@ export { getOwner, modelHasAttributeOrRelationshipNamedType } from './utils'; export { default as coerceId } from './system/coerce-id'; export { default as parseResponseHeaders } from './utils/parse-response-headers'; -// should be private ? -export { default as global } from './global'; export { default as isEnabled } from './features'; // `ember-data-model-fragments` relies on `RootState` and `InternalModel` export { default as RootState } from './system/model/states'; diff --git a/addon/index.js b/addon/index.js index 397f90fb601..012352ad391 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,6 +1,5 @@ import EmberError from '@ember/error'; import Ember from "ember"; -import { deprecate } from '@ember/debug'; /** Ember Data @@ -22,7 +21,6 @@ import { BuildURLMixin, belongsTo, hasMany, - global, Errors, RootState, Model, @@ -145,18 +143,4 @@ Object.defineProperty(DS, 'normalizeModelName', { value: normalizeModelName }); -Object.defineProperty(global, 'DS', { - configurable: true, - get() { - deprecate( - 'Using the global version of DS is deprecated. Please either import ' + - 'the specific modules needed or `import DS from \'ember-data\';`.', - false, - { id: 'ember-data.global-ds', until: '3.0.0' } - ); - - return DS; - } -}); - export default DS; From bbe8b41a06f648f2cb467c2a7d4b04a8f0d11dee Mon Sep 17 00:00:00 2001 From: Wesley Workman Date: Thu, 17 Aug 2017 19:42:00 -0400 Subject: [PATCH 2111/2527] Added failing test for #5136. --- tests/integration/records/unload-test.js | 46 ++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 99bb0e83215..7568ea66cdb 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -765,3 +765,49 @@ test('after unloading a record, the record can be saved again immediately', func store.createRecord('person').save(); }); }); + +test('after unloading a record, pushing a new copy will setup relatioonships', function (assert) { + const store = env.store; + const personData = { + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + } + } + }; + const carData = { + data: { + type: 'car', + id: '10', + attributes: { + make: 'VW', + model: 'Beetle' + }, + relationships: { + person: { + data: { type: 'person', id: '1' } + } + } + } + }; + + function pushCar() { + store.push(Ember.copy(carData, true)); + } + + Ember.run(() => { store.push(personData) }); + + let adam = env.store.peekRecord('person', 1); + assert.equal(adam.get('cars.length'), 0, 'cars hasMany starts off empty'); + + Ember.run(() => pushCar()); + assert.equal(adam.get('cars.length'), 1, 'pushing car setups inverse relationship'); + + Ember.run(() => adam.get('cars.firstObject').unloadRecord()); + assert.equal(adam.get('cars.length'), 0, 'unloading car cleaned up hasMany'); + + Ember.run(() => pushCar()); + assert.equal(adam.get('cars.length'), 1, 'pushing car again setups inverse relationship'); +}); From 6e8a23656cb073596cd951bdab9ca0541d1bcbe3 Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Tue, 5 Dec 2017 08:06:28 -0800 Subject: [PATCH 2112/2527] Restore 2.12 semantics for sync unloadRecord A number of use cases rely on unloadRecord's 2.12 behaviour of treating unloadRecord as a client-side delete on the inverse side of a sync relationship. This pr restores that functionality, while retaining the invalidate+refetch functionality for async relationships. This behaviour is codified in a number of tests within tests/integration/records/unload-test.js Fix #5136, #5137 --- addon/-private/system/model/internal-model.js | 26 +- .../system/relationships/state/belongs-to.js | 19 + .../system/relationships/state/has-many.js | 61 +- .../relationships/state/relationship.js | 110 +- .../integration/records/rematerialize-test.js | 2 +- tests/integration/records/unload-test.js | 1301 ++++++++++++++++- .../relationships/many-to-many-test.js | 2 +- 7 files changed, 1436 insertions(+), 85 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 6c5d896dccb..d9ccb8f8e2f 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -62,12 +62,24 @@ function areAllModelsUnloaded(internalModels) { return true; } +// Handle dematerialization for relationship `rel`. In all cases, notify the +// relatinoship of the dematerialization: this is done so the relationship can +// notify its inverse which needs to update state +// +// If the inverse is sync, unloading this record is treated as a client-side +// delete, so we remove the inverse records from this relationship to +// disconnect the graph. Because it's not async, we don't need to keep around +// the internalModel as an id-wrapper for references and because the graph is +// disconnected we can actually destroy the internalModel when checking for +// orphaned models. function destroyRelationship(rel) { - if (rel._inverseIsAsync()) { - rel.removeInternalModelFromInverse(rel.inverseInternalModel); - rel.removeInverseRelationships(); - } else { - rel.removeCompletelyFromInverse(); + rel.internalModelDidDematerialize(); + + if (rel._inverseIsSync()) { + // disconnect the graph so that the sync inverse relationship does not + // prevent us from cleaning up during `_cleanupOrphanedInternalModels` + rel.removeAllInternalModelsFromOwn(); + rel.removeAllCanonicalInternalModelsFromOwn(); } } // this (and all heimdall instrumentation) will be stripped by a babel transform @@ -432,6 +444,7 @@ export default class InternalModel { */ _directlyRelatedInternalModels() { let array = []; + this._relationships.forEach((name, rel) => { array = array.concat(rel.members.list, rel.canonicalMembers.list); }); @@ -923,10 +936,7 @@ export default class InternalModel { this.__implicitRelationships = null; Object.keys(implicitRelationships).forEach((key) => { let rel = implicitRelationships[key]; - destroyRelationship(rel); - - rel.destroy(); }); } diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 82a4d968856..ea3bda37abe 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -58,6 +58,7 @@ export default class BelongsToRelationship extends Relationship { } inverseDidDematerialize() { + super.inverseDidDematerialize(this.inverseInternalModel); this.notifyBelongsToChanged(); } @@ -74,6 +75,13 @@ export default class BelongsToRelationship extends Relationship { } } + + removeCompletelyFromInverse() { + super.removeCompletelyFromInverse(); + + this.inverseInternalModel = null; + } + flushCanonical() { //temporary fix to not remove newly created records if server returned null. //TODO remove once we have proper diffing @@ -115,6 +123,12 @@ export default class BelongsToRelationship extends Relationship { this.notifyBelongsToChanged(); } + removeAllInternalModelsFromOwn() { + super.removeAllInternalModelsFromOwn(); + this.inverseInternalModel = null; + this.notifyBelongsToChanged(); + } + notifyBelongsToChanged() { this.internalModel.notifyBelongsToChanged(this.key); } @@ -125,6 +139,11 @@ export default class BelongsToRelationship extends Relationship { super.removeCanonicalInternalModelFromOwn(internalModel); } + removeAllCanonicalInternalModelsFromOwn() { + super.removeAllCanonicalInternalModelsFromOwn(); + this.canonicalState = null; + } + findRecord() { if (this.inverseInternalModel) { return this.store._findByInternalModel(this.inverseInternalModel); diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 2062e8ba11c..962a58ffbeb 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -11,7 +11,12 @@ export default class ManyRelationship extends Relationship { this.belongsToType = relationshipMeta.type; this.canonicalState = []; this.isPolymorphic = relationshipMeta.options.polymorphic; + // The ManyArray for this relationship this._manyArray = null; + // The previous ManyArray for this relationship. It will be destroyed when + // we create a new many array, but in the interim it will be updated if + // inverse internal models are unloaded. + this._retainedManyArray = null; this.__loadingPromise = null; } @@ -33,6 +38,8 @@ export default class ManyRelationship extends Relationship { } get manyArray() { + assert(`Error: relationship ${this.parentType}:${this.key} has both many array and retained many array`, this._manyArray === null || this._retainedManyArray === null); + if (!this._manyArray) { this._manyArray = ManyArray.create({ canonicalState: this.canonicalState, @@ -43,7 +50,13 @@ export default class ManyRelationship extends Relationship { meta: this.meta, isPolymorphic: this.isPolymorphic }); + + if (this._retainedManyArray !== null) { + this._retainedManyArray.destroy(); + this._retainedManyArray = null; + } } + return this._manyArray; } @@ -78,10 +91,14 @@ export default class ManyRelationship extends Relationship { super.addCanonicalInternalModel(internalModel, idx); } - inverseDidDematerialize() { - if (this._manyArray) { - this._manyArray.destroy(); - this._manyArray = null; + inverseDidDematerialize(inverseInternalModel) { + super.inverseDidDematerialize(inverseInternalModel); + if (this.isAsync) { + if (this._manyArray) { + this._retainedManyArray = this._manyArray; + this._manyArray = null; + } + this._removeInternalModelFromManyArray(this._retainedManyArray, inverseInternalModel); } this.notifyHasManyChanged(); } @@ -111,6 +128,12 @@ export default class ManyRelationship extends Relationship { super.removeCanonicalInternalModelFromOwn(internalModel, idx); } + removeAllCanonicalInternalModelsFromOwn() { + super.removeAllCanonicalInternalModelsFromOwn(); + this.canonicalMembers.clear(); + this.canonicalState.splice(0, this.canonicalState.length); + } + removeCompletelyFromOwn(internalModel) { super.removeCompletelyFromOwn(internalModel); @@ -143,7 +166,33 @@ export default class ManyRelationship extends Relationship { return; } super.removeInternalModelFromOwn(internalModel, idx); - let manyArray = this.manyArray; + // note that ensuring the many array is created, via `this.manyArray` + // (instead of `this._manyArray`) is intentional. + // + // Because we're removing from local, and not canonical, state, it is + // important that the many array is initialized now with those changes, + // otherwise it will be initialized with canonical state and we'll have + // lost the fact that this internalModel was removed. + this._removeInternalModelFromManyArray(this.manyArray, internalModel, idx); + this._removeInternalModelFromManyArray(this._retainedManyArray, internalModel, idx); + } + + removeAllInternalModelsFromOwn() { + super.removeAllInternalModelsFromOwn(); + // as with removeInternalModelFromOwn, we make sure the many array is + // instantiated, or we'll lose local removals, as we're not updating + // canonical state here. + this.manyArray.clear(); + if (this._retainedManyArray) { + this._retainedManyArray.clear(); + } + } + + _removeInternalModelFromManyArray(manyArray, internalModel, idx) { + if (manyArray === null) { + return; + } + if (idx !== undefined) { //TODO(Igor) not used currently, fix manyArray.currentState.removeAt(idx); @@ -292,12 +341,14 @@ export default class ManyRelationship extends Relationship { let manyArray = this._manyArray; if (manyArray) { manyArray.destroy(); + this._manyArray = null; } let proxy = this.__loadingPromise; if (proxy) { proxy.destroy(); + this.__loadingPromise = null; } } } diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 90ce273b424..5891d8ed8b3 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -1,5 +1,6 @@ /* global heimdall */ import { guidFor } from '@ember/object/internals'; +import { get } from '@ember/object'; import { assert, warn } from '@ember/debug'; import OrderedSet from '../../ordered-set'; @@ -76,35 +77,67 @@ export default class Relationship { this.meta = null; this.hasData = false; this.hasLoaded = false; + this.__inverseMeta = undefined; } - get parentType() { - return this.internalModel.modelName; + _inverseIsAsync() { + let inverseMeta = this._inverseMeta; + if (!inverseMeta) { + return false; + } + + let inverseAsync = inverseMeta.options.async; + return typeof inverseAsync === 'undefined' ? true : inverseAsync; } - _inverseIsAsync() { - if (!this.inverseKey || !this.inverseInternalModel) { + _inverseIsSync() { + let inverseMeta = this._inverseMeta; + if (!inverseMeta) { return false; } - return this.inverseInternalModel._relationships.get(this.inverseKey).isAsync; + + let inverseAsync = inverseMeta.options.async; + return typeof inverseAsync === 'undefined' ? false : !inverseAsync; } - removeInverseRelationships() { - if (!this.inverseKey) { return; } + get _inverseMeta() { + if (this.__inverseMeta === undefined) { + let inverseMeta = null; - let allMembers = - // we actually want a union of members and canonicalMembers - // they should be disjoint but currently are not due to a bug - this.members.list.concat(this.canonicalMembers.list); + if (this.inverseKey) { + let inverseModelClass = this.store.modelFor(this.relationshipMeta.type); + let inverseRelationships = get(inverseModelClass, 'relationshipsByName'); + inverseMeta = inverseRelationships.get(this.inverseKey); + } - for (let i = 0; i < allMembers.length; i++) { - let inverseInternalModel = allMembers[i]; - let relationship = inverseInternalModel._relationships.get(this.inverseKey); - relationship.inverseDidDematerialize(); + this.__inverseMeta = inverseMeta; } + + return this.__inverseMeta; + } + + get parentType() { + return this.internalModel.modelName; + } + + internalModelDidDematerialize() { + if (!this.inverseKey) { return; } + + this.forAllMembers((inverseInternalModel) => { + let relationship = inverseInternalModel._relationships.get(this.inverseKey); + relationship.inverseDidDematerialize(this.internalModel); + }); } - inverseDidDematerialize() {} + inverseDidDematerialize(inverseInternalModel) { + if (!this.isAsync) { + // unloading inverse of a sync relationship is treated as a client-side + // delete, so actually remove the models don't merely invalidate the cp + // cache. + this.removeInternalModelFromOwn(inverseInternalModel); + this.removeCanonicalInternalModelFromOwn(inverseInternalModel); + } + } updateMeta(meta) { heimdall.increment(updateMeta); @@ -127,6 +160,16 @@ export default class Relationship { } } + removeAllInternalModelsFromOwn() { + this.members.clear(); + this.internalModel.updateRecordArrays(); + } + + removeAllCanonicalInternalModelsFromOwn() { + this.canonicalMembers.clear(); + this.flushCanonicalLater(); + } + removeInternalModels(internalModels) { heimdall.increment(removeInternalModels); internalModels.forEach((internalModel) => this.removeInternalModel(internalModel)); @@ -181,7 +224,7 @@ export default class Relationship { let relationship = relationships[this.inverseKeyForImplicit]; if (!relationship) { relationship = relationships[this.inverseKeyForImplicit] = - new Relationship(this.store, internalModel, this.key, { options: { async: this.isAsync } }); + new Relationship(this.store, internalModel, this.key, { options: { async: this.isAsync }, type: this.parentType }); } relationship.addCanonicalInternalModel(this.internalModel); } @@ -222,7 +265,12 @@ export default class Relationship { internalModel._relationships.get(this.inverseKey).addInternalModel(this.internalModel); } else { if (!internalModel._implicitRelationships[this.inverseKeyForImplicit]) { - internalModel._implicitRelationships[this.inverseKeyForImplicit] = new Relationship(this.store, internalModel, this.key, { options: { async: this.isAsync } }); + internalModel._implicitRelationships[this.inverseKeyForImplicit] = new Relationship( + this.store, + internalModel, + this.key, + { options: { async: this.isAsync }, type: this.parentType } + ); } internalModel._implicitRelationships[this.inverseKeyForImplicit].addInternalModel(this.internalModel); } @@ -303,6 +351,32 @@ export default class Relationship { this.members.forEach(unload); this.canonicalMembers.forEach(unload); + + if (!this.isAsync) { + this.clear(); + } + } + + forAllMembers(callback) { + let seen = Object.create(null); + + for (let i = 0; i < this.members.list.length; i++) { + const inverseInternalModel = this.members.list[i]; + const id = guidFor(inverseInternalModel); + if (!seen[id]) { + seen[id] = true; + callback(inverseInternalModel); + } + } + + for (let i = 0; i < this.canonicalMembers.list.length; i++) { + const inverseInternalModel = this.canonicalMembers.list[i]; + const id = guidFor(inverseInternalModel); + if (!seen[id]) { + seen[id] = true; + callback(inverseInternalModel); + } + } } /* diff --git a/tests/integration/records/rematerialize-test.js b/tests/integration/records/rematerialize-test.js index 0e7917043b6..416e299f24c 100644 --- a/tests/integration/records/rematerialize-test.js +++ b/tests/integration/records/rematerialize-test.js @@ -110,7 +110,7 @@ test("a sync belongs to relationship to an unloaded record can restore that reco run(() => person.unloadRecord()); assert.equal(env.store.hasRecordForId('person', 1), false, 'The person is unloaded'); - assert.equal(env.store._internalModelsFor('person').has(1), true, 'The person internalModel is retained'); + assert.equal(env.store._internalModelsFor('person').has(1), false, 'The person internalModel is freed'); run(() => { env.store.push({ diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 7568ea66cdb..3afc287f901 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -17,12 +17,43 @@ let env; let Person = DS.Model.extend({ name: attr('string'), + // 1:many sync cars: hasMany('car', { async: false }), + // 1:many async boats: hasMany('boat', { async: true }), - bike: belongsTo('boat', { async: false, inverse: null }) + // many:many sync + groups: hasMany('group', { async: false }), + // many:many async + friends: hasMany('people', { async: true }), + // 1:1 sync inverse null + bike: belongsTo('bike', { async: false, inverse: null }), + // 1:1 sync + house: belongsTo('house', { async: false }), + // 1:1 async + mortgage: belongsTo('mortgage', { async: true }), + // 1 async : 1 sync + favoriteBook: belongsTo('book', { async: false }), + // 1 async : many sync + favoriteSpoons: hasMany('spoon', { async: false }), + // 1 sync: many async + favoriteShows: hasMany('show', { async: true }), + // many sync : many async + favoriteFriends: hasMany('people', { async: true, inverse: 'favoriteAsyncFriends' }), + // many async : many sync + favoriteAsyncFriends: hasMany('people', { async: false, inverse: 'favoriteFriends' }) }); Person.reopenClass({ toString() { return 'Person'; } }); +let House = DS.Model.extend({ + person: belongsTo('person', { async: false }) +}); +House.reopenClass({ toString() { return 'House'; } }); + +let Mortgage = DS.Model.extend({ + person: belongsTo('person', { async: true }) +}); +Mortgage.reopenClass({ toString() { return 'Mortgage'; } }); + let Group = DS.Model.extend({ people: hasMany('person', { async: false }) }); @@ -37,7 +68,7 @@ Car.reopenClass({ toString() { return 'Car'; } }); let Boat = DS.Model.extend({ name: attr('string'), - person: belongsTo('person', { async: false }) + person: belongsTo('person', { async: true }) }); Boat.toString = function() { return 'Boat'; }; @@ -46,6 +77,21 @@ let Bike = DS.Model.extend({ }); Bike.toString = function() { return 'Bike'; }; +let Book = DS.Model.extend({ + person: belongsTo('person', { async: true }) +}); +Book.toString = function() { return 'Book'; }; + +let Spoon = DS.Model.extend({ + person: belongsTo('person', { async: true }) +}); +Spoon.toString = function() { return 'Spoon'; }; + +let Show = DS.Model.extend({ + person: belongsTo('person', { async: false }) +}); +Show.toString = function() { return 'Show'; }; + module("integration/unload - Unloading Records", { beforeEach() { env = setupStore({ @@ -53,8 +99,13 @@ module("integration/unload - Unloading Records", { person: Person, car: Car, group: Group, + house: House, + mortgage: Mortgage, boat: Boat, - bike: Bike + bike: Bike, + book: Book, + spoon: Spoon, + show: Show }); }, @@ -325,10 +376,10 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu name: 'Could be Anybody' }, relationships: { - cars: { + boats: { data: [ - { type: 'car', id: '1' }, - { type: 'car', id: '2' } + { type: 'boat', id: '1' }, + { type: 'boat', id: '2' } ] } } @@ -339,11 +390,10 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu run(() => { env.store.push({ data: { - type: 'car', + type: 'boat', id: '1', attributes: { - make: 'Nissan', - model: 'Altima' + name: 'Boaty McBoatface' }, relationships: { person: { @@ -357,11 +407,10 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu run(() => { env.store.push({ data: { - type: 'car', + type: 'boat', id: '2', attributes: { - make: 'Tesla', - model: 'S' + name: 'The jackson' }, relationships: { person: { @@ -378,17 +427,17 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu 'one person record is loaded' ); assert.equal( - env.store._internalModelsFor('car').models.length, + env.store._internalModelsFor('boat').models.length, 2, - 'two car records are loaded' + 'two boat records are loaded' ); assert.equal(env.store.hasRecordForId('person', 1), true); - assert.equal(env.store.hasRecordForId('car', 1), true); - assert.equal(env.store.hasRecordForId('car', 2), true); + assert.equal(env.store.hasRecordForId('boat', 1), true); + assert.equal(env.store.hasRecordForId('boat', 2), true); let relPayloads = env.store._relationshipsPayloads; - assert.equal(relPayloads.get('person', 1, 'cars').data.length, 2, 'person - cars relationship payload loaded'); + assert.equal(relPayloads.get('person', 1, 'boats').data.length, 2, 'person - boats relationship payload loaded'); let checkOrphanCalls = 0; let cleanupOrphanCalls = 0; @@ -408,25 +457,25 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu }; } countOrphanCalls(env.store.peekRecord('person', 1)); - countOrphanCalls(env.store.peekRecord('car', 1)); - countOrphanCalls(env.store.peekRecord('car', 2)); + countOrphanCalls(env.store.peekRecord('boat', 1)); + countOrphanCalls(env.store.peekRecord('boat', 2)); // make sure relationships are initialized - env.store.peekRecord('person', 1).get('cars'); - - run(() => { - env.store.peekRecord('person', 1).unloadRecord(); - env.store.peekRecord('car', 1).unloadRecord(); - env.store.peekRecord('car', 2).unloadRecord(); - }); + return env.store.peekRecord('person', 1).get('boats').then(() => { + run(() => { + env.store.peekRecord('person', 1).unloadRecord(); + env.store.peekRecord('boat', 1).unloadRecord(); + env.store.peekRecord('boat', 2).unloadRecord(); + }); - assert.equal(env.store._internalModelsFor('person').models.length, 0); - assert.equal(env.store._internalModelsFor('car').models.length, 0); + assert.equal(env.store._internalModelsFor('person').models.length, 0); + assert.equal(env.store._internalModelsFor('boat').models.length, 0); - assert.equal(checkOrphanCalls, 3, 'each internalModel checks for cleanup'); - assert.equal(cleanupOrphanCalls, 1, 'cleanup only happens once'); + assert.equal(checkOrphanCalls, 3, 'each internalModel checks for cleanup'); + assert.equal(cleanupOrphanCalls, 1, 'cleanup only happens once'); - assert.equal(relPayloads.get('person', 1, 'cars'), null, 'person - cars relationship payload unloaded'); + assert.equal(relPayloads.get('person', 1, 'boats'), null, 'person - boats relationship payload unloaded'); + }); }); @@ -766,7 +815,7 @@ test('after unloading a record, the record can be saved again immediately', func }); }); -test('after unloading a record, pushing a new copy will setup relatioonships', function (assert) { +test('after unloading a record, pushing a new copy will setup relationships', function (assert) { const store = env.store; const personData = { data: { @@ -777,37 +826,1185 @@ test('after unloading a record, pushing a new copy will setup relatioonships', f } } }; - const carData = { - data: { - type: 'car', - id: '10', - attributes: { - make: 'VW', - model: 'Beetle' - }, - relationships: { - person: { - data: { type: 'person', id: '1' } - } - } - } - }; function pushCar() { - store.push(Ember.copy(carData, true)); + store.push({ + data: { + type: 'car', + id: '10', + attributes: { + make: 'VW', + model: 'Beetle' + }, + relationships: { + person: { + data: { type: 'person', id: '1' } + } + } + } + }); } - Ember.run(() => { store.push(personData) }); + run(() => { store.push(personData) }); let adam = env.store.peekRecord('person', 1); assert.equal(adam.get('cars.length'), 0, 'cars hasMany starts off empty'); - Ember.run(() => pushCar()); + run(() => pushCar()); assert.equal(adam.get('cars.length'), 1, 'pushing car setups inverse relationship'); - Ember.run(() => adam.get('cars.firstObject').unloadRecord()); + run(() => adam.get('cars.firstObject').unloadRecord()); assert.equal(adam.get('cars.length'), 0, 'unloading car cleaned up hasMany'); - Ember.run(() => pushCar()); + run(() => pushCar()); assert.equal(adam.get('cars.length'), 1, 'pushing car again setups inverse relationship'); }); + +test('1:1 sync unload', function (assert) { + run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + house: { + data: { + id: 2, + type: 'house' + } + } + } + }, + included: [{ + id: 2, + type: 'house' + }] + }) + ); + + let person = env.store.peekRecord('person', 1); + let house = env.store.peekRecord('house', 2); + + assert.equal(person.get('house.id'), 2, 'initially relationship established lhs'); + assert.equal(house.get('person.id'), 1, 'initially relationship established rhs'); + + run(() => house.unloadRecord()); + + + assert.equal(person.get('house'), null, 'unloading acts as a delete for sync relationships'); + assert.equal(env.store.hasRecordForId('house', 2), false, 'unloaded record gone from store'); + + house = run(() => + env.store.push({ + data: { + id: 2, + type: 'house' + } + }) + ); + + assert.equal(env.store.hasRecordForId('house', 2), true, 'unloaded record can be restored'); + assert.equal(person.get('house'), null, 'restoring unloaded record does not restore relationship'); + assert.equal(house.get('person'), null, 'restoring unloaded record does not restore relationship'); + + run(() => + env.store.push({ + data: { + id: 2, + type: 'house', + relationships: { + person: { + data: { + id: 1, + type: 'person' + } + } + } + } + }) + ); + + assert.equal(person.get('house.id'), 2, 'after unloading, relationship can be restored'); + assert.equal(house.get('person.id'), 1, 'after unloading, relationship can be restored'); +}); + +test('1:many sync unload 1 side', function (assert) { + run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + cars: { + data: [{ + id: 2, + type: 'car' + }, { + id: 3, + type: 'car' + }] + } + } + }, + included: [{ + id: 2, + type: 'car' + }, { + id: 3, + type: 'car' + }] + }) + ); + + let person = env.store.peekRecord('person', 1); + let car2 = env.store.peekRecord('car', 2); + let car3 = env.store.peekRecord('car', 3); + let cars = person.get('cars'); + + assert.equal(cars.isDestroyed, false, 'ManyArray not destroyed'); + assert.deepEqual(person.get('cars').mapBy('id'), ['2', '3'], 'initialy relationship established lhs'); + assert.equal(car2.get('person.id'), 1, 'initially relationship established rhs'); + assert.equal(car3.get('person.id'), 1, 'initially relationship established rhs'); + + run(() => person.unloadRecord()); + + assert.equal(env.store.hasRecordForId('person', 1), false, 'unloaded record gone from store'); + + assert.equal(car2.get('person'), null, 'unloading acts as delete for sync relationships'); + assert.equal(car3.get('person'), null, 'unloading acts as delete for sync relationships'); + assert.equal(cars.isDestroyed, true, 'ManyArray destroyed'); + + person = run(() => + env.store.push({ + data: { + id: 1, + type: 'person' + } + }) + ); + + assert.equal(env.store.hasRecordForId('person', 1), true, 'unloaded record can be restored'); + assert.deepEqual(person.get('cars').mapBy('id'), [], 'restoring unloaded record does not restore relationship'); + assert.equal(car2.get('person'), null, 'restoring unloaded record does not restore relationship'); + assert.equal(car3.get('person'), null, 'restoring unloaded record does not restore relationship'); + + run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + cars: { + data: [{ + id: 2, + type: 'car' + }, { + id: 3, + type: 'car' + }] + } + } + } + }) + ); + + assert.equal(car2.get('person.id'), '1', 'after unloading, relationship can be restored'); + assert.equal(car3.get('person.id'), '1', 'after unloading, relationship can be restored'); + assert.deepEqual(person.get('cars').mapBy('id'), ['2', '3'], 'after unloading, relationship can be restored'); +}); + +test('1:many sync unload many side', function (assert) { + run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + cars: { + data: [{ + id: 2, + type: 'car' + }, { + id: 3, + type: 'car' + }] + } + } + }, + included: [{ + id: 2, + type: 'car' + }, { + id: 3, + type: 'car' + }] + }) + ); + + let person = env.store.peekRecord('person', 1); + let car2 = env.store.peekRecord('car', 2); + let car3 = env.store.peekRecord('car', 3); + let cars = person.get('cars'); + + assert.equal(cars.isDestroyed, false, 'ManyArray not destroyed'); + assert.deepEqual(person.get('cars').mapBy('id'), ['2', '3'], 'initialy relationship established lhs'); + assert.equal(car2.get('person.id'), 1, 'initially relationship established rhs'); + assert.equal(car3.get('person.id'), 1, 'initially relationship established rhs'); + + run(() => car2.unloadRecord()); + + assert.equal(env.store.hasRecordForId('car', 2), false, 'unloaded record gone from store'); + + assert.equal(cars.isDestroyed, false, 'ManyArray not destroyed'); + assert.deepEqual(person.get('cars').mapBy('id'), ['3'], 'unload sync relationship acts as delete'); + assert.equal(car3.get('person.id'), '1', 'unloading one of a sync hasMany does not affect the rest'); + + car2 = run(() => + env.store.push({ + data: { + id: 2, + type: 'car' + } + }) + ); + + assert.equal(env.store.hasRecordForId('car', 2), true, 'unloaded record can be restored'); + assert.deepEqual(person.get('cars').mapBy('id'), ['3'], 'restoring unloaded record does not restore relationship'); + assert.equal(car2.get('person'), null, 'restoring unloaded record does not restore relationship'); + + run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + cars: { + data: [{ + id: 2, + type: 'car' + }, { + id: 3, + type: 'car' + }] + } + } + } + }) + ); + + assert.equal(car2.get('person.id'), '1', 'after unloading, relationship can be restored'); + assert.deepEqual(person.get('cars').mapBy('id'), ['2', '3'], 'after unloading, relationship can be restored'); +}); + +test('many:many sync unload', function (assert) { + run(() => + env.store.push({ + data: [{ + id: 1, + type: 'person', + relationships: { + groups: { + data: [{ + id: 3, + type: 'group' + }, { + id: 4, + type: 'group' + }] + } + } + }, { + id: 2, + type: 'person', + relationships: { + groups: { + data: [{ + id: 3, + type: 'group' + }, { + id: 4, + type: 'group' + }] + } + } + }], + included: [{ + id: 3, + type: 'group' + }, { + id: 4, + type: 'group' + }] + }) + ); + + let person1 = env.store.peekRecord('person', 1); + let person2 = env.store.peekRecord('person', 2); + let group3 = env.store.peekRecord('group', 3); + let group4 = env.store.peekRecord('group', 4); + let p2groups = person2.get('groups'); + let g3people = group3.get('people'); + + assert.deepEqual(person1.get('groups').mapBy('id'), ['3', '4'], 'initially established relationship lhs'); + assert.deepEqual(person2.get('groups').mapBy('id'), ['3', '4'], 'initially established relationship lhs'); + assert.deepEqual(group3.get('people').mapBy('id'), ['1', '2'], 'initially established relationship lhs'); + assert.deepEqual(group4.get('people').mapBy('id'), ['1', '2'], 'initially established relationship lhs'); + + assert.equal(p2groups.isDestroyed, false, 'groups is not destroyed'); + assert.equal(g3people.isDestroyed, false, 'people is not destroyed'); + + run(() => person2.unloadRecord()); + + assert.equal(p2groups.isDestroyed, true, 'groups (unloaded side) is destroyed'); + assert.equal(g3people.isDestroyed, false, 'people (inverse) is not destroyed'); + + assert.deepEqual(person1.get('groups').mapBy('id'), ['3', '4'], 'unloaded record in many:many does not affect inverse of inverse'); + assert.deepEqual(group3.get('people').mapBy('id'), ['1'], 'unloading acts as delete for sync relationships'); + assert.deepEqual(group4.get('people').mapBy('id'), ['1'], 'unloading acts as delete for sync relationships'); + + assert.equal(env.store.hasRecordForId('person', 2), false, 'unloading removes record from store'); + + person2 = run(() => + env.store.push({ + data: { + id: 2, + type: 'person' + } + }) + ); + + assert.equal(env.store.hasRecordForId('person', 2), true, 'unloaded record can be restored'); + assert.deepEqual(person2.get('groups').mapBy('id'), [], 'restoring unloaded record does not restore relationship'); + assert.deepEqual(group3.get('people').mapBy('id'), ['1'], 'restoring unloaded record does not restore relationship'); + assert.deepEqual(group4.get('people').mapBy('id'), ['1'], 'restoring unloaded record does not restore relationship'); + + run(() => + env.store.push({ + data: { + id: 2, + type: 'person', + relationships: { + groups: { + data: [{ + id: 3, + type: 'group' + }, { + id: 4, + type: 'group' + }] + } + } + } + }) + ); + + assert.deepEqual(person2.get('groups').mapBy('id'), ['3', '4'], 'after unloading, relationship can be restored'); + assert.deepEqual(group3.get('people').mapBy('id'), ['1', '2'], 'after unloading, relationship can be restored'); + assert.deepEqual(group4.get('people').mapBy('id'), ['1', '2'], 'after unloading, relationship can be restored'); +}); + +test('1:1 async unload', function (assert) { + let findRecordCalls = 0; + + env.adapter.findRecord = (store, type, id) => { + assert.equal(type, Mortgage, 'findRecord(_, type) is correct'); + assert.equal(id, '2', 'findRecord(_, _, id) is correct'); + ++findRecordCalls; + + return { + data: { + id: 2, + type: 'mortgage' + } + }; + }; + + let person = run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + mortgage: { + data: { + id: 2, + type: 'mortgage' + } + } + } + } + }) + ); + let mortgage; + + return run(() => + person.get('mortgage').then((asyncRecord) => { + mortgage = asyncRecord; + return mortgage.get('person'); + }).then(() => { + assert.equal(mortgage.belongsTo('person').id(), '1', 'initially relationship established lhs'); + assert.equal(person.belongsTo('mortgage').id(), '2', 'initially relationship established rhs'); + + run(() => mortgage.unloadRecord()); + + assert.equal(person.belongsTo('mortgage').id(), '2', 'unload async is not treated as delete'); + + return person.get('mortgage'); + }).then((refetchedMortgage) => { + assert.notEqual(mortgage, refetchedMortgage, 'the previously loaded record is not reused'); + + assert.equal(person.belongsTo('mortgage').id(), '2', 'unload async is not treated as delete'); + assert.equal(refetchedMortgage.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal(findRecordCalls, 2); + }) + ); +}); + +test('1:many async unload 1 side', function (assert) { + let findRecordCalls = 0; + let findManyCalls = 0; + + env.adapter.coalesceFindRequests = true; + + env.adapter.findRecord = (store, type, id) => { + assert.equal(type, Person, 'findRecord(_, type) is correct'); + assert.deepEqual(id, '1', 'findRecord(_, _, id) is correct'); + ++findRecordCalls; + + return { + data: { + id: 1, + type: 'person' + } + }; + }; + + env.adapter.findMany = (store, type, ids) => { + assert.equal(type+'', Boat+'', 'findMany(_, type) is correct'); + assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); + ++findManyCalls; + + return { + data: [{ + id: 2, + type: 'boat' + }, { + id: 3, + type: 'boat' + }] + }; + }; + + let person = run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + boats: { + data: [{ + id: 2, + type: 'boat' + }, { + id: 3, + type: 'boat' + }] + } + } + } + }) + ); + let boats, boat2, boat3; + + return run(() => + person.get('boats').then((asyncRecords) => { + boats = asyncRecords; + [boat2, boat3] = boats.toArray(); + return EmberPromise.all([boat2, boat3].map(b => b.get('person'))); + }).then(() => { + assert.deepEqual(person.hasMany('boats').ids(), ['2', '3'], 'initially relationship established lhs'); + assert.equal(boat2.belongsTo('person').id(), '1', 'initially relationship established rhs'); + assert.equal(boat3.belongsTo('person').id(), '1', 'initially relationship established rhs'); + + assert.equal(boats.isDestroyed, false, 'ManyArray is not destroyed'); + + run(() => person.unloadRecord()); + + assert.equal(boats.isDestroyed, false, 'ManyArray is not destroyed when 1 side is unloaded'); + assert.equal(boat2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + + return boat2.get('person'); + }).then((refetchedPerson) => { + assert.notEqual(person, refetchedPerson, 'the previously loaded record is not reused'); + + assert.deepEqual(person.hasMany('boats').ids(), ['2', '3'], 'unload async is not treated as delete'); + assert.equal(boat2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + + assert.equal(findManyCalls, 1, 'findMany called as expected'); + assert.equal(findRecordCalls, 1, 'findRecord called as expected'); + }) + ); +}); + +test('1:many async unload many side', function (assert) { + let findManyCalls = 0; + + env.adapter.coalesceFindRequests = true; + + env.adapter.findMany = (store, type, ids) => { + assert.equal(type+'', Boat+'', 'findMany(_, type) is correct'); + assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); + ++findManyCalls; + + return { + data: [{ + id: 2, + type: 'boat' + }, { + id: 3, + type: 'boat' + }] + }; + }; + + let person = run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + boats: { + data: [{ + id: 2, + type: 'boat' + }, { + id: 3, + type: 'boat' + }] + } + } + } + }) + ); + let boats, boat2, boat3; + + return run(() => + person.get('boats').then((asyncRecords) => { + boats = asyncRecords; + [boat2, boat3] = boats.toArray(); + return EmberPromise.all([boat2, boat3].map(b => b.get('person'))); + }).then(() => { + assert.deepEqual(person.hasMany('boats').ids(), ['2', '3'], 'initially relationship established lhs'); + assert.equal(boat2.belongsTo('person').id(), '1', 'initially relationship established rhs'); + assert.equal(boat3.belongsTo('person').id(), '1', 'initially relationship established rhs'); + + assert.deepEqual(boats.mapBy('id'), ['2', '3'], 'many array is initially set up correctly'); + run(() => boat2.unloadRecord()); + assert.deepEqual(boats.mapBy('id'), ['3'], 'unload async removes from previous many array'); + assert.equal(boats.isDestroyed, false, 'previous ManyArray not destroyed'); + + run(() => boat3.unloadRecord()); + assert.deepEqual(boats.mapBy('id'), [], 'unload async removes from previous many array'); + assert.equal(boats.isDestroyed, false, 'previous ManyArray not destroyed'); + + assert.deepEqual(person.hasMany('boats').ids(), ['2', '3'], 'unload async is not treated as delete'); + assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + + return person.get('boats'); + }).then((refetchedBoats) => { + assert.equal(boats.isDestroyed, false, 'previous ManyArray is not immediately destroyed after refetch'); + assert.equal(boats.isDestroying, true, 'previous ManyArray is being destroyed immediately after refetch'); + assert.deepEqual(refetchedBoats.mapBy('id'), ['2', '3'], 'boats refetched'); + assert.deepEqual(person.hasMany('boats').ids(), ['2', '3'], 'unload async is not treated as delete'); + assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + + assert.equal(findManyCalls, 2, 'findMany called as expected'); + }) + ).then(() => { + assert.equal(boats.isDestroyed, true, 'previous ManyArray is destroyed in the runloop after refetching'); + }); +}); + +test('many:many async unload', function (assert) { + let findManyCalls = 0; + + env.adapter.coalesceFindRequests = true; + + env.adapter.findMany = (store, type, ids) => { + assert.equal(type+'', Person+'', 'findMany(_, type) is correct'); + assert.deepEqual(ids, ['3', '4'], 'findMany(_, _, ids) is correct'); + ++findManyCalls; + + return { + data: [{ + id: 3, + type: 'person' + }, { + id: 4, + type: 'person' + }] + }; + }; + + let [person1, person2] = run(() => + env.store.push({ + data: [{ + id: 1, + type: 'person', + relationships: { + friends: { + data: [{ + id: 3, + type: 'person' + }, { + id: 4, + type: 'person' + }] + } + } + }, { + id: 2, + type: 'person', + relationships: { + friends: { + data: [{ + id: 3, + type: 'person' + }, { + id: 4, + type: 'person' + }] + } + } + }] + }) + ); + + let person1Friends, person3, person4; + + return run(() => + person1.get('friends').then((asyncRecords) => { + person1Friends = asyncRecords; + [person3, person4] = person1Friends.toArray(); + return EmberPromise.all([person2, person3, person4].map(b => b.get('friends'))); + }).then(() => { + assert.deepEqual(person1.hasMany('friends').ids(), ['3', '4'], 'initially relationship established lhs'); + assert.deepEqual(person2.hasMany('friends').ids(), ['3', '4'], 'initially relationship established lhs'); + assert.deepEqual(person3.hasMany('friends').ids(), ['1', '2'], 'initially relationship established rhs'); + assert.deepEqual(person4.hasMany('friends').ids(), ['1', '2'], 'initially relationship established rhs'); + + run(() => person3.unloadRecord()); + assert.deepEqual(person1Friends.mapBy('id'), ['4'], 'unload async removes from previous many array'); + assert.equal(person1Friends.isDestroyed, false, 'previous ManyArray not destroyed'); + + run(() => person4.unloadRecord()); + assert.deepEqual(person1Friends.mapBy('id'), [], 'unload async removes from previous many array'); + assert.equal(person1Friends.isDestroyed, false, 'previous ManyArray not destroyed'); + + assert.deepEqual(person1.hasMany('friends').ids(), ['3', '4'], 'unload async is not treated as delete'); + + return person1.get('friends'); + }).then((refetchedFriends) => { + assert.equal(person1Friends.isDestroyed, false, 'previous ManyArray is not immediately destroyed after refetch'); + assert.equal(person1Friends.isDestroying, true, 'previous ManyArray is being destroyed immediately after refetch'); + assert.deepEqual(refetchedFriends.mapBy('id'), ['3', '4'], 'friends refetched'); + assert.deepEqual(person1.hasMany('friends').ids(), ['3', '4'], 'unload async is not treated as delete'); + + assert.deepEqual(refetchedFriends.map(p => p.hasMany('friends').ids()), [ + ['1', '2'], + ['1', '2'] + ], 'unload async is not treated as delete'); + + assert.equal(findManyCalls, 2, 'findMany called as expected'); + }) + ).then(() => { + assert.equal(person1Friends.isDestroyed, true, 'previous ManyArray is destroyed in the runloop after refetching'); + }); +}); + +test('1 sync : 1 async unload sync side', function (assert) { + run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteBook: { + data: { + id: 2, + type: 'book' + } + } + } + }, + included: [{ + id: 2, + type: 'book' + }] + }) + ); + + let person = env.store.peekRecord('person', 1); + let book = env.store.peekRecord('book', 2); + + return book.get('person').then(() => { + assert.equal(person.get('favoriteBook.id'), 2, 'initially relationship established lhs'); + assert.equal(book.belongsTo('person').id(), 1, 'initially relationship established rhs'); + + run(() => book.unloadRecord()); + + assert.equal(person.get('book'), null, 'unloading acts as a delete for sync relationships'); + assert.equal(env.store.hasRecordForId('book', 2), false, 'unloaded record gone from store'); + + book = run(() => + env.store.push({ + data: { + id: 2, + type: 'book' + } + }) + ); + + assert.equal(env.store.hasRecordForId('book', 2), true, 'unloaded record can be restored'); + assert.equal(person.get('book'), null, 'restoring unloaded record does not restore relationship'); + assert.equal(book.belongsTo('person').id(), null, 'restoring unloaded record does not restore relationship'); + + run(() => + env.store.push({ + data: { + id: 2, + type: 'book', + relationships: { + person: { + data: { + id: 1, + type: 'person' + } + } + } + } + }) + ); + + assert.equal(person.get('favoriteBook.id'), 2, 'after unloading, relationship can be restored'); + assert.equal(book.get('person.id'), 1, 'after unloading, relationship can be restored'); + }); +}); + +test('1 sync : 1 async unload async side', function (assert) { + let findRecordCalls = 0; + + env.adapter.findRecord = (store, type, id) => { + assert.equal(type, Person, 'findRecord(_, type) is correct'); + assert.equal(id, '1', 'findRecord(_, _, id) is correct'); + ++findRecordCalls; + + return { + data: { + id: 1, + type: 'person' + } + }; + }; + + run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteBook: { + data: { + id: 2, + type: 'book' + } + } + } + }, + included: [{ + id: 2, + type: 'book' + }] + }) + ); + + let person = env.store.peekRecord('person', 1); + let book = env.store.peekRecord('book', 2); + + return run(() => + book.get('person').then(() => { + assert.equal(person.get('favoriteBook.id'), 2, 'initially relationship established lhs'); + assert.equal(book.belongsTo('person').id(), 1, 'initially relationship established rhs'); + + run(() => person.unloadRecord()); + + assert.equal(book.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + + return book.get('person'); + }).then((refetchedPerson) => { + assert.notEqual(person, refetchedPerson, 'the previously loaded record is not reused'); + + assert.equal(book.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal(refetchedPerson.get('favoriteBook.id'), '2', 'unload async is not treated as delete'); + assert.equal(findRecordCalls, 1); + }) + ); +}); + +test('1 async : many sync unload sync side', function (assert) { + run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteSpoons: { + data: [{ + id: 2, + type: 'spoon' + }, { + id: 3, + type: 'spoon' + }] + } + } + }, + included: [{ + id: 2, + type: 'spoon' + }, { + id: 3, + type: 'spoon' + }] + }) + ); + + let person = env.store.peekRecord('person', 1); + let spoon2 = env.store.peekRecord('spoon', 2); + let spoon3 = env.store.peekRecord('spoon', 3); + let spoons = person.get('favoriteSpoons'); + + assert.equal(spoons.isDestroyed, false, 'ManyArray not destroyed'); + assert.deepEqual(person.get('favoriteSpoons').mapBy('id'), ['2', '3'], 'initialy relationship established lhs'); + assert.equal(spoon2.belongsTo('person').id(), '1', 'initially relationship established rhs'); + assert.equal(spoon3.belongsTo('person').id(), '1', 'initially relationship established rhs'); + + run(() => spoon2.unloadRecord()); + + assert.equal(env.store.hasRecordForId('spoon', 2), false, 'unloaded record gone from store'); + + assert.equal(spoons.isDestroyed, false, 'ManyArray not destroyed'); + assert.deepEqual(person.get('favoriteSpoons').mapBy('id'), ['3'], 'unload sync relationship acts as delete'); + assert.equal(spoon3.belongsTo('person').id(), '1', 'unloading one of a sync hasMany does not affect the rest'); + + spoon2 = run(() => + env.store.push({ + data: { + id: 2, + type: 'spoon' + } + }) + ); + + assert.equal(env.store.hasRecordForId('spoon', 2), true, 'unloaded record can be restored'); + assert.deepEqual(person.get('favoriteSpoons').mapBy('id'), ['3'], 'restoring unloaded record does not restore relationship'); + assert.equal(spoon2.belongsTo('person').id(), null, 'restoring unloaded record does not restore relationship'); + + run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteSpoons: { + data: [{ + id: 2, + type: 'spoon' + }, { + id: 3, + type: 'spoon' + }] + } + } + } + }) + ); + + assert.equal(spoon2.belongsTo('person').id(), '1', 'after unloading, relationship can be restored'); + assert.deepEqual(person.get('favoriteSpoons').mapBy('id'), ['2', '3'], 'after unloading, relationship can be restored'); +}); + +test('1 async : many sync unload async side', function (assert) { + let findRecordCalls = 0; + + env.adapter.coalesceFindRequests = true; + + env.adapter.findRecord = (store, type, id) => { + assert.equal(type, Person, 'findRecord(_, type) is correct'); + assert.deepEqual(id, '1', 'findRecord(_, _, id) is correct'); + ++findRecordCalls; + + return { + data: { + id: 1, + type: 'person' + } + }; + }; + + let person = run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteSpoons: { + data: [ + { + id: 2, + type: 'spoon' + }, + { + id: 3, + type: 'spoon' + } + ] + } + } + }, + included: [ + { + id: 2, + type: 'spoon' + }, + { + id: 3, + type: 'spoon' + } + ] + }) + ); + let spoon2 = env.store.peekRecord('spoon', 2); + let spoon3 = env.store.peekRecord('spoon', 3); + let spoons = person.get('favoriteSpoons'); + + return run(() => { + assert.deepEqual(person.get('favoriteSpoons').mapBy('id'), ['2', '3'], 'initially relationship established lhs'); + assert.equal(spoon2.belongsTo('person').id(), '1', 'initially relationship established rhs'); + assert.equal(spoon3.belongsTo('person').id(), '1', 'initially relationship established rhs'); + + assert.equal(spoons.isDestroyed, false, 'ManyArray is not destroyed'); + + run(() => person.unloadRecord()); + + assert.equal(spoons.isDestroyed, false, 'ManyArray is not destroyed when 1 side is unloaded'); + assert.equal(spoon2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal(spoon3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + + return spoon2.get('person'); + }).then((refetchedPerson) => { + assert.notEqual(person, refetchedPerson, 'the previously loaded record is not reused'); + + assert.deepEqual(person.get('favoriteSpoons').mapBy('id'), ['2', '3'], 'unload async is not treated as delete'); + assert.equal(spoon2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal(spoon3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + + assert.equal(findRecordCalls, 1, 'findRecord called as expected'); + }); +}); + +test('1 sync : many async unload async side', function(assert) { + let findManyCalls = 0; + + env.adapter.coalesceFindRequests = true; + + env.adapter.findMany = (store, type, ids) => { + assert.equal(type+'', Show+'', 'findMany(_, type) is correct'); + assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); + ++findManyCalls; + + return { + data: [{ + id: 2, + type: 'show' + }, { + id: 3, + type: 'show' + }] + }; + }; + + let person = run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteShows: { + data: [ + { + id: 2, + type: 'show' + }, + { + id: 3, + type: 'show' + } + ] + } + } + } + }) + ); + + let shows, show2, show3; + + return run(() => person.get('favoriteShows') + .then((asyncRecords) => { + shows = asyncRecords; + [show2, show3] = shows.toArray(); + + assert.deepEqual(person.hasMany('favoriteShows').ids(), ['2', '3'], 'initially relationship established lhs'); + assert.equal(show2.get('person.id'), '1', 'initially relationship established rhs'); + assert.equal(show3.get('person.id'), '1', 'initially relationship established rhs'); + assert.deepEqual(shows.mapBy('id'), ['2', '3'], 'many array is initially set up correctly'); + + run(() => show2.unloadRecord()); + + assert.deepEqual(shows.mapBy('id'), ['3'], 'unload async removes from previous many array'); + assert.equal(shows.isDestroyed, false, 'previous many array not destroyed'); + + run(() => show3.unloadRecord()); + + assert.deepEqual(shows.mapBy('id'), [], 'unload async removes from previous many array'); + assert.equal(shows.isDestroyed, false, 'previous many array not destroyed'); + assert.deepEqual(person.hasMany('favoriteShows').ids(), ['2', '3'], 'unload async is not treated as delete'); + + return person.get('favoriteShows'); + }).then((refetchedShows) => { + assert.equal(shows.isDestroyed, false, 'previous ManyArray is not immediately destroyed after refetch'); + assert.equal(shows.isDestroying, true, 'previous ManyArray is being destroyed immediately after refetch'); + assert.deepEqual(refetchedShows.mapBy('id'), ['2', '3'], 'shows refetched'); + assert.deepEqual(person.hasMany('favoriteShows').ids(), ['2', '3'], 'unload async is not treated as delete'); + + assert.equal(findManyCalls, 2, 'findMany called as expected'); + }) + ).then(() => { + assert.equal(shows.isDestroyed, true, 'previous ManyArray is destroyed in the runloop after refetching'); + }); +}); + +test('1 sync : many async unload sync side', function(assert) { + let findManyCalls = 0; + + env.adapter.coalesceFindRequests = true; + + env.adapter.findMany = (store, type, ids) => { + assert.equal(type+'', Show+'', 'findMany(_, type) is correct'); + assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); + ++findManyCalls; + + return { + data: [{ + id: 2, + type: 'show' + }, { + id: 3, + type: 'show' + }] + }; + }; + + let person = run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteShows: { + data: [ + { + id: 2, + type: 'show' + }, + { + id: 3, + type: 'show' + } + ] + } + } + } + }) + ); + + let shows, show2, show3; + + return run(() => person.get('favoriteShows') + .then((asyncRecords) => { + shows = asyncRecords; + [show2, show3] = shows.toArray(); + + assert.deepEqual(person.hasMany('favoriteShows').ids(), ['2', '3'], 'initially relationship established lhs'); + assert.equal(show2.get('person.id'), '1', 'initially relationship established rhs'); + assert.equal(show3.get('person.id'), '1', 'initially relationship established rhs'); + assert.deepEqual(shows.mapBy('id'), ['2', '3'], 'many array is initially set up correctly'); + + run(() => person.unloadRecord()); + + assert.equal(env.store.hasRecordForId('person', 1), false, 'unloaded record gone from store'); + + assert.equal(shows.isDestroyed, true, 'previous manyarray immediately destroyed'); + assert.equal(show2.get('person.id'), null, 'unloading acts as delete for sync relationships'); + assert.equal(show3.get('person.id'), null, 'unloading acts as delete for sync relationships'); + + person = run(() => + env.store.push({ + data: { + id: 1, + type: 'person' + } + }) + ); + + assert.equal(env.store.hasRecordForId('person', 1), true, 'unloaded record can be restored'); + assert.deepEqual(person.hasMany('favoriteShows').ids(), [], 'restoring unloaded record does not restore relationship'); + assert.equal(show2.get('person.id'), null, 'restoring unloaded record does not restore relationship'); + assert.equal(show3.get('person.id'), null, 'restoring unloaded record does not restore relationship'); + + run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteShows: { + data: [ + { + id: 2, + type: 'show' + }, + { + id: 3, + type: 'show' + } + ] + } + } + } + }) + ); + + assert.deepEqual(person.hasMany('favoriteShows').ids(), ['2', '3'], 'relationship can be restored'); + + return person.get('favoriteShows'); + }).then((refetchedShows) => { + assert.notEqual(refetchedShows, shows, 'ManyArray not reused'); + assert.deepEqual(refetchedShows.mapBy('id'), ['2', '3'], 'unload async not treated as a delete'); + + assert.equal(findManyCalls, 1, 'findMany calls as expected'); + }) + ); +}); diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index 82f0746466e..420cb0fb5a1 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -521,7 +521,7 @@ test("Rollbacking attributes for a created record that has a ManyToMany relation }); }); -test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function(assert) { +test("Deleting an unpersisted record via rollbackAttributes that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function(assert) { let account, user; run(() => { account = store.push({ From 611c17e39984ebd7d2c473d7cf9ece16e7ea647c Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 2 Jan 2018 22:05:08 -0500 Subject: [PATCH 2113/2527] Avoid bower usage in config/ember-try.js --- config/ember-try.js | 172 +++++++++++++------------------------- package.json | 1 + yarn.lock | 199 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 253 insertions(+), 119 deletions(-) diff --git a/config/ember-try.js b/config/ember-try.js index 08aa1b9a0d0..44c3e0be73e 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -1,122 +1,62 @@ -/* eslint-env node */ -module.exports = { - scenarios: [ - { - name: 'default', - bower: { }, - npm: { } - }, - { - name: 'ember-1-13', - bower: { - dependencies: { - 'ember': '1.13.13' +/* eslint-env node, es6 */ + +const getChannelURL = require('ember-source-channel-url'); + +module.exports = function() { + return Promise.all([ + getChannelURL('release'), + getChannelURL('beta'), + getChannelURL('canary') + ]).then((urls) => { + return { + useYarn: true, + scenarios: [ + { + name: 'default', + bower: { }, + npm: { } }, - resolutions: { - 'ember': '1.13.13' - } - }, - npm: { - devDependencies: { - 'ember-source': null - } - } - }, - { - name: 'ember-2-4', - bower: { - dependencies: { - 'ember': '~2.4.0' - }, - resolutions: { - 'ember': '~2.4.0' - } - }, - npm: { - devDependencies: { - 'ember-source': null - } - } - }, - { - name: 'ember-2-8', - bower: { - dependencies: { - 'ember': '~2.8.0' - }, - resolutions: { - 'ember': '~2.8.0' - } - }, - npm: { - devDependencies: { - 'ember-source': null - } - } - }, - { - name: 'ember-release', - bower: { - dependencies: { - 'ember': 'components/ember#release' + { + name: 'ember-lts-2.12', + npm: { + devDependencies: { + 'ember-source': '~2.12.0' + } + } }, - resolutions: { - 'ember': 'release' - } - }, - npm: { - devDependencies: { - 'ember-source': null - } - } - }, - { - name: 'ember-beta', - bower: { - dependencies: { - 'ember': 'components/ember#beta' + { + name: 'ember-lts-2.16', + npm: { + devDependencies: { + 'ember-source': '~2.16.0' + } + } }, - resolutions: { - 'ember': 'beta' - } - }, - npm: { - devDependencies: { - 'ember-source': null - } - } - }, - { - name: 'ember-canary', - bower: { - dependencies: { - 'ember': 'components/ember#canary' + { + name: 'ember-release', + npm: { + devDependencies: { + 'ember-source': urls[0] + } + } }, - resolutions: { - 'ember': 'canary' - } - }, - npm: { - devDependencies: { - 'ember-source': null - } - } - }, - { - name: 'ember-alpha', - bower: { - dependencies: { - 'ember': 'alpha' + { + name: 'ember-beta', + npm: { + devDependencies: { + 'ember-source': urls[1] + } + } }, - resolutions: { - 'ember': 'alpha' - } - }, - npm: { - devDependencies: { - 'ember-source': null - } - } - } - ] + { + name: 'ember-canary', + npm: { + devDependencies: { + 'ember-source': urls[2] + } + } + } + ] + }; + }); }; diff --git a/package.json b/package.json index 1fba64b1d27..71fab955f4d 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "ember-publisher": "0.0.7", "ember-resolver": "^4.1.0", "ember-source": "~2.11.0", + "ember-source-channel-url": "^1.0.1", "ember-watson": "^0.7.0", "express": "^4.14.0", "faker": "^3.1.0", diff --git a/yarn.lock b/yarn.lock index 0e405441acb..d0e43af11bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,6 +12,10 @@ dependencies: "@glimmer/di" "^0.2.0" +"@sindresorhus/is@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" + "@types/node@*": version "8.0.44" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.44.tgz#5c39800fda4b76dab39a5f28fda676fc500015ac" @@ -1561,6 +1565,18 @@ bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" +cacheable-request@^2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" + dependencies: + clone-response "1.0.2" + get-stream "3.0.0" + http-cache-semantics "3.8.1" + keyv "3.0.0" + lowercase-keys "1.0.0" + normalize-url "2.0.1" + responselike "1.0.2" + calculate-cache-key-for-tree@^1.0.0, calculate-cache-key-for-tree@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" @@ -1780,6 +1796,12 @@ cliui@^3.2.0: strip-ansi "^3.0.1" wrap-ansi "^2.0.0" +clone-response@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + dependencies: + mimic-response "^1.0.0" + clone@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" @@ -2071,6 +2093,16 @@ decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + dependencies: + mimic-response "^1.0.0" + deep-eql@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" @@ -2188,6 +2220,10 @@ dot-prop@^4.1.0: dependencies: is-obj "^1.0.0" +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + editions@^1.1.1: version "1.3.3" resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" @@ -2657,6 +2693,12 @@ ember-runtime-enumerable-includes-polyfill@^2.0.0: ember-cli-babel "^6.0.0" ember-cli-version-checker "^1.1.6" +ember-source-channel-url@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ember-source-channel-url/-/ember-source-channel-url-1.0.1.tgz#93517ccbd97a26220184b7986a5325317065308b" + dependencies: + got "^8.0.1" + ember-source@~2.11.0: version "2.11.3" resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-2.11.3.tgz#12c50cc2b4a7f8ae8c5daa3a72fb09415476c510" @@ -3283,6 +3325,13 @@ fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" +from2@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + fs-exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" @@ -3401,7 +3450,7 @@ get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" -get-stream@^3.0.0: +get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -3529,6 +3578,28 @@ globby@^5.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" +got@^8.0.1: + version "8.0.2" + resolved "https://registry.yarnpkg.com/got/-/got-8.0.2.tgz#94d2054767875df4d5eb330f703c63881fc9cd64" + dependencies: + "@sindresorhus/is" "^0.7.0" + cacheable-request "^2.1.1" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + into-stream "^3.1.0" + is-retry-allowed "^1.1.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + mimic-response "^1.0.0" + p-cancelable "^0.3.0" + p-timeout "^2.0.1" + pify "^3.0.0" + safe-buffer "^5.1.1" + timed-out "^4.0.1" + url-parse-lax "^3.0.0" + url-to-options "^1.0.1" + graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -3587,6 +3658,16 @@ has-flag@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" +has-symbol-support-x@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.1.tgz#66ec2e377e0c7d7ccedb07a3a84d77510ff1bc4c" + +has-to-string-tag-x@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + dependencies: + has-symbol-support-x "^1.4.1" + has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -3680,6 +3761,10 @@ hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: version "2.5.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" +http-cache-semantics@3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + http-errors@1.6.2, http-errors@~1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" @@ -3806,6 +3891,13 @@ inquirer@^3.2.1: strip-ansi "^4.0.0" through "^2.3.6" +into-stream@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" + dependencies: + from2 "^2.1.1" + p-is-promise "^1.1.0" + invariant@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" @@ -3913,6 +4005,10 @@ is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" +is-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" + is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -3959,6 +4055,10 @@ is-resolvable@^1.0.0: dependencies: tryit "^1.0.1" +is-retry-allowed@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -4007,6 +4107,13 @@ istextorbinary@2.1.0: editions "^1.1.1" textextensions "1 || 2" +isurl@^1.0.0-alpha5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + dependencies: + has-to-string-tag-x "^1.2.0" + is-object "^1.0.1" + jade@0.26.3: version "0.26.3" resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" @@ -4068,6 +4175,10 @@ json-api-mock-server@0.1.1: jsonapi-validator "^2.1.1" object-assign "^4.1.0" +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" @@ -4117,6 +4228,12 @@ jsonpointer@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" +keyv@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" + dependencies: + json-buffer "3.0.0" + kind-of@^3.0.2: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -4544,6 +4661,10 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0" +lowercase-keys@1.0.0, lowercase-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + lru-cache@2: version "2.7.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" @@ -4702,6 +4823,10 @@ mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" +mimic-response@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" + minimatch@0.3: version "0.3.0" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" @@ -4879,6 +5004,14 @@ normalize-path@^2.0.0, normalize-path@^2.0.1: dependencies: remove-trailing-separator "^1.0.1" +normalize-url@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + dependencies: + prepend-http "^2.0.0" + query-string "^5.0.1" + sort-keys "^2.0.0" + npm-git-info@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" @@ -5022,10 +5155,18 @@ output-file-sync@^1.1.0: mkdirp "^0.5.1" object-assign "^4.1.0" +p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" +p-is-promise@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + p-limit@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" @@ -5036,6 +5177,12 @@ p-locate@^2.0.0: dependencies: p-limit "^1.1.0" +p-timeout@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" + dependencies: + p-finally "^1.0.0" + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -5131,6 +5278,10 @@ pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" @@ -5161,6 +5312,10 @@ prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" @@ -5231,6 +5386,14 @@ qs@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" +query-string@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.0.1.tgz#6e2b86fe0e08aef682ecbe86e85834765402bd88" + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" @@ -5299,7 +5462,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^2, readable-stream@^2.0.6, readable-stream@^2.2.2: +readable-stream@^2, readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.2.2: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" dependencies: @@ -5505,6 +5668,12 @@ resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.0, dependencies: path-parse "^1.0.5" +responselike@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + dependencies: + lowercase-keys "^1.0.0" + restore-cursor@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" @@ -5593,7 +5762,7 @@ rx-lite@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" -safe-buffer@5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@5.1.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -5792,6 +5961,12 @@ socket.io@1.6.0: socket.io-client "1.6.0" socket.io-parser "2.3.1" +sort-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + dependencies: + is-plain-obj "^1.0.0" + sort-object-keys@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" @@ -5895,6 +6070,10 @@ stream-consume@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + string-template@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" @@ -6091,6 +6270,10 @@ through@^2.3.6, through@^2.3.8, through@~2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" +timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + tiny-lr@^1.0.3: version "1.0.5" resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.0.5.tgz#21f40bf84ebd1f853056680375eef1670c334112" @@ -6264,6 +6447,16 @@ untildify@^2.1.0: dependencies: os-homedir "^1.0.0" +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + dependencies: + prepend-http "^2.0.0" + +url-to-options@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + url@0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" From a4e7e28cd8495cb751776734e817c1c980744226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Mu=C3=B1oz?= Date: Sun, 14 Jan 2018 14:04:07 -0500 Subject: [PATCH 2114/2527] Remove usages of enumerable observers ... and replace them with array observers. --- tests/integration/relationships/has-many-test.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 1f46d79f96b..aa70c8e36b4 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -2340,13 +2340,13 @@ test("ManyArray notifies the array observers and flushes bindings when removing" page2 = env.store.peekRecord('page', 2); chapter = env.store.peekRecord('chapter', 1); - chapter.get('pages').addEnumerableObserver(this, { - willChange(pages, removing, addCount) { + chapter.get('pages').addArrayObserver(this, { + willChange(pages, index, removeCount, addCount) { if (observe) { - assert.equal(removing[0], page2, 'page2 is passed to willChange'); + assert.equal(pages.objectAt(index), page2, 'page2 is passed to willChange'); } }, - didChange(pages, removeCount, adding) { + didChange(pages, index, removeCount, addCount) { if (observe) { assert.equal(removeCount, 1, 'removeCount is correct'); } @@ -2399,15 +2399,15 @@ test("ManyArray notifies the array observers and flushes bindings when adding", page2 = env.store.peekRecord('page', 2); chapter = env.store.peekRecord('chapter', 1); - chapter.get('pages').addEnumerableObserver(this, { - willChange(pages, removing, addCount) { + chapter.get('pages').addArrayObserver(this, { + willChange(pages, index, removeCount, addCount) { if (observe) { assert.equal(addCount, 1, 'addCount is correct'); } }, - didChange(pages, removeCount, adding) { + didChange(pages, index, removeCount, addCount) { if (observe) { - assert.equal(adding[0], page2, 'page2 is passed to didChange'); + assert.equal(pages.objectAt(index), page2, 'page2 is passed to didChange'); } } }); From 6fcb2cd2ea0ebf590a7bd5019d012f17e68e6e5e Mon Sep 17 00:00:00 2001 From: Cory Forsyth Date: Mon, 15 Jan 2018 17:14:18 -0500 Subject: [PATCH 2115/2527] Fix Changelog release date for v2.11.0 The release date for v2.11.0 (according to `npm info ember-data`) is '2017-01-09T20:44:27.764Z'. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f945803483..9a3367f54dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -376,7 +376,7 @@ - [#4734](https://github.com/emberjs/data/pull/4734) [DOC] fix a couple of typos in model class docs - [#4739](https://github.com/emberjs/data/pull/4739) Removed id in urlForFindAll signature -### Release 2.11.0 (January 9, 2016) +### Release 2.11.0 (January 9, 2017) - [#4518](https://github.com/emberjs/data/pull/4518) Update the relationship docs to remove some references to a globals s… - [#4581](https://github.com/emberjs/data/pull/4581) [DOC] Update descriptions of findRecord() and findAll() - [#4438](https://github.com/emberjs/data/pull/4438) add `relationship` property to findHasMany RESTAdapter docs From a24bf821ab9c37e061029adfdba7ffef0b33977c Mon Sep 17 00:00:00 2001 From: bekzod Date: Fri, 19 Jan 2018 00:31:37 +0500 Subject: [PATCH 2116/2527] bump rsvp --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 71fab955f4d..755ee9e85dc 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "mocha-only-detector": "0.0.2", "morgan": "^1.7.0", "rimraf": "2.5.2", - "rsvp": "4.7.0", + "rsvp": "4.8.0", "testdouble": "^3.2.6", "testem": "^1.15.0" }, diff --git a/yarn.lock b/yarn.lock index d0e43af11bc..ffab60db843 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5720,9 +5720,9 @@ route-recognizer@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" -rsvp@4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.7.0.tgz#dc1b0b1a536f7dec9d2be45e0a12ad4197c9fd96" +rsvp@4.8.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.0.tgz#dc1dc400e2d48bcf3b1991f2a3b714f038fc432e" rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0, rsvp@^3.5.0, rsvp@^3.6.0: version "3.6.2" From e743b01d0d7964708c3989d0a271018e20fda9ac Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 18 Jan 2018 14:52:47 -0800 Subject: [PATCH 2117/2527] updates to benchmark harness --- benchmarks/BenchmarkGuide.md | 19 ++++++++++++++++ benchmarks/config.js | 44 ++++++++++++++++-------------------- package.json | 2 +- server/scenarios/default.js | 2 +- yarn.lock | 6 ++--- 5 files changed, 43 insertions(+), 30 deletions(-) create mode 100644 benchmarks/BenchmarkGuide.md diff --git a/benchmarks/BenchmarkGuide.md b/benchmarks/BenchmarkGuide.md new file mode 100644 index 00000000000..9ae29e392ae --- /dev/null +++ b/benchmarks/BenchmarkGuide.md @@ -0,0 +1,19 @@ +### Launch + +*Start the API development servers* + +```cli +ember serve --instrument +``` + +*Configure benchmarks* + +In `benchmarks/config.js`, configure the slug(s) +you wish to benchmark, and the number of runs to +complete. + +*Run the desired benchmarks* + +```cli +node ./benchmarks +``` diff --git a/benchmarks/config.js b/benchmarks/config.js index b5cbf311ad3..e88a8ae7708 100644 --- a/benchmarks/config.js +++ b/benchmarks/config.js @@ -14,11 +14,11 @@ module.exports = { // complex returns 7 total records of 3 model types per count in limit // a primary record with 5 hasMany 1 belongsTo - // "query?modelName=complex&limit=1", // 7 total - // "query?modelName=complex&limit=2", // 14 total - // "query?modelName=complex&limit=5", // 35 total - // "query?modelName=complex&limit=17", // 119 total - "query?modelName=complex&limit=34&included=foo,baz", // 238 total + // "query?modelName=complex&limit=1&included=foo,baz", // 7 total + // "query?modelName=complex&limit=2&included=foo,baz", // 14 total + // "query?modelName=complex&limit=5&included=foo,baz", // 35 total + // "query?modelName=complex&limit=17&included=foo,baz", // 119 total + // "query?modelName=complex&limit=34&included=foo,baz", // 238 total // heavy returns 17 total records of 5 model types per count in limit @@ -26,14 +26,15 @@ module.exports = { // - 5 hasMany with 1 belongsTo each // - 1 belongsTo with 5 hasMany - // "query?modelName=heavy&limit=1", // 17 total - // "query?modelName=heavy&limit=2", // 34 total - // "query?modelName=heavy&limit=7", // 119 total - // "query?modelName=heavy&limit=14" // 238 total + // "query?modelName=heavy&limit=1&included=foo,baz,heavy-foo,heavy-baz", // 17 total + // "query?modelName=heavy&limit=2&included=foo,baz,heavy-foo,heavy-baz", // 34 total + // "query?modelName=heavy&limit=7&included=foo,baz,heavy-foo,heavy-baz", // 119 total + // "query?modelName=heavy&limit=14&included=foo,baz,heavy-foo,heavy-baz" // 238 total + "query?modelName=heavy&limit=50&included=foo,baz,heavy-foo,heavy-baz" // 238 total ], ignoreBranches: [ - 'adapter._makeRequest', + // 'adapter._makeRequest', // 'InternalModel._materializeRecord' ], buckets: { @@ -46,10 +47,6 @@ module.exports = { rollup: false, transform: function(t, c) { return c;} }, - /* - { key: "stats.self.selfTime", name: 'Self Time', rollup: false }, - { key: "stats.self.selfTime", name: 'Total Time', rollup: true }, - */ { key: "stats.self.duration", name: 'Duration', @@ -58,19 +55,16 @@ module.exports = { return `${(t / 1e6).toFixed(2)}ms`; } }, - // { key: "stats.store.modelFor", name: 'modelFor', transform: function(t, c) { console.log(t); return t; }, rollup: false }, - // { key: "stats.store.modelFactoryFor", name: 'modelFactoryFor', account: 0.00025, rollup: false }, - { key: "stats.self.selfTime", name: 'Self Time', account: 0, rollup: false }, - { key: "stats.self.selfTime", name: 'Total Time', account: 0, rollup: true }, - /* { key: "stats.self.selfTime", - name: 'Throughput', - rollup: false, - account: 0.00025, - transform: function(t, c) { return `${(c / (t / 1e6)).toFixed(2)} ops/ms`;} - } - */ + name: 'Self Time', + rollup: false + }, + { + key: "stats.self.selfTime", + name: 'Total Time', + rollup: true + }, ], "browser": "chrome", "name": "Performance Analysis", diff --git a/package.json b/package.json index 755ee9e85dc..7993b746b22 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "faker": "^3.1.0", "github": "^1.1.1", "glob": "^5.0.13", - "heimdall-query": "^0.0.8", + "heimdall-query": "^0.1.0", "json-api-mock-server": "0.1.1", "loader.js": "^4.5.0", "mocha": "^2.4.5", diff --git a/server/scenarios/default.js b/server/scenarios/default.js index d84ed006106..3316c65c360 100644 --- a/server/scenarios/default.js +++ b/server/scenarios/default.js @@ -1,6 +1,6 @@ module.exports = function(store) { store.seed('simple', 10000); // 240 store.seed('complex', 400); - store.seed('heavy', 14); + store.seed('heavy', 50); }; diff --git a/yarn.lock b/yarn.lock index ffab60db843..e335b5f1a4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3690,9 +3690,9 @@ hawk@1.1.1: hoek "0.9.x" sntp "0.2.x" -heimdall-query@^0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/heimdall-query/-/heimdall-query-0.0.8.tgz#74f01be023690be7d09f92aef747b642fd8bde8e" +heimdall-query@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/heimdall-query/-/heimdall-query-0.1.0.tgz#4b1bb8de46dc292f2f10620bee4f81b2f5443937" dependencies: chalk "^1.1.1" chrome-debugging-client "^0.2.4" From 30514b974eafe230b143ddbef5bd52fe641b889e Mon Sep 17 00:00:00 2001 From: bmac Date: Sun, 7 Jan 2018 17:32:10 -0500 Subject: [PATCH 2118/2527] [doc beta] Use Ember.computed in the headers examples to avoid ember eslint warning --- addon/adapters/rest.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index abf5b847218..a1d6400ed86 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -233,11 +233,14 @@ const Promise = EmberPromise; ```app/adapters/application.js import DS from 'ember-data'; + import { computed } from '@ember/object'; export default DS.RESTAdapter.extend({ - headers: { - 'API_KEY': 'secret key', - 'ANOTHER_HEADER': 'Some header value' + headers: computed(function() { + return { + 'API_KEY': 'secret key', + 'ANOTHER_HEADER': 'Some header value' + }; } }); ``` @@ -441,12 +444,15 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { ```app/adapters/application.js import DS from 'ember-data'; + import { computed } from '@ember/object'; export default DS.RESTAdapter.extend({ - headers: { - 'API_KEY': 'secret key', - 'ANOTHER_HEADER': 'Some header value' - } + headers: computed(function() { + return { + 'API_KEY': 'secret key', + 'ANOTHER_HEADER': 'Some header value' + }; + }) }); ``` From c08a8a072ca58a3f50ca93b1414068f057533a16 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 22 Jan 2018 14:26:45 -0800 Subject: [PATCH 2119/2527] [DEV-BUGFIX] Fix instrumentation when running in production (#5333) * fix production instrumented builds --- index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index cafe40a0fdc..bb18ce28210 100644 --- a/index.js +++ b/index.js @@ -35,6 +35,10 @@ function isProductionEnv() { return isProd && !isTest; } +function isInstrumentedBuild() { + return INSTRUMENT_HEIMDALL; +} + module.exports = { name: 'ember-data', @@ -137,7 +141,7 @@ module.exports = { let withoutPrivate = new Funnel(treeWithVersion, { exclude: [ '-private', - isProductionEnv() ? '-debug' : false + isProductionEnv() && !isInstrumentedBuild() ? '-debug' : false ].filter(Boolean), destDir: 'ember-data' From 18a0534c5648828f3360f1eb4079161dafd13737 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 22 Jan 2018 13:32:47 -0500 Subject: [PATCH 2120/2527] [BUGFIX beta] Remove non-functional (error prone) manual CP caching. The previous implementation was intending to cache relationships when in the production environment, but avoid caching them in development. Unfortunately, this code was factored in a way that relied on mutating internal private state of the underlying `Ember.ComputedProperty` instance when `Ember.testing` was true (which was used as a way to determine prod vs non-prod). When this code was introduced (2014-12-02), setting `_cacheable` on a `ComputedProperty` instance would have worked as intended, however a refactor in Ember (ironically one day prior, but on Ember's canary channel) deprecated using `_cacheable` or `.cacheable()` (in favor of opting out of caching via `.volatile()`). Since this has not worked since Ember 2.0.0, and it has not been an issue, this commit completely removes the manual caching / volatile swapping between prod/dev/testing environments. --- addon/-private/system/relationships/ext.js | 9 --- .../relationships/belongs-to-test.js | 73 ------------------- 2 files changed, 82 deletions(-) diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 872d9f0e1f2..2a8bf05159e 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -2,7 +2,6 @@ import { A } from '@ember/array'; import { computed } from '@ember/object'; import MapWithDefault from '@ember/map/with-default'; import Map from '@ember/map'; -import Ember from 'ember'; import { assert } from '@ember/debug'; import { typeForRelationshipMeta, @@ -10,10 +9,6 @@ import { } from "../relationship-meta"; export const relationshipsDescriptor = computed(function() { - if (Ember.testing === true && relationshipsDescriptor._cacheable === true) { - relationshipsDescriptor._cacheable = false; - } - let map = new MapWithDefault({ defaultValue() { return []; } }); @@ -37,10 +32,6 @@ export const relationshipsDescriptor = computed(function() { }).readOnly(); export const relatedTypesDescriptor = computed(function() { - if (Ember.testing === true && relatedTypesDescriptor._cacheable === true) { - relatedTypesDescriptor._cacheable = false; - } - let modelName; let types = A(); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 842aff95feb..f10d71fa0b1 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -2,7 +2,6 @@ import { get } from '@ember/object'; import { run } from '@ember/runloop'; import RSVP, { resolve } from 'rsvp'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { @@ -542,78 +541,6 @@ test("relationshipsByName does not cache a factory", function(assert) { "model factory based on relationship type matches the model based on store.modelFor"); }); -function getDescriptor(object, key) { - var meta = Ember.meta(object); - var mixins = (meta && meta._mixins) || {}; - for (let key in mixins) { - let klass = mixins[key] - if (!klass.properties) { - continue; - } - let descriptor = klass.properties[key]; - if (descriptor) { - return descriptor; - } - } - // Fallback to grabbing the descriptor off of the object for old - // versions of Ember - return object[key]; -} - -test("relationshipsByName is cached in production", function(assert) { - let model = store.modelFor('user'); - let oldTesting = Ember.testing; - //We set the cacheable to true because that is the default state for any CP and then assert that it - //did not get dynamically changed when accessed - let relationshipsByName = getDescriptor(model, 'relationshipsByName'); - let oldCacheable = relationshipsByName._cacheable; - relationshipsByName._cacheable = true; - Ember.testing = false; - try { - assert.equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached'); - assert.equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached'); - } finally { - Ember.testing = oldTesting; - relationshipsByName._cacheable = oldCacheable; - } -}); - -test("relatedTypes is cached in production", function(assert) { - let model = store.modelFor('user'); - let oldTesting = Ember.testing; - //We set the cacheable to true because that is the default state for any CP and then assert that it - //did not get dynamically changed when accessed - let relatedTypes = getDescriptor(model, 'relatedTypes'); - let oldCacheable = relatedTypes._cacheable; - relatedTypes._cacheable = true; - Ember.testing = false; - try { - assert.equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached'); - assert.equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached'); - } finally { - Ember.testing = oldTesting; - relatedTypes._cacheable = oldCacheable; - } -}); - -test("relationships is cached in production", function(assert) { - let model = store.modelFor('user'); - let oldTesting = Ember.testing; - //We set the cacheable to true because that is the default state for any CP and then assert that it - //did not get dynamically changed when accessed - let relationships = getDescriptor(model, 'relationships'); - let oldCacheable = relationships._cacheable; - relationships._cacheable = true; - Ember.testing = false; - try { - assert.equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached'); - assert.equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached'); - } finally { - Ember.testing = oldTesting; - relationships._cacheable = oldCacheable; - } -}); - test("relationship changes shouldn’t cause async fetches", function(assert) { assert.expect(2); From 028aac71311fc63939149cf5dfefe912f3735973 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sat, 27 Jan 2018 13:34:17 -0800 Subject: [PATCH 2121/2527] Prevent build issues when linking ember-source. Prior to this, we used our ember-data's own dirname as the default `baseDir` for any of our custom babel plugins. This baseDir is used to traverse all JS files in all deps (recursively) and ensure that if any of them are changed, the transpilation cache is invalidated. Once we swapped to using ember-source as an npm package this meant that we would be stating/hashing all files inside of `node_modules/ember-source/**`. When using `npm link ember-source` this leads to a JS max heap errors (because of `node_modules/ember-source/tmp/**` being _MASSIVE_). This fixes that specific issue, by using the **correct** basedir for each individual plugin. --- lib/stripped-build-plugins.js | 38 +++++++++++++++++++++-------------- package.json | 1 + yarn.lock | 6 ++++++ 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 45570f1826d..9e76f19f56e 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -1,13 +1,15 @@ 'use strict'; var path = require('path'); -var fs = require('fs'); -var FilterImports = require('babel-plugin-filter-imports'); -var FeatureFlags = require('babel-plugin-feature-flags'); -var StripHeimdall = require('babel6-plugin-strip-heimdall'); -var StripClassCallCheck = require('babel6-plugin-strip-class-callcheck'); +var fs = require('fs'); +var resolve = require('resolve'); + +var FilterImports = requireBabelPlugin('babel-plugin-filter-imports'); +var FeatureFlags = requireBabelPlugin('babel-plugin-feature-flags'); +var StripHeimdall = requireBabelPlugin('babel6-plugin-strip-heimdall'); +var StripClassCallCheck = requireBabelPlugin('babel6-plugin-strip-class-callcheck'); var StripFilteredImports = require('./transforms/babel-plugin-remove-imports'); -var TransformBlockScoping = require('babel-plugin-transform-es2015-block-scoping'); +var TransformBlockScoping = requireBabelPlugin('babel-plugin-transform-es2015-block-scoping'); function uniqueAdd(obj, key, values) { var a = obj[key] = obj[key] || []; @@ -19,14 +21,26 @@ function uniqueAdd(obj, key, values) { } } -function addBaseDir(Plugin) { +// ensures that a `baseDir` property is present on the babel plugins +// that we will be using, this prevents ember-cli-babel/broccoli-babel-transpiler +// from opting out of caching (and printing a giant warning) +function requireBabelPlugin(packageName) { + var Plugin = require(packageName); + var PluginPath = resolve.sync(packageName + '/package.json', { basedir: __dirname }); + + return addBaseDir(Plugin, path.dirname(PluginPath)); +} + +function addBaseDir(Plugin, baseDir) { let type = typeof Plugin; if (type === 'function' && !Plugin.baseDir) { - Plugin.baseDir = () => path.join(__dirname, '..'); + Plugin.baseDir = () => baseDir; } else if (type === 'object' && Plugin !== null && Plugin.default) { - addBaseDir(Plugin.default); + addBaseDir(Plugin.default, baseDir); } + + return Plugin; } module.exports = function(environment) { @@ -72,11 +86,5 @@ module.exports = function(environment) { [TransformBlockScoping, { 'throwIfClosureRequired': true }] ); - // ensures that a `baseDir` property is present on the babel plugins - // that we will be using, this prevents ember-cli-babel/broccoli-babel-transpiler - // from opting out of caching (and printing a giant warning) - plugins.forEach((pluginWithOptions) => addBaseDir(pluginWithOptions[0])); - - return { plugins, postTransformPlugins }; }; diff --git a/package.json b/package.json index 7993b746b22..56364723173 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "heimdalljs": "^0.3.0", "inflection": "^1.8.0", "npm-git-info": "^1.0.0", + "resolve": "^1.5.0", "semver": "^5.1.0", "silent-error": "^1.0.0" }, diff --git a/yarn.lock b/yarn.lock index e335b5f1a4a..96763e5cf95 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5668,6 +5668,12 @@ resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.0, dependencies: path-parse "^1.0.5" +resolve@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" + dependencies: + path-parse "^1.0.5" + responselike@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" From 64d5620714b8b8821e09fa028349f5ce296ea91b Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Sat, 27 Jan 2018 17:35:35 -0800 Subject: [PATCH 2122/2527] [BUGFIX beta] Update DS.Errors#unknownProperty to return `undefined`. In Ember 3.1+ any object that has an `unknownProperty` will throw an error if its `unknownProperty` returns any value other than `undefined` and the property is accessed via `obj.someProperty` (instead of `obj.get('someProperty')` or `Ember.get(obj, 'someProperty')`). --- addon/-private/system/model/errors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index 7ddbf5f4412..92427d95e5f 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -186,7 +186,7 @@ export default ArrayProxy.extend(Evented, { */ unknownProperty(attribute) { let errors = this.errorsFor(attribute); - if (isEmpty(errors)) { return null; } + if (isEmpty(errors)) { return undefined; } return errors; }, From ab4dff563000f1ba9112ec2886cc8c6a8652a803 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 29 Jan 2018 12:27:00 -0800 Subject: [PATCH 2123/2527] Refactor Travis setup to leverage stages... (#5342) * [BUGFIX beta] Switch to Chrome for CI. * Remove extra Node 6 runs from CI. * Make `yarn test` test with normal deps. * Refactor .travis.yml to use build stages. * Fix error in production build tests with Chrome. When running in PhantomJS the error message matched accidentally. This test should only be ran in debug builds because it is specifically testing an `Ember.assert` (which does not thrown in production). * Move floating dependencies build into `additional tests`. * Do not install phantomjs on Appveyor. * Update ember-try version to properly respect promises. * Fix npm script name for node tests. --- .travis.yml | 75 ++++++++++++++++++++++++++--------- appveyor.yml | 11 ++--- ember-cli-build.js | 3 -- package.json | 11 ++--- testem.js | 17 ++++++-- tests/unit/store/push-test.js | 2 +- yarn.lock | 26 ++++++++++++ 7 files changed, 107 insertions(+), 38 deletions(-) diff --git a/.travis.yml b/.travis.yml index a6543656e6a..b297c4ab255 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,37 +4,74 @@ sudo: false dist: trusty node_js: - "4" - - "6" -# hack to get after_success skipped in node 4 -matrix: - exclude: - - node_js: "4" - include: - - node_js: "4" - after_success: skip +addons: + chrome: stable cache: yarn: true +stages: + - test + - additional tests + - older version tests + - deploy + +jobs: + fail_fast: true + + include: + # runs tests with current locked deps and linting + - stage: test + env: NAME=test # used only to make Travis UI show description + script: + - ./bin/lint-features + - yarn test + + - stage: additional tests + env: NAME=optional-features # used only to make Travis UI show description + install: yarn install + script: yarn test:optional-features + + - env: NAME=floating dependencies # used only to make Travis UI show description + install: yarn install --no-lockfile --non-interactive + script: yarn test + + - env: NAME=production # used only to make Travis UI show description + install: yarn install + script: yarn test:production + + - env: NAME=node-tests # used only to make Travis UI show description + install: yarn install + script: yarn test:node + + # runs tests against each supported Ember version + - stage: older version tests + env: EMBER_TRY_SCENARIO=ember-lts-2.12 + - env: EMBER_TRY_SCENARIO=ember-lts-2.16 + - env: EMBER_TRY_SCENARIO=ember-release + - env: EMBER_TRY_SCENARIO=ember-beta + - env: EMBER_TRY_SCENARIO=ember-canary + + - stage: deploy + if: branch IN (master, beta, release) OR tag IS present + env: NAME=publish # used only to make Travis UI show description + install: yarn install + script: + - yarn build:production + - "./bin/publish-builds" + + before_install: - curl -o- -L https://yarnpkg.com/install.sh | bash - export PATH=$HOME/.yarn/bin:$PATH - - yarn global add phantomjs-prebuilt - - phantomjs --version install: - - yarn install --no-lockfile --no-interactive + - yarn install script: - - ./bin/lint-features - - yarn run test - - yarn run test:optional-features - - yarn run test:production - - yarn run node-tests -after_success: - - yarn run production - - "./bin/publish-builds" + - node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO --skip-cleanup + env: global: - BROCCOLI_ENV="production" diff --git a/appveyor.yml b/appveyor.yml index 5d41989135a..778376491fd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,19 +13,16 @@ cache: install: # Get the latest stable version of Node 0.STABLE.latest - ps: Install-Product node $env:nodejs_version - # Install PhantomJS - - choco install phantomjs --version 2.0.0 -y - - set path=%path%;C:\ProgramData\chocolatey\lib\PhantomJS\tools\ # Typical npm stuff. - md C:\nc - appveyor-retry yarn install # Post-install test scripts. test_script: # Output useful info for debugging. - - cmd: yarn run test-appveyor - - cmd: yarn run test:optional-features - - cmd: yarn run test:production - - cmd: yarn run node-tests + - cmd: yarn test + - cmd: yarn test:optional-features + - cmd: yarn test:production + - cmd: yarn test:node # Don't actually build. build: off diff --git a/ember-cli-build.js b/ember-cli-build.js index ec588e8a84e..c17b7d456eb 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -26,9 +26,6 @@ module.exports = function(defaults) { // while ember-data strips itself, ember does not currently [StripClassCallCheck] ] - }, - 'ember-cli-babel': { - includePolyfill: true } }); diff --git a/package.json b/package.json index 56364723173..36b988affea 100644 --- a/package.json +++ b/package.json @@ -9,13 +9,13 @@ }, "scripts": { "build": "ember build", + "build:production": "ember build --environment=production", "start": "ember server", - "test": "ember try:testall", - "test-appveyor": "ember test", - "node-tests": "node node-tests/nodetest-runner.js", - "test:optional-features": "ember test --environment=test-optional-features", + "test": "ember test", + "test:all": "ember try:each", + "test:node": "node node-tests/nodetest-runner.js", "test:production": "ember test --environment=production", - "production": "ember build --environment=production" + "test:optional-features": "ember test --environment=test-optional-features" }, "author": "", "license": "MIT", @@ -97,6 +97,7 @@ "ember-resolver": "^4.1.0", "ember-source": "~2.11.0", "ember-source-channel-url": "^1.0.1", + "ember-try": "^0.2.23", "ember-watson": "^0.7.0", "express": "^4.14.0", "faker": "^3.1.0", diff --git a/testem.js b/testem.js index 4cb09405ca0..158a909be30 100644 --- a/testem.js +++ b/testem.js @@ -5,10 +5,21 @@ module.exports = { "disable_watching": true, "reporter": "dot", "launch_in_ci": [ - "PhantomJS" + "Chrome" ], "launch_in_dev": [ - "PhantomJS", "Chrome" - ] + ], + browser_args: { + Chrome: { + mode: 'ci', + args: [ + '--disable-gpu', + '--headless', + '--remote-debugging-port=0', + '--window-size=1440,900', + '--no-sandbox' + ] + } + } }; diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index 08667010bb1..e842cd5b15b 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -503,7 +503,7 @@ test('Calling pushPayload allows partial updates with raw JSON', function(assert assert.equal(person.get('lastName'), 'Jackson', 'existing fields are untouched'); }); -test('calling push without data argument as an object raises an error', function(assert) { +testInDebug('calling push without data argument as an object raises an error', function(assert) { let invalidValues = [ null, 1, diff --git a/yarn.lock b/yarn.lock index 96763e5cf95..c47b7b465dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2732,6 +2732,15 @@ ember-try-config@^2.0.1: rsvp "^3.2.1" semver "^5.1.0" +ember-try-config@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ember-try-config/-/ember-try-config-2.2.0.tgz#6be0af6c71949813e02ac793564fddbf8336b807" + dependencies: + lodash "^4.6.1" + node-fetch "^1.3.3" + rsvp "^3.2.1" + semver "^5.1.0" + ember-try@^0.2.15: version "0.2.17" resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.17.tgz#0ffff687630291b4cf94f5b196e728c1a92d8aec" @@ -2750,6 +2759,23 @@ ember-try@^0.2.15: rsvp "^3.0.17" semver "^5.1.0" +ember-try@^0.2.23: + version "0.2.23" + resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.23.tgz#39b57141b4907541d0ac8b503d211e6946b08718" + dependencies: + chalk "^1.0.0" + cli-table2 "^0.2.0" + core-object "^1.1.0" + debug "^2.2.0" + ember-try-config "^2.2.0" + extend "^3.0.0" + fs-extra "^0.26.0" + promise-map-series "^0.2.1" + resolve "^1.1.6" + rimraf "^2.3.2" + rsvp "^3.0.17" + semver "^5.1.0" + ember-watson@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" From 56a37b5938c48c1d615ae0ee43b853fe5fff8cef Mon Sep 17 00:00:00 2001 From: Ryan Toronto Date: Wed, 31 Jan 2018 10:28:58 -0500 Subject: [PATCH 2124/2527] Check if adapter#query is a wrapped function --- addon/-private/system/store/finders.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 0103a0084a1..ed3f8416f06 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -138,7 +138,10 @@ export function _query(adapter, store, modelName, query, recordArray) { let modelClass = store.modelFor(modelName); // adapter.query needs the class let promise; - if (adapter.query.length > 3) { + let createRecordArray = adapter.query.length > 3 || + (adapter.query.wrappedFunction && adapter.query.wrappedFunction.length > 3); + + if (createRecordArray) { recordArray = recordArray || store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); promise = adapter.query(store, modelClass, query, recordArray); } else { From c8236d03d9a2b0f40611cec9549affa38fa89d14 Mon Sep 17 00:00:00 2001 From: Lukas Kohler Date: Wed, 31 Jan 2018 18:22:58 +0100 Subject: [PATCH 2125/2527] failing test for id relationship does not update after the record is provided #5134 (#5135) --- .../integration/references/belongs-to-test.js | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index fab5da5d26e..bf2e9eecf6c 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -405,6 +405,39 @@ test("value() returns the referenced record when loaded", function(assert) { assert.equal(familyReference.value(), family); }); +test("value() returns the referenced record when loaded even if links are present", function(assert) { + var person, family; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } + } + } + } + }); + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + links: { + related: '/this/should/not/matter' + } + } + } + } + }); + }); + + var familyReference = person.belongsTo('family'); + assert.equal(familyReference.value(), family); +}); + test("load() fetches the record", function(assert) { var done = assert.async(); From 6d8b013dc5d476bc1657bd5d49c2c3cc23fc4e41 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 12 Feb 2018 09:20:37 -0500 Subject: [PATCH 2126/2527] Update changelog for 3.0.0 release --- CHANGELOG.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a3367f54dd..923decbf405 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,31 @@ ### Master +### Release 3.0.0 (Feburary 12, 2018) +- [#5296](https://github.com/emberjs/data/pull/5296) blueprints/adapter-test: Add RFC232 variants +- [#5249](https://github.com/emberjs/data/pull/5249) Fix client-side delete + resurrection +- [#5301](https://github.com/emberjs/data/pull/5301) Add a test to ensure multiple stores get unique instances of serializ… +- [#5289](https://github.com/emberjs/data/pull/5289) [CLEANUP beta] Remove support/deprecation for normalizeHash in 3.0.0 (#5289) +- [#5286](https://github.com/emberjs/data/pull/5286) Remove deprecation/support for complex object as defaultValues of DS.attr +- [#5288](https://github.com/emberjs/data/pull/5288) Remove date transforms deprecations and support for Ember.Date.parse +- [#5289](https://github.com/emberjs/data/pull/5289) [CLEANUP beta] Remove support/deprecation for normalizeHash in 3.0.0 (#5289) +- [#5289](https://github.com/emberjs/data/pull/5289) [CLEANUP beta] Remove support/deprecation for normalizeHash in 3.0.0 (#5289) +- [#5289](https://github.com/emberjs/data/pull/5289) [CLEANUP beta] Remove support/deprecation for normalizeHash in 3.0.0 (#5289) +- [#5289](https://github.com/emberjs/data/pull/5289) [CLEANUP beta] Remove support/deprecation for normalizeHash in 3.0.0 (#5289) +- [#5289](https://github.com/emberjs/data/pull/5289) [CLEANUP beta] Remove support/deprecation for normalizeHash in 3.0.0 (#5289) +- [#5261](https://github.com/emberjs/data/pull/5261) [BUGFIX] inverseFor should respect inverse: null +- [#5285](https://github.com/emberjs/data/pull/5285) Remove deprecation messages for old instance initializers +- [#5290](https://github.com/emberjs/data/pull/5290) Remove deprecation around shouldSerializeHasMany +- [#5291](https://github.com/emberjs/data/pull/5291) Remove deprecation and fallback for keyForAttribute when keyForPolymo… +- [#5293](https://github.com/emberjs/data/pull/5293) cleanup: node-tests cleanup (#5293) +- [#5294](https://github.com/emberjs/data/pull/5294) blueprints/transform-test: Add RFC232 variants +- [#5297](https://github.com/emberjs/data/pull/5297) bluepints/model-test: Add RFC232 variants +- [#5298](https://github.com/emberjs/data/pull/5298) blueprints/serializer-test: Add RFC232 variants +- [#5299](https://github.com/emberjs/data/pull/5299) Fixup the RFC232 model-test files. +- [#5300](https://github.com/emberjs/data/pull/5300) Simplify `store.adapterFor` and `store.serializerFor`. +- [#5305](https://github.com/emberjs/data/pull/5305) Serializers and adapters should be unique per store +- [#5308](https://github.com/emberjs/data/pull/5308) Simplify the getDescriptor test helper + ### Release 2.18.0 (December 28, 2017) - [#5225](https://github.com/emberjs/data/pull/5225) Remove blueprints for Mocha < 0.12. (#5225) - [#4998](https://github.com/emberjs/data/pull/4998) [DOC beta] Assert that both modelName and id are passed to `peekRecord` (#4998) From 4136a07f3032c8983eca862e5d19ed8416969152 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 12 Feb 2018 09:32:21 -0500 Subject: [PATCH 2127/2527] Bump release to 3.2.0-canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 36b988affea..117ab108f73 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "3.1.0-canary", + "version": "3.2.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From ddd8142813133322d6426652409ebf5b207c18da Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 12 Feb 2018 09:33:19 -0500 Subject: [PATCH 2128/2527] Update release instructions for the new build command --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 0c8a092bb0e..ad716656968 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -20,7 +20,7 @@ STEPS: * Git tag version * `git tag vX.Y.Z-beta.n` * Do a production build. - * `rm -rf node_modules bower_components; yarn install; bower install; npm run production` + * `rm -rf node_modules; yarn install; npm run build:production` * Publish to Bower * Commit built globals code to the https://github.com/components/ember-data repo * `cp dist/globals/* ../components-ember-data/` From ff5f11a8a6b53b75d00de8f75674ae2124b53e17 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 13 Feb 2018 08:53:56 -0500 Subject: [PATCH 2129/2527] Update changelog with 3.0.1 and 2.18.1 --- CHANGELOG.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 923decbf405..d6f9bf4d64a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ ### Master -### Release 3.0.0 (Feburary 12, 2018) +### Release 3.0.1 (February 13, 2018) +- [#5273](https://github.com/emberjs/data/pull/5273) client-side-delete semantics `unloadRecord` + +### Release 3.0.0 (February 12, 2018) - [#5296](https://github.com/emberjs/data/pull/5296) blueprints/adapter-test: Add RFC232 variants - [#5249](https://github.com/emberjs/data/pull/5249) Fix client-side delete + resurrection - [#5301](https://github.com/emberjs/data/pull/5301) Add a test to ensure multiple stores get unique instances of serializ… @@ -10,10 +13,6 @@ - [#5286](https://github.com/emberjs/data/pull/5286) Remove deprecation/support for complex object as defaultValues of DS.attr - [#5288](https://github.com/emberjs/data/pull/5288) Remove date transforms deprecations and support for Ember.Date.parse - [#5289](https://github.com/emberjs/data/pull/5289) [CLEANUP beta] Remove support/deprecation for normalizeHash in 3.0.0 (#5289) -- [#5289](https://github.com/emberjs/data/pull/5289) [CLEANUP beta] Remove support/deprecation for normalizeHash in 3.0.0 (#5289) -- [#5289](https://github.com/emberjs/data/pull/5289) [CLEANUP beta] Remove support/deprecation for normalizeHash in 3.0.0 (#5289) -- [#5289](https://github.com/emberjs/data/pull/5289) [CLEANUP beta] Remove support/deprecation for normalizeHash in 3.0.0 (#5289) -- [#5289](https://github.com/emberjs/data/pull/5289) [CLEANUP beta] Remove support/deprecation for normalizeHash in 3.0.0 (#5289) - [#5261](https://github.com/emberjs/data/pull/5261) [BUGFIX] inverseFor should respect inverse: null - [#5285](https://github.com/emberjs/data/pull/5285) Remove deprecation messages for old instance initializers - [#5290](https://github.com/emberjs/data/pull/5290) Remove deprecation around shouldSerializeHasMany @@ -27,6 +26,9 @@ - [#5305](https://github.com/emberjs/data/pull/5305) Serializers and adapters should be unique per store - [#5308](https://github.com/emberjs/data/pull/5308) Simplify the getDescriptor test helper +### Release 2.18.1 (February 13, 2018) +- [#5273](https://github.com/emberjs/data/pull/5273) client-side-delete semantics `unloadRecord` + ### Release 2.18.0 (December 28, 2017) - [#5225](https://github.com/emberjs/data/pull/5225) Remove blueprints for Mocha < 0.12. (#5225) - [#4998](https://github.com/emberjs/data/pull/4998) [DOC beta] Assert that both modelName and id are passed to `peekRecord` (#4998) From ae1d83dfefa6c77d9246462bc0183670b40b456d Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Sun, 18 Feb 2018 20:31:47 -0500 Subject: [PATCH 2130/2527] Remove extra parameter from assert.equal that was causing issues on travis (#5360) --- tests/integration/relationships/one-to-many-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index 7477cea1d63..37ec95a233b 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -1375,7 +1375,7 @@ test("Rollbacking attributes of a created record works correctly when the hasMan assert.equal(fetchedUser, null, 'Message does not have the user anymore'); }); user.get('messages').then(function(fetchedMessages) { - assert.equal(fetchedMessages.get('length'), 0, message, 'User does not have the message anymore'); + assert.equal(fetchedMessages.get('length'), 0, 'User does not have the message anymore'); assert.equal(fetchedMessages.get('firstObject'), null, "User message can't be accessed"); }); }); From 283f8e92a70b15071a1e4321dce7e43cf3939db4 Mon Sep 17 00:00:00 2001 From: Ralph Mack Date: Sun, 18 Feb 2018 21:47:17 -0500 Subject: [PATCH 2131/2527] Removing reference to Ember.Logger (#5356) --- tests/test-helper.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test-helper.js b/tests/test-helper.js index 31c7459330e..e27a313804a 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -19,7 +19,6 @@ import { asyncEqual, invokeAsync } from 'dummy/tests/helpers/async'; -import Ember from 'ember'; import loadInitializers from 'ember-load-initializers'; setResolver(resolver); @@ -39,7 +38,7 @@ QUnit.begin(() => { // otherwise, let a future turn of the event loop // handle the error. if (reason && reason instanceof Error) { - Ember.Logger.log(reason, reason.stack); + console.log(reason, reason.stack); throw reason; } }); From 2e1a1122490bae9add17138b2e0e3ecef05f9544 Mon Sep 17 00:00:00 2001 From: bek Date: Wed, 21 Feb 2018 07:36:26 +0500 Subject: [PATCH 2132/2527] convert to es6 class `references` (#5361) --- .../-private/system/references/belongs-to.js | 675 +++++++++-------- addon/-private/system/references/has-many.js | 700 +++++++++--------- addon/-private/system/references/record.js | 249 +++---- 3 files changed, 807 insertions(+), 817 deletions(-) diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 0344a931d47..440583e4c10 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -15,79 +15,30 @@ import { assertPolymorphicType } from 'ember-data/-debug'; @namespace DS @extends DS.Reference */ -const BelongsToReference = function(store, parentInternalModel, belongsToRelationship) { - this._super$constructor(store, parentInternalModel); - this.belongsToRelationship = belongsToRelationship; - this.type = belongsToRelationship.relationshipMeta.type; - this.parent = parentInternalModel.recordReference; - - // TODO inverse -}; - -BelongsToReference.prototype = Object.create(Reference.prototype); -BelongsToReference.prototype.constructor = BelongsToReference; -BelongsToReference.prototype._super$constructor = Reference; - -/** - This returns a string that represents how the reference will be - looked up when it is loaded. If the relationship has a link it will - use the "link" otherwise it defaults to "id". - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - }); - let userRef = blog.belongsTo('user'); - - // get the identifier of the reference - if (userRef.remoteType() === "id") { - let id = userRef.id(); - } else if (userRef.remoteType() === "link") { - let link = userRef.link(); - } - ``` - - @method remoteType - @return {String} The name of the remote type. This should either be "link" or "id" -*/ -BelongsToReference.prototype.remoteType = function() { - if (this.belongsToRelationship.link) { - return "link"; +export default class BelongsToReference extends Reference { + + constructor(store, parentInternalModel, belongsToRelationship) { + super(store, parentInternalModel); + this.belongsToRelationship = belongsToRelationship; + this.type = belongsToRelationship.relationshipMeta.type; + this.parent = parentInternalModel.recordReference; + // TODO inverse } - return "id"; -}; + /** + This returns a string that represents how the reference will be + looked up when it is loaded. If the relationship has a link it will + use the "link" otherwise it defaults to "id". -/** - The `id` of the record that this reference refers to. Together, the - `type()` and `id()` methods form a composite key for the identity - map. This can be used to access the id of an async relationship - without triggering a fetch that would normally happen if you - attempted to use `record.get('relationship.id')`. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); - let blog = store.push({ - data: { + let blog = store.push({ type: 'blog', id: 1, relationships: { @@ -95,318 +46,364 @@ BelongsToReference.prototype.remoteType = function() { data: { type: 'user', id: 1 } } } + }); + let userRef = blog.belongsTo('user'); + + // get the identifier of the reference + if (userRef.remoteType() === "id") { + let id = userRef.id(); + } else if (userRef.remoteType() === "link") { + let link = userRef.link(); } - }); - let userRef = blog.belongsTo('user'); - - // get the identifier of the reference - if (userRef.remoteType() === "id") { - let id = userRef.id(); + ``` + + @method remoteType + @return {String} The name of the remote type. This should either be "link" or "id" + */ + remoteType() { + if (this.belongsToRelationship.link) { + return "link"; } - ``` - @method id - @return {String} The id of the record in this belongsTo relationship. -*/ -BelongsToReference.prototype.id = function() { - let inverseInternalModel = this.belongsToRelationship.inverseInternalModel; - return inverseInternalModel && inverseInternalModel.id; -}; - -/** - The link Ember Data will use to fetch or reload this belongs-to - relationship. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); + return "id"; + } - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - links: { - related: '/articles/1/author' + /** + The `id` of the record that this reference refers to. Together, the + `type()` and `id()` methods form a composite key for the identity + map. This can be used to access the id of an async relationship + without triggering a fetch that would normally happen if you + attempted to use `record.get('relationship.id')`. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } } } } - } - }); - let userRef = blog.belongsTo('user'); - - // get the identifier of the reference - if (userRef.remoteType() === "link") { - let link = userRef.link(); - } - ``` + }); + let userRef = blog.belongsTo('user'); - @method link - @return {String} The link Ember Data will use to fetch or reload this belongs-to relationship. -*/ -BelongsToReference.prototype.link = function() { - return this.belongsToRelationship.link; -}; + // get the identifier of the reference + if (userRef.remoteType() === "id") { + let id = userRef.id(); + } + ``` + + @method id + @return {String} The id of the record in this belongsTo relationship. + */ + id() { + let inverseInternalModel = this.belongsToRelationship.inverseInternalModel; + return inverseInternalModel && inverseInternalModel.id; + } -/** - The meta data for the belongs-to relationship. + /** + The link Ember Data will use to fetch or reload this belongs-to + relationship. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + links: { + related: '/articles/1/author' + } + } + } + } + }); + let userRef = blog.belongsTo('user'); - Example + // get the identifier of the reference + if (userRef.remoteType() === "link") { + let link = userRef.link(); + } + ``` - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); + @method link + @return {String} The link Ember Data will use to fetch or reload this belongs-to relationship. + */ + link() { + return this.belongsToRelationship.link; + } - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - links: { - related: { - href: '/articles/1/author', - meta: { - lastUpdated: 1458014400000 + /** + The meta data for the belongs-to relationship. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + links: { + related: { + href: '/articles/1/author', + meta: { + lastUpdated: 1458014400000 + } } } } } } - } - }); + }); - let userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); - userRef.meta() // { lastUpdated: 1458014400000 } - ``` + userRef.meta() // { lastUpdated: 1458014400000 } + ``` - @method meta - @return {Object} The meta information for the belongs-to relationship. -*/ -BelongsToReference.prototype.meta = function() { - return this.belongsToRelationship.meta; -}; - -/** - `push` can be used to update the data in the relationship and Ember - Data will treat the new data as the conanical value of this - relationship on the backend. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); + @method meta + @return {Object} The meta information for the belongs-to relationship. + */ + meta() { + return this.belongsToRelationship.meta; + } - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } + /** + `push` can be used to update the data in the relationship and Ember + Data will treat the new data as the conanical value of this + relationship on the backend. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } } } - } - }); - let userRef = blog.belongsTo('user'); - - // provide data for reference - userRef.push({ - data: { - type: 'user', - id: 1, - attributes: { - username: "@user" + }); + let userRef = blog.belongsTo('user'); + + // provide data for reference + userRef.push({ + data: { + type: 'user', + id: 1, + attributes: { + username: "@user" + } } + }).then(function(user) { + userRef.value() === user; + }); + ``` + + @method push + @param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. + @return {Promise} A promise that resolves with the new value in this belongs-to relationship. + */ + push(objectOrPromise) { + return resolve(objectOrPromise).then((data) => { + let record; + + if (data instanceof Model) { + if (isEnabled('ds-overhaul-references')) { + deprecate("BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead.", false, { + id: 'ds.references.belongs-to.push-record', + until: '4.0.0' + }); + } + record = data; + } else { + record = this.store.push(data); } - }).then(function(user) { - userRef.value() === user; - }); - ``` - - @method push - @param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. - @return {Promise} A promise that resolves with the new value in this belongs-to relationship. -*/ -BelongsToReference.prototype.push = function(objectOrPromise) { - return resolve(objectOrPromise).then((data) => { - let record; - - if (data instanceof Model) { - if (isEnabled('ds-overhaul-references')) { - deprecate("BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead.", false, { - id: 'ds.references.belongs-to.push-record', - until: '4.0.0' - }); - } - record = data; - } else { - record = this.store.push(data); - } - assertPolymorphicType(this.internalModel, this.belongsToRelationship.relationshipMeta, record._internalModel); + assertPolymorphicType(this.internalModel, this.belongsToRelationship.relationshipMeta, record._internalModel); - this.belongsToRelationship.setCanonicalInternalModel(record._internalModel); + this.belongsToRelationship.setCanonicalInternalModel(record._internalModel); - return record; - }); -}; - -/** - `value()` synchronously returns the current value of the belongs-to - relationship. Unlike `record.get('relationshipName')`, calling - `value()` on a reference does not trigger a fetch if the async - relationship is not yet loaded. If the relationship is not loaded - it will always return `null`. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) + return record; }); + } - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } + /** + `value()` synchronously returns the current value of the belongs-to + relationship. Unlike `record.get('relationshipName')`, calling + `value()` on a reference does not trigger a fetch if the async + relationship is not yet loaded. If the relationship is not loaded + it will always return `null`. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } } } - } - }); - let userRef = blog.belongsTo('user'); - - userRef.value(); // null - - // provide data for reference - userRef.push({ - data: { - type: 'user', - id: 1, - attributes: { - username: "@user" + }); + let userRef = blog.belongsTo('user'); + + userRef.value(); // null + + // provide data for reference + userRef.push({ + data: { + type: 'user', + id: 1, + attributes: { + username: "@user" + } } - } - }).then(function(user) { - userRef.value(); // user - }); - ``` - - @method value - @return {DS.Model} the record in this relationship -*/ -BelongsToReference.prototype.value = function() { - let inverseInternalModel = this.belongsToRelationship.inverseInternalModel; + }).then(function(user) { + userRef.value(); // user + }); + ``` + + @method value + @return {DS.Model} the record in this relationship + */ + value() { + let inverseInternalModel = this.belongsToRelationship.inverseInternalModel; + + if (inverseInternalModel && inverseInternalModel.isLoaded()) { + return inverseInternalModel.getRecord(); + } - if (inverseInternalModel && inverseInternalModel.isLoaded()) { - return inverseInternalModel.getRecord(); + return null; } - return null; -}; - -/** - Loads a record in a belongs to relationship if it is not already - loaded. If the relationship is already loaded this method does not - trigger a new load. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } + /** + Loads a record in a belongs to relationship if it is not already + loaded. If the relationship is already loaded this method does not + trigger a new load. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } } } - } - }); - let userRef = blog.belongsTo('user'); - - userRef.value(); // null - - userRef.load().then(function(user) { - userRef.value() === user - }); - ``` - - @method load - @return {Promise} a promise that resolves with the record in this belongs-to relationship. -*/ -BelongsToReference.prototype.load = function() { - if (this.remoteType() === "id") { - return this.belongsToRelationship.getRecord(); - } + }); + let userRef = blog.belongsTo('user'); + + userRef.value(); // null + + userRef.load().then(function(user) { + userRef.value() === user + }); + ``` + + @method load + @return {Promise} a promise that resolves with the record in this belongs-to relationship. + */ + load() { + if (this.remoteType() === "id") { + return this.belongsToRelationship.getRecord(); + } - if (this.remoteType() === "link") { - return this.belongsToRelationship.findLink().then((internalModel) => { - return this.value(); - }); + if (this.remoteType() === "link") { + return this.belongsToRelationship.findLink().then((internalModel) => { + return this.value(); + }); + } } -}; - -/** - Triggers a reload of the value in this relationship. If the - remoteType is `"link"` Ember Data will use the relationship link to - reload the relationship. Otherwise it will reload the record by its - id. - - Example - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } + /** + Triggers a reload of the value in this relationship. If the + remoteType is `"link"` Ember Data will use the relationship link to + reload the relationship. Otherwise it will reload the record by its + id. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } } } - } - }); - let userRef = blog.belongsTo('user'); - - userRef.reload().then(function(user) { - userRef.value() === user + }); + let userRef = blog.belongsTo('user'); + + userRef.reload().then(function(user) { + userRef.value() === user + }); + ``` + + @method reload + @return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed. + */ + reload() { + return this.belongsToRelationship.reload().then((internalModel) => { + return this.value(); }); - ``` - - @method reload - @return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed. -*/ -BelongsToReference.prototype.reload = function() { - return this.belongsToRelationship.reload().then((internalModel) => { - return this.value(); - }); -}; + } -export default BelongsToReference; +} diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 26ac78b45d9..a14a1bcbc42 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -15,428 +15,424 @@ import isEnabled from '../../features'; @class HasManyReference @namespace DS */ -const HasManyReference = function(store, parentInternalModel, hasManyRelationship) { - this._super$constructor(store, parentInternalModel); - this.hasManyRelationship = hasManyRelationship; - this.type = hasManyRelationship.relationshipMeta.type; - this.parent = parentInternalModel.recordReference; - - // TODO inverse -}; - -HasManyReference.prototype = Object.create(Reference.prototype); -HasManyReference.prototype.constructor = HasManyReference; -HasManyReference.prototype._super$constructor = Reference; +export default class HasManyReference extends Reference { + constructor(store, parentInternalModel, hasManyRelationship) { + super(store, parentInternalModel); + this.hasManyRelationship = hasManyRelationship; + this.type = hasManyRelationship.relationshipMeta.type; + this.parent = parentInternalModel.recordReference; + // TODO inverse + } -/** - This returns a string that represents how the reference will be - looked up when it is loaded. If the relationship has a link it will - use the "link" otherwise it defaults to "id". - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] + /** + This returns a string that represents how the reference will be + looked up when it is loaded. If the relationship has a link it will + use the "link" otherwise it defaults to "id". + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } } } - } - }); + }); - let commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); - // get the identifier of the reference - if (commentsRef.remoteType() === "ids") { - let ids = commentsRef.ids(); - } else if (commentsRef.remoteType() === "link") { - let link = commentsRef.link(); - } - ``` + // get the identifier of the reference + if (commentsRef.remoteType() === "ids") { + let ids = commentsRef.ids(); + } else if (commentsRef.remoteType() === "link") { + let link = commentsRef.link(); + } + ``` + + @method remoteType + @return {String} The name of the remote type. This should either be "link" or "ids" + */ + remoteType() { + if (this.hasManyRelationship.link) { + return "link"; + } - @method remoteType - @return {String} The name of the remote type. This should either be "link" or "ids" -*/ -HasManyReference.prototype.remoteType = function() { - if (this.hasManyRelationship.link) { - return "link"; + return "ids"; } - return "ids"; -}; - -/** - The link Ember Data will use to fetch or reload this has-many - relationship. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - links: { - related: '/posts/1/comments' + /** + The link Ember Data will use to fetch or reload this has-many + relationship. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + links: { + related: '/posts/1/comments' + } } } } - } - }); + }); - let commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); - commentsRef.link(); // '/posts/1/comments' - ``` + commentsRef.link(); // '/posts/1/comments' + ``` - @method link - @return {String} The link Ember Data will use to fetch or reload this has-many relationship. -*/ -HasManyReference.prototype.link = function() { - return this.hasManyRelationship.link; -}; + @method link + @return {String} The link Ember Data will use to fetch or reload this has-many relationship. + */ + link() { + return this.hasManyRelationship.link; + } -/** - `ids()` returns an array of the record ids in this relationship. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] + /** + `ids()` returns an array of the record ids in this relationship. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } } } - } - }); + }); - let commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); - commentsRef.ids(); // ['1'] - ``` + commentsRef.ids(); // ['1'] + ``` - @method ids - @return {Array} The ids in this has-many relationship -*/ -HasManyReference.prototype.ids = function() { - let members = this.hasManyRelationship.members.toArray(); + @method ids + @return {Array} The ids in this has-many relationship + */ + ids() { + let members = this.hasManyRelationship.members.toArray(); - return members.map(function(internalModel) { - return internalModel.id; - }); -}; + return members.map(function(internalModel) { + return internalModel.id; + }); + } -/** - The meta data for the has-many relationship. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - links: { - related: { - href: '/posts/1/comments', - meta: { - count: 10 + /** + The meta data for the has-many relationship. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + links: { + related: { + href: '/posts/1/comments', + meta: { + count: 10 + } } } } } } - } - }); + }); - let commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); - commentsRef.meta(); // { count: 10 } - ``` + commentsRef.meta(); // { count: 10 } + ``` - @method meta - @return {Object} The meta information for the has-many relationship. -*/ -HasManyReference.prototype.meta = function() { - return this.hasManyRelationship.meta; -}; + @method meta + @return {Object} The meta information for the has-many relationship. + */ + meta() { + return this.hasManyRelationship.meta; + } -/** - `push` can be used to update the data in the relationship and Ember - Data will treat the new data as the canonical value of this - relationship on the backend. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ``` - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] + /** + `push` can be used to update the data in the relationship and Ember + Data will treat the new data as the canonical value of this + relationship on the backend. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ``` + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } } } - } - }); + }); - let commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); - commentsRef.ids(); // ['1'] + commentsRef.ids(); // ['1'] - commentsRef.push([ - [{ type: 'comment', id: 2 }], - [{ type: 'comment', id: 3 }], - ]) + commentsRef.push([ + [{ type: 'comment', id: 2 }], + [{ type: 'comment', id: 3 }], + ]) - commentsRef.ids(); // ['2', '3'] - ``` - - @method push - @param {Array|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. - @return {DS.ManyArray} -*/ -HasManyReference.prototype.push = function(objectOrPromise) { - return resolve(objectOrPromise).then((payload) => { - let array = payload; - - if (isEnabled("ds-overhaul-references")) { - deprecate("HasManyReference#push(array) is deprecated. Push a JSON-API document instead.", !Array.isArray(payload), { - id: 'ds.references.has-many.push-array', - until: '4.0.0' - }); - } + commentsRef.ids(); // ['2', '3'] + ``` - let useLegacyArrayPush = true; - if (typeof payload === "object" && payload.data) { - array = payload.data; - useLegacyArrayPush = array.length && array[0].data; + @method push + @param {Array|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. + @return {DS.ManyArray} + */ + push(objectOrPromise) { + return resolve(objectOrPromise).then((payload) => { + let array = payload; - if (isEnabled('ds-overhaul-references')) { - deprecate("HasManyReference#push() expects a valid JSON-API document.", !useLegacyArrayPush, { - id: 'ds.references.has-many.push-invalid-json-api', + if (isEnabled("ds-overhaul-references")) { + deprecate("HasManyReference#push(array) is deprecated. Push a JSON-API document instead.", !Array.isArray(payload), { + id: 'ds.references.has-many.push-array', until: '4.0.0' }); } - } - - if (!isEnabled('ds-overhaul-references')) { - useLegacyArrayPush = true; - } - let internalModels; - if (useLegacyArrayPush) { - internalModels = array.map((obj) => { - let record = this.store.push(obj); + let useLegacyArrayPush = true; + if (typeof payload === "object" && payload.data) { + array = payload.data; + useLegacyArrayPush = array.length && array[0].data; - if (DEBUG) { - let relationshipMeta = this.hasManyRelationship.relationshipMeta; - assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel); + if (isEnabled('ds-overhaul-references')) { + deprecate("HasManyReference#push() expects a valid JSON-API document.", !useLegacyArrayPush, { + id: 'ds.references.has-many.push-invalid-json-api', + until: '4.0.0' + }); } + } + + if (!isEnabled('ds-overhaul-references')) { + useLegacyArrayPush = true; + } + + let internalModels; + if (useLegacyArrayPush) { + internalModels = array.map((obj) => { + let record = this.store.push(obj); - return record._internalModel; - }); - } else { - let records = this.store.push(payload); - internalModels = A(records).mapBy('_internalModel'); + if (DEBUG) { + let relationshipMeta = this.hasManyRelationship.relationshipMeta; + assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel); + } - if (DEBUG) { - internalModels.forEach((internalModel) => { - let relationshipMeta = this.hasManyRelationship.relationshipMeta; - assertPolymorphicType(this.internalModel, relationshipMeta, internalModel); + return record._internalModel; }); - } - } + } else { + let records = this.store.push(payload); + internalModels = A(records).mapBy('_internalModel'); - this.hasManyRelationship.computeChanges(internalModels); + if (DEBUG) { + internalModels.forEach((internalModel) => { + let relationshipMeta = this.hasManyRelationship.relationshipMeta; + assertPolymorphicType(this.internalModel, relationshipMeta, internalModel); + }); + } + } - return this.hasManyRelationship.manyArray; - }); -}; + this.hasManyRelationship.computeChanges(internalModels); -HasManyReference.prototype._isLoaded = function() { - let hasData = get(this.hasManyRelationship, 'hasData'); - if (!hasData) { - return false; + return this.hasManyRelationship.manyArray; + }); } - let members = this.hasManyRelationship.members.toArray(); + _isLoaded() { + let hasData = get(this.hasManyRelationship, 'hasData'); + if (!hasData) { + return false; + } - return members.every(function(internalModel) { - return internalModel.isLoaded() === true; - }); -}; + let members = this.hasManyRelationship.members.toArray(); -/** - `value()` synchronously returns the current value of the has-many - relationship. Unlike `record.get('relationshipName')`, calling - `value()` on a reference does not trigger a fetch if the async - relationship is not yet loaded. If the relationship is not loaded - it will always return `null`. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] + return members.every(function(internalModel) { + return internalModel.isLoaded() === true; + }); + } + + /** + `value()` synchronously returns the current value of the has-many + relationship. Unlike `record.get('relationshipName')`, calling + `value()` on a reference does not trigger a fetch if the async + relationship is not yet loaded. If the relationship is not loaded + it will always return `null`. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } } } - } - }); + }); - let commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); - post.get('comments').then(function(comments) { - commentsRef.value() === comments - }) - ``` + post.get('comments').then(function(comments) { + commentsRef.value() === comments + }) + ``` - @method value - @return {DS.ManyArray} -*/ -HasManyReference.prototype.value = function() { - if (this._isLoaded()) { - return this.hasManyRelationship.manyArray; - } + @method value + @return {DS.ManyArray} + */ + value() { + if (this._isLoaded()) { + return this.hasManyRelationship.manyArray; + } - return null; -}; + return null; + } -/** - Loads the relationship if it is not already loaded. If the - relationship is already loaded this method does not trigger a new - load. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] + /** + Loads the relationship if it is not already loaded. If the + relationship is already loaded this method does not trigger a new + load. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } } } - } - }); - - let commentsRef = post.hasMany('comments'); - - commentsRef.load().then(function(comments) { - //... - }); - ``` + }); + + let commentsRef = post.hasMany('comments'); + + commentsRef.load().then(function(comments) { + //... + }); + ``` + + @method load + @return {Promise} a promise that resolves with the ManyArray in + this has-many relationship. + */ + load() { + if (!this._isLoaded()) { + return this.hasManyRelationship.getRecords(); + } - @method load - @return {Promise} a promise that resolves with the ManyArray in - this has-many relationship. -*/ -HasManyReference.prototype.load = function() { - if (!this._isLoaded()) { - return this.hasManyRelationship.getRecords(); + return resolve(this.hasManyRelationship.manyArray); } - return resolve(this.hasManyRelationship.manyArray); -}; - -/** - Reloads this has-many relationship. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] + /** + Reloads this has-many relationship. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } } } - } - }); + }); - let commentsRef = post.hasMany('comments'); + let commentsRef = post.hasMany('comments'); - commentsRef.reload().then(function(comments) { - //... - }); - ``` + commentsRef.reload().then(function(comments) { + //... + }); + ``` - @method reload - @return {Promise} a promise that resolves with the ManyArray in this has-many relationship. -*/ -HasManyReference.prototype.reload = function() { - return this.hasManyRelationship.reload(); -}; + @method reload + @return {Promise} a promise that resolves with the ManyArray in this has-many relationship. + */ + reload() { + return this.hasManyRelationship.reload(); + } -export default HasManyReference; +} diff --git a/addon/-private/system/references/record.js b/addon/-private/system/references/record.js index 0583d13832a..086945b3a22 100644 --- a/addon/-private/system/references/record.js +++ b/addon/-private/system/references/record.js @@ -8,159 +8,156 @@ import Reference from './reference'; @class RecordReference @namespace DS */ -const RecordReference = function(store, internalModel) { - this._super$constructor(store, internalModel); - this.type = internalModel.modelName; - this._id = internalModel.id; -}; - -RecordReference.prototype = Object.create(Reference.prototype); -RecordReference.prototype.constructor = RecordReference; -RecordReference.prototype._super$constructor = Reference; +export default class RecordReference extends Reference { + constructor(store, internalModel) { + super(store, internalModel); + this.type = internalModel.modelName; + this._id = internalModel.id; + } -/** - The `id` of the record that this reference refers to. + /** + The `id` of the record that this reference refers to. - Together, the `type` and `id` properties form a composite key for - the identity map. + Together, the `type` and `id` properties form a composite key for + the identity map. - Example + Example - ```javascript - let userRef = store.getReference('user', 1); + ```javascript + let userRef = store.getReference('user', 1); - userRef.id(); // '1' - ``` + userRef.id(); // '1' + ``` - @method id - @return {String} The id of the record. -*/ -RecordReference.prototype.id = function() { - return this._id; -}; + @method id + @return {String} The id of the record. + */ + id() { + return this._id; + } -/** - How the reference will be looked up when it is loaded: Currently - this always return `identity` to signifying that a record will be - loaded by the `type` and `id`. + /** + How the reference will be looked up when it is loaded: Currently + this always return `identity` to signifying that a record will be + loaded by the `type` and `id`. - Example + Example - ```javascript - const userRef = store.getReference('user', 1); + ```javascript + const userRef = store.getReference('user', 1); - userRef.remoteType(); // 'identity' - ``` + userRef.remoteType(); // 'identity' + ``` - @method remoteType - @return {String} 'identity' -*/ -RecordReference.prototype.remoteType = function() { - return 'identity'; -}; + @method remoteType + @return {String} 'identity' + */ + remoteType() { + return 'identity'; + } -/** - This API allows you to provide a reference with new data. The - simplest usage of this API is similar to `store.push`: you provide a - normalized hash of data and the object represented by the reference - will update. - - If you pass a promise to `push`, Ember Data will not ask the adapter - for the data if another attempt to fetch it is made in the - interim. When the promise resolves, the underlying object is updated - with the new data, and the promise returned by *this function* is resolved - with that object. - - For example, `recordReference.push(promise)` will be resolved with a - record. - - Example - - ```javascript - let userRef = store.getReference('user', 1); - - // provide data for reference - userRef.push({ data: { id: 1, username: "@user" }}).then(function(user) { - userRef.value() === user; - }); - ``` - - @method push - @param objectOrPromise {Promise|Object} - @return Promise a promise for the value (record or relationship) -*/ -RecordReference.prototype.push = function(objectOrPromise) { - return resolve(objectOrPromise).then((data) => { - return this.store.push(data); - }); -}; + /** + This API allows you to provide a reference with new data. The + simplest usage of this API is similar to `store.push`: you provide a + normalized hash of data and the object represented by the reference + will update. + + If you pass a promise to `push`, Ember Data will not ask the adapter + for the data if another attempt to fetch it is made in the + interim. When the promise resolves, the underlying object is updated + with the new data, and the promise returned by *this function* is resolved + with that object. + + For example, `recordReference.push(promise)` will be resolved with a + record. + + Example + + ```javascript + let userRef = store.getReference('user', 1); + + // provide data for reference + userRef.push({ data: { id: 1, username: "@user" }}).then(function(user) { + userRef.value() === user; + }); + ``` + + @method push + @param objectOrPromise {Promise|Object} + @return Promise a promise for the value (record or relationship) + */ + push(objectOrPromise) { + return resolve(objectOrPromise).then((data) => { + return this.store.push(data); + }); + } -/** - If the entity referred to by the reference is already loaded, it is - present as `reference.value`. Otherwise the value returned by this function - is `null`. + /** + If the entity referred to by the reference is already loaded, it is + present as `reference.value`. Otherwise the value returned by this function + is `null`. - Example + Example - ```javascript - let userRef = store.getReference('user', 1); + ```javascript + let userRef = store.getReference('user', 1); - userRef.value(); // user - ``` + userRef.value(); // user + ``` - @method value - @return {DS.Model} the record for this RecordReference -*/ -RecordReference.prototype.value = function() { - if (this.internalModel.hasRecord) { - return this.internalModel.getRecord(); + @method value + @return {DS.Model} the record for this RecordReference + */ + value() { + if (this.internalModel.hasRecord) { + return this.internalModel.getRecord(); + } + return null; } - return null; -}; -/** - Triggers a fetch for the backing entity based on its `remoteType` - (see `remoteType` definitions per reference type). + /** + Triggers a fetch for the backing entity based on its `remoteType` + (see `remoteType` definitions per reference type). - Example + Example - ```javascript - let userRef = store.getReference('user', 1); + ```javascript + let userRef = store.getReference('user', 1); - // load user (via store.find) - userRef.load().then(...) - ``` + // load user (via store.find) + userRef.load().then(...) + ``` - @method load - @return {Promise} the record for this RecordReference -*/ -RecordReference.prototype.load = function() { - return this.store.findRecord(this.type, this._id); -}; + @method load + @return {Promise} the record for this RecordReference + */ + load() { + return this.store.findRecord(this.type, this._id); + } -/** - Reloads the record if it is already loaded. If the record is not - loaded it will load the record via `store.findRecord` + /** + Reloads the record if it is already loaded. If the record is not + loaded it will load the record via `store.findRecord` - Example + Example - ```javascript - let userRef = store.getReference('user', 1); + ```javascript + let userRef = store.getReference('user', 1); - // or trigger a reload - userRef.reload().then(...) - ``` + // or trigger a reload + userRef.reload().then(...) + ``` - @method reload - @return {Promise} the record for this RecordReference -*/ -RecordReference.prototype.reload = function() { - let record = this.value(); - if (record) { - return record.reload(); - } + @method reload + @return {Promise} the record for this RecordReference + */ + reload() { + let record = this.value(); + if (record) { + return record.reload(); + } - return this.load(); -}; + return this.load(); + } -export default RecordReference; +} From 09f9c7ecd104334bf7b7a75737a0183a26184dad Mon Sep 17 00:00:00 2001 From: Bryan Date: Wed, 28 Feb 2018 19:07:37 +0000 Subject: [PATCH 2133/2527] remove private API calls (changeProperties is mistakenly marked as private but is in fact public) (#5365) --- addon/-private/system/model/model.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 9e2dad3953b..08115b2095d 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -8,7 +8,6 @@ import EmberObject, { observer } from '@ember/object'; import Map from '@ember/map'; -import Ember from 'ember'; import { DEBUG } from '@glimmer/env'; import { assert, warn } from '@ember/debug'; import { PromiseObject } from "../promise-proxies"; @@ -21,6 +20,9 @@ import { relationshipsDescriptor } from '../relationships/ext'; +import Ember from 'ember'; +const { changeProperties } = Ember; + /** @module ember-data */ @@ -635,13 +637,16 @@ const Model = EmberObject.extend(Evented, { @private */ _notifyProperties(keys) { - Ember.beginPropertyChanges(); - let key; - for (let i = 0, length = keys.length; i < length; i++) { - key = keys[i]; - this.notifyPropertyChange(key); - } - Ember.endPropertyChanges(); + // changeProperties defers notifications until after the delegate + // and protects with a try...finally block + // previously used begin...endPropertyChanges but this is private API + changeProperties(() => { + let key; + for (let i = 0, length = keys.length; i < length; i++) { + key = keys[i]; + this.notifyPropertyChange(key); + } + }); }, /** From b93b3e732956786dadb0ead029c236c3d1b0941f Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 28 Feb 2018 11:49:20 -0800 Subject: [PATCH 2134/2527] [BUGFIX] enable lazy-relationship payloads to work with polymorphic relationships (#5230) * [BUGFIX] enable lazy-relationship payloads to work with polymorphic relationships --- addon/-private/system/model/model.js | 4 + addon/-private/system/relationship-meta.js | 11 +- .../relationship-payloads-manager.js | 197 ++++- .../relationships/relationship-payloads.js | 304 ++++--- .../relationships/belongs-to-test.js | 4 +- .../relationships/has-many-test.js | 5 +- .../polymorphic-relationship-payloads-test.js | 825 ++++++++++++++++++ .../relationship-payload-manager-test.js | 56 +- 8 files changed, 1191 insertions(+), 215 deletions(-) create mode 100644 tests/unit/system/relationships/polymorphic-relationship-payloads-test.js diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 08115b2095d..d91dc663484 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1912,6 +1912,10 @@ if (DEBUG) { // the computed property. let meta = value.meta(); + /* + This is buggy because if the parent has never been looked up + via `modelFor` it will not have `modelName` set. + */ meta.parentType = proto.constructor; } } diff --git a/addon/-private/system/relationship-meta.js b/addon/-private/system/relationship-meta.js index 740eff604ee..3f10d7c6265 100644 --- a/addon/-private/system/relationship-meta.js +++ b/addon/-private/system/relationship-meta.js @@ -1,6 +1,5 @@ import { singularize } from 'ember-inflector'; import normalizeModelName from './normalize-model-name'; -import { DEBUG } from '@glimmer/env'; export function typeForRelationshipMeta(meta) { let modelName; @@ -13,19 +12,13 @@ export function typeForRelationshipMeta(meta) { } export function relationshipFromMeta(meta) { - let result = { + return { key: meta.key, kind: meta.kind, type: typeForRelationshipMeta(meta), - options: meta.options, + options: meta.options, name: meta.name, parentType: meta.parentType, isRelationship: true }; - - if (DEBUG) { - result.parentType = meta.parentType; - } - - return result; } diff --git a/addon/-private/system/relationships/relationship-payloads-manager.js b/addon/-private/system/relationships/relationship-payloads-manager.js index 3bf03430a0b..f64e976fe0a 100644 --- a/addon/-private/system/relationships/relationship-payloads-manager.js +++ b/addon/-private/system/relationships/relationship-payloads-manager.js @@ -1,5 +1,7 @@ import { get } from '@ember/object'; -import RelationshipPayloads from './relationship-payloads'; +// import { DEBUG } from '@glimmer/env'; +import { assert } from '@ember/debug'; +import { default as RelationshipPayloads, TypeCache } from './relationship-payloads'; /** Manages relationship payloads for a given store, for uninitialized @@ -59,6 +61,7 @@ export default class RelationshipPayloadsManager { this._store = store; // cache of `RelationshipPayload`s this._cache = Object.create(null); + this._inverseLookupCache = new TypeCache(); } /** @@ -81,9 +84,7 @@ export default class RelationshipPayloadsManager { @method */ get(modelName, id, relationshipName) { - let modelClass = this._store._modelFor(modelName); - let relationshipsByName = get(modelClass, 'relationshipsByName'); - let relationshipPayloads = this._getRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName, false); + let relationshipPayloads = this._getRelationshipPayloads(modelName, relationshipName, false); return relationshipPayloads && relationshipPayloads.get(modelName, id, relationshipName); } @@ -113,10 +114,8 @@ export default class RelationshipPayloadsManager { push(modelName, id, relationshipsData) { if (!relationshipsData) { return; } - let modelClass = this._store._modelFor(modelName); - let relationshipsByName = get(modelClass, 'relationshipsByName'); Object.keys(relationshipsData).forEach(key => { - let relationshipPayloads = this._getRelationshipPayloads(modelName, key, modelClass, relationshipsByName, true); + let relationshipPayloads = this._getRelationshipPayloads(modelName, key, true); if (relationshipPayloads) { relationshipPayloads.push(modelName, id, key, relationshipsData[key]); } @@ -132,7 +131,7 @@ export default class RelationshipPayloadsManager { let modelClass = this._store._modelFor(modelName); let relationshipsByName = get(modelClass, 'relationshipsByName'); relationshipsByName.forEach((_, relationshipName) => { - let relationshipPayloads = this._getRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName, false); + let relationshipPayloads = this._getRelationshipPayloads(modelName, relationshipName, false); if (relationshipPayloads) { relationshipPayloads.unload(modelName, id, relationshipName); } @@ -156,7 +155,7 @@ export default class RelationshipPayloadsManager { relationshipPayloads.get('user', 'hobbies') === relationshipPayloads.get('hobby', 'user'); The signature has a somewhat large arity to avoid extra work, such as - a) string maipulation & allocation with `modelName` and + a) string manipulation & allocation with `modelName` and `relationshipName` b) repeatedly getting `relationshipsByName` via `Ember.get` @@ -164,15 +163,131 @@ export default class RelationshipPayloadsManager { @private @method */ - _getRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName, init) { - if (!relationshipsByName.has(relationshipName)) { return; } + _getRelationshipPayloads(modelName, relationshipName, init) { + let relInfo = this.getRelationshipInfo(modelName, relationshipName); + + if (relInfo === null) { + return; + } + + let cache = this._cache[relInfo.lhs_key]; + + if (!cache && init) { + return this._initializeRelationshipPayloads(relInfo); + } + + return cache; + } + + getRelationshipInfo(modelName, relationshipName) { + let inverseCache = this._inverseLookupCache; + let store = this._store; + let cached = inverseCache.get(modelName, relationshipName); + + // CASE: We have a cached resolution (null if no relationship exists) + if (cached !== undefined) { + return cached; + } + + let modelClass = store._modelFor(modelName); + let relationshipsByName = get(modelClass, 'relationshipsByName'); + + // CASE: We don't have a relationship at all + if (!relationshipsByName.has(relationshipName)) { + inverseCache.set(modelName, relationshipName, null); + return null; + } + + let inverseMeta = modelClass.inverseFor(relationshipName, store); + let relationshipMeta = relationshipsByName.get(relationshipName); + let selfIsPolymorphic = relationshipMeta.options !== undefined && relationshipMeta.options.polymorphic === true; + let inverseBaseModelName = relationshipMeta.type; + + // CASE: We have no inverse + if (!inverseMeta) { + let info = { + lhs_key: `${modelName}:${relationshipName}`, + lhs_modelNames: [modelName], + lhs_baseModelName: modelName, + lhs_relationshipName: relationshipName, + lhs_relationshipMeta: relationshipMeta, + lhs_isPolymorphic: selfIsPolymorphic, + rhs_key: '', + rhs_modelNames: [], + rhs_baseModelName: inverseBaseModelName, + rhs_relationshipName: '', + rhs_relationshipMeta: null, + rhs_isPolymorphic: false, + hasInverse: false, + isSelfReferential: false, // modelName === inverseBaseModelName, + isReflexive: false + }; + + inverseCache.set(modelName, relationshipName, info); + + return info; + } + + // CASE: We do have an inverse - let key = `${modelName}:${relationshipName}`; - if (!this._cache[key] && init) { - return this._initializeRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName); + let inverseRelationshipName = inverseMeta.name; + let inverseRelationshipMeta = get(inverseMeta.type, 'relationshipsByName').get(inverseRelationshipName); + let baseModelName = inverseRelationshipMeta.type; + let isSelfReferential = baseModelName === inverseBaseModelName; + + // TODO we want to assert this but this breaks all of our shoddily written tests + /* + if (DEBUG) { + let inverseDoubleCheck = inverseMeta.type.inverseFor(inverseRelationshipName, store); + + assert(`The ${inverseBaseModelName}:${inverseRelationshipName} relationship declares 'inverse: null', but it was resolved as the inverse for ${baseModelName}:${relationshipName}.`, inverseDoubleCheck); + } + */ + + // CASE: We may have already discovered the inverse for the baseModelName + // CASE: We have already discovered the inverse + cached = inverseCache.get(baseModelName, relationshipName) || + inverseCache.get(inverseBaseModelName, inverseRelationshipName); + if (cached) { + // TODO this assert can be removed if the above assert is enabled + assert(`The ${inverseBaseModelName}:${inverseRelationshipName} relationship declares 'inverse: null', but it was resolved as the inverse for ${baseModelName}:${relationshipName}.`, cached.hasInverse !== false); + + let isLHS = cached.lhs_baseModelName === baseModelName; + let modelNames = isLHS ? cached.lhs_modelNames : cached.rhs_modelNames; + // make this lookup easier in the future by caching the key + modelNames.push(modelName); + inverseCache.set(modelName, relationshipName, cached); + + return cached; } - return this._cache[key]; + let info = { + lhs_key: `${baseModelName}:${relationshipName}`, + lhs_modelNames: [modelName], + lhs_baseModelName: baseModelName, + lhs_relationshipName: relationshipName, + lhs_relationshipMeta: relationshipMeta, + lhs_isPolymorphic: selfIsPolymorphic, + rhs_key: `${inverseBaseModelName}:${inverseRelationshipName}`, + rhs_modelNames: [], + rhs_baseModelName: inverseBaseModelName, + rhs_relationshipName: inverseRelationshipName, + rhs_relationshipMeta: inverseRelationshipMeta, + rhs_isPolymorphic: inverseRelationshipMeta.options !== undefined && inverseRelationshipMeta.options.polymorphic === true, + hasInverse: true, + isSelfReferential, + isReflexive: isSelfReferential && relationshipName === inverseRelationshipName + }; + + // Create entries for the baseModelName as well as modelName to speed up + // inverse lookups + inverseCache.set(baseModelName, relationshipName, info); + inverseCache.set(modelName, relationshipName, info); + + // Greedily populate the inverse + inverseCache.set(inverseBaseModelName, inverseRelationshipName, info); + + return info; } /** @@ -181,29 +296,19 @@ export default class RelationshipPayloadsManager { @private @method */ - _initializeRelationshipPayloads(modelName, relationshipName, modelClass, relationshipsByName) { - let relationshipMeta = relationshipsByName.get(relationshipName); - let inverseMeta = modelClass.inverseFor(relationshipName, this._store); - - let inverseModelName; - let inverseRelationshipName; - let inverseRelationshipMeta; - - // figure out the inverse relationship; we need two things - // a) the inverse model name - //- b) the name of the inverse relationship - if (inverseMeta) { - inverseRelationshipName = inverseMeta.name - inverseModelName = relationshipMeta.type; - inverseRelationshipMeta = get(inverseMeta.type, 'relationshipsByName').get(inverseRelationshipName); - } else { - // relationship has no inverse - inverseModelName = inverseRelationshipName = ''; - inverseRelationshipMeta = null; - } + _initializeRelationshipPayloads(relInfo) { + let lhsKey = relInfo.lhs_key; + let rhsKey = relInfo.rhs_key; + let existingPayloads = this._cache[lhsKey]; + + if (relInfo.hasInverse === true && relInfo.rhs_isPolymorphic === true) { + existingPayloads = this._cache[rhsKey]; - let lhsKey = `${modelName}:${relationshipName}`; - let rhsKey = `${inverseModelName}:${inverseRelationshipName}`; + if (existingPayloads !== undefined) { + this._cache[lhsKey] = existingPayloads; + return existingPayloads; + } + } // populate the cache for both sides of the relationship, as they both use // the same `RelationshipPayloads`. @@ -211,16 +316,12 @@ export default class RelationshipPayloadsManager { // This works out better than creating a single common key, because to // compute that key we would need to do work to look up the inverse // - return this._cache[lhsKey] = - this._cache[rhsKey] = - new RelationshipPayloads( - this._store, - modelName, - relationshipName, - relationshipMeta, - inverseModelName, - inverseRelationshipName, - inverseRelationshipMeta - ); + let cache = this._cache[lhsKey] = new RelationshipPayloads(relInfo); + + if (relInfo.hasInverse === true) { + this._cache[rhsKey] = cache; + } + + return cache; } } diff --git a/addon/-private/system/relationships/relationship-payloads.js b/addon/-private/system/relationships/relationship-payloads.js index d0815007048..4233d461cbe 100644 --- a/addon/-private/system/relationships/relationship-payloads.js +++ b/addon/-private/system/relationships/relationship-payloads.js @@ -1,22 +1,56 @@ import { assert } from '@ember/debug'; +// TODO this is now VERY similar to the identity/internal-model map +// so we should probably generalize +export class TypeCache { + constructor() { + this.types = Object.create(null); + } + get(modelName, id) { + let { types } = this; + + if (types[modelName] !== undefined) { + return types[modelName][id]; + } + } + + set(modelName, id, payload) { + let { types } = this; + let typeMap = types[modelName]; + + if (typeMap === undefined) { + typeMap = types[modelName] = Object.create(null); + } + + typeMap[id] = payload; + } + + delete(modelName, id) { + let { types } = this; + + if (types[modelName] !== undefined) { + delete types[modelName][id]; + } + } +} + /** - Manages the payloads for both sides of a single relationship, across all model - instances. + Manages the payloads for both sides of a single relationship, across all model + instances. - For example, with + For example, with - const User = DS.Model.extend({ + const User = DS.Model.extend({ hobbies: DS.hasMany('hobby') }); - const Hobby = DS.Model.extend({ + const Hobby = DS.Model.extend({ user: DS.belongsTo('user') }); - let relationshipPayloads = new RelationshipPayloads('user', 'hobbies', 'hobby', 'user'); + let relationshipPayloads = new RelationshipPayloads('user', 'hobbies', 'hobby', 'user'); - let userPayload = { + let userPayload = { data: { id: 1, type: 'user', @@ -31,44 +65,22 @@ import { assert } from '@ember/debug'; } }; - // here we expect the payload of the individual relationship - relationshipPayloads.push('user', 1, 'hobbies', userPayload.data.relationships.hobbies); + // here we expect the payload of the individual relationship + relationshipPayloads.push('user', 1, 'hobbies', userPayload.data.relationships.hobbies); - relationshipPayloads.get('user', 1, 'hobbies'); - relationshipPayloads.get('hobby', 2, 'user'); + relationshipPayloads.get('user', 1, 'hobbies'); + relationshipPayloads.get('hobby', 2, 'user'); - @class RelationshipPayloads - @private -*/ + @class RelationshipPayloads + @private + */ export default class RelationshipPayloads { - constructor(store, modelName, relationshipName, relationshipMeta, inverseModelName, inverseRelationshipName, inverseRelationshipMeta) { - this._store = store; - - this._lhsModelName = modelName; - this._lhsRelationshipName = relationshipName; - this._lhsRelationshipMeta = relationshipMeta; - - this._rhsModelName = inverseModelName; - this._rhsRelationshipName = inverseRelationshipName; - this._rhsRelationshipMeta = inverseRelationshipMeta; + constructor(relInfo) { + this._relInfo = relInfo; // a map of id -> payloads for the left hand side of the relationship. - this._lhsPayloads = Object.create(null); - if (modelName !== inverseModelName || relationshipName !== inverseRelationshipName) { - // The common case of a non-reflexive relationship, or a reflexive - // relationship whose inverse is not itself - this._rhsPayloads = Object.create(null); - this._isReflexive = false; - } else { - // Edge case when we have a reflexive relationship to itself - // eg user hasMany friends inverse friends - // - // In this case there aren't really two sides to the relationship, but - // we set `_rhsPayloads = _lhsPayloads` to make things easier to reason - // about - this._rhsPayloads = this._lhsPayloads; - this._isReflexive = true; - } + this.lhs_payloads = new TypeCache(); + this.rhs_payloads = relInfo.isReflexive ? this.lhs_payloads : new TypeCache(); // When we push relationship payloads, just stash them in a queue until // somebody actually asks for one of them. @@ -79,71 +91,91 @@ export default class RelationshipPayloads { } /** - Get the payload for the relationship of an individual record. + Get the payload for the relationship of an individual record. - This might return the raw payload as pushed into the store, or one computed - from the payload of the inverse relationship. + This might return the raw payload as pushed into the store, or one computed + from the payload of the inverse relationship. - @method - */ + @method + */ get(modelName, id, relationshipName) { this._flushPending(); if (this._isLHS(modelName, relationshipName)) { - return this._lhsPayloads[id]; + return this.lhs_payloads.get(modelName, id); } else { - assert(`${modelName}:${relationshipName} is not either side of this relationship, ${this._lhsModelName}:${this._lhsRelationshipName}<->${this._rhsModelName}:${this._rhsRelationshipName}`, this._isRHS(modelName, relationshipName)); - return this._rhsPayloads[id]; + assert(`${modelName}:${relationshipName} is not either side of this relationship, ${this._relInfo.lhs_key}<->${this._relInfo.rhs_key}`, this._isRHS(modelName, relationshipName)); + return this.rhs_payloads.get(modelName, id); } } /** - Push a relationship payload for an individual record. + Push a relationship payload for an individual record. - This will make the payload available later for both this relationship and its inverse. + This will make the payload available later for both this relationship and its inverse. - @method - */ + @method + */ push(modelName, id, relationshipName, relationshipData) { this._pendingPayloads.push([modelName, id, relationshipName, relationshipData]); } /** - Unload the relationship payload for an individual record. + Unload the relationship payload for an individual record. - This does not unload the inverse relationship payload. + This does not unload the inverse relationship payload. - @method - */ + @method + */ unload(modelName, id, relationshipName) { this._flushPending(); if (this._isLHS(modelName, relationshipName)) { - delete this._lhsPayloads[id]; + delete this.lhs_payloads.delete(modelName, id); } else { - assert(`${modelName}:${relationshipName} is not either side of this relationship, ${this._lhsModelName}:${this._lhsRelationshipName}<->${this._rhsModelName}:${this._rhsRelationshipName}`, this._isRHS(modelName, relationshipName)); - delete this._rhsPayloads[id]; + assert(`${modelName}:${relationshipName} is not either side of this relationship, ${this._relInfo.lhs_baseModelName}:${this._relInfo.lhs_relationshipName}<->${this._relInfo.rhs_baseModelName}:${this._relInfo.rhs_relationshipName}`, this._isRHS(modelName, relationshipName)); + delete this.rhs_payloads.delete(modelName, id); } } /** - @return {boolean} true iff `modelName` and `relationshipName` refer to the - left hand side of this relationship, as opposed to the right hand side. + @return {boolean} true iff `modelName` and `relationshipName` refer to the + left hand side of this relationship, as opposed to the right hand side. - @method - */ + @method + */ _isLHS(modelName, relationshipName) { - return modelName === this._lhsModelName && relationshipName === this._lhsRelationshipName; + let relInfo = this._relInfo; + let isSelfReferential = relInfo.isSelfReferential; + let isRelationship = relationshipName === relInfo.lhs_relationshipName; + + if (isRelationship === true) { + return isSelfReferential === true || // itself + modelName === relInfo.lhs_baseModelName || // base or non-polymorphic + relInfo.lhs_modelNames.indexOf(modelName) !== -1; // polymorphic + } + + return false; } /** - @return {boolean} true iff `modelName` and `relationshipName` refer to the - right hand side of this relationship, as opposed to the left hand side. + @return {boolean} true iff `modelName` and `relationshipName` refer to the + right hand side of this relationship, as opposed to the left hand side. - @method - */ + @method + */ _isRHS(modelName, relationshipName) { - return modelName === this._rhsModelName && relationshipName === this._rhsRelationshipName; + let relInfo = this._relInfo; + let isSelfReferential = relInfo.isSelfReferential; + let isRelationship = relationshipName === relInfo.rhs_relationshipName; + + if (isRelationship === true) { + return isSelfReferential === true || // itself + modelName === relInfo.rhs_baseModelName || // base or non-polymorphic + relInfo.rhs_modelNames.indexOf(modelName) !== -1; // polymorphic + } + + return false; } _flushPending() { @@ -162,26 +194,27 @@ export default class RelationshipPayloads { id: id, type: modelName } - } + }; // start flushing this individual payload. The logic is the same whether // it's for the left hand side of the relationship or the right hand side, // except the role of primary and inverse idToPayloads is reversed // let previousPayload; - let idToPayloads; - let inverseIdToPayloads; + let payloadMap; + let inversePayloadMap; let inverseIsMany; + if (this._isLHS(modelName, relationshipName)) { - previousPayload = this._lhsPayloads[id]; - idToPayloads = this._lhsPayloads; - inverseIdToPayloads = this._rhsPayloads; + previousPayload = this.lhs_payloads.get(modelName, id); + payloadMap = this.lhs_payloads; + inversePayloadMap = this.rhs_payloads; inverseIsMany = this._rhsRelationshipIsMany; } else { - assert(`${modelName}:${relationshipName} is not either side of this relationship, ${this._lhsModelName}:${this._lhsRelationshipName}<->${this._rhsModelName}:${this._rhsRelationshipName}`, this._isRHS(modelName, relationshipName)); - previousPayload = this._rhsPayloads[id]; - idToPayloads = this._rhsPayloads; - inverseIdToPayloads = this._lhsPayloads; + assert(`${modelName}:${relationshipName} is not either side of this relationship, ${this._relInfo.lhs_key}<->${this._relInfo.rhs_key}`, this._isRHS(modelName, relationshipName)); + previousPayload = this.rhs_payloads.get(modelName, id); + payloadMap = this.rhs_payloads; + inversePayloadMap = this.lhs_payloads; inverseIsMany = this._lhsRelationshipIsMany; } @@ -225,24 +258,24 @@ export default class RelationshipPayloads { // * undefined is NOT considered new information, we should keep original state // * anything else is considered new information, and it should win if (relationshipData.data !== undefined) { - this._removeInverse(id, previousPayload, inverseIdToPayloads); + this._removeInverse(id, previousPayload, inversePayloadMap); } - idToPayloads[id] = relationshipData; - this._populateInverse(relationshipData, inverseRelationshipData, inverseIdToPayloads, inverseIsMany); + payloadMap.set(modelName, id, relationshipData); + this._populateInverse(relationshipData, inverseRelationshipData, inversePayloadMap, inverseIsMany); } } /** - Populate the inverse relationship for `relationshipData`. + Populate the inverse relationship for `relationshipData`. - If `relationshipData` is an array (eg because the relationship is hasMany) - this means populate each inverse, otherwise populate only the single - inverse. + If `relationshipData` is an array (eg because the relationship is hasMany) + this means populate each inverse, otherwise populate only the single + inverse. - @private - @method - */ - _populateInverse(relationshipData, inversePayload, inverseIdToPayloads, inverseIsMany) { + @private + @method + */ + _populateInverse(relationshipData, inversePayload, inversePayloadMap, inverseIsMany) { if (!relationshipData.data) { // This id doesn't have an inverse, eg a belongsTo with a payload // { data: null }, so there's nothing to populate @@ -251,33 +284,35 @@ export default class RelationshipPayloads { if (Array.isArray(relationshipData.data)) { for (let i=0; i.friends = [{ id: 1, type: 'user' }] return; } - let existingPayload = inverseIdToPayloads[inverseId]; + let existingPayload = inversePayloadMap.get(resourceIdentifier.type, resourceIdentifier.id); let existingData = existingPayload && existingPayload.data; if (existingData) { @@ -287,38 +322,40 @@ export default class RelationshipPayloads { if (Array.isArray(existingData)) { existingData.push(inversePayload.data); } else { - inverseIdToPayloads[inverseId] = inversePayload; + inversePayloadMap.set(resourceIdentifier.type, resourceIdentifier.id, inversePayload); } } else { // first time we're populating the inverse side // if (inverseIsMany) { - inverseIdToPayloads[inverseId] = { + inversePayloadMap.set(resourceIdentifier.type, resourceIdentifier.id, { data: [inversePayload.data] - } + }); } else { - inverseIdToPayloads[inverseId] = inversePayload; + inversePayloadMap.set(resourceIdentifier.type, resourceIdentifier.id, inversePayload); } } } get _lhsRelationshipIsMany() { - return this._lhsRelationshipMeta && this._lhsRelationshipMeta.kind === 'hasMany'; + let meta = this._relInfo.lhs_relationshipMeta; + return meta !== null && meta.kind === 'hasMany'; } get _rhsRelationshipIsMany() { - return this._rhsRelationshipMeta && this._rhsRelationshipMeta.kind === 'hasMany'; + let meta = this._relInfo.rhs_relationshipMeta; + return meta !== null && meta.kind === 'hasMany'; } /** - Remove the relationship in `previousPayload` from its inverse(s), because - this relationship payload has just been updated (eg because the same - relationship had multiple payloads pushed before the relationship was - initialized). - - @method - */ - _removeInverse(id, previousPayload, inverseIdToPayloads) { + Remove the relationship in `previousPayload` from its inverse(s), because + this relationship payload has just been updated (eg because the same + relationship had multiple payloads pushed before the relationship was + initialized). + + @method + */ + _removeInverse(id, previousPayload, inversePayloadMap) { let data = previousPayload && previousPayload.data; if (!data) { // either this is the first time we've seen a payload for this id, or its @@ -333,22 +370,23 @@ export default class RelationshipPayloads { if (Array.isArray(data)) { // TODO: diff rather than removeall addall? for (let i=0; i x.id !== id); } else { - inversePayloads[inverseId] = { + inversePayloads.set(resourceIdentifier.type, resourceIdentifier.id, { data: null - }; + }); } } } diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index f10d71fa0b1..236dd9f3ff2 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -32,12 +32,12 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { Post = Message.extend({ title: attr('string'), - comments: hasMany('comment', { async: false }) + comments: hasMany('comment', { async: false, inverse: null }) }); Comment = Message.extend({ body: DS.attr('string'), - message: DS.belongsTo('message', { polymorphic: true, async: false }) + message: DS.belongsTo('message', { polymorphic: true, async: false, inverse: null }) }); Book = DS.Model.extend({ diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index aa70c8e36b4..fa16f5dc5a2 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -3159,7 +3159,10 @@ test("PromiseArray proxies createRecord to its ManyArray before the hasMany is l test("deleteRecord + unloadRecord fun", function(assert) { User.reopen({ - posts: DS.hasMany('posts', { inverse: null }) + posts: DS.hasMany('post', { inverse: null }) + }); + Post.reopen({ + user: DS.belongsTo('user', { inverse: null, async: false }) }); run(() => { diff --git a/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js b/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js new file mode 100644 index 00000000000..b1398af49b0 --- /dev/null +++ b/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js @@ -0,0 +1,825 @@ +import { run } from '@ember/runloop'; +import { copy } from '@ember/object/internals'; +import { RelationshipPayloadsManager } from 'ember-data/-private'; +import DS from 'ember-data'; +import { createStore } from 'dummy/tests/helpers/store'; +import { module, test } from 'qunit'; +import testInDebug from '../../../helpers/test-in-debug'; + +const { Model, hasMany, belongsTo, attr } = DS; + +module('unit/system/relationships/relationship-payloads-manager (polymorphic)', { + beforeEach() { + const User = DS.Model.extend({ + hats: hasMany('hat', { async: false, polymorphic: true, inverse: 'user' }), + sharedHats: hasMany('hat', { async: false, polymorphic: true, inverse: 'sharingUsers' }) + }); + User.toString = () => 'User'; + + const Alien = User.extend({}); + Alien.toString = () => 'Alien'; + + const Hat = Model.extend({ + type: attr('string'), + user: belongsTo('user', { async: false, inverse: 'hats', polymorphic: true }), + sharingUsers: belongsTo('users', { async: false, inverse: 'sharedHats', polymorphic: true }), + hat: belongsTo('hat', { async: false, inverse: 'hats', polymorphic: true }), + hats: hasMany('hat', { async: false, inverse: 'hat', polymorphic: true }) + }); + const BigHat = Hat.extend({}); + const SmallHat = Hat.extend({}); + + let store = this.store = createStore({ + user: User, + alien: Alien, + hat: Hat, + 'big-hat': BigHat, + 'small-hat': SmallHat + }); + + this.relationshipPayloadsManager = new RelationshipPayloadsManager(store); + } +}); + +test('push one side is polymorphic, baseType then subTypes', function(assert) { + let id = 1; + + function makeHat(type, props) { + const resource = copy(props, true); + resource.id = `${id++}`; + resource.type = type; + resource.attributes.type = type; + return resource; + } + + const hatData = { + attributes: {}, + relationships: { + user: { + data: { id: '1' , type: 'user' } + } + } + }; + + const hatData1 = makeHat('hat', hatData), + bigHatData1 = makeHat('big-hat', hatData), + smallHatData1 = makeHat('small-hat', hatData); + + const userData = { + data: { + id: '1', + type: 'user', + attributes: {} + }, + included: [ + hatData1, + bigHatData1, + smallHatData1 + ] + }; + + const user = run(() => this.store.push(userData)); + + const finalResult = user.get('hats').mapBy('type'); + + assert.deepEqual(finalResult, ['hat', 'big-hat', 'small-hat'], 'We got all our hats!'); +}); + +test('push one side is polymorphic, subType then baseType', function(assert) { + let id = 1; + + function makeHat(type, props) { + const resource = copy(props, true); + resource.id = `${id++}`; + resource.type = type; + resource.attributes.type = type; + return resource; + } + + const hatData = { + attributes: {}, + relationships: { + user: { + data: { id: '1' , type: 'user' } + } + } + }; + + const bigHatData1 = makeHat('hat', hatData), + smallHatData1 = makeHat('small-hat', hatData), + hatData1 = makeHat('big-hat', hatData), + included = [bigHatData1, smallHatData1, hatData1]; + + const userData = { + data: { + id: '1', + type: 'user', + attributes: {} + }, + included + }; + + const user = run(() => this.store.push(userData)), + finalResult = user.get('hats').mapBy('type'), + expectedResults = included.map(m=>m.type); + + assert.deepEqual(finalResult, expectedResults, 'We got all our hats!'); +}); + +test('push one side is polymorphic, different subtypes', function(assert) { + let id = 1; + + function makeHat(type, props) { + const resource = copy(props, true); + resource.id = `${id++}`; + resource.type = type; + resource.attributes.type = type; + return resource; + } + + const hatData = { + attributes:{}, + relationships: { + user: { + data: { id: '1' , type: 'user' } + } + } + }; + + const bigHatData1 = makeHat('big-hat', hatData), + smallHatData1 = makeHat('small-hat', hatData), + bigHatData2 = makeHat('big-hat', hatData), + smallHatData2 = makeHat('small-hat', hatData), + included = [ + bigHatData1, + smallHatData1, + bigHatData2, + smallHatData2 + ]; + + const userData = { + data: { + id: '1', + type: 'user', + attributes: {} + }, + included + }; + + const user = run(() => this.store.push(userData)), + finalResult = user.get('hats').mapBy('type'), + expectedResults = included.map(m => m.type); + + assert.deepEqual(finalResult, expectedResults, 'We got all our hats!'); +}); + +test('push both sides are polymorphic', function(assert) { + let id = 1; + + function makeHat(type, props) { + const resource = copy(props, true); + resource.id = `${id++}`; + resource.type = type; + resource.attributes.type = type; + return resource; + } + + const alienHatData = { + attributes: {}, + relationships: { + user: { + data: { id: '1' , type: 'alien' } + } + } + }; + + const bigHatData1 = makeHat('hat', alienHatData), + hatData1 = makeHat('big-hat', alienHatData), + alienIncluded = [bigHatData1, hatData1]; + + const alienData = { + data: { + id: '1', + type: 'alien', + attributes: {} + }, + included: alienIncluded + }; + + const expectedAlienResults = alienIncluded.map(m => m.type), + alien = run(() => this.store.push(alienData)), + alienFinalHats = alien.get('hats').mapBy('type'); + + assert.deepEqual(alienFinalHats, expectedAlienResults, 'We got all alien hats!'); +}); + +test('handles relationships where both sides are polymorphic', function(assert) { + let id = 1; + function makePolymorphicHatForPolymorphicPerson(type, isForBigPerson = true) { + return { + id: `${id++}`, + type, + relationships: { + person: { + data: { + id: isForBigPerson ? '1' : '2', + type: isForBigPerson ? 'big-person' : 'small-person' + } + } + } + }; + } + + const bigHatData1 = makePolymorphicHatForPolymorphicPerson('big-hat'); + const bigHatData2 = makePolymorphicHatForPolymorphicPerson('big-hat'); + const bigHatData3 = makePolymorphicHatForPolymorphicPerson('big-hat', false); + const smallHatData1 = makePolymorphicHatForPolymorphicPerson('small-hat'); + const smallHatData2 = makePolymorphicHatForPolymorphicPerson('small-hat'); + const smallHatData3 = makePolymorphicHatForPolymorphicPerson('small-hat', false); + + const bigPersonData = { + data: { + id: '1', + type: 'big-person', + attributes: {} + }, + included: [ + bigHatData1, + smallHatData1, + bigHatData2, + smallHatData2 + ] + }; + + const smallPersonData = { + data: { + id: '2', + type: 'small-person', + attributes: {} + }, + included: [ + bigHatData3, + smallHatData3 + ] + }; + + const PersonModel = Model.extend({ + hats: hasMany('hat', { + async: false, + polymorphic: true, + inverse: 'person' + }) + }); + const HatModel = Model.extend({ + type: attr('string'), + person: belongsTo('person', { + async: false, + inverse: 'hats', + polymorphic: true + }) + }); + const BigHatModel = HatModel.extend({}); + const SmallHatModel = HatModel.extend({}); + + const BigPersonModel = PersonModel.extend({}); + const SmallPersonModel = PersonModel.extend({}); + + const store = this.store = createStore({ + person: PersonModel, + bigPerson: BigPersonModel, + smallPerson: SmallPersonModel, + hat: HatModel, + bigHat: BigHatModel, + smallHat: SmallHatModel + }); + + const bigPerson = run(() => { + return store.push(bigPersonData); + }); + + const smallPerson = run(() => { + return store.push(smallPersonData); + }); + + const finalBigResult = bigPerson.get('hats').toArray(); + const finalSmallResult = smallPerson.get('hats').toArray(); + + assert.equal(finalBigResult.length, 4, 'We got all our hats!'); + assert.equal(finalSmallResult.length, 2, 'We got all our hats!'); +}); + +test('handles relationships where both sides are polymorphic reflexive', function(assert) { + function link(a, b, relationshipName, recurse = true) { + a.relationships = a.relationships || {}; + const rel = a.relationships[relationshipName] = a.relationships[relationshipName] || {}; + + if (Array.isArray(b)) { + rel.data = b.map((i) => { + let {type, id} = i; + + if (recurse === true) { + link(i, [a], relationshipName, false); + } + + return { type, id }; + }); + } else { + rel.data = { + type: b.type, + id: b.id + }; + + if (recurse === true) { + link(b, a, relationshipName, false); + } + } + } + + let id = 1; + const Person = Model.extend({ + name: attr(), + family: hasMany('person', { async: false, polymorphic: true, inverse: 'family' }), + twin: belongsTo('person', { async: false, polymorphic: true, inverse: 'twin' }) + }); + const Girl = Person.extend({}); + const Boy = Person.extend({}); + const Grownup = Person.extend({}); + + const brotherPayload = { + type: 'boy', + id: `${id++}`, + attributes: { + name: 'Gavin' + } + }; + const sisterPayload = { + type: 'girl', + id: `${id++}`, + attributes: { + name: 'Rose' + } + }; + const fatherPayload = { + type: 'grownup', + id: `${id++}`, + attributes: { + name: 'Garak' + } + }; + const motherPayload = { + type: 'grownup', + id: `${id++}`, + attributes: { + name: 'Kira' + } + }; + + link(brotherPayload, sisterPayload, 'twin'); + link(brotherPayload, [sisterPayload, fatherPayload, motherPayload], 'family'); + + const payload = { + data: brotherPayload, + included: [ + sisterPayload, + fatherPayload, + motherPayload + ] + }; + const expectedFamilyReferences = [ + { type: 'girl', id: sisterPayload.id }, + { type: 'grownup', id: fatherPayload.id }, + { type: 'grownup', id: motherPayload.id } + ]; + const expectedTwinReference = { type: 'girl', id: sisterPayload.id }; + + const store = this.store = createStore({ + person: Person, + grownup: Grownup, + boy: Boy, + girl: Girl + }); + + const boyInstance = run(() => { + return store.push(payload); + }); + + const familyResultReferences = boyInstance.get('family').toArray() + .map((i) => { + return { type: i.constructor.modelName, id: i.id }; + }); + const twinResult = boyInstance.get('twin'); + const twinResultReference = { type: twinResult.constructor.modelName, id: twinResult.id }; + + assert.deepEqual(familyResultReferences, expectedFamilyReferences, 'We linked family correctly'); + assert.deepEqual(twinResultReference, expectedTwinReference, 'We linked twin correctly'); +}); + +test('handles relationships where both sides are polymorphic reflexive but the primary payload does not include linkage', function(assert) { + function link(a, b, relationshipName, recurse = true) { + a.relationships = a.relationships || {}; + const rel = a.relationships[relationshipName] = a.relationships[relationshipName] || {}; + + if (Array.isArray(b)) { + rel.data = b.map((i) => { + let {type, id} = i; + + if (recurse === true) { + link(i, [a], relationshipName, false); + } + + return { type, id }; + }); + } else { + rel.data = { + type: b.type, + id: b.id + }; + + if (recurse === true) { + link(b, a, relationshipName, false); + } + } + } + + let id = 1; + const Person = Model.extend({ + name: attr(), + family: hasMany('person', { async: false, polymorphic: true, inverse: 'family' }), + twin: belongsTo('person', { async: false, polymorphic: true, inverse: 'twin' }) + }); + const Girl = Person.extend({}); + const Boy = Person.extend({}); + const Grownup = Person.extend({}); + + const brotherPayload = { + type: 'boy', + id: `${id++}`, + attributes: { + name: 'Gavin' + } + }; + const sisterPayload = { + type: 'girl', + id: `${id++}`, + attributes: { + name: 'Rose' + } + }; + const fatherPayload = { + type: 'grownup', + id: `${id++}`, + attributes: { + name: 'Garak' + } + }; + const motherPayload = { + type: 'grownup', + id: `${id++}`, + attributes: { + name: 'Kira' + } + }; + + link(brotherPayload, sisterPayload, 'twin'); + link(brotherPayload, [sisterPayload, fatherPayload, motherPayload], 'family'); + + // unlink all relationships from the primary payload + delete brotherPayload.relationships; + + const payload = { + data: brotherPayload, + included: [ + sisterPayload, + fatherPayload, + motherPayload + ] + }; + const expectedFamilyReferences = [ + { type: 'girl', id: sisterPayload.id }, + { type: 'grownup', id: fatherPayload.id }, + { type: 'grownup', id: motherPayload.id } + ]; + const expectedTwinReference = { type: 'girl', id: sisterPayload.id }; + + const store = this.store = createStore({ + person: Person, + grownup: Grownup, + boy: Boy, + girl: Girl + }); + + const boyInstance = run(() => { + return store.push(payload); + }); + + const familyResultReferences = boyInstance.get('family').toArray() + .map((i) => { + return { type: i.constructor.modelName, id: i.id }; + }); + const twinResult = boyInstance.get('twin'); + const twinResultReference = twinResult && { type: twinResult.constructor.modelName, id: twinResult.id }; + + assert.deepEqual(familyResultReferences, expectedFamilyReferences, 'We linked family correctly'); + assert.deepEqual(twinResultReference, expectedTwinReference, 'We linked twin correctly'); +}); + +test('push polymorphic self-referential non-reflexive relationship', function(assert) { + const store = this.store; + const hat1Data = { + data: { + id: '1', + type: 'big-hat', + attributes: {} + } + }; + const hat2Data = { + data: { + id: '2', + type: 'big-hat', + attributes: {}, + relationships: { + hats: { + data: [{ id: '1', type: 'big-hat' }] + } + } + } + }; + + const hat1 = run(() => store.push(hat1Data)); + const hat2 = run(() => store.push(hat2Data)); + + const expectedHatReference = { id: '2', type: 'big-hat' }; + const expectedHatsReferences = [{ id: '1', type: 'big-hat' }]; + + const finalHatsReferences = hat2.get('hats').toArray() + .map((i) => { + return { type: i.constructor.modelName, id: i.id }; + }); + const hatResult = hat1.get('hat'); + const finalHatReference = hatResult && { type: hatResult.constructor.modelName, id: hatResult.id }; + + + assert.deepEqual(finalHatReference, expectedHatReference, 'we set hat on hat:1'); + assert.deepEqual(finalHatsReferences, expectedHatsReferences, 'We have hats on hat:2'); +}); + + +test('push polymorphic self-referential circular non-reflexive relationship', function(assert) { + const store = this.store; + const hatData = { + data: { + id: '1', + type: 'big-hat', + attributes: {}, + relationships: { + hat: { + data: { id: '1', type: 'big-hat' } + }, + hats: { + data: [{ id: '1', type: 'big-hat' }] + } + } + } + }; + + const hat = run(() => store.push(hatData)); + + const expectedHatReference = { id: '1', type: 'big-hat' }; + const expectedHatsReferences = [{ id: '1', type: 'big-hat' }]; + + const finalHatsReferences = hat.get('hats').toArray() + .map((i) => { + return { type: i.constructor.modelName, id: i.id }; + }); + const hatResult = hat.get('hat'); + const finalHatReference = hatResult && { type: hatResult.constructor.modelName, id: hatResult.id }; + + + assert.deepEqual(finalHatReference, expectedHatReference, 'we set hat on hat:1'); + assert.deepEqual(finalHatsReferences, expectedHatsReferences, 'We have hats on hat:2'); +}); + +test('polymorphic hasMany to types with separate id-spaces', function(assert) { + const user = run(() => this.store.push({ + data: { + id: '1', + type: 'user', + relationships: { + hats: { + data: [ + { id: '1', type: 'big-hat' }, + { id: '1', type: 'small-hat' } + ] + } + } + }, + included: [{ + id: '1', + type: 'big-hat' + }, { + id: '1', + type: 'small-hat' + }] + })); + + const hats = user.get('hats'); + + assert.deepEqual( + hats.map(h => h.constructor.modelName), + ['big-hat', 'small-hat'] + ); + assert.deepEqual( + hats.map(h => h.id), + ['1', '1'] + ); +}); + +test('polymorphic hasMany to types with separate id-spaces, from inverse payload', function (assert) { + const user = run(() => this.store.push({ + data: { + id: '1', + type: 'user' + }, + included: [{ + id: '1', + type: 'big-hat', + relationships: { + user: { + data: { id: '1', type: 'user' } + } + } + }, { + id: '1', + type: 'small-hat', + relationships: { + user: { + data: { id: '1', type: 'user' } + } + } + }] + })); + + const hats = user.get('hats'); + + assert.deepEqual( + hats.map(h => h.constructor.modelName), + ['big-hat', 'small-hat'] + ); + assert.deepEqual( + hats.map(h => h.id), + ['1', '1'] + ); +}); + +test('polymorphic hasMany to polymorphic hasMany types with separate id-spaces', function (assert) { + let bigHatId = 1; + let smallHatId = 1; + function makePolymorphicHatForPolymorphicPerson(type, isForBigPerson = true) { + const isSmallHat = type === 'small-hat'; + return { + id: `${isSmallHat ? smallHatId++ : bigHatId++}`, + type, + relationships: { + person: { + data: { + id: '1', + type: isForBigPerson ? 'big-person' : 'small-person' + } + } + } + }; + } + + const bigHatData1 = makePolymorphicHatForPolymorphicPerson('big-hat'); + const bigHatData2 = makePolymorphicHatForPolymorphicPerson('big-hat'); + const bigHatData3 = makePolymorphicHatForPolymorphicPerson('big-hat', false); + const smallHatData1 = makePolymorphicHatForPolymorphicPerson('small-hat'); + const smallHatData2 = makePolymorphicHatForPolymorphicPerson('small-hat'); + const smallHatData3 = makePolymorphicHatForPolymorphicPerson('small-hat', false); + + const bigPersonData = { + data: { + id: '1', + type: 'big-person', + attributes: {} + }, + included: [ + bigHatData1, + smallHatData1, + bigHatData2, + smallHatData2 + ] + }; + + const smallPersonData = { + data: { + id: '1', + type: 'small-person', + attributes: {} + }, + included: [ + bigHatData3, + smallHatData3 + ] + }; + + const PersonModel = Model.extend({ + hats: hasMany('hat', { + async: false, + polymorphic: true, + inverse: 'person' + }) + }); + const HatModel = Model.extend({ + type: attr('string'), + person: belongsTo('person', { + async: false, + inverse: 'hats', + polymorphic: true + }) + }); + const BigHatModel = HatModel.extend({}); + const SmallHatModel = HatModel.extend({}); + + const BigPersonModel = PersonModel.extend({}); + const SmallPersonModel = PersonModel.extend({}); + + const store = this.store = createStore({ + person: PersonModel, + bigPerson: BigPersonModel, + smallPerson: SmallPersonModel, + hat: HatModel, + bigHat: BigHatModel, + smallHat: SmallHatModel + }); + + const bigPerson = run(() => { + return store.push(bigPersonData); + }); + + const smallPerson = run(() => { + return store.push(smallPersonData); + }); + + const finalBigResult = bigPerson.get('hats').toArray(); + const finalSmallResult = smallPerson.get('hats').toArray(); + + assert.deepEqual( + finalBigResult.map(h => ({ type: h.constructor.modelName, id: h.get('id') })), + [{ type: 'big-hat', id: '1'}, { type: 'small-hat', id: '1'}, { type: 'big-hat', id: '2'}, { type: 'small-hat', id: '2'}], + 'big-person hats is all good' + ); + + assert.deepEqual( + finalSmallResult.map(h => ({ type: h.constructor.modelName, id: h.get('id') })), + [{ type: 'big-hat', id: '3'}, { type: 'small-hat', id: '3'}], + 'small-person hats is all good' + ); +}); + +testInDebug('Invalid inverses throw errors', function(assert) { + let PostModel = Model.extend({ + comments: hasMany('comment', { async: false }) + }); + let CommentModel = Model.extend({ + post: belongsTo('post', { async: false, inverse: null }) + }); + let store = createStore({ + post: PostModel, + comment: CommentModel + }); + + function runInvalidPush() { + return run(() => { + return store.push({ + data: { + type: 'post', + id: '1', + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' } + ] + } + } + }, + included: [ + { + type: 'comment', + id: '1', + relationships: { + post: { + data: { + type: 'post', + id: '1' + } + } + } + } + ] + }); + }); + } + + assert.throws(runInvalidPush, /The comment:post relationship declares 'inverse: null', but it was resolved as the inverse for post:comments/, 'We detected the invalid inverse'); +}); diff --git a/tests/unit/system/relationships/relationship-payload-manager-test.js b/tests/unit/system/relationships/relationship-payload-manager-test.js index 9ade62feb01..af7159f0291 100644 --- a/tests/unit/system/relationships/relationship-payload-manager-test.js +++ b/tests/unit/system/relationships/relationship-payload-manager-test.js @@ -4,28 +4,30 @@ import DS from 'ember-data'; import { createStore } from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; +const { Model, hasMany, belongsTo } = DS; + module('unit/system/relationships/relationship-payloads-manager', { beforeEach() { - const User = DS.Model.extend({ - purpose: DS.belongsTo('purpose', { inverse: 'user' }), - hobbies: DS.hasMany('hobby', { inverse: 'user'}), - friends: DS.hasMany('user', { inverse: 'friends' }) + const User = Model.extend({ + purpose: belongsTo('purpose', { inverse: 'user' }), + hobbies: hasMany('hobby', { inverse: 'user'}), + friends: hasMany('user', { inverse: 'friends' }) }); User.toString = () => 'User'; - const Hobby = DS.Model.extend({ + const Hobby = Model.extend({ user: DS.belongsTo('user', { inverse: 'hobbies' }) }); Hobby.toString = () => 'Hobby'; - const Purpose = DS.Model.extend({ + const Purpose = Model.extend({ user: DS.belongsTo('user', { inverse: 'purpose' }) }); Purpose.toString = () => 'Purpose'; let store = this.store = createStore({ user: User, - Hobby: Hobby, + hobby: Hobby, purpose: Purpose }); @@ -33,13 +35,12 @@ module('unit/system/relationships/relationship-payloads-manager', { } }); - test('get throws for invalid models', function(assert) { this.relationshipPayloadsManager._store._modelFor = (name) => { if (name === 'fish') { throw new Error('What is fish?'); } - } + }; assert.throws(() => { this.relationshipPayloadsManager.get('fish', 9, 'hobbies'); @@ -471,7 +472,7 @@ test('push populates the same RelationshipPayloads for either side of a relation 'hobbies', userModel, get(userModel, 'relationshipsByName') - ); + ); let hobbyModel = this.store.modelFor('hobby'); let hobbyPayloads = @@ -486,14 +487,15 @@ test('push populates the same RelationshipPayloads for either side of a relation }); test('push does not eagerly populate inverse payloads', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { + const relData = { hobbies: { data: [{ id: 2, type: 'hobby' }] } - }); + }; + this.relationshipPayloadsManager.push('user', 1, relData); let userModel = this.store.modelFor('user'); let relationshipPayloads = @@ -502,31 +504,41 @@ test('push does not eagerly populate inverse payloads', function(assert) { 'hobbies', userModel, get(userModel, 'relationshipsByName') - ); + ); assert.deepEqual( - Object.keys(relationshipPayloads._lhsPayloads), - [] , + Object.keys(relationshipPayloads.lhs_payloads.types), + [], 'user.hobbies payloads not eagerly populated' ); assert.deepEqual( - Object.keys(relationshipPayloads._rhsPayloads), - [] , + Object.keys(relationshipPayloads.rhs_payloads.types), + [], 'hobby.user payloads not eagerly populated' - ); + ); relationshipPayloads.get('user', 1, 'hobbies'); assert.deepEqual( - Object.keys(relationshipPayloads._lhsPayloads), - ['1'] , + Object.keys(relationshipPayloads.lhs_payloads.types), + ['user'], + 'user.hobbies payloads lazily populated' + ); + assert.deepEqual( + Object.keys(relationshipPayloads.lhs_payloads.types.user), + ['1'], 'user.hobbies payloads lazily populated' ); assert.deepEqual( - Object.keys(relationshipPayloads._rhsPayloads), + Object.keys(relationshipPayloads.rhs_payloads.types), + ['hobby'] , + 'hobby.user payloads lazily populated' + ); + assert.deepEqual( + Object.keys(relationshipPayloads.rhs_payloads.types.hobby), ['2'] , 'hobby.user payloads lazily populated' - ); + ); }); test('push populates each individual relationship in a payload', function(assert) { From fb5fbab0110f40c305439e5a131c88539b2c5250 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 2 Mar 2018 10:04:20 -0500 Subject: [PATCH 2135/2527] Fix failing test on master by adding an invalid inverse to trigger the expected error --- .../relationships/polymorphic-relationship-payloads-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js b/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js index b1398af49b0..333160db5c4 100644 --- a/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js +++ b/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js @@ -779,7 +779,7 @@ test('polymorphic hasMany to polymorphic hasMany types with separate id-spaces', testInDebug('Invalid inverses throw errors', function(assert) { let PostModel = Model.extend({ - comments: hasMany('comment', { async: false }) + comments: hasMany('comment', { async: false, inverse: 'post' }) }); let CommentModel = Model.extend({ post: belongsTo('post', { async: false, inverse: null }) From 0508db201295020d645a98e8ced83f7e83bcbda0 Mon Sep 17 00:00:00 2001 From: bmac Date: Sat, 3 Mar 2018 23:33:49 -0500 Subject: [PATCH 2136/2527] Fix build with ember canary --- tests/unit/adapters/json-api-adapter/ajax-test.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/unit/adapters/json-api-adapter/ajax-test.js b/tests/unit/adapters/json-api-adapter/ajax-test.js index c97fd3f1b53..94b9036a307 100644 --- a/tests/unit/adapters/json-api-adapter/ajax-test.js +++ b/tests/unit/adapters/json-api-adapter/ajax-test.js @@ -1,4 +1,3 @@ -import { computed } from '@ember/object'; import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; @@ -55,9 +54,7 @@ test('ajaxOptions() adds Accept header to existing headers', function(assert) { }); test('ajaxOptions() adds Accept header to existing computed properties headers', function(assert) { - adapter.headers = computed(function() { - return { 'Other-key': 'Other Value' }; - }); + adapter.headers = { 'Other-key': 'Other Value' }; let url = 'example.com'; let type = 'GET'; let ajaxOptions = adapter.ajaxOptions(url, type, {}); From 6f9e27ca420bee15bcd592096390fc06e4f51882 Mon Sep 17 00:00:00 2001 From: Derek Wickern Date: Fri, 16 Feb 2018 10:47:54 -0800 Subject: [PATCH 2137/2527] failed test: createRecord creates two records on ember 3.0 --- .../relationships/one-to-many-test.js | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index 37ec95a233b..3039341b6ec 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -1452,3 +1452,35 @@ test("Rollbacking attributes of a created record works correctly when the belong assert.equal(user.get('accounts.length'), 0, "User does not have the account anymore"); assert.equal(account.get('user'), null, 'Account does not have the user anymore'); }); + +test("createRecord updates inverse record array which has observers", function(assert) { + + env.adapter.findAll = () => { + return { + data: [{ + id: '2', + type: 'user', + attributes: { + name: 'Stanley' + } + }] + } + }; + + return store.findAll('user').then(users => { + assert.equal(users.get('length'), 1, 'Exactly 1 user'); + + let user = users.get('firstObject'); + assert.equal(user.get('messages.length'), 0, 'Record array is initially empty'); + + // set up an observer + user.addObserver('messages.@each.title', () => {}); + user.get('messages.firstObject'); + + let message = run(() => store.createRecord('message', { user, title: 'EmberFest was great' })); + assert.equal(user.get('messages.length'), 1, 'The message is added to the record array'); + + let messageFromArray = user.get('messages.firstObject'); + assert.equal(message, messageFromArray, 'Only one message should be created'); + }); +}); From 9a8c66617afcaeb0b31e6e2dc545433904a9ffce Mon Sep 17 00:00:00 2001 From: Derek Wickern Date: Thu, 1 Mar 2018 15:19:39 -0800 Subject: [PATCH 2138/2527] fix createRecord creating duplicates --- addon/-private/system/store.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index f1bbb9f1fb7..b5c45639a2a 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -358,7 +358,8 @@ Store = Service.extend({ let internalModel = this._buildInternalModel(normalizedModelName, properties.id); internalModel.loadedData(); - let record = internalModel.getRecord(properties); + let record = internalModel.getRecord(); + record.setProperties(properties); // TODO @runspired this should also be coalesced into some form of internalModel.setState() internalModel.eachRelationship((key, descriptor) => { From d51e1a264fab46b222bf98ebb4d5dcdc3f32a1a4 Mon Sep 17 00:00:00 2001 From: Derek Wickern Date: Fri, 2 Mar 2018 08:29:28 -0800 Subject: [PATCH 2139/2527] remove getRecord argument --- addon/-private/system/model/internal-model.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index d9ccb8f8e2f..60a831c1d94 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -334,7 +334,7 @@ export default class InternalModel { return this.currentState.dirtyType; } - getRecord(properties) { + getRecord() { if (!this._record && !this._isDematerializing) { heimdall.increment(materializeRecord); let token = heimdall.start('InternalModel.getRecord'); @@ -350,10 +350,6 @@ export default class InternalModel { adapterError: this.error }; - if (typeof properties === 'object' && properties !== null) { - emberAssign(createOptions, properties); - } - if (setOwner) { // ensure that `getOwner(this)` works inside a model instance setOwner(createOptions, getOwner(this.store)); From 662fe749b8e5f2e145c750ada0237bedfcbe5618 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Mon, 5 Mar 2018 09:44:21 -0500 Subject: [PATCH 2140/2527] Update change log for backported releases (#5368) --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6f9bf4d64a..ffc1f0f49e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ### Master +### Release 3.0.2 (March 1, 2018) +- [#5230](https://github.com/emberjs/data/pull/5230) [BUGFIX] enable lazy-relationship payloads to work with polymorphic relationships + ### Release 3.0.1 (February 13, 2018) - [#5273](https://github.com/emberjs/data/pull/5273) client-side-delete semantics `unloadRecord` @@ -26,6 +29,9 @@ - [#5305](https://github.com/emberjs/data/pull/5305) Serializers and adapters should be unique per store - [#5308](https://github.com/emberjs/data/pull/5308) Simplify the getDescriptor test helper +### Release 2.18.2 (March 1, 2018) +- [#5230](https://github.com/emberjs/data/pull/5230) [BUGFIX] enable lazy-relationship payloads to work with polymorphic relationships + ### Release 2.18.1 (February 13, 2018) - [#5273](https://github.com/emberjs/data/pull/5273) client-side-delete semantics `unloadRecord` @@ -52,6 +58,9 @@ - [#5250](https://github.com/emberjs/data/pull/5250) [doc] Update links to Ember Guide (#5250) - [#5260](https://github.com/emberjs/data/pull/5260) [doc] Update urlForFindRecord example +### Release 2.17.1 (March 1, 2018) +- [#5230](https://github.com/emberjs/data/pull/5230) [BUGFIX] enable lazy-relationship payloads to work with polymorphic relationships + ### Release 2.17.0 (November 19, 2017) - [#5216](https://github.com/emberjs/data/pull/5216) [BUGFIX beta] invalid record becomes loaded when property is reset - [#4998](https://github.com/emberjs/data/pull/4998) [DOC beta] Assert that both modelName and id are passed to `peekRecord` (#4998) @@ -76,6 +85,9 @@ - [#5224](https://github.com/emberjs/data/pull/5224) Add missing dependency for travis build - [#5232](https://github.com/emberjs/data/pull/5232) Update documentation in model.js +### Release 2.16.4 (March 1, 2018) +- [#5230](https://github.com/emberjs/data/pull/5230) [BUGFIX] enable lazy-relationship payloads to work with polymorphic relationships + ### Release 2.16.1 (October 4, 2017) - [#5114](https://github.com/emberjs/data/pull/5114) Make import stripping smarter to resolve #5019 - [#5197](https://github.com/emberjs/data/pull/5197) Fix ember-data Node 4.x builds @@ -130,6 +142,9 @@ - [#5162](https://github.com/emberjs/data/pull/5162) Update RELEASE.md - [#5192](https://github.com/emberjs/data/pull/5192) Remove feature flagging for ds-extended-errors. +### Release 2.15.4 (March 1, 2018) +- [#5230](https://github.com/emberjs/data/pull/5230) [BUGFIX] enable lazy-relationship payloads to work with polymorphic relationships + ### Release 2.15.3 (September 30, 2017) - [#5195](https://github.com/emberjs/data/pull/5195) Ensure `ember-data/-private` module is emitted properly for ember-cli… @@ -186,6 +201,9 @@ - [#5009](https://github.com/emberjs/data/pull/5009) cleanup `index.js` and drop `0.12` node - [#5011](https://github.com/emberjs/data/pull/5011) Fix and tests for unloadRecord => findRecord issue +### Release 2.14.11 (February 28, 2018) +- [#5230](https://github.com/emberjs/data/pull/5230) [BUGFIX] enable lazy-relationship payloads to work with polymorphic relationships + ### Release 2.14.10 (August 10, 2017) - [#5119](https://github.com/emberjs/data/pull/5119) [BUGFIX release] Don't notify relationships with links during initialization From 77a9fef887af50197866ece0ce328950a181e676 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 5 Mar 2018 13:31:37 -0500 Subject: [PATCH 2141/2527] [BUGFIX beta] Avoid `isEmpty` for known object types. (#5341) `Ember.isEmpty` does **a lot of things**, there is no reason to use it when you are operating on known data types. **_Use the platform..._** --- addon/-private/system/model/errors.js | 5 ++--- addon/-private/system/model/internal-model.js | 4 ++-- addon/-private/system/store/serializer-response.js | 3 +-- addon/transforms/number.js | 5 ++--- tests/unit/model/rollback-attributes-test.js | 6 +++--- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index 92427d95e5f..34df971dd27 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -2,7 +2,6 @@ import { mapBy, not } from '@ember/object/computed'; import Evented from '@ember/object/evented'; import ArrayProxy from '@ember/array/proxy'; import { set, get, computed } from '@ember/object'; -import { isEmpty } from '@ember/utils'; import { makeArray, A } from '@ember/array'; import MapWithDefault from '@ember/map/with-default'; import { deprecate, warn } from '@ember/debug'; @@ -186,7 +185,7 @@ export default ArrayProxy.extend(Evented, { */ unknownProperty(attribute) { let errors = this.errorsFor(attribute); - if (isEmpty(errors)) { return undefined; } + if (errors.length === 0) { return undefined; } return errors; }, @@ -425,6 +424,6 @@ export default ArrayProxy.extend(Evented, { @return {Boolean} true if there some errors on given attribute */ has(attribute) { - return !isEmpty(this.errorsFor(attribute)); + return this.errorsFor(attribute).length > 0; } }); diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 60a831c1d94..e1043f11d8c 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -2,7 +2,7 @@ import { assign, merge } from '@ember/polyfills'; import { set, get } from '@ember/object'; import { copy } from '@ember/object/internals'; import EmberError from '@ember/error'; -import { isEqual, isEmpty } from '@ember/utils'; +import { isEqual } from '@ember/utils'; import { setOwner } from '@ember/application'; import { run } from '@ember/runloop'; import RSVP, { Promise } from 'rsvp'; @@ -1095,7 +1095,7 @@ export default class InternalModel { hasErrors() { let errors = get(this.getRecord(), 'errors'); - return !isEmpty(errors); + return errors.get('length') > 0; } // FOR USE DURING COMMIT PROCESS diff --git a/addon/-private/system/store/serializer-response.js b/addon/-private/system/store/serializer-response.js index 8a75dde9644..155b13d0617 100644 --- a/addon/-private/system/store/serializer-response.js +++ b/addon/-private/system/store/serializer-response.js @@ -1,4 +1,3 @@ -import { isEmpty } from '@ember/utils'; import { assert } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; @@ -79,7 +78,7 @@ export function normalizeResponseHelper(serializer, store, modelClass, payload, if (DEBUG) { validationErrors = validateDocumentStructure(normalizedResponse); } - assert(`normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join('\n\t* ')}`, isEmpty(validationErrors)); + assert(`normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join('\n\t* ')}`, validationErrors.length === 0); return normalizedResponse; } diff --git a/addon/transforms/number.js b/addon/transforms/number.js index 4bc294e9d88..75b35eda250 100644 --- a/addon/transforms/number.js +++ b/addon/transforms/number.js @@ -1,4 +1,3 @@ -import { isEmpty as empty } from '@ember/utils'; import Transform from './transform'; function isNumber(value) { @@ -31,7 +30,7 @@ export default Transform.extend({ deserialize(serialized) { let transformed; - if (empty(serialized)) { + if (serialized === '' || serialized === null || serialized === undefined) { return null; } else { transformed = Number(serialized); @@ -43,7 +42,7 @@ export default Transform.extend({ serialize(deserialized) { let transformed; - if (empty(deserialized)) { + if (deserialized === '' || deserialized === null || deserialized === undefined) { return null; } else { transformed = Number(deserialized); diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index 403ad8e1910..4681dac1cb7 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -1,4 +1,4 @@ -import { isEmpty, isPresent } from '@ember/utils'; +import { isPresent } from '@ember/utils'; import { addObserver } from '@ember/object/observers'; import { Promise as EmberPromise, reject } from 'rsvp'; import { run, later } from '@ember/runloop'; @@ -402,7 +402,7 @@ test("invalid record's attributes can be rollbacked", function(assert) { assert.equal(dog.get('hasDirtyAttributes'), false, 'must not be dirty'); assert.equal(dog.get('name'), 'Pluto'); - assert.ok(isEmpty(dog.get('errors.name'))); + assert.notOk(dog.get('errors.name')); assert.ok(dog.get('isValid')); }); }); @@ -477,7 +477,7 @@ test(`invalid record's attributes rolled back to correct state after set`, funct assert.equal(dog.get('name'), 'Pluto'); assert.equal(dog.get('breed'), 'Disney'); assert.equal(dog.get('hasDirtyAttributes'), false, 'must not be dirty'); - assert.ok(isEmpty(dog.get('errors.name'))); + assert.notOk(dog.get('errors.name')); assert.ok(dog.get('isValid')); }); }); From f60d1e935dababca70ac03a77381f6a60633c4e5 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 5 Mar 2018 13:44:21 -0500 Subject: [PATCH 2142/2527] [BUGFIX beta] Use native Map if present. (#5255) When native `Map` is present, use it. Otherwise fallback to `Ember.Map`. This positions ember-data for the eventual deprecation and dropping of `Ember.Map` and `Ember.MapWithDefault` in Ember itself (and using native classes should generally be better for us long term than shipping custom _slightly_ different versions). Note there are a few specific differences between native `Map` (and the `MapWithDefault` implementation that extends from the native `Map` when possible) and Ember's `Ember.Map` that we should be aware of: * `Ember.Map` has custom `copy` and `isEmpty` methods which are not present in native `Map` * `Ember.Map` adds a static `create` method (which simply instantiates itself with `new Ember.Map()`) * `Ember.Map` does not accept constructor arguments * `Ember.Map` does not have: * `@@species` * `@@iterator` * `entries` * `values` --- .eslintrc.js | 3 +- addon/-private/index.js | 3 + addon/-private/system/map-with-default.js | 21 +++++ addon/-private/system/map.js | 102 +++++++++++++++++++++ addon/-private/system/model/errors.js | 6 +- addon/-private/system/model/model.js | 18 ++-- addon/-private/system/relationships/ext.js | 6 +- addon/-private/system/store.js | 4 +- addon/adapters/rest.js | 6 +- 9 files changed, 148 insertions(+), 21 deletions(-) create mode 100644 addon/-private/system/map-with-default.js create mode 100644 addon/-private/system/map.js diff --git a/.eslintrc.js b/.eslintrc.js index 7772cb11d12..3cb5fd6ea66 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -10,7 +10,8 @@ module.exports = { 'browser': true, }, globals: { - 'heimdall': true + 'heimdall': true, + 'Map': false, }, rules: { 'no-unused-vars': ['error', { diff --git a/addon/-private/index.js b/addon/-private/index.js index 0c529fcd05d..9929693db86 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -48,6 +48,9 @@ export { default as ManyArray } from './system/many-array'; export { default as RecordArrayManager } from './system/record-array-manager'; export { default as Relationship } from './system/relationships/state/relationship'; +export { default as Map } from './system/map'; +export { default as MapWithDefault } from './system/map-with-default'; + // Should be a different Repo ? export { default as DebugAdapter } from './system/debug/debug-adapter'; diff --git a/addon/-private/system/map-with-default.js b/addon/-private/system/map-with-default.js new file mode 100644 index 00000000000..69f397e06f3 --- /dev/null +++ b/addon/-private/system/map-with-default.js @@ -0,0 +1,21 @@ +import Map from './map'; + +export default class MapWithDefault extends Map { + constructor(options) { + super(); + + this.defaultValue = options.defaultValue; + } + + get(key) { + let hasValue = this.has(key); + + if (hasValue) { + return super.get(key); + } else { + let defaultValue = this.defaultValue(key); + this.set(key, defaultValue); + return defaultValue; + } + } +} diff --git a/addon/-private/system/map.js b/addon/-private/system/map.js new file mode 100644 index 00000000000..6018913a453 --- /dev/null +++ b/addon/-private/system/map.js @@ -0,0 +1,102 @@ +import { deprecate } from '@ember/debug'; + +/* + ## Why does this exist?!? + + `Ember.Map` was a private API provided by Ember (for quite some time). + Unfortunately, ember-data made `Ember.Map` part of its public API surface via + documentation blocks. + + `Ember.Map` will be deprecated and removed from Ember "soon" + (https://github.com/emberjs/rfcs/pull/237) and we would like to confirm that + Ember Data will work without deprecation before and after that happens. + + `Ember.Map` differs from native `Map` in a few ways: + + * `Ember.Map` has custom `copy` and `isEmpty` methods which are not present in native `Map` + * `Ember.Map` adds a static `create` method (which simply instantiates itself with `new Ember.Map()`) + * `Ember.Map` does not accept constructor arguments + * `Ember.Map` does not have: + * `@@species` + * `@@iterator` + * `entries` + * `values` + + This implementation adds a deprecated backwards compatibility for: + + * `copy` + * `isEmpty` + + ## Why is this written this way?!? + + This is needed because `Map` requires instantiation with `new` and by default + Babel transpilation will do `superConstructor.apply(this, arguments)` which + throws an error with native `Map`. + + The desired code (if we lived in an "only native class" world) would be: + + ```js + export default class MapWithDeprecations extends Map { + constructor(options) { + super(); + this.defaultValue = options.defaultValue; + } + + get(key) { + let hasValue = this.has(key); + + if (hasValue) { + return super.get(key); + } else { + let defaultValue = this.defaultValue(key); + this.set(key, defaultValue); + return defaultValue; + } + } + } + ``` +*/ +export default class MapWithDeprecations { + constructor(options) { + this._map = new Map(); + } + + copy() { + deprecate( + 'Calling `.copy()` on a map generated by ember-data is deprecated, please migrate to using native Map functionality only.', + false, + { id: 'ember-data.map.copy', until: '3.5.0' } + ); + + // can't just pass `this._map` here because IE11 doesn't accept + // constructor args with its `Map` + let newMap = new MapWithDeprecations(); + this._map.forEach(function(value, key) { + newMap.set(key, value) + }); + + return newMap; + } + + isEmpty() { + deprecate( + 'Calling `.isEmpty()` on a map generated by ember-data is deprecated, please migrate to using native Map functionality only.', + false, + { id: 'ember-data.map.isEmpty', until: '3.5.0' } + ); + + return this.size === 0; + } + + // proxy all normal Map methods to the underlying Map + get size() { return this._map.size; } + clear() { return this._map.clear(...arguments) } + delete() { return this._map.delete(...arguments) } + entries() { return this._map.entries(...arguments) } + forEach() { return this._map.forEach(...arguments) } + get() { return this._map.get(...arguments) } + has() { return this._map.has(...arguments) } + keys() { return this._map.keys(...arguments) } + set() { return this._map.set(...arguments) } + values() { return this._map.values(...arguments) } +} diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index 34df971dd27..11c5213b9a0 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -3,7 +3,7 @@ import Evented from '@ember/object/evented'; import ArrayProxy from '@ember/array/proxy'; import { set, get, computed } from '@ember/object'; import { makeArray, A } from '@ember/array'; -import MapWithDefault from '@ember/map/with-default'; +import MapWithDefault from '../map-with-default'; import { deprecate, warn } from '@ember/debug'; /** @@ -120,11 +120,11 @@ export default ArrayProxy.extend(Evented, { /** @property errorsByAttributeName - @type {Ember.MapWithDefault} + @type {MapWithDefault} @private */ errorsByAttributeName: computed(function() { - return MapWithDefault.create({ + return new MapWithDefault({ defaultValue() { return A(); } diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index d91dc663484..5d2ecce2d28 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -7,7 +7,7 @@ import EmberObject, { get, observer } from '@ember/object'; -import Map from '@ember/map'; +import Map from '../map'; import { DEBUG } from '@glimmer/env'; import { assert, warn } from '@ember/debug'; import { PromiseObject } from "../promise-proxies"; @@ -1399,7 +1399,7 @@ Model.reopenClass({ @property relationships @static - @type Ember.Map + @type Map @readOnly */ @@ -1522,7 +1522,7 @@ Model.reopenClass({ @property relationshipsByName @static - @type Ember.Map + @type Map @readOnly */ relationshipsByName: relationshipsByNameDescriptor, @@ -1565,11 +1565,11 @@ Model.reopenClass({ @property fields @static - @type Ember.Map + @type Map @readOnly */ fields: computed(function() { - let map = Map.create(); + let map = new Map(); this.eachComputedProperty((name, meta) => { if (meta.isRelationship) { @@ -1674,11 +1674,11 @@ Model.reopenClass({ @property attributes @static - @type {Ember.Map} + @type {Map} @readOnly */ attributes: computed(function() { - let map = Map.create(); + let map = new Map(); this.eachComputedProperty((name, meta) => { if (meta.isAttribute) { @@ -1727,11 +1727,11 @@ Model.reopenClass({ @property transformedAttributes @static - @type {Ember.Map} + @type {Map} @readOnly */ transformedAttributes: computed(function() { - let map = Map.create(); + let map = new Map(); this.eachAttribute((key, meta) => { if (meta.type) { diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 2a8bf05159e..fb7836ab91d 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -1,7 +1,7 @@ import { A } from '@ember/array'; import { computed } from '@ember/object'; -import MapWithDefault from '@ember/map/with-default'; -import Map from '@ember/map'; +import MapWithDefault from '../map-with-default'; +import Map from '../map'; import { assert } from '@ember/debug'; import { typeForRelationshipMeta, @@ -56,7 +56,7 @@ export const relatedTypesDescriptor = computed(function() { }).readOnly(); export const relationshipsByNameDescriptor = computed(function() { - let map = Map.create(); + let map = new Map(); this.eachComputedProperty((name, meta) => { if (meta.isRelationship) { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index b5c45639a2a..1e04de2be9b 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -6,7 +6,7 @@ import { A } from '@ember/array'; import { copy } from '@ember/object/internals'; import EmberError from '@ember/error'; -import MapWithDefault from '@ember/map/with-default'; +import MapWithDefault from './map-with-default'; import { run as emberRun } from '@ember/runloop'; import { set, get, computed } from '@ember/object'; import RSVP from 'rsvp'; @@ -230,7 +230,7 @@ Store = Service.extend({ this._updatedInternalModels = []; // used to keep track of all the find requests that need to be coalesced - this._pendingFetch = MapWithDefault.create({ defaultValue() { return []; } }); + this._pendingFetch = new MapWithDefault({ defaultValue() { return []; } }); this._adapterCache = Object.create(null); this._serializerCache = Object.create(null); diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index a1d6400ed86..7686435c300 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -6,7 +6,6 @@ import $ from 'jquery'; import { Promise as EmberPromise } from 'rsvp'; -import MapWithDefault from '@ember/map/with-default'; import { get } from '@ember/object'; import { run } from '@ember/runloop'; import Adapter from "../adapter"; @@ -22,7 +21,8 @@ import { ConflictError, ServerError, TimeoutError, - AbortError + AbortError, + MapWithDefault } from '../-private'; import { instrument } from 'ember-data/-debug'; import { warn, deprecate } from '@ember/debug'; @@ -901,7 +901,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { loaded separately by `findMany`. */ groupRecordsForFindMany(store, snapshots) { - let groups = MapWithDefault.create({ defaultValue() { return []; } }); + let groups = new MapWithDefault({ defaultValue() { return []; } }); let adapter = this; let maxURLLength = this.maxURLLength; From d9254e274834c7dae5a368ecefcbe4162cc57cf6 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Wed, 7 Mar 2018 11:40:33 -0500 Subject: [PATCH 2143/2527] Update ember twiddle links to working versions (#5367) --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bea9a49688b..4ab0a43ae93 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,8 +29,8 @@ demonstrate. The more pared down, the better. A preconfigured [EmberTwiddle (RES [EmberTwiddle][2] with mocked requests is available. -[rest]: https://ember-twiddle.com/aa257da01fe4fde3c1a502538e2e4902/copy -[json-api]: https://ember-twiddle.com/c0beed7d3c0bed65ac8ed018dcc57894/copy +[rest]: https://ember-twiddle.com/abbc9e9e9165e5ae05804f165fa5388c/copy +[json-api]: https://ember-twiddle.com/aa59b876f393e4d1573f7cad911ec5ad/copy [2]: https://ember-twiddle.com/0e1a24aabb8fa7c1fdd8/copy?fileTreeShown=false&numColumns=2&openFiles=routes.application.js%2Ctemplates.application.hbs 4. If possible, submit a Pull Request with a failing test. Better yet, take From d478a04ee3e570b5ea9eacf5d16fe78db02cd873 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 7 Mar 2018 12:00:59 -0500 Subject: [PATCH 2144/2527] [BUGFIX beta] Use @ember/ordered-set to avoid deprecations. Ember will deprecate usage of `Ember.OrderedSet` (likely in 3.2 or 3.3), and as part of that process the implementation has been extracted to an addon `@ember/ordered-set`. The addon intelligently avoids shipping duplicated implementations, and is compatible with newer _and_ older Ember versions. --- addon/-private/system/ordered-set.js | 4 +- package.json | 1 + .../integration/record-array-manager-test.js | 4 +- yarn.lock | 43 +++++++++++++++++++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/addon/-private/system/ordered-set.js b/addon/-private/system/ordered-set.js index 0577ec61664..27a6205057c 100644 --- a/addon/-private/system/ordered-set.js +++ b/addon/-private/system/ordered-set.js @@ -1,7 +1,5 @@ +import EmberOrderedSet from '@ember/ordered-set'; import { guidFor } from '@ember/object/internals'; -import Ember from 'ember'; - -const EmberOrderedSet = Ember.OrderedSet; export default function OrderedSet() { this._super$constructor(); diff --git a/package.json b/package.json index 117ab108f73..10a1fc06faf 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "author": "", "license": "MIT", "dependencies": { + "@ember/ordered-set": "^1.0.0", "amd-name-resolver": "0.0.7", "babel-plugin-ember-modules-api-polyfill": "^1.4.2", "babel-plugin-feature-flags": "^0.3.1", diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index b78380b3dae..1be66ac461d 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -1,7 +1,7 @@ import { A } from '@ember/array'; import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; +import OrderedSet from '@ember/ordered-set'; import { module, test } from 'qunit'; @@ -304,7 +304,7 @@ test('createRecordArray', function(assert) { test('createRecordArray \w optional content', function(assert) { let record = {}; let internalModel = { - _recordArrays: new Ember.OrderedSet(), + _recordArrays: new OrderedSet(), getRecord() { return record; } diff --git a/yarn.lock b/yarn.lock index c47b7b465dd..1a07533aa27 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,13 @@ # yarn lockfile v1 +"@ember/ordered-set@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@ember/ordered-set/-/ordered-set-1.0.0.tgz#cf9ab5fd7510bcad370370ebcded705f6d1c542b" + dependencies: + ember-cli-babel "6.12.0" + ember-compatibility-helpers "^1.0.0-beta.2" + "@glimmer/di@^0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" @@ -563,6 +570,12 @@ babel-plugin-ember-modules-api-polyfill@^2.0.1: dependencies: ember-rfc176-data "^0.3.0" +babel-plugin-ember-modules-api-polyfill@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.3.0.tgz#0c01f359658cfb9c797f705af6b09f6220205ae0" + dependencies: + ember-rfc176-data "^0.3.0" + babel-plugin-eval@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" @@ -2243,6 +2256,24 @@ ember-cli-app-version@^3.0.0: ember-cli-babel "^6.8.0" git-repo-version "0.4.1" +ember-cli-babel@6.12.0: + version "6.12.0" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.12.0.tgz#3adcdbe1278da1fcd0b9038f1360cb4ac5d4414c" + dependencies: + amd-name-resolver "0.0.7" + babel-plugin-debug-macros "^0.1.11" + babel-plugin-ember-modules-api-polyfill "^2.3.0" + babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-polyfill "^6.16.0" + babel-preset-env "^1.5.1" + broccoli-babel-transpiler "^6.1.2" + broccoli-debug "^0.6.2" + broccoli-funnel "^1.0.0" + broccoli-source "^1.1.0" + clone "^2.0.0" + ember-cli-version-checker "^2.1.0" + semver "^5.4.1" + ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.2.1: version "5.2.4" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" @@ -2614,6 +2645,14 @@ ember-cli@^2.11.1: walk-sync "^0.3.0" yam "0.0.22" +ember-compatibility-helpers@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.0.0-beta.2.tgz#00cb134af45f9562fa47a23f4da81a63aad41943" + dependencies: + babel-plugin-debug-macros "^0.1.11" + ember-cli-version-checker "^2.0.0" + semver "^5.4.1" + ember-dev@emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed: version "0.0.0" resolved "https://codeload.github.com/emberjs/ember-dev/tar.gz/bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed" @@ -5844,6 +5883,10 @@ semver@^4.1.0, semver@^4.3.1: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" +semver@^5.4.1: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + semver@~5.0.1: version "5.0.3" resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" From 55dbe2f3258658f677c27aafc0c78315622d6a2a Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Thu, 8 Mar 2018 11:19:17 -0500 Subject: [PATCH 2145/2527] =?UTF-8?q?Upgrade=20to=20ember-cli-qunit=204.0?= =?UTF-8?q?=20and=20replace=20ember-dev=20with=20ember-qunit=E2=80=A6=20(#?= =?UTF-8?q?5371)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Upgrade to ember-cli-qunit 4.0 and replace ember-dev with ember-qunit-assert-helpers * Undo strange runloop move * Fix node tests * Fix failing tests with optional features enabled * Update ember-source to 2.18.0 --- .../adapter-test/application-default.js | 18 +- .../fixtures/adapter-test/foo-default.js | 18 +- .../fixtures/model-test/comment-default.js | 20 +- node-tests/fixtures/model-test/foo-default.js | 20 +- .../fixtures/model-test/post-default.js | 20 +- .../serializer-test/application-default.js | 29 +- .../fixtures/serializer-test/foo-default.js | 29 +- node-tests/fixtures/transform-test/default.js | 18 +- package.json | 6 +- tests/dummy/config/environment.js | 2 +- tests/helpers/setup-ember-dev.js | 68 - tests/integration/adapter/find-all-test.js | 2 +- tests/integration/adapter/find-test.js | 6 +- .../integration/adapter/rest-adapter-test.js | 25 +- tests/integration/injection-test.js | 8 +- tests/integration/inverse-test.js | 2 +- tests/integration/multiple-stores-test.js | 4 +- tests/integration/records/error-test.js | 18 +- .../integration/references/belongs-to-test.js | 54 +- tests/integration/references/has-many-test.js | 66 +- .../inverse-relationships-test.js | 4 +- .../serializers/json-api-serializer-test.js | 83 +- .../serializers/json-serializer-test.js | 36 +- .../serializers/rest-serializer-test.js | 39 +- .../store/json-api-validation-test.js | 15 +- tests/test-helper.js | 13 +- tests/unit/model-test.js | 4 +- tests/unit/model/errors-test.js | 40 +- tests/unit/model/lifecycle-callbacks-test.js | 13 +- tests/unit/store/push-test.js | 50 +- tests/unit/store/serialize-test.js | 5 +- .../polymorphic-relationship-payloads-test.js | 2 +- yarn.lock | 2296 ++++++++++++----- 33 files changed, 2050 insertions(+), 983 deletions(-) delete mode 100644 tests/helpers/setup-ember-dev.js diff --git a/node-tests/fixtures/adapter-test/application-default.js b/node-tests/fixtures/adapter-test/application-default.js index f0a2101e7a8..eff23bb9421 100644 --- a/node-tests/fixtures/adapter-test/application-default.js +++ b/node-tests/fixtures/adapter-test/application-default.js @@ -1,12 +1,12 @@ -import { moduleFor, test } from 'ember-qunit'; +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; -moduleFor('adapter:application', 'Unit | Adapter | application', { - // Specify the other units that are required for this test. - // needs: ['serializer:foo'] -}); +module('Unit | Adapter | application', function(hooks) { + setupTest(hooks); -// Replace this with your real tests. -test('it exists', function(assert) { - let adapter = this.subject(); - assert.ok(adapter); + // Replace this with your real tests. + test('it exists', function(assert) { + let adapter = this.owner.lookup('adapter:application'); + assert.ok(adapter); + }); }); diff --git a/node-tests/fixtures/adapter-test/foo-default.js b/node-tests/fixtures/adapter-test/foo-default.js index 4ea377cecf3..61b5526f49e 100644 --- a/node-tests/fixtures/adapter-test/foo-default.js +++ b/node-tests/fixtures/adapter-test/foo-default.js @@ -1,12 +1,12 @@ -import { moduleFor, test } from 'ember-qunit'; +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; -moduleFor('adapter:foo', 'Unit | Adapter | foo', { - // Specify the other units that are required for this test. - // needs: ['serializer:foo'] -}); +module('Unit | Adapter | foo', function(hooks) { + setupTest(hooks); -// Replace this with your real tests. -test('it exists', function(assert) { - let adapter = this.subject(); - assert.ok(adapter); + // Replace this with your real tests. + test('it exists', function(assert) { + let adapter = this.owner.lookup('adapter:foo'); + assert.ok(adapter); + }); }); diff --git a/node-tests/fixtures/model-test/comment-default.js b/node-tests/fixtures/model-test/comment-default.js index 5a1628a037f..342341a0824 100644 --- a/node-tests/fixtures/model-test/comment-default.js +++ b/node-tests/fixtures/model-test/comment-default.js @@ -1,12 +1,14 @@ -import { moduleForModel, test } from 'ember-qunit'; +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { run } from '@ember/runloop'; -moduleForModel('comment', 'Unit | Model | comment', { - // Specify the other units that are required for this test. - needs: ['model:post', 'model:user'] -}); +module('Unit | Model | comment', function(hooks) { + setupTest(hooks); -test('it exists', function(assert) { - let model = this.subject(); - // let store = this.store(); - assert.ok(!!model); + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let model = run(() => store.createRecord('comment', {})); + assert.ok(model); + }); }); diff --git a/node-tests/fixtures/model-test/foo-default.js b/node-tests/fixtures/model-test/foo-default.js index b75921b883c..4440fd8539c 100644 --- a/node-tests/fixtures/model-test/foo-default.js +++ b/node-tests/fixtures/model-test/foo-default.js @@ -1,12 +1,14 @@ -import { moduleForModel, test } from 'ember-qunit'; +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { run } from '@ember/runloop'; -moduleForModel('foo', 'Unit | Model | foo', { - // Specify the other units that are required for this test. - needs: [] -}); +module('Unit | Model | foo', function(hooks) { + setupTest(hooks); -test('it exists', function(assert) { - let model = this.subject(); - // let store = this.store(); - assert.ok(!!model); + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let model = run(() => store.createRecord('foo', {})); + assert.ok(model); + }); }); diff --git a/node-tests/fixtures/model-test/post-default.js b/node-tests/fixtures/model-test/post-default.js index 71c81011693..b9d68646ce6 100644 --- a/node-tests/fixtures/model-test/post-default.js +++ b/node-tests/fixtures/model-test/post-default.js @@ -1,12 +1,14 @@ -import { moduleForModel, test } from 'ember-qunit'; +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { run } from '@ember/runloop'; -moduleForModel('post', 'Unit | Model | post', { - // Specify the other units that are required for this test. - needs: ['model:comment'] -}); +module('Unit | Model | post', function(hooks) { + setupTest(hooks); -test('it exists', function(assert) { - let model = this.subject(); - // let store = this.store(); - assert.ok(!!model); + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let model = run(() => store.createRecord('post', {})); + assert.ok(model); + }); }); diff --git a/node-tests/fixtures/serializer-test/application-default.js b/node-tests/fixtures/serializer-test/application-default.js index 705e9ecedcb..7f9b85de818 100644 --- a/node-tests/fixtures/serializer-test/application-default.js +++ b/node-tests/fixtures/serializer-test/application-default.js @@ -1,15 +1,24 @@ -import { moduleForModel, test } from 'ember-qunit'; +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { run } from '@ember/runloop'; -moduleForModel('application', 'Unit | Serializer | application', { - // Specify the other units that are required for this test. - needs: ['serializer:application'] -}); +module('Unit | Serializer | application', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let serializer = store.serializerFor('application'); + + assert.ok(serializer); + }); -// Replace this with your real tests. -test('it serializes records', function(assert) { - let record = this.subject(); + test('it serializes records', function(assert) { + let store = this.owner.lookup('service:store'); + let record = run(() => store.createRecord('application', {})); - let serializedRecord = record.serialize(); + let serializedRecord = record.serialize(); - assert.ok(serializedRecord); + assert.ok(serializedRecord); + }); }); diff --git a/node-tests/fixtures/serializer-test/foo-default.js b/node-tests/fixtures/serializer-test/foo-default.js index 48c11de4a78..eb94a50b2a4 100644 --- a/node-tests/fixtures/serializer-test/foo-default.js +++ b/node-tests/fixtures/serializer-test/foo-default.js @@ -1,15 +1,24 @@ -import { moduleForModel, test } from 'ember-qunit'; +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { run } from '@ember/runloop'; -moduleForModel('foo', 'Unit | Serializer | foo', { - // Specify the other units that are required for this test. - needs: ['serializer:foo'] -}); +module('Unit | Serializer | foo', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let serializer = store.serializerFor('foo'); + + assert.ok(serializer); + }); -// Replace this with your real tests. -test('it serializes records', function(assert) { - let record = this.subject(); + test('it serializes records', function(assert) { + let store = this.owner.lookup('service:store'); + let record = run(() => store.createRecord('foo', {})); - let serializedRecord = record.serialize(); + let serializedRecord = record.serialize(); - assert.ok(serializedRecord); + assert.ok(serializedRecord); + }); }); diff --git a/node-tests/fixtures/transform-test/default.js b/node-tests/fixtures/transform-test/default.js index 4e9dbc2b3e1..23d10b815cd 100644 --- a/node-tests/fixtures/transform-test/default.js +++ b/node-tests/fixtures/transform-test/default.js @@ -1,12 +1,12 @@ -import { moduleFor, test } from 'ember-qunit'; +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; -moduleFor('transform:foo', 'Unit | Transform | foo', { - // Specify the other units that are required for this test. - // needs: ['serializer:foo'] -}); +module('transform:foo', 'Unit | Transform | foo', function(hooks) { + setupTest(hooks); -// Replace this with your real tests. -test('it exists', function(assert) { - let transform = this.subject(); - assert.ok(transform); + // Replace this with your real tests. + test('it exists', function(assert) { + let transform = this.owner.lookup('transform:foo'); + assert.ok(transform); + }); }); diff --git a/package.json b/package.json index 10a1fc06faf..a190cd4f590 100644 --- a/package.json +++ b/package.json @@ -83,20 +83,20 @@ "ember-cli-inject-live-reload": "^1.4.1", "ember-cli-internal-test-helpers": "^0.8.1", "ember-cli-pretender": "^1.0.1", - "ember-cli-qunit": "^2.1.0", + "ember-cli-qunit": "^4.0.0", "ember-cli-release": "^0.2.9", "ember-cli-shims": "^1.0.2", "ember-cli-sri": "^2.1.0", "ember-cli-test-loader": "^1.1.0", "ember-cli-uglify": "^1.2.0", - "ember-dev": "emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed", "ember-disable-prototype-extensions": "^1.1.0", "ember-disable-proxy-controllers": "^1.0.0", "ember-export-application-global": "^1.0.5", "ember-load-initializers": "^0.6.0", "ember-publisher": "0.0.7", + "ember-qunit-assert-helpers": "^0.2.1", "ember-resolver": "^4.1.0", - "ember-source": "~2.11.0", + "ember-source": "~2.18.0", "ember-source-channel-url": "^1.0.1", "ember-try": "^0.2.23", "ember-watson": "^0.7.0", diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index ad6657a6117..41ca5779a8a 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -16,7 +16,7 @@ module.exports = function(environment) { EmberENV: { FEATURES: featureFlags, ENABLE_DS_FILTER: true, - RAISE_ON_DEPRECATION: true + RAISE_ON_DEPRECATION: false }, APP: { diff --git a/tests/helpers/setup-ember-dev.js b/tests/helpers/setup-ember-dev.js deleted file mode 100644 index bfa724ff2c5..00000000000 --- a/tests/helpers/setup-ember-dev.js +++ /dev/null @@ -1,68 +0,0 @@ -/* globals QUnit */ -import Ember from 'ember'; -import EmberTestHelpers from "ember-dev/test-helper/index"; - -const AVAILABLE_ASSERTIONS = ['expectAssertion', 'expectDeprecation', 'expectNoDeprecation', 'expectWarning', 'expectNoWarning', 'ignoreDeprecation']; - -// Maintain backwards compatiblity with older versions of ember. -let emberDebugModule; -if (Ember.__loader && Ember.__loader.registry && Ember.__loader.registry["ember-metal/debug"]) { - emberDebugModule = Ember.__loader.require('ember-metal/debug'); -} - -function getDebugFunction(name) { - if (emberDebugModule && emberDebugModule.getDebugFunction) { - return emberDebugModule.getDebugFunction(name); - } else { - return Ember[name]; - } -} - -function setDebugFunction(name, func) { - if (emberDebugModule && emberDebugModule.setDebugFunction) { - emberDebugModule.setDebugFunction(name, func); - } else { - Ember[name] = func; - } -} - -const originalModule = QUnit.module; - -/** - * We patch QUnit.module here so we can setup and teardown the helpers from - * ember-dev before every test. - * - * Creating the helpers within QUnit.testStart and checking for the assertions - * in QUnit.testDone doesn't work, as failed assertions in QUnit.testDone won't - * make the corresponding test fail. - */ -QUnit.module = function(name, options = {}) { - let testHelpers = new EmberTestHelpers({ - Ember, - getDebugFunction, - setDebugFunction - }); - - let originalBeforeEach = options.beforeEach || function() { }; - let originalAfterEach = options.afterEach || function() { }; - - options.beforeEach = function(assert) { - testHelpers.reset(); - testHelpers.inject(); - - AVAILABLE_ASSERTIONS.forEach((name) => assert[name] = window[name] ); - - originalBeforeEach.apply(this, arguments); - }; - - options.afterEach = function(assert) { - originalAfterEach.apply(this, arguments); - - testHelpers.assert(); - testHelpers.restore(); - - AVAILABLE_ASSERTIONS.forEach((name) => assert[name] = null ); - }; - - return originalModule(name, options); -}; diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index 28ab5e1a574..5d7375bb612 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -11,7 +11,7 @@ const { attr } = DS; let Person, store, allRecords, env; -module("integration/adapter/find_all - Finding All Records of a Type", { +module("integration/adapter/find-all - Finding All Records of a Type", { beforeEach() { Person = DS.Model.extend({ updatedAt: attr('string'), diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 4e5a98e5b14..b537c3c6dfc 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -179,7 +179,7 @@ testInDebug("warns when returned record has different id", function(assert) { } })); - assert.expectWarning(/You requested a record of type 'person' with id 'me' but the adapter returned a payload with primary data having an id of '1'/); - - return run(() => env.store.findRecord('person', 'me')); + assert.expectWarning( + () => run(() => env.store.findRecord('person', 'me')), + /You requested a record of type 'person' with id 'me' but the adapter returned a payload with primary data having an id of '1'/); }); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index d6466770f52..90ceb6c460b 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1361,16 +1361,18 @@ testInDebug("queryRecord - returning an array picks the first one but saves all post: [{ id: 1, name: "Rails is omakase" }, { id: 2, name: "Ember is js" }] }); - assert.expectDeprecation('The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record.'); + assert.expectDeprecation( + () => + run(() => { + return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { + let post2 = store.peekRecord('post', 2); - return run(() => { - return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { - let post2 = store.peekRecord('post', 2); + assert.deepEqual(post.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }); + assert.deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "Ember is js" }); + }); + }), - assert.deepEqual(post.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }); - assert.deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "Ember is js" }); - }); - }); + /The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record./); }); testInDebug("queryRecord - returning an array is deprecated", function(assert) { @@ -1378,9 +1380,10 @@ testInDebug("queryRecord - returning an array is deprecated", function(assert) { post: [{ id: 1, name: "Rails is omakase" }, { id: 2, name: "Ember is js" }] }); - assert.expectDeprecation('The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record.'); - - return run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })); + assert.expectDeprecation( + () => + run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })), + 'The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record.'); }); testInDebug("queryRecord - returning an single object doesn't throw a deprecation", function(assert) { diff --git a/tests/integration/injection-test.js b/tests/integration/injection-test.js index aef9d58a9cf..2ef91bcf148 100644 --- a/tests/integration/injection-test.js +++ b/tests/integration/injection-test.js @@ -20,7 +20,7 @@ const factory = { }; module('integration/injection factoryFor enabled', { - setup() { + beforeEach() { env = setupStore(); if (getOwner) { @@ -49,7 +49,7 @@ module('integration/injection factoryFor enabled', { } }, - teardown() { + afterEach() { if (getOwner) { let owner = getOwner(env.store); @@ -82,7 +82,7 @@ test('modelFor', function(assert) { }); module('integration/injection eager injections', { - setup() { + beforeEach() { setupModelFactoryInjections(); env = setupStore(); @@ -92,7 +92,7 @@ module('integration/injection eager injections', { // container injection }, - teardown() { + afterEach() { // can be removed once we no longer support ember versions without lookupFactory resetModelFactoryInjections(); diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index 2656594cee7..eb9c7159065 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -109,7 +109,7 @@ testInDebug("Errors out if you define 2 inverses to the same model", function(as assert.expectAssertion(() => { User.inverseFor('job', store); - }, /^You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times/i); + }, /You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times/i); }); diff --git a/tests/integration/multiple-stores-test.js b/tests/integration/multiple-stores-test.js index 116d953cea6..b632c75562a 100644 --- a/tests/integration/multiple-stores-test.js +++ b/tests/integration/multiple-stores-test.js @@ -9,7 +9,7 @@ let env; let SuperVillain, HomePlanet, EvilMinion; module("integration/multiple_stores - Multiple Stores Tests", { - setup() { + beforeEach() { SuperVillain = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), @@ -41,7 +41,7 @@ module("integration/multiple_stores - Multiple Stores Tests", { env.store_b = env.container.lookup('store:store-b'); }, - teardown() { + afterEach() { run(env.store, 'destroy'); } }); diff --git a/tests/integration/records/error-test.js b/tests/integration/records/error-test.js index faab0e113e1..a1841c4e57f 100644 --- a/tests/integration/records/error-test.js +++ b/tests/integration/records/error-test.js @@ -8,8 +8,8 @@ import RSVP from 'rsvp'; var env, store, Person; var attr = DS.attr; -function updateErrors(func) { - window.expectWarning(function() { +function updateErrors(func, assert) { + assert.expectWarning(function() { run(func); }, 'Interacting with a record errors object will no longer change the record state.'); } @@ -90,11 +90,11 @@ testInDebug('adding errors root.loaded.created.invalid works', function(assert) assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); - updateErrors(() => person.get('errors').add('firstName', 'is invalid') ); + updateErrors(() => person.get('errors').add('firstName', 'is invalid'), assert); assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); - updateErrors(() => person.get('errors').add('lastName', 'is invalid') ); + updateErrors(() => person.get('errors').add('lastName', 'is invalid'), assert); assert.deepEqual(person.get('errors').toArray(), [ { attribute: 'firstName', message: 'is invalid' }, @@ -118,15 +118,15 @@ testInDebug('adding errors root.loaded.created.invalid works add + remove + add' assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); - updateErrors(() => person.get('errors').add('firstName', 'is invalid') ); + updateErrors(() => person.get('errors').add('firstName', 'is invalid'), assert); assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); - updateErrors(() => person.get('errors').remove('firstName')); + updateErrors(() => person.get('errors').remove('firstName'), assert); assert.deepEqual(person.get('errors').toArray(), []); - updateErrors(() => person.get('errors').add('firstName', 'is invalid') ); + updateErrors(() => person.get('errors').add('firstName', 'is invalid'), assert); assert.deepEqual(person.get('errors').toArray(), [ { attribute: 'firstName', message: 'is invalid' } @@ -151,14 +151,14 @@ testInDebug('adding errors root.loaded.created.invalid works add + (remove, add) updateErrors(() => { person.get('errors').add('firstName', 'is invalid'); - }); + }, assert); assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); updateErrors(() => { person.get('errors').remove('firstName'); person.get('errors').add('firstName', 'is invalid'); - }); + }, assert); assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index bf2e9eecf6c..2bf955af3d6 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -230,10 +230,6 @@ testInDebug("push(record)", function(assert) { var familyReference = person.belongsTo('family'); run(function() { - if (isEnabled('ds-overhaul-references')) { - assert.expectDeprecation("BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead."); - } - familyReference.push(family).then(function(record) { assert.ok(Family.detectInstance(record), "push resolves with the referenced record"); assert.equal(get(record, 'name'), "Coreleone", "name is set"); @@ -244,6 +240,50 @@ testInDebug("push(record)", function(assert) { }); }); +if (isEnabled('ds-overhaul-references')) { + testInDebug("push(record) logs a deprecation warning", function(assert) { + var done = assert.async(); + + var person, family; + run(function() { + person = env.store.push({ + data: { + type: 'person', + id: 1, + relationships: { + family: { + data: { type: 'family', id: 1 } + } + } + } + }); + family = env.store.push({ + data: { + type: 'family', + id: 1, + attributes: { + name: "Coreleone" + } + } + }); + }); + + var familyReference = person.belongsTo('family'); + + assert.expectDeprecation(() => { + run(function() { + familyReference.push(family).then(function(record) { + assert.ok(Family.detectInstance(record), "push resolves with the referenced record"); + assert.equal(get(record, 'name'), "Coreleone", "name is set"); + assert.equal(record, family); + + done(); + }); + }); + }, "BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead."); + }); +} + test("push(promise)", function(assert) { var done = assert.async(); @@ -292,9 +332,6 @@ test("push(promise)", function(assert) { testInDebug("push(record) asserts for invalid modelClass", function(assert) { var person, anotherPerson; - if (isEnabled('ds-overhaul-references')) { - assert.expectDeprecation('BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set(\'relationshipName\', value)` instead.') - } run(function() { person = env.store.push({ data: { @@ -329,9 +366,6 @@ testInDebug("push(record) works with polymorphic modelClass", function(assert) { var person, mafiaFamily; - if (isEnabled('ds-overhaul-references')) { - assert.expectDeprecation('BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set(\'relationshipName\', value)` instead.') - } env.registry.register('model:mafia-family', Family.extend()); run(function() { diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 3f094b647be..3deab094433 100755 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -186,10 +186,6 @@ testInDebug("push(array)", function(assert) { var personsReference = family.hasMany('persons'); - if (isEnabled('ds-overhaul-references')) { - assert.expectDeprecation("HasManyReference#push(array) is deprecated. Push a JSON-API document instead."); - } - run(function() { var data = [ { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, @@ -207,6 +203,50 @@ testInDebug("push(array)", function(assert) { }); }); +if (isEnabled('ds-overhaul-references')) { + testInDebug("push(array) logs a deprecation warning", function(assert) { + var done = assert.async(); + + var family; + run(function() { + family = env.store.push({ + data: { + type: 'family', + id: 1, + relationships: { + persons: { + data: [ + { type: 'person', id: 1 }, + { type: 'person', id: 2 } + ] + } + } + } + }); + }); + + var personsReference = family.hasMany('persons'); + + assert.expectDeprecation(() => { + run(function() { + var data = [ + { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, + { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } + ]; + + personsReference.push(data).then(function(records) { + assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), "Vito"); + assert.equal(records.objectAt(1).get('name'), "Michael"); + + done(); + }); + }); + }, "HasManyReference#push(array) is deprecated. Push a JSON-API document instead."); + }); +} + testInDebug("push(array) works with polymorphic type", function(assert) { var done = assert.async(); @@ -229,12 +269,6 @@ testInDebug("push(array) works with polymorphic type", function(assert) { { data: { type: 'mafia-boss', id: 1, attributes: { name: "Vito" } } } ]; - if (isEnabled('ds-overhaul-references')) { - assert.expectDeprecation("HasManyReference#push(array) is deprecated. Push a JSON-API document instead."); - } else { - assert.expectNoDeprecation(); - } - personsReference.push(data).then(function(records) { assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); assert.equal(get(records, 'length'), 1); @@ -258,12 +292,6 @@ testInDebug("push(array) asserts polymorphic type", function(assert) { var personsReference = family.hasMany('persons'); - if (isEnabled('ds-overhaul-references')) { - assert.expectDeprecation("HasManyReference#push(array) is deprecated. Push a JSON-API document instead."); - } else { - assert.expectNoDeprecation(); - } - assert.expectAssertion(() => { run(() => { var data = [ @@ -306,12 +334,6 @@ testInDebug("push(object) supports legacy, non-JSON-API-conform payload", functi ] }; - if (isEnabled('ds-overhaul-references')) { - assert.expectDeprecation("HasManyReference#push() expects a valid JSON-API document."); - } else { - assert.expectNoDeprecation(); - } - personsReference.push(payload).then(function(records) { assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); assert.equal(get(records, 'length'), 2); diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index 91641283935..41249b75226 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -640,9 +640,9 @@ testInDebug("Inverse null relationships with models that don't exist throw a nic let env = setupStore({ user: User }); - assert.throws(() => { + assert.expectAssertion(() => { run(() => env.store.createRecord('user', { post: {}})); - }, /No model was found for 'post'/); + }, /No model was found for/) // but don't error if the relationship is not used run(() => env.store.createRecord('user', {})); diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 75598b45ba5..b9d42ecd544 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -211,7 +211,7 @@ testInDebug('Warns when normalizing with type missing', function(assert) { } }; - assert.throws(function() { + assert.expectAssertion(function() { run(function() { env.store.serializerFor('user').normalizeResponse(env.store, User, documentHash, '1', 'findRecord'); }); @@ -552,33 +552,34 @@ if (isEnabled("ds-payload-type-hooks")) { } }; - assert.expectDeprecation("You are using modelNameFromPayloadKey to normalize the type for a relationship. This has been deprecated in favor of modelNameFromPayloadType"); - - let user = env.store.serializerFor('user').normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); + assert.expectDeprecation(() => { + let user = env.store.serializerFor('user').normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); - assert.deepEqual(user, { - data: { - id: "1", - type: "user", - attributes: {}, - relationships: { - company: { - data: { - id: "1", - type: "company" + assert.deepEqual(user, { + data: { + id: "1", + type: "user", + attributes: {}, + relationships: { + company: { + data: { + id: "1", + type: "company" + } + }, + handles: { + data: [{ + id: "1", + type: "handle" + }] } - }, - handles: { - data: [{ - id: "1", - type: "handle" - }] } } - } - }); + }); + }, "You are using modelNameFromPayloadKey to normalize the type for a relationship. This has been deprecated in favor of modelNameFromPayloadType"); }); + test('mapping of model name can be customized via payloadTypeFromModelName', function(assert) { env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ attrs: { @@ -678,28 +679,28 @@ if (isEnabled("ds-payload-type-hooks")) { }); }); - assert.expectDeprecation("You used payloadKeyFromModelName to customize how a type is serialized. Use payloadTypeFromModelName instead."); - - var payload = env.store.serializerFor("user").serialize(user._createSnapshot()); + assert.expectDeprecation(() => { + var payload = env.store.serializerFor("user").serialize(user._createSnapshot()); - assert.deepEqual(payload, { - data: { - type: 'api::v1::user', - relationships: { - company: { - data: { - id: '1', - type: 'api::v1::company' + assert.deepEqual(payload, { + data: { + type: 'api::v1::user', + relationships: { + company: { + data: { + id: '1', + type: 'api::v1::company' + } + }, + handles: { + data: [{ + id: '1', + type: 'api::v1::handle' + }] } - }, - handles: { - data: [{ - id: '1', - type: 'api::v1::handle' - }] } } - } - }); + }); + }, "You used payloadKeyFromModelName to customize how a type is serialized. Use payloadTypeFromModelName instead."); }); } diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 9e13bef9304..30c01e06f2f 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -1115,26 +1115,26 @@ if (isEnabled("ds-payload-type-hooks")) { } }; - assert.expectDeprecation("You used modelNameFromPayloadKey to customize how a type is normalized. Use modelNameFromPayloadType instead"); - - let normalized = serializer.normalizeSingleResponse(env.store, Favorite, jsonHash); - - assert.deepEqual(normalized, { - data: { - id: '1', - type: 'favorite', - attributes: {}, - relationships: { - post: { - data: { - id: '1', - type: 'post' + assert.expectDeprecation(() => { + let normalized = serializer.normalizeSingleResponse(env.store, Favorite, jsonHash); + + assert.deepEqual(normalized, { + data: { + id: '1', + type: 'favorite', + attributes: {}, + relationships: { + post: { + data: { + id: '1', + type: 'post' + } } } - } - }, - included: [] - }); + }, + included: [] + }); + }, "You used modelNameFromPayloadKey to customize how a type is normalized. Use modelNameFromPayloadType instead"); }); } diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index d83759c327d..88a98061251 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -158,7 +158,7 @@ test("normalizeResponse with custom modelNameFromPayloadKey", function(assert) { }); testInDebug("normalizeResponse with type and custom modelNameFromPayloadKey", function(assert) { - assert.expect(isEnabled("ds-payload-type-hooks") ? 3 : 2); + assert.expect(2); var homePlanetNormalizeCount = 0; @@ -179,9 +179,6 @@ testInDebug("normalizeResponse with type and custom modelNameFromPayloadKey", fu var array; - if (isEnabled("ds-payload-type-hooks")) { - assert.expectDeprecation('You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This is has been deprecated in favor of modelNameFromPayloadType'); - } run(function() { array = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, '1', 'findAll'); }); @@ -975,26 +972,26 @@ if (isEnabled("ds-payload-type-hooks")) { } }; - assert.expectDeprecation("You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This has been deprecated in favor of modelNameFromPayloadType"); + assert.expectDeprecation(() => { + let normalized = env.restSerializer.normalizeResponse(env.store, DoomsdayDevice, jsonHash, '1', 'findRecord'); - let normalized = env.restSerializer.normalizeResponse(env.store, DoomsdayDevice, jsonHash, '1', 'findRecord'); - - assert.deepEqual(normalized, { - data: { - id: '1', - type: 'doomsday-device', - attributes: {}, - relationships: { - evilMinion: { - data: { - id: '1', - type: 'evil-minion' + assert.deepEqual(normalized, { + data: { + id: '1', + type: 'doomsday-device', + attributes: {}, + relationships: { + evilMinion: { + data: { + id: '1', + type: 'evil-minion' + } } } - } - }, - included: [] - }); + }, + included: [] + }); + }, "You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This has been deprecated in favor of modelNameFromPayloadType"); }); test("mapping of model name can be customized via payloadTypeFromModelName", function(assert) { diff --git a/tests/integration/store/json-api-validation-test.js b/tests/integration/store/json-api-validation-test.js index 47300f88518..09906f695b3 100644 --- a/tests/integration/store/json-api-validation-test.js +++ b/tests/integration/store/json-api-validation-test.js @@ -7,7 +7,7 @@ import DS from 'ember-data'; var Person, store, env; -function payloadError(payload, expectedError) { +function payloadError(payload, expectedError, assert) { env.registry.register('serializer:person', DS.Serializer.extend({ normalizeResponse(store, type, pld) { return pld; @@ -18,7 +18,7 @@ function payloadError(payload, expectedError) { return resolve(payload); } })); - this.throws(function () { + this.expectAssertion(function () { run(function() { store.findRecord('person', 1); }); @@ -29,7 +29,7 @@ function payloadError(payload, expectedError) { module("integration/store/json-validation", { beforeEach() { - QUnit.assert.payloadError = payloadError; + QUnit.assert.payloadError = payloadError.bind(QUnit.assert); Person = DS.Model.extend({ updatedAt: DS.attr('string'), @@ -62,7 +62,7 @@ testInDebug("when normalizeResponse returns undefined (or doesn't return), throw } })); - assert.throws(function () { + assert.expectAssertion(function () { run(function() { store.findRecord('person', 1); }); @@ -81,7 +81,7 @@ testInDebug("when normalizeResponse returns null, throws an error", function(ass } })); - assert.throws(function () { + assert.expectAssertion(function () { run(function() { store.findRecord('person', 1); }); @@ -101,7 +101,7 @@ testInDebug("when normalizeResponse returns an empty object, throws an error", f } })); - assert.throws(function () { + assert.expectAssertion(function () { run(function() { store.findRecord('person', 1); }); @@ -125,7 +125,7 @@ testInDebug("when normalizeResponse returns a document with both data and errors } })); - assert.throws(function () { + assert.expectAssertion(function () { run(function() { store.findRecord('person', 1); }); @@ -138,7 +138,6 @@ testInDebug("normalizeResponse 'data' cannot be undefined, a number, a string or assert.payloadError({ data: 1 }, /data must be/); assert.payloadError({ data: 'lollerskates' }, /data must be/); assert.payloadError({ data: true }, /data must be/); - }); testInDebug("normalizeResponse 'meta' cannot be an array, undefined, a number, a string or a boolean", function(assert) { diff --git a/tests/test-helper.js b/tests/test-helper.js index e27a313804a..c011eeb5a42 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -1,17 +1,12 @@ -/* - babel@6 currently (6.24.0) puts `import 'foo'` (for side effects) at the - end of the module dep list. Unfortunately, for this to work `setup-ember-dev` - must be evaluated before the `qunit` module is evaluated (because we change - `QUnit.module`). - */ import RSVP from 'rsvp'; import Application from '@ember/application'; -import requiredWorkAroundBabelBug from 'dummy/tests/helpers/setup-ember-dev'; // eslint-disable-line import resolver from './helpers/resolver'; import { setResolver -} from 'ember-qunit'; +} from '@ember/test-helpers'; +import { start } from 'ember-qunit'; + import QUnit from 'qunit'; import DS from 'ember-data'; import { @@ -38,7 +33,6 @@ QUnit.begin(() => { // otherwise, let a future turn of the event loop // handle the error. if (reason && reason instanceof Error) { - console.log(reason, reason.stack); throw reason; } }); @@ -75,3 +69,4 @@ QUnit.config.urlConfig.push({ id: 'enableoptionalfeatures', label: 'Enable Opt Features' }); +start(); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index f313550ded7..2a1b60761fd 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -1234,11 +1234,11 @@ testInDebug(`don't allow setting`, function(assert) { let record = run(() => store.createRecord('person')); - assert.throws(() => { + assert.expectAssertion(() => { run(() => { record.set('isLoaded', true); }); - }, 'raised error when trying to set an unsettable record'); + }, /Cannot set read-only property "isLoaded"/); }); test('ensure model exits loading state, materializes data and fulfills promise only after data is available', function(assert) { diff --git a/tests/unit/model/errors-test.js b/tests/unit/model/errors-test.js index 71374b7d31e..d81f7dc7de4 100644 --- a/tests/unit/model/errors-test.js +++ b/tests/unit/model/errors-test.js @@ -12,8 +12,8 @@ module('unit/model/errors', { } }); -function updateErrors(func) { - window.expectWarning(func, 'Interacting with a record errors object will no longer change the record state.'); +function updateErrors(func, assert) { + assert.expectWarning(func, 'Interacting with a record errors object will no longer change the record state.'); } AssertPrototype.becameInvalid = function becameInvalid(eventName) { @@ -40,15 +40,15 @@ testInDebug('add error', function(assert) { assert.expect(10); errors.trigger = assert.becameInvalid; - updateErrors(() => errors.add('firstName', 'error')); + updateErrors(() => errors.add('firstName', 'error'), assert); errors.trigger = assert.unexpectedSend; assert.ok(errors.has('firstName'), 'it has firstName errors'); assert.equal(errors.get('length'), 1, 'it has 1 error'); - updateErrors(() => errors.add('firstName', ['error1', 'error2'])); + updateErrors(() => errors.add('firstName', ['error1', 'error2']), assert); assert.equal(errors.get('length'), 3, 'it has 3 errors'); assert.ok(!errors.get('isEmpty'), 'it is not empty'); - updateErrors(() => errors.add('lastName', 'error')); - updateErrors(() => errors.add('lastName', 'error')); + updateErrors(() => errors.add('lastName', 'error'), assert); + updateErrors(() => errors.add('lastName', 'error'), assert); assert.equal(errors.get('length'), 4, 'it has 4 errors'); }); @@ -57,13 +57,13 @@ testInDebug('get error', function(assert) { assert.ok(errors.get('firstObject') === undefined, 'returns undefined'); errors.trigger = assert.becameInvalid; - updateErrors(() => errors.add('firstName', 'error')); + updateErrors(() => errors.add('firstName', 'error'), assert); errors.trigger = assert.unexpectedSend; assert.ok(errors.get('firstName').length === 1, 'returns errors'); assert.deepEqual(errors.get('firstObject'), { attribute: 'firstName', message: 'error' }); - updateErrors(() => errors.add('firstName', 'error2')); + updateErrors(() => errors.add('firstName', 'error2'), assert); assert.ok(errors.get('firstName').length === 2, 'returns errors'); - updateErrors(() => errors.add('lastName', 'error3')); + updateErrors(() => errors.add('lastName', 'error3'), assert); assert.deepEqual(errors.toArray(), [ { attribute: 'firstName', message: 'error' }, { attribute: 'firstName', message: 'error2' }, @@ -80,28 +80,28 @@ testInDebug('remove error', function(assert) { assert.expect(8); errors.trigger = assert.becameInvalid; - updateErrors(() => errors.add('firstName', 'error')); + updateErrors(() => errors.add('firstName', 'error'), assert); errors.trigger = assert.becameValid; - updateErrors(() => errors.remove('firstName')); + updateErrors(() => errors.remove('firstName'), assert); errors.trigger = assert.unexpectedSend; assert.ok(!errors.has('firstName'), 'it has no firstName errors'); assert.equal(errors.get('length'), 0, 'it has 0 error'); assert.ok(errors.get('isEmpty'), 'it is empty'); - updateErrors(() => errors.remove('firstName')); + updateErrors(() => errors.remove('firstName'), assert); }); -testInDebug('remove same errors from different attributes', function(assert) { +testInDebug('remove same errors fromm different attributes', function(assert) { assert.expect(9); errors.trigger = assert.becameInvalid; - updateErrors(() => errors.add('firstName', 'error')); - updateErrors(() => errors.add('lastName', 'error')); + updateErrors(() => errors.add('firstName', 'error'), assert); + updateErrors(() => errors.add('lastName', 'error'), assert); errors.trigger = assert.unexpectedSend; assert.equal(errors.get('length'), 2, 'it has 2 error'); - updateErrors(() => errors.remove('firstName')); + updateErrors(() => errors.remove('firstName'), assert); assert.equal(errors.get('length'), 1, 'it has 1 error'); errors.trigger = assert.becameValid; - updateErrors(() => errors.remove('lastName')); + updateErrors(() => errors.remove('lastName'), assert); assert.ok(errors.get('isEmpty'), 'it is empty'); }); @@ -109,12 +109,12 @@ testInDebug('clear errors', function(assert) { assert.expect(8); errors.trigger = assert.becameInvalid; - updateErrors(() => errors.add('firstName', ['error', 'error1'])); + updateErrors(() => errors.add('firstName', ['error', 'error1']), assert); assert.equal(errors.get('length'), 2, 'it has 2 errors'); errors.trigger = assert.becameValid; - updateErrors(() => errors.clear()); + updateErrors(() => errors.clear(), assert); errors.trigger = assert.unexpectedSend; assert.ok(!errors.has('firstName'), 'it has no firstName errors'); assert.equal(errors.get('length'), 0, 'it has 0 error'); - updateErrors(() => errors.clear()); + updateErrors(() => errors.clear(), assert); }); diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index 3ea46df61ba..ccbee5e8dd8 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -276,13 +276,14 @@ test('a record receives a becameInvalid callback when it became invalid', functi return asyncPerson.then(person => { return run(() => { person.set('bar', 'Bar'); - return person.save(); + return person.save().catch(reason => { + assert.ok(reason.isAdapterError, 'reason should have been an adapter error'); + + assert.equal(reason.errors.length, 1, 'reason should have one error'); + assert.equal(reason.errors[0].title, 'Invalid Attribute'); + assert.equal(callCount, 1, 'becameInvalid called after invalidating'); + }); }); - }).catch(reason => { - assert.ok(reason.isAdapterError, 'reason should have been an adapter error'); - assert.equal(reason.errors.length, 1, 'reason should have one error'); - assert.equal(reason.errors[0].title, 'Invalid Attribute'); - assert.equal(callCount, 1, 'becameInvalid called after invalidating'); }); }); }); diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index e842cd5b15b..3f624a29d12 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -1,4 +1,3 @@ -import { inspect } from '@ember/debug'; import EmberObject from '@ember/object'; import { Promise as EmberPromise, resolve } from 'rsvp'; import { run } from '@ember/runloop'; @@ -516,7 +515,7 @@ testInDebug('calling push without data argument as an object raises an error', f assert.expect(invalidValues.length); invalidValues.forEach((invalidValue) => { - assert.throws(() => { + assert.expectAssertion(() => { run(() => { store.push('person', invalidValue); }); @@ -638,37 +637,20 @@ test('Calling push with a link containing the value null', function(assert) { }); testInDebug('calling push with hasMany relationship the value must be an array', function(assert) { - let invalidValues = [ - 1, - 'string', - EmberObject.create(), - EmberObject.extend(), - true - ]; - - assert.expect(invalidValues.length); - - invalidValues.forEach(invalidValue => { - assert.throws(() => { - try { - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - relationships: { - phoneNumbers: { - data: invalidValue - } - } + assert.expectAssertion(() => { + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + relationships: { + phoneNumbers: { + data: 1 } - }); - }); - } catch (e) { - store._pushedInternalModels.length = 0; - throw e; - } - }, /must be an array/, `Expect that '${inspect(invalidValue)}' is not an array`); + } + } + }); + }); }); }); @@ -682,7 +664,7 @@ testInDebug('calling push with missing or invalid `id` throws assertion error', assert.expect(invalidValues.length); invalidValues.forEach(invalidValue => { - assert.throws(() => { + assert.expectAssertion(() => { run(() => { store.push({ data: invalidValue @@ -693,7 +675,7 @@ testInDebug('calling push with missing or invalid `id` throws assertion error', }); testInDebug('calling push with belongsTo relationship the value must not be an array', function(assert) { - assert.throws(() => { + assert.expectAssertion(() => { run(() => { store.push({ data: { diff --git a/tests/unit/store/serialize-test.js b/tests/unit/store/serialize-test.js index d92f3b5f488..6fe6c4ea5dd 100644 --- a/tests/unit/store/serialize-test.js +++ b/tests/unit/store/serialize-test.js @@ -25,8 +25,9 @@ if (isEnabled('ds-deprecate-store-serialize')) { } }); - assert.expectDeprecation('Use of store.serialize is deprecated, use record.serialize instead.'); - store.serialize(person); + assert.expectDeprecation(() => { + store.serialize(person); + }, 'Use of store.serialize is deprecated, use record.serialize instead.'); }); }); diff --git a/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js b/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js index 333160db5c4..f1a62e54ae3 100644 --- a/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js +++ b/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js @@ -821,5 +821,5 @@ testInDebug('Invalid inverses throw errors', function(assert) { }); } - assert.throws(runInvalidPush, /The comment:post relationship declares 'inverse: null', but it was resolved as the inverse for post:comments/, 'We detected the invalid inverse'); + assert.expectAssertion(runInvalidPush, /The comment:post relationship declares 'inverse: null', but it was resolved as the inverse for post:comments/, 'We detected the invalid inverse'); }); diff --git a/yarn.lock b/yarn.lock index 1a07533aa27..dfd952cb155 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,13 +9,21 @@ ember-cli-babel "6.12.0" ember-compatibility-helpers "^1.0.0-beta.2" +"@ember/test-helpers@^0.7.18": + version "0.7.18" + resolved "https://registry.yarnpkg.com/@ember/test-helpers/-/test-helpers-0.7.18.tgz#a0c474c3029588ec46d2e406252fc072b7f9aa3c" + dependencies: + broccoli-funnel "^2.0.1" + ember-cli-babel "^6.10.0" + ember-cli-htmlbars-inline-precompile "^1.0.0" + "@glimmer/di@^0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" "@glimmer/resolver@^0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@glimmer/resolver/-/resolver-0.4.1.tgz#cd9644572c556e7e799de1cf8eff2b999cf5b878" + version "0.4.3" + resolved "https://registry.yarnpkg.com/@glimmer/resolver/-/resolver-0.4.3.tgz#b1baae5c3291b4621002ccf8d7870466097e841d" dependencies: "@glimmer/di" "^0.2.0" @@ -24,20 +32,20 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" "@types/node@*": - version "8.0.44" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.44.tgz#5c39800fda4b76dab39a5f28fda676fc500015ac" + version "9.4.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.6.tgz#d8176d864ee48753d053783e4e463aec86b8d82e" "@types/node@^7.0.5": - version "7.0.44" - resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.44.tgz#20422b3dada536f35bf318ac3e24b8c48200803d" + version "7.0.55" + resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.55.tgz#7bb6215ff9425a1d714106be9f0d3e0e28829288" "@types/rimraf@^0.0.28": version "0.0.28" resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06" "@types/tape@^4.2.29": - version "4.2.30" - resolved "https://registry.yarnpkg.com/@types/tape/-/tape-4.2.30.tgz#3c1917c4dfd6f27271b9922772513515bc6c46b4" + version "4.2.31" + resolved "https://registry.yarnpkg.com/@types/tape/-/tape-4.2.31.tgz#d2cd0f2e410d2c288a5eb54c01c04e6b8a301fd2" dependencies: "@types/node" "*" @@ -59,10 +67,10 @@ accepts@1.3.3: negotiator "0.6.1" accepts@~1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" dependencies: - mime-types "~2.1.16" + mime-types "~2.1.18" negotiator "0.6.1" acorn-jsx@^3.0.0: @@ -75,13 +83,9 @@ acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" -acorn@^4.0.3: - version "4.0.13" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" - -acorn@^5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" +acorn@^5.2.1, acorn@^5.5.0: + version "5.5.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.1.tgz#84e05a9ea0acbe131227da50301e62464dc9c1d8" adm-zip@0.4.4: version "0.4.4" @@ -102,7 +106,7 @@ ajv-keywords@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" -ajv@^4.1.3, ajv@^4.7.0: +ajv@^4.1.3, ajv@^4.7.0, ajv@^4.9.1: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" dependencies: @@ -143,10 +147,6 @@ ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" -ansi-escapes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" - ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" @@ -167,9 +167,9 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@^3.0.0, ansi-styles@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" +ansi-styles@^3.0.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" dependencies: color-convert "^1.9.0" @@ -196,8 +196,8 @@ are-we-there-yet@~1.1.2: readable-stream "^2.0.6" argparse@^1.0.7, argparse@~1.0.2: - version "1.0.9" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" dependencies: sprintf-js "~1.0.2" @@ -207,14 +207,26 @@ arr-diff@^2.0.0: dependencies: arr-flatten "^1.0.1" -arr-flatten@^1.0.1: +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + array-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -243,6 +255,10 @@ array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + arraybuffer.slice@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" @@ -255,13 +271,29 @@ asn1@0.1.11: version "0.1.11" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + assert-plus@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + assertion-error@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" ast-traverse@~0.1.1: version "0.1.1" @@ -291,6 +323,10 @@ async-disk-cache@^1.2.1: rsvp "^3.0.18" username-sync "1.0.1" +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + async-promise-queue@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/async-promise-queue/-/async-promise-queue-1.0.4.tgz#308baafbc74aff66a0bb6e7f4a18d4fe8434440c" @@ -303,8 +339,8 @@ async@^1.4.0, async@^1.5.2: resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" async@^2.4.1: - version "2.5.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" + version "2.6.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" dependencies: lodash "^4.14.0" @@ -316,12 +352,19 @@ async@~0.9.0: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +atob@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d" + aws-sdk@^2.0.9: - version "2.132.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.132.0.tgz#6ece84bf355a6626fc8ba24023809c08ca1ee372" + version "2.205.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.205.0.tgz#1a93730253e2be027a4bd3af9248cbda0573de80" dependencies: buffer "4.9.1" - crypto-browserify "1.0.9" events "^1.1.1" jmespath "0.15.0" querystring "0.2.0" @@ -335,6 +378,14 @@ aws-sign2@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -419,8 +470,8 @@ babel-core@^6.14.0, babel-core@^6.26.0: source-map "^0.5.6" babel-generator@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5" + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" dependencies: babel-messages "^6.23.0" babel-runtime "^6.26.0" @@ -428,7 +479,7 @@ babel-generator@^6.26.0: detect-indent "^4.0.0" jsesc "^1.3.0" lodash "^4.17.4" - source-map "^0.5.6" + source-map "^0.5.7" trim-right "^1.0.1" babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: @@ -564,12 +615,6 @@ babel-plugin-ember-modules-api-polyfill@^1.4.2: dependencies: ember-rfc176-data "^0.2.0" -babel-plugin-ember-modules-api-polyfill@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.1.0.tgz#78848cc4fcc2274882a6c15cbb23fefcdc771301" - dependencies: - ember-rfc176-data "^0.3.0" - babel-plugin-ember-modules-api-polyfill@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.3.0.tgz#0c01f359658cfb9c797f705af6b09f6220205ae0" @@ -868,8 +913,8 @@ babel-polyfill@^6.16.0: regenerator-runtime "^0.10.5" babel-preset-env@^1.5.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.0.tgz#2de1c782a780a0a5d605d199c957596da43c44e4" + version "1.6.1" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48" dependencies: babel-plugin-check-es2015-constants "^6.22.0" babel-plugin-syntax-trailing-function-commas "^6.22.0" @@ -995,28 +1040,50 @@ base64-arraybuffer@0.1.5: resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" base64-js@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" + version "1.2.3" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.3.tgz#fb13668233d9614cf5fb4bce95a9ba4096cdf801" base64id@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + basic-auth@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.0.tgz#015db3f353e02e56377755f962742e8981e7bbba" dependencies: safe-buffer "5.1.1" +bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + better-assert@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" dependencies: callsite "1.0.0" +binary-extensions@^1.0.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + "binaryextensions@1 || 2": - version "2.0.0" - resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.0.0.tgz#e597d1a7a6a3558a2d1c7241a16c99965e6aa40f" + version "2.1.1" + resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" bindings@1.2.x, bindings@~1.2.1: version "1.2.1" @@ -1030,6 +1097,12 @@ blob@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + bluebird@^2.9.33: version "2.11.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" @@ -1068,6 +1141,12 @@ boom@0.4.x: dependencies: hoek "0.9.x" +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + bower-config@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc" @@ -1083,8 +1162,8 @@ bower-endpoint-parser@0.2.2: resolved "https://registry.yarnpkg.com/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" brace-expansion@^1.0.0, brace-expansion@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" dependencies: balanced-match "^1.0.0" concat-map "0.0.1" @@ -1097,6 +1176,23 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" +braces@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.1.tgz#7086c913b4e5a08dbe37ac0ee6a2500c4ba691bb" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + define-property "^1.0.0" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + kind-of "^6.0.2" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + breakable@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" @@ -1117,9 +1213,9 @@ broccoli-asset-rewrite@^1.1.0: dependencies: broccoli-filter "^1.2.3" -broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: - version "5.7.2" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.2.tgz#756c30544775144e984333b7115f42c916ba08e0" +broccoli-babel-transpiler@^5.6.2: + version "5.7.4" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.4.tgz#2b0611ce9e5d98b8d8d2b49ae1219af2f52767e3" dependencies: babel-core "^5.0.0" broccoli-funnel "^1.0.0" @@ -1130,11 +1226,11 @@ broccoli-babel-transpiler@^5.5.0, broccoli-babel-transpiler@^5.6.2: heimdalljs-logger "^0.1.7" json-stable-stringify "^1.0.0" rsvp "^3.5.0" - workerpool "^2.2.1" + workerpool "^2.3.0" broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2: - version "6.1.2" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.1.2.tgz#26019c045b5ea3e44cfef62821302f9bd483cabd" + version "6.1.4" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.1.4.tgz#8be8074c42abf2e17ff79b2d2a21df5c51143c82" dependencies: babel-core "^6.14.0" broccoli-funnel "^1.0.0" @@ -1145,7 +1241,7 @@ broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2: heimdalljs-logger "^0.1.7" json-stable-stringify "^1.0.0" rsvp "^3.5.0" - workerpool "^2.2.1" + workerpool "^2.3.0" broccoli-brocfile-loader@^0.18.0: version "0.18.0" @@ -1154,8 +1250,8 @@ broccoli-brocfile-loader@^0.18.0: findup-sync "^0.4.2" broccoli-builder@^0.18.8: - version "0.18.8" - resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.8.tgz#fe54694d544c3cdfdb01028e802eeca65749a879" + version "0.18.11" + resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.11.tgz#a42393c7b10bb0380df255a616307945f5e26efb" dependencies: heimdalljs "^0.2.0" promise-map-series "^0.2.1" @@ -1164,7 +1260,7 @@ broccoli-builder@^0.18.8: rsvp "^3.0.17" silent-error "^1.0.1" -broccoli-caching-writer@^2.2.0, broccoli-caching-writer@^2.3.1: +broccoli-caching-writer@^2.2.0: version "2.3.1" resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: @@ -1195,19 +1291,6 @@ broccoli-clean-css@^1.1.0: inline-source-map-comment "^1.0.5" json-stable-stringify "^1.0.0" -broccoli-concat@^2.2.0: - version "2.3.8" - resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-2.3.8.tgz#590cdcc021bb905b6c121d87c2d1d57df44a2a48" - dependencies: - broccoli-caching-writer "^2.3.1" - broccoli-kitchen-sink-helpers "^0.3.1" - broccoli-stew "^1.3.3" - fast-sourcemap-concat "^1.0.1" - fs-extra "^0.30.0" - lodash.merge "^4.3.0" - lodash.omit "^4.1.0" - lodash.uniq "^4.2.0" - broccoli-concat@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" @@ -1241,18 +1324,17 @@ broccoli-config-replace@^1.1.2: fs-extra "^0.24.0" broccoli-debug@^0.6.1, broccoli-debug@^0.6.2, broccoli-debug@^0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/broccoli-debug/-/broccoli-debug-0.6.3.tgz#1f33bb0eacb5db81366f0492524c82b1217eb578" + version "0.6.4" + resolved "https://registry.yarnpkg.com/broccoli-debug/-/broccoli-debug-0.6.4.tgz#986eb3d2005e00e3bb91f9d0a10ab137210cd150" dependencies: broccoli-plugin "^1.2.1" fs-tree-diff "^0.5.2" heimdalljs "^0.2.1" heimdalljs-logger "^0.1.7" - minimatch "^3.0.3" symlink-or-copy "^1.1.8" tree-sync "^1.2.2" -broccoli-file-creator@^1.0.0: +broccoli-file-creator@^1.0.0, broccoli-file-creator@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" dependencies: @@ -1263,9 +1345,9 @@ broccoli-file-creator@^1.0.0: rsvp "~3.0.6" symlink-or-copy "^1.0.1" -broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/broccoli-filter/-/broccoli-filter-1.2.4.tgz#409afb94b9a3a6da9fac8134e91e205f40cc7330" +broccoli-filter@^1.0.1, broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: + version "1.3.0" + resolved "https://registry.yarnpkg.com/broccoli-filter/-/broccoli-filter-1.3.0.tgz#71e3a8e32a17f309e12261919c5b1006d6766de6" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.0.0" @@ -1281,7 +1363,7 @@ broccoli-funnel-reducer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" -broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli-funnel@^1.1.0, broccoli-funnel@^1.2.0: +broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.1.0, broccoli-funnel@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" dependencies: @@ -1300,7 +1382,7 @@ broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.0.6, broccoli symlink-or-copy "^1.0.0" walk-sync "^0.3.1" -broccoli-funnel@^2.0.0: +broccoli-funnel@^2.0.0, broccoli-funnel@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-2.0.1.tgz#6823c73b675ef78fffa7ab800f083e768b51d449" dependencies: @@ -1343,7 +1425,7 @@ broccoli-lint-eslint@^2.0.0: json-stable-stringify "^1.0.1" md5-hex "^1.2.1" -broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.0, broccoli-merge-trees@^1.1.4, broccoli-merge-trees@^1.2.1: +broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" dependencies: @@ -1364,11 +1446,11 @@ broccoli-merge-trees@^2.0.0: merge-trees "^1.0.1" broccoli-middleware@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-1.0.0.tgz#92f4e1fb9a791ea986245a7077f35cc648dab097" + version "1.2.1" + resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-1.2.1.tgz#a21f255f8bfe5a21c2f0fbf2417addd9d24c9436" dependencies: handlebars "^4.0.4" - mime "^1.2.11" + mime-types "^2.1.18" broccoli-node-info@1.1.0: version "1.1.0" @@ -1426,7 +1508,11 @@ broccoli-rollup@^1.2.0: symlink-or-copy "^1.1.8" walk-sync "^0.3.1" -broccoli-slow-trees@3.0.1, broccoli-slow-trees@^3.0.1: +broccoli-slow-trees@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-2.0.0.tgz#9741afe992787add64aec7f7c8211dfcc058278d" + +broccoli-slow-trees@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" dependencies: @@ -1515,11 +1601,11 @@ broccoli-yuidoc@^3.0.0: yuidocjs "^0.10.2" broccoli@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/broccoli/-/broccoli-1.1.3.tgz#98405e86b7b0e6c268fb8302a006d834d17ed292" + version "1.1.4" + resolved "https://registry.yarnpkg.com/broccoli/-/broccoli-1.1.4.tgz#b023b028b866f447ed14341007961efd03f7251c" dependencies: broccoli-node-info "1.1.0" - broccoli-slow-trees "3.0.1" + broccoli-slow-trees "2.0.0" broccoli-source "^1.1.0" commander "^2.5.0" connect "^3.3.3" @@ -1535,11 +1621,11 @@ broccoli@^1.1.0: underscore.string "^3.2.2" browserslist@^2.1.2: - version "2.5.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.5.1.tgz#68e4bc536bbcc6086d62843a2ffccea8396821c6" + version "2.11.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.3.tgz#fe36167aed1bbcde4827ebfe71347a2cc70b99b2" dependencies: - caniuse-lite "^1.0.30000744" - electron-to-chromium "^1.3.24" + caniuse-lite "^1.0.30000792" + electron-to-chromium "^1.3.30" bser@^2.0.0: version "2.0.0" @@ -1578,6 +1664,20 @@ bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + cacheable-request@^2.1.1: version "2.1.4" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" @@ -1610,10 +1710,21 @@ callsites@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + camelcase@^1.0.2, camelcase@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" @@ -1624,9 +1735,9 @@ can-symlink@^1.0.0: dependencies: tmp "0.0.28" -caniuse-lite@^1.0.30000744: - version "1.0.30000746" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000746.tgz#c64f95a3925cfd30207a308ed76c1ae96ea09ea0" +caniuse-lite@^1.0.30000792: + version "1.0.30000813" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000813.tgz#7b25e27fdfb8d133f3c932b01f77452140fcc6c9" capture-exit@^1.1.0: version "1.2.0" @@ -1641,6 +1752,10 @@ cardinal@^1.0.0: ansicolors "~0.2.1" redeyed "~1.0.0" +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + center-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" @@ -1705,13 +1820,13 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" dependencies: - ansi-styles "^3.1.0" + ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" - supports-color "^4.0.0" + supports-color "^5.3.0" charm@^1.0.0: version "1.0.2" @@ -1723,6 +1838,21 @@ check-error@^1.0.1, check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" +chokidar@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + chrome-debugging-client@^0.2.4: version "0.2.5" resolved "https://registry.yarnpkg.com/chrome-debugging-client/-/chrome-debugging-client-0.2.5.tgz#b8e1a6c37283323b6ff5d60525f6ea1fc8899fbd" @@ -1739,6 +1869,15 @@ circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + clean-base-url@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" @@ -1770,7 +1909,7 @@ cli-cursor@^2.1.0: dependencies: restore-cursor "^2.0.0" -cli-spinners@^1.0.0: +cli-spinners@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.1.0.tgz#f1847b168844d917a671eb9d147e3df497c90d06" @@ -1819,6 +1958,10 @@ clone@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" +clone@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f" + clone@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" @@ -1831,9 +1974,16 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + color-convert@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" dependencies: color-name "^1.1.1" @@ -1849,6 +1999,12 @@ colors@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" + dependencies: + delayed-stream "~1.0.0" + combined-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" @@ -1859,6 +2015,10 @@ commander@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" +commander@2.12.2: + version "2.12.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" + commander@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" @@ -1870,14 +2030,14 @@ commander@2.8.x: graceful-readlink ">= 1.0.0" commander@^2.5.0, commander@^2.6.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + version "2.14.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" common-tags@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.4.0.tgz#1187be4f3d4cf0c0427d43f74eef1f73501614c0" + version "1.7.2" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.7.2.tgz#24d9768c63d253a56ecff93845b44b4df1d52771" dependencies: - babel-runtime "^6.18.0" + babel-runtime "^6.26.0" commoner@~0.10.3: version "0.10.8" @@ -1901,7 +2061,7 @@ component-emitter@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" -component-emitter@1.2.1: +component-emitter@1.2.1, component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" @@ -1909,19 +2069,19 @@ component-inherit@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" -compressible@~2.0.11: - version "2.0.11" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.11.tgz#16718a75de283ed8e604041625a2064586797d8a" +compressible@~2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.13.tgz#0d1020ab924b2fdb4d6279875c7d6daba6baa7a9" dependencies: - mime-db ">= 1.29.0 < 2" + mime-db ">= 1.33.0 < 2" compression@^1.4.4: - version "1.7.1" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.1.tgz#eff2603efc2e22cf86f35d2eb93589f9875373db" + version "1.7.2" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.2.tgz#aaffbcd6aaf854b44ebb280353d5ad1651f59a69" dependencies: accepts "~1.3.4" bytes "3.0.0" - compressible "~2.0.11" + compressible "~2.0.13" debug "2.6.9" on-headers "~1.0.1" safe-buffer "5.1.1" @@ -1931,9 +2091,9 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.6: - version "1.6.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" +concat-stream@^1.4.6, concat-stream@^1.4.7: + version "1.6.1" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.1.tgz#261b8f518301f1d834e36342b9fea095d2620a26" dependencies: inherits "^2.0.3" readable-stream "^2.2.2" @@ -1965,11 +2125,11 @@ configstore@^3.0.0: xdg-basedir "^3.0.0" connect@^3.3.3: - version "3.6.5" - resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.5.tgz#fb8dde7ba0763877d0ec9df9dac0b4b40e72c7da" + version "3.6.6" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" dependencies: debug "2.6.9" - finalhandler "1.0.6" + finalhandler "1.1.0" parseurl "~1.3.2" utils-merge "1.0.1" @@ -1978,13 +2138,15 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" console-ui@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-2.0.0.tgz#159ef7d098a491f84705bb69cd63ecec9a367b14" + version "2.2.2" + resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-2.2.2.tgz#b294a2934de869dd06789ab4be69555411edef29" dependencies: chalk "^2.1.0" - inquirer "^3.2.1" - ora "^1.3.0" + inquirer "^2" + json-stable-stringify "^1.0.1" + ora "^2.0.0" through "^2.3.8" + user-info "^1.0.0" consolidate@^0.14.0: version "0.14.5" @@ -2005,8 +2167,8 @@ continuable-cache@^0.3.1: resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" convert-source-map@^1.1.0, convert-source-map@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" cookie-signature@1.0.6: version "1.0.6" @@ -2020,13 +2182,17 @@ copy-dereference@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" core-js@^2.4.0, core-js@^2.5.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" + version "2.5.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" core-object@^1.1.0: version "1.1.0" @@ -2038,7 +2204,7 @@ core-object@^3.1.3: dependencies: chalk "^2.0.0" -core-util-is@~1.0.0: +core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -2056,9 +2222,11 @@ cryptiles@0.2.x: dependencies: boom "0.4.x" -crypto-browserify@1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0" +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" crypto-random-string@^1.0.0: version "1.0.0" @@ -2068,6 +2236,12 @@ ctype@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + dependencies: + array-find-index "^1.0.1" + d@1: version "1.0.0" resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" @@ -2078,7 +2252,13 @@ dag-map@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" -debug@2, debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.4.0, debug@^2.6.8, debug@~2.6.7: +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +debug@2, debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.4.0, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -2096,13 +2276,13 @@ debug@2.3.3: dependencies: ms "0.7.2" -debug@^3.0.0: +debug@^3.0.0, debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: ms "2.0.0" -decamelize@^1.0.0, decamelize@^1.1.1: +decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2128,10 +2308,39 @@ deep-eql@^3.0.0: dependencies: type-detect "^4.0.0" +deep-extend@~0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" + deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + dependencies: + clone "^1.0.2" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + defined@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" @@ -2167,14 +2376,22 @@ delayed-stream@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" -depd@1.1.1, depd@~1.1.1: +depd@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" +depd@~1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -2185,6 +2402,10 @@ detect-file@^0.1.0: dependencies: fs-exists-sync "^0.1.0" +detect-file@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + detect-indent@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" @@ -2199,11 +2420,15 @@ detect-indent@^4.0.0: dependencies: repeating "^2.0.0" +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + detective@^4.3.1: - version "4.5.0" - resolved "https://registry.yarnpkg.com/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" + version "4.7.1" + resolved "https://registry.yarnpkg.com/detective/-/detective-4.7.1.tgz#0eca7314338442febb6d65da54c10bb1c82b246e" dependencies: - acorn "^4.0.3" + acorn "^5.2.1" defined "^1.0.0" diff@1.4.0: @@ -2211,8 +2436,8 @@ diff@1.4.0: resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" diff@^3.2.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c" + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" doctrine@^1.2.2: version "1.5.0" @@ -2237,26 +2462,32 @@ duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + editions@^1.1.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" + version "1.3.4" + resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -electron-to-chromium@^1.3.24: - version "1.3.25" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.25.tgz#453b21009836d0997d86035601ff6cae4791c460" +electron-to-chromium@^1.3.30: + version "1.3.36" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.36.tgz#0eabf71a9ebea9013fb1cc35a390e068624f27e8" ember-cli-app-version@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-3.1.0.tgz#074b0330581a7b8ab094ff07fefb34e0d0254bfd" + version "3.1.3" + resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-3.1.3.tgz#26d25f5e653ff0106f0b39da6d75518ba8ed282d" dependencies: ember-cli-babel "^6.8.0" - git-repo-version "0.4.1" + git-repo-version "^1.0.0" -ember-cli-babel@6.12.0: +ember-cli-babel@6.12.0, ember-cli-babel@^6.0.0, ember-cli-babel@^6.10.0, ember-cli-babel@^6.11.0, ember-cli-babel@^6.3.0, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: version "6.12.0" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.12.0.tgz#3adcdbe1278da1fcd0b9038f1360cb4ac5d4414c" dependencies: @@ -2284,23 +2515,6 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-c ember-cli-version-checker "^1.0.2" resolve "^1.1.2" -ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2: - version "6.8.2" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.8.2.tgz#eac2785964f4743f4c815cd53c6288f00cc087d7" - dependencies: - amd-name-resolver "0.0.7" - babel-plugin-debug-macros "^0.1.11" - babel-plugin-ember-modules-api-polyfill "^2.0.1" - babel-plugin-transform-es2015-modules-amd "^6.24.0" - babel-polyfill "^6.16.0" - babel-preset-env "^1.5.1" - broccoli-babel-transpiler "^6.1.2" - broccoli-debug "^0.6.2" - broccoli-funnel "^1.0.0" - broccoli-source "^1.1.0" - clone "^2.0.0" - ember-cli-version-checker "^2.0.0" - ember-cli-blueprint-test-helpers@^0.18.3: version "0.18.3" resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.18.3.tgz#945c606d855f0263f5e8c03522e4040a74f259cc" @@ -2315,14 +2529,14 @@ ember-cli-blueprint-test-helpers@^0.18.3: tmp-sync "^1.0.0" ember-cli-broccoli-sane-watcher@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.0.4.tgz#f43f42f75b7509c212fb926cd9aea86ae19264c6" + version "2.1.1" + resolved "https://registry.yarnpkg.com/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.1.1.tgz#1687adada9022de26053fba833dc7dd10f03dd08" dependencies: broccoli-slow-trees "^3.0.1" heimdalljs "^0.2.1" heimdalljs-logger "^0.1.7" rsvp "^3.0.18" - sane "^1.1.1" + sane "^2.4.1" ember-cli-dependency-checker@^1.3.0: version "1.4.0" @@ -2357,6 +2571,16 @@ ember-cli-htmlbars-inline-precompile@^0.4.3: hash-for-dep "^1.0.2" silent-error "^1.1.0" +ember-cli-htmlbars-inline-precompile@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.2.tgz#5b544f664d5d9911f08cd979c5f70d8cb0ca2add" + dependencies: + babel-plugin-htmlbars-inline-precompile "^0.2.3" + ember-cli-version-checker "^2.0.0" + hash-for-dep "^1.0.2" + heimdalljs-logger "^0.1.7" + silent-error "^1.1.0" + ember-cli-htmlbars@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-2.0.3.tgz#e116e1500dba12f29c94b05b9ec90f52cb8bb042" @@ -2409,26 +2633,26 @@ ember-cli-is-package-missing@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" -ember-cli-legacy-blueprints@^0.1.2: - version "0.1.5" - resolved "https://registry.yarnpkg.com/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.1.5.tgz#93c15ca242ec5107d62a8af7ec30f6ac538f3ad9" +ember-cli-legacy-blueprints@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.2.1.tgz#480f37cb83f1eda2d46bbc7d07c59ea2e8ce9b84" dependencies: - chalk "^1.1.1" + chalk "^2.3.0" ember-cli-get-component-path-option "^1.0.0" ember-cli-get-dependency-depth "^1.0.0" ember-cli-is-package-missing "^1.0.0" - ember-cli-lodash-subset "^1.0.7" + ember-cli-lodash-subset "^2.0.1" ember-cli-normalize-entity-name "^1.0.0" ember-cli-path-utils "^1.0.0" ember-cli-string-utils "^1.0.0" ember-cli-test-info "^1.0.0" ember-cli-valid-component-name "^1.0.0" - ember-cli-version-checker "^1.1.7" + ember-cli-version-checker "^2.1.0" ember-router-generator "^1.0.0" exists-sync "0.0.3" - fs-extra "^0.24.0" + fs-extra "^4.0.0" inflection "^1.7.1" - rsvp "^3.0.17" + rsvp "^4.7.0" silent-error "^1.0.0" ember-cli-lodash-subset@^1.0.7: @@ -2471,21 +2695,12 @@ ember-cli-pretender@^1.0.1: pretender "^1.4.2" resolve "^1.2.0" -ember-cli-qunit@^2.1.0: - version "2.2.6" - resolved "https://registry.yarnpkg.com/ember-cli-qunit/-/ember-cli-qunit-2.2.6.tgz#d802174724edd59b61ffdd0581fceb3236014dd1" +ember-cli-qunit@^4.0.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ember-cli-qunit/-/ember-cli-qunit-4.3.2.tgz#cfd89ad3b0dbc28a9c2223d532b52eeade7c602c" dependencies: - broccoli-babel-transpiler "^5.5.0" - broccoli-concat "^2.2.0" - broccoli-funnel "^1.0.1" - broccoli-merge-trees "^1.1.0" - ember-cli-babel "^5.1.5" - ember-cli-version-checker "^1.1.4" - ember-qunit "^0.4.18" - qunit-notifications "^0.1.1" - qunitjs "^1.20.0" - resolve "^1.1.6" - rsvp "^3.2.1" + ember-cli-babel "^6.11.0" + ember-qunit "^3.3.2" ember-cli-release@^0.2.9: version "0.2.9" @@ -2502,11 +2717,13 @@ ember-cli-release@^0.2.9: silent-error "^1.0.0" ember-cli-shims@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/ember-cli-shims/-/ember-cli-shims-1.1.0.tgz#0e3b8a048be865b4f81cc81d397ff1eeb13f75b6" + version "1.2.0" + resolved "https://registry.yarnpkg.com/ember-cli-shims/-/ember-cli-shims-1.2.0.tgz#0f53aff0aab80b5f29da3a9731bac56169dd941f" dependencies: - ember-cli-babel "^6.0.0-beta.7" - ember-cli-version-checker "^1.2.0" + broccoli-file-creator "^1.1.1" + broccoli-merge-trees "^2.0.0" + ember-cli-version-checker "^2.0.0" + ember-rfc176-data "^0.3.1" silent-error "^1.0.1" ember-cli-sri@^2.1.0: @@ -2515,7 +2732,7 @@ ember-cli-sri@^2.1.0: dependencies: broccoli-sri-hash "^2.1.0" -ember-cli-string-utils@^1.0.0: +ember-cli-string-utils@^1.0.0, ember-cli-string-utils@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" @@ -2531,6 +2748,12 @@ ember-cli-test-loader@^1.1.0: dependencies: ember-cli-babel "^5.2.1" +ember-cli-test-loader@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ember-cli-test-loader/-/ember-cli-test-loader-2.2.0.tgz#3fb8d5d1357e4460d3f0a092f5375e71b6f7c243" + dependencies: + ember-cli-babel "^6.8.1" + ember-cli-uglify@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/ember-cli-uglify/-/ember-cli-uglify-1.2.0.tgz#3208c32b54bc2783056e8bb0d5cfe9bbaf17ffb2" @@ -2543,7 +2766,7 @@ ember-cli-valid-component-name@^1.0.0: dependencies: silent-error "^1.0.0" -ember-cli-version-checker@^1.0.2, ember-cli-version-checker@^1.1.4, ember-cli-version-checker@^1.1.6, ember-cli-version-checker@^1.1.7, ember-cli-version-checker@^1.2.0: +ember-cli-version-checker@^1.0.2: version "1.3.1" resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz#0bc2d134c830142da64bf9627a0eded10b61ae72" dependencies: @@ -2557,8 +2780,8 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0: semver "^5.3.0" ember-cli@^2.11.1: - version "2.16.2" - resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-2.16.2.tgz#53b922073a8e6f34255a6e0dcb1794a91ba3e1b7" + version "2.18.2" + resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-2.18.2.tgz#bb15313a15139a85248a86d203643f918ba40f57" dependencies: amd-name-resolver "1.0.0" babel-plugin-transform-es2015-modules-amd "^6.24.0" @@ -2589,7 +2812,7 @@ ember-cli@^2.11.1: diff "^3.2.0" ember-cli-broccoli-sane-watcher "^2.0.4" ember-cli-is-package-missing "^1.0.0" - ember-cli-legacy-blueprints "^0.1.2" + ember-cli-legacy-blueprints "^0.2.0" ember-cli-lodash-subset "^2.0.1" ember-cli-normalize-entity-name "^1.0.0" ember-cli-preprocess-registry "^3.1.0" @@ -2625,19 +2848,19 @@ ember-cli@^2.11.1: morgan "^1.8.1" node-modules-path "^1.0.0" nopt "^3.0.6" - npm-package-arg "^4.1.1" + npm-package-arg "^6.0.0" portfinder "^1.0.7" promise-map-series "^0.2.1" quick-temp "^0.1.8" resolve "^1.3.0" - rsvp "^3.6.0" - sane "^1.6.0" + rsvp "^4.7.0" + sane "^2.2.0" semver "^5.1.1" silent-error "^1.0.0" sort-package-json "^1.4.0" symlink-or-copy "^1.1.8" temp "0.8.3" - testem "^1.18.0" + testem "^2.0.0" tiny-lr "^1.0.3" tree-sync "^1.2.1" uuid "^3.0.0" @@ -2653,12 +2876,6 @@ ember-compatibility-helpers@^1.0.0-beta.2: ember-cli-version-checker "^2.0.0" semver "^5.4.1" -ember-dev@emberjs/ember-dev#bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed: - version "0.0.0" - resolved "https://codeload.github.com/emberjs/ember-dev/tar.gz/bcfb9c3487ec2fd58b932394a15ce16fd9cf7eed" - dependencies: - ember-cli-babel "^5.0.0" - ember-disable-prototype-extensions@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" @@ -2676,8 +2893,8 @@ ember-export-application-global@^1.0.5: ember-cli-babel "^5.1.10" ember-inflector@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ember-inflector/-/ember-inflector-2.0.1.tgz#e9ac469ffa17992a43276bb1c9b8d87992b10d37" + version "2.1.0" + resolved "https://registry.yarnpkg.com/ember-inflector/-/ember-inflector-2.1.0.tgz#afcb92d022a4eab58f08ff4578eafc3a1de2d09b" dependencies: ember-cli-babel "^6.0.0" @@ -2693,15 +2910,28 @@ ember-publisher@0.0.7: dependencies: aws-sdk "^2.0.9" -ember-qunit@^0.4.18: - version "0.4.24" - resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-0.4.24.tgz#b54cf6688c442d07eacea47c3285879cdd7c2163" +ember-qunit-assert-helpers@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ember-qunit-assert-helpers/-/ember-qunit-assert-helpers-0.2.1.tgz#4a77f8ff252e47cc53db6fa7fb4becb426de8d29" + dependencies: + broccoli-filter "^1.0.1" + ember-cli-babel "^6.9.0" + +ember-qunit@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-3.3.2.tgz#cb48e9deaffa3b4c90983f28c5cf8590894c8ea3" dependencies: - ember-test-helpers "^0.5.32" + "@ember/test-helpers" "^0.7.18" + broccoli-funnel "^2.0.1" + broccoli-merge-trees "^2.0.0" + common-tags "^1.4.0" + ember-cli-babel "^6.3.0" + ember-cli-test-loader "^2.2.0" + qunit "^2.5.0" ember-resolver@^4.1.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-4.5.0.tgz#9248bf534dfc197fafe3118fff538d436078bf99" + version "4.5.2" + resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-4.5.2.tgz#9f6d1cae036ebd2cf573e0e20a41849e12df7a4c" dependencies: "@glimmer/resolver" "^0.4.1" babel-plugin-debug-macros "^0.1.10" @@ -2715,22 +2945,22 @@ ember-rfc176-data@^0.2.0: version "0.2.7" resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.2.7.tgz#bd355bc9b473e08096b518784170a23388bc973b" -ember-rfc176-data@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.0.tgz#6aee728cb521c5f80710990965027b9c320f6f08" +ember-rfc176-data@^0.3.0, ember-rfc176-data@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.1.tgz#6a5a4b8b82ec3af34f3010965fa96b936ca94519" -ember-router-generator@^1.0.0: +ember-router-generator@^1.0.0, ember-router-generator@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" dependencies: recast "^0.11.3" ember-runtime-enumerable-includes-polyfill@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-2.0.0.tgz#6e9ba118bc909d1d7762de1b03a550d8955308a9" + version "2.1.0" + resolved "https://registry.yarnpkg.com/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-2.1.0.tgz#dc6d4a028471e4acc350dfd2a149874fb20913f5" dependencies: - ember-cli-babel "^6.0.0" - ember-cli-version-checker "^1.1.6" + ember-cli-babel "^6.9.0" + ember-cli-version-checker "^2.1.0" ember-source-channel-url@^1.0.1: version "1.0.1" @@ -2738,38 +2968,24 @@ ember-source-channel-url@^1.0.1: dependencies: got "^8.0.1" -ember-source@~2.11.0: - version "2.11.3" - resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-2.11.3.tgz#12c50cc2b4a7f8ae8c5daa3a72fb09415476c510" +ember-source@~2.18.0: + version "2.18.2" + resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-2.18.2.tgz#75d00eef5488bfe504044b025c752ba924eaf87f" dependencies: - broccoli-funnel "^1.0.6" - broccoli-merge-trees "^1.1.4" + broccoli-funnel "^2.0.1" + broccoli-merge-trees "^2.0.0" ember-cli-get-component-path-option "^1.0.0" + ember-cli-is-package-missing "^1.0.0" ember-cli-normalize-entity-name "^1.0.0" ember-cli-path-utils "^1.0.0" - ember-cli-string-utils "^1.0.0" + ember-cli-string-utils "^1.1.0" ember-cli-test-info "^1.0.0" ember-cli-valid-component-name "^1.0.0" - ember-cli-version-checker "^1.1.7" - jquery "^3.1.1" - resolve "^1.1.7" - rsvp "^3.4.0" - simple-dom "^0.3.0" - -ember-test-helpers@^0.5.32: - version "0.5.34" - resolved "https://registry.yarnpkg.com/ember-test-helpers/-/ember-test-helpers-0.5.34.tgz#c8439108d1cba1d7d838c212208a5c4061471b83" - dependencies: - klassy "^0.1.3" - -ember-try-config@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ember-try-config/-/ember-try-config-2.1.0.tgz#e0e156229a542346a58ee6f6ad605104c98edfe0" - dependencies: - lodash "^4.6.1" - node-fetch "^1.3.3" - rsvp "^3.2.1" - semver "^5.1.0" + ember-cli-version-checker "^2.1.0" + ember-router-generator "^1.2.3" + inflection "^1.12.0" + jquery "^3.2.1" + resolve "^1.3.3" ember-try-config@^2.2.0: version "2.2.0" @@ -2780,27 +2996,9 @@ ember-try-config@^2.2.0: rsvp "^3.2.1" semver "^5.1.0" -ember-try@^0.2.15: - version "0.2.17" - resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.17.tgz#0ffff687630291b4cf94f5b196e728c1a92d8aec" - dependencies: - chalk "^1.0.0" - cli-table2 "^0.2.0" - core-object "^1.1.0" - debug "^2.2.0" - ember-cli-version-checker "^1.1.6" - ember-try-config "^2.0.1" - extend "^3.0.0" - fs-extra "^0.26.0" - promise-map-series "^0.2.1" - resolve "^1.1.6" - rimraf "^2.3.2" - rsvp "^3.0.17" - semver "^5.1.0" - -ember-try@^0.2.23: - version "0.2.23" - resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.23.tgz#39b57141b4907541d0ac8b503d211e6946b08718" +ember-try@^0.2.15, ember-try@^0.2.23: + version "0.2.23" + resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.23.tgz#39b57141b4907541d0ac8b503d211e6946b08718" dependencies: chalk "^1.0.0" cli-table2 "^0.2.0" @@ -2828,8 +3026,8 @@ ember-watson@^0.7.0: walk-sync "^0.1.3" encodeurl@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" encoding@^0.1.11: version "0.1.12" @@ -2897,20 +3095,20 @@ error@^7.0.0: string-template "~0.2.1" xtend "~4.0.0" -es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.31" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.31.tgz#7bb938c95a7f1b9f728092dc09c41edcc398eefe" +es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: + version "0.10.39" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.39.tgz#fca21b67559277ca4ac1a1ed7048b107b6f76d87" dependencies: - es6-iterator "~2.0.1" + es6-iterator "~2.0.3" es6-symbol "~3.1.1" -es6-iterator@^2.0.1, es6-iterator@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" +es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" dependencies: d "1" - es5-ext "^0.10.14" - es6-symbol "^3.1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" es6-map@^0.1.3, es6-map@^0.1.4, es6-map@^0.1.5: version "0.1.5" @@ -2933,7 +3131,7 @@ es6-set@~0.1.5: es6-symbol "3.1.1" event-emitter "~0.3.5" -es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: +es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" dependencies: @@ -3009,10 +3207,10 @@ eslint@^2.13.0: user-home "^2.0.0" espree@^3.1.6: - version "3.5.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.1.tgz#0c988b8ab46db53100a1954ae4ba995ddd27d87e" + version "3.5.4" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" dependencies: - acorn "^5.1.1" + acorn "^5.5.0" acorn-jsx "^3.0.0" esprima-fb@~15001.1001.0-dev-harmony-fb: @@ -3044,11 +3242,10 @@ esprimaq@^0.0.1: resolved "https://registry.yarnpkg.com/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" esrecurse@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" dependencies: estraverse "^4.1.0" - object-assign "^4.0.1" estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" @@ -3081,6 +3278,14 @@ events@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" +exec-file-sync@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/exec-file-sync/-/exec-file-sync-2.0.2.tgz#58d441db46e40de6d1f30de5be022785bd89e328" + dependencies: + is-obj "^1.0.0" + object-assign "^4.0.1" + spawn-sync "^1.0.11" + exec-sh@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" @@ -3099,6 +3304,22 @@ execa@^0.8.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +execa@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.9.0.tgz#adb7ce62cf985071f60580deb4a88b9e34712d01" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +exists-stat@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/exists-stat/-/exists-stat-1.0.0.tgz#0660e3525a2e89d9e446129440c272edfa24b529" + exists-sync@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" @@ -3121,6 +3342,18 @@ expand-brackets@^0.1.4: dependencies: is-posix-bracket "^0.1.0" +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + expand-range@^1.8.1: version "1.8.2" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" @@ -3133,6 +3366,12 @@ expand-tilde@^1.2.2: dependencies: os-homedir "^1.0.1" +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + dependencies: + homedir-polyfill "^1.0.1" + express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: version "4.16.2" resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" @@ -3168,17 +3407,30 @@ express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: utils-merge "1.0.1" vary "~1.1.2" +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + extend@3, extend@^3.0.0, extend@~3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" -external-editor@^2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.5.tgz#52c249a3981b9ba187c7cacf5beb50bf1d91a6bc" +external-editor@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" dependencies: - iconv-lite "^0.4.17" - jschardet "^1.4.2" - tmp "^0.0.33" + extend "^3.0.0" + spawn-sync "^1.0.15" + tmp "^0.0.29" extglob@^0.3.1: version "0.3.2" @@ -3186,6 +3438,27 @@ extglob@^0.3.1: dependencies: is-extglob "^1.0.0" +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + fake-xml-http-request@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-1.6.0.tgz#bd0ac79ae3e2660098282048a12c730a6f64d550" @@ -3205,15 +3478,14 @@ fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: blank-object "^1.0.1" fast-sourcemap-concat@^1.0.1: - version "1.2.3" - resolved "https://registry.yarnpkg.com/fast-sourcemap-concat/-/fast-sourcemap-concat-1.2.3.tgz#22f14e92d739e37920334376ec8433bf675eaa04" + version "1.2.4" + resolved "https://registry.yarnpkg.com/fast-sourcemap-concat/-/fast-sourcemap-concat-1.2.4.tgz#dec83ec49fb3674bb750b92cec53b79bb7c46f67" dependencies: chalk "^0.5.1" fs-extra "^0.30.0" heimdalljs-logger "^0.1.7" memory-streams "^0.1.0" mkdirp "^0.5.0" - rsvp "^3.0.14" source-map "^0.4.2" source-map-url "^0.3.0" sourcemap-validator "^1.0.5" @@ -3255,8 +3527,8 @@ filename-regex@^2.0.0: resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" filesize@^3.1.3: - version "3.5.10" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.10.tgz#fc8fa23ddb4ef9e5e0ab6e1e64f679a24a56761f" + version "3.6.0" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.0.tgz#22d079615624bb6fd3c04026120628a41b3f4efa" fill-range@^2.1.0: version "2.2.3" @@ -3268,17 +3540,14 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" -finalhandler@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.6.tgz#007aea33d1a4d3e42017f624848ad58d212f814f" +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" dependencies: - 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" + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" finalhandler@1.1.0: version "1.1.0" @@ -3309,6 +3578,15 @@ find-up@^2.1.0: dependencies: locate-path "^2.0.0" +findup-sync@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" + dependencies: + detect-file "^1.0.0" + is-glob "^3.1.0" + micromatch "^3.0.4" + resolve-dir "^1.0.1" + findup-sync@^0.4.2: version "0.4.3" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" @@ -3360,7 +3638,7 @@ follow-redirects@0.0.7: debug "^2.2.0" stream-consume "^0.1.0" -for-in@^1.0.1: +for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -3374,6 +3652,10 @@ forever-agent@~0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + form-data@~0.1.0: version "0.1.4" resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" @@ -3382,10 +3664,24 @@ form-data@~0.1.0: combined-stream "~0.0.4" mime "~1.2.11" +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" @@ -3446,8 +3742,8 @@ fs-extra@^2.0.0: jsonfile "^2.1.0" fs-extra@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b" + version "4.0.3" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -3468,8 +3764,8 @@ fs-sync@^1.0.4: rimraf "^2.1.4" fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6: - version "0.5.6" - resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-0.5.6.tgz#342665749e8dca406800b672268c8f5073f3e623" + version "0.5.7" + resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-0.5.7.tgz#315e2b098d5fe7f622880ac965b1b051868ac871" dependencies: heimdalljs-logger "^0.1.7" object-assign "^4.1.0" @@ -3480,6 +3776,30 @@ fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" +fsevents@^1.0.0, fsevents@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.39" + +fstream-ignore@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -3519,19 +3839,25 @@ get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + git-repo-info@^1.1.2, git-repo-info@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" -git-repo-info@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.2.0.tgz#43d8513e04a24dd441330a2f7c6655a709fdbaf2" - -git-repo-version@0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-0.4.1.tgz#75fab9a0a4ec8470755b0eea7fdaa6f9d41453bf" +git-repo-version@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-1.0.2.tgz#2c8e9bee5d970cafc0dd58480f9dc56d9afe8e4f" dependencies: - git-repo-info "~1.2.0" + git-repo-info "^1.4.1" git-tools@^0.1.4: version "0.1.4" @@ -3615,6 +3941,14 @@ global-modules@^0.2.3: global-prefix "^0.1.4" is-windows "^0.2.0" +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + global-prefix@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" @@ -3624,6 +3958,16 @@ global-prefix@^0.1.4: is-windows "^0.2.0" which "^1.2.12" +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + globals@^6.4.0: version "6.4.1" resolved "https://registry.yarnpkg.com/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" @@ -3644,8 +3988,8 @@ globby@^5.0.0: pinkie-promise "^2.0.0" got@^8.0.1: - version "8.0.2" - resolved "https://registry.yarnpkg.com/got/-/got-8.0.2.tgz#94d2054767875df4d5eb330f703c63881fc9cd64" + version "8.2.0" + resolved "https://registry.yarnpkg.com/got/-/got-8.2.0.tgz#0d11a071d05046348a2f5c0a5fa047fb687fdfc6" dependencies: "@sindresorhus/is" "^0.7.0" cacheable-request "^2.1.1" @@ -3682,8 +4026,8 @@ growly@^1.3.0: resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" handlebars@^4.0.4: - version "4.0.10" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f" + version "4.0.11" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" dependencies: async "^1.4.0" optimist "^0.6.1" @@ -3691,6 +4035,17 @@ handlebars@^4.0.4: optionalDependencies: uglify-js "^2.6" +har-schema@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + +har-validator@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" + dependencies: + ajv "^4.9.1" + har-schema "^1.0.5" + has-ansi@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" @@ -3719,13 +4074,13 @@ has-cors@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" -has-flag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" has-symbol-support-x@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.1.tgz#66ec2e377e0c7d7ccedb07a3a84d77510ff1bc4c" + version "1.4.2" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" has-to-string-tag-x@^1.2.0: version "1.4.1" @@ -3737,9 +4092,36 @@ has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + hash-for-dep@^1.0.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.2.0.tgz#3bdb883aef0d34e82097ef2f7109b1b401cada6b" + version "1.2.3" + resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.2.3.tgz#5ec69fca32c23523972d52acb5bb65ffc3664cab" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" heimdalljs "^0.2.3" @@ -3755,9 +4137,18 @@ hawk@1.1.1: hoek "0.9.x" sntp "0.2.x" +hawk@3.1.3, hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + heimdall-query@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/heimdall-query/-/heimdall-query-0.1.0.tgz#4b1bb8de46dc292f2f10620bee4f81b2f5443937" + resolved "https://registry.yarnpkg.com/heimdall-query/-/heimdall-query-0.1.0.tgz#4b1bb8de46dc292f2f10620bee4f81b2f5443937" dependencies: chalk "^1.1.1" chrome-debugging-client "^0.2.4" @@ -3776,8 +4167,8 @@ heimdalljs-fs-monitor@^0.1.0: heimdalljs-logger "^0.1.7" heimdalljs-graph@^0.3.1: - version "0.3.3" - resolved "https://registry.yarnpkg.com/heimdalljs-graph/-/heimdalljs-graph-0.3.3.tgz#ea801dbba659c8d522fe1cb83b2d605726e4918f" + version "0.3.4" + resolved "https://registry.yarnpkg.com/heimdalljs-graph/-/heimdalljs-graph-0.3.4.tgz#0bd75797beeaa20b0ed59017aed3b2d95312acee" heimdalljs-logger@^0.1.7: version "0.1.9" @@ -3802,6 +4193,10 @@ hoek@0.9.x: version "0.9.1" resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + home-or-tmp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" @@ -3816,13 +4211,13 @@ home-or-tmp@^2.0.0: os-homedir "^1.0.0" os-tmpdir "^1.0.1" -homedir-polyfill@^1.0.0: +homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" dependencies: parse-passwd "^1.0.0" -hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: +hosted-git-info@^2.1.4, hosted-git-info@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" @@ -3840,8 +4235,8 @@ http-errors@1.6.2, http-errors@~1.6.2: statuses ">= 1.3.1 < 2" http-parser-js@>=0.4.0: - version "0.4.9" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.9.tgz#ea1a04fb64adff0242e9974f297dd4c3cad271e1" + version "0.4.10" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4" http-proxy@^1.13.1, http-proxy@^1.9.0: version "1.16.2" @@ -3858,6 +4253,14 @@ http-signature@~0.10.0: assert-plus "^0.1.5" ctype "0.5.3" +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + https-proxy-agent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" @@ -3866,7 +4269,7 @@ https-proxy-agent@^1.0.0: debug "2" extend "3" -iconv-lite@0.4.19, iconv-lite@^0.4.13, iconv-lite@^0.4.17, iconv-lite@^0.4.5, iconv-lite@~0.4.13: +iconv-lite@0.4.19, iconv-lite@^0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -3875,13 +4278,19 @@ ieee754@^1.1.4: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" ignore@^3.1.2: - version "3.3.5" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.5.tgz#c4e715455f6073a8d7e5dae72d2fc9d71663dba6" + version "3.3.7" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" @@ -3890,7 +4299,7 @@ inflected@^1.1.6: version "1.1.7" resolved "https://registry.yarnpkg.com/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" -inflection@^1.7.0, inflection@^1.7.1, inflection@^1.8.0: +inflection@^1.12.0, inflection@^1.7.0, inflection@^1.7.1, inflection@^1.8.0: version "1.12.0" resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" @@ -3901,13 +4310,13 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" -ini@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" +ini@^1.3.4, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" inline-source-map-comment@^1.0.5: version "1.0.5" @@ -3937,23 +4346,23 @@ inquirer@^0.12.0: strip-ansi "^3.0.0" through "^2.3.6" -inquirer@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" +inquirer@^2: + version "2.0.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-2.0.0.tgz#e1351687b90d150ca403ceaa3cefb1e3065bef4b" dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" + ansi-escapes "^1.1.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" cli-width "^2.0.0" - external-editor "^2.0.4" + external-editor "^1.1.0" figures "^2.0.0" lodash "^4.3.0" - mute-stream "0.0.7" + mute-stream "0.0.6" + pinkie-promise "^2.0.0" run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" - string-width "^2.1.0" - strip-ansi "^4.0.0" + rx "^4.1.0" + string-width "^2.0.0" + strip-ansi "^3.0.0" through "^2.3.6" into-stream@^3.1.0: @@ -3964,8 +4373,8 @@ into-stream@^3.1.0: p-is-promise "^1.1.0" invariant@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + version "2.2.3" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.3.tgz#1a827dfde7dcbd7c323f0ca826be8fa7c5e9d688" dependencies: loose-envify "^1.0.0" @@ -3973,17 +4382,35 @@ invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" -ipaddr.js@1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.5.2.tgz#d4b505bde9946987ccf0fc58d9010ff9607e3fa0" +ipaddr.js@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + is-buffer@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" is-builtin-module@^1.0.0: version "1.0.0" @@ -3991,6 +4418,34 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" @@ -4001,14 +4456,24 @@ is-equal-shallow@^0.1.3: dependencies: is-primitive "^2.0.0" -is-extendable@^0.1.1: +is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" +is-extglob@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + is-finite@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" @@ -4039,18 +4504,29 @@ is-glob@^2.0.0, is-glob@^2.0.1: dependencies: is-extglob "^1.0.0" +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + is-integer@^1.0.4: version "1.0.7" resolved "https://registry.yarnpkg.com/is-integer/-/is-integer-1.0.7.tgz#6bde81aacddf78b659b6629d629cadc51a886d5c" dependencies: is-finite "^1.0.0" +is-my-ip-valid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824" + is-my-json-valid@^2.10.0: - version "2.16.1" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz#5a846777e2c2620d1e69104e5d3a03b1f6088f11" + version "2.17.2" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz#6b2103a288e94ef3de5cf15d29dd85fc4b78d65c" dependencies: generate-function "^2.0.0" generate-object-property "^1.1.0" + is-my-ip-valid "^1.0.0" jsonpointer "^4.0.0" xtend "^4.0.0" @@ -4066,6 +4542,10 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" @@ -4074,6 +4554,12 @@ is-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" +is-odd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" + dependencies: + is-number "^4.0.0" + is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -4085,8 +4571,8 @@ is-path-in-cwd@^1.0.0: is-path-inside "^1.0.0" is-path-inside@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" dependencies: path-is-inside "^1.0.1" @@ -4094,6 +4580,12 @@ is-plain-obj@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" @@ -4115,10 +4607,8 @@ is-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" is-resolvable@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" - dependencies: - tryit "^1.0.1" + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" is-retry-allowed@^1.1.0: version "1.1.0" @@ -4134,6 +4624,10 @@ is-type@0.0.1: dependencies: core-util-is "~1.0.0" +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" @@ -4142,6 +4636,10 @@ is-windows@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" +is-windows@^1.0.1, is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -4164,6 +4662,14 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + istextorbinary@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" @@ -4190,9 +4696,13 @@ jmespath@0.15.0: version "0.15.0" resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" -jquery@^3.1.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787" +jquery@^3.2.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" + +js-reporters@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b" js-string-escape@^1.0.0, js-string-escape@^1.0.1: version "1.0.1" @@ -4207,15 +4717,15 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: - version "3.10.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" + version "3.11.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" dependencies: argparse "^1.0.7" esprima "^4.0.0" -jschardet@^1.4.2: - version "1.5.1" - resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.5.1.tgz#c519f629f86b3a5bedba58a88d311309eec097f9" +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" jsesc@^1.3.0: version "1.3.0" @@ -4244,13 +4754,17 @@ json-buffer@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: jsonify "~0.0.0" -json-stringify-safe@~5.0.0: +json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -4293,13 +4807,22 @@ jsonpointer@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + keyv@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" dependencies: json-buffer "3.0.0" -kind-of@^3.0.2: +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" dependencies: @@ -4311,9 +4834,13 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" -klassy@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/klassy/-/klassy-0.1.3.tgz#c31d5756d583197d75f582b6e692872be497067f" +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" klaw@^1.0.0: version "1.3.1" @@ -4325,6 +4852,12 @@ lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" +lazy-cache@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264" + dependencies: + set-getter "^0.1.0" + lcid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" @@ -4362,9 +4895,9 @@ linkify-it@~1.2.0: dependencies: uc.micro "^1.0.1" -livereload-js@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" +livereload-js@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.3.0.tgz#c3ab22e8aaf5bf3505d80d098cbad67726548c9a" load-json-file@^1.0.0: version "1.1.0" @@ -4545,6 +5078,10 @@ lodash.bind@~2.3.0: lodash._renative "~2.3.0" lodash._slice "~2.3.0" +lodash.castarray@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" + lodash.clonedeep@^4.4.1: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -4635,8 +5172,8 @@ lodash.keys@~2.3.0: lodash.isobject "~2.3.0" lodash.merge@^4.3.0, lodash.merge@^4.4.0, lodash.merge@^4.5.1, lodash.merge@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5" + version "4.6.1" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" lodash.noop@~2.3.0: version "2.3.0" @@ -4707,14 +5244,14 @@ lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.16.1, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1: - version "4.17.4" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + version "4.17.5" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" -log-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" +log-symbols@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" dependencies: - chalk "^1.0.0" + chalk "^2.0.1" longest@^1.0.1: version "1.0.1" @@ -4726,9 +5263,16 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0" -lowercase-keys@1.0.0, lowercase-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lowercase-keys@1.0.0, lowercase-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" lru-cache@2: version "2.7.3" @@ -4746,10 +5290,10 @@ make-array@^0.1.2: resolved "https://registry.yarnpkg.com/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" make-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.0.0.tgz#97a011751e91dd87cfadef58832ebb04936de978" + version "1.2.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b" dependencies: - pify "^2.3.0" + pify "^3.0.0" makeerror@1.0.x: version "1.0.11" @@ -4757,6 +5301,20 @@ makeerror@1.0.x: dependencies: tmpl "1.0.x" +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + markdown-it-terminal@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/markdown-it-terminal/-/markdown-it-terminal-0.1.0.tgz#545abd8dd01c3d62353bfcea71db580b51d22bd9" @@ -4778,14 +5336,14 @@ markdown-it@^4.3.0: uc.micro "^1.0.0" markdown-it@^8.3.0, markdown-it@^8.3.1: - version "8.4.0" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.0.tgz#e2400881bf171f7018ed1bd9da441dac8af6306d" + version "8.4.1" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.1.tgz#206fe59b0e4e1b78a7c73250af9b34a4ad0aaf44" dependencies: argparse "^1.0.7" entities "~1.1.1" linkify-it "^2.0.0" mdurl "^1.0.1" - uc.micro "^1.0.3" + uc.micro "^1.0.5" matcher-collection@^1.0.0, matcher-collection@^1.0.4: version "1.0.5" @@ -4816,11 +5374,26 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" memory-streams@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.2.tgz#273ff777ab60fec599b116355255282cca2c50c2" + version "0.1.3" + resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.3.tgz#d9b0017b4b87f1d92f55f2745c9caacb1dc93ceb" dependencies: readable-stream "~1.0.2" +meow@^3.4.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -4862,31 +5435,53 @@ micromatch@^2.1.5, micromatch@^2.3.7: parse-glob "^3.0.4" regex-cache "^0.4.2" -"mime-db@>= 1.29.0 < 2", mime-db@~1.30.0: - version "1.30.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" +micromatch@^3.0.4: + version "3.1.9" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.9.tgz#15dc93175ae39e52e93087847096effc73efcf89" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +"mime-db@>= 1.33.0 < 2", mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + +mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.11, mime-types@~2.1.18, mime-types@~2.1.7: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + dependencies: + mime-db "~1.33.0" mime-types@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" -mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.16: - version "2.1.17" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" - dependencies: - mime-db "~1.30.0" - -mime@1.4.1, mime@^1.2.11: +mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" +mime@^1.2.11: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + mime@~1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" mimic-fn@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" mimic-response@^1.0.0: version "1.0.0" @@ -4915,7 +5510,7 @@ minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@^1.1.0, minimist@^1.1.1: +minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -4923,11 +5518,18 @@ minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + mkdirp@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" -mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: +mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: @@ -4967,8 +5569,8 @@ moment-timezone@^0.3.0: moment ">= 2.6.0" "moment@>= 2.6.0": - version "2.19.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.1.tgz#56da1a2d1cbf01d38b7e1afc31c10bcfa1929167" + version "2.21.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.21.0.tgz#2a114b51d2a6ec9e6d83cf803f838a878d8a023a" morgan@^1.7.0, morgan@^1.8.1: version "1.9.0" @@ -5004,18 +5606,35 @@ mute-stream@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" +mute-stream@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" -nan@^2.0.5: - version "2.7.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46" +nan@^2.0.5, nan@^2.3.0: + version "2.9.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.9.2.tgz#f564d75f5f8f36a6d9456cca7a6c4fe488ab7866" nan@~2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232" +nanomatch@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-odd "^2.0.0" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" @@ -5036,13 +5655,29 @@ node-modules-path@^1.0.0, node-modules-path@^1.0.1: resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" node-notifier@^5.0.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff" + version "5.2.1" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" dependencies: growly "^1.3.0" + semver "^5.4.1" + shellwords "^0.1.1" + which "^1.3.0" + +node-pre-gyp@^0.6.39: + version "0.6.39" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" + dependencies: + detect-libc "^1.0.2" + hawk "3.1.3" + mkdirp "^0.5.1" + nopt "^4.0.1" + npmlog "^4.0.2" + rc "^1.1.7" + request "2.81.0" + rimraf "^2.6.1" semver "^5.3.0" - shellwords "^0.1.0" - which "^1.2.12" + tar "^2.2.1" + tar-pack "^3.4.0" node-uuid@~1.4.0: version "1.4.8" @@ -5054,7 +5689,14 @@ nopt@^3.0.3, nopt@^3.0.6: dependencies: abbrev "1" -normalize-package-data@^2.3.2: +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: @@ -5081,12 +5723,14 @@ npm-git-info@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" -npm-package-arg@^4.1.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" +npm-package-arg@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.0.0.tgz#8cce04b49d3f9faec3f56b0fe5f4391aeb9d2fac" dependencies: - hosted-git-info "^2.1.5" - semver "^5.1.0" + hosted-git-info "^2.5.0" + osenv "^0.1.4" + semver "^5.4.1" + validate-npm-package-name "^3.0.0" npm-run-path@^2.0.0: version "2.0.2" @@ -5094,7 +5738,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -npmlog@^4.0.0: +npmlog@^4.0.0, npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" dependencies: @@ -5111,6 +5755,10 @@ oauth-sign@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + object-assign@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" @@ -5123,6 +5771,20 @@ object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" @@ -5130,6 +5792,12 @@ object.omit@^2.0.0: for-own "^0.1.4" is-extendable "^0.1.1" +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -5140,7 +5808,7 @@ on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" -once@^1.3.0: +once@^1.3.0, once@^1.3.3: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: @@ -5178,14 +5846,16 @@ options@>=0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" -ora@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-1.3.0.tgz#80078dd2b92a934af66a3ad72a5b910694ede51a" +ora@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-2.0.0.tgz#8ec3a37fa7bffb54a3a0c188a1f6798e7e1827cd" dependencies: - chalk "^1.1.1" + chalk "^2.3.1" cli-cursor "^2.1.0" - cli-spinners "^1.0.0" - log-symbols "^1.0.2" + cli-spinners "^1.1.0" + log-symbols "^2.2.0" + strip-ansi "^4.0.0" + wcwidth "^1.0.1" os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" @@ -5197,13 +5867,17 @@ os-locale@^1.4.0: dependencies: lcid "^1.0.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: +os-shim@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -osenv@^0.1.0, osenv@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" +osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" @@ -5233,8 +5907,10 @@ p-is-promise@^1.1.0: resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" p-limit@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" + dependencies: + p-try "^1.0.0" p-locate@^2.0.0: version "2.0.0" @@ -5248,6 +5924,10 @@ p-timeout@^2.0.1: dependencies: p-finally "^1.0.0" +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -5289,6 +5969,16 @@ parseurl@~1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + +passwd-user@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/passwd-user/-/passwd-user-1.2.1.tgz#a01a5dc639ef007dc56364b8178569080ad3a7b8" + dependencies: + exec-file-sync "^2.0.0" + path-exists@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" @@ -5339,7 +6029,11 @@ pathval@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" -pify@^2.0.0, pify@^2.3.0: +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + +pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -5373,6 +6067,10 @@ portfinder@^1.0.7: debug "^2.2.0" mkdirp "0.5.x" +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -5386,8 +6084,8 @@ preserve@^0.2.0: resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" pretender@^1.4.2: - version "1.6.0" - resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.6.0.tgz#0bb6dc9622b576772938814bc36f7cf2f86660dd" + version "1.6.1" + resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.6.1.tgz#77d1e42ac8c6b298f5cd43534a87645df035db8c" dependencies: fake-xml-http-request "^1.6.0" route-recognizer "^0.3.3" @@ -5397,12 +6095,12 @@ printf@^0.2.3: resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" private@^0.1.6, private@^0.1.7, private@~0.1.5: - version "0.1.7" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" process-relative-require@^1.0.0: version "1.0.0" @@ -5421,11 +6119,11 @@ promise-map-series@^0.2.1: rsvp "^3.0.14" proxy-addr@~2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec" + version "2.0.3" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" dependencies: forwarded "~0.1.2" - ipaddr.js "1.5.2" + ipaddr.js "1.6.0" pseudomap@^1.0.2: version "1.0.2" @@ -5440,8 +6138,8 @@ punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" q@^1.1.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" qs@6.5.1, qs@^6.4.0: version "6.5.1" @@ -5451,9 +6149,13 @@ qs@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" +qs@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + query-string@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.0.1.tgz#6e2b86fe0e08aef682ecbe86e85834765402bd88" + version "5.1.0" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.0.tgz#9583b15fd1307f899e973ed418886426a9976469" dependencies: decode-uri-component "^0.2.0" object-assign "^4.1.0" @@ -5464,10 +6166,11 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" quibble@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/quibble/-/quibble-0.5.1.tgz#b7fd1fc0a9c1eea012ac9d71bcb6da8d9a5dc9e9" + version "0.5.3" + resolved "https://registry.yarnpkg.com/quibble/-/quibble-0.5.3.tgz#3dfd53206fc6873f61c96f3bece63b69747b4d0c" dependencies: lodash "^4.17.2" + resolve "^1.5.0" quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: version "0.1.8" @@ -5477,13 +6180,18 @@ quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quic rimraf "^2.5.4" underscore.string "~3.3.4" -qunit-notifications@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/qunit-notifications/-/qunit-notifications-0.1.1.tgz#3001afc6a6a77dfbd962ccbcddde12dec5286c09" - -qunitjs@^1.20.0: - version "1.23.1" - resolved "https://registry.yarnpkg.com/qunitjs/-/qunitjs-1.23.1.tgz#1971cf97ac9be01a64d2315508d2e48e6fd4e719" +qunit@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/qunit/-/qunit-2.5.1.tgz#739b0ea9595bbf508b0600d5af04dcb2ba2a74e5" + dependencies: + chokidar "1.7.0" + commander "2.12.2" + exists-stat "1.0.0" + findup-sync "2.0.0" + js-reporters "1.2.1" + resolve "1.5.0" + shelljs "^0.2.6" + walk-sync "0.3.2" randomatic@^1.1.3: version "1.1.7" @@ -5512,6 +6220,15 @@ raw-body@~1.1.0: bytes "1" string_decoder "0.10" +rc@^1.1.7: + version "1.2.5" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.5.tgz#275cd687f6e3b36cc756baa26dfee80a790301fd" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -5527,14 +6244,14 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^2, readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.2.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" +readable-stream@^2, readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2: + version "2.3.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.5.tgz#b4f85003a938cbb6ecbce2a124fb1012bd1a838d" dependencies: core-util-is "~1.0.0" inherits "~2.0.3" isarray "~1.0.0" - process-nextick-args "~1.0.6" + process-nextick-args "~2.0.0" safe-buffer "~5.1.1" string_decoder "~1.0.3" util-deprecate "~1.0.1" @@ -5548,6 +6265,15 @@ readable-stream@~1.0.2: isarray "0.0.1" string_decoder "~0.10.x" +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + readline2@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" @@ -5583,6 +6309,13 @@ recast@^0.11.17, recast@^0.11.3: private "~0.1.5" source-map "~0.5.0" +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + redeyed@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" @@ -5598,8 +6331,8 @@ regenerator-runtime@^0.10.5: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" regenerator-runtime@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" regenerator-transform@^0.10.0: version "0.10.1" @@ -5626,6 +6359,13 @@ regex-cache@^0.4.2: dependencies: is-equal-shallow "^0.1.3" +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -5662,7 +6402,7 @@ repeat-element@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" -repeat-string@^1.5.2: +repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" @@ -5678,6 +6418,33 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" +request@2.81.0: + version "2.81.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~4.2.1" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + performance-now "^0.2.0" + qs "~6.4.0" + safe-buffer "^5.0.1" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "^0.6.0" + uuid "^3.0.0" + request@~2.40.0: version "2.40.0" resolved "https://registry.yarnpkg.com/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" @@ -5723,17 +6490,22 @@ resolve-dir@^0.1.0: expand-tilde "^1.2.2" global-modules "^0.2.3" +resolve-dir@^1.0.0, resolve-dir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" -resolve@^1.1.2, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" - dependencies: - path-parse "^1.0.5" +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" -resolve@^1.5.0: +resolve@1.5.0, resolve@^1.1.2, resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: @@ -5759,24 +6531,28 @@ restore-cursor@^2.0.0: onetime "^2.0.0" signal-exit "^3.0.2" +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" dependencies: align-text "^0.1.1" +rimraf@2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + rimraf@2.5.2: version "2.5.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" -rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - dependencies: - glob "^7.0.5" - rimraf@~2.2.6: version "2.2.8" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" @@ -5795,10 +6571,14 @@ rsvp@4.8.0: version "4.8.0" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.0.tgz#dc1dc400e2d48bcf3b1991f2a3b714f038fc432e" -rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.4.0, rsvp@^3.5.0, rsvp@^3.6.0: +rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.5.0: version "3.6.2" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" +rsvp@^4.7.0: + version "4.8.2" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.2.tgz#9d5647108735784eb13418cdddb56f75b919d722" + rsvp@~3.0.6: version "3.0.21" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" @@ -5819,21 +6599,15 @@ run-async@^2.2.0: dependencies: is-promise "^2.1.0" -rx-lite-aggregates@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" - dependencies: - rx-lite "*" - -rx-lite@*, rx-lite@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" - rx-lite@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" -safe-buffer@5.1.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +rx@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + +safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -5841,7 +6615,13 @@ safe-json-parse@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" -sane@^1.1.1, sane@^1.4.1, sane@^1.6.0: +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + +sane@^1.4.1: version "1.7.0" resolved "https://registry.yarnpkg.com/sane/-/sane-1.7.0.tgz#b3579bccb45c94cf20355cc81124990dfd346e30" dependencies: @@ -5853,6 +6633,20 @@ sane@^1.1.1, sane@^1.4.1, sane@^1.6.0: walker "~1.0.5" watch "~0.10.0" +sane@^2.2.0, sane@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/sane/-/sane-2.4.1.tgz#29f991208cf28636720efdc584293e7fd66663a5" + dependencies: + anymatch "^1.3.0" + exec-sh "^0.2.0" + fb-watchman "^2.0.0" + minimatch "^3.0.2" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.18.0" + optionalDependencies: + fsevents "^1.1.1" + sax@0.6.x: version "0.6.1" resolved "https://registry.yarnpkg.com/sax/-/sax-0.6.1.tgz#563b19c7c1de892e09bfc4f2fc30e3c27f0952b9" @@ -5875,18 +6669,14 @@ selenium-webdriver@2.48.2: ws "^0.8.0" xml2js "0.4.4" -"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" +"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0, semver@^5.4.1: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" semver@^4.1.0, semver@^4.3.1: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" -semver@^5.4.1: - version "5.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" - semver@~5.0.1: version "5.0.3" resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" @@ -5922,6 +6712,34 @@ set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" +set-getter@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376" + dependencies: + to-object-path "^0.3.0" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + setprototypeof@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" @@ -5940,11 +6758,15 @@ shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" +shelljs@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.2.6.tgz#90492d72ffcc8159976baba62fb0f6884f0c3378" + shelljs@^0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" -shellwords@^0.1.0: +shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" @@ -5962,10 +6784,6 @@ silent-error@^1.0.0, silent-error@^1.0.1, silent-error@^1.1.0: dependencies: debug "^2.2.0" -simple-dom@^0.3.0: - version "0.3.2" - resolved "https://registry.yarnpkg.com/simple-dom/-/simple-dom-0.3.2.tgz#0663d10f1556f1500551d518f56e3aba0871371d" - simple-fmt@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" @@ -5986,12 +6804,45 @@ slide@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.1.tgz#e12b5487faded3e3dea0ac91e9400bf75b401370" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^2.0.0" + sntp@0.2.x: version "0.2.4" resolved "https://registry.yarnpkg.com/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" dependencies: hoek "0.9.x" +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + socket.io-adapter@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" @@ -6047,11 +6898,21 @@ sort-object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" sort-package-json@^1.4.0: - version "1.7.1" - resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.7.1.tgz#f2e5fbffe8420cc1bb04485f4509f05e73b4c0f2" + version "1.11.0" + resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.11.0.tgz#b7b59ebdfaf3f8719ec0bc2056264e937868cbfb" dependencies: sort-object-keys "^1.1.1" +source-map-resolve@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a" + dependencies: + atob "^2.0.0" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + source-map-support@^0.2.10: version "0.2.10" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" @@ -6068,6 +6929,10 @@ source-map-url@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + source-map@0.1.32: version "0.1.32" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" @@ -6080,7 +6945,7 @@ source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: dependencies: amdefine ">=0.0.4" -source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: +source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0, source-map@~0.5.1: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -6091,8 +6956,8 @@ source-map@~0.1.x: amdefine ">=0.0.4" sourcemap-validator@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/sourcemap-validator/-/sourcemap-validator-1.0.6.tgz#abd2f1ecdae6a3c46c2c96c5f256705b2147c9c0" + version "1.0.7" + resolved "https://registry.yarnpkg.com/sourcemap-validator/-/sourcemap-validator-1.0.7.tgz#d76aaadbe2c6ec269293b5f212100fad91eef260" dependencies: jsesc "~0.3.x" lodash.foreach "~2.3.x" @@ -6103,23 +6968,44 @@ spawn-args@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" +spawn-sync@^1.0.11, spawn-sync@^1.0.15: + version "1.0.15" + resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + dependencies: + concat-stream "^1.4.7" + os-shim "^0.1.2" + spawnback@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" -spdx-correct@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" +spdx-correct@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" dependencies: - spdx-license-ids "^1.0.2" + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" -spdx-expression-parse@~1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" +spdx-exceptions@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" -spdx-license-ids@^1.0.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" sprintf-js@^1.0.3: version "1.1.1" @@ -6133,17 +7019,42 @@ sri-toolbox@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" +sshpk@^1.7.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + stable@~0.1.3: version "0.1.6" resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10" -"statuses@>= 1.3.1 < 2", statuses@~1.3.1: +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.3.1 < 2": + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + +statuses@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" stream-consume@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f" + version "0.1.1" + resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.1.tgz#d3bdb598c2bd0ae82b8cac7ac50b1107a7996c48" strict-uri-encode@^1.0.0: version "1.1.0" @@ -6161,7 +7072,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0, string-width@^2.1.0: +string-width@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: @@ -6229,10 +7140,20 @@ strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + dependencies: + get-stdin "^4.0.1" + strip-json-comments@~1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + styled_string@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" @@ -6255,15 +7176,15 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -supports-color@^4.0.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" +supports-color@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" dependencies: - has-flag "^2.0.0" + has-flag "^3.0.0" symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.1.8.tgz#cabe61e0010c1c023c173b25ee5108b37f4b4aa3" + version "1.2.0" + resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" table@^3.7.8: version "3.8.3" @@ -6285,6 +7206,27 @@ tap-parser@^5.1.0: optionalDependencies: readable-stream "^2" +tar-pack@^3.4.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" + dependencies: + debug "^2.2.0" + fstream "^1.0.10" + fstream-ignore "^1.0.5" + once "^1.3.3" + readable-stream "^2.1.4" + rimraf "^2.5.1" + tar "^2.2.1" + uid-number "^0.0.6" + +tar@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + temp@0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" @@ -6293,16 +7235,15 @@ temp@0.8.3: rimraf "~2.2.6" testdouble@^3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/testdouble/-/testdouble-3.2.6.tgz#8fc47149c59f1becc795bf80f02b41de30ea4035" + version "3.5.2" + resolved "https://registry.yarnpkg.com/testdouble/-/testdouble-3.5.2.tgz#7ac91d08be05bac3b2acba57c430f6c62d0ad8af" dependencies: es6-map "^0.1.5" lodash "^4.17.4" quibble "^0.5.1" - resolve "^1.3.3" stringify-object-es5 "^2.5.0" -testem@^1.15.0, testem@^1.18.0: +testem@^1.15.0: version "1.18.4" resolved "https://registry.yarnpkg.com/testem/-/testem-1.18.4.tgz#e45fed922bec2f54a616c43f11922598ac97eb41" dependencies: @@ -6333,13 +7274,45 @@ testem@^1.15.0, testem@^1.18.0: tap-parser "^5.1.0" xmldom "^0.1.19" +testem@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/testem/-/testem-2.0.0.tgz#b05c96200c7ac98bae998d71c94c0c5345907d13" + dependencies: + backbone "^1.1.2" + bluebird "^3.4.6" + charm "^1.0.0" + commander "^2.6.0" + consolidate "^0.14.0" + execa "^0.9.0" + express "^4.10.7" + fireworm "^0.7.0" + glob "^7.0.4" + http-proxy "^1.13.1" + js-yaml "^3.2.5" + lodash.assignin "^4.1.0" + lodash.castarray "^4.4.0" + lodash.clonedeep "^4.4.1" + lodash.find "^4.5.1" + lodash.uniqby "^4.7.0" + mkdirp "^0.5.1" + mustache "^2.2.1" + node-notifier "^5.0.1" + npmlog "^4.0.0" + printf "^0.2.3" + rimraf "^2.4.4" + socket.io "1.6.0" + spawn-args "^0.2.0" + styled_string "0.0.1" + tap-parser "^5.1.0" + xmldom "^0.1.19" + text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" "textextensions@1 || 2": - version "2.1.0" - resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.1.0.tgz#1be0dc2a0dc244d44be8a09af6a85afb93c4dbc3" + version "2.2.0" + resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" through@^2.3.6, through@^2.3.8, through@~2.3.8: version "2.3.8" @@ -6350,13 +7323,13 @@ timed-out@^4.0.1: resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" tiny-lr@^1.0.3: - version "1.0.5" - resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.0.5.tgz#21f40bf84ebd1f853056680375eef1670c334112" + version "1.1.1" + resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" dependencies: body "^5.1.0" - debug "~2.6.7" + debug "^3.1.0" faye-websocket "~0.10.0" - livereload-js "^2.2.2" + livereload-js "^2.3.0" object-assign "^4.1.0" qs "^6.4.0" @@ -6383,11 +7356,11 @@ tmp@0.0.31: dependencies: os-tmpdir "~1.0.1" -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" +tmp@^0.0.29: + version "0.0.29" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" dependencies: - os-tmpdir "~1.0.2" + os-tmpdir "~1.0.1" tmpl@1.0.x: version "1.0.4" @@ -6405,9 +7378,31 @@ to-iso-string@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" -tough-cookie@>=0.12.0: - version "2.3.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +tough-cookie@>=0.12.0, tough-cookie@~2.3.0: + version "2.3.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" dependencies: punycode "^1.4.1" @@ -6421,6 +7416,10 @@ tree-sync@^1.2.1, tree-sync@^1.2.2: quick-temp "^0.1.5" walk-sync "^0.2.7" +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + trim-right@^1.0.0, trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" @@ -6429,18 +7428,24 @@ try-resolve@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" -tryit@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" - tryor@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + tunnel-agent@~0.4.0: version "0.4.3" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -6456,23 +7461,23 @@ type-detect@^1.0.0: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" type-detect@^4.0.0: - version "4.0.5" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.5.tgz#d70e5bc81db6de2a381bcaca0c6e0cbdc7635de2" + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" type-is@~1.6.15: - version "1.6.15" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" dependencies: media-typer "0.3.0" - mime-types "~2.1.15" + mime-types "~2.1.18" typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" +uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" uglify-js@^2.6, uglify-js@^2.7.0: version "2.8.29" @@ -6487,6 +7492,10 @@ uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" +uid-number@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + ultron@1.0.x: version "1.0.2" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" @@ -6502,6 +7511,15 @@ underscore@>=1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + unique-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" @@ -6516,12 +7534,23 @@ unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + untildify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" dependencies: os-homedir "^1.0.0" +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" @@ -6539,6 +7568,14 @@ url@0.10.3: punycode "1.3.2" querystring "0.2.0" +use@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/use/-/use-2.0.2.tgz#ae28a0d72f93bf22422a18a2e379993112dec8e8" + dependencies: + define-property "^0.2.5" + isobject "^3.0.0" + lazy-cache "^2.0.2" + user-home@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" @@ -6549,10 +7586,24 @@ user-home@^2.0.0: dependencies: os-homedir "^1.0.0" +user-info@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/user-info/-/user-info-1.0.0.tgz#81c82b7ed63e674c2475667653413b3c76fde239" + dependencies: + os-homedir "^1.0.1" + passwd-user "^1.2.1" + username "^1.0.1" + username-sync@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/username-sync/-/username-sync-1.0.1.tgz#1cde87eefcf94b8822984d938ba2b797426dae1f" +username@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/username/-/username-1.0.1.tgz#e1f72295e3e58e06f002c6327ce06897a99cd67f" + dependencies: + meow "^3.4.0" + utf-8-validate@1.2.x: version "1.2.2" resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-1.2.2.tgz#8bb871a4741e085c70487ca7acdbd7d6d36029eb" @@ -6568,7 +7619,7 @@ utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" -uuid@3.1.0, uuid@^3.0.0: +uuid@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" @@ -6576,12 +7627,16 @@ uuid@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" +uuid@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" + validate-npm-package-license@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + version "3.0.3" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" dependencies: - spdx-correct "~1.0.0" - spdx-expression-parse "~1.0.0" + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" validate-npm-package-name@^3.0.0: version "3.0.0" @@ -6593,6 +7648,21 @@ vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +walk-sync@0.3.2, walk-sync@^0.3.0, walk-sync@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" + dependencies: + ensure-posix-path "^1.0.0" + matcher-collection "^1.0.0" + walk-sync@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" @@ -6604,13 +7674,6 @@ walk-sync@^0.2.5, walk-sync@^0.2.7: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" -walk-sync@^0.3.0, walk-sync@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" - dependencies: - ensure-posix-path "^1.0.0" - matcher-collection "^1.0.0" - walker@~1.0.5: version "1.0.7" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" @@ -6621,6 +7684,19 @@ watch@~0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" +watch@~0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + dependencies: + exec-sh "^0.2.0" + minimist "^1.2.0" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + dependencies: + defaults "^1.0.3" + websocket-driver@>=0.5.1: version "0.7.0" resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" @@ -6629,14 +7705,14 @@ websocket-driver@>=0.5.1: websocket-extensions ">=0.1.1" websocket-extensions@>=0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.2.tgz#0e18781de629a18308ce1481650f67ffa2693a5d" + version "0.1.3" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" which-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" -which@^1.2.12, which@^1.2.9: +which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" dependencies: @@ -6672,7 +7748,7 @@ wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" -workerpool@^2.2.1: +workerpool@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-2.3.0.tgz#86c5cbe946b55e7dc9d12b1936c8801a6e2d744d" dependencies: @@ -6729,8 +7805,8 @@ ws@^0.8.0: utf-8-validate "1.2.x" ws@^1.0.1: - version "1.1.4" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.4.tgz#57f40d036832e5f5055662a397c4de76ed66bf61" + version "1.1.5" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51" dependencies: options ">=0.0.5" ultron "1.0.x" @@ -6770,8 +7846,8 @@ xmlbuilder@4.2.1, xmlbuilder@^4.1.0: lodash "^4.0.0" xmlbuilder@>=1.0.0: - version "9.0.4" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.4.tgz#519cb4ca686d005a8420d3496f3f0caeecca580f" + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" xmldom@^0.1.19: version "0.1.27" From 93b5d26314abf54616787f292889e9b6bdaf7bd5 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Mon, 12 Mar 2018 09:30:19 -0700 Subject: [PATCH 2146/2527] Remove $.parseJSON usage Working towards #5320 --- addon/adapters/json-api.js | 3 +-- addon/adapters/rest.js | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index 3d6d986a305..d321e91659b 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -3,7 +3,6 @@ @module ember-data */ import { dasherize } from '@ember/string'; -import $ from 'jquery'; import RESTAdapter from "./rest"; import { isEnabled } from '../-private'; import { deprecate } from '@ember/debug'; @@ -170,7 +169,7 @@ const JSONAPIAdapter = RESTAdapter.extend({ let token = heimdall.start('json.parse'); let json; try { - json = $.parseJSON(payload); + json = JSON.parse(payload); } catch (e) { json = payload; } diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 7686435c300..c2d02d92cbd 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1115,7 +1115,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { let token = heimdall.start('json.parse'); let json; try { - json = $.parseJSON(payload); + json = JSON.parse(payload); } catch (e) { json = payload; } @@ -1150,7 +1150,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { let json = responseText; try { - json = $.parseJSON(responseText); + json = JSON.parse(responseText); } catch (e) { // ignored } @@ -1473,7 +1473,7 @@ if (isEnabled('ds-improved-ajax')) { let token = heimdall.start('json.parse'); let json; try { - json = $.parseJSON(payload); + json = JSON.parse(payload); } catch (e) { json = payload; } From 872f015bdc842cceb2aab113f85123d147a20c7c Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Tue, 13 Mar 2018 17:39:31 -0700 Subject: [PATCH 2147/2527] [bugfix beta] invalidate link promise on inverse unload (#5377) * unload should invalidate async hasMany * observing a hasMany and reading it immediately triggers an error * [bugfix beta] Invalidate link on inverse unload Invalidates link promises when inverse records are unloaded. Subsequent fetches of a `hasMany` unloaded in this way will load from the link again, rather than loading whatever ids were returned from the prior link load. [fix #5354] --- .../relationships/state/relationship.js | 1 + tests/integration/records/unload-test.js | 81 +++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 5891d8ed8b3..d6c97f5e7b9 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -130,6 +130,7 @@ export default class Relationship { } inverseDidDematerialize(inverseInternalModel) { + this.linkPromise = null; if (!this.isAsync) { // unloading inverse of a sync relationship is treated as a client-side // delete, so actually remove the models don't merely invalidate the cp diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 3afc287f901..34e98b168cc 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -2008,3 +2008,84 @@ test('1 sync : many async unload sync side', function(assert) { }) ); }); + +test('unload invalidates link promises', function(assert) { + let isUnloaded = false; + env.adapter.coalesceFindRequests = false; + + env.adapter.findRecord = (/* store, type, id */) => { + assert.notOk('Records only expected to be loaded via link'); + }; + + env.adapter.findHasMany = (store, snapshot, link) => { + assert.equal(snapshot.modelName, 'person', 'findHasMany(_, snapshot) is correct'); + assert.equal(link, 'boats', 'findHasMany(_, _, link) is correct'); + + let relationships = { + person: { + data: { + type: 'person', + id: 1 + } + } + }; + + let data = [ + { + id: 3, + type: 'boat', + relationships + } + ]; + + if (!isUnloaded) { + data.unshift({ + id: 2, + type: 'boat', + relationships + }); + } + + return { + data + }; + }; + + let person = run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + boats: { + links: { related: 'boats' } + } + } + } + }) + ); + let boats, boat2, boat3; + + return run(() => + person.get('boats').then((asyncRecords) => { + boats = asyncRecords; + [boat2, boat3] = boats.toArray(); + }).then(() => { + assert.deepEqual(person.hasMany('boats').ids(), ['2', '3'], 'initially relationship established rhs'); + assert.equal(boat2.belongsTo('person').id(), '1', 'initially relationship established rhs'); + assert.equal(boat3.belongsTo('person').id(), '1', 'initially relationship established rhs'); + + isUnloaded = true; + run(() => { + boat2.unloadRecord(); + person.get('boats'); + }); + + assert.deepEqual(boats.mapBy('id'), ['3'], 'unloaded boat is removed from ManyArray'); + }).then(() => { + return run(() => person.get('boats')); + }).then(newBoats => { + assert.equal(newBoats.length, 1, 'new ManyArray has only 1 boat after unload'); + }) + ); +}); From 74444443980ffb9e9fd94bb70762c3791b9b93ad Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Tue, 13 Mar 2018 15:16:27 -0700 Subject: [PATCH 2148/2527] [bugfix beta] Fetch cancels unload When fetching records, cancel internal model destruction if it is scheduled, ie if the model is dematerializing because it was unloaded. It is not possible to construct snapshots for dematerializing internal models. Prior to this commit, this could happen when fetching a record in the same runloop that it was unloaded. A straightfoward way of getting into this state was via ``` store.findRecord('book', 1).then(b => b.unloadRecord) ``` when the model is already cached in the store. Under these conditions, the fetch is scheduled, then the promise fulfills with the cached record and is unloaded and *then* the scheduled fetch is flushed. [fix #5343] --- addon/-private/system/store.js | 12 ++++++++++ tests/integration/records/unload-test.js | 28 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 1e04de2be9b..87822122ef5 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -855,6 +855,18 @@ Store = Service.extend({ seeking[internalModel.id] = pendingItem; } + for (let i = 0; i < totalItems; i++) { + let internalModel = internalModels[i]; + // We may have unloaded the record after scheduling this fetch, in which + // case we must cancel the destory. This is because we require a record + // to build a snapshot. This is not fundamental: this cancelation code + // can be removed when snapshots can be created for internal models that + // have no records. + if (internalModel.hasScheduledDestroy()) { + internalModels[i].cancelDestroy(); + } + } + function _fetchRecord(recordResolverPair) { let recordFetch = store._fetchRecord( recordResolverPair.internalModel, diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 34e98b168cc..f7cdb8494a4 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -2089,3 +2089,31 @@ test('unload invalidates link promises', function(assert) { }) ); }); + +test('fetching records cancels unloading', function(assert) { + env.adapter.findRecord = (store, type, id) => { + assert.equal(type, Person, 'findRecord(_, type) is correct'); + assert.deepEqual(id, '1', 'findRecord(_, _, id) is correct'); + + return { + data: { + id: 1, + type: 'person' + } + } + }; + + run(() => + env.store.push({ + data: { + id: 1, + type: 'person' + } + }) + ); + + return run(() => + env.store.findRecord('person', 1, { backgroundReload: true }) + .then(person => person.unloadRecord()) + ); +}); From 207a534db66d399fcc506139b77eb97996bec204 Mon Sep 17 00:00:00 2001 From: Sylvain MINA Date: Thu, 15 Mar 2018 13:55:54 +0100 Subject: [PATCH 2149/2527] minor typo --- addon/-private/system/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 87822122ef5..885c83a4c0c 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -858,7 +858,7 @@ Store = Service.extend({ for (let i = 0; i < totalItems; i++) { let internalModel = internalModels[i]; // We may have unloaded the record after scheduling this fetch, in which - // case we must cancel the destory. This is because we require a record + // case we must cancel the destroy. This is because we require a record // to build a snapshot. This is not fundamental: this cancelation code // can be removed when snapshots can be created for internal models that // have no records. From dc2523230b222c8554813f4416459faef79f3e89 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 16 Mar 2018 10:52:39 -0700 Subject: [PATCH 2150/2527] ember-cli no longer requires the modules directory to be used and will deprecate it soon (#5380) --- index.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index bb18ce28210..07664a23c77 100644 --- a/index.js +++ b/index.js @@ -62,6 +62,16 @@ module.exports = { } }, + getOutputDirForVersion() { + let VersionChecker = require('ember-cli-version-checker'); + let checker = new VersionChecker(this); + let emberCli = checker.for('ember-cli', 'npm'); + + let requiresModulesDir = emberCli.satisfies('< 3.0.0'); + + return requiresModulesDir ? 'modules' : ''; + }, + init() { this._super.init && this._super.init.apply(this, arguments); this._prodLikeWarning(); @@ -180,9 +190,10 @@ module.exports = { privateTree = this.debugTree(privateTree, 'rollup-output'); - // the output of treeForAddon is required to be modules/ - publicTree = new Funnel(publicTree, { destDir: 'modules' }); - privateTree = new Funnel(privateTree, { destDir: 'modules' }); + let destDir = this.getOutputDirForVersion(); + + publicTree = new Funnel(publicTree, { destDir }); + privateTree = new Funnel(privateTree, { destDir }); return this.debugTree(merge([ publicTree, From ec9b9fe9c8cc190bbc8152fc5793dad6307e6f23 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 16 Mar 2018 11:31:47 -0700 Subject: [PATCH 2151/2527] [FIX] update ember-cli-dependency-checker to avoid deprecation warning --- package.json | 2 +- yarn.lock | 31 ++++++++++++++----------------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index a190cd4f590..03806b29e87 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "ember-cli": "^2.11.1", "ember-cli-app-version": "^3.0.0", "ember-cli-blueprint-test-helpers": "^0.18.3", - "ember-cli-dependency-checker": "^1.3.0", + "ember-cli-dependency-checker": "^2.1.0", "ember-cli-eslint": "1.3.0", "ember-cli-htmlbars": "^2.0.1", "ember-cli-htmlbars-inline-precompile": "^0.4.3", diff --git a/yarn.lock b/yarn.lock index dfd952cb155..528c9820256 100644 --- a/yarn.lock +++ b/yarn.lock @@ -149,7 +149,7 @@ ansi-escapes@^1.1.0: ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" ansi-regex@^2.0.0: version "2.1.1" @@ -161,7 +161,7 @@ ansi-regex@^3.0.0: ansi-styles@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" ansi-styles@^2.2.1: version "2.2.1" @@ -1802,7 +1802,7 @@ chai@^4.1.0: chalk@^0.5.1: version "0.5.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" + resolved "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" dependencies: ansi-styles "^1.1.0" escape-string-regexp "^1.0.0" @@ -2538,13 +2538,14 @@ ember-cli-broccoli-sane-watcher@^2.0.4: rsvp "^3.0.18" sane "^2.4.1" -ember-cli-dependency-checker@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ember-cli-dependency-checker/-/ember-cli-dependency-checker-1.4.0.tgz#2b13f977e1eea843fc1a21a001be6ca5d4ef1942" +ember-cli-dependency-checker@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/ember-cli-dependency-checker/-/ember-cli-dependency-checker-2.1.0.tgz#9d66286a7c778e94733eaf21320d129c4fd0dd64" dependencies: - chalk "^0.5.1" - is-git-url "^0.2.0" - semver "^4.1.0" + chalk "^1.1.3" + is-git-url "^1.0.0" + resolve "^1.5.0" + semver "^5.3.0" ember-cli-eslint@1.3.0: version "1.3.0" @@ -4048,7 +4049,7 @@ har-validator@~4.2.1: has-ansi@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" + resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" dependencies: ansi-regex "^0.2.0" @@ -4490,10 +4491,6 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" -is-git-url@^0.2.0: - version "0.2.3" - resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-0.2.3.tgz#445200d6fbd6da028fb5e01440d9afc93f3ccb64" - is-git-url@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-1.0.0.tgz#53f684cd143285b52c3244b4e6f28253527af66b" @@ -6673,7 +6670,7 @@ selenium-webdriver@2.48.2: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" -semver@^4.1.0, semver@^4.3.1: +semver@^4.3.1: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" @@ -7110,7 +7107,7 @@ stringstream@~0.0.4: strip-ansi@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" dependencies: ansi-regex "^0.2.1" @@ -7170,7 +7167,7 @@ supports-color@1.2.0: supports-color@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" supports-color@^2.0.0: version "2.0.0" From 022be46a67ce7184db36657946f90fc592126d4b Mon Sep 17 00:00:00 2001 From: sly7-7 Date: Fri, 16 Mar 2018 19:38:46 +0100 Subject: [PATCH 2152/2527] fix external ordered set dependency --- index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 07664a23c77..b743e6f5528 100644 --- a/index.js +++ b/index.js @@ -182,7 +182,8 @@ module.exports = { 'ember-inflector', 'ember-data/version', 'ember-data/-debug', - 'ember-data/adapters/errors' + 'ember-data/adapters/errors', + '@ember/ordered-set' ] // cache: true|false Defaults to true } From a24cd5011e2f3f9ec910a373400ca6cf1d98afb8 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Fri, 23 Mar 2018 09:38:49 -0400 Subject: [PATCH 2153/2527] Trap exceptions that are thrown from adapter methods and reject the (#4977) store promise with the exception. Closes #4945 --- addon/-private/system/store.js | 2 +- addon/-private/system/store/finders.js | 10 ++-- tests/integration/store-test.js | 66 ++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 885c83a4c0c..5a05a368999 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2880,7 +2880,7 @@ function _commit(adapter, store, operation, snapshot) { let modelClass = store._modelFor(modelName); assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter); assert(`You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`, typeof adapter[operation] === 'function'); - let promise = adapter[operation](store, modelClass, snapshot); + let promise = Promise.resolve().then(() => adapter[operation](store, modelClass, snapshot)); let serializer = serializerForAdapter(store, adapter, modelName); let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 0103a0084a1..414833edb07 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -21,7 +21,7 @@ function payloadIsNotBlank(adapterPayload) { export function _find(adapter, store, modelClass, id, internalModel, options) { let snapshot = internalModel.createSnapshot(options); let { modelName } = internalModel; - let promise = adapter.findRecord(store, modelClass, id, snapshot); + let promise = Promise.resolve().then(() => adapter.findRecord(store, modelClass, id, snapshot)); let label = `DS: Handle Adapter#findRecord of '${modelName}' with id: '${id}'`; promise = Promise.resolve(promise, label); @@ -116,7 +116,7 @@ export function _findAll(adapter, store, modelName, sinceToken, options) { let modelClass = store.modelFor(modelName); // adapter.findAll depends on the class let recordArray = store.peekAll(modelName); let snapshotArray = recordArray._createSnapshot(options); - let promise = adapter.findAll(store, modelClass, sinceToken, snapshotArray); + let promise = Promise.resolve().then(() => adapter.findAll(store, modelClass, sinceToken, snapshotArray)); let label = "DS: Handle Adapter#findAll of " + modelClass; promise = Promise.resolve(promise, label); @@ -140,9 +140,9 @@ export function _query(adapter, store, modelName, query, recordArray) { let promise; if (adapter.query.length > 3) { recordArray = recordArray || store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); - promise = adapter.query(store, modelClass, query, recordArray); + promise = Promise.resolve().then(() => adapter.query(store, modelClass, query, recordArray)); } else { - promise = adapter.query(store, modelClass, query); + promise = Promise.resolve().then(() => adapter.query(store, modelClass, query)); } let label = `DS: Handle Adapter#query of ${modelClass}`; @@ -172,7 +172,7 @@ export function _query(adapter, store, modelName, query, recordArray) { export function _queryRecord(adapter, store, modelName, query) { let modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class - let promise = adapter.queryRecord(store, modelClass, query); + let promise = Promise.resolve().then(() => adapter.queryRecord(store, modelClass, query)); let label = `DS: Handle Adapter#queryRecord of ${modelName}`; promise = Promise.resolve(promise, label); diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index bf33dc85f4e..21cc58a623a 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -914,4 +914,70 @@ testInDebug('store#queryRecord should assert when normalized payload of adapter }, /Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array./); }); +test('The store should trap exceptions that are thrown from adapter#findRecord', function(assert) { + assert.expect(1) + env.adapter.findRecord = function() { + throw new Error('Refusing to find record'); + }; + + run(() => { + store.findRecord('car', 1).catch(error => { + assert.equal(error.message, 'Refusing to find record') + }) + }); +}); +test('The store should trap exceptions that are thrown from adapter#findAll', function(assert) { + assert.expect(1) + env.adapter.findAll = function() { + throw new Error('Refusing to find all records'); + }; + + run(() => { + store.findAll('car').catch(error => { + assert.equal(error.message, 'Refusing to find all records') + }) + }); +}); + +test('The store should trap exceptions that are thrown from adapter#query', function(assert) { + assert.expect(1) + env.adapter.query = function() { + throw new Error('Refusing to query records'); + }; + + run(() => { + store.query('car', {}).catch(error => { + assert.equal(error.message, 'Refusing to query records') + }) + }); +}); + +test('The store should trap exceptions that are thrown from adapter#queryRecord', function(assert) { + assert.expect(1) + env.adapter.queryRecord = function() { + throw new Error('Refusing to query record'); + }; + + run(() => { + store.queryRecord('car', {}).catch(error => { + assert.equal(error.message, 'Refusing to query record') + }) + }); +}); + + +test('The store should trap exceptions that are thrown from adapter#createRecord', function(assert) { + assert.expect(1) + env.adapter.createRecord = function() { + throw new Error('Refusing to serialize'); + }; + + run(() => { + let car = store.createRecord('car') + + car.save().catch(error => { + assert.equal(error.message, 'Refusing to serialize') + }) + }); +}); From 615b6c695e0bce697f8c864a736f17fe007aaa8a Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 23 Mar 2018 06:46:59 -0700 Subject: [PATCH 2154/2527] [FEAT BREAKING] remove globals build for 3.x (#5381) * [FEAT BREAKING] remove globals build * restore version.js * restore S3 publishing for yuidocs and cleanup release instructions * Remove globals demo from readme --- README.md | 23 -------- RELEASE.md | 8 --- bin/bower-ember-data-build | 63 -------------------- bin/publish-builds | 1 - bin/publish-to-s3.js | 3 + ember-cli-build.js | 4 +- ember-data-source.gemspec | 18 ------ lib/amd-build.js | 33 ----------- lib/ds-global.js | 9 --- lib/ember-data-shims.js | 38 ------------- lib/ember-shim.js | 6 -- lib/globals.js | 12 ---- lib/javascripts.js | 114 ------------------------------------- 13 files changed, 4 insertions(+), 328 deletions(-) delete mode 100755 bin/bower-ember-data-build delete mode 100644 ember-data-source.gemspec delete mode 100644 lib/amd-build.js delete mode 100644 lib/ds-global.js delete mode 100644 lib/ember-data-shims.js delete mode 100644 lib/ember-shim.js delete mode 100644 lib/globals.js delete mode 100644 lib/javascripts.js diff --git a/README.md b/README.md index 25e1cc1b282..3efd95d35b9 100644 --- a/README.md +++ b/README.md @@ -103,29 +103,6 @@ export default DS.Model.extend({ }); ``` -If you're using globals (that is, not something like ember-cli), your -models would look like this: - -```js -var attr = DS.attr; -var hasMany = DS.hasMany; -var belongsTo = DS.belongsTo; - -App.BlogPost = DS.Model.extend({ - title: attr('string'), - createdAt: attr('date'), - - comments: hasMany('comment') -}); - -App.Comment = DS.Model.extend({ - body: attr('string'), - username: attr('string'), - - post: belongsTo('blog-post') -}); -``` - ### A Brief Note on Adapters Without immediately diving in to the depths of the architecture, one diff --git a/RELEASE.md b/RELEASE.md index ad716656968..049331d59f5 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -21,12 +21,6 @@ STEPS: * `git tag vX.Y.Z-beta.n` * Do a production build. * `rm -rf node_modules; yarn install; npm run build:production` -* Publish to Bower - * Commit built globals code to the https://github.com/components/ember-data repo - * `cp dist/globals/* ../components-ember-data/` -* Publish Rubygems - * `gem build ember-data-source.gemspec` - * `gem push ember-data-source-2.4.0.beta.1.gem` * Publish to NPM * `npm publish` or `npm publish --tag beta` or `npm publish --tag release-1-13` * Update the `/builds/` page on the website @@ -37,8 +31,6 @@ STEPS: * Write a Release Blog Post (Does not happen for beta releases) * Commits since last release: `git log --oneline release..beta | wc -l`. * Contributors since last release: `git shortlog -s -n release...beta | wc -l` -* Submit a Pull request to the https://github.com/ember-cli/ember-cli to update the version of Ember Data - * (per request by @rwjblue and is also a great idea to make upgrading/new apps easier) * Bump version in package.json back to a canary version * For beta.1 releases, branch beta from master and update https://github.com/emberjs/data/blob/master/config/features.json to have `false` values instead of `null` and update the version in package.json diff --git a/bin/bower-ember-data-build b/bin/bower-ember-data-build deleted file mode 100755 index e306b1b98ed..00000000000 --- a/bin/bower-ember-data-build +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env bash - -git config --global user.email "tomster@emberjs.com" -git config --global user.name "Tomster" - -# This specifies the repository we are going to work with. This will most likely be set to 'ember' -COMPONENTS_EMBER_REPO_SLUG="components/ember-data" - -# This specifies the user who is associated to the GH_TOKEN -USER="rwjblue" - -# This ensure that no directories within dist will be copied when script is run. -INCLUDED_FILES=`find dist/globals -maxdepth 1 -type f` - -CURRENT_BRANCH=$TRAVIS_BRANCH - -echo -e "COMPONENTS_EMBER_REPO_SLUG: ${COMPONENTS_EMBER_REPO_SLUG}\n" -echo -e "INCLUDED_FILES: ${INCLUDED_FILES}\n" -echo -e "CURRENT_BRANCH: ${CURRENT_BRANCH}\n" - -if [[ $TRAVIS_PULL_REQUEST != "false" ]]; then - echo "not publishing because this is a pull request." - exit 0 -fi - -if [[ -z $GH_TOKEN ]]; then - echo "secure environment variables not detected." - echo "not a repo owner, exiting." - exit 0 -fi - -# Set channel to publish to. If no suitable branch is found exit successfully. -case $CURRENT_BRANCH in - "master" ) - CHANNEL="canary" ;; - "beta" ) - CHANNEL="beta" ;; - "stable" ) - CHANNEL="release" ;; - "release" ) - CHANNEL="release" ;; - * ) - echo "Not a bower release branch. Exiting!" - exit 0 ;; -esac -echo -e "CHANNEL: ${CHANNEL}\n" - -# sending output to /dev/null to prevent GH_TOKEN leak on error -git clone --branch ${CHANNEL} https://${USER}:${GH_TOKEN}@github.com/${COMPONENTS_EMBER_REPO_SLUG}.git bower_ember &> /dev/null -rm -rf bower_ember/* -cp -r ${INCLUDED_FILES} bower_ember/ -cd bower_ember -git remote rm origin - -# sending output to /dev/null to prevent GH_TOKEN leak on error -git remote add origin https://${USER}:${GH_TOKEN}@github.com/${COMPONENTS_EMBER_REPO_SLUG}.git &> /dev/null -git add -A -git commit -m "Ember Data Bower Auto build for https://github.com/emberjs/data/commits/${TRAVIS_COMMIT}." - -# sending output to /dev/null to prevent GH_TOKEN leak on error -git push -fq origin ${CHANNEL} &> /dev/null -echo -e "Done\n" - diff --git a/bin/publish-builds b/bin/publish-builds index 98eb397aa50..1842d996b27 100755 --- a/bin/publish-builds +++ b/bin/publish-builds @@ -5,5 +5,4 @@ echo -e "PULL_REQUEST: ${TRAVIS_PULL_REQUEST}\n" if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then ./bin/publish-to-s3.js - ./bin/bower-ember-data-build fi diff --git a/bin/publish-to-s3.js b/bin/publish-to-s3.js index 7cda3058eb2..d01b3febc36 100755 --- a/bin/publish-to-s3.js +++ b/bin/publish-to-s3.js @@ -1,5 +1,8 @@ #!/usr/bin/env node +// This publish script remains in order to publish the yui-docs to S3, builds no +// longer need to be published to S3. +// // To invoke this from the commandline you need the following to env vars to exist: // // S3_BUCKET_NAME diff --git a/ember-cli-build.js b/ember-cli-build.js index c17b7d456eb..b1b8a785cf9 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -2,7 +2,6 @@ var EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); var merge = require('broccoli-merge-trees'); var Funnel = require('broccoli-funnel'); -var globals = require('./lib/globals'); var yuidoc = require('./lib/yuidoc'); var StripClassCallCheck = require('babel6-plugin-strip-class-callcheck'); var path = require('path'); @@ -51,8 +50,7 @@ module.exports = function(defaults) { var appTree = app.toTree(); if (process.env.EMBER_ENV === 'production') { - var globalsBuild = globals('addon', 'config/package-manager-files'); - return merge([appTree, globalsBuild, yuidoc()]); + return merge([appTree, yuidoc()]); } else { return appTree; } diff --git a/ember-data-source.gemspec b/ember-data-source.gemspec deleted file mode 100644 index d73b168d87e..00000000000 --- a/ember-data-source.gemspec +++ /dev/null @@ -1,18 +0,0 @@ -# -*- encoding: utf-8 -*- -require './lib/ember/data/version' - -Gem::Specification.new do |gem| - gem.name = "ember-data-source" - gem.authors = ["Yehuda Katz"] - gem.email = ["wycats@gmail.com"] - gem.date = Time.now.strftime("%Y-%m-%d") - gem.summary = %q{ember-data source code wrapper.} - gem.description = %q{ember-data source code wrapper for use with Ruby libs.} - gem.homepage = "https://github.com/emberjs/data" - gem.version = Ember::Data::VERSION - gem.license = "MIT" - - gem.add_dependency "ember-source", ">= 2", "< 3.0" - - gem.files = %w(package.json) + Dir['dist/globals/ember-data*.js', 'dist/globals/ember-data.js.map', 'lib/ember/data/*.rb'] -end diff --git a/lib/amd-build.js b/lib/amd-build.js deleted file mode 100644 index 0fc58f3ae25..00000000000 --- a/lib/amd-build.js +++ /dev/null @@ -1,33 +0,0 @@ -var es6 = require('broccoli-es6-module-transpiler'); -var merge = require('broccoli-merge-trees'); -var PackageResolver = require('es6-module-transpiler-package-resolver'); -var AMDFormatter = require('es6-module-transpiler-amd-formatter'); -var replace = require('broccoli-replace'); - -function amdES6Package(packages, root, outfile) { - - var es6Build = es6(packages, { - inputFiles: ['ember-data'], - output: '/ember-data/', - resolvers: [PackageResolver], - formatter: new AMDFormatter(), - basePath: '/ember-data/', - sourceRoot: '/ember-data/' - }); - - return replace(es6Build, { - files: ['**/*.js'], - patterns: [ - { - match: /\/lib/g, - replacement: '' - }, - { - match: /\/main/g, - replacement: '' - } - ] - }); -} - -module.exports = amdES6Package; diff --git a/lib/ds-global.js b/lib/ds-global.js deleted file mode 100644 index 8208c950821..00000000000 --- a/lib/ds-global.js +++ /dev/null @@ -1,9 +0,0 @@ -;(function() { - var global = require('ember-data/-private/global').default; - var DS = require('ember-data').default; - Object.defineProperty(global, 'DS', { - get: function() { - return DS; - } - }); -})(); diff --git a/lib/ember-data-shims.js b/lib/ember-data-shims.js deleted file mode 100644 index dcb9bbb3236..00000000000 --- a/lib/ember-data-shims.js +++ /dev/null @@ -1,38 +0,0 @@ -;(function() { - function processEmberDataShims() { - var shims = { - 'ember-data': { default: DS }, - 'ember-data/model': { default: DS.Model }, - 'ember-data/mixins/embedded-records': { default: DS.EmbeddedRecordsMixin }, - 'ember-data/serializers/rest': { default: DS.RESTSerializer }, - 'ember-data/serializers/active-model': { default: DS.ActiveModelSerializer }, - 'ember-data/serializers/json': { default: DS.JSONSerializer }, - 'ember-data/serializers/json-api': { default: DS.JSONAPISerializer }, - 'ember-data/serializer': { default: DS.Serializer }, - 'ember-data/adapters/json-api': { default: DS.JSONAPIAdapter }, - 'ember-data/adapters/rest': { default: DS.RESTAdapter }, - 'ember-data/adapter': { default: DS.Adapter }, - 'ember-data/adapters/active-model': { default: DS.ActiveModelAdapter }, - 'ember-data/store': { default: DS.Store }, - 'ember-data/transform': { default: DS.Transform }, - 'ember-data/attr': { default: DS.attr }, - 'ember-data/relationships': { hasMany: DS.hasMany, belongsTo: DS.belongsTo } - }; - - for (var moduleName in shims) { - generateModule(moduleName, shims[moduleName]); - } - } - - function generateModule(name, values) { - define(name, [], function() { - 'use strict'; - - return values; - }); - } - - if (typeof define !== 'undefined' && define && define.petal) { - processEmberDataShims(); - } -})(); diff --git a/lib/ember-shim.js b/lib/ember-shim.js deleted file mode 100644 index 4ed59dbb763..00000000000 --- a/lib/ember-shim.js +++ /dev/null @@ -1,6 +0,0 @@ -define('ember', [], function() { - return { - default: Ember - }; -}); - diff --git a/lib/globals.js b/lib/globals.js deleted file mode 100644 index 26396c4fa56..00000000000 --- a/lib/globals.js +++ /dev/null @@ -1,12 +0,0 @@ -var merge = require('broccoli-merge-trees'); -var js = require('./javascripts'); -var versionReplace = require('./version-replace'); -var stew = require('broccoli-stew'); - -module.exports = function(jsDir, configDir) { - var javascripts = js(jsDir); - var configFiles = versionReplace(configDir); - - var globalFiles = merge([configFiles, javascripts]); - return stew.mv(globalFiles, 'globals'); -}; diff --git a/lib/javascripts.js b/lib/javascripts.js deleted file mode 100644 index 6ba021c6e1d..00000000000 --- a/lib/javascripts.js +++ /dev/null @@ -1,114 +0,0 @@ -/* eslint-env node */ - -var merge = require('broccoli-merge-trees'); -var concat = require('broccoli-concat'); -var uglify = require('broccoli-uglify-sourcemap'); -var stew = require('broccoli-stew'); -var version = require('./version'); -var fs = require('fs'); -var path = require('path'); -var Funnel = require('broccoli-funnel'); -var versionReplace = require('./version-replace'); -var fileCreator = require('broccoli-file-creator'); -var strippedBuild = require('./stripped-build'); - -function debugBuild(packageName, tree) { - var compiled = strippedBuild(packageName, tree, 'development'); - - return stew.mv(compiled, packageName); -} - -function makeStrippedBuild(packageName, tree) { - var withoutDebug = new Funnel(tree, { - exclude: ['ember-data/-private/debug.js'] - }); - - var stripped = strippedBuild(packageName, withoutDebug, 'production'); - - return stew.mv(stripped, packageName); -} - -function collapse(tree, outputFileName) { - var loaderDir = path.join(__dirname, '..', 'node_modules', 'loader.js', 'dist', 'loader'); - var loader = new Funnel(loaderDir, { - include: ['loader.js'] - }); - - var emberShim = new Funnel(__dirname, { - include: ['ember-shim.js'] - }); - - var generatorDir = path.join(__dirname, '..', 'generators'); - var license = new Funnel(generatorDir, {include: ['license.js']}); - license = versionReplace(license); - - var emberDataShimsPath = path.join(__dirname, 'ember-data-shims.js'); - var emberDataShims = fs.readFileSync(emberDataShimsPath, { encoding: 'utf8' }); - var dsGlobalPath = path.join(__dirname, 'ds-global.js'); - var dsGlobal = fs.readFileSync(dsGlobalPath, { encoding: 'utf8' }); - - var withLoader = merge([tree, loader, license, emberShim]); - - return concat(withLoader, { - headerFiles: ['license.js', 'loader.js'], - inputFiles: ['**/*.js'], - outputFile: '/' + outputFileName, - header: '(function(){ \n"use strict";\n', - footer: '\nrequire("ember-data");\nrequire("ember-load-initializers")["default"](Ember.Application, "ember-data");\n' + dsGlobal + '}).call(this);\n' + emberDataShims - }); -} - -function minify(tree) { - return uglify(tree, { - sourceMapIncludeSources: false, - sourceMapConfig: { - enabled: false - } - }); -} - -function buildEmberInflector() { - var emberInflector = new Funnel(path.dirname(require.resolve('ember-inflector/addon')), { - include: ['**/*.js'] - }); - - return debugBuild('ember-inflector', emberInflector); -} - -function buildLoadInitializers() { - var emberLoadInitializers = new Funnel(path.dirname(require.resolve('ember-load-initializers/addon')), { - include: ['**/*.js'] - }); - - return debugBuild('ember-load-initializers', emberLoadInitializers); -} - -module.exports = function(tree) { - var emberInflector = buildEmberInflector(); - var loadInitializers = buildLoadInitializers(); - var emberData = merge([tree, version()]); - - var javascripts = merge([ - emberInflector, - loadInitializers, - debugBuild('ember-data/initializers', 'app/initializers'), - debugBuild('ember-data/instance-initializers', 'app/instance-initializers'), - debugBuild('ember-data', emberData) - ]); - - var strippedJavascripts = merge([ - emberInflector, - loadInitializers, - makeStrippedBuild('ember-data/initializers', 'app/initializers'), - makeStrippedBuild('ember-data/instance-initializers', 'app/instance-initializers'), - makeStrippedBuild('ember-data', emberData) - ]); - - var debug = collapse(javascripts, 'ember-data.js'); - var production = collapse(strippedJavascripts, 'ember-data.prod.js'); - var minified = stew.rename(minify(production), 'ember-data.prod.js', 'ember-data.min.js'); - // Hack to get around https://github.com/emberjs/data/blob/v2.1.0/lib/ember-addon/index.js#L28 - var emptySourcemapFile = fileCreator('ember-data.js.map', ''); - - return merge([debug, production, minified, emptySourcemapFile]); -}; From fc327b2a65f8a1da4e812f6ee16bd2764d99b489 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 26 Mar 2018 05:43:05 -0700 Subject: [PATCH 2155/2527] [BUGFIX] resolve issues with RecordArray sync for peekAll (#5378) * [BUGFIX] resolve issues with RecordArray sync for peekAll * remove unneeded part of fix * Adds a test for #5167 * add test and fix for #5350 * port test from #5095 * fix filter test for older versions of Ember --- addon/-private/system/model/internal-model.js | 4 +- addon/-private/system/record-array-manager.js | 82 ++-- package.json | 2 +- tests/helpers/watch-property.js | 144 ++++++ .../record-arrays/peeked-records-test.js | 433 ++++++++++++++++++ yarn.lock | 9 +- 6 files changed, 632 insertions(+), 42 deletions(-) create mode 100644 tests/helpers/watch-property.js create mode 100644 tests/integration/record-arrays/peeked-records-test.js diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index e1043f11d8c..07a6a336de2 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -293,6 +293,7 @@ export default class InternalModel { // models to rematerialize their records. return this._isDematerializing || + this.hasScheduledDestroy() || this.isDestroyed || this.currentState.stateName === 'root.deleted.saved' || this.isEmpty(); @@ -381,9 +382,10 @@ export default class InternalModel { this._isDematerializing = true; this._record.destroy(); this.destroyRelationships(); - this.updateRecordArrays(); this.resetRecord(); } + + this.updateRecordArrays(); } deleteRecord() { diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 9802e02ce79..d8bd619bd8c 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -96,45 +96,49 @@ export default class RecordArrayManager { emberRun.schedule('actions', this, this._flush); } - _flush() { - heimdall.increment(_flush); - - let pending = this._pending; - this._pending = Object.create(null); + _flushPendingInternalModelsForModelName(modelName, internalModels) { let modelsToRemove = []; - for (let modelName in pending) { - let internalModels = pending[modelName]; - for (let j = 0; j < internalModels.length; j++) { - let internalModel = internalModels[j]; - // mark internalModels, so they can once again be processed by the - // recordArrayManager - internalModel._pendingRecordArrayManagerFlush = false; - // build up a set of models to ensure we have purged correctly; - if (internalModel.isHiddenFromRecordArrays()) { - modelsToRemove.push(internalModel); - } + for (let j = 0; j < internalModels.length; j++) { + let internalModel = internalModels[j]; + // mark internalModels, so they can once again be processed by the + // recordArrayManager + internalModel._pendingRecordArrayManagerFlush = false; + // build up a set of models to ensure we have purged correctly; + if (internalModel.isHiddenFromRecordArrays()) { + modelsToRemove.push(internalModel); } + } - // process filteredRecordArrays - if (this._filteredRecordArrays[modelName]) { - let recordArrays = this.filteredRecordArraysFor(modelName); - for (let i = 0; i < recordArrays.length; i++) { - this.updateFilterRecordArray(recordArrays[i], modelName, internalModels); - } + // process filteredRecordArrays + if (this._filteredRecordArrays[modelName]) { + let recordArrays = this.filteredRecordArraysFor(modelName); + for (let i = 0; i < recordArrays.length; i++) { + this.updateFilterRecordArray(recordArrays[i], modelName, internalModels); } + } - let array = this._liveRecordArrays[modelName]; - if (array) { - // TODO: skip if it only changed - // process liveRecordArrays - this.updateLiveRecordArray(array, internalModels); - } + let array = this._liveRecordArrays[modelName]; + if (array) { + // TODO: skip if it only changed + // process liveRecordArrays + this.updateLiveRecordArray(array, internalModels); + } - // process adapterPopulatedRecordArrays - if (modelsToRemove.length > 0) { - removeFromAdapterPopulatedRecordArrays(modelsToRemove); - } + // process adapterPopulatedRecordArrays + if (modelsToRemove.length > 0) { + removeFromAdapterPopulatedRecordArrays(modelsToRemove); + } + } + + _flush() { + heimdall.increment(_flush); + + let pending = this._pending; + this._pending = Object.create(null); + + for (let modelName in pending) { + this._flushPendingInternalModelsForModelName(modelName, pending[modelName]); } } @@ -177,10 +181,11 @@ export default class RecordArrayManager { if (shouldBeRemoved.length > 0) { array._removeInternalModels(shouldBeRemoved); } } - // TODO: remove, utilize existing flush code but make it flush sync based on 1 modelName _syncLiveRecordArray(array, modelName) { assert(`recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); - let hasNoPotentialDeletions = Object.keys(this._pending).length === 0; + let pending = this._pending[modelName]; + let hasPendingChanges = Array.isArray(pending); + let hasNoPotentialDeletions = !hasPendingChanges || pending.length === 0; let map = this.store._internalModelsFor(modelName); let hasNoInsertionsOrRemovals = get(map, 'length') === get(array, 'length'); @@ -194,6 +199,11 @@ export default class RecordArrayManager { return; } + if (hasPendingChanges) { + this._flushPendingInternalModelsForModelName(modelName, pending); + delete pending[modelName]; + } + let internalModels = this._visibleInternalModelsByType(modelName); let modelsToAdd = []; for (let i = 0; i < internalModels.length; i++) { @@ -205,7 +215,9 @@ export default class RecordArrayManager { } } - array._pushInternalModels(modelsToAdd); + if (modelsToAdd.length) { + array._pushInternalModels(modelsToAdd); + } } /** diff --git a/package.json b/package.json index 03806b29e87..6a491560b51 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "ember-publisher": "0.0.7", "ember-qunit-assert-helpers": "^0.2.1", "ember-resolver": "^4.1.0", - "ember-source": "~2.18.0", + "ember-source": "~3.0.0", "ember-source-channel-url": "^1.0.1", "ember-try": "^0.2.23", "ember-watson": "^0.7.0", diff --git a/tests/helpers/watch-property.js b/tests/helpers/watch-property.js new file mode 100644 index 00000000000..9b88dd8277a --- /dev/null +++ b/tests/helpers/watch-property.js @@ -0,0 +1,144 @@ +import Ember from 'ember'; +import QUnit from 'qunit'; + +const { + addObserver, + removeObserver +} = Ember; + +function makeCounter() { + let count = 0; + const counter = Object.create(null); + counter.reset = function resetCounter() { count = 0; }; + + Object.defineProperty(counter, 'count', { + get() { return count; }, + set() {}, + configurable: false, + enumerable: true + }); + + Object.freeze(counter); + + function increment() { + count++; + } + + return { counter, increment }; +} + +export function watchProperty(obj, propertyName) { + let { counter, increment } = makeCounter(); + + function observe() { + increment(); + } + + addObserver(obj, propertyName, observe); + + function unwatch() { + removeObserver(obj, propertyName, observe); + } + + return { counter, unwatch }; +} + +export function watchProperties(obj, propertyNames) { + let watched = {}; + let counters = {}; + + if (!Array.isArray(propertyNames)) { + throw new Error(`Must call watchProperties with an array of propertyNames to watch, received ${propertyNames}`); + } + + for (let i = 0; i < propertyNames.length; i++) { + let propertyName = propertyNames[i]; + + if (watched[propertyName] !== undefined) { + throw new Error(`Cannot watch the same property ${propertyName} more than once`); + } + + let { counter, increment } = makeCounter(); + watched[propertyName] = increment; + counters[propertyName] = counter; + + addObserver(obj, propertyName, increment); + } + + function unwatch() { + Object.keys(watched).forEach((propertyName) => { + removeObserver(obj, propertyName, watched[propertyName]); + }); + } + + return { counters, unwatch }; +} + +QUnit.assert.watchedPropertyCounts = function assertWatchedPropertyCount(watchedObject, expectedCounts, label = '') { + if (!watchedObject || !watchedObject.counters) { + throw new Error('Expected to receive the return value of watchProperties: an object containing counters'); + } + + let counters = watchedObject.counters; + + Object.keys(expectedCounts).forEach((propertyName) => { + let counter = counters[propertyName]; + let expectedCount = expectedCounts[propertyName]; + let assertionText = label; + + if (Array.isArray(expectedCount)) { + label = expectedCount[1]; + expectedCount = expectedCount[0]; + } + + assertionText += ` | Expected ${expectedCount} change notifications for ${propertyName} but recieved ${counter.count}`; + + if (counter === undefined) { + throw new Error(`Cannot assert expected count for ${propertyName} as there is no watcher for that property`); + } + + this.pushResult({ + result: counter.count === expectedCount, + actual: counter.count, + expected: expectedCount, + message: assertionText + }); + }); +}; + +QUnit.assert.watchedPropertyCount = function assertWatchedPropertyCount(watcher, expectedCount, label) { + let counter; + if (!watcher) { + throw new Error(`Expected to receive a watcher`); + } + + // this allows us to handle watchers passed in from a watchProperties return hash + if (!watcher.counter && watcher.count !== undefined) { + counter = watcher; + } else { + counter = watcher.counter; + } + + this.pushResult({ + result: counter.count === expectedCount, + actual: counter.count, + expected: expectedCount, + message: label + }); +}; + +QUnit.assert.dirties = function assertDirties(options, updateMethodCallback, label) { + let { object: obj, property, count } = options; + count = typeof count === 'number' ? count : 1; + let { counter, unwatch } = watchProperty(obj, property); + updateMethodCallback(); + this.pushResult({ + result: counter.count === count, + actual: counter.count, + expected: count, + message: label + }); + unwatch(); +}; + + diff --git a/tests/integration/record-arrays/peeked-records-test.js b/tests/integration/record-arrays/peeked-records-test.js new file mode 100644 index 00000000000..2693d2ac7ad --- /dev/null +++ b/tests/integration/record-arrays/peeked-records-test.js @@ -0,0 +1,433 @@ +import { run } from '@ember/runloop'; +import { createStore } from 'dummy/tests/helpers/store'; +import { module, test } from 'qunit'; +import DS from 'ember-data'; +import { get } from '@ember/object'; +import hasEmberVersion from 'ember-test-helpers/has-ember-version'; +import { watchProperties } from '../../helpers/watch-property'; + +let store; + +const Person = DS.Model.extend({ + name: DS.attr('string'), + toString() { + return ``; + } +}); + +module('integration/peeked-records', { + beforeEach() { + store = createStore({ + person: Person + }); + } +}); + +test('repeated calls to peekAll in separate run-loops works as expected', function(assert) { + let peekedRecordArray = run(() => store.peekAll('person')); + let watcher = watchProperties(peekedRecordArray, ['length', '[]']); + + run(() => store.push({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'John' + } + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Joe' + } + } + ] + })); + + assert.watchedPropertyCounts( + watcher, + { length: 1, '[]': 1 }, + 'RecordArray state after a single push with multiple records to add' + ); + + run(() => store.peekAll('person')); + + assert.watchedPropertyCounts( + watcher, + { length: 1, '[]': 1 }, + 'RecordArray state has not changed after another call to peek' + ); +}); + +test('peekAll in the same run-loop as push works as expected', function(assert) { + let peekedRecordArray = run(() => store.peekAll('person')); + let watcher = watchProperties(peekedRecordArray, ['length', '[]']); + + run(() => { + store.push({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'John' + } + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Joe' + } + } + ] + }); + store.peekAll('person'); + }); + + assert.watchedPropertyCounts( + watcher, + { length: 1, '[]': 1 }, + 'RecordArray state after a single push with multiple records to add' + ); + + run(() => store.peekAll('person')); + + assert.watchedPropertyCounts( + watcher, + { length: 1, '[]': 1 }, + 'RecordArray state has not changed after another call to peek' + ); +}); + +test('newly created records notify the array as expected', function(assert) { + let peekedRecordArray = run(() => store.peekAll('person')); + let watcher = watchProperties(peekedRecordArray, ['length', '[]']); + + let aNewlyCreatedRecord = run(() => store.createRecord('person', { + name: 'James' + })); + + assert.watchedPropertyCounts( + watcher, + { length: 1, '[]': 1 }, + 'RecordArray state when a new record is created' + ); + + run(() => { + aNewlyCreatedRecord.unloadRecord(); + }); + + assert.watchedPropertyCounts( + watcher, + { length: 2, '[]': 2 }, + 'RecordArray state when a new record is unloaded' + ); +}); + +test('immediately peeking newly created records works as expected', function(assert) { + let peekedRecordArray = run(() => store.peekAll('person')); + let watcher = watchProperties(peekedRecordArray, ['length', '[]']); + + let aNewlyCreatedRecord = run(() => store.createRecord('person', { + name: 'James' + })); + + assert.watchedPropertyCounts( + watcher, + { length: 1, '[]': 1 }, + 'RecordArray state when a new record is created' + ); + + run(() => { + aNewlyCreatedRecord.unloadRecord(); + store.peekAll('person'); + }); + + assert.watchedPropertyCounts( + watcher, + { length: 2, '[]': 2 }, + 'RecordArray state when a new record is unloaded' + ); +}); + +test('unloading newly created records notify the array as expected', function(assert) { + let peekedRecordArray = run(() => store.peekAll('person')); + let watcher = watchProperties(peekedRecordArray, ['length', '[]']); + let aNewlyCreatedRecord = run(() => store.createRecord('person', { + name: 'James' + })); + + assert.watchedPropertyCounts( + watcher, + { length: 1, '[]': 1 }, + 'RecordArray state when a new record is created' + ); + + run(() => { + aNewlyCreatedRecord.unloadRecord(); + }); + + assert.watchedPropertyCounts( + watcher, + { length: 2, '[]': 2 }, + 'RecordArray state when a new record is unloaded' + ); +}); + +test('immediately peeking after unloading newly created records works as expected', function(assert) { + let peekedRecordArray = run(() => store.peekAll('person')); + let watcher = watchProperties(peekedRecordArray, ['length', '[]']); + let aNewlyCreatedRecord = run(() => store.createRecord('person', { + name: 'James' + })); + + assert.watchedPropertyCounts( + watcher, + { length: 1, '[]': 1 }, + 'RecordArray state when a new record is created' + ); + + run(() => { + aNewlyCreatedRecord.unloadRecord(); + store.peekAll('person'); + }); + + assert.watchedPropertyCounts( + watcher, + { length: 2, '[]': 2 }, + 'RecordArray state when a new record is unloaded' + ); +}); + +test('unloadAll followed by peekAll in the same run-loop works as expected', function(assert) { + let peekedRecordArray = run(() => store.peekAll('person')); + let watcher = watchProperties(peekedRecordArray, ['length', '[]']); + + run(() => { + store.push({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'John' + } + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Joe' + } + } + ] + }); + }); + + run(() => { + store.peekAll('person'); + + assert.watchedPropertyCounts( + watcher, + { length: 1, '[]': 1 }, + 'RecordArray state after a single push with multiple records to add' + ); + + store.unloadAll('person'); + + assert.watchedPropertyCounts( + watcher, + { length: 1, '[]': 1 }, + 'RecordArray state after unloadAll has not changed yet' + ); + + assert.equal(get(peekedRecordArray, 'length'), 2, 'Array length is unchanged before the next peek'); + + store.peekAll('person'); + + assert.equal(get(peekedRecordArray, 'length'), 0, 'We no longer have any array content'); + + assert.watchedPropertyCounts( + watcher, + { length: 2, '[]': 2 }, + 'RecordArray state after a follow up peekAll reflects unload changes' + ); + }); + + assert.watchedPropertyCounts( + watcher, + { length: 2, '[]': 2 }, + 'RecordArray state has not changed any further' + ); +}); + +test('push+materialize => unloadAll => push+materialize works as expected', function(assert) { + function push() { + run(() => { + store.push({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'John' + } + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Joe' + } + } + ] + }); + }); + } + function unload() { + run(() => store.unloadAll('person')); + } + function peek() { + return run(() => store.peekAll('person')); + } + + let peekedRecordArray = peek(); + let watcher = watchProperties(peekedRecordArray, ['length', '[]']); + + push(); + assert.watchedPropertyCounts( + watcher, + { length: 1, '[]': 1 }, + 'RecordArray state after a single push with multiple records to add' + ); + + unload(); + assert.equal(get(peekedRecordArray, 'length'), 0, 'We no longer have any array content'); + assert.watchedPropertyCounts( + watcher, + { length: 2, '[]': 2 }, + 'RecordArray state has signaled the unload' + ); + + push(); + assert.equal(get(peekedRecordArray, 'length'), 2, 'We have array content'); + assert.watchedPropertyCounts( + watcher, + { length: 3, '[]': 3 }, + 'RecordArray state now has records again' + ); +}); + +test('push-without-materialize => unloadAll => push-without-materialize works as expected', function(assert) { + function _push() { + run(() => { + store._push({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'John' + } + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Joe' + } + } + ] + }); + }); + } + function unload() { + run(() => store.unloadAll('person')); + } + function peek() { + return run(() => store.peekAll('person')); + } + + let peekedRecordArray = peek(); + let watcher = watchProperties(peekedRecordArray, ['length', '[]']); + + _push(); + assert.watchedPropertyCounts( + watcher, + { length: 1, '[]': 1 }, + 'RecordArray state after a single push with multiple records to add' + ); + + unload(); + assert.equal(get(peekedRecordArray, 'length'), 0, 'We no longer have any array content'); + assert.watchedPropertyCounts( + watcher, + { length: 2, '[]': 2 }, + 'RecordArray state has signaled the unload' + ); + + _push(); + assert.equal(get(peekedRecordArray, 'length'), 2, 'We have array content'); + assert.watchedPropertyCounts( + watcher, + { length: 3, '[]': 3 }, + 'RecordArray state now has records again' + ); +}); + +test('unloading filtered records', function(assert) { + function push() { + run(() => { + store.push({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Scumbag John' + } + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Joe' + } + } + ] + }); + }); + } + + let people = run(() => { + return store.filter('person', hash => { + if (hash.get('name').match(/Scumbag/)) { + return true; + } + }); + }); + + assert.equal(get(people, 'length'), 0, 'precond - no items in the RecordArray'); + + push(); + + assert.equal(get(people, 'length'), 2, 'precond - two items in the RecordArray'); + + run(() => { + people.objectAt(0).unloadRecord(); + + if (hasEmberVersion(3, 0)) { + assert.equal(get(people, 'length'), 2, 'Unload does not complete until the end of the loop'); + assert.equal(get(people.objectAt(0), 'name'), 'Scumbag John', 'John is still the first object until the end of the loop'); + } else { + assert.equal(get(people, 'length'), 2, 'Unload does not complete until the end of the loop'); + assert.equal(people.objectAt(0), undefined, 'John is still the first object until the end of the loop'); + } + }); + + assert.equal(get(people, 'length'), 1, 'Unloaded record removed from the array'); + assert.equal(get(people.objectAt(0), 'name'), 'Scumbag Joe', 'Joe shifted down after the unload'); +}); diff --git a/yarn.lock b/yarn.lock index 528c9820256..3275bf1c980 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2969,9 +2969,9 @@ ember-source-channel-url@^1.0.1: dependencies: got "^8.0.1" -ember-source@~2.18.0: - version "2.18.2" - resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-2.18.2.tgz#75d00eef5488bfe504044b025c752ba924eaf87f" +ember-source@~3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/ember-source/-/ember-source-3.0.0.tgz#51811cae98d2ceec53bcfbaa876d02b2b5b2159f" dependencies: broccoli-funnel "^2.0.1" broccoli-merge-trees "^2.0.0" @@ -2980,7 +2980,6 @@ ember-source@~2.18.0: ember-cli-normalize-entity-name "^1.0.0" ember-cli-path-utils "^1.0.0" ember-cli-string-utils "^1.1.0" - ember-cli-test-info "^1.0.0" ember-cli-valid-component-name "^1.0.0" ember-cli-version-checker "^2.1.0" ember-router-generator "^1.2.3" @@ -4695,7 +4694,7 @@ jmespath@0.15.0: jquery@^3.2.1: version "3.3.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" + resolved "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" js-reporters@1.2.1: version "1.2.1" From 69cb27a9b7cd12a2c3b1854a693ff476181e27c0 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 26 Mar 2018 05:46:41 -0700 Subject: [PATCH 2156/2527] [FIX release-guide] restore guidance to update default ember-cli blueprint (#5390) --- RELEASE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASE.md b/RELEASE.md index 049331d59f5..ce6301e96dd 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -31,6 +31,8 @@ STEPS: * Write a Release Blog Post (Does not happen for beta releases) * Commits since last release: `git log --oneline release..beta | wc -l`. * Contributors since last release: `git shortlog -s -n release...beta | wc -l` +* Submit a Pull request to the https://github.com/ember-cli/ember-cli to update the version of Ember Data + * (per request by @rwjblue and is also a great idea to make upgrading/new apps easier) * Bump version in package.json back to a canary version * For beta.1 releases, branch beta from master and update https://github.com/emberjs/data/blob/master/config/features.json to have `false` values instead of `null` and update the version in package.json From ea6aadd73bb9fabc14357e7791325e811efecedc Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 26 Mar 2018 05:48:11 -0700 Subject: [PATCH 2157/2527] [FEAT] remove all stale feature flags (#5384) * [FEAT] remove all stale feature flags * fix lint errors --- FEATURES.md | 124 +----- addon/-private/system/model/internal-model.js | 18 - addon/-private/system/model/model.js | 26 -- .../-private/system/references/belongs-to.js | 8 - addon/-private/system/references/has-many.js | 50 +-- addon/-private/system/store.js | 18 +- addon/adapters/json-api.js | 79 +--- addon/adapters/rest.js | 420 ++---------------- addon/serializers/json-api.js | 234 +--------- addon/serializers/json.js | 95 +--- addon/serializers/rest.js | 190 +------- config/features.json | 7 - 12 files changed, 88 insertions(+), 1181 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 2d566c89c37..fd945910b0e 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -11,126 +11,4 @@ entry in `config/features.json`. ## Feature Flags -- `ds-improved-ajax` [#3099](https://github.com/emberjs/data/pull/3099) - - This feature allows to customize how a request is formed by overwriting - `methodForRequest`, `urlForRequest`, `headersForRequest` and `bodyForRequest` - in the `DS.RESTAdapter`. - -- `ds-pushpayload-return` [#4110](https://github.com/emberjs/data/pull/4110) - - Enables `pushPayload` to return the model(s) that are created or - updated via the internal `store.push`. - -- `ds-payload-type-hooks` [#4318](https://github.com/emberjs/data/pull/4318) - - Adds two new hooks `modelNameFromPayloadType` and `payloadTypeFromModelName` - hooks to the serializers. They are used to map a custom type in the payload - to the Ember-Data model name and vice versa. - - It also deprecates `modelNameFromPayloadKey` and `payloadKeyFromModelName` - for the JSONSerializer and JSONAPISerializer: those payloads don't have - _keys_ which represent a model name. Only the keys in the payload for a - RESTSerializer represent model names, so the `payloadKeyFromModelName` and - `modelNameFromPayloadKey` are available in that serializer. - - ```js - // rest response - { - "blog/post": { - "id": 1, - "user": 1, - "userType": "api::v1::administrator" - } - } - - // RESTSerializer invokes the following hooks - restSerializer.modelNameFromPayloadKey("blog/post"); - restSerializer.modelNameFromPayloadType("api::v1::administrator"); - ``` - - ```js - // json-api response - { - "data": { - "id": 1, - "type": "api::v1::administrator", - "relationships": { - "supervisor": { - "data": { - "id": 1, - "type": "api::v1::super-user" - } - } - } - } - } - - // JSONAPISerializer invokes the following hooks - jsonApiSerializer.modelNameFromPayloadType("api::v1::administrator"); - jsonApiSerializer.modelNameFromPayloadType("api::v1::super-user"); - ``` - -- `ds-overhaul-references` [#4398](https://github.com/emberjs/data/pull/4398) - - This tackles some inconsistencies within `push()` on references. It should - only be used to push a JSON-API payload. The following use cases are - addressed and deprecated: - - - `BelongsToReference#push()` accepts a `DS.Model` - - `HasManyReference#push()` accepts a plain array - - `HasManyReference#push()` accepts a pseudo-JSON-API format: - - ```js - { - data: [ - { data: { type: 'model', id: 1 } } - ] - } - ``` - -- `ds-check-should-serialize-relationships` [#4279](https://github.com/emberjs/data/pull/4279) - - Adds public method for `shouldSerializeHasMany`, used to determine if a - `hasMany` relationship can be serialized. - -- `ds-rollback-attribute` [#4246](https://github.com/emberjs/data/pull/4246) - - Adds a `rollbackAttribute` method to models. Similar to `rollbackAttributes`, - but for only a single attribute. - - ```js - // { firstName: 'Tom', lastName: 'Dale' } - let tom = store.peekRecord('person', 1); - - tom.setProperties({ - firstName: 'Yehuda', - lastName: 'Katz' - }); - - tom.rollbackAttribute('firstName') // { firstName: 'Tom', lastName: 'Katz' } - tom.get('hasDirtyAttributes') // true - - tom.rollbackAttribute('lastName') // { firstName: 'Tom', lastName: 'Dale' } - tom.get('hasDirtyAttributes') // false - ``` - -- `ds-serialize-id` [#4620](https://github.com/emberjs/data/pull/4620) - - Adds a `serializeId` method to JSONSerializer. - - ```js - // app/serializers/application.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - serializeId(snapshot, json, primaryKey) { - var id = snapshot.id; - json[primaryKey] = parseInt(id, 10); - } - }); - ``` -- `ds-deprecate-store-serialize` [#4654](https://github.com/emberjs/data/pull/4654) - - Adds a deprecation warning when using Store#serialize(record) method. - You can use record.serialize() instead. +- None currently. diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 07a6a336de2..959550bd3ef 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -12,7 +12,6 @@ import { assert, inspect } from '@ember/debug'; import RootState from "./states"; import Relationships from "../relationships/state/create"; import Snapshot from "../snapshot"; -import isEnabled from '../../features'; import OrderedSet from "../ordered-set"; import { getOwner } from '../../utils'; @@ -1251,20 +1250,3 @@ export default class InternalModel { return reference; } } - -if (isEnabled('ds-rollback-attribute')) { - /* - Returns the latest truth for an attribute - the canonical value, or the - in-flight value. - - @method lastAcknowledgedValue - @private - */ - InternalModel.prototype.lastAcknowledgedValue = function lastAcknowledgedValue(key) { - if (key in this._inFlightAttributes) { - return this._inFlightAttributes[key]; - } else { - return this._data[key]; - } - }; -} diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 5d2ecce2d28..9963195b06a 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -12,7 +12,6 @@ import { DEBUG } from '@glimmer/env'; import { assert, warn } from '@ember/debug'; import { PromiseObject } from "../promise-proxies"; import Errors from "../model/errors"; -import isEnabled from '../../features'; import RootState from '../model/states'; import { relationshipsByNameDescriptor, @@ -1842,31 +1841,6 @@ Model.reopenClass({ } }); -if (isEnabled('ds-rollback-attribute')) { - Model.reopen({ - /** - Discards any unsaved changes to the given attribute. This feature is not enabled by default. You must enable `ds-rollback-attribute` and be running a canary build. - - Example - - ```javascript - record.get('name'); // 'Untitled Document' - record.set('name', 'Doc 1'); - record.get('name'); // 'Doc 1' - record.rollbackAttribute('name'); - record.get('name'); // 'Untitled Document' - ``` - - @method rollbackAttribute - */ - rollbackAttribute(attributeName) { - if (attributeName in this._internalModel._attributes) { - this.set(attributeName, this._internalModel.lastAcknowledgedValue(attributeName)); - } - } - }); -} - if (DEBUG) { Model.reopen({ // This is a temporary solution until we refactor DS.Model to not diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 440583e4c10..20a285bbb44 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -2,8 +2,6 @@ import { resolve } from 'rsvp'; import Model from '../model/model'; import Reference from './reference'; -import isEnabled from '../../features'; -import { deprecate } from '@ember/debug'; import { assertPolymorphicType } from 'ember-data/-debug'; /** @@ -241,12 +239,6 @@ export default class BelongsToReference extends Reference { let record; if (data instanceof Model) { - if (isEnabled('ds-overhaul-references')) { - deprecate("BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead.", false, { - id: 'ds.references.belongs-to.push-record', - until: '4.0.0' - }); - } record = data; } else { record = this.store.push(data); diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index a14a1bcbc42..9af516d6d48 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -1,13 +1,9 @@ -import { A } from '@ember/array'; import { resolve } from 'rsvp'; import { get } from '@ember/object'; import Reference from './reference'; import { DEBUG } from '@glimmer/env'; -import { deprecate } from '@ember/debug'; import { assertPolymorphicType } from 'ember-data/-debug'; -import isEnabled from '../../features'; - /** A HasManyReference is a low level API that allows users and addon author to perform meta-operations on a has-many relationship. @@ -239,53 +235,21 @@ export default class HasManyReference extends Reference { return resolve(objectOrPromise).then((payload) => { let array = payload; - if (isEnabled("ds-overhaul-references")) { - deprecate("HasManyReference#push(array) is deprecated. Push a JSON-API document instead.", !Array.isArray(payload), { - id: 'ds.references.has-many.push-array', - until: '4.0.0' - }); - } - - let useLegacyArrayPush = true; if (typeof payload === "object" && payload.data) { array = payload.data; - useLegacyArrayPush = array.length && array[0].data; - - if (isEnabled('ds-overhaul-references')) { - deprecate("HasManyReference#push() expects a valid JSON-API document.", !useLegacyArrayPush, { - id: 'ds.references.has-many.push-invalid-json-api', - until: '4.0.0' - }); - } - } - - if (!isEnabled('ds-overhaul-references')) { - useLegacyArrayPush = true; } let internalModels; - if (useLegacyArrayPush) { - internalModels = array.map((obj) => { - let record = this.store.push(obj); - - if (DEBUG) { - let relationshipMeta = this.hasManyRelationship.relationshipMeta; - assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel); - } - - return record._internalModel; - }); - } else { - let records = this.store.push(payload); - internalModels = A(records).mapBy('_internalModel'); + internalModels = array.map((obj) => { + let record = this.store.push(obj); if (DEBUG) { - internalModels.forEach((internalModel) => { - let relationshipMeta = this.hasManyRelationship.relationshipMeta; - assertPolymorphicType(this.internalModel, relationshipMeta, internalModel); - }); + let relationshipMeta = this.hasManyRelationship.relationshipMeta; + assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel); } - } + + return record._internalModel; + }); this.hasManyRelationship.computeChanges(internalModels); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 5a05a368999..4ff0fb72f0f 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -51,7 +51,6 @@ import { getOwner } from '../utils'; import coerceId from "./coerce-id"; import RecordArrayManager from "./record-array-manager"; import InternalModel from "./model/internal-model"; -import isEnabled from '../features'; const badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; @@ -273,12 +272,11 @@ Store = Service.extend({ @param {Object} options an options hash */ serialize(record, options) { - if (isEnabled('ds-deprecate-store-serialize')) { - deprecate('Use of store.serialize is deprecated, use record.serialize instead.', false, { - id: 'ds.store.serialize', - until: '3.0' - }); - } + deprecate('Use of store.serialize is deprecated, use record.serialize instead.', false, { + id: 'ds.store.serialize', + until: '3.0' + }); + let snapshot = record._internalModel.createSnapshot(); return snapshot.serialize(options); }, @@ -2525,11 +2523,7 @@ Store = Service.extend({ let normalizedModelName = normalizeModelName(modelName); serializer = this.serializerFor(normalizedModelName); } - if (isEnabled('ds-pushpayload-return')) { - return serializer.pushPayload(this, payload); - } else { - serializer.pushPayload(this, payload); - } + serializer.pushPayload(this, payload); }, /** diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index d321e91659b..fa85c6a1e93 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -4,7 +4,6 @@ */ import { dasherize } from '@ember/string'; import RESTAdapter from "./rest"; -import { isEnabled } from '../-private'; import { deprecate } from '@ember/debug'; import { instrument } from 'ember-data/-debug'; import { pluralize } from 'ember-inflector'; @@ -248,12 +247,8 @@ const JSONAPIAdapter = RESTAdapter.extend({ coalesceFindRequests: false, findMany(store, type, ids, snapshots) { - if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - return this._super(...arguments); - } else { - let url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); - return this.ajax(url, 'GET', { data: { filter: { id: ids.join(',') } } }); - } + let url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); + return this.ajax(url, 'GET', { data: { filter: { id: ids.join(',') } } }); }, pathForType(modelName) { @@ -263,18 +258,14 @@ const JSONAPIAdapter = RESTAdapter.extend({ // TODO: Remove this once we have a better way to override HTTP verbs. updateRecord(store, type, snapshot) { - if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - return this._super(...arguments); - } else { - let data = {}; - let serializer = store.serializerFor(type.modelName); + let data = {}; + let serializer = store.serializerFor(type.modelName); - serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); + serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); - let url = this.buildURL(type.modelName, snapshot.id, snapshot, 'updateRecord'); + let url = this.buildURL(type.modelName, snapshot.id, snapshot, 'updateRecord'); - return this.ajax(url, 'PATCH', { data: data }); - } + return this.ajax(url, 'PATCH', { data: data }); }, _hasCustomizedAjax() { @@ -298,60 +289,4 @@ const JSONAPIAdapter = RESTAdapter.extend({ } }); -if (isEnabled('ds-improved-ajax')) { - - JSONAPIAdapter.reopen({ - - methodForRequest(params) { - if (params.requestType === 'updateRecord') { - return 'PATCH'; - } - - return this._super(...arguments); - }, - - dataForRequest(params) { - let { requestType, ids } = params; - - if (requestType === 'findMany') { - return { - filter: { id: ids.join(',') } - }; - } - - if (requestType === 'updateRecord') { - let { store, type, snapshot } = params; - let data = {}; - let serializer = store.serializerFor(type.modelName); - - serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); - - return data; - } - - return this._super(...arguments); - }, - - headersForRequest() { - let headers = this._super(...arguments) || {}; - - headers['Accept'] = 'application/vnd.api+json'; - - return headers; - }, - - _requestToJQueryAjaxHash() { - let hash = this._super(...arguments); - - if (hash.contentType) { - hash.contentType = 'application/vnd.api+json'; - } - - return hash; - } - - }); - -} - export default JSONAPIAdapter; diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index c2d02d92cbd..d5f30682fa4 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -12,7 +12,6 @@ import Adapter from "../adapter"; import { parseResponseHeaders, BuildURLMixin, - isEnabled, AdapterError, InvalidError, UnauthorizedError, @@ -478,19 +477,10 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findRecord(store, type, id, snapshot) { - if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - let request = this._requestFor({ - store, type, id, snapshot, - requestType: 'findRecord' - }); - - return this._makeRequest(request); - } else { - let url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); - let query = this.buildQuery(snapshot); + let url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); + let query = this.buildQuery(snapshot); - return this.ajax(url, 'GET', { data: query }); - } + return this.ajax(url, 'GET', { data: query }); }, /** @@ -509,24 +499,13 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { */ findAll(store, type, sinceToken, snapshotRecordArray) { let query = this.buildQuery(snapshotRecordArray); + let url = this.buildURL(type.modelName, null, snapshotRecordArray, 'findAll'); - if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - let request = this._requestFor({ - store, type, sinceToken, query, - snapshots: snapshotRecordArray, - requestType: 'findAll' - }); - - return this._makeRequest(request); - } else { - let url = this.buildURL(type.modelName, null, snapshotRecordArray, 'findAll'); - - if (sinceToken) { - query.since = sinceToken; - } - - return this.ajax(url, 'GET', { data: query }); + if (sinceToken) { + query.since = sinceToken; } + + return this.ajax(url, 'GET', { data: query }); }, /** @@ -547,22 +526,13 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ query(store, type, query) { - if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - let request = this._requestFor({ - store, type, query, - requestType: 'query' - }); + let url = this.buildURL(type.modelName, null, null, 'query', query); - return this._makeRequest(request); - } else { - let url = this.buildURL(type.modelName, null, null, 'query', query); - - if (this.sortQueryParams) { - query = this.sortQueryParams(query); - } - - return this.ajax(url, 'GET', { data: query }); + if (this.sortQueryParams) { + query = this.sortQueryParams(query); } + + return this.ajax(url, 'GET', { data: query }); }, /** @@ -584,22 +554,13 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ queryRecord(store, type, query) { - if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - let request = this._requestFor({ - store, type, query, - requestType: 'queryRecord' - }); - - return this._makeRequest(request); - } else { - let url = this.buildURL(type.modelName, null, null, 'queryRecord', query); - - if (this.sortQueryParams) { - query = this.sortQueryParams(query); - } + let url = this.buildURL(type.modelName, null, null, 'queryRecord', query); - return this.ajax(url, 'GET', { data: query }); + if (this.sortQueryParams) { + query = this.sortQueryParams(query); } + + return this.ajax(url, 'GET', { data: query }); }, /** @@ -636,17 +597,8 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findMany(store, type, ids, snapshots) { - if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - let request = this._requestFor({ - store, type, ids, snapshots, - requestType: 'findMany' - }); - - return this._makeRequest(request); - } else { - let url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); - return this.ajax(url, 'GET', { data: { ids: ids } }); - } + let url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); + return this.ajax(url, 'GET', { data: { ids: ids } }); }, /** @@ -686,21 +638,12 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findHasMany(store, snapshot, url, relationship) { - if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - let request = this._requestFor({ - store, snapshot, url, relationship, - requestType: 'findHasMany' - }); + let id = snapshot.id; + let type = snapshot.modelName; - return this._makeRequest(request); - } else { - let id = snapshot.id; - let type = snapshot.modelName; - - url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findHasMany')); + url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findHasMany')); - return this.ajax(url, 'GET'); - } + return this.ajax(url, 'GET'); }, /** @@ -740,20 +683,11 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findBelongsTo(store, snapshot, url, relationship) { - if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - let request = this._requestFor({ - store, snapshot, url, relationship, - requestType: 'findBelongsTo' - }); - - return this._makeRequest(request); - } else { - let id = snapshot.id; - let type = snapshot.modelName; + let id = snapshot.id; + let type = snapshot.modelName; - url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findBelongsTo')); - return this.ajax(url, 'GET'); - } + url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findBelongsTo')); + return this.ajax(url, 'GET'); }, /** @@ -773,22 +707,13 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ createRecord(store, type, snapshot) { - if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - let request = this._requestFor({ - store, type, snapshot, - requestType: 'createRecord' - }); - - return this._makeRequest(request); - } else { - let data = {}; - let serializer = store.serializerFor(type.modelName); - let url = this.buildURL(type.modelName, null, snapshot, 'createRecord'); + let data = {}; + let serializer = store.serializerFor(type.modelName); + let url = this.buildURL(type.modelName, null, snapshot, 'createRecord'); - serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); + serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); - return this.ajax(url, "POST", { data: data }); - } + return this.ajax(url, "POST", { data: data }); }, /** @@ -808,24 +733,15 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ updateRecord(store, type, snapshot) { - if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - let request = this._requestFor({ - store, type, snapshot, - requestType: 'updateRecord' - }); + let data = {}; + let serializer = store.serializerFor(type.modelName); - return this._makeRequest(request); - } else { - let data = {}; - let serializer = store.serializerFor(type.modelName); - - serializer.serializeIntoHash(data, type, snapshot); + serializer.serializeIntoHash(data, type, snapshot); - let id = snapshot.id; - let url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); + let id = snapshot.id; + let url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); - return this.ajax(url, "PUT", { data: data }); - } + return this.ajax(url, "PUT", { data: data }); }, /** @@ -840,18 +756,9 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ deleteRecord(store, type, snapshot) { - if (isEnabled('ds-improved-ajax') && !this._hasCustomizedAjax()) { - let request = this._requestFor({ - store, type, snapshot, - requestType: 'deleteRecord' - }); - - return this._makeRequest(request); - } else { - let id = snapshot.id; + let id = snapshot.id; - return this.ajax(this.buildURL(type.modelName, id, snapshot, 'deleteRecord'), "DELETE"); - } + return this.ajax(this.buildURL(type.modelName, id, snapshot, 'deleteRecord'), "DELETE"); }, _stripIDFromURL(store, snapshot) { @@ -1246,251 +1153,6 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { } }); -if (isEnabled('ds-improved-ajax')) { - - RESTAdapter.reopen({ - - /* - * Get the data (body or query params) for a request. - * - * @public - * @method dataForRequest - * @param {Object} params - * @return {Object} data - */ - dataForRequest(params) { - let { store, type, snapshot, requestType, query } = params; - - // type is not passed to findBelongsTo and findHasMany - type = type || (snapshot && snapshot.type); - - let serializer = store.serializerFor(type.modelName); - let data = {}; - - switch (requestType) { - case 'createRecord': - serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); - break; - - case 'updateRecord': - serializer.serializeIntoHash(data, type, snapshot); - break; - - case 'findRecord': - data = this.buildQuery(snapshot); - break; - - case 'findAll': - if (params.sinceToken) { - query = query || {}; - query.since = params.sinceToken; - } - data = query; - break; - - case 'query': - case 'queryRecord': - if (this.sortQueryParams) { - query = this.sortQueryParams(query); - } - data = query; - break; - - case 'findMany': - data = { ids: params.ids }; - break; - - default: - data = undefined; - break; - } - - return data; - }, - - /* - * Get the HTTP method for a request. - * - * @public - * @method methodForRequest - * @param {Object} params - * @return {String} HTTP method - */ - methodForRequest(params) { - let { requestType } = params; - - switch (requestType) { - case 'createRecord': return 'POST'; - case 'updateRecord': return 'PUT'; - case 'deleteRecord': return 'DELETE'; - } - - return 'GET'; - }, - - /* - * Get the URL for a request. - * - * @public - * @method urlForRequest - * @param {Object} params - * @return {String} URL - */ - urlForRequest(params) { - let { type, id, ids, snapshot, snapshots, requestType, query } = params; - - // type and id are not passed from updateRecord and deleteRecord, hence they - // are defined if not set - type = type || (snapshot && snapshot.type); - id = id || (snapshot && snapshot.id); - - switch (requestType) { - case 'findAll': - return this.buildURL(type.modelName, null, snapshots, requestType); - - case 'query': - case 'queryRecord': - return this.buildURL(type.modelName, null, null, requestType, query); - - case 'findMany': - return this.buildURL(type.modelName, ids, snapshots, requestType); - - case 'findHasMany': - case 'findBelongsTo': { - let url = this.buildURL(type.modelName, id, snapshot, requestType); - return this.urlPrefix(params.url, url); - } - } - - return this.buildURL(type.modelName, id, snapshot, requestType, query); - }, - - /* - * Get the headers for a request. - * - * By default the value of the `headers` property of the adapter is - * returned. - * - * @public - * @method headersForRequest - * @param {Object} params - * @return {Object} headers - */ - headersForRequest(params) { - return this.get('headers'); - }, - - /* - * Get an object which contains all properties for a request which should - * be made. - * - * @private - * @method _requestFor - * @param {Object} params - * @return {Object} request object - */ - _requestFor(params) { - let method = this.methodForRequest(params); - let url = this.urlForRequest(params); - let headers = this.headersForRequest(params); - let data = this.dataForRequest(params); - - return { method, url, headers, data }; - }, - - /* - * Convert a request object into a hash which can be passed to `jQuery.ajax`. - * - * @private - * @method _requestToJQueryAjaxHash - * @param {Object} request - * @return {Object} jQuery ajax hash - */ - _requestToJQueryAjaxHash(request) { - let hash = {}; - - hash.type = request.method; - hash.url = request.url; - hash.dataType = 'json'; - hash.context = this; - - if (request.data) { - if (request.method !== 'GET') { - hash.contentType = 'application/json; charset=utf-8'; - hash.data = JSON.stringify(request.data); - } else { - hash.data = request.data; - } - } - - let headers = request.headers; - if (headers !== undefined) { - hash.beforeSend = function(xhr) { - Object.keys(headers).forEach((key) => xhr.setRequestHeader(key, headers[key])); - }; - } - - return hash; - }, - - /* - * Make a request using `jQuery.ajax`. - * - * @private - * @method _makeRequest - * @param {Object} request - * @return {Promise} promise - */ - _makeRequest(request) { - let token = heimdall.start('adapter._makeRequest'); - let adapter = this; - let hash = this._requestToJQueryAjaxHash(request); - - let { method, url } = request; - let requestData = { method, url }; - - return new Promise((resolve, reject) => { - - hash.success = function(payload, textStatus, jqXHR) { - heimdall.stop(token); - let response = ajaxSuccess(adapter, jqXHR, payload, requestData); - run.join(null, resolve, response); - }; - - hash.error = function(jqXHR, textStatus, errorThrown) { - heimdall.stop(token); - let responseData = { - textStatus, - errorThrown - }; - let error = ajaxError(adapter, jqXHR, requestData, responseData); - run.join(null, reject, error); - }; - - instrument(function() { - hash.converters = { - 'text json': function(payload) { - let token = heimdall.start('json.parse'); - let json; - try { - json = JSON.parse(payload); - } catch (e) { - json = payload; - } - heimdall.stop(token); - return json; - } - }; - }); - - adapter._ajaxRequest(hash); - - }, `DS: RESTAdapter#makeRequest: ${method} ${url}`); - } - }); - -} - function ajaxSuccess(adapter, jqXHR, payload, requestData) { let response; try { diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 02ba82f1acd..0c6684eacd6 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -6,11 +6,11 @@ import { typeOf, isNone } from '@ember/utils'; import { dasherize } from '@ember/string'; import { pluralize, singularize } from 'ember-inflector'; -import { assert, deprecate, warn } from '@ember/debug'; +import { assert, warn } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; import JSONSerializer from './json'; -import { normalizeModelName, isEnabled } from '../-private'; +import { normalizeModelName } from '../-private'; /** Ember Data 2.0 Serializer: @@ -174,23 +174,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @private */ _normalizeRelationshipDataHelper(relationshipDataHash) { - if (isEnabled("ds-payload-type-hooks")) { - let modelName = this.modelNameFromPayloadType(relationshipDataHash.type); - let deprecatedModelNameLookup = this.modelNameFromPayloadKey(relationshipDataHash.type); - - if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { - deprecate("You are using modelNameFromPayloadKey to normalize the type for a relationship. This has been deprecated in favor of modelNameFromPayloadType", false, { - id: 'ds.json-api-serializer.deprecated-model-name-for-relationship', - until: '4.0.0' - }); - - modelName = deprecatedModelNameLookup; - } - - relationshipDataHash.type = modelName; - } else { - relationshipDataHash.type = this.modelNameFromPayloadKey(relationshipDataHash.type); - } + relationshipDataHash.type = this.modelNameFromPayloadKey(relationshipDataHash.type); return relationshipDataHash; }, @@ -208,25 +192,8 @@ const JSONAPISerializer = JSONSerializer.extend({ let modelName, usedLookup; - if (isEnabled("ds-payload-type-hooks")) { - modelName = this.modelNameFromPayloadType(resourceHash.type); - let deprecatedModelNameLookup = this.modelNameFromPayloadKey(resourceHash.type); - - usedLookup = 'modelNameFromPayloadType'; - - if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { - deprecate("You are using modelNameFromPayloadKey to normalize the type for a resource. This has been deprecated in favor of modelNameFromPayloadType", false, { - id: 'ds.json-api-serializer.deprecated-model-name-for-resource', - until: '4.0.0' - }); - - modelName = deprecatedModelNameLookup; - usedLookup = 'modelNameFromPayloadKey'; - } - } else { - modelName = this.modelNameFromPayloadKey(resourceHash.type); - usedLookup = 'modelNameFromPayloadKey'; - } + modelName = this.modelNameFromPayloadKey(resourceHash.type); + usedLookup = 'modelNameFromPayloadKey'; if (!this.store._hasModelFor(modelName)) { warn(this.warnMessageNoModelForType(modelName, resourceHash.type, usedLookup), false, { @@ -248,11 +215,7 @@ const JSONAPISerializer = JSONSerializer.extend({ */ pushPayload(store, payload) { let normalizedPayload = this._normalizeDocumentHelper(payload); - if (isEnabled('ds-pushpayload-return')) { - return store.push(normalizedPayload); - } else { - store.push(normalizedPayload); - } + store.push(normalizedPayload); }, /** @@ -371,23 +334,7 @@ const JSONAPISerializer = JSONSerializer.extend({ @private */ _extractType(modelClass, resourceHash) { - if (isEnabled("ds-payload-type-hooks")) { - let modelName = this.modelNameFromPayloadType(resourceHash.type); - let deprecatedModelNameLookup = this.modelNameFromPayloadKey(resourceHash.type); - - if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { - deprecate("You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This has been deprecated in favor of modelNameFromPayloadType", false, { - id: 'ds.json-api-serializer.deprecated-model-name-for-polymorphic-type', - until: '3.0.0' - }); - - modelName = deprecatedModelNameLookup; - } - - return modelName; - } else { - return this.modelNameFromPayloadKey(resourceHash.type); - } + return this.modelNameFromPayloadKey(resourceHash.type); }, /** @@ -506,25 +453,8 @@ const JSONAPISerializer = JSONSerializer.extend({ serialize(snapshot, options) { let data = this._super(...arguments); + data.type = this.payloadKeyFromModelName(snapshot.modelName); - let payloadType; - if (isEnabled("ds-payload-type-hooks")) { - payloadType = this.payloadTypeFromModelName(snapshot.modelName); - let deprecatedPayloadTypeLookup = this.payloadKeyFromModelName(snapshot.modelName); - - if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { - deprecate("You used payloadKeyFromModelName to customize how a type is serialized. Use payloadTypeFromModelName instead.", false, { - id: 'ds.json-api-serializer.deprecated-payload-type-for-model', - until: '4.0.0' - }); - - payloadType = deprecatedPayloadTypeLookup; - } - } else { - payloadType = this.payloadKeyFromModelName(snapshot.modelName); - } - - data.type = payloadType; return { data }; }, @@ -567,23 +497,7 @@ const JSONAPISerializer = JSONSerializer.extend({ let data = null; if (belongsTo) { - let payloadType; - - if (isEnabled("ds-payload-type-hooks")) { - payloadType = this.payloadTypeFromModelName(belongsTo.modelName); - let deprecatedPayloadTypeLookup = this.payloadKeyFromModelName(belongsTo.modelName); - - if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { - deprecate("You used payloadKeyFromModelName to serialize type for belongs-to relationship. Use payloadTypeFromModelName instead.", false, { - id: 'ds.json-api-serializer.deprecated-payload-type-for-belongs-to', - until: '4.0.0' - }); - - payloadType = deprecatedPayloadTypeLookup; - } - } else { - payloadType = this.payloadKeyFromModelName(belongsTo.modelName); - } + let payloadType = this.payloadKeyFromModelName(belongsTo.modelName); data = { type: payloadType, @@ -614,24 +528,7 @@ const JSONAPISerializer = JSONSerializer.extend({ for (let i = 0; i < hasMany.length; i++) { let item = hasMany[i]; - - let payloadType; - - if (isEnabled("ds-payload-type-hooks")) { - payloadType = this.payloadTypeFromModelName(item.modelName); - let deprecatedPayloadTypeLookup = this.payloadKeyFromModelName(item.modelName); - - if (payloadType !== deprecatedPayloadTypeLookup && this._hasCustomPayloadKeyFromModelName()) { - deprecate("You used payloadKeyFromModelName to serialize type for belongs-to relationship. Use payloadTypeFromModelName instead.", false, { - id: 'ds.json-api-serializer.deprecated-payload-type-for-has-many', - until: '4.0.0' - }); - - payloadType = deprecatedPayloadTypeLookup; - } - } else { - payloadType = this.payloadKeyFromModelName(item.modelName); - } + let payloadType = this.payloadKeyFromModelName(item.modelName); data[i] = { type: payloadType, @@ -645,117 +542,6 @@ const JSONAPISerializer = JSONSerializer.extend({ } }); -if (isEnabled("ds-payload-type-hooks")) { - - JSONAPISerializer.reopen({ - - /** - `modelNameFromPayloadType` can be used to change the mapping for a DS model - name, taken from the value in the payload. - - Say your API namespaces the type of a model and returns the following - payload for the `post` model: - - ```javascript - // GET /api/posts/1 - { - "data": { - "id": 1, - "type: "api::v1::post" - } - } - ``` - - By overwriting `modelNameFromPayloadType` you can specify that the - `post` model should be used: - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.JSONAPISerializer.extend({ - modelNameFromPayloadType(payloadType) { - return payloadType.replace('api::v1::', ''); - } - }); - ``` - - By default the modelName for a model is its singularized name in dasherized - form. Usually, Ember Data can use the correct inflection to do this for - you. Most of the time, you won't need to override - `modelNameFromPayloadType` for this purpose. - - Also take a look at - [payloadTypeFromModelName](#method_payloadTypeFromModelName) to customize - how the type of a record should be serialized. - - @method modelNameFromPayloadType - @public - @param {String} payloadType type from payload - @return {String} modelName - */ - modelNameFromPayloadType(type) { - return singularize(normalizeModelName(type)); - }, - - /** - `payloadTypeFromModelName` can be used to change the mapping for the type in - the payload, taken from the model name. - - Say your API namespaces the type of a model and expects the following - payload when you update the `post` model: - - ```javascript - // POST /api/posts/1 - { - "data": { - "id": 1, - "type": "api::v1::post" - } - } - ``` - - By overwriting `payloadTypeFromModelName` you can specify that the - namespaces model name for the `post` should be used: - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default JSONAPISerializer.extend({ - payloadTypeFromModelName(modelName) { - return 'api::v1::' + modelName; - } - }); - ``` - - By default the payload type is the pluralized model name. Usually, Ember - Data can use the correct inflection to do this for you. Most of the time, - you won't need to override `payloadTypeFromModelName` for this purpose. - - Also take a look at - [modelNameFromPayloadType](#method_modelNameFromPayloadType) to customize - how the model name from should be mapped from the payload. - - @method payloadTypeFromModelName - @public - @param {String} modelname modelName from the record - @return {String} payloadType - */ - payloadTypeFromModelName(modelName) { - return pluralize(modelName); - }, - - _hasCustomModelNameFromPayloadKey() { - return this.modelNameFromPayloadKey !== JSONAPISerializer.prototype.modelNameFromPayloadKey; - }, - - _hasCustomPayloadKeyFromModelName() { - return this.payloadKeyFromModelName !== JSONAPISerializer.prototype.payloadKeyFromModelName; - } - - }); - -} - if (DEBUG) { JSONAPISerializer.reopen({ willMergeMixin(props) { diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 1970d21dcb5..88d9c1a33d3 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1,15 +1,14 @@ import { assign, merge } from '@ember/polyfills'; import { isNone, typeOf } from '@ember/utils'; import { get } from '@ember/object'; -import { assert, deprecate, warn } from '@ember/debug'; +import { assert, warn } from '@ember/debug'; import Serializer from "../serializer"; import { getOwner, coerceId, modelHasAttributeOrRelationshipNamedType, normalizeModelName, - errorsArrayToHash, - isEnabled + errorsArrayToHash } from '../-private'; const emberAssign = assign || merge; @@ -611,26 +610,9 @@ const JSONSerializer = Serializer.extend({ let modelClass = this.store.modelFor(relationshipModelName); if (relationshipHash.type && !modelHasAttributeOrRelationshipNamedType(modelClass)) { - - if (isEnabled("ds-payload-type-hooks")) { - let modelName = this.modelNameFromPayloadType(relationshipHash.type); - let deprecatedModelNameLookup = this.modelNameFromPayloadKey(relationshipHash.type); - - if (modelName !== deprecatedModelNameLookup && this._hasCustomModelNameFromPayloadKey()) { - deprecate("You used modelNameFromPayloadKey to customize how a type is normalized. Use modelNameFromPayloadType instead", false, { - id: 'ds.json-serializer.deprecated-type-for-polymorphic-relationship', - until: '3.0.0' - }); - - modelName = deprecatedModelNameLookup; - } - - relationshipHash.type = modelName; - - } else { - relationshipHash.type = this.modelNameFromPayloadKey(relationshipHash.type); - } + relationshipHash.type = this.modelNameFromPayloadKey(relationshipHash.type); } + return relationshipHash; } return { id: coerceId(relationshipHash), type: relationshipModelName }; @@ -1012,13 +994,9 @@ const JSONSerializer = Serializer.extend({ let json = {}; if (options && options.includeId) { - if (isEnabled('ds-serialize-id')) { - this.serializeId(snapshot, json, get(this, 'primaryKey')); - } else { - const id = snapshot.id; - if (id) { - json[get(this, 'primaryKey')] = id; - } + const id = snapshot.id; + if (id) { + json[get(this, 'primaryKey')] = id; } } @@ -1479,63 +1457,4 @@ const JSONSerializer = Serializer.extend({ } }); -if (isEnabled("ds-payload-type-hooks")) { - - JSONSerializer.reopen({ - - /** - @method modelNameFromPayloadType - @public - @param {String} type - @return {String} the model's modelName - */ - modelNameFromPayloadType(type) { - return normalizeModelName(type); - }, - - _hasCustomModelNameFromPayloadKey() { - return this.modelNameFromPayloadKey !== JSONSerializer.prototype.modelNameFromPayloadKey; - } - - }); - -} - -if (isEnabled("ds-serialize-id")) { - - JSONSerializer.reopen({ - - /** - serializeId can be used to customize how id is serialized - For example, your server may expect integer datatype of id - - By default the snapshot's id (String) is set on the json hash via json[primaryKey] = snapshot.id. - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - serializeId(snapshot, json, primaryKey) { - var id = snapshot.id; - json[primaryKey] = parseInt(id, 10); - } - }); - ``` - - @method serializeId - @public - @param {DS.Snapshot} snapshot - @param {Object} json - @param {String} primaryKey - */ - serializeId(snapshot, json, primaryKey) { - let id = snapshot.id; - - if (id) { - json[primaryKey] = id; - } - } - }); -} - export default JSONSerializer; diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 3480b3f9bab..97e1085808e 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -14,8 +14,7 @@ import JSONSerializer from "../serializers/json"; import { coerceId, modelHasAttributeOrRelationshipNamedType, - normalizeModelName, - isEnabled + normalizeModelName } from '../-private'; /** @@ -201,22 +200,7 @@ const RESTSerializer = JSONSerializer.extend({ if (!primaryHasTypeAttribute && hash.type) { // Support polymorphic records in async relationships - let modelName; - if (isEnabled("ds-payload-type-hooks")) { - modelName = this.modelNameFromPayloadType(hash.type); - let deprecatedModelNameLookup = this.modelNameFromPayloadKey(hash.type); - - if (modelName !== deprecatedModelNameLookup && !this._hasCustomModelNameFromPayloadType() && this._hasCustomModelNameFromPayloadKey()) { - deprecate("You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This is has been deprecated in favor of modelNameFromPayloadType", false, { - id: 'ds.rest-serializer.deprecated-model-name-for-polymorphic-type', - until: '3.0.0' - }); - - modelName = deprecatedModelNameLookup; - } - } else { - modelName = this.modelNameFromPayloadKey(hash.type); - } + let modelName = this.modelNameFromPayloadKey(hash.type); if (store._hasModelFor(modelName)) { serializer = store.serializerFor(modelName); @@ -429,11 +413,7 @@ const RESTSerializer = JSONSerializer.extend({ }); } - if (isEnabled('ds-pushpayload-return')) { - return store.push(documentHash); - } else { - store.push(documentHash); - } + store.push(documentHash); }, /** @@ -755,11 +735,7 @@ const RESTSerializer = JSONSerializer.extend({ if (isNone(belongsTo)) { json[typeKey] = null; } else { - if (isEnabled("ds-payload-type-hooks")) { - json[typeKey] = this.payloadTypeFromModelName(belongsTo.modelName); - } else { - json[typeKey] = camelize(belongsTo.modelName); - } + json[typeKey] = camelize(belongsTo.modelName); } }, @@ -797,165 +773,17 @@ const RESTSerializer = JSONSerializer.extend({ let typeProperty = this.keyForPolymorphicType(key, relationshipType, 'deserialize'); if (isPolymorphic && resourceHash[typeProperty] !== undefined && typeof relationshipHash !== 'object') { - - if (isEnabled("ds-payload-type-hooks")) { - - let payloadType = resourceHash[typeProperty]; - let type = this.modelNameFromPayloadType(payloadType); - let deprecatedTypeLookup = this.modelNameFromPayloadKey(payloadType); - - if (payloadType !== deprecatedTypeLookup && !this._hasCustomModelNameFromPayloadType() && this._hasCustomModelNameFromPayloadKey()) { - deprecate("You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This has been deprecated in favor of modelNameFromPayloadType", false, { - id: 'ds.rest-serializer.deprecated-model-name-for-polymorphic-type', - until: '3.0.0' - }); - - type = deprecatedTypeLookup; - } - - return { - id: relationshipHash, - type: type - }; - - } else { - - let type = this.modelNameFromPayloadKey(resourceHash[typeProperty]); - return { - id: relationshipHash, - type: type - }; - - } + let type = this.modelNameFromPayloadKey(resourceHash[typeProperty]); + return { + id: relationshipHash, + type: type + }; } return this._super(...arguments); } }); - -if (isEnabled("ds-payload-type-hooks")) { - - RESTSerializer.reopen({ - - /** - `modelNameFromPayloadType` can be used to change the mapping for a DS model - name, taken from the value in the payload. - - Say your API namespaces the type of a model and returns the following - payload for the `post` model, which has a polymorphic `user` relationship: - - ```javascript - // GET /api/posts/1 - { - "post": { - "id": 1, - "user": 1, - "userType: "api::v1::administrator" - } - } - ``` - - By overwriting `modelNameFromPayloadType` you can specify that the - `administrator` model should be used: - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.RESTSerializer.extend({ - modelNameFromPayloadType(payloadType) { - return payloadType.replace('api::v1::', ''); - } - }); - ``` - - By default the modelName for a model is its name in dasherized form. - Usually, Ember Data can use the correct inflection to do this for you. Most - of the time, you won't need to override `modelNameFromPayloadType` for this - purpose. - - Also take a look at - [payloadTypeFromModelName](#method_payloadTypeFromModelName) to customize - how the type of a record should be serialized. - - @method modelNameFromPayloadType - @public - @param {String} payloadType type from payload - @return {String} modelName - */ - modelNameFromPayloadType(payloadType) { - return singularize(normalizeModelName(payloadType)); - }, - - /** - `payloadTypeFromModelName` can be used to change the mapping for the type in - the payload, taken from the model name. - - Say your API namespaces the type of a model and expects the following - payload when you update the `post` model, which has a polymorphic `user` - relationship: - - ```javascript - // POST /api/posts/1 - { - "post": { - "id": 1, - "user": 1, - "userType": "api::v1::administrator" - } - } - ``` - - By overwriting `payloadTypeFromModelName` you can specify that the - namespaces model name for the `administrator` should be used: - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.RESTSerializer.extend({ - payloadTypeFromModelName(modelName) { - return 'api::v1::' + modelName; - } - }); - ``` - - By default the payload type is the camelized model name. Usually, Ember - Data can use the correct inflection to do this for you. Most of the time, - you won't need to override `payloadTypeFromModelName` for this purpose. - - Also take a look at - [modelNameFromPayloadType](#method_modelNameFromPayloadType) to customize - how the model name from should be mapped from the payload. - - @method payloadTypeFromModelName - @public - @param {String} modelName modelName from the record - @return {String} payloadType - */ - payloadTypeFromModelName(modelName) { - return camelize(modelName); - }, - - _hasCustomModelNameFromPayloadKey() { - return this.modelNameFromPayloadKey !== RESTSerializer.prototype.modelNameFromPayloadKey; - }, - - _hasCustomModelNameFromPayloadType() { - return this.modelNameFromPayloadType !== RESTSerializer.prototype.modelNameFromPayloadType; - }, - - _hasCustomPayloadTypeFromModelName() { - return this.payloadTypeFromModelName !== RESTSerializer.prototype.payloadTypeFromModelName; - }, - - _hasCustomPayloadKeyFromModelName() { - return this.payloadKeyFromModelName !== RESTSerializer.prototype.payloadKeyFromModelName; - } - - }); - -} - if (DEBUG) { RESTSerializer.reopen({ warnMessageNoModelForKey(prop, typeKey) { diff --git a/config/features.json b/config/features.json index e7bcedaf466..2c63c085104 100644 --- a/config/features.json +++ b/config/features.json @@ -1,9 +1,2 @@ { - "ds-improved-ajax": null, - "ds-pushpayload-return": null, - "ds-overhaul-references": null, - "ds-payload-type-hooks": null, - "ds-rollback-attribute": null, - "ds-serialize-id": null, - "ds-deprecate-store-serialize": true } From d29551bd74a5272782c12c9b10865bc9b2126ca4 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Mon, 26 Mar 2018 15:36:43 +0200 Subject: [PATCH 2158/2527] Remove jQuery usage from tests (#5375) Working towards #5320 --- .../integration/adapter/rest-adapter-test.js | 152 ++++++------------ 1 file changed, 45 insertions(+), 107 deletions(-) diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 90ceb6c460b..3c32202dd03 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1,7 +1,6 @@ import { underscore } from '@ember/string'; import { copy } from '@ember/object/internals'; import RSVP, { resolve, reject } from 'rsvp'; -import $ from 'jquery'; import { run } from '@ember/runloop'; import { get } from '@ember/object'; import setupStore from 'dummy/tests/helpers/store'; @@ -17,7 +16,6 @@ import { isEnabled } from 'ember-data/-private'; let env, store, adapter, Post, Comment, SuperUser; let passedUrl, passedVerb, passedHash; -let originalAjax = $.ajax; let server; module("integration/adapter/rest_adapter - REST Adapter", { @@ -39,14 +37,13 @@ module("integration/adapter/rest_adapter - REST Adapter", { adapter: DS.RESTAdapter }); + server = new Pretender(); store = env.store; adapter = env.adapter; passedUrl = passedVerb = passedHash = null; }, afterEach() { - $.ajax = originalAjax; - if (server) { server.shutdown(); server = null; @@ -74,6 +71,17 @@ function ajaxResponse(value) { } } +function ajaxError(responseText, status = 400, headers = '') { + adapter._ajaxRequest = function(hash) { + let jqXHR = { + status, + responseText, + getAllResponseHeaders() { return headers; } + }; + hash.error(jqXHR, responseText); + }; +} + test("findRecord - basic payload", function(assert) { ajaxResponse({ posts: [{ id: 1, name: "Rails is omakase" }] }); @@ -2231,10 +2239,7 @@ test('groupRecordsForFindMany groups calls for small ids', function(assert) { test("calls adapter.handleResponse with the jqXHR and json", function(assert) { assert.expect(2); - let jqXHR = { - status: 200, - getAllResponseHeaders() { return ''; } - }; + let data = { post: { id: "1", @@ -2242,9 +2247,9 @@ test("calls adapter.handleResponse with the jqXHR and json", function(assert) { } }; - $.ajax = function(hash) { - hash.success(data, 'ok', jqXHR); - }; + server.get('/posts/1', function() { + return [200, { "Content-Type": "application/json" }, JSON.stringify(data)]; + }); adapter.handleResponse = function(status, headers, json) { assert.deepEqual(status, 200); @@ -2252,29 +2257,26 @@ test("calls adapter.handleResponse with the jqXHR and json", function(assert) { return json; }; - run(() => store.findRecord('post', '1')); + return run(() => store.findRecord('post', '1')); }); test('calls handleResponse with jqXHR, jqXHR.responseText, and requestData', function(assert) { assert.expect(4); - let jqXHR = { - status: 400, - responseText: 'Nope lol', - getAllResponseHeaders() { return ''; } - }; + + let responseText = 'Nope lol'; let expectedRequestData = { method: "GET", url: "/posts/1" }; - $.ajax = function(hash) { - hash.error(jqXHR, jqXHR.responseText, 'Bad Request'); - }; + server.get('/posts/1', function() { + return [400, {}, responseText]; + }); adapter.handleResponse = function(status, headers, json, requestData) { assert.deepEqual(status, 400); - assert.deepEqual(json, jqXHR.responseText); + assert.deepEqual(json, responseText); assert.deepEqual(requestData, expectedRequestData); return new DS.AdapterError('nope!'); }; @@ -2286,16 +2288,14 @@ test('calls handleResponse with jqXHR, jqXHR.responseText, and requestData', fun test("rejects promise if DS.AdapterError is returned from adapter.handleResponse", function(assert) { assert.expect(3); - let jqXHR = { - getAllResponseHeaders() { return ''; } - }; + let data = { something: 'is invalid' }; - $.ajax = function(hash) { - hash.success(data, 'ok', jqXHR); - }; + server.get('/posts/1', function() { + return [200, { "Content-Type": "application/json" }, JSON.stringify(data)]; + }); adapter.handleResponse = function(status, headers, json) { assert.ok(true, 'handleResponse should be called'); @@ -2312,14 +2312,10 @@ test("rejects promise if DS.AdapterError is returned from adapter.handleResponse test("gracefully handles exceptions in handleResponse", function(assert) { assert.expect(1); - let jqXHR = { - status: 200, - getAllResponseHeaders() { return ''; } - }; - $.ajax = function(hash) { - setTimeout(function() { hash.success({}, 'ok', jqXHR); }, 1) - }; + server.post('/posts/1', function() { + return [200, { "Content-Type": "application/json" }, "ok"]; + }); adapter.handleResponse = function(status, headers, json) { throw new Error('Unexpected error'); @@ -2334,14 +2330,10 @@ test("gracefully handles exceptions in handleResponse", function(assert) { test("gracefully handles exceptions in handleResponse where the ajax request errors", function(assert) { assert.expect(1); - let jqXHR = { - status: 500, - getAllResponseHeaders() { return ''; } - }; - $.ajax = function(hash) { - setTimeout(() => hash.error({}, 'Internal Server Error', jqXHR) , 1); - }; + server.get('/posts/1', function() { + return [500, { "Content-Type": "application/json" }, "Internal Server Error"]; + }); adapter.handleResponse = function(status, headers, json) { throw new Error('Unexpected error'); @@ -2357,15 +2349,9 @@ test("gracefully handles exceptions in handleResponse where the ajax request err test('treats status code 0 as an abort', function(assert) { assert.expect(1); - let jqXHR = { - status: 0, - getAllResponseHeaders() { return ''; } - }; - - $.ajax = function(hash) { - hash.error(jqXHR, 'error'); + adapter._ajaxRequest = function(hash) { + hash.error({ status: 0, getAllResponseHeaders() { return ''; } }); }; - adapter.handleResponse = function(status, headers, payload) { assert.ok(false); }; @@ -2387,7 +2373,7 @@ test('on error appends errorThrown for sanity', function(assert) { let errorThrown = new Error('nope!'); - $.ajax = function(hash) { + adapter._ajaxRequest = function(hash) { hash.error(jqXHR, jqXHR.responseText, errorThrown); }; @@ -2406,15 +2392,7 @@ test('on error appends errorThrown for sanity', function(assert) { test("rejects promise with a specialized subclass of DS.AdapterError if ajax responds with http error codes", function(assert) { assert.expect(10); - let jqXHR = { - getAllResponseHeaders() { return ''; } - }; - let originalAjax = $.ajax; - - $.ajax = function(hash) { - jqXHR.status = 401; - hash.error(jqXHR, 'error'); - }; + ajaxError('error', 401); run(() => { store.find('post', '1').catch(reason => { @@ -2423,10 +2401,7 @@ test("rejects promise with a specialized subclass of DS.AdapterError if ajax res }); }); - $.ajax = function(hash) { - jqXHR.status = 403; - hash.error(jqXHR, 'error'); - }; + ajaxError('error', 403); run(() => { store.find('post', '1').catch(reason => { @@ -2435,10 +2410,7 @@ test("rejects promise with a specialized subclass of DS.AdapterError if ajax res }); }); - $.ajax = function(hash) { - jqXHR.status = 404; - hash.error(jqXHR, 'error'); - }; + ajaxError('error', 404); run(() => { store.find('post', '1').catch(reason => { @@ -2447,10 +2419,7 @@ test("rejects promise with a specialized subclass of DS.AdapterError if ajax res }); }); - $.ajax = function(hash) { - jqXHR.status = 409; - hash.error(jqXHR, 'error'); - }; + ajaxError('error', 409); run(() => { store.find('post', '1').catch(reason => { @@ -2459,10 +2428,7 @@ test("rejects promise with a specialized subclass of DS.AdapterError if ajax res }); }); - $.ajax = function(hash) { - jqXHR.status = 500; - hash.error(jqXHR, 'error'); - }; + ajaxError('error', 500); run(() => { store.find('post', '1').catch(reason => { @@ -2471,8 +2437,6 @@ test("rejects promise with a specialized subclass of DS.AdapterError if ajax res }); }); - - $.ajax = originalAjax; }); test('on error wraps the error string in an DS.AdapterError object', function(assert) { @@ -2485,7 +2449,7 @@ test('on error wraps the error string in an DS.AdapterError object', function(as let errorThrown = 'nope!'; - $.ajax = function(hash) { + adapter._ajaxRequest = function(hash) { hash.error(jqXHR, 'error', errorThrown); }; @@ -2499,15 +2463,8 @@ test('on error wraps the error string in an DS.AdapterError object', function(as test('error handling includes a detailed message from the server', (assert) => { assert.expect(2); - let jqXHR = { - status: 500, - responseText: 'An error message, perhaps generated from a backend server!', - getAllResponseHeaders() { return 'Content-Type: text/plain'; } - }; - $.ajax = function(hash) { - hash.error(jqXHR, 'error'); - }; + ajaxError('An error message, perhaps generated from a backend server!', 500, 'Content-Type: text/plain'); run(() => { store.findRecord('post', '1').catch(err => { @@ -2515,21 +2472,12 @@ test('error handling includes a detailed message from the server', (assert) => { assert.ok(err, 'promise rejected'); }); }); - }); test('error handling with a very long HTML-formatted payload truncates the friendly message', (assert) => { assert.expect(2); - let jqXHR = { - status: 500, - responseText: new Array(100).join(""), - getAllResponseHeaders() { return 'Content-Type: text/html'; } - }; - - $.ajax = function(hash) { - hash.error(jqXHR, 'error'); - }; + ajaxError(new Array(100).join(""), 500, 'Content-Type: text/html'); run(() => { store.findRecord('post', '1').catch(err => { @@ -2602,8 +2550,6 @@ test("createRecord - sideloaded records are pushed to the store", function(asser }); testInDebug("warns when an empty response is returned, though a valid stringified JSON is expected", function(assert) { - let server = new Pretender(); - server.post('/posts', function() { return [201, { "Content-Type": "application/json" }, ""]; }); @@ -2635,13 +2581,7 @@ if (isEnabled('ds-improved-ajax')) { testInDebug("The RESTAdapter should use `ajaxOptions` with a deprecation message when it is overridden by the user.", function(assert) { assert.expect(2) - adapter._ajaxRequest = function(hash) { - let jqXHR = { - status: 200, - getAllResponseHeaders() { return ''; } - }; - hash.success({ posts: { id: 1, name: "Rails is omakase" } }, 'OK', jqXHR); - } + ajaxResponse({ posts: { id: 1, name: "Rails is omakase" } }); let oldAjaxOptions = adapter.ajaxOptions; adapter.ajaxOptions = function() { @@ -2655,8 +2595,6 @@ if (isEnabled('ds-improved-ajax')) { }); test("_requestToJQueryAjaxHash works correctly for GET requests - GH-4445", function(assert) { - server = new Pretender(); - server.get('/posts/1', function(request) { assert.equal(request.url, "/posts/1", "no query param is added to the GET request"); From f0cfde607bed5edf389764fb63d54b82e2ca90a3 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Mon, 26 Mar 2018 09:40:00 -0400 Subject: [PATCH 2159/2527] update states to trigger rollback. update tests. (#4676) --- addon/-private/system/model/states.js | 14 +++++ tests/unit/model/rollback-attributes-test.js | 66 +++++++++++++------- 2 files changed, 56 insertions(+), 24 deletions(-) diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index 66bbc1093eb..080941fd4b3 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -267,6 +267,7 @@ const DirtyState = { rolledBack(internalModel) { internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('rolledBack'); }, becameInvalid(internalModel) { @@ -301,6 +302,10 @@ const DirtyState = { internalModel.send('invokeLifecycleCallbacks', this.dirtyType); }, + rolledBack(internalModel) { + internalModel.triggerLater('rolledBack'); + }, + becameInvalid(internalModel) { internalModel.transitionTo('invalid'); internalModel.send('invokeLifecycleCallbacks'); @@ -399,10 +404,12 @@ const createdState = dirtyState({ createdState.invalid.rolledBack = function(internalModel) { internalModel.transitionTo('deleted.saved'); + internalModel.triggerLater('rolledBack'); }; createdState.uncommitted.rolledBack = function(internalModel) { internalModel.transitionTo('deleted.saved'); + internalModel.triggerLater('rolledBack'); }; const updatedState = dirtyState({ @@ -447,6 +454,12 @@ updatedState.uncommitted.deleteRecord = function(internalModel) { internalModel.transitionTo('deleted.uncommitted'); }; +updatedState.invalid.rolledBack = function(internalModel) { + internalModel.clearErrorMessages(); + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('rolledBack'); +}; + const RootState = { // FLAGS isEmpty: false, @@ -636,6 +649,7 @@ const RootState = { rolledBack(internalModel) { internalModel.transitionTo('loaded.saved'); internalModel.triggerLater('ready'); + internalModel.triggerLater('rolledBack'); } }, diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index 4681dac1cb7..27bb8bed3ae 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -15,7 +15,11 @@ module('unit/model/rollbackAttributes - model.rollbackAttributes()', { beforeEach() { Person = DS.Model.extend({ firstName: DS.attr(), - lastName: DS.attr() + lastName: DS.attr(), + rolledBackCount: 0, + rolledBack() { + this.incrementProperty('rolledBackCount'); + } }); Person.reopenClass({ toString() { return 'Person'; } }); @@ -42,11 +46,13 @@ test('changes to attributes can be rolled back', function(assert) { }); assert.equal(person.get('firstName'), "Thomas"); + assert.equal(person.get('rolledBackCount'), 0); run(() => person.rollbackAttributes()); assert.equal(person.get('firstName'), "Tom"); assert.equal(person.get('hasDirtyAttributes'), false); + assert.equal(person.get('rolledBackCount'), 1); }); test('changes to unassigned attributes can be rolled back', function(assert) { @@ -67,11 +73,13 @@ test('changes to unassigned attributes can be rolled back', function(assert) { }); assert.equal(person.get('firstName'), "Thomas"); + assert.equal(person.get('rolledBackCount'), 0); run(() => person.rollbackAttributes()); assert.strictEqual(person.get('firstName'), undefined); assert.equal(person.get('hasDirtyAttributes'), false); + assert.equal(person.get('rolledBackCount'), 1); }); test('changes to attributes made after a record is in-flight only rolls back the local changes', function(assert) { @@ -106,6 +114,7 @@ test('changes to attributes made after a record is in-flight only rolls back the person.set('lastName', "Dolly"); assert.equal(person.get('lastName'), "Dolly"); + assert.equal(person.get('rolledBackCount'), 0); person.rollbackAttributes(); @@ -114,6 +123,7 @@ test('changes to attributes made after a record is in-flight only rolls back the assert.equal(person.get('isSaving'), true); return saving.then(() => { + assert.equal(person.get('rolledBackCount'), 1); assert.equal(person.get('hasDirtyAttributes'), false, 'The person is now clean'); }); }); @@ -148,18 +158,22 @@ test("a record's changes can be made if it fails to save", function(assert) { person.save().then(null, function() { assert.equal(person.get('isError'), true); assert.deepEqual(person.changedAttributes().firstName, ["Tom", "Thomas"]); + assert.equal(person.get('rolledBackCount'), 0); - person.rollbackAttributes(); + run(function() { + person.rollbackAttributes(); + }); assert.equal(person.get('firstName'), "Tom"); assert.equal(person.get('isError'), false); assert.equal(Object.keys(person.changedAttributes()).length, 0); + assert.equal(person.get('rolledBackCount'), 1); }); }); }); test(`a deleted record's attributes can be rollbacked if it fails to save, record arrays are updated accordingly`, function(assert) { - assert.expect(8); + assert.expect(10); env.adapter.deleteRecord = function(store, type, snapshot) { return reject(); }; @@ -190,10 +204,14 @@ test(`a deleted record's attributes can be rollbacked if it fails to save, recor return person.save().catch(() => { assert.equal(person.get('isError'), true); assert.equal(person.get('isDeleted'), true); + assert.equal(person.get('rolledBackCount'), 0); + run(() => person.rollbackAttributes()); + assert.equal(person.get('isDeleted'), false); assert.equal(person.get('isError'), false); assert.equal(person.get('hasDirtyAttributes'), false, 'must be not dirty'); + assert.equal(person.get('rolledBackCount'), 1); }).then(() => { assert.equal(people.get('length'), 1, 'the underlying record array is updated accordingly in an asynchronous way'); }); @@ -205,12 +223,14 @@ test(`new record's attributes can be rollbacked`, function(assert) { assert.equal(person.get('isNew'), true, 'must be new'); assert.equal(person.get('hasDirtyAttributes'), true, 'must be dirty'); + assert.equal(person.get('rolledBackCount'), 0); run(person, 'rollbackAttributes'); assert.equal(person.get('isNew'), false, 'must not be new'); assert.equal(person.get('hasDirtyAttributes'), false, 'must not be dirty'); assert.equal(person.get('isDeleted'), true, 'must be deleted'); + assert.equal(person.get('rolledBackCount'), 1); }); test(`invalid new record's attributes can be rollbacked`, function(assert) { @@ -247,33 +267,25 @@ test(`invalid new record's attributes can be rollbacked`, function(assert) { return person.save().catch(reason => { assert.equal(error, reason); assert.equal(person.get('isValid'), false); - person.rollbackAttributes(); + + run(() => person.rollbackAttributes()); assert.equal(person.get('isNew'), false, 'must not be new'); assert.equal(person.get('hasDirtyAttributes'), false, 'must not be dirty'); assert.equal(person.get('isDeleted'), true, 'must be deleted'); + assert.equal(person.get('rolledBackCount'), 1); }); }); }); test(`invalid record's attributes can be rollbacked after multiple failed calls - #3677`, function(assert) { - let adapter; - if (isEnabled('ds-improved-ajax')) { - adapter = DS.RESTAdapter.extend({ - _makeRequest() { - let error = new DS.InvalidError(); - return reject(error); - } - }); - } else { - adapter = DS.RESTAdapter.extend({ - ajax(url, type, hash) { - let error = new DS.InvalidError(); - return reject(error); - } - }); - } + let adapter = DS.RESTAdapter.extend({ + ajax(url, type, hash) { + let error = new DS.InvalidError(); + return reject(error); + } + }); env = setupStore({ person: Person, adapter: adapter }); @@ -301,10 +313,11 @@ test(`invalid record's attributes can be rollbacked after multiple failed calls return person.save(); }).catch(() => { - person.rollbackAttributes(); + run(() => person.rollbackAttributes()); assert.equal(person.get('hasDirtyAttributes'), false, 'has no dirty attributes'); assert.equal(person.get('firstName'), 'original name', 'after rollbackAttributes() firstName has the original value'); + assert.equal(person.get('rolledBackCount'), 1); }); }); }); @@ -337,9 +350,13 @@ test(`deleted record's attributes can be rollbacked`, function(assert) { }); test("invalid record's attributes can be rollbacked", function(assert) { - assert.expect(11); + assert.expect(12); const Dog = DS.Model.extend({ - name: DS.attr() + name: DS.attr(), + rolledBackCount: 0, + rolledBack() { + this.incrementProperty('rolledBackCount'); + } }); let error = new DS.InvalidError([ @@ -398,12 +415,13 @@ test("invalid record's attributes can be rollbacked", function(assert) { return dog.save().catch(reason => { assert.equal(reason, error); - dog.rollbackAttributes(); + run(() => { dog.rollbackAttributes() }); assert.equal(dog.get('hasDirtyAttributes'), false, 'must not be dirty'); assert.equal(dog.get('name'), 'Pluto'); assert.notOk(dog.get('errors.name')); assert.ok(dog.get('isValid')); + assert.equal(dog.get('rolledBackCount'), 1); }); }); }); From d2110713004d2fd01a87c8e68d863feec8fb7651 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 26 Mar 2018 15:25:41 -0400 Subject: [PATCH 2160/2527] Update changelog for the Ember Data 3.1.0 release --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffc1f0f49e0..dfc44dd1142 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,33 @@ ### Master +### Release 3.1.0 (March 26, 2018) +- [#5255](https://github.com/emberjs/data/pull/5255) [BUGFIX beta] Use native Map if present. (#5255) +- [#5367](https://github.com/emberjs/data/pull/5367) Update ember twiddle links to working versions (#5367) +- [#5370](https://github.com/emberjs/data/pull/5370) Fix failing test on master by adding an invalid inverse to trigger th… +- [#5372](https://github.com/emberjs/data/pull/5372) [BUGFIX beta] Use @ember/ordered-set to avoid deprecations. +- [#5376](https://github.com/emberjs/data/pull/5376) [bugfix beta] Fetch cancels unload +- [#5377](https://github.com/emberjs/data/pull/5377) invalidate link promise on inverse unload +- [#5341](https://github.com/emberjs/data/pull/5341) Avoid `isEmpty` for known object types. +- [#5230](https://github.com/emberjs/data/pull/5230) [BUGFIX] enable lazy-relationship payloads to work with polymorphic relationships +- [#5327](https://github.com/emberjs/data/pull/5327) [DOC] Fix Changelog release date for v2.11.0 +- [#5310](https://github.com/emberjs/data/pull/5310) Remove `s3-put` and `cached-npm` scripts. +- [#5273](https://github.com/emberjs/data/pull/5273) client-side-delete semantics `unloadRecord` +- [#5330](https://github.com/emberjs/data/pull/5330) [CHORE] updates to benchmark harness +- [#5322](https://github.com/emberjs/data/pull/5322) Clean up a bunch of invalid yuidoc blocks that were causing warnings … +- [#5318](https://github.com/emberjs/data/pull/5318) Use Ember.computed in the headers examples to avoid ember eslint warning +- [#5311](https://github.com/emberjs/data/pull/5311) Avoid bower usage in config/ember-try.js +- [#5321](https://github.com/emberjs/data/pull/5321) Update some dependencies to clean up some noise when running yarn ins… +- [#5317](https://github.com/emberjs/data/pull/5317) Dont serialize new belongsTo records (#5317) +- [#5323](https://github.com/emberjs/data/pull/5323) Stop using deprecated vendor-prefix hook to inject enableoptionalfeat… +- [#5326](https://github.com/emberjs/data/pull/5326) Remove usages of enumerable observers +- [#5329](https://github.com/emberjs/data/pull/5329) bump rsvp +- [#5332](https://github.com/emberjs/data/pull/5332) [BUGFIX beta] Fix development build relationship caching. +- [#5333](https://github.com/emberjs/data/pull/5333) [DEV-BUGFIX] Fix instrumentation when running in production (#5333) +- [#5339](https://github.com/emberjs/data/pull/5339) Prevent build issues when linking ember-source. +- [#5340](https://github.com/emberjs/data/pull/5340) [BUGFIX beta] Update DS.Errors#unknownProperty to return `undefined`. +- [#5342](https://github.com/emberjs/data/pull/5342) Refactor Travis setup to leverage stages... (#5342) + ### Release 3.0.2 (March 1, 2018) - [#5230](https://github.com/emberjs/data/pull/5230) [BUGFIX] enable lazy-relationship payloads to work with polymorphic relationships From d5a7f6e834de71481fe4be5e9e921d50408a83f2 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 26 Mar 2018 15:27:28 -0400 Subject: [PATCH 2161/2527] Bump canary version to 3.3.0-canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6a491560b51..efd54233c4b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "3.2.0-canary", + "version": "3.3.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From 768f272c768898f2af52b9dcd75294d3f2bc5f12 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Mon, 26 Mar 2018 15:42:18 -0400 Subject: [PATCH 2162/2527] The deploy stage appears to be running for prs. The travis docs seem to apply we should move the conditional to the stages list (#5393) --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b297c4ab255..1b6b7ead606 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,8 @@ stages: - test - additional tests - older version tests - - deploy + - name: deploy + if: type = push AND (branch IN (master, beta, release) OR tag IS present) jobs: fail_fast: true @@ -54,7 +55,6 @@ jobs: - env: EMBER_TRY_SCENARIO=ember-canary - stage: deploy - if: branch IN (master, beta, release) OR tag IS present env: NAME=publish # used only to make Travis UI show description install: yarn install script: From 27f9ccdf1bbbefc3d82a7d5c0814e8a01b7cf0fc Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Tue, 27 Mar 2018 09:00:36 -0400 Subject: [PATCH 2163/2527] [BUGFIX beta] Do not attempt to publish the globals build of ember data to s3 (#5394) --- config/s3ProjectConfig.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/s3ProjectConfig.js b/config/s3ProjectConfig.js index 7750e4bdac6..8a45d8e1177 100644 --- a/config/s3ProjectConfig.js +++ b/config/s3ProjectConfig.js @@ -1,9 +1,5 @@ function fileMap(revision,tag,date) { return { - 'globals/ember-data.js': fileObject('ember-data', '.js', 'text/javascript', revision, tag, date), - 'globals/ember-data.js.map': fileObject('ember-data.js', '.map', 'application/json', revision, tag, date), - 'globals/ember-data.min.js': fileObject('ember-data.min', '.js', 'text/javascript', revision, tag, date), - 'globals/ember-data.prod.js': fileObject('ember-data.prod', '.js', 'text/javascript', revision, tag, date), 'docs/data.json': fileObject('ember-data-docs', '.json', 'application/json', revision, tag, date) }; } From fe685f604c30e451f3a7d0d7b980ec64e0291560 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 27 Mar 2018 09:04:11 -0400 Subject: [PATCH 2164/2527] Update changelog for 3.1.1 release (cherry picked from commit 3b7f2af46b0e061706f32dd64f2d88cc6819360a) --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfc44dd1142..9f65519aff2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ### Master +### Release 3.1.1 (March 27, 2018) +- [#5383](https://github.com/emberjs/data/pull/5383) Remove '@ember/ordered-set' warning when building Ember Data + ### Release 3.1.0 (March 26, 2018) - [#5255](https://github.com/emberjs/data/pull/5255) [BUGFIX beta] Use native Map if present. (#5255) - [#5367](https://github.com/emberjs/data/pull/5367) Update ember twiddle links to working versions (#5367) From d475bc73068e116603650e6bc43dd44c80f94233 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 27 Mar 2018 10:51:15 -0400 Subject: [PATCH 2165/2527] Remove unneeded feature flagged tests --- .../adapter/build-url-mixin-test.js | 19 +- .../adapter/json-api-adapter-test.js | 27 +- .../integration/adapter/rest-adapter-test.js | 66 +---- .../integration/references/belongs-to-test.js | 45 ---- tests/integration/references/has-many-test.js | 158 ------------ .../serializers/json-api-serializer-test.js | 239 ------------------ .../serializers/json-serializer-test.js | 132 ---------- .../serializers/rest-serializer-test.js | 171 ------------- tests/integration/store-test.js | 13 +- tests/unit/adapters/rest-adapter/ajax-test.js | 37 +-- .../group-records-for-find-many-test.js | 61 ++--- tests/unit/model-test.js | 181 ------------- tests/unit/model/rollback-attributes-test.js | 78 ++---- tests/unit/store/push-test.js | 29 --- tests/unit/store/serialize-test.js | 39 ++- 15 files changed, 88 insertions(+), 1207 deletions(-) diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index b550bf85afe..59418aa40ac 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -4,7 +4,6 @@ import RSVP from 'rsvp'; import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; import { pluralize } from 'ember-inflector'; -import { isEnabled } from 'ember-data/-private'; import { module, test } from 'qunit'; @@ -44,19 +43,11 @@ module("integration/adapter/build-url-mixin - BuildURLMixin with RESTAdapter", { }); function ajaxResponse(value) { - if (isEnabled('ds-improved-ajax')) { - adapter._makeRequest = function(request) { - passedUrl = request.url; - - return run(RSVP, 'resolve', copy(value, true)); - }; - } else { - adapter.ajax = function(url, verb, hash) { - passedUrl = url; - - return run(RSVP, 'resolve', copy(value, true)); - }; - } + adapter.ajax = function(url, verb, hash) { + passedUrl = url; + + return run(RSVP, 'resolve', copy(value, true)); + }; } diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index a119c908116..6443d7d4910 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -6,7 +6,6 @@ import { module, test } from 'qunit'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import DS from 'ember-data'; -import { isEnabled } from 'ember-data/-private'; let env, store, adapter; let passedUrl, passedVerb, passedHash; @@ -90,27 +89,15 @@ function ajaxResponse(responses) { passedVerb = []; passedHash = []; - if (isEnabled('ds-improved-ajax')) { - adapter._makeRequest = function(request) { - index = counter++; + adapter.ajax = function(url, verb, hash) { + index = counter++; - passedUrl[index] = request.url; - passedVerb[index] = request.method; - passedHash[index] = request.data ? { data: request.data } : undefined; + passedUrl[index] = url; + passedVerb[index] = verb; + passedHash[index] = hash; - return run(RSVP, 'resolve', responses[index]); - }; - } else { - adapter.ajax = function(url, verb, hash) { - index = counter++; - - passedUrl[index] = url; - passedVerb[index] = verb; - passedHash[index] = hash; - - return run(RSVP, 'resolve', responses[index]); - }; - } + return run(RSVP, 'resolve', responses[index]); + }; } test('find a single record', function(assert) { diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 3c32202dd03..b266c96fe3b 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -12,7 +12,6 @@ import { module, test } from 'qunit'; import Pretender from "pretender"; import DS from 'ember-data'; -import { isEnabled } from 'ember-data/-private'; let env, store, adapter, Post, Comment, SuperUser; let passedUrl, passedVerb, passedHash; @@ -52,23 +51,13 @@ module("integration/adapter/rest_adapter - REST Adapter", { }); function ajaxResponse(value) { - if (isEnabled('ds-improved-ajax')) { - adapter._makeRequest = function(request) { - passedUrl = request.url; - passedVerb = request.method; - passedHash = request.data ? { data: request.data } : undefined; + adapter.ajax = function(url, verb, hash) { + passedUrl = url; + passedVerb = verb; + passedHash = hash; - return run(RSVP, 'resolve', copy(value, true)); - }; - } else { - adapter.ajax = function(url, verb, hash) { - passedUrl = url; - passedVerb = verb; - passedHash = hash; - - return run(RSVP, 'resolve', copy(value, true)); - }; - } + return run(RSVP, 'resolve', copy(value, true)); + }; } function ajaxError(responseText, status = 400, headers = '') { @@ -2562,46 +2551,3 @@ testInDebug("warns when an empty response is returned, though a valid stringifie assert.ok(/JSON/.test(reason.message)); }); }); - -if (isEnabled('ds-improved-ajax')) { - testInDebug("The RESTAdapter should use `ajax` with a deprecation message when it is overridden by the user.", function(assert) { - assert.expect(2) - - adapter.ajax = function(url, verb, hash) { - assert.ok(true, 'The ajax method should be called when it is overridden'); - return { posts: { id: 1, name: "Rails is omakase" } }; - }; - - assert.expectDeprecation(() => { - run(() => store.findRecord('post', 1)); - }, /RESTAdapter#ajax has been deprecated/) - }); - - - testInDebug("The RESTAdapter should use `ajaxOptions` with a deprecation message when it is overridden by the user.", function(assert) { - assert.expect(2) - - ajaxResponse({ posts: { id: 1, name: "Rails is omakase" } }); - - let oldAjaxOptions = adapter.ajaxOptions; - adapter.ajaxOptions = function() { - assert.ok(true, 'The ajaxOptions method should be called when it is overridden'); - return oldAjaxOptions.apply(this, arguments); - }; - - assert.expectDeprecation(() => { - run(() => store.findRecord('post', 1)); - }, /RESTAdapter#ajaxOptions has been deprecated/) - }); - - test("_requestToJQueryAjaxHash works correctly for GET requests - GH-4445", function(assert) { - server.get('/posts/1', function(request) { - assert.equal(request.url, "/posts/1", "no query param is added to the GET request"); - - return [201, { "Content-Type": "application/json" }, JSON.stringify({ post: { id: 1 } })]; - }); - - return run(() => store.findRecord('post', 1)); - }); - -} diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index 2bf955af3d6..47b7ebffa37 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -4,7 +4,6 @@ import { get } from '@ember/object'; import DS from 'ember-data'; import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import { isEnabled } from 'ember-data/-private'; import { module, test } from 'qunit'; var env, Family; @@ -240,50 +239,6 @@ testInDebug("push(record)", function(assert) { }); }); -if (isEnabled('ds-overhaul-references')) { - testInDebug("push(record) logs a deprecation warning", function(assert) { - var done = assert.async(); - - var person, family; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1, - relationships: { - family: { - data: { type: 'family', id: 1 } - } - } - } - }); - family = env.store.push({ - data: { - type: 'family', - id: 1, - attributes: { - name: "Coreleone" - } - } - }); - }); - - var familyReference = person.belongsTo('family'); - - assert.expectDeprecation(() => { - run(function() { - familyReference.push(family).then(function(record) { - assert.ok(Family.detectInstance(record), "push resolves with the referenced record"); - assert.equal(get(record, 'name'), "Coreleone", "name is set"); - assert.equal(record, family); - - done(); - }); - }); - }, "BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead."); - }); -} - test("push(promise)", function(assert) { var done = assert.async(); diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 3deab094433..030ca234fde 100755 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -3,7 +3,6 @@ import { run } from '@ember/runloop'; import { get } from '@ember/object'; import DS from 'ember-data'; import setupStore from 'dummy/tests/helpers/store'; -import { isEnabled } from 'ember-data/-private'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; @@ -203,50 +202,6 @@ testInDebug("push(array)", function(assert) { }); }); -if (isEnabled('ds-overhaul-references')) { - testInDebug("push(array) logs a deprecation warning", function(assert) { - var done = assert.async(); - - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } - } - } - }); - }); - - var personsReference = family.hasMany('persons'); - - assert.expectDeprecation(() => { - run(function() { - var data = [ - { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, - { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } - ]; - - personsReference.push(data).then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); - assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito"); - assert.equal(records.objectAt(1).get('name'), "Michael"); - - done(); - }); - }); - }, "HasManyReference#push(array) is deprecated. Push a JSON-API document instead."); - }); -} - testInDebug("push(array) works with polymorphic type", function(assert) { var done = assert.async(); @@ -345,110 +300,6 @@ testInDebug("push(object) supports legacy, non-JSON-API-conform payload", functi }); }); -if (isEnabled('ds-overhaul-references')) { - test("push(object) supports JSON-API payload", function(assert) { - var done = assert.async(); - - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1, - relationships: { - persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } - } - } - }); - }); - - var personsReference = family.hasMany('persons'); - - run(function() { - var payload = { - data: [ - { type: 'person', id: 1, attributes: { name: "Vito" } }, - { type: 'person', id: 2, attributes: { name: "Michael" } } - ] - }; - - personsReference.push(payload).then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); - assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito"); - assert.equal(records.objectAt(1).get('name'), "Michael"); - - done(); - }); - }); - }); - - test("push(object) works with polymorphic type", function(assert) { - var done = assert.async(); - - env.registry.register('model:mafia-boss', Person.extend()); - - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1 - } - }); - }); - - var personsReference = family.hasMany('persons'); - - run(() => { - var payload = { - data: [ - { type: 'mafia-boss', id: 1, attributes: { name: "Vito" } } - ] - }; - - personsReference.push(payload).then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); - assert.equal(get(records, 'length'), 1); - assert.equal(records.objectAt(0).get('name'), "Vito"); - - done(); - }); - }); - }); - - test("push(object) asserts polymorphic type", function(assert) { - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1 - } - }); - }); - - var personsReference = family.hasMany('persons'); - - assert.expectAssertion(() => { - run(() => { - var payload = { - data: [ - { type: 'family', id: 1 } - ] - }; - - personsReference.push(payload); - }); - }, "You cannot add a record of modelClass 'family' to the 'family.persons' relationship (only 'person' allowed)"); - }); -} - test("push(promise)", function(assert) { var done = assert.async(); @@ -484,15 +335,6 @@ test("push(promise)", function(assert) { ] }; - if (isEnabled('ds-overhaul-references')) { - payload = { - data: [ - { type: 'person', id: 1, attributes: { name: "Vito" } }, - { type: 'person', id: 2, attributes: { name: "Michael" } } - ] - }; - } - deferred.resolve(payload); }); diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index b9d42ecd544..174de5a8bfa 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -5,8 +5,6 @@ import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; -import { isEnabled } from 'ember-data/-private'; - import DS from 'ember-data'; var env, store, serializer; @@ -467,240 +465,3 @@ testInDebug('Asserts when normalized relationship key is not found in payload bu env.store.serializerFor("user").normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); }, /Your payload for 'user' contains 'reportsTo', but your serializer is setup to look for 'reports-to'/); }); - -if (isEnabled("ds-payload-type-hooks")) { - test('mapping of payload type can be customized via modelNameFromPayloadType', function(assert) { - env.registry.register('serializer:user', DS.JSONAPISerializer.extend({ - modelNameFromPayloadType: function(payloadType) { - return payloadType.replace("api::v1::", ""); - } - })); - - let jsonHash = { - data: { - id: "1", - type: "api::v1::user", - relationships: { - company: { - data: { - id: "1", - type: "api::v1::company" - } - }, - handles: { - data: [{ - id: "1", - type: "api::v1::handle" - }] - } - } - } - }; - - assert.expectNoDeprecation(); - - let user = env.store.serializerFor('user').normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); - - assert.deepEqual(user, { - data: { - id: "1", - type: "user", - attributes: {}, - relationships: { - company: { - data: { - id: "1", - type: "company" - } - }, - handles: { - data: [{ - id: "1", - type: "handle" - }] - } - } - } - }); - }); - - testInDebug('DEPRECATED - mapping of payload type can be customized via modelNameFromPayloadKey', function(assert) { - env.registry.register('serializer:user', DS.JSONAPISerializer.extend({ - modelNameFromPayloadKey: function(payloadType) { - return payloadType.replace("api::v1::", ""); - } - })); - - let jsonHash = { - data: { - id: "1", - type: "api::v1::user", - relationships: { - company: { - data: { - id: "1", - type: "api::v1::company" - } - }, - handles: { - data: [{ - id: "1", - type: "api::v1::handle" - }] - } - } - } - }; - - assert.expectDeprecation(() => { - let user = env.store.serializerFor('user').normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); - - assert.deepEqual(user, { - data: { - id: "1", - type: "user", - attributes: {}, - relationships: { - company: { - data: { - id: "1", - type: "company" - } - }, - handles: { - data: [{ - id: "1", - type: "handle" - }] - } - } - } - }); - }, "You are using modelNameFromPayloadKey to normalize the type for a relationship. This has been deprecated in favor of modelNameFromPayloadType"); - }); - - - test('mapping of model name can be customized via payloadTypeFromModelName', function(assert) { - env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ - attrs: { - handles: { serialize: true }, - firstName: { serialize: false }, - lastName: { serialize: false }, - title: { serialize: false }, - reportsTo: { serialize: false } - }, - payloadTypeFromModelName: function(modelName) { - return `api::v1::${modelName}`; - } - })); - - let user; - - run(function() { - let company = env.store.push({ - data: { - type: 'company', - id: '1' - } - }); - - let handle = env.store.push({ - data: { - type: 'handle', - id: '1' - } - }); - - user = env.store.createRecord('user', { - company, - handles: [handle] - }); - }); - - assert.expectNoDeprecation(); - - var payload = env.store.serializerFor("user").serialize(user._createSnapshot()); - - assert.deepEqual(payload, { - data: { - type: 'api::v1::user', - relationships: { - company: { - data: { - id: '1', - type: 'api::v1::company' - } - }, - handles: { - data: [{ - id: '1', - type: 'api::v1::handle' - }] - } - } - } - }); - }); - - testInDebug('DEPRECATED - mapping of model name can be customized via payloadKeyFromModelName', function(assert) { - env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ - attrs: { - handles: { serialize: true }, - firstName: { serialize: false }, - lastName: { serialize: false }, - title: { serialize: false }, - reportsTo: { serialize: false } - }, - payloadKeyFromModelName: function(modelName) { - return `api::v1::${modelName}`; - } - })); - - let user; - - run(function() { - let company = env.store.push({ - data: { - type: 'company', - id: '1' - } - }); - - let handle = env.store.push({ - data: { - type: 'handle', - id: '1' - } - }); - - user = env.store.createRecord('user', { - company, - handles: [handle] - }); - }); - - assert.expectDeprecation(() => { - var payload = env.store.serializerFor("user").serialize(user._createSnapshot()); - - assert.deepEqual(payload, { - data: { - type: 'api::v1::user', - relationships: { - company: { - data: { - id: '1', - type: 'api::v1::company' - } - }, - handles: { - data: [{ - id: '1', - type: 'api::v1::handle' - }] - } - } - } - }); - }, "You used payloadKeyFromModelName to customize how a type is serialized. Use payloadTypeFromModelName instead."); - }); -} diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 30c01e06f2f..9359670abe2 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -1,7 +1,6 @@ import { underscore } from '@ember/string'; import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import { isEnabled } from 'ember-data/-private'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; @@ -79,64 +78,6 @@ test("serialize includes id when includeId is true", function(assert) { }); }); -if (isEnabled("ds-serialize-id")) { - test("serializeId", function(assert) { - run(() => { - post = env.store.createRecord('post'); - post.set('id', 'test'); - }); - - let json = {}; - serializer.serializeId(post._createSnapshot(), json, 'id'); - - assert.deepEqual(json, { - id: 'test' - }); - }); - - test("modified serializeId is called from serialize", function(assert) { - env.registry.register('serializer:post', DS.JSONSerializer.extend({ - serializeId(snapshot, json, primaryKey) { - var id = snapshot.id; - json[primaryKey] = id.toUpperCase(); - } - })); - - run(function() { - post = env.store.createRecord('post', { title: 'Rails is omakase' }); - post.set('id', 'test'); - }); - var json = {}; - - json = env.store.serializerFor("post").serialize(post._createSnapshot(), { includeId: true }); - - assert.deepEqual(json, { - id: 'TEST', - title: 'Rails is omakase' - }); - }); - - test("serializeId respects `primaryKey` serializer property", function(assert) { - env.registry.register('serializer:post', DS.JSONSerializer.extend({ - primaryKey: '_ID_' - })); - - run(function() { - post = env.store.createRecord('post', { title: 'Rails is omakase' }); - post.set('id', 'test'); - }); - var json = {}; - - json = env.store.serializerFor("post").serialize(post._createSnapshot(), { includeId: true }); - - assert.deepEqual(json, { - _ID_: 'test', - title: 'Rails is omakase' - }); - }); - -} - test("serializeAttribute", function(assert) { run(function() { post = env.store.createRecord('post', { title: "Rails is omakase" }); @@ -1065,76 +1006,3 @@ test('Serializer should respect the attrs hash in links', function(assert) { assert.equal(post.data.relationships.comments.links.related, 'posts/1/comments'); }); -if (isEnabled("ds-payload-type-hooks")) { - - test("mapping of model name can be customized via modelNameFromPayloadType", function(assert) { - serializer.modelNameFromPayloadType = function(payloadType) { - return payloadType.replace("api::v1::", ""); - }; - - let jsonHash = { - id: '1', - post: { - id: '1', - type: "api::v1::post" - } - }; - - assert.expectNoDeprecation(); - - let normalized = serializer.normalizeSingleResponse(env.store, Favorite, jsonHash); - - assert.deepEqual(normalized, { - data: { - id: '1', - type: 'favorite', - attributes: {}, - relationships: { - post: { - data: { - id: '1', - type: 'post' - } - } - } - }, - included: [] - }); - }); - - testInDebug("DEPRECATED - mapping of model name can be customized via modelNameFromPayloadKey", function(assert) { - serializer.modelNameFromPayloadKey = function(payloadType) { - return payloadType.replace("api::v1::", ""); - }; - - let jsonHash = { - id: '1', - post: { - id: '1', - type: "api::v1::post" - } - }; - - assert.expectDeprecation(() => { - let normalized = serializer.normalizeSingleResponse(env.store, Favorite, jsonHash); - - assert.deepEqual(normalized, { - data: { - id: '1', - type: 'favorite', - attributes: {}, - relationships: { - post: { - data: { - id: '1', - type: 'post' - } - } - } - }, - included: [] - }); - }, "You used modelNameFromPayloadKey to customize how a type is normalized. Use modelNameFromPayloadType instead"); - }); - -} diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 88a98061251..63c9e2d212f 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -4,7 +4,6 @@ import { run, bind } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; -import { isEnabled } from 'ember-data/-private'; import DS from 'ember-data'; @@ -847,173 +846,3 @@ test('normalizes sideloaded single record so that it sideloads correctly - hasMa } }); }); - -if (isEnabled("ds-payload-type-hooks")) { - - test("mapping of payload type can be customized via modelNameFromPayloadType", function(assert) { - env.restSerializer.modelNameFromPayloadType = function(payloadType) { - return payloadType.replace("api::v1::", ""); - }; - - var jsonHash = { - doomsdayDevice: { - id: '1', - evilMinion: '1', - evilMinionType: "api::v1::evil-minion" - } - }; - - assert.expectNoDeprecation(); - - let normalized = env.restSerializer.normalizeResponse(env.store, DoomsdayDevice, jsonHash, '1', 'findRecord'); - - assert.deepEqual(normalized, { - data: { - id: '1', - type: 'doomsday-device', - attributes: {}, - relationships: { - evilMinion: { - data: { - id: '1', - type: 'evil-minion' - } - } - } - }, - included: [] - }); - }); - - test("payload key and payload type can be mapped", function(assert) { - env.restSerializer.modelNameFromPayloadKey = function(payloadKey) { - return 'doomsday-device'; - }; - - env.restSerializer.modelNameFromPayloadType = function(payloadType) { - return payloadType.replace("api::v1::", ""); - }; - - var jsonHash = { - "api/models/doomsday-device": { - id: '1', - evilMinion: '1', - evilMinionType: "api::v1::evil-minion" - } - }; - - assert.expectNoDeprecation(); - - let normalized = env.restSerializer.normalizeResponse(env.store, DoomsdayDevice, jsonHash, '1', 'findRecord'); - - assert.deepEqual(normalized, { - data: { - id: '1', - type: 'doomsday-device', - attributes: {}, - relationships: { - evilMinion: { - data: { - id: '1', - type: 'evil-minion' - } - } - } - }, - included: [] - }); - }); - - test("only overwriting modelNameFromPayloadKey works", function(assert) { - env.restSerializer.modelNameFromPayloadKey = function(payloadKey) { - return payloadKey.replace("api/models/", ""); - }; - - var jsonHash = { - "api/models/doomsday-device": { - id: '1', - evilMinion: '1', - evilMinionType: "evil-minion" - } - }; - - assert.expectNoDeprecation(); - - let normalized = env.restSerializer.normalizeResponse(env.store, DoomsdayDevice, jsonHash, '1', 'findRecord'); - - assert.deepEqual(normalized, { - data: { - id: '1', - type: 'doomsday-device', - attributes: {}, - relationships: { - evilMinion: { - data: { - id: '1', - type: 'evil-minion' - } - } - } - }, - included: [] - }); - }); - - testInDebug("DEPRECATED - mapping of payload type can be customized via modelNameFromPayloadKey", function(assert) { - env.restSerializer.modelNameFromPayloadKey = function(payloadType) { - return payloadType.replace("api::v1::", ""); - }; - - var jsonHash = { - doomsdayDevice: { - id: '1', - evilMinion: '1', - evilMinionType: "api::v1::evil-minion" - } - }; - - assert.expectDeprecation(() => { - let normalized = env.restSerializer.normalizeResponse(env.store, DoomsdayDevice, jsonHash, '1', 'findRecord'); - - assert.deepEqual(normalized, { - data: { - id: '1', - type: 'doomsday-device', - attributes: {}, - relationships: { - evilMinion: { - data: { - id: '1', - type: 'evil-minion' - } - } - } - }, - included: [] - }); - }, "You are using modelNameFromPayloadKey to normalize the type for a polymorphic relationship. This has been deprecated in favor of modelNameFromPayloadType"); - }); - - test("mapping of model name can be customized via payloadTypeFromModelName", function(assert) { - env.restSerializer.payloadTypeFromModelName = function(modelName) { - return `api::v1::${modelName}`; - }; - - let tom, ray; - run(function() { - tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); - ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: "DeathRay" }); - }); - - assert.expectNoDeprecation(); - - let json = env.restSerializer.serialize(ray._createSnapshot()); - - assert.deepEqual(json, { - name: "DeathRay", - evilMinion: "124", - evilMinionType: "api::v1::yellow-minion" - }); - }); - -} diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 21cc58a623a..9bdb7806cc7 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -10,7 +10,6 @@ import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; import DS from 'ember-data'; -import { isEnabled } from 'ember-data/-private'; let store, env; @@ -211,15 +210,9 @@ test("destroying the store correctly cleans everything up", function(assert) { }); function ajaxResponse(value) { - if (isEnabled('ds-improved-ajax')) { - env.adapter._makeRequest = function() { - return run(RSVP, 'resolve', copy(value, true)); - }; - } else { - env.adapter.ajax = function(url, verb, hash) { - return run(RSVP, 'resolve', copy(value, true)); - }; - } + env.adapter.ajax = function(url, verb, hash) { + return run(RSVP, 'resolve', copy(value, true)); + }; } module("integration/store - findRecord"); diff --git a/tests/unit/adapters/rest-adapter/ajax-test.js b/tests/unit/adapters/rest-adapter/ajax-test.js index f7baae4b4c4..285707123e3 100644 --- a/tests/unit/adapters/rest-adapter/ajax-test.js +++ b/tests/unit/adapters/rest-adapter/ajax-test.js @@ -5,7 +5,6 @@ import setupStore from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; import DS from 'ember-data'; -import { isEnabled } from 'ember-data/-private'; var Person, Place, store, adapter, env; @@ -31,21 +30,12 @@ test('When an id is searched, the correct url should be generated', function(ass let count = 0; - if (isEnabled('ds-improved-ajax')) { - adapter._makeRequest = function(request) { - if (count === 0) { assert.equal(request.url, '/people/1', 'should create the correct url'); } - if (count === 1) { assert.equal(request.url, '/places/1', 'should create the correct url'); } - count++; - return resolve(); - }; - } else { - adapter.ajax = function(url, method) { - if (count === 0) { assert.equal(url, '/people/1', 'should create the correct url'); } - if (count === 1) { assert.equal(url, '/places/1', 'should create the correct url'); } - count++; - return resolve(); - }; - } + adapter.ajax = function(url, method) { + if (count === 0) { assert.equal(url, '/people/1', 'should create the correct url'); } + if (count === 1) { assert.equal(url, '/places/1', 'should create the correct url'); } + count++; + return resolve(); + }; return run(() => { return EmberPromise.all([ @@ -58,17 +48,10 @@ test('When an id is searched, the correct url should be generated', function(ass test(`id's should be sanatized`, function(assert) { assert.expect(1); - if (isEnabled('ds-improved-ajax')) { - adapter._makeRequest = function(request) { - assert.equal(request.url, '/people/..%2Fplace%2F1', `should create the correct url`); - return resolve(); - }; - } else { - adapter.ajax = function(url, method) { - assert.equal(url, '/people/..%2Fplace%2F1', "should create the correct url"); - return resolve(); - }; - } + adapter.ajax = function(url, method) { + assert.equal(url, '/people/..%2Fplace%2F1', "should create the correct url"); + return resolve(); + }; return run(() => adapter.findRecord(store, Person, '../place/1', {})); }); diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index fdcef39969a..1bebf1b9a91 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -5,7 +5,6 @@ import { createStore } from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; import DS from 'ember-data'; -import { isEnabled } from 'ember-data/-private'; let GroupsAdapter, store, requests; let maxLength; @@ -26,47 +25,25 @@ module('unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda } }); - if (isEnabled('ds-improved-ajax')) { - GroupsAdapter.reopen({ - _makeRequest(request) { - requests.push({ - url: request.url, - ids: request.data.ids - }); - - let queryString = request.data.ids.map(i => { - return encodeURIComponent('ids[]') + '=' + encodeURIComponent(i); - }).join('&'); - let fullUrl = request.url + '?' + queryString; - - maxLength = this.get('maxURLLength'); - lengths.push(fullUrl.length); - - let testRecords = request.data.ids.map(id => ({ id })); - return EmberPromise.resolve({ 'testRecords' : testRecords }); - } - }); - } else { - GroupsAdapter.reopen({ - ajax(url, type, options) { - requests.push({ - url, - ids: options.data.ids - }); - - let queryString = options.data.ids.map(i => { - return encodeURIComponent('ids[]') + '=' + encodeURIComponent(i); - }).join('&'); - let fullUrl = url + '?' + queryString; - - maxLength = this.get('maxURLLength'); - lengths.push(fullUrl.length); - - let testRecords = options.data.ids.map(id => ({ id })); - return EmberPromise.resolve({ 'testRecords' : testRecords }); - } - }); - } + GroupsAdapter.reopen({ + ajax(url, type, options) { + requests.push({ + url, + ids: options.data.ids + }); + + let queryString = options.data.ids.map(i => { + return encodeURIComponent('ids[]') + '=' + encodeURIComponent(i); + }).join('&'); + let fullUrl = url + '?' + queryString; + + maxLength = this.get('maxURLLength'); + lengths.push(fullUrl.length); + + let testRecords = options.data.ids.map(id => ({ id })); + return EmberPromise.resolve({ 'testRecords' : testRecords }); + } + }); store = createStore({ adapter: GroupsAdapter, diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 2a1b60761fd..16cd9b9707a 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -8,7 +8,6 @@ import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; import DS from 'ember-data'; -import { isEnabled } from 'ember-data/-private'; import { getOwner } from 'ember-data/-private'; let Person, store, env; @@ -512,186 +511,6 @@ test('changedAttributes() works while the record is being updated', function(ass }); }); -if (isEnabled('ds-rollback-attribute')) { - test('rollbackAttribute() reverts a single attribute to its canonical value', function(assert) { - assert.expect(5); - - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Peter', - isDrugAddict: true - } - } - }); - - let person = store.peekRecord('person', 1); - - assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); - person.setProperties({ - name: 'Piper', - isDrugAddict: false - }); - assert.equal(person.get('hasDirtyAttributes'), true, 'record becomes dirty after setting property to a new value'); - person.rollbackAttribute('isDrugAddict'); - assert.equal(person.get('isDrugAddict'), true, 'The specified attribute is rolled back'); - assert.equal(person.get('name'), 'Piper', 'Unspecified attributes are not rolled back'); - assert.equal(person.get('hasDirtyAttributes'), true, 'record with changed attributes is still dirty'); - }); - }); - - test('calling rollbackAttribute() on an unmodified property has no effect', function(assert) { - assert.expect(5); - - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Peter', - isDrugAddict: true - } - } - }); - - let person = store.peekRecord('person', 1); - - assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); - person.set('name', 'Piper'); - assert.equal(person.get('hasDirtyAttributes'), true, 'record becomes dirty after setting property to a new value'); - person.rollbackAttribute('isDrugAddict'); - assert.equal(person.get('isDrugAddict'), true, 'The specified attribute does not change value'); - assert.equal(person.get('name'), 'Piper', 'Unspecified attributes are not rolled back'); - assert.equal(person.get('hasDirtyAttributes'), true, 'record with changed attributes is still dirty'); - }); - }); - - test('Rolling back the final value with rollbackAttribute() causes the record to become clean again', function(assert) { - assert.expect(3); - - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Peter', - isDrugAddict: true - } - } - }); - - let person = store.peekRecord('person', 1); - - assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); - person.set('isDrugAddict', false); - assert.equal(person.get('hasDirtyAttributes'), true, 'record becomes dirty after setting property to a new value'); - person.rollbackAttribute('isDrugAddict'); - assert.equal(person.get('hasDirtyAttributes'), false, 'record becomes clean after resetting property to the old value'); - }); - }); - - test('Using rollbackAttribute on an in-flight record reverts to the latest in-flight value', function(assert) { - assert.expect(4); - - let person; - - // Make sure the save is async - env.adapter.updateRecord = function(store, type, snapshot) { - return resolve(); - }; - - return run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: "Tom" - } - } - }); - person = store.peekRecord('person', 1); - person.set('name', 'Thomas'); - - let saving = person.save(); - - assert.equal(person.get('isSaving'), true); - assert.equal(person.get('name'), 'Thomas'); - - person.set('name', 'Tomathy'); - assert.equal(person.get('name'), 'Tomathy'); - - person.rollbackAttribute('name'); - assert.equal(person.get('name'), 'Thomas'); - - return saving; - }); - }); - - test('Saving an in-flight record updates the in-flight value rollbackAttribute will use', function(assert) { - assert.expect(7); - - let person, finishSaving; - let updateRecordPromise = new EmberPromise(resolve => finishSaving = resolve); - - // Make sure the save is async - env.adapter.updateRecord = function(store, type, snapshot) { - return updateRecordPromise; - }; - - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: "Tom" - } - } - }); - - person = store.peekRecord('person', 1); - }); - - let saving = []; - - run(() => { - person.set('name', 'Thomas'); - saving.push(person.save()); - }); - - run(() => { - assert.equal(person.get('isSaving'), true); - assert.equal(person.get('name'), 'Thomas'); - - person.set('name', 'Tomathy'); - assert.equal(person.get('name'), 'Tomathy'); - - saving.push(person.save()); - }); - - run(() => { - assert.equal(person.get('isSaving'), true); - assert.equal(person.get('name'), "Tomathy"); - - person.set('name', "Tomny"); - assert.equal(person.get('name'), 'Tomny'); - - person.rollbackAttribute('name'); - assert.equal(person.get('name'), 'Tomathy'); - - finishSaving(); - }); - - return EmberPromise.all(saving); - }); -} - test("a DS.Model does not require an attribute type", function(assert) { const Tag = DS.Model.extend({ name: DS.attr() diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index 27bb8bed3ae..50c6e8f93d8 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -7,7 +7,6 @@ import setupStore from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; import DS from 'ember-data'; -import { isEnabled } from 'ember-data/-private'; let env, store, Person; @@ -241,20 +240,11 @@ test(`invalid new record's attributes can be rollbacked`, function(assert) { } ]); - let adapter; - if (isEnabled('ds-improved-ajax')) { - adapter = DS.RESTAdapter.extend({ - _makeRequest() { - return reject(error); - } - }); - } else { - adapter = DS.RESTAdapter.extend({ - ajax(url, type, hash) { - return reject(error); - } - }); - } + let adapter = DS.RESTAdapter.extend({ + ajax(url, type, hash) { + return reject(error); + } + }); env = setupStore({ person: Person, adapter: adapter }); @@ -366,21 +356,11 @@ test("invalid record's attributes can be rollbacked", function(assert) { } ]); - let adapter; - if (isEnabled('ds-improved-ajax')) { - adapter = DS.RESTAdapter.extend({ - _makeRequest() { - return reject(error); - } - }); - } else { - adapter = DS.RESTAdapter.extend({ - ajax(url, type, hash) { - return reject(error); - } - }); - } - + let adapter = DS.RESTAdapter.extend({ + ajax(url, type, hash) { + return reject(error); + } + }); env = setupStore({ dog: Dog, adapter: adapter }); let dog; @@ -440,20 +420,11 @@ test(`invalid record's attributes rolled back to correct state after set`, funct } ]); - let adapter; - if (isEnabled('ds-improved-ajax')) { - adapter = DS.RESTAdapter.extend({ - _makeRequest() { - return reject(error); - } - }); - } else { - adapter = DS.RESTAdapter.extend({ - ajax(url, type, hash) { - return reject(error); - } - }); - } + let adapter = DS.RESTAdapter.extend({ + ajax(url, type, hash) { + return reject(error); + } + }); env = setupStore({ dog: Dog, adapter: adapter }); let dog; @@ -513,20 +484,11 @@ test(`when destroying a record setup the record state to invalid, the record's a } ]); - let adapter; - if (isEnabled('ds-improved-ajax')) { - adapter = DS.RESTAdapter.extend({ - _makeRequest() { - return reject(error); - } - }); - } else { - adapter = DS.RESTAdapter.extend({ - ajax(url, type, hash) { - return reject(error); - } - }); - } + let adapter = DS.RESTAdapter.extend({ + ajax(url, type, hash) { + return reject(error); + } + }); env = setupStore({ dog: Dog, adapter: adapter }); let dog = run(() => { diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index 3f624a29d12..22291b6e4d2 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -9,8 +9,6 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; -import { isEnabled } from 'ember-data/-private'; - let env, store, Person, PhoneNumber, Post; const { attr, hasMany, belongsTo } = DS; @@ -758,33 +756,6 @@ testInDebug('Calling push with unknown keys should not warn by default', functio }, /The payload for 'person' contains these unknown .*: .* Make sure they've been defined in your model./); }); -if (isEnabled('ds-pushpayload-return')) { - test("Calling pushPayload returns records", function(assert) { - env.registry.register('serializer:person', DS.RESTSerializer); - - let people = run(() => { - return store.pushPayload('person', { - people: [{ - id: '1', - firstName: 'Robert', - lastName: 'Jackson' - }, { - id: '2', - firstName: 'Matthew', - lastName: 'Beale' - }] - }); - }); - - assert.equal(people.length, 2, 'both records were returned by `store.pushPayload`'); - - assert.equal(people[0].get('firstName'), 'Robert', 'pushPayload returns pushed records'); - assert.equal(people[0].get('lastName'), 'Jackson', 'pushPayload returns pushed records'); - assert.equal(people[1].get('firstName'), 'Matthew', 'pushPayload returns pushed records'); - assert.equal(people[1].get('lastName'), 'Beale', 'pushPayload returns pushed records'); - }); -} - test('_push returns an instance of InternalModel if an object is pushed', function(assert) { let pushResult; diff --git a/tests/unit/store/serialize-test.js b/tests/unit/store/serialize-test.js index 6fe6c4ea5dd..5378324a9e4 100644 --- a/tests/unit/store/serialize-test.js +++ b/tests/unit/store/serialize-test.js @@ -4,31 +4,28 @@ import testInDebug from 'dummy/tests/helpers/test-in-debug'; import attr from 'ember-data/attr'; import Model from 'ember-data/model'; import { createStore } from 'dummy/tests/helpers/store'; -import { isEnabled } from 'ember-data/-private'; -if (isEnabled('ds-deprecate-store-serialize')) { - module("unit/store/serialize - DS.Store#serialize"); +module("unit/store/serialize - DS.Store#serialize"); - testInDebug('Store#serialize is deprecated', function(assert) { - let store = createStore({ - person: Model.extend({ firstName: attr() }) - }); +testInDebug('Store#serialize is deprecated', function(assert) { + let store = createStore({ + person: Model.extend({ firstName: attr() }) + }); - run(() => { - let person = store.push({ - data: { - type: 'person', - id: 1, - attributes: { - firstName: 'original first name' - } + run(() => { + let person = store.push({ + data: { + type: 'person', + id: 1, + attributes: { + firstName: 'original first name' } - }); - - assert.expectDeprecation(() => { - store.serialize(person); - }, 'Use of store.serialize is deprecated, use record.serialize instead.'); + } }); + assert.expectDeprecation(() => { + store.serialize(person); + }, 'Use of store.serialize is deprecated, use record.serialize instead.'); }); -} + +}); From 01520149a1c4c7eab7ce95949dad5607cef5a6ef Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Mon, 13 Mar 2017 11:59:51 -0700 Subject: [PATCH 2166/2527] [BUGFIX #4497] query/queryRecord/filter now support adapter options --- addon/-private/system/store.js | 18 ++++++-- addon/-private/system/store/finders.js | 15 +++---- .../integration/adapter/store-adapter-test.js | 42 +++++++++++++++++++ 3 files changed, 62 insertions(+), 13 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 4ff0fb72f0f..3f4ed0c72d9 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1268,11 +1268,16 @@ Store = Service.extend({ assert(`You need to pass a query hash to the store's query method`, query); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let options = {}; + + options.adapterOptions = query.adapterOptions; + delete query.adapterOptions; + let normalizedModelName = normalizeModelName(modelName); - return this._query(normalizedModelName, query); + return this._query(normalizedModelName, query, null, options); }, - _query(modelName, query, array) { + _query(modelName, query, array, options) { let token = heimdall.start('store._query'); assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); assert(`You need to pass a query hash to the store's query method`, query); @@ -1288,7 +1293,7 @@ Store = Service.extend({ assert(`You tried to load a query but you have no adapter (for ${modelName})`, adapter); assert(`You tried to load a query but your adapter does not implement 'query'`, typeof adapter.query === 'function'); - let pA = promiseArray(_query(adapter, this, modelName, query, array)); + let pA = promiseArray(_query(adapter, this, modelName, query, array, options)); instrument(() => { pA.finally(() => { heimdall.stop(token); }); }); @@ -1400,10 +1405,15 @@ Store = Service.extend({ let adapter = this.adapterFor(normalizedModelName); + let options = {}; + + options.adapterOptions = query.adapterOptions; + delete query.adapterOptions; + assert(`You tried to make a query but you have no adapter (for ${normalizedModelName})`, adapter); assert(`You tried to make a query but your adapter does not implement 'queryRecord'`, typeof adapter.queryRecord === 'function'); - return promiseObject(_queryRecord(adapter, this, modelName, query).then(internalModel => { + return promiseObject(_queryRecord(adapter, this, modelName, query, options).then(internalModel => { // the promise returned by store.queryRecord is expected to resolve with // an instance of DS.Model if (internalModel) { diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index a7f2570da4f..132210d141e 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -134,23 +134,21 @@ export function _findAll(adapter, store, modelName, sinceToken, options) { }, null, 'DS: Extract payload of findAll ${modelName}'); } -export function _query(adapter, store, modelName, query, recordArray) { +export function _query(adapter, store, modelName, query, recordArray, options) { let modelClass = store.modelFor(modelName); // adapter.query needs the class let promise; + let label = `DS: Handle Adapter#query of ${modelName}`; let createRecordArray = adapter.query.length > 3 || (adapter.query.wrappedFunction && adapter.query.wrappedFunction.length > 3); if (createRecordArray) { recordArray = recordArray || store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); - promise = Promise.resolve().then(() => adapter.query(store, modelClass, query, recordArray)); + promise = Promise.resolve(adapter.query(store, modelClass, query, recordArray, options), label); } else { - promise = Promise.resolve().then(() => adapter.query(store, modelClass, query)); + promise = Promise.resolve(adapter.query(store, modelClass, query), label); } - let label = `DS: Handle Adapter#query of ${modelClass}`; - - promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(adapterPayload => { @@ -173,12 +171,11 @@ export function _query(adapter, store, modelName, query, recordArray) { }, null, `DS: Extract payload of query ${modelName}`); } -export function _queryRecord(adapter, store, modelName, query) { +export function _queryRecord(adapter, store, modelName, query, options) { let modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class - let promise = Promise.resolve().then(() => adapter.queryRecord(store, modelClass, query)); let label = `DS: Handle Adapter#queryRecord of ${modelName}`; + let promise = Promise.resolve(adapter.queryRecord(store, modelClass, query, options), label); - promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(adapterPayload => { diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index ae6c09ecd4d..626e1e00f7a 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -1363,6 +1363,48 @@ test("store.findRecord should pass adapterOptions to adapter.findRecord", functi }); }); +test("store.query should pass adapterOptions to adapter.query ", function(assert) { + assert.expect(2); + + env.adapter.query = function(store, type, query, array, options) { + assert.ok(!('adapterOptions' in query)); + assert.deepEqual(options.adapterOptions, { query: { embed: true } }); + return []; + }; + + return run(() => { + return store.query('person', { adapterOptions: { query: { embed: true } } }); + }); +}); + +test("store.filter should pass adapterOptions to adapter.query", function(assert) { + assert.expect(2); + + env.adapter.query = function(store, type, query, array, options) { + assert.ok(!('adapterOptions' in query)); + assert.deepEqual(options.adapterOptions, { query: { embed: true } }); + return []; + }; + + return run(() => { + return store.filter('person', { adapterOptions: { query: { embed: true } } }, () => {}); + }); +}); + +test("store.queryRecord should pass adapterOptions to adapter.queryRecord", function(assert) { + assert.expect(2); + + env.adapter.queryRecord = function(store, type, query, snapshot) { + assert.ok(!('adapterOptions' in query)); + assert.deepEqual(snapshot.adapterOptions, { query: { embed: true } }); + return { id: 1 }; + }; + + return run(() => { + return store.queryRecord('person', { adapterOptions: { query: { embed: true } } }); + }); +}); + test("store.findRecord should pass 'include' to adapter.findRecord", function(assert) { assert.expect(1); From 9ff2c86536442cb369bd117adb2f580192b986e1 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 29 Mar 2018 13:19:59 -0700 Subject: [PATCH 2167/2527] fix tests --- addon/-private/system/store/finders.js | 13 ++++++++----- tests/integration/adapter/store-adapter-test.js | 13 +++++++++---- .../adapter-populated-record-array-test.js | 4 ++-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 132210d141e..102633d41e1 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -138,17 +138,19 @@ export function _query(adapter, store, modelName, query, recordArray, options) { let modelClass = store.modelFor(modelName); // adapter.query needs the class let promise; - let label = `DS: Handle Adapter#query of ${modelName}`; let createRecordArray = adapter.query.length > 3 || (adapter.query.wrappedFunction && adapter.query.wrappedFunction.length > 3); if (createRecordArray) { recordArray = recordArray || store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); - promise = Promise.resolve(adapter.query(store, modelClass, query, recordArray, options), label); + promise = Promise.resolve().then(() => adapter.query(store, modelClass, query, recordArray, options)); } else { - promise = Promise.resolve(adapter.query(store, modelClass, query), label); + promise = Promise.resolve().then(() => adapter.query(store, modelClass, query)); } + let label = `DS: Handle Adapter#query of ${modelName}`; + promise = Promise.resolve(promise, label); + promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(adapterPayload => { @@ -173,9 +175,10 @@ export function _query(adapter, store, modelName, query, recordArray, options) { export function _queryRecord(adapter, store, modelName, query, options) { let modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class - let label = `DS: Handle Adapter#queryRecord of ${modelName}`; - let promise = Promise.resolve(adapter.queryRecord(store, modelClass, query, options), label); + let promise = Promise.resolve().then(() => adapter.queryRecord(store, modelClass, query, options)); + let label = `DS: Handle Adapter#queryRecord of ${modelName}`; + promise = Promise.resolve(promise, label); promise = _guard(promise, _bind(_objectIsAlive, store)); return promise.then(adapterPayload => { diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 626e1e00f7a..5382a7adbf4 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -37,7 +37,12 @@ module("integration/adapter/store-adapter - DS.Store and DS.Adapter integration name: DS.attr('string') }); - env = setupStore({ person: Person, dog: Dog }); + env = setupStore({ + serializer: DS.JSONAPISerializer, + adapter: DS.JSONAPIAdapter, + person: Person, + dog: Dog + }); store = env.store; adapter = env.adapter; }, @@ -1369,7 +1374,7 @@ test("store.query should pass adapterOptions to adapter.query ", function(assert env.adapter.query = function(store, type, query, array, options) { assert.ok(!('adapterOptions' in query)); assert.deepEqual(options.adapterOptions, { query: { embed: true } }); - return []; + return { data: [] }; }; return run(() => { @@ -1383,7 +1388,7 @@ test("store.filter should pass adapterOptions to adapter.query", function(assert env.adapter.query = function(store, type, query, array, options) { assert.ok(!('adapterOptions' in query)); assert.deepEqual(options.adapterOptions, { query: { embed: true } }); - return []; + return { data: [] }; }; return run(() => { @@ -1397,7 +1402,7 @@ test("store.queryRecord should pass adapterOptions to adapter.queryRecord", func env.adapter.queryRecord = function(store, type, query, snapshot) { assert.ok(!('adapterOptions' in query)); assert.deepEqual(snapshot.adapterOptions, { query: { embed: true } }); - return { id: 1 }; + return { data: { type: 'person', id: 1, attributes: {} } }; }; return run(() => { diff --git a/tests/integration/record-arrays/adapter-populated-record-array-test.js b/tests/integration/record-arrays/adapter-populated-record-array-test.js index ed368e67404..3797d6691e6 100644 --- a/tests/integration/record-arrays/adapter-populated-record-array-test.js +++ b/tests/integration/record-arrays/adapter-populated-record-array-test.js @@ -179,7 +179,7 @@ test('pass record array to adapter.query based on arity', function(assert) { return store.query('person', { }).then(recordArray => { env.adapter.query = function(store, type, query, _recordArray) { - assert.equal(arguments.length, 4); + assert.equal(arguments.length, 5); return payload; }; return store.query('person', { }); @@ -218,7 +218,7 @@ test('pass record array to adapter.query based on arity', function(assert) { return store.query('person', actualQuery).then(recordArray => { env.adapter.query = function(store, type, query, _recordArray) { - assert.equal(arguments.length, 4); + assert.equal(arguments.length, 5); return payload; }; From 08ef8c2b6b49e7d98ba4a689879f09c13fe2db19 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 24 Jan 2018 15:02:16 -0800 Subject: [PATCH 2168/2527] [CHORE] remove all benchmark related code --- .npmignore | 1 - benchmarks/.gitignore | 1 - benchmarks/BenchmarkGuide.md | 19 -- benchmarks/bash-analyze.js | 8 - benchmarks/bash-run.js | 7 - benchmarks/config.js | 75 ----- benchmarks/index.js | 7 - .../results/development-stripped/.gitkeep | 0 benchmarks/results/development/.gitkeep | 0 .../results/production-stripped/.gitkeep | 0 benchmarks/results/production/.gitkeep | 0 ember-cli-build.js | 36 +-- package.json | 5 - server/index.js | 13 - server/models/baz.js | 12 - server/models/complex.js | 13 - server/models/foo.js | 12 - server/models/heavy-baz.js | 13 - server/models/heavy-foo.js | 12 - server/models/heavy.js | 13 - server/models/simple.js | 9 - server/scenarios/default.js | 6 - tests/dummy/app/adapters/application.js | 5 - tests/dummy/app/models/baz.js | 14 - tests/dummy/app/models/complex.js | 15 - tests/dummy/app/models/foo.js | 14 - tests/dummy/app/models/heavy-baz.js | 15 - tests/dummy/app/models/heavy-foo.js | 14 - tests/dummy/app/models/heavy.js | 15 - tests/dummy/app/models/simple.js | 11 - tests/dummy/app/router.js | 4 +- .../dummy/app/routes/application/template.hbs | 20 -- tests/dummy/app/routes/index/route.js | 4 - tests/dummy/app/routes/index/template.hbs | 0 tests/dummy/app/routes/query/controller.js | 10 - tests/dummy/app/routes/query/route.js | 88 ------ tests/dummy/app/routes/query/template.hbs | 1 - tests/dummy/app/serializers/application.js | 7 - yarn.lock | 278 +++--------------- 39 files changed, 41 insertions(+), 736 deletions(-) delete mode 100644 benchmarks/.gitignore delete mode 100644 benchmarks/BenchmarkGuide.md delete mode 100644 benchmarks/bash-analyze.js delete mode 100644 benchmarks/bash-run.js delete mode 100644 benchmarks/config.js delete mode 100644 benchmarks/index.js delete mode 100644 benchmarks/results/development-stripped/.gitkeep delete mode 100644 benchmarks/results/development/.gitkeep delete mode 100644 benchmarks/results/production-stripped/.gitkeep delete mode 100644 benchmarks/results/production/.gitkeep delete mode 100644 server/index.js delete mode 100644 server/models/baz.js delete mode 100644 server/models/complex.js delete mode 100644 server/models/foo.js delete mode 100644 server/models/heavy-baz.js delete mode 100644 server/models/heavy-foo.js delete mode 100644 server/models/heavy.js delete mode 100644 server/models/simple.js delete mode 100644 server/scenarios/default.js delete mode 100644 tests/dummy/app/adapters/application.js delete mode 100644 tests/dummy/app/models/baz.js delete mode 100644 tests/dummy/app/models/complex.js delete mode 100644 tests/dummy/app/models/foo.js delete mode 100644 tests/dummy/app/models/heavy-baz.js delete mode 100644 tests/dummy/app/models/heavy-foo.js delete mode 100644 tests/dummy/app/models/heavy.js delete mode 100644 tests/dummy/app/models/simple.js delete mode 100644 tests/dummy/app/routes/index/route.js delete mode 100644 tests/dummy/app/routes/index/template.hbs delete mode 100644 tests/dummy/app/routes/query/controller.js delete mode 100644 tests/dummy/app/routes/query/route.js delete mode 100644 tests/dummy/app/routes/query/template.hbs delete mode 100644 tests/dummy/app/serializers/application.js diff --git a/.npmignore b/.npmignore index 076f02ba550..7f6b54db04f 100644 --- a/.npmignore +++ b/.npmignore @@ -4,7 +4,6 @@ /node-tests /tests /tmp -/benchmarks /bin /docs diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore deleted file mode 100644 index fbca2253799..00000000000 --- a/benchmarks/.gitignore +++ /dev/null @@ -1 +0,0 @@ -results/ diff --git a/benchmarks/BenchmarkGuide.md b/benchmarks/BenchmarkGuide.md deleted file mode 100644 index 9ae29e392ae..00000000000 --- a/benchmarks/BenchmarkGuide.md +++ /dev/null @@ -1,19 +0,0 @@ -### Launch - -*Start the API development servers* - -```cli -ember serve --instrument -``` - -*Configure benchmarks* - -In `benchmarks/config.js`, configure the slug(s) -you wish to benchmark, and the number of runs to -complete. - -*Run the desired benchmarks* - -```cli -node ./benchmarks -``` diff --git a/benchmarks/bash-analyze.js b/benchmarks/bash-analyze.js deleted file mode 100644 index 30b95ae6f4d..00000000000 --- a/benchmarks/bash-analyze.js +++ /dev/null @@ -1,8 +0,0 @@ -const config = require('./config'); -const CACHE_DIR = process.argv[2] === '-c' ? process.argv[3] : '.'; -const path = require('path'); -const cachePath = path.join(__dirname, './results', CACHE_DIR); -const analyze = require('heimdall-query/src/analyze'); - -analyze(config, cachePath); - diff --git a/benchmarks/bash-run.js b/benchmarks/bash-run.js deleted file mode 100644 index 949bceddb24..00000000000 --- a/benchmarks/bash-run.js +++ /dev/null @@ -1,7 +0,0 @@ -const config = require('./config'); -const CACHE_DIR = process.argv[2] === '-c' ? process.argv[3] : '.'; -const path = require('path'); -const cachePath = path.join(__dirname, './results', CACHE_DIR); -const run = require('heimdall-query/src/run'); - -run(config, cachePath); diff --git a/benchmarks/config.js b/benchmarks/config.js deleted file mode 100644 index e88a8ae7708..00000000000 --- a/benchmarks/config.js +++ /dev/null @@ -1,75 +0,0 @@ -module.exports = { - runs: 35, - domain: 'http://localhost:4200/', - slugs: [ - // simple returns a 1 simple record with no relationships per count in limit - - // "query?modelName=simple&limit=1", // 1 total - // "query?modelName=simple&limit=2", // 2 total - // "query?modelName=simple&limit=34", // 34 total - // "query?modelName=simple&limit=119", // 119 total - // "query?modelName=simple&limit=238", // 238 total - - - // complex returns 7 total records of 3 model types per count in limit - // a primary record with 5 hasMany 1 belongsTo - - // "query?modelName=complex&limit=1&included=foo,baz", // 7 total - // "query?modelName=complex&limit=2&included=foo,baz", // 14 total - // "query?modelName=complex&limit=5&included=foo,baz", // 35 total - // "query?modelName=complex&limit=17&included=foo,baz", // 119 total - // "query?modelName=complex&limit=34&included=foo,baz", // 238 total - - - // heavy returns 17 total records of 5 model types per count in limit - // a primary record with - // - 5 hasMany with 1 belongsTo each - // - 1 belongsTo with 5 hasMany - - // "query?modelName=heavy&limit=1&included=foo,baz,heavy-foo,heavy-baz", // 17 total - // "query?modelName=heavy&limit=2&included=foo,baz,heavy-foo,heavy-baz", // 34 total - // "query?modelName=heavy&limit=7&included=foo,baz,heavy-foo,heavy-baz", // 119 total - // "query?modelName=heavy&limit=14&included=foo,baz,heavy-foo,heavy-baz" // 238 total - "query?modelName=heavy&limit=50&included=foo,baz,heavy-foo,heavy-baz" // 238 total - - ], - ignoreBranches: [ - // 'adapter._makeRequest', - // 'InternalModel._materializeRecord' - ], - buckets: { - - }, - stats: [ - { - key: "stats.self.selfTime", - name: 'Count', - rollup: false, - transform: function(t, c) { return c;} - }, - { - key: "stats.self.duration", - name: 'Duration', - rollup: false, - transform: function(t) { - return `${(t / 1e6).toFixed(2)}ms`; - } - }, - { - key: "stats.self.selfTime", - name: 'Self Time', - rollup: false - }, - { - key: "stats.self.selfTime", - name: 'Total Time', - rollup: true - }, - ], - "browser": "chrome", - "name": "Performance Analysis", - "compressAfter": 10, - "maxDepth": 25, - "collapseByName": true, - "finderPath": "ember-data" -}; diff --git a/benchmarks/index.js b/benchmarks/index.js deleted file mode 100644 index c3eaaaca258..00000000000 --- a/benchmarks/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const config = require('./config'); -const CACHE_DIR = process.argv[2] === '-c' ? process.argv[3] : '.'; -const path = require('path'); -const cachePath = path.join(__dirname, './results', CACHE_DIR); -const run = require('heimdall-query'); - -run(config, cachePath); diff --git a/benchmarks/results/development-stripped/.gitkeep b/benchmarks/results/development-stripped/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/benchmarks/results/development/.gitkeep b/benchmarks/results/development/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/benchmarks/results/production-stripped/.gitkeep b/benchmarks/results/production-stripped/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/benchmarks/results/production/.gitkeep b/benchmarks/results/production/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/ember-cli-build.js b/ember-cli-build.js index b1b8a785cf9..e7d419c8bb8 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -1,44 +1,10 @@ /* eslint-env node */ var EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); var merge = require('broccoli-merge-trees'); -var Funnel = require('broccoli-funnel'); var yuidoc = require('./lib/yuidoc'); -var StripClassCallCheck = require('babel6-plugin-strip-class-callcheck'); -var path = require('path'); - -// allow toggling of heimdall instrumentation -var INSTRUMENT_HEIMDALL = false; -var args = process.argv; - -for (var i = 0; i < args.length; i++) { - if (args[i] === '--instrument') { - INSTRUMENT_HEIMDALL = true; - break; - } -} module.exports = function(defaults) { - var app = new EmberAddon(defaults, { - // use babel6 options until we are using ember-cli@2.13 - babel6: { - postTransformPlugins: [ - // while ember-data strips itself, ember does not currently - [StripClassCallCheck] - ] - } - }); - - if (INSTRUMENT_HEIMDALL) { - console.warn('IMPORTED HEIMDALL & SET EMBER TO PRODUCTION'); - var heimdallTree = new Funnel('node_modules/heimdalljs', { - destDir: 'heimdalljs' - }); - - app.trees.vendor = merge([app.trees.vendor, heimdallTree]); - - app.import('vendor/heimdalljs/dist/heimdalljs.iife.js', {prepend: true}); - app.vendorFiles['ember.js'].development = path.join(app.bowerDirectory, 'ember/ember.prod.js'); - } + var app = new EmberAddon(defaults, {}); /* This build file specifies the options for the dummy test app of this diff --git a/package.json b/package.json index efd54233c4b..9dc6a29314b 100644 --- a/package.json +++ b/package.json @@ -100,16 +100,11 @@ "ember-source-channel-url": "^1.0.1", "ember-try": "^0.2.23", "ember-watson": "^0.7.0", - "express": "^4.14.0", - "faker": "^3.1.0", "github": "^1.1.1", "glob": "^5.0.13", - "heimdall-query": "^0.1.0", - "json-api-mock-server": "0.1.1", "loader.js": "^4.5.0", "mocha": "^2.4.5", "mocha-only-detector": "0.0.2", - "morgan": "^1.7.0", "rimraf": "2.5.2", "rsvp": "4.8.0", "testdouble": "^3.2.6", diff --git a/server/index.js b/server/index.js deleted file mode 100644 index 9a758f9bf21..00000000000 --- a/server/index.js +++ /dev/null @@ -1,13 +0,0 @@ -/* jshint node:true */ -var mountEndpoints = require('json-api-mock-server'); - -module.exports = function(app, project) { - var configPath = project.project.configPath(); - var config = require(configPath)(project.environment).mockServer || {}; - - // Log proxy requests - var morgan = require('morgan'); - app.use(morgan('dev')); - - mountEndpoints(app, config); -}; diff --git a/server/models/baz.js b/server/models/baz.js deleted file mode 100644 index c8d20ae2979..00000000000 --- a/server/models/baz.js +++ /dev/null @@ -1,12 +0,0 @@ -var faker = require('faker'); -var props = require('json-api-mock-server/lib/store/props'); -var attr = props.attr; -var one = props.one; -var between = require('json-api-mock-server/lib/utils/between'); - -module.exports = { - name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), - description: attr('string', { defaultValue: function() { return faker.lorem.sentences(between(3, 7)); }}), - complex: one('complex', { inverse: 'baz', defaultValue: false }), - heavyBaz: one('heavy-baz', { inverse: 'bazs', defaultValue: false }) -}; diff --git a/server/models/complex.js b/server/models/complex.js deleted file mode 100644 index 48449179d54..00000000000 --- a/server/models/complex.js +++ /dev/null @@ -1,13 +0,0 @@ -var faker = require('faker'); -var props = require('json-api-mock-server/lib/store/props'); -var attr = props.attr; -var many = props.many; -var one = props.one; -var between = require('json-api-mock-server/lib/utils/between'); - -module.exports = { - name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), - description: attr('string', { defaultValue: function() { return faker.lorem.sentences(between(3, 7)); }}), - baz: one('baz', { inverse: 'complex', defaultValue: true }), - foos: many('foo', { inverse: 'complex', defaultValue: 5 }) -}; diff --git a/server/models/foo.js b/server/models/foo.js deleted file mode 100644 index 5a4988da31d..00000000000 --- a/server/models/foo.js +++ /dev/null @@ -1,12 +0,0 @@ -var faker = require('faker'); -var props = require('json-api-mock-server/lib/store/props'); -var attr = props.attr; -var one = props.one; -var between = require('json-api-mock-server/lib/utils/between'); - -module.exports = { - name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), - description: attr('string', { defaultValue: function() { return faker.lorem.sentences(between(3, 7)); }}), - complex: one('complex', { inverse: 'foos', defaultValue: false }), - heavyFoo: one('heavy-foo', { inverse: 'foo', defaultValue: false }) -}; diff --git a/server/models/heavy-baz.js b/server/models/heavy-baz.js deleted file mode 100644 index 3e4de0f4d48..00000000000 --- a/server/models/heavy-baz.js +++ /dev/null @@ -1,13 +0,0 @@ -var faker = require('faker'); -var props = require('json-api-mock-server/lib/store/props'); -var attr = props.attr; -var one = props.one; -var many = props.many; -var between = require('json-api-mock-server/lib/utils/between'); - -module.exports = { - name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), - description: attr('string', { defaultValue: function() { return faker.lorem.sentences(between(3, 7)); }}), - heavy: one('heavy', { inverse: 'heavyBaz', defaultValue: false }), - bazs: many('baz', { inverse: 'heavyBaz', defaultValue: 5 }) -}; diff --git a/server/models/heavy-foo.js b/server/models/heavy-foo.js deleted file mode 100644 index af67f260353..00000000000 --- a/server/models/heavy-foo.js +++ /dev/null @@ -1,12 +0,0 @@ -var faker = require('faker'); -var props = require('json-api-mock-server/lib/store/props'); -var attr = props.attr; -var one = props.one; -var between = require('json-api-mock-server/lib/utils/between'); - -module.exports = { - name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), - description: attr('string', { defaultValue: function() { return faker.lorem.sentences(between(3, 7)); }}), - heavy: one('heavy', { inverse: 'heavyFoos', defaultValue: false }), - foo: one('foo', { inverse: 'heavyFoo', defaultValue: true }) -}; diff --git a/server/models/heavy.js b/server/models/heavy.js deleted file mode 100644 index c521ac6677f..00000000000 --- a/server/models/heavy.js +++ /dev/null @@ -1,13 +0,0 @@ -var faker = require('faker'); -var props = require('json-api-mock-server/lib/store/props'); -var attr = props.attr; -var many = props.many; -var one = props.one; -var between = require('json-api-mock-server/lib/utils/between'); - -module.exports = { - name: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), - description: attr('string', { defaultValue: function() { return faker.lorem.sentences(between(3, 7)); }}), - heavyBaz: one('heavy-baz', { inverse: 'heavy', defaultValue: true }), - heavyFoos: many('heavy-foo', { inverse: 'heavy', defaultValue: 5 }) -}; diff --git a/server/models/simple.js b/server/models/simple.js deleted file mode 100644 index 9e4806eba14..00000000000 --- a/server/models/simple.js +++ /dev/null @@ -1,9 +0,0 @@ -var faker = require('faker'); -var props = require('json-api-mock-server/lib/store/props'); -var attr = props.attr; -var between = require('json-api-mock-server/lib/utils/between'); - -module.exports = { - title: attr('string', { defaultValue: function() { return faker.lorem.words(between(3, 7)); }}), - description: attr('string', { defaultValue: function() { return faker.lorem.sentences(between(3, 7)); }}) -}; diff --git a/server/scenarios/default.js b/server/scenarios/default.js deleted file mode 100644 index 3316c65c360..00000000000 --- a/server/scenarios/default.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = function(store) { - store.seed('simple', 10000); // 240 - store.seed('complex', 400); - store.seed('heavy', 50); -}; - diff --git a/tests/dummy/app/adapters/application.js b/tests/dummy/app/adapters/application.js deleted file mode 100644 index f1b1ab1ea42..00000000000 --- a/tests/dummy/app/adapters/application.js +++ /dev/null @@ -1,5 +0,0 @@ -import DS from 'ember-data'; - -export default DS.JSONAPIAdapter.extend({ - namespace: 'api' -}); diff --git a/tests/dummy/app/models/baz.js b/tests/dummy/app/models/baz.js deleted file mode 100644 index 168267544cf..00000000000 --- a/tests/dummy/app/models/baz.js +++ /dev/null @@ -1,14 +0,0 @@ -import DS from 'ember-data'; - -const { - attr, - belongsTo, - Model -} = DS; - -export default Model.extend({ - name: attr(), - description: attr(), - complex: belongsTo('complex', { inverse: 'baz', async: false }), - heavyFoo: belongsTo('heavy-foo', { inverse: 'baz', async: false }) -}); diff --git a/tests/dummy/app/models/complex.js b/tests/dummy/app/models/complex.js deleted file mode 100644 index d217eb5f34f..00000000000 --- a/tests/dummy/app/models/complex.js +++ /dev/null @@ -1,15 +0,0 @@ -import DS from 'ember-data'; - -const { - attr, - belongsTo, - hasMany, - Model -} = DS; - -export default Model.extend({ - name: attr(), - description: attr(), - baz: belongsTo('baz', { inverse: 'complex', async: false }), - foos: hasMany('foo', { inverse: 'complex', async: false }) -}); diff --git a/tests/dummy/app/models/foo.js b/tests/dummy/app/models/foo.js deleted file mode 100644 index 75d7b269f81..00000000000 --- a/tests/dummy/app/models/foo.js +++ /dev/null @@ -1,14 +0,0 @@ -import DS from 'ember-data'; - -const { - attr, - belongsTo, - Model -} = DS; - -export default Model.extend({ - name: attr(), - description: attr(), - complex: belongsTo('complex', { inverse: 'foos', async: false }), - heavyBaz: belongsTo('heavy-baz', { inverse: 'foos', async: false }) -}); diff --git a/tests/dummy/app/models/heavy-baz.js b/tests/dummy/app/models/heavy-baz.js deleted file mode 100644 index 0c1c3facc06..00000000000 --- a/tests/dummy/app/models/heavy-baz.js +++ /dev/null @@ -1,15 +0,0 @@ -import DS from 'ember-data'; - -const { - attr, - belongsTo, - hasMany, - Model -} = DS; - -export default Model.extend({ - name: attr(), - description: attr(), - heavy: belongsTo('heavy', { inverse: 'heavyBaz', async: false }), - foos: hasMany('foo', { inverse: 'heavyBaz', async: false}) -}); diff --git a/tests/dummy/app/models/heavy-foo.js b/tests/dummy/app/models/heavy-foo.js deleted file mode 100644 index 3e152ada5bb..00000000000 --- a/tests/dummy/app/models/heavy-foo.js +++ /dev/null @@ -1,14 +0,0 @@ -import DS from 'ember-data'; - -const { - attr, - belongsTo, - Model -} = DS; - -export default Model.extend({ - name: attr(), - description: attr(), - heavy: belongsTo('heavy', { inverse: 'heavyFoos', async: false }), - baz: belongsTo('baz', { inverse: 'heavyFoo', async: false }) -}); diff --git a/tests/dummy/app/models/heavy.js b/tests/dummy/app/models/heavy.js deleted file mode 100644 index 9d937ef9180..00000000000 --- a/tests/dummy/app/models/heavy.js +++ /dev/null @@ -1,15 +0,0 @@ -import DS from 'ember-data'; - -const { - attr, - belongsTo, - hasMany, - Model -} = DS; - -export default Model.extend({ - name: attr(), - description: attr(), - heavyBaz: belongsTo('heavy-baz', { inverse: 'heavy', async: false }), - heavyFoos: hasMany('heavy-foo', { inverse: 'heavy', async: false }) -}); diff --git a/tests/dummy/app/models/simple.js b/tests/dummy/app/models/simple.js deleted file mode 100644 index f8181b0c38a..00000000000 --- a/tests/dummy/app/models/simple.js +++ /dev/null @@ -1,11 +0,0 @@ -import DS from 'ember-data'; - -const { - Model, - attr -} = DS; - -export default Model.extend({ - title: attr(), - description: attr() -}); diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js index 8f3740ce8a6..53c53c6c075 100644 --- a/tests/dummy/app/router.js +++ b/tests/dummy/app/router.js @@ -6,8 +6,6 @@ const Router = EmberRouter.extend({ rootURL: config.rootURL }); -Router.map(function() { - this.route('query'); -}); +Router.map(function() {}); export default Router; diff --git a/tests/dummy/app/routes/application/template.hbs b/tests/dummy/app/routes/application/template.hbs index 525fbd3f0fb..1c967ea89c3 100644 --- a/tests/dummy/app/routes/application/template.hbs +++ b/tests/dummy/app/routes/application/template.hbs @@ -1,26 +1,6 @@ -

      {{#link-to 'index'}}Ember Data Performance Test Suite{{/link-to}}

      • Tests
      • -
      • - {{#link-to 'query'}}Query{{/link-to}} -
      • -
      • - {{#link-to 'query' (query-params - modelName='complex' - limit=400 - included='foo,baz' - eagerRelationships=false) - }}2800 models, lazy relationship{{/link-to}} -
      • -
      • - {{#link-to 'query' (query-params - modelName='complex' - limit=400 - included='foo,baz' - eagerRelationships=true) - }}2800 models, eager relationship{{/link-to}} -
      {{outlet}} diff --git a/tests/dummy/app/routes/index/route.js b/tests/dummy/app/routes/index/route.js deleted file mode 100644 index 6c74252aa1b..00000000000 --- a/tests/dummy/app/routes/index/route.js +++ /dev/null @@ -1,4 +0,0 @@ -import Route from '@ember/routing/route'; - -export default Route.extend({ -}); diff --git a/tests/dummy/app/routes/index/template.hbs b/tests/dummy/app/routes/index/template.hbs deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/dummy/app/routes/query/controller.js b/tests/dummy/app/routes/query/controller.js deleted file mode 100644 index 0c416ad7362..00000000000 --- a/tests/dummy/app/routes/query/controller.js +++ /dev/null @@ -1,10 +0,0 @@ -import Controller from '@ember/controller'; - -export default Controller.extend({ - queryParams: ['limit', 'modelName', 'included', 'eagerMaterialize', 'eagerRelationships'], - limit: 240, - included: '', - modelName: 'simple', - eagerMaterialize: true, - eagerRelationships: false -}); diff --git a/tests/dummy/app/routes/query/route.js b/tests/dummy/app/routes/query/route.js deleted file mode 100644 index 104824bce44..00000000000 --- a/tests/dummy/app/routes/query/route.js +++ /dev/null @@ -1,88 +0,0 @@ -/* global window, heimdall, console */ -import Route from '@ember/routing/route'; - -// fallback if no-heimdall happens to be present when loading the dummy app -let heimdall = self.heimdall; -if (typeof heimdall !== 'object') { - heimdall = { - start() { }, - stop() { } - }; -} - - -export default Route.extend({ - queryParams: { - limit: { - refreshModel: true - }, - modelName: { - refreshModel: true - }, - included: { - refreshModel: true - }, - eagerMaterialize: { - refreshModel: true - }, - eagerRelationships: { - refreshModel: true - } - }, - - model(params) { - // switch this to 'production' when generating production build baselines - let modelName = params.modelName; - delete params.modelName; - - let store = this.get('store'); - let token = heimdall.start('ember-data'); - return store.query(modelName, params) - .then((records) => { - let modelNames = [modelName, ...params.included.split(',')]; - let recordArrays = null; - - if (params.eagerMaterialize || params.eagerRelationships) { - recordArrays = getRecordArrays(store, ...modelNames); - // RecordArray lazily materializes the records - // We call toArray() to force materialization for benchmarking - // otherwise we would need to consume the RecordArray in our UI - // and clutter our benchmarks and make it harder to time. - materializeRecords(...recordArrays); - } - if (params.eagerRelationships) { - expandAllRelationships(...recordArrays); - } - - heimdall.stop(token); - self.result = heimdall.toString(); - - return records; - }); - } -}); - -function getRecordArrays(store, ...modelNames) { - return modelNames.map(modelName => store.peekAll(modelName)); -} - -function materializeRecords(...recordArrays) { - recordArrays.forEach(records => records.toArray()); -} - -function expandAllRelationships(...recordArrays) { - recordArrays.forEach(expandRelationships); -} - - -function expandRelationships(records, seen) { - let obj = records.objectAt(0); - if (!obj) { return; } - - records.objectAt(0).eachRelationship(rel => { - records.forEach(record => { - record._internalModel._relationships.get(rel); - }); - }); -} - diff --git a/tests/dummy/app/routes/query/template.hbs b/tests/dummy/app/routes/query/template.hbs deleted file mode 100644 index dc735570a2b..00000000000 --- a/tests/dummy/app/routes/query/template.hbs +++ /dev/null @@ -1 +0,0 @@ -

      Test Complete

      diff --git a/tests/dummy/app/serializers/application.js b/tests/dummy/app/serializers/application.js deleted file mode 100644 index 7fb674f33aa..00000000000 --- a/tests/dummy/app/serializers/application.js +++ /dev/null @@ -1,7 +0,0 @@ -import DS from 'ember-data'; - -export default DS.JSONAPISerializer.extend({ - normalizeResponse(store, modelClass, payload, id, requestType) { - return payload; - } -}); diff --git a/yarn.lock b/yarn.lock index 3275bf1c980..e889abf7128 100644 --- a/yarn.lock +++ b/yarn.lock @@ -31,30 +31,6 @@ version "0.7.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" -"@types/node@*": - version "9.4.6" - resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.6.tgz#d8176d864ee48753d053783e4e463aec86b8d82e" - -"@types/node@^7.0.5": - version "7.0.55" - resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.55.tgz#7bb6215ff9425a1d714106be9f0d3e0e28829288" - -"@types/rimraf@^0.0.28": - version "0.0.28" - resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06" - -"@types/tape@^4.2.29": - version "4.2.31" - resolved "https://registry.yarnpkg.com/@types/tape/-/tape-4.2.31.tgz#d2cd0f2e410d2c288a5eb54c01c04e6b8a301fd2" - dependencies: - "@types/node" "*" - -"@types/ws@^0.0.38": - version "0.0.38" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-0.0.38.tgz#42106fff4b422ca956734e29f0d73a6d893194d3" - dependencies: - "@types/node" "*" - abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -87,10 +63,6 @@ acorn@^5.2.1, acorn@^5.5.0: version "5.5.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.1.tgz#84e05a9ea0acbe131227da50301e62464dc9c1d8" -adm-zip@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.4.tgz#a61ed5ae6905c3aea58b3a657d25033091052736" - after@0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" @@ -106,7 +78,7 @@ ajv-keywords@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" -ajv@^4.1.3, ajv@^4.7.0, ajv@^4.9.1: +ajv@^4.7.0, ajv@^4.9.1: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" dependencies: @@ -1085,10 +1057,6 @@ binary-extensions@^1.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" -bindings@1.2.x, bindings@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11" - blank-object@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" @@ -1111,7 +1079,7 @@ bluebird@^3.1.1, bluebird@^3.4.6: version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" -body-parser@1.18.2, body-parser@^1.15.2: +body-parser@1.18.2: version "1.18.2" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" dependencies: @@ -1641,16 +1609,9 @@ buffer@4.9.1: ieee754 "^1.1.4" isarray "^1.0.0" -bufferutil@1.2.x: - version "1.2.1" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-1.2.1.tgz#37be5d36e1e06492221e68d474b1ac58e510cbd7" - dependencies: - bindings "1.2.x" - nan "^2.0.5" - builtin-modules@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" builtins@^1.0.3: version "1.0.3" @@ -1725,10 +1686,6 @@ camelcase@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" -camelcase@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" - can-symlink@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" @@ -1853,18 +1810,6 @@ chokidar@1.7.0: optionalDependencies: fsevents "^1.0.0" -chrome-debugging-client@^0.2.4: - version "0.2.5" - resolved "https://registry.yarnpkg.com/chrome-debugging-client/-/chrome-debugging-client-0.2.5.tgz#b8e1a6c37283323b6ff5d60525f6ea1fc8899fbd" - dependencies: - "@types/node" "^7.0.5" - "@types/rimraf" "^0.0.28" - "@types/tape" "^4.2.29" - "@types/ws" "^0.0.38" - mktemp "^0.4.0" - rimraf "^2.5.1" - ws "^1.0.1" - circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" @@ -1940,14 +1885,6 @@ cliui@^2.1.0: right-align "^0.1.1" wordwrap "0.0.2" -cliui@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - clone-response@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" @@ -2282,7 +2219,7 @@ debug@^3.0.0, debug@^3.1.0: dependencies: ms "2.0.0" -decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: +decamelize@^1.0.0, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -3084,7 +3021,7 @@ entities@~1.1.1: error-ex@^1.2.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" dependencies: is-arrayish "^0.2.1" @@ -3372,7 +3309,7 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2: dependencies: homedir-polyfill "^1.0.1" -express@^4.10.7, express@^4.12.3, express@^4.13.1, express@^4.14.0: +express@^4.10.7, express@^4.12.3, express@^4.13.1: version "4.16.2" resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" dependencies: @@ -3463,10 +3400,6 @@ fake-xml-http-request@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-1.6.0.tgz#bd0ac79ae3e2660098282048a12c730a6f64d550" -faker@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/faker/-/faker-3.1.0.tgz#0f908faf4e6ec02524e54a57e432c5c013e08c9f" - fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" @@ -3567,7 +3500,7 @@ find-index@^1.1.0: find-up@^1.0.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" @@ -3823,7 +3756,7 @@ generate-object-property@^1.1.0: dependencies: is-property "^1.0.0" -get-caller-file@^1.0.0, get-caller-file@^1.0.1: +get-caller-file@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" @@ -3923,7 +3856,7 @@ glob@^5.0.10, glob@^5.0.13, glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1: +glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -4146,19 +4079,6 @@ hawk@3.1.3, hawk@~3.1.3: hoek "2.x.x" sntp "1.x.x" -heimdall-query@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/heimdall-query/-/heimdall-query-0.1.0.tgz#4b1bb8de46dc292f2f10620bee4f81b2f5443937" - dependencies: - chalk "^1.1.1" - chrome-debugging-client "^0.2.4" - cli-table "^0.3.1" - lodash "^4.15.0" - outliers "0.0.3" - plain-text-box-plot "0.0.1" - progress "^1.1.8" - selenium-webdriver "2.48.2" - heimdalljs-fs-monitor@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.1.0.tgz#d404a65688c6714c485469ed3495da4853440272" @@ -4735,17 +4655,6 @@ jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" -json-api-mock-server@0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/json-api-mock-server/-/json-api-mock-server-0.1.1.tgz#00acb22ac58127e87fa9a172159cd8ed558e8106" - dependencies: - body-parser "^1.15.2" - chalk "^1.1.1" - express "^4.14.0" - glob "^7.1.1" - jsonapi-validator "^2.1.1" - object-assign "^4.1.0" - json-buffer@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" @@ -4776,13 +4685,6 @@ json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" -jsonapi-validator@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/jsonapi-validator/-/jsonapi-validator-2.2.0.tgz#07f9bdb6d118c1e728fa77280605fa9b527f8c66" - dependencies: - ajv "^4.1.3" - yargs "^5.0.0" - jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" @@ -4897,7 +4799,7 @@ livereload-js@^2.3.0: load-json-file@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -5058,10 +4960,6 @@ lodash.assign@^3.2.0: lodash._createassigner "^3.0.0" lodash.keys "^3.0.0" -lodash.assign@^4.1.0, lodash.assign@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" - lodash.assignin@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" @@ -5239,9 +5137,9 @@ lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.16.1, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1: - version "4.17.5" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.16.1, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" log-symbols@^2.2.0: version "2.2.0" @@ -5568,7 +5466,7 @@ moment-timezone@^0.3.0: version "2.21.0" resolved "https://registry.yarnpkg.com/moment/-/moment-2.21.0.tgz#2a114b51d2a6ec9e6d83cf803f838a878d8a023a" -morgan@^1.7.0, morgan@^1.8.1: +morgan@^1.8.1: version "1.9.0" resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.0.tgz#d01fa6c65859b76fcf31b3cb53a3821a311d8051" dependencies: @@ -5606,14 +5504,10 @@ mute-stream@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" -nan@^2.0.5, nan@^2.3.0: +nan@^2.3.0: version "2.9.2" resolved "https://registry.yarnpkg.com/nan/-/nan-2.9.2.tgz#f564d75f5f8f36a6d9456cca7a6c4fe488ab7866" -nan@~2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232" - nanomatch@^1.2.9: version "1.2.9" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" @@ -5878,10 +5772,6 @@ osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" -outliers@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/outliers/-/outliers-0.0.3.tgz#4d8329bf25340495b628d3997016525d097dd5b8" - output-file-sync@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" @@ -5935,7 +5825,7 @@ parse-glob@^3.0.4: parse-json@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" dependencies: error-ex "^1.2.0" @@ -5981,7 +5871,7 @@ path-exists@^1.0.0: path-exists@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" dependencies: pinkie-promise "^2.0.0" @@ -6015,7 +5905,7 @@ path-to-regexp@0.1.7: path-type@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" dependencies: graceful-fs "^4.1.2" pify "^2.0.0" @@ -6047,10 +5937,6 @@ pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" -plain-text-box-plot@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/plain-text-box-plot/-/plain-text-box-plot-0.0.1.tgz#d3b2e53071ea6706972318565761242f779c04b8" - pluralize@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" @@ -6240,7 +6126,19 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^2, readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2: +readable-stream@^2, readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.2.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + safe-buffer "~5.1.1" + string_decoder "~1.0.3" + util-deprecate "~1.0.1" + +readable-stream@^2.0.2, readable-stream@^2.1.4: version "2.3.5" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.5.tgz#b4f85003a938cbb6ecbce2a124fb1012bd1a838d" dependencies: @@ -6460,14 +6358,6 @@ request@~2.40.0: tough-cookie ">=0.12.0" tunnel-agent "~0.4.0" -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - require-uncached@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -6643,10 +6533,6 @@ sane@^2.2.0, sane@^2.4.1: optionalDependencies: fsevents "^1.1.1" -sax@0.6.x: - version "0.6.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-0.6.1.tgz#563b19c7c1de892e09bfc4f2fc30e3c27f0952b9" - sax@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" @@ -6655,17 +6541,7 @@ sax@>=0.6.0: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -selenium-webdriver@2.48.2: - version "2.48.2" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-2.48.2.tgz#b26a4631430d0a9f36284ee0cfe09676e8f348ca" - dependencies: - adm-zip "0.4.4" - rimraf "^2.2.8" - tmp "0.0.24" - ws "^0.8.0" - xml2js "0.4.4" - -"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0, semver@^5.4.1: +"semver@2 || 3 || 4 || 5", semver@^5.4.1: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" @@ -6673,6 +6549,10 @@ semver@^4.3.1: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" +semver@^5.1.0, semver@^5.1.1, semver@^5.3.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + semver@~5.0.1: version "5.0.3" resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" @@ -6704,7 +6584,7 @@ serve-static@1.13.1: parseurl "~1.3.2" send "0.16.1" -set-blocking@^2.0.0, set-blocking@~2.0.0: +set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -7124,7 +7004,7 @@ strip-ansi@^4.0.0: strip-bom@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" dependencies: is-utf8 "^0.2.0" @@ -7336,10 +7216,6 @@ tmp-sync@^1.0.0: fs-sync "^1.0.4" osenv "^0.1.0" -tmp@0.0.24: - version "0.0.24" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.24.tgz#d6a5e198d14a9835cc6f2d7c3d9e302428c8cf12" - tmp@0.0.28: version "0.0.28" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" @@ -7600,13 +7476,6 @@ username@^1.0.1: dependencies: meow "^3.4.0" -utf-8-validate@1.2.x: - version "1.2.2" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-1.2.2.tgz#8bb871a4741e085c70487ca7acdbd7d6d36029eb" - dependencies: - bindings "~1.2.1" - nan "~2.4.0" - util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -7704,10 +7573,6 @@ websocket-extensions@>=0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" -which-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" - which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" @@ -7728,10 +7593,6 @@ window-size@^0.1.2: version "0.1.4" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" -window-size@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" - wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" @@ -7750,13 +7611,6 @@ workerpool@^2.3.0: dependencies: object-assign "4.1.1" -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -7790,23 +7644,6 @@ ws@1.1.1: options ">=0.0.5" ultron "1.0.x" -ws@^0.8.0: - version "0.8.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-0.8.1.tgz#6b65273b99193c5f067a4cf5809598f777e3b759" - dependencies: - options ">=0.0.5" - ultron "1.0.x" - optionalDependencies: - bufferutil "1.2.x" - utf-8-validate "1.2.x" - -ws@^1.0.1: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51" - dependencies: - options ">=0.0.5" - ultron "1.0.x" - wtf-8@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" @@ -7828,23 +7665,12 @@ xml2js@0.4.17: sax ">=0.6.0" xmlbuilder "^4.1.0" -xml2js@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.4.tgz#3111010003008ae19240eba17497b57c729c555d" - dependencies: - sax "0.6.x" - xmlbuilder ">=1.0.0" - xmlbuilder@4.2.1, xmlbuilder@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" dependencies: lodash "^4.0.0" -xmlbuilder@>=1.0.0: - version "9.0.7" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" - xmldom@^0.1.19: version "0.1.27" resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" @@ -7857,7 +7683,7 @@ xtend@^4.0.0, xtend@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" -y18n@^3.2.0, y18n@^3.2.1: +y18n@^3.2.0: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" @@ -7872,32 +7698,6 @@ yam@0.0.22: fs-extra "^0.30.0" lodash.merge "^4.4.0" -yargs-parser@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-3.2.0.tgz#5081355d19d9d0c8c5d81ada908cb4e6d186664f" - dependencies: - camelcase "^3.0.0" - lodash.assign "^4.1.0" - -yargs@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-5.0.0.tgz#3355144977d05757dbb86d6e38ec056123b3a66e" - dependencies: - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - lodash.assign "^4.2.0" - os-locale "^1.4.0" - read-pkg-up "^1.0.1" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^1.0.2" - which-module "^1.0.0" - window-size "^0.2.0" - y18n "^3.2.1" - yargs-parser "^3.2.0" - yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" From 7eaf18c11037aa4d2559ec21f1cd7a0a5d08ccc9 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 29 Mar 2018 14:02:29 -0700 Subject: [PATCH 2169/2527] make options the last arg --- addon/-private/system/store.js | 33 ++++++++++--------- .../integration/adapter/store-adapter-test.js | 6 ++-- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 3f4ed0c72d9..f4ef346a373 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1261,20 +1261,22 @@ Store = Service.extend({ @method query @param {String} modelName @param {any} query an opaque query to be used by the adapter + @param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.query @return {Promise} promise */ - query(modelName, query) { + query(modelName, query, options) { assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); assert(`You need to pass a query hash to the store's query method`, query); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let options = {}; + let adapterOptionsWrapper = {}; - options.adapterOptions = query.adapterOptions; - delete query.adapterOptions; + if (options && options.adapterOptions) { + adapterOptionsWrapper.adapterOptions = options.adapterOptions + } let normalizedModelName = normalizeModelName(modelName); - return this._query(normalizedModelName, query, null, options); + return this._query(normalizedModelName, query, null, adapterOptionsWrapper); }, _query(modelName, query, array, options) { @@ -1394,26 +1396,26 @@ Store = Service.extend({ @method queryRecord @param {String} modelName @param {any} query an opaque query to be used by the adapter + @param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.queryRecord @return {Promise} promise which resolves with the found record or `null` */ - queryRecord(modelName, query) { + queryRecord(modelName, query, options) { assert(`You need to pass a model name to the store's queryRecord method`, isPresent(modelName)); assert(`You need to pass a query hash to the store's queryRecord method`, query); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); let normalizedModelName = normalizeModelName(modelName); - let adapter = this.adapterFor(normalizedModelName); + let adapterOptionsWrapper = {}; - let options = {}; - - options.adapterOptions = query.adapterOptions; - delete query.adapterOptions; + if (options && options.adapterOptions) { + adapterOptionsWrapper.adapterOptions = options.adapterOptions + } assert(`You tried to make a query but you have no adapter (for ${normalizedModelName})`, adapter); assert(`You tried to make a query but your adapter does not implement 'queryRecord'`, typeof adapter.queryRecord === 'function'); - return promiseObject(_queryRecord(adapter, this, modelName, query, options).then(internalModel => { + return promiseObject(_queryRecord(adapter, this, modelName, query, adapterOptionsWrapper).then(internalModel => { // the promise returned by store.queryRecord is expected to resolve with // an instance of DS.Model if (internalModel) { @@ -1788,10 +1790,11 @@ Store = Service.extend({ @param {String} modelName @param {Object} query optional query @param {Function} filter + @param {Object} options optional, options to be passed to store.query @return {DS.PromiseArray} @deprecated */ - filter(modelName, query, filter) { + filter(modelName, query, filter, options) { assert(`You need to pass a model name to the store's filter method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); @@ -1802,13 +1805,13 @@ Store = Service.extend({ let promise; let length = arguments.length; let array; - let hasQuery = length === 3; + let hasQuery = length >= 3; let normalizedModelName = normalizeModelName(modelName); // allow an optional server query if (hasQuery) { - promise = this.query(normalizedModelName, query); + promise = this.query(normalizedModelName, query, options); } else if (arguments.length === 2) { filter = query; } diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 5382a7adbf4..d25b4dd1981 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -1378,7 +1378,7 @@ test("store.query should pass adapterOptions to adapter.query ", function(assert }; return run(() => { - return store.query('person', { adapterOptions: { query: { embed: true } } }); + return store.query('person', {}, { adapterOptions: { query: { embed: true } } }); }); }); @@ -1392,7 +1392,7 @@ test("store.filter should pass adapterOptions to adapter.query", function(assert }; return run(() => { - return store.filter('person', { adapterOptions: { query: { embed: true } } }, () => {}); + return store.filter('person', {}, () => {}, { adapterOptions: { query: { embed: true } } }); }); }); @@ -1406,7 +1406,7 @@ test("store.queryRecord should pass adapterOptions to adapter.queryRecord", func }; return run(() => { - return store.queryRecord('person', { adapterOptions: { query: { embed: true } } }); + return store.queryRecord('person', {}, { adapterOptions: { query: { embed: true } } }); }); }); From 89f76ebf9acfc4e12b6dc2e153031f8b44172c4c Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 29 Mar 2018 14:33:40 -0700 Subject: [PATCH 2170/2527] [CHORE] remove dead methods left behind from ff removal --- addon/adapters/json-api.js | 20 -------------------- addon/adapters/rest.js | 20 -------------------- 2 files changed, 40 deletions(-) diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index fa85c6a1e93..c6f0004901b 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -266,26 +266,6 @@ const JSONAPIAdapter = RESTAdapter.extend({ let url = this.buildURL(type.modelName, snapshot.id, snapshot, 'updateRecord'); return this.ajax(url, 'PATCH', { data: data }); - }, - - _hasCustomizedAjax() { - if (this.ajax !== JSONAPIAdapter.prototype.ajax) { - deprecate('JSONAPIAdapter#ajax has been deprecated please use. `methodForRequest`, `urlForRequest`, `headersForRequest` or `dataForRequest` instead.', false, { - id: 'ds.json-api-adapter.ajax', - until: '3.0.0' - }); - return true; - } - - if (this.ajaxOptions !== JSONAPIAdapter.prototype.ajaxOptions) { - deprecate('JSONAPIAdapterr#ajaxOptions has been deprecated please use. `methodForRequest`, `urlForRequest`, `headersForRequest` or `dataForRequest` instead.', false, { - id: 'ds.json-api-adapter.ajax-options', - until: '3.0.0' - }); - return true; - } - - return false; } }); diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index d5f30682fa4..189179360eb 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1130,26 +1130,6 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { } return query; - }, - - _hasCustomizedAjax() { - if (this.ajax !== RESTAdapter.prototype.ajax) { - deprecate('RESTAdapter#ajax has been deprecated please use. `methodForRequest`, `urlForRequest`, `headersForRequest` or `dataForRequest` instead.', false, { - id: 'ds.rest-adapter.ajax', - until: '3.0.0' - }); - return true; - } - - if (this.ajaxOptions !== RESTAdapter.prototype.ajaxOptions) { - deprecate('RESTAdapter#ajaxOptions has been deprecated please use. `methodForRequest`, `urlForRequest`, `headersForRequest` or `dataForRequest` instead.', false, { - id: 'ds.rest-adapter.ajax-options', - until: '3.0.0' - }); - return true; - } - - return false; } }); From 74d2d7674fe53eb8051276574234f2823d24d027 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 29 Mar 2018 14:47:08 -0700 Subject: [PATCH 2171/2527] remove import of deprecate --- addon/adapters/json-api.js | 1 - addon/adapters/rest.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index c6f0004901b..9d59c572f78 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -4,7 +4,6 @@ */ import { dasherize } from '@ember/string'; import RESTAdapter from "./rest"; -import { deprecate } from '@ember/debug'; import { instrument } from 'ember-data/-debug'; import { pluralize } from 'ember-inflector'; diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 189179360eb..330457242dd 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -24,7 +24,7 @@ import { MapWithDefault } from '../-private'; import { instrument } from 'ember-data/-debug'; -import { warn, deprecate } from '@ember/debug'; +import { warn } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; const Promise = EmberPromise; From dbf0acac1390f10e92a5128ce292acc2e090b9c8 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 29 Mar 2018 20:00:28 -0400 Subject: [PATCH 2172/2527] [BUGFIX release] Fix `Model.modelName` inheritance with Ember 3.2+. On Ember 3.2 and higher, Ember uses "real" inheritance when an `Ember.Object` is `.extend()`ed. This means that in 3.2 and higher the `ModelClassHere.modelName` property is now being inherited (where previously each `.extend()` reset the value to `null`). The fix here ensures that each `ModelClass.extend()` gets its own `modelName`... --- addon/-private/system/store.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index f4ef346a373..1a138bc8763 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2144,7 +2144,10 @@ Store = Service.extend({ assert(`'${inspect(klass)}' does not appear to be an ember-data model`, klass.isModel); // TODO: deprecate this - klass.modelName = klass.modelName || modelName; + let hasOwnModelNameSet = klass.modelName && klass.hasOwnProperty('modelName'); + if (!hasOwnModelNameSet) { + klass.modelName = modelName; + } this._modelFactoryCache[modelName] = factory; } From 342de276cd605a6621ef2e34b3be7cfa6a49ffb2 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 29 Mar 2018 20:03:36 -0400 Subject: [PATCH 2173/2527] [BUGFIX release] Fix toString test to work with Ember 3.2+. This test was attempting to ensure that the records guid was included in the `record.toString()` output, but changes in Ember 3.2+ changed the default output of the class / constructor name portion (therefore failing the assertion in a useless way). This updates the test to add a custom `toString` to the model class so that we can be decoupled from how Ember `.toString()`'s classes when there is no custom `.toString` setup (because this is actually fairly unstable version over version). --- tests/unit/model-test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 16cd9b9707a..3b0ebe9a070 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -18,6 +18,7 @@ module('unit/model - DS.Model', { name: DS.attr('string'), isDrugAddict: DS.attr('boolean') }); + Person.toString = () => 'person'; env = setupStore({ person: Person @@ -268,7 +269,7 @@ test("a record's id is included in its toString representation", function(assert }); return store.findRecord('person', 1).then(record => { - assert.equal(record.toString(), `<(subclass of DS.Model):${guidFor(record)}:1>`, 'reports id in toString'); + assert.equal(record.toString(), ``, 'reports id in toString'); }); }); }); From 948201c56ff941a1924a28806c2773b980f24d6a Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Fri, 16 Mar 2018 14:53:15 -0700 Subject: [PATCH 2174/2527] Bring support for FastBoot in ember-data --- addon/adapters/rest.js | 55 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 330457242dd..4cd4b4b087f 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1,4 +1,5 @@ /* global heimdall */ +/* globals najax */ /** @module ember-data */ @@ -6,7 +7,8 @@ import $ from 'jquery'; import { Promise as EmberPromise } from 'rsvp'; -import { get } from '@ember/object'; +import { get, computed } from '@ember/object'; +import { getOwner } from '@ember/application'; import { run } from '@ember/runloop'; import Adapter from "../adapter"; import { @@ -293,6 +295,10 @@ const Promise = EmberPromise; const RESTAdapter = Adapter.extend(BuildURLMixin, { defaultSerializer: '-rest', + fastboot: computed(function() { + return getOwner(this).lookup('service:fastboot'); + }), + /** By default, the RESTAdapter will send the query params sorted alphabetically to the server. @@ -988,7 +994,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { run.join(null, reject, error); }; - adapter._ajaxRequest(hash); + adapter._ajax(hash); }, 'DS: RESTAdapter#ajax ' + type + ' to ' + url); }, @@ -1001,6 +1007,27 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { $.ajax(options); }, + /** + @method _najaxRequest + @private + @param {Object} options jQuery ajax options to be used for the najax request + */ + _najaxRequest(options) { + if (typeof najax !== 'undefined') { + najax(options); + } else { + throw new Error('najax does not seem to be defined in your app. Did you override it via `addOrOverrideSandboxGlobals` in the fastboot server?'); + } + }, + + _ajax(options) { + if (get(this, 'fastboot.isFastBoot')) { + this._najaxRequest(options); + } else { + this._ajaxRequest(options); + } + }, + /** @method ajaxOptions @private @@ -1011,7 +1038,6 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { */ ajaxOptions(url, type, options) { let hash = options || {}; - hash.url = url; hash.type = type; hash.dataType = 'json'; hash.context = this; @@ -1044,9 +1070,32 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { }; } + hash.url = this._ajaxURL(url); + return hash; }, + _ajaxURL(url) { + if (get(this, 'fastboot.isFastBoot')) { + let httpRegex = /^https?:\/\//; + let protocolRelativeRegex = /^\/\//; + let protocol = get(this, 'fastboot.request.protocol'); + let host = get(this, 'fastboot.request.host'); + + if (protocolRelativeRegex.test(url)) { + return `${protocol}${url}`; + } else if (!httpRegex.test(url)) { + try { + return `${protocol}//${host}${url}`; + } catch (fbError) { + throw new Error('You are using Ember Data with no host defined in your adapter. This will attempt to use the host of the FastBoot request, which is not configured for the current host of this request. Please set the hostWhitelist property for in your environment.js. FastBoot Error: ' + fbError.message); + } + } + } + + return url; + }, + /** @method parseErrorResponse @private From dd2662e11d4c80e835ca7b84e08ee7727563afeb Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Fri, 16 Mar 2018 16:09:13 -0700 Subject: [PATCH 2175/2527] Refactor for more jQuery.ajax isolation --- addon/adapters/rest.js | 50 +++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 4cd4b4b087f..140126fceca 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -974,23 +974,17 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { url: url, method: type }; + let hash = adapter.ajaxOptions(url, type, options); return new Promise(function(resolve, reject) { - let hash = adapter.ajaxOptions(url, type, options); - hash.success = function(payload, textStatus, jqXHR) { heimdall.stop(token); - let response = ajaxSuccess(adapter, jqXHR, payload, requestData); + let response = ajaxSuccessHandler(adapter, payload, jqXHR, requestData); run.join(null, resolve, response); }; - hash.error = function(jqXHR, textStatus, errorThrown) { heimdall.stop(token); - let responseData = { - textStatus, - errorThrown - }; - let error = ajaxError(adapter, jqXHR, requestData, responseData); + let error = ajaxErrorHandler(adapter, jqXHR, errorThrown, requestData); run.join(null, reject, error); }; @@ -1182,12 +1176,12 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { } }); -function ajaxSuccess(adapter, jqXHR, payload, requestData) { +function ajaxSuccess(adapter, payload, requestData, responseData) { let response; try { response = adapter.handleResponse( - jqXHR.status, - parseResponseHeaders(jqXHR.getAllResponseHeaders()), + responseData.status, + responseData.headers, payload, requestData ); @@ -1202,10 +1196,10 @@ function ajaxSuccess(adapter, jqXHR, payload, requestData) { } } -function ajaxError(adapter, jqXHR, requestData, responseData) { +function ajaxError(adapter, payload, requestData, responseData) { if (DEBUG) { let message = `The server returned an empty string for ${requestData.method} ${requestData.url}, which cannot be parsed into a valid JSON. Return either null or {}.`; - let validJSONString = !(responseData.textStatus === "parsererror" && jqXHR.responseText === ""); + let validJSONString = !(responseData.textStatus === "parsererror" && payload === ""); warn(message, validJSONString, { id: 'ds.adapter.returned-empty-string-as-JSON' }); @@ -1217,14 +1211,14 @@ function ajaxError(adapter, jqXHR, requestData, responseData) { error = responseData.errorThrown; } else if (responseData.textStatus === 'timeout') { error = new TimeoutError(); - } else if (responseData.textStatus === 'abort' || jqXHR.status === 0) { + } else if (responseData.textStatus === 'abort' || responseData.status === 0) { error = new AbortError(); } else { try { error = adapter.handleResponse( - jqXHR.status, - parseResponseHeaders(jqXHR.getAllResponseHeaders()), - adapter.parseErrorResponse(jqXHR.responseText) || responseData.errorThrown, + responseData.status, + responseData.headers, + payload || responseData.errorThrown, requestData ); } catch (e) { @@ -1244,4 +1238,24 @@ function endsWith(string, suffix) { } } +function ajaxSuccessHandler(adapter, payload, jqXHR, requestData) { + let responseData = ajaxResponseData(jqXHR); + return ajaxSuccess(adapter, payload, requestData, responseData); +} + +function ajaxErrorHandler(adapter, jqXHR, errorThrown, requestData) { + let responseData = ajaxResponseData(jqXHR); + responseData.errorThrown = errorThrown; + let payload = adapter.parseErrorResponse(jqXHR.responseText); + return ajaxError(adapter, payload, requestData, responseData); +} + +function ajaxResponseData(jqXHR) { + return { + status: jqXHR.status, + textStatus: jqXHR.textStatus, + headers: parseResponseHeaders(jqXHR.getAllResponseHeaders()) + }; +} + export default RESTAdapter; From 7c193c5862082abca8278586dfcc7e8b60e8bf9b Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Fri, 30 Mar 2018 11:19:16 -0400 Subject: [PATCH 2176/2527] remove `id` observer from DS.Model (#5407) --- addon/-private/system/model/internal-model.js | 7 +++-- addon/-private/system/model/model.js | 28 +++++++++++++------ tests/unit/model-test.js | 27 ++++++++++++++++++ 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 959550bd3ef..1cdc5afe5ef 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -344,7 +344,6 @@ export default class InternalModel { let createOptions = { store: this.store, _internalModel: this, - id: this.id, currentState: this.currentState, isError: this.isError, adapterError: this.error @@ -1019,9 +1018,11 @@ export default class InternalModel { setId(id) { assert('A record\'s id cannot be changed once it is in the loaded state', this.id === null || this.id === id || this.isNew()); + let didChange = id !== this.id; this.id = id; - if (this._record.get('id') !== id) { - this._record.set('id', id); + + if (didChange && this.hasRecord) { + this._record.notifyPropertyChange('id'); } } diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 9963195b06a..547ea49f3e4 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -4,8 +4,7 @@ import EmberError from '@ember/error'; import Evented from '@ember/object/evented'; import EmberObject, { computed, - get, - observer + get } from '@ember/object'; import Map from '../map'; import { DEBUG } from '@glimmer/env'; @@ -340,7 +339,6 @@ const Model = EmberObject.extend(Evented, { @property id @type {String} */ - id: null, /** @property currentState @@ -744,7 +742,10 @@ const Model = EmberObject.extend(Evented, { }, toStringExtension() { - return get(this, 'id'); + // the _internalModel guard exists, because some dev-only deprecation code + // (addListener via validatePropertyInjections) invokes toString before the + // object is real. + return this._internalModel && this._internalModel.id; }, /** @@ -980,10 +981,6 @@ const Model = EmberObject.extend(Evented, { return this._internalModel.referenceFor('hasMany', name); }, - setId: observer('id', function () { - this._internalModel.setId(this.get('id')); - }), - /** Provides info about the model for debugging purposes by grouping the properties into more semantic groups. @@ -1133,11 +1130,26 @@ const Model = EmberObject.extend(Evented, { @type {Object} */ Object.defineProperty(Model.prototype, 'data', { + configurable: false, get() { return this._internalModel._data; } }); +Object.defineProperty(Model.prototype, 'id', { + configurable: false, + set(id) { + this._internalModel.setId(id); + }, + + get() { + // the _internalModel guard exists, because some dev-only deprecation code + // (addListener via validatePropertyInjections) invokes toString before the + // object is real. + return this._internalModel && this._internalModel.id; + } +}); + if (DEBUG) { Model.reopen({ init() { diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 3b0ebe9a070..b30da69289f 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -1329,3 +1329,30 @@ test('accessing the model id without the get function should work when id is wat assert.equal(person.id, 'john', 'new id should be correctly set.'); }); }); + + +test('ID mutation (complicated)', function(assert) { + assert.expect(5); + let idChange = 0; + const Person = DS.Model.extend({ + name: DS.attr('string'), + idComputed: Ember.computed('id', function() {}), + idDidChange: Ember.observer('id', () => idChange++) + }); + + let { store } = setupStore({ + person: Person.extend() + }); + + run(() => { + let person = store.createRecord('person'); + person.get('idComputed'); + assert.equal(idChange, 0); + + assert.equal(person.get('id'), null, 'initial created model id should be null'); + assert.equal(idChange, 0); + store.updateId(person._internalModel, { id: 'john' }); + assert.equal(idChange, 1); + assert.equal(person.id, 'john', 'new id should be correctly set.'); + }); +}); From 6b380e1a1ace41381e404f0030ce3ee67b67c76a Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 2 Apr 2018 15:51:13 -0700 Subject: [PATCH 2177/2527] FIX push on deleted --- addon/-private/system/model/states.js | 3 +- .../relationships/json-api-links-test.js | 0 tests/unit/model-test.js | 50 ++++++++++++++++++- 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 tests/integration/relationships/json-api-links-test.js diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index 080941fd4b3..e1edd9bff92 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -701,7 +701,8 @@ const RootState = { }, willCommit() { }, - didCommit() { } + didCommit() { }, + pushedData() {} }, invalid: { diff --git a/tests/integration/relationships/json-api-links-test.js b/tests/integration/relationships/json-api-links-test.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index b30da69289f..1f48402fdbb 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -16,11 +16,13 @@ module('unit/model - DS.Model', { beforeEach() { Person = DS.Model.extend({ name: DS.attr('string'), - isDrugAddict: DS.attr('boolean') + isDrugAddict: DS.attr('boolean'), + isArchived: DS.attr() }); Person.toString = () => 'person'; env = setupStore({ + adapter: DS.JSONAPIAdapter, person: Person }); store = env.store; @@ -567,6 +569,52 @@ test('supports pushedData in root.deleted.uncommitted', function(assert) { }); }); +test('supports pushedData in root.deleted.saved', function(assert) { + let { adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.deleteRecord = () => { + return Ember.RSVP.resolve(); + }; + + let record = run(() => store.push({ + data: { + type: 'person', + id: '1', + attributes: { + isArchived: false + } + } + })); + + run(() => { + record.destroyRecord().then(() => { + let currentState = record._internalModel.currentState; + + assert.ok(currentState.stateName === 'root.deleted.saved', + 'record is in a persisted deleted state'); + assert.equal(get(record, 'isDeleted'), true); + assert.ok(store.peekRecord('person', '1') !== null, 'the deleted person is not removed from store (no unload called)'); + }); + }); + + run(() => { + try { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + isArchived: true + } + } + }) + } catch (e) { + assert.ok(false, e); + } + }); +}); + test('currentState is accessible when the record is created', function(assert) { let hash = { data: { From bc2f6e8da1a93865fe2986fb6e357c9a6fd74401 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 2 Apr 2018 17:03:48 -0700 Subject: [PATCH 2178/2527] Add additional test coverage --- tests/unit/model-test.js | 58 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 1f48402fdbb..61c4ce7c4fe 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -569,7 +569,7 @@ test('supports pushedData in root.deleted.uncommitted', function(assert) { }); }); -test('supports pushedData in root.deleted.saved', function(assert) { +test('supports canonical updates via pushedData in root.deleted.saved', function(assert) { let { adapter } = env; adapter.shouldBackgroundReloadRecord = () => false; @@ -608,10 +608,64 @@ test('supports pushedData in root.deleted.saved', function(assert) { isArchived: true } } - }) + }); } catch (e) { assert.ok(false, e); } + + let currentState = record._internalModel.currentState; + + assert.ok(currentState.stateName === 'root.deleted.saved', + 'record is still in a persisted deleted state'); + assert.ok(get(record, 'isDeleted') === true, 'The record is still deleted'); + assert.ok(get(record, 'isArchived') === true, 'The record reflects the update to canonical state'); + }); +}); + + +test('Does not support dirtying in root.deleted.saved', function(assert) { + let { adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.deleteRecord = () => { + return Ember.RSVP.resolve(); + }; + + let record = run(() => store.push({ + data: { + type: 'person', + id: '1', + attributes: { + isArchived: false + } + } + })); + + run(() => { + record.destroyRecord().then(() => { + let currentState = record._internalModel.currentState; + + assert.ok(currentState.stateName === 'root.deleted.saved', + 'record is in a persisted deleted state'); + assert.equal(get(record, 'isDeleted'), true); + assert.ok(store.peekRecord('person', '1') !== null, 'the deleted person is not removed from store (no unload called)'); + }); + }); + + run(() => { + try { + set(record, 'isArchived', true); + assert.ok(false, 'Was unable to dirty a deleted record'); + } catch (e) { + assert.ok(true, e.message); + } + + let currentState = record._internalModel.currentState; + + assert.ok(currentState.stateName === 'root.deleted.saved', + 'record is still in a persisted deleted state'); + assert.ok(get(record, 'isDeleted') === true, 'The record is still deleted'); + assert.ok(get(record, 'isArchived') === false, 'The record reflects canonical state'); }); }); From a75f7169fc30cdb077b08b7fcdeb2354e9c33646 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 2 Apr 2018 17:06:59 -0700 Subject: [PATCH 2179/2527] rm ghost file --- tests/integration/relationships/json-api-links-test.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/integration/relationships/json-api-links-test.js diff --git a/tests/integration/relationships/json-api-links-test.js b/tests/integration/relationships/json-api-links-test.js deleted file mode 100644 index e69de29bb2d..00000000000 From ec0fcf05ad4ed6edfb54e4bca10623a69e8e107f Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 2 Apr 2018 17:18:48 -0700 Subject: [PATCH 2180/2527] cleanup tests --- tests/unit/model-test.js | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 61c4ce7c4fe..1c423e819db 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -599,19 +599,15 @@ test('supports canonical updates via pushedData in root.deleted.saved', function }); run(() => { - try { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - isArchived: true - } + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + isArchived: true } - }); - } catch (e) { - assert.ok(false, e); - } + } + }); let currentState = record._internalModel.currentState; @@ -653,12 +649,9 @@ test('Does not support dirtying in root.deleted.saved', function(assert) { }); run(() => { - try { + assert.expectAssertion(() => { set(record, 'isArchived', true); - assert.ok(false, 'Was unable to dirty a deleted record'); - } catch (e) { - assert.ok(true, e.message); - } + }, /Attempted to handle event `didSetProperty` on while in state root.deleted.saved. Called with {name: isArchived, oldValue: false, originalValue: false, value: true}./); let currentState = record._internalModel.currentState; From 4281bdf028df52c4c653c80a1f1493eb60c08739 Mon Sep 17 00:00:00 2001 From: Sylvain MINA Date: Wed, 28 Feb 2018 10:07:05 +0100 Subject: [PATCH 2181/2527] fix initial polymorphic attribute --- addon/-private/system/relationships/state/has-many.js | 1 - addon/-private/system/relationships/state/relationship.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 962a58ffbeb..508552dcde3 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -10,7 +10,6 @@ export default class ManyRelationship extends Relationship { super(store, internalModel, inverseKey, relationshipMeta); this.belongsToType = relationshipMeta.type; this.canonicalState = []; - this.isPolymorphic = relationshipMeta.options.polymorphic; // The ManyArray for this relationship this._manyArray = null; // The previous ManyArray for this relationship. It will be destroyed when diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index d6c97f5e7b9..2760a9ac822 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -68,7 +68,7 @@ export default class Relationship { this.inverseKey = inverseKey; this.internalModel = internalModel; this.isAsync = typeof async === 'undefined' ? true : async; - this.isPolymorphic = typeof polymorphic === 'undefined' ? true : polymorphic; + this.isPolymorphic = typeof polymorphic === 'undefined' ? false : polymorphic; this.relationshipMeta = relationshipMeta; //This probably breaks for polymorphic relationship in complex scenarios, due to //multiple possible modelNames From 856b6040df7476923bd2c6f7233c7133099a709b Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 3 Apr 2018 02:45:02 -0700 Subject: [PATCH 2182/2527] [CHORE] remove deprecated code --- addon/-private/system/model/errors.js | 22 +--------- addon/-private/system/store.js | 59 --------------------------- tests/unit/store/serialize-test.js | 31 -------------- 3 files changed, 1 insertion(+), 111 deletions(-) delete mode 100644 tests/unit/store/serialize-test.js diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index 11c5213b9a0..b955dc1ef61 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -4,7 +4,7 @@ import ArrayProxy from '@ember/array/proxy'; import { set, get, computed } from '@ember/object'; import { makeArray, A } from '@ember/array'; import MapWithDefault from '../map-with-default'; -import { deprecate, warn } from '@ember/debug'; +import { warn } from '@ember/debug'; /** @module ember-data @@ -86,25 +86,6 @@ import { deprecate, warn } from '@ember/debug'; @uses Ember.Evented */ export default ArrayProxy.extend(Evented, { - /** - Register with target handler - - @method registerHandlers - @param {Object} target - @param {Function} becameInvalid - @param {Function} becameValid - @deprecated - */ - registerHandlers(target, becameInvalid, becameValid) { - deprecate( - `Record errors will no longer be evented.`, false, { - id: 'ds.errors.registerHandlers', - until: '3.0.0' - }); - - this._registerHandlers(target, becameInvalid, becameValid); - }, - /** Register with target handler @@ -117,7 +98,6 @@ export default ArrayProxy.extend(Evented, { this.on('becameValid', target, becameValid); }, - /** @property errorsByAttributeName @type {MapWithDefault} diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 1a138bc8763..36efa2542a5 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -256,31 +256,6 @@ Store = Service.extend({ */ adapter: '-json-api', - /** - Returns a JSON representation of the record using a custom - type-specific serializer, if one exists. - - The available options are: - - * `includeId`: `true` if the record's ID should be included in - the JSON representation - - @method serialize - @private - @deprecated - @param {DS.Model} record the record to serialize - @param {Object} options an options hash - */ - serialize(record, options) { - deprecate('Use of store.serialize is deprecated, use record.serialize instead.', false, { - id: 'ds.store.serialize', - until: '3.0' - }); - - let snapshot = record._internalModel.createSnapshot(); - return snapshot.serialize(options); - }, - /** This property returns the adapter, after resolving a possible string key. @@ -1827,24 +1802,6 @@ Store = Service.extend({ return promiseArray(promise.then(() => array, null, `DS: Store#filter of ${normalizedModelName}`)); }, - /** - This method has been deprecated and is an alias for store.hasRecordForId, which should - be used instead. - - @deprecated - @method recordIsLoaded - @param {String} modelName - @param {string} id - @return {boolean} - */ - recordIsLoaded(modelName, id) { - deprecate(`Use of recordIsLoaded is deprecated, use hasRecordForId instead.`, false, { - id: 'ds.store.recordIsLoaded', - until: '3.0' - }); - return this.hasRecordForId(modelName, id); - }, - // .............. // . PERSISTING . @@ -2785,22 +2742,6 @@ Store = Service.extend({ return serializer; }, - lookupAdapter(name) { - deprecate(`Use of lookupAdapter is deprecated, use adapterFor instead.`, false, { - id: 'ds.store.lookupAdapter', - until: '3.0' - }); - return this.adapterFor(name); - }, - - lookupSerializer(name) { - deprecate(`Use of lookupSerializer is deprecated, use serializerFor instead.`, false, { - id: 'ds.store.lookupSerializer', - until: '3.0' - }); - return this.serializerFor(name); - }, - willDestroy() { this._super(...arguments); this._pushedInternalModels = null; diff --git a/tests/unit/store/serialize-test.js b/tests/unit/store/serialize-test.js deleted file mode 100644 index 5378324a9e4..00000000000 --- a/tests/unit/store/serialize-test.js +++ /dev/null @@ -1,31 +0,0 @@ -import { run } from '@ember/runloop'; -import { module } from 'qunit'; -import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import attr from 'ember-data/attr'; -import Model from 'ember-data/model'; -import { createStore } from 'dummy/tests/helpers/store'; - -module("unit/store/serialize - DS.Store#serialize"); - -testInDebug('Store#serialize is deprecated', function(assert) { - let store = createStore({ - person: Model.extend({ firstName: attr() }) - }); - - run(() => { - let person = store.push({ - data: { - type: 'person', - id: 1, - attributes: { - firstName: 'original first name' - } - } - }); - - assert.expectDeprecation(() => { - store.serialize(person); - }, 'Use of store.serialize is deprecated, use record.serialize instead.'); - }); - -}); From 1d0e9f2527b3ff127bfa714e8cfcb54b912263a9 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 3 Apr 2018 02:48:39 -0700 Subject: [PATCH 2183/2527] cleanup --- addon/-private/system/store.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 36efa2542a5..f1aecf14094 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -16,7 +16,7 @@ import { typeOf, isPresent, isNone } from '@ember/utils'; import Ember from 'ember'; import { InvalidError } from '../adapters/errors'; import { instrument } from 'ember-data/-debug'; -import { assert, deprecate, warn, inspect } from '@ember/debug'; +import { assert, warn, inspect } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; import Model from './model/model'; import normalizeModelName from "./normalize-model-name"; @@ -1652,11 +1652,6 @@ Store = Service.extend({ this.recordArrayManager._didUpdateAll(modelName); }, - didUpdateAll(modelName) { - deprecate('didUpdateAll was documented as private and will be removed in the next version of Ember Data.', false, { id: 'ember-data.didUpdateAll', until: '2.17.0' }); - return this._didUpdateAll(modelName); - }, - /** This method returns a filtered array that contains all of the known records for a given type in the store. @@ -2569,11 +2564,6 @@ Store = Service.extend({ return internalModel; }, - buildInternalModel(modelName, id, data) { - deprecate('buildInternalModel was documented as private and will be removed in the next version of Ember Data.', false, { id: 'ember-data.buildInternalModel', until: '2.17.0' }); - return this._buildInternalModel(modelName, id, data); - }, - //Called by the state machine to notify the store that the record is ready to be interacted with recordWasLoaded(record) { this.recordArrayManager.recordWasLoaded(record); From 7f6423270eb9b3df82523f2feb5ce0fd65f7bb52 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 3 Apr 2018 13:09:26 -0700 Subject: [PATCH 2184/2527] [BUGFIX] properly cleanup builds post-test to avoid publishing test artifacts --- .npmignore | 1 + .travis.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.npmignore b/.npmignore index 7f6b54db04f..a77a4b041d4 100644 --- a/.npmignore +++ b/.npmignore @@ -6,6 +6,7 @@ /tmp /bin /docs +/.node_modules.ember-try **/.gitkeep .appveyor.yml diff --git a/.travis.yml b/.travis.yml index 1b6b7ead606..a2dddebc0e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -70,7 +70,7 @@ install: - yarn install script: - - node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO --skip-cleanup + - node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO env: global: From 6dd0dcf4fa7666078a2f1bb58c56806023a63e4d Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 3 Apr 2018 13:10:52 -0700 Subject: [PATCH 2185/2527] keep build speed --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a2dddebc0e2..6811b7897e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,6 +58,7 @@ jobs: env: NAME=publish # used only to make Travis UI show description install: yarn install script: + - node_modules/.bin/ember try:reset - yarn build:production - "./bin/publish-builds" @@ -70,7 +71,7 @@ install: - yarn install script: - - node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO + - node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO --skip-cleanup env: global: From 9a451516f6a41ffc1b70882546aa1e216fc6c184 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 3 Apr 2018 18:07:04 -0700 Subject: [PATCH 2186/2527] [FEAT BUGFIX] adds adapterOptions ability to model.reload() --- addon/-private/system/model/internal-model.js | 4 +- addon/-private/system/model/model.js | 16 ++++++-- addon/-private/system/model/states.js | 8 ++-- addon/-private/system/store.js | 5 ++- tests/integration/records/reload-test.js | 38 +++++++++++++++++++ 5 files changed, 60 insertions(+), 11 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 1cdc5afe5ef..66bfaf82cd7 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -412,13 +412,13 @@ export default class InternalModel { } } - reload() { + reload(options) { this.startedReloading(); let internalModel = this; let promiseLabel = "DS: Model#reload of " + this; return new Promise(function(resolve) { - internalModel.send('reloadRecord', resolve); + internalModel.send('reloadRecord', { resolve, options }); }, promiseLabel).then(function() { internalModel.didCleanError(); return internalModel; diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 547ea49f3e4..b8a1c50a30b 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -816,13 +816,23 @@ const Model = EmberObject.extend(Evented, { ``` @method reload - @return {Promise} a promise that will be resolved with the record when the + @param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter request + + @return {Promise} a promise that will be resolved with the record when the adapter returns successfully or rejected if the adapter returns with an error. */ - reload() { + reload(options) { + let wrappedAdapterOptions; + + if (typeof options === 'object' && options !== null && options.adapterOptions) { + wrappedAdapterOptions = { + adapterOptions: options.adapterOptions + }; + } + return PromiseObject.create({ - promise: this._internalModel.reload().then(() => this) + promise: this._internalModel.reload(wrappedAdapterOptions).then(() => this) }); }, diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index 080941fd4b3..897a7ed7d2b 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -261,8 +261,8 @@ const DirtyState = { internalModel.transitionTo('inFlight'); }, - reloadRecord(internalModel, resolve) { - resolve(internalModel.store._reloadRecord(internalModel)); + reloadRecord(internalModel, { resolve, options }) { + resolve(internalModel.store._reloadRecord(internalModel, options)); }, rolledBack(internalModel) { @@ -580,8 +580,8 @@ const RootState = { internalModel.transitionTo('updated.inFlight'); }, - reloadRecord(internalModel, resolve) { - resolve(internalModel.store._reloadRecord(internalModel)); + reloadRecord(internalModel, { resolve, options }) { + resolve(internalModel.store._reloadRecord(internalModel, options)); }, deleteRecord(internalModel) { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 1a138bc8763..ffa954e3867 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1063,9 +1063,10 @@ Store = Service.extend({ @method reloadRecord @private @param {DS.Model} internalModel + @param options optional to include adapterOptions @return {Promise} promise */ - _reloadRecord(internalModel) { + _reloadRecord(internalModel, options) { let { id, modelName } = internalModel; let adapter = this.adapterFor(modelName); @@ -1073,7 +1074,7 @@ Store = Service.extend({ assert(`You tried to reload a record but you have no adapter (for ${modelName})`, adapter); assert(`You tried to reload a record but your adapter does not implement 'findRecord'`, typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); - return this._scheduleFetch(internalModel); + return this._scheduleFetch(internalModel, options); }, /** diff --git a/tests/integration/records/reload-test.js b/tests/integration/records/reload-test.js index 31ef546fca5..694d801ecb5 100644 --- a/tests/integration/records/reload-test.js +++ b/tests/integration/records/reload-test.js @@ -56,6 +56,44 @@ test("When a single record is requested, the adapter's find method should be cal }); }); +test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function(assert) { + let count = 0; + let reloadOptions = { + adapterOptions: { + makeSnazzy: true + } + }; + + env.adapter.findRecord = function(store, type, id, snapshot) { + if (count === 0) { + count++; + return resolve({ data: { id: id, type: 'person', attributes: { name: "Tom Dale" } } }); + } else if (count === 1) { + assert.equal(snapshot.adapterOptions, reloadOptions.adapterOptions, 'We passed adapterOptions via reload'); + count++; + return resolve({ data: { id: id, type: 'person', attributes: { name: "Braaaahm Dale" } } }); + } else { + assert.ok(false, "Should not get here"); + } + }; + + run(function() { + env.store.findRecord('person', 1).then(function(person) { + assert.equal(get(person, 'name'), "Tom Dale", "The person is loaded with the right name"); + assert.equal(get(person, 'isLoaded'), true, "The person is now loaded"); + + let promise = person.reload(reloadOptions); + + assert.equal(get(person, 'isReloading'), true, "The person is now reloading"); + + return promise; + }).then(function(person) { + assert.equal(get(person, 'isReloading'), false, "The person is no longer reloading"); + assert.equal(get(person, 'name'), "Braaaahm Dale", "The person is now updated with the right name"); + }); + }); +}); + test("When a record is reloaded and fails, it can try again", function(assert) { var tom; run(function() { From a76a6ccf6f92c508f822cc51055bfa38ee96f67e Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 3 Apr 2018 23:33:15 -0700 Subject: [PATCH 2187/2527] adds a more robust test around reload --- tests/integration/store-test.js | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 9bdb7806cc7..621663375ad 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -321,6 +321,47 @@ test("store#findRecord { reload: true } ignores cached record and reloads record }); }); + +test("store#findRecord { reload: true } ignores cached record and reloads record from server even after previous findRecord", function(assert) { + assert.expect(5); + let calls = 0; + + const testAdapter = DS.JSONAPIAdapter.extend({ + shouldReloadRecord(store, type, id, snapshot) { + assert.ok(false, 'shouldReloadRecord should not be called when { reload: true }'); + }, + findRecord() { + calls++; + return resolve({ + data: { + type: 'car', + id: '1', + attributes: { + make: 'BMC', + model: calls === 1 ? 'Mini' : 'Princess' + } + } + }); + } + }); + + initializeStore(testAdapter); + + let car = run(() => store.findRecord('car', '1')); + + assert.equal(calls, 1, 'We made one call to findRecord'); + assert.equal(car.get('model'), 'Mini', 'cached car has expected model'); + + run(() => { + let promiseCar = store.findRecord('car', 1, { reload: true }); + + assert.ok(promiseCar.get('model') === undefined, `We don't have early access to local data`); + }); + + assert.equal(calls, 2, 'We made a second call to findRecord'); + assert.equal(car.get('model'), 'Princess', 'cached record ignored, record reloaded via server'); +}); + test("store#findRecord { backgroundReload: false } returns cached record and does not reload in the background", function(assert) { assert.expect(2); From 484e3a689e711b0c6ba2d70ccc182aafe2b99602 Mon Sep 17 00:00:00 2001 From: Ryan Toronto Date: Fri, 12 Jan 2018 15:29:59 -0500 Subject: [PATCH 2188/2527] Don't serialize new has many relationships --- addon/serializers/json-api.js | 34 +++-- .../serializers/json-api-serializer-test.js | 141 ++++++++++++++++++ yarn.lock | 4 + 3 files changed, 164 insertions(+), 15 deletions(-) diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 0c6684eacd6..77c93fb7c1d 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -516,27 +516,31 @@ const JSONAPISerializer = JSONSerializer.extend({ if (this.shouldSerializeHasMany(snapshot, key, relationship)) { let hasMany = snapshot.hasMany(key); if (hasMany !== undefined) { + // only serialize has many relationships that are not new + let nonNewHasMany = hasMany.filter(item => item.record && !item.record.get('isNew')); - json.relationships = json.relationships || {}; + if (nonNewHasMany.length > 0) { + json.relationships = json.relationships || {}; - let payloadKey = this._getMappedKey(key, snapshot.type); - if (payloadKey === key && this.keyForRelationship) { - payloadKey = this.keyForRelationship(key, 'hasMany', 'serialize'); - } + let payloadKey = this._getMappedKey(key, snapshot.type); + if (payloadKey === key && this.keyForRelationship) { + payloadKey = this.keyForRelationship(key, 'hasMany', 'serialize'); + } - let data = new Array(hasMany.length); + let data = new Array(nonNewHasMany.length); - for (let i = 0; i < hasMany.length; i++) { - let item = hasMany[i]; - let payloadType = this.payloadKeyFromModelName(item.modelName); + for (let i = 0; i < nonNewHasMany.length; i++) { + let item = hasMany[i]; + let payloadType = this.payloadKeyFromModelName(item.modelName); - data[i] = { - type: payloadType, - id: item.id - }; - } + data[i] = { + type: payloadType, + id: item.id + }; - json.relationships[payloadKey] = { data }; + json.relationships[payloadKey] = { data }; + } + } } } } diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 174de5a8bfa..abd221d541f 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -428,6 +428,147 @@ test('a belongsTo relationship set to a new record will not show in the relation }); }); +test('it should serialize a hasMany relationship', function(assert) { + env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ + attrs: { + handles: { serialize: true } + } + })); + + run(function() { + serializer.pushPayload(store, { + data: { + type: 'users', + id: 1, + relationships: { + handles: { + data: [ + { type: 'handles', id: 1 }, + { type: 'handles', id: 2 } + ] + } + } + }, + included: [ + { type: 'handles', id: 1 }, + { type: 'handles', id: 2 } + ] + }); + + let user = store.peekRecord('user', 1); + + let serialized = user.serialize({ includeId: true }); + + assert.deepEqual(serialized, { + data: { + type: 'users', + id: '1', + attributes: { + 'first-name': null, + 'last-name': null, + title: null + }, + relationships: { + handles: { + data: [ + { type: 'handles', id: '1' }, + { type: 'handles', id: '2' } + ] + } + } + } + }); + }); +}); + +test('it should not include new records when serializing a hasMany relationship', function(assert) { + env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ + attrs: { + handles: { serialize: true } + } + })); + + run(function() { + serializer.pushPayload(store, { + data: { + type: 'users', + id: 1, + relationships: { + handles: { + data: [ + { type: 'handles', id: 1 }, + { type: 'handles', id: 2 } + ] + } + } + }, + included: [ + { type: 'handles', id: 1 }, + { type: 'handles', id: 2 } + ] + }); + + let user = store.peekRecord('user', 1); + store.createRecord('handle', { user }); + + let serialized = user.serialize({ includeId: true }); + + assert.deepEqual(serialized, { + data: { + type: 'users', + id: '1', + attributes: { + 'first-name': null, + 'last-name': null, + title: null + }, + relationships: { + handles: { + data: [ + { type: 'handles', id: '1' }, + { type: 'handles', id: '2' } + ] + } + } + } + }); + }); +}); + +test('it should not include any records when serializing a hasMany relationship if they are all new', function(assert) { + env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ + attrs: { + handles: { serialize: true } + } + })); + + run(function() { + serializer.pushPayload(store, { + data: { + type: 'users', + id: 1 + } + }); + + let user = store.peekRecord('user', 1); + store.createRecord('handle', { user }); + + let serialized = user.serialize({ includeId: true }); + + assert.deepEqual(serialized, { + data: { + type: 'users', + id: '1', + attributes: { + 'first-name': null, + 'last-name': null, + title: null + } + } + }); + }); +}); + testInDebug('JSON warns when combined with EmbeddedRecordsMixin', function(assert) { assert.expectWarning(function() { DS.JSONAPISerializer.extend(DS.EmbeddedRecordsMixin).create(); diff --git a/yarn.lock b/yarn.lock index e889abf7128..7cbdcd1e980 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5980,6 +5980,10 @@ private@^0.1.6, private@^0.1.7, private@~0.1.5: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + process-nextick-args@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" From 22d481a8e73c7ca690292907ae12b7cba5d33890 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 3 Apr 2018 13:33:35 -0700 Subject: [PATCH 2189/2527] refactor attr to enable internalModel to set dirty state directly --- addon/-private/system/model/internal-model.js | 36 ++++++++++++++++++ addon/attr.js | 37 +------------------ 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 1cdc5afe5ef..77f8e0c9986 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -602,6 +602,42 @@ export default class InternalModel { } } + getAttributeValue(key) { + if (key in this._attributes) { + return this._attributes[key]; + } else if (key in this._inFlightAttributes) { + return this._inFlightAttributes[key]; + } else { + return this._data[key]; + } + } + + setDirtyAttribute(key, value) { + let oldValue = this.getAttributeValue(key); + let originalValue; + + if (value !== oldValue) { + // Add the new value to the changed attributes hash; it will get deleted by + // the 'didSetProperty' handler if it is no different from the original value + this._attributes[key] = value; + + if (key in this._inFlightAttributes) { + originalValue = this._inFlightAttributes[key]; + } else { + originalValue = this._data[key]; + } + + this.send('didSetProperty', { + name: key, + oldValue: oldValue, + originalValue: originalValue, + value: value + }); + } + + return value; + } + get isDestroyed() { return this._isDestroyed; } diff --git a/addon/attr.js b/addon/attr.js index 2a49d22ed64..48c2e237767 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -22,16 +22,6 @@ function hasValue(record, key) { key in record._data; } -function getValue(record, key) { - if (key in record._attributes) { - return record._attributes[key]; - } else if (key in record._inFlightAttributes) { - return record._inFlightAttributes[key]; - } else { - return record._data[key]; - } -} - /** `DS.attr` defines an attribute on a [DS.Model](/api/data/classes/DS.Model.html). By default, attributes are passed through as-is, however you can specify an @@ -135,36 +125,13 @@ export default function attr(type, options) { get(key) { let internalModel = this._internalModel; if (hasValue(internalModel, key)) { - return getValue(internalModel, key); + return internalModel.getAttributeValue(key); } else { return getDefaultValue(this, options, key); } }, set(key, value) { - let internalModel = this._internalModel; - let oldValue = getValue(internalModel, key); - let originalValue; - - if (value !== oldValue) { - // Add the new value to the changed attributes hash; it will get deleted by - // the 'didSetProperty' handler if it is no different from the original value - internalModel._attributes[key] = value; - - if (key in internalModel._inFlightAttributes) { - originalValue = internalModel._inFlightAttributes[key]; - } else { - originalValue = internalModel._data[key]; - } - - this._internalModel.send('didSetProperty', { - name: key, - oldValue: oldValue, - originalValue: originalValue, - value: value - }); - } - - return value; + return this._internalModel.setDirtyAttribute(key, value); } }).meta(meta); } From 4b32222bfe7705cbc671f9a72fc91fd286c90ce6 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 3 Apr 2018 13:44:21 -0700 Subject: [PATCH 2190/2527] refactor hasMany/belongsTo to enable internal-model to setup dirty state --- addon/-private/system/model/internal-model.js | 26 +++++++++++++++++++ .../system/relationships/belongs-to.js | 11 +------- .../-private/system/relationships/has-many.js | 18 +++---------- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 77f8e0c9986..44aacaf39aa 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -1,4 +1,5 @@ import { assign, merge } from '@ember/polyfills'; +import { A } from '@ember/array'; import { set, get } from '@ember/object'; import { copy } from '@ember/object/internals'; import EmberError from '@ember/error'; @@ -13,6 +14,7 @@ import RootState from "./states"; import Relationships from "../relationships/state/create"; import Snapshot from "../snapshot"; import OrderedSet from "../ordered-set"; +import isArrayLike from "../is-array-like"; import { getOwner } from '../../utils'; @@ -612,6 +614,30 @@ export default class InternalModel { } } + setDirtyHasMany(key, records) { + assert(`You must pass an array of records to set a hasMany relationship`, isArrayLike(records)); + assert(`All elements of a hasMany relationship must be instances of DS.Model, you passed ${inspect(records)}`, (function() { + return A(records).every((record) => record.hasOwnProperty('_internalModel') === true); + })()); + + let relationship = this._relationships.get(key); + relationship.clear(); + relationship.addInternalModels(records.map(record => get(record, '_internalModel'))); + } + + setDirtyBelongsTo(key, value) { + if (value === undefined) { + value = null; + } + if (value && value.then) { + this._relationships.get(key).setRecordPromise(value); + } else if (value) { + this._relationships.get(key).setInternalModel(value._internalModel); + } else { + this._relationships.get(key).setInternalModel(value); + } + } + setDirtyAttribute(key, value) { let oldValue = this.getAttributeValue(key); let originalValue; diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 043d468f02d..8256a5737ee 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -118,16 +118,7 @@ export default function belongsTo(modelName, options) { return this._internalModel._relationships.get(key).getRecord(); }, set(key, value) { - if (value === undefined) { - value = null; - } - if (value && value.then) { - this._internalModel._relationships.get(key).setRecordPromise(value); - } else if (value) { - this._internalModel._relationships.get(key).setInternalModel(value._internalModel); - } else { - this._internalModel._relationships.get(key).setInternalModel(value); - } + this._internalModel.setDirtyBelongsTo(key, value); return this._internalModel._relationships.get(key).getRecord(); } diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index ed353e3bd27..6a575466a41 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -1,13 +1,9 @@ /** @module ember-data */ - -import { A } from '@ember/array'; - -import { get, computed } from '@ember/object'; +import { computed } from '@ember/object'; import { assert, inspect } from '@ember/debug'; import normalizeModelName from "../normalize-model-name"; -import isArrayLike from "../is-array-like"; /** `DS.hasMany` is used to define One-To-Many and Many-To-Many @@ -147,15 +143,9 @@ export default function hasMany(type, options) { return this._internalModel._relationships.get(key).getRecords(); }, set(key, records) { - assert(`You must pass an array of records to set a hasMany relationship`, isArrayLike(records)); - assert(`All elements of a hasMany relationship must be instances of DS.Model, you passed ${inspect(records)}`, (function() { - return A(records).every((record) => record.hasOwnProperty('_internalModel') === true); - })()); - - let relationship = this._internalModel._relationships.get(key); - relationship.clear(); - relationship.addInternalModels(records.map(record => get(record, '_internalModel'))); - return relationship.getRecords(); + this._internalModel.setDirtyHasMany(key, records); + + return this._internalModel._relationships.get(key).getRecords(); } }).meta(meta); } From 64f2db19ce185e7ad4c21ecbc4a0d8ee0eff479b Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 3 Apr 2018 14:06:21 -0700 Subject: [PATCH 2191/2527] adds a failing test for createRecord with properties --- tests/unit/store/create-record-test.js | 65 ++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js index 5fdcc219fa9..6950006d535 100644 --- a/tests/unit/store/create-record-test.js +++ b/tests/unit/store/create-record-test.js @@ -5,6 +5,8 @@ import setupStore from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; import DS from 'ember-data'; +const { Model, attr, belongsTo, hasMany } = DS; + let store, Record, Storage; module('unit/store/createRecord - Store creating records', { @@ -69,6 +71,69 @@ test('allow passing relationships as well as attributes', function(assert) { assert.equal(storage.get('records').findBy('id', '2'), A(records).findBy('id', '2'), 'Defined relationships are allowed in createRecord'); }); +test('createRecord(properties) makes properties available during record init', function(assert) { + assert.expect(4); + let comment; + let author; + + const Post = Model.extend({ + title: attr(), + author: belongsTo('author', { async: false, inverse: 'post' }), + comments: hasMany('comment', { async: false, inverse: 'post' }), + init() { + this._super(...arguments); + assert.ok(this.get('title') === 'My Post', 'Attrs are available as expected'); + assert.ok(this.get('randomProp') === 'An unknown prop', 'Unknown properties are available as expected'); + assert.ok(this.get('author') === author, 'belongsTo relationships are available as expected'); + assert.ok(this.get('comments.firstObject') === comment, 'hasMany relationships are available as expected'); + } + }); + const Comment = Model.extend({ + text: attr(), + post: belongsTo('post', { async: false, inverse: 'comments' }) + }); + const Author = Model.extend({ + name: attr(), + post: belongsTo('post', { async: false, inverse: 'author' }) + }); + let env = setupStore({ + post: Post, + comment: Comment, + author: Author + }); + let store = env.store; + + run(() => { + comment = store.push({ + data: { + type: 'comment', + id: '1', + attributes: { + text: 'Hello darkness my old friend' + } + } + }); + author = store.push({ + data: { + type: 'author', + id: '1', + attributes: { + name: '@runspired' + } + } + }); + }); + + run(() => { + store.createRecord('post', { + title: 'My Post', + randomProp: 'An unknown prop', + comments: [comment], + author + }); + }); +}); + module('unit/store/createRecord - Store with models by dash', { beforeEach() { let env = setupStore({ From 1cbacd382eea7acd3385a18ed00c43f8f110b357 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 3 Apr 2018 15:39:42 -0700 Subject: [PATCH 2192/2527] lets begin by just making internal state setup work --- addon/-private/system/model/internal-model.js | 35 ++++++++++++++++++- addon/-private/system/store.js | 3 +- .../relationships/one-to-many-test.js | 2 +- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 44aacaf39aa..41e72f051c6 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -336,7 +336,7 @@ export default class InternalModel { return this.currentState.dirtyType; } - getRecord() { + getRecord(properties) { if (!this._record && !this._isDematerializing) { heimdall.increment(materializeRecord); let token = heimdall.start('InternalModel.getRecord'); @@ -360,6 +360,39 @@ export default class InternalModel { this._record = this.store.modelFactoryFor(this.modelName).create(createOptions); + if (typeof properties === 'object' && properties !== null) { + let initializedRelationships = []; + let initializedAttributes = []; + + this.eachAttribute((name) => { + if (name in properties) { + initializedAttributes.push(name); + this.setDirtyAttribute(name, properties[name]); + delete properties[name]; + } + }); + this.eachRelationship((name, { kind }) => { + if (name in properties) { + initializedRelationships.push(name); + if (kind === 'belongsTo') { + this.setDirtyBelongsTo(name, properties[name]); + } else { + this.setDirtyHasMany(name, properties[name]); + } + delete properties[name]; + } + }); + + if ('id' in properties) { + this.setId(properties.id); + delete properties.id; + } + + this._record._notifyProperties(initializedAttributes); + this._record._notifyProperties(initializedRelationships); + this._record.setProperties(properties); + } + this._triggerDeferredTriggers(); heimdall.stop(token); } diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 1a138bc8763..1cfaead323f 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -356,8 +356,7 @@ Store = Service.extend({ let internalModel = this._buildInternalModel(normalizedModelName, properties.id); internalModel.loadedData(); - let record = internalModel.getRecord(); - record.setProperties(properties); + let record = internalModel.getRecord(properties); // TODO @runspired this should also be coalesced into some form of internalModel.setState() internalModel.eachRelationship((key, descriptor) => { diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index 3039341b6ec..12bddd0a3e1 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -1481,6 +1481,6 @@ test("createRecord updates inverse record array which has observers", function(a assert.equal(user.get('messages.length'), 1, 'The message is added to the record array'); let messageFromArray = user.get('messages.firstObject'); - assert.equal(message, messageFromArray, 'Only one message should be created'); + assert.ok(message === messageFromArray, 'Only one message should be created'); }); }); From ec2f6dfc8bb52b99352d97542dcb3955b70192c2 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 3 Apr 2018 15:50:10 -0700 Subject: [PATCH 2193/2527] go back to initializing through the record --- addon/-private/system/model/internal-model.js | 37 ++----------------- 1 file changed, 4 insertions(+), 33 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 41e72f051c6..c4aaf3af8a3 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -351,6 +351,10 @@ export default class InternalModel { adapterError: this.error }; + if (typeof properties === 'object' && properties !== null) { + emberAssign(createOptions, properties); + } + if (setOwner) { // ensure that `getOwner(this)` works inside a model instance setOwner(createOptions, getOwner(this.store)); @@ -360,39 +364,6 @@ export default class InternalModel { this._record = this.store.modelFactoryFor(this.modelName).create(createOptions); - if (typeof properties === 'object' && properties !== null) { - let initializedRelationships = []; - let initializedAttributes = []; - - this.eachAttribute((name) => { - if (name in properties) { - initializedAttributes.push(name); - this.setDirtyAttribute(name, properties[name]); - delete properties[name]; - } - }); - this.eachRelationship((name, { kind }) => { - if (name in properties) { - initializedRelationships.push(name); - if (kind === 'belongsTo') { - this.setDirtyBelongsTo(name, properties[name]); - } else { - this.setDirtyHasMany(name, properties[name]); - } - delete properties[name]; - } - }); - - if ('id' in properties) { - this.setId(properties.id); - delete properties.id; - } - - this._record._notifyProperties(initializedAttributes); - this._record._notifyProperties(initializedRelationships); - this._record.setProperties(properties); - } - this._triggerDeferredTriggers(); heimdall.stop(token); } From 07396728f32c94f16b4ddbabe2c3aa748f731de9 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 3 Apr 2018 15:51:40 -0700 Subject: [PATCH 2194/2527] fix setId behavior on createRecord --- addon/-private/system/model/internal-model.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index c4aaf3af8a3..908df8a6a85 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -352,6 +352,12 @@ export default class InternalModel { }; if (typeof properties === 'object' && properties !== null) { + + if ('id' in properties) { + this.setId(properties.id); + delete properties.id; + } + emberAssign(createOptions, properties); } From 74476c853888175bb9b8fa90a518a8e525acba54 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 3 Apr 2018 16:34:49 -0700 Subject: [PATCH 2195/2527] make it all work --- addon/-private/system/many-array.js | 3 ++ addon/-private/system/model/internal-model.js | 30 ++++++++++++- .../system/relationships/state/has-many.js | 44 ++++++++++++++++++- addon/-private/system/store.js | 36 +++++++-------- .../relationships/has-many-test.js | 4 +- 5 files changed, 91 insertions(+), 26 deletions(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 7ea140ff392..f2b8a38ebf6 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -136,6 +136,9 @@ export default EmberObject.extend(MutableArray, Evented, { }, objectAt(index) { + if (this.relationship._willUpdateManyArray) { + this.relationship._flushPendingManyArrayUpdates(); + } let internalModel = this.currentState[index]; if (internalModel === undefined) { return; } diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 908df8a6a85..4bf2467611c 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -350,14 +350,36 @@ export default class InternalModel { isError: this.isError, adapterError: this.error }; + let hasCreateProperties = typeof properties === 'object' && properties !== null; + let initializedRelationships; - if (typeof properties === 'object' && properties !== null) { + if (hasCreateProperties) { + initializedRelationships = []; if ('id' in properties) { this.setId(properties.id); delete properties.id; } + this.eachAttribute((name) => { + if (name in properties) { + this.setDirtyAttribute(name, properties[name]); + delete properties[name]; + } + }); + + this.eachRelationship((name, { kind }) => { + if (name in properties) { + initializedRelationships.push(name); + if (kind === 'belongsTo') { + this.setDirtyBelongsTo(name, properties[name]); + } else { + this.setDirtyHasMany(name, properties[name]); + } + delete properties[name]; + } + }); + emberAssign(createOptions, properties); } @@ -370,6 +392,12 @@ export default class InternalModel { this._record = this.store.modelFactoryFor(this.modelName).create(createOptions); + if (hasCreateProperties && initializedRelationships.length) { + for (let i = 0; i < initializedRelationships.length; i++) { + this._relationships.get(initializedRelationships[i]).setHasData(true); + } + } + this._triggerDeferredTriggers(); heimdall.stop(token); } diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 508552dcde3..edd6d60c8e8 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -17,6 +17,8 @@ export default class ManyRelationship extends Relationship { // inverse internal models are unloaded. this._retainedManyArray = null; this.__loadingPromise = null; + this._willUpdateManyArray = false; + this._pendingManyArrayUpdates = null; } get _loadingPromise() { return this.__loadingPromise; } @@ -109,8 +111,46 @@ export default class ManyRelationship extends Relationship { assertPolymorphicType(this.internalModel, this.relationshipMeta, internalModel); super.addInternalModel(internalModel, idx); - // make lazy later - this.manyArray._addInternalModels([internalModel], idx); + this.scheduleManyArrayUpdate(internalModel, idx); + } + + scheduleManyArrayUpdate(internalModel, idx) { + // ideally we would early exit here, but some tests + // currently suggest that we cannot. + // if (!this._manyArray) { + // return; + // } + + let pending = this._pendingManyArrayUpdates = this._pendingManyArrayUpdates || []; + pending.push(internalModel, idx); + + if (this._willUpdateManyArray === true) { + return; + } + + this._willUpdateManyArray = true; + let backburner = this.store._backburner; + + backburner.join(() => { + backburner.schedule('syncRelationships', this, this._flushPendingManyArrayUpdates); + }); + } + + _flushPendingManyArrayUpdates() { + if (this._willUpdateManyArray === false) { + return; + } + + let pending = this._pendingManyArrayUpdates; + this._pendingManyArrayUpdates = []; + this._willUpdateManyArray = false; + + for (let i = 0; i < pending.length; i += 2) { + let internalModel = pending[i]; + let idx = pending[i + 1]; + + this.manyArray._addInternalModels([internalModel], idx); + } } removeCanonicalInternalModelFromOwn(internalModel, idx) { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 1cfaead323f..6bff79adb83 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -339,33 +339,27 @@ Store = Service.extend({ createRecord(modelName, inputProperties) { assert(`You need to pass a model name to the store's createRecord method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = normalizeModelName(modelName); - let properties = copy(inputProperties) || Object.create(null); - // If the passed properties do not include a primary key, - // give the adapter an opportunity to generate one. Typically, - // client-side ID generators will use something like uuid.js - // to avoid conflicts. + return this._backburner.join(() => { + let normalizedModelName = normalizeModelName(modelName); + let properties = copy(inputProperties) || Object.create(null); - if (isNone(properties.id)) { - properties.id = this._generateId(normalizedModelName, properties); - } + // If the passed properties do not include a primary key, + // give the adapter an opportunity to generate one. Typically, + // client-side ID generators will use something like uuid.js + // to avoid conflicts. - // Coerce ID to a string - properties.id = coerceId(properties.id); + if (isNone(properties.id)) { + properties.id = this._generateId(normalizedModelName, properties); + } - let internalModel = this._buildInternalModel(normalizedModelName, properties.id); - internalModel.loadedData(); - let record = internalModel.getRecord(properties); + // Coerce ID to a string + properties.id = coerceId(properties.id); - // TODO @runspired this should also be coalesced into some form of internalModel.setState() - internalModel.eachRelationship((key, descriptor) => { - if (properties[key] !== undefined) { - internalModel._relationships.get(key).setHasData(true); - } + let internalModel = this._buildInternalModel(normalizedModelName, properties.id); + internalModel.loadedData(); + return internalModel.getRecord(properties); }); - - return record; }, /** diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index fa16f5dc5a2..fa4752eaec3 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -575,13 +575,13 @@ test("A hasMany updated link should not remove new children", function(assert) { return post.get('comments') .then(comments => { - assert.equal(comments.get('length'), 1); + assert.equal(comments.get('length'), 1, 'initially we have one comment'); return post.save(); }) .then(() => post.get('comments')) .then(comments => { - assert.equal(comments.get('length'), 1); + assert.equal(comments.get('length'), 1, 'after saving, we still have one comment'); }); }); }); From 5fbbfab32b7bd26b3ac2c7177ae77a1044c1fbd6 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 4 Apr 2018 11:01:03 -0700 Subject: [PATCH 2196/2527] refactor implementation to not mutate properties --- addon/-private/system/model/internal-model.js | 64 +++++++++---------- tests/unit/model-test.js | 4 +- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 4bf2467611c..d42e2fb5126 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -350,37 +350,39 @@ export default class InternalModel { isError: this.isError, adapterError: this.error }; - let hasCreateProperties = typeof properties === 'object' && properties !== null; - let initializedRelationships; - if (hasCreateProperties) { - initializedRelationships = []; + if (properties !== undefined) { + assert(`You passed '${properties}' as properties for record creation instead of an object.`, typeof properties === 'object' && properties !== null); + let classFields = this.getFields(); + let relationships = this._relationships; + let propertyNames = Object.keys(properties); - if ('id' in properties) { - this.setId(properties.id); - delete properties.id; - } + for (let i = 0; i < propertyNames.length; i++) { + let name = propertyNames[i]; + let fieldType = classFields.get(name); + let propertyValue = properties[name]; - this.eachAttribute((name) => { - if (name in properties) { - this.setDirtyAttribute(name, properties[name]); - delete properties[name]; - } - }); - - this.eachRelationship((name, { kind }) => { - if (name in properties) { - initializedRelationships.push(name); - if (kind === 'belongsTo') { - this.setDirtyBelongsTo(name, properties[name]); - } else { - this.setDirtyHasMany(name, properties[name]); - } - delete properties[name]; + if (name === 'id') { + this.setId(propertyValue); + continue; } - }); - emberAssign(createOptions, properties); + switch (fieldType) { + case 'attribute': + this.setDirtyAttribute(name, propertyValue); + break; + case 'belongsTo': + this.setDirtyBelongsTo(name, propertyValue); + relationships.get(name).setHasData(true); + break; + case 'hasMany': + this.setDirtyHasMany(name, propertyValue); + relationships.get(name).setHasData(true); + break; + default: + createOptions[name] = propertyValue; + } + } } if (setOwner) { @@ -392,12 +394,6 @@ export default class InternalModel { this._record = this.store.modelFactoryFor(this.modelName).create(createOptions); - if (hasCreateProperties && initializedRelationships.length) { - for (let i = 0; i < initializedRelationships.length; i++) { - this._relationships.get(initializedRelationships[i]).setHasData(true); - } - } - this._triggerDeferredTriggers(); heimdall.stop(token); } @@ -405,6 +401,10 @@ export default class InternalModel { return this._record; } + getFields() { + return get(this.modelClass, 'fields'); + } + resetRecord() { this._record = null; this.isReloading = false; diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 1c423e819db..a24aadb08dc 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -1397,7 +1397,7 @@ test('updating the id with store.updateId should correctly when the id property store.updateId(person._internalModel, { id: 'john' }); - assert.equal(person.get('id'), 'john', 'new id should be correctly set.'); + assert.equal(person.id, 'john', 'new id should be correctly set.'); }); }); @@ -1448,6 +1448,6 @@ test('ID mutation (complicated)', function(assert) { assert.equal(idChange, 0); store.updateId(person._internalModel, { id: 'john' }); assert.equal(idChange, 1); - assert.equal(person.id, 'john', 'new id should be correctly set.'); + assert.equal(person.get('id'), 'john', 'new id should be correctly set.'); }); }); From 684f10b231275780e249438a4621b8d40f084a52 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 4 Apr 2018 13:06:51 -0700 Subject: [PATCH 2197/2527] expand test ensuring that properties passed to createRecord are not mutated --- tests/unit/store/create-record-test.js | 60 ++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js index 6950006d535..c00b93803f1 100644 --- a/tests/unit/store/create-record-test.js +++ b/tests/unit/store/create-record-test.js @@ -29,14 +29,66 @@ module('unit/store/createRecord - Store creating records', { }); test(`doesn't modify passed in properties hash`, function(assert) { - let attributes = { foo: 'bar' }; + const Post = Model.extend({ + title: attr(), + author: belongsTo('author', { async: false, inverse: 'post' }), + comments: hasMany('comment', { async: false, inverse: 'post' }) + }); + const Comment = Model.extend({ + text: attr(), + post: belongsTo('post', { async: false, inverse: 'comments' }) + }); + const Author = Model.extend({ + name: attr(), + post: belongsTo('post', { async: false, inverse: 'author' }) + }); + let env = setupStore({ + post: Post, + comment: Comment, + author: Author + }); + let store = env.store; + let comment, author; + + run(() => { + comment = store.push({ + data: { + type: 'comment', + id: '1', + attributes: { + text: 'Hello darkness my old friend' + } + } + }); + author = store.push({ + data: { + type: 'author', + id: '1', + attributes: { + name: '@runspired' + } + } + }); + }); + + let properties = { + title: 'My Post', + randomProp: 'An unknown prop', + comments: [comment], + author + }; + let propertiesClone = { + title: 'My Post', + randomProp: 'An unknown prop', + comments: [comment], + author + }; run(() => { - store.createRecord('record', attributes); - store.createRecord('record', attributes); + store.createRecord('post', properties); }); - assert.deepEqual(attributes, { foo: 'bar' }, 'The properties hash is not modified'); + assert.deepEqual(properties, propertiesClone, 'The properties hash is not modified'); }); test('allow passing relationships as well as attributes', function(assert) { From ba094eeaed4275957d108533f32be6105acf3e17 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 4 Apr 2018 14:10:08 -0700 Subject: [PATCH 2198/2527] add additional test coverage --- tests/unit/model/init-properties-test.js | 234 +++++++++++++++++++++++ tests/unit/store/create-record-test.js | 63 ------ 2 files changed, 234 insertions(+), 63 deletions(-) create mode 100644 tests/unit/model/init-properties-test.js diff --git a/tests/unit/model/init-properties-test.js b/tests/unit/model/init-properties-test.js new file mode 100644 index 00000000000..5651f87679b --- /dev/null +++ b/tests/unit/model/init-properties-test.js @@ -0,0 +1,234 @@ +import { run } from '@ember/runloop'; +import { get } from '@ember/object'; +import { resolve } from 'rsvp'; +import setupStore from 'dummy/tests/helpers/store'; +import { module, test } from 'qunit'; +import DS from 'ember-data'; + +const { JSONAPIAdapter, Model, attr, belongsTo, hasMany } = DS; + +function setupModels(testState) { + let types; + const Comment = Model.extend({ + text: attr(), + post: belongsTo('post', { async: false, inverse: 'comments' }) + }); + const Author = Model.extend({ + name: attr(), + post: belongsTo('post', { async: false, inverse: 'author' }) + }); + const Post = Model.extend({ + title: attr(), + author: belongsTo('author', { async: false, inverse: 'post' }), + comments: hasMany('comment', { async: false, inverse: 'post' }), + init() { + this._super(...arguments); + testState(types, this); + } + }); + types = { + Author, + Comment, + Post + }; + + return setupStore({ + adapter: JSONAPIAdapter.extend(), + post: Post, + comment: Comment, + author: Author + }); +} + +module('unit/model - init properties', {}); + +test('createRecord(properties) makes properties available during record init', function(assert) { + assert.expect(4); + let comment; + let author; + + function testState(types, record) { + assert.ok(get(record, 'title') === 'My Post', 'Attrs are available as expected'); + assert.ok(get(record, 'randomProp') === 'An unknown prop', 'Unknown properties are available as expected'); + assert.ok(get(record, 'author') instanceof types.Author, 'belongsTo relationships are available as expected'); + assert.ok(get(record, 'comments.firstObject') instanceof types.Comment, 'hasMany relationships are available as expected'); + } + + let { store } = setupModels(testState); + + run(() => { + comment = store.push({ + data: { + type: 'comment', + id: '1', + attributes: { + text: 'Hello darkness my old friend' + } + } + }); + author = store.push({ + data: { + type: 'author', + id: '1', + attributes: { + name: '@runspired' + } + } + }); + }); + + run(() => { + store.createRecord('post', { + title: 'My Post', + randomProp: 'An unknown prop', + comments: [comment], + author + }); + }); +}); + +test('store.push() makes properties available during record init', function(assert) { + assert.expect(3); + + function testState(types, record) { + assert.ok(get(record, 'title') === 'My Post', 'Attrs are available as expected'); + assert.ok(get(record, 'author') instanceof types.Author, 'belongsTo relationships are available as expected'); + assert.ok(get(record, 'comments.firstObject') instanceof types.Comment, 'hasMany relationships are available as expected'); + } + + let { store } = setupModels(testState); + + run(() => store.push({ + data: { + type: 'post', + id: '1', + attributes: { + title: 'My Post' + }, + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }] + }, + author: { + data: { type: 'author', id: '1' } + } + } + }, + included: [ + { + type: 'comment', + id: '1', + attributes: { + text: 'Hello darkness my old friend' + } + }, + { + type: 'author', + id: '1', + attributes: { + name: '@runspired' + } + } + ] + })); +}); + +test('store.findRecord(type, id) makes properties available during record init', function(assert) { + assert.expect(3); + + function testState(types, record) { + assert.ok(get(record, 'title') === 'My Post', 'Attrs are available as expected'); + assert.ok(get(record, 'author') instanceof types.Author, 'belongsTo relationships are available as expected'); + assert.ok(get(record, 'comments.firstObject') instanceof types.Comment, 'hasMany relationships are available as expected'); + } + + let { adapter, store } = setupModels(testState); + + adapter.findRecord = () => { + return resolve({ + data: { + type: 'post', + id: '1', + attributes: { + title: 'My Post' + }, + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }] + }, + author: { + data: { type: 'author', id: '1' } + } + } + }, + included: [ + { + type: 'comment', + id: '1', + attributes: { + text: 'Hello darkness my old friend' + } + }, + { + type: 'author', + id: '1', + attributes: { + name: '@runspired' + } + } + ] + }); + }; + + run(() => store.findRecord('post', '1')); +}); + +test('store.queryRecord(type, query) makes properties available during record init', function(assert) { + assert.expect(3); + + function testState(types, record) { + assert.ok(get(record, 'title') === 'My Post', 'Attrs are available as expected'); + assert.ok(get(record, 'author') instanceof types.Author, 'belongsTo relationships are available as expected'); + assert.ok(get(record, 'comments.firstObject') instanceof types.Comment, 'hasMany relationships are available as expected'); + } + + let { adapter, store } = setupModels(testState); + + adapter.queryRecord = () => { + return resolve({ + data: { + type: 'post', + id: '1', + attributes: { + title: 'My Post' + }, + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }] + }, + author: { + data: { type: 'author', id: '1' } + } + } + }, + included: [ + { + type: 'comment', + id: '1', + attributes: { + text: 'Hello darkness my old friend' + } + }, + { + type: 'author', + id: '1', + attributes: { + name: '@runspired' + } + } + ] + }); + }; + + run(() => store.queryRecord('post', { id: '1' })); +}); diff --git a/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js index c00b93803f1..da135984994 100644 --- a/tests/unit/store/create-record-test.js +++ b/tests/unit/store/create-record-test.js @@ -123,69 +123,6 @@ test('allow passing relationships as well as attributes', function(assert) { assert.equal(storage.get('records').findBy('id', '2'), A(records).findBy('id', '2'), 'Defined relationships are allowed in createRecord'); }); -test('createRecord(properties) makes properties available during record init', function(assert) { - assert.expect(4); - let comment; - let author; - - const Post = Model.extend({ - title: attr(), - author: belongsTo('author', { async: false, inverse: 'post' }), - comments: hasMany('comment', { async: false, inverse: 'post' }), - init() { - this._super(...arguments); - assert.ok(this.get('title') === 'My Post', 'Attrs are available as expected'); - assert.ok(this.get('randomProp') === 'An unknown prop', 'Unknown properties are available as expected'); - assert.ok(this.get('author') === author, 'belongsTo relationships are available as expected'); - assert.ok(this.get('comments.firstObject') === comment, 'hasMany relationships are available as expected'); - } - }); - const Comment = Model.extend({ - text: attr(), - post: belongsTo('post', { async: false, inverse: 'comments' }) - }); - const Author = Model.extend({ - name: attr(), - post: belongsTo('post', { async: false, inverse: 'author' }) - }); - let env = setupStore({ - post: Post, - comment: Comment, - author: Author - }); - let store = env.store; - - run(() => { - comment = store.push({ - data: { - type: 'comment', - id: '1', - attributes: { - text: 'Hello darkness my old friend' - } - } - }); - author = store.push({ - data: { - type: 'author', - id: '1', - attributes: { - name: '@runspired' - } - } - }); - }); - - run(() => { - store.createRecord('post', { - title: 'My Post', - randomProp: 'An unknown prop', - comments: [comment], - author - }); - }); -}); - module('unit/store/createRecord - Store with models by dash', { beforeEach() { let env = setupStore({ From d578710d0482c301d0d35e789a4a4e9360fdd221 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 4 Apr 2018 14:10:46 -0700 Subject: [PATCH 2199/2527] fix tests for findRecord by making snapshot lazily call getRecord if possible, skip test that should have never worked but also improve it so that we can maybe make it work in the future --- addon/-private/system/snapshot.js | 43 +++++++++++++++++------------- tests/integration/snapshot-test.js | 15 +++++++---- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index 98f4842d536..adfc8cd1df1 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -24,25 +24,13 @@ export default class Snapshot { this._hasManyIds = Object.create(null); this._internalModel = internalModel; - let record = internalModel.getRecord(); + // TODO is there a way we can assign known attributes without + // using `eachAttribute`? This forces us to lookup the model-class + // but for findRecord / findAll these are empty and doing so at + // this point in time is unnecessary. + internalModel.eachAttribute((keyName) => this._attributes[keyName] = internalModel.getAttributeValue(keyName)); - /** - The underlying record for this snapshot. Can be used to access methods and - properties defined on the record. - - Example - - ```javascript - let json = snapshot.record.toJSON(); - ``` - - @property record - @type {DS.Model} - */ - this.record = record; - record.eachAttribute((keyName) => this._attributes[keyName] = get(record, keyName)); - - /** + /**O The id of the snapshot's underlying record Example @@ -73,7 +61,24 @@ export default class Snapshot { */ this.modelName = internalModel.modelName; - this._changedAttributes = record.changedAttributes(); + this._changedAttributes = internalModel.changedAttributes(); + } + + /** + The underlying record for this snapshot. Can be used to access methods and + properties defined on the record. + + Example + + ```javascript + let json = snapshot.record.toJSON(); + ``` + + @property record + @type {DS.Model} + */ + get record() { + return this._internalModel.getRecord(); } /** diff --git a/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js index b92963cf6e3..6ae8d776c2b 100644 --- a/tests/integration/snapshot-test.js +++ b/tests/integration/snapshot-test.js @@ -2,7 +2,7 @@ import { resolve } from 'rsvp'; import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import { module, test } from 'qunit'; +import { module, test, skip } from 'qunit'; import DS from 'ember-data'; @@ -75,16 +75,21 @@ test("snapshot.id, snapshot.type and snapshot.modelName returns correctly", func }); }); -test('snapshot.type loads the class lazily', function(assert) { +// skipped because snapshot creation requires using `eachAttribute` +// which as an approach requires that we MUST load the class. +// there may be strategies via which we can snapshot known attributes +// only if no record exists yet, since we would then know for sure +// that this snapshot is not being used for a `.save()`. +skip('snapshot.type loads the class lazily', function(assert) { assert.expect(3); let postClassLoaded = false; - let modelFor = env.store._modelFor; - env.store._modelFor = (name) => { + let modelFactoryFor = env.store._modelFactoryFor; + env.store._modelFactoryFor = (name) => { if (name === 'post') { postClassLoaded = true; } - return modelFor.call(env.store, name); + return modelFactoryFor.call(env.store, name); }; run(() => { From de553788471f1f7fe5f0c3129862af7d2dc3fb8e Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 4 Apr 2018 14:32:58 -0700 Subject: [PATCH 2200/2527] address failing test post-rebase --- addon/-private/system/model/internal-model.js | 4 ++++ tests/unit/model-test.js | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index d42e2fb5126..94bd50f02a1 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -677,6 +677,10 @@ export default class InternalModel { } setDirtyAttribute(key, value) { + if (this.isDeleted()) { + throw new EmberError(`Attempted to set '${key}' to '${value}' on the deleted record ${this}`); + } + let oldValue = this.getAttributeValue(key); let originalValue; diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index a24aadb08dc..81103e18e6c 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -651,7 +651,7 @@ test('Does not support dirtying in root.deleted.saved', function(assert) { run(() => { assert.expectAssertion(() => { set(record, 'isArchived', true); - }, /Attempted to handle event `didSetProperty` on while in state root.deleted.saved. Called with {name: isArchived, oldValue: false, originalValue: false, value: true}./); + }, /Attempted to set 'isArchived' to 'true' on the deleted record /); let currentState = record._internalModel.currentState; From 7b0e9781ba94b6bfef14ed801dad049e79896738 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 4 Apr 2018 18:31:53 -0400 Subject: [PATCH 2201/2527] Limit CI runs on branches to master, beta, release --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index 6811b7897e4..d9a6b400138 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,14 @@ addons: cache: yarn: true +branches: + only: + - master + - beta + - release + # npm version tags + - /^v\d+\.\d+\.\d+/ + stages: - test - additional tests From 5ded0426fb2b2ae6f9e387fe013fec0b1dd27ed4 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 5 Apr 2018 12:37:30 -0700 Subject: [PATCH 2202/2527] [FEAT] Prevent async test leakage (feat. adds test waiters) bump qunit register a waiter and use a global backburner instance add test waiter for network requests cleanup leaky tests fix blueprints to account for ember-qunit update delete record does not have a return value --- addon/-private/system/backburner.js | 12 ++++ addon/-private/system/store.js | 22 +++---- addon/-private/system/store/common.js | 20 ++++++ addon/-private/system/store/finders.js | 35 +++++----- .../tests/unit/__path__/__test__.js | 18 ++--- .../tests/unit/__path__/__test__.js | 12 ---- .../tests/unit/__path__/__test__.js | 20 +++--- .../tests/unit/__path__/__test__.js | 14 ---- .../tests/unit/__path__/__test__.js | 29 ++++++--- .../tests/unit/__path__/__test__.js | 24 ------- .../tests/unit/__path__/__test__.js | 18 ++--- .../tests/unit/__path__/__test__.js | 12 ---- package.json | 2 +- .../adapter/build-url-mixin-test.js | 20 +++--- .../integration/adapter/rest-adapter-test.js | 65 ++++++++++--------- .../integration/adapter/store-adapter-test.js | 63 +++++++++--------- tests/test-helper.js | 2 +- yarn.lock | 15 ++--- 18 files changed, 190 insertions(+), 213 deletions(-) create mode 100644 addon/-private/system/backburner.js delete mode 100644 blueprints/adapter-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js delete mode 100644 blueprints/model-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js delete mode 100644 blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js delete mode 100644 blueprints/transform-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js diff --git a/addon/-private/system/backburner.js b/addon/-private/system/backburner.js new file mode 100644 index 00000000000..266c37c3b4b --- /dev/null +++ b/addon/-private/system/backburner.js @@ -0,0 +1,12 @@ +import Ember from 'ember'; +import { DEBUG } from '@glimmer/env'; + +const backburner = new Ember._Backburner(['normalizeRelationships', 'syncRelationships', 'finished']); + +if (DEBUG) { + Ember.Test.registerWaiter(() => { + return !backburner.currentInstance && !backburner.hasTimers(); + }); +} + +export default backburner; diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 3422adf4f3f..6495a8866e3 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -9,7 +9,7 @@ import EmberError from '@ember/error'; import MapWithDefault from './map-with-default'; import { run as emberRun } from '@ember/runloop'; import { set, get, computed } from '@ember/object'; -import RSVP from 'rsvp'; +import { default as RSVP, Promise } from 'rsvp'; import Service from '@ember/service'; import { typeOf, isPresent, isNone } from '@ember/utils'; @@ -30,7 +30,9 @@ import { import { _bind, _guard, - _objectIsAlive + _objectIsAlive, + guardDestroyedStore, + incrementRequestCount } from "./store/common"; import { normalizeResponseHelper } from "./store/serializer-response"; @@ -51,15 +53,11 @@ import { getOwner } from '../utils'; import coerceId from "./coerce-id"; import RecordArrayManager from "./record-array-manager"; import InternalModel from "./model/internal-model"; +import edBackburner from './backburner'; const badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; -const { - _Backburner: Backburner, - ENV -} = Ember; - -const { Promise } = RSVP; +const { ENV } = Ember; //Get the materialized model from the internalModel/promise that returns //an internal model and return it in a promiseObject. Useful for returning @@ -204,7 +202,7 @@ Store = Service.extend({ */ init() { this._super(...arguments); - this._backburner = new Backburner(['normalizeRelationships', 'syncRelationships', 'finished']); + this._backburner = edBackburner; // internal bookkeeping; not observable this.recordArrayManager = new RecordArrayManager({ store: this }); this._identityMap = new IdentityMap(); @@ -2884,14 +2882,16 @@ function _commit(adapter, store, operation, snapshot) { let modelClass = store._modelFor(modelName); assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter); assert(`You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`, typeof adapter[operation] === 'function'); + + if (DEBUG) { incrementRequestCount(); } + let promise = Promise.resolve().then(() => adapter[operation](store, modelClass, snapshot)); let serializer = serializerForAdapter(store, adapter, modelName); let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; assert(`Your adapter's '${operation}' method must return a value, but it returned 'undefined'`, promise !==undefined); - promise = Promise.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); + promise = guardDestroyedStore(promise, store, label); promise = _guard(promise, _bind(_objectIsAlive, internalModel)); return promise.then((adapterPayload) => { diff --git a/addon/-private/system/store/common.js b/addon/-private/system/store/common.js index e0548b71467..007671f5114 100644 --- a/addon/-private/system/store/common.js +++ b/addon/-private/system/store/common.js @@ -1,4 +1,7 @@ import { get } from '@ember/object'; +import { DEBUG } from '@glimmer/env'; +import Ember from 'ember'; +import { Promise } from 'rsvp'; const { __bind, @@ -33,3 +36,20 @@ export function _objectIsAlive(object) { heimdall.increment(__objectIsAlive); return !(get(object, "isDestroyed") || get(object, "isDestroying")); } + +let ASYNC_REQUEST_COUNT = 0; +export function incrementRequestCount() { + ASYNC_REQUEST_COUNT++; +} + +if (DEBUG) { + Ember.Test.registerWaiter(() => { + return ASYNC_REQUEST_COUNT === 0; + }); +} + +export function guardDestroyedStore(promise, store, label) { + promise = Promise.resolve(promise, label); + + return _guard(promise, () => { if (DEBUG) { ASYNC_REQUEST_COUNT--; } return _objectIsAlive(store); }); +} diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 102633d41e1..d9923eaf29a 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -1,10 +1,14 @@ import { A } from '@ember/array'; import { Promise } from 'rsvp'; import { assert, warn } from '@ember/debug'; +import { DEBUG } from '@glimmer/env'; + import { _bind, _guard, - _objectIsAlive + _objectIsAlive, + guardDestroyedStore, + incrementRequestCount } from "./common"; import { normalizeResponseHelper } from "./serializer-response"; @@ -19,13 +23,13 @@ function payloadIsNotBlank(adapterPayload) { } export function _find(adapter, store, modelClass, id, internalModel, options) { + if (DEBUG) { incrementRequestCount(); } let snapshot = internalModel.createSnapshot(options); let { modelName } = internalModel; let promise = Promise.resolve().then(() => adapter.findRecord(store, modelClass, id, snapshot)); let label = `DS: Handle Adapter#findRecord of '${modelName}' with id: '${id}'`; - promise = Promise.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); + promise = guardDestroyedStore(promise, store, label); return promise.then(adapterPayload => { assert(`You made a 'findRecord' request for a '${modelName}' with id '${id}', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); @@ -49,6 +53,7 @@ export function _find(adapter, store, modelClass, id, internalModel, options) { } export function _findMany(adapter, store, modelName, ids, internalModels) { + if (DEBUG) { incrementRequestCount(); } let snapshots = A(internalModels).invoke('createSnapshot'); let modelClass = store.modelFor(modelName); // `adapter.findMany` gets the modelClass still let promise = adapter.findMany(store, modelClass, ids, snapshots); @@ -58,8 +63,7 @@ export function _findMany(adapter, store, modelName, ids, internalModels) { throw new Error('adapter.findMany returned undefined, this was very likely a mistake'); } - promise = Promise.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); + promise = guardDestroyedStore(promise, store, label); return promise.then(adapterPayload => { assert(`You made a 'findMany' request for '${modelName}' records with ids '[${ids}]', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); @@ -70,13 +74,13 @@ export function _findMany(adapter, store, modelName, ids, internalModels) { } export function _findHasMany(adapter, store, internalModel, link, relationship) { + if (DEBUG) { incrementRequestCount(); } let snapshot = internalModel.createSnapshot(); let modelClass = store.modelFor(relationship.type); let promise = adapter.findHasMany(store, snapshot, link, relationship); let label = `DS: Handle Adapter#findHasMany of '${internalModel.modelName}' : '${relationship.type}'`; - promise = Promise.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); + promise = guardDestroyedStore(promise, store, label); promise = _guard(promise, _bind(_objectIsAlive, internalModel)); return promise.then(adapterPayload => { @@ -91,13 +95,13 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) } export function _findBelongsTo(adapter, store, internalModel, link, relationship) { + if (DEBUG) { incrementRequestCount(); } let snapshot = internalModel.createSnapshot(); let modelClass = store.modelFor(relationship.type); let promise = adapter.findBelongsTo(store, snapshot, link, relationship); let label = `DS: Handle Adapter#findBelongsTo of ${internalModel.modelName} : ${relationship.type}`; - promise = Promise.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); + promise = guardDestroyedStore(promise, store, label); promise = _guard(promise, _bind(_objectIsAlive, internalModel)); return promise.then(adapterPayload => { @@ -113,14 +117,14 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship } export function _findAll(adapter, store, modelName, sinceToken, options) { + if (DEBUG) { incrementRequestCount(); } let modelClass = store.modelFor(modelName); // adapter.findAll depends on the class let recordArray = store.peekAll(modelName); let snapshotArray = recordArray._createSnapshot(options); let promise = Promise.resolve().then(() => adapter.findAll(store, modelClass, sinceToken, snapshotArray)); let label = "DS: Handle Adapter#findAll of " + modelClass; - promise = Promise.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); + promise = guardDestroyedStore(promise, store, label); return promise.then(adapterPayload => { assert(`You made a 'findAll' request for '${modelName}' records, but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); @@ -135,6 +139,7 @@ export function _findAll(adapter, store, modelName, sinceToken, options) { } export function _query(adapter, store, modelName, query, recordArray, options) { + if (DEBUG) { incrementRequestCount(); } let modelClass = store.modelFor(modelName); // adapter.query needs the class let promise; @@ -149,9 +154,7 @@ export function _query(adapter, store, modelName, query, recordArray, options) { } let label = `DS: Handle Adapter#query of ${modelName}`; - promise = Promise.resolve(promise, label); - - promise = _guard(promise, _bind(_objectIsAlive, store)); + promise = guardDestroyedStore(promise, store, label); return promise.then(adapterPayload => { let serializerToken = heimdall.start('initial-serializerFor-lookup'); @@ -174,12 +177,12 @@ export function _query(adapter, store, modelName, query, recordArray, options) { } export function _queryRecord(adapter, store, modelName, query, options) { + if (DEBUG) { incrementRequestCount(); } let modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class let promise = Promise.resolve().then(() => adapter.queryRecord(store, modelClass, query, options)); let label = `DS: Handle Adapter#queryRecord of ${modelName}`; - promise = Promise.resolve(promise, label); - promise = _guard(promise, _bind(_objectIsAlive, store)); + promise = guardDestroyedStore(promise, store, label); return promise.then(adapterPayload => { let serializer = serializerForAdapter(store, adapter, modelName); diff --git a/blueprints/adapter-test/qunit-files/tests/unit/__path__/__test__.js b/blueprints/adapter-test/qunit-files/tests/unit/__path__/__test__.js index 739d5eb7303..8fc52439de3 100644 --- a/blueprints/adapter-test/qunit-files/tests/unit/__path__/__test__.js +++ b/blueprints/adapter-test/qunit-files/tests/unit/__path__/__test__.js @@ -1,12 +1,12 @@ -import { moduleFor, test } from 'ember-qunit'; +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; -moduleFor('adapter:<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', { - // Specify the other units that are required for this test. - // needs: ['serializer:foo'] -}); +module('<%= friendlyTestDescription %>', function(hooks) { + setupTest(hooks); -// Replace this with your real tests. -test('it exists', function(assert) { - let adapter = this.subject(); - assert.ok(adapter); + // Replace this with your real tests. + test('it exists', function(assert) { + let adapter = this.owner.lookup('adapter:<%= dasherizedModuleName %>'); + assert.ok(adapter); + }); }); diff --git a/blueprints/adapter-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js b/blueprints/adapter-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js deleted file mode 100644 index 8fc52439de3..00000000000 --- a/blueprints/adapter-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js +++ /dev/null @@ -1,12 +0,0 @@ -import { module, test } from 'qunit'; -import { setupTest } from 'ember-qunit'; - -module('<%= friendlyTestDescription %>', function(hooks) { - setupTest(hooks); - - // Replace this with your real tests. - test('it exists', function(assert) { - let adapter = this.owner.lookup('adapter:<%= dasherizedModuleName %>'); - assert.ok(adapter); - }); -}); diff --git a/blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js b/blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js index d7d880b44a6..84dbd712791 100644 --- a/blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js +++ b/blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js @@ -1,12 +1,14 @@ -import { moduleForModel, test } from 'ember-qunit'; +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { run } from '@ember/runloop'; -moduleForModel('<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', { - // Specify the other units that are required for this test. -<%= typeof needs !== 'undefined' ? needs : '' %> -}); +module('<%= friendlyTestDescription %>', function(hooks) { + setupTest(hooks); -test('it exists', function(assert) { - let model = this.subject(); - // let store = this.store(); - assert.ok(!!model); + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let model = run(() => store.createRecord('<%= dasherizedModuleName %>', {})); + assert.ok(model); + }); }); diff --git a/blueprints/model-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js b/blueprints/model-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js deleted file mode 100644 index 84dbd712791..00000000000 --- a/blueprints/model-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js +++ /dev/null @@ -1,14 +0,0 @@ -import { module, test } from 'qunit'; -import { setupTest } from 'ember-qunit'; -import { run } from '@ember/runloop'; - -module('<%= friendlyTestDescription %>', function(hooks) { - setupTest(hooks); - - // Replace this with your real tests. - test('it exists', function(assert) { - let store = this.owner.lookup('service:store'); - let model = run(() => store.createRecord('<%= dasherizedModuleName %>', {})); - assert.ok(model); - }); -}); diff --git a/blueprints/serializer-test/qunit-files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/qunit-files/tests/unit/__path__/__test__.js index bfc3aa943ca..0a72b125520 100644 --- a/blueprints/serializer-test/qunit-files/tests/unit/__path__/__test__.js +++ b/blueprints/serializer-test/qunit-files/tests/unit/__path__/__test__.js @@ -1,15 +1,24 @@ -import { moduleForModel, test } from 'ember-qunit'; +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { run } from '@ember/runloop'; -moduleForModel('<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', { - // Specify the other units that are required for this test. - needs: ['serializer:<%= dasherizedModuleName %>'] -}); +module('<%= friendlyTestDescription %>', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let store = this.owner.lookup('service:store'); + let serializer = store.serializerFor('<%= dasherizedModuleName %>'); + + assert.ok(serializer); + }); -// Replace this with your real tests. -test('it serializes records', function(assert) { - let record = this.subject(); + test('it serializes records', function(assert) { + let store = this.owner.lookup('service:store'); + let record = run(() => store.createRecord('<%= dasherizedModuleName %>', {})); - let serializedRecord = record.serialize(); + let serializedRecord = record.serialize(); - assert.ok(serializedRecord); + assert.ok(serializedRecord); + }); }); diff --git a/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js deleted file mode 100644 index 0a72b125520..00000000000 --- a/blueprints/serializer-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js +++ /dev/null @@ -1,24 +0,0 @@ -import { module, test } from 'qunit'; -import { setupTest } from 'ember-qunit'; -import { run } from '@ember/runloop'; - -module('<%= friendlyTestDescription %>', function(hooks) { - setupTest(hooks); - - // Replace this with your real tests. - test('it exists', function(assert) { - let store = this.owner.lookup('service:store'); - let serializer = store.serializerFor('<%= dasherizedModuleName %>'); - - assert.ok(serializer); - }); - - test('it serializes records', function(assert) { - let store = this.owner.lookup('service:store'); - let record = run(() => store.createRecord('<%= dasherizedModuleName %>', {})); - - let serializedRecord = record.serialize(); - - assert.ok(serializedRecord); - }); -}); diff --git a/blueprints/transform-test/qunit-files/tests/unit/__path__/__test__.js b/blueprints/transform-test/qunit-files/tests/unit/__path__/__test__.js index ef14ae150b3..e4f745717d3 100644 --- a/blueprints/transform-test/qunit-files/tests/unit/__path__/__test__.js +++ b/blueprints/transform-test/qunit-files/tests/unit/__path__/__test__.js @@ -1,12 +1,12 @@ -import { moduleFor, test } from 'ember-qunit'; +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; -moduleFor('transform:<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', { - // Specify the other units that are required for this test. - // needs: ['serializer:foo'] -}); +module('transform:<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', function(hooks) { + setupTest(hooks); -// Replace this with your real tests. -test('it exists', function(assert) { - let transform = this.subject(); - assert.ok(transform); + // Replace this with your real tests. + test('it exists', function(assert) { + let transform = this.owner.lookup('transform:<%= dasherizedModuleName %>'); + assert.ok(transform); + }); }); diff --git a/blueprints/transform-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js b/blueprints/transform-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js deleted file mode 100644 index e4f745717d3..00000000000 --- a/blueprints/transform-test/qunit-rfc-232-files/tests/unit/__path__/__test__.js +++ /dev/null @@ -1,12 +0,0 @@ -import { module, test } from 'qunit'; -import { setupTest } from 'ember-qunit'; - -module('transform:<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', function(hooks) { - setupTest(hooks); - - // Replace this with your real tests. - test('it exists', function(assert) { - let transform = this.owner.lookup('transform:<%= dasherizedModuleName %>'); - assert.ok(transform); - }); -}); diff --git a/package.json b/package.json index 9dc6a29314b..2a156b52e6e 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "ember-cli-inject-live-reload": "^1.4.1", "ember-cli-internal-test-helpers": "^0.8.1", "ember-cli-pretender": "^1.0.1", - "ember-cli-qunit": "^4.0.0", + "ember-qunit": "^3.4.0", "ember-cli-release": "^0.2.9", "ember-cli-shims": "^1.0.2", "ember-cli-sri": "^2.1.0", diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index 59418aa40ac..a2cacd1da63 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -61,9 +61,9 @@ test('buildURL - with host and namespace', function(assert) { ajaxResponse({ posts: [{ id: 1 }] }); - return run(store, 'findRecord', 'post', 1).then(post => { + return run(() => store.findRecord('post', 1).then(post => { assert.equal(passedUrl, "http://example.com/api/v1/posts/1"); - }); + })); }); test('buildURL - with relative paths in links', function(assert) { @@ -79,12 +79,12 @@ test('buildURL - with relative paths in links', function(assert) { ajaxResponse({ posts: [{ id: 1, links: { comments: 'comments' } }] }); - return run(store, 'findRecord', 'post', '1').then(post => { + return run(() => store.findRecord('post', 1).then(post => { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); }).then(comments => { assert.equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); - }); + })); }); test('buildURL - with absolute paths in links', function(assert) { @@ -99,12 +99,12 @@ test('buildURL - with absolute paths in links', function(assert) { ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - return run(store, 'findRecord', 'post', 1).then(post => { + return run(() => store.findRecord('post', 1).then(post => { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); }).then(comments => { assert.equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); - }); + })); }); @@ -120,12 +120,12 @@ test('buildURL - with absolute paths in links and protocol relative host', funct ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - return run(store, 'findRecord', 'post', 1).then(post => { + return run(() => store.findRecord('post', 1).then(post => { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); }).then(comments => { assert.equal(passedUrl, "//example.com/api/v1/posts/1/comments"); - }); + })); }); test('buildURL - with absolute paths in links and host is /', function(assert) { @@ -140,12 +140,12 @@ test('buildURL - with absolute paths in links and host is /', function(assert) { ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - return run(store, 'findRecord', 'post', 1).then(post => { + return run(() => store.findRecord('post', 1).then(post => { ajaxResponse({ comments: [{ id: 1 }] }); return post.get('comments'); }).then(comments => { assert.equal(passedUrl, '/api/v1/posts/1/comments', 'host stripped out properly'); - }); + })); }); test('buildURL - with full URLs in links', function(assert) { diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index b266c96fe3b..17e95316351 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -74,14 +74,14 @@ function ajaxError(responseText, status = 400, headers = '') { test("findRecord - basic payload", function(assert) { ajaxResponse({ posts: [{ id: 1, name: "Rails is omakase" }] }); - return run(store, 'findRecord', 'post', 1).then(post => { + return run(() => store.findRecord('post', 1).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.deepEqual(passedHash.data, {}); assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); - }); + })); }); @@ -93,22 +93,22 @@ test("findRecord - passes buildURL a requestType", function(assert) { ajaxResponse({ posts: [{ id: 1, name: "Rails is omakase" }] }); - return run(store, 'findRecord', 'post', 1).then(post => { + return run(() => store.findRecord('post', 1).then(post => { assert.equal(passedUrl, "/findRecord/post/1"); - }); + })); }); test("findRecord - basic payload (with legacy singular name)", function(assert) { ajaxResponse({ post: { id: 1, name: "Rails is omakase" } }); - return run(store, 'findRecord', 'post', 1).then(post => { + return run(() => store.findRecord('post', 1).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.deepEqual(passedHash.data, {}); assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); - }); + })); }); test("findRecord - payload with sideloaded records of the same type", function(assert) { @@ -119,7 +119,7 @@ test("findRecord - payload with sideloaded records of the same type", function(a ] }); - return run(store, 'findRecord', 'post', 1).then(post => { + return run(() => store.findRecord('post', 1).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.deepEqual(passedHash.data, {}); @@ -130,7 +130,7 @@ test("findRecord - payload with sideloaded records of the same type", function(a let post2 = store.peekRecord('post', 2); assert.equal(post2.get('id'), "2"); assert.equal(post2.get('name'), "The Parley Letter"); - }); + })); }); test("findRecord - payload with sideloaded records of a different type", function(assert) { @@ -139,7 +139,7 @@ test("findRecord - payload with sideloaded records of a different type", functio comments: [{ id: 1, name: "FIRST" }] }); - return run(store, 'findRecord', 'post', 1).then(post => { + return run(() => store.findRecord('post', 1).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.deepEqual(passedHash.data, {}); @@ -150,7 +150,7 @@ test("findRecord - payload with sideloaded records of a different type", functio let comment = store.peekRecord('comment', 1); assert.equal(comment.get('id'), "1"); assert.equal(comment.get('name'), "FIRST"); - }); + })); }); @@ -161,14 +161,14 @@ test("findRecord - payload with an serializer-specified primary key", function(a ajaxResponse({ posts: [{ "_ID_": 1, name: "Rails is omakase" }] }); - return run(store, 'findRecord', 'post', 1).then(post => { + return run(() => store.findRecord('post', 1).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.deepEqual(passedHash.data, {}); assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); - }); + })); }); test("findRecord - payload with a serializer-specified attribute mapping", function(assert) { @@ -185,7 +185,7 @@ test("findRecord - payload with a serializer-specified attribute mapping", funct ajaxResponse({ posts: [{ id: 1, _NAME_: "Rails is omakase", _CREATED_AT_: 2013 }] }); - return run(store, 'findRecord', 'post', 1).then(post => { + return run(() => store.findRecord('post', 1).then(post => { assert.equal(passedUrl, "/posts/1"); assert.equal(passedVerb, "GET"); assert.deepEqual(passedHash.data, {}); @@ -193,7 +193,7 @@ test("findRecord - payload with a serializer-specified attribute mapping", funct assert.equal(post.get('id'), "1"); assert.equal(post.get('name'), "Rails is omakase"); assert.equal(post.get('createdAt'), 2013); - }); + })); }); test("findRecord - passes `include` as a query parameter to ajax", function(assert) { @@ -201,9 +201,9 @@ test("findRecord - passes `include` as a query parameter to ajax", function(asse post: { id: 1, name: 'Rails is very expensive sushi' } }); - return run(store, 'findRecord', 'post', 1, { include: 'comments' }).then(() => { + return run(() => store.findRecord('post', 1, { include: 'comments' }).then(() => { assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` parameter sent to adapter.ajax'); - }); + })); }); test("createRecord - an empty payload is a basic success if an id was specified", function(assert) { @@ -330,9 +330,12 @@ test("createRecord - a serializer's primary key and attributes are consulted whe post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); }); - return run(post, 'save').then(post => { - assert.deepEqual(passedHash.data, { post: { _id_: 'some-uuid', '_name_': "The Parley Letter" } }); - }); + return run(() => + post.save() + .then(post => { + assert.deepEqual(passedHash.data, { post: { _id_: 'some-uuid', '_name_': "The Parley Letter" } }); + }) + ); }); test("createRecord - a serializer's attributes are consulted when building the payload if no id is pre-defined", function(assert) { @@ -584,7 +587,7 @@ test("createRecord - relationships are not duplicated", function(assert) { ajaxResponse({ post: [{ id: 1, name: "Rails is omakase", comments: [] }] }); - return run(post, 'save').then(post => { + return run(() => post.save().then(post => { assert.equal(post.get('comments.length'), 0, "post has 0 comments"); post.get('comments').pushObject(comment); assert.equal(post.get('comments.length'), 1, "post has 1 comment"); @@ -597,7 +600,7 @@ test("createRecord - relationships are not duplicated", function(assert) { return post.save(); }).then(post => { assert.equal(post.get('comments.length'), 1, "post has 1 comment"); - }); + })); }); test("updateRecord - an empty payload is a basic success", function(assert) { @@ -1446,10 +1449,10 @@ test("findMany - findMany uses a correct URL to access the records", function(as ] }); - return run(post, 'get', 'comments').then(comments => { + return run(() => post.get('comments').then(comments => { assert.equal(passedUrl, "/comments"); assert.deepEqual(passedHash, { data: { ids: ["1", "2", "3"] } }); - }); + })); }); test("findMany - passes buildURL the requestType", function(assert) { @@ -1529,10 +1532,10 @@ test("findMany - findMany does not coalesce by default", function(assert) { ] }); - return run(post, 'get', 'comments').then(comments => { + return run(() => post.get('comments').then(comments => { assert.equal(passedUrl, "/comments/3"); assert.deepEqual(passedHash.data, {}); - }); + })); }); test("findMany - returning an array populates the array", function(assert) { @@ -1725,7 +1728,7 @@ test("findHasMany - returning an array populates the array", function(assert) { }); }); - return run(store, 'findRecord', 'post', '1').then(post => { + return run(() => store.findRecord('post', '1').then(post => { ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1749,7 +1752,7 @@ test("findHasMany - returning an array populates the array", function(assert) { assert.deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); - }); + })); }); test("findHasMany - passes buildURL the requestType", function(assert) { @@ -1781,7 +1784,7 @@ test("findHasMany - passes buildURL the requestType", function(assert) { }); }); - return run(store, 'findRecord', 'post', '1').then(post => { + return run(() => store.findRecord('post', '1').then(post => { ajaxResponse({ comments: [ { id: 1, name: "FIRST" }, @@ -1791,7 +1794,7 @@ test("findHasMany - passes buildURL the requestType", function(assert) { }); return post.get('comments'); - }); + })); }); test("findMany - returning sideloaded data loads the data (with JSONApi Links)", function(assert) { @@ -1925,10 +1928,10 @@ test('findBelongsTo - passes buildURL the requestType', function(assert) { }); }); - return run(store, 'findRecord', 'comment', 1).then(comment => { + return run(() => store.findRecord('comment', '1').then(comment => { ajaxResponse({ post: { id: 1, name: 'Rails is omakase' } }); return comment.get('post'); - }); + })); }); testInDebug('coalesceFindRequests assert.warns if the expected records are not returned in the coalesced request', function(assert) { diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index d25b4dd1981..65534fb5560 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -73,7 +73,7 @@ test("Records loaded multiple times and retrieved in recordArray are ready to se }); }; - return run(store, 'query', 'person', { q: 'bla' }).then(people => { + return run(() => store.query('person', { q: 'bla' }).then(people => { let people2 = store.query('person', { q: 'bla2' }); return hash({ people: people, people2: people2 }); @@ -86,7 +86,7 @@ test("Records loaded multiple times and retrieved in recordArray are ready to se // delete record will not throw exception person.deleteRecord(); - }); + })); }); test("by default, createRecords calls createRecord once per record", function(assert) { @@ -426,7 +426,7 @@ test("if an existing model is edited then deleted, deleteRecord is called on the }); // Retrieve that loaded record and edit it so it becomes dirty - return run(store, 'findRecord', 'person', 'deleted-record').then(tom => { + return run(() => store.findRecord('person', 'deleted-record').then(tom => { tom.set('name', "Tom Mothereffin' Dale"); assert.equal(get(tom, 'hasDirtyAttributes'), true, "precond - record should be dirty after editing"); @@ -436,7 +436,7 @@ test("if an existing model is edited then deleted, deleteRecord is called on the }).then(tom => { assert.equal(get(tom, 'hasDirtyAttributes'), false, "record should not be dirty"); assert.equal(get(tom, 'isDeleted'), true, "record should be considered deleted"); - }); + })); }); test("if a deleted record errors, it enters the error state", function(assert) { @@ -870,14 +870,14 @@ test("if a updated record is marked as erred by the server, it enters an error s return store.peekRecord('person', 1); }); - return run(store, 'findRecord', 'person', 1).then(record => { + return run(() => store.findRecord('person', 1).then(record => { assert.equal(record, person, "The person was resolved"); person.set('name', "Jonathan Doe"); return person.save(); }).catch(reason => { assert.ok(get(person, 'isError'), "the record is in the error state"); assert.equal(get(person, 'adapterError'), error, "error object is exposed"); - }); + })); }); test("can be created after the DS.Store", function(assert) { @@ -914,18 +914,20 @@ test("the filter method can optionally take a server query as well", function(as }); }; - let asyncFilter = store.filter('person', { page: 1 }, data => { - return data.get('name') === "Tom Dale"; - }); + return run(() => { + let asyncFilter = store.filter('person', { page: 1 }, data => { + return data.get('name') === "Tom Dale"; + }); - let loadedFilter; + let loadedFilter; - return asyncFilter.then(filter => { - loadedFilter = filter; - return store.findRecord('person', 2); - }).then(tom => { - assert.equal(get(loadedFilter, 'length'), 1, "The filter has an item in it"); - assert.deepEqual(loadedFilter.toArray(), [tom], "The filter has a single entry in it"); + return asyncFilter.then(filter => { + loadedFilter = filter; + return store.findRecord('person', 2); + }).then(tom => { + assert.equal(get(loadedFilter, 'length'), 1, "The filter has an item in it"); + assert.deepEqual(loadedFilter.toArray(), [tom], "The filter has a single entry in it"); + }); }); }); @@ -1043,7 +1045,7 @@ test("relationships don't get reset if the links is the same", function(assert) let tom, dogs; - return run(store, 'findRecord', 'person', 1).then(person => { + return run(() => store.findRecord('person', 1).then(person => { tom = person; dogs = tom.get('dogs'); return dogs; @@ -1069,7 +1071,7 @@ test("relationships don't get reset if the links is the same", function(assert) return tom.get('dogs'); }).then(dogs => { assert.equal(dogs.get('length'), 1, "The same dogs are loaded"); - }); + })); }); test("async hasMany always returns a promise", function(assert) { @@ -1486,22 +1488,20 @@ test("An async hasMany relationship with links should not trigger shouldBackgrou store = env.store; - return run(store, 'findRecord', 'post', '1').then(post => { + return run(() => store.findRecord('post', '1').then(post => { return post.get('comments'); }).then(comments => { assert.equal(comments.get('length'), 3); - }); + })); }); testInDebug("There should be a friendly error for if the adapter does not implement createRecord", function(assert) { adapter.createRecord = null; - let tom; + let tom = run(() => store.createRecord('person', { name: "Tom Dale" })); + assert.expectAssertion(() => { - run(() => { - tom = store.createRecord('person', { name: "Tom Dale" }); - tom.save(); - }); + run(() => tom.save()); }, /does not implement 'createRecord'/); moveRecordOutOfInFlight(tom); @@ -1510,12 +1510,9 @@ testInDebug("There should be a friendly error for if the adapter does not implem testInDebug("There should be a friendly error for if the adapter does not implement updateRecord", function(assert) { adapter.updateRecord = null; - let tom; + let tom = run(() => store.push({ data: { type: 'person', id: 1 } })); assert.expectAssertion(() => { - run(() => { - tom = store.push({ data: { type: 'person', id: 1 } }); - tom.save(); - }); + run(() => tom.save()); }, /does not implement 'updateRecord'/); moveRecordOutOfInFlight(tom); @@ -1524,12 +1521,12 @@ testInDebug("There should be a friendly error for if the adapter does not implem testInDebug("There should be a friendly error for if the adapter does not implement deleteRecord", function(assert) { adapter.deleteRecord = null; - let tom; + let tom = run(() => store.push({ data: { type: 'person', id: 1 } })); + assert.expectAssertion(() => { run(() => { - tom = store.push({ data: { type: 'person', id: 1 } }); tom.deleteRecord(); - tom.save(); + return tom.save(); }); }, /does not implement 'deleteRecord'/); diff --git a/tests/test-helper.js b/tests/test-helper.js index c011eeb5a42..360c70df4f7 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -69,4 +69,4 @@ QUnit.config.urlConfig.push({ id: 'enableoptionalfeatures', label: 'Enable Opt Features' }); -start(); +start({ setupTestIsolationValidation: true }); diff --git a/yarn.lock b/yarn.lock index 7cbdcd1e980..194ada067a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2424,7 +2424,7 @@ ember-cli-app-version@^3.0.0: ember-cli-babel "^6.8.0" git-repo-version "^1.0.0" -ember-cli-babel@6.12.0, ember-cli-babel@^6.0.0, ember-cli-babel@^6.10.0, ember-cli-babel@^6.11.0, ember-cli-babel@^6.3.0, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: +ember-cli-babel@6.12.0, ember-cli-babel@^6.0.0, ember-cli-babel@^6.10.0, ember-cli-babel@^6.3.0, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: version "6.12.0" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.12.0.tgz#3adcdbe1278da1fcd0b9038f1360cb4ac5d4414c" dependencies: @@ -2633,13 +2633,6 @@ ember-cli-pretender@^1.0.1: pretender "^1.4.2" resolve "^1.2.0" -ember-cli-qunit@^4.0.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ember-cli-qunit/-/ember-cli-qunit-4.3.2.tgz#cfd89ad3b0dbc28a9c2223d532b52eeade7c602c" - dependencies: - ember-cli-babel "^6.11.0" - ember-qunit "^3.3.2" - ember-cli-release@^0.2.9: version "0.2.9" resolved "https://registry.yarnpkg.com/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" @@ -2855,9 +2848,9 @@ ember-qunit-assert-helpers@^0.2.1: broccoli-filter "^1.0.1" ember-cli-babel "^6.9.0" -ember-qunit@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-3.3.2.tgz#cb48e9deaffa3b4c90983f28c5cf8590894c8ea3" +ember-qunit@^3.4.0: + version "3.4.0" + resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-3.4.0.tgz#47a60c2b889cd4b4a46380bf9da2b10115c0eae7" dependencies: "@ember/test-helpers" "^0.7.18" broccoli-funnel "^2.0.1" From 6abd20d480b172dcc4acda6a91316d41db0a5bc9 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 3 Apr 2018 20:37:31 -0700 Subject: [PATCH 2203/2527] refactor all the test usage or run-wrapping for createRecord, we really sohuld run prettier minor style tweak remove invalid filter test --- addon/-private/system/store.js | 41 +- .../tests/unit/__path__/__test__.js | 3 +- .../tests/unit/__path__/__test__.js | 3 +- .../fixtures/model-test/comment-default.js | 3 +- node-tests/fixtures/model-test/foo-default.js | 3 +- .../fixtures/model-test/post-default.js | 3 +- node-tests/fixtures/model-test/rfc232.js | 3 +- .../serializer-test/application-default.js | 3 +- .../fixtures/serializer-test/foo-default.js | 3 +- node-tests/fixtures/serializer-test/rfc232.js | 3 +- tests/integration/adapter/find-all-test.js | 4 +- .../integration/adapter/rest-adapter-test.js | 32 +- tests/integration/adapter/serialize-test.js | 6 +- .../integration/adapter/store-adapter-test.js | 33 +- .../integration/client-id-generation-test.js | 14 +- tests/integration/debug-adapter-test.js | 5 +- tests/integration/filter-test.js | 45 +- tests/integration/injection-test.js | 2 +- tests/integration/lifecycle-hooks-test.js | 4 +- tests/integration/record-array-test.js | 15 +- .../record-arrays/peeked-records-test.js | 18 +- .../records/collection-save-test.js | 25 +- .../integration/records/delete-record-test.js | 6 +- tests/integration/records/error-test.js | 26 +- tests/integration/records/save-test.js | 38 +- .../relationships/belongs-to-test.js | 24 +- .../relationships/has-many-test.js | 71 +-- .../inverse-relationships-test.js | 111 ++-- .../relationships/one-to-many-test.js | 2 +- .../embedded-records-mixin-test.js | 484 +++++++----------- .../serializers/json-api-serializer-test.js | 13 +- .../serializers/json-serializer-test.js | 227 +++----- .../serializers/rest-serializer-test.js | 73 +-- tests/integration/store-test.js | 2 +- .../group-records-for-find-many-test.js | 2 +- tests/unit/debug-test.js | 5 +- tests/unit/model-test.js | 59 +-- tests/unit/model/lifecycle-callbacks-test.js | 5 +- tests/unit/model/merge-test.js | 2 +- tests/unit/model/relationships-test.js | 7 +- .../model/relationships/belongs-to-test.js | 11 +- .../unit/model/relationships/has-many-test.js | 43 +- tests/unit/model/rollback-attributes-test.js | 4 +- tests/unit/store/adapter-interop-test.js | 22 +- tests/unit/store/create-record-test.js | 7 +- tests/unit/store/unload-test.js | 2 +- 46 files changed, 539 insertions(+), 978 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 6495a8866e3..a8d7b91bdb0 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -338,25 +338,32 @@ Store = Service.extend({ assert(`You need to pass a model name to the store's createRecord method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - return this._backburner.join(() => { - let normalizedModelName = normalizeModelName(modelName); - let properties = copy(inputProperties) || Object.create(null); - - // If the passed properties do not include a primary key, - // give the adapter an opportunity to generate one. Typically, - // client-side ID generators will use something like uuid.js - // to avoid conflicts. - - if (isNone(properties.id)) { - properties.id = this._generateId(normalizedModelName, properties); - } + // This is wrapped in a `run.join` so that in test environments users do not need to manually wrap + // calls to `createRecord`. The run loop usage here is because we batch the joining and updating + // of record-arrays via ember's run loop, not our own. + // + // to remove this, we would need to move to a new `async` API. + return emberRun.join(() => { + return this._backburner.join(() => { + let normalizedModelName = normalizeModelName(modelName); + let properties = copy(inputProperties) || Object.create(null); + + // If the passed properties do not include a primary key, + // give the adapter an opportunity to generate one. Typically, + // client-side ID generators will use something like uuid.js + // to avoid conflicts. + + if (isNone(properties.id)) { + properties.id = this._generateId(normalizedModelName, properties); + } - // Coerce ID to a string - properties.id = coerceId(properties.id); + // Coerce ID to a string + properties.id = coerceId(properties.id); - let internalModel = this._buildInternalModel(normalizedModelName, properties.id); - internalModel.loadedData(); - return internalModel.getRecord(properties); + let internalModel = this._buildInternalModel(normalizedModelName, properties.id); + internalModel.loadedData(); + return internalModel.getRecord(properties); + }); }); }, diff --git a/blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js b/blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js index 84dbd712791..17693d66fb7 100644 --- a/blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js +++ b/blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js @@ -1,6 +1,5 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -import { run } from '@ember/runloop'; module('<%= friendlyTestDescription %>', function(hooks) { setupTest(hooks); @@ -8,7 +7,7 @@ module('<%= friendlyTestDescription %>', function(hooks) { // Replace this with your real tests. test('it exists', function(assert) { let store = this.owner.lookup('service:store'); - let model = run(() => store.createRecord('<%= dasherizedModuleName %>', {})); + let model = store.createRecord('<%= dasherizedModuleName %>', {}); assert.ok(model); }); }); diff --git a/blueprints/serializer-test/qunit-files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/qunit-files/tests/unit/__path__/__test__.js index 0a72b125520..a1bea0f05ce 100644 --- a/blueprints/serializer-test/qunit-files/tests/unit/__path__/__test__.js +++ b/blueprints/serializer-test/qunit-files/tests/unit/__path__/__test__.js @@ -1,6 +1,5 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -import { run } from '@ember/runloop'; module('<%= friendlyTestDescription %>', function(hooks) { setupTest(hooks); @@ -15,7 +14,7 @@ module('<%= friendlyTestDescription %>', function(hooks) { test('it serializes records', function(assert) { let store = this.owner.lookup('service:store'); - let record = run(() => store.createRecord('<%= dasherizedModuleName %>', {})); + let record = store.createRecord('<%= dasherizedModuleName %>', {}); let serializedRecord = record.serialize(); diff --git a/node-tests/fixtures/model-test/comment-default.js b/node-tests/fixtures/model-test/comment-default.js index 342341a0824..a207d46059e 100644 --- a/node-tests/fixtures/model-test/comment-default.js +++ b/node-tests/fixtures/model-test/comment-default.js @@ -1,6 +1,5 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -import { run } from '@ember/runloop'; module('Unit | Model | comment', function(hooks) { setupTest(hooks); @@ -8,7 +7,7 @@ module('Unit | Model | comment', function(hooks) { // Replace this with your real tests. test('it exists', function(assert) { let store = this.owner.lookup('service:store'); - let model = run(() => store.createRecord('comment', {})); + let model = store.createRecord('comment', {}); assert.ok(model); }); }); diff --git a/node-tests/fixtures/model-test/foo-default.js b/node-tests/fixtures/model-test/foo-default.js index 4440fd8539c..7d570199909 100644 --- a/node-tests/fixtures/model-test/foo-default.js +++ b/node-tests/fixtures/model-test/foo-default.js @@ -1,6 +1,5 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -import { run } from '@ember/runloop'; module('Unit | Model | foo', function(hooks) { setupTest(hooks); @@ -8,7 +7,7 @@ module('Unit | Model | foo', function(hooks) { // Replace this with your real tests. test('it exists', function(assert) { let store = this.owner.lookup('service:store'); - let model = run(() => store.createRecord('foo', {})); + let model = store.createRecord('foo', {}); assert.ok(model); }); }); diff --git a/node-tests/fixtures/model-test/post-default.js b/node-tests/fixtures/model-test/post-default.js index b9d68646ce6..ba645efc9ee 100644 --- a/node-tests/fixtures/model-test/post-default.js +++ b/node-tests/fixtures/model-test/post-default.js @@ -1,6 +1,5 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -import { run } from '@ember/runloop'; module('Unit | Model | post', function(hooks) { setupTest(hooks); @@ -8,7 +7,7 @@ module('Unit | Model | post', function(hooks) { // Replace this with your real tests. test('it exists', function(assert) { let store = this.owner.lookup('service:store'); - let model = run(() => store.createRecord('post', {})); + let model = store.createRecord('post', {}); assert.ok(model); }); }); diff --git a/node-tests/fixtures/model-test/rfc232.js b/node-tests/fixtures/model-test/rfc232.js index 4440fd8539c..7d570199909 100644 --- a/node-tests/fixtures/model-test/rfc232.js +++ b/node-tests/fixtures/model-test/rfc232.js @@ -1,6 +1,5 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -import { run } from '@ember/runloop'; module('Unit | Model | foo', function(hooks) { setupTest(hooks); @@ -8,7 +7,7 @@ module('Unit | Model | foo', function(hooks) { // Replace this with your real tests. test('it exists', function(assert) { let store = this.owner.lookup('service:store'); - let model = run(() => store.createRecord('foo', {})); + let model = store.createRecord('foo', {}); assert.ok(model); }); }); diff --git a/node-tests/fixtures/serializer-test/application-default.js b/node-tests/fixtures/serializer-test/application-default.js index 7f9b85de818..d197afe0294 100644 --- a/node-tests/fixtures/serializer-test/application-default.js +++ b/node-tests/fixtures/serializer-test/application-default.js @@ -1,6 +1,5 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -import { run } from '@ember/runloop'; module('Unit | Serializer | application', function(hooks) { setupTest(hooks); @@ -15,7 +14,7 @@ module('Unit | Serializer | application', function(hooks) { test('it serializes records', function(assert) { let store = this.owner.lookup('service:store'); - let record = run(() => store.createRecord('application', {})); + let record = store.createRecord('application', {}); let serializedRecord = record.serialize(); diff --git a/node-tests/fixtures/serializer-test/foo-default.js b/node-tests/fixtures/serializer-test/foo-default.js index eb94a50b2a4..34805556175 100644 --- a/node-tests/fixtures/serializer-test/foo-default.js +++ b/node-tests/fixtures/serializer-test/foo-default.js @@ -1,6 +1,5 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -import { run } from '@ember/runloop'; module('Unit | Serializer | foo', function(hooks) { setupTest(hooks); @@ -15,7 +14,7 @@ module('Unit | Serializer | foo', function(hooks) { test('it serializes records', function(assert) { let store = this.owner.lookup('service:store'); - let record = run(() => store.createRecord('foo', {})); + let record = store.createRecord('foo', {}); let serializedRecord = record.serialize(); diff --git a/node-tests/fixtures/serializer-test/rfc232.js b/node-tests/fixtures/serializer-test/rfc232.js index eb94a50b2a4..34805556175 100644 --- a/node-tests/fixtures/serializer-test/rfc232.js +++ b/node-tests/fixtures/serializer-test/rfc232.js @@ -1,6 +1,5 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -import { run } from '@ember/runloop'; module('Unit | Serializer | foo', function(hooks) { setupTest(hooks); @@ -15,7 +14,7 @@ module('Unit | Serializer | foo', function(hooks) { test('it serializes records', function(assert) { let store = this.owner.lookup('service:store'); - let record = run(() => store.createRecord('foo', {})); + let record = store.createRecord('foo', {}); let serializedRecord = record.serialize(); diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index 5d7375bb612..c787fe11b01 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -144,9 +144,7 @@ test("When all records for a type are requested, records that are created on the assert.equal(get(allRecords, 'length'), 0, "precond - the record array's length is zero before any records are loaded"); - run(() => { - store.createRecord('person', { name: "Carsten Nielsen" }); - }); + store.createRecord('person', { name: "Carsten Nielsen" }); assert.equal(get(allRecords, 'length'), 1, "the record array's length is 1"); assert.equal(allRecords.objectAt(0).get('name'), "Carsten Nielsen", "the first item in the record array is Carsten Nielsen"); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 17e95316351..e5ac658334b 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -256,11 +256,8 @@ test("createRecord - a payload with a new ID and data applies the updates", func }); test("createRecord - a payload with a new ID and data applies the updates (with legacy singular name)", function(assert) { - let post; ajaxResponse({ post: { id: "1", name: "Dat Parley Letter" } }); - run(function() { - post = store.createRecord('post', { name: "The Parley Letter" }); - }); + let post = store.createRecord('post', { name: "The Parley Letter" }); return run(post, 'save').then(post => { assert.equal(passedUrl, "/posts"); @@ -297,7 +294,7 @@ test("createRecord - findMany doesn't overwrite owner", function(assert) { }); let post = store.peekRecord('post', 1); - let comment = run(() => store.createRecord('comment', { name: "The Parley Letter" })); + let comment = store.createRecord('comment', { name: "The Parley Letter" }); run(() => { post.get('comments').pushObject(comment); @@ -315,7 +312,6 @@ test("createRecord - findMany doesn't overwrite owner", function(assert) { }); test("createRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { - let post; env.registry.register('serializer:post', DS.RESTSerializer.extend({ primaryKey: '_id_', @@ -326,9 +322,7 @@ test("createRecord - a serializer's primary key and attributes are consulted whe ajaxResponse(); - run(() => { - post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); - }); + let post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); return run(() => post.save() @@ -513,14 +507,11 @@ test("createRecord - a record on the many side of a hasMany relationship should test("createRecord - sideloaded belongsTo relationships are both marked as loaded", function(assert) { assert.expect(4); - let post; Post.reopen({ comment: DS.belongsTo('comment', { async: false }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - run(() => { - post = store.createRecord('post', { name: "man" }); - }); + let post = store.createRecord('post', { name: "man" }); ajaxResponse({ posts: [{ id: 1, comment: 1, name: "marked" }], @@ -556,10 +547,7 @@ test("createRecord - response can contain relationships the client doesn't yet k Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - let post; - run(() => { - post = store.createRecord('post', { name: "Rails is omakase" }); - }); + let post = store.createRecord('post', { name: "Rails is omakase" }); return run(() => { return post.save().then(post => { @@ -575,15 +563,11 @@ test("createRecord - response can contain relationships the client doesn't yet k }); test("createRecord - relationships are not duplicated", function(assert) { - let post, comment; - Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - run(() => { - post = store.createRecord('post', { name: "Tomtomhuda" }); - comment = store.createRecord('comment', { id: 2, name: "Comment title" }); - }); + let post = store.createRecord('post', { name: "Tomtomhuda" }); + let comment = store.createRecord('comment', { id: 2, name: "Comment title" }); ajaxResponse({ post: [{ id: 1, name: "Rails is omakase", comments: [] }] }); @@ -989,7 +973,7 @@ test("deleteRecord - a payload with sidloaded updates pushes the updates when th }); test("deleteRecord - deleting a newly created record should not throw an error", function(assert) { - let post = run(() => store.createRecord('post')); + let post = store.createRecord('post'); return run(() => { post.deleteRecord(); diff --git a/tests/integration/adapter/serialize-test.js b/tests/integration/adapter/serialize-test.js index 1d2a80dc3ed..f0b1686b9b3 100644 --- a/tests/integration/adapter/serialize-test.js +++ b/tests/integration/adapter/serialize-test.js @@ -31,8 +31,6 @@ test("serialize() is delegated to the serializer", function(assert) { assert.deepEqual(options, { foo: 'bar' }); }; - run(() => { - let person = store.createRecord('person'); - adapter.serialize(person._createSnapshot(), { foo: 'bar' }); - }); + let person = store.createRecord('person'); + adapter.serialize(person._createSnapshot(), { foo: 'bar' }); }); diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 65534fb5560..f0fd2377618 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -117,12 +117,8 @@ test("by default, createRecords calls createRecord once per record", function(as }); }; - let tom, yehuda; - - run(() => { - tom = store.createRecord('person', { name: "Tom Dale" }); - yehuda = store.createRecord('person', { name: "Yehuda Katz" }); - }); + let tom = store.createRecord('person', { name: "Tom Dale" }); + let yehuda = store.createRecord('person', { name: "Yehuda Katz" }); let promise = run(() => { return hash({ @@ -502,9 +498,7 @@ test("if a created record is marked as invalid by the server, it enters an error } }; - let yehuda = run(() => { - return store.createRecord('person', { id: 1, name: "Yehuda Katz" }); - }); + let yehuda = store.createRecord('person', { id: 1, name: "Yehuda Katz" }); // Wrap this in an Ember.run so that all chained async behavior is set up // before flushing any scheduled behavior. return run(function() { @@ -549,9 +543,7 @@ test("allows errors on arbitrary properties on create", function(assert) { } }; - let yehuda = run(() => { - return store.createRecord('person', { id: 1, name: "Yehuda Katz" }); - }); + let yehuda = store.createRecord('person', { id: 1, name: "Yehuda Katz" }); // Wrap this in an Ember.run so that all chained async behavior is set up // before flushing any scheduled behavior. @@ -603,9 +595,7 @@ test("if a created record is marked as invalid by the server, you can attempt th } }; - let yehuda = run(() => { - return store.createRecord('person', { id: 1, name: "Yehuda Katz" }); - }); + let yehuda = store.createRecord('person', { id: 1, name: "Yehuda Katz" }); // Wrap this in an Ember.run so that all chained async behavior is set up // before flushing any scheduled behavior. @@ -1094,7 +1084,7 @@ test("async hasMany always returns a promise", function(assert) { }); }; - let tom = run(() => store.createRecord('person', { name: "Tom Dale" })); + let tom = store.createRecord('person', { name: "Tom Dale" }); run(() => { assert.ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise before save"); @@ -1115,12 +1105,9 @@ test("createRecord receives a snapshot", function(assert) { return resolve(); }; - var person; + let record = store.createRecord('person', { name: "Tom Dale", id: 1 }); - run(() => { - person = store.createRecord('person', { name: "Tom Dale", id: 1 }); - person.save(); - }); + run(() => record.save()); }); test("updateRecord receives a snapshot", function(assert) { @@ -1329,8 +1316,8 @@ test("record.save should pass adapterOptions to the createRecord method", functi }; return run(() => { - let person = store.createRecord('person', { name: 'Tom' }); - return person.save({ adapterOptions: { subscribe: true } }); + store.createRecord('person', { name: 'Tom' }) + .save({ adapterOptions: { subscribe: true } }); }); }); diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index 62966f4f0d9..e7a0561fabe 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -56,11 +56,8 @@ test("If an adapter implements the `generateIdForRecord` method, the store shoul } }; - let comment, post; - run(function() { - comment = env.store.createRecord('comment'); - post = env.store.createRecord('post'); - }); + let comment = env.store.createRecord('comment'); + let post = env.store.createRecord('post'); assert.equal(get(comment, 'id'), 'id-1', "comment is assigned id 'id-1'"); assert.equal(get(post, 'id'), 'id-2', "post is assigned id 'id-2'"); @@ -75,7 +72,6 @@ test("If an adapter implements the `generateIdForRecord` method, the store shoul test("empty string and undefined ids should coerce to null", function(assert) { assert.expect(6); - let comment, post; let idCount = 0; let id = 1; let ids = [undefined, '']; @@ -90,10 +86,8 @@ test("empty string and undefined ids should coerce to null", function(assert) { return resolve({ data: { id: id++, type: type.modelName } }); }; - run(() => { - comment = env.store.createRecord('misc'); - post = env.store.createRecord('misc'); - }); + let comment = env.store.createRecord('misc'); + let post = env.store.createRecord('misc'); assert.equal(get(comment, 'id'), null, "comment is assigned id 'null'"); assert.equal(get(post, 'id'), null, "post is assigned id 'null'"); diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index 5833c5506c8..0d0d0759697 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -141,9 +141,8 @@ test("Watching Records", function(assert) { assert.deepEqual(record.searchKeywords, ['1', 'Modified Post']); assert.deepEqual(record.color, 'blue'); - run(function() { - post = store.createRecord('post', { id: '2', title: 'New Post' }); - }); + post = store.createRecord('post', { id: '2', title: 'New Post' }); + assert.equal(get(addedRecords, 'length'), 1); record = addedRecords[0]; assert.deepEqual(record.columnValues, { id: '2', title: 'New Post' }); diff --git a/tests/integration/filter-test.js b/tests/integration/filter-test.js index fb5a8f38d32..ac934cd9532 100644 --- a/tests/integration/filter-test.js +++ b/tests/integration/filter-test.js @@ -196,9 +196,7 @@ test('a filtered record array includes created elements', function(assert) { assert.equal(get(recordArray, 'length'), 2, 'precond - The Record Array should have the filtered objects on it'); - run(() => { - store.createRecord('person', { name: 'Scumbag Koz' }); - }); + store.createRecord('person', { name: 'Scumbag Koz' }); assert.equal(get(recordArray, 'length'), 3, 'The record array has the new object on it'); }); @@ -566,11 +564,9 @@ test('it is possible to filter created records by dirtiness', function(assert) { return store.filter('person', person => !person.get('hasDirtyAttributes')); }); - let person = run(() => { - return store.createRecord('person', { - id: 1, - name: 'Tom Dale' - }); + let person = store.createRecord('person', { + id: 1, + name: 'Tom Dale' }); assert.equal(filter.get('length'), 0, 'the dirty record is not in the filter'); @@ -582,35 +578,6 @@ test('it is possible to filter created records by dirtiness', function(assert) { }); }); -test('it is possible to filter created records by isReloading', function(assert) { - customAdapter(env, DS.Adapter.extend({ - findRecord(store, type, id, snapshot) { - return { - data: { - id: 1, - type: 'person', - attributes: { - name: 'Tom Dalle' - } - } - }; - } - })); - - let filter = store.filter('person', person => { - return !person.get('isReloading'); - }); - - let person = store.createRecord('person', { - id: 1, - name: 'Tom Dale' - }); - - return person.reload().then(person => { - assert.equal(filter.get('length'), 1, 'the filter correctly returned a reloaded object'); - }); -}); - // SERVER SIDE TESTS let edited; @@ -632,9 +599,7 @@ function clientEdits(ids) { function clientCreates(names) { // wrap in an run to guarantee coalescence of the // iterated `set` calls. - edited = run(() => { - return names.map(name => store.createRecord('person', { name: 'Client-side ' + name })); - }); + edited = names.map(name => store.createRecord('person', { name: 'Client-side ' + name })); } function serverResponds() { diff --git a/tests/integration/injection-test.js b/tests/integration/injection-test.js index 2ef91bcf148..81fda524348 100644 --- a/tests/integration/injection-test.js +++ b/tests/integration/injection-test.js @@ -101,7 +101,7 @@ module('integration/injection eager injections', { }); test('did inject', function(assert) { - let foo = run(() => env.store.createRecord('foo')); + let foo = env.store.createRecord('foo'); let apple = foo.get('apple'); let Apple = env.registry.registrations['service:apple']; diff --git a/tests/integration/lifecycle-hooks-test.js b/tests/integration/lifecycle-hooks-test.js index 705997b19f5..9e6de92c52e 100644 --- a/tests/integration/lifecycle-hooks-test.js +++ b/tests/integration/lifecycle-hooks-test.js @@ -33,7 +33,7 @@ test("When the adapter acknowledges that a record has been created, a `didCreate return resolve({ data: { id: 99, type: "person", attributes: { name: "Yehuda Katz" } } }); }; - let person = run(() => env.store.createRecord('person', { name: "Yehuda Katz" })); + let person = env.store.createRecord('person', { name: "Yehuda Katz" }); person.on('didCreate', function() { assert.equal(this, person, "this is bound to the record"); @@ -52,7 +52,7 @@ test("When the adapter acknowledges that a record has been created without a new return resolve(); }; - let person = run(() => env.store.createRecord('person', { id: 99, name: "Yehuda Katz" })); + let person = env.store.createRecord('person', { id: 99, name: "Yehuda Katz" }); person.on('didCreate', function() { assert.equal(this, person, "this is bound to the record"); diff --git a/tests/integration/record-array-test.js b/tests/integration/record-array-test.js index cf2ec8c1288..02b73cc5aba 100644 --- a/tests/integration/record-array-test.js +++ b/tests/integration/record-array-test.js @@ -379,20 +379,15 @@ test('a newly created record is removed from a record array when it is deleted', tag: Tag }); let recordArray = store.peekAll('person'); - let scumbag = run(() => { - return store.createRecord('person', { - name: 'Scumbag Dale' - }); + let scumbag = store.createRecord('person', { + name: 'Scumbag Dale' }); assert.equal(get(recordArray, 'length'), 1, 'precond - record array already has the first created item'); - // guarantee coalescence - run(() => { - store.createRecord('person', { name: 'p1' }); - store.createRecord('person', { name: 'p2' }); - store.createRecord('person', { name: 'p3' }); - }); + store.createRecord('person', { name: 'p1' }); + store.createRecord('person', { name: 'p2' }); + store.createRecord('person', { name: 'p3' }); assert.equal(get(recordArray, 'length'), 4, 'precond - record array has the created item'); assert.equal(recordArray.objectAt(0), scumbag, 'item at index 0 is record with id 1'); diff --git a/tests/integration/record-arrays/peeked-records-test.js b/tests/integration/record-arrays/peeked-records-test.js index 2693d2ac7ad..f2a4af70fea 100644 --- a/tests/integration/record-arrays/peeked-records-test.js +++ b/tests/integration/record-arrays/peeked-records-test.js @@ -105,10 +105,9 @@ test('peekAll in the same run-loop as push works as expected', function(assert) test('newly created records notify the array as expected', function(assert) { let peekedRecordArray = run(() => store.peekAll('person')); let watcher = watchProperties(peekedRecordArray, ['length', '[]']); - - let aNewlyCreatedRecord = run(() => store.createRecord('person', { + let aNewlyCreatedRecord = store.createRecord('person', { name: 'James' - })); + }); assert.watchedPropertyCounts( watcher, @@ -130,10 +129,9 @@ test('newly created records notify the array as expected', function(assert) { test('immediately peeking newly created records works as expected', function(assert) { let peekedRecordArray = run(() => store.peekAll('person')); let watcher = watchProperties(peekedRecordArray, ['length', '[]']); - - let aNewlyCreatedRecord = run(() => store.createRecord('person', { + let aNewlyCreatedRecord = store.createRecord('person', { name: 'James' - })); + }); assert.watchedPropertyCounts( watcher, @@ -156,9 +154,9 @@ test('immediately peeking newly created records works as expected', function(ass test('unloading newly created records notify the array as expected', function(assert) { let peekedRecordArray = run(() => store.peekAll('person')); let watcher = watchProperties(peekedRecordArray, ['length', '[]']); - let aNewlyCreatedRecord = run(() => store.createRecord('person', { + let aNewlyCreatedRecord = store.createRecord('person', { name: 'James' - })); + }); assert.watchedPropertyCounts( watcher, @@ -180,9 +178,9 @@ test('unloading newly created records notify the array as expected', function(as test('immediately peeking after unloading newly created records works as expected', function(assert) { let peekedRecordArray = run(() => store.peekAll('person')); let watcher = watchProperties(peekedRecordArray, ['length', '[]']); - let aNewlyCreatedRecord = run(() => store.createRecord('person', { + let aNewlyCreatedRecord = store.createRecord('person', { name: 'James' - })); + }); assert.watchedPropertyCounts( watcher, diff --git a/tests/integration/records/collection-save-test.js b/tests/integration/records/collection-save-test.js index ebe56231995..cd715aa1083 100644 --- a/tests/integration/records/collection-save-test.js +++ b/tests/integration/records/collection-save-test.js @@ -25,10 +25,9 @@ module("integration/records/collection_save - Save Collection of Records", { test("Collection will resolve save on success", function(assert) { assert.expect(1); let id = 1; - run(() => { - env.store.createRecord('post', { title: 'Hello' }); - env.store.createRecord('post', { title: 'World' }); - }); + + env.store.createRecord('post', { title: 'Hello' }); + env.store.createRecord('post', { title: 'World' }); let posts = env.store.peekAll('post'); @@ -44,10 +43,8 @@ test("Collection will resolve save on success", function(assert) { }); test("Collection will reject save on error", function(assert) { - run(() => { - env.store.createRecord('post', { title: 'Hello' }); - env.store.createRecord('post', { title: 'World' }); - }); + env.store.createRecord('post', { title: 'Hello' }); + env.store.createRecord('post', { title: 'World' }); let posts = env.store.peekAll('post'); @@ -63,10 +60,8 @@ test("Collection will reject save on error", function(assert) { }); test("Retry is allowed in a failure handler", function(assert) { - run(() => { - env.store.createRecord('post', { title: 'Hello' }); - env.store.createRecord('post', { title: 'World' }); - }); + env.store.createRecord('post', { title: 'Hello' }); + env.store.createRecord('post', { title: 'World' }); let posts = env.store.peekAll('post'); @@ -99,10 +94,8 @@ test("Retry is allowed in a failure handler", function(assert) { test("Collection will reject save on invalid", function(assert) { assert.expect(1); - run(() => { - env.store.createRecord('post', { title: 'Hello' }); - env.store.createRecord('post', { title: 'World' }); - }); + env.store.createRecord('post', { title: 'Hello' }); + env.store.createRecord('post', { title: 'World' }); let posts = env.store.peekAll('post'); diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index 957c3ecc38f..e8749f50e6e 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -308,10 +308,8 @@ test("Will resolve destroy and save in same loop", function(assert) { }); }; - run(function() { - adam = env.store.createRecord('person', { name: 'Adam Sunderland' }); - dave = env.store.createRecord('person', { name: 'Dave Sunderland' }); - }); + adam = env.store.createRecord('person', { name: 'Adam Sunderland' }); + dave = env.store.createRecord('person', { name: 'Dave Sunderland' }); run(function() { promises = [ diff --git a/tests/integration/records/error-test.js b/tests/integration/records/error-test.js index a1841c4e57f..10ea3ba7289 100644 --- a/tests/integration/records/error-test.js +++ b/tests/integration/records/error-test.js @@ -75,12 +75,10 @@ testInDebug('adding errors during root.loaded.created.invalid works', function(a testInDebug('adding errors root.loaded.created.invalid works', function(assert) { assert.expect(5); - var person = run(() => { - return store.createRecord('person', { - id: 'wat', - firstName: 'Yehuda', - lastName: 'Katz' - }); + let person = store.createRecord('person', { + id: 'wat', + firstName: 'Yehuda', + lastName: 'Katz' }); run(() => { @@ -105,11 +103,9 @@ testInDebug('adding errors root.loaded.created.invalid works', function(assert) testInDebug('adding errors root.loaded.created.invalid works add + remove + add', function(assert) { assert.expect(7); - var person = run(() => { - return store.createRecord('person', { - id: 'wat', - firstName: 'Yehuda' - }); + let person = store.createRecord('person', { + id: 'wat', + firstName: 'Yehuda' }); run(() => { @@ -136,11 +132,9 @@ testInDebug('adding errors root.loaded.created.invalid works add + remove + add' testInDebug('adding errors root.loaded.created.invalid works add + (remove, add)', function(assert) { assert.expect(6); - var person = run(() => { - return store.createRecord('person', { - id: 'wat', - firstName: 'Yehuda' - }); + let person = store.createRecord('person', { + id: 'wat', + firstName: 'Yehuda' }); run(() => { diff --git a/tests/integration/records/save-test.js b/tests/integration/records/save-test.js index 4be3a2990e3..018d3fd2066 100644 --- a/tests/integration/records/save-test.js +++ b/tests/integration/records/save-test.js @@ -24,10 +24,7 @@ module("integration/records/save - Save Record", { test("Will resolve save on success", function(assert) { assert.expect(4); - var post; - run(function() { - post = env.store.createRecord('post', { title: 'toto' }); - }); + let post = env.store.createRecord('post', { title: 'toto' }); var deferred = defer(); env.adapter.createRecord = function(store, type, snapshot) { @@ -50,10 +47,7 @@ test("Will resolve save on success", function(assert) { }); test("Will reject save on error", function(assert) { - var post; - run(function() { - post = env.store.createRecord('post', { title: 'toto' }); - }); + let post = env.store.createRecord('post', { title: 'toto' }); env.adapter.createRecord = function(store, type, snapshot) { var error = new DS.InvalidError([{ title: 'not valid' }]); @@ -69,10 +63,7 @@ test("Will reject save on error", function(assert) { }); test("Retry is allowed in a failure handler", function(assert) { - var post; - run(function() { - post = env.store.createRecord('post', { title: 'toto' }); - }); + let post = env.store.createRecord('post', { title: 'toto' }); var count = 0; @@ -97,11 +88,7 @@ test("Retry is allowed in a failure handler", function(assert) { test("Repeated failed saves keeps the record in uncommited state", function(assert) { assert.expect(4); - var post; - - run(function() { - post = env.store.createRecord('post', { title: 'toto' }); - }); + let post = env.store.createRecord('post', { title: 'toto' }); env.adapter.createRecord = function(store, type, snapshot) { return reject(); @@ -122,11 +109,7 @@ test("Repeated failed saves keeps the record in uncommited state", function(asse test("Repeated failed saves with invalid error marks the record as invalid", function(assert) { assert.expect(2); - var post; - - run(function() { - post = env.store.createRecord('post', { title: 'toto' }); - }); + let post = env.store.createRecord('post', { title: 'toto' }); env.adapter.createRecord = function(store, type, snapshot) { var error = new DS.InvalidError([ @@ -152,11 +135,7 @@ test("Repeated failed saves with invalid error marks the record as invalid", fun test("Repeated failed saves with invalid error without payload marks the record as invalid", function(assert) { assert.expect(2); - var post; - - run(function() { - post = env.store.createRecord('post', { title: 'toto' }); - }); + let post = env.store.createRecord('post', { title: 'toto' }); env.adapter.createRecord = function(store, type, snapshot) { var error = new DS.InvalidError(); @@ -177,10 +156,7 @@ test("Repeated failed saves with invalid error without payload marks the record test("Will reject save on invalid", function(assert) { assert.expect(1); - var post; - run(function() { - post = env.store.createRecord('post', { title: 'toto' }); - }); + let post = env.store.createRecord('post', { title: 'toto' }); env.adapter.createRecord = function(store, type, snapshot) { var error = new DS.InvalidError([{ title: 'not valid' }]); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 236dd9f3ff2..6b954f18463 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -499,11 +499,10 @@ test("polymorphic belongsTo class-checks check the superclass when MODEL_FACTORY test("the subclass in a polymorphic belongsTo relationship is an instanceof its superclass", function(assert) { setupModelFactoryInjections(false); assert.expect(1); - run(() => { - let message = env.store.createRecord('message', { id: 1 }); - let comment = env.store.createRecord('comment', { id: 2, message: message }); - assert.ok(comment instanceof Message, 'a comment is an instance of a message'); - }); + + let message = env.store.createRecord('message', { id: 1 }); + let comment = env.store.createRecord('comment', { id: 2, message: message }); + assert.ok(comment instanceof Message, 'a comment is an instance of a message'); }); test("relationshipsByName does not cache a factory", function(assert) { @@ -969,16 +968,13 @@ test("Model's belongsTo relationship should not be created during model creation }); test("Model's belongsTo relationship should be created during model creation if relationship passed in constructor", function(assert) { - let user, message; - - run(() => { - message = env.store.createRecord('message'); - user = env.store.createRecord('user', { - name: 'John Doe', - favouriteMessage: message - }); - assert.ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); + let message = env.store.createRecord('message'); + let user = env.store.createRecord('user', { + name: 'John Doe', + favouriteMessage: message }); + + assert.ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); }); test("Model's belongsTo relationship should be created during 'set' method", function(assert) { diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index fa4752eaec3..fe63d8490f5 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1515,13 +1515,10 @@ test("Polymorphic relationships with a hasMany is set up correctly on both sides Post.reopen({ contact: DS.belongsTo('contact', { polymorphic: true, async: false }) }); - let email, post; - run(function () { - email = env.store.createRecord('email'); - post = env.store.createRecord('post', { - contact: email - }); + let email = env.store.createRecord('email'); + let post = env.store.createRecord('post', { + contact: email }); assert.equal(post.get('contact'), email, 'The polymorphic belongsTo is set up correctly'); @@ -1696,11 +1693,7 @@ test("A record can be removed from a polymorphic association", function(assert) test("When a record is created on the client, its hasMany arrays should be in a loaded state", function(assert) { assert.expect(3); - let post; - - run(function() { - post = env.store.createRecord('post'); - }); + let post = env.store.createRecord('post'); assert.ok(get(post, 'isLoaded'), "The post should have isLoaded flag"); let comments; @@ -1720,9 +1713,7 @@ test("When a record is created on the client, its async hasMany arrays should be comments: DS.hasMany('comment', { async: true }) }); - let post = run(function() { - return env.store.createRecord('post'); - }); + let post = env.store.createRecord('post'); assert.ok(get(post, 'isLoaded'), "The post should have isLoaded flag"); @@ -1737,9 +1728,8 @@ test("When a record is created on the client, its async hasMany arrays should be test("we can set records SYNC HM relationship", function(assert) { assert.expect(1); - let post = run(function() { - return env.store.createRecord('post'); - }); + let post = env.store.createRecord('post'); + run(function() { env.store.push({ data: [{ @@ -1768,9 +1758,8 @@ test("We can set records ASYNC HM relationship", function(assert) { comments: DS.hasMany('comment', { async: true }) }); - let post = run(function() { - return env.store.createRecord('post'); - }); + let post = env.store.createRecord('post'); + run(function() { env.store.push({ data: [{ @@ -2773,40 +2762,36 @@ test("hasMany hasData async created", function(assert) { pages: hasMany('pages', { async: true }) }); - run(() => { - let chapter = store.createRecord('chapter', { title: 'The Story Begins' }); - let page = store.createRecord('page'); + let chapter = store.createRecord('chapter', { title: 'The Story Begins' }); + let page = store.createRecord('page'); - let relationship = chapter._internalModel._relationships.get('pages'); - assert.equal(relationship.hasData, false, 'relationship does not have data'); + let relationship = chapter._internalModel._relationships.get('pages'); + assert.equal(relationship.hasData, false, 'relationship does not have data'); - chapter = store.createRecord('chapter', { - title: 'The Story Begins', - pages: [page] - }); - - relationship = chapter._internalModel._relationships.get('pages'); - assert.equal(relationship.hasData, true, 'relationship has data'); + chapter = store.createRecord('chapter', { + title: 'The Story Begins', + pages: [page] }); + + relationship = chapter._internalModel._relationships.get('pages'); + assert.equal(relationship.hasData, true, 'relationship has data'); }); test("hasMany hasData sync created", function(assert) { assert.expect(2); - run(() => { - let chapter = store.createRecord('chapter', { title: 'The Story Begins' }); - let relationship = chapter._internalModel._relationships.get('pages'); - - assert.equal(relationship.hasData, false, 'relationship does not have data'); + let chapter = store.createRecord('chapter', { title: 'The Story Begins' }); + let relationship = chapter._internalModel._relationships.get('pages'); - chapter = store.createRecord('chapter', { - title: 'The Story Begins', - pages: [store.createRecord('page')] - }); - relationship = chapter._internalModel._relationships.get('pages'); + assert.equal(relationship.hasData, false, 'relationship does not have data'); - assert.equal(relationship.hasData, true, 'relationship has data'); + chapter = store.createRecord('chapter', { + title: 'The Story Begins', + pages: [store.createRecord('page')] }); + relationship = chapter._internalModel._relationships.get('pages'); + + assert.equal(relationship.hasData, true, 'relationship has data'); }); test("Model's hasMany relationship should not be created during model creation", function(assert) { diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index 41249b75226..088b4e9600e 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -28,12 +28,9 @@ test("When a record is added to a has-many relationship, the inverse belongsTo i var env = setupStore({ post: Post, comment: Comment }); var store = env.store; - var comment, post; - run(function() { - comment = store.createRecord('comment'); - post = store.createRecord('post'); - }); + let comment = store.createRecord('comment'); + let post = store.createRecord('post'); assert.equal(comment.get('post'), null, "no post has been set on the comment"); @@ -59,12 +56,9 @@ test("Inverse relationships can be explicitly nullable", function(assert) { user: User, post: Post }); - var user, post; - run(function() { - user = store.createRecord('user'); - post = store.createRecord('post'); - }); + let user = store.createRecord('user'); + let post = store.createRecord('post'); assert.equal(user.inverseFor('posts').name, 'participants', 'User.posts inverse is Post.participants'); assert.equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); @@ -87,12 +81,9 @@ test("Null inverses are excluded from potential relationship resolutions", funct user: User, post: Post }); - let user, post; - run(function() { - user = store.createRecord('user'); - post = store.createRecord('post'); - }); + let user = store.createRecord('user'); + let post = store.createRecord('post'); assert.equal(user.inverseFor('posts').name, 'participants', 'User.posts inverse is Post.participants'); assert.equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); @@ -113,12 +104,9 @@ test("When a record is added to a has-many relationship, the inverse belongsTo c var env = setupStore({ post: Post, comment: Comment }); var store = env.store; - var comment, post; - run(function() { - comment = store.createRecord('comment'); - post = store.createRecord('post'); - }); + let comment = store.createRecord('comment'); + let post = store.createRecord('post'); assert.equal(comment.get('onePost'), null, "onePost has not been set on the comment"); assert.equal(comment.get('twoPost'), null, "twoPost has not been set on the comment"); @@ -179,13 +167,11 @@ test("When setting a belongsTo, the OneToOne invariant is respected even when ot var env = setupStore({ post: Post, comment: Comment }); var store = env.store; - var comment, post, post2; - run(function() { - comment = store.createRecord('comment'); - post = store.createRecord('post'); - post2 = store.createRecord('post'); - }); + let comment = store.createRecord('comment'); + let post = store.createRecord('post'); + let post2 = store.createRecord('post'); + run(function() { comment.set('post', post); post2.set('bestComment', null); @@ -217,13 +203,10 @@ test("When setting a belongsTo, the OneToOne invariant is transitive", function( post: Post, comment: Comment }); - var post, post2, comment; - run(function() { - comment = store.createRecord('comment'); - post = store.createRecord('post'); - post2 = store.createRecord('post'); - }); + let comment = store.createRecord('comment'); + let post = store.createRecord('post'); + let post2 = store.createRecord('post'); run(function() { comment.set('post', post); @@ -255,13 +238,12 @@ test("When setting a belongsTo, the OneToOne invariant is commutative", function post: Post, comment: Comment }); - var post, comment, comment2; - run(function() { - post = store.createRecord('post'); - comment = store.createRecord('comment'); - comment2 = store.createRecord('comment'); + let post = store.createRecord('post'); + let comment = store.createRecord('comment'); + let comment2 = store.createRecord('comment'); + run(function() { comment.set('post', post); }); @@ -290,13 +272,10 @@ test("OneToNone relationship works", function(assert) { var env = setupStore({ post: Post, comment: Comment }); var store = env.store; - var comment, post1, post2; - run(function() { - comment = store.createRecord('comment'); - post1 = store.createRecord('post'); - post2 = store.createRecord('post'); - }); + let comment = store.createRecord('comment'); + let post1 = store.createRecord('post'); + let post2 = store.createRecord('post'); run(function() { comment.set('post', post1); @@ -335,12 +314,9 @@ test("When a record is added to or removed from a polymorphic has-many relations var env = setupStore({ user: User, message: Message, post: Post }); var store = env.store; - var post, user; - run(function() { - post = store.createRecord('post'); - user = store.createRecord('user'); - }); + let post = store.createRecord('post'); + let user = store.createRecord('user'); assert.equal(post.get('oneUser'), null, "oneUser has not been set on the user"); assert.equal(post.get('twoUser'), null, "twoUser has not been set on the user"); @@ -381,16 +357,15 @@ test("When a record's belongsTo relationship is set, it can specify the inverse var env = setupStore({ user: User, message: Message, post: Post }); var store = env.store; - var user, post; - run(function() { - user = store.createRecord('user'); - post = store.createRecord('post'); + let user = store.createRecord('user'); + let post = store.createRecord('post'); - assert.equal(user.get('meMessages.length'), 0, "meMessages has no posts"); - assert.equal(user.get('youMessages.length'), 0, "youMessages has no posts"); - assert.equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(user.get('meMessages.length'), 0, "meMessages has no posts"); + assert.equal(user.get('youMessages.length'), 0, "youMessages has no posts"); + assert.equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + run(function() { post.set('user', user); }); @@ -426,16 +401,15 @@ test("When a record's polymorphic belongsTo relationship is set, it can specify var env = setupStore({ comment: Comment, message: Message, post: Post }); var store = env.store; - var comment, post; - run(function() { - comment = store.createRecord('comment'); - post = store.createRecord('post'); + let comment = store.createRecord('comment'); + let post = store.createRecord('post'); - assert.equal(post.get('meMessages.length'), 0, "meMessages has no posts"); - assert.equal(post.get('youMessages.length'), 0, "youMessages has no posts"); - assert.equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(post.get('meMessages.length'), 0, "meMessages has no posts"); + assert.equal(post.get('youMessages.length'), 0, "youMessages has no posts"); + assert.equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + run(function() { comment.set('message', post); }); @@ -462,9 +436,8 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a has var env = setupStore({ post: Post, comment: Comment, user: User }); var post; - run(function() { - env.store.createRecord('comment'); - }); + + env.store.createRecord('comment'); assert.expectAssertion(function() { run(function() { @@ -484,9 +457,7 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a bel var env = setupStore({ post: Post, comment: Comment, user: User }); var post; - run(function() { - env.store.createRecord('user'); - }); + env.store.createRecord('user'); assert.expectAssertion(function() { run(function() { @@ -641,9 +612,9 @@ testInDebug("Inverse null relationships with models that don't exist throw a nic let env = setupStore({ user: User }); assert.expectAssertion(() => { - run(() => env.store.createRecord('user', { post: {}})); + env.store.createRecord('user', { post: {}}); }, /No model was found for/) // but don't error if the relationship is not used - run(() => env.store.createRecord('user', {})); + env.store.createRecord('user', {}); }); diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index 12bddd0a3e1..ff2dcf8a1ed 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -1477,7 +1477,7 @@ test("createRecord updates inverse record array which has observers", function(a user.addObserver('messages.@each.title', () => {}); user.get('messages.firstObject'); - let message = run(() => store.createRecord('message', { user, title: 'EmberFest was great' })); + let message = store.createRecord('message', { user, title: 'EmberFest was great' }); assert.equal(user.get('messages.length'), 1, 'The message is added to the record array'); let messageFromArray = user.get('messages.firstObject'); diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index fc6a8b3bc26..ee33f3b76a9 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -8,9 +8,8 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; -var HomePlanet, SuperVillain, CommanderVillain, NormalMinion, EvilMinion, YellowMinion, RedMinion, SecretLab, SecretWeapon, BatCave, Comment, - league, superVillain, commanderVillain, evilMinion, yellowMinion, redMinion, secretWeapon, homePlanet, secretLab, env; -var LightSaber; +var HomePlanet, SuperVillain, CommanderVillain, NormalMinion, EvilMinion, YellowMinion, RedMinion, + SecretLab, SecretWeapon, BatCave, Comment, env, LightSaber; module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { beforeEach() { @@ -862,10 +861,7 @@ test("normalizeResponse with embedded objects of same type, but from separate at }); test("serialize supports serialize:false on non-relationship properties", function(assert) { - var tom; - run(function() { - tom = env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", id: '1' }); - }); + let tom = env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", id: '1' }); env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -886,11 +882,8 @@ test("serialize supports serialize:false on non-relationship properties", functi }); test("serialize with embedded objects (hasMany relationship)", function(assert) { - var tom, league; - run(function() { - league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); - tom = env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); - }); + let league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); + let tom = env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -918,11 +911,8 @@ test("serialize with embedded objects (hasMany relationship)", function(assert) }); test("serialize with embedded objects and a custom keyForAttribute (hasMany relationship)", function(assert) { - var tom, league; - run(function() { - league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); - tom = env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); - }); + let league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); + let tom = env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { keyForRelationship(key) { @@ -988,10 +978,8 @@ testInDebug("serialize with embedded objects (unknown hasMany relationship)", fu }); test("serialize with embedded objects (hasMany relationship) supports serialize:false", function(assert) { - run(function() { - league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); - env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); - }); + let league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); + env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1011,10 +999,8 @@ test("serialize with embedded objects (hasMany relationship) supports serialize: }); test("serialize with (new) embedded objects (hasMany relationship)", function(assert) { - run(function() { - league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); - env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league }); - }); + let league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); + env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league }); env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1039,10 +1025,11 @@ test("serialize with (new) embedded objects (hasMany relationship)", function(as }); test("serialize with embedded objects (hasMany relationships, including related objects not embedded)", function(assert) { + let superVillain = env.store.createRecord('super-villain', { id: 1, firstName: "Super", lastName: "Villian" }); + let evilMinion = env.store.createRecord('evil-minion', { id: 1, name: "Evil Minion", superVillian: superVillain }); + let secretWeapon = env.store.createRecord('secret-weapon', { id: 1, name: "Secret Weapon", superVillain: superVillain }); + run(function() { - superVillain = env.store.createRecord('super-villain', { id: 1, firstName: "Super", lastName: "Villian" }); - evilMinion = env.store.createRecord('evil-minion', { id: 1, name: "Evil Minion", superVillian: superVillain }); - secretWeapon = env.store.createRecord('secret-weapon', { id: 1, name: "Secret Weapon", superVillain: superVillain }); superVillain.get('evilMinions').pushObject(evilMinion); superVillain.get('secretWeapons').pushObject(secretWeapon); }); @@ -1074,11 +1061,9 @@ test("serialize with embedded objects (hasMany relationships, including related }); test("serialize has many relationship using the `ids-and-types` strategy", function(assert) { - run(function() { - yellowMinion = env.store.createRecord('yellow-minion', { id: 1, name: "Yellowy" }); - redMinion = env.store.createRecord('red-minion', { id: 1, name: "Reddy" }); - commanderVillain = env.store.createRecord('commander-villain', { id: 1, name: "Jeff", minions: [yellowMinion, redMinion] }); - }); + let yellowMinion = env.store.createRecord('yellow-minion', { id: 1, name: "Yellowy" }); + let redMinion = env.store.createRecord('red-minion', { id: 1, name: "Reddy" }); + let commanderVillain = env.store.createRecord('commander-villain', { id: 1, name: "Jeff", minions: [yellowMinion, redMinion] }); env.registry.register('serializer:commander-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1128,11 +1113,7 @@ test("normalizeResponse with embedded object (belongsTo relationship)", function secretWeapons: [] } }; - var json; - - run(function() { - json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); - }); + let json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); assert.deepEqual(json, { "data": { @@ -1179,24 +1160,17 @@ test("serialize with embedded object (belongsTo relationship)", function(assert) secretLab: { embedded: 'always' } } })); - var serializer, json, tom; - run(function() { - serializer = env.store.serializerFor("super-villain"); - - // records with an id, persisted - tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); - }); + // records with an id, persisted + let tom = env.store.createRecord( + 'super-villain', + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) + } + ); - run(function() { - json = serializer.serialize(tom._createSnapshot()); - }); + let json = env.store.serializerFor("super-villain").serialize(tom._createSnapshot()); assert.deepEqual(json, { firstName: get(tom, "firstName"), @@ -1221,31 +1195,26 @@ test("serialize with embedded object (polymorphic belongsTo relationship)", func secretLab: DS.belongsTo('secret-lab', { polymorphic: true }) }); - var json, tom; - run(function() { - tom = env.store.createRecord( - 'super-villain', - { - id: "1", - firstName: "Tom", - lastName: "Dale", - secretLab: env.store.createRecord('bat-cave', { - id: "101", - minionCapacity: 5000, - vicinity: "California, USA", - infiltrated: true - }), - homePlanet: env.store.createRecord('home-planet', { - id: "123", - name: "Villain League" - }) - } - ); - }); + let tom = env.store.createRecord( + 'super-villain', + { + id: "1", + firstName: "Tom", + lastName: "Dale", + secretLab: env.store.createRecord('bat-cave', { + id: "101", + minionCapacity: 5000, + vicinity: "California, USA", + infiltrated: true + }), + homePlanet: env.store.createRecord('home-planet', { + id: "123", + name: "Villain League" + }) + } + ); - run(function() { - json = tom.serialize(); - }); + let json = tom.serialize(); assert.deepEqual(json, { firstName: get(tom, "firstName"), @@ -1275,21 +1244,15 @@ test("serialize with embedded object (belongsTo relationship) works with differe var serializer = env.store.serializerFor("super-villain"); // records with an id, persisted - var tom, json; - - run(function() { - tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); - }); + let tom = env.store.createRecord( + 'super-villain', + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) + } + ); - run(function() { - json = serializer.serialize(tom._createSnapshot()); - }); + let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { firstName: get(tom, "firstName"), @@ -1313,21 +1276,14 @@ test("serialize with embedded object (belongsTo relationship, new no id)", funct var serializer = env.store.serializerFor("super-villain"); // records without ids, new - var tom, json; - - run(function() { - tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); - }); - - run(function() { - json = serializer.serialize(tom._createSnapshot()); - }); + let tom = env.store.createRecord( + 'super-villain', + { firstName: "Tom", lastName: "Dale", + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) + } + ); + let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { firstName: get(tom, "firstName"), @@ -1351,20 +1307,15 @@ test("serialize with embedded object (polymorphic belongsTo relationship) suppor } })); - var tom, json; - run(function() { - tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('bat-cave', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); - }); + let tom = env.store.createRecord( + 'super-villain', + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord('bat-cave', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) + } + ); - run(function() { - json = tom.serialize(); - }); + let json = tom.serialize(); assert.deepEqual(json, { firstName: get(tom, "firstName"), @@ -1386,20 +1337,15 @@ test("serialize with embedded object (belongsTo relationship) supports serialize } })); - var tom, json; - run(function() { - tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('bat-cave', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); - }); + let tom = env.store.createRecord( + 'super-villain', + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord('bat-cave', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) + } + ); - run(function() { - json = tom.serialize(); - }); + let json = tom.serialize(); assert.deepEqual(json, { firstName: get(tom, "firstName"), @@ -1421,20 +1367,15 @@ test("serialize with embedded object (belongsTo relationship) supports serialize } })); - var tom, json; - run(function() { - tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('bat-cave', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); - }); + let tom = env.store.createRecord( + 'super-villain', + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord('bat-cave', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) + } + ); - run(function() { - json = tom.serialize(); - }); + let json = tom.serialize(); assert.deepEqual(json, { firstName: get(tom, "firstName"), @@ -1454,21 +1395,15 @@ test("serialize with embedded object (belongsTo relationship) supports serialize var serializer = env.store.serializerFor("super-villain"); // records with an id, persisted - var tom, json; - - run(function() { - tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); - }); + let tom = env.store.createRecord( + 'super-villain', + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) + } + ); - run(function() { - json = serializer.serialize(tom._createSnapshot()); - }); + let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { firstName: get(tom, "firstName"), @@ -1488,21 +1423,14 @@ test("serialize with embedded object (belongsTo relationship) supports serialize var serializer = env.store.serializerFor("super-villain"); // records with an id, persisted - var tom, json; - - run(function() { - tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); - }); - - run(function() { - json = serializer.serialize(tom._createSnapshot()); - }); + let tom = env.store.createRecord( + 'super-villain', + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) + } + ); + let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { firstName: get(tom, "firstName"), @@ -1522,21 +1450,14 @@ test("serialize with embedded object (belongsTo relationship) supports serialize var serializer = env.store.serializerFor("super-villain"); // records with an id, persisted - var tom, json; - - run(function() { - tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); - }); - - run(function() { - json = serializer.serialize(tom._createSnapshot()); - }); + let tom = env.store.createRecord( + 'super-villain', + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) + } + ); + let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { firstName: get(tom, "firstName"), @@ -1556,20 +1477,14 @@ test("serialize with embedded object (belongsTo relationship) supports serialize // records with an id, persisted - var tom, json; - run(function() { - tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); - }); - - run(function() { - json = serializer.serialize(tom._createSnapshot()); - }); + let tom = env.store.createRecord( + 'super-villain', + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) + } + ); + let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { firstName: get(tom, "firstName"), @@ -1583,22 +1498,14 @@ test("serialize with embedded object (belongsTo relationship) serializes the id var serializer = env.store.serializerFor("super-villain"); // records with an id, persisted - - var tom, json; - - run(function() { - tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); - }); - - run(function() { - json = serializer.serialize(tom._createSnapshot()); - }); + let tom = env.store.createRecord( + 'super-villain', + { firstName: "Tom", lastName: "Dale", id: "1", + secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) + } + ); + let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { firstName: get(tom, "firstName"), @@ -1615,20 +1522,13 @@ test("when related record is not present, serialize embedded record (with a belo } })); var serializer = env.store.serializerFor("super-villain"); - var tom, json; - - run(function() { - tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); - }); - - run(function() { - json = serializer.serialize(tom._createSnapshot()); - }); + let tom = env.store.createRecord( + 'super-villain', + { firstName: "Tom", lastName: "Dale", id: "1", + homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) + } + ); + let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { firstName: get(tom, "firstName"), @@ -1998,13 +1898,15 @@ test("normalizeResponse with polymorphic belongsTo and custom primary key", func }); test("Mixin can be used with RESTSerializer which does not define keyForAttribute", function(assert) { + let homePlanet = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); + let secretLab = env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); + let superVillain = env.store.createRecord('super-villain', { + id: "1", firstName: "Super", lastName: "Villian", homePlanet: homePlanet, secretLab: secretLab + }); + let secretWeapon = env.store.createRecord('secret-weapon', { id: "1", name: "Secret Weapon", superVillain: superVillain }); + let evilMinion; + run(function() { - homePlanet = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); - secretLab = env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); - superVillain = env.store.createRecord('super-villain', { - id: "1", firstName: "Super", lastName: "Villian", homePlanet: homePlanet, secretLab: secretLab - }); - secretWeapon = env.store.createRecord('secret-weapon', { id: "1", name: "Secret Weapon", superVillain: superVillain }); superVillain.get('secretWeapons').pushObject(secretWeapon); evilMinion = env.store.createRecord('evil-minion', { id: "1", name: "Evil Minion", superVillian: superVillain }); superVillain.get('evilMinions').pushObject(evilMinion); @@ -2015,12 +1917,8 @@ test("Mixin can be used with RESTSerializer which does not define keyForAttribut evilMinions: { serialize: 'records', deserialize: 'records' } } })); - var serializer = env.store.serializerFor("super-villain"); - var json; - - run(function() { - json = serializer.serialize(superVillain._createSnapshot()); - }); + let serializer = env.store.serializerFor("super-villain"); + let json = serializer.serialize(superVillain._createSnapshot()); assert.deepEqual(json, { firstName: get(superVillain, "firstName"), @@ -2091,13 +1989,15 @@ test("normalize with custom belongsTo primary key", function(assert) { }); test("serializing relationships with an embedded and without calls super when not attr not present", function(assert) { + let homePlanet = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); + let secretLab = env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); + let superVillain = env.store.createRecord('super-villain', { + id: "1", firstName: "Super", lastName: "Villian", homePlanet: homePlanet, secretLab: secretLab + }); + let secretWeapon = env.store.createRecord('secret-weapon', { id: "1", name: "Secret Weapon", superVillain: superVillain }); + let evilMinion; + run(function() { - homePlanet = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); - secretLab = env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); - superVillain = env.store.createRecord('super-villain', { - id: "1", firstName: "Super", lastName: "Villian", homePlanet: homePlanet, secretLab: secretLab - }); - secretWeapon = env.store.createRecord('secret-weapon', { id: "1", name: "Secret Weapon", superVillain: superVillain }); superVillain.get('secretWeapons').pushObject(secretWeapon); evilMinion = env.store.createRecord('evil-minion', { id: "1", name: "Evil Minion", superVillian: superVillain }); superVillain.get('evilMinions').pushObject(evilMinion); @@ -2132,12 +2032,8 @@ test("serializing relationships with an embedded and without calls super when no // e.g. secretWeapons: { serialize: 'ids' } } })); - var serializer = env.store.serializerFor("super-villain"); - - var json; - run(function() { - json = serializer.serialize(superVillain._createSnapshot()); - }); + let serializer = env.store.serializerFor("super-villain"); + let json = serializer.serialize(superVillain._createSnapshot()); assert.deepEqual(json, { firstName: get(superVillain, "firstName"), @@ -2165,10 +2061,8 @@ test("serializing belongsTo correctly removes embedded foreign key", function(as superVillain: null }); - run(function() { - secretWeapon = env.store.createRecord('secret-weapon', { name: "Secret Weapon" }); - evilMinion = env.store.createRecord('evil-minion', { name: "Evil Minion", secretWeapon: secretWeapon }); - }); + let secretWeapon = env.store.createRecord('secret-weapon', { name: "Secret Weapon" }); + let evilMinion = env.store.createRecord('evil-minion', { name: "Evil Minion", secretWeapon: secretWeapon }); env.registry.register('serializer:evil-minion', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2176,12 +2070,8 @@ test("serializing belongsTo correctly removes embedded foreign key", function(as } })); - var serializer = env.store.serializerFor("evil-minion"); - var json; - - run(function() { - json = serializer.serialize(evilMinion._createSnapshot()); - }); + let serializer = env.store.serializerFor("evil-minion"); + let json = serializer.serialize(evilMinion._createSnapshot()); assert.deepEqual(json, { name: "Evil Minion", @@ -2193,10 +2083,8 @@ test("serializing belongsTo correctly removes embedded foreign key", function(as test("serializing embedded belongsTo respects remapped attrs key", function(assert) { - run(function() { - homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); - superVillain = env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); - }); + let homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); + let superVillain = env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2204,12 +2092,8 @@ test("serializing embedded belongsTo respects remapped attrs key", function(asse } })); - var serializer = env.store.serializerFor("super-villain"); - var json; - - run(function() { - json = serializer.serialize(superVillain._createSnapshot()); - }); + let serializer = env.store.serializerFor("super-villain"); + let json = serializer.serialize(superVillain._createSnapshot()); assert.deepEqual(json, { firstName: "Ice", @@ -2222,10 +2106,8 @@ test("serializing embedded belongsTo respects remapped attrs key", function(asse }); test("serializing embedded hasMany respects remapped attrs key", function(assert) { - run(function() { - homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); - superVillain = env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); - }); + let homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); + env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2240,13 +2122,8 @@ test("serializing embedded hasMany respects remapped attrs key", function(assert } })); - - var serializer = env.store.serializerFor("home-planet"); - var json; - - run(function() { - json = serializer.serialize(homePlanet._createSnapshot()); - }); + let serializer = env.store.serializerFor("home-planet"); + let json = serializer.serialize(homePlanet._createSnapshot()); assert.deepEqual(json, { name: "Hoth", @@ -2258,10 +2135,8 @@ test("serializing embedded hasMany respects remapped attrs key", function(assert }); test("serializing id belongsTo respects remapped attrs key", function(assert) { - run(function() { - homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); - superVillain = env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); - }); + let homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); + let superVillain = env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2269,12 +2144,8 @@ test("serializing id belongsTo respects remapped attrs key", function(assert) { } })); - var serializer = env.store.serializerFor("super-villain"); - var json; - - run(function() { - json = serializer.serialize(superVillain._createSnapshot()); - }); + let serializer = env.store.serializerFor("super-villain"); + let json = serializer.serialize(superVillain._createSnapshot()); assert.deepEqual(json, { firstName: "Ice", @@ -2285,10 +2156,8 @@ test("serializing id belongsTo respects remapped attrs key", function(assert) { }); test("serializing ids hasMany respects remapped attrs key", function(assert) { - run(function() { - homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); - superVillain = env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); - }); + let homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); + let superVillain = env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2303,13 +2172,8 @@ test("serializing ids hasMany respects remapped attrs key", function(assert) { } })); - - var serializer = env.store.serializerFor("home-planet"); - var json; - - run(function() { - json = serializer.serialize(homePlanet._createSnapshot()); - }); + let serializer = env.store.serializerFor("home-planet"); + let json = serializer.serialize(homePlanet._createSnapshot()); assert.deepEqual(json, { name: "Hoth", diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index abd221d541f..157aa85903b 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -314,13 +314,9 @@ test('Serializer should respect the attrs hash when serializing attributes with 'company-name': 'company_name' } })); - var project; - run(function() { - project = env.store.createRecord('project', { 'company-name': 'Tilde Inc.' }); - }); - - var payload = env.store.serializerFor('project').serialize(project._createSnapshot()); + let project = env.store.createRecord('project', { 'company-name': 'Tilde Inc.' }); + let payload = env.store.serializerFor('project').serialize(project._createSnapshot()); assert.equal(payload.data.attributes['company_name'], 'Tilde Inc.'); }); @@ -340,10 +336,7 @@ test('options are passed to transform for serialization', function(assert) { }) }); - var user; - run(function() { - user = env.store.createRecord('user', { myCustomField: 'value' }); - }); + let user = env.store.createRecord('user', { myCustomField: 'value' }); env.store.serializerFor('user').serialize(user._createSnapshot()); }); diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 9359670abe2..0080703e330 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -7,7 +7,7 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; -var Post, post, Comment, comment, Favorite, favorite, env, serializer; +var Post, Comment, Favorite, env, serializer; module("integration/serializer/json - JSONSerializer", { beforeEach() { @@ -39,9 +39,7 @@ module("integration/serializer/json - JSONSerializer", { }); test("serialize doesn't include ID when includeId is false", function(assert) { - run(() => { - post = env.store.createRecord('post', { title: 'Rails is omakase', comments: [] }); - }); + let post = env.store.createRecord('post', { title: 'Rails is omakase', comments: [] }); let json = serializer.serialize(post._createSnapshot(), { includeId: false }); assert.deepEqual(json, { @@ -52,10 +50,7 @@ test("serialize doesn't include ID when includeId is false", function(assert) { test("serialize doesn't include relationship if not aware of one", function(assert) { - run(() => { - post = env.store.createRecord('post', { title: 'Rails is omakase' }); - }); - + let post = env.store.createRecord('post', { title: 'Rails is omakase' }); let json = serializer.serialize(post._createSnapshot()); assert.deepEqual(json, { @@ -64,8 +59,9 @@ test("serialize doesn't include relationship if not aware of one", function(asse }); test("serialize includes id when includeId is true", function(assert) { + let post = env.store.createRecord('post', { title: 'Rails is omakase', comments: [] }); + run(() => { - post = env.store.createRecord('post', { title: 'Rails is omakase', comments: [] }); post.set('id', 'test'); }); @@ -79,10 +75,8 @@ test("serialize includes id when includeId is true", function(assert) { }); test("serializeAttribute", function(assert) { - run(function() { - post = env.store.createRecord('post', { title: "Rails is omakase" }); - }); - var json = {}; + let post = env.store.createRecord('post', { title: "Rails is omakase" }); + let json = {}; serializer.serializeAttribute(post._createSnapshot(), json, "title", { type: "string" }); @@ -98,10 +92,8 @@ test("serializeAttribute respects keyForAttribute", function(assert) { } })); - run(function() { - post = env.store.createRecord('post', { title: "Rails is omakase" }); - }); - var json = {}; + let post = env.store.createRecord('post', { title: "Rails is omakase" }); + let json = {}; env.store.serializerFor("post").serializeAttribute(post._createSnapshot(), json, "title", { type: "string" }); @@ -109,12 +101,9 @@ test("serializeAttribute respects keyForAttribute", function(assert) { }); test("serializeBelongsTo", function(assert) { - run(function() { - post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); - comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); - }); - - var json = {}; + let post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); + let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + let json = {}; serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); @@ -122,10 +111,8 @@ test("serializeBelongsTo", function(assert) { }); test("serializeBelongsTo with null", function(assert) { - run(function() { - comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: null }); - }); - var json = {}; + let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: null }); + let json = {}; serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); @@ -138,10 +125,8 @@ test("async serializeBelongsTo with null", function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: true }) }); - run(function() { - comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: null }); - }); - var json = {}; + let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: null }); + let json = {}; serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); @@ -156,11 +141,10 @@ test("serializeBelongsTo respects keyForRelationship", function(assert) { return key.toUpperCase(); } })); - run(function() { - post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); - comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); - }); - var json = {}; + + let post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); + let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + let json = {}; env.store.serializerFor("post").serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); @@ -176,17 +160,18 @@ test("serializeHasMany respects keyForRelationship", function(assert) { } })); + let post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); + let comment = env.store.createRecord('comment', { + body: "Omakase is delicious", + post: post, + id: "1" + }); + run(function() { - post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); - comment = env.store.createRecord('comment', { - body: "Omakase is delicious", - post: post, - id: "1" - }); post.get('comments').pushObject(comment); }); - var json = {}; + let json = {}; env.store.serializerFor("post").serializeHasMany(post._createSnapshot(), json, { key: "comments", options: {} }); @@ -196,20 +181,16 @@ test("serializeHasMany respects keyForRelationship", function(assert) { }); test("serializeHasMany omits unknown relationships on pushed record", function(assert) { - - run(function() { - post = env.store.push({ - data: { - id: "1", - type: "post", - attributes: { - title: "Rails is omakase" - } + let post = run(() => env.store.push({ + data: { + id: "1", + type: "post", + attributes: { + title: "Rails is omakase" } - }); - }); - - var json = {}; + } + })); + let json = {}; env.store.serializerFor("post").serializeHasMany(post._createSnapshot(), json, { key: "comments", options: {} }); @@ -217,11 +198,8 @@ test("serializeHasMany omits unknown relationships on pushed record", function(a }); test("shouldSerializeHasMany", function(assert) { - - run(function() { - post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); - comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post, id: "1" }); - }); + let post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); + env.store.createRecord('comment', { body: "Omakase is delicious", post: post, id: "1" }); var snapshot = post._createSnapshot(); var relationship = snapshot.record.relationshipFor('comments'); @@ -233,11 +211,9 @@ test("shouldSerializeHasMany", function(assert) { }); test("serializeIntoHash", function(assert) { - run(() => { - post = env.store.createRecord('post', { title: "Rails is omakase", comments: [] }); - }); - + let post = env.store.createRecord('post', { title: "Rails is omakase", comments: [] }); let json = {}; + serializer.serializeIntoHash(json, Post, post._createSnapshot()); assert.deepEqual(json, { @@ -259,10 +235,8 @@ test("serializePolymorphicType sync", function(assert) { } })); - run(function() { - post = env.store.createRecord('post', { title: 'Rails is omakase', id: 1 }); - comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); - }); + let post = env.store.createRecord('post', { title: 'Rails is omakase', id: 1 }); + let comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); env.store.serializerFor('comment').serializeBelongsTo(comment._createSnapshot(), {}, { key: 'post', options: { polymorphic: true } }); }); @@ -280,10 +254,8 @@ test("serializePolymorphicType async", function(assert) { } })); - run(function() { - post = env.store.createRecord('post', { title: 'Rails is omakase', id: 1 }); - comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); - }); + let post = env.store.createRecord('post', { title: 'Rails is omakase', id: 1 }); + let comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); env.store.serializerFor('comment').serializeBelongsTo(comment._createSnapshot(), {}, { key: 'post', options: { async: true, polymorphic: true } }); }); @@ -362,23 +334,18 @@ test('Serializer should respect the attrs hash when serializing records', functi parentPost: { key: "my_parent" } } })); - var parentPost; - run(function() { - env.store.push({ - data: { - type: 'post', - id: '2', - attributes: { - title: "Rails is omakase" - } + let parentPost = run(() => env.store.push({ + data: { + type: 'post', + id: '2', + attributes: { + title: "Rails is omakase" } - }); - parentPost = env.store.peekRecord('post', 2); - post = env.store.createRecord('post', { title: "Rails is omakase", parentPost: parentPost }); - }); - - var payload = env.store.serializerFor("post").serialize(post._createSnapshot()); + } + })); + let post = env.store.createRecord('post', { title: "Rails is omakase", parentPost: parentPost }); + let payload = env.store.serializerFor("post").serialize(post._createSnapshot()); assert.equal(payload.title_payload_key, "Rails is omakase"); assert.equal(payload.my_parent, '2'); @@ -470,11 +437,8 @@ test('Serializer respects `serialize: false` on the attrs hash', function(assert } })); - run(function() { - post = env.store.createRecord('post', { title: "Rails is omakase" }); - }); - - var payload = env.store.serializerFor("post").serialize(post._createSnapshot()); + let post = env.store.createRecord('post', { title: "Rails is omakase" }); + let payload = env.store.serializerFor("post").serialize(post._createSnapshot()); assert.ok(!payload.hasOwnProperty('title'), "Does not add the key to instance"); assert.ok(!payload.hasOwnProperty('[object Object]'), "Does not add some random key like [object Object]"); @@ -488,10 +452,8 @@ test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` p } })); - run(function() { - post = env.store.createRecord('post', { title: "Rails is omakase" }); - comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); - }); + let post = env.store.createRecord('post', { title: "Rails is omakase" }); + env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); var serializer = env.store.serializerFor("post"); var serializedProperty = serializer.keyForRelationship('comments', 'hasMany'); @@ -508,10 +470,8 @@ test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` } })); - run(function() { - post = env.store.createRecord('post', { title: "Rails is omakase" }); - comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); - }); + let post = env.store.createRecord('post', { title: "Rails is omakase" }); + let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); var serializer = env.store.serializerFor("comment"); var serializedProperty = serializer.keyForRelationship('post', 'belongsTo'); @@ -528,10 +488,8 @@ test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` p } })); - run(function() { - post = env.store.createRecord('post', { title: "Rails is omakase" }); - comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); - }); + let post = env.store.createRecord('post', { title: "Rails is omakase" }); + env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); var serializer = env.store.serializerFor("post"); var serializedProperty = serializer.keyForRelationship('comments', 'hasMany'); @@ -548,10 +506,8 @@ test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` } })); - run(function() { - post = env.store.createRecord('post', { title: "Rails is omakase" }); - comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); - }); + let post = env.store.createRecord('post', { title: "Rails is omakase" }); + let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); var serializer = env.store.serializerFor("comment"); var serializedProperty = serializer.keyForRelationship('post', 'belongsTo'); @@ -568,9 +524,10 @@ test('Serializer respects `serialize: true` on the attrs hash for a `hasMany` pr } })); + let post = env.store.createRecord('post', { title: "Rails is omakase" }); + let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + run(function() { - post = env.store.createRecord('post', { title: "Rails is omakase" }); - comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); post.get('comments').pushObject(comment); }); @@ -589,10 +546,8 @@ test('Serializer respects `serialize: true` on the attrs hash for a `belongsTo` } })); - run(function() { - post = env.store.createRecord('post', { title: "Rails is omakase" }); - comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); - }); + let post = env.store.createRecord('post', { title: "Rails is omakase" }); + let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); var serializer = env.store.serializerFor("comment"); var serializedProperty = serializer.keyForRelationship('post', 'belongsTo'); @@ -620,11 +575,8 @@ test("Serializer should merge attrs from superclasses", function(assert) { } })); - run(function() { - post = env.store.createRecord("post", { title: "Rails is omakase", description: "Omakase is delicious", anotherString: "yet another string" }); - }); - - var payload = env.store.serializerFor("post").serialize(post._createSnapshot()); + let post = env.store.createRecord("post", { title: "Rails is omakase", description: "Omakase is delicious", anotherString: "yet another string" }); + let payload = env.store.serializerFor("post").serialize(post._createSnapshot()); assert.equal(payload.title_payload_key, "Rails is omakase"); assert.equal(payload.description_payload_key, "Omakase is delicious"); @@ -637,11 +589,8 @@ test("Serializer should respect the primaryKey attribute when extracting records primaryKey: '_ID_' })); - var jsonHash = { "_ID_": 1, title: "Rails is omakase" }; - - run(function() { - post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); - }); + let jsonHash = { "_ID_": 1, title: "Rails is omakase" }; + let post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); assert.equal(post.data.id, "1"); assert.equal(post.data.attributes.title, "Rails is omakase"); @@ -652,11 +601,8 @@ test("Serializer should respect the primaryKey attribute when serializing record primaryKey: '_ID_' })); - run(function() { - post = env.store.createRecord('post', { id: "1", title: "Rails is omakase" }); - }); - - var payload = env.store.serializerFor("post").serialize(post._createSnapshot(), { includeId: true }); + let post = env.store.createRecord('post', { id: "1", title: "Rails is omakase" }); + let payload = env.store.serializerFor("post").serialize(post._createSnapshot(), { includeId: true }); assert.equal(payload._ID_, "1"); }); @@ -668,9 +614,8 @@ test("Serializer should respect keyForAttribute when extracting records", functi } })); - var jsonHash = { id: 1, TITLE: 'Rails is omakase' }; - - post = env.store.serializerFor("post").normalize(Post, jsonHash); + let jsonHash = { id: 1, TITLE: 'Rails is omakase' }; + let post = env.store.serializerFor("post").normalize(Post, jsonHash); assert.equal(post.data.id, "1"); assert.equal(post.data.attributes.title, "Rails is omakase"); @@ -683,9 +628,8 @@ test("Serializer should respect keyForRelationship when extracting records", fun } })); - var jsonHash = { id: 1, title: 'Rails is omakase', COMMENTS: ['1'] }; - - post = env.store.serializerFor("post").normalize(Post, jsonHash); + let jsonHash = { id: 1, title: 'Rails is omakase', COMMENTS: ['1'] }; + let post = env.store.serializerFor("post").normalize(Post, jsonHash); assert.deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }]); }); @@ -746,10 +690,8 @@ test('serializeBelongsTo with async polymorphic', function(assert) { } })); - run(function() { - post = env.store.createRecord('post', { title: 'Kitties are omakase', id: '1' }); - favorite = env.store.createRecord('favorite', { post: post, id: '3' }); - }); + let post = env.store.createRecord('post', { title: 'Kitties are omakase', id: '1' }); + let favorite = env.store.createRecord('favorite', { post: post, id: '3' }); env.store.serializerFor('favorite').serializeBelongsTo(favorite._createSnapshot(), json, { key: 'post', options: { polymorphic: true, async: true } }); @@ -957,10 +899,7 @@ test('options are passed to transform for serialization', function(assert) { }) }); - var post; - run(function() { - post = env.store.createRecord('post', { custom: 'value' }); - }); + let post = env.store.createRecord('post', { custom: 'value' }); serializer.serialize(post._createSnapshot()); }); diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 63c9e2d212f..60445918b58 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -4,10 +4,9 @@ import { run, bind } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; - import DS from 'ember-data'; -var HomePlanet, league, SuperVillain, EvilMinion, YellowMinion, DoomsdayDevice, Comment, Basket, Container, env; +let HomePlanet, SuperVillain, EvilMinion, YellowMinion, DoomsdayDevice, Comment, Basket, Container, env; module("integration/serializer/rest - RESTSerializer", { beforeEach() { @@ -271,13 +270,9 @@ testInDebug("normalizeResponse warning with custom modelNameFromPayloadKey", fun }); test("serialize polymorphicType", function(assert) { - var tom, ray; - run(function() { - tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); - ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: "DeathRay" }); - }); - - var json = env.restSerializer.serialize(ray._createSnapshot()); + let tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); + let ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: "DeathRay" }); + let json = env.restSerializer.serialize(ray._createSnapshot()); assert.deepEqual(json, { name: "DeathRay", @@ -287,24 +282,16 @@ test("serialize polymorphicType", function(assert) { }); test("serialize polymorphicType with decamelized modelName", function(assert) { - var tom, ray; - run(function() { - tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); - ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: "DeathRay" }); - }); - - var json = env.restSerializer.serialize(ray._createSnapshot()); + let tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); + let ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: "DeathRay" }); + let json = env.restSerializer.serialize(ray._createSnapshot()); assert.deepEqual(json["evilMinionType"], "yellowMinion"); }); test("serialize polymorphic when associated object is null", function(assert) { - var ray; - run(function() { - ray = env.store.createRecord('doomsday-device', { name: "DeathRay" }); - }); - - var json = env.restSerializer.serialize(ray._createSnapshot()); + let ray = env.store.createRecord('doomsday-device', { name: "DeathRay" }); + let json = env.restSerializer.serialize(ray._createSnapshot()); assert.deepEqual(json["evilMinionType"], null); }); @@ -415,10 +402,8 @@ test('normalize should allow for different levels of normalization - attributes' }); test("serializeIntoHash", function(assert) { - run(function() { - league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); - }); - var json = {}; + let league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); + let json = {}; env.restSerializer.serializeIntoHash(json, HomePlanet, league._createSnapshot()); @@ -430,10 +415,8 @@ test("serializeIntoHash", function(assert) { }); test("serializeIntoHash with decamelized modelName", function(assert) { - run(function() { - league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); - }); - var json = {}; + let league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); + let json = {}; env.restSerializer.serializeIntoHash(json, HomePlanet, league._createSnapshot()); @@ -445,14 +428,10 @@ test("serializeIntoHash with decamelized modelName", function(assert) { }); test('serializeBelongsTo with async polymorphic', function(assert) { - var evilMinion, doomsdayDevice; - var json = {}; - var expected = { evilMinion: '1', evilMinionType: 'evilMinion' }; - - run(function() { - evilMinion = env.store.createRecord('evil-minion', { id: 1, name: 'Tomster' }); - doomsdayDevice = env.store.createRecord('doomsday-device', { id: 2, name: 'Yehuda', evilMinion: evilMinion }); - }); + let json = {}; + let expected = { evilMinion: '1', evilMinionType: 'evilMinion' }; + let evilMinion = env.store.createRecord('evil-minion', { id: 1, name: 'Tomster' }); + let doomsdayDevice = env.store.createRecord('doomsday-device', { id: 2, name: 'Yehuda', evilMinion: evilMinion }); env.restSerializer.serializeBelongsTo(doomsdayDevice._createSnapshot(), json, { key: 'evilMinion', options: { polymorphic: true, async: true } }); @@ -460,18 +439,15 @@ test('serializeBelongsTo with async polymorphic', function(assert) { }); test('keyForPolymorphicType can be used to overwrite how the type of a polymorphic record is serialized', function(assert) { - var evilMinion, doomsdayDevice; - var json = {}; - var expected = { evilMinion: '1', typeForEvilMinion: 'evilMinion' }; + let json = {}; + let expected = { evilMinion: '1', typeForEvilMinion: 'evilMinion' }; env.restSerializer.keyForPolymorphicType = function() { return 'typeForEvilMinion'; }; - run(function() { - evilMinion = env.store.createRecord('evil-minion', { id: 1, name: 'Tomster' }); - doomsdayDevice = env.store.createRecord('doomsday-device', { id: 2, name: 'Yehuda', evilMinion: evilMinion }); - }); + let evilMinion = env.store.createRecord('evil-minion', { id: 1, name: 'Tomster' }); + let doomsdayDevice = env.store.createRecord('doomsday-device', { id: 2, name: 'Yehuda', evilMinion: evilMinion }); env.restSerializer.serializeBelongsTo(doomsdayDevice._createSnapshot(), json, { key: 'evilMinion', options: { polymorphic: true, async: true } }); @@ -514,10 +490,9 @@ test('keyForPolymorphicType can be used to overwrite how the type of a polymorph }); test('serializeIntoHash uses payloadKeyFromModelName to normalize the payload root key', function(assert) { - run(function() { - league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); - }); - var json = {}; + let league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); + let json = {}; + env.registry.register('serializer:home-planet', DS.RESTSerializer.extend({ payloadKeyFromModelName(modelName) { return dasherize(modelName); diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 621663375ad..4c787f80aad 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -1008,7 +1008,7 @@ test('The store should trap exceptions that are thrown from adapter#createRecord }; run(() => { - let car = store.createRecord('car') + let car = store.createRecord('car'); car.save().catch(error => { assert.equal(error.message, 'Refusing to serialize') diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 1bebf1b9a91..981005ea274 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -82,7 +82,7 @@ test('groupRecordsForFindMany works for encodeURIComponent-ified ids', function( }); test('_stripIDFromURL works with id being encoded - #4190', function(assert) { - let record = run(() => store.createRecord('testRecord', { id: "id:123" })); + let record = store.createRecord('testRecord', { id: "id:123" }); let adapter = store.adapterFor('testRecord'); let snapshot = record._internalModel.createSnapshot(); let strippedUrl = adapter._stripIDFromURL(store, snapshot); diff --git a/tests/unit/debug-test.js b/tests/unit/debug-test.js index 5925c8441cc..2625e2c6738 100644 --- a/tests/unit/debug-test.js +++ b/tests/unit/debug-test.js @@ -1,5 +1,4 @@ import { computed } from '@ember/object'; -import { run } from '@ember/runloop'; import { createStore } from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; @@ -33,7 +32,7 @@ test('_debugInfo groups the attributes and relationships correctly', function(as user: User }); - let record = run(() => store.createRecord('user')); + let record = store.createRecord('user'); let propertyInfo = record._debugInfo().propertyInfo; @@ -73,7 +72,7 @@ test('_debugInfo supports arbitray relationship types', function(assert) { user: User }); - let record = run(() => store.createRecord('user')); + let record = store.createRecord('user'); let propertyInfo = record._debugInfo().propertyInfo; diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 81103e18e6c..dc6cae9cd41 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -523,7 +523,7 @@ test("a DS.Model does not require an attribute type", function(assert) { tag: Tag }); - let tag = run(() => store.createRecord('tag', { name: "test" })); + let tag = store.createRecord('tag', { name: "test" }); assert.equal(get(tag, 'name'), 'test', 'the value is persisted'); }); @@ -537,7 +537,7 @@ test('a DS.Model can have a defaultValue without an attribute type', function(as tag: Tag }); - let tag = run(() => store.createRecord('tag')); + let tag = store.createRecord('tag'); assert.equal(get(tag, 'name'), 'unknown', 'the default value is found'); }); @@ -545,7 +545,7 @@ test('a DS.Model can have a defaultValue without an attribute type', function(as testInDebug('Calling attr() throws a warning', function(assert) { assert.expect(1); - let person = run(() => store.createRecord('person', { id: 1, name: 'TomHuda' })); + let person = store.createRecord('person', { id: 1, name: 'TomHuda' }); assert.throws(() => { person.attr(); @@ -742,7 +742,7 @@ test('a DS.Model can have a defaultValue', function(assert) { tag: Tag }); - let tag = run(() => store.createRecord('tag')); + let tag = store.createRecord('tag'); assert.equal(get(tag, 'name'), 'unknown', 'the default value is found'); @@ -789,10 +789,8 @@ test('a defaultValue for an attribute can be a function', function(assert) { tag: Tag }); - run(() => { - let tag = store.createRecord('tag'); - assert.equal(get(tag, 'createdAt'), 'le default value', 'the defaultValue function is evaluated'); - }); + let tag = store.createRecord('tag'); + assert.equal(get(tag, 'createdAt'), 'le default value', 'the defaultValue function is evaluated'); }); test('a defaultValue function gets the record, options, and key', function(assert) { @@ -812,7 +810,7 @@ test('a defaultValue function gets the record, options, and key', function(asser tag: Tag }); - let tag = run(() => store.createRecord('tag')); + let tag = store.createRecord('tag'); get(tag, 'createdAt'); }); @@ -826,7 +824,7 @@ testInDebug('a complex object defaultValue is deprecated', function(assert) { tag: Tag }); - let tag = run(() => store.createRecord('tag')); + let tag = store.createRecord('tag'); assert.expectAssertion(() => { get(tag, 'tagInfo'); @@ -854,7 +852,7 @@ test('setting a property to undefined on a newly created record should not impac assert.equal(get(tag, 'currentState.stateName'), 'root.loaded.created.uncommitted'); - tag = run(() => store.createRecord('tag', { name: undefined })); + tag = store.createRecord('tag', { name: undefined }); assert.equal(get(tag, 'currentState.stateName'), 'root.loaded.created.uncommitted'); }); @@ -932,7 +930,7 @@ test("a listener can be added to a record", function(assert) { let count = 0; let F = function() { count++; }; - let record = run(() => store.createRecord('person')); + let record = store.createRecord('person'); record.on('event!', F); run(() => record.trigger('event!')); @@ -947,7 +945,7 @@ test("a listener can be added to a record", function(assert) { test('when an event is triggered on a record the method with the same name is invoked with arguments', function(assert) { let count = 0; let F = function() { count++; }; - let record = run(() => store.createRecord('person')); + let record = store.createRecord('person'); record.eventNamedMethod = F; @@ -959,7 +957,7 @@ test('when an event is triggered on a record the method with the same name is in test('when a method is invoked from an event with the same name the arguments are passed through', function(assert) { let eventMethodArgs = null; let F = function() { eventMethodArgs = arguments; }; - let record = run(() => store.createRecord('person')); + let record = store.createRecord('person'); record.eventThatTriggersMethod = F; @@ -1147,7 +1145,7 @@ testInDebug(`don't allow setting`, function(assert) { person: Person }); - let record = run(() => store.createRecord('person')); + let record = store.createRecord('person'); assert.expectAssertion(() => { run(() => { @@ -1188,7 +1186,7 @@ test('A DS.Model can be JSONified', function(assert) { }); let store = createStore({ person: Person }); - let record = run(() => store.createRecord('person', { name: 'TomHuda' })); + let record = store.createRecord('person', { name: 'TomHuda' }); assert.deepEqual(record.toJSON(), { data: { type: 'people', attributes: { name: 'TomHuda' } } }); }); @@ -1202,9 +1200,7 @@ testInDebug('A subclass of DS.Model can not use the `data` property', function(a let store = createStore({ person: Person }); assert.expectAssertion(() => { - run(() => { - store.createRecord('person', { name: 'TomHuda' }); - }); + store.createRecord('person', { name: 'TomHuda' }); }, /`data` is a reserved property name on DS.Model objects/); }); @@ -1217,9 +1213,7 @@ testInDebug('A subclass of DS.Model can not use the `store` property', function( let store = createStore({ retailer: Retailer }); assert.expectAssertion(() => { - run(() => { - store.createRecord('retailer', { name: 'Buy n Large' }); - }); + store.createRecord('retailer', { name: 'Buy n Large' }); }, /`store` is a reserved property name on DS.Model objects/); }); @@ -1235,9 +1229,7 @@ testInDebug('A subclass of DS.Model can not use reserved properties', function(a let store = createStore({ post: Post }); assert.expectAssertion(() => { - run(() => { - store.createRecord('post', {}); - }); + store.createRecord('post', {}); }, /is a reserved property name on DS.Model objects/); }); }); @@ -1248,12 +1240,11 @@ test('Pushing a record into the store should transition it to the loaded state', }); let store = createStore({ person: Person }); + let person = store.createRecord('person', { id: 1, name: 'TomHuda' }); - run(() => { - let person = store.createRecord('person', { id: 1, name: 'TomHuda' }); - - assert.equal(person.get('isNew'), true, 'createRecord should put records into the new state'); + assert.equal(person.get('isNew'), true, 'createRecord should put records into the new state'); + run(() => { store.push({ data: { type: 'person', @@ -1332,7 +1323,7 @@ test('internalModel is ready by `init`', function(assert) { let { store } = setupStore({ person: Person }); assert.equal(nameDidChange, 0, 'observer should not trigger on create'); - let person = run(() => store.createRecord('person')); + let person = store.createRecord('person'); assert.equal(person.get('name'), 'my-name-set-in-init'); }); @@ -1352,7 +1343,7 @@ test('accessing attributes in the initializer should not throw an error', functi person: Person }); - run(() => store.createRecord('person')); + store.createRecord('person'); }); test('setting the id after model creation should correctly update the id', function(assert) { @@ -1366,11 +1357,11 @@ test('setting the id after model creation should correctly update the id', funct person: Person }); - run(() => { - let person = store.createRecord('person'); + let person = store.createRecord('person'); - assert.equal(person.get('id'), null, 'initial created model id should be null'); + assert.equal(person.get('id'), null, 'initial created model id should be null'); + run(() => { person.set('id', 'john'); assert.equal(person.get('id'), 'john', 'new id should be correctly set.'); diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index ccbee5e8dd8..c007aac027a 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -136,8 +136,7 @@ test('a record receives a didCreate callback when it has finished updating', fun }); assert.equal(callCount, 0, 'precond - didCreate callback was not called yet'); - let person = run(() => store.createRecord('person', { id: 69, name: 'Newt Gingrich' })); - + let person = store.createRecord('person', { id: 69, name: 'Newt Gingrich' }); return run(() => { return person.save().then(() => { @@ -216,7 +215,7 @@ test('an uncommited record also receives a didDelete callback when it is deleted person: Person }); - let person = run(() => store.createRecord('person', { name: 'Tomster' })); + let person = store.createRecord('person', { name: 'Tomster' }); assert.equal(callCount, 0, 'precond - didDelete callback was not called yet'); diff --git a/tests/unit/model/merge-test.js b/tests/unit/model/merge-test.js index bac3ef1f41e..680db2281bd 100644 --- a/tests/unit/model/merge-test.js +++ b/tests/unit/model/merge-test.js @@ -31,7 +31,7 @@ test('When a record is in flight, changes can be made', function(assert) { person: Person }); - let person = run(() => store.createRecord('person', { name: 'Tom Dale' })); + let person = store.createRecord('person', { name: 'Tom Dale' }); // Make sure saving isn't resolved synchronously return run(() => { diff --git a/tests/unit/model/relationships-test.js b/tests/unit/model/relationships-test.js index 3edee836733..0bee85d9a23 100644 --- a/tests/unit/model/relationships-test.js +++ b/tests/unit/model/relationships-test.js @@ -1,5 +1,4 @@ import { get } from '@ember/object'; -import { run } from '@ember/runloop'; import { createStore } from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; @@ -28,10 +27,8 @@ module('unit/model/relationships - DS.Model', { }); test('exposes a hash of the relationships on a model', function(assert) { - run(() => { - store.createRecord('person'); - store.createRecord('occupation'); - }); + store.createRecord('person'); + store.createRecord('occupation'); let relationships = get(Person, 'relationships'); assert.deepEqual(relationships.get('person'), [ diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index 496558e5ed6..9a6601b15f2 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -290,10 +290,10 @@ test('calling createRecord and passing in an undefined value for a relationship let { store } = env; env.adapter.shouldBackgroundReloadRecord = () => false; - run(() => store.createRecord('person', { id: 1, tag: undefined })); + store.createRecord('person', { id: '1', tag: undefined }); return run(() => { - return store.findRecord('person', 1).then(person => { + return store.findRecord('person', '1').then(person => { assert.strictEqual(person.get('tag'), null, 'undefined values should return null relationships'); }); }); @@ -585,10 +585,7 @@ test('DS.belongsTo should be async by default', function(assert) { let env = setupStore({ tag: Tag, person: Person }); let { store } = env; + let person = store.createRecord('person'); - run(() => { - let person = store.createRecord('person'); - - assert.ok(person.get('tag') instanceof DS.PromiseObject, 'tag should be an async relationship'); - }); + assert.ok(person.get('tag') instanceof DS.PromiseObject, 'tag should be an async relationship'); }); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index b856b18f73e..3cfb8a533ce 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -1865,16 +1865,13 @@ test('it is possible to add an item to a relationship, remove it, then add it ag let env = setupStore({ tag: Tag, person: Person }); let { store } = env; - let person, tag1, tag2, tag3, tags; + let person = store.createRecord('person'); + let tag1 = store.createRecord('tag'); + let tag2 = store.createRecord('tag'); + let tag3 = store.createRecord('tag'); + let tags = get(person, 'tags'); run(() => { - person = store.createRecord('person'); - tag1 = store.createRecord('tag'); - tag2 = store.createRecord('tag'); - tag3 = store.createRecord('tag'); - - tags = get(person, 'tags'); - tags.pushObjects([tag1, tag2, tag3]); tags.removeObject(tag2); }); @@ -1905,11 +1902,9 @@ test("DS.hasMany is async by default", function(assert) { }); let { store } = setupStore({ tag: Tag, person: Person }); + let tag = store.createRecord('tag'); - run(() => { - let tag = store.createRecord('tag'); - assert.ok(tag.get('people') instanceof DS.PromiseArray, 'people should be an async relationship'); - }); + assert.ok(tag.get('people') instanceof DS.PromiseArray, 'people should be an async relationship'); }); test('DS.hasMany is stable', function(assert) { @@ -1925,7 +1920,7 @@ test('DS.hasMany is stable', function(assert) { let { store } = setupStore({ tag: Tag, person: Person }); - let tag = run(() => store.createRecord('tag')); + let tag = store.createRecord('tag'); let people = tag.get('people'); let peopleCached = tag.get('people'); @@ -1954,7 +1949,7 @@ test('DS.hasMany proxy is destroyed', function(assert) { let { store } = setupStore({ tag: Tag, person: Person }); - let tag = run(() => store.createRecord('tag')); + let tag = store.createRecord('tag'); let peopleProxy = tag.get('people'); return peopleProxy.then(people => { @@ -1987,7 +1982,7 @@ test('DS.ManyArray is lazy', function(assert) { }); let env = setupStore({ tag: Tag, person: Person }); - let tag = run(() => env.store.createRecord('tag')); + let tag = env.store.createRecord('tag'); let hasManyRelationship = tag.hasMany('people').hasManyRelationship; assert.ok(!hasManyRelationship._manyArray); @@ -2001,7 +1996,7 @@ test('DS.ManyArray is lazy', function(assert) { assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (after access, but after the current run loop)'); assert.ok(hasManyRelationship._manyArray instanceof DS.ManyArray); - let person = run(() => env.store.createRecord('person')); + let person = env.store.createRecord('person'); run(() => { assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (before access)'); @@ -2017,12 +2012,8 @@ testInDebug('throws assertion if of not set with an array', function(assert) { }); let { store }= setupStore({ tag: Tag, person: Person }); - let tag, person; - - run(() => { - tag = store.createRecord('tag'); - person = store.createRecord('person'); - }); + let tag = store.createRecord('tag'); + let person = store.createRecord('person'); run(() => { assert.expectAssertion(() => { @@ -2048,12 +2039,8 @@ testInDebug('checks if passed array only contains instances of DS.Model', functi }; }; - let tag, person; - - run(() => { - tag = env.store.createRecord('tag'); - person = env.store.findRecord('person', 1); - }); + let tag = env.store.createRecord('tag'); + let person = run(() => env.store.findRecord('person', 1)); run(() => { assert.expectAssertion(() => { diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index 50c6e8f93d8..5d25c7e7f51 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -218,7 +218,7 @@ test(`a deleted record's attributes can be rollbacked if it fails to save, recor }); test(`new record's attributes can be rollbacked`, function(assert) { - let person = run(() => store.createRecord('person', { id: 1 })); + let person = store.createRecord('person', { id: 1 }); assert.equal(person.get('isNew'), true, 'must be new'); assert.equal(person.get('hasDirtyAttributes'), true, 'must be dirty'); @@ -248,7 +248,7 @@ test(`invalid new record's attributes can be rollbacked`, function(assert) { env = setupStore({ person: Person, adapter: adapter }); - let person = run(() => env.store.createRecord('person', { id: 1 })); + let person = env.store.createRecord('person', { id: 1 }); assert.equal(person.get('isNew'), true, 'must be new'); assert.equal(person.get('hasDirtyAttributes'), true, 'must be dirty'); diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index 6e64d831a2c..7f04382de6b 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -337,7 +337,7 @@ test('a new record of a particular type is created via store.createRecord(type)' person: Person }); - let person = run(() => store.createRecord('person')); + let person = store.createRecord('person'); assert.equal(get(person, 'isLoaded'), true, 'A newly created record is loaded'); assert.equal(get(person, 'isNew'), true, 'A newly created record is new'); @@ -363,12 +363,10 @@ testInDebug("a new record with a specific id can't be created if this id is alre person: Person }); - run(() => store.createRecord('person', { id: 5 })); + store.createRecord('person', { id: 5 }); assert.expectAssertion(() => { - run(() => { - store.createRecord('person', { id: 5 }); - }); + store.createRecord('person', { id: 5 }); }, /The id 5 has already been used with another record for modelClass 'person'/); }); @@ -381,7 +379,7 @@ test('an initial data hash can be provided via store.createRecord(type, hash)', person: Person }); - let person = run(() => store.createRecord('person', { name: 'Brohuda Katz' })); + let person = store.createRecord('person', { name: 'Brohuda Katz' }); assert.equal(get(person, 'isLoaded'), true, 'A newly created record is loaded'); assert.equal(get(person, 'isNew'), true, 'A newly created record is new'); @@ -650,12 +648,8 @@ test('records should have their ids updated when the adapter returns the id data }); let people = store.peekAll('person'); - let tom, yehuda; - - run(() => { - tom = store.createRecord('person', { name: 'Tom Dale' }); - yehuda = store.createRecord('person', { name: 'Yehuda Katz' }); - }); + let tom = store.createRecord('person', { name: 'Tom Dale' }); + let yehuda = store.createRecord('person', { name: 'Yehuda Katz' }); return run(() => { return all([ @@ -678,7 +672,7 @@ test('store.fetchMany should always return a promise', function(assert) { person: Person }); - run(() => store.createRecord('person')); + store.createRecord('person') let records = []; let results = run(() => store._scheduleFetchMany(records)); @@ -723,7 +717,7 @@ test('store._scheduleFetchMany should not resolve until all the records are reso phone: Phone }); - run(() => store.createRecord('test')); + store.createRecord('test'); let internalModels = [ store._internalModelForId('test', 10), diff --git a/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js index da135984994..1c87e24d29f 100644 --- a/tests/unit/store/create-record-test.js +++ b/tests/unit/store/create-record-test.js @@ -84,9 +84,7 @@ test(`doesn't modify passed in properties hash`, function(assert) { author }; - run(() => { - store.createRecord('post', properties); - }); + store.createRecord('post', properties); assert.deepEqual(properties, propertiesClone, 'The properties hash is not modified'); }); @@ -136,8 +134,7 @@ module('unit/store/createRecord - Store with models by dash', { test('creating a record by dasherize string finds the model', function(assert) { let attributes = { foo: 'bar' }; - - let record = run(() => store.createRecord('some-thing', attributes)); + let record = store.createRecord('some-thing', attributes); assert.equal(record.get('foo'), attributes.foo, 'The record is created'); assert.equal(store.modelFor('some-thing').modelName, 'some-thing'); diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index 98d88e3f3e0..ee7b1920333 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -102,7 +102,7 @@ test('unload a record', function(assert) { }); test('unload followed by create of the same type + id', function(assert) { - let record = run(() => store.createRecord('record', { id: 1 })); + let record = store.createRecord('record', { id: 1 }); assert.ok(store.recordForId('record', 1) === record, 'record should exactly equal'); From 9464ed0918069db68dc70bd9f86864ebb4671cd0 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 6 Apr 2018 07:13:47 -0700 Subject: [PATCH 2204/2527] [FEAT BUGFIX] resolves issues with links and data in relationships (#5410) * [FEAT BUGFIX] resolves issues with links and data in relationships * remove useless code * fix belongsTo reload for async relationships * fix merge forward of meta/links on inverses * fix test * fix much of merge-forward * not done yet, but getting there * aye! there's the rub * apparently testem thinks successful TODOs are test failures * misc cleanup * add code comments * add more comments and remove dead code * document _partialData --- addon/-private/system/model/internal-model.js | 6 +- addon/-private/system/promise-proxies.js | 26 +- addon/-private/system/references/has-many.js | 4 +- .../relationships/relationship-payloads.js | 107 +- .../system/relationships/state/belongs-to.js | 72 +- .../system/relationships/state/has-many.js | 56 +- .../relationships/state/relationship.js | 176 +- addon/-private/system/snapshot.js | 20 +- .../adapter/json-api-adapter-test.js | 2 +- .../integration/records/rematerialize-test.js | 59 +- .../relationships/belongs-to-test.js | 129 +- .../relationships/has-many-test.js | 301 ++- .../relationships/json-api-links-test.js | 1932 +++++++++++++++++ .../relationships/many-to-many-test.js | 7 +- .../relationships/nested-relationship-test.js | 64 +- .../relationships/one-to-many-test.js | 40 +- tests/integration/snapshot-test.js | 2 +- .../unit/model/relationships/has-many-test.js | 72 + .../relationship-payloads-test.js | 218 +- 19 files changed, 2998 insertions(+), 295 deletions(-) create mode 100644 tests/integration/relationships/json-api-links-test.js diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 42b01cbd255..d8f99b67a17 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -373,11 +373,13 @@ export default class InternalModel { break; case 'belongsTo': this.setDirtyBelongsTo(name, propertyValue); - relationships.get(name).setHasData(true); + relationships.get(name).setHasAnyRelationshipData(true); + relationships.get(name).setRelationshipIsEmpty(false); break; case 'hasMany': this.setDirtyHasMany(name, propertyValue); - relationships.get(name).setHasData(true); + relationships.get(name).setHasAnyRelationshipData(true); + relationships.get(name).setRelationshipIsEmpty(false); break; default: createOptions[name] = propertyValue; diff --git a/addon/-private/system/promise-proxies.js b/addon/-private/system/promise-proxies.js index f2a6bb814a8..a740d003c6b 100644 --- a/addon/-private/system/promise-proxies.js +++ b/addon/-private/system/promise-proxies.js @@ -1,7 +1,7 @@ import ObjectProxy from '@ember/object/proxy'; import PromiseProxyMixin from '@ember/object/promise-proxy-mixin'; import ArrayProxy from '@ember/array/proxy'; -import { get } from '@ember/object'; +import { get, computed } from '@ember/object'; import { reads } from '@ember/object/computed'; import { Promise } from 'rsvp'; import { assert } from '@ember/debug'; @@ -82,6 +82,28 @@ export function promiseArray(promise, label) { }); } +export const PromiseBelongsTo = PromiseObject.extend({ + + // we don't proxy meta because we would need to proxy it to the relationship state container + // however, meta on relationships does not trigger change notifications. + // if you need relationship meta, you should do `record.belongsTo(relationshipName).meta()` + meta: computed(function() { + assert( + 'You attempted to access meta on the promise for the async belongsTo relationship ' + + `${this.get('_belongsToState').internalModel.modelName}:${this.get('_belongsToState').key}'.` + + '\nUse `record.belongsTo(relationshipName).meta()` instead.', + false + ); + }), + + reload() { + assert('You are trying to reload an async belongsTo before it has been created', this.get('content') !== undefined); + this.get('_belongsToState').reload(); + + return this; + } +}); + /** A PromiseManyArray is a PromiseArray that also proxies certain method calls to the underlying manyArray. @@ -109,7 +131,7 @@ export function proxyToContent(method) { export const PromiseManyArray = PromiseArray.extend({ reload() { assert('You are trying to reload an async manyArray before it has been created', get(this, 'content')); - this.set('promise', this.get('content').reload()) + this.set('promise', this.get('content').reload()); return this; }, diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 9af516d6d48..5e88af85754 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -258,8 +258,8 @@ export default class HasManyReference extends Reference { } _isLoaded() { - let hasData = get(this.hasManyRelationship, 'hasData'); - if (!hasData) { + let hasRelationshipDataProperty = get(this.hasManyRelationship, 'hasAnyRelationshipData'); + if (!hasRelationshipDataProperty) { return false; } diff --git a/addon/-private/system/relationships/relationship-payloads.js b/addon/-private/system/relationships/relationship-payloads.js index 4233d461cbe..e82d5b7bcc5 100644 --- a/addon/-private/system/relationships/relationship-payloads.js +++ b/addon/-private/system/relationships/relationship-payloads.js @@ -1,5 +1,41 @@ import { assert } from '@ember/debug'; +/** + * Merge data,meta,links information forward to the next payload + * if required. Latest data will always win. + * + * @param oldPayload + * @param newPayload + */ +function mergeForwardPayload(oldPayload, newPayload) { + if (oldPayload && oldPayload.data !== undefined && newPayload.data === undefined) { + newPayload.data = oldPayload.data; + } + + /* + _partialData is has-many relationship data that has been discovered via + inverses in the absence of canonical `data` availability from the primary + payload. + + We can't merge this data into `data` as that would trick has-many relationships + into believing they know their complete membership. Anytime we find canonical + data from the primary record, this partial data is discarded. If no canonical + data is ever discovered, the partial data will be loaded by the relationship + in a way that correctly preserves the `stale` relationship state. + */ + if (newPayload.data === undefined && oldPayload && oldPayload._partialData !== undefined) { + newPayload._partialData = oldPayload._partialData; + } + + if (oldPayload && oldPayload.meta !== undefined && newPayload.meta === undefined) { + newPayload.meta = oldPayload.meta; + } + + if (oldPayload && oldPayload.links !== undefined && newPayload.links === undefined) { + newPayload.links = oldPayload.links; + } +} + // TODO this is now VERY similar to the identity/internal-model map // so we should probably generalize export class TypeCache { @@ -204,7 +240,6 @@ export default class RelationshipPayloads { let payloadMap; let inversePayloadMap; let inverseIsMany; - if (this._isLHS(modelName, relationshipName)) { previousPayload = this.lhs_payloads.get(modelName, id); payloadMap = this.lhs_payloads; @@ -257,14 +292,34 @@ export default class RelationshipPayloads { // * null is considered new information "empty", and it should win // * undefined is NOT considered new information, we should keep original state // * anything else is considered new information, and it should win + let isMatchingIdentifier = this._isMatchingIdentifier( + relationshipData && relationshipData.data, + previousPayload && previousPayload.data + ); + if (relationshipData.data !== undefined) { - this._removeInverse(id, previousPayload, inversePayloadMap); + if (!isMatchingIdentifier) { + this._removeInverse(id, previousPayload, inversePayloadMap); + } } + + mergeForwardPayload(previousPayload, relationshipData); payloadMap.set(modelName, id, relationshipData); - this._populateInverse(relationshipData, inverseRelationshipData, inversePayloadMap, inverseIsMany); + + if (!isMatchingIdentifier) { + this._populateInverse(relationshipData, inverseRelationshipData, inversePayloadMap, inverseIsMany); + } } } + _isMatchingIdentifier(a, b) { + return a && b && + a.type === b.type && + a.id === b.id && + !Array.isArray(a) && + !Array.isArray(b); + } + /** Populate the inverse relationship for `relationshipData`. @@ -306,22 +361,33 @@ export default class RelationshipPayloads { */ _addToInverse(inversePayload, resourceIdentifier, inversePayloadMap, inverseIsMany) { let relInfo = this._relInfo; + let inverseData = inversePayload.data; - if (relInfo.isReflexive && inversePayload.data.id === resourceIdentifier.id) { + if (relInfo.isReflexive && inverseData && inverseData.id === resourceIdentifier.id) { // eg .friends = [{ id: 1, type: 'user' }] return; } let existingPayload = inversePayloadMap.get(resourceIdentifier.type, resourceIdentifier.id); - let existingData = existingPayload && existingPayload.data; - if (existingData) { - // There already is an inverse, either add or overwrite depehnding on + if (existingPayload) { + // There already is an inverse, either add or overwrite depending on // whether the inverse is a many relationship or not // - if (Array.isArray(existingData)) { - existingData.push(inversePayload.data); + if (inverseIsMany) { + let existingData = existingPayload.data; + + // in the case of a hasMany + // we do not want create a `data` array where there was none before + // if we also have links, which this would indicate + if (existingData) { + existingData.push(inversePayload.data); + } else { + existingPayload._partialData = existingPayload._partialData || []; + existingPayload._partialData.push(inversePayload.data); + } } else { + mergeForwardPayload(existingPayload, inversePayload); inversePayloadMap.set(resourceIdentifier.type, resourceIdentifier.id, inversePayload); } } else { @@ -329,7 +395,7 @@ export default class RelationshipPayloads { // if (inverseIsMany) { inversePayloadMap.set(resourceIdentifier.type, resourceIdentifier.id, { - data: [inversePayload.data] + _partialData: [inversePayload.data] }); } else { inversePayloadMap.set(resourceIdentifier.type, resourceIdentifier.id, inversePayload); @@ -357,7 +423,10 @@ export default class RelationshipPayloads { */ _removeInverse(id, previousPayload, inversePayloadMap) { let data = previousPayload && previousPayload.data; - if (!data) { + let partialData = previousPayload && previousPayload._partialData; + let maybeData = data || partialData; + + if (!maybeData) { // either this is the first time we've seen a payload for this id, or its // previous payload indicated that it had no inverse, eg a belongsTo // relationship with payload { data: null } @@ -367,10 +436,10 @@ export default class RelationshipPayloads { return; } - if (Array.isArray(data)) { + if (Array.isArray(maybeData)) { // TODO: diff rather than removeall addall? - for (let i=0; i x.id !== id); + } else if (Array.isArray(partialData)) { + inversePayload._partialData = partialData.filter((x) => x.id !== id); } else { - inversePayloads.set(resourceIdentifier.type, resourceIdentifier.id, { - data: null - }); + // this merges forward links and meta + inversePayload.data = null; } } } diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index ea3bda37abe..a95c2692c6b 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -2,17 +2,16 @@ import { Promise as EmberPromise } from 'rsvp'; import { assert, inspect } from '@ember/debug'; import { assertPolymorphicType } from 'ember-data/-debug'; import { - PromiseObject + PromiseBelongsTo } from "../../promise-proxies"; import Relationship from "./relationship"; export default class BelongsToRelationship extends Relationship { constructor(store, internalModel, inverseKey, relationshipMeta) { super(store, internalModel, inverseKey, relationshipMeta); - this.internalModel = internalModel; - this.key = relationshipMeta.key; this.inverseInternalModel = null; this.canonicalState = null; + this._loadingPromise = null; } setInternalModel(internalModel) { @@ -21,8 +20,10 @@ export default class BelongsToRelationship extends Relationship { } else if (this.inverseInternalModel) { this.removeInternalModel(this.inverseInternalModel); } - this.setHasData(true); - this.setHasLoaded(true); + this.setHasAnyRelationshipData(true); + this.setRelationshipIsStale(false); + this.setRelationshipIsEmpty(false); + this.setHasRelatedResources(!this.localStateIsEmpty()); } setCanonicalInternalModel(internalModel) { @@ -165,20 +166,16 @@ export default class BelongsToRelationship extends Relationship { //TODO(Igor) flushCanonical here once our syncing is not stupid if (this.isAsync) { let promise; - if (this.link) { - if (this.hasLoaded) { - promise = this.findRecord(); - } else { - promise = this.findLink().then(() => this.findRecord()); - } + + if (this._shouldFindViaLink()) { + promise = this.findLink().then(() => this.findRecord()); } else { promise = this.findRecord(); } - return PromiseObject.create({ - promise: promise, - content: this.inverseInternalModel ? this.inverseInternalModel.getRecord() : null - }); + let record = this.inverseInternalModel ? this.inverseInternalModel.getRecord() : null + + return this._updateLoadingPromise(promise, record); } else { if (this.inverseInternalModel === null) { return null; @@ -189,19 +186,50 @@ export default class BelongsToRelationship extends Relationship { } } + _updateLoadingPromise(promise, content) { + if (this._loadingPromise) { + if (content) { + this._loadingPromise.set('content', content) + } + this._loadingPromise.set('promise', promise) + } else { + this._loadingPromise = PromiseBelongsTo.create({ + _belongsToState: this, + promise, + content + }); + } + + return this._loadingPromise; + } + reload() { - // TODO handle case when reload() is triggered multiple times + // we've already fired off a request + if (this._loadingPromise) { + if (this._loadingPromise.get('isPending')) { + return this._loadingPromise; + } + } + + let promise; + this.setRelationshipIsStale(true); if (this.link) { - return this.fetchLink(); + promise = this.fetchLink(); + } else if (this.inverseInternalModel && this.inverseInternalModel.hasRecord) { + // reload record, if it is already loaded + promise = this.inverseInternalModel.getRecord().reload(); + } else { + promise = this.findRecord(); } - // reload record, if it is already loaded - if (this.inverseInternalModel && this.inverseInternalModel.hasRecord) { - return this.inverseInternalModel.getRecord().reload(); - } + return this._updateLoadingPromise(promise); + } + + localStateIsEmpty() { + let internalModel = this.inverseInternalModel; - return this.findRecord(); + return !internalModel || internalModel.isEmpty(); } updateData(data, initial) { diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index edd6d60c8e8..6a73365e369 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -16,26 +16,25 @@ export default class ManyRelationship extends Relationship { // we create a new many array, but in the interim it will be updated if // inverse internal models are unloaded. this._retainedManyArray = null; - this.__loadingPromise = null; + this._loadingPromise = null; this._willUpdateManyArray = false; this._pendingManyArrayUpdates = null; } - get _loadingPromise() { return this.__loadingPromise; } _updateLoadingPromise(promise, content) { - if (this.__loadingPromise) { + if (this._loadingPromise) { if (content) { - this.__loadingPromise.set('content', content) + this._loadingPromise.set('content', content) } - this.__loadingPromise.set('promise', promise) + this._loadingPromise.set('promise', promise) } else { - this.__loadingPromise = PromiseManyArray.create({ + this._loadingPromise = PromiseManyArray.create({ promise, content }); } - return this.__loadingPromise; + return this._loadingPromise; } get manyArray() { @@ -246,17 +245,15 @@ export default class ManyRelationship extends Relationship { reload() { let manyArray = this.manyArray; - let manyArrayLoadedState = manyArray.get('isLoaded'); if (this._loadingPromise) { if (this._loadingPromise.get('isPending')) { return this._loadingPromise; } - if (this._loadingPromise.get('isRejected')) { - manyArray.set('isLoaded', manyArrayLoadedState); - } } + this.setRelationshipIsStale(true); + let promise; if (this.link) { promise = this.fetchLink(); @@ -315,7 +312,6 @@ export default class ManyRelationship extends Relationship { this.store._backburner.join(() => { this.updateInternalModelsFromAdapter(records); this.manyArray.set('isLoaded', true); - this.setHasData(true); }); return this.manyArray; }); @@ -342,26 +338,22 @@ export default class ManyRelationship extends Relationship { getRecords() { //TODO(Igor) sync server here, once our syncing is not stupid let manyArray = this.manyArray; + if (this.isAsync) { let promise; - if (this.link) { - if (this.hasLoaded) { - promise = this.findRecords(); - } else { - promise = this.findLink().then(() => this.findRecords()); - } + + if (this._shouldFindViaLink()) { + promise = this.findLink().then(() => this.findRecords()); } else { promise = this.findRecords(); } + return this._updateLoadingPromise(promise, manyArray); } else { assert(`You looked up the '${this.key}' relationship on a '${this.internalModel.type.modelName}' with id ${this.internalModel.id} but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async ('DS.hasMany({ async: true })')`, manyArray.isEvery('isEmpty', false)); - //TODO(Igor) WTF DO I DO HERE? - // TODO @runspired equal WTFs to Igor - if (!manyArray.get('isDestroyed')) { - manyArray.set('isLoaded', true); - } + manyArray.set('isLoaded', true); + return manyArray; } } @@ -375,6 +367,20 @@ export default class ManyRelationship extends Relationship { } } + localStateIsEmpty() { + let manyArray = this.manyArray; + let internalModels = manyArray.currentState; + let manyArrayIsLoaded = manyArray.get('isLoaded'); + + if (!manyArrayIsLoaded && internalModels.length) { + manyArrayIsLoaded = internalModels.reduce((hasNoEmptyModel, i) => { + return hasNoEmptyModel && !i.isEmpty(); + }, true); + } + + return !manyArrayIsLoaded; + } + destroy() { super.destroy(); let manyArray = this._manyArray; @@ -383,11 +389,11 @@ export default class ManyRelationship extends Relationship { this._manyArray = null; } - let proxy = this.__loadingPromise; + let proxy = this._loadingPromise; if (proxy) { proxy.destroy(); - this.__loadingPromise = null; + this._loadingPromise = null; } } } diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 2760a9ac822..4d2bef4c5a4 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -25,8 +25,6 @@ const { removeInternalModelFromInverse, removeInternalModelFromOwn, removeInternalModels, - setHasData, - setHasLoaded, updateLink, updateMeta, updateInternalModelsFromAdapter @@ -49,8 +47,6 @@ const { 'removeInternalModelFromInverse', 'removeInternalModelFromOwn', 'removeInternalModels', - 'setHasData', - 'setHasLoaded', 'updateLink', 'updateMeta', 'updateInternalModelsFromAdapter' @@ -75,19 +71,81 @@ export default class Relationship { this.inverseKeyForImplicit = this.internalModel.modelName + this.key; this.linkPromise = null; this.meta = null; - this.hasData = false; - this.hasLoaded = false; this.__inverseMeta = undefined; - } - _inverseIsAsync() { - let inverseMeta = this._inverseMeta; - if (!inverseMeta) { - return false; - } + /* + This flag indicates whether we should + re-fetch the relationship the next time + it is accessed. + + false when + => internalModel.isNew() on initial setup + => a previously triggered request has resolved + => we get relationship data via push + + true when + => !internalModel.isNew() on initial setup + => an inverse has been unloaded + => relationship.reload() has been called + => we get a new link for the relationship + */ + this.relationshipIsStale = !internalModel.isNew(); - let inverseAsync = inverseMeta.options.async; - return typeof inverseAsync === 'undefined' ? true : inverseAsync; + /* + This flag indicates whether we should consider the content + of this relationship "known". + + If we have no relationship knowledge, and the relationship + is `async`, we will attempt to fetch the relationship on + access if it is also stale. + + Snapshot uses this to tell the difference between unknown + (`undefined`) or empty (`null`). The reason for this is that + we wouldn't want to serialize unknown relationships as `null` + as that might overwrite remote state. + + All relationships for a newly created (`store.createRecord()`) are + considered known (`hasAnyRelationshipData === true`). + + true when + => we receive a push with either new data or explicit empty (`[]` or `null`) + => the relationship is a belongsTo and we have received data from + the other side. + + false when + => we have received no signal about what data belongs in this relationship + => the relationship is a hasMany and we have only received data from + the other side. + */ + this.hasAnyRelationshipData = false; + + /* + Flag that indicates whether an empty relationship is explicitly empty + (signaled by push giving us an empty array or null relationship) + e.g. an API response has told us that this relationship is empty. + + Thus far, it does not appear that we actually need this flag; however, + @runspired has found it invaluable when debugging relationship tests + to determine whether (and why if so) we are in an incorrect state. + + true when + => we receive a push with explicit empty (`[]` or `null`) + => we have received no signal about what data belongs in this relationship + => on initial create (as no signal is known yet) + + false at all other times + */ + this.relationshipIsEmpty = true; + + /* + true when + => hasAnyRelationshipData is true + AND + => members (NOT canonicalMembers) @each !isEmpty + + TODO, consider changing the conditional here from !isEmpty to !hiddenFromRecordArrays + */ + this.hasRelatedResources = false; } _inverseIsSync() { @@ -131,6 +189,8 @@ export default class Relationship { inverseDidDematerialize(inverseInternalModel) { this.linkPromise = null; + this.setRelationshipIsStale(true); + if (!this.isAsync) { // unloading inverse of a sync relationship is treated as a client-side // delete, so actually remove the models don't merely invalidate the cp @@ -204,7 +264,7 @@ export default class Relationship { this.setupInverseRelationship(internalModel); } this.flushCanonicalLater(); - this.setHasData(true); + this.setHasAnyRelationshipData(true); } setupInverseRelationship(internalModel) { @@ -277,7 +337,7 @@ export default class Relationship { } this.internalModel.updateRecordArrays(); } - this.setHasData(true); + this.setHasAnyRelationshipData(true); } removeInternalModel(internalModel) { @@ -423,19 +483,29 @@ export default class Relationship { updateLink(link, initial) { heimdall.increment(updateLink); - warn(`You pushed a record of type '${this.internalModel.modelName}' with a relationship '${this.key}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, this.isAsync || this.hasData , { + warn(`You pushed a record of type '${this.internalModel.modelName}' with a relationship '${this.key}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, this.isAsync || this.hasAnyRelationshipData , { id: 'ds.store.push-link-for-sync-relationship' }); assert(`You have pushed a record of type '${this.internalModel.modelName}' with '${this.key}' as a link, but the value of that link is not a string.`, typeof link === 'string' || link === null); this.link = link; this.linkPromise = null; + this.setRelationshipIsStale(true); if (!initial) { this.internalModel.notifyPropertyChange(this.key); } } + _shouldFindViaLink() { + if (!this.link) { + return false; + } + + return this.relationshipIsStale || + !this.hasRelatedResources; + } + findLink() { heimdall.increment(findLink); if (this.linkPromise) { @@ -449,7 +519,7 @@ export default class Relationship { updateInternalModelsFromAdapter(internalModels) { heimdall.increment(updateInternalModelsFromAdapter); - this.setHasData(true); + this.setHasAnyRelationshipData(true); //TODO(Igor) move this to a proper place //TODO Once we have adapter support, we need to handle updated and canonical changes this.computeChanges(internalModels); @@ -457,34 +527,20 @@ export default class Relationship { notifyRecordRelationshipAdded() { } - /* - `hasData` for a relationship is a flag to indicate if we consider the - content of this relationship "known". Snapshots uses this to tell the - difference between unknown (`undefined`) or empty (`null`). The reason for - this is that we wouldn't want to serialize unknown relationships as `null` - as that might overwrite remote state. - - All relationships for a newly created (`store.createRecord()`) are - considered known (`hasData === true`). - */ - setHasData(value) { - heimdall.increment(setHasData); - this.hasData = value; + setHasAnyRelationshipData(value) { + this.hasAnyRelationshipData = value; } - /* - `hasLoaded` is a flag to indicate if we have gotten data from the adapter or - not when the relationship has a link. + setHasRelatedResources(v) { + this.hasRelatedResources = v; + } - This is used to be able to tell when to fetch the link and when to return - the local data in scenarios where the local state is considered known - (`hasData === true`). + setRelationshipIsStale(value) { + this.relationshipIsStale = value; + } - Updating the link will automatically set `hasLoaded` to `false`. - */ - setHasLoaded(value) { - heimdall.increment(setHasLoaded); - this.hasLoaded = value; + setRelationshipIsEmpty(value) { + this.relationshipIsEmpty = value; } /* @@ -498,7 +554,7 @@ export default class Relationship { push(payload, initial) { heimdall.increment(push); - let hasData = false; + let hasRelationshipDataProperty = false; let hasLink = false; if (payload.meta) { @@ -506,8 +562,10 @@ export default class Relationship { } if (payload.data !== undefined) { - hasData = true; + hasRelationshipDataProperty = true; this.updateData(payload.data, initial); + } else if (payload._partialData !== undefined) { + this.updateData(payload._partialData, initial); } if (payload.links && payload.links.related) { @@ -522,19 +580,29 @@ export default class Relationship { Data being pushed into the relationship might contain only data or links, or a combination of both. - If we got data we want to set both hasData and hasLoaded to true since - this would indicate that we should prefer the local state instead of - trying to fetch the link or call findRecord(). + IF contains only data + IF contains both links and data + relationshipIsEmpty -> true if is empty array (has-many) or is null (belongs-to) + hasAnyRelationshipData -> true + relationshipIsStale -> false + hasRelatedResources -> run-check-to-determine - If we have no data but a link is present we want to set hasLoaded to false - without modifying the hasData flag. This will ensure we fetch the updated - link next time the relationship is accessed. + IF contains only links + relationshipIsStale -> true */ - if (hasData) { - this.setHasData(true); - this.setHasLoaded(true); + + if (hasRelationshipDataProperty) { + let relationshipIsEmpty = payload.data === null || + (Array.isArray(payload.data) && payload.data.length === 0); + + this.setHasAnyRelationshipData(true); + this.setRelationshipIsStale(false); + this.setRelationshipIsEmpty(relationshipIsEmpty); + this.setHasRelatedResources( + relationshipIsEmpty || !this.localStateIsEmpty() + ); } else if (hasLink) { - this.setHasLoaded(false); + this.setRelationshipIsStale(true); } } diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index adfc8cd1df1..e6b04c8b20f 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -198,7 +198,7 @@ export default class Snapshot { */ belongsTo(keyName, options) { let id = options && options.id; - let relationship, inverseInternalModel, hasData; + let relationship; let result; if (id && keyName in this._belongsToIds) { @@ -214,10 +214,12 @@ export default class Snapshot { throw new EmberError("Model '" + inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined."); } - hasData = get(relationship, 'hasData'); - inverseInternalModel = get(relationship, 'inverseInternalModel'); + let { + hasAnyRelationshipData, + inverseInternalModel + } = relationship; - if (hasData) { + if (hasAnyRelationshipData) { if (inverseInternalModel && !inverseInternalModel.isDeleted()) { if (id) { result = get(inverseInternalModel, 'id'); @@ -269,7 +271,7 @@ export default class Snapshot { */ hasMany(keyName, options) { let ids = options && options.ids; - let relationship, members, hasData; + let relationship; let results; if (ids && keyName in this._hasManyIds) { @@ -285,10 +287,12 @@ export default class Snapshot { throw new EmberError("Model '" + inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined."); } - hasData = get(relationship, 'hasData'); - members = get(relationship, 'members'); + let { + hasAnyRelationshipData, + members + } = relationship; - if (hasData) { + if (hasAnyRelationshipData) { results = []; members.forEach((member) => { if (!member.isDeleted()) { diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index 6443d7d4910..c945eeb51cf 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -59,7 +59,7 @@ module('integration/adapter/json-api-adapter - JSONAPIAdapter', { }); env = setupStore({ - adapter: DS.JSONAPIAdapter, + adapter: DS.JSONAPIAdapter.extend(), 'user': User, 'post': Post, diff --git a/tests/integration/records/rematerialize-test.js b/tests/integration/records/rematerialize-test.js index 416e299f24c..76dfdaba91c 100644 --- a/tests/integration/records/rematerialize-test.js +++ b/tests/integration/records/rematerialize-test.js @@ -1,38 +1,36 @@ /*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(adam|bob|dudu)" }]*/ import { run } from '@ember/runloop'; - +import Ember from 'ember'; import setupStore from 'dummy/tests/helpers/store'; - import { module, test } from 'qunit'; - import DS from 'ember-data'; -let attr = DS.attr; -let belongsTo = DS.belongsTo; -let hasMany = DS.hasMany; +const { copy } = Ember; +const { attr, belongsTo, hasMany, Model } = DS; + let env; -let Person = DS.Model.extend({ +let Person = Model.extend({ name: attr('string'), cars: hasMany('car', { async: false }), boats: hasMany('boat', { async: true }) }); Person.reopenClass({ toString() { return 'Person'; } }); -let Group = DS.Model.extend({ +let Group = Model.extend({ people: hasMany('person', { async: false }) }); Group.reopenClass({ toString() { return 'Group'; } }); -let Car = DS.Model.extend({ +let Car = Model.extend({ make: attr('string'), model: attr('string'), person: belongsTo('person', { async: false }) }); Car.reopenClass({ toString() { return 'Car'; } }); -let Boat = DS.Model.extend({ +let Boat = Model.extend({ name: attr('string'), person: belongsTo('person', { async: false }) }); @@ -139,7 +137,7 @@ test("a sync belongs to relationship to an unloaded record can restore that reco }); test("an async has many relationship to an unloaded record can restore that record", function(assert) { - assert.expect(15); + assert.expect(16); // disable background reloading so we do not re-create the relationship. env.adapter.shouldBackgroundReloadRecord = () => false; @@ -175,9 +173,9 @@ test("an async has many relationship to an unloaded record can restore that reco let data; if (param === '1') { - data = BOAT_ONE; + data = copy(BOAT_ONE, true); } else if (param === '1') { - data = BOAT_TWO; + data = copy(BOAT_TWO, true); } else { throw new Error(`404: no such boat with id=${param}`); } @@ -185,7 +183,7 @@ test("an async has many relationship to an unloaded record can restore that reco return { data }; - } + }; run(() => { env.store.push({ @@ -209,17 +207,20 @@ test("an async has many relationship to an unloaded record can restore that reco run(() => { env.store.push({ - data: [BOAT_ONE, BOAT_TWO] + data: [ + copy(BOAT_ONE, true), + copy(BOAT_TWO, true) + ] }); }); - let adam = env.store.peekRecord('person', 1); - let boaty = env.store.peekRecord('boat', 1); + let adam = env.store.peekRecord('person', '1'); + let boaty = env.store.peekRecord('boat', '1'); - assert.equal(env.store.hasRecordForId('person', 1), true, 'The person is in the store'); - assert.equal(env.store._internalModelsFor('person').has(1), true, 'The person internalModel is loaded'); - assert.equal(env.store.hasRecordForId('boat', 1), true, 'The boat is in the store'); - assert.equal(env.store._internalModelsFor('boat').has(1), true, 'The boat internalModel is loaded'); + assert.equal(env.store.hasRecordForId('person', '1'), true, 'The person is in the store'); + assert.equal(env.store._internalModelsFor('person').has('1'), true, 'The person internalModel is loaded'); + assert.equal(env.store.hasRecordForId('boat', '1'), true, 'The boat is in the store'); + assert.equal(env.store._internalModelsFor('boat').has('1'), true, 'The boat internalModel is loaded'); let boats = run(() => adam.get('boats')); @@ -228,16 +229,18 @@ test("an async has many relationship to an unloaded record can restore that reco run(() => boaty.unloadRecord()); assert.equal(boats.get('length'), 1, 'after unloading boats.length is correct'); - assert.equal(env.store.hasRecordForId('boat', 1), false, 'The boat is unloaded'); - assert.equal(env.store._internalModelsFor('boat').has(1), true, 'The boat internalModel is retained'); + assert.equal(env.store.hasRecordForId('boat', '1'), false, 'The boat is unloaded'); + assert.equal(env.store._internalModelsFor('boat').has('1'), true, 'The boat internalModel is retained'); - let rematerializedBoaty = run(() => adam.get('boats')).objectAt(0); + boats = run(() => adam.get('boats')); + let rematerializedBoaty = boats.objectAt(1); + assert.ok(!!rematerializedBoaty, 'We have a boat!'); assert.equal(adam.get('boats.length'), 2, 'boats.length correct after rematerialization'); - assert.equal(rematerializedBoaty.get('id'), '1'); - assert.equal(rematerializedBoaty.get('name'), 'Boaty McBoatface'); + assert.equal(rematerializedBoaty.get('id'), '1', 'Rematerialized boat has the right id'); + assert.equal(rematerializedBoaty.get('name'), 'Boaty McBoatface', 'Rematerialized boat has the right name'); assert.notEqual(rematerializedBoaty, boaty, 'the boat is rematerialized, not recycled'); - assert.equal(env.store.hasRecordForId('boat', 1), true, 'The boat is loaded'); - assert.equal(env.store._internalModelsFor('boat').has(1), true, 'The boat internalModel is retained'); + assert.equal(env.store.hasRecordForId('boat', '1'), true, 'The boat is loaded'); + assert.equal(env.store._internalModelsFor('boat').has('1'), true, 'The boat internalModel is retained'); }); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 6b954f18463..60e58df49d1 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -43,12 +43,12 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { Book = DS.Model.extend({ name: attr('string'), author: belongsTo('author', { async: false }), - chapters: hasMany('chapters', { async: false }) + chapters: hasMany('chapters', { async: false, inverse: 'book' }) }); Chapter = DS.Model.extend({ title: attr('string'), - book: belongsTo('book', { async: false }) + book: belongsTo('book', { async: false, inverse: 'chapters' }) }); Author = DS.Model.extend({ @@ -804,7 +804,7 @@ testInDebug("Passing a model as type to belongsTo should not work", function(ass }, /The first argument to DS.belongsTo must be a string/); }); -test("belongsTo hasData async loaded", function(assert) { +test("belongsTo hasAnyRelationshipData async loaded", function(assert) { assert.expect(1); Book.reopen({ @@ -827,12 +827,12 @@ test("belongsTo hasData async loaded", function(assert) { return run(() => { return store.findRecord('book', 1).then(book => { let relationship = book._internalModel._relationships.get('author'); - assert.equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); }); }); -test("belongsTo hasData sync loaded", function(assert) { +test("belongsTo hasAnyRelationshipData sync loaded", function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -851,12 +851,12 @@ test("belongsTo hasData sync loaded", function(assert) { return run(() => { return store.findRecord('book', 1).then(book => { let relationship = book._internalModel._relationships.get('author'); - assert.equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); }); }); -test("belongsTo hasData async not loaded", function(assert) { +test("belongsTo hasAnyRelationshipData async not loaded", function(assert) { assert.expect(1); Book.reopen({ @@ -879,12 +879,12 @@ test("belongsTo hasData async not loaded", function(assert) { return run(() => { return store.findRecord('book', 1).then(book => { let relationship = book._internalModel._relationships.get('author'); - assert.equal(relationship.hasData, false, 'relationship does not have data'); + assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); }); }); }); -test("belongsTo hasData sync not loaded", function(assert) { +test("belongsTo hasAnyRelationshipData sync not loaded", function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -900,12 +900,12 @@ test("belongsTo hasData sync not loaded", function(assert) { return run(() => { return store.findRecord('book', 1).then(book => { let relationship = book._internalModel._relationships.get('author'); - assert.equal(relationship.hasData, false, 'relationship does not have data'); + assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); }); }); }); -test("belongsTo hasData NOT created", function(assert) { +test("belongsTo hasAnyRelationshipData NOT created", function(assert) { assert.expect(2); Book.reopen({ @@ -917,7 +917,7 @@ test("belongsTo hasData NOT created", function(assert) { let book = store.createRecord('book', { name: 'The Greatest Book' }); let relationship = book._internalModel._relationships.get('author'); - assert.equal(relationship.hasData, false, 'relationship does not have data'); + assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); book = store.createRecord('book', { name: 'The Greatest Book', @@ -926,11 +926,11 @@ test("belongsTo hasData NOT created", function(assert) { relationship = book._internalModel._relationships.get('author'); - assert.equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); }); -test("belongsTo hasData sync created", function(assert) { +test("belongsTo hasAnyRelationshipData sync created", function(assert) { assert.expect(2); run(() => { @@ -940,7 +940,7 @@ test("belongsTo hasData sync created", function(assert) { }); let relationship = book._internalModel._relationships.get('author'); - assert.equal(relationship.hasData, false, 'relationship does not have data'); + assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); book = store.createRecord('book', { name: 'The Greatest Book', @@ -948,7 +948,7 @@ test("belongsTo hasData sync created", function(assert) { }); relationship = book._internalModel._relationships.get('author'); - assert.equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); }); @@ -998,7 +998,7 @@ test("Model's belongsTo relationship should be created during 'get' method", fun }); }); -test("Related link should be fetched when no local data is present", function(assert) { +test("Related link should be fetched when no relationship data is present", function(assert) { assert.expect(3); Book.reopen({ @@ -1010,7 +1010,7 @@ test("Related link should be fetched when no local data is present", function(as assert.ok(true, "The adapter's findBelongsTo method should be called"); return resolve({ data: { - id: 1, + id: '1', type: 'author', attributes: { name: 'This is author' } } @@ -1038,18 +1038,15 @@ test("Related link should be fetched when no local data is present", function(as }); }); -test("Local data should take precedence over related link", function(assert) { - assert.expect(1); +test("Related link should take precedence over relationship data if no local record data is available", function(assert) { + assert.expect(2); Book.reopen({ author: DS.belongsTo('author', { async: true }) }); env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { - assert.ok(false, "The adapter's findBelongsTo method should not be called"); - }; - - env.adapter.findRecord = function(store, type, id, snapshot) { + assert.ok(true, "The adapter's findBelongsTo method should be called"); return resolve({ data: { id: 1, @@ -1059,6 +1056,10 @@ test("Local data should take precedence over related link", function(assert) { }); }; + env.adapter.findRecord = function() { + assert.ok(false, "The adapter's findRecord method should not be called"); + }; + return run(() => { let book = env.store.push({ data: { @@ -1081,6 +1082,51 @@ test("Local data should take precedence over related link", function(assert) { }); }); +test("Relationship data should take precedence over related link when local record data is available", function(assert) { + assert.expect(1); + + Book.reopen({ + author: DS.belongsTo('author', { async: true }) + }); + + env.adapter.shouldBackgroundReloadRecord = () => { return false; }; + env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { + assert.ok(false, "The adapter's findBelongsTo method should not be called"); + }; + + env.adapter.findRecord = function(store, type, id, snapshot) { + assert.ok(false, "The adapter's findRecord method should not be called"); + }; + + return run(() => { + let book = env.store.push({ + data: { + type: 'book', + id: '1', + relationships: { + author: { + links: { + related: 'author' + }, + data: { type: 'author', id: '1' } + } + } + }, + included: [ + { + id: '1', + type: 'author', + attributes: { name: 'This is author' } + } + ] + }); + + return book.get('author').then(author => { + assert.equal(author.get('name'), 'This is author', 'author name is correct'); + }); + }); +}); + test("New related link should take precedence over local data", function(assert) { assert.expect(3); @@ -1140,7 +1186,7 @@ test("New related link should take precedence over local data", function(assert) }); }); -test("Updated related link should take precedence over local data", function(assert) { +test("Updated related link should take precedence over relationship data and local record data", function(assert) { assert.expect(4); Book.reopen({ @@ -1152,9 +1198,11 @@ test("Updated related link should take precedence over local data", function(ass assert.ok(true, "The adapter's findBelongsTo method should be called"); return resolve({ data: { - id: 1, + id: '1', type: 'author', - attributes: { name: 'This is updated author' } + attributes: { + name: 'This is updated author' + } } }); }; @@ -1177,18 +1225,21 @@ test("Updated related link should take precedence over local data", function(ass } } }, - included: [{ - type: 'author', - id: '1', - attributes: { - name: 'This is author' + included: [ + { + type: 'author', + id: '1', + attributes: { + name: 'This is author' + } } - }] + ] }); return book.get('author').then((author) => { assert.equal(author.get('name'), 'This is author', 'author name is correct'); }).then(() => { + env.store.push({ data: { type: 'book', @@ -1329,9 +1380,9 @@ test("A belongsTo relationship can be reloaded using the reference if it was fet }); }); -test("A sync belongsTo relationship can be reloaded using a reference if it was fetched via id", function(assert) { +test("A synchronous belongsTo relationship can be reloaded using a reference if it was fetched via id", function(assert) { Chapter.reopen({ - book: DS.belongsTo() + book: DS.belongsTo({ async: false }) }); let chapter; @@ -1339,10 +1390,10 @@ test("A sync belongsTo relationship can be reloaded using a reference if it was chapter = env.store.push({ data: { type: 'chapter', - id: 1, + id: '1', relationships: { book: { - data: { type: 'book', id: 1 } + data: { type: 'book', id: '1' } } } } @@ -1350,7 +1401,7 @@ test("A sync belongsTo relationship can be reloaded using a reference if it was env.store.push({ data: { type: 'book', - id: 1, + id: '1', attributes: { name: "book title" } @@ -1361,7 +1412,7 @@ test("A sync belongsTo relationship can be reloaded using a reference if it was env.adapter.findRecord = function() { return resolve({ data: { - id: 1, + id: '1', type: 'book', attributes: { name: 'updated book title' } } diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index fe63d8490f5..f73db1f5c7d 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -2648,7 +2648,7 @@ test("adding and removing records from hasMany relationship #2666", function(ass }); }); -test("hasMany hasData async loaded", function(assert) { +test("hasMany hasAnyRelationshipData async loaded", function(assert) { assert.expect(1); Chapter.reopen({ @@ -2673,12 +2673,12 @@ test("hasMany hasData async loaded", function(assert) { return run(() => { return store.findRecord('chapter', 1).then(chapter => { let relationship = chapter._internalModel._relationships.get('pages'); - assert.equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); }); }); -test("hasMany hasData sync loaded", function(assert) { +test("hasMany hasAnyRelationshipData sync loaded", function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -2699,12 +2699,12 @@ test("hasMany hasData sync loaded", function(assert) { return run(() => { return store.findRecord('chapter', 1).then(chapter => { let relationship = chapter._internalModel._relationships.get('pages'); - assert.equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); }); }); -test("hasMany hasData async not loaded", function(assert) { +test("hasMany hasAnyRelationshipData async not loaded", function(assert) { assert.expect(1); Chapter.reopen({ @@ -2729,12 +2729,12 @@ test("hasMany hasData async not loaded", function(assert) { return run(() => { return store.findRecord('chapter', 1).then(chapter => { let relationship = chapter._internalModel._relationships.get('pages'); - assert.equal(relationship.hasData, false, 'relationship does not have data'); + assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); }); }); }); -test("hasMany hasData sync not loaded", function(assert) { +test("hasMany hasAnyRelationshipData sync not loaded", function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -2750,12 +2750,12 @@ test("hasMany hasData sync not loaded", function(assert) { return run(() => { return store.findRecord('chapter', 1).then(chapter => { let relationship = chapter._internalModel._relationships.get('pages'); - assert.equal(relationship.hasData, false, 'relationship does not have data'); + assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); }); }); }); -test("hasMany hasData async created", function(assert) { +test("hasMany hasAnyRelationshipData async created", function(assert) { assert.expect(2); Chapter.reopen({ @@ -2766,7 +2766,7 @@ test("hasMany hasData async created", function(assert) { let page = store.createRecord('page'); let relationship = chapter._internalModel._relationships.get('pages'); - assert.equal(relationship.hasData, false, 'relationship does not have data'); + assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); chapter = store.createRecord('chapter', { title: 'The Story Begins', @@ -2774,16 +2774,16 @@ test("hasMany hasData async created", function(assert) { }); relationship = chapter._internalModel._relationships.get('pages'); - assert.equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); -test("hasMany hasData sync created", function(assert) { +test("hasMany hasAnyRelationshipData sync created", function(assert) { assert.expect(2); let chapter = store.createRecord('chapter', { title: 'The Story Begins' }); let relationship = chapter._internalModel._relationships.get('pages'); - assert.equal(relationship.hasData, false, 'relationship does not have data'); + assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); chapter = store.createRecord('chapter', { title: 'The Story Begins', @@ -2791,7 +2791,7 @@ test("hasMany hasData sync created", function(assert) { }); relationship = chapter._internalModel._relationships.get('pages'); - assert.equal(relationship.hasData, true, 'relationship has data'); + assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); test("Model's hasMany relationship should not be created during model creation", function(assert) { @@ -2973,19 +2973,37 @@ test("metadata should be reset between requests", function(assert) { }); }); -test("Related link should be fetched when no local data is present", function(assert) { +test("Related link should be fetched when no relationship data is present", function(assert) { assert.expect(3); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true, inverse: 'post' }) + }); + Comment.reopen({ + post: DS.belongsTo('post', { async: false, inverse: 'comments' }) }); + env.adapter.shouldBackgroundReloadRecord = () => { return false; }; + env.adapter.findRecord = () => { + assert.ok(false, "The adapter's findRecord method should not be called"); + }; + env.adapter.findMany = () => { + assert.ok(false, "The adapter's findMany method should not be called"); + }; env.adapter.findHasMany = function(store, snapshot, url, relationship) { - assert.equal(url, 'comments', 'url is correct'); + assert.equal(url, 'get-comments', 'url is correct'); assert.ok(true, "The adapter's findHasMany method should be called"); - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: 'This is comment' } } - ]}); + return resolve({ + data: [ + { + id: '1', + type: 'comment', + attributes: { + body: 'This is comment' + } + } + ] + }); }; return run(() => { @@ -2996,7 +3014,7 @@ test("Related link should be fetched when no local data is present", function(as relationships: { comments: { links: { - related: 'comments' + related: 'get-comments' } } } @@ -3009,19 +3027,82 @@ test("Related link should be fetched when no local data is present", function(as }); }); -test("Local data should take precedence over related link", function(assert) { - assert.expect(1); +test("Related link should take precedence over relationship data when local record data is missing", function(assert) { + assert.expect(3); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true, inverse: 'post' }) }); + Comment.reopen({ + post: DS.belongsTo('post', { async: false, inverse: 'comments' }) + }); + env.adapter.shouldBackgroundReloadRecord = () => { return false; }; + env.adapter.findRecord = () => { + assert.ok(false, "The adapter's findRecord method should not be called"); + }; + env.adapter.findMany = () => { + assert.ok(false, "The adapter's findMany method should not be called"); + }; env.adapter.findHasMany = function(store, snapshot, url, relationship) { - assert.ok(false, "The adapter's findHasMany method should not be called"); + assert.equal(url, 'get-comments', 'url is correct'); + assert.ok(true, "The adapter's findHasMany method should be called"); + return resolve({ + data: [ + { + id: '1', + type: 'comment', + attributes: { + body: 'This is comment' + } + } + ] + }); }; - env.adapter.findRecord = function(store, type, id, snapshot) { - return resolve({ data: { id: 1, type: 'comment', attributes: { body: 'This is comment' } } }); + return run(() => { + let post = env.store.push({ + data: { + type: 'post', + id: '1', + relationships: { + comments: { + links: { + related: 'get-comments' + }, + data: [ + { type: 'comment', id: '1' } + ] + } + } + } + }); + + return post.get('comments').then(comments => { + assert.equal(comments.get('firstObject.body'), 'This is comment', 'comment body is correct'); + }); + }); +}); + +test("Local relationship data should take precedence over related link when local record data is available", function(assert) { + assert.expect(1); + + Post.reopen({ + comments: DS.hasMany('comment', { async: true, inverse: 'post' }) + }); + Comment.reopen({ + post: DS.belongsTo('post', { async: false, inverse: 'comments' }) + }); + env.adapter.shouldBackgroundReloadRecord = () => { return false; }; + env.adapter.findRecord = () => { + assert.ok(false, "The adapter's findRecord method should not be called"); + }; + env.adapter.findMany = () => { + assert.ok(false, "The adapter's findMany method should not be called"); + }; + + env.adapter.findHasMany = function(store, snapshot, url, relationship) { + assert.ok(false, "The adapter's findHasMany method should not be called"); }; return run(() => { @@ -3032,14 +3113,23 @@ test("Local data should take precedence over related link", function(assert) { relationships: { comments: { links: { - related: 'comments' + related: 'get-comments' }, data: [ { type: 'comment', id: '1' } ] } } - } + }, + included: [ + { + id: '1', + type: 'comment', + attributes: { + body: 'This is comment' + } + } + ] }); return post.get('comments').then(comments => { @@ -3048,7 +3138,78 @@ test("Local data should take precedence over related link", function(assert) { }); }); -test("Updated related link should take precedence over local data", function(assert) { +test("Related link should take precedence over local record data when relationship data is not initially available", function(assert) { + assert.expect(3); + + Post.reopen({ + comments: DS.hasMany('comment', { async: true, inverse: 'post' }) + }); + Comment.reopen({ + post: DS.belongsTo('post', { async: false, inverse: 'comments' }) + }); + env.adapter.shouldBackgroundReloadRecord = () => { return false; }; + env.adapter.findRecord = () => { + assert.ok(false, "The adapter's findRecord method should not be called"); + }; + env.adapter.findMany = () => { + assert.ok(false, "The adapter's findMany method should not be called"); + }; + + env.adapter.findHasMany = function(store, snapshot, url, relationship) { + assert.equal(url, 'get-comments', 'url is correct'); + assert.ok(true, "The adapter's findHasMany method should be called"); + return resolve({ + data: [ + { + id: '1', + type: 'comment', + attributes: { + body: 'This is comment fetched by link' + } + } + ] + }); + }; + + return run(() => { + let post = env.store.push({ + data: { + type: 'post', + id: '1', + relationships: { + comments: { + links: { + related: 'get-comments' + } + } + } + }, + included: [ + { + id: '1', + type: 'comment', + attributes: { + body: 'This is comment' + }, + relationships: { + post: { + data: { + type: 'post', + id: '1' + } + } + } + } + ] + }); + + return post.get('comments').then(comments => { + assert.equal(comments.get('firstObject.body'), 'This is comment fetched by link', 'comment body is correct'); + }); + }); +}); + +test("Updated related link should take precedence over relationship data and local record data", function(assert) { assert.expect(3); Post.reopen({ @@ -3059,7 +3220,7 @@ test("Updated related link should take precedence over local data", function(ass assert.equal(url, 'comments-updated-link', 'url is correct'); assert.ok(true, "The adapter's findHasMany method should be called"); return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: 'This is comment' } } + { id: 1, type: 'comment', attributes: { body: 'This is updated comment' } } ]}); }; @@ -3100,7 +3261,7 @@ test("Updated related link should take precedence over local data", function(ass }); return post.get('comments').then(comments => { - assert.equal(comments.get('firstObject.body'), 'This is comment', 'comment body is correct'); + assert.equal(comments.get('firstObject.body'), 'This is updated comment', 'comment body is correct'); }); }); }); @@ -3365,3 +3526,79 @@ test("hasMany relationship with links doesn't trigger extra change notifications assert.equal(count, 0); }); + +test("A hasMany relationship with a link will trigger the link request even if a inverse related object is pushed to the store", function(assert) { + Post.reopen({ + comments: DS.hasMany('comment', { async: true }) + }); + + Comment.reopen({ + message: DS.belongsTo('post', { async: true}) + }); + + const postID = '1'; + + run(function() { + // load a record with a link hasMany relationship + env.store.push({ + data: { + type: 'post', + id: postID, + relationships: { + comments: { + links: { + related: '/posts/1/comments' + } + } + } + } + }); + + // if a related comment is pushed into the store, + // the post.comments.link will not be requested + // + // If this comment is not inserted into the store, everything works properly + env.store.push({ + data: { + type: 'comment', + id: '1', + attributes: { body: "First" }, + relationships: { + message: { + data: { type: 'post', id: postID } + } + } + } + }); + + env.adapter.findRecord = function(store, type, id, snapshot) { + throw new Error(`findRecord for ${type} should not be called`); + }; + + let hasManyCounter = 0; + env.adapter.findHasMany = function(store, snapshot, link, relationship) { + assert.equal(relationship.type, 'comment', "findHasMany relationship type was Comment"); + assert.equal(relationship.key, 'comments', "findHasMany relationship key was comments"); + assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); + hasManyCounter++; + + return resolve({ data: [ + { id: 1, type: 'comment', attributes: { body: "First" } }, + { id: 2, type: 'comment', attributes: { body: "Second" } } + ]}); + }; + + const post = env.store.peekRecord('post', postID); + post.get('comments').then(function(comments) { + assert.equal(comments.get('isLoaded'), true, "comments are loaded"); + assert.equal(hasManyCounter, 1, "link was requested"); + assert.equal(comments.get('length'), 2, "comments have 2 length"); + + post.hasMany('comments').reload().then(function(comments) { + assert.equal(comments.get('isLoaded'), true, "comments are loaded"); + assert.equal(hasManyCounter, 2, "link was requested"); + assert.equal(comments.get('length'), 2, "comments have 2 length"); + }); + }); + }); +}); diff --git a/tests/integration/relationships/json-api-links-test.js b/tests/integration/relationships/json-api-links-test.js new file mode 100644 index 00000000000..7c094e7b4c3 --- /dev/null +++ b/tests/integration/relationships/json-api-links-test.js @@ -0,0 +1,1932 @@ +import { run } from '@ember/runloop'; +import { get } from '@ember/object'; +import Ember from 'ember'; +import { resolve } from 'rsvp'; +import setupStore from 'dummy/tests/helpers/store'; +import { + reset as resetModelFactoryInjection +} from 'dummy/tests/helpers/model-factory-injection'; +import { module, test } from 'qunit'; +import DS from 'ember-data'; +import JSONAPIAdapter from "ember-data/adapters/json-api"; + +const { copy } = Ember; +const { Model, attr, hasMany, belongsTo } = DS; + +let env, User, Organisation; + +module("integration/relationship/json-api-links | Relationship state updates", { + beforeEach() {}, + + afterEach() { + resetModelFactoryInjection(); + run(env.container, 'destroy'); + } +}); + +test("Loading link with inverse:null on other model caches the two ends separately", function (assert) { + User = DS.Model.extend({ + organisation: belongsTo('organisation', { inverse: null }) + }); + + Organisation = DS.Model.extend({ + adminUsers: hasMany('user', { inverse: null }) + }); + + env = setupStore({ + user: User, + organisation: Organisation + }); + + env.registry.optionsForType('serializer', { singleton: false }); + env.registry.optionsForType('adapter', { singleton: false }); + + const store = env.store; + + User = store.modelFor('user'); + Organisation = store.modelFor('organisation'); + + env.registry.register('adapter:user', DS.JSONAPISerializer.extend({ + findRecord(store, type, id) { + return resolve({ + data: { + id, + type: 'user', + relationships: { + organisation: { + data: { id: 1, type: 'organisation' } + } + } + } + }); + } + })); + + env.registry.register('adapter:organisation', DS.JSONAPISerializer.extend({ + findRecord(store, type, id) { + return resolve({ + data: { + type: 'organisation', + id, + relationships: { + 'admin-users': { + links: { + related: '/org-admins' + } + } + } + } + }); + } + })); + + return run(() => { + return store.findRecord('user', 1) + .then(user1 => { + assert.ok(user1, 'user should be populated'); + + return store.findRecord('organisation', 2) + .then(org2FromFind => { + assert.equal(user1.belongsTo('organisation').remoteType(), 'id', `user's belongsTo is based on id`); + assert.equal(user1.belongsTo('organisation').id(), 1, `user's belongsTo has its id populated`); + + return user1.get('organisation') + .then(orgFromUser => { + assert.equal(user1.belongsTo('organisation').belongsToRelationship.relationshipIsStale, false, 'user should have loaded its belongsTo relationship'); + + assert.ok(org2FromFind, 'organisation we found should be populated'); + assert.ok(orgFromUser, 'user\'s organisation should be populated'); + }) + }) + }) + }); +}); + +test("Pushing child record should not mark parent:children as loaded", function (assert) { + let Child = DS.Model.extend({ + parent: belongsTo('parent', { inverse: 'children' }) + }); + + let Parent = DS.Model.extend({ + children: hasMany('child', { inverse: 'parent' }) + }); + + env = setupStore({ + parent: Parent, + child: Child + }); + + env.registry.optionsForType('serializer', { singleton: false }); + env.registry.optionsForType('adapter', { singleton: false }); + + const store = env.store; + + Parent = store.modelFor('parent'); + Child = store.modelFor('child'); + + return run(() => { + const parent = store.push({ + data: { + id: 'p1', + type: 'parent', + relationships: { + children: { + links: { + related: '/parent/1/children' + } + } + } + } + }); + + store.push({ + data: { + id: 'c1', + type: 'child', + relationships: { + parent: { + data: { + id: 'p1', + type: 'parent' + } + } + } + } + }); + + assert.equal(parent.hasMany('children').hasManyRelationship.relationshipIsStale, true, 'parent should think that children still needs to be loaded'); + }); +}); + +test("pushing has-many payloads with data (no links), then more data (no links) works as expected", function(assert) { + const User = Model.extend({ + pets: hasMany('pet', { async: true, inverse: 'owner' }) + }); + const Pet = Model.extend({ + owner: belongsTo('user', { async: false, inverse: 'pets' }) + }); + const Adapter = JSONAPIAdapter.extend({ + findHasMany() { + assert.ok(false, 'We dont fetch a link when we havent given a link'); + }, + findMany() { + assert.ok(false, 'adapter findMany called instead of using findRecord'); + }, + findRecord(_, __, id) { + assert.ok(id !== '1', `adapter findRecord called for all IDs except "1", called for "${id}"`); + return resolve({ + data: { + type: 'pet', + id, + relationships: { + owner: { + data: { type: 'user', id: '1' } + } + } + } + }); + } + }); + + env = setupStore({ + adapter: Adapter, + user: User, + pet: Pet + }); + + let { store } = env; + + // push data, no links + run(() => store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' } + ] + } + } + } + })); + + // push links, no data + run(() => store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + data: [ + { type: 'pet', id: '2' }, + { type: 'pet', id: '3' } + ] + } + } + } + })); + + let Chris = run(() => store.peekRecord('user', '1')); + run(() => get(Chris, 'pets')); +}); + +test("pushing has-many payloads with data (no links), then links (no data) works as expected", function(assert) { + const User = Model.extend({ + pets: hasMany('pet', { async: true, inverse: 'owner' }) + }); + const Pet = Model.extend({ + owner: belongsTo('user', { async: false, inverse: 'pets' }) + }); + const Adapter = JSONAPIAdapter.extend({ + findHasMany(_, __, link) { + assert.ok(link === './user/1/pets', 'We fetched via the correct link'); + return resolve({ + data: [ + { + type: 'pet', + id: '1', + relationships: { + owner: { + data: { type: 'user', id: '1' } + } + } + }, + { + type: 'pet', + id: '2', + relationships: { + owner: { + data: { type: 'user', id: '1' } + } + } + } + ] + }); + }, + findMany() { + assert.ok(false, 'adapter findMany called instead of using findHasMany with a link'); + }, + findRecord() { + assert.ok(false, 'adapter findRecord called instead of using findHasMany with a link'); + } + }); + + env = setupStore({ + adapter: Adapter, + user: User, + pet: Pet + }); + + let { store } = env; + + // push data, no links + run(() => store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' } + ] + } + } + } + })); + + // push links, no data + run(() => store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + links: { + related: './user/1/pets' + } + } + } + } + })); + + let Chris = run(() => store.peekRecord('user', '1')); + run(() => get(Chris, 'pets')); +}); + +test("pushing has-many payloads with links (no data), then data (no links) works as expected", function(assert) { + const User = Model.extend({ + pets: hasMany('pet', { async: true, inverse: 'owner' }) + }); + const Pet = Model.extend({ + owner: belongsTo('user', { async: false, inverse: 'pets' }) + }); + const Adapter = JSONAPIAdapter.extend({ + findHasMany(_, __, link) { + assert.ok(link === './user/1/pets', 'We fetched via the correct link'); + return resolve({ + data: [ + { + type: 'pet', + id: '1', + relationships: { + owner: { + data: { type: 'user', id: '1' } + } + } + }, + { + type: 'pet', + id: '2', + relationships: { + owner: { + data: { type: 'user', id: '1' } + } + } + } + ] + }); + }, + findMany() { + assert.ok(false, 'adapter findMany called instead of using findHasMany with a link'); + }, + findRecord() { + assert.ok(false, 'adapter findRecord called instead of using findHasMany with a link'); + } + }); + + env = setupStore({ + adapter: Adapter, + user: User, + pet: Pet + }); + + let { store } = env; + + // push links, no data + run(() => store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + links: { + related: './user/1/pets' + } + } + } + } + })); + + // push data, no links + run(() => store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' } + ] + } + } + } + })); + + let Chris = run(() => store.peekRecord('user', '1')); + + // we expect to still use the link info + run(() => get(Chris, 'pets')); +}); + +test("pushing has-many payloads with links, then links again works as expected", function(assert) { + const User = Model.extend({ + pets: hasMany('pet', { async: true, inverse: 'owner' }) + }); + const Pet = Model.extend({ + owner: belongsTo('user', { async: false, inverse: 'pets' }) + }); + const Adapter = JSONAPIAdapter.extend({ + findHasMany(_, __, link) { + assert.ok(link === './user/1/pets', 'We fetched via the correct link'); + return resolve({ + data: [ + { + type: 'pet', + id: '1', + relationships: { + owner: { + data: { type: 'user', id: '1' } + } + } + }, + { + type: 'pet', + id: '2', + relationships: { + owner: { + data: { type: 'user', id: '1' } + } + } + } + ] + }); + }, + findMany() { + assert.ok(false, 'adapter findMany called instead of using findHasMany with a link'); + }, + findRecord() { + assert.ok(false, 'adapter findRecord called instead of using findHasMany with a link'); + } + }); + + env = setupStore({ + adapter: Adapter, + user: User, + pet: Pet + }); + + let { store } = env; + + // push links, no data + run(() => store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + links: { + related: './user/1/not-pets' + } + } + } + } + })); + + // push data, no links + run(() => store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + links: { + related: './user/1/pets' + } + } + } + } + })); + + let Chris = run(() => store.peekRecord('user', '1')); + + // we expect to use the link info from the second push + run(() => get(Chris, 'pets')); +}); + +test("pushing has-many payloads with links and data works as expected", function(assert) { + const User = Model.extend({ + pets: hasMany('pet', { async: true, inverse: 'owner' }) + }); + const Pet = Model.extend({ + owner: belongsTo('user', { async: false, inverse: 'pets' }) + }); + const Adapter = JSONAPIAdapter.extend({ + findHasMany(_, __, link) { + assert.ok(link === './user/1/pets', 'We fetched via the correct link'); + return resolve({ + data: [ + { + type: 'pet', + id: '1', + relationships: { + owner: { + data: { type: 'user', id: '1' } + } + } + }, + { + type: 'pet', + id: '2', + relationships: { + owner: { + data: { type: 'user', id: '1' } + } + } + } + ] + }); + }, + findMany() { + assert.ok(false, 'adapter findMany called instead of using findHasMany with a link'); + }, + findRecord() { + assert.ok(false, 'adapter findRecord called instead of using findHasMany with a link'); + } + }); + + env = setupStore({ + adapter: Adapter, + user: User, + pet: Pet + }); + + let { store } = env; + + // push data and links + run(() => store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' } + ], + links: { + related: './user/1/pets' + } + } + } + } + })); + + let Chris = run(() => store.peekRecord('user', '1')); + run(() => get(Chris, 'pets')); +}); + +test("pushing has-many payloads with links, then one with links and data works as expected", function(assert) { + const User = Model.extend({ + pets: hasMany('pet', { async: true, inverse: 'owner' }) + }); + const Pet = Model.extend({ + owner: belongsTo('user', { async: false, inverse: 'pets' }) + }); + const Adapter = JSONAPIAdapter.extend({ + findHasMany(_, __, link) { + assert.ok(link === './user/1/pets', 'We fetched via the correct link'); + return resolve({ + data: [ + { + type: 'pet', + id: '1', + relationships: { + owner: { + data: { type: 'user', id: '1' } + } + } + }, + { + type: 'pet', + id: '2', + relationships: { + owner: { + data: { type: 'user', id: '1' } + } + } + } + ] + }); + }, + findMany() { + assert.ok(false, 'adapter findMany called instead of using findHasMany with a link'); + }, + findRecord() { + assert.ok(false, 'adapter findRecord called instead of using findHasMany with a link'); + } + }); + + env = setupStore({ + adapter: Adapter, + user: User, + pet: Pet + }); + + let { store } = env; + + // push data, no links + run(() => store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' } + ] + } + } + } + })); + + // push links and data + run(() => store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' }, + { type: 'pet', id: '2' }, + { type: 'pet', id: '3' } + ], + links: { + related: './user/1/pets' + } + } + } + } + })); + + let Chris = run(() => store.peekRecord('user', '1')); + run(() => get(Chris, 'pets')); +}); + +module("integration/relationship/json-api-links | Relationship fetching", { + beforeEach() { + const User = Model.extend({ + name: attr(), + pets: hasMany('pet', { async: true, inverse: 'owner' }), + home: belongsTo('home', { async: true, inverse: 'owner' }) + }); + const Home = Model.extend({ + address: attr(), + owner: belongsTo('user', { async: false, inverse: 'home' }) + }); + const Pet = Model.extend({ + name: attr(), + owner: belongsTo('user', { async: false, inverse: 'pets' }) + }); + const Adapter = JSONAPIAdapter.extend(); + + env = setupStore({ + adapter: Adapter, + user: User, + pet: Pet, + home: Home + }); + }, + + afterEach() { + resetModelFactoryInjection(); + run(env.container, 'destroy'); + env = null; + } +}); + +/* +Tests: + +Fetches Link +- get/reload hasMany with a link (no data) +- get/reload hasMany with a link and data (not available in store) +- get/reload hasMany with a link and empty data (`data: []`) + +Uses Link for Reload +- get/reload hasMany with a link and data (available in store) + +Does Not Use Link (as there is none) +- get/reload hasMany with data, no links +- get/reload hasMany with no data, no links +*/ + +/* + Used for situations when even initially we should fetch via link + */ +function shouldFetchLinkTests(description, payloads) { + test(`get+reload hasMany with ${description}`, function(assert) { + assert.expect(3); + let { store, adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(false, 'We should not call findRecord'); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = (_, __, link) => { + assert.ok( + link === payloads.user.data.relationships.pets.links.related, + 'We fetched the appropriate link' + ); + return resolve(copy(payloads.pets, true)); + }; + + // setup user + let user = run(() => store.push(copy(payloads.user, true))); + let pets = run(() => user.get('pets')); + + assert.ok(!!pets, 'We found our pets'); + + run(() => pets.reload()); + }); + test(`get+unload+get hasMany with ${description}`, function(assert) { + assert.expect(3); + let { store, adapter } = env; + + let petRelationshipData = payloads.user.data.relationships.pets.data; + let petRelDataWasEmpty = petRelationshipData && petRelationshipData.length === 0; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(false, 'We should not call findRecord'); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = (_, __, link) => { + if (petRelDataWasEmpty) { + assert.ok( + link === payloads.user.data.relationships.pets.links.related, + 'We fetched this link even though we really should not have' + ); + } else { + assert.ok( + link === payloads.user.data.relationships.pets.links.related, + 'We fetched the appropriate link' + ); + } + return resolve(copy(payloads.pets, true)); + }; + + // setup user + let user = run(() => store.push(copy(payloads.user, true))); + let pets = run(() => user.get('pets')); + + assert.ok(!!pets, 'We found our pets'); + + if (!petRelDataWasEmpty) { + run(() => pets.objectAt(0).unloadRecord()); + run(() => user.get('pets')); + } else { + assert.ok(true, `We cant dirty a relationship we have no knowledge of`); + } + }); + test(`get+reload belongsTo with ${description}`, function(assert) { + assert.expect(3); + let { store, adapter } = env; + + let homeRelationshipData = payloads.user.data.relationships.home.data; + let homeRelWasEmpty = homeRelationshipData === null; + let isInitialFetch = true; + let didFetchInitially = false; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(false, 'We should not call findRecord'); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findBelongsTo = (_, __, link) => { + if (isInitialFetch && homeRelWasEmpty) { + assert.ok(false, 'We should not fetch a relationship we believe is empty'); + didFetchInitially = true; + } else { + assert.ok( + link === payloads.user.data.relationships.home.links.related, + 'We fetched the appropriate link' + ); + } + return resolve(copy(payloads.home, true)); + }; + + // setup user + let user = run(() => store.push(copy(payloads.user, true))); + let home = run(() => user.get('home')); + + if (homeRelWasEmpty) { + assert.ok(!didFetchInitially, 'We did not fetch'); + } + + assert.ok(!!home, 'We found our home'); + isInitialFetch = false; + + run(() => home.reload()); + }); + test(`get+unload+get belongsTo with ${description}`, function(assert) { + assert.expect(3); + let { store, adapter } = env; + + let homeRelationshipData = payloads.user.data.relationships.home.data; + let homeRelWasEmpty = homeRelationshipData === null; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(false, 'We should not call findRecord'); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findBelongsTo = (_, __, link) => { + assert.ok( + !homeRelWasEmpty && + link === payloads.user.data.relationships.home.links.related, + 'We fetched the appropriate link' + ); + return resolve(copy(payloads.home, true)); + }; + + // setup user + let user = run(() => store.push(copy(payloads.user, true))); + let home = run(() => user.get('home')); + + assert.ok(!!home, 'We found our home'); + + if (!homeRelWasEmpty) { + run(() => home.then(h => h.unloadRecord())); + run(() => user.get('home')); + } else { + assert.ok(true, `We cant dirty a relationship we have no knowledge of`); + assert.ok(true, `Nor should we have fetched it.`); + } + }); +} + +shouldFetchLinkTests('a link (no data)', { + user: { + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: { + pets: { + links: { + related: './runspired/pets' + } + }, + home: { + links: { + related: './runspired/address' + } + } + } + } + }, + pets: { + data: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shen' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + ] + }, + home: { + data: { + type: 'home', + id: '1', + attributes: { + address: 'Oakland, Ca' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + } +}); + +shouldFetchLinkTests('a link and data (not available in the store)', { + user: { + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: { + pets: { + links: { + related: './runspired/pets' + }, + data: [ + { type: 'pet', id: '1' } + ] + }, + home: { + links: { + related: './runspired/address' + }, + data: { type: 'home', id: '1' } + } + } + } + }, + pets: { + data: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shen' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + }, + links: { + related: './user/1' + } + } + } + } + ] + }, + home: { + data: { + type: 'home', + id: '1', + attributes: { + address: 'Oakland, Ca' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + }, + links: { + related: './user/1' + } + } + } + } + } +}); + +/* + Used for situations when initially we have data, but reload/missing data + situations should be done via link + */ +function shouldReloadWithLinkTests(description, payloads) { + test(`get+reload hasMany with ${description}`, function(assert) { + assert.expect(2); + let { store, adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(false, 'We should not call findRecord'); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = (_, __, link) => { + assert.ok( + link === payloads.user.data.relationships.pets.links.related, + 'We fetched the appropriate link' + ); + return resolve(copy(payloads.pets, true)); + }; + + // setup user and pets + let user = run(() => store.push(copy(payloads.user, true))); + run(() => store.push(copy(payloads.pets, true))); + let pets = run(() => user.get('pets')); + + assert.ok(!!pets, 'We found our pets'); + + run(() => pets.reload()); + }); + test(`get+unload+get hasMany with ${description}`, function(assert) { + assert.expect(2); + let { store, adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(false, 'We should not call findRecord'); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = (_, __, link) => { + assert.ok( + link === payloads.user.data.relationships.pets.links.related, + 'We fetched the appropriate link' + ); + return resolve(copy(payloads.pets, true)); + }; + + // setup user and pets + let user = run(() => store.push(copy(payloads.user, true))); + run(() => store.push(copy(payloads.pets, true))); + let pets = run(() => user.get('pets')); + + assert.ok(!!pets, 'We found our pets'); + + run(() => pets.objectAt(0).unloadRecord()); + run(() => user.get('pets')); + }); + test(`get+reload belongsTo with ${description}`, function(assert) { + assert.expect(2); + let { store, adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(false, 'We should not call findRecord'); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findBelongsTo = (_, __, link) => { + assert.ok( + link === payloads.user.data.relationships.home.links.related, + 'We fetched the appropriate link' + ); + return resolve(copy(payloads.home, true)); + }; + + // setup user and home + let user = run(() => store.push(copy(payloads.user, true))); + run(() => store.push(copy(payloads.home, true))); + let home = run(() => user.get('home')); + + assert.ok(!!home, 'We found our home'); + + run(() => home.reload()); + }); + test(`get+unload+get belongsTo with ${description}`, function(assert) { + assert.expect(2); + let { store, adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(false, 'We should not call findRecord'); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findBelongsTo = (_, __, link) => { + assert.ok( + link === payloads.user.data.relationships.home.links.related, + 'We fetched the appropriate link' + ); + return resolve(copy(payloads.home, true)); + }; + + // setup user + let user = run(() => store.push(copy(payloads.user, true))); + run(() => store.push(copy(payloads.home, true))); + let home; + run(() => user.get('home').then(h => home = h)); + + assert.ok(!!home, 'We found our home'); + + run(() => home.unloadRecord()); + run(() => user.get('home')); + }); +} + +shouldReloadWithLinkTests('a link and data (available in the store)', { + user: { + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: { + pets: { + links: { + related: './runspired/pets' + }, + data: [ + { type: 'pet', id: '1' } + ] + }, + home: { + links: { + related: './runspired/address' + }, + data: { type: 'home', id: '1' } + } + } + } + }, + pets: { + data: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shen' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + ] + }, + home: { + data: { + type: 'home', + id: '1', + attributes: { + address: 'Oakland, Ca' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + } +}); + +shouldReloadWithLinkTests('a link and empty data (`data: []` or `data: null`), true inverse loaded', { + user: { + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: { + pets: { + links: { + related: './runspired/pets' + }, + data: [] + }, + home: { + links: { + related: './runspired/address' + }, + data: null + } + } + } + }, + pets: { + data: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shen' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + }, + links: { + related: './user/1' + } + } + } + } + ] + }, + home: { + data: { + type: 'home', + id: '1', + attributes: { + address: 'Oakland, Ca' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + }, + links: { + related: './user/1' + } + } + } + } + } +}); + +shouldReloadWithLinkTests('a link and empty data (`data: []` or `data: null`), true inverse unloaded', { + user: { + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: { + pets: { + links: { + related: './runspired/pets' + }, + data: [] + }, + home: { + links: { + related: './runspired/address' + }, + data: null + } + } + } + }, + pets: { + data: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shen' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + ] + }, + home: { + data: { + type: 'home', + id: '1', + attributes: { + address: 'Oakland, Ca' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + } +}); + +/* + Ad Hoc Situations when we don't have a link + */ + +// data, no links +test(`get+reload hasMany with data, no links`, function(assert) { + assert.expect(3); + let { store, adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(true, 'We should call findRecord'); + return resolve({ + data: { + type: 'pet', + id: '1', + attributes: { + name: 'Shen' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + }); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = () => { + assert.ok(false, 'We should not call findHasMany'); + }; + + // setup user + let user = run(() => store.push({ + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' } + ] + }, + home: { + data: { type: 'home', id: '1' } + } + } + } + })); + let pets = run(() => user.get('pets')); + + assert.ok(!!pets, 'We found our pets'); + + run(() => pets.reload()); +}); +test(`get+unload+get hasMany with data, no links`, function(assert) { + assert.expect(3); + let { store, adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(true, 'We should call findRecord'); + return resolve({ + data: { + type: 'pet', + id: '1', + attributes: { + name: 'Shen' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + }); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = () => { + assert.ok(false, 'We should not call findHasMany'); + }; + + // setup user + let user = run(() => store.push({ + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' } + ] + }, + home: { + data: { type: 'home', id: '1' } + } + } + } + })); + let pets = run(() => user.get('pets')); + + assert.ok(!!pets, 'We found our pets'); + + run(() => pets.objectAt(0).unloadRecord()); + run(() => user.get('pets')); +}); +test(`get+reload belongsTo with data, no links`, function(assert) { + assert.expect(3); + let { store, adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(true, 'We should call findRecord'); + return resolve({ + data: { + type: 'home', + id: '1', + attributes: { + address: 'Oakland, CA' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + }); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = () => { + assert.ok(false, 'We should not call findHasMany'); + }; + + + // setup user + let user = run(() => store.push({ + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' } + ] + }, + home: { + data: { type: 'home', id: '1' } + } + } + } + })); + let home = run(() => user.get('home')); + + assert.ok(!!home, 'We found our home'); + + run(() => home.reload()); +}); +test(`get+unload+get belongsTo with data, no links`, function(assert) { + assert.expect(3); + let { store, adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(true, 'We should call findRecord'); + return resolve({ + data: { + type: 'home', + id: '1', + attributes: { + address: 'Oakland, Ca' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + }); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = () => { + assert.ok(false, 'We should not call findHasMany'); + }; + + + // setup user + let user = run(() => store.push({ + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: { + pets: { + data: [ + { type: 'pet', id: '1' } + ] + }, + home: { + data: { type: 'home', id: '1' } + } + } + } + })); + let home = run(() => user.get('home')); + + assert.ok(!!home, 'We found our home'); + + run(() => home.then(h => h.unloadRecord())); + run(() => user.get('home')); +}); + +// missing data setup from the other side, no links +test(`get+reload hasMany with missing data setup from the other side, no links`, function(assert) { + assert.expect(2); + let { store, adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(true, 'We should call findRecord'); + return resolve({ + data: { + type: 'pet', + id: '1', + attributes: { + name: 'Shen' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + }); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = () => { + assert.ok(false, 'We should not call findHasMany'); + }; + + // setup user and pet + let user = run(() => store.push({ + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: {} + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shen' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + ] + })); + let pets = run(() => user.get('pets')); + + assert.ok(!!pets, 'We found our pets'); + + run(() => pets.reload()); +}); +test(`get+unload+get hasMany with missing data setup from the other side, no links`, function(assert) { + assert.expect(2); + let { store, adapter } = env; + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(true, 'We should call findRecord'); + return resolve({ + data: { + type: 'pet', + id: '1', + attributes: { + name: 'Shen' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + }); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = () => { + assert.ok(false, 'We should not call findHasMany'); + }; + + // setup user and pet + let user = run(() => store.push({ + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: {} + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shen' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + ] + })); + let pets = run(() => user.get('pets')); + + assert.ok(!!pets, 'We found our pets'); + + run(() => pets.objectAt(0).unloadRecord()); + run(() => user.get('pets')); +}); +test(`get+reload belongsTo with missing data setup from the other side, no links`, function(assert) { + assert.expect(2); + let { store, adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(true, 'We should call findRecord'); + return resolve({ + data: { + type: 'home', + id: '1', + attributes: { + address: 'Oakland, CA' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + }); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = () => { + assert.ok(false, 'We should not call findHasMany'); + }; + + // setup user and home + let user = run(() => store.push({ + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: {} + }, + included: [ + { + type: 'home', + id: '1', + attributes: { + address: 'Oakland, CA' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + ] + })); + let home = run(() => user.get('home')); + + assert.ok(!!home, 'We found our home'); + + run(() => home.reload()); +}); +test(`get+unload+get belongsTo with missing data setup from the other side, no links`, function(assert) { + assert.expect(2); + let { store, adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(true, 'We should call findRecord'); + return resolve({ + data: { + type: 'home', + id: '1', + attributes: { + address: 'Oakland, CA' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + }); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = () => { + assert.ok(false, 'We should not call findHasMany'); + }; + + // setup user and home + let user = run(() => store.push({ + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: {} + }, + included: [ + { + type: 'home', + id: '1', + attributes: { + address: 'Oakland, CA' + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + ] + })); + let home = run(() => user.get('home')); + + assert.ok(!!home, 'We found our home'); + + run(() => home.then(h => h.unloadRecord())); + run(() => user.get('home')); +}); + +// empty data, no links +test(`get+reload hasMany with empty data, no links`, function(assert) { + assert.expect(1); + let { store, adapter } = env; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(false, 'We should not call findRecord'); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = () => { + assert.ok(false, 'We should not call findHasMany'); + }; + + // setup user + let user = run(() => store.push({ + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: { + pets: { + data: [] + }, + home: { + data: null + } + } + } + })); + let pets = run(() => user.get('pets')); + + assert.ok(!!pets, 'We found our pets'); + + run(() => pets.reload()); +}); + +/* + Ad hoc situations where we do have a link + */ +test('We should not fetch a hasMany relationship with links that we know is empty', function(assert) { + assert.expect(1); + let { store, adapter } = env; + + let user1Payload = { + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired' + }, + relationships: { + pets: { + links: { + related: './runspired/pets' + }, + data: [] // we are explicitly told this is empty + } + } + } + }; + let user2Payload = { + data: { + type: 'user', + id: '2', + attributes: { + name: '@hjdivad' + }, + relationships: { + pets: { + links: { + related: './hjdivad/pets' + } + // we have no data, so we do not know that this is empty + } + } + } + }; + let requestedUser = null; + let failureDescription = ''; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(false, 'We should not call findRecord'); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = (_, __, link) => { + if (!requestedUser) { + assert.ok(false, failureDescription); + } else { + assert.ok( + link === requestedUser.data.relationships.pets.links.related, + 'We fetched the appropriate link' + ); + } + + return resolve({ + data: [] + }); + }; + + // setup users + let user1 = run(() => store.push(copy(user1Payload, true))); + let user2 = run(() => store.push(copy(user2Payload, true))); + + // should not fire a request + requestedUser = null; + failureDescription = 'We fetched the link for a known empty relationship'; + run(() => user1.get('pets')); + + // still should not fire a request + requestedUser = null; + failureDescription = 'We fetched the link (again) for a known empty relationship'; + run(() => user1.get('pets')); + + // should fire a request + requestedUser = user2Payload; + run(() => user2.get('pets')); + + // should not fire a request + requestedUser = null; + failureDescription = 'We fetched the link for a previously fetched and found to be empty relationship'; + run(() => user2.get('pets')); +}); diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index 420cb0fb5a1..5a614d08332 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -145,10 +145,9 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan }, relationships: { topics: { - data: [{ - id: '2', - type: 'topic' - }] + data: [ + { id: '2', type: 'topic' } + ] } } } diff --git a/tests/integration/relationships/nested-relationship-test.js b/tests/integration/relationships/nested-relationship-test.js index 9ef5d78c4a0..f6eceffee47 100644 --- a/tests/integration/relationships/nested-relationship-test.js +++ b/tests/integration/relationships/nested-relationship-test.js @@ -8,7 +8,7 @@ import DS from 'ember-data'; const { attr, hasMany, belongsTo } = DS; -let env, store, serializer, Elder, MiddleAger, Kid; +let env, store, Elder, MiddleAger, Kid; module('integration/relationships/nested_relationships_test - Nested relationships', { beforeEach() { @@ -36,7 +36,6 @@ module('integration/relationships/nested_relationships_test - Nested relationshi }); store = env.store; - serializer = env.serializer; }, afterEach() { @@ -49,36 +48,35 @@ module('integration/relationships/nested_relationships_test - Nested relationshi */ test('Sideloaded nested relationships load correctly', function(assert) { + env.adapter.shouldBackgroundReloadRecord = () => { return false; }; run(() => { - serializer.pushPayload(store, { - data: [ - { - id: '1', - type: 'kids', - links: { - self: '/kids/1' - }, - attributes: { - name: 'Kid 1' - }, - relationships: { - 'middle-ager': { - links: { - self: '/kids/1/relationships/middle-ager', - related: '/kids/1/middle-ager' - }, - data:{ - type: 'middle-agers', - id: '1' - } + store.push({ + data: { + id: '1', + type: 'kid', + links: { + self: '/kids/1' + }, + attributes: { + name: 'Kid 1' + }, + relationships: { + middleAger: { + links: { + self: '/kids/1/relationships/middle-ager', + related: '/kids/1/middle-ager' + }, + data:{ + type: 'middle-ager', + id: '1' } } } - ], + }, included: [ { id: '1', - type: 'middle-agers', + type: 'middle-ager', links: { self: '/middle-ager/1' }, @@ -92,7 +90,7 @@ test('Sideloaded nested relationships load correctly', function(assert) { related: '/middle-agers/1/elder' }, data: { - type: 'elders', + type: 'elder', id: '1' } }, @@ -100,14 +98,20 @@ test('Sideloaded nested relationships load correctly', function(assert) { links: { self: '/middle-agers/1/relationships/kids', related: '/middle-agers/1/kids' - } + }, + data: [ + { + type: 'kid', + id: '1' + } + ] } } }, { id: '1', - type: 'elders', + type: 'elder', links: { self: '/elders/1' }, @@ -115,7 +119,7 @@ test('Sideloaded nested relationships load correctly', function(assert) { name: 'Elder 1' }, relationships: { - 'middle-agers': { + middleAger: { links: { self: '/elders/1/relationships/middle-agers', related: '/elders/1/middle-agers' @@ -128,7 +132,7 @@ test('Sideloaded nested relationships load correctly', function(assert) { }); return run(() => { - let kid = store.peekRecord('kid', 1); + let kid = store.peekRecord('kid', '1'); return kid.get('middleAger').then(middleAger => { assert.ok(middleAger, 'MiddleAger relationship was set up correctly'); diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index ff2dcf8a1ed..9bb335fbf48 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -487,9 +487,13 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT }); test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsTo to null - sync", function(assert) { - var account; + let account1; + let account2; + let user; + run(function () { - store.push({ + // tell the store user:1 has account:1 + user = store.push({ data: { id: '1', type: 'user', @@ -498,15 +502,16 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT }, relationships: { accounts: { - data: [{ - id: '1', - type: 'account' - }] + data: [ + { id: '1', type: 'account' } + ] } } } }); - account = store.push({ + + // tell the store account:1 has user:1 + account1 = store.push({ data: { id: '1', type: 'account', @@ -515,15 +520,14 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT }, relationships: { user: { - data: { - id: '1', - type: 'user' - } + data: { id: '1', type: 'user' } } } } }); - store.push({ + + // tell the store account:2 has no user + account2 = store.push({ data: { id: '2', type: 'account', @@ -532,6 +536,8 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT } } }); + + // tell the store user:1 has account:2 and not account:1 store.push({ data: { id: '1', @@ -541,10 +547,9 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT }, relationships: { accounts: { - data: [{ - id: '2', - type: 'account' - }] + data: [ + { id: '2', type: 'account' } + ] } } } @@ -552,7 +557,8 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT }); run(function() { - assert.equal(account.get('user'), null, 'User was removed correctly'); + assert.ok(account1.get('user') === null, 'User was removed correctly'); + assert.ok(account2.get('user') === user, 'User was added correctly'); }); }); diff --git a/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js index 6ae8d776c2b..3e8169a3440 100644 --- a/tests/integration/snapshot-test.js +++ b/tests/integration/snapshot-test.js @@ -75,7 +75,7 @@ test("snapshot.id, snapshot.type and snapshot.modelName returns correctly", func }); }); -// skipped because snapshot creation requires using `eachAttribute` +// TODO'd because snapshot creation requires using `eachAttribute` // which as an approach requires that we MUST load the class. // there may be strategies via which we can snapshot known attributes // only if no record exists yet, since we would then know for sure diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 3cfb8a533ce..29bbbae7138 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -2005,6 +2005,78 @@ test('DS.ManyArray is lazy', function(assert) { }); }); +test('fetch hasMany loads full relationship after a parent and child have been loaded', function(assert) { + assert.expect(4); + + const Tag = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person', { async: true, inverse: 'tags' }) + }); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + tags: DS.hasMany('tag', { async: true, inverse: 'person' }) + }); + + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + + env.adapter.findHasMany = function(store, snapshot, url, relationship) { + assert.equal(relationship.key, 'tags', 'relationship should be tags'); + + return { data: [ + { id: 1, type: 'tag', attributes: { name: 'first' } }, + { id: 2, type: 'tag', attributes: { name: 'second' } }, + { id: 3, type: 'tag', attributes: { name: 'third' } } + ]}; + }; + + env.adapter.findRecord = function(store, type, id, snapshot) { + if (type === Person) { + return { + data: { + id: 1, + type: 'person', + attributes: { name: 'Watson' }, + relationships: { + tags: { links: { related: 'person/1/tags'} } + } + } + }; + } else if (type === Tag) { + return { + data: { + id: 2, + type: 'tag', + attributes: { name: 'second' }, + relationships: { + person: { + data: { id: 1, type: 'person'} + } + } + } + }; + } else { + assert.true(false, 'wrong type') + } + }; + + return run(() => { + return store.findRecord('person', 1).then(person => { + assert.equal(get(person, 'name'), 'Watson', 'The person is now loaded'); + + // when I remove this findRecord the test passes + return store.findRecord('tag', 2).then(tag => { + assert.equal(get(tag, 'name'), 'second', 'The tag is now loaded'); + + return run(() => person.get('tags').then(tags => { + assert.equal(get(tags, 'length'), 3, 'the tags are all loaded'); + })); + }); + }); + }); +}); + testInDebug('throws assertion if of not set with an array', function(assert) { const Person = DS.Model.extend(); const Tag = DS.Model.extend({ diff --git a/tests/unit/system/relationships/relationship-payloads-test.js b/tests/unit/system/relationships/relationship-payloads-test.js index 6f7715760d0..a0f9a76e51a 100644 --- a/tests/unit/system/relationships/relationship-payloads-test.js +++ b/tests/unit/system/relationships/relationship-payloads-test.js @@ -1,36 +1,54 @@ import { get } from '@ember/object'; import { RelationshipPayloadsManager } from 'ember-data/-private'; import DS from 'ember-data'; -import { createStore } from 'dummy/tests/helpers/store'; +import setupStore from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import { run } from '@ember/runloop'; +import { + reset as resetModelFactoryInjection +} from 'dummy/tests/helpers/model-factory-injection'; + +const { + belongsTo, + hasMany, + attr, + Model +} = DS; module('unit/system/relationships/relationship-payloads', { beforeEach() { - const User = DS.Model.extend({ - purpose: DS.belongsTo('purpose', { inverse: 'user' }), - hobbies: DS.hasMany('hobby', { inverse: 'user'}), - friends: DS.hasMany('user', { inverse: 'friends' }) + const User = Model.extend({ + purpose: belongsTo('purpose', { inverse: 'user' }), + hobbies: hasMany('hobby', { inverse: 'user'}), + friends: hasMany('user', { inverse: 'friends' }) }); User.toString = () => 'User'; - const Hobby = DS.Model.extend({ - user: DS.belongsTo('user', { inverse: 'hobbies' }) + const Hobby = Model.extend({ + user: belongsTo('user', { inverse: 'hobbies' }) }); Hobby.toString = () => 'Hobby'; - const Purpose = DS.Model.extend({ - user: DS.belongsTo('user', { inverse: 'purpose' }) + const Purpose = Model.extend({ + user: belongsTo('user', { inverse: 'purpose' }) }); Purpose.toString = () => 'Purpose'; - let store = this.store = createStore({ + this.env = setupStore({ user: User, Hobby: Hobby, purpose: Purpose }); + let store = this.store = this.env.store; + this.relationshipPayloadsManager = new RelationshipPayloadsManager(store); + }, + + afterEach() { + resetModelFactoryInjection(); + run(this.env.container, 'destroy'); } }); @@ -144,3 +162,183 @@ testInDebug('unload asserts the passed modelName and relationshipName refer to t }, 'brand-of-catnip:purpose is not either side of this relationship, user:purpose<->purpose:user'); }); +module("Unit | Relationship Payloads | Merge Forward Links & Meta", { + beforeEach() { + const User = Model.extend({ + name: attr(), + pets: hasMany('pet', { async: true, inverse: 'owner' }), + home: belongsTo('home', { async: true, inverse: 'owners' }) + }); + const Home = Model.extend({ + address: attr(), + owners: hasMany('user', { async: true, inverse: 'home' }) + }); + const Pet = Model.extend({ + name: attr(), + owner: belongsTo('user', { async: false, inverse: 'pets' }) + }); + + this.env = setupStore({ + user: User, + pet: Pet, + home: Home + }); + + this.store = this.env.store; + }, + + afterEach() { + resetModelFactoryInjection(); + run(this.env.container, 'destroy'); + } +}); + +test('links and meta for hasMany inverses are not overwritten', function(assert) { + let { store } = this; + + // user:1 with pet:1 pet:2 and home:1 and links and meta for both + let user1 = run(() => store.push({ + data: { + type: 'user', + id: '1', + attributes: { name: '@runspired ' }, + relationships: { + home: { + links: { + related: './runspired/home' + }, + data: { + type: 'home', + id: '1' + }, + meta: { + slogan: 'home is where the <3 emoji is' + } + }, + pets: { + links: { + related: './runspired/pets' + }, + data: [ + { type: 'pet', id: '1' }, + { type: 'pet', id: '2' } + ], + meta: { + slogan: 'catz rewl rawr' + } + } + } + } + })); + + // home:1 with user:1 user:2 and links and meta + // user:2 sideloaded to prevent needing to fetch + let home1 = run(() => store.push({ + data: { + type: 'home', + id: '1', + attributes: { address: 'Oakland, CA' }, + relationships: { + owners: { + links: { + related: './home/1/owners' + }, + data: [ + { type: 'user', id: '2' }, + { type: 'user', id: '1' } + ], + meta: { + slogan: 'what is woof?' + } + } + } + }, + included: [ + { + type: 'user', + id: '2', + attribute: { name: '@hjdivad' }, + relationships: { + home: { + data: { type: 'home', id: '1' } + } + } + } + ] + })); + + // Toss a couple of pets in for good measure + run(() => store.push({ + data: [ + { + type: 'pet', + id:'1', + attributes: { name: 'Shen' }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + }, + { + type: 'pet', + id:'2', + attributes: { name: 'Rambo' }, + relationships: { + owner: { + data: { + type: 'user', + id: '1' + } + } + } + } + ] + })); + + run(() => user1.get('home')); + run(() => user1.get('pets')); + run(() => home1.get('owners')); + + assert.deepEqual( + user1.belongsTo('home').belongsToRelationship.meta, + { + slogan: 'home is where the <3 emoji is' + }, + `We merged forward meta for user 1's home` + ); + assert.deepEqual( + home1.hasMany('owners').hasManyRelationship.meta, + { + slogan: 'what is woof?' + }, + `We merged forward meta for home 1's owners` + ); + assert.deepEqual( + user1.hasMany('pets').hasManyRelationship.meta, + { + slogan: 'catz rewl rawr' + }, + `We merged forward meta for user 1's pets` + ); + + // check the link as best we can + assert.equal( + user1.belongsTo('home').belongsToRelationship.link, + './runspired/home', + `We merged forward links for user 1's home` + ); + assert.equal( + user1.hasMany('pets').hasManyRelationship.link, + './runspired/pets', + `We merged forward links for user 1's pets` + ); + assert.equal( + home1.hasMany('owners').hasManyRelationship.link, + './home/1/owners', + `We merged forward links for home 1's owners` + ); +}); From f6d248be6026a5e550be0dc84ac99fc095629088 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 9 Apr 2018 17:48:25 -0700 Subject: [PATCH 2205/2527] Implement fix adds an explicit test for laziness during findRecord cleanup test --- addon/-private/system/snapshot.js | 30 +++++-- tests/integration/snapshot-test.js | 133 ++++++++++++++++++++++++----- 2 files changed, 134 insertions(+), 29 deletions(-) diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index e6b04c8b20f..8d9d30f1f61 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -17,18 +17,23 @@ import { get } from '@ember/object'; */ export default class Snapshot { constructor(internalModel, options = {}) { - this._attributes = Object.create(null); + this.__attributes = null; this._belongsToRelationships = Object.create(null); this._belongsToIds = Object.create(null); this._hasManyRelationships = Object.create(null); this._hasManyIds = Object.create(null); this._internalModel = internalModel; - // TODO is there a way we can assign known attributes without - // using `eachAttribute`? This forces us to lookup the model-class - // but for findRecord / findAll these are empty and doing so at - // this point in time is unnecessary. - internalModel.eachAttribute((keyName) => this._attributes[keyName] = internalModel.getAttributeValue(keyName)); + /* + If the internalModel does not yet have a record, then we are + likely a snapshot being provided to a find request, so we + populate __attributes lazily. Else, to preserve the "moment + in time" in which a snapshot is created, we greedily grab + the values. + */ + if (internalModel.hasRecord) { + this._attributes; + } /**O The id of the snapshot's underlying record @@ -81,6 +86,19 @@ export default class Snapshot { return this._internalModel.getRecord(); } + get _attributes() { + let attributes = this.__attributes; + + if (attributes === null) { + let record = this.record; + attributes = this.__attributes = Object.create(null); + + record.eachAttribute((keyName) => attributes[keyName] = get(record, keyName)); + } + + return attributes; + } + /** The type of the underlying record for this snapshot, as a DS.Model. diff --git a/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js index 3e8169a3440..f9e79980a00 100644 --- a/tests/integration/snapshot-test.js +++ b/tests/integration/snapshot-test.js @@ -2,22 +2,23 @@ import { resolve } from 'rsvp'; import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import { module, test, skip } from 'qunit'; +import { module, test } from 'qunit'; import DS from 'ember-data'; +const { Model, attr, hasMany,belongsTo, Snapshot } = DS; let env, Post, Comment; -module("integration/snapshot - DS.Snapshot", { +module("integration/snapshot - Snapshot", { beforeEach() { - Post = DS.Model.extend({ - author: DS.attr(), - title: DS.attr(), - comments: DS.hasMany({ async: true }) + Post = Model.extend({ + author: attr(), + title: attr(), + comments: hasMany({ async: true }) }); - Comment = DS.Model.extend({ - body: DS.attr(), - post: DS.belongsTo({ async: true }) + Comment = Model.extend({ + body: attr(), + post: belongsTo({ async: true }) }); env = setupStore({ @@ -33,6 +34,30 @@ module("integration/snapshot - DS.Snapshot", { } }); +test('snapshot.attributes() includes defaultValues when appropriate', function(assert) { + const Address = Model.extend({ + street: attr(), + country: attr({ defaultValue: 'USA' }), + state: attr({ defaultValue: () => 'CA' }) + }); + + let { store } = setupStore({ + address: Address + }); + let newAddress = store.createRecord('address', {}); + let snapshot = newAddress._createSnapshot(); + let expected = { + country: "USA", + state: "CA", + street: undefined + }; + + assert.ok(snapshot instanceof Snapshot, 'snapshot is an instance of Snapshot'); + assert.deepEqual(snapshot.attributes(), expected, 'We generated attributes with default values'); + + run(() => store.destroy()); +}); + test("record._createSnapshot() returns a snapshot", function(assert) { assert.expect(1); @@ -49,7 +74,7 @@ test("record._createSnapshot() returns a snapshot", function(assert) { let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); - assert.ok(snapshot instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); + assert.ok(snapshot instanceof Snapshot, 'snapshot is an instance of Snapshot'); }); }); @@ -70,17 +95,12 @@ test("snapshot.id, snapshot.type and snapshot.modelName returns correctly", func let snapshot = post._createSnapshot(); assert.equal(snapshot.id, '1', 'id is correct'); - assert.ok(DS.Model.detect(snapshot.type), 'type is correct'); + assert.ok(Model.detect(snapshot.type), 'type is correct'); assert.equal(snapshot.modelName, 'post', 'modelName is correct'); }); }); -// TODO'd because snapshot creation requires using `eachAttribute` -// which as an approach requires that we MUST load the class. -// there may be strategies via which we can snapshot known attributes -// only if no record exists yet, since we would then know for sure -// that this snapshot is not being used for a `.save()`. -skip('snapshot.type loads the class lazily', function(assert) { +test('snapshot.type loads the class lazily', function(assert) { assert.expect(3); let postClassLoaded = false; @@ -93,7 +113,7 @@ skip('snapshot.type loads the class lazily', function(assert) { }; run(() => { - env.store.push({ + env.store._push({ data: { type: 'post', id: '1', @@ -111,6 +131,73 @@ skip('snapshot.type loads the class lazily', function(assert) { }); }); +test('an initial findRecord call has no record for internal-model when a snapshot is generated', function(assert) { + assert.expect(2); + env.adapter.findRecord = (store, type, id, snapshot) => { + assert.equal(snapshot._internalModel.hasRecord, false, 'We do not have a materialized record'); + assert.equal(snapshot.__attributes, null, 'attributes were not populated initially'); + return resolve({ + data: { + type: 'post', + id: '1', + attributes: { + title: 'Hello World' + } + } + }); + }; + + run(() => env.store.findRecord('post', '1')); +}); + +test('snapshots for un-materialized internal-models generate attributes lazily', function(assert) { + assert.expect(2); + + run(() => env.store._push({ + data: { + type: 'post', + id: '1', + attributes: { + title: 'Hello World' + } + } + })); + + let postInternalModel = env.store._internalModelForId('post', 1); + let snapshot = postInternalModel.createSnapshot(); + let expected = { + author: undefined, + title: 'Hello World' + }; + + assert.equal(snapshot.__attributes, null, 'attributes were not populated initially'); + snapshot.attributes(); + assert.deepEqual(snapshot.__attributes, expected, 'attributes were populated on access'); +}); + +test('snapshots for materialized internal-models generate attributes greedily', function(assert) { + assert.expect(1); + + run(() => env.store.push({ + data: { + type: 'post', + id: '1', + attributes: { + title: 'Hello World' + } + } + })); + + let postInternalModel = env.store._internalModelForId('post', 1); + let snapshot = postInternalModel.createSnapshot(); + let expected = { + author: undefined, + title: 'Hello World' + }; + + assert.deepEqual(snapshot.__attributes, expected, 'attributes were populated initially'); +}); + test("snapshot.attr() does not change when record changes", function(assert) { assert.expect(2); @@ -281,7 +368,7 @@ test("snapshot.belongsTo() returns a snapshot if relationship is set", function( let snapshot = comment._createSnapshot(); let relationship = snapshot.belongsTo('post'); - assert.ok(relationship instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); + assert.ok(relationship instanceof Snapshot, 'snapshot is an instance of Snapshot'); assert.equal(relationship.id, '1', 'post id is correct'); assert.equal(relationship.attr('title'), 'Hello World', 'post title is correct'); }); @@ -403,7 +490,7 @@ test("snapshot.belongsTo() returns a snapshot if relationship link has been fetc let snapshot = comment._createSnapshot(); let relationship = snapshot.belongsTo('post'); - assert.ok(relationship instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); + assert.ok(relationship instanceof Snapshot, 'snapshot is an instance of Snapshot'); assert.equal(relationship.id, '1', 'post id is correct'); }); }); @@ -443,7 +530,7 @@ test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when adding assert.ok(hasManyRelationship instanceof Array, 'hasMany relationship is an instance of Array'); assert.equal(hasManyRelationship.length, 1, 'hasMany relationship contains related object'); - assert.ok(belongsToRelationship instanceof DS.Snapshot, 'belongsTo relationship is an instance of DS.Snapshot'); + assert.ok(belongsToRelationship instanceof Snapshot, 'belongsTo relationship is an instance of Snapshot'); assert.equal(belongsToRelationship.attr('title'), 'Hello World', 'belongsTo relationship contains related object'); }); }); @@ -482,7 +569,7 @@ test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when setting assert.ok(hasManyRelationship instanceof Array, 'hasMany relationship is an instance of Array'); assert.equal(hasManyRelationship.length, 1, 'hasMany relationship contains related object'); - assert.ok(belongsToRelationship instanceof DS.Snapshot, 'belongsTo relationship is an instance of DS.Snapshot'); + assert.ok(belongsToRelationship instanceof Snapshot, 'belongsTo relationship is an instance of Snapshot'); assert.equal(belongsToRelationship.attr('title'), 'Hello World', 'belongsTo relationship contains related object'); }); }); @@ -645,7 +732,7 @@ test("snapshot.hasMany() returns array of snapshots if relationship is set", fun let relationship1 = relationship[0]; - assert.ok(relationship1 instanceof DS.Snapshot, 'relationship item is an instance of DS.Snapshot'); + assert.ok(relationship1 instanceof Snapshot, 'relationship item is an instance of Snapshot'); assert.equal(relationship1.id, '1', 'relationship item id is correct'); assert.equal(relationship1.attr('body'), 'This is the first comment', 'relationship item body is correct'); From 5e680a78141e2a5525fc0897bbb4d5e62eb38ab3 Mon Sep 17 00:00:00 2001 From: Eli Flanagan Date: Mon, 9 Apr 2018 11:48:33 -0400 Subject: [PATCH 2206/2527] improve tests for unloading relationships also formats quotes for consistency --- addon/-private/system/internal-model-map.js | 2 + tests/integration/records/unload-test.js | 224 +++++++++++++++++--- tests/unit/store/unload-test.js | 4 +- 3 files changed, 193 insertions(+), 37 deletions(-) diff --git a/addon/-private/system/internal-model-map.js b/addon/-private/system/internal-model-map.js index d3f9d180469..59cd6b0501d 100644 --- a/addon/-private/system/internal-model-map.js +++ b/addon/-private/system/internal-model-map.js @@ -49,6 +49,8 @@ export default class InternalModelMap { assert(`You cannot re-add an already present InternalModel to the InternalModelMap.`, !this.contains(internalModel)); if (id) { + assert(`Duplicate InternalModel for ${this.modelName}:${id} detected.`, !this.has(id) || this.get(id) === internalModel); + this._idToModel[id] = internalModel; } diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index f7cdb8494a4..1d4b628c809 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -1,21 +1,22 @@ /*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(adam|bob|dudu)" }]*/ -import { Promise as EmberPromise } from 'rsvp'; - +import { resolve, Promise as EmberPromise } from 'rsvp'; +import { get } from '@ember/object'; import { run } from '@ember/runloop'; - -import setupStore from 'dummy/tests/helpers/store'; - import { module, test } from 'qunit'; - import DS from 'ember-data'; +import setupStore from 'dummy/tests/helpers/store'; + +const { + attr, + belongsTo, + hasMany, + Model +} = DS; -let attr = DS.attr; -let belongsTo = DS.belongsTo; -let hasMany = DS.hasMany; let env; -let Person = DS.Model.extend({ +let Person = Model.extend({ name: attr('string'), // 1:many sync cars: hasMany('car', { async: false }), @@ -44,55 +45,55 @@ let Person = DS.Model.extend({ }); Person.reopenClass({ toString() { return 'Person'; } }); -let House = DS.Model.extend({ +let House = Model.extend({ person: belongsTo('person', { async: false }) }); House.reopenClass({ toString() { return 'House'; } }); -let Mortgage = DS.Model.extend({ +let Mortgage = Model.extend({ person: belongsTo('person', { async: true }) }); Mortgage.reopenClass({ toString() { return 'Mortgage'; } }); -let Group = DS.Model.extend({ +let Group = Model.extend({ people: hasMany('person', { async: false }) }); Group.reopenClass({ toString() { return 'Group'; } }); -let Car = DS.Model.extend({ +let Car = Model.extend({ make: attr('string'), model: attr('string'), person: belongsTo('person', { async: false }) }); Car.reopenClass({ toString() { return 'Car'; } }); -let Boat = DS.Model.extend({ +let Boat = Model.extend({ name: attr('string'), person: belongsTo('person', { async: true }) }); Boat.toString = function() { return 'Boat'; }; -let Bike = DS.Model.extend({ +let Bike = Model.extend({ name: DS.attr() }); Bike.toString = function() { return 'Bike'; }; -let Book = DS.Model.extend({ +let Book = Model.extend({ person: belongsTo('person', { async: true }) }); Book.toString = function() { return 'Book'; }; -let Spoon = DS.Model.extend({ +let Spoon = Model.extend({ person: belongsTo('person', { async: true }) }); Spoon.toString = function() { return 'Spoon'; }; -let Show = DS.Model.extend({ +let Show = Model.extend({ person: belongsTo('person', { async: false }) }); Show.toString = function() { return 'Show'; }; -module("integration/unload - Unloading Records", { +module('integration/unload - Unloading Records', { beforeEach() { env = setupStore({ adapter: DS.JSONAPIAdapter, @@ -116,7 +117,7 @@ module("integration/unload - Unloading Records", { } }); -test("can unload a single record", function(assert) { +test('can unload a single record', function(assert) { let adam; run(function() { env.store.push({ @@ -165,7 +166,7 @@ test("can unload a single record", function(assert) { assert.equal(relPayloads.get('person', 1, 'boats'), null, 'no boat relationship payload is cached'); }); -test("can unload all records for a given type", function(assert) { +test('can unload all records for a given type', function(assert) { assert.expect(11); let adam, bob, dudu; @@ -193,8 +194,8 @@ test("can unload all records for a given type", function(assert) { type: 'car', id: '1', attributes: { - make: "VW", - model: "Beetle" + make: 'VW', + model: 'Beetle' }, relationships: { person: { @@ -240,7 +241,7 @@ test("can unload all records for a given type", function(assert) { assert.equal(env.store.peekRecord('car', 1).get('person.name'), 'Richard II', 'Inverse can load relationship after the record is unloaded'); }); -test("can unload all records", function(assert) { +test('can unload all records', function(assert) { assert.expect(8); let adam, bob, dudu; @@ -268,8 +269,8 @@ test("can unload all records", function(assert) { type: 'car', id: '1', attributes: { - make: "VW", - model: "Beetle" + make: 'VW', + model: 'Beetle' }, relationships: { person: { @@ -296,7 +297,7 @@ test("can unload all records", function(assert) { assert.equal(env.store._internalModelsFor('car').length, 0, 'zero car internalModels loaded'); }); -test("removes findAllCache after unloading all records", function(assert) { +test('removes findAllCache after unloading all records', function(assert) { assert.expect(4); let adam, bob; @@ -332,7 +333,7 @@ test("removes findAllCache after unloading all records", function(assert) { assert.equal(env.store._internalModelsFor('person').length, 0, 'zero person internalModels loaded'); }); -test("unloading all records also updates record array from peekAll()", function(assert) { +test('unloading all records also updates record array from peekAll()', function(assert) { let adam, bob; run(function() { env.store.push({ @@ -364,6 +365,159 @@ test("unloading all records also updates record array from peekAll()", function( assert.equal(all.get('length'), 0); }); +function makeBoatOneForPersonOne() { + return { + type: 'boat', + id: '1', + attributes: { + name: 'Boaty McBoatface' + }, + relationships: { + person: { + data: { type: 'person', id: '1' } + } + } + }; +} + +test('unloadAll(type) does not leave stranded internalModels in relationships (rediscover via store.push)', function(assert) { + assert.expect(15); + + let { store } = env; + + let person = run(() => store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Could be Anybody' + }, + relationships: { + boats: { + data: [ + { type: 'boat', id: '1' } + ] + } + } + }, + included: [ + makeBoatOneForPersonOne() + ] + })); + + let boat = store.peekRecord('boat', '1'); + let initialBoatInternalModel = boat._internalModel; + let relationshipState = person.hasMany('boats').hasManyRelationship; + let knownPeople = env.store._internalModelsFor('person'); + let knownBoats = store._internalModelsFor('boat'); + + // ensure we loaded the people and boats + assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); + assert.equal(knownBoats.models.length, 1, 'one boat record is loaded'); + assert.equal(env.store.hasRecordForId('person', '1'), true); + assert.equal(env.store.hasRecordForId('boat', '1'), true); + + // ensure the relationship was established (we reach through the async proxy here) + let peopleBoats = run(() => person.get('boats.content')); + let boatPerson = run(() => boat.get('person.content')); + + assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should be 1'); + assert.equal(relationshipState.members.size, 1, 'members size should be 1'); + assert.ok(get(peopleBoats, 'length') === 1, 'Our person has a boat'); + assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat'); + assert.ok(boatPerson === person, 'Our boat has the right person'); + + run(() => { store.unloadAll('boat') }); + + // ensure that our new state is correct + assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); + assert.equal(knownBoats.models.length, 0, 'no boat records are loaded'); + assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should still be 1'); + assert.equal(relationshipState.members.size, 1, 'members size should still be 1'); + assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats'); + + run(() => store.push({ + data: makeBoatOneForPersonOne() + })); + + let reloadedBoat = store.peekRecord('boat', '1'); + let reloadedBoatInternalModel = reloadedBoat._internalModel; + + assert.ok(reloadedBoatInternalModel === initialBoatInternalModel, 'after an unloadAll, subsequent fetch results in the same InternalModel'); +}); + +test('unloadAll(type) does not leave stranded internalModels in relationships (rediscover via relationship reload)', function(assert) { + assert.expect(17); + + let { store } = env; + + env.adapter.findRecord = (store, type, id) => { + assert.ok(type.modelName === 'boat', 'We refetch the boat'); + assert.ok(id === '1', 'We refetch the right boat'); + return resolve({ + data: makeBoatOneForPersonOne() + }); + }; + + let person = run(() => store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Could be Anybody' + }, + relationships: { + boats: { + data: [ + { type: 'boat', id: '1' } + ] + } + } + }, + included: [ + makeBoatOneForPersonOne() + ] + })); + + let boat = store.peekRecord('boat', '1'); + let initialBoatInternalModel = boat._internalModel; + let relationshipState = person.hasMany('boats').hasManyRelationship; + let knownPeople = env.store._internalModelsFor('person'); + let knownBoats = store._internalModelsFor('boat'); + + // ensure we loaded the people and boats + assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); + assert.equal(knownBoats.models.length, 1, 'one boat record is loaded'); + assert.equal(env.store.hasRecordForId('person', '1'), true); + assert.equal(env.store.hasRecordForId('boat', '1'), true); + + // ensure the relationship was established (we reach through the async proxy here) + let peopleBoats = run(() => person.get('boats.content')); + let boatPerson = run(() => boat.get('person.content')); + + assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should be 1'); + assert.equal(relationshipState.members.size, 1, 'members size should be 1'); + assert.ok(get(peopleBoats, 'length') === 1, 'Our person has a boat'); + assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat'); + assert.ok(boatPerson === person, 'Our boat has the right person'); + + run(() => { store.unloadAll('boat') }); + + // ensure that our new state is correct + assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); + assert.equal(knownBoats.models.length, 0, 'no boat records are loaded'); + assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should still be 1'); + assert.equal(relationshipState.members.size, 1, 'members size should still be 1'); + assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats'); + + run(() => person.get('boats')); + + let reloadedBoat = store.peekRecord('boat', '1'); + let reloadedBoatInternalModel = reloadedBoat._internalModel; + + assert.ok(reloadedBoatInternalModel === initialBoatInternalModel, 'after an unloadAll, subsequent fetch results in the same InternalModel'); +}); + test('unloading a disconnected subgraph clears the relevant internal models', function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; @@ -479,7 +633,7 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu }); -test("Unloading a record twice only schedules destroy once", function(assert) { +test('Unloading a record twice only schedules destroy once', function(assert) { const store = env.store; let record; @@ -507,7 +661,7 @@ test("Unloading a record twice only schedules destroy once", function(assert) { assert.equal(internalModel.isDestroyed, false, 'We cancelled destroy'); }); -test("Cancelling destroy leaves the record in the empty state", function(assert) { +test('Cancelling destroy leaves the record in the empty state', function(assert) { const store = env.store; let record; @@ -541,7 +695,7 @@ test("Cancelling destroy leaves the record in the empty state", function(assert) assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are still unloaded after unloadRecord'); }); -test("after unloading a record, the record can be fetched again immediately", function(assert) { +test('after unloading a record, the record can be fetched again immediately', function(assert) { const store = env.store; // stub findRecord @@ -605,7 +759,7 @@ test("after unloading a record, the record can be fetched again immediately", fu }); }); -test("after unloading a record, the record can be fetched again immediately (purge relationship)", function(assert) { +test('after unloading a record, the record can be fetched again immediately (purge relationship)', function(assert) { const store = env.store; // stub findRecord @@ -675,7 +829,7 @@ test("after unloading a record, the record can be fetched again immediately (pur }); }); -test("after unloading a record, the record can be fetched again immediately (with relationships)", function(assert) { +test('after unloading a record, the record can be fetched again immediately (with relationships)', function(assert) { const store = env.store; // stub findRecord env.adapter.findRecord = () => { @@ -738,7 +892,7 @@ test("after unloading a record, the record can be fetched again immediately (wit return wait; }); -test("after unloading a record, the record can be fetched again soon there after", function(assert) { +test('after unloading a record, the record can be fetched again soon there after', function(assert) { const store = env.store; let record; diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index ee7b1920333..772b5cd959e 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -60,7 +60,7 @@ testInDebug('unload a dirty record asserts', function(assert) { record.set('title', 'toto2'); record._internalModel.send('willCommit'); - assert.equal(get(record, 'hasDirtyAttributes'), true, "record is dirty"); + assert.equal(get(record, 'hasDirtyAttributes'), true, 'record is dirty'); assert.expectAssertion(function() { record.unloadRecord(); @@ -113,7 +113,7 @@ test('unload followed by create of the same type + id', function(assert) { }); }); -module("DS.Store - unload record with relationships"); +module('DS.Store - unload record with relationships'); test('can commit store after unload record with relationships', function(assert) { assert.expect(1); From f1cada5954018316a1638750a7bc6b51395e6e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barth=C3=A9lemy=20Laurans?= Date: Wed, 11 Apr 2018 22:55:47 +0200 Subject: [PATCH 2207/2527] Remove exists-sync dependency --- lib/calculate-version.js | 4 ++-- lib/utilities/extend-from-application-entity.js | 4 ++-- package.json | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/calculate-version.js b/lib/calculate-version.js index db2eb446447..f3d937c3c9b 100644 --- a/lib/calculate-version.js +++ b/lib/calculate-version.js @@ -1,5 +1,5 @@ var path = require('path'); -var existsSync = require('exists-sync'); +var fs = require('fs'); var gitRepoInfo = require('git-repo-info'); var npmGitInfo = require('npm-git-info'); @@ -9,7 +9,7 @@ module.exports = function() { var packageVersion = package.version; var suffix = ''; - if (existsSync(gitPath)) { + if (fs.existsSync(gitPath)) { var info = gitRepoInfo(gitPath); if (info.tag) { return info.tag.replace(/^v/, ''); diff --git a/lib/utilities/extend-from-application-entity.js b/lib/utilities/extend-from-application-entity.js index 437a38818b4..cd958854cb7 100644 --- a/lib/utilities/extend-from-application-entity.js +++ b/lib/utilities/extend-from-application-entity.js @@ -1,7 +1,7 @@ var stringUtil = require('ember-cli-string-utils'); var SilentError = require('silent-error'); var pathUtil = require('ember-cli-path-utils'); -var existsSync = require('exists-sync'); +var fs = require('fs'); var path = require('path'); module.exports = function(type, baseClass, options) { @@ -15,7 +15,7 @@ module.exports = function(type, baseClass, options) { var entityDirectory = type + 's'; var applicationEntityPath = path.join(options.project.root, 'app', entityDirectory, 'application.js'); - var hasApplicationEntity = existsSync(applicationEntityPath); + var hasApplicationEntity = fs.existsSync(applicationEntityPath); if (!isAddon && !options.baseClass && entityName !== 'application' && hasApplicationEntity) { options.baseClass = 'application'; } diff --git a/package.json b/package.json index 2a156b52e6e..4a352fc86ed 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,6 @@ "ember-cli-version-checker": "^2.1.0", "ember-inflector": "^2.0.0", "ember-runtime-enumerable-includes-polyfill": "^2.0.0", - "exists-sync": "0.0.3", "git-repo-info": "^1.1.2", "heimdalljs": "^0.3.0", "inflection": "^1.8.0", From 9ea15748b8d8fb8135f140fa4d0790f12ce2b16c Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Thu, 12 Apr 2018 14:02:00 +0100 Subject: [PATCH 2208/2527] [DOC release] Update attr.js Due to the indentation in the description of the defaultValue bullet point, our markdown renderer is considering it to be a code block. --- addon/attr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/attr.js b/addon/attr.js index 48c2e237767..ddbb80e3724 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -36,7 +36,7 @@ function hasValue(record, key) { supported options are: - `defaultValue`: Pass a string or a function to be called to set the attribute - to a default value if none is supplied. + to a default value if none is supplied. Example From 23a87e8e7a7cd39e33ef877148f7d9e8f103c2ab Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 16 Apr 2018 13:30:09 -0700 Subject: [PATCH 2209/2527] [CHORE] remove all usage of Ember.copy fix package.json support IE11 --- addon/-private/system/model/internal-model.js | 17 +++--- addon/-private/system/snapshot.js | 8 ++- addon/-private/system/store.js | 5 +- tests/helpers/deep-copy.js | 54 +++++++++++++++++++ .../adapter/build-url-mixin-test.js | 4 +- .../integration/adapter/rest-adapter-test.js | 5 +- .../integration/records/rematerialize-test.js | 11 ++-- .../relationships/json-api-links-test.js | 47 ++++++++-------- tests/integration/store-test.js | 4 +- .../polymorphic-relationship-payloads-test.js | 10 ++-- 10 files changed, 105 insertions(+), 60 deletions(-) create mode 100644 tests/helpers/deep-copy.js diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index d8f99b67a17..936a6385402 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -1,7 +1,6 @@ -import { assign, merge } from '@ember/polyfills'; import { A } from '@ember/array'; import { set, get } from '@ember/object'; -import { copy } from '@ember/object/internals'; +import { assign } from '@ember/polyfills'; import EmberError from '@ember/error'; import { isEqual } from '@ember/utils'; import { setOwner } from '@ember/application'; @@ -24,8 +23,6 @@ import { HasManyReference } from "../references"; -const emberAssign = assign || merge; - /* The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached when transitioning from one state to another, so that future transitions can replay the @@ -636,7 +633,7 @@ export default class InternalModel { changedKeys = this._changedKeys(data.attributes); } - emberAssign(this._data, data.attributes); + assign(this._data, data.attributes); this.pushedData(); if (this.hasRecord) { @@ -809,7 +806,7 @@ export default class InternalModel { let oldData = this._data; let currentData = this._attributes; let inFlightData = this._inFlightAttributes; - let newData = emberAssign(copy(inFlightData), currentData); + let newData = assign({}, inFlightData, currentData); let diffData = Object.create(null); let newDataKeys = Object.keys(newData); @@ -1173,9 +1170,9 @@ export default class InternalModel { this.didCleanError(); let changedKeys = this._changedKeys(data); - emberAssign(this._data, this._inFlightAttributes); + assign(this._data, this._inFlightAttributes); if (data) { - emberAssign(this._data, data); + assign(this._data, data); } this._inFlightAttributes = null; @@ -1303,8 +1300,8 @@ export default class InternalModel { attrs= this._attributes; } - original = emberAssign(Object.create(null), this._data); - original = emberAssign(original, this._inFlightAttributes); + original = Object.create(null); + assign(original, this._data, this._inFlightAttributes); for (i = 0; i < length; i++) { key = keys[i]; diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index 8d9d30f1f61..369e868a3f1 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -1,12 +1,10 @@ /** @module ember-data */ - -import { copy } from '@ember/object/internals'; - import { inspect } from '@ember/debug'; import EmberError from '@ember/error'; import { get } from '@ember/object'; +import { assign } from '@ember/polyfills'; /** @class Snapshot @@ -150,7 +148,7 @@ export default class Snapshot { @return {Object} All attributes of the current snapshot */ attributes() { - return copy(this._attributes); + return assign({}, this._attributes); } /** @@ -173,7 +171,7 @@ export default class Snapshot { for (let i=0, length = changedAttributeKeys.length; i < length; i++) { let key = changedAttributeKeys[i]; - changedAttributes[key] = copy(this._changedAttributes[key]); + changedAttributes[key] = this._changedAttributes[key].slice(); } return changedAttributes; diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 44ec7050193..f57a811e28c 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -3,12 +3,11 @@ */ import { A } from '@ember/array'; - -import { copy } from '@ember/object/internals'; import EmberError from '@ember/error'; import MapWithDefault from './map-with-default'; import { run as emberRun } from '@ember/runloop'; import { set, get, computed } from '@ember/object'; +import { assign } from '@ember/polyfills'; import { default as RSVP, Promise } from 'rsvp'; import Service from '@ember/service'; import { typeOf, isPresent, isNone } from '@ember/utils'; @@ -321,7 +320,7 @@ Store = Service.extend({ return emberRun.join(() => { return this._backburner.join(() => { let normalizedModelName = normalizeModelName(modelName); - let properties = copy(inputProperties) || Object.create(null); + let properties = assign({}, inputProperties); // If the passed properties do not include a primary key, // give the adapter an opportunity to generate one. Typically, diff --git a/tests/helpers/deep-copy.js b/tests/helpers/deep-copy.js new file mode 100644 index 00000000000..143c31d3dbc --- /dev/null +++ b/tests/helpers/deep-copy.js @@ -0,0 +1,54 @@ +/* global WeakMap */ +export default function deepCopy(obj) { + return _deepCopy(obj, new WeakMap()); +} + +function isPrimitive(value) { + return typeof value !== 'object' || value === null; +} + +function _deepCopy(oldObject, seen) { + if (Array.isArray(oldObject)) { + return copyArray(oldObject, seen); + } else if (!isPrimitive(oldObject)) { + return copyObject(oldObject, seen); + } else { + return oldObject; + } +} + +function copyObject(oldObject, seen) { + let newObject = {}; + + Object.keys(oldObject).forEach(key => { + let value = oldObject[key]; + let newValue = isPrimitive(value) ? value : seen.get(value); + + if (value && newValue === undefined) { + newValue = newObject[key] = _deepCopy(value, seen); + seen.set(value, newValue); + } + + newObject[key] = newValue; + }); + + return newObject; +} + +function copyArray(oldArray, seen) { + let newArray = []; + + for (let i = 0; i < oldArray.length; i++) { + let value = oldArray[i]; + let newValue = isPrimitive(value) ? value : seen.get(value); + + if (value && newValue === undefined) { + newValue = newArray[i] = _deepCopy(value, seen); + seen.set(value, newValue); + } + + newArray[i] = newValue; + } + + return newArray; +} diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index a2cacd1da63..e97535f32b1 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -1,8 +1,8 @@ import { decamelize, underscore } from '@ember/string'; -import { copy } from '@ember/object/internals'; import RSVP from 'rsvp'; import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; +import deepCopy from 'dummy/tests/helpers/deep-copy'; import { pluralize } from 'ember-inflector'; import { module, test } from 'qunit'; @@ -46,7 +46,7 @@ function ajaxResponse(value) { adapter.ajax = function(url, verb, hash) { passedUrl = url; - return run(RSVP, 'resolve', copy(value, true)); + return run(RSVP, 'resolve', deepCopy(value)); }; } diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index e5ac658334b..cdb94a18b74 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1,11 +1,10 @@ import { underscore } from '@ember/string'; -import { copy } from '@ember/object/internals'; import RSVP, { resolve, reject } from 'rsvp'; import { run } from '@ember/runloop'; import { get } from '@ember/object'; import setupStore from 'dummy/tests/helpers/store'; import { singularize } from 'ember-inflector'; - +import deepCopy from 'dummy/tests/helpers/deep-copy'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; @@ -56,7 +55,7 @@ function ajaxResponse(value) { passedVerb = verb; passedHash = hash; - return run(RSVP, 'resolve', copy(value, true)); + return run(RSVP, 'resolve', deepCopy(value)); }; } diff --git a/tests/integration/records/rematerialize-test.js b/tests/integration/records/rematerialize-test.js index 76dfdaba91c..19e72905cb6 100644 --- a/tests/integration/records/rematerialize-test.js +++ b/tests/integration/records/rematerialize-test.js @@ -1,12 +1,11 @@ /*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(adam|bob|dudu)" }]*/ import { run } from '@ember/runloop'; -import Ember from 'ember'; import setupStore from 'dummy/tests/helpers/store'; +import deepCopy from 'dummy/tests/helpers/deep-copy'; import { module, test } from 'qunit'; import DS from 'ember-data'; -const { copy } = Ember; const { attr, belongsTo, hasMany, Model } = DS; let env; @@ -173,9 +172,9 @@ test("an async has many relationship to an unloaded record can restore that reco let data; if (param === '1') { - data = copy(BOAT_ONE, true); + data = deepCopy(BOAT_ONE); } else if (param === '1') { - data = copy(BOAT_TWO, true); + data = deepCopy(BOAT_TWO); } else { throw new Error(`404: no such boat with id=${param}`); } @@ -208,8 +207,8 @@ test("an async has many relationship to an unloaded record can restore that reco run(() => { env.store.push({ data: [ - copy(BOAT_ONE, true), - copy(BOAT_TWO, true) + deepCopy(BOAT_ONE), + deepCopy(BOAT_TWO) ] }); }); diff --git a/tests/integration/relationships/json-api-links-test.js b/tests/integration/relationships/json-api-links-test.js index 7c094e7b4c3..d92ea3d1879 100644 --- a/tests/integration/relationships/json-api-links-test.js +++ b/tests/integration/relationships/json-api-links-test.js @@ -1,6 +1,5 @@ import { run } from '@ember/runloop'; import { get } from '@ember/object'; -import Ember from 'ember'; import { resolve } from 'rsvp'; import setupStore from 'dummy/tests/helpers/store'; import { @@ -9,8 +8,8 @@ import { import { module, test } from 'qunit'; import DS from 'ember-data'; import JSONAPIAdapter from "ember-data/adapters/json-api"; +import deepCopy from 'dummy/tests/helpers/deep-copy'; -const { copy } = Ember; const { Model, attr, hasMany, belongsTo } = DS; let env, User, Organisation; @@ -711,11 +710,11 @@ function shouldFetchLinkTests(description, payloads) { link === payloads.user.data.relationships.pets.links.related, 'We fetched the appropriate link' ); - return resolve(copy(payloads.pets, true)); + return resolve(deepCopy(payloads.pets)); }; // setup user - let user = run(() => store.push(copy(payloads.user, true))); + let user = run(() => store.push(deepCopy(payloads.user))); let pets = run(() => user.get('pets')); assert.ok(!!pets, 'We found our pets'); @@ -748,11 +747,11 @@ function shouldFetchLinkTests(description, payloads) { 'We fetched the appropriate link' ); } - return resolve(copy(payloads.pets, true)); + return resolve(deepCopy(payloads.pets)); }; // setup user - let user = run(() => store.push(copy(payloads.user, true))); + let user = run(() => store.push(deepCopy(payloads.user))); let pets = run(() => user.get('pets')); assert.ok(!!pets, 'We found our pets'); @@ -790,11 +789,11 @@ function shouldFetchLinkTests(description, payloads) { 'We fetched the appropriate link' ); } - return resolve(copy(payloads.home, true)); + return resolve(deepCopy(payloads.home)); }; // setup user - let user = run(() => store.push(copy(payloads.user, true))); + let user = run(() => store.push(deepCopy(payloads.user))); let home = run(() => user.get('home')); if (homeRelWasEmpty) { @@ -826,11 +825,11 @@ function shouldFetchLinkTests(description, payloads) { link === payloads.user.data.relationships.home.links.related, 'We fetched the appropriate link' ); - return resolve(copy(payloads.home, true)); + return resolve(deepCopy(payloads.home)); }; // setup user - let user = run(() => store.push(copy(payloads.user, true))); + let user = run(() => store.push(deepCopy(payloads.user))); let home = run(() => user.get('home')); assert.ok(!!home, 'We found our home'); @@ -996,12 +995,12 @@ function shouldReloadWithLinkTests(description, payloads) { link === payloads.user.data.relationships.pets.links.related, 'We fetched the appropriate link' ); - return resolve(copy(payloads.pets, true)); + return resolve(deepCopy(payloads.pets)); }; // setup user and pets - let user = run(() => store.push(copy(payloads.user, true))); - run(() => store.push(copy(payloads.pets, true))); + let user = run(() => store.push(deepCopy(payloads.user))); + run(() => store.push(deepCopy(payloads.pets))); let pets = run(() => user.get('pets')); assert.ok(!!pets, 'We found our pets'); @@ -1024,12 +1023,12 @@ function shouldReloadWithLinkTests(description, payloads) { link === payloads.user.data.relationships.pets.links.related, 'We fetched the appropriate link' ); - return resolve(copy(payloads.pets, true)); + return resolve(deepCopy(payloads.pets)); }; // setup user and pets - let user = run(() => store.push(copy(payloads.user, true))); - run(() => store.push(copy(payloads.pets, true))); + let user = run(() => store.push(deepCopy(payloads.user))); + run(() => store.push(deepCopy(payloads.pets))); let pets = run(() => user.get('pets')); assert.ok(!!pets, 'We found our pets'); @@ -1053,12 +1052,12 @@ function shouldReloadWithLinkTests(description, payloads) { link === payloads.user.data.relationships.home.links.related, 'We fetched the appropriate link' ); - return resolve(copy(payloads.home, true)); + return resolve(deepCopy(payloads.home)); }; // setup user and home - let user = run(() => store.push(copy(payloads.user, true))); - run(() => store.push(copy(payloads.home, true))); + let user = run(() => store.push(deepCopy(payloads.user))); + run(() => store.push(deepCopy(payloads.home))); let home = run(() => user.get('home')); assert.ok(!!home, 'We found our home'); @@ -1081,12 +1080,12 @@ function shouldReloadWithLinkTests(description, payloads) { link === payloads.user.data.relationships.home.links.related, 'We fetched the appropriate link' ); - return resolve(copy(payloads.home, true)); + return resolve(deepCopy(payloads.home)); }; // setup user - let user = run(() => store.push(copy(payloads.user, true))); - run(() => store.push(copy(payloads.home, true))); + let user = run(() => store.push(deepCopy(payloads.user))); + run(() => store.push(deepCopy(payloads.home))); let home; run(() => user.get('home').then(h => home = h)); @@ -1908,8 +1907,8 @@ test('We should not fetch a hasMany relationship with links that we know is empt }; // setup users - let user1 = run(() => store.push(copy(user1Payload, true))); - let user2 = run(() => store.push(copy(user2Payload, true))); + let user1 = run(() => store.push(deepCopy(user1Payload))); + let user2 = run(() => store.push(deepCopy(user2Payload))); // should not fire a request requestedUser = null; diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 4c787f80aad..489b0622520 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -1,4 +1,3 @@ -import { copy } from '@ember/object/internals'; import RSVP, { Promise as EmberPromise, resolve @@ -7,6 +6,7 @@ import { run, next } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import deepCopy from 'dummy/tests/helpers/deep-copy'; import { module, test } from 'qunit'; import DS from 'ember-data'; @@ -211,7 +211,7 @@ test("destroying the store correctly cleans everything up", function(assert) { function ajaxResponse(value) { env.adapter.ajax = function(url, verb, hash) { - return run(RSVP, 'resolve', copy(value, true)); + return run(RSVP, 'resolve', deepCopy(value)); }; } diff --git a/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js b/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js index f1a62e54ae3..f14a2e2ec18 100644 --- a/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js +++ b/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js @@ -1,8 +1,8 @@ import { run } from '@ember/runloop'; -import { copy } from '@ember/object/internals'; import { RelationshipPayloadsManager } from 'ember-data/-private'; import DS from 'ember-data'; import { createStore } from 'dummy/tests/helpers/store'; +import deepCopy from 'dummy/tests/helpers/deep-copy'; import { module, test } from 'qunit'; import testInDebug from '../../../helpers/test-in-debug'; @@ -45,7 +45,7 @@ test('push one side is polymorphic, baseType then subTypes', function(assert) { let id = 1; function makeHat(type, props) { - const resource = copy(props, true); + const resource = deepCopy(props); resource.id = `${id++}`; resource.type = type; resource.attributes.type = type; @@ -89,7 +89,7 @@ test('push one side is polymorphic, subType then baseType', function(assert) { let id = 1; function makeHat(type, props) { - const resource = copy(props, true); + const resource = deepCopy(props); resource.id = `${id++}`; resource.type = type; resource.attributes.type = type; @@ -130,7 +130,7 @@ test('push one side is polymorphic, different subtypes', function(assert) { let id = 1; function makeHat(type, props) { - const resource = copy(props, true); + const resource = deepCopy(props); resource.id = `${id++}`; resource.type = type; resource.attributes.type = type; @@ -177,7 +177,7 @@ test('push both sides are polymorphic', function(assert) { let id = 1; function makeHat(type, props) { - const resource = copy(props, true); + const resource = deepCopy(props); resource.id = `${id++}`; resource.type = type; resource.attributes.type = type; From 020c5e1ef04baba2030ef1c30954e451dfc0b34c Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 18 Apr 2018 00:22:08 -0700 Subject: [PATCH 2210/2527] [BUGFIX] ensure destroy-sync cleanup is correct --- tests/integration/records/unload-test.js | 87 +++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 1d4b628c809..13bbf8aab1f 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -518,6 +518,92 @@ test('unloadAll(type) does not leave stranded internalModels in relationships (r assert.ok(reloadedBoatInternalModel === initialBoatInternalModel, 'after an unloadAll, subsequent fetch results in the same InternalModel'); }); +test('(regression) unloadRecord followed by push in the same run-loop', function(assert) { + let { store } = env; + + let person = run(() => store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Could be Anybody' + }, + relationships: { + boats: { + data: [ + { type: 'boat', id: '1' } + ] + } + } + }, + included: [ + makeBoatOneForPersonOne() + ] + })); + + let boat = store.peekRecord('boat', '1'); + let initialBoatInternalModel = boat._internalModel; + let relationshipState = person.hasMany('boats').hasManyRelationship; + let knownPeople = env.store._internalModelsFor('person'); + let knownBoats = store._internalModelsFor('boat'); + + // ensure we loaded the people and boats + assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); + assert.equal(knownBoats.models.length, 1, 'one boat record is loaded'); + assert.equal(env.store.hasRecordForId('person', '1'), true); + assert.equal(env.store.hasRecordForId('boat', '1'), true); + + // ensure the relationship was established (we reach through the async proxy here) + let peopleBoats = run(() => person.get('boats.content')); + let boatPerson = run(() => boat.get('person.content')); + + assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should be 1'); + assert.equal(relationshipState.members.size, 1, 'members size should be 1'); + assert.ok(get(peopleBoats, 'length') === 1, 'Our person has a boat'); + assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat'); + assert.ok(boatPerson === person, 'Our boat has the right person'); + + run(() => boat.unloadRecord()); + + // ensure that our new state is correct + assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); + assert.equal(knownBoats.models.length, 1, 'one boat record is known'); + assert.ok(knownBoats.models[0] === initialBoatInternalModel, 'We still have our boat'); + assert.equal(initialBoatInternalModel.isEmpty(), true, 'Model is in the empty state'); + assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should still be 1'); + assert.equal(relationshipState.members.size, 1, 'members size should still be 1'); + assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats'); + + run(() => store.push({ + data: makeBoatOneForPersonOne() + })); + + let reloadedBoat = store.peekRecord('boat', '1'); + let reloadedBoatInternalModel = reloadedBoat._internalModel; + + assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should be 1'); + assert.equal(relationshipState.members.size, 1, 'members size should be 1'); + assert.ok(reloadedBoatInternalModel === initialBoatInternalModel, 'after an unloadRecord, subsequent fetch results in the same InternalModel'); + + // and now the kicker, run-loop fun! + // here, we will dematerialize the record, but push it back into the store + // all in the same run-loop! + // effectively this tests that our destroySync is not stupid + run(() => { + reloadedBoat.unloadRecord(); + store.push({ + data: makeBoatOneForPersonOne() + }); + }); + + let yaBoat = store.peekRecord('boat', '1'); + let yaBoatInternalModel = yaBoat._internalModel; + + assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should be 1'); + assert.equal(relationshipState.members.size, 1, 'members size should be 1'); + assert.ok(yaBoatInternalModel === initialBoatInternalModel, 'after an unloadRecord, subsequent same-loop push results in the same InternalModel'); +}); + test('unloading a disconnected subgraph clears the relevant internal models', function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; @@ -632,7 +718,6 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu }); }); - test('Unloading a record twice only schedules destroy once', function(assert) { const store = env.store; let record; From da4a36417b9d6881ea6e3119e617b51d9f698476 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 18 Apr 2018 14:30:52 -0700 Subject: [PATCH 2211/2527] implement fix --- addon/-private/system/model/internal-model.js | 12 ++++++---- .../system/relationships/state/has-many.js | 2 +- addon/-private/system/store.js | 23 +++++++++++++------ tests/integration/records/unload-test.js | 19 +++++++++------ 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 936a6385402..5244df8f305 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -141,7 +141,7 @@ export default class InternalModel { this._record = null; this._isDestroyed = false; this.isError = false; - this._isUpdatingRecordArrays = false; // used by the recordArrayManager + this._pendingRecordArrayManagerFlush = false; // used by the recordArrayManager // During dematerialization we don't want to rematerialize the record. The // reason this might happen is that dematerialization removes records from @@ -415,13 +415,15 @@ export default class InternalModel { } dematerializeRecord() { + this._isDematerializing = true; + if (this._record) { - this._isDematerializing = true; this._record.destroy(); - this.destroyRelationships(); - this.resetRecord(); } + // move to an empty never-loaded state + this.destroyRelationships(); + this.resetRecord(); this.updateRecordArrays(); } @@ -607,7 +609,7 @@ export default class InternalModel { destroy() { assert("Cannot destroy an internalModel while its record is materialized", !this._record || this._record.get('isDestroyed') || this._record.get('isDestroying')); - + this.isDestroying = true; this.store._internalModelDestroyed(this); this._relationships.forEach((name, rel) => rel.destroy()); diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 6a73365e369..dd0c1a29680 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -167,9 +167,9 @@ export default class ManyRelationship extends Relationship { } removeAllCanonicalInternalModelsFromOwn() { - super.removeAllCanonicalInternalModelsFromOwn(); this.canonicalMembers.clear(); this.canonicalState.splice(0, this.canonicalState.length); + super.removeAllCanonicalInternalModelsFromOwn(); } removeCompletelyFromOwn(internalModel) { diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index f57a811e28c..887b7c69244 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1103,15 +1103,20 @@ Store = Service.extend({ let internalModel = this._internalModelsFor(modelName).get(trueId); if (internalModel) { + // unloadRecord is async, if one attempts to unload + then sync push, + // we must ensure the unload is canceled before continuing + // The createRecord path will take _existingInternalModelForId() + // which will call `destroySync` instead for this unload + then + // sync createRecord scenario. Once we have true client-side + // delete signaling, we should never call destroySync if (internalModel.hasScheduledDestroy()) { - internalModel.destroySync(); - return this._buildInternalModel(modelName, trueId); - } else { - return internalModel; + internalModel.cancelDestroy(); } - } else { - return this._buildInternalModel(modelName, trueId); + + return internalModel; } + + return this._buildInternalModel(modelName, trueId); }, _internalModelDidReceiveRelationshipData(modelName, id, relationshipData) { @@ -2555,7 +2560,11 @@ Store = Service.extend({ if (internalModel && internalModel.hasScheduledDestroy()) { // unloadRecord is async, if one attempts to unload + then sync create, - // we must ensure the unload is complete before starting the create + // we must ensure the unload is complete before starting the create + // The push path will take _internalModelForId() + // which will call `cancelDestroy` instead for this unload + then + // sync push scenario. Once we have true client-side + // delete signaling, we should never call destroySync internalModel.destroySync(); internalModel = null; } diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 13bbf8aab1f..b3531d3cf7f 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -838,7 +838,7 @@ test('after unloading a record, the record can be fetched again immediately', fu assert.equal(record.isDestroying, true, 'the record is destroying'); assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are unloaded after unloadRecord'); return store.findRecord('person', '1').then(newRecord => { - assert.equal(internalModel.currentState.stateName, 'root.empty', 'the old internalModel is discarded'); + assert.ok(internalModel === newRecord._internalModel, 'the old internalModel is reused'); assert.equal(newRecord._internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded after findRecord'); }); }); @@ -857,7 +857,9 @@ test('after unloading a record, the record can be fetched again immediately (pur name: 'Adam Sunderland' }, relationships: { - cars: { data: null } + cars: { + data: [] + } } } }; @@ -876,7 +878,7 @@ test('after unloading a record, the record can be fetched again immediately (pur cars: { data: [ { - id: 1, + id: '1', type: 'car' } ] @@ -886,7 +888,7 @@ test('after unloading a record, the record can be fetched again immediately (pur included: [ { type: 'car', - id: 1, + id: '1', attributes: { make: 'jeep', model: 'wrangler' @@ -907,8 +909,8 @@ test('after unloading a record, the record can be fetched again immediately (pur assert.equal(internalModel.currentState.stateName, 'root.empty', 'Expected the previous internal model tobe unloaded'); return store.findRecord('person', '1').then(record => { - assert.equal(record.get('cars.length'), 0); - assert.equal(internalModel.currentState.stateName, 'root.empty', 'Expected the previous internal model to STILL be unloaded'); + assert.equal(record.get('cars.length'), 0, 'Expected relationship to be cleared by the new push'); + assert.ok(internalModel === record._internalModel, 'the old internalModel is reused'); assert.equal(record._internalModel.currentState.stateName, 'root.loaded.saved', 'Expected the NEW internal model to be loaded'); }); }); @@ -955,6 +957,7 @@ test('after unloading a record, the record can be fetched again immediately (wit }); const internalModel = record._internalModel; + const bike = store.peekRecord('bike', '1'); assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded initially'); assert.equal(record.get('bike.name'), 'mr bike'); @@ -965,10 +968,12 @@ test('after unloading a record, the record can be fetched again immediately (wit assert.equal(record.isDestroying, true, 'the record is destroying'); assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are unloaded after unloadRecord'); + let wait = store.findRecord('person', '1').then(newRecord => { assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); - assert.ok(newRecord.get('bike') === null, 'the newRecord should NOT have had a bike'); + assert.ok(newRecord.get('bike') === bike, 'the newRecord should retain knowledge of the bike'); }); + assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); return wait; }); From 9297ccc43378db51e3d4b5d23b60402ed8e835c8 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 17 Apr 2018 13:55:29 -0700 Subject: [PATCH 2212/2527] [CHORE] removes deprecated Store.filter feature --- addon/-private/index.js | 1 - addon/-private/system/record-array-manager.js | 172 +--- addon/-private/system/record-arrays.js | 2 - .../record-arrays/filtered-record-array.js | 67 -- addon/-private/system/store.js | 89 +- addon/index.js | 2 - tests/dummy/config/environment.js | 1 - .../integration/adapter/store-adapter-test.js | 54 -- tests/integration/filter-test.js | 804 ------------------ .../integration/record-array-manager-test.js | 165 ++-- .../adapter-populated-record-array-test.js | 22 +- .../record-arrays/peeked-records-test.js | 54 -- .../integration/records/delete-record-test.js | 40 - tests/integration/store-test.js | 8 - .../filtered-record-array-test.js | 90 -- tests/unit/store/adapter-interop-test.js | 6 +- tests/unit/store/asserts-test.js | 1 - 17 files changed, 128 insertions(+), 1450 deletions(-) delete mode 100644 addon/-private/system/record-arrays/filtered-record-array.js delete mode 100644 tests/integration/filter-test.js delete mode 100644 tests/unit/record-arrays/filtered-record-array-test.js diff --git a/addon/-private/index.js b/addon/-private/index.js index 9929693db86..4b948d24c4f 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -40,7 +40,6 @@ export { export { RecordArray, - FilteredRecordArray, AdapterPopulatedRecordArray } from './system/record-arrays'; diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index d8bd619bd8c..71b686dbee2 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -3,48 +3,33 @@ */ import { A } from '@ember/array'; - import { set, get } from '@ember/object'; import { run as emberRun } from '@ember/runloop'; +import { assert } from '@ember/debug'; +import cloneNull from './clone-null'; import { RecordArray, - FilteredRecordArray, AdapterPopulatedRecordArray -} from "./record-arrays"; - -import cloneNull from "./clone-null"; -import { assert } from '@ember/debug'; +} from './record-arrays'; const { _flush, - array_flatten, array_remove, create, createAdapterPopulatedRecordArray, - createFilteredRecordArray, createRecordArray, liveRecordArrayFor, - filteredRecordArraysFor, recordDidChange, - registerFilteredRecordArray, - unregisterRecordArray, - updateFilter, - updateFilterRecordArray + unregisterRecordArray } = heimdall.registerMonitor('recordArrayManager', '_flush', - 'array_fatten', 'array_remove', 'create', 'createAdapterPopulatedRecordArray', - 'createFilteredRecordArray', 'createRecordArray', 'liveRecordArrayFor', - 'filteredRecordArraysFor', 'recordDidChange', - 'registerFilteredRecordArray', - 'unregisterRecordArray', - 'updateFilter', - 'updateFilterRecordArray' + 'unregisterRecordArray' ); /** @@ -58,7 +43,6 @@ export default class RecordArrayManager { this.store = options.store; this.isDestroying = false; this.isDestroyed = false; - this._filteredRecordArrays = Object.create(null); this._liveRecordArrays = Object.create(null); this._pending = Object.create(null); this._adapterPopulatedRecordArrays = []; @@ -110,14 +94,6 @@ export default class RecordArrayManager { } } - // process filteredRecordArrays - if (this._filteredRecordArrays[modelName]) { - let recordArrays = this.filteredRecordArraysFor(modelName); - for (let i = 0; i < recordArrays.length; i++) { - this.updateFilterRecordArray(recordArrays[i], modelName, internalModels); - } - } - let array = this._liveRecordArrays[modelName]; if (array) { // TODO: skip if it only changed @@ -146,41 +122,6 @@ export default class RecordArrayManager { return updateLiveRecordArray(array, internalModels); } - /** - Update an individual filter. - - @private - @method updateFilterRecordArray - @param {DS.FilteredRecordArray} array - @param {String} modelName - @param {Array} internalModels - */ - updateFilterRecordArray(array, modelName, internalModels) { - heimdall.increment(updateFilterRecordArray); - - let filter = get(array, 'filterFunction'); - - let shouldBeInAdded = []; - let shouldBeRemoved = []; - - for (let i = 0; i < internalModels.length; i++) { - let internalModel = internalModels[i]; - if (internalModel.isHiddenFromRecordArrays() === false && - filter(internalModel.getRecord())) { - if (internalModel._recordArrays.has(array)) { continue; } - shouldBeInAdded.push(internalModel); - internalModel._recordArrays.add(array); - } else { - if (internalModel._recordArrays.delete(array)) { - shouldBeRemoved.push(internalModel); - } - } - } - - if (shouldBeInAdded.length > 0) { array._pushInternalModels(shouldBeInAdded); } - if (shouldBeRemoved.length > 0) { array._removeInternalModels(shouldBeRemoved); } - } - _syncLiveRecordArray(array, modelName) { assert(`recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); let pending = this._pending[modelName]; @@ -220,27 +161,6 @@ export default class RecordArrayManager { } } - /** - This method is invoked if the `filterFunction` property is - changed on a `DS.FilteredRecordArray`. - - It essentially re-runs the filter from scratch. This same - method is invoked when the filter is created in th first place. - - @method updateFilter - @param {Array} array - @param {String} modelName - @param {Function} filter - */ - updateFilter(array, modelName, filter) { - assert(`recordArrayManger.updateFilter expects modelName not modelClass as the second param, received ${modelName}`, typeof modelName === 'string'); - heimdall.increment(updateFilter); - let modelMap = this.store._internalModelsFor(modelName); - let internalModels = modelMap.models; - - this.updateFilterRecordArray(array, filter, internalModels); - } - _didUpdateAll(modelName) { let recordArray = this._liveRecordArrays[modelName]; if (recordArray) { @@ -288,21 +208,7 @@ export default class RecordArrayManager { } return visible; } - /** - Get the `DS.RecordArray` for a modelName, which contains all loaded records of - given modelName. - @method filteredRecordArraysFor - @param {String} modelName - @return {DS.RecordArray} - */ - filteredRecordArraysFor(modelName) { - assert(`recordArrayManger.filteredRecordArraysFor expects modelName not modelClass as the param`, typeof modelName === 'string'); - - heimdall.increment(filteredRecordArraysFor); - - return this._filteredRecordArrays[modelName] || (this._filteredRecordArrays[modelName] = []); - } /** Create a `DS.RecordArray` for a modelName. @@ -330,32 +236,6 @@ export default class RecordArrayManager { return array; } - /** - Create a `DS.FilteredRecordArray` for a modelName and register it for updates. - - @method createFilteredRecordArray - @param {String} modelName - @param {Function} filter - @param {Object} query (optional - @return {DS.FilteredRecordArray} - */ - createFilteredRecordArray(modelName, filter, query) { - assert(`recordArrayManger.createFilteredRecordArray expects modelName not modelClass as the first param, received ${modelName}`, typeof modelName === 'string'); - - heimdall.increment(createFilteredRecordArray); - let array = FilteredRecordArray.create({ - query, - modelName, - content: A(), - store: this.store, - manager: this, - filterFunction: filter - }); - - this.registerFilteredRecordArray(array, modelName, filter); - - return array; - } /** Create a `DS.AdapterPopulatedRecordArray` for a modelName with given query. @@ -399,25 +279,6 @@ export default class RecordArrayManager { return array; } - /** - Register a RecordArray for a given modelName to be backed by - a filter function. This will cause the array to update - automatically when records of that modelName change attribute - values or states. - - @method registerFilteredRecordArray - @param {DS.RecordArray} array - @param {String} modelName - @param {Function} filter - */ - registerFilteredRecordArray(array, modelName, filter) { - heimdall.increment(registerFilteredRecordArray); - assert(`recordArrayManger.registerFilteredRecordArray expects modelName not modelClass as the second param, received ${modelName}`, typeof modelName === 'string'); - - this.filteredRecordArraysFor(modelName).push(array); - this.updateFilter(array, modelName, filter); - } - /** Unregister a RecordArray. So manager will not update this array. @@ -430,14 +291,10 @@ export default class RecordArrayManager { let modelName = array.modelName; - // unregister filtered record array - let recordArrays = this.filteredRecordArraysFor(modelName); - let removedFromFiltered = remove(recordArrays, array); - // remove from adapter populated record array let removedFromAdapterPopulated = remove(this._adapterPopulatedRecordArrays, array); - if (!removedFromFiltered && !removedFromAdapterPopulated) { + if (!removedFromAdapterPopulated) { let liveRecordArrayForType = this._liveRecordArrays[modelName]; // unregister live record array @@ -450,7 +307,6 @@ export default class RecordArrayManager { } willDestroy() { - Object.keys(this._filteredRecordArrays).forEach(modelName => flatten(this._filteredRecordArrays[modelName]).forEach(destroy)); Object.keys(this._liveRecordArrays).forEach(modelName => this._liveRecordArrays[modelName].destroy()); this._adapterPopulatedRecordArrays.forEach(destroy); this.isDestroyed = true; @@ -466,18 +322,6 @@ function destroy(entry) { entry.destroy(); } -function flatten(list) { - heimdall.increment(array_flatten); - let length = list.length; - let result = []; - - for (let i = 0; i < length; i++) { - result = result.concat(list[i]); - } - - return result; -} - function remove(array, item) { heimdall.increment(array_remove); let index = array.indexOf(item); @@ -514,6 +358,10 @@ function updateLiveRecordArray(array, internalModels) { if (modelsToAdd.length > 0) { array._pushInternalModels(modelsToAdd); } if (modelsToRemove.length > 0) { array._removeInternalModels(modelsToRemove); } + + // return whether we performed an update. + // Necessary until 3.5 allows us to finish off ember-data-filter support. + return (modelsToAdd.length || modelsToRemove.length) > 0; } function removeFromAdapterPopulatedRecordArrays(internalModels) { diff --git a/addon/-private/system/record-arrays.js b/addon/-private/system/record-arrays.js index e5dd1375283..d65107ed72a 100644 --- a/addon/-private/system/record-arrays.js +++ b/addon/-private/system/record-arrays.js @@ -3,11 +3,9 @@ */ import RecordArray from "./record-arrays/record-array"; -import FilteredRecordArray from "./record-arrays/filtered-record-array"; import AdapterPopulatedRecordArray from "./record-arrays/adapter-populated-record-array"; export { RecordArray, - FilteredRecordArray, AdapterPopulatedRecordArray }; diff --git a/addon/-private/system/record-arrays/filtered-record-array.js b/addon/-private/system/record-arrays/filtered-record-array.js deleted file mode 100644 index 66ab0ff8016..00000000000 --- a/addon/-private/system/record-arrays/filtered-record-array.js +++ /dev/null @@ -1,67 +0,0 @@ -import { once } from '@ember/runloop'; -import { get, observer } from '@ember/object'; -import RecordArray from "./record-array"; - -/** - Represents a list of records whose membership is determined by the - store. As records are created, loaded, or modified, the store - evaluates them to determine if they should be part of the record - array. - - @class FilteredRecordArray - @namespace DS - @extends DS.RecordArray -*/ -export default RecordArray.extend({ - init() { - this._super(...arguments); - - this.set('filterFunction', this.get('filterFunction') || null); - this.isLoaded = true; - }, - /** - The filterFunction is a function used to test records from the store to - determine if they should be part of the record array. - - Example - - ```javascript - var allPeople = store.peekAll('person'); - allPeople.mapBy('name'); // ["Tom Dale", "Yehuda Katz", "Trek Glowacki"] - - var people = store.filter('person', function(person) { - if (person.get('name').match(/Katz$/)) { return true; } - }); - people.mapBy('name'); // ["Yehuda Katz"] - - var notKatzFilter = function(person) { - return !person.get('name').match(/Katz$/); - }; - people.set('filterFunction', notKatzFilter); - people.mapBy('name'); // ["Tom Dale", "Trek Glowacki"] - ``` - - @method filterFunction - @param {DS.Model} record - @return {Boolean} `true` if the record should be in the array - */ - - replace() { - throw new Error(`The result of a client-side filter (on ${this.modelName}) is immutable.`); - }, - - /** - @method updateFilter - @private - */ - _updateFilter() { - if (get(this, 'isDestroying') || get(this, 'isDestroyed')) { - return; - } - get(this, 'manager').updateFilter(this, this.modelName, get(this, 'filterFunction')); - }, - - updateFilter: observer('filterFunction', function() { - once(this, this._updateFilter); - }) -}); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index f57a811e28c..9fcda7acfbe 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1707,95 +1707,10 @@ Store = Service.extend({ } }, - /** - Takes a type and filter function, and returns a live RecordArray that - remains up to date as new records are loaded into the store or created - locally. - - The filter function takes a materialized record, and returns true - if the record should be included in the filter and false if it should - not. - - Example - - ```javascript - store.filter('post', function(post) { - return post.get('unread'); - }); - ``` - - The filter function is called once on all records for the type when - it is created, and then once on each newly loaded or created record. - - If any of a record's properties change, or if it changes state, the - filter function will be invoked again to determine whether it should - still be in the array. - - Optionally you can pass a query, which is the equivalent of calling - [query](#method_query) with that same query, to fetch additional records - from the server. The results returned by the server could then appear - in the filter if they match the filter function. - - The query itself is not used to filter records, it's only sent to your - server for you to be able to do server-side filtering. The filter - function will be applied on the returned results regardless. - - Example - - ```javascript - store.filter('post', { unread: true }, function(post) { - return post.get('unread'); - }).then(function(unreadPosts) { - unreadPosts.get('length'); // 5 - let unreadPost = unreadPosts.objectAt(0); - unreadPost.set('unread', false); - unreadPosts.get('length'); // 4 - }); - ``` - - @method filter - @private - @param {String} modelName - @param {Object} query optional query - @param {Function} filter - @param {Object} options optional, options to be passed to store.query - @return {DS.PromiseArray} - @deprecated - */ - filter(modelName, query, filter, options) { - assert(`You need to pass a model name to the store's filter method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - - if (!ENV.ENABLE_DS_FILTER) { - assert('The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', false); - } - - let promise; - let length = arguments.length; - let array; - let hasQuery = length >= 3; - - let normalizedModelName = normalizeModelName(modelName); - - // allow an optional server query - if (hasQuery) { - promise = this.query(normalizedModelName, query, options); - } else if (arguments.length === 2) { - filter = query; - } - - if (hasQuery) { - array = this.recordArrayManager.createFilteredRecordArray(normalizedModelName, filter, query); - } else { - array = this.recordArrayManager.createFilteredRecordArray(normalizedModelName, filter); - } - - promise = promise || Promise.resolve(array); - - return promiseArray(promise.then(() => array, null, `DS: Store#filter of ${normalizedModelName}`)); + filter() { + assert('The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', false); }, - // .............. // . PERSISTING . // .............. diff --git a/addon/index.js b/addon/index.js index 012352ad391..90968d071f1 100644 --- a/addon/index.js +++ b/addon/index.js @@ -30,7 +30,6 @@ import { PromiseObject, PromiseManyArray, RecordArray, - FilteredRecordArray, AdapterPopulatedRecordArray, ManyArray, RecordArrayManager, @@ -105,7 +104,6 @@ DS.Serializer = Serializer; DS.DebugAdapter = DebugAdapter; DS.RecordArray = RecordArray; -DS.FilteredRecordArray = FilteredRecordArray; DS.AdapterPopulatedRecordArray = AdapterPopulatedRecordArray; DS.ManyArray = ManyArray; diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index 41ca5779a8a..0d8efda6eee 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -15,7 +15,6 @@ module.exports = function(environment) { locationType: 'auto', EmberENV: { FEATURES: featureFlags, - ENABLE_DS_FILTER: true, RAISE_ON_DEPRECATION: false }, diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index f0fd2377618..2adefff5a95 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -881,46 +881,6 @@ test("can be created after the DS.Store", function(assert) { run(() => store.findRecord('person', 1)); }); -test("the filter method can optionally take a server query as well", function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - adapter.query = function(store, type, query, array) { - return resolve({ - data: [ - { - id: 1, - type: "person", - attributes: { - name: "Yehuda Katz" - } - }, - { - id: 2, - type: "person", - attributes: { - name: "Tom Dale" - } - } - ] - }); - }; - - return run(() => { - let asyncFilter = store.filter('person', { page: 1 }, data => { - return data.get('name') === "Tom Dale"; - }); - - let loadedFilter; - - return asyncFilter.then(filter => { - loadedFilter = filter; - return store.findRecord('person', 2); - }).then(tom => { - assert.equal(get(loadedFilter, 'length'), 1, "The filter has an item in it"); - assert.deepEqual(loadedFilter.toArray(), [tom], "The filter has a single entry in it"); - }); - }); -}); - test("relationships returned via `commit` do not trigger additional findManys", function(assert) { Person.reopen({ dogs: DS.hasMany('dog', { async: false }) @@ -1371,20 +1331,6 @@ test("store.query should pass adapterOptions to adapter.query ", function(assert }); }); -test("store.filter should pass adapterOptions to adapter.query", function(assert) { - assert.expect(2); - - env.adapter.query = function(store, type, query, array, options) { - assert.ok(!('adapterOptions' in query)); - assert.deepEqual(options.adapterOptions, { query: { embed: true } }); - return { data: [] }; - }; - - return run(() => { - return store.filter('person', {}, () => {}, { adapterOptions: { query: { embed: true } } }); - }); -}); - test("store.queryRecord should pass adapterOptions to adapter.queryRecord", function(assert) { assert.expect(2); diff --git a/tests/integration/filter-test.js b/tests/integration/filter-test.js deleted file mode 100644 index ac934cd9532..00000000000 --- a/tests/integration/filter-test.js +++ /dev/null @@ -1,804 +0,0 @@ -import { hash, all } from 'rsvp'; -import { set, get, computed } from '@ember/object'; -import { run } from '@ember/runloop'; -import setupStore from 'dummy/tests/helpers/store'; - -import { module, test } from 'qunit'; - -import DS from 'ember-data'; - -import customAdapter from 'dummy/tests/helpers/custom-adapter'; - -let store, env, data, recordArray; - -const Person = DS.Model.extend({ - name: DS.attr('string'), - bestFriend: DS.belongsTo('person', { inverse: null, async: false }), - upperName: computed('name', function() { - return this.get('name').toUpperCase(); - }).readOnly() -}); - -module('integration/filter - DS.Model updating', { - beforeEach() { - data = [ - { - id: '1', - type: 'person', - attributes: { - name: 'Scumbag Dale' - }, - relationships: { - bestFriend: { - data: { - id: '2', - type: 'person' - } - } - } - }, - { - id: '2', - type: 'person', - attributes: { - name: 'Scumbag Katz' - } - }, - { - id: '3', - type: 'person', - attributes: { - name: 'Scumbag Bryn' - } - } - ]; - - env = setupStore({ person: Person }); - store = env.store; - }, - - afterEach() { - edited = null; - data = null; - - run(store, 'destroy'); - } -}); - -function tapFn(fn, callback) { - const old_fn = fn; - - function new_fn() { - let result = old_fn.apply(this, arguments); - if (callback) { - callback.apply(fn, arguments); - } - new_fn.summary.called.push(arguments); - return result; - } - new_fn.summary = { called: [] }; - - return new_fn; -} - - -test('when a DS.Model updates its attributes, its changes affect its filtered Array membership', function(assert) { - run(() => store.push({ data })); - - let people = run(() => { - return store.filter('person', hash => { - if (hash.get('name').match(/Katz$/)) { - return true; - } - }); - }); - - assert.equal(get(people, 'length'), 1, 'precond - one item is in the RecordArray'); - - const person = people.objectAt(0); - - assert.equal(get(person, 'name'), 'Scumbag Katz', 'precond - the item is correct'); - - run(() => set(person, 'name', 'Yehuda Katz')); - - assert.equal(get(people, 'length'), 1, 'there is still one item'); - assert.equal(get(person, 'name'), 'Yehuda Katz', "it has the updated item"); - - run(() => set(person, 'name', 'Yehuda Katz-Foo')); - - assert.equal(get(people, 'query'), null, 'expected no query object set'); - assert.equal(get(people, 'length'), 0, 'there are now no items'); -}); - -test('when a DS.Model updates its relationships, its changes affect its filtered Array membership', function(assert) { - run(() => store.push({ data })); - - let people = run(() => { - return store.filter('person', person => { - if (person.get('bestFriend') && person.get('bestFriend.name').match(/Katz$/)) { - return true; - } - }); - }); - - run(() => assert.equal(get(people, 'length'), 1, 'precond - one item is in the RecordArray')); - - let person = people.objectAt(0); - - assert.equal(get(person, 'name'), 'Scumbag Dale', 'precond - the item is correct'); - - run(() => set(person, 'bestFriend', null)); - - assert.equal(get(people, 'length'), 0, 'there are now 0 items'); - - let erik = store.peekRecord('person', 3); - let yehuda = store.peekRecord('person', 2); - - run(() => erik.set('bestFriend', yehuda)); - - person = people.objectAt(0); - assert.equal(get(people, 'length'), 1, 'there is now 1 item'); - assert.equal(get(person, 'name'), 'Scumbag Bryn', 'precond - the item is correct'); -}); - -test('a record array can have a filter on it', function(assert) { - run(() => store.push({ data })); - - let recordArray = run(() => { - return store.filter('person', hash => { - if (hash.get('name').match(/Scumbag [KD]/)) { - return true; - } - }); - }); - - assert.equal(get(recordArray, 'length'), 2, 'The Record Array should have the filtered objects on it'); - - run(() => { - store.push({ - data: [{ - id: '4', - type: 'person', - attributes: { - name: 'Scumbag Koz' - } - }] - }); - }); - - assert.equal(get(recordArray, 'length'), 3, 'The Record Array should be updated as new items are added to the store'); - - run(() => { - store.push({ - data: [{ - id: '1', - type: 'person', - attributes: { - name: 'Scumbag Tom' - } - }] - }); - }); - - assert.equal(get(recordArray, 'length'), 2, 'The Record Array should be updated as existing members are updated'); -}); - -test('a filtered record array includes created elements', function(assert) { - run(() => store.push({ data })); - - let recordArray = run(() => { - return store.filter('person', hash => { - if (hash.get('name').match(/Scumbag [KD]/)) { - return true; - } - }); - }); - - assert.equal(get(recordArray, 'length'), 2, 'precond - The Record Array should have the filtered objects on it'); - - store.createRecord('person', { name: 'Scumbag Koz' }); - - assert.equal(get(recordArray, 'length'), 3, 'The record array has the new object on it'); -}); - -test('a Record Array can update its filter', function(assert) { - customAdapter(env, DS.Adapter.extend({ - deleteRecord(store, type, snapshot) { }, - shouldBackgroundReloadRecord() { return false; } - })); - - run(() => store.push({ data })); - - let dickens = run(() => { - let record = store.createRecord('person', { id: 4, name: 'Scumbag Dickens' }); - record.deleteRecord(); - return record; - }); - - let asyncData = run(() => { - return { - dale: store.findRecord('person', 1), - katz: store.findRecord('person', 2), - bryn: store.findRecord('person', 3) - }; - }); - - return store.filter('person', hash => { - if (hash.get('name').match(/Scumbag [KD]/)) { - return true; - } - }).then(recordArray => { - - return hash(asyncData).then(records => { - assert.contains(recordArray, records.dale); - assert.contains(recordArray, records.katz); - assert.without(recordArray, dickens); - assert.without(recordArray, records.bryn); - - run(() => { - recordArray.set('filterFunction', hash => { - if (hash.get('name').match(/Katz/)) { - return true; - } - }); - }); - - assert.equal(get(recordArray, 'length'), 1, 'The Record Array should have one object on it'); - - run(() => { - store.push({ - data: [{ - id: '5', - type: 'person', - attributes: { - name: 'Other Katz' - } - }] - }); - }); - - assert.equal(get(recordArray, 'length'), 2, 'The Record Array now has the new object matching the filter'); - - run(() => { - store.push({ - data: [{ - id: '6', - type: 'person', - attributes: { - name: 'Scumbag Demon' - } - }] - }); - }); - - assert.equal(get(recordArray, 'length'), 2, 'The Record Array doesn\'t have objects matching the old filter'); - }); - }); -}); - -test('a Record Array can update its filter and notify array observers', function(assert) { - customAdapter(env, DS.Adapter.extend({ - deleteRecord(store, type, snapshot) { }, - shouldBackgroundReloadRecord() { return false; } - })); - - run(() => store.push({ data })); - - let dickens = run(() => { - dickens = store.createRecord('person', { id: 4, name: 'Scumbag Dickens' }); - dickens.deleteRecord(); - return dickens; - }); - - let asyncData = run(() => { - return [ - store.findRecord('person', 1), - store.findRecord('person', 2), - store.findRecord('person', 3) - ]; - }); - - return store.filter('person', hash => { - if (hash.get('name').match(/Scumbag [KD]/)) { - return true; - } - }).then(recordArray => { - - let didChangeIdx; - let didChangeRemoved = 0; - let didChangeAdded = 0; - - let arrayObserver = { - arrayWillChange() { }, - - arrayDidChange(array, idx, removed, added) { - didChangeIdx = idx; - didChangeRemoved += removed; - didChangeAdded += added; - } - }; - - recordArray.addArrayObserver(arrayObserver); - - run(() => { - recordArray.set('filterFunction', hash => { - if (hash.get('name').match(/Katz/)) { - return true; - } - }); - }); - - return all(asyncData).then(() => { - assert.equal(didChangeRemoved, 1, 'removed one item from array'); - didChangeRemoved = 0; - - run(() => { - store.push({ - data: [{ - id: '5', - type: 'person', - attributes: { - name: 'Other Katz' - } - }] - }); - }); - - assert.equal(didChangeAdded, 1, 'one item was added'); - didChangeAdded = 0; - - assert.equal(recordArray.objectAt(didChangeIdx).get('name'), 'Other Katz'); - - run(() => { - store.push({ - data: [{ - id: '6', - type: 'person', - attributes: { - name: 'Scumbag Demon' - } - }] - }); - }); - - assert.equal(didChangeAdded, 0, 'did not get called when an object that doesn\'t match is added'); - - run(() => { - recordArray.set('filterFunction', hash => { - if (hash.get('name').match(/Scumbag [KD]/)) { - return true; - } - }); - }); - - assert.equal(didChangeAdded, 2, 'one item is added when going back'); - assert.equal(recordArray.objectAt(didChangeIdx).get('name'), 'Scumbag Dale'); - assert.equal(recordArray.objectAt(didChangeIdx+1).get('name'), 'Scumbag Demon'); - }); - }); -}); - -test('it is possible to filter by computed properties', function(assert) { - customAdapter(env, DS.Adapter.extend({ - shouldBackgroundReloadRecord: () => false - })); - - let filter = run(() => { - return store.filter('person', person => person.get('upperName') === 'TOM DALE'); - }); - - assert.equal(filter.get('length'), 0, 'precond - the filter starts empty'); - - run(() => { - store.push({ - data: [{ - id: '1', - type: 'person', - attributes: { - name: 'Tom Dale' - } - }] - }); - }); - - assert.equal(filter.get('length'), 1, 'the filter now has a record in it'); - - return store.findRecord('person', 1).then(person => { - run(() => { - person.set('name', 'Yehuda Katz'); - }); - - assert.equal(filter.get('length'), 0, 'the filter is empty again'); - }); -}); - -test('a filter created after a record is already loaded works', function(assert) { - customAdapter(env, DS.Adapter.extend({ - shouldBackgroundReloadRecord() { return false; } - })); - - run(() => { - store.push({ - data: [{ - id: '1', - type: 'person', - attributes: { - name: 'Tom Dale' - } - }] - }); - }); - - let filter = run(() => { - return store.filter('person', person => person.get('upperName') === 'TOM DALE'); - }); - - assert.equal(filter.get('length'), 1, 'the filter now has a record in it'); - - return store.findRecord('person', 1).then(person => { - assert.equal(filter.objectAt(0), person); - }); -}); - -test('filter with query persists query on the resulting filteredRecordArray', function(assert) { - customAdapter(env, DS.Adapter.extend({ - query(store, type, id) { - return { - data: [ - { - id: id, - type: 'person', - attributes: { - name: 'Tom Dale' - } - } - ] - }; - } - })); - - let filter = run(() => { - return store.filter('person', { foo: 1 }, person => true); - }); - - return run(() => { - return filter.then(array => { - assert.deepEqual(get(array, 'query'), { foo: 1 }, 'has expected query'); - }); - }); -}); - -test('it is possible to filter by state flags', function(assert) { - customAdapter(env, DS.Adapter.extend({ - findRecord(store, type, id, snapshot) { - return { - data: { - id, - type: 'person', - attributes: { - name: 'Tom Dale' - } - } - }; - } - })); - - let filter = run(() => { - return store.filter('person', person => person.get('isLoaded')); - }); - - assert.equal(filter.get('length'), 0, 'precond - there are no records yet'); - - let person = run(() => { - let person = store.findRecord('person', 1); - - // run will block `find` from being synchronously - // resolved in test mode - - assert.equal(filter.get('length'), 0, 'the unloaded record isn\'t in the filter'); - return person; - }); - - return person.then(person => { - assert.equal(filter.get('length'), 1, 'the now-loaded record is in the filter'); - assert.equal(filter.objectAt(0), person); - }); -}); - -test('it is possible to filter loaded records by dirtiness', function(assert) { - customAdapter(env, DS.Adapter.extend({ - updateRecord(type, model, snapshot) { - return { data: { id: snapshot.id, type: model.modelName } }; - }, - shouldBackgroundReloadRecord() { - return false; - } - })); - - let filter = store.filter('person', person => !person.get('hasDirtyAttributes')); - - run(() => { - store.push({ - data: [{ - id: '1', - type: 'person', - attributes: { - name: 'Tom Dale' - } - }] - }); - }); - - return store.findRecord('person', 1).then(person => { - assert.equal(filter.get('length'), 1, 'the clean record is in the filter'); - - // Force synchronous update of the filter, even though - // we're already inside a run loop - run(() => person.set('name', 'Yehuda Katz')); - - assert.equal(filter.get('length'), 0, 'the now-dirty record is not in the filter'); - - return person.save(); - }).then(person => { - assert.equal(filter.get('length'), 1, 'the clean record is back in the filter'); - }); -}); - -test('it is possible to filter created records by dirtiness', function(assert) { - run(() => { - customAdapter(env, DS.Adapter.extend({ - createRecord(type, model, snapshot) { - return { - data: { - id: snapshot.id, - type: model.modelName, - attributes: snapshot._attributes - } - } - }, - shouldBackgroundReloadRecord() { return false; } - })); - }); - - let filter = run(() => { - return store.filter('person', person => !person.get('hasDirtyAttributes')); - }); - - let person = store.createRecord('person', { - id: 1, - name: 'Tom Dale' - }); - - assert.equal(filter.get('length'), 0, 'the dirty record is not in the filter'); - - return run(() => { - return person.save().then(person => { - assert.equal(filter.get('length'), 1, 'the clean record is in the filter'); - }); - }); -}); - -// SERVER SIDE TESTS -let edited; - -function clientEdits(ids) { - edited = []; - - ids.forEach(id => { - // wrap in an run to guarantee coalescence of the - // iterated `set` calls and promise resolution. - run(() => { - store.findRecord('person', id).then(person => { - edited.push(person); - person.set('name', 'Client-side ' + id ); - }); - }); - }); -} - -function clientCreates(names) { - // wrap in an run to guarantee coalescence of the - // iterated `set` calls. - edited = names.map(name => store.createRecord('person', { name: 'Client-side ' + name })); -} - -function serverResponds() { - edited.forEach(person => run(person, 'save')); -} - -function setup(assert, serverCallbacks) { - customAdapter(env, DS.Adapter.extend(serverCallbacks)); - - run(() => { - store.push({ data }); - - recordArray = store.filter('person', hash => { - if (hash.get('name').match(/Scumbag/)) { - return true; - } - }); - }); - - assert.equal(get(recordArray, 'length'), 3, 'The filter function should work'); -} - -test('a Record Array can update its filter after server-side updates one record', function(assert) { - setup(assert, { - updateRecord(store, type, snapshot) { - return { - data: { - id: 1, - type: 'person', - attributes: { - name: 'Scumbag Server-side Dale' - } - } - }; - }, - shouldBackgroundReloadRecord() { return false; } - }); - - clientEdits([1]); - assert.equal(get(recordArray, 'length'), 2, 'The record array updates when the client changes records'); - - serverResponds(); - assert.equal(get(recordArray, 'length'), 3, 'The record array updates when the server changes one record'); -}); - -test('a Record Array can update its filter after server-side updates multiple records', function(assert) { - setup(assert, { - updateRecord(store, type, snapshot) { - switch (snapshot.id) { - case '1': - return { - data: { - id: 1, - type: 'person', - attributes: { - name: 'Scumbag Server-side Dale' - } - } - }; - case '2': - return { - data: { - id: 2, - type: 'person', - attributes: { - name: 'Scumbag Server-side Katz' - } - } - }; - } - }, - shouldBackgroundReloadRecord() { return false; } - }); - - clientEdits([1, 2]); - assert.equal(get(recordArray, 'length'), 1, 'The record array updates when the client changes records'); - - serverResponds(); - assert.equal(get(recordArray, 'length'), 3, 'The record array updates when the server changes multiple records'); -}); - -test('a Record Array can update its filter after server-side creates one record', function(assert) { - setup(assert, { - createRecord(store, type, snapshot) { - return { - data: { - id: 4, - type: 'person', - attributes: { - name: 'Scumbag Server-side Tim' - } - } - }; - } - }); - - clientCreates(['Tim']); - assert.equal(get(recordArray, 'length'), 3, 'The record array does not include non-matching records'); - - serverResponds(); - assert.equal(get(recordArray, 'length'), 4, 'The record array updates when the server creates a record'); -}); - -test('a Record Array can update its filter after server-side creates multiple records', function(assert) { - setup(assert, { - createRecord(store, type, snapshot) { - switch (snapshot.attr('name')) { - case 'Client-side Mike': - return { - data: { - id: 4, - type: 'person', - attributes: { - name: 'Scumbag Server-side Mike' - } - } - }; - case 'Client-side David': - return { - data: { - id: 5, - type: 'person', - attributes: { - name: 'Scumbag Server-side David' - } - } - }; - } - } - }); - - clientCreates(['Mike', 'David']); - assert.equal(get(recordArray, 'length'), 3, 'The record array does not include non-matching records'); - - serverResponds(); - assert.equal(get(recordArray, 'length'), 5, 'The record array updates when the server creates multiple records'); -}); - -test('a Record Array can update its filter after server-side creates multiple records', function(assert) { - setup(assert, { - createRecord(store, type, snapshot) { - switch (snapshot.attr('name')) { - case 'Client-side Mike': - return { - data: { - id: 4, - type: 'person', - attributes: { - name: 'Scumbag Server-side Mike' - } - } - }; - case 'Client-side David': - return { - data: { - id: 5, - type: 'person', - attributes: { - name: 'Scumbag Server-side David' - } - } - }; - } - } - }); - - clientCreates(['Mike', 'David']); - assert.equal(get(recordArray, 'length'), 3, 'The record array does not include non-matching records'); - - serverResponds(); - assert.equal(get(recordArray, 'length'), 5, 'The record array updates when the server creates multiple records'); -}); - -test('destroying filteredRecordArray unregisters models from being filtered', function(assert) { - const filterFn = tapFn(() => true); - - customAdapter(env, DS.Adapter.extend({ - shouldBackgroundReloadRecord() { return false; } - })); - - run(() => { - store.push({ - data: [{ - id: '1', - type: 'person', - attributes: { - name: 'Tom Dale' - } - }] - }); - }); - - const recordArray = run(() => store.filter('person', filterFn)); - - assert.equal(filterFn.summary.called.length, 1); - - run(() => recordArray.then(array => array.destroy())); - - clientEdits([1]); - - assert.equal(filterFn.summary.called.length, 1, 'expected the filter function not being called anymore'); -}); diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index 1be66ac461d..d46e0ea72a2 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -93,89 +93,30 @@ test('destroying the store correctly cleans everything up', function(assert) { person = store.peekRecord('person', 1); }); - let filterd = manager.createFilteredRecordArray('person', () => true); - let filterd2 = manager.createFilteredRecordArray('person', () => true); let all = store.peekAll('person'); let adapterPopulated = manager.createAdapterPopulatedRecordArray('person', query); - - let filterdSummary = tap(filterd, 'willDestroy'); - let filterd2Summary = tap(filterd2, 'willDestroy'); let allSummary = tap(all, 'willDestroy'); let adapterPopulatedSummary = tap(adapterPopulated, 'willDestroy'); - let internalPersonModel = person._internalModel; - assert.equal(filterdSummary.called.length, 0); - assert.equal(filterd2Summary.called.length, 0); assert.equal(allSummary.called.length, 0); assert.equal(adapterPopulatedSummary.called.length, 0); - - assert.equal(internalPersonModel._recordArrays.size, 3, 'expected the person to be a member of 3 recordArrays'); - - run(filterd2, filterd2.destroy); - - assert.equal(internalPersonModel._recordArrays.size, 2, 'expected the person to be a member of 2 recordArrays'); - assert.equal(filterd2Summary.called.length, 1); - + assert.equal(internalPersonModel._recordArrays.size, 1, 'expected the person to be a member of 1 recordArrays'); assert.equal('person' in manager._liveRecordArrays, true); run(all, all.destroy); - assert.equal(internalPersonModel._recordArrays.size, 1, 'expected the person to be a member of 1 recordArrays'); + assert.equal(internalPersonModel._recordArrays.size, 0, 'expected the person to be a member of 1 recordArrays'); assert.equal(allSummary.called.length, 1); assert.equal('person' in manager._liveRecordArrays, false); run(manager, manager.destroy); assert.equal(internalPersonModel._recordArrays.size, 0, 'expected the person to be a member of no recordArrays'); - assert.equal(filterdSummary.called.length, 1); - assert.equal(filterd2Summary.called.length, 1); assert.equal(allSummary.called.length, 1); assert.equal(adapterPopulatedSummary.called.length, 1); }); -test('Should not filter a store.peekAll() array when a record property is changed', function(assert) { - let updateLiveRecordArray = tap(store.recordArrayManager, 'updateLiveRecordArray'); - let updateFilterRecordArray = tap(store.recordArrayManager, 'updateFilterRecordArray'); - - let cars = store.peekAll('car'); - - assert.deepEqual(cars.toArray(), []); - - let car = run(() => { - store.push({ - data: { - type: 'car', - id: '1', - attributes: { - make: 'BMC', - model: 'Mini Cooper' - }, - relationships: { - person: { - data: { type: 'person', id: '1' } - } - } - } - }); - - return store.peekRecord('car', 1); - }); - - assert.deepEqual(cars.toArray(), [car], 'cars should contain [car]'); - - assert.equal(updateLiveRecordArray.called.length, 1, 'updateLiveRecordArray should be called 1 time'); - assert.equal(updateFilterRecordArray.called.length, 0, 'updateLiveRecordArray should be called 0 times'); - - run(() => car.set('model', 'Mini')); - - assert.deepEqual(cars.toArray(), [car], 'cars should contain [car]'); - - // TODO: differentiate between change + add/remove so we can skip non-filtered record arrays - assert.equal(updateLiveRecordArray.called.length, 2, 'updateLiveRecordArray should be called 2 times'); - assert.equal(updateFilterRecordArray.called.length, 0, 'updateFilterRecordArray should be called 0 times'); -}); - test('batch liveRecordArray changes', function(assert) { let cars = store.peekAll('car'); let arrayContentWillChangeCount = 0; @@ -358,3 +299,105 @@ test('liveRecordArrayFor create with content', function(assert) { manager.liveRecordArrayFor('car'); assert.equal(createRecordArrayCalled, 1, 'no new record array is created'); }); + +test('[DEPRECATED FILTER SUPPORT until 3.5]', function(assert) { + let cars = store.peekAll('car'); + let arrayContentWillChangeCount = 0; + let updatesWithoutLiveArrayChangeCount = 0; + let updatesSignaledCount = 0; + + let originalUpdate = store.recordArrayManager.updateLiveRecordArray; + store.recordArrayManager.updateLiveRecordArray = function(recordArray, internalModels) { + updatesSignaledCount++; + let didUpdate = originalUpdate.call(store.recordArrayManager, recordArray, internalModels); + + if (!didUpdate) { + updatesWithoutLiveArrayChangeCount++; + } + + return didUpdate; + }; + + cars.arrayContentWillChange = function() { + arrayContentWillChangeCount++; + }; + + assert.deepEqual(cars.toArray(), []); + assert.equal(arrayContentWillChangeCount, 0, 'expected NO arrayChangeEvents yet'); + assert.equal(updatesWithoutLiveArrayChangeCount, 0, 'expected NO silent updates yet'); + assert.equal(updatesSignaledCount, 0, 'expected NO signals yet'); + + let [car1, car2] = run(() => store.push({ + data: [ + { + type: 'car', + id: '1', + attributes: { + make: 'BMC', + model: 'Mini Cooper' + } + }, + { + type: 'car', + id: '2', + attributes: { + make: 'Jeep', + model: 'Wrangler' + } + } + ] + })); + + assert.equal(arrayContentWillChangeCount, 1, 'expected ONE array change event'); + assert.equal(updatesWithoutLiveArrayChangeCount, 0, 'expected NO silent updates yet'); + assert.equal(updatesSignaledCount, 1, 'expected ONE signal'); + assert.deepEqual(cars.toArray(), [car1, car2]); + + arrayContentWillChangeCount = 0; + updatesWithoutLiveArrayChangeCount = 0; + updatesSignaledCount = 0; + + run(() => car1.set('model', 'Mini')); + + assert.equal(arrayContentWillChangeCount, 0, 'expected no array change events'); + assert.equal(updatesWithoutLiveArrayChangeCount, 1, 'expected ONE silent update'); + assert.equal(updatesSignaledCount, 1, 'expected ONE total signals'); + + arrayContentWillChangeCount = 0; + updatesWithoutLiveArrayChangeCount = 0; + updatesSignaledCount = 0; + + run(() => store.push({ + data: { + type: 'car', + id: '2', // this ID is already present, array wont need to change + attributes: { + make: 'Tesla', + model: 'S' + } + } + })); + + assert.equal(arrayContentWillChangeCount, 0, 'expected NO array change events'); + assert.equal(updatesWithoutLiveArrayChangeCount, 1, 'expected ONE silent update'); + assert.equal(updatesSignaledCount, 1, 'expected ONE total signals'); + + arrayContentWillChangeCount = 0; + updatesWithoutLiveArrayChangeCount = 0; + updatesSignaledCount = 0; + + run(() => store.push({ + data: { + type: 'car', + id: '3', + attributes: { + make: 'Tesla', + model: 'S' + } + } + })); + + assert.equal(arrayContentWillChangeCount, 1, 'expected ONE array change event'); + assert.equal(updatesWithoutLiveArrayChangeCount, 0, 'expected ONE silent update'); + assert.equal(updatesSignaledCount, 1, 'expected ONE total signals'); +}); diff --git a/tests/integration/record-arrays/adapter-populated-record-array-test.js b/tests/integration/record-arrays/adapter-populated-record-array-test.js index 3797d6691e6..809c3e92ed7 100644 --- a/tests/integration/record-arrays/adapter-populated-record-array-test.js +++ b/tests/integration/record-arrays/adapter-populated-record-array-test.js @@ -270,7 +270,7 @@ test('loadRecord re-syncs internalModels recordArrays', function(assert) { test('when an adapter populated record gets updated the array contents are also updated', function(assert) { assert.expect(8); - let filteredPromise, filteredArr, findPromise, findArray; + let queryPromise, queryArr, findPromise, findArray; let env = setupStore({ person: Person }); let store = env.store; let array = [{ id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }]; @@ -287,14 +287,14 @@ test('when an adapter populated record gets updated the array contents are also }; run(() => { - filteredPromise = store.query('person', { slice: 1 }); + queryPromise = store.query('person', { slice: 1 }); findPromise = store.findAll('person'); // initialize adapter populated record array and assert initial state - filteredPromise.then((_filteredArr) => { - filteredArr = _filteredArr; - assert.equal(filteredArr.get('length'), 0, 'No records for this query'); - assert.equal(filteredArr.get('isUpdating'), false, 'Record array isUpdating state updated'); + queryPromise.then((_queryArr) => { + queryArr = _queryArr; + assert.equal(queryArr.get('length'), 0, 'No records for this query'); + assert.equal(queryArr.get('isUpdating'), false, 'Record array isUpdating state updated'); }); // initialize a record collection array and assert initial state @@ -307,9 +307,9 @@ test('when an adapter populated record gets updated the array contents are also // a new element gets pushed in record array run(() => { array.push({ id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } }); - filteredArr.update().then(() => { - assert.equal(filteredArr.get('length'), 1, 'The new record is returned and added in adapter populated array'); - assert.equal(filteredArr.get('isUpdating'), false, 'Record array isUpdating state updated'); + queryArr.update().then(() => { + assert.equal(queryArr.get('length'), 1, 'The new record is returned and added in adapter populated array'); + assert.equal(queryArr.get('isUpdating'), false, 'Record array isUpdating state updated'); assert.equal(findArray.get('length'), 2); }); }); @@ -317,8 +317,8 @@ test('when an adapter populated record gets updated the array contents are also // element gets removed run(() => { array.pop(0); - filteredArr.update().then(() => { - assert.equal(filteredArr.get('length'), 0, 'Record removed from array'); + queryArr.update().then(() => { + assert.equal(queryArr.get('length'), 0, 'Record removed from array'); // record not removed from the model collection assert.equal(findArray.get('length'), 2, 'Record still remains in collection array'); }); diff --git a/tests/integration/record-arrays/peeked-records-test.js b/tests/integration/record-arrays/peeked-records-test.js index f2a4af70fea..f8aa2431791 100644 --- a/tests/integration/record-arrays/peeked-records-test.js +++ b/tests/integration/record-arrays/peeked-records-test.js @@ -3,7 +3,6 @@ import { createStore } from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; import DS from 'ember-data'; import { get } from '@ember/object'; -import hasEmberVersion from 'ember-test-helpers/has-ember-version'; import { watchProperties } from '../../helpers/watch-property'; let store; @@ -376,56 +375,3 @@ test('push-without-materialize => unloadAll => push-without-materialize works as ); }); -test('unloading filtered records', function(assert) { - function push() { - run(() => { - store.push({ - data: [ - { - type: 'person', - id: '1', - attributes: { - name: 'Scumbag John' - } - }, - { - type: 'person', - id: '2', - attributes: { - name: 'Scumbag Joe' - } - } - ] - }); - }); - } - - let people = run(() => { - return store.filter('person', hash => { - if (hash.get('name').match(/Scumbag/)) { - return true; - } - }); - }); - - assert.equal(get(people, 'length'), 0, 'precond - no items in the RecordArray'); - - push(); - - assert.equal(get(people, 'length'), 2, 'precond - two items in the RecordArray'); - - run(() => { - people.objectAt(0).unloadRecord(); - - if (hasEmberVersion(3, 0)) { - assert.equal(get(people, 'length'), 2, 'Unload does not complete until the end of the loop'); - assert.equal(get(people.objectAt(0), 'name'), 'Scumbag John', 'John is still the first object until the end of the loop'); - } else { - assert.equal(get(people, 'length'), 2, 'Unload does not complete until the end of the loop'); - assert.equal(people.objectAt(0), undefined, 'John is still the first object until the end of the loop'); - } - }); - - assert.equal(get(people, 'length'), 1, 'Unloaded record removed from the array'); - assert.equal(get(people.objectAt(0), 'name'), 'Scumbag Joe', 'Joe shifted down after the unload'); -}); diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index e8749f50e6e..44e2fcd8462 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -177,46 +177,6 @@ test("records can be deleted during record array enumeration", function(assert) assert.equal(all.objectAt(0), null, "can't get any records"); }); -test("when deleted records are rolled back, they are still in their previous record arrays", function(assert) { - var jaime, cersei; - run(function() { - env.store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Jaime Lannister' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Cersei Lannister' - } - }] - }); - jaime = env.store.peekRecord('person', 1); - cersei = env.store.peekRecord('person', 2); - }); - var all = env.store.peekAll('person'); - var filtered; - run(function() { - filtered = env.store.filter('person', function () { - return true; - }); - }); - - assert.equal(all.get('length'), 2, 'precond - we start with two people'); - assert.equal(filtered.get('length'), 2, 'precond - we start with two people'); - - run(function() { - jaime.deleteRecord(); - jaime.rollbackAttributes(); - }); - assert.equal(all.get('length'), 2, 'record was not removed'); - assert.equal(filtered.get('length'), 2, 'record was not removed'); -}); - test("Deleting an invalid newly created record should remove it from the store", function(assert) { var record; var store = env.store; diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 489b0622520..50799070505 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -182,9 +182,6 @@ test("destroying the store correctly cleans everything up", function(assert) { }); }); - let filterdPeople = run(() => store.filter('person', () => true)); - - let filterdPeopleWillDestroy = tap(filterdPeople.get('content'), 'willDestroy'); let adapterPopulatedPeopleWillDestroy = tap(adapterPopulatedPeople.get('content'), 'willDestroy'); run(() => store.findRecord('person', 2)); @@ -193,10 +190,6 @@ test("destroying the store correctly cleans everything up", function(assert) { assert.equal(carWillDestroy.called.length, 0, 'expected car.willDestroy to not have been called'); assert.equal(carsWillDestroy.called.length, 0, 'expected cars.willDestroy to not have been called'); assert.equal(adapterPopulatedPeopleWillDestroy.called.length, 0, 'expected adapterPopulatedPeople.willDestroy to not have been called'); - assert.equal(filterdPeopleWillDestroy.called.length, 0, 'expected filterdPeople.willDestroy to not have been called'); - - assert.equal(filterdPeople.get('length'), 2, 'expected filterdPeople to have 2 entries'); - assert.equal(car.get('person'), person, "expected car's person to be the correct person"); assert.equal(person.get('cars.firstObject'), car, " expected persons cars's firstRecord to be the correct car"); @@ -206,7 +199,6 @@ test("destroying the store correctly cleans everything up", function(assert) { assert.equal(carWillDestroy.called.length, 1, 'expected car to recieve willDestroy once'); assert.equal(carsWillDestroy.called.length, 1, 'expected person.cars to recieve willDestroy once'); assert.equal(adapterPopulatedPeopleWillDestroy.called.length, 1, 'expected adapterPopulatedPeople to recieve willDestroy once'); - assert.equal(filterdPeopleWillDestroy.called.length, 1, 'expected filterdPeople.willDestroy to have been called once'); }); function ajaxResponse(value) { diff --git a/tests/unit/record-arrays/filtered-record-array-test.js b/tests/unit/record-arrays/filtered-record-array-test.js deleted file mode 100644 index bf25e22dd88..00000000000 --- a/tests/unit/record-arrays/filtered-record-array-test.js +++ /dev/null @@ -1,90 +0,0 @@ -import { run } from '@ember/runloop'; -import { A } from '@ember/array'; -import { get } from '@ember/object'; -import DS from 'ember-data'; - -import { module, test } from 'qunit'; - -const { FilteredRecordArray } = DS; - -module('unit/record-arrays/filtered-record-array - DS.FilteredRecordArray'); - -test('default initial state', function(assert) { - let recordArray = FilteredRecordArray.create({ modelName: 'recordType' }); - - assert.equal(get(recordArray, 'isLoaded'), true); - assert.equal(get(recordArray, 'modelName'), 'recordType'); - assert.strictEqual(get(recordArray, 'content'), null); - assert.strictEqual(get(recordArray, 'filterFunction'), null); - assert.strictEqual(get(recordArray, 'store'), null); -}); - -test('custom initial state', function(assert) { - let content = A(); - let store = {}; - let filterFunction = () => true; - let recordArray = FilteredRecordArray.create({ - modelName: 'apple', - isLoaded: false, // ignored - isUpdating: true, - content, - store, - filterFunction - }); - assert.equal(get(recordArray, 'isLoaded'), true); - assert.equal(get(recordArray, 'isUpdating'), false); // cannot set as default value: - assert.equal(get(recordArray, 'modelName'), 'apple'); - assert.equal(get(recordArray, 'content'), content); - assert.equal(get(recordArray, 'store'), store); - assert.equal(get(recordArray, 'filterFunction'), filterFunction); -}); - -test('#replace() throws error', function(assert) { - let recordArray = FilteredRecordArray.create({ modelName: 'recordType' }); - - assert.throws(() => { - recordArray.replace(); - }, Error('The result of a client-side filter (on recordType) is immutable.'), 'throws error'); -}); - -test('updateFilter', function(assert) { - let didUpdateFilter = 0; - const updatedFilterFunction = () => true; - - const manager = { - updateFilter(array, modelName, filterFunction) { - didUpdateFilter++; - assert.equal(recordArray, array); - assert.equal(modelName, 'recordType'); - assert.equal(filterFunction, updatedFilterFunction); - }, - unregisterRecordArray() {} - }; - - let recordArray = FilteredRecordArray.create({ - modelName: 'recordType', - manager, - content: A() - }); - - assert.equal(didUpdateFilter, 0, 'no filterFunction should have been changed yet'); - - run(() => { - recordArray.set('filterFunction', updatedFilterFunction); - assert.equal(didUpdateFilter, 0, 'record array manager should not yet be informed of the filterFunction change'); - recordArray.set('filterFunction', updatedFilterFunction); - assert.equal(didUpdateFilter, 0, 'record array manager should not yet be informed of the filterFunction change') - }); - - assert.equal(didUpdateFilter, 1, 'record array manager should have been informed once that the array filterFunction has changed'); - - didUpdateFilter = 0; - run(() => { - recordArray.set('filterFunction', updatedFilterFunction); - assert.equal(didUpdateFilter, 0, 'record array manager should not be informed of this change'); - recordArray.destroy(); - assert.equal(didUpdateFilter, 0, 'record array manager should not be informed of this change'); - }); - - assert.equal(didUpdateFilter, 0, 'record array manager should not be informed of this change'); -}); diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index 7f04382de6b..e2bd5b86b9d 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -8,26 +8,22 @@ import { set, get } from '@ember/object'; import { run } from '@ember/runloop'; import { createStore } from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; import DS from 'ember-data'; -let TestAdapter, store, oldFilterEnabled; +let TestAdapter, store; module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', { beforeEach() { TestAdapter = DS.Adapter.extend(); - oldFilterEnabled = Ember.ENV.ENABLE_DS_FILTER; - Ember.ENV.ENABLE_DS_FILTER = false; }, afterEach() { run(() => { if (store) { store.destroy(); } - Ember.ENV.ENABLE_DS_FILTER = oldFilterEnabled; }); } }); diff --git a/tests/unit/store/asserts-test.js b/tests/unit/store/asserts-test.js index c84fbb22637..a610a8298cc 100644 --- a/tests/unit/store/asserts-test.js +++ b/tests/unit/store/asserts-test.js @@ -15,7 +15,6 @@ const MODEL_NAME_METHODS = [ 'queryRecord', 'findAll', 'peekAll', - 'filter', 'modelFor', 'modelFactoryFor', 'normalize', From 88069026a7698db9f0d5f57469048f2919b7ccdf Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 18 Apr 2018 19:52:16 -0700 Subject: [PATCH 2213/2527] assert against IDs to catch more error cases --- tests/integration/records/unload-test.js | 28 ++++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index b3531d3cf7f..28589232515 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -7,6 +7,10 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; import setupStore from 'dummy/tests/helpers/store'; +function idsFromOrderedSet(set) { + return set.list.map(i => i.id); +} + const { attr, belongsTo, @@ -548,8 +552,8 @@ test('(regression) unloadRecord followed by push in the same run-loop', function let knownBoats = store._internalModelsFor('boat'); // ensure we loaded the people and boats - assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); - assert.equal(knownBoats.models.length, 1, 'one boat record is loaded'); + assert.deepEqual(knownPeople.models.map(m => m.id), ['1'], 'one person record is loaded'); + assert.deepEqual(knownBoats.models.map(m => m.id), ['1'], 'one boat record is loaded'); assert.equal(env.store.hasRecordForId('person', '1'), true); assert.equal(env.store.hasRecordForId('boat', '1'), true); @@ -557,8 +561,8 @@ test('(regression) unloadRecord followed by push in the same run-loop', function let peopleBoats = run(() => person.get('boats.content')); let boatPerson = run(() => boat.get('person.content')); - assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should be 1'); - assert.equal(relationshipState.members.size, 1, 'members size should be 1'); + assert.deepEqual(idsFromOrderedSet(relationshipState.canonicalMembers), ['1'], 'canonical member size should be 1'); + assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should be 1'); assert.ok(get(peopleBoats, 'length') === 1, 'Our person has a boat'); assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat'); assert.ok(boatPerson === person, 'Our boat has the right person'); @@ -566,12 +570,12 @@ test('(regression) unloadRecord followed by push in the same run-loop', function run(() => boat.unloadRecord()); // ensure that our new state is correct - assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); - assert.equal(knownBoats.models.length, 1, 'one boat record is known'); + assert.deepEqual(knownPeople.models.map(m => m.id), ['1'], 'one person record is loaded'); + assert.deepEqual(knownBoats.models.map(m => m.id), ['1'], 'one boat record is known'); assert.ok(knownBoats.models[0] === initialBoatInternalModel, 'We still have our boat'); assert.equal(initialBoatInternalModel.isEmpty(), true, 'Model is in the empty state'); - assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should still be 1'); - assert.equal(relationshipState.members.size, 1, 'members size should still be 1'); + assert.deepEqual(idsFromOrderedSet(relationshipState.canonicalMembers), ['1'], 'canonical member size should still be 1'); + assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should still be 1'); assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats'); run(() => store.push({ @@ -581,8 +585,8 @@ test('(regression) unloadRecord followed by push in the same run-loop', function let reloadedBoat = store.peekRecord('boat', '1'); let reloadedBoatInternalModel = reloadedBoat._internalModel; - assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should be 1'); - assert.equal(relationshipState.members.size, 1, 'members size should be 1'); + assert.deepEqual(idsFromOrderedSet(relationshipState.canonicalMembers), ['1'], 'canonical member size should be 1'); + assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should be 1'); assert.ok(reloadedBoatInternalModel === initialBoatInternalModel, 'after an unloadRecord, subsequent fetch results in the same InternalModel'); // and now the kicker, run-loop fun! @@ -599,8 +603,8 @@ test('(regression) unloadRecord followed by push in the same run-loop', function let yaBoat = store.peekRecord('boat', '1'); let yaBoatInternalModel = yaBoat._internalModel; - assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should be 1'); - assert.equal(relationshipState.members.size, 1, 'members size should be 1'); + assert.deepEqual(idsFromOrderedSet(relationshipState.canonicalMembers), ['1'], 'canonical member size should be 1'); + assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should be 1'); assert.ok(yaBoatInternalModel === initialBoatInternalModel, 'after an unloadRecord, subsequent same-loop push results in the same InternalModel'); }); From d3eacea34a2b372b8411c652351482649886317d Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 18 Apr 2018 21:39:36 -0700 Subject: [PATCH 2214/2527] [FEAT] play nice with route rehydration from shoebox --- addon/-private/system/store.js | 14 +++-- .../integration/adapter/rest-adapter-test.js | 62 +++++++++++-------- tests/unit/model-test.js | 5 +- 3 files changed, 49 insertions(+), 32 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 86d9014067c..7f1eff9f1dd 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -793,7 +793,7 @@ Store = Service.extend({ internalModel.loadingData(promise); if (this._pendingFetch.size === 0) { - emberRun.schedule('afterRender', this, this.flushAllPendingFetches); + emberRun.schedule('actions', this, this.flushAllPendingFetches); } this._pendingFetch.get(modelName).push(pendingFetchItem); @@ -872,9 +872,15 @@ Store = Service.extend({ } if (missingInternalModels.length) { - warn('Ember Data expected to find records with the following ids in the adapter response but they were missing: ' + inspect(missingInternalModels.map(r => r.id)), false, { - id: 'ds.store.missing-records-from-adapter' - }); + warn( + 'Ember Data expected to find records with the following ids in the adapter response but they were missing: [ "' + + missingInternalModels.map(r => r.id).join('", "') + + '" ]', + false, + { + id: 'ds.store.missing-records-from-adapter' + } + ); rejectInternalModels(missingInternalModels); } } diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index cdb94a18b74..61ca6b3f822 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -1918,40 +1918,48 @@ test('findBelongsTo - passes buildURL the requestType', function(assert) { }); testInDebug('coalesceFindRequests assert.warns if the expected records are not returned in the coalesced request', function(assert) { + assert.expect(2); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; - ajaxResponse({ comments: [{ id: 1 }] }); - - let wait; - assert.expectWarning(() => { - run(() => { - store.push({ - data: { - type: 'post', - id: '2', - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - } - }); + ajaxResponse({ + comments: [ + { id: '1', type: 'comment' } + ] + }); - let post = store.peekRecord('post', 2); - wait = post.get('comments').catch(e => { - assert.equal(e.message, `Expected: '' to be present in the adapter provided payload, but it was not found.`) - }) - }); + let post = run(() => store.push({ + data: { + type: 'post', + id: '2', + relationships: { + comments: { + data: [ + { type: 'comment', id: '1'}, + { type: 'comment', id: '2'}, + { type: 'comment', id: '3'} + ] + } + } + } + })); - return wait; - }, /expected to find records with the following ids in the adapter response but they were missing: \[2,3\]/); + assert.expectWarning( + () => { + return run(() => { + return post.get('comments') + .catch(e => { + assert.equal( + e.message, + `Expected: '' to be present in the adapter provided payload, but it was not found.` + ); + }); + }); + }, + /expected to find records with the following ids in the adapter response but they were missing: \[ "2", "3" \]/ + ); }); test('groupRecordsForFindMany groups records based on their url', function(assert) { diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index dc6cae9cd41..ca5bce0f05b 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -352,6 +352,9 @@ test('it should cache attributes', function(assert) { }); const store = createStore({ + adapter: DS.JSONAPIAdapter.extend({ + shouldBackgroundReloadRecord: () => false + }), post: Post }); @@ -366,7 +369,7 @@ test('it should cache attributes', function(assert) { } }); - return store.findRecord('post', 1).then(record => { + return store.findRecord('post', '1').then(record => { record.set('updatedAt', date); assert.deepEqual(date, get(record, 'updatedAt'), 'setting a date returns the same date'); From b4de0c271c50d50fe75373fb8ede04e4d3357be5 Mon Sep 17 00:00:00 2001 From: Michael Lange Date: Wed, 9 Aug 2017 13:19:05 -0700 Subject: [PATCH 2215/2527] Give Model a static toString method This changes the dreaded (unknown mixin) to something like model:person. --- addon/-private/system/model/model.js | 10 ++++++++++ tests/unit/model-test.js | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index b8a1c50a30b..32e96606dc4 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1860,6 +1860,16 @@ Model.reopenClass({ get(this, 'transformedAttributes').forEach((type, name) => { callback.call(binding, name, type); }); + }, + + /** + Returns the name of the model class. + + @method toString + @static + */ + toString() { + return `model:${get(this, 'modelName')}`; } }); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index ca5bce0f05b..6d2a57e8703 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -271,7 +271,7 @@ test("a record's id is included in its toString representation", function(assert }); return store.findRecord('person', 1).then(record => { - assert.equal(record.toString(), ``, 'reports id in toString'); + assert.equal(record.toString(), ``, 'reports id in toString'); }); }); }); From 13c4094e0bfade657fb66f4cb1a6f912330de24d Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Sat, 21 Apr 2018 21:40:33 -0700 Subject: [PATCH 2216/2527] fix rebase --- tests/unit/model-test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 6d2a57e8703..172d6f5468c 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -19,7 +19,6 @@ module('unit/model - DS.Model', { isDrugAddict: DS.attr('boolean'), isArchived: DS.attr() }); - Person.toString = () => 'person'; env = setupStore({ adapter: DS.JSONAPIAdapter, @@ -271,7 +270,7 @@ test("a record's id is included in its toString representation", function(assert }); return store.findRecord('person', 1).then(record => { - assert.equal(record.toString(), ``, 'reports id in toString'); + assert.equal(record.toString(), ``, 'reports id in toString'); }); }); }); From 4270054d73baf53baabe540a1b25d4c69feb13ed Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Sat, 21 Apr 2018 19:43:43 -0700 Subject: [PATCH 2217/2527] [CLEANUP BUGFIX] cleanup modelFor and modelFactoryFor codepaths --- addon/-private/system/model/internal-model.js | 4 +- .../system/record-arrays/record-array.js | 2 +- .../relationship-payloads-manager.js | 4 +- addon/-private/system/store.js | 261 +++++++++++------- addon/serializers/json-api.js | 2 +- addon/serializers/rest.js | 4 +- tests/integration/injection-test.js | 2 +- tests/unit/model-test.js | 22 +- tests/unit/store/asserts-test.js | 2 +- .../relationship-payload-manager-test.js | 8 +- 10 files changed, 179 insertions(+), 132 deletions(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 5244df8f305..61fda841a20 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -172,7 +172,7 @@ export default class InternalModel { } get modelClass() { - return this._modelClass || (this._modelClass = this.store._modelFor(this.modelName)); + return this._modelClass || (this._modelClass = this.store.modelFor(this.modelName)); } get type() { @@ -391,7 +391,7 @@ export default class InternalModel { createOptions.container = this.store.container; } - this._record = this.store.modelFactoryFor(this.modelName).create(createOptions); + this._record = this.store._modelFactoryFor(this.modelName).create(createOptions); this._triggerDeferredTriggers(); heimdall.stop(token); diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index 220e17f01d2..71d2ffdef1c 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -95,7 +95,7 @@ export default ArrayProxy.extend(Evented, { if (!this.modelName) { return null; } - return this.store._modelFor(this.modelName); + return this.store.modelFor(this.modelName); }).readOnly(), /** diff --git a/addon/-private/system/relationships/relationship-payloads-manager.js b/addon/-private/system/relationships/relationship-payloads-manager.js index f64e976fe0a..8bf9ce4d967 100644 --- a/addon/-private/system/relationships/relationship-payloads-manager.js +++ b/addon/-private/system/relationships/relationship-payloads-manager.js @@ -128,7 +128,7 @@ export default class RelationshipPayloadsManager { @method */ unload(modelName, id) { - let modelClass = this._store._modelFor(modelName); + let modelClass = this._store.modelFor(modelName); let relationshipsByName = get(modelClass, 'relationshipsByName'); relationshipsByName.forEach((_, relationshipName) => { let relationshipPayloads = this._getRelationshipPayloads(modelName, relationshipName, false); @@ -189,7 +189,7 @@ export default class RelationshipPayloadsManager { return cached; } - let modelClass = store._modelFor(modelName); + let modelClass = store.modelFor(modelName); let relationshipsByName = get(modelClass, 'relationshipsByName'); // CASE: We don't have a relationship at all diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 7f1eff9f1dd..d1dc9f34337 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -15,7 +15,7 @@ import { typeOf, isPresent, isNone } from '@ember/utils'; import Ember from 'ember'; import { InvalidError } from '../adapters/errors'; import { instrument } from 'ember-data/-debug'; -import { assert, warn, inspect } from '@ember/debug'; +import { assert, deprecate, warn, inspect } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; import Model from './model/model'; import normalizeModelName from "./normalize-model-name"; @@ -88,14 +88,11 @@ const { _generateId, _internalModelForId, _load, - _modelForMixin, _pushInternalModel, _setupRelationships, adapterFor, _buildInternalModel, _didUpdateAll, - modelFactoryFor, - modelFor, normalize, peekAll, peekRecord, @@ -105,14 +102,11 @@ const { '_generateId', '_internalModelForId', '_load', - '_modelForMixin', '_pushInternalModel', '_setupRelationships', 'adapterFor', '_buildInternalModel', '_didUpdateAll', - 'modelFactoryFor', - 'modelFor', 'normalize', 'peekAll', 'peekRecord', @@ -1924,49 +1918,23 @@ Store = Service.extend({ }, /* - In case someone defined a relationship to a mixin, for example: - ``` - let Comment = DS.Model.extend({ - owner: belongsTo('commentable'. { polymorphic: true }) - }); - let Commentable = Ember.Mixin.create({ - comments: hasMany('comment') - }); - ``` - we want to look up a Commentable class which has all the necessary - relationship metadata. Thus, we look up the mixin and create a mock - DS.Model, so we can access the relationship CPs of the mixin (`comments`) - in this case - + @deprecated @private - */ - _modelForMixin(normalizedModelName) { - heimdall.increment(_modelForMixin); - // container.registry = 2.1 - // container._registry = 1.11 - 2.0 - // container = < 1.11 - let owner = getOwner(this); - let mixin; - - if (owner.factoryFor) { - let MaybeMixin = owner.factoryFor(`mixin:${normalizedModelName}`); - mixin = MaybeMixin && MaybeMixin.class; - } else { - mixin = owner._lookupFactory(`mixin:${normalizedModelName}`); - } - - if (mixin) { - let ModelForMixin = Model.extend(mixin); - ModelForMixin.reopenClass({ - __isMixin: true, - __mixin: mixin - }); - - //Cache the class as a model - owner.register('model:' + normalizedModelName, ModelForMixin); - } + */ + _modelForMixin(modelName) { + deprecate( + '_modelForMixin is private and deprecated and should never be used directly, use modelFor instead', + false, + { + id: 'ember-data:_modelForMixin', + until: '3.5' + } + ); + assert(`You need to pass a model name to the store's _modelForMixin method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); - return this.modelFactoryFor(normalizedModelName); + return _modelForMixin(this, normalizedModelName); }, /** @@ -1985,68 +1953,71 @@ Store = Service.extend({ assert(`You need to pass a model name to the store's modelFor method`, isPresent(modelName)); assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - let normalizedModelName = normalizeModelName(modelName); + let maybeFactory = this._modelFactoryFor(modelName); - return this._modelFor(normalizedModelName); + // for factorFor factory/class split + return maybeFactory.class ? maybeFactory.class : maybeFactory; }, /* + @deprecated @private - */ + */ _modelFor(modelName) { - let maybeFactory = this._modelFactoryFor(modelName); - // for factorFor factory/class split - return maybeFactory.class ? maybeFactory.class : maybeFactory; + deprecate( + '_modelFor is private and deprecated, you should use modelFor instead', + false, + { + id: 'ember-data:_modelFor', + until: '3.5' + } + ); + return this.modelFor(modelName); }, _modelFactoryFor(modelName) { - heimdall.increment(modelFor); - let factory = this._modelFactoryCache[modelName]; - - if (!factory) { - factory = this.modelFactoryFor(modelName); - - if (!factory) { - //Support looking up mixins as base types for polymorphic relationships - factory = this._modelForMixin(modelName); - } - if (!factory) { - throw new EmberError(`No model was found for '${modelName}'`); - } - - // interopt with the future - let klass = getOwner(this).factoryFor ? factory.class : factory; - - assert(`'${inspect(klass)}' does not appear to be an ember-data model`, klass.isModel); - - // TODO: deprecate this - let hasOwnModelNameSet = klass.modelName && klass.hasOwnProperty('modelName'); - if (!hasOwnModelNameSet) { - klass.modelName = modelName; - } + assert(`You need to pass a model name to the store's _modelFactoryFor method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + let factory = getModelFactory(this, this._modelFactoryCache, normalizedModelName); - this._modelFactoryCache[modelName] = factory; + if (factory === null) { + throw new EmberError(`No model was found for '${normalizedModelName}'`); } return factory; }, /* - @private - */ + @deprecated + @private + */ modelFactoryFor(modelName) { - heimdall.increment(modelFactoryFor); - assert(`You need to pass a model name to the store's modelFactoryFor method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + deprecate('modelFactoryFor is private and deprecated', false, { + id: 'ember-data:modelFactoryFor', + until: '3.5' + }); + return this._modelFactoryFor(modelName); + }, + + /* + Returns whether a ModelClass exists for a given modelName + This exists for legacy support for the RESTSerializer, + which due to how it must guess whether a key is a model + must query for whether a match exists. + + We should investigate an RFC to make this public or removing + this requirement. + @private + */ + _hasModelFor(modelName) { + assert(`You need to pass a model name to the store's hasModelFor method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); let normalizedModelName = normalizeModelName(modelName); - let owner = getOwner(this); + let factory = getModelFactory(this, this._modelFactoryCache, normalizedModelName); - if (owner.factoryFor) { - return owner.factoryFor(`model:${normalizedModelName}`); - } else { - return owner._lookupFactory(`model:${normalizedModelName}`); - } + return factory !== null; }, /** @@ -2262,17 +2233,6 @@ Store = Service.extend({ return internalModelOrModels; }, - _hasModelFor(modelName) { - let owner = getOwner(this); - modelName = normalizeModelName(modelName); - - if (owner.factoryFor) { - return !!owner.factoryFor(`model:${modelName}`); - } else { - return !!owner._lookupFactory(`model:${modelName}`); - } - }, - _pushInternalModel(data) { heimdall.increment(_pushInternalModel); let modelName = data.type; @@ -2284,7 +2244,7 @@ Store = Service.extend({ // contains unknown attributes or relationships, log a warning. if (ENV.DS_WARN_ON_UNKNOWN_KEYS) { - let modelClass = this._modelFor(modelName); + let modelClass = this.modelFor(modelName); // Check unknown attributes let unknownAttributes = Object.keys(data.attributes || {}).filter((key) => { @@ -2443,7 +2403,7 @@ Store = Service.extend({ assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); let normalizedModelName = normalizeModelName(modelName); let serializer = this.serializerFor(normalizedModelName); - let model = this._modelFor(normalizedModelName); + let model = this.modelFor(normalizedModelName); return serializer.normalize(model, payload); }, @@ -2746,7 +2706,7 @@ function defaultSerializer(store) { function _commit(adapter, store, operation, snapshot) { let internalModel = snapshot._internalModel; let modelName = snapshot.modelName; - let modelClass = store._modelFor(modelName); + let modelClass = store.modelFor(modelName); assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter); assert(`You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`, typeof adapter[operation] === 'function'); @@ -2835,6 +2795,99 @@ function isInverseRelationshipInitialized(store, internalModel, data, key, model } } +/** + * + * @param store + * @param cache modelFactoryCache + * @param normalizedModelName already normalized modelName + * @returns {*} + */ +function getModelFactory(store, cache, normalizedModelName) { + let factory = cache[normalizedModelName]; + + if (!factory) { + factory = _lookupModelFactory(store, normalizedModelName); + + if (!factory) { + //Support looking up mixins as base types for polymorphic relationships + factory = _modelForMixin(store, normalizedModelName); + } + + if (!factory) { + // we don't cache misses in case someone wants to register a missing model + return null; + } + + // interopt with the future + let klass = getOwner(store).factoryFor ? factory.class : factory; + assert(`'${inspect(klass)}' does not appear to be an ember-data model`, klass.isModel); + + // TODO: deprecate this + let hasOwnModelNameSet = klass.modelName && klass.hasOwnProperty('modelName'); + if (!hasOwnModelNameSet) { + klass.modelName = normalizedModelName; + } + + cache[normalizedModelName] = factory; + } + + return factory; +} + +function _lookupModelFactory(store, normalizedModelName) { + let owner = getOwner(store); + + if (owner.factoryFor) { + return owner.factoryFor(`model:${normalizedModelName}`); + } else { + return owner._lookupFactory(`model:${normalizedModelName}`); + } +} + + +/* + In case someone defined a relationship to a mixin, for example: + ``` + let Comment = DS.Model.extend({ + owner: belongsTo('commentable'. { polymorphic: true }) + }); + let Commentable = Ember.Mixin.create({ + comments: hasMany('comment') + }); + ``` + we want to look up a Commentable class which has all the necessary + relationship metadata. Thus, we look up the mixin and create a mock + DS.Model, so we can access the relationship CPs of the mixin (`comments`) + in this case +*/ +function _modelForMixin(store, normalizedModelName) { + // container.registry = 2.1 + // container._registry = 1.11 - 2.0 + // container = < 1.11 + let owner = getOwner(store); + let mixin; + + if (owner.factoryFor) { + let MaybeMixin = owner.factoryFor(`mixin:${normalizedModelName}`); + mixin = MaybeMixin && MaybeMixin.class; + } else { + mixin = owner._lookupFactory(`mixin:${normalizedModelName}`); + } + + if (mixin) { + let ModelForMixin = Model.extend(mixin); + ModelForMixin.reopenClass({ + __isMixin: true, + __mixin: mixin + }); + + //Cache the class as a model + owner.register('model:' + normalizedModelName, ModelForMixin); + } + + return _lookupModelFactory(store, normalizedModelName); +} + function setupRelationships(store, internalModel, data, modelNameToInverseMap) { Object.keys(data.relationships).forEach(relationshipName => { let relationships = internalModel._relationships; diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 77c93fb7c1d..24f16827522 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -202,7 +202,7 @@ const JSONAPISerializer = JSONSerializer.extend({ return null; } - let modelClass = this.store._modelFor(modelName); + let modelClass = this.store.modelFor(modelName); let serializer = this.store.serializerFor(modelName); let { data } = serializer.normalize(modelClass, resourceHash); return data; diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 97e1085808e..84acff2610b 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -267,7 +267,7 @@ const RESTSerializer = JSONSerializer.extend({ } var typeName = this.modelNameFromPayloadKey(modelName); - if (!store.modelFactoryFor(typeName)) { + if (!store._hasModelFor(typeName)) { warn(this.warnMessageNoModelForKey(modelName, typeName), false, { id: 'ds.serializer.model-for-key-missing' }); @@ -395,7 +395,7 @@ const RESTSerializer = JSONSerializer.extend({ for (var prop in payload) { var modelName = this.modelNameFromPayloadKey(prop); - if (!store.modelFactoryFor(modelName)) { + if (!store._hasModelFor(modelName)) { warn(this.warnMessageNoModelForKey(prop, modelName), false, { id: 'ds.serializer.model-for-key-missing' }); diff --git a/tests/integration/injection-test.js b/tests/integration/injection-test.js index 81fda524348..9b7e72315c9 100644 --- a/tests/integration/injection-test.js +++ b/tests/integration/injection-test.js @@ -67,7 +67,7 @@ module('integration/injection factoryFor enabled', { }); test('modelFactoryFor', function(assert) { - const modelFactory = env.store.modelFactoryFor('super-villain'); + const modelFactory = env.store._modelFactoryFor('super-villain'); assert.equal(modelFactory, hasFactoryFor ? factory : model, 'expected the factory itself to be returned'); }); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 172d6f5468c..a3848aad1e1 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -261,18 +261,18 @@ test("a record's id is included in its toString representation", function(assert assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; - return run(() => { - store.push({ - data: { - type: 'person', - id: '1' - } - }); + let person = run(() => store.push({ + data: { + type: 'person', + id: '1' + } + })); - return store.findRecord('person', 1).then(record => { - assert.equal(record.toString(), ``, 'reports id in toString'); - }); - }); + assert.equal( + person.toString(), + ``, + 'reports id in toString' + ); }); testInDebug('trying to set an `id` attribute should raise', function(assert) { diff --git a/tests/unit/store/asserts-test.js b/tests/unit/store/asserts-test.js index a610a8298cc..279bd62dbc2 100644 --- a/tests/unit/store/asserts-test.js +++ b/tests/unit/store/asserts-test.js @@ -16,7 +16,7 @@ const MODEL_NAME_METHODS = [ 'findAll', 'peekAll', 'modelFor', - 'modelFactoryFor', + '_modelFactoryFor', 'normalize', 'adapterFor', 'serializerFor' diff --git a/tests/unit/system/relationships/relationship-payload-manager-test.js b/tests/unit/system/relationships/relationship-payload-manager-test.js index af7159f0291..196302302d1 100644 --- a/tests/unit/system/relationships/relationship-payload-manager-test.js +++ b/tests/unit/system/relationships/relationship-payload-manager-test.js @@ -36,15 +36,9 @@ module('unit/system/relationships/relationship-payloads-manager', { }); test('get throws for invalid models', function(assert) { - this.relationshipPayloadsManager._store._modelFor = (name) => { - if (name === 'fish') { - throw new Error('What is fish?'); - } - }; - assert.throws(() => { this.relationshipPayloadsManager.get('fish', 9, 'hobbies'); - }, /What is fish/); + }, /No model was found for 'fish'/); }); test('get returns null for invalid relationships', function(assert) { From 34aef620f6dc8a4e133da2968fbb2b2325e10a9a Mon Sep 17 00:00:00 2001 From: Bryan Date: Fri, 10 Mar 2017 01:23:00 +0000 Subject: [PATCH 2218/2527] Optimise has many notifications (#4850) * optimise has-many notifications * bring in line with master * bring in line with master * exit flushCanonical early if not alive * add test for non contiguous change * niggles * jshint fix optimise changes to hasMany 10x improvement with 5000 records add comments optimise fixing up relationships that have been edited since the last canonical flush clear _removedRecords every time --- addon/-private/system/diff-array.js | 1 + .../system/relationships/state/has-many.js | 85 +++++++++++-- .../records/relationship-changes-test.js | 118 ++++++++---------- tests/unit/diff-array-test.js | 1 - .../unit/model/relationships/has-many-test.js | 27 ++-- 5 files changed, 139 insertions(+), 93 deletions(-) diff --git a/addon/-private/system/diff-array.js b/addon/-private/system/diff-array.js index ae28e8e35b3..34955e3e282 100644 --- a/addon/-private/system/diff-array.js +++ b/addon/-private/system/diff-array.js @@ -2,6 +2,7 @@ @namespace @method diffArray @private + @for DS @param {Array} oldArray the old array @param {Array} newArray the new array @return {hash} { diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index dd0c1a29680..5b243aaaaf4 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -5,6 +5,8 @@ import Relationship from './relationship'; import OrderedSet from '../../ordered-set'; import ManyArray from '../../many-array'; +import diffArray from '../../diff-array'; + export default class ManyRelationship extends Relationship { constructor(store, internalModel, inverseKey, relationshipMeta) { super(store, internalModel, inverseKey, relationshipMeta); @@ -19,6 +21,7 @@ export default class ManyRelationship extends Relationship { this._loadingPromise = null; this._willUpdateManyArray = false; this._pendingManyArrayUpdates = null; + this._removedInternalModels = null; } _updateLoadingPromise(promise, content) { @@ -203,6 +206,11 @@ export default class ManyRelationship extends Relationship { if (!this.members.has(internalModel)) { return; } + // remember removals so we can deal with them in computeChanges + if (!this._removedInternalModels) { + this._removedInternalModels = new OrderedSet(); + } + this._removedInternalModels.add(internalModel); super.removeInternalModelFromOwn(internalModel, idx); // note that ensuring the many array is created, via `this.manyArray` // (instead of `this._manyArray`) is intentional. @@ -266,22 +274,75 @@ export default class ManyRelationship extends Relationship { } computeChanges(internalModels = []) { - let members = this.canonicalMembers; - let internalModelsToRemove = []; - let internalModelSet = setForArray(internalModels); - - members.forEach(member => { - if (internalModelSet.has(member)) { return; } + let members = this.canonicalMembers.toArray(); + let removedSinceLastTime = this._removedInternalModels; + this._removedInternalModels = null; // clear it for next time + + let diff = diffArray(members, internalModels); + + if (diff.firstChangeIndex === null) { + // no changes found + if (removedSinceLastTime) { + // records that have been removed since last compute will need their inverses to be corrected + for (let i = 0, l = internalModels.length; i < l; i++) { + let record = internalModels[i]; + if (removedSinceLastTime.has(record)) { + this.flushCanonicalLater(); + break; + } + } + } + return; + } + let removedMembersSet = setForArray(members.slice(diff.firstChangeIndex, diff.firstChangeIndex + diff.removedCount)); + let changeBlockSet = setForArray(internalModels.slice(diff.firstChangeIndex, diff.firstChangeIndex + diff.addedCount)); - internalModelsToRemove.push(member); + // remove members that were removed but not re-added + removedMembersSet.forEach(member => { + if (!changeBlockSet.has(member)) { + this.removeCanonicalInternalModel(member); + } }); - this.removeCanonicalInternalModels(internalModelsToRemove); + let flushCanonicalLater = false; + + // --- deal with records before the change block + if (removedSinceLastTime) { + // records that have been removed since last compute will need their inverses to be corrected + for (let i = 0; i < diff.firstChangeIndex; i++) { + let record = internalModels[i]; + if (removedSinceLastTime.has(record)) { + flushCanonicalLater = true; + break; + } + } + } + // --- deal with records in the change block + for (let i = diff.firstChangeIndex, l = diff.firstChangeIndex + diff.addedCount; i < l; i++) { + let record = internalModels[i]; + if (members[i] !== record) { + if (removedMembersSet.has(record)) { + // this is a reorder + this.removeCanonicalInternalModel(record); + } + // reorder or insert + this.addCanonicalInternalModel(record, i); + } + } + // --- deal with records after the change block + if (!flushCanonicalLater && removedSinceLastTime) { + // records that have been removed since last compute will need their inverses to be corrected + for (let i = diff.firstChangeIndex + diff.addedCount, l = internalModels.length; i < l; i++) { + let record = internalModels[i]; + if (removedSinceLastTime.has(record)) { + flushCanonicalLater = true; + break; + } + } + } - for (let i = 0, l = internalModels.length; i < l; i++) { - let internalModel = internalModels[i]; - this.removeCanonicalInternalModel(internalModel); - this.addCanonicalInternalModel(internalModel, i); + if (flushCanonicalLater) { + this.flushCanonicalLater(); } } diff --git a/tests/integration/records/relationship-changes-test.js b/tests/integration/records/relationship-changes-test.js index 5547164a3d2..871093ec9fc 100644 --- a/tests/integration/records/relationship-changes-test.js +++ b/tests/integration/records/relationship-changes-test.js @@ -2,7 +2,6 @@ import { alias } from '@ember/object/computed'; import { run } from '@ember/runloop'; import EmberObject, { set, get } from '@ember/object'; import setupStore from 'dummy/tests/helpers/store'; - import DS from 'ember-data'; import { module, test } from 'qunit'; @@ -533,32 +532,26 @@ test('Calling push with relationship triggers willChange and didChange with deta } }; - run(() => { - store.push({ - data: { - type: 'person', - id: 'wat', - attributes: { - firstName: 'Yehuda', - lastName: 'Katz' - }, - relationships: { - siblings: { - data: [sibling1Ref] - } - } + let person = run(() => store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' }, - included: [ - sibling1 - ] - - }); - }); - + relationships: { + siblings: { + data: [sibling1Ref] + } + } + }, + included: [ + sibling1 + ] + })); - let person = store.peekRecord('person', 'wat'); let siblings = run(() => person.get('siblings')); - siblings.addArrayObserver(observer); run(() => { @@ -589,31 +582,26 @@ test('Calling push with relationship triggers willChange and didChange with deta test('Calling push with relationship triggers willChange and didChange with detail when truncating', function(assert) { let willChangeCount = 0; let didChangeCount = 0; - - run(() => { - store.push({ - data: { - type: 'person', - id: 'wat', - attributes: { - firstName: 'Yehuda', - lastName: 'Katz' - }, - relationships: { - siblings: { - data: [sibling1Ref, sibling2Ref] - } - } + let person = run(() => store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' }, - included: [ - sibling1, sibling2 - ] - }); - }); + relationships: { + siblings: { + data: [sibling1Ref, sibling2Ref] + } + } + }, + included: [ + sibling1, sibling2 + ] + })); - let person = store.peekRecord('person', 'wat'); let siblings = run(() => person.get('siblings')); - let observer = { arrayWillChange(array, start, removing, adding) { willChangeCount++; @@ -658,28 +646,24 @@ test('Calling push with relationship triggers willChange and didChange with deta test('Calling push with relationship triggers willChange and didChange with detail when inserting at front', function(assert) { let willChangeCount = 0; let didChangeCount = 0; - - run(() => { - store.push({ - data: { - type: 'person', - id: 'wat', - attributes: { - firstName: 'Yehuda', - lastName: 'Katz' - }, - relationships: { - siblings: { - data: [sibling2Ref] - } - } + let person = run(() => store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' }, - included: [ - sibling2 - ] - }); - }); - let person = store.peekRecord('person', 'wat'); + relationships: { + siblings: { + data: [sibling2Ref] + } + } + }, + included: [ + sibling2 + ] + })); let observer = { arrayWillChange(array, start, removing, adding) { diff --git a/tests/unit/diff-array-test.js b/tests/unit/diff-array-test.js index a226a2ffd07..7dc8f889b3a 100644 --- a/tests/unit/diff-array-test.js +++ b/tests/unit/diff-array-test.js @@ -1,5 +1,4 @@ import { module, test } from 'qunit'; - import { diffArray } from 'ember-data/-private'; module('unit/diff-array Diff Array tests', { diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 29bbbae7138..7f7e835bedc 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -1611,7 +1611,7 @@ test('hasMany.firstObject.unloadRecord should not break that hasMany', function( the parent record's hasMany is a situation in which this limitation will be encountered should other local changes to the relationship still exist. */ -test('[ASSERTS KNOWN LIMITATION STILL EXISTS] returning new hasMany relationship info from a delete clears local state', function(assert) { +test('returning new hasMany relationship info from a delete maintains a local addition', function(assert) { assert.expect(4); const Person = DS.Model.extend({ @@ -1642,7 +1642,7 @@ test('[ASSERTS KNOWN LIMITATION STILL EXISTS] returning new hasMany relationship relationships: { pets: { data: [ - { type: 'pet', id: '2' } + { type: 'pet', id: 'server-known-2' } ] } } @@ -1664,8 +1664,8 @@ test('[ASSERTS KNOWN LIMITATION STILL EXISTS] returning new hasMany relationship relationships: { pets: { data: [ - { type: 'pet', id: '1' }, - { type: 'pet', id: '2' } + { type: 'pet', id: 'will-destroy-1' }, + { type: 'pet', id: 'server-known-2' } ] } } @@ -1673,21 +1673,21 @@ test('[ASSERTS KNOWN LIMITATION STILL EXISTS] returning new hasMany relationship included: [ { type: 'pet', - id: '1', + id: 'will-destroy-1', attributes: { name: 'Shenanigans' } }, { type: 'pet', - id: '2', + id: 'server-known-2', attributes: { name: 'Rambunctious' } }, { type: 'pet', - id: '3', + id: 'local-3', attributes: { name: 'Rebel' } @@ -1699,25 +1699,26 @@ test('[ASSERTS KNOWN LIMITATION STILL EXISTS] returning new hasMany relationship const person = store.peekRecord('person', '1'); const pets = run(() => person.get('pets')); - const shen = store.peekRecord('pet', '1'); - const rebel = store.peekRecord('pet', '3'); + const shen = store.peekRecord('pet', 'will-destroy-1'); + const rebel = store.peekRecord('pet', 'local-3'); assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); - assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2'], 'precond - relationship has the correct pets to start'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['will-destroy-1', 'server-known-2'], 'precond - relationship has the correct pets to start'); + // add a new item locally run(() => { pets.pushObjects([rebel]); }); - assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2', '3'], 'precond2 - relationship now has the correct three pets'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['will-destroy-1', 'server-known-2', 'local-3'], 'precond2 - relationship now has the correct three pets'); return run(() => { return shen.destroyRecord({}) .then(() => { shen.unloadRecord(); - // were ember-data to now preserve local edits during a relationship push, this would be '2' - assert.deepEqual(pets.map(p => get(p, 'id')), ['2'], 'relationship now has only one pet, we lost the local change'); + // were ember-data to not preserve local edits during a relationship push, this would be 'server-known-2' + assert.deepEqual(pets.map(p => get(p, 'id')), ['server-known-2', 'local-3'], 'relationship now has only one pet, we kept the local change'); }); }); }); From ff8ae3c364dbb9be3e575cc82e17c97b08b2f7e7 Mon Sep 17 00:00:00 2001 From: "Andrey Mikhaylov (lolmaus)" Date: Tue, 24 Apr 2018 15:53:28 +0300 Subject: [PATCH 2219/2527] Fix `_reloadRecord` method name in JSDoc --- addon/-private/system/store.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index d1dc9f34337..13aaccffb42 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1029,10 +1029,10 @@ Store = Service.extend({ This method is called by the record's `reload` method. This method calls the adapter's `find` method, which returns a promise. When - **that** promise resolves, `reloadRecord` will resolve the promise returned + **that** promise resolves, `_reloadRecord` will resolve the promise returned by the record's `reload`. - @method reloadRecord + @method _reloadRecord @private @param {DS.Model} internalModel @param options optional to include adapterOptions From a0884bd06883fbefed93fb76453abf1221965304 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 24 Apr 2018 18:04:34 -0700 Subject: [PATCH 2220/2527] Revert "Optimise has many notifications (#4850)" This reverts commit 34aef620f6dc8a4e133da2968fbb2b2325e10a9a. --- addon/-private/system/diff-array.js | 1 - .../system/relationships/state/has-many.js | 85 ++----------- .../records/relationship-changes-test.js | 118 ++++++++++-------- tests/unit/diff-array-test.js | 1 + .../unit/model/relationships/has-many-test.js | 27 ++-- 5 files changed, 93 insertions(+), 139 deletions(-) diff --git a/addon/-private/system/diff-array.js b/addon/-private/system/diff-array.js index 34955e3e282..ae28e8e35b3 100644 --- a/addon/-private/system/diff-array.js +++ b/addon/-private/system/diff-array.js @@ -2,7 +2,6 @@ @namespace @method diffArray @private - @for DS @param {Array} oldArray the old array @param {Array} newArray the new array @return {hash} { diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 5b243aaaaf4..dd0c1a29680 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -5,8 +5,6 @@ import Relationship from './relationship'; import OrderedSet from '../../ordered-set'; import ManyArray from '../../many-array'; -import diffArray from '../../diff-array'; - export default class ManyRelationship extends Relationship { constructor(store, internalModel, inverseKey, relationshipMeta) { super(store, internalModel, inverseKey, relationshipMeta); @@ -21,7 +19,6 @@ export default class ManyRelationship extends Relationship { this._loadingPromise = null; this._willUpdateManyArray = false; this._pendingManyArrayUpdates = null; - this._removedInternalModels = null; } _updateLoadingPromise(promise, content) { @@ -206,11 +203,6 @@ export default class ManyRelationship extends Relationship { if (!this.members.has(internalModel)) { return; } - // remember removals so we can deal with them in computeChanges - if (!this._removedInternalModels) { - this._removedInternalModels = new OrderedSet(); - } - this._removedInternalModels.add(internalModel); super.removeInternalModelFromOwn(internalModel, idx); // note that ensuring the many array is created, via `this.manyArray` // (instead of `this._manyArray`) is intentional. @@ -274,75 +266,22 @@ export default class ManyRelationship extends Relationship { } computeChanges(internalModels = []) { - let members = this.canonicalMembers.toArray(); - let removedSinceLastTime = this._removedInternalModels; - this._removedInternalModels = null; // clear it for next time - - let diff = diffArray(members, internalModels); - - if (diff.firstChangeIndex === null) { - // no changes found - if (removedSinceLastTime) { - // records that have been removed since last compute will need their inverses to be corrected - for (let i = 0, l = internalModels.length; i < l; i++) { - let record = internalModels[i]; - if (removedSinceLastTime.has(record)) { - this.flushCanonicalLater(); - break; - } - } - } - return; - } - let removedMembersSet = setForArray(members.slice(diff.firstChangeIndex, diff.firstChangeIndex + diff.removedCount)); - let changeBlockSet = setForArray(internalModels.slice(diff.firstChangeIndex, diff.firstChangeIndex + diff.addedCount)); + let members = this.canonicalMembers; + let internalModelsToRemove = []; + let internalModelSet = setForArray(internalModels); - // remove members that were removed but not re-added - removedMembersSet.forEach(member => { - if (!changeBlockSet.has(member)) { - this.removeCanonicalInternalModel(member); - } + members.forEach(member => { + if (internalModelSet.has(member)) { return; } + + internalModelsToRemove.push(member); }); - let flushCanonicalLater = false; - - // --- deal with records before the change block - if (removedSinceLastTime) { - // records that have been removed since last compute will need their inverses to be corrected - for (let i = 0; i < diff.firstChangeIndex; i++) { - let record = internalModels[i]; - if (removedSinceLastTime.has(record)) { - flushCanonicalLater = true; - break; - } - } - } - // --- deal with records in the change block - for (let i = diff.firstChangeIndex, l = diff.firstChangeIndex + diff.addedCount; i < l; i++) { - let record = internalModels[i]; - if (members[i] !== record) { - if (removedMembersSet.has(record)) { - // this is a reorder - this.removeCanonicalInternalModel(record); - } - // reorder or insert - this.addCanonicalInternalModel(record, i); - } - } - // --- deal with records after the change block - if (!flushCanonicalLater && removedSinceLastTime) { - // records that have been removed since last compute will need their inverses to be corrected - for (let i = diff.firstChangeIndex + diff.addedCount, l = internalModels.length; i < l; i++) { - let record = internalModels[i]; - if (removedSinceLastTime.has(record)) { - flushCanonicalLater = true; - break; - } - } - } + this.removeCanonicalInternalModels(internalModelsToRemove); - if (flushCanonicalLater) { - this.flushCanonicalLater(); + for (let i = 0, l = internalModels.length; i < l; i++) { + let internalModel = internalModels[i]; + this.removeCanonicalInternalModel(internalModel); + this.addCanonicalInternalModel(internalModel, i); } } diff --git a/tests/integration/records/relationship-changes-test.js b/tests/integration/records/relationship-changes-test.js index 871093ec9fc..5547164a3d2 100644 --- a/tests/integration/records/relationship-changes-test.js +++ b/tests/integration/records/relationship-changes-test.js @@ -2,6 +2,7 @@ import { alias } from '@ember/object/computed'; import { run } from '@ember/runloop'; import EmberObject, { set, get } from '@ember/object'; import setupStore from 'dummy/tests/helpers/store'; + import DS from 'ember-data'; import { module, test } from 'qunit'; @@ -532,26 +533,32 @@ test('Calling push with relationship triggers willChange and didChange with deta } }; - let person = run(() => store.push({ - data: { - type: 'person', - id: 'wat', - attributes: { - firstName: 'Yehuda', - lastName: 'Katz' - }, - relationships: { - siblings: { - data: [sibling1Ref] + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [sibling1Ref] + } } - } - }, - included: [ - sibling1 - ] - })); + }, + included: [ + sibling1 + ] + + }); + }); + + let person = store.peekRecord('person', 'wat'); let siblings = run(() => person.get('siblings')); + siblings.addArrayObserver(observer); run(() => { @@ -582,26 +589,31 @@ test('Calling push with relationship triggers willChange and didChange with deta test('Calling push with relationship triggers willChange and didChange with detail when truncating', function(assert) { let willChangeCount = 0; let didChangeCount = 0; - let person = run(() => store.push({ - data: { - type: 'person', - id: 'wat', - attributes: { - firstName: 'Yehuda', - lastName: 'Katz' - }, - relationships: { - siblings: { - data: [sibling1Ref, sibling2Ref] + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [sibling1Ref, sibling2Ref] + } } - } - }, - included: [ - sibling1, sibling2 - ] - })); + }, + included: [ + sibling1, sibling2 + ] + }); + }); + let person = store.peekRecord('person', 'wat'); let siblings = run(() => person.get('siblings')); + let observer = { arrayWillChange(array, start, removing, adding) { willChangeCount++; @@ -646,24 +658,28 @@ test('Calling push with relationship triggers willChange and didChange with deta test('Calling push with relationship triggers willChange and didChange with detail when inserting at front', function(assert) { let willChangeCount = 0; let didChangeCount = 0; - let person = run(() => store.push({ - data: { - type: 'person', - id: 'wat', - attributes: { - firstName: 'Yehuda', - lastName: 'Katz' - }, - relationships: { - siblings: { - data: [sibling2Ref] + + run(() => { + store.push({ + data: { + type: 'person', + id: 'wat', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz' + }, + relationships: { + siblings: { + data: [sibling2Ref] + } } - } - }, - included: [ - sibling2 - ] - })); + }, + included: [ + sibling2 + ] + }); + }); + let person = store.peekRecord('person', 'wat'); let observer = { arrayWillChange(array, start, removing, adding) { diff --git a/tests/unit/diff-array-test.js b/tests/unit/diff-array-test.js index 7dc8f889b3a..a226a2ffd07 100644 --- a/tests/unit/diff-array-test.js +++ b/tests/unit/diff-array-test.js @@ -1,4 +1,5 @@ import { module, test } from 'qunit'; + import { diffArray } from 'ember-data/-private'; module('unit/diff-array Diff Array tests', { diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 7f7e835bedc..29bbbae7138 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -1611,7 +1611,7 @@ test('hasMany.firstObject.unloadRecord should not break that hasMany', function( the parent record's hasMany is a situation in which this limitation will be encountered should other local changes to the relationship still exist. */ -test('returning new hasMany relationship info from a delete maintains a local addition', function(assert) { +test('[ASSERTS KNOWN LIMITATION STILL EXISTS] returning new hasMany relationship info from a delete clears local state', function(assert) { assert.expect(4); const Person = DS.Model.extend({ @@ -1642,7 +1642,7 @@ test('returning new hasMany relationship info from a delete maintains a local ad relationships: { pets: { data: [ - { type: 'pet', id: 'server-known-2' } + { type: 'pet', id: '2' } ] } } @@ -1664,8 +1664,8 @@ test('returning new hasMany relationship info from a delete maintains a local ad relationships: { pets: { data: [ - { type: 'pet', id: 'will-destroy-1' }, - { type: 'pet', id: 'server-known-2' } + { type: 'pet', id: '1' }, + { type: 'pet', id: '2' } ] } } @@ -1673,21 +1673,21 @@ test('returning new hasMany relationship info from a delete maintains a local ad included: [ { type: 'pet', - id: 'will-destroy-1', + id: '1', attributes: { name: 'Shenanigans' } }, { type: 'pet', - id: 'server-known-2', + id: '2', attributes: { name: 'Rambunctious' } }, { type: 'pet', - id: 'local-3', + id: '3', attributes: { name: 'Rebel' } @@ -1699,26 +1699,25 @@ test('returning new hasMany relationship info from a delete maintains a local ad const person = store.peekRecord('person', '1'); const pets = run(() => person.get('pets')); - const shen = store.peekRecord('pet', 'will-destroy-1'); - const rebel = store.peekRecord('pet', 'local-3'); + const shen = store.peekRecord('pet', '1'); + const rebel = store.peekRecord('pet', '3'); assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); - assert.deepEqual(pets.map(p => get(p, 'id')), ['will-destroy-1', 'server-known-2'], 'precond - relationship has the correct pets to start'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2'], 'precond - relationship has the correct pets to start'); - // add a new item locally run(() => { pets.pushObjects([rebel]); }); - assert.deepEqual(pets.map(p => get(p, 'id')), ['will-destroy-1', 'server-known-2', 'local-3'], 'precond2 - relationship now has the correct three pets'); + assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2', '3'], 'precond2 - relationship now has the correct three pets'); return run(() => { return shen.destroyRecord({}) .then(() => { shen.unloadRecord(); - // were ember-data to not preserve local edits during a relationship push, this would be 'server-known-2' - assert.deepEqual(pets.map(p => get(p, 'id')), ['server-known-2', 'local-3'], 'relationship now has only one pet, we kept the local change'); + // were ember-data to now preserve local edits during a relationship push, this would be '2' + assert.deepEqual(pets.map(p => get(p, 'id')), ['2'], 'relationship now has only one pet, we lost the local change'); }); }); }); From dab545ed960c50881786f9dd881a1ea17a03f9bd Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Wed, 25 Apr 2018 12:47:30 -0700 Subject: [PATCH 2221/2527] remove unused import --- index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/index.js b/index.js index b743e6f5528..284dfdf591d 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,6 @@ const path = require('path'); const SilentError = require('silent-error'); const Funnel = require('broccoli-funnel'); const Rollup = require('broccoli-rollup'); -const Babel = require('broccoli-babel-transpiler'); const merge = require('broccoli-merge-trees'); const semver = require('semver'); const version = require('./lib/version'); From 741fe77b3e08789b72e37f71dbc2c959224e9b84 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Mon, 30 Apr 2018 13:29:07 -0700 Subject: [PATCH 2222/2527] failing test for relationships not updating when null data returned This adds a failing test that a relationship should disassociate records on both sides of the relationship when a payload explicitly returns null for the data of that relationship. --- .../relationships/belongs-to-test.js | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 60e58df49d1..040aa4e998c 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -92,6 +92,77 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { } }); +test("returning a null relationship from payload sets the relationship to null on both sides", function(assert) { + env.registry.register('model:app', DS.Model.extend({ + name: attr('string'), + team: belongsTo('team', { async: true }), + })); + env.registry.register('model:team', DS.Model.extend({ + apps: hasMany('app', {async: true}) + })); + run(() => { + env.store.push({ + data: { + id: '1', + type: 'app', + relationships: { + team: { + data: { + id: '1', + type: 'team' + } + } + } + }, + included: [ + { + id: '1', + type: 'team', + relationships: { + apps: { + data: [{ + id: '1', + type: 'app' + }] + } + } + } + ] + }); + }); + + const app = env.store.peekRecord('app', '1'); + const team = env.store.peekRecord('team', '1'); + assert.equal(app.get('team.id'), team.get('id'), 'sets team correctly on app'); + assert.deepEqual(team.get('apps').toArray().mapBy('id'), ['1'], 'sets apps correctly on team'); + + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.updateRecord = (store, type, snapshot) => { + return RSVP.resolve({ + data: { + id: '1', + type: 'app', + attributes: { + name: 'Hello' + }, + relationships: { + team: { + data: null + } + } + } + }); + }; + + return run(() => { + app.set('name', 'Hello'); + return app.save().then(() => { + assert.equal(app.get('team.id'), null, 'team removed from app relationship'); + assert.deepEqual(team.get('apps').toArray().mapBy('id'), [], 'app removed from team apps relationship'); + }); + }); +}); + test("The store can materialize a non loaded monomorphic belongsTo association", function(assert) { assert.expect(1); From ddf5e9540ffbbd58d177ef50f965607a2a66ccad Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 30 Apr 2018 14:58:38 -0700 Subject: [PATCH 2223/2527] [BUGFIX] ensure that the belongsTo proxy for async relationships updates content when new content is explicitly null --- addon/-private/system/relationships/state/belongs-to.js | 2 +- tests/integration/relationships/belongs-to-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index a95c2692c6b..c1d813fe829 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -188,7 +188,7 @@ export default class BelongsToRelationship extends Relationship { _updateLoadingPromise(promise, content) { if (this._loadingPromise) { - if (content) { + if (content !== undefined) { this._loadingPromise.set('content', content) } this._loadingPromise.set('promise', promise) diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 040aa4e998c..616788fe09e 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -95,7 +95,7 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { test("returning a null relationship from payload sets the relationship to null on both sides", function(assert) { env.registry.register('model:app', DS.Model.extend({ name: attr('string'), - team: belongsTo('team', { async: true }), + team: belongsTo('team', { async: true }) })); env.registry.register('model:team', DS.Model.extend({ apps: hasMany('app', {async: true}) From 07856f2e63f91f8e1f4b7e9e08228585fc0fbb4b Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 8 May 2018 13:13:11 -0700 Subject: [PATCH 2224/2527] [BUGFIX] dont cause unnecessary work during destroy --- addon/-private/system/store.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 13aaccffb42..2cc4f400294 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1125,7 +1125,10 @@ Store = Service.extend({ _internalModelDestroyed(internalModel) { this._removeFromIdMap(internalModel); - this._relationshipsPayloads.unload(internalModel.modelName, internalModel.id); + + if (!this.isDestroying) { + this._relationshipsPayloads.unload(internalModel.modelName, internalModel.id); + } }, /** @@ -2625,6 +2628,7 @@ Store = Service.extend({ this._pushedInternalModels = null; this.recordArrayManager.destroy(); + this._relationshipsPayloads = null; this._adapterCache = null; this._serializerCache = null; From dfd6d8e58b1688d7f5454760160bbf67a1460c73 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 8 May 2018 14:14:34 -0700 Subject: [PATCH 2225/2527] [FEAT RFC] RecordData RFC Implementation behind Feature Flag Co-authored-by: Igor Terzic Co-authored-by: Chris Thoburn --- .gitignore | 2 +- .travis.yml | 2 +- addon/-debug/index.js | 7 +- addon/-private/attr.js | 137 + addon/-private/index.js | 1 + addon/-private/system/model/model.js | 36 +- addon/-private/system/record-array-manager.js | 4 + .../adapter-populated-record-array.js | 3 +- .../-private/system/references/belongs-to.js | 2 +- addon/-private/system/references/has-many.js | 2 +- addon/-private/system/relationship-meta.js | 90 +- addon/-private/system/relationships/ext.js | 24 +- .../relationship-payloads-manager.js | 10 +- .../system/relationships/state/belongs-to.js | 2 +- .../system/relationships/state/has-many.js | 6 +- addon/-private/system/store.js | 37 +- .../adapters/build-url-mixin.js | 443 +++ .../adapters/errors.js | 461 +++ addon/-record-data-rfc-private/attr.js | 135 + addon/-record-data-rfc-private/core.js | 29 + addon/-record-data-rfc-private/features.js | 5 + addon/-record-data-rfc-private/index.js | 60 + .../system/backburner.js | 12 + .../system/clone-null.js | 7 + .../system/coerce-id.js | 11 + .../system/debug/debug-adapter.js | 126 + .../system/diff-array.js | 58 + .../system/identity-map.js | 50 + .../system/internal-model-map.js | 119 + .../system/is-array-like.js | 23 + .../system/many-array.js | 290 ++ .../system/map-with-default.js | 21 + addon/-record-data-rfc-private/system/map.js | 102 + .../system/model/errors.js | 409 +++ .../system/model/internal-model.js | 1175 +++++++ .../system/model/model-data.js | 697 ++++ .../system/model/model.js | 1928 +++++++++++ .../system/model/states.js | 764 +++++ .../system/normalize-link.js | 19 + .../system/normalize-model-name.js | 18 + .../system/ordered-set.js | 37 + .../system/promise-proxies.js | 160 + .../system/record-array-manager.js | 389 +++ .../system/record-arrays.js | 11 + .../adapter-populated-record-array.js | 92 + .../system/record-arrays/record-array.js | 255 ++ .../system/references.js | 5 + .../system/references/belongs-to.js | 307 ++ .../system/references/has-many.js | 332 ++ .../system/references/record.js | 163 + .../system/references/reference.js | 152 + .../system/relationship-meta.js | 96 + .../system/relationships/belongs-to.js | 126 + .../system/relationships/ext.js | 76 + .../system/relationships/has-many.js | 152 + .../system/relationships/state/belongs-to.js | 196 ++ .../system/relationships/state/create.js | 47 + .../system/relationships/state/has-many.js | 257 ++ .../relationships/state/relationship.js | 602 ++++ .../system/snapshot-record-array.js | 165 + .../system/snapshot.js | 406 +++ .../-record-data-rfc-private/system/store.js | 3043 +++++++++++++++++ .../system/store/common.js | 55 + .../system/store/finders.js | 197 ++ .../system/store/model-data-wrapper.js | 115 + .../system/store/serializer-response.js | 84 + .../system/store/serializers.js | 15 + addon/-record-data-rfc-private/utils.js | 47 + .../utils/parse-response-headers.js | 36 + addon/attr.js | 138 +- ember-cli-build.js | 11 +- index.js | 109 +- package.json | 12 +- tests/helpers/test-in-debug.js | 23 +- tests/integration/inverse-test.js | 20 +- .../records/relationship-changes-test.js | 1 - .../integration/records/rematerialize-test.js | 11 +- tests/integration/records/unload-test.js | 171 +- .../relationships/belongs-to-test.js | 2 +- .../relationships/has-many-test.js | 12 +- .../inverse-relationships-test.js | 141 +- .../relationships/one-to-many-test.js | 2 +- .../serializers/json-api-serializer-test.js | 30 +- tests/unit/debug-test.js | 6 +- tests/unit/model-test.js | 61 +- tests/unit/model/relationships-test.js | 22 +- .../unit/model/relationships/has-many-test.js | 16 +- .../adapter-populated-record-array-test.js | 13 +- .../polymorphic-relationship-payloads-test.js | 5 +- .../relationship-payload-manager-test.js | 682 ---- .../relationship-payloads-test.js | 344 -- tests/unit/utils-test.js | 8 +- yarn.lock | 196 +- 93 files changed, 15564 insertions(+), 1417 deletions(-) create mode 100644 addon/-private/attr.js create mode 100644 addon/-record-data-rfc-private/adapters/build-url-mixin.js create mode 100644 addon/-record-data-rfc-private/adapters/errors.js create mode 100644 addon/-record-data-rfc-private/attr.js create mode 100644 addon/-record-data-rfc-private/core.js create mode 100644 addon/-record-data-rfc-private/features.js create mode 100644 addon/-record-data-rfc-private/index.js create mode 100644 addon/-record-data-rfc-private/system/backburner.js create mode 100644 addon/-record-data-rfc-private/system/clone-null.js create mode 100644 addon/-record-data-rfc-private/system/coerce-id.js create mode 100644 addon/-record-data-rfc-private/system/debug/debug-adapter.js create mode 100644 addon/-record-data-rfc-private/system/diff-array.js create mode 100644 addon/-record-data-rfc-private/system/identity-map.js create mode 100644 addon/-record-data-rfc-private/system/internal-model-map.js create mode 100644 addon/-record-data-rfc-private/system/is-array-like.js create mode 100644 addon/-record-data-rfc-private/system/many-array.js create mode 100644 addon/-record-data-rfc-private/system/map-with-default.js create mode 100644 addon/-record-data-rfc-private/system/map.js create mode 100644 addon/-record-data-rfc-private/system/model/errors.js create mode 100644 addon/-record-data-rfc-private/system/model/internal-model.js create mode 100644 addon/-record-data-rfc-private/system/model/model-data.js create mode 100644 addon/-record-data-rfc-private/system/model/model.js create mode 100644 addon/-record-data-rfc-private/system/model/states.js create mode 100644 addon/-record-data-rfc-private/system/normalize-link.js create mode 100644 addon/-record-data-rfc-private/system/normalize-model-name.js create mode 100644 addon/-record-data-rfc-private/system/ordered-set.js create mode 100644 addon/-record-data-rfc-private/system/promise-proxies.js create mode 100644 addon/-record-data-rfc-private/system/record-array-manager.js create mode 100644 addon/-record-data-rfc-private/system/record-arrays.js create mode 100644 addon/-record-data-rfc-private/system/record-arrays/adapter-populated-record-array.js create mode 100644 addon/-record-data-rfc-private/system/record-arrays/record-array.js create mode 100644 addon/-record-data-rfc-private/system/references.js create mode 100644 addon/-record-data-rfc-private/system/references/belongs-to.js create mode 100644 addon/-record-data-rfc-private/system/references/has-many.js create mode 100644 addon/-record-data-rfc-private/system/references/record.js create mode 100644 addon/-record-data-rfc-private/system/references/reference.js create mode 100644 addon/-record-data-rfc-private/system/relationship-meta.js create mode 100644 addon/-record-data-rfc-private/system/relationships/belongs-to.js create mode 100644 addon/-record-data-rfc-private/system/relationships/ext.js create mode 100644 addon/-record-data-rfc-private/system/relationships/has-many.js create mode 100644 addon/-record-data-rfc-private/system/relationships/state/belongs-to.js create mode 100644 addon/-record-data-rfc-private/system/relationships/state/create.js create mode 100755 addon/-record-data-rfc-private/system/relationships/state/has-many.js create mode 100644 addon/-record-data-rfc-private/system/relationships/state/relationship.js create mode 100644 addon/-record-data-rfc-private/system/snapshot-record-array.js create mode 100644 addon/-record-data-rfc-private/system/snapshot.js create mode 100644 addon/-record-data-rfc-private/system/store.js create mode 100644 addon/-record-data-rfc-private/system/store/common.js create mode 100644 addon/-record-data-rfc-private/system/store/finders.js create mode 100644 addon/-record-data-rfc-private/system/store/model-data-wrapper.js create mode 100644 addon/-record-data-rfc-private/system/store/serializer-response.js create mode 100644 addon/-record-data-rfc-private/system/store/serializers.js create mode 100644 addon/-record-data-rfc-private/utils.js create mode 100644 addon/-record-data-rfc-private/utils/parse-response-headers.js delete mode 100644 tests/unit/system/relationships/relationship-payload-manager-test.js delete mode 100644 tests/unit/system/relationships/relationship-payloads-test.js diff --git a/.gitignore b/.gitignore index 3fa6bc6e064..8d89d47e86c 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,4 @@ bower_components/ .metadata_never_index npm-debug.log -DEBUG-* +/DEBUG diff --git a/.travis.yml b/.travis.yml index d9a6b400138..1f6d6bdacb8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: node_js sudo: false dist: trusty node_js: - - "4" + - "6" addons: chrome: stable diff --git a/addon/-debug/index.js b/addon/-debug/index.js index 2dd3d1911ea..7d8fc71c211 100644 --- a/addon/-debug/index.js +++ b/addon/-debug/index.js @@ -40,15 +40,16 @@ if (DEBUG) { return modelClass.detect(addedModelClass); }; - assertPolymorphicType = function assertPolymorphicType(parentInternalModel, relationshipMeta, addedInternalModel) { + assertPolymorphicType = function assertPolymorphicType(parentInternalModel, relationshipMeta, addedInternalModel, store) { let addedModelName = addedInternalModel.modelName; let parentModelName = parentInternalModel.modelName; let key = relationshipMeta.key; let relationshipModelName = relationshipMeta.type; - let relationshipClass = parentInternalModel.store.modelFor(relationshipModelName); + let relationshipClass = store.modelFor(relationshipModelName); + let addedClass = store.modelFor(addedInternalModel.modelName); let assertionMessage = `You cannot add a record of modelClass '${addedModelName}' to the '${parentModelName}.${key}' relationship (only '${relationshipModelName}' allowed)`; - assert(assertionMessage, checkPolymorphic(relationshipClass, addedInternalModel.modelClass)); + assert(assertionMessage, checkPolymorphic(relationshipClass, addedClass)); }; } diff --git a/addon/-private/attr.js b/addon/-private/attr.js new file mode 100644 index 00000000000..ddbb80e3724 --- /dev/null +++ b/addon/-private/attr.js @@ -0,0 +1,137 @@ +import { computed } from '@ember/object'; +import { assert } from '@ember/debug'; + +/** + @module ember-data +*/ + +function getDefaultValue(record, options, key) { + if (typeof options.defaultValue === 'function') { + return options.defaultValue.apply(null, arguments); + } else { + let defaultValue = options.defaultValue; + assert(`Non primitive defaultValues are not supported because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.`, + typeof defaultValue !== 'object' || defaultValue === null); + return defaultValue; + } +} + +function hasValue(record, key) { + return key in record._attributes || + key in record._inFlightAttributes || + key in record._data; +} + +/** + `DS.attr` defines an attribute on a [DS.Model](/api/data/classes/DS.Model.html). + By default, attributes are passed through as-is, however you can specify an + optional type to have the value automatically transformed. + Ember Data ships with four basic transform types: `string`, `number`, + `boolean` and `date`. You can define your own transforms by subclassing + [DS.Transform](/api/data/classes/DS.Transform.html). + + Note that you cannot use `attr` to define an attribute of `id`. + + `DS.attr` takes an optional hash as a second parameter, currently + supported options are: + + - `defaultValue`: Pass a string or a function to be called to set the attribute + to a default value if none is supplied. + + Example + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + username: DS.attr('string'), + email: DS.attr('string'), + verified: DS.attr('boolean', { defaultValue: false }) + }); + ``` + + Default value can also be a function. This is useful it you want to return + a new object for each attribute. + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + username: DS.attr('string'), + email: DS.attr('string'), + settings: DS.attr({ + defaultValue() { + return {}; + } + }) + }); + ``` + + The `options` hash is passed as second argument to a transforms' + `serialize` and `deserialize` method. This allows to configure a + transformation and adapt the corresponding value, based on the config: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + text: DS.attr('text', { + uppercase: true + }) + }); + ``` + + ```app/transforms/text.js + import DS from 'ember-data'; + + export default DS.Transform.extend({ + serialize(value, options) { + if (options.uppercase) { + return value.toUpperCase(); + } + + return value; + }, + + deserialize(value) { + return value; + } + }) + ``` + + @namespace + @method attr + @for DS + @param {String|Object} type the attribute type + @param {Object} options a hash of options + @return {Attribute} +*/ + +export default function attr(type, options) { + if (typeof type === 'object') { + options = type; + type = undefined; + } else { + options = options || {}; + } + + let meta = { + type: type, + isAttribute: true, + options: options + }; + + return computed({ + get(key) { + let internalModel = this._internalModel; + if (hasValue(internalModel, key)) { + return internalModel.getAttributeValue(key); + } else { + return getDefaultValue(this, options, key); + } + }, + set(key, value) { + return this._internalModel.setDirtyAttribute(key, value); + } + }).meta(meta); +} diff --git a/addon/-private/index.js b/addon/-private/index.js index 4b948d24c4f..6cfb8a5da96 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -7,6 +7,7 @@ export { default as belongsTo } from './system/relationships/belongs-to'; export { default as hasMany } from './system/relationships/has-many'; export { default as BuildURLMixin } from './adapters/build-url-mixin'; export { default as Snapshot } from './system/snapshot'; +export { default as attr } from './attr'; export { AdapterError, InvalidError, diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 32e96606dc4..7c221af8461 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1300,23 +1300,19 @@ Model.reopenClass({ let inverseMap = get(this, 'inverseMap'); if (inverseMap[name] !== undefined) { return inverseMap[name]; - } else { - let relationship = get(this, 'relationshipsByName').get(name); - if (!relationship) { - inverseMap[name] = null; - return null; - } - - let options = relationship.options; - if (options && options.inverse === null) { - // populate the cache with a miss entry so we can skip getting and going - // through `relationshipsByName` - inverseMap[name] = null; - return null; - } + } - return inverseMap[name] = this._findInverseFor(name, store); + let relationship = get(this, 'relationshipsByName').get(name); + if ( + !relationship || + // populate the cache with a miss entry so we can skip getting and going + // through `relationshipsByName` + (relationship.options && relationship.options.inverse === null) + ) { + return inverseMap[name] = null; } + + return inverseMap[name] = this._findInverseFor(name, store); }, //Calculate the inverse, ignoring the cache @@ -1332,7 +1328,7 @@ Model.reopenClass({ let options = propertyMeta.options; if (options.inverse === null) { return null; } - let inverseName, inverseKind, inverse; + let inverseName, inverseKind, inverse, inverseOptions; //If inverse is specified manually, return the inverse if (options.inverse) { @@ -1342,7 +1338,9 @@ Model.reopenClass({ assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.modelName + "' model. This is most likely due to a missing attribute on your model definition.", !isNone(inverse)); + // TODO probably just return the whole inverse here inverseKind = inverse.kind; + inverseOptions = inverse.options; } else { //No inverse was specified manually, we need to use a heuristic to guess one if (propertyMeta.parentType && propertyMeta.type === propertyMeta.parentType.modelName) { @@ -1374,12 +1372,16 @@ Model.reopenClass({ inverseName = possibleRelationships[0].name; inverseKind = possibleRelationships[0].kind; + inverseOptions = possibleRelationships[0].options; } + assert(`The ${inverseType.modelName}:${inverseName} relationship declares 'inverse: null', but it was resolved as the inverse for ${this.modelName}:${name}.`, !inverseOptions || inverseOptions.inverse !== null); + return { type: inverseType, name: inverseName, - kind: inverseKind + kind: inverseKind, + options: inverseOptions }; }, diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index 71b686dbee2..a3608c16a54 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -306,6 +306,10 @@ export default class RecordArrayManager { } } + _associateWithRecordArray(internalModels, array) { + associateWithRecordArray(internalModels, array); + } + willDestroy() { Object.keys(this._liveRecordArrays).forEach(modelName => this._liveRecordArrays[modelName].destroy()); this._adapterPopulatedRecordArrays.forEach(destroy); diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index 959f61938f8..7ccf8e89085 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -3,7 +3,6 @@ import { A } from '@ember/array'; import { get } from '@ember/object'; import RecordArray from "./record-array"; import cloneNull from "../clone-null"; -import { associateWithRecordArray } from '../record-array-manager'; /** Represents an ordered list of records whose order and membership is @@ -84,7 +83,7 @@ export default RecordArray.extend({ links: cloneNull(payload.links) }); - associateWithRecordArray(internalModels, this); + this.manager._associateWithRecordArray(internalModels, this); // TODO: should triggering didLoad event be the last action of the runLoop? once(this, 'trigger', 'didLoad'); diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 20a285bbb44..44094076f65 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -244,7 +244,7 @@ export default class BelongsToReference extends Reference { record = this.store.push(data); } - assertPolymorphicType(this.internalModel, this.belongsToRelationship.relationshipMeta, record._internalModel); + assertPolymorphicType(this.internalModel, this.belongsToRelationship.relationshipMeta, record._internalModel, this.store); this.belongsToRelationship.setCanonicalInternalModel(record._internalModel); diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 5e88af85754..ddd775d89de 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -245,7 +245,7 @@ export default class HasManyReference extends Reference { if (DEBUG) { let relationshipMeta = this.hasManyRelationship.relationshipMeta; - assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel); + assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel, this.store); } return record._internalModel; diff --git a/addon/-private/system/relationship-meta.js b/addon/-private/system/relationship-meta.js index 3f10d7c6265..2951df4c616 100644 --- a/addon/-private/system/relationship-meta.js +++ b/addon/-private/system/relationship-meta.js @@ -1,4 +1,5 @@ import { singularize } from 'ember-inflector'; +import { DEBUG } from '@glimmer/env'; import normalizeModelName from './normalize-model-name'; export function typeForRelationshipMeta(meta) { @@ -11,14 +12,85 @@ export function typeForRelationshipMeta(meta) { return modelName; } +function shouldFindInverse(relationshipMeta) { + let options = relationshipMeta.options; + return !(options && options.inverse === null); +} + +class RelationshipDefinition { + constructor(meta) { + this.meta = meta; + this._type = ''; + this.__inverseKey = ''; + this.__inverseIsAsync = null; + this.modelClass = meta.parentType; + this.store = null; + } + + get key() { + return this.meta.key; + } + get kind() { + return this.meta.kind; + } + get type() { + if (this._type) { + return this._type; + } + this._type = typeForRelationshipMeta(this.meta); + return this._type; + } + get options() { + return this.meta.options; + } + get name() { + return this.meta.name; + } + get parentType() { + return this.meta.parentType; + } + + _inverseKey(store, modelClass) { + if (this.__inverseKey === '') { + this._calculateInverse(store, modelClass); + } + return this.__inverseKey; + } + + _inverseIsAsync(store, modelClass) { + if (this.__inverseIsAsync === null) { + this._calculateInverse(store, modelClass); + } + return this.__inverseIsAsync; + } + + _calculateInverse(store, modelClass) { + let inverseKey, inverseIsAsync; + let inverse = null; + + if (shouldFindInverse(this.meta)) { + inverse = modelClass.inverseFor(this.key, store); + } else if (DEBUG) { + modelClass.typeForRelationship(this.key, store); + } + + if (inverse) { + inverseKey = inverse.name; + inverseIsAsync = isInverseAsync(inverse); + } else { + inverseKey = null; + inverseIsAsync = false; + } + this.__inverseKey = inverseKey; + this.__inverseIsAsync = inverseIsAsync; + } +} + +function isInverseAsync(meta) { + let inverseAsync = meta.options && meta.options.async; + return typeof inverseAsync === 'undefined' ? true : inverseAsync; +} + export function relationshipFromMeta(meta) { - return { - key: meta.key, - kind: meta.kind, - type: typeForRelationshipMeta(meta), - options: meta.options, - name: meta.name, - parentType: meta.parentType, - isRelationship: true - }; + return new RelationshipDefinition(meta); } diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index fb7836ab91d..d848397cf1d 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -1,5 +1,5 @@ import { A } from '@ember/array'; -import { computed } from '@ember/object'; +import { computed , get } from '@ember/object'; import MapWithDefault from '../map-with-default'; import Map from '../map'; import { assert } from '@ember/debug'; @@ -13,19 +13,12 @@ export const relationshipsDescriptor = computed(function() { defaultValue() { return []; } }); - // Loop through each computed property on the class - this.eachComputedProperty((name, meta) => { - // If the computed property is a relationship, add - // it to the map. - if (meta.isRelationship) { - meta.key = name; - let relationshipsForType = map.get(typeForRelationshipMeta(meta)); + let relationshipsByName = get(this, 'relationshipsByName'); - relationshipsForType.push({ - name: name, - kind: meta.kind - }); - } + // Loop through each computed property on the class + relationshipsByName.forEach(desc => { + let relationshipsForType = map.get(desc.type); + relationshipsForType.push(desc); }); return map; @@ -61,9 +54,8 @@ export const relationshipsByNameDescriptor = computed(function() { this.eachComputedProperty((name, meta) => { if (meta.isRelationship) { meta.key = name; - let relationship = relationshipFromMeta(meta); - relationship.type = typeForRelationshipMeta(meta); - map.set(name, relationship); + meta.name = name; + map.set(name, relationshipFromMeta(meta)); } }); diff --git a/addon/-private/system/relationships/relationship-payloads-manager.js b/addon/-private/system/relationships/relationship-payloads-manager.js index 8bf9ce4d967..bc67a6aefde 100644 --- a/addon/-private/system/relationships/relationship-payloads-manager.js +++ b/addon/-private/system/relationships/relationship-payloads-manager.js @@ -198,8 +198,16 @@ export default class RelationshipPayloadsManager { return null; } - let inverseMeta = modelClass.inverseFor(relationshipName, store); let relationshipMeta = relationshipsByName.get(relationshipName); + let inverseMeta; + + // CASE: Inverse is explicitly null + if (relationshipMeta.options && relationshipMeta.options.inverse === null) { + inverseMeta = null; + } else { + inverseMeta = modelClass.inverseFor(relationshipName, store); + } + let selfIsPolymorphic = relationshipMeta.options !== undefined && relationshipMeta.options.polymorphic === true; let inverseBaseModelName = relationshipMeta.type; diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index c1d813fe829..7d696e290bd 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -100,7 +100,7 @@ export default class BelongsToRelationship extends Relationship { addInternalModel(internalModel) { if (this.members.has(internalModel)) { return; } - assertPolymorphicType(this.internalModel, this.relationshipMeta, internalModel); + assertPolymorphicType(this.internalModel, this.relationshipMeta, internalModel, this.store); if (this.inverseInternalModel) { this.removeInternalModel(this.inverseInternalModel); diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index dd0c1a29680..cc4523051cf 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -40,7 +40,7 @@ export default class ManyRelationship extends Relationship { get manyArray() { assert(`Error: relationship ${this.parentType}:${this.key} has both many array and retained many array`, this._manyArray === null || this._retainedManyArray === null); - if (!this._manyArray) { + if (!this._manyArray && !this.isDestroying) { this._manyArray = ManyArray.create({ canonicalState: this.canonicalState, store: this.store, @@ -108,7 +108,7 @@ export default class ManyRelationship extends Relationship { return; } - assertPolymorphicType(this.internalModel, this.relationshipMeta, internalModel); + assertPolymorphicType(this.internalModel, this.relationshipMeta, internalModel, this.store); super.addInternalModel(internalModel, idx); this.scheduleManyArrayUpdate(internalModel, idx); } @@ -382,6 +382,7 @@ export default class ManyRelationship extends Relationship { } destroy() { + this.isDestroying = true; super.destroy(); let manyArray = this._manyArray; if (manyArray) { @@ -395,6 +396,7 @@ export default class ManyRelationship extends Relationship { proxy.destroy(); this._loadingPromise = null; } + this.isDestroyed = true; } } diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 2cc4f400294..cddc90006ec 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2769,7 +2769,7 @@ function isInverseRelationshipInitialized(store, internalModel, data, key, model return false; } - let inverseMap = modelNameToInverseMap[internalModel.modelName] + let inverseMap = modelNameToInverseMap[internalModel.modelName]; if (!inverseMap) { inverseMap = modelNameToInverseMap[internalModel.modelName] = get(internalModel.type, 'inverseMap'); } @@ -2903,7 +2903,6 @@ function setupRelationships(store, internalModel, data, modelNameToInverseMap) { relationships.get(relationshipName).push(relationshipData, false); } - // in debug, assert payload validity eagerly if (DEBUG) { let relationshipMeta = get(internalModel.type, 'relationshipsByName').get(relationshipName); let relationshipData = data.relationships[relationshipName]; @@ -2911,16 +2910,44 @@ function setupRelationships(store, internalModel, data, modelNameToInverseMap) { return; } + // eslint-disable-next-line no-inner-declarations + function assertRelationshipData(store, internalModel, data, meta) { + assert( + `Encountered a relationship identifier without a type for the ${meta.kind} relationship '${meta.key}' on ${internalModel}, expected a json-api identifier with type '${meta.type}'.`, + data === null || (typeof data.type === 'string' && data.type.length) + ); + assert( + `Encountered a relationship identifier without an id for the ${meta.kind} relationship '${meta.key}' on ${internalModel}, expected a json-api identifier.`, + data === null || data.id || data.id === 0 + ); + assert( + `Encountered a relationship identifier with type '${ + data.type + }' for the ${meta.kind} relationship '${meta.key}' on ${ + internalModel + }, Expected a json-api identifier with type '${ + meta.type + }'. No model was found for '${data.type}'.`, + data === null || !data.type || store._hasModelFor(data.type) + ); + } + if (relationshipData.links) { let isAsync = relationshipMeta.options && relationshipMeta.options.async !== false; - warn(`You pushed a record of type '${internalModel.type.modelName}' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, isAsync || relationshipData.data , { + warn(`You pushed a record of type '${internalModel.modelName}' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, isAsync || relationshipData.data , { id: 'ds.store.push-link-for-sync-relationship' }); } else if (relationshipData.data) { if (relationshipMeta.kind === 'belongsTo') { - assert(`A ${internalModel.type.modelName} record was pushed into the store with the value of ${relationshipName} being ${inspect(relationshipData.data)}, but ${relationshipName} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(relationshipData.data)); + assert(`A ${internalModel.modelName} record was pushed into the store with the value of ${relationshipName} being ${inspect(relationshipData.data)}, but ${relationshipName} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(relationshipData.data)); + assertRelationshipData(store, internalModel, relationshipData.data, relationshipMeta); } else if (relationshipMeta.kind === 'hasMany') { - assert(`A ${internalModel.type.modelName} record was pushed into the store with the value of ${relationshipName} being '${inspect(relationshipData.data)}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(relationshipData.data)); + assert(`A ${internalModel.modelName} record was pushed into the store with the value of ${relationshipName} being '${inspect(relationshipData.data)}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(relationshipData.data)); + if (Array.isArray(relationshipData.data)) { + for (let i = 0; i < relationshipData.data.length; i++) { + assertRelationshipData(store, internalModel, relationshipData.data[i], relationshipMeta); + } + } } } } diff --git a/addon/-record-data-rfc-private/adapters/build-url-mixin.js b/addon/-record-data-rfc-private/adapters/build-url-mixin.js new file mode 100644 index 00000000000..2472a83d31a --- /dev/null +++ b/addon/-record-data-rfc-private/adapters/build-url-mixin.js @@ -0,0 +1,443 @@ +import { camelize } from '@ember/string'; +import Mixin from '@ember/object/mixin'; +import { get } from '@ember/object'; +import { pluralize } from 'ember-inflector'; + +/** + + WARNING: This interface is likely to change in order to accomodate https://github.com/emberjs/rfcs/pull/4 + + ## Using BuildURLMixin + + To use url building, include the mixin when extending an adapter, and call `buildURL` where needed. + The default behaviour is designed for RESTAdapter. + + ### Example + + ```javascript + export default DS.Adapter.extend(BuildURLMixin, { + findRecord: function(store, type, id, snapshot) { + var url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); + return this.ajax(url, 'GET'); + } + }); + ``` + + ### Attributes + + The `host` and `namespace` attributes will be used if defined, and are optional. + + @class BuildURLMixin + @namespace DS +*/ +export default Mixin.create({ + /** + Builds a URL for a given type and optional ID. + + By default, it pluralizes the type's name (for example, 'post' + becomes 'posts' and 'person' becomes 'people'). To override the + pluralization see [pathForType](#method_pathForType). + + If an ID is specified, it adds the ID to the path generated + for the type, separated by a `/`. + + When called by RESTAdapter.findMany() the `id` and `snapshot` parameters + will be arrays of ids and snapshots. + + @method buildURL + @param {String} modelName + @param {(String|Array|Object)} id single id or array of ids or query + @param {(DS.Snapshot|Array)} snapshot single snapshot or array of snapshots + @param {String} requestType + @param {Object} query object of query parameters to send for query requests. + @return {String} url + */ + buildURL(modelName, id, snapshot, requestType, query) { + switch (requestType) { + case 'findRecord': + return this.urlForFindRecord(id, modelName, snapshot); + case 'findAll': + return this.urlForFindAll(modelName, snapshot); + case 'query': + return this.urlForQuery(query, modelName); + case 'queryRecord': + return this.urlForQueryRecord(query, modelName); + case 'findMany': + return this.urlForFindMany(id, modelName, snapshot); + case 'findHasMany': + return this.urlForFindHasMany(id, modelName, snapshot); + case 'findBelongsTo': + return this.urlForFindBelongsTo(id, modelName, snapshot); + case 'createRecord': + return this.urlForCreateRecord(modelName, snapshot); + case 'updateRecord': + return this.urlForUpdateRecord(id, modelName, snapshot); + case 'deleteRecord': + return this.urlForDeleteRecord(id, modelName, snapshot); + default: + return this._buildURL(modelName, id); + } + }, + + /** + @method _buildURL + @private + @param {String} modelName + @param {String} id + @return {String} url + */ + _buildURL(modelName, id) { + let path; + let url = []; + let host = get(this, 'host'); + let prefix = this.urlPrefix(); + + if (modelName) { + path = this.pathForType(modelName); + if (path) { url.push(path); } + } + + if (id) { url.push(encodeURIComponent(id)); } + if (prefix) { url.unshift(prefix); } + + url = url.join('/'); + if (!host && url && url.charAt(0) !== '/') { + url = '/' + url; + } + + return url; + }, + + /** + Builds a URL for a `store.findRecord(type, id)` call. + + Example: + + ```app/adapters/user.js + import DS from 'ember-data'; + + export default DS.JSONAPIAdapter.extend({ + urlForFindRecord(id, modelName, snapshot) { + let baseUrl = this.buildURL(modelName, id, snapshot); + return `${baseUrl}/users/${snapshot.adapterOptions.user_id}/playlists/${id}`; + } + }); + ``` + + @method urlForFindRecord + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url + + */ + urlForFindRecord(id, modelName, snapshot) { + return this._buildURL(modelName, id); + }, + + /** + Builds a URL for a `store.findAll(type)` call. + + Example: + + ```app/adapters/comment.js + import DS from 'ember-data'; + + export default DS.JSONAPIAdapter.extend({ + urlForFindAll(modelName, snapshot) { + return 'data/comments.json'; + } + }); + ``` + + @method urlForFindAll + @param {String} modelName + @param {DS.SnapshotRecordArray} snapshot + @return {String} url + */ + urlForFindAll(modelName, snapshot) { + return this._buildURL(modelName); + }, + + /** + Builds a URL for a `store.query(type, query)` call. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + host: 'https://api.github.com', + urlForQuery (query, modelName) { + switch(modelName) { + case 'repo': + return `https://api.github.com/orgs/${query.orgId}/repos`; + default: + return this._super(...arguments); + } + } + }); + ``` + + @method urlForQuery + @param {Object} query + @param {String} modelName + @return {String} url + */ + urlForQuery(query, modelName) { + return this._buildURL(modelName); + }, + + /** + Builds a URL for a `store.queryRecord(type, query)` call. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForQueryRecord({ slug }, modelName) { + let baseUrl = this.buildURL(); + return `${baseUrl}/${encodeURIComponent(slug)}`; + } + }); + ``` + + @method urlForQueryRecord + @param {Object} query + @param {String} modelName + @return {String} url + */ + urlForQueryRecord(query, modelName) { + return this._buildURL(modelName); + }, + + /** + Builds a URL for coalesceing multiple `store.findRecord(type, id)` + records into 1 request when the adapter's `coalesceFindRequests` + property is true. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForFindMany(ids, modelName) { + let baseUrl = this.buildURL(); + return `${baseUrl}/coalesce`; + } + }); + ``` + + @method urlForFindMany + @param {Array} ids + @param {String} modelName + @param {Array} snapshots + @return {String} url + */ + urlForFindMany(ids, modelName, snapshots) { + return this._buildURL(modelName); + }, + + /** + Builds a URL for fetching a async hasMany relationship when a url + is not provided by the server. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.JSONAPIAdapter.extend({ + urlForFindHasMany(id, modelName, snapshot) { + let baseUrl = this.buildURL(id, modelName); + return `${baseUrl}/relationships`; + } + }); + ``` + + @method urlForFindHasMany + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url + */ + urlForFindHasMany(id, modelName, snapshot) { + return this._buildURL(modelName, id); + }, + + /** + Builds a URL for fetching a async belongsTo relationship when a url + is not provided by the server. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.JSONAPIAdapter.extend({ + urlForFindBelongsTo(id, modelName, snapshot) { + let baseUrl = this.buildURL(id, modelName); + return `${baseUrl}/relationships`; + } + }); + ``` + + @method urlForFindBelongsTo + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url + */ + urlForFindBelongsTo(id, modelName, snapshot) { + return this._buildURL(modelName, id); + }, + + /** + Builds a URL for a `record.save()` call when the record was created + locally using `store.createRecord()`. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForCreateRecord(modelName, snapshot) { + return this._super(...arguments) + '/new'; + } + }); + ``` + + @method urlForCreateRecord + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url + */ + urlForCreateRecord(modelName, snapshot) { + return this._buildURL(modelName); + }, + + /** + Builds a URL for a `record.save()` call when the record has been update locally. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForUpdateRecord(id, modelName, snapshot) { + return `/${id}/feed?access_token=${snapshot.adapterOptions.token}`; + } + }); + ``` + + @method urlForUpdateRecord + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url + */ + urlForUpdateRecord(id, modelName, snapshot) { + return this._buildURL(modelName, id); + }, + + /** + Builds a URL for a `record.save()` call when the record has been deleted locally. + + Example: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + urlForDeleteRecord(id, modelName, snapshot) { + return this._super(...arguments) + '/destroy'; + } + }); + ``` + + @method urlForDeleteRecord + @param {String} id + @param {String} modelName + @param {DS.Snapshot} snapshot + @return {String} url + */ + urlForDeleteRecord(id, modelName, snapshot) { + return this._buildURL(modelName, id); + }, + + /** + @method urlPrefix + @private + @param {String} path + @param {String} parentURL + @return {String} urlPrefix + */ + urlPrefix(path, parentURL) { + let host = get(this, 'host'); + let namespace = get(this, 'namespace'); + + if (!host || host === '/') { + host = ''; + } + + if (path) { + // Protocol relative url + if (/^\/\//.test(path) || /http(s)?:\/\//.test(path)) { + // Do nothing, the full host is already included. + return path; + + // Absolute path + } else if (path.charAt(0) === '/') { + return `${host}${path}`; + // Relative path + } else { + return `${parentURL}/${path}`; + } + } + + // No path provided + let url = []; + if (host) { url.push(host); } + if (namespace) { url.push(namespace); } + return url.join('/'); + }, + + /** + Determines the pathname for a given type. + + By default, it pluralizes the type's name (for example, + 'post' becomes 'posts' and 'person' becomes 'people'). + + ### Pathname customization + + For example if you have an object LineItem with an + endpoint of "/line_items/". + + ```app/adapters/application.js + import DS from 'ember-data'; + import { decamelize } from '@ember/string'; + import { pluralize } from 'ember-inflector'; + + export default DS.RESTAdapter.extend({ + pathForType: function(modelName) { + var decamelized = decamelize(modelName); + return pluralize(decamelized); + } + }); + ``` + + @method pathForType + @param {String} modelName + @return {String} path + **/ + pathForType(modelName) { + let camelized = camelize(modelName); + return pluralize(camelized); + } +}); diff --git a/addon/-record-data-rfc-private/adapters/errors.js b/addon/-record-data-rfc-private/adapters/errors.js new file mode 100644 index 00000000000..ec8919818cf --- /dev/null +++ b/addon/-record-data-rfc-private/adapters/errors.js @@ -0,0 +1,461 @@ +import { makeArray } from '@ember/array'; +import { isPresent } from '@ember/utils'; +import EmberError from '@ember/error'; +import { assert } from '@ember/debug'; + +const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/; +const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/; +const PRIMARY_ATTRIBUTE_KEY = 'base'; + +/** + A `DS.AdapterError` is used by an adapter to signal that an error occurred + during a request to an external API. It indicates a generic error, and + subclasses are used to indicate specific error states. The following + subclasses are provided: + + - `DS.InvalidError` + - `DS.TimeoutError` + - `DS.AbortError` + - `DS.UnauthorizedError` + - `DS.ForbiddenError` + - `DS.NotFoundError` + - `DS.ConflictError` + - `DS.ServerError` + + To create a custom error to signal a specific error state in communicating + with an external API, extend the `DS.AdapterError`. For example if the + external API exclusively used HTTP `503 Service Unavailable` to indicate + it was closed for maintenance: + + ```app/adapters/maintenance-error.js + import DS from 'ember-data'; + + export default DS.AdapterError.extend({ message: "Down for maintenance." }); + ``` + + This error would then be returned by an adapter's `handleResponse` method: + + ```app/adapters/application.js + import DS from 'ember-data'; + import MaintenanceError from './maintenance-error'; + + export default DS.JSONAPIAdapter.extend({ + handleResponse(status) { + if (503 === status) { + return new MaintenanceError(); + } + + return this._super(...arguments); + } + }); + ``` + + And can then be detected in an application and used to send the user to an + `under-maintenance` route: + + ```app/routes/application.js + import Route from '@ember/routing/route'; + import MaintenanceError from '../adapters/maintenance-error'; + + export default Route.extend({ + actions: { + error(error, transition) { + if (error instanceof MaintenanceError) { + this.transitionTo('under-maintenance'); + return; + } + + // ...other error handling logic + } + } + }); + ``` + + @class AdapterError + @namespace DS +*/ +export function AdapterError(errors, message = 'Adapter operation failed') { + this.isAdapterError = true; + EmberError.call(this, message); + + this.errors = errors || [ + { + title: 'Adapter Error', + detail: message + } + ]; +} + +function extendFn(ErrorClass) { + return function({ message: defaultMessage } = {}) { + return extend(ErrorClass, defaultMessage); + }; +} + +function extend(ParentErrorClass, defaultMessage) { + let ErrorClass = function(errors, message) { + assert('`AdapterError` expects json-api formatted errors array.', Array.isArray(errors || [])); + ParentErrorClass.call(this, errors, message || defaultMessage); + }; + ErrorClass.prototype = Object.create(ParentErrorClass.prototype); + ErrorClass.extend = extendFn(ErrorClass); + + return ErrorClass; +} + +AdapterError.prototype = Object.create(EmberError.prototype); + +AdapterError.extend = extendFn(AdapterError); + +/** + A `DS.InvalidError` is used by an adapter to signal the external API + was unable to process a request because the content was not + semantically correct or meaningful per the API. Usually this means a + record failed some form of server side validation. When a promise + from an adapter is rejected with a `DS.InvalidError` the record will + transition to the `invalid` state and the errors will be set to the + `errors` property on the record. + + For Ember Data to correctly map errors to their corresponding + properties on the model, Ember Data expects each error to be + a valid json-api error object with a `source/pointer` that matches + the property name. For example if you had a Post model that + looked like this. + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + title: DS.attr('string'), + content: DS.attr('string') + }); + ``` + + To show an error from the server related to the `title` and + `content` properties your adapter could return a promise that + rejects with a `DS.InvalidError` object that looks like this: + + ```app/adapters/post.js + import RSVP from 'RSVP'; + import DS from 'ember-data'; + + export default DS.RESTAdapter.extend({ + updateRecord() { + // Fictional adapter that always rejects + return RSVP.reject(new DS.InvalidError([ + { + detail: 'Must be unique', + source: { pointer: '/data/attributes/title' } + }, + { + detail: 'Must not be blank', + source: { pointer: '/data/attributes/content'} + } + ])); + } + }); + ``` + + Your backend may use different property names for your records the + store will attempt extract and normalize the errors using the + serializer's `extractErrors` method before the errors get added to + the the model. As a result, it is safe for the `InvalidError` to + wrap the error payload unaltered. + + @class InvalidError + @namespace DS +*/ +export const InvalidError = extend(AdapterError, + 'The adapter rejected the commit because it was invalid'); + +/** + A `DS.TimeoutError` is used by an adapter to signal that a request + to the external API has timed out. I.e. no response was received from + the external API within an allowed time period. + + An example use case would be to warn the user to check their internet + connection if an adapter operation has timed out: + + ```app/routes/application.js + import Route from '@ember/routing/route'; + import DS from 'ember-data'; + + const { TimeoutError } = DS; + + export default Route.extend({ + actions: { + error(error, transition) { + if (error instanceof TimeoutError) { + // alert the user + alert('Are you still connected to the internet?'); + return; + } + + // ...other error handling logic + } + } + }); + ``` + + @class TimeoutError + @namespace DS +*/ +export const TimeoutError = extend(AdapterError, + 'The adapter operation timed out'); + +/** + A `DS.AbortError` is used by an adapter to signal that a request to + the external API was aborted. For example, this can occur if the user + navigates away from the current page after a request to the external API + has been initiated but before a response has been received. + + @class AbortError + @namespace DS +*/ +export const AbortError = extend(AdapterError, + 'The adapter operation was aborted'); + +/** + A `DS.UnauthorizedError` equates to a HTTP `401 Unauthorized` response + status. It is used by an adapter to signal that a request to the external + API was rejected because authorization is required and has failed or has not + yet been provided. + + An example use case would be to redirect the user to a log in route if a + request is unauthorized: + + ```app/routes/application.js + import Route from '@ember/routing/route'; + import DS from 'ember-data'; + + const { UnauthorizedError } = DS; + + export default Route.extend({ + actions: { + error(error, transition) { + if (error instanceof UnauthorizedError) { + // go to the sign in route + this.transitionTo('login'); + return; + } + + // ...other error handling logic + } + } + }); + ``` + + @class UnauthorizedError + @namespace DS +*/ +export const UnauthorizedError = extend(AdapterError, 'The adapter operation is unauthorized'); + +/** + A `DS.ForbiddenError` equates to a HTTP `403 Forbidden` response status. + It is used by an adapter to signal that a request to the external API was + valid but the server is refusing to respond to it. If authorization was + provided and is valid, then the authenticated user does not have the + necessary permissions for the request. + + @class ForbiddenError + @namespace DS +*/ +export const ForbiddenError = extend(AdapterError, 'The adapter operation is forbidden'); + +/** + A `DS.NotFoundError` equates to a HTTP `404 Not Found` response status. + It is used by an adapter to signal that a request to the external API + was rejected because the resource could not be found on the API. + + An example use case would be to detect if the user has entered a route + for a specific model that does not exist. For example: + + ```app/routes/post.js + import Route from '@ember/routing/route'; + import DS from 'ember-data'; + + const { NotFoundError } = DS; + + export default Route.extend({ + model(params) { + return this.get('store').findRecord('post', params.post_id); + }, + + actions: { + error(error, transition) { + if (error instanceof NotFoundError) { + // redirect to a list of all posts instead + this.transitionTo('posts'); + } else { + // otherwise let the error bubble + return true; + } + } + } + }); + ``` + + @class NotFoundError + @namespace DS +*/ +export const NotFoundError = extend(AdapterError, 'The adapter could not find the resource'); + +/** + A `DS.ConflictError` equates to a HTTP `409 Conflict` response status. + It is used by an adapter to indicate that the request could not be processed + because of a conflict in the request. An example scenario would be when + creating a record with a client generated id but that id is already known + to the external API. + + @class ConflictError + @namespace DS +*/ +export const ConflictError = extend(AdapterError, 'The adapter operation failed due to a conflict'); + +/** + A `DS.ServerError` equates to a HTTP `500 Internal Server Error` response + status. It is used by the adapter to indicate that a request has failed + because of an error in the external API. + + @class ServerError + @namespace DS +*/ +export const ServerError = extend(AdapterError, 'The adapter operation failed due to a server error'); + +/** + Convert an hash of errors into an array with errors in JSON-API format. + + ```javascript + import DS from 'ember-data'; + + const { errorsHashToArray } = DS; + + let errors = { + base: 'Invalid attributes on saving this record', + name: 'Must be present', + age: ['Must be present', 'Must be a number'] + }; + + let errorsArray = errorsHashToArray(errors); + // [ + // { + // title: "Invalid Document", + // detail: "Invalid attributes on saving this record", + // source: { pointer: "/data" } + // }, + // { + // title: "Invalid Attribute", + // detail: "Must be present", + // source: { pointer: "/data/attributes/name" } + // }, + // { + // title: "Invalid Attribute", + // detail: "Must be present", + // source: { pointer: "/data/attributes/age" } + // }, + // { + // title: "Invalid Attribute", + // detail: "Must be a number", + // source: { pointer: "/data/attributes/age" } + // } + // ] + ``` + + @method errorsHashToArray + @public + @namespace + @for DS + @param {Object} errors hash with errors as properties + @return {Array} array of errors in JSON-API format +*/ +export function errorsHashToArray(errors) { + let out = []; + + if (isPresent(errors)) { + Object.keys(errors).forEach((key) => { + let messages = makeArray(errors[key]); + for (let i = 0; i < messages.length; i++) { + let title = 'Invalid Attribute'; + let pointer = `/data/attributes/${key}`; + if (key === PRIMARY_ATTRIBUTE_KEY) { + title = 'Invalid Document'; + pointer = `/data`; + } + out.push({ + title: title, + detail: messages[i], + source: { + pointer: pointer + } + }); + } + }); + } + + return out; +} + +/** + Convert an array of errors in JSON-API format into an object. + + ```javascript + import DS from 'ember-data'; + + const { errorsArrayToHash } = DS; + + let errorsArray = [ + { + title: 'Invalid Attribute', + detail: 'Must be present', + source: { pointer: '/data/attributes/name' } + }, + { + title: 'Invalid Attribute', + detail: 'Must be present', + source: { pointer: '/data/attributes/age' } + }, + { + title: 'Invalid Attribute', + detail: 'Must be a number', + source: { pointer: '/data/attributes/age' } + } + ]; + + let errors = errorsArrayToHash(errorsArray); + // { + // "name": ["Must be present"], + // "age": ["Must be present", "must be a number"] + // } + ``` + + @method errorsArrayToHash + @public + @namespace + @for DS + @param {Array} errors array of errors in JSON-API format + @return {Object} +*/ +export function errorsArrayToHash(errors) { + let out = {}; + + if (isPresent(errors)) { + errors.forEach((error) => { + if (error.source && error.source.pointer) { + let key = error.source.pointer.match(SOURCE_POINTER_REGEXP); + + if (key) { + key = key[2]; + } else if (error.source.pointer.search(SOURCE_POINTER_PRIMARY_REGEXP) !== -1) { + key = PRIMARY_ATTRIBUTE_KEY; + } + + if (key) { + out[key] = out[key] || []; + out[key].push(error.detail || error.title); + } + } + }); + } + + return out; +} diff --git a/addon/-record-data-rfc-private/attr.js b/addon/-record-data-rfc-private/attr.js new file mode 100644 index 00000000000..f4b266d7ace --- /dev/null +++ b/addon/-record-data-rfc-private/attr.js @@ -0,0 +1,135 @@ +import { computed } from '@ember/object'; +import { assert } from '@ember/debug'; + +/** + @module ember-data +*/ + +function getDefaultValue(record, options, key) { + if (typeof options.defaultValue === 'function') { + return options.defaultValue.apply(null, arguments); + } else { + let defaultValue = options.defaultValue; + assert(`Non primitive defaultValues are not supported because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.`, + typeof defaultValue !== 'object' || defaultValue === null); + return defaultValue; + } +} + +function hasValue(internalModel, key) { + return internalModel._modelData.hasAttr(key); +} + +/** + `DS.attr` defines an attribute on a [DS.Model](/api/data/classes/DS.Model.html). + By default, attributes are passed through as-is, however you can specify an + optional type to have the value automatically transformed. + Ember Data ships with four basic transform types: `string`, `number`, + `boolean` and `date`. You can define your own transforms by subclassing + [DS.Transform](/api/data/classes/DS.Transform.html). + + Note that you cannot use `attr` to define an attribute of `id`. + + `DS.attr` takes an optional hash as a second parameter, currently + supported options are: + + - `defaultValue`: Pass a string or a function to be called to set the attribute + to a default value if none is supplied. + + Example + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + username: DS.attr('string'), + email: DS.attr('string'), + verified: DS.attr('boolean', { defaultValue: false }) + }); + ``` + + Default value can also be a function. This is useful it you want to return + a new object for each attribute. + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + username: DS.attr('string'), + email: DS.attr('string'), + settings: DS.attr({ + defaultValue() { + return {}; + } + }) + }); + ``` + + The `options` hash is passed as second argument to a transforms' + `serialize` and `deserialize` method. This allows to configure a + transformation and adapt the corresponding value, based on the config: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + text: DS.attr('text', { + uppercase: true + }) + }); + ``` + + ```app/transforms/text.js + import DS from 'ember-data'; + + export default DS.Transform.extend({ + serialize(value, options) { + if (options.uppercase) { + return value.toUpperCase(); + } + + return value; + }, + + deserialize(value) { + return value; + } + }) + ``` + + @namespace + @method attr + @for DS + @param {String|Object} type the attribute type + @param {Object} options a hash of options + @return {Attribute} +*/ + +export default function attr(type, options) { + if (typeof type === 'object') { + options = type; + type = undefined; + } else { + options = options || {}; + } + + let meta = { + type: type, + isAttribute: true, + options: options + }; + + return computed({ + get(key) { + let internalModel = this._internalModel; + if (hasValue(internalModel, key)) { + return internalModel.getAttributeValue(key); + } else { + return getDefaultValue(this, options, key); + } + }, + set(key, value) { + return this._internalModel.setDirtyAttribute(key, value); + } + }).meta(meta); +} diff --git a/addon/-record-data-rfc-private/core.js b/addon/-record-data-rfc-private/core.js new file mode 100644 index 00000000000..b16369a0ff4 --- /dev/null +++ b/addon/-record-data-rfc-private/core.js @@ -0,0 +1,29 @@ +import Ember from 'ember'; +import VERSION from 'ember-data/version'; + +/** + @module ember-data +*/ + +/** + All Ember Data classes, methods and functions are defined inside of this namespace. + + @class DS + @static +*/ + +/** + @property VERSION + @type String + @static +*/ +const DS = Ember.Namespace.create({ + VERSION: VERSION, + name: "DS" +}); + +if (Ember.libraries) { + Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); +} + +export default DS; diff --git a/addon/-record-data-rfc-private/features.js b/addon/-record-data-rfc-private/features.js new file mode 100644 index 00000000000..8e023905a04 --- /dev/null +++ b/addon/-record-data-rfc-private/features.js @@ -0,0 +1,5 @@ +import Ember from 'ember'; + +export default function isEnabled() { + return Ember.FEATURES.isEnabled(...arguments); +} diff --git a/addon/-record-data-rfc-private/index.js b/addon/-record-data-rfc-private/index.js new file mode 100644 index 00000000000..c99397b872f --- /dev/null +++ b/addon/-record-data-rfc-private/index.js @@ -0,0 +1,60 @@ +// public +export { default as Model } from './system/model/model'; +export { default as Errors } from './system/model/errors'; +export { default as Store } from './system/store'; +export { default as DS } from './core'; +export { default as belongsTo } from './system/relationships/belongs-to'; +export { default as hasMany } from './system/relationships/has-many'; +export { default as BuildURLMixin } from './adapters/build-url-mixin'; +export { default as Snapshot } from './system/snapshot'; +export { default as attr } from './attr'; +export { + AdapterError, + InvalidError, + UnauthorizedError, + ForbiddenError, + NotFoundError, + ConflictError, + ServerError, + TimeoutError, + AbortError, + errorsHashToArray, + errorsArrayToHash +} from './adapters/errors'; + +// maybe public ? +export { default as normalizeModelName } from './system/normalize-model-name'; +export { getOwner, modelHasAttributeOrRelationshipNamedType } from './utils'; +export { default as coerceId } from './system/coerce-id'; +export { default as parseResponseHeaders } from './utils/parse-response-headers'; + +export { default as isEnabled } from './features'; +// `ember-data-model-fragments` relies on `RootState` and `InternalModel` +export { default as RootState } from './system/model/states'; +export { default as InternalModel } from './system/model/internal-model'; +export { default as ModelData } from './system/model/model-data'; + +export { + PromiseArray, + PromiseObject, + PromiseManyArray +} from './system/promise-proxies'; + +export { + RecordArray, + AdapterPopulatedRecordArray +} from './system/record-arrays'; + +export { default as ManyArray } from './system/many-array'; +export { default as RecordArrayManager } from './system/record-array-manager'; +export { default as Relationship } from './system/relationships/state/relationship'; + +export { default as Map } from './system/map'; +export { default as MapWithDefault } from './system/map-with-default'; + +// Should be a different Repo ? +export { default as DebugAdapter } from './system/debug/debug-adapter'; + +// Used by tests +export { default as diffArray } from './system/diff-array'; +export { default as SnapshotRecordArray } from './system/snapshot-record-array'; diff --git a/addon/-record-data-rfc-private/system/backburner.js b/addon/-record-data-rfc-private/system/backburner.js new file mode 100644 index 00000000000..266c37c3b4b --- /dev/null +++ b/addon/-record-data-rfc-private/system/backburner.js @@ -0,0 +1,12 @@ +import Ember from 'ember'; +import { DEBUG } from '@glimmer/env'; + +const backburner = new Ember._Backburner(['normalizeRelationships', 'syncRelationships', 'finished']); + +if (DEBUG) { + Ember.Test.registerWaiter(() => { + return !backburner.currentInstance && !backburner.hasTimers(); + }); +} + +export default backburner; diff --git a/addon/-record-data-rfc-private/system/clone-null.js b/addon/-record-data-rfc-private/system/clone-null.js new file mode 100644 index 00000000000..9972c430fef --- /dev/null +++ b/addon/-record-data-rfc-private/system/clone-null.js @@ -0,0 +1,7 @@ +export default function cloneNull(source) { + let clone = Object.create(null); + for (let key in source) { + clone[key] = source[key]; + } + return clone; +} diff --git a/addon/-record-data-rfc-private/system/coerce-id.js b/addon/-record-data-rfc-private/system/coerce-id.js new file mode 100644 index 00000000000..8f8c305a98d --- /dev/null +++ b/addon/-record-data-rfc-private/system/coerce-id.js @@ -0,0 +1,11 @@ +// Used by the store to normalize IDs entering the store. Despite the fact +// that developers may provide IDs as numbers (e.g., `store.findRecord('person', 1)`), +// it is important that internally we use strings, since IDs may be serialized +// and lose type information. For example, Ember's router may put a record's +// ID into the URL, and if we later try to deserialize that URL and find the +// corresponding record, we will not know if it is a string or a number. +export default function coerceId(id) { + if (id === null || id === undefined || id === '') { return null; } + if (typeof id === 'string') { return id; } + return '' + id; +} diff --git a/addon/-record-data-rfc-private/system/debug/debug-adapter.js b/addon/-record-data-rfc-private/system/debug/debug-adapter.js new file mode 100644 index 00000000000..eca07a7d7df --- /dev/null +++ b/addon/-record-data-rfc-private/system/debug/debug-adapter.js @@ -0,0 +1,126 @@ +/** + @module ember-data +*/ +import { addObserver, removeObserver } from '@ember/object/observers'; + +import { A } from '@ember/array'; +import DataAdapter from '@ember/debug/data-adapter'; +import { capitalize, underscore } from '@ember/string'; +import { assert } from '@ember/debug'; +import { get } from '@ember/object'; +import Model from '../model/model'; + +/* + Extend `Ember.DataAdapter` with ED specific code. + + @class DebugAdapter + @namespace DS + @extends Ember.DataAdapter + @private +*/ +export default DataAdapter.extend({ + getFilters() { + return [ + { name: 'isNew', desc: 'New' }, + { name: 'isModified', desc: 'Modified' }, + { name: 'isClean', desc: 'Clean' } + ]; + }, + + detect(typeClass) { + return typeClass !== Model && Model.detect(typeClass); + }, + + columnsForType(typeClass) { + let columns = [{ + name: 'id', + desc: 'Id' + }]; + let count = 0; + let self = this; + get(typeClass, 'attributes').forEach((meta, name) => { + if (count++ > self.attributeLimit) { return false; } + let desc = capitalize(underscore(name).replace('_', ' ')); + columns.push({ name: name, desc: desc }); + }); + return columns; + }, + + getRecords(modelClass, modelName) { + if (arguments.length < 2) { + // Legacy Ember.js < 1.13 support + let containerKey = modelClass._debugContainerKey; + if (containerKey) { + let match = containerKey.match(/model:(.*)/); + if (match !== null) { + modelName = match[1]; + } + } + } + assert("Cannot find model name. Please upgrade to Ember.js >= 1.13 for Ember Inspector support", !!modelName); + return this.get('store').peekAll(modelName); + }, + + getRecordColumnValues(record) { + let count = 0; + let columnValues = { id: get(record, 'id') }; + + record.eachAttribute((key) => { + if (count++ > this.attributeLimit) { + return false; + } + columnValues[key] = get(record, key); + }); + return columnValues; + }, + + getRecordKeywords(record) { + let keywords = []; + let keys = A(['id']); + record.eachAttribute((key) => keys.push(key)); + keys.forEach((key) => keywords.push(get(record, key))); + return keywords; + }, + + getRecordFilterValues(record) { + return { + isNew: record.get('isNew'), + isModified: record.get('hasDirtyAttributes') && !record.get('isNew'), + isClean: !record.get('hasDirtyAttributes') + }; + }, + + getRecordColor(record) { + let color = 'black'; + if (record.get('isNew')) { + color = 'green'; + } else if (record.get('hasDirtyAttributes')) { + color = 'blue'; + } + return color; + }, + + observeRecord(record, recordUpdated) { + let releaseMethods = A(); + let keysToObserve = A(['id', 'isNew', 'hasDirtyAttributes']); + + record.eachAttribute((key) => keysToObserve.push(key)); + let adapter = this; + + keysToObserve.forEach(function(key) { + let handler = function() { + recordUpdated(adapter.wrapRecord(record)); + }; + addObserver(record, key, handler); + releaseMethods.push(function() { + removeObserver(record, key, handler); + }); + }); + + let release = function() { + releaseMethods.forEach((fn) => fn()); + }; + + return release; + } +}); diff --git a/addon/-record-data-rfc-private/system/diff-array.js b/addon/-record-data-rfc-private/system/diff-array.js new file mode 100644 index 00000000000..ae28e8e35b3 --- /dev/null +++ b/addon/-record-data-rfc-private/system/diff-array.js @@ -0,0 +1,58 @@ +/** + @namespace + @method diffArray + @private + @param {Array} oldArray the old array + @param {Array} newArray the new array + @return {hash} { + firstChangeIndex: , // null if no change + addedCount: , // 0 if no change + removedCount: // 0 if no change + } +*/ +export default function diffArray(oldArray, newArray) { + const oldLength = oldArray.length; + const newLength = newArray.length; + + const shortestLength = Math.min(oldLength, newLength); + let firstChangeIndex = null; // null signifies no changes + + // find the first change + for (let i=0; i 1 + // meta.total => 5 + }); + ``` + + @property {Object} meta + @public + */ + // TODO this is likely broken in our refactor + this.meta = this.meta || null; + + /** + `true` if the relationship is polymorphic, `false` otherwise. + + @property {Boolean} isPolymorphic + @private + */ + this.isPolymorphic = this.isPolymorphic || false; + + /** + The relationship which manages this array. + + @property {ManyRelationship} relationship + @private + */ + this.currentState = []; + this.flushCanonical(this.initialState, false); + }, + + // TODO: if(DEBUG) + anyUnloaded() { + let unloaded = this.currentState.find((im) => im._isDematerializing || !im.isLoaded()); + return !!unloaded; + }, + + removeUnloadedInternalModel() { + for (let i = 0; i < this.currentState.length; ++i) { + let internalModel = this.currentState[i]; + if (internalModel._isDematerializing || !internalModel.isLoaded()) { + this.arrayContentWillChange(i, 1, 0); + this.currentState.splice(i, 1); + this.set('length', this.currentState.length); + this.arrayContentDidChange(i, 1, 0); + return true; + } + } + return false; + }, + + objectAt(index) { + // TODO we likely need to force flush here + /* + if (this.relationship._willUpdateManyArray) { + this.relationship._flushPendingManyArrayUpdates(); + } + */ + let internalModel = this.currentState[index]; + if (internalModel === undefined) { return; } + + return internalModel.getRecord(); + }, + + flushCanonical(toSet, isInitialized = true) { + // It’s possible the parent side of the relationship may have been unloaded by this point + if (!_objectIsAlive(this)) { + return; + } + // diff to find changes + let diff = diffArray(this.currentState, toSet); + if (diff.firstChangeIndex !== null) { // it's null if no change found + // we found a change + this.arrayContentWillChange(diff.firstChangeIndex, diff.removedCount, diff.addedCount); + this.set('length', toSet.length); + this.currentState = toSet.slice(); + this.arrayContentDidChange(diff.firstChangeIndex, diff.removedCount, diff.addedCount); + if (isInitialized && diff.addedCount > 0) { + //notify only on additions + //TODO only notify if unloaded + this.internalModel.manyArrayRecordAdded(this.get('key')); + } + } + }, + + replace(idx, amt, objects) { + let internalModels; + if (amt > 0) { + internalModels = this.currentState.slice(idx, idx+amt); + this.get('modelData').removeFromHasMany(this.get('key'), internalModels.map((im) => im._modelData)); + } + if (objects) { + this.get('modelData').addToHasMany(this.get('key'), objects.map(obj => obj._internalModel._modelData), idx); + //this.get('relationship').addInternalModels(objects.map(obj => obj._internalModel), idx); + } + this.retrieveLatest(); + }, + + // Ok this is kinda funky because if buggy we might lose positions, etc. + // but current code is this way so shouldn't be too big of a problem + retrieveLatest() { + let jsonApi = this.get('modelData').getHasMany(this.get('key')); + // TODO this is odd, why should ManyArray ever tell itself to resync? + let internalModels = this.store._getHasManyByJsonApiResource(jsonApi); + if (jsonApi.meta) { + this.set('meta', jsonApi.meta); + } + this.flushCanonical(internalModels, true); + }, + + /** + Reloads all of the records in the manyArray. If the manyArray + holds a relationship that was originally fetched using a links url + Ember Data will revisit the original links url to repopulate the + relationship. + + If the manyArray holds the result of a `store.query()` reload will + re-run the original query. + + Example + + ```javascript + var user = store.peekRecord('user', 1) + user.login().then(function() { + user.get('permissions').then(function(permissions) { + return permissions.reload(); + }); + }); + ``` + + @method reload + @public + */ + reload() { + // TODO this is odd, we don't ask the store for anything else like this? + return this.get('store').reloadManyArray(this, this.get('internalModel'), this.get('key')); + }, + + /** + Saves all of the records in the `ManyArray`. + + Example + + ```javascript + store.findRecord('inbox', 1).then(function(inbox) { + inbox.get('messages').then(function(messages) { + messages.forEach(function(message) { + message.set('isRead', true); + }); + messages.save() + }); + }); + ``` + + @method save + @return {DS.PromiseArray} promise + */ + save() { + let manyArray = this; + let promiseLabel = 'DS: ManyArray#save ' + get(this, 'type'); + let promise = all(this.invoke("save"), promiseLabel). + then(() => manyArray, null, 'DS: ManyArray#save return ManyArray'); + + return PromiseArray.create({ promise }); + }, + + /** + Create a child record within the owner + + @method createRecord + @private + @param {Object} hash + @return {DS.Model} record + */ + createRecord(hash) { + const store = get(this, 'store'); + const type = get(this, 'type'); + + assert(`You cannot add '${type.modelName}' records to this polymorphic relationship.`, !get(this, 'isPolymorphic')); + let record = store.createRecord(type.modelName, hash); + this.pushObject(record); + + return record; + } +}); diff --git a/addon/-record-data-rfc-private/system/map-with-default.js b/addon/-record-data-rfc-private/system/map-with-default.js new file mode 100644 index 00000000000..69f397e06f3 --- /dev/null +++ b/addon/-record-data-rfc-private/system/map-with-default.js @@ -0,0 +1,21 @@ +import Map from './map'; + +export default class MapWithDefault extends Map { + constructor(options) { + super(); + + this.defaultValue = options.defaultValue; + } + + get(key) { + let hasValue = this.has(key); + + if (hasValue) { + return super.get(key); + } else { + let defaultValue = this.defaultValue(key); + this.set(key, defaultValue); + return defaultValue; + } + } +} diff --git a/addon/-record-data-rfc-private/system/map.js b/addon/-record-data-rfc-private/system/map.js new file mode 100644 index 00000000000..6018913a453 --- /dev/null +++ b/addon/-record-data-rfc-private/system/map.js @@ -0,0 +1,102 @@ +import { deprecate } from '@ember/debug'; + +/* + ## Why does this exist?!? + + `Ember.Map` was a private API provided by Ember (for quite some time). + Unfortunately, ember-data made `Ember.Map` part of its public API surface via + documentation blocks. + + `Ember.Map` will be deprecated and removed from Ember "soon" + (https://github.com/emberjs/rfcs/pull/237) and we would like to confirm that + Ember Data will work without deprecation before and after that happens. + + `Ember.Map` differs from native `Map` in a few ways: + + * `Ember.Map` has custom `copy` and `isEmpty` methods which are not present in native `Map` + * `Ember.Map` adds a static `create` method (which simply instantiates itself with `new Ember.Map()`) + * `Ember.Map` does not accept constructor arguments + * `Ember.Map` does not have: + * `@@species` + * `@@iterator` + * `entries` + * `values` + + This implementation adds a deprecated backwards compatibility for: + + * `copy` + * `isEmpty` + + ## Why is this written this way?!? + + This is needed because `Map` requires instantiation with `new` and by default + Babel transpilation will do `superConstructor.apply(this, arguments)` which + throws an error with native `Map`. + + The desired code (if we lived in an "only native class" world) would be: + + ```js + export default class MapWithDeprecations extends Map { + constructor(options) { + super(); + this.defaultValue = options.defaultValue; + } + + get(key) { + let hasValue = this.has(key); + + if (hasValue) { + return super.get(key); + } else { + let defaultValue = this.defaultValue(key); + this.set(key, defaultValue); + return defaultValue; + } + } + } + ``` +*/ +export default class MapWithDeprecations { + constructor(options) { + this._map = new Map(); + } + + copy() { + deprecate( + 'Calling `.copy()` on a map generated by ember-data is deprecated, please migrate to using native Map functionality only.', + false, + { id: 'ember-data.map.copy', until: '3.5.0' } + ); + + // can't just pass `this._map` here because IE11 doesn't accept + // constructor args with its `Map` + let newMap = new MapWithDeprecations(); + this._map.forEach(function(value, key) { + newMap.set(key, value) + }); + + return newMap; + } + + isEmpty() { + deprecate( + 'Calling `.isEmpty()` on a map generated by ember-data is deprecated, please migrate to using native Map functionality only.', + false, + { id: 'ember-data.map.isEmpty', until: '3.5.0' } + ); + + return this.size === 0; + } + + // proxy all normal Map methods to the underlying Map + get size() { return this._map.size; } + clear() { return this._map.clear(...arguments) } + delete() { return this._map.delete(...arguments) } + entries() { return this._map.entries(...arguments) } + forEach() { return this._map.forEach(...arguments) } + get() { return this._map.get(...arguments) } + has() { return this._map.has(...arguments) } + keys() { return this._map.keys(...arguments) } + set() { return this._map.set(...arguments) } + values() { return this._map.values(...arguments) } +} diff --git a/addon/-record-data-rfc-private/system/model/errors.js b/addon/-record-data-rfc-private/system/model/errors.js new file mode 100644 index 00000000000..b955dc1ef61 --- /dev/null +++ b/addon/-record-data-rfc-private/system/model/errors.js @@ -0,0 +1,409 @@ +import { mapBy, not } from '@ember/object/computed'; +import Evented from '@ember/object/evented'; +import ArrayProxy from '@ember/array/proxy'; +import { set, get, computed } from '@ember/object'; +import { makeArray, A } from '@ember/array'; +import MapWithDefault from '../map-with-default'; +import { warn } from '@ember/debug'; + +/** +@module ember-data +*/ + +/** + Holds validation errors for a given record, organized by attribute names. + + Every `DS.Model` has an `errors` property that is an instance of + `DS.Errors`. This can be used to display validation error + messages returned from the server when a `record.save()` rejects. + + For Example, if you had a `User` model that looked like this: + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + username: DS.attr('string'), + email: DS.attr('string') + }); + ``` + And you attempted to save a record that did not validate on the backend: + + ```javascript + let user = store.createRecord('user', { + username: 'tomster', + email: 'invalidEmail' + }); + user.save(); + ``` + + Your backend would be expected to return an error response that described + the problem, so that error messages can be generated on the app. + + API responses will be translated into instances of `DS.Errors` differently, + depending on the specific combination of adapter and serializer used. You + may want to check the documentation or the source code of the libraries + that you are using, to know how they expect errors to be communicated. + + Errors can be displayed to the user by accessing their property name + to get an array of all the error objects for that property. Each + error object is a JavaScript object with two keys: + + - `message` A string containing the error message from the backend + - `attribute` The name of the property associated with this error message + + ```handlebars + + {{#each model.errors.username as |error|}} +
      + {{error.message}} +
      + {{/each}} + + + {{#each model.errors.email as |error|}} +
      + {{error.message}} +
      + {{/each}} + ``` + + You can also access the special `messages` property on the error + object to get an array of all the error strings. + + ```handlebars + {{#each model.errors.messages as |message|}} +
      + {{message}} +
      + {{/each}} + ``` + + @class Errors + @namespace DS + @extends Ember.Object + @uses Ember.Enumerable + @uses Ember.Evented + */ +export default ArrayProxy.extend(Evented, { + + /** + Register with target handler + + @method _registerHandlers + @private + */ + _registerHandlers(target, becameInvalid, becameValid) { + this.on('becameInvalid', target, becameInvalid); + this.on('becameValid', target, becameValid); + }, + + /** + @property errorsByAttributeName + @type {MapWithDefault} + @private + */ + errorsByAttributeName: computed(function() { + return new MapWithDefault({ + defaultValue() { + return A(); + } + }); + }), + + /** + Returns errors for a given attribute + + ```javascript + let user = store.createRecord('user', { + username: 'tomster', + email: 'invalidEmail' + }); + user.save().catch(function(){ + user.get('errors').errorsFor('email'); // returns: + // [{attribute: "email", message: "Doesn't look like a valid email."}] + }); + ``` + + @method errorsFor + @param {String} attribute + @return {Array} + */ + errorsFor(attribute) { + return get(this, 'errorsByAttributeName').get(attribute); + }, + + /** + An array containing all of the error messages for this + record. This is useful for displaying all errors to the user. + + ```handlebars + {{#each model.errors.messages as |message|}} +
      + {{message}} +
      + {{/each}} + ``` + + @property messages + @type {Array} + */ + messages: mapBy('content', 'message'), + + /** + @property content + @type {Array} + @private + */ + content: computed(function() { + return A(); + }), + + /** + @method unknownProperty + @private + */ + unknownProperty(attribute) { + let errors = this.errorsFor(attribute); + if (errors.length === 0) { return undefined; } + return errors; + }, + + /** + Total number of errors. + + @property length + @type {Number} + @readOnly + */ + + /** + @property isEmpty + @type {Boolean} + @readOnly + */ + isEmpty: not('length').readOnly(), + + /** + Adds error messages to a given attribute and sends + `becameInvalid` event to the record. + + Example: + + ```javascript + if (!user.get('username') { + user.get('errors').add('username', 'This field is required'); + } + ``` + + @method add + @param {String} attribute + @param {(Array|String)} messages + @deprecated + */ + add(attribute, messages) { + warn(`Interacting with a record errors object will no longer change the record state.`, false, { + id: 'ds.errors.add' + }); + + let wasEmpty = get(this, 'isEmpty'); + + this._add(attribute, messages); + + if (wasEmpty && !get(this, 'isEmpty')) { + this.trigger('becameInvalid'); + } + }, + + + /** + Adds error messages to a given attribute without sending event. + + @method _add + @private + */ + _add(attribute, messages) { + messages = this._findOrCreateMessages(attribute, messages); + this.addObjects(messages); + get(this, 'errorsByAttributeName').get(attribute).addObjects(messages); + + this.notifyPropertyChange(attribute); + }, + + /** + @method _findOrCreateMessages + @private + */ + _findOrCreateMessages(attribute, messages) { + let errors = this.errorsFor(attribute); + let messagesArray = makeArray(messages); + let _messages = new Array(messagesArray.length); + + for (let i = 0; i < messagesArray.length; i++) { + let message = messagesArray[i]; + let err = errors.findBy('message', message); + if (err) { + _messages[i] = err; + } else { + _messages[i] = { + attribute: attribute, + message: message + }; + } + } + + return _messages; + }, + + /** + Removes all error messages from the given attribute and sends + `becameValid` event to the record if there no more errors left. + + Example: + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + email: DS.attr('string'), + twoFactorAuth: DS.attr('boolean'), + phone: DS.attr('string') + }); + ``` + + ```app/routes/user/edit.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + actions: { + save: function(user) { + if (!user.get('twoFactorAuth')) { + user.get('errors').remove('phone'); + } + user.save(); + } + } + }); + ``` + + @method remove + @param {String} attribute + @deprecated + */ + remove(attribute) { + warn(`Interacting with a record errors object will no longer change the record state.`, false, { + id: 'ds.errors.remove' + }); + + if (get(this, 'isEmpty')) { return; } + + this._remove(attribute); + + if (get(this, 'isEmpty')) { + this.trigger('becameValid'); + } + }, + + /** + Removes all error messages from the given attribute without sending event. + + @method _remove + @private + */ + _remove(attribute) { + if (get(this, 'isEmpty')) { return; } + + let content = this.rejectBy('attribute', attribute); + set(this, 'content', content); + get(this, 'errorsByAttributeName').delete(attribute); + + this.notifyPropertyChange(attribute); + this.notifyPropertyChange('length'); + }, + + /** + Removes all error messages and sends `becameValid` event + to the record. + + Example: + + ```app/routes/user/edit.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + actions: { + retrySave: function(user) { + user.get('errors').clear(); + user.save(); + } + } + }); + ``` + + @method clear + @deprecated + */ + clear() { + warn(`Interacting with a record errors object will no longer change the record state.`, false, { + id: 'ds.errors.clear' + }); + + if (get(this, 'isEmpty')) { return; } + + this._clear(); + this.trigger('becameValid'); + }, + + + /** + Removes all error messages. + to the record. + + @method _clear + @private + */ + _clear() { + if (get(this, 'isEmpty')) { return; } + + let errorsByAttributeName = get(this, 'errorsByAttributeName'); + let attributes = A(); + + errorsByAttributeName.forEach(function(_, attribute) { + attributes.push(attribute); + }); + + errorsByAttributeName.clear(); + attributes.forEach(function(attribute) { + this.notifyPropertyChange(attribute); + }, this); + + ArrayProxy.prototype.clear.call(this); + }, + + + /** + Checks if there is error messages for the given attribute. + + ```app/routes/user/edit.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + actions: { + save: function(user) { + if (user.get('errors').has('email')) { + return alert('Please update your email before attempting to save.'); + } + user.save(); + } + } + }); + ``` + + @method has + @param {String} attribute + @return {Boolean} true if there some errors on given attribute + */ + has(attribute) { + return this.errorsFor(attribute).length > 0; + } +}); diff --git a/addon/-record-data-rfc-private/system/model/internal-model.js b/addon/-record-data-rfc-private/system/model/internal-model.js new file mode 100644 index 00000000000..3ca0b0b70c5 --- /dev/null +++ b/addon/-record-data-rfc-private/system/model/internal-model.js @@ -0,0 +1,1175 @@ +import { A } from '@ember/array'; +import { set, get } from '@ember/object'; +import EmberError from '@ember/error'; +import { setOwner } from '@ember/application'; +import { run } from '@ember/runloop'; +import RSVP, { Promise } from 'rsvp'; +import Ember from 'ember'; +import { DEBUG } from '@glimmer/env'; +import { assert, inspect } from '@ember/debug'; +import RootState from "./states"; +import Snapshot from "../snapshot"; +import OrderedSet from "../ordered-set"; +import isArrayLike from "../is-array-like"; +import ManyArray from '../many-array'; +import { + PromiseBelongsTo, + PromiseManyArray +} from '../promise-proxies'; +import { getOwner } from '../../utils'; + +import { + RecordReference, + BelongsToReference, + HasManyReference +} from "../references"; + +/* + The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached + when transitioning from one state to another, so that future transitions can replay the + transition without needing to walk the state tree, collect these hook calls and determine + the state to transition into. + + A future optimization would be to build a single chained method out of the collected enters + and setups. It may also be faster to do a two level cache (from: { to }) instead of caching based + on a key that adds the two together. + */ +const TransitionChainMap = Object.create(null); + +const _extractPivotNameCache = Object.create(null); +const _splitOnDotCache = Object.create(null); + +function splitOnDot(name) { + return _splitOnDotCache[name] || ( + _splitOnDotCache[name] = name.split('.') + ); +} + +function extractPivotName(name) { + return _extractPivotNameCache[name] || ( + _extractPivotNameCache[name] = splitOnDot(name)[0] + ); +} + +// this (and all heimdall instrumentation) will be stripped by a babel transform +// https://github.com/heimdalljs/babel5-plugin-strip-heimdall +const { + _triggerDeferredTriggers, + changedAttributes, + createSnapshot, + hasChangedAttributes, + materializeRecord, + new_InternalModel, + send, + setupData, + transitionTo +} = heimdall.registerMonitor('InternalModel', + '_triggerDeferredTriggers', + 'changedAttributes', + 'createSnapshot', + 'hasChangedAttributes', + 'materializeRecord', + 'new_InternalModel', + 'send', + 'setupData', + 'transitionTo' +); + +let InternalModelReferenceId = 1; + +/* + `InternalModel` is the Model class that we use internally inside Ember Data to represent models. + Internal ED methods should only deal with `InternalModel` objects. It is a fast, plain Javascript class. + + We expose `DS.Model` to application code, by materializing a `DS.Model` from `InternalModel` lazily, as + a performance optimization. + + `InternalModel` should never be exposed to application code. At the boundaries of the system, in places + like `find`, `push`, etc. we convert between Models and InternalModels. + + We need to make sure that the properties from `InternalModel` are correctly exposed/proxied on `Model` + if they are needed. + + @private + @class InternalModel +*/ +export default class InternalModel { + constructor(modelName, id, store, data, clientId) { + heimdall.increment(new_InternalModel); + this.id = id; + this.store = store; + this.modelName = modelName; + this.clientId = clientId; + + this._modelData = store._createModelData(modelName, id, clientId, this); + + // this ensure ordered set can quickly identify this as unique + this[Ember.GUID_KEY] = InternalModelReferenceId++ + 'internal-model'; + + this._loadingPromise = null; + this._record = null; + this._isDestroyed = false; + this.isError = false; + this._pendingRecordArrayManagerFlush = false; // used by the recordArrayManager + + // During dematerialization we don't want to rematerialize the record. The + // reason this might happen is that dematerialization removes records from + // record arrays, and Ember arrays will always `objectAt(0)` and + // `objectAt(len - 1)` to test whether or not `firstObject` or `lastObject` + // have changed. + this._isDematerializing = false; + this._scheduledDestroy = null; + + this.resetRecord(); + + // caches for lazy getters + this._modelClass = null; + this.__deferredTriggers = null; + this.__recordArrays = null; + this._references = null; + this._recordReference = null; + + this._manyArrayCache = Object.create(null); + this._retainedManyArrayCache = Object.create(null); + this._relationshipPromisesCache = Object.create(null); + + } + + get modelClass() { + return this._modelClass || (this._modelClass = this.store.modelFor(this.modelName)); + } + + get type() { + return this.modelClass; + } + + get recordReference() { + if (this._recordReference === null) { + this._recordReference = new RecordReference(this.store, this); + } + return this._recordReference; + } + + get _recordArrays() { + if (this.__recordArrays === null) { + this.__recordArrays = OrderedSet.create(); + } + return this.__recordArrays; + } + + get references() { + if (this._references === null) { + this._references = Object.create(null); + } + return this._references; + } + + get _deferredTriggers() { + if (this.__deferredTriggers === null) { + this.__deferredTriggers = []; + } + return this.__deferredTriggers; + } + + isHiddenFromRecordArrays() { + // During dematerialization we don't want to rematerialize the record. + // recordWasDeleted can cause other records to rematerialize because it + // removes the internal model from the array and Ember arrays will always + // `objectAt(0)` and `objectAt(len -1)` to check whether `firstObject` or + // `lastObject` have changed. When this happens we don't want those + // models to rematerialize their records. + + return this._isDematerializing || + this.hasScheduledDestroy() || + this.isDestroyed || + this.currentState.stateName === 'root.deleted.saved' || + this.isEmpty(); + } + + isRecordInUse() { + let record = this._record; + return record && !(record.get('isDestroyed') || record.get('isDestroying')); + } + + isEmpty() { + return this.currentState.isEmpty; + } + + isLoading() { + return this.currentState.isLoading; + } + + isLoaded() { + return this.currentState.isLoaded; + } + + hasDirtyAttributes() { + return this.currentState.hasDirtyAttributes; + } + + isSaving() { + return this.currentState.isSaving; + } + + isDeleted() { + return this.currentState.isDeleted; + } + + isNew() { + return this.currentState.isNew; + } + + isValid() { + return this.currentState.isValid; + } + + dirtyType() { + return this.currentState.dirtyType; + } + + // DO NOT USE : purely to ease the transition in tests + get _attributes() { + return this._modelData._attributes; + } + + // DO NOT USE : purely to ease the transition in tests + get _relationships() { + return this._modelData._relationships; + } + + getRecord(properties) { + if (!this._record && !this._isDematerializing) { + heimdall.increment(materializeRecord); + let token = heimdall.start('InternalModel.getRecord'); + + // lookupFactory should really return an object that creates + // instances with the injections applied + let createOptions = { + store: this.store, + _internalModel: this, + currentState: this.currentState, + isError: this.isError, + adapterError: this.error + }; + + if (properties !== undefined) { + assert(`You passed '${properties}' as properties for record creation instead of an object.`, typeof properties === 'object' && properties !== null); + let classFields = this.getFields(); + // TODO disentangle post-rebase + let relationships = this._modelData._relationships; + let propertyNames = Object.keys(properties); + + for (let i = 0; i < propertyNames.length; i++) { + let name = propertyNames[i]; + let fieldType = classFields.get(name); + let propertyValue = properties[name]; + + if (name === 'id') { + this.setId(propertyValue); + continue; + } + + switch (fieldType) { + case 'attribute': + this.setDirtyAttribute(name, propertyValue); + break; + case 'belongsTo': + this.setDirtyBelongsTo(name, propertyValue); + relationships.get(name).setHasAnyRelationshipData(true); + relationships.get(name).setRelationshipIsEmpty(false); + break; + case 'hasMany': + this.setDirtyHasMany(name, propertyValue); + relationships.get(name).setHasAnyRelationshipData(true); + relationships.get(name).setRelationshipIsEmpty(false); + break; + default: + createOptions[name] = propertyValue; + } + } + } + + if (setOwner) { + // ensure that `getOwner(this)` works inside a model instance + setOwner(createOptions, getOwner(this.store)); + } else { + createOptions.container = this.store.container; + } + + this._record = this.store._modelFactoryFor(this.modelName).create(createOptions); + + this._triggerDeferredTriggers(); + heimdall.stop(token); + } + + return this._record; + } + + getFields() { + return get(this.modelClass, 'fields'); + } + + resetRecord() { + this._record = null; + this.isReloading = false; + this.error = null; + this.currentState = RootState.empty; + } + + dematerializeRecord() { + this._isDematerializing = true; + + // TODO IGOR add a test that fails when this is missing, something that involves canceliing a destroy + // and the destroy not happening, and then later on trying to destroy + this._doNotDestroy = false; + + if (this._record) { + Object.keys(this._relationshipPromisesCache).forEach((key) => { + // TODO Igor cleanup the guard + // TODO there is probably relationship cleanup to do outside of the _record check + if (this._relationshipPromisesCache[key].destroy) { + this._relationshipPromisesCache[key].destroy(); + } + delete this._relationshipPromisesCache[key]; + }); + Object.keys(this._manyArrayCache).forEach((key) => { + this._retainedManyArrayCache[key] = this._manyArrayCache[key]; + delete this._manyArrayCache[key]; + }); + this._record.destroy(); + } + + // move to an empty never-loaded state + this.resetRecord(); + this._modelData.unloadRecord(); + this.updateRecordArrays(); + } + + deleteRecord() { + this.send('deleteRecord'); + } + + save(options) { + let promiseLabel = "DS: Model#save " + this; + let resolver = RSVP.defer(promiseLabel); + + this.store.scheduleSave(this, resolver, options); + return resolver.promise; + } + + startedReloading() { + this.isReloading = true; + if (this.hasRecord) { + set(this._record, 'isReloading', true); + } + } + + linkWasLoadedForRelationship(key, data) { + let relationships = {}; + relationships[key] = data; + this._modelData.pushData({ id: this.id, type: this.modelName, relationships }); + } + + finishedReloading() { + this.isReloading = false; + if (this.hasRecord) { + set(this._record, 'isReloading', false); + } + } + + reload(options) { + this.startedReloading(); + let internalModel = this; + let promiseLabel = "DS: Model#reload of " + this; + + return new Promise(function(resolve) { + internalModel.send('reloadRecord', { resolve, options }); + }, promiseLabel).then(function() { + internalModel.didCleanError(); + return internalModel; + }, function(error) { + internalModel.didError(error); + throw error; + }, "DS: Model#reload complete, update flags").finally(function () { + internalModel.finishedReloading(); + internalModel.updateRecordArrays(); + }); + } + + + /* + Unload the record for this internal model. This will cause the record to be + destroyed and freed up for garbage collection. It will also do a check + for cleaning up internal models. + + This check is performed by first computing the set of related internal + models. If all records in this set are unloaded, then the entire set is + destroyed. Otherwise, nothing in the set is destroyed. + + This means that this internal model will be freed up for garbage collection + once all models that refer to it via some relationship are also unloaded. + */ + unloadRecord() { + if (this.isDestroyed) { return; } + this.send('unloadRecord'); + this.dematerializeRecord(); + if (this._scheduledDestroy === null) { + // TODO: use run.schedule once we drop 1.13 + if (!run.currentRunLoop) { + assert('You have turned on testing mode, which disabled the run-loop\'s autorun.\n You will need to wrap any code with asynchronous side-effects in a run', Ember.testing); + } + this._scheduledDestroy = run.backburner.schedule('destroy', this, '_checkForOrphanedInternalModels') + } + } + + hasScheduledDestroy() { + return !!this._scheduledDestroy; + } + + cancelDestroy() { + assert(`You cannot cancel the destruction of an InternalModel once it has already been destroyed`, !this.isDestroyed); + + this._doNotDestroy = true; + this._isDematerializing = false; + run.cancel(this._scheduledDestroy); + this._scheduledDestroy = null; + } + + // typically, we prefer to async destroy this lets us batch cleanup work. + // Unfortunately, some scenarios where that is not possible. Such as: + // + // ```js + // const record = store.find(‘record’, 1); + // record.unloadRecord(); + // store.createRecord(‘record’, 1); + // ``` + // + // In those scenarios, we make that model's cleanup work, sync. + // + destroySync() { + if (this._isDematerializing) { + this.cancelDestroy(); + } + this._checkForOrphanedInternalModels(); + if (this.isDestroyed || this.isDestroying) { return; } + + // just in-case we are not one of the orphaned, we should still + // still destroy ourselves + this.destroy(); + } + + _checkForOrphanedInternalModels() { + this._isDematerializing = false; + this._scheduledDestroy = null; + if (this.isDestroyed) { return; } + } + + eachRelationship(callback, binding) { + return this.modelClass.eachRelationship(callback, binding); + } + + getBelongsTo(key) { + let resource = this._modelData.getBelongsTo(key); + let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key); + let store = this.store; + let parentInternalModel = this; + let async = relationshipMeta.options.async; + let isAsync = typeof async === 'undefined' ? true : async; + + if (isAsync) { + let internalModel = resource && resource.data ? store._internalModelForResource(resource.data) : null; + return PromiseBelongsTo.create({ + _belongsToState: resource._relationship, + promise: store._findBelongsToByJsonApiResource(resource, parentInternalModel, relationshipMeta), + content: internalModel ? internalModel.getRecord() : null + }); + } else { + if (!resource || !resource.data) { + return null; + } else { + let internalModel = store._internalModelForResource(resource.data); + let toReturn = internalModel.getRecord(); + assert("You looked up the '" + key + "' relationship on a '" + parentInternalModel.modelName + "' with id " + parentInternalModel.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); + return toReturn; + } + } + } + + // TODO Igor consider getting rid of initial state + getManyArray(key) { + let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key); + let jsonApi = this._modelData.getHasMany(key); + let manyArray = this._manyArrayCache[key]; + + assert(`Error: relationship ${this.modelName}:${key} has both many array and retained many array`, !manyArray || !this._retainedManyArrayCache[key]); + + if (!manyArray) { + let initialState = this.store._getHasManyByJsonApiResource(jsonApi); + + manyArray = ManyArray.create({ + store: this.store, + type: this.store.modelFor(relationshipMeta.type), + modelData: this._modelData, + meta: jsonApi.meta, + key, + isPolymorphic: relationshipMeta.options.polymorphic, + initialState: initialState.slice(), + internalModel: this + }); + this._manyArrayCache[key] = manyArray; + } + + if (this._retainedManyArrayCache[key]) { + this._retainedManyArrayCache[key].destroy(); + delete this._retainedManyArrayCache[key]; + } + + return manyArray; + } + + fetchAsyncHasMany(relationshipMeta, jsonApi, manyArray) { + let promise = this.store._findHasManyByJsonApiResource(jsonApi, this, relationshipMeta); + promise = promise.then((initialState) => { + // TODO why don't we do this in the store method + manyArray.retrieveLatest(); + manyArray.set('isLoaded', true); + + return manyArray; + }); + return promise; + } + + getHasMany(key) { + let jsonApi = this._modelData.getHasMany(key); + let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key); + let async = relationshipMeta.options.async; + let isAsync = typeof async === 'undefined' ? true : async; + let manyArray = this.getManyArray(key); + + if (isAsync) { + let promiseArray = this._relationshipPromisesCache[key]; + + if (!promiseArray) { + promiseArray = PromiseManyArray.create({ + promise: this.fetchAsyncHasMany(relationshipMeta, jsonApi, manyArray), + content: manyArray + }); + this._relationshipPromisesCache[key] = promiseArray; + } + + return promiseArray; + } else { + manyArray.set('isLoaded', true); + assert(`You looked up the '${key}' relationship on a '${this.type.modelName}' with id ${this.id} but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async ('DS.hasMany({ async: true })')`, !manyArray.anyUnloaded()); + + return manyArray; + } + } + + _updateLoadingPromiseForHasMany(key, promise, content) { + let loadingPromise = this._relationshipPromisesCache[key]; + if (loadingPromise) { + if (content) { + loadingPromise.set('content', content) + } + loadingPromise.set('promise', promise) + } else { + this._relationshipPromisesCache[key] = PromiseManyArray.create({ + promise, + content + }); + } + + return this._relationshipPromisesCache[key]; + } + + reloadHasMany(key) { + let loadingPromise = this._relationshipPromisesCache[key]; + if (loadingPromise) { + if (loadingPromise.get('isPending')) { + return loadingPromise; + } + /* TODO Igor check wtf this is about + if (loadingPromise.get('isRejected')) { + manyArray.set('isLoaded', manyArrayLoadedState); + } + */ + } + + let jsonApi = this._modelData.getHasMany(key); + jsonApi._relationship.setRelationshipIsStale(true); + let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key); + let manyArray = this.getManyArray(key); + let promise = this.fetchAsyncHasMany(relationshipMeta, jsonApi, manyArray); + + // TODO igor Seems like this would mess with promiseArray wrapping, investigate + this._updateLoadingPromiseForHasMany(key, promise); + return promise; + } + + reloadBelongsTo(key) { + let resource = this._modelData.getBelongsTo(key); + resource._relationship.setRelationshipIsStale(true); + let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key); + + return this.store._findBelongsToByJsonApiResource(resource, this, relationshipMeta); + } + + destroyFromModelData() { + if (this._doNotDestroy) { + this._doNotDestroy = false; + return; + } + this.destroy(); + } + + destroy() { + assert("Cannot destroy an internalModel while its record is materialized", !this._record || this._record.get('isDestroyed') || this._record.get('isDestroying')); + this.isDestroying = true; + Object.keys(this._retainedManyArrayCache).forEach((key) => { + this._retainedManyArrayCache[key].destroy(); + delete this._retainedManyArrayCache[key]; + }); + + this.store._removeFromIdMap(this); + this._isDestroyed = true; + } + + eachAttribute(callback, binding) { + return this.modelClass.eachAttribute(callback, binding); + } + + inverseFor(key) { + return this.modelClass.inverseFor(key); + } + + setupData(data) { + heimdall.increment(setupData); + let changedKeys = this._modelData.pushData(data, this.hasRecord); + if (this.hasRecord) { + this._record._notifyProperties(changedKeys); + } + this.pushedData(); + } + + getAttributeValue(key) { + return this._modelData.getAttr(key); + } + + setDirtyHasMany(key, records) { + assert(`You must pass an array of records to set a hasMany relationship`, isArrayLike(records)); + assert(`All elements of a hasMany relationship must be instances of DS.Model, you passed ${inspect(records)}`, (function() { + return A(records).every((record) => record.hasOwnProperty('_internalModel') === true); + })()); + + // TODO this seems like unnecessary churn + this._modelData.setDirtyHasMany(key, records.map((record) => record.get('_internalModel._modelData').getResourceIdentifier())); + } + + setDirtyBelongsTo(key, value) { + + // TODO this seems like a digression from the pattern in setDirtyHasMany + return this._modelData.setDirtyBelongsTo(key, value); + } + + setDirtyAttribute(key, value) { + if (this.isDeleted()) { + throw new EmberError(`Attempted to set '${key}' to '${value}' on the deleted record ${this}`); + } + + let currentValue = this.getAttributeValue(key); + if (currentValue !== value) { + this._modelData.setDirtyAttribute(key, value); + let isDirty = this._modelData.isAttrDirty(key); + this.send('didSetProperty', { + name: key, + isDirty: isDirty + }); + } + + return value; + } + + get isDestroyed() { + return this._isDestroyed; + } + + get hasRecord() { + return !!this._record; + } + + /* + @method createSnapshot + @private + */ + createSnapshot(options) { + heimdall.increment(createSnapshot); + return new Snapshot(this, options); + } + + /* + @method loadingData + @private + @param {Promise} promise + */ + loadingData(promise) { + this.send('loadingData', promise); + } + + /* + @method loadedData + @private + */ + loadedData() { + this.send('loadedData'); + } + + /* + @method notFound + @private + */ + notFound() { + this.send('notFound'); + } + + /* + @method pushedData + @private + */ + pushedData() { + this.send('pushedData'); + } + + hasChangedAttributes() { + heimdall.increment(hasChangedAttributes); + return this._modelData.hasChangedAttributes(); + } + + /* + Returns an object, whose keys are changed properties, and value is an + [oldProp, newProp] array. + + @method changedAttributes + @private + */ + changedAttributes() { + heimdall.increment(changedAttributes); + return this._modelData.changedAttributes(); + } + + /* + @method adapterWillCommit + @private + */ + adapterWillCommit() { + this._modelData.willCommit(); + this.send('willCommit'); + } + + /* + @method adapterDidDirty + @private + */ + adapterDidDirty() { + this.send('becomeDirty'); + this.updateRecordArrays(); + } + + /* + @method send + @private + @param {String} name + @param {Object} context + */ + send(name, context) { + heimdall.increment(send); + let currentState = this.currentState; + + if (!currentState[name]) { + this._unhandledEvent(currentState, name, context); + } + + return currentState[name](this, context); + } + + manyArrayRecordAdded(key) { + if (this.hasRecord) { + this._record.notifyHasManyAdded(key); + } + } + + notifyHasManyChange(key, record, idx) { + if (this.hasRecord) { + let manyArray = this._manyArrayCache[key]; + if (manyArray) { + // TODO: this will "resurrect" previously unloaded records + // see test '1:many async unload many side' + // in `tests/integration/records/unload-test.js` + // probably we don't want to retrieve latest eagerly when notifyhasmany changed + // but rather lazily when someone actually asks for a manyarray + // + // that said, also not clear why we haven't moved this to retainedmanyarray so maybe that's the bit that's just not workign + manyArray.retrieveLatest(); + // TODO Igor be rigorous about when to delete this + // TODO: igor check for case where we later unload again + if (this._relationshipPromisesCache[key] && manyArray.anyUnloaded()) { + delete this._relationshipPromisesCache[key]; + } + } + this.updateRecordArrays(); + } + } + + notifyBelongsToChange(key, record) { + if (this.hasRecord) { + this._record.notifyBelongsToChanged(key, record); + this.updateRecordArrays(); + } + } + + notifyPropertyChange(key) { + if (this.hasRecord) { + this._record.notifyPropertyChange(key); + this.updateRecordArrays(); + } + let manyArray = this._manyArrayCache[key] || this._retainedManyArrayCache[key]; + if (manyArray) { + let didRemoveUnloadedModel = manyArray.removeUnloadedInternalModel(); + if (this._manyArrayCache[key] && didRemoveUnloadedModel) { + this._retainedManyArrayCache[key] = this._manyArrayCache[key]; + delete this._manyArrayCache[key]; + } + } + if (this._relationshipPromisesCache[key]) { + this._relationshipPromisesCache[key].destroy(); + delete this._relationshipPromisesCache[key]; + } + } + + didCreateRecord() { + this._modelData.clientDidCreate(); + } + + rollbackAttributes() { + let dirtyKeys = this._modelData.rollbackAttributes(); + if (get(this, 'isError')) { + this.didCleanError(); + } + + this.send('rolledBack'); + + if (this._record && dirtyKeys && dirtyKeys.length > 0) { + this._record._notifyProperties(dirtyKeys); + } + } + + /* + @method transitionTo + @private + @param {String} name + */ + transitionTo(name) { + heimdall.increment(transitionTo); + // POSSIBLE TODO: Remove this code and replace with + // always having direct reference to state objects + + let pivotName = extractPivotName(name); + let state = this.currentState; + let transitionMapId = `${state.stateName}->${name}`; + + do { + if (state.exit) { state.exit(this); } + state = state.parentState; + } while (!state[pivotName]); + + let setups; + let enters; + let i; + let l; + let map = TransitionChainMap[transitionMapId]; + + if (map) { + setups = map.setups; + enters = map.enters; + state = map.state; + } else { + setups = []; + enters = []; + + let path = splitOnDot(name); + + for (i = 0, l = path.length; i < l; i++) { + state = state[path[i]]; + + if (state.enter) { enters.push(state); } + if (state.setup) { setups.push(state); } + } + + TransitionChainMap[transitionMapId] = { setups, enters, state }; + } + + for (i = 0, l = enters.length; i < l; i++) { + enters[i].enter(this); + } + + this.currentState = state; + if (this.hasRecord) { + set(this._record, 'currentState', state); + } + + for (i = 0, l = setups.length; i < l; i++) { + setups[i].setup(this); + } + + this.updateRecordArrays(); + } + + _unhandledEvent(state, name, context) { + let errorMessage = "Attempted to handle event `" + name + "` "; + errorMessage += "on " + String(this) + " while in state "; + errorMessage += state.stateName + ". "; + + if (context !== undefined) { + errorMessage += "Called with " + inspect(context) + "."; + } + + throw new EmberError(errorMessage); + } + + triggerLater(...args) { + if (this._deferredTriggers.push(args) !== 1) { + return; + } + + this.store._updateInternalModel(this); + } + + _triggerDeferredTriggers() { + heimdall.increment(_triggerDeferredTriggers); + //TODO: Before 1.0 we want to remove all the events that happen on the pre materialized record, + //but for now, we queue up all the events triggered before the record was materialized, and flush + //them once we have the record + if (!this.hasRecord) { + return; + } + let triggers = this._deferredTriggers; + let record = this._record; + let trigger = record.trigger; + for (let i = 0, l= triggers.length; i { + let preloadValue = get(preload, key); + let relationshipMeta = this.modelClass.metaForProperty(key); + if (relationshipMeta.isRelationship) { + if (!jsonPayload.relationships) { + jsonPayload.relationships = {}; + } + jsonPayload.relationships[key] = this._preloadRelationship(key, preloadValue); + } else { + if (!jsonPayload.attributes) { + jsonPayload.attributes = {}; + } + jsonPayload.attributes[key] = preloadValue; + } + }); + this._modelData.pushData(jsonPayload); + } + + _preloadRelationship(key, preloadValue) { + let relationshipMeta = this.modelClass.metaForProperty(key); + let modelClass = relationshipMeta.type; + let data; + if (relationshipMeta.kind === 'hasMany') { + assert("You need to pass in an array to set a hasMany property on a record", Array.isArray(preloadValue)); + data = preloadValue.map((value) => this._convertPreloadRelationshipToJSON(value, modelClass )); + } else { + data = this._convertPreloadRelationshipToJSON(preloadValue, modelClass); + } + return { data }; + } + + _convertPreloadRelationshipToJSON(value, modelClass) { + if (typeof value === 'string' || typeof value === 'number') { + return { type: modelClass, id: value }; + } + let internalModel; + if (value._internalModel) { + internalModel = value._internalModel; + } else { + internalModel = value; + } + // TODO IGOR DAVID assert if no id is present + return { type: internalModel.modelName, id: internalModel.id }; + } + + /* + Used to notify the store to update FilteredRecordArray membership. + + @method updateRecordArrays + @private + */ + updateRecordArrays() { + this.store.recordArrayManager.recordDidChange(this); + } + + setId(id) { + assert('A record\'s id cannot be changed once it is in the loaded state', this.id === null || this.id === id || this.isNew()); + let didChange = id !== this.id; + this.id = id; + + if (didChange && this.hasRecord) { + this._record.notifyPropertyChange('id'); + } + } + + didError(error) { + this.error = error; + this.isError = true; + + if (this.hasRecord) { + this._record.setProperties({ + isError: true, + adapterError: error + }); + } + } + + didCleanError() { + this.error = null; + this.isError = false; + + if (this.hasRecord) { + this._record.setProperties({ + isError: false, + adapterError: null + }); + } + } + + /* + If the adapter did not return a hash in response to a commit, + merge the changed attributes and relationships into the existing + saved data. + + @method adapterDidCommit + */ + adapterDidCommit(data) { + this.didCleanError(); + + let changedKeys = this._modelData.didCommit(data); + + this.send('didCommit'); + this.updateRecordArrays(); + + if (!data) { return; } + + this._record._notifyProperties(changedKeys); + } + + addErrorMessageToAttribute(attribute, message) { + get(this.getRecord(), 'errors')._add(attribute, message); + } + + removeErrorMessageFromAttribute(attribute) { + get(this.getRecord(), 'errors')._remove(attribute); + } + + clearErrorMessages() { + get(this.getRecord(), 'errors')._clear(); + } + + hasErrors() { + let errors = get(this.getRecord(), 'errors'); + + return errors.get('length') > 0; + } + + // FOR USE DURING COMMIT PROCESS + + /* + @method adapterDidInvalidate + @private + */ + adapterDidInvalidate(errors) { + let attribute; + + for (attribute in errors) { + if (errors.hasOwnProperty(attribute)) { + this.addErrorMessageToAttribute(attribute, errors[attribute]); + } + } + + this.send('becameInvalid'); + + this._modelData.commitWasRejected(); + } + + /* + @method adapterDidError + @private + */ + adapterDidError(error) { + this.send('becameError'); + this.didError(error); + + this._modelData.commitWasRejected(); + } + + toString() { + return `<${this.modelName}:${this.id}>`; + } + + referenceFor(kind, name) { + let reference = this.references[name]; + + if (!reference) { + // TODO IGOR AND DAVID REFACTOR + let relationship = this._modelData._relationships.get(name); + + if (DEBUG) { + let modelName = this.modelName; + assert(`There is no ${kind} relationship named '${name}' on a model of modelClass '${modelName}'`, relationship); + + let actualRelationshipKind = relationship.relationshipMeta.kind; + assert(`You tried to get the '${name}' relationship on a '${modelName}' via record.${kind}('${name}'), but the relationship is of kind '${actualRelationshipKind}'. Use record.${actualRelationshipKind}('${name}') instead.`, actualRelationshipKind === kind); + } + + if (kind === "belongsTo") { + reference = new BelongsToReference(this.store, this, relationship, name); + } else if (kind === "hasMany") { + reference = new HasManyReference(this.store, this, relationship, name); + } + + this.references[name] = reference; + } + + return reference; + } +} diff --git a/addon/-record-data-rfc-private/system/model/model-data.js b/addon/-record-data-rfc-private/system/model/model-data.js new file mode 100644 index 00000000000..238775edd89 --- /dev/null +++ b/addon/-record-data-rfc-private/system/model/model-data.js @@ -0,0 +1,697 @@ +import isEnabled from '../../features'; +import { DEBUG } from '@glimmer/env'; +import Relationships from "../relationships/state/create"; +import { assign } from '@ember/polyfills'; +import { isEqual } from '@ember/utils'; +import { assert, warn, inspect } from '@ember/debug'; +import coerceId from "../coerce-id"; +import { run } from '@ember/runloop'; + +let nextBfsId = 1; +export default class ModelData { + constructor(modelName, id, clientId, storeWrapper, store) { + this.store = store; + this.modelName = modelName; + this.__relationships = null; + this.__implicitRelationships = null; + this.clientId = clientId; + this.id = id; + this.storeWrapper = storeWrapper; + this.isDestroyed = false; + this._isNew = false; + // Used during the mark phase of unloading to avoid checking the same internal + // model twice in the same scan + this._bfsId = 0; + this.reset(); + } + + // PUBLIC API + + getResourceIdentifier() { + return { + id: this.id, + type: this.modelName, + clientId: this.clientId + } + } + + pushData(data, calculateChange) { + let changedKeys; + + if (calculateChange) { + changedKeys = this._changedKeys(data.attributes); + } + + assign(this._data, data.attributes); + if (this.__attributes) { + // only do if we have attribute changes + this._updateChangedAttributes(); + } + + if (data.relationships) { + this._setupRelationships(data); + } + + if (data.id) { + this.id = coerceId(data.id); + } + + return changedKeys; + } + + willCommit() { + this._inFlightAttributes = this._attributes; + this._attributes = null; + } + + hasChangedAttributes() { + return this.__attributes !== null && Object.keys(this.__attributes).length > 0; + } + + // this is a hack bc we don't have access to the state machine + // and relationships need this info and @runspired didn't see + // how to get it just yet from storeWrapper. + isEmpty() { + return this.__attributes === null && + this.__inFlightAttributes === null && + this.__data === null; + } + + reset() { + this.__attributes = null; + this.__inFlightAttributes = null; + this.__data = null; + } + + _setupRelationships(data) { + let relationships = this.storeWrapper.relationshipsDefinitionFor(this.modelName); + let keys = Object.keys(relationships); + for (let i=0; i < keys.length; i++) { + let relationshipName = keys[i]; + + if (!data.relationships[relationshipName]) { + continue; + } + + // in debug, assert payload validity eagerly + let relationshipData = data.relationships[relationshipName]; + if (DEBUG) { + let store = this.store; + let modelData = this; + let relationshipMeta = relationships[relationshipName]; + if (!relationshipData || !relationshipMeta) { + continue; + } + + // eslint-disable-next-line no-inner-declarations + function assertRelationshipData(store, modelData, data, meta) { + assert( + `Encountered a relationship identifier without a type for the ${meta.kind} relationship '${meta.key}' on ${modelData}, expected a json-api identifier with type '${meta.type}'.`, + data === null || (typeof data.type === 'string' && data.type.length) + ); + assert( + `Encountered a relationship identifier without an id for the ${meta.kind} relationship '${meta.key}' on ${modelData}, expected a json-api identifier.`, + data === null || data.id || data.id === 0 + ); + assert( + `Encountered a relationship identifier with type '${ + data.type + }' for the ${meta.kind} relationship '${meta.key}' on ${ + modelData + }, Expected a json-api identifier with type '${ + meta.type + }'. No model was found for '${data.type}'.`, + data === null || !data.type || store._hasModelFor(data.type) + ); + } + + if (relationshipData.links) { + let isAsync = relationshipMeta.options && relationshipMeta.options.async !== false; + warn(`You pushed a record of type '${this.modelName}' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, isAsync || relationshipData.data , { + id: 'ds.store.push-link-for-sync-relationship' + }); + } else if (relationshipData.data) { + if (relationshipMeta.kind === 'belongsTo') { + assert(`A ${this.modelName} record was pushed into the store with the value of ${relationshipName} being ${inspect(relationshipData.data)}, but ${relationshipName} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(relationshipData.data)); + assertRelationshipData(store, modelData, relationshipData.data, relationshipMeta); + } else if (relationshipMeta.kind === 'hasMany') { + assert(`A ${this.modelName} record was pushed into the store with the value of ${relationshipName} being '${inspect(relationshipData.data)}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(relationshipData.data)); + if (Array.isArray(relationshipData.data)) { + for (let i = 0; i < relationshipData.data.length; i++) { + assertRelationshipData(store, modelData, relationshipData.data[i], relationshipMeta); + } + } + } + } + } + let relationship = this._relationships.get(relationshipName); + + relationship.push(relationshipData); + } + } + + /* + Checks if the attributes which are considered as changed are still + different to the state which is acknowledged by the server. + + This method is needed when data for the internal model is pushed and the + pushed data might acknowledge dirty attributes as confirmed. + + @method updateChangedAttributes + @private + */ + _updateChangedAttributes() { + let changedAttributes = this.changedAttributes(); + let changedAttributeNames = Object.keys(changedAttributes); + let attrs = this._attributes; + + for (let i = 0, length = changedAttributeNames.length; i < length; i++) { + let attribute = changedAttributeNames[i]; + let data = changedAttributes[attribute]; + let oldData = data[0]; + let newData = data[1]; + + if (oldData === newData) { + delete attrs[attribute]; + } + } + } + + /* + Returns an object, whose keys are changed properties, and value is an + [oldProp, newProp] array. + + @method changedAttributes + @private + */ + changedAttributes() { + let oldData = this._data; + let currentData = this._attributes; + let inFlightData = this._inFlightAttributes; + let newData = assign({}, inFlightData, currentData); + let diffData = Object.create(null); + let newDataKeys = Object.keys(newData); + + for (let i = 0, length = newDataKeys.length; i < length; i++) { + let key = newDataKeys[i]; + diffData[key] = [oldData[key], newData[key]]; + } + + return diffData; + } + + isNew() { + return this._isNew; + } + + rollbackAttributes() { + let dirtyKeys; + if (this.hasChangedAttributes()) { + dirtyKeys = Object.keys(this._attributes); + this._attributes = null; + } + + if (this.isNew()) { + this.removeFromInverseRelationships(true); + } + + this._inFlightAttributes = null; + + return dirtyKeys; + } + + didCommit(data) { + this._isNew = false; + if (data) { + // this.store._internalModelDidReceiveRelationshipData(this.modelName, this.id, data.relationships); + if (data.relationships) { + this._setupRelationships(data); + } + if (data.id) { + // didCommit provided an ID, notify the store of it + this.storeWrapper.setRecordId(this.modelName, data.id, this.clientId); + this.id = coerceId(data.id); + } + data = data.attributes; + } + let changedKeys = this._changedKeys(data); + + assign(this._data, this.__inFlightAttributes, data); + + this._inFlightAttributes = null; + + this._updateChangedAttributes(); + return changedKeys; + } + + // get ResourceIdentifiers for "current state" + // TODO should this return ModelDatas for API consistency? + getHasMany(key) { + return this._relationships.get(key).getData(); + } + + // set a new "current state" via ResourceIdentifiers + // TODO should this take in ModelDatas for API consistency? + setDirtyHasMany(key, resources) { + let relationship = this._relationships.get(key); + relationship.clear(); + relationship.addModelDatas(resources.map(resource => this.storeWrapper.modelDataFor(resource.type, resource.id, resource.clientId))); + } + + // append to "current state" via ModelDatas + // TODO should this take in ResourceIdentifiers for API consistency? + addToHasMany(key, modelDatas, idx) { + this._relationships.get(key).addModelDatas(modelDatas, idx); + } + + // remove from "current state" via ModelDatas + // TODO should this take in ResourceIdentifiers for API consistency? + removeFromHasMany(key, modelDatas) { + this._relationships.get(key).removeModelDatas(modelDatas); + } + + commitWasRejected() { + let keys = Object.keys(this._inFlightAttributes); + if (keys.length > 0) { + let attrs = this._attributes; + for (let i=0; i < keys.length; i++) { + if (attrs[keys[i]] === undefined) { + attrs[keys[i]] = this._inFlightAttributes[keys[i]]; + } + } + } + this._inFlightAttributes = null; + } + + getBelongsTo(key) { + return this._relationships.get(key).getData(); + } + + setDirtyBelongsTo(key, value) { + if (value === undefined) { + value = null; + } + + if (value && value.then) { + this._relationships.get(key).setRecordPromise(value); + } else if (value) { + this._relationships.get(key).setModelData(value._internalModel._modelData); + } else { + this._relationships.get(key).setModelData(value); + } + } + + setDirtyAttribute(key, value) { + let originalValue; + // Add the new value to the changed attributes hash + this._attributes[key] = value; + + if (key in this._inFlightAttributes) { + originalValue = this._inFlightAttributes[key]; + } else { + originalValue = this._data[key]; + } + // If we went back to our original value, we shouldn't keep the attribute around anymore + if (value === originalValue) { + delete this._attributes[key]; + } + } + + getAttr(key) { + if (key in this._attributes) { + return this._attributes[key]; + } else if (key in this._inFlightAttributes) { + return this._inFlightAttributes[key]; + } else { + return this._data[key]; + } + } + + hasAttr(key) { + return key in this._attributes || + key in this._inFlightAttributes || + key in this._data; + } + + unloadRecord() { + if (this.isDestroyed) { + return; + } + this._destroyRelationships(); + this.reset(); + if (!this._scheduledDestroy) { + this._scheduledDestroy = run.backburner.schedule('destroy', this, '_cleanupOrphanedModelDatas') + } + } + + _cleanupOrphanedModelDatas() { + let relatedModelDatas = this._allRelatedModelDatas(); + if (areAllModelsUnloaded(relatedModelDatas)) { + for (let i=0; i rel.destroy()); + this.isDestroyed = true; + this.storeWrapper.disconnectRecord(this.modelName, this.id, this.clientId); + } + + isRecordInUse() { + return this.storeWrapper.isRecordInUse(this.modelName, this.id, this.clientId); + } + + /** + Computes the set of internal models reachable from `this` across exactly one + relationship. + + @return {Array} An array containing the internal models that `this` belongs + to or has many. + + */ + _directlyRelatedModelDatas() { + let array = []; + + this._relationships.forEach((name, rel) => { + let members = rel.members.list; + let canonicalMembers = rel.canonicalMembers.list; + array = array.concat(members, canonicalMembers); + }); + return array; + } + + /** + Computes the set of internal models reachable from this internal model. + + Reachability is determined over the relationship graph (ie a graph where + nodes are internal models and edges are belongs to or has many + relationships). + + @return {Array} An array including `this` and all internal models reachable + from `this`. + */ + _allRelatedModelDatas() { + let array = []; + let queue = []; + let bfsId = nextBfsId++; + queue.push(this); + this._bfsId = bfsId; + while (queue.length > 0) { + let node = queue.shift(); + array.push(node); + let related = node._directlyRelatedModelDatas(); + for (let i=0; i { + rel.removeCompletelyFromInverse(); + if (isNew === true) { + rel.clear(); + } + }); + + let implicitRelationships = this._implicitRelationships; + this.__implicitRelationships = null; + + Object.keys(implicitRelationships).forEach((key) => { + let rel = implicitRelationships[key]; + + rel.removeCompletelyFromInverse(); + if (isNew === true) { + rel.clear(); + } + }); + } + + _destroyRelationships() { + let relationships = this._relationships; + relationships.forEach((name, rel) => destroyRelationship(rel)); + + let implicitRelationships = this._implicitRelationships; + this.__implicitRelationships = null; + Object.keys(implicitRelationships).forEach((key) => { + let rel = implicitRelationships[key]; + destroyRelationship(rel); + }); + } + + clientDidCreate() { + this._isNew = true; + } + + + /* + Ember Data has 3 buckets for storing the value of an attribute on an internalModel. + + `_data` holds all of the attributes that have been acknowledged by + a backend via the adapter. When rollbackAttributes is called on a model all + attributes will revert to the record's state in `_data`. + + `_attributes` holds any change the user has made to an attribute + that has not been acknowledged by the adapter. Any values in + `_attributes` are have priority over values in `_data`. + + `_inFlightAttributes`. When a record is being synced with the + backend the values in `_attributes` are copied to + `_inFlightAttributes`. This way if the backend acknowledges the + save but does not return the new state Ember Data can copy the + values from `_inFlightAttributes` to `_data`. Without having to + worry about changes made to `_attributes` while the save was + happenign. + + + Changed keys builds a list of all of the values that may have been + changed by the backend after a successful save. + + It does this by iterating over each key, value pair in the payload + returned from the server after a save. If the `key` is found in + `_attributes` then the user has a local changed to the attribute + that has not been synced with the server and the key is not + included in the list of changed keys. + + + + If the value, for a key differs from the value in what Ember Data + believes to be the truth about the backend state (A merger of the + `_data` and `_inFlightAttributes` objects where + `_inFlightAttributes` has priority) then that means the backend + has updated the value and the key is added to the list of changed + keys. + + @method _changedKeys + @private + */ + /* + TODO IGOR DAVID + There seems to be a potential bug here, where we will return keys that are not + in the schema + */ + _changedKeys(updates) { + let changedKeys = []; + + if (updates) { + let original, i, value, key; + let keys = Object.keys(updates); + let length = keys.length; + let hasAttrs = this.hasChangedAttributes(); + let attrs; + if (hasAttrs) { + attrs= this._attributes; + } + + original = assign(Object.create(null), this._data, this.__inFlightAttributes); + + for (i = 0; i < length; i++) { + key = keys[i]; + value = updates[key]; + + // A value in _attributes means the user has a local change to + // this attributes. We never override this value when merging + // updates from the backend so we should not sent a change + // notification if the server value differs from the original. + if (hasAttrs === true && attrs[key] !== undefined) { + continue; + } + + if (!isEqual(original[key], value)) { + changedKeys.push(key); + } + } + } + + return changedKeys; + } + + toString() { + return `<${this.modelName}:${this.id}>`; + } + +} + +if (isEnabled('ds-rollback-attribute')) { + /* + Returns the latest truth for an attribute - the canonical value, or the + in-flight value. + + @method lastAcknowledgedValue + @private + */ + ModelData.prototype.lastAcknowledgedValue = function lastAcknowledgedValue(key) { + if (key in this._inFlightAttributes) { + return this._inFlightAttributes[key]; + } else { + return this._data[key]; + } + }; +} + +// Handle dematerialization for relationship `rel`. In all cases, notify the +// relatinoship of the dematerialization: this is done so the relationship can +// notify its inverse which needs to update state +// +// If the inverse is sync, unloading this record is treated as a client-side +// delete, so we remove the inverse records from this relationship to +// disconnect the graph. Because it's not async, we don't need to keep around +// the internalModel as an id-wrapper for references and because the graph is +// disconnected we can actually destroy the internalModel when checking for +// orphaned models. +function destroyRelationship(rel) { + rel.modelDataDidDematerialize(); + + if (rel._inverseIsSync()) { + rel.removeAllModelDatasFromOwn(); + rel.removeAllCanonicalModelDatasFromOwn(); + } +} + +function areAllModelsUnloaded(modelDatas) { + for (let i=0; i { + let optionsForRelationship = inverseType.metaForProperty(relationship.name).options; + + if (!optionsForRelationship.inverse && optionsForRelationship.inverse !== null) { + return true; + } + + return name === optionsForRelationship.inverse; + }); + + if (relationships) { + possibleRelationships.push.apply(possibleRelationships, relationships); + } + + //Recurse to support polymorphism + if (type.superclass) { + findPossibleInverses(type.superclass, inverseType, name, possibleRelationships); + } + + return possibleRelationships; +} + +function intersection (array1, array2) { + let result = []; + array1.forEach((element) => { + if (array2.indexOf(element) >= 0) { + result.push(element); + } + }); + + return result; +} + +const RESERVED_MODEL_PROPS = [ + 'currentState', 'data', 'store' +]; + +const retrieveFromCurrentState = computed('currentState', function(key) { + return get(this._internalModel.currentState, key); +}).readOnly(); + +/** + + The model class that all Ember Data records descend from. + This is the public API of Ember Data models. If you are using Ember Data + in your application, this is the class you should use. + If you are working on Ember Data internals, you most likely want to be dealing + with `InternalModel` + + @class Model + @namespace DS + @extends Ember.Object + @uses Ember.Evented +*/ +const Model = EmberObject.extend(Evented, { + _internalModel: null, + store: null, + __defineNonEnumerable(property) { + this[property.name] = property.descriptor.value; + }, + + /** + If this property is `true` the record is in the `empty` + state. Empty is the first state all records enter after they have + been created. Most records created by the store will quickly + transition to the `loading` state if data needs to be fetched from + the server or the `created` state if the record is created on the + client. A record can also enter the empty state if the adapter is + unable to locate the record. + + @property isEmpty + @type {Boolean} + @readOnly + */ + isEmpty: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `loading` state. A + record enters this state when the store asks the adapter for its + data. It remains in this state until the adapter provides the + requested data. + + @property isLoading + @type {Boolean} + @readOnly + */ + isLoading: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `loaded` state. A + record enters this state when its data is populated. Most of a + record's lifecycle is spent inside substates of the `loaded` + state. + + Example + + ```javascript + let record = store.createRecord('model'); + record.get('isLoaded'); // true + + store.findRecord('model', 1).then(function(model) { + model.get('isLoaded'); // true + }); + ``` + + @property isLoaded + @type {Boolean} + @readOnly + */ + isLoaded: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `dirty` state. The + record has local changes that have not yet been saved by the + adapter. This includes records that have been created (but not yet + saved) or deleted. + + Example + + ```javascript + let record = store.createRecord('model'); + record.get('hasDirtyAttributes'); // true + + store.findRecord('model', 1).then(function(model) { + model.get('hasDirtyAttributes'); // false + model.set('foo', 'some value'); + model.get('hasDirtyAttributes'); // true + }); + ``` + + @since 1.13.0 + @property hasDirtyAttributes + @type {Boolean} + @readOnly + */ + hasDirtyAttributes: computed('currentState.isDirty', function() { + return this.get('currentState.isDirty'); + }), + /** + If this property is `true` the record is in the `saving` state. A + record enters the saving state when `save` is called, but the + adapter has not yet acknowledged that the changes have been + persisted to the backend. + + Example + + ```javascript + let record = store.createRecord('model'); + record.get('isSaving'); // false + let promise = record.save(); + record.get('isSaving'); // true + promise.then(function() { + record.get('isSaving'); // false + }); + ``` + + @property isSaving + @type {Boolean} + @readOnly + */ + isSaving: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `deleted` state + and has been marked for deletion. When `isDeleted` is true and + `hasDirtyAttributes` is true, the record is deleted locally but the deletion + was not yet persisted. When `isSaving` is true, the change is + in-flight. When both `hasDirtyAttributes` and `isSaving` are false, the + change has persisted. + + Example + + ```javascript + let record = store.createRecord('model'); + record.get('isDeleted'); // false + record.deleteRecord(); + + // Locally deleted + record.get('isDeleted'); // true + record.get('hasDirtyAttributes'); // true + record.get('isSaving'); // false + + // Persisting the deletion + let promise = record.save(); + record.get('isDeleted'); // true + record.get('isSaving'); // true + + // Deletion Persisted + promise.then(function() { + record.get('isDeleted'); // true + record.get('isSaving'); // false + record.get('hasDirtyAttributes'); // false + }); + ``` + + @property isDeleted + @type {Boolean} + @readOnly + */ + isDeleted: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `new` state. A + record will be in the `new` state when it has been created on the + client and the adapter has not yet report that it was successfully + saved. + + Example + + ```javascript + let record = store.createRecord('model'); + record.get('isNew'); // true + + record.save().then(function(model) { + model.get('isNew'); // false + }); + ``` + + @property isNew + @type {Boolean} + @readOnly + */ + isNew: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `valid` state. + + A record will be in the `valid` state when the adapter did not report any + server-side validation failures. + + @property isValid + @type {Boolean} + @readOnly + */ + isValid: retrieveFromCurrentState, + /** + If the record is in the dirty state this property will report what + kind of change has caused it to move into the dirty + state. Possible values are: + + - `created` The record has been created by the client and not yet saved to the adapter. + - `updated` The record has been updated by the client and not yet saved to the adapter. + - `deleted` The record has been deleted by the client and not yet saved to the adapter. + + Example + + ```javascript + let record = store.createRecord('model'); + record.get('dirtyType'); // 'created' + ``` + + @property dirtyType + @type {String} + @readOnly + */ + dirtyType: retrieveFromCurrentState, + + /** + If `true` the adapter reported that it was unable to save local + changes to the backend for any reason other than a server-side + validation error. + + Example + + ```javascript + record.get('isError'); // false + record.set('foo', 'valid value'); + record.save().then(null, function() { + record.get('isError'); // true + }); + ``` + + @property isError + @type {Boolean} + @readOnly + */ + isError: false, + + /** + If `true` the store is attempting to reload the record from the adapter. + + Example + + ```javascript + record.get('isReloading'); // false + record.reload(); + record.get('isReloading'); // true + ``` + + @property isReloading + @type {Boolean} + @readOnly + */ + isReloading: false, + + /** + All ember models have an id property. This is an identifier + managed by an external source. These are always coerced to be + strings before being used internally. Note when declaring the + attributes for a model it is an error to declare an id + attribute. + + ```javascript + let record = store.createRecord('model'); + record.get('id'); // null + + store.findRecord('model', 1).then(function(model) { + model.get('id'); // '1' + }); + ``` + + @property id + @type {String} + */ + + /** + @property currentState + @private + @type {Object} + */ + currentState: RootState.empty, + + /** + When the record is in the `invalid` state this object will contain + any errors returned by the adapter. When present the errors hash + contains keys corresponding to the invalid property names + and values which are arrays of Javascript objects with two keys: + + - `message` A string containing the error message from the backend + - `attribute` The name of the property associated with this error message + + ```javascript + record.get('errors.length'); // 0 + record.set('foo', 'invalid value'); + record.save().catch(function() { + record.get('errors').get('foo'); + // [{message: 'foo should be a number.', attribute: 'foo'}] + }); + ``` + + The `errors` property us useful for displaying error messages to + the user. + + ```handlebars + + {{#each model.errors.username as |error|}} +
      + {{error.message}} +
      + {{/each}} + + {{#each model.errors.email as |error|}} +
      + {{error.message}} +
      + {{/each}} + ``` + + + You can also access the special `messages` property on the error + object to get an array of all the error strings. + + ```handlebars + {{#each model.errors.messages as |message|}} +
      + {{message}} +
      + {{/each}} + ``` + + @property errors + @type {DS.Errors} + */ + errors: computed(function() { + let errors = Errors.create(); + + errors._registerHandlers(this._internalModel, + function() { + this.send('becameInvalid'); + }, + function() { + this.send('becameValid'); + }); + return errors; + }).readOnly(), + + /** + This property holds the `DS.AdapterError` object with which + last adapter operation was rejected. + + @property adapterError + @type {DS.AdapterError} + */ + adapterError: null, + + /** + Create a JSON representation of the record, using the serialization + strategy of the store's adapter. + + `serialize` takes an optional hash as a parameter, currently + supported options are: + + - `includeId`: `true` if the record's ID should be included in the + JSON representation. + + @method serialize + @param {Object} options + @return {Object} an object whose values are primitive JSON values only + */ + serialize(options) { + return this._internalModel.createSnapshot().serialize(options); + }, + + /** + Use [DS.JSONSerializer](DS.JSONSerializer.html) to + get the JSON representation of a record. + + `toJSON` takes an optional hash as a parameter, currently + supported options are: + + - `includeId`: `true` if the record's ID should be included in the + JSON representation. + + @method toJSON + @param {Object} options + @return {Object} A JSON representation of the object. + */ + toJSON(options) { + // container is for lazy transform lookups + let serializer = this.store.serializerFor('-default'); + let snapshot = this._internalModel.createSnapshot(); + + return serializer.serialize(snapshot, options); + }, + + /** + Fired when the record is ready to be interacted with, + that is either loaded from the server or created locally. + + @event ready + */ + ready: null, + + /** + Fired when the record is loaded from the server. + + @event didLoad + */ + didLoad: null, + + /** + Fired when the record is updated. + + @event didUpdate + */ + didUpdate: null, + + /** + Fired when a new record is commited to the server. + + @event didCreate + */ + didCreate: null, + + /** + Fired when the record is deleted. + + @event didDelete + */ + didDelete: null, + + /** + Fired when the record becomes invalid. + + @event becameInvalid + */ + becameInvalid: null, + + /** + Fired when the record enters the error state. + + @event becameError + */ + becameError: null, + + /** + Fired when the record is rolled back. + + @event rolledBack + */ + rolledBack: null, + + //TODO Do we want to deprecate these? + /** + @method send + @private + @param {String} name + @param {Object} context + */ + send(name, context) { + return this._internalModel.send(name, context); + }, + + /** + @method transitionTo + @private + @param {String} name + */ + transitionTo(name) { + return this._internalModel.transitionTo(name); + }, + + + /** + Marks the record as deleted but does not save it. You must call + `save` afterwards if you want to persist it. You might use this + method if you want to allow the user to still `rollbackAttributes()` + after a delete was made. + + Example + + ```app/routes/model/delete.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + actions: { + softDelete() { + this.get('controller.model').deleteRecord(); + }, + confirm() { + this.get('controller.model').save(); + }, + undo() { + this.get('controller.model').rollbackAttributes(); + } + } + }); + ``` + + @method deleteRecord + */ + deleteRecord() { + this._internalModel.deleteRecord(); + }, + + /** + Same as `deleteRecord`, but saves the record immediately. + + Example + + ```app/routes/model/delete.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + actions: { + delete() { + this.get('controller.model').destroyRecord().then(function() { + controller.transitionToRoute('model.index'); + }); + } + } + }); + ``` + + If you pass an object on the `adapterOptions` property of the options + argument it will be passed to your adapter via the snapshot + + ```js + record.destroyRecord({ adapterOptions: { subscribe: false } }); + ``` + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + deleteRecord(store, type, snapshot) { + if (snapshot.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + + @method destroyRecord + @param {Object} options + @return {Promise} a promise that will be resolved when the adapter returns + successfully or rejected if the adapter returns with an error. + */ + destroyRecord(options) { + this.deleteRecord(); + return this.save(options); + }, + + /** + Unloads the record from the store. This will cause the record to be destroyed and freed up for garbage collection. + + @method unloadRecord + */ + unloadRecord() { + if (this.isDestroyed) { return; } + this._internalModel.unloadRecord(); + }, + + /** + @method _notifyProperties + @private + */ + _notifyProperties(keys) { + // changeProperties defers notifications until after the delegate + // and protects with a try...finally block + // previously used begin...endPropertyChanges but this is private API + changeProperties(() => { + let key; + for (let i = 0, length = keys.length; i < length; i++) { + key = keys[i]; + this.notifyPropertyChange(key); + } + }); + }, + + /** + Returns an object, whose keys are changed properties, and value is + an [oldProp, newProp] array. + + The array represents the diff of the canonical state with the local state + of the model. Note: if the model is created locally, the canonical state is + empty since the adapter hasn't acknowledged the attributes yet: + + Example + + ```app/models/mascot.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + name: DS.attr('string'), + isAdmin: DS.attr('boolean', { + defaultValue: false + }) + }); + ``` + + ```javascript + let mascot = store.createRecord('mascot'); + + mascot.changedAttributes(); // {} + + mascot.set('name', 'Tomster'); + mascot.changedAttributes(); // { name: [undefined, 'Tomster'] } + + mascot.set('isAdmin', true); + mascot.changedAttributes(); // { isAdmin: [undefined, true], name: [undefined, 'Tomster'] } + + mascot.save().then(function() { + mascot.changedAttributes(); // {} + + mascot.set('isAdmin', false); + mascot.changedAttributes(); // { isAdmin: [true, false] } + }); + ``` + + @method changedAttributes + @return {Object} an object, whose keys are changed properties, + and value is an [oldProp, newProp] array. + */ + changedAttributes() { + return this._internalModel.changedAttributes(); + }, + + //TODO discuss with tomhuda about events/hooks + //Bring back as hooks? + /** + @method adapterWillCommit + @private + adapterWillCommit: function() { + this.send('willCommit'); + }, + + /** + @method adapterDidDirty + @private + adapterDidDirty: function() { + this.send('becomeDirty'); + this.updateRecordArraysLater(); + }, + */ + + /** + If the model `hasDirtyAttributes` this function will discard any unsaved + changes. If the model `isNew` it will be removed from the store. + + Example + + ```javascript + record.get('name'); // 'Untitled Document' + record.set('name', 'Doc 1'); + record.get('name'); // 'Doc 1' + record.rollbackAttributes(); + record.get('name'); // 'Untitled Document' + ``` + + @since 1.13.0 + @method rollbackAttributes + */ + rollbackAttributes() { + this._internalModel.rollbackAttributes(); + }, + + /* + @method _createSnapshot + @private + */ + _createSnapshot() { + return this._internalModel.createSnapshot(); + }, + + toStringExtension() { + // the _internalModel guard exists, because some dev-only deprecation code + // (addListener via validatePropertyInjections) invokes toString before the + // object is real. + return this._internalModel && this._internalModel.id; + }, + + /** + Save the record and persist any changes to the record to an + external source via the adapter. + + Example + + ```javascript + record.set('name', 'Tomster'); + record.save().then(function() { + // Success callback + }, function() { + // Error callback + }); + ``` + + If you pass an object using the `adapterOptions` property of the options + argument it will be passed to your adapter via the snapshot. + + ```js + record.save({ adapterOptions: { subscribe: false } }); + ``` + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + updateRecord(store, type, snapshot) { + if (snapshot.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + + @method save + @param {Object} options + @return {Promise} a promise that will be resolved when the adapter returns + successfully or rejected if the adapter returns with an error. + */ + save(options) { + return PromiseObject.create({ + promise: this._internalModel.save(options).then(() => this) + }); + }, + + /** + Reload the record from the adapter. + + This will only work if the record has already finished loading. + + Example + + ```app/routes/model/view.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + actions: { + reload() { + this.controller.get('model').reload().then(function(model) { + // do something with the reloaded model + }); + } + } + }); + ``` + + @method reload + @param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter request + + @return {Promise} a promise that will be resolved with the record when the + adapter returns successfully or rejected if the adapter returns + with an error. + */ + reload(options) { + let wrappedAdapterOptions; + + if (typeof options === 'object' && options !== null && options.adapterOptions) { + wrappedAdapterOptions = { + adapterOptions: options.adapterOptions + }; + } + + return PromiseObject.create({ + promise: this._internalModel.reload(wrappedAdapterOptions).then(() => this) + }); + }, + + + /** + Override the default event firing from Ember.Evented to + also call methods with the given name. + + @method trigger + @private + @param {String} name + */ + trigger(name) { + let fn = this[name]; + + if (typeof fn === 'function') { + let length = arguments.length; + let args = new Array(length - 1); + + for (let i = 1; i < length; i++) { + args[i - 1] = arguments[i]; + } + fn.apply(this, args) + } + + this._super(...arguments); + }, + + attr() { + assert("The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); + }, + + /** + Get the reference for the specified belongsTo relationship. + + Example + + ```app/models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + ``` + + ```javascript + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + let userRef = blog.belongsTo('user'); + + // check if the user relationship is loaded + let isLoaded = userRef.value() !== null; + + // get the record of the reference (null if not yet available) + let user = userRef.value(); + + // get the identifier of the reference + if (userRef.remoteType() === "id") { + let id = userRef.id(); + } else if (userRef.remoteType() === "link") { + let link = userRef.link(); + } + + // load user (via store.findRecord or store.findBelongsTo) + userRef.load().then(...) + + // or trigger a reload + userRef.reload().then(...) + + // provide data for reference + userRef.push({ + type: 'user', + id: 1, + attributes: { + username: "@user" + } + }).then(function(user) { + userRef.value() === user; + }); + ``` + + @method belongsTo + @param {String} name of the relationship + @since 2.5.0 + @return {BelongsToReference} reference for this relationship + */ + belongsTo(name) { + return this._internalModel.referenceFor('belongsTo', name); + }, + + /** + Get the reference for the specified hasMany relationship. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + comments: { + data: [ + { type: 'comment', id: 1 }, + { type: 'comment', id: 2 } + ] + } + } + } + }); + let commentsRef = blog.hasMany('comments'); + + // check if the comments are loaded already + let isLoaded = commentsRef.value() !== null; + + // get the records of the reference (null if not yet available) + let comments = commentsRef.value(); + + // get the identifier of the reference + if (commentsRef.remoteType() === "ids") { + let ids = commentsRef.ids(); + } else if (commentsRef.remoteType() === "link") { + let link = commentsRef.link(); + } + + // load comments (via store.findMany or store.findHasMany) + commentsRef.load().then(...) + + // or trigger a reload + commentsRef.reload().then(...) + + // provide data for reference + commentsRef.push([{ type: 'comment', id: 1 }, { type: 'comment', id: 2 }]).then(function(comments) { + commentsRef.value() === comments; + }); + ``` + + @method hasMany + @param {String} name of the relationship + @since 2.5.0 + @return {HasManyReference} reference for this relationship + */ + hasMany(name) { + return this._internalModel.referenceFor('hasMany', name); + }, + + /** + Provides info about the model for debugging purposes + by grouping the properties into more semantic groups. + + Meant to be used by debugging tools such as the Chrome Ember Extension. + + - Groups all attributes in "Attributes" group. + - Groups all belongsTo relationships in "Belongs To" group. + - Groups all hasMany relationships in "Has Many" group. + - Groups all flags in "Flags" group. + - Flags relationship CPs as expensive properties. + + @method _debugInfo + @for DS.Model + @private + */ + _debugInfo() { + let attributes = ['id']; + let relationships = { }; + let expensiveProperties = []; + + this.eachAttribute((name, meta) => attributes.push(name)); + + let groups = [ + { + name: 'Attributes', + properties: attributes, + expand: true + } + ]; + + this.eachRelationship((name, relationship) => { + let properties = relationships[relationship.kind]; + + if (properties === undefined) { + properties = relationships[relationship.kind] = []; + groups.push({ + name: relationship.name, + properties, + expand: true + }); + } + properties.push(name); + expensiveProperties.push(name); + }); + + groups.push({ + name: 'Flags', + properties: ['isLoaded', 'hasDirtyAttributes', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'] + }); + + return { + propertyInfo: { + // include all other mixins / properties (not just the grouped ones) + includeOtherProperties: true, + groups: groups, + // don't pre-calculate unless cached + expensiveProperties: expensiveProperties + } + }; + }, + + notifyBelongsToChanged(key) { + this.notifyPropertyChange(key); + }, + /** + Given a callback, iterates over each of the relationships in the model, + invoking the callback with the name of each relationship and its relationship + descriptor. + + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(name, descriptor); + ``` + + - `name` the name of the current property in the iteration + - `descriptor` the meta object that describes this relationship + + The relationship descriptor argument is an object with the following properties. + + - **key** String the name of this relationship on the Model + - **kind** String "hasMany" or "belongsTo" + - **options** Object the original options hash passed when the relationship was declared + - **parentType** DS.Model the type of the Model that owns this relationship + - **type** String the type name of the related Model + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. + + Example + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.JSONSerializer.extend({ + serialize: function(record, options) { + let json = {}; + + record.eachRelationship(function(name, descriptor) { + if (descriptor.kind === 'hasMany') { + let serializedHasManyName = name.toUpperCase() + '_IDS'; + json[serializedHasManyName] = record.get(name).mapBy('id'); + } + }); + + return json; + } + }); + ``` + + @method eachRelationship + @param {Function} callback the callback to invoke + @param {any} binding the value to which the callback's `this` should be bound + */ + eachRelationship(callback, binding) { + this.constructor.eachRelationship(callback, binding); + }, + + relationshipFor(name) { + return get(this.constructor, 'relationshipsByName').get(name); + }, + + inverseFor(key) { + return this.constructor.inverseFor(key, this.store); + }, + + notifyHasManyAdded(key) { + //We need to notifyPropertyChange in the adding case because we need to make sure + //we fetch the newly added record in case it is unloaded + //TODO(Igor): Consider whether we could do this only if the record state is unloaded + this.notifyPropertyChange(key); + }, + + eachAttribute(callback, binding) { + this.constructor.eachAttribute(callback, binding); + } +}); + +/** + @property data + @private + @type {Object} + */ +Object.defineProperty(Model.prototype, 'data', { + configurable: false, + get() { + // TODO deprecate this!!!!!!!!!!! it's private but intimate + return this._internalModel._modelData._data; + } +}); + +Object.defineProperty(Model.prototype, 'id', { + configurable: false, + set(id) { + this._internalModel.setId(id); + }, + + get() { + // the _internalModel guard exists, because some dev-only deprecation code + // (addListener via validatePropertyInjections) invokes toString before the + // object is real. + return this._internalModel && this._internalModel.id; + } +}); + +if (DEBUG) { + Model.reopen({ + init() { + this._super(...arguments); + + if (!this._internalModel) { + throw new EmberError('You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.'); + } + } + }); +} + +Model.reopenClass({ + isModel: true, + + /** + Override the class' `create()` method to raise an error. This + prevents end users from inadvertently calling `create()` instead + of `createRecord()`. The store is still able to create instances + by calling the `_create()` method. To create an instance of a + `DS.Model` use [store.createRecord](DS.Store.html#method_createRecord). + + @method create + @private + @static + */ + /** + Represents the model's class name as a string. This can be used to look up the model's class name through + `DS.Store`'s modelFor method. + + `modelName` is generated for you by Ember Data. It will be a lowercased, dasherized string. + For example: + + ```javascript + store.modelFor('post').modelName; // 'post' + store.modelFor('blog-post').modelName; // 'blog-post' + ``` + + The most common place you'll want to access `modelName` is in your serializer's `payloadKeyFromModelName` method. For example, to change payload + keys to underscore (instead of dasherized), you might use the following code: + + ```javascript + import { underscore } from '@ember/string'; + + export default const PostSerializer = DS.RESTSerializer.extend({ + payloadKeyFromModelName(modelName) { + return underscore(modelName); + } + }); + ``` + @property modelName + @type String + @readonly + @static + */ + modelName: null, + + /* + These class methods below provide relationship + introspection abilities about relationships. + + A note about the computed properties contained here: + + **These properties are effectively sealed once called for the first time.** + To avoid repeatedly doing expensive iteration over a model's fields, these + values are computed once and then cached for the remainder of the runtime of + your application. + + If your application needs to modify a class after its initial definition + (for example, using `reopen()` to add additional attributes), make sure you + do it before using your model with the store, which uses these properties + extensively. + */ + + /** + For a given relationship name, returns the model type of the relationship. + + For example, if you define a model like this: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + comments: DS.hasMany('comment') + }); + ``` + + Calling `store.modelFor('post').typeForRelationship('comments', store)` will return `Comment`. + + @method typeForRelationship + @static + @param {String} name the name of the relationship + @param {store} store an instance of DS.Store + @return {DS.Model} the type of the relationship, or undefined + */ + typeForRelationship(name, store) { + let relationship = get(this, 'relationshipsByName').get(name); + return relationship && store.modelFor(relationship.type); + }, + + inverseMap: computed(function() { + return Object.create(null); + }), + + /** + Find the relationship which is the inverse of the one asked for. + + For example, if you define models like this: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + comments: DS.hasMany('message') + }); + ``` + + ```app/models/message.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + owner: DS.belongsTo('post') + }); + ``` + + ``` js + store.modelFor('post').inverseFor('comments', store) // { type: App.Message, name: 'owner', kind: 'belongsTo' } + store.modelFor('message').inverseFor('owner', store) // { type: App.Post, name: 'comments', kind: 'hasMany' } + ``` + + @method inverseFor + @static + @param {String} name the name of the relationship + @param {DS.Store} store + @return {Object} the inverse relationship, or null + */ + inverseFor(name, store) { + let inverseMap = get(this, 'inverseMap'); + if (inverseMap[name]) { + return inverseMap[name]; + } else { + let inverse = this._findInverseFor(name, store); + inverseMap[name] = inverse; + return inverse; + } + }, + + //Calculate the inverse, ignoring the cache + _findInverseFor(name, store) { + + let inverseType = this.typeForRelationship(name, store); + if (!inverseType) { + return null; + } + + let propertyMeta = this.metaForProperty(name); + //If inverse is manually specified to be null, like `comments: DS.hasMany('message', { inverse: null })` + let options = propertyMeta.options; + if (options.inverse === null) { return null; } + + let inverseName, inverseKind, inverse, inverseOptions; + + //If inverse is specified manually, return the inverse + if (options.inverse) { + inverseName = options.inverse; + inverse = get(inverseType, 'relationshipsByName').get(inverseName); + + assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.modelName + + "' model. This is most likely due to a missing attribute on your model definition.", !isNone(inverse)); + + // TODO probably just return the whole inverse here + inverseKind = inverse.kind; + inverseOptions = inverse.options; + } else { + //No inverse was specified manually, we need to use a heuristic to guess one + if (propertyMeta.parentType && propertyMeta.type === propertyMeta.parentType.modelName) { + warn(`Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at https://guides.emberjs.com/current/models/relationships/#toc_reflexive-relations for how to explicitly specify inverses.`, false, { + id: 'ds.model.reflexive-relationship-without-inverse' + }); + } + + let possibleRelationships = findPossibleInverses(this, inverseType, name); + + if (possibleRelationships.length === 0) { return null; } + + let filteredRelationships = possibleRelationships.filter((possibleRelationship) => { + let optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options; + return name === optionsForRelationship.inverse; + }); + + assert("You defined the '" + name + "' relationship on " + this + ", but you defined the inverse relationships of type " + + inverseType.toString() + " multiple times. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses", + filteredRelationships.length < 2); + + if (filteredRelationships.length === 1 ) { + possibleRelationships = filteredRelationships; + } + + assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + + this + " were found on " + inverseType + ". Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses", + possibleRelationships.length === 1); + + inverseName = possibleRelationships[0].name; + inverseKind = possibleRelationships[0].kind; + inverseOptions = possibleRelationships[0].options; + } + + assert(`The ${inverseType.modelName}:${inverseName} relationship declares 'inverse: null', but it was resolved as the inverse for ${this.modelName}:${name}.`, !inverseOptions || inverseOptions.inverse !== null); + + return { + type: inverseType, + name: inverseName, + kind: inverseKind, + options: inverseOptions + }; + }, + + /** + The model's relationships as a map, keyed on the type of the + relationship. The value of each entry is an array containing a descriptor + for each relationship with that type, describing the name of the relationship + as well as the type. + + For example, given the following model definition: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + posts: DS.hasMany('post') + }); + ``` + + This computed property would return a map describing these + relationships, like this: + + ```javascript + import Ember from 'ember'; + import Blog from 'app/models/blog'; + import User from 'app/models/user'; + import Post from 'app/models/post'; + + let relationships = Ember.get(Blog, 'relationships'); + relationships.get(User); + //=> [ { name: 'users', kind: 'hasMany' }, + // { name: 'owner', kind: 'belongsTo' } ] + relationships.get(Post); + //=> [ { name: 'posts', kind: 'hasMany' } ] + ``` + + @property relationships + @static + @type Map + @readOnly + */ + + relationships: relationshipsDescriptor, + + /** + A hash containing lists of the model's relationships, grouped + by the relationship kind. For example, given a model with this + definition: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + + posts: DS.hasMany('post') + }); + ``` + + This property would contain the following: + + ```javascript + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + let relationshipNames = Ember.get(Blog, 'relationshipNames'); + relationshipNames.hasMany; + //=> ['users', 'posts'] + relationshipNames.belongsTo; + //=> ['owner'] + ``` + + @property relationshipNames + @static + @type Object + @readOnly + */ + relationshipNames: computed(function() { + let names = { + hasMany: [], + belongsTo: [] + }; + + this.eachComputedProperty((name, meta) => { + if (meta.isRelationship) { + names[meta.kind].push(name); + } + }); + + return names; + }), + + /** + An array of types directly related to a model. Each type will be + included once, regardless of the number of relationships it has with + the model. + + For example, given a model with this definition: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + + posts: DS.hasMany('post') + }); + ``` + + This property would contain the following: + + ```javascript + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + let relatedTypes = Ember.get(Blog, 'relatedTypes'); + //=> [ User, Post ] + ``` + + @property relatedTypes + @static + @type Ember.Array + @readOnly + */ + relatedTypes: relatedTypesDescriptor, + + /** + A map whose keys are the relationships of a model and whose values are + relationship descriptors. + + For example, given a model with this + definition: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + + posts: DS.hasMany('post') + }); + ``` + + This property would contain the following: + + ```javascript + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + let relationshipsByName = Ember.get(Blog, 'relationshipsByName'); + relationshipsByName.get('users'); + //=> { key: 'users', kind: 'hasMany', type: 'user', options: Object, isRelationship: true } + relationshipsByName.get('owner'); + //=> { key: 'owner', kind: 'belongsTo', type: 'user', options: Object, isRelationship: true } + ``` + + @property relationshipsByName + @static + @type Map + @readOnly + */ + relationshipsByName: relationshipsByNameDescriptor, + + + relationshipsObject: relationshipsObjectDescriptor, + + /** + A map whose keys are the fields of the model and whose values are strings + describing the kind of the field. A model's fields are the union of all of its + attributes and relationships. + + For example: + + ```app/models/blog.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + + posts: DS.hasMany('post'), + + title: DS.attr('string') + }); + ``` + + ```js + import Ember from 'ember'; + import Blog from 'app/models/blog'; + + let fields = Ember.get(Blog, 'fields'); + fields.forEach(function(kind, field) { + console.log(field, kind); + }); + + // prints: + // users, hasMany + // owner, belongsTo + // posts, hasMany + // title, attribute + ``` + + @property fields + @static + @type Map + @readOnly + */ + fields: computed(function() { + let map = new Map(); + + this.eachComputedProperty((name, meta) => { + if (meta.isRelationship) { + map.set(name, meta.kind); + } else if (meta.isAttribute) { + map.set(name, 'attribute'); + } + }); + + return map; + }).readOnly(), + + /** + Given a callback, iterates over each of the relationships in the model, + invoking the callback with the name of each relationship and its relationship + descriptor. + + @method eachRelationship + @static + @param {Function} callback the callback to invoke + @param {any} binding the value to which the callback's `this` should be bound + */ + eachRelationship(callback, binding) { + get(this, 'relationshipsByName').forEach((relationship, name) => { + callback.call(binding, name, relationship); + }); + }, + + /** + Given a callback, iterates over each of the types related to a model, + invoking the callback with the related type's class. Each type will be + returned just once, regardless of how many different relationships it has + with a model. + + @method eachRelatedType + @static + @param {Function} callback the callback to invoke + @param {any} binding the value to which the callback's `this` should be bound + */ + eachRelatedType(callback, binding) { + let relationshipTypes = get(this, 'relatedTypes'); + + for (let i = 0; i < relationshipTypes.length; i++) { + let type = relationshipTypes[i]; + callback.call(binding, type); + } + }, + + determineRelationshipType(knownSide, store) { + let knownKey = knownSide.key; + let knownKind = knownSide.kind; + let inverse = this.inverseFor(knownKey, store); + // let key; + let otherKind; + + if (!inverse) { + return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone'; + } + + // key = inverse.name; + otherKind = inverse.kind; + + if (otherKind === 'belongsTo') { + return knownKind === 'belongsTo' ? 'oneToOne' : 'manyToOne'; + } else { + return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany'; + } + }, + + /** + A map whose keys are the attributes of the model (properties + described by DS.attr) and whose values are the meta object for the + property. + + Example + + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + birthday: DS.attr('date') + }); + ``` + + ```javascript + import Ember from 'ember'; + import Person from 'app/models/person'; + + let attributes = Ember.get(Person, 'attributes') + + attributes.forEach(function(meta, name) { + console.log(name, meta); + }); + + // prints: + // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} + // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} + // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} + ``` + + @property attributes + @static + @type {Map} + @readOnly + */ + attributes: computed(function() { + let map = new Map(); + + this.eachComputedProperty((name, meta) => { + if (meta.isAttribute) { + assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.toString(), name !== 'id'); + + meta.name = name; + map.set(name, meta); + } + }); + + return map; + }).readOnly(), + + /** + A map whose keys are the attributes of the model (properties + described by DS.attr) and whose values are type of transformation + applied to each attribute. This map does not include any + attributes that do not have an transformation type. + + Example + + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + firstName: DS.attr(), + lastName: DS.attr('string'), + birthday: DS.attr('date') + }); + ``` + + ```javascript + import Ember from 'ember'; + import Person from 'app/models/person'; + + let transformedAttributes = Ember.get(Person, 'transformedAttributes') + + transformedAttributes.forEach(function(field, type) { + console.log(field, type); + }); + + // prints: + // lastName string + // birthday date + ``` + + @property transformedAttributes + @static + @type {Map} + @readOnly + */ + transformedAttributes: computed(function() { + let map = new Map(); + + this.eachAttribute((key, meta) => { + if (meta.type) { + map.set(key, meta.type); + } + }); + + return map; + }).readOnly(), + + /** + Iterates through the attributes of the model, calling the passed function on each + attribute. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(name, meta); + ``` + + - `name` the name of the current property in the iteration + - `meta` the meta object for the attribute property in the iteration + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. + + Example + + ```javascript + import DS from 'ember-data'; + + let Person = DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + birthday: DS.attr('date') + }); + + Person.eachAttribute(function(name, meta) { + console.log(name, meta); + }); + + // prints: + // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} + // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} + // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} + ``` + + @method eachAttribute + @param {Function} callback The callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + @static + */ + eachAttribute(callback, binding) { + get(this, 'attributes').forEach((meta, name) => { + callback.call(binding, name, meta); + }); + }, + + /** + Iterates through the transformedAttributes of the model, calling + the passed function on each attribute. Note the callback will not be + called for any attributes that do not have an transformation type. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(name, type); + ``` + + - `name` the name of the current property in the iteration + - `type` a string containing the name of the type of transformed + applied to the attribute + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. + + Example + + ```javascript + import DS from 'ember-data'; + + let Person = DS.Model.extend({ + firstName: DS.attr(), + lastName: DS.attr('string'), + birthday: DS.attr('date') + }); + + Person.eachTransformedAttribute(function(name, type) { + console.log(name, type); + }); + + // prints: + // lastName string + // birthday date + ``` + + @method eachTransformedAttribute + @param {Function} callback The callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + @static + */ + eachTransformedAttribute(callback, binding) { + get(this, 'transformedAttributes').forEach((type, name) => { + callback.call(binding, name, type); + }); + }, + + /** + Returns the name of the model class. + + @method toString + @static + */ + toString() { + return `model:${get(this, 'modelName')}`; + } +}); + +if (DEBUG) { + Model.reopen({ + // This is a temporary solution until we refactor DS.Model to not + // rely on the data property. + willMergeMixin(props) { + let constructor = this.constructor; + assert('`' + intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + constructor.toString(), !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0]); + assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + constructor.toString(), Object.keys(props).indexOf('id') === -1); + }, + + /** + This Ember.js hook allows an object to be notified when a property + is defined. + + In this case, we use it to be notified when an Ember Data user defines a + belongs-to relationship. In that case, we need to set up observers for + each one, allowing us to track relationship changes and automatically + reflect changes in the inverse has-many array. + + This hook passes the class being set up, as well as the key and value + being defined. So, for example, when the user does this: + + ```javascript + DS.Model.extend({ + parent: DS.belongsTo('user') + }); + ``` + + This hook would be called with "parent" as the key and the computed + property returned by `DS.belongsTo` as the value. + + @method didDefineProperty + @param {Object} proto + @param {String} key + @param {Ember.ComputedProperty} value + */ + didDefineProperty(proto, key, value) { + // Check if the value being set is a computed property. + if (value instanceof ComputedProperty) { + + // If it is, get the metadata for the relationship. This is + // populated by the `DS.belongsTo` helper when it is creating + // the computed property. + let meta = value.meta(); + + /* + This is buggy because if the parent has never been looked up + via `modelFor` it will not have `modelName` set. + */ + meta.parentType = proto.constructor; + } + } + }); +} + +export default Model; diff --git a/addon/-record-data-rfc-private/system/model/states.js b/addon/-record-data-rfc-private/system/model/states.js new file mode 100644 index 00000000000..f67bd7a0cbc --- /dev/null +++ b/addon/-record-data-rfc-private/system/model/states.js @@ -0,0 +1,764 @@ +/** + @module ember-data +*/ +import { assert } from '@ember/debug'; + +/* + This file encapsulates the various states that a record can transition + through during its lifecycle. +*/ +/** + ### State + + Each record has a `currentState` property that explicitly tracks what + state a record is in at any given time. For instance, if a record is + newly created and has not yet been sent to the adapter to be saved, + it would be in the `root.loaded.created.uncommitted` state. If a + record has had local modifications made to it that are in the + process of being saved, the record would be in the + `root.loaded.updated.inFlight` state. (This state paths will be + explained in more detail below.) + + Events are sent by the record or its store to the record's + `currentState` property. How the state reacts to these events is + dependent on which state it is in. In some states, certain events + will be invalid and will cause an exception to be raised. + + States are hierarchical and every state is a substate of the + `RootState`. For example, a record can be in the + `root.deleted.uncommitted` state, then transition into the + `root.deleted.inFlight` state. If a child state does not implement + an event handler, the state manager will attempt to invoke the event + on all parent states until the root state is reached. The state + hierarchy of a record is described in terms of a path string. You + can determine a record's current state by getting the state's + `stateName` property: + + ```javascript + record.get('currentState.stateName'); + //=> "root.created.uncommitted" + ``` + + The hierarchy of valid states that ship with ember data looks like + this: + + ```text + * root + * deleted + * saved + * uncommitted + * inFlight + * empty + * loaded + * created + * uncommitted + * inFlight + * saved + * updated + * uncommitted + * inFlight + * loading + ``` + + The `DS.Model` states are themselves stateless. What that means is + that, the hierarchical states that each of *those* points to is a + shared data structure. For performance reasons, instead of each + record getting its own copy of the hierarchy of states, each record + points to this global, immutable shared instance. How does a state + know which record it should be acting on? We pass the record + instance into the state's event handlers as the first argument. + + The record passed as the first parameter is where you should stash + state about the record if needed; you should never store data on the state + object itself. + + ### Events and Flags + + A state may implement zero or more events and flags. + + #### Events + + Events are named functions that are invoked when sent to a record. The + record will first look for a method with the given name on the + current state. If no method is found, it will search the current + state's parent, and then its grandparent, and so on until reaching + the top of the hierarchy. If the root is reached without an event + handler being found, an exception will be raised. This can be very + helpful when debugging new features. + + Here's an example implementation of a state with a `myEvent` event handler: + + ```javascript + aState: DS.State.create({ + myEvent: function(manager, param) { + console.log("Received myEvent with", param); + } + }) + ``` + + To trigger this event: + + ```javascript + record.send('myEvent', 'foo'); + //=> "Received myEvent with foo" + ``` + + Note that an optional parameter can be sent to a record's `send()` method, + which will be passed as the second parameter to the event handler. + + Events should transition to a different state if appropriate. This can be + done by calling the record's `transitionTo()` method with a path to the + desired state. The state manager will attempt to resolve the state path + relative to the current state. If no state is found at that path, it will + attempt to resolve it relative to the current state's parent, and then its + parent, and so on until the root is reached. For example, imagine a hierarchy + like this: + + * created + * uncommitted <-- currentState + * inFlight + * updated + * inFlight + + If we are currently in the `uncommitted` state, calling + `transitionTo('inFlight')` would transition to the `created.inFlight` state, + while calling `transitionTo('updated.inFlight')` would transition to + the `updated.inFlight` state. + + Remember that *only events* should ever cause a state transition. You should + never call `transitionTo()` from outside a state's event handler. If you are + tempted to do so, create a new event and send that to the state manager. + + #### Flags + + Flags are Boolean values that can be used to introspect a record's current + state in a more user-friendly way than examining its state path. For example, + instead of doing this: + + ```javascript + var statePath = record.get('stateManager.currentPath'); + if (statePath === 'created.inFlight') { + doSomething(); + } + ``` + + You can say: + + ```javascript + if (record.get('isNew') && record.get('isSaving')) { + doSomething(); + } + ``` + + If your state does not set a value for a given flag, the value will + be inherited from its parent (or the first place in the state hierarchy + where it is defined). + + The current set of flags are defined below. If you want to add a new flag, + in addition to the area below, you will also need to declare it in the + `DS.Model` class. + + + * [isEmpty](DS.Model.html#property_isEmpty) + * [isLoading](DS.Model.html#property_isLoading) + * [isLoaded](DS.Model.html#property_isLoaded) + * [hasDirtyAttributes](DS.Model.html#property_hasDirtyAttributes) + * [isSaving](DS.Model.html#property_isSaving) + * [isDeleted](DS.Model.html#property_isDeleted) + * [isNew](DS.Model.html#property_isNew) + * [isValid](DS.Model.html#property_isValid) + + @namespace DS + @class RootState +*/ + +function didSetProperty(internalModel, context) { + if (context.isDirty) { + internalModel.send('becomeDirty'); + } else { + internalModel.send('propertyWasReset'); + } + + internalModel.updateRecordArrays(); +} + +// Implementation notes: +// +// Each state has a boolean value for all of the following flags: +// +// * isLoaded: The record has a populated `data` property. When a +// record is loaded via `store.find`, `isLoaded` is false +// until the adapter sets it. When a record is created locally, +// its `isLoaded` property is always true. +// * isDirty: The record has local changes that have not yet been +// saved by the adapter. This includes records that have been +// created (but not yet saved) or deleted. +// * isSaving: The record has been committed, but +// the adapter has not yet acknowledged that the changes have +// been persisted to the backend. +// * isDeleted: The record was marked for deletion. When `isDeleted` +// is true and `isDirty` is true, the record is deleted locally +// but the deletion was not yet persisted. When `isSaving` is +// true, the change is in-flight. When both `isDirty` and +// `isSaving` are false, the change has persisted. +// * isNew: The record was created on the client and the adapter +// did not yet report that it was successfully saved. +// * isValid: The adapter did not report any server-side validation +// failures. + +// The dirty state is a abstract state whose functionality is +// shared between the `created` and `updated` states. +// +// The deleted state shares the `isDirty` flag with the +// subclasses of `DirtyState`, but with a very different +// implementation. +// +// Dirty states have three child states: +// +// `uncommitted`: the store has not yet handed off the record +// to be saved. +// `inFlight`: the store has handed off the record to be saved, +// but the adapter has not yet acknowledged success. +// `invalid`: the record has invalid information and cannot be +// sent to the adapter yet. +const DirtyState = { + initialState: 'uncommitted', + + // FLAGS + isDirty: true, + + // SUBSTATES + + // When a record first becomes dirty, it is `uncommitted`. + // This means that there are local pending changes, but they + // have not yet begun to be saved, and are not invalid. + uncommitted: { + // EVENTS + didSetProperty, + + //TODO(Igor) reloading now triggers a + //loadingData event, though it seems fine? + loadingData() { }, + + propertyWasReset(internalModel, name) { + if (!internalModel.hasChangedAttributes()) { internalModel.send('rolledBack'); } + }, + + pushedData(internalModel) { + let token = heimdall.start('stats.uncommitted.pushedData'); + + if (!internalModel.hasChangedAttributes()) { + internalModel.transitionTo('loaded.saved'); + } + heimdall.stop(token); + }, + + becomeDirty() {}, + + willCommit(internalModel) { + internalModel.transitionTo('inFlight'); + }, + + reloadRecord(internalModel, { resolve, options }) { + resolve(internalModel.store._reloadRecord(internalModel, options)); + }, + + rolledBack(internalModel) { + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('rolledBack'); + }, + + becameInvalid(internalModel) { + internalModel.transitionTo('invalid'); + }, + + rollback(internalModel) { + internalModel.rollbackAttributes(); + internalModel.triggerLater('ready'); + } + }, + + // Once a record has been handed off to the adapter to be + // saved, it is in the 'in flight' state. Changes to the + // record cannot be made during this window. + inFlight: { + // FLAGS + isSaving: true, + + // EVENTS + didSetProperty, + becomeDirty() { }, + pushedData() { }, + + unloadRecord: assertAgainstUnloadRecord, + + // TODO: More robust semantics around save-while-in-flight + willCommit() { }, + + didCommit(internalModel) { + internalModel.transitionTo('saved'); + internalModel.send('invokeLifecycleCallbacks', this.dirtyType); + }, + + rolledBack(internalModel) { + internalModel.triggerLater('rolledBack'); + }, + + becameInvalid(internalModel) { + internalModel.transitionTo('invalid'); + internalModel.send('invokeLifecycleCallbacks'); + }, + + becameError(internalModel) { + internalModel.transitionTo('uncommitted'); + internalModel.triggerLater('becameError', internalModel); + } + }, + + // A record is in the `invalid` if the adapter has indicated + // the the record failed server-side invalidations. + invalid: { + // FLAGS + isValid: false, + + // EVENTS + deleteRecord(internalModel) { + internalModel.transitionTo('deleted.uncommitted'); + }, + + didSetProperty(internalModel, context) { + internalModel.removeErrorMessageFromAttribute(context.name); + + didSetProperty(internalModel, context); + + if (!internalModel.hasErrors()) { + this.becameValid(internalModel); + } + }, + + becameInvalid() { }, + becomeDirty() { }, + pushedData() { }, + + willCommit(internalModel) { + internalModel.clearErrorMessages(); + internalModel.transitionTo('inFlight'); + }, + + rolledBack(internalModel) { + internalModel.clearErrorMessages(); + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('ready'); + }, + + becameValid(internalModel) { + internalModel.transitionTo('uncommitted'); + }, + + invokeLifecycleCallbacks(internalModel) { + internalModel.triggerLater('becameInvalid', internalModel); + } + } +}; + +// The created and updated states are created outside the state +// chart so we can reopen their substates and add mixins as +// necessary. + +function deepClone(object) { + const clone = {}; + let value; + + for (let prop in object) { + value = object[prop]; + if (value && typeof value === 'object') { + clone[prop] = deepClone(value); + } else { + clone[prop] = value; + } + } + + return clone; +} + +function mixin(original, hash) { + for (let prop in hash) { + original[prop] = hash[prop]; + } + + return original; +} + +function dirtyState(options) { + var newState = deepClone(DirtyState); + return mixin(newState, options); +} + +const createdState = dirtyState({ + dirtyType: 'created', + // FLAGS + isNew: true +}); + +createdState.invalid.rolledBack = function(internalModel) { + internalModel.transitionTo('deleted.saved'); + internalModel.triggerLater('rolledBack'); +}; + +createdState.uncommitted.rolledBack = function(internalModel) { + internalModel.transitionTo('deleted.saved'); + internalModel.triggerLater('rolledBack'); +}; + +const updatedState = dirtyState({ + dirtyType: 'updated' +}); + +function createdStateDeleteRecord(internalModel) { + internalModel.transitionTo('deleted.saved'); + internalModel.send('invokeLifecycleCallbacks'); +} + +createdState.uncommitted.deleteRecord = createdStateDeleteRecord; + +createdState.invalid.deleteRecord = createdStateDeleteRecord; + +createdState.uncommitted.rollback = function(internalModel) { + DirtyState.uncommitted.rollback.apply(this, arguments); + internalModel.transitionTo('deleted.saved'); +}; + +createdState.uncommitted.pushedData = function(internalModel) { + internalModel.transitionTo('loaded.updated.uncommitted'); + internalModel.triggerLater('didLoad'); +}; + +createdState.uncommitted.propertyWasReset = function() {}; + +function assertAgainstUnloadRecord(internalModel) { + assert("You can only unload a record which is not inFlight. `" + internalModel + "`", false); +} + +updatedState.invalid.becameValid = function(internalModel) { + // we're eagerly transition into the loaded.saved state, even though we could + // be still dirty; but the setup hook of the loaded.saved state checks for + // dirty attributes and transitions into the corresponding dirty state + internalModel.transitionTo('loaded.saved'); +}; + +updatedState.inFlight.unloadRecord = assertAgainstUnloadRecord; + +updatedState.uncommitted.deleteRecord = function(internalModel) { + internalModel.transitionTo('deleted.uncommitted'); +}; + +updatedState.invalid.rolledBack = function(internalModel) { + internalModel.clearErrorMessages(); + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('rolledBack'); +}; + +const RootState = { + // FLAGS + isEmpty: false, + isLoading: false, + isLoaded: false, + isDirty: false, + isSaving: false, + isDeleted: false, + isNew: false, + isValid: true, + + // DEFAULT EVENTS + + // Trying to roll back if you're not in the dirty state + // doesn't change your state. For example, if you're in the + // in-flight state, rolling back the record doesn't move + // you out of the in-flight state. + rolledBack() { }, + unloadRecord(internalModel) { + }, + + propertyWasReset() { }, + + // SUBSTATES + + // A record begins its lifecycle in the `empty` state. + // If its data will come from the adapter, it will + // transition into the `loading` state. Otherwise, if + // the record is being created on the client, it will + // transition into the `created` state. + empty: { + isEmpty: true, + + // EVENTS + loadingData(internalModel, promise) { + internalModel._loadingPromise = promise; + internalModel.transitionTo('loading'); + }, + + loadedData(internalModel) { + internalModel.transitionTo('loaded.created.uncommitted'); + internalModel.triggerLater('ready'); + }, + + pushedData(internalModel) { + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('didLoad'); + internalModel.triggerLater('ready'); + } + }, + + // A record enters this state when the store asks + // the adapter for its data. It remains in this state + // until the adapter provides the requested data. + // + // Usually, this process is asynchronous, using an + // XHR to retrieve the data. + loading: { + // FLAGS + isLoading: true, + + exit(internalModel) { + internalModel._loadingPromise = null; + }, + + // EVENTS + pushedData(internalModel) { + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('didLoad'); + internalModel.triggerLater('ready'); + //TODO this seems out of place here + internalModel.didCleanError(); + }, + + becameError(internalModel) { + internalModel.triggerLater('becameError', internalModel); + }, + + notFound(internalModel) { + internalModel.transitionTo('empty'); + } + }, + + // A record enters this state when its data is populated. + // Most of a record's lifecycle is spent inside substates + // of the `loaded` state. + loaded: { + initialState: 'saved', + + // FLAGS + isLoaded: true, + + //TODO(Igor) Reloading now triggers a loadingData event, + //but it should be ok? + loadingData() { }, + + // SUBSTATES + + // If there are no local changes to a record, it remains + // in the `saved` state. + saved: { + setup(internalModel) { + if (internalModel.hasChangedAttributes()) { + internalModel.adapterDidDirty(); + } + }, + + // EVENTS + didSetProperty, + + pushedData() { }, + + becomeDirty(internalModel) { + internalModel.transitionTo('updated.uncommitted'); + }, + + willCommit(internalModel) { + internalModel.transitionTo('updated.inFlight'); + }, + + reloadRecord(internalModel, { resolve, options }) { + resolve(internalModel.store._reloadRecord(internalModel, options)); + }, + + deleteRecord(internalModel) { + internalModel.transitionTo('deleted.uncommitted'); + }, + + unloadRecord(internalModel) { + }, + + didCommit() {}, + + // loaded.saved.notFound would be triggered by a failed + // `reload()` on an unchanged record + notFound() { } + }, + + // A record is in this state after it has been locally + // created but before the adapter has indicated that + // it has been saved. + created: createdState, + + // A record is in this state if it has already been + // saved to the server, but there are new local changes + // that have not yet been saved. + updated: updatedState + }, + + // A record is in this state if it was deleted from the store. + deleted: { + initialState: 'uncommitted', + dirtyType: 'deleted', + + // FLAGS + isDeleted: true, + isLoaded: true, + isDirty: true, + + // TRANSITIONS + setup(internalModel) { + internalModel.updateRecordArrays(); + }, + + // SUBSTATES + + // When a record is deleted, it enters the `start` + // state. It will exit this state when the record + // starts to commit. + uncommitted: { + + // EVENTS + + willCommit(internalModel) { + internalModel.transitionTo('inFlight'); + }, + + rollback(internalModel) { + internalModel.rollbackAttributes(); + internalModel.triggerLater('ready'); + }, + + pushedData() { }, + becomeDirty() { }, + deleteRecord() { }, + + rolledBack(internalModel) { + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('ready'); + internalModel.triggerLater('rolledBack'); + } + }, + + // After a record starts committing, but + // before the adapter indicates that the deletion + // has saved to the server, a record is in the + // `inFlight` substate of `deleted`. + inFlight: { + // FLAGS + isSaving: true, + + // EVENTS + + unloadRecord: assertAgainstUnloadRecord, + + // TODO: More robust semantics around save-while-in-flight + willCommit() { }, + didCommit(internalModel) { + internalModel.transitionTo('saved'); + + internalModel.send('invokeLifecycleCallbacks'); + }, + + becameError(internalModel) { + internalModel.transitionTo('uncommitted'); + internalModel.triggerLater('becameError', internalModel); + }, + + becameInvalid(internalModel) { + internalModel.transitionTo('invalid'); + internalModel.triggerLater('becameInvalid', internalModel); + } + }, + + // Once the adapter indicates that the deletion has + // been saved, the record enters the `saved` substate + // of `deleted`. + saved: { + // FLAGS + isDirty: false, + + setup(internalModel) { + internalModel.removeFromInverseRelationships(); + }, + + invokeLifecycleCallbacks(internalModel) { + internalModel.triggerLater('didDelete', internalModel); + internalModel.triggerLater('didCommit', internalModel); + }, + + willCommit() { }, + didCommit() { }, + pushedData() {} + }, + + invalid: { + isValid: false, + + didSetProperty(internalModel, context) { + internalModel.removeErrorMessageFromAttribute(context.name); + + didSetProperty(internalModel, context); + + if (!internalModel.hasErrors()) { + this.becameValid(internalModel); + } + }, + + becameInvalid() { }, + becomeDirty() { }, + deleteRecord() { }, + willCommit() { }, + + rolledBack(internalModel) { + internalModel.clearErrorMessages(); + internalModel.transitionTo('loaded.saved'); + internalModel.triggerLater('ready'); + }, + + becameValid(internalModel) { + internalModel.transitionTo('uncommitted'); + } + + } + }, + + invokeLifecycleCallbacks(internalModel, dirtyType) { + if (dirtyType === 'created') { + internalModel.triggerLater('didCreate', internalModel); + } else { + internalModel.triggerLater('didUpdate', internalModel); + } + + internalModel.triggerLater('didCommit', internalModel); + } +}; + +function wireState(object, parent, name) { + // TODO: Use Object.create and copy instead + object = mixin(parent ? Object.create(parent) : {}, object); + object.parentState = parent; + object.stateName = name; + + for (let prop in object) { + if (!object.hasOwnProperty(prop) || prop === 'parentState' || prop === 'stateName') { continue; } + if (typeof object[prop] === 'object') { + object[prop] = wireState(object[prop], object, name + '.' + prop); + } + } + + return object; +} + +export default wireState(RootState, null, 'root'); diff --git a/addon/-record-data-rfc-private/system/normalize-link.js b/addon/-record-data-rfc-private/system/normalize-link.js new file mode 100644 index 00000000000..59d9d6536e8 --- /dev/null +++ b/addon/-record-data-rfc-private/system/normalize-link.js @@ -0,0 +1,19 @@ +/* + This method normalizes a link to an "links object". If the passed link is + already an object it's returned without any modifications. + + See http://jsonapi.org/format/#document-links for more information. + + @method _normalizeLink + @private + @param {String} link + @return {Object|null} + @for DS +*/ +export default function _normalizeLink(link) { + switch (typeof link) { + case 'object': return link; + case 'string': return { href: link }; + } + return null; +} diff --git a/addon/-record-data-rfc-private/system/normalize-model-name.js b/addon/-record-data-rfc-private/system/normalize-model-name.js new file mode 100644 index 00000000000..7ff61d9841d --- /dev/null +++ b/addon/-record-data-rfc-private/system/normalize-model-name.js @@ -0,0 +1,18 @@ +import { dasherize } from '@ember/string'; + +// All modelNames are dasherized internally. Changing this function may +// require changes to other normalization hooks (such as typeForRoot). + +/** + This method normalizes a modelName into the format Ember Data uses + internally. + + @method normalizeModelName + @public + @param {String} modelName + @return {String} normalizedModelName + @for DS +*/ +export default function normalizeModelName(modelName) { + return dasherize(modelName); +} diff --git a/addon/-record-data-rfc-private/system/ordered-set.js b/addon/-record-data-rfc-private/system/ordered-set.js new file mode 100644 index 00000000000..27a6205057c --- /dev/null +++ b/addon/-record-data-rfc-private/system/ordered-set.js @@ -0,0 +1,37 @@ +import EmberOrderedSet from '@ember/ordered-set'; +import { guidFor } from '@ember/object/internals'; + +export default function OrderedSet() { + this._super$constructor(); +} + +OrderedSet.create = function() { + let Constructor = this; + return new Constructor(); +}; + +OrderedSet.prototype = Object.create(EmberOrderedSet.prototype); +OrderedSet.prototype.constructor = OrderedSet; +OrderedSet.prototype._super$constructor = EmberOrderedSet; + +OrderedSet.prototype.addWithIndex = function(obj, idx) { + let guid = guidFor(obj); + let presenceSet = this.presenceSet; + let list = this.list; + + if (presenceSet[guid] === true) { + return; + } + + presenceSet[guid] = true; + + if (idx === undefined || idx === null) { + list.push(obj); + } else { + list.splice(idx, 0, obj); + } + + this.size += 1; + + return this; +}; diff --git a/addon/-record-data-rfc-private/system/promise-proxies.js b/addon/-record-data-rfc-private/system/promise-proxies.js new file mode 100644 index 00000000000..07adef6523e --- /dev/null +++ b/addon/-record-data-rfc-private/system/promise-proxies.js @@ -0,0 +1,160 @@ +import ObjectProxy from '@ember/object/proxy'; +import PromiseProxyMixin from '@ember/object/promise-proxy-mixin'; +import ArrayProxy from '@ember/array/proxy'; +import { get, computed } from '@ember/object'; +import { reads } from '@ember/object/computed'; +import { Promise } from 'rsvp'; +import { assert } from '@ember/debug'; + +/** + A `PromiseArray` is an object that acts like both an `Ember.Array` + and a promise. When the promise is resolved the resulting value + will be set to the `PromiseArray`'s `content` property. This makes + it easy to create data bindings with the `PromiseArray` that will be + updated when the promise resolves. + + For more information see the [Ember.PromiseProxyMixin + documentation](/api/classes/Ember.PromiseProxyMixin.html). + + Example + + ```javascript + let promiseArray = DS.PromiseArray.create({ + promise: $.getJSON('/some/remote/data.json') + }); + + promiseArray.get('length'); // 0 + + promiseArray.then(function() { + promiseArray.get('length'); // 100 + }); + ``` + + @class PromiseArray + @namespace DS + @extends Ember.ArrayProxy + @uses Ember.PromiseProxyMixin +*/ +export const PromiseArray = ArrayProxy.extend(PromiseProxyMixin, { + meta: reads('content.meta') +}); + +/** + A `PromiseObject` is an object that acts like both an `Ember.Object` + and a promise. When the promise is resolved, then the resulting value + will be set to the `PromiseObject`'s `content` property. This makes + it easy to create data bindings with the `PromiseObject` that will + be updated when the promise resolves. + + For more information see the [Ember.PromiseProxyMixin + documentation](/api/classes/Ember.PromiseProxyMixin.html). + + Example + + ```javascript + let promiseObject = DS.PromiseObject.create({ + promise: $.getJSON('/some/remote/data.json') + }); + + promiseObject.get('name'); // null + + promiseObject.then(function() { + promiseObject.get('name'); // 'Tomster' + }); + ``` + + @class PromiseObject + @namespace DS + @extends Ember.ObjectProxy + @uses Ember.PromiseProxyMixin +*/ +export let PromiseObject = ObjectProxy.extend(PromiseProxyMixin); + +export function promiseObject(promise, label) { + return PromiseObject.create({ + promise: Promise.resolve(promise, label) + }); +} + +export function promiseArray(promise, label) { + return PromiseArray.create({ + promise: Promise.resolve(promise, label) + }); +} + +export const PromiseBelongsTo = PromiseObject.extend({ + + // we don't proxy meta because we would need to proxy it to the relationship state container + // however, meta on relationships does not trigger change notifications. + // if you need relationship meta, you should do `record.belongsTo(relationshipName).meta()` + meta: computed(function() { + assert( + 'You attempted to access meta on the promise for the async belongsTo relationship ' + + `${this.get('_belongsToState').internalModel.modelName}:${this.get('_belongsToState').key}'.` + + '\nUse `record.belongsTo(relationshipName).meta()` instead.', + false + ); + }), + + reload() { + assert('You are trying to reload an async belongsTo before it has been created', this.get('content') !== undefined); + let state = this.get('_belongsToState'); + let key = state.key; + let store = state.store; + let resource = state.modelData.getResourceIdentifier(); + let internalModel = store._internalModelForResource(resource); + + return store.reloadBelongsTo(this, internalModel, key) + .then(() => this); + } +}); + +/** + A PromiseManyArray is a PromiseArray that also proxies certain method calls + to the underlying manyArray. + Right now we proxy: + + * `reload()` + * `createRecord()` + * `on()` + * `one()` + * `trigger()` + * `off()` + * `has()` + + @class PromiseManyArray + @namespace DS + @extends Ember.ArrayProxy +*/ + +export function proxyToContent(method) { + return function() { + return get(this, 'content')[method](...arguments); + }; +} + +export const PromiseManyArray = PromiseArray.extend({ + reload() { + assert('You are trying to reload an async manyArray before it has been created', get(this, 'content')); + this.set('promise', this.get('content').reload()); + return this; + }, + + createRecord: proxyToContent('createRecord'), + + on: proxyToContent('on'), + + one: proxyToContent('one'), + + trigger: proxyToContent('trigger'), + + off: proxyToContent('off'), + + has: proxyToContent('has') +}); + +export function promiseManyArray(promise, label) { + return PromiseManyArray.create({ + promise: Promise.resolve(promise, label) + }); +} diff --git a/addon/-record-data-rfc-private/system/record-array-manager.js b/addon/-record-data-rfc-private/system/record-array-manager.js new file mode 100644 index 00000000000..b61d6289fe1 --- /dev/null +++ b/addon/-record-data-rfc-private/system/record-array-manager.js @@ -0,0 +1,389 @@ +/** + @module ember-data +*/ + +import { A } from '@ember/array'; +import { set, get } from '@ember/object'; +import { run as emberRun } from '@ember/runloop'; +import { assert } from '@ember/debug'; +import cloneNull from './clone-null'; +import { + RecordArray, + AdapterPopulatedRecordArray +} from './record-arrays'; + +const { + _flush, + array_remove, + create, + createAdapterPopulatedRecordArray, + createRecordArray, + liveRecordArrayFor, + recordDidChange, + unregisterRecordArray +} = heimdall.registerMonitor('recordArrayManager', + '_flush', + 'array_remove', + 'create', + 'createAdapterPopulatedRecordArray', + 'createRecordArray', + 'liveRecordArrayFor', + 'recordDidChange', + 'unregisterRecordArray' +); + +/** + @class RecordArrayManager + @namespace DS + @private +*/ +export default class RecordArrayManager { + constructor(options) { + heimdall.increment(create); + this.store = options.store; + this.isDestroying = false; + this.isDestroyed = false; + this._liveRecordArrays = Object.create(null); + this._pending = Object.create(null); + this._adapterPopulatedRecordArrays = []; + } + + recordDidChange(internalModel) { + // TODO: change name + // TODO: track that it was also a change + this.internalModelDidChange(internalModel); + } + + recordWasLoaded(internalModel) { + // TODO: change name + // TODO: track that it was also that it was first loaded + this.internalModelDidChange(internalModel); + } + + internalModelDidChange(internalModel) { + heimdall.increment(recordDidChange); + + let modelName = internalModel.modelName; + + if (internalModel._pendingRecordArrayManagerFlush) { + return; + } + + internalModel._pendingRecordArrayManagerFlush = true; + + let pending = this._pending; + let models = pending[modelName] = pending[modelName] || []; + if (models.push(internalModel) !== 1) { + return; + } + + emberRun.schedule('actions', this, this._flush); + } + + _flushPendingInternalModelsForModelName(modelName, internalModels) { + let modelsToRemove = []; + + for (let j = 0; j < internalModels.length; j++) { + let internalModel = internalModels[j]; + // mark internalModels, so they can once again be processed by the + // recordArrayManager + internalModel._pendingRecordArrayManagerFlush = false; + // build up a set of models to ensure we have purged correctly; + if (internalModel.isHiddenFromRecordArrays()) { + modelsToRemove.push(internalModel); + } + } + + let array = this._liveRecordArrays[modelName]; + if (array) { + // TODO: skip if it only changed + // process liveRecordArrays + this.updateLiveRecordArray(array, internalModels); + } + + // process adapterPopulatedRecordArrays + if (modelsToRemove.length > 0) { + removeFromAdapterPopulatedRecordArrays(modelsToRemove); + } + } + + _flush() { + heimdall.increment(_flush); + + let pending = this._pending; + this._pending = Object.create(null); + + for (let modelName in pending) { + this._flushPendingInternalModelsForModelName(modelName, pending[modelName]); + } + } + + updateLiveRecordArray(array, internalModels) { + return updateLiveRecordArray(array, internalModels); + } + + _syncLiveRecordArray(array, modelName) { + assert(`recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); + let pending = this._pending[modelName]; + let hasPendingChanges = Array.isArray(pending); + let hasNoPotentialDeletions = !hasPendingChanges || pending.length === 0; + let map = this.store._internalModelsFor(modelName); + let hasNoInsertionsOrRemovals = get(map, 'length') === get(array, 'length'); + + /* + Ideally the recordArrayManager has knowledge of the changes to be applied to + liveRecordArrays, and is capable of strategically flushing those changes and applying + small diffs if desired. However, until we've refactored recordArrayManager, this dirty + check prevents us from unnecessarily wiping out live record arrays returned by peekAll. + */ + if (hasNoPotentialDeletions && hasNoInsertionsOrRemovals) { + return; + } + + if (hasPendingChanges) { + this._flushPendingInternalModelsForModelName(modelName, pending); + delete pending[modelName]; + } + + let internalModels = this._visibleInternalModelsByType(modelName); + let modelsToAdd = []; + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; + let recordArrays = internalModel._recordArrays; + if (recordArrays.has(array) === false) { + recordArrays.add(array); + modelsToAdd.push(internalModel); + } + } + + if (modelsToAdd.length) { + array._pushInternalModels(modelsToAdd); + } + } + + _didUpdateAll(modelName) { + let recordArray = this._liveRecordArrays[modelName]; + if (recordArray) { + set(recordArray, 'isUpdating', false); + } + } + + /** + Get the `DS.RecordArray` for a modelName, which contains all loaded records of + given modelName. + + @method liveRecordArrayFor + @param {String} modelName + @return {DS.RecordArray} + */ + liveRecordArrayFor(modelName) { + assert(`recordArrayManger.liveRecordArrayFor expects modelName not modelClass as the param`, typeof modelName === 'string'); + + heimdall.increment(liveRecordArrayFor); + + let array = this._liveRecordArrays[modelName]; + + if (array) { + // if the array already exists, synchronize + this._syncLiveRecordArray(array, modelName); + } else { + // if the array is being newly created merely create it with its initial + // content already set. This prevents unneeded change events. + let internalModels = this._visibleInternalModelsByType(modelName); + array = this.createRecordArray(modelName, internalModels); + this._liveRecordArrays[modelName] = array; + } + + return array; + } + + _visibleInternalModelsByType(modelName) { + let all = this.store._internalModelsFor(modelName)._models; + let visible = []; + for (let i = 0; i < all.length; i++) { + let model = all[i]; + if (model.isHiddenFromRecordArrays() === false) { + visible.push(model); + } + } + return visible; + } + + /** + Create a `DS.RecordArray` for a modelName. + + @method createRecordArray + @param {String} modelName + @param {Array} _content (optional|private) + @return {DS.RecordArray} + */ + createRecordArray(modelName, content) { + assert(`recordArrayManger.createRecordArray expects modelName not modelClass as the param`, typeof modelName === 'string'); + heimdall.increment(createRecordArray); + + let array = RecordArray.create({ + modelName, + content: A(content || []), + store: this.store, + isLoaded: true, + manager: this + }); + + if (Array.isArray(content)) { + associateWithRecordArray(content, array); + } + + return array; + } + + /** + Create a `DS.AdapterPopulatedRecordArray` for a modelName with given query. + + @method createAdapterPopulatedRecordArray + @param {String} modelName + @param {Object} query + @return {DS.AdapterPopulatedRecordArray} + */ + createAdapterPopulatedRecordArray(modelName, query, internalModels, payload) { + heimdall.increment(createAdapterPopulatedRecordArray); + assert(`recordArrayManger.createAdapterPopulatedRecordArray expects modelName not modelClass as the first param, received ${modelName}`, typeof modelName === 'string'); + + let array; + if (Array.isArray(internalModels)) { + array = AdapterPopulatedRecordArray.create({ + modelName, + query: query, + content: A(internalModels), + store: this.store, + manager: this, + isLoaded: true, + isUpdating: false, + meta: cloneNull(payload.meta), + links: cloneNull(payload.links) + }); + + associateWithRecordArray(internalModels, array); + } else { + array = AdapterPopulatedRecordArray.create({ + modelName, + query: query, + content: A(), + store: this.store, + manager: this + }); + } + + this._adapterPopulatedRecordArrays.push(array); + + return array; + } + + /** + Unregister a RecordArray. + So manager will not update this array. + + @method unregisterRecordArray + @param {DS.RecordArray} array + */ + unregisterRecordArray(array) { + heimdall.increment(unregisterRecordArray); + + let modelName = array.modelName; + + // remove from adapter populated record array + let removedFromAdapterPopulated = remove(this._adapterPopulatedRecordArrays, array); + + if (!removedFromAdapterPopulated) { + + let liveRecordArrayForType = this._liveRecordArrays[modelName]; + // unregister live record array + if (liveRecordArrayForType) { + if (array === liveRecordArrayForType) { + delete this._liveRecordArrays[modelName]; + } + } + } + } + + _associateWithRecordArray(internalModels, array) { + associateWithRecordArray(internalModels, array); + } + + willDestroy() { + Object.keys(this._liveRecordArrays).forEach(modelName => this._liveRecordArrays[modelName].destroy()); + this._adapterPopulatedRecordArrays.forEach(destroy); + this.isDestroyed = true; + } + + destroy() { + this.isDestroying = true; + emberRun.schedule('actions', this, this.willDestroy); + } +} + +function destroy(entry) { + entry.destroy(); +} + +function remove(array, item) { + heimdall.increment(array_remove); + let index = array.indexOf(item); + + if (index !== -1) { + array.splice(index, 1); + return true; + } + + return false; +} + +function updateLiveRecordArray(array, internalModels) { + let modelsToAdd = []; + let modelsToRemove = []; + + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; + let isDeleted = internalModel.isHiddenFromRecordArrays(); + let recordArrays = internalModel._recordArrays; + + if (!isDeleted && !internalModel.isEmpty()) { + if (!recordArrays.has(array)) { + modelsToAdd.push(internalModel); + recordArrays.add(array); + } + } + + if (isDeleted) { + modelsToRemove.push(internalModel); + recordArrays.delete(array) + } + } + + if (modelsToAdd.length > 0) { array._pushInternalModels(modelsToAdd); } + if (modelsToRemove.length > 0) { array._removeInternalModels(modelsToRemove); } + + // return whether we performed an update. + // Necessary until 3.5 allows us to finish off ember-data-filter support. + return (modelsToAdd.length || modelsToRemove.length) > 0; +} + +function removeFromAdapterPopulatedRecordArrays(internalModels) { + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; + let list = internalModel._recordArrays.list; + + for (let j = 0; j < list.length; j++) { + // TODO: group by arrays, so we can batch remove + list[j]._removeInternalModels([internalModel]); + } + + internalModel._recordArrays.clear(); + } +} + +export function associateWithRecordArray(internalModels, array) { + for (let i = 0, l = internalModels.length; i < l; i++) { + let internalModel = internalModels[i]; + internalModel._recordArrays.add(array); + } +} diff --git a/addon/-record-data-rfc-private/system/record-arrays.js b/addon/-record-data-rfc-private/system/record-arrays.js new file mode 100644 index 00000000000..d65107ed72a --- /dev/null +++ b/addon/-record-data-rfc-private/system/record-arrays.js @@ -0,0 +1,11 @@ +/** + @module ember-data +*/ + +import RecordArray from "./record-arrays/record-array"; +import AdapterPopulatedRecordArray from "./record-arrays/adapter-populated-record-array"; + +export { + RecordArray, + AdapterPopulatedRecordArray +}; diff --git a/addon/-record-data-rfc-private/system/record-arrays/adapter-populated-record-array.js b/addon/-record-data-rfc-private/system/record-arrays/adapter-populated-record-array.js new file mode 100644 index 00000000000..7ccf8e89085 --- /dev/null +++ b/addon/-record-data-rfc-private/system/record-arrays/adapter-populated-record-array.js @@ -0,0 +1,92 @@ +import { once } from '@ember/runloop'; +import { A } from '@ember/array'; +import { get } from '@ember/object'; +import RecordArray from "./record-array"; +import cloneNull from "../clone-null"; + +/** + Represents an ordered list of records whose order and membership is + determined by the adapter. For example, a query sent to the adapter + may trigger a search on the server, whose results would be loaded + into an instance of the `AdapterPopulatedRecordArray`. + + --- + + If you want to update the array and get the latest records from the + adapter, you can invoke [`update()`](#method_update): + + Example + + ```javascript + // GET /users?isAdmin=true + var admins = store.query('user', { isAdmin: true }); + + admins.then(function() { + console.log(admins.get("length")); // 42 + }); + + // somewhere later in the app code, when new admins have been created + // in the meantime + // + // GET /users?isAdmin=true + admins.update().then(function() { + admins.get('isUpdating'); // false + console.log(admins.get("length")); // 123 + }); + + admins.get('isUpdating'); // true + ``` + + @class AdapterPopulatedRecordArray + @namespace DS + @extends DS.RecordArray +*/ +export default RecordArray.extend({ + init() { + // yes we are touching `this` before super, but ArrayProxy has a bug that requires this. + this.set('content', this.get('content') || A()); + + this._super(...arguments); + this.query = this.query || null; + this.links = this.links || null; + }, + + replace() { + throw new Error(`The result of a server query (on ${this.modelName}) is immutable.`); + }, + + _update() { + let store = get(this, 'store'); + let query = get(this, 'query'); + + return store._query(this.modelName, query, this); + }, + + /** + @method _setInternalModels + @param {Array} internalModels + @param {Object} payload normalized payload + @private + */ + _setInternalModels(internalModels, payload) { + let token = heimdall.start('AdapterPopulatedRecordArray._setInternalModels'); + + // TODO: initial load should not cause change events at all, only + // subsequent. This requires changing the public api of adapter.query, but + // hopefully we can do that soon. + this.get('content').setObjects(internalModels); + + this.setProperties({ + isLoaded: true, + isUpdating: false, + meta: cloneNull(payload.meta), + links: cloneNull(payload.links) + }); + + this.manager._associateWithRecordArray(internalModels, this); + + // TODO: should triggering didLoad event be the last action of the runLoop? + once(this, 'trigger', 'didLoad'); + heimdall.stop(token); + } +}); diff --git a/addon/-record-data-rfc-private/system/record-arrays/record-array.js b/addon/-record-data-rfc-private/system/record-arrays/record-array.js new file mode 100644 index 00000000000..71d2ffdef1c --- /dev/null +++ b/addon/-record-data-rfc-private/system/record-arrays/record-array.js @@ -0,0 +1,255 @@ +/** + @module ember-data +*/ + +import Evented from '@ember/object/evented'; + +import ArrayProxy from '@ember/array/proxy'; +import { set, get, computed } from '@ember/object'; +import { Promise } from 'rsvp'; +import { PromiseArray } from "../promise-proxies"; +import SnapshotRecordArray from "../snapshot-record-array"; + +/** + A record array is an array that contains records of a certain modelName. The record + array materializes records as needed when they are retrieved for the first + time. You should not create record arrays yourself. Instead, an instance of + `DS.RecordArray` or its subclasses will be returned by your application's store + in response to queries. + + @class RecordArray + @namespace DS + @extends Ember.ArrayProxy + @uses Ember.Evented +*/ + +export default ArrayProxy.extend(Evented, { + init() { + this._super(...arguments); + + /** + The array of client ids backing the record array. When a + record is requested from the record array, the record + for the client id at the same index is materialized, if + necessary, by the store. + + @property content + @private + @type Ember.Array + */ + this.set('content', this.content || null); + + /** + The flag to signal a `RecordArray` is finished loading data. + + Example + + ```javascript + var people = store.peekAll('person'); + people.get('isLoaded'); // true + ``` + + @property isLoaded + @type Boolean + */ + this.isLoaded = this.isLoaded || false; + /** + The flag to signal a `RecordArray` is currently loading data. + + Example + + ```javascript + var people = store.peekAll('person'); + people.get('isUpdating'); // false + people.update(); + people.get('isUpdating'); // true + ``` + + @property isUpdating + @type Boolean + */ + this.isUpdating = false; + + /** + The store that created this record array. + + @property store + @private + @type DS.Store + */ + this.store = this.store || null; + this._updatingPromise = null; + }, + + replace() { + throw new Error(`The result of a server query (for all ${this.modelName} types) is immutable. To modify contents, use toArray()`); + }, + + /** + The modelClass represented by this record array. + + @property type + @type DS.Model + */ + type: computed('modelName', function() { + if (!this.modelName) { + return null; + } + return this.store.modelFor(this.modelName); + }).readOnly(), + + /** + Retrieves an object from the content by index. + + @method objectAtContent + @private + @param {Number} index + @return {DS.Model} record + */ + objectAtContent(index) { + let internalModel = get(this, 'content').objectAt(index); + return internalModel && internalModel.getRecord(); + }, + + /** + Used to get the latest version of all of the records in this array + from the adapter. + + Example + + ```javascript + var people = store.peekAll('person'); + people.get('isUpdating'); // false + + people.update().then(function() { + people.get('isUpdating'); // false + }); + + people.get('isUpdating'); // true + ``` + + @method update + */ + update() { + if (get(this, 'isUpdating')) { return this._updatingPromise; } + + this.set('isUpdating', true); + + let updatingPromise = this._update().finally(() => { + this._updatingPromise = null; + if (this.get('isDestroying') || this.get('isDestroyed')) { return } + this.set('isUpdating', false); + }); + + this._updatingPromise = updatingPromise; + + return updatingPromise; + }, + + /* + Update this RecordArray and return a promise which resolves once the update + is finished. + */ + _update() { + return this.store.findAll(this.modelName, { reload: true }); + }, + + /** + Adds an internal model to the `RecordArray` without duplicates + + @method _pushInternalModels + @private + @param {InternalModel} internalModel + */ + _pushInternalModels(internalModels) { + // pushObjects because the internalModels._recordArrays set was already + // consulted for inclusion, so addObject and its on .contains call is not + // required. + get(this, 'content').pushObjects(internalModels); + }, + + /** + Removes an internalModel to the `RecordArray`. + + @method removeInternalModel + @private + @param {InternalModel} internalModel + */ + _removeInternalModels(internalModels) { + get(this, 'content').removeObjects(internalModels); + }, + + /** + Saves all of the records in the `RecordArray`. + + Example + + ```javascript + var messages = store.peekAll('message'); + messages.forEach(function(message) { + message.set('hasBeenSeen', true); + }); + messages.save(); + ``` + + @method save + @return {DS.PromiseArray} promise + */ + save() { + let promiseLabel = `DS: RecordArray#save ${this.modelName}`; + let promise = Promise.all(this.invoke('save'), promiseLabel) + .then(() => this, null, 'DS: RecordArray#save return RecordArray'); + + return PromiseArray.create({ promise }); + }, + + _dissociateFromOwnRecords() { + this.get('content').forEach(internalModel => { + let recordArrays = internalModel.__recordArrays; + + if (recordArrays) { + recordArrays.delete(this); + } + }); + }, + + /** + @method _unregisterFromManager + @private + */ + _unregisterFromManager() { + this.manager.unregisterRecordArray(this); + }, + + willDestroy() { + this._unregisterFromManager(); + this._dissociateFromOwnRecords(); + // TODO: we should not do work during destroy: + // * when objects are destroyed, they should simply be left to do + // * if logic errors do to this, that logic needs to be more careful during + // teardown (ember provides isDestroying/isDestroyed) for this reason + // * the exception being: if an dominator has a reference to this object, + // and must be informed to release e.g. e.g. removing itself from th + // recordArrayMananger + set(this, 'content', null); + set(this, 'length', 0); + this._super(...arguments); + }, + + /* + @method _createSnapshot + @private + */ + _createSnapshot(options) { + // this is private for users, but public for ember-data internals + return new SnapshotRecordArray(this, this.get('meta'), options); + }, + + /* + @method _takeSnapshot + @private + */ + _takeSnapshot() { + return get(this, 'content').map(internalModel => internalModel.createSnapshot()); + } +}); diff --git a/addon/-record-data-rfc-private/system/references.js b/addon/-record-data-rfc-private/system/references.js new file mode 100644 index 00000000000..ad073f586ca --- /dev/null +++ b/addon/-record-data-rfc-private/system/references.js @@ -0,0 +1,5 @@ +import RecordReference from './references/record'; +import BelongsToReference from './references/belongs-to'; +import HasManyReference from './references/has-many'; + +export { RecordReference, BelongsToReference, HasManyReference }; diff --git a/addon/-record-data-rfc-private/system/references/belongs-to.js b/addon/-record-data-rfc-private/system/references/belongs-to.js new file mode 100644 index 00000000000..8938e8265eb --- /dev/null +++ b/addon/-record-data-rfc-private/system/references/belongs-to.js @@ -0,0 +1,307 @@ +import { resolve } from 'rsvp'; +import Model from '../model/model'; +import Reference from './reference'; + +import isEnabled from '../../features'; +import { deprecate } from '@ember/debug'; +import { assertPolymorphicType } from 'ember-data/-debug'; + +/** + A BelongsToReference is a low level API that allows users and + addon author to perform meta-operations on a belongs-to + relationship. + + @class BelongsToReference + @namespace DS + @extends DS.Reference + */ +export default class BelongsToReference extends Reference { + constructor(store, parentInternalModel, belongsToRelationship, key) { + super(store, parentInternalModel); + this.key = key; + this.belongsToRelationship = belongsToRelationship; + this.type = belongsToRelationship.relationshipMeta.type; + this.parent = parentInternalModel.recordReference; + this.parentInternalModel = parentInternalModel; + + // TODO inverse + } + + /** + The `id` of the record that this reference refers to. Together, the + `type()` and `id()` methods form a composite key for the identity + map. This can be used to access the id of an async relationship + without triggering a fetch that would normally happen if you + attempted to use `record.get('relationship.id')`. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + let userRef = blog.belongsTo('user'); + + // get the identifier of the reference + if (userRef.remoteType() === "id") { + let id = userRef.id(); + } + ``` + + @method id + @return {String} The id of the record in this belongsTo relationship. + */ + id() { + let id = null; + let resource = this._resource(); + if (resource && resource.data && resource.data.id) { + id = resource.data.id; + } + return id; + } + + _resource() { + return this.modelData.getBelongsTo(this.key); + } + + /** + `push` can be used to update the data in the relationship and Ember + Data will treat the new data as the conanical value of this + relationship on the backend. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + let userRef = blog.belongsTo('user'); + + // provide data for reference + userRef.push({ + data: { + type: 'user', + id: 1, + attributes: { + username: "@user" + } + } + }).then(function(user) { + userRef.value() === user; + }); + ``` + + @method push + @param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. + @return {Promise} A promise that resolves with the new value in this belongs-to relationship. + */ + push(objectOrPromise) { + return resolve(objectOrPromise).then((data) => { + let record; + + if (data instanceof Model) { + if (isEnabled('ds-overhaul-references')) { + deprecate("BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead.", false, { + id: 'ds.references.belongs-to.push-record', + until: '4.0.0' + }); + } + record = data; + } else { + record = this.store.push(data); + } + + assertPolymorphicType(this.internalModel, this.belongsToRelationship.relationshipMeta, record._internalModel, this.store); + + //TODO Igor cleanup, maybe move to relationship push + this.belongsToRelationship.setCanonicalModelData(record._internalModel._modelData); + + return record; + }); + } + + /** + `value()` synchronously returns the current value of the belongs-to + relationship. Unlike `record.get('relationshipName')`, calling + `value()` on a reference does not trigger a fetch if the async + relationship is not yet loaded. If the relationship is not loaded + it will always return `null`. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + let userRef = blog.belongsTo('user'); + + userRef.value(); // null + + // provide data for reference + userRef.push({ + data: { + type: 'user', + id: 1, + attributes: { + username: "@user" + } + } + }).then(function(user) { + userRef.value(); // user + }); + ``` + + @method value + @return {DS.Model} the record in this relationship + */ + value() { + let store = this.parentInternalModel.store; + let resource = this._resource(); + if (resource && resource.data) { + let inverseInternalModel = store._internalModelForResource(resource.data); + if (inverseInternalModel && inverseInternalModel.isLoaded()) { + return inverseInternalModel.getRecord(); + } + } + + return null; + } + + /** + Loads a record in a belongs to relationship if it is not already + loaded. If the relationship is already loaded this method does not + trigger a new load. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + let userRef = blog.belongsTo('user'); + + userRef.value(); // null + + userRef.load().then(function(user) { + userRef.value() === user + }); + ``` + + @method load + @return {Promise} a promise that resolves with the record in this belongs-to relationship. + */ + load() { + return this.parentInternalModel.getBelongsTo(this.key); + } + + + /** + Triggers a reload of the value in this relationship. If the + remoteType is `"link"` Ember Data will use the relationship link to + reload the relationship. Otherwise it will reload the record by its + id. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + data: { type: 'user', id: 1 } + } + } + } + }); + let userRef = blog.belongsTo('user'); + + userRef.reload().then(function(user) { + userRef.value() === user + }); + ``` + + @method reload + @return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed. + */ + // TODO IGOR CHECK FOR OBJECT PROXIES + reload() { + let resource = this._resource(); + if (resource && resource.links && resource.links.related) { + return this.store._fetchBelongsToLinkFromResource(resource, this.parentInternalModel, this.belongsToRelationship.relationshipMeta); + } + if (resource && resource.data) { + if (resource.data && (resource.data.id || resource.data.clientId)) { + let internalModel = this.store._internalModelForResource(resource.data); + if (internalModel.isLoaded()) { + return internalModel.reload().then((internalModel) => { + if (internalModel) { + return internalModel.getRecord(); + } + return null; + }); + } else { + return this.store._findByInternalModel(internalModel); + } + } + } + } +} diff --git a/addon/-record-data-rfc-private/system/references/has-many.js b/addon/-record-data-rfc-private/system/references/has-many.js new file mode 100644 index 00000000000..f0a44b728b9 --- /dev/null +++ b/addon/-record-data-rfc-private/system/references/has-many.js @@ -0,0 +1,332 @@ +import { resolve } from 'rsvp'; +import { get } from '@ember/object'; +import Reference from './reference'; +import { DEBUG } from '@glimmer/env'; +import { assertPolymorphicType } from 'ember-data/-debug'; + +/** + A HasManyReference is a low level API that allows users and addon + author to perform meta-operations on a has-many relationship. + + @class HasManyReference + @namespace DS + */ +export default class HasManyReference extends Reference { + constructor(store, parentInternalModel, hasManyRelationship, key) { + super(store, parentInternalModel); + this.key = key; + this.hasManyRelationship = hasManyRelationship; + this.type = hasManyRelationship.relationshipMeta.type; + this.parent = parentInternalModel.recordReference; + this.parentInternalModel = parentInternalModel; + + // TODO inverse + } + + _resource() { + return this.modelData.getHasMany(this.key); + } + + /** + This returns a string that represents how the reference will be + looked up when it is loaded. If the relationship has a link it will + use the "link" otherwise it defaults to "id". + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + // get the identifier of the reference + if (commentsRef.remoteType() === "ids") { + let ids = commentsRef.ids(); + } else if (commentsRef.remoteType() === "link") { + let link = commentsRef.link(); + } + ``` + + @method remoteType + @return {String} The name of the remote type. This should either be "link" or "ids" + */ + remoteType() { + let value = this._resource(); + if (value && value.links && value.links.related) { + return "link"; + } + + return "ids"; + } + + + /** + `ids()` returns an array of the record ids in this relationship. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + commentsRef.ids(); // ['1'] + ``` + + @method ids + @return {Array} The ids in this has-many relationship + */ + ids() { + let resource = this._resource(); + + let ids = []; + if (resource.data) { + ids = resource.data.map((data) => data.id); + } + + return ids; + } + + + + /** + `push` can be used to update the data in the relationship and Ember + Data will treat the new data as the canonical value of this + relationship on the backend. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ``` + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + commentsRef.ids(); // ['1'] + + commentsRef.push([ + [{ type: 'comment', id: 2 }], + [{ type: 'comment', id: 3 }], + ]) + + commentsRef.ids(); // ['2', '3'] + ``` + + @method push + @param {Array|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. + @return {DS.ManyArray} + */ + push(objectOrPromise) { + return resolve(objectOrPromise).then((payload) => { + let array = payload; + + if (typeof payload === "object" && payload.data) { + array = payload.data; + } + + let internalModels = array.map((obj) => { + let record = this.store.push(obj); + + if (DEBUG) { + let relationshipMeta = this.hasManyRelationship.relationshipMeta; + assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel, this.store); + } + return record._internalModel._modelData; + }); + + this.hasManyRelationship.computeChanges(internalModels); + + return this.internalModel.getHasMany(this.hasManyRelationship.key); + // TODO IGOR it seems wrong that we were returning the many array here + //return this.hasManyRelationship.manyArray; + }); + } + + _isLoaded() { + let hasRelationshipDataProperty = get(this.hasManyRelationship, 'hasAnyRelationshipData'); + if (!hasRelationshipDataProperty) { + return false; + } + + let members = this.hasManyRelationship.members.toArray(); + + //TODO Igor cleanup + return members.every((modelData) => { + let store = this.parentInternalModel.store; + let internalModel = store._internalModelForModelData(modelData); + return internalModel.isLoaded() === true; + }); + } + + /** + `value()` synchronously returns the current value of the has-many + relationship. Unlike `record.get('relationshipName')`, calling + `value()` on a reference does not trigger a fetch if the async + relationship is not yet loaded. If the relationship is not loaded + it will always return `null`. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + post.get('comments').then(function(comments) { + commentsRef.value() === comments + }) + ``` + + @method value + @return {DS.ManyArray} + */ + value() { + if (this._isLoaded()) { + return this.internalModel.getManyArray(this.key); + } + + return null; + } + + /** + Loads the relationship if it is not already loaded. If the + relationship is already loaded this method does not trigger a new + load. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + commentsRef.load().then(function(comments) { + //... + }); + ``` + + @method load + @return {Promise} a promise that resolves with the ManyArray in + this has-many relationship. + */ + load() { + return this.internalModel.getHasMany(this.key); + } + + /** + Reloads this has-many relationship. + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + commentsRef.reload().then(function(comments) { + //... + }); + ``` + + @method reload + @return {Promise} a promise that resolves with the ManyArray in this has-many relationship. + */ + reload() { + return this.internalModel.reloadHasMany(this.key); + } +} diff --git a/addon/-record-data-rfc-private/system/references/record.js b/addon/-record-data-rfc-private/system/references/record.js new file mode 100644 index 00000000000..086945b3a22 --- /dev/null +++ b/addon/-record-data-rfc-private/system/references/record.js @@ -0,0 +1,163 @@ +import { resolve } from 'rsvp'; +import Reference from './reference'; + +/** + An RecordReference is a low level API that allows users and + addon author to perform meta-operations on a record. + + @class RecordReference + @namespace DS +*/ +export default class RecordReference extends Reference { + constructor(store, internalModel) { + super(store, internalModel); + this.type = internalModel.modelName; + this._id = internalModel.id; + } + + /** + The `id` of the record that this reference refers to. + + Together, the `type` and `id` properties form a composite key for + the identity map. + + Example + + ```javascript + let userRef = store.getReference('user', 1); + + userRef.id(); // '1' + ``` + + @method id + @return {String} The id of the record. + */ + id() { + return this._id; + } + + /** + How the reference will be looked up when it is loaded: Currently + this always return `identity` to signifying that a record will be + loaded by the `type` and `id`. + + Example + + ```javascript + const userRef = store.getReference('user', 1); + + userRef.remoteType(); // 'identity' + ``` + + @method remoteType + @return {String} 'identity' + */ + remoteType() { + return 'identity'; + } + + /** + This API allows you to provide a reference with new data. The + simplest usage of this API is similar to `store.push`: you provide a + normalized hash of data and the object represented by the reference + will update. + + If you pass a promise to `push`, Ember Data will not ask the adapter + for the data if another attempt to fetch it is made in the + interim. When the promise resolves, the underlying object is updated + with the new data, and the promise returned by *this function* is resolved + with that object. + + For example, `recordReference.push(promise)` will be resolved with a + record. + + Example + + ```javascript + let userRef = store.getReference('user', 1); + + // provide data for reference + userRef.push({ data: { id: 1, username: "@user" }}).then(function(user) { + userRef.value() === user; + }); + ``` + + @method push + @param objectOrPromise {Promise|Object} + @return Promise a promise for the value (record or relationship) + */ + push(objectOrPromise) { + return resolve(objectOrPromise).then((data) => { + return this.store.push(data); + }); + } + + /** + If the entity referred to by the reference is already loaded, it is + present as `reference.value`. Otherwise the value returned by this function + is `null`. + + Example + + ```javascript + let userRef = store.getReference('user', 1); + + userRef.value(); // user + ``` + + @method value + @return {DS.Model} the record for this RecordReference + */ + value() { + if (this.internalModel.hasRecord) { + return this.internalModel.getRecord(); + } + return null; + } + + /** + Triggers a fetch for the backing entity based on its `remoteType` + (see `remoteType` definitions per reference type). + + Example + + ```javascript + let userRef = store.getReference('user', 1); + + // load user (via store.find) + userRef.load().then(...) + ``` + + @method load + @return {Promise} the record for this RecordReference + */ + load() { + return this.store.findRecord(this.type, this._id); + } + + /** + Reloads the record if it is already loaded. If the record is not + loaded it will load the record via `store.findRecord` + + Example + + ```javascript + let userRef = store.getReference('user', 1); + + // or trigger a reload + userRef.reload().then(...) + ``` + + @method reload + @return {Promise} the record for this RecordReference + */ + reload() { + let record = this.value(); + if (record) { + return record.reload(); + } + + return this.load(); + } + +} diff --git a/addon/-record-data-rfc-private/system/references/reference.js b/addon/-record-data-rfc-private/system/references/reference.js new file mode 100644 index 00000000000..6c54cf75ba1 --- /dev/null +++ b/addon/-record-data-rfc-private/system/references/reference.js @@ -0,0 +1,152 @@ +var Reference = function(store, internalModel) { + this.store = store; + this.internalModel = internalModel; + this.modelData = internalModel._modelData; +}; + +Reference.prototype = { + constructor: Reference +}; + +/** + This returns a string that represents how the reference will be + looked up when it is loaded. If the relationship has a link it will + use the "link" otherwise it defaults to "id". + + Example + + ```app/models/post.js + export default DS.Model.extend({ + comments: DS.hasMany({ async: true }) + }); + ``` + + ```javascript + let post = store.push({ + data: { + type: 'post', + id: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: 1 }] + } + } + } + }); + + let commentsRef = post.hasMany('comments'); + + // get the identifier of the reference + if (commentsRef.remoteType() === "ids") { + let ids = commentsRef.ids(); + } else if (commentsRef.remoteType() === "link") { + let link = commentsRef.link(); + } + ``` + + @method remoteType + @return {String} The name of the remote type. This should either be "link" or "ids" +*/ +Reference.prototype.remoteType = function() { + let value = this._resource(); + if (value && value.links && value.links.related) { + return "link"; + } + + return "id"; +}; + +/** + The link Ember Data will use to fetch or reload this belongs-to + relationship. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + links: { + related: '/articles/1/author' + } + } + } + } + }); + let userRef = blog.belongsTo('user'); + + // get the identifier of the reference + if (userRef.remoteType() === "link") { + let link = userRef.link(); + } + ``` + + @method link + @return {String} The link Ember Data will use to fetch or reload this belongs-to relationship. +*/ +Reference.prototype.link = function() { + let link = null; + let resource = this._resource(); + + if (resource && resource.links && resource.links.related) { + link = resource.links.related; + } + return link; +}; + +/** + The meta data for the belongs-to relationship. + + Example + + ```javascript + // models/blog.js + export default DS.Model.extend({ + user: DS.belongsTo({ async: true }) + }); + + let blog = store.push({ + data: { + type: 'blog', + id: 1, + relationships: { + user: { + links: { + related: { + href: '/articles/1/author', + meta: { + lastUpdated: 1458014400000 + } + } + } + } + } + } + }); + + let userRef = blog.belongsTo('user'); + + userRef.meta() // { lastUpdated: 1458014400000 } + ``` + + @method meta + @return {Object} The meta information for the belongs-to relationship. +*/ +Reference.prototype.meta = function() { + let meta = null; + let resource = this._resource(); + if (resource && resource.meta) { + meta = resource.meta; + } + return meta; +}; + +export default Reference; diff --git a/addon/-record-data-rfc-private/system/relationship-meta.js b/addon/-record-data-rfc-private/system/relationship-meta.js new file mode 100644 index 00000000000..2951df4c616 --- /dev/null +++ b/addon/-record-data-rfc-private/system/relationship-meta.js @@ -0,0 +1,96 @@ +import { singularize } from 'ember-inflector'; +import { DEBUG } from '@glimmer/env'; +import normalizeModelName from './normalize-model-name'; + +export function typeForRelationshipMeta(meta) { + let modelName; + + modelName = meta.type || meta.key; + if (meta.kind === 'hasMany') { + modelName = singularize(normalizeModelName(modelName)); + } + return modelName; +} + +function shouldFindInverse(relationshipMeta) { + let options = relationshipMeta.options; + return !(options && options.inverse === null); +} + +class RelationshipDefinition { + constructor(meta) { + this.meta = meta; + this._type = ''; + this.__inverseKey = ''; + this.__inverseIsAsync = null; + this.modelClass = meta.parentType; + this.store = null; + } + + get key() { + return this.meta.key; + } + get kind() { + return this.meta.kind; + } + get type() { + if (this._type) { + return this._type; + } + this._type = typeForRelationshipMeta(this.meta); + return this._type; + } + get options() { + return this.meta.options; + } + get name() { + return this.meta.name; + } + get parentType() { + return this.meta.parentType; + } + + _inverseKey(store, modelClass) { + if (this.__inverseKey === '') { + this._calculateInverse(store, modelClass); + } + return this.__inverseKey; + } + + _inverseIsAsync(store, modelClass) { + if (this.__inverseIsAsync === null) { + this._calculateInverse(store, modelClass); + } + return this.__inverseIsAsync; + } + + _calculateInverse(store, modelClass) { + let inverseKey, inverseIsAsync; + let inverse = null; + + if (shouldFindInverse(this.meta)) { + inverse = modelClass.inverseFor(this.key, store); + } else if (DEBUG) { + modelClass.typeForRelationship(this.key, store); + } + + if (inverse) { + inverseKey = inverse.name; + inverseIsAsync = isInverseAsync(inverse); + } else { + inverseKey = null; + inverseIsAsync = false; + } + this.__inverseKey = inverseKey; + this.__inverseIsAsync = inverseIsAsync; + } +} + +function isInverseAsync(meta) { + let inverseAsync = meta.options && meta.options.async; + return typeof inverseAsync === 'undefined' ? true : inverseAsync; +} + +export function relationshipFromMeta(meta) { + return new RelationshipDefinition(meta); +} diff --git a/addon/-record-data-rfc-private/system/relationships/belongs-to.js b/addon/-record-data-rfc-private/system/relationships/belongs-to.js new file mode 100644 index 00000000000..f979a8a7fc2 --- /dev/null +++ b/addon/-record-data-rfc-private/system/relationships/belongs-to.js @@ -0,0 +1,126 @@ +import { computed } from '@ember/object'; +import { assert, warn, inspect } from '@ember/debug'; +import normalizeModelName from "../normalize-model-name"; + +/** + `DS.belongsTo` is used to define One-To-One and One-To-Many + relationships on a [DS.Model](/api/data/classes/DS.Model.html). + + + `DS.belongsTo` takes an optional hash as a second parameter, currently + supported options are: + + - `async`: A boolean value used to explicitly declare this to be an async relationship. + - `inverse`: A string used to identify the inverse property on a + related model in a One-To-Many relationship. See [Explicit Inverses](#toc_explicit-inverses) + + #### One-To-One + To declare a one-to-one relationship between two models, use + `DS.belongsTo`: + + ```app/models/user.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + profile: DS.belongsTo('profile') + }); + ``` + + ```app/models/profile.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + user: DS.belongsTo('user') + }); + ``` + + #### One-To-Many + To declare a one-to-many relationship between two models, use + `DS.belongsTo` in combination with `DS.hasMany`, like this: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + comments: DS.hasMany('comment') + }); + ``` + + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + post: DS.belongsTo('post') + }); + ``` + + You can avoid passing a string as the first parameter. In that case Ember Data + will infer the type from the key name. + + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + post: DS.belongsTo() + }); + ``` + + will lookup for a Post type. + + @namespace + @method belongsTo + @for DS + @param {String} modelName (optional) type of the relationship + @param {Object} options (optional) a hash of options + @return {Ember.computed} relationship +*/ +export default function belongsTo(modelName, options) { + let opts, userEnteredModelName; + if (typeof modelName === 'object') { + opts = modelName; + userEnteredModelName = undefined; + } else { + opts = options; + userEnteredModelName = modelName; + } + + if (typeof userEnteredModelName === 'string') { + userEnteredModelName = normalizeModelName(userEnteredModelName); + } + + assert("The first argument to DS.belongsTo must be a string representing a model type key, not an instance of " + inspect(userEnteredModelName) + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", typeof userEnteredModelName === 'string' || typeof userEnteredModelName === 'undefined'); + + opts = opts || {}; + + let meta = { + type: userEnteredModelName, + isRelationship: true, + options: opts, + kind: 'belongsTo', + name: 'Belongs To', + key: null + }; + + return computed({ + get(key) { + if (opts.hasOwnProperty('serialize')) { + warn(`You provided a serialize option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.Serializer and it's implementations https://emberjs.com/api/data/classes/DS.Serializer.html`, false, { + id: 'ds.model.serialize-option-in-belongs-to' + }); + } + + if (opts.hasOwnProperty('embedded')) { + warn(`You provided an embedded option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin https://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html`, false, { + id: 'ds.model.embedded-option-in-belongs-to' + }); + } + + return this._internalModel.getBelongsTo(key); + }, + set(key, value) { + this._internalModel.setDirtyBelongsTo(key, value); + + return this._internalModel.getBelongsTo(key); + } + }).meta(meta); +} diff --git a/addon/-record-data-rfc-private/system/relationships/ext.js b/addon/-record-data-rfc-private/system/relationships/ext.js new file mode 100644 index 00000000000..058de16a08c --- /dev/null +++ b/addon/-record-data-rfc-private/system/relationships/ext.js @@ -0,0 +1,76 @@ +import { A } from '@ember/array'; +import { computed, get } from '@ember/object'; +import MapWithDefault from '../map-with-default'; +import Map from '../map'; +import { assert } from '@ember/debug'; +import { + typeForRelationshipMeta, + relationshipFromMeta +} from "../relationship-meta"; + +export const relationshipsDescriptor = computed(function() { + let map = new MapWithDefault({ + defaultValue() { return []; } + }); + + let relationshipsByName = get(this, 'relationshipsByName'); + + // Loop through each computed property on the class + relationshipsByName.forEach(desc => { + let relationshipsForType = map.get(desc.type); + relationshipsForType.push(desc); + }); + + return map; +}).readOnly(); + +export const relatedTypesDescriptor = computed(function() { + let modelName; + let types = A(); + + // Loop through each computed property on the class, + // and create an array of the unique types involved + // in relationships + this.eachComputedProperty((name, meta) => { + if (meta.isRelationship) { + meta.key = name; + modelName = typeForRelationshipMeta(meta); + + assert(`You specified a hasMany (${meta.type}) on ${meta.parentType} but ${meta.type} was not found.`, modelName); + + if (!types.includes(modelName)) { + assert(`Trying to sideload ${name} on ${this.toString()} but the type doesn't exist.`, !!modelName); + types.push(modelName); + } + } + }); + + return types; +}).readOnly(); + +export const relationshipsObjectDescriptor = computed(function() { + let relationships = Object.create(null); + this.eachComputedProperty((name, meta) => { + if (meta.isRelationship) { + meta.key = name; + meta.name = name; + relationships[name] = relationshipFromMeta(meta); + } + }); + return relationships; +}); + +export const relationshipsByNameDescriptor = computed(function() { + let map = new Map(); + let rels = get(this, 'relationshipsObject'); + let relationships = Object.keys(rels); + + for (let i=0; i < relationships.length; i++) { + let key = relationships[i]; + let value = rels[key]; + + map.set(value.key, value); + } + + return map; +}).readOnly(); diff --git a/addon/-record-data-rfc-private/system/relationships/has-many.js b/addon/-record-data-rfc-private/system/relationships/has-many.js new file mode 100644 index 00000000000..be80f3bf32b --- /dev/null +++ b/addon/-record-data-rfc-private/system/relationships/has-many.js @@ -0,0 +1,152 @@ +/** + @module ember-data +*/ +import { computed } from '@ember/object'; +import { assert, inspect } from '@ember/debug'; +import normalizeModelName from "../normalize-model-name"; + +/** + `DS.hasMany` is used to define One-To-Many and Many-To-Many + relationships on a [DS.Model](/api/data/classes/DS.Model.html). + + `DS.hasMany` takes an optional hash as a second parameter, currently + supported options are: + + - `async`: A boolean value used to explicitly declare this to be an async relationship. + - `inverse`: A string used to identify the inverse property on a related model. + + #### One-To-Many + To declare a one-to-many relationship between two models, use + `DS.belongsTo` in combination with `DS.hasMany`, like this: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + comments: DS.hasMany('comment') + }); + ``` + + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + post: DS.belongsTo('post') + }); + ``` + + #### Many-To-Many + To declare a many-to-many relationship between two models, use + `DS.hasMany`: + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + tags: DS.hasMany('tag') + }); + ``` + + ```app/models/tag.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + posts: DS.hasMany('post') + }); + ``` + + You can avoid passing a string as the first parameter. In that case Ember Data + will infer the type from the singularized key name. + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + tags: DS.hasMany() + }); + ``` + + will lookup for a Tag type. + + #### Explicit Inverses + + Ember Data will do its best to discover which relationships map to + one another. In the one-to-many code above, for example, Ember Data + can figure out that changing the `comments` relationship should update + the `post` relationship on the inverse because post is the only + relationship to that model. + + However, sometimes you may have multiple `belongsTo`/`hasMany` for the + same type. You can specify which property on the related model is + the inverse using `DS.hasMany`'s `inverse` option: + + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + onePost: DS.belongsTo('post'), + twoPost: DS.belongsTo('post'), + redPost: DS.belongsTo('post'), + bluePost: DS.belongsTo('post') + }); + ``` + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + comments: DS.hasMany('comment', { + inverse: 'redPost' + }) + }); + ``` + + You can also specify an inverse on a `belongsTo`, which works how + you'd expect. + + @namespace + @method hasMany + @for DS + @param {String} type (optional) type of the relationship + @param {Object} options (optional) a hash of options + @return {Ember.computed} relationship +*/ +export default function hasMany(type, options) { + if (typeof type === 'object') { + options = type; + type = undefined; + } + + assert(`The first argument to DS.hasMany must be a string representing a model type key, not an instance of ${inspect(type)}. E.g., to define a relation to the Comment model, use DS.hasMany('comment')`, typeof type === 'string' || typeof type === 'undefined'); + + options = options || {}; + + if (typeof type === 'string') { + type = normalizeModelName(type); + } + + // Metadata about relationships is stored on the meta of + // the relationship. This is used for introspection and + // serialization. Note that `key` is populated lazily + // the first time the CP is called. + let meta = { + type, + options, + isRelationship: true, + kind: 'hasMany', + name: 'Has Many', + key: null + }; + + return computed({ + get(key) { + return this._internalModel.getHasMany(key); + }, + set(key, records) { + let internalModel = this._internalModel; + internalModel.setDirtyHasMany(key, records); + + return internalModel.getHasMany(key); + } + }).meta(meta); +} diff --git a/addon/-record-data-rfc-private/system/relationships/state/belongs-to.js b/addon/-record-data-rfc-private/system/relationships/state/belongs-to.js new file mode 100644 index 00000000000..85d46804c97 --- /dev/null +++ b/addon/-record-data-rfc-private/system/relationships/state/belongs-to.js @@ -0,0 +1,196 @@ +import { assert, inspect } from '@ember/debug'; +import { assertPolymorphicType } from 'ember-data/-debug'; +import { isNone } from '@ember/utils'; +import Relationship from "./relationship"; + +export default class BelongsToRelationship extends Relationship { + constructor(store, inverseKey, relationshipMeta, modelData, inverseIsAsync) { + super(store, inverseKey, relationshipMeta, modelData, inverseIsAsync); + this.key = relationshipMeta.key; + this.inverseModelData = null; + this.canonicalState = null; + } + + setModelData(modelData) { + if (modelData) { + this.addModelData(modelData); + } else if (this.inverseModelData) { + this.removeModelData(this.inverseModelData); + } + + this.setHasAnyRelationshipData(true); + this.setRelationshipIsStale(false); + this.setRelationshipIsEmpty(false); + } + + setCanonicalModelData(modelData) { + if (modelData) { + this.addCanonicalModelData(modelData); + } else if (this.canonicalState) { + this.removeCanonicalModelData(this.canonicalState); + } + this.flushCanonicalLater(); + } + + setInitialCanonicalModelData(modelData) { + if (!modelData) { return; } + + // When we initialize a belongsTo relationship, we want to avoid work like + // notifying our internalModel that we've "changed" and excessive thrash on + // setting up inverse relationships + this.canonicalMembers.add(modelData); + this.members.add(modelData); + this.inverseModelData = this.canonicalState = modelData; + this.setupInverseRelationship(modelData); + } + + addCanonicalModelData(modelData) { + if (this.canonicalMembers.has(modelData)) { return;} + + if (this.canonicalState) { + this.removeCanonicalModelData(this.canonicalState); + } + + this.canonicalState = modelData; + super.addCanonicalModelData(modelData); + } + + inverseDidDematerialize() { + super.inverseDidDematerialize(this.inverseModelData); + this.notifyBelongsToChanged(); + } + + removeCompletelyFromOwn(modelData) { + super.removeCompletelyFromOwn(modelData); + + if (this.canonicalState === modelData) { + this.canonicalState = null; + } + + if (this.inverseModelData === modelData) { + this.inverseModelData = null; + this.notifyBelongsToChanged(); + } + } + + + removeCompletelyFromInverse() { + super.removeCompletelyFromInverse(); + + this.inverseModelData = null; + } + + flushCanonical() { + //temporary fix to not remove newly created records if server returned null. + //TODO remove once we have proper diffing + if (this.inverseModelData && this.inverseModelData.isNew() && !this.canonicalState) { + this.willSync = false; + return; + } + if (this.inverseModelData !== this.canonicalState) { + this.inverseModelData = this.canonicalState; + this.notifyBelongsToChanged(); + } + super.flushCanonical(); + } + + addModelData(modelData) { + if (this.members.has(modelData)) { return; } + + // TODO Igor cleanup + assertPolymorphicType(this.modelData, this.relationshipMeta, modelData, this.store); + + if (this.inverseModelData) { + this.removeModelData(this.inverseModelData); + } + + this.inverseModelData = modelData; + super.addModelData(modelData); + this.notifyBelongsToChanged(); + } + + setRecordPromise(newPromise) { + let content = newPromise.get && newPromise.get('content'); + assert("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); + // TODO Igor deal with this + this.setModelData(content ? content._internalModel._modelData : content); + } + + removeModelDataFromOwn(modelData) { + if (!this.members.has(modelData)) { return;} + this.inverseModelData = null; + super.removeModelDataFromOwn(modelData); + this.notifyBelongsToChanged(); + } + + removeAllModelDatasFromOwn() { + super.removeAllModelDatasFromOwn(); + this.inverseModelData = null; + this.notifyBelongsToChanged(); + } + + notifyBelongsToChanged() { + let modelData = this.modelData; + let storeWrapper = this.modelData.storeWrapper; + storeWrapper.notifyBelongsToChange(modelData.modelName, modelData.id, modelData.clientId, this.key); + } + + removeCanonicalModelDataFromOwn(modelData) { + if (!this.canonicalMembers.has(modelData)) { return;} + this.canonicalState = null; + super.removeCanonicalModelDataFromOwn(modelData); + } + + removeAllCanonicalModelDatasFromOwn() { + super.removeAllCanonicalModelDatasFromOwn(); + this.canonicalState = null; + } + + getData() { + let data; + let payload = {}; + if (this.inverseModelData) { + data = this.inverseModelData.getResourceIdentifier(); + } + if (this.inverseModelData === null && this.hasAnyRelationshipData) { + data = null; + } + if (this.link) { + payload.links = { + related: this.link + } + } + if (data !== undefined) { + payload.data = data; + } + if (this.meta) { + payload.meta = this.meta; + } + + payload._relationship = this; + return payload; + } + + localStateIsEmpty() { + let modelData = this.inverseModelData; + + return !modelData || modelData.isEmpty(); + } + + updateData(data, initial) { + let modelData; + if (isNone(data)) { + modelData = null; + } + assert(`Ember Data expected the data for the ${this.key} relationship on a ${this.modelData.toString()} to be in a JSON API format and include an \`id\` and \`type\` property but it found ${inspect(data)}. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || data.id !== undefined && data.type !== undefined); + + if (modelData !== null) { + modelData = this.modelData.storeWrapper.modelDataFor(data.type, data.id); + } + if (initial) { + this.setInitialCanonicalModelData(modelData); + } else { + this.setCanonicalModelData(modelData); + } + } +} diff --git a/addon/-record-data-rfc-private/system/relationships/state/create.js b/addon/-record-data-rfc-private/system/relationships/state/create.js new file mode 100644 index 00000000000..fa69818b8c8 --- /dev/null +++ b/addon/-record-data-rfc-private/system/relationships/state/create.js @@ -0,0 +1,47 @@ +import ManyRelationship from "./has-many"; +import BelongsToRelationship from "./belongs-to"; + +function createRelationshipFor(relationshipMeta, store, modelData, key) { + let inverseKey = modelData.storeWrapper.inverseForRelationship(modelData.modelName, key); + let inverseIsAsync = modelData.storeWrapper.inverseIsAsyncForRelationship(modelData.modelName, key); + + if (relationshipMeta.kind === 'hasMany') { + return new ManyRelationship(store, inverseKey, relationshipMeta, modelData, inverseIsAsync); + } else { + return new BelongsToRelationship(store, inverseKey, relationshipMeta, modelData, inverseIsAsync); + } +} + +export default class Relationships { + constructor(modelData) { + this.modelData = modelData; + this.initializedRelationships = Object.create(null); + } + + has(key) { + return !!this.initializedRelationships[key]; + } + + forEach(cb) { + let rels = this.initializedRelationships; + Object.keys(rels).forEach(name => { + cb(name, rels[name]); + }); + } + + get(key) { + let relationships = this.initializedRelationships; + let relationship = relationships[key]; + + if (!relationship) { + let modelData = this.modelData; + let rel = this.modelData.storeWrapper.relationshipsDefinitionFor(this.modelData.modelName)[key]; + + if (rel) { + relationship = relationships[key] = createRelationshipFor(rel, modelData.store, modelData, key); + } + } + + return relationship; + } +} diff --git a/addon/-record-data-rfc-private/system/relationships/state/has-many.js b/addon/-record-data-rfc-private/system/relationships/state/has-many.js new file mode 100755 index 00000000000..bf3514fbabb --- /dev/null +++ b/addon/-record-data-rfc-private/system/relationships/state/has-many.js @@ -0,0 +1,257 @@ +import { assertPolymorphicType } from 'ember-data/-debug'; +import Relationship from './relationship'; +import OrderedSet from '../../ordered-set'; +import { isNone } from '@ember/utils'; + +export default class ManyRelationship extends Relationship { + constructor(store, inverseKey, relationshipMeta, modelData, inverseIsAsync) { + super(store, inverseKey, relationshipMeta, modelData, inverseIsAsync); + this.canonicalState = []; + this.currentState = []; + this._willUpdateManyArray = false; + this._pendingManyArrayUpdates = null; + } + + removeInverseRelationships() { + super.removeInverseRelationships(); + + /* TODO Igor make sure this is still working + if (this._loadingPromise) { + this._loadingPromise.destroy(); + } + */ + } + + addCanonicalModelData(modelData, idx) { + if (this.canonicalMembers.has(modelData)) { + return; + } + if (idx !== undefined) { + this.canonicalState.splice(idx, 0, modelData); + } else { + this.canonicalState.push(modelData); + } + super.addCanonicalModelData(modelData, idx); + } + + inverseDidDematerialize(inverseModelData) { + super.inverseDidDematerialize(inverseModelData); + if (this.isAsync) { + this.notifyManyArrayIsStale(); + } + } + + notifyManyArrayIsStale() { + let storeWrapper = this.modelData.storeWrapper; + let modelData = this.modelData; + storeWrapper.notifyPropertyChange(modelData.modelName, modelData.id, modelData.clientId, this.key); + } + + addModelData(modelData, idx) { + if (this.members.has(modelData)) { + return; + } + + assertPolymorphicType(this.modelData, this.relationshipMeta, modelData, this.store); + super.addModelData(modelData, idx); + // make lazy later + if (idx === undefined) { + idx = this.currentState.length; + } + this.currentState.splice(idx, 0, modelData); + // TODO Igor consider making direct to remove the indirection + // We are not lazily accessing the manyArray here because the change is coming from app side + // this.manyArray.flushCanonical(this.currentState); + this.notifyHasManyChanged(); + } + + removeCanonicalModelDataFromOwn(modelData, idx) { + let i = idx; + if (!this.canonicalMembers.has(modelData)) { + return; + } + if (i === undefined) { + i = this.canonicalState.indexOf(modelData); + } + if (i > -1) { + this.canonicalState.splice(i, 1); + } + super.removeCanonicalModelDataFromOwn(modelData, idx); + //TODO(Igor) Figure out what to do here + } + + removeAllCanonicalModelDatasFromOwn() { + super.removeAllCanonicalModelDatasFromOwn(); + this.canonicalMembers.clear(); + this.canonicalState.splice(0, this.canonicalState.length); + super.removeAllCanonicalModelDatasFromOwn(); + } + + //TODO(Igor) DO WE NEED THIS? + removeCompletelyFromOwn(modelData) { + super.removeCompletelyFromOwn(modelData); + + // TODO SkEPTICAL + const canonicalIndex = this.canonicalState.indexOf(modelData); + + if (canonicalIndex !== -1) { + this.canonicalState.splice(canonicalIndex, 1); + } + + this.removeModelDataFromOwn(modelData); + } + + flushCanonical() { + let toSet = this.canonicalState; + + //a hack for not removing new records + //TODO remove once we have proper diffing + let newModelDatas = this.currentState.filter( + // only add new internalModels which are not yet in the canonical state of this + // relationship (a new internalModel can be in the canonical state if it has + // been 'acknowleged' to be in the relationship via a store.push) + + //TODO Igor deal with this + (modelData) => modelData.isNew() && toSet.indexOf(modelData) === -1 + ); + toSet = toSet.concat(newModelDatas); + + /* + if (this._manyArray) { + this._manyArray.flushCanonical(toSet); + } + */ + this.currentState = toSet; + super.flushCanonical(); + // Once we clean up all the flushing, we will be left with at least the notifying part + this.notifyHasManyChanged(); + } + + //TODO(Igor) idx not used currently, fix + removeModelDataFromOwn(modelData, idx) { + super.removeModelDataFromOwn(modelData, idx); + let index = idx || this.currentState.indexOf(modelData); + + //TODO IGOR DAVID INVESTIGATE + if (index === -1) { + return; + } + this.currentState.splice(index, 1); + // TODO Igor consider making direct to remove the indirection + // We are not lazily accessing the manyArray here because the change is coming from app side + this.notifyHasManyChanged(); + // this.manyArray.flushCanonical(this.currentState); + } + + notifyRecordRelationshipAdded() { + this.notifyHasManyChanged(); + } + + computeChanges(modelDatas = []) { + let members = this.canonicalMembers; + let modelDatasToRemove = []; + let modelDatasSet = setForArray(modelDatas); + + members.forEach(member => { + if (modelDatasSet.has(member)) { return; } + + modelDatasToRemove.push(member); + }); + + this.removeCanonicalModelDatas(modelDatasToRemove); + + for (let i = 0, l = modelDatas.length; i < l; i++) { + let modelData = modelDatas[i]; + this.removeCanonicalModelData(modelData); + this.addCanonicalModelData(modelData, i); + } + } + + setInitialModelDatas(modelDatas) { + if (Array.isArray(modelDatas) === false || modelDatas.length === 0) { + return; + } + + for (let i = 0; i< modelDatas.length; i++) { + let modelData = modelDatas[i]; + if (this.canonicalMembers.has(modelData)) { + continue; + } + + this.canonicalMembers.add(modelData); + this.members.add(modelData); + this.setupInverseRelationship(modelData); + } + + this.canonicalState = this.canonicalMembers.toArray(); + } + + notifyHasManyChanged() { + let modelData = this.modelData; + let storeWrapper = this.modelData.storeWrapper; + storeWrapper.notifyHasManyChange(modelData.modelName, modelData.id, modelData.clientId, this.key); + } + + getData() { + let payload = {}; + if (this.hasAnyRelationshipData) { + payload.data = this.currentState.map((modelData) => modelData.getResourceIdentifier()); + } + if (this.link) { + payload.links = { + related: this.link + } + } + if (this.meta) { + payload.meta = this.meta; + } + + // TODO @runspired: the @igor refactor is too limiting for relationship state + // we should reconsider where we fetch from. + payload._relationship = this; + + return payload; + } + + updateData(data, initial) { + let modelDatas; + if (isNone(data)) { + modelDatas = undefined; + } else { + modelDatas = new Array(data.length); + for (let i = 0; i < data.length; i++) { + modelDatas[i] = this.modelData.storeWrapper.modelDataFor(data[i].type, data[i].id); + } + } + if (initial) { + this.setInitialModelDatas(modelDatas); + } else { + this.updateModelDatasFromAdapter(modelDatas); + } + } + + localStateIsEmpty() { + let modelDatas = this.canonicalState; + let isLoaded = false; + + if (modelDatas.length) { + isLoaded = modelDatas.reduce((hasNoEmptyModel, i) => { + return hasNoEmptyModel && !i.isEmpty(); + }, true); + } + + return !isLoaded; + } +} + +function setForArray(array) { + var set = new OrderedSet(); + + if (array) { + for (var i=0, l=array.length; i initial setup + => a previously triggered request has resolved + => we get relationship data via push + + true when + => relationship.reload() has been called + => we get a new link for the relationship + */ + this.relationshipIsStale = false; + + /* + This flag indicates whether we should + **partially** re-fetch the relationship the + next time it is accessed. + + false when + => initial setup + => a previously triggered request has resolved + + true when + => an inverse has been unloaded + */ + this.hasDematerializedInverse = false; + + /* + This flag indicates whether we should consider the content + of this relationship "known". + + If we have no relationship knowledge, and the relationship + is `async`, we will attempt to fetch the relationship on + access if it is also stale. + + Snapshot uses this to tell the difference between unknown + (`undefined`) or empty (`null`). The reason for this is that + we wouldn't want to serialize unknown relationships as `null` + as that might overwrite remote state. + + All relationships for a newly created (`store.createRecord()`) are + considered known (`hasAnyRelationshipData === true`). + + true when + => we receive a push with either new data or explicit empty (`[]` or `null`) + => the relationship is a belongsTo and we have received data from + the other side. + + false when + => we have received no signal about what data belongs in this relationship + => the relationship is a hasMany and we have only received data from + the other side. + */ + this.hasAnyRelationshipData = false; + + /* + Flag that indicates whether an empty relationship is explicitly empty + (signaled by push giving us an empty array or null relationship) + e.g. an API response has told us that this relationship is empty. + + Thus far, it does not appear that we actually need this flag; however, + @runspired has found it invaluable when debugging relationship tests + to determine whether (and why if so) we are in an incorrect state. + + true when + => we receive a push with explicit empty (`[]` or `null`) + => we have received no signal about what data belongs in this relationship + => on initial create (as no signal is known yet) + + false at all other times + */ + this.relationshipIsEmpty = true; + + /* + Flag def here for reference, defined as getter below + + true when + => hasAnyRelationshipData is true + AND + => members (NOT canonicalMembers) @each !isEmpty + + TODO, consider changing the conditional here from !isEmpty to !hiddenFromRecordArrays + */ + // this.hasRelatedResources = false; + + // TODO do we want this anymore? Seems somewhat useful + // especially if we rename to `hasUpdatedLink` + // which would tell us slightly more about why the + // relationship is stale + // this.updatedLink = false; + } + + get hasRelatedResources() { + return !this.localStateIsEmpty(); + } + + _inverseIsAsync() { + return this.inverseIsAsync; + } + + _inverseIsSync() { + return this.inverseKey && !this.inverseIsAsync; + } + + get _inverseMeta() { + if (this.__inverseMeta === undefined) { + let inverseMeta = null; + + if (this.inverseKey) { + let inverseModelClass = this.store.modelFor(this.relationshipMeta.type); + let inverseRelationships = get(inverseModelClass, 'relationshipsByName'); + inverseMeta = inverseRelationships.get(this.inverseKey); + } + + this.__inverseMeta = inverseMeta; + } + return this.__inverseMeta; + } + + get parentType() { + return this.internalModel.modelName; + } + + modelDataDidDematerialize() { + if (!this.inverseKey) { return; } + // we actually want a union of members and canonicalMembers + // they should be disjoint but currently are not due to a bug + this.forAllMembers((inverseModelData) => { + let relationship = inverseModelData._relationships.get(this.inverseKey); + relationship.inverseDidDematerialize(this.modelData); + }); + } + + forAllMembers(callback) { + let seen = Object.create(null); + + for (let i = 0; i < this.members.list.length; i++) { + const inverseInternalModel = this.members.list[i]; + const id = guidFor(inverseInternalModel); + if (!seen[id]) { + seen[id] = true; + callback(inverseInternalModel); + } + } + + for (let i = 0; i < this.canonicalMembers.list.length; i++) { + const inverseInternalModel = this.canonicalMembers.list[i]; + const id = guidFor(inverseInternalModel); + if (!seen[id]) { + seen[id] = true; + callback(inverseInternalModel); + } + } + } + + inverseDidDematerialize(inverseModelData) { + if (!this.isAsync) { + // unloading inverse of a sync relationship is treated as a client-side + // delete, so actually remove the models don't merely invalidate the cp + // cache. + this.removeModelDataFromOwn(inverseModelData); + this.removeCanonicalModelDataFromOwn(inverseModelData); + this.setRelationshipIsEmpty(true); + } else { + this.setHasDematerializedInverse(true); + } + } + + updateMeta(meta) { + heimdall.increment(updateMeta); + this.meta = meta; + } + + clear() { + heimdall.increment(clear); + + let members = this.members.list; + while (members.length > 0) { + let member = members[0]; + this.removeModelData(member); + } + + let canonicalMembers = this.canonicalMembers.list; + while (canonicalMembers.length > 0) { + let member = canonicalMembers[0]; + this.removeCanonicalModelData(member); + } + } + + removeAllModelDatasFromOwn() { + this.members.clear(); + } + + removeAllCanonicalModelDatasFromOwn() { + this.canonicalMembers.clear(); + this.flushCanonicalLater(); + } + + removeModelDatas(modelDatas) { + heimdall.increment(removeModelDatas); + modelDatas.forEach((modelData) => this.removeModelData(modelData)); + } + + addModelDatas(modelDatas, idx) { + heimdall.increment(addModelDatas); + modelDatas.forEach(modelData => { + this.addModelData(modelData, idx); + if (idx !== undefined) { + idx++; + } + }); + } + + addCanonicalModelDatas(modelDatas, idx) { + heimdall.increment(addCanonicalModelDatas); + for (let i=0; i { + const id = guidFor(inverseModelData); + + if (seen[id] === undefined) { + const relationship = inverseModelData._relationships.get(this.inverseKey); + relationship.removeCompletelyFromOwn(modelData); + seen[id] = true; + } + }; + + this.members.forEach(unload); + this.canonicalMembers.forEach(unload); + + if (!this.isAsync) { + this.clear(); + } + } + + /* + Removes the given ModelData from BOTH canonical AND current state. + + This method is useful when either a deletion or a rollback on a new record + needs to entirely purge itself from an inverse relationship. + */ + removeCompletelyFromOwn(modelData) { + this.canonicalMembers.delete(modelData); + this.members.delete(modelData); + } + + flushCanonical() { + heimdall.increment(flushCanonical); + let list = this.members.list; + this.willSync = false; + //a hack for not removing new ModelDatas + //TODO remove once we have proper diffing + let newModelDatas = []; + for (let i = 0; i < list.length; i++) { + // TODO Igor deal with this + if (list[i].isNew()) { + newModelDatas.push(list[i]); + } + } + + //TODO(Igor) make this less abysmally slow + this.members = this.canonicalMembers.copy(); + for (let i = 0; i < newModelDatas.length; i++) { + this.members.add(newModelDatas[i]); + } + } + + flushCanonicalLater() { + heimdall.increment(flushCanonicalLater); + if (this.willSync) { + return; + } + this.willSync = true; + // Reaching back into the store to use ED's runloop + this.store._updateRelationshipState(this); + } + + updateLink(link, initial) { + heimdall.increment(updateLink); + warn(`You pushed a record of type '${this.modelData.modelName}' with a relationship '${this.key}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, this.isAsync || this.hasAnyRelationshipData , { + id: 'ds.store.push-link-for-sync-relationship' + }); + assert(`You have pushed a record of type '${this.modelData.modelName}' with '${this.key}' as a link, but the value of that link is not a string.`, typeof link === 'string' || link === null); + + this.link = link; + this.setRelationshipIsStale(true); + + if (!initial) { + let modelData = this.modelData; + let storeWrapper = this.modelData.storeWrapper; + storeWrapper.notifyPropertyChange(modelData.modelName, modelData.id, modelData.clientId, this.key); + } + } + + updateModelDatasFromAdapter(modelDatas) { + heimdall.increment(updateModelDatasFromAdapter); + this.setHasAnyRelationshipData(true); + //TODO(Igor) move this to a proper place + //TODO Once we have adapter support, we need to handle updated and canonical changes + this.computeChanges(modelDatas); + } + + notifyRecordRelationshipAdded() { } + + setHasAnyRelationshipData(value) { + this.hasAnyRelationshipData = value; + } + + setHasDematerializedInverse(value) { + this.hasDematerializedInverse = value; + } + + setRelationshipIsStale(value) { + this.relationshipIsStale = value; + } + + setRelationshipIsEmpty(value) { + this.relationshipIsEmpty = value; + } + + /* + `push` for a relationship allows the store to push a JSON API Relationship + Object onto the relationship. The relationship will then extract and set the + meta, data and links of that relationship. + + `push` use `updateMeta`, `updateData` and `updateLink` to update the state + of the relationship. + */ + push(payload, initial) { + heimdall.increment(push); + + let hasRelationshipDataProperty = false; + let hasLink = false; + + if (payload.meta) { + this.updateMeta(payload.meta); + } + + if (payload.data !== undefined) { + hasRelationshipDataProperty = true; + this.updateData(payload.data, initial); + } + + if (payload.links && payload.links.related) { + let relatedLink = _normalizeLink(payload.links.related); + if (relatedLink && relatedLink.href && relatedLink.href !== this.link) { + hasLink = true; + this.updateLink(relatedLink.href, initial); + } + } + + /* + Data being pushed into the relationship might contain only data or links, + or a combination of both. + + IF contains only data + IF contains both links and data + relationshipIsEmpty -> true if is empty array (has-many) or is null (belongs-to) + hasAnyRelationshipData -> true + hasDematerializedInverse -> false + relationshipIsStale -> false + hasRelatedResources -> run-check-to-determine + + IF contains only links + relationshipIsStale -> true + */ + if (hasRelationshipDataProperty) { + let relationshipIsEmpty = payload.data === null || + (Array.isArray(payload.data) && payload.data.length === 0); + + this.setHasAnyRelationshipData(true); + this.setRelationshipIsStale(false); + this.setHasDematerializedInverse(false); + this.setRelationshipIsEmpty(relationshipIsEmpty); + } else if (hasLink) { + this.setRelationshipIsStale(true); + } + } + + localStateIsEmpty() {} + + updateData() {} + + destroy() {} +} diff --git a/addon/-record-data-rfc-private/system/snapshot-record-array.js b/addon/-record-data-rfc-private/system/snapshot-record-array.js new file mode 100644 index 00000000000..9afe2408670 --- /dev/null +++ b/addon/-record-data-rfc-private/system/snapshot-record-array.js @@ -0,0 +1,165 @@ +/** + @module ember-data +*/ + +/** + @class SnapshotRecordArray + @namespace DS + @private + @constructor + @param {Array} snapshots An array of snapshots + @param {Object} meta +*/ +export default class SnapshotRecordArray { + constructor(recordArray, meta, options = {}) { + /** + An array of snapshots + @private + @property _snapshots + @type {Array} + */ + this._snapshots = null; + + /** + An array of records + @private + @property _recordArray + @type {Array} + */ + this._recordArray = recordArray; + + /** + Number of records in the array + + Example + + ```app/adapters/post.js + import DS from 'ember-data' + + export default DS.JSONAPIAdapter.extend({ + shouldReloadAll(store, snapshotRecordArray) { + return !snapshotRecordArray.length; + }, + }); + ``` + + @property length + @type {Number} + */ + this.length = recordArray.get('length'); + + this._type = null; + + /** + Meta objects for the record array. + + Example + + ```app/adapters/post.js + import DS from 'ember-data' + + export default DS.JSONAPIAdapter.extend({ + shouldReloadAll(store, snapshotRecordArray) { + var lastRequestTime = snapshotRecordArray.meta.lastRequestTime; + var twentyMinutes = 20 * 60 * 1000; + return Date.now() > lastRequestTime + twentyMinutes; + }, + }); + ``` + + @property meta + @type {Object} + */ + this.meta = meta; + + /** + A hash of adapter options passed into the store method for this request. + + Example + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + findAll(store, type, sinceToken, snapshotRecordArray) { + if (snapshotRecordArray.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + + @property adapterOptions + @type {Object} + */ + this.adapterOptions = options.adapterOptions; + + /** + The relationships to include for this request. + + Example + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + findAll(store, type, snapshotRecordArray) { + var url = `/${type.modelName}?include=${encodeURIComponent(snapshotRecordArray.include)}`; + + return fetch(url).then((response) => response.json()) + } + }); + + @property include + @type {String|Array} + */ + this.include = options.include; + } + + /** + The type of the underlying records for the snapshots in the array, as a DS.Model + @property type + @type {DS.Model} + */ + get type() { + return this._type || (this._type = this._recordArray.get('type')); + } + + /** + Get snapshots of the underlying record array + + Example + + ```app/adapters/post.js + import DS from 'ember-data' + + export default DS.JSONAPIAdapter.extend({ + shouldReloadAll(store, snapshotArray) { + var snapshots = snapshotArray.snapshots(); + + return snapshots.any(function(ticketSnapshot) { + var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt'), 'minutes'); + if (timeDiff > 20) { + return true; + } else { + return false; + } + }); + } + }); + ``` + + @method snapshots + @return {Array} Array of snapshots + */ + snapshots() { + if (this._snapshots !== null) { + return this._snapshots; + } + + this._snapshots = this._recordArray._takeSnapshot(); + + return this._snapshots; + } +} diff --git a/addon/-record-data-rfc-private/system/snapshot.js b/addon/-record-data-rfc-private/system/snapshot.js new file mode 100644 index 00000000000..daeb46e2d3e --- /dev/null +++ b/addon/-record-data-rfc-private/system/snapshot.js @@ -0,0 +1,406 @@ +/** + @module ember-data +*/ +import { inspect } from '@ember/debug'; +import EmberError from '@ember/error'; +import { get } from '@ember/object'; +import { assign } from '@ember/polyfills'; + +/** + @class Snapshot + @namespace DS + @private + @constructor + @param {DS.Model} internalModel The model to create a snapshot from +*/ +export default class Snapshot { + constructor(internalModel, options = {}) { + this.__attributes = null; + this._belongsToRelationships = Object.create(null); + this._belongsToIds = Object.create(null); + this._hasManyRelationships = Object.create(null); + this._hasManyIds = Object.create(null); + this._internalModel = internalModel; + + /* + If the internalModel does not yet have a record, then we are + likely a snapshot being provided to a find request, so we + populate __attributes lazily. Else, to preserve the "moment + in time" in which a snapshot is created, we greedily grab + the values. + */ + if (internalModel.hasRecord) { + this._attributes; + } + + /**O + The id of the snapshot's underlying record + + Example + + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postSnapshot.id; // => '1' + ``` + + @property id + @type {String} + */ + this.id = internalModel.id; + + /** + A hash of adapter options + @property adapterOptions + @type {Object} + */ + this.adapterOptions = options.adapterOptions; + this.include = options.include; + + /** + The name of the type of the underlying record for this snapshot, as a string. + + @property modelName + @type {String} + */ + this.modelName = internalModel.modelName; + + this._changedAttributes = internalModel.changedAttributes(); + } + + /** + The underlying record for this snapshot. Can be used to access methods and + properties defined on the record. + + Example + + ```javascript + let json = snapshot.record.toJSON(); + ``` + + @property record + @type {DS.Model} + */ + get record() { + return this._internalModel.getRecord(); + } + + get _attributes() { + let attributes = this.__attributes; + + if (attributes === null) { + let record = this.record; + attributes = this.__attributes = Object.create(null); + + record.eachAttribute((keyName) => attributes[keyName] = get(record, keyName)); + } + + return attributes; + } + + /** + The type of the underlying record for this snapshot, as a DS.Model. + + @property type + @type {DS.Model} + */ + get type() { + // TODO @runspired we should deprecate this in favor of modelClass but only once + // we've cleaned up the internals enough that a public change to follow suite is + // uncontroversial. + return this._internalModel.modelClass; + } + + /** + Returns the value of an attribute. + + Example + + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postSnapshot.attr('author'); // => 'Tomster' + postSnapshot.attr('title'); // => 'Ember.js rocks' + ``` + + Note: Values are loaded eagerly and cached when the snapshot is created. + + @method attr + @param {String} keyName + @return {Object} The attribute value or undefined + */ + attr(keyName) { + if (keyName in this._attributes) { + return this._attributes[keyName]; + } + throw new EmberError("Model '" + inspect(this.record) + "' has no attribute named '" + keyName + "' defined."); + } + + /** + Returns all attributes and their corresponding values. + + Example + + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postSnapshot.attributes(); // => { author: 'Tomster', title: 'Ember.js rocks' } + ``` + + @method attributes + @return {Object} All attributes of the current snapshot + */ + attributes() { + return assign({}, this._attributes); + } + + /** + Returns all changed attributes and their old and new values. + + Example + + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postModel.set('title', 'Ember.js rocks!'); + postSnapshot.changedAttributes(); // => { title: ['Ember.js rocks', 'Ember.js rocks!'] } + ``` + + @method changedAttributes + @return {Object} All changed attributes of the current snapshot + */ + changedAttributes() { + let changedAttributes = Object.create(null); + let changedAttributeKeys = Object.keys(this._changedAttributes); + + for (let i=0, length = changedAttributeKeys.length; i < length; i++) { + let key = changedAttributeKeys[i]; + changedAttributes[key] = this._changedAttributes[key].slice(); + } + + return changedAttributes; + } + + /** + Returns the current value of a belongsTo relationship. + + `belongsTo` takes an optional hash of options as a second parameter, + currently supported options are: + + - `id`: set to `true` if you only want the ID of the related record to be + returned. + + Example + + ```javascript + // store.push('post', { id: 1, title: 'Hello World' }); + // store.createRecord('comment', { body: 'Lorem ipsum', post: post }); + commentSnapshot.belongsTo('post'); // => DS.Snapshot + commentSnapshot.belongsTo('post', { id: true }); // => '1' + + // store.push('comment', { id: 1, body: 'Lorem ipsum' }); + commentSnapshot.belongsTo('post'); // => undefined + ``` + + Calling `belongsTo` will return a new Snapshot as long as there's any known + data for the relationship available, such as an ID. If the relationship is + known but unset, `belongsTo` will return `null`. If the contents of the + relationship is unknown `belongsTo` will return `undefined`. + + Note: Relationships are loaded lazily and cached upon first access. + + @method belongsTo + @param {String} keyName + @param {Object} [options] + @return {(DS.Snapshot|String|null|undefined)} A snapshot or ID of a known + relationship or null if the relationship is known but unset. undefined + will be returned if the contents of the relationship is unknown. + */ + belongsTo(keyName, options) { + let id = options && options.id; + let relationship; + let inverseInternalModel; + let result; + let store = this._internalModel.store; + + if (id && keyName in this._belongsToIds) { + return this._belongsToIds[keyName]; + } + + if (!id && keyName in this._belongsToRelationships) { + return this._belongsToRelationships[keyName]; + } + + let relationshipMeta = store._relationshipMetaFor(this.modelName, null, keyName); + if (!(relationshipMeta && relationshipMeta.kind === 'belongsTo')) { + throw new EmberError("Model '" + inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined."); + } + + relationship = this._internalModel._modelData._relationships.get(keyName); + + let value = relationship.getData(); + let data = value && value.data; + + inverseInternalModel = data && store._internalModelForResource(data); + + if (value && value.data !== undefined) { + if (inverseInternalModel && !inverseInternalModel.isDeleted()) { + if (id) { + result = get(inverseInternalModel, 'id'); + } else { + result = inverseInternalModel.createSnapshot(); + } + } else { + result = null; + } + } + + if (id) { + this._belongsToIds[keyName] = result; + } else { + this._belongsToRelationships[keyName] = result; + } + + return result; + } + + /** + Returns the current value of a hasMany relationship. + + `hasMany` takes an optional hash of options as a second parameter, + currently supported options are: + + - `ids`: set to `true` if you only want the IDs of the related records to be + returned. + + Example + + ```javascript + // store.push('post', { id: 1, title: 'Hello World', comments: [2, 3] }); + postSnapshot.hasMany('comments'); // => [DS.Snapshot, DS.Snapshot] + postSnapshot.hasMany('comments', { ids: true }); // => ['2', '3'] + + // store.push('post', { id: 1, title: 'Hello World' }); + postSnapshot.hasMany('comments'); // => undefined + ``` + + Note: Relationships are loaded lazily and cached upon first access. + + @method hasMany + @param {String} keyName + @param {Object} [options] + @return {(Array|undefined)} An array of snapshots or IDs of a known + relationship or an empty array if the relationship is known but unset. + undefined will be returned if the contents of the relationship is unknown. + */ + hasMany(keyName, options) { + let ids = options && options.ids; + let relationship; + let results; + + if (ids && keyName in this._hasManyIds) { + return this._hasManyIds[keyName]; + } + + if (!ids && keyName in this._hasManyRelationships) { + return this._hasManyRelationships[keyName]; + } + + let store = this._internalModel.store; + let relationshipMeta = store._relationshipMetaFor(this.modelName, null, keyName); + if (!(relationshipMeta && relationshipMeta.kind === 'hasMany')) { + throw new EmberError("Model '" + inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined."); + } + + relationship = this._internalModel._modelData._relationships.get(keyName); + + let value = relationship.getData(); + + if (value.data) { + results = []; + value.data.forEach((member) => { + let internalModel = store._internalModelForResource(member); + if (!internalModel.isDeleted()) { + if (ids) { + results.push(member.id); + } else { + results.push(internalModel.createSnapshot()); + } + } + }); + } + + if (ids) { + this._hasManyIds[keyName] = results; + } else { + this._hasManyRelationships[keyName] = results; + } + + return results; + } + + /** + Iterates through all the attributes of the model, calling the passed + function on each attribute. + + Example + + ```javascript + snapshot.eachAttribute(function(name, meta) { + // ... + }); + ``` + + @method eachAttribute + @param {Function} callback the callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + */ + eachAttribute(callback, binding) { + this.record.eachAttribute(callback, binding); + } + + /** + Iterates through all the relationships of the model, calling the passed + function on each relationship. + + Example + + ```javascript + snapshot.eachRelationship(function(name, relationship) { + // ... + }); + ``` + + @method eachRelationship + @param {Function} callback the callback to execute + @param {Object} [binding] the value to which the callback's `this` should be bound + */ + eachRelationship(callback, binding) { + this.record.eachRelationship(callback, binding); + } + + /** + Serializes the snapshot using the serializer for the model. + + Example + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + createRecord(store, type, snapshot) { + var data = snapshot.serialize({ includeId: true }); + var url = `/${type.modelName}`; + + return fetch(url, { + method: 'POST', + body: data, + }).then((response) => response.json()) + } + }); + ``` + + @method serialize + @param {Object} options + @return {Object} an object whose values are primitive JSON values only + */ + serialize(options) { + return this.record.store.serializerFor(this.modelName).serialize(this, options); + } +} diff --git a/addon/-record-data-rfc-private/system/store.js b/addon/-record-data-rfc-private/system/store.js new file mode 100644 index 00000000000..98d66becabf --- /dev/null +++ b/addon/-record-data-rfc-private/system/store.js @@ -0,0 +1,3043 @@ +/** + @module ember-data +*/ +import { A } from '@ember/array'; +import EmberError from '@ember/error'; +import MapWithDefault from './map-with-default'; +import { run as emberRun } from '@ember/runloop'; +import { set, get, computed } from '@ember/object'; +import { assign } from '@ember/polyfills'; +import { default as RSVP, Promise } from 'rsvp'; +import Service from '@ember/service'; +import { typeOf, isPresent, isNone } from '@ember/utils'; + +import Ember from 'ember'; +import { InvalidError } from '../adapters/errors'; +import { instrument } from 'ember-data/-debug'; +import { assert, deprecate, warn, inspect } from '@ember/debug'; +import { DEBUG } from '@glimmer/env'; +import Model from './model/model'; +import normalizeModelName from "./normalize-model-name"; +import IdentityMap from './identity-map'; +import ModelDataWrapper from './store/model-data-wrapper'; + +import { + promiseArray, + promiseObject +} from "./promise-proxies"; + +import { + _bind, + _guard, + _objectIsAlive, + guardDestroyedStore, + incrementRequestCount +} from "./store/common"; + +import { normalizeResponseHelper } from "./store/serializer-response"; +import { serializerForAdapter } from "./store/serializers"; + +import { + _find, + _findMany, + _findHasMany, + _findBelongsTo, + _findAll, + _query, + _queryRecord +} from "./store/finders"; + +import { getOwner } from '../utils'; +import coerceId from "./coerce-id"; +import RecordArrayManager from "./record-array-manager"; +import InternalModel from "./model/internal-model"; +import ModelData from "./model/model-data"; +import edBackburner from './backburner'; + +const badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; + +const { ENV } = Ember; +let globalClientIdCounter = 1; + +//Get the materialized model from the internalModel/promise that returns +//an internal model and return it in a promiseObject. Useful for returning +//from find methods +function promiseRecord(internalModelPromise, label) { + let toReturn = internalModelPromise.then(internalModel => internalModel.getRecord()); + + return promiseObject(toReturn, label); +} + +let Store; + +// Implementors Note: +// +// The variables in this file are consistently named according to the following +// scheme: +// +// * +id+ means an identifier managed by an external source, provided inside +// the data provided by that source. These are always coerced to be strings +// before being used internally. +// * +clientId+ means a transient numerical identifier generated at runtime by +// the data store. It is important primarily because newly created objects may +// not yet have an externally generated id. +// * +internalModel+ means a record internalModel object, which holds metadata about a +// record, even if it has not yet been fully materialized. +// * +type+ means a DS.Model. + +const { + _generateId, + _internalModelForId, + _load, + _pushInternalModel, + adapterFor, + _buildInternalModel, + _didUpdateAll, + normalize, + peekAll, + peekRecord, + serializerFor, + _internalModelsFor +} = heimdall.registerMonitor('store', + '_generateId', + '_internalModelForId', + '_load', + '_pushInternalModel', + 'adapterFor', + '_buildInternalModel', + '_didUpdateAll', + 'normalize', + 'peekAll', + 'peekRecord', + 'serializerFor', + '_internalModelsFor' +); + +/** + The store contains all of the data for records loaded from the server. + It is also responsible for creating instances of `DS.Model` that wrap + the individual data for a record, so that they can be bound to in your + Handlebars templates. + + Define your application's store like this: + + ```app/services/store.js + import DS from 'ember-data'; + + export default DS.Store.extend({ + }); + ``` + + Most Ember.js applications will only have a single `DS.Store` that is + automatically created by their `Ember.Application`. + + You can retrieve models from the store in several ways. To retrieve a record + for a specific id, use `DS.Store`'s `findRecord()` method: + + ```javascript + store.findRecord('person', 123).then(function (person) { + }); + ``` + + By default, the store will talk to your backend using a standard + REST mechanism. You can customize how the store talks to your + backend by specifying a custom adapter: + + ```app/adapters/application.js + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + }); + ``` + + You can learn more about writing a custom adapter by reading the `DS.Adapter` + documentation. + + ### Store createRecord() vs. push() vs. pushPayload() + + The store provides multiple ways to create new record objects. They have + some subtle differences in their use which are detailed below: + + [createRecord](#method_createRecord) is used for creating new + records on the client side. This will return a new record in the + `created.uncommitted` state. In order to persist this record to the + backend you will need to call `record.save()`. + + [push](#method_push) is used to notify Ember Data's store of new or + updated records that exist in the backend. This will return a record + in the `loaded.saved` state. The primary use-case for `store#push` is + to notify Ember Data about record updates (full or partial) that happen + outside of the normal adapter methods (for example + [SSE](http://dev.w3.org/html5/eventsource/) or [Web + Sockets](http://www.w3.org/TR/2009/WD-websockets-20091222/)). + + [pushPayload](#method_pushPayload) is a convenience wrapper for + `store#push` that will deserialize payloads if the + Serializer implements a `pushPayload` method. + + Note: When creating a new record using any of the above methods + Ember Data will update `DS.RecordArray`s such as those returned by + `store#peekAll()` or `store#findAll()`. This means any + data bindings or computed properties that depend on the RecordArray + will automatically be synced to include the new or updated record + values. + + @class Store + @namespace DS + @extends Ember.Service +*/ +Store = Service.extend({ + + /** + @method init + @private + */ + init() { + this._super(...arguments); + this._backburner = edBackburner; + // internal bookkeeping; not observable + this.recordArrayManager = new RecordArrayManager({ store: this }); + this._identityMap = new IdentityMap(); + // To keep track of clientIds for newly created records + this._newlyCreated = new IdentityMap(); + this._pendingSave = []; + this._modelFactoryCache = Object.create(null); + + /* + Ember Data uses several specialized micro-queues for organizing + and coalescing similar async work. + + These queues are currently controlled by a flush scheduled into + ember-data's custom backburner instance. + */ + // used for coalescing record save requests + this._pendingSave = []; + // used for coalescing relationship updates + this._updatedRelationships = []; + // used for coalescing relationship setup needs + this._pushedInternalModels = []; + // used for coalescing internal model updates + this._updatedInternalModels = []; + + + // used to keep track of all the find requests that need to be coalesced + this._pendingFetch = new MapWithDefault({ defaultValue() { return []; } }); + + this._adapterCache = Object.create(null); + this._serializerCache = Object.create(null); + + this.modelDataWrapper = new ModelDataWrapper(this); + }, + + /** + The default adapter to use to communicate to a backend server or + other persistence layer. This will be overridden by an application + adapter if present. + + If you want to specify `app/adapters/custom.js` as a string, do: + + ```js + import DS from 'ember-data'; + + export default DS.Store.extend({ + adapter: 'custom', + }); + ``` + + @property adapter + @default '-json-api' + @type {String} + */ + adapter: '-json-api', + + /** + This property returns the adapter, after resolving a possible + string key. + + If the supplied `adapter` was a class, or a String property + path resolved to a class, this property will instantiate the + class. + + This property is cacheable, so the same instance of a specified + adapter class should be used for the lifetime of the store. + + @property defaultAdapter + @private + @return DS.Adapter + */ + defaultAdapter: computed('adapter', function() { + let adapter = get(this, 'adapter'); + + assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name', typeof adapter === 'string'); + + return this.adapterFor(adapter); + }), + + // ..................... + // . CREATE NEW RECORD . + // ..................... + + /** + Create a new record in the current store. The properties passed + to this method are set on the newly created record. + + To create a new instance of a `Post`: + + ```js + store.createRecord('post', { + title: 'Rails is omakase' + }); + ``` + + To create a new instance of a `Post` that has a relationship with a `User` record: + + ```js + let user = this.store.peekRecord('user', 1); + store.createRecord('post', { + title: 'Rails is omakase', + user: user + }); + ``` + + @method createRecord + @param {String} modelName + @param {Object} inputProperties a hash of properties to set on the + newly created record. + @return {DS.Model} record + */ + createRecord(modelName, inputProperties) { + assert(`You need to pass a model name to the store's createRecord method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + // This is wrapped in a `run.join` so that in test environments users do not need to manually wrap + // calls to `createRecord`. The run loop usage here is because we batch the joining and updating + // of record-arrays via ember's run loop, not our own. + // + // to remove this, we would need to move to a new `async` API. + return emberRun.join(() => { + return this._backburner.join(() => { + let normalizedModelName = normalizeModelName(modelName); + let properties = assign({}, inputProperties); + + // If the passed properties do not include a primary key, + // give the adapter an opportunity to generate one. Typically, + // client-side ID generators will use something like uuid.js + // to avoid conflicts. + + if (isNone(properties.id)) { + properties.id = this._generateId(normalizedModelName, properties); + } + + // Coerce ID to a string + properties.id = coerceId(properties.id); + + let internalModel = this._buildInternalModel(normalizedModelName, properties.id); + internalModel.loadedData(); + // TODO this exists just to proxy `isNew` to ModelData which is weird + internalModel.didCreateRecord(); + + return internalModel.getRecord(properties); + }); + }); + }, + + /** + If possible, this method asks the adapter to generate an ID for + a newly created record. + + @method _generateId + @private + @param {String} modelName + @param {Object} properties from the new record + @return {String} if the adapter can generate one, an ID + */ + _generateId(modelName, properties) { + heimdall.increment(_generateId); + let adapter = this.adapterFor(modelName); + + if (adapter && adapter.generateIdForRecord) { + return adapter.generateIdForRecord(this, modelName, properties); + } + + return null; + }, + + // ................. + // . DELETE RECORD . + // ................. + + /** + For symmetry, a record can be deleted via the store. + + Example + + ```javascript + let post = store.createRecord('post', { + title: 'Rails is omakase' + }); + + store.deleteRecord(post); + ``` + + @method deleteRecord + @param {DS.Model} record + */ + deleteRecord(record) { + record.deleteRecord(); + }, + + /** + For symmetry, a record can be unloaded via the store. + This will cause the record to be destroyed and freed up for garbage collection. + + Example + + ```javascript + store.findRecord('post', 1).then(function(post) { + store.unloadRecord(post); + }); + ``` + + @method unloadRecord + @param {DS.Model} record + */ + unloadRecord(record) { + record.unloadRecord(); + }, + + // ................ + // . FIND RECORDS . + // ................ + + /** + @method find + @param {String} modelName + @param {String|Integer} id + @param {Object} options + @return {Promise} promise + @private + */ + find(modelName, id, options) { + // The default `model` hook in Route calls `find(modelName, id)`, + // that's why we have to keep this method around even though `findRecord` is + // the public way to get a record by modelName and id. + assert(`Using store.find(type) has been removed. Use store.findAll(modelName) to retrieve all records for a given type.`, arguments.length !== 1); + assert(`Calling store.find(modelName, id, { preload: preload }) is no longer supported. Use store.findRecord(modelName, id, { preload: preload }) instead.`, !options); + assert(`You need to pass the model name and id to the store's find method`, arguments.length === 2); + assert(`You cannot pass '${id}' as id to the store's find method`, typeof id === 'string' || typeof id === 'number'); + assert(`Calling store.find() with a query object is no longer supported. Use store.query() instead.`, typeof id !== 'object'); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + return this.findRecord(modelName, id); + }, + + /** + This method returns a record for a given type and id combination. + + The `findRecord` method will always resolve its promise with the same + object for a given type and `id`. + + The `findRecord` method will always return a **promise** that will be + resolved with the record. + + Example + + ```app/routes/post.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + model(params) { + return this.store.findRecord('post', params.post_id); + } + }); + ``` + + If the record is not yet available, the store will ask the adapter's `find` + method to find the necessary data. If the record is already present in the + store, it depends on the reload behavior _when_ the returned promise + resolves. + + ### Preloading + + You can optionally `preload` specific attributes and relationships that you know of + by passing them via the passed `options`. + + For example, if your Ember route looks like `/posts/1/comments/2` and your API route + for the comment also looks like `/posts/1/comments/2` if you want to fetch the comment + without fetching the post you can pass in the post to the `findRecord` call: + + ```javascript + store.findRecord('comment', 2, { preload: { post: 1 } }); + ``` + + If you have access to the post model you can also pass the model itself: + + ```javascript + store.findRecord('post', 1).then(function (myPostModel) { + store.findRecord('comment', 2, { post: myPostModel }); + }); + ``` + + ### Reloading + + The reload behavior is configured either via the passed `options` hash or + the result of the adapter's `shouldReloadRecord`. + + If `{ reload: true }` is passed or `adapter.shouldReloadRecord` evaluates + to `true`, then the returned promise resolves once the adapter returns + data, regardless if the requested record is already in the store: + + ```js + store.push({ + data: { + id: 1, + type: 'post', + revision: 1 + } + }); + + // adapter#findRecord resolves with + // [ + // { + // id: 1, + // type: 'post', + // revision: 2 + // } + // ] + store.findRecord('post', 1, { reload: true }).then(function(post) { + post.get('revision'); // 2 + }); + ``` + + If no reload is indicated via the abovementioned ways, then the promise + immediately resolves with the cached version in the store. + + ### Background Reloading + + Optionally, if `adapter.shouldBackgroundReloadRecord` evaluates to `true`, + then a background reload is started, which updates the records' data, once + it is available: + + ```js + // app/adapters/post.js + import ApplicationAdapter from "./application"; + + export default ApplicationAdapter.extend({ + shouldReloadRecord(store, snapshot) { + return false; + }, + + shouldBackgroundReloadRecord(store, snapshot) { + return true; + } + }); + + // ... + + store.push({ + data: { + id: 1, + type: 'post', + revision: 1 + } + }); + + let blogPost = store.findRecord('post', 1).then(function(post) { + post.get('revision'); // 1 + }); + + // later, once adapter#findRecord resolved with + // [ + // { + // id: 1, + // type: 'post', + // revision: 2 + // } + // ] + + blogPost.get('revision'); // 2 + ``` + + If you would like to force or prevent background reloading, you can set a + boolean value for `backgroundReload` in the options object for + `findRecord`. + + ```app/routes/post/edit.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + model(params) { + return this.store.findRecord('post', params.post_id, { backgroundReload: false }); + } + }); + ``` + + If you pass an object on the `adapterOptions` property of the options + argument it will be passed to you adapter via the snapshot + + ```app/routes/post/edit.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + model(params) { + return this.store.findRecord('post', params.post_id, { + adapterOptions: { subscribe: false } + }); + } + }); + ``` + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + findRecord(store, type, id, snapshot) { + if (snapshot.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + + See [peekRecord](#method_peekRecord) to get the cached version of a record. + + ### Retrieving Related Model Records + + If you use an adapter such as Ember's default + [`JSONAPIAdapter`](https://emberjs.com/api/data/classes/DS.JSONAPIAdapter.html) + that supports the [JSON API specification](http://jsonapi.org/) and if your server + endpoint supports the use of an + ['include' query parameter](http://jsonapi.org/format/#fetching-includes), + you can use `findRecord()` to automatically retrieve additional records related to + the one you request by supplying an `include` parameter in the `options` object. + + For example, given a `post` model that has a `hasMany` relationship with a `comment` + model, when we retrieve a specific post we can have the server also return that post's + comments in the same request: + + ```app/routes/post.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + model(params) { + return this.store.findRecord('post', params.post_id, { include: 'comments' }); + } + }); + + ``` + In this case, the post's comments would then be available in your template as + `model.comments`. + + Multiple relationships can be requested using an `include` parameter consisting of a + comma-separated list (without white-space) while nested relationships can be specified + using a dot-separated sequence of relationship names. So to request both the post's + comments and the authors of those comments the request would look like this: + + ```app/routes/post.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + model(params) { + return this.store.findRecord('post', params.post_id, { include: 'comments,comments.author' }); + } + }); + + ``` + + @since 1.13.0 + @method findRecord + @param {String} modelName + @param {(String|Integer)} id + @param {Object} options + @return {Promise} promise + */ + findRecord(modelName, id, options) { + assert(`You need to pass a model name to the store's findRecord method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert(badIdFormatAssertion, (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id))); + + let normalizedModelName = normalizeModelName(modelName); + + let internalModel = this._internalModelForId(normalizedModelName, id); + options = options || {}; + + if (!this.hasRecordForId(normalizedModelName, id)) { + return this._findByInternalModel(internalModel, options); + } + + let fetchedInternalModel = this._findRecord(internalModel, options); + + return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${normalizedModelName} with id: ${id}`); + }, + + _findRecord(internalModel, options) { + // Refetch if the reload option is passed + if (options.reload) { + return this._scheduleFetch(internalModel, options); + } + + let snapshot = internalModel.createSnapshot(options); + let adapter = this.adapterFor(internalModel.modelName); + + // Refetch the record if the adapter thinks the record is stale + if (adapter.shouldReloadRecord(this, snapshot)) { + return this._scheduleFetch(internalModel, options); + } + + if (options.backgroundReload === false) { + return Promise.resolve(internalModel); + } + + // Trigger the background refetch if backgroundReload option is passed + if (options.backgroundReload || adapter.shouldBackgroundReloadRecord(this, snapshot)) { + this._scheduleFetch(internalModel, options); + } + + // Return the cached record + return Promise.resolve(internalModel); + }, + + _findByInternalModel(internalModel, options = {}) { + if (options.preload) { + internalModel.preloadData(options.preload); + } + + let fetchedInternalModel = this._findEmptyInternalModel(internalModel, options); + + return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${internalModel.modelName} with id: ${internalModel.id}`); + }, + + _findEmptyInternalModel(internalModel, options) { + if (internalModel.isEmpty()) { + return this._scheduleFetch(internalModel, options); + } + + //TODO double check about reloading + if (internalModel.isLoading()) { + return internalModel._loadingPromise; + } + + return Promise.resolve(internalModel); + }, + + /** + This method makes a series of requests to the adapter's `find` method + and returns a promise that resolves once they are all loaded. + + @private + @method findByIds + @param {String} modelName + @param {Array} ids + @return {Promise} promise + */ + findByIds(modelName, ids) { + assert(`You need to pass a model name to the store's findByIds method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let promises = new Array(ids.length); + + let normalizedModelName = normalizeModelName(modelName); + + for (let i = 0; i < ids.length; i++) { + promises[i] = this.findRecord(normalizedModelName, ids[i]); + } + + return promiseArray(RSVP.all(promises).then(A, null, `DS: Store#findByIds of ${normalizedModelName} complete`)); + }, + + /** + This method is called by `findRecord` if it discovers that a particular + type/id pair hasn't been loaded yet to kick off a request to the + adapter. + + @method _fetchRecord + @private + @param {InternalModel} internalModel model + @return {Promise} promise + */ + _fetchRecord(internalModel, options) { + let modelName = internalModel.modelName; + let adapter = this.adapterFor(modelName); + + assert(`You tried to find a record but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to find a record but your adapter (for ${modelName}) does not implement 'findRecord'`, typeof adapter.findRecord === 'function'); + + return _find(adapter, this, internalModel.type, internalModel.id, internalModel, options); + }, + + _scheduleFetchMany(internalModels) { + let fetches = new Array(internalModels.length); + + for (let i = 0; i < internalModels.length; i++) { + fetches[i] = this._scheduleFetch(internalModels[i]); + } + + return Promise.all(fetches); + }, + + _scheduleFetch(internalModel, options) { + if (internalModel._loadingPromise) { + return internalModel._loadingPromise; + } + + let { id, modelName } = internalModel; + let resolver = RSVP.defer(`Fetching ${modelName}' with id: ${id}`); + let pendingFetchItem = { + internalModel, + resolver, + options + }; + + let promise = resolver.promise; + + internalModel.loadingData(promise); + if (this._pendingFetch.size === 0) { + emberRun.schedule('actions', this, this.flushAllPendingFetches); + } + + this._pendingFetch.get(modelName).push(pendingFetchItem); + + return promise; + }, + + flushAllPendingFetches() { + if (this.isDestroyed || this.isDestroying) { + return; + } + + this._pendingFetch.forEach(this._flushPendingFetchForType, this); + this._pendingFetch.clear(); + }, + + _flushPendingFetchForType(pendingFetchItems, modelName) { + let store = this; + let adapter = store.adapterFor(modelName); + let shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; + let totalItems = pendingFetchItems.length; + let internalModels = new Array(totalItems); + let seeking = Object.create(null); + + for (let i = 0; i < totalItems; i++) { + let pendingItem = pendingFetchItems[i]; + let internalModel = pendingItem.internalModel; + internalModels[i] = internalModel; + seeking[internalModel.id] = pendingItem; + } + + for (let i = 0; i < totalItems; i++) { + let internalModel = internalModels[i]; + // We may have unloaded the record after scheduling this fetch, in which + // case we must cancel the destroy. This is because we require a record + // to build a snapshot. This is not fundamental: this cancelation code + // can be removed when snapshots can be created for internal models that + // have no records. + if (internalModel.hasScheduledDestroy()) { + internalModels[i].cancelDestroy(); + } + } + + function _fetchRecord(recordResolverPair) { + let recordFetch = store._fetchRecord( + recordResolverPair.internalModel, + recordResolverPair.options + ); // TODO adapter options + + recordResolverPair.resolver.resolve(recordFetch); + } + + function handleFoundRecords(foundInternalModels, expectedInternalModels) { + // resolve found records + let found = Object.create(null); + for (let i = 0, l = foundInternalModels.length; i < l; i++) { + let internalModel = foundInternalModels[i]; + let pair = seeking[internalModel.id]; + found[internalModel.id] = internalModel; + + if (pair) { + let resolver = pair.resolver; + resolver.resolve(internalModel); + } + } + + // reject missing records + let missingInternalModels = []; + + for (let i = 0, l = expectedInternalModels.length; i < l; i++) { + let internalModel = expectedInternalModels[i]; + + if (!found[internalModel.id]) { + missingInternalModels.push(internalModel); + } + } + + if (missingInternalModels.length) { + warn( + 'Ember Data expected to find records with the following ids in the adapter response but they were missing: [ "' + + missingInternalModels.map(r => r.id).join('", "') + + '" ]', + false, + { + id: 'ds.store.missing-records-from-adapter' + } + ); + rejectInternalModels(missingInternalModels); + } + } + + function rejectInternalModels(internalModels, error) { + for (let i = 0, l = internalModels.length; i < l; i++) { + let internalModel = internalModels[i]; + let pair = seeking[internalModel.id]; + + if (pair) { + pair.resolver.reject(error || new Error(`Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.`)); + } + } + } + + if (shouldCoalesce) { + // TODO: Improve records => snapshots => records => snapshots + // + // We want to provide records to all store methods and snapshots to all + // adapter methods. To make sure we're doing that we're providing an array + // of snapshots to adapter.groupRecordsForFindMany(), which in turn will + // return grouped snapshots instead of grouped records. + // + // But since the _findMany() finder is a store method we need to get the + // records from the grouped snapshots even though the _findMany() finder + // will once again convert the records to snapshots for adapter.findMany() + let snapshots = new Array(totalItems); + for (let i = 0; i < totalItems; i++) { + snapshots[i] = internalModels[i].createSnapshot(); + } + + let groups = adapter.groupRecordsForFindMany(this, snapshots); + + for (var i = 0, l = groups.length; i < l; i++) { + var group = groups[i]; + var totalInGroup = groups[i].length; + var ids = new Array(totalInGroup); + var groupedInternalModels = new Array(totalInGroup); + + for (var j = 0; j < totalInGroup; j++) { + var internalModel = group[j]._internalModel; + + groupedInternalModels[j] = internalModel; + ids[j] = internalModel.id; + } + + if (totalInGroup > 1) { + (function(groupedInternalModels) { + _findMany(adapter, store, modelName, ids, groupedInternalModels) + .then(function(foundInternalModels) { + handleFoundRecords(foundInternalModels, groupedInternalModels); + }) + .catch(function(error) { + rejectInternalModels(groupedInternalModels, error); + }); + }(groupedInternalModels)); + } else if (ids.length === 1) { + var pair = seeking[groupedInternalModels[0].id]; + _fetchRecord(pair); + } else { + assert("You cannot return an empty array from adapter's method groupRecordsForFindMany", false); + } + } + } else { + for (let i = 0; i < totalItems; i++) { + _fetchRecord(pendingFetchItems[i]); + } + } + }, + + /** + Get the reference for the specified record. + + Example + + ```javascript + let userRef = store.getReference('user', 1); + + // check if the user is loaded + let isLoaded = userRef.value() !== null; + + // get the record of the reference (null if not yet available) + let user = userRef.value(); + + // get the identifier of the reference + if (userRef.remoteType() === 'id') { + let id = userRef.id(); + } + + // load user (via store.find) + userRef.load().then(...) + + // or trigger a reload + userRef.reload().then(...) + + // provide data for reference + userRef.push({ id: 1, username: '@user' }).then(function(user) { + userRef.value() === user; + }); + ``` + + @method getReference + @param {String} modelName + @param {String|Integer} id + @since 2.5.0 + @return {RecordReference} + */ + getReference(modelName, id) { + let normalizedModelName = normalizeModelName(modelName); + + return this._internalModelForId(normalizedModelName, id).recordReference; + }, + + /** + Get a record by a given type and ID without triggering a fetch. + + This method will synchronously return the record if it is available in the store, + otherwise it will return `null`. A record is available if it has been fetched earlier, or + pushed manually into the store. + + See [findRecord](#method_findRecord) if you would like to request this record from the backend. + + _Note: This is a synchronous method and does not return a promise._ + + ```js + let post = store.peekRecord('post', 1); + + post.get('id'); // 1 + ``` + + @since 1.13.0 + @method peekRecord + @param {String} modelName + @param {String|Integer} id + @return {DS.Model|null} record + */ + peekRecord(modelName, id) { + heimdall.increment(peekRecord); + assert(`You need to pass a model name to the store's peekRecord method`, isPresent(modelName)); + assert(`You need to pass both a model name and id to the store's peekRecord method`, isPresent(modelName) && isPresent(id)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + + if (this.hasRecordForId(normalizedModelName, id)) { + return this._internalModelForId(normalizedModelName, id).getRecord(); + } else { + return null; + } + }, + + /** + This method is called by the record's `reload` method. + + This method calls the adapter's `find` method, which returns a promise. When + **that** promise resolves, `_reloadRecord` will resolve the promise returned + by the record's `reload`. + + @method _reloadRecord + @private + @param {DS.Model} internalModel + @param options optional to include adapterOptions + @return {Promise} promise + */ + _reloadRecord(internalModel, options) { + let { id, modelName } = internalModel; + let adapter = this.adapterFor(modelName); + + assert(`You cannot reload a record without an ID`, id); + assert(`You tried to reload a record but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to reload a record but your adapter does not implement 'findRecord'`, typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); + + return this._scheduleFetch(internalModel, options); + }, + + /** + This method returns true if a record for a given modelName and id is already + loaded in the store. Use this function to know beforehand if a findRecord() + will result in a request or that it will be a cache hit. + + Example + + ```javascript + store.hasRecordForId('post', 1); // false + store.findRecord('post', 1).then(function() { + store.hasRecordForId('post', 1); // true + }); + ``` + + @method hasRecordForId + @param {String} modelName + @param {(String|Integer)} id + @return {Boolean} + */ + hasRecordForId(modelName, id) { + assert(`You need to pass a model name to the store's hasRecordForId method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let normalizedModelName = normalizeModelName(modelName); + + let trueId = coerceId(id); + let internalModel = this._internalModelsFor(normalizedModelName).get(trueId); + + return !!internalModel && internalModel.isLoaded(); + }, + + /** + Returns id record for a given type and ID. If one isn't already loaded, + it builds a new record and leaves it in the `empty` state. + + @method recordForId + @private + @param {String} modelName + @param {(String|Integer)} id + @return {DS.Model} record + */ + recordForId(modelName, id) { + assert(`You need to pass a model name to the store's recordForId method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + return this._internalModelForId(modelName, id).getRecord(); + }, + + + // directly get an internal model from ID map if it is there, without doing any + // processing + _getInternalModelForId(modelName, id, clientId) { + let internalModel; + if (clientId) { + internalModel = this._newlyCreatedModelsFor(modelName).get(clientId); + } + + if (!internalModel) { + internalModel = this._internalModelsFor(modelName).get(id); + } + return internalModel; + }, + + _internalModelForId(modelName, id, clientId) { + heimdall.increment(_internalModelForId); + let trueId = coerceId(id); + let internalModel = this._getInternalModelForId(modelName, trueId, clientId); + + if (internalModel) { + // unloadRecord is async, if one attempts to unload + then sync push, + // we must ensure the unload is canceled before continuing + // The createRecord path will take _existingInternalModelForId() + // which will call `destroySync` instead for this unload + then + // sync createRecord scenario. Once we have true client-side + // delete signaling, we should never call destroySync + if (internalModel.hasScheduledDestroy()) { + internalModel.cancelDestroy(); + } + + return internalModel; + } + + return this._buildInternalModel(modelName, trueId, null, clientId); + }, + + + + /** + @method findMany + @private + @param {Array} internalModels + @return {Promise} promise + */ + findMany(internalModels) { + let finds = new Array(internalModels.length); + + for (let i = 0; i < internalModels.length; i++) { + finds[i] = this._findEmptyInternalModel(internalModels[i]); + } + + return Promise.all(finds); + }, + + + /** + If a relationship was originally populated by the adapter as a link + (as opposed to a list of IDs), this method is called when the + relationship is fetched. + + The link (which is usually a URL) is passed through unchanged, so the + adapter can make whatever request it wants. + + The usual use-case is for the server to register a URL as a link, and + then use that URL in the future to make a request for the relationship. + + @method findHasMany + @private + @param {InternalModel} internalModel + @param {any} link + @param {(Relationship)} relationship + @return {Promise} promise + */ + findHasMany(internalModel, link, relationship) { + let adapter = this.adapterFor(internalModel.modelName); + + assert(`You tried to load a hasMany relationship but you have no adapter (for ${internalModel.modelName})`, adapter); + assert(`You tried to load a hasMany relationship from a specified 'link' in the original payload but your adapter does not implement 'findHasMany'`, typeof adapter.findHasMany === 'function'); + + return _findHasMany(adapter, this, internalModel, link, relationship); + }, + + _findHasManyByJsonApiResource(resource, parentInternalModel, relationshipMeta) { + if (!resource) { + return RSVP.resolve([]); + } + + let { + relationshipIsStale, + hasRelatedResources, + hasDematerializedInverse, + hasAnyRelationshipData, + relationshipIsEmpty + } = resource._relationship; + + let shouldFindViaLink = resource.links && resource.links.related + && (hasDematerializedInverse || relationshipIsStale || + (!hasRelatedResources && !relationshipIsEmpty)); + + // fetch via link + if (shouldFindViaLink) { + return this.findHasMany(parentInternalModel, resource.links.related, relationshipMeta).then(internalModels => { + let payload = { data: internalModels.map((im) => im._modelData.getResourceIdentifier()) }; + if (internalModels.meta !== undefined) { + payload.meta = internalModels.meta; + } + parentInternalModel.linkWasLoadedForRelationship(relationshipMeta.key, payload); + return internalModels; + }); + } + + let preferLocalCache = hasAnyRelationshipData && + // hasRelatedResources && + !relationshipIsEmpty; + let hasLocalPartialData = hasDematerializedInverse || + (relationshipIsEmpty && + Array.isArray(resource.data) && + resource.data.length > 0); + + // fetch using data, pulling from local cache if possible + if (!relationshipIsStale && (preferLocalCache || hasLocalPartialData)) { + let internalModels = resource.data.map((json) => this._internalModelForResource(json)); + + return this.findMany(internalModels); + } + + let hasData = hasAnyRelationshipData && !relationshipIsEmpty; + + // fetch by data + if (hasData || hasLocalPartialData) { + let internalModels = resource.data.map((json) => this._internalModelForResource(json)); + + return this._scheduleFetchMany(internalModels); + } + + // we were explicitly told we have no data and no links. + // TODO if the relationshipIsStale, should we hit the adapter anyway? + return RSVP.resolve([]); + }, + + _getHasManyByJsonApiResource(resource) { + let internalModels = []; + if (resource && resource.data) { + internalModels = resource.data.map((reference) => this._internalModelForResource(reference)); + } + return internalModels; + }, + + + /** + @method findBelongsTo + @private + @param {InternalModel} internalModel + @param {any} link + @param {Relationship} relationship + @return {Promise} promise + */ + findBelongsTo(internalModel, link, relationship) { + let adapter = this.adapterFor(internalModel.modelName); + + assert(`You tried to load a belongsTo relationship but you have no adapter (for ${internalModel.modelName})`, adapter); + assert(`You tried to load a belongsTo relationship from a specified 'link' in the original payload but your adapter does not implement 'findBelongsTo'`, typeof adapter.findBelongsTo === 'function'); + + return _findBelongsTo(adapter, this, internalModel, link, relationship); + }, + + _fetchBelongsToLinkFromResource(resource, parentInternalModel, relationshipMeta) { + if (!resource || !resource.links || !resource.links.related) { + // should we warn here, not sure cause its an internal method + return RSVP.resolve(null); + } + return this.findBelongsTo(parentInternalModel, resource.links.related, relationshipMeta).then((internalModel) => { + let response = internalModel && internalModel._modelData.getResourceIdentifier(); + parentInternalModel.linkWasLoadedForRelationship(relationshipMeta.key, { data: response }); + if (internalModel === null) { + return null; + } + // TODO Igor this doesn't seem like the right boundary, probably the caller method should extract the record out + return internalModel.getRecord(); + }); + }, + + _findBelongsToByJsonApiResource(resource, parentInternalModel, relationshipMeta) { + if (!resource) { + return RSVP.resolve(null); + } + + let { + relationshipIsStale, + hasRelatedResources, + hasDematerializedInverse, + hasAnyRelationshipData, + relationshipIsEmpty + } = resource._relationship; + + let shouldFindViaLink = resource.links && resource.links.related + && (hasDematerializedInverse || relationshipIsStale || + (!hasRelatedResources && !relationshipIsEmpty)); + + // fetch via link + if (shouldFindViaLink) { + return this._fetchBelongsToLinkFromResource(resource, parentInternalModel, relationshipMeta); + } + + let preferLocalCache = hasAnyRelationshipData && + hasRelatedResources && + !relationshipIsEmpty; + let hasLocalPartialData = hasDematerializedInverse || + (relationshipIsEmpty && resource.data); + + // fetch using data, pulling from local cache if possible + if (!relationshipIsStale && (preferLocalCache || hasLocalPartialData)) { + let internalModel = this._internalModelForResource(resource.data); + + return this._findByInternalModel(internalModel); + } + + // null is explicit empty, undefined is "we don't know anything" + let localDataIsEmpty = resource.data === undefined || resource.data === null; + let resourceIsLocal = !localDataIsEmpty && resource.data.id === null; + + if (resourceIsLocal) { + let internalModel = this._internalModelForResource(resource.data); + + return RSVP.resolve(internalModel.getRecord()); + } + + // fetch by data + if (!localDataIsEmpty) { + let internalModel = this._internalModelForResource(resource.data); + + return this._fetchRecord(internalModel).then(() => { + return internalModel.getRecord(); + }); + } + + // we were explicitly told we have no data and no links. + // TODO if the relationshipIsStale, should we hit the adapter anyway? + return RSVP.resolve(null); + }, + + + /** + This method delegates a query to the adapter. This is the one place where + adapter-level semantics are exposed to the application. + + Each time this method is called a new request is made through the adapter. + + Exposing queries this way seems preferable to creating an abstract query + language for all server-side queries, and then require all adapters to + implement them. + + --- + + If you do something like this: + + ```javascript + store.query('person', { page: 1 }); + ``` + + The call made to the server, using a Rails backend, will look something like this: + + ``` + Started GET "/api/v1/person?page=1" + Processing by Api::V1::PersonsController#index as HTML + Parameters: { "page"=>"1" } + ``` + + --- + + If you do something like this: + + ```javascript + store.query('person', { ids: [1, 2, 3] }); + ``` + + The call to the server, using a Rails backend, will look something like this: + + ``` + Started GET "/api/v1/person?ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3" + Processing by Api::V1::PersonsController#index as HTML + Parameters: { "ids" => ["1", "2", "3"] } + ``` + + This method returns a promise, which is resolved with an + [`AdapterPopulatedRecordArray`](https://emberjs.com/api/data/classes/DS.AdapterPopulatedRecordArray.html) + once the server returns. + + @since 1.13.0 + @method query + @param {String} modelName + @param {any} query an opaque query to be used by the adapter + @param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.query + @return {Promise} promise + */ + query(modelName, query, options) { + assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); + assert(`You need to pass a query hash to the store's query method`, query); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let adapterOptionsWrapper = {}; + + if (options && options.adapterOptions) { + adapterOptionsWrapper.adapterOptions = options.adapterOptions + } + + let normalizedModelName = normalizeModelName(modelName); + return this._query(normalizedModelName, query, null, adapterOptionsWrapper); + }, + + _query(modelName, query, array, options) { + let token = heimdall.start('store._query'); + assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); + assert(`You need to pass a query hash to the store's query method`, query); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let modelToken = heimdall.start('initial-modelFor-lookup'); + heimdall.stop(modelToken); + + let adapterToken = heimdall.start('initial-adapterFor-lookup'); + let adapter = this.adapterFor(modelName); + heimdall.stop(adapterToken); + + assert(`You tried to load a query but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to load a query but your adapter does not implement 'query'`, typeof adapter.query === 'function'); + + let pA = promiseArray(_query(adapter, this, modelName, query, array, options)); + instrument(() => { + pA.finally(() => { heimdall.stop(token); }); + }); + return pA; + }, + + /** + This method makes a request for one record, where the `id` is not known + beforehand (if the `id` is known, use [`findRecord`](#method_findRecord) + instead). + + This method can be used when it is certain that the server will return a + single object for the primary data. + + Each time this method is called a new request is made through the adapter. + + Let's assume our API provides an endpoint for the currently logged in user + via: + + ``` + // GET /api/current_user + { + user: { + id: 1234, + username: 'admin' + } + } + ``` + + Since the specific `id` of the `user` is not known beforehand, we can use + `queryRecord` to get the user: + + ```javascript + store.queryRecord('user', {}).then(function(user) { + let username = user.get('username'); + console.log(`Currently logged in as ${username}`); + }); + ``` + + The request is made through the adapters' `queryRecord`: + + ```app/adapters/user.js + import $ from 'jquery'; + import DS from 'ember-data'; + + export default DS.Adapter.extend({ + queryRecord(modelName, query) { + return $.getJSON('/api/current_user'); + } + }); + ``` + + Note: the primary use case for `store.queryRecord` is when a single record + is queried and the `id` is not known beforehand. In all other cases + `store.query` and using the first item of the array is likely the preferred + way: + + ``` + // GET /users?username=unique + { + data: [{ + id: 1234, + type: 'user', + attributes: { + username: "unique" + } + }] + } + ``` + + ```javascript + store.query('user', { username: 'unique' }).then(function(users) { + return users.get('firstObject'); + }).then(function(user) { + let id = user.get('id'); + }); + ``` + + This method returns a promise, which resolves with the found record. + + If the adapter returns no data for the primary data of the payload, then + `queryRecord` resolves with `null`: + + ``` + // GET /users?username=unique + { + data: null + } + ``` + + ```javascript + store.queryRecord('user', { username: 'unique' }).then(function(user) { + console.log(user); // null + }); + ``` + + @since 1.13.0 + @method queryRecord + @param {String} modelName + @param {any} query an opaque query to be used by the adapter + @param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.queryRecord + @return {Promise} promise which resolves with the found record or `null` + */ + queryRecord(modelName, query, options) { + assert(`You need to pass a model name to the store's queryRecord method`, isPresent(modelName)); + assert(`You need to pass a query hash to the store's queryRecord method`, query); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let normalizedModelName = normalizeModelName(modelName); + let adapter = this.adapterFor(normalizedModelName); + let adapterOptionsWrapper = {}; + + if (options && options.adapterOptions) { + adapterOptionsWrapper.adapterOptions = options.adapterOptions + } + + assert(`You tried to make a query but you have no adapter (for ${normalizedModelName})`, adapter); + assert(`You tried to make a query but your adapter does not implement 'queryRecord'`, typeof adapter.queryRecord === 'function'); + + return promiseObject(_queryRecord(adapter, this, modelName, query, adapterOptionsWrapper).then(internalModel => { + // the promise returned by store.queryRecord is expected to resolve with + // an instance of DS.Model + if (internalModel) { + return internalModel.getRecord(); + } + + return null; + })); + }, + + /** + `findAll` asks the adapter's `findAll` method to find the records for the + given type, and returns a promise which will resolve with all records of + this type present in the store, even if the adapter only returns a subset + of them. + + ```app/routes/authors.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + model(params) { + return this.store.findAll('author'); + } + }); + ``` + + _When_ the returned promise resolves depends on the reload behavior, + configured via the passed `options` hash and the result of the adapter's + `shouldReloadAll` method. + + ### Reloading + + If `{ reload: true }` is passed or `adapter.shouldReloadAll` evaluates to + `true`, then the returned promise resolves once the adapter returns data, + regardless if there are already records in the store: + + ```js + store.push({ + data: { + id: 'first', + type: 'author' + } + }); + + // adapter#findAll resolves with + // [ + // { + // id: 'second', + // type: 'author' + // } + // ] + store.findAll('author', { reload: true }).then(function(authors) { + authors.getEach('id'); // ['first', 'second'] + }); + ``` + + If no reload is indicated via the abovementioned ways, then the promise + immediately resolves with all the records currently loaded in the store. + + ### Background Reloading + + Optionally, if `adapter.shouldBackgroundReloadAll` evaluates to `true`, + then a background reload is started. Once this resolves, the array with + which the promise resolves, is updated automatically so it contains all the + records in the store: + + ```app/adapters/application.js + import DS from 'ember-data'; + export default DS.Adapter.extend({ + shouldReloadAll(store, snapshotsArray) { + return false; + }, + + shouldBackgroundReloadAll(store, snapshotsArray) { + return true; + } + }); + + // ... + + store.push({ + data: { + id: 'first', + type: 'author' + } + }); + + let allAuthors; + store.findAll('author').then(function(authors) { + authors.getEach('id'); // ['first'] + + allAuthors = authors; + }); + + // later, once adapter#findAll resolved with + // [ + // { + // id: 'second', + // type: 'author' + // } + // ] + + allAuthors.getEach('id'); // ['first', 'second'] + ``` + + If you would like to force or prevent background reloading, you can set a + boolean value for `backgroundReload` in the options object for + `findAll`. + + ```app/routes/post/edit.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + model() { + return this.store.findAll('post', { backgroundReload: false }); + } + }); + ``` + + If you pass an object on the `adapterOptions` property of the options + argument it will be passed to you adapter via the `snapshotRecordArray` + + ```app/routes/posts.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + model(params) { + return this.store.findAll('post', { + adapterOptions: { subscribe: false } + }); + } + }); + ``` + + ```app/adapters/post.js + import MyCustomAdapter from './custom-adapter'; + + export default MyCustomAdapter.extend({ + findAll(store, type, sinceToken, snapshotRecordArray) { + if (snapshotRecordArray.adapterOptions.subscribe) { + // ... + } + // ... + } + }); + ``` + + See [peekAll](#method_peekAll) to get an array of current records in the + store, without waiting until a reload is finished. + + ### Retrieving Related Model Records + + If you use an adapter such as Ember's default + [`JSONAPIAdapter`](https://emberjs.com/api/data/classes/DS.JSONAPIAdapter.html) + that supports the [JSON API specification](http://jsonapi.org/) and if your server + endpoint supports the use of an + ['include' query parameter](http://jsonapi.org/format/#fetching-includes), + you can use `findAll()` to automatically retrieve additional records related to + those requested by supplying an `include` parameter in the `options` object. + + For example, given a `post` model that has a `hasMany` relationship with a `comment` + model, when we retrieve all of the post records we can have the server also return + all of the posts' comments in the same request: + + ```app/routes/posts.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + model() { + return this.store.findAll('post', { include: 'comments' }); + } + }); + + ``` + Multiple relationships can be requested using an `include` parameter consisting of a + comma-separated list (without white-space) while nested relationships can be specified + using a dot-separated sequence of relationship names. So to request both the posts' + comments and the authors of those comments the request would look like this: + + ```app/routes/posts.js + import Route from '@ember/routing/route'; + + export default Route.extend({ + model() { + return this.store.findAll('post', { include: 'comments,comments.author' }); + } + }); + + ``` + + See [query](#method_query) to only get a subset of records from the server. + + @since 1.13.0 + @method findAll + @param {String} modelName + @param {Object} options + @return {Promise} promise + */ + findAll(modelName, options) { + assert(`You need to pass a model name to the store's findAll method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let token = heimdall.start('store.findAll'); + let normalizedModelName = normalizeModelName(modelName); + let fetch = this._fetchAll(normalizedModelName, this.peekAll(normalizedModelName), options); + + instrument(() => { + fetch.finally(() => { heimdall.stop(token); }); + }); + + return fetch; + }, + + /** + @method _fetchAll + @private + @param {DS.Model} modelName + @param {DS.RecordArray} array + @return {Promise} promise + */ + _fetchAll(modelName, array, options = {}) { + let adapter = this.adapterFor(modelName); + let sinceToken = this._internalModelsFor(modelName).metadata.since; + + assert(`You tried to load all records but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to load all records but your adapter does not implement 'findAll'`, typeof adapter.findAll === 'function'); + + if (options.reload) { + set(array, 'isUpdating', true); + return promiseArray(_findAll(adapter, this, modelName, sinceToken, options)); + } + + let snapshotArray = array._createSnapshot(options); + + if (adapter.shouldReloadAll(this, snapshotArray)) { + set(array, 'isUpdating', true); + return promiseArray(_findAll(adapter, this, modelName, sinceToken, options)); + } + + if (options.backgroundReload === false) { + return promiseArray(Promise.resolve(array)); + } + + if (options.backgroundReload || adapter.shouldBackgroundReloadAll(this, snapshotArray)) { + set(array, 'isUpdating', true); + _findAll(adapter, this, modelName, sinceToken, options); + } + + return promiseArray(Promise.resolve(array)); + }, + + /** + @method _didUpdateAll + @param {String} modelName + @private + */ + _didUpdateAll(modelName) { + heimdall.increment(_didUpdateAll); + this.recordArrayManager._didUpdateAll(modelName); + }, + + /** + This method returns a filtered array that contains all of the + known records for a given type in the store. + + Note that because it's just a filter, the result will contain any + locally created records of the type, however, it will not make a + request to the backend to retrieve additional records. If you + would like to request all the records from the backend please use + [store.findAll](#method_findAll). + + Also note that multiple calls to `peekAll` for a given type will always + return the same `RecordArray`. + + Example + + ```javascript + let localPosts = store.peekAll('post'); + ``` + + @since 1.13.0 + @method peekAll + @param {String} modelName + @return {DS.RecordArray} + */ + peekAll(modelName) { + heimdall.increment(peekAll); + assert(`You need to pass a model name to the store's peekAll method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + return this.recordArrayManager.liveRecordArrayFor(normalizedModelName); + }, + + /** + This method unloads all records in the store. + It schedules unloading to happen during the next run loop. + + Optionally you can pass a type which unload all records for a given type. + + ```javascript + store.unloadAll(); + store.unloadAll('post'); + ``` + + @method unloadAll + @param {String} modelName + */ + unloadAll(modelName) { + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, !modelName || typeof modelName === 'string'); + + if (arguments.length === 0) { + this._identityMap.clear(); + } else { + let normalizedModelName = normalizeModelName(modelName); + this._internalModelsFor(normalizedModelName).clear(); + } + }, + + filter() { + assert('The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', false); + }, + + // .............. + // . PERSISTING . + // .............. + + /** + This method is called by `record.save`, and gets passed a + resolver for the promise that `record.save` returns. + + It schedules saving to happen at the end of the run loop. + + @method scheduleSave + @private + @param {InternalModel} internalModel + @param {Resolver} resolver + @param {Object} options + */ + scheduleSave(internalModel, resolver, options) { + let snapshot = internalModel.createSnapshot(options); + internalModel.adapterWillCommit(); + this._pendingSave.push({ + snapshot: snapshot, + resolver: resolver + }); + emberRun.once(this, this.flushPendingSave); + }, + + /** + This method is called at the end of the run loop, and + flushes any records passed into `scheduleSave` + + @method flushPendingSave + @private + */ + flushPendingSave() { + let pending = this._pendingSave.slice(); + this._pendingSave = []; + + for (let i = 0, j = pending.length; i < j; i++) { + let pendingItem = pending[i]; + let snapshot = pendingItem.snapshot; + let resolver = pendingItem.resolver; + let internalModel = snapshot._internalModel; + let adapter = this.adapterFor(internalModel.modelName); + let operation; + + if (internalModel.currentState.stateName === 'root.deleted.saved') { + resolver.resolve(); + continue; + } else if (internalModel.isNew()) { + operation = 'createRecord'; + } else if (internalModel.isDeleted()) { + operation = 'deleteRecord'; + } else { + operation = 'updateRecord'; + } + + resolver.resolve(_commit(adapter, this, operation, snapshot)); + } + + }, + + /** + This method is called once the promise returned by an + adapter's `createRecord`, `updateRecord` or `deleteRecord` + is resolved. + + If the data provides a server-generated ID, it will + update the record and the store's indexes. + + @method didSaveRecord + @private + @param {InternalModel} internalModel the in-flight internal model + @param {Object} data optional data (see above) + */ + didSaveRecord(internalModel, dataArg) { + let data; + if (dataArg) { + data = dataArg.data; + } + if (!data) { + assert(`Your ${internalModel.modelName} record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, internalModel.id); + } + + //We first make sure the primary data has been updated + //TODO try to move notification to the user to the end of the runloop + internalModel.adapterDidCommit(data); + }, + + /** + This method is called once the promise returned by an + adapter's `createRecord`, `updateRecord` or `deleteRecord` + is rejected with a `DS.InvalidError`. + + @method recordWasInvalid + @private + @param {InternalModel} internalModel + @param {Object} errors + */ + recordWasInvalid(internalModel, errors) { + internalModel.adapterDidInvalidate(errors); + }, + + /** + This method is called once the promise returned by an + adapter's `createRecord`, `updateRecord` or `deleteRecord` + is rejected (with anything other than a `DS.InvalidError`). + + @method recordWasError + @private + @param {InternalModel} internalModel + @param {Error} error + */ + recordWasError(internalModel, error) { + internalModel.adapterDidError(error); + }, + + /** + Sets newly received ID from the adapter's `createRecord`, `updateRecord` + or `deleteRecord`. + + @method setRecordId + @private + @param {String} modelName + @param {string} newId + @param {number} clientId + */ + setRecordId(modelName, newId, clientId) { + let trueId = coerceId(newId); + let internalModel = this._getInternalModelForId(modelName, trueId, clientId); + this._setRecordId(internalModel, newId, clientId); + }, + + updateId(internalModel, data) { + deprecate('store.updateId was documented as private and will be removed.', false, { + id: 'ds.store.updateId', + until: '3.5' + }); + this._setRecordId(internalModel, coerceId(data.id)); + }, + + _setRecordId(internalModel, id, clientId) { + let oldId = internalModel.id; + let modelName = internalModel.modelName; + + // ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record) + assert(`'${modelName}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null)); + + // ID absolutely can't be different than oldID if oldID is not null + assert(`'${modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, !(oldId !== null && id !== oldId)); + + // ID can be null if oldID is not null (altered ID in response for a record) + // however, this is more than likely a developer error. + if (oldId !== null && id === null) { + warn(`Your ${modelName} record was saved to the server, but the response does not have an id.`, !(oldId !== null && id === null)); + return; + } + + let existingInternalModel = this._existingInternalModelForId(modelName, id); + + assert(`'${modelName}' was saved to the server, but the response returned the new id '${id}', which has already been used with another record.'`, + isNone(existingInternalModel) || existingInternalModel === internalModel); + + this._internalModelsFor(internalModel.modelName).set(id, internalModel); + this._newlyCreatedModelsFor(internalModel.modelName).remove(internalModel, clientId); + + internalModel.setId(id); + }, + + /** + Returns a map of IDs to client IDs for a given modelName. + + @method _internalModelsFor + @private + @param {String} modelName + @return {Object} recordMap + */ + _internalModelsFor(modelName) { + heimdall.increment(_internalModelsFor); + return this._identityMap.retrieve(modelName); + }, + + _newlyCreatedModelsFor(modelName) { + return this._newlyCreated.retrieve(modelName); + }, + + // ................ + // . LOADING DATA . + // ................ + + /** + This internal method is used by `push`. + + @method _load + @private + @param {Object} data + */ + _load(data) { + heimdall.increment(_load); + let modelName = normalizeModelName(data.type); + let internalModel = this._internalModelForId(modelName, data.id); + + let isUpdate = internalModel.currentState.isEmpty === false; + + internalModel.setupData(data); + + if (isUpdate) { + this.recordArrayManager.recordDidChange(internalModel); + } else { + this.recordArrayManager.recordWasLoaded(internalModel); + } + + return internalModel; + }, + + /* + @deprecated + @private + */ + _modelForMixin(modelName) { + deprecate( + '_modelForMixin is private and deprecated and should never be used directly, use modelFor instead', + false, + { + id: 'ember-data:_modelForMixin', + until: '3.5' + } + ); + assert(`You need to pass a model name to the store's _modelForMixin method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + + return _modelForMixin(this, normalizedModelName); + }, + + /** + Returns the model class for the particular `modelName`. + + The class of a model might be useful if you want to get a list of all the + relationship names of the model, see + [`relationshipNames`](https://emberjs.com/api/data/classes/DS.Model.html#property_relationshipNames) + for example. + + @method modelFor + @param {String} modelName + @return {DS.Model} + */ + modelFor(modelName) { + assert(`You need to pass a model name to the store's modelFor method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + + let maybeFactory = this._modelFactoryFor(modelName); + + // for factorFor factory/class split + return maybeFactory.class ? maybeFactory.class : maybeFactory; + }, + + /* + @deprecated + @private + */ + _modelFor(modelName) { + deprecate( + '_modelFor is private and deprecated, you should use modelFor instead', + false, + { + id: 'ember-data:_modelFor', + until: '3.5' + } + ); + return this.modelFor(modelName); + }, + + _modelFactoryFor(modelName) { + assert(`You need to pass a model name to the store's _modelFactoryFor method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + let factory = getModelFactory(this, this._modelFactoryCache, normalizedModelName); + + if (factory === null) { + throw new EmberError(`No model was found for '${normalizedModelName}'`); + } + + return factory; + }, + + /* + @deprecated + @private + */ + modelFactoryFor(modelName) { + deprecate('modelFactoryFor is private and deprecated', false, { + id: 'ember-data:modelFactoryFor', + until: '3.5' + }); + return this._modelFactoryFor(modelName); + }, + + /* + Returns whether a ModelClass exists for a given modelName + This exists for legacy support for the RESTSerializer, + which due to how it must guess whether a key is a model + must query for whether a match exists. + + We should investigate an RFC to make this public or removing + this requirement. + + @private + */ + _hasModelFor(modelName) { + assert(`You need to pass a model name to the store's hasModelFor method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + let factory = getModelFactory(this, this._modelFactoryCache, normalizedModelName); + + return factory !== null; + }, + + /** + Push some data for a given type into the store. + + This method expects normalized [JSON API](http://jsonapi.org/) document. This means you have to follow [JSON API specification](http://jsonapi.org/format/) with few minor adjustments: + - record's `type` should always be in singular, dasherized form + - members (properties) should be camelCased + + [Your primary data should be wrapped inside `data` property](http://jsonapi.org/format/#document-top-level): + + ```js + store.push({ + data: { + // primary data for single record of type `Person` + id: '1', + type: 'person', + attributes: { + firstName: 'Daniel', + lastName: 'Kmak' + } + } + }); + ``` + + [Demo.](http://ember-twiddle.com/fb99f18cd3b4d3e2a4c7) + + `data` property can also hold an array (of records): + + ```js + store.push({ + data: [ + // an array of records + { + id: '1', + type: 'person', + attributes: { + firstName: 'Daniel', + lastName: 'Kmak' + } + }, + { + id: '2', + type: 'person', + attributes: { + firstName: 'Tom', + lastName: 'Dale' + } + } + ] + }); + ``` + + [Demo.](http://ember-twiddle.com/69cdbeaa3702159dc355) + + There are some typical properties for `JSONAPI` payload: + * `id` - mandatory, unique record's key + * `type` - mandatory string which matches `model`'s dasherized name in singular form + * `attributes` - object which holds data for record attributes - `DS.attr`'s declared in model + * `relationships` - object which must contain any of the following properties under each relationships' respective key (example path is `relationships.achievements.data`): + - [`links`](http://jsonapi.org/format/#document-links) + - [`data`](http://jsonapi.org/format/#document-resource-object-linkage) - place for primary data + - [`meta`](http://jsonapi.org/format/#document-meta) - object which contains meta-information about relationship + + For this model: + + ```app/models/person.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + firstName: DS.attr('string'), + lastName: DS.attr('string'), + + children: DS.hasMany('person') + }); + ``` + + To represent the children as IDs: + + ```js + { + data: { + id: '1', + type: 'person', + attributes: { + firstName: 'Tom', + lastName: 'Dale' + }, + relationships: { + children: { + data: [ + { + id: '2', + type: 'person' + }, + { + id: '3', + type: 'person' + }, + { + id: '4', + type: 'person' + } + ] + } + } + } + } + ``` + + [Demo.](http://ember-twiddle.com/343e1735e034091f5bde) + + To represent the children relationship as a URL: + + ```js + { + data: { + id: '1', + type: 'person', + attributes: { + firstName: 'Tom', + lastName: 'Dale' + }, + relationships: { + children: { + links: { + related: '/people/1/children' + } + } + } + } + } + ``` + + If you're streaming data or implementing an adapter, make sure + that you have converted the incoming data into this form. The + store's [normalize](#method_normalize) method is a convenience + helper for converting a json payload into the form Ember Data + expects. + + ```js + store.push(store.normalize('person', data)); + ``` + + This method can be used both to push in brand new + records, as well as to update existing records. + + @method push + @param {Object} data + @return {DS.Model|Array} the record(s) that was created or + updated. + */ + push(data) { + let token = heimdall.start('store.push'); + let pushed = this._push(data); + + if (Array.isArray(pushed)) { + let records = pushed.map(internalModel => internalModel.getRecord()); + heimdall.stop(token); + return records; + } + + if (pushed === null) { + heimdall.stop(token); + return null; + } + + let record = pushed.getRecord(); + heimdall.stop(token); + return record; + }, + + /* + Push some data in the form of a json-api document into the store, + without creating materialized records. + + @method _push + @private + @param {Object} jsonApiDoc + @return {DS.InternalModel|Array} pushed InternalModel(s) + */ + _push(jsonApiDoc) { + let token = heimdall.start('store._push'); + let internalModelOrModels = this._backburner.join(() => { + let included = jsonApiDoc.included; + let i, length; + + if (included) { + for (i = 0, length = included.length; i < length; i++) { + this._pushInternalModel(included[i]); + } + } + + if (Array.isArray(jsonApiDoc.data)) { + length = jsonApiDoc.data.length; + let internalModels = new Array(length); + + for (i = 0; i < length; i++) { + internalModels[i] = this._pushInternalModel(jsonApiDoc.data[i]); + } + return internalModels; + } + + if (jsonApiDoc.data === null) { + return null; + } + + assert(`Expected an object in the 'data' property in a call to 'push' for ${jsonApiDoc.type}, but was ${typeOf(jsonApiDoc.data)}`, typeOf(jsonApiDoc.data) === 'object'); + + return this._pushInternalModel(jsonApiDoc.data); + }); + heimdall.stop(token); + return internalModelOrModels; + }, + + _pushInternalModel(data) { + heimdall.increment(_pushInternalModel); + let modelName = data.type; + assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id !== null && data.id !== undefined && data.id !== ''); + assert(`You tried to push data with a type '${modelName}' but no model could be found with that name.`, this._hasModelFor(modelName)); + + if (DEBUG) { + // If ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload + // contains unknown attributes or relationships, log a warning. + + if (ENV.DS_WARN_ON_UNKNOWN_KEYS) { + let modelClass = this.modelFor(modelName); + + // Check unknown attributes + let unknownAttributes = Object.keys(data.attributes || {}).filter((key) => { + return !get(modelClass, 'fields').has(key); + }); + let unknownAttributesMessage = `The payload for '${modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`; + warn(unknownAttributesMessage, unknownAttributes.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); + + // Check unknown relationships + let unknownRelationships = Object.keys(data.relationships || {}).filter((key) => { + return !get(modelClass, 'fields').has(key); + }); + let unknownRelationshipsMessage = `The payload for '${modelName}' contains these unknown relationships: ${unknownRelationships}. Make sure they've been defined in your model.`; + warn(unknownRelationshipsMessage, unknownRelationships.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); + } + } + + // Actually load the record into the store. + let internalModel = this._load(data); + +// this._setupRelationshipsForModel(internalModel, data); + + return internalModel; + }, + + /** + Push some raw data into the store. + + This method can be used both to push in brand new + records, as well as to update existing records. You + can push in more than one type of object at once. + All objects should be in the format expected by the + serializer. + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.ActiveModelSerializer; + ``` + + ```js + let pushData = { + posts: [ + { id: 1, post_title: "Great post", comment_ids: [2] } + ], + comments: [ + { id: 2, comment_body: "Insightful comment" } + ] + } + + store.pushPayload(pushData); + ``` + + By default, the data will be deserialized using a default + serializer (the application serializer if it exists). + + Alternatively, `pushPayload` will accept a model type which + will determine which serializer will process the payload. + + ```app/serializers/application.js + import DS from 'ember-data'; + + export default DS.ActiveModelSerializer; + ``` + + ```app/serializers/post.js + import DS from 'ember-data'; + + export default DS.JSONSerializer; + ``` + + ```js + store.pushPayload(pushData); // Will use the application serializer + store.pushPayload('post', pushData); // Will use the post serializer + ``` + + @method pushPayload + @param {String} modelName Optionally, a model type used to determine which serializer will be used + @param {Object} inputPayload + */ + pushPayload(modelName, inputPayload) { + let serializer; + let payload; + if (!inputPayload) { + payload = modelName; + serializer = defaultSerializer(this); + assert(`You cannot use 'store#pushPayload' without a modelName unless your default serializer defines 'pushPayload'`, typeof serializer.pushPayload === 'function'); + } else { + payload = inputPayload; + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + serializer = this.serializerFor(normalizedModelName); + } + serializer.pushPayload(this, payload); + }, + + reloadManyArray(manyArray, internalModel, key) { + return internalModel.reloadHasMany(key); + }, + + reloadBelongsTo(belongsToProxy, internalModel, key) { + return internalModel.reloadBelongsTo(key) + }, + + _relationshipMetaFor(modelName, id, key) { + let modelClass = this.modelFor(modelName); + let relationshipsByName = get(modelClass, 'relationshipsByName'); + return relationshipsByName.get(key); + }, + + _internalModelForResource(resource) { + let internalModel; + if (resource.clientId) { + internalModel = this._newlyCreatedModelsFor(resource.type).get(resource.clientId); + } + if (!internalModel) { + internalModel = this._internalModelForId(resource.type, resource.id); + } + return internalModel; + }, + + _createModelData(modelName, id, clientId, internalModel) { + return this.createModelDataFor(modelName, id, clientId, this.modelDataWrapper); + }, + + createModelDataFor(modelName, id, clientId, storeWrapper) { + return new ModelData(modelName, id, clientId, storeWrapper, this); + }, + + modelDataFor(modelName, id, clientId) { + let internalModel = this._internalModelForId(modelName, id, clientId); + return internalModel._modelData; + }, + + _internalModelForModelData(modelData) { + let resource = modelData.getResourceIdentifier(); + return this._internalModelForId(resource.type, resource.id, resource.clientId); + }, + /** + `normalize` converts a json payload into the normalized form that + [push](#method_push) expects. + + Example + + ```js + socket.on('message', function(message) { + let modelName = message.model; + let data = message.data; + store.push(store.normalize(modelName, data)); + }); + ``` + + @method normalize + @param {String} modelName The name of the model type for this payload + @param {Object} payload + @return {Object} The normalized payload + */ + normalize(modelName, payload) { + heimdall.increment(normalize); + assert(`You need to pass a model name to the store's normalize method`, isPresent(modelName)); + assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + let serializer = this.serializerFor(normalizedModelName); + let model = this.modelFor(normalizedModelName); + return serializer.normalize(model, payload); + }, + + newClientId() { + return globalClientIdCounter++; + }, + /** + Build a brand new record for a given type, ID, and + initial data. + + @method _buildInternalModel + @private + @param {String} modelName + @param {String} id + @param {Object} data + @return {InternalModel} internal model + */ + _buildInternalModel(modelName, id, data, clientId) { + heimdall.increment(_buildInternalModel); + + assert(`You can no longer pass a modelClass as the first argument to store._buildInternalModel. Pass modelName instead.`, typeof modelName === 'string'); + + let existingInternalModel = this._existingInternalModelForId(modelName, id); + + assert(`The id ${id} has already been used with another record for modelClass '${modelName}'.`, !existingInternalModel); + + if (id === null && !clientId) { + clientId = this.newClientId(); + } + // lookupFactory should really return an object that creates + // instances with the injections applied + let internalModel = new InternalModel(modelName, id, this, data, clientId); + if (clientId) { + this._newlyCreatedModelsFor(modelName).add(internalModel, clientId); + } + + this._internalModelsFor(modelName).add(internalModel, id); + + return internalModel; + }, + + _existingInternalModelForId(modelName, id) { + let internalModel = this._internalModelsFor(modelName).get(id); + + if (internalModel && internalModel.hasScheduledDestroy()) { + // unloadRecord is async, if one attempts to unload + then sync create, + // we must ensure the unload is complete before starting the create + // The push path will take _internalModelForId() + // which will call `cancelDestroy` instead for this unload + then + // sync push scenario. Once we have true client-side + // delete signaling, we should never call destroySync + internalModel.destroySync(); + internalModel = null; + } + return internalModel; + }, + + //Called by the state machine to notify the store that the record is ready to be interacted with + recordWasLoaded(record) { + this.recordArrayManager.recordWasLoaded(record); + }, + + // ............... + // . DESTRUCTION . + // ............... + + /** + When a record is destroyed, this un-indexes it and + removes it from any record arrays so it can be GCed. + + @method _removeFromIdMap + @private + @param {InternalModel} internalModel + */ + _removeFromIdMap(internalModel) { + let recordMap = this._internalModelsFor(internalModel.modelName); + let id = internalModel.id; + + recordMap.remove(internalModel, id); + //TODO IGOR DAVID remove from client id map + }, + + // ...................... + // . PER-TYPE ADAPTERS + // ...................... + + /** + Returns an instance of the adapter for a given type. For + example, `adapterFor('person')` will return an instance of + `App.PersonAdapter`. + + If no `App.PersonAdapter` is found, this method will look + for an `App.ApplicationAdapter` (the default adapter for + your entire application). + + If no `App.ApplicationAdapter` is found, it will return + the value of the `defaultAdapter`. + + @method adapterFor + @public + @param {String} modelName + @return DS.Adapter + */ + adapterFor(modelName) { + heimdall.increment(adapterFor); + assert(`You need to pass a model name to the store's adapterFor method`, isPresent(modelName)); + assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + + let { _adapterCache } = this; + let adapter = _adapterCache[normalizedModelName]; + if (adapter) { return adapter; } + + let owner = getOwner(this); + + adapter = owner.lookup(`adapter:${normalizedModelName}`); + if (adapter !== undefined) { + set(adapter, 'store', this); + _adapterCache[normalizedModelName] = adapter; + return adapter; + } + + // no adapter found for the specific model, fallback and check for application adapter + adapter = _adapterCache.application || owner.lookup('adapter:application'); + if (adapter !== undefined) { + set(adapter, 'store', this); + _adapterCache[normalizedModelName] = adapter; + _adapterCache.application = adapter; + return adapter; + } + + // no model specific adapter or application adapter, check for an `adapter` + // property defined on the store + let adapterName = this.get('adapter'); + adapter = _adapterCache[adapterName] || owner.lookup(`adapter:${adapterName}`); + if (adapter !== undefined) { + set(adapter, 'store', this); + _adapterCache[normalizedModelName] = adapter; + _adapterCache[adapterName] = adapter; + return adapter; + } + + // final fallback, no model specific adapter, no application adapter, no + // `adapter` property on store: use json-api adapter + adapter = _adapterCache['-json-api'] || owner.lookup('adapter:-json-api'); + set(adapter, 'store', this); + _adapterCache[normalizedModelName] = adapter; + _adapterCache['-json-api'] = adapter; + return adapter; + }, + + // .............................. + // . RECORD CHANGE NOTIFICATION . + // .............................. + + /** + Returns an instance of the serializer for a given type. For + example, `serializerFor('person')` will return an instance of + `App.PersonSerializer`. + + If no `App.PersonSerializer` is found, this method will look + for an `App.ApplicationSerializer` (the default serializer for + your entire application). + + if no `App.ApplicationSerializer` is found, it will attempt + to get the `defaultSerializer` from the `PersonAdapter` + (`adapterFor('person')`). + + If a serializer cannot be found on the adapter, it will fall back + to an instance of `DS.JSONSerializer`. + + @method serializerFor + @public + @param {String} modelName the record to serialize + @return {DS.Serializer} + */ + serializerFor(modelName) { + heimdall.increment(serializerFor); + assert(`You need to pass a model name to the store's serializerFor method`, isPresent(modelName)); + assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + let normalizedModelName = normalizeModelName(modelName); + + let { _serializerCache } = this; + let serializer = _serializerCache[normalizedModelName]; + if (serializer) { return serializer; } + + let owner = getOwner(this); + + serializer = owner.lookup(`serializer:${normalizedModelName}`); + if (serializer !== undefined) { + set(serializer, 'store', this); + _serializerCache[normalizedModelName] = serializer; + return serializer; + } + + // no serializer found for the specific model, fallback and check for application serializer + serializer = _serializerCache.application || owner.lookup('serializer:application'); + if (serializer !== undefined) { + set(serializer, 'store', this); + _serializerCache[normalizedModelName] = serializer; + _serializerCache.application = serializer; + return serializer; + } + + // no model specific serializer or application serializer, check for the `defaultSerializer` + // property defined on the adapter + let adapter = this.adapterFor(modelName); + let serializerName = get(adapter, 'defaultSerializer'); + serializer = _serializerCache[serializerName] || owner.lookup(`serializer:${serializerName}`); + if (serializer !== undefined) { + set(serializer, 'store', this); + _serializerCache[normalizedModelName] = serializer; + _serializerCache[serializerName] = serializer; + return serializer; + } + + // final fallback, no model specific serializer, no application serializer, no + // `serializer` property on store: use json-api serializer + serializer = _serializerCache['-default'] || owner.lookup('serializer:-default'); + set(serializer, 'store', this); + _serializerCache[normalizedModelName] = serializer; + _serializerCache['-default'] = serializer; + + return serializer; + }, + + willDestroy() { + this._super(...arguments); + this._pushedInternalModels = null; + this.recordArrayManager.destroy(); + + this._adapterCache = null; + this._serializerCache = null; + + this.unloadAll(); + }, + + _updateRelationshipState(relationship) { + if (this._updatedRelationships.push(relationship) !== 1) { + return; + } + + this._backburner.join(() => { + this._backburner.schedule('syncRelationships', this, this._flushUpdatedRelationships); + }); + }, + + _flushUpdatedRelationships() { + let updated = this._updatedRelationships; + + for (let i = 0, l = updated.length; i < l; i++) { + updated[i].flushCanonical(); + } + + updated.length = 0; + }, + + _updateInternalModel(internalModel) { + if (this._updatedInternalModels.push(internalModel) !== 1) { + return; + } + + emberRun.schedule('actions', this, this._flushUpdatedInternalModels); + }, + + _flushUpdatedInternalModels() { + let updated = this._updatedInternalModels; + + for (let i = 0, l = updated.length; i < l; i++) { + updated[i]._triggerDeferredTriggers(); + } + + updated.length = 0; + }, + + _pushResourceIdentifier(relationship, resourceIdentifier) { + if (isNone(resourceIdentifier)) { + return; + } + + assert(`A ${relationship.internalModel.modelName} record was pushed into the store with the value of ${relationship.key} being ${inspect(resourceIdentifier)}, but ${relationship.key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(resourceIdentifier)); + + //TODO:Better asserts + return this._internalModelForId(resourceIdentifier.type, resourceIdentifier.id); + }, + + _pushResourceIdentifiers(relationship, resourceIdentifiers) { + if (isNone(resourceIdentifiers)) { + return; + } + + assert(`A ${relationship.internalModel.modelName} record was pushed into the store with the value of ${relationship.key} being '${inspect(resourceIdentifiers)}', but ${relationship.key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(resourceIdentifiers)); + + let _internalModels = new Array(resourceIdentifiers.length); + for (let i = 0; i < resourceIdentifiers.length; i++) { + _internalModels[i] = this._pushResourceIdentifier(relationship, resourceIdentifiers[i]); + } + return _internalModels; + } +}); + +// Delegation to the adapter and promise management + + + +function defaultSerializer(store) { + return store.serializerFor('application'); +} + +function _commit(adapter, store, operation, snapshot) { + let internalModel = snapshot._internalModel; + let modelName = snapshot.modelName; + let modelClass = store.modelFor(modelName); + assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter); + assert(`You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`, typeof adapter[operation] === 'function'); + + if (DEBUG) { incrementRequestCount(); } + + let promise = Promise.resolve().then(() => adapter[operation](store, modelClass, snapshot)); + let serializer = serializerForAdapter(store, adapter, modelName); + let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; + + assert(`Your adapter's '${operation}' method must return a value, but it returned 'undefined'`, promise !==undefined); + + promise = guardDestroyedStore(promise, store, label); + promise = _guard(promise, _bind(_objectIsAlive, internalModel)); + + return promise.then((adapterPayload) => { + /* + Note to future spelunkers hoping to optimize. + We rely on this `run` to create a run loop if needed + that `store._push` and `store.didSaveRecord` will both share. + + We use `join` because it is often the case that we + have an outer run loop available still from the first + call to `store._push`; + */ + store._backburner.join(() => { + let payload, data, sideloaded; + if (adapterPayload) { + payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, snapshot.id, operation); + if (payload.included) { + sideloaded = payload.included; + } + data = payload.data; + } + store.didSaveRecord(internalModel, { data }); + // seems risky, but if the tests pass might be fine? + if (sideloaded) { + store._push({ data: null, included: sideloaded }); + } + }); + + return internalModel; + }, function(error) { + if (error instanceof InvalidError) { + let errors = serializer.extractErrors(store, modelClass, error, snapshot.id); + + store.recordWasInvalid(internalModel, errors); + } else { + store.recordWasError(internalModel, error); + } + + throw error; + }, label); +} + +/** + * + * @param store + * @param cache modelFactoryCache + * @param normalizedModelName already normalized modelName + * @returns {*} + */ +function getModelFactory(store, cache, normalizedModelName) { + let factory = cache[normalizedModelName]; + + if (!factory) { + factory = _lookupModelFactory(store, normalizedModelName); + + if (!factory) { + //Support looking up mixins as base types for polymorphic relationships + factory = _modelForMixin(store, normalizedModelName); + } + + if (!factory) { + // we don't cache misses in case someone wants to register a missing model + return null; + } + + // interopt with the future + let klass = getOwner(store).factoryFor ? factory.class : factory; + assert(`'${inspect(klass)}' does not appear to be an ember-data model`, klass.isModel); + + // TODO: deprecate this + let hasOwnModelNameSet = klass.modelName && klass.hasOwnProperty('modelName'); + if (!hasOwnModelNameSet) { + klass.modelName = normalizedModelName; + } + + cache[normalizedModelName] = factory; + } + + return factory; +} + +function _lookupModelFactory(store, normalizedModelName) { + let owner = getOwner(store); + + if (owner.factoryFor) { + return owner.factoryFor(`model:${normalizedModelName}`); + } else { + return owner._lookupFactory(`model:${normalizedModelName}`); + } +} + + +/* + In case someone defined a relationship to a mixin, for example: + ``` + let Comment = DS.Model.extend({ + owner: belongsTo('commentable'. { polymorphic: true }) + }); + let Commentable = Ember.Mixin.create({ + comments: hasMany('comment') + }); + ``` + we want to look up a Commentable class which has all the necessary + relationship metadata. Thus, we look up the mixin and create a mock + DS.Model, so we can access the relationship CPs of the mixin (`comments`) + in this case +*/ +function _modelForMixin(store, normalizedModelName) { + // container.registry = 2.1 + // container._registry = 1.11 - 2.0 + // container = < 1.11 + let owner = getOwner(store); + let mixin; + + if (owner.factoryFor) { + let MaybeMixin = owner.factoryFor(`mixin:${normalizedModelName}`); + mixin = MaybeMixin && MaybeMixin.class; + } else { + mixin = owner._lookupFactory(`mixin:${normalizedModelName}`); + } + + if (mixin) { + let ModelForMixin = Model.extend(mixin); + ModelForMixin.reopenClass({ + __isMixin: true, + __mixin: mixin + }); + + //Cache the class as a model + owner.register('model:' + normalizedModelName, ModelForMixin); + } + + return _lookupModelFactory(store, normalizedModelName); +} + +export { Store }; +export default Store; diff --git a/addon/-record-data-rfc-private/system/store/common.js b/addon/-record-data-rfc-private/system/store/common.js new file mode 100644 index 00000000000..007671f5114 --- /dev/null +++ b/addon/-record-data-rfc-private/system/store/common.js @@ -0,0 +1,55 @@ +import { get } from '@ember/object'; +import { DEBUG } from '@glimmer/env'; +import Ember from 'ember'; +import { Promise } from 'rsvp'; + +const { + __bind, + __guard, + __objectIsAlive +} = heimdall.registerMonitor('system.store.common', + '_bind', + '_guard', + '_objectIsAlive' +); + +export function _bind(fn, ...args) { + heimdall.increment(__bind); + + return function() { + return fn.apply(undefined, args); + }; +} + +export function _guard(promise, test) { + heimdall.increment(__guard); + let guarded = promise['finally'](function() { + if (!test()) { + guarded._subscribers.length = 0; + } + }); + + return guarded; +} + +export function _objectIsAlive(object) { + heimdall.increment(__objectIsAlive); + return !(get(object, "isDestroyed") || get(object, "isDestroying")); +} + +let ASYNC_REQUEST_COUNT = 0; +export function incrementRequestCount() { + ASYNC_REQUEST_COUNT++; +} + +if (DEBUG) { + Ember.Test.registerWaiter(() => { + return ASYNC_REQUEST_COUNT === 0; + }); +} + +export function guardDestroyedStore(promise, store, label) { + promise = Promise.resolve(promise, label); + + return _guard(promise, () => { if (DEBUG) { ASYNC_REQUEST_COUNT--; } return _objectIsAlive(store); }); +} diff --git a/addon/-record-data-rfc-private/system/store/finders.js b/addon/-record-data-rfc-private/system/store/finders.js new file mode 100644 index 00000000000..d9923eaf29a --- /dev/null +++ b/addon/-record-data-rfc-private/system/store/finders.js @@ -0,0 +1,197 @@ +import { A } from '@ember/array'; +import { Promise } from 'rsvp'; +import { assert, warn } from '@ember/debug'; +import { DEBUG } from '@glimmer/env'; + +import { + _bind, + _guard, + _objectIsAlive, + guardDestroyedStore, + incrementRequestCount +} from "./common"; + +import { normalizeResponseHelper } from "./serializer-response"; +import { serializerForAdapter } from "./serializers"; + +function payloadIsNotBlank(adapterPayload) { + if (Array.isArray(adapterPayload)) { + return true; + } else { + return Object.keys(adapterPayload || {}).length; + } +} + +export function _find(adapter, store, modelClass, id, internalModel, options) { + if (DEBUG) { incrementRequestCount(); } + let snapshot = internalModel.createSnapshot(options); + let { modelName } = internalModel; + let promise = Promise.resolve().then(() => adapter.findRecord(store, modelClass, id, snapshot)); + let label = `DS: Handle Adapter#findRecord of '${modelName}' with id: '${id}'`; + + promise = guardDestroyedStore(promise, store, label); + + return promise.then(adapterPayload => { + assert(`You made a 'findRecord' request for a '${modelName}' with id '${id}', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, id, 'findRecord'); + assert(`Ember Data expected the primary data returned from a 'findRecord' response to be an object but instead it found an array.`, !Array.isArray(payload.data)); + + warn(`You requested a record of type '${modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead https://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, payload.data.id === id, { + id: 'ds.store.findRecord.id-mismatch' + }); + + return store._push(payload); + }, error => { + internalModel.notFound(); + if (internalModel.isEmpty()) { + internalModel.unloadRecord(); + } + + throw error; + }, `DS: Extract payload of '${modelName}'`); +} + +export function _findMany(adapter, store, modelName, ids, internalModels) { + if (DEBUG) { incrementRequestCount(); } + let snapshots = A(internalModels).invoke('createSnapshot'); + let modelClass = store.modelFor(modelName); // `adapter.findMany` gets the modelClass still + let promise = adapter.findMany(store, modelClass, ids, snapshots); + let label = `DS: Handle Adapter#findMany of '${modelName}'`; + + if (promise === undefined) { + throw new Error('adapter.findMany returned undefined, this was very likely a mistake'); + } + + promise = guardDestroyedStore(promise, store, label); + + return promise.then(adapterPayload => { + assert(`You made a 'findMany' request for '${modelName}' records with ids '[${ids}]', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findMany'); + return store._push(payload); + }, null, `DS: Extract payload of ${modelName}`); +} + +export function _findHasMany(adapter, store, internalModel, link, relationship) { + if (DEBUG) { incrementRequestCount(); } + let snapshot = internalModel.createSnapshot(); + let modelClass = store.modelFor(relationship.type); + let promise = adapter.findHasMany(store, snapshot, link, relationship); + let label = `DS: Handle Adapter#findHasMany of '${internalModel.modelName}' : '${relationship.type}'`; + + promise = guardDestroyedStore(promise, store, label); + promise = _guard(promise, _bind(_objectIsAlive, internalModel)); + + return promise.then(adapterPayload => { + assert(`You made a 'findHasMany' request for a ${internalModel.modelName}'s '${relationship.key}' relationship, using link '${link}' , but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); + let serializer = serializerForAdapter(store, adapter, relationship.type); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findHasMany'); + let internalModelArray = store._push(payload); + + internalModelArray.meta = payload.meta; + return internalModelArray; + }, null, `DS: Extract payload of '${internalModel.modelName}' : hasMany '${relationship.type}'`); +} + +export function _findBelongsTo(adapter, store, internalModel, link, relationship) { + if (DEBUG) { incrementRequestCount(); } + let snapshot = internalModel.createSnapshot(); + let modelClass = store.modelFor(relationship.type); + let promise = adapter.findBelongsTo(store, snapshot, link, relationship); + let label = `DS: Handle Adapter#findBelongsTo of ${internalModel.modelName} : ${relationship.type}`; + + promise = guardDestroyedStore(promise, store, label); + promise = _guard(promise, _bind(_objectIsAlive, internalModel)); + + return promise.then(adapterPayload => { + let serializer = serializerForAdapter(store, adapter, relationship.type); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findBelongsTo'); + + if (!payload.data) { + return null; + } + + return store._push(payload); + }, null, `DS: Extract payload of ${internalModel.modelName} : ${relationship.type}`); +} + +export function _findAll(adapter, store, modelName, sinceToken, options) { + if (DEBUG) { incrementRequestCount(); } + let modelClass = store.modelFor(modelName); // adapter.findAll depends on the class + let recordArray = store.peekAll(modelName); + let snapshotArray = recordArray._createSnapshot(options); + let promise = Promise.resolve().then(() => adapter.findAll(store, modelClass, sinceToken, snapshotArray)); + let label = "DS: Handle Adapter#findAll of " + modelClass; + + promise = guardDestroyedStore(promise, store, label); + + return promise.then(adapterPayload => { + assert(`You made a 'findAll' request for '${modelName}' records, but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findAll'); + + store._push(payload); + store._didUpdateAll(modelName); + + return recordArray; + }, null, 'DS: Extract payload of findAll ${modelName}'); +} + +export function _query(adapter, store, modelName, query, recordArray, options) { + if (DEBUG) { incrementRequestCount(); } + let modelClass = store.modelFor(modelName); // adapter.query needs the class + + let promise; + let createRecordArray = adapter.query.length > 3 || + (adapter.query.wrappedFunction && adapter.query.wrappedFunction.length > 3); + + if (createRecordArray) { + recordArray = recordArray || store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); + promise = Promise.resolve().then(() => adapter.query(store, modelClass, query, recordArray, options)); + } else { + promise = Promise.resolve().then(() => adapter.query(store, modelClass, query)); + } + + let label = `DS: Handle Adapter#query of ${modelName}`; + promise = guardDestroyedStore(promise, store, label); + + return promise.then(adapterPayload => { + let serializerToken = heimdall.start('initial-serializerFor-lookup'); + let serializer = serializerForAdapter(store, adapter, modelName); + heimdall.stop(serializerToken); + let normalizeToken = heimdall.start('finders#_query::normalizeResponseHelper'); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'query'); + heimdall.stop(normalizeToken); + let internalModels = store._push(payload); + + assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Array.isArray(internalModels)); + if (recordArray) { + recordArray._setInternalModels(internalModels, payload); + } else { + recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query, internalModels, payload); + } + + return recordArray; + }, null, `DS: Extract payload of query ${modelName}`); +} + +export function _queryRecord(adapter, store, modelName, query, options) { + if (DEBUG) { incrementRequestCount(); } + let modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class + let promise = Promise.resolve().then(() => adapter.queryRecord(store, modelClass, query, options)); + + let label = `DS: Handle Adapter#queryRecord of ${modelName}`; + promise = guardDestroyedStore(promise, store, label); + + return promise.then(adapterPayload => { + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'queryRecord'); + + assert(`Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array.`, !Array.isArray(payload.data), { + id: 'ds.store.queryRecord-array-response' + }); + + return store._push(payload); + }, null, `DS: Extract payload of queryRecord ${modelName}`); +} diff --git a/addon/-record-data-rfc-private/system/store/model-data-wrapper.js b/addon/-record-data-rfc-private/system/store/model-data-wrapper.js new file mode 100644 index 00000000000..46411b95eb0 --- /dev/null +++ b/addon/-record-data-rfc-private/system/store/model-data-wrapper.js @@ -0,0 +1,115 @@ +import { get } from '@ember/object'; + +export default class ModelDataWrapper { + constructor(store) { + this.store = store; + this._relationshipsDefCache = Object.create(null); + this._attributesDefCache = Object.create(null); + this._willUpdateManyArrays = false; + this._pendingManyArrayUpdates = null; + } + + _scheduleManyArrayUpdate(modelName, id, clientId, key) { + let pending = this._pendingManyArrayUpdates = this._pendingManyArrayUpdates || []; + pending.push(modelName, id, clientId, key); + + if (this._willUpdateManyArrays === true) { + return; + } + + this._willUpdateManyArrays = true; + let backburner = this.store._backburner; + + backburner.join(() => { + backburner.schedule('syncRelationships', this, this._flushPendingManyArrayUpdates); + }); + } + + _flushPendingManyArrayUpdates() { + if (this._willUpdateManyArrays === false) { + return; + } + + let pending = this._pendingManyArrayUpdates; + this._pendingManyArrayUpdates = []; + this._willUpdateManyArrays = false; + let store = this.store; + + for (let i = 0; i < pending.length; i += 4) { + let modelName = pending[i]; + let id = pending[i + 1]; + let clientId = pending[i + 2]; + let key = pending[i + 3]; + let internalModel = store._getInternalModelForId(modelName, id, clientId); + internalModel.notifyHasManyChange(key); + } + } + + attributesDefinitionFor(modelName) { + let attributes = this._attributesDefCache[modelName]; + if (attributes) { + return attributes; + } else { + // TODO IGOR DAVID + } + } + + relationshipsDefinitionFor(modelName) { + let relationships = this._relationshipsDefCache[modelName]; + if (!relationships) { + let modelClass = this.store.modelFor(modelName); + relationships = get(modelClass, 'relationshipsObject'); + this._relationshipsDefCache[modelName] = relationships; + } + return relationships; + } + + inverseForRelationship(modelName, key) { + let modelClass = this.store.modelFor(modelName); + return this.relationshipsDefinitionFor(modelName)[key]._inverseKey(this.store, modelClass); + } + + // TODO Igor David cleanup + inverseIsAsyncForRelationship(modelName, key) { + let modelClass = this.store.modelFor(modelName); + return this.relationshipsDefinitionFor(modelName)[key]._inverseIsAsync(this.store, modelClass); + } + + notifyPropertyChange(modelName, id, clientId, key) { + let internalModel = this.store._getInternalModelForId(modelName, id, clientId); + internalModel.notifyPropertyChange(key); + } + + notifyHasManyChange(modelName, id, clientId, key) { + this._scheduleManyArrayUpdate(modelName, id, clientId, key); + } + + notifyBelongsToChange(modelName, id, clientId, key) { + let internalModel = this.store._getInternalModelForId(modelName, id, clientId); + internalModel.notifyBelongsToChange(key); + } + + modelDataFor(modelName, id, clientId) { + return this.store.modelDataFor(modelName, id, clientId); + } + + setRecordId(modelName, id, clientId) { + this.store.setRecordId(modelName, id, clientId); + } + + isRecordInUse(modelName, id, clientId) { + let internalModel = this.store._getInternalModelForId(modelName, id, clientId); + if (!internalModel) { + return false + } + return internalModel.isRecordInUse(); + } + + disconnectRecord(modelName, id, clientId) { + let internalModel = this.store._getInternalModelForId(modelName, id, clientId); + if (internalModel) { + internalModel.destroyFromModelData(); + } + } + +} diff --git a/addon/-record-data-rfc-private/system/store/serializer-response.js b/addon/-record-data-rfc-private/system/store/serializer-response.js new file mode 100644 index 00000000000..155b13d0617 --- /dev/null +++ b/addon/-record-data-rfc-private/system/store/serializer-response.js @@ -0,0 +1,84 @@ +import { assert } from '@ember/debug'; +import { DEBUG } from '@glimmer/env'; + +/* + This is a helper method that validates a JSON API top-level document + + The format of a document is described here: + http://jsonapi.org/format/#document-top-level + + @method validateDocumentStructure + @param {Object} doc JSON API document + @return {array} An array of errors found in the document structure +*/ +export function validateDocumentStructure(doc) { + let errors = []; + if (!doc || typeof doc !== 'object') { + errors.push('Top level of a JSON API document must be an object'); + } else { + if (!('data' in doc) && + !('errors' in doc) && + !('meta' in doc)) { + errors.push('One or more of the following keys must be present: "data", "errors", "meta".'); + } else { + if (('data' in doc) && ('errors' in doc)) { + errors.push('Top level keys "errors" and "data" cannot both be present in a JSON API document'); + } + } + if ('data' in doc) { + if (!(doc.data === null || Array.isArray(doc.data) || typeof doc.data === 'object')) { + errors.push('data must be null, an object, or an array'); + } + } + if ('meta' in doc) { + if (typeof doc.meta !== 'object') { + errors.push('meta must be an object'); + } + } + if ('errors' in doc) { + if (!Array.isArray(doc.errors)) { + errors.push('errors must be an array'); + } + } + if ('links' in doc) { + if (typeof doc.links !== 'object') { + errors.push('links must be an object'); + } + } + if ('jsonapi' in doc) { + if (typeof doc.jsonapi !== 'object') { + errors.push('jsonapi must be an object'); + } + } + if ('included' in doc) { + if (typeof doc.included !== 'object') { + errors.push('included must be an array'); + } + } + } + + return errors; +} + +/* + This is a helper method that always returns a JSON-API Document. + + @method normalizeResponseHelper + @param {DS.Serializer} serializer + @param {DS.Store} store + @param {subclass of DS.Model} modelClass + @param {Object} payload + @param {String|Number} id + @param {String} requestType + @return {Object} JSON-API Document +*/ +export function normalizeResponseHelper(serializer, store, modelClass, payload, id, requestType) { + let normalizedResponse = serializer.normalizeResponse(store, modelClass, payload, id, requestType); + let validationErrors = []; + if (DEBUG) { + validationErrors = validateDocumentStructure(normalizedResponse); + } + assert(`normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join('\n\t* ')}`, validationErrors.length === 0); + + return normalizedResponse; +} diff --git a/addon/-record-data-rfc-private/system/store/serializers.js b/addon/-record-data-rfc-private/system/store/serializers.js new file mode 100644 index 00000000000..71ca0829809 --- /dev/null +++ b/addon/-record-data-rfc-private/system/store/serializers.js @@ -0,0 +1,15 @@ +export function serializerForAdapter(store, adapter, modelName) { + let serializer = adapter.serializer; + + if (serializer === undefined) { + serializer = store.serializerFor(modelName); + } + + if (serializer === null || serializer === undefined) { + serializer = { + extract(store, type, payload) { return payload; } + }; + } + + return serializer; +} diff --git a/addon/-record-data-rfc-private/utils.js b/addon/-record-data-rfc-private/utils.js new file mode 100644 index 00000000000..234af6842fa --- /dev/null +++ b/addon/-record-data-rfc-private/utils.js @@ -0,0 +1,47 @@ +import { getOwner as emberGetOwner } from '@ember/application'; +import { get } from '@ember/object'; + +/* + Check if the passed model has a `type` attribute or a relationship named `type`. + + @method modelHasAttributeOrRelationshipNamedType + @param modelClass + */ +function modelHasAttributeOrRelationshipNamedType(modelClass) { + return get(modelClass, 'attributes').has('type') || get(modelClass, 'relationshipsByName').has('type'); +} + +/* + ember-container-inject-owner is a new feature in Ember 2.3 that finally provides a public + API for looking items up. This function serves as a super simple polyfill to avoid + triggering deprecations. + */ +function getOwner(context) { + let owner; + + if (emberGetOwner) { + owner = emberGetOwner(context); + } else if (context.container) { + owner = context.container; + } + + if (owner && owner.lookupFactory && !owner._lookupFactory) { + // `owner` is a container, we are just making this work + owner._lookupFactory = function() { + return owner.lookupFactory(...arguments); + } + + owner.register = function() { + let registry = owner.registry || owner._registry || owner; + + return registry.register(...arguments); + }; + } + + return owner; +} + +export { + modelHasAttributeOrRelationshipNamedType, + getOwner +}; diff --git a/addon/-record-data-rfc-private/utils/parse-response-headers.js b/addon/-record-data-rfc-private/utils/parse-response-headers.js new file mode 100644 index 00000000000..3e02ab16fc8 --- /dev/null +++ b/addon/-record-data-rfc-private/utils/parse-response-headers.js @@ -0,0 +1,36 @@ +const CLRF = '\u000d\u000a'; + +export default function parseResponseHeaders(headersString) { + let headers = Object.create(null); + + if (!headersString) { + return headers; + } + + let headerPairs = headersString.split(CLRF); + for (let i = 0; i < headerPairs.length; i++) { + let header = headerPairs[i]; + let j = 0; + let foundSep = false; + + for (; j < header.length; j++) { + if (header.charCodeAt(j) === 58 /* ':' */) { + foundSep = true; + break; + } + } + + if (foundSep === false) { + continue; + } + + let field = header.substring(0, j).trim(); + let value = header.substring(j + 1, header.length).trim(); + + if (value) { + headers[field] = value; + } + } + + return headers; +} diff --git a/addon/attr.js b/addon/attr.js index ddbb80e3724..fbaf420e5a9 100644 --- a/addon/attr.js +++ b/addon/attr.js @@ -1,137 +1 @@ -import { computed } from '@ember/object'; -import { assert } from '@ember/debug'; - -/** - @module ember-data -*/ - -function getDefaultValue(record, options, key) { - if (typeof options.defaultValue === 'function') { - return options.defaultValue.apply(null, arguments); - } else { - let defaultValue = options.defaultValue; - assert(`Non primitive defaultValues are not supported because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.`, - typeof defaultValue !== 'object' || defaultValue === null); - return defaultValue; - } -} - -function hasValue(record, key) { - return key in record._attributes || - key in record._inFlightAttributes || - key in record._data; -} - -/** - `DS.attr` defines an attribute on a [DS.Model](/api/data/classes/DS.Model.html). - By default, attributes are passed through as-is, however you can specify an - optional type to have the value automatically transformed. - Ember Data ships with four basic transform types: `string`, `number`, - `boolean` and `date`. You can define your own transforms by subclassing - [DS.Transform](/api/data/classes/DS.Transform.html). - - Note that you cannot use `attr` to define an attribute of `id`. - - `DS.attr` takes an optional hash as a second parameter, currently - supported options are: - - - `defaultValue`: Pass a string or a function to be called to set the attribute - to a default value if none is supplied. - - Example - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - username: DS.attr('string'), - email: DS.attr('string'), - verified: DS.attr('boolean', { defaultValue: false }) - }); - ``` - - Default value can also be a function. This is useful it you want to return - a new object for each attribute. - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - username: DS.attr('string'), - email: DS.attr('string'), - settings: DS.attr({ - defaultValue() { - return {}; - } - }) - }); - ``` - - The `options` hash is passed as second argument to a transforms' - `serialize` and `deserialize` method. This allows to configure a - transformation and adapt the corresponding value, based on the config: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - text: DS.attr('text', { - uppercase: true - }) - }); - ``` - - ```app/transforms/text.js - import DS from 'ember-data'; - - export default DS.Transform.extend({ - serialize(value, options) { - if (options.uppercase) { - return value.toUpperCase(); - } - - return value; - }, - - deserialize(value) { - return value; - } - }) - ``` - - @namespace - @method attr - @for DS - @param {String|Object} type the attribute type - @param {Object} options a hash of options - @return {Attribute} -*/ - -export default function attr(type, options) { - if (typeof type === 'object') { - options = type; - type = undefined; - } else { - options = options || {}; - } - - let meta = { - type: type, - isAttribute: true, - options: options - }; - - return computed({ - get(key) { - let internalModel = this._internalModel; - if (hasValue(internalModel, key)) { - return internalModel.getAttributeValue(key); - } else { - return getDefaultValue(this, options, key); - } - }, - set(key, value) { - return this._internalModel.setDirtyAttribute(key, value); - } - }).meta(meta); -} +export { attr as default } from './-private'; diff --git a/ember-cli-build.js b/ember-cli-build.js index e7d419c8bb8..d2b879664e8 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -1,10 +1,11 @@ +"use strict"; /* eslint-env node */ -var EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); -var merge = require('broccoli-merge-trees'); -var yuidoc = require('./lib/yuidoc'); +const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); +const merge = require('broccoli-merge-trees'); +const yuidoc = require('./lib/yuidoc'); module.exports = function(defaults) { - var app = new EmberAddon(defaults, {}); + let app = new EmberAddon(defaults, {}); /* This build file specifies the options for the dummy test app of this @@ -13,7 +14,7 @@ module.exports = function(defaults) { behave. You most likely want to be modifying `./index.js` or app's build file */ - var appTree = app.toTree(); + let appTree = app.toTree(); if (process.env.EMBER_ENV === 'production') { return merge([appTree, yuidoc()]); diff --git a/index.js b/index.js index 284dfdf591d..8fb58cb5d27 100644 --- a/index.js +++ b/index.js @@ -2,28 +2,31 @@ 'use strict'; const path = require('path'); -const SilentError = require('silent-error'); const Funnel = require('broccoli-funnel'); const Rollup = require('broccoli-rollup'); const merge = require('broccoli-merge-trees'); -const semver = require('semver'); const version = require('./lib/version'); const BroccoliDebug = require('broccoli-debug'); const calculateCacheKeyForTree = require('calculate-cache-key-for-tree'); // allow toggling of heimdall instrumentation let INSTRUMENT_HEIMDALL = false; +let USE_RECORD_DATA_RFC = false; let args = process.argv; for (let i = 1; i < args.length; i++) { if (args[i] === '--instrument') { INSTRUMENT_HEIMDALL = true; - break; + if (USE_RECORD_DATA_RFC) { + break; + } + } else if (args[i] === '--record-data-rfc-build') { + USE_RECORD_DATA_RFC = true; + if (INSTRUMENT_HEIMDALL) { + break; + } } } -const NOOP_TREE = function(dir) { - return { inputTree: dir, rebuild() { return []; } }; -}; process.env.INSTRUMENT_HEIMDALL = INSTRUMENT_HEIMDALL; @@ -42,7 +45,7 @@ module.exports = { name: 'ember-data', _prodLikeWarning() { - let emberEnv = process.env.EMBER_ENV + let emberEnv = process.env.EMBER_ENV; if(emberEnv !== 'production' && /production/.test(emberEnv)) { this._warn(`Production-like values for EMBER_ENV are deprecated (your EMBER_ENV is "${emberEnv}") and support will be removed in Ember Data 4.0.0. If using ember-cli-deploy, please configure your build using 'production'. Otherwise please set your EMBER_ENV to 'production' for production builds.`); } @@ -75,68 +78,22 @@ module.exports = { this._super.init && this._super.init.apply(this, arguments); this._prodLikeWarning(); this.debugTree = BroccoliDebug.buildDebugCallback('ember-data'); + this.options = this.options || {}; + }, - let bowerDeps = this.project.bowerDependencies(); - - let VersionChecker = require('ember-cli-version-checker'); - let options = this.options = this.options || {}; - - let checker = new VersionChecker(this); - // prevent errors when ember-cli-shims is no longer required - let shims = bowerDeps['ember-cli-shims'] && checker.for('ember-cli-shims', 'bower'); - - let version = require('./package').version; - - if (process.env.EMBER_DATA_SKIP_VERSION_CHECKING_DO_NOT_USE_THIS_ENV_VARIABLE) { - // Skip for node tests as we can't currently override the version of ember-cli-shims - // before the test helpers run. - return; - } - - let hasShims = !!shims; - let shimsHasEmberDataShims = hasShims && shims.satisfies('< 0.1.0'); - let emberDataNPMWithShimsIncluded = semver.satisfies(version, '^2.3.0-beta.3'); - - if (bowerDeps['ember-data']) { - this._warn('Please remove `ember-data` from `bower.json`. As of Ember Data 2.3.0, only the NPM package is needed. If you need an ' + - 'earlier version of ember-data (< 2.3.0), you can leave this unchanged for now, but we strongly suggest you upgrade your version of Ember Data ' + - 'as soon as possible.'); - this._forceBowerUsage = true; - - let emberDataBower = checker.for('ember-data', 'bower'); - let emberDataBowerWithShimsIncluded = emberDataBower.satisfies('>= 2.3.0-beta.3'); - - if (hasShims && !shimsHasEmberDataShims && !emberDataBowerWithShimsIncluded) { - throw new SilentError('Using a version of ember-cli-shims greater than or equal to 0.1.0 will cause errors while loading Ember Data < 2.3.0-beta.3 Please update ember-cli-shims from ' + shims.version + ' to 0.0.6'); - } - - if (hasShims && shimsHasEmberDataShims && !emberDataBowerWithShimsIncluded) { - throw new SilentError('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3.0-beta.3+. Please update ember-cli-shims from ' + shims.version + ' to 0.1.0.'); - } - - } else { - // NPM only, but ember-cli-shims does not match - if (hasShims && shimsHasEmberDataShims && emberDataNPMWithShimsIncluded) { - throw new SilentError('Using a version of ember-cli-shims prior to 0.1.0 will cause errors while loading Ember Data 2.3.0-beta.3+. Please update ember-cli-shims from ' + shims.version + ' to 0.1.0.'); + config() { + return { + emberData: { + enableRecordDataRFCBuild: USE_RECORD_DATA_RFC } - } + }; }, blueprintsPath() { return path.join(__dirname, 'blueprints'); }, - treeForApp(dir) { - if (this._forceBowerUsage) { return NOOP_TREE(dir); } - - // this._super.treeForApp is undefined in ember-cli (1.13) for some reason. - // TODO: investigate why treeForApp isn't on _super - return dir; - }, - treeForAddon(tree) { - if (this._forceBowerUsage) { return NOOP_TREE(tree); } - tree = this.debugTree(tree, 'input'); let babel = this.addons.find(addon => addon.name === 'ember-cli-babel'); @@ -146,10 +103,20 @@ module.exports = { version() // compile the VERSION into the build ]); - let withPrivate = new Funnel(tree, { include: ['-private/**'] }); + let withPrivate; + + if (USE_RECORD_DATA_RFC) { + withPrivate = new Funnel(tree, { + include: ['-record-data-rfc-private/**'] + }); + } else { + withPrivate = new Funnel(tree, { include: ['-private/**'] }); + } + let withoutPrivate = new Funnel(treeWithVersion, { exclude: [ '-private', + '-record-data-rfc-private', isProductionEnv() && !isInstrumentedBuild() ? '-debug' : false ].filter(Boolean), @@ -172,9 +139,14 @@ module.exports = { privateTree = new Rollup(privateTree, { rollup: { - entry: '-private/index.js', - targets: [ - { dest: 'ember-data/-private.js', format: babel.shouldCompileModules() ? 'amd' : 'es', moduleId: 'ember-data/-private' } + input: USE_RECORD_DATA_RFC ? '-record-data-rfc-private/index.js' : '-private/index.js', + output: [ + { + file: 'ember-data/-private.js', + format: babel.shouldCompileModules() ? 'amd' : 'es', + amd: { id: 'ember-data/-private' }, + exports: 'named', + } ], external: [ 'ember', @@ -183,7 +155,7 @@ module.exports = { 'ember-data/-debug', 'ember-data/adapters/errors', '@ember/ordered-set' - ] + ], // cache: true|false Defaults to true } }); @@ -229,13 +201,6 @@ module.exports = { this._super.included.apply(this, arguments); this._setupBabelOptions(); - - if (this._forceBowerUsage) { - this.app.import({ - development: app.bowerDirectory + '/ember-data/ember-data.js', - production: app.bowerDirectory + '/ember-data/ember-data.prod.js' - }); - } }, cacheKeyForTree(treeType) { diff --git a/package.json b/package.json index 4a352fc86ed..9ee9d6d90cb 100644 --- a/package.json +++ b/package.json @@ -11,11 +11,11 @@ "build": "ember build", "build:production": "ember build --environment=production", "start": "ember server", - "test": "ember test", + "test": "ember test && ember test --record-data-rfc-build", "test:all": "ember try:each", "test:node": "node node-tests/nodetest-runner.js", - "test:production": "ember test --environment=production", - "test:optional-features": "ember test --environment=test-optional-features" + "test:production": "ember test -e production && ember test -e production --record-data-rfc-build", + "test:optional-features": "ember test -e test-optional-features && ember test -e test-optional-features --record-data-rfc-build" }, "author": "", "license": "MIT", @@ -33,7 +33,7 @@ "broccoli-file-creator": "^1.0.0", "broccoli-funnel": "^1.2.0", "broccoli-merge-trees": "^2.0.0", - "broccoli-rollup": "^1.2.0", + "broccoli-rollup": "^2.1.0", "calculate-cache-key-for-tree": "^1.1.0", "chalk": "^1.1.1", "ember-cli-babel": "^6.8.2", @@ -87,7 +87,7 @@ "ember-cli-shims": "^1.0.2", "ember-cli-sri": "^2.1.0", "ember-cli-test-loader": "^1.1.0", - "ember-cli-uglify": "^1.2.0", + "ember-cli-uglify": "2.0.0-beta.1", "ember-disable-prototype-extensions": "^1.1.0", "ember-disable-proxy-controllers": "^1.0.0", "ember-export-application-global": "^1.0.5", @@ -110,7 +110,7 @@ "testem": "^1.15.0" }, "engines": { - "node": ">= 4.0.0" + "node": ">= 6.0.0" }, "keywords": [ "ember-addon" diff --git a/tests/helpers/test-in-debug.js b/tests/helpers/test-in-debug.js index 949b64daac2..561b1d4cbae 100644 --- a/tests/helpers/test-in-debug.js +++ b/tests/helpers/test-in-debug.js @@ -1,10 +1,31 @@ import { DEBUG } from '@glimmer/env'; import { test, skip } from 'qunit'; +import config from 'dummy/config/environment'; -export default function testInDebug() { +const IS_RECORD_DATA = config.emberData.enableRecordDataRFCBuild; + +export function testInDebug() { if (DEBUG) { test(...arguments); } else { skip(...arguments); } } + +export default testInDebug; + +export function testRecordData() { + if (IS_RECORD_DATA) { + test(...arguments); + } else { + skip(...arguments); + } +} + +export function skipRecordData() { + if (IS_RECORD_DATA) { + skip(...arguments); + } else { + test(...arguments); + } +} diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index eb9c7159065..25c57d81dd7 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -56,10 +56,15 @@ module('integration/inverse_test - inverseFor', { }); test("Finds the inverse when there is only one possible available", function(assert) { - assert.deepEqual(Job.inverseFor('user', store), { + let inverseDefinition = Job.inverseFor('user', store); + + assert.deepEqual(inverseDefinition, { type: User, name: 'job', - kind: 'belongsTo' + kind: 'belongsTo', + options: { + async: false + } }, 'Gets correct type, name and kind'); }); @@ -75,13 +80,20 @@ test("Finds the inverse when only one side has defined it manually", function(as assert.deepEqual(Job.inverseFor('owner', store), { type: User, //the model's type name: 'previousJob', //the models relationship key - kind: 'belongsTo' + kind: 'belongsTo', + options: { + async: false + } }, 'Gets correct type, name and kind'); assert.deepEqual(User.inverseFor('previousJob', store), { type: Job, //the model's type name: 'owner', //the models relationship key - kind: 'belongsTo' + kind: 'belongsTo', + options: { + inverse: 'previousJob', + async: false + } }, 'Gets correct type, name and kind'); }); diff --git a/tests/integration/records/relationship-changes-test.js b/tests/integration/records/relationship-changes-test.js index 5547164a3d2..8385abd3a81 100644 --- a/tests/integration/records/relationship-changes-test.js +++ b/tests/integration/records/relationship-changes-test.js @@ -890,7 +890,6 @@ test('Calling push with updated belongsTo relationship trigger observer', functi }] }); - // as with all cps, observers don't fire if the cp isn't lazy. post.get('author'); post.addObserver('author', function() { diff --git a/tests/integration/records/rematerialize-test.js b/tests/integration/records/rematerialize-test.js index 19e72905cb6..6375ab15f3e 100644 --- a/tests/integration/records/rematerialize-test.js +++ b/tests/integration/records/rematerialize-test.js @@ -167,13 +167,14 @@ test("an async has many relationship to an unloaded record can restore that reco } }; + let adapterCalls = 0; env.adapter.findRecord = function(store, model, param) { - assert.ok('adapter called'); + assert.ok(true, `adapter called ${++adapterCalls}x`); let data; if (param === '1') { data = deepCopy(BOAT_ONE); - } else if (param === '1') { + } else if (param === '2') { data = deepCopy(BOAT_TWO); } else { throw new Error(`404: no such boat with id=${param}`); @@ -216,21 +217,23 @@ test("an async has many relationship to an unloaded record can restore that reco let adam = env.store.peekRecord('person', '1'); let boaty = env.store.peekRecord('boat', '1'); + // assert our initial cache state assert.equal(env.store.hasRecordForId('person', '1'), true, 'The person is in the store'); assert.equal(env.store._internalModelsFor('person').has('1'), true, 'The person internalModel is loaded'); assert.equal(env.store.hasRecordForId('boat', '1'), true, 'The boat is in the store'); assert.equal(env.store._internalModelsFor('boat').has('1'), true, 'The boat internalModel is loaded'); let boats = run(() => adam.get('boats')); - assert.equal(boats.get('length'), 2, 'Before unloading boats.length is correct'); run(() => boaty.unloadRecord()); assert.equal(boats.get('length'), 1, 'after unloading boats.length is correct'); + // assert our new cache state assert.equal(env.store.hasRecordForId('boat', '1'), false, 'The boat is unloaded'); assert.equal(env.store._internalModelsFor('boat').has('1'), true, 'The boat internalModel is retained'); + // cause a rematerialization, this should also cause us to fetch boat '1' again boats = run(() => adam.get('boats')); let rematerializedBoaty = boats.objectAt(1); @@ -238,7 +241,7 @@ test("an async has many relationship to an unloaded record can restore that reco assert.equal(adam.get('boats.length'), 2, 'boats.length correct after rematerialization'); assert.equal(rematerializedBoaty.get('id'), '1', 'Rematerialized boat has the right id'); assert.equal(rematerializedBoaty.get('name'), 'Boaty McBoatface', 'Rematerialized boat has the right name'); - assert.notEqual(rematerializedBoaty, boaty, 'the boat is rematerialized, not recycled'); + assert.ok(rematerializedBoaty !== boaty, 'the boat is rematerialized, not recycled'); assert.equal(env.store.hasRecordForId('boat', '1'), true, 'The boat is loaded'); assert.equal(env.store._internalModelsFor('boat').has('1'), true, 'The boat internalModel is retained'); diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 28589232515..0b91dddd2d1 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -6,6 +6,7 @@ import { run } from '@ember/runloop'; import { module, test } from 'qunit'; import DS from 'ember-data'; import setupStore from 'dummy/tests/helpers/store'; +import { testRecordData, skipRecordData } from 'dummy/tests/helpers/test-in-debug'; function idsFromOrderedSet(set) { return set.list.map(i => i.id); @@ -150,30 +151,21 @@ test('can unload a single record', function(assert) { adam = env.store.peekRecord('person', 1); }); - assert.equal(env.store.peekAll('person').get('length'), 1, 'one person record loaded'); assert.equal(env.store._internalModelsFor('person').length, 1, 'one person internalModel loaded'); - let relPayloads = env.store._relationshipsPayloads; - - assert.equal(relPayloads.get('person', 1, 'cars').data.length, 1, 'one car relationship payload is cached'); - assert.equal(relPayloads.get('person', 1, 'boats').data.length, 1, 'one boat relationship payload is cached'); - run(function() { adam.unloadRecord(); }); assert.equal(env.store.peekAll('person').get('length'), 0, 'no person records'); assert.equal(env.store._internalModelsFor('person').length, 0, 'no person internalModels'); - - assert.equal(relPayloads.get('person', 1, 'cars'), null, 'no car relationship payload is cached'); - assert.equal(relPayloads.get('person', 1, 'boats'), null, 'no boat relationship payload is cached'); }); test('can unload all records for a given type', function(assert) { - assert.expect(11); + assert.expect(10); - let adam, bob, dudu; + let adam, bob, dudu, car; run(function() { env.store.push({ data: [{ @@ -193,7 +185,7 @@ test('can unload all records for a given type', function(assert) { adam = env.store.peekRecord('person', 1); bob = env.store.peekRecord('person', 2); - env.store.push({ + car = env.store.push({ data: { type: 'car', id: '1', @@ -216,11 +208,8 @@ test('can unload all records for a given type', function(assert) { assert.equal(env.store.peekAll('car').get('length'), 1, 'one car record loaded'); assert.equal(env.store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); - let relPayloads = env.store._relationshipsPayloads; - - assert.equal(relPayloads.get('car', 1, 'person').data.id, 1, 'car - person payload is loaded'); - run(function() { + car.get('person'); env.store.unloadAll('person'); }); @@ -241,8 +230,26 @@ test('can unload all records for a given type', function(assert) { }); }); - assert.equal(env.store.peekRecord('car', 1).get('person.id'), '1', 'Inverse can load relationship after the record is unloaded'); - assert.equal(env.store.peekRecord('car', 1).get('person.name'), 'Richard II', 'Inverse can load relationship after the record is unloaded'); + car = env.store.peekRecord('car', 1); + let person = car.get('person'); + + assert.ok(!!car, 'We have a car'); + assert.ok(!person, 'We dont have a person'); + + /* + @runspired believes these asserts were incorrect on master. + Basically, we intentionally treat unload on a sync belongsTo as client-side + delete bc "bad reason" of legacy support for the mis-use of unloadRecord. + + Because of this, there should be no way to resurrect the relationship without + receiving new relationship info which does not occur in this test. + + He checked how master manages to do this, and discovered bad things. TL;DR + because the `person` relationship is never materialized, it's state was + not cleared on unload, and thus the client-side delete never happened as intended. + */ + // assert.equal(person.get('id'), '1', 'Inverse can load relationship after the record is unloaded'); + // assert.equal(person.get('name'), 'Richard II', 'Inverse can load relationship after the record is unloaded'); }); test('can unload all records', function(assert) { @@ -608,7 +615,7 @@ test('(regression) unloadRecord followed by push in the same run-loop', function assert.ok(yaBoatInternalModel === initialBoatInternalModel, 'after an unloadRecord, subsequent same-loop push results in the same InternalModel'); }); -test('unloading a disconnected subgraph clears the relevant internal models', function(assert) { +testRecordData('unloading a disconnected subgraph clears the relevant internal models', function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; run(() => { @@ -679,25 +686,133 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu assert.equal(env.store.hasRecordForId('boat', 1), true); assert.equal(env.store.hasRecordForId('boat', 2), true); - let relPayloads = env.store._relationshipsPayloads; + let checkOrphanCalls = 0; + let cleanupOrphanCalls = 0; - assert.equal(relPayloads.get('person', 1, 'boats').data.length, 2, 'person - boats relationship payload loaded'); + function countOrphanCalls(record) { + let internalModel = record._internalModel; + let origCheck = internalModel._checkForOrphanedInternalModels; + + let modelData = internalModel._modelData; + let origCleanup = modelData._cleanupOrphanedModelDatas; + + internalModel._checkForOrphanedInternalModels = function () { + ++checkOrphanCalls; + return origCheck.apply(record._internalModel, arguments); + }; + + modelData._cleanupOrphanedModelDatas = function () { + ++cleanupOrphanCalls; + return origCleanup.apply(modelData, arguments); + }; + } + countOrphanCalls(env.store.peekRecord('person', 1)); + countOrphanCalls(env.store.peekRecord('boat', 1)); + countOrphanCalls(env.store.peekRecord('boat', 2)); + + // make sure relationships are initialized + return env.store.peekRecord('person', 1).get('boats').then(() => { + run(() => { + env.store.peekRecord('person', 1).unloadRecord(); + env.store.peekRecord('boat', 1).unloadRecord(); + env.store.peekRecord('boat', 2).unloadRecord(); + }); + + assert.equal(env.store._internalModelsFor('person').models.length, 0); + assert.equal(env.store._internalModelsFor('boat').models.length, 0); + + assert.equal(checkOrphanCalls, 3, 'each internalModel checks for cleanup'); + assert.equal(cleanupOrphanCalls, 3, 'each model data tries to cleanup'); + }); +}); + +skipRecordData('unloading a disconnected subgraph clears the relevant internal models', function(assert) { + env.adapter.shouldBackgroundReloadRecord = () => false; + + run(() => { + env.store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Could be Anybody' + }, + relationships: { + boats: { + data: [ + { type: 'boat', id: '1' }, + { type: 'boat', id: '2' } + ] + } + } + } + }); + }); + + run(() => { + env.store.push({ + data: { + type: 'boat', + id: '1', + attributes: { + name: 'Boaty McBoatface' + }, + relationships: { + person: { + data: { type: 'person', id: '1' } + } + } + } + }); + }); + + run(() => { + env.store.push({ + data: { + type: 'boat', + id: '2', + attributes: { + name: 'The jackson' + }, + relationships: { + person: { + data: { type: 'person', id: '1' } + } + } + } + }); + }); + + assert.equal( + env.store._internalModelsFor('person').models.length, + 1, + 'one person record is loaded' + ); + assert.equal( + env.store._internalModelsFor('boat').models.length, + 2, + 'two boat records are loaded' + ); + assert.equal(env.store.hasRecordForId('person', 1), true); + assert.equal(env.store.hasRecordForId('boat', 1), true); + assert.equal(env.store.hasRecordForId('boat', 2), true); let checkOrphanCalls = 0; let cleanupOrphanCalls = 0; function countOrphanCalls(record) { - let origCheck = record._internalModel._checkForOrphanedInternalModels; - let origCleanup = record._internalModel._cleanupOrphanedInternalModels; + let internalModel = record._internalModel; + let origCheck = internalModel._checkForOrphanedInternalModels; + let origCleanup = internalModel._cleanupOrphanedInternalModels; - record._internalModel._checkForOrphanedInternalModels = function () { + internalModel._checkForOrphanedInternalModels = function () { ++checkOrphanCalls; return origCheck.apply(record._internalModel, arguments); }; - record._internalModel._cleanupOrphanedInternalModels = function () { + internalModel._cleanupOrphanedInternalModels = function () { ++cleanupOrphanCalls; - return origCleanup.apply(record._internalModel, arguments); + return origCleanup.apply(internalModel, arguments); }; } countOrphanCalls(env.store.peekRecord('person', 1)); @@ -716,9 +831,7 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu assert.equal(env.store._internalModelsFor('boat').models.length, 0); assert.equal(checkOrphanCalls, 3, 'each internalModel checks for cleanup'); - assert.equal(cleanupOrphanCalls, 1, 'cleanup only happens once'); - - assert.equal(relPayloads.get('person', 1, 'boats'), null, 'person - boats relationship payload unloaded'); + assert.equal(cleanupOrphanCalls, 1, 'each model data tries to cleanup'); }); }); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 616788fe09e..57817720e18 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1567,7 +1567,7 @@ testInDebug("A belongsTo relationship warns if malformatted data is pushed into }); chapter.get('book'); }); - }, /expected the data for the book relationship on a to be in a JSON API format/); + }, /Encountered a relationship identifier without a type for the belongsTo relationship 'book' on , expected a json-api identifier with type 'book'/); }); test("belongsTo relationship with links doesn't trigger extra change notifications - #4942", function(assert) { diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index f73db1f5c7d..552eefbe07f 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -35,7 +35,6 @@ module("integration/relationships/has_many - Has-Many Relationships", { messages: hasMany('message', { polymorphic: true, async: false }), contacts: hasMany('user', { inverse: null, async: false }) }); - User.reopenClass({ toString: () => 'User' }); Contact = DS.Model.extend({ user: belongsTo('user', { async: false }) @@ -1864,11 +1863,16 @@ test("dual non-async HM <-> BT", function(assert) { }); test("When an unloaded record is added to the hasMany, it gets fetched once the hasMany is accessed even if the hasMany has been already fetched", function(assert) { + assert.expect(6); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + let findManyCalls = 0; + let findRecordCalls = 0; + env.adapter.findMany = function(store, type, ids, snapshots) { + assert.ok(true, `findMany called ${++findManyCalls}x`); return resolve({ data: [ { id: 1, type: 'comment', attributes: { body: 'first' } }, { id: 2, type: 'comment', attributes: { body: 'second' } } @@ -1876,6 +1880,7 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the }; env.adapter.findRecord = function(store, type, id, snapshot) { + assert.ok(true, `findRecord called ${++findRecordCalls}x`); return resolve({ data: { id: 3, type: 'comment', attributes: { body: 'third' } } }); }; let post; @@ -1902,6 +1907,7 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the return post.get('comments').then(fetchedComments => { assert.equal(fetchedComments.get('length'), 2, 'comments fetched successfully'); assert.equal(fetchedComments.objectAt(0).get('body'), 'first', 'first comment loaded successfully'); + env.store.push({ data: { type: 'post', @@ -2478,10 +2484,6 @@ test("Relationship.clear removes all records correctly", function(assert) { }); run(() => { - // unclear what the semantics of clearing a yet to be created relationship - // ought to be. - env.store.peekAll('comment').mapBy('post'); - post._internalModel._relationships.get('comments').clear(); let comments = A(env.store.peekAll('comment')); assert.deepEqual(comments.mapBy('post'), [null, null, null]); diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index 088b4e9600e..5483d77e124 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -2,7 +2,7 @@ import { run } from '@ember/runloop'; import { createStore } from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; -import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import { testInDebug, testRecordData, skipRecordData } from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; import DS from 'ember-data'; @@ -467,7 +467,7 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a bel }, /We found no inverse relationships by the name of 'testPost' on the 'user' model/); }); -test("inverseFor short-circuits when inverse is null", function(assert) { +skipRecordData("inverseFor short-circuits when inverse is null", function(assert) { assert.expect(4); Post = DS.Model.extend({ comments: DS.hasMany('comment', { async: false, inverse: null }) @@ -604,6 +604,143 @@ test("inverseFor short-circuits when inverse is null", function(assert) { }); }); +testRecordData("inverseFor is only called when inverse is not null", function(assert) { + assert.expect(2); + Post = DS.Model.extend({ + comments: DS.hasMany('comment', { async: false, inverse: null }) + }); + + Comment = DS.Model.extend({ + post: DS.belongsTo('post', { async: false, inverse: null }) + }); + + User = DS.Model.extend({ + messages: DS.hasMany('message', { async: false, inverse: 'user' }) + }); + + Message = DS.Model.extend({ + user: DS.belongsTo('user', { async: false, inverse: 'messages' }) + }); + + var env = setupStore({ post: Post, comment: Comment, user: User, message: Message }); + var store = env.store; + + Post.inverseFor = function() { + assert.notOk(true, 'Post model inverseFor is not called'); + }; + + Comment.inverseFor = function() { + assert.notOk(true, 'Comment model inverseFor is not called'); + }; + + Message.inverseFor = function() { + assert.ok(true, 'Message model inverseFor is called'); + }; + + User.inverseFor = function() { + assert.ok(true, 'User model inverseFor is called'); + }; + + run(function() { + store.push({ + data: { + id: '1', + type: 'post', + relationships: { + comments: { + data: [ + { + id: '1', + type: 'comment' + }, + { + id: '2', + type: 'comment' + } + ] + } + } + } + }); + store.push({ + data: [ + { + id: '1', + type: 'comment', + relationships: { + post: { + data: { + id: '1', + type: 'post' + } + } + } + }, + { + id: '2', + type: 'comment', + relationships: { + post: { + data: { + id: '1', + type: 'post' + } + } + } + } + ] + }); + store.push({ + data: { + id: '1', + type: 'user', + relationships: { + messages: { + data: [ + { + id: '1', + type: 'message' + }, + { + id: '2', + type: 'message' + } + ] + } + } + } + }); + store.push({ + data: [ + { + id: '1', + type: 'message', + relationships: { + user: { + data: { + id: '1', + type: 'user' + } + } + } + }, + { + id: '2', + type: 'message', + relationships: { + post: { + data: { + id: '1', + type: 'user' + } + } + } + } + ] + }); + }); +}); + testInDebug("Inverse null relationships with models that don't exist throw a nice error if trying to use that relationship", function(assert) { User = DS.Model.extend({ post: DS.belongsTo('post', { inverse: null }) diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index 9bb335fbf48..2f095d0cb4a 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -1487,6 +1487,6 @@ test("createRecord updates inverse record array which has observers", function(a assert.equal(user.get('messages.length'), 1, 'The message is added to the record array'); let messageFromArray = user.get('messages.firstObject'); - assert.ok(message === messageFromArray, 'Only one message should be created'); + assert.ok(message === messageFromArray, 'Only one message record instance should be created'); }); }); diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 157aa85903b..1ca4c768e80 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -173,11 +173,6 @@ testInDebug('Warns but does not fail when pushing payload with unknown type incl attributes: { 'first-name': 'Yehuda', 'last-name': 'Katz' - }, - relationships: { - company: { - data: { type: 'unknown-types', id: '2' } - } } }, included: [{ @@ -199,6 +194,30 @@ testInDebug('Warns but does not fail when pushing payload with unknown type incl assert.equal(get(user, 'firstName'), 'Yehuda', 'firstName is correct'); }); +testInDebug('Errors when pushing payload with unknown type included in relationship', function(assert) { + var documentHash = { + data: { + type: 'users', + id: '1', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz' + }, + relationships: { + company: { + data: { type: 'unknown-types', id: '2' } + } + } + } + }; + + assert.expectAssertion(function() { + run(function() { + env.store.pushPayload(documentHash); + }); + }, /No model was found for 'unknown-type'/); +}); + testInDebug('Warns when normalizing with type missing', function(assert) { var documentHash = { data: { @@ -407,7 +426,6 @@ test('a belongsTo relationship set to a new record will not show in the relation }); let handle = store.peekRecord('handle', 1); - let user = store.createRecord('user'); handle.set('user', user); diff --git a/tests/unit/debug-test.js b/tests/unit/debug-test.js index 2625e2c6738..fe44fb27660 100644 --- a/tests/unit/debug-test.js +++ b/tests/unit/debug-test.js @@ -60,7 +60,7 @@ test('_debugInfo supports arbitray relationship types', function(assert) { options: { inverse: null }, isRelationship: true, kind: 'customRelationship', - name: 'Custom Relationship', + name: 'posts', type: 'post' }) }); @@ -89,14 +89,14 @@ test('_debugInfo supports arbitray relationship types', function(assert) { expand: true }, { - name: 'Belongs To', + name: 'maritalStatus', properties: [ 'maritalStatus' ], expand: true }, { - name: 'Custom Relationship', + name: 'posts', properties: [ 'posts' ], diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index a3848aad1e1..59e8f2896e6 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -5,7 +5,7 @@ import { run } from '@ember/runloop'; import { createStore } from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; -import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import { testInDebug, testRecordData, skipRecordData } from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; import DS from 'ember-data'; import { getOwner } from 'ember-data/-private'; @@ -867,15 +867,17 @@ test('setting a property back to its original value removes the property from th return run(() => { return store.findRecord('person', 1).then(person => { - assert.equal(person._internalModel._attributes.name, undefined, 'the `_attributes` hash is clean'); + let internalModel = person._internalModel; + let dataSource = internalModel._modelData || internalModel; + assert.equal(dataSource._attributes.name, undefined, 'the `_attributes` hash is clean'); set(person, 'name', 'Niceguy Dale'); - assert.equal(person._internalModel._attributes.name, 'Niceguy Dale', 'the `_attributes` hash contains the changed value'); + assert.equal(dataSource._attributes.name, 'Niceguy Dale', 'the `_attributes` hash contains the changed value'); set(person, 'name', 'Scumbag Dale'); - assert.equal(person._internalModel._attributes.name, undefined, 'the `_attributes` hash is reset'); + assert.equal(dataSource._attributes.name, undefined, 'the `_attributes` hash is reset'); }); }); }); @@ -1370,7 +1372,31 @@ test('setting the id after model creation should correctly update the id', funct }); }); -test('updating the id with store.updateId should correctly when the id property is watched', function(assert) { +testRecordData('updating the id with store.setRecordId should correctly when the id property is watched', function(assert) { + assert.expect(2); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + idComputed: computed('id', function() {}) + }); + + let { store } = setupStore({ + person: Person + }); + + run(() => { + let person = store.createRecord('person'); + person.get('idComputed'); + + assert.equal(person.get('id'), null, 'initial created model id should be null'); + + store.setRecordId('person', 'john', person._internalModel.clientId); + + assert.equal(person.id, 'john', 'new id should be correctly set.'); + }); +}); + +skipRecordData('updating the id with store.updateId should correctly when the id property is watched', function(assert) { assert.expect(2); const Person = DS.Model.extend({ @@ -1389,12 +1415,35 @@ test('updating the id with store.updateId should correctly when the id property assert.equal(person.get('id'), null, 'initial created model id should be null'); store.updateId(person._internalModel, { id: 'john' }); + assert.equal(person.id, 'john', 'new id should be correctly set.'); + }); +}); + +testRecordData('accessing the model id without the get function should work when id is watched', function(assert) { + assert.expect(2); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + idComputed: computed('id', function() {}) + }); + + let { store } = setupStore({ + person: Person + }); + + run(() => { + let person = store.createRecord('person'); + person.get('idComputed'); + + assert.equal(person.get('id'), null, 'initial created model id should be null'); + + store.setRecordId('person', 'john', person._internalModel.clientId); assert.equal(person.id, 'john', 'new id should be correctly set.'); }); }); -test('accessing the model id without the get function should work when id is watched', function(assert) { +skipRecordData('accessing the model id without the get function should work when id is watched', function(assert) { assert.expect(2); const Person = DS.Model.extend({ diff --git a/tests/unit/model/relationships-test.js b/tests/unit/model/relationships-test.js index 0bee85d9a23..d1d1ecf609d 100644 --- a/tests/unit/model/relationships-test.js +++ b/tests/unit/model/relationships-test.js @@ -31,12 +31,24 @@ test('exposes a hash of the relationships on a model', function(assert) { store.createRecord('occupation'); let relationships = get(Person, 'relationships'); - assert.deepEqual(relationships.get('person'), [ - { name: "people", kind: "hasMany" }, - { name: "parent", kind: "belongsTo" } + function extractDetails(key) { + let descs = relationships.get(key); + + return descs.map(desc => { + return { + kind: desc.kind, + name: desc.name, + options: desc.options + }; + }); + } + + assert.deepEqual(extractDetails('person'), [ + { name: "people", kind: "hasMany", options: { async: false, inverse: 'parent'} }, + { name: "parent", kind: "belongsTo", options: { async: false, inverse: 'people' } } ]); - assert.deepEqual(relationships.get('occupation'), [ - { name: "occupations", kind: "hasMany" } + assert.deepEqual(extractDetails('occupation'), [ + { name: "occupations", kind: "hasMany", options: { async: false } } ]); }); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 29bbbae7138..8feb6fb13aa 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -1954,10 +1954,17 @@ test('DS.hasMany proxy is destroyed', function(assert) { return peopleProxy.then(people => { run(() => { + let isRecordDataBuild = people.modelData !== undefined; tag.unloadRecord(); + // TODO Check all unloading behavior assert.equal(people.isDestroying, false, 'people is NOT destroying sync after unloadRecord'); assert.equal(people.isDestroyed, false, 'people is NOT destroyed sync after unloadRecord'); - assert.equal(peopleProxy.isDestroying, false, 'peopleProxy is destroying sync after unloadRecord'); + + // unload is not the same as destroy, and we may cancel + // prior to RecordData, this was coupled to the destroy + // of the relationship, which was async and possibly could + // be cancelled were an unload to be aborted. + assert.equal(peopleProxy.isDestroying, isRecordDataBuild, 'peopleProxy is not destroying sync after unloadRecord'); assert.equal(peopleProxy.isDestroyed, false, 'peopleProxy is NOT YET destroyed sync after unloadRecord'); }); @@ -1983,9 +1990,10 @@ test('DS.ManyArray is lazy', function(assert) { let env = setupStore({ tag: Tag, person: Person }); let tag = env.store.createRecord('tag'); - let hasManyRelationship = tag.hasMany('people').hasManyRelationship; + // TODO replace with a test that checks for wherever the new ManyArray location is + //let hasManyRelationship = tag.hasMany('people').hasManyRelationship; - assert.ok(!hasManyRelationship._manyArray); + //assert.ok(!hasManyRelationship._manyArray); run(() => { assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (before access)'); @@ -1994,7 +2002,7 @@ test('DS.ManyArray is lazy', function(assert) { }); assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (after access, but after the current run loop)'); - assert.ok(hasManyRelationship._manyArray instanceof DS.ManyArray); + //assert.ok(hasManyRelationship._manyArray instanceof DS.ManyArray); let person = env.store.createRecord('person'); diff --git a/tests/unit/record-arrays/adapter-populated-record-array-test.js b/tests/unit/record-arrays/adapter-populated-record-array-test.js index 3bc283652aa..3c0b4001236 100644 --- a/tests/unit/record-arrays/adapter-populated-record-array-test.js +++ b/tests/unit/record-arrays/adapter-populated-record-array-test.js @@ -2,9 +2,8 @@ import { A } from '@ember/array'; import RSVP from 'rsvp'; import { run } from '@ember/runloop'; import DS from 'ember-data'; - import { module, test } from 'qunit'; -const { AdapterPopulatedRecordArray } = DS; +const { AdapterPopulatedRecordArray , RecordArrayManager } = DS; module('unit/record-arrays/adapter-populated-record-array - DS.AdapterPopulatedRecordArray'); @@ -18,7 +17,7 @@ function internalModelFor(record) { } }; - record._internalModel = _internalModel + record._internalModel = _internalModel; return _internalModel; } @@ -110,7 +109,8 @@ test('#_setInternalModels', function(assert) { } let recordArray = AdapterPopulatedRecordArray.create({ - query: 'some-query' + query: 'some-query', + manager: new RecordArrayManager({}) }); let model1 = internalModelFor({ id: 1 }); @@ -166,11 +166,12 @@ test('change events when receiving a new query payload', function(assert) { } let recordArray = AdapterPopulatedRecordArray.create({ - query: 'some-query' + query: 'some-query', + manager: new RecordArrayManager({}) }); let model1 = internalModelFor({ id: '1', name: 'Scumbag Dale' }); - let model2 = internalModelFor({ id: '2', name: 'Scumbag Katz' }) + let model2 = internalModelFor({ id: '2', name: 'Scumbag Katz' }); model1._recordArrays = { add, delete: del }; model2._recordArrays = { add, delete: del }; diff --git a/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js b/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js index f14a2e2ec18..5d73cce6798 100644 --- a/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js +++ b/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js @@ -1,5 +1,4 @@ import { run } from '@ember/runloop'; -import { RelationshipPayloadsManager } from 'ember-data/-private'; import DS from 'ember-data'; import { createStore } from 'dummy/tests/helpers/store'; import deepCopy from 'dummy/tests/helpers/deep-copy'; @@ -29,15 +28,13 @@ module('unit/system/relationships/relationship-payloads-manager (polymorphic)', const BigHat = Hat.extend({}); const SmallHat = Hat.extend({}); - let store = this.store = createStore({ + this.store = createStore({ user: User, alien: Alien, hat: Hat, 'big-hat': BigHat, 'small-hat': SmallHat }); - - this.relationshipPayloadsManager = new RelationshipPayloadsManager(store); } }); diff --git a/tests/unit/system/relationships/relationship-payload-manager-test.js b/tests/unit/system/relationships/relationship-payload-manager-test.js deleted file mode 100644 index 196302302d1..00000000000 --- a/tests/unit/system/relationships/relationship-payload-manager-test.js +++ /dev/null @@ -1,682 +0,0 @@ -import { get } from '@ember/object'; -import { RelationshipPayloadsManager } from 'ember-data/-private'; -import DS from 'ember-data'; -import { createStore } from 'dummy/tests/helpers/store'; -import { module, test } from 'qunit'; - -const { Model, hasMany, belongsTo } = DS; - -module('unit/system/relationships/relationship-payloads-manager', { - beforeEach() { - const User = Model.extend({ - purpose: belongsTo('purpose', { inverse: 'user' }), - hobbies: hasMany('hobby', { inverse: 'user'}), - friends: hasMany('user', { inverse: 'friends' }) - }); - User.toString = () => 'User'; - - const Hobby = Model.extend({ - user: DS.belongsTo('user', { inverse: 'hobbies' }) - }); - Hobby.toString = () => 'Hobby'; - - const Purpose = Model.extend({ - user: DS.belongsTo('user', { inverse: 'purpose' }) - }); - Purpose.toString = () => 'Purpose'; - - let store = this.store = createStore({ - user: User, - hobby: Hobby, - purpose: Purpose - }); - - this.relationshipPayloadsManager = new RelationshipPayloadsManager(store); - } -}); - -test('get throws for invalid models', function(assert) { - assert.throws(() => { - this.relationshipPayloadsManager.get('fish', 9, 'hobbies'); - }, /No model was found for 'fish'/); -}); - -test('get returns null for invalid relationships', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - hobbies: { - data: [{ - id: 1, - type: 'hobby' - }] - } - }); - let entry = this.relationshipPayloadsManager.get('user', 2, 'potatoes'); - assert.equal(entry, null, 'nothing returned for invalid relationship'); -}); - -test('get returns null if there are no payloads', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - hobbies: { - data: [{ - id: 1, - type: 'hobby' - }] - } - }); - let entry = this.relationshipPayloadsManager.get('user', 2, 'hobbies'); - assert.equal(entry, null, 'no payloads for user 2'); - - entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); - assert.equal(entry, null, 'no payloads for user 1 purpose'); -}); - -test('get returns direct payloads', function(assert) { - let hobbyPayload = { - data: [{ - id: 1, - type: 'hobby' - }] - }; - let purposePayload = { - data: { - id: 2, - type: 'purpose' - } - }; - let friendsPayload = { - data: [{ - id: 2, - type: 'user' - }, { - id: 3, - type: 'user' - }] - }; - this.relationshipPayloadsManager.push('user', 1, { - hobbies: hobbyPayload, - purpose: purposePayload, - friends: friendsPayload - }); - - let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); - assert.deepEqual(entry, purposePayload, 'direct one-to-one payload loaded'); - - entry = this.relationshipPayloadsManager.get('user', 1, 'hobbies'); - assert.deepEqual(entry, hobbyPayload, 'direct one-to-many payload loaded'); - - entry = this.relationshipPayloadsManager.get('user', 1, 'friends'); - assert.deepEqual(entry, friendsPayload, 'direct many-to-many payload loaded'); -}); - -test('get returns inverse payloads one-to-one', function(assert) { - this.relationshipPayloadsManager.push('purpose', 2, { - user: { - data: { - id: 1, - type: 'user' - } - } - }); - - let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); - assert.deepEqual(entry, { - data: { - id: 2, - type: 'purpose' - } - }, 'inverse one-to-one payload loaded'); -}); - -test('get returns inverse payloads one-to-many', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - hobbies: { - data: [{ - id: 2, - type: 'hobby' - }, { - id: 3, - type: 'hobby' - }] - } - }); - - let entry = this.relationshipPayloadsManager.get('hobby', 2, 'user'); - assert.deepEqual(entry, { - data: { - id: 1, - type: 'user' - } - }, 'inverse one-to-many payload loaded'); - - entry = this.relationshipPayloadsManager.get('hobby', 3, 'user'); - assert.deepEqual(entry, { - data: { - id: 1, - type: 'user' - } - }, 'inverse one-to-many payload loaded'); -}); - -test('get handles inverse payloads that unset one-to-one', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - purpose: { - data: { - id: 2, - type: 'purpose' - } - } - }); - - let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); - assert.deepEqual(entry, { - data: { - id: 2, - type: 'purpose' - } - }, 'user.purpose.id is initially 2'); - - entry = this.relationshipPayloadsManager.get('purpose', 2, 'user'); - assert.deepEqual(entry, { - data: { - id: 1, - type: 'user' - } - }, 'purpose.user.id is initially 1'); - - this.relationshipPayloadsManager.push('purpose', 2, { - user: { - data: null - } - }); - - entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); - assert.deepEqual(entry, { - data: null - }, 'inverse payload unset one-to-one'); -}); - -test('get handles inverse payloads that change one-to-one', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - purpose: { - data: { - id: 2, - type: 'purpose' - } - } - }); - - let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); - assert.deepEqual(entry, { - data: { - id: 2, - type: 'purpose' - } - }, 'user.purpose.id is initially 2'); - - entry = this.relationshipPayloadsManager.get('purpose', 2, 'user'); - assert.deepEqual(entry, { - data: { - id: 1, - type: 'user' - } - }, 'purpose.user.id is initially 1'); - - this.relationshipPayloadsManager.push('purpose', 2, { - user: { - data: { - id: 2, - type: 'user' - } - } - }); - - entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); - assert.deepEqual(entry, { - data: null - }, 'inverse payload unset one-to-one'); - - entry = this.relationshipPayloadsManager.get('user', 2, 'purpose'); - assert.deepEqual(entry, { - data: { - id: 2, - type: 'purpose' - } - }, 'inverse payload changed one-to-one'); -}); - -test('get handles inverse payloads that remove one-to-many', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - hobbies: { - data: [{ - id: 2, - type: 'hobby' - }, { - id: 3, - type: 'hobby' - }] - } - }); - - let entry = this.relationshipPayloadsManager.get('user', 1, 'hobbies'); - assert.deepEqual(entry, { - data: [{ - id: 2, - type: 'hobby' - }, { - id: 3, - type: 'hobby' - }] - }, 'user.hobbies.ids is initially 2,3'); - - entry = this.relationshipPayloadsManager.get('hobby', 2, 'user'); - assert.deepEqual(entry, { - data: { - id: 1, - type: 'user' - } - }, 'hobby(2).user.id is initially 1'); - - entry = this.relationshipPayloadsManager.get('hobby', 3, 'user'); - assert.deepEqual(entry, { - data: { - id: 1, - type: 'user' - } - }, 'hobby(3).user.id is initially 1'); - - this.relationshipPayloadsManager.push('hobby', 2, { - user: { - data: null - } - }); - - entry = this.relationshipPayloadsManager.get('user', 1, 'hobbies'); - assert.deepEqual(entry, { - data: [{ - id: 3, - type: 'hobby' - }] - }, 'inverse payload removes from one-to-many'); -}); - -test('get handles inverse payloads that add one-to-many', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - hobbies: { - data: [{ - id: 2, - type: 'hobby' - }, { - id: 3, - type: 'hobby' - }] - } - }); - - let entry = this.relationshipPayloadsManager.get('user', 1, 'hobbies'); - assert.deepEqual(entry, { - data: [{ - id: 2, - type: 'hobby' - }, { - id: 3, - type: 'hobby' - }] - }, 'user.hobbies.ids is initially 2,3'); - - entry = this.relationshipPayloadsManager.get('hobby', 2, 'user'); - assert.deepEqual(entry, { - data: { - id: 1, - type: 'user' - } - }, 'hobby(2).user.id is initially 1'); - - entry = this.relationshipPayloadsManager.get('hobby', 3, 'user'); - assert.deepEqual(entry, { - data: { - id: 1, - type: 'user' - } - }, 'hobby(3).user.id is initially 1'); - - this.relationshipPayloadsManager.push('hobby', 4, { - user: { - data: { - id: 1, - type: 'user' - } - } - }); - - entry = this.relationshipPayloadsManager.get('user', 1, 'hobbies'); - assert.deepEqual(entry, { - data: [{ - id: 2, - type: 'hobby' - }, { - id: 3, - type: 'hobby' - }, { - id: 4, - type: 'hobby' - }] - }, 'inverse payload adds to one-to-many'); -}); - -test('get handles inverse payloads that remove many-to-many', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - friends: { - data: [{ - id: 2, - type: 'user' - }, { - id: 3, - type: 'user' - }] - } - }); - - let entry = this.relationshipPayloadsManager.get('user', 1, 'friends'); - assert.deepEqual(entry, { - data: [{ - id: 2, - type: 'user' - }, { - id: 3, - type: 'user' - }] - }, 'user.friends.ids is initially 2,3'); - - this.relationshipPayloadsManager.push('user', 3, { - friends: { - data: [] - } - }); - - entry = this.relationshipPayloadsManager.get('user', 1, 'friends'); - assert.deepEqual(entry, { - data: [{ - id: 2, - type: 'user' - }] - }, 'inverse payload removes from many-to-many'); -}); - -test('get handles inverse payloads that add many-to-many', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - friends: { - data: [{ - id: 2, - type: 'user' - }, { - id: 3, - type: 'user' - }] - } - }); - - let entry = this.relationshipPayloadsManager.get('user', 1, 'friends'); - assert.deepEqual(entry, { - data: [{ - id: 2, - type: 'user' - }, { - id: 3, - type: 'user' - }] - }, 'user.friends.ids is initially 2,3'); - - this.relationshipPayloadsManager.push('user', 4, { - friends: { - data: [{ - id: 1, - type: 'user' - }] - } - }); - - entry = this.relationshipPayloadsManager.get('user', 1, 'friends'); - assert.deepEqual(entry, { - data: [{ - id: 2, - type: 'user' - }, { - id: 3, - type: 'user' - }, { - id: 4, - type: 'user' - }] - }, 'inverse payload adds to many-to-many'); -}); - -test('push populates the same RelationshipPayloads for either side of a relationship', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - hobbies: [{ - id: 2, - type: 'hobby' - }] - }); - - let userModel = this.store.modelFor('user'); - - let userPayloads = - this.relationshipPayloadsManager._getRelationshipPayloads( - 'user', - 'hobbies', - userModel, - get(userModel, 'relationshipsByName') - ); - - let hobbyModel = this.store.modelFor('hobby'); - let hobbyPayloads = - this.relationshipPayloadsManager._getRelationshipPayloads( - 'hobby', - 'user', - hobbyModel, - get(hobbyModel, 'relationshipsByName') - ); - - assert.equal(userPayloads, hobbyPayloads, 'both sides of a relationship share a RelationshipPayloads'); -}); - -test('push does not eagerly populate inverse payloads', function(assert) { - const relData = { - hobbies: { - data: [{ - id: 2, - type: 'hobby' - }] - } - }; - this.relationshipPayloadsManager.push('user', 1, relData); - - let userModel = this.store.modelFor('user'); - let relationshipPayloads = - this.relationshipPayloadsManager._getRelationshipPayloads( - 'user', - 'hobbies', - userModel, - get(userModel, 'relationshipsByName') - ); - - assert.deepEqual( - Object.keys(relationshipPayloads.lhs_payloads.types), - [], - 'user.hobbies payloads not eagerly populated' - ); - assert.deepEqual( - Object.keys(relationshipPayloads.rhs_payloads.types), - [], - 'hobby.user payloads not eagerly populated' - ); - - relationshipPayloads.get('user', 1, 'hobbies'); - - assert.deepEqual( - Object.keys(relationshipPayloads.lhs_payloads.types), - ['user'], - 'user.hobbies payloads lazily populated' - ); - assert.deepEqual( - Object.keys(relationshipPayloads.lhs_payloads.types.user), - ['1'], - 'user.hobbies payloads lazily populated' - ); - assert.deepEqual( - Object.keys(relationshipPayloads.rhs_payloads.types), - ['hobby'] , - 'hobby.user payloads lazily populated' - ); - assert.deepEqual( - Object.keys(relationshipPayloads.rhs_payloads.types.hobby), - ['2'] , - 'hobby.user payloads lazily populated' - ); -}); - -test('push populates each individual relationship in a payload', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - purpose: { - data: { - id: 3, - type: 'purpose' - } - }, - friends: { - data: [{ - id: 3, - type: 'user' - }] - }, - hobbies: { - data: [{ - id: 2, - type: 'hobby' - }] - } - }); - - let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); - assert.deepEqual(entry, { - data: { - id: 3, - type: 'purpose' - } - }, 'user.purpose is loaded'); - - entry = this.relationshipPayloadsManager.get('user', 1, 'friends'); - assert.deepEqual(entry, { - data: [{ - id: 3, - type: 'user' - }] - }, 'user.friends is loaded'); - - entry = this.relationshipPayloadsManager.get('user', 1, 'hobbies'); - assert.deepEqual(entry, { - data: [{ - id: 2, - type: 'hobby' - }] - }, 'user.hobbies is loaded'); -}); - -test('push ignores invalid relationships in a payload', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - purpose: { - data: { - id: 3, - type: 'purpose' - } - }, - loyalBadgers: { - data: [{ - id: 1, - type: 'badger-obviously' - }, { - id: 2, - type: 'badger-obviously' - }] - } - }); - - let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); - assert.deepEqual(entry, { - data: { - id: 3, - type: 'purpose' - } - }, 'user.purpose is loaded'); -}); - -test('unload unloads payloads that have no inverse', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - purpose: { - data: { - id: 1, - type: 'purpose' - } - } - }); - - let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); - assert.deepEqual(entry, { - data: { - id: 1, - type: 'purpose' - } - }, 'payload is initially loaded'); - - this.relationshipPayloadsManager.unload('user', 1, 'purpose'); - - entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); - assert.equal(entry, null, 'payload is unloaded when inverse is not in store'); -}); - -test('unload unloads only one side of the payload when it has an inverse', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - purpose: { - data: { - id: 1, - type: 'purpose' - } - } - }); - - let entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); - assert.deepEqual(entry, { - data: { - id: 1, - type: 'purpose' - } - }, 'payload is initially loaded'); - - this.relationshipPayloadsManager.unload('user', 1, 'purpose'); - - entry = this.relationshipPayloadsManager.get('user', 1, 'purpose'); - assert.equal(null, entry, 'payload is unloaded'); - - entry = this.relationshipPayloadsManager.get('purpose', 1, 'user'); - assert.deepEqual(entry, { - data: { - id: 1, - type: 'user' - } - }, 'inverse is retained'); -}); - -test('get can retrieve payloads with self-links in reflexive relationships', function(assert) { - let friendsPayload = { - data: [{ - id: 1, - type: 'user' - }] - }; - this.relationshipPayloadsManager.push('user', 1, { - friends: friendsPayload - }); - - let entry = this.relationshipPayloadsManager.get('user', 1, 'friends'); - assert.deepEqual(entry, friendsPayload, 'self-link in reflexive relationship'); -}); diff --git a/tests/unit/system/relationships/relationship-payloads-test.js b/tests/unit/system/relationships/relationship-payloads-test.js deleted file mode 100644 index a0f9a76e51a..00000000000 --- a/tests/unit/system/relationships/relationship-payloads-test.js +++ /dev/null @@ -1,344 +0,0 @@ -import { get } from '@ember/object'; -import { RelationshipPayloadsManager } from 'ember-data/-private'; -import DS from 'ember-data'; -import setupStore from 'dummy/tests/helpers/store'; -import { module, test } from 'qunit'; -import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import { run } from '@ember/runloop'; -import { - reset as resetModelFactoryInjection -} from 'dummy/tests/helpers/model-factory-injection'; - -const { - belongsTo, - hasMany, - attr, - Model -} = DS; - -module('unit/system/relationships/relationship-payloads', { - beforeEach() { - const User = Model.extend({ - purpose: belongsTo('purpose', { inverse: 'user' }), - hobbies: hasMany('hobby', { inverse: 'user'}), - friends: hasMany('user', { inverse: 'friends' }) - }); - User.toString = () => 'User'; - - const Hobby = Model.extend({ - user: belongsTo('user', { inverse: 'hobbies' }) - }); - Hobby.toString = () => 'Hobby'; - - const Purpose = Model.extend({ - user: belongsTo('user', { inverse: 'purpose' }) - }); - Purpose.toString = () => 'Purpose'; - - this.env = setupStore({ - user: User, - Hobby: Hobby, - purpose: Purpose - }); - - let store = this.store = this.env.store; - - this.relationshipPayloadsManager = new RelationshipPayloadsManager(store); - }, - - afterEach() { - resetModelFactoryInjection(); - run(this.env.container, 'destroy'); - } -}); - -test('_{lhs,rhs}RelationshipIsMany returns true for hasMany relationships', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - purpose: { - data: null - }, - hobbies: { - data: [] - }, - friends: { - data: [] - } - }); - - let userModel = this.store.modelFor('user'); - let relationshipPayloads = - this.relationshipPayloadsManager._getRelationshipPayloads( - 'user', - 'friends', - userModel, - get(userModel, 'relationshipsByName') - ); - - assert.equal(relationshipPayloads._lhsRelationshipIsMany, true, 'lhsRelationshipIsMany'); - assert.equal(relationshipPayloads._rhsRelationshipIsMany, true, 'rhsRelationshipIsMany'); -}); - -test('_{lhs,rhs}RelationshipIsMany returns false for belongsTo relationships', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - purpose: { - data: null - } - }); - - let userModel = this.store.modelFor('user'); - let relationshipPayloads = - this.relationshipPayloadsManager._getRelationshipPayloads( - 'user', - 'purpose', - userModel, - get(userModel, 'relationshipsByName') - ); - - assert.equal(relationshipPayloads._lhsRelationshipIsMany, false, 'purpose:user !isMany'); - assert.equal(relationshipPayloads._rhsRelationshipIsMany, false, 'user:purpose !isMany'); -}); - -testInDebug('get asserts the passed modelName and relationshipName refer to this relationship', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - purpose: { - data: null - } - }); - - let userModel = this.store.modelFor('user'); - let relationshipPayloads = - this.relationshipPayloadsManager._getRelationshipPayloads( - 'user', - 'purpose', - userModel, - get(userModel, 'relationshipsByName') - ); - - assert.expectAssertion(() => { - // relationship is wrong, lhs - relationshipPayloads.get('user', 1, 'favouriteFood'); - }, 'user:favouriteFood is not either side of this relationship, user:purpose<->purpose:user'); - - assert.expectAssertion(() => { - // relationship is wrong, rhs - relationshipPayloads.get('purpose', 1, 'fork'); - }, 'purpose:fork is not either side of this relationship, user:purpose<->purpose:user'); - - assert.expectAssertion(() => { - // model doesn't match either side of the relationship - relationshipPayloads.get('brand-of-catnip', 1, 'purpose'); - }, 'brand-of-catnip:purpose is not either side of this relationship, user:purpose<->purpose:user'); -}); - -testInDebug('unload asserts the passed modelName and relationshipName refer to this relationship', function(assert) { - this.relationshipPayloadsManager.push('user', 1, { - purpose: { - data: null - } - }); - - let userModel = this.store.modelFor('user'); - let relationshipPayloads = - this.relationshipPayloadsManager._getRelationshipPayloads( - 'user', - 'purpose', - userModel, - get(userModel, 'relationshipsByName') - ); - - assert.expectAssertion(() => { - // relationship is wrong, lhs - relationshipPayloads.unload('user', 1, 'favouriteFood'); - }, 'user:favouriteFood is not either side of this relationship, user:purpose<->purpose:user'); - - assert.expectAssertion(() => { - // relationship is wrong, rhs - relationshipPayloads.unload('purpose', 1, 'fork'); - }, 'purpose:fork is not either side of this relationship, user:purpose<->purpose:user'); - - assert.expectAssertion(() => { - // model doesn't match either side of the relationship - relationshipPayloads.unload('brand-of-catnip', 1, 'purpose'); - }, 'brand-of-catnip:purpose is not either side of this relationship, user:purpose<->purpose:user'); -}); - -module("Unit | Relationship Payloads | Merge Forward Links & Meta", { - beforeEach() { - const User = Model.extend({ - name: attr(), - pets: hasMany('pet', { async: true, inverse: 'owner' }), - home: belongsTo('home', { async: true, inverse: 'owners' }) - }); - const Home = Model.extend({ - address: attr(), - owners: hasMany('user', { async: true, inverse: 'home' }) - }); - const Pet = Model.extend({ - name: attr(), - owner: belongsTo('user', { async: false, inverse: 'pets' }) - }); - - this.env = setupStore({ - user: User, - pet: Pet, - home: Home - }); - - this.store = this.env.store; - }, - - afterEach() { - resetModelFactoryInjection(); - run(this.env.container, 'destroy'); - } -}); - -test('links and meta for hasMany inverses are not overwritten', function(assert) { - let { store } = this; - - // user:1 with pet:1 pet:2 and home:1 and links and meta for both - let user1 = run(() => store.push({ - data: { - type: 'user', - id: '1', - attributes: { name: '@runspired ' }, - relationships: { - home: { - links: { - related: './runspired/home' - }, - data: { - type: 'home', - id: '1' - }, - meta: { - slogan: 'home is where the <3 emoji is' - } - }, - pets: { - links: { - related: './runspired/pets' - }, - data: [ - { type: 'pet', id: '1' }, - { type: 'pet', id: '2' } - ], - meta: { - slogan: 'catz rewl rawr' - } - } - } - } - })); - - // home:1 with user:1 user:2 and links and meta - // user:2 sideloaded to prevent needing to fetch - let home1 = run(() => store.push({ - data: { - type: 'home', - id: '1', - attributes: { address: 'Oakland, CA' }, - relationships: { - owners: { - links: { - related: './home/1/owners' - }, - data: [ - { type: 'user', id: '2' }, - { type: 'user', id: '1' } - ], - meta: { - slogan: 'what is woof?' - } - } - } - }, - included: [ - { - type: 'user', - id: '2', - attribute: { name: '@hjdivad' }, - relationships: { - home: { - data: { type: 'home', id: '1' } - } - } - } - ] - })); - - // Toss a couple of pets in for good measure - run(() => store.push({ - data: [ - { - type: 'pet', - id:'1', - attributes: { name: 'Shen' }, - relationships: { - owner: { - data: { - type: 'user', - id: '1' - } - } - } - }, - { - type: 'pet', - id:'2', - attributes: { name: 'Rambo' }, - relationships: { - owner: { - data: { - type: 'user', - id: '1' - } - } - } - } - ] - })); - - run(() => user1.get('home')); - run(() => user1.get('pets')); - run(() => home1.get('owners')); - - assert.deepEqual( - user1.belongsTo('home').belongsToRelationship.meta, - { - slogan: 'home is where the <3 emoji is' - }, - `We merged forward meta for user 1's home` - ); - assert.deepEqual( - home1.hasMany('owners').hasManyRelationship.meta, - { - slogan: 'what is woof?' - }, - `We merged forward meta for home 1's owners` - ); - assert.deepEqual( - user1.hasMany('pets').hasManyRelationship.meta, - { - slogan: 'catz rewl rawr' - }, - `We merged forward meta for user 1's pets` - ); - - // check the link as best we can - assert.equal( - user1.belongsTo('home').belongsToRelationship.link, - './runspired/home', - `We merged forward links for user 1's home` - ); - assert.equal( - user1.hasMany('pets').hasManyRelationship.link, - './runspired/pets', - `We merged forward links for user 1's pets` - ); - assert.equal( - home1.hasMany('owners').hasManyRelationship.link, - './home/1/owners', - `We merged forward links for home 1's owners` - ); -}); diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index 573796df4b3..6c97dbb7212 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -79,13 +79,13 @@ testInDebug('assertPolymorphicType works for subclasses', function(assert) { person = person._internalModel; try { - assertPolymorphicType(user, relationship, post); + assertPolymorphicType(user, relationship, post, env.store); } catch (e) { assert.ok(false, 'should not throw an error'); } assert.expectAssertion(() => { - assertPolymorphicType(user, relationship, person); + assertPolymorphicType(user, relationship, person, env.store); }, "You cannot add a record of modelClass 'person' to the 'user.messages' relationship (only 'message' allowed)"); }); @@ -134,12 +134,12 @@ testInDebug('assertPolymorphicType works for mixins', function(assert) { person = person._internalModel; try { - assertPolymorphicType(post, relationship, video); + assertPolymorphicType(post, relationship, video, env.store); } catch (e) { assert.ok(false, 'should not throw an error'); } assert.expectAssertion(() => { - assertPolymorphicType(post, relationship, person); + assertPolymorphicType(post, relationship, person, env.store); }, "You cannot add a record of modelClass 'person' to the 'post.medias' relationship (only 'medium' allowed)"); }); diff --git a/yarn.lock b/yarn.lock index 194ada067a3..8953e5a9438 100644 --- a/yarn.lock +++ b/yarn.lock @@ -31,6 +31,24 @@ version "0.7.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" +"@types/acorn@^4.0.3": + version "4.0.3" + resolved "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.3.tgz#d1f3e738dde52536f9aad3d3380d14e448820afd" + dependencies: + "@types/estree" "*" + +"@types/estree@*": + version "0.0.39" + resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" + +"@types/estree@0.0.38": + version "0.0.38" + resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.38.tgz#c1be40aa933723c608820a99a373a16d215a1ca2" + +"@types/node@^9.6.0": + version "9.6.12" + resolved "https://registry.npmjs.org/@types/node/-/node-9.6.12.tgz#ab2d716505858ebc8ee94b347b5c9d311eb81b72" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -49,6 +67,12 @@ accepts@~1.3.4: mime-types "~2.1.18" negotiator "0.6.1" +acorn-dynamic-import@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" + dependencies: + acorn "^5.0.0" + acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" @@ -59,6 +83,10 @@ acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" +acorn@^5.0.0, acorn@^5.5.3: + version "5.5.3" + resolved "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" + acorn@^5.2.1, acorn@^5.5.0: version "5.5.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.1.tgz#84e05a9ea0acbe131227da50301e62464dc9c1d8" @@ -111,6 +139,12 @@ amd-name-resolver@1.0.0: dependencies: ensure-posix-path "^1.0.1" +amd-name-resolver@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz#fc41b3848824b557313897d71f8d5a0184fbe679" + dependencies: + ensure-posix-path "^1.0.1" + amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -299,7 +333,7 @@ async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" -async-promise-queue@^1.0.3: +async-promise-queue@^1.0.3, async-promise-queue@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/async-promise-queue/-/async-promise-queue-1.0.4.tgz#308baafbc74aff66a0bb6e7f4a18d4fe8434440c" dependencies: @@ -1460,19 +1494,19 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli rimraf "^2.3.4" symlink-or-copy "^1.1.8" -broccoli-rollup@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/broccoli-rollup/-/broccoli-rollup-1.3.0.tgz#43a0a7798555bab54217009eb470a4ff5a056df0" +broccoli-rollup@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/broccoli-rollup/-/broccoli-rollup-2.1.0.tgz#94d703625c24dbad2e57789508f63ccfcbb13c00" dependencies: + "@types/node" "^9.6.0" + amd-name-resolver "^1.2.0" broccoli-plugin "^1.2.1" - es6-map "^0.1.4" - fs-extra "^0.30.0" fs-tree-diff "^0.5.2" heimdalljs "^0.2.1" heimdalljs-logger "^0.1.7" - md5-hex "^1.3.0" + magic-string "^0.24.0" node-modules-path "^1.0.1" - rollup "^0.41.4" + rollup "^0.57.1" symlink-or-copy "^1.1.8" walk-sync "^0.3.1" @@ -1537,7 +1571,7 @@ broccoli-test-helper@^1.2.0: rimraf "^2.5.4" walk-sync "^0.3.1" -broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: +broccoli-uglify-sourcemap@^1.0.1: version "1.5.2" resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.2.tgz#04f84ab0db539031fa868ccfa563c9932d50cedb" dependencies: @@ -1551,6 +1585,22 @@ broccoli-uglify-sourcemap@^1.0.0, broccoli-uglify-sourcemap@^1.0.1: uglify-js "^2.7.0" walk-sync "^0.1.3" +broccoli-uglify-sourcemap@^2.0.0-beta.1: + version "2.1.1" + resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-2.1.1.tgz#33005537e18a322a181a5aea3e46d145b3355630" + dependencies: + async-promise-queue "^1.0.4" + broccoli-plugin "^1.2.1" + debug "^3.1.0" + lodash.defaultsdeep "^4.6.0" + matcher-collection "^1.0.5" + mkdirp "^0.5.0" + source-map-url "^0.4.0" + symlink-or-copy "^1.0.1" + uglify-es "^3.1.3" + walk-sync "^0.3.2" + workerpool "^2.3.0" + broccoli-writer@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/broccoli-writer/-/broccoli-writer-0.1.1.tgz#d4d71aa8f2afbc67a3866b91a2da79084b96ab2d" @@ -1970,6 +2020,10 @@ commander@^2.5.0, commander@^2.6.0: version "2.14.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" +commander@~2.13.0: + version "2.13.0" + resolved "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" + common-tags@^1.4.0: version "1.7.2" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.7.2.tgz#24d9768c63d253a56ecff93845b44b4df1d52771" @@ -2195,6 +2249,12 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +date-time@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/date-time/-/date-time-2.1.0.tgz#0286d1b4c769633b3ca13e1e62558d2dbdc2eba2" + dependencies: + time-zone "^1.0.0" + debug@2, debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.4.0, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -2685,11 +2745,12 @@ ember-cli-test-loader@^2.2.0: dependencies: ember-cli-babel "^6.8.1" -ember-cli-uglify@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ember-cli-uglify/-/ember-cli-uglify-1.2.0.tgz#3208c32b54bc2783056e8bb0d5cfe9bbaf17ffb2" +ember-cli-uglify@2.0.0-beta.1: + version "2.0.0-beta.1" + resolved "https://registry.npmjs.org/ember-cli-uglify/-/ember-cli-uglify-2.0.0-beta.1.tgz#9cb509f7f3f3342271df4a59b41176f0ffbda48a" dependencies: - broccoli-uglify-sourcemap "^1.0.0" + broccoli-uglify-sourcemap "^2.0.0-beta.1" + lodash.defaultsdeep "^4.6.0" ember-cli-valid-component-name@^1.0.0: version "1.0.0" @@ -3040,7 +3101,7 @@ es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3: es5-ext "^0.10.35" es6-symbol "^3.1.1" -es6-map@^0.1.3, es6-map@^0.1.4, es6-map@^0.1.5: +es6-map@^0.1.3, es6-map@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" dependencies: @@ -3181,6 +3242,10 @@ estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" +estree-walker@^0.3.0: + version "0.3.1" + resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-0.3.1.tgz#e6b1a51cf7292524e7237c312e5fe6660c1ce1aa" + esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -4299,6 +4364,10 @@ ipaddr.js@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" +irregular-plurals@^1.0.0: + version "1.4.0" + resolved "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.4.0.tgz#2ca9b033651111855412f16be5d77c62a458a766" + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -4511,6 +4580,12 @@ is-property@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" +is-reference@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-reference/-/is-reference-1.1.0.tgz#50e6ef3f64c361e2c53c0416cdc9420037f2685b" + dependencies: + "@types/estree" "0.0.38" + is-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" @@ -4804,6 +4879,10 @@ loader.js@^4.5.0: version "4.6.0" resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.6.0.tgz#b965663ddbe2d80da482454cb865efe496e93e22" +locate-character@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/locate-character/-/locate-character-2.0.5.tgz#f2d2614d49820ecb3c92d80d193b8db755f74c0f" + locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -4986,6 +5065,10 @@ lodash.defaults@~2.3.0: lodash._objecttypes "~2.3.0" lodash.keys "~2.3.0" +lodash.defaultsdeep@^4.6.0: + version "4.6.0" + resolved "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.0.tgz#bec1024f85b1bd96cbea405b23c14ad6443a6f81" + lodash.escape@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-2.3.0.tgz#844c38c58f844e1362ebe96726159b62cf5f2a58" @@ -5172,6 +5255,12 @@ lru-cache@^4.0.1: pseudomap "^1.0.2" yallist "^2.1.2" +magic-string@^0.24.0: + version "0.24.0" + resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.24.0.tgz#1b396d26406188f1fa3730a68229562d36a1c2f2" + dependencies: + sourcemap-codec "^1.4.1" + make-array@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" @@ -5232,13 +5321,13 @@ markdown-it@^8.3.0, markdown-it@^8.3.1: mdurl "^1.0.1" uc.micro "^1.0.5" -matcher-collection@^1.0.0, matcher-collection@^1.0.4: +matcher-collection@^1.0.0, matcher-collection@^1.0.4, matcher-collection@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-1.0.5.tgz#2ee095438372cb8884f058234138c05c644ec339" dependencies: minimatch "^3.0.2" -md5-hex@^1.2.1, md5-hex@^1.3.0: +md5-hex@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" dependencies: @@ -5304,9 +5393,9 @@ methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" -micromatch@^2.1.5, micromatch@^2.3.7: +micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7: version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" dependencies: arr-diff "^2.0.0" array-unique "^0.2.1" @@ -5822,6 +5911,10 @@ parse-json@^2.2.0: dependencies: error-ex "^1.2.0" +parse-ms@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d" + parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" @@ -5930,6 +6023,12 @@ pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" +plur@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/plur/-/plur-2.1.2.tgz#7482452c1a0f508e3e344eaec312c91c29dc655a" + dependencies: + irregular-plurals "^1.0.0" + pluralize@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" @@ -5965,6 +6064,13 @@ pretender@^1.4.2: fake-xml-http-request "^1.6.0" route-recognizer "^0.3.3" +pretty-ms@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/pretty-ms/-/pretty-ms-3.1.0.tgz#e9cac9c76bf6ee52fe942dd9c6c4213153b12881" + dependencies: + parse-ms "^1.0.0" + plur "^2.1.2" + printf@^0.2.3: version "0.2.5" resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" @@ -6355,6 +6461,10 @@ request@~2.40.0: tough-cookie ">=0.12.0" tunnel-agent "~0.4.0" +require-relative@^0.8.7: + version "0.8.7" + resolved "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" + require-uncached@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -6440,11 +6550,28 @@ rimraf@~2.2.6: version "2.2.8" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" -rollup@^0.41.4: - version "0.41.6" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.41.6.tgz#e0d05497877a398c104d816d2733a718a7a94e2a" - dependencies: - source-map-support "^0.4.0" +rollup-pluginutils@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.0.1.tgz#7ec95b3573f6543a46a6461bd9a7c544525d0fc0" + dependencies: + estree-walker "^0.3.0" + micromatch "^2.3.11" + +rollup@^0.57.1: + version "0.57.1" + resolved "https://registry.npmjs.org/rollup/-/rollup-0.57.1.tgz#0bb28be6151d253f67cf4a00fea48fb823c74027" + dependencies: + "@types/acorn" "^4.0.3" + acorn "^5.5.3" + acorn-dynamic-import "^3.0.0" + date-time "^2.1.0" + is-reference "^1.1.0" + locate-character "^2.0.5" + pretty-ms "^3.1.0" + require-relative "^0.8.7" + rollup-pluginutils "^2.0.1" + signal-exit "^3.0.2" + sourcemap-codec "^1.4.1" route-recognizer@^0.3.3: version "0.3.3" @@ -6792,7 +6919,7 @@ source-map-support@^0.2.10: dependencies: source-map "0.1.32" -source-map-support@^0.4.0, source-map-support@^0.4.15: +source-map-support@^0.4.15: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" dependencies: @@ -6828,6 +6955,14 @@ source-map@~0.1.x: dependencies: amdefine ">=0.0.4" +source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +sourcemap-codec@^1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.1.tgz#c8fd92d91889e902a07aee392bdd2c5863958ba2" + sourcemap-validator@^1.0.5: version "1.0.7" resolved "https://registry.yarnpkg.com/sourcemap-validator/-/sourcemap-validator-1.0.7.tgz#d76aaadbe2c6ec269293b5f212100fad91eef260" @@ -7191,6 +7326,10 @@ through@^2.3.6, through@^2.3.8, through@~2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" +time-zone@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz#99c5bf55958966af6d06d83bdf3800dc82faec5d" + timed-out@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" @@ -7348,6 +7487,13 @@ uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" +uglify-es@^3.1.3: + version "3.3.9" + resolved "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" + dependencies: + commander "~2.13.0" + source-map "~0.6.1" + uglify-js@^2.6, uglify-js@^2.7.0: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" @@ -7518,7 +7664,7 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -walk-sync@0.3.2, walk-sync@^0.3.0, walk-sync@^0.3.1: +walk-sync@0.3.2, walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" dependencies: From bff2093b33a848bbe0c671f17bccde4ffe4846de Mon Sep 17 00:00:00 2001 From: Ryan Toronto Date: Fri, 4 May 2018 11:24:21 -0700 Subject: [PATCH 2226/2527] Serialize empty hasMany relationships --- addon/serializers/json-api.js | 36 ++++++----- .../serializers/json-api-serializer-test.js | 59 +++++++++++++++++++ 2 files changed, 76 insertions(+), 19 deletions(-) diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 24f16827522..b9c587f11aa 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -516,31 +516,29 @@ const JSONAPISerializer = JSONSerializer.extend({ if (this.shouldSerializeHasMany(snapshot, key, relationship)) { let hasMany = snapshot.hasMany(key); if (hasMany !== undefined) { - // only serialize has many relationships that are not new - let nonNewHasMany = hasMany.filter(item => item.record && !item.record.get('isNew')); - if (nonNewHasMany.length > 0) { - json.relationships = json.relationships || {}; - - let payloadKey = this._getMappedKey(key, snapshot.type); - if (payloadKey === key && this.keyForRelationship) { - payloadKey = this.keyForRelationship(key, 'hasMany', 'serialize'); - } + json.relationships = json.relationships || {}; - let data = new Array(nonNewHasMany.length); + let payloadKey = this._getMappedKey(key, snapshot.type); + if (payloadKey === key && this.keyForRelationship) { + payloadKey = this.keyForRelationship(key, 'hasMany', 'serialize'); + } - for (let i = 0; i < nonNewHasMany.length; i++) { - let item = hasMany[i]; - let payloadType = this.payloadKeyFromModelName(item.modelName); + // only serialize has many relationships that are not new + let nonNewHasMany = hasMany.filter(item => item.record && !item.record.get('isNew')); + let data = new Array(nonNewHasMany.length); - data[i] = { - type: payloadType, - id: item.id - }; + for (let i = 0; i < nonNewHasMany.length; i++) { + let item = hasMany[i]; + let payloadType = this.payloadKeyFromModelName(item.modelName); - json.relationships[payloadKey] = { data }; - } + data[i] = { + type: payloadType, + id: item.id + }; } + + json.relationships[payloadKey] = { data }; } } } diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 157aa85903b..5ec6e7cb08a 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -556,6 +556,65 @@ test('it should not include any records when serializing a hasMany relationship 'first-name': null, 'last-name': null, title: null + }, + relationships: { + handles: { + data: [] + } + } + } + }); + }); +}); + +test('it should include an empty list when serializing an empty hasMany relationship', function(assert) { + env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ + attrs: { + handles: { serialize: true } + } + })); + + run(function() { + serializer.pushPayload(store, { + data: { + type: 'users', + id: 1, + relationships: { + handles: { + data: [ + { type: 'handles', id: 1 }, + { type: 'handles', id: 2 } + ] + } + } + }, + included: [ + { type: 'handles', id: 1 }, + { type: 'handles', id: 2 } + ] + }); + + let user = store.peekRecord('user', 1); + let handle1 = store.peekRecord('handle', 1); + let handle2 = store.peekRecord('handle', 2); + user.get('handles').removeObject(handle1); + user.get('handles').removeObject(handle2); + + let serialized = user.serialize({ includeId: true }); + + assert.deepEqual(serialized, { + data: { + type: 'users', + id: '1', + attributes: { + 'first-name': null, + 'last-name': null, + title: null + }, + relationships: { + handles: { + data: [] + } } } }); From f7ca0bd9d69e53eaab105f8296375b69520a9627 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 8 May 2018 14:48:32 -0700 Subject: [PATCH 2227/2527] fix appveyor build --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 778376491fd..a7144bfcd9d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,7 +3,7 @@ # Test against these versions of Node.js. environment: matrix: - - nodejs_version: "4" + - nodejs_version: "6" cache: - '%LOCALAPPDATA%\Yarn' From 85bd2ca5af5769905bc894490b0a29e2f52d66dc Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 9 May 2018 03:12:36 +0300 Subject: [PATCH 2228/2527] [FEAT] improved assertions for invalid relationship payloads (#5445) * [FEAT] improved assertions for invalid relationship payloads --- .../system/relationships/state/belongs-to.js | 3 +- addon/-private/system/store.js | 49 ++++++++--------- .../system/model/model-data.js | 44 +++++++-------- .../relationships/belongs-to-test.js | 53 +++++++++++++++++++ .../relationships/has-many-test.js | 52 ++++++++++++++++++ 5 files changed, 151 insertions(+), 50 deletions(-) diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 7d696e290bd..2f859682ec9 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -1,5 +1,5 @@ import { Promise as EmberPromise } from 'rsvp'; -import { assert, inspect } from '@ember/debug'; +import { assert } from '@ember/debug'; import { assertPolymorphicType } from 'ember-data/-debug'; import { PromiseBelongsTo @@ -233,7 +233,6 @@ export default class BelongsToRelationship extends Relationship { } updateData(data, initial) { - assert(`Ember Data expected the data for the ${this.key} relationship on a ${this.internalModel.toString()} to be in a JSON API format and include an \`id\` and \`type\` property but it found ${inspect(data)}. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || data.id !== undefined && data.type !== undefined); let internalModel = this.store._pushResourceIdentifier(this, data); if (initial) { this.setInitialCanonicalInternalModel(internalModel); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index cddc90006ec..f146066966e 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -2677,10 +2677,8 @@ Store = Service.extend({ if (isNone(resourceIdentifier)) { return; } + assertRelationshipData(this, relationship.internalModel, resourceIdentifier, relationship.relationshipMeta); - assert(`A ${relationship.internalModel.modelName} record was pushed into the store with the value of ${relationship.key} being ${inspect(resourceIdentifier)}, but ${relationship.key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(resourceIdentifier)); - - //TODO:Better asserts return this._internalModelForId(resourceIdentifier.type, resourceIdentifier.id); }, @@ -2910,28 +2908,6 @@ function setupRelationships(store, internalModel, data, modelNameToInverseMap) { return; } - // eslint-disable-next-line no-inner-declarations - function assertRelationshipData(store, internalModel, data, meta) { - assert( - `Encountered a relationship identifier without a type for the ${meta.kind} relationship '${meta.key}' on ${internalModel}, expected a json-api identifier with type '${meta.type}'.`, - data === null || (typeof data.type === 'string' && data.type.length) - ); - assert( - `Encountered a relationship identifier without an id for the ${meta.kind} relationship '${meta.key}' on ${internalModel}, expected a json-api identifier.`, - data === null || data.id || data.id === 0 - ); - assert( - `Encountered a relationship identifier with type '${ - data.type - }' for the ${meta.kind} relationship '${meta.key}' on ${ - internalModel - }, Expected a json-api identifier with type '${ - meta.type - }'. No model was found for '${data.type}'.`, - data === null || !data.type || store._hasModelFor(data.type) - ); - } - if (relationshipData.links) { let isAsync = relationshipMeta.options && relationshipMeta.options.async !== false; warn(`You pushed a record of type '${internalModel.modelName}' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, isAsync || relationshipData.data , { @@ -2939,7 +2915,6 @@ function setupRelationships(store, internalModel, data, modelNameToInverseMap) { }); } else if (relationshipData.data) { if (relationshipMeta.kind === 'belongsTo') { - assert(`A ${internalModel.modelName} record was pushed into the store with the value of ${relationshipName} being ${inspect(relationshipData.data)}, but ${relationshipName} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(relationshipData.data)); assertRelationshipData(store, internalModel, relationshipData.data, relationshipMeta); } else if (relationshipMeta.kind === 'hasMany') { assert(`A ${internalModel.modelName} record was pushed into the store with the value of ${relationshipName} being '${inspect(relationshipData.data)}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(relationshipData.data)); @@ -2954,5 +2929,27 @@ function setupRelationships(store, internalModel, data, modelNameToInverseMap) { }); } +function assertRelationshipData(store, internalModel, data, meta) { + assert(`A ${internalModel.modelName} record was pushed into the store with the value of ${meta.key} being '${JSON.stringify(data)}', but ${meta.key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(data)); + assert( + `Encountered a relationship identifier without a type for the ${meta.kind} relationship '${meta.key}' on ${internalModel}, expected a json-api identifier with type '${meta.type}' but found '${JSON.stringify(data)}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, + data === null || (typeof data.type === 'string' && data.type.length) + ); + assert( + `Encountered a relationship identifier without an id for the ${meta.kind} relationship '${meta.key}' on ${internalModel}, expected a json-api identifier but found '${JSON.stringify(data)}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, + data === null || coerceId(data.id) + ); + assert( + `Encountered a relationship identifier with type '${ + data.type + }' for the ${meta.kind} relationship '${meta.key}' on ${ + internalModel + }, Expected a json-api identifier with type '${ + meta.type + }'. No model was found for '${data.type}'.`, + data === null || !data.type || store._hasModelFor(data.type) + ); +} + export { Store }; export default Store; diff --git a/addon/-record-data-rfc-private/system/model/model-data.js b/addon/-record-data-rfc-private/system/model/model-data.js index 238775edd89..dd39f9e17d6 100644 --- a/addon/-record-data-rfc-private/system/model/model-data.js +++ b/addon/-record-data-rfc-private/system/model/model-data.js @@ -103,28 +103,6 @@ export default class ModelData { continue; } - // eslint-disable-next-line no-inner-declarations - function assertRelationshipData(store, modelData, data, meta) { - assert( - `Encountered a relationship identifier without a type for the ${meta.kind} relationship '${meta.key}' on ${modelData}, expected a json-api identifier with type '${meta.type}'.`, - data === null || (typeof data.type === 'string' && data.type.length) - ); - assert( - `Encountered a relationship identifier without an id for the ${meta.kind} relationship '${meta.key}' on ${modelData}, expected a json-api identifier.`, - data === null || data.id || data.id === 0 - ); - assert( - `Encountered a relationship identifier with type '${ - data.type - }' for the ${meta.kind} relationship '${meta.key}' on ${ - modelData - }, Expected a json-api identifier with type '${ - meta.type - }'. No model was found for '${data.type}'.`, - data === null || !data.type || store._hasModelFor(data.type) - ); - } - if (relationshipData.links) { let isAsync = relationshipMeta.options && relationshipMeta.options.async !== false; warn(`You pushed a record of type '${this.modelName}' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, isAsync || relationshipData.data , { @@ -668,6 +646,28 @@ if (isEnabled('ds-rollback-attribute')) { }; } +function assertRelationshipData(store, modelData, data, meta) { + assert(`A ${modelData.modelName} record was pushed into the store with the value of ${meta.key} being '${JSON.stringify(data)}', but ${meta.key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(data)); + assert( + `Encountered a relationship identifier without a type for the ${meta.kind} relationship '${meta.key}' on ${modelData}, expected a json-api identifier with type '${meta.type}' but found '${JSON.stringify(data)}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, + data === null || (typeof data.type === 'string' && data.type.length) + ); + assert( + `Encountered a relationship identifier without an id for the ${meta.kind} relationship '${meta.key}' on ${modelData}, expected a json-api identifier but found '${JSON.stringify(data)}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, + data === null || coerceId(data.id) + ); + assert( + `Encountered a relationship identifier with type '${ + data.type + }' for the ${meta.kind} relationship '${meta.key}' on ${ + modelData + }, Expected a json-api identifier with type '${ + meta.type + }'. No model was found for '${data.type}'.`, + data === null || !data.type || store._hasModelFor(data.type) + ); +} + // Handle dematerialization for relationship `rel`. In all cases, notify the // relatinoship of the dematerialization: this is done so the relationship can // notify its inverse which needs to update state diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 57817720e18..cb0ecbc143b 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -207,6 +207,59 @@ test("The store can materialize a non loaded monomorphic belongsTo association", }); }); +testInDebug("Invalid belongsTo relationship identifiers throw errors", function(assert) { + assert.expect(2); + let { store } = env; + + // test null id + assert.expectAssertion( + () => { + run(() => { + let post = store.push({ + data: { + id: '1', + type: 'post', + relationships: { + user: { + data: { + id: null, + type: 'user' + } + } + } + } + }); + post.get('user'); + }); + }, + `Assertion Failed: Encountered a relationship identifier without an id for the belongsTo relationship 'user' on , expected a json-api identifier but found '{"id":null,"type":"user"}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.` + ); + + // test missing type + assert.expectAssertion( + () => { + run(() => { + let post = store.push({ + data: { + id: '2', + type: 'post', + relationships: { + user: { + data: { + id: '1', + type: null + } + } + } + } + }); + post.get('user'); + }); + }, + `Assertion Failed: Encountered a relationship identifier without a type for the belongsTo relationship 'user' on , expected a json-api identifier with type 'user' but found '{"id":"1","type":null}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.` + ); +}); + testInDebug("Only a record of the same modelClass can be used with a monomorphic belongsTo relationship", function(assert) { assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 552eefbe07f..4f5c0414a6b 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -108,6 +108,58 @@ module("integration/relationships/has_many - Has-Many Relationships", { } }); +testInDebug("Invalid hasMany relationship identifiers throw errors", function(assert) { + assert.expect(2); + let { store } = env; + + // test null id + assert.expectAssertion( + () => { + run(() => { + let post = store.push({ + data: { + id: '1', + type: 'post', + relationships: { + comments: { + data: [ + { id: null, type: 'comment' } + ] + } + } + } + }); + + post.get('comments'); + }); + }, + `Assertion Failed: Encountered a relationship identifier without an id for the hasMany relationship 'comments' on , expected a json-api identifier but found '{"id":null,"type":"comment"}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.` + ); + + // test missing type + assert.expectAssertion( + () => { + run(() => { + let post = store.push({ + data: { + id: '2', + type: 'post', + relationships: { + comments: { + data: [ + { id: '1', type: null } + ] + } + } + } + }); + post.get('comments') + }); + }, + `Assertion Failed: Encountered a relationship identifier without a type for the hasMany relationship 'comments' on , expected a json-api identifier with type 'comment' but found '{"id":"1","type":null}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.` + ); +}); + test("When a hasMany relationship is accessed, the adapter's findMany method should not be called if all the records in the relationship are already loaded", function(assert) { assert.expect(0); From 583a09b532e272de804a4fa959de77dc49a5bc97 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 8 May 2018 16:17:05 -0700 Subject: [PATCH 2229/2527] Update eslint configuration to use overrides. --- .eslintrc.js | 85 ++++++++++++++++++++++++++++------------------------ package.json | 3 +- yarn.lock | 13 ++++++++ 3 files changed, 61 insertions(+), 40 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 3cb5fd6ea66..e75b8d81830 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,18 +1,10 @@ -/* global module */ module.exports = { root: true, parserOptions: { - ecmaVersion: 6, + ecmaVersion: 2017, sourceType: 'module', }, - extends: 'eslint:recommended', - env: { - 'browser': true, - }, - globals: { - 'heimdall': true, - 'Map': false, - }, + extends: ['eslint:recommended'], rules: { 'no-unused-vars': ['error', { 'args': 'none', @@ -29,35 +21,50 @@ module.exports = { 'no-irregular-whitespace': 'error', 'no-undef': 'error', 'no-eq-null': 'error', + }, + overrides: [ + // node files + { + files: [ + 'ember-cli-build.js', + 'index.js', + 'testem.js', + 'blueprints/*/index.js', + 'config/**/*.js', + 'tests/dummy/config/**/*.js' + ], + excludedFiles: [ + 'addon/**', + 'addon-test-support/**', + 'app/**', + 'tests/dummy/app/**' + ], + parserOptions: { + sourceType: 'script', + ecmaVersion: 2015 + }, + env: { + browser: false, + node: true + }, + plugins: ['node'], + rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, { + // add your custom rules and overrides for node files here + }) + }, - // from JSCS - 'array-bracket-spacing': ['error', 'never'], - 'comma-style': ['error', 'last'], - 'brace-style': ['error', '1tbs', { - 'allowSingleLine': true, - }], - 'no-spaced-func': 'error', - 'no-empty': 'error', - 'curly': ['error', 'all'], - 'eol-last': 'error', - 'no-trailing-spaces': 'error', - 'comma-dangle': ['error', 'never'], - 'space-before-blocks': ['error', 'always'], - 'indent': ['error', 2, { - 'SwitchCase': 1, - }], - 'keyword-spacing': ['error', { - 'overrides': { - 'else': { - 'before': true, - }, - 'while': { - 'before': true, - }, - 'catch': { - 'before': true, - }, + { + files: [ + 'addon/**', + ], + env: { + browser: true, + node: false, }, - }], - }, + globals: { + Heimdall: true, + Map: false, + } + } + ], }; diff --git a/package.json b/package.json index 9ee9d6d90cb..3b1cf6ae3f3 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,6 @@ "ember-cli-inject-live-reload": "^1.4.1", "ember-cli-internal-test-helpers": "^0.8.1", "ember-cli-pretender": "^1.0.1", - "ember-qunit": "^3.4.0", "ember-cli-release": "^0.2.9", "ember-cli-shims": "^1.0.2", "ember-cli-sri": "^2.1.0", @@ -93,12 +92,14 @@ "ember-export-application-global": "^1.0.5", "ember-load-initializers": "^0.6.0", "ember-publisher": "0.0.7", + "ember-qunit": "^3.4.0", "ember-qunit-assert-helpers": "^0.2.1", "ember-resolver": "^4.1.0", "ember-source": "~3.0.0", "ember-source-channel-url": "^1.0.1", "ember-try": "^0.2.23", "ember-watson": "^0.7.0", + "eslint-plugin-node": "^6.0.1", "github": "^1.1.1", "glob": "^5.0.13", "loader.js": "^4.5.0", diff --git a/yarn.lock b/yarn.lock index 8953e5a9438..faa0df620d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3159,6 +3159,15 @@ escope@^3.6.0: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-plugin-node@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz#bf19642298064379315d7a4b2a75937376fa05e4" + dependencies: + ignore "^3.3.6" + minimatch "^3.0.4" + resolve "^1.3.3" + semver "^5.4.1" + eslint@^2.13.0: version "2.13.1" resolved "https://registry.yarnpkg.com/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" @@ -4259,6 +4268,10 @@ ignore@^3.1.2: version "3.3.7" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" +ignore@^3.3.6: + version "3.3.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.8.tgz#3f8e9c35d38708a3a7e0e9abb6c73e7ee7707b2b" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" From d507bb395b30aee74f3d73e5674a3a4786683cd2 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 8 May 2018 16:24:54 -0700 Subject: [PATCH 2230/2527] Move all eslint exceptions to top-level overrides. --- .eslintignore | 6 +++ .eslintrc.js | 39 +++++++++++++++++-- blueprints/adapter-test/index.js | 2 - blueprints/adapter/index.js | 2 - blueprints/model-test/index.js | 2 - blueprints/model/index.js | 2 - blueprints/serializer-test/index.js | 2 - blueprints/serializer/index.js | 2 - blueprints/transform-test/index.js | 2 - blueprints/transform/index.js | 2 - config/ember-try.js | 2 +- ember-cli-build.js | 2 +- index.js | 1 - lib/.eslintrc.js | 10 ----- lib/enable-optional-features-via-url/index.js | 1 - testem.js | 1 - tests/.eslintrc.js | 9 ----- tests/dummy/config/environment.js | 2 +- 18 files changed, 45 insertions(+), 44 deletions(-) create mode 100644 .eslintignore delete mode 100644 lib/.eslintrc.js delete mode 100644 tests/.eslintrc.js diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000000..0d169ddba78 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +tmp +dist +node-tests/fixtures/ +blueprints/*/mocha-files/ +blueprints/*/qunit-files/ +blueprints/*/files/ diff --git a/.eslintrc.js b/.eslintrc.js index e75b8d81830..bd0d11a2de7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -29,9 +29,13 @@ module.exports = { 'ember-cli-build.js', 'index.js', 'testem.js', + 'lib/**/*.js', 'blueprints/*/index.js', + 'blueprints/*.js', 'config/**/*.js', - 'tests/dummy/config/**/*.js' + 'tests/dummy/config/**/*.js', + 'node-tests/**', + 'bin/**', ], excludedFiles: [ 'addon/**', @@ -45,7 +49,8 @@ module.exports = { }, env: { browser: false, - node: true + node: true, + es6: true, }, plugins: ['node'], rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, { @@ -53,18 +58,46 @@ module.exports = { }) }, + // browser files { files: [ 'addon/**', + 'app/**', + 'tests/**', + ], + excludedFiles: [ + 'tests/dummy/config/**' ], env: { browser: true, node: false, }, globals: { - Heimdall: true, + heimdall: true, Map: false, } + }, + + // browser tests + { + files: [ + 'tests/**' + ], + + rules: { + 'no-console': 0 + } + }, + + // node tests + { + files: [ + 'node-tests/**' + ], + + env: { + mocha: true, + } } ], }; diff --git a/blueprints/adapter-test/index.js b/blueprints/adapter-test/index.js index 1373dc62c71..22f160b5f0b 100644 --- a/blueprints/adapter-test/index.js +++ b/blueprints/adapter-test/index.js @@ -1,5 +1,3 @@ -/* eslint-env node */ - var testInfo = require('ember-cli-test-info'); var useTestFrameworkDetector = require('../test-framework-detector'); diff --git a/blueprints/adapter/index.js b/blueprints/adapter/index.js index b3ecab8c23f..22ecb861ace 100644 --- a/blueprints/adapter/index.js +++ b/blueprints/adapter/index.js @@ -1,5 +1,3 @@ -/* eslint-env node */ - var extendFromApplicationEntity = require('../../lib/utilities/extend-from-application-entity'); module.exports = { diff --git a/blueprints/model-test/index.js b/blueprints/model-test/index.js index d4406a1c08f..0cc96cb9dfc 100644 --- a/blueprints/model-test/index.js +++ b/blueprints/model-test/index.js @@ -1,5 +1,3 @@ -/* eslint-env node */ - var ModelBlueprint = require('../model'); var testInfo = require('ember-cli-test-info'); var useTestFrameworkDetector = require('../test-framework-detector'); diff --git a/blueprints/model/index.js b/blueprints/model/index.js index 6f49c9a3a6a..657c3aeb887 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -1,5 +1,3 @@ -/* eslint-env node */ - var inflection = require('inflection'); var stringUtils = require('ember-cli-string-utils'); var EOL = require('os').EOL; diff --git a/blueprints/serializer-test/index.js b/blueprints/serializer-test/index.js index 3216223b666..ee11066acd8 100644 --- a/blueprints/serializer-test/index.js +++ b/blueprints/serializer-test/index.js @@ -1,5 +1,3 @@ -/* eslint-env node */ - var testInfo = require('ember-cli-test-info'); var useTestFrameworkDetector = require('../test-framework-detector'); diff --git a/blueprints/serializer/index.js b/blueprints/serializer/index.js index b5b278ae70a..37417997855 100644 --- a/blueprints/serializer/index.js +++ b/blueprints/serializer/index.js @@ -1,5 +1,3 @@ -/* eslint-env node */ - var extendFromApplicationEntity = require('../../lib/utilities/extend-from-application-entity'); module.exports = { diff --git a/blueprints/transform-test/index.js b/blueprints/transform-test/index.js index fe0ed6781f6..72fad344f52 100644 --- a/blueprints/transform-test/index.js +++ b/blueprints/transform-test/index.js @@ -1,5 +1,3 @@ -/* eslint-env node */ - var testInfo = require('ember-cli-test-info'); var useTestFrameworkDetector = require('../test-framework-detector'); diff --git a/blueprints/transform/index.js b/blueprints/transform/index.js index a272e5162ed..5f1b96cbe7b 100644 --- a/blueprints/transform/index.js +++ b/blueprints/transform/index.js @@ -1,5 +1,3 @@ -/* eslint-env node */ - module.exports = { description: 'Generates an ember-data value transform.' }; diff --git a/config/ember-try.js b/config/ember-try.js index 44c3e0be73e..e55993db4f4 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -1,4 +1,4 @@ -/* eslint-env node, es6 */ +'use strict'; const getChannelURL = require('ember-source-channel-url'); diff --git a/ember-cli-build.js b/ember-cli-build.js index d2b879664e8..7feb9720053 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -1,5 +1,5 @@ "use strict"; -/* eslint-env node */ + const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); const merge = require('broccoli-merge-trees'); const yuidoc = require('./lib/yuidoc'); diff --git a/index.js b/index.js index 8fb58cb5d27..3fc1d791c0c 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,3 @@ -/* eslint-env node */ 'use strict'; const path = require('path'); diff --git a/lib/.eslintrc.js b/lib/.eslintrc.js deleted file mode 100644 index e8efd22a07f..00000000000 --- a/lib/.eslintrc.js +++ /dev/null @@ -1,10 +0,0 @@ -/* global module */ -module.exports = { - parserOptions: { - ecmaVersion: 6, - }, - - env: { - node: true, - } -}; diff --git a/lib/enable-optional-features-via-url/index.js b/lib/enable-optional-features-via-url/index.js index 28986444d1c..70713bb27c4 100644 --- a/lib/enable-optional-features-via-url/index.js +++ b/lib/enable-optional-features-via-url/index.js @@ -1,4 +1,3 @@ -/* eslint-env node */ module.exports = { name: 'enable-optional-features-via-url', diff --git a/testem.js b/testem.js index 158a909be30..0e0b3601de1 100644 --- a/testem.js +++ b/testem.js @@ -1,4 +1,3 @@ -/* eslint-env node */ module.exports = { "framework": "qunit", "test_page": "tests/index.html?hidepassed", diff --git a/tests/.eslintrc.js b/tests/.eslintrc.js deleted file mode 100644 index 3a43edc6e04..00000000000 --- a/tests/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -/* global module */ -module.exports = { - rules: { - 'no-console': 0 - }, - globals: { - 'heimdall': true - } -}; diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index 0d8efda6eee..0c9597834e4 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -1,4 +1,4 @@ -/* eslint-env node */ +'use strict'; var fs = require('fs'); var path = require('path'); From cfc71889fb862061f0f392a5494d22b302a59001 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 8 May 2018 16:30:28 -0700 Subject: [PATCH 2231/2527] Update ember-cli-eslint version. --- package.json | 2 +- yarn.lock | 463 +++++++++++++++++++++++++++------------------------ 2 files changed, 250 insertions(+), 215 deletions(-) diff --git a/package.json b/package.json index 3b1cf6ae3f3..9a652aa965a 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "ember-cli-app-version": "^3.0.0", "ember-cli-blueprint-test-helpers": "^0.18.3", "ember-cli-dependency-checker": "^2.1.0", - "ember-cli-eslint": "1.3.0", + "ember-cli-eslint": "^4.2.3", "ember-cli-htmlbars": "^2.0.1", "ember-cli-htmlbars-inline-precompile": "^0.4.3", "ember-cli-inject-live-reload": "^1.4.1", diff --git a/yarn.lock b/yarn.lock index faa0df620d4..8e222a26ed6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -102,17 +102,26 @@ agent-base@2: extend "~3.0.0" semver "~5.0.1" -ajv-keywords@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" -ajv@^4.7.0, ajv@^4.9.1: +ajv@^4.9.1: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" dependencies: co "^4.6.0" json-stable-stringify "^1.0.1" +ajv@^5.2.3, ajv@^5.3.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" @@ -153,6 +162,10 @@ ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" +ansi-escapes@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" @@ -190,6 +203,12 @@ anymatch@^1.3.0: micromatch "^2.1.5" normalize-path "^2.0.0" +aot-test-generators@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/aot-test-generators/-/aot-test-generators-0.1.0.tgz#43f0f615f97cb298d7919c1b0b4e6b7310b03cd0" + dependencies: + jsesc "^2.5.0" + aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -392,7 +411,7 @@ aws4@^1.2.1: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" -babel-code-frame@^6.26.0: +babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: @@ -1416,16 +1435,17 @@ broccoli-kitchen-sink-helpers@^0.3.1: glob "^5.0.10" mkdirp "^0.5.1" -broccoli-lint-eslint@^2.0.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/broccoli-lint-eslint/-/broccoli-lint-eslint-2.7.0.tgz#a2d905d02b397a90ae82439f283c459ef819f140" +broccoli-lint-eslint@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/broccoli-lint-eslint/-/broccoli-lint-eslint-4.2.1.tgz#f780dc083a7357a9746a9cfa8f76feb092777477" dependencies: - broccoli-persistent-filter "^1.2.0" - escape-string-regexp "^1.0.5" - eslint "^2.13.0" - js-string-escape "^1.0.1" + aot-test-generators "^0.1.0" + broccoli-concat "^3.2.2" + broccoli-persistent-filter "^1.4.3" + eslint "^4.0.0" json-stable-stringify "^1.0.1" - md5-hex "^1.2.1" + lodash.defaultsdeep "^4.6.0" + md5-hex "^2.0.0" broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.2.1: version "1.2.4" @@ -1458,7 +1478,7 @@ broccoli-node-info@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" -broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.2.0, broccoli-persistent-filter@^1.4.0, broccoli-persistent-filter@^1.4.2: +broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.4.0, broccoli-persistent-filter@^1.4.2, broccoli-persistent-filter@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz#3511bc52fc53740cda51621f58a28152d9911bc1" dependencies: @@ -1651,6 +1671,10 @@ bser@^2.0.0: dependencies: node-int64 "^0.4.0" +buffer-from@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" + buffer@4.9.1: version "4.9.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" @@ -1835,6 +1859,10 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chardet@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + charm@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" @@ -2082,7 +2110,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.6, concat-stream@^1.4.7: +concat-stream@^1.4.7: version "1.6.1" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.1.tgz#261b8f518301f1d834e36342b9fea095d2620a26" dependencies: @@ -2090,6 +2118,15 @@ concat-stream@^1.4.6, concat-stream@^1.4.7: readable-stream "^2.2.2" typedarray "^0.0.6" +concat-stream@^1.6.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + configstore@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" @@ -2436,12 +2473,11 @@ diff@^3.2.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" -doctrine@^1.2.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" dependencies: esutils "^2.0.2" - isarray "^1.0.0" dot-prop@^3.0.0: version "3.0.0" @@ -2502,7 +2538,7 @@ ember-cli-babel@6.12.0, ember-cli-babel@^6.0.0, ember-cli-babel@^6.10.0, ember-c ember-cli-version-checker "^2.1.0" semver "^5.4.1" -ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.5, ember-cli-babel@^5.1.6, ember-cli-babel@^5.2.1: +ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.6, ember-cli-babel@^5.2.1: version "5.2.4" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" dependencies: @@ -2544,13 +2580,14 @@ ember-cli-dependency-checker@^2.1.0: resolve "^1.5.0" semver "^5.3.0" -ember-cli-eslint@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/ember-cli-eslint/-/ember-cli-eslint-1.3.0.tgz#8a7eda0d7e6a00c5a5a823f59664932d6429a8f1" +ember-cli-eslint@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/ember-cli-eslint/-/ember-cli-eslint-4.2.3.tgz#2844d3f5e8184f19b2d7132ba99eb0b370b55598" dependencies: - broccoli-lint-eslint "^2.0.0" - ember-cli-babel "^5.1.5" - js-string-escape "^1.0.0" + broccoli-lint-eslint "^4.2.1" + ember-cli-version-checker "^2.1.0" + rsvp "^4.6.1" + walk-sync "^0.3.0" ember-cli-get-component-path-option@^1.0.0: version "1.0.0" @@ -3086,14 +3123,14 @@ error@^7.0.0: string-template "~0.2.1" xtend "~4.0.0" -es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: +es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: version "0.10.39" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.39.tgz#fca21b67559277ca4ac1a1ed7048b107b6f76d87" dependencies: es6-iterator "~2.0.3" es6-symbol "~3.1.1" -es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3: +es6-iterator@~2.0.1, es6-iterator@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" dependencies: @@ -3101,7 +3138,7 @@ es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3: es5-ext "^0.10.35" es6-symbol "^3.1.1" -es6-map@^0.1.3, es6-map@^0.1.5: +es6-map@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" dependencies: @@ -3129,15 +3166,6 @@ es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: d "1" es5-ext "~0.10.14" -es6-weak-map@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" - dependencies: - d "1" - es5-ext "^0.10.14" - es6-iterator "^2.0.1" - es6-symbol "^3.1.1" - escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -3150,15 +3178,6 @@ escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^ version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -escope@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" - dependencies: - es6-map "^0.1.3" - es6-weak-map "^2.0.1" - esrecurse "^4.1.0" - estraverse "^4.1.1" - eslint-plugin-node@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz#bf19642298064379315d7a4b2a75937376fa05e4" @@ -3168,45 +3187,61 @@ eslint-plugin-node@^6.0.1: resolve "^1.3.3" semver "^5.4.1" -eslint@^2.13.0: - version "2.13.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" +eslint-scope@^3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" dependencies: - chalk "^1.1.3" - concat-stream "^1.4.6" - debug "^2.1.1" - doctrine "^1.2.2" - es6-map "^0.1.3" - escope "^3.6.0" - espree "^3.1.6" - estraverse "^4.2.0" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + +eslint@^4.0.0: + version "4.19.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" + dependencies: + ajv "^5.3.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" + espree "^3.5.4" + esquery "^1.0.0" esutils "^2.0.2" - file-entry-cache "^1.1.1" - glob "^7.0.3" - globals "^9.2.0" - ignore "^3.1.2" + file-entry-cache "^2.0.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.0.1" + ignore "^3.3.3" imurmurhash "^0.1.4" - inquirer "^0.12.0" - is-my-json-valid "^2.10.0" + inquirer "^3.0.6" is-resolvable "^1.0.0" - js-yaml "^3.5.1" - json-stable-stringify "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" - lodash "^4.0.0" - mkdirp "^0.5.0" - optionator "^0.8.1" - path-is-absolute "^1.0.0" - path-is-inside "^1.0.1" - pluralize "^1.2.1" - progress "^1.1.8" - require-uncached "^1.0.2" - shelljs "^0.6.0" - strip-json-comments "~1.0.1" - table "^3.7.8" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + regexpp "^1.0.1" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" + strip-json-comments "~2.0.1" + table "4.0.2" text-table "~0.2.0" - user-home "^2.0.0" -espree@^3.1.6: +espree@^3.5.4: version "3.5.4" resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" dependencies: @@ -3241,13 +3276,19 @@ esprimaq@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" +esquery@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + dependencies: + estraverse "^4.0.0" + esrecurse@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" dependencies: estraverse "^4.1.0" -estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" @@ -3436,6 +3477,14 @@ external-editor@^1.1.0: spawn-sync "^1.0.15" tmp "^0.0.29" +external-editor@^2.0.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" @@ -3467,6 +3516,14 @@ fake-xml-http-request@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-1.6.0.tgz#bd0ac79ae3e2660098282048a12c730a6f64d550" +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" @@ -3502,22 +3559,15 @@ fb-watchman@^2.0.0: dependencies: bser "^2.0.0" -figures@^1.3.5: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" - figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" dependencies: escape-string-regexp "^1.0.5" -file-entry-cache@^1.1.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" dependencies: flat-cache "^1.2.1" object-assign "^4.0.1" @@ -3800,6 +3850,10 @@ fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: mkdirp ">=0.5 0" rimraf "2" +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -3813,16 +3867,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -generate-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - dependencies: - is-property "^1.0.0" - get-caller-file@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" @@ -3923,7 +3967,7 @@ glob@^5.0.10, glob@^5.0.13, glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0: +glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -3968,11 +4012,15 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" +globals@^11.0.1: + version "11.5.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.5.0.tgz#6bc840de6771173b191f13d3a9c94d441ee92642" + globals@^6.4.0: version "6.4.1" resolved "https://registry.yarnpkg.com/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" -globals@^9.18.0, globals@^9.2.0: +globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -4260,15 +4308,17 @@ iconv-lite@0.4.19, iconv-lite@^0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" +iconv-lite@^0.4.17: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + dependencies: + safer-buffer ">= 2.1.2 < 3" + ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" -ignore@^3.1.2: - version "3.3.7" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" - -ignore@^3.3.6: +ignore@^3.3.3, ignore@^3.3.6: version "3.3.8" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.8.tgz#3f8e9c35d38708a3a7e0e9abb6c73e7ee7707b2b" @@ -4319,24 +4369,6 @@ inline-source-map-comment@^1.0.5: sum-up "^1.0.1" xtend "^4.0.0" -inquirer@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" - dependencies: - ansi-escapes "^1.1.0" - ansi-regex "^2.0.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" - cli-width "^2.0.0" - figures "^1.3.5" - lodash "^4.3.0" - readline2 "^1.0.1" - run-async "^0.1.0" - rx-lite "^3.1.2" - string-width "^1.0.1" - strip-ansi "^3.0.0" - through "^2.3.6" - inquirer@^2: version "2.0.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-2.0.0.tgz#e1351687b90d150ca403ceaa3cefb1e3065bef4b" @@ -4356,6 +4388,25 @@ inquirer@^2: strip-ansi "^3.0.0" through "^2.3.6" +inquirer@^3.0.6: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.0.4" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + into-stream@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" @@ -4507,20 +4558,6 @@ is-integer@^1.0.4: dependencies: is-finite "^1.0.0" -is-my-ip-valid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824" - -is-my-json-valid@^2.10.0: - version "2.17.2" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz#6b2103a288e94ef3de5cf15d29dd85fc4b78d65c" - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - is-my-ip-valid "^1.0.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" @@ -4589,10 +4626,6 @@ is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" -is-property@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - is-reference@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/is-reference/-/is-reference-1.1.0.tgz#50e6ef3f64c361e2c53c0416cdc9420037f2685b" @@ -4701,10 +4734,6 @@ js-reporters@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b" -js-string-escape@^1.0.0, js-string-escape@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" - js-tokens@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" @@ -4713,7 +4742,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" -js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.5.1, js-yaml@^3.6.1: +js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.6.1, js-yaml@^3.9.1: version "3.11.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" dependencies: @@ -4728,6 +4757,10 @@ jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" +jsesc@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + jsesc@~0.3.x: version "0.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.3.0.tgz#1bf5ee63b4539fe2e26d0c1e99c240b97a457972" @@ -4740,10 +4773,18 @@ json-buffer@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" @@ -4782,10 +4823,6 @@ jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -5340,9 +5377,9 @@ matcher-collection@^1.0.0, matcher-collection@^1.0.4, matcher-collection@^1.0.5: dependencies: minimatch "^3.0.2" -md5-hex@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" +md5-hex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-2.0.0.tgz#d0588e9f1c74954492ecd24ac0ac6ce997d92e33" dependencies: md5-o-matic "^0.1.1" @@ -5591,14 +5628,14 @@ mustache@^2.2.1: version "2.3.0" resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" -mute-stream@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" - mute-stream@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + nan@^2.3.0: version "2.9.2" resolved "https://registry.yarnpkg.com/nan/-/nan-2.9.2.tgz#f564d75f5f8f36a6d9456cca7a6c4fe488ab7866" @@ -5620,6 +5657,10 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" @@ -5816,7 +5857,7 @@ optimist@^0.6.1: minimist "~0.0.1" wordwrap "~0.0.2" -optionator@^0.8.1: +optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: @@ -5856,7 +5897,7 @@ os-shim@^0.1.2: version "0.1.3" resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -5982,7 +6023,7 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-is-inside@^1.0.1: +path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" @@ -6042,9 +6083,9 @@ plur@^2.1.2: dependencies: irregular-plurals "^1.0.0" -pluralize@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" +pluralize@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" portfinder@^1.0.7: version "1.0.13" @@ -6106,9 +6147,9 @@ process-relative-require@^1.0.0: dependencies: node-modules-path "^1.0.0" -progress@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" +progress@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" promise-map-series@^0.2.1: version "0.2.3" @@ -6284,14 +6325,6 @@ readdirp@^2.0.0: readable-stream "^2.0.2" set-immediate-shim "^1.0.1" -readline2@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - mute-stream "0.0.5" - recast@0.10.33: version "0.10.33" resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" @@ -6376,6 +6409,10 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexpp@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" + regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -6478,7 +6515,7 @@ require-relative@^0.8.7: version "0.8.7" resolved "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" -require-uncached@^1.0.2: +require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" dependencies: @@ -6598,7 +6635,7 @@ rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0. version "3.6.2" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" -rsvp@^4.7.0: +rsvp@^4.6.1, rsvp@^4.7.0: version "4.8.2" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.2.tgz#9d5647108735784eb13418cdddb56f75b919d722" @@ -6610,21 +6647,21 @@ rsvp@~3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" -run-async@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" - dependencies: - once "^1.3.0" - run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" dependencies: is-promise "^2.1.0" -rx-lite@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" rx@^4.1.0: version "4.1.0" @@ -6644,6 +6681,10 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + sane@^1.4.1: version "1.7.0" resolved "https://registry.yarnpkg.com/sane/-/sane-1.7.0.tgz#b3579bccb45c94cf20355cc81124990dfd346e30" @@ -6775,10 +6816,6 @@ shelljs@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.2.6.tgz#90492d72ffcc8159976baba62fb0f6884f0c3378" -shelljs@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" - shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" @@ -6809,9 +6846,11 @@ slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" -slice-ansi@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" +slice-ansi@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + dependencies: + is-fullwidth-code-point "^2.0.0" slide@^1.1.5: version "1.1.6" @@ -7093,7 +7132,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0: +string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: @@ -7167,10 +7206,6 @@ strip-indent@^1.0.1: dependencies: get-stdin "^4.0.1" -strip-json-comments@~1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" - strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -7207,16 +7242,16 @@ symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: version "1.2.0" resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" -table@^3.7.8: - version "3.8.3" - resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" +table@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" dependencies: - ajv "^4.7.0" - ajv-keywords "^1.0.0" - chalk "^1.1.1" - lodash "^4.0.0" - slice-ansi "0.0.4" - string-width "^2.0.0" + ajv "^5.2.3" + ajv-keywords "^2.1.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" tap-parser@^5.1.0: version "5.4.0" @@ -7383,6 +7418,12 @@ tmp@^0.0.29: dependencies: os-tmpdir "~1.0.1" +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -7608,12 +7649,6 @@ user-home@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" -user-home@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" - dependencies: - os-homedir "^1.0.0" - user-info@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/user-info/-/user-info-1.0.0.tgz#81c82b7ed63e674c2475667653413b3c76fde239" From 48b1c69cb22997d156ef5e72dcb7843af36c6bce Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 8 May 2018 17:06:30 -0700 Subject: [PATCH 2232/2527] Fix eslint failures. --- .npmignore | 2 ++ bin/publish-builds | 2 +- bin/publish-to-s3.js | 2 -- index.js | 1 + lib/babel-build.js | 1 - lib/calculate-version.js | 5 +++-- lib/stripped-build-plugins.js | 1 + lib/stripped-build.js | 4 ---- lib/utilities/extend-from-application-entity.js | 2 +- lib/yuidoc.js | 1 - node-tests/nodetest-runner.js | 2 ++ package.json | 2 +- tests/dummy/config/environment.js | 4 ---- tests/integration/record-array-manager-test.js | 2 +- yarn.lock | 2 +- 15 files changed, 14 insertions(+), 19 deletions(-) diff --git a/.npmignore b/.npmignore index a77a4b041d4..4a0e13d6067 100644 --- a/.npmignore +++ b/.npmignore @@ -25,3 +25,5 @@ testem.js *.gemspec **/*.rb node-tests/ +lib/yuidoc.js +lib/version-replace.js diff --git a/bin/publish-builds b/bin/publish-builds index 1842d996b27..6d23a328c40 100755 --- a/bin/publish-builds +++ b/bin/publish-builds @@ -4,5 +4,5 @@ echo -e "CURRENT_BRANCH: ${TRAVIS_BRANCH}\n" echo -e "PULL_REQUEST: ${TRAVIS_PULL_REQUEST}\n" if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then - ./bin/publish-to-s3.js + node ./bin/publish-to-s3.js fi diff --git a/bin/publish-to-s3.js b/bin/publish-to-s3.js index d01b3febc36..9147180f8a6 100755 --- a/bin/publish-to-s3.js +++ b/bin/publish-to-s3.js @@ -1,5 +1,3 @@ -#!/usr/bin/env node - // This publish script remains in order to publish the yui-docs to S3, builds no // longer need to be published to S3. // diff --git a/index.js b/index.js index 3fc1d791c0c..4ea77e5639a 100644 --- a/index.js +++ b/index.js @@ -59,6 +59,7 @@ module.exports = { } else if (this.ui) { this.ui.writeLine(warning); } else { + // eslint-disable-next-line no-console console.log(warning); } }, diff --git a/lib/babel-build.js b/lib/babel-build.js index 4f36eadbb90..6c700db9775 100644 --- a/lib/babel-build.js +++ b/lib/babel-build.js @@ -1,7 +1,6 @@ 'use strict'; var babel = require('broccoli-babel-transpiler'); -var path = require('path'); var moduleResolve = require('amd-name-resolver').moduleResolve; function getDebugMacroPlugins() { diff --git a/lib/calculate-version.js b/lib/calculate-version.js index f3d937c3c9b..4ad045dd94f 100644 --- a/lib/calculate-version.js +++ b/lib/calculate-version.js @@ -9,15 +9,16 @@ module.exports = function() { var packageVersion = package.version; var suffix = ''; + var info; if (fs.existsSync(gitPath)) { - var info = gitRepoInfo(gitPath); + info = gitRepoInfo(gitPath); if (info.tag) { return info.tag.replace(/^v/, ''); } suffix = '+' + info.sha.slice(0, 10); } else { - var info = npmGitInfo(package); + info = npmGitInfo(package); if (info.isInstalledAsNpmPackage() && !info.hasVersionInRef()) { suffix = '+' + info.abbreviatedSha; } diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 9e76f19f56e..8302ab7ae43 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -70,6 +70,7 @@ module.exports = function(environment) { plugins.push([StripHeimdall]); uniqueAdd(filteredImports, 'ember-data/-debug', ['instrument']); } else { + // eslint-disable-next-line no-console console.warn('NOT STRIPPING HEIMDALL'); } diff --git a/lib/stripped-build.js b/lib/stripped-build.js index d59b2677a67..19ea9404ca4 100644 --- a/lib/stripped-build.js +++ b/lib/stripped-build.js @@ -1,7 +1,3 @@ -var fs = require('fs'); -var path = require('path'); -var filterImports = require('babel-plugin-filter-imports'); -var featureFlags = require('babel-plugin-feature-flags'); var babelBuild = require('./babel-build'); var strippedBuildPlugins = require('./stripped-build-plugins'); diff --git a/lib/utilities/extend-from-application-entity.js b/lib/utilities/extend-from-application-entity.js index cd958854cb7..c166356d738 100644 --- a/lib/utilities/extend-from-application-entity.js +++ b/lib/utilities/extend-from-application-entity.js @@ -26,7 +26,7 @@ module.exports = function(type, baseClass, options) { var importStatement = 'import DS from \'ember-data\';'; if (options.baseClass) { - baseClass = stringUtil.classify(options.baseClass.replace('\/', '-')); + baseClass = stringUtil.classify(options.baseClass.replace('/', '-')); baseClass = baseClass + stringUtil.classify(type); importStatement = 'import ' + baseClass + ' from \'' + relativePath + options.baseClass + '\';'; } diff --git a/lib/yuidoc.js b/lib/yuidoc.js index 3292300894f..37f201b3dd2 100644 --- a/lib/yuidoc.js +++ b/lib/yuidoc.js @@ -1,6 +1,5 @@ var YUIDoc = require('broccoli-yuidoc'); var calculateVersion = require('./calculate-version'); -var path = require('path'); module.exports = function yui() { return new YUIDoc(['addon', 'node_modules/ember-inflector/addon'], { diff --git a/node-tests/nodetest-runner.js b/node-tests/nodetest-runner.js index 4f3fb1b12a6..caf05ba204b 100644 --- a/node-tests/nodetest-runner.js +++ b/node-tests/nodetest-runner.js @@ -1,5 +1,7 @@ 'use strict'; +/* eslint-disable no-console, no-process-exit */ + if (/^win/.test(require('os').platform())){ // don't run these tests in windows right now, they don't work process.exit(0); diff --git a/package.json b/package.json index 9a652aa965a..d9c6d7dd7d7 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "dependencies": { "@ember/ordered-set": "^1.0.0", "amd-name-resolver": "0.0.7", + "babel-plugin-debug-macros": "^0.1.11", "babel-plugin-ember-modules-api-polyfill": "^1.4.2", "babel-plugin-feature-flags": "^0.3.1", "babel-plugin-filter-imports": "^0.3.1", @@ -52,7 +53,6 @@ "silent-error": "^1.0.0" }, "devDependencies": { - "babel-plugin-debug-macros": "^0.1.7", "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", "babel-plugin-transform-es2015-classes": "^6.23.0", "babel-plugin-transform-es2015-computed-properties": "^6.22.0", diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index 0c9597834e4..81d1ede135d 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -47,9 +47,5 @@ module.exports = function(environment) { ENV.APP.rootElement = '#ember-testing'; } - if (environment === 'production') { - - } - return ENV; }; diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index d46e0ea72a2..dad551c5fcb 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -242,7 +242,7 @@ test('createRecordArray', function(assert) { assert.deepEqual(recordArray.toArray(), []); }); -test('createRecordArray \w optional content', function(assert) { +test('createRecordArray with optional content', function(assert) { let record = {}; let internalModel = { _recordArrays: new OrderedSet(), diff --git a/yarn.lock b/yarn.lock index 8e222a26ed6..45f086910b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -628,7 +628,7 @@ babel-plugin-dead-code-elimination@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" -babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.11, babel-plugin-debug-macros@^0.1.7: +babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.11: version "0.1.11" resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" dependencies: From 67ac66b001e47c55ed48bca0f37636766d39f54d Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 8 May 2018 17:09:41 -0700 Subject: [PATCH 2233/2527] Add prettier configuration to eslint. --- .eslintrc.js | 5 ++++- .prettierrc.js | 7 +++++++ package.json | 3 +++ yarn.lock | 29 +++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 .prettierrc.js diff --git a/.eslintrc.js b/.eslintrc.js index bd0d11a2de7..eec3bbc74e7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,8 +4,11 @@ module.exports = { ecmaVersion: 2017, sourceType: 'module', }, - extends: ['eslint:recommended'], + extends: ['eslint:recommended', 'prettier'], + plugins: ['prettier'], rules: { + 'prettier/prettier': 'error', + 'no-unused-vars': ['error', { 'args': 'none', }], diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 00000000000..978b4d511ea --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,7 @@ +'use strict'; + +module.exports = { + singleQuote: true, + trailingComma: 'es5', + printWidth: 100, +}; diff --git a/package.json b/package.json index d9c6d7dd7d7..14e80cbdf2e 100644 --- a/package.json +++ b/package.json @@ -99,12 +99,15 @@ "ember-source-channel-url": "^1.0.1", "ember-try": "^0.2.23", "ember-watson": "^0.7.0", + "eslint-config-prettier": "^2.9.0", "eslint-plugin-node": "^6.0.1", + "eslint-plugin-prettier": "^2.6.0", "github": "^1.1.1", "glob": "^5.0.13", "loader.js": "^4.5.0", "mocha": "^2.4.5", "mocha-only-detector": "0.0.2", + "prettier": "^1.12.1", "rimraf": "2.5.2", "rsvp": "4.8.0", "testdouble": "^3.2.6", diff --git a/yarn.lock b/yarn.lock index 45f086910b9..27aafafdff9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3178,6 +3178,12 @@ escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^ version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" +eslint-config-prettier@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" + dependencies: + get-stdin "^5.0.1" + eslint-plugin-node@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz#bf19642298064379315d7a4b2a75937376fa05e4" @@ -3187,6 +3193,13 @@ eslint-plugin-node@^6.0.1: resolve "^1.3.3" semver "^5.4.1" +eslint-plugin-prettier@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz#33e4e228bdb06142d03c560ce04ec23f6c767dd7" + dependencies: + fast-diff "^1.1.1" + jest-docblock "^21.0.0" + eslint-scope@^3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" @@ -3520,6 +3533,10 @@ fast-deep-equal@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" +fast-diff@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" + fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -3879,6 +3896,10 @@ get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" +get-stdin@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" + get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -4722,6 +4743,10 @@ jade@0.26.3: commander "0.6.1" mkdirp "0.3.0" +jest-docblock@^21.0.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" + jmespath@0.15.0: version "0.15.0" resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" @@ -6118,6 +6143,10 @@ pretender@^1.4.2: fake-xml-http-request "^1.6.0" route-recognizer "^0.3.3" +prettier@^1.12.1: + version "1.12.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325" + pretty-ms@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/pretty-ms/-/pretty-ms-3.1.0.tgz#e9cac9c76bf6ee52fe942dd9c6c4213153b12881" From 1ae7502592aafd5f83e1e40c7a07d5dfc21b9773 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 8 May 2018 17:11:55 -0700 Subject: [PATCH 2234/2527] Add `yarn lint:js` script. --- .travis.yml | 1 + package.json | 1 + 2 files changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1f6d6bdacb8..7503f1bb1c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,6 +35,7 @@ jobs: env: NAME=test # used only to make Travis UI show description script: - ./bin/lint-features + - yarn lint:js - yarn test - stage: additional tests diff --git a/package.json b/package.json index 14e80cbdf2e..375a360cd77 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "scripts": { "build": "ember build", "build:production": "ember build --environment=production", + "lint:js": "eslint .", "start": "ember server", "test": "ember test && ember test --record-data-rfc-build", "test:all": "ember try:each", From 5ae301c62baa9539192b1755175dd5c323d35f2e Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Tue, 8 May 2018 17:18:25 -0700 Subject: [PATCH 2235/2527] yarn eslint --fix . --- addon/-debug/index.js | 9 +- addon/-private/adapters/build-url-mixin.js | 26 +- addon/-private/adapters/errors.js | 29 +- addon/-private/attr.js | 14 +- addon/-private/core.js | 2 +- addon/-private/index.js | 19 +- addon/-private/system/backburner.js | 6 +- addon/-private/system/coerce-id.js | 8 +- addon/-private/system/debug/debug-adapter.js | 35 +- addon/-private/system/diff-array.js | 10 +- addon/-private/system/identity-map.js | 1 - addon/-private/system/internal-model-map.js | 26 +- addon/-private/system/is-array-like.js | 20 +- addon/-private/system/many-array.js | 33 +- addon/-private/system/map.js | 46 +- addon/-private/system/model/errors.js | 40 +- addon/-private/system/model/internal-model.js | 203 +- addon/-private/system/model/model.js | 187 +- addon/-private/system/model/states.js | 92 +- addon/-private/system/normalize-link.js | 6 +- addon/-private/system/promise-proxies.js | 29 +- addon/-private/system/record-array-manager.js | 54 +- addon/-private/system/record-arrays.js | 9 +- .../adapter-populated-record-array.js | 8 +- .../system/record-arrays/record-array.js | 31 +- .../-private/system/references/belongs-to.js | 23 +- addon/-private/system/references/has-many.js | 18 +- addon/-private/system/references/record.js | 3 +- addon/-private/system/references/reference.js | 2 +- .../system/relationships/belongs-to.js | 37 +- addon/-private/system/relationships/ext.js | 23 +- .../-private/system/relationships/has-many.js | 13 +- .../relationship-payloads-manager.js | 29 +- .../relationships/relationship-payloads.js | 72 +- .../system/relationships/state/belongs-to.js | 67 +- .../system/relationships/state/create.js | 22 +- .../system/relationships/state/has-many.js | 54 +- .../relationships/state/relationship.js | 82 +- addon/-private/system/snapshot.js | 36 +- addon/-private/system/store.js | 618 ++- addon/-private/system/store/common.js | 16 +- addon/-private/system/store/finders.js | 340 +- .../system/store/serializer-response.js | 25 +- addon/-private/system/store/serializers.js | 4 +- addon/-private/utils.js | 11 +- .../adapters/build-url-mixin.js | 26 +- .../adapters/errors.js | 29 +- addon/-record-data-rfc-private/attr.js | 10 +- addon/-record-data-rfc-private/core.js | 2 +- addon/-record-data-rfc-private/index.js | 15 +- .../system/backburner.js | 6 +- .../system/coerce-id.js | 8 +- .../system/debug/debug-adapter.js | 35 +- .../system/diff-array.js | 10 +- .../system/identity-map.js | 1 - .../system/internal-model-map.js | 26 +- .../system/is-array-like.js | 20 +- .../system/many-array.js | 40 +- addon/-record-data-rfc-private/system/map.js | 46 +- .../system/model/errors.js | 40 +- .../system/model/internal-model.js | 239 +- .../system/model/model-data.js | 118 +- .../system/model/model.js | 184 +- .../system/model/states.js | 92 +- .../system/normalize-link.js | 6 +- .../system/promise-proxies.js | 32 +- .../system/record-array-manager.js | 55 +- .../system/record-arrays.js | 9 +- .../adapter-populated-record-array.js | 8 +- .../system/record-arrays/record-array.js | 31 +- .../system/references/belongs-to.js | 30 +- .../system/references/has-many.js | 24 +- .../system/references/record.js | 3 +- .../system/references/reference.js | 6 +- .../system/relationships/belongs-to.js | 37 +- .../system/relationships/ext.js | 23 +- .../system/relationships/has-many.js | 13 +- .../system/relationships/state/belongs-to.js | 48 +- .../system/relationships/state/create.js | 28 +- .../system/relationships/state/has-many.js | 32 +- .../relationships/state/relationship.js | 92 +- .../system/snapshot.js | 26 +- .../-record-data-rfc-private/system/store.js | 627 ++- .../system/store/common.js | 16 +- .../system/store/finders.js | 340 +- .../system/store/model-data-wrapper.js | 5 +- .../system/store/serializer-response.js | 25 +- .../system/store/serializers.js | 4 +- addon/-record-data-rfc-private/utils.js | 11 +- addon/adapter.js | 6 +- addon/adapters/errors.js | 2 +- addon/adapters/json-api.js | 6 +- addon/adapters/rest.js | 88 +- addon/index.js | 64 +- addon/serializer.js | 4 +- addon/serializers/embedded-records-mixin.js | 42 +- addon/serializers/json-api.js | 91 +- addon/serializers/json.js | 82 +- addon/serializers/rest.js | 75 +- addon/setup-container.js | 6 +- addon/transforms/boolean.js | 8 +- addon/transforms/date.js | 8 +- addon/transforms/number.js | 2 +- addon/transforms/string.js | 2 +- addon/transforms/transform.js | 2 +- app/initializers/ember-data.js | 2 +- app/instance-initializers/ember-data.js | 4 +- bin/publish-to-s3.js | 2 +- blueprints/adapter-test/index.js | 4 +- blueprints/adapter/index.js | 6 +- blueprints/model-test/index.js | 4 +- blueprints/model/index.js | 33 +- blueprints/serializer-test/index.js | 4 +- blueprints/serializer/index.js | 6 +- blueprints/test-framework-detector.js | 10 +- blueprints/transform-test/index.js | 4 +- blueprints/transform/index.js | 2 +- config/ember-try.js | 42 +- config/environment.js | 2 +- config/s3ProjectConfig.js | 69 +- ember-cli-build.js | 6 +- index.js | 44 +- lib/babel-build.js | 50 +- lib/enable-optional-features-via-url/index.js | 26 +- ...allow-multiple-var-decl-with-assignment.js | 10 +- .../disallow-space-before-semicolon.js | 2 +- ...-inside-round-braces-in-call-expression.js | 23 +- ...ing-parenthesis-in-function-declaration.js | 22 +- lib/stripped-build-plugins.js | 21 +- lib/stripped-build.js | 2 +- lib/transforms/babel-plugin-remove-imports.js | 7 +- .../extend-from-application-entity.js | 32 +- lib/version-replace.js | 4 +- lib/yuidoc.js | 23 +- node-tests/blueprints/adapter-test.js | 81 +- node-tests/blueprints/model-test.js | 98 +- node-tests/blueprints/serializer-test.js | 80 +- node-tests/blueprints/transform-test.js | 26 +- .../helpers/generate-fake-package-manifest.js | 9 +- node-tests/nodetest-runner.js | 12 +- .../unit/babel-plugin-remove-imports-test.js | 82 +- testem.js | 24 +- tests/dummy/app/app.js | 2 +- tests/dummy/app/router.js | 2 +- tests/dummy/app/routes/application/route.js | 3 +- tests/dummy/config/environment.js | 4 +- tests/helpers/async.js | 14 +- tests/helpers/module-for-acceptance.js | 2 +- tests/helpers/resolver.js | 2 +- tests/helpers/store.js | 17 +- tests/helpers/watch-property.js | 55 +- .../adapter/build-url-mixin-test.js | 194 +- .../adapter/client-side-delete-test.js | 101 +- tests/integration/adapter/find-all-test.js | 317 +- tests/integration/adapter/find-test.js | 171 +- .../adapter/json-api-adapter-test.js | 1040 ++--- tests/integration/adapter/queries-test.js | 131 +- .../adapter/record-persistence-test.js | 365 +- .../integration/adapter/rest-adapter-test.js | 2366 ++++++----- tests/integration/adapter/serialize-test.js | 8 +- .../integration/adapter/store-adapter-test.js | 1429 ++++--- tests/integration/application-test.js | 75 +- .../non-dasherized-lookups-test.js | 166 +- .../integration/client-id-generation-test.js | 22 +- tests/integration/debug-adapter-test.js | 31 +- tests/integration/injection-test.js | 24 +- tests/integration/inverse-test.js | 110 +- tests/integration/lifecycle-hooks-test.js | 30 +- tests/integration/multiple-stores-test.js | 196 +- tests/integration/peek-all-test.js | 63 +- .../polymorphic-belongs-to-test.js | 76 +- .../integration/record-array-manager-test.js | 185 +- tests/integration/record-array-test.js | 374 +- .../adapter-populated-record-array-test.js | 176 +- .../record-arrays/peeked-records-test.js | 107 +- .../records/collection-save-test.js | 21 +- .../integration/records/delete-record-test.js | 190 +- tests/integration/records/error-test.js | 62 +- tests/integration/records/load-test.js | 8 +- .../records/property-changes-test.js | 48 +- .../records/relationship-changes-test.js | 395 +- tests/integration/records/reload-test.js | 211 +- .../integration/records/rematerialize-test.js | 154 +- tests/integration/records/save-test.js | 60 +- tests/integration/records/unload-test.js | 2472 +++++++----- .../integration/references/belongs-to-test.js | 315 +- tests/integration/references/has-many-test.js | 416 +- tests/integration/references/record-test.js | 98 +- .../relationships/belongs-to-test.js | 1148 +++--- .../relationships/has-many-test.js | 2966 +++++++------- .../inverse-relationships-test.js | 398 +- .../relationships/json-api-links-test.js | 1498 +++---- .../relationships/many-to-many-test.js | 362 +- .../relationships/nested-relationship-test.js | 69 +- .../relationships/one-to-many-test.js | 1107 +++--- .../relationships/one-to-one-test.js | 551 +-- .../polymorphic-mixins-belongs-to-test.js | 289 +- .../polymorphic-mixins-has-many-test.js | 339 +- .../embedded-records-mixin-test.js | 3447 +++++++++-------- .../serializers/json-api-serializer-test.js | 556 +-- .../serializers/json-serializer-test.js | 1111 +++--- .../serializers/rest-serializer-test.js | 750 ++-- tests/integration/setup-container-test.js | 19 +- tests/integration/snapshot-test.js | 897 +++-- tests/integration/store-test.js | 683 ++-- .../store/json-api-validation-test.js | 342 +- tests/integration/store/query-record-test.js | 94 +- tests/integration/store/query-test.js | 21 +- tests/test-helper.js | 33 +- tests/unit/adapter-errors-test.js | 22 +- .../build-url-mixin/build-url-test.js | 12 +- .../build-url-mixin/path-for-type-test.js | 13 +- .../adapters/json-api-adapter/ajax-test.js | 22 +- tests/unit/adapters/rest-adapter/ajax-test.js | 35 +- .../rest-adapter/detailed-message-test.js | 47 +- .../group-records-for-find-many-test.js | 92 +- tests/unit/debug-test.js | 64 +- tests/unit/diff-array-test.js | 153 +- tests/unit/many-array-test.js | 82 +- tests/unit/model-test.js | 799 ++-- tests/unit/model/errors-test.js | 11 +- tests/unit/model/init-properties-test.js | 175 +- tests/unit/model/lifecycle-callbacks-test.js | 121 +- tests/unit/model/merge-test.js | 118 +- tests/unit/model/relationships-test.js | 20 +- .../model/relationships/belongs-to-test.js | 515 +-- .../unit/model/relationships/has-many-test.js | 1621 ++++---- .../model/relationships/record-array-test.js | 64 +- tests/unit/model/rollback-attributes-test.js | 266 +- tests/unit/modules-test.js | 7 +- tests/unit/private-test.js | 5 +- tests/unit/promise-proxies-test.js | 9 +- .../adapter-populated-record-array-test.js | 69 +- tests/unit/record-arrays/record-array-test.js | 247 +- tests/unit/states-test.js | 14 +- tests/unit/store/adapter-interop-test.js | 586 +-- tests/unit/store/asserts-test.js | 4 +- tests/unit/store/create-record-test.js | 62 +- tests/unit/store/finders-test.js | 148 +- tests/unit/store/has-model-for-test.js | 8 +- tests/unit/store/has-record-for-id-test.js | 52 +- tests/unit/store/lookup-test.js | 62 +- tests/unit/store/model-for-test.js | 16 +- tests/unit/store/peek-record-test.js | 24 +- tests/unit/store/push-test.js | 699 ++-- tests/unit/store/serializer-for-test.js | 17 +- tests/unit/store/unload-test.js | 103 +- .../polymorphic-relationship-payloads-test.js | 447 +-- .../unit/system/snapshot-record-array-test.js | 14 +- tests/unit/transform/boolean-test.js | 2 +- tests/unit/transform/number-test.js | 2 +- tests/unit/utils-test.js | 76 +- .../unit/utils/parse-response-headers-test.js | 52 +- 253 files changed, 23955 insertions(+), 18292 deletions(-) diff --git a/addon/-debug/index.js b/addon/-debug/index.js index 7d8fc71c211..240e5031959 100644 --- a/addon/-debug/index.js +++ b/addon/-debug/index.js @@ -40,7 +40,12 @@ if (DEBUG) { return modelClass.detect(addedModelClass); }; - assertPolymorphicType = function assertPolymorphicType(parentInternalModel, relationshipMeta, addedInternalModel, store) { + assertPolymorphicType = function assertPolymorphicType( + parentInternalModel, + relationshipMeta, + addedInternalModel, + store + ) { let addedModelName = addedInternalModel.modelName; let parentModelName = parentInternalModel.modelName; let key = relationshipMeta.key; @@ -53,4 +58,4 @@ if (DEBUG) { }; } -export { assertPolymorphicType } +export { assertPolymorphicType }; diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index 2472a83d31a..d1552ae675f 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -94,11 +94,17 @@ export default Mixin.create({ if (modelName) { path = this.pathForType(modelName); - if (path) { url.push(path); } + if (path) { + url.push(path); + } } - if (id) { url.push(encodeURIComponent(id)); } - if (prefix) { url.unshift(prefix); } + if (id) { + url.push(encodeURIComponent(id)); + } + if (prefix) { + url.unshift(prefix); + } url = url.join('/'); if (!host && url && url.charAt(0) !== '/') { @@ -392,10 +398,10 @@ export default Mixin.create({ // Do nothing, the full host is already included. return path; - // Absolute path + // Absolute path } else if (path.charAt(0) === '/') { return `${host}${path}`; - // Relative path + // Relative path } else { return `${parentURL}/${path}`; } @@ -403,8 +409,12 @@ export default Mixin.create({ // No path provided let url = []; - if (host) { url.push(host); } - if (namespace) { url.push(namespace); } + if (host) { + url.push(host); + } + if (namespace) { + url.push(namespace); + } return url.join('/'); }, @@ -439,5 +449,5 @@ export default Mixin.create({ pathForType(modelName) { let camelized = camelize(modelName); return pluralize(camelized); - } + }, }); diff --git a/addon/-private/adapters/errors.js b/addon/-private/adapters/errors.js index ec8919818cf..8cfd7b978dd 100644 --- a/addon/-private/adapters/errors.js +++ b/addon/-private/adapters/errors.js @@ -81,8 +81,8 @@ export function AdapterError(errors, message = 'Adapter operation failed') { this.errors = errors || [ { title: 'Adapter Error', - detail: message - } + detail: message, + }, ]; } @@ -165,8 +165,10 @@ AdapterError.extend = extendFn(AdapterError); @class InvalidError @namespace DS */ -export const InvalidError = extend(AdapterError, - 'The adapter rejected the commit because it was invalid'); +export const InvalidError = extend( + AdapterError, + 'The adapter rejected the commit because it was invalid' +); /** A `DS.TimeoutError` is used by an adapter to signal that a request @@ -200,8 +202,7 @@ export const InvalidError = extend(AdapterError, @class TimeoutError @namespace DS */ -export const TimeoutError = extend(AdapterError, - 'The adapter operation timed out'); +export const TimeoutError = extend(AdapterError, 'The adapter operation timed out'); /** A `DS.AbortError` is used by an adapter to signal that a request to @@ -212,8 +213,7 @@ export const TimeoutError = extend(AdapterError, @class AbortError @namespace DS */ -export const AbortError = extend(AdapterError, - 'The adapter operation was aborted'); +export const AbortError = extend(AdapterError, 'The adapter operation was aborted'); /** A `DS.UnauthorizedError` equates to a HTTP `401 Unauthorized` response @@ -320,7 +320,10 @@ export const ConflictError = extend(AdapterError, 'The adapter operation failed @class ServerError @namespace DS */ -export const ServerError = extend(AdapterError, 'The adapter operation failed due to a server error'); +export const ServerError = extend( + AdapterError, + 'The adapter operation failed due to a server error' +); /** Convert an hash of errors into an array with errors in JSON-API format. @@ -372,7 +375,7 @@ export function errorsHashToArray(errors) { let out = []; if (isPresent(errors)) { - Object.keys(errors).forEach((key) => { + Object.keys(errors).forEach(key => { let messages = makeArray(errors[key]); for (let i = 0; i < messages.length; i++) { let title = 'Invalid Attribute'; @@ -385,8 +388,8 @@ export function errorsHashToArray(errors) { title: title, detail: messages[i], source: { - pointer: pointer - } + pointer: pointer, + }, }); } }); @@ -439,7 +442,7 @@ export function errorsArrayToHash(errors) { let out = {}; if (isPresent(errors)) { - errors.forEach((error) => { + errors.forEach(error => { if (error.source && error.source.pointer) { let key = error.source.pointer.match(SOURCE_POINTER_REGEXP); diff --git a/addon/-private/attr.js b/addon/-private/attr.js index ddbb80e3724..47d2947c6e6 100644 --- a/addon/-private/attr.js +++ b/addon/-private/attr.js @@ -10,16 +10,16 @@ function getDefaultValue(record, options, key) { return options.defaultValue.apply(null, arguments); } else { let defaultValue = options.defaultValue; - assert(`Non primitive defaultValues are not supported because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.`, - typeof defaultValue !== 'object' || defaultValue === null); + assert( + `Non primitive defaultValues are not supported because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.`, + typeof defaultValue !== 'object' || defaultValue === null + ); return defaultValue; } } function hasValue(record, key) { - return key in record._attributes || - key in record._inFlightAttributes || - key in record._data; + return key in record._attributes || key in record._inFlightAttributes || key in record._data; } /** @@ -118,7 +118,7 @@ export default function attr(type, options) { let meta = { type: type, isAttribute: true, - options: options + options: options, }; return computed({ @@ -132,6 +132,6 @@ export default function attr(type, options) { }, set(key, value) { return this._internalModel.setDirtyAttribute(key, value); - } + }, }).meta(meta); } diff --git a/addon/-private/core.js b/addon/-private/core.js index b16369a0ff4..70816f3c203 100644 --- a/addon/-private/core.js +++ b/addon/-private/core.js @@ -19,7 +19,7 @@ import VERSION from 'ember-data/version'; */ const DS = Ember.Namespace.create({ VERSION: VERSION, - name: "DS" + name: 'DS', }); if (Ember.libraries) { diff --git a/addon/-private/index.js b/addon/-private/index.js index 6cfb8a5da96..a1addb6ec09 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -1,7 +1,7 @@ // public export { default as Model } from './system/model/model'; export { default as Errors } from './system/model/errors'; -export { default as Store } from './system/store'; +export { default as Store } from './system/store'; export { default as DS } from './core'; export { default as belongsTo } from './system/relationships/belongs-to'; export { default as hasMany } from './system/relationships/has-many'; @@ -19,7 +19,7 @@ export { TimeoutError, AbortError, errorsHashToArray, - errorsArrayToHash + errorsArrayToHash, } from './adapters/errors'; // maybe public ? @@ -33,16 +33,9 @@ export { default as isEnabled } from './features'; export { default as RootState } from './system/model/states'; export { default as InternalModel } from './system/model/internal-model'; -export { - PromiseArray, - PromiseObject, - PromiseManyArray -} from './system/promise-proxies'; +export { PromiseArray, PromiseObject, PromiseManyArray } from './system/promise-proxies'; -export { - RecordArray, - AdapterPopulatedRecordArray -} from './system/record-arrays'; +export { RecordArray, AdapterPopulatedRecordArray } from './system/record-arrays'; export { default as ManyArray } from './system/many-array'; export { default as RecordArrayManager } from './system/record-array-manager'; @@ -56,6 +49,8 @@ export { default as DebugAdapter } from './system/debug/debug-adapter'; // Used by tests export { default as diffArray } from './system/diff-array'; -export { default as RelationshipPayloadsManager } from './system/relationships/relationship-payloads-manager'; +export { + default as RelationshipPayloadsManager, +} from './system/relationships/relationship-payloads-manager'; export { default as RelationshipPayloads } from './system/relationships/relationship-payloads'; export { default as SnapshotRecordArray } from './system/snapshot-record-array'; diff --git a/addon/-private/system/backburner.js b/addon/-private/system/backburner.js index 266c37c3b4b..7ac43f9b390 100644 --- a/addon/-private/system/backburner.js +++ b/addon/-private/system/backburner.js @@ -1,7 +1,11 @@ import Ember from 'ember'; import { DEBUG } from '@glimmer/env'; -const backburner = new Ember._Backburner(['normalizeRelationships', 'syncRelationships', 'finished']); +const backburner = new Ember._Backburner([ + 'normalizeRelationships', + 'syncRelationships', + 'finished', +]); if (DEBUG) { Ember.Test.registerWaiter(() => { diff --git a/addon/-private/system/coerce-id.js b/addon/-private/system/coerce-id.js index 8f8c305a98d..18173352148 100644 --- a/addon/-private/system/coerce-id.js +++ b/addon/-private/system/coerce-id.js @@ -5,7 +5,11 @@ // ID into the URL, and if we later try to deserialize that URL and find the // corresponding record, we will not know if it is a string or a number. export default function coerceId(id) { - if (id === null || id === undefined || id === '') { return null; } - if (typeof id === 'string') { return id; } + if (id === null || id === undefined || id === '') { + return null; + } + if (typeof id === 'string') { + return id; + } return '' + id; } diff --git a/addon/-private/system/debug/debug-adapter.js b/addon/-private/system/debug/debug-adapter.js index eca07a7d7df..2904a93427f 100644 --- a/addon/-private/system/debug/debug-adapter.js +++ b/addon/-private/system/debug/debug-adapter.js @@ -23,7 +23,7 @@ export default DataAdapter.extend({ return [ { name: 'isNew', desc: 'New' }, { name: 'isModified', desc: 'Modified' }, - { name: 'isClean', desc: 'Clean' } + { name: 'isClean', desc: 'Clean' }, ]; }, @@ -32,14 +32,18 @@ export default DataAdapter.extend({ }, columnsForType(typeClass) { - let columns = [{ - name: 'id', - desc: 'Id' - }]; + let columns = [ + { + name: 'id', + desc: 'Id', + }, + ]; let count = 0; let self = this; get(typeClass, 'attributes').forEach((meta, name) => { - if (count++ > self.attributeLimit) { return false; } + if (count++ > self.attributeLimit) { + return false; + } let desc = capitalize(underscore(name).replace('_', ' ')); columns.push({ name: name, desc: desc }); }); @@ -57,7 +61,10 @@ export default DataAdapter.extend({ } } } - assert("Cannot find model name. Please upgrade to Ember.js >= 1.13 for Ember Inspector support", !!modelName); + assert( + 'Cannot find model name. Please upgrade to Ember.js >= 1.13 for Ember Inspector support', + !!modelName + ); return this.get('store').peekAll(modelName); }, @@ -65,7 +72,7 @@ export default DataAdapter.extend({ let count = 0; let columnValues = { id: get(record, 'id') }; - record.eachAttribute((key) => { + record.eachAttribute(key => { if (count++ > this.attributeLimit) { return false; } @@ -77,8 +84,8 @@ export default DataAdapter.extend({ getRecordKeywords(record) { let keywords = []; let keys = A(['id']); - record.eachAttribute((key) => keys.push(key)); - keys.forEach((key) => keywords.push(get(record, key))); + record.eachAttribute(key => keys.push(key)); + keys.forEach(key => keywords.push(get(record, key))); return keywords; }, @@ -86,7 +93,7 @@ export default DataAdapter.extend({ return { isNew: record.get('isNew'), isModified: record.get('hasDirtyAttributes') && !record.get('isNew'), - isClean: !record.get('hasDirtyAttributes') + isClean: !record.get('hasDirtyAttributes'), }; }, @@ -104,7 +111,7 @@ export default DataAdapter.extend({ let releaseMethods = A(); let keysToObserve = A(['id', 'isNew', 'hasDirtyAttributes']); - record.eachAttribute((key) => keysToObserve.push(key)); + record.eachAttribute(key => keysToObserve.push(key)); let adapter = this; keysToObserve.forEach(function(key) { @@ -118,9 +125,9 @@ export default DataAdapter.extend({ }); let release = function() { - releaseMethods.forEach((fn) => fn()); + releaseMethods.forEach(fn => fn()); }; return release; - } + }, }); diff --git a/addon/-private/system/diff-array.js b/addon/-private/system/diff-array.js index ae28e8e35b3..e935a525b6b 100644 --- a/addon/-private/system/diff-array.js +++ b/addon/-private/system/diff-array.js @@ -18,7 +18,7 @@ export default function diffArray(oldArray, newArray) { let firstChangeIndex = null; // null signifies no changes // find the first change - for (let i=0; i internalModel.isNew() && toSet.indexOf(internalModel) === -1 + internalModel => internalModel.isNew() && toSet.indexOf(internalModel) === -1 ); toSet = toSet.concat(newInternalModels); // diff to find changes let diff = diffArray(this.currentState, toSet); - if (diff.firstChangeIndex !== null) { // it's null if no change found + if (diff.firstChangeIndex !== null) { + // it's null if no change found // we found a change this.arrayContentWillChange(diff.firstChangeIndex, diff.removedCount, diff.addedCount); this.set('length', toSet.length); @@ -191,7 +194,7 @@ export default EmberObject.extend(MutableArray, Evented, { //TODO(Igor) optimize _removeInternalModels(internalModels) { - for (let i=0; i < internalModels.length; i++) { + for (let i = 0; i < internalModels.length; i++) { let index = this.currentState.indexOf(internalModels[i]); this.internalReplace(index, 1); } @@ -208,7 +211,7 @@ export default EmberObject.extend(MutableArray, Evented, { replace(idx, amt, objects) { let internalModels; if (amt > 0) { - internalModels = this.currentState.slice(idx, idx+amt); + internalModels = this.currentState.slice(idx, idx + amt); this.get('relationship').removeInternalModels(internalModels); } if (objects) { @@ -265,8 +268,11 @@ export default EmberObject.extend(MutableArray, Evented, { save() { let manyArray = this; let promiseLabel = 'DS: ManyArray#save ' + get(this, 'type'); - let promise = all(this.invoke("save"), promiseLabel). - then(() => manyArray, null, 'DS: ManyArray#save return ManyArray'); + let promise = all(this.invoke('save'), promiseLabel).then( + () => manyArray, + null, + 'DS: ManyArray#save return ManyArray' + ); return PromiseArray.create({ promise }); }, @@ -283,10 +289,13 @@ export default EmberObject.extend(MutableArray, Evented, { const store = get(this, 'store'); const type = get(this, 'type'); - assert(`You cannot add '${type.modelName}' records to this polymorphic relationship.`, !get(this, 'isPolymorphic')); + assert( + `You cannot add '${type.modelName}' records to this polymorphic relationship.`, + !get(this, 'isPolymorphic') + ); let record = store.createRecord(type.modelName, hash); this.pushObject(record); return record; - } + }, }); diff --git a/addon/-private/system/map.js b/addon/-private/system/map.js index 6018913a453..c7c0be9846b 100644 --- a/addon/-private/system/map.js +++ b/addon/-private/system/map.js @@ -64,7 +64,7 @@ export default class MapWithDeprecations { copy() { deprecate( 'Calling `.copy()` on a map generated by ember-data is deprecated, please migrate to using native Map functionality only.', - false, + false, { id: 'ember-data.map.copy', until: '3.5.0' } ); @@ -72,7 +72,7 @@ export default class MapWithDeprecations { // constructor args with its `Map` let newMap = new MapWithDeprecations(); this._map.forEach(function(value, key) { - newMap.set(key, value) + newMap.set(key, value); }); return newMap; @@ -81,7 +81,7 @@ export default class MapWithDeprecations { isEmpty() { deprecate( 'Calling `.isEmpty()` on a map generated by ember-data is deprecated, please migrate to using native Map functionality only.', - false, + false, { id: 'ember-data.map.isEmpty', until: '3.5.0' } ); @@ -89,14 +89,34 @@ export default class MapWithDeprecations { } // proxy all normal Map methods to the underlying Map - get size() { return this._map.size; } - clear() { return this._map.clear(...arguments) } - delete() { return this._map.delete(...arguments) } - entries() { return this._map.entries(...arguments) } - forEach() { return this._map.forEach(...arguments) } - get() { return this._map.get(...arguments) } - has() { return this._map.has(...arguments) } - keys() { return this._map.keys(...arguments) } - set() { return this._map.set(...arguments) } - values() { return this._map.values(...arguments) } + get size() { + return this._map.size; + } + clear() { + return this._map.clear(...arguments); + } + delete() { + return this._map.delete(...arguments); + } + entries() { + return this._map.entries(...arguments); + } + forEach() { + return this._map.forEach(...arguments); + } + get() { + return this._map.get(...arguments); + } + has() { + return this._map.has(...arguments); + } + keys() { + return this._map.keys(...arguments); + } + set() { + return this._map.set(...arguments); + } + values() { + return this._map.values(...arguments); + } } diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index b955dc1ef61..005fb9ec7ca 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -86,7 +86,6 @@ import { warn } from '@ember/debug'; @uses Ember.Evented */ export default ArrayProxy.extend(Evented, { - /** Register with target handler @@ -107,7 +106,7 @@ export default ArrayProxy.extend(Evented, { return new MapWithDefault({ defaultValue() { return A(); - } + }, }); }), @@ -165,7 +164,9 @@ export default ArrayProxy.extend(Evented, { */ unknownProperty(attribute) { let errors = this.errorsFor(attribute); - if (errors.length === 0) { return undefined; } + if (errors.length === 0) { + return undefined; + } return errors; }, @@ -203,7 +204,7 @@ export default ArrayProxy.extend(Evented, { */ add(attribute, messages) { warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.add' + id: 'ds.errors.add', }); let wasEmpty = get(this, 'isEmpty'); @@ -215,7 +216,6 @@ export default ArrayProxy.extend(Evented, { } }, - /** Adds error messages to a given attribute without sending event. @@ -225,7 +225,9 @@ export default ArrayProxy.extend(Evented, { _add(attribute, messages) { messages = this._findOrCreateMessages(attribute, messages); this.addObjects(messages); - get(this, 'errorsByAttributeName').get(attribute).addObjects(messages); + get(this, 'errorsByAttributeName') + .get(attribute) + .addObjects(messages); this.notifyPropertyChange(attribute); }, @@ -247,7 +249,7 @@ export default ArrayProxy.extend(Evented, { } else { _messages[i] = { attribute: attribute, - message: message + message: message, }; } } @@ -292,10 +294,12 @@ export default ArrayProxy.extend(Evented, { */ remove(attribute) { warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.remove' + id: 'ds.errors.remove', }); - if (get(this, 'isEmpty')) { return; } + if (get(this, 'isEmpty')) { + return; + } this._remove(attribute); @@ -311,7 +315,9 @@ export default ArrayProxy.extend(Evented, { @private */ _remove(attribute) { - if (get(this, 'isEmpty')) { return; } + if (get(this, 'isEmpty')) { + return; + } let content = this.rejectBy('attribute', attribute); set(this, 'content', content); @@ -345,16 +351,17 @@ export default ArrayProxy.extend(Evented, { */ clear() { warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.clear' + id: 'ds.errors.clear', }); - if (get(this, 'isEmpty')) { return; } + if (get(this, 'isEmpty')) { + return; + } this._clear(); this.trigger('becameValid'); }, - /** Removes all error messages. to the record. @@ -363,7 +370,9 @@ export default ArrayProxy.extend(Evented, { @private */ _clear() { - if (get(this, 'isEmpty')) { return; } + if (get(this, 'isEmpty')) { + return; + } let errorsByAttributeName = get(this, 'errorsByAttributeName'); let attributes = A(); @@ -380,7 +389,6 @@ export default ArrayProxy.extend(Evented, { ArrayProxy.prototype.clear.call(this); }, - /** Checks if there is error messages for the given attribute. @@ -405,5 +413,5 @@ export default ArrayProxy.extend(Evented, { */ has(attribute) { return this.errorsFor(attribute).length > 0; - } + }, }); diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 61fda841a20..e94bb3623d3 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -9,19 +9,15 @@ import RSVP, { Promise } from 'rsvp'; import Ember from 'ember'; import { DEBUG } from '@glimmer/env'; import { assert, inspect } from '@ember/debug'; -import RootState from "./states"; -import Relationships from "../relationships/state/create"; -import Snapshot from "../snapshot"; -import OrderedSet from "../ordered-set"; -import isArrayLike from "../is-array-like"; +import RootState from './states'; +import Relationships from '../relationships/state/create'; +import Snapshot from '../snapshot'; +import OrderedSet from '../ordered-set'; +import isArrayLike from '../is-array-like'; import { getOwner } from '../../utils'; -import { - RecordReference, - BelongsToReference, - HasManyReference -} from "../references"; +import { RecordReference, BelongsToReference, HasManyReference } from '../references'; /* The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached @@ -39,19 +35,15 @@ const _extractPivotNameCache = Object.create(null); const _splitOnDotCache = Object.create(null); function splitOnDot(name) { - return _splitOnDotCache[name] || ( - _splitOnDotCache[name] = name.split('.') - ); + return _splitOnDotCache[name] || (_splitOnDotCache[name] = name.split('.')); } function extractPivotName(name) { - return _extractPivotNameCache[name] || ( - _extractPivotNameCache[name] = splitOnDot(name)[0] - ); + return _extractPivotNameCache[name] || (_extractPivotNameCache[name] = splitOnDot(name)[0]); } function areAllModelsUnloaded(internalModels) { - for (let i=0; i record.hasOwnProperty('_internalModel') === true); - })()); + assert( + `All elements of a hasMany relationship must be instances of DS.Model, you passed ${inspect( + records + )}`, + (function() { + return A(records).every(record => record.hasOwnProperty('_internalModel') === true); + })() + ); let relationship = this._relationships.get(key); relationship.clear(); @@ -700,7 +730,7 @@ export default class InternalModel { name: key, oldValue: oldValue, originalValue: originalValue, - value: value + value: value, }); } @@ -879,7 +909,6 @@ export default class InternalModel { this._attributes = null; } - if (get(this, 'isError')) { this._inFlightAttributes = null; this.didCleanError(); @@ -915,7 +944,9 @@ export default class InternalModel { let transitionMapId = `${state.stateName}->${name}`; do { - if (state.exit) { state.exit(this); } + if (state.exit) { + state.exit(this); + } state = state.parentState; } while (!state[pivotName]); @@ -938,8 +969,12 @@ export default class InternalModel { for (i = 0, l = path.length; i < l; i++) { state = state[path[i]]; - if (state.enter) { enters.push(state); } - if (state.setup) { setups.push(state); } + if (state.enter) { + enters.push(state); + } + if (state.setup) { + setups.push(state); + } } TransitionChainMap[transitionMapId] = { setups, enters, state }; @@ -962,12 +997,12 @@ export default class InternalModel { } _unhandledEvent(state, name, context) { - let errorMessage = "Attempted to handle event `" + name + "` "; - errorMessage += "on " + String(this) + " while in state "; - errorMessage += state.stateName + ". "; + let errorMessage = 'Attempted to handle event `' + name + '` '; + errorMessage += 'on ' + String(this) + ' while in state '; + errorMessage += state.stateName + '. '; if (context !== undefined) { - errorMessage += "Called with " + inspect(context) + "."; + errorMessage += 'Called with ' + inspect(context) + '.'; } throw new EmberError(errorMessage); @@ -992,7 +1027,7 @@ export default class InternalModel { let triggers = this._deferredTriggers; let record = this._record; let trigger = record.trigger; - for (let i = 0, l= triggers.length; i { + Object.keys(implicitRelationships).forEach(key => { let rel = implicitRelationships[key]; rel.removeCompletelyFromInverse(); @@ -1035,7 +1070,7 @@ export default class InternalModel { let implicitRelationships = this._implicitRelationships; this.__implicitRelationships = null; - Object.keys(implicitRelationships).forEach((key) => { + Object.keys(implicitRelationships).forEach(key => { let rel = implicitRelationships[key]; destroyRelationship(rel); }); @@ -1058,7 +1093,7 @@ export default class InternalModel { */ preloadData(preload) { //TODO(Igor) consider the polymorphic case - Object.keys(preload).forEach((key) => { + Object.keys(preload).forEach(key => { let preloadValue = get(preload, key); let relationshipMeta = this.modelClass.metaForProperty(key); if (relationshipMeta.isRelationship) { @@ -1080,7 +1115,10 @@ export default class InternalModel { } _preloadHasMany(key, preloadValue, modelClass) { - assert("You need to pass in an array to set a hasMany property on a record", Array.isArray(preloadValue)); + assert( + 'You need to pass in an array to set a hasMany property on a record', + Array.isArray(preloadValue) + ); let recordsToSet = new Array(preloadValue.length); for (let i = 0; i < preloadValue.length; i++) { @@ -1122,7 +1160,10 @@ export default class InternalModel { } setId(id) { - assert('A record\'s id cannot be changed once it is in the loaded state', this.id === null || this.id === id || this.isNew()); + assert( + "A record's id cannot be changed once it is in the loaded state", + this.id === null || this.id === id || this.isNew() + ); let didChange = id !== this.id; this.id = id; @@ -1138,7 +1179,7 @@ export default class InternalModel { if (this.hasRecord) { this._record.setProperties({ isError: true, - adapterError: error + adapterError: error, }); } } @@ -1150,7 +1191,7 @@ export default class InternalModel { if (this.hasRecord) { this._record.setProperties({ isError: false, - adapterError: null + adapterError: null, }); } } @@ -1164,7 +1205,11 @@ export default class InternalModel { */ adapterDidCommit(data) { if (data) { - this.store._internalModelDidReceiveRelationshipData(this.modelName, this.id, data.relationships); + this.store._internalModelDidReceiveRelationshipData( + this.modelName, + this.id, + data.relationships + ); data = data.attributes; } @@ -1182,7 +1227,9 @@ export default class InternalModel { this.send('didCommit'); this.updateRecordArrays(); - if (!data) { return; } + if (!data) { + return; + } this._record._notifyProperties(changedKeys); } @@ -1239,7 +1286,7 @@ export default class InternalModel { let keys = Object.keys(this._inFlightAttributes); if (keys.length > 0) { let attrs = this._attributes; - for (let i=0; i < keys.length; i++) { + for (let i = 0; i < keys.length; i++) { if (attrs[keys[i]] === undefined) { attrs[keys[i]] = this._inFlightAttributes[keys[i]]; } @@ -1299,7 +1346,7 @@ export default class InternalModel { let hasAttrs = this.hasChangedAttributes(); let attrs; if (hasAttrs) { - attrs= this._attributes; + attrs = this._attributes; } original = Object.create(null); @@ -1338,15 +1385,21 @@ export default class InternalModel { if (DEBUG) { let modelName = this.modelName; - assert(`There is no ${kind} relationship named '${name}' on a model of modelClass '${modelName}'`, relationship); + assert( + `There is no ${kind} relationship named '${name}' on a model of modelClass '${modelName}'`, + relationship + ); let actualRelationshipKind = relationship.relationshipMeta.kind; - assert(`You tried to get the '${name}' relationship on a '${modelName}' via record.${kind}('${name}'), but the relationship is of kind '${actualRelationshipKind}'. Use record.${actualRelationshipKind}('${name}') instead.`, actualRelationshipKind === kind); + assert( + `You tried to get the '${name}' relationship on a '${modelName}' via record.${kind}('${name}'), but the relationship is of kind '${actualRelationshipKind}'. Use record.${actualRelationshipKind}('${name}') instead.`, + actualRelationshipKind === kind + ); } - if (kind === "belongsTo") { + if (kind === 'belongsTo') { reference = new BelongsToReference(this.store, this, relationship); - } else if (kind === "hasMany") { + } else if (kind === 'hasMany') { reference = new HasManyReference(this.store, this, relationship); } diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 7c221af8461..2c1c45e0f1a 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -2,20 +2,17 @@ import ComputedProperty from '@ember/object/computed'; import { isNone } from '@ember/utils'; import EmberError from '@ember/error'; import Evented from '@ember/object/evented'; -import EmberObject, { - computed, - get -} from '@ember/object'; +import EmberObject, { computed, get } from '@ember/object'; import Map from '../map'; import { DEBUG } from '@glimmer/env'; import { assert, warn } from '@ember/debug'; -import { PromiseObject } from "../promise-proxies"; -import Errors from "../model/errors"; +import { PromiseObject } from '../promise-proxies'; +import Errors from '../model/errors'; import RootState from '../model/states'; import { relationshipsByNameDescriptor, relatedTypesDescriptor, - relationshipsDescriptor + relationshipsDescriptor, } from '../relationships/ext'; import Ember from 'ember'; @@ -29,7 +26,9 @@ function findPossibleInverses(type, inverseType, name, relationshipsSoFar) { let possibleRelationships = relationshipsSoFar || []; let relationshipMap = get(inverseType, 'relationships'); - if (!relationshipMap) { return possibleRelationships; } + if (!relationshipMap) { + return possibleRelationships; + } let relationships = relationshipMap.get(type.modelName).filter(relationship => { let optionsForRelationship = inverseType.metaForProperty(relationship.name).options; @@ -53,9 +52,9 @@ function findPossibleInverses(type, inverseType, name, relationshipsSoFar) { return possibleRelationships; } -function intersection (array1, array2) { +function intersection(array1, array2) { let result = []; - array1.forEach((element) => { + array1.forEach(element => { if (array2.indexOf(element) >= 0) { result.push(element); } @@ -64,9 +63,7 @@ function intersection (array1, array2) { return result; } -const RESERVED_MODEL_PROPS = [ - 'currentState', 'data', 'store' -]; +const RESERVED_MODEL_PROPS = ['currentState', 'data', 'store']; const retrieveFromCurrentState = computed('currentState', function(key) { return get(this._internalModel.currentState, key); @@ -401,13 +398,15 @@ const Model = EmberObject.extend(Evented, { errors: computed(function() { let errors = Errors.create(); - errors._registerHandlers(this._internalModel, + errors._registerHandlers( + this._internalModel, function() { this.send('becameInvalid'); }, function() { this.send('becameValid'); - }); + } + ); return errors; }).readOnly(), @@ -537,7 +536,6 @@ const Model = EmberObject.extend(Evented, { return this._internalModel.transitionTo(name); }, - /** Marks the record as deleted but does not save it. You must call `save` afterwards if you want to persist it. You might use this @@ -625,7 +623,9 @@ const Model = EmberObject.extend(Evented, { @method unloadRecord */ unloadRecord() { - if (this.isDestroyed) { return; } + if (this.isDestroyed) { + return; + } this._internalModel.unloadRecord(); }, @@ -790,7 +790,7 @@ const Model = EmberObject.extend(Evented, { */ save(options) { return PromiseObject.create({ - promise: this._internalModel.save(options).then(() => this) + promise: this._internalModel.save(options).then(() => this), }); }, @@ -827,16 +827,15 @@ const Model = EmberObject.extend(Evented, { if (typeof options === 'object' && options !== null && options.adapterOptions) { wrappedAdapterOptions = { - adapterOptions: options.adapterOptions + adapterOptions: options.adapterOptions, }; } return PromiseObject.create({ - promise: this._internalModel.reload(wrappedAdapterOptions).then(() => this) + promise: this._internalModel.reload(wrappedAdapterOptions).then(() => this), }); }, - /** Override the default event firing from Ember.Evented to also call methods with the given name. @@ -855,14 +854,17 @@ const Model = EmberObject.extend(Evented, { for (let i = 1; i < length; i++) { args[i - 1] = arguments[i]; } - fn.apply(this, args) + fn.apply(this, args); } this._super(...arguments); }, attr() { - assert("The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); + assert( + 'The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?', + false + ); }, /** @@ -1009,7 +1011,7 @@ const Model = EmberObject.extend(Evented, { */ _debugInfo() { let attributes = ['id']; - let relationships = { }; + let relationships = {}; let expensiveProperties = []; this.eachAttribute((name, meta) => attributes.push(name)); @@ -1018,8 +1020,8 @@ const Model = EmberObject.extend(Evented, { { name: 'Attributes', properties: attributes, - expand: true - } + expand: true, + }, ]; this.eachRelationship((name, relationship) => { @@ -1030,7 +1032,7 @@ const Model = EmberObject.extend(Evented, { groups.push({ name: relationship.name, properties, - expand: true + expand: true, }); } properties.push(name); @@ -1039,7 +1041,15 @@ const Model = EmberObject.extend(Evented, { groups.push({ name: 'Flags', - properties: ['isLoaded', 'hasDirtyAttributes', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'] + properties: [ + 'isLoaded', + 'hasDirtyAttributes', + 'isSaving', + 'isDeleted', + 'isError', + 'isNew', + 'isValid', + ], }); return { @@ -1048,8 +1058,8 @@ const Model = EmberObject.extend(Evented, { includeOtherProperties: true, groups: groups, // don't pre-calculate unless cached - expensiveProperties: expensiveProperties - } + expensiveProperties: expensiveProperties, + }, }; }, @@ -1131,7 +1141,7 @@ const Model = EmberObject.extend(Evented, { eachAttribute(callback, binding) { this.constructor.eachAttribute(callback, binding); - } + }, }); /** @@ -1143,7 +1153,7 @@ Object.defineProperty(Model.prototype, 'data', { configurable: false, get() { return this._internalModel._data; - } + }, }); Object.defineProperty(Model.prototype, 'id', { @@ -1157,7 +1167,7 @@ Object.defineProperty(Model.prototype, 'id', { // (addListener via validatePropertyInjections) invokes toString before the // object is real. return this._internalModel && this._internalModel.id; - } + }, }); if (DEBUG) { @@ -1166,9 +1176,11 @@ if (DEBUG) { this._super(...arguments); if (!this._internalModel) { - throw new EmberError('You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.'); + throw new EmberError( + 'You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.' + ); } - } + }, }); } @@ -1309,15 +1321,14 @@ Model.reopenClass({ // through `relationshipsByName` (relationship.options && relationship.options.inverse === null) ) { - return inverseMap[name] = null; + return (inverseMap[name] = null); } - return inverseMap[name] = this._findInverseFor(name, store); + return (inverseMap[name] = this._findInverseFor(name, store)); }, //Calculate the inverse, ignoring the cache _findInverseFor(name, store) { - let inverseType = this.typeForRelationship(name, store); if (!inverseType) { return null; @@ -1326,7 +1337,9 @@ Model.reopenClass({ let propertyMeta = this.metaForProperty(name); //If inverse is manually specified to be null, like `comments: DS.hasMany('message', { inverse: null })` let options = propertyMeta.options; - if (options.inverse === null) { return null; } + if (options.inverse === null) { + return null; + } let inverseName, inverseKind, inverse, inverseOptions; @@ -1335,8 +1348,14 @@ Model.reopenClass({ inverseName = options.inverse; inverse = get(inverseType, 'relationshipsByName').get(inverseName); - assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.modelName + - "' model. This is most likely due to a missing attribute on your model definition.", !isNone(inverse)); + assert( + "We found no inverse relationships by the name of '" + + inverseName + + "' on the '" + + inverseType.modelName + + "' model. This is most likely due to a missing attribute on your model definition.", + !isNone(inverse) + ); // TODO probably just return the whole inverse here inverseKind = inverse.kind; @@ -1344,44 +1363,73 @@ Model.reopenClass({ } else { //No inverse was specified manually, we need to use a heuristic to guess one if (propertyMeta.parentType && propertyMeta.type === propertyMeta.parentType.modelName) { - warn(`Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at https://guides.emberjs.com/current/models/relationships/#toc_reflexive-relations for how to explicitly specify inverses.`, false, { - id: 'ds.model.reflexive-relationship-without-inverse' - }); + warn( + `Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at https://guides.emberjs.com/current/models/relationships/#toc_reflexive-relations for how to explicitly specify inverses.`, + false, + { + id: 'ds.model.reflexive-relationship-without-inverse', + } + ); } let possibleRelationships = findPossibleInverses(this, inverseType, name); - if (possibleRelationships.length === 0) { return null; } + if (possibleRelationships.length === 0) { + return null; + } - let filteredRelationships = possibleRelationships.filter((possibleRelationship) => { + let filteredRelationships = possibleRelationships.filter(possibleRelationship => { let optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options; return name === optionsForRelationship.inverse; }); - assert("You defined the '" + name + "' relationship on " + this + ", but you defined the inverse relationships of type " + - inverseType.toString() + " multiple times. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses", - filteredRelationships.length < 2); - - if (filteredRelationships.length === 1 ) { + assert( + "You defined the '" + + name + + "' relationship on " + + this + + ', but you defined the inverse relationships of type ' + + inverseType.toString() + + ' multiple times. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses', + filteredRelationships.length < 2 + ); + + if (filteredRelationships.length === 1) { possibleRelationships = filteredRelationships; } - assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + - this + " were found on " + inverseType + ". Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses", - possibleRelationships.length === 1); + assert( + "You defined the '" + + name + + "' relationship on " + + this + + ', but multiple possible inverse relationships of type ' + + this + + ' were found on ' + + inverseType + + '. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses', + possibleRelationships.length === 1 + ); inverseName = possibleRelationships[0].name; inverseKind = possibleRelationships[0].kind; inverseOptions = possibleRelationships[0].options; } - assert(`The ${inverseType.modelName}:${inverseName} relationship declares 'inverse: null', but it was resolved as the inverse for ${this.modelName}:${name}.`, !inverseOptions || inverseOptions.inverse !== null); + assert( + `The ${ + inverseType.modelName + }:${inverseName} relationship declares 'inverse: null', but it was resolved as the inverse for ${ + this.modelName + }:${name}.`, + !inverseOptions || inverseOptions.inverse !== null + ); return { type: inverseType, name: inverseName, kind: inverseKind, - options: inverseOptions + options: inverseOptions, }; }, @@ -1465,7 +1513,7 @@ Model.reopenClass({ relationshipNames: computed(function() { let names = { hasMany: [], - belongsTo: [] + belongsTo: [], }; this.eachComputedProperty((name, meta) => { @@ -1705,7 +1753,11 @@ Model.reopenClass({ this.eachComputedProperty((name, meta) => { if (meta.isAttribute) { - assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.toString(), name !== 'id'); + assert( + "You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + + this.toString(), + name !== 'id' + ); meta.name = name; map.set(name, meta); @@ -1872,7 +1924,7 @@ Model.reopenClass({ */ toString() { return `model:${get(this, 'modelName')}`; - } + }, }); if (DEBUG) { @@ -1881,8 +1933,18 @@ if (DEBUG) { // rely on the data property. willMergeMixin(props) { let constructor = this.constructor; - assert('`' + intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + constructor.toString(), !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0]); - assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + constructor.toString(), Object.keys(props).indexOf('id') === -1); + assert( + '`' + + intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + + '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + + constructor.toString(), + !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + ); + assert( + "You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + + constructor.toString(), + Object.keys(props).indexOf('id') === -1 + ); }, /** @@ -1914,7 +1976,6 @@ if (DEBUG) { didDefineProperty(proto, key, value) { // Check if the value being set is a computed property. if (value instanceof ComputedProperty) { - // If it is, get the metadata for the relationship. This is // populated by the `DS.belongsTo` helper when it is creating // the computed property. @@ -1926,7 +1987,7 @@ if (DEBUG) { */ meta.parentType = proto.constructor; } - } + }, }); } diff --git a/addon/-private/system/model/states.js b/addon/-private/system/model/states.js index 84085f14fe4..ad7562b5659 100644 --- a/addon/-private/system/model/states.js +++ b/addon/-private/system/model/states.js @@ -239,10 +239,12 @@ const DirtyState = { //TODO(Igor) reloading now triggers a //loadingData event, though it seems fine? - loadingData() { }, + loadingData() {}, propertyWasReset(internalModel, name) { - if (!internalModel.hasChangedAttributes()) { internalModel.send('rolledBack'); } + if (!internalModel.hasChangedAttributes()) { + internalModel.send('rolledBack'); + } }, pushedData(internalModel) { @@ -277,7 +279,7 @@ const DirtyState = { rollback(internalModel) { internalModel.rollbackAttributes(); internalModel.triggerLater('ready'); - } + }, }, // Once a record has been handed off to the adapter to be @@ -289,13 +291,13 @@ const DirtyState = { // EVENTS didSetProperty, - becomeDirty() { }, - pushedData() { }, + becomeDirty() {}, + pushedData() {}, unloadRecord: assertAgainstUnloadRecord, // TODO: More robust semantics around save-while-in-flight - willCommit() { }, + willCommit() {}, didCommit(internalModel) { internalModel.transitionTo('saved'); @@ -314,7 +316,7 @@ const DirtyState = { becameError(internalModel) { internalModel.transitionTo('uncommitted'); internalModel.triggerLater('becameError', internalModel); - } + }, }, // A record is in the `invalid` if the adapter has indicated @@ -338,9 +340,9 @@ const DirtyState = { } }, - becameInvalid() { }, - becomeDirty() { }, - pushedData() { }, + becameInvalid() {}, + becomeDirty() {}, + pushedData() {}, willCommit(internalModel) { internalModel.clearErrorMessages(); @@ -359,8 +361,8 @@ const DirtyState = { invokeLifecycleCallbacks(internalModel) { internalModel.triggerLater('becameInvalid', internalModel); - } - } + }, + }, }; // The created and updated states are created outside the state @@ -399,7 +401,7 @@ function dirtyState(options) { const createdState = dirtyState({ dirtyType: 'created', // FLAGS - isNew: true + isNew: true, }); createdState.invalid.rolledBack = function(internalModel) { @@ -413,7 +415,7 @@ createdState.uncommitted.rolledBack = function(internalModel) { }; const updatedState = dirtyState({ - dirtyType: 'updated' + dirtyType: 'updated', }); function createdStateDeleteRecord(internalModel) { @@ -438,7 +440,7 @@ createdState.uncommitted.pushedData = function(internalModel) { createdState.uncommitted.propertyWasReset = function() {}; function assertAgainstUnloadRecord(internalModel) { - assert("You can only unload a record which is not inFlight. `" + internalModel + "`", false); + assert('You can only unload a record which is not inFlight. `' + internalModel + '`', false); } updatedState.invalid.becameValid = function(internalModel) { @@ -477,11 +479,10 @@ const RootState = { // doesn't change your state. For example, if you're in the // in-flight state, rolling back the record doesn't move // you out of the in-flight state. - rolledBack() { }, - unloadRecord(internalModel) { - }, + rolledBack() {}, + unloadRecord(internalModel) {}, - propertyWasReset() { }, + propertyWasReset() {}, // SUBSTATES @@ -508,7 +509,7 @@ const RootState = { internalModel.transitionTo('loaded.saved'); internalModel.triggerLater('didLoad'); internalModel.triggerLater('ready'); - } + }, }, // A record enters this state when the store asks @@ -540,7 +541,7 @@ const RootState = { notFound(internalModel) { internalModel.transitionTo('empty'); - } + }, }, // A record enters this state when its data is populated. @@ -554,7 +555,7 @@ const RootState = { //TODO(Igor) Reloading now triggers a loadingData event, //but it should be ok? - loadingData() { }, + loadingData() {}, // SUBSTATES @@ -570,7 +571,7 @@ const RootState = { // EVENTS didSetProperty, - pushedData() { }, + pushedData() {}, becomeDirty(internalModel) { internalModel.transitionTo('updated.uncommitted'); @@ -588,14 +589,13 @@ const RootState = { internalModel.transitionTo('deleted.uncommitted'); }, - unloadRecord(internalModel) { - }, + unloadRecord(internalModel) {}, didCommit() {}, // loaded.saved.notFound would be triggered by a failed // `reload()` on an unchanged record - notFound() { } + notFound() {}, }, // A record is in this state after it has been locally @@ -606,7 +606,7 @@ const RootState = { // A record is in this state if it has already been // saved to the server, but there are new local changes // that have not yet been saved. - updated: updatedState + updated: updatedState, }, // A record is in this state if it was deleted from the store. @@ -630,7 +630,6 @@ const RootState = { // state. It will exit this state when the record // starts to commit. uncommitted: { - // EVENTS willCommit(internalModel) { @@ -642,15 +641,15 @@ const RootState = { internalModel.triggerLater('ready'); }, - pushedData() { }, - becomeDirty() { }, - deleteRecord() { }, + pushedData() {}, + becomeDirty() {}, + deleteRecord() {}, rolledBack(internalModel) { internalModel.transitionTo('loaded.saved'); internalModel.triggerLater('ready'); internalModel.triggerLater('rolledBack'); - } + }, }, // After a record starts committing, but @@ -666,7 +665,7 @@ const RootState = { unloadRecord: assertAgainstUnloadRecord, // TODO: More robust semantics around save-while-in-flight - willCommit() { }, + willCommit() {}, didCommit(internalModel) { internalModel.transitionTo('saved'); @@ -681,7 +680,7 @@ const RootState = { becameInvalid(internalModel) { internalModel.transitionTo('invalid'); internalModel.triggerLater('becameInvalid', internalModel); - } + }, }, // Once the adapter indicates that the deletion has @@ -700,9 +699,9 @@ const RootState = { internalModel.triggerLater('didCommit', internalModel); }, - willCommit() { }, - didCommit() { }, - pushedData() {} + willCommit() {}, + didCommit() {}, + pushedData() {}, }, invalid: { @@ -718,10 +717,10 @@ const RootState = { } }, - becameInvalid() { }, - becomeDirty() { }, - deleteRecord() { }, - willCommit() { }, + becameInvalid() {}, + becomeDirty() {}, + deleteRecord() {}, + willCommit() {}, rolledBack(internalModel) { internalModel.clearErrorMessages(); @@ -731,9 +730,8 @@ const RootState = { becameValid(internalModel) { internalModel.transitionTo('uncommitted'); - } - - } + }, + }, }, invokeLifecycleCallbacks(internalModel, dirtyType) { @@ -744,7 +742,7 @@ const RootState = { } internalModel.triggerLater('didCommit', internalModel); - } + }, }; function wireState(object, parent, name) { @@ -754,7 +752,9 @@ function wireState(object, parent, name) { object.stateName = name; for (let prop in object) { - if (!object.hasOwnProperty(prop) || prop === 'parentState' || prop === 'stateName') { continue; } + if (!object.hasOwnProperty(prop) || prop === 'parentState' || prop === 'stateName') { + continue; + } if (typeof object[prop] === 'object') { object[prop] = wireState(object[prop], object, name + '.' + prop); } diff --git a/addon/-private/system/normalize-link.js b/addon/-private/system/normalize-link.js index 59d9d6536e8..33e7a31ad97 100644 --- a/addon/-private/system/normalize-link.js +++ b/addon/-private/system/normalize-link.js @@ -12,8 +12,10 @@ */ export default function _normalizeLink(link) { switch (typeof link) { - case 'object': return link; - case 'string': return { href: link }; + case 'object': + return link; + case 'string': + return { href: link }; } return null; } diff --git a/addon/-private/system/promise-proxies.js b/addon/-private/system/promise-proxies.js index a740d003c6b..4a419ac7a01 100644 --- a/addon/-private/system/promise-proxies.js +++ b/addon/-private/system/promise-proxies.js @@ -36,7 +36,7 @@ import { assert } from '@ember/debug'; @uses Ember.PromiseProxyMixin */ export const PromiseArray = ArrayProxy.extend(PromiseProxyMixin, { - meta: reads('content.meta') + meta: reads('content.meta'), }); /** @@ -72,36 +72,40 @@ export let PromiseObject = ObjectProxy.extend(PromiseProxyMixin); export function promiseObject(promise, label) { return PromiseObject.create({ - promise: Promise.resolve(promise, label) + promise: Promise.resolve(promise, label), }); } export function promiseArray(promise, label) { return PromiseArray.create({ - promise: Promise.resolve(promise, label) + promise: Promise.resolve(promise, label), }); } export const PromiseBelongsTo = PromiseObject.extend({ - // we don't proxy meta because we would need to proxy it to the relationship state container // however, meta on relationships does not trigger change notifications. // if you need relationship meta, you should do `record.belongsTo(relationshipName).meta()` meta: computed(function() { assert( 'You attempted to access meta on the promise for the async belongsTo relationship ' + - `${this.get('_belongsToState').internalModel.modelName}:${this.get('_belongsToState').key}'.` + - '\nUse `record.belongsTo(relationshipName).meta()` instead.', + `${this.get('_belongsToState').internalModel.modelName}:${ + this.get('_belongsToState').key + }'.` + + '\nUse `record.belongsTo(relationshipName).meta()` instead.', false ); }), reload() { - assert('You are trying to reload an async belongsTo before it has been created', this.get('content') !== undefined); + assert( + 'You are trying to reload an async belongsTo before it has been created', + this.get('content') !== undefined + ); this.get('_belongsToState').reload(); return this; - } + }, }); /** @@ -130,7 +134,10 @@ export function proxyToContent(method) { export const PromiseManyArray = PromiseArray.extend({ reload() { - assert('You are trying to reload an async manyArray before it has been created', get(this, 'content')); + assert( + 'You are trying to reload an async manyArray before it has been created', + get(this, 'content') + ); this.set('promise', this.get('content').reload()); return this; }, @@ -145,11 +152,11 @@ export const PromiseManyArray = PromiseArray.extend({ off: proxyToContent('off'), - has: proxyToContent('has') + has: proxyToContent('has'), }); export function promiseManyArray(promise, label) { return PromiseManyArray.create({ - promise: Promise.resolve(promise, label) + promise: Promise.resolve(promise, label), }); } diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index a3608c16a54..e8e3ae6c5b8 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -7,10 +7,7 @@ import { set, get } from '@ember/object'; import { run as emberRun } from '@ember/runloop'; import { assert } from '@ember/debug'; import cloneNull from './clone-null'; -import { - RecordArray, - AdapterPopulatedRecordArray -} from './record-arrays'; +import { RecordArray, AdapterPopulatedRecordArray } from './record-arrays'; const { _flush, @@ -20,8 +17,9 @@ const { createRecordArray, liveRecordArrayFor, recordDidChange, - unregisterRecordArray -} = heimdall.registerMonitor('recordArrayManager', + unregisterRecordArray, +} = heimdall.registerMonitor( + 'recordArrayManager', '_flush', 'array_remove', 'create', @@ -72,7 +70,7 @@ export default class RecordArrayManager { internalModel._pendingRecordArrayManagerFlush = true; let pending = this._pending; - let models = pending[modelName] = pending[modelName] || []; + let models = (pending[modelName] = pending[modelName] || []); if (models.push(internalModel) !== 1) { return; } @@ -123,7 +121,10 @@ export default class RecordArrayManager { } _syncLiveRecordArray(array, modelName) { - assert(`recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); + assert( + `recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, + typeof modelName === 'string' + ); let pending = this._pending[modelName]; let hasPendingChanges = Array.isArray(pending); let hasNoPotentialDeletions = !hasPendingChanges || pending.length === 0; @@ -177,7 +178,10 @@ export default class RecordArrayManager { @return {DS.RecordArray} */ liveRecordArrayFor(modelName) { - assert(`recordArrayManger.liveRecordArrayFor expects modelName not modelClass as the param`, typeof modelName === 'string'); + assert( + `recordArrayManger.liveRecordArrayFor expects modelName not modelClass as the param`, + typeof modelName === 'string' + ); heimdall.increment(liveRecordArrayFor); @@ -218,7 +222,10 @@ export default class RecordArrayManager { @return {DS.RecordArray} */ createRecordArray(modelName, content) { - assert(`recordArrayManger.createRecordArray expects modelName not modelClass as the param`, typeof modelName === 'string'); + assert( + `recordArrayManger.createRecordArray expects modelName not modelClass as the param`, + typeof modelName === 'string' + ); heimdall.increment(createRecordArray); let array = RecordArray.create({ @@ -226,7 +233,7 @@ export default class RecordArrayManager { content: A(content || []), store: this.store, isLoaded: true, - manager: this + manager: this, }); if (Array.isArray(content)) { @@ -236,7 +243,6 @@ export default class RecordArrayManager { return array; } - /** Create a `DS.AdapterPopulatedRecordArray` for a modelName with given query. @@ -247,7 +253,10 @@ export default class RecordArrayManager { */ createAdapterPopulatedRecordArray(modelName, query, internalModels, payload) { heimdall.increment(createAdapterPopulatedRecordArray); - assert(`recordArrayManger.createAdapterPopulatedRecordArray expects modelName not modelClass as the first param, received ${modelName}`, typeof modelName === 'string'); + assert( + `recordArrayManger.createAdapterPopulatedRecordArray expects modelName not modelClass as the first param, received ${modelName}`, + typeof modelName === 'string' + ); let array; if (Array.isArray(internalModels)) { @@ -260,7 +269,7 @@ export default class RecordArrayManager { isLoaded: true, isUpdating: false, meta: cloneNull(payload.meta), - links: cloneNull(payload.links) + links: cloneNull(payload.links), }); associateWithRecordArray(internalModels, array); @@ -270,7 +279,7 @@ export default class RecordArrayManager { query: query, content: A(), store: this.store, - manager: this + manager: this, }); } @@ -295,7 +304,6 @@ export default class RecordArrayManager { let removedFromAdapterPopulated = remove(this._adapterPopulatedRecordArrays, array); if (!removedFromAdapterPopulated) { - let liveRecordArrayForType = this._liveRecordArrays[modelName]; // unregister live record array if (liveRecordArrayForType) { @@ -311,7 +319,9 @@ export default class RecordArrayManager { } willDestroy() { - Object.keys(this._liveRecordArrays).forEach(modelName => this._liveRecordArrays[modelName].destroy()); + Object.keys(this._liveRecordArrays).forEach(modelName => + this._liveRecordArrays[modelName].destroy() + ); this._adapterPopulatedRecordArrays.forEach(destroy); this.isDestroyed = true; } @@ -356,12 +366,16 @@ function updateLiveRecordArray(array, internalModels) { if (isDeleted) { modelsToRemove.push(internalModel); - recordArrays.delete(array) + recordArrays.delete(array); } } - if (modelsToAdd.length > 0) { array._pushInternalModels(modelsToAdd); } - if (modelsToRemove.length > 0) { array._removeInternalModels(modelsToRemove); } + if (modelsToAdd.length > 0) { + array._pushInternalModels(modelsToAdd); + } + if (modelsToRemove.length > 0) { + array._removeInternalModels(modelsToRemove); + } // return whether we performed an update. // Necessary until 3.5 allows us to finish off ember-data-filter support. diff --git a/addon/-private/system/record-arrays.js b/addon/-private/system/record-arrays.js index d65107ed72a..5439899ad81 100644 --- a/addon/-private/system/record-arrays.js +++ b/addon/-private/system/record-arrays.js @@ -2,10 +2,7 @@ @module ember-data */ -import RecordArray from "./record-arrays/record-array"; -import AdapterPopulatedRecordArray from "./record-arrays/adapter-populated-record-array"; +import RecordArray from './record-arrays/record-array'; +import AdapterPopulatedRecordArray from './record-arrays/adapter-populated-record-array'; -export { - RecordArray, - AdapterPopulatedRecordArray -}; +export { RecordArray, AdapterPopulatedRecordArray }; diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index 7ccf8e89085..d3cc1e68a91 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -1,8 +1,8 @@ import { once } from '@ember/runloop'; import { A } from '@ember/array'; import { get } from '@ember/object'; -import RecordArray from "./record-array"; -import cloneNull from "../clone-null"; +import RecordArray from './record-array'; +import cloneNull from '../clone-null'; /** Represents an ordered list of records whose order and membership is @@ -80,7 +80,7 @@ export default RecordArray.extend({ isLoaded: true, isUpdating: false, meta: cloneNull(payload.meta), - links: cloneNull(payload.links) + links: cloneNull(payload.links), }); this.manager._associateWithRecordArray(internalModels, this); @@ -88,5 +88,5 @@ export default RecordArray.extend({ // TODO: should triggering didLoad event be the last action of the runLoop? once(this, 'trigger', 'didLoad'); heimdall.stop(token); - } + }, }); diff --git a/addon/-private/system/record-arrays/record-array.js b/addon/-private/system/record-arrays/record-array.js index 71d2ffdef1c..78afefda737 100644 --- a/addon/-private/system/record-arrays/record-array.js +++ b/addon/-private/system/record-arrays/record-array.js @@ -7,8 +7,8 @@ import Evented from '@ember/object/evented'; import ArrayProxy from '@ember/array/proxy'; import { set, get, computed } from '@ember/object'; import { Promise } from 'rsvp'; -import { PromiseArray } from "../promise-proxies"; -import SnapshotRecordArray from "../snapshot-record-array"; +import { PromiseArray } from '../promise-proxies'; +import SnapshotRecordArray from '../snapshot-record-array'; /** A record array is an array that contains records of a certain modelName. The record @@ -53,7 +53,7 @@ export default ArrayProxy.extend(Evented, { @type Boolean */ this.isLoaded = this.isLoaded || false; - /** + /** The flag to signal a `RecordArray` is currently loading data. Example @@ -70,7 +70,7 @@ export default ArrayProxy.extend(Evented, { */ this.isUpdating = false; - /** + /** The store that created this record array. @property store @@ -82,7 +82,11 @@ export default ArrayProxy.extend(Evented, { }, replace() { - throw new Error(`The result of a server query (for all ${this.modelName} types) is immutable. To modify contents, use toArray()`); + throw new Error( + `The result of a server query (for all ${ + this.modelName + } types) is immutable. To modify contents, use toArray()` + ); }, /** @@ -131,13 +135,17 @@ export default ArrayProxy.extend(Evented, { @method update */ update() { - if (get(this, 'isUpdating')) { return this._updatingPromise; } + if (get(this, 'isUpdating')) { + return this._updatingPromise; + } this.set('isUpdating', true); let updatingPromise = this._update().finally(() => { this._updatingPromise = null; - if (this.get('isDestroying') || this.get('isDestroyed')) { return } + if (this.get('isDestroying') || this.get('isDestroyed')) { + return; + } this.set('isUpdating', false); }); @@ -197,8 +205,11 @@ export default ArrayProxy.extend(Evented, { */ save() { let promiseLabel = `DS: RecordArray#save ${this.modelName}`; - let promise = Promise.all(this.invoke('save'), promiseLabel) - .then(() => this, null, 'DS: RecordArray#save return RecordArray'); + let promise = Promise.all(this.invoke('save'), promiseLabel).then( + () => this, + null, + 'DS: RecordArray#save return RecordArray' + ); return PromiseArray.create({ promise }); }, @@ -251,5 +262,5 @@ export default ArrayProxy.extend(Evented, { */ _takeSnapshot() { return get(this, 'content').map(internalModel => internalModel.createSnapshot()); - } + }, }); diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 44094076f65..24c9ad6cddf 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -14,7 +14,6 @@ import { assertPolymorphicType } from 'ember-data/-debug'; @extends DS.Reference */ export default class BelongsToReference extends Reference { - constructor(store, parentInternalModel, belongsToRelationship) { super(store, parentInternalModel); this.belongsToRelationship = belongsToRelationship; @@ -60,10 +59,10 @@ export default class BelongsToReference extends Reference { */ remoteType() { if (this.belongsToRelationship.link) { - return "link"; + return 'link'; } - return "id"; + return 'id'; } /** @@ -235,7 +234,7 @@ export default class BelongsToReference extends Reference { @return {Promise} A promise that resolves with the new value in this belongs-to relationship. */ push(objectOrPromise) { - return resolve(objectOrPromise).then((data) => { + return resolve(objectOrPromise).then(data => { let record; if (data instanceof Model) { @@ -244,7 +243,12 @@ export default class BelongsToReference extends Reference { record = this.store.push(data); } - assertPolymorphicType(this.internalModel, this.belongsToRelationship.relationshipMeta, record._internalModel, this.store); + assertPolymorphicType( + this.internalModel, + this.belongsToRelationship.relationshipMeta, + record._internalModel, + this.store + ); this.belongsToRelationship.setCanonicalInternalModel(record._internalModel); @@ -346,12 +350,12 @@ export default class BelongsToReference extends Reference { @return {Promise} a promise that resolves with the record in this belongs-to relationship. */ load() { - if (this.remoteType() === "id") { + if (this.remoteType() === 'id') { return this.belongsToRelationship.getRecord(); } - if (this.remoteType() === "link") { - return this.belongsToRelationship.findLink().then((internalModel) => { + if (this.remoteType() === 'link') { + return this.belongsToRelationship.findLink().then(internalModel => { return this.value(); }); } @@ -393,9 +397,8 @@ export default class BelongsToReference extends Reference { @return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed. */ reload() { - return this.belongsToRelationship.reload().then((internalModel) => { + return this.belongsToRelationship.reload().then(internalModel => { return this.value(); }); } - } diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index ddd775d89de..60b7acb75fd 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -61,10 +61,10 @@ export default class HasManyReference extends Reference { */ remoteType() { if (this.hasManyRelationship.link) { - return "link"; + return 'link'; } - return "ids"; + return 'ids'; } /** @@ -232,20 +232,25 @@ export default class HasManyReference extends Reference { @return {DS.ManyArray} */ push(objectOrPromise) { - return resolve(objectOrPromise).then((payload) => { + return resolve(objectOrPromise).then(payload => { let array = payload; - if (typeof payload === "object" && payload.data) { + if (typeof payload === 'object' && payload.data) { array = payload.data; } let internalModels; - internalModels = array.map((obj) => { + internalModels = array.map(obj => { let record = this.store.push(obj); if (DEBUG) { let relationshipMeta = this.hasManyRelationship.relationshipMeta; - assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel, this.store); + assertPolymorphicType( + this.internalModel, + relationshipMeta, + record._internalModel, + this.store + ); } return record._internalModel; @@ -398,5 +403,4 @@ export default class HasManyReference extends Reference { reload() { return this.hasManyRelationship.reload(); } - } diff --git a/addon/-private/system/references/record.js b/addon/-private/system/references/record.js index 086945b3a22..56bb3338192 100644 --- a/addon/-private/system/references/record.js +++ b/addon/-private/system/references/record.js @@ -87,7 +87,7 @@ export default class RecordReference extends Reference { @return Promise a promise for the value (record or relationship) */ push(objectOrPromise) { - return resolve(objectOrPromise).then((data) => { + return resolve(objectOrPromise).then(data => { return this.store.push(data); }); } @@ -159,5 +159,4 @@ export default class RecordReference extends Reference { return this.load(); } - } diff --git a/addon/-private/system/references/reference.js b/addon/-private/system/references/reference.js index 5f3fbdae646..bdf669d3ae4 100644 --- a/addon/-private/system/references/reference.js +++ b/addon/-private/system/references/reference.js @@ -4,7 +4,7 @@ var Reference = function(store, internalModel) { }; Reference.prototype = { - constructor: Reference + constructor: Reference, }; export default Reference; diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 8256a5737ee..3fe47ee9cc7 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -1,6 +1,6 @@ import { computed } from '@ember/object'; import { assert, warn, inspect } from '@ember/debug'; -import normalizeModelName from "../normalize-model-name"; +import normalizeModelName from '../normalize-model-name'; /** `DS.belongsTo` is used to define One-To-One and One-To-Many @@ -88,7 +88,12 @@ export default function belongsTo(modelName, options) { userEnteredModelName = normalizeModelName(userEnteredModelName); } - assert("The first argument to DS.belongsTo must be a string representing a model type key, not an instance of " + inspect(userEnteredModelName) + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", typeof userEnteredModelName === 'string' || typeof userEnteredModelName === 'undefined'); + assert( + 'The first argument to DS.belongsTo must be a string representing a model type key, not an instance of ' + + inspect(userEnteredModelName) + + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", + typeof userEnteredModelName === 'string' || typeof userEnteredModelName === 'undefined' + ); opts = opts || {}; @@ -98,21 +103,33 @@ export default function belongsTo(modelName, options) { options: opts, kind: 'belongsTo', name: 'Belongs To', - key: null + key: null, }; return computed({ get(key) { if (opts.hasOwnProperty('serialize')) { - warn(`You provided a serialize option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.Serializer and it's implementations https://emberjs.com/api/data/classes/DS.Serializer.html`, false, { - id: 'ds.model.serialize-option-in-belongs-to' - }); + warn( + `You provided a serialize option on the "${key}" property in the "${ + this._internalModel.modelName + }" class, this belongs in the serializer. See DS.Serializer and it's implementations https://emberjs.com/api/data/classes/DS.Serializer.html`, + false, + { + id: 'ds.model.serialize-option-in-belongs-to', + } + ); } if (opts.hasOwnProperty('embedded')) { - warn(`You provided an embedded option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin https://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html`, false, { - id: 'ds.model.embedded-option-in-belongs-to' - }); + warn( + `You provided an embedded option on the "${key}" property in the "${ + this._internalModel.modelName + }" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin https://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html`, + false, + { + id: 'ds.model.embedded-option-in-belongs-to', + } + ); } return this._internalModel._relationships.get(key).getRecord(); @@ -121,6 +138,6 @@ export default function belongsTo(modelName, options) { this._internalModel.setDirtyBelongsTo(key, value); return this._internalModel._relationships.get(key).getRecord(); - } + }, }).meta(meta); } diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index d848397cf1d..d35608b5583 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -1,16 +1,15 @@ import { A } from '@ember/array'; -import { computed , get } from '@ember/object'; +import { computed, get } from '@ember/object'; import MapWithDefault from '../map-with-default'; import Map from '../map'; import { assert } from '@ember/debug'; -import { - typeForRelationshipMeta, - relationshipFromMeta -} from "../relationship-meta"; +import { typeForRelationshipMeta, relationshipFromMeta } from '../relationship-meta'; export const relationshipsDescriptor = computed(function() { let map = new MapWithDefault({ - defaultValue() { return []; } + defaultValue() { + return []; + }, }); let relationshipsByName = get(this, 'relationshipsByName'); @@ -36,10 +35,18 @@ export const relatedTypesDescriptor = computed(function() { meta.key = name; modelName = typeForRelationshipMeta(meta); - assert(`You specified a hasMany (${meta.type}) on ${meta.parentType} but ${meta.type} was not found.`, modelName); + assert( + `You specified a hasMany (${meta.type}) on ${meta.parentType} but ${ + meta.type + } was not found.`, + modelName + ); if (!types.includes(modelName)) { - assert(`Trying to sideload ${name} on ${this.toString()} but the type doesn't exist.`, !!modelName); + assert( + `Trying to sideload ${name} on ${this.toString()} but the type doesn't exist.`, + !!modelName + ); types.push(modelName); } } diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index 6a575466a41..56546c69e89 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -3,7 +3,7 @@ */ import { computed } from '@ember/object'; import { assert, inspect } from '@ember/debug'; -import normalizeModelName from "../normalize-model-name"; +import normalizeModelName from '../normalize-model-name'; /** `DS.hasMany` is used to define One-To-Many and Many-To-Many @@ -117,7 +117,12 @@ export default function hasMany(type, options) { type = undefined; } - assert(`The first argument to DS.hasMany must be a string representing a model type key, not an instance of ${inspect(type)}. E.g., to define a relation to the Comment model, use DS.hasMany('comment')`, typeof type === 'string' || typeof type === 'undefined'); + assert( + `The first argument to DS.hasMany must be a string representing a model type key, not an instance of ${inspect( + type + )}. E.g., to define a relation to the Comment model, use DS.hasMany('comment')`, + typeof type === 'string' || typeof type === 'undefined' + ); options = options || {}; @@ -135,7 +140,7 @@ export default function hasMany(type, options) { isRelationship: true, kind: 'hasMany', name: 'Has Many', - key: null + key: null, }; return computed({ @@ -146,6 +151,6 @@ export default function hasMany(type, options) { this._internalModel.setDirtyHasMany(key, records); return this._internalModel._relationships.get(key).getRecords(); - } + }, }).meta(meta); } diff --git a/addon/-private/system/relationships/relationship-payloads-manager.js b/addon/-private/system/relationships/relationship-payloads-manager.js index bc67a6aefde..64282e729cf 100644 --- a/addon/-private/system/relationships/relationship-payloads-manager.js +++ b/addon/-private/system/relationships/relationship-payloads-manager.js @@ -112,7 +112,9 @@ export default class RelationshipPayloadsManager { @method */ push(modelName, id, relationshipsData) { - if (!relationshipsData) { return; } + if (!relationshipsData) { + return; + } Object.keys(relationshipsData).forEach(key => { let relationshipPayloads = this._getRelationshipPayloads(modelName, key, true); @@ -208,7 +210,8 @@ export default class RelationshipPayloadsManager { inverseMeta = modelClass.inverseFor(relationshipName, store); } - let selfIsPolymorphic = relationshipMeta.options !== undefined && relationshipMeta.options.polymorphic === true; + let selfIsPolymorphic = + relationshipMeta.options !== undefined && relationshipMeta.options.polymorphic === true; let inverseBaseModelName = relationshipMeta.type; // CASE: We have no inverse @@ -228,7 +231,7 @@ export default class RelationshipPayloadsManager { rhs_isPolymorphic: false, hasInverse: false, isSelfReferential: false, // modelName === inverseBaseModelName, - isReflexive: false + isReflexive: false, }; inverseCache.set(modelName, relationshipName, info); @@ -239,7 +242,9 @@ export default class RelationshipPayloadsManager { // CASE: We do have an inverse let inverseRelationshipName = inverseMeta.name; - let inverseRelationshipMeta = get(inverseMeta.type, 'relationshipsByName').get(inverseRelationshipName); + let inverseRelationshipMeta = get(inverseMeta.type, 'relationshipsByName').get( + inverseRelationshipName + ); let baseModelName = inverseRelationshipMeta.type; let isSelfReferential = baseModelName === inverseBaseModelName; @@ -254,11 +259,15 @@ export default class RelationshipPayloadsManager { // CASE: We may have already discovered the inverse for the baseModelName // CASE: We have already discovered the inverse - cached = inverseCache.get(baseModelName, relationshipName) || + cached = + inverseCache.get(baseModelName, relationshipName) || inverseCache.get(inverseBaseModelName, inverseRelationshipName); if (cached) { // TODO this assert can be removed if the above assert is enabled - assert(`The ${inverseBaseModelName}:${inverseRelationshipName} relationship declares 'inverse: null', but it was resolved as the inverse for ${baseModelName}:${relationshipName}.`, cached.hasInverse !== false); + assert( + `The ${inverseBaseModelName}:${inverseRelationshipName} relationship declares 'inverse: null', but it was resolved as the inverse for ${baseModelName}:${relationshipName}.`, + cached.hasInverse !== false + ); let isLHS = cached.lhs_baseModelName === baseModelName; let modelNames = isLHS ? cached.lhs_modelNames : cached.rhs_modelNames; @@ -281,10 +290,12 @@ export default class RelationshipPayloadsManager { rhs_baseModelName: inverseBaseModelName, rhs_relationshipName: inverseRelationshipName, rhs_relationshipMeta: inverseRelationshipMeta, - rhs_isPolymorphic: inverseRelationshipMeta.options !== undefined && inverseRelationshipMeta.options.polymorphic === true, + rhs_isPolymorphic: + inverseRelationshipMeta.options !== undefined && + inverseRelationshipMeta.options.polymorphic === true, hasInverse: true, isSelfReferential, - isReflexive: isSelfReferential && relationshipName === inverseRelationshipName + isReflexive: isSelfReferential && relationshipName === inverseRelationshipName, }; // Create entries for the baseModelName as well as modelName to speed up @@ -324,7 +335,7 @@ export default class RelationshipPayloadsManager { // This works out better than creating a single common key, because to // compute that key we would need to do work to look up the inverse // - let cache = this._cache[lhsKey] = new RelationshipPayloads(relInfo); + let cache = (this._cache[lhsKey] = new RelationshipPayloads(relInfo)); if (relInfo.hasInverse === true) { this._cache[rhsKey] = cache; diff --git a/addon/-private/system/relationships/relationship-payloads.js b/addon/-private/system/relationships/relationship-payloads.js index e82d5b7bcc5..07b051dd14f 100644 --- a/addon/-private/system/relationships/relationship-payloads.js +++ b/addon/-private/system/relationships/relationship-payloads.js @@ -140,7 +140,12 @@ export default class RelationshipPayloads { if (this._isLHS(modelName, relationshipName)) { return this.lhs_payloads.get(modelName, id); } else { - assert(`${modelName}:${relationshipName} is not either side of this relationship, ${this._relInfo.lhs_key}<->${this._relInfo.rhs_key}`, this._isRHS(modelName, relationshipName)); + assert( + `${modelName}:${relationshipName} is not either side of this relationship, ${ + this._relInfo.lhs_key + }<->${this._relInfo.rhs_key}`, + this._isRHS(modelName, relationshipName) + ); return this.rhs_payloads.get(modelName, id); } } @@ -169,7 +174,14 @@ export default class RelationshipPayloads { if (this._isLHS(modelName, relationshipName)) { delete this.lhs_payloads.delete(modelName, id); } else { - assert(`${modelName}:${relationshipName} is not either side of this relationship, ${this._relInfo.lhs_baseModelName}:${this._relInfo.lhs_relationshipName}<->${this._relInfo.rhs_baseModelName}:${this._relInfo.rhs_relationshipName}`, this._isRHS(modelName, relationshipName)); + assert( + `${modelName}:${relationshipName} is not either side of this relationship, ${ + this._relInfo.lhs_baseModelName + }:${this._relInfo.lhs_relationshipName}<->${this._relInfo.rhs_baseModelName}:${ + this._relInfo.rhs_relationshipName + }`, + this._isRHS(modelName, relationshipName) + ); delete this.rhs_payloads.delete(modelName, id); } } @@ -186,9 +198,11 @@ export default class RelationshipPayloads { let isRelationship = relationshipName === relInfo.lhs_relationshipName; if (isRelationship === true) { - return isSelfReferential === true || // itself + return ( + isSelfReferential === true || // itself modelName === relInfo.lhs_baseModelName || // base or non-polymorphic - relInfo.lhs_modelNames.indexOf(modelName) !== -1; // polymorphic + relInfo.lhs_modelNames.indexOf(modelName) !== -1 + ); // polymorphic } return false; @@ -206,19 +220,23 @@ export default class RelationshipPayloads { let isRelationship = relationshipName === relInfo.rhs_relationshipName; if (isRelationship === true) { - return isSelfReferential === true || // itself + return ( + isSelfReferential === true || // itself modelName === relInfo.rhs_baseModelName || // base or non-polymorphic - relInfo.rhs_modelNames.indexOf(modelName) !== -1; // polymorphic + relInfo.rhs_modelNames.indexOf(modelName) !== -1 + ); // polymorphic } return false; } _flushPending() { - if (this._pendingPayloads.length === 0) { return; } + if (this._pendingPayloads.length === 0) { + return; + } let payloadsToBeProcessed = this._pendingPayloads.splice(0, this._pendingPayloads.length); - for (let i=0; i${this._relInfo.rhs_key}`, this._isRHS(modelName, relationshipName)); + assert( + `${modelName}:${relationshipName} is not either side of this relationship, ${ + this._relInfo.lhs_key + }<->${this._relInfo.rhs_key}`, + this._isRHS(modelName, relationshipName) + ); previousPayload = this.rhs_payloads.get(modelName, id); payloadMap = this.rhs_payloads; inversePayloadMap = this.lhs_payloads; @@ -307,17 +330,18 @@ export default class RelationshipPayloads { payloadMap.set(modelName, id, relationshipData); if (!isMatchingIdentifier) { - this._populateInverse(relationshipData, inverseRelationshipData, inversePayloadMap, inverseIsMany); + this._populateInverse( + relationshipData, + inverseRelationshipData, + inversePayloadMap, + inverseIsMany + ); } } } _isMatchingIdentifier(a, b) { - return a && b && - a.type === b.type && - a.id === b.id && - !Array.isArray(a) && - !Array.isArray(b); + return a && b && a.type === b.type && a.id === b.id && !Array.isArray(a) && !Array.isArray(b); } /** @@ -338,7 +362,7 @@ export default class RelationshipPayloads { } if (Array.isArray(relationshipData.data)) { - for (let i=0; i x.id !== id); + inversePayload.data = data.filter(x => x.id !== id); } else if (Array.isArray(partialData)) { - inversePayload._partialData = partialData.filter((x) => x.id !== id); + inversePayload._partialData = partialData.filter(x => x.id !== id); } else { // this merges forward links and meta inversePayload.data = null; diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 2f859682ec9..ba907947725 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -1,10 +1,8 @@ import { Promise as EmberPromise } from 'rsvp'; import { assert } from '@ember/debug'; import { assertPolymorphicType } from 'ember-data/-debug'; -import { - PromiseBelongsTo -} from "../../promise-proxies"; -import Relationship from "./relationship"; +import { PromiseBelongsTo } from '../../promise-proxies'; +import Relationship from './relationship'; export default class BelongsToRelationship extends Relationship { constructor(store, internalModel, inverseKey, relationshipMeta) { @@ -36,7 +34,9 @@ export default class BelongsToRelationship extends Relationship { } setInitialCanonicalInternalModel(internalModel) { - if (!internalModel) { return; } + if (!internalModel) { + return; + } // When we initialize a belongsTo relationship, we want to avoid work like // notifying our internalModel that we've "changed" and excessive thrash on @@ -48,7 +48,9 @@ export default class BelongsToRelationship extends Relationship { } addCanonicalInternalModel(internalModel) { - if (this.canonicalMembers.has(internalModel)) { return;} + if (this.canonicalMembers.has(internalModel)) { + return; + } if (this.canonicalState) { this.removeCanonicalInternalModel(this.canonicalState); @@ -76,7 +78,6 @@ export default class BelongsToRelationship extends Relationship { } } - removeCompletelyFromInverse() { super.removeCompletelyFromInverse(); @@ -98,7 +99,9 @@ export default class BelongsToRelationship extends Relationship { } addInternalModel(internalModel) { - if (this.members.has(internalModel)) { return; } + if (this.members.has(internalModel)) { + return; + } assertPolymorphicType(this.internalModel, this.relationshipMeta, internalModel, this.store); @@ -113,12 +116,17 @@ export default class BelongsToRelationship extends Relationship { setRecordPromise(newPromise) { let content = newPromise.get && newPromise.get('content'); - assert("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); + assert( + 'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.', + content !== undefined + ); this.setInternalModel(content ? content._internalModel : content); } removeInternalModelFromOwn(internalModel) { - if (!this.members.has(internalModel)) { return;} + if (!this.members.has(internalModel)) { + return; + } this.inverseInternalModel = null; super.removeInternalModelFromOwn(internalModel); this.notifyBelongsToChanged(); @@ -135,7 +143,9 @@ export default class BelongsToRelationship extends Relationship { } removeCanonicalInternalModelFromOwn(internalModel) { - if (!this.canonicalMembers.has(internalModel)) { return;} + if (!this.canonicalMembers.has(internalModel)) { + return; + } this.canonicalState = null; super.removeCanonicalInternalModelFromOwn(internalModel); } @@ -154,12 +164,14 @@ export default class BelongsToRelationship extends Relationship { } fetchLink() { - return this.store.findBelongsTo(this.internalModel, this.link, this.relationshipMeta).then((internalModel) => { - if (internalModel) { - this.addInternalModel(internalModel); - } - return internalModel; - }); + return this.store + .findBelongsTo(this.internalModel, this.link, this.relationshipMeta) + .then(internalModel => { + if (internalModel) { + this.addInternalModel(internalModel); + } + return internalModel; + }); } getRecord() { @@ -173,7 +185,7 @@ export default class BelongsToRelationship extends Relationship { promise = this.findRecord(); } - let record = this.inverseInternalModel ? this.inverseInternalModel.getRecord() : null + let record = this.inverseInternalModel ? this.inverseInternalModel.getRecord() : null; return this._updateLoadingPromise(promise, record); } else { @@ -181,7 +193,16 @@ export default class BelongsToRelationship extends Relationship { return null; } let toReturn = this.inverseInternalModel.getRecord(); - assert("You looked up the '" + this.key + "' relationship on a '" + this.internalModel.modelName + "' with id " + this.internalModel.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); + assert( + "You looked up the '" + + this.key + + "' relationship on a '" + + this.internalModel.modelName + + "' with id " + + this.internalModel.id + + ' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)', + toReturn === null || !toReturn.get('isEmpty') + ); return toReturn; } } @@ -189,14 +210,14 @@ export default class BelongsToRelationship extends Relationship { _updateLoadingPromise(promise, content) { if (this._loadingPromise) { if (content !== undefined) { - this._loadingPromise.set('content', content) + this._loadingPromise.set('content', content); } - this._loadingPromise.set('promise', promise) + this._loadingPromise.set('promise', promise); } else { this._loadingPromise = PromiseBelongsTo.create({ _belongsToState: this, promise, - content + content, }); } @@ -229,7 +250,7 @@ export default class BelongsToRelationship extends Relationship { localStateIsEmpty() { let internalModel = this.inverseInternalModel; - return !internalModel || internalModel.isEmpty(); + return !internalModel || internalModel.isEmpty(); } updateData(data, initial) { diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index 1039683f91e..ed82b773f7c 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -1,6 +1,6 @@ import { get } from '@ember/object'; -import ManyRelationship from "./has-many"; -import BelongsToRelationship from "./belongs-to"; +import ManyRelationship from './has-many'; +import BelongsToRelationship from './belongs-to'; import { DEBUG } from '@glimmer/env'; function shouldFindInverse(relationshipMeta) { @@ -60,11 +60,21 @@ export default class Relationships { let relationshipsByName = get(internalModel.type, 'relationshipsByName'); let rel = relationshipsByName.get(key); - if (!rel) { return undefined; } - - let relationshipPayload = internalModel.store._relationshipsPayloads.get(internalModel.modelName, internalModel.id, key); + if (!rel) { + return undefined; + } - relationship = relationships[key] = createRelationshipFor(internalModel, rel, internalModel.store); + let relationshipPayload = internalModel.store._relationshipsPayloads.get( + internalModel.modelName, + internalModel.id, + key + ); + + relationship = relationships[key] = createRelationshipFor( + internalModel, + rel, + internalModel.store + ); if (relationshipPayload) { relationship.push(relationshipPayload, true); diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index cc4523051cf..54253422634 100755 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -24,13 +24,13 @@ export default class ManyRelationship extends Relationship { _updateLoadingPromise(promise, content) { if (this._loadingPromise) { if (content) { - this._loadingPromise.set('content', content) + this._loadingPromise.set('content', content); } - this._loadingPromise.set('promise', promise) + this._loadingPromise.set('promise', promise); } else { this._loadingPromise = PromiseManyArray.create({ promise, - content + content, }); } @@ -38,7 +38,12 @@ export default class ManyRelationship extends Relationship { } get manyArray() { - assert(`Error: relationship ${this.parentType}:${this.key} has both many array and retained many array`, this._manyArray === null || this._retainedManyArray === null); + assert( + `Error: relationship ${this.parentType}:${ + this.key + } has both many array and retained many array`, + this._manyArray === null || this._retainedManyArray === null + ); if (!this._manyArray && !this.isDestroying) { this._manyArray = ManyArray.create({ @@ -48,7 +53,7 @@ export default class ManyRelationship extends Relationship { type: this.store.modelFor(this.belongsToType), record: this.internalModel, meta: this.meta, - isPolymorphic: this.isPolymorphic + isPolymorphic: this.isPolymorphic, }); if (this._retainedManyArray !== null) { @@ -120,7 +125,7 @@ export default class ManyRelationship extends Relationship { // return; // } - let pending = this._pendingManyArrayUpdates = this._pendingManyArrayUpdates || []; + let pending = (this._pendingManyArrayUpdates = this._pendingManyArrayUpdates || []); pending.push(internalModel, idx); if (this._willUpdateManyArray === true) { @@ -271,7 +276,9 @@ export default class ManyRelationship extends Relationship { let internalModelSet = setForArray(internalModels); members.forEach(member => { - if (internalModelSet.has(member)) { return; } + if (internalModelSet.has(member)) { + return; + } internalModelsToRemove.push(member); }); @@ -290,7 +297,7 @@ export default class ManyRelationship extends Relationship { return; } - for (let i = 0; i< internalModels.length; i++) { + for (let i = 0; i < internalModels.length; i++) { let internalModel = internalModels[i]; if (this.canonicalMembers.has(internalModel)) { continue; @@ -305,16 +312,18 @@ export default class ManyRelationship extends Relationship { } fetchLink() { - return this.store.findHasMany(this.internalModel, this.link, this.relationshipMeta).then(records => { - if (records.hasOwnProperty('meta')) { - this.updateMeta(records.meta); - } - this.store._backburner.join(() => { - this.updateInternalModelsFromAdapter(records); - this.manyArray.set('isLoaded', true); + return this.store + .findHasMany(this.internalModel, this.link, this.relationshipMeta) + .then(records => { + if (records.hasOwnProperty('meta')) { + this.updateMeta(records.meta); + } + this.store._backburner.join(() => { + this.updateInternalModelsFromAdapter(records); + this.manyArray.set('isLoaded', true); + }); + return this.manyArray; }); - return this.manyArray; - }); } findRecords() { @@ -350,7 +359,14 @@ export default class ManyRelationship extends Relationship { return this._updateLoadingPromise(promise, manyArray); } else { - assert(`You looked up the '${this.key}' relationship on a '${this.internalModel.type.modelName}' with id ${this.internalModel.id} but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async ('DS.hasMany({ async: true })')`, manyArray.isEvery('isEmpty', false)); + assert( + `You looked up the '${this.key}' relationship on a '${ + this.internalModel.type.modelName + }' with id ${ + this.internalModel.id + } but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async ('DS.hasMany({ async: true })')`, + manyArray.isEvery('isEmpty', false) + ); manyArray.set('isLoaded', true); @@ -404,7 +420,7 @@ function setForArray(array) { var set = new OrderedSet(); if (array) { - for (var i=0, l=array.length; i { + this.forAllMembers(inverseInternalModel => { let relationship = inverseInternalModel._relationships.get(this.inverseKey); relationship.inverseDidDematerialize(this.internalModel); }); @@ -233,7 +236,7 @@ export default class Relationship { removeInternalModels(internalModels) { heimdall.increment(removeInternalModels); - internalModels.forEach((internalModel) => this.removeInternalModel(internalModel)); + internalModels.forEach(internalModel => this.removeInternalModel(internalModel)); } addInternalModels(internalModels, idx) { @@ -248,9 +251,9 @@ export default class Relationship { addCanonicalInternalModels(internalModels, idx) { heimdall.increment(addCanonicalInternalModels); - for (let i=0; i result); + return promise.then(result => result); } } @@ -525,7 +550,7 @@ export default class Relationship { this.computeChanges(internalModels); } - notifyRecordRelationshipAdded() { } + notifyRecordRelationshipAdded() {} setHasAnyRelationshipData(value) { this.hasAnyRelationshipData = value; @@ -592,15 +617,13 @@ export default class Relationship { */ if (hasRelationshipDataProperty) { - let relationshipIsEmpty = payload.data === null || - (Array.isArray(payload.data) && payload.data.length === 0); + let relationshipIsEmpty = + payload.data === null || (Array.isArray(payload.data) && payload.data.length === 0); this.setHasAnyRelationshipData(true); this.setRelationshipIsStale(false); this.setRelationshipIsEmpty(relationshipIsEmpty); - this.setHasRelatedResources( - relationshipIsEmpty || !this.localStateIsEmpty() - ); + this.setHasRelatedResources(relationshipIsEmpty || !this.localStateIsEmpty()); } else if (hasLink) { this.setRelationshipIsStale(true); } @@ -608,6 +631,5 @@ export default class Relationship { updateData() {} - destroy() { - } + destroy() {} } diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index 369e868a3f1..2ff17d9d7de 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -91,7 +91,7 @@ export default class Snapshot { let record = this.record; attributes = this.__attributes = Object.create(null); - record.eachAttribute((keyName) => attributes[keyName] = get(record, keyName)); + record.eachAttribute(keyName => (attributes[keyName] = get(record, keyName))); } return attributes; @@ -131,7 +131,9 @@ export default class Snapshot { if (keyName in this._attributes) { return this._attributes[keyName]; } - throw new EmberError("Model '" + inspect(this.record) + "' has no attribute named '" + keyName + "' defined."); + throw new EmberError( + "Model '" + inspect(this.record) + "' has no attribute named '" + keyName + "' defined." + ); } /** @@ -169,7 +171,7 @@ export default class Snapshot { let changedAttributes = Object.create(null); let changedAttributeKeys = Object.keys(this._changedAttributes); - for (let i=0, length = changedAttributeKeys.length; i < length; i++) { + for (let i = 0, length = changedAttributeKeys.length; i < length; i++) { let key = changedAttributeKeys[i]; changedAttributes[key] = this._changedAttributes[key].slice(); } @@ -227,13 +229,16 @@ export default class Snapshot { relationship = this._internalModel._relationships.get(keyName); if (!(relationship && relationship.relationshipMeta.kind === 'belongsTo')) { - throw new EmberError("Model '" + inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined."); + throw new EmberError( + "Model '" + + inspect(this.record) + + "' has no belongsTo relationship named '" + + keyName + + "' defined." + ); } - let { - hasAnyRelationshipData, - inverseInternalModel - } = relationship; + let { hasAnyRelationshipData, inverseInternalModel } = relationship; if (hasAnyRelationshipData) { if (inverseInternalModel && !inverseInternalModel.isDeleted()) { @@ -300,17 +305,20 @@ export default class Snapshot { relationship = this._internalModel._relationships.get(keyName); if (!(relationship && relationship.relationshipMeta.kind === 'hasMany')) { - throw new EmberError("Model '" + inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined."); + throw new EmberError( + "Model '" + + inspect(this.record) + + "' has no hasMany relationship named '" + + keyName + + "' defined." + ); } - let { - hasAnyRelationshipData, - members - } = relationship; + let { hasAnyRelationshipData, members } = relationship; if (hasAnyRelationshipData) { results = []; - members.forEach((member) => { + members.forEach(member => { if (!member.isDeleted()) { if (ids) { results.push(member.id); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index f146066966e..3ca251ae158 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -18,24 +18,21 @@ import { instrument } from 'ember-data/-debug'; import { assert, deprecate, warn, inspect } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; import Model from './model/model'; -import normalizeModelName from "./normalize-model-name"; +import normalizeModelName from './normalize-model-name'; import IdentityMap from './identity-map'; -import { - promiseArray, - promiseObject -} from "./promise-proxies"; +import { promiseArray, promiseObject } from './promise-proxies'; import { _bind, _guard, _objectIsAlive, guardDestroyedStore, - incrementRequestCount -} from "./store/common"; + incrementRequestCount, +} from './store/common'; -import { normalizeResponseHelper } from "./store/serializer-response"; -import { serializerForAdapter } from "./store/serializers"; +import { normalizeResponseHelper } from './store/serializer-response'; +import { serializerForAdapter } from './store/serializers'; import RelationshipPayloadsManager from './relationships/relationship-payloads-manager'; import { @@ -45,13 +42,13 @@ import { _findBelongsTo, _findAll, _query, - _queryRecord -} from "./store/finders"; + _queryRecord, +} from './store/finders'; import { getOwner } from '../utils'; -import coerceId from "./coerce-id"; -import RecordArrayManager from "./record-array-manager"; -import InternalModel from "./model/internal-model"; +import coerceId from './coerce-id'; +import RecordArrayManager from './record-array-manager'; +import InternalModel from './model/internal-model'; import edBackburner from './backburner'; const badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; @@ -97,8 +94,9 @@ const { peekAll, peekRecord, serializerFor, - _internalModelsFor -} = heimdall.registerMonitor('store', + _internalModelsFor, +} = heimdall.registerMonitor( + 'store', '_generateId', '_internalModelForId', '_load', @@ -188,7 +186,6 @@ const { @extends Ember.Service */ Store = Service.extend({ - /** @method init @private @@ -220,7 +217,11 @@ Store = Service.extend({ this._updatedInternalModels = []; // used to keep track of all the find requests that need to be coalesced - this._pendingFetch = new MapWithDefault({ defaultValue() { return []; } }); + this._pendingFetch = new MapWithDefault({ + defaultValue() { + return []; + }, + }); this._adapterCache = Object.create(null); this._serializerCache = Object.create(null); @@ -265,7 +266,10 @@ Store = Service.extend({ defaultAdapter: computed('adapter', function() { let adapter = get(this, 'adapter'); - assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name', typeof adapter === 'string'); + assert( + 'You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name', + typeof adapter === 'string' + ); return this.adapterFor(adapter); }), @@ -303,8 +307,14 @@ Store = Service.extend({ @return {DS.Model} record */ createRecord(modelName, inputProperties) { - assert(`You need to pass a model name to the store's createRecord method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `You need to pass a model name to the store's createRecord method`, + isPresent(modelName) + ); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); // This is wrapped in a `run.join` so that in test environments users do not need to manually wrap // calls to `createRecord`. The run loop usage here is because we batch the joining and updating @@ -415,12 +425,30 @@ Store = Service.extend({ // The default `model` hook in Route calls `find(modelName, id)`, // that's why we have to keep this method around even though `findRecord` is // the public way to get a record by modelName and id. - assert(`Using store.find(type) has been removed. Use store.findAll(modelName) to retrieve all records for a given type.`, arguments.length !== 1); - assert(`Calling store.find(modelName, id, { preload: preload }) is no longer supported. Use store.findRecord(modelName, id, { preload: preload }) instead.`, !options); - assert(`You need to pass the model name and id to the store's find method`, arguments.length === 2); - assert(`You cannot pass '${id}' as id to the store's find method`, typeof id === 'string' || typeof id === 'number'); - assert(`Calling store.find() with a query object is no longer supported. Use store.query() instead.`, typeof id !== 'object'); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Using store.find(type) has been removed. Use store.findAll(modelName) to retrieve all records for a given type.`, + arguments.length !== 1 + ); + assert( + `Calling store.find(modelName, id, { preload: preload }) is no longer supported. Use store.findRecord(modelName, id, { preload: preload }) instead.`, + !options + ); + assert( + `You need to pass the model name and id to the store's find method`, + arguments.length === 2 + ); + assert( + `You cannot pass '${id}' as id to the store's find method`, + typeof id === 'string' || typeof id === 'number' + ); + assert( + `Calling store.find() with a query object is no longer supported. Use store.query() instead.`, + typeof id !== 'object' + ); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); return this.findRecord(modelName, id); }, @@ -648,8 +676,14 @@ Store = Service.extend({ */ findRecord(modelName, id, options) { assert(`You need to pass a model name to the store's findRecord method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - assert(badIdFormatAssertion, (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id))); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); + assert( + badIdFormatAssertion, + (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id)) + ); let normalizedModelName = normalizeModelName(modelName); @@ -662,7 +696,10 @@ Store = Service.extend({ let fetchedInternalModel = this._findRecord(internalModel, options); - return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${normalizedModelName} with id: ${id}`); + return promiseRecord( + fetchedInternalModel, + `DS: Store#findRecord ${normalizedModelName} with id: ${id}` + ); }, _findRecord(internalModel, options) { @@ -699,7 +736,10 @@ Store = Service.extend({ let fetchedInternalModel = this._findEmptyInternalModel(internalModel, options); - return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${internalModel.modelName} with id: ${internalModel.id}`); + return promiseRecord( + fetchedInternalModel, + `DS: Store#findRecord ${internalModel.modelName} with id: ${internalModel.id}` + ); }, _findEmptyInternalModel(internalModel, options) { @@ -727,7 +767,10 @@ Store = Service.extend({ */ findByIds(modelName, ids) { assert(`You need to pass a model name to the store's findByIds method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let promises = new Array(ids.length); @@ -737,7 +780,9 @@ Store = Service.extend({ promises[i] = this.findRecord(normalizedModelName, ids[i]); } - return promiseArray(RSVP.all(promises).then(A, null, `DS: Store#findByIds of ${normalizedModelName} complete`)); + return promiseArray( + RSVP.all(promises).then(A, null, `DS: Store#findByIds of ${normalizedModelName} complete`) + ); }, /** @@ -755,7 +800,10 @@ Store = Service.extend({ let adapter = this.adapterFor(modelName); assert(`You tried to find a record but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to find a record but your adapter (for ${modelName}) does not implement 'findRecord'`, typeof adapter.findRecord === 'function'); + assert( + `You tried to find a record but your adapter (for ${modelName}) does not implement 'findRecord'`, + typeof adapter.findRecord === 'function' + ); return _find(adapter, this, internalModel.type, internalModel.id, internalModel, options); }, @@ -780,7 +828,7 @@ Store = Service.extend({ let pendingFetchItem = { internalModel, resolver, - options + options, }; let promise = resolver.promise; @@ -835,7 +883,7 @@ Store = Service.extend({ let recordFetch = store._fetchRecord( recordResolverPair.internalModel, recordResolverPair.options - ); // TODO adapter options + ); // TODO adapter options recordResolverPair.resolver.resolve(recordFetch); } @@ -872,7 +920,7 @@ Store = Service.extend({ '" ]', false, { - id: 'ds.store.missing-records-from-adapter' + id: 'ds.store.missing-records-from-adapter', } ); rejectInternalModels(missingInternalModels); @@ -885,7 +933,12 @@ Store = Service.extend({ let pair = seeking[internalModel.id]; if (pair) { - pair.resolver.reject(error || new Error(`Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.`)); + pair.resolver.reject( + error || + new Error( + `Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.` + ) + ); } } } @@ -930,12 +983,15 @@ Store = Service.extend({ .catch(function(error) { rejectInternalModels(groupedInternalModels, error); }); - }(groupedInternalModels)); + })(groupedInternalModels); } else if (ids.length === 1) { var pair = seeking[groupedInternalModels[0].id]; _fetchRecord(pair); } else { - assert("You cannot return an empty array from adapter's method groupRecordsForFindMany", false); + assert( + "You cannot return an empty array from adapter's method groupRecordsForFindMany", + false + ); } } } else { @@ -1014,8 +1070,14 @@ Store = Service.extend({ peekRecord(modelName, id) { heimdall.increment(peekRecord); assert(`You need to pass a model name to the store's peekRecord method`, isPresent(modelName)); - assert(`You need to pass both a model name and id to the store's peekRecord method`, isPresent(modelName) && isPresent(id)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `You need to pass both a model name and id to the store's peekRecord method`, + isPresent(modelName) && isPresent(id) + ); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); if (this.hasRecordForId(normalizedModelName, id)) { @@ -1044,7 +1106,10 @@ Store = Service.extend({ assert(`You cannot reload a record without an ID`, id); assert(`You tried to reload a record but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to reload a record but your adapter does not implement 'findRecord'`, typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); + assert( + `You tried to reload a record but your adapter does not implement 'findRecord'`, + typeof adapter.findRecord === 'function' || typeof adapter.find === 'function' + ); return this._scheduleFetch(internalModel, options); }, @@ -1069,8 +1134,14 @@ Store = Service.extend({ @return {Boolean} */ hasRecordForId(modelName, id) { - assert(`You need to pass a model name to the store's hasRecordForId method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `You need to pass a model name to the store's hasRecordForId method`, + isPresent(modelName) + ); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); @@ -1092,7 +1163,10 @@ Store = Service.extend({ */ recordForId(modelName, id) { assert(`You need to pass a model name to the store's recordForId method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); return this._internalModelForId(modelName, id).getRecord(); }, @@ -1147,7 +1221,6 @@ Store = Service.extend({ return Promise.all(finds); }, - /** If a relationship was originally populated by the adapter as a link (as opposed to a list of IDs), this method is called when the @@ -1169,8 +1242,16 @@ Store = Service.extend({ findHasMany(internalModel, link, relationship) { let adapter = this.adapterFor(internalModel.modelName); - assert(`You tried to load a hasMany relationship but you have no adapter (for ${internalModel.modelName})`, adapter); - assert(`You tried to load a hasMany relationship from a specified 'link' in the original payload but your adapter does not implement 'findHasMany'`, typeof adapter.findHasMany === 'function'); + assert( + `You tried to load a hasMany relationship but you have no adapter (for ${ + internalModel.modelName + })`, + adapter + ); + assert( + `You tried to load a hasMany relationship from a specified 'link' in the original payload but your adapter does not implement 'findHasMany'`, + typeof adapter.findHasMany === 'function' + ); return _findHasMany(adapter, this, internalModel, link, relationship); }, @@ -1186,8 +1267,16 @@ Store = Service.extend({ findBelongsTo(internalModel, link, relationship) { let adapter = this.adapterFor(internalModel.modelName); - assert(`You tried to load a belongsTo relationship but you have no adapter (for ${internalModel.modelName})`, adapter); - assert(`You tried to load a belongsTo relationship from a specified 'link' in the original payload but your adapter does not implement 'findBelongsTo'`, typeof adapter.findBelongsTo === 'function'); + assert( + `You tried to load a belongsTo relationship but you have no adapter (for ${ + internalModel.modelName + })`, + adapter + ); + assert( + `You tried to load a belongsTo relationship from a specified 'link' in the original payload but your adapter does not implement 'findBelongsTo'`, + typeof adapter.findBelongsTo === 'function' + ); return _findBelongsTo(adapter, this, internalModel, link, relationship); }, @@ -1248,12 +1337,15 @@ Store = Service.extend({ query(modelName, query, options) { assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); assert(`You need to pass a query hash to the store's query method`, query); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let adapterOptionsWrapper = {}; if (options && options.adapterOptions) { - adapterOptionsWrapper.adapterOptions = options.adapterOptions + adapterOptionsWrapper.adapterOptions = options.adapterOptions; } let normalizedModelName = normalizeModelName(modelName); @@ -1264,7 +1356,10 @@ Store = Service.extend({ let token = heimdall.start('store._query'); assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); assert(`You need to pass a query hash to the store's query method`, query); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let modelToken = heimdall.start('initial-modelFor-lookup'); heimdall.stop(modelToken); @@ -1274,11 +1369,16 @@ Store = Service.extend({ heimdall.stop(adapterToken); assert(`You tried to load a query but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to load a query but your adapter does not implement 'query'`, typeof adapter.query === 'function'); + assert( + `You tried to load a query but your adapter does not implement 'query'`, + typeof adapter.query === 'function' + ); let pA = promiseArray(_query(adapter, this, modelName, query, array, options)); instrument(() => { - pA.finally(() => { heimdall.stop(token); }); + pA.finally(() => { + heimdall.stop(token); + }); }); return pA; }, @@ -1383,28 +1483,39 @@ Store = Service.extend({ queryRecord(modelName, query, options) { assert(`You need to pass a model name to the store's queryRecord method`, isPresent(modelName)); assert(`You need to pass a query hash to the store's queryRecord method`, query); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); let adapter = this.adapterFor(normalizedModelName); let adapterOptionsWrapper = {}; if (options && options.adapterOptions) { - adapterOptionsWrapper.adapterOptions = options.adapterOptions + adapterOptionsWrapper.adapterOptions = options.adapterOptions; } - assert(`You tried to make a query but you have no adapter (for ${normalizedModelName})`, adapter); - assert(`You tried to make a query but your adapter does not implement 'queryRecord'`, typeof adapter.queryRecord === 'function'); + assert( + `You tried to make a query but you have no adapter (for ${normalizedModelName})`, + adapter + ); + assert( + `You tried to make a query but your adapter does not implement 'queryRecord'`, + typeof adapter.queryRecord === 'function' + ); - return promiseObject(_queryRecord(adapter, this, modelName, query, adapterOptionsWrapper).then(internalModel => { - // the promise returned by store.queryRecord is expected to resolve with - // an instance of DS.Model - if (internalModel) { - return internalModel.getRecord(); - } + return promiseObject( + _queryRecord(adapter, this, modelName, query, adapterOptionsWrapper).then(internalModel => { + // the promise returned by store.queryRecord is expected to resolve with + // an instance of DS.Model + if (internalModel) { + return internalModel.getRecord(); + } - return null; - })); + return null; + }) + ); }, /** @@ -1597,14 +1708,19 @@ Store = Service.extend({ */ findAll(modelName, options) { assert(`You need to pass a model name to the store's findAll method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let token = heimdall.start('store.findAll'); let normalizedModelName = normalizeModelName(modelName); let fetch = this._fetchAll(normalizedModelName, this.peekAll(normalizedModelName), options); instrument(() => { - fetch.finally(() => { heimdall.stop(token); }); + fetch.finally(() => { + heimdall.stop(token); + }); }); return fetch; @@ -1622,7 +1738,10 @@ Store = Service.extend({ let sinceToken = this._internalModelsFor(modelName).metadata.since; assert(`You tried to load all records but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to load all records but your adapter does not implement 'findAll'`, typeof adapter.findAll === 'function'); + assert( + `You tried to load all records but your adapter does not implement 'findAll'`, + typeof adapter.findAll === 'function' + ); if (options.reload) { set(array, 'isUpdating', true); @@ -1685,7 +1804,10 @@ Store = Service.extend({ peekAll(modelName) { heimdall.increment(peekAll); assert(`You need to pass a model name to the store's peekAll method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); return this.recordArrayManager.liveRecordArrayFor(normalizedModelName); }, @@ -1705,7 +1827,10 @@ Store = Service.extend({ @param {String} modelName */ unloadAll(modelName) { - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, !modelName || typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + !modelName || typeof modelName === 'string' + ); if (arguments.length === 0) { this._identityMap.clear(); @@ -1716,7 +1841,10 @@ Store = Service.extend({ }, filter() { - assert('The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', false); + assert( + 'The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', + false + ); }, // .............. @@ -1741,7 +1869,7 @@ Store = Service.extend({ internalModel.adapterWillCommit(); this._pendingSave.push({ snapshot: snapshot, - resolver: resolver + resolver: resolver, }); emberRun.once(this, this.flushPendingSave); }, @@ -1778,7 +1906,6 @@ Store = Service.extend({ resolver.resolve(_commit(adapter, this, operation, snapshot)); } - }, /** @@ -1804,7 +1931,12 @@ Store = Service.extend({ this.updateId(internalModel, data); this._setupRelationshipsForModel(internalModel, data); } else { - assert(`Your ${internalModel.modelName} record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, internalModel.id); + assert( + `Your ${ + internalModel.modelName + } record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, + internalModel.id + ); } //We first make sure the primary data has been updated @@ -1856,22 +1988,33 @@ Store = Service.extend({ let id = coerceId(data.id); // ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record) - assert(`'${modelName}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null)); + assert( + `'${modelName}' was saved to the server, but the response does not have an id and your record does not either.`, + !(id === null && oldId === null) + ); // ID absolutely can't be different than oldID if oldID is not null - assert(`'${modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, !(oldId !== null && id !== oldId)); + assert( + `'${modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, + !(oldId !== null && id !== oldId) + ); // ID can be null if oldID is not null (altered ID in response for a record) // however, this is more than likely a developer error. if (oldId !== null && id === null) { - warn(`Your ${modelName} record was saved to the server, but the response does not have an id.`, !(oldId !== null && id === null)); + warn( + `Your ${modelName} record was saved to the server, but the response does not have an id.`, + !(oldId !== null && id === null) + ); return; } let existingInternalModel = this._existingInternalModelForId(modelName, id); - assert(`'${modelName}' was saved to the server, but the response returned the new id '${id}', which has already been used with another record.'`, - isNone(existingInternalModel) || existingInternalModel === internalModel); + assert( + `'${modelName}' was saved to the server, but the response returned the new id '${id}', which has already been used with another record.'`, + isNone(existingInternalModel) || existingInternalModel === internalModel + ); this._internalModelsFor(internalModel.modelName).set(id, internalModel); @@ -1930,11 +2073,17 @@ Store = Service.extend({ false, { id: 'ember-data:_modelForMixin', - until: '3.5' + until: '3.5', } ); - assert(`You need to pass a model name to the store's _modelForMixin method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `You need to pass a model name to the store's _modelForMixin method`, + isPresent(modelName) + ); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); return _modelForMixin(this, normalizedModelName); @@ -1954,7 +2103,10 @@ Store = Service.extend({ */ modelFor(modelName) { assert(`You need to pass a model name to the store's modelFor method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let maybeFactory = this._modelFactoryFor(modelName); @@ -1967,20 +2119,22 @@ Store = Service.extend({ @private */ _modelFor(modelName) { - deprecate( - '_modelFor is private and deprecated, you should use modelFor instead', - false, - { - id: 'ember-data:_modelFor', - until: '3.5' - } - ); + deprecate('_modelFor is private and deprecated, you should use modelFor instead', false, { + id: 'ember-data:_modelFor', + until: '3.5', + }); return this.modelFor(modelName); }, _modelFactoryFor(modelName) { - assert(`You need to pass a model name to the store's _modelFactoryFor method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `You need to pass a model name to the store's _modelFactoryFor method`, + isPresent(modelName) + ); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); let factory = getModelFactory(this, this._modelFactoryCache, normalizedModelName); @@ -1998,7 +2152,7 @@ Store = Service.extend({ modelFactoryFor(modelName) { deprecate('modelFactoryFor is private and deprecated', false, { id: 'ember-data:modelFactoryFor', - until: '3.5' + until: '3.5', }); return this._modelFactoryFor(modelName); }, @@ -2016,7 +2170,10 @@ Store = Service.extend({ */ _hasModelFor(modelName) { assert(`You need to pass a model name to the store's hasModelFor method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); let factory = getModelFactory(this, this._modelFactoryCache, normalizedModelName); @@ -2228,7 +2385,12 @@ Store = Service.extend({ return null; } - assert(`Expected an object in the 'data' property in a call to 'push' for ${jsonApiDoc.type}, but was ${typeOf(jsonApiDoc.data)}`, typeOf(jsonApiDoc.data) === 'object'); + assert( + `Expected an object in the 'data' property in a call to 'push' for ${ + jsonApiDoc.type + }, but was ${typeOf(jsonApiDoc.data)}`, + typeOf(jsonApiDoc.data) === 'object' + ); return this._pushInternalModel(jsonApiDoc.data); }); @@ -2239,8 +2401,14 @@ Store = Service.extend({ _pushInternalModel(data) { heimdall.increment(_pushInternalModel); let modelName = data.type; - assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id !== null && data.id !== undefined && data.id !== ''); - assert(`You tried to push data with a type '${modelName}' but no model could be found with that name.`, this._hasModelFor(modelName)); + assert( + `You must include an 'id' for ${modelName} in an object passed to 'push'`, + data.id !== null && data.id !== undefined && data.id !== '' + ); + assert( + `You tried to push data with a type '${modelName}' but no model could be found with that name.`, + this._hasModelFor(modelName) + ); if (DEBUG) { // If ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload @@ -2250,18 +2418,22 @@ Store = Service.extend({ let modelClass = this.modelFor(modelName); // Check unknown attributes - let unknownAttributes = Object.keys(data.attributes || {}).filter((key) => { + let unknownAttributes = Object.keys(data.attributes || {}).filter(key => { return !get(modelClass, 'fields').has(key); }); let unknownAttributesMessage = `The payload for '${modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`; - warn(unknownAttributesMessage, unknownAttributes.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); + warn(unknownAttributesMessage, unknownAttributes.length === 0, { + id: 'ds.store.unknown-keys-in-payload', + }); // Check unknown relationships - let unknownRelationships = Object.keys(data.relationships || {}).filter((key) => { + let unknownRelationships = Object.keys(data.relationships || {}).filter(key => { return !get(modelClass, 'fields').has(key); }); let unknownRelationshipsMessage = `The payload for '${modelName}' contains these unknown relationships: ${unknownRelationships}. Make sure they've been defined in your model.`; - warn(unknownRelationshipsMessage, unknownRelationships.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); + warn(unknownRelationshipsMessage, unknownRelationships.length === 0, { + id: 'ds.store.unknown-keys-in-payload', + }); } } @@ -2371,10 +2543,16 @@ Store = Service.extend({ if (!inputPayload) { payload = modelName; serializer = defaultSerializer(this); - assert(`You cannot use 'store#pushPayload' without a modelName unless your default serializer defines 'pushPayload'`, typeof serializer.pushPayload === 'function'); + assert( + `You cannot use 'store#pushPayload' without a modelName unless your default serializer defines 'pushPayload'`, + typeof serializer.pushPayload === 'function' + ); } else { payload = inputPayload; - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); serializer = this.serializerFor(normalizedModelName); } @@ -2403,7 +2581,12 @@ Store = Service.extend({ normalize(modelName, payload) { heimdall.increment(normalize); assert(`You need to pass a model name to the store's normalize method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect( + modelName + )}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); let serializer = this.serializerFor(normalizedModelName); let model = this.modelFor(normalizedModelName); @@ -2424,11 +2607,17 @@ Store = Service.extend({ _buildInternalModel(modelName, id, data) { heimdall.increment(_buildInternalModel); - assert(`You can no longer pass a modelClass as the first argument to store._buildInternalModel. Pass modelName instead.`, typeof modelName === 'string'); + assert( + `You can no longer pass a modelClass as the first argument to store._buildInternalModel. Pass modelName instead.`, + typeof modelName === 'string' + ); let existingInternalModel = this._existingInternalModelForId(modelName, id); - assert(`The id ${id} has already been used with another record for modelClass '${modelName}'.`, !existingInternalModel); + assert( + `The id ${id} has already been used with another record for modelClass '${modelName}'.`, + !existingInternalModel + ); // lookupFactory should really return an object that creates // instances with the injections applied @@ -2503,12 +2692,17 @@ Store = Service.extend({ adapterFor(modelName) { heimdall.increment(adapterFor); assert(`You need to pass a model name to the store's adapterFor method`, isPresent(modelName)); - assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); let { _adapterCache } = this; let adapter = _adapterCache[normalizedModelName]; - if (adapter) { return adapter; } + if (adapter) { + return adapter; + } let owner = getOwner(this); @@ -2575,13 +2769,21 @@ Store = Service.extend({ */ serializerFor(modelName) { heimdall.increment(serializerFor); - assert(`You need to pass a model name to the store's serializerFor method`, isPresent(modelName)); - assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `You need to pass a model name to the store's serializerFor method`, + isPresent(modelName) + ); + assert( + `Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); let { _serializerCache } = this; let serializer = _serializerCache[normalizedModelName]; - if (serializer) { return serializer; } + if (serializer) { + return serializer; + } let owner = getOwner(this); @@ -2677,7 +2879,12 @@ Store = Service.extend({ if (isNone(resourceIdentifier)) { return; } - assertRelationshipData(this, relationship.internalModel, resourceIdentifier, relationship.relationshipMeta); + assertRelationshipData( + this, + relationship.internalModel, + resourceIdentifier, + relationship.relationshipMeta + ); return this._internalModelForId(resourceIdentifier.type, resourceIdentifier.id); }, @@ -2687,20 +2894,27 @@ Store = Service.extend({ return; } - assert(`A ${relationship.internalModel.modelName} record was pushed into the store with the value of ${relationship.key} being '${inspect(resourceIdentifiers)}', but ${relationship.key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(resourceIdentifiers)); + assert( + `A ${ + relationship.internalModel.modelName + } record was pushed into the store with the value of ${relationship.key} being '${inspect( + resourceIdentifiers + )}', but ${ + relationship.key + } is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, + Array.isArray(resourceIdentifiers) + ); let _internalModels = new Array(resourceIdentifiers.length); for (let i = 0; i < resourceIdentifiers.length; i++) { _internalModels[i] = this._pushResourceIdentifier(relationship, resourceIdentifiers[i]); } return _internalModels; - } + }, }); // Delegation to the adapter and promise management - - function defaultSerializer(store) { return store.serializerFor('application'); } @@ -2710,21 +2924,30 @@ function _commit(adapter, store, operation, snapshot) { let modelName = snapshot.modelName; let modelClass = store.modelFor(modelName); assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`, typeof adapter[operation] === 'function'); + assert( + `You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`, + typeof adapter[operation] === 'function' + ); - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let promise = Promise.resolve().then(() => adapter[operation](store, modelClass, snapshot)); let serializer = serializerForAdapter(store, adapter, modelName); let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; - assert(`Your adapter's '${operation}' method must return a value, but it returned 'undefined'`, promise !==undefined); + assert( + `Your adapter's '${operation}' method must return a value, but it returned 'undefined'`, + promise !== undefined + ); promise = guardDestroyedStore(promise, store, label); promise = _guard(promise, _bind(_objectIsAlive, internalModel)); - return promise.then((adapterPayload) => { - /* + return promise.then( + adapterPayload => { + /* Note to future spelunkers hoping to optimize. We rely on this `run` to create a run loop if needed that `store._push` and `store.didSaveRecord` will both share. @@ -2733,30 +2956,40 @@ function _commit(adapter, store, operation, snapshot) { have an outer run loop available still from the first call to `store._push`; */ - store._backburner.join(() => { - let payload, data; - if (adapterPayload) { - payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, snapshot.id, operation); - if (payload.included) { - store._push({ data: null, included: payload.included }); + store._backburner.join(() => { + let payload, data; + if (adapterPayload) { + payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + snapshot.id, + operation + ); + if (payload.included) { + store._push({ data: null, included: payload.included }); + } + data = payload.data; } - data = payload.data; - } - store.didSaveRecord(internalModel, { data }); - }); + store.didSaveRecord(internalModel, { data }); + }); - return internalModel; - }, function(error) { - if (error instanceof InvalidError) { - let errors = serializer.extractErrors(store, modelClass, error, snapshot.id); + return internalModel; + }, + function(error) { + if (error instanceof InvalidError) { + let errors = serializer.extractErrors(store, modelClass, error, snapshot.id); - store.recordWasInvalid(internalModel, errors); - } else { - store.recordWasError(internalModel, error); - } + store.recordWasInvalid(internalModel, errors); + } else { + store.recordWasError(internalModel, error); + } - throw error; - }, label); + throw error; + }, + label + ); } function isInverseRelationshipInitialized(store, internalModel, data, key, modelNameToInverseMap) { @@ -2769,7 +3002,10 @@ function isInverseRelationshipInitialized(store, internalModel, data, key, model let inverseMap = modelNameToInverseMap[internalModel.modelName]; if (!inverseMap) { - inverseMap = modelNameToInverseMap[internalModel.modelName] = get(internalModel.type, 'inverseMap'); + inverseMap = modelNameToInverseMap[internalModel.modelName] = get( + internalModel.type, + 'inverseMap' + ); } let inverseRelationshipMetadata = inverseMap[key]; if (inverseRelationshipMetadata === undefined) { @@ -2783,16 +3019,23 @@ function isInverseRelationshipInitialized(store, internalModel, data, key, model let { name: inverseRelationshipName } = inverseRelationshipMetadata; if (Array.isArray(relationshipData)) { - for (let i=0; i { let relationships = internalModel._relationships; - let relationshipRequiresNotification = relationships.has(relationshipName) || - isInverseRelationshipInitialized(store, internalModel, data, relationshipName, modelNameToInverseMap); + let relationshipRequiresNotification = + relationships.has(relationshipName) || + isInverseRelationshipInitialized( + store, + internalModel, + data, + relationshipName, + modelNameToInverseMap + ); if (relationshipRequiresNotification) { let relationshipData = data.relationships[relationshipName]; @@ -2910,17 +3159,35 @@ function setupRelationships(store, internalModel, data, modelNameToInverseMap) { if (relationshipData.links) { let isAsync = relationshipMeta.options && relationshipMeta.options.async !== false; - warn(`You pushed a record of type '${internalModel.modelName}' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, isAsync || relationshipData.data , { - id: 'ds.store.push-link-for-sync-relationship' - }); + warn( + `You pushed a record of type '${ + internalModel.modelName + }' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, + isAsync || relationshipData.data, + { + id: 'ds.store.push-link-for-sync-relationship', + } + ); } else if (relationshipData.data) { if (relationshipMeta.kind === 'belongsTo') { assertRelationshipData(store, internalModel, relationshipData.data, relationshipMeta); } else if (relationshipMeta.kind === 'hasMany') { - assert(`A ${internalModel.modelName} record was pushed into the store with the value of ${relationshipName} being '${inspect(relationshipData.data)}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(relationshipData.data)); + assert( + `A ${ + internalModel.modelName + } record was pushed into the store with the value of ${relationshipName} being '${inspect( + relationshipData.data + )}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, + Array.isArray(relationshipData.data) + ); if (Array.isArray(relationshipData.data)) { for (let i = 0; i < relationshipData.data.length; i++) { - assertRelationshipData(store, internalModel, relationshipData.data[i], relationshipMeta); + assertRelationshipData( + store, + internalModel, + relationshipData.data[i], + relationshipMeta + ); } } } @@ -2930,23 +3197,38 @@ function setupRelationships(store, internalModel, data, modelNameToInverseMap) { } function assertRelationshipData(store, internalModel, data, meta) { - assert(`A ${internalModel.modelName} record was pushed into the store with the value of ${meta.key} being '${JSON.stringify(data)}', but ${meta.key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(data)); assert( - `Encountered a relationship identifier without a type for the ${meta.kind} relationship '${meta.key}' on ${internalModel}, expected a json-api identifier with type '${meta.type}' but found '${JSON.stringify(data)}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, + `A ${internalModel.modelName} record was pushed into the store with the value of ${ + meta.key + } being '${JSON.stringify(data)}', but ${ + meta.key + } is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, + !Array.isArray(data) + ); + assert( + `Encountered a relationship identifier without a type for the ${meta.kind} relationship '${ + meta.key + }' on ${internalModel}, expected a json-api identifier with type '${ + meta.type + }' but found '${JSON.stringify( + data + )}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || (typeof data.type === 'string' && data.type.length) ); assert( - `Encountered a relationship identifier without an id for the ${meta.kind} relationship '${meta.key}' on ${internalModel}, expected a json-api identifier but found '${JSON.stringify(data)}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, + `Encountered a relationship identifier without an id for the ${meta.kind} relationship '${ + meta.key + }' on ${internalModel}, expected a json-api identifier but found '${JSON.stringify( + data + )}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || coerceId(data.id) ); assert( - `Encountered a relationship identifier with type '${ - data.type - }' for the ${meta.kind} relationship '${meta.key}' on ${ - internalModel - }, Expected a json-api identifier with type '${ + `Encountered a relationship identifier with type '${data.type}' for the ${ + meta.kind + } relationship '${meta.key}' on ${internalModel}, Expected a json-api identifier with type '${ meta.type - }'. No model was found for '${data.type}'.`, + }'. No model was found for '${data.type}'.`, data === null || !data.type || store._hasModelFor(data.type) ); } diff --git a/addon/-private/system/store/common.js b/addon/-private/system/store/common.js index 007671f5114..c095fe701c8 100644 --- a/addon/-private/system/store/common.js +++ b/addon/-private/system/store/common.js @@ -3,11 +3,8 @@ import { DEBUG } from '@glimmer/env'; import Ember from 'ember'; import { Promise } from 'rsvp'; -const { - __bind, - __guard, - __objectIsAlive -} = heimdall.registerMonitor('system.store.common', +const { __bind, __guard, __objectIsAlive } = heimdall.registerMonitor( + 'system.store.common', '_bind', '_guard', '_objectIsAlive' @@ -34,7 +31,7 @@ export function _guard(promise, test) { export function _objectIsAlive(object) { heimdall.increment(__objectIsAlive); - return !(get(object, "isDestroyed") || get(object, "isDestroying")); + return !(get(object, 'isDestroyed') || get(object, 'isDestroying')); } let ASYNC_REQUEST_COUNT = 0; @@ -51,5 +48,10 @@ if (DEBUG) { export function guardDestroyedStore(promise, store, label) { promise = Promise.resolve(promise, label); - return _guard(promise, () => { if (DEBUG) { ASYNC_REQUEST_COUNT--; } return _objectIsAlive(store); }); + return _guard(promise, () => { + if (DEBUG) { + ASYNC_REQUEST_COUNT--; + } + return _objectIsAlive(store); + }); } diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index d9923eaf29a..1709a79cb39 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -8,11 +8,11 @@ import { _guard, _objectIsAlive, guardDestroyedStore, - incrementRequestCount -} from "./common"; + incrementRequestCount, +} from './common'; -import { normalizeResponseHelper } from "./serializer-response"; -import { serializerForAdapter } from "./serializers"; +import { normalizeResponseHelper } from './serializer-response'; +import { serializerForAdapter } from './serializers'; function payloadIsNotBlank(adapterPayload) { if (Array.isArray(adapterPayload)) { @@ -23,7 +23,9 @@ function payloadIsNotBlank(adapterPayload) { } export function _find(adapter, store, modelClass, id, internalModel, options) { - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let snapshot = internalModel.createSnapshot(options); let { modelName } = internalModel; let promise = Promise.resolve().then(() => adapter.findRecord(store, modelClass, id, snapshot)); @@ -31,29 +33,54 @@ export function _find(adapter, store, modelClass, id, internalModel, options) { promise = guardDestroyedStore(promise, store, label); - return promise.then(adapterPayload => { - assert(`You made a 'findRecord' request for a '${modelName}' with id '${id}', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, id, 'findRecord'); - assert(`Ember Data expected the primary data returned from a 'findRecord' response to be an object but instead it found an array.`, !Array.isArray(payload.data)); - - warn(`You requested a record of type '${modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead https://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, payload.data.id === id, { - id: 'ds.store.findRecord.id-mismatch' - }); - - return store._push(payload); - }, error => { - internalModel.notFound(); - if (internalModel.isEmpty()) { - internalModel.unloadRecord(); - } - - throw error; - }, `DS: Extract payload of '${modelName}'`); + return promise.then( + adapterPayload => { + assert( + `You made a 'findRecord' request for a '${modelName}' with id '${id}', but the adapter's response did not have any data`, + payloadIsNotBlank(adapterPayload) + ); + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + id, + 'findRecord' + ); + assert( + `Ember Data expected the primary data returned from a 'findRecord' response to be an object but instead it found an array.`, + !Array.isArray(payload.data) + ); + + warn( + `You requested a record of type '${modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${ + payload.data.id + }'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead https://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, + payload.data.id === id, + { + id: 'ds.store.findRecord.id-mismatch', + } + ); + + return store._push(payload); + }, + error => { + internalModel.notFound(); + if (internalModel.isEmpty()) { + internalModel.unloadRecord(); + } + + throw error; + }, + `DS: Extract payload of '${modelName}'` + ); } export function _findMany(adapter, store, modelName, ids, internalModels) { - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let snapshots = A(internalModels).invoke('createSnapshot'); let modelClass = store.modelFor(modelName); // `adapter.findMany` gets the modelClass still let promise = adapter.findMany(store, modelClass, ids, snapshots); @@ -65,90 +92,163 @@ export function _findMany(adapter, store, modelName, ids, internalModels) { promise = guardDestroyedStore(promise, store, label); - return promise.then(adapterPayload => { - assert(`You made a 'findMany' request for '${modelName}' records with ids '[${ids}]', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findMany'); - return store._push(payload); - }, null, `DS: Extract payload of ${modelName}`); + return promise.then( + adapterPayload => { + assert( + `You made a 'findMany' request for '${modelName}' records with ids '[${ids}]', but the adapter's response did not have any data`, + payloadIsNotBlank(adapterPayload) + ); + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + null, + 'findMany' + ); + return store._push(payload); + }, + null, + `DS: Extract payload of ${modelName}` + ); } export function _findHasMany(adapter, store, internalModel, link, relationship) { - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let snapshot = internalModel.createSnapshot(); let modelClass = store.modelFor(relationship.type); let promise = adapter.findHasMany(store, snapshot, link, relationship); - let label = `DS: Handle Adapter#findHasMany of '${internalModel.modelName}' : '${relationship.type}'`; + let label = `DS: Handle Adapter#findHasMany of '${internalModel.modelName}' : '${ + relationship.type + }'`; promise = guardDestroyedStore(promise, store, label); promise = _guard(promise, _bind(_objectIsAlive, internalModel)); - return promise.then(adapterPayload => { - assert(`You made a 'findHasMany' request for a ${internalModel.modelName}'s '${relationship.key}' relationship, using link '${link}' , but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); - let serializer = serializerForAdapter(store, adapter, relationship.type); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findHasMany'); - let internalModelArray = store._push(payload); - - internalModelArray.meta = payload.meta; - return internalModelArray; - }, null, `DS: Extract payload of '${internalModel.modelName}' : hasMany '${relationship.type}'`); + return promise.then( + adapterPayload => { + assert( + `You made a 'findHasMany' request for a ${internalModel.modelName}'s '${ + relationship.key + }' relationship, using link '${link}' , but the adapter's response did not have any data`, + payloadIsNotBlank(adapterPayload) + ); + let serializer = serializerForAdapter(store, adapter, relationship.type); + let payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + null, + 'findHasMany' + ); + let internalModelArray = store._push(payload); + + internalModelArray.meta = payload.meta; + return internalModelArray; + }, + null, + `DS: Extract payload of '${internalModel.modelName}' : hasMany '${relationship.type}'` + ); } export function _findBelongsTo(adapter, store, internalModel, link, relationship) { - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let snapshot = internalModel.createSnapshot(); let modelClass = store.modelFor(relationship.type); let promise = adapter.findBelongsTo(store, snapshot, link, relationship); - let label = `DS: Handle Adapter#findBelongsTo of ${internalModel.modelName} : ${relationship.type}`; + let label = `DS: Handle Adapter#findBelongsTo of ${internalModel.modelName} : ${ + relationship.type + }`; promise = guardDestroyedStore(promise, store, label); promise = _guard(promise, _bind(_objectIsAlive, internalModel)); - return promise.then(adapterPayload => { - let serializer = serializerForAdapter(store, adapter, relationship.type); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findBelongsTo'); - - if (!payload.data) { - return null; - } - - return store._push(payload); - }, null, `DS: Extract payload of ${internalModel.modelName} : ${relationship.type}`); + return promise.then( + adapterPayload => { + let serializer = serializerForAdapter(store, adapter, relationship.type); + let payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + null, + 'findBelongsTo' + ); + + if (!payload.data) { + return null; + } + + return store._push(payload); + }, + null, + `DS: Extract payload of ${internalModel.modelName} : ${relationship.type}` + ); } export function _findAll(adapter, store, modelName, sinceToken, options) { - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let modelClass = store.modelFor(modelName); // adapter.findAll depends on the class let recordArray = store.peekAll(modelName); let snapshotArray = recordArray._createSnapshot(options); - let promise = Promise.resolve().then(() => adapter.findAll(store, modelClass, sinceToken, snapshotArray)); - let label = "DS: Handle Adapter#findAll of " + modelClass; + let promise = Promise.resolve().then(() => + adapter.findAll(store, modelClass, sinceToken, snapshotArray) + ); + let label = 'DS: Handle Adapter#findAll of ' + modelClass; promise = guardDestroyedStore(promise, store, label); - return promise.then(adapterPayload => { - assert(`You made a 'findAll' request for '${modelName}' records, but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findAll'); - - store._push(payload); - store._didUpdateAll(modelName); - - return recordArray; - }, null, 'DS: Extract payload of findAll ${modelName}'); + return promise.then( + adapterPayload => { + assert( + `You made a 'findAll' request for '${modelName}' records, but the adapter's response did not have any data`, + payloadIsNotBlank(adapterPayload) + ); + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + null, + 'findAll' + ); + + store._push(payload); + store._didUpdateAll(modelName); + + return recordArray; + }, + null, + 'DS: Extract payload of findAll ${modelName}' + ); } export function _query(adapter, store, modelName, query, recordArray, options) { - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let modelClass = store.modelFor(modelName); // adapter.query needs the class let promise; - let createRecordArray = adapter.query.length > 3 || + let createRecordArray = + adapter.query.length > 3 || (adapter.query.wrappedFunction && adapter.query.wrappedFunction.length > 3); if (createRecordArray) { - recordArray = recordArray || store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); - promise = Promise.resolve().then(() => adapter.query(store, modelClass, query, recordArray, options)); + recordArray = + recordArray || store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); + promise = Promise.resolve().then(() => + adapter.query(store, modelClass, query, recordArray, options) + ); } else { promise = Promise.resolve().then(() => adapter.query(store, modelClass, query)); } @@ -156,42 +256,80 @@ export function _query(adapter, store, modelName, query, recordArray, options) { let label = `DS: Handle Adapter#query of ${modelName}`; promise = guardDestroyedStore(promise, store, label); - return promise.then(adapterPayload => { - let serializerToken = heimdall.start('initial-serializerFor-lookup'); - let serializer = serializerForAdapter(store, adapter, modelName); - heimdall.stop(serializerToken); - let normalizeToken = heimdall.start('finders#_query::normalizeResponseHelper'); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'query'); - heimdall.stop(normalizeToken); - let internalModels = store._push(payload); - - assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Array.isArray(internalModels)); - if (recordArray) { - recordArray._setInternalModels(internalModels, payload); - } else { - recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query, internalModels, payload); - } - - return recordArray; - }, null, `DS: Extract payload of query ${modelName}`); + return promise.then( + adapterPayload => { + let serializerToken = heimdall.start('initial-serializerFor-lookup'); + let serializer = serializerForAdapter(store, adapter, modelName); + heimdall.stop(serializerToken); + let normalizeToken = heimdall.start('finders#_query::normalizeResponseHelper'); + let payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + null, + 'query' + ); + heimdall.stop(normalizeToken); + let internalModels = store._push(payload); + + assert( + 'The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', + Array.isArray(internalModels) + ); + if (recordArray) { + recordArray._setInternalModels(internalModels, payload); + } else { + recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray( + modelName, + query, + internalModels, + payload + ); + } + + return recordArray; + }, + null, + `DS: Extract payload of query ${modelName}` + ); } export function _queryRecord(adapter, store, modelName, query, options) { - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class - let promise = Promise.resolve().then(() => adapter.queryRecord(store, modelClass, query, options)); + let promise = Promise.resolve().then(() => + adapter.queryRecord(store, modelClass, query, options) + ); let label = `DS: Handle Adapter#queryRecord of ${modelName}`; promise = guardDestroyedStore(promise, store, label); - return promise.then(adapterPayload => { - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'queryRecord'); - - assert(`Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array.`, !Array.isArray(payload.data), { - id: 'ds.store.queryRecord-array-response' - }); - - return store._push(payload); - }, null, `DS: Extract payload of queryRecord ${modelName}`); + return promise.then( + adapterPayload => { + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + null, + 'queryRecord' + ); + + assert( + `Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array.`, + !Array.isArray(payload.data), + { + id: 'ds.store.queryRecord-array-response', + } + ); + + return store._push(payload); + }, + null, + `DS: Extract payload of queryRecord ${modelName}` + ); } diff --git a/addon/-private/system/store/serializer-response.js b/addon/-private/system/store/serializer-response.js index 155b13d0617..c4a08c6b5cf 100644 --- a/addon/-private/system/store/serializer-response.js +++ b/addon/-private/system/store/serializer-response.js @@ -16,13 +16,13 @@ export function validateDocumentStructure(doc) { if (!doc || typeof doc !== 'object') { errors.push('Top level of a JSON API document must be an object'); } else { - if (!('data' in doc) && - !('errors' in doc) && - !('meta' in doc)) { + if (!('data' in doc) && !('errors' in doc) && !('meta' in doc)) { errors.push('One or more of the following keys must be present: "data", "errors", "meta".'); } else { - if (('data' in doc) && ('errors' in doc)) { - errors.push('Top level keys "errors" and "data" cannot both be present in a JSON API document'); + if ('data' in doc && 'errors' in doc) { + errors.push( + 'Top level keys "errors" and "data" cannot both be present in a JSON API document' + ); } } if ('data' in doc) { @@ -73,12 +73,23 @@ export function validateDocumentStructure(doc) { @return {Object} JSON-API Document */ export function normalizeResponseHelper(serializer, store, modelClass, payload, id, requestType) { - let normalizedResponse = serializer.normalizeResponse(store, modelClass, payload, id, requestType); + let normalizedResponse = serializer.normalizeResponse( + store, + modelClass, + payload, + id, + requestType + ); let validationErrors = []; if (DEBUG) { validationErrors = validateDocumentStructure(normalizedResponse); } - assert(`normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join('\n\t* ')}`, validationErrors.length === 0); + assert( + `normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join( + '\n\t* ' + )}`, + validationErrors.length === 0 + ); return normalizedResponse; } diff --git a/addon/-private/system/store/serializers.js b/addon/-private/system/store/serializers.js index 71ca0829809..d6788427061 100644 --- a/addon/-private/system/store/serializers.js +++ b/addon/-private/system/store/serializers.js @@ -7,7 +7,9 @@ export function serializerForAdapter(store, adapter, modelName) { if (serializer === null || serializer === undefined) { serializer = { - extract(store, type, payload) { return payload; } + extract(store, type, payload) { + return payload; + }, }; } diff --git a/addon/-private/utils.js b/addon/-private/utils.js index 234af6842fa..f3bd4ed6aaf 100644 --- a/addon/-private/utils.js +++ b/addon/-private/utils.js @@ -8,7 +8,9 @@ import { get } from '@ember/object'; @param modelClass */ function modelHasAttributeOrRelationshipNamedType(modelClass) { - return get(modelClass, 'attributes').has('type') || get(modelClass, 'relationshipsByName').has('type'); + return ( + get(modelClass, 'attributes').has('type') || get(modelClass, 'relationshipsByName').has('type') + ); } /* @@ -29,7 +31,7 @@ function getOwner(context) { // `owner` is a container, we are just making this work owner._lookupFactory = function() { return owner.lookupFactory(...arguments); - } + }; owner.register = function() { let registry = owner.registry || owner._registry || owner; @@ -41,7 +43,4 @@ function getOwner(context) { return owner; } -export { - modelHasAttributeOrRelationshipNamedType, - getOwner -}; +export { modelHasAttributeOrRelationshipNamedType, getOwner }; diff --git a/addon/-record-data-rfc-private/adapters/build-url-mixin.js b/addon/-record-data-rfc-private/adapters/build-url-mixin.js index 2472a83d31a..d1552ae675f 100644 --- a/addon/-record-data-rfc-private/adapters/build-url-mixin.js +++ b/addon/-record-data-rfc-private/adapters/build-url-mixin.js @@ -94,11 +94,17 @@ export default Mixin.create({ if (modelName) { path = this.pathForType(modelName); - if (path) { url.push(path); } + if (path) { + url.push(path); + } } - if (id) { url.push(encodeURIComponent(id)); } - if (prefix) { url.unshift(prefix); } + if (id) { + url.push(encodeURIComponent(id)); + } + if (prefix) { + url.unshift(prefix); + } url = url.join('/'); if (!host && url && url.charAt(0) !== '/') { @@ -392,10 +398,10 @@ export default Mixin.create({ // Do nothing, the full host is already included. return path; - // Absolute path + // Absolute path } else if (path.charAt(0) === '/') { return `${host}${path}`; - // Relative path + // Relative path } else { return `${parentURL}/${path}`; } @@ -403,8 +409,12 @@ export default Mixin.create({ // No path provided let url = []; - if (host) { url.push(host); } - if (namespace) { url.push(namespace); } + if (host) { + url.push(host); + } + if (namespace) { + url.push(namespace); + } return url.join('/'); }, @@ -439,5 +449,5 @@ export default Mixin.create({ pathForType(modelName) { let camelized = camelize(modelName); return pluralize(camelized); - } + }, }); diff --git a/addon/-record-data-rfc-private/adapters/errors.js b/addon/-record-data-rfc-private/adapters/errors.js index ec8919818cf..8cfd7b978dd 100644 --- a/addon/-record-data-rfc-private/adapters/errors.js +++ b/addon/-record-data-rfc-private/adapters/errors.js @@ -81,8 +81,8 @@ export function AdapterError(errors, message = 'Adapter operation failed') { this.errors = errors || [ { title: 'Adapter Error', - detail: message - } + detail: message, + }, ]; } @@ -165,8 +165,10 @@ AdapterError.extend = extendFn(AdapterError); @class InvalidError @namespace DS */ -export const InvalidError = extend(AdapterError, - 'The adapter rejected the commit because it was invalid'); +export const InvalidError = extend( + AdapterError, + 'The adapter rejected the commit because it was invalid' +); /** A `DS.TimeoutError` is used by an adapter to signal that a request @@ -200,8 +202,7 @@ export const InvalidError = extend(AdapterError, @class TimeoutError @namespace DS */ -export const TimeoutError = extend(AdapterError, - 'The adapter operation timed out'); +export const TimeoutError = extend(AdapterError, 'The adapter operation timed out'); /** A `DS.AbortError` is used by an adapter to signal that a request to @@ -212,8 +213,7 @@ export const TimeoutError = extend(AdapterError, @class AbortError @namespace DS */ -export const AbortError = extend(AdapterError, - 'The adapter operation was aborted'); +export const AbortError = extend(AdapterError, 'The adapter operation was aborted'); /** A `DS.UnauthorizedError` equates to a HTTP `401 Unauthorized` response @@ -320,7 +320,10 @@ export const ConflictError = extend(AdapterError, 'The adapter operation failed @class ServerError @namespace DS */ -export const ServerError = extend(AdapterError, 'The adapter operation failed due to a server error'); +export const ServerError = extend( + AdapterError, + 'The adapter operation failed due to a server error' +); /** Convert an hash of errors into an array with errors in JSON-API format. @@ -372,7 +375,7 @@ export function errorsHashToArray(errors) { let out = []; if (isPresent(errors)) { - Object.keys(errors).forEach((key) => { + Object.keys(errors).forEach(key => { let messages = makeArray(errors[key]); for (let i = 0; i < messages.length; i++) { let title = 'Invalid Attribute'; @@ -385,8 +388,8 @@ export function errorsHashToArray(errors) { title: title, detail: messages[i], source: { - pointer: pointer - } + pointer: pointer, + }, }); } }); @@ -439,7 +442,7 @@ export function errorsArrayToHash(errors) { let out = {}; if (isPresent(errors)) { - errors.forEach((error) => { + errors.forEach(error => { if (error.source && error.source.pointer) { let key = error.source.pointer.match(SOURCE_POINTER_REGEXP); diff --git a/addon/-record-data-rfc-private/attr.js b/addon/-record-data-rfc-private/attr.js index f4b266d7ace..e2df4230ae3 100644 --- a/addon/-record-data-rfc-private/attr.js +++ b/addon/-record-data-rfc-private/attr.js @@ -10,8 +10,10 @@ function getDefaultValue(record, options, key) { return options.defaultValue.apply(null, arguments); } else { let defaultValue = options.defaultValue; - assert(`Non primitive defaultValues are not supported because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.`, - typeof defaultValue !== 'object' || defaultValue === null); + assert( + `Non primitive defaultValues are not supported because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.`, + typeof defaultValue !== 'object' || defaultValue === null + ); return defaultValue; } } @@ -116,7 +118,7 @@ export default function attr(type, options) { let meta = { type: type, isAttribute: true, - options: options + options: options, }; return computed({ @@ -130,6 +132,6 @@ export default function attr(type, options) { }, set(key, value) { return this._internalModel.setDirtyAttribute(key, value); - } + }, }).meta(meta); } diff --git a/addon/-record-data-rfc-private/core.js b/addon/-record-data-rfc-private/core.js index b16369a0ff4..70816f3c203 100644 --- a/addon/-record-data-rfc-private/core.js +++ b/addon/-record-data-rfc-private/core.js @@ -19,7 +19,7 @@ import VERSION from 'ember-data/version'; */ const DS = Ember.Namespace.create({ VERSION: VERSION, - name: "DS" + name: 'DS', }); if (Ember.libraries) { diff --git a/addon/-record-data-rfc-private/index.js b/addon/-record-data-rfc-private/index.js index c99397b872f..15e211a9de9 100644 --- a/addon/-record-data-rfc-private/index.js +++ b/addon/-record-data-rfc-private/index.js @@ -1,7 +1,7 @@ // public export { default as Model } from './system/model/model'; export { default as Errors } from './system/model/errors'; -export { default as Store } from './system/store'; +export { default as Store } from './system/store'; export { default as DS } from './core'; export { default as belongsTo } from './system/relationships/belongs-to'; export { default as hasMany } from './system/relationships/has-many'; @@ -19,7 +19,7 @@ export { TimeoutError, AbortError, errorsHashToArray, - errorsArrayToHash + errorsArrayToHash, } from './adapters/errors'; // maybe public ? @@ -34,16 +34,9 @@ export { default as RootState } from './system/model/states'; export { default as InternalModel } from './system/model/internal-model'; export { default as ModelData } from './system/model/model-data'; -export { - PromiseArray, - PromiseObject, - PromiseManyArray -} from './system/promise-proxies'; +export { PromiseArray, PromiseObject, PromiseManyArray } from './system/promise-proxies'; -export { - RecordArray, - AdapterPopulatedRecordArray -} from './system/record-arrays'; +export { RecordArray, AdapterPopulatedRecordArray } from './system/record-arrays'; export { default as ManyArray } from './system/many-array'; export { default as RecordArrayManager } from './system/record-array-manager'; diff --git a/addon/-record-data-rfc-private/system/backburner.js b/addon/-record-data-rfc-private/system/backburner.js index 266c37c3b4b..7ac43f9b390 100644 --- a/addon/-record-data-rfc-private/system/backburner.js +++ b/addon/-record-data-rfc-private/system/backburner.js @@ -1,7 +1,11 @@ import Ember from 'ember'; import { DEBUG } from '@glimmer/env'; -const backburner = new Ember._Backburner(['normalizeRelationships', 'syncRelationships', 'finished']); +const backburner = new Ember._Backburner([ + 'normalizeRelationships', + 'syncRelationships', + 'finished', +]); if (DEBUG) { Ember.Test.registerWaiter(() => { diff --git a/addon/-record-data-rfc-private/system/coerce-id.js b/addon/-record-data-rfc-private/system/coerce-id.js index 8f8c305a98d..18173352148 100644 --- a/addon/-record-data-rfc-private/system/coerce-id.js +++ b/addon/-record-data-rfc-private/system/coerce-id.js @@ -5,7 +5,11 @@ // ID into the URL, and if we later try to deserialize that URL and find the // corresponding record, we will not know if it is a string or a number. export default function coerceId(id) { - if (id === null || id === undefined || id === '') { return null; } - if (typeof id === 'string') { return id; } + if (id === null || id === undefined || id === '') { + return null; + } + if (typeof id === 'string') { + return id; + } return '' + id; } diff --git a/addon/-record-data-rfc-private/system/debug/debug-adapter.js b/addon/-record-data-rfc-private/system/debug/debug-adapter.js index eca07a7d7df..2904a93427f 100644 --- a/addon/-record-data-rfc-private/system/debug/debug-adapter.js +++ b/addon/-record-data-rfc-private/system/debug/debug-adapter.js @@ -23,7 +23,7 @@ export default DataAdapter.extend({ return [ { name: 'isNew', desc: 'New' }, { name: 'isModified', desc: 'Modified' }, - { name: 'isClean', desc: 'Clean' } + { name: 'isClean', desc: 'Clean' }, ]; }, @@ -32,14 +32,18 @@ export default DataAdapter.extend({ }, columnsForType(typeClass) { - let columns = [{ - name: 'id', - desc: 'Id' - }]; + let columns = [ + { + name: 'id', + desc: 'Id', + }, + ]; let count = 0; let self = this; get(typeClass, 'attributes').forEach((meta, name) => { - if (count++ > self.attributeLimit) { return false; } + if (count++ > self.attributeLimit) { + return false; + } let desc = capitalize(underscore(name).replace('_', ' ')); columns.push({ name: name, desc: desc }); }); @@ -57,7 +61,10 @@ export default DataAdapter.extend({ } } } - assert("Cannot find model name. Please upgrade to Ember.js >= 1.13 for Ember Inspector support", !!modelName); + assert( + 'Cannot find model name. Please upgrade to Ember.js >= 1.13 for Ember Inspector support', + !!modelName + ); return this.get('store').peekAll(modelName); }, @@ -65,7 +72,7 @@ export default DataAdapter.extend({ let count = 0; let columnValues = { id: get(record, 'id') }; - record.eachAttribute((key) => { + record.eachAttribute(key => { if (count++ > this.attributeLimit) { return false; } @@ -77,8 +84,8 @@ export default DataAdapter.extend({ getRecordKeywords(record) { let keywords = []; let keys = A(['id']); - record.eachAttribute((key) => keys.push(key)); - keys.forEach((key) => keywords.push(get(record, key))); + record.eachAttribute(key => keys.push(key)); + keys.forEach(key => keywords.push(get(record, key))); return keywords; }, @@ -86,7 +93,7 @@ export default DataAdapter.extend({ return { isNew: record.get('isNew'), isModified: record.get('hasDirtyAttributes') && !record.get('isNew'), - isClean: !record.get('hasDirtyAttributes') + isClean: !record.get('hasDirtyAttributes'), }; }, @@ -104,7 +111,7 @@ export default DataAdapter.extend({ let releaseMethods = A(); let keysToObserve = A(['id', 'isNew', 'hasDirtyAttributes']); - record.eachAttribute((key) => keysToObserve.push(key)); + record.eachAttribute(key => keysToObserve.push(key)); let adapter = this; keysToObserve.forEach(function(key) { @@ -118,9 +125,9 @@ export default DataAdapter.extend({ }); let release = function() { - releaseMethods.forEach((fn) => fn()); + releaseMethods.forEach(fn => fn()); }; return release; - } + }, }); diff --git a/addon/-record-data-rfc-private/system/diff-array.js b/addon/-record-data-rfc-private/system/diff-array.js index ae28e8e35b3..e935a525b6b 100644 --- a/addon/-record-data-rfc-private/system/diff-array.js +++ b/addon/-record-data-rfc-private/system/diff-array.js @@ -18,7 +18,7 @@ export default function diffArray(oldArray, newArray) { let firstChangeIndex = null; // null signifies no changes // find the first change - for (let i=0; i im._isDematerializing || !im.isLoaded()); + let unloaded = this.currentState.find(im => im._isDematerializing || !im.isLoaded()); return !!unloaded; }, @@ -162,7 +162,9 @@ export default EmberObject.extend(MutableArray, Evented, { } */ let internalModel = this.currentState[index]; - if (internalModel === undefined) { return; } + if (internalModel === undefined) { + return; + } return internalModel.getRecord(); }, @@ -174,7 +176,8 @@ export default EmberObject.extend(MutableArray, Evented, { } // diff to find changes let diff = diffArray(this.currentState, toSet); - if (diff.firstChangeIndex !== null) { // it's null if no change found + if (diff.firstChangeIndex !== null) { + // it's null if no change found // we found a change this.arrayContentWillChange(diff.firstChangeIndex, diff.removedCount, diff.addedCount); this.set('length', toSet.length); @@ -191,11 +194,18 @@ export default EmberObject.extend(MutableArray, Evented, { replace(idx, amt, objects) { let internalModels; if (amt > 0) { - internalModels = this.currentState.slice(idx, idx+amt); - this.get('modelData').removeFromHasMany(this.get('key'), internalModels.map((im) => im._modelData)); + internalModels = this.currentState.slice(idx, idx + amt); + this.get('modelData').removeFromHasMany( + this.get('key'), + internalModels.map(im => im._modelData) + ); } if (objects) { - this.get('modelData').addToHasMany(this.get('key'), objects.map(obj => obj._internalModel._modelData), idx); + this.get('modelData').addToHasMany( + this.get('key'), + objects.map(obj => obj._internalModel._modelData), + idx + ); //this.get('relationship').addInternalModels(objects.map(obj => obj._internalModel), idx); } this.retrieveLatest(); @@ -263,8 +273,11 @@ export default EmberObject.extend(MutableArray, Evented, { save() { let manyArray = this; let promiseLabel = 'DS: ManyArray#save ' + get(this, 'type'); - let promise = all(this.invoke("save"), promiseLabel). - then(() => manyArray, null, 'DS: ManyArray#save return ManyArray'); + let promise = all(this.invoke('save'), promiseLabel).then( + () => manyArray, + null, + 'DS: ManyArray#save return ManyArray' + ); return PromiseArray.create({ promise }); }, @@ -281,10 +294,13 @@ export default EmberObject.extend(MutableArray, Evented, { const store = get(this, 'store'); const type = get(this, 'type'); - assert(`You cannot add '${type.modelName}' records to this polymorphic relationship.`, !get(this, 'isPolymorphic')); + assert( + `You cannot add '${type.modelName}' records to this polymorphic relationship.`, + !get(this, 'isPolymorphic') + ); let record = store.createRecord(type.modelName, hash); this.pushObject(record); return record; - } + }, }); diff --git a/addon/-record-data-rfc-private/system/map.js b/addon/-record-data-rfc-private/system/map.js index 6018913a453..c7c0be9846b 100644 --- a/addon/-record-data-rfc-private/system/map.js +++ b/addon/-record-data-rfc-private/system/map.js @@ -64,7 +64,7 @@ export default class MapWithDeprecations { copy() { deprecate( 'Calling `.copy()` on a map generated by ember-data is deprecated, please migrate to using native Map functionality only.', - false, + false, { id: 'ember-data.map.copy', until: '3.5.0' } ); @@ -72,7 +72,7 @@ export default class MapWithDeprecations { // constructor args with its `Map` let newMap = new MapWithDeprecations(); this._map.forEach(function(value, key) { - newMap.set(key, value) + newMap.set(key, value); }); return newMap; @@ -81,7 +81,7 @@ export default class MapWithDeprecations { isEmpty() { deprecate( 'Calling `.isEmpty()` on a map generated by ember-data is deprecated, please migrate to using native Map functionality only.', - false, + false, { id: 'ember-data.map.isEmpty', until: '3.5.0' } ); @@ -89,14 +89,34 @@ export default class MapWithDeprecations { } // proxy all normal Map methods to the underlying Map - get size() { return this._map.size; } - clear() { return this._map.clear(...arguments) } - delete() { return this._map.delete(...arguments) } - entries() { return this._map.entries(...arguments) } - forEach() { return this._map.forEach(...arguments) } - get() { return this._map.get(...arguments) } - has() { return this._map.has(...arguments) } - keys() { return this._map.keys(...arguments) } - set() { return this._map.set(...arguments) } - values() { return this._map.values(...arguments) } + get size() { + return this._map.size; + } + clear() { + return this._map.clear(...arguments); + } + delete() { + return this._map.delete(...arguments); + } + entries() { + return this._map.entries(...arguments); + } + forEach() { + return this._map.forEach(...arguments); + } + get() { + return this._map.get(...arguments); + } + has() { + return this._map.has(...arguments); + } + keys() { + return this._map.keys(...arguments); + } + set() { + return this._map.set(...arguments); + } + values() { + return this._map.values(...arguments); + } } diff --git a/addon/-record-data-rfc-private/system/model/errors.js b/addon/-record-data-rfc-private/system/model/errors.js index b955dc1ef61..005fb9ec7ca 100644 --- a/addon/-record-data-rfc-private/system/model/errors.js +++ b/addon/-record-data-rfc-private/system/model/errors.js @@ -86,7 +86,6 @@ import { warn } from '@ember/debug'; @uses Ember.Evented */ export default ArrayProxy.extend(Evented, { - /** Register with target handler @@ -107,7 +106,7 @@ export default ArrayProxy.extend(Evented, { return new MapWithDefault({ defaultValue() { return A(); - } + }, }); }), @@ -165,7 +164,9 @@ export default ArrayProxy.extend(Evented, { */ unknownProperty(attribute) { let errors = this.errorsFor(attribute); - if (errors.length === 0) { return undefined; } + if (errors.length === 0) { + return undefined; + } return errors; }, @@ -203,7 +204,7 @@ export default ArrayProxy.extend(Evented, { */ add(attribute, messages) { warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.add' + id: 'ds.errors.add', }); let wasEmpty = get(this, 'isEmpty'); @@ -215,7 +216,6 @@ export default ArrayProxy.extend(Evented, { } }, - /** Adds error messages to a given attribute without sending event. @@ -225,7 +225,9 @@ export default ArrayProxy.extend(Evented, { _add(attribute, messages) { messages = this._findOrCreateMessages(attribute, messages); this.addObjects(messages); - get(this, 'errorsByAttributeName').get(attribute).addObjects(messages); + get(this, 'errorsByAttributeName') + .get(attribute) + .addObjects(messages); this.notifyPropertyChange(attribute); }, @@ -247,7 +249,7 @@ export default ArrayProxy.extend(Evented, { } else { _messages[i] = { attribute: attribute, - message: message + message: message, }; } } @@ -292,10 +294,12 @@ export default ArrayProxy.extend(Evented, { */ remove(attribute) { warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.remove' + id: 'ds.errors.remove', }); - if (get(this, 'isEmpty')) { return; } + if (get(this, 'isEmpty')) { + return; + } this._remove(attribute); @@ -311,7 +315,9 @@ export default ArrayProxy.extend(Evented, { @private */ _remove(attribute) { - if (get(this, 'isEmpty')) { return; } + if (get(this, 'isEmpty')) { + return; + } let content = this.rejectBy('attribute', attribute); set(this, 'content', content); @@ -345,16 +351,17 @@ export default ArrayProxy.extend(Evented, { */ clear() { warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.clear' + id: 'ds.errors.clear', }); - if (get(this, 'isEmpty')) { return; } + if (get(this, 'isEmpty')) { + return; + } this._clear(); this.trigger('becameValid'); }, - /** Removes all error messages. to the record. @@ -363,7 +370,9 @@ export default ArrayProxy.extend(Evented, { @private */ _clear() { - if (get(this, 'isEmpty')) { return; } + if (get(this, 'isEmpty')) { + return; + } let errorsByAttributeName = get(this, 'errorsByAttributeName'); let attributes = A(); @@ -380,7 +389,6 @@ export default ArrayProxy.extend(Evented, { ArrayProxy.prototype.clear.call(this); }, - /** Checks if there is error messages for the given attribute. @@ -405,5 +413,5 @@ export default ArrayProxy.extend(Evented, { */ has(attribute) { return this.errorsFor(attribute).length > 0; - } + }, }); diff --git a/addon/-record-data-rfc-private/system/model/internal-model.js b/addon/-record-data-rfc-private/system/model/internal-model.js index 3ca0b0b70c5..37c119c26e7 100644 --- a/addon/-record-data-rfc-private/system/model/internal-model.js +++ b/addon/-record-data-rfc-private/system/model/internal-model.js @@ -7,22 +7,15 @@ import RSVP, { Promise } from 'rsvp'; import Ember from 'ember'; import { DEBUG } from '@glimmer/env'; import { assert, inspect } from '@ember/debug'; -import RootState from "./states"; -import Snapshot from "../snapshot"; -import OrderedSet from "../ordered-set"; -import isArrayLike from "../is-array-like"; +import RootState from './states'; +import Snapshot from '../snapshot'; +import OrderedSet from '../ordered-set'; +import isArrayLike from '../is-array-like'; import ManyArray from '../many-array'; -import { - PromiseBelongsTo, - PromiseManyArray -} from '../promise-proxies'; +import { PromiseBelongsTo, PromiseManyArray } from '../promise-proxies'; import { getOwner } from '../../utils'; -import { - RecordReference, - BelongsToReference, - HasManyReference -} from "../references"; +import { RecordReference, BelongsToReference, HasManyReference } from '../references'; /* The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached @@ -40,15 +33,11 @@ const _extractPivotNameCache = Object.create(null); const _splitOnDotCache = Object.create(null); function splitOnDot(name) { - return _splitOnDotCache[name] || ( - _splitOnDotCache[name] = name.split('.') - ); + return _splitOnDotCache[name] || (_splitOnDotCache[name] = name.split('.')); } function extractPivotName(name) { - return _extractPivotNameCache[name] || ( - _extractPivotNameCache[name] = splitOnDot(name)[0] - ); + return _extractPivotNameCache[name] || (_extractPivotNameCache[name] = splitOnDot(name)[0]); } // this (and all heimdall instrumentation) will be stripped by a babel transform @@ -62,8 +51,9 @@ const { new_InternalModel, send, setupData, - transitionTo -} = heimdall.registerMonitor('InternalModel', + transitionTo, +} = heimdall.registerMonitor( + 'InternalModel', '_triggerDeferredTriggers', 'changedAttributes', 'createSnapshot', @@ -132,7 +122,6 @@ export default class InternalModel { this._manyArrayCache = Object.create(null); this._retainedManyArrayCache = Object.create(null); this._relationshipPromisesCache = Object.create(null); - } get modelClass() { @@ -179,11 +168,13 @@ export default class InternalModel { // `lastObject` have changed. When this happens we don't want those // models to rematerialize their records. - return this._isDematerializing || + return ( + this._isDematerializing || this.hasScheduledDestroy() || this.isDestroyed || this.currentState.stateName === 'root.deleted.saved' || - this.isEmpty(); + this.isEmpty() + ); } isRecordInUse() { @@ -249,11 +240,14 @@ export default class InternalModel { _internalModel: this, currentState: this.currentState, isError: this.isError, - adapterError: this.error + adapterError: this.error, }; if (properties !== undefined) { - assert(`You passed '${properties}' as properties for record creation instead of an object.`, typeof properties === 'object' && properties !== null); + assert( + `You passed '${properties}' as properties for record creation instead of an object.`, + typeof properties === 'object' && properties !== null + ); let classFields = this.getFields(); // TODO disentangle post-rebase let relationships = this._modelData._relationships; @@ -324,7 +318,7 @@ export default class InternalModel { this._doNotDestroy = false; if (this._record) { - Object.keys(this._relationshipPromisesCache).forEach((key) => { + Object.keys(this._relationshipPromisesCache).forEach(key => { // TODO Igor cleanup the guard // TODO there is probably relationship cleanup to do outside of the _record check if (this._relationshipPromisesCache[key].destroy) { @@ -332,7 +326,7 @@ export default class InternalModel { } delete this._relationshipPromisesCache[key]; }); - Object.keys(this._manyArrayCache).forEach((key) => { + Object.keys(this._manyArrayCache).forEach(key => { this._retainedManyArrayCache[key] = this._manyArrayCache[key]; delete this._manyArrayCache[key]; }); @@ -350,7 +344,7 @@ export default class InternalModel { } save(options) { - let promiseLabel = "DS: Model#save " + this; + let promiseLabel = 'DS: Model#save ' + this; let resolver = RSVP.defer(promiseLabel); this.store.scheduleSave(this, resolver, options); @@ -380,23 +374,28 @@ export default class InternalModel { reload(options) { this.startedReloading(); let internalModel = this; - let promiseLabel = "DS: Model#reload of " + this; + let promiseLabel = 'DS: Model#reload of ' + this; return new Promise(function(resolve) { internalModel.send('reloadRecord', { resolve, options }); - }, promiseLabel).then(function() { - internalModel.didCleanError(); - return internalModel; - }, function(error) { - internalModel.didError(error); - throw error; - }, "DS: Model#reload complete, update flags").finally(function () { - internalModel.finishedReloading(); - internalModel.updateRecordArrays(); - }); + }, promiseLabel) + .then( + function() { + internalModel.didCleanError(); + return internalModel; + }, + function(error) { + internalModel.didError(error); + throw error; + }, + 'DS: Model#reload complete, update flags' + ) + .finally(function() { + internalModel.finishedReloading(); + internalModel.updateRecordArrays(); + }); } - /* Unload the record for this internal model. This will cause the record to be destroyed and freed up for garbage collection. It will also do a check @@ -410,15 +409,24 @@ export default class InternalModel { once all models that refer to it via some relationship are also unloaded. */ unloadRecord() { - if (this.isDestroyed) { return; } + if (this.isDestroyed) { + return; + } this.send('unloadRecord'); this.dematerializeRecord(); if (this._scheduledDestroy === null) { // TODO: use run.schedule once we drop 1.13 if (!run.currentRunLoop) { - assert('You have turned on testing mode, which disabled the run-loop\'s autorun.\n You will need to wrap any code with asynchronous side-effects in a run', Ember.testing); + assert( + "You have turned on testing mode, which disabled the run-loop's autorun.\n You will need to wrap any code with asynchronous side-effects in a run", + Ember.testing + ); } - this._scheduledDestroy = run.backburner.schedule('destroy', this, '_checkForOrphanedInternalModels') + this._scheduledDestroy = run.backburner.schedule( + 'destroy', + this, + '_checkForOrphanedInternalModels' + ); } } @@ -427,7 +435,10 @@ export default class InternalModel { } cancelDestroy() { - assert(`You cannot cancel the destruction of an InternalModel once it has already been destroyed`, !this.isDestroyed); + assert( + `You cannot cancel the destruction of an InternalModel once it has already been destroyed`, + !this.isDestroyed + ); this._doNotDestroy = true; this._isDematerializing = false; @@ -451,7 +462,9 @@ export default class InternalModel { this.cancelDestroy(); } this._checkForOrphanedInternalModels(); - if (this.isDestroyed || this.isDestroying) { return; } + if (this.isDestroyed || this.isDestroying) { + return; + } // just in-case we are not one of the orphaned, we should still // still destroy ourselves @@ -461,7 +474,9 @@ export default class InternalModel { _checkForOrphanedInternalModels() { this._isDematerializing = false; this._scheduledDestroy = null; - if (this.isDestroyed) { return; } + if (this.isDestroyed) { + return; + } } eachRelationship(callback, binding) { @@ -477,11 +492,16 @@ export default class InternalModel { let isAsync = typeof async === 'undefined' ? true : async; if (isAsync) { - let internalModel = resource && resource.data ? store._internalModelForResource(resource.data) : null; + let internalModel = + resource && resource.data ? store._internalModelForResource(resource.data) : null; return PromiseBelongsTo.create({ _belongsToState: resource._relationship, - promise: store._findBelongsToByJsonApiResource(resource, parentInternalModel, relationshipMeta), - content: internalModel ? internalModel.getRecord() : null + promise: store._findBelongsToByJsonApiResource( + resource, + parentInternalModel, + relationshipMeta + ), + content: internalModel ? internalModel.getRecord() : null, }); } else { if (!resource || !resource.data) { @@ -489,7 +509,16 @@ export default class InternalModel { } else { let internalModel = store._internalModelForResource(resource.data); let toReturn = internalModel.getRecord(); - assert("You looked up the '" + key + "' relationship on a '" + parentInternalModel.modelName + "' with id " + parentInternalModel.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); + assert( + "You looked up the '" + + key + + "' relationship on a '" + + parentInternalModel.modelName + + "' with id " + + parentInternalModel.id + + ' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)', + toReturn === null || !toReturn.get('isEmpty') + ); return toReturn; } } @@ -501,7 +530,10 @@ export default class InternalModel { let jsonApi = this._modelData.getHasMany(key); let manyArray = this._manyArrayCache[key]; - assert(`Error: relationship ${this.modelName}:${key} has both many array and retained many array`, !manyArray || !this._retainedManyArrayCache[key]); + assert( + `Error: relationship ${this.modelName}:${key} has both many array and retained many array`, + !manyArray || !this._retainedManyArrayCache[key] + ); if (!manyArray) { let initialState = this.store._getHasManyByJsonApiResource(jsonApi); @@ -514,7 +546,7 @@ export default class InternalModel { key, isPolymorphic: relationshipMeta.options.polymorphic, initialState: initialState.slice(), - internalModel: this + internalModel: this, }); this._manyArrayCache[key] = manyArray; } @@ -529,7 +561,7 @@ export default class InternalModel { fetchAsyncHasMany(relationshipMeta, jsonApi, manyArray) { let promise = this.store._findHasManyByJsonApiResource(jsonApi, this, relationshipMeta); - promise = promise.then((initialState) => { + promise = promise.then(initialState => { // TODO why don't we do this in the store method manyArray.retrieveLatest(); manyArray.set('isLoaded', true); @@ -552,7 +584,7 @@ export default class InternalModel { if (!promiseArray) { promiseArray = PromiseManyArray.create({ promise: this.fetchAsyncHasMany(relationshipMeta, jsonApi, manyArray), - content: manyArray + content: manyArray, }); this._relationshipPromisesCache[key] = promiseArray; } @@ -560,7 +592,12 @@ export default class InternalModel { return promiseArray; } else { manyArray.set('isLoaded', true); - assert(`You looked up the '${key}' relationship on a '${this.type.modelName}' with id ${this.id} but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async ('DS.hasMany({ async: true })')`, !manyArray.anyUnloaded()); + assert( + `You looked up the '${key}' relationship on a '${this.type.modelName}' with id ${ + this.id + } but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async ('DS.hasMany({ async: true })')`, + !manyArray.anyUnloaded() + ); return manyArray; } @@ -570,13 +607,13 @@ export default class InternalModel { let loadingPromise = this._relationshipPromisesCache[key]; if (loadingPromise) { if (content) { - loadingPromise.set('content', content) + loadingPromise.set('content', content); } - loadingPromise.set('promise', promise) + loadingPromise.set('promise', promise); } else { this._relationshipPromisesCache[key] = PromiseManyArray.create({ promise, - content + content, }); } @@ -624,9 +661,12 @@ export default class InternalModel { } destroy() { - assert("Cannot destroy an internalModel while its record is materialized", !this._record || this._record.get('isDestroyed') || this._record.get('isDestroying')); + assert( + 'Cannot destroy an internalModel while its record is materialized', + !this._record || this._record.get('isDestroyed') || this._record.get('isDestroying') + ); this.isDestroying = true; - Object.keys(this._retainedManyArrayCache).forEach((key) => { + Object.keys(this._retainedManyArrayCache).forEach(key => { this._retainedManyArrayCache[key].destroy(); delete this._retainedManyArrayCache[key]; }); @@ -658,16 +698,23 @@ export default class InternalModel { setDirtyHasMany(key, records) { assert(`You must pass an array of records to set a hasMany relationship`, isArrayLike(records)); - assert(`All elements of a hasMany relationship must be instances of DS.Model, you passed ${inspect(records)}`, (function() { - return A(records).every((record) => record.hasOwnProperty('_internalModel') === true); - })()); + assert( + `All elements of a hasMany relationship must be instances of DS.Model, you passed ${inspect( + records + )}`, + (function() { + return A(records).every(record => record.hasOwnProperty('_internalModel') === true); + })() + ); // TODO this seems like unnecessary churn - this._modelData.setDirtyHasMany(key, records.map((record) => record.get('_internalModel._modelData').getResourceIdentifier())); + this._modelData.setDirtyHasMany( + key, + records.map(record => record.get('_internalModel._modelData').getResourceIdentifier()) + ); } setDirtyBelongsTo(key, value) { - // TODO this seems like a digression from the pattern in setDirtyHasMany return this._modelData.setDirtyBelongsTo(key, value); } @@ -683,7 +730,7 @@ export default class InternalModel { let isDirty = this._modelData.isAttrDirty(key); this.send('didSetProperty', { name: key, - isDirty: isDirty + isDirty: isDirty, }); } @@ -878,7 +925,9 @@ export default class InternalModel { let transitionMapId = `${state.stateName}->${name}`; do { - if (state.exit) { state.exit(this); } + if (state.exit) { + state.exit(this); + } state = state.parentState; } while (!state[pivotName]); @@ -901,8 +950,12 @@ export default class InternalModel { for (i = 0, l = path.length; i < l; i++) { state = state[path[i]]; - if (state.enter) { enters.push(state); } - if (state.setup) { setups.push(state); } + if (state.enter) { + enters.push(state); + } + if (state.setup) { + setups.push(state); + } } TransitionChainMap[transitionMapId] = { setups, enters, state }; @@ -925,12 +978,12 @@ export default class InternalModel { } _unhandledEvent(state, name, context) { - let errorMessage = "Attempted to handle event `" + name + "` "; - errorMessage += "on " + String(this) + " while in state "; - errorMessage += state.stateName + ". "; + let errorMessage = 'Attempted to handle event `' + name + '` '; + errorMessage += 'on ' + String(this) + ' while in state '; + errorMessage += state.stateName + '. '; if (context !== undefined) { - errorMessage += "Called with " + inspect(context) + "."; + errorMessage += 'Called with ' + inspect(context) + '.'; } throw new EmberError(errorMessage); @@ -955,7 +1008,7 @@ export default class InternalModel { let triggers = this._deferredTriggers; let record = this._record; let trigger = record.trigger; - for (let i = 0, l= triggers.length; i { + Object.keys(preload).forEach(key => { let preloadValue = get(preload, key); let relationshipMeta = this.modelClass.metaForProperty(key); if (relationshipMeta.isRelationship) { @@ -1007,8 +1060,11 @@ export default class InternalModel { let modelClass = relationshipMeta.type; let data; if (relationshipMeta.kind === 'hasMany') { - assert("You need to pass in an array to set a hasMany property on a record", Array.isArray(preloadValue)); - data = preloadValue.map((value) => this._convertPreloadRelationshipToJSON(value, modelClass )); + assert( + 'You need to pass in an array to set a hasMany property on a record', + Array.isArray(preloadValue) + ); + data = preloadValue.map(value => this._convertPreloadRelationshipToJSON(value, modelClass)); } else { data = this._convertPreloadRelationshipToJSON(preloadValue, modelClass); } @@ -1040,7 +1096,10 @@ export default class InternalModel { } setId(id) { - assert('A record\'s id cannot be changed once it is in the loaded state', this.id === null || this.id === id || this.isNew()); + assert( + "A record's id cannot be changed once it is in the loaded state", + this.id === null || this.id === id || this.isNew() + ); let didChange = id !== this.id; this.id = id; @@ -1056,7 +1115,7 @@ export default class InternalModel { if (this.hasRecord) { this._record.setProperties({ isError: true, - adapterError: error + adapterError: error, }); } } @@ -1068,7 +1127,7 @@ export default class InternalModel { if (this.hasRecord) { this._record.setProperties({ isError: false, - adapterError: null + adapterError: null, }); } } @@ -1088,7 +1147,9 @@ export default class InternalModel { this.send('didCommit'); this.updateRecordArrays(); - if (!data) { return; } + if (!data) { + return; + } this._record._notifyProperties(changedKeys); } @@ -1155,15 +1216,21 @@ export default class InternalModel { if (DEBUG) { let modelName = this.modelName; - assert(`There is no ${kind} relationship named '${name}' on a model of modelClass '${modelName}'`, relationship); + assert( + `There is no ${kind} relationship named '${name}' on a model of modelClass '${modelName}'`, + relationship + ); let actualRelationshipKind = relationship.relationshipMeta.kind; - assert(`You tried to get the '${name}' relationship on a '${modelName}' via record.${kind}('${name}'), but the relationship is of kind '${actualRelationshipKind}'. Use record.${actualRelationshipKind}('${name}') instead.`, actualRelationshipKind === kind); + assert( + `You tried to get the '${name}' relationship on a '${modelName}' via record.${kind}('${name}'), but the relationship is of kind '${actualRelationshipKind}'. Use record.${actualRelationshipKind}('${name}') instead.`, + actualRelationshipKind === kind + ); } - if (kind === "belongsTo") { + if (kind === 'belongsTo') { reference = new BelongsToReference(this.store, this, relationship, name); - } else if (kind === "hasMany") { + } else if (kind === 'hasMany') { reference = new HasManyReference(this.store, this, relationship, name); } diff --git a/addon/-record-data-rfc-private/system/model/model-data.js b/addon/-record-data-rfc-private/system/model/model-data.js index dd39f9e17d6..ac677577dae 100644 --- a/addon/-record-data-rfc-private/system/model/model-data.js +++ b/addon/-record-data-rfc-private/system/model/model-data.js @@ -1,10 +1,10 @@ import isEnabled from '../../features'; import { DEBUG } from '@glimmer/env'; -import Relationships from "../relationships/state/create"; +import Relationships from '../relationships/state/create'; import { assign } from '@ember/polyfills'; import { isEqual } from '@ember/utils'; import { assert, warn, inspect } from '@ember/debug'; -import coerceId from "../coerce-id"; +import coerceId from '../coerce-id'; import { run } from '@ember/runloop'; let nextBfsId = 1; @@ -31,8 +31,8 @@ export default class ModelData { return { id: this.id, type: this.modelName, - clientId: this.clientId - } + clientId: this.clientId, + }; } pushData(data, calculateChange) { @@ -72,9 +72,7 @@ export default class ModelData { // and relationships need this info and @runspired didn't see // how to get it just yet from storeWrapper. isEmpty() { - return this.__attributes === null && - this.__inFlightAttributes === null && - this.__data === null; + return this.__attributes === null && this.__inFlightAttributes === null && this.__data === null; } reset() { @@ -86,7 +84,7 @@ export default class ModelData { _setupRelationships(data) { let relationships = this.storeWrapper.relationshipsDefinitionFor(this.modelName); let keys = Object.keys(relationships); - for (let i=0; i < keys.length; i++) { + for (let i = 0; i < keys.length; i++) { let relationshipName = keys[i]; if (!data.relationships[relationshipName]) { @@ -105,18 +103,43 @@ export default class ModelData { if (relationshipData.links) { let isAsync = relationshipMeta.options && relationshipMeta.options.async !== false; - warn(`You pushed a record of type '${this.modelName}' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, isAsync || relationshipData.data , { - id: 'ds.store.push-link-for-sync-relationship' - }); + warn( + `You pushed a record of type '${ + this.modelName + }' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, + isAsync || relationshipData.data, + { + id: 'ds.store.push-link-for-sync-relationship', + } + ); } else if (relationshipData.data) { if (relationshipMeta.kind === 'belongsTo') { - assert(`A ${this.modelName} record was pushed into the store with the value of ${relationshipName} being ${inspect(relationshipData.data)}, but ${relationshipName} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(relationshipData.data)); + assert( + `A ${ + this.modelName + } record was pushed into the store with the value of ${relationshipName} being ${inspect( + relationshipData.data + )}, but ${relationshipName} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, + !Array.isArray(relationshipData.data) + ); assertRelationshipData(store, modelData, relationshipData.data, relationshipMeta); } else if (relationshipMeta.kind === 'hasMany') { - assert(`A ${this.modelName} record was pushed into the store with the value of ${relationshipName} being '${inspect(relationshipData.data)}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(relationshipData.data)); + assert( + `A ${ + this.modelName + } record was pushed into the store with the value of ${relationshipName} being '${inspect( + relationshipData.data + )}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, + Array.isArray(relationshipData.data) + ); if (Array.isArray(relationshipData.data)) { for (let i = 0; i < relationshipData.data.length; i++) { - assertRelationshipData(store, modelData, relationshipData.data[i], relationshipMeta); + assertRelationshipData( + store, + modelData, + relationshipData.data[i], + relationshipMeta + ); } } } @@ -233,7 +256,11 @@ export default class ModelData { setDirtyHasMany(key, resources) { let relationship = this._relationships.get(key); relationship.clear(); - relationship.addModelDatas(resources.map(resource => this.storeWrapper.modelDataFor(resource.type, resource.id, resource.clientId))); + relationship.addModelDatas( + resources.map(resource => + this.storeWrapper.modelDataFor(resource.type, resource.id, resource.clientId) + ) + ); } // append to "current state" via ModelDatas @@ -252,7 +279,7 @@ export default class ModelData { let keys = Object.keys(this._inFlightAttributes); if (keys.length > 0) { let attrs = this._attributes; - for (let i=0; i < keys.length; i++) { + for (let i = 0; i < keys.length; i++) { if (attrs[keys[i]] === undefined) { attrs[keys[i]] = this._inFlightAttributes[keys[i]]; } @@ -306,9 +333,7 @@ export default class ModelData { } hasAttr(key) { - return key in this._attributes || - key in this._inFlightAttributes || - key in this._data; + return key in this._attributes || key in this._inFlightAttributes || key in this._data; } unloadRecord() { @@ -318,14 +343,18 @@ export default class ModelData { this._destroyRelationships(); this.reset(); if (!this._scheduledDestroy) { - this._scheduledDestroy = run.backburner.schedule('destroy', this, '_cleanupOrphanedModelDatas') + this._scheduledDestroy = run.backburner.schedule( + 'destroy', + this, + '_cleanupOrphanedModelDatas' + ); } } _cleanupOrphanedModelDatas() { let relatedModelDatas = this._allRelatedModelDatas(); if (areAllModelsUnloaded(relatedModelDatas)) { - for (let i=0; i { + Object.keys(implicitRelationships).forEach(key => { let rel = implicitRelationships[key]; rel.removeCompletelyFromInverse(); @@ -530,7 +557,7 @@ export default class ModelData { let implicitRelationships = this._implicitRelationships; this.__implicitRelationships = null; - Object.keys(implicitRelationships).forEach((key) => { + Object.keys(implicitRelationships).forEach(key => { let rel = implicitRelationships[key]; destroyRelationship(rel); }); @@ -540,7 +567,6 @@ export default class ModelData { this._isNew = true; } - /* Ember Data has 3 buckets for storing the value of an attribute on an internalModel. @@ -597,7 +623,7 @@ export default class ModelData { let hasAttrs = this.hasChangedAttributes(); let attrs; if (hasAttrs) { - attrs= this._attributes; + attrs = this._attributes; } original = assign(Object.create(null), this._data, this.__inFlightAttributes); @@ -626,7 +652,6 @@ export default class ModelData { toString() { return `<${this.modelName}:${this.id}>`; } - } if (isEnabled('ds-rollback-attribute')) { @@ -647,23 +672,38 @@ if (isEnabled('ds-rollback-attribute')) { } function assertRelationshipData(store, modelData, data, meta) { - assert(`A ${modelData.modelName} record was pushed into the store with the value of ${meta.key} being '${JSON.stringify(data)}', but ${meta.key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(data)); assert( - `Encountered a relationship identifier without a type for the ${meta.kind} relationship '${meta.key}' on ${modelData}, expected a json-api identifier with type '${meta.type}' but found '${JSON.stringify(data)}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, + `A ${modelData.modelName} record was pushed into the store with the value of ${ + meta.key + } being '${JSON.stringify(data)}', but ${ + meta.key + } is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, + !Array.isArray(data) + ); + assert( + `Encountered a relationship identifier without a type for the ${meta.kind} relationship '${ + meta.key + }' on ${modelData}, expected a json-api identifier with type '${ + meta.type + }' but found '${JSON.stringify( + data + )}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || (typeof data.type === 'string' && data.type.length) ); assert( - `Encountered a relationship identifier without an id for the ${meta.kind} relationship '${meta.key}' on ${modelData}, expected a json-api identifier but found '${JSON.stringify(data)}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, + `Encountered a relationship identifier without an id for the ${meta.kind} relationship '${ + meta.key + }' on ${modelData}, expected a json-api identifier but found '${JSON.stringify( + data + )}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || coerceId(data.id) ); assert( - `Encountered a relationship identifier with type '${ - data.type - }' for the ${meta.kind} relationship '${meta.key}' on ${ - modelData - }, Expected a json-api identifier with type '${ + `Encountered a relationship identifier with type '${data.type}' for the ${ + meta.kind + } relationship '${meta.key}' on ${modelData}, Expected a json-api identifier with type '${ meta.type - }'. No model was found for '${data.type}'.`, + }'. No model was found for '${data.type}'.`, data === null || !data.type || store._hasModelFor(data.type) ); } @@ -688,7 +728,7 @@ function destroyRelationship(rel) { } function areAllModelsUnloaded(modelDatas) { - for (let i=0; i { let optionsForRelationship = inverseType.metaForProperty(relationship.name).options; @@ -54,9 +53,9 @@ function findPossibleInverses(type, inverseType, name, relationshipsSoFar) { return possibleRelationships; } -function intersection (array1, array2) { +function intersection(array1, array2) { let result = []; - array1.forEach((element) => { + array1.forEach(element => { if (array2.indexOf(element) >= 0) { result.push(element); } @@ -65,9 +64,7 @@ function intersection (array1, array2) { return result; } -const RESERVED_MODEL_PROPS = [ - 'currentState', 'data', 'store' -]; +const RESERVED_MODEL_PROPS = ['currentState', 'data', 'store']; const retrieveFromCurrentState = computed('currentState', function(key) { return get(this._internalModel.currentState, key); @@ -402,13 +399,15 @@ const Model = EmberObject.extend(Evented, { errors: computed(function() { let errors = Errors.create(); - errors._registerHandlers(this._internalModel, + errors._registerHandlers( + this._internalModel, function() { this.send('becameInvalid'); }, function() { this.send('becameValid'); - }); + } + ); return errors; }).readOnly(), @@ -538,7 +537,6 @@ const Model = EmberObject.extend(Evented, { return this._internalModel.transitionTo(name); }, - /** Marks the record as deleted but does not save it. You must call `save` afterwards if you want to persist it. You might use this @@ -626,7 +624,9 @@ const Model = EmberObject.extend(Evented, { @method unloadRecord */ unloadRecord() { - if (this.isDestroyed) { return; } + if (this.isDestroyed) { + return; + } this._internalModel.unloadRecord(); }, @@ -791,7 +791,7 @@ const Model = EmberObject.extend(Evented, { */ save(options) { return PromiseObject.create({ - promise: this._internalModel.save(options).then(() => this) + promise: this._internalModel.save(options).then(() => this), }); }, @@ -828,16 +828,15 @@ const Model = EmberObject.extend(Evented, { if (typeof options === 'object' && options !== null && options.adapterOptions) { wrappedAdapterOptions = { - adapterOptions: options.adapterOptions + adapterOptions: options.adapterOptions, }; } return PromiseObject.create({ - promise: this._internalModel.reload(wrappedAdapterOptions).then(() => this) + promise: this._internalModel.reload(wrappedAdapterOptions).then(() => this), }); }, - /** Override the default event firing from Ember.Evented to also call methods with the given name. @@ -856,14 +855,17 @@ const Model = EmberObject.extend(Evented, { for (let i = 1; i < length; i++) { args[i - 1] = arguments[i]; } - fn.apply(this, args) + fn.apply(this, args); } this._super(...arguments); }, attr() { - assert("The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?", false); + assert( + 'The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?', + false + ); }, /** @@ -1010,7 +1012,7 @@ const Model = EmberObject.extend(Evented, { */ _debugInfo() { let attributes = ['id']; - let relationships = { }; + let relationships = {}; let expensiveProperties = []; this.eachAttribute((name, meta) => attributes.push(name)); @@ -1019,8 +1021,8 @@ const Model = EmberObject.extend(Evented, { { name: 'Attributes', properties: attributes, - expand: true - } + expand: true, + }, ]; this.eachRelationship((name, relationship) => { @@ -1031,7 +1033,7 @@ const Model = EmberObject.extend(Evented, { groups.push({ name: relationship.name, properties, - expand: true + expand: true, }); } properties.push(name); @@ -1040,7 +1042,15 @@ const Model = EmberObject.extend(Evented, { groups.push({ name: 'Flags', - properties: ['isLoaded', 'hasDirtyAttributes', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'] + properties: [ + 'isLoaded', + 'hasDirtyAttributes', + 'isSaving', + 'isDeleted', + 'isError', + 'isNew', + 'isValid', + ], }); return { @@ -1049,8 +1059,8 @@ const Model = EmberObject.extend(Evented, { includeOtherProperties: true, groups: groups, // don't pre-calculate unless cached - expensiveProperties: expensiveProperties - } + expensiveProperties: expensiveProperties, + }, }; }, @@ -1130,7 +1140,7 @@ const Model = EmberObject.extend(Evented, { eachAttribute(callback, binding) { this.constructor.eachAttribute(callback, binding); - } + }, }); /** @@ -1143,7 +1153,7 @@ Object.defineProperty(Model.prototype, 'data', { get() { // TODO deprecate this!!!!!!!!!!! it's private but intimate return this._internalModel._modelData._data; - } + }, }); Object.defineProperty(Model.prototype, 'id', { @@ -1157,7 +1167,7 @@ Object.defineProperty(Model.prototype, 'id', { // (addListener via validatePropertyInjections) invokes toString before the // object is real. return this._internalModel && this._internalModel.id; - } + }, }); if (DEBUG) { @@ -1166,9 +1176,11 @@ if (DEBUG) { this._super(...arguments); if (!this._internalModel) { - throw new EmberError('You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.'); + throw new EmberError( + 'You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.' + ); } - } + }, }); } @@ -1309,7 +1321,6 @@ Model.reopenClass({ //Calculate the inverse, ignoring the cache _findInverseFor(name, store) { - let inverseType = this.typeForRelationship(name, store); if (!inverseType) { return null; @@ -1318,7 +1329,9 @@ Model.reopenClass({ let propertyMeta = this.metaForProperty(name); //If inverse is manually specified to be null, like `comments: DS.hasMany('message', { inverse: null })` let options = propertyMeta.options; - if (options.inverse === null) { return null; } + if (options.inverse === null) { + return null; + } let inverseName, inverseKind, inverse, inverseOptions; @@ -1327,8 +1340,14 @@ Model.reopenClass({ inverseName = options.inverse; inverse = get(inverseType, 'relationshipsByName').get(inverseName); - assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.modelName + - "' model. This is most likely due to a missing attribute on your model definition.", !isNone(inverse)); + assert( + "We found no inverse relationships by the name of '" + + inverseName + + "' on the '" + + inverseType.modelName + + "' model. This is most likely due to a missing attribute on your model definition.", + !isNone(inverse) + ); // TODO probably just return the whole inverse here inverseKind = inverse.kind; @@ -1336,44 +1355,73 @@ Model.reopenClass({ } else { //No inverse was specified manually, we need to use a heuristic to guess one if (propertyMeta.parentType && propertyMeta.type === propertyMeta.parentType.modelName) { - warn(`Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at https://guides.emberjs.com/current/models/relationships/#toc_reflexive-relations for how to explicitly specify inverses.`, false, { - id: 'ds.model.reflexive-relationship-without-inverse' - }); + warn( + `Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at https://guides.emberjs.com/current/models/relationships/#toc_reflexive-relations for how to explicitly specify inverses.`, + false, + { + id: 'ds.model.reflexive-relationship-without-inverse', + } + ); } let possibleRelationships = findPossibleInverses(this, inverseType, name); - if (possibleRelationships.length === 0) { return null; } + if (possibleRelationships.length === 0) { + return null; + } - let filteredRelationships = possibleRelationships.filter((possibleRelationship) => { + let filteredRelationships = possibleRelationships.filter(possibleRelationship => { let optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options; return name === optionsForRelationship.inverse; }); - assert("You defined the '" + name + "' relationship on " + this + ", but you defined the inverse relationships of type " + - inverseType.toString() + " multiple times. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses", - filteredRelationships.length < 2); - - if (filteredRelationships.length === 1 ) { + assert( + "You defined the '" + + name + + "' relationship on " + + this + + ', but you defined the inverse relationships of type ' + + inverseType.toString() + + ' multiple times. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses', + filteredRelationships.length < 2 + ); + + if (filteredRelationships.length === 1) { possibleRelationships = filteredRelationships; } - assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + - this + " were found on " + inverseType + ". Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses", - possibleRelationships.length === 1); + assert( + "You defined the '" + + name + + "' relationship on " + + this + + ', but multiple possible inverse relationships of type ' + + this + + ' were found on ' + + inverseType + + '. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses', + possibleRelationships.length === 1 + ); inverseName = possibleRelationships[0].name; inverseKind = possibleRelationships[0].kind; inverseOptions = possibleRelationships[0].options; } - assert(`The ${inverseType.modelName}:${inverseName} relationship declares 'inverse: null', but it was resolved as the inverse for ${this.modelName}:${name}.`, !inverseOptions || inverseOptions.inverse !== null); + assert( + `The ${ + inverseType.modelName + }:${inverseName} relationship declares 'inverse: null', but it was resolved as the inverse for ${ + this.modelName + }:${name}.`, + !inverseOptions || inverseOptions.inverse !== null + ); return { type: inverseType, name: inverseName, kind: inverseKind, - options: inverseOptions + options: inverseOptions, }; }, @@ -1457,7 +1505,7 @@ Model.reopenClass({ relationshipNames: computed(function() { let names = { hasMany: [], - belongsTo: [] + belongsTo: [], }; this.eachComputedProperty((name, meta) => { @@ -1542,7 +1590,6 @@ Model.reopenClass({ */ relationshipsByName: relationshipsByNameDescriptor, - relationshipsObject: relationshipsObjectDescriptor, /** @@ -1700,7 +1747,11 @@ Model.reopenClass({ this.eachComputedProperty((name, meta) => { if (meta.isAttribute) { - assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.toString(), name !== 'id'); + assert( + "You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + + this.toString(), + name !== 'id' + ); meta.name = name; map.set(name, meta); @@ -1867,7 +1918,7 @@ Model.reopenClass({ */ toString() { return `model:${get(this, 'modelName')}`; - } + }, }); if (DEBUG) { @@ -1876,8 +1927,18 @@ if (DEBUG) { // rely on the data property. willMergeMixin(props) { let constructor = this.constructor; - assert('`' + intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + constructor.toString(), !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0]); - assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + constructor.toString(), Object.keys(props).indexOf('id') === -1); + assert( + '`' + + intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + + '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + + constructor.toString(), + !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + ); + assert( + "You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + + constructor.toString(), + Object.keys(props).indexOf('id') === -1 + ); }, /** @@ -1909,7 +1970,6 @@ if (DEBUG) { didDefineProperty(proto, key, value) { // Check if the value being set is a computed property. if (value instanceof ComputedProperty) { - // If it is, get the metadata for the relationship. This is // populated by the `DS.belongsTo` helper when it is creating // the computed property. @@ -1921,7 +1981,7 @@ if (DEBUG) { */ meta.parentType = proto.constructor; } - } + }, }); } diff --git a/addon/-record-data-rfc-private/system/model/states.js b/addon/-record-data-rfc-private/system/model/states.js index f67bd7a0cbc..55438b134f6 100644 --- a/addon/-record-data-rfc-private/system/model/states.js +++ b/addon/-record-data-rfc-private/system/model/states.js @@ -238,10 +238,12 @@ const DirtyState = { //TODO(Igor) reloading now triggers a //loadingData event, though it seems fine? - loadingData() { }, + loadingData() {}, propertyWasReset(internalModel, name) { - if (!internalModel.hasChangedAttributes()) { internalModel.send('rolledBack'); } + if (!internalModel.hasChangedAttributes()) { + internalModel.send('rolledBack'); + } }, pushedData(internalModel) { @@ -275,7 +277,7 @@ const DirtyState = { rollback(internalModel) { internalModel.rollbackAttributes(); internalModel.triggerLater('ready'); - } + }, }, // Once a record has been handed off to the adapter to be @@ -287,13 +289,13 @@ const DirtyState = { // EVENTS didSetProperty, - becomeDirty() { }, - pushedData() { }, + becomeDirty() {}, + pushedData() {}, unloadRecord: assertAgainstUnloadRecord, // TODO: More robust semantics around save-while-in-flight - willCommit() { }, + willCommit() {}, didCommit(internalModel) { internalModel.transitionTo('saved'); @@ -312,7 +314,7 @@ const DirtyState = { becameError(internalModel) { internalModel.transitionTo('uncommitted'); internalModel.triggerLater('becameError', internalModel); - } + }, }, // A record is in the `invalid` if the adapter has indicated @@ -336,9 +338,9 @@ const DirtyState = { } }, - becameInvalid() { }, - becomeDirty() { }, - pushedData() { }, + becameInvalid() {}, + becomeDirty() {}, + pushedData() {}, willCommit(internalModel) { internalModel.clearErrorMessages(); @@ -357,8 +359,8 @@ const DirtyState = { invokeLifecycleCallbacks(internalModel) { internalModel.triggerLater('becameInvalid', internalModel); - } - } + }, + }, }; // The created and updated states are created outside the state @@ -397,7 +399,7 @@ function dirtyState(options) { const createdState = dirtyState({ dirtyType: 'created', // FLAGS - isNew: true + isNew: true, }); createdState.invalid.rolledBack = function(internalModel) { @@ -411,7 +413,7 @@ createdState.uncommitted.rolledBack = function(internalModel) { }; const updatedState = dirtyState({ - dirtyType: 'updated' + dirtyType: 'updated', }); function createdStateDeleteRecord(internalModel) { @@ -436,7 +438,7 @@ createdState.uncommitted.pushedData = function(internalModel) { createdState.uncommitted.propertyWasReset = function() {}; function assertAgainstUnloadRecord(internalModel) { - assert("You can only unload a record which is not inFlight. `" + internalModel + "`", false); + assert('You can only unload a record which is not inFlight. `' + internalModel + '`', false); } updatedState.invalid.becameValid = function(internalModel) { @@ -475,11 +477,10 @@ const RootState = { // doesn't change your state. For example, if you're in the // in-flight state, rolling back the record doesn't move // you out of the in-flight state. - rolledBack() { }, - unloadRecord(internalModel) { - }, + rolledBack() {}, + unloadRecord(internalModel) {}, - propertyWasReset() { }, + propertyWasReset() {}, // SUBSTATES @@ -506,7 +507,7 @@ const RootState = { internalModel.transitionTo('loaded.saved'); internalModel.triggerLater('didLoad'); internalModel.triggerLater('ready'); - } + }, }, // A record enters this state when the store asks @@ -538,7 +539,7 @@ const RootState = { notFound(internalModel) { internalModel.transitionTo('empty'); - } + }, }, // A record enters this state when its data is populated. @@ -552,7 +553,7 @@ const RootState = { //TODO(Igor) Reloading now triggers a loadingData event, //but it should be ok? - loadingData() { }, + loadingData() {}, // SUBSTATES @@ -568,7 +569,7 @@ const RootState = { // EVENTS didSetProperty, - pushedData() { }, + pushedData() {}, becomeDirty(internalModel) { internalModel.transitionTo('updated.uncommitted'); @@ -586,14 +587,13 @@ const RootState = { internalModel.transitionTo('deleted.uncommitted'); }, - unloadRecord(internalModel) { - }, + unloadRecord(internalModel) {}, didCommit() {}, // loaded.saved.notFound would be triggered by a failed // `reload()` on an unchanged record - notFound() { } + notFound() {}, }, // A record is in this state after it has been locally @@ -604,7 +604,7 @@ const RootState = { // A record is in this state if it has already been // saved to the server, but there are new local changes // that have not yet been saved. - updated: updatedState + updated: updatedState, }, // A record is in this state if it was deleted from the store. @@ -628,7 +628,6 @@ const RootState = { // state. It will exit this state when the record // starts to commit. uncommitted: { - // EVENTS willCommit(internalModel) { @@ -640,15 +639,15 @@ const RootState = { internalModel.triggerLater('ready'); }, - pushedData() { }, - becomeDirty() { }, - deleteRecord() { }, + pushedData() {}, + becomeDirty() {}, + deleteRecord() {}, rolledBack(internalModel) { internalModel.transitionTo('loaded.saved'); internalModel.triggerLater('ready'); internalModel.triggerLater('rolledBack'); - } + }, }, // After a record starts committing, but @@ -664,7 +663,7 @@ const RootState = { unloadRecord: assertAgainstUnloadRecord, // TODO: More robust semantics around save-while-in-flight - willCommit() { }, + willCommit() {}, didCommit(internalModel) { internalModel.transitionTo('saved'); @@ -679,7 +678,7 @@ const RootState = { becameInvalid(internalModel) { internalModel.transitionTo('invalid'); internalModel.triggerLater('becameInvalid', internalModel); - } + }, }, // Once the adapter indicates that the deletion has @@ -698,9 +697,9 @@ const RootState = { internalModel.triggerLater('didCommit', internalModel); }, - willCommit() { }, - didCommit() { }, - pushedData() {} + willCommit() {}, + didCommit() {}, + pushedData() {}, }, invalid: { @@ -716,10 +715,10 @@ const RootState = { } }, - becameInvalid() { }, - becomeDirty() { }, - deleteRecord() { }, - willCommit() { }, + becameInvalid() {}, + becomeDirty() {}, + deleteRecord() {}, + willCommit() {}, rolledBack(internalModel) { internalModel.clearErrorMessages(); @@ -729,9 +728,8 @@ const RootState = { becameValid(internalModel) { internalModel.transitionTo('uncommitted'); - } - - } + }, + }, }, invokeLifecycleCallbacks(internalModel, dirtyType) { @@ -742,7 +740,7 @@ const RootState = { } internalModel.triggerLater('didCommit', internalModel); - } + }, }; function wireState(object, parent, name) { @@ -752,7 +750,9 @@ function wireState(object, parent, name) { object.stateName = name; for (let prop in object) { - if (!object.hasOwnProperty(prop) || prop === 'parentState' || prop === 'stateName') { continue; } + if (!object.hasOwnProperty(prop) || prop === 'parentState' || prop === 'stateName') { + continue; + } if (typeof object[prop] === 'object') { object[prop] = wireState(object[prop], object, name + '.' + prop); } diff --git a/addon/-record-data-rfc-private/system/normalize-link.js b/addon/-record-data-rfc-private/system/normalize-link.js index 59d9d6536e8..33e7a31ad97 100644 --- a/addon/-record-data-rfc-private/system/normalize-link.js +++ b/addon/-record-data-rfc-private/system/normalize-link.js @@ -12,8 +12,10 @@ */ export default function _normalizeLink(link) { switch (typeof link) { - case 'object': return link; - case 'string': return { href: link }; + case 'object': + return link; + case 'string': + return { href: link }; } return null; } diff --git a/addon/-record-data-rfc-private/system/promise-proxies.js b/addon/-record-data-rfc-private/system/promise-proxies.js index 07adef6523e..a34330d0c59 100644 --- a/addon/-record-data-rfc-private/system/promise-proxies.js +++ b/addon/-record-data-rfc-private/system/promise-proxies.js @@ -36,7 +36,7 @@ import { assert } from '@ember/debug'; @uses Ember.PromiseProxyMixin */ export const PromiseArray = ArrayProxy.extend(PromiseProxyMixin, { - meta: reads('content.meta') + meta: reads('content.meta'), }); /** @@ -72,41 +72,44 @@ export let PromiseObject = ObjectProxy.extend(PromiseProxyMixin); export function promiseObject(promise, label) { return PromiseObject.create({ - promise: Promise.resolve(promise, label) + promise: Promise.resolve(promise, label), }); } export function promiseArray(promise, label) { return PromiseArray.create({ - promise: Promise.resolve(promise, label) + promise: Promise.resolve(promise, label), }); } export const PromiseBelongsTo = PromiseObject.extend({ - // we don't proxy meta because we would need to proxy it to the relationship state container // however, meta on relationships does not trigger change notifications. // if you need relationship meta, you should do `record.belongsTo(relationshipName).meta()` meta: computed(function() { assert( 'You attempted to access meta on the promise for the async belongsTo relationship ' + - `${this.get('_belongsToState').internalModel.modelName}:${this.get('_belongsToState').key}'.` + - '\nUse `record.belongsTo(relationshipName).meta()` instead.', + `${this.get('_belongsToState').internalModel.modelName}:${ + this.get('_belongsToState').key + }'.` + + '\nUse `record.belongsTo(relationshipName).meta()` instead.', false ); }), reload() { - assert('You are trying to reload an async belongsTo before it has been created', this.get('content') !== undefined); + assert( + 'You are trying to reload an async belongsTo before it has been created', + this.get('content') !== undefined + ); let state = this.get('_belongsToState'); let key = state.key; let store = state.store; let resource = state.modelData.getResourceIdentifier(); let internalModel = store._internalModelForResource(resource); - return store.reloadBelongsTo(this, internalModel, key) - .then(() => this); - } + return store.reloadBelongsTo(this, internalModel, key).then(() => this); + }, }); /** @@ -135,7 +138,10 @@ export function proxyToContent(method) { export const PromiseManyArray = PromiseArray.extend({ reload() { - assert('You are trying to reload an async manyArray before it has been created', get(this, 'content')); + assert( + 'You are trying to reload an async manyArray before it has been created', + get(this, 'content') + ); this.set('promise', this.get('content').reload()); return this; }, @@ -150,11 +156,11 @@ export const PromiseManyArray = PromiseArray.extend({ off: proxyToContent('off'), - has: proxyToContent('has') + has: proxyToContent('has'), }); export function promiseManyArray(promise, label) { return PromiseManyArray.create({ - promise: Promise.resolve(promise, label) + promise: Promise.resolve(promise, label), }); } diff --git a/addon/-record-data-rfc-private/system/record-array-manager.js b/addon/-record-data-rfc-private/system/record-array-manager.js index b61d6289fe1..e8e3ae6c5b8 100644 --- a/addon/-record-data-rfc-private/system/record-array-manager.js +++ b/addon/-record-data-rfc-private/system/record-array-manager.js @@ -7,10 +7,7 @@ import { set, get } from '@ember/object'; import { run as emberRun } from '@ember/runloop'; import { assert } from '@ember/debug'; import cloneNull from './clone-null'; -import { - RecordArray, - AdapterPopulatedRecordArray -} from './record-arrays'; +import { RecordArray, AdapterPopulatedRecordArray } from './record-arrays'; const { _flush, @@ -20,8 +17,9 @@ const { createRecordArray, liveRecordArrayFor, recordDidChange, - unregisterRecordArray -} = heimdall.registerMonitor('recordArrayManager', + unregisterRecordArray, +} = heimdall.registerMonitor( + 'recordArrayManager', '_flush', 'array_remove', 'create', @@ -72,7 +70,7 @@ export default class RecordArrayManager { internalModel._pendingRecordArrayManagerFlush = true; let pending = this._pending; - let models = pending[modelName] = pending[modelName] || []; + let models = (pending[modelName] = pending[modelName] || []); if (models.push(internalModel) !== 1) { return; } @@ -123,7 +121,10 @@ export default class RecordArrayManager { } _syncLiveRecordArray(array, modelName) { - assert(`recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, typeof modelName === 'string'); + assert( + `recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, + typeof modelName === 'string' + ); let pending = this._pending[modelName]; let hasPendingChanges = Array.isArray(pending); let hasNoPotentialDeletions = !hasPendingChanges || pending.length === 0; @@ -177,7 +178,10 @@ export default class RecordArrayManager { @return {DS.RecordArray} */ liveRecordArrayFor(modelName) { - assert(`recordArrayManger.liveRecordArrayFor expects modelName not modelClass as the param`, typeof modelName === 'string'); + assert( + `recordArrayManger.liveRecordArrayFor expects modelName not modelClass as the param`, + typeof modelName === 'string' + ); heimdall.increment(liveRecordArrayFor); @@ -218,7 +222,10 @@ export default class RecordArrayManager { @return {DS.RecordArray} */ createRecordArray(modelName, content) { - assert(`recordArrayManger.createRecordArray expects modelName not modelClass as the param`, typeof modelName === 'string'); + assert( + `recordArrayManger.createRecordArray expects modelName not modelClass as the param`, + typeof modelName === 'string' + ); heimdall.increment(createRecordArray); let array = RecordArray.create({ @@ -226,7 +233,7 @@ export default class RecordArrayManager { content: A(content || []), store: this.store, isLoaded: true, - manager: this + manager: this, }); if (Array.isArray(content)) { @@ -246,7 +253,10 @@ export default class RecordArrayManager { */ createAdapterPopulatedRecordArray(modelName, query, internalModels, payload) { heimdall.increment(createAdapterPopulatedRecordArray); - assert(`recordArrayManger.createAdapterPopulatedRecordArray expects modelName not modelClass as the first param, received ${modelName}`, typeof modelName === 'string'); + assert( + `recordArrayManger.createAdapterPopulatedRecordArray expects modelName not modelClass as the first param, received ${modelName}`, + typeof modelName === 'string' + ); let array; if (Array.isArray(internalModels)) { @@ -259,7 +269,7 @@ export default class RecordArrayManager { isLoaded: true, isUpdating: false, meta: cloneNull(payload.meta), - links: cloneNull(payload.links) + links: cloneNull(payload.links), }); associateWithRecordArray(internalModels, array); @@ -269,7 +279,7 @@ export default class RecordArrayManager { query: query, content: A(), store: this.store, - manager: this + manager: this, }); } @@ -294,7 +304,6 @@ export default class RecordArrayManager { let removedFromAdapterPopulated = remove(this._adapterPopulatedRecordArrays, array); if (!removedFromAdapterPopulated) { - let liveRecordArrayForType = this._liveRecordArrays[modelName]; // unregister live record array if (liveRecordArrayForType) { @@ -305,12 +314,14 @@ export default class RecordArrayManager { } } - _associateWithRecordArray(internalModels, array) { + _associateWithRecordArray(internalModels, array) { associateWithRecordArray(internalModels, array); } willDestroy() { - Object.keys(this._liveRecordArrays).forEach(modelName => this._liveRecordArrays[modelName].destroy()); + Object.keys(this._liveRecordArrays).forEach(modelName => + this._liveRecordArrays[modelName].destroy() + ); this._adapterPopulatedRecordArrays.forEach(destroy); this.isDestroyed = true; } @@ -355,12 +366,16 @@ function updateLiveRecordArray(array, internalModels) { if (isDeleted) { modelsToRemove.push(internalModel); - recordArrays.delete(array) + recordArrays.delete(array); } } - if (modelsToAdd.length > 0) { array._pushInternalModels(modelsToAdd); } - if (modelsToRemove.length > 0) { array._removeInternalModels(modelsToRemove); } + if (modelsToAdd.length > 0) { + array._pushInternalModels(modelsToAdd); + } + if (modelsToRemove.length > 0) { + array._removeInternalModels(modelsToRemove); + } // return whether we performed an update. // Necessary until 3.5 allows us to finish off ember-data-filter support. diff --git a/addon/-record-data-rfc-private/system/record-arrays.js b/addon/-record-data-rfc-private/system/record-arrays.js index d65107ed72a..5439899ad81 100644 --- a/addon/-record-data-rfc-private/system/record-arrays.js +++ b/addon/-record-data-rfc-private/system/record-arrays.js @@ -2,10 +2,7 @@ @module ember-data */ -import RecordArray from "./record-arrays/record-array"; -import AdapterPopulatedRecordArray from "./record-arrays/adapter-populated-record-array"; +import RecordArray from './record-arrays/record-array'; +import AdapterPopulatedRecordArray from './record-arrays/adapter-populated-record-array'; -export { - RecordArray, - AdapterPopulatedRecordArray -}; +export { RecordArray, AdapterPopulatedRecordArray }; diff --git a/addon/-record-data-rfc-private/system/record-arrays/adapter-populated-record-array.js b/addon/-record-data-rfc-private/system/record-arrays/adapter-populated-record-array.js index 7ccf8e89085..d3cc1e68a91 100644 --- a/addon/-record-data-rfc-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-record-data-rfc-private/system/record-arrays/adapter-populated-record-array.js @@ -1,8 +1,8 @@ import { once } from '@ember/runloop'; import { A } from '@ember/array'; import { get } from '@ember/object'; -import RecordArray from "./record-array"; -import cloneNull from "../clone-null"; +import RecordArray from './record-array'; +import cloneNull from '../clone-null'; /** Represents an ordered list of records whose order and membership is @@ -80,7 +80,7 @@ export default RecordArray.extend({ isLoaded: true, isUpdating: false, meta: cloneNull(payload.meta), - links: cloneNull(payload.links) + links: cloneNull(payload.links), }); this.manager._associateWithRecordArray(internalModels, this); @@ -88,5 +88,5 @@ export default RecordArray.extend({ // TODO: should triggering didLoad event be the last action of the runLoop? once(this, 'trigger', 'didLoad'); heimdall.stop(token); - } + }, }); diff --git a/addon/-record-data-rfc-private/system/record-arrays/record-array.js b/addon/-record-data-rfc-private/system/record-arrays/record-array.js index 71d2ffdef1c..78afefda737 100644 --- a/addon/-record-data-rfc-private/system/record-arrays/record-array.js +++ b/addon/-record-data-rfc-private/system/record-arrays/record-array.js @@ -7,8 +7,8 @@ import Evented from '@ember/object/evented'; import ArrayProxy from '@ember/array/proxy'; import { set, get, computed } from '@ember/object'; import { Promise } from 'rsvp'; -import { PromiseArray } from "../promise-proxies"; -import SnapshotRecordArray from "../snapshot-record-array"; +import { PromiseArray } from '../promise-proxies'; +import SnapshotRecordArray from '../snapshot-record-array'; /** A record array is an array that contains records of a certain modelName. The record @@ -53,7 +53,7 @@ export default ArrayProxy.extend(Evented, { @type Boolean */ this.isLoaded = this.isLoaded || false; - /** + /** The flag to signal a `RecordArray` is currently loading data. Example @@ -70,7 +70,7 @@ export default ArrayProxy.extend(Evented, { */ this.isUpdating = false; - /** + /** The store that created this record array. @property store @@ -82,7 +82,11 @@ export default ArrayProxy.extend(Evented, { }, replace() { - throw new Error(`The result of a server query (for all ${this.modelName} types) is immutable. To modify contents, use toArray()`); + throw new Error( + `The result of a server query (for all ${ + this.modelName + } types) is immutable. To modify contents, use toArray()` + ); }, /** @@ -131,13 +135,17 @@ export default ArrayProxy.extend(Evented, { @method update */ update() { - if (get(this, 'isUpdating')) { return this._updatingPromise; } + if (get(this, 'isUpdating')) { + return this._updatingPromise; + } this.set('isUpdating', true); let updatingPromise = this._update().finally(() => { this._updatingPromise = null; - if (this.get('isDestroying') || this.get('isDestroyed')) { return } + if (this.get('isDestroying') || this.get('isDestroyed')) { + return; + } this.set('isUpdating', false); }); @@ -197,8 +205,11 @@ export default ArrayProxy.extend(Evented, { */ save() { let promiseLabel = `DS: RecordArray#save ${this.modelName}`; - let promise = Promise.all(this.invoke('save'), promiseLabel) - .then(() => this, null, 'DS: RecordArray#save return RecordArray'); + let promise = Promise.all(this.invoke('save'), promiseLabel).then( + () => this, + null, + 'DS: RecordArray#save return RecordArray' + ); return PromiseArray.create({ promise }); }, @@ -251,5 +262,5 @@ export default ArrayProxy.extend(Evented, { */ _takeSnapshot() { return get(this, 'content').map(internalModel => internalModel.createSnapshot()); - } + }, }); diff --git a/addon/-record-data-rfc-private/system/references/belongs-to.js b/addon/-record-data-rfc-private/system/references/belongs-to.js index 8938e8265eb..29a679eea92 100644 --- a/addon/-record-data-rfc-private/system/references/belongs-to.js +++ b/addon/-record-data-rfc-private/system/references/belongs-to.js @@ -122,22 +122,31 @@ export default class BelongsToReference extends Reference { @return {Promise} A promise that resolves with the new value in this belongs-to relationship. */ push(objectOrPromise) { - return resolve(objectOrPromise).then((data) => { + return resolve(objectOrPromise).then(data => { let record; if (data instanceof Model) { if (isEnabled('ds-overhaul-references')) { - deprecate("BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead.", false, { - id: 'ds.references.belongs-to.push-record', - until: '4.0.0' - }); + deprecate( + "BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead.", + false, + { + id: 'ds.references.belongs-to.push-record', + until: '4.0.0', + } + ); } record = data; } else { record = this.store.push(data); } - assertPolymorphicType(this.internalModel, this.belongsToRelationship.relationshipMeta, record._internalModel, this.store); + assertPolymorphicType( + this.internalModel, + this.belongsToRelationship.relationshipMeta, + record._internalModel, + this.store + ); //TODO Igor cleanup, maybe move to relationship push this.belongsToRelationship.setCanonicalModelData(record._internalModel._modelData); @@ -246,7 +255,6 @@ export default class BelongsToReference extends Reference { return this.parentInternalModel.getBelongsTo(this.key); } - /** Triggers a reload of the value in this relationship. If the remoteType is `"link"` Ember Data will use the relationship link to @@ -286,13 +294,17 @@ export default class BelongsToReference extends Reference { reload() { let resource = this._resource(); if (resource && resource.links && resource.links.related) { - return this.store._fetchBelongsToLinkFromResource(resource, this.parentInternalModel, this.belongsToRelationship.relationshipMeta); + return this.store._fetchBelongsToLinkFromResource( + resource, + this.parentInternalModel, + this.belongsToRelationship.relationshipMeta + ); } if (resource && resource.data) { if (resource.data && (resource.data.id || resource.data.clientId)) { let internalModel = this.store._internalModelForResource(resource.data); if (internalModel.isLoaded()) { - return internalModel.reload().then((internalModel) => { + return internalModel.reload().then(internalModel => { if (internalModel) { return internalModel.getRecord(); } diff --git a/addon/-record-data-rfc-private/system/references/has-many.js b/addon/-record-data-rfc-private/system/references/has-many.js index f0a44b728b9..d74fe7871dc 100644 --- a/addon/-record-data-rfc-private/system/references/has-many.js +++ b/addon/-record-data-rfc-private/system/references/has-many.js @@ -69,13 +69,12 @@ export default class HasManyReference extends Reference { remoteType() { let value = this._resource(); if (value && value.links && value.links.related) { - return "link"; + return 'link'; } - return "ids"; + return 'ids'; } - /** `ids()` returns an array of the record ids in this relationship. @@ -113,14 +112,12 @@ export default class HasManyReference extends Reference { let ids = []; if (resource.data) { - ids = resource.data.map((data) => data.id); + ids = resource.data.map(data => data.id); } return ids; } - - /** `push` can be used to update the data in the relationship and Ember Data will treat the new data as the canonical value of this @@ -164,19 +161,24 @@ export default class HasManyReference extends Reference { @return {DS.ManyArray} */ push(objectOrPromise) { - return resolve(objectOrPromise).then((payload) => { + return resolve(objectOrPromise).then(payload => { let array = payload; - if (typeof payload === "object" && payload.data) { + if (typeof payload === 'object' && payload.data) { array = payload.data; } - let internalModels = array.map((obj) => { + let internalModels = array.map(obj => { let record = this.store.push(obj); if (DEBUG) { let relationshipMeta = this.hasManyRelationship.relationshipMeta; - assertPolymorphicType(this.internalModel, relationshipMeta, record._internalModel, this.store); + assertPolymorphicType( + this.internalModel, + relationshipMeta, + record._internalModel, + this.store + ); } return record._internalModel._modelData; }); @@ -198,7 +200,7 @@ export default class HasManyReference extends Reference { let members = this.hasManyRelationship.members.toArray(); //TODO Igor cleanup - return members.every((modelData) => { + return members.every(modelData => { let store = this.parentInternalModel.store; let internalModel = store._internalModelForModelData(modelData); return internalModel.isLoaded() === true; diff --git a/addon/-record-data-rfc-private/system/references/record.js b/addon/-record-data-rfc-private/system/references/record.js index 086945b3a22..56bb3338192 100644 --- a/addon/-record-data-rfc-private/system/references/record.js +++ b/addon/-record-data-rfc-private/system/references/record.js @@ -87,7 +87,7 @@ export default class RecordReference extends Reference { @return Promise a promise for the value (record or relationship) */ push(objectOrPromise) { - return resolve(objectOrPromise).then((data) => { + return resolve(objectOrPromise).then(data => { return this.store.push(data); }); } @@ -159,5 +159,4 @@ export default class RecordReference extends Reference { return this.load(); } - } diff --git a/addon/-record-data-rfc-private/system/references/reference.js b/addon/-record-data-rfc-private/system/references/reference.js index 6c54cf75ba1..a764bd83293 100644 --- a/addon/-record-data-rfc-private/system/references/reference.js +++ b/addon/-record-data-rfc-private/system/references/reference.js @@ -5,7 +5,7 @@ var Reference = function(store, internalModel) { }; Reference.prototype = { - constructor: Reference + constructor: Reference, }; /** @@ -50,10 +50,10 @@ Reference.prototype = { Reference.prototype.remoteType = function() { let value = this._resource(); if (value && value.links && value.links.related) { - return "link"; + return 'link'; } - return "id"; + return 'id'; }; /** diff --git a/addon/-record-data-rfc-private/system/relationships/belongs-to.js b/addon/-record-data-rfc-private/system/relationships/belongs-to.js index f979a8a7fc2..5cd2516357f 100644 --- a/addon/-record-data-rfc-private/system/relationships/belongs-to.js +++ b/addon/-record-data-rfc-private/system/relationships/belongs-to.js @@ -1,6 +1,6 @@ import { computed } from '@ember/object'; import { assert, warn, inspect } from '@ember/debug'; -import normalizeModelName from "../normalize-model-name"; +import normalizeModelName from '../normalize-model-name'; /** `DS.belongsTo` is used to define One-To-One and One-To-Many @@ -88,7 +88,12 @@ export default function belongsTo(modelName, options) { userEnteredModelName = normalizeModelName(userEnteredModelName); } - assert("The first argument to DS.belongsTo must be a string representing a model type key, not an instance of " + inspect(userEnteredModelName) + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", typeof userEnteredModelName === 'string' || typeof userEnteredModelName === 'undefined'); + assert( + 'The first argument to DS.belongsTo must be a string representing a model type key, not an instance of ' + + inspect(userEnteredModelName) + + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", + typeof userEnteredModelName === 'string' || typeof userEnteredModelName === 'undefined' + ); opts = opts || {}; @@ -98,21 +103,33 @@ export default function belongsTo(modelName, options) { options: opts, kind: 'belongsTo', name: 'Belongs To', - key: null + key: null, }; return computed({ get(key) { if (opts.hasOwnProperty('serialize')) { - warn(`You provided a serialize option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.Serializer and it's implementations https://emberjs.com/api/data/classes/DS.Serializer.html`, false, { - id: 'ds.model.serialize-option-in-belongs-to' - }); + warn( + `You provided a serialize option on the "${key}" property in the "${ + this._internalModel.modelName + }" class, this belongs in the serializer. See DS.Serializer and it's implementations https://emberjs.com/api/data/classes/DS.Serializer.html`, + false, + { + id: 'ds.model.serialize-option-in-belongs-to', + } + ); } if (opts.hasOwnProperty('embedded')) { - warn(`You provided an embedded option on the "${key}" property in the "${this._internalModel.modelName}" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin https://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html`, false, { - id: 'ds.model.embedded-option-in-belongs-to' - }); + warn( + `You provided an embedded option on the "${key}" property in the "${ + this._internalModel.modelName + }" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin https://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html`, + false, + { + id: 'ds.model.embedded-option-in-belongs-to', + } + ); } return this._internalModel.getBelongsTo(key); @@ -121,6 +138,6 @@ export default function belongsTo(modelName, options) { this._internalModel.setDirtyBelongsTo(key, value); return this._internalModel.getBelongsTo(key); - } + }, }).meta(meta); } diff --git a/addon/-record-data-rfc-private/system/relationships/ext.js b/addon/-record-data-rfc-private/system/relationships/ext.js index 058de16a08c..d1087e680a9 100644 --- a/addon/-record-data-rfc-private/system/relationships/ext.js +++ b/addon/-record-data-rfc-private/system/relationships/ext.js @@ -3,14 +3,13 @@ import { computed, get } from '@ember/object'; import MapWithDefault from '../map-with-default'; import Map from '../map'; import { assert } from '@ember/debug'; -import { - typeForRelationshipMeta, - relationshipFromMeta -} from "../relationship-meta"; +import { typeForRelationshipMeta, relationshipFromMeta } from '../relationship-meta'; export const relationshipsDescriptor = computed(function() { let map = new MapWithDefault({ - defaultValue() { return []; } + defaultValue() { + return []; + }, }); let relationshipsByName = get(this, 'relationshipsByName'); @@ -36,10 +35,18 @@ export const relatedTypesDescriptor = computed(function() { meta.key = name; modelName = typeForRelationshipMeta(meta); - assert(`You specified a hasMany (${meta.type}) on ${meta.parentType} but ${meta.type} was not found.`, modelName); + assert( + `You specified a hasMany (${meta.type}) on ${meta.parentType} but ${ + meta.type + } was not found.`, + modelName + ); if (!types.includes(modelName)) { - assert(`Trying to sideload ${name} on ${this.toString()} but the type doesn't exist.`, !!modelName); + assert( + `Trying to sideload ${name} on ${this.toString()} but the type doesn't exist.`, + !!modelName + ); types.push(modelName); } } @@ -65,7 +72,7 @@ export const relationshipsByNameDescriptor = computed(function() { let rels = get(this, 'relationshipsObject'); let relationships = Object.keys(rels); - for (let i=0; i < relationships.length; i++) { + for (let i = 0; i < relationships.length; i++) { let key = relationships[i]; let value = rels[key]; diff --git a/addon/-record-data-rfc-private/system/relationships/has-many.js b/addon/-record-data-rfc-private/system/relationships/has-many.js index be80f3bf32b..b4e782bbf49 100644 --- a/addon/-record-data-rfc-private/system/relationships/has-many.js +++ b/addon/-record-data-rfc-private/system/relationships/has-many.js @@ -3,7 +3,7 @@ */ import { computed } from '@ember/object'; import { assert, inspect } from '@ember/debug'; -import normalizeModelName from "../normalize-model-name"; +import normalizeModelName from '../normalize-model-name'; /** `DS.hasMany` is used to define One-To-Many and Many-To-Many @@ -117,7 +117,12 @@ export default function hasMany(type, options) { type = undefined; } - assert(`The first argument to DS.hasMany must be a string representing a model type key, not an instance of ${inspect(type)}. E.g., to define a relation to the Comment model, use DS.hasMany('comment')`, typeof type === 'string' || typeof type === 'undefined'); + assert( + `The first argument to DS.hasMany must be a string representing a model type key, not an instance of ${inspect( + type + )}. E.g., to define a relation to the Comment model, use DS.hasMany('comment')`, + typeof type === 'string' || typeof type === 'undefined' + ); options = options || {}; @@ -135,7 +140,7 @@ export default function hasMany(type, options) { isRelationship: true, kind: 'hasMany', name: 'Has Many', - key: null + key: null, }; return computed({ @@ -147,6 +152,6 @@ export default function hasMany(type, options) { internalModel.setDirtyHasMany(key, records); return internalModel.getHasMany(key); - } + }, }).meta(meta); } diff --git a/addon/-record-data-rfc-private/system/relationships/state/belongs-to.js b/addon/-record-data-rfc-private/system/relationships/state/belongs-to.js index 85d46804c97..231c9e78d5f 100644 --- a/addon/-record-data-rfc-private/system/relationships/state/belongs-to.js +++ b/addon/-record-data-rfc-private/system/relationships/state/belongs-to.js @@ -1,7 +1,7 @@ import { assert, inspect } from '@ember/debug'; import { assertPolymorphicType } from 'ember-data/-debug'; import { isNone } from '@ember/utils'; -import Relationship from "./relationship"; +import Relationship from './relationship'; export default class BelongsToRelationship extends Relationship { constructor(store, inverseKey, relationshipMeta, modelData, inverseIsAsync) { @@ -33,7 +33,9 @@ export default class BelongsToRelationship extends Relationship { } setInitialCanonicalModelData(modelData) { - if (!modelData) { return; } + if (!modelData) { + return; + } // When we initialize a belongsTo relationship, we want to avoid work like // notifying our internalModel that we've "changed" and excessive thrash on @@ -45,7 +47,9 @@ export default class BelongsToRelationship extends Relationship { } addCanonicalModelData(modelData) { - if (this.canonicalMembers.has(modelData)) { return;} + if (this.canonicalMembers.has(modelData)) { + return; + } if (this.canonicalState) { this.removeCanonicalModelData(this.canonicalState); @@ -73,7 +77,6 @@ export default class BelongsToRelationship extends Relationship { } } - removeCompletelyFromInverse() { super.removeCompletelyFromInverse(); @@ -95,7 +98,9 @@ export default class BelongsToRelationship extends Relationship { } addModelData(modelData) { - if (this.members.has(modelData)) { return; } + if (this.members.has(modelData)) { + return; + } // TODO Igor cleanup assertPolymorphicType(this.modelData, this.relationshipMeta, modelData, this.store); @@ -111,13 +116,18 @@ export default class BelongsToRelationship extends Relationship { setRecordPromise(newPromise) { let content = newPromise.get && newPromise.get('content'); - assert("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); + assert( + 'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.', + content !== undefined + ); // TODO Igor deal with this this.setModelData(content ? content._internalModel._modelData : content); } removeModelDataFromOwn(modelData) { - if (!this.members.has(modelData)) { return;} + if (!this.members.has(modelData)) { + return; + } this.inverseModelData = null; super.removeModelDataFromOwn(modelData); this.notifyBelongsToChanged(); @@ -132,11 +142,18 @@ export default class BelongsToRelationship extends Relationship { notifyBelongsToChanged() { let modelData = this.modelData; let storeWrapper = this.modelData.storeWrapper; - storeWrapper.notifyBelongsToChange(modelData.modelName, modelData.id, modelData.clientId, this.key); + storeWrapper.notifyBelongsToChange( + modelData.modelName, + modelData.id, + modelData.clientId, + this.key + ); } removeCanonicalModelDataFromOwn(modelData) { - if (!this.canonicalMembers.has(modelData)) { return;} + if (!this.canonicalMembers.has(modelData)) { + return; + } this.canonicalState = null; super.removeCanonicalModelDataFromOwn(modelData); } @@ -157,8 +174,8 @@ export default class BelongsToRelationship extends Relationship { } if (this.link) { payload.links = { - related: this.link - } + related: this.link, + }; } if (data !== undefined) { payload.data = data; @@ -182,7 +199,14 @@ export default class BelongsToRelationship extends Relationship { if (isNone(data)) { modelData = null; } - assert(`Ember Data expected the data for the ${this.key} relationship on a ${this.modelData.toString()} to be in a JSON API format and include an \`id\` and \`type\` property but it found ${inspect(data)}. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || data.id !== undefined && data.type !== undefined); + assert( + `Ember Data expected the data for the ${ + this.key + } relationship on a ${this.modelData.toString()} to be in a JSON API format and include an \`id\` and \`type\` property but it found ${inspect( + data + )}. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, + data === null || (data.id !== undefined && data.type !== undefined) + ); if (modelData !== null) { modelData = this.modelData.storeWrapper.modelDataFor(data.type, data.id); diff --git a/addon/-record-data-rfc-private/system/relationships/state/create.js b/addon/-record-data-rfc-private/system/relationships/state/create.js index fa69818b8c8..61e20400804 100644 --- a/addon/-record-data-rfc-private/system/relationships/state/create.js +++ b/addon/-record-data-rfc-private/system/relationships/state/create.js @@ -1,14 +1,23 @@ -import ManyRelationship from "./has-many"; -import BelongsToRelationship from "./belongs-to"; +import ManyRelationship from './has-many'; +import BelongsToRelationship from './belongs-to'; function createRelationshipFor(relationshipMeta, store, modelData, key) { let inverseKey = modelData.storeWrapper.inverseForRelationship(modelData.modelName, key); - let inverseIsAsync = modelData.storeWrapper.inverseIsAsyncForRelationship(modelData.modelName, key); + let inverseIsAsync = modelData.storeWrapper.inverseIsAsyncForRelationship( + modelData.modelName, + key + ); if (relationshipMeta.kind === 'hasMany') { return new ManyRelationship(store, inverseKey, relationshipMeta, modelData, inverseIsAsync); } else { - return new BelongsToRelationship(store, inverseKey, relationshipMeta, modelData, inverseIsAsync); + return new BelongsToRelationship( + store, + inverseKey, + relationshipMeta, + modelData, + inverseIsAsync + ); } } @@ -35,10 +44,17 @@ export default class Relationships { if (!relationship) { let modelData = this.modelData; - let rel = this.modelData.storeWrapper.relationshipsDefinitionFor(this.modelData.modelName)[key]; + let rel = this.modelData.storeWrapper.relationshipsDefinitionFor(this.modelData.modelName)[ + key + ]; if (rel) { - relationship = relationships[key] = createRelationshipFor(rel, modelData.store, modelData, key); + relationship = relationships[key] = createRelationshipFor( + rel, + modelData.store, + modelData, + key + ); } } diff --git a/addon/-record-data-rfc-private/system/relationships/state/has-many.js b/addon/-record-data-rfc-private/system/relationships/state/has-many.js index bf3514fbabb..2a0e2df719e 100755 --- a/addon/-record-data-rfc-private/system/relationships/state/has-many.js +++ b/addon/-record-data-rfc-private/system/relationships/state/has-many.js @@ -44,7 +44,12 @@ export default class ManyRelationship extends Relationship { notifyManyArrayIsStale() { let storeWrapper = this.modelData.storeWrapper; let modelData = this.modelData; - storeWrapper.notifyPropertyChange(modelData.modelName, modelData.id, modelData.clientId, this.key); + storeWrapper.notifyPropertyChange( + modelData.modelName, + modelData.id, + modelData.clientId, + this.key + ); } addModelData(modelData, idx) { @@ -112,7 +117,7 @@ export default class ManyRelationship extends Relationship { // been 'acknowleged' to be in the relationship via a store.push) //TODO Igor deal with this - (modelData) => modelData.isNew() && toSet.indexOf(modelData) === -1 + modelData => modelData.isNew() && toSet.indexOf(modelData) === -1 ); toSet = toSet.concat(newModelDatas); @@ -140,7 +145,7 @@ export default class ManyRelationship extends Relationship { // TODO Igor consider making direct to remove the indirection // We are not lazily accessing the manyArray here because the change is coming from app side this.notifyHasManyChanged(); - // this.manyArray.flushCanonical(this.currentState); + // this.manyArray.flushCanonical(this.currentState); } notifyRecordRelationshipAdded() { @@ -153,7 +158,9 @@ export default class ManyRelationship extends Relationship { let modelDatasSet = setForArray(modelDatas); members.forEach(member => { - if (modelDatasSet.has(member)) { return; } + if (modelDatasSet.has(member)) { + return; + } modelDatasToRemove.push(member); }); @@ -172,7 +179,7 @@ export default class ManyRelationship extends Relationship { return; } - for (let i = 0; i< modelDatas.length; i++) { + for (let i = 0; i < modelDatas.length; i++) { let modelData = modelDatas[i]; if (this.canonicalMembers.has(modelData)) { continue; @@ -189,18 +196,23 @@ export default class ManyRelationship extends Relationship { notifyHasManyChanged() { let modelData = this.modelData; let storeWrapper = this.modelData.storeWrapper; - storeWrapper.notifyHasManyChange(modelData.modelName, modelData.id, modelData.clientId, this.key); + storeWrapper.notifyHasManyChange( + modelData.modelName, + modelData.id, + modelData.clientId, + this.key + ); } getData() { let payload = {}; if (this.hasAnyRelationshipData) { - payload.data = this.currentState.map((modelData) => modelData.getResourceIdentifier()); + payload.data = this.currentState.map(modelData => modelData.getResourceIdentifier()); } if (this.link) { payload.links = { - related: this.link - } + related: this.link, + }; } if (this.meta) { payload.meta = this.meta; @@ -248,7 +260,7 @@ function setForArray(array) { var set = new OrderedSet(); if (array) { - for (var i=0, l=array.length; i { + this.forAllMembers(inverseModelData => { let relationship = inverseModelData._relationships.get(this.inverseKey); relationship.inverseDidDematerialize(this.modelData); }); @@ -275,7 +277,7 @@ export default class Relationship { removeModelDatas(modelDatas) { heimdall.increment(removeModelDatas); - modelDatas.forEach((modelData) => this.removeModelData(modelData)); + modelDatas.forEach(modelData => this.removeModelData(modelData)); } addModelDatas(modelDatas, idx) { @@ -290,9 +292,9 @@ export default class Relationship { addCanonicalModelDatas(modelDatas, idx) { heimdall.increment(addCanonicalModelDatas); - for (let i=0; i true */ if (hasRelationshipDataProperty) { - let relationshipIsEmpty = payload.data === null || - (Array.isArray(payload.data) && payload.data.length === 0); + let relationshipIsEmpty = + payload.data === null || (Array.isArray(payload.data) && payload.data.length === 0); this.setHasAnyRelationshipData(true); this.setRelationshipIsStale(false); diff --git a/addon/-record-data-rfc-private/system/snapshot.js b/addon/-record-data-rfc-private/system/snapshot.js index daeb46e2d3e..f61b9591660 100644 --- a/addon/-record-data-rfc-private/system/snapshot.js +++ b/addon/-record-data-rfc-private/system/snapshot.js @@ -91,7 +91,7 @@ export default class Snapshot { let record = this.record; attributes = this.__attributes = Object.create(null); - record.eachAttribute((keyName) => attributes[keyName] = get(record, keyName)); + record.eachAttribute(keyName => (attributes[keyName] = get(record, keyName))); } return attributes; @@ -131,7 +131,9 @@ export default class Snapshot { if (keyName in this._attributes) { return this._attributes[keyName]; } - throw new EmberError("Model '" + inspect(this.record) + "' has no attribute named '" + keyName + "' defined."); + throw new EmberError( + "Model '" + inspect(this.record) + "' has no attribute named '" + keyName + "' defined." + ); } /** @@ -169,7 +171,7 @@ export default class Snapshot { let changedAttributes = Object.create(null); let changedAttributeKeys = Object.keys(this._changedAttributes); - for (let i=0, length = changedAttributeKeys.length; i < length; i++) { + for (let i = 0, length = changedAttributeKeys.length; i < length; i++) { let key = changedAttributeKeys[i]; changedAttributes[key] = this._changedAttributes[key].slice(); } @@ -229,7 +231,13 @@ export default class Snapshot { let relationshipMeta = store._relationshipMetaFor(this.modelName, null, keyName); if (!(relationshipMeta && relationshipMeta.kind === 'belongsTo')) { - throw new EmberError("Model '" + inspect(this.record) + "' has no belongsTo relationship named '" + keyName + "' defined."); + throw new EmberError( + "Model '" + + inspect(this.record) + + "' has no belongsTo relationship named '" + + keyName + + "' defined." + ); } relationship = this._internalModel._modelData._relationships.get(keyName); @@ -305,7 +313,13 @@ export default class Snapshot { let store = this._internalModel.store; let relationshipMeta = store._relationshipMetaFor(this.modelName, null, keyName); if (!(relationshipMeta && relationshipMeta.kind === 'hasMany')) { - throw new EmberError("Model '" + inspect(this.record) + "' has no hasMany relationship named '" + keyName + "' defined."); + throw new EmberError( + "Model '" + + inspect(this.record) + + "' has no hasMany relationship named '" + + keyName + + "' defined." + ); } relationship = this._internalModel._modelData._relationships.get(keyName); @@ -314,7 +328,7 @@ export default class Snapshot { if (value.data) { results = []; - value.data.forEach((member) => { + value.data.forEach(member => { let internalModel = store._internalModelForResource(member); if (!internalModel.isDeleted()) { if (ids) { diff --git a/addon/-record-data-rfc-private/system/store.js b/addon/-record-data-rfc-private/system/store.js index 98d66becabf..f0bc6a7ff38 100644 --- a/addon/-record-data-rfc-private/system/store.js +++ b/addon/-record-data-rfc-private/system/store.js @@ -17,25 +17,22 @@ import { instrument } from 'ember-data/-debug'; import { assert, deprecate, warn, inspect } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; import Model from './model/model'; -import normalizeModelName from "./normalize-model-name"; +import normalizeModelName from './normalize-model-name'; import IdentityMap from './identity-map'; import ModelDataWrapper from './store/model-data-wrapper'; -import { - promiseArray, - promiseObject -} from "./promise-proxies"; +import { promiseArray, promiseObject } from './promise-proxies'; import { _bind, _guard, _objectIsAlive, guardDestroyedStore, - incrementRequestCount -} from "./store/common"; + incrementRequestCount, +} from './store/common'; -import { normalizeResponseHelper } from "./store/serializer-response"; -import { serializerForAdapter } from "./store/serializers"; +import { normalizeResponseHelper } from './store/serializer-response'; +import { serializerForAdapter } from './store/serializers'; import { _find, @@ -44,14 +41,14 @@ import { _findBelongsTo, _findAll, _query, - _queryRecord -} from "./store/finders"; + _queryRecord, +} from './store/finders'; import { getOwner } from '../utils'; -import coerceId from "./coerce-id"; -import RecordArrayManager from "./record-array-manager"; -import InternalModel from "./model/internal-model"; -import ModelData from "./model/model-data"; +import coerceId from './coerce-id'; +import RecordArrayManager from './record-array-manager'; +import InternalModel from './model/internal-model'; +import ModelData from './model/model-data'; import edBackburner from './backburner'; const badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; @@ -97,8 +94,9 @@ const { peekAll, peekRecord, serializerFor, - _internalModelsFor -} = heimdall.registerMonitor('store', + _internalModelsFor, +} = heimdall.registerMonitor( + 'store', '_generateId', '_internalModelForId', '_load', @@ -187,7 +185,6 @@ const { @extends Ember.Service */ Store = Service.extend({ - /** @method init @private @@ -219,9 +216,12 @@ Store = Service.extend({ // used for coalescing internal model updates this._updatedInternalModels = []; - // used to keep track of all the find requests that need to be coalesced - this._pendingFetch = new MapWithDefault({ defaultValue() { return []; } }); + this._pendingFetch = new MapWithDefault({ + defaultValue() { + return []; + }, + }); this._adapterCache = Object.create(null); this._serializerCache = Object.create(null); @@ -268,7 +268,10 @@ Store = Service.extend({ defaultAdapter: computed('adapter', function() { let adapter = get(this, 'adapter'); - assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name', typeof adapter === 'string'); + assert( + 'You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name', + typeof adapter === 'string' + ); return this.adapterFor(adapter); }), @@ -306,8 +309,14 @@ Store = Service.extend({ @return {DS.Model} record */ createRecord(modelName, inputProperties) { - assert(`You need to pass a model name to the store's createRecord method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `You need to pass a model name to the store's createRecord method`, + isPresent(modelName) + ); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); // This is wrapped in a `run.join` so that in test environments users do not need to manually wrap // calls to `createRecord`. The run loop usage here is because we batch the joining and updating @@ -421,12 +430,30 @@ Store = Service.extend({ // The default `model` hook in Route calls `find(modelName, id)`, // that's why we have to keep this method around even though `findRecord` is // the public way to get a record by modelName and id. - assert(`Using store.find(type) has been removed. Use store.findAll(modelName) to retrieve all records for a given type.`, arguments.length !== 1); - assert(`Calling store.find(modelName, id, { preload: preload }) is no longer supported. Use store.findRecord(modelName, id, { preload: preload }) instead.`, !options); - assert(`You need to pass the model name and id to the store's find method`, arguments.length === 2); - assert(`You cannot pass '${id}' as id to the store's find method`, typeof id === 'string' || typeof id === 'number'); - assert(`Calling store.find() with a query object is no longer supported. Use store.query() instead.`, typeof id !== 'object'); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Using store.find(type) has been removed. Use store.findAll(modelName) to retrieve all records for a given type.`, + arguments.length !== 1 + ); + assert( + `Calling store.find(modelName, id, { preload: preload }) is no longer supported. Use store.findRecord(modelName, id, { preload: preload }) instead.`, + !options + ); + assert( + `You need to pass the model name and id to the store's find method`, + arguments.length === 2 + ); + assert( + `You cannot pass '${id}' as id to the store's find method`, + typeof id === 'string' || typeof id === 'number' + ); + assert( + `Calling store.find() with a query object is no longer supported. Use store.query() instead.`, + typeof id !== 'object' + ); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); return this.findRecord(modelName, id); }, @@ -654,8 +681,14 @@ Store = Service.extend({ */ findRecord(modelName, id, options) { assert(`You need to pass a model name to the store's findRecord method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); - assert(badIdFormatAssertion, (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id))); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); + assert( + badIdFormatAssertion, + (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id)) + ); let normalizedModelName = normalizeModelName(modelName); @@ -668,7 +701,10 @@ Store = Service.extend({ let fetchedInternalModel = this._findRecord(internalModel, options); - return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${normalizedModelName} with id: ${id}`); + return promiseRecord( + fetchedInternalModel, + `DS: Store#findRecord ${normalizedModelName} with id: ${id}` + ); }, _findRecord(internalModel, options) { @@ -705,7 +741,10 @@ Store = Service.extend({ let fetchedInternalModel = this._findEmptyInternalModel(internalModel, options); - return promiseRecord(fetchedInternalModel, `DS: Store#findRecord ${internalModel.modelName} with id: ${internalModel.id}`); + return promiseRecord( + fetchedInternalModel, + `DS: Store#findRecord ${internalModel.modelName} with id: ${internalModel.id}` + ); }, _findEmptyInternalModel(internalModel, options) { @@ -733,7 +772,10 @@ Store = Service.extend({ */ findByIds(modelName, ids) { assert(`You need to pass a model name to the store's findByIds method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let promises = new Array(ids.length); @@ -743,7 +785,9 @@ Store = Service.extend({ promises[i] = this.findRecord(normalizedModelName, ids[i]); } - return promiseArray(RSVP.all(promises).then(A, null, `DS: Store#findByIds of ${normalizedModelName} complete`)); + return promiseArray( + RSVP.all(promises).then(A, null, `DS: Store#findByIds of ${normalizedModelName} complete`) + ); }, /** @@ -761,7 +805,10 @@ Store = Service.extend({ let adapter = this.adapterFor(modelName); assert(`You tried to find a record but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to find a record but your adapter (for ${modelName}) does not implement 'findRecord'`, typeof adapter.findRecord === 'function'); + assert( + `You tried to find a record but your adapter (for ${modelName}) does not implement 'findRecord'`, + typeof adapter.findRecord === 'function' + ); return _find(adapter, this, internalModel.type, internalModel.id, internalModel, options); }, @@ -786,7 +833,7 @@ Store = Service.extend({ let pendingFetchItem = { internalModel, resolver, - options + options, }; let promise = resolver.promise; @@ -841,7 +888,7 @@ Store = Service.extend({ let recordFetch = store._fetchRecord( recordResolverPair.internalModel, recordResolverPair.options - ); // TODO adapter options + ); // TODO adapter options recordResolverPair.resolver.resolve(recordFetch); } @@ -878,7 +925,7 @@ Store = Service.extend({ '" ]', false, { - id: 'ds.store.missing-records-from-adapter' + id: 'ds.store.missing-records-from-adapter', } ); rejectInternalModels(missingInternalModels); @@ -891,7 +938,12 @@ Store = Service.extend({ let pair = seeking[internalModel.id]; if (pair) { - pair.resolver.reject(error || new Error(`Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.`)); + pair.resolver.reject( + error || + new Error( + `Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.` + ) + ); } } } @@ -936,12 +988,15 @@ Store = Service.extend({ .catch(function(error) { rejectInternalModels(groupedInternalModels, error); }); - }(groupedInternalModels)); + })(groupedInternalModels); } else if (ids.length === 1) { var pair = seeking[groupedInternalModels[0].id]; _fetchRecord(pair); } else { - assert("You cannot return an empty array from adapter's method groupRecordsForFindMany", false); + assert( + "You cannot return an empty array from adapter's method groupRecordsForFindMany", + false + ); } } } else { @@ -1020,8 +1075,14 @@ Store = Service.extend({ peekRecord(modelName, id) { heimdall.increment(peekRecord); assert(`You need to pass a model name to the store's peekRecord method`, isPresent(modelName)); - assert(`You need to pass both a model name and id to the store's peekRecord method`, isPresent(modelName) && isPresent(id)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `You need to pass both a model name and id to the store's peekRecord method`, + isPresent(modelName) && isPresent(id) + ); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); if (this.hasRecordForId(normalizedModelName, id)) { @@ -1050,7 +1111,10 @@ Store = Service.extend({ assert(`You cannot reload a record without an ID`, id); assert(`You tried to reload a record but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to reload a record but your adapter does not implement 'findRecord'`, typeof adapter.findRecord === 'function' || typeof adapter.find === 'function'); + assert( + `You tried to reload a record but your adapter does not implement 'findRecord'`, + typeof adapter.findRecord === 'function' || typeof adapter.find === 'function' + ); return this._scheduleFetch(internalModel, options); }, @@ -1075,8 +1139,14 @@ Store = Service.extend({ @return {Boolean} */ hasRecordForId(modelName, id) { - assert(`You need to pass a model name to the store's hasRecordForId method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `You need to pass a model name to the store's hasRecordForId method`, + isPresent(modelName) + ); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); @@ -1098,12 +1168,14 @@ Store = Service.extend({ */ recordForId(modelName, id) { assert(`You need to pass a model name to the store's recordForId method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); return this._internalModelForId(modelName, id).getRecord(); }, - // directly get an internal model from ID map if it is there, without doing any // processing _getInternalModelForId(modelName, id, clientId) { @@ -1140,8 +1212,6 @@ Store = Service.extend({ return this._buildInternalModel(modelName, trueId, null, clientId); }, - - /** @method findMany @private @@ -1158,7 +1228,6 @@ Store = Service.extend({ return Promise.all(finds); }, - /** If a relationship was originally populated by the adapter as a link (as opposed to a list of IDs), this method is called when the @@ -1180,8 +1249,16 @@ Store = Service.extend({ findHasMany(internalModel, link, relationship) { let adapter = this.adapterFor(internalModel.modelName); - assert(`You tried to load a hasMany relationship but you have no adapter (for ${internalModel.modelName})`, adapter); - assert(`You tried to load a hasMany relationship from a specified 'link' in the original payload but your adapter does not implement 'findHasMany'`, typeof adapter.findHasMany === 'function'); + assert( + `You tried to load a hasMany relationship but you have no adapter (for ${ + internalModel.modelName + })`, + adapter + ); + assert( + `You tried to load a hasMany relationship from a specified 'link' in the original payload but your adapter does not implement 'findHasMany'`, + typeof adapter.findHasMany === 'function' + ); return _findHasMany(adapter, this, internalModel, link, relationship); }, @@ -1196,36 +1273,41 @@ Store = Service.extend({ hasRelatedResources, hasDematerializedInverse, hasAnyRelationshipData, - relationshipIsEmpty + relationshipIsEmpty, } = resource._relationship; - let shouldFindViaLink = resource.links && resource.links.related - && (hasDematerializedInverse || relationshipIsStale || + let shouldFindViaLink = + resource.links && + resource.links.related && + (hasDematerializedInverse || + relationshipIsStale || (!hasRelatedResources && !relationshipIsEmpty)); // fetch via link if (shouldFindViaLink) { - return this.findHasMany(parentInternalModel, resource.links.related, relationshipMeta).then(internalModels => { - let payload = { data: internalModels.map((im) => im._modelData.getResourceIdentifier()) }; - if (internalModels.meta !== undefined) { - payload.meta = internalModels.meta; + return this.findHasMany(parentInternalModel, resource.links.related, relationshipMeta).then( + internalModels => { + let payload = { data: internalModels.map(im => im._modelData.getResourceIdentifier()) }; + if (internalModels.meta !== undefined) { + payload.meta = internalModels.meta; + } + parentInternalModel.linkWasLoadedForRelationship(relationshipMeta.key, payload); + return internalModels; } - parentInternalModel.linkWasLoadedForRelationship(relationshipMeta.key, payload); - return internalModels; - }); + ); } - let preferLocalCache = hasAnyRelationshipData && + let preferLocalCache = + hasAnyRelationshipData && // hasRelatedResources && !relationshipIsEmpty; - let hasLocalPartialData = hasDematerializedInverse || - (relationshipIsEmpty && - Array.isArray(resource.data) && - resource.data.length > 0); + let hasLocalPartialData = + hasDematerializedInverse || + (relationshipIsEmpty && Array.isArray(resource.data) && resource.data.length > 0); // fetch using data, pulling from local cache if possible if (!relationshipIsStale && (preferLocalCache || hasLocalPartialData)) { - let internalModels = resource.data.map((json) => this._internalModelForResource(json)); + let internalModels = resource.data.map(json => this._internalModelForResource(json)); return this.findMany(internalModels); } @@ -1234,7 +1316,7 @@ Store = Service.extend({ // fetch by data if (hasData || hasLocalPartialData) { - let internalModels = resource.data.map((json) => this._internalModelForResource(json)); + let internalModels = resource.data.map(json => this._internalModelForResource(json)); return this._scheduleFetchMany(internalModels); } @@ -1247,12 +1329,11 @@ Store = Service.extend({ _getHasManyByJsonApiResource(resource) { let internalModels = []; if (resource && resource.data) { - internalModels = resource.data.map((reference) => this._internalModelForResource(reference)); + internalModels = resource.data.map(reference => this._internalModelForResource(reference)); } return internalModels; }, - /** @method findBelongsTo @private @@ -1264,8 +1345,16 @@ Store = Service.extend({ findBelongsTo(internalModel, link, relationship) { let adapter = this.adapterFor(internalModel.modelName); - assert(`You tried to load a belongsTo relationship but you have no adapter (for ${internalModel.modelName})`, adapter); - assert(`You tried to load a belongsTo relationship from a specified 'link' in the original payload but your adapter does not implement 'findBelongsTo'`, typeof adapter.findBelongsTo === 'function'); + assert( + `You tried to load a belongsTo relationship but you have no adapter (for ${ + internalModel.modelName + })`, + adapter + ); + assert( + `You tried to load a belongsTo relationship from a specified 'link' in the original payload but your adapter does not implement 'findBelongsTo'`, + typeof adapter.findBelongsTo === 'function' + ); return _findBelongsTo(adapter, this, internalModel, link, relationship); }, @@ -1275,15 +1364,17 @@ Store = Service.extend({ // should we warn here, not sure cause its an internal method return RSVP.resolve(null); } - return this.findBelongsTo(parentInternalModel, resource.links.related, relationshipMeta).then((internalModel) => { - let response = internalModel && internalModel._modelData.getResourceIdentifier(); - parentInternalModel.linkWasLoadedForRelationship(relationshipMeta.key, { data: response }); - if (internalModel === null) { - return null; + return this.findBelongsTo(parentInternalModel, resource.links.related, relationshipMeta).then( + internalModel => { + let response = internalModel && internalModel._modelData.getResourceIdentifier(); + parentInternalModel.linkWasLoadedForRelationship(relationshipMeta.key, { data: response }); + if (internalModel === null) { + return null; + } + // TODO Igor this doesn't seem like the right boundary, probably the caller method should extract the record out + return internalModel.getRecord(); } - // TODO Igor this doesn't seem like the right boundary, probably the caller method should extract the record out - return internalModel.getRecord(); - }); + ); }, _findBelongsToByJsonApiResource(resource, parentInternalModel, relationshipMeta) { @@ -1296,11 +1387,14 @@ Store = Service.extend({ hasRelatedResources, hasDematerializedInverse, hasAnyRelationshipData, - relationshipIsEmpty + relationshipIsEmpty, } = resource._relationship; - let shouldFindViaLink = resource.links && resource.links.related - && (hasDematerializedInverse || relationshipIsStale || + let shouldFindViaLink = + resource.links && + resource.links.related && + (hasDematerializedInverse || + relationshipIsStale || (!hasRelatedResources && !relationshipIsEmpty)); // fetch via link @@ -1308,11 +1402,8 @@ Store = Service.extend({ return this._fetchBelongsToLinkFromResource(resource, parentInternalModel, relationshipMeta); } - let preferLocalCache = hasAnyRelationshipData && - hasRelatedResources && - !relationshipIsEmpty; - let hasLocalPartialData = hasDematerializedInverse || - (relationshipIsEmpty && resource.data); + let preferLocalCache = hasAnyRelationshipData && hasRelatedResources && !relationshipIsEmpty; + let hasLocalPartialData = hasDematerializedInverse || (relationshipIsEmpty && resource.data); // fetch using data, pulling from local cache if possible if (!relationshipIsStale && (preferLocalCache || hasLocalPartialData)) { @@ -1345,7 +1436,6 @@ Store = Service.extend({ return RSVP.resolve(null); }, - /** This method delegates a query to the adapter. This is the one place where adapter-level semantics are exposed to the application. @@ -1402,12 +1492,15 @@ Store = Service.extend({ query(modelName, query, options) { assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); assert(`You need to pass a query hash to the store's query method`, query); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let adapterOptionsWrapper = {}; if (options && options.adapterOptions) { - adapterOptionsWrapper.adapterOptions = options.adapterOptions + adapterOptionsWrapper.adapterOptions = options.adapterOptions; } let normalizedModelName = normalizeModelName(modelName); @@ -1418,7 +1511,10 @@ Store = Service.extend({ let token = heimdall.start('store._query'); assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); assert(`You need to pass a query hash to the store's query method`, query); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let modelToken = heimdall.start('initial-modelFor-lookup'); heimdall.stop(modelToken); @@ -1428,11 +1524,16 @@ Store = Service.extend({ heimdall.stop(adapterToken); assert(`You tried to load a query but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to load a query but your adapter does not implement 'query'`, typeof adapter.query === 'function'); + assert( + `You tried to load a query but your adapter does not implement 'query'`, + typeof adapter.query === 'function' + ); let pA = promiseArray(_query(adapter, this, modelName, query, array, options)); instrument(() => { - pA.finally(() => { heimdall.stop(token); }); + pA.finally(() => { + heimdall.stop(token); + }); }); return pA; }, @@ -1537,28 +1638,39 @@ Store = Service.extend({ queryRecord(modelName, query, options) { assert(`You need to pass a model name to the store's queryRecord method`, isPresent(modelName)); assert(`You need to pass a query hash to the store's queryRecord method`, query); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); let adapter = this.adapterFor(normalizedModelName); let adapterOptionsWrapper = {}; if (options && options.adapterOptions) { - adapterOptionsWrapper.adapterOptions = options.adapterOptions + adapterOptionsWrapper.adapterOptions = options.adapterOptions; } - assert(`You tried to make a query but you have no adapter (for ${normalizedModelName})`, adapter); - assert(`You tried to make a query but your adapter does not implement 'queryRecord'`, typeof adapter.queryRecord === 'function'); + assert( + `You tried to make a query but you have no adapter (for ${normalizedModelName})`, + adapter + ); + assert( + `You tried to make a query but your adapter does not implement 'queryRecord'`, + typeof adapter.queryRecord === 'function' + ); - return promiseObject(_queryRecord(adapter, this, modelName, query, adapterOptionsWrapper).then(internalModel => { - // the promise returned by store.queryRecord is expected to resolve with - // an instance of DS.Model - if (internalModel) { - return internalModel.getRecord(); - } + return promiseObject( + _queryRecord(adapter, this, modelName, query, adapterOptionsWrapper).then(internalModel => { + // the promise returned by store.queryRecord is expected to resolve with + // an instance of DS.Model + if (internalModel) { + return internalModel.getRecord(); + } - return null; - })); + return null; + }) + ); }, /** @@ -1751,14 +1863,19 @@ Store = Service.extend({ */ findAll(modelName, options) { assert(`You need to pass a model name to the store's findAll method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let token = heimdall.start('store.findAll'); let normalizedModelName = normalizeModelName(modelName); let fetch = this._fetchAll(normalizedModelName, this.peekAll(normalizedModelName), options); instrument(() => { - fetch.finally(() => { heimdall.stop(token); }); + fetch.finally(() => { + heimdall.stop(token); + }); }); return fetch; @@ -1776,7 +1893,10 @@ Store = Service.extend({ let sinceToken = this._internalModelsFor(modelName).metadata.since; assert(`You tried to load all records but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to load all records but your adapter does not implement 'findAll'`, typeof adapter.findAll === 'function'); + assert( + `You tried to load all records but your adapter does not implement 'findAll'`, + typeof adapter.findAll === 'function' + ); if (options.reload) { set(array, 'isUpdating', true); @@ -1839,7 +1959,10 @@ Store = Service.extend({ peekAll(modelName) { heimdall.increment(peekAll); assert(`You need to pass a model name to the store's peekAll method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); return this.recordArrayManager.liveRecordArrayFor(normalizedModelName); }, @@ -1859,7 +1982,10 @@ Store = Service.extend({ @param {String} modelName */ unloadAll(modelName) { - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, !modelName || typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + !modelName || typeof modelName === 'string' + ); if (arguments.length === 0) { this._identityMap.clear(); @@ -1870,7 +1996,10 @@ Store = Service.extend({ }, filter() { - assert('The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', false); + assert( + 'The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', + false + ); }, // .............. @@ -1894,7 +2023,7 @@ Store = Service.extend({ internalModel.adapterWillCommit(); this._pendingSave.push({ snapshot: snapshot, - resolver: resolver + resolver: resolver, }); emberRun.once(this, this.flushPendingSave); }, @@ -1931,7 +2060,6 @@ Store = Service.extend({ resolver.resolve(_commit(adapter, this, operation, snapshot)); } - }, /** @@ -1953,7 +2081,12 @@ Store = Service.extend({ data = dataArg.data; } if (!data) { - assert(`Your ${internalModel.modelName} record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, internalModel.id); + assert( + `Your ${ + internalModel.modelName + } record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, + internalModel.id + ); } //We first make sure the primary data has been updated @@ -2008,7 +2141,7 @@ Store = Service.extend({ updateId(internalModel, data) { deprecate('store.updateId was documented as private and will be removed.', false, { id: 'ds.store.updateId', - until: '3.5' + until: '3.5', }); this._setRecordId(internalModel, coerceId(data.id)); }, @@ -2018,22 +2151,33 @@ Store = Service.extend({ let modelName = internalModel.modelName; // ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record) - assert(`'${modelName}' was saved to the server, but the response does not have an id and your record does not either.`, !(id === null && oldId === null)); + assert( + `'${modelName}' was saved to the server, but the response does not have an id and your record does not either.`, + !(id === null && oldId === null) + ); // ID absolutely can't be different than oldID if oldID is not null - assert(`'${modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, !(oldId !== null && id !== oldId)); + assert( + `'${modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, + !(oldId !== null && id !== oldId) + ); // ID can be null if oldID is not null (altered ID in response for a record) // however, this is more than likely a developer error. if (oldId !== null && id === null) { - warn(`Your ${modelName} record was saved to the server, but the response does not have an id.`, !(oldId !== null && id === null)); + warn( + `Your ${modelName} record was saved to the server, but the response does not have an id.`, + !(oldId !== null && id === null) + ); return; } let existingInternalModel = this._existingInternalModelForId(modelName, id); - assert(`'${modelName}' was saved to the server, but the response returned the new id '${id}', which has already been used with another record.'`, - isNone(existingInternalModel) || existingInternalModel === internalModel); + assert( + `'${modelName}' was saved to the server, but the response returned the new id '${id}', which has already been used with another record.'`, + isNone(existingInternalModel) || existingInternalModel === internalModel + ); this._internalModelsFor(internalModel.modelName).set(id, internalModel); this._newlyCreatedModelsFor(internalModel.modelName).remove(internalModel, clientId); @@ -2097,11 +2241,17 @@ Store = Service.extend({ false, { id: 'ember-data:_modelForMixin', - until: '3.5' + until: '3.5', } ); - assert(`You need to pass a model name to the store's _modelForMixin method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `You need to pass a model name to the store's _modelForMixin method`, + isPresent(modelName) + ); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); return _modelForMixin(this, normalizedModelName); @@ -2121,7 +2271,10 @@ Store = Service.extend({ */ modelFor(modelName) { assert(`You need to pass a model name to the store's modelFor method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let maybeFactory = this._modelFactoryFor(modelName); @@ -2134,20 +2287,22 @@ Store = Service.extend({ @private */ _modelFor(modelName) { - deprecate( - '_modelFor is private and deprecated, you should use modelFor instead', - false, - { - id: 'ember-data:_modelFor', - until: '3.5' - } - ); + deprecate('_modelFor is private and deprecated, you should use modelFor instead', false, { + id: 'ember-data:_modelFor', + until: '3.5', + }); return this.modelFor(modelName); }, _modelFactoryFor(modelName) { - assert(`You need to pass a model name to the store's _modelFactoryFor method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `You need to pass a model name to the store's _modelFactoryFor method`, + isPresent(modelName) + ); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); let factory = getModelFactory(this, this._modelFactoryCache, normalizedModelName); @@ -2165,7 +2320,7 @@ Store = Service.extend({ modelFactoryFor(modelName) { deprecate('modelFactoryFor is private and deprecated', false, { id: 'ember-data:modelFactoryFor', - until: '3.5' + until: '3.5', }); return this._modelFactoryFor(modelName); }, @@ -2183,7 +2338,10 @@ Store = Service.extend({ */ _hasModelFor(modelName) { assert(`You need to pass a model name to the store's hasModelFor method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); let factory = getModelFactory(this, this._modelFactoryCache, normalizedModelName); @@ -2395,7 +2553,12 @@ Store = Service.extend({ return null; } - assert(`Expected an object in the 'data' property in a call to 'push' for ${jsonApiDoc.type}, but was ${typeOf(jsonApiDoc.data)}`, typeOf(jsonApiDoc.data) === 'object'); + assert( + `Expected an object in the 'data' property in a call to 'push' for ${ + jsonApiDoc.type + }, but was ${typeOf(jsonApiDoc.data)}`, + typeOf(jsonApiDoc.data) === 'object' + ); return this._pushInternalModel(jsonApiDoc.data); }); @@ -2406,8 +2569,14 @@ Store = Service.extend({ _pushInternalModel(data) { heimdall.increment(_pushInternalModel); let modelName = data.type; - assert(`You must include an 'id' for ${modelName} in an object passed to 'push'`, data.id !== null && data.id !== undefined && data.id !== ''); - assert(`You tried to push data with a type '${modelName}' but no model could be found with that name.`, this._hasModelFor(modelName)); + assert( + `You must include an 'id' for ${modelName} in an object passed to 'push'`, + data.id !== null && data.id !== undefined && data.id !== '' + ); + assert( + `You tried to push data with a type '${modelName}' but no model could be found with that name.`, + this._hasModelFor(modelName) + ); if (DEBUG) { // If ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload @@ -2417,25 +2586,29 @@ Store = Service.extend({ let modelClass = this.modelFor(modelName); // Check unknown attributes - let unknownAttributes = Object.keys(data.attributes || {}).filter((key) => { + let unknownAttributes = Object.keys(data.attributes || {}).filter(key => { return !get(modelClass, 'fields').has(key); }); let unknownAttributesMessage = `The payload for '${modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`; - warn(unknownAttributesMessage, unknownAttributes.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); + warn(unknownAttributesMessage, unknownAttributes.length === 0, { + id: 'ds.store.unknown-keys-in-payload', + }); // Check unknown relationships - let unknownRelationships = Object.keys(data.relationships || {}).filter((key) => { + let unknownRelationships = Object.keys(data.relationships || {}).filter(key => { return !get(modelClass, 'fields').has(key); }); let unknownRelationshipsMessage = `The payload for '${modelName}' contains these unknown relationships: ${unknownRelationships}. Make sure they've been defined in your model.`; - warn(unknownRelationshipsMessage, unknownRelationships.length === 0, { id: 'ds.store.unknown-keys-in-payload' }); + warn(unknownRelationshipsMessage, unknownRelationships.length === 0, { + id: 'ds.store.unknown-keys-in-payload', + }); } } // Actually load the record into the store. let internalModel = this._load(data); -// this._setupRelationshipsForModel(internalModel, data); + // this._setupRelationshipsForModel(internalModel, data); return internalModel; }, @@ -2501,10 +2674,16 @@ Store = Service.extend({ if (!inputPayload) { payload = modelName; serializer = defaultSerializer(this); - assert(`You cannot use 'store#pushPayload' without a modelName unless your default serializer defines 'pushPayload'`, typeof serializer.pushPayload === 'function'); + assert( + `You cannot use 'store#pushPayload' without a modelName unless your default serializer defines 'pushPayload'`, + typeof serializer.pushPayload === 'function' + ); } else { payload = inputPayload; - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); serializer = this.serializerFor(normalizedModelName); } @@ -2516,7 +2695,7 @@ Store = Service.extend({ }, reloadBelongsTo(belongsToProxy, internalModel, key) { - return internalModel.reloadBelongsTo(key) + return internalModel.reloadBelongsTo(key); }, _relationshipMetaFor(modelName, id, key) { @@ -2575,7 +2754,12 @@ Store = Service.extend({ normalize(modelName, payload) { heimdall.increment(normalize); assert(`You need to pass a model name to the store's normalize method`, isPresent(modelName)); - assert(`Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect(modelName)}`, typeof modelName === 'string'); + assert( + `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect( + modelName + )}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); let serializer = this.serializerFor(normalizedModelName); let model = this.modelFor(normalizedModelName); @@ -2599,11 +2783,17 @@ Store = Service.extend({ _buildInternalModel(modelName, id, data, clientId) { heimdall.increment(_buildInternalModel); - assert(`You can no longer pass a modelClass as the first argument to store._buildInternalModel. Pass modelName instead.`, typeof modelName === 'string'); + assert( + `You can no longer pass a modelClass as the first argument to store._buildInternalModel. Pass modelName instead.`, + typeof modelName === 'string' + ); let existingInternalModel = this._existingInternalModelForId(modelName, id); - assert(`The id ${id} has already been used with another record for modelClass '${modelName}'.`, !existingInternalModel); + assert( + `The id ${id} has already been used with another record for modelClass '${modelName}'.`, + !existingInternalModel + ); if (id === null && !clientId) { clientId = this.newClientId(); @@ -2685,12 +2875,17 @@ Store = Service.extend({ adapterFor(modelName) { heimdall.increment(adapterFor); assert(`You need to pass a model name to the store's adapterFor method`, isPresent(modelName)); - assert(`Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); let { _adapterCache } = this; let adapter = _adapterCache[normalizedModelName]; - if (adapter) { return adapter; } + if (adapter) { + return adapter; + } let owner = getOwner(this); @@ -2757,13 +2952,21 @@ Store = Service.extend({ */ serializerFor(modelName) { heimdall.increment(serializerFor); - assert(`You need to pass a model name to the store's serializerFor method`, isPresent(modelName)); - assert(`Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${modelName}`, typeof modelName === 'string'); + assert( + `You need to pass a model name to the store's serializerFor method`, + isPresent(modelName) + ); + assert( + `Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${modelName}`, + typeof modelName === 'string' + ); let normalizedModelName = normalizeModelName(modelName); let { _serializerCache } = this; let serializer = _serializerCache[normalizedModelName]; - if (serializer) { return serializer; } + if (serializer) { + return serializer; + } let owner = getOwner(this); @@ -2859,7 +3062,16 @@ Store = Service.extend({ return; } - assert(`A ${relationship.internalModel.modelName} record was pushed into the store with the value of ${relationship.key} being ${inspect(resourceIdentifier)}, but ${relationship.key} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(resourceIdentifier)); + assert( + `A ${ + relationship.internalModel.modelName + } record was pushed into the store with the value of ${relationship.key} being ${inspect( + resourceIdentifier + )}, but ${ + relationship.key + } is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, + !Array.isArray(resourceIdentifier) + ); //TODO:Better asserts return this._internalModelForId(resourceIdentifier.type, resourceIdentifier.id); @@ -2870,20 +3082,27 @@ Store = Service.extend({ return; } - assert(`A ${relationship.internalModel.modelName} record was pushed into the store with the value of ${relationship.key} being '${inspect(resourceIdentifiers)}', but ${relationship.key} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(resourceIdentifiers)); + assert( + `A ${ + relationship.internalModel.modelName + } record was pushed into the store with the value of ${relationship.key} being '${inspect( + resourceIdentifiers + )}', but ${ + relationship.key + } is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, + Array.isArray(resourceIdentifiers) + ); let _internalModels = new Array(resourceIdentifiers.length); for (let i = 0; i < resourceIdentifiers.length; i++) { _internalModels[i] = this._pushResourceIdentifier(relationship, resourceIdentifiers[i]); } return _internalModels; - } + }, }); // Delegation to the adapter and promise management - - function defaultSerializer(store) { return store.serializerFor('application'); } @@ -2893,21 +3112,30 @@ function _commit(adapter, store, operation, snapshot) { let modelName = snapshot.modelName; let modelClass = store.modelFor(modelName); assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter); - assert(`You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`, typeof adapter[operation] === 'function'); + assert( + `You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`, + typeof adapter[operation] === 'function' + ); - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let promise = Promise.resolve().then(() => adapter[operation](store, modelClass, snapshot)); let serializer = serializerForAdapter(store, adapter, modelName); let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; - assert(`Your adapter's '${operation}' method must return a value, but it returned 'undefined'`, promise !==undefined); + assert( + `Your adapter's '${operation}' method must return a value, but it returned 'undefined'`, + promise !== undefined + ); promise = guardDestroyedStore(promise, store, label); promise = _guard(promise, _bind(_objectIsAlive, internalModel)); - return promise.then((adapterPayload) => { - /* + return promise.then( + adapterPayload => { + /* Note to future spelunkers hoping to optimize. We rely on this `run` to create a run loop if needed that `store._push` and `store.didSaveRecord` will both share. @@ -2916,34 +3144,44 @@ function _commit(adapter, store, operation, snapshot) { have an outer run loop available still from the first call to `store._push`; */ - store._backburner.join(() => { - let payload, data, sideloaded; - if (adapterPayload) { - payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, snapshot.id, operation); - if (payload.included) { - sideloaded = payload.included; + store._backburner.join(() => { + let payload, data, sideloaded; + if (adapterPayload) { + payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + snapshot.id, + operation + ); + if (payload.included) { + sideloaded = payload.included; + } + data = payload.data; } - data = payload.data; - } - store.didSaveRecord(internalModel, { data }); - // seems risky, but if the tests pass might be fine? - if (sideloaded) { - store._push({ data: null, included: sideloaded }); - } - }); + store.didSaveRecord(internalModel, { data }); + // seems risky, but if the tests pass might be fine? + if (sideloaded) { + store._push({ data: null, included: sideloaded }); + } + }); - return internalModel; - }, function(error) { - if (error instanceof InvalidError) { - let errors = serializer.extractErrors(store, modelClass, error, snapshot.id); + return internalModel; + }, + function(error) { + if (error instanceof InvalidError) { + let errors = serializer.extractErrors(store, modelClass, error, snapshot.id); - store.recordWasInvalid(internalModel, errors); - } else { - store.recordWasError(internalModel, error); - } + store.recordWasInvalid(internalModel, errors); + } else { + store.recordWasError(internalModel, error); + } - throw error; - }, label); + throw error; + }, + label + ); } /** @@ -2995,7 +3233,6 @@ function _lookupModelFactory(store, normalizedModelName) { } } - /* In case someone defined a relationship to a mixin, for example: ``` @@ -3029,7 +3266,7 @@ function _modelForMixin(store, normalizedModelName) { let ModelForMixin = Model.extend(mixin); ModelForMixin.reopenClass({ __isMixin: true, - __mixin: mixin + __mixin: mixin, }); //Cache the class as a model diff --git a/addon/-record-data-rfc-private/system/store/common.js b/addon/-record-data-rfc-private/system/store/common.js index 007671f5114..c095fe701c8 100644 --- a/addon/-record-data-rfc-private/system/store/common.js +++ b/addon/-record-data-rfc-private/system/store/common.js @@ -3,11 +3,8 @@ import { DEBUG } from '@glimmer/env'; import Ember from 'ember'; import { Promise } from 'rsvp'; -const { - __bind, - __guard, - __objectIsAlive -} = heimdall.registerMonitor('system.store.common', +const { __bind, __guard, __objectIsAlive } = heimdall.registerMonitor( + 'system.store.common', '_bind', '_guard', '_objectIsAlive' @@ -34,7 +31,7 @@ export function _guard(promise, test) { export function _objectIsAlive(object) { heimdall.increment(__objectIsAlive); - return !(get(object, "isDestroyed") || get(object, "isDestroying")); + return !(get(object, 'isDestroyed') || get(object, 'isDestroying')); } let ASYNC_REQUEST_COUNT = 0; @@ -51,5 +48,10 @@ if (DEBUG) { export function guardDestroyedStore(promise, store, label) { promise = Promise.resolve(promise, label); - return _guard(promise, () => { if (DEBUG) { ASYNC_REQUEST_COUNT--; } return _objectIsAlive(store); }); + return _guard(promise, () => { + if (DEBUG) { + ASYNC_REQUEST_COUNT--; + } + return _objectIsAlive(store); + }); } diff --git a/addon/-record-data-rfc-private/system/store/finders.js b/addon/-record-data-rfc-private/system/store/finders.js index d9923eaf29a..1709a79cb39 100644 --- a/addon/-record-data-rfc-private/system/store/finders.js +++ b/addon/-record-data-rfc-private/system/store/finders.js @@ -8,11 +8,11 @@ import { _guard, _objectIsAlive, guardDestroyedStore, - incrementRequestCount -} from "./common"; + incrementRequestCount, +} from './common'; -import { normalizeResponseHelper } from "./serializer-response"; -import { serializerForAdapter } from "./serializers"; +import { normalizeResponseHelper } from './serializer-response'; +import { serializerForAdapter } from './serializers'; function payloadIsNotBlank(adapterPayload) { if (Array.isArray(adapterPayload)) { @@ -23,7 +23,9 @@ function payloadIsNotBlank(adapterPayload) { } export function _find(adapter, store, modelClass, id, internalModel, options) { - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let snapshot = internalModel.createSnapshot(options); let { modelName } = internalModel; let promise = Promise.resolve().then(() => adapter.findRecord(store, modelClass, id, snapshot)); @@ -31,29 +33,54 @@ export function _find(adapter, store, modelClass, id, internalModel, options) { promise = guardDestroyedStore(promise, store, label); - return promise.then(adapterPayload => { - assert(`You made a 'findRecord' request for a '${modelName}' with id '${id}', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, id, 'findRecord'); - assert(`Ember Data expected the primary data returned from a 'findRecord' response to be an object but instead it found an array.`, !Array.isArray(payload.data)); - - warn(`You requested a record of type '${modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${payload.data.id}'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead https://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, payload.data.id === id, { - id: 'ds.store.findRecord.id-mismatch' - }); - - return store._push(payload); - }, error => { - internalModel.notFound(); - if (internalModel.isEmpty()) { - internalModel.unloadRecord(); - } - - throw error; - }, `DS: Extract payload of '${modelName}'`); + return promise.then( + adapterPayload => { + assert( + `You made a 'findRecord' request for a '${modelName}' with id '${id}', but the adapter's response did not have any data`, + payloadIsNotBlank(adapterPayload) + ); + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + id, + 'findRecord' + ); + assert( + `Ember Data expected the primary data returned from a 'findRecord' response to be an object but instead it found an array.`, + !Array.isArray(payload.data) + ); + + warn( + `You requested a record of type '${modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${ + payload.data.id + }'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead https://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, + payload.data.id === id, + { + id: 'ds.store.findRecord.id-mismatch', + } + ); + + return store._push(payload); + }, + error => { + internalModel.notFound(); + if (internalModel.isEmpty()) { + internalModel.unloadRecord(); + } + + throw error; + }, + `DS: Extract payload of '${modelName}'` + ); } export function _findMany(adapter, store, modelName, ids, internalModels) { - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let snapshots = A(internalModels).invoke('createSnapshot'); let modelClass = store.modelFor(modelName); // `adapter.findMany` gets the modelClass still let promise = adapter.findMany(store, modelClass, ids, snapshots); @@ -65,90 +92,163 @@ export function _findMany(adapter, store, modelName, ids, internalModels) { promise = guardDestroyedStore(promise, store, label); - return promise.then(adapterPayload => { - assert(`You made a 'findMany' request for '${modelName}' records with ids '[${ids}]', but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findMany'); - return store._push(payload); - }, null, `DS: Extract payload of ${modelName}`); + return promise.then( + adapterPayload => { + assert( + `You made a 'findMany' request for '${modelName}' records with ids '[${ids}]', but the adapter's response did not have any data`, + payloadIsNotBlank(adapterPayload) + ); + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + null, + 'findMany' + ); + return store._push(payload); + }, + null, + `DS: Extract payload of ${modelName}` + ); } export function _findHasMany(adapter, store, internalModel, link, relationship) { - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let snapshot = internalModel.createSnapshot(); let modelClass = store.modelFor(relationship.type); let promise = adapter.findHasMany(store, snapshot, link, relationship); - let label = `DS: Handle Adapter#findHasMany of '${internalModel.modelName}' : '${relationship.type}'`; + let label = `DS: Handle Adapter#findHasMany of '${internalModel.modelName}' : '${ + relationship.type + }'`; promise = guardDestroyedStore(promise, store, label); promise = _guard(promise, _bind(_objectIsAlive, internalModel)); - return promise.then(adapterPayload => { - assert(`You made a 'findHasMany' request for a ${internalModel.modelName}'s '${relationship.key}' relationship, using link '${link}' , but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); - let serializer = serializerForAdapter(store, adapter, relationship.type); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findHasMany'); - let internalModelArray = store._push(payload); - - internalModelArray.meta = payload.meta; - return internalModelArray; - }, null, `DS: Extract payload of '${internalModel.modelName}' : hasMany '${relationship.type}'`); + return promise.then( + adapterPayload => { + assert( + `You made a 'findHasMany' request for a ${internalModel.modelName}'s '${ + relationship.key + }' relationship, using link '${link}' , but the adapter's response did not have any data`, + payloadIsNotBlank(adapterPayload) + ); + let serializer = serializerForAdapter(store, adapter, relationship.type); + let payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + null, + 'findHasMany' + ); + let internalModelArray = store._push(payload); + + internalModelArray.meta = payload.meta; + return internalModelArray; + }, + null, + `DS: Extract payload of '${internalModel.modelName}' : hasMany '${relationship.type}'` + ); } export function _findBelongsTo(adapter, store, internalModel, link, relationship) { - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let snapshot = internalModel.createSnapshot(); let modelClass = store.modelFor(relationship.type); let promise = adapter.findBelongsTo(store, snapshot, link, relationship); - let label = `DS: Handle Adapter#findBelongsTo of ${internalModel.modelName} : ${relationship.type}`; + let label = `DS: Handle Adapter#findBelongsTo of ${internalModel.modelName} : ${ + relationship.type + }`; promise = guardDestroyedStore(promise, store, label); promise = _guard(promise, _bind(_objectIsAlive, internalModel)); - return promise.then(adapterPayload => { - let serializer = serializerForAdapter(store, adapter, relationship.type); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findBelongsTo'); - - if (!payload.data) { - return null; - } - - return store._push(payload); - }, null, `DS: Extract payload of ${internalModel.modelName} : ${relationship.type}`); + return promise.then( + adapterPayload => { + let serializer = serializerForAdapter(store, adapter, relationship.type); + let payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + null, + 'findBelongsTo' + ); + + if (!payload.data) { + return null; + } + + return store._push(payload); + }, + null, + `DS: Extract payload of ${internalModel.modelName} : ${relationship.type}` + ); } export function _findAll(adapter, store, modelName, sinceToken, options) { - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let modelClass = store.modelFor(modelName); // adapter.findAll depends on the class let recordArray = store.peekAll(modelName); let snapshotArray = recordArray._createSnapshot(options); - let promise = Promise.resolve().then(() => adapter.findAll(store, modelClass, sinceToken, snapshotArray)); - let label = "DS: Handle Adapter#findAll of " + modelClass; + let promise = Promise.resolve().then(() => + adapter.findAll(store, modelClass, sinceToken, snapshotArray) + ); + let label = 'DS: Handle Adapter#findAll of ' + modelClass; promise = guardDestroyedStore(promise, store, label); - return promise.then(adapterPayload => { - assert(`You made a 'findAll' request for '${modelName}' records, but the adapter's response did not have any data`, payloadIsNotBlank(adapterPayload)); - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'findAll'); - - store._push(payload); - store._didUpdateAll(modelName); - - return recordArray; - }, null, 'DS: Extract payload of findAll ${modelName}'); + return promise.then( + adapterPayload => { + assert( + `You made a 'findAll' request for '${modelName}' records, but the adapter's response did not have any data`, + payloadIsNotBlank(adapterPayload) + ); + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + null, + 'findAll' + ); + + store._push(payload); + store._didUpdateAll(modelName); + + return recordArray; + }, + null, + 'DS: Extract payload of findAll ${modelName}' + ); } export function _query(adapter, store, modelName, query, recordArray, options) { - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let modelClass = store.modelFor(modelName); // adapter.query needs the class let promise; - let createRecordArray = adapter.query.length > 3 || + let createRecordArray = + adapter.query.length > 3 || (adapter.query.wrappedFunction && adapter.query.wrappedFunction.length > 3); if (createRecordArray) { - recordArray = recordArray || store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); - promise = Promise.resolve().then(() => adapter.query(store, modelClass, query, recordArray, options)); + recordArray = + recordArray || store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); + promise = Promise.resolve().then(() => + adapter.query(store, modelClass, query, recordArray, options) + ); } else { promise = Promise.resolve().then(() => adapter.query(store, modelClass, query)); } @@ -156,42 +256,80 @@ export function _query(adapter, store, modelName, query, recordArray, options) { let label = `DS: Handle Adapter#query of ${modelName}`; promise = guardDestroyedStore(promise, store, label); - return promise.then(adapterPayload => { - let serializerToken = heimdall.start('initial-serializerFor-lookup'); - let serializer = serializerForAdapter(store, adapter, modelName); - heimdall.stop(serializerToken); - let normalizeToken = heimdall.start('finders#_query::normalizeResponseHelper'); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'query'); - heimdall.stop(normalizeToken); - let internalModels = store._push(payload); - - assert('The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', Array.isArray(internalModels)); - if (recordArray) { - recordArray._setInternalModels(internalModels, payload); - } else { - recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query, internalModels, payload); - } - - return recordArray; - }, null, `DS: Extract payload of query ${modelName}`); + return promise.then( + adapterPayload => { + let serializerToken = heimdall.start('initial-serializerFor-lookup'); + let serializer = serializerForAdapter(store, adapter, modelName); + heimdall.stop(serializerToken); + let normalizeToken = heimdall.start('finders#_query::normalizeResponseHelper'); + let payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + null, + 'query' + ); + heimdall.stop(normalizeToken); + let internalModels = store._push(payload); + + assert( + 'The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', + Array.isArray(internalModels) + ); + if (recordArray) { + recordArray._setInternalModels(internalModels, payload); + } else { + recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray( + modelName, + query, + internalModels, + payload + ); + } + + return recordArray; + }, + null, + `DS: Extract payload of query ${modelName}` + ); } export function _queryRecord(adapter, store, modelName, query, options) { - if (DEBUG) { incrementRequestCount(); } + if (DEBUG) { + incrementRequestCount(); + } let modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class - let promise = Promise.resolve().then(() => adapter.queryRecord(store, modelClass, query, options)); + let promise = Promise.resolve().then(() => + adapter.queryRecord(store, modelClass, query, options) + ); let label = `DS: Handle Adapter#queryRecord of ${modelName}`; promise = guardDestroyedStore(promise, store, label); - return promise.then(adapterPayload => { - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper(serializer, store, modelClass, adapterPayload, null, 'queryRecord'); - - assert(`Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array.`, !Array.isArray(payload.data), { - id: 'ds.store.queryRecord-array-response' - }); - - return store._push(payload); - }, null, `DS: Extract payload of queryRecord ${modelName}`); + return promise.then( + adapterPayload => { + let serializer = serializerForAdapter(store, adapter, modelName); + let payload = normalizeResponseHelper( + serializer, + store, + modelClass, + adapterPayload, + null, + 'queryRecord' + ); + + assert( + `Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array.`, + !Array.isArray(payload.data), + { + id: 'ds.store.queryRecord-array-response', + } + ); + + return store._push(payload); + }, + null, + `DS: Extract payload of queryRecord ${modelName}` + ); } diff --git a/addon/-record-data-rfc-private/system/store/model-data-wrapper.js b/addon/-record-data-rfc-private/system/store/model-data-wrapper.js index 46411b95eb0..0ddb9cf94aa 100644 --- a/addon/-record-data-rfc-private/system/store/model-data-wrapper.js +++ b/addon/-record-data-rfc-private/system/store/model-data-wrapper.js @@ -10,7 +10,7 @@ export default class ModelDataWrapper { } _scheduleManyArrayUpdate(modelName, id, clientId, key) { - let pending = this._pendingManyArrayUpdates = this._pendingManyArrayUpdates || []; + let pending = (this._pendingManyArrayUpdates = this._pendingManyArrayUpdates || []); pending.push(modelName, id, clientId, key); if (this._willUpdateManyArrays === true) { @@ -100,7 +100,7 @@ export default class ModelDataWrapper { isRecordInUse(modelName, id, clientId) { let internalModel = this.store._getInternalModelForId(modelName, id, clientId); if (!internalModel) { - return false + return false; } return internalModel.isRecordInUse(); } @@ -111,5 +111,4 @@ export default class ModelDataWrapper { internalModel.destroyFromModelData(); } } - } diff --git a/addon/-record-data-rfc-private/system/store/serializer-response.js b/addon/-record-data-rfc-private/system/store/serializer-response.js index 155b13d0617..c4a08c6b5cf 100644 --- a/addon/-record-data-rfc-private/system/store/serializer-response.js +++ b/addon/-record-data-rfc-private/system/store/serializer-response.js @@ -16,13 +16,13 @@ export function validateDocumentStructure(doc) { if (!doc || typeof doc !== 'object') { errors.push('Top level of a JSON API document must be an object'); } else { - if (!('data' in doc) && - !('errors' in doc) && - !('meta' in doc)) { + if (!('data' in doc) && !('errors' in doc) && !('meta' in doc)) { errors.push('One or more of the following keys must be present: "data", "errors", "meta".'); } else { - if (('data' in doc) && ('errors' in doc)) { - errors.push('Top level keys "errors" and "data" cannot both be present in a JSON API document'); + if ('data' in doc && 'errors' in doc) { + errors.push( + 'Top level keys "errors" and "data" cannot both be present in a JSON API document' + ); } } if ('data' in doc) { @@ -73,12 +73,23 @@ export function validateDocumentStructure(doc) { @return {Object} JSON-API Document */ export function normalizeResponseHelper(serializer, store, modelClass, payload, id, requestType) { - let normalizedResponse = serializer.normalizeResponse(store, modelClass, payload, id, requestType); + let normalizedResponse = serializer.normalizeResponse( + store, + modelClass, + payload, + id, + requestType + ); let validationErrors = []; if (DEBUG) { validationErrors = validateDocumentStructure(normalizedResponse); } - assert(`normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join('\n\t* ')}`, validationErrors.length === 0); + assert( + `normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join( + '\n\t* ' + )}`, + validationErrors.length === 0 + ); return normalizedResponse; } diff --git a/addon/-record-data-rfc-private/system/store/serializers.js b/addon/-record-data-rfc-private/system/store/serializers.js index 71ca0829809..d6788427061 100644 --- a/addon/-record-data-rfc-private/system/store/serializers.js +++ b/addon/-record-data-rfc-private/system/store/serializers.js @@ -7,7 +7,9 @@ export function serializerForAdapter(store, adapter, modelName) { if (serializer === null || serializer === undefined) { serializer = { - extract(store, type, payload) { return payload; } + extract(store, type, payload) { + return payload; + }, }; } diff --git a/addon/-record-data-rfc-private/utils.js b/addon/-record-data-rfc-private/utils.js index 234af6842fa..f3bd4ed6aaf 100644 --- a/addon/-record-data-rfc-private/utils.js +++ b/addon/-record-data-rfc-private/utils.js @@ -8,7 +8,9 @@ import { get } from '@ember/object'; @param modelClass */ function modelHasAttributeOrRelationshipNamedType(modelClass) { - return get(modelClass, 'attributes').has('type') || get(modelClass, 'relationshipsByName').has('type'); + return ( + get(modelClass, 'attributes').has('type') || get(modelClass, 'relationshipsByName').has('type') + ); } /* @@ -29,7 +31,7 @@ function getOwner(context) { // `owner` is a container, we are just making this work owner._lookupFactory = function() { return owner.lookupFactory(...arguments); - } + }; owner.register = function() { let registry = owner.registry || owner._registry || owner; @@ -41,7 +43,4 @@ function getOwner(context) { return owner; } -export { - modelHasAttributeOrRelationshipNamedType, - getOwner -}; +export { modelHasAttributeOrRelationshipNamedType, getOwner }; diff --git a/addon/adapter.js b/addon/adapter.js index ed121c640dd..fec86b72db6 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -61,7 +61,6 @@ import EmberObject from '@ember/object'; */ export default EmberObject.extend({ - /** If you would like your adapter to use a custom serializer you can set the `defaultSerializer` property to be the name of the custom @@ -282,7 +281,7 @@ export default EmberObject.extend({ @return {Object} serialized snapshot */ serialize(snapshot, options) { - return snapshot.serialize(options) + return snapshot.serialize(options); }, /** @@ -493,7 +492,6 @@ export default EmberObject.extend({ return [snapshots]; }, - /** This method is used by the store to determine if the store should reload a record from the adapter when a record is requested by @@ -677,5 +675,5 @@ export default EmberObject.extend({ */ shouldBackgroundReloadAll(store, snapshotRecordArray) { return true; - } + }, }); diff --git a/addon/adapters/errors.js b/addon/adapters/errors.js index 051e090262c..b9a59d69abc 100644 --- a/addon/adapters/errors.js +++ b/addon/adapters/errors.js @@ -9,5 +9,5 @@ export { TimeoutError, AbortError, errorsHashToArray, - errorsArrayToHash + errorsArrayToHash, } from '../-private'; diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index 9d59c572f78..f23aa34eb20 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -3,7 +3,7 @@ @module ember-data */ import { dasherize } from '@ember/string'; -import RESTAdapter from "./rest"; +import RESTAdapter from './rest'; import { instrument } from 'ember-data/-debug'; import { pluralize } from 'ember-inflector'; @@ -173,7 +173,7 @@ const JSONAPIAdapter = RESTAdapter.extend({ } heimdall.stop(token); return json; - } + }, }; }); @@ -265,7 +265,7 @@ const JSONAPIAdapter = RESTAdapter.extend({ let url = this.buildURL(type.modelName, snapshot.id, snapshot, 'updateRecord'); return this.ajax(url, 'PATCH', { data: data }); - } + }, }); export default JSONAPIAdapter; diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 140126fceca..a8cd88d2532 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -10,7 +10,7 @@ import { Promise as EmberPromise } from 'rsvp'; import { get, computed } from '@ember/object'; import { getOwner } from '@ember/application'; import { run } from '@ember/runloop'; -import Adapter from "../adapter"; +import Adapter from '../adapter'; import { parseResponseHeaders, BuildURLMixin, @@ -23,7 +23,7 @@ import { ServerError, TimeoutError, AbortError, - MapWithDefault + MapWithDefault, } from '../-private'; import { instrument } from 'ember-data/-debug'; import { warn } from '@ember/debug'; @@ -644,7 +644,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findHasMany(store, snapshot, url, relationship) { - let id = snapshot.id; + let id = snapshot.id; let type = snapshot.modelName; url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findHasMany')); @@ -689,7 +689,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Promise} promise */ findBelongsTo(store, snapshot, url, relationship) { - let id = snapshot.id; + let id = snapshot.id; let type = snapshot.modelName; url = this.urlPrefix(url, this.buildURL(type, id, snapshot, 'findBelongsTo')); @@ -719,7 +719,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { serializer.serializeIntoHash(data, type, snapshot, { includeId: true }); - return this.ajax(url, "POST", { data: data }); + return this.ajax(url, 'POST', { data: data }); }, /** @@ -747,7 +747,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { let id = snapshot.id; let url = this.buildURL(type.modelName, id, snapshot, 'updateRecord'); - return this.ajax(url, "PUT", { data: data }); + return this.ajax(url, 'PUT', { data: data }); }, /** @@ -764,7 +764,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { deleteRecord(store, type, snapshot) { let id = snapshot.id; - return this.ajax(this.buildURL(type.modelName, id, snapshot, 'deleteRecord'), "DELETE"); + return this.ajax(this.buildURL(type.modelName, id, snapshot, 'deleteRecord'), 'DELETE'); }, _stripIDFromURL(store, snapshot) { @@ -779,10 +779,13 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { let lastSegment = expandedURL[expandedURL.length - 1]; let id = snapshot.id; if (decodeURIComponent(lastSegment) === id) { - expandedURL[expandedURL.length - 1] = ""; + expandedURL[expandedURL.length - 1] = ''; } else if (endsWith(lastSegment, '?id=' + id)) { //Case when the url is of the format ...something?id=:id - expandedURL[expandedURL.length - 1] = lastSegment.substring(0, lastSegment.length - id.length - 1); + expandedURL[expandedURL.length - 1] = lastSegment.substring( + 0, + lastSegment.length - id.length - 1 + ); } return expandedURL.join('/'); @@ -814,11 +817,15 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { loaded separately by `findMany`. */ groupRecordsForFindMany(store, snapshots) { - let groups = new MapWithDefault({ defaultValue() { return []; } }); + let groups = new MapWithDefault({ + defaultValue() { + return []; + }, + }); let adapter = this; let maxURLLength = this.maxURLLength; - snapshots.forEach((snapshot) => { + snapshots.forEach(snapshot => { let baseUrl = adapter._stripIDFromURL(store, snapshot); groups.get(baseUrl).push(snapshot); }); @@ -828,7 +835,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { let baseUrl = adapter._stripIDFromURL(store, group[0]); let splitGroups = [[]]; - group.forEach((snapshot) => { + group.forEach(snapshot => { let additionalLength = encodeURIComponent(snapshot.id).length + paramNameLength; if (baseUrl.length + idsSize + additionalLength >= maxURLLength) { idsSize = 0; @@ -849,7 +856,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { let paramNameLength = '&ids%5B%5D='.length; let splitGroups = splitGroupToFitInUrl(group, maxURLLength, paramNameLength); - splitGroups.forEach((splitGroup) => groupsArray.push(splitGroup)); + splitGroups.forEach(splitGroup => groupsArray.push(splitGroup)); }); return groupsArray; @@ -891,7 +898,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { return new InvalidError(payload.errors); } - let errors = this.normalizeErrorResponse(status, headers, payload); + let errors = this.normalizeErrorResponse(status, headers, payload); let detailedMessage = this.generatedDetailedMessage(status, headers, payload, requestData); switch (status) { @@ -924,7 +931,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { @return {Boolean} */ isSuccess(status, headers, payload) { - return status >= 200 && status < 300 || status === 304; + return (status >= 200 && status < 300) || status === 304; }, /** @@ -971,8 +978,8 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { let adapter = this; let requestData = { - url: url, - method: type + url: url, + method: type, }; let hash = adapter.ajaxOptions(url, type, options); @@ -1010,7 +1017,9 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { if (typeof najax !== 'undefined') { najax(options); } else { - throw new Error('najax does not seem to be defined in your app. Did you override it via `addOrOverrideSandboxGlobals` in the fastboot server?'); + throw new Error( + 'najax does not seem to be defined in your app. Did you override it via `addOrOverrideSandboxGlobals` in the fastboot server?' + ); } }, @@ -1048,7 +1057,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { } heimdall.stop(token); return json; - } + }, }; }); @@ -1059,8 +1068,8 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { let headers = get(this, 'headers'); if (headers !== undefined) { - hash.beforeSend = function (xhr) { - Object.keys(headers).forEach((key) => xhr.setRequestHeader(key, headers[key])); + hash.beforeSend = function(xhr) { + Object.keys(headers).forEach(key => xhr.setRequestHeader(key, headers[key])); }; } @@ -1082,7 +1091,10 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { try { return `${protocol}//${host}${url}`; } catch (fbError) { - throw new Error('You are using Ember Data with no host defined in your adapter. This will attempt to use the host of the FastBoot request, which is not configured for the current host of this request. Please set the hostWhitelist property for in your environment.js. FastBoot Error: ' + fbError.message); + throw new Error( + 'You are using Ember Data with no host defined in your adapter. This will attempt to use the host of the FastBoot request, which is not configured for the current host of this request. Please set the hostWhitelist property for in your environment.js. FastBoot Error: ' + + fbError.message + ); } } } @@ -1123,9 +1135,9 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { return [ { status: `${status}`, - title: "The backend responded with an error", - detail: `${payload}` - } + title: 'The backend responded with an error', + detail: `${payload}`, + }, ]; } }, @@ -1144,10 +1156,10 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { */ generatedDetailedMessage: function(status, headers, payload, requestData) { let shortenedPayload; - let payloadContentType = headers["Content-Type"] || "Empty Content-Type"; + let payloadContentType = headers['Content-Type'] || 'Empty Content-Type'; - if (payloadContentType === "text/html" && payload.length > 250) { - shortenedPayload = "[Omitted Lengthy HTML]"; + if (payloadContentType === 'text/html' && payload.length > 250) { + shortenedPayload = '[Omitted Lengthy HTML]'; } else { shortenedPayload = payload; } @@ -1155,9 +1167,11 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { let requestDescription = requestData.method + ' ' + requestData.url; let payloadDescription = 'Payload (' + payloadContentType + ')'; - return ['Ember Data Request ' + requestDescription + ' returned a ' + status, - payloadDescription, - shortenedPayload].join('\n'); + return [ + 'Ember Data Request ' + requestDescription + ' returned a ' + status, + payloadDescription, + shortenedPayload, + ].join('\n'); }, // @since 2.5.0 @@ -1173,7 +1187,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { } return query; - } + }, }); function ajaxSuccess(adapter, payload, requestData, responseData) { @@ -1198,10 +1212,12 @@ function ajaxSuccess(adapter, payload, requestData, responseData) { function ajaxError(adapter, payload, requestData, responseData) { if (DEBUG) { - let message = `The server returned an empty string for ${requestData.method} ${requestData.url}, which cannot be parsed into a valid JSON. Return either null or {}.`; - let validJSONString = !(responseData.textStatus === "parsererror" && payload === ""); + let message = `The server returned an empty string for ${requestData.method} ${ + requestData.url + }, which cannot be parsed into a valid JSON. Return either null or {}.`; + let validJSONString = !(responseData.textStatus === 'parsererror' && payload === ''); warn(message, validJSONString, { - id: 'ds.adapter.returned-empty-string-as-JSON' + id: 'ds.adapter.returned-empty-string-as-JSON', }); } @@ -1254,7 +1270,7 @@ function ajaxResponseData(jqXHR) { return { status: jqXHR.status, textStatus: jqXHR.textStatus, - headers: parseResponseHeaders(jqXHR.getAllResponseHeaders()) + headers: parseResponseHeaders(jqXHR.getAllResponseHeaders()), }; } diff --git a/addon/index.js b/addon/index.js index 90968d071f1..0064e81d076 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,5 +1,5 @@ import EmberError from '@ember/error'; -import Ember from "ember"; +import Ember from 'ember'; /** Ember Data @@ -8,9 +8,11 @@ import Ember from "ember"; */ if (Ember.VERSION.match(/^1\.([0-9]|1[0-2])\./)) { - throw new EmberError("Ember Data requires at least Ember 1.13.0, but you have " + - Ember.VERSION + - ". Please upgrade your version of Ember, then upgrade Ember Data."); + throw new EmberError( + 'Ember Data requires at least Ember 1.13.0, but you have ' + + Ember.VERSION + + '. Please upgrade your version of Ember, then upgrade Ember Data.' + ); } import { @@ -44,11 +46,11 @@ import { TimeoutError, AbortError, errorsHashToArray, - errorsArrayToHash + errorsArrayToHash, } from './-private'; -import "ember-inflector"; -import setupContainer from "./setup-container"; +import 'ember-inflector'; +import setupContainer from './setup-container'; import initializeStoreService from './initialize-store-service'; import Transform from './transforms/transform'; @@ -57,44 +59,44 @@ import DateTransform from './transforms/date'; import StringTransform from './transforms/string'; import BooleanTransform from './transforms/boolean'; -import Adapter from "./adapter"; +import Adapter from './adapter'; import JSONAPIAdapter from './adapters/json-api'; import RESTAdapter from './adapters/rest'; -import Serializer from "./serializer"; +import Serializer from './serializer'; import JSONAPISerializer from './serializers/json-api'; import JSONSerializer from './serializers/json'; import RESTSerializer from './serializers/rest'; -import EmbeddedRecordsMixin from "./serializers/embedded-records-mixin"; +import EmbeddedRecordsMixin from './serializers/embedded-records-mixin'; import attr from './attr'; -DS.Store = Store; -DS.PromiseArray = PromiseArray; +DS.Store = Store; +DS.PromiseArray = PromiseArray; DS.PromiseObject = PromiseObject; DS.PromiseManyArray = PromiseManyArray; -DS.Model = Model; +DS.Model = Model; DS.RootState = RootState; -DS.attr = attr; -DS.Errors = Errors; +DS.attr = attr; +DS.Errors = Errors; DS.InternalModel = InternalModel; DS.Snapshot = Snapshot; -DS.Adapter = Adapter; +DS.Adapter = Adapter; DS.AdapterError = AdapterError; DS.InvalidError = InvalidError; DS.TimeoutError = TimeoutError; -DS.AbortError = AbortError; +DS.AbortError = AbortError; DS.UnauthorizedError = UnauthorizedError; -DS.ForbiddenError = ForbiddenError; -DS.NotFoundError = NotFoundError; -DS.ConflictError = ConflictError; -DS.ServerError = ServerError; +DS.ForbiddenError = ForbiddenError; +DS.NotFoundError = NotFoundError; +DS.ConflictError = ConflictError; +DS.ServerError = ServerError; DS.errorsHashToArray = errorsHashToArray; DS.errorsArrayToHash = errorsArrayToHash; @@ -103,14 +105,14 @@ DS.Serializer = Serializer; DS.DebugAdapter = DebugAdapter; -DS.RecordArray = RecordArray; +DS.RecordArray = RecordArray; DS.AdapterPopulatedRecordArray = AdapterPopulatedRecordArray; -DS.ManyArray = ManyArray; +DS.ManyArray = ManyArray; DS.RecordArrayManager = RecordArrayManager; -DS.RESTAdapter = RESTAdapter; -DS.BuildURLMixin = BuildURLMixin; +DS.RESTAdapter = RESTAdapter; +DS.BuildURLMixin = BuildURLMixin; DS.RESTSerializer = RESTSerializer; DS.JSONSerializer = JSONSerializer; @@ -118,18 +120,18 @@ DS.JSONSerializer = JSONSerializer; DS.JSONAPIAdapter = JSONAPIAdapter; DS.JSONAPISerializer = JSONAPISerializer; -DS.Transform = Transform; -DS.DateTransform = DateTransform; +DS.Transform = Transform; +DS.DateTransform = DateTransform; DS.StringTransform = StringTransform; DS.NumberTransform = NumberTransform; DS.BooleanTransform = BooleanTransform; -DS.EmbeddedRecordsMixin = EmbeddedRecordsMixin; +DS.EmbeddedRecordsMixin = EmbeddedRecordsMixin; DS.belongsTo = belongsTo; -DS.hasMany = hasMany; +DS.hasMany = hasMany; -DS.Relationship = Relationship; +DS.Relationship = Relationship; DS._setupContainer = setupContainer; DS._initializeStoreService = initializeStoreService; @@ -138,7 +140,7 @@ Object.defineProperty(DS, 'normalizeModelName', { enumerable: true, writable: false, configurable: false, - value: normalizeModelName + value: normalizeModelName, }); export default DS; diff --git a/addon/serializer.js b/addon/serializer.js index 67f1daf2085..cf9d47cbbd7 100644 --- a/addon/serializer.js +++ b/addon/serializer.js @@ -25,7 +25,6 @@ import EmberObject from '@ember/object'; */ export default EmberObject.extend({ - /** The `store` property is the application's `store` that contains all records. It can be used to look up serializers for other model @@ -154,6 +153,5 @@ export default EmberObject.extend({ */ normalize(typeClass, hash) { return hash; - } - + }, }); diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 8bd9c347e3c..9868f15033c 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -98,7 +98,6 @@ import { warn } from '@ember/debug'; @namespace DS */ export default Mixin.create({ - /** Normalize the record and recursively normalize/extract all the embedded records while pushing them into the store as they are encountered @@ -132,8 +131,10 @@ export default Mixin.create({ }, keyForRelationship(key, typeClass, method) { - if ((method === 'serialize' && this.hasSerializeRecordsOption(key)) || - (method === 'deserialize' && this.hasDeserializeRecordsOption(key))) { + if ( + (method === 'serialize' && this.hasSerializeRecordsOption(key)) || + (method === 'deserialize' && this.hasDeserializeRecordsOption(key)) + ) { return this.keyForAttribute(key, method); } else { return this._super(key, typeClass, method) || key; @@ -203,7 +204,7 @@ export default Mixin.create({ if (includeIds) { let serializedKey = this._getMappedKey(relationship.key, snapshot.type); if (serializedKey === relationship.key && this.keyForRelationship) { - serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); + serializedKey = this.keyForRelationship(relationship.key, relationship.kind, 'serialize'); } if (!embeddedSnapshot) { @@ -224,7 +225,7 @@ export default Mixin.create({ let embeddedSnapshot = snapshot.belongsTo(relationship.key); let serializedKey = this._getMappedKey(relationship.key, snapshot.type); if (serializedKey === relationship.key && this.keyForRelationship) { - serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); + serializedKey = this.keyForRelationship(relationship.key, relationship.kind, 'serialize'); } if (!embeddedSnapshot) { @@ -384,7 +385,7 @@ export default Mixin.create({ if (this.hasSerializeIdsOption(attr)) { let serializedKey = this._getMappedKey(relationship.key, snapshot.type); if (serializedKey === relationship.key && this.keyForRelationship) { - serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); + serializedKey = this.keyForRelationship(relationship.key, relationship.kind, 'serialize'); } json[serializedKey] = snapshot.hasMany(attr, { ids: true }); @@ -409,7 +410,7 @@ export default Mixin.create({ let serializedKey = this.keyForAttribute(relationship.key, 'serialize'); let hasMany = snapshot.hasMany(relationship.key); - json[serializedKey] = A(hasMany).map(function (recordSnapshot) { + json[serializedKey] = A(hasMany).map(function(recordSnapshot) { // // I'm sure I'm being utterly naive here. Propably id is a configurate property and // type too, and the modelName has to be normalized somehow. @@ -421,12 +422,13 @@ export default Mixin.create({ _serializeEmbeddedHasMany(snapshot, json, relationship) { let serializedKey = this._getMappedKey(relationship.key, snapshot.type); if (serializedKey === relationship.key && this.keyForRelationship) { - serializedKey = this.keyForRelationship(relationship.key, relationship.kind, "serialize"); + serializedKey = this.keyForRelationship(relationship.key, relationship.kind, 'serialize'); } - warn( - `The embedded relationship '${serializedKey}' is undefined for '${snapshot.modelName}' with id '${snapshot.id}'. Please include it in your original payload.`, + `The embedded relationship '${serializedKey}' is undefined for '${ + snapshot.modelName + }' with id '${snapshot.id}'. Please include it in your original payload.`, typeOf(snapshot.hasMany(relationship.key)) !== 'undefined', { id: 'ds.serializer.embedded-relationship-undefined' } ); @@ -474,7 +476,11 @@ export default Mixin.create({ if (parentRecord) { let name = parentRecord.name; let embeddedSerializer = this.store.serializerFor(embeddedSnapshot.modelName); - let parentKey = embeddedSerializer.keyForRelationship(name, parentRecord.kind, 'deserialize'); + let parentKey = embeddedSerializer.keyForRelationship( + name, + parentRecord.kind, + 'deserialize' + ); if (parentKey) { delete json[parentKey]; } @@ -494,7 +500,7 @@ export default Mixin.create({ hasSerializeRecordsOption(attr) { let alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); let option = this.attrsOption(attr); - return alwaysEmbed || (option && (option.serialize === 'records')); + return alwaysEmbed || (option && option.serialize === 'records'); }, // checks config for attrs option to serialize records @@ -536,10 +542,10 @@ export default Mixin.create({ _extractEmbeddedRecords(serializer, store, typeClass, partial) { typeClass.eachRelationship((key, relationship) => { if (serializer.hasDeserializeRecordsOption(key)) { - if (relationship.kind === "hasMany") { + if (relationship.kind === 'hasMany') { this._extractEmbeddedHasMany(store, key, partial, relationship); } - if (relationship.kind === "belongsTo") { + if (relationship.kind === 'belongsTo') { this._extractEmbeddedBelongsTo(store, key, partial, relationship); } } @@ -586,7 +592,11 @@ export default Mixin.create({ return; } - let { data, included } = this._normalizeEmbeddedRelationship(store, relationshipMeta, relationshipHash); + let { data, included } = this._normalizeEmbeddedRelationship( + store, + relationshipMeta, + relationshipHash + ); hash.included = hash.included || []; hash.included.push(data); if (included) { @@ -613,5 +623,5 @@ export default Mixin.create({ return serializer.normalize(modelClass, relationshipHash, null); }, - isEmbeddedRecordsMixin: true + isEmbeddedRecordsMixin: true, }); diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index b9c587f11aa..923b769eb09 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -129,7 +129,6 @@ import { normalizeModelName } from '../-private'; @extends DS.JSONSerializer */ const JSONAPISerializer = JSONSerializer.extend({ - /** @method _normalizeDocumentHelper @param {Object} documentHash @@ -137,7 +136,6 @@ const JSONAPISerializer = JSONSerializer.extend({ @private */ _normalizeDocumentHelper(documentHash) { - if (typeOf(documentHash.data) === 'object') { documentHash.data = this._normalizeResourceHelper(documentHash.data); } else if (Array.isArray(documentHash.data)) { @@ -156,7 +154,8 @@ const JSONAPISerializer = JSONSerializer.extend({ for (let i = 0; i < documentHash.included.length; i++) { let included = documentHash.included[i]; let normalized = this._normalizeResourceHelper(included); - if (normalized !== null) { // can be null when unknown type is encountered + if (normalized !== null) { + // can be null when unknown type is encountered ret.push(normalized); } } @@ -187,7 +186,7 @@ const JSONAPISerializer = JSONSerializer.extend({ */ _normalizeResourceHelper(resourceHash) { assert(this.warnMessageForUndefinedType(), !isNone(resourceHash.type), { - id: 'ds.serializer.type-is-undefined' + id: 'ds.serializer.type-is-undefined', }); let modelName, usedLookup; @@ -197,7 +196,7 @@ const JSONAPISerializer = JSONSerializer.extend({ if (!this.store._hasModelFor(modelName)) { warn(this.warnMessageNoModelForType(modelName, resourceHash.type, usedLookup), false, { - id: 'ds.serializer.model-for-type-missing' + id: 'ds.serializer.model-for-type-missing', }); return null; } @@ -237,9 +236,13 @@ const JSONAPISerializer = JSONSerializer.extend({ normalizeQueryRecordResponse() { let normalized = this._super(...arguments); - assert('Expected the primary data returned by the serializer for a `queryRecord` response to be a single object but instead it was an array.', !Array.isArray(normalized.data), { - id: 'ds.serializer.json-api.queryRecord-array-response' - }); + assert( + 'Expected the primary data returned by the serializer for a `queryRecord` response to be a single object but instead it was an array.', + !Array.isArray(normalized.data), + { + id: 'ds.serializer.json-api.queryRecord-array-response', + } + ); return normalized; }, @@ -248,14 +251,22 @@ const JSONAPISerializer = JSONSerializer.extend({ let attributes = {}; if (resourceHash.attributes) { - modelClass.eachAttribute((key) => { + modelClass.eachAttribute(key => { let attributeKey = this.keyForAttribute(key, 'deserialize'); if (resourceHash.attributes[attributeKey] !== undefined) { attributes[key] = resourceHash.attributes[attributeKey]; } if (DEBUG) { - if (resourceHash.attributes[attributeKey] === undefined && resourceHash.attributes[key] !== undefined) { - assert(`Your payload for '${modelClass.modelName}' contains '${key}', but your serializer is setup to look for '${attributeKey}'. This is most likely because Ember Data's JSON API serializer dasherizes attribute keys by default. You should subclass JSONAPISerializer and implement 'keyForAttribute(key) { return key; }' to prevent Ember Data from customizing your attribute keys.`, false); + if ( + resourceHash.attributes[attributeKey] === undefined && + resourceHash.attributes[key] !== undefined + ) { + assert( + `Your payload for '${ + modelClass.modelName + }' contains '${key}', but your serializer is setup to look for '${attributeKey}'. This is most likely because Ember Data's JSON API serializer dasherizes attribute keys by default. You should subclass JSONAPISerializer and implement 'keyForAttribute(key) { return key; }' to prevent Ember Data from customizing your attribute keys.`, + false + ); } } }); @@ -274,7 +285,6 @@ const JSONAPISerializer = JSONSerializer.extend({ @return {Object} */ extractRelationship(relationshipHash) { - if (typeOf(relationshipHash.data) === 'object') { relationshipHash.data = this._normalizeRelationshipDataHelper(relationshipHash.data); } @@ -310,14 +320,20 @@ const JSONAPISerializer = JSONSerializer.extend({ modelClass.eachRelationship((key, relationshipMeta) => { let relationshipKey = this.keyForRelationship(key, relationshipMeta.kind, 'deserialize'); if (resourceHash.relationships[relationshipKey] !== undefined) { - let relationshipHash = resourceHash.relationships[relationshipKey]; relationships[key] = this.extractRelationship(relationshipHash); - } if (DEBUG) { - if (resourceHash.relationships[relationshipKey] === undefined && resourceHash.relationships[key] !== undefined) { - assert(`Your payload for '${modelClass.modelName}' contains '${key}', but your serializer is setup to look for '${relationshipKey}'. This is most likely because Ember Data's JSON API serializer dasherizes relationship keys by default. You should subclass JSONAPISerializer and implement 'keyForRelationship(key) { return key; }' to prevent Ember Data from customizing your relationship keys.`, false); + if ( + resourceHash.relationships[relationshipKey] === undefined && + resourceHash.relationships[key] !== undefined + ) { + assert( + `Your payload for '${ + modelClass.modelName + }' contains '${key}', but your serializer is setup to look for '${relationshipKey}'. This is most likely because Ember Data's JSON API serializer dasherizes relationship keys by default. You should subclass JSONAPISerializer and implement 'keyForRelationship(key) { return key; }' to prevent Ember Data from customizing your relationship keys.`, + false + ); } } }); @@ -378,10 +394,10 @@ const JSONAPISerializer = JSONSerializer.extend({ } let data = { - id: this.extractId(modelClass, resourceHash), - type: this._extractType(modelClass, resourceHash), - attributes: this.extractAttributes(modelClass, resourceHash), - relationships: this.extractRelationships(modelClass, resourceHash) + id: this.extractId(modelClass, resourceHash), + type: this._extractType(modelClass, resourceHash), + attributes: this.extractAttributes(modelClass, resourceHash), + relationships: this.extractRelationships(modelClass, resourceHash), }; this.applyTransforms(modelClass, data.attributes); @@ -501,7 +517,7 @@ const JSONAPISerializer = JSONSerializer.extend({ data = { type: payloadType, - id: belongsTo.id + id: belongsTo.id, }; } @@ -516,7 +532,6 @@ const JSONAPISerializer = JSONSerializer.extend({ if (this.shouldSerializeHasMany(snapshot, key, relationship)) { let hasMany = snapshot.hasMany(key); if (hasMany !== undefined) { - json.relationships = json.relationships || {}; let payloadKey = this._getMappedKey(key, snapshot.type); @@ -534,33 +549,45 @@ const JSONAPISerializer = JSONSerializer.extend({ data[i] = { type: payloadType, - id: item.id + id: item.id, }; } json.relationships[payloadKey] = { data }; } } - } + }, }); if (DEBUG) { JSONAPISerializer.reopen({ willMergeMixin(props) { let constructor = this.constructor; - warn(`You've defined 'extractMeta' in ${constructor.toString()} which is not used for serializers extending JSONAPISerializer. Read more at https://emberjs.com/api/data/classes/DS.JSONAPISerializer.html#toc_customizing-meta on how to customize meta when using JSON API.`, isNone(props.extractMeta) || props.extractMeta === JSONSerializer.prototype.extractMeta, { - id: 'ds.serializer.json-api.extractMeta' - }); - warn('The JSONAPISerializer does not work with the EmbeddedRecordsMixin because the JSON API spec does not describe how to format embedded resources.', !props.isEmbeddedRecordsMixin, { - id: 'ds.serializer.embedded-records-mixin-not-supported' - }); + warn( + `You've defined 'extractMeta' in ${constructor.toString()} which is not used for serializers extending JSONAPISerializer. Read more at https://emberjs.com/api/data/classes/DS.JSONAPISerializer.html#toc_customizing-meta on how to customize meta when using JSON API.`, + isNone(props.extractMeta) || props.extractMeta === JSONSerializer.prototype.extractMeta, + { + id: 'ds.serializer.json-api.extractMeta', + } + ); + warn( + 'The JSONAPISerializer does not work with the EmbeddedRecordsMixin because the JSON API spec does not describe how to format embedded resources.', + !props.isEmbeddedRecordsMixin, + { + id: 'ds.serializer.embedded-records-mixin-not-supported', + } + ); }, warnMessageForUndefinedType() { - return 'Encountered a resource object with an undefined type (resolved resource using ' + this.constructor.toString() + ')'; + return ( + 'Encountered a resource object with an undefined type (resolved resource using ' + + this.constructor.toString() + + ')' + ); }, warnMessageNoModelForType(modelName, originalType, usedLookup) { return `Encountered a resource object with type "${originalType}", but no model was found for model name "${modelName}" (resolved model name using '${this.constructor.toString()}.${usedLookup}("${originalType}")').`; - } + }, }); } diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 88d9c1a33d3..8fd59410393 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -2,13 +2,13 @@ import { assign, merge } from '@ember/polyfills'; import { isNone, typeOf } from '@ember/utils'; import { get } from '@ember/object'; import { assert, warn } from '@ember/debug'; -import Serializer from "../serializer"; +import Serializer from '../serializer'; import { getOwner, coerceId, modelHasAttributeOrRelationshipNamedType, normalizeModelName, - errorsArrayToHash + errorsArrayToHash, } from '../-private'; const emberAssign = assign || merge; @@ -80,7 +80,6 @@ const emberAssign = assign || merge; @extends DS.Serializer */ const JSONSerializer = Serializer.extend({ - /** The `primaryKey` is used when serializing and deserializing data. Ember Data always uses the `id` property to store the id of @@ -186,7 +185,9 @@ const JSONSerializer = Serializer.extend({ let attributes = get(typeClass, 'attributes'); typeClass.eachTransformedAttribute((key, typeClass) => { - if (data[key] === undefined) { return; } + if (data[key] === undefined) { + return; + } let transform = this.transformFor(typeClass); let transformMeta = attributes.get(key); @@ -452,12 +453,15 @@ const JSONSerializer = Serializer.extend({ _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { let documentHash = { data: null, - included: [] + included: [], }; let meta = this.extractMeta(store, primaryModelClass, payload); if (meta) { - assert('The `meta` returned from `extractMeta` has to be an object, not "' + typeOf(meta) + '".', typeOf(meta) === 'object'); + assert( + 'The `meta` returned from `extractMeta` has to be an object, not "' + typeOf(meta) + '".', + typeOf(meta) === 'object' + ); documentHash.meta = meta; } @@ -484,7 +488,6 @@ const JSONSerializer = Serializer.extend({ return documentHash; }, - /** Normalizes a part of the JSON payload returned by the server. You should override this method, munge the hash @@ -536,10 +539,10 @@ const JSONSerializer = Serializer.extend({ } data = { - id: this.extractId(modelClass, resourceHash), - type: modelClass.modelName, - attributes: this.extractAttributes(modelClass, resourceHash), - relationships: this.extractRelationships(modelClass, resourceHash) + id: this.extractId(modelClass, resourceHash), + type: modelClass.modelName, + attributes: this.extractAttributes(modelClass, resourceHash), + relationships: this.extractRelationships(modelClass, resourceHash), }; this.applyTransforms(modelClass, data.attributes); @@ -576,7 +579,7 @@ const JSONSerializer = Serializer.extend({ let attributeKey; let attributes = {}; - modelClass.eachAttribute((key) => { + modelClass.eachAttribute(key => { attributeKey = this.keyForAttribute(key, 'deserialize'); if (resourceHash[attributeKey] !== undefined) { attributes[key] = resourceHash[attributeKey]; @@ -597,7 +600,9 @@ const JSONSerializer = Serializer.extend({ @return {Object} */ extractRelationship(relationshipModelName, relationshipHash) { - if (isNone(relationshipHash)) { return null; } + if (isNone(relationshipHash)) { + return null; + } /* When `relationshipHash` is an object it usually means that the relationship is polymorphic. It could however also be embedded resources that the @@ -666,7 +671,11 @@ const JSONSerializer = Serializer.extend({ // than the type and the hash (which might only be an id) for the // relationship, hence we pass the key, resource and // relationshipMeta too - data = this.extractPolymorphicRelationship(relationshipMeta.type, relationshipHash, { key, resourceHash, relationshipMeta }); + data = this.extractPolymorphicRelationship(relationshipMeta.type, relationshipHash, { + key, + resourceHash, + relationshipMeta, + }); } else { data = this.extractRelationship(relationshipMeta.type, relationshipHash); } @@ -717,8 +726,12 @@ const JSONSerializer = Serializer.extend({ if (this.keyForRelationship) { typeClass.eachRelationship((key, relationship) => { payloadKey = this.keyForRelationship(key, relationship.kind, 'deserialize'); - if (key === payloadKey) { return; } - if (hash[payloadKey] === undefined) { return; } + if (key === payloadKey) { + return; + } + if (hash[payloadKey] === undefined) { + return; + } hash[key] = hash[payloadKey]; delete hash[payloadKey]; @@ -739,7 +752,9 @@ const JSONSerializer = Serializer.extend({ for (let key in attrs) { normalizedKey = payloadKey = this._getMappedKey(key, modelClass); - if (hash[payloadKey] === undefined) { continue; } + if (hash[payloadKey] === undefined) { + continue; + } if (get(modelClass, 'attributes').has(key)) { normalizedKey = this.keyForAttribute(key); @@ -767,9 +782,17 @@ const JSONSerializer = Serializer.extend({ @return {String} key */ _getMappedKey(key, modelClass) { - warn('There is no attribute or relationship with the name `' + key + '` on `' + modelClass.modelName + '`. Check your serializers attrs hash.', get(modelClass, 'attributes').has(key) || get(modelClass, 'relationshipsByName').has(key), { - id: 'ds.serializer.no-mapped-attrs-key' - }); + warn( + 'There is no attribute or relationship with the name `' + + key + + '` on `' + + modelClass.modelName + + '`. Check your serializers attrs hash.', + get(modelClass, 'attributes').has(key) || get(modelClass, 'relationshipsByName').has(key), + { + id: 'ds.serializer.no-mapped-attrs-key', + } + ); let attrs = get(this, 'attrs'); let mappedKey; @@ -833,10 +856,12 @@ const JSONSerializer = Serializer.extend({ if (this._mustSerialize(key)) { return true; } - return this._canSerialize(key) && (relationshipType === 'manyToNone' || relationshipType === 'manyToMany'); + return ( + this._canSerialize(key) && + (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') + ); }, - // SERIALIZE /** Called when a record is saved in order to convert the @@ -1073,7 +1098,6 @@ const JSONSerializer = Serializer.extend({ @param {Object} attribute */ serializeAttribute(snapshot, json, key, attribute) { - if (this._canSerialize(key)) { let type = attribute.type; let value = snapshot.attr(key); @@ -1084,7 +1108,7 @@ const JSONSerializer = Serializer.extend({ // if provided, use the mapping provided by `attrs` in // the serializer - let payloadKey = this._getMappedKey(key, snapshot.type); + let payloadKey = this._getMappedKey(key, snapshot.type); if (payloadKey === key && this.keyForAttribute) { payloadKey = this.keyForAttribute(key, 'serialize'); @@ -1131,7 +1155,7 @@ const JSONSerializer = Serializer.extend({ // the serializer let payloadKey = this._getMappedKey(key, snapshot.type); if (payloadKey === key && this.keyForRelationship) { - payloadKey = this.keyForRelationship(key, "belongsTo", "serialize"); + payloadKey = this.keyForRelationship(key, 'belongsTo', 'serialize'); } //Need to check whether the id is there for new&async records @@ -1183,7 +1207,7 @@ const JSONSerializer = Serializer.extend({ // the serializer let payloadKey = this._getMappedKey(key, snapshot.type); if (payloadKey === key && this.keyForRelationship) { - payloadKey = this.keyForRelationship(key, "hasMany", "serialize"); + payloadKey = this.keyForRelationship(key, 'hasMany', 'serialize'); } json[payloadKey] = hasMany; @@ -1352,7 +1376,7 @@ const JSONSerializer = Serializer.extend({ this.normalizeUsingDeclaredMapping(typeClass, payload); - typeClass.eachAttribute((name) => { + typeClass.eachAttribute(name => { let key = this.keyForAttribute(name, 'deserialize'); if (key !== name && payload[key] !== undefined) { payload[name] = payload[key]; @@ -1360,7 +1384,7 @@ const JSONSerializer = Serializer.extend({ } }); - typeClass.eachRelationship((name) => { + typeClass.eachRelationship(name => { let key = this.keyForRelationship(name, 'deserialize'); if (key !== name && payload[key] !== undefined) { payload[name] = payload[key]; @@ -1454,7 +1478,7 @@ const JSONSerializer = Serializer.extend({ assert("Unable to find transform for '" + attributeType + "'", skipAssertion || !!transform); return transform; - } + }, }); export default JSONSerializer; diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 84acff2610b..8987067e4f7 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -6,15 +6,15 @@ import { typeOf, isNone } from '@ember/utils'; import { makeArray } from '@ember/array'; import { camelize } from '@ember/string'; -import { singularize } from "ember-inflector"; +import { singularize } from 'ember-inflector'; import { assert, deprecate, warn } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; -import JSONSerializer from "../serializers/json"; +import JSONSerializer from '../serializers/json'; import { coerceId, modelHasAttributeOrRelationshipNamedType, - normalizeModelName + normalizeModelName, } from '../-private'; /** @@ -61,7 +61,6 @@ import { @extends DS.JSONSerializer */ const RESTSerializer = JSONSerializer.extend({ - /** `keyForPolymorphicType` can be used to define a custom key when serializing and deserializing a polymorphic type. By default, the @@ -175,14 +174,20 @@ const RESTSerializer = JSONSerializer.extend({ _normalizeArray(store, modelName, arrayHash, prop) { let documentHash = { data: [], - included: [] + included: [], }; let modelClass = store.modelFor(modelName); let serializer = store.serializerFor(modelName); - makeArray(arrayHash).forEach((hash) => { - let { data, included } = this._normalizePolymorphicRecord(store, hash, prop, modelClass, serializer); + makeArray(arrayHash).forEach(hash => { + let { data, included } = this._normalizePolymorphicRecord( + store, + hash, + prop, + modelClass, + serializer + ); documentHash.data.push(data); if (included) { documentHash.included.push(...included); @@ -225,12 +230,15 @@ const RESTSerializer = JSONSerializer.extend({ _normalizeResponse(store, primaryModelClass, payload, id, requestType, isSingle) { let documentHash = { data: null, - included: [] + included: [], }; let meta = this.extractMeta(store, primaryModelClass, payload); if (meta) { - assert('The `meta` returned from `extractMeta` has to be an object, not "' + typeOf(meta) + '".', typeOf(meta) === 'object'); + assert( + 'The `meta` returned from `extractMeta` has to be an object, not "' + typeOf(meta) + '".', + typeOf(meta) === 'object' + ); documentHash.meta = meta; } @@ -269,12 +277,12 @@ const RESTSerializer = JSONSerializer.extend({ var typeName = this.modelNameFromPayloadKey(modelName); if (!store._hasModelFor(typeName)) { warn(this.warnMessageNoModelForKey(modelName, typeName), false, { - id: 'ds.serializer.model-for-key-missing' + id: 'ds.serializer.model-for-key-missing', }); continue; } - var isPrimary = (!forcedSecondary && this.isPrimaryType(store, typeName, primaryModelClass)); + var isPrimary = !forcedSecondary && this.isPrimaryType(store, typeName, primaryModelClass); var value = payload[prop]; if (value === null) { @@ -282,12 +290,14 @@ const RESTSerializer = JSONSerializer.extend({ } if (DEBUG) { - let isQueryRecordAnArray = requestType === 'queryRecord' && isPrimary && Array.isArray(value); - let message = "The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record."; + let isQueryRecordAnArray = + requestType === 'queryRecord' && isPrimary && Array.isArray(value); + let message = + 'The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record.'; deprecate(message, !isQueryRecordAnArray, { id: 'ds.serializer.rest.queryRecord-array-response', - until: '3.0' + until: '3.0', }); } @@ -303,7 +313,13 @@ const RESTSerializer = JSONSerializer.extend({ ``` */ if (isPrimary && !Array.isArray(value)) { - let { data, included } = this._normalizePolymorphicRecord(store, value, prop, primaryModelClass, this); + let { data, included } = this._normalizePolymorphicRecord( + store, + value, + prop, + primaryModelClass, + this + ); documentHash.data = data; if (included) { documentHash.included.push(...included); @@ -319,7 +335,6 @@ const RESTSerializer = JSONSerializer.extend({ if (isSingle) { data.forEach(resource => { - /* Figures out if this is the primary record or not. @@ -390,14 +405,14 @@ const RESTSerializer = JSONSerializer.extend({ pushPayload(store, payload) { let documentHash = { data: [], - included: [] + included: [], }; for (var prop in payload) { var modelName = this.modelNameFromPayloadKey(prop); if (!store._hasModelFor(modelName)) { warn(this.warnMessageNoModelForKey(prop, modelName), false, { - id: 'ds.serializer.model-for-key-missing' + id: 'ds.serializer.model-for-key-missing', }); continue; } @@ -772,23 +787,37 @@ const RESTSerializer = JSONSerializer.extend({ let isPolymorphic = relationshipMeta.options.polymorphic; let typeProperty = this.keyForPolymorphicType(key, relationshipType, 'deserialize'); - if (isPolymorphic && resourceHash[typeProperty] !== undefined && typeof relationshipHash !== 'object') { + if ( + isPolymorphic && + resourceHash[typeProperty] !== undefined && + typeof relationshipHash !== 'object' + ) { let type = this.modelNameFromPayloadKey(resourceHash[typeProperty]); return { id: relationshipHash, - type: type + type: type, }; } return this._super(...arguments); - } + }, }); if (DEBUG) { RESTSerializer.reopen({ warnMessageNoModelForKey(prop, typeKey) { - return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + typeKey + '" (resolved model name using ' + this.constructor.toString() + '.modelNameFromPayloadKey("' + prop + '"))'; - } + return ( + 'Encountered "' + + prop + + '" in payload, but no model was found for model name "' + + typeKey + + '" (resolved model name using ' + + this.constructor.toString() + + '.modelNameFromPayloadKey("' + + prop + + '"))' + ); + }, }); } diff --git a/addon/setup-container.js b/addon/setup-container.js index 9b78e973ff7..1040478a339 100644 --- a/addon/setup-container.js +++ b/addon/setup-container.js @@ -1,7 +1,4 @@ -import { - DebugAdapter, - Store -} from './-private'; +import { DebugAdapter, Store } from './-private'; import JSONAPISerializer from './serializers/json-api'; import JSONSerializer from './serializers/json'; import RESTSerializer from './serializers/rest'; @@ -41,7 +38,6 @@ function initializeStore(registry) { registry.register('adapter:-json-api', JSONAPIAdapter); registry.register('serializer:-json-api', JSONAPISerializer); - if (!has(registry, 'service:store')) { registry.register('service:store', Store); } diff --git a/addon/transforms/boolean.js b/addon/transforms/boolean.js index b7d1a5a9b1e..241084ba3a0 100644 --- a/addon/transforms/boolean.js +++ b/addon/transforms/boolean.js @@ -44,11 +44,11 @@ export default Transform.extend({ } let type = typeof serialized; - if (type === "boolean") { + if (type === 'boolean') { return serialized; - } else if (type === "string") { + } else if (type === 'string') { return /^(true|t|1)$/i.test(serialized); - } else if (type === "number") { + } else if (type === 'number') { return serialized === 1; } else { return false; @@ -61,5 +61,5 @@ export default Transform.extend({ } return Boolean(deserialized); - } + }, }); diff --git a/addon/transforms/date.js b/addon/transforms/date.js index e984ca9f448..8fef1da008e 100644 --- a/addon/transforms/date.js +++ b/addon/transforms/date.js @@ -26,7 +26,7 @@ export default Transform.extend({ deserialize(serialized) { let type = typeof serialized; - if (type === "string") { + if (type === 'string') { let offset = serialized.indexOf('+'); if (offset !== -1 && serialized.length - 5 === offset) { @@ -34,8 +34,8 @@ export default Transform.extend({ return new Date(serialized.slice(0, offset) + ':' + serialized.slice(offset)); } return new Date(serialized); - } else if (type === "number") { - return new Date(serialized) + } else if (type === 'number') { + return new Date(serialized); } else if (serialized === null || serialized === undefined) { // if the value is null return null // if the value is not present in the data return undefined @@ -51,5 +51,5 @@ export default Transform.extend({ } else { return null; } - } + }, }); diff --git a/addon/transforms/number.js b/addon/transforms/number.js index 75b35eda250..267df17e6f6 100644 --- a/addon/transforms/number.js +++ b/addon/transforms/number.js @@ -49,5 +49,5 @@ export default Transform.extend({ return isNumber(transformed) ? transformed : null; } - } + }, }); diff --git a/addon/transforms/string.js b/addon/transforms/string.js index 2c071006920..c4aeac50781 100644 --- a/addon/transforms/string.js +++ b/addon/transforms/string.js @@ -29,5 +29,5 @@ export default Transform.extend({ }, serialize(deserialized) { return none(deserialized) ? null : String(deserialized); - } + }, }); diff --git a/addon/transforms/transform.js b/addon/transforms/transform.js index c04986d1f44..5cbdb20a1ce 100644 --- a/addon/transforms/transform.js +++ b/addon/transforms/transform.js @@ -106,5 +106,5 @@ export default EmberObject.extend({ @param options hash of options passed to `DS.attr` @return The deserialized value */ - deserialize: null + deserialize: null, }); diff --git a/app/initializers/ember-data.js b/app/initializers/ember-data.js index fba3329b260..8d185c5c98b 100644 --- a/app/initializers/ember-data.js +++ b/app/initializers/ember-data.js @@ -42,5 +42,5 @@ import 'ember-data'; export default { name: 'ember-data', - initialize: setupContainer + initialize: setupContainer, }; diff --git a/app/instance-initializers/ember-data.js b/app/instance-initializers/ember-data.js index 50b27f03026..6b0dee68e7b 100644 --- a/app/instance-initializers/ember-data.js +++ b/app/instance-initializers/ember-data.js @@ -1,6 +1,6 @@ import initializeStoreService from 'ember-data/initialize-store-service'; export default { - name: "ember-data", - initialize: initializeStoreService + name: 'ember-data', + initialize: initializeStoreService, }; diff --git a/bin/publish-to-s3.js b/bin/publish-to-s3.js index 9147180f8a6..80d9b39d07b 100755 --- a/bin/publish-to-s3.js +++ b/bin/publish-to-s3.js @@ -17,5 +17,5 @@ // ``` var S3Publisher = require('ember-publisher'); var configPath = require('path').join(__dirname, '../config/s3ProjectConfig.js'); -var publisher = new S3Publisher({projectConfigPath: configPath}); +var publisher = new S3Publisher({ projectConfigPath: configPath }); publisher.publish(); diff --git a/blueprints/adapter-test/index.js b/blueprints/adapter-test/index.js index 22f160b5f0b..8fb29a4621d 100644 --- a/blueprints/adapter-test/index.js +++ b/blueprints/adapter-test/index.js @@ -6,7 +6,7 @@ module.exports = useTestFrameworkDetector({ locals: function(options) { return { - friendlyTestDescription: testInfo.description(options.entity.name, "Unit", "Adapter") + friendlyTestDescription: testInfo.description(options.entity.name, 'Unit', 'Adapter'), }; - } + }, }); diff --git a/blueprints/adapter/index.js b/blueprints/adapter/index.js index 22ecb861ace..d8db9642bb3 100644 --- a/blueprints/adapter/index.js +++ b/blueprints/adapter/index.js @@ -3,11 +3,9 @@ var extendFromApplicationEntity = require('../../lib/utilities/extend-from-appli module.exports = { description: 'Generates an ember-data adapter.', - availableOptions: [ - { name: 'base-class', type: String } - ], + availableOptions: [{ name: 'base-class', type: String }], locals: function(options) { return extendFromApplicationEntity('adapter', 'DS.JSONAPIAdapter', options); - } + }, }; diff --git a/blueprints/model-test/index.js b/blueprints/model-test/index.js index 0cc96cb9dfc..d8e0f7f1092 100644 --- a/blueprints/model-test/index.js +++ b/blueprints/model-test/index.js @@ -8,8 +8,8 @@ module.exports = useTestFrameworkDetector({ locals: function(options) { var result = ModelBlueprint.locals.apply(this, arguments); - result.friendlyTestDescription = testInfo.description(options.entity.name, "Unit", "Model"); + result.friendlyTestDescription = testInfo.description(options.entity.name, 'Unit', 'Model'); return result; - } + }, }); diff --git a/blueprints/model/index.js b/blueprints/model/index.js index 657c3aeb887..9ea731000dd 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -1,14 +1,11 @@ -var inflection = require('inflection'); +var inflection = require('inflection'); var stringUtils = require('ember-cli-string-utils'); -var EOL = require('os').EOL; +var EOL = require('os').EOL; module.exports = { description: 'Generates an ember-data model.', - anonymousOptions: [ - 'name', - 'attr:type' - ], + anonymousOptions: ['name', 'attr:type'], locals: function(options) { var attrs = []; @@ -55,22 +52,22 @@ module.exports = { return { attrs: attrs, - needs: needs + needs: needs, }; - } + }, }; function dsAttr(name, type) { switch (type) { - case 'belongs-to': - return 'DS.belongsTo(\'' + name + '\')'; - case 'has-many': - return 'DS.hasMany(\'' + name + '\')'; - case '': - //"If you don't specify the type of the attribute, it will be whatever was provided by the server" - //https://emberjs.com/guides/models/defining-models/ - return 'DS.attr()'; - default: - return 'DS.attr(\'' + type + '\')'; + case 'belongs-to': + return "DS.belongsTo('" + name + "')"; + case 'has-many': + return "DS.hasMany('" + name + "')"; + case '': + //"If you don't specify the type of the attribute, it will be whatever was provided by the server" + //https://emberjs.com/guides/models/defining-models/ + return 'DS.attr()'; + default: + return "DS.attr('" + type + "')"; } } diff --git a/blueprints/serializer-test/index.js b/blueprints/serializer-test/index.js index ee11066acd8..a7388eb4efc 100644 --- a/blueprints/serializer-test/index.js +++ b/blueprints/serializer-test/index.js @@ -6,7 +6,7 @@ module.exports = useTestFrameworkDetector({ locals: function(options) { return { - friendlyTestDescription: testInfo.description(options.entity.name, "Unit", "Serializer") + friendlyTestDescription: testInfo.description(options.entity.name, 'Unit', 'Serializer'), }; - } + }, }); diff --git a/blueprints/serializer/index.js b/blueprints/serializer/index.js index 37417997855..704014851f4 100644 --- a/blueprints/serializer/index.js +++ b/blueprints/serializer/index.js @@ -3,11 +3,9 @@ var extendFromApplicationEntity = require('../../lib/utilities/extend-from-appli module.exports = { description: 'Generates an ember-data serializer.', - availableOptions: [ - { name: 'base-class', type: String } - ], + availableOptions: [{ name: 'base-class', type: String }], locals: function(options) { return extendFromApplicationEntity('serializer', 'DS.JSONAPISerializer', options); - } + }, }; diff --git a/blueprints/test-framework-detector.js b/blueprints/test-framework-detector.js index 6b7ef9d3a01..2fa3da77255 100644 --- a/blueprints/test-framework-detector.js +++ b/blueprints/test-framework-detector.js @@ -15,20 +15,20 @@ module.exports = function(blueprint) { let dependencies = this.project.dependencies(); if ('ember-qunit' in dependencies) { type = 'qunit-rfc-232'; - } else if ('ember-cli-qunit' in dependencies) { let checker = new VersionChecker(this.project); - if (fs.existsSync(this.path + '/qunit-rfc-232-files') && checker.for('ember-cli-qunit', 'npm').gte('4.2.0')) { + if ( + fs.existsSync(this.path + '/qunit-rfc-232-files') && + checker.for('ember-cli-qunit', 'npm').gte('4.2.0') + ) { type = 'qunit-rfc-232'; } else { type = 'qunit'; } - } else if ('ember-cli-mocha' in dependencies) { type = 'mocha'; - } else { - this.ui.writeLine('Couldn\'t determine test style - using QUnit'); + this.ui.writeLine("Couldn't determine test style - using QUnit"); type = 'qunit'; } diff --git a/blueprints/transform-test/index.js b/blueprints/transform-test/index.js index 72fad344f52..35d846c0d64 100644 --- a/blueprints/transform-test/index.js +++ b/blueprints/transform-test/index.js @@ -6,7 +6,7 @@ module.exports = useTestFrameworkDetector({ locals: function(options) { return { - friendlyTestDescription: testInfo.description(options.entity.name, "Unit", "Transform") + friendlyTestDescription: testInfo.description(options.entity.name, 'Unit', 'Transform'), }; - } + }, }); diff --git a/blueprints/transform/index.js b/blueprints/transform/index.js index 5f1b96cbe7b..476ff90924a 100644 --- a/blueprints/transform/index.js +++ b/blueprints/transform/index.js @@ -1,3 +1,3 @@ module.exports = { - description: 'Generates an ember-data value transform.' + description: 'Generates an ember-data value transform.', }; diff --git a/config/ember-try.js b/config/ember-try.js index e55993db4f4..fdaa5362d1b 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -6,57 +6,57 @@ module.exports = function() { return Promise.all([ getChannelURL('release'), getChannelURL('beta'), - getChannelURL('canary') - ]).then((urls) => { + getChannelURL('canary'), + ]).then(urls => { return { useYarn: true, scenarios: [ { name: 'default', - bower: { }, - npm: { } + bower: {}, + npm: {}, }, { name: 'ember-lts-2.12', npm: { devDependencies: { - 'ember-source': '~2.12.0' - } - } + 'ember-source': '~2.12.0', + }, + }, }, { name: 'ember-lts-2.16', npm: { devDependencies: { - 'ember-source': '~2.16.0' - } - } + 'ember-source': '~2.16.0', + }, + }, }, { name: 'ember-release', npm: { devDependencies: { - 'ember-source': urls[0] - } - } + 'ember-source': urls[0], + }, + }, }, { name: 'ember-beta', npm: { devDependencies: { - 'ember-source': urls[1] - } - } + 'ember-source': urls[1], + }, + }, }, { name: 'ember-canary', npm: { devDependencies: { - 'ember-source': urls[2] - } - } - } - ] + 'ember-source': urls[2], + }, + }, + }, + ], }; }); }; diff --git a/config/environment.js b/config/environment.js index 28a787b62f4..b5300869ad2 100644 --- a/config/environment.js +++ b/config/environment.js @@ -2,5 +2,5 @@ 'use strict'; module.exports = function(/* environment, appConfig */) { - return { }; + return {}; }; diff --git a/config/s3ProjectConfig.js b/config/s3ProjectConfig.js index 8a45d8e1177..40f5e770d64 100644 --- a/config/s3ProjectConfig.js +++ b/config/s3ProjectConfig.js @@ -1,42 +1,49 @@ -function fileMap(revision,tag,date) { +function fileMap(revision, tag, date) { return { - 'docs/data.json': fileObject('ember-data-docs', '.json', 'application/json', revision, tag, date) + 'docs/data.json': fileObject( + 'ember-data-docs', + '.json', + 'application/json', + revision, + tag, + date + ), }; } -function fileObject(baseName, extension, contentType, currentRevision, tag, date){ +function fileObject(baseName, extension, contentType, currentRevision, tag, date) { var fullName = '/' + baseName + extension; - var obj = { + var obj = { contentType: contentType, - destinations: { - canary: [ - 'latest' + fullName, - 'canary' + fullName, - 'canary/daily/' + date + fullName, - 'canary/shas/' + currentRevision + fullName - ], - release: [ - 'stable' + fullName, - 'release' + fullName, - 'release/daily/' + date + fullName, - 'release/shas/' + currentRevision + fullName - ], - beta: [ - 'beta' + fullName, - 'beta/daily/' + date + fullName, - 'beta/shas/' + currentRevision + fullName - ], - wildcard: [] - } - }; + destinations: { + canary: [ + 'latest' + fullName, + 'canary' + fullName, + 'canary/daily/' + date + fullName, + 'canary/shas/' + currentRevision + fullName, + ], + release: [ + 'stable' + fullName, + 'release' + fullName, + 'release/daily/' + date + fullName, + 'release/shas/' + currentRevision + fullName, + ], + beta: [ + 'beta' + fullName, + 'beta/daily/' + date + fullName, + 'beta/shas/' + currentRevision + fullName, + ], + wildcard: [], + }, + }; - if (tag) { - for (var key in obj.destinations) { - obj.destinations[key].push('tags/' + tag + fullName); - } - } + if (tag) { + for (var key in obj.destinations) { + obj.destinations[key].push('tags/' + tag + fullName); + } + } - return obj; + return obj; } module.exports = fileMap; diff --git a/ember-cli-build.js b/ember-cli-build.js index 7feb9720053..432afc11cd1 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -1,8 +1,8 @@ -"use strict"; +'use strict'; const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); -const merge = require('broccoli-merge-trees'); -const yuidoc = require('./lib/yuidoc'); +const merge = require('broccoli-merge-trees'); +const yuidoc = require('./lib/yuidoc'); module.exports = function(defaults) { let app = new EmberAddon(defaults, {}); diff --git a/index.js b/index.js index 4ea77e5639a..0cee37ca2af 100644 --- a/index.js +++ b/index.js @@ -45,8 +45,10 @@ module.exports = { _prodLikeWarning() { let emberEnv = process.env.EMBER_ENV; - if(emberEnv !== 'production' && /production/.test(emberEnv)) { - this._warn(`Production-like values for EMBER_ENV are deprecated (your EMBER_ENV is "${emberEnv}") and support will be removed in Ember Data 4.0.0. If using ember-cli-deploy, please configure your build using 'production'. Otherwise please set your EMBER_ENV to 'production' for production builds.`); + if (emberEnv !== 'production' && /production/.test(emberEnv)) { + this._warn( + `Production-like values for EMBER_ENV are deprecated (your EMBER_ENV is "${emberEnv}") and support will be removed in Ember Data 4.0.0. If using ember-cli-deploy, please configure your build using 'production'. Otherwise please set your EMBER_ENV to 'production' for production builds.` + ); } }, @@ -84,8 +86,8 @@ module.exports = { config() { return { emberData: { - enableRecordDataRFCBuild: USE_RECORD_DATA_RFC - } + enableRecordDataRFCBuild: USE_RECORD_DATA_RFC, + }, }; }, @@ -100,15 +102,15 @@ module.exports = { let treeWithVersion = merge([ tree, - version() // compile the VERSION into the build + version(), // compile the VERSION into the build ]); let withPrivate; if (USE_RECORD_DATA_RFC) { withPrivate = new Funnel(tree, { - include: ['-record-data-rfc-private/**'] - }); + include: ['-record-data-rfc-private/**'], + }); } else { withPrivate = new Funnel(tree, { include: ['-private/**'] }); } @@ -117,17 +119,17 @@ module.exports = { exclude: [ '-private', '-record-data-rfc-private', - isProductionEnv() && !isInstrumentedBuild() ? '-debug' : false + isProductionEnv() && !isInstrumentedBuild() ? '-debug' : false, ].filter(Boolean), - destDir: 'ember-data' + destDir: 'ember-data', }); let privateTree = babel.transpileTree(this.debugTree(withPrivate, 'babel-private:input'), { babel: this.buildBabelOptions(), 'ember-cli-babel': { - compileModules: false - } + compileModules: false, + }, }); privateTree = this.debugTree(privateTree, 'babel-private:output'); @@ -146,7 +148,7 @@ module.exports = { format: babel.shouldCompileModules() ? 'amd' : 'es', amd: { id: 'ember-data/-private' }, exports: 'named', - } + }, ], external: [ 'ember', @@ -154,23 +156,20 @@ module.exports = { 'ember-data/version', 'ember-data/-debug', 'ember-data/adapters/errors', - '@ember/ordered-set' + '@ember/ordered-set', ], // cache: true|false Defaults to true - } + }, }); privateTree = this.debugTree(privateTree, 'rollup-output'); let destDir = this.getOutputDirForVersion(); - publicTree = new Funnel(publicTree, { destDir }); + publicTree = new Funnel(publicTree, { destDir }); privateTree = new Funnel(privateTree, { destDir }); - return this.debugTree(merge([ - publicTree, - privateTree - ]), 'final'); + return this.debugTree(merge([publicTree, privateTree]), 'final'); }, buildBabelOptions() { @@ -180,10 +179,7 @@ module.exports = { loose: true, plugins: customPlugins.plugins, postTransformPlugins: customPlugins.postTransformPlugins, - exclude: [ - 'transform-es2015-block-scoping', - 'transform-es2015-typeof-symbol' - ] + exclude: ['transform-es2015-block-scoping', 'transform-es2015-typeof-symbol'], }; }, @@ -205,5 +201,5 @@ module.exports = { cacheKeyForTree(treeType) { return calculateCacheKeyForTree(treeType, this); - } + }, }; diff --git a/lib/babel-build.js b/lib/babel-build.js index 6c700db9775..89ac0e7854c 100644 --- a/lib/babel-build.js +++ b/lib/babel-build.js @@ -10,16 +10,16 @@ function getDebugMacroPlugins() { let options = { envFlags: { source: '@glimmer/env', - flags: { DEBUG: !isProduction, CI: !!process.env.CI } + flags: { DEBUG: !isProduction, CI: !!process.env.CI }, }, externalizeHelpers: { - global: 'Ember' + global: 'Ember', }, debugTools: { - source: '@ember/debug' - } + source: '@ember/debug', + }, }; return [DebugMacros, options]; @@ -35,33 +35,41 @@ function babelOptions(libraryName, _options) { moduleRoot: libraryName, moduleIds: true, // Transforms /index.js files to use their containing directory name - getModuleId: function (name) { + getModuleId: function(name) { return name.replace(/\/index$/g, ''); }, resolveModuleSource: function(source, fileName) { return moduleResolve.call(this, source, libraryName + '/' + fileName); - } + }, }; Object.keys(_options).forEach(function(opt) { options[opt] = _options[opt]; }); - options.plugins = options.plugins.concat([ - getDebugMacroPlugins(), - ['ember-modules-api-polyfill', { blacklist: { '@ember/debug': ['assert', 'deprecate', 'warn']} }], - ['transform-es2015-modules-amd', { noInterop: true, loose: true }], - 'transform-es2015-arrow-functions', - 'transform-es2015-computed-properties', - 'transform-es2015-shorthand-properties', - 'transform-es2015-template-literals', - 'transform-es2015-parameters', - 'transform-es2015-destructuring', - 'transform-es2015-spread', - 'transform-es2015-block-scoping', - 'transform-es2015-constants', - ['transform-es2015-classes', { loose: true }], - ], options.postTransformPlugins).filter(Boolean); + options.plugins = options.plugins + .concat( + [ + getDebugMacroPlugins(), + [ + 'ember-modules-api-polyfill', + { blacklist: { '@ember/debug': ['assert', 'deprecate', 'warn'] } }, + ], + ['transform-es2015-modules-amd', { noInterop: true, loose: true }], + 'transform-es2015-arrow-functions', + 'transform-es2015-computed-properties', + 'transform-es2015-shorthand-properties', + 'transform-es2015-template-literals', + 'transform-es2015-parameters', + 'transform-es2015-destructuring', + 'transform-es2015-spread', + 'transform-es2015-block-scoping', + 'transform-es2015-constants', + ['transform-es2015-classes', { loose: true }], + ], + options.postTransformPlugins + ) + .filter(Boolean); // this is not a "real" babel option, so we delete it delete options.postTransformPlugins; diff --git a/lib/enable-optional-features-via-url/index.js b/lib/enable-optional-features-via-url/index.js index 70713bb27c4..2819bec72c2 100644 --- a/lib/enable-optional-features-via-url/index.js +++ b/lib/enable-optional-features-via-url/index.js @@ -11,25 +11,25 @@ module.exports = { the flag to true when there is a `enableoptionalfeatures` query parameter. */ contentFor: function(name) { - if (name === "enable-optional-features") { + if (name === 'enable-optional-features') { var array = [ - "", + ' }', + ' return this._EmberENV;', + ' },', + ' set(value) {', + ' this._EmberENV = value;', + ' }', + '});', + '', ]; return array.join('\n'); } - } + }, }; diff --git a/lib/jscs-rules/disallow-multiple-var-decl-with-assignment.js b/lib/jscs-rules/disallow-multiple-var-decl-with-assignment.js index 838e3e18f3f..dd851874a4d 100644 --- a/lib/jscs-rules/disallow-multiple-var-decl-with-assignment.js +++ b/lib/jscs-rules/disallow-multiple-var-decl-with-assignment.js @@ -22,18 +22,22 @@ module.exports.prototype = { file.iterateNodesByType('VariableDeclaration', function(node) { // allow multiple var declarations in for statement // for (var i = 0, j = myArray.length; i < j; i++) {} - if (node.parentNode.type === 'ForStatement') { return; } + if (node.parentNode.type === 'ForStatement') { + return; + } var hasAssignment = false; var multiDeclaration = node.declarations.length > 1; node.declarations.forEach(function(declaration) { - if (declaration.init) { hasAssignment = true; } + if (declaration.init) { + hasAssignment = true; + } }); if (hasAssignment && multiDeclaration) { errors.add('Multiple assigning variable declarations', node.loc.start); } }); - } + }, }; diff --git a/lib/jscs-rules/disallow-space-before-semicolon.js b/lib/jscs-rules/disallow-space-before-semicolon.js index d755672d1cf..c7c711b38c2 100644 --- a/lib/jscs-rules/disallow-space-before-semicolon.js +++ b/lib/jscs-rules/disallow-space-before-semicolon.js @@ -25,5 +25,5 @@ module.exports.prototype = { errors.add('Spaces are disallowed before semicolons.', i + 1, lines[i].length - 2); } } - } + }, }; diff --git a/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js b/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js index 1245ee81680..cae0a4d67b1 100644 --- a/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js +++ b/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js @@ -43,32 +43,29 @@ module.exports.prototype = { } var roundBraceTokenStart = file.getTokenByRangeStart(nodeBeforeRoundBrace.range[0]); - var roundBraceTokenEnd = file.getTokenByRangeStart(nodeBeforeRoundBrace.range[0]); + var roundBraceTokenEnd = file.getTokenByRangeStart(nodeBeforeRoundBrace.range[0]); do { roundBraceTokenStart = file.findNextToken(roundBraceTokenStart, 'Punctuator', '('); - roundBraceTokenEnd = file.findNextToken(roundBraceTokenEnd, 'Punctuator', ')'); + roundBraceTokenEnd = file.findNextToken(roundBraceTokenEnd, 'Punctuator', ')'); } while (roundBraceTokenStart.range[0] < nodeBeforeRoundBrace.range[1]); var firstArg = nodeBeforeRoundBrace.parentNode.arguments[0]; - var lastArg = nodeBeforeRoundBrace.parentNode.arguments[nodeBeforeRoundBrace.parentNode.arguments.length - 1]; + var lastArg = + nodeBeforeRoundBrace.parentNode.arguments[ + nodeBeforeRoundBrace.parentNode.arguments.length - 1 + ]; - var spaceAfterOpeningRoundBraceExists = spaceAfterBrace(firstArg, roundBraceTokenStart); + var spaceAfterOpeningRoundBraceExists = spaceAfterBrace(firstArg, roundBraceTokenStart); var spaceBeforeClosingRoundBraceExists = spaceBeforeBrace(lastArg, roundBraceTokenEnd); if (spaceAfterOpeningRoundBraceExists) { - errors.add( - 'Illegal space after opening round brace', - roundBraceTokenStart.loc.start - ); + errors.add('Illegal space after opening round brace', roundBraceTokenStart.loc.start); } if (spaceBeforeClosingRoundBraceExists) { - errors.add( - 'Illegal space before closing round brace', - roundBraceTokenEnd.loc.start - ); + errors.add('Illegal space before closing round brace', roundBraceTokenEnd.loc.start); } }); - } + }, }; diff --git a/lib/jscs-rules/require-spaces-after-closing-parenthesis-in-function-declaration.js b/lib/jscs-rules/require-spaces-after-closing-parenthesis-in-function-declaration.js index 690574ad3a3..62120235446 100644 --- a/lib/jscs-rules/require-spaces-after-closing-parenthesis-in-function-declaration.js +++ b/lib/jscs-rules/require-spaces-after-closing-parenthesis-in-function-declaration.js @@ -32,17 +32,11 @@ module.exports.prototype = { if (beforeOpeningRoundBrace) { if (nextToken) { - errors.add( - 'Missing space before opening round brace', - nextToken.loc.start - ); + errors.add('Missing space before opening round brace', nextToken.loc.start); } } else { if (!nextToken) { - errors.add( - 'Illegal space before opening round brace', - functionToken.loc.end - ); + errors.add('Illegal space before opening round brace', functionToken.loc.end); } } @@ -51,19 +45,13 @@ module.exports.prototype = { if (beforeOpeningCurlyBrace) { if (tokenBeforeBody) { - errors.add( - 'Missing space before opening curly brace', - tokenBeforeBody.loc.start - ); + errors.add('Missing space before opening curly brace', tokenBeforeBody.loc.start); } } else { if (!tokenBeforeBody) { - errors.add( - 'Illegal space before opening curly brace', - node.body.loc.end - ); + errors.add('Illegal space before opening curly brace', node.body.loc.end); } } }); - } + }, }; diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 8302ab7ae43..4806655243e 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -5,14 +5,14 @@ var fs = require('fs'); var resolve = require('resolve'); var FilterImports = requireBabelPlugin('babel-plugin-filter-imports'); -var FeatureFlags = requireBabelPlugin('babel-plugin-feature-flags'); +var FeatureFlags = requireBabelPlugin('babel-plugin-feature-flags'); var StripHeimdall = requireBabelPlugin('babel6-plugin-strip-heimdall'); var StripClassCallCheck = requireBabelPlugin('babel6-plugin-strip-class-callcheck'); var StripFilteredImports = require('./transforms/babel-plugin-remove-imports'); var TransformBlockScoping = requireBabelPlugin('babel-plugin-transform-es2015-block-scoping'); function uniqueAdd(obj, key, values) { - var a = obj[key] = obj[key] || []; + var a = (obj[key] = obj[key] || []); for (var i = 0; i < values.length; i++) { if (a.indexOf(values[i]) === -1) { @@ -60,10 +60,13 @@ module.exports = function(environment) { var postTransformPlugins = []; var plugins = [ - [FeatureFlags, { - import: { module: 'ember-data/-private/features' }, - features: features - }] + [ + FeatureFlags, + { + import: { module: 'ember-data/-private/features' }, + features: features, + }, + ], ]; if (process.env.INSTRUMENT_HEIMDALL === 'false') { @@ -76,15 +79,13 @@ module.exports = function(environment) { if (/production/.test(environment) || process.env.INSTRUMENT_HEIMDALL === 'true') { postTransformPlugins.push([StripClassCallCheck]); - uniqueAdd(filteredImports, 'ember-data/-debug', [ - 'assertPolymorphicType' - ]); + uniqueAdd(filteredImports, 'ember-data/-debug', ['assertPolymorphicType']); } plugins.push( [FilterImports, filteredImports], [StripFilteredImports, filteredImports], - [TransformBlockScoping, { 'throwIfClosureRequired': true }] + [TransformBlockScoping, { throwIfClosureRequired: true }] ); return { plugins, postTransformPlugins }; diff --git a/lib/stripped-build.js b/lib/stripped-build.js index 19ea9404ca4..f70e7a8723c 100644 --- a/lib/stripped-build.js +++ b/lib/stripped-build.js @@ -1,4 +1,4 @@ -var babelBuild = require('./babel-build'); +var babelBuild = require('./babel-build'); var strippedBuildPlugins = require('./stripped-build-plugins'); module.exports = function(packageName, tree, environmentBuildingFor) { diff --git a/lib/transforms/babel-plugin-remove-imports.js b/lib/transforms/babel-plugin-remove-imports.js index 2b4b92631ab..4d39e5b59bb 100644 --- a/lib/transforms/babel-plugin-remove-imports.js +++ b/lib/transforms/babel-plugin-remove-imports.js @@ -20,7 +20,7 @@ function PluginRemoveFilteredImports() { }); importDeclarationsToRemove = undefined; - } + }, }, ImportDeclaration: function(path) { @@ -56,9 +56,8 @@ function PluginRemoveFilteredImports() { } } } - } - - } + }, + }, }; } diff --git a/lib/utilities/extend-from-application-entity.js b/lib/utilities/extend-from-application-entity.js index c166356d738..0cdcac2431c 100644 --- a/lib/utilities/extend-from-application-entity.js +++ b/lib/utilities/extend-from-application-entity.js @@ -1,38 +1,46 @@ -var stringUtil = require('ember-cli-string-utils'); +var stringUtil = require('ember-cli-string-utils'); var SilentError = require('silent-error'); -var pathUtil = require('ember-cli-path-utils'); -var fs = require('fs'); -var path = require('path'); +var pathUtil = require('ember-cli-path-utils'); +var fs = require('fs'); +var path = require('path'); module.exports = function(type, baseClass, options) { - var entityName = options.entity.name; - var isAddon = options.inRepoAddon || options.project.isEmberCLIAddon(); - var relativePath = pathUtil.getRelativePath(options.entity.name); + var entityName = options.entity.name; + var isAddon = options.inRepoAddon || options.project.isEmberCLIAddon(); + var relativePath = pathUtil.getRelativePath(options.entity.name); if (options.pod && options.podPath) { relativePath = pathUtil.getRelativePath(options.podPath + options.entity.name); } var entityDirectory = type + 's'; - var applicationEntityPath = path.join(options.project.root, 'app', entityDirectory, 'application.js'); + var applicationEntityPath = path.join( + options.project.root, + 'app', + entityDirectory, + 'application.js' + ); var hasApplicationEntity = fs.existsSync(applicationEntityPath); if (!isAddon && !options.baseClass && entityName !== 'application' && hasApplicationEntity) { options.baseClass = 'application'; } if (options.baseClass === entityName) { - throw new SilentError(stringUtil.classify(type) + 's cannot extend from themself. To resolve this, remove the `--base-class` option or change to a different base-class.'); + throw new SilentError( + stringUtil.classify(type) + + 's cannot extend from themself. To resolve this, remove the `--base-class` option or change to a different base-class.' + ); } - var importStatement = 'import DS from \'ember-data\';'; + var importStatement = "import DS from 'ember-data';"; if (options.baseClass) { baseClass = stringUtil.classify(options.baseClass.replace('/', '-')); baseClass = baseClass + stringUtil.classify(type); - importStatement = 'import ' + baseClass + ' from \'' + relativePath + options.baseClass + '\';'; + importStatement = 'import ' + baseClass + " from '" + relativePath + options.baseClass + "';"; } return { importStatement: importStatement, - baseClass: baseClass + baseClass: baseClass, }; }; diff --git a/lib/version-replace.js b/lib/version-replace.js index 56eeb8f1574..d8d694855e3 100644 --- a/lib/version-replace.js +++ b/lib/version-replace.js @@ -7,7 +7,7 @@ module.exports = function configFiles(tree) { files: ['*.{json,js}'], pattern: { match: /VERSION_STRING_PLACEHOLDER/g, - replacement: version - } + replacement: version, + }, }); }; diff --git a/lib/yuidoc.js b/lib/yuidoc.js index 37f201b3dd2..7b560eb2ee5 100644 --- a/lib/yuidoc.js +++ b/lib/yuidoc.js @@ -1,20 +1,19 @@ -var YUIDoc = require('broccoli-yuidoc'); +var YUIDoc = require('broccoli-yuidoc'); var calculateVersion = require('./calculate-version'); module.exports = function yui() { return new YUIDoc(['addon', 'node_modules/ember-inflector/addon'], { destDir: 'docs', yuidoc: { - "name": "The ember-data API", - "description": "The ember-data API: a data persistence library for Ember.js", - "version": calculateVersion(), - "logo": "http://f.cl.ly/items/1A1L432s022u1O1q1V3p/ember%20logo.png", - "url": "https://github.com/emberjs/data", - "options": { - "exclude": "vendor", - "outdir": "docs/build" - } - } + name: 'The ember-data API', + description: 'The ember-data API: a data persistence library for Ember.js', + version: calculateVersion(), + logo: 'http://f.cl.ly/items/1A1L432s022u1O1q1V3p/ember%20logo.png', + url: 'https://github.com/emberjs/data', + options: { + exclude: 'vendor', + outdir: 'docs/build', + }, + }, }); }; - diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index a4e244cd00b..23dbcc55f76 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -22,74 +22,81 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { return emberNew(); }); - it('adapter', function() { let args = ['adapter', 'foo']; return emberGenerateDestroy(args, _file => { - expect(_file('app/adapters/foo.js')) - .to.contain('import DS from \'ember-data\';') - .to.contain('export default DS.JSONAPIAdapter.extend({'); + expect(_file('app/adapters/foo.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.JSONAPIAdapter.extend({'); - expect(_file('tests/unit/adapters/foo-test.js')) - .to.equal(fixture('adapter-test/foo-default.js')); - }); + expect(_file('tests/unit/adapters/foo-test.js')).to.equal( + fixture('adapter-test/foo-default.js') + ); + }); }); it('adapter extends application adapter if it exists', function() { let args = ['adapter', 'foo']; - return emberGenerate(['adapter', 'application']) - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerate(['adapter', 'application']).then(() => + emberGenerateDestroy(args, _file => { expect(_file('app/adapters/foo.js')) - .to.contain('import ApplicationAdapter from \'./application\';') + .to.contain("import ApplicationAdapter from './application';") .to.contain('export default ApplicationAdapter.extend({'); - expect(_file('tests/unit/adapters/foo-test.js')) - .to.equal(fixture('adapter-test/foo-default.js')); - })); + expect(_file('tests/unit/adapters/foo-test.js')).to.equal( + fixture('adapter-test/foo-default.js') + ); + }) + ); }); it('adapter with --base-class', function() { let args = ['adapter', 'foo', '--base-class=bar']; return emberGenerateDestroy(args, _file => { - expect(_file('app/adapters/foo.js')) - .to.contain('import BarAdapter from \'./bar\';') - .to.contain('export default BarAdapter.extend({'); + expect(_file('app/adapters/foo.js')) + .to.contain("import BarAdapter from './bar';") + .to.contain('export default BarAdapter.extend({'); - expect(_file('tests/unit/adapters/foo-test.js')) - .to.equal(fixture('adapter-test/foo-default.js')); - }); + expect(_file('tests/unit/adapters/foo-test.js')).to.equal( + fixture('adapter-test/foo-default.js') + ); + }); }); xit('adapter throws when --base-class is same as name', function() { let args = ['adapter', 'foo', '--base-class=foo']; - return expect(emberGenerate(args)) - .to.be.rejectedWith(SilentError, /Adapters cannot extend from themself/); + return expect(emberGenerate(args)).to.be.rejectedWith( + SilentError, + /Adapters cannot extend from themself/ + ); }); it('adapter when is named "application"', function() { let args = ['adapter', 'application']; return emberGenerateDestroy(args, _file => { - expect(_file('app/adapters/application.js')) - .to.contain('import DS from \'ember-data\';') - .to.contain('export default DS.JSONAPIAdapter.extend({'); + expect(_file('app/adapters/application.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.JSONAPIAdapter.extend({'); - expect(_file('tests/unit/adapters/application-test.js')) - .to.equal(fixture('adapter-test/application-default.js')); - }); + expect(_file('tests/unit/adapters/application-test.js')).to.equal( + fixture('adapter-test/application-default.js') + ); + }); }); it('adapter-test', function() { let args = ['adapter-test', 'foo']; return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/adapters/foo-test.js')) - .to.equal(fixture('adapter-test/foo-default.js')); - }); + expect(_file('tests/unit/adapters/foo-test.js')).to.equal( + fixture('adapter-test/foo-default.js') + ); + }); }); describe('adapter-test with ember-cli-qunit@4.2.0', function() { @@ -99,18 +106,18 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { it('adapter-test-test foo', function() { return emberGenerateDestroy(['adapter-test', 'foo'], _file => { - expect(_file('tests/unit/adapters/foo-test.js')) - .to.equal(fixture('adapter-test/rfc232.js')); + expect(_file('tests/unit/adapters/foo-test.js')).to.equal( + fixture('adapter-test/rfc232.js') + ); }); }); }); - describe('with ember-cli-mocha v0.12+', function() { beforeEach(function() { modifyPackages([ { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-cli-mocha', dev: true } + { name: 'ember-cli-mocha', dev: true }, ]); generateFakePackageManifest('ember-cli-mocha', '0.12.0'); }); @@ -119,10 +126,10 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { let args = ['adapter-test', 'foo']; return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/adapters/foo-test.js')) - .to.equal(fixture('adapter-test/foo-mocha-0.12.js')); + expect(_file('tests/unit/adapters/foo-test.js')).to.equal( + fixture('adapter-test/foo-mocha-0.12.js') + ); }); }); }); - }); diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index 53ddf1352ab..820411b1d27 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -12,7 +12,6 @@ const expect = chai.expect; const generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); const fixture = require('../helpers/fixture'); - describe('Acceptance: generate and destroy model blueprints', function() { setupTestHooks(this); @@ -20,18 +19,16 @@ describe('Acceptance: generate and destroy model blueprints', function() { return emberNew(); }); - it('model', function() { let args = ['model', 'foo']; return emberGenerateDestroy(args, _file => { - expect(_file('app/models/foo.js')) - .to.contain('import DS from \'ember-data\';') - .to.contain('export default DS.Model.extend('); + expect(_file('app/models/foo.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.Model.extend('); - expect(_file('tests/unit/models/foo-test.js')) - .to.equal(fixture('model-test/foo-default.js')); - }); + expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/foo-default.js')); + }); }); it('model with attrs', function() { @@ -45,64 +42,64 @@ describe('Acceptance: generate and destroy model blueprints', function() { 'someObject:object', 'age:number', 'name:string', - 'customAttr:custom-transform' + 'customAttr:custom-transform', ]; return emberGenerateDestroy(args, _file => { - expect(_file('app/models/foo.js')) - .to.contain('import DS from \'ember-data\';') - .to.contain('export default DS.Model.extend(') - .to.contain('misc: DS.attr()') - .to.contain('skills: DS.attr(\'array\')') - .to.contain('isActive: DS.attr(\'boolean\')') - .to.contain('birthday: DS.attr(\'date\')') - .to.contain('someObject: DS.attr(\'object\')') - .to.contain('age: DS.attr(\'number\')') - .to.contain('name: DS.attr(\'string\')') - .to.contain('customAttr: DS.attr(\'custom-transform\')'); - - expect(_file('tests/unit/models/foo-test.js')) - .to.equal(fixture('model-test/foo-default.js')); - }); + expect(_file('app/models/foo.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.Model.extend(') + .to.contain('misc: DS.attr()') + .to.contain("skills: DS.attr('array')") + .to.contain("isActive: DS.attr('boolean')") + .to.contain("birthday: DS.attr('date')") + .to.contain("someObject: DS.attr('object')") + .to.contain("age: DS.attr('number')") + .to.contain("name: DS.attr('string')") + .to.contain("customAttr: DS.attr('custom-transform')"); + + expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/foo-default.js')); + }); }); it('model with belongsTo', function() { let args = ['model', 'comment', 'post:belongs-to', 'author:belongs-to:user']; return emberGenerateDestroy(args, _file => { - expect(_file('app/models/comment.js')) - .to.contain('import DS from \'ember-data\';') - .to.contain('export default DS.Model.extend(') - .to.contain('post: DS.belongsTo(\'post\')') - .to.contain('author: DS.belongsTo(\'user\')'); - - expect(_file('tests/unit/models/comment-test.js')) - .to.equal(fixture('model-test/comment-default.js')); - }); + expect(_file('app/models/comment.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.Model.extend(') + .to.contain("post: DS.belongsTo('post')") + .to.contain("author: DS.belongsTo('user')"); + + expect(_file('tests/unit/models/comment-test.js')).to.equal( + fixture('model-test/comment-default.js') + ); + }); }); it('model with hasMany', function() { let args = ['model', 'post', 'comments:has-many', 'otherComments:has-many:comment']; return emberGenerateDestroy(args, _file => { - expect(_file('app/models/post.js')) - .to.contain('import DS from \'ember-data\';') - .to.contain('export default DS.Model.extend(') - .to.contain('comments: DS.hasMany(\'comment\')') - .to.contain('otherComments: DS.hasMany(\'comment\')'); - - expect(_file('tests/unit/models/post-test.js')) - .to.equal(fixture('model-test/post-default.js')); - }); + expect(_file('app/models/post.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.Model.extend(') + .to.contain("comments: DS.hasMany('comment')") + .to.contain("otherComments: DS.hasMany('comment')"); + + expect(_file('tests/unit/models/post-test.js')).to.equal( + fixture('model-test/post-default.js') + ); + }); }); it('model-test', function() { let args = ['model-test', 'foo']; return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/models/foo-test.js')) - .to.equal(fixture('model-test/foo-default.js')); - }); + expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/foo-default.js')); + }); }); describe('model-test with ember-cli-qunit@4.2.0', function() { @@ -112,18 +109,16 @@ describe('Acceptance: generate and destroy model blueprints', function() { it('model-test-test foo', function() { return emberGenerateDestroy(['model-test', 'foo'], _file => { - expect(_file('tests/unit/models/foo-test.js')) - .to.equal(fixture('model-test/rfc232.js')); + expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/rfc232.js')); }); }); }); - describe('with ember-cli-mocha v0.12+', function() { beforeEach(function() { modifyPackages([ { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-cli-mocha', dev: true } + { name: 'ember-cli-mocha', dev: true }, ]); generateFakePackageManifest('ember-cli-mocha', '0.12.0'); }); @@ -132,8 +127,9 @@ describe('Acceptance: generate and destroy model blueprints', function() { let args = ['model-test', 'foo']; return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/models/foo-test.js')) - .to.equal(fixture('model-test/foo-mocha-0.12.js')); + expect(_file('tests/unit/models/foo-test.js')).to.equal( + fixture('model-test/foo-mocha-0.12.js') + ); }); }); }); diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index 76ccf58623c..0c67640092a 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -18,7 +18,6 @@ const fixture = require('../helpers/fixture'); describe('Acceptance: generate and destroy serializer blueprints', function() { setupTestHooks(this); - beforeEach(function() { return emberNew(); }); @@ -27,69 +26,77 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { let args = ['serializer', 'foo']; return emberGenerateDestroy(args, _file => { - expect(_file('app/serializers/foo.js')) - .to.contain('import DS from \'ember-data\';') - .to.contain('export default DS.JSONAPISerializer.extend('); + expect(_file('app/serializers/foo.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.JSONAPISerializer.extend('); - expect(_file('tests/unit/serializers/foo-test.js')) - .to.equal(fixture('serializer-test/foo-default.js')); - }); + expect(_file('tests/unit/serializers/foo-test.js')).to.equal( + fixture('serializer-test/foo-default.js') + ); + }); }); it('serializer extends application serializer if it exists', function() { let args = ['serializer', 'foo']; - return emberGenerate(['serializer', 'application']) - .then(() => emberGenerateDestroy(args, _file => { + return emberGenerate(['serializer', 'application']).then(() => + emberGenerateDestroy(args, _file => { expect(_file('app/serializers/foo.js')) - .to.contain('import ApplicationSerializer from \'./application\';') + .to.contain("import ApplicationSerializer from './application';") .to.contain('export default ApplicationSerializer.extend({'); - expect(_file('tests/unit/serializers/foo-test.js')) - .to.equal(fixture('serializer-test/foo-default.js')); - })); + expect(_file('tests/unit/serializers/foo-test.js')).to.equal( + fixture('serializer-test/foo-default.js') + ); + }) + ); }); it('serializer with --base-class', function() { let args = ['serializer', 'foo', '--base-class=bar']; return emberGenerateDestroy(args, _file => { - expect(_file('app/serializers/foo.js')) - .to.contain('import BarSerializer from \'./bar\';') - .to.contain('export default BarSerializer.extend({'); + expect(_file('app/serializers/foo.js')) + .to.contain("import BarSerializer from './bar';") + .to.contain('export default BarSerializer.extend({'); - expect(_file('tests/unit/serializers/foo-test.js')) - .to.equal(fixture('serializer-test/foo-default.js')); - }); + expect(_file('tests/unit/serializers/foo-test.js')).to.equal( + fixture('serializer-test/foo-default.js') + ); + }); }); xit('serializer throws when --base-class is same as name', function() { let args = ['serializer', 'foo', '--base-class=foo']; - return expect(emberGenerate(args)) - .to.be.rejectedWith(SilentError, /Serializers cannot extend from themself/); + return expect(emberGenerate(args)).to.be.rejectedWith( + SilentError, + /Serializers cannot extend from themself/ + ); }); it('serializer when is named "application"', function() { let args = ['serializer', 'application']; return emberGenerateDestroy(args, _file => { - expect(_file('app/serializers/application.js')) - .to.contain('import DS from \'ember-data\';') - .to.contain('export default DS.JSONAPISerializer.extend({'); + expect(_file('app/serializers/application.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.JSONAPISerializer.extend({'); - expect(_file('tests/unit/serializers/application-test.js')) - .to.equal(fixture('serializer-test/application-default.js')); - }); + expect(_file('tests/unit/serializers/application-test.js')).to.equal( + fixture('serializer-test/application-default.js') + ); + }); }); it('serializer-test', function() { let args = ['serializer-test', 'foo']; return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/serializers/foo-test.js')) - .to.equal(fixture('serializer-test/foo-default.js')); - }); + expect(_file('tests/unit/serializers/foo-test.js')).to.equal( + fixture('serializer-test/foo-default.js') + ); + }); }); describe('serializer-test with ember-cli-qunit@4.2.0', function() { @@ -99,8 +106,9 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { it('serializer-test-test foo', function() { return emberGenerateDestroy(['serializer-test', 'foo'], _file => { - expect(_file('tests/unit/serializers/foo-test.js')) - .to.equal(fixture('serializer-test/rfc232.js')); + expect(_file('tests/unit/serializers/foo-test.js')).to.equal( + fixture('serializer-test/rfc232.js') + ); }); }); }); @@ -109,7 +117,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { beforeEach(function() { modifyPackages([ { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-cli-mocha', dev: true } + { name: 'ember-cli-mocha', dev: true }, ]); generateFakePackageManifest('ember-cli-mocha', '0.12.0'); }); @@ -118,10 +126,10 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { let args = ['serializer-test', 'foo']; return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/serializers/foo-test.js')) - .to.equal(fixture('serializer-test/foo-mocha-0.12.js')); + expect(_file('tests/unit/serializers/foo-test.js')).to.equal( + fixture('serializer-test/foo-mocha-0.12.js') + ); }); }); }); - }); diff --git a/node-tests/blueprints/transform-test.js b/node-tests/blueprints/transform-test.js index 525c34c4604..29add489003 100644 --- a/node-tests/blueprints/transform-test.js +++ b/node-tests/blueprints/transform-test.js @@ -20,19 +20,19 @@ describe('Acceptance: generate and destroy transform blueprints', function() { return emberNew(); }); - it('transform', function() { let args = ['transform', 'foo']; return emberGenerateDestroy(args, _file => { expect(_file('app/transforms/foo.js')) - .to.contain('import DS from \'ember-data\';') + .to.contain("import DS from 'ember-data';") .to.contain('export default DS.Transform.extend(') .to.contain('deserialize(serialized) {') .to.contain('serialize(deserialized) {'); - expect(_file('tests/unit/transforms/foo-test.js')) - .to.equal(fixture('transform-test/default.js')); + expect(_file('tests/unit/transforms/foo-test.js')).to.equal( + fixture('transform-test/default.js') + ); }); }); @@ -40,8 +40,9 @@ describe('Acceptance: generate and destroy transform blueprints', function() { let args = ['transform-test', 'foo']; return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/transforms/foo-test.js')) - .to.equal(fixture('transform-test/default.js')); + expect(_file('tests/unit/transforms/foo-test.js')).to.equal( + fixture('transform-test/default.js') + ); }); }); @@ -52,18 +53,18 @@ describe('Acceptance: generate and destroy transform blueprints', function() { it('transform-test-test foo', function() { return emberGenerateDestroy(['transform-test', 'foo'], _file => { - expect(_file('tests/unit/transforms/foo-test.js')) - .to.equal(fixture('transform-test/rfc232.js')); + expect(_file('tests/unit/transforms/foo-test.js')).to.equal( + fixture('transform-test/rfc232.js') + ); }); }); }); - describe('with ember-cli-mocha v0.12+', function() { beforeEach(function() { modifyPackages([ { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-cli-mocha', dev: true } + { name: 'ember-cli-mocha', dev: true }, ]); generateFakePackageManifest('ember-cli-mocha', '0.12.0'); }); @@ -72,8 +73,9 @@ describe('Acceptance: generate and destroy transform blueprints', function() { let args = ['transform-test', 'foo']; return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/transforms/foo-test.js')) - .to.equal(fixture('transform-test/mocha-0.12.js')); + expect(_file('tests/unit/transforms/foo-test.js')).to.equal( + fixture('transform-test/mocha-0.12.js') + ); }); }); }); diff --git a/node-tests/helpers/generate-fake-package-manifest.js b/node-tests/helpers/generate-fake-package-manifest.js index d6f92f1f5a9..ca16d36cc44 100644 --- a/node-tests/helpers/generate-fake-package-manifest.js +++ b/node-tests/helpers/generate-fake-package-manifest.js @@ -7,7 +7,10 @@ module.exports = function generateFakePackageManifest(name, version) { if (!fs.existsSync('node_modules/' + name)) { fs.mkdirSync('node_modules/' + name); } - fs.writeFileSync('node_modules/' + name + '/package.json', JSON.stringify({ - version: version, - })); + fs.writeFileSync( + 'node_modules/' + name + '/package.json', + JSON.stringify({ + version: version, + }) + ); }; diff --git a/node-tests/nodetest-runner.js b/node-tests/nodetest-runner.js index caf05ba204b..e909e06564d 100644 --- a/node-tests/nodetest-runner.js +++ b/node-tests/nodetest-runner.js @@ -2,7 +2,7 @@ /* eslint-disable no-console, no-process-exit */ -if (/^win/.test(require('os').platform())){ +if (/^win/.test(require('os').platform())) { // don't run these tests in windows right now, they don't work process.exit(0); } @@ -17,11 +17,13 @@ rimraf.sync('.node_modules-tmp'); rimraf.sync('.bower_components-tmp'); var root = 'node-tests/{blueprints,acceptance,unit}'; -var _checkOnlyInTests = RSVP.denodeify(mochaOnlyDetector.checkFolder.bind(null, root + '/**/*{-test}.js')); +var _checkOnlyInTests = RSVP.denodeify( + mochaOnlyDetector.checkFolder.bind(null, root + '/**/*{-test}.js') +); var optionOrFile = process.argv[2]; var mocha = new Mocha({ timeout: 5000, - reporter: 'spec' + reporter: 'spec', }); var testFiles = glob.sync(root + '/**/*-test.js'); /*var jshintPosition = testFiles.indexOf('tests/unit/jshint-test.js'); @@ -33,14 +35,14 @@ if (optionOrFile === 'all') { addFiles(mocha, testFiles); addFiles(mocha, 'node-tests/**/*-test.js'); addFiles(mocha, '/**/*-test-slow.js'); -} else if (process.argv.length > 2) { +} else if (process.argv.length > 2) { addFiles(mocha, process.argv.slice(2)); } else { addFiles(mocha, testFiles); } function addFiles(mocha, files) { - files = (typeof files === 'string') ? glob.sync(root + files) : files; + files = typeof files === 'string' ? glob.sync(root + files) : files; files.forEach(mocha.addFile.bind(mocha)); } diff --git a/node-tests/unit/babel-plugin-remove-imports-test.js b/node-tests/unit/babel-plugin-remove-imports-test.js index c2816d57c90..b01980d9b4c 100644 --- a/node-tests/unit/babel-plugin-remove-imports-test.js +++ b/node-tests/unit/babel-plugin-remove-imports-test.js @@ -20,10 +20,10 @@ describe('Unit: babel-plugin-remove-filtered-imports', function() { let input, output; function transform(code) { - return co.wrap(function* () { + return co.wrap(function*() { input.write({ 'test.js': code }); let babel = new Babel(input.path(), { - plugins + plugins, }); output = createBuilder(babel); @@ -36,26 +36,28 @@ describe('Unit: babel-plugin-remove-filtered-imports', function() { })(); } - beforeEach(co.wrap(function* () { - pluginOptions = {}; + beforeEach( + co.wrap(function*() { + pluginOptions = {}; - plugins = [ - [StripFilteredImports, pluginOptions] - ]; + plugins = [[StripFilteredImports, pluginOptions]]; - input = yield createTempDir(); - })); + input = yield createTempDir(); + }) + ); - afterEach(co.wrap(function* () { - if (input) { - yield input.dispose(); - } - if (output) { - yield output.dispose(); - } + afterEach( + co.wrap(function*() { + if (input) { + yield input.dispose(); + } + if (output) { + yield output.dispose(); + } - input = output = undefined; - })); + input = output = undefined; + }) + ); it('Returns a plugin', function() { let plugin = StripFilteredImports(); @@ -63,20 +65,25 @@ describe('Unit: babel-plugin-remove-filtered-imports', function() { expect(plugin).to.be.ok; }); - it('Does not alter a file if no imports are meant to be filtered', co.wrap(function*() { - const input = stripIndent` + it( + 'Does not alter a file if no imports are meant to be filtered', + co.wrap(function*() { + const input = stripIndent` import Foo from 'bar'; import { baz } from 'none'; import * as drinks from 'drinks'; import 'bem'; `; - const result = yield transform(input); + const result = yield transform(input); - expect(result).to.equal(stripNewlines(input)); - })); + expect(result).to.equal(stripNewlines(input)); + }) + ); - it('Properly strips desired imports and specifiers', co.wrap(function*() { - const input = stripIndent` + it( + 'Properly strips desired imports and specifiers', + co.wrap(function*() { + const input = stripIndent` import Foo from 'bar'; import { bit } from 'wow'; import { baz, bell } from 'none'; @@ -88,23 +95,24 @@ describe('Unit: babel-plugin-remove-filtered-imports', function() { import 'bell'; `; - pluginOptions.none = ['baz']; - pluginOptions.bar = true; - pluginOptions.drinks = '*'; - pluginOptions.wow = ['bit']; - pluginOptions.bem = ['biz']; - pluginOptions.bosh = '*'; - pluginOptions.dranks = ['bex']; - pluginOptions.bell = true; + pluginOptions.none = ['baz']; + pluginOptions.bar = true; + pluginOptions.drinks = '*'; + pluginOptions.wow = ['bit']; + pluginOptions.bem = ['biz']; + pluginOptions.bosh = '*'; + pluginOptions.dranks = ['bex']; + pluginOptions.bell = true; - const expectedOutput = stripNewlines(stripIndent` + const expectedOutput = stripNewlines(stripIndent` import { bell } from 'none'; import { foo } from 'happy'; import * as dranks from 'dranks'; import 'bem'; `); - const result = yield transform(input); + const result = yield transform(input); - expect(result).to.equal(expectedOutput); - })); + expect(result).to.equal(expectedOutput); + }) + ); }); diff --git a/testem.js b/testem.js index 0e0b3601de1..cc773d51c58 100644 --- a/testem.js +++ b/testem.js @@ -1,14 +1,10 @@ module.exports = { - "framework": "qunit", - "test_page": "tests/index.html?hidepassed", - "disable_watching": true, - "reporter": "dot", - "launch_in_ci": [ - "Chrome" - ], - "launch_in_dev": [ - "Chrome" - ], + framework: 'qunit', + test_page: 'tests/index.html?hidepassed', + disable_watching: true, + reporter: 'dot', + launch_in_ci: ['Chrome'], + launch_in_dev: ['Chrome'], browser_args: { Chrome: { mode: 'ci', @@ -17,8 +13,8 @@ module.exports = { '--headless', '--remote-debugging-port=0', '--window-size=1440,900', - '--no-sandbox' - ] - } - } + '--no-sandbox', + ], + }, + }, }; diff --git a/tests/dummy/app/app.js b/tests/dummy/app/app.js index b3b2bd677e0..f08aaaf0304 100644 --- a/tests/dummy/app/app.js +++ b/tests/dummy/app/app.js @@ -6,7 +6,7 @@ import config from './config/environment'; const App = Application.extend({ modulePrefix: config.modulePrefix, podModulePrefix: config.podModulePrefix, - Resolver + Resolver, }); loadInitializers(App, config.modulePrefix); diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js index 53c53c6c075..8f6f4598916 100644 --- a/tests/dummy/app/router.js +++ b/tests/dummy/app/router.js @@ -3,7 +3,7 @@ import config from './config/environment'; const Router = EmberRouter.extend({ location: config.locationType, - rootURL: config.rootURL + rootURL: config.rootURL, }); Router.map(function() {}); diff --git a/tests/dummy/app/routes/application/route.js b/tests/dummy/app/routes/application/route.js index 6c74252aa1b..d09f667b240 100644 --- a/tests/dummy/app/routes/application/route.js +++ b/tests/dummy/app/routes/application/route.js @@ -1,4 +1,3 @@ import Route from '@ember/routing/route'; -export default Route.extend({ -}); +export default Route.extend({}); diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index 81d1ede135d..8f6ea148349 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -15,13 +15,13 @@ module.exports = function(environment) { locationType: 'auto', EmberENV: { FEATURES: featureFlags, - RAISE_ON_DEPRECATION: false + RAISE_ON_DEPRECATION: false, }, APP: { // Here you can pass flags/options to your application instance // when it is created - } + }, }; if (environment === 'test-optional-features') { diff --git a/tests/helpers/async.js b/tests/helpers/async.js index 5a0e787af55..40a5e12c93d 100644 --- a/tests/helpers/async.js +++ b/tests/helpers/async.js @@ -5,7 +5,7 @@ export function wait(callback, timeout) { let done = this.async(); let timer = setTimeout(() => { - this.ok(false, "Timeout was reached"); + this.ok(false, 'Timeout was reached'); done(); }, timeout || 200); @@ -24,15 +24,13 @@ export function wait(callback, timeout) { } export function asyncEqual(a, b, message) { - return all([ - resolve(a), - resolve(b) - ]).then(this.wait((array) => { - this.push(array[0] === array[1], array[0], array[1], message); - })); + return all([resolve(a), resolve(b)]).then( + this.wait(array => { + this.push(array[0] === array[1], array[0], array[1], message); + }) + ); } export function invokeAsync(callback, timeout = 1) { setTimeout(this.wait(callback, timeout + 100), timeout); } - diff --git a/tests/helpers/module-for-acceptance.js b/tests/helpers/module-for-acceptance.js index 0daf9c9a7e2..53ef0cfac24 100644 --- a/tests/helpers/module-for-acceptance.js +++ b/tests/helpers/module-for-acceptance.js @@ -16,6 +16,6 @@ export default function(name, options = {}) { afterEach() { let afterEach = options.afterEach && options.afterEach.apply(this, arguments); return Promise.resolve(afterEach).then(() => destroyApp(this.application)); - } + }, }); } diff --git a/tests/helpers/resolver.js b/tests/helpers/resolver.js index b208d38d097..319b45fc1c2 100644 --- a/tests/helpers/resolver.js +++ b/tests/helpers/resolver.js @@ -5,7 +5,7 @@ const resolver = Resolver.create(); resolver.namespace = { modulePrefix: config.modulePrefix, - podModulePrefix: config.podModulePrefix + podModulePrefix: config.podModulePrefix, }; export default resolver; diff --git a/tests/helpers/store.js b/tests/helpers/store.js index 5cbea0dd3f8..b2297944a58 100644 --- a/tests/helpers/store.js +++ b/tests/helpers/store.js @@ -11,10 +11,10 @@ export default function setupStore(options) { if (Ember.Registry) { registry = env.registry = new Ember.Registry(); owner = Owner.create({ - __registry__: registry + __registry__: registry, }); container = env.container = registry.container({ - owner: owner + owner: owner, }); owner.__container__ = container; } else { @@ -30,7 +30,7 @@ export default function setupStore(options) { } }; - let adapter = env.adapter = (options.adapter || '-default'); + let adapter = (env.adapter = options.adapter || '-default'); delete options.adapter; if (typeof adapter !== 'string') { @@ -42,9 +42,12 @@ export default function setupStore(options) { registry.register('model:' + dasherize(prop), options[prop]); } - registry.register('service:store', DS.Store.extend({ - adapter: adapter - })); + registry.register( + 'service:store', + DS.Store.extend({ + adapter: adapter, + }) + ); registry.optionsForType('serializer', { singleton: false }); registry.optionsForType('adapter', { singleton: false }); @@ -78,7 +81,7 @@ export default function setupStore(options) { this._adapter = adapter; }, enumerable: true, - configurable: true + configurable: true, }); return env; diff --git a/tests/helpers/watch-property.js b/tests/helpers/watch-property.js index 9b88dd8277a..d8df6e9e898 100644 --- a/tests/helpers/watch-property.js +++ b/tests/helpers/watch-property.js @@ -1,21 +1,22 @@ import Ember from 'ember'; import QUnit from 'qunit'; -const { - addObserver, - removeObserver -} = Ember; +const { addObserver, removeObserver } = Ember; function makeCounter() { let count = 0; const counter = Object.create(null); - counter.reset = function resetCounter() { count = 0; }; + counter.reset = function resetCounter() { + count = 0; + }; Object.defineProperty(counter, 'count', { - get() { return count; }, + get() { + return count; + }, set() {}, configurable: false, - enumerable: true + enumerable: true, }); Object.freeze(counter); @@ -48,7 +49,9 @@ export function watchProperties(obj, propertyNames) { let counters = {}; if (!Array.isArray(propertyNames)) { - throw new Error(`Must call watchProperties with an array of propertyNames to watch, received ${propertyNames}`); + throw new Error( + `Must call watchProperties with an array of propertyNames to watch, received ${propertyNames}` + ); } for (let i = 0; i < propertyNames.length; i++) { @@ -66,7 +69,7 @@ export function watchProperties(obj, propertyNames) { } function unwatch() { - Object.keys(watched).forEach((propertyName) => { + Object.keys(watched).forEach(propertyName => { removeObserver(obj, propertyName, watched[propertyName]); }); } @@ -74,14 +77,20 @@ export function watchProperties(obj, propertyNames) { return { counters, unwatch }; } -QUnit.assert.watchedPropertyCounts = function assertWatchedPropertyCount(watchedObject, expectedCounts, label = '') { +QUnit.assert.watchedPropertyCounts = function assertWatchedPropertyCount( + watchedObject, + expectedCounts, + label = '' +) { if (!watchedObject || !watchedObject.counters) { - throw new Error('Expected to receive the return value of watchProperties: an object containing counters'); + throw new Error( + 'Expected to receive the return value of watchProperties: an object containing counters' + ); } let counters = watchedObject.counters; - Object.keys(expectedCounts).forEach((propertyName) => { + Object.keys(expectedCounts).forEach(propertyName => { let counter = counters[propertyName]; let expectedCount = expectedCounts[propertyName]; let assertionText = label; @@ -91,22 +100,30 @@ QUnit.assert.watchedPropertyCounts = function assertWatchedPropertyCount(watched expectedCount = expectedCount[0]; } - assertionText += ` | Expected ${expectedCount} change notifications for ${propertyName} but recieved ${counter.count}`; + assertionText += ` | Expected ${expectedCount} change notifications for ${propertyName} but recieved ${ + counter.count + }`; if (counter === undefined) { - throw new Error(`Cannot assert expected count for ${propertyName} as there is no watcher for that property`); + throw new Error( + `Cannot assert expected count for ${propertyName} as there is no watcher for that property` + ); } this.pushResult({ result: counter.count === expectedCount, actual: counter.count, expected: expectedCount, - message: assertionText + message: assertionText, }); }); }; -QUnit.assert.watchedPropertyCount = function assertWatchedPropertyCount(watcher, expectedCount, label) { +QUnit.assert.watchedPropertyCount = function assertWatchedPropertyCount( + watcher, + expectedCount, + label +) { let counter; if (!watcher) { throw new Error(`Expected to receive a watcher`); @@ -123,7 +140,7 @@ QUnit.assert.watchedPropertyCount = function assertWatchedPropertyCount(watcher, result: counter.count === expectedCount, actual: counter.count, expected: expectedCount, - message: label + message: label, }); }; @@ -136,9 +153,7 @@ QUnit.assert.dirties = function assertDirties(options, updateMethodCallback, lab result: counter.count === count, actual: counter.count, expected: count, - message: label + message: label, }); unwatch(); }; - - diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index e97535f32b1..5bbdaa461d6 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -12,14 +12,14 @@ import DS from 'ember-data'; let env, store, adapter, Post, Comment, SuperUser; let passedUrl; -module("integration/adapter/build-url-mixin - BuildURLMixin with RESTAdapter", { +module('integration/adapter/build-url-mixin - BuildURLMixin with RESTAdapter', { beforeEach() { Post = DS.Model.extend({ - name: DS.attr("string") + name: DS.attr('string'), }); Comment = DS.Model.extend({ - name: DS.attr("string") + name: DS.attr('string'), }); SuperUser = DS.Model.extend(); @@ -28,7 +28,7 @@ module("integration/adapter/build-url-mixin - BuildURLMixin with RESTAdapter", { post: Post, comment: Comment, superUser: SuperUser, - adapter: DS.RESTAdapter + adapter: DS.RESTAdapter, }); store = env.store; @@ -39,7 +39,7 @@ module("integration/adapter/build-url-mixin - BuildURLMixin with RESTAdapter", { SuperUser = store.modelFor('super-user'); passedUrl = null; - } + }, }); function ajaxResponse(value) { @@ -50,27 +50,28 @@ function ajaxResponse(value) { }; } - test('buildURL - with host and namespace', function(assert) { run(() => { adapter.setProperties({ host: 'http://example.com', - namespace: 'api/v1' + namespace: 'api/v1', }); }); ajaxResponse({ posts: [{ id: 1 }] }); - return run(() => store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, "http://example.com/api/v1/posts/1"); - })); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, 'http://example.com/api/v1/posts/1'); + }) + ); }); test('buildURL - with relative paths in links', function(assert) { run(() => { adapter.setProperties({ host: 'http://example.com', - namespace: 'api/v1' + namespace: 'api/v1', }); }); @@ -79,19 +80,24 @@ test('buildURL - with relative paths in links', function(assert) { ajaxResponse({ posts: [{ id: 1, links: { comments: 'comments' } }] }); - return run(() => store.findRecord('post', 1).then(post => { - ajaxResponse({ comments: [{ id: 1 }] }); - return post.get('comments'); - }).then(comments => { - assert.equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); - })); + return run(() => + store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ comments: [{ id: 1 }] }); + return post.get('comments'); + }) + .then(comments => { + assert.equal(passedUrl, 'http://example.com/api/v1/posts/1/comments'); + }) + ); }); test('buildURL - with absolute paths in links', function(assert) { run(() => { adapter.setProperties({ host: 'http://example.com', - namespace: 'api/v1' + namespace: 'api/v1', }); }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -99,20 +105,24 @@ test('buildURL - with absolute paths in links', function(assert) { ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - return run(() => store.findRecord('post', 1).then(post => { - ajaxResponse({ comments: [{ id: 1 }] }); - return post.get('comments'); - }).then(comments => { - assert.equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); - })); + return run(() => + store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ comments: [{ id: 1 }] }); + return post.get('comments'); + }) + .then(comments => { + assert.equal(passedUrl, 'http://example.com/api/v1/posts/1/comments'); + }) + ); }); - test('buildURL - with absolute paths in links and protocol relative host', function(assert) { run(() => { adapter.setProperties({ host: '//example.com', - namespace: 'api/v1' + namespace: 'api/v1', }); }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -120,19 +130,24 @@ test('buildURL - with absolute paths in links and protocol relative host', funct ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - return run(() => store.findRecord('post', 1).then(post => { - ajaxResponse({ comments: [{ id: 1 }] }); - return post.get('comments'); - }).then(comments => { - assert.equal(passedUrl, "//example.com/api/v1/posts/1/comments"); - })); + return run(() => + store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ comments: [{ id: 1 }] }); + return post.get('comments'); + }) + .then(comments => { + assert.equal(passedUrl, '//example.com/api/v1/posts/1/comments'); + }) + ); }); test('buildURL - with absolute paths in links and host is /', function(assert) { run(() => { adapter.setProperties({ host: '/', - namespace: 'api/v1' + namespace: 'api/v1', }); }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -140,37 +155,46 @@ test('buildURL - with absolute paths in links and host is /', function(assert) { ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - return run(() => store.findRecord('post', 1).then(post => { - ajaxResponse({ comments: [{ id: 1 }] }); - return post.get('comments'); - }).then(comments => { - assert.equal(passedUrl, '/api/v1/posts/1/comments', 'host stripped out properly'); - })); + return run(() => + store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ comments: [{ id: 1 }] }); + return post.get('comments'); + }) + .then(comments => { + assert.equal(passedUrl, '/api/v1/posts/1/comments', 'host stripped out properly'); + }) + ); }); test('buildURL - with full URLs in links', function(assert) { adapter.setProperties({ host: 'http://example.com', - namespace: 'api/v1' + namespace: 'api/v1', }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); ajaxResponse({ posts: [ - { id: 1, - links: { comments: 'http://example.com/api/v1/posts/1/comments' } - } - ] + { + id: 1, + links: { comments: 'http://example.com/api/v1/posts/1/comments' }, + }, + ], }); return run(() => { - return store.findRecord('post', 1).then(post => { - ajaxResponse({ comments: [{ id: 1 }] }); - return post.get('comments'); - }).then(comments => { - assert.equal(passedUrl, "http://example.com/api/v1/posts/1/comments"); - }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ comments: [{ id: 1 }] }); + return post.get('comments'); + }) + .then(comments => { + assert.equal(passedUrl, 'http://example.com/api/v1/posts/1/comments'); + }); }); }); @@ -179,14 +203,14 @@ test('buildURL - with camelized names', function(assert) { pathForType(type) { let decamelized = decamelize(type); return underscore(pluralize(decamelized)); - } + }, }); ajaxResponse({ superUsers: [{ id: 1 }] }); return run(() => { return store.findRecord('super-user', 1).then(post => { - assert.equal(passedUrl, "/super_users/1"); + assert.equal(passedUrl, '/super_users/1'); }); }); }); @@ -194,7 +218,7 @@ test('buildURL - with camelized names', function(assert) { test('buildURL - buildURL takes a record from find', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); adapter.buildURL = function(type, id, snapshot) { - return "/posts/" + snapshot.belongsTo('post', { id: true }) + '/comments/' + snapshot.id; + return '/posts/' + snapshot.belongsTo('post', { id: true }) + '/comments/' + snapshot.id; }; ajaxResponse({ comments: [{ id: 1 }] }); @@ -204,14 +228,14 @@ test('buildURL - buildURL takes a record from find', function(assert) { post = store.push({ data: { type: 'post', - id: '2' - } + id: '2', + }, }); }); return run(() => { return store.findRecord('comment', 1, { preload: { post: post } }).then(post => { - assert.equal(passedUrl, "/posts/2/comments/1"); + assert.equal(passedUrl, '/posts/2/comments/1'); }); }); }); @@ -222,16 +246,18 @@ test('buildURL - buildURL takes the records from findMany', function(assert) { adapter.buildURL = function(type, ids, snapshots) { if (Array.isArray(snapshots)) { - return "/posts/" + snapshots.get('firstObject').belongsTo('post', { id: true }) + '/comments/'; + return ( + '/posts/' + snapshots.get('firstObject').belongsTo('post', { id: true }) + '/comments/' + ); } - return ""; + return ''; }; adapter.coalesceFindRequests = true; ajaxResponse({ comments: [{ id: 1 }, { id: 2 }, { id: 3 }] }); let post; - return run(() => { + return run(() => { post = store.push({ data: { type: 'post', @@ -241,15 +267,15 @@ test('buildURL - buildURL takes the records from findMany', function(assert) { data: [ { id: '1', type: 'comment' }, { id: '2', type: 'comment' }, - { id: '3', type: 'comment' } - ] - } - } - } + { id: '3', type: 'comment' }, + ], + }, + }, + }, }); return post.get('comments').then(post => { - assert.equal(passedUrl, "/posts/2/comments/"); + assert.equal(passedUrl, '/posts/2/comments/'); }); }); }); @@ -257,7 +283,7 @@ test('buildURL - buildURL takes the records from findMany', function(assert) { test('buildURL - buildURL takes a record from create', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); adapter.buildURL = function(type, id, snapshot) { - return "/posts/" + snapshot.belongsTo('post', { id: true }) + '/comments/'; + return '/posts/' + snapshot.belongsTo('post', { id: true }) + '/comments/'; }; ajaxResponse({ comments: [{ id: 1 }] }); @@ -266,13 +292,13 @@ test('buildURL - buildURL takes a record from create', function(assert) { let post = store.push({ data: { type: 'post', - id: '2' - } + id: '2', + }, }); let comment = store.createRecord('comment'); comment.set('post', post); return comment.save().then(post => { - assert.equal(passedUrl, "/posts/2/comments/"); + assert.equal(passedUrl, '/posts/2/comments/'); }); }); }); @@ -287,7 +313,7 @@ test('buildURL - buildURL takes a record from create to query a resolved async b assert.equal(post.get('id'), 2); adapter.buildURL = function(type, id, snapshot) { - return "/posts/" + snapshot.belongsTo('post', { id: true }) + '/comments/'; + return '/posts/' + snapshot.belongsTo('post', { id: true }) + '/comments/'; }; ajaxResponse({ comments: [{ id: 1 }] }); @@ -295,7 +321,7 @@ test('buildURL - buildURL takes a record from create to query a resolved async b let comment = store.createRecord('comment'); comment.set('post', post); return comment.save().then(post => { - assert.equal(passedUrl, "/posts/2/comments/"); + assert.equal(passedUrl, '/posts/2/comments/'); }); }); }); @@ -304,7 +330,7 @@ test('buildURL - buildURL takes a record from create to query a resolved async b test('buildURL - buildURL takes a record from update', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); adapter.buildURL = function(type, id, snapshot) { - return "/posts/" + snapshot.belongsTo('post', { id: true }) + '/comments/' + snapshot.id; + return '/posts/' + snapshot.belongsTo('post', { id: true }) + '/comments/' + snapshot.id; }; ajaxResponse({ comments: [{ id: 1 }] }); @@ -314,21 +340,21 @@ test('buildURL - buildURL takes a record from update', function(assert) { post = store.push({ data: { type: 'post', - id: '2' - } + id: '2', + }, }); comment = store.push({ data: { type: 'comment', - id: '1' - } + id: '1', + }, }); comment.set('post', post); }); return run(() => { return comment.save().then(post => { - assert.equal(passedUrl, "/posts/2/comments/1"); + assert.equal(passedUrl, '/posts/2/comments/1'); }); }); }); @@ -348,14 +374,14 @@ test('buildURL - buildURL takes a record from delete', function(assert) { post = store.push({ data: { type: 'post', - id: '2' - } + id: '2', + }, }); comment = store.push({ data: { type: 'comment', - id: '1' - } + id: '1', + }, }); comment.set('post', post); @@ -364,7 +390,7 @@ test('buildURL - buildURL takes a record from delete', function(assert) { return run(() => { return comment.save().then(post => { - assert.equal(passedUrl, "posts/2/comments/1"); + assert.equal(passedUrl, 'posts/2/comments/1'); }); }); }); @@ -372,13 +398,13 @@ test('buildURL - buildURL takes a record from delete', function(assert) { test('buildURL - with absolute namespace', function(assert) { run(() => { adapter.setProperties({ - namespace: '/api/v1' + namespace: '/api/v1', }); }); ajaxResponse({ posts: [{ id: 1 }] }); return run(store, 'findRecord', 'post', 1).then(post => { - assert.equal(passedUrl, "/api/v1/posts/1"); + assert.equal(passedUrl, '/api/v1/posts/1'); }); }); diff --git a/tests/integration/adapter/client-side-delete-test.js b/tests/integration/adapter/client-side-delete-test.js index 38693df8dd5..c755de89971 100644 --- a/tests/integration/adapter/client-side-delete-test.js +++ b/tests/integration/adapter/client-side-delete-test.js @@ -9,15 +9,15 @@ import DS from 'ember-data'; module('integration/adapter/store-adapter - client-side delete', { beforeEach() { this.Bookstore = DS.Model.extend({ - books: DS.hasMany('book', { async: false, inverse: 'bookstore' }) + books: DS.hasMany('book', { async: false, inverse: 'bookstore' }), }); this.Book = DS.Model.extend({ - bookstore: DS.belongsTo('bookstore', { inverse: 'books' }) + bookstore: DS.belongsTo('bookstore', { inverse: 'books' }), }); this.env = setupStore({ bookstore: this.Bookstore, - book: this.Book + book: this.Book, }); this.store = this.env.store; this.adapter = this.env.adapter; @@ -25,39 +25,50 @@ module('integration/adapter/store-adapter - client-side delete', { afterEach() { run(this.env.container, 'destroy'); - } + }, }); test('client-side deleted records can be added back from an inverse', function(assert) { - this.adapter.deleteRecord = function (store, modelClass, snapshot) { + this.adapter.deleteRecord = function(store, modelClass, snapshot) { if (snapshot.adapterOptions.clientSideDelete) { return resolve(); } assert.ok(false, 'unreachable'); - } + }; - run(() => this.store.push({ - data: { - id: '1', - type: 'bookstore', - relationships: { - books: { - data: [{ - id: '1', type: 'book' - }, { - id: '2', type: 'book' - }] - } - } - }, included: [{ - id: '1', - type: 'book' - }, { - id: '2', - type: 'book' - }] - })); + run(() => + this.store.push({ + data: { + id: '1', + type: 'bookstore', + relationships: { + books: { + data: [ + { + id: '1', + type: 'book', + }, + { + id: '2', + type: 'book', + }, + ], + }, + }, + }, + included: [ + { + id: '1', + type: 'book', + }, + { + id: '2', + type: 'book', + }, + ], + }) + ); let bookstore = this.store.peekRecord('bookstore', '1'); assert.deepEqual(bookstore.get('books').mapBy('id'), ['1', '2'], 'initial hasmany loaded'); @@ -68,21 +79,27 @@ test('client-side deleted records can be added back from an inverse', function(a assert.equal(this.store.hasRecordForId('book', '2'), false, 'book 2 unloaded'); assert.deepEqual(bookstore.get('books').mapBy('id'), ['1'], 'one book client-side deleted'); - run(() => this.store.push({ - data: { - id: '2', - type: 'book', - relationships: { - bookstore: { - data: { - id: '1', - type: 'bookstore' - } - } - } - } - })); + run(() => + this.store.push({ + data: { + id: '2', + type: 'book', + relationships: { + bookstore: { + data: { + id: '1', + type: 'bookstore', + }, + }, + }, + }, + }) + ); - assert.deepEqual(bookstore.get('books').mapBy('id'), ['1', '2'], 'the deleted book (with same id) is pushed back into the store'); + assert.deepEqual( + bookstore.get('books').mapBy('id'), + ['1', '2'], + 'the deleted book (with same id) is pushed back into the store' + ); }); }); diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index c787fe11b01..1d1b2b01cab 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -11,103 +11,146 @@ const { attr } = DS; let Person, store, allRecords, env; -module("integration/adapter/find-all - Finding All Records of a Type", { +module('integration/adapter/find-all - Finding All Records of a Type', { beforeEach() { Person = DS.Model.extend({ updatedAt: attr('string'), name: attr('string'), firstName: attr('string'), - lastName: attr('string') + lastName: attr('string'), + }); + Person.reopenClass({ + toString() { + return 'Person'; + }, }); - Person.reopenClass({ toString() { return 'Person'; } }); allRecords = null; env = setupStore({ - person: Person + person: Person, }); store = env.store; }, afterEach() { run(() => { - if (allRecords) { allRecords.destroy(); } + if (allRecords) { + allRecords.destroy(); + } store.destroy(); }); - } + }, }); -test("When all records for a type are requested, the store should call the adapter's `findAll` method.", (assert) => { +test("When all records for a type are requested, the store should call the adapter's `findAll` method.", assert => { assert.expect(5); - env.registry.register('adapter:person', DS.Adapter.extend({ - findAll() { - // this will get called twice - assert.ok(true, "the adapter's findAll method should be invoked"); - - return resolve({ data: [{ - id: 1, - type: 'person', - attributes: { - name: "Braaaahm Dale" - } - }]}); - } - })); + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findAll() { + // this will get called twice + assert.ok(true, "the adapter's findAll method should be invoked"); + + return resolve({ + data: [ + { + id: 1, + type: 'person', + attributes: { + name: 'Braaaahm Dale', + }, + }, + ], + }); + }, + }) + ); return run(() => { return store.findAll('person').then(all => { let allRecords = all; - assert.equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); - assert.equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); + assert.equal( + get(all, 'length'), + 1, + "the record array's length is 1 after a record is loaded into it" + ); + assert.equal( + all.objectAt(0).get('name'), + 'Braaaahm Dale', + 'the first item in the record array is Braaaahm Dale' + ); return store.findAll('person').then(all => { // Only one record array per type should ever be created (identity map) - assert.strictEqual(allRecords, all, "the same record array is returned every time all records of a type are requested"); + assert.strictEqual( + allRecords, + all, + 'the same record array is returned every time all records of a type are requested' + ); }); }); }); }); -test("When all records for a type are requested, a rejection should reject the promise", (assert) => { +test('When all records for a type are requested, a rejection should reject the promise', assert => { assert.expect(5); let count = 0; - env.registry.register('adapter:person', DS.Adapter.extend({ - findAll() { - // this will get called twice - assert.ok(true, "the adapter's findAll method should be invoked"); - - if (count++ === 0) { - return reject(); - } else { - return resolve({ data: [{ - id: 1, - type: 'person', - attributes: { - name: "Braaaahm Dale" - } - }]}); - } - } - })); + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findAll() { + // this will get called twice + assert.ok(true, "the adapter's findAll method should be invoked"); + + if (count++ === 0) { + return reject(); + } else { + return resolve({ + data: [ + { + id: 1, + type: 'person', + attributes: { + name: 'Braaaahm Dale', + }, + }, + ], + }); + } + }, + }) + ); return run(() => { - return store.findAll('person').catch(() => { - assert.ok(true, "The rejection should get here"); - return store.findAll('person'); - }).then(all => { - assert.equal(get(all, 'length'), 1, "the record array's length is 1 after a record is loaded into it"); - assert.equal(all.objectAt(0).get('name'), "Braaaahm Dale", "the first item in the record array is Braaaahm Dale"); - }); + return store + .findAll('person') + .catch(() => { + assert.ok(true, 'The rejection should get here'); + return store.findAll('person'); + }) + .then(all => { + assert.equal( + get(all, 'length'), + 1, + "the record array's length is 1 after a record is loaded into it" + ); + assert.equal( + all.objectAt(0).get('name'), + 'Braaaahm Dale', + 'the first item in the record array is Braaaahm Dale' + ); + }); }); }); -test("When all records for a type are requested, records that are already loaded should be returned immediately.", (assert) => { +test('When all records for a type are requested, records that are already loaded should be returned immediately.', assert => { assert.expect(3); store = createStore({ adapter: DS.Adapter.extend(), - person: Person + person: Person, }); run(() => { @@ -117,119 +160,148 @@ test("When all records for a type are requested, records that are already loaded type: 'person', id: '1', attributes: { - name: 'Jeremy Ashkenas' - } - } + name: 'Jeremy Ashkenas', + }, + }, }); // Create a new, unsaved record in the store - store.createRecord('person', { name: "Alex MacCaw" }); + store.createRecord('person', { name: 'Alex MacCaw' }); }); allRecords = store.peekAll('person'); assert.equal(get(allRecords, 'length'), 2, "the record array's length is 2"); - assert.equal(allRecords.objectAt(0).get('name'), "Jeremy Ashkenas", "the first item in the record array is Jeremy Ashkenas"); - assert.equal(allRecords.objectAt(1).get('name'), "Alex MacCaw", "the second item in the record array is Alex MacCaw"); + assert.equal( + allRecords.objectAt(0).get('name'), + 'Jeremy Ashkenas', + 'the first item in the record array is Jeremy Ashkenas' + ); + assert.equal( + allRecords.objectAt(1).get('name'), + 'Alex MacCaw', + 'the second item in the record array is Alex MacCaw' + ); }); -test("When all records for a type are requested, records that are created on the client should be added to the record array.", (assert) => { +test('When all records for a type are requested, records that are created on the client should be added to the record array.', assert => { assert.expect(3); store = createStore({ adapter: DS.Adapter.extend(), - person: Person + person: Person, }); allRecords = store.peekAll('person'); - assert.equal(get(allRecords, 'length'), 0, "precond - the record array's length is zero before any records are loaded"); + assert.equal( + get(allRecords, 'length'), + 0, + "precond - the record array's length is zero before any records are loaded" + ); - store.createRecord('person', { name: "Carsten Nielsen" }); + store.createRecord('person', { name: 'Carsten Nielsen' }); assert.equal(get(allRecords, 'length'), 1, "the record array's length is 1"); - assert.equal(allRecords.objectAt(0).get('name'), "Carsten Nielsen", "the first item in the record array is Carsten Nielsen"); + assert.equal( + allRecords.objectAt(0).get('name'), + 'Carsten Nielsen', + 'the first item in the record array is Carsten Nielsen' + ); }); -testInDebug('When all records are requested, assert the payload is not blank', (assert) => { - env.registry.register('adapter:person', DS.Adapter.extend({ - findAll: () => resolve({}) - })); +testInDebug('When all records are requested, assert the payload is not blank', assert => { + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findAll: () => resolve({}), + }) + ); assert.expectAssertion(() => { run(() => store.findAll('person')); }, /You made a 'findAll' request for 'person' records, but the adapter's response did not have any data/); }); -test("isUpdating is true while records are fetched", function(assert) { +test('isUpdating is true while records are fetched', function(assert) { let findAllDeferred = defer(); - env.registry.register('adapter:person', DS.Adapter.extend({ - findAll() { - return findAllDeferred.promise; - }, + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findAll() { + return findAllDeferred.promise; + }, - shouldReloadAll: () => true - })); + shouldReloadAll: () => true, + }) + ); run(() => { store.push({ - data: [{ - type: 'person', - id: 1 - }] + data: [ + { + type: 'person', + id: 1, + }, + ], }); }); let persons = store.peekAll('person'); - assert.equal(persons.get("length"), 1); + assert.equal(persons.get('length'), 1); let wait = run(() => { return store.findAll('person').then(persons => { - assert.equal(persons.get("isUpdating"), false); - assert.equal(persons.get("length"), 2); + assert.equal(persons.get('isUpdating'), false); + assert.equal(persons.get('length'), 2); }); }); - assert.equal(persons.get("isUpdating"), true); + assert.equal(persons.get('isUpdating'), true); findAllDeferred.resolve({ data: [{ id: 2, type: 'person' }] }); return wait; }); -test("isUpdating is true while records are fetched in the background", function(assert) { +test('isUpdating is true while records are fetched in the background', function(assert) { let findAllDeferred = defer(); - env.registry.register('adapter:person', DS.Adapter.extend({ - findAll() { - return findAllDeferred.promise; - }, - - shouldReloadAll() { - return false; - }, - shouldBackgroundReloadAll() { - return true; - } - })); + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findAll() { + return findAllDeferred.promise; + }, + + shouldReloadAll() { + return false; + }, + shouldBackgroundReloadAll() { + return true; + }, + }) + ); run(() => { store.push({ - data: [{ - type: 'person', - id: 1 - }] + data: [ + { + type: 'person', + id: 1, + }, + ], }); }); let persons = store.peekAll('person'); - assert.equal(persons.get("length"), 1); + assert.equal(persons.get('length'), 1); return run(() => { return store.findAll('person').then(persons => { - assert.equal(persons.get("isUpdating"), true); - assert.equal(persons.get("length"), 1, "persons are updated in the background"); + assert.equal(persons.get('isUpdating'), true); + assert.equal(persons.get('length'), 1, 'persons are updated in the background'); }); }).then(() => { - assert.equal(persons.get("isUpdating"), true); + assert.equal(persons.get('isUpdating'), true); run(() => { findAllDeferred.resolve({ data: [{ id: 2, type: 'person' }] }); @@ -237,40 +309,45 @@ test("isUpdating is true while records are fetched in the background", function( return run(() => { return findAllDeferred.promise.then(() => { - assert.equal(persons.get("isUpdating"), false); - assert.equal(persons.get("length"), 2); + assert.equal(persons.get('isUpdating'), false); + assert.equal(persons.get('length'), 2); }); }); }); }); -test("isUpdating is false if records are not fetched in the background", function(assert) { +test('isUpdating is false if records are not fetched in the background', function(assert) { let findAllDeferred = defer(); - env.registry.register('adapter:person', DS.Adapter.extend({ - findAll() { - return findAllDeferred.promise; - }, - shouldReloadAll: () => false, - shouldBackgroundReloadAll: () => false - })); + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findAll() { + return findAllDeferred.promise; + }, + shouldReloadAll: () => false, + shouldBackgroundReloadAll: () => false, + }) + ); run(() => { store.push({ - data: [{ - type: 'person', - id: 1 - }] + data: [ + { + type: 'person', + id: 1, + }, + ], }); }); let persons = store.peekAll('person'); - assert.equal(persons.get("length"), 1); + assert.equal(persons.get('length'), 1); return run(() => { return store.findAll('person').then(persons => { - assert.equal(persons.get("isUpdating"), false); + assert.equal(persons.get('isUpdating'), false); }); }).then(() => { - assert.equal(persons.get("isUpdating"), false); + assert.equal(persons.get('isUpdating'), false); }); }); diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index b537c3c6dfc..00cf5c73791 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -9,27 +9,27 @@ const { attr } = DS; let Person, store, env; -module("integration/adapter/find - Finding Records", { +module('integration/adapter/find - Finding Records', { beforeEach() { Person = DS.Model.extend({ updatedAt: attr('string'), name: attr('string'), firstName: attr('string'), - lastName: attr('string') + lastName: attr('string'), }); env = setupStore({ - person: Person + person: Person, }); store = env.store; }, afterEach() { run(store, 'destroy'); - } + }, }); -testInDebug("It raises an assertion when `undefined` is passed as id (#1705)", function(assert) { +testInDebug('It raises an assertion when `undefined` is passed as id (#1705)', function(assert) { assert.expectAssertion(() => { store.find('person', undefined); }, `You cannot pass 'undefined' as id to the store's find method`); @@ -44,23 +44,26 @@ test("When a single record is requested, the adapter's find method should be cal let count = 0; - env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord(_, type) { - assert.equal(type, Person, "the find method is called with the correct type"); - assert.equal(count, 0, "the find method is only called once"); - - count++; - return { - data: { - id: 1, - type: "person", - attributes: { - name: "Braaaahm Dale" - } - } - }; - } - })); + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findRecord(_, type) { + assert.equal(type, Person, 'the find method is called with the correct type'); + assert.equal(count, 0, 'the find method is only called once'); + + count++; + return { + data: { + id: 1, + type: 'person', + attributes: { + name: 'Braaaahm Dale', + }, + }, + }; + }, + }) + ); run(() => { store.findRecord('person', 1); @@ -68,26 +71,29 @@ test("When a single record is requested, the adapter's find method should be cal }); }); -test("When a single record is requested multiple times, all .findRecord() calls are resolved after the promise is resolved", function(assert) { +test('When a single record is requested multiple times, all .findRecord() calls are resolved after the promise is resolved', function(assert) { let deferred = defer(); - env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord() { - return deferred.promise; - } - })); + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findRecord() { + return deferred.promise; + }, + }) + ); let requestOne = run(() => { return store.findRecord('person', 1).then(person => { - assert.equal(person.get('id'), "1"); - assert.equal(person.get('name'), "Braaaahm Dale"); + assert.equal(person.get('id'), '1'); + assert.equal(person.get('name'), 'Braaaahm Dale'); }); }); let requestTwo = run(() => { return store.findRecord('person', 1).then(post => { - assert.equal(post.get('id'), "1"); - assert.equal(post.get('name'), "Braaaahm Dale"); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Braaaahm Dale'); }); }); @@ -95,26 +101,26 @@ test("When a single record is requested multiple times, all .findRecord() calls deferred.resolve({ data: { id: 1, - type: "person", + type: 'person', attributes: { - name: "Braaaahm Dale" - } - } + name: 'Braaaahm Dale', + }, + }, }); }); - return Promise.all([ - requestOne, - requestTwo - ]) + return Promise.all([requestOne, requestTwo]); }); -test("When a single record is requested, and the promise is rejected, .findRecord() is rejected.", function(assert) { - env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord() { - return reject(); - } - })); +test('When a single record is requested, and the promise is rejected, .findRecord() is rejected.', function(assert) { + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findRecord() { + return reject(); + }, + }) + ); return run(() => { return store.findRecord('person', 1).catch(() => { @@ -123,27 +129,33 @@ test("When a single record is requested, and the promise is rejected, .findRecor }); }); -test("When a single record is requested, and the promise is rejected, the record should be unloaded.", function(assert) { +test('When a single record is requested, and the promise is rejected, the record should be unloaded.', function(assert) { assert.expect(2); - env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord() { - return reject(); - } - })); + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findRecord() { + return reject(); + }, + }) + ); return run(() => { return store.findRecord('person', 1).catch(reason => { - assert.ok(true, "The rejection handler was called"); - assert.ok(!store.hasRecordForId('person', 1), "The record has been unloaded"); + assert.ok(true, 'The rejection handler was called'); + assert.ok(!store.hasRecordForId('person', 1), 'The record has been unloaded'); }); }); }); testInDebug('When a single record is requested, and the payload is blank', function(assert) { - env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord: () => resolve({}) - })); + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findRecord: () => resolve({}), + }) + ); assert.expectAssertion(() => { run(() => store.findRecord('person', 'the-id')); @@ -151,10 +163,13 @@ testInDebug('When a single record is requested, and the payload is blank', funct }); testInDebug('When multiple records are requested, and the payload is blank', function(assert) { - env.registry.register('adapter:person', DS.Adapter.extend({ - coalesceFindRequests: true, - findMany: () => resolve({}) - })); + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + coalesceFindRequests: true, + findMany: () => resolve({}), + }) + ); assert.expectAssertion(() => { run(() => { @@ -164,22 +179,26 @@ testInDebug('When multiple records are requested, and the payload is blank', fun }, /You made a 'findMany' request for 'person' records with ids '\[1,2\]', but the adapter's response did not have any data/); }); -testInDebug("warns when returned record has different id", function(assert) { - env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord() { - return { - data: { - id: 1, - type: "person", - attributes: { - name: "Braaaahm Dale" - } - } - }; - } - })); +testInDebug('warns when returned record has different id', function(assert) { + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findRecord() { + return { + data: { + id: 1, + type: 'person', + attributes: { + name: 'Braaaahm Dale', + }, + }, + }; + }, + }) + ); assert.expectWarning( () => run(() => env.store.findRecord('person', 'me')), - /You requested a record of type 'person' with id 'me' but the adapter returned a payload with primary data having an id of '1'/); + /You requested a record of type 'person' with id 'me' but the adapter returned a payload with primary data having an id of '1'/ + ); }); diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index c945eeb51cf..67e49141b8c 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -10,7 +10,15 @@ import DS from 'ember-data'; let env, store, adapter; let passedUrl, passedVerb, passedHash; -let User, Post, Comment, Handle, GithubHandle, TwitterHandle, Company, DevelopmentShop, DesignStudio; +let User, + Post, + Comment, + Handle, + GithubHandle, + TwitterHandle, + Company, + DevelopmentShop, + DesignStudio; module('integration/adapter/json-api-adapter - JSONAPIAdapter', { beforeEach() { @@ -19,57 +27,57 @@ module('integration/adapter/json-api-adapter - JSONAPIAdapter', { lastName: DS.attr('string'), posts: DS.hasMany('post', { async: true }), handles: DS.hasMany('handle', { async: true, polymorphic: true }), - company: DS.belongsTo('company', { async: true, polymorphic: true }) + company: DS.belongsTo('company', { async: true, polymorphic: true }), }); Post = DS.Model.extend({ title: DS.attr('string'), author: DS.belongsTo('user', { async: true }), - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); Comment = DS.Model.extend({ text: DS.attr('string'), - post: DS.belongsTo('post', { async: true }) + post: DS.belongsTo('post', { async: true }), }); Handle = DS.Model.extend({ - user: DS.belongsTo('user', { async: true }) + user: DS.belongsTo('user', { async: true }), }); GithubHandle = Handle.extend({ - username: DS.attr('string') + username: DS.attr('string'), }); TwitterHandle = Handle.extend({ - nickname: DS.attr('string') + nickname: DS.attr('string'), }); Company = DS.Model.extend({ name: DS.attr('string'), - employees: DS.hasMany('user', { async: true }) + employees: DS.hasMany('user', { async: true }), }); DevelopmentShop = Company.extend({ - coffee: DS.attr('boolean') + coffee: DS.attr('boolean'), }); DesignStudio = Company.extend({ - hipsters: DS.attr('number') + hipsters: DS.attr('number'), }); env = setupStore({ adapter: DS.JSONAPIAdapter.extend(), - 'user': User, - 'post': Post, - 'comment': Comment, - 'handle': Handle, + user: User, + post: Post, + comment: Comment, + handle: Handle, 'github-handle': GithubHandle, 'twitter-handle': TwitterHandle, - 'company': Company, + company: Company, 'development-shop': DevelopmentShop, - 'design-studio': DesignStudio + 'design-studio': DesignStudio, }); store = env.store; @@ -78,7 +86,7 @@ module('integration/adapter/json-api-adapter - JSONAPIAdapter', { afterEach() { run(env.store, 'destroy'); - } + }, }); function ajaxResponse(responses) { @@ -103,15 +111,17 @@ function ajaxResponse(responses) { test('find a single record', function(assert) { assert.expect(3); - ajaxResponse([{ - data: { - type: 'post', - id: '1', - attributes: { - title: 'Ember.js rocks' - } - } - }]); + ajaxResponse([ + { + data: { + type: 'post', + id: '1', + attributes: { + title: 'Ember.js rocks', + }, + }, + }, + ]); return run(() => { return store.findRecord('post', 1).then(post => { @@ -126,57 +136,63 @@ test('find a single record', function(assert) { test('find all records with sideloaded relationships', function(assert) { assert.expect(9); - ajaxResponse([{ - data: [{ - type: 'posts', - id: '1', - attributes: { - title: 'Ember.js rocks' - }, - relationships: { - author: { - data: { type: 'users', id: '3' } - } - } - }, { - type: 'posts', - id: '2', - attributes: { - title: 'Tomster rules' - }, - relationships: { - author: { - data: { type: 'users', id: '3' } - }, - comments: { - data: [ - { type: 'comments', id: '4' }, - { type: 'comments', id: '5' } - ] - } - } - }], - included: [{ - type: 'users', - id: '3', - attributes: { - 'first-name': 'Yehuda', - 'last-name': 'Katz' - } - }, { - type: 'comments', - id: '4', - attributes: { - text: 'This is the first comment' - } - }, { - type: 'comments', - id: '5', - attributes: { - text: 'This is the second comment' - } - }] - }]); + ajaxResponse([ + { + data: [ + { + type: 'posts', + id: '1', + attributes: { + title: 'Ember.js rocks', + }, + relationships: { + author: { + data: { type: 'users', id: '3' }, + }, + }, + }, + { + type: 'posts', + id: '2', + attributes: { + title: 'Tomster rules', + }, + relationships: { + author: { + data: { type: 'users', id: '3' }, + }, + comments: { + data: [{ type: 'comments', id: '4' }, { type: 'comments', id: '5' }], + }, + }, + }, + ], + included: [ + { + type: 'users', + id: '3', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz', + }, + }, + { + type: 'comments', + id: '4', + attributes: { + text: 'This is the first comment', + }, + }, + { + type: 'comments', + id: '5', + attributes: { + text: 'This is the second comment', + }, + }, + ], + }, + ]); return run(() => { return store.findAll('post').then(posts => { @@ -200,15 +216,19 @@ test('find all records with sideloaded relationships', function(assert) { test('find many records', function(assert) { assert.expect(4); - ajaxResponse([{ - data: [{ - type: 'posts', - id: '1', - attributes: { - title: 'Ember.js rocks' - } - }] - }]); + ajaxResponse([ + { + data: [ + { + type: 'posts', + id: '1', + attributes: { + title: 'Ember.js rocks', + }, + }, + ], + }, + ]); return run(() => { return store.query('post', { filter: { id: 1 } }).then(posts => { @@ -222,15 +242,17 @@ test('find many records', function(assert) { }); test('queryRecord - primary data being a single record', function(assert) { - ajaxResponse([{ - data: { - type: 'posts', - id: '1', - attributes: { - title: 'Ember.js rocks' - } - } - }]); + ajaxResponse([ + { + data: { + type: 'posts', + id: '1', + attributes: { + title: 'Ember.js rocks', + }, + }, + }, + ]); return run(() => { return store.queryRecord('post', {}).then(post => { @@ -242,9 +264,11 @@ test('queryRecord - primary data being a single record', function(assert) { }); test('queryRecord - primary data being null', function(assert) { - ajaxResponse([{ - data: null - }]); + ajaxResponse([ + { + data: null, + }, + ]); return run(() => { return store.queryRecord('post', {}).then(post => { @@ -256,46 +280,53 @@ test('queryRecord - primary data being null', function(assert) { }); testInDebug('queryRecord - primary data being an array throws an assertion', function(assert) { - ajaxResponse([{ - data: [{ - type: 'posts', - id: '1' - }] - }]); + ajaxResponse([ + { + data: [ + { + type: 'posts', + id: '1', + }, + ], + }, + ]); assert.expectAssertion(() => { run(() => store.queryRecord('post', {})); - }, "Expected the primary data returned by the serializer for a `queryRecord` response to be a single object but instead it was an array."); + }, 'Expected the primary data returned by the serializer for a `queryRecord` response to be a single object but instead it was an array.'); }); test('find a single record with belongsTo link as object { related }', function(assert) { assert.expect(7); - ajaxResponse([{ - data: { - type: 'posts', - id: '1', - attributes: { - title: 'Ember.js rocks' + ajaxResponse([ + { + data: { + type: 'posts', + id: '1', + attributes: { + title: 'Ember.js rocks', + }, + relationships: { + author: { + links: { + related: 'http://example.com/user/2', + }, + }, + }, }, - relationships: { - author: { - links: { - related: 'http://example.com/user/2' - } - } - } - } - }, { - data: { - type: 'users', - id: '2', - attributes: { - 'first-name': 'Yehuda', - 'last-name': 'Katz' - } - } - }]); + }, + { + data: { + type: 'users', + id: '2', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz', + }, + }, + }, + ]); return run(() => { return store.findRecord('post', 1).then(post => { @@ -318,29 +349,32 @@ test('find a single record with belongsTo link as object { related }', function( test('find a single record with belongsTo link as object { data }', function(assert) { assert.expect(7); - ajaxResponse([{ - data: { - type: 'posts', - id: '1', - attributes: { - title: 'Ember.js rocks' + ajaxResponse([ + { + data: { + type: 'posts', + id: '1', + attributes: { + title: 'Ember.js rocks', + }, + relationships: { + author: { + data: { type: 'users', id: '2' }, + }, + }, + }, + }, + { + data: { + type: 'users', + id: '2', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz', + }, }, - relationships: { - author: { - data: { type: 'users', id: '2' } - } - } - } - }, { - data: { - type: 'users', - id: '2', - attributes: { - 'first-name': 'Yehuda', - 'last-name': 'Katz' - } - } - }]); + }, + ]); return run(() => { return store.findRecord('post', 1).then(post => { @@ -363,30 +397,33 @@ test('find a single record with belongsTo link as object { data }', function(ass test('find a single record with belongsTo link as object { data } (polymorphic)', function(assert) { assert.expect(8); - ajaxResponse([{ - data: { - type: 'users', - id: '1', - attributes: { - 'first-name': 'Yehuda', - 'last-name': 'Katz' + ajaxResponse([ + { + data: { + type: 'users', + id: '1', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz', + }, + relationships: { + company: { + data: { type: 'development-shops', id: '2' }, + }, + }, }, - relationships: { - company: { - data: { type: 'development-shops', id: '2' } - } - } - } - }, { - data: { - type: 'development-shop', - id: '2', - attributes: { - name: 'Tilde', - coffee: true - } - } - }]); + }, + { + data: { + type: 'development-shop', + id: '2', + attributes: { + name: 'Tilde', + coffee: true, + }, + }, + }, + ]); return run(() => { return store.findRecord('user', 1).then(user => { @@ -410,28 +447,32 @@ test('find a single record with belongsTo link as object { data } (polymorphic)' test('find a single record with sideloaded belongsTo link as object { data }', function(assert) { assert.expect(7); - ajaxResponse([{ - data: { - type: 'post', - id: '1', - attributes: { - title: 'Ember.js rocks' + ajaxResponse([ + { + data: { + type: 'post', + id: '1', + attributes: { + title: 'Ember.js rocks', + }, + relationships: { + author: { + data: { type: 'user', id: '2' }, + }, + }, }, - relationships: { - author: { - data: { type: 'user', id: '2' } - } - } + included: [ + { + type: 'user', + id: '2', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz', + }, + }, + ], }, - included: [{ - type: 'user', - id: '2', - attributes: { - 'first-name': 'Yehuda', - 'last-name': 'Katz' - } - }] - }]); + ]); return run(() => { return store.findRecord('post', 1).then(post => { @@ -454,36 +495,42 @@ test('find a single record with sideloaded belongsTo link as object { data }', f test('find a single record with hasMany link as object { related }', function(assert) { assert.expect(7); - ajaxResponse([{ - data: { - type: 'post', - id: '1', - attributes: { - title: 'Ember.js rocks' + ajaxResponse([ + { + data: { + type: 'post', + id: '1', + attributes: { + title: 'Ember.js rocks', + }, + relationships: { + comments: { + links: { + related: 'http://example.com/post/1/comments', + }, + }, + }, }, - relationships: { - comments: { - links: { - related: 'http://example.com/post/1/comments' - } - } - } - } - }, { - data: [{ - type: 'comment', - id: '2', - attributes: { - text: 'This is the first comment' - } - }, { - type: 'comment', - id: '3', - attributes: { - text: 'This is the second comment' - } - }] - }]); + }, + { + data: [ + { + type: 'comment', + id: '2', + attributes: { + text: 'This is the first comment', + }, + }, + { + type: 'comment', + id: '3', + attributes: { + text: 'This is the second comment', + }, + }, + ], + }, + ]); return run(() => { return store.findRecord('post', 1).then(post => { @@ -506,39 +553,40 @@ test('find a single record with hasMany link as object { related }', function(as test('find a single record with hasMany link as object { data }', function(assert) { assert.expect(8); - ajaxResponse([{ - data: { - type: 'post', - id: '1', - attributes: { - title: 'Ember.js rocks' + ajaxResponse([ + { + data: { + type: 'post', + id: '1', + attributes: { + title: 'Ember.js rocks', + }, + relationships: { + comments: { + data: [{ type: 'comment', id: '2' }, { type: 'comment', id: '3' }], + }, + }, }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - } - }, { - data: { - type: 'comment', - id: '2', - attributes: { - text: 'This is the first comment' - } - } - }, { - data: { - type: 'comment', - id: '3', - attributes: { - text: 'This is the second comment' - } - } - }]); + }, + { + data: { + type: 'comment', + id: '2', + attributes: { + text: 'This is the first comment', + }, + }, + }, + { + data: { + type: 'comment', + id: '3', + attributes: { + text: 'This is the second comment', + }, + }, + }, + ]); return run(() => { return store.findRecord('post', 1).then(post => { @@ -562,40 +610,41 @@ test('find a single record with hasMany link as object { data }', function(asser test('find a single record with hasMany link as object { data } (polymorphic)', function(assert) { assert.expect(9); - ajaxResponse([{ - data: { - type: 'user', - id: '1', - attributes: { - 'first-name': 'Yehuda', - 'last-name': 'Katz' + ajaxResponse([ + { + data: { + type: 'user', + id: '1', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz', + }, + relationships: { + handles: { + data: [{ type: 'github-handle', id: '2' }, { type: 'twitter-handle', id: '3' }], + }, + }, }, - relationships: { - handles: { - data: [ - { type: 'github-handle', id: '2' }, - { type: 'twitter-handle', id: '3' } - ] - } - } - } - }, { - data: { - type: 'github-handle', - id: '2', - attributes: { - username: 'wycats' - } - } - }, { - data: { - type: 'twitter-handle', - id: '3', - attributes: { - nickname: '@wycats' - } - } - }]); + }, + { + data: { + type: 'github-handle', + id: '2', + attributes: { + username: 'wycats', + }, + }, + }, + { + data: { + type: 'twitter-handle', + id: '3', + attributes: { + nickname: '@wycats', + }, + }, + }, + ]); return run(() => { return store.findRecord('user', 1).then(user => { @@ -620,36 +669,38 @@ test('find a single record with hasMany link as object { data } (polymorphic)', test('find a single record with sideloaded hasMany link as object { data }', function(assert) { assert.expect(7); - ajaxResponse([{ - data: { - type: 'post', - id: '1', - attributes: { - title: 'Ember.js rocks' + ajaxResponse([ + { + data: { + type: 'post', + id: '1', + attributes: { + title: 'Ember.js rocks', + }, + relationships: { + comments: { + data: [{ type: 'comment', id: '2' }, { type: 'comment', id: '3' }], + }, + }, }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } + included: [ + { + type: 'comment', + id: '2', + attributes: { + text: 'This is the first comment', + }, + }, + { + type: 'comment', + id: '3', + attributes: { + text: 'This is the second comment', + }, + }, + ], }, - included: [{ - type: 'comment', - id: '2', - attributes: { - text: 'This is the first comment' - } - }, { - type: 'comment', - id: '3', - attributes: { - text: 'This is the second comment' - } - }] - }]); + ]); return run(() => { return store.findRecord('post', 1).then(post => { @@ -672,37 +723,39 @@ test('find a single record with sideloaded hasMany link as object { data }', fun test('find a single record with sideloaded hasMany link as object { data } (polymorphic)', function(assert) { assert.expect(8); - ajaxResponse([{ - data: { - type: 'user', - id: '1', - attributes: { - 'first-name': 'Yehuda', - 'last-name': 'Katz' + ajaxResponse([ + { + data: { + type: 'user', + id: '1', + attributes: { + 'first-name': 'Yehuda', + 'last-name': 'Katz', + }, + relationships: { + handles: { + data: [{ type: 'github-handle', id: '2' }, { type: 'twitter-handle', id: '3' }], + }, + }, }, - relationships: { - handles: { - data: [ - { type: 'github-handle', id: '2' }, - { type: 'twitter-handle', id: '3' } - ] - } - } + included: [ + { + type: 'github-handle', + id: '2', + attributes: { + username: 'wycats', + }, + }, + { + type: 'twitter-handle', + id: '3', + attributes: { + nickname: '@wycats', + }, + }, + ], }, - included: [{ - type: 'github-handle', - id: '2', - attributes: { - username: 'wycats' - } - }, { - type: 'twitter-handle', - id: '3', - attributes: { - nickname: '@wycats' - } - }] - }]); + ]); return run(() => { return store.findRecord('user', 1).then(user => { @@ -726,35 +779,40 @@ test('find a single record with sideloaded hasMany link as object { data } (poly test('create record', function(assert) { assert.expect(3); - ajaxResponse([{ - data: { - type: 'users', - id: '3' - } - }]); + ajaxResponse([ + { + data: { + type: 'users', + id: '3', + }, + }, + ]); return run(() => { + let company = store.push({ + data: { + type: 'company', + id: '1', + attributes: { + name: 'Tilde Inc.', + }, + }, + }); - let company = store.push({ data: { - type: 'company', - id: '1', - attributes: { - name: 'Tilde Inc.' - } - } }); - - let githubHandle = store.push({ data: { - type: 'github-handle', - id: '2', - attributes: { - username: 'wycats' - } - } }); + let githubHandle = store.push({ + data: { + type: 'github-handle', + id: '2', + attributes: { + username: 'wycats', + }, + }, + }); let user = store.createRecord('user', { firstName: 'Yehuda', lastName: 'Katz', - company: company + company: company, }); return user.get('handles').then(handles => { @@ -765,19 +823,19 @@ test('create record', function(assert) { assert.equal(passedVerb[0], 'POST'); assert.deepEqual(passedHash[0], { data: { - data : { + data: { type: 'users', attributes: { 'first-name': 'Yehuda', - 'last-name': 'Katz' + 'last-name': 'Katz', }, relationships: { company: { - data: { type: 'companies', id: '1' } - } - } - } - } + data: { type: 'companies', id: '1' }, + }, + }, + }, + }, }); }); }); @@ -787,38 +845,46 @@ test('create record', function(assert) { test('update record', function(assert) { assert.expect(3); - ajaxResponse([{ - data: { - type: 'users', - id: '1' - } - }]); + ajaxResponse([ + { + data: { + type: 'users', + id: '1', + }, + }, + ]); return run(() => { - let user = store.push({ data: { - type: 'user', - id: '1', - attributes: { - firstName: 'Yehuda', - lastName: 'Katz' - } - } }); - - let company = store.push({ data: { - type: 'company', - id: '2', - attributes: { - name: 'Tilde Inc.' - } - } }); - - let githubHandle = store.push({ data: { - type: 'github-handle', - id: '3', - attributes: { - username: 'wycats' - } - } }); + let user = store.push({ + data: { + type: 'user', + id: '1', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz', + }, + }, + }); + + let company = store.push({ + data: { + type: 'company', + id: '2', + attributes: { + name: 'Tilde Inc.', + }, + }, + }); + + let githubHandle = store.push({ + data: { + type: 'github-handle', + id: '3', + attributes: { + username: 'wycats', + }, + }, + }); user.set('firstName', 'Yehuda!'); user.set('company', company); @@ -831,20 +897,20 @@ test('update record', function(assert) { assert.equal(passedVerb[0], 'PATCH'); assert.deepEqual(passedHash[0], { data: { - data : { + data: { type: 'users', id: '1', attributes: { 'first-name': 'Yehuda!', - 'last-name': 'Katz' + 'last-name': 'Katz', }, relationships: { company: { - data: { type: 'companies', id: '2' } - } - } - } - } + data: { type: 'companies', id: '2' }, + }, + }, + }, + }, }); }); }); @@ -854,44 +920,55 @@ test('update record', function(assert) { test('update record - serialize hasMany', function(assert) { assert.expect(3); - ajaxResponse([{ - data: { - type: 'users', - id: '1' - } - }]); + ajaxResponse([ + { + data: { + type: 'users', + id: '1', + }, + }, + ]); - env.registry.register('serializer:user', DS.JSONAPISerializer.extend({ - attrs: { - handles: { serialize: true } - } - })); + env.registry.register( + 'serializer:user', + DS.JSONAPISerializer.extend({ + attrs: { + handles: { serialize: true }, + }, + }) + ); return run(() => { - let user = store.push({ data: { - type: 'user', - id: '1', - attributes: { - firstName: 'Yehuda', - lastName: 'Katz' - } - } }); - - let githubHandle = store.push({ data: { - type: 'github-handle', - id: '2', - attributes: { - username: 'wycats' - } - } }); - - let twitterHandle = store.push({ data: { - type: 'twitter-handle', - id: '3', - attributes: { - nickname: '@wycats' - } - } }); + let user = store.push({ + data: { + type: 'user', + id: '1', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz', + }, + }, + }); + + let githubHandle = store.push({ + data: { + type: 'github-handle', + id: '2', + attributes: { + username: 'wycats', + }, + }, + }); + + let twitterHandle = store.push({ + data: { + type: 'twitter-handle', + id: '3', + attributes: { + nickname: '@wycats', + }, + }, + }); user.set('firstName', 'Yehuda!'); @@ -904,23 +981,20 @@ test('update record - serialize hasMany', function(assert) { assert.equal(passedVerb[0], 'PATCH'); assert.deepEqual(passedHash[0], { data: { - data : { + data: { type: 'users', id: '1', attributes: { 'first-name': 'Yehuda!', - 'last-name': 'Katz' + 'last-name': 'Katz', }, relationships: { handles: { - data: [ - { type: 'github-handles', id: '2' }, - { type: 'twitter-handles', id: '3' } - ] - } - } - } - } + data: [{ type: 'github-handles', id: '2' }, { type: 'twitter-handles', id: '3' }], + }, + }, + }, + }, }); }); }); @@ -930,32 +1004,38 @@ test('update record - serialize hasMany', function(assert) { test('fetching a belongsTo relationship link that returns null', function(assert) { assert.expect(3); - ajaxResponse([{ - data: { - type: 'post', - id: '1', - attributes: { - title: 'Ember.js rocks' + ajaxResponse([ + { + data: { + type: 'post', + id: '1', + attributes: { + title: 'Ember.js rocks', + }, + relationships: { + author: { + links: { + related: 'http://example.com/post/1/author', + }, + }, + }, }, - relationships: { - author: { - links: { - related: 'http://example.com/post/1/author' - } - } - } - } - }, { - data: null - }]); + }, + { + data: null, + }, + ]); return run(() => { - return store.findRecord('post', 1).then(post => { - assert.equal(passedUrl[0], '/posts/1'); - return post.get('author'); - }).then(author => { - assert.equal(passedUrl[1], 'http://example.com/post/1/author'); - assert.strictEqual(author, null); - }); + return store + .findRecord('post', 1) + .then(post => { + assert.equal(passedUrl[0], '/posts/1'); + return post.get('author'); + }) + .then(author => { + assert.equal(passedUrl[1], 'http://example.com/post/1/author'); + assert.strictEqual(author, null); + }); }); }); diff --git a/tests/integration/adapter/queries-test.js b/tests/integration/adapter/queries-test.js index d42574d137f..7ae4e1f7250 100644 --- a/tests/integration/adapter/queries-test.js +++ b/tests/integration/adapter/queries-test.js @@ -10,13 +10,13 @@ import DS from 'ember-data'; let Person, env, store, adapter; -module("integration/adapter/queries - Queries", { +module('integration/adapter/queries - Queries', { beforeEach() { Person = DS.Model.extend({ updatedAt: DS.attr('string'), name: DS.attr('string'), firstName: DS.attr('string'), - lastName: DS.attr('string') + lastName: DS.attr('string'), }); env = setupStore({ person: Person }); @@ -26,24 +26,24 @@ module("integration/adapter/queries - Queries", { afterEach() { run(env.container, 'destroy'); - } + }, }); -testInDebug("It raises an assertion when no type is passed", function(assert) { +testInDebug('It raises an assertion when no type is passed', function(assert) { assert.expectAssertion(() => { store.query(); }, "You need to pass a model name to the store's query method"); }); -testInDebug("It raises an assertion when no query hash is passed", function(assert) { +testInDebug('It raises an assertion when no query hash is passed', function(assert) { assert.expectAssertion(() => { store.query('person'); }, "You need to pass a query hash to the store's query method"); }); -test("When a query is made, the adapter should receive a record array it can populate with the results of the query.", function(assert) { +test('When a query is made, the adapter should receive a record array it can populate with the results of the query.', function(assert) { adapter.query = function(store, type, query, recordArray) { - assert.equal(type, Person, "the query method is called with the correct type"); + assert.equal(type, Person, 'the query method is called with the correct type'); return EmberPromise.resolve({ data: [ @@ -51,72 +51,93 @@ test("When a query is made, the adapter should receive a record array it can pop id: 1, type: 'person', attributes: { - name: "Peter Wagenet" - } + name: 'Peter Wagenet', + }, }, { id: 2, - type: "person", + type: 'person', attributes: { - name: "Brohuda Katz" - } - } - ] + name: 'Brohuda Katz', + }, + }, + ], }); - } + }; return store.query('person', { page: 1 }).then(queryResults => { - assert.equal(get(queryResults, 'length'), 2, "the record array has a length of 2 after the results are loaded"); - assert.equal(get(queryResults, 'isLoaded'), true, "the record array's `isLoaded` property should be true"); - - assert.equal(queryResults.objectAt(0).get('name'), "Peter Wagenet", "the first record is 'Peter Wagenet'"); - assert.equal(queryResults.objectAt(1).get('name'), "Brohuda Katz", "the second record is 'Brohuda Katz'"); + assert.equal( + get(queryResults, 'length'), + 2, + 'the record array has a length of 2 after the results are loaded' + ); + assert.equal( + get(queryResults, 'isLoaded'), + true, + "the record array's `isLoaded` property should be true" + ); + + assert.equal( + queryResults.objectAt(0).get('name'), + 'Peter Wagenet', + "the first record is 'Peter Wagenet'" + ); + assert.equal( + queryResults.objectAt(1).get('name'), + 'Brohuda Katz', + "the second record is 'Brohuda Katz'" + ); }); }); -test("a query can be updated via `update()`", function(assert) { +test('a query can be updated via `update()`', function(assert) { adapter.query = function() { return resolve({ data: [{ id: 'first', type: 'person' }] }); }; return run(() => { - return store.query('person', {}).then(query => { - assert.equal(query.get('length'), 1); - assert.equal(query.get('firstObject.id'), 'first'); - assert.equal(query.get('isUpdating'), false); - - adapter.query = function() { - assert.ok('query is called a second time'); - return resolve({data: [{ id: 'second', type: 'person' }] }); - }; - - let updateQuery = query.update(); - - assert.equal(query.get('isUpdating'), true); - - return updateQuery; - - }).then(query => { - assert.equal(query.get('length'), 1); - assert.equal(query.get('firstObject.id'), 'second'); - - assert.equal(query.get('isUpdating'), false); - }); + return store + .query('person', {}) + .then(query => { + assert.equal(query.get('length'), 1); + assert.equal(query.get('firstObject.id'), 'first'); + assert.equal(query.get('isUpdating'), false); + + adapter.query = function() { + assert.ok('query is called a second time'); + return resolve({ data: [{ id: 'second', type: 'person' }] }); + }; + + let updateQuery = query.update(); + + assert.equal(query.get('isUpdating'), true); + + return updateQuery; + }) + .then(query => { + assert.equal(query.get('length'), 1); + assert.equal(query.get('firstObject.id'), 'second'); + + assert.equal(query.get('isUpdating'), false); + }); }); }); -testInDebug("The store asserts when query is made and the adapter responses with a single record.", function(assert) { - env = setupStore({ person: Person, adapter: DS.RESTAdapter }); - store = env.store; - adapter = env.adapter; +testInDebug( + 'The store asserts when query is made and the adapter responses with a single record.', + function(assert) { + env = setupStore({ person: Person, adapter: DS.RESTAdapter }); + store = env.store; + adapter = env.adapter; - adapter.query = function(store, type, query, recordArray) { - assert.equal(type, Person, "the query method is called with the correct type"); + adapter.query = function(store, type, query, recordArray) { + assert.equal(type, Person, 'the query method is called with the correct type'); - return resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Peter Wagenet" } }] }); - }; + return resolve({ data: [{ id: 1, type: 'person', attributes: { name: 'Peter Wagenet' } }] }); + }; - assert.expectAssertion(() => { - run(() => store.query('person', { page: 1 })); - }, /The response to store.query is expected to be an array but it was a single record/); -}); + assert.expectAssertion(() => { + run(() => store.query('person', { page: 1 })); + }, /The response to store.query is expected to be an array but it was a single record/); + } +); diff --git a/tests/integration/adapter/record-persistence-test.js b/tests/integration/adapter/record-persistence-test.js index 62da7acd16f..1ce033654ca 100644 --- a/tests/integration/adapter/record-persistence-test.js +++ b/tests/integration/adapter/record-persistence-test.js @@ -11,35 +11,35 @@ const { attr } = DS; let Person, env, store; -module("integration/adapter/record_persistence - Persisting Records", { +module('integration/adapter/record_persistence - Persisting Records', { beforeEach() { Person = DS.Model.extend({ updatedAt: attr('string'), name: attr('string'), firstName: attr('string'), - lastName: attr('string') + lastName: attr('string'), }); env = setupStore({ adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord: () => false + shouldBackgroundReloadRecord: () => false, }), - person: Person + person: Person, }); store = env.store; }, afterEach() { run(env.container, 'destroy'); - } + }, }); test("When a store is committed, the adapter's `commit` method should be called with records that have been changed.", function(assert) { assert.expect(2); env.adapter.updateRecord = function(store, type, snapshot) { - assert.equal(type, Person, "the type is correct"); - assert.equal(snapshot.record, tom, "the record is correct"); + assert.equal(type, Person, 'the type is correct'); + assert.equal(snapshot.record, tom, 'the record is correct'); return run(RSVP, 'resolve'); }; @@ -50,9 +50,9 @@ test("When a store is committed, the adapter's `commit` method should be called type: 'person', id: '1', attributes: { - name: 'Braaaahm Dale' - } - } + name: 'Braaaahm Dale', + }, + }, }); }); @@ -61,7 +61,7 @@ test("When a store is committed, the adapter's `commit` method should be called return run(() => { return env.store.findRecord('person', 1).then(person => { tom = person; - set(tom, "name", "Tom Dale"); + set(tom, 'name', 'Tom Dale'); return tom.save(); }); }); @@ -72,40 +72,40 @@ test("When a store is committed, the adapter's `commit` method should be called let tom; env.adapter.createRecord = function(store, type, snapshot) { - assert.equal(type, Person, "the type is correct"); - assert.equal(snapshot.record, tom, "the record is correct"); + assert.equal(type, Person, 'the type is correct'); + assert.equal(snapshot.record, tom, 'the record is correct'); - return resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale" } } }); + return resolve({ data: { id: 1, type: 'person', attributes: { name: 'Tom Dale' } } }); }; return run(() => { - tom = env.store.createRecord('person', { name: "Tom Dale" }); + tom = env.store.createRecord('person', { name: 'Tom Dale' }); return tom.save(); }); }); -test("After a created record has been assigned an ID, finding a record by that ID returns the original record.", function(assert) { +test('After a created record has been assigned an ID, finding a record by that ID returns the original record.', function(assert) { assert.expect(1); let tom; env.adapter.createRecord = function(store, type, snapshot) { - return resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale" } } }); + return resolve({ data: { id: 1, type: 'person', attributes: { name: 'Tom Dale' } } }); }; return run(() => { - tom = env.store.createRecord('person', { name: "Tom Dale" }); + tom = env.store.createRecord('person', { name: 'Tom Dale' }); return tom.save(); }).then(tom => { return env.store.find('person', 1).then(nextTom => { - assert.equal(tom, nextTom, "the retrieved record is the same as the created record"); + assert.equal(tom, nextTom, 'the retrieved record is the same as the created record'); }); }); }); test("when a store is committed, the adapter's `commit` method should be called with records that have been deleted.", function(assert) { env.adapter.deleteRecord = function(store, type, snapshot) { - assert.equal(type, Person, "the type is correct"); - assert.equal(snapshot.record, tom, "the record is correct"); + assert.equal(type, Person, 'the type is correct'); + assert.equal(snapshot.record, tom, 'the record is correct'); return run(RSVP, 'resolve'); }; @@ -118,22 +118,25 @@ test("when a store is committed, the adapter's `commit` method should be called type: 'person', id: '1', attributes: { - name: "Tom Dale" - } - } + name: 'Tom Dale', + }, + }, }); }); - return env.store.findRecord('person', 1).then(person => { - tom = person; - tom.deleteRecord(); - return tom.save(); - }).then(tom => { - assert.equal(get(tom, 'isDeleted'), true, "record is marked as deleted"); - }); + return env.store + .findRecord('person', 1) + .then(person => { + tom = person; + tom.deleteRecord(); + return tom.save(); + }) + .then(tom => { + assert.equal(get(tom, 'isDeleted'), true, 'record is marked as deleted'); + }); }); -test("An adapter can notify the store that records were updated by calling `didSaveRecords`.", function(assert) { +test('An adapter can notify the store that records were updated by calling `didSaveRecords`.', function(assert) { assert.expect(6); let tom, yehuda; @@ -144,196 +147,252 @@ test("An adapter can notify the store that records were updated by calling `didS run(() => { env.store.push({ - data: [{ - type: 'person', - id: '1' - }, { - type: 'person', - id: '2' - }] + data: [ + { + type: 'person', + id: '1', + }, + { + type: 'person', + id: '2', + }, + ], }); }); - return all([ - env.store.findRecord('person', 1), - env.store.findRecord('person', 2) - ]) - .then(array => { - tom = array[0]; - yehuda = array[1]; + return all([env.store.findRecord('person', 1), env.store.findRecord('person', 2)]).then(array => { + tom = array[0]; + yehuda = array[1]; - tom.set('name', "Michael Phelps"); - yehuda.set('name', "Usain Bolt"); + tom.set('name', 'Michael Phelps'); + yehuda.set('name', 'Usain Bolt'); - assert.ok(tom.get('hasDirtyAttributes'), "tom is dirty"); - assert.ok(yehuda.get('hasDirtyAttributes'), "yehuda is dirty"); - - let savedTom = assert.assertClean(tom.save()).then(record => { - assert.equal(record, tom, "The record is correct"); - }); + assert.ok(tom.get('hasDirtyAttributes'), 'tom is dirty'); + assert.ok(yehuda.get('hasDirtyAttributes'), 'yehuda is dirty'); - let savedYehuda = assert.assertClean(yehuda.save()).then(record => { - assert.equal(record, yehuda, "The record is correct"); - }); + let savedTom = assert.assertClean(tom.save()).then(record => { + assert.equal(record, tom, 'The record is correct'); + }); - return all([ - savedTom, - savedYehuda - ]); + let savedYehuda = assert.assertClean(yehuda.save()).then(record => { + assert.equal(record, yehuda, 'The record is correct'); }); + + return all([savedTom, savedYehuda]); + }); }); -test("An adapter can notify the store that records were updated and provide new data by calling `didSaveRecords`.", function(assert) { +test('An adapter can notify the store that records were updated and provide new data by calling `didSaveRecords`.', function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { - if (snapshot.id === "1") { - return resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale", "updated-at": "now" } } }); - } else if (snapshot.id === "2") { - return resolve({ data: { id: 2, type: "person", attributes: { name: "Yehuda Katz", "updated-at": "now!" } } }); + if (snapshot.id === '1') { + return resolve({ + data: { id: 1, type: 'person', attributes: { name: 'Tom Dale', 'updated-at': 'now' } }, + }); + } else if (snapshot.id === '2') { + return resolve({ + data: { id: 2, type: 'person', attributes: { name: 'Yehuda Katz', 'updated-at': 'now!' } }, + }); } }; run(() => { env.store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Braaaahm Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Gentile Katz' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Braaaahm Dale', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Gentile Katz', + }, + }, + ], }); }); return hash({ tom: env.store.findRecord('person', 1), - yehuda: env.store.findRecord('person', 2) - }).then(people => { - people.tom.set('name', "Draaaaaahm Dale"); - people.yehuda.set('name', "Goy Katz"); - - return hash({ - tom: people.tom.save(), - yehuda: people.yehuda.save() + yehuda: env.store.findRecord('person', 2), + }) + .then(people => { + people.tom.set('name', 'Draaaaaahm Dale'); + people.yehuda.set('name', 'Goy Katz'); + + return hash({ + tom: people.tom.save(), + yehuda: people.yehuda.save(), + }); + }) + .then(people => { + assert.equal( + people.tom.get('name'), + 'Tom Dale', + 'name attribute should reflect value of hash passed to didSaveRecords' + ); + assert.equal( + people.tom.get('updatedAt'), + 'now', + 'updatedAt attribute should reflect value of hash passed to didSaveRecords' + ); + assert.equal( + people.yehuda.get('name'), + 'Yehuda Katz', + 'name attribute should reflect value of hash passed to didSaveRecords' + ); + assert.equal( + people.yehuda.get('updatedAt'), + 'now!', + 'updatedAt attribute should reflect value of hash passed to didSaveRecords' + ); }); - }).then(people => { - assert.equal(people.tom.get('name'), "Tom Dale", "name attribute should reflect value of hash passed to didSaveRecords"); - assert.equal(people.tom.get('updatedAt'), "now", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); - assert.equal(people.yehuda.get('name'), "Yehuda Katz", "name attribute should reflect value of hash passed to didSaveRecords"); - assert.equal(people.yehuda.get('updatedAt'), "now!", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); - }); }); -test("An adapter can notify the store that a record was updated by calling `didSaveRecord`.", function(assert) { +test('An adapter can notify the store that a record was updated by calling `didSaveRecord`.', function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { return resolve(); }; run(() => { store.push({ - data: [{ - type: 'person', - id: '1' - }, { - type: 'person', - id: '2' - }] + data: [ + { + type: 'person', + id: '1', + }, + { + type: 'person', + id: '2', + }, + ], }); }); return hash({ tom: store.findRecord('person', 1), - yehuda: store.findRecord('person', 2) + yehuda: store.findRecord('person', 2), }).then(people => { - people.tom.set('name', "Tom Dale"); - people.yehuda.set('name', "Yehuda Katz"); + people.tom.set('name', 'Tom Dale'); + people.yehuda.set('name', 'Yehuda Katz'); - assert.ok(people.tom.get('hasDirtyAttributes'), "tom is dirty"); - assert.ok(people.yehuda.get('hasDirtyAttributes'), "yehuda is dirty"); + assert.ok(people.tom.get('hasDirtyAttributes'), 'tom is dirty'); + assert.ok(people.yehuda.get('hasDirtyAttributes'), 'yehuda is dirty'); assert.assertClean(people.tom.save()); assert.assertClean(people.yehuda.save()); }); }); -test("An adapter can notify the store that a record was updated and provide new data by calling `didSaveRecord`.", function(assert) { +test('An adapter can notify the store that a record was updated and provide new data by calling `didSaveRecord`.', function(assert) { env.adapter.updateRecord = function(store, type, snapshot) { switch (snapshot.id) { - case "1": - return resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale", "updated-at": "now" } } }); - case "2": - return resolve({ data: { id: 2, type: "person", attributes: { name: "Yehuda Katz", "updated-at": "now!" } } }); + case '1': + return resolve({ + data: { id: 1, type: 'person', attributes: { name: 'Tom Dale', 'updated-at': 'now' } }, + }); + case '2': + return resolve({ + data: { + id: 2, + type: 'person', + attributes: { name: 'Yehuda Katz', 'updated-at': 'now!' }, + }, + }); } }; run(() => { env.store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Braaaahm Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Gentile Katz' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Braaaahm Dale', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Gentile Katz', + }, + }, + ], }); }); return hash({ tom: store.findRecord('person', 1), - yehuda: store.findRecord('person', 2) - }).then(people => { - people.tom.set('name', "Draaaaaahm Dale"); - people.yehuda.set('name', "Goy Katz"); - - return hash({ - tom: people.tom.save(), - yehuda: people.yehuda.save() + yehuda: store.findRecord('person', 2), + }) + .then(people => { + people.tom.set('name', 'Draaaaaahm Dale'); + people.yehuda.set('name', 'Goy Katz'); + + return hash({ + tom: people.tom.save(), + yehuda: people.yehuda.save(), + }); + }) + .then(people => { + assert.equal( + people.tom.get('name'), + 'Tom Dale', + 'name attribute should reflect value of hash passed to didSaveRecords' + ); + assert.equal( + people.tom.get('updatedAt'), + 'now', + 'updatedAt attribute should reflect value of hash passed to didSaveRecords' + ); + assert.equal( + people.yehuda.get('name'), + 'Yehuda Katz', + 'name attribute should reflect value of hash passed to didSaveRecords' + ); + assert.equal( + people.yehuda.get('updatedAt'), + 'now!', + 'updatedAt attribute should reflect value of hash passed to didSaveRecords' + ); }); - }).then(people => { - assert.equal(people.tom.get('name'), "Tom Dale", "name attribute should reflect value of hash passed to didSaveRecords"); - assert.equal(people.tom.get('updatedAt'), "now", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); - assert.equal(people.yehuda.get('name'), "Yehuda Katz", "name attribute should reflect value of hash passed to didSaveRecords"); - assert.equal(people.yehuda.get('updatedAt'), "now!", "updatedAt attribute should reflect value of hash passed to didSaveRecords"); - }); }); -test("An adapter can notify the store that records were deleted by calling `didSaveRecords`.", function(assert) { +test('An adapter can notify the store that records were deleted by calling `didSaveRecords`.', function(assert) { env.adapter.deleteRecord = function(store, type, snapshot) { return resolve(); }; run(() => { env.store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Braaaahm Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Gentile Katz' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Braaaahm Dale', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Gentile Katz', + }, + }, + ], }); }); return hash({ tom: store.findRecord('person', 1), - yehuda: store.findRecord('person', 2) + yehuda: store.findRecord('person', 2), }).then(people => { people.tom.deleteRecord(); people.yehuda.deleteRecord(); diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index 61ca6b3f822..af83bc8ff4d 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -8,7 +8,7 @@ import deepCopy from 'dummy/tests/helpers/deep-copy'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; -import Pretender from "pretender"; +import Pretender from 'pretender'; import DS from 'ember-data'; @@ -16,14 +16,14 @@ let env, store, adapter, Post, Comment, SuperUser; let passedUrl, passedVerb, passedHash; let server; -module("integration/adapter/rest_adapter - REST Adapter", { +module('integration/adapter/rest_adapter - REST Adapter', { beforeEach() { Post = DS.Model.extend({ - name: DS.attr("string") + name: DS.attr('string'), }); Comment = DS.Model.extend({ - name: DS.attr("string") + name: DS.attr('string'), }); SuperUser = DS.Model.extend(); @@ -32,7 +32,7 @@ module("integration/adapter/rest_adapter - REST Adapter", { post: Post, comment: Comment, superUser: SuperUser, - adapter: DS.RESTAdapter + adapter: DS.RESTAdapter, }); server = new Pretender(); @@ -46,7 +46,7 @@ module("integration/adapter/rest_adapter - REST Adapter", { server.shutdown(); server = null; } - } + }, }); function ajaxResponse(value) { @@ -64,213 +64,235 @@ function ajaxError(responseText, status = 400, headers = '') { let jqXHR = { status, responseText, - getAllResponseHeaders() { return headers; } + getAllResponseHeaders() { + return headers; + }, }; hash.error(jqXHR, responseText); }; } -test("findRecord - basic payload", function(assert) { - ajaxResponse({ posts: [{ id: 1, name: "Rails is omakase" }] }); - - return run(() => store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, "/posts/1"); - assert.equal(passedVerb, "GET"); - assert.deepEqual(passedHash.data, {}); +test('findRecord - basic payload', function(assert) { + ajaxResponse({ posts: [{ id: 1, name: 'Rails is omakase' }] }); - assert.equal(post.get('id'), "1"); - assert.equal(post.get('name'), "Rails is omakase"); - })); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); + + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); + }) + ); }); - -test("findRecord - passes buildURL a requestType", function(assert) { +test('findRecord - passes buildURL a requestType', function(assert) { adapter.buildURL = function(type, id, snapshot, requestType) { - return "/" + requestType + "/post/" + id; + return '/' + requestType + '/post/' + id; }; - ajaxResponse({ posts: [{ id: 1, name: "Rails is omakase" }] }); + ajaxResponse({ posts: [{ id: 1, name: 'Rails is omakase' }] }); - - return run(() => store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, "/findRecord/post/1"); - })); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/findRecord/post/1'); + }) + ); }); -test("findRecord - basic payload (with legacy singular name)", function(assert) { - ajaxResponse({ post: { id: 1, name: "Rails is omakase" } }); - - return run(() => store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, "/posts/1"); - assert.equal(passedVerb, "GET"); - assert.deepEqual(passedHash.data, {}); +test('findRecord - basic payload (with legacy singular name)', function(assert) { + ajaxResponse({ post: { id: 1, name: 'Rails is omakase' } }); - assert.equal(post.get('id'), "1"); - assert.equal(post.get('name'), "Rails is omakase"); - })); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); + + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); + }) + ); }); -test("findRecord - payload with sideloaded records of the same type", function(assert) { +test('findRecord - payload with sideloaded records of the same type', function(assert) { ajaxResponse({ - posts: [ - { id: 1, name: "Rails is omakase" }, - { id: 2, name: "The Parley Letter" } - ] + posts: [{ id: 1, name: 'Rails is omakase' }, { id: 2, name: 'The Parley Letter' }], }); - return run(() => store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, "/posts/1"); - assert.equal(passedVerb, "GET"); - assert.deepEqual(passedHash.data, {}); - - assert.equal(post.get('id'), "1"); - assert.equal(post.get('name'), "Rails is omakase"); - - let post2 = store.peekRecord('post', 2); - assert.equal(post2.get('id'), "2"); - assert.equal(post2.get('name'), "The Parley Letter"); - })); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); + + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); + + let post2 = store.peekRecord('post', 2); + assert.equal(post2.get('id'), '2'); + assert.equal(post2.get('name'), 'The Parley Letter'); + }) + ); }); -test("findRecord - payload with sideloaded records of a different type", function(assert) { +test('findRecord - payload with sideloaded records of a different type', function(assert) { ajaxResponse({ - posts: [{ id: 1, name: "Rails is omakase" }], - comments: [{ id: 1, name: "FIRST" }] + posts: [{ id: 1, name: 'Rails is omakase' }], + comments: [{ id: 1, name: 'FIRST' }], }); - return run(() => store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, "/posts/1"); - assert.equal(passedVerb, "GET"); - assert.deepEqual(passedHash.data, {}); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - assert.equal(post.get('id'), "1"); - assert.equal(post.get('name'), "Rails is omakase"); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); - let comment = store.peekRecord('comment', 1); - assert.equal(comment.get('id'), "1"); - assert.equal(comment.get('name'), "FIRST"); - })); + let comment = store.peekRecord('comment', 1); + assert.equal(comment.get('id'), '1'); + assert.equal(comment.get('name'), 'FIRST'); + }) + ); }); +test('findRecord - payload with an serializer-specified primary key', function(assert) { + env.registry.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + }) + ); -test("findRecord - payload with an serializer-specified primary key", function(assert) { - env.registry.register('serializer:post', DS.RESTSerializer.extend({ - primaryKey: '_ID_' - })); - - ajaxResponse({ posts: [{ "_ID_": 1, name: "Rails is omakase" }] }); - - return run(() => store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, "/posts/1"); - assert.equal(passedVerb, "GET"); - assert.deepEqual(passedHash.data, {}); + ajaxResponse({ posts: [{ _ID_: 1, name: 'Rails is omakase' }] }); - assert.equal(post.get('id'), "1"); - assert.equal(post.get('name'), "Rails is omakase"); - })); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); + + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); + }) + ); }); -test("findRecord - payload with a serializer-specified attribute mapping", function(assert) { - env.registry.register('serializer:post', DS.RESTSerializer.extend({ - attrs: { - 'name': '_NAME_', - 'createdAt': { key: '_CREATED_AT_', someOtherOption: 'option' } - } - })); +test('findRecord - payload with a serializer-specified attribute mapping', function(assert) { + env.registry.register( + 'serializer:post', + DS.RESTSerializer.extend({ + attrs: { + name: '_NAME_', + createdAt: { key: '_CREATED_AT_', someOtherOption: 'option' }, + }, + }) + ); Post.reopen({ - createdAt: DS.attr("number") + createdAt: DS.attr('number'), }); - ajaxResponse({ posts: [{ id: 1, _NAME_: "Rails is omakase", _CREATED_AT_: 2013 }] }); - - return run(() => store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, "/posts/1"); - assert.equal(passedVerb, "GET"); - assert.deepEqual(passedHash.data, {}); + ajaxResponse({ posts: [{ id: 1, _NAME_: 'Rails is omakase', _CREATED_AT_: 2013 }] }); - assert.equal(post.get('id'), "1"); - assert.equal(post.get('name'), "Rails is omakase"); - assert.equal(post.get('createdAt'), 2013); - })); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); + + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); + assert.equal(post.get('createdAt'), 2013); + }) + ); }); -test("findRecord - passes `include` as a query parameter to ajax", function(assert) { +test('findRecord - passes `include` as a query parameter to ajax', function(assert) { ajaxResponse({ - post: { id: 1, name: 'Rails is very expensive sushi' } + post: { id: 1, name: 'Rails is very expensive sushi' }, }); - return run(() => store.findRecord('post', 1, { include: 'comments' }).then(() => { - assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` parameter sent to adapter.ajax'); - })); + return run(() => + store.findRecord('post', 1, { include: 'comments' }).then(() => { + assert.deepEqual( + passedHash.data, + { include: 'comments' }, + '`include` parameter sent to adapter.ajax' + ); + }) + ); }); -test("createRecord - an empty payload is a basic success if an id was specified", function(assert) { +test('createRecord - an empty payload is a basic success if an id was specified', function(assert) { ajaxResponse(); return run(() => { - let post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); + let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); return post.save().then(post => { - assert.equal(passedUrl, "/posts"); - assert.equal(passedVerb, "POST"); - assert.deepEqual(passedHash.data, { post: { id: "some-uuid", name: "The Parley Letter" } }); + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'POST'); + assert.deepEqual(passedHash.data, { post: { id: 'some-uuid', name: 'The Parley Letter' } }); assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), "The Parley Letter", "the post was updated"); + assert.equal(post.get('name'), 'The Parley Letter', 'the post was updated'); }); }); }); -test("createRecord - passes buildURL the requestType", function(assert) { +test('createRecord - passes buildURL the requestType', function(assert) { adapter.buildURL = function(type, id, snapshot, requestType) { - return "/post/" + requestType; + return '/post/' + requestType; }; ajaxResponse(); return run(() => { - let post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); + let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); return post.save().then(post => { - assert.equal(passedUrl, "/post/createRecord"); + assert.equal(passedUrl, '/post/createRecord'); }); }); }); -test("createRecord - a payload with a new ID and data applies the updates", function(assert) { - ajaxResponse({ posts: [{ id: "1", name: "Dat Parley Letter" }] }); +test('createRecord - a payload with a new ID and data applies the updates', function(assert) { + ajaxResponse({ posts: [{ id: '1', name: 'Dat Parley Letter' }] }); return run(() => { - let post = store.createRecord('post', { name: "The Parley Letter" }); + let post = store.createRecord('post', { name: 'The Parley Letter' }); return post.save().then(post => { - assert.equal(passedUrl, "/posts"); - assert.equal(passedVerb, "POST"); - assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'POST'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - assert.equal(post.get('id'), "1", "the post has the updated ID"); + assert.equal(post.get('id'), '1', 'the post has the updated ID'); assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); }); }); }); -test("createRecord - a payload with a new ID and data applies the updates (with legacy singular name)", function(assert) { - ajaxResponse({ post: { id: "1", name: "Dat Parley Letter" } }); - let post = store.createRecord('post', { name: "The Parley Letter" }); +test('createRecord - a payload with a new ID and data applies the updates (with legacy singular name)', function(assert) { + ajaxResponse({ post: { id: '1', name: 'Dat Parley Letter' } }); + let post = store.createRecord('post', { name: 'The Parley Letter' }); return run(post, 'save').then(post => { - assert.equal(passedUrl, "/posts"); - assert.equal(passedVerb, "POST"); - assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'POST'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - assert.equal(post.get('id'), "1", "the post has the updated ID"); + assert.equal(post.get('id'), '1', 'the post has the updated ID'); assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); }); }); test("createRecord - findMany doesn't overwrite owner", function(assert) { - ajaxResponse({ comment: { id: "1", name: "Dat Parley Letter", post: 1 } }); + ajaxResponse({ comment: { id: '1', name: 'Dat Parley Letter', post: 1 } }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); @@ -281,168 +303,202 @@ test("createRecord - findMany doesn't overwrite owner", function(assert) { type: 'post', id: '1', attributes: { - name: "Rails is omakase" + name: 'Rails is omakase', }, relationships: { comments: { - data: [] - } - } - } + data: [], + }, + }, + }, }); }); let post = store.peekRecord('post', 1); - let comment = store.createRecord('comment', { name: "The Parley Letter" }); + let comment = store.createRecord('comment', { name: 'The Parley Letter' }); run(() => { post.get('comments').pushObject(comment); - assert.equal(comment.get('post'), post, "the post has been set correctly"); + assert.equal(comment.get('post'), post, 'the post has been set correctly'); }); return run(() => { return comment.save().then(comment => { assert.equal(comment.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(comment.get('name'), "Dat Parley Letter", "the post was updated"); - assert.equal(comment.get('post'), post, "the post is still set"); + assert.equal(comment.get('name'), 'Dat Parley Letter', 'the post was updated'); + assert.equal(comment.get('post'), post, 'the post is still set'); }); }); }); test("createRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { - env.registry.register('serializer:post', DS.RESTSerializer.extend({ - primaryKey: '_id_', + env.registry.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_id_', - attrs: { - name: '_name_' - } - })); + attrs: { + name: '_name_', + }, + }) + ); ajaxResponse(); - let post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); + let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); return run(() => - post.save() - .then(post => { - assert.deepEqual(passedHash.data, { post: { _id_: 'some-uuid', '_name_': "The Parley Letter" } }); - }) + post.save().then(post => { + assert.deepEqual(passedHash.data, { + post: { _id_: 'some-uuid', _name_: 'The Parley Letter' }, + }); + }) ); }); test("createRecord - a serializer's attributes are consulted when building the payload if no id is pre-defined", function(assert) { let post; - env.registry.register('serializer:post', DS.RESTSerializer.extend({ - attrs: { - name: '_name_' - } - })); + env.registry.register( + 'serializer:post', + DS.RESTSerializer.extend({ + attrs: { + name: '_name_', + }, + }) + ); ajaxResponse({ - post: { '_name_': "The Parley Letter", id: '1' } + post: { _name_: 'The Parley Letter', id: '1' }, }); return run(() => { - post = store.createRecord('post', { name: "The Parley Letter" }); + post = store.createRecord('post', { name: 'The Parley Letter' }); return post.save().then(post => { - assert.deepEqual(passedHash.data, { post: { '_name_': "The Parley Letter" } }); + assert.deepEqual(passedHash.data, { post: { _name_: 'The Parley Letter' } }); }); }); }); test("createRecord - a serializer's attribute mapping takes precedence over keyForAttribute when building the payload", function(assert) { - env.registry.register('serializer:post', DS.RESTSerializer.extend({ - attrs: { - name: 'given_name' - }, + env.registry.register( + 'serializer:post', + DS.RESTSerializer.extend({ + attrs: { + name: 'given_name', + }, - keyForAttribute(attr) { - return attr.toUpperCase(); - } - })); + keyForAttribute(attr) { + return attr.toUpperCase(); + }, + }) + ); ajaxResponse(); return run(() => { - let post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter" }); + let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); return post.save().then(post => { - assert.deepEqual(passedHash.data, { post: { 'given_name': "The Parley Letter", id: "some-uuid" } }); + assert.deepEqual(passedHash.data, { + post: { given_name: 'The Parley Letter', id: 'some-uuid' }, + }); }); }); }); test("createRecord - a serializer's attribute mapping takes precedence over keyForRelationship (belongsTo) when building the payload", function(assert) { - env.registry.register('serializer:comment', DS.RESTSerializer.extend({ - attrs: { - post: 'article' - }, + env.registry.register( + 'serializer:comment', + DS.RESTSerializer.extend({ + attrs: { + post: 'article', + }, - keyForRelationship(attr, kind) { - return attr.toUpperCase(); - } - })); + keyForRelationship(attr, kind) { + return attr.toUpperCase(); + }, + }) + ); ajaxResponse(); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); return run(() => { - let post = store.createRecord('post', { id: "a-post-id", name: "The Parley Letter" }); - let comment = store.createRecord('comment', { id: "some-uuid", name: "Letters are fun", post: post }); + let post = store.createRecord('post', { id: 'a-post-id', name: 'The Parley Letter' }); + let comment = store.createRecord('comment', { + id: 'some-uuid', + name: 'Letters are fun', + post: post, + }); return comment.save().then(post => { - assert.deepEqual(passedHash.data, { comment: { article: "a-post-id", id: "some-uuid", name: "Letters are fun" } }); + assert.deepEqual(passedHash.data, { + comment: { article: 'a-post-id', id: 'some-uuid', name: 'Letters are fun' }, + }); }); }); }); test("createRecord - a serializer's attribute mapping takes precedence over keyForRelationship (hasMany) when building the payload", function(assert) { - env.registry.register('serializer:post', DS.RESTSerializer.extend({ - attrs: { - comments: 'opinions' - }, + env.registry.register( + 'serializer:post', + DS.RESTSerializer.extend({ + attrs: { + comments: 'opinions', + }, - keyForRelationship(attr, kind) { - return attr.toUpperCase(); - } - })); + keyForRelationship(attr, kind) { + return attr.toUpperCase(); + }, + }) + ); ajaxResponse(); Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); return run(() => { - let comment = store.createRecord('comment', { id: "a-comment-id", name: "First!" }); - let post = store.createRecord('post', { id: "some-uuid", name: "The Parley Letter", comments: [comment] }); + let comment = store.createRecord('comment', { id: 'a-comment-id', name: 'First!' }); + let post = store.createRecord('post', { + id: 'some-uuid', + name: 'The Parley Letter', + comments: [comment], + }); return post.save().then(post => { - assert.deepEqual(passedHash.data, { post: { opinions: ["a-comment-id"], id: "some-uuid", name: "The Parley Letter" } }); + assert.deepEqual(passedHash.data, { + post: { opinions: ['a-comment-id'], id: 'some-uuid', name: 'The Parley Letter' }, + }); }); }); }); -test("createRecord - a record on the many side of a hasMany relationship should update relationships when data is sideloaded", function(assert) { +test('createRecord - a record on the many side of a hasMany relationship should update relationships when data is sideloaded', function(assert) { assert.expect(3); ajaxResponse({ - posts: [{ - id: "1", - name: "Rails is omakase", - comments: [1,2] - }], - comments: [{ - id: "2", - name: "Another Comment", - post: 1 - }, - { - id: "1", - name: "Dat Parley Letter", - post: 1 - }] + posts: [ + { + id: '1', + name: 'Rails is omakase', + comments: [1, 2], + }, + ], + comments: [ + { + id: '2', + name: 'Another Comment', + post: 1, + }, + { + id: '1', + name: 'Dat Parley Letter', + post: 1, + }, + ], // My API is returning a comment:{} as well as a comments:[{...},...] //, comment: { // id: "2", @@ -460,69 +516,79 @@ test("createRecord - a record on the many side of a hasMany relationship should type: 'post', id: '1', attributes: { - name: "Rails is omakase" + name: 'Rails is omakase', }, relationships: { comments: { - data: [ - { type: 'comment', id: '1' } - ] - } - } - } + data: [{ type: 'comment', id: '1' }], + }, + }, + }, }); store.push({ data: { type: 'comment', id: '1', attributes: { - name: "Dat Parlay Letter" + name: 'Dat Parlay Letter', }, relationships: { post: { - data: { type: 'post', id: '1' } - } - } - } + data: { type: 'post', id: '1' }, + }, + }, + }, }); }); let post = store.peekRecord('post', 1); let commentCount = run(() => post.get('comments.length')); - assert.equal(commentCount, 1, "the post starts life with a comment"); + assert.equal(commentCount, 1, 'the post starts life with a comment'); return run(() => { - let comment = store.createRecord('comment', { name: "Another Comment", post: post }); + let comment = store.createRecord('comment', { name: 'Another Comment', post: post }); return comment.save().then(comment => { - assert.equal(comment.get('post'), post, "the comment is related to the post"); + assert.equal(comment.get('post'), post, 'the comment is related to the post'); return post.reload().then(post => { - assert.equal(post.get('comments.length'), 2, "Post comment count has been updated"); + assert.equal(post.get('comments.length'), 2, 'Post comment count has been updated'); }); }); }); }); -test("createRecord - sideloaded belongsTo relationships are both marked as loaded", function(assert) { +test('createRecord - sideloaded belongsTo relationships are both marked as loaded', function(assert) { assert.expect(4); Post.reopen({ comment: DS.belongsTo('comment', { async: false }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - let post = store.createRecord('post', { name: "man" }); + let post = store.createRecord('post', { name: 'man' }); ajaxResponse({ - posts: [{ id: 1, comment: 1, name: "marked" }], - comments: [{ id: 1, post: 1, name: "Comcast is a bargain" }] + posts: [{ id: 1, comment: 1, name: 'marked' }], + comments: [{ id: 1, post: 1, name: 'Comcast is a bargain' }], }); return run(() => { return post.save().then(record => { - assert.equal(store.peekRecord('post', 1).get('comment.isLoaded'), true, "post's comment isLoaded (via store)"); - assert.equal(store.peekRecord('comment', 1).get('post.isLoaded'), true, "comment's post isLoaded (via store)"); + assert.equal( + store.peekRecord('post', 1).get('comment.isLoaded'), + true, + "post's comment isLoaded (via store)" + ); + assert.equal( + store.peekRecord('comment', 1).get('post.isLoaded'), + true, + "comment's post isLoaded (via store)" + ); assert.equal(record.get('comment.isLoaded'), true, "post's comment isLoaded (via record)"); - assert.equal(record.get('comment.post.isLoaded'), true, "post's comment's post isLoaded (via record)"); + assert.equal( + record.get('comment.post.isLoaded'), + true, + "post's comment's post isLoaded (via record)" + ); }); }); }); @@ -531,71 +597,92 @@ test("createRecord - response can contain relationships the client doesn't yet k assert.expect(3); // while records.length is 2, we are getting 4 assertions ajaxResponse({ - posts: [{ - id: "1", - name: "Rails is omakase", - comments: [2] - }], - comments: [{ - id: "2", - name: "Another Comment", - post: 1 - }] + posts: [ + { + id: '1', + name: 'Rails is omakase', + comments: [2], + }, + ], + comments: [ + { + id: '2', + name: 'Another Comment', + post: 1, + }, + ], }); Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - let post = store.createRecord('post', { name: "Rails is omakase" }); + let post = store.createRecord('post', { name: 'Rails is omakase' }); return run(() => { return post.save().then(post => { - assert.equal(post.get('comments.firstObject.post'), post, "the comments are related to the correct post model"); - assert.equal(store._internalModelsFor('post').models.length, 1, "There should only be one post record in the store"); + assert.equal( + post.get('comments.firstObject.post'), + post, + 'the comments are related to the correct post model' + ); + assert.equal( + store._internalModelsFor('post').models.length, + 1, + 'There should only be one post record in the store' + ); let postRecords = store._internalModelsFor('post').models; for (var i = 0; i < postRecords.length; i++) { - assert.equal(post, postRecords[i].getRecord(), "The object in the identity map is the same"); + assert.equal( + post, + postRecords[i].getRecord(), + 'The object in the identity map is the same' + ); } }); }); }); -test("createRecord - relationships are not duplicated", function(assert) { +test('createRecord - relationships are not duplicated', function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - let post = store.createRecord('post', { name: "Tomtomhuda" }); - let comment = store.createRecord('comment', { id: 2, name: "Comment title" }); + let post = store.createRecord('post', { name: 'Tomtomhuda' }); + let comment = store.createRecord('comment', { id: 2, name: 'Comment title' }); - ajaxResponse({ post: [{ id: 1, name: "Rails is omakase", comments: [] }] }); + ajaxResponse({ post: [{ id: 1, name: 'Rails is omakase', comments: [] }] }); - return run(() => post.save().then(post => { - assert.equal(post.get('comments.length'), 0, "post has 0 comments"); - post.get('comments').pushObject(comment); - assert.equal(post.get('comments.length'), 1, "post has 1 comment"); + return run(() => + post + .save() + .then(post => { + assert.equal(post.get('comments.length'), 0, 'post has 0 comments'); + post.get('comments').pushObject(comment); + assert.equal(post.get('comments.length'), 1, 'post has 1 comment'); - ajaxResponse({ - post: [{ id: 1, name: "Rails is omakase", comments: [2] }], - comments: [{ id: 2, name: "Comment title" }] - }); + ajaxResponse({ + post: [{ id: 1, name: 'Rails is omakase', comments: [2] }], + comments: [{ id: 2, name: 'Comment title' }], + }); - return post.save(); - }).then(post => { - assert.equal(post.get('comments.length'), 1, "post has 1 comment"); - })); + return post.save(); + }) + .then(post => { + assert.equal(post.get('comments.length'), 1, 'post has 1 comment'); + }) + ); }); -test("updateRecord - an empty payload is a basic success", function(assert) { +test('updateRecord - an empty payload is a basic success', function(assert) { run(() => { store.push({ data: { type: 'post', id: '1', attributes: { - name: "Rails is omakase" - } - } + name: 'Rails is omakase', + }, + }, }); }); @@ -603,21 +690,21 @@ test("updateRecord - an empty payload is a basic success", function(assert) { let post = store.peekRecord('post', 1); ajaxResponse(); - post.set('name', "The Parley Letter"); + post.set('name', 'The Parley Letter'); return post.save().then(post => { - assert.equal(passedUrl, "/posts/1"); - assert.equal(passedVerb, "PUT"); - assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'PUT'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), "The Parley Letter", "the post was updated"); + assert.equal(post.get('name'), 'The Parley Letter', 'the post was updated'); }); }); }); -test("updateRecord - passes the requestType to buildURL", function(assert) { +test('updateRecord - passes the requestType to buildURL', function(assert) { adapter.buildURL = function(type, id, snapshot, requestType) { - return "/posts/" + id + "/" + requestType; + return '/posts/' + id + '/' + requestType; }; adapter.shouldBackgroundReloadRecord = () => false; @@ -627,25 +714,28 @@ test("updateRecord - passes the requestType to buildURL", function(assert) { type: 'post', id: '1', attributes: { - name: "Rails is omakase" - } - } + name: 'Rails is omakase', + }, + }, }); }); return run(() => { - return store.findRecord('post', 1).then(post => { - ajaxResponse(); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse(); - post.set('name', "The Parley Letter"); - return post.save(); - }).then(post => { - assert.equal(passedUrl, "/posts/1/updateRecord"); - }); + post.set('name', 'The Parley Letter'); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1/updateRecord'); + }); }); }); -test("updateRecord - a payload with updates applies the updates", function(assert) { +test('updateRecord - a payload with updates applies the updates', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(() => { store.push({ @@ -653,28 +743,31 @@ test("updateRecord - a payload with updates applies the updates", function(asser type: 'post', id: '1', attributes: { - name: "Rails is omakase" - } - } + name: 'Rails is omakase', + }, + }, }); }); - return store.findRecord('post', 1).then(post => { - ajaxResponse({ posts: [{ id: 1, name: "Dat Parley Letter" }] }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ posts: [{ id: 1, name: 'Dat Parley Letter' }] }); - post.set('name', "The Parley Letter"); - return post.save(); - }).then(post => { - assert.equal(passedUrl, "/posts/1"); - assert.equal(passedVerb, "PUT"); - assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); + post.set('name', 'The Parley Letter'); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'PUT'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); - }); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); + }); }); -test("updateRecord - a payload with updates applies the updates (with legacy singular name)", function(assert) { +test('updateRecord - a payload with updates applies the updates (with legacy singular name)', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(() => { store.push({ @@ -682,52 +775,55 @@ test("updateRecord - a payload with updates applies the updates (with legacy sin type: 'post', id: '1', attributes: { - name: "Rails is omakase" - } - } + name: 'Rails is omakase', + }, + }, }); }); - return store.findRecord('post', 1).then(post =>{ - ajaxResponse({ post: { id: 1, name: "Dat Parley Letter" } }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ post: { id: 1, name: 'Dat Parley Letter' } }); - post.set('name', "The Parley Letter"); - return post.save(); - }).then(post => { - assert.equal(passedUrl, "/posts/1"); - assert.equal(passedVerb, "PUT"); - assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); + post.set('name', 'The Parley Letter'); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'PUT'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); - }); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); + }); }); -test("updateRecord - a payload with sideloaded updates pushes the updates", function(assert) { +test('updateRecord - a payload with sideloaded updates pushes the updates', function(assert) { let post; ajaxResponse({ - posts: [{ id: 1, name: "Dat Parley Letter" }], - comments: [{ id: 1, name: "FIRST" }] + posts: [{ id: 1, name: 'Dat Parley Letter' }], + comments: [{ id: 1, name: 'FIRST' }], }); return run(() => { - post = store.createRecord('post', { name: "The Parley Letter" }); + post = store.createRecord('post', { name: 'The Parley Letter' }); return post.save().then(post => { - assert.equal(passedUrl, "/posts"); - assert.equal(passedVerb, "POST"); - assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'POST'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - assert.equal(post.get('id'), "1", "the post has the updated ID"); + assert.equal(post.get('id'), '1', 'the post has the updated ID'); assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); let comment = store.peekRecord('comment', 1); - assert.equal(comment.get('name'), "FIRST", "The comment was sideloaded"); + assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); }); }); }); -test("updateRecord - a payload with sideloaded updates pushes the updates", function(assert) { +test('updateRecord - a payload with sideloaded updates pushes the updates', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(() => { store.push({ @@ -735,64 +831,73 @@ test("updateRecord - a payload with sideloaded updates pushes the updates", func type: 'post', id: '1', attributes: { - name: "Rails is omakase" - } - } + name: 'Rails is omakase', + }, + }, }); }); - return store.findRecord('post', 1).then(post => { - ajaxResponse({ - posts: [{ id: 1, name: "Dat Parley Letter" }], - comments: [{ id: 1, name: "FIRST" }] - }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + posts: [{ id: 1, name: 'Dat Parley Letter' }], + comments: [{ id: 1, name: 'FIRST' }], + }); - post.set('name', "The Parley Letter"); - return post.save(); - }).then(post => { - assert.equal(passedUrl, "/posts/1"); - assert.equal(passedVerb, "PUT"); - assert.deepEqual(passedHash.data, { post: { name: "The Parley Letter" } }); + post.set('name', 'The Parley Letter'); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'PUT'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), "Dat Parley Letter", "the post was updated"); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); - let comment = store.peekRecord('comment', 1); - assert.equal(comment.get('name'), "FIRST", "The comment was sideloaded"); - }); + let comment = store.peekRecord('comment', 1); + assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); + }); }); test("updateRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; - env.registry.register('serializer:post', DS.RESTSerializer.extend({ - primaryKey: '_id_', + env.registry.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_id_', - attrs: { - name: '_name_' - } - })); + attrs: { + name: '_name_', + }, + }) + ); run(() => { store.push({ data: { type: 'post', id: '1', - name: "Rails is omakase" - } + name: 'Rails is omakase', + }, }); }); ajaxResponse(); - return store.findRecord('post', 1).then(post => { - post.set('name', "The Parley Letter"); - return post.save(); - }).then(post => { - assert.deepEqual(passedHash.data, { post: { '_name_': "The Parley Letter" } }); - }); + return store + .findRecord('post', 1) + .then(post => { + post.set('name', 'The Parley Letter'); + return post.save(); + }) + .then(post => { + assert.deepEqual(passedHash.data, { post: { _name_: 'The Parley Letter' } }); + }); }); -test("updateRecord - hasMany relationships faithfully reflect simultaneous adds and removes", function(assert) { +test('updateRecord - hasMany relationships faithfully reflect simultaneous adds and removes', function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); adapter.shouldBackgroundReloadRecord = () => false; @@ -803,54 +908,63 @@ test("updateRecord - hasMany relationships faithfully reflect simultaneous adds type: 'post', id: '1', attributes: { - name: "Not everyone uses Rails" + name: 'Not everyone uses Rails', }, relationships: { comments: { - data: [ - { type: 'comment', id: '1' } - ] - } - } + data: [{ type: 'comment', id: '1' }], + }, + }, }, - included: [{ - type: 'comment', - id: '1', - attributes: { - name: "Rails is omakase" - } - }, { - type: 'comment', - id: '2', - attributes: { - name: "Yes. Yes it is." - } - }] + included: [ + { + type: 'comment', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + }, + { + type: 'comment', + id: '2', + attributes: { + name: 'Yes. Yes it is.', + }, + }, + ], }); }); ajaxResponse({ - posts: { id: 1, name: "Not everyone uses Rails", comments: [2] } + posts: { id: 1, name: 'Not everyone uses Rails', comments: [2] }, }); - return store.findRecord('comment', 2).then(() => { - return store.findRecord('post', 1); - }).then(post => { - let newComment = store.peekRecord('comment', 2); - let comments = post.get('comments'); + return store + .findRecord('comment', 2) + .then(() => { + return store.findRecord('post', 1); + }) + .then(post => { + let newComment = store.peekRecord('comment', 2); + let comments = post.get('comments'); - // Replace the comment with a new one - comments.popObject(); - comments.pushObject(newComment); + // Replace the comment with a new one + comments.popObject(); + comments.pushObject(newComment); - return post.save(); - }).then(post => { - assert.equal(post.get('comments.length'), 1, "the post has the correct number of comments"); - assert.equal(post.get('comments.firstObject.name'), "Yes. Yes it is.", "the post has the correct comment"); - }); + return post.save(); + }) + .then(post => { + assert.equal(post.get('comments.length'), 1, 'the post has the correct number of comments'); + assert.equal( + post.get('comments.firstObject.name'), + 'Yes. Yes it is.', + 'the post has the correct comment' + ); + }); }); -test("deleteRecord - an empty payload is a basic success", function(assert) { +test('deleteRecord - an empty payload is a basic success', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(() => { store.push({ @@ -858,31 +972,34 @@ test("deleteRecord - an empty payload is a basic success", function(assert) { type: 'post', id: '1', attributes: { - name: "Rails is omakase" - } - } + name: 'Rails is omakase', + }, + }, }); }); - return store.findRecord('post', 1).then(post => { - ajaxResponse(); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse(); - post.deleteRecord(); - return post.save(); - }).then(post => { - assert.equal(passedUrl, "/posts/1"); - assert.equal(passedVerb, "DELETE"); - assert.strictEqual(passedHash, undefined); + post.deleteRecord(); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'DELETE'); + assert.strictEqual(passedHash, undefined); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('isDeleted'), true, "the post is now deleted"); - }); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); + }); }); -test("deleteRecord - passes the requestType to buildURL", function(assert) { +test('deleteRecord - passes the requestType to buildURL', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.buildURL = function(type, id, snapshot, requestType) { - return "/posts/" + id + "/" + requestType; + return '/posts/' + id + '/' + requestType; }; run(() => { @@ -891,23 +1008,26 @@ test("deleteRecord - passes the requestType to buildURL", function(assert) { type: 'post', id: '1', attributes: { - name: "Rails is omakase" - } - } + name: 'Rails is omakase', + }, + }, }); }); - return store.findRecord('post', 1).then(post => { - ajaxResponse(); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse(); - post.deleteRecord(); - return post.save(); - }).then(post => { - assert.equal(passedUrl, "/posts/1/deleteRecord"); - }); + post.deleteRecord(); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1/deleteRecord'); + }); }); -test("deleteRecord - a payload with sideloaded updates pushes the updates", function(assert) { +test('deleteRecord - a payload with sideloaded updates pushes the updates', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(() => { store.push({ @@ -915,31 +1035,34 @@ test("deleteRecord - a payload with sideloaded updates pushes the updates", func type: 'post', id: '1', attributes: { - name: "Rails is omakase" - } - } + name: 'Rails is omakase', + }, + }, }); }); - return store.findRecord('post', 1).then(post => { - ajaxResponse({ comments: [{ id: 1, name: "FIRST" }] }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ comments: [{ id: 1, name: 'FIRST' }] }); - post.deleteRecord(); - return post.save(); - }).then(post => { - assert.equal(passedUrl, "/posts/1"); - assert.equal(passedVerb, "DELETE"); - assert.strictEqual(passedHash, undefined); + post.deleteRecord(); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'DELETE'); + assert.strictEqual(passedHash, undefined); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('isDeleted'), true, "the post is now deleted"); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); - let comment = store.peekRecord('comment', 1); - assert.equal(comment.get('name'), "FIRST", "The comment was sideloaded"); - }); + let comment = store.peekRecord('comment', 1); + assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); + }); }); -test("deleteRecord - a payload with sidloaded updates pushes the updates when the original record is omitted", function(assert) { +test('deleteRecord - a payload with sidloaded updates pushes the updates when the original record is omitted', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; run(() => { store.push({ @@ -947,57 +1070,69 @@ test("deleteRecord - a payload with sidloaded updates pushes the updates when th type: 'post', id: '1', attributes: { - name: "Rails is omakase" - } - } + name: 'Rails is omakase', + }, + }, }); }); - return store.findRecord('post', 1).then(post => { - ajaxResponse({ posts: [{ id: 2, name: "The Parley Letter" }] }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ posts: [{ id: 2, name: 'The Parley Letter' }] }); - post.deleteRecord(); - return post.save(); - }).then(post => { - assert.equal(passedUrl, "/posts/1"); - assert.equal(passedVerb, "DELETE"); - assert.strictEqual(passedHash, undefined); + post.deleteRecord(); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'DELETE'); + assert.strictEqual(passedHash, undefined); - assert.equal(post.get('hasDirtyAttributes'), false, "the original post isn't dirty anymore"); - assert.equal(post.get('isDeleted'), true, "the original post is now deleted"); + assert.equal(post.get('hasDirtyAttributes'), false, "the original post isn't dirty anymore"); + assert.equal(post.get('isDeleted'), true, 'the original post is now deleted'); - let newPost = store.peekRecord('post', 2); - assert.equal(newPost.get('name'), "The Parley Letter", "The new post was added to the store"); - }); + let newPost = store.peekRecord('post', 2); + assert.equal(newPost.get('name'), 'The Parley Letter', 'The new post was added to the store'); + }); }); -test("deleteRecord - deleting a newly created record should not throw an error", function(assert) { +test('deleteRecord - deleting a newly created record should not throw an error', function(assert) { let post = store.createRecord('post'); return run(() => { post.deleteRecord(); return post.save().then(post => { - assert.equal(passedUrl, null, "There is no ajax call to delete a record that has never been saved."); - assert.equal(passedVerb, null, "There is no ajax call to delete a record that has never been saved."); - assert.equal(passedHash, null, "There is no ajax call to delete a record that has never been saved."); + assert.equal( + passedUrl, + null, + 'There is no ajax call to delete a record that has never been saved.' + ); + assert.equal( + passedVerb, + null, + 'There is no ajax call to delete a record that has never been saved.' + ); + assert.equal( + passedHash, + null, + 'There is no ajax call to delete a record that has never been saved.' + ); - assert.equal(post.get('isDeleted'), true, "the post is now deleted"); - assert.equal(post.get('isError'), false, "the post is not an error"); + assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); + assert.equal(post.get('isError'), false, 'the post is not an error'); }); }); }); -test("findAll - returning an array populates the array", function(assert) { +test('findAll - returning an array populates the array', function(assert) { ajaxResponse({ - posts: [ - { id: 1, name: "Rails is omakase" }, - { id: 2, name: "The Parley Letter" } - ] + posts: [{ id: 1, name: 'Rails is omakase' }, { id: 2, name: 'The Parley Letter' }], }); return store.findAll('post').then(posts => { - assert.equal(passedUrl, "/posts"); - assert.equal(passedVerb, "GET"); + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'GET'); assert.deepEqual(passedHash.data, {}); let post1 = store.peekRecord('post', 1); @@ -1005,83 +1140,77 @@ test("findAll - returning an array populates the array", function(assert) { assert.deepEqual( post1.getProperties('id', 'name'), - { id: "1", name: "Rails is omakase" }, - "Post 1 is loaded" + { id: '1', name: 'Rails is omakase' }, + 'Post 1 is loaded' ); assert.deepEqual( post2.getProperties('id', 'name'), - { id: "2", name: "The Parley Letter" }, - "Post 2 is loaded" + { id: '2', name: 'The Parley Letter' }, + 'Post 2 is loaded' ); - assert.equal(posts.get('length'), 2, "The posts are in the array"); - assert.equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); - assert.deepEqual( - posts.toArray(), - [post1, post2], - "The correct records are in the array" - ); + assert.equal(posts.get('length'), 2, 'The posts are in the array'); + assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); + assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); }); }); - -test("findAll - passes buildURL the requestType and snapshot", function(assert) { +test('findAll - passes buildURL the requestType and snapshot', function(assert) { assert.expect(2); let adapterOptionsStub = { stub: true }; adapter.buildURL = function(type, id, snapshot, requestType) { assert.equal(snapshot.adapterOptions, adapterOptionsStub); - return "/" + requestType + "/posts"; + return '/' + requestType + '/posts'; }; ajaxResponse({ - posts: [ - { id: 1, name: "Rails is omakase" }, - { id: 2, name: "The Parley Letter" } - ] + posts: [{ id: 1, name: 'Rails is omakase' }, { id: 2, name: 'The Parley Letter' }], }); return store.findAll('post', { adapterOptions: adapterOptionsStub }).then(posts => { - assert.equal(passedUrl, "/findAll/posts"); + assert.equal(passedUrl, '/findAll/posts'); }); }); -test("findAll - passed `include` as a query parameter to ajax", function(assert) { +test('findAll - passed `include` as a query parameter to ajax', function(assert) { ajaxResponse({ - posts: [{ id: 1, name: 'Rails is very expensive sushi' }] + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], }); return run(store, 'findAll', 'post', { include: 'comments' }).then(() => { - assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` params sent to adapter.ajax'); + assert.deepEqual( + passedHash.data, + { include: 'comments' }, + '`include` params sent to adapter.ajax' + ); }); }); -test("findAll - returning sideloaded data loads the data", function(assert) { +test('findAll - returning sideloaded data loads the data', function(assert) { ajaxResponse({ - posts: [ - { id: 1, name: "Rails is omakase" }, - { id: 2, name: "The Parley Letter" } - ], - comments: [{ id: 1, name: "FIRST" }] }); + posts: [{ id: 1, name: 'Rails is omakase' }, { id: 2, name: 'The Parley Letter' }], + comments: [{ id: 1, name: 'FIRST' }], + }); return store.findAll('post').then(posts => { let comment = store.peekRecord('comment', 1); - assert.deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); + assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); }); }); -test("findAll - data is normalized through custom serializers", function(assert) { - env.registry.register('serializer:post', DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' } - })); +test('findAll - data is normalized through custom serializers', function(assert) { + env.registry.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); ajaxResponse({ - posts: [ - { _ID_: 1, _NAME_: "Rails is omakase" }, - { _ID_: 2, _NAME_: "The Parley Letter" } - ] + posts: [{ _ID_: 1, _NAME_: 'Rails is omakase' }, { _ID_: 2, _NAME_: 'The Parley Letter' }], }); return store.findAll('post').then(posts => { @@ -1090,68 +1219,74 @@ test("findAll - data is normalized through custom serializers", function(assert) assert.deepEqual( post1.getProperties('id', 'name'), - { id: "1", name: "Rails is omakase" }, - "Post 1 is loaded" + { id: '1', name: 'Rails is omakase' }, + 'Post 1 is loaded' ); assert.deepEqual( post2.getProperties('id', 'name'), - { id: "2", name: "The Parley Letter" }, - "Post 2 is loaded" + { id: '2', name: 'The Parley Letter' }, + 'Post 2 is loaded' ); - assert.equal(posts.get('length'), 2, "The posts are in the array"); - assert.equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); - assert.deepEqual( - posts.toArray(), - [post1, post2], - "The correct records are in the array" - ); + assert.equal(posts.get('length'), 2, 'The posts are in the array'); + assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); + assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); }); }); -test("query - if `sortQueryParams` option is not provided, query params are sorted alphabetically", function(assert) { +test('query - if `sortQueryParams` option is not provided, query params are sorted alphabetically', function(assert) { ajaxResponse({ - posts: [{ id: 1, name: "Rails is very expensive sushi" }] + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], }); - return store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(() => { - assert.deepEqual(Object.keys(passedHash.data), ["in", "order", "params", "wrong"], 'query params are received in alphabetical order'); + return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { + assert.deepEqual( + Object.keys(passedHash.data), + ['in', 'order', 'params', 'wrong'], + 'query params are received in alphabetical order' + ); }); }); -test("query - passes buildURL the requestType", function(assert) { +test('query - passes buildURL the requestType', function(assert) { adapter.buildURL = function(type, id, snapshot, requestType) { - return "/" + requestType + "/posts"; + return '/' + requestType + '/posts'; }; ajaxResponse({ - posts: [{ id: 1, name: "Rails is very expensive sushi" }] + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], }); - return store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(() => { + return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { assert.equal(passedUrl, '/query/posts'); }); }); -test("query - if `sortQueryParams` is falsey, query params are not sorted at all", function(assert) { +test('query - if `sortQueryParams` is falsey, query params are not sorted at all', function(assert) { ajaxResponse({ - posts: [{ id: 1, name: "Rails is very expensive sushi" }] + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], }); adapter.sortQueryParams = null; - return store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(() => { - assert.deepEqual(Object.keys(passedHash.data), ["params", "in", "wrong", "order"], 'query params are received in their original order'); + return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { + assert.deepEqual( + Object.keys(passedHash.data), + ['params', 'in', 'wrong', 'order'], + 'query params are received in their original order' + ); }); }); -test("query - if `sortQueryParams` is a custom function, query params passed through that function", function(assert) { +test('query - if `sortQueryParams` is a custom function, query params passed through that function', function(assert) { ajaxResponse({ - posts: [{ id: 1, name: "Rails is very expensive sushi" }] + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], }); adapter.sortQueryParams = function(obj) { - let sortedKeys = Object.keys(obj).sort().reverse(); + let sortedKeys = Object.keys(obj) + .sort() + .reverse(); let len = sortedKeys.length; let newQueryParams = {}; @@ -1161,22 +1296,26 @@ test("query - if `sortQueryParams` is a custom function, query params passed thr return newQueryParams; }; - return store.query('post', { "params": 1, "in": 2, "wrong": 3, "order": 4 }).then(() => { - assert.deepEqual(Object.keys(passedHash.data), ["wrong", "params", "order", "in"], 'query params are received in reverse alphabetical order'); + return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { + assert.deepEqual( + Object.keys(passedHash.data), + ['wrong', 'params', 'order', 'in'], + 'query params are received in reverse alphabetical order' + ); }); }); test("query - payload 'meta' is accessible on the record array", function(assert) { ajaxResponse({ meta: { offset: 5 }, - posts: [{ id: 1, name: "Rails is very expensive sushi" }] + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], }); return store.query('post', { page: 2 }).then(posts => { assert.equal( posts.get('meta.offset'), 5, - "Reponse metadata can be accessed with recordArray.meta" + 'Reponse metadata can be accessed with recordArray.meta' ); }); }); @@ -1184,18 +1323,18 @@ test("query - payload 'meta' is accessible on the record array", function(assert test("query - each record array can have it's own meta object", function(assert) { ajaxResponse({ meta: { offset: 5 }, - posts: [{ id: 1, name: "Rails is very expensive sushi" }] + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], }); return store.query('post', { page: 2 }).then(posts => { assert.equal( posts.get('meta.offset'), 5, - "Reponse metadata can be accessed with recordArray.meta" + 'Reponse metadata can be accessed with recordArray.meta' ); ajaxResponse({ meta: { offset: 1 }, - posts: [{ id: 1, name: "Rails is very expensive sushi" }] + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], }); return store.query('post', { page: 1 }).then(newPosts => { @@ -1205,12 +1344,9 @@ test("query - each record array can have it's own meta object", function(assert) }); }); - -test("query - returning an array populates the array", function(assert) { +test('query - returning an array populates the array', function(assert) { ajaxResponse({ - posts: [ - { id: 1, name: "Rails is omakase" }, - { id: 2, name: "The Parley Letter" }] + posts: [{ id: 1, name: 'Rails is omakase' }, { id: 2, name: 'The Parley Letter' }], }); return store.query('post', { page: 1 }).then(posts => { @@ -1223,50 +1359,45 @@ test("query - returning an array populates the array", function(assert) { assert.deepEqual( post1.getProperties('id', 'name'), - { id: "1", name: "Rails is omakase" }, - "Post 1 is loaded" + { id: '1', name: 'Rails is omakase' }, + 'Post 1 is loaded' ); assert.deepEqual( post2.getProperties('id', 'name'), - { id: "2", name: "The Parley Letter" }, - "Post 2 is loaded" + { id: '2', name: 'The Parley Letter' }, + 'Post 2 is loaded' ); - assert.equal(posts.get('length'), 2, "The posts are in the array"); - assert.equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); - assert.deepEqual( - posts.toArray(), - [post1, post2], - "The correct records are in the array" - ); + assert.equal(posts.get('length'), 2, 'The posts are in the array'); + assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); + assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); }); }); -test("query - returning sideloaded data loads the data", function(assert) { +test('query - returning sideloaded data loads the data', function(assert) { ajaxResponse({ - posts: [ - { id: 1, name: "Rails is omakase" }, - { id: 2, name: "The Parley Letter" } - ], - comments: [{ id: 1, name: "FIRST" }] + posts: [{ id: 1, name: 'Rails is omakase' }, { id: 2, name: 'The Parley Letter' }], + comments: [{ id: 1, name: 'FIRST' }], }); return store.query('post', { page: 1 }).then(posts => { let comment = store.peekRecord('comment', 1); - assert.deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); + assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); }); }); -test("query - data is normalized through custom serializers", function(assert) { - env.registry.register('serializer:post', DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' } - })); +test('query - data is normalized through custom serializers', function(assert) { + env.registry.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); ajaxResponse({ - posts: [{ _ID_: 1, _NAME_: "Rails is omakase" }, - { _ID_: 2, _NAME_: "The Parley Letter" }] + posts: [{ _ID_: 1, _NAME_: 'Rails is omakase' }, { _ID_: 2, _NAME_: 'The Parley Letter' }], }); return store.query('post', { page: 1 }).then(posts => { @@ -1275,27 +1406,23 @@ test("query - data is normalized through custom serializers", function(assert) { assert.deepEqual( post1.getProperties('id', 'name'), - { id: "1", name: "Rails is omakase" }, - "Post 1 is loaded" + { id: '1', name: 'Rails is omakase' }, + 'Post 1 is loaded' ); assert.deepEqual( post2.getProperties('id', 'name'), - { id: "2", name: "The Parley Letter" }, - "Post 2 is loaded" + { id: '2', name: 'The Parley Letter' }, + 'Post 2 is loaded' ); - assert.equal(posts.get('length'), 2, "The posts are in the array"); - assert.equal(posts.get('isLoaded'), true, "The RecordArray is loaded"); - assert.deepEqual( - posts.toArray(), - [post1, post2], - "The correct records are in the array" - ); + assert.equal(posts.get('length'), 2, 'The posts are in the array'); + assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); + assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); }); }); -test("queryRecord - empty response", function(assert) { +test('queryRecord - empty response', function(assert) { ajaxResponse({}); return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { @@ -1303,9 +1430,9 @@ test("queryRecord - empty response", function(assert) { }); }); -test("queryRecord - primary data being null", function(assert) { +test('queryRecord - primary data being null', function(assert) { ajaxResponse({ - post: null + post: null, }); return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { @@ -1313,65 +1440,74 @@ test("queryRecord - primary data being null", function(assert) { }); }); -test("queryRecord - primary data being a single object", function(assert) { +test('queryRecord - primary data being a single object', function(assert) { ajaxResponse({ post: { id: '1', - name: 'Ember.js rocks' - } + name: 'Ember.js rocks', + }, }); return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { - assert.deepEqual(post.get('name'), "Ember.js rocks"); + assert.deepEqual(post.get('name'), 'Ember.js rocks'); }); }); -test("queryRecord - returning sideloaded data loads the data", function(assert) { +test('queryRecord - returning sideloaded data loads the data', function(assert) { ajaxResponse({ - post: { id: 1, name: "Rails is omakase" }, - comments: [{ id: 1, name: "FIRST" }] + post: { id: 1, name: 'Rails is omakase' }, + comments: [{ id: 1, name: 'FIRST' }], }); return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { let comment = store.peekRecord('comment', 1); - assert.deepEqual(comment.getProperties('id', 'name'), { id: "1", name: "FIRST" }); + assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); }); }); -testInDebug("queryRecord - returning an array picks the first one but saves all records to the store", function(assert) { - ajaxResponse({ - post: [{ id: 1, name: "Rails is omakase" }, { id: 2, name: "Ember is js" }] - }); +testInDebug( + 'queryRecord - returning an array picks the first one but saves all records to the store', + function(assert) { + ajaxResponse({ + post: [{ id: 1, name: 'Rails is omakase' }, { id: 2, name: 'Ember is js' }], + }); - assert.expectDeprecation( - () => - run(() => { - return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { - let post2 = store.peekRecord('post', 2); + assert.expectDeprecation( + () => + run(() => { + return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { + let post2 = store.peekRecord('post', 2); - assert.deepEqual(post.getProperties('id', 'name'), { id: "1", name: "Rails is omakase" }); - assert.deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "Ember is js" }); - }); - }), + assert.deepEqual(post.getProperties('id', 'name'), { + id: '1', + name: 'Rails is omakase', + }); + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'Ember is js' }); + }); + }), - /The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record./); -}); + /The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record./ + ); + } +); -testInDebug("queryRecord - returning an array is deprecated", function(assert) { +testInDebug('queryRecord - returning an array is deprecated', function(assert) { ajaxResponse({ - post: [{ id: 1, name: "Rails is omakase" }, { id: 2, name: "Ember is js" }] + post: [{ id: 1, name: 'Rails is omakase' }, { id: 2, name: 'Ember is js' }], }); assert.expectDeprecation( - () => - run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })), - 'The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record.'); + () => run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })), + 'The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record.' + ); }); -testInDebug("queryRecord - returning an single object doesn't throw a deprecation", function(assert) { +testInDebug("queryRecord - returning an single object doesn't throw a deprecation", function( + assert +) { ajaxResponse({ - post: { id: 1, name: "Rails is omakase" } + post: { id: 1, name: 'Rails is omakase' }, }); assert.expectNoDeprecation(); @@ -1379,26 +1515,29 @@ testInDebug("queryRecord - returning an single object doesn't throw a deprecatio return run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })); }); -test("queryRecord - data is normalized through custom serializers", function(assert) { - env.registry.register('serializer:post', DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' } - })); +test('queryRecord - data is normalized through custom serializers', function(assert) { + env.registry.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); ajaxResponse({ - post: { _ID_: 1, _NAME_: "Rails is omakase" } + post: { _ID_: 1, _NAME_: 'Rails is omakase' }, }); return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { assert.deepEqual( post.getProperties('id', 'name'), - { id: "1", name: "Rails is omakase" }, - "Post 1 is loaded with correct data" + { id: '1', name: 'Rails is omakase' }, + 'Post 1 is loaded with correct data' ); }); }); -test("findMany - findMany uses a correct URL to access the records", function(assert) { +test('findMany - findMany uses a correct URL to access the records', function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; @@ -1408,39 +1547,41 @@ test("findMany - findMany uses a correct URL to access the records", function(as type: 'post', id: '1', attributes: { - name: "Rails is omakase" + name: 'Rails is omakase', }, relationships: { comments: { data: [ { type: 'comment', id: '1' }, { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - } + { type: 'comment', id: '3' }, + ], + }, + }, + }, }); }); let post = store.peekRecord('post', 1); ajaxResponse({ comments: [ - { id: 1, name: "FIRST" }, - { id: 2, name: "Rails is unagi" }, - { id: 3, name: "What is omakase?" } - ] + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], }); - return run(() => post.get('comments').then(comments => { - assert.equal(passedUrl, "/comments"); - assert.deepEqual(passedHash, { data: { ids: ["1", "2", "3"] } }); - })); + return run(() => + post.get('comments').then(comments => { + assert.equal(passedUrl, '/comments'); + assert.deepEqual(passedHash, { data: { ids: ['1', '2', '3'] } }); + }) + ); }); -test("findMany - passes buildURL the requestType", function(assert) { +test('findMany - passes buildURL the requestType', function(assert) { adapter.buildURL = function(type, id, snapshot, requestType) { - return "/" + requestType + "/" + type; + return '/' + requestType + '/' + type; }; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -1452,36 +1593,36 @@ test("findMany - passes buildURL the requestType", function(assert) { type: 'post', id: '1', attributes: { - name: "Rails is omakase" + name: 'Rails is omakase', }, relationships: { comments: { data: [ { type: 'comment', id: '1' }, { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - } + { type: 'comment', id: '3' }, + ], + }, + }, + }, }); }); let post = store.peekRecord('post', 1); ajaxResponse({ comments: [ - { id: 1, name: "FIRST" }, - { id: 2, name: "Rails is unagi" }, - { id: 3, name: "What is omakase?" } - ] + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], }); return run(post, 'get', 'comments').then(comments => { - assert.equal(passedUrl, "/findMany/comment"); + assert.equal(passedUrl, '/findMany/comment'); }); }); -test("findMany - findMany does not coalesce by default", function(assert) { +test('findMany - findMany does not coalesce by default', function(assert) { Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); run(() => { @@ -1490,18 +1631,18 @@ test("findMany - findMany does not coalesce by default", function(assert) { type: 'post', id: '1', attributes: { - name: "Rails is omakase" + name: 'Rails is omakase', }, relationships: { comments: { data: [ { type: 'comment', id: '1' }, { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - } + { type: 'comment', id: '3' }, + ], + }, + }, + }, }); }); @@ -1509,19 +1650,21 @@ test("findMany - findMany does not coalesce by default", function(assert) { //It's still ok to return this even without coalescing because RESTSerializer supports sideloading ajaxResponse({ comments: [ - { id: 1, name: "FIRST" }, - { id: 2, name: "Rails is unagi" }, - { id: 3, name: "What is omakase?" } - ] + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], }); - return run(() => post.get('comments').then(comments => { - assert.equal(passedUrl, "/comments/3"); - assert.deepEqual(passedHash.data, {}); - })); + return run(() => + post.get('comments').then(comments => { + assert.equal(passedUrl, '/comments/3'); + assert.deepEqual(passedHash.data, {}); + }) + ); }); -test("findMany - returning an array populates the array", function(assert) { +test('findMany - returning an array populates the array', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; @@ -1532,49 +1675,52 @@ test("findMany - returning an array populates the array", function(assert) { type: 'post', id: '1', attributes: { - name: "Rails is omakase" + name: 'Rails is omakase', }, relationships: { comments: { data: [ { type: 'comment', id: '1' }, { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - } + { type: 'comment', id: '3' }, + ], + }, + }, + }, }); }); - return store.findRecord('post', 1).then(post => { - ajaxResponse({ - comments: [ - { id: 1, name: "FIRST" }, - { id: 2, name: "Rails is unagi" }, - { id: 3, name: "What is omakase?" } - ] - }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], + }); - return post.get('comments'); - }).then(comments => { - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); + return post.get('comments'); + }) + .then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); - assert.deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); - assert.deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); - assert.deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); + assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); + assert.deepEqual(comment3.getProperties('id', 'name'), { id: '3', name: 'What is omakase?' }); - assert.deepEqual( - comments.toArray(), - [comment1, comment2, comment3], - "The correct records are in the array" - ); - }); + assert.deepEqual( + comments.toArray(), + [comment1, comment2, comment3], + 'The correct records are in the array' + ); + }); }); -test("findMany - returning sideloaded data loads the data", function(assert) { +test('findMany - returning sideloaded data loads the data', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; @@ -1585,62 +1731,74 @@ test("findMany - returning sideloaded data loads the data", function(assert) { type: 'post', id: '1', attributes: { - name: "Rails is omakase" + name: 'Rails is omakase', }, relationships: { comments: { data: [ { type: 'comment', id: '1' }, { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - } + { type: 'comment', id: '3' }, + ], + }, + }, + }, }); }); - return store.findRecord('post', 1).then(post => { - ajaxResponse({ - comments: [ - { id: 1, name: "FIRST" }, - { id: 2, name: "Rails is unagi" }, - { id: 3, name: "What is omakase?" }, - { id: 4, name: "Unrelated comment" } - ], - posts: [{ id: 2, name: "The Parley Letter" }] - }); - - return post.get('comments'); - }).then(comments => { - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); - let comment4 = store.peekRecord('comment', 4); - let post2 = store.peekRecord('post', 2); - - assert.deepEqual( - comments.toArray(), - [comment1, comment2, comment3], - "The correct records are in the array" - ); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + { id: 4, name: 'Unrelated comment' }, + ], + posts: [{ id: 2, name: 'The Parley Letter' }], + }); - assert.deepEqual(comment4.getProperties('id', 'name'), { id: "4", name: "Unrelated comment" }); - assert.deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "The Parley Letter" }); - }); + return post.get('comments'); + }) + .then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); + let comment4 = store.peekRecord('comment', 4); + let post2 = store.peekRecord('post', 2); + + assert.deepEqual( + comments.toArray(), + [comment1, comment2, comment3], + 'The correct records are in the array' + ); + + assert.deepEqual(comment4.getProperties('id', 'name'), { + id: '4', + name: 'Unrelated comment', + }); + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }); + }); }); -test("findMany - a custom serializer is used if present", function(assert) { +test('findMany - a custom serializer is used if present', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; - env.registry.register('serializer:post', DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' } - })); + env.registry.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); - env.registry.register('serializer:comment', DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' } - })); + env.registry.register( + 'serializer:comment', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); adapter.coalesceFindRequests = true; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -1651,44 +1809,52 @@ test("findMany - a custom serializer is used if present", function(assert) { type: 'post', id: '1', attributes: { - name: "Rails is omakase" + name: 'Rails is omakase', }, relationships: { comments: { data: [ { type: 'comment', id: '1' }, { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - } + { type: 'comment', id: '3' }, + ], + }, + }, + }, }); }); - return store.findRecord('post', 1).then(post => { - ajaxResponse({ - comments: [ - { _ID_: 1, _NAME_: "FIRST" }, - { _ID_: 2, _NAME_: "Rails is unagi" }, - { _ID_: 3, _NAME_: "What is omakase?" }] - }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + comments: [ + { _ID_: 1, _NAME_: 'FIRST' }, + { _ID_: 2, _NAME_: 'Rails is unagi' }, + { _ID_: 3, _NAME_: 'What is omakase?' }, + ], + }); - return post.get('comments'); - }).then(comments => { - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); + return post.get('comments'); + }) + .then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); - assert.deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); - assert.deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); - assert.deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); + assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); + assert.deepEqual(comment3.getProperties('id', 'name'), { id: '3', name: 'What is omakase?' }); - assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); - }); + assert.deepEqual( + comments.toArray(), + [comment1, comment2, comment3], + 'The correct records are in the array' + ); + }); }); -test("findHasMany - returning an array populates the array", function(assert) { +test('findHasMany - returning an array populates the array', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -1698,47 +1864,59 @@ test("findHasMany - returning an array populates the array", function(assert) { type: 'post', id: '1', attributes: { - name: "Rails is omakase" + name: 'Rails is omakase', }, relationships: { comments: { links: { - related: '/posts/1/comments' - } - } - } - } + related: '/posts/1/comments', + }, + }, + }, + }, }); }); - return run(() => store.findRecord('post', '1').then(post => { - ajaxResponse({ - comments: [ - { id: 1, name: "FIRST" }, - { id: 2, name: "Rails is unagi" }, - { id: 3, name: "What is omakase?" } - ] - }); - - return post.get('comments'); - }).then(comments => { - assert.equal(passedUrl, '/posts/1/comments'); - assert.equal(passedVerb, 'GET'); - assert.strictEqual(passedHash, undefined); - - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); + return run(() => + store + .findRecord('post', '1') + .then(post => { + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], + }); - assert.deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); - assert.deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); - assert.deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); + return post.get('comments'); + }) + .then(comments => { + assert.equal(passedUrl, '/posts/1/comments'); + assert.equal(passedVerb, 'GET'); + assert.strictEqual(passedHash, undefined); + + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); + + assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); + assert.deepEqual(comment3.getProperties('id', 'name'), { + id: '3', + name: 'What is omakase?', + }); - assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); - })); + assert.deepEqual( + comments.toArray(), + [comment1, comment2, comment3], + 'The correct records are in the array' + ); + }) + ); }); -test("findHasMany - passes buildURL the requestType", function(assert) { +test('findHasMany - passes buildURL the requestType', function(assert) { assert.expect(2); adapter.shouldBackgroundReloadRecord = () => false; adapter.buildURL = function(type, id, snapshot, requestType) { @@ -1754,33 +1932,35 @@ test("findHasMany - passes buildURL the requestType", function(assert) { type: 'post', id: '1', attributes: { - name: "Rails is omakase" + name: 'Rails is omakase', }, relationships: { comments: { links: { - related: '/posts/1/comments' - } - } - } - } + related: '/posts/1/comments', + }, + }, + }, + }, }); }); - return run(() => store.findRecord('post', '1').then(post => { - ajaxResponse({ - comments: [ - { id: 1, name: "FIRST" }, - { id: 2, name: "Rails is unagi" }, - { id: 3, name: "What is omakase?" } - ] - }); + return run(() => + store.findRecord('post', '1').then(post => { + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], + }); - return post.get('comments'); - })); + return post.get('comments'); + }) + ); }); -test("findMany - returning sideloaded data loads the data (with JSONApi Links)", function(assert) { +test('findMany - returning sideloaded data loads the data (with JSONApi Links)', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); adapter.coalesceFindRequests = true; @@ -1791,53 +1971,66 @@ test("findMany - returning sideloaded data loads the data (with JSONApi Links)", type: 'post', id: '1', attributes: { - name: "Rails is omakase" + name: 'Rails is omakase', }, relationships: { comments: { links: { - related: '/posts/1/comments' - } - } - } - } + related: '/posts/1/comments', + }, + }, + }, + }, }); }); - return store.findRecord('post', 1).then(post => { - ajaxResponse({ - comments: [ - { id: 1, name: "FIRST" }, - { id: 2, name: "Rails is unagi" }, - { id: 3, name: "What is omakase?" } - ], - posts: [{ id: 2, name: "The Parley Letter" }] - }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], + posts: [{ id: 2, name: 'The Parley Letter' }], + }); - return post.get('comments'); - }).then(comments => { - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); - let post2 = store.peekRecord('post', 2); + return post.get('comments'); + }) + .then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); + let post2 = store.peekRecord('post', 2); - assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); + assert.deepEqual( + comments.toArray(), + [comment1, comment2, comment3], + 'The correct records are in the array' + ); - assert.deepEqual(post2.getProperties('id', 'name'), { id: "2", name: "The Parley Letter" }); - }); + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }); + }); }); -test("findMany - a custom serializer is used if present", function(assert) { +test('findMany - a custom serializer is used if present', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; - env.registry.register('serializer:post', DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' } - })); + env.registry.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); - env.registry.register('serializer:comment', DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' } - })); + env.registry.register( + 'serializer:comment', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); @@ -1847,39 +2040,46 @@ test("findMany - a custom serializer is used if present", function(assert) { type: 'post', id: '1', attributes: { - name: "Rails is omakase" + name: 'Rails is omakase', }, relationships: { comments: { links: { - related: '/posts/1/comments' - } - } - } - } + related: '/posts/1/comments', + }, + }, + }, + }, }); }); - return store.findRecord('post', 1).then(post => { - ajaxResponse({ - comments: [ - { _ID_: 1, _NAME_: "FIRST" }, - { _ID_: 2, _NAME_: "Rails is unagi" }, - { _ID_: 3, _NAME_: "What is omakase?" } - ] - }); - return post.get('comments'); - }).then(comments => { - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + comments: [ + { _ID_: 1, _NAME_: 'FIRST' }, + { _ID_: 2, _NAME_: 'Rails is unagi' }, + { _ID_: 3, _NAME_: 'What is omakase?' }, + ], + }); + return post.get('comments'); + }) + .then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); - assert.deepEqual(comment1.getProperties('id', 'name'), { id: "1", name: "FIRST" }); - assert.deepEqual(comment2.getProperties('id', 'name'), { id: "2", name: "Rails is unagi" }); - assert.deepEqual(comment3.getProperties('id', 'name'), { id: "3", name: "What is omakase?" }); + assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); + assert.deepEqual(comment3.getProperties('id', 'name'), { id: '3', name: 'What is omakase?' }); - assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], "The correct records are in the array"); - }); + assert.deepEqual( + comments.toArray(), + [comment1, comment2, comment3], + 'The correct records are in the array' + ); + }); }); test('findBelongsTo - passes buildURL the requestType', function(assert) { @@ -1898,69 +2098,70 @@ test('findBelongsTo - passes buildURL the requestType', function(assert) { type: 'comment', id: '1', attributes: { - name: "FIRST" + name: 'FIRST', }, relationships: { post: { links: { - related: '/posts/1' - } - } - } - } + related: '/posts/1', + }, + }, + }, + }, }); }); - return run(() => store.findRecord('comment', '1').then(comment => { - ajaxResponse({ post: { id: 1, name: 'Rails is omakase' } }); - return comment.get('post'); - })); + return run(() => + store.findRecord('comment', '1').then(comment => { + ajaxResponse({ post: { id: 1, name: 'Rails is omakase' } }); + return comment.get('post'); + }) + ); }); -testInDebug('coalesceFindRequests assert.warns if the expected records are not returned in the coalesced request', function(assert) { - assert.expect(2); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); +testInDebug( + 'coalesceFindRequests assert.warns if the expected records are not returned in the coalesced request', + function(assert) { + assert.expect(2); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; + adapter.coalesceFindRequests = true; - ajaxResponse({ - comments: [ - { id: '1', type: 'comment' } - ] - }); - - let post = run(() => store.push({ - data: { - type: 'post', - id: '2', - relationships: { - comments: { - data: [ - { type: 'comment', id: '1'}, - { type: 'comment', id: '2'}, - { type: 'comment', id: '3'} - ] - } - } - } - })); + ajaxResponse({ + comments: [{ id: '1', type: 'comment' }], + }); + + let post = run(() => + store.push({ + data: { + type: 'post', + id: '2', + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], + }, + }, + }, + }) + ); - assert.expectWarning( - () => { + assert.expectWarning(() => { return run(() => { - return post.get('comments') - .catch(e => { - assert.equal( - e.message, - `Expected: '' to be present in the adapter provided payload, but it was not found.` - ); - }); + return post.get('comments').catch(e => { + assert.equal( + e.message, + `Expected: '' to be present in the adapter provided payload, but it was not found.` + ); + }); }); - }, - /expected to find records with the following ids in the adapter response but they were missing: \[ "2", "3" \]/ - ); -}); + }, /expected to find records with the following ids in the adapter response but they were missing: \[ "2", "3" \]/); + } +); test('groupRecordsForFindMany groups records based on their url', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); @@ -1996,11 +2197,11 @@ test('groupRecordsForFindMany groups records based on their url', function(asser data: [ { type: 'comment', id: '1' }, { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - } + { type: 'comment', id: '3' }, + ], + }, + }, + }, }); post = store.peekRecord('post', 2); }); @@ -2042,11 +2243,11 @@ test('groupRecordsForFindMany groups records correctly when singular URLs are en data: [ { type: 'comment', id: '1' }, { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - } + { type: 'comment', id: '3' }, + ], + }, + }, + }, }); post = store.peekRecord('post', 2); }); @@ -2055,69 +2256,87 @@ test('groupRecordsForFindMany groups records correctly when singular URLs are en }); test('normalizeKey - to set up _ids and _id', function(assert) { - env.registry.register('serializer:application', DS.RESTSerializer.extend({ - keyForAttribute(attr) { - return underscore(attr); - }, + env.registry.register( + 'serializer:application', + DS.RESTSerializer.extend({ + keyForAttribute(attr) { + return underscore(attr); + }, - keyForBelongsTo(belongsTo) { - }, + keyForBelongsTo(belongsTo) {}, - keyForRelationship(rel, kind) { - if (kind === 'belongsTo') { - let underscored = underscore(rel); - return underscored + '_id'; - } else { - let singular = singularize(rel); - return underscore(singular) + '_ids'; - } - } - })); + keyForRelationship(rel, kind) { + if (kind === 'belongsTo') { + let underscored = underscore(rel); + return underscored + '_id'; + } else { + let singular = singularize(rel); + return underscore(singular) + '_ids'; + } + }, + }) + ); - env.registry.register('model:post', DS.Model.extend({ - name: DS.attr(), - authorName: DS.attr(), - author: DS.belongsTo('user', { async: false }), - comments: DS.hasMany('comment', { async: false }) - })); + env.registry.register( + 'model:post', + DS.Model.extend({ + name: DS.attr(), + authorName: DS.attr(), + author: DS.belongsTo('user', { async: false }), + comments: DS.hasMany('comment', { async: false }), + }) + ); - env.registry.register('model:user', DS.Model.extend({ - createdAt: DS.attr(), - name: DS.attr() - })); + env.registry.register( + 'model:user', + DS.Model.extend({ + createdAt: DS.attr(), + name: DS.attr(), + }) + ); - env.registry.register('model:comment', DS.Model.extend({ - body: DS.attr() - })); + env.registry.register( + 'model:comment', + DS.Model.extend({ + body: DS.attr(), + }) + ); ajaxResponse({ - posts: [{ - id: "1", - name: "Rails is omakase", - author_name: "@d2h", - author_id: "1", - comment_ids: ["1", "2"] - }], - - users: [{ - id: "1", - name: "D2H" - }], - - comments: [{ - id: "1", - body: "Rails is unagi" - }, { - id: "2", - body: "What is omakase?" - }] + posts: [ + { + id: '1', + name: 'Rails is omakase', + author_name: '@d2h', + author_id: '1', + comment_ids: ['1', '2'], + }, + ], + + users: [ + { + id: '1', + name: 'D2H', + }, + ], + + comments: [ + { + id: '1', + body: 'Rails is unagi', + }, + { + id: '2', + body: 'What is omakase?', + }, + ], }); return run(() => { return store.findRecord('post', 1).then(post => { - assert.equal(post.get('authorName'), "@d2h"); - assert.equal(post.get('author.name'), "D2H"); - assert.deepEqual(post.get('comments').mapBy('body'), ["Rails is unagi", "What is omakase?"]); + assert.equal(post.get('authorName'), '@d2h'); + assert.equal(post.get('author.name'), 'D2H'); + assert.deepEqual(post.get('comments').mapBy('body'), ['Rails is unagi', 'What is omakase?']); }); }); }); @@ -2129,7 +2348,7 @@ test('groupRecordsForFindMany splits up calls for large ids', function(assert) { assert.expect(2); function repeatChar(character, n) { - return new Array(n+1).join(character); + return new Array(n + 1).join(character); } let a2000 = repeatChar('a', 2000); @@ -2143,13 +2362,10 @@ test('groupRecordsForFindMany splits up calls for large ids', function(assert) { id: '1', relationships: { comments: { - data: [ - { type: 'comment', id: a2000 }, - { type: 'comment', id: b2000 } - ] - } - } - } + data: [{ type: 'comment', id: a2000 }, { type: 'comment', id: b2000 }], + }, + }, + }, }); post = store.peekRecord('post', 1); }); @@ -2158,14 +2374,17 @@ test('groupRecordsForFindMany splits up calls for large ids', function(assert) { adapter.findRecord = function(store, type, id, snapshot) { if (id === a2000 || id === b2000) { - assert.ok(true, "Found " + id); + assert.ok(true, 'Found ' + id); } return resolve({ comments: { id: id } }); }; adapter.findMany = function(store, type, ids, snapshots) { - assert.ok(false, "findMany should not be called - we expect 2 calls to find for a2000 and b2000"); + assert.ok( + false, + 'findMany should not be called - we expect 2 calls to find for a2000 and b2000' + ); return reject(); }; @@ -2179,7 +2398,7 @@ test('groupRecordsForFindMany groups calls for small ids', function(assert) { assert.expect(1); function repeatChar(character, n) { - return new Array(n+1).join(character); + return new Array(n + 1).join(character); } let a100 = repeatChar('a', 100); @@ -2193,13 +2412,10 @@ test('groupRecordsForFindMany groups calls for small ids', function(assert) { id: '1', relationships: { comments: { - data: [ - { type: 'comment', id: a100 }, - { type: 'comment', id: b100 } - ] - } - } - } + data: [{ type: 'comment', id: a100 }, { type: 'comment', id: b100 }], + }, + }, + }, }); post = store.peekRecord('post', 1); }); @@ -2207,7 +2423,10 @@ test('groupRecordsForFindMany groups calls for small ids', function(assert) { adapter.coalesceFindRequests = true; adapter.findRecord = function(store, type, id, snapshot) { - assert.ok(false, "findRecord should not be called - we expect 1 call to findMany for a100 and b100"); + assert.ok( + false, + 'findRecord should not be called - we expect 1 call to findMany for a100 and b100' + ); return reject(); }; @@ -2219,19 +2438,18 @@ test('groupRecordsForFindMany groups calls for small ids', function(assert) { run(() => post.get('comments')); }); - -test("calls adapter.handleResponse with the jqXHR and json", function(assert) { +test('calls adapter.handleResponse with the jqXHR and json', function(assert) { assert.expect(2); let data = { post: { - id: "1", - name: "Docker is amazing" - } + id: '1', + name: 'Docker is amazing', + }, }; server.get('/posts/1', function() { - return [200, { "Content-Type": "application/json" }, JSON.stringify(data)]; + return [200, { 'Content-Type': 'application/json' }, JSON.stringify(data)]; }); adapter.handleResponse = function(status, headers, json) { @@ -2249,8 +2467,8 @@ test('calls handleResponse with jqXHR, jqXHR.responseText, and requestData', fun let responseText = 'Nope lol'; let expectedRequestData = { - method: "GET", - url: "/posts/1" + method: 'GET', + url: '/posts/1', }; server.get('/posts/1', function() { @@ -2269,15 +2487,15 @@ test('calls handleResponse with jqXHR, jqXHR.responseText, and requestData', fun }); }); -test("rejects promise if DS.AdapterError is returned from adapter.handleResponse", function(assert) { +test('rejects promise if DS.AdapterError is returned from adapter.handleResponse', function(assert) { assert.expect(3); let data = { - something: 'is invalid' + something: 'is invalid', }; server.get('/posts/1', function() { - return [200, { "Content-Type": "application/json" }, JSON.stringify(data)]; + return [200, { 'Content-Type': 'application/json' }, JSON.stringify(data)]; }); adapter.handleResponse = function(status, headers, json) { @@ -2288,16 +2506,19 @@ test("rejects promise if DS.AdapterError is returned from adapter.handleResponse return run(() => { return store.findRecord('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.AdapterError, 'reason should be an instance of DS.AdapterError'); + assert.ok( + reason instanceof DS.AdapterError, + 'reason should be an instance of DS.AdapterError' + ); }); }); }); -test("gracefully handles exceptions in handleResponse", function(assert) { +test('gracefully handles exceptions in handleResponse', function(assert) { assert.expect(1); server.post('/posts/1', function() { - return [200, { "Content-Type": "application/json" }, "ok"]; + return [200, { 'Content-Type': 'application/json' }, 'ok']; }); adapter.handleResponse = function(status, headers, json) { @@ -2311,11 +2532,11 @@ test("gracefully handles exceptions in handleResponse", function(assert) { }); }); -test("gracefully handles exceptions in handleResponse where the ajax request errors", function(assert) { +test('gracefully handles exceptions in handleResponse where the ajax request errors', function(assert) { assert.expect(1); server.get('/posts/1', function() { - return [500, { "Content-Type": "application/json" }, "Internal Server Error"]; + return [500, { 'Content-Type': 'application/json' }, 'Internal Server Error']; }); adapter.handleResponse = function(status, headers, json) { @@ -2333,7 +2554,12 @@ test('treats status code 0 as an abort', function(assert) { assert.expect(1); adapter._ajaxRequest = function(hash) { - hash.error({ status: 0, getAllResponseHeaders() { return ''; } }); + hash.error({ + status: 0, + getAllResponseHeaders() { + return ''; + }, + }); }; adapter.handleResponse = function(status, headers, payload) { assert.ok(false); @@ -2351,7 +2577,9 @@ test('on error appends errorThrown for sanity', function(assert) { let jqXHR = { responseText: 'Nope lol', - getAllResponseHeaders() { return ''; } + getAllResponseHeaders() { + return ''; + }, }; let errorThrown = new Error('nope!'); @@ -2372,7 +2600,7 @@ test('on error appends errorThrown for sanity', function(assert) { }); }); -test("rejects promise with a specialized subclass of DS.AdapterError if ajax responds with http error codes", function(assert) { +test('rejects promise with a specialized subclass of DS.AdapterError if ajax responds with http error codes', function(assert) { assert.expect(10); ajaxError('error', 401); @@ -2380,7 +2608,10 @@ test("rejects promise with a specialized subclass of DS.AdapterError if ajax res run(() => { store.find('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.UnauthorizedError, 'reason should be an instance of DS.UnauthorizedError'); + assert.ok( + reason instanceof DS.UnauthorizedError, + 'reason should be an instance of DS.UnauthorizedError' + ); }); }); @@ -2389,7 +2620,10 @@ test("rejects promise with a specialized subclass of DS.AdapterError if ajax res run(() => { store.find('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.ForbiddenError, 'reason should be an instance of DS.ForbiddenError'); + assert.ok( + reason instanceof DS.ForbiddenError, + 'reason should be an instance of DS.ForbiddenError' + ); }); }); @@ -2398,7 +2632,10 @@ test("rejects promise with a specialized subclass of DS.AdapterError if ajax res run(() => { store.find('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.NotFoundError, 'reason should be an instance of DS.NotFoundError'); + assert.ok( + reason instanceof DS.NotFoundError, + 'reason should be an instance of DS.NotFoundError' + ); }); }); @@ -2407,7 +2644,10 @@ test("rejects promise with a specialized subclass of DS.AdapterError if ajax res run(() => { store.find('post', '1').catch(reason => { assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.ConflictError, 'reason should be an instance of DS.ConflictError'); + assert.ok( + reason instanceof DS.ConflictError, + 'reason should be an instance of DS.ConflictError' + ); }); }); @@ -2418,7 +2658,6 @@ test("rejects promise with a specialized subclass of DS.AdapterError if ajax res assert.ok(true, 'promise should be rejected'); assert.ok(reason instanceof DS.ServerError, 'reason should be an instance of DS.ServerError'); }); - }); }); @@ -2427,7 +2666,9 @@ test('on error wraps the error string in an DS.AdapterError object', function(as let jqXHR = { responseText: '', - getAllResponseHeaders() { return ''; } + getAllResponseHeaders() { + return ''; + }, }; let errorThrown = 'nope!'; @@ -2444,78 +2685,91 @@ test('on error wraps the error string in an DS.AdapterError object', function(as }); }); -test('error handling includes a detailed message from the server', (assert) => { +test('error handling includes a detailed message from the server', assert => { assert.expect(2); - ajaxError('An error message, perhaps generated from a backend server!', 500, 'Content-Type: text/plain'); + ajaxError( + 'An error message, perhaps generated from a backend server!', + 500, + 'Content-Type: text/plain' + ); run(() => { store.findRecord('post', '1').catch(err => { - assert.equal(err.message, "Ember Data Request GET /posts/1 returned a 500\nPayload (text/plain)\nAn error message, perhaps generated from a backend server!"); + assert.equal( + err.message, + 'Ember Data Request GET /posts/1 returned a 500\nPayload (text/plain)\nAn error message, perhaps generated from a backend server!' + ); assert.ok(err, 'promise rejected'); }); }); }); -test('error handling with a very long HTML-formatted payload truncates the friendly message', (assert) => { +test('error handling with a very long HTML-formatted payload truncates the friendly message', assert => { assert.expect(2); - ajaxError(new Array(100).join(""), 500, 'Content-Type: text/html'); + ajaxError(new Array(100).join(''), 500, 'Content-Type: text/html'); run(() => { store.findRecord('post', '1').catch(err => { - assert.equal(err.message, "Ember Data Request GET /posts/1 returned a 500\nPayload (text/html)\n[Omitted Lengthy HTML]"); + assert.equal( + err.message, + 'Ember Data Request GET /posts/1 returned a 500\nPayload (text/html)\n[Omitted Lengthy HTML]' + ); assert.ok(err, 'promise rejected'); }); }); }); -test('findAll resolves with a collection of DS.Models, not DS.InternalModels', (assert) => { +test('findAll resolves with a collection of DS.Models, not DS.InternalModels', assert => { assert.expect(4); ajaxResponse({ posts: [ { id: 1, - name: 'dhh lol' + name: 'dhh lol', }, { id: 2, - name: 'james mickens is rad' + name: 'james mickens is rad', }, { id: 3, - name: 'in the name of love' - } - ] + name: 'in the name of love', + }, + ], }); return run(() => { return store.findAll('post').then(posts => { assert.equal(get(posts, 'length'), 3); - posts.forEach((post) => assert.ok(post instanceof DS.Model)); + posts.forEach(post => assert.ok(post instanceof DS.Model)); }); }); }); -test("createRecord - sideloaded records are pushed to the store", function(assert) { +test('createRecord - sideloaded records are pushed to the store', function(assert) { Post.reopen({ - comments: DS.hasMany('comment') + comments: DS.hasMany('comment'), }); ajaxResponse({ post: { id: 1, name: 'The Parley Letter', - comments: [2, 3] + comments: [2, 3], }, - comments: [{ - id: 2, - name: 'First comment' - }, { - id: 3, - name: 'Second comment' - }] + comments: [ + { + id: 2, + name: 'First comment', + }, + { + id: 3, + name: 'Second comment', + }, + ], }); let post; @@ -2526,22 +2780,36 @@ test("createRecord - sideloaded records are pushed to the store", function(asser let comments = store.peekAll('comment'); assert.equal(get(comments, 'length'), 2, 'comments.length is correct'); - assert.equal(get(comments, 'firstObject.name'), 'First comment', 'comments.firstObject.name is correct'); - assert.equal(get(comments, 'lastObject.name'), 'Second comment', 'comments.lastObject.name is correct'); + assert.equal( + get(comments, 'firstObject.name'), + 'First comment', + 'comments.firstObject.name is correct' + ); + assert.equal( + get(comments, 'lastObject.name'), + 'Second comment', + 'comments.lastObject.name is correct' + ); }); }); }); -testInDebug("warns when an empty response is returned, though a valid stringified JSON is expected", function(assert) { - server.post('/posts', function() { - return [201, { "Content-Type": "application/json" }, ""]; - }); +testInDebug( + 'warns when an empty response is returned, though a valid stringified JSON is expected', + function(assert) { + server.post('/posts', function() { + return [201, { 'Content-Type': 'application/json' }, '']; + }); - return run(() => { - return store.createRecord('post').save(); - }).then(() => { - assert.equal(true, false, 'should not have fulfilled'); - }, reason => { - assert.ok(/JSON/.test(reason.message)); - }); -}); + return run(() => { + return store.createRecord('post').save(); + }).then( + () => { + assert.equal(true, false, 'should not have fulfilled'); + }, + reason => { + assert.ok(/JSON/.test(reason.message)); + } + ); + } +); diff --git a/tests/integration/adapter/serialize-test.js b/tests/integration/adapter/serialize-test.js index f0b1686b9b3..f5ced5ec0b6 100644 --- a/tests/integration/adapter/serialize-test.js +++ b/tests/integration/adapter/serialize-test.js @@ -7,10 +7,10 @@ import DS from 'ember-data'; let env, store, adapter, serializer; -module("integration/adapter/serialize - DS.Adapter integration test", { +module('integration/adapter/serialize - DS.Adapter integration test', { beforeEach() { const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); env = setupStore({ person: Person }); @@ -21,10 +21,10 @@ module("integration/adapter/serialize - DS.Adapter integration test", { afterEach() { run(env.container, 'destroy'); - } + }, }); -test("serialize() is delegated to the serializer", function(assert) { +test('serialize() is delegated to the serializer', function(assert) { assert.expect(1); serializer.serialize = function(snapshot, options) { diff --git a/tests/integration/adapter/store-adapter-test.js b/tests/integration/adapter/store-adapter-test.js index 2adefff5a95..655f5df7d45 100644 --- a/tests/integration/adapter/store-adapter-test.js +++ b/tests/integration/adapter/store-adapter-test.js @@ -1,9 +1,4 @@ -import { - resolve, - hash, - Promise as EmberPromise, - reject -} from 'rsvp'; +import { resolve, hash, Promise as EmberPromise, reject } from 'rsvp'; import { set, get } from '@ember/object'; import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; @@ -24,24 +19,24 @@ function moveRecordOutOfInFlight(record) { }); } -module("integration/adapter/store-adapter - DS.Store and DS.Adapter integration test", { +module('integration/adapter/store-adapter - DS.Store and DS.Adapter integration test', { beforeEach() { Person = DS.Model.extend({ updatedAt: DS.attr('string'), name: DS.attr('string'), firstName: DS.attr('string'), - lastName: DS.attr('string') + lastName: DS.attr('string'), }); Dog = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); env = setupStore({ serializer: DS.JSONAPISerializer, adapter: DS.JSONAPIAdapter, person: Person, - dog: Dog + dog: Dog, }); store = env.store; adapter = env.adapter; @@ -49,81 +44,87 @@ module("integration/adapter/store-adapter - DS.Store and DS.Adapter integration afterEach() { run(env.container, 'destroy'); - } + }, }); -test("Records loaded multiple times and retrieved in recordArray are ready to send state events", function(assert) { +test('Records loaded multiple times and retrieved in recordArray are ready to send state events', function(assert) { adapter.query = function(store, type, query, recordArray) { return resolve({ data: [ { id: 1, - type: "person", + type: 'person', attributes: { - name: "Mickael Ramírez" - } - }, { + name: 'Mickael Ramírez', + }, + }, + { id: 2, - type: "person", + type: 'person', attributes: { - name: "Johny Fontana" - } - } - ] + name: 'Johny Fontana', + }, + }, + ], }); }; - return run(() => store.query('person', { q: 'bla' }).then(people => { - let people2 = store.query('person', { q: 'bla2' }); - - return hash({ people: people, people2: people2 }); - }).then(results => { - assert.equal(results.people2.get('length'), 2, 'return the elements'); - assert.ok(results.people2.get('isLoaded'), 'array is loaded'); - - var person = results.people.objectAt(0); - assert.ok(person.get('isLoaded'), 'record is loaded'); - - // delete record will not throw exception - person.deleteRecord(); - })); + return run(() => + store + .query('person', { q: 'bla' }) + .then(people => { + let people2 = store.query('person', { q: 'bla2' }); + + return hash({ people: people, people2: people2 }); + }) + .then(results => { + assert.equal(results.people2.get('length'), 2, 'return the elements'); + assert.ok(results.people2.get('isLoaded'), 'array is loaded'); + + var person = results.people.objectAt(0); + assert.ok(person.get('isLoaded'), 'record is loaded'); + + // delete record will not throw exception + person.deleteRecord(); + }) + ); }); -test("by default, createRecords calls createRecord once per record", function(assert) { +test('by default, createRecords calls createRecord once per record', function(assert) { let count = 1; adapter.shouldBackgroundReloadRecord = () => false; adapter.createRecord = function(store, type, snapshot) { - assert.equal(type, Person, "the type is correct"); + assert.equal(type, Person, 'the type is correct'); if (count === 1) { - assert.equal(snapshot.attr('name'), "Tom Dale"); + assert.equal(snapshot.attr('name'), 'Tom Dale'); } else if (count === 2) { - assert.equal(snapshot.attr('name'), "Yehuda Katz"); + assert.equal(snapshot.attr('name'), 'Yehuda Katz'); } else { - assert.ok(false, "should not have invoked more than 2 times"); + assert.ok(false, 'should not have invoked more than 2 times'); } let hash = snapshot.attributes(); let recordId = count; - hash['updated-at'] = "now"; + hash['updated-at'] = 'now'; count++; return resolve({ data: { id: recordId, - type: "person", - attributes: hash - } + type: 'person', + attributes: hash, + }, }); }; - let tom = store.createRecord('person', { name: "Tom Dale" }); - let yehuda = store.createRecord('person', { name: "Yehuda Katz" }); + let tom = store.createRecord('person', { name: 'Tom Dale' }); + let yehuda = store.createRecord('person', { name: 'Yehuda Katz' }); let promise = run(() => { return hash({ tom: tom.save(), - yehuda: yehuda.save() + yehuda: yehuda.save(), }); }); @@ -131,162 +132,184 @@ test("by default, createRecords calls createRecord once per record", function(as tom = records.tom; yehuda = records.yehuda; - assert.asyncEqual(tom, store.findRecord('person', 1), "Once an ID is in, findRecord returns the same object"); - assert.asyncEqual(yehuda, store.findRecord('person', 2), "Once an ID is in, findRecord returns the same object"); - assert.equal(get(tom, 'updatedAt'), "now", "The new information is received"); - assert.equal(get(yehuda, 'updatedAt'), "now", "The new information is received"); + assert.asyncEqual( + tom, + store.findRecord('person', 1), + 'Once an ID is in, findRecord returns the same object' + ); + assert.asyncEqual( + yehuda, + store.findRecord('person', 2), + 'Once an ID is in, findRecord returns the same object' + ); + assert.equal(get(tom, 'updatedAt'), 'now', 'The new information is received'); + assert.equal(get(yehuda, 'updatedAt'), 'now', 'The new information is received'); }); }); -test("by default, updateRecords calls updateRecord once per record", function(assert) { +test('by default, updateRecords calls updateRecord once per record', function(assert) { let count = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { - assert.equal(type, Person, "the type is correct"); + assert.equal(type, Person, 'the type is correct'); if (count === 0) { - assert.equal(snapshot.attr('name'), "Tom Dale"); + assert.equal(snapshot.attr('name'), 'Tom Dale'); } else if (count === 1) { - assert.equal(snapshot.attr('name'), "Yehuda Katz"); + assert.equal(snapshot.attr('name'), 'Yehuda Katz'); } else { - assert.ok(false, "should not get here"); + assert.ok(false, 'should not get here'); } count++; - assert.equal(snapshot.record.get('isSaving'), true, "record is saving"); + assert.equal(snapshot.record.get('isSaving'), true, 'record is saving'); return resolve(); }; run(() => { env.store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Braaaahm Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Brohuda Katz' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Braaaahm Dale', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Brohuda Katz', + }, + }, + ], }); }); let promise = run(() => { return hash({ tom: store.findRecord('person', 1), - yehuda: store.findRecord('person', 2) + yehuda: store.findRecord('person', 2), }); }); - return promise.then(records => { - let tom = records.tom; - let yehuda = records.yehuda; + return promise + .then(records => { + let tom = records.tom; + let yehuda = records.yehuda; - set(tom, "name", "Tom Dale"); - set(yehuda, "name", "Yehuda Katz"); + set(tom, 'name', 'Tom Dale'); + set(yehuda, 'name', 'Yehuda Katz'); - return hash({ - tom: tom.save(), - yehuda: yehuda.save() - }); - }).then(records => { - let tom = records.tom; - let yehuda = records.yehuda; + return hash({ + tom: tom.save(), + yehuda: yehuda.save(), + }); + }) + .then(records => { + let tom = records.tom; + let yehuda = records.yehuda; - assert.equal(tom.get('isSaving'), false, "record is no longer saving"); - assert.equal(tom.get('isLoaded'), true, "record is loaded"); + assert.equal(tom.get('isSaving'), false, 'record is no longer saving'); + assert.equal(tom.get('isLoaded'), true, 'record is loaded'); - assert.equal(yehuda.get('isSaving'), false, "record is no longer saving"); - assert.equal(yehuda.get('isLoaded'), true, "record is loaded"); - }); + assert.equal(yehuda.get('isSaving'), false, 'record is no longer saving'); + assert.equal(yehuda.get('isLoaded'), true, 'record is loaded'); + }); }); -test("calling store.didSaveRecord can provide an optional hash", function(assert) { +test('calling store.didSaveRecord can provide an optional hash', function(assert) { let count = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { - assert.equal(type, Person, "the type is correct"); + assert.equal(type, Person, 'the type is correct'); count++; if (count === 1) { - assert.equal(snapshot.attr('name'), "Tom Dale"); - return resolve({ data: { id: 1, type: "person", attributes: { name: "Tom Dale", "updated-at": "now" } } }); + assert.equal(snapshot.attr('name'), 'Tom Dale'); + return resolve({ + data: { id: 1, type: 'person', attributes: { name: 'Tom Dale', 'updated-at': 'now' } }, + }); } else if (count === 2) { - assert.equal(snapshot.attr('name'), "Yehuda Katz"); - return resolve({ data: { id: 2, type: "person", attributes: { name: "Yehuda Katz", "updated-at": "now!" } } }); + assert.equal(snapshot.attr('name'), 'Yehuda Katz'); + return resolve({ + data: { id: 2, type: 'person', attributes: { name: 'Yehuda Katz', 'updated-at': 'now!' } }, + }); } else { - assert.ok(false, "should not get here"); + assert.ok(false, 'should not get here'); } }; run(() => { env.store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Braaaahm Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Brohuda Katz' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Braaaahm Dale', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Brohuda Katz', + }, + }, + ], }); }); let promise = run(() => { return hash({ tom: store.findRecord('person', 1), - yehuda: store.findRecord('person', 2) + yehuda: store.findRecord('person', 2), }); }); - return promise.then(records => { - let tom = records.tom; - let yehuda = records.yehuda; + return promise + .then(records => { + let tom = records.tom; + let yehuda = records.yehuda; - set(tom, "name", "Tom Dale"); - set(yehuda, "name", "Yehuda Katz"); + set(tom, 'name', 'Tom Dale'); + set(yehuda, 'name', 'Yehuda Katz'); - return hash({ - tom: tom.save(), - yehuda: yehuda.save() - }); - }).then(records => { - let tom = records.tom; - let yehuda = records.yehuda; + return hash({ + tom: tom.save(), + yehuda: yehuda.save(), + }); + }) + .then(records => { + let tom = records.tom; + let yehuda = records.yehuda; - assert.equal(get(tom, 'hasDirtyAttributes'), false, "the record should not be dirty"); - assert.equal(get(tom, 'updatedAt'), "now", "the hash was updated"); + assert.equal(get(tom, 'hasDirtyAttributes'), false, 'the record should not be dirty'); + assert.equal(get(tom, 'updatedAt'), 'now', 'the hash was updated'); - assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "the record should not be dirty"); - assert.equal(get(yehuda, 'updatedAt'), "now!", "the hash was updated"); - }); + assert.equal(get(yehuda, 'hasDirtyAttributes'), false, 'the record should not be dirty'); + assert.equal(get(yehuda, 'updatedAt'), 'now!', 'the hash was updated'); + }); }); -test("by default, deleteRecord calls deleteRecord once per record", function(assert) { +test('by default, deleteRecord calls deleteRecord once per record', function(assert) { assert.expect(4); let count = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.deleteRecord = function(store, type, snapshot) { - assert.equal(type, Person, "the type is correct"); + assert.equal(type, Person, 'the type is correct'); if (count === 0) { - assert.equal(snapshot.attr('name'), "Tom Dale"); + assert.equal(snapshot.attr('name'), 'Tom Dale'); } else if (count === 1) { - assert.equal(snapshot.attr('name'), "Yehuda Katz"); + assert.equal(snapshot.attr('name'), 'Yehuda Katz'); } else { - assert.ok(false, "should not get here"); + assert.ok(false, 'should not get here'); } count++; @@ -296,26 +319,29 @@ test("by default, deleteRecord calls deleteRecord once per record", function(ass run(() => { env.store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Yehuda Katz' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Yehuda Katz', + }, + }, + ], }); }); let promise = run(() => { return hash({ tom: store.findRecord('person', 1), - yehuda: store.findRecord('person', 2) + yehuda: store.findRecord('person', 2), }); }); @@ -326,28 +352,25 @@ test("by default, deleteRecord calls deleteRecord once per record", function(ass tom.deleteRecord(); yehuda.deleteRecord(); - return EmberPromise.all([ - tom.save(), - yehuda.save() - ]); + return EmberPromise.all([tom.save(), yehuda.save()]); }); }); -test("by default, destroyRecord calls deleteRecord once per record without requiring .save", function(assert) { +test('by default, destroyRecord calls deleteRecord once per record without requiring .save', function(assert) { assert.expect(4); let count = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.deleteRecord = function(store, type, snapshot) { - assert.equal(type, Person, "the type is correct"); + assert.equal(type, Person, 'the type is correct'); if (count === 0) { - assert.equal(snapshot.attr('name'), "Tom Dale"); + assert.equal(snapshot.attr('name'), 'Tom Dale'); } else if (count === 1) { - assert.equal(snapshot.attr('name'), "Yehuda Katz"); + assert.equal(snapshot.attr('name'), 'Yehuda Katz'); } else { - assert.ok(false, "should not get here"); + assert.ok(false, 'should not get here'); } count++; @@ -357,26 +380,29 @@ test("by default, destroyRecord calls deleteRecord once per record without requi run(() => { env.store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Yehuda Katz' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Yehuda Katz', + }, + }, + ], }); }); let promise = run(() => { return hash({ tom: store.findRecord('person', 1), - yehuda: store.findRecord('person', 2) + yehuda: store.findRecord('person', 2), }); }); @@ -384,28 +410,25 @@ test("by default, destroyRecord calls deleteRecord once per record without requi let tom = records.tom; let yehuda = records.yehuda; - return EmberPromise.all([ - tom.destroyRecord(), - yehuda.destroyRecord() - ]); + return EmberPromise.all([tom.destroyRecord(), yehuda.destroyRecord()]); }); }); -test("if an existing model is edited then deleted, deleteRecord is called on the adapter", function(assert) { +test('if an existing model is edited then deleted, deleteRecord is called on the adapter', function(assert) { assert.expect(5); let count = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.deleteRecord = function(store, type, snapshot) { count++; - assert.equal(snapshot.id, 'deleted-record', "should pass correct record to deleteRecord"); - assert.equal(count, 1, "should only call deleteRecord method of adapter once"); + assert.equal(snapshot.id, 'deleted-record', 'should pass correct record to deleteRecord'); + assert.equal(count, 1, 'should only call deleteRecord method of adapter once'); return resolve(); }; adapter.updateRecord = function() { - assert.ok(false, "should not have called updateRecord method of adapter"); + assert.ok(false, 'should not have called updateRecord method of adapter'); }; // Load data for a record into the store. @@ -415,27 +438,36 @@ test("if an existing model is edited then deleted, deleteRecord is called on the type: 'person', id: 'deleted-record', attributes: { - name: 'Tom Dale' - } - } + name: 'Tom Dale', + }, + }, }); }); // Retrieve that loaded record and edit it so it becomes dirty - return run(() => store.findRecord('person', 'deleted-record').then(tom => { - tom.set('name', "Tom Mothereffin' Dale"); - - assert.equal(get(tom, 'hasDirtyAttributes'), true, "precond - record should be dirty after editing"); - - tom.deleteRecord(); - return tom.save(); - }).then(tom => { - assert.equal(get(tom, 'hasDirtyAttributes'), false, "record should not be dirty"); - assert.equal(get(tom, 'isDeleted'), true, "record should be considered deleted"); - })); + return run(() => + store + .findRecord('person', 'deleted-record') + .then(tom => { + tom.set('name', "Tom Mothereffin' Dale"); + + assert.equal( + get(tom, 'hasDirtyAttributes'), + true, + 'precond - record should be dirty after editing' + ); + + tom.deleteRecord(); + return tom.save(); + }) + .then(tom => { + assert.equal(get(tom, 'hasDirtyAttributes'), false, 'record should not be dirty'); + assert.equal(get(tom, 'isDeleted'), true, 'record should be considered deleted'); + }) + ); }); -test("if a deleted record errors, it enters the error state", function(assert) { +test('if a deleted record errors, it enters the error state', function(assert) { let count = 0; let error = new DS.AdapterError(); @@ -454,179 +486,215 @@ test("if a deleted record errors, it enters the error state", function(assert) { type: 'person', id: 'deleted-record', attributes: { - name: 'Tom Dale' - } - } + name: 'Tom Dale', + }, + }, }); }); return run(() => { let tom; - store.findRecord('person', 'deleted-record').then(person => { - tom = person; - person.deleteRecord(); - return person.save(); - }).catch(() => { - assert.equal(tom.get('isError'), true, "Tom is now errored"); - assert.equal(tom.get('adapterError'), error, "error object is exposed"); - - // this time it succeeds - return tom.save(); - }).then(() => { - assert.equal(tom.get('isError'), false, "Tom is not errored anymore"); - assert.equal(tom.get('adapterError'), null, "error object is discarded"); - }); + store + .findRecord('person', 'deleted-record') + .then(person => { + tom = person; + person.deleteRecord(); + return person.save(); + }) + .catch(() => { + assert.equal(tom.get('isError'), true, 'Tom is now errored'); + assert.equal(tom.get('adapterError'), error, 'error object is exposed'); + + // this time it succeeds + return tom.save(); + }) + .then(() => { + assert.equal(tom.get('isError'), false, 'Tom is not errored anymore'); + assert.equal(tom.get('adapterError'), null, 'error object is discarded'); + }); }); }); -test("if a created record is marked as invalid by the server, it enters an error state", function(assert) { +test('if a created record is marked as invalid by the server, it enters an error state', function(assert) { adapter.createRecord = function(store, type, snapshot) { - assert.equal(type, Person, "the type is correct"); + assert.equal(type, Person, 'the type is correct'); if (snapshot.attr('name').indexOf('Bro') === -1) { - return reject(new DS.InvalidError([ - { - title: 'Invalid Attribute', - detail: 'common... name requires a "bro"', - source: { - pointer: '/data/attributes/name' - } - } - ])); + return reject( + new DS.InvalidError([ + { + title: 'Invalid Attribute', + detail: 'common... name requires a "bro"', + source: { + pointer: '/data/attributes/name', + }, + }, + ]) + ); } else { return resolve(); } }; - let yehuda = store.createRecord('person', { id: 1, name: "Yehuda Katz" }); + let yehuda = store.createRecord('person', { id: 1, name: 'Yehuda Katz' }); // Wrap this in an Ember.run so that all chained async behavior is set up // before flushing any scheduled behavior. return run(function() { - return yehuda.save().catch(error => { - assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); - assert.ok(get(yehuda, 'errors.name'), "The errors.name property exists"); + return yehuda + .save() + .catch(error => { + assert.equal(get(yehuda, 'isValid'), false, 'the record is invalid'); + assert.ok(get(yehuda, 'errors.name'), 'The errors.name property exists'); - set(yehuda, 'updatedAt', true); - assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid"); + set(yehuda, 'updatedAt', true); + assert.equal(get(yehuda, 'isValid'), false, 'the record is still invalid'); - set(yehuda, 'name', "Brohuda Brokatz"); + set(yehuda, 'name', 'Brohuda Brokatz'); - assert.equal(get(yehuda, 'isValid'), true, "the record is no longer invalid after changing"); - assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); + assert.equal( + get(yehuda, 'isValid'), + true, + 'the record is no longer invalid after changing' + ); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, 'the record has outstanding changes'); - assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); + assert.equal(get(yehuda, 'isNew'), true, 'precond - record is still new'); - return yehuda.save(); - }).then(person => { - assert.strictEqual(person, yehuda, "The promise resolves with the saved record"); + return yehuda.save(); + }) + .then(person => { + assert.strictEqual(person, yehuda, 'The promise resolves with the saved record'); - assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); - assert.equal(get(yehuda, 'isNew'), false, "record is no longer new"); - }); + assert.equal(get(yehuda, 'isValid'), true, 'record remains valid after committing'); + assert.equal(get(yehuda, 'isNew'), false, 'record is no longer new'); + }); }); }); -test("allows errors on arbitrary properties on create", function(assert) { +test('allows errors on arbitrary properties on create', function(assert) { adapter.createRecord = function(store, type, snapshot) { if (snapshot.attr('name').indexOf('Bro') === -1) { - return reject(new DS.InvalidError([ - { - title: "Invalid Attribute", - detail: "is a generally unsavoury character", - source: { - pointer: "/data/attributes/base" - } - } - ])); + return reject( + new DS.InvalidError([ + { + title: 'Invalid Attribute', + detail: 'is a generally unsavoury character', + source: { + pointer: '/data/attributes/base', + }, + }, + ]) + ); } else { return resolve(); } }; - let yehuda = store.createRecord('person', { id: 1, name: "Yehuda Katz" }); + let yehuda = store.createRecord('person', { id: 1, name: 'Yehuda Katz' }); // Wrap this in an Ember.run so that all chained async behavior is set up // before flushing any scheduled behavior. return run(() => { - return yehuda.save().catch(error => { - assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); - assert.ok(get(yehuda, 'errors.base'), "The errors.base property exists"); - assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), [{ attribute: 'base', message: "is a generally unsavoury character" }]); - - set(yehuda, 'updatedAt', true); - assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid"); - - set(yehuda, 'name', "Brohuda Brokatz"); - - assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid as far as we know"); - assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); - - assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); - - return yehuda.save(); - }).then(person => { - assert.strictEqual(person, yehuda, "The promise resolves with the saved record"); - assert.ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); - assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), []); - assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); - assert.equal(get(yehuda, 'isNew'), false, "record is no longer new"); - }); + return yehuda + .save() + .catch(error => { + assert.equal(get(yehuda, 'isValid'), false, 'the record is invalid'); + assert.ok(get(yehuda, 'errors.base'), 'The errors.base property exists'); + assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), [ + { attribute: 'base', message: 'is a generally unsavoury character' }, + ]); + + set(yehuda, 'updatedAt', true); + assert.equal(get(yehuda, 'isValid'), false, 'the record is still invalid'); + + set(yehuda, 'name', 'Brohuda Brokatz'); + + assert.equal( + get(yehuda, 'isValid'), + false, + 'the record is still invalid as far as we know' + ); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, 'the record has outstanding changes'); + + assert.equal(get(yehuda, 'isNew'), true, 'precond - record is still new'); + + return yehuda.save(); + }) + .then(person => { + assert.strictEqual(person, yehuda, 'The promise resolves with the saved record'); + assert.ok(!get(yehuda, 'errors.base'), 'The errors.base property does not exist'); + assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), []); + assert.equal(get(yehuda, 'isValid'), true, 'record remains valid after committing'); + assert.equal(get(yehuda, 'isNew'), false, 'record is no longer new'); + }); }); }); -test("if a created record is marked as invalid by the server, you can attempt the save again", function(assert) { +test('if a created record is marked as invalid by the server, you can attempt the save again', function(assert) { let saveCount = 0; adapter.createRecord = function(store, type, snapshot) { - assert.equal(type, Person, "the type is correct"); + assert.equal(type, Person, 'the type is correct'); saveCount++; if (snapshot.attr('name').indexOf('Bro') === -1) { - return reject(new DS.InvalidError([ - { - title: 'Invalid Attribute', - detail: 'common... name requires a "bro"', - source: { - pointer: '/data/attributes/name' - } - } - ])); + return reject( + new DS.InvalidError([ + { + title: 'Invalid Attribute', + detail: 'common... name requires a "bro"', + source: { + pointer: '/data/attributes/name', + }, + }, + ]) + ); } else { return resolve(); } }; - let yehuda = store.createRecord('person', { id: 1, name: "Yehuda Katz" }); + let yehuda = store.createRecord('person', { id: 1, name: 'Yehuda Katz' }); // Wrap this in an Ember.run so that all chained async behavior is set up // before flushing any scheduled behavior. return run(() => { - return yehuda.save().catch(reason => { - assert.equal(saveCount, 1, "The record has been saved once"); - assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); - assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); - assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); - assert.ok(get(yehuda, 'errors.name'), "The errors.name property exists"); - assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); - return yehuda.save(); - }).catch(reason => { - assert.equal(saveCount, 2, "The record has been saved twice"); - assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); - assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid"); - assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); - assert.ok(get(yehuda, 'errors.name'), "The errors.name property exists"); - assert.equal(get(yehuda, 'isNew'), true, "precond - record is still new"); - set(yehuda, 'name', 'Brohuda Brokatz'); - return yehuda.save(); - }).then(person => { - assert.equal(saveCount, 3, "The record has been saved thrice"); - assert.equal(get(yehuda, 'isValid'), true, "record is valid"); - assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is not dirty"); - assert.equal(get(yehuda, 'errors.isEmpty'), true, "record has no errors"); - }); + return yehuda + .save() + .catch(reason => { + assert.equal(saveCount, 1, 'The record has been saved once'); + assert.ok( + reason.message.match('The adapter rejected the commit because it was invalid'), + 'It should fail due to being invalid' + ); + assert.equal(get(yehuda, 'isValid'), false, 'the record is invalid'); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, 'the record has outstanding changes'); + assert.ok(get(yehuda, 'errors.name'), 'The errors.name property exists'); + assert.equal(get(yehuda, 'isNew'), true, 'precond - record is still new'); + return yehuda.save(); + }) + .catch(reason => { + assert.equal(saveCount, 2, 'The record has been saved twice'); + assert.ok( + reason.message.match('The adapter rejected the commit because it was invalid'), + 'It should fail due to being invalid' + ); + assert.equal(get(yehuda, 'isValid'), false, 'the record is still invalid'); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, 'the record has outstanding changes'); + assert.ok(get(yehuda, 'errors.name'), 'The errors.name property exists'); + assert.equal(get(yehuda, 'isNew'), true, 'precond - record is still new'); + set(yehuda, 'name', 'Brohuda Brokatz'); + return yehuda.save(); + }) + .then(person => { + assert.equal(saveCount, 3, 'The record has been saved thrice'); + assert.equal(get(yehuda, 'isValid'), true, 'record is valid'); + assert.equal(get(yehuda, 'hasDirtyAttributes'), false, 'record is not dirty'); + assert.equal(get(yehuda, 'errors.isEmpty'), true, 'record has no errors'); + }); }); }); -test("if a created record is marked as erred by the server, it enters an error state", function(assert) { +test('if a created record is marked as erred by the server, it enters an error state', function(assert) { let error = new DS.AdapterError(); adapter.createRecord = function(store, type, snapshot) { @@ -634,30 +702,32 @@ test("if a created record is marked as erred by the server, it enters an error s }; return run(() => { - let person = store.createRecord('person', { id: 1, name: "John Doe" }); + let person = store.createRecord('person', { id: 1, name: 'John Doe' }); return person.save().catch(() => { - assert.ok(get(person, 'isError'), "the record is in the error state"); - assert.equal(get(person, 'adapterError'), error, "error object is exposed"); + assert.ok(get(person, 'isError'), 'the record is in the error state'); + assert.equal(get(person, 'adapterError'), error, 'error object is exposed'); }); }); }); -test("if an updated record is marked as invalid by the server, it enters an error state", function(assert) { +test('if an updated record is marked as invalid by the server, it enters an error state', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { - assert.equal(type, Person, "the type is correct"); + assert.equal(type, Person, 'the type is correct'); if (snapshot.attr('name').indexOf('Bro') === -1) { - return reject(new DS.InvalidError([ - { - title: 'Invalid Attribute', - detail: 'common... name requires a "bro"', - source: { - pointer: '/data/attributes/name' - } - } - ])); + return reject( + new DS.InvalidError([ + { + title: 'Invalid Attribute', + detail: 'common... name requires a "bro"', + source: { + pointer: '/data/attributes/name', + }, + }, + ]) + ); } else { return resolve(); } @@ -669,57 +739,71 @@ test("if an updated record is marked as invalid by the server, it enters an erro type: 'person', id: '1', attributes: { - name: 'Brohuda Brokatz' - } - } + name: 'Brohuda Brokatz', + }, + }, }); return store.peekRecord('person', 1); }); return run(() => { - return store.findRecord('person', 1).then(person => { - assert.equal(person, yehuda, "The same object is passed through"); - - assert.equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); - set(yehuda, 'name', "Yehuda Katz"); - assert.equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); - - assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); - - return yehuda.save(); - }).catch(reason => { - assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); - assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); - - set(yehuda, 'updatedAt', true); - assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid"); - - set(yehuda, 'name', "Brohuda Brokatz"); - assert.equal(get(yehuda, 'isValid'), true, "the record is no longer invalid after changing"); - assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); - - return yehuda.save(); - }).then(yehuda => { - assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); - assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is no longer new"); - }); + return store + .findRecord('person', 1) + .then(person => { + assert.equal(person, yehuda, 'The same object is passed through'); + + assert.equal(get(yehuda, 'isValid'), true, 'precond - the record is valid'); + set(yehuda, 'name', 'Yehuda Katz'); + assert.equal( + get(yehuda, 'isValid'), + true, + 'precond - the record is still valid as far as we know' + ); + + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, 'the record is dirty'); + + return yehuda.save(); + }) + .catch(reason => { + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, 'the record is still dirty'); + assert.equal(get(yehuda, 'isValid'), false, 'the record is invalid'); + + set(yehuda, 'updatedAt', true); + assert.equal(get(yehuda, 'isValid'), false, 'the record is still invalid'); + + set(yehuda, 'name', 'Brohuda Brokatz'); + assert.equal( + get(yehuda, 'isValid'), + true, + 'the record is no longer invalid after changing' + ); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, 'the record has outstanding changes'); + + return yehuda.save(); + }) + .then(yehuda => { + assert.equal(get(yehuda, 'isValid'), true, 'record remains valid after committing'); + assert.equal(get(yehuda, 'hasDirtyAttributes'), false, 'record is no longer new'); + }); }); }); -test("records can have errors on arbitrary properties after update", function(assert) { +test('records can have errors on arbitrary properties after update', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { if (snapshot.attr('name').indexOf('Bro') === -1) { - return reject(new DS.InvalidError([ - { - title: "Invalid Attribute", - detail: "is a generally unsavoury character", - source: { - pointer: "/data/attributes/base" - } - } - ])); + return reject( + new DS.InvalidError([ + { + title: 'Invalid Attribute', + detail: 'is a generally unsavoury character', + source: { + pointer: '/data/attributes/base', + }, + }, + ]) + ); } else { return resolve(); } @@ -731,63 +815,79 @@ test("records can have errors on arbitrary properties after update", function(as type: 'person', id: '1', attributes: { - name: 'Brohuda Brokatz' - } - } + name: 'Brohuda Brokatz', + }, + }, }); return store.peekRecord('person', 1); }); return run(() => { - return store.findRecord('person', 1).then(person => { - assert.equal(person, yehuda, "The same object is passed through"); - - assert.equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); - set(yehuda, 'name', "Yehuda Katz"); - assert.equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); - - assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); - - return yehuda.save(); - }).catch(reason => { - assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); - assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); - assert.ok(get(yehuda, 'errors.base'), "The errors.base property exists"); - assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), [{ attribute: 'base', message: "is a generally unsavoury character" }]); - - set(yehuda, 'updatedAt', true); - assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid"); - - set(yehuda, 'name', "Brohuda Brokatz"); - assert.equal(get(yehuda, 'isValid'), false, "the record is still invalid after changing (only server can know if it's now valid)"); - assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record has outstanding changes"); - - return yehuda.save(); - }).then(yehuda => { - assert.equal(get(yehuda, 'isValid'), true, "record remains valid after committing"); - assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is no longer new"); - assert.ok(!get(yehuda, 'errors.base'), "The errors.base property does not exist"); - assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), []); - }); + return store + .findRecord('person', 1) + .then(person => { + assert.equal(person, yehuda, 'The same object is passed through'); + + assert.equal(get(yehuda, 'isValid'), true, 'precond - the record is valid'); + set(yehuda, 'name', 'Yehuda Katz'); + assert.equal( + get(yehuda, 'isValid'), + true, + 'precond - the record is still valid as far as we know' + ); + + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, 'the record is dirty'); + + return yehuda.save(); + }) + .catch(reason => { + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, 'the record is still dirty'); + assert.equal(get(yehuda, 'isValid'), false, 'the record is invalid'); + assert.ok(get(yehuda, 'errors.base'), 'The errors.base property exists'); + assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), [ + { attribute: 'base', message: 'is a generally unsavoury character' }, + ]); + + set(yehuda, 'updatedAt', true); + assert.equal(get(yehuda, 'isValid'), false, 'the record is still invalid'); + + set(yehuda, 'name', 'Brohuda Brokatz'); + assert.equal( + get(yehuda, 'isValid'), + false, + "the record is still invalid after changing (only server can know if it's now valid)" + ); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, 'the record has outstanding changes'); + + return yehuda.save(); + }) + .then(yehuda => { + assert.equal(get(yehuda, 'isValid'), true, 'record remains valid after committing'); + assert.equal(get(yehuda, 'hasDirtyAttributes'), false, 'record is no longer new'); + assert.ok(!get(yehuda, 'errors.base'), 'The errors.base property does not exist'); + assert.deepEqual(get(yehuda, 'errors').errorsFor('base'), []); + }); }); }); -test("if an updated record is marked as invalid by the server, you can attempt the save again", function(assert) { +test('if an updated record is marked as invalid by the server, you can attempt the save again', function(assert) { let saveCount = 0; adapter.shouldBackgroundReloadRecord = () => false; adapter.updateRecord = function(store, type, snapshot) { - assert.equal(type, Person, "the type is correct"); + assert.equal(type, Person, 'the type is correct'); saveCount++; if (snapshot.attr('name').indexOf('Bro') === -1) { - return reject(new DS.InvalidError([ - { - title: 'Invalid Attribute', - detail: 'common... name requires a "bro"', - source: { - pointer: '/data/attributes/name' - } - } - ])); + return reject( + new DS.InvalidError([ + { + title: 'Invalid Attribute', + detail: 'common... name requires a "bro"', + source: { + pointer: '/data/attributes/name', + }, + }, + ]) + ); } else { return resolve(); } @@ -799,47 +899,62 @@ test("if an updated record is marked as invalid by the server, you can attempt t type: 'person', id: '1', attributes: { - name: 'Brohuda Brokatz' - } - } + name: 'Brohuda Brokatz', + }, + }, }); return store.peekRecord('person', 1); }); return run(() => { - return store.findRecord('person', 1).then(person => { - assert.equal(person, yehuda, "The same object is passed through"); - - assert.equal(get(yehuda, 'isValid'), true, "precond - the record is valid"); - set(yehuda, 'name', "Yehuda Katz"); - assert.equal(get(yehuda, 'isValid'), true, "precond - the record is still valid as far as we know"); - - assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is dirty"); - - return yehuda.save(); - }).catch(reason => { - assert.equal(saveCount, 1, "The record has been saved once"); - assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); - assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "the record is still dirty"); - assert.equal(get(yehuda, 'isValid'), false, "the record is invalid"); - return yehuda.save(); - }).catch(reason => { - assert.equal(saveCount, 2, "The record has been saved twice"); - assert.ok(reason.message.match("The adapter rejected the commit because it was invalid"), "It should fail due to being invalid"); - assert.equal(get(yehuda, 'isValid'), false, "record is still invalid"); - assert.equal(get(yehuda, 'hasDirtyAttributes'), true, "record is still dirty"); - set(yehuda, 'name', 'Brohuda Brokatz'); - return yehuda.save(); - }).then(person => { - assert.equal(saveCount, 3, "The record has been saved thrice"); - assert.equal(get(yehuda, 'isValid'), true, "record is valid"); - assert.equal(get(yehuda, 'hasDirtyAttributes'), false, "record is not dirty"); - assert.equal(get(yehuda, 'errors.isEmpty'), true, "record has no errors"); - }); + return store + .findRecord('person', 1) + .then(person => { + assert.equal(person, yehuda, 'The same object is passed through'); + + assert.equal(get(yehuda, 'isValid'), true, 'precond - the record is valid'); + set(yehuda, 'name', 'Yehuda Katz'); + assert.equal( + get(yehuda, 'isValid'), + true, + 'precond - the record is still valid as far as we know' + ); + + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, 'the record is dirty'); + + return yehuda.save(); + }) + .catch(reason => { + assert.equal(saveCount, 1, 'The record has been saved once'); + assert.ok( + reason.message.match('The adapter rejected the commit because it was invalid'), + 'It should fail due to being invalid' + ); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, 'the record is still dirty'); + assert.equal(get(yehuda, 'isValid'), false, 'the record is invalid'); + return yehuda.save(); + }) + .catch(reason => { + assert.equal(saveCount, 2, 'The record has been saved twice'); + assert.ok( + reason.message.match('The adapter rejected the commit because it was invalid'), + 'It should fail due to being invalid' + ); + assert.equal(get(yehuda, 'isValid'), false, 'record is still invalid'); + assert.equal(get(yehuda, 'hasDirtyAttributes'), true, 'record is still dirty'); + set(yehuda, 'name', 'Brohuda Brokatz'); + return yehuda.save(); + }) + .then(person => { + assert.equal(saveCount, 3, 'The record has been saved thrice'); + assert.equal(get(yehuda, 'isValid'), true, 'record is valid'); + assert.equal(get(yehuda, 'hasDirtyAttributes'), false, 'record is not dirty'); + assert.equal(get(yehuda, 'errors.isEmpty'), true, 'record has no errors'); + }); }); }); -test("if a updated record is marked as erred by the server, it enters an error state", function(assert) { +test('if a updated record is marked as erred by the server, it enters an error state', function(assert) { let error = new DS.AdapterError(); adapter.shouldBackgroundReloadRecord = () => false; @@ -853,37 +968,42 @@ test("if a updated record is marked as erred by the server, it enters an error s type: 'person', id: '1', attributes: { - name: 'John Doe' - } - } + name: 'John Doe', + }, + }, }); return store.peekRecord('person', 1); }); - return run(() => store.findRecord('person', 1).then(record => { - assert.equal(record, person, "The person was resolved"); - person.set('name', "Jonathan Doe"); - return person.save(); - }).catch(reason => { - assert.ok(get(person, 'isError'), "the record is in the error state"); - assert.equal(get(person, 'adapterError'), error, "error object is exposed"); - })); + return run(() => + store + .findRecord('person', 1) + .then(record => { + assert.equal(record, person, 'The person was resolved'); + person.set('name', 'Jonathan Doe'); + return person.save(); + }) + .catch(reason => { + assert.ok(get(person, 'isError'), 'the record is in the error state'); + assert.equal(get(person, 'adapterError'), error, 'error object is exposed'); + }) + ); }); -test("can be created after the DS.Store", function(assert) { +test('can be created after the DS.Store', function(assert) { assert.expect(1); adapter.findRecord = function(store, type, id, snapshot) { - assert.equal(type, Person, "the type is correct"); - return resolve({ data: { id: 1, type: "person" } }); + assert.equal(type, Person, 'the type is correct'); + return resolve({ data: { id: 1, type: 'person' } }); }; run(() => store.findRecord('person', 1)); }); -test("relationships returned via `commit` do not trigger additional findManys", function(assert) { +test('relationships returned via `commit` do not trigger additional findManys', function(assert) { Person.reopen({ - dogs: DS.hasMany('dog', { async: false }) + dogs: DS.hasMany('dog', { async: false }), }); run(() => { @@ -892,9 +1012,9 @@ test("relationships returned via `commit` do not trigger additional findManys", type: 'dog', id: '1', attributes: { - name: 'Scruffy' - } - } + name: 'Scruffy', + }, + }, }); }); @@ -902,14 +1022,14 @@ test("relationships returned via `commit` do not trigger additional findManys", return resolve({ data: { id: 1, - type: "person", - attributes: { name: "Tom Dale" }, + type: 'person', + attributes: { name: 'Tom Dale' }, relationships: { dogs: { - data: [{ id: 1, type: "dog" }] - } - } - } + data: [{ id: 1, type: 'dog' }], + }, + }, + }, }); }; @@ -920,58 +1040,61 @@ test("relationships returned via `commit` do not trigger additional findManys", type: 'person', id: '1', attributes: { - name: 'Tom Dale' + name: 'Tom Dale', }, relationships: { dogs: { - data: [ - { type: 'dog', id: '1' }, - { type: 'dog', id: '2' } - ] - } - } + data: [{ type: 'dog', id: '1' }, { type: 'dog', id: '2' }], + }, + }, }, - included: [{ - type: 'dog', - id: '2', - attributes: { - name: 'Scruffles' - } - }] + included: [ + { + type: 'dog', + id: '2', + attributes: { + name: 'Scruffles', + }, + }, + ], }); - resolve({ data: { id: 1, type: "dog", attributes: { name: "Scruffy" } } }); + resolve({ data: { id: 1, type: 'dog', attributes: { name: 'Scruffy' } } }); }); }; adapter.findMany = function(store, type, ids, snapshots) { - assert.ok(false, "Should not get here"); + assert.ok(false, 'Should not get here'); }; return run(() => { - store.findRecord('person', 1).then(person => { - return hash({ tom: person, dog: store.findRecord('dog', 1) }); - }).then(records => { - records.tom.get('dogs'); - return records.dog.save(); - }).then(tom => { - assert.ok(true, "Tom was saved"); - }); + store + .findRecord('person', 1) + .then(person => { + return hash({ tom: person, dog: store.findRecord('dog', 1) }); + }) + .then(records => { + records.tom.get('dogs'); + return records.dog.save(); + }) + .then(tom => { + assert.ok(true, 'Tom was saved'); + }); }); }); test("relationships don't get reset if the links is the same", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; Person.reopen({ - dogs: DS.hasMany({ async: true }) + dogs: DS.hasMany({ async: true }), }); let count = 0; adapter.findHasMany = function(store, snapshot, link, relationship) { - assert.ok(count++ === 0, "findHasMany is only called once"); + assert.ok(count++ === 0, 'findHasMany is only called once'); - return resolve({ data: [{ id: 1, type: "dog", attributes: { name: "Scruffy" } }] }); + return resolve({ data: [{ id: 1, type: 'dog', attributes: { name: 'Scruffy' } }] }); }; run(() => { @@ -980,101 +1103,107 @@ test("relationships don't get reset if the links is the same", function(assert) type: 'person', id: '1', attributes: { - name: 'Tom Dale' + name: 'Tom Dale', }, relationships: { dogs: { links: { - related: '/dogs' - } - } - } - } + related: '/dogs', + }, + }, + }, + }, }); }); let tom, dogs; - return run(() => store.findRecord('person', 1).then(person => { - tom = person; - dogs = tom.get('dogs'); - return dogs; - }).then(dogs => { - assert.equal(dogs.get('length'), 1, "The dogs are loaded"); - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' - }, - relationships: { - dogs: { - links: { - related: '/dogs' - } - } - } - } - }); - assert.ok(tom.get('dogs') instanceof DS.PromiseArray, 'dogs is a promise'); - return tom.get('dogs'); - }).then(dogs => { - assert.equal(dogs.get('length'), 1, "The same dogs are loaded"); - })); + return run(() => + store + .findRecord('person', 1) + .then(person => { + tom = person; + dogs = tom.get('dogs'); + return dogs; + }) + .then(dogs => { + assert.equal(dogs.get('length'), 1, 'The dogs are loaded'); + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + dogs: { + links: { + related: '/dogs', + }, + }, + }, + }, + }); + assert.ok(tom.get('dogs') instanceof DS.PromiseArray, 'dogs is a promise'); + return tom.get('dogs'); + }) + .then(dogs => { + assert.equal(dogs.get('length'), 1, 'The same dogs are loaded'); + }) + ); }); -test("async hasMany always returns a promise", function(assert) { +test('async hasMany always returns a promise', function(assert) { Person.reopen({ - dogs: DS.hasMany({ async: true }) + dogs: DS.hasMany({ async: true }), }); adapter.createRecord = function(store, type, snapshot) { return resolve({ data: { id: 1, - type: "person", + type: 'person', attributes: { - name: "Tom Dale" + name: 'Tom Dale', }, relationships: { - dogs: [] - } - } + dogs: [], + }, + }, }); }; - let tom = store.createRecord('person', { name: "Tom Dale" }); + let tom = store.createRecord('person', { name: 'Tom Dale' }); run(() => { - assert.ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise before save"); + assert.ok(tom.get('dogs') instanceof DS.PromiseArray, 'dogs is a promise before save'); }); return run(() => { return tom.save().then(() => { - assert.ok(tom.get('dogs') instanceof DS.PromiseArray, "dogs is a promise after save"); + assert.ok(tom.get('dogs') instanceof DS.PromiseArray, 'dogs is a promise after save'); }); }); }); -test("createRecord receives a snapshot", function(assert) { +test('createRecord receives a snapshot', function(assert) { assert.expect(1); adapter.createRecord = function(store, type, snapshot) { - assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); + assert.ok(snapshot instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); return resolve(); }; - let record = store.createRecord('person', { name: "Tom Dale", id: 1 }); + let record = store.createRecord('person', { name: 'Tom Dale', id: 1 }); run(() => record.save()); }); -test("updateRecord receives a snapshot", function(assert) { +test('updateRecord receives a snapshot', function(assert) { assert.expect(1); adapter.updateRecord = function(store, type, snapshot) { - assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); + assert.ok(snapshot instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); return resolve(); }; @@ -1086,24 +1215,24 @@ test("updateRecord receives a snapshot", function(assert) { type: 'person', id: '1', attributes: { - name: 'Tom Dale' - } - } + name: 'Tom Dale', + }, + }, }); person = store.peekRecord('person', 1); }); run(() => { - set(person, "name", "Tomster"); + set(person, 'name', 'Tomster'); person.save(); }); }); -test("deleteRecord receives a snapshot", function(assert) { +test('deleteRecord receives a snapshot', function(assert) { assert.expect(1); adapter.deleteRecord = function(store, type, snapshot) { - assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); + assert.ok(snapshot instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); return resolve(); }; @@ -1115,9 +1244,9 @@ test("deleteRecord receives a snapshot", function(assert) { type: 'person', id: '1', attributes: { - name: 'Tom Dale' - } - } + name: 'Tom Dale', + }, + }, }); person = store.peekRecord('person', 1); }); @@ -1128,29 +1257,29 @@ test("deleteRecord receives a snapshot", function(assert) { }); }); -test("findRecord receives a snapshot", function(assert) { +test('findRecord receives a snapshot', function(assert) { assert.expect(1); adapter.findRecord = function(store, type, id, snapshot) { - assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); - return resolve({ data: { id: 1, type: "person" } }); + assert.ok(snapshot instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); + return resolve({ data: { id: 1, type: 'person' } }); }; return run(() => store.findRecord('person', 1)); }); -test("findMany receives an array of snapshots", function(assert) { +test('findMany receives an array of snapshots', function(assert) { assert.expect(2); Person.reopen({ - dogs: DS.hasMany({ async: true }) + dogs: DS.hasMany({ async: true }), }); adapter.coalesceFindRequests = true; adapter.findMany = function(store, type, ids, snapshots) { - assert.ok(snapshots[0] instanceof DS.Snapshot, "snapshots[0] is an instance of DS.Snapshot"); - assert.ok(snapshots[1] instanceof DS.Snapshot, "snapshots[1] is an instance of DS.Snapshot"); - return resolve({ data: [{ id: 2, type: "dog" }, { id: 3, type: "dog" }] }); + assert.ok(snapshots[0] instanceof DS.Snapshot, 'snapshots[0] is an instance of DS.Snapshot'); + assert.ok(snapshots[1] instanceof DS.Snapshot, 'snapshots[1] is an instance of DS.Snapshot'); + return resolve({ data: [{ id: 2, type: 'dog' }, { id: 3, type: 'dog' }] }); }; let person; @@ -1162,13 +1291,10 @@ test("findMany receives an array of snapshots", function(assert) { id: '1', relationships: { dogs: { - data: [ - { type: 'dog', id: '2' }, - { type: 'dog', id: '3' } - ] - } - } - } + data: [{ type: 'dog', id: '2' }, { type: 'dog', id: '3' }], + }, + }, + }, }); person = store.peekRecord('person', 1); }); @@ -1176,16 +1302,16 @@ test("findMany receives an array of snapshots", function(assert) { run(() => person.get('dogs')); }); -test("findHasMany receives a snapshot", function(assert) { +test('findHasMany receives a snapshot', function(assert) { assert.expect(1); Person.reopen({ - dogs: DS.hasMany({ async: true }) + dogs: DS.hasMany({ async: true }), }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); - return resolve({ data: [{ id: 2, type: "dog" }, { id: 3, type: "dog" }] }); + assert.ok(snapshot instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); + return resolve({ data: [{ id: 2, type: 'dog' }, { id: 3, type: 'dog' }] }); }; let person; @@ -1198,11 +1324,11 @@ test("findHasMany receives a snapshot", function(assert) { relationships: { dogs: { links: { - related: 'dogs' - } - } - } - } + related: 'dogs', + }, + }, + }, + }, }); person = store.peekRecord('person', 1); }); @@ -1210,16 +1336,16 @@ test("findHasMany receives a snapshot", function(assert) { return run(() => person.get('dogs')); }); -test("findBelongsTo receives a snapshot", function(assert) { +test('findBelongsTo receives a snapshot', function(assert) { assert.expect(1); Person.reopen({ - dog: DS.belongsTo({ async: true }) + dog: DS.belongsTo({ async: true }), }); env.adapter.findBelongsTo = function(store, snapshot, link, relationship) { - assert.ok(snapshot instanceof DS.Snapshot, "snapshot is an instance of DS.Snapshot"); - return resolve({ data: { id: 2, type: "dog" } }); + assert.ok(snapshot instanceof DS.Snapshot, 'snapshot is an instance of DS.Snapshot'); + return resolve({ data: { id: 2, type: 'dog' } }); }; let person; @@ -1232,11 +1358,11 @@ test("findBelongsTo receives a snapshot", function(assert) { relationships: { dog: { links: { - related: 'dog' - } - } - } - } + related: 'dog', + }, + }, + }, + }, }); person = store.peekRecord('person', 1); }); @@ -1244,12 +1370,12 @@ test("findBelongsTo receives a snapshot", function(assert) { return run(() => person.get('dog')); }); -test("record.save should pass adapterOptions to the updateRecord method", function(assert) { +test('record.save should pass adapterOptions to the updateRecord method', function(assert) { assert.expect(1); env.adapter.updateRecord = function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); - return resolve({ data: { id: 1, type: "person" } }); + return resolve({ data: { id: 1, type: 'person' } }); }; return run(() => { @@ -1258,35 +1384,34 @@ test("record.save should pass adapterOptions to the updateRecord method", functi type: 'person', id: '1', attributes: { - name: 'Tom' - } - } + name: 'Tom', + }, + }, }); let person = store.peekRecord('person', 1); return person.save({ adapterOptions: { subscribe: true } }); }); }); -test("record.save should pass adapterOptions to the createRecord method", function(assert) { +test('record.save should pass adapterOptions to the createRecord method', function(assert) { assert.expect(1); env.adapter.createRecord = function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); - return resolve({ data: { id: 1, type: "person" } }); + return resolve({ data: { id: 1, type: 'person' } }); }; return run(() => { - store.createRecord('person', { name: 'Tom' }) - .save({ adapterOptions: { subscribe: true } }); + store.createRecord('person', { name: 'Tom' }).save({ adapterOptions: { subscribe: true } }); }); }); -test("record.save should pass adapterOptions to the deleteRecord method", function(assert) { +test('record.save should pass adapterOptions to the deleteRecord method', function(assert) { assert.expect(1); env.adapter.deleteRecord = function(store, type, snapshot) { assert.deepEqual(snapshot.adapterOptions, { subscribe: true }); - return resolve({ data: { id: 1, type: "person" } }); + return resolve({ data: { id: 1, type: 'person' } }); }; run(() => { @@ -1295,21 +1420,21 @@ test("record.save should pass adapterOptions to the deleteRecord method", functi type: 'person', id: '1', attributes: { - name: 'Tom' - } - } + name: 'Tom', + }, + }, }); let person = store.peekRecord('person', 1); person.destroyRecord({ adapterOptions: { subscribe: true } }); }); }); -test("store.findRecord should pass adapterOptions to adapter.findRecord", function(assert) { +test('store.findRecord should pass adapterOptions to adapter.findRecord', function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { assert.deepEqual(snapshot.adapterOptions, { query: { embed: true } }); - return resolve({ data: { id: 1, type: "person" } }); + return resolve({ data: { id: 1, type: 'person' } }); }; return run(() => { @@ -1317,7 +1442,7 @@ test("store.findRecord should pass adapterOptions to adapter.findRecord", functi }); }); -test("store.query should pass adapterOptions to adapter.query ", function(assert) { +test('store.query should pass adapterOptions to adapter.query ', function(assert) { assert.expect(2); env.adapter.query = function(store, type, query, array, options) { @@ -1331,7 +1456,7 @@ test("store.query should pass adapterOptions to adapter.query ", function(assert }); }); -test("store.queryRecord should pass adapterOptions to adapter.queryRecord", function(assert) { +test('store.queryRecord should pass adapterOptions to adapter.queryRecord', function(assert) { assert.expect(2); env.adapter.queryRecord = function(store, type, query, snapshot) { @@ -1349,20 +1474,20 @@ test("store.findRecord should pass 'include' to adapter.findRecord", function(as assert.expect(1); env.adapter.findRecord = (store, type, id, snapshot) => { - assert.equal(snapshot.include, 'books', 'include passed to adapter.findRecord'); - return resolve({ data: { id: 1, type: "person" } }); + assert.equal(snapshot.include, 'books', 'include passed to adapter.findRecord'); + return resolve({ data: { id: 1, type: 'person' } }); }; run(() => store.findRecord('person', 1, { include: 'books' })); }); -test("store.findAll should pass adapterOptions to the adapter.findAll method", function(assert) { +test('store.findAll should pass adapterOptions to the adapter.findAll method', function(assert) { assert.expect(1); env.adapter.findAll = function(store, type, sinceToken, arraySnapshot) { let adapterOptions = arraySnapshot.adapterOptions; assert.deepEqual(adapterOptions, { query: { embed: true } }); - return resolve({ data: [{ id: 1, type: "person" }] }); + return resolve({ data: [{ id: 1, type: 'person' }] }); }; return run(() => { @@ -1375,20 +1500,20 @@ test("store.findAll should pass 'include' to adapter.findAll", function(assert) env.adapter.findAll = function(store, type, sinceToken, arraySnapshot) { assert.equal(arraySnapshot.include, 'books', 'include passed to adapter.findAll'); - return resolve({ data: [{ id: 1, type: "person" }] }); + return resolve({ data: [{ id: 1, type: 'person' }] }); }; run(() => store.findAll('person', { include: 'books' })); }); -test("An async hasMany relationship with links should not trigger shouldBackgroundReloadRecord", function(assert) { +test('An async hasMany relationship with links should not trigger shouldBackgroundReloadRecord', function(assert) { const Post = DS.Model.extend({ - name: DS.attr("string"), - comments: DS.hasMany('comment', { async: true }) + name: DS.attr('string'), + comments: DS.hasMany('comment', { async: true }), }); const Comment = DS.Model.extend({ - name: DS.attr("string") + name: DS.attr('string'), }); env = setupStore({ @@ -1399,69 +1524,83 @@ test("An async hasMany relationship with links should not trigger shouldBackgrou return { posts: { id: 1, - name: "Rails is omakase", - links: { comments: '/posts/1/comments' } - } + name: 'Rails is omakase', + links: { comments: '/posts/1/comments' }, + }, }; }, findHasMany() { return resolve({ comments: [ - { id: 1, name: "FIRST" }, - { id: 2, name: "Rails is unagi" }, - { id: 3, name: "What is omakase?" } - ] + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], }); }, shouldBackgroundReloadRecord() { assert.ok(false, 'shouldBackgroundReloadRecord should not be called'); - } - }) + }, + }), }); store = env.store; - return run(() => store.findRecord('post', '1').then(post => { - return post.get('comments'); - }).then(comments => { - assert.equal(comments.get('length'), 3); - })); + return run(() => + store + .findRecord('post', '1') + .then(post => { + return post.get('comments'); + }) + .then(comments => { + assert.equal(comments.get('length'), 3); + }) + ); }); -testInDebug("There should be a friendly error for if the adapter does not implement createRecord", function(assert) { - adapter.createRecord = null; +testInDebug( + 'There should be a friendly error for if the adapter does not implement createRecord', + function(assert) { + adapter.createRecord = null; - let tom = run(() => store.createRecord('person', { name: "Tom Dale" })); + let tom = run(() => store.createRecord('person', { name: 'Tom Dale' })); - assert.expectAssertion(() => { - run(() => tom.save()); - }, /does not implement 'createRecord'/); + assert.expectAssertion(() => { + run(() => tom.save()); + }, /does not implement 'createRecord'/); - moveRecordOutOfInFlight(tom); -}); + moveRecordOutOfInFlight(tom); + } +); -testInDebug("There should be a friendly error for if the adapter does not implement updateRecord", function(assert) { - adapter.updateRecord = null; +testInDebug( + 'There should be a friendly error for if the adapter does not implement updateRecord', + function(assert) { + adapter.updateRecord = null; - let tom = run(() => store.push({ data: { type: 'person', id: 1 } })); - assert.expectAssertion(() => { - run(() => tom.save()); - }, /does not implement 'updateRecord'/); + let tom = run(() => store.push({ data: { type: 'person', id: 1 } })); + assert.expectAssertion(() => { + run(() => tom.save()); + }, /does not implement 'updateRecord'/); - moveRecordOutOfInFlight(tom); -}); + moveRecordOutOfInFlight(tom); + } +); -testInDebug("There should be a friendly error for if the adapter does not implement deleteRecord", function(assert) { - adapter.deleteRecord = null; +testInDebug( + 'There should be a friendly error for if the adapter does not implement deleteRecord', + function(assert) { + adapter.deleteRecord = null; - let tom = run(() => store.push({ data: { type: 'person', id: 1 } })); + let tom = run(() => store.push({ data: { type: 'person', id: 1 } })); - assert.expectAssertion(() => { - run(() => { - tom.deleteRecord(); - return tom.save(); - }); - }, /does not implement 'deleteRecord'/); + assert.expectAssertion(() => { + run(() => { + tom.deleteRecord(); + return tom.save(); + }); + }, /does not implement 'deleteRecord'/); - moveRecordOutOfInFlight(tom); -}); + moveRecordOutOfInFlight(tom); + } +); diff --git a/tests/integration/application-test.js b/tests/integration/application-test.js index d09499705c7..fdbcc0ed0d3 100644 --- a/tests/integration/application-test.js +++ b/tests/integration/application-test.js @@ -26,7 +26,7 @@ function lookup(thing) { return run(container, 'lookup', thing); } -module("integration/application - Injecting a Custom Store", { +module('integration/application - Injecting a Custom Store', { beforeEach() { run(() => { app = Application.create({ @@ -34,7 +34,7 @@ module("integration/application - Injecting a Custom Store", { FooController: Controller.extend(), BazController: {}, ApplicationController: Controller.extend(), - rootElement: '#qunit-fixture' + rootElement: '#qunit-fixture', }); }); @@ -44,22 +44,22 @@ module("integration/application - Injecting a Custom Store", { afterEach() { run(app, app.destroy); Ember.BOOTED = false; - } + }, }); -test("If a Store property exists on an Ember.Application, it should be instantiated.", function(assert) { +test('If a Store property exists on an Ember.Application, it should be instantiated.', function(assert) { run(() => { - assert.ok(getStore().get('isCustom'), "the custom store was instantiated"); + assert.ok(getStore().get('isCustom'), 'the custom store was instantiated'); }); }); -test("If a store is instantiated, it should be made available to each controller.", function(assert) { +test('If a store is instantiated, it should be made available to each controller.', function(assert) { let fooController = lookup('controller:foo'); let isCustom = run(fooController, 'get', 'store.isCustom'); - assert.ok(isCustom, "the custom store was injected"); + assert.ok(isCustom, 'the custom store was injected'); }); -test("The JSONAPIAdapter is the default adapter when no custom adapter is provided", function(assert) { +test('The JSONAPIAdapter is the default adapter when no custom adapter is provided', function(assert) { run(() => { let store = getStore(); let adapter = store.adapterFor('application'); @@ -68,13 +68,13 @@ test("The JSONAPIAdapter is the default adapter when no custom adapter is provid }); }); -module("integration/application - Injecting the Default Store", { +module('integration/application - Injecting the Default Store', { beforeEach() { run(() => { app = Application.create({ FooController: Controller.extend(), BazController: {}, - ApplicationController: Controller.extend() + ApplicationController: Controller.extend(), }); }); @@ -84,32 +84,32 @@ module("integration/application - Injecting the Default Store", { afterEach() { run(app, 'destroy'); Ember.BOOTED = false; - } + }, }); -test("If a Store property exists on an Ember.Application, it should be instantiated.", function(assert) { - assert.ok(getStore() instanceof DS.Store, "the store was instantiated"); +test('If a Store property exists on an Ember.Application, it should be instantiated.', function(assert) { + assert.ok(getStore() instanceof DS.Store, 'the store was instantiated'); }); -test("If a store is instantiated, it should be made available to each controller.", function(assert) { +test('If a store is instantiated, it should be made available to each controller.', function(assert) { run(() => { let fooController = lookup('controller:foo'); - assert.ok(fooController.get('store') instanceof DS.Store, "the store was injected"); + assert.ok(fooController.get('store') instanceof DS.Store, 'the store was injected'); }); }); -test("the DS namespace should be accessible", function(assert) { +test('the DS namespace should be accessible', function(assert) { run(() => { - assert.ok(Namespace.byName('DS') instanceof Namespace, "the DS namespace is accessible"); + assert.ok(Namespace.byName('DS') instanceof Namespace, 'the DS namespace is accessible'); }); }); if (Ember.inject && service) { - module("integration/application - Using the store as a service", { + module('integration/application - Using the store as a service', { beforeEach() { run(() => { app = Application.create({ - DoodleService: Service.extend({ store: service() }) + DoodleService: Service.extend({ store: service() }), }); }); @@ -119,18 +119,18 @@ if (Ember.inject && service) { afterEach() { run(app, 'destroy'); Ember.BOOTED = false; - } + }, }); - test("The store can be injected as a service", function(assert) { + test('The store can be injected as a service', function(assert) { run(() => { let doodleService = lookup('service:doodle'); - assert.ok(doodleService.get('store') instanceof Store, "the store can be used as a service"); + assert.ok(doodleService.get('store') instanceof Store, 'the store can be used as a service'); }); }); } -module("integration/application - Attaching initializer", { +module('integration/application - Attaching initializer', { beforeEach() { App = Application.extend(); }, @@ -140,15 +140,17 @@ module("integration/application - Attaching initializer", { run(app, app.destroy); } Ember.BOOTED = false; - } + }, }); -test("ember-data initializer is run", function(assert) { +test('ember-data initializer is run', function(assert) { let ran = false; App.initializer({ - name: "after-ember-data", - after: "ember-data", - initialize() { ran = true; } + name: 'after-ember-data', + after: 'ember-data', + initialize() { + ran = true; + }, }); run(() => { @@ -158,18 +160,17 @@ test("ember-data initializer is run", function(assert) { assert.ok(ran, 'ember-data initializer was found'); }); -test("ember-data initializer does not register the store service when it was already registered", function(assert) { - +test('ember-data initializer does not register the store service when it was already registered', function(assert) { let AppStore = Store.extend({ - isCustomStore: true + isCustomStore: true, }); App.initializer({ - name: "after-ember-data", - before: "ember-data", + name: 'after-ember-data', + before: 'ember-data', initialize(registry) { registry.register('service:store', AppStore); - } + }, }); run(() => { @@ -178,6 +179,8 @@ test("ember-data initializer does not register the store service when it was alr }); let store = getStore(); - assert.ok(store && store.get('isCustomStore'), 'ember-data initializer does not overwrite the previous registered service store'); - + assert.ok( + store && store.get('isCustomStore'), + 'ember-data initializer does not overwrite the previous registered service store' + ); }); diff --git a/tests/integration/backwards-compat/non-dasherized-lookups-test.js b/tests/integration/backwards-compat/non-dasherized-lookups-test.js index 807a1657966..bfbb18379a2 100644 --- a/tests/integration/backwards-compat/non-dasherized-lookups-test.js +++ b/tests/integration/backwards-compat/non-dasherized-lookups-test.js @@ -6,40 +6,37 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; -const { - JSONAPIAdapter, - Model, - attr, - belongsTo, - hasMany -} = DS; +const { JSONAPIAdapter, Model, attr, belongsTo, hasMany } = DS; let store; -module('integration/backwards-compat/non-dasherized-lookups - non dasherized lookups in application code finders', { - beforeEach() { - const PostNote = Model.extend({ - name: attr('string') - }); - - const ApplicationAdapter = JSONAPIAdapter.extend({ - shouldBackgroundReloadRecord() { - return false; - } - }); +module( + 'integration/backwards-compat/non-dasherized-lookups - non dasherized lookups in application code finders', + { + beforeEach() { + const PostNote = Model.extend({ + name: attr('string'), + }); + + const ApplicationAdapter = JSONAPIAdapter.extend({ + shouldBackgroundReloadRecord() { + return false; + }, + }); - const env = setupStore({ - postNote: PostNote, - adapter: ApplicationAdapter - }); + const env = setupStore({ + postNote: PostNote, + adapter: ApplicationAdapter, + }); - store = env.store; - }, + store = env.store; + }, - afterEach() { - run(store, 'destroy'); + afterEach() { + run(store, 'destroy'); + }, } -}); +); test('can lookup records using camelCase strings', function(assert) { assert.expect(1); @@ -50,14 +47,14 @@ test('can lookup records using camelCase strings', function(assert) { type: 'post-notes', id: '1', attributes: { - name: 'Ember Data' - } - } + name: 'Ember Data', + }, + }, }); }); run(() => { - store.findRecord('postNote', 1).then((postNote) => { + store.findRecord('postNote', 1).then(postNote => { assert.equal(get(postNote, 'name'), 'Ember Data', 'record found'); }); }); @@ -72,55 +69,58 @@ test('can lookup records using under_scored strings', function(assert) { type: 'post-notes', id: '1', attributes: { - name: 'Ember Data' - } - } + name: 'Ember Data', + }, + }, }); }); run(() => { - store.findRecord('post_note', 1).then((postNote) => { + store.findRecord('post_note', 1).then(postNote => { assert.equal(get(postNote, 'name'), 'Ember Data', 'record found'); }); }); }); -module('integration/backwards-compat/non-dasherized-lookups - non dasherized lookups in application code relationship macros', { - beforeEach() { - const PostNote = Model.extend({ - notePost: belongsTo('note-post', { async: false }), +module( + 'integration/backwards-compat/non-dasherized-lookups - non dasherized lookups in application code relationship macros', + { + beforeEach() { + const PostNote = Model.extend({ + notePost: belongsTo('note-post', { async: false }), - name: attr('string') - }); + name: attr('string'), + }); - const NotePost = Model.extend({ - name: attr('string') - }); + const NotePost = Model.extend({ + name: attr('string'), + }); - const LongModelName = Model.extend({ - postNotes: hasMany('post_note') - }); + const LongModelName = Model.extend({ + postNotes: hasMany('post_note'), + }); - const ApplicationAdapter = JSONAPIAdapter.extend({ - shouldBackgroundReloadRecord() { - return false; - } - }); + const ApplicationAdapter = JSONAPIAdapter.extend({ + shouldBackgroundReloadRecord() { + return false; + }, + }); - const env = setupStore({ - longModelName: LongModelName, - notePost: NotePost, - postNote: PostNote, - adapter: ApplicationAdapter - }); + const env = setupStore({ + longModelName: LongModelName, + notePost: NotePost, + postNote: PostNote, + adapter: ApplicationAdapter, + }); - store = env.store; - }, + store = env.store; + }, - afterEach() { - run(store, 'destroy'); + afterEach() { + run(store, 'destroy'); + }, } -}); +); test('looks up belongsTo using camelCase strings', function(assert) { assert.expect(1); @@ -131,28 +131,28 @@ test('looks up belongsTo using camelCase strings', function(assert) { type: 'post-notes', id: '1', attributes: { - name: 'Ember Data' + name: 'Ember Data', }, relationships: { 'note-post': { - data: { type: 'note-post', id: '1' } - } - } - } + data: { type: 'note-post', id: '1' }, + }, + }, + }, }); store.pushPayload('notePost', { data: { type: 'note-posts', id: '1', attributes: { - name: 'Inverse' - } - } + name: 'Inverse', + }, + }, }); }); run(() => { - store.findRecord('post-note', 1).then((postNote) => { + store.findRecord('post-note', 1).then(postNote => { assert.equal(get(postNote, 'notePost.name'), 'Inverse', 'inverse record found'); }); }); @@ -166,14 +166,13 @@ test('looks up belongsTo using under_scored strings', function(assert) { data: { type: 'long-model-names', id: '1', - attributes: { - }, + attributes: {}, relationships: { 'post-notes': { - data: [{ type: 'post-note', id: '1' }] - } - } - } + data: [{ type: 'post-note', id: '1' }], + }, + }, + }, }); store.pushPayload('post-note', { @@ -181,18 +180,17 @@ test('looks up belongsTo using under_scored strings', function(assert) { type: 'post-notes', id: '1', attributes: { - name: 'Ember Data' - } - } + name: 'Ember Data', + }, + }, }); }); run(() => { - store.findRecord('long_model_name', 1).then((longModelName) => { + store.findRecord('long_model_name', 1).then(longModelName => { const postNotes = get(longModelName, 'postNotes').toArray(); - assert.deepEqual(postNotes, [store.peekRecord('postNote', 1)], - 'inverse records found'); + assert.deepEqual(postNotes, [store.peekRecord('postNote', 1)], 'inverse records found'); }); }); }); diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index e7a0561fabe..f9929264304 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -9,41 +9,41 @@ import DS from 'ember-data'; let Post, Comment, Misc, env; -module("integration/client_id_generation - Client-side ID Generation", { +module('integration/client_id_generation - Client-side ID Generation', { beforeEach() { Comment = DS.Model.extend({ - post: DS.belongsTo('post', { async: false }) + post: DS.belongsTo('post', { async: false }), }); Post = DS.Model.extend({ - comments: DS.hasMany('comment', { async: false }) + comments: DS.hasMany('comment', { async: false }), }); Misc = DS.Model.extend({ - foo: DS.attr('string') + foo: DS.attr('string'), }); env = setupStore({ post: Post, comment: Comment, - misc: Misc + misc: Misc, }); }, afterEach() { run(env.container, 'destroy'); - } + }, }); -test("If an adapter implements the `generateIdForRecord` method, the store should be able to assign IDs without saving to the persistence layer.", function(assert) { +test('If an adapter implements the `generateIdForRecord` method, the store should be able to assign IDs without saving to the persistence layer.', function(assert) { assert.expect(6); let idCount = 1; env.adapter.generateIdForRecord = function(passedStore, record) { - assert.equal(env.store, passedStore, "store is the first parameter"); + assert.equal(env.store, passedStore, 'store is the first parameter'); - return "id-" + idCount++; + return 'id-' + idCount++; }; env.adapter.createRecord = function(store, type, snapshot) { @@ -70,13 +70,13 @@ test("If an adapter implements the `generateIdForRecord` method, the store shoul }); }); -test("empty string and undefined ids should coerce to null", function(assert) { +test('empty string and undefined ids should coerce to null', function(assert) { assert.expect(6); let idCount = 0; let id = 1; let ids = [undefined, '']; env.adapter.generateIdForRecord = function(passedStore, record) { - assert.equal(env.store, passedStore, "store is the first parameter"); + assert.equal(env.store, passedStore, 'store is the first parameter'); return ids[idCount++]; }; diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index 0d0d0759697..13a7e11a7dc 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -13,24 +13,25 @@ module('DS.DebugAdapter', { beforeEach() { run(function() { App = Application.extend({ - toString() { return 'debug-app'; } + toString() { + return 'debug-app'; + }, }).create(); App.StoreService = DS.Store.extend({}); App.ApplicationAdapter = DS.Adapter.extend({ - shouldBackgroundReloadRecord: () => false + shouldBackgroundReloadRecord: () => false, }); App.Post = DS.Model.extend({ - title: DS.attr('string') + title: DS.attr('string'), }); // TODO: Remove this when Ember is upgraded to >= 1.13 App.Post.reopenClass({ - _debugContainerKey: 'model:post' + _debugContainerKey: 'model:post', }); - }); store = App.__container__.lookup('service:store'); @@ -47,13 +48,13 @@ module('DS.DebugAdapter', { debugAdapter.reopen({ getModelTypes() { return A([{ klass, name: 'post' }]); - } + }, }); }, afterEach() { run(App, App.destroy); App = store = null; - } + }, }); test('Watching Model Types', function(assert) { @@ -78,14 +79,14 @@ test('Watching Model Types', function(assert) { type: 'post', id: '1', attributes: { - title: 'Post Title' - } - } + title: 'Post Title', + }, + }, }); }); }); -test("Watching Records", function(assert) { +test('Watching Records', function(assert) { var post, record, addedRecords, updatedRecords, removedIndex, removedCount; run(function() { @@ -94,16 +95,16 @@ test("Watching Records", function(assert) { type: 'post', id: '1', attributes: { - title: 'Clean Post' - } - } + title: 'Clean Post', + }, + }, }); }); var recordsAdded = function(wrappedRecords) { addedRecords = wrappedRecords; }; - var recordsUpdated = function(wrappedRecords) { + var recordsUpdated = function(wrappedRecords) { updatedRecords = wrappedRecords; }; var recordsRemoved = function(index, count) { diff --git a/tests/integration/injection-test.js b/tests/integration/injection-test.js index 9b7e72315c9..4e5d80c7cbf 100644 --- a/tests/integration/injection-test.js +++ b/tests/integration/injection-test.js @@ -1,6 +1,6 @@ import { setup as setupModelFactoryInjections, - reset as resetModelFactoryInjections + reset as resetModelFactoryInjections, } from 'dummy/tests/helpers/model-factory-injection'; import EmberObject from '@ember/object'; import { getOwner } from '@ember/application'; @@ -13,10 +13,10 @@ let env, hasFactoryFor, originalLookupFactory, originalOwnerLookupFactory, origi const model = { isModel: true, - _create() { } + _create() {}, }; const factory = { - class: model + class: model, }; module('integration/injection factoryFor enabled', { @@ -63,13 +63,17 @@ module('integration/injection factoryFor enabled', { } run(env.store, 'destroy'); - } + }, }); test('modelFactoryFor', function(assert) { const modelFactory = env.store._modelFactoryFor('super-villain'); - assert.equal(modelFactory, hasFactoryFor ? factory : model, 'expected the factory itself to be returned'); + assert.equal( + modelFactory, + hasFactoryFor ? factory : model, + 'expected the factory itself to be returned' + ); }); test('modelFor', function(assert) { @@ -78,7 +82,11 @@ test('modelFor', function(assert) { assert.equal(modelFactory, model, 'expected the factory itself to be returned'); // TODO: we should deprecate this next line. Resolved state on the class is fraught with peril - assert.equal(modelFactory.modelName, 'super-villain', 'expected the factory itself to be returned'); + assert.equal( + modelFactory.modelName, + 'super-villain', + 'expected the factory itself to be returned' + ); }); module('integration/injection eager injections', { @@ -87,7 +95,7 @@ module('integration/injection eager injections', { env = setupStore(); env.registry.injection('model:foo', 'apple', 'service:apple'); - env.registry.register('model:foo', DS.Model); + env.registry.register('model:foo', DS.Model); env.registry.register('service:apple', EmberObject.extend({ isService: true })); // container injection }, @@ -97,7 +105,7 @@ module('integration/injection eager injections', { resetModelFactoryInjections(); run(env.store, 'destroy'); - } + }, }); test('did inject', function(assert) { diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index 25c57d81dd7..870f6139bab 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -11,7 +11,9 @@ let env, store, User, Job, ReflexiveModel; const { attr, belongsTo } = DS; function stringify(string) { - return function() { return string; }; + return function() { + return string; + }; } module('integration/inverse_test - inverseFor', { @@ -19,20 +21,20 @@ module('integration/inverse_test - inverseFor', { User = DS.Model.extend({ name: attr('string'), bestFriend: belongsTo('user', { async: true, inverse: null }), - job: belongsTo('job', { async: false }) + job: belongsTo('job', { async: false }), }); User.toString = stringify('user'); Job = DS.Model.extend({ isGood: attr(), - user: belongsTo('user', { async: false }) + user: belongsTo('user', { async: false }), }); Job.toString = stringify('job'); ReflexiveModel = DS.Model.extend({ - reflexiveProp: belongsTo('reflexive-model', { async: false }) + reflexiveProp: belongsTo('reflexive-model', { async: false }), }); ReflexiveModel.toString = stringify('reflexiveModel'); @@ -40,7 +42,7 @@ module('integration/inverse_test - inverseFor', { env = setupStore({ user: User, job: Job, - reflexiveModel: ReflexiveModel + reflexiveModel: ReflexiveModel, }); store = env.store; @@ -52,71 +54,83 @@ module('integration/inverse_test - inverseFor', { afterEach() { run(env.container, 'destroy'); - } + }, }); -test("Finds the inverse when there is only one possible available", function(assert) { +test('Finds the inverse when there is only one possible available', function(assert) { let inverseDefinition = Job.inverseFor('user', store); - assert.deepEqual(inverseDefinition, { - type: User, - name: 'job', - kind: 'belongsTo', - options: { - async: false - } - }, 'Gets correct type, name and kind'); + assert.deepEqual( + inverseDefinition, + { + type: User, + name: 'job', + kind: 'belongsTo', + options: { + async: false, + }, + }, + 'Gets correct type, name and kind' + ); }); -test("Finds the inverse when only one side has defined it manually", function(assert) { +test('Finds the inverse when only one side has defined it manually', function(assert) { Job.reopen({ - owner: belongsTo('user', { inverse: 'previousJob', async: false }) + owner: belongsTo('user', { inverse: 'previousJob', async: false }), }); User.reopen({ - previousJob: belongsTo('job', { async: false }) + previousJob: belongsTo('job', { async: false }), }); - assert.deepEqual(Job.inverseFor('owner', store), { - type: User, //the model's type - name: 'previousJob', //the models relationship key - kind: 'belongsTo', - options: { - async: false - } - }, 'Gets correct type, name and kind'); - - assert.deepEqual(User.inverseFor('previousJob', store), { - type: Job, //the model's type - name: 'owner', //the models relationship key - kind: 'belongsTo', - options: { - inverse: 'previousJob', - async: false - } - }, 'Gets correct type, name and kind'); + assert.deepEqual( + Job.inverseFor('owner', store), + { + type: User, //the model's type + name: 'previousJob', //the models relationship key + kind: 'belongsTo', + options: { + async: false, + }, + }, + 'Gets correct type, name and kind' + ); + + assert.deepEqual( + User.inverseFor('previousJob', store), + { + type: Job, //the model's type + name: 'owner', //the models relationship key + kind: 'belongsTo', + options: { + inverse: 'previousJob', + async: false, + }, + }, + 'Gets correct type, name and kind' + ); }); -test("Returns null if inverse relationship it is manually set with a different relationship key", function(assert) { +test('Returns null if inverse relationship it is manually set with a different relationship key', function(assert) { Job.reopen({ - user: belongsTo('user', { inverse: 'previousJob', async: false }) + user: belongsTo('user', { inverse: 'previousJob', async: false }), }); User.reopen({ - job: belongsTo('job', { async: false }) + job: belongsTo('job', { async: false }), }); assert.equal(User.inverseFor('job', store), null, 'There is no inverse'); }); -testInDebug("Errors out if you define 2 inverses to the same model", function(assert) { +testInDebug('Errors out if you define 2 inverses to the same model', function(assert) { Job.reopen({ user: belongsTo('user', { inverse: 'job', async: false }), - owner: belongsTo('user', { inverse: 'job', async: false }) + owner: belongsTo('user', { inverse: 'job', async: false }), }); User.reopen({ - job: belongsTo('job', { async: false }) + job: belongsTo('job', { async: false }), }); assert.expectAssertion(() => { @@ -124,8 +138,7 @@ testInDebug("Errors out if you define 2 inverses to the same model", function(as }, /You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times/i); }); - -test("Caches findInverseFor return value", function(assert) { +test('Caches findInverseFor return value', function(assert) { assert.expect(1); var inverseForUser = Job.inverseFor('user', store); @@ -136,8 +149,9 @@ test("Caches findInverseFor return value", function(assert) { assert.equal(inverseForUser, Job.inverseFor('user', store), 'Inverse cached succesfully'); }); -testInDebug("Errors out if you do not define an inverse for a reflexive relationship", function(assert) { - +testInDebug('Errors out if you do not define an inverse for a reflexive relationship', function( + assert +) { //Maybe store is evaluated lazily, so we need this :( assert.expectWarning(() => { var reflexiveModel; @@ -145,8 +159,8 @@ testInDebug("Errors out if you do not define an inverse for a reflexive relation store.push({ data: { type: 'reflexive-model', - id: '1' - } + id: '1', + }, }); reflexiveModel = store.peekRecord('reflexive-model', 1); reflexiveModel.get('reflexiveProp'); diff --git a/tests/integration/lifecycle-hooks-test.js b/tests/integration/lifecycle-hooks-test.js index 9e6de92c52e..aaf85583e20 100644 --- a/tests/integration/lifecycle-hooks-test.js +++ b/tests/integration/lifecycle-hooks-test.js @@ -9,55 +9,55 @@ import DS from 'ember-data'; let Person, env; const { attr } = DS; -module("integration/lifecycle_hooks - Lifecycle Hooks", { +module('integration/lifecycle_hooks - Lifecycle Hooks', { beforeEach() { Person = DS.Model.extend({ - name: attr('string') + name: attr('string'), }); env = setupStore({ - person: Person + person: Person, }); }, afterEach() { run(env.container, 'destroy'); - } + }, }); -test("When the adapter acknowledges that a record has been created, a `didCreate` event is triggered.", function(assert) { +test('When the adapter acknowledges that a record has been created, a `didCreate` event is triggered.', function(assert) { let done = assert.async(); assert.expect(3); env.adapter.createRecord = function(store, type, snapshot) { - return resolve({ data: { id: 99, type: "person", attributes: { name: "Yehuda Katz" } } }); + return resolve({ data: { id: 99, type: 'person', attributes: { name: 'Yehuda Katz' } } }); }; - let person = env.store.createRecord('person', { name: "Yehuda Katz" }); + let person = env.store.createRecord('person', { name: 'Yehuda Katz' }); person.on('didCreate', function() { - assert.equal(this, person, "this is bound to the record"); - assert.equal(this.get('id'), "99", "the ID has been assigned"); - assert.equal(this.get('name'), "Yehuda Katz", "the attribute has been assigned"); + assert.equal(this, person, 'this is bound to the record'); + assert.equal(this.get('id'), '99', 'the ID has been assigned'); + assert.equal(this.get('name'), 'Yehuda Katz', 'the attribute has been assigned'); done(); }); run(person, 'save'); }); -test("When the adapter acknowledges that a record has been created without a new data payload, a `didCreate` event is triggered.", function(assert) { +test('When the adapter acknowledges that a record has been created without a new data payload, a `didCreate` event is triggered.', function(assert) { assert.expect(3); env.adapter.createRecord = function(store, type, snapshot) { return resolve(); }; - let person = env.store.createRecord('person', { id: 99, name: "Yehuda Katz" }); + let person = env.store.createRecord('person', { id: 99, name: 'Yehuda Katz' }); person.on('didCreate', function() { - assert.equal(this, person, "this is bound to the record"); - assert.equal(this.get('id'), "99", "the ID has been assigned"); - assert.equal(this.get('name'), "Yehuda Katz", "the attribute has been assigned"); + assert.equal(this, person, 'this is bound to the record'); + assert.equal(this.get('id'), '99', 'the ID has been assigned'); + assert.equal(this.get('name'), 'Yehuda Katz', 'the attribute has been assigned'); }); run(person, 'save'); diff --git a/tests/integration/multiple-stores-test.js b/tests/integration/multiple-stores-test.js index b632c75562a..2081e0d6743 100644 --- a/tests/integration/multiple-stores-test.js +++ b/tests/integration/multiple-stores-test.js @@ -8,27 +8,27 @@ import DS from 'ember-data'; let env; let SuperVillain, HomePlanet, EvilMinion; -module("integration/multiple_stores - Multiple Stores Tests", { +module('integration/multiple_stores - Multiple Stores Tests', { beforeEach() { SuperVillain = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - homePlanet: DS.belongsTo('home-planet', { inverse: 'villains', async: false }), - evilMinions: DS.hasMany('evil-minion', { async: false }) + firstName: DS.attr('string'), + lastName: DS.attr('string'), + homePlanet: DS.belongsTo('home-planet', { inverse: 'villains', async: false }), + evilMinions: DS.hasMany('evil-minion', { async: false }), }); HomePlanet = DS.Model.extend({ - name: DS.attr('string'), - villains: DS.hasMany('super-villain', { inverse: 'homePlanet', async: false }) + name: DS.attr('string'), + villains: DS.hasMany('super-villain', { inverse: 'homePlanet', async: false }), }); EvilMinion = DS.Model.extend({ - superVillain: DS.belongsTo('super-villain', { async: false }), - name: DS.attr('string') + superVillain: DS.belongsTo('super-villain', { async: false }), + name: DS.attr('string'), }); env = setupStore({ - superVillain: SuperVillain, - homePlanet: HomePlanet, - evilMinion: EvilMinion + superVillain: SuperVillain, + homePlanet: HomePlanet, + evilMinion: EvilMinion, }); env.registry.register('adapter:application', DS.RESTAdapter); @@ -43,13 +43,16 @@ module("integration/multiple_stores - Multiple Stores Tests", { afterEach() { run(env.store, 'destroy'); - } + }, }); -test("should be able to push into multiple stores", function(assert) { - env.registry.register('adapter:home-planet', DS.RESTAdapter.extend({ - shouldBackgroundReloadRecord: () => false - })); +test('should be able to push into multiple stores', function(assert) { + env.registry.register( + 'adapter:home-planet', + DS.RESTAdapter.extend({ + shouldBackgroundReloadRecord: () => false, + }) + ); let home_planet_main = { id: '1', name: 'Earth' }; let home_planet_a = { id: '1', name: 'Mars' }; @@ -61,24 +64,31 @@ test("should be able to push into multiple stores", function(assert) { env.store_b.push(env.store_b.normalize('home-planet', home_planet_b)); }); - return env.store.findRecord('home-planet', 1).then(homePlanet => { - assert.equal(homePlanet.get('name'), 'Earth'); - - return env.store_a.findRecord('homePlanet', 1); - }).then(homePlanet => { - assert.equal(homePlanet.get('name'), 'Mars'); - return env.store_b.findRecord('homePlanet', 1); - }).then(homePlanet => { - assert.equal(homePlanet.get('name'), 'Saturn'); - }); + return env.store + .findRecord('home-planet', 1) + .then(homePlanet => { + assert.equal(homePlanet.get('name'), 'Earth'); + + return env.store_a.findRecord('homePlanet', 1); + }) + .then(homePlanet => { + assert.equal(homePlanet.get('name'), 'Mars'); + return env.store_b.findRecord('homePlanet', 1); + }) + .then(homePlanet => { + assert.equal(homePlanet.get('name'), 'Saturn'); + }); }); -test("embedded records should be created in multiple stores", function(assert) { - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' } - } - })); +test('embedded records should be created in multiple stores', function(assert) { + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); let serializer_main = env.store.serializerFor('home-planet'); let serializer_a = env.store_a.serializerFor('home-planet'); @@ -86,72 +96,118 @@ test("embedded records should be created in multiple stores", function(assert) { let json_hash_main = { homePlanet: { - id: "1", - name: "Earth", - villains: [{ - id: "1", - firstName: "Tom", - lastName: "Dale" - }] - } + id: '1', + name: 'Earth', + villains: [ + { + id: '1', + firstName: 'Tom', + lastName: 'Dale', + }, + ], + }, }; let json_hash_a = { homePlanet: { - id: "1", - name: "Mars", - villains: [{ - id: "1", - firstName: "James", - lastName: "Murphy" - }] - } + id: '1', + name: 'Mars', + villains: [ + { + id: '1', + firstName: 'James', + lastName: 'Murphy', + }, + ], + }, }; let json_hash_b = { homePlanet: { - id: "1", - name: "Saturn", - villains: [{ - id: "1", - firstName: "Jade", - lastName: "John" - }] - } + id: '1', + name: 'Saturn', + villains: [ + { + id: '1', + firstName: 'Jade', + lastName: 'John', + }, + ], + }, }; let json_main, json_a, json_b; run(() => { - json_main = serializer_main.normalizeResponse(env.store, env.store.modelFor('home-planet'), json_hash_main, 1, 'findRecord'); + json_main = serializer_main.normalizeResponse( + env.store, + env.store.modelFor('home-planet'), + json_hash_main, + 1, + 'findRecord' + ); env.store.push(json_main); - assert.equal(env.store.hasRecordForId('super-villain', "1"), true, "superVillain should exist in service:store"); + assert.equal( + env.store.hasRecordForId('super-villain', '1'), + true, + 'superVillain should exist in service:store' + ); }); run(() => { - json_a = serializer_a.normalizeResponse(env.store_a, env.store_a.modelFor('home-planet'), json_hash_a, 1, 'findRecord'); + json_a = serializer_a.normalizeResponse( + env.store_a, + env.store_a.modelFor('home-planet'), + json_hash_a, + 1, + 'findRecord' + ); env.store_a.push(json_a); - assert.equal(env.store_a.hasRecordForId("super-villain", "1"), true, "superVillain should exist in store:store-a"); + assert.equal( + env.store_a.hasRecordForId('super-villain', '1'), + true, + 'superVillain should exist in store:store-a' + ); }); run(() => { - json_b = serializer_b.normalizeResponse(env.store_b, env.store_a.modelFor('home-planet'), json_hash_b, 1, 'findRecord'); + json_b = serializer_b.normalizeResponse( + env.store_b, + env.store_a.modelFor('home-planet'), + json_hash_b, + 1, + 'findRecord' + ); env.store_b.push(json_b); - assert.equal(env.store_b.hasRecordForId("super-villain", "1"), true, "superVillain should exist in store:store-b"); + assert.equal( + env.store_b.hasRecordForId('super-villain', '1'), + true, + 'superVillain should exist in store:store-b' + ); }); }); - -test("each store should have a unique instance of the serializers", function(assert) { +test('each store should have a unique instance of the serializers', function(assert) { env.registry.register('serializer:home-planet', DS.RESTSerializer.extend({})); let serializer_a = env.store_a.serializerFor('home-planet'); let serializer_b = env.store_b.serializerFor('home-planet'); - assert.equal(get(serializer_a, 'store'), env.store_a, 'serializer_a\'s store prop should be sotre_a'); - assert.equal(get(serializer_b, 'store'), env.store_b, 'serializer_b\'s store prop should be sotre_b'); - assert.notEqual(serializer_a, serializer_b, 'serialier_a and serialier_b should be unique instances'); + assert.equal( + get(serializer_a, 'store'), + env.store_a, + "serializer_a's store prop should be sotre_a" + ); + assert.equal( + get(serializer_b, 'store'), + env.store_b, + "serializer_b's store prop should be sotre_b" + ); + assert.notEqual( + serializer_a, + serializer_b, + 'serialier_a and serialier_b should be unique instances' + ); }); - -test("each store should have a unique instance of the adapters", function(assert) { +test('each store should have a unique instance of the adapters', function(assert) { env.registry.register('adapter:home-planet', DS.Adapter.extend({})); let adapter_a = env.store_a.adapterFor('home-planet'); diff --git a/tests/integration/peek-all-test.js b/tests/integration/peek-all-test.js index c023ee7ee96..28560111ac6 100644 --- a/tests/integration/peek-all-test.js +++ b/tests/integration/peek-all-test.js @@ -8,31 +8,36 @@ import DS from 'ember-data'; let Person, store, array, moreArray; -module("integration/peek-all - DS.Store#peekAll()", { +module('integration/peek-all - DS.Store#peekAll()', { beforeEach() { array = { - data: [{ - type: 'person', - id: '1', - attributes: { - name: "Scumbag Dale" - } - }, { - type: 'person', - id: '2', - attributes: { - name: "Scumbag Katz" - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz', + }, + }, + ], }; moreArray = { - data: [{ - type: 'person', - id: '3', - attributes: { - name: "Scumbag Bryn" - } - }] + data: [ + { + type: 'person', + id: '3', + attributes: { + name: 'Scumbag Bryn', + }, + }, + ], }; Person = DS.Model.extend({ name: DS.attr('string') }); @@ -43,7 +48,7 @@ module("integration/peek-all - DS.Store#peekAll()", { run(store, 'destroy'); Person = null; array = null; - } + }, }); test("store.peekAll('person') should return all records and should update with new ones", function(assert) { @@ -61,31 +66,31 @@ test("store.peekAll('person') should return all records and should update with n assert.equal(get(all, 'length'), 3); }); -test("Calling store.peekAll() multiple times should update immediately inside the runloop", function(assert) { +test('Calling store.peekAll() multiple times should update immediately inside the runloop', function(assert) { assert.expect(3); run(() => { assert.equal(get(store.peekAll('person'), 'length'), 0, 'should initially be empty'); - store.createRecord('person', { name: "Tomster" }); + store.createRecord('person', { name: 'Tomster' }); assert.equal(get(store.peekAll('person'), 'length'), 1, 'should contain one person'); store.push({ data: { type: 'person', id: '1', attributes: { - name: "Tomster's friend" - } - } + name: "Tomster's friend", + }, + }, }); assert.equal(get(store.peekAll('person'), 'length'), 2, 'should contain two people'); }); }); -test("Calling store.peekAll() after creating a record should return correct data", function(assert) { +test('Calling store.peekAll() after creating a record should return correct data', function(assert) { assert.expect(1); run(() => { - store.createRecord('person', { name: "Tomster" }); + store.createRecord('person', { name: 'Tomster' }); assert.equal(get(store.peekAll('person'), 'length'), 1, 'should contain one person'); }); }); diff --git a/tests/integration/polymorphic-belongs-to-test.js b/tests/integration/polymorphic-belongs-to-test.js index a6272b795a9..558f0419be2 100644 --- a/tests/integration/polymorphic-belongs-to-test.js +++ b/tests/integration/polymorphic-belongs-to-test.js @@ -11,15 +11,15 @@ let store; const Book = DS.Model.extend({ title: attr(), - author: belongsTo('person', { polymorphic: true, async: false }) + author: belongsTo('person', { polymorphic: true, async: false }), }); const Author = DS.Model.extend({ - name: attr() + name: attr(), }); const AsyncBook = DS.Model.extend({ - author: belongsTo('person', { polymorphic: true }) + author: belongsTo('person', { polymorphic: true }), }); module('integration/polymorphic-belongs-to - Polymorphic BelongsTo', { @@ -28,18 +28,17 @@ module('integration/polymorphic-belongs-to - Polymorphic BelongsTo', { book: Book, author: Author, 'async-book': AsyncBook, - person: DS.Model.extend() + person: DS.Model.extend(), }); store = env.store; }, afterEach() { run(store, 'destroy'); - } + }, }); - -test('using store.push with a null value for a payload in relationships sets the Models relationship to null - sync relationship', (assert) => { +test('using store.push with a null value for a payload in relationships sets the Models relationship to null - sync relationship', assert => { let payload = { data: { type: 'book', @@ -49,18 +48,18 @@ test('using store.push with a null value for a payload in relationships sets the author: { data: { type: 'author', - id: 1 - } - } - } + id: 1, + }, + }, + }, }, included: [ { id: 1, name: 'Amy Poehler', - type: 'author' - } - ] + type: 'author', + }, + ], }; let book = run(() => { @@ -77,17 +76,17 @@ test('using store.push with a null value for a payload in relationships sets the title: 'Yes, Please', relationships: { author: { - data: null - } - } - } + data: null, + }, + }, + }, }; run(() => store.push(payloadThatResetsBelongToRelationship)); assert.strictEqual(book.get('author'), null); }); -test('using store.push with a null value for a payload in relationships sets the Models relationship to null - async relationship', (assert) => { +test('using store.push with a null value for a payload in relationships sets the Models relationship to null - async relationship', assert => { let payload = { data: { type: 'async-book', @@ -97,18 +96,18 @@ test('using store.push with a null value for a payload in relationships sets the author: { data: { type: 'author', - id: 1 - } - } - } + id: 1, + }, + }, + }, }, included: [ { id: 1, name: 'Amy Poehler', - type: 'author' - } - ] + type: 'author', + }, + ], }; let book = run(() => { @@ -123,17 +122,20 @@ test('using store.push with a null value for a payload in relationships sets the title: 'Yes, Please', relationships: { author: { - data: null - } - } - } + data: null, + }, + }, + }, }; - return book.get('author').then(author => { - assert.equal(author.get('id'), 1); - run(() => store.push(payloadThatResetsBelongToRelationship)); - return book.get('author'); - }).then(author => { - assert.strictEqual(author, null); - }); + return book + .get('author') + .then(author => { + assert.equal(author.get('id'), 1); + run(() => store.push(payloadThatResetsBelongToRelationship)); + return book.get('author'); + }) + .then(author => { + assert.strictEqual(author, null); + }); }); diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index dad551c5fcb..ba276658cfd 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -11,19 +11,19 @@ let store, env, manager; const Person = DS.Model.extend({ name: DS.attr('string'), - cars: DS.hasMany('car', { async: false }) + cars: DS.hasMany('car', { async: false }), }); const Car = DS.Model.extend({ make: DS.attr('string'), model: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); module('integration/record_array_manager', { beforeEach() { env = setupStore({ - adapter: DS.RESTAdapter.extend() + adapter: DS.RESTAdapter.extend(), }); store = env.store; @@ -31,7 +31,7 @@ module('integration/record_array_manager', { env.registry.register('model:car', Car); env.registry.register('model:person', Person); - } + }, }); function tap(obj, methodName, callback) { @@ -52,7 +52,7 @@ function tap(obj, methodName, callback) { } test('destroying the store correctly cleans everything up', function(assert) { - let query = { }; + let query = {}; let person; run(() => { @@ -62,14 +62,14 @@ test('destroying the store correctly cleans everything up', function(assert) { id: '1', attributes: { make: 'BMC', - model: 'Mini Cooper' + model: 'Mini Cooper', }, relationships: { person: { - data: { type: 'person', id: '1' } - } - } - } + data: { type: 'person', id: '1' }, + }, + }, + }, }); }); @@ -79,16 +79,14 @@ test('destroying the store correctly cleans everything up', function(assert) { type: 'person', id: '1', attributes: { - name: 'Tom Dale' + name: 'Tom Dale', }, relationships: { cars: { - data: [ - { type: 'car', id: '1' } - ] - } - } - } + data: [{ type: 'car', id: '1' }], + }, + }, + }, }); person = store.peekRecord('person', 1); }); @@ -101,18 +99,30 @@ test('destroying the store correctly cleans everything up', function(assert) { assert.equal(allSummary.called.length, 0); assert.equal(adapterPopulatedSummary.called.length, 0); - assert.equal(internalPersonModel._recordArrays.size, 1, 'expected the person to be a member of 1 recordArrays'); + assert.equal( + internalPersonModel._recordArrays.size, + 1, + 'expected the person to be a member of 1 recordArrays' + ); assert.equal('person' in manager._liveRecordArrays, true); run(all, all.destroy); - assert.equal(internalPersonModel._recordArrays.size, 0, 'expected the person to be a member of 1 recordArrays'); + assert.equal( + internalPersonModel._recordArrays.size, + 0, + 'expected the person to be a member of 1 recordArrays' + ); assert.equal(allSummary.called.length, 1); assert.equal('person' in manager._liveRecordArrays, false); run(manager, manager.destroy); - assert.equal(internalPersonModel._recordArrays.size, 0, 'expected the person to be a member of no recordArrays'); + assert.equal( + internalPersonModel._recordArrays.size, + 0, + 'expected the person to be a member of no recordArrays' + ); assert.equal(allSummary.called.length, 1); assert.equal(adapterPopulatedSummary.called.length, 1); }); @@ -139,27 +149,24 @@ test('batch liveRecordArray changes', function(assert) { id: '1', attributes: { make: 'BMC', - model: 'Mini Cooper' - } + model: 'Mini Cooper', + }, }, { type: 'car', id: '2', attributes: { make: 'Jeep', - model: 'Wrangler' - } - } - ] + model: 'Wrangler', + }, + }, + ], }); }); assert.equal(arrayContentWillChangeCount, 1, 'expected ONE array change event'); - assert.deepEqual(cars.toArray(), [ - store.peekRecord('car', 1), - store.peekRecord('car', 2) - ]); + assert.deepEqual(cars.toArray(), [store.peekRecord('car', 1), store.peekRecord('car', 2)]); run(() => store.peekRecord('car', 1).set('model', 'Mini')); @@ -182,10 +189,10 @@ test('batch liveRecordArray changes', function(assert) { id: 2, // this ID is already present, array wont need to change attributes: { make: 'Tesla', - model: 'S' - } - } - ] + model: 'S', + }, + }, + ], }); }); @@ -199,10 +206,10 @@ test('batch liveRecordArray changes', function(assert) { id: 3, attributes: { make: 'Tesla', - model: 'S' - } - } - ] + model: 'S', + }, + }, + ], }); }); @@ -217,9 +224,9 @@ test('#GH-4041 store#query AdapterPopulatedRecordArrays are removed from their m id: '1', attributes: { make: 'Honda', - model: 'fit' - } - } + model: 'fit', + }, + }, }); }); @@ -248,7 +255,7 @@ test('createRecordArray with optional content', function(assert) { _recordArrays: new OrderedSet(), getRecord() { return record; - } + }, }; let content = A([internalModel]); let recordArray = manager.createRecordArray('foo', content); @@ -263,7 +270,7 @@ test('createRecordArray with optional content', function(assert) { }); test('liveRecordArrayFor always return the same array for a given type', function(assert) { - assert.equal(manager.liveRecordArrayFor('foo'), manager.liveRecordArrayFor('foo')) + assert.equal(manager.liveRecordArrayFor('foo'), manager.liveRecordArrayFor('foo')); }); test('liveRecordArrayFor create with content', function(assert) { @@ -287,9 +294,9 @@ test('liveRecordArrayFor create with content', function(assert) { id: '1', attributes: { make: 'BMC', - model: 'Mini Cooper' - } - } + model: 'Mini Cooper', + }, + }, }); }); @@ -327,26 +334,28 @@ test('[DEPRECATED FILTER SUPPORT until 3.5]', function(assert) { assert.equal(updatesWithoutLiveArrayChangeCount, 0, 'expected NO silent updates yet'); assert.equal(updatesSignaledCount, 0, 'expected NO signals yet'); - let [car1, car2] = run(() => store.push({ - data: [ - { - type: 'car', - id: '1', - attributes: { - make: 'BMC', - model: 'Mini Cooper' - } - }, - { - type: 'car', - id: '2', - attributes: { - make: 'Jeep', - model: 'Wrangler' - } - } - ] - })); + let [car1, car2] = run(() => + store.push({ + data: [ + { + type: 'car', + id: '1', + attributes: { + make: 'BMC', + model: 'Mini Cooper', + }, + }, + { + type: 'car', + id: '2', + attributes: { + make: 'Jeep', + model: 'Wrangler', + }, + }, + ], + }) + ); assert.equal(arrayContentWillChangeCount, 1, 'expected ONE array change event'); assert.equal(updatesWithoutLiveArrayChangeCount, 0, 'expected NO silent updates yet'); @@ -367,16 +376,18 @@ test('[DEPRECATED FILTER SUPPORT until 3.5]', function(assert) { updatesWithoutLiveArrayChangeCount = 0; updatesSignaledCount = 0; - run(() => store.push({ - data: { - type: 'car', - id: '2', // this ID is already present, array wont need to change - attributes: { - make: 'Tesla', - model: 'S' - } - } - })); + run(() => + store.push({ + data: { + type: 'car', + id: '2', // this ID is already present, array wont need to change + attributes: { + make: 'Tesla', + model: 'S', + }, + }, + }) + ); assert.equal(arrayContentWillChangeCount, 0, 'expected NO array change events'); assert.equal(updatesWithoutLiveArrayChangeCount, 1, 'expected ONE silent update'); @@ -386,16 +397,18 @@ test('[DEPRECATED FILTER SUPPORT until 3.5]', function(assert) { updatesWithoutLiveArrayChangeCount = 0; updatesSignaledCount = 0; - run(() => store.push({ - data: { - type: 'car', - id: '3', - attributes: { - make: 'Tesla', - model: 'S' - } - } - })); + run(() => + store.push({ + data: { + type: 'car', + id: '3', + attributes: { + make: 'Tesla', + model: 'S', + }, + }, + }) + ); assert.equal(arrayContentWillChangeCount, 1, 'expected ONE array change event'); assert.equal(updatesWithoutLiveArrayChangeCount, 0, 'expected ONE silent update'); diff --git a/tests/integration/record-array-test.js b/tests/integration/record-array-test.js index 02b73cc5aba..cb2bd5c2963 100644 --- a/tests/integration/record-array-test.js +++ b/tests/integration/record-array-test.js @@ -12,15 +12,15 @@ let results; const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); const Tag = DS.Model.extend({ - people: DS.hasMany('person', { async: false }) + people: DS.hasMany('person', { async: false }), }); const Tool = DS.Model.extend({ - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); module('unit/record_array - DS.RecordArray', { @@ -29,10 +29,10 @@ module('unit/record_array - DS.RecordArray', { data: [ { id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }, { id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } }, - { id: '3', type: 'person', attributes: { name: 'Scumbag Bryn' } } - ] + { id: '3', type: 'person', attributes: { name: 'Scumbag Bryn' } }, + ], }; - } + }, }); test('a record array is backed by records', function(assert) { @@ -43,8 +43,8 @@ test('a record array is backed by records', function(assert) { adapter: DS.Adapter.extend({ shouldBackgroundReloadRecord() { return false; - } - }) + }, + }), }); run(() => { @@ -54,31 +54,39 @@ test('a record array is backed by records', function(assert) { type: 'person', id: '1', attributes: { - name: 'Scumbag Dale' - } + name: 'Scumbag Dale', + }, }, { type: 'person', id: '2', attributes: { - name: 'Scumbag Katz' - } + name: 'Scumbag Katz', + }, }, { type: 'person', id: '3', attributes: { - name: 'Scumbag Bryn' - } - }] + name: 'Scumbag Bryn', + }, + }, + ], }); }); return run(() => { - return store.findByIds('person', [1,2,3]).then(records => { - for (let i=0, l = get(results, 'data.length'); i { + for (let i = 0, l = get(results, 'data.length'); i < l; i++) { + let { + id, + attributes: { name }, + } = results.data[i]; + assert.deepEqual( + records[i].getProperties('id', 'name'), + { id, name }, + 'a record array materializes objects on demand' + ); } }); }); @@ -86,7 +94,7 @@ test('a record array is backed by records', function(assert) { test('acts as a live query', function(assert) { let store = createStore({ - person: Person + person: Person, }); let recordArray = store.peekAll('person'); @@ -97,9 +105,9 @@ test('acts as a live query', function(assert) { type: 'person', id: '1', attributes: { - name: 'wycats' - } - } + name: 'wycats', + }, + }, }); }); @@ -111,18 +119,18 @@ test('acts as a live query', function(assert) { type: 'person', id: '2', attributes: { - name: 'brohuda' - } - } + name: 'brohuda', + }, + }, }); }); assert.equal(get(recordArray, 'lastObject.name'), 'brohuda'); }); -test('acts as a live query (normalized names)', function (assert) { +test('acts as a live query (normalized names)', function(assert) { let store = createStore({ person: Person, - Person: Person + Person: Person, }); let recordArray = store.peekAll('Person'); @@ -133,9 +141,9 @@ test('acts as a live query (normalized names)', function (assert) { type: 'Person', id: '1', attributes: { - name: 'John Churchill' - } - } + name: 'John Churchill', + }, + }, }); }); @@ -147,9 +155,9 @@ test('acts as a live query (normalized names)', function (assert) { type: 'Person', id: '2', attributes: { - name: 'Winston Churchill' - } - } + name: 'Winston Churchill', + }, + }, }); }); assert.deepEqual(recordArray.mapBy('name'), ['John Churchill', 'Winston Churchill']); @@ -159,7 +167,7 @@ test('stops updating when destroyed', function(assert) { assert.expect(3); let store = createStore({ - person: Person + person: Person, }); let recordArray = store.peekAll('person'); @@ -169,9 +177,9 @@ test('stops updating when destroyed', function(assert) { type: 'person', id: '1', attributes: { - name: 'wycats' - } - } + name: 'wycats', + }, + }, }); }); @@ -184,9 +192,9 @@ test('stops updating when destroyed', function(assert) { type: 'person', id: '2', attributes: { - name: 'brohuda' - } - } + name: 'brohuda', + }, + }, }); }); @@ -206,43 +214,48 @@ test('a loaded record is removed from a record array when it is deleted', functi }, shouldBackgroundReloadRecord() { return false; - } - }) + }, + }), }); let store = env.store; run(() => { store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Scumbag Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Scumbag Katz' - } - }, { - type: 'person', - id: '3', - attributes: { - name: 'Scumbag Bryn' - } - }, { - type: 'tag', - id: '1' - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz', + }, + }, + { + type: 'person', + id: '3', + attributes: { + name: 'Scumbag Bryn', + }, + }, + { + type: 'tag', + id: '1', + }, + ], }); }); return run(() => { return hash({ scumbag: store.findRecord('person', 1), - tag: store.findRecord('tag', 1) + tag: store.findRecord('tag', 1), }).then(records => { let scumbag = records.scumbag; let tag = records.tag; @@ -254,28 +267,40 @@ test('a loaded record is removed from a record array when it is deleted', functi let recordArray = tag.get('people'); assert.equal(get(recordArray, 'length'), 1, 'precond - record array has one item'); - assert.equal(get(recordArray.objectAt(0), 'name'), 'Scumbag Dale', "item at index 0 is record with id 1"); + assert.equal( + get(recordArray.objectAt(0), 'name'), + 'Scumbag Dale', + 'item at index 0 is record with id 1' + ); scumbag.deleteRecord(); - assert.equal(get(recordArray, 'length'), 1, 'record is still in the record array until it is saved'); + assert.equal( + get(recordArray, 'length'), + 1, + 'record is still in the record array until it is saved' + ); run(scumbag, 'save'); - assert.equal(get(recordArray, 'length'), 0, 'record is removed from the array when it is saved'); + assert.equal( + get(recordArray, 'length'), + 0, + 'record is removed from the array when it is saved' + ); }); }); }); -test('a loaded record is not removed from a record array when it is deleted even if the belongsTo side isn\'t defined', function(assert) { +test("a loaded record is not removed from a record array when it is deleted even if the belongsTo side isn't defined", function(assert) { let env = setupStore({ tag: Tag, - person: Person.reopen({tags: null }), + person: Person.reopen({ tags: null }), adapter: DS.Adapter.extend({ deleteRecord() { return Promise.resolve(); - } - }) + }, + }), }); let store = env.store; @@ -283,23 +308,24 @@ test('a loaded record is not removed from a record array when it is deleted even run(() => { store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Scumbag Tom' - } - }, { - type: 'tag', - id: '1', - relationships: { - people: { - data: [ - { type: 'person', id: '1' } - ] - } - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Tom', + }, + }, + { + type: 'tag', + id: '1', + relationships: { + people: { + data: [{ type: 'person', id: '1' }], + }, + }, + }, + ], }); scumbag = store.peekRecord('person', 1); tag = store.peekRecord('tag', 1); @@ -321,8 +347,8 @@ test("a loaded record is not removed from both the record array and from the bel adapter: DS.Adapter.extend({ deleteRecord() { return Promise.resolve(); - } - }) + }, + }), }); let store = env.store; @@ -330,31 +356,33 @@ test("a loaded record is not removed from both the record array and from the bel run(() => { store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Scumbag Tom' - } - }, { - type: 'tag', - id: '1', - relationships: { - people: { - data: [ - { type: 'person', id: '1' } - ] - } - } - }, { - type: 'tool', - id: '1', - relationships: { - person: { - data: { type: 'person', id: '1' } - } - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Tom', + }, + }, + { + type: 'tag', + id: '1', + relationships: { + people: { + data: [{ type: 'person', id: '1' }], + }, + }, + }, + { + type: 'tool', + id: '1', + relationships: { + person: { + data: { type: 'person', id: '1' }, + }, + }, + }, + ], }); scumbag = store.peekRecord('person', 1); tag = store.peekRecord('tag', 1); @@ -376,14 +404,18 @@ test("a loaded record is not removed from both the record array and from the bel test('a newly created record is removed from a record array when it is deleted', function(assert) { let store = createStore({ person: Person, - tag: Tag + tag: Tag, }); let recordArray = store.peekAll('person'); let scumbag = store.createRecord('person', { - name: 'Scumbag Dale' + name: 'Scumbag Dale', }); - assert.equal(get(recordArray, 'length'), 1, 'precond - record array already has the first created item'); + assert.equal( + get(recordArray, 'length'), + 1, + 'precond - record array already has the first created item' + ); store.createRecord('person', { name: 'p1' }); store.createRecord('person', { name: 'p2' }); @@ -399,73 +431,85 @@ test('a newly created record is removed from a record array when it is deleted', test("a record array returns undefined when asking for a member outside of its content Array's range", function(assert) { let store = createStore({ - person: Person + person: Person, }); run(() => { store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Scumbag Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Scumbag Katz' - } - }, { - type: 'person', - id: '3', - attributes: { - name: 'Scumbag Bryn' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz', + }, + }, + { + type: 'person', + id: '3', + attributes: { + name: 'Scumbag Bryn', + }, + }, + ], }); }); let recordArray = store.peekAll('person'); - assert.strictEqual(recordArray.objectAt(20), undefined, "objects outside of the range just return undefined"); + assert.strictEqual( + recordArray.objectAt(20), + undefined, + 'objects outside of the range just return undefined' + ); }); // This tests for a bug in the recordCache, where the records were being cached in the incorrect order. test('a record array should be able to be enumerated in any order', function(assert) { let store = createStore({ - person: Person + person: Person, }); run(() => { store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Scumbag Dale' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Scumbag Katz' - } - }, { - type: 'person', - id: '3', - attributes: { - name: 'Scumbag Bryn' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz', + }, + }, + { + type: 'person', + id: '3', + attributes: { + name: 'Scumbag Bryn', + }, + }, + ], }); }); let recordArray = store.peekAll('person'); - assert.equal(get(recordArray.objectAt(2), 'id'), 3, "should retrieve correct record at index 2"); - assert.equal(get(recordArray.objectAt(1), 'id'), 2, "should retrieve correct record at index 1"); - assert.equal(get(recordArray.objectAt(0), 'id'), 1, "should retrieve correct record at index 0"); + assert.equal(get(recordArray.objectAt(2), 'id'), 3, 'should retrieve correct record at index 2'); + assert.equal(get(recordArray.objectAt(1), 'id'), 2, 'should retrieve correct record at index 1'); + assert.equal(get(recordArray.objectAt(0), 'id'), 1, 'should retrieve correct record at index 0'); }); test("an AdapterPopulatedRecordArray knows if it's loaded or not", function(assert) { @@ -480,7 +524,7 @@ test("an AdapterPopulatedRecordArray knows if it's loaded or not", function(asse return run(() => { return store.query('person', { page: 1 }).then(people => { - assert.equal(get(people, 'isLoaded'), true, "The array is now loaded"); + assert.equal(get(people, 'isLoaded'), true, 'The array is now loaded'); }); }); }); diff --git a/tests/integration/record-arrays/adapter-populated-record-array-test.js b/tests/integration/record-arrays/adapter-populated-record-array-test.js index 809c3e92ed7..6d376136442 100644 --- a/tests/integration/record-arrays/adapter-populated-record-array-test.js +++ b/tests/integration/record-arrays/adapter-populated-record-array-test.js @@ -12,28 +12,29 @@ const Person = DS.Model.extend({ name: DS.attr('string'), toString() { return ``; - } + }, }); - const adapter = DS.Adapter.extend({ deleteRecord() { return Promise.resolve(); - } + }, }); -module('integration/record-arrays/adapter_populated_record_array - DS.AdapterPopulatedRecordArray', { - beforeEach() { - store = createStore({ - adapter: adapter, - person: Person - }); +module( + 'integration/record-arrays/adapter_populated_record_array - DS.AdapterPopulatedRecordArray', + { + beforeEach() { + store = createStore({ + adapter: adapter, + person: Person, + }); + }, } -}); +); test('when a record is deleted in an adapter populated record array, it should be removed', function(assert) { - let recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray('person', null); + let recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray('person', null); let payload = { data: [ @@ -41,40 +42,39 @@ test('when a record is deleted in an adapter populated record array, it should b type: 'person', id: '1', attributes: { - name: 'Scumbag Dale' - } + name: 'Scumbag Dale', + }, }, { type: 'person', id: '2', attributes: { - name: 'Scumbag Katz' - } + name: 'Scumbag Katz', + }, }, { type: 'person', id: '3', attributes: { - name: 'Scumbag Bryn' - } - } - ] + name: 'Scumbag Bryn', + }, + }, + ], }; run(() => { recordArray._setInternalModels(store._push(payload), payload); }); - assert.equal(recordArray.get('length'), 3, "expected recordArray to contain exactly 3 records"); + assert.equal(recordArray.get('length'), 3, 'expected recordArray to contain exactly 3 records'); run(() => recordArray.get('firstObject').destroyRecord()); - assert.equal(recordArray.get('length'), 2, "expected recordArray to contain exactly 2 records"); + assert.equal(recordArray.get('length'), 2, 'expected recordArray to contain exactly 2 records'); }); test('stores the metadata off the payload', function(assert) { - let recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray('person', null); + let recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray('person', null); let payload = { data: [ @@ -82,27 +82,27 @@ test('stores the metadata off the payload', function(assert) { type: 'person', id: '1', attributes: { - name: 'Scumbag Dale' - } + name: 'Scumbag Dale', + }, }, { type: 'person', id: '2', attributes: { - name: 'Scumbag Katz' - } + name: 'Scumbag Katz', + }, }, { type: 'person', id: '3', attributes: { - name: 'Scumbag Bryn' - } - } + name: 'Scumbag Bryn', + }, + }, ], meta: { - foo: 'bar' - } + foo: 'bar', + }, }; run(() => { @@ -113,8 +113,7 @@ test('stores the metadata off the payload', function(assert) { }); test('stores the links off the payload', function(assert) { - let recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray('person', null); + let recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray('person', null); let payload = { data: [ @@ -122,43 +121,50 @@ test('stores the links off the payload', function(assert) { type: 'person', id: '1', attributes: { - name: 'Scumbag Dale' - } + name: 'Scumbag Dale', + }, }, { type: 'person', id: '2', attributes: { - name: 'Scumbag Katz' - } + name: 'Scumbag Katz', + }, }, { type: 'person', id: '3', attributes: { - name: 'Scumbag Bryn' - } - } + name: 'Scumbag Bryn', + }, + }, ], links: { - first: '/foo?page=1' - } + first: '/foo?page=1', + }, }; run(() => { recordArray._setInternalModels(store._push(payload), payload); }); - assert.equal(recordArray.get('links.first'), '/foo?page=1', 'expected links.first to be "/foo?page=1" from payload'); + assert.equal( + recordArray.get('links.first'), + '/foo?page=1', + 'expected links.first to be "/foo?page=1" from payload' + ); }); test('recordArray.replace() throws error', function(assert) { - let recordArray = store.recordArrayManager - .createAdapterPopulatedRecordArray('person', null); - - assert.throws(() => { - recordArray.replace(); - }, Error('The result of a server query (on person) is immutable.'), 'throws error'); + let recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray('person', null); + + assert.throws( + () => { + recordArray.replace(); + }, + Error('The result of a server query (on person) is immutable.'), + 'throws error' + ); }); test('pass record array to adapter.query based on arity', function(assert) { @@ -168,8 +174,8 @@ test('pass record array to adapter.query based on arity', function(assert) { let payload = { data: [ { id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }, - { id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } } - ] + { id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } }, + ], }; env.adapter.query = function(store, type, query) { @@ -177,12 +183,12 @@ test('pass record array to adapter.query based on arity', function(assert) { return payload; }; - return store.query('person', { }).then(recordArray => { + return store.query('person', {}).then(recordArray => { env.adapter.query = function(store, type, query, _recordArray) { assert.equal(arguments.length, 5); return payload; }; - return store.query('person', { }); + return store.query('person', {}); }); }); @@ -193,13 +199,14 @@ test('pass record array to adapter.query based on arity', function(assert) { let payload = { data: [ { id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }, - { id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } } - ] + { id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } }, + ], }; - let actualQuery = { }; + let actualQuery = {}; - let superCreateAdapterPopulatedRecordArray = store.recordArrayManager.createAdapterPopulatedRecordArray; + let superCreateAdapterPopulatedRecordArray = + store.recordArrayManager.createAdapterPopulatedRecordArray; store.recordArrayManager.createStore = function(modelName, query, internalModels, _payload) { assert.equal(arguments.length === 4); @@ -241,29 +248,36 @@ test('loadRecord re-syncs internalModels recordArrays', function(assert) { let payload = { data: [ { id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }, - { id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } } - ] + { id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } }, + ], }; env.adapter.query = function(store, type, query, recordArray) { return payload; }; - return store.query('person', { }).then(recordArray => { - return recordArray.update().then(recordArray => { - assert.deepEqual(recordArray.getEach('name'), ['Scumbag Dale', 'Scumbag Katz'], 'expected query to contain specific records'); - - payload = { - data: [ - { id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }, - { id: '3', type: 'person', attributes: { name: 'Scumbag Penner' } } - ] - }; - - return recordArray.update(); - }).then(recordArray => { - assert.deepEqual(recordArray.getEach('name'), ['Scumbag Dale', 'Scumbag Penner']); - }); + return store.query('person', {}).then(recordArray => { + return recordArray + .update() + .then(recordArray => { + assert.deepEqual( + recordArray.getEach('name'), + ['Scumbag Dale', 'Scumbag Katz'], + 'expected query to contain specific records' + ); + + payload = { + data: [ + { id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }, + { id: '3', type: 'person', attributes: { name: 'Scumbag Penner' } }, + ], + }; + + return recordArray.update(); + }) + .then(recordArray => { + assert.deepEqual(recordArray.getEach('name'), ['Scumbag Dale', 'Scumbag Penner']); + }); }); }); @@ -291,14 +305,14 @@ test('when an adapter populated record gets updated the array contents are also findPromise = store.findAll('person'); // initialize adapter populated record array and assert initial state - queryPromise.then((_queryArr) => { + queryPromise.then(_queryArr => { queryArr = _queryArr; assert.equal(queryArr.get('length'), 0, 'No records for this query'); assert.equal(queryArr.get('isUpdating'), false, 'Record array isUpdating state updated'); }); // initialize a record collection array and assert initial state - findPromise.then((_findArr) => { + findPromise.then(_findArr => { findArray = _findArr; assert.equal(findArray.get('length'), 1, 'All records are included in collection array'); }); @@ -308,7 +322,11 @@ test('when an adapter populated record gets updated the array contents are also run(() => { array.push({ id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } }); queryArr.update().then(() => { - assert.equal(queryArr.get('length'), 1, 'The new record is returned and added in adapter populated array'); + assert.equal( + queryArr.get('length'), + 1, + 'The new record is returned and added in adapter populated array' + ); assert.equal(queryArr.get('isUpdating'), false, 'Record array isUpdating state updated'); assert.equal(findArray.get('length'), 2); }); diff --git a/tests/integration/record-arrays/peeked-records-test.js b/tests/integration/record-arrays/peeked-records-test.js index f8aa2431791..9ea46a67b98 100644 --- a/tests/integration/record-arrays/peeked-records-test.js +++ b/tests/integration/record-arrays/peeked-records-test.js @@ -11,39 +11,41 @@ const Person = DS.Model.extend({ name: DS.attr('string'), toString() { return ``; - } + }, }); module('integration/peeked-records', { beforeEach() { store = createStore({ - person: Person + person: Person, }); - } + }, }); test('repeated calls to peekAll in separate run-loops works as expected', function(assert) { let peekedRecordArray = run(() => store.peekAll('person')); let watcher = watchProperties(peekedRecordArray, ['length', '[]']); - run(() => store.push({ - data: [ - { - type: 'person', - id: '1', - attributes: { - name: 'John' - } - }, - { - type: 'person', - id: '2', - attributes: { - name: 'Joe' - } - } - ] - })); + run(() => + store.push({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'John', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Joe', + }, + }, + ], + }) + ); assert.watchedPropertyCounts( watcher, @@ -71,17 +73,17 @@ test('peekAll in the same run-loop as push works as expected', function(assert) type: 'person', id: '1', attributes: { - name: 'John' - } + name: 'John', + }, }, { type: 'person', id: '2', attributes: { - name: 'Joe' - } - } - ] + name: 'Joe', + }, + }, + ], }); store.peekAll('person'); }); @@ -105,7 +107,7 @@ test('newly created records notify the array as expected', function(assert) { let peekedRecordArray = run(() => store.peekAll('person')); let watcher = watchProperties(peekedRecordArray, ['length', '[]']); let aNewlyCreatedRecord = store.createRecord('person', { - name: 'James' + name: 'James', }); assert.watchedPropertyCounts( @@ -129,7 +131,7 @@ test('immediately peeking newly created records works as expected', function(ass let peekedRecordArray = run(() => store.peekAll('person')); let watcher = watchProperties(peekedRecordArray, ['length', '[]']); let aNewlyCreatedRecord = store.createRecord('person', { - name: 'James' + name: 'James', }); assert.watchedPropertyCounts( @@ -154,7 +156,7 @@ test('unloading newly created records notify the array as expected', function(as let peekedRecordArray = run(() => store.peekAll('person')); let watcher = watchProperties(peekedRecordArray, ['length', '[]']); let aNewlyCreatedRecord = store.createRecord('person', { - name: 'James' + name: 'James', }); assert.watchedPropertyCounts( @@ -178,7 +180,7 @@ test('immediately peeking after unloading newly created records works as expecte let peekedRecordArray = run(() => store.peekAll('person')); let watcher = watchProperties(peekedRecordArray, ['length', '[]']); let aNewlyCreatedRecord = store.createRecord('person', { - name: 'James' + name: 'James', }); assert.watchedPropertyCounts( @@ -210,17 +212,17 @@ test('unloadAll followed by peekAll in the same run-loop works as expected', fun type: 'person', id: '1', attributes: { - name: 'John' - } + name: 'John', + }, }, { type: 'person', id: '2', attributes: { - name: 'Joe' - } - } - ] + name: 'Joe', + }, + }, + ], }); }); @@ -241,7 +243,11 @@ test('unloadAll followed by peekAll in the same run-loop works as expected', fun 'RecordArray state after unloadAll has not changed yet' ); - assert.equal(get(peekedRecordArray, 'length'), 2, 'Array length is unchanged before the next peek'); + assert.equal( + get(peekedRecordArray, 'length'), + 2, + 'Array length is unchanged before the next peek' + ); store.peekAll('person'); @@ -270,17 +276,17 @@ test('push+materialize => unloadAll => push+materialize works as expected', func type: 'person', id: '1', attributes: { - name: 'John' - } + name: 'John', + }, }, { type: 'person', id: '2', attributes: { - name: 'Joe' - } - } - ] + name: 'Joe', + }, + }, + ], }); }); } @@ -327,17 +333,17 @@ test('push-without-materialize => unloadAll => push-without-materialize works as type: 'person', id: '1', attributes: { - name: 'John' - } + name: 'John', + }, }, { type: 'person', id: '2', attributes: { - name: 'Joe' - } - } - ] + name: 'Joe', + }, + }, + ], }); }); } @@ -374,4 +380,3 @@ test('push-without-materialize => unloadAll => push-without-materialize works as 'RecordArray state now has records again' ); }); - diff --git a/tests/integration/records/collection-save-test.js b/tests/integration/records/collection-save-test.js index cd715aa1083..c4f7b3bc900 100644 --- a/tests/integration/records/collection-save-test.js +++ b/tests/integration/records/collection-save-test.js @@ -8,10 +8,10 @@ import DS from 'ember-data'; let Post, env; -module("integration/records/collection_save - Save Collection of Records", { +module('integration/records/collection_save - Save Collection of Records', { beforeEach() { Post = DS.Model.extend({ - title: DS.attr('string') + title: DS.attr('string'), }); env = setupStore({ post: Post }); @@ -19,10 +19,10 @@ module("integration/records/collection_save - Save Collection of Records", { afterEach() { run(env.container, 'destroy'); - } + }, }); -test("Collection will resolve save on success", function(assert) { +test('Collection will resolve save on success', function(assert) { assert.expect(1); let id = 1; @@ -32,7 +32,7 @@ test("Collection will resolve save on success", function(assert) { let posts = env.store.peekAll('post'); env.adapter.createRecord = function(store, type, snapshot) { - return resolve({ data: { id: id++ , type: 'post' } }); + return resolve({ data: { id: id++, type: 'post' } }); }; return run(() => { @@ -42,7 +42,7 @@ test("Collection will resolve save on success", function(assert) { }); }); -test("Collection will reject save on error", function(assert) { +test('Collection will reject save on error', function(assert) { env.store.createRecord('post', { title: 'Hello' }); env.store.createRecord('post', { title: 'World' }); @@ -59,7 +59,7 @@ test("Collection will reject save on error", function(assert) { }); }); -test("Retry is allowed in a failure handler", function(assert) { +test('Retry is allowed in a failure handler', function(assert) { env.store.createRecord('post', { title: 'Hello' }); env.store.createRecord('post', { title: 'World' }); @@ -81,17 +81,18 @@ test("Retry is allowed in a failure handler", function(assert) { }; return run(() => { - return posts.save() + return posts + .save() .catch(() => posts.save()) .then(post => { // the ID here is '2' because the second post saves on the first attempt, // while the first post saves on the second attempt - assert.equal(posts.get('firstObject.id'), '2', "The post ID made it through"); + assert.equal(posts.get('firstObject.id'), '2', 'The post ID made it through'); }); }); }); -test("Collection will reject save on invalid", function(assert) { +test('Collection will reject save on invalid', function(assert) { assert.expect(1); env.store.createRecord('post', { title: 'Hello' }); diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index 44e2fcd8462..116b533e824 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -14,15 +14,17 @@ import DS from 'ember-data'; var attr = DS.attr; var Person, env; -module("integration/deletedRecord - Deleting Records", { +module('integration/deletedRecord - Deleting Records', { beforeEach() { Person = DS.Model.extend({ - name: attr('string') + name: attr('string'), }); - Person.toString = () => { return 'Person'; }; + Person.toString = () => { + return 'Person'; + }; env = setupStore({ - person: Person + person: Person, }); }, @@ -30,10 +32,10 @@ module("integration/deletedRecord - Deleting Records", { run(function() { env.container.destroy(); }); - } + }, }); -test("records should not be removed from record arrays just after deleting, but only after committing them", function(assert) { +test('records should not be removed from record arrays just after deleting, but only after committing them', function(assert) { var adam, dave; env.adapter.deleteRecord = function() { @@ -43,26 +45,28 @@ test("records should not be removed from record arrays just after deleting, but var all; run(function() { env.store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Dave Sunderland' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Dave Sunderland', + }, + }, + ], }); adam = env.store.peekRecord('person', 1); dave = env.store.peekRecord('person', 2); - all = env.store.peekAll('person'); + all = env.store.peekAll('person'); }); - // pre-condition assert.equal(all.get('length'), 2, 'pre-condition: 2 records in array'); @@ -79,9 +83,11 @@ test('deleting a record that is part of a hasMany removes it from the hasMany re let group; let person; const Group = DS.Model.extend({ - people: DS.hasMany('person', { inverse: null, async: false }) + people: DS.hasMany('person', { inverse: null, async: false }), }); - Group.toString = () => { return 'Group'; } + Group.toString = () => { + return 'Group'; + }; env.adapter.deleteRecord = function() { return EmberPromise.resolve(); @@ -96,29 +102,26 @@ test('deleting a record that is part of a hasMany removes it from the hasMany re id: '1', relationships: { people: { - data: [ - { type: 'person', id: '1' }, - { type: 'person', id: '2' } - ] - } - } + data: [{ type: 'person', id: '1' }, { type: 'person', id: '2' }], + }, + }, }, included: [ { type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' - } + name: 'Adam Sunderland', + }, }, { type: 'person', id: '2', attributes: { - name: 'Dave Sunderland' - } - } - ] + name: 'Dave Sunderland', + }, + }, + ], }); group = env.store.peekRecord('group', '1'); @@ -136,7 +139,7 @@ test('deleting a record that is part of a hasMany removes it from the hasMany re assert.equal(group.get('people.length'), 1, 'expected 1 related records after delete'); }); -test("records can be deleted during record array enumeration", function(assert) { +test('records can be deleted during record array enumeration', function(assert) { var adam, dave; env.adapter.deleteRecord = function() { @@ -145,19 +148,22 @@ test("records can be deleted during record array enumeration", function(assert) run(function() { env.store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Dave Sunderland' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Dave Sunderland', + }, + }, + ], }); adam = env.store.peekRecord('person', 1); dave = env.store.peekRecord('person', 2); @@ -177,20 +183,22 @@ test("records can be deleted during record array enumeration", function(assert) assert.equal(all.objectAt(0), null, "can't get any records"); }); -test("Deleting an invalid newly created record should remove it from the store", function(assert) { +test('Deleting an invalid newly created record should remove it from the store', function(assert) { var record; var store = env.store; env.adapter.createRecord = function() { - return EmberPromise.reject(new DS.InvalidError([ - { - title: 'Invalid Attribute', - detail: 'name is invalid', - source: { - pointer: '/data/attributes/name' - } - } - ])); + return EmberPromise.reject( + new DS.InvalidError([ + { + title: 'Invalid Attribute', + detail: 'name is invalid', + source: { + pointer: '/data/attributes/name', + }, + }, + ]) + ); }; run(function() { @@ -200,8 +208,11 @@ test("Deleting an invalid newly created record should remove it from the store", }); // Preconditions - assert.equal(get(record, 'currentState.stateName'), 'root.loaded.created.invalid', - 'records should start in the created.invalid state'); + assert.equal( + get(record, 'currentState.stateName'), + 'root.loaded.created.invalid', + 'records should start in the created.invalid state' + ); assert.equal(get(store.peekAll('person'), 'length'), 1, 'The new person should be in the store'); run(function() { @@ -209,28 +220,35 @@ test("Deleting an invalid newly created record should remove it from the store", }); assert.equal(get(record, 'currentState.stateName'), 'root.deleted.saved'); - assert.equal(get(store.peekAll('person'), 'length'), 0, 'The new person should be removed from the store'); + assert.equal( + get(store.peekAll('person'), 'length'), + 0, + 'The new person should be removed from the store' + ); }); - -test("Destroying an invalid newly created record should remove it from the store", function(assert) { +test('Destroying an invalid newly created record should remove it from the store', function(assert) { var record; var store = env.store; env.adapter.deleteRecord = function() { - assert.fail('The adapter\'s deletedRecord method should not be called when the record was created locally.'); + assert.fail( + "The adapter's deletedRecord method should not be called when the record was created locally." + ); }; env.adapter.createRecord = function() { - return EmberPromise.reject(new DS.InvalidError([ - { - title: 'Invalid Attribute', - detail: 'name is invalid', - source: { - pointer: '/data/attributes/name' - } - } - ])); + return EmberPromise.reject( + new DS.InvalidError([ + { + title: 'Invalid Attribute', + detail: 'name is invalid', + source: { + pointer: '/data/attributes/name', + }, + }, + ]) + ); }; run(function() { @@ -240,8 +258,11 @@ test("Destroying an invalid newly created record should remove it from the store }); // Preconditions - assert.equal(get(record, 'currentState.stateName'), 'root.loaded.created.invalid', - 'records should start in the created.invalid state'); + assert.equal( + get(record, 'currentState.stateName'), + 'root.loaded.created.invalid', + 'records should start in the created.invalid state' + ); assert.equal(get(store.peekAll('person'), 'length'), 1, 'The new person should be in the store'); run(function() { @@ -249,10 +270,14 @@ test("Destroying an invalid newly created record should remove it from the store }); assert.equal(get(record, 'currentState.stateName'), 'root.deleted.saved'); - assert.equal(get(store.peekAll('person'), 'length'), 0, 'The new person should be removed from the store'); + assert.equal( + get(store.peekAll('person'), 'length'), + 0, + 'The new person should be removed from the store' + ); }); -test("Will resolve destroy and save in same loop", function(assert) { +test('Will resolve destroy and save in same loop', function(assert) { let adam, dave; let promises; @@ -263,8 +288,8 @@ test("Will resolve destroy and save in same loop", function(assert) { return EmberPromise.resolve({ data: { id: 123, - type: 'person' - } + type: 'person', + }, }); }; @@ -272,10 +297,7 @@ test("Will resolve destroy and save in same loop", function(assert) { dave = env.store.createRecord('person', { name: 'Dave Sunderland' }); run(function() { - promises = [ - adam.destroyRecord(), - dave.save() - ]; + promises = [adam.destroyRecord(), dave.save()]; }); return all(promises); diff --git a/tests/integration/records/error-test.js b/tests/integration/records/error-test.js index 10ea3ba7289..851950316fc 100644 --- a/tests/integration/records/error-test.js +++ b/tests/integration/records/error-test.js @@ -18,11 +18,11 @@ module('integration/records/error', { beforeEach: function() { Person = DS.Model.extend({ firstName: attr('string'), - lastName: attr('string') + lastName: attr('string'), }); env = setupStore({ - person: Person + person: Person, }); store = env.store; @@ -32,7 +32,7 @@ module('integration/records/error', { run(function() { env.container.destroy(); }); - } + }, }); testInDebug('adding errors during root.loaded.created.invalid works', function(assert) { @@ -45,9 +45,9 @@ testInDebug('adding errors during root.loaded.created.invalid works', function(a id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' - } - } + lastName: 'Katz', + }, + }, }); return store.peekRecord('person', 'wat'); }); @@ -59,7 +59,7 @@ testInDebug('adding errors during root.loaded.created.invalid works', function(a assert.equal(person._internalModel.currentState.stateName, 'root.loaded.updated.uncommitted'); - updateErrors(() => person.get('errors').add('firstName', 'is invalid') , assert); + updateErrors(() => person.get('errors').add('firstName', 'is invalid'), assert); assert.equal(person._internalModel.currentState.stateName, 'root.loaded.updated.invalid'); @@ -67,18 +67,17 @@ testInDebug('adding errors during root.loaded.created.invalid works', function(a assert.deepEqual(person.get('errors').toArray(), [ { attribute: 'firstName', message: 'is invalid' }, - { attribute: 'lastName', message: 'is invalid' } + { attribute: 'lastName', message: 'is invalid' }, ]); }); - testInDebug('adding errors root.loaded.created.invalid works', function(assert) { assert.expect(5); let person = store.createRecord('person', { id: 'wat', firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }); run(() => { @@ -96,7 +95,7 @@ testInDebug('adding errors root.loaded.created.invalid works', function(assert) assert.deepEqual(person.get('errors').toArray(), [ { attribute: 'firstName', message: 'is invalid' }, - { attribute: 'lastName', message: 'is invalid' } + { attribute: 'lastName', message: 'is invalid' }, ]); }); @@ -105,7 +104,7 @@ testInDebug('adding errors root.loaded.created.invalid works add + remove + add' let person = store.createRecord('person', { id: 'wat', - firstName: 'Yehuda' + firstName: 'Yehuda', }); run(() => { @@ -125,16 +124,18 @@ testInDebug('adding errors root.loaded.created.invalid works add + remove + add' updateErrors(() => person.get('errors').add('firstName', 'is invalid'), assert); assert.deepEqual(person.get('errors').toArray(), [ - { attribute: 'firstName', message: 'is invalid' } + { attribute: 'firstName', message: 'is invalid' }, ]); }); -testInDebug('adding errors root.loaded.created.invalid works add + (remove, add)', function(assert) { +testInDebug('adding errors root.loaded.created.invalid works add + (remove, add)', function( + assert +) { assert.expect(6); let person = store.createRecord('person', { id: 'wat', - firstName: 'Yehuda' + firstName: 'Yehuda', }); run(() => { @@ -154,28 +155,29 @@ testInDebug('adding errors root.loaded.created.invalid works add + (remove, add) person.get('errors').add('firstName', 'is invalid'); }, assert); - assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); assert.deepEqual(person.get('errors').toArray(), [ - { attribute: 'firstName', message: 'is invalid' } + { attribute: 'firstName', message: 'is invalid' }, ]); }); test('using setProperties to clear errors', function(assert) { env.adapter.reopen({ createRecord() { - return RSVP.reject(new DS.InvalidError([ - { - detail: 'Must be unique', - source: { pointer: '/data/attributes/first-name' } - }, - { - detail: 'Must not be blank', - source: { pointer: '/data/attributes/last-name'} - } - ])); - } + return RSVP.reject( + new DS.InvalidError([ + { + detail: 'Must be unique', + source: { pointer: '/data/attributes/first-name' }, + }, + { + detail: 'Must not be blank', + source: { pointer: '/data/attributes/last-name' }, + }, + ]) + ); + }, }); return run(() => { @@ -189,8 +191,8 @@ test('using setProperties to clear errors', function(assert) { assert.ok(errors.has('lastName')); person.setProperties({ - firstName: "updated", - lastName: "updated" + firstName: 'updated', + lastName: 'updated', }); assert.equal(errors.get('length'), 0); diff --git a/tests/integration/records/load-test.js b/tests/integration/records/load-test.js index 605e92115c4..f7836cc2d33 100644 --- a/tests/integration/records/load-test.js +++ b/tests/integration/records/load-test.js @@ -10,10 +10,10 @@ const { hasMany } = DS; let Post, Comment, env; -module("integration/load - Loading Records", { +module('integration/load - Loading Records', { beforeEach() { Post = DS.Model.extend({ - comments: hasMany({ async: true }) + comments: hasMany({ async: true }), }); Comment = DS.Model.extend(); @@ -23,10 +23,10 @@ module("integration/load - Loading Records", { afterEach() { run(env.container, 'destroy'); - } + }, }); -test("When loading a record fails, the record is not left behind", function(assert) { +test('When loading a record fails, the record is not left behind', function(assert) { env.adapter.findRecord = function(store, type, id, snapshot) { return reject(); }; diff --git a/tests/integration/records/property-changes-test.js b/tests/integration/records/property-changes-test.js index 059434d14c8..c1a2ffbe1d6 100644 --- a/tests/integration/records/property-changes-test.js +++ b/tests/integration/records/property-changes-test.js @@ -13,11 +13,11 @@ module('integration/records/property-changes - Property changes', { beforeEach() { Person = DS.Model.extend({ firstName: attr('string'), - lastName: attr('string') + lastName: attr('string'), }); env = setupStore({ - person: Person + person: Person, }); store = env.store; }, @@ -26,7 +26,7 @@ module('integration/records/property-changes - Property changes', { run(function() { env.container.destroy(); }); - } + }, }); test('Calling push with partial records trigger observers for just those attributes that changed', function(assert) { @@ -40,9 +40,9 @@ test('Calling push with partial records trigger observers for just those attribu id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' - } - } + lastName: 'Katz', + }, + }, }); person = store.peekRecord('person', 'wat'); }); @@ -62,9 +62,9 @@ test('Calling push with partial records trigger observers for just those attribu id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz!' - } - } + lastName: 'Katz!', + }, + }, }); }); }); @@ -80,9 +80,9 @@ test('Calling push does not trigger observers for locally changed attributes wit id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' - } - } + lastName: 'Katz', + }, + }, }); person = store.peekRecord('person', 'wat'); person.set('lastName', 'Katz!'); @@ -103,9 +103,9 @@ test('Calling push does not trigger observers for locally changed attributes wit id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz!' - } - } + lastName: 'Katz!', + }, + }, }); }); }); @@ -125,9 +125,9 @@ test('Saving a record trigger observers for locally changed attributes with the id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' - } - } + lastName: 'Katz', + }, + }, }); person = store.peekRecord('person', 'wat'); person.set('lastName', 'Katz!'); @@ -157,9 +157,9 @@ test('store.push should not override a modified attribute', function(assert) { id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' - } - } + lastName: 'Katz', + }, + }, }); person = store.peekRecord('person', 'wat'); person.set('lastName', 'Katz!'); @@ -180,9 +180,9 @@ test('store.push should not override a modified attribute', function(assert) { id: 'wat', attributes: { firstName: 'Tom', - lastName: 'Dale' - } - } + lastName: 'Dale', + }, + }, }); }); }); diff --git a/tests/integration/records/relationship-changes-test.js b/tests/integration/records/relationship-changes-test.js index 8385abd3a81..b7c1d38d764 100644 --- a/tests/integration/records/relationship-changes-test.js +++ b/tests/integration/records/relationship-changes-test.js @@ -11,17 +11,17 @@ const { attr, belongsTo, hasMany, Model } = DS; let env, store; const Author = Model.extend({ - name: attr('string') + name: attr('string'), }); const Post = Model.extend({ - author: belongsTo() + author: belongsTo(), }); const Person = DS.Model.extend({ firstName: attr('string'), lastName: attr('string'), - siblings: hasMany('person') + siblings: hasMany('person'), }); const sibling1 = { @@ -29,13 +29,13 @@ const sibling1 = { id: '1', attributes: { firstName: 'Dogzn', - lastName: 'Katz' - } + lastName: 'Katz', + }, }; const sibling1Ref = { type: 'person', - id: '1' + id: '1', }; const sibling2 = { @@ -43,13 +43,13 @@ const sibling2 = { id: '2', attributes: { firstName: 'Katzn', - lastName: 'Dogz' - } + lastName: 'Dogz', + }, }; const sibling2Ref = { type: 'person', - id: '2' + id: '2', }; const sibling3 = { @@ -57,13 +57,13 @@ const sibling3 = { id: '3', attributes: { firstName: 'Snakezn', - lastName: 'Ladderz' - } + lastName: 'Ladderz', + }, }; const sibling3Ref = { type: 'person', - id: '3' + id: '3', }; const sibling4 = { @@ -71,13 +71,13 @@ const sibling4 = { id: '4', attributes: { firstName: 'Hamsterzn', - lastName: 'Gerbilz' - } + lastName: 'Gerbilz', + }, }; const sibling4Ref = { type: 'person', - id: '4' + id: '4', }; const sibling5 = { @@ -85,13 +85,13 @@ const sibling5 = { id: '5', attributes: { firstName: 'Donkeyzn', - lastName: 'Llamaz' - } + lastName: 'Llamaz', + }, }; const sibling5Ref = { type: 'person', - id: '5' + id: '5', }; module('integration/records/relationship-changes - Relationship changes', { @@ -99,7 +99,7 @@ module('integration/records/relationship-changes - Relationship changes', { env = setupStore({ person: Person, author: Author, - post: Post + post: Post, }); store = env.store; }, @@ -108,7 +108,7 @@ module('integration/records/relationship-changes - Relationship changes', { run(() => { env.container.destroy(); }); - } + }, }); test('Calling push with relationship triggers observers once if the relationship was empty and is added to', function(assert) { @@ -123,14 +123,14 @@ test('Calling push with relationship triggers observers once if the relationship id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }, relationships: { siblings: { - data: [] - } - } - } + data: [], + }, + }, + }, }); person = store.peekRecord('person', 'wat'); }); @@ -148,17 +148,14 @@ test('Calling push with relationship triggers observers once if the relationship data: { type: 'person', id: 'wat', - attributes: { - }, + attributes: {}, relationships: { siblings: { - data: [sibling1Ref] - } - } + data: [sibling1Ref], + }, + }, }, - included: [ - sibling1 - ] + included: [sibling1], }); }); @@ -172,7 +169,7 @@ test('Calling push with relationship recalculates computed alias property if the let Obj = EmberObject.extend({ person: null, - siblings: alias('person.siblings') + siblings: alias('person.siblings'), }); const obj = Obj.create(); @@ -184,14 +181,14 @@ test('Calling push with relationship recalculates computed alias property if the id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }, relationships: { siblings: { - data: [] - } - } - } + data: [], + }, + }, + }, }); set(obj, 'person', store.peekRecord('person', 'wat')); }); @@ -201,17 +198,14 @@ test('Calling push with relationship recalculates computed alias property if the data: { type: 'person', id: 'wat', - attributes: { - }, + attributes: {}, relationships: { siblings: { - data: [sibling1Ref] - } - } + data: [sibling1Ref], + }, + }, }, - included: [ - sibling1 - ] + included: [sibling1], }); }); @@ -227,7 +221,7 @@ test('Calling push with relationship recalculates computed alias property to fir let Obj = EmberObject.extend({ person: null, - firstSibling: alias('person.siblings.firstObject') + firstSibling: alias('person.siblings.firstObject'), }); const obj = Obj.create(); @@ -239,14 +233,14 @@ test('Calling push with relationship recalculates computed alias property to fir id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }, relationships: { siblings: { - data: [] - } - } - } + data: [], + }, + }, + }, }); set(obj, 'person', store.peekRecord('person', 'wat')); }); @@ -256,17 +250,14 @@ test('Calling push with relationship recalculates computed alias property to fir data: { type: 'person', id: 'wat', - attributes: { - }, + attributes: {}, relationships: { siblings: { - data: [sibling1Ref] - } - } + data: [sibling1Ref], + }, + }, }, - included: [ - sibling1 - ] + included: [sibling1], }); }); @@ -289,17 +280,15 @@ test('Calling push with relationship triggers observers once if the relationship id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }, relationships: { siblings: { - data: [sibling1Ref] - } - } + data: [sibling1Ref], + }, + }, }, - included: [ - sibling1 - ] + included: [sibling1], }); person = store.peekRecord('person', 'wat'); }); @@ -317,17 +306,14 @@ test('Calling push with relationship triggers observers once if the relationship data: { type: 'person', id: 'wat', - attributes: { - }, + attributes: {}, relationships: { siblings: { - data: [sibling1Ref, sibling2Ref] - } - } + data: [sibling1Ref, sibling2Ref], + }, + }, }, - included: [ - sibling2 - ] + included: [sibling2], }); }); @@ -348,17 +334,15 @@ test('Calling push with relationship triggers observers once if the relationship id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }, relationships: { siblings: { - data: [sibling1Ref] - } - } + data: [sibling1Ref], + }, + }, }, - included: [ - sibling1 - ] + included: [sibling1], }); person = store.peekRecord('person', 'wat'); }); @@ -371,21 +355,19 @@ test('Calling push with relationship triggers observers once if the relationship person.get('siblings'); }); - run(() => { store.push({ data: { type: 'person', id: 'wat', - attributes: { - }, + attributes: {}, relationships: { siblings: { - data: [] - } - } + data: [], + }, + }, }, - included: [] + included: [], }); }); @@ -406,19 +388,15 @@ test('Calling push with relationship triggers observers once if the relationship id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }, relationships: { siblings: { - data: [sibling1Ref, sibling2Ref] - } - } + data: [sibling1Ref, sibling2Ref], + }, + }, }, - included: [ - sibling1, - sibling2 - ] - + included: [sibling1, sibling2], }); person = store.peekRecord('person', 'wat'); }); @@ -431,21 +409,19 @@ test('Calling push with relationship triggers observers once if the relationship person.get('siblings'); }); - run(() => { store.push({ data: { type: 'person', id: 'wat', - attributes: { - }, + attributes: {}, relationships: { siblings: { - data: [sibling2Ref, sibling1Ref] - } - } + data: [sibling2Ref, sibling1Ref], + }, + }, }, - included: [] + included: [], }); }); @@ -466,18 +442,15 @@ test('Calling push with relationship does not trigger observers if the relations id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }, relationships: { siblings: { - data: [sibling1Ref] - } - } + data: [sibling1Ref], + }, + }, }, - included: [ - sibling1 - ] - + included: [sibling1], }); person = store.peekRecord('person', 'wat'); }); @@ -490,21 +463,19 @@ test('Calling push with relationship does not trigger observers if the relations }); }); - run(() => { store.push({ data: { type: 'person', id: 'wat', - attributes: { - }, + attributes: {}, relationships: { siblings: { - data: [sibling1Ref] - } - } + data: [sibling1Ref], + }, + }, }, - included: [] + included: [], }); }); @@ -530,7 +501,7 @@ test('Calling push with relationship triggers willChange and didChange with deta assert.equal(start, 1, 'didChange.start'); assert.equal(removed, 0, 'didChange.removed'); assert.equal(added, 1, 'didChange.added'); - } + }, }; run(() => { @@ -540,22 +511,18 @@ test('Calling push with relationship triggers willChange and didChange with deta id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }, relationships: { siblings: { - data: [sibling1Ref] - } - } + data: [sibling1Ref], + }, + }, }, - included: [ - sibling1 - ] - + included: [sibling1], }); }); - let person = store.peekRecord('person', 'wat'); let siblings = run(() => person.get('siblings')); @@ -566,17 +533,14 @@ test('Calling push with relationship triggers willChange and didChange with deta data: { type: 'person', id: 'wat', - attributes: { - }, + attributes: {}, relationships: { siblings: { - data: [sibling1Ref, sibling2Ref] - } - } + data: [sibling1Ref, sibling2Ref], + }, + }, }, - included: [ - sibling2 - ] + included: [sibling2], }); }); @@ -597,17 +561,15 @@ test('Calling push with relationship triggers willChange and didChange with deta id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }, relationships: { siblings: { - data: [sibling1Ref, sibling2Ref] - } - } + data: [sibling1Ref, sibling2Ref], + }, + }, }, - included: [ - sibling1, sibling2 - ] + included: [sibling1, sibling2], }); }); @@ -627,7 +589,7 @@ test('Calling push with relationship triggers willChange and didChange with deta assert.equal(start, 1); assert.equal(removed, 1); assert.equal(added, 0); - } + }, }; siblings.addArrayObserver(observer); @@ -637,15 +599,14 @@ test('Calling push with relationship triggers willChange and didChange with deta data: { type: 'person', id: 'wat', - attributes: { - }, + attributes: {}, relationships: { siblings: { - data: [sibling1Ref] - } - } + data: [sibling1Ref], + }, + }, }, - included: [] + included: [], }); }); @@ -666,17 +627,15 @@ test('Calling push with relationship triggers willChange and didChange with deta id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }, relationships: { siblings: { - data: [sibling2Ref] - } - } + data: [sibling2Ref], + }, + }, }, - included: [ - sibling2 - ] + included: [sibling2], }); }); let person = store.peekRecord('person', 'wat'); @@ -694,7 +653,7 @@ test('Calling push with relationship triggers willChange and didChange with deta assert.equal(start, 0); assert.equal(removed, 0); assert.equal(added, 1); - } + }, }; let siblings = run(() => person.get('siblings')); @@ -705,17 +664,14 @@ test('Calling push with relationship triggers willChange and didChange with deta data: { type: 'person', id: 'wat', - attributes: { - }, + attributes: {}, relationships: { siblings: { - data: [sibling1Ref, sibling2Ref] - } - } + data: [sibling1Ref, sibling2Ref], + }, + }, }, - included: [ - sibling2 - ] + included: [sibling2], }); }); @@ -736,19 +692,15 @@ test('Calling push with relationship triggers willChange and didChange with deta id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }, relationships: { siblings: { - data: [sibling1Ref, sibling3Ref] - } - } + data: [sibling1Ref, sibling3Ref], + }, + }, }, - included: [ - sibling1, - sibling3 - ] - + included: [sibling1, sibling3], }); }); let person = store.peekRecord('person', 'wat'); @@ -764,7 +716,7 @@ test('Calling push with relationship triggers willChange and didChange with deta assert.equal(start, 1); assert.equal(removed, 0); assert.equal(added, 1); - } + }, }; let siblings = run(() => person.get('siblings')); @@ -775,17 +727,14 @@ test('Calling push with relationship triggers willChange and didChange with deta data: { type: 'person', id: 'wat', - attributes: { - }, + attributes: {}, relationships: { siblings: { - data: [sibling1Ref, sibling2Ref, sibling3Ref] - } - } + data: [sibling1Ref, sibling2Ref, sibling3Ref], + }, + }, }, - included: [ - sibling2 - ] + included: [sibling2], }); }); @@ -806,19 +755,15 @@ test('Calling push with relationship triggers willChange and didChange with deta id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }, relationships: { siblings: { - data: [sibling1Ref, sibling2Ref, sibling3Ref] - } - } + data: [sibling1Ref, sibling2Ref, sibling3Ref], + }, + }, }, - included: [ - sibling1, - sibling2, - sibling3 - ] + included: [sibling1, sibling2, sibling3], }); }); @@ -836,10 +781,10 @@ test('Calling push with relationship triggers willChange and didChange with deta assert.equal(start, 1); assert.equal(removed, 1); assert.equal(added, 2); - } + }, }; - let siblings = run(() => person.get('siblings')); + let siblings = run(() => person.get('siblings')); siblings.addArrayObserver(observer); run(() => { @@ -847,18 +792,14 @@ test('Calling push with relationship triggers willChange and didChange with deta data: { type: 'person', id: 'wat', - attributes: { - }, + attributes: {}, relationships: { siblings: { - data: [sibling1Ref, sibling4Ref, sibling5Ref, sibling3Ref] - } - } + data: [sibling1Ref, sibling4Ref, sibling5Ref, sibling3Ref], + }, + }, }, - included: [ - sibling4, - sibling5 - ] + included: [sibling4, sibling5], }); }); @@ -880,14 +821,16 @@ test('Calling push with updated belongsTo relationship trigger observer', functi id: '1', relationships: { author: { - data: { type: 'author', id: '2' } - } - } + data: { type: 'author', id: '2' }, + }, + }, }, - included: [{ - id: 2, - type: 'author' - }] + included: [ + { + id: 2, + type: 'author', + }, + ], }); post.get('author'); @@ -902,10 +845,10 @@ test('Calling push with updated belongsTo relationship trigger observer', functi id: '1', relationships: { author: { - data: { type: 'author', id: '3' } - } - } - } + data: { type: 'author', id: '3' }, + }, + }, + }, }); }); @@ -924,10 +867,10 @@ test('Calling push with same belongsTo relationship does not trigger observer', id: '1', relationships: { author: { - data: { type: 'author', id: '2' } - } - } - } + data: { type: 'author', id: '2' }, + }, + }, + }, }); post.addObserver('author', function() { @@ -940,10 +883,10 @@ test('Calling push with same belongsTo relationship does not trigger observer', id: '1', relationships: { author: { - data: { type: 'author', id: '2' } - } - } - } + data: { type: 'author', id: '2' }, + }, + }, + }, }); }); diff --git a/tests/integration/records/reload-test.js b/tests/integration/records/reload-test.js index 694d801ecb5..e764cd4cb56 100644 --- a/tests/integration/records/reload-test.js +++ b/tests/integration/records/reload-test.js @@ -10,13 +10,13 @@ import DS from 'ember-data'; var attr = DS.attr; var Person, env; -module("integration/reload - Reloading Records", { +module('integration/reload - Reloading Records', { beforeEach() { Person = DS.Model.extend({ updatedAt: attr('string'), name: attr('string'), firstName: attr('string'), - lastName: attr('string') + lastName: attr('string'), }); env = setupStore({ person: Person }); @@ -24,7 +24,7 @@ module("integration/reload - Reloading Records", { afterEach() { run(env.container, 'destroy'); - } + }, }); test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function(assert) { @@ -33,26 +33,33 @@ test("When a single record is requested, the adapter's find method should be cal env.adapter.findRecord = function(store, type, id, snapshot) { if (count === 0) { count++; - return resolve({ data: { id: id, type: 'person', attributes: { name: "Tom Dale" } } }); + return resolve({ data: { id: id, type: 'person', attributes: { name: 'Tom Dale' } } }); } else if (count === 1) { count++; - return resolve({ data: { id: id, type: 'person', attributes: { name: "Braaaahm Dale" } } }); + return resolve({ data: { id: id, type: 'person', attributes: { name: 'Braaaahm Dale' } } }); } else { - assert.ok(false, "Should not get here"); + assert.ok(false, 'Should not get here'); } }; run(function() { - env.store.findRecord('person', 1).then(function(person) { - assert.equal(get(person, 'name'), "Tom Dale", "The person is loaded with the right name"); - assert.equal(get(person, 'isLoaded'), true, "The person is now loaded"); - var promise = person.reload(); - assert.equal(get(person, 'isReloading'), true, "The person is now reloading"); - return promise; - }).then(function(person) { - assert.equal(get(person, 'isReloading'), false, "The person is no longer reloading"); - assert.equal(get(person, 'name'), "Braaaahm Dale", "The person is now updated with the right name"); - }); + env.store + .findRecord('person', 1) + .then(function(person) { + assert.equal(get(person, 'name'), 'Tom Dale', 'The person is loaded with the right name'); + assert.equal(get(person, 'isLoaded'), true, 'The person is now loaded'); + var promise = person.reload(); + assert.equal(get(person, 'isReloading'), true, 'The person is now reloading'); + return promise; + }) + .then(function(person) { + assert.equal(get(person, 'isReloading'), false, 'The person is no longer reloading'); + assert.equal( + get(person, 'name'), + 'Braaaahm Dale', + 'The person is now updated with the right name' + ); + }); }); }); @@ -60,41 +67,52 @@ test("When a single record is requested, the adapter's find method should be cal let count = 0; let reloadOptions = { adapterOptions: { - makeSnazzy: true - } + makeSnazzy: true, + }, }; env.adapter.findRecord = function(store, type, id, snapshot) { if (count === 0) { count++; - return resolve({ data: { id: id, type: 'person', attributes: { name: "Tom Dale" } } }); + return resolve({ data: { id: id, type: 'person', attributes: { name: 'Tom Dale' } } }); } else if (count === 1) { - assert.equal(snapshot.adapterOptions, reloadOptions.adapterOptions, 'We passed adapterOptions via reload'); + assert.equal( + snapshot.adapterOptions, + reloadOptions.adapterOptions, + 'We passed adapterOptions via reload' + ); count++; - return resolve({ data: { id: id, type: 'person', attributes: { name: "Braaaahm Dale" } } }); + return resolve({ data: { id: id, type: 'person', attributes: { name: 'Braaaahm Dale' } } }); } else { - assert.ok(false, "Should not get here"); + assert.ok(false, 'Should not get here'); } }; run(function() { - env.store.findRecord('person', 1).then(function(person) { - assert.equal(get(person, 'name'), "Tom Dale", "The person is loaded with the right name"); - assert.equal(get(person, 'isLoaded'), true, "The person is now loaded"); - - let promise = person.reload(reloadOptions); - - assert.equal(get(person, 'isReloading'), true, "The person is now reloading"); - - return promise; - }).then(function(person) { - assert.equal(get(person, 'isReloading'), false, "The person is no longer reloading"); - assert.equal(get(person, 'name'), "Braaaahm Dale", "The person is now updated with the right name"); - }); + env.store + .findRecord('person', 1) + .then(function(person) { + assert.equal(get(person, 'name'), 'Tom Dale', 'The person is loaded with the right name'); + assert.equal(get(person, 'isLoaded'), true, 'The person is now loaded'); + + let promise = person.reload(reloadOptions); + + assert.equal(get(person, 'isReloading'), true, 'The person is now reloading'); + + return promise; + }) + .then(function(person) { + assert.equal(get(person, 'isReloading'), false, 'The person is no longer reloading'); + assert.equal( + get(person, 'name'), + 'Braaaahm Dale', + 'The person is now updated with the right name' + ); + }); }); }); -test("When a record is reloaded and fails, it can try again", function(assert) { +test('When a record is reloaded and fails, it can try again', function(assert) { var tom; run(function() { env.store.push({ @@ -102,46 +120,49 @@ test("When a record is reloaded and fails, it can try again", function(assert) { type: 'person', id: '1', attributes: { - name: 'Tom Dale' - } - } + name: 'Tom Dale', + }, + }, }); tom = env.store.peekRecord('person', 1); }); var count = 0; env.adapter.findRecord = function(store, type, id, snapshot) { - assert.equal(tom.get('isReloading'), true, "Tom is reloading"); + assert.equal(tom.get('isReloading'), true, 'Tom is reloading'); if (count++ === 0) { return reject(); } else { - return resolve({ data: { id: 1, type: 'person', attributes: { name: "Thomas Dale" } } }); + return resolve({ data: { id: 1, type: 'person', attributes: { name: 'Thomas Dale' } } }); } }; run(function() { - tom.reload().then(null, function() { - assert.equal(tom.get('isError'), true, "Tom is now errored"); - assert.equal(tom.get('isReloading'), false, "Tom is no longer reloading"); - return tom.reload(); - }).then(function(person) { - assert.equal(person, tom, "The resolved value is the record"); - assert.equal(tom.get('isError'), false, "Tom is no longer errored"); - assert.equal(tom.get('isReloading'), false, "Tom is no longer reloading"); - assert.equal(tom.get('name'), "Thomas Dale", "the updates apply"); - }); + tom + .reload() + .then(null, function() { + assert.equal(tom.get('isError'), true, 'Tom is now errored'); + assert.equal(tom.get('isReloading'), false, 'Tom is no longer reloading'); + return tom.reload(); + }) + .then(function(person) { + assert.equal(person, tom, 'The resolved value is the record'); + assert.equal(tom.get('isError'), false, 'Tom is no longer errored'); + assert.equal(tom.get('isReloading'), false, 'Tom is no longer reloading'); + assert.equal(tom.get('name'), 'Thomas Dale', 'the updates apply'); + }); }); }); -test("When a record is loaded a second time, isLoaded stays true", function(assert) { +test('When a record is loaded a second time, isLoaded stays true', function(assert) { let record = { data: { type: 'person', id: '1', attributes: { - name: 'Tom Dale' - } - } + name: 'Tom Dale', + }, + }, }; env.adapter.findRecord = function(store, type, id, snapshot) { return record; @@ -152,13 +173,13 @@ test("When a record is loaded a second time, isLoaded stays true", function(asse run(function() { env.store.findRecord('person', 1).then(function(person) { - assert.equal(get(person, 'isLoaded'), true, "The person is loaded"); + assert.equal(get(person, 'isLoaded'), true, 'The person is loaded'); person.addObserver('isLoaded', isLoadedDidChange); // Reload the record env.store.push(record); - assert.equal(get(person, 'isLoaded'), true, "The person is still loaded after load"); + assert.equal(get(person, 'isLoaded'), true, 'The person is still loaded after load'); person.removeObserver('isLoaded', isLoadedDidChange); }); @@ -166,21 +187,27 @@ test("When a record is loaded a second time, isLoaded stays true", function(asse function isLoadedDidChange() { // This shouldn't be hit - assert.equal(get(this, 'isLoaded'), true, "The person is still loaded after change"); + assert.equal(get(this, 'isLoaded'), true, 'The person is still loaded after change'); } }); -test("When a record is reloaded, its async hasMany relationships still work", function(assert) { - env.registry.register('model:person', DS.Model.extend({ - name: DS.attr(), - tags: DS.hasMany('tag', { async: true }) - })); +test('When a record is reloaded, its async hasMany relationships still work', function(assert) { + env.registry.register( + 'model:person', + DS.Model.extend({ + name: DS.attr(), + tags: DS.hasMany('tag', { async: true }), + }) + ); - env.registry.register('model:tag', DS.Model.extend({ - name: DS.attr() - })); + env.registry.register( + 'model:tag', + DS.Model.extend({ + name: DS.attr(), + }) + ); - var tags = { 1: "hipster", 2: "hair" }; + var tags = { 1: 'hipster', 2: 'hair' }; env.adapter.findRecord = function(store, type, id, snapshot) { switch (type.modelName) { @@ -189,16 +216,13 @@ test("When a record is reloaded, its async hasMany relationships still work", fu data: { id: 1, type: 'person', - attributes: { name: "Tom" }, + attributes: { name: 'Tom' }, relationships: { tags: { - data: [ - { id: 1, type: 'tag' }, - { id: 2, type: 'tag' } - ] - } - } - } + data: [{ id: 1, type: 'tag' }, { id: 2, type: 'tag' }], + }, + }, + }, }); case 'tag': return resolve({ data: { id: id, type: 'tag', attributes: { name: tags[id] } } }); @@ -208,21 +232,26 @@ test("When a record is reloaded, its async hasMany relationships still work", fu var tom; run(function() { - env.store.findRecord('person', 1).then(function(person) { - tom = person; - assert.equal(person.get('name'), "Tom", "precond"); - - return person.get('tags'); - }).then(function(tags) { - assert.deepEqual(tags.mapBy('name'), ['hipster', 'hair']); - - return tom.reload(); - }).then(function(person) { - assert.equal(person.get('name'), "Tom", "precond"); - - return person.get('tags'); - }).then(function(tags) { - assert.deepEqual(tags.mapBy('name'), ['hipster', 'hair'], "The tags are still there"); - }); + env.store + .findRecord('person', 1) + .then(function(person) { + tom = person; + assert.equal(person.get('name'), 'Tom', 'precond'); + + return person.get('tags'); + }) + .then(function(tags) { + assert.deepEqual(tags.mapBy('name'), ['hipster', 'hair']); + + return tom.reload(); + }) + .then(function(person) { + assert.equal(person.get('name'), 'Tom', 'precond'); + + return person.get('tags'); + }) + .then(function(tags) { + assert.deepEqual(tags.mapBy('name'), ['hipster', 'hair'], 'The tags are still there'); + }); }); }); diff --git a/tests/integration/records/rematerialize-test.js b/tests/integration/records/rematerialize-test.js index 6375ab15f3e..c55e59c4c94 100644 --- a/tests/integration/records/rematerialize-test.js +++ b/tests/integration/records/rematerialize-test.js @@ -13,36 +13,50 @@ let env; let Person = Model.extend({ name: attr('string'), cars: hasMany('car', { async: false }), - boats: hasMany('boat', { async: true }) + boats: hasMany('boat', { async: true }), +}); +Person.reopenClass({ + toString() { + return 'Person'; + }, }); -Person.reopenClass({ toString() { return 'Person'; } }); let Group = Model.extend({ - people: hasMany('person', { async: false }) + people: hasMany('person', { async: false }), +}); +Group.reopenClass({ + toString() { + return 'Group'; + }, }); -Group.reopenClass({ toString() { return 'Group'; } }); let Car = Model.extend({ make: attr('string'), model: attr('string'), - person: belongsTo('person', { async: false }) + person: belongsTo('person', { async: false }), +}); +Car.reopenClass({ + toString() { + return 'Car'; + }, }); -Car.reopenClass({ toString() { return 'Car'; } }); let Boat = Model.extend({ name: attr('string'), - person: belongsTo('person', { async: false }) + person: belongsTo('person', { async: false }), }); -Boat.toString = function() { return 'Boat'; }; +Boat.toString = function() { + return 'Boat'; +}; -module("integration/unload - Rematerializing Unloaded Records", { +module('integration/unload - Rematerializing Unloaded Records', { beforeEach() { env = setupStore({ adapter: DS.JSONAPIAdapter, person: Person, car: Car, group: Group, - boat: Boat + boat: Boat, }); }, @@ -50,10 +64,10 @@ module("integration/unload - Rematerializing Unloaded Records", { run(function() { env.container.destroy(); }); - } + }, }); -test("a sync belongs to relationship to an unloaded record can restore that record", function(assert) { +test('a sync belongs to relationship to an unloaded record can restore that record', function(assert) { // disable background reloading so we do not re-create the relationship. env.adapter.shouldBackgroundReloadRecord = () => false; @@ -63,16 +77,14 @@ test("a sync belongs to relationship to an unloaded record can restore that reco type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' + name: 'Adam Sunderland', }, relationships: { cars: { - data: [ - { type: 'car', id: '1' } - ] - } - } - } + data: [{ type: 'car', id: '1' }], + }, + }, + }, }); return env.store.peekRecord('person', 1); @@ -84,15 +96,15 @@ test("a sync belongs to relationship to an unloaded record can restore that reco type: 'car', id: '1', attributes: { - make: "Lotus", - model: "Exige" + make: 'Lotus', + model: 'Exige', }, relationships: { person: { - data: { type: 'person', id: '1' } - } - } - } + data: { type: 'person', id: '1' }, + }, + }, + }, }); return env.store.peekRecord('car', 1); @@ -102,12 +114,20 @@ test("a sync belongs to relationship to an unloaded record can restore that reco assert.equal(person.get('cars.length'), 1, 'The inital length of cars is correct'); assert.equal(env.store.hasRecordForId('person', 1), true, 'The person is in the store'); - assert.equal(env.store._internalModelsFor('person').has(1), true, 'The person internalModel is loaded'); + assert.equal( + env.store._internalModelsFor('person').has(1), + true, + 'The person internalModel is loaded' + ); run(() => person.unloadRecord()); assert.equal(env.store.hasRecordForId('person', 1), false, 'The person is unloaded'); - assert.equal(env.store._internalModelsFor('person').has(1), false, 'The person internalModel is freed'); + assert.equal( + env.store._internalModelsFor('person').has(1), + false, + 'The person internalModel is freed' + ); run(() => { env.store.push({ @@ -115,16 +135,14 @@ test("a sync belongs to relationship to an unloaded record can restore that reco type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' + name: 'Adam Sunderland', }, relationships: { cars: { - data: [ - { type: 'car', id: '1' } - ] - } - } - } + data: [{ type: 'car', id: '1' }], + }, + }, + }, }); }); @@ -135,7 +153,7 @@ test("a sync belongs to relationship to an unloaded record can restore that reco assert.notEqual(rematerializedPerson, adam, 'the person is rematerialized, not recycled'); }); -test("an async has many relationship to an unloaded record can restore that record", function(assert) { +test('an async has many relationship to an unloaded record can restore that record', function(assert) { assert.expect(16); // disable background reloading so we do not re-create the relationship. @@ -145,26 +163,26 @@ test("an async has many relationship to an unloaded record can restore that reco type: 'boat', id: '1', attributes: { - name: "Boaty McBoatface" + name: 'Boaty McBoatface', }, relationships: { person: { - data: { type: 'person', id: '1' } - } - } + data: { type: 'person', id: '1' }, + }, + }, }; const BOAT_TWO = { type: 'boat', id: '2', attributes: { - name: 'Some other boat' + name: 'Some other boat', }, relationships: { person: { - data: { type: 'person', id: '1' } - } - } + data: { type: 'person', id: '1' }, + }, + }, }; let adapterCalls = 0; @@ -181,7 +199,7 @@ test("an async has many relationship to an unloaded record can restore that reco } return { - data + data, }; }; @@ -191,26 +209,20 @@ test("an async has many relationship to an unloaded record can restore that reco type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' + name: 'Adam Sunderland', }, relationships: { boats: { - data: [ - { type: 'boat', id: '2' }, - { type: 'boat', id: '1' } - ] - } - } - } + data: [{ type: 'boat', id: '2' }, { type: 'boat', id: '1' }], + }, + }, + }, }); }); run(() => { env.store.push({ - data: [ - deepCopy(BOAT_ONE), - deepCopy(BOAT_TWO) - ] + data: [deepCopy(BOAT_ONE), deepCopy(BOAT_TWO)], }); }); @@ -219,9 +231,17 @@ test("an async has many relationship to an unloaded record can restore that reco // assert our initial cache state assert.equal(env.store.hasRecordForId('person', '1'), true, 'The person is in the store'); - assert.equal(env.store._internalModelsFor('person').has('1'), true, 'The person internalModel is loaded'); + assert.equal( + env.store._internalModelsFor('person').has('1'), + true, + 'The person internalModel is loaded' + ); assert.equal(env.store.hasRecordForId('boat', '1'), true, 'The boat is in the store'); - assert.equal(env.store._internalModelsFor('boat').has('1'), true, 'The boat internalModel is loaded'); + assert.equal( + env.store._internalModelsFor('boat').has('1'), + true, + 'The boat internalModel is loaded' + ); let boats = run(() => adam.get('boats')); assert.equal(boats.get('length'), 2, 'Before unloading boats.length is correct'); @@ -231,7 +251,11 @@ test("an async has many relationship to an unloaded record can restore that reco // assert our new cache state assert.equal(env.store.hasRecordForId('boat', '1'), false, 'The boat is unloaded'); - assert.equal(env.store._internalModelsFor('boat').has('1'), true, 'The boat internalModel is retained'); + assert.equal( + env.store._internalModelsFor('boat').has('1'), + true, + 'The boat internalModel is retained' + ); // cause a rematerialization, this should also cause us to fetch boat '1' again boats = run(() => adam.get('boats')); @@ -240,9 +264,17 @@ test("an async has many relationship to an unloaded record can restore that reco assert.ok(!!rematerializedBoaty, 'We have a boat!'); assert.equal(adam.get('boats.length'), 2, 'boats.length correct after rematerialization'); assert.equal(rematerializedBoaty.get('id'), '1', 'Rematerialized boat has the right id'); - assert.equal(rematerializedBoaty.get('name'), 'Boaty McBoatface', 'Rematerialized boat has the right name'); + assert.equal( + rematerializedBoaty.get('name'), + 'Boaty McBoatface', + 'Rematerialized boat has the right name' + ); assert.ok(rematerializedBoaty !== boaty, 'the boat is rematerialized, not recycled'); assert.equal(env.store.hasRecordForId('boat', '1'), true, 'The boat is loaded'); - assert.equal(env.store._internalModelsFor('boat').has('1'), true, 'The boat internalModel is retained'); + assert.equal( + env.store._internalModelsFor('boat').has('1'), + true, + 'The boat internalModel is retained' + ); }); diff --git a/tests/integration/records/save-test.js b/tests/integration/records/save-test.js index 018d3fd2066..86abd1f34fa 100644 --- a/tests/integration/records/save-test.js +++ b/tests/integration/records/save-test.js @@ -8,10 +8,10 @@ import DS from 'ember-data'; var Post, env; -module("integration/records/save - Save Record", { +module('integration/records/save - Save Record', { beforeEach() { Post = DS.Model.extend({ - title: DS.attr('string') + title: DS.attr('string'), }); env = setupStore({ post: Post }); @@ -19,10 +19,10 @@ module("integration/records/save - Save Record", { afterEach() { run(env.container, 'destroy'); - } + }, }); -test("Will resolve save on success", function(assert) { +test('Will resolve save on success', function(assert) { assert.expect(4); let post = env.store.createRecord('post', { title: 'toto' }); @@ -41,12 +41,12 @@ test("Will resolve save on success", function(assert) { saved.then(function(model) { assert.ok(true, 'save operation was resolved'); assert.equal(saved.get('id'), 123); - assert.equal(model, post, "resolves with the model"); + assert.equal(model, post, 'resolves with the model'); }); }); }); -test("Will reject save on error", function(assert) { +test('Will reject save on error', function(assert) { let post = env.store.createRecord('post', { title: 'toto' }); env.adapter.createRecord = function(store, type, snapshot) { @@ -56,13 +56,16 @@ test("Will reject save on error", function(assert) { }; run(function() { - post.save().then(function() {}, function() { - assert.ok(true, 'save operation was rejected'); - }); + post.save().then( + function() {}, + function() { + assert.ok(true, 'save operation was rejected'); + } + ); }); }); -test("Retry is allowed in a failure handler", function(assert) { +test('Retry is allowed in a failure handler', function(assert) { let post = env.store.createRecord('post', { title: 'toto' }); var count = 0; @@ -78,15 +81,21 @@ test("Retry is allowed in a failure handler", function(assert) { }; run(function() { - post.save().then(function() {}, function() { - return post.save(); - }).then(function(post) { - assert.equal(post.get('id'), '123', "The post ID made it through"); - }); + post + .save() + .then( + function() {}, + function() { + return post.save(); + } + ) + .then(function(post) { + assert.equal(post.get('id'), '123', 'The post ID made it through'); + }); }); }); -test("Repeated failed saves keeps the record in uncommited state", function(assert) { +test('Repeated failed saves keeps the record in uncommited state', function(assert) { assert.expect(4); let post = env.store.createRecord('post', { title: 'toto' }); @@ -107,7 +116,7 @@ test("Repeated failed saves keeps the record in uncommited state", function(asse }); }); -test("Repeated failed saves with invalid error marks the record as invalid", function(assert) { +test('Repeated failed saves with invalid error marks the record as invalid', function(assert) { assert.expect(2); let post = env.store.createRecord('post', { title: 'toto' }); @@ -115,8 +124,8 @@ test("Repeated failed saves with invalid error marks the record as invalid", fun var error = new DS.InvalidError([ { detail: 'is invalid', - source: { pointer: 'data/attributes/title' } - } + source: { pointer: 'data/attributes/title' }, + }, ]); return reject(error); @@ -133,7 +142,7 @@ test("Repeated failed saves with invalid error marks the record as invalid", fun }); }); -test("Repeated failed saves with invalid error without payload marks the record as invalid", function(assert) { +test('Repeated failed saves with invalid error without payload marks the record as invalid', function(assert) { assert.expect(2); let post = env.store.createRecord('post', { title: 'toto' }); @@ -154,7 +163,7 @@ test("Repeated failed saves with invalid error without payload marks the record }); }); -test("Will reject save on invalid", function(assert) { +test('Will reject save on invalid', function(assert) { assert.expect(1); let post = env.store.createRecord('post', { title: 'toto' }); @@ -165,8 +174,11 @@ test("Will reject save on invalid", function(assert) { }; run(function() { - post.save().then(function() {}, function() { - assert.ok(true, 'save operation was rejected'); - }); + post.save().then( + function() {}, + function() { + assert.ok(true, 'save operation was rejected'); + } + ); }); }); diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 0b91dddd2d1..6caa286b03d 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -12,12 +12,7 @@ function idsFromOrderedSet(set) { return set.list.map(i => i.id); } -const { - attr, - belongsTo, - hasMany, - Model -} = DS; +const { attr, belongsTo, hasMany, Model } = DS; let env; @@ -46,57 +41,87 @@ let Person = Model.extend({ // many sync : many async favoriteFriends: hasMany('people', { async: true, inverse: 'favoriteAsyncFriends' }), // many async : many sync - favoriteAsyncFriends: hasMany('people', { async: false, inverse: 'favoriteFriends' }) + favoriteAsyncFriends: hasMany('people', { async: false, inverse: 'favoriteFriends' }), +}); +Person.reopenClass({ + toString() { + return 'Person'; + }, }); -Person.reopenClass({ toString() { return 'Person'; } }); let House = Model.extend({ - person: belongsTo('person', { async: false }) + person: belongsTo('person', { async: false }), +}); +House.reopenClass({ + toString() { + return 'House'; + }, }); -House.reopenClass({ toString() { return 'House'; } }); let Mortgage = Model.extend({ - person: belongsTo('person', { async: true }) + person: belongsTo('person', { async: true }), +}); +Mortgage.reopenClass({ + toString() { + return 'Mortgage'; + }, }); -Mortgage.reopenClass({ toString() { return 'Mortgage'; } }); let Group = Model.extend({ - people: hasMany('person', { async: false }) + people: hasMany('person', { async: false }), +}); +Group.reopenClass({ + toString() { + return 'Group'; + }, }); -Group.reopenClass({ toString() { return 'Group'; } }); let Car = Model.extend({ make: attr('string'), model: attr('string'), - person: belongsTo('person', { async: false }) + person: belongsTo('person', { async: false }), +}); +Car.reopenClass({ + toString() { + return 'Car'; + }, }); -Car.reopenClass({ toString() { return 'Car'; } }); let Boat = Model.extend({ name: attr('string'), - person: belongsTo('person', { async: true }) + person: belongsTo('person', { async: true }), }); -Boat.toString = function() { return 'Boat'; }; +Boat.toString = function() { + return 'Boat'; +}; let Bike = Model.extend({ - name: DS.attr() + name: DS.attr(), }); -Bike.toString = function() { return 'Bike'; }; +Bike.toString = function() { + return 'Bike'; +}; let Book = Model.extend({ - person: belongsTo('person', { async: true }) + person: belongsTo('person', { async: true }), }); -Book.toString = function() { return 'Book'; }; +Book.toString = function() { + return 'Book'; +}; let Spoon = Model.extend({ - person: belongsTo('person', { async: true }) + person: belongsTo('person', { async: true }), }); -Spoon.toString = function() { return 'Spoon'; }; +Spoon.toString = function() { + return 'Spoon'; +}; let Show = Model.extend({ - person: belongsTo('person', { async: false }) + person: belongsTo('person', { async: false }), }); -Show.toString = function() { return 'Show'; }; +Show.toString = function() { + return 'Show'; +}; module('integration/unload - Unloading Records', { beforeEach() { @@ -111,7 +136,7 @@ module('integration/unload - Unloading Records', { bike: Bike, book: Book, spoon: Spoon, - show: Show + show: Show, }); }, @@ -119,7 +144,7 @@ module('integration/unload - Unloading Records', { run(function() { env.container.destroy(); }); - } + }, }); test('can unload a single record', function(assert) { @@ -130,23 +155,27 @@ test('can unload a single record', function(assert) { type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' + name: 'Adam Sunderland', }, relationships: { cars: { - data: [{ - id: 1, - type: 'car' - }] + data: [ + { + id: 1, + type: 'car', + }, + ], }, boats: { - data: [{ - id: 2, - type: 'boat' - }] - } - } - } + data: [ + { + id: 2, + type: 'boat', + }, + ], + }, + }, + }, }); adam = env.store.peekRecord('person', 1); }); @@ -168,19 +197,22 @@ test('can unload all records for a given type', function(assert) { let adam, bob, dudu, car; run(function() { env.store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Bob Bobson' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Bob Bobson', + }, + }, + ], }); adam = env.store.peekRecord('person', 1); bob = env.store.peekRecord('person', 2); @@ -191,20 +223,24 @@ test('can unload all records for a given type', function(assert) { id: '1', attributes: { make: 'VW', - model: 'Beetle' + model: 'Beetle', }, relationships: { person: { - data: { type: 'person', id: '1' } - } - } - } + data: { type: 'person', id: '1' }, + }, + }, + }, }); dudu = bob = env.store.peekRecord('car', 1); }); assert.equal(env.store.peekAll('person').get('length'), 2, 'two person records loaded'); - assert.equal(env.store._internalModelsFor('person').length, 2, 'two person internalModels loaded'); + assert.equal( + env.store._internalModelsFor('person').length, + 2, + 'two person internalModels loaded' + ); assert.equal(env.store.peekAll('car').get('length'), 1, 'one car record loaded'); assert.equal(env.store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); @@ -215,7 +251,11 @@ test('can unload all records for a given type', function(assert) { assert.equal(env.store.peekAll('person').get('length'), 0); assert.equal(env.store.peekAll('car').get('length'), 1); - assert.equal(env.store._internalModelsFor('person').length, 0, 'zero person internalModels loaded'); + assert.equal( + env.store._internalModelsFor('person').length, + 0, + 'zero person internalModels loaded' + ); assert.equal(env.store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); run(function() { @@ -224,9 +264,9 @@ test('can unload all records for a given type', function(assert) { id: 1, type: 'person', attributes: { - name: 'Richard II' - } - } + name: 'Richard II', + }, + }, }); }); @@ -258,19 +298,22 @@ test('can unload all records', function(assert) { let adam, bob, dudu; run(function() { env.store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Bob Bobson' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Bob Bobson', + }, + }, + ], }); adam = env.store.peekRecord('person', 1); bob = env.store.peekRecord('person', 2); @@ -281,20 +324,24 @@ test('can unload all records', function(assert) { id: '1', attributes: { make: 'VW', - model: 'Beetle' + model: 'Beetle', }, relationships: { person: { - data: { type: 'person', id: '1' } - } - } - } + data: { type: 'person', id: '1' }, + }, + }, + }, }); dudu = bob = env.store.peekRecord('car', 1); }); assert.equal(env.store.peekAll('person').get('length'), 2, 'two person records loaded'); - assert.equal(env.store._internalModelsFor('person').length, 2, 'two person internalModels loaded'); + assert.equal( + env.store._internalModelsFor('person').length, + 2, + 'two person internalModels loaded' + ); assert.equal(env.store.peekAll('car').get('length'), 1, 'one car record loaded'); assert.equal(env.store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); @@ -304,7 +351,11 @@ test('can unload all records', function(assert) { assert.equal(env.store.peekAll('person').get('length'), 0); assert.equal(env.store.peekAll('car').get('length'), 0); - assert.equal(env.store._internalModelsFor('person').length, 0, 'zero person internalModels loaded'); + assert.equal( + env.store._internalModelsFor('person').length, + 0, + 'zero person internalModels loaded' + ); assert.equal(env.store._internalModelsFor('car').length, 0, 'zero car internalModels loaded'); }); @@ -314,26 +365,33 @@ test('removes findAllCache after unloading all records', function(assert) { let adam, bob; run(function() { env.store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Bob Bobson' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Bob Bobson', + }, + }, + ], }); adam = env.store.peekRecord('person', 1); bob = env.store.peekRecord('person', 2); }); assert.equal(env.store.peekAll('person').get('length'), 2, 'two person records loaded'); - assert.equal(env.store._internalModelsFor('person').length, 2, 'two person internalModels loaded'); + assert.equal( + env.store._internalModelsFor('person').length, + 2, + 'two person internalModels loaded' + ); run(function() { env.store.peekAll('person'); @@ -341,26 +399,33 @@ test('removes findAllCache after unloading all records', function(assert) { }); assert.equal(env.store.peekAll('person').get('length'), 0, 'zero person records loaded'); - assert.equal(env.store._internalModelsFor('person').length, 0, 'zero person internalModels loaded'); + assert.equal( + env.store._internalModelsFor('person').length, + 0, + 'zero person internalModels loaded' + ); }); test('unloading all records also updates record array from peekAll()', function(assert) { let adam, bob; run(function() { env.store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland' - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Bob Bobson' - } - }] + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Bob Bobson', + }, + }, + ], }); adam = env.store.peekRecord('person', 1); bob = env.store.peekRecord('person', 2); @@ -369,7 +434,6 @@ test('unloading all records also updates record array from peekAll()', function( assert.equal(all.get('length'), 2); - run(function() { env.store.unloadAll('person'); }); @@ -381,13 +445,13 @@ function makeBoatOneForPersonOne() { type: 'boat', id: '1', attributes: { - name: 'Boaty McBoatface' + name: 'Boaty McBoatface', }, relationships: { person: { - data: { type: 'person', id: '1' } - } - } + data: { type: 'person', id: '1' }, + }, + }, }; } @@ -396,25 +460,23 @@ test('unloadAll(type) does not leave stranded internalModels in relationships (r let { store } = env; - let person = run(() => store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Could be Anybody' + let person = run(() => + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Could be Anybody', + }, + relationships: { + boats: { + data: [{ type: 'boat', id: '1' }], + }, + }, }, - relationships: { - boats: { - data: [ - { type: 'boat', id: '1' } - ] - } - } - }, - included: [ - makeBoatOneForPersonOne() - ] - })); + included: [makeBoatOneForPersonOne()], + }) + ); let boat = store.peekRecord('boat', '1'); let initialBoatInternalModel = boat._internalModel; @@ -438,23 +500,34 @@ test('unloadAll(type) does not leave stranded internalModels in relationships (r assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat'); assert.ok(boatPerson === person, 'Our boat has the right person'); - run(() => { store.unloadAll('boat') }); + run(() => { + store.unloadAll('boat'); + }); // ensure that our new state is correct assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); assert.equal(knownBoats.models.length, 0, 'no boat records are loaded'); - assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should still be 1'); + assert.equal( + relationshipState.canonicalMembers.size, + 1, + 'canonical member size should still be 1' + ); assert.equal(relationshipState.members.size, 1, 'members size should still be 1'); assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats'); - run(() => store.push({ - data: makeBoatOneForPersonOne() - })); + run(() => + store.push({ + data: makeBoatOneForPersonOne(), + }) + ); let reloadedBoat = store.peekRecord('boat', '1'); let reloadedBoatInternalModel = reloadedBoat._internalModel; - assert.ok(reloadedBoatInternalModel === initialBoatInternalModel, 'after an unloadAll, subsequent fetch results in the same InternalModel'); + assert.ok( + reloadedBoatInternalModel === initialBoatInternalModel, + 'after an unloadAll, subsequent fetch results in the same InternalModel' + ); }); test('unloadAll(type) does not leave stranded internalModels in relationships (rediscover via relationship reload)', function(assert) { @@ -466,29 +539,27 @@ test('unloadAll(type) does not leave stranded internalModels in relationships (r assert.ok(type.modelName === 'boat', 'We refetch the boat'); assert.ok(id === '1', 'We refetch the right boat'); return resolve({ - data: makeBoatOneForPersonOne() + data: makeBoatOneForPersonOne(), }); }; - let person = run(() => store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Could be Anybody' + let person = run(() => + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Could be Anybody', + }, + relationships: { + boats: { + data: [{ type: 'boat', id: '1' }], + }, + }, }, - relationships: { - boats: { - data: [ - { type: 'boat', id: '1' } - ] - } - } - }, - included: [ - makeBoatOneForPersonOne() - ] - })); + included: [makeBoatOneForPersonOne()], + }) + ); let boat = store.peekRecord('boat', '1'); let initialBoatInternalModel = boat._internalModel; @@ -512,12 +583,18 @@ test('unloadAll(type) does not leave stranded internalModels in relationships (r assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat'); assert.ok(boatPerson === person, 'Our boat has the right person'); - run(() => { store.unloadAll('boat') }); + run(() => { + store.unloadAll('boat'); + }); // ensure that our new state is correct assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); assert.equal(knownBoats.models.length, 0, 'no boat records are loaded'); - assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should still be 1'); + assert.equal( + relationshipState.canonicalMembers.size, + 1, + 'canonical member size should still be 1' + ); assert.equal(relationshipState.members.size, 1, 'members size should still be 1'); assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats'); @@ -526,31 +603,32 @@ test('unloadAll(type) does not leave stranded internalModels in relationships (r let reloadedBoat = store.peekRecord('boat', '1'); let reloadedBoatInternalModel = reloadedBoat._internalModel; - assert.ok(reloadedBoatInternalModel === initialBoatInternalModel, 'after an unloadAll, subsequent fetch results in the same InternalModel'); + assert.ok( + reloadedBoatInternalModel === initialBoatInternalModel, + 'after an unloadAll, subsequent fetch results in the same InternalModel' + ); }); test('(regression) unloadRecord followed by push in the same run-loop', function(assert) { let { store } = env; - let person = run(() => store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Could be Anybody' + let person = run(() => + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Could be Anybody', + }, + relationships: { + boats: { + data: [{ type: 'boat', id: '1' }], + }, + }, }, - relationships: { - boats: { - data: [ - { type: 'boat', id: '1' } - ] - } - } - }, - included: [ - makeBoatOneForPersonOne() - ] - })); + included: [makeBoatOneForPersonOne()], + }) + ); let boat = store.peekRecord('boat', '1'); let initialBoatInternalModel = boat._internalModel; @@ -568,7 +646,11 @@ test('(regression) unloadRecord followed by push in the same run-loop', function let peopleBoats = run(() => person.get('boats.content')); let boatPerson = run(() => boat.get('person.content')); - assert.deepEqual(idsFromOrderedSet(relationshipState.canonicalMembers), ['1'], 'canonical member size should be 1'); + assert.deepEqual( + idsFromOrderedSet(relationshipState.canonicalMembers), + ['1'], + 'canonical member size should be 1' + ); assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should be 1'); assert.ok(get(peopleBoats, 'length') === 1, 'Our person has a boat'); assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat'); @@ -581,20 +663,37 @@ test('(regression) unloadRecord followed by push in the same run-loop', function assert.deepEqual(knownBoats.models.map(m => m.id), ['1'], 'one boat record is known'); assert.ok(knownBoats.models[0] === initialBoatInternalModel, 'We still have our boat'); assert.equal(initialBoatInternalModel.isEmpty(), true, 'Model is in the empty state'); - assert.deepEqual(idsFromOrderedSet(relationshipState.canonicalMembers), ['1'], 'canonical member size should still be 1'); - assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should still be 1'); + assert.deepEqual( + idsFromOrderedSet(relationshipState.canonicalMembers), + ['1'], + 'canonical member size should still be 1' + ); + assert.deepEqual( + idsFromOrderedSet(relationshipState.members), + ['1'], + 'members size should still be 1' + ); assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats'); - run(() => store.push({ - data: makeBoatOneForPersonOne() - })); + run(() => + store.push({ + data: makeBoatOneForPersonOne(), + }) + ); let reloadedBoat = store.peekRecord('boat', '1'); let reloadedBoatInternalModel = reloadedBoat._internalModel; - assert.deepEqual(idsFromOrderedSet(relationshipState.canonicalMembers), ['1'], 'canonical member size should be 1'); + assert.deepEqual( + idsFromOrderedSet(relationshipState.canonicalMembers), + ['1'], + 'canonical member size should be 1' + ); assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should be 1'); - assert.ok(reloadedBoatInternalModel === initialBoatInternalModel, 'after an unloadRecord, subsequent fetch results in the same InternalModel'); + assert.ok( + reloadedBoatInternalModel === initialBoatInternalModel, + 'after an unloadRecord, subsequent fetch results in the same InternalModel' + ); // and now the kicker, run-loop fun! // here, we will dematerialize the record, but push it back into the store @@ -603,19 +702,28 @@ test('(regression) unloadRecord followed by push in the same run-loop', function run(() => { reloadedBoat.unloadRecord(); store.push({ - data: makeBoatOneForPersonOne() + data: makeBoatOneForPersonOne(), }); }); let yaBoat = store.peekRecord('boat', '1'); let yaBoatInternalModel = yaBoat._internalModel; - assert.deepEqual(idsFromOrderedSet(relationshipState.canonicalMembers), ['1'], 'canonical member size should be 1'); + assert.deepEqual( + idsFromOrderedSet(relationshipState.canonicalMembers), + ['1'], + 'canonical member size should be 1' + ); assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should be 1'); - assert.ok(yaBoatInternalModel === initialBoatInternalModel, 'after an unloadRecord, subsequent same-loop push results in the same InternalModel'); + assert.ok( + yaBoatInternalModel === initialBoatInternalModel, + 'after an unloadRecord, subsequent same-loop push results in the same InternalModel' + ); }); -testRecordData('unloading a disconnected subgraph clears the relevant internal models', function(assert) { +testRecordData('unloading a disconnected subgraph clears the relevant internal models', function( + assert +) { env.adapter.shouldBackgroundReloadRecord = () => false; run(() => { @@ -624,17 +732,14 @@ testRecordData('unloading a disconnected subgraph clears the relevant internal m type: 'person', id: '1', attributes: { - name: 'Could be Anybody' + name: 'Could be Anybody', }, relationships: { boats: { - data: [ - { type: 'boat', id: '1' }, - { type: 'boat', id: '2' } - ] - } - } - } + data: [{ type: 'boat', id: '1' }, { type: 'boat', id: '2' }], + }, + }, + }, }); }); @@ -644,14 +749,14 @@ testRecordData('unloading a disconnected subgraph clears the relevant internal m type: 'boat', id: '1', attributes: { - name: 'Boaty McBoatface' + name: 'Boaty McBoatface', }, relationships: { person: { - data: { type: 'person', id: '1' } - } - } - } + data: { type: 'person', id: '1' }, + }, + }, + }, }); }); @@ -661,14 +766,14 @@ testRecordData('unloading a disconnected subgraph clears the relevant internal m type: 'boat', id: '2', attributes: { - name: 'The jackson' + name: 'The jackson', }, relationships: { person: { - data: { type: 'person', id: '1' } - } - } - } + data: { type: 'person', id: '1' }, + }, + }, + }, }); }); @@ -696,12 +801,12 @@ testRecordData('unloading a disconnected subgraph clears the relevant internal m let modelData = internalModel._modelData; let origCleanup = modelData._cleanupOrphanedModelDatas; - internalModel._checkForOrphanedInternalModels = function () { + internalModel._checkForOrphanedInternalModels = function() { ++checkOrphanCalls; return origCheck.apply(record._internalModel, arguments); }; - modelData._cleanupOrphanedModelDatas = function () { + modelData._cleanupOrphanedModelDatas = function() { ++cleanupOrphanCalls; return origCleanup.apply(modelData, arguments); }; @@ -711,22 +816,27 @@ testRecordData('unloading a disconnected subgraph clears the relevant internal m countOrphanCalls(env.store.peekRecord('boat', 2)); // make sure relationships are initialized - return env.store.peekRecord('person', 1).get('boats').then(() => { - run(() => { - env.store.peekRecord('person', 1).unloadRecord(); - env.store.peekRecord('boat', 1).unloadRecord(); - env.store.peekRecord('boat', 2).unloadRecord(); - }); + return env.store + .peekRecord('person', 1) + .get('boats') + .then(() => { + run(() => { + env.store.peekRecord('person', 1).unloadRecord(); + env.store.peekRecord('boat', 1).unloadRecord(); + env.store.peekRecord('boat', 2).unloadRecord(); + }); - assert.equal(env.store._internalModelsFor('person').models.length, 0); - assert.equal(env.store._internalModelsFor('boat').models.length, 0); + assert.equal(env.store._internalModelsFor('person').models.length, 0); + assert.equal(env.store._internalModelsFor('boat').models.length, 0); - assert.equal(checkOrphanCalls, 3, 'each internalModel checks for cleanup'); - assert.equal(cleanupOrphanCalls, 3, 'each model data tries to cleanup'); - }); + assert.equal(checkOrphanCalls, 3, 'each internalModel checks for cleanup'); + assert.equal(cleanupOrphanCalls, 3, 'each model data tries to cleanup'); + }); }); -skipRecordData('unloading a disconnected subgraph clears the relevant internal models', function(assert) { +skipRecordData('unloading a disconnected subgraph clears the relevant internal models', function( + assert +) { env.adapter.shouldBackgroundReloadRecord = () => false; run(() => { @@ -735,17 +845,14 @@ skipRecordData('unloading a disconnected subgraph clears the relevant internal m type: 'person', id: '1', attributes: { - name: 'Could be Anybody' + name: 'Could be Anybody', }, relationships: { boats: { - data: [ - { type: 'boat', id: '1' }, - { type: 'boat', id: '2' } - ] - } - } - } + data: [{ type: 'boat', id: '1' }, { type: 'boat', id: '2' }], + }, + }, + }, }); }); @@ -755,14 +862,14 @@ skipRecordData('unloading a disconnected subgraph clears the relevant internal m type: 'boat', id: '1', attributes: { - name: 'Boaty McBoatface' + name: 'Boaty McBoatface', }, relationships: { person: { - data: { type: 'person', id: '1' } - } - } - } + data: { type: 'person', id: '1' }, + }, + }, + }, }); }); @@ -772,14 +879,14 @@ skipRecordData('unloading a disconnected subgraph clears the relevant internal m type: 'boat', id: '2', attributes: { - name: 'The jackson' + name: 'The jackson', }, relationships: { person: { - data: { type: 'person', id: '1' } - } - } - } + data: { type: 'person', id: '1' }, + }, + }, + }, }); }); @@ -805,12 +912,12 @@ skipRecordData('unloading a disconnected subgraph clears the relevant internal m let origCheck = internalModel._checkForOrphanedInternalModels; let origCleanup = internalModel._cleanupOrphanedInternalModels; - internalModel._checkForOrphanedInternalModels = function () { + internalModel._checkForOrphanedInternalModels = function() { ++checkOrphanCalls; return origCheck.apply(record._internalModel, arguments); }; - internalModel._cleanupOrphanedInternalModels = function () { + internalModel._cleanupOrphanedInternalModels = function() { ++cleanupOrphanCalls; return origCleanup.apply(internalModel, arguments); }; @@ -820,19 +927,22 @@ skipRecordData('unloading a disconnected subgraph clears the relevant internal m countOrphanCalls(env.store.peekRecord('boat', 2)); // make sure relationships are initialized - return env.store.peekRecord('person', 1).get('boats').then(() => { - run(() => { - env.store.peekRecord('person', 1).unloadRecord(); - env.store.peekRecord('boat', 1).unloadRecord(); - env.store.peekRecord('boat', 2).unloadRecord(); - }); + return env.store + .peekRecord('person', 1) + .get('boats') + .then(() => { + run(() => { + env.store.peekRecord('person', 1).unloadRecord(); + env.store.peekRecord('boat', 1).unloadRecord(); + env.store.peekRecord('boat', 2).unloadRecord(); + }); - assert.equal(env.store._internalModelsFor('person').models.length, 0); - assert.equal(env.store._internalModelsFor('boat').models.length, 0); + assert.equal(env.store._internalModelsFor('person').models.length, 0); + assert.equal(env.store._internalModelsFor('boat').models.length, 0); - assert.equal(checkOrphanCalls, 3, 'each internalModel checks for cleanup'); - assert.equal(cleanupOrphanCalls, 1, 'each model data tries to cleanup'); - }); + assert.equal(checkOrphanCalls, 3, 'each internalModel checks for cleanup'); + assert.equal(cleanupOrphanCalls, 1, 'each model data tries to cleanup'); + }); }); test('Unloading a record twice only schedules destroy once', function(assert) { @@ -846,9 +956,9 @@ test('Unloading a record twice only schedules destroy once', function(assert) { type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' - } - } + name: 'Adam Sunderland', + }, + }, }); }); @@ -874,14 +984,18 @@ test('Cancelling destroy leaves the record in the empty state', function(assert) type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' - } - } + name: 'Adam Sunderland', + }, + }, }); }); const internalModel = record._internalModel; - assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded initially'); + assert.equal( + internalModel.currentState.stateName, + 'root.loaded.saved', + 'We are loaded initially' + ); run(function() { store.unloadRecord(record); @@ -889,12 +1003,24 @@ test('Cancelling destroy leaves the record in the empty state', function(assert) assert.equal(internalModel.isDestroyed, false, 'the internal model is not destroyed'); assert.equal(internalModel._isDematerializing, true, 'the internal model is dematerializing'); internalModel.cancelDestroy(); - assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are unloaded after unloadRecord'); + assert.equal( + internalModel.currentState.stateName, + 'root.empty', + 'We are unloaded after unloadRecord' + ); }); assert.equal(internalModel.isDestroyed, false, 'the internal model was not destroyed'); - assert.equal(internalModel._isDematerializing, false, 'the internal model is no longer dematerializing'); - assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are still unloaded after unloadRecord'); + assert.equal( + internalModel._isDematerializing, + false, + 'the internal model is no longer dematerializing' + ); + assert.equal( + internalModel.currentState.stateName, + 'root.empty', + 'We are still unloaded after unloadRecord' + ); }); test('after unloading a record, the record can be fetched again immediately', function(assert) { @@ -907,9 +1033,9 @@ test('after unloading a record, the record can be fetched again immediately', fu type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' - } - } + name: 'Adam Sunderland', + }, + }, }; }; @@ -920,18 +1046,18 @@ test('after unloading a record, the record can be fetched again immediately', fu type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' + name: 'Adam Sunderland', }, relationships: { cars: { data: [ { id: 1, - type: 'car' - } - ] - } - } + type: 'car', + }, + ], + }, + }, }, included: [ { @@ -939,24 +1065,36 @@ test('after unloading a record, the record can be fetched again immediately', fu id: 1, attributes: { make: 'jeep', - model: 'wrangler' - } - } - ] + model: 'wrangler', + }, + }, + ], }); }); const internalModel = record._internalModel; - assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded initially'); + assert.equal( + internalModel.currentState.stateName, + 'root.loaded.saved', + 'We are loaded initially' + ); // we test that we can sync call unloadRecord followed by findRecord return run(() => { store.unloadRecord(record); assert.equal(record.isDestroying, true, 'the record is destroying'); - assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are unloaded after unloadRecord'); + assert.equal( + internalModel.currentState.stateName, + 'root.empty', + 'We are unloaded after unloadRecord' + ); return store.findRecord('person', '1').then(newRecord => { assert.ok(internalModel === newRecord._internalModel, 'the old internalModel is reused'); - assert.equal(newRecord._internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded after findRecord'); + assert.equal( + newRecord._internalModel.currentState.stateName, + 'root.loaded.saved', + 'We are loaded after findRecord' + ); }); }); }); @@ -971,14 +1109,14 @@ test('after unloading a record, the record can be fetched again immediately (pur type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' + name: 'Adam Sunderland', }, relationships: { cars: { - data: [] - } - } - } + data: [], + }, + }, + }, }; }; @@ -989,18 +1127,18 @@ test('after unloading a record, the record can be fetched again immediately (pur type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' + name: 'Adam Sunderland', }, relationships: { cars: { data: [ { id: '1', - type: 'car' - } - ] - } - } + type: 'car', + }, + ], + }, + }, }, included: [ { @@ -1008,27 +1146,43 @@ test('after unloading a record, the record can be fetched again immediately (pur id: '1', attributes: { make: 'jeep', - model: 'wrangler' - } - } - ] + model: 'wrangler', + }, + }, + ], }); }); const internalModel = record._internalModel; - assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded initially'); + assert.equal( + internalModel.currentState.stateName, + 'root.loaded.saved', + 'We are loaded initially' + ); // we test that we can sync call unloadRecord followed by findRecord return run(() => { assert.equal(record.get('cars.firstObject.make'), 'jeep'); store.unloadRecord(record); assert.equal(record.isDestroying, true, 'the record is destroying'); - assert.equal(internalModel.currentState.stateName, 'root.empty', 'Expected the previous internal model tobe unloaded'); + assert.equal( + internalModel.currentState.stateName, + 'root.empty', + 'Expected the previous internal model tobe unloaded' + ); return store.findRecord('person', '1').then(record => { - assert.equal(record.get('cars.length'), 0, 'Expected relationship to be cleared by the new push'); + assert.equal( + record.get('cars.length'), + 0, + 'Expected relationship to be cleared by the new push' + ); assert.ok(internalModel === record._internalModel, 'the old internalModel is reused'); - assert.equal(record._internalModel.currentState.stateName, 'root.loaded.saved', 'Expected the NEW internal model to be loaded'); + assert.equal( + record._internalModel.currentState.stateName, + 'root.loaded.saved', + 'Expected the NEW internal model to be loaded' + ); }); }); }); @@ -1042,9 +1196,9 @@ test('after unloading a record, the record can be fetched again immediately (wit type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' - } - } + name: 'Adam Sunderland', + }, + }, }; }; @@ -1056,9 +1210,9 @@ test('after unloading a record, the record can be fetched again immediately (wit id: '1', relationships: { bike: { - data: { type: 'bike', id: '1' } - } - } + data: { type: 'bike', id: '1' }, + }, + }, }, included: [ @@ -1066,16 +1220,20 @@ test('after unloading a record, the record can be fetched again immediately (wit id: '1', type: 'bike', attributes: { - name: 'mr bike' - } - } - ] + name: 'mr bike', + }, + }, + ], }); }); const internalModel = record._internalModel; const bike = store.peekRecord('bike', '1'); - assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded initially'); + assert.equal( + internalModel.currentState.stateName, + 'root.loaded.saved', + 'We are loaded initially' + ); assert.equal(record.get('bike.name'), 'mr bike'); @@ -1084,11 +1242,18 @@ test('after unloading a record, the record can be fetched again immediately (wit store.unloadRecord(record); assert.equal(record.isDestroying, true, 'the record is destroying'); assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); - assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are unloaded after unloadRecord'); + assert.equal( + internalModel.currentState.stateName, + 'root.empty', + 'We are unloaded after unloadRecord' + ); let wait = store.findRecord('person', '1').then(newRecord => { assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); - assert.ok(newRecord.get('bike') === bike, 'the newRecord should retain knowledge of the bike'); + assert.ok( + newRecord.get('bike') === bike, + 'the newRecord should retain knowledge of the bike' + ); }); assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); @@ -1110,9 +1275,9 @@ test('after unloading a record, the record can be fetched again soon there after type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' - } - } + name: 'Adam Sunderland', + }, + }, }); }; @@ -1123,19 +1288,27 @@ test('after unloading a record, the record can be fetched again soon there after type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' - } - } + name: 'Adam Sunderland', + }, + }, }); }); let internalModel = record._internalModel; - assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded initially'); + assert.equal( + internalModel.currentState.stateName, + 'root.loaded.saved', + 'We are loaded initially' + ); run(function() { store.unloadRecord(record); assert.equal(record.isDestroying, true, 'the record is destroying'); - assert.equal(internalModel.currentState.stateName, 'root.empty', 'We are unloaded after unloadRecord'); + assert.equal( + internalModel.currentState.stateName, + 'root.empty', + 'We are unloaded after unloadRecord' + ); }); run(function() { @@ -1145,10 +1318,14 @@ test('after unloading a record, the record can be fetched again soon there after record = store.peekRecord('person', '1'); internalModel = record._internalModel; - assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded after findRecord'); + assert.equal( + internalModel.currentState.stateName, + 'root.loaded.saved', + 'We are loaded after findRecord' + ); }); -test('after unloading a record, the record can be saved again immediately', function (assert) { +test('after unloading a record, the record can be saved again immediately', function(assert) { assert.expect(0); const store = env.store; @@ -1157,9 +1334,9 @@ test('after unloading a record, the record can be saved again immediately', func type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' - } - } + name: 'Adam Sunderland', + }, + }, }; env.adapter.createRecord = () => EmberPromise.resolve(data); @@ -1176,16 +1353,16 @@ test('after unloading a record, the record can be saved again immediately', func }); }); -test('after unloading a record, pushing a new copy will setup relationships', function (assert) { +test('after unloading a record, pushing a new copy will setup relationships', function(assert) { const store = env.store; const personData = { data: { type: 'person', id: '1', attributes: { - name: 'Adam Sunderland' - } - } + name: 'Adam Sunderland', + }, + }, }; function pushCar() { @@ -1195,18 +1372,20 @@ test('after unloading a record, pushing a new copy will setup relationships', fu id: '10', attributes: { make: 'VW', - model: 'Beetle' + model: 'Beetle', }, relationships: { person: { - data: { type: 'person', id: '1' } - } - } - } + data: { type: 'person', id: '1' }, + }, + }, + }, }); } - run(() => { store.push(personData) }); + run(() => { + store.push(personData); + }); let adam = env.store.peekRecord('person', 1); assert.equal(adam.get('cars.length'), 0, 'cars hasMany starts off empty'); @@ -1221,7 +1400,7 @@ test('after unloading a record, pushing a new copy will setup relationships', fu assert.equal(adam.get('cars.length'), 1, 'pushing car again setups inverse relationship'); }); -test('1:1 sync unload', function (assert) { +test('1:1 sync unload', function(assert) { run(() => env.store.push({ data: { @@ -1231,15 +1410,17 @@ test('1:1 sync unload', function (assert) { house: { data: { id: 2, - type: 'house' - } - } - } + type: 'house', + }, + }, + }, }, - included: [{ - id: 2, - type: 'house' - }] + included: [ + { + id: 2, + type: 'house', + }, + ], }) ); @@ -1251,7 +1432,6 @@ test('1:1 sync unload', function (assert) { run(() => house.unloadRecord()); - assert.equal(person.get('house'), null, 'unloading acts as a delete for sync relationships'); assert.equal(env.store.hasRecordForId('house', 2), false, 'unloaded record gone from store'); @@ -1259,14 +1439,22 @@ test('1:1 sync unload', function (assert) { env.store.push({ data: { id: 2, - type: 'house' - } + type: 'house', + }, }) ); assert.equal(env.store.hasRecordForId('house', 2), true, 'unloaded record can be restored'); - assert.equal(person.get('house'), null, 'restoring unloaded record does not restore relationship'); - assert.equal(house.get('person'), null, 'restoring unloaded record does not restore relationship'); + assert.equal( + person.get('house'), + null, + 'restoring unloaded record does not restore relationship' + ); + assert.equal( + house.get('person'), + null, + 'restoring unloaded record does not restore relationship' + ); run(() => env.store.push({ @@ -1277,11 +1465,11 @@ test('1:1 sync unload', function (assert) { person: { data: { id: 1, - type: 'person' - } - } - } - } + type: 'person', + }, + }, + }, + }, }) ); @@ -1289,7 +1477,7 @@ test('1:1 sync unload', function (assert) { assert.equal(house.get('person.id'), 1, 'after unloading, relationship can be restored'); }); -test('1:many sync unload 1 side', function (assert) { +test('1:many sync unload 1 side', function(assert) { run(() => env.store.push({ data: { @@ -1297,23 +1485,29 @@ test('1:many sync unload 1 side', function (assert) { type: 'person', relationships: { cars: { - data: [{ - id: 2, - type: 'car' - }, { - id: 3, - type: 'car' - }] - } - } + data: [ + { + id: 2, + type: 'car', + }, + { + id: 3, + type: 'car', + }, + ], + }, + }, }, - included: [{ - id: 2, - type: 'car' - }, { - id: 3, - type: 'car' - }] + included: [ + { + id: 2, + type: 'car', + }, + { + id: 3, + type: 'car', + }, + ], }) ); @@ -1323,7 +1517,11 @@ test('1:many sync unload 1 side', function (assert) { let cars = person.get('cars'); assert.equal(cars.isDestroyed, false, 'ManyArray not destroyed'); - assert.deepEqual(person.get('cars').mapBy('id'), ['2', '3'], 'initialy relationship established lhs'); + assert.deepEqual( + person.get('cars').mapBy('id'), + ['2', '3'], + 'initialy relationship established lhs' + ); assert.equal(car2.get('person.id'), 1, 'initially relationship established rhs'); assert.equal(car3.get('person.id'), 1, 'initially relationship established rhs'); @@ -1339,13 +1537,17 @@ test('1:many sync unload 1 side', function (assert) { env.store.push({ data: { id: 1, - type: 'person' - } + type: 'person', + }, }) ); assert.equal(env.store.hasRecordForId('person', 1), true, 'unloaded record can be restored'); - assert.deepEqual(person.get('cars').mapBy('id'), [], 'restoring unloaded record does not restore relationship'); + assert.deepEqual( + person.get('cars').mapBy('id'), + [], + 'restoring unloaded record does not restore relationship' + ); assert.equal(car2.get('person'), null, 'restoring unloaded record does not restore relationship'); assert.equal(car3.get('person'), null, 'restoring unloaded record does not restore relationship'); @@ -1356,25 +1558,32 @@ test('1:many sync unload 1 side', function (assert) { type: 'person', relationships: { cars: { - data: [{ - id: 2, - type: 'car' - }, { - id: 3, - type: 'car' - }] - } - } - } + data: [ + { + id: 2, + type: 'car', + }, + { + id: 3, + type: 'car', + }, + ], + }, + }, + }, }) ); assert.equal(car2.get('person.id'), '1', 'after unloading, relationship can be restored'); assert.equal(car3.get('person.id'), '1', 'after unloading, relationship can be restored'); - assert.deepEqual(person.get('cars').mapBy('id'), ['2', '3'], 'after unloading, relationship can be restored'); + assert.deepEqual( + person.get('cars').mapBy('id'), + ['2', '3'], + 'after unloading, relationship can be restored' + ); }); -test('1:many sync unload many side', function (assert) { +test('1:many sync unload many side', function(assert) { run(() => env.store.push({ data: { @@ -1382,23 +1591,29 @@ test('1:many sync unload many side', function (assert) { type: 'person', relationships: { cars: { - data: [{ - id: 2, - type: 'car' - }, { - id: 3, - type: 'car' - }] - } - } + data: [ + { + id: 2, + type: 'car', + }, + { + id: 3, + type: 'car', + }, + ], + }, + }, }, - included: [{ - id: 2, - type: 'car' - }, { - id: 3, - type: 'car' - }] + included: [ + { + id: 2, + type: 'car', + }, + { + id: 3, + type: 'car', + }, + ], }) ); @@ -1408,7 +1623,11 @@ test('1:many sync unload many side', function (assert) { let cars = person.get('cars'); assert.equal(cars.isDestroyed, false, 'ManyArray not destroyed'); - assert.deepEqual(person.get('cars').mapBy('id'), ['2', '3'], 'initialy relationship established lhs'); + assert.deepEqual( + person.get('cars').mapBy('id'), + ['2', '3'], + 'initialy relationship established lhs' + ); assert.equal(car2.get('person.id'), 1, 'initially relationship established rhs'); assert.equal(car3.get('person.id'), 1, 'initially relationship established rhs'); @@ -1417,20 +1636,32 @@ test('1:many sync unload many side', function (assert) { assert.equal(env.store.hasRecordForId('car', 2), false, 'unloaded record gone from store'); assert.equal(cars.isDestroyed, false, 'ManyArray not destroyed'); - assert.deepEqual(person.get('cars').mapBy('id'), ['3'], 'unload sync relationship acts as delete'); - assert.equal(car3.get('person.id'), '1', 'unloading one of a sync hasMany does not affect the rest'); + assert.deepEqual( + person.get('cars').mapBy('id'), + ['3'], + 'unload sync relationship acts as delete' + ); + assert.equal( + car3.get('person.id'), + '1', + 'unloading one of a sync hasMany does not affect the rest' + ); car2 = run(() => env.store.push({ data: { id: 2, - type: 'car' - } + type: 'car', + }, }) ); assert.equal(env.store.hasRecordForId('car', 2), true, 'unloaded record can be restored'); - assert.deepEqual(person.get('cars').mapBy('id'), ['3'], 'restoring unloaded record does not restore relationship'); + assert.deepEqual( + person.get('cars').mapBy('id'), + ['3'], + 'restoring unloaded record does not restore relationship' + ); assert.equal(car2.get('person'), null, 'restoring unloaded record does not restore relationship'); run(() => @@ -1440,62 +1671,81 @@ test('1:many sync unload many side', function (assert) { type: 'person', relationships: { cars: { - data: [{ - id: 2, - type: 'car' - }, { - id: 3, - type: 'car' - }] - } - } - } + data: [ + { + id: 2, + type: 'car', + }, + { + id: 3, + type: 'car', + }, + ], + }, + }, + }, }) ); assert.equal(car2.get('person.id'), '1', 'after unloading, relationship can be restored'); - assert.deepEqual(person.get('cars').mapBy('id'), ['2', '3'], 'after unloading, relationship can be restored'); + assert.deepEqual( + person.get('cars').mapBy('id'), + ['2', '3'], + 'after unloading, relationship can be restored' + ); }); -test('many:many sync unload', function (assert) { +test('many:many sync unload', function(assert) { run(() => env.store.push({ - data: [{ - id: 1, - type: 'person', - relationships: { - groups: { - data: [{ - id: 3, - type: 'group' - }, { - id: 4, - type: 'group' - }] - } - } - }, { - id: 2, - type: 'person', - relationships: { - groups: { - data: [{ - id: 3, - type: 'group' - }, { - id: 4, - type: 'group' - }] - } - } - }], - included: [{ - id: 3, - type: 'group' - }, { - id: 4, - type: 'group' - }] + data: [ + { + id: 1, + type: 'person', + relationships: { + groups: { + data: [ + { + id: 3, + type: 'group', + }, + { + id: 4, + type: 'group', + }, + ], + }, + }, + }, + { + id: 2, + type: 'person', + relationships: { + groups: { + data: [ + { + id: 3, + type: 'group', + }, + { + id: 4, + type: 'group', + }, + ], + }, + }, + }, + ], + included: [ + { + id: 3, + type: 'group', + }, + { + id: 4, + type: 'group', + }, + ], }) ); @@ -1506,10 +1756,26 @@ test('many:many sync unload', function (assert) { let p2groups = person2.get('groups'); let g3people = group3.get('people'); - assert.deepEqual(person1.get('groups').mapBy('id'), ['3', '4'], 'initially established relationship lhs'); - assert.deepEqual(person2.get('groups').mapBy('id'), ['3', '4'], 'initially established relationship lhs'); - assert.deepEqual(group3.get('people').mapBy('id'), ['1', '2'], 'initially established relationship lhs'); - assert.deepEqual(group4.get('people').mapBy('id'), ['1', '2'], 'initially established relationship lhs'); + assert.deepEqual( + person1.get('groups').mapBy('id'), + ['3', '4'], + 'initially established relationship lhs' + ); + assert.deepEqual( + person2.get('groups').mapBy('id'), + ['3', '4'], + 'initially established relationship lhs' + ); + assert.deepEqual( + group3.get('people').mapBy('id'), + ['1', '2'], + 'initially established relationship lhs' + ); + assert.deepEqual( + group4.get('people').mapBy('id'), + ['1', '2'], + 'initially established relationship lhs' + ); assert.equal(p2groups.isDestroyed, false, 'groups is not destroyed'); assert.equal(g3people.isDestroyed, false, 'people is not destroyed'); @@ -1519,9 +1785,21 @@ test('many:many sync unload', function (assert) { assert.equal(p2groups.isDestroyed, true, 'groups (unloaded side) is destroyed'); assert.equal(g3people.isDestroyed, false, 'people (inverse) is not destroyed'); - assert.deepEqual(person1.get('groups').mapBy('id'), ['3', '4'], 'unloaded record in many:many does not affect inverse of inverse'); - assert.deepEqual(group3.get('people').mapBy('id'), ['1'], 'unloading acts as delete for sync relationships'); - assert.deepEqual(group4.get('people').mapBy('id'), ['1'], 'unloading acts as delete for sync relationships'); + assert.deepEqual( + person1.get('groups').mapBy('id'), + ['3', '4'], + 'unloaded record in many:many does not affect inverse of inverse' + ); + assert.deepEqual( + group3.get('people').mapBy('id'), + ['1'], + 'unloading acts as delete for sync relationships' + ); + assert.deepEqual( + group4.get('people').mapBy('id'), + ['1'], + 'unloading acts as delete for sync relationships' + ); assert.equal(env.store.hasRecordForId('person', 2), false, 'unloading removes record from store'); @@ -1529,15 +1807,27 @@ test('many:many sync unload', function (assert) { env.store.push({ data: { id: 2, - type: 'person' - } + type: 'person', + }, }) ); assert.equal(env.store.hasRecordForId('person', 2), true, 'unloaded record can be restored'); - assert.deepEqual(person2.get('groups').mapBy('id'), [], 'restoring unloaded record does not restore relationship'); - assert.deepEqual(group3.get('people').mapBy('id'), ['1'], 'restoring unloaded record does not restore relationship'); - assert.deepEqual(group4.get('people').mapBy('id'), ['1'], 'restoring unloaded record does not restore relationship'); + assert.deepEqual( + person2.get('groups').mapBy('id'), + [], + 'restoring unloaded record does not restore relationship' + ); + assert.deepEqual( + group3.get('people').mapBy('id'), + ['1'], + 'restoring unloaded record does not restore relationship' + ); + assert.deepEqual( + group4.get('people').mapBy('id'), + ['1'], + 'restoring unloaded record does not restore relationship' + ); run(() => env.store.push({ @@ -1546,25 +1836,40 @@ test('many:many sync unload', function (assert) { type: 'person', relationships: { groups: { - data: [{ - id: 3, - type: 'group' - }, { - id: 4, - type: 'group' - }] - } - } - } + data: [ + { + id: 3, + type: 'group', + }, + { + id: 4, + type: 'group', + }, + ], + }, + }, + }, }) ); - assert.deepEqual(person2.get('groups').mapBy('id'), ['3', '4'], 'after unloading, relationship can be restored'); - assert.deepEqual(group3.get('people').mapBy('id'), ['1', '2'], 'after unloading, relationship can be restored'); - assert.deepEqual(group4.get('people').mapBy('id'), ['1', '2'], 'after unloading, relationship can be restored'); + assert.deepEqual( + person2.get('groups').mapBy('id'), + ['3', '4'], + 'after unloading, relationship can be restored' + ); + assert.deepEqual( + group3.get('people').mapBy('id'), + ['1', '2'], + 'after unloading, relationship can be restored' + ); + assert.deepEqual( + group4.get('people').mapBy('id'), + ['1', '2'], + 'after unloading, relationship can be restored' + ); }); -test('1:1 async unload', function (assert) { +test('1:1 async unload', function(assert) { let findRecordCalls = 0; env.adapter.findRecord = (store, type, id) => { @@ -1575,8 +1880,8 @@ test('1:1 async unload', function (assert) { return { data: { id: 2, - type: 'mortgage' - } + type: 'mortgage', + }, }; }; @@ -1589,39 +1894,63 @@ test('1:1 async unload', function (assert) { mortgage: { data: { id: 2, - type: 'mortgage' - } - } - } - } + type: 'mortgage', + }, + }, + }, + }, }) ); let mortgage; return run(() => - person.get('mortgage').then((asyncRecord) => { - mortgage = asyncRecord; - return mortgage.get('person'); - }).then(() => { - assert.equal(mortgage.belongsTo('person').id(), '1', 'initially relationship established lhs'); - assert.equal(person.belongsTo('mortgage').id(), '2', 'initially relationship established rhs'); - - run(() => mortgage.unloadRecord()); - - assert.equal(person.belongsTo('mortgage').id(), '2', 'unload async is not treated as delete'); - - return person.get('mortgage'); - }).then((refetchedMortgage) => { - assert.notEqual(mortgage, refetchedMortgage, 'the previously loaded record is not reused'); - - assert.equal(person.belongsTo('mortgage').id(), '2', 'unload async is not treated as delete'); - assert.equal(refetchedMortgage.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - assert.equal(findRecordCalls, 2); - }) + person + .get('mortgage') + .then(asyncRecord => { + mortgage = asyncRecord; + return mortgage.get('person'); + }) + .then(() => { + assert.equal( + mortgage.belongsTo('person').id(), + '1', + 'initially relationship established lhs' + ); + assert.equal( + person.belongsTo('mortgage').id(), + '2', + 'initially relationship established rhs' + ); + + run(() => mortgage.unloadRecord()); + + assert.equal( + person.belongsTo('mortgage').id(), + '2', + 'unload async is not treated as delete' + ); + + return person.get('mortgage'); + }) + .then(refetchedMortgage => { + assert.notEqual(mortgage, refetchedMortgage, 'the previously loaded record is not reused'); + + assert.equal( + person.belongsTo('mortgage').id(), + '2', + 'unload async is not treated as delete' + ); + assert.equal( + refetchedMortgage.belongsTo('person').id(), + '1', + 'unload async is not treated as delete' + ); + assert.equal(findRecordCalls, 2); + }) ); }); -test('1:many async unload 1 side', function (assert) { +test('1:many async unload 1 side', function(assert) { let findRecordCalls = 0; let findManyCalls = 0; @@ -1635,24 +1964,27 @@ test('1:many async unload 1 side', function (assert) { return { data: { id: 1, - type: 'person' - } + type: 'person', + }, }; }; env.adapter.findMany = (store, type, ids) => { - assert.equal(type+'', Boat+'', 'findMany(_, type) is correct'); + assert.equal(type + '', Boat + '', 'findMany(_, type) is correct'); assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); ++findManyCalls; return { - data: [{ - id: 2, - type: 'boat' - }, { - id: 3, - type: 'boat' - }] + data: [ + { + id: 2, + type: 'boat', + }, + { + id: 3, + type: 'boat', + }, + ], }; }; @@ -1663,70 +1995,92 @@ test('1:many async unload 1 side', function (assert) { type: 'person', relationships: { boats: { - data: [{ - id: 2, - type: 'boat' - }, { - id: 3, - type: 'boat' - }] - } - } - } + data: [ + { + id: 2, + type: 'boat', + }, + { + id: 3, + type: 'boat', + }, + ], + }, + }, + }, }) ); let boats, boat2, boat3; return run(() => - person.get('boats').then((asyncRecords) => { - boats = asyncRecords; - [boat2, boat3] = boats.toArray(); - return EmberPromise.all([boat2, boat3].map(b => b.get('person'))); - }).then(() => { - assert.deepEqual(person.hasMany('boats').ids(), ['2', '3'], 'initially relationship established lhs'); - assert.equal(boat2.belongsTo('person').id(), '1', 'initially relationship established rhs'); - assert.equal(boat3.belongsTo('person').id(), '1', 'initially relationship established rhs'); - - assert.equal(boats.isDestroyed, false, 'ManyArray is not destroyed'); - - run(() => person.unloadRecord()); - - assert.equal(boats.isDestroyed, false, 'ManyArray is not destroyed when 1 side is unloaded'); - assert.equal(boat2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - - return boat2.get('person'); - }).then((refetchedPerson) => { - assert.notEqual(person, refetchedPerson, 'the previously loaded record is not reused'); - - assert.deepEqual(person.hasMany('boats').ids(), ['2', '3'], 'unload async is not treated as delete'); - assert.equal(boat2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - - assert.equal(findManyCalls, 1, 'findMany called as expected'); - assert.equal(findRecordCalls, 1, 'findRecord called as expected'); - }) + person + .get('boats') + .then(asyncRecords => { + boats = asyncRecords; + [boat2, boat3] = boats.toArray(); + return EmberPromise.all([boat2, boat3].map(b => b.get('person'))); + }) + .then(() => { + assert.deepEqual( + person.hasMany('boats').ids(), + ['2', '3'], + 'initially relationship established lhs' + ); + assert.equal(boat2.belongsTo('person').id(), '1', 'initially relationship established rhs'); + assert.equal(boat3.belongsTo('person').id(), '1', 'initially relationship established rhs'); + + assert.equal(boats.isDestroyed, false, 'ManyArray is not destroyed'); + + run(() => person.unloadRecord()); + + assert.equal( + boats.isDestroyed, + false, + 'ManyArray is not destroyed when 1 side is unloaded' + ); + assert.equal(boat2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + + return boat2.get('person'); + }) + .then(refetchedPerson => { + assert.notEqual(person, refetchedPerson, 'the previously loaded record is not reused'); + + assert.deepEqual( + person.hasMany('boats').ids(), + ['2', '3'], + 'unload async is not treated as delete' + ); + assert.equal(boat2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + + assert.equal(findManyCalls, 1, 'findMany called as expected'); + assert.equal(findRecordCalls, 1, 'findRecord called as expected'); + }) ); }); -test('1:many async unload many side', function (assert) { +test('1:many async unload many side', function(assert) { let findManyCalls = 0; env.adapter.coalesceFindRequests = true; env.adapter.findMany = (store, type, ids) => { - assert.equal(type+'', Boat+'', 'findMany(_, type) is correct'); + assert.equal(type + '', Boat + '', 'findMany(_, type) is correct'); assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); ++findManyCalls; return { - data: [{ - id: 2, - type: 'boat' - }, { - id: 3, - type: 'boat' - }] + data: [ + { + id: 2, + type: 'boat', + }, + { + id: 3, + type: 'boat', + }, + ], }; }; @@ -1737,155 +2091,247 @@ test('1:many async unload many side', function (assert) { type: 'person', relationships: { boats: { - data: [{ - id: 2, - type: 'boat' - }, { - id: 3, - type: 'boat' - }] - } - } - } + data: [ + { + id: 2, + type: 'boat', + }, + { + id: 3, + type: 'boat', + }, + ], + }, + }, + }, }) ); let boats, boat2, boat3; return run(() => - person.get('boats').then((asyncRecords) => { - boats = asyncRecords; - [boat2, boat3] = boats.toArray(); - return EmberPromise.all([boat2, boat3].map(b => b.get('person'))); - }).then(() => { - assert.deepEqual(person.hasMany('boats').ids(), ['2', '3'], 'initially relationship established lhs'); - assert.equal(boat2.belongsTo('person').id(), '1', 'initially relationship established rhs'); - assert.equal(boat3.belongsTo('person').id(), '1', 'initially relationship established rhs'); - - assert.deepEqual(boats.mapBy('id'), ['2', '3'], 'many array is initially set up correctly'); - run(() => boat2.unloadRecord()); - assert.deepEqual(boats.mapBy('id'), ['3'], 'unload async removes from previous many array'); - assert.equal(boats.isDestroyed, false, 'previous ManyArray not destroyed'); - - run(() => boat3.unloadRecord()); - assert.deepEqual(boats.mapBy('id'), [], 'unload async removes from previous many array'); - assert.equal(boats.isDestroyed, false, 'previous ManyArray not destroyed'); - - assert.deepEqual(person.hasMany('boats').ids(), ['2', '3'], 'unload async is not treated as delete'); - assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - - return person.get('boats'); - }).then((refetchedBoats) => { - assert.equal(boats.isDestroyed, false, 'previous ManyArray is not immediately destroyed after refetch'); - assert.equal(boats.isDestroying, true, 'previous ManyArray is being destroyed immediately after refetch'); - assert.deepEqual(refetchedBoats.mapBy('id'), ['2', '3'], 'boats refetched'); - assert.deepEqual(person.hasMany('boats').ids(), ['2', '3'], 'unload async is not treated as delete'); - assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - - assert.equal(findManyCalls, 2, 'findMany called as expected'); - }) + person + .get('boats') + .then(asyncRecords => { + boats = asyncRecords; + [boat2, boat3] = boats.toArray(); + return EmberPromise.all([boat2, boat3].map(b => b.get('person'))); + }) + .then(() => { + assert.deepEqual( + person.hasMany('boats').ids(), + ['2', '3'], + 'initially relationship established lhs' + ); + assert.equal(boat2.belongsTo('person').id(), '1', 'initially relationship established rhs'); + assert.equal(boat3.belongsTo('person').id(), '1', 'initially relationship established rhs'); + + assert.deepEqual(boats.mapBy('id'), ['2', '3'], 'many array is initially set up correctly'); + run(() => boat2.unloadRecord()); + assert.deepEqual(boats.mapBy('id'), ['3'], 'unload async removes from previous many array'); + assert.equal(boats.isDestroyed, false, 'previous ManyArray not destroyed'); + + run(() => boat3.unloadRecord()); + assert.deepEqual(boats.mapBy('id'), [], 'unload async removes from previous many array'); + assert.equal(boats.isDestroyed, false, 'previous ManyArray not destroyed'); + + assert.deepEqual( + person.hasMany('boats').ids(), + ['2', '3'], + 'unload async is not treated as delete' + ); + assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + + return person.get('boats'); + }) + .then(refetchedBoats => { + assert.equal( + boats.isDestroyed, + false, + 'previous ManyArray is not immediately destroyed after refetch' + ); + assert.equal( + boats.isDestroying, + true, + 'previous ManyArray is being destroyed immediately after refetch' + ); + assert.deepEqual(refetchedBoats.mapBy('id'), ['2', '3'], 'boats refetched'); + assert.deepEqual( + person.hasMany('boats').ids(), + ['2', '3'], + 'unload async is not treated as delete' + ); + assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + + assert.equal(findManyCalls, 2, 'findMany called as expected'); + }) ).then(() => { - assert.equal(boats.isDestroyed, true, 'previous ManyArray is destroyed in the runloop after refetching'); + assert.equal( + boats.isDestroyed, + true, + 'previous ManyArray is destroyed in the runloop after refetching' + ); }); }); -test('many:many async unload', function (assert) { +test('many:many async unload', function(assert) { let findManyCalls = 0; env.adapter.coalesceFindRequests = true; env.adapter.findMany = (store, type, ids) => { - assert.equal(type+'', Person+'', 'findMany(_, type) is correct'); + assert.equal(type + '', Person + '', 'findMany(_, type) is correct'); assert.deepEqual(ids, ['3', '4'], 'findMany(_, _, ids) is correct'); ++findManyCalls; return { - data: [{ - id: 3, - type: 'person' - }, { - id: 4, - type: 'person' - }] + data: [ + { + id: 3, + type: 'person', + }, + { + id: 4, + type: 'person', + }, + ], }; }; let [person1, person2] = run(() => env.store.push({ - data: [{ - id: 1, - type: 'person', - relationships: { - friends: { - data: [{ - id: 3, - type: 'person' - }, { - id: 4, - type: 'person' - }] - } - } - }, { - id: 2, - type: 'person', - relationships: { - friends: { - data: [{ - id: 3, - type: 'person' - }, { - id: 4, - type: 'person' - }] - } - } - }] + data: [ + { + id: 1, + type: 'person', + relationships: { + friends: { + data: [ + { + id: 3, + type: 'person', + }, + { + id: 4, + type: 'person', + }, + ], + }, + }, + }, + { + id: 2, + type: 'person', + relationships: { + friends: { + data: [ + { + id: 3, + type: 'person', + }, + { + id: 4, + type: 'person', + }, + ], + }, + }, + }, + ], }) ); let person1Friends, person3, person4; return run(() => - person1.get('friends').then((asyncRecords) => { - person1Friends = asyncRecords; - [person3, person4] = person1Friends.toArray(); - return EmberPromise.all([person2, person3, person4].map(b => b.get('friends'))); - }).then(() => { - assert.deepEqual(person1.hasMany('friends').ids(), ['3', '4'], 'initially relationship established lhs'); - assert.deepEqual(person2.hasMany('friends').ids(), ['3', '4'], 'initially relationship established lhs'); - assert.deepEqual(person3.hasMany('friends').ids(), ['1', '2'], 'initially relationship established rhs'); - assert.deepEqual(person4.hasMany('friends').ids(), ['1', '2'], 'initially relationship established rhs'); - - run(() => person3.unloadRecord()); - assert.deepEqual(person1Friends.mapBy('id'), ['4'], 'unload async removes from previous many array'); - assert.equal(person1Friends.isDestroyed, false, 'previous ManyArray not destroyed'); - - run(() => person4.unloadRecord()); - assert.deepEqual(person1Friends.mapBy('id'), [], 'unload async removes from previous many array'); - assert.equal(person1Friends.isDestroyed, false, 'previous ManyArray not destroyed'); - - assert.deepEqual(person1.hasMany('friends').ids(), ['3', '4'], 'unload async is not treated as delete'); - - return person1.get('friends'); - }).then((refetchedFriends) => { - assert.equal(person1Friends.isDestroyed, false, 'previous ManyArray is not immediately destroyed after refetch'); - assert.equal(person1Friends.isDestroying, true, 'previous ManyArray is being destroyed immediately after refetch'); - assert.deepEqual(refetchedFriends.mapBy('id'), ['3', '4'], 'friends refetched'); - assert.deepEqual(person1.hasMany('friends').ids(), ['3', '4'], 'unload async is not treated as delete'); - - assert.deepEqual(refetchedFriends.map(p => p.hasMany('friends').ids()), [ - ['1', '2'], - ['1', '2'] - ], 'unload async is not treated as delete'); - - assert.equal(findManyCalls, 2, 'findMany called as expected'); - }) + person1 + .get('friends') + .then(asyncRecords => { + person1Friends = asyncRecords; + [person3, person4] = person1Friends.toArray(); + return EmberPromise.all([person2, person3, person4].map(b => b.get('friends'))); + }) + .then(() => { + assert.deepEqual( + person1.hasMany('friends').ids(), + ['3', '4'], + 'initially relationship established lhs' + ); + assert.deepEqual( + person2.hasMany('friends').ids(), + ['3', '4'], + 'initially relationship established lhs' + ); + assert.deepEqual( + person3.hasMany('friends').ids(), + ['1', '2'], + 'initially relationship established rhs' + ); + assert.deepEqual( + person4.hasMany('friends').ids(), + ['1', '2'], + 'initially relationship established rhs' + ); + + run(() => person3.unloadRecord()); + assert.deepEqual( + person1Friends.mapBy('id'), + ['4'], + 'unload async removes from previous many array' + ); + assert.equal(person1Friends.isDestroyed, false, 'previous ManyArray not destroyed'); + + run(() => person4.unloadRecord()); + assert.deepEqual( + person1Friends.mapBy('id'), + [], + 'unload async removes from previous many array' + ); + assert.equal(person1Friends.isDestroyed, false, 'previous ManyArray not destroyed'); + + assert.deepEqual( + person1.hasMany('friends').ids(), + ['3', '4'], + 'unload async is not treated as delete' + ); + + return person1.get('friends'); + }) + .then(refetchedFriends => { + assert.equal( + person1Friends.isDestroyed, + false, + 'previous ManyArray is not immediately destroyed after refetch' + ); + assert.equal( + person1Friends.isDestroying, + true, + 'previous ManyArray is being destroyed immediately after refetch' + ); + assert.deepEqual(refetchedFriends.mapBy('id'), ['3', '4'], 'friends refetched'); + assert.deepEqual( + person1.hasMany('friends').ids(), + ['3', '4'], + 'unload async is not treated as delete' + ); + + assert.deepEqual( + refetchedFriends.map(p => p.hasMany('friends').ids()), + [['1', '2'], ['1', '2']], + 'unload async is not treated as delete' + ); + + assert.equal(findManyCalls, 2, 'findMany called as expected'); + }) ).then(() => { - assert.equal(person1Friends.isDestroyed, true, 'previous ManyArray is destroyed in the runloop after refetching'); + assert.equal( + person1Friends.isDestroyed, + true, + 'previous ManyArray is destroyed in the runloop after refetching' + ); }); }); -test('1 sync : 1 async unload sync side', function (assert) { +test('1 sync : 1 async unload sync side', function(assert) { run(() => env.store.push({ data: { @@ -1895,15 +2341,17 @@ test('1 sync : 1 async unload sync side', function (assert) { favoriteBook: { data: { id: 2, - type: 'book' - } - } - } + type: 'book', + }, + }, + }, }, - included: [{ - id: 2, - type: 'book' - }] + included: [ + { + id: 2, + type: 'book', + }, + ], }) ); @@ -1923,14 +2371,22 @@ test('1 sync : 1 async unload sync side', function (assert) { env.store.push({ data: { id: 2, - type: 'book' - } + type: 'book', + }, }) ); assert.equal(env.store.hasRecordForId('book', 2), true, 'unloaded record can be restored'); - assert.equal(person.get('book'), null, 'restoring unloaded record does not restore relationship'); - assert.equal(book.belongsTo('person').id(), null, 'restoring unloaded record does not restore relationship'); + assert.equal( + person.get('book'), + null, + 'restoring unloaded record does not restore relationship' + ); + assert.equal( + book.belongsTo('person').id(), + null, + 'restoring unloaded record does not restore relationship' + ); run(() => env.store.push({ @@ -1941,11 +2397,11 @@ test('1 sync : 1 async unload sync side', function (assert) { person: { data: { id: 1, - type: 'person' - } - } - } - } + type: 'person', + }, + }, + }, + }, }) ); @@ -1954,7 +2410,7 @@ test('1 sync : 1 async unload sync side', function (assert) { }); }); -test('1 sync : 1 async unload async side', function (assert) { +test('1 sync : 1 async unload async side', function(assert) { let findRecordCalls = 0; env.adapter.findRecord = (store, type, id) => { @@ -1965,8 +2421,8 @@ test('1 sync : 1 async unload async side', function (assert) { return { data: { id: 1, - type: 'person' - } + type: 'person', + }, }; }; @@ -1979,15 +2435,17 @@ test('1 sync : 1 async unload async side', function (assert) { favoriteBook: { data: { id: 2, - type: 'book' - } - } - } + type: 'book', + }, + }, + }, }, - included: [{ - id: 2, - type: 'book' - }] + included: [ + { + id: 2, + type: 'book', + }, + ], }) ); @@ -1995,26 +2453,33 @@ test('1 sync : 1 async unload async side', function (assert) { let book = env.store.peekRecord('book', 2); return run(() => - book.get('person').then(() => { - assert.equal(person.get('favoriteBook.id'), 2, 'initially relationship established lhs'); - assert.equal(book.belongsTo('person').id(), 1, 'initially relationship established rhs'); + book + .get('person') + .then(() => { + assert.equal(person.get('favoriteBook.id'), 2, 'initially relationship established lhs'); + assert.equal(book.belongsTo('person').id(), 1, 'initially relationship established rhs'); - run(() => person.unloadRecord()); + run(() => person.unloadRecord()); - assert.equal(book.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal(book.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - return book.get('person'); - }).then((refetchedPerson) => { - assert.notEqual(person, refetchedPerson, 'the previously loaded record is not reused'); - - assert.equal(book.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - assert.equal(refetchedPerson.get('favoriteBook.id'), '2', 'unload async is not treated as delete'); - assert.equal(findRecordCalls, 1); - }) + return book.get('person'); + }) + .then(refetchedPerson => { + assert.notEqual(person, refetchedPerson, 'the previously loaded record is not reused'); + + assert.equal(book.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal( + refetchedPerson.get('favoriteBook.id'), + '2', + 'unload async is not treated as delete' + ); + assert.equal(findRecordCalls, 1); + }) ); }); -test('1 async : many sync unload sync side', function (assert) { +test('1 async : many sync unload sync side', function(assert) { run(() => env.store.push({ data: { @@ -2022,23 +2487,29 @@ test('1 async : many sync unload sync side', function (assert) { type: 'person', relationships: { favoriteSpoons: { - data: [{ - id: 2, - type: 'spoon' - }, { - id: 3, - type: 'spoon' - }] - } - } + data: [ + { + id: 2, + type: 'spoon', + }, + { + id: 3, + type: 'spoon', + }, + ], + }, + }, }, - included: [{ - id: 2, - type: 'spoon' - }, { - id: 3, - type: 'spoon' - }] + included: [ + { + id: 2, + type: 'spoon', + }, + { + id: 3, + type: 'spoon', + }, + ], }) ); @@ -2048,7 +2519,11 @@ test('1 async : many sync unload sync side', function (assert) { let spoons = person.get('favoriteSpoons'); assert.equal(spoons.isDestroyed, false, 'ManyArray not destroyed'); - assert.deepEqual(person.get('favoriteSpoons').mapBy('id'), ['2', '3'], 'initialy relationship established lhs'); + assert.deepEqual( + person.get('favoriteSpoons').mapBy('id'), + ['2', '3'], + 'initialy relationship established lhs' + ); assert.equal(spoon2.belongsTo('person').id(), '1', 'initially relationship established rhs'); assert.equal(spoon3.belongsTo('person').id(), '1', 'initially relationship established rhs'); @@ -2057,21 +2532,37 @@ test('1 async : many sync unload sync side', function (assert) { assert.equal(env.store.hasRecordForId('spoon', 2), false, 'unloaded record gone from store'); assert.equal(spoons.isDestroyed, false, 'ManyArray not destroyed'); - assert.deepEqual(person.get('favoriteSpoons').mapBy('id'), ['3'], 'unload sync relationship acts as delete'); - assert.equal(spoon3.belongsTo('person').id(), '1', 'unloading one of a sync hasMany does not affect the rest'); + assert.deepEqual( + person.get('favoriteSpoons').mapBy('id'), + ['3'], + 'unload sync relationship acts as delete' + ); + assert.equal( + spoon3.belongsTo('person').id(), + '1', + 'unloading one of a sync hasMany does not affect the rest' + ); spoon2 = run(() => env.store.push({ data: { id: 2, - type: 'spoon' - } + type: 'spoon', + }, }) ); assert.equal(env.store.hasRecordForId('spoon', 2), true, 'unloaded record can be restored'); - assert.deepEqual(person.get('favoriteSpoons').mapBy('id'), ['3'], 'restoring unloaded record does not restore relationship'); - assert.equal(spoon2.belongsTo('person').id(), null, 'restoring unloaded record does not restore relationship'); + assert.deepEqual( + person.get('favoriteSpoons').mapBy('id'), + ['3'], + 'restoring unloaded record does not restore relationship' + ); + assert.equal( + spoon2.belongsTo('person').id(), + null, + 'restoring unloaded record does not restore relationship' + ); run(() => env.store.push({ @@ -2080,24 +2571,35 @@ test('1 async : many sync unload sync side', function (assert) { type: 'person', relationships: { favoriteSpoons: { - data: [{ - id: 2, - type: 'spoon' - }, { - id: 3, - type: 'spoon' - }] - } - } - } + data: [ + { + id: 2, + type: 'spoon', + }, + { + id: 3, + type: 'spoon', + }, + ], + }, + }, + }, }) ); - assert.equal(spoon2.belongsTo('person').id(), '1', 'after unloading, relationship can be restored'); - assert.deepEqual(person.get('favoriteSpoons').mapBy('id'), ['2', '3'], 'after unloading, relationship can be restored'); + assert.equal( + spoon2.belongsTo('person').id(), + '1', + 'after unloading, relationship can be restored' + ); + assert.deepEqual( + person.get('favoriteSpoons').mapBy('id'), + ['2', '3'], + 'after unloading, relationship can be restored' + ); }); -test('1 async : many sync unload async side', function (assert) { +test('1 async : many sync unload async side', function(assert) { let findRecordCalls = 0; env.adapter.coalesceFindRequests = true; @@ -2110,8 +2612,8 @@ test('1 async : many sync unload async side', function (assert) { return { data: { id: 1, - type: 'person' - } + type: 'person', + }, }; }; @@ -2125,26 +2627,26 @@ test('1 async : many sync unload async side', function (assert) { data: [ { id: 2, - type: 'spoon' + type: 'spoon', }, { id: 3, - type: 'spoon' - } - ] - } - } + type: 'spoon', + }, + ], + }, + }, }, included: [ { id: 2, - type: 'spoon' + type: 'spoon', }, { id: 3, - type: 'spoon' - } - ] + type: 'spoon', + }, + ], }) ); let spoon2 = env.store.peekRecord('spoon', 2); @@ -2152,7 +2654,11 @@ test('1 async : many sync unload async side', function (assert) { let spoons = person.get('favoriteSpoons'); return run(() => { - assert.deepEqual(person.get('favoriteSpoons').mapBy('id'), ['2', '3'], 'initially relationship established lhs'); + assert.deepEqual( + person.get('favoriteSpoons').mapBy('id'), + ['2', '3'], + 'initially relationship established lhs' + ); assert.equal(spoon2.belongsTo('person').id(), '1', 'initially relationship established rhs'); assert.equal(spoon3.belongsTo('person').id(), '1', 'initially relationship established rhs'); @@ -2165,10 +2671,14 @@ test('1 async : many sync unload async side', function (assert) { assert.equal(spoon3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); return spoon2.get('person'); - }).then((refetchedPerson) => { + }).then(refetchedPerson => { assert.notEqual(person, refetchedPerson, 'the previously loaded record is not reused'); - assert.deepEqual(person.get('favoriteSpoons').mapBy('id'), ['2', '3'], 'unload async is not treated as delete'); + assert.deepEqual( + person.get('favoriteSpoons').mapBy('id'), + ['2', '3'], + 'unload async is not treated as delete' + ); assert.equal(spoon2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); assert.equal(spoon3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); @@ -2182,18 +2692,21 @@ test('1 sync : many async unload async side', function(assert) { env.adapter.coalesceFindRequests = true; env.adapter.findMany = (store, type, ids) => { - assert.equal(type+'', Show+'', 'findMany(_, type) is correct'); + assert.equal(type + '', Show + '', 'findMany(_, type) is correct'); assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); ++findManyCalls; return { - data: [{ - id: 2, - type: 'show' - }, { - id: 3, - type: 'show' - }] + data: [ + { + id: 2, + type: 'show', + }, + { + id: 3, + type: 'show', + }, + ], }; }; @@ -2207,53 +2720,80 @@ test('1 sync : many async unload async side', function(assert) { data: [ { id: 2, - type: 'show' + type: 'show', }, { id: 3, - type: 'show' - } - ] - } - } - } + type: 'show', + }, + ], + }, + }, + }, }) ); let shows, show2, show3; - return run(() => person.get('favoriteShows') - .then((asyncRecords) => { - shows = asyncRecords; - [show2, show3] = shows.toArray(); - - assert.deepEqual(person.hasMany('favoriteShows').ids(), ['2', '3'], 'initially relationship established lhs'); - assert.equal(show2.get('person.id'), '1', 'initially relationship established rhs'); - assert.equal(show3.get('person.id'), '1', 'initially relationship established rhs'); - assert.deepEqual(shows.mapBy('id'), ['2', '3'], 'many array is initially set up correctly'); - - run(() => show2.unloadRecord()); - - assert.deepEqual(shows.mapBy('id'), ['3'], 'unload async removes from previous many array'); - assert.equal(shows.isDestroyed, false, 'previous many array not destroyed'); - - run(() => show3.unloadRecord()); - - assert.deepEqual(shows.mapBy('id'), [], 'unload async removes from previous many array'); - assert.equal(shows.isDestroyed, false, 'previous many array not destroyed'); - assert.deepEqual(person.hasMany('favoriteShows').ids(), ['2', '3'], 'unload async is not treated as delete'); - - return person.get('favoriteShows'); - }).then((refetchedShows) => { - assert.equal(shows.isDestroyed, false, 'previous ManyArray is not immediately destroyed after refetch'); - assert.equal(shows.isDestroying, true, 'previous ManyArray is being destroyed immediately after refetch'); - assert.deepEqual(refetchedShows.mapBy('id'), ['2', '3'], 'shows refetched'); - assert.deepEqual(person.hasMany('favoriteShows').ids(), ['2', '3'], 'unload async is not treated as delete'); - - assert.equal(findManyCalls, 2, 'findMany called as expected'); - }) + return run(() => + person + .get('favoriteShows') + .then(asyncRecords => { + shows = asyncRecords; + [show2, show3] = shows.toArray(); + + assert.deepEqual( + person.hasMany('favoriteShows').ids(), + ['2', '3'], + 'initially relationship established lhs' + ); + assert.equal(show2.get('person.id'), '1', 'initially relationship established rhs'); + assert.equal(show3.get('person.id'), '1', 'initially relationship established rhs'); + assert.deepEqual(shows.mapBy('id'), ['2', '3'], 'many array is initially set up correctly'); + + run(() => show2.unloadRecord()); + + assert.deepEqual(shows.mapBy('id'), ['3'], 'unload async removes from previous many array'); + assert.equal(shows.isDestroyed, false, 'previous many array not destroyed'); + + run(() => show3.unloadRecord()); + + assert.deepEqual(shows.mapBy('id'), [], 'unload async removes from previous many array'); + assert.equal(shows.isDestroyed, false, 'previous many array not destroyed'); + assert.deepEqual( + person.hasMany('favoriteShows').ids(), + ['2', '3'], + 'unload async is not treated as delete' + ); + + return person.get('favoriteShows'); + }) + .then(refetchedShows => { + assert.equal( + shows.isDestroyed, + false, + 'previous ManyArray is not immediately destroyed after refetch' + ); + assert.equal( + shows.isDestroying, + true, + 'previous ManyArray is being destroyed immediately after refetch' + ); + assert.deepEqual(refetchedShows.mapBy('id'), ['2', '3'], 'shows refetched'); + assert.deepEqual( + person.hasMany('favoriteShows').ids(), + ['2', '3'], + 'unload async is not treated as delete' + ); + + assert.equal(findManyCalls, 2, 'findMany called as expected'); + }) ).then(() => { - assert.equal(shows.isDestroyed, true, 'previous ManyArray is destroyed in the runloop after refetching'); + assert.equal( + shows.isDestroyed, + true, + 'previous ManyArray is destroyed in the runloop after refetching' + ); }); }); @@ -2263,18 +2803,21 @@ test('1 sync : many async unload sync side', function(assert) { env.adapter.coalesceFindRequests = true; env.adapter.findMany = (store, type, ids) => { - assert.equal(type+'', Show+'', 'findMany(_, type) is correct'); + assert.equal(type + '', Show + '', 'findMany(_, type) is correct'); assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); ++findManyCalls; return { - data: [{ - id: 2, - type: 'show' - }, { - id: 3, - type: 'show' - }] + data: [ + { + id: 2, + type: 'show', + }, + { + id: 3, + type: 'show', + }, + ], }; }; @@ -2288,85 +2831,128 @@ test('1 sync : many async unload sync side', function(assert) { data: [ { id: 2, - type: 'show' + type: 'show', }, { id: 3, - type: 'show' - } - ] - } - } - } + type: 'show', + }, + ], + }, + }, + }, }) ); let shows, show2, show3; - return run(() => person.get('favoriteShows') - .then((asyncRecords) => { - shows = asyncRecords; - [show2, show3] = shows.toArray(); - - assert.deepEqual(person.hasMany('favoriteShows').ids(), ['2', '3'], 'initially relationship established lhs'); - assert.equal(show2.get('person.id'), '1', 'initially relationship established rhs'); - assert.equal(show3.get('person.id'), '1', 'initially relationship established rhs'); - assert.deepEqual(shows.mapBy('id'), ['2', '3'], 'many array is initially set up correctly'); - - run(() => person.unloadRecord()); - - assert.equal(env.store.hasRecordForId('person', 1), false, 'unloaded record gone from store'); - - assert.equal(shows.isDestroyed, true, 'previous manyarray immediately destroyed'); - assert.equal(show2.get('person.id'), null, 'unloading acts as delete for sync relationships'); - assert.equal(show3.get('person.id'), null, 'unloading acts as delete for sync relationships'); - - person = run(() => - env.store.push({ - data: { - id: 1, - type: 'person' - } - }) - ); - - assert.equal(env.store.hasRecordForId('person', 1), true, 'unloaded record can be restored'); - assert.deepEqual(person.hasMany('favoriteShows').ids(), [], 'restoring unloaded record does not restore relationship'); - assert.equal(show2.get('person.id'), null, 'restoring unloaded record does not restore relationship'); - assert.equal(show3.get('person.id'), null, 'restoring unloaded record does not restore relationship'); - - run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - favoriteShows: { - data: [ - { - id: 2, - type: 'show' - }, - { - id: 3, - type: 'show' - } - ] - } - } - } - }) - ); - - assert.deepEqual(person.hasMany('favoriteShows').ids(), ['2', '3'], 'relationship can be restored'); + return run(() => + person + .get('favoriteShows') + .then(asyncRecords => { + shows = asyncRecords; + [show2, show3] = shows.toArray(); + + assert.deepEqual( + person.hasMany('favoriteShows').ids(), + ['2', '3'], + 'initially relationship established lhs' + ); + assert.equal(show2.get('person.id'), '1', 'initially relationship established rhs'); + assert.equal(show3.get('person.id'), '1', 'initially relationship established rhs'); + assert.deepEqual(shows.mapBy('id'), ['2', '3'], 'many array is initially set up correctly'); + + run(() => person.unloadRecord()); + + assert.equal( + env.store.hasRecordForId('person', 1), + false, + 'unloaded record gone from store' + ); + + assert.equal(shows.isDestroyed, true, 'previous manyarray immediately destroyed'); + assert.equal( + show2.get('person.id'), + null, + 'unloading acts as delete for sync relationships' + ); + assert.equal( + show3.get('person.id'), + null, + 'unloading acts as delete for sync relationships' + ); + + person = run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + }, + }) + ); + + assert.equal( + env.store.hasRecordForId('person', 1), + true, + 'unloaded record can be restored' + ); + assert.deepEqual( + person.hasMany('favoriteShows').ids(), + [], + 'restoring unloaded record does not restore relationship' + ); + assert.equal( + show2.get('person.id'), + null, + 'restoring unloaded record does not restore relationship' + ); + assert.equal( + show3.get('person.id'), + null, + 'restoring unloaded record does not restore relationship' + ); + + run(() => + env.store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteShows: { + data: [ + { + id: 2, + type: 'show', + }, + { + id: 3, + type: 'show', + }, + ], + }, + }, + }, + }) + ); - return person.get('favoriteShows'); - }).then((refetchedShows) => { - assert.notEqual(refetchedShows, shows, 'ManyArray not reused'); - assert.deepEqual(refetchedShows.mapBy('id'), ['2', '3'], 'unload async not treated as a delete'); + assert.deepEqual( + person.hasMany('favoriteShows').ids(), + ['2', '3'], + 'relationship can be restored' + ); - assert.equal(findManyCalls, 1, 'findMany calls as expected'); - }) + return person.get('favoriteShows'); + }) + .then(refetchedShows => { + assert.notEqual(refetchedShows, shows, 'ManyArray not reused'); + assert.deepEqual( + refetchedShows.mapBy('id'), + ['2', '3'], + 'unload async not treated as a delete' + ); + + assert.equal(findManyCalls, 1, 'findMany calls as expected'); + }) ); }); @@ -2386,29 +2972,29 @@ test('unload invalidates link promises', function(assert) { person: { data: { type: 'person', - id: 1 - } - } + id: 1, + }, + }, }; let data = [ { id: 3, type: 'boat', - relationships - } + relationships, + }, ]; if (!isUnloaded) { data.unshift({ id: 2, type: 'boat', - relationships + relationships, }); } return { - data + data, }; }; @@ -2419,35 +3005,44 @@ test('unload invalidates link promises', function(assert) { type: 'person', relationships: { boats: { - links: { related: 'boats' } - } - } - } + links: { related: 'boats' }, + }, + }, + }, }) ); let boats, boat2, boat3; return run(() => - person.get('boats').then((asyncRecords) => { - boats = asyncRecords; - [boat2, boat3] = boats.toArray(); - }).then(() => { - assert.deepEqual(person.hasMany('boats').ids(), ['2', '3'], 'initially relationship established rhs'); - assert.equal(boat2.belongsTo('person').id(), '1', 'initially relationship established rhs'); - assert.equal(boat3.belongsTo('person').id(), '1', 'initially relationship established rhs'); - - isUnloaded = true; - run(() => { - boat2.unloadRecord(); - person.get('boats'); - }); - - assert.deepEqual(boats.mapBy('id'), ['3'], 'unloaded boat is removed from ManyArray'); - }).then(() => { - return run(() => person.get('boats')); - }).then(newBoats => { - assert.equal(newBoats.length, 1, 'new ManyArray has only 1 boat after unload'); - }) + person + .get('boats') + .then(asyncRecords => { + boats = asyncRecords; + [boat2, boat3] = boats.toArray(); + }) + .then(() => { + assert.deepEqual( + person.hasMany('boats').ids(), + ['2', '3'], + 'initially relationship established rhs' + ); + assert.equal(boat2.belongsTo('person').id(), '1', 'initially relationship established rhs'); + assert.equal(boat3.belongsTo('person').id(), '1', 'initially relationship established rhs'); + + isUnloaded = true; + run(() => { + boat2.unloadRecord(); + person.get('boats'); + }); + + assert.deepEqual(boats.mapBy('id'), ['3'], 'unloaded boat is removed from ManyArray'); + }) + .then(() => { + return run(() => person.get('boats')); + }) + .then(newBoats => { + assert.equal(newBoats.length, 1, 'new ManyArray has only 1 boat after unload'); + }) ); }); @@ -2456,25 +3051,26 @@ test('fetching records cancels unloading', function(assert) { assert.equal(type, Person, 'findRecord(_, type) is correct'); assert.deepEqual(id, '1', 'findRecord(_, _, id) is correct'); - return { + return { data: { id: 1, - type: 'person' - } - } + type: 'person', + }, + }; }; run(() => env.store.push({ data: { id: 1, - type: 'person' - } + type: 'person', + }, }) ); return run(() => - env.store.findRecord('person', 1, { backgroundReload: true }) + env.store + .findRecord('person', 1, { backgroundReload: true }) .then(person => person.unloadRecord()) ); }); diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index 47b7ebffa37..cda9590dff6 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -8,25 +8,25 @@ import { module, test } from 'qunit'; var env, Family; -module("integration/references/belongs-to", { +module('integration/references/belongs-to', { beforeEach() { Family = DS.Model.extend({ persons: DS.hasMany(), - name: DS.attr() + name: DS.attr(), }); var Person = DS.Model.extend({ - family: DS.belongsTo({ async: true }) + family: DS.belongsTo({ async: true }), }); env = setupStore({ person: Person, - family: Family + family: Family, }); }, afterEach() { run(env.container, 'destroy'); - } + }, }); testInDebug("record#belongsTo asserts when specified relationship doesn't exist", function(assert) { @@ -35,37 +35,40 @@ testInDebug("record#belongsTo asserts when specified relationship doesn't exist" person = env.store.push({ data: { type: 'person', - id: 1 - } + id: 1, + }, }); }); assert.expectAssertion(function() { run(function() { - person.belongsTo("unknown-relationship"); + person.belongsTo('unknown-relationship'); }); }, "There is no belongsTo relationship named 'unknown-relationship' on a model of modelClass 'person'"); }); -testInDebug("record#belongsTo asserts when the type of the specified relationship isn't the requested one", function(assert) { - var family; - run(function() { - family = env.store.push({ - data: { - type: 'family', - id: 1 - } - }); - }); - - assert.expectAssertion(function() { +testInDebug( + "record#belongsTo asserts when the type of the specified relationship isn't the requested one", + function(assert) { + var family; run(function() { - family.belongsTo("persons"); - }); - }, "You tried to get the 'persons' relationship on a 'family' via record.belongsTo('persons'), but the relationship is of kind 'hasMany'. Use record.hasMany('persons') instead."); -}); + family = env.store.push({ + data: { + type: 'family', + id: 1, + }, + }); + }); + + assert.expectAssertion(function() { + run(function() { + family.belongsTo('persons'); + }); + }, "You tried to get the 'persons' relationship on a 'family' via record.belongsTo('persons'), but the relationship is of kind 'hasMany'. Use record.hasMany('persons') instead."); + } +); -test("record#belongsTo", function(assert) { +test('record#belongsTo', function(assert) { var person; run(function() { person = env.store.push({ @@ -74,10 +77,10 @@ test("record#belongsTo", function(assert) { id: 1, relationships: { family: { - data: { type: 'family', id: 1 } - } - } - } + data: { type: 'family', id: 1 }, + }, + }, + }, }); }); @@ -88,7 +91,7 @@ test("record#belongsTo", function(assert) { assert.equal(familyReference.id(), 1); }); -test("record#belongsTo for a linked reference", function(assert) { +test('record#belongsTo for a linked reference', function(assert) { var person; run(function() { person = env.store.push({ @@ -97,10 +100,10 @@ test("record#belongsTo for a linked reference", function(assert) { id: 1, relationships: { family: { - links: { related: '/families/1' } - } - } - } + links: { related: '/families/1' }, + }, + }, + }, }); }); @@ -108,10 +111,10 @@ test("record#belongsTo for a linked reference", function(assert) { assert.equal(familyReference.remoteType(), 'link'); assert.equal(familyReference.type, 'family'); - assert.equal(familyReference.link(), "/families/1"); + assert.equal(familyReference.link(), '/families/1'); }); -test("BelongsToReference#parent is a reference to the parent where the relationship is defined", function(assert) { +test('BelongsToReference#parent is a reference to the parent where the relationship is defined', function(assert) { var person; run(function() { person = env.store.push({ @@ -120,10 +123,10 @@ test("BelongsToReference#parent is a reference to the parent where the relations id: 1, relationships: { family: { - data: { type: 'family', id: 1 } - } - } - } + data: { type: 'family', id: 1 }, + }, + }, + }, }); }); @@ -134,7 +137,7 @@ test("BelongsToReference#parent is a reference to the parent where the relations assert.equal(familyReference.parent, personReference); }); -test("BelongsToReference#meta() returns the most recent meta for the relationship", function(assert) { +test('BelongsToReference#meta() returns the most recent meta for the relationship', function(assert) { var person; run(function() { person = env.store.push({ @@ -144,14 +147,14 @@ test("BelongsToReference#meta() returns the most recent meta for the relationshi relationships: { family: { links: { - related: '/families/1' + related: '/families/1', }, meta: { - foo: true - } - } - } - } + foo: true, + }, + }, + }, + }, }); }); @@ -159,7 +162,7 @@ test("BelongsToReference#meta() returns the most recent meta for the relationshi assert.deepEqual(familyReference.meta(), { foo: true }); }); -test("push(object)", function(assert) { +test('push(object)', function(assert) { var done = assert.async(); var person; @@ -170,10 +173,10 @@ test("push(object)", function(assert) { id: 1, relationships: { family: { - data: { type: 'family', id: 1 } - } - } - } + data: { type: 'family', id: 1 }, + }, + }, + }, }); }); @@ -185,21 +188,21 @@ test("push(object)", function(assert) { type: 'family', id: 1, attributes: { - name: "Coreleone" - } - } + name: 'Coreleone', + }, + }, }; familyReference.push(data).then(function(record) { - assert.ok(Family.detectInstance(record), "push resolves with the referenced record"); - assert.equal(get(record, 'name'), "Coreleone", "name is set"); + assert.ok(Family.detectInstance(record), 'push resolves with the referenced record'); + assert.equal(get(record, 'name'), 'Coreleone', 'name is set'); done(); }); }); }); -testInDebug("push(record)", function(assert) { +testInDebug('push(record)', function(assert) { var done = assert.async(); var person, family; @@ -210,19 +213,19 @@ testInDebug("push(record)", function(assert) { id: 1, relationships: { family: { - data: { type: 'family', id: 1 } - } - } - } + data: { type: 'family', id: 1 }, + }, + }, + }, }); family = env.store.push({ data: { type: 'family', id: 1, attributes: { - name: "Coreleone" - } - } + name: 'Coreleone', + }, + }, }); }); @@ -230,8 +233,8 @@ testInDebug("push(record)", function(assert) { run(function() { familyReference.push(family).then(function(record) { - assert.ok(Family.detectInstance(record), "push resolves with the referenced record"); - assert.equal(get(record, 'name'), "Coreleone", "name is set"); + assert.ok(Family.detectInstance(record), 'push resolves with the referenced record'); + assert.equal(get(record, 'name'), 'Coreleone', 'name is set'); assert.equal(record, family); done(); @@ -239,7 +242,7 @@ testInDebug("push(record)", function(assert) { }); }); -test("push(promise)", function(assert) { +test('push(promise)', function(assert) { var done = assert.async(); var push; @@ -252,10 +255,10 @@ test("push(promise)", function(assert) { id: 1, relationships: { family: { - data: { type: 'family', id: 1 } - } - } - } + data: { type: 'family', id: 1 }, + }, + }, + }, }); var familyReference = person.belongsTo('family'); push = familyReference.push(deferred.promise); @@ -269,23 +272,23 @@ test("push(promise)", function(assert) { type: 'family', id: 1, attributes: { - name: "Coreleone" - } - } + name: 'Coreleone', + }, + }, }); }); run(function() { push.then(function(record) { - assert.ok(Family.detectInstance(record), "push resolves with the record"); - assert.equal(get(record, 'name'), "Coreleone", "name is updated"); + assert.ok(Family.detectInstance(record), 'push resolves with the record'); + assert.equal(get(record, 'name'), 'Coreleone', 'name is updated'); done(); }); }); }); -testInDebug("push(record) asserts for invalid modelClass", function(assert) { +testInDebug('push(record) asserts for invalid modelClass', function(assert) { var person, anotherPerson; run(function() { person = env.store.push({ @@ -294,16 +297,16 @@ testInDebug("push(record) asserts for invalid modelClass", function(assert) { id: 1, relationships: { family: { - data: { type: 'family', id: 1 } - } - } - } + data: { type: 'family', id: 1 }, + }, + }, + }, }); anotherPerson = env.store.push({ data: { type: 'person', - id: 2 - } + id: 2, + }, }); }); @@ -316,7 +319,7 @@ testInDebug("push(record) asserts for invalid modelClass", function(assert) { }, "You cannot add a record of modelClass 'person' to the 'person.family' relationship (only 'family' allowed)"); }); -testInDebug("push(record) works with polymorphic modelClass", function(assert) { +testInDebug('push(record) works with polymorphic modelClass', function(assert) { var done = assert.async(); var person, mafiaFamily; @@ -327,14 +330,14 @@ testInDebug("push(record) works with polymorphic modelClass", function(assert) { person = env.store.push({ data: { type: 'person', - id: 1 - } + id: 1, + }, }); mafiaFamily = env.store.push({ data: { type: 'mafia-family', - id: 1 - } + id: 1, + }, }); }); @@ -348,7 +351,7 @@ testInDebug("push(record) works with polymorphic modelClass", function(assert) { }); }); -test("value() is null when reference is not yet loaded", function(assert) { +test('value() is null when reference is not yet loaded', function(assert) { var person; run(function() { person = env.store.push({ @@ -357,10 +360,10 @@ test("value() is null when reference is not yet loaded", function(assert) { id: 1, relationships: { family: { - data: { type: 'family', id: 1 } - } - } - } + data: { type: 'family', id: 1 }, + }, + }, + }, }); }); @@ -368,7 +371,7 @@ test("value() is null when reference is not yet loaded", function(assert) { assert.strictEqual(familyReference.value(), null); }); -test("value() returns the referenced record when loaded", function(assert) { +test('value() returns the referenced record when loaded', function(assert) { var person, family; run(function() { person = env.store.push({ @@ -377,16 +380,16 @@ test("value() returns the referenced record when loaded", function(assert) { id: 1, relationships: { family: { - data: { type: 'family', id: 1 } - } - } - } + data: { type: 'family', id: 1 }, + }, + }, + }, }); family = env.store.push({ data: { type: 'family', - id: 1 - } + id: 1, + }, }); }); @@ -394,7 +397,7 @@ test("value() returns the referenced record when loaded", function(assert) { assert.equal(familyReference.value(), family); }); -test("value() returns the referenced record when loaded even if links are present", function(assert) { +test('value() returns the referenced record when loaded even if links are present', function(assert) { var person, family; run(function() { person = env.store.push({ @@ -403,10 +406,10 @@ test("value() returns the referenced record when loaded even if links are presen id: 1, relationships: { family: { - data: { type: 'family', id: 1 } - } - } - } + data: { type: 'family', id: 1 }, + }, + }, + }, }); family = env.store.push({ data: { @@ -415,11 +418,11 @@ test("value() returns the referenced record when loaded even if links are presen relationships: { persons: { links: { - related: '/this/should/not/matter' - } - } - } - } + related: '/this/should/not/matter', + }, + }, + }, + }, }); }); @@ -427,7 +430,7 @@ test("value() returns the referenced record when loaded even if links are presen assert.equal(familyReference.value(), family); }); -test("load() fetches the record", function(assert) { +test('load() fetches the record', function(assert) { var done = assert.async(); env.adapter.findRecord = function(store, type, id) { @@ -435,8 +438,8 @@ test("load() fetches the record", function(assert) { data: { id: 1, type: 'family', - attributes: { name: "Coreleone" } - } + attributes: { name: 'Coreleone' }, + }, }); }; @@ -448,10 +451,10 @@ test("load() fetches the record", function(assert) { id: 1, relationships: { family: { - data: { type: 'family', id: 1 } - } - } - } + data: { type: 'family', id: 1 }, + }, + }, + }, }); }); @@ -459,25 +462,25 @@ test("load() fetches the record", function(assert) { run(function() { familyReference.load().then(function(record) { - assert.equal(get(record, 'name'), "Coreleone"); + assert.equal(get(record, 'name'), 'Coreleone'); done(); }); }); }); -test("load() fetches link when remoteType is link", function(assert) { +test('load() fetches link when remoteType is link', function(assert) { var done = assert.async(); env.adapter.findBelongsTo = function(store, snapshot, link) { - assert.equal(link, "/families/1"); + assert.equal(link, '/families/1'); return resolve({ data: { id: 1, type: 'family', - attributes: { name: "Coreleone" } - } + attributes: { name: 'Coreleone' }, + }, }); }; @@ -489,26 +492,26 @@ test("load() fetches link when remoteType is link", function(assert) { id: 1, relationships: { family: { - links: { related: '/families/1' } - } - } - } + links: { related: '/families/1' }, + }, + }, + }, }); }); var familyReference = person.belongsTo('family'); - assert.equal(familyReference.remoteType(), "link"); + assert.equal(familyReference.remoteType(), 'link'); run(function() { familyReference.load().then(function(record) { - assert.equal(get(record, 'name'), "Coreleone"); + assert.equal(get(record, 'name'), 'Coreleone'); done(); }); }); }); -test("reload() - loads the record when not yet loaded", function(assert) { +test('reload() - loads the record when not yet loaded', function(assert) { var done = assert.async(); var count = 0; @@ -520,8 +523,8 @@ test("reload() - loads the record when not yet loaded", function(assert) { data: { id: 1, type: 'family', - attributes: { name: "Coreleone" } - } + attributes: { name: 'Coreleone' }, + }, }); }; @@ -533,10 +536,10 @@ test("reload() - loads the record when not yet loaded", function(assert) { id: 1, relationships: { family: { - data: { type: 'family', id: 1 } - } - } - } + data: { type: 'family', id: 1 }, + }, + }, + }, }); }); @@ -544,14 +547,14 @@ test("reload() - loads the record when not yet loaded", function(assert) { run(function() { familyReference.reload().then(function(record) { - assert.equal(get(record, 'name'), "Coreleone"); + assert.equal(get(record, 'name'), 'Coreleone'); done(); }); }); }); -test("reload() - reloads the record when already loaded", function(assert) { +test('reload() - reloads the record when already loaded', function(assert) { var done = assert.async(); var count = 0; @@ -563,8 +566,8 @@ test("reload() - reloads the record when already loaded", function(assert) { data: { id: 1, type: 'family', - attributes: { name: "Coreleone" } - } + attributes: { name: 'Coreleone' }, + }, }); }; @@ -576,16 +579,16 @@ test("reload() - reloads the record when already loaded", function(assert) { id: 1, relationships: { family: { - data: { type: 'family', id: 1 } - } - } - } + data: { type: 'family', id: 1 }, + }, + }, + }, }); env.store.push({ data: { type: 'family', - id: 1 - } + id: 1, + }, }); }); @@ -593,25 +596,25 @@ test("reload() - reloads the record when already loaded", function(assert) { run(function() { familyReference.reload().then(function(record) { - assert.equal(get(record, 'name'), "Coreleone"); + assert.equal(get(record, 'name'), 'Coreleone'); done(); }); }); }); -test("reload() - uses link to reload record", function(assert) { +test('reload() - uses link to reload record', function(assert) { var done = assert.async(); env.adapter.findBelongsTo = function(store, snapshot, link) { - assert.equal(link, "/families/1"); + assert.equal(link, '/families/1'); return resolve({ data: { id: 1, type: 'family', - attributes: { name: "Coreleone" } - } + attributes: { name: 'Coreleone' }, + }, }); }; @@ -623,10 +626,10 @@ test("reload() - uses link to reload record", function(assert) { id: 1, relationships: { family: { - links: { related: '/families/1' } - } - } - } + links: { related: '/families/1' }, + }, + }, + }, }); }); @@ -634,7 +637,7 @@ test("reload() - uses link to reload record", function(assert) { run(function() { familyReference.reload().then(function(record) { - assert.equal(get(record, 'name'), "Coreleone"); + assert.equal(get(record, 'name'), 'Coreleone'); done(); }); diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 030ca234fde..9682b97754c 100755 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -8,24 +8,24 @@ import { module, test } from 'qunit'; var env, Person; -module("integration/references/has-many", { +module('integration/references/has-many', { beforeEach() { var Family = DS.Model.extend({ - persons: DS.hasMany({ async: true }) + persons: DS.hasMany({ async: true }), }); Person = DS.Model.extend({ name: DS.attr(), - family: DS.belongsTo() + family: DS.belongsTo(), }); env = setupStore({ person: Person, - family: Family + family: Family, }); }, afterEach() { run(env.container, 'destroy'); - } + }, }); testInDebug("record#hasMany asserts when specified relationship doesn't exist", function(assert) { @@ -34,37 +34,40 @@ testInDebug("record#hasMany asserts when specified relationship doesn't exist", family = env.store.push({ data: { type: 'family', - id: 1 - } + id: 1, + }, }); }); assert.expectAssertion(function() { run(function() { - family.hasMany("unknown-relationship"); + family.hasMany('unknown-relationship'); }); }, "There is no hasMany relationship named 'unknown-relationship' on a model of modelClass 'family'"); }); -testInDebug("record#hasMany asserts when the type of the specified relationship isn't the requested one", function(assert) { - var person; - run(function() { - person = env.store.push({ - data: { - type: 'person', - id: 1 - } - }); - }); - - assert.expectAssertion(function() { +testInDebug( + "record#hasMany asserts when the type of the specified relationship isn't the requested one", + function(assert) { + var person; run(function() { - person.hasMany("family"); - }); - }, "You tried to get the 'family' relationship on a 'person' via record.hasMany('family'), but the relationship is of kind 'belongsTo'. Use record.belongsTo('family') instead."); -}); + person = env.store.push({ + data: { + type: 'person', + id: 1, + }, + }); + }); + + assert.expectAssertion(function() { + run(function() { + person.hasMany('family'); + }); + }, "You tried to get the 'family' relationship on a 'person' via record.hasMany('family'), but the relationship is of kind 'belongsTo'. Use record.belongsTo('family') instead."); + } +); -test("record#hasMany", function(assert) { +test('record#hasMany', function(assert) { var family; run(function() { family = env.store.push({ @@ -73,13 +76,10 @@ test("record#hasMany", function(assert) { id: 1, relationships: { persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } - } - } + data: [{ type: 'person', id: 1 }, { type: 'person', id: 2 }], + }, + }, + }, }); }); @@ -90,7 +90,7 @@ test("record#hasMany", function(assert) { assert.deepEqual(personsReference.ids(), ['1', '2']); }); -test("record#hasMany for linked references", function(assert) { +test('record#hasMany for linked references', function(assert) { var family; run(function() { family = env.store.push({ @@ -99,10 +99,10 @@ test("record#hasMany for linked references", function(assert) { id: 1, relationships: { persons: { - links: { related: '/families/1/persons' } - } - } - } + links: { related: '/families/1/persons' }, + }, + }, + }, }); }); @@ -113,7 +113,7 @@ test("record#hasMany for linked references", function(assert) { assert.equal(personsReference.link(), '/families/1/persons'); }); -test("HasManyReference#parent is a reference to the parent where the relationship is defined", function(assert) { +test('HasManyReference#parent is a reference to the parent where the relationship is defined', function(assert) { var family; run(function() { family = env.store.push({ @@ -122,13 +122,10 @@ test("HasManyReference#parent is a reference to the parent where the relationshi id: 1, relationships: { persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } - } - } + data: [{ type: 'person', id: 1 }, { type: 'person', id: 2 }], + }, + }, + }, }); }); @@ -139,7 +136,7 @@ test("HasManyReference#parent is a reference to the parent where the relationshi assert.equal(personsReference.parent, familyReference); }); -test("HasManyReference#meta() returns the most recent meta for the relationship", function(assert) { +test('HasManyReference#meta() returns the most recent meta for the relationship', function(assert) { var family; run(function() { family = env.store.push({ @@ -150,11 +147,11 @@ test("HasManyReference#meta() returns the most recent meta for the relationship" persons: { links: { related: '/families/1/persons' }, meta: { - foo: true - } - } - } - } + foo: true, + }, + }, + }, + }, }); }); @@ -162,7 +159,7 @@ test("HasManyReference#meta() returns the most recent meta for the relationship" assert.deepEqual(personsReference.meta(), { foo: true }); }); -testInDebug("push(array)", function(assert) { +testInDebug('push(array)', function(assert) { var done = assert.async(); var family; @@ -173,13 +170,10 @@ testInDebug("push(array)", function(assert) { id: 1, relationships: { persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } - } - } + data: [{ type: 'person', id: 1 }, { type: 'person', id: 2 }], + }, + }, + }, }); }); @@ -187,22 +181,22 @@ testInDebug("push(array)", function(assert) { run(function() { var data = [ - { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, - { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } + { data: { type: 'person', id: 1, attributes: { name: 'Vito' } } }, + { data: { type: 'person', id: 2, attributes: { name: 'Michael' } } }, ]; personsReference.push(data).then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.ok(records instanceof DS.ManyArray, 'push resolves with the referenced records'); assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito"); - assert.equal(records.objectAt(1).get('name'), "Michael"); + assert.equal(records.objectAt(0).get('name'), 'Vito'); + assert.equal(records.objectAt(1).get('name'), 'Michael'); done(); }); }); }); -testInDebug("push(array) works with polymorphic type", function(assert) { +testInDebug('push(array) works with polymorphic type', function(assert) { var done = assert.async(); env.registry.register('model:mafia-boss', Person.extend()); @@ -212,36 +206,34 @@ testInDebug("push(array) works with polymorphic type", function(assert) { family = env.store.push({ data: { type: 'family', - id: 1 - } + id: 1, + }, }); }); var personsReference = family.hasMany('persons'); run(() => { - var data = [ - { data: { type: 'mafia-boss', id: 1, attributes: { name: "Vito" } } } - ]; + var data = [{ data: { type: 'mafia-boss', id: 1, attributes: { name: 'Vito' } } }]; personsReference.push(data).then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.ok(records instanceof DS.ManyArray, 'push resolves with the referenced records'); assert.equal(get(records, 'length'), 1); - assert.equal(records.objectAt(0).get('name'), "Vito"); + assert.equal(records.objectAt(0).get('name'), 'Vito'); done(); }); }); }); -testInDebug("push(array) asserts polymorphic type", function(assert) { +testInDebug('push(array) asserts polymorphic type', function(assert) { var family; run(function() { family = env.store.push({ data: { type: 'family', - id: 1 - } + id: 1, + }, }); }); @@ -249,16 +241,14 @@ testInDebug("push(array) asserts polymorphic type", function(assert) { assert.expectAssertion(() => { run(() => { - var data = [ - { data: { type: 'family', id: 1 } } - ]; + var data = [{ data: { type: 'family', id: 1 } }]; personsReference.push(data); }); }, "You cannot add a record of modelClass 'family' to the 'family.persons' relationship (only 'person' allowed)"); }); -testInDebug("push(object) supports legacy, non-JSON-API-conform payload", function(assert) { +testInDebug('push(object) supports legacy, non-JSON-API-conform payload', function(assert) { var done = assert.async(); var family; @@ -269,13 +259,10 @@ testInDebug("push(object) supports legacy, non-JSON-API-conform payload", functi id: 1, relationships: { persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } - } - } + data: [{ type: 'person', id: 1 }, { type: 'person', id: 2 }], + }, + }, + }, }); }); @@ -284,23 +271,23 @@ testInDebug("push(object) supports legacy, non-JSON-API-conform payload", functi run(function() { var payload = { data: [ - { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, - { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } - ] + { data: { type: 'person', id: 1, attributes: { name: 'Vito' } } }, + { data: { type: 'person', id: 2, attributes: { name: 'Michael' } } }, + ], }; personsReference.push(payload).then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.ok(records instanceof DS.ManyArray, 'push resolves with the referenced records'); assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito"); - assert.equal(records.objectAt(1).get('name'), "Michael"); + assert.equal(records.objectAt(0).get('name'), 'Vito'); + assert.equal(records.objectAt(1).get('name'), 'Michael'); done(); }); }); }); -test("push(promise)", function(assert) { +test('push(promise)', function(assert) { var done = assert.async(); var push; @@ -313,13 +300,10 @@ test("push(promise)", function(assert) { id: 1, relationships: { persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } - } - } + data: [{ type: 'person', id: 1 }, { type: 'person', id: 2 }], + }, + }, + }, }); var personsReference = family.hasMany('persons'); push = personsReference.push(deferred.promise); @@ -330,9 +314,9 @@ test("push(promise)", function(assert) { run(function() { var payload = { data: [ - { data: { type: 'person', id: 1, attributes: { name: "Vito" } } }, - { data: { type: 'person', id: 2, attributes: { name: "Michael" } } } - ] + { data: { type: 'person', id: 1, attributes: { name: 'Vito' } } }, + { data: { type: 'person', id: 2, attributes: { name: 'Michael' } } }, + ], }; deferred.resolve(payload); @@ -340,17 +324,17 @@ test("push(promise)", function(assert) { run(function() { push.then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.ok(records instanceof DS.ManyArray, 'push resolves with the referenced records'); assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito"); - assert.equal(records.objectAt(1).get('name'), "Michael"); + assert.equal(records.objectAt(0).get('name'), 'Vito'); + assert.equal(records.objectAt(1).get('name'), 'Michael'); done(); }); }); }); -test("value() returns null when reference is not yet loaded", function(assert) { +test('value() returns null when reference is not yet loaded', function(assert) { var family; run(function() { family = env.store.push({ @@ -359,13 +343,10 @@ test("value() returns null when reference is not yet loaded", function(assert) { id: 1, relationships: { persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } - } - } + data: [{ type: 'person', id: 1 }, { type: 'person', id: 2 }], + }, + }, + }, }); }); @@ -373,7 +354,7 @@ test("value() returns null when reference is not yet loaded", function(assert) { assert.strictEqual(personsReference.value(), null); }); -test("value() returns the referenced records when all records are loaded", function(assert) { +test('value() returns the referenced records when all records are loaded', function(assert) { var family; run(function() { family = env.store.push({ @@ -382,16 +363,13 @@ test("value() returns the referenced records when all records are loaded", funct id: 1, relationships: { persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } - } - } + data: [{ type: 'person', id: 1 }, { type: 'person', id: 2 }], + }, + }, + }, }); - env.store.push({ data: { type: 'person', id: 1, attributes: { name: "Vito" } } }); - env.store.push({ data: { type: 'person', id: 2, attributes: { name: "Michael" } } }); + env.store.push({ data: { type: 'person', id: 1, attributes: { name: 'Vito' } } }); + env.store.push({ data: { type: 'person', id: 2, attributes: { name: 'Michael' } } }); }); run(function() { @@ -402,7 +380,7 @@ test("value() returns the referenced records when all records are loaded", funct }); }); -test("value() returns an empty array when the reference is loaded and empty", function(assert) { +test('value() returns an empty array when the reference is loaded and empty', function(assert) { var family; run(function() { family = env.store.push({ @@ -411,10 +389,10 @@ test("value() returns an empty array when the reference is loaded and empty", fu id: 1, relationships: { persons: { - data: [] - } - } - } + data: [], + }, + }, + }, }); }); @@ -425,7 +403,7 @@ test("value() returns an empty array when the reference is loaded and empty", fu }); }); -test("_isLoaded() returns an true array when the reference is loaded and empty", function(assert) { +test('_isLoaded() returns an true array when the reference is loaded and empty', function(assert) { var family; run(function() { family = env.store.push({ @@ -434,10 +412,10 @@ test("_isLoaded() returns an true array when the reference is loaded and empty", id: 1, relationships: { persons: { - data: [] - } - } - } + data: [], + }, + }, + }, }); }); @@ -448,11 +426,16 @@ test("_isLoaded() returns an true array when the reference is loaded and empty", }); }); -test("load() fetches the referenced records", function(assert) { +test('load() fetches the referenced records', function(assert) { var done = assert.async(); env.adapter.findMany = function(store, type, id) { - return resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito" } }, { id: 2, type: 'person', attributes: { name: "Michael" } }] }); + return resolve({ + data: [ + { id: 1, type: 'person', attributes: { name: 'Vito' } }, + { id: 2, type: 'person', attributes: { name: 'Michael' } }, + ], + }); }; var family; @@ -463,13 +446,10 @@ test("load() fetches the referenced records", function(assert) { id: 1, relationships: { persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } - } - } + data: [{ type: 'person', id: 1 }, { type: 'person', id: 2 }], + }, + }, + }, }); }); @@ -477,23 +457,28 @@ test("load() fetches the referenced records", function(assert) { run(function() { personsReference.load().then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.ok(records instanceof DS.ManyArray, 'push resolves with the referenced records'); assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito"); - assert.equal(records.objectAt(1).get('name'), "Michael"); + assert.equal(records.objectAt(0).get('name'), 'Vito'); + assert.equal(records.objectAt(1).get('name'), 'Michael'); done(); }); }); }); -test("load() fetches link when remoteType is link", function(assert) { +test('load() fetches link when remoteType is link', function(assert) { var done = assert.async(); env.adapter.findHasMany = function(store, snapshot, link) { - assert.equal(link, "/families/1/persons"); + assert.equal(link, '/families/1/persons'); - return resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito" } }, { id: 2, type: 'person', attributes: { name: "Michael" } }] }); + return resolve({ + data: [ + { id: 1, type: 'person', attributes: { name: 'Vito' } }, + { id: 2, type: 'person', attributes: { name: 'Michael' } }, + ], + }); }; var family; @@ -504,31 +489,31 @@ test("load() fetches link when remoteType is link", function(assert) { id: 1, relationships: { persons: { - links: { related: '/families/1/persons' } - } - } - } + links: { related: '/families/1/persons' }, + }, + }, + }, }); }); var personsReference = family.hasMany('persons'); - assert.equal(personsReference.remoteType(), "link"); + assert.equal(personsReference.remoteType(), 'link'); run(function() { personsReference.load().then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.ok(records instanceof DS.ManyArray, 'push resolves with the referenced records'); assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito"); - assert.equal(records.objectAt(1).get('name'), "Michael"); + assert.equal(records.objectAt(0).get('name'), 'Vito'); + assert.equal(records.objectAt(1).get('name'), 'Michael'); done(); }); }); }); -test("load() fetches link when remoteType is link but an empty set of records is returned", function(assert) { +test('load() fetches link when remoteType is link but an empty set of records is returned', function(assert) { env.adapter.findHasMany = function(store, snapshot, link) { - assert.equal(link, "/families/1/persons"); + assert.equal(link, '/families/1/persons'); return resolve({ data: [] }); }; @@ -541,26 +526,26 @@ test("load() fetches link when remoteType is link but an empty set of records is id: 1, relationships: { persons: { - links: { related: '/families/1/persons' } - } - } - } + links: { related: '/families/1/persons' }, + }, + }, + }, }); }); let personsReference = family.hasMany('persons'); - assert.equal(personsReference.remoteType(), "link"); + assert.equal(personsReference.remoteType(), 'link'); return run(() => { - return personsReference.load().then((records) => { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + return personsReference.load().then(records => { + assert.ok(records instanceof DS.ManyArray, 'push resolves with the referenced records'); assert.equal(get(records, 'length'), 0); assert.equal(get(personsReference.value(), 'length'), 0); }); }); }); -test("load() - only a single find is triggered", function(assert) { +test('load() - only a single find is triggered', function(assert) { var done = assert.async(); var deferred = defer(); @@ -581,13 +566,10 @@ test("load() - only a single find is triggered", function(assert) { id: 1, relationships: { persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } - } - } + data: [{ type: 'person', id: 1 }, { type: 'person', id: 2 }], + }, + }, + }, }); }); @@ -601,7 +583,12 @@ test("load() - only a single find is triggered", function(assert) { }); run(function() { - deferred.resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito" } }, { id: 2, type: 'person', attributes: { name: "Michael" } }] }); + deferred.resolve({ + data: [ + { id: 1, type: 'person', attributes: { name: 'Vito' } }, + { id: 2, type: 'person', attributes: { name: 'Michael' } }, + ], + }); }); run(function() { @@ -613,11 +600,16 @@ test("load() - only a single find is triggered", function(assert) { }); }); -test("reload()", function(assert) { +test('reload()', function(assert) { var done = assert.async(); env.adapter.findMany = function(store, type, id) { - return resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito Coreleone" } }, { id: 2, type: 'person', attributes: { name: "Michael Coreleone" } }] }); + return resolve({ + data: [ + { id: 1, type: 'person', attributes: { name: 'Vito Coreleone' } }, + { id: 2, type: 'person', attributes: { name: 'Michael Coreleone' } }, + ], + }); }; var family; @@ -628,44 +620,51 @@ test("reload()", function(assert) { id: 1, relationships: { persons: { - data: [ - { type: 'person', id: 1 }, - { type: 'person', id: 2 } - ] - } - } - } + data: [{ type: 'person', id: 1 }, { type: 'person', id: 2 }], + }, + }, + }, }); - env.store.push({ data: { type: 'person', id: 1, attributes: { name: "Vito" } } }); - env.store.push({ data: { type: 'person', id: 2, attributes: { name: "Michael" } } }); + env.store.push({ data: { type: 'person', id: 1, attributes: { name: 'Vito' } } }); + env.store.push({ data: { type: 'person', id: 2, attributes: { name: 'Michael' } } }); }); var personsReference = family.hasMany('persons'); run(function() { personsReference.reload().then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); + assert.ok(records instanceof DS.ManyArray, 'push resolves with the referenced records'); assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito Coreleone"); - assert.equal(records.objectAt(1).get('name'), "Michael Coreleone"); + assert.equal(records.objectAt(0).get('name'), 'Vito Coreleone'); + assert.equal(records.objectAt(1).get('name'), 'Michael Coreleone'); done(); }); }); }); -test("reload() fetches link when remoteType is link", function(assert) { +test('reload() fetches link when remoteType is link', function(assert) { var done = assert.async(); var count = 0; env.adapter.findHasMany = function(store, snapshot, link) { count++; - assert.equal(link, "/families/1/persons"); + assert.equal(link, '/families/1/persons'); if (count === 1) { - return resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito" } }, { id: 2, type: 'person', attributes: { name: "Michael" } }] }); + return resolve({ + data: [ + { id: 1, type: 'person', attributes: { name: 'Vito' } }, + { id: 2, type: 'person', attributes: { name: 'Michael' } }, + ], + }); } else { - return resolve({ data: [{ id: 1, type: 'person', attributes: { name: "Vito Coreleone" } }, { id: 2, type: 'person', attributes: { name: "Michael Coreleone" } }] }); + return resolve({ + data: [ + { id: 1, type: 'person', attributes: { name: 'Vito Coreleone' } }, + { id: 2, type: 'person', attributes: { name: 'Michael Coreleone' } }, + ], + }); } }; @@ -677,26 +676,29 @@ test("reload() fetches link when remoteType is link", function(assert) { id: 1, relationships: { persons: { - links: { related: '/families/1/persons' } - } - } - } + links: { related: '/families/1/persons' }, + }, + }, + }, }); }); var personsReference = family.hasMany('persons'); - assert.equal(personsReference.remoteType(), "link"); + assert.equal(personsReference.remoteType(), 'link'); run(function() { - personsReference.load().then(function() { - return personsReference.reload(); - }).then(function(records) { - assert.ok(records instanceof DS.ManyArray, "push resolves with the referenced records"); - assert.equal(get(records, 'length'), 2); - assert.equal(records.objectAt(0).get('name'), "Vito Coreleone"); - assert.equal(records.objectAt(1).get('name'), "Michael Coreleone"); + personsReference + .load() + .then(function() { + return personsReference.reload(); + }) + .then(function(records) { + assert.ok(records instanceof DS.ManyArray, 'push resolves with the referenced records'); + assert.equal(get(records, 'length'), 2); + assert.equal(records.objectAt(0).get('name'), 'Vito Coreleone'); + assert.equal(records.objectAt(1).get('name'), 'Michael Coreleone'); - done(); - }); + done(); + }); }); }); diff --git a/tests/integration/references/record-test.js b/tests/integration/references/record-test.js index 3701206cebd..d5484cfd814 100644 --- a/tests/integration/references/record-test.js +++ b/tests/integration/references/record-test.js @@ -7,24 +7,24 @@ import { module, test } from 'qunit'; var env, Person; -module("integration/references/record", { +module('integration/references/record', { beforeEach() { Person = DS.Model.extend({ - name: DS.attr() + name: DS.attr(), }); env = setupStore({ - person: Person + person: Person, }); }, afterEach() { run(env.store, 'unloadAll'); run(env.container, 'destroy'); - } + }, }); -test("a RecordReference can be retrieved via store.getReference(type, id)", function(assert) { +test('a RecordReference can be retrieved via store.getReference(type, id)', function(assert) { var recordReference = env.store.getReference('person', 1); assert.equal(recordReference.remoteType(), 'identity'); @@ -32,7 +32,7 @@ test("a RecordReference can be retrieved via store.getReference(type, id)", func assert.equal(recordReference.id(), 1); }); -test("push(object)", function(assert) { +test('push(object)', function(assert) { var done = assert.async(); var push; @@ -44,9 +44,9 @@ test("push(object)", function(assert) { type: 'person', id: 1, attributes: { - name: "le name" - } - } + name: 'le name', + }, + }, }); }); @@ -54,15 +54,15 @@ test("push(object)", function(assert) { run(function() { push.then(function(record) { - assert.ok(record instanceof Person, "push resolves with the record"); - assert.equal(get(record, 'name'), "le name"); + assert.ok(record instanceof Person, 'push resolves with the record'); + assert.equal(get(record, 'name'), 'le name'); done(); }); }); }); -test("push(promise)", function(assert) { +test('push(promise)', function(assert) { var done = assert.async(); var push; @@ -81,35 +81,35 @@ test("push(promise)", function(assert) { type: 'person', id: 1, attributes: { - name: "le name" - } - } + name: 'le name', + }, + }, }); }); run(function() { push.then(function(record) { - assert.ok(record instanceof Person, "push resolves with the record"); - assert.equal(get(record, 'name'), "le name", "name is updated"); + assert.ok(record instanceof Person, 'push resolves with the record'); + assert.equal(get(record, 'name'), 'le name', 'name is updated'); done(); }); }); }); -test("value() returns null when not yet loaded", function(assert) { +test('value() returns null when not yet loaded', function(assert) { var recordReference = env.store.getReference('person', 1); assert.strictEqual(recordReference.value(), null); }); -test("value() returns the record when loaded", function(assert) { +test('value() returns the record when loaded', function(assert) { var person; run(function() { person = env.store.push({ data: { type: 'person', - id: 1 - } + id: 1, + }, }); }); @@ -117,7 +117,7 @@ test("value() returns the record when loaded", function(assert) { assert.equal(recordReference.value(), person); }); -test("load() fetches the record", function(assert) { +test('load() fetches the record', function(assert) { var done = assert.async(); env.adapter.findRecord = function(store, type, id) { @@ -126,9 +126,9 @@ test("load() fetches the record", function(assert) { id: 1, type: 'person', attributes: { - name: 'Vito' - } - } + name: 'Vito', + }, + }, }); }; @@ -136,20 +136,24 @@ test("load() fetches the record", function(assert) { run(function() { recordReference.load().then(function(record) { - assert.equal(get(record, 'name'), "Vito"); + assert.equal(get(record, 'name'), 'Vito'); done(); }); }); }); -test("load() only a single find is triggered", function(assert) { +test('load() only a single find is triggered', function(assert) { var done = assert.async(); var deferred = defer(); var count = 0; - env.adapter.shouldReloadRecord = function() { return false; }; - env.adapter.shouldBackgroundReloadRecord = function() { return false; }; + env.adapter.shouldReloadRecord = function() { + return false; + }; + env.adapter.shouldBackgroundReloadRecord = function() { + return false; + }; env.adapter.findRecord = function(store, type, id) { count++; assert.equal(count, 1); @@ -162,7 +166,7 @@ test("load() only a single find is triggered", function(assert) { run(function() { recordReference.load(); recordReference.load().then(function(record) { - assert.equal(get(record, 'name'), "Vito"); + assert.equal(get(record, 'name'), 'Vito'); }); }); @@ -172,22 +176,22 @@ test("load() only a single find is triggered", function(assert) { id: 1, type: 'person', attributes: { - name: 'Vito' - } - } + name: 'Vito', + }, + }, }); }); run(function() { recordReference.load().then(function(record) { - assert.equal(get(record, 'name'), "Vito"); + assert.equal(get(record, 'name'), 'Vito'); done(); }); }); }); -test("reload() loads the record if not yet loaded", function(assert) { +test('reload() loads the record if not yet loaded', function(assert) { var done = assert.async(); var count = 0; @@ -200,9 +204,9 @@ test("reload() loads the record if not yet loaded", function(assert) { id: 1, type: 'person', attributes: { - name: 'Vito Coreleone' - } - } + name: 'Vito Coreleone', + }, + }, }); }; @@ -210,14 +214,14 @@ test("reload() loads the record if not yet loaded", function(assert) { run(function() { recordReference.reload().then(function(record) { - assert.equal(get(record, 'name'), "Vito Coreleone"); + assert.equal(get(record, 'name'), 'Vito Coreleone'); done(); }); }); }); -test("reload() fetches the record", function(assert) { +test('reload() fetches the record', function(assert) { var done = assert.async(); env.adapter.findRecord = function(store, type, id) { @@ -226,9 +230,9 @@ test("reload() fetches the record", function(assert) { id: 1, type: 'person', attributes: { - name: 'Vito Coreleone' - } - } + name: 'Vito Coreleone', + }, + }, }); }; @@ -238,9 +242,9 @@ test("reload() fetches the record", function(assert) { type: 'person', id: 1, attributes: { - name: 'Vito' - } - } + name: 'Vito', + }, + }, }); }); @@ -248,7 +252,7 @@ test("reload() fetches the record", function(assert) { run(function() { recordReference.reload().then(function(record) { - assert.equal(get(record, 'name'), "Vito Coreleone"); + assert.equal(get(record, 'name'), 'Vito Coreleone'); done(); }); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index cb0ecbc143b..605e2a8353d 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -6,7 +6,7 @@ import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { setup as setupModelFactoryInjections, - reset as resetModelFactoryInjection + reset as resetModelFactoryInjection, } from 'dummy/tests/helpers/model-factory-injection'; import { module, test } from 'qunit'; @@ -17,43 +17,43 @@ const { hash } = RSVP; let env, store, User, Message, Post, Comment, Book, Chapter, Author, NewMessage; -module("integration/relationship/belongs_to Belongs-To Relationships", { +module('integration/relationship/belongs_to Belongs-To Relationships', { beforeEach() { User = DS.Model.extend({ name: attr('string'), messages: hasMany('message', { polymorphic: true, async: false }), - favouriteMessage: belongsTo('message', { polymorphic: true, inverse: null, async: false }) + favouriteMessage: belongsTo('message', { polymorphic: true, inverse: null, async: false }), }); Message = DS.Model.extend({ user: belongsTo('user', { inverse: 'messages', async: false }), - created_at: attr('date') + created_at: attr('date'), }); Post = Message.extend({ title: attr('string'), - comments: hasMany('comment', { async: false, inverse: null }) + comments: hasMany('comment', { async: false, inverse: null }), }); Comment = Message.extend({ body: DS.attr('string'), - message: DS.belongsTo('message', { polymorphic: true, async: false, inverse: null }) + message: DS.belongsTo('message', { polymorphic: true, async: false, inverse: null }), }); Book = DS.Model.extend({ name: attr('string'), author: belongsTo('author', { async: false }), - chapters: hasMany('chapters', { async: false, inverse: 'book' }) + chapters: hasMany('chapters', { async: false, inverse: 'book' }), }); Chapter = DS.Model.extend({ title: attr('string'), - book: belongsTo('book', { async: false, inverse: 'chapters' }) + book: belongsTo('book', { async: false, inverse: 'chapters' }), }); Author = DS.Model.extend({ name: attr('string'), - books: hasMany('books', { async: false }) + books: hasMany('books', { async: false }), }); env = setupStore({ @@ -63,43 +63,52 @@ module("integration/relationship/belongs_to Belongs-To Relationships", { message: Message, book: Book, chapter: Chapter, - author: Author + author: Author, }); env.registry.optionsForType('serializer', { singleton: false }); env.registry.optionsForType('adapter', { singleton: false }); - env.registry.register('serializer:user', DS.JSONAPISerializer.extend({ - attrs: { - favouriteMessage: { embedded: 'always' } - } - })); + env.registry.register( + 'serializer:user', + DS.JSONAPISerializer.extend({ + attrs: { + favouriteMessage: { embedded: 'always' }, + }, + }) + ); store = env.store; - User = store.modelFor('user'); - Post = store.modelFor('post'); + User = store.modelFor('user'); + Post = store.modelFor('post'); Comment = store.modelFor('comment'); Message = store.modelFor('message'); - Book = store.modelFor('book'); + Book = store.modelFor('book'); Chapter = store.modelFor('chapter'); - Author = store.modelFor('author'); + Author = store.modelFor('author'); }, afterEach() { resetModelFactoryInjection(); run(env.container, 'destroy'); - } + }, }); -test("returning a null relationship from payload sets the relationship to null on both sides", function(assert) { - env.registry.register('model:app', DS.Model.extend({ - name: attr('string'), - team: belongsTo('team', { async: true }) - })); - env.registry.register('model:team', DS.Model.extend({ - apps: hasMany('app', {async: true}) - })); +test('returning a null relationship from payload sets the relationship to null on both sides', function(assert) { + env.registry.register( + 'model:app', + DS.Model.extend({ + name: attr('string'), + team: belongsTo('team', { async: true }), + }) + ); + env.registry.register( + 'model:team', + DS.Model.extend({ + apps: hasMany('app', { async: true }), + }) + ); run(() => { env.store.push({ data: { @@ -109,10 +118,10 @@ test("returning a null relationship from payload sets the relationship to null o team: { data: { id: '1', - type: 'team' - } - } - } + type: 'team', + }, + }, + }, }, included: [ { @@ -120,21 +129,30 @@ test("returning a null relationship from payload sets the relationship to null o type: 'team', relationships: { apps: { - data: [{ - id: '1', - type: 'app' - }] - } - } - } - ] + data: [ + { + id: '1', + type: 'app', + }, + ], + }, + }, + }, + ], }); }); const app = env.store.peekRecord('app', '1'); const team = env.store.peekRecord('team', '1'); assert.equal(app.get('team.id'), team.get('id'), 'sets team correctly on app'); - assert.deepEqual(team.get('apps').toArray().mapBy('id'), ['1'], 'sets apps correctly on team'); + assert.deepEqual( + team + .get('apps') + .toArray() + .mapBy('id'), + ['1'], + 'sets apps correctly on team' + ); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.updateRecord = (store, type, snapshot) => { @@ -143,14 +161,14 @@ test("returning a null relationship from payload sets the relationship to null o id: '1', type: 'app', attributes: { - name: 'Hello' + name: 'Hello', }, relationships: { team: { - data: null - } - } - } + data: null, + }, + }, + }, }); }; @@ -158,19 +176,26 @@ test("returning a null relationship from payload sets the relationship to null o app.set('name', 'Hello'); return app.save().then(() => { assert.equal(app.get('team.id'), null, 'team removed from app relationship'); - assert.deepEqual(team.get('apps').toArray().mapBy('id'), [], 'app removed from team apps relationship'); + assert.deepEqual( + team + .get('apps') + .toArray() + .mapBy('id'), + [], + 'app removed from team apps relationship' + ); }); }); }); -test("The store can materialize a non loaded monomorphic belongsTo association", function(assert) { +test('The store can materialize a non loaded monomorphic belongsTo association', function(assert) { assert.expect(1); env.store.modelFor('post').reopen({ user: DS.belongsTo('user', { async: true, - inverse: 'messages' - }) + inverse: 'messages', + }), }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.findRecord = function(store, type, id, snapshot) { @@ -178,8 +203,8 @@ test("The store can materialize a non loaded monomorphic belongsTo association", return resolve({ data: { id, - type: snapshot.modelName - } + type: snapshot.modelName, + }, }); }; @@ -192,11 +217,11 @@ test("The store can materialize a non loaded monomorphic belongsTo association", user: { data: { id: '2', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); }); @@ -207,149 +232,149 @@ test("The store can materialize a non loaded monomorphic belongsTo association", }); }); -testInDebug("Invalid belongsTo relationship identifiers throw errors", function(assert) { +testInDebug('Invalid belongsTo relationship identifiers throw errors', function(assert) { assert.expect(2); let { store } = env; // test null id - assert.expectAssertion( - () => { - run(() => { - let post = store.push({ - data: { - id: '1', - type: 'post', - relationships: { - user: { - data: { - id: null, - type: 'user' - } - } - } - } - }); - post.get('user'); + assert.expectAssertion(() => { + run(() => { + let post = store.push({ + data: { + id: '1', + type: 'post', + relationships: { + user: { + data: { + id: null, + type: 'user', + }, + }, + }, + }, }); - }, - `Assertion Failed: Encountered a relationship identifier without an id for the belongsTo relationship 'user' on , expected a json-api identifier but found '{"id":null,"type":"user"}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.` - ); + post.get('user'); + }); + }, `Assertion Failed: Encountered a relationship identifier without an id for the belongsTo relationship 'user' on , expected a json-api identifier but found '{"id":null,"type":"user"}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`); // test missing type - assert.expectAssertion( - () => { - run(() => { - let post = store.push({ - data: { - id: '2', - type: 'post', - relationships: { - user: { - data: { - id: '1', - type: null - } - } - } - } - }); - post.get('user'); + assert.expectAssertion(() => { + run(() => { + let post = store.push({ + data: { + id: '2', + type: 'post', + relationships: { + user: { + data: { + id: '1', + type: null, + }, + }, + }, + }, }); - }, - `Assertion Failed: Encountered a relationship identifier without a type for the belongsTo relationship 'user' on , expected a json-api identifier with type 'user' but found '{"id":"1","type":null}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.` - ); + post.get('user'); + }); + }, `Assertion Failed: Encountered a relationship identifier without a type for the belongsTo relationship 'user' on , expected a json-api identifier with type 'user' but found '{"id":"1","type":null}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`); }); -testInDebug("Only a record of the same modelClass can be used with a monomorphic belongsTo relationship", function(assert) { - assert.expect(1); - env.adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - id: '1', - type: 'post' - } - }); - store.push({ - data: { - id: '2', - type: 'comment' - } +testInDebug( + 'Only a record of the same modelClass can be used with a monomorphic belongsTo relationship', + function(assert) { + assert.expect(1); + env.adapter.shouldBackgroundReloadRecord = () => false; + run(() => { + store.push({ + data: { + id: '1', + type: 'post', + }, + }); + store.push({ + data: { + id: '2', + type: 'comment', + }, + }); }); - }); - - return run(() => { - return hash({ - post: store.findRecord('post', 1), - comment: store.findRecord('comment', 2) - }).then(records => { - assert.expectAssertion(() => { - records.post.set('user', records.comment); - }, /You cannot add a record of modelClass 'comment' to the 'post.user' relationship/); + return run(() => { + return hash({ + post: store.findRecord('post', 1), + comment: store.findRecord('comment', 2), + }).then(records => { + assert.expectAssertion(() => { + records.post.set('user', records.comment); + }, /You cannot add a record of modelClass 'comment' to the 'post.user' relationship/); + }); }); - }); -}); + } +); -testInDebug("Only a record of the same base modelClass can be used with a polymorphic belongsTo relationship", function(assert) { - env.adapter.shouldBackgroundReloadRecord = () => false; - assert.expect(1); - run(() => { - store.push({ - data: [{ - id: '1', - type: 'comment' - }, - { - id: '2', - type: 'comment' - }] - }); - store.push({ - data: { - id: '1', - type: 'post' - } - }); - store.push({ - data: { - id: '3', - type: 'user' - } +testInDebug( + 'Only a record of the same base modelClass can be used with a polymorphic belongsTo relationship', + function(assert) { + env.adapter.shouldBackgroundReloadRecord = () => false; + assert.expect(1); + run(() => { + store.push({ + data: [ + { + id: '1', + type: 'comment', + }, + { + id: '2', + type: 'comment', + }, + ], + }); + store.push({ + data: { + id: '1', + type: 'post', + }, + }); + store.push({ + data: { + id: '3', + type: 'user', + }, + }); }); - }); - - return run(() => { - let asyncRecords = hash({ - user: store.findRecord('user', 3), - post: store.findRecord('post', 1), - comment: store.findRecord('comment', 1), - anotherComment: store.findRecord('comment', 2) - }); + return run(() => { + let asyncRecords = hash({ + user: store.findRecord('user', 3), + post: store.findRecord('post', 1), + comment: store.findRecord('comment', 1), + anotherComment: store.findRecord('comment', 2), + }); - return asyncRecords.then(records => { - let comment = records.comment; + return asyncRecords.then(records => { + let comment = records.comment; - comment.set('message', records.anotherComment); - comment.set('message', records.post); - comment.set('message', null); + comment.set('message', records.anotherComment); + comment.set('message', records.post); + comment.set('message', null); - assert.expectAssertion(() => { - comment.set('message', records.user); - }, /You cannot add a record of modelClass 'user' to the 'comment.message' relationship \(only 'message' allowed\)/); + assert.expectAssertion(() => { + comment.set('message', records.user); + }, /You cannot add a record of modelClass 'user' to the 'comment.message' relationship \(only 'message' allowed\)/); + }); }); - }); -}); + } +); -test("The store can load a polymorphic belongsTo association", function(assert) { +test('The store can load a polymorphic belongsTo association', function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; run(() => { env.store.push({ data: { id: '1', - type: 'post' - } + type: 'post', + }, }); env.store.push({ @@ -360,39 +385,39 @@ test("The store can load a polymorphic belongsTo association", function(assert) message: { data: { id: '1', - type: 'post' - } - } - } - } + type: 'post', + }, + }, + }, + }, }); }); return run(() => { return hash({ message: store.findRecord('post', 1), - comment: store.findRecord('comment', 2) + comment: store.findRecord('comment', 2), }).then(records => { assert.equal(records.comment.get('message'), records.message); }); }); }); -test("The store can serialize a polymorphic belongsTo association", function(assert) { +test('The store can serialize a polymorphic belongsTo association', function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; let serializerInstance = store.serializerFor('comment'); serializerInstance.serializePolymorphicType = function(record, json, relationship) { assert.ok(true, "The serializer's serializePolymorphicType method should be called"); - json["message_type"] = "post"; + json['message_type'] = 'post'; }; return run(() => { env.store.push({ data: { id: '1', - type: 'post' - } + type: 'post', + }, }); env.store.push({ @@ -403,11 +428,11 @@ test("The store can serialize a polymorphic belongsTo association", function(ass message: { data: { id: '1', - type: 'post' - } - } - } - } + type: 'post', + }, + }, + }, + }, }); return store.findRecord('comment', 2).then(comment => { @@ -418,14 +443,14 @@ test("The store can serialize a polymorphic belongsTo association", function(ass }); }); -test("A serializer can materialize a belongsTo as a link that gets sent back to findBelongsTo", function(assert) { +test('A serializer can materialize a belongsTo as a link that gets sent back to findBelongsTo', function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; let Group = DS.Model.extend({ - people: DS.hasMany('person', { async: false }) + people: DS.hasMany('person', { async: false }), }); let Person = DS.Model.extend({ - group: DS.belongsTo({ async: true }) + group: DS.belongsTo({ async: true }), }); env.registry.register('model:group', Group); @@ -439,11 +464,11 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to relationships: { group: { links: { - related: '/people/1/group' - } - } - } - } + related: '/people/1/group', + }, + }, + }, + }, }); }); @@ -454,7 +479,7 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to env.adapter.findBelongsTo = function(store, snapshot, link, relationship) { assert.equal(relationship.type, 'group'); assert.equal(relationship.key, 'group'); - assert.equal(link, "/people/1/group"); + assert.equal(link, '/people/1/group'); return resolve({ data: { @@ -462,31 +487,34 @@ test("A serializer can materialize a belongsTo as a link that gets sent back to type: 'group', relationships: { people: { - data: [{ id: 1, type: 'person' }] - } - } - } + data: [{ id: 1, type: 'person' }], + }, + }, + }, }); }; return run(() => { - return env.store.findRecord('person', 1).then(person => { - return person.get('group'); - }).then(group => { - assert.ok(group instanceof Group, "A group object is loaded"); - assert.ok(group.get('id') === '1', 'It is the group we are expecting'); - }); + return env.store + .findRecord('person', 1) + .then(person => { + return person.get('group'); + }) + .then(group => { + assert.ok(group instanceof Group, 'A group object is loaded'); + assert.ok(group.get('id') === '1', 'It is the group we are expecting'); + }); }); }); test('A record with an async belongsTo relationship always returns a promise for that relationship', function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; let Seat = DS.Model.extend({ - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); let Person = DS.Model.extend({ - seat: DS.belongsTo('seat', { async: true }) + seat: DS.belongsTo('seat', { async: true }), }); env.registry.register('model:seat', Seat); @@ -500,11 +528,11 @@ test('A record with an async belongsTo relationship always returns a promise for relationships: { seat: { links: { - related: '/people/1/seat' - } - } - } - } + related: '/people/1/seat', + }, + }, + }, + }, }); }); @@ -528,16 +556,16 @@ test('A record with an async belongsTo relationship always returns a promise for }); }); -test("A record with an async belongsTo relationship returning null should resolve null", function(assert) { +test('A record with an async belongsTo relationship returning null should resolve null', function(assert) { assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; let Group = DS.Model.extend({ - people: DS.hasMany('person', { async: false }) + people: DS.hasMany('person', { async: false }), }); let Person = DS.Model.extend({ - group: DS.belongsTo({ async: true }) + group: DS.belongsTo({ async: true }), }); env.registry.register('model:group', Group); @@ -551,11 +579,11 @@ test("A record with an async belongsTo relationship returning null should resolv relationships: { group: { links: { - related: '/people/1/group' - } - } - } - } + related: '/people/1/group', + }, + }, + }, + }, }); }); @@ -567,23 +595,26 @@ test("A record with an async belongsTo relationship returning null should resolv return resolve({ data: null }); }; - return env.store.findRecord('person', '1').then(person => { - return person.get('group'); - }).then(group => { - assert.ok(group === null, "group should be null"); - }); + return env.store + .findRecord('person', '1') + .then(person => { + return person.get('group'); + }) + .then(group => { + assert.ok(group === null, 'group should be null'); + }); }); -test("A record can be created with a resolved belongsTo promise", function(assert) { +test('A record can be created with a resolved belongsTo promise', function(assert) { assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; let Group = DS.Model.extend({ - people: DS.hasMany('person', { async: false }) + people: DS.hasMany('person', { async: false }), }); let Person = DS.Model.extend({ - group: DS.belongsTo({ async: true }) + group: DS.belongsTo({ async: true }), }); env.registry.register('model:group', Group); @@ -593,21 +624,21 @@ test("A record can be created with a resolved belongsTo promise", function(asser store.push({ data: { id: 1, - type: 'group' - } + type: 'group', + }, }); }); let groupPromise = store.findRecord('group', 1); return groupPromise.then(group => { let person = env.store.createRecord('person', { - group: groupPromise + group: groupPromise, }); assert.equal(person.get('group.content'), group); }); }); -test("polymorphic belongsTo class-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled", function(assert) { +test('polymorphic belongsTo class-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled', function(assert) { assert.expect(1); run(() => { @@ -620,7 +651,7 @@ test("polymorphic belongsTo class-checks check the superclass when MODEL_FACTORY }); }); -test("the subclass in a polymorphic belongsTo relationship is an instanceof its superclass", function(assert) { +test('the subclass in a polymorphic belongsTo relationship is an instanceof its superclass', function(assert) { setupModelFactoryInjections(false); assert.expect(1); @@ -629,8 +660,7 @@ test("the subclass in a polymorphic belongsTo relationship is an instanceof its assert.ok(comment instanceof Message, 'a comment is an instance of a message'); }); -test("relationshipsByName does not cache a factory", function(assert) { - +test('relationshipsByName does not cache a factory', function(assert) { // The model is loaded up via a container. It has relationshipsByName // called on it. let modelViaFirstFactory = store.modelFor('user'); @@ -646,25 +676,28 @@ test("relationshipsByName does not cache a factory", function(assert) { // A new store is created. env = setupStore({ user: User, - message: NewMessage + message: NewMessage, }); store = env.store; // relationshipsByName is called again. let modelViaSecondFactory = store.modelFor('user'); - let relationshipsByName = get(modelViaSecondFactory, 'relationshipsByName'); - let messageType = relationshipsByName.get('messages').type; + let relationshipsByName = get(modelViaSecondFactory, 'relationshipsByName'); + let messageType = relationshipsByName.get('messages').type; // A model is looked up in the store based on a string, via user input - let messageModelFromStore = store.modelFor('message'); + let messageModelFromStore = store.modelFor('message'); // And the model is lookup up internally via the relationship type let messageModelFromRelationType = store.modelFor(messageType); - assert.equal(messageModelFromRelationType, messageModelFromStore, - "model factory based on relationship type matches the model based on store.modelFor"); + assert.equal( + messageModelFromRelationType, + messageModelFromStore, + 'model factory based on relationship type matches the model based on store.modelFor' + ); }); -test("relationship changes shouldn’t cause async fetches", function(assert) { +test('relationship changes shouldn’t cause async fetches', function(assert) { assert.expect(2); /* Scenario: @@ -683,12 +716,12 @@ test("relationship changes shouldn’t cause async fetches", function(assert) { env.store.modelFor('post').reopen({ comments: DS.hasMany('comment', { async: true, - inverse: 'post' - }) + inverse: 'post', + }), }); env.store.modelFor('comment').reopen({ - post: DS.belongsTo('post', { async: false }) + post: DS.belongsTo('post', { async: false }), }); let comment; run(() => { @@ -698,19 +731,23 @@ test("relationship changes shouldn’t cause async fetches", function(assert) { type: 'post', relationships: { comments: { - data: [{ - id: '1', - type: 'comment' - }, { - id: '2', - type: 'comment' - }, { - id: '3', - type: 'comment' - }] - } - } - } + data: [ + { + id: '1', + type: 'comment', + }, + { + id: '2', + type: 'comment', + }, + { + id: '3', + type: 'comment', + }, + ], + }, + }, + }, }); comment = env.store.push({ @@ -721,11 +758,11 @@ test("relationship changes shouldn’t cause async fetches", function(assert) { post: { data: { id: '1', - type: 'post' - } - } - } - } + type: 'post', + }, + }, + }, + }, }); }); @@ -742,21 +779,21 @@ test("relationship changes shouldn’t cause async fetches", function(assert) { run(comment, 'destroyRecord'); }); -test("Destroying a record with an unloaded aync belongsTo association does not fetch the record", function(assert) { +test('Destroying a record with an unloaded aync belongsTo association does not fetch the record', function(assert) { assert.expect(2); let post; env.store.modelFor('message').reopen({ user: DS.hasMany('user', { - async: true - }) + async: true, + }), }); env.store.modelFor('post').reopen({ user: DS.belongsTo('user', { async: true, - inverse: 'messages' - }) + inverse: 'messages', + }), }); run(() => { @@ -768,11 +805,11 @@ test("Destroying a record with an unloaded aync belongsTo association does not f user: { data: { id: '2', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); }); @@ -789,24 +826,24 @@ test("Destroying a record with an unloaded aync belongsTo association does not f type: 'post', attributes: { title: null, - 'created-at': null + 'created-at': null, }, relationships: { user: { data: { id: '2', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }; }; run(post, 'destroyRecord'); }); -testInDebug("A sync belongsTo errors out if the record is unlaoded", function(assert) { +testInDebug('A sync belongsTo errors out if the record is unlaoded', function(assert) { let message; run(() => { message = env.store.push({ @@ -817,13 +854,12 @@ testInDebug("A sync belongsTo errors out if the record is unlaoded", function(as user: { data: { id: '2', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); - }); assert.expectAssertion(() => { @@ -831,9 +867,9 @@ testInDebug("A sync belongsTo errors out if the record is unlaoded", function(as }, /You looked up the 'user' relationship on a 'message' with id 1 but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async \(`DS.belongsTo\({ async: true }\)`\)/); }); -test("Rollbacking attributes for a deleted record restores implicit relationship - async", function(assert) { +test('Rollbacking attributes for a deleted record restores implicit relationship - async', function(assert) { Book.reopen({ - author: DS.belongsTo('author', { async: true }) + author: DS.belongsTo('author', { async: true }), }); let book, author; run(() => { @@ -842,28 +878,27 @@ test("Rollbacking attributes for a deleted record restores implicit relationship id: '1', type: 'book', attributes: { - name: "Stanley's Amazing Adventures" + name: "Stanley's Amazing Adventures", }, relationships: { author: { data: { id: '2', - type: 'author' - } - } - } - } + type: 'author', + }, + }, + }, + }, }); author = env.store.push({ data: { id: '2', type: 'author', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); - }); return run(() => { author.deleteRecord(); @@ -875,7 +910,7 @@ test("Rollbacking attributes for a deleted record restores implicit relationship }); }); -test("Rollbacking attributes for a deleted record restores implicit relationship - sync", function(assert) { +test('Rollbacking attributes for a deleted record restores implicit relationship - sync', function(assert) { let book, author; run(() => { @@ -884,17 +919,17 @@ test("Rollbacking attributes for a deleted record restores implicit relationship id: '1', type: 'book', attributes: { - name: "Stanley's Amazing Adventures" + name: "Stanley's Amazing Adventures", }, relationships: { author: { data: { id: '2', - type: 'author' - } - } - } - } + type: 'author', + }, + }, + }, + }, }); author = env.store.push({ @@ -902,13 +937,13 @@ test("Rollbacking attributes for a deleted record restores implicit relationship id: '2', type: 'author', attributes: { - name: "Stanley" - } - } + name: 'Stanley', + }, + }, }); }); - run(() =>{ + run(() => { author.deleteRecord(); author.rollbackAttributes(); }); @@ -916,23 +951,23 @@ test("Rollbacking attributes for a deleted record restores implicit relationship assert.equal(book.get('author'), author, 'Book has an author after rollback attributes'); }); -testInDebug("Passing a model as type to belongsTo should not work", function(assert) { +testInDebug('Passing a model as type to belongsTo should not work', function(assert) { assert.expect(1); assert.expectAssertion(() => { User = DS.Model.extend(); DS.Model.extend({ - user: belongsTo(User, { async: false }) + user: belongsTo(User, { async: false }), }); }, /The first argument to DS.belongsTo must be a string/); }); -test("belongsTo hasAnyRelationshipData async loaded", function(assert) { +test('belongsTo hasAnyRelationshipData async loaded', function(assert) { assert.expect(1); Book.reopen({ - author: belongsTo('author', { async: true }) + author: belongsTo('author', { async: true }), }); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -942,9 +977,9 @@ test("belongsTo hasAnyRelationshipData async loaded", function(assert) { type: 'book', attributes: { name: 'The Greatest Book' }, relationships: { - author: { data: { id: 2, type: 'author'} } - } - } + author: { data: { id: 2, type: 'author' } }, + }, + }, }); }; @@ -956,7 +991,7 @@ test("belongsTo hasAnyRelationshipData async loaded", function(assert) { }); }); -test("belongsTo hasAnyRelationshipData sync loaded", function(assert) { +test('belongsTo hasAnyRelationshipData sync loaded', function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -966,9 +1001,9 @@ test("belongsTo hasAnyRelationshipData sync loaded", function(assert) { type: 'book', attributes: { name: 'The Greatest Book' }, relationships: { - author: { data: { id: 2, type: 'author'} } - } - } + author: { data: { id: 2, type: 'author' } }, + }, + }, }); }; @@ -980,11 +1015,11 @@ test("belongsTo hasAnyRelationshipData sync loaded", function(assert) { }); }); -test("belongsTo hasAnyRelationshipData async not loaded", function(assert) { +test('belongsTo hasAnyRelationshipData async not loaded', function(assert) { assert.expect(1); Book.reopen({ - author: belongsTo('author', { async: true }) + author: belongsTo('author', { async: true }), }); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -994,9 +1029,9 @@ test("belongsTo hasAnyRelationshipData async not loaded", function(assert) { type: 'book', attributes: { name: 'The Greatest Book' }, relationships: { - author: { links: { related: 'author'} } - } - } + author: { links: { related: 'author' } }, + }, + }, }); }; @@ -1008,7 +1043,7 @@ test("belongsTo hasAnyRelationshipData async not loaded", function(assert) { }); }); -test("belongsTo hasAnyRelationshipData sync not loaded", function(assert) { +test('belongsTo hasAnyRelationshipData sync not loaded', function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -1016,10 +1051,10 @@ test("belongsTo hasAnyRelationshipData sync not loaded", function(assert) { data: { id: 1, type: 'book', - attributes: { name: 'The Greatest Book' } - } + attributes: { name: 'The Greatest Book' }, + }, }); - } + }; return run(() => { return store.findRecord('book', 1).then(book => { @@ -1029,11 +1064,11 @@ test("belongsTo hasAnyRelationshipData sync not loaded", function(assert) { }); }); -test("belongsTo hasAnyRelationshipData NOT created", function(assert) { +test('belongsTo hasAnyRelationshipData NOT created', function(assert) { assert.expect(2); Book.reopen({ - author: belongsTo('author', { async: true }) + author: belongsTo('author', { async: true }), }); run(() => { @@ -1045,7 +1080,7 @@ test("belongsTo hasAnyRelationshipData NOT created", function(assert) { book = store.createRecord('book', { name: 'The Greatest Book', - author + author, }); relationship = book._internalModel._relationships.get('author'); @@ -1054,13 +1089,13 @@ test("belongsTo hasAnyRelationshipData NOT created", function(assert) { }); }); -test("belongsTo hasAnyRelationshipData sync created", function(assert) { +test('belongsTo hasAnyRelationshipData sync created', function(assert) { assert.expect(2); run(() => { let author = store.createRecord('author'); let book = store.createRecord('book', { - name: 'The Greatest Book' + name: 'The Greatest Book', }); let relationship = book._internalModel._relationships.get('author'); @@ -1068,7 +1103,7 @@ test("belongsTo hasAnyRelationshipData sync created", function(assert) { book = store.createRecord('book', { name: 'The Greatest Book', - author + author, }); relationship = book._internalModel._relationships.get('author'); @@ -1083,11 +1118,14 @@ test("Model's belongsTo relationship should not be created during model creation user = env.store.push({ data: { id: '1', - type: 'user' - } + type: 'user', + }, }); - assert.ok(!user._internalModel._relationships.has('favouriteMessage'), 'Newly created record should not have relationships'); + assert.ok( + !user._internalModel._relationships.has('favouriteMessage'), + 'Newly created record should not have relationships' + ); }); }); @@ -1095,10 +1133,13 @@ test("Model's belongsTo relationship should be created during model creation if let message = env.store.createRecord('message'); let user = env.store.createRecord('user', { name: 'John Doe', - favouriteMessage: message + favouriteMessage: message, }); - assert.ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); + assert.ok( + user._internalModel._relationships.has('favouriteMessage'), + 'Newly created record with relationships in params passed in its constructor should have relationships' + ); }); test("Model's belongsTo relationship should be created during 'set' method", function(assert) { @@ -1108,7 +1149,10 @@ test("Model's belongsTo relationship should be created during 'set' method", fun message = env.store.createRecord('message'); user = env.store.createRecord('user'); user.set('favouriteMessage', message); - assert.ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); + assert.ok( + user._internalModel._relationships.has('favouriteMessage'), + 'Newly created record with relationships in params passed in its constructor should have relationships' + ); }); }); @@ -1118,15 +1162,18 @@ test("Model's belongsTo relationship should be created during 'get' method", fun run(() => { user = env.store.createRecord('user'); user.get('favouriteMessage'); - assert.ok(user._internalModel._relationships.has('favouriteMessage'), "Newly created record with relationships in params passed in its constructor should have relationships"); + assert.ok( + user._internalModel._relationships.has('favouriteMessage'), + 'Newly created record with relationships in params passed in its constructor should have relationships' + ); }); }); -test("Related link should be fetched when no relationship data is present", function(assert) { +test('Related link should be fetched when no relationship data is present', function(assert) { assert.expect(3); Book.reopen({ - author: DS.belongsTo('author', { async: true }) + author: DS.belongsTo('author', { async: true }), }); env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { @@ -1136,8 +1183,8 @@ test("Related link should be fetched when no relationship data is present", func data: { id: '1', type: 'author', - attributes: { name: 'This is author' } - } + attributes: { name: 'This is author' }, + }, }); }; @@ -1149,11 +1196,11 @@ test("Related link should be fetched when no relationship data is present", func relationships: { author: { links: { - related: 'author' - } - } - } - } + related: 'author', + }, + }, + }, + }, }); return book.get('author').then(author => { @@ -1162,11 +1209,11 @@ test("Related link should be fetched when no relationship data is present", func }); }); -test("Related link should take precedence over relationship data if no local record data is available", function(assert) { +test('Related link should take precedence over relationship data if no local record data is available', function(assert) { assert.expect(2); Book.reopen({ - author: DS.belongsTo('author', { async: true }) + author: DS.belongsTo('author', { async: true }), }); env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { @@ -1175,8 +1222,8 @@ test("Related link should take precedence over relationship data if no local rec data: { id: 1, type: 'author', - attributes: { name: 'This is author' } - } + attributes: { name: 'This is author' }, + }, }); }; @@ -1192,12 +1239,12 @@ test("Related link should take precedence over relationship data if no local rec relationships: { author: { links: { - related: 'author' + related: 'author', }, - data: { type: 'author', id: '1' } - } - } - } + data: { type: 'author', id: '1' }, + }, + }, + }, }); return book.get('author').then(author => { @@ -1206,14 +1253,16 @@ test("Related link should take precedence over relationship data if no local rec }); }); -test("Relationship data should take precedence over related link when local record data is available", function(assert) { +test('Relationship data should take precedence over related link when local record data is available', function(assert) { assert.expect(1); Book.reopen({ - author: DS.belongsTo('author', { async: true }) + author: DS.belongsTo('author', { async: true }), }); - env.adapter.shouldBackgroundReloadRecord = () => { return false; }; + env.adapter.shouldBackgroundReloadRecord = () => { + return false; + }; env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { assert.ok(false, "The adapter's findBelongsTo method should not be called"); }; @@ -1230,19 +1279,19 @@ test("Relationship data should take precedence over related link when local reco relationships: { author: { links: { - related: 'author' + related: 'author', }, - data: { type: 'author', id: '1' } - } - } + data: { type: 'author', id: '1' }, + }, + }, }, included: [ { id: '1', type: 'author', - attributes: { name: 'This is author' } - } - ] + attributes: { name: 'This is author' }, + }, + ], }); return book.get('author').then(author => { @@ -1251,11 +1300,11 @@ test("Relationship data should take precedence over related link when local reco }); }); -test("New related link should take precedence over local data", function(assert) { +test('New related link should take precedence over local data', function(assert) { assert.expect(3); Book.reopen({ - author: DS.belongsTo('author', { async: true }) + author: DS.belongsTo('author', { async: true }), }); env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { @@ -1265,8 +1314,8 @@ test("New related link should take precedence over local data", function(assert) data: { id: 1, type: 'author', - attributes: { name: 'This is author' } - } + attributes: { name: 'This is author' }, + }, }); }; @@ -1283,11 +1332,11 @@ test("New related link should take precedence over local data", function(assert) author: { data: { type: 'author', - id: '1' - } - } - } - } + id: '1', + }, + }, + }, + }, }); env.store.push({ @@ -1297,24 +1346,24 @@ test("New related link should take precedence over local data", function(assert) relationships: { author: { links: { - related: 'author-new-link' - } - } - } - } + related: 'author-new-link', + }, + }, + }, + }, }); - book.get('author').then((author) => { + book.get('author').then(author => { assert.equal(author.get('name'), 'This is author', 'author name is correct'); }); }); }); -test("Updated related link should take precedence over relationship data and local record data", function(assert) { +test('Updated related link should take precedence over relationship data and local record data', function(assert) { assert.expect(4); Book.reopen({ - author: DS.belongsTo('author', { async: true }) + author: DS.belongsTo('author', { async: true }), }); env.adapter.findBelongsTo = function(store, snapshot, url, relationship) { @@ -1325,9 +1374,9 @@ test("Updated related link should take precedence over relationship data and loc id: '1', type: 'author', attributes: { - name: 'This is updated author' - } - } + name: 'This is updated author', + }, + }, }); }; @@ -1343,53 +1392,55 @@ test("Updated related link should take precedence over relationship data and loc relationships: { author: { links: { - related: 'author' + related: 'author', }, - data: { type: 'author', id: '1' } - } - } + data: { type: 'author', id: '1' }, + }, + }, }, included: [ { type: 'author', id: '1', attributes: { - name: 'This is author' - } - } - ] + name: 'This is author', + }, + }, + ], }); - return book.get('author').then((author) => { - assert.equal(author.get('name'), 'This is author', 'author name is correct'); - }).then(() => { - - env.store.push({ - data: { - type: 'book', - id: '1', - relationships: { - author: { - links: { - related: 'author-updated-link' - } - } - } - } - }); + return book + .get('author') + .then(author => { + assert.equal(author.get('name'), 'This is author', 'author name is correct'); + }) + .then(() => { + env.store.push({ + data: { + type: 'book', + id: '1', + relationships: { + author: { + links: { + related: 'author-updated-link', + }, + }, + }, + }, + }); - return book.get('author').then((author) => { - assert.equal(author.get('name'), 'This is updated author', 'author name is correct'); + return book.get('author').then(author => { + assert.equal(author.get('name'), 'This is updated author', 'author name is correct'); + }); }); - }); }); }); -test("Updated identical related link should not take precedence over local data", function(assert) { +test('Updated identical related link should not take precedence over local data', function(assert) { assert.expect(2); Book.reopen({ - author: DS.belongsTo('author', { async: true }) + author: DS.belongsTo('author', { async: true }), }); env.adapter.findBelongsTo = function() { @@ -1408,49 +1459,53 @@ test("Updated identical related link should not take precedence over local data" relationships: { author: { links: { - related: 'author' + related: 'author', }, - data: { type: 'author', id: '1' } - } - } + data: { type: 'author', id: '1' }, + }, + }, }, - included: [{ - type: 'author', - id: '1', - attributes: { - name: 'This is author' - } - }] - }); - - return book.get('author').then((author) => { - assert.equal(author.get('name'), 'This is author', 'author name is correct'); - }).then(() => { - - env.store.push({ - data: { - type: 'book', + included: [ + { + type: 'author', id: '1', - relationships: { - author: { - links: { - related: 'author' - } - } - } - } - }); + attributes: { + name: 'This is author', + }, + }, + ], + }); - return book.get('author').then((author) => { + return book + .get('author') + .then(author => { assert.equal(author.get('name'), 'This is author', 'author name is correct'); + }) + .then(() => { + env.store.push({ + data: { + type: 'book', + id: '1', + relationships: { + author: { + links: { + related: 'author', + }, + }, + }, + }, + }); + + return book.get('author').then(author => { + assert.equal(author.get('name'), 'This is author', 'author name is correct'); + }); }); - }); }); }); -test("A belongsTo relationship can be reloaded using the reference if it was fetched via link", function(assert) { +test('A belongsTo relationship can be reloaded using the reference if it was fetched via link', function(assert) { Chapter.reopen({ - book: DS.belongsTo({ async: true }) + book: DS.belongsTo({ async: true }), }); env.adapter.findRecord = function() { @@ -1460,10 +1515,10 @@ test("A belongsTo relationship can be reloaded using the reference if it was fet type: 'chapter', relationships: { book: { - links: { related: '/books/1' } - } - } - } + links: { related: '/books/1' }, + }, + }, + }, }); }; @@ -1472,41 +1527,45 @@ test("A belongsTo relationship can be reloaded using the reference if it was fet data: { id: 1, type: 'book', - attributes: { name: "book title" } - } + attributes: { name: 'book title' }, + }, }); }; return run(() => { let chapter; - return store.findRecord('chapter', 1).then(_chapter => { - chapter = _chapter; + return store + .findRecord('chapter', 1) + .then(_chapter => { + chapter = _chapter; - return chapter.get('book'); - }).then(book => { - assert.equal(book.get('name'), "book title"); + return chapter.get('book'); + }) + .then(book => { + assert.equal(book.get('name'), 'book title'); - env.adapter.findBelongsTo = function() { - return resolve({ - data: { - id: 1, - type: 'book', - attributes: { name: "updated book title" } - } - }); - }; + env.adapter.findBelongsTo = function() { + return resolve({ + data: { + id: 1, + type: 'book', + attributes: { name: 'updated book title' }, + }, + }); + }; - return chapter.belongsTo('book').reload(); - }).then(book => { - assert.equal(book.get('name'), "updated book title"); - }); + return chapter.belongsTo('book').reload(); + }) + .then(book => { + assert.equal(book.get('name'), 'updated book title'); + }); }); }); -test("A synchronous belongsTo relationship can be reloaded using a reference if it was fetched via id", function(assert) { +test('A synchronous belongsTo relationship can be reloaded using a reference if it was fetched via id', function(assert) { Chapter.reopen({ - book: DS.belongsTo({ async: false }) + book: DS.belongsTo({ async: false }), }); let chapter; @@ -1517,19 +1576,19 @@ test("A synchronous belongsTo relationship can be reloaded using a reference if id: '1', relationships: { book: { - data: { type: 'book', id: '1' } - } - } - } + data: { type: 'book', id: '1' }, + }, + }, + }, }); env.store.push({ data: { type: 'book', id: '1', attributes: { - name: "book title" - } - } + name: 'book title', + }, + }, }); }); @@ -1538,24 +1597,27 @@ test("A synchronous belongsTo relationship can be reloaded using a reference if data: { id: '1', type: 'book', - attributes: { name: 'updated book title' } - } + attributes: { name: 'updated book title' }, + }, }); }; return run(() => { let book = chapter.get('book'); - assert.equal(book.get('name'), "book title"); + assert.equal(book.get('name'), 'book title'); - return chapter.belongsTo('book').reload().then(function(book) { - assert.equal(book.get('name'), "updated book title"); - }); + return chapter + .belongsTo('book') + .reload() + .then(function(book) { + assert.equal(book.get('name'), 'updated book title'); + }); }); }); -test("A belongsTo relationship can be reloaded using a reference if it was fetched via id", function(assert) { +test('A belongsTo relationship can be reloaded using a reference if it was fetched via id', function(assert) { Chapter.reopen({ - book: DS.belongsTo({ async: true }) + book: DS.belongsTo({ async: true }), }); let chapter; @@ -1566,10 +1628,10 @@ test("A belongsTo relationship can be reloaded using a reference if it was fetch id: 1, relationships: { book: { - data: { type: 'book', id: 1 } - } - } - } + data: { type: 'book', id: 1 }, + }, + }, + }, }); }); @@ -1578,54 +1640,60 @@ test("A belongsTo relationship can be reloaded using a reference if it was fetch data: { id: 1, type: 'book', - attributes: { name: "book title" } - } + attributes: { name: 'book title' }, + }, }); }; return run(() => { - return chapter.get('book').then(book => { - assert.equal(book.get('name'), "book title"); + return chapter + .get('book') + .then(book => { + assert.equal(book.get('name'), 'book title'); - env.adapter.findRecord = function() { - return resolve({ - data: { - id: 1, - type: 'book', - attributes: { name: "updated book title" } - } - }); - }; + env.adapter.findRecord = function() { + return resolve({ + data: { + id: 1, + type: 'book', + attributes: { name: 'updated book title' }, + }, + }); + }; - return chapter.belongsTo('book').reload(); - }).then(book => { - assert.equal(book.get('name'), "updated book title"); - }); + return chapter.belongsTo('book').reload(); + }) + .then(book => { + assert.equal(book.get('name'), 'updated book title'); + }); }); }); -testInDebug("A belongsTo relationship warns if malformatted data is pushed into the store", function(assert) { - assert.expectAssertion(() => { - run(() => { - let chapter = env.store.push({ - data: { - type: 'chapter', - id: 1, - relationships: { - book: { - data: { id: 1, name: 'The Gallic Wars' } - } - } - } +testInDebug( + 'A belongsTo relationship warns if malformatted data is pushed into the store', + function(assert) { + assert.expectAssertion(() => { + run(() => { + let chapter = env.store.push({ + data: { + type: 'chapter', + id: 1, + relationships: { + book: { + data: { id: 1, name: 'The Gallic Wars' }, + }, + }, + }, + }); + chapter.get('book'); }); - chapter.get('book'); - }); - }, /Encountered a relationship identifier without a type for the belongsTo relationship 'book' on , expected a json-api identifier with type 'book'/); -}); + }, /Encountered a relationship identifier without a type for the belongsTo relationship 'book' on , expected a json-api identifier with type 'book'/); + } +); test("belongsTo relationship with links doesn't trigger extra change notifications - #4942", function(assert) { Chapter.reopen({ - book: DS.belongsTo({ async: true }) + book: DS.belongsTo({ async: true }), }); run(() => { @@ -1636,11 +1704,11 @@ test("belongsTo relationship with links doesn't trigger extra change notificatio relationships: { book: { data: { type: 'book', id: '1' }, - links: { related: '/chapter/1/book' } - } - } + links: { related: '/chapter/1/book' }, + }, + }, }, - included: [{ type: 'book', id: '1' }] + included: [{ type: 'book', id: '1' }], }); }); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 4f5c0414a6b..ac4efc97327 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -2,17 +2,11 @@ import { setup as setupModelFactoryInjections, - reset as resetModelFactoryInjections + reset as resetModelFactoryInjections, } from 'dummy/tests/helpers/model-factory-injection'; import { A } from '@ember/array'; -import { - resolve, - Promise as EmberPromise, - all, - reject, - hash -} from 'rsvp'; +import { resolve, Promise as EmberPromise, all, reject, hash } from 'rsvp'; import { get } from '@ember/object'; import { run } from '@ember/runloop'; @@ -28,62 +22,62 @@ let Book, Chapter, Page; const { attr, hasMany, belongsTo } = DS; -module("integration/relationships/has_many - Has-Many Relationships", { +module('integration/relationships/has_many - Has-Many Relationships', { beforeEach() { User = DS.Model.extend({ name: attr('string'), messages: hasMany('message', { polymorphic: true, async: false }), - contacts: hasMany('user', { inverse: null, async: false }) + contacts: hasMany('user', { inverse: null, async: false }), }); Contact = DS.Model.extend({ - user: belongsTo('user', { async: false }) + user: belongsTo('user', { async: false }), }); Contact.reopenClass({ toString: () => 'Contact' }); Email = Contact.extend({ - email: attr('string') + email: attr('string'), }); Email.reopenClass({ toString: () => 'Email' }); Phone = Contact.extend({ - number: attr('string') + number: attr('string'), }); Phone.reopenClass({ toString: () => 'Phone' }); Message = DS.Model.extend({ user: belongsTo('user', { async: false }), - created_at: attr('date') + created_at: attr('date'), }); Message.reopenClass({ toString: () => 'Message' }); Post = Message.extend({ title: attr('string'), - comments: hasMany('comment', { async: false }) + comments: hasMany('comment', { async: false }), }); Post.reopenClass({ toString: () => 'Post' }); Comment = Message.extend({ body: DS.attr('string'), - message: DS.belongsTo('post', { polymorphic: true, async: true }) + message: DS.belongsTo('post', { polymorphic: true, async: true }), }); Comment.reopenClass({ toString: () => 'Comment' }); Book = DS.Model.extend({ title: attr(), - chapters: hasMany('chapter', { async: true }) + chapters: hasMany('chapter', { async: true }), }); Book.reopenClass({ toString: () => 'Book' }); Chapter = DS.Model.extend({ title: attr(), - pages: hasMany('page', { async: false }) + pages: hasMany('page', { async: false }), }); Chapter.reopenClass({ toString: () => 'Chapter' }); Page = DS.Model.extend({ number: attr('number'), - chapter: belongsTo('chapter', { async: false }) + chapter: belongsTo('chapter', { async: false }), }); Page.reopenClass({ toString: () => 'Page' }); @@ -97,7 +91,7 @@ module("integration/relationships/has_many - Has-Many Relationships", { message: Message, book: Book, chapter: Chapter, - page: Page + page: Page, }); store = env.store; @@ -105,59 +99,49 @@ module("integration/relationships/has_many - Has-Many Relationships", { afterEach() { run(env.container, 'destroy'); - } + }, }); -testInDebug("Invalid hasMany relationship identifiers throw errors", function(assert) { +testInDebug('Invalid hasMany relationship identifiers throw errors', function(assert) { assert.expect(2); let { store } = env; // test null id - assert.expectAssertion( - () => { - run(() => { - let post = store.push({ - data: { - id: '1', - type: 'post', - relationships: { - comments: { - data: [ - { id: null, type: 'comment' } - ] - } - } - } - }); - - post.get('comments'); + assert.expectAssertion(() => { + run(() => { + let post = store.push({ + data: { + id: '1', + type: 'post', + relationships: { + comments: { + data: [{ id: null, type: 'comment' }], + }, + }, + }, }); - }, - `Assertion Failed: Encountered a relationship identifier without an id for the hasMany relationship 'comments' on , expected a json-api identifier but found '{"id":null,"type":"comment"}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.` - ); + + post.get('comments'); + }); + }, `Assertion Failed: Encountered a relationship identifier without an id for the hasMany relationship 'comments' on , expected a json-api identifier but found '{"id":null,"type":"comment"}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`); // test missing type - assert.expectAssertion( - () => { - run(() => { - let post = store.push({ - data: { - id: '2', - type: 'post', - relationships: { - comments: { - data: [ - { id: '1', type: null } - ] - } - } - } - }); - post.get('comments') + assert.expectAssertion(() => { + run(() => { + let post = store.push({ + data: { + id: '2', + type: 'post', + relationships: { + comments: { + data: [{ id: '1', type: null }], + }, + }, + }, }); - }, - `Assertion Failed: Encountered a relationship identifier without a type for the hasMany relationship 'comments' on , expected a json-api identifier with type 'comment' but found '{"id":"1","type":null}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.` - ); + post.get('comments'); + }); + }, `Assertion Failed: Encountered a relationship identifier without a type for the hasMany relationship 'comments' on , expected a json-api identifier with type 'comment' but found '{"id":"1","type":null}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`); }); test("When a hasMany relationship is accessed, the adapter's findMany method should not be called if all the records in the relationship are already loaded", function(assert) { @@ -168,11 +152,9 @@ test("When a hasMany relationship is accessed, the adapter's findMany method sho id: '1', relationships: { comments: { - data: [ - { type: 'comment', id: '1' } - ] - } - } + data: [{ type: 'comment', id: '1' }], + }, + }, }; env.adapter.findMany = function(store, type, ids, snapshots) { @@ -186,10 +168,12 @@ test("When a hasMany relationship is accessed, the adapter's findMany method sho return run(() => { env.store.push({ data: postData, - included: [{ - type: 'comment', - id: '1' - }] + included: [ + { + type: 'comment', + id: '1', + }, + ], }); return env.store.findRecord('post', 1).then(post => { @@ -198,33 +182,33 @@ test("When a hasMany relationship is accessed, the adapter's findMany method sho }); }); -test("hasMany + canonical vs currentState + destroyRecord ", function(assert) { +test('hasMany + canonical vs currentState + destroyRecord ', function(assert) { assert.expect(6); let postData = { type: 'user', id: '1', attributes: { - name: 'omg' + name: 'omg', }, relationships: { contacts: { data: [ { type: 'user', - id: 2 + id: 2, }, { type: 'user', - id: 3 + id: 3, }, { type: 'user', - id: 4 - } - ] - } - } + id: 4, + }, + ], + }, + }, }; run(() => { @@ -233,17 +217,17 @@ test("hasMany + canonical vs currentState + destroyRecord ", function(assert) { included: [ { type: 'user', - id: 2 + id: 2, }, { type: 'user', - id: 3 + id: 3, }, { type: 'user', - id: 4 - } - ] + id: 4, + }, + ], }); }); @@ -254,7 +238,11 @@ test("hasMany + canonical vs currentState + destroyRecord ", function(assert) { return { data: { type: 'user', id: 2 } }; }; - assert.deepEqual(contacts.map(c => c.get('id')), ['2','3','4'], 'user should have expected contacts'); + assert.deepEqual( + contacts.map(c => c.get('id')), + ['2', '3', '4'], + 'user should have expected contacts' + ); run(() => { contacts.addObject(env.store.createRecord('user', { id: 5 })); @@ -262,51 +250,63 @@ test("hasMany + canonical vs currentState + destroyRecord ", function(assert) { contacts.addObject(env.store.createRecord('user', { id: 7 })); }); - assert.deepEqual(contacts.map(c => c.get('id')), ['2','3','4','5','6','7'], 'user should have expected contacts'); + assert.deepEqual( + contacts.map(c => c.get('id')), + ['2', '3', '4', '5', '6', '7'], + 'user should have expected contacts' + ); run(() => { env.store.peekRecord('user', 2).destroyRecord(); env.store.peekRecord('user', 6).destroyRecord(); }); - assert.deepEqual(contacts.map(c => c.get('id')), ['3','4','5','7'], `user's contacts should have expected contacts`); + assert.deepEqual( + contacts.map(c => c.get('id')), + ['3', '4', '5', '7'], + `user's contacts should have expected contacts` + ); assert.equal(contacts, user.get('contacts')); run(() => { contacts.addObject(env.store.createRecord('user', { id: 8 })); }); - assert.deepEqual(contacts.map(c => c.get('id')), ['3','4','5','7','8'], `user's contacts should have expected contacts`); + assert.deepEqual( + contacts.map(c => c.get('id')), + ['3', '4', '5', '7', '8'], + `user's contacts should have expected contacts` + ); assert.equal(contacts, user.get('contacts')); }); -test("hasMany + canonical vs currentState + unloadRecord", function(assert) { +test('hasMany + canonical vs currentState + unloadRecord', function(assert) { assert.expect(6); let postData = { type: 'user', id: '1', attributes: { - name: 'omg' + name: 'omg', }, relationships: { contacts: { data: [ { type: 'user', - id: 2 + id: 2, }, { type: 'user', - id: 3 + id: 3, }, { type: 'user', - id: 4 - } - ] - } - } + id: 4, + }, + ], + }, + }, }; run(() => { @@ -315,17 +315,17 @@ test("hasMany + canonical vs currentState + unloadRecord", function(assert) { included: [ { type: 'user', - id: 2 + id: 2, }, { type: 'user', - id: 3 + id: 3, }, { type: 'user', - id: 4 - } - ] + id: 4, + }, + ], }); }); @@ -336,7 +336,11 @@ test("hasMany + canonical vs currentState + unloadRecord", function(assert) { return { data: { type: 'user', id: 2 } }; }; - assert.deepEqual(contacts.map(c => c.get('id')), ['2','3','4'], 'user should have expected contacts'); + assert.deepEqual( + contacts.map(c => c.get('id')), + ['2', '3', '4'], + 'user should have expected contacts' + ); run(() => { contacts.addObject(env.store.createRecord('user', { id: 5 })); @@ -344,25 +348,37 @@ test("hasMany + canonical vs currentState + unloadRecord", function(assert) { contacts.addObject(env.store.createRecord('user', { id: 7 })); }); - assert.deepEqual(contacts.map(c => c.get('id')), ['2','3','4','5','6','7'], 'user should have expected contacts'); + assert.deepEqual( + contacts.map(c => c.get('id')), + ['2', '3', '4', '5', '6', '7'], + 'user should have expected contacts' + ); run(() => { env.store.peekRecord('user', 2).unloadRecord(); env.store.peekRecord('user', 6).unloadRecord(); }); - assert.deepEqual(contacts.map(c => c.get('id')), ['3','4','5','7'], `user's contacts should have expected contacts`); + assert.deepEqual( + contacts.map(c => c.get('id')), + ['3', '4', '5', '7'], + `user's contacts should have expected contacts` + ); assert.equal(contacts, user.get('contacts')); run(() => { contacts.addObject(env.store.createRecord('user', { id: 8 })); }); - assert.deepEqual(contacts.map(c => c.get('id')), ['3','4','5','7','8'], `user's contacts should have expected contacts`); + assert.deepEqual( + contacts.map(c => c.get('id')), + ['3', '4', '5', '7', '8'], + `user's contacts should have expected contacts` + ); assert.equal(contacts, user.get('contacts')); }); -test("adapter.findMany only gets unique IDs even if duplicate IDs are present in the hasMany relationship", function(assert) { +test('adapter.findMany only gets unique IDs even if duplicate IDs are present in the hasMany relationship', function(assert) { assert.expect(2); let bookData = { @@ -373,10 +389,10 @@ test("adapter.findMany only gets unique IDs even if duplicate IDs are present in data: [ { type: 'chapter', id: '2' }, { type: 'chapter', id: '3' }, - { type: 'chapter', id: '3' } - ] - } - } + { type: 'chapter', id: '3' }, + ], + }, + }, }; env.adapter.findMany = function(store, type, ids, snapshots) { @@ -386,8 +402,8 @@ test("adapter.findMany only gets unique IDs even if duplicate IDs are present in return resolve({ data: [ { id: 2, type: 'chapter', attributes: { title: 'Chapter One' } }, - { id: 3, type: 'chapter', attributes: { title: 'Chapter Two' } } - ] + { id: 3, type: 'chapter', attributes: { title: 'Chapter Two' } }, + ], }); }; @@ -397,7 +413,7 @@ test("adapter.findMany only gets unique IDs even if duplicate IDs are present in return run(() => { env.store.push({ - data: bookData + data: bookData, }); return env.store.findRecord('book', 1).then(book => { @@ -412,14 +428,14 @@ test("adapter.findMany only gets unique IDs even if duplicate IDs are present in // is loaded later. test("A serializer can materialize a hasMany as an opaque token that can be lazily fetched via the adapter's findHasMany hook", function(assert) { Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); // When the store asks the adapter for the record with ID 1, // provide some fake data. env.adapter.findRecord = function(store, type, id, snapshot) { - assert.equal(type, Post, "find type was Post"); - assert.equal(id, "1", "find id was 1"); + assert.equal(type, Post, 'find type was Post'); + assert.equal(id, '1', 'find id was 1'); return resolve({ data: { @@ -428,11 +444,11 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi relationships: { comments: { links: { - related: "/posts/1/comments" - } - } - } - } + related: '/posts/1/comments', + }, + }, + }, + }, }); }; //({ id: 1, links: { comments: "/posts/1/comments" } }); @@ -442,37 +458,40 @@ test("A serializer can materialize a hasMany as an opaque token that can be lazi }; env.adapter.findHasMany = function(store, snapshot, link, relationship) { - assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); - assert.equal(relationship.type, "comment", "relationship was passed correctly"); + assert.equal(link, '/posts/1/comments', 'findHasMany link was /posts/1/comments'); + assert.equal(relationship.type, 'comment', 'relationship was passed correctly'); return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "First" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ] + { id: 1, type: 'comment', attributes: { body: 'First' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], }); }; return run(() => { - return env.store.findRecord('post', 1).then(post => { - return post.get('comments'); - }).then(comments => { - assert.equal(comments.get('isLoaded'), true, "comments are loaded"); - assert.equal(comments.get('length'), 2, "comments have 2 length"); - assert.equal(comments.objectAt(0).get('body'), 'First', "comment loaded successfully"); - }); + return env.store + .findRecord('post', 1) + .then(post => { + return post.get('comments'); + }) + .then(comments => { + assert.equal(comments.get('isLoaded'), true, 'comments are loaded'); + assert.equal(comments.get('length'), 2, 'comments have 2 length'); + assert.equal(comments.objectAt(0).get('body'), 'First', 'comment loaded successfully'); + }); }); }); -test("Accessing a hasMany backed by a link multiple times triggers only one request", function(assert) { +test('Accessing a hasMany backed by a link multiple times triggers only one request', function(assert) { assert.expect(2); let count = 0; Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); Comment.reopen({ - message: DS.belongsTo('post', { async: true }) + message: DS.belongsTo('post', { async: true }), }); let post; @@ -484,25 +503,25 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ relationships: { comments: { links: { - related: '/posts/1/comments' - } - } - } - } + related: '/posts/1/comments', + }, + }, + }, + }, }); post = env.store.peekRecord('post', 1); }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { count++; - assert.equal(count, 1, "findHasMany has only been called once"); + assert.equal(count, 1, 'findHasMany has only been called once'); return new EmberPromise((resolve, reject) => { setTimeout(() => { let value = { data: [ - { id: 1, type: 'comment', attributes: { body: "First" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ] + { id: 1, type: 'comment', attributes: { body: 'First' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], }; resolve(value); }, 100); @@ -520,38 +539,39 @@ test("Accessing a hasMany backed by a link multiple times triggers only one requ id: '1', relationships: { message: { - data: { type: 'post', id: '1' } - } - } - } + data: { type: 'post', id: '1' }, + }, + }, + }, }); promise2 = post.get('comments'); }); - return all([ - promise1, - promise2 - ]).then(() => { - assert.equal(promise1.get('promise'), promise2.get('promise'), "Same promise is returned both times"); - }) + return all([promise1, promise2]).then(() => { + assert.equal( + promise1.get('promise'), + promise2.get('promise'), + 'Same promise is returned both times' + ); + }); }); -test("A hasMany backed by a link remains a promise after a record has been added to it", function(assert) { +test('A hasMany backed by a link remains a promise after a record has been added to it', function(assert) { assert.expect(1); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); Comment.reopen({ - message: DS.belongsTo('post', { async: true }) + message: DS.belongsTo('post', { async: true }), }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "First" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ] + { id: 1, type: 'comment', attributes: { body: 'First' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], }); }; let post; @@ -563,11 +583,11 @@ test("A hasMany backed by a link remains a promise after a record has been added relationships: { comments: { links: { - related: '/posts/1/comments' - } - } - } - } + related: '/posts/1/comments', + }, + }, + }, + }, }); post = env.store.peekRecord('post', 1); }); @@ -580,10 +600,10 @@ test("A hasMany backed by a link remains a promise after a record has been added id: '3', relationships: { message: { - data: { type: 'post', id: '1' } - } - } - } + data: { type: 'post', id: '1' }, + }, + }, + }, }); return post.get('comments').then(() => { @@ -593,13 +613,13 @@ test("A hasMany backed by a link remains a promise after a record has been added }); }); -test("A hasMany updated link should not remove new children", function(assert) { +test('A hasMany updated link should not remove new children', function(assert) { Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); Comment.reopen({ - message: DS.belongsTo('post', { async: true }) + message: DS.belongsTo('post', { async: true }), }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { @@ -613,10 +633,10 @@ test("A hasMany updated link should not remove new children", function(assert) { type: 'post', relationships: { comments: { - links: { related: '/some/link' } - } - } - } + links: { related: '/some/link' }, + }, + }, + }, }); }; @@ -624,7 +644,8 @@ test("A hasMany updated link should not remove new children", function(assert) { let post = env.store.createRecord('post', {}); env.store.createRecord('comment', { message: post }); - return post.get('comments') + return post + .get('comments') .then(comments => { assert.equal(comments.get('length'), 1, 'initially we have one comment'); @@ -637,19 +658,19 @@ test("A hasMany updated link should not remove new children", function(assert) { }); }); -test("A hasMany updated link should not remove new children when the parent record has children already", function(assert) { +test('A hasMany updated link should not remove new children when the parent record has children already', function(assert) { Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); Comment.reopen({ - message: DS.belongsTo('post', { async: true }) + message: DS.belongsTo('post', { async: true }), }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return resolve({ data: [ - { id: 5, type: 'comment', attributes: { body: 'hello' } } - ]}); + return resolve({ + data: [{ id: 5, type: 'comment', attributes: { body: 'hello' } }], + }); }; env.adapter.createRecord = function(store, snapshot, link, relationship) { @@ -659,10 +680,10 @@ test("A hasMany updated link should not remove new children when the parent reco type: 'post', relationships: { comments: { - links: { related: '/some/link' } - } - } - } + links: { related: '/some/link' }, + }, + }, + }, }); }; @@ -670,12 +691,13 @@ test("A hasMany updated link should not remove new children when the parent reco let post = env.store.createRecord('post', {}); env.store.createRecord('comment', { message: post }); - return post.get('comments') + return post + .get('comments') .then(comments => { assert.equal(comments.get('length'), 1); return post.save(); }) - .then(() =>post.get('comments')) + .then(() => post.get('comments')) .then(comments => { assert.equal(comments.get('length'), 2); }); @@ -683,13 +705,12 @@ test("A hasMany updated link should not remove new children when the parent reco }); test("A hasMany relationship doesn't contain duplicate children, after the canonical state of the relationship is updated via store#push", function(assert) { - Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); Comment.reopen({ - message: DS.belongsTo('post', { async: true }) + message: DS.belongsTo('post', { async: true }), }); env.adapter.createRecord = function(store, snapshot, link, relationship) { @@ -703,7 +724,8 @@ test("A hasMany relationship doesn't contain duplicate children, after the canon // relationship of post let localComment = env.store.createRecord('comment', { id: 'local', message: post }); - return post.get('comments') + return post + .get('comments') .then(comments => { assert.equal(comments.get('length'), 1); assert.equal(localComment.get('isNew'), true); @@ -711,7 +733,6 @@ test("A hasMany relationship doesn't contain duplicate children, after the canon return post.save(); }) .then(() => { - // Now the post is saved but the locally created comment with the id // 'local' is still in the created state since it hasn't been saved // yet. @@ -730,14 +751,11 @@ test("A hasMany relationship doesn't contain duplicate children, after the canon id: 1, relationships: { comments: { - data: [ - { id: 'local', type: 'comment' } - ] - } - } - } + data: [{ id: 'local', type: 'comment' }], + }, + }, + }, }); - }) .then(() => post.get('comments')) .then(comments => { @@ -747,15 +765,14 @@ test("A hasMany relationship doesn't contain duplicate children, after the canon }); }); - -test("A hasMany relationship can be reloaded if it was fetched via a link", function(assert) { +test('A hasMany relationship can be reloaded if it was fetched via a link', function(assert) { Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); env.adapter.findRecord = function(store, type, id, snapshot) { - assert.equal(type, Post, "find type was Post"); - assert.equal(id, "1", "find id was 1"); + assert.equal(type, Post, 'find type was Post'); + assert.equal(id, '1', 'find id was 1'); return resolve({ data: { @@ -763,58 +780,65 @@ test("A hasMany relationship can be reloaded if it was fetched via a link", func type: 'post', relationships: { comments: { - links: { related: "/posts/1/comments" } - } - } - } + links: { related: '/posts/1/comments' }, + }, + }, + }, }); }; env.adapter.findHasMany = function(store, snapshot, link, relationship) { - assert.equal(relationship.type, 'comment', "findHasMany relationship type was Comment"); - assert.equal(relationship.key, 'comments', "findHasMany relationship key was comments"); - assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); + assert.equal(relationship.type, 'comment', 'findHasMany relationship type was Comment'); + assert.equal(relationship.key, 'comments', 'findHasMany relationship key was comments'); + assert.equal(link, '/posts/1/comments', 'findHasMany link was /posts/1/comments'); - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "First" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ]}); + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'First' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); }; run(function() { - run(env.store, 'findRecord', 'post', 1).then(function(post) { - return post.get('comments'); - }).then(function(comments) { - assert.equal(comments.get('isLoaded'), true, "comments are loaded"); - assert.equal(comments.get('length'), 2, "comments have 2 length"); + run(env.store, 'findRecord', 'post', 1) + .then(function(post) { + return post.get('comments'); + }) + .then(function(comments) { + assert.equal(comments.get('isLoaded'), true, 'comments are loaded'); + assert.equal(comments.get('length'), 2, 'comments have 2 length'); - env.adapter.findHasMany = function(store, snapshot, link, relationship) { - assert.equal(relationship.type, 'comment', "findHasMany relationship type was Comment"); - assert.equal(relationship.key, 'comments', "findHasMany relationship key was comments"); - assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); + env.adapter.findHasMany = function(store, snapshot, link, relationship) { + assert.equal(relationship.type, 'comment', 'findHasMany relationship type was Comment'); + assert.equal(relationship.key, 'comments', 'findHasMany relationship key was comments'); + assert.equal(link, '/posts/1/comments', 'findHasMany link was /posts/1/comments'); - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "First" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } }, - { id: 3, type: 'comment', attributes: { body: "Thirds" } } - ]}); - }; + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'First' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + { id: 3, type: 'comment', attributes: { body: 'Thirds' } }, + ], + }); + }; - return comments.reload(); - }).then(function(newComments) { - assert.equal(newComments.get('length'), 3, "reloaded comments have 3 length"); - }); + return comments.reload(); + }) + .then(function(newComments) { + assert.equal(newComments.get('length'), 3, 'reloaded comments have 3 length'); + }); }); }); -test("A sync hasMany relationship can be reloaded if it was fetched via ids", function(assert) { +test('A sync hasMany relationship can be reloaded if it was fetched via ids', function(assert) { Post.reopen({ - comments: DS.hasMany('comment', { async: false }) + comments: DS.hasMany('comment', { async: false }), }); env.adapter.findRecord = function(store, type, id, snapshot) { - assert.equal(type, Post, "find type was Post"); - assert.equal(id, "1", "find id was 1"); + assert.equal(type, Post, 'find type was Post'); + assert.equal(id, '1', 'find id was 1'); return resolve({ data: { @@ -822,60 +846,69 @@ test("A sync hasMany relationship can be reloaded if it was fetched via ids", fu type: 'post', relationships: { comments: { - data: [ - { id: 1, type: 'comment' }, - { id: 2, type: 'comment' } - ] - } - } - } + data: [{ id: 1, type: 'comment' }, { id: 2, type: 'comment' }], + }, + }, + }, }); }; run(function() { env.store.push({ - data: [{ - type: 'comment', - id: '1', - attributes: { - body: 'First' - } - }, { - type: 'comment', - id: '2', - attributes: { - body: 'Second' - } - }] + data: [ + { + type: 'comment', + id: '1', + attributes: { + body: 'First', + }, + }, + { + type: 'comment', + id: '2', + attributes: { + body: 'Second', + }, + }, + ], }); - env.store.findRecord('post', '1').then(function(post) { - let comments = post.get('comments'); - assert.equal(comments.get('isLoaded'), true, "comments are loaded"); - assert.equal(comments.get('length'), 2, "comments have a length of 2"); + env.store + .findRecord('post', '1') + .then(function(post) { + let comments = post.get('comments'); + assert.equal(comments.get('isLoaded'), true, 'comments are loaded'); + assert.equal(comments.get('length'), 2, 'comments have a length of 2'); - env.adapter.findMany = function(store, type, ids, snapshots) { - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ]}); - }; + env.adapter.findMany = function(store, type, ids, snapshots) { + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'FirstUpdated' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); + }; - return comments.reload(); - }).then(function(newComments) { - assert.equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); - }); + return comments.reload(); + }) + .then(function(newComments) { + assert.equal( + newComments.get('firstObject.body'), + 'FirstUpdated', + 'Record body was correctly updated' + ); + }); }); }); -test("A hasMany relationship can be reloaded if it was fetched via ids", function(assert) { +test('A hasMany relationship can be reloaded if it was fetched via ids', function(assert) { Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); env.adapter.findRecord = function(store, type, id, snapshot) { - assert.equal(type, Post, "find type was Post"); - assert.equal(id, "1", "find id was 1"); + assert.equal(type, Post, 'find type was Post'); + assert.equal(id, '1', 'find id was 1'); return resolve({ data: { @@ -883,46 +916,58 @@ test("A hasMany relationship can be reloaded if it was fetched via ids", functio type: 'post', relationships: { comments: { - data: [{ id: 1, type: 'comment' }, { id: 2, type: 'comment' }] - } - } - } + data: [{ id: 1, type: 'comment' }, { id: 2, type: 'comment' }], + }, + }, + }, }); }; env.adapter.findMany = function(store, type, ids, snapshots) { - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "First" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ]}); + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'First' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); }; run(function() { - env.store.findRecord('post', 1).then(function(post) { - return post.get('comments'); - }).then(function(comments) { - assert.equal(comments.get('isLoaded'), true, "comments are loaded"); - assert.equal(comments.get('length'), 2, "comments have 2 length"); + env.store + .findRecord('post', 1) + .then(function(post) { + return post.get('comments'); + }) + .then(function(comments) { + assert.equal(comments.get('isLoaded'), true, 'comments are loaded'); + assert.equal(comments.get('length'), 2, 'comments have 2 length'); - env.adapter.findMany = function(store, type, ids, snapshots) { - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ]}); - }; + env.adapter.findMany = function(store, type, ids, snapshots) { + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'FirstUpdated' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); + }; - return comments.reload(); - }).then(function(newComments) { - assert.equal(newComments.get('firstObject.body'), 'FirstUpdated', "Record body was correctly updated"); - }); + return comments.reload(); + }) + .then(function(newComments) { + assert.equal( + newComments.get('firstObject.body'), + 'FirstUpdated', + 'Record body was correctly updated' + ); + }); }); }); -test("A hasMany relationship can be reloaded even if it failed at the first time", function(assert) { +test('A hasMany relationship can be reloaded even if it failed at the first time', function(assert) { assert.expect(4); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); env.adapter.findRecord = function(store, type, id) { @@ -932,10 +977,10 @@ test("A hasMany relationship can be reloaded even if it failed at the first time type: 'post', relationships: { comments: { - links: { related: "/posts/1/comments" } - } - } - } + links: { related: '/posts/1/comments' }, + }, + }, + }, }); }; @@ -945,41 +990,57 @@ test("A hasMany relationship can be reloaded even if it failed at the first time if (loadingCount % 2 === 0) { return reject(); } else { - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ]}); + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'FirstUpdated' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); } }; run(function() { env.store.findRecord('post', 1).then(function(post) { let comments = post.get('comments'); - return comments.catch(function() { - return comments.reload(); - }).then(function(manyArray) { - assert.equal(manyArray.get('isLoaded'), true, "the reload worked, comments are now loaded"); - return manyArray.reload().catch(function () { - assert.equal(manyArray.get('isLoaded'), true, "the second reload failed, comments are still loaded though"); - return manyArray.reload().then(function(reloadedManyArray) { - assert.equal(reloadedManyArray.get('isLoaded'), true, "the third reload worked, comments are loaded again"); - assert.ok(reloadedManyArray === manyArray, "the many array stays the same"); + return comments + .catch(function() { + return comments.reload(); + }) + .then(function(manyArray) { + assert.equal( + manyArray.get('isLoaded'), + true, + 'the reload worked, comments are now loaded' + ); + return manyArray.reload().catch(function() { + assert.equal( + manyArray.get('isLoaded'), + true, + 'the second reload failed, comments are still loaded though' + ); + return manyArray.reload().then(function(reloadedManyArray) { + assert.equal( + reloadedManyArray.get('isLoaded'), + true, + 'the third reload worked, comments are loaded again' + ); + assert.ok(reloadedManyArray === manyArray, 'the many array stays the same'); + }); }); }); - }); }); }); }); -test("A hasMany relationship can be directly reloaded if it was fetched via links", function(assert) { +test('A hasMany relationship can be directly reloaded if it was fetched via links', function(assert) { assert.expect(6); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); env.adapter.findRecord = function(store, type, id) { - assert.equal(type, Post, "find type was Post"); - assert.equal(id, "1", "find id was 1"); + assert.equal(type, Post, 'find type was Post'); + assert.equal(id, '1', 'find id was 1'); return resolve({ data: { @@ -987,38 +1048,47 @@ test("A hasMany relationship can be directly reloaded if it was fetched via link type: 'post', relationships: { comments: { - links: { related: "/posts/1/comments" } - } - } - } + links: { related: '/posts/1/comments' }, + }, + }, + }, }); }; env.adapter.findHasMany = function(store, record, link, relationship) { - assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); + assert.equal(link, '/posts/1/comments', 'findHasMany link was /posts/1/comments'); - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ]}); + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'FirstUpdated' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); }; run(function() { env.store.findRecord('post', 1).then(function(post) { - return post.get('comments').reload().then(function(comments) { - assert.equal(comments.get('isLoaded'), true, "comments are loaded"); - assert.equal(comments.get('length'), 2, "comments have 2 length"); - assert.equal(comments.get('firstObject.body'), "FirstUpdated", "Record body was correctly updated"); - }); + return post + .get('comments') + .reload() + .then(function(comments) { + assert.equal(comments.get('isLoaded'), true, 'comments are loaded'); + assert.equal(comments.get('length'), 2, 'comments have 2 length'); + assert.equal( + comments.get('firstObject.body'), + 'FirstUpdated', + 'Record body was correctly updated' + ); + }); }); }); }); -test("Has many via links - Calling reload multiple times does not send a new request if the first one is not settled", function(assert) { +test('Has many via links - Calling reload multiple times does not send a new request if the first one is not settled', function(assert) { assert.expect(1); let done = assert.async(); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); env.adapter.findRecord = function(store, type, id) { @@ -1028,26 +1098,32 @@ test("Has many via links - Calling reload multiple times does not send a new req type: 'post', relationships: { comments: { - links: { related: "/posts/1/comments" } - } - } - } + links: { related: '/posts/1/comments' }, + }, + }, + }, }); }; let count = 0; env.adapter.findHasMany = function(store, record, link, relationship) { count++; - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "First" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ]}); + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'First' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); }; run(function() { env.store.findRecord('post', 1).then(function(post) { post.get('comments').then(function(comments) { all([comments.reload(), comments.reload(), comments.reload()]).then(function(comments) { - assert.equal(count, 2, "One request for the original access and only one request for the mulitple reloads"); + assert.equal( + count, + 2, + 'One request for the original access and only one request for the mulitple reloads' + ); done(); }); }); @@ -1055,14 +1131,14 @@ test("Has many via links - Calling reload multiple times does not send a new req }); }); -test("A hasMany relationship can be directly reloaded if it was fetched via ids", function(assert) { +test('A hasMany relationship can be directly reloaded if it was fetched via ids', function(assert) { Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); env.adapter.findRecord = function(store, type, id, snapshot) { - assert.equal(type, Post, "find type was Post"); - assert.equal(id, "1", "find id was 1"); + assert.equal(type, Post, 'find type was Post'); + assert.equal(id, '1', 'find id was 1'); return resolve({ data: { @@ -1070,37 +1146,46 @@ test("A hasMany relationship can be directly reloaded if it was fetched via ids" type: 'post', relationships: { comments: { - data: [{ id: 1, type: 'comment' }, { id: 2, type: 'comment' }] - } - } - } + data: [{ id: 1, type: 'comment' }, { id: 2, type: 'comment' }], + }, + }, + }, }); }; env.adapter.findMany = function(store, type, ids, snapshots) { - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ]}); + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'FirstUpdated' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); }; run(function() { env.store.findRecord('post', 1).then(function(post) { - return post.get('comments').reload().then(function(comments) { - assert.equal(comments.get('isLoaded'), true, "comments are loaded"); - assert.equal(comments.get('length'), 2, "comments have 2 length"); - assert.equal(comments.get('firstObject.body'), "FirstUpdated", "Record body was correctly updated"); - }); + return post + .get('comments') + .reload() + .then(function(comments) { + assert.equal(comments.get('isLoaded'), true, 'comments are loaded'); + assert.equal(comments.get('length'), 2, 'comments have 2 length'); + assert.equal( + comments.get('firstObject.body'), + 'FirstUpdated', + 'Record body was correctly updated' + ); + }); }); }); }); -test("Has many via ids - Calling reload multiple times does not send a new request if the first one is not settled", function(assert) { +test('Has many via ids - Calling reload multiple times does not send a new request if the first one is not settled', function(assert) { assert.expect(1); let done = assert.async(); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -1110,27 +1195,33 @@ test("Has many via ids - Calling reload multiple times does not send a new reque type: 'post', relationships: { comments: { - data: [{ id: 1, type: 'comment' }, { id: 2, type: 'comment' }] - } - } - } + data: [{ id: 1, type: 'comment' }, { id: 2, type: 'comment' }], + }, + }, + }, }); }; let count = 0; env.adapter.findMany = function(store, type, ids, snapshots) { count++; - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "FirstUpdated" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ]}); + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'FirstUpdated' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); }; run(function() { env.store.findRecord('post', 1).then(function(post) { post.get('comments').then(function(comments) { all([comments.reload(), comments.reload(), comments.reload()]).then(function(comments) { - assert.equal(count, 2, "One request for the original access and only one request for the mulitple reloads"); + assert.equal( + count, + 2, + 'One request for the original access and only one request for the mulitple reloads' + ); done(); }); }); @@ -1138,18 +1229,20 @@ test("Has many via ids - Calling reload multiple times does not send a new reque }); }); -test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loaded", function(assert) { +test('PromiseArray proxies createRecord to its ManyArray once the hasMany is loaded', function(assert) { assert.expect(4); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "First" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ]}); + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'First' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); }; let post; @@ -1161,39 +1254,41 @@ test("PromiseArray proxies createRecord to its ManyArray once the hasMany is loa relationships: { comments: { links: { - related: 'someLink' - } - } - } - } + related: 'someLink', + }, + }, + }, + }, }); post = env.store.peekRecord('post', 1); }); run(function() { post.get('comments').then(function(comments) { - assert.equal(comments.get('isLoaded'), true, "comments are loaded"); - assert.equal(comments.get('length'), 2, "comments have 2 length"); + assert.equal(comments.get('isLoaded'), true, 'comments are loaded'); + assert.equal(comments.get('length'), 2, 'comments have 2 length'); let newComment = post.get('comments').createRecord({ body: 'Third' }); - assert.equal(newComment.get('body'), 'Third', "new comment is returned"); - assert.equal(comments.get('length'), 3, "comments have 3 length, including new record"); + assert.equal(newComment.get('body'), 'Third', 'new comment is returned'); + assert.equal(comments.get('length'), 3, 'comments have 3 length, including new record'); }); }); }); -test("PromiseArray proxies evented methods to its ManyArray", function(assert) { +test('PromiseArray proxies evented methods to its ManyArray', function(assert) { assert.expect(6); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "First" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ]}); + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'First' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); }; let post, comments; @@ -1205,17 +1300,16 @@ test("PromiseArray proxies evented methods to its ManyArray", function(assert) { relationships: { comments: { links: { - related: 'someLink' - } - } - } - } + related: 'someLink', + }, + }, + }, + }, }); post = env.store.peekRecord('post', 1); comments = post.get('comments'); }); - comments.on('on-event', function() { assert.ok(true); }); @@ -1247,26 +1341,30 @@ test("PromiseArray proxies evented methods to its ManyArray", function(assert) { assert.equal(comments.has('one-event'), false); }); -test("An updated `links` value should invalidate a relationship cache", function(assert) { +test('An updated `links` value should invalidate a relationship cache', function(assert) { assert.expect(8); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - assert.equal(relationship.type, "comment", "relationship was passed correctly"); + assert.equal(relationship.type, 'comment', 'relationship was passed correctly'); if (link === '/first') { - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "First" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ]}); + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'First' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); } else if (link === '/second') { - return resolve({ data: [ - { id: 3, type: 'comment', attributes: { body: "Third" } }, - { id: 4, type: 'comment', attributes: { body: "Fourth" } }, - { id: 5, type: 'comment', attributes: { body: "Fifth" } } - ]}); + return resolve({ + data: [ + { id: 3, type: 'comment', attributes: { body: 'Third' } }, + { id: 4, type: 'comment', attributes: { body: 'Fourth' } }, + { id: 5, type: 'comment', attributes: { body: 'Fifth' } }, + ], + }); } }; let post; @@ -1279,20 +1377,20 @@ test("An updated `links` value should invalidate a relationship cache", function relationships: { comments: { links: { - related: '/first' - } - } - } - } - }); - post = env.store.peekRecord('post', 1); + related: '/first', + }, + }, + }, + }, + }); + post = env.store.peekRecord('post', 1); }); run(function() { post.get('comments').then(function(comments) { - assert.equal(comments.get('isLoaded'), true, "comments are loaded"); - assert.equal(comments.get('length'), 2, "comments have 2 length"); - assert.equal(comments.objectAt(0).get('body'), 'First', "comment 1 successfully loaded"); + assert.equal(comments.get('isLoaded'), true, 'comments are loaded'); + assert.equal(comments.get('length'), 2, 'comments have 2 length'); + assert.equal(comments.objectAt(0).get('body'), 'First', 'comment 1 successfully loaded'); env.store.push({ data: { type: 'post', @@ -1300,16 +1398,20 @@ test("An updated `links` value should invalidate a relationship cache", function relationships: { comments: { links: { - related: '/second' - } - } - } - } + related: '/second', + }, + }, + }, + }, }); post.get('comments').then(function(newComments) { - assert.equal(comments, newComments, "hasMany array was kept the same"); - assert.equal(newComments.get('length'), 3, "comments updated successfully"); - assert.equal(newComments.objectAt(0).get('body'), 'Third', "third comment loaded successfully"); + assert.equal(comments, newComments, 'hasMany array was kept the same'); + assert.equal(newComments.get('length'), 3, 'comments updated successfully'); + assert.equal( + newComments.objectAt(0).get('body'), + 'Third', + 'third comment loaded successfully' + ); }); }); }); @@ -1323,12 +1425,9 @@ test("When a polymorphic hasMany relationship is accessed, the adapter's findMan id: '1', relationships: { messages: { - data: [ - { type: 'post', id: '1' }, - { type: 'comment', id: '3' } - ] - } - } + data: [{ type: 'post', id: '1' }, { type: 'comment', id: '3' }], + }, + }, }; env.adapter.findMany = function(store, type, ids, snapshots) { @@ -1342,27 +1441,30 @@ test("When a polymorphic hasMany relationship is accessed, the adapter's findMan run(function() { env.store.push({ data: userData, - included: [{ - type: 'post', - id: '1' - }, { - type: 'comment', - id: '3' - }] + included: [ + { + type: 'post', + id: '1', + }, + { + type: 'comment', + id: '3', + }, + ], }); }); run(function() { env.store.findRecord('user', 1).then(function(user) { let messages = user.get('messages'); - assert.equal(messages.get('length'), 2, "The messages are correctly loaded"); + assert.equal(messages.get('length'), 2, 'The messages are correctly loaded'); }); }); }); test("When a polymorphic hasMany relationship is accessed, the store can call multiple adapters' findMany or find methods if the records are not loaded", function(assert) { User.reopen({ - messages: hasMany('message', { polymorphic: true, async: true }) + messages: hasMany('message', { polymorphic: true, async: true }), }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.findRecord = function(store, type, id, snapshot) { @@ -1380,47 +1482,47 @@ test("When a polymorphic hasMany relationship is accessed, the store can call mu id: '1', relationships: { messages: { - data: [ - { type: 'post', id: '1' }, - { type: 'comment', id: '3' } - ] - } - } - } + data: [{ type: 'post', id: '1' }, { type: 'comment', id: '3' }], + }, + }, + }, }); }); run(function() { - env.store.findRecord('user', 1).then(function(user) { - return user.get('messages'); - }).then(function(messages) { - assert.equal(messages.get('length'), 2, "The messages are correctly loaded"); - }); + env.store + .findRecord('user', 1) + .then(function(user) { + return user.get('messages'); + }) + .then(function(messages) { + assert.equal(messages.get('length'), 2, 'The messages are correctly loaded'); + }); }); }); -test("polymorphic hasMany type-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled", function(assert) { +test('polymorphic hasMany type-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled', function(assert) { assert.expect(1); setupModelFactoryInjections(); try { - run(function () { + run(function() { let igor = env.store.createRecord('user', { name: 'Igor' }); - let comment = env.store.createRecord('comment', { body: "Well I thought the title was fine" }); + let comment = env.store.createRecord('comment', { + body: 'Well I thought the title was fine', + }); igor.get('messages').addObject(comment); - assert.equal(igor.get('messages.firstObject.body'), "Well I thought the title was fine"); + assert.equal(igor.get('messages.firstObject.body'), 'Well I thought the title was fine'); }); } finally { resetModelFactoryInjections(); } }); - - -test("Type can be inferred from the key of a hasMany relationship", function(assert) { +test('Type can be inferred from the key of a hasMany relationship', function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, ids, snapshots) { @@ -1430,10 +1532,10 @@ test("Type can be inferred from the key of a hasMany relationship", function(ass type: 'user', relationships: { contacts: { - data: [{ id: 1, type: 'contact' }] - } - } - } + data: [{ id: 1, type: 'contact' }], + }, + }, + }, }; }; @@ -1444,32 +1546,35 @@ test("Type can be inferred from the key of a hasMany relationship", function(ass id: '1', relationships: { contacts: { - data: [ - { type: 'contact', id: '1' } - ] - } - } + data: [{ type: 'contact', id: '1' }], + }, + }, }, - included: [{ - type: 'contact', - id: '1' - }] + included: [ + { + type: 'contact', + id: '1', + }, + ], }); }); run(function() { - env.store.findRecord('user', 1).then(function(user) { - return user.get('contacts'); - }).then(function(contacts) { - assert.equal(contacts.get('length'), 1, "The contacts relationship is correctly set up"); - }); + env.store + .findRecord('user', 1) + .then(function(user) { + return user.get('contacts'); + }) + .then(function(contacts) { + assert.equal(contacts.get('length'), 1, 'The contacts relationship is correctly set up'); + }); }); }); -test("Type can be inferred from the key of an async hasMany relationship", function(assert) { +test('Type can be inferred from the key of an async hasMany relationship', function(assert) { assert.expect(1); User.reopen({ - contacts: DS.hasMany({ async: true }) + contacts: DS.hasMany({ async: true }), }); env.adapter.findRecord = function(store, type, ids, snapshots) { @@ -1479,10 +1584,10 @@ test("Type can be inferred from the key of an async hasMany relationship", funct type: 'user', relationships: { contacts: { - data: [{ id: 1, type: 'contact' }] - } - } - } + data: [{ id: 1, type: 'contact' }], + }, + }, + }, }; }; @@ -1493,30 +1598,33 @@ test("Type can be inferred from the key of an async hasMany relationship", funct id: '1', relationships: { contacts: { - data: [ - { type: 'contact', id: '1' } - ] - } - } + data: [{ type: 'contact', id: '1' }], + }, + }, }, - included: [{ - type: 'contact', - id: '1' - }] + included: [ + { + type: 'contact', + id: '1', + }, + ], }); }); run(function() { - env.store.findRecord('user', 1).then(function(user) { - return user.get('contacts'); - }).then(function(contacts) { - assert.equal(contacts.get('length'), 1, "The contacts relationship is correctly set up"); - }); + env.store + .findRecord('user', 1) + .then(function(user) { + return user.get('contacts'); + }) + .then(function(contacts) { + assert.equal(contacts.get('length'), 1, 'The contacts relationship is correctly set up'); + }); }); }); -test("Polymorphic relationships work with a hasMany whose type is inferred", function(assert) { +test('Polymorphic relationships work with a hasMany whose type is inferred', function(assert) { User.reopen({ - contacts: DS.hasMany({ polymorphic: true, async: false }) + contacts: DS.hasMany({ polymorphic: true, async: false }), }); env.adapter.findRecord = function(store, type, ids, snapshots) { @@ -1531,49 +1639,56 @@ test("Polymorphic relationships work with a hasMany whose type is inferred", fun id: '1', relationships: { contacts: { - data: [ - { type: 'email', id: '1' }, - { type: 'phone', id: '2' } - ] - } - } + data: [{ type: 'email', id: '1' }, { type: 'phone', id: '2' }], + }, + }, }, - included: [{ - type: 'email', - id: '1' - }, { - type: 'phone', - id: '2' - }] + included: [ + { + type: 'email', + id: '1', + }, + { + type: 'phone', + id: '2', + }, + ], }); }); run(function() { - env.store.findRecord('user', 1).then(function(user) { - return user.get('contacts'); - }).then(function(contacts) { - assert.equal(contacts.get('length'), 2, "The contacts relationship is correctly set up"); - }); + env.store + .findRecord('user', 1) + .then(function(user) { + return user.get('contacts'); + }) + .then(function(contacts) { + assert.equal(contacts.get('length'), 2, 'The contacts relationship is correctly set up'); + }); }); }); -test("Polymorphic relationships with a hasMany is set up correctly on both sides", function(assert) { +test('Polymorphic relationships with a hasMany is set up correctly on both sides', function(assert) { assert.expect(2); Contact.reopen({ - posts: DS.hasMany('post', { async: false }) + posts: DS.hasMany('post', { async: false }), }); Post.reopen({ - contact: DS.belongsTo('contact', { polymorphic: true, async: false }) + contact: DS.belongsTo('contact', { polymorphic: true, async: false }), }); let email = env.store.createRecord('email'); let post = env.store.createRecord('post', { - contact: email + contact: email, }); assert.equal(post.get('contact'), email, 'The polymorphic belongsTo is set up correctly'); - assert.equal(get(email, 'posts.length'), 1, "The inverse has many is set up correctly on the email side."); + assert.equal( + get(email, 'posts.length'), + 1, + 'The inverse has many is set up correctly on the email side.' + ); }); testInDebug("A record can't be created from a polymorphic hasMany relationship", function(assert) { @@ -1585,118 +1700,137 @@ testInDebug("A record can't be created from a polymorphic hasMany relationship", id: '1', relationships: { messages: { - data: [] - } - } - } + data: [], + }, + }, + }, }); }); run(function() { - env.store.findRecord('user', 1).then(function(user) { - return user.get('messages'); - }).then(function(messages) { - assert.expectAssertion(function() { - messages.createRecord(); - }, /You cannot add 'message' records to this polymorphic relationship/); - }); + env.store + .findRecord('user', 1) + .then(function(user) { + return user.get('messages'); + }) + .then(function(messages) { + assert.expectAssertion(function() { + messages.createRecord(); + }, /You cannot add 'message' records to this polymorphic relationship/); + }); }); }); -testInDebug("Only records of the same type can be added to a monomorphic hasMany relationship", function(assert) { - assert.expect(1); - env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { - env.store.push({ - data: [{ - type: 'post', - id: '1', - relationships: { - comments: { - data: [] - } - } - }, { - type: 'post', - id: '2' - }] - }); - }); - - run(function() { - all([ - env.store.findRecord('post', 1), - env.store.findRecord('post', 2) - ]).then(function(records) { - assert.expectAssertion(function() { - records[0].get('comments').pushObject(records[1]); - }, /You cannot add a record of modelClass 'post' to the 'post.comments' relationship \(only 'comment' allowed\)/); +testInDebug( + 'Only records of the same type can be added to a monomorphic hasMany relationship', + function(assert) { + assert.expect(1); + env.adapter.shouldBackgroundReloadRecord = () => false; + run(function() { + env.store.push({ + data: [ + { + type: 'post', + id: '1', + relationships: { + comments: { + data: [], + }, + }, + }, + { + type: 'post', + id: '2', + }, + ], + }); }); - }); -}); -testInDebug("Only records of the same base modelClass can be added to a polymorphic hasMany relationship", function(assert) { - assert.expect(2); - env.adapter.shouldBackgroundReloadRecord = () => false; - run(function() { - env.store.push({ - data: [{ - type: 'user', - id: '1', - relationships: { - messages: { - data: [] - } - } - }, { - type: 'user', - id: '2', - relationships: { - messages: { - data: [] - } - } - }], - included: [{ - type: 'post', - id: '1', - relationships: { - comments: { - data: [] - } - } - }, { - type: 'comment', - id: '3' - }] + run(function() { + all([env.store.findRecord('post', 1), env.store.findRecord('post', 2)]).then(function( + records + ) { + assert.expectAssertion(function() { + records[0].get('comments').pushObject(records[1]); + }, /You cannot add a record of modelClass 'post' to the 'post.comments' relationship \(only 'comment' allowed\)/); + }); }); - }); - let asyncRecords; - - run(function() { - asyncRecords = hash({ - user: env.store.findRecord('user', 1), - anotherUser: env.store.findRecord('user', 2), - post: env.store.findRecord('post', 1), - comment: env.store.findRecord('comment', 3) + } +); + +testInDebug( + 'Only records of the same base modelClass can be added to a polymorphic hasMany relationship', + function(assert) { + assert.expect(2); + env.adapter.shouldBackgroundReloadRecord = () => false; + run(function() { + env.store.push({ + data: [ + { + type: 'user', + id: '1', + relationships: { + messages: { + data: [], + }, + }, + }, + { + type: 'user', + id: '2', + relationships: { + messages: { + data: [], + }, + }, + }, + ], + included: [ + { + type: 'post', + id: '1', + relationships: { + comments: { + data: [], + }, + }, + }, + { + type: 'comment', + id: '3', + }, + ], + }); }); + let asyncRecords; - asyncRecords.then(function(records) { - records.messages = records.user.get('messages'); - return hash(records); - }).then(function(records) { - records.messages.pushObject(records.post); - records.messages.pushObject(records.comment); - assert.equal(records.messages.get('length'), 2, "The messages are correctly added"); + run(function() { + asyncRecords = hash({ + user: env.store.findRecord('user', 1), + anotherUser: env.store.findRecord('user', 2), + post: env.store.findRecord('post', 1), + comment: env.store.findRecord('comment', 3), + }); - assert.expectAssertion(function() { - records.messages.pushObject(records.anotherUser); - }, /You cannot add a record of modelClass 'user' to the 'user.messages' relationship \(only 'message' allowed\)/); + asyncRecords + .then(function(records) { + records.messages = records.user.get('messages'); + return hash(records); + }) + .then(function(records) { + records.messages.pushObject(records.post); + records.messages.pushObject(records.comment); + assert.equal(records.messages.get('length'), 2, 'The messages are correctly added'); + + assert.expectAssertion(function() { + records.messages.pushObject(records.anotherUser); + }, /You cannot add a record of modelClass 'user' to the 'user.messages' relationship \(only 'message' allowed\)/); + }); }); - }); -}); + } +); -test("A record can be removed from a polymorphic association", function(assert) { +test('A record can be removed from a polymorphic association', function(assert) { assert.expect(4); env.adapter.shouldBackgroundReloadRecord = () => false; run(function() { @@ -1706,16 +1840,16 @@ test("A record can be removed from a polymorphic association", function(assert) id: '1', relationships: { messages: { - data: [ - { type: 'comment', id: '3' } - ] - } - } + data: [{ type: 'comment', id: '3' }], + }, + }, }, - included: [{ - type: 'comment', - id: '3' - }] + included: [ + { + type: 'comment', + id: '3', + }, + ], }); }); let asyncRecords; @@ -1723,119 +1857,126 @@ test("A record can be removed from a polymorphic association", function(assert) run(function() { asyncRecords = hash({ user: env.store.findRecord('user', 1), - comment: env.store.findRecord('comment', 3) + comment: env.store.findRecord('comment', 3), }); - asyncRecords.then(function(records) { - records.messages = records.user.get('messages'); - return hash(records); - }).then(function(records) { - assert.equal(records.messages.get('length'), 1, "The user has 1 message"); + asyncRecords + .then(function(records) { + records.messages = records.user.get('messages'); + return hash(records); + }) + .then(function(records) { + assert.equal(records.messages.get('length'), 1, 'The user has 1 message'); - let removedObject = records.messages.popObject(); + let removedObject = records.messages.popObject(); - assert.equal(removedObject, records.comment, "The message is correctly removed"); - assert.equal(records.messages.get('length'), 0, "The user does not have any messages"); - assert.equal(records.messages.objectAt(0), null, "No messages can't be fetched"); - }); + assert.equal(removedObject, records.comment, 'The message is correctly removed'); + assert.equal(records.messages.get('length'), 0, 'The user does not have any messages'); + assert.equal(records.messages.objectAt(0), null, "No messages can't be fetched"); + }); }); }); -test("When a record is created on the client, its hasMany arrays should be in a loaded state", function(assert) { +test('When a record is created on the client, its hasMany arrays should be in a loaded state', function(assert) { assert.expect(3); let post = env.store.createRecord('post'); - assert.ok(get(post, 'isLoaded'), "The post should have isLoaded flag"); + assert.ok(get(post, 'isLoaded'), 'The post should have isLoaded flag'); let comments; run(function() { comments = get(post, 'comments'); }); - assert.equal(get(comments, 'length'), 0, "The comments should be an empty array"); + assert.equal(get(comments, 'length'), 0, 'The comments should be an empty array'); - assert.ok(get(comments, 'isLoaded'), "The comments should have isLoaded flag"); + assert.ok(get(comments, 'isLoaded'), 'The comments should have isLoaded flag'); }); -test("When a record is created on the client, its async hasMany arrays should be in a loaded state", function(assert) { +test('When a record is created on the client, its async hasMany arrays should be in a loaded state', function(assert) { assert.expect(4); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); let post = env.store.createRecord('post'); - assert.ok(get(post, 'isLoaded'), "The post should have isLoaded flag"); + assert.ok(get(post, 'isLoaded'), 'The post should have isLoaded flag'); run(function() { get(post, 'comments').then(function(comments) { - assert.ok(true, "Comments array successfully resolves"); - assert.equal(get(comments, 'length'), 0, "The comments should be an empty array"); - assert.ok(get(comments, 'isLoaded'), "The comments should have isLoaded flag"); + assert.ok(true, 'Comments array successfully resolves'); + assert.equal(get(comments, 'length'), 0, 'The comments should be an empty array'); + assert.ok(get(comments, 'isLoaded'), 'The comments should have isLoaded flag'); }); }); }); -test("we can set records SYNC HM relationship", function(assert) { +test('we can set records SYNC HM relationship', function(assert) { assert.expect(1); let post = env.store.createRecord('post'); run(function() { env.store.push({ - data: [{ - type: 'comment', - id: '1', - attributes: { - body: 'First' - } - }, { - type: 'comment', - id: '2', - attributes: { - body: 'Second' - } - }] + data: [ + { + type: 'comment', + id: '1', + attributes: { + body: 'First', + }, + }, + { + type: 'comment', + id: '2', + attributes: { + body: 'Second', + }, + }, + ], }); post.set('comments', env.store.peekAll('comment')); }); - assert.equal(get(post, 'comments.length'), 2, "we can set HM relationship"); + assert.equal(get(post, 'comments.length'), 2, 'we can set HM relationship'); }); - -test("We can set records ASYNC HM relationship", function(assert) { +test('We can set records ASYNC HM relationship', function(assert) { assert.expect(1); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); let post = env.store.createRecord('post'); run(function() { env.store.push({ - data: [{ - type: 'comment', - id: '1', - attributes: { - body: 'First' - } - }, { - type: 'comment', - id: '2', - attributes: { - body: 'Second' - } - }] + data: [ + { + type: 'comment', + id: '1', + attributes: { + body: 'First', + }, + }, + { + type: 'comment', + id: '2', + attributes: { + body: 'Second', + }, + }, + ], }); post.set('comments', env.store.peekAll('comment')); }); return post.get('comments').then(comments => { - assert.equal(comments.get('length') , 2, "we can set async HM relationship"); + assert.equal(comments.get('length'), 2, 'we can set async HM relationship'); }); }); -test("When a record is saved, its unsaved hasMany records should be kept", function(assert) { +test('When a record is saved, its unsaved hasMany records should be kept', function(assert) { assert.expect(1); let post, comment; @@ -1850,17 +1991,21 @@ test("When a record is saved, its unsaved hasMany records should be kept", funct post.get('comments').pushObject(comment); return post.save(); }).then(() => { - assert.equal(get(post, 'comments.length'), 1, "The unsaved comment should be in the post's comments array"); + assert.equal( + get(post, 'comments.length'), + 1, + "The unsaved comment should be in the post's comments array" + ); }); }); -test("dual non-async HM <-> BT", function(assert) { +test('dual non-async HM <-> BT', function(assert) { Post.reopen({ - comments: DS.hasMany('comment', { inverse: 'post', async: false }) + comments: DS.hasMany('comment', { inverse: 'post', async: false }), }); Comment.reopen({ - post: DS.belongsTo('post', { async: false }) + post: DS.belongsTo('post', { async: false }), }); env.adapter.createRecord = function(store, type, snapshot) { @@ -1877,12 +2022,10 @@ test("dual non-async HM <-> BT", function(assert) { id: '1', relationships: { comments: { - data: [ - { type: 'comment', id: '1' } - ] - } - } - } + data: [{ type: 'comment', id: '1' }], + }, + }, + }, }); env.store.push({ data: { @@ -1890,34 +2033,47 @@ test("dual non-async HM <-> BT", function(assert) { id: '1', relationships: { comments: { - post: { type: 'post', id: '1' } - } - } - } + post: { type: 'post', id: '1' }, + }, + }, + }, }); post = env.store.peekRecord('post', 1); firstComment = env.store.peekRecord('comment', 1); - env.store.createRecord('comment', { - post: post - }).save().then(function(comment) { - let commentPost = comment.get('post'); - let postComments = comment.get('post.comments'); - let postCommentsLength = comment.get('post.comments.length'); - - assert.deepEqual(post, commentPost, 'expect the new comments post, to be the correct post'); - assert.ok(postComments, "comments should exist"); - assert.equal(postCommentsLength, 2, "comment's post should have a internalModel back to comment"); - assert.ok(postComments && postComments.indexOf(firstComment) !== -1, 'expect to contain first comment'); - assert.ok(postComments && postComments.indexOf(comment) !== -1, 'expected to contain the new comment'); - }); + env.store + .createRecord('comment', { + post: post, + }) + .save() + .then(function(comment) { + let commentPost = comment.get('post'); + let postComments = comment.get('post.comments'); + let postCommentsLength = comment.get('post.comments.length'); + + assert.deepEqual(post, commentPost, 'expect the new comments post, to be the correct post'); + assert.ok(postComments, 'comments should exist'); + assert.equal( + postCommentsLength, + 2, + "comment's post should have a internalModel back to comment" + ); + assert.ok( + postComments && postComments.indexOf(firstComment) !== -1, + 'expect to contain first comment' + ); + assert.ok( + postComments && postComments.indexOf(comment) !== -1, + 'expected to contain the new comment' + ); + }); }); }); -test("When an unloaded record is added to the hasMany, it gets fetched once the hasMany is accessed even if the hasMany has been already fetched", function(assert) { +test('When an unloaded record is added to the hasMany, it gets fetched once the hasMany is accessed even if the hasMany has been already fetched', function(assert) { assert.expect(6); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); let findManyCalls = 0; @@ -1925,10 +2081,12 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the env.adapter.findMany = function(store, type, ids, snapshots) { assert.ok(true, `findMany called ${++findManyCalls}x`); - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: 'first' } }, - { id: 2, type: 'comment', attributes: { body: 'second' } } - ]}); + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'first' } }, + { id: 2, type: 'comment', attributes: { body: 'second' } }, + ], + }); }; env.adapter.findRecord = function(store, type, id, snapshot) { @@ -1944,13 +2102,10 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the id: '1', relationships: { comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' } - ] - } - } - } + data: [{ type: 'comment', id: '1' }, { type: 'comment', id: '2' }], + }, + }, + }, }); post = env.store.peekRecord('post', 1); }); @@ -1958,7 +2113,11 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the return run(() => { return post.get('comments').then(fetchedComments => { assert.equal(fetchedComments.get('length'), 2, 'comments fetched successfully'); - assert.equal(fetchedComments.objectAt(0).get('body'), 'first', 'first comment loaded successfully'); + assert.equal( + fetchedComments.objectAt(0).get('body'), + 'first', + 'first comment loaded successfully' + ); env.store.push({ data: { @@ -1969,16 +2128,24 @@ test("When an unloaded record is added to the hasMany, it gets fetched once the data: [ { type: 'comment', id: '1' }, { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - } + { type: 'comment', id: '3' }, + ], + }, + }, + }, }); return post.get('comments').then(newlyFetchedComments => { - assert.equal(newlyFetchedComments.get('length'), 3, 'all three comments fetched successfully'); - assert.equal(newlyFetchedComments.objectAt(2).get('body'), 'third', 'third comment loaded successfully'); + assert.equal( + newlyFetchedComments.get('length'), + 3, + 'all three comments fetched successfully' + ); + assert.equal( + newlyFetchedComments.objectAt(2).get('body'), + 'third', + 'third comment loaded successfully' + ); }); }); }); @@ -1992,13 +2159,10 @@ testInDebug('A sync hasMany errors out if there are unlaoded records in it', fun id: '1', relationships: { comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' } - ] - } - } - } + data: [{ type: 'comment', id: '1' }, { type: 'comment', id: '2' }], + }, + }, + }, }); return env.store.peekRecord('post', 1); }); @@ -2016,15 +2180,11 @@ test('After removing and unloading a record, a hasMany relationship should still id: '1', relationships: { comments: { - data: [ - { type: 'comment', id: '1' } - ] - } - } + data: [{ type: 'comment', id: '1' }], + }, + }, }, - included: [ - { type: 'comment', id: '1' } - ] + included: [{ type: 'comment', id: '1' }], }); const post = env.store.peekRecord('post', 1); const comments = post.get('comments'); @@ -2039,25 +2199,30 @@ test('After removing and unloading a record, a hasMany relationship should still assert.equal(run(post, 'get', 'comments.length'), 0); }); -test("If reordered hasMany data has been pushed to the store, the many array reflects the ordering change - sync", function(assert) { +test('If reordered hasMany data has been pushed to the store, the many array reflects the ordering change - sync', function(assert) { let comment1, comment2, comment3, comment4; let post; run(() => { env.store.push({ - data: [{ - type: 'comment', - id: '1' - }, { - type: 'comment', - id: '2' - }, { - type: 'comment', - id: '3' - }, { - type: 'comment', - id: '4' - }] + data: [ + { + type: 'comment', + id: '1', + }, + { + type: 'comment', + id: '2', + }, + { + type: 'comment', + id: '3', + }, + { + type: 'comment', + id: '4', + }, + ], }); comment1 = env.store.peekRecord('comment', 1); @@ -2073,17 +2238,18 @@ test("If reordered hasMany data has been pushed to the store, the many array ref id: '1', relationships: { comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' } - ] - } - } - } + data: [{ type: 'comment', id: '1' }, { type: 'comment', id: '2' }], + }, + }, + }, }); post = env.store.peekRecord('post', 1); - assert.deepEqual(post.get('comments').toArray(), [comment1, comment2], 'Initial ordering is correct'); + assert.deepEqual( + post.get('comments').toArray(), + [comment1, comment2], + 'Initial ordering is correct' + ); }); run(() => { @@ -2093,16 +2259,17 @@ test("If reordered hasMany data has been pushed to the store, the many array ref id: '1', relationships: { comments: { - data: [ - { type: 'comment', id: '2' }, - { type: 'comment', id: '1' } - ] - } - } - } + data: [{ type: 'comment', id: '2' }, { type: 'comment', id: '1' }], + }, + }, + }, }); }); - assert.deepEqual(post.get('comments').toArray(), [comment2, comment1], 'Updated ordering is correct'); + assert.deepEqual( + post.get('comments').toArray(), + [comment2, comment1], + 'Updated ordering is correct' + ); run(() => { env.store.push({ @@ -2111,12 +2278,10 @@ test("If reordered hasMany data has been pushed to the store, the many array ref id: '1', relationships: { comments: { - data: [ - { type: 'comment', id: '2' } - ] - } - } - } + data: [{ type: 'comment', id: '2' }], + }, + }, + }, }); }); assert.deepEqual(post.get('comments').toArray(), [comment2], 'Updated ordering is correct'); @@ -2132,14 +2297,18 @@ test("If reordered hasMany data has been pushed to the store, the many array ref { type: 'comment', id: '1' }, { type: 'comment', id: '2' }, { type: 'comment', id: '3' }, - { type: 'comment', id: '4' } - ] - } - } - } + { type: 'comment', id: '4' }, + ], + }, + }, + }, }); }); - assert.deepEqual(post.get('comments').toArray(), [comment1, comment2, comment3, comment4], 'Updated ordering is correct'); + assert.deepEqual( + post.get('comments').toArray(), + [comment1, comment2, comment3, comment4], + 'Updated ordering is correct' + ); run(() => { env.store.push({ @@ -2148,16 +2317,17 @@ test("If reordered hasMany data has been pushed to the store, the many array ref id: '1', relationships: { comments: { - data: [ - { type: 'comment', id: '4' }, - { type: 'comment', id: '3' } - ] - } - } - } + data: [{ type: 'comment', id: '4' }, { type: 'comment', id: '3' }], + }, + }, + }, }); }); - assert.deepEqual(post.get('comments').toArray(), [comment4, comment3], 'Updated ordering is correct'); + assert.deepEqual( + post.get('comments').toArray(), + [comment4, comment3], + 'Updated ordering is correct' + ); run(() => { env.store.push({ @@ -2170,18 +2340,22 @@ test("If reordered hasMany data has been pushed to the store, the many array ref { type: 'comment', id: '4' }, { type: 'comment', id: '2' }, { type: 'comment', id: '3' }, - { type: 'comment', id: '1' } - ] - } - } - } + { type: 'comment', id: '1' }, + ], + }, + }, + }, }); }); - assert.deepEqual(post.get('comments').toArray(), [comment4, comment2, comment3, comment1], 'Updated ordering is correct'); + assert.deepEqual( + post.get('comments').toArray(), + [comment4, comment2, comment3, comment1], + 'Updated ordering is correct' + ); }); -test("Rollbacking attributes for deleted record restores implicit relationship correctly when the hasMany side has been deleted - async", function(assert) { +test('Rollbacking attributes for deleted record restores implicit relationship correctly when the hasMany side has been deleted - async', function(assert) { let book, chapter; run(() => { @@ -2190,23 +2364,23 @@ test("Rollbacking attributes for deleted record restores implicit relationship c type: 'book', id: '1', attributes: { - title: "Stanley's Amazing Adventures" + title: "Stanley's Amazing Adventures", }, relationships: { chapters: { - data: [ - { type: 'chapter', id: '2' } - ] - } - } + data: [{ type: 'chapter', id: '2' }], + }, + }, }, - included: [{ - type: 'chapter', - id: '2', - attributes: { - title: 'Sailing the Seven Seas' - } - }] + included: [ + { + type: 'chapter', + id: '2', + attributes: { + title: 'Sailing the Seven Seas', + }, + }, + ], }); book = env.store.peekRecord('book', 1); chapter = env.store.peekRecord('chapter', 2); @@ -2219,12 +2393,16 @@ test("Rollbacking attributes for deleted record restores implicit relationship c return run(() => { return book.get('chapters').then(fetchedChapters => { - assert.equal(fetchedChapters.objectAt(0), chapter, 'Book has a chapter after rollback attributes'); + assert.equal( + fetchedChapters.objectAt(0), + chapter, + 'Book has a chapter after rollback attributes' + ); }); }); }); -test("Rollbacking attributes for deleted record restores implicit relationship correctly when the hasMany side has been deleted - sync", function(assert) { +test('Rollbacking attributes for deleted record restores implicit relationship correctly when the hasMany side has been deleted - sync', function(assert) { let book, chapter; run(() => { @@ -2233,23 +2411,23 @@ test("Rollbacking attributes for deleted record restores implicit relationship c type: 'book', id: '1', attributes: { - title: "Stanley's Amazing Adventures" + title: "Stanley's Amazing Adventures", }, relationships: { chapters: { - data: [ - { type: 'chapter', id: '2' } - ] - } - } + data: [{ type: 'chapter', id: '2' }], + }, + }, }, - included: [{ - type: 'chapter', - id: '2', - attributes: { - title: 'Sailing the Seven Seas' - } - }] + included: [ + { + type: 'chapter', + id: '2', + attributes: { + title: 'Sailing the Seven Seas', + }, + }, + ], }); book = env.store.peekRecord('book', 1); chapter = env.store.peekRecord('chapter', 2); @@ -2261,13 +2439,17 @@ test("Rollbacking attributes for deleted record restores implicit relationship c }); run(() => { - assert.equal(book.get('chapters.firstObject'), chapter, "Book has a chapter after rollback attributes"); + assert.equal( + book.get('chapters.firstObject'), + chapter, + 'Book has a chapter after rollback attributes' + ); }); }); -test("Rollbacking attributes for deleted record restores implicit relationship correctly when the belongsTo side has been deleted - async", function(assert) { +test('Rollbacking attributes for deleted record restores implicit relationship correctly when the belongsTo side has been deleted - async', function(assert) { Page.reopen({ - chapter: DS.belongsTo('chapter', { async: true }) + chapter: DS.belongsTo('chapter', { async: true }), }); let chapter, page; @@ -2278,21 +2460,23 @@ test("Rollbacking attributes for deleted record restores implicit relationship c type: 'chapter', id: '2', attributes: { - title: 'Sailing the Seven Seas' - } + title: 'Sailing the Seven Seas', + }, }, - included: [{ - type: 'page', - id: '3', - attributes: { - number: 1 + included: [ + { + type: 'page', + id: '3', + attributes: { + number: 1, + }, + relationships: { + chapter: { + data: { type: 'chapter', id: '2' }, + }, + }, }, - relationships: { - chapter: { - data: { type: 'chapter', id: '2' } - } - } - }] + ], }); chapter = env.store.peekRecord('chapter', 2); page = env.store.peekRecord('page', 3); @@ -2310,7 +2494,7 @@ test("Rollbacking attributes for deleted record restores implicit relationship c }); }); -test("Rollbacking attributes for deleted record restores implicit relationship correctly when the belongsTo side has been deleted - sync", function(assert) { +test('Rollbacking attributes for deleted record restores implicit relationship correctly when the belongsTo side has been deleted - sync', function(assert) { let chapter, page; run(() => { env.store.push({ @@ -2318,21 +2502,23 @@ test("Rollbacking attributes for deleted record restores implicit relationship c type: 'chapter', id: '2', attributes: { - title: 'Sailing the Seven Seas' - } + title: 'Sailing the Seven Seas', + }, }, - included: [{ - type: 'page', - id: '3', - attributes: { - number: 1 + included: [ + { + type: 'page', + id: '3', + attributes: { + number: 1, + }, + relationships: { + chapter: { + data: { type: 'chapter', id: '2' }, + }, + }, }, - relationships: { - chapter: { - data: { type: 'chapter', id: '2' } - } - } - }] + ], }); chapter = env.store.peekRecord('chapter', 2); page = env.store.peekRecord('page', 3); @@ -2344,44 +2530,45 @@ test("Rollbacking attributes for deleted record restores implicit relationship c }); run(() => { - assert.equal(page.get('chapter'), chapter, "Page has a chapter after rollback attributes"); + assert.equal(page.get('chapter'), chapter, 'Page has a chapter after rollback attributes'); }); }); -test("ManyArray notifies the array observers and flushes bindings when removing", function(assert) { +test('ManyArray notifies the array observers and flushes bindings when removing', function(assert) { assert.expect(2); let chapter, page, page2; let observe = false; run(() => { env.store.push({ - data: [{ - type: 'page', - id: '1', - attributes: { - number: 1 - } - }, { - type: 'page', - id: '2', - attributes: { - number: 2 - } - }, { - type: 'chapter', - id: '1', - attributes: { - title: 'Sailing the Seven Seas' + data: [ + { + type: 'page', + id: '1', + attributes: { + number: 1, + }, }, - relationships: { - pages: { - data: [ - { type: 'page', id: '1' }, - { type: 'page', id: '2' } - ] - } - } - }] + { + type: 'page', + id: '2', + attributes: { + number: 2, + }, + }, + { + type: 'chapter', + id: '1', + attributes: { + title: 'Sailing the Seven Seas', + }, + relationships: { + pages: { + data: [{ type: 'page', id: '1' }, { type: 'page', id: '2' }], + }, + }, + }, + ], }); page = env.store.peekRecord('page', 1); page2 = env.store.peekRecord('page', 2); @@ -2397,7 +2584,7 @@ test("ManyArray notifies the array observers and flushes bindings when removing" if (observe) { assert.equal(removeCount, 1, 'removeCount is correct'); } - } + }, }); }); @@ -2408,39 +2595,41 @@ test("ManyArray notifies the array observers and flushes bindings when removing" }); }); -test("ManyArray notifies the array observers and flushes bindings when adding", function(assert) { +test('ManyArray notifies the array observers and flushes bindings when adding', function(assert) { assert.expect(2); let chapter, page, page2; let observe = false; run(() => { env.store.push({ - data: [{ - type: 'page', - id: '1', - attributes: { - number: 1 - } - }, { - type: 'page', - id: '2', - attributes: { - number: 2 - } - }, { - type: 'chapter', - id: '1', - attributes: { - title: 'Sailing the Seven Seas' + data: [ + { + type: 'page', + id: '1', + attributes: { + number: 1, + }, }, - relationships: { - pages: { - data: [ - { type: 'page', id: '1' } - ] - } - } - }] + { + type: 'page', + id: '2', + attributes: { + number: 2, + }, + }, + { + type: 'chapter', + id: '1', + attributes: { + title: 'Sailing the Seven Seas', + }, + relationships: { + pages: { + data: [{ type: 'page', id: '1' }], + }, + }, + }, + ], }); page = env.store.peekRecord('page', 1); page2 = env.store.peekRecord('page', 2); @@ -2456,7 +2645,7 @@ test("ManyArray notifies the array observers and flushes bindings when adding", if (observe) { assert.equal(pages.objectAt(index), page2, 'page2 is passed to didChange'); } - } + }, }); }); @@ -2467,70 +2656,72 @@ test("ManyArray notifies the array observers and flushes bindings when adding", }); }); -testInDebug("Passing a model as type to hasMany should not work", function(assert) { +testInDebug('Passing a model as type to hasMany should not work', function(assert) { assert.expect(1); assert.expectAssertion(() => { User = DS.Model.extend(); Contact = DS.Model.extend({ - users: hasMany(User, { async: false }) + users: hasMany(User, { async: false }), }); }, /The first argument to DS.hasMany must be a string/); }); -test("Relationship.clear removes all records correctly", function(assert) { +test('Relationship.clear removes all records correctly', function(assert) { let post; Comment.reopen({ - post: DS.belongsTo('post', { async: false }) + post: DS.belongsTo('post', { async: false }), }); Post.reopen({ - comments: DS.hasMany('comment', { inverse: 'post', async: false }) + comments: DS.hasMany('comment', { inverse: 'post', async: false }), }); run(() => { env.store.push({ - data: [{ - type: 'post', - id: '2', - attributes: { - title: 'Sailing the Seven Seas' + data: [ + { + type: 'post', + id: '2', + attributes: { + title: 'Sailing the Seven Seas', + }, + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }, { type: 'comment', id: '2' }], + }, + }, }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' } - ] - } - } - }, { - type: 'comment', - id: '1', - relationships: { - post: { - data: { type: 'post', id: '2' } - } - } - }, { - type: 'comment', - id: '2', - relationships: { - post: { - data: { type: 'post', id: '2' } - } - } - }, { - type: 'comment', - id: '3', - relationships: { - post: { - data: { type: 'post', id: '2' } - } - } - }] + { + type: 'comment', + id: '1', + relationships: { + post: { + data: { type: 'post', id: '2' }, + }, + }, + }, + { + type: 'comment', + id: '2', + relationships: { + post: { + data: { type: 'post', id: '2' }, + }, + }, + }, + { + type: 'comment', + id: '3', + relationships: { + post: { + data: { type: 'post', id: '2' }, + }, + }, + }, + ], }); post = env.store.peekRecord('post', 2); }); @@ -2546,46 +2737,47 @@ test('unloading a record with associated records does not prevent the store from let post; Comment.reopen({ - post: DS.belongsTo('post', { async: false }) + post: DS.belongsTo('post', { async: false }), }); Post.reopen({ - comments: DS.hasMany('comment', { inverse: 'post', async: false }) + comments: DS.hasMany('comment', { inverse: 'post', async: false }), }); run(() => { env.store.push({ - data: [{ - type: 'post', - id: '2', - attributes: { - title: 'Sailing the Seven Seas' + data: [ + { + type: 'post', + id: '2', + attributes: { + title: 'Sailing the Seven Seas', + }, + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }, { type: 'comment', id: '2' }], + }, + }, }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' } - ] - } - } - }, { - type: 'comment', - id: '1', - relationships: { - post: { - data: { type: 'post', id: '2' } - } - } - }, { - type: 'comment', - id: '2', - relationships: { - post: { - data: { type: 'post', id: '2' } - } - } - }] + { + type: 'comment', + id: '1', + relationships: { + post: { + data: { type: 'post', id: '2' }, + }, + }, + }, + { + type: 'comment', + id: '2', + relationships: { + post: { + data: { type: 'post', id: '2' }, + }, + }, + }, + ], }); post = env.store.peekRecord('post', 2); @@ -2602,22 +2794,22 @@ test('unloading a record with associated records does not prevent the store from run(() => { env.store.destroy(); }); - assert.ok(true, "store destroyed correctly"); + assert.ok(true, 'store destroyed correctly'); } catch (error) { - assert.ok(false, "store prevented from being destroyed"); + assert.ok(false, 'store prevented from being destroyed'); } }); -test("adding and removing records from hasMany relationship #2666", function(assert) { +test('adding and removing records from hasMany relationship #2666', function(assert) { assert.expect(4); let Post = DS.Model.extend({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); Post.reopenClass({ toString: () => 'Post' }); let Comment = DS.Model.extend({ - post: DS.belongsTo('post', { async: false }) + post: DS.belongsTo('post', { async: false }), }); Comment.reopenClass({ toString: () => 'Comment' }); @@ -2625,88 +2817,100 @@ test("adding and removing records from hasMany relationship #2666", function(ass post: Post, comment: Comment, adapter: DS.RESTAdapter.extend({ - shouldBackgroundReloadRecord: () => false - }) + shouldBackgroundReloadRecord: () => false, + }), }); let commentId = 4; - env.registry.register('adapter:comment', DS.RESTAdapter.extend({ - deleteRecord(record) { - return resolve(); - }, - updateRecord(record) { - return resolve(); - }, - createRecord() { - return resolve({ comments: { id: commentId++ }}); - } - })); + env.registry.register( + 'adapter:comment', + DS.RESTAdapter.extend({ + deleteRecord(record) { + return resolve(); + }, + updateRecord(record) { + return resolve(); + }, + createRecord() { + return resolve({ comments: { id: commentId++ } }); + }, + }) + ); run(() => { env.store.push({ - data: [{ - type: 'post', - id: '1', - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - }, { - type: 'comment', - id: '1' - }, { - type: 'comment', - id: '2' - }, { - type: 'comment', - id: '3' - }] + data: [ + { + type: 'post', + id: '1', + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], + }, + }, + }, + { + type: 'comment', + id: '1', + }, + { + type: 'comment', + id: '2', + }, + { + type: 'comment', + id: '3', + }, + ], }); }); return run(() => { return env.store.findRecord('post', 1).then(post => { let comments = post.get('comments'); - assert.equal(comments.get('length'), 3, "Initial comments count"); + assert.equal(comments.get('length'), 3, 'Initial comments count'); // Add comment #4 let comment = env.store.createRecord('comment'); comments.addObject(comment); - return comment.save().then(() => { - let comments = post.get('comments'); - assert.equal(comments.get('length'), 4, "Comments count after first add"); - - // Delete comment #4 - return comments.get('lastObject').destroyRecord(); - }).then(() => { - let comments = post.get('comments'); - let length = comments.get('length'); - - assert.equal(length, 3, "Comments count after destroy"); - - // Add another comment #4 - let comment = env.store.createRecord('comment'); - comments.addObject(comment); - return comment.save(); - }).then(() => { - let comments = post.get('comments'); - assert.equal(comments.get('length'), 4, "Comments count after second add"); - }); + return comment + .save() + .then(() => { + let comments = post.get('comments'); + assert.equal(comments.get('length'), 4, 'Comments count after first add'); + + // Delete comment #4 + return comments.get('lastObject').destroyRecord(); + }) + .then(() => { + let comments = post.get('comments'); + let length = comments.get('length'); + + assert.equal(length, 3, 'Comments count after destroy'); + + // Add another comment #4 + let comment = env.store.createRecord('comment'); + comments.addObject(comment); + return comment.save(); + }) + .then(() => { + let comments = post.get('comments'); + assert.equal(comments.get('length'), 4, 'Comments count after second add'); + }); }); }); }); -test("hasMany hasAnyRelationshipData async loaded", function(assert) { +test('hasMany hasAnyRelationshipData async loaded', function(assert) { assert.expect(1); Chapter.reopen({ - pages: hasMany('pages', { async: true }) + pages: hasMany('pages', { async: true }), }); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -2717,10 +2921,10 @@ test("hasMany hasAnyRelationshipData async loaded", function(assert) { attributes: { title: 'The Story Begins' }, relationships: { pages: { - data: [{ id: 2, type: 'page' }, { id: 3, type: 'page' }] - } - } - } + data: [{ id: 2, type: 'page' }, { id: 3, type: 'page' }], + }, + }, + }, }); }; @@ -2732,7 +2936,7 @@ test("hasMany hasAnyRelationshipData async loaded", function(assert) { }); }); -test("hasMany hasAnyRelationshipData sync loaded", function(assert) { +test('hasMany hasAnyRelationshipData sync loaded', function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -2743,10 +2947,10 @@ test("hasMany hasAnyRelationshipData sync loaded", function(assert) { attributes: { title: 'The Story Begins' }, relationships: { pages: { - data: [{ id: 2, type: 'page' }, { id: 3, type: 'page' }] - } - } - } + data: [{ id: 2, type: 'page' }, { id: 3, type: 'page' }], + }, + }, + }, }); }; @@ -2758,11 +2962,11 @@ test("hasMany hasAnyRelationshipData sync loaded", function(assert) { }); }); -test("hasMany hasAnyRelationshipData async not loaded", function(assert) { +test('hasMany hasAnyRelationshipData async not loaded', function(assert) { assert.expect(1); Chapter.reopen({ - pages: hasMany('pages', { async: true }) + pages: hasMany('pages', { async: true }), }); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -2773,10 +2977,10 @@ test("hasMany hasAnyRelationshipData async not loaded", function(assert) { attributes: { title: 'The Story Begins' }, relationships: { pages: { - links: { related: 'pages' } - } - } - } + links: { related: 'pages' }, + }, + }, + }, }); }; @@ -2788,7 +2992,7 @@ test("hasMany hasAnyRelationshipData async not loaded", function(assert) { }); }); -test("hasMany hasAnyRelationshipData sync not loaded", function(assert) { +test('hasMany hasAnyRelationshipData sync not loaded', function(assert) { assert.expect(1); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -2796,8 +3000,8 @@ test("hasMany hasAnyRelationshipData sync not loaded", function(assert) { data: { id: 1, type: 'chapter', - attributes: { title: 'The Story Begins' } - } + attributes: { title: 'The Story Begins' }, + }, }); }; @@ -2809,11 +3013,11 @@ test("hasMany hasAnyRelationshipData sync not loaded", function(assert) { }); }); -test("hasMany hasAnyRelationshipData async created", function(assert) { +test('hasMany hasAnyRelationshipData async created', function(assert) { assert.expect(2); Chapter.reopen({ - pages: hasMany('pages', { async: true }) + pages: hasMany('pages', { async: true }), }); let chapter = store.createRecord('chapter', { title: 'The Story Begins' }); @@ -2824,14 +3028,14 @@ test("hasMany hasAnyRelationshipData async created", function(assert) { chapter = store.createRecord('chapter', { title: 'The Story Begins', - pages: [page] + pages: [page], }); relationship = chapter._internalModel._relationships.get('pages'); assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); -test("hasMany hasAnyRelationshipData sync created", function(assert) { +test('hasMany hasAnyRelationshipData sync created', function(assert) { assert.expect(2); let chapter = store.createRecord('chapter', { title: 'The Story Begins' }); @@ -2841,7 +3045,7 @@ test("hasMany hasAnyRelationshipData sync created", function(assert) { chapter = store.createRecord('chapter', { title: 'The Story Begins', - pages: [store.createRecord('page')] + pages: [store.createRecord('page')], }); relationship = chapter._internalModel._relationships.get('pages'); @@ -2854,11 +3058,14 @@ test("Model's hasMany relationship should not be created during model creation", env.store.push({ data: { type: 'user', - id: '1' - } + id: '1', + }, }); user = env.store.peekRecord('user', 1); - assert.ok(!user._internalModel._relationships.has('messages'), 'Newly created record should not have relationships'); + assert.ok( + !user._internalModel._relationships.has('messages'), + 'Newly created record should not have relationships' + ); }); }); @@ -2867,11 +3074,14 @@ test("Model's belongsTo relationship should be created during 'get' method", fun run(() => { user = env.store.createRecord('user'); user.get('messages'); - assert.ok(user._internalModel._relationships.has('messages'), "Newly created record with relationships in params passed in its constructor should have relationships"); + assert.ok( + user._internalModel._relationships.has('messages'), + 'Newly created record with relationships in params passed in its constructor should have relationships' + ); }); }); -test("metadata is accessible when pushed as a meta property for a relationship", function(assert) { +test('metadata is accessible when pushed as a meta property for a relationship', function(assert) { assert.expect(1); let book; env.adapter.findHasMany = function() { @@ -2884,41 +3094,42 @@ test("metadata is accessible when pushed as a meta property for a relationship", type: 'book', id: '1', attributes: { - title: 'Sailing the Seven Seas' + title: 'Sailing the Seven Seas', }, relationships: { chapters: { meta: { - where: 'the lefkada sea' + where: 'the lefkada sea', }, links: { - related: '/chapters' - } - } - } - } + related: '/chapters', + }, + }, + }, + }, }); book = env.store.peekRecord('book', 1); }); run(() => { - assert.equal(book._internalModel._relationships.get('chapters').meta.where, 'the lefkada sea', 'meta is there'); + assert.equal( + book._internalModel._relationships.get('chapters').meta.where, + 'the lefkada sea', + 'meta is there' + ); }); }); -test("metadata is accessible when return from a fetchLink", function(assert) { +test('metadata is accessible when return from a fetchLink', function(assert) { assert.expect(1); env.registry.register('serializer:application', DS.RESTSerializer); env.adapter.findHasMany = function() { return resolve({ meta: { - foo: 'bar' + foo: 'bar', }, - chapters: [ - { id: '2' }, - { id: '3' } - ] + chapters: [{ id: '2' }, { id: '3' }], }); }; @@ -2930,16 +3141,16 @@ test("metadata is accessible when return from a fetchLink", function(assert) { type: 'book', id: '1', attributes: { - title: 'Sailing the Seven Seas' + title: 'Sailing the Seven Seas', }, relationships: { chapters: { links: { - related: '/chapters' - } - } - } - } + related: '/chapters', + }, + }, + }, + }, }); book = env.store.peekRecord('book', 1); }); @@ -2952,19 +3163,16 @@ test("metadata is accessible when return from a fetchLink", function(assert) { }); }); -test("metadata should be reset between requests", function(assert) { +test('metadata should be reset between requests', function(assert) { let counter = 0; env.registry.register('serializer:application', DS.RESTSerializer); env.adapter.findHasMany = function() { let data = { meta: { - foo: 'bar' + foo: 'bar', }, - chapters: [ - { id: '2' }, - { id: '3' } - ] + chapters: [{ id: '2' }, { id: '3' }], }; assert.ok(true, 'findHasMany should be called twice'); @@ -2982,33 +3190,36 @@ test("metadata should be reset between requests", function(assert) { run(() => { env.store.push({ - data: [{ - type: 'book', - id: '1', - attributes: { - title: 'Sailing the Seven Seas' + data: [ + { + type: 'book', + id: '1', + attributes: { + title: 'Sailing the Seven Seas', + }, + relationships: { + chapters: { + links: { + related: 'chapters', + }, + }, + }, }, - relationships: { - chapters: { - links: { - related: 'chapters' - } - } - } - }, { - type: 'book', - id: '2', - attributes: { - title: 'Another book title' + { + type: 'book', + id: '2', + attributes: { + title: 'Another book title', + }, + relationships: { + chapters: { + links: { + related: 'chapters', + }, + }, + }, }, - relationships: { - chapters: { - links: { - related: 'chapters' - } - } - } - }] + ], }); book1 = env.store.peekRecord('book', 1); book2 = env.store.peekRecord('book', 2); @@ -3027,16 +3238,18 @@ test("metadata should be reset between requests", function(assert) { }); }); -test("Related link should be fetched when no relationship data is present", function(assert) { +test('Related link should be fetched when no relationship data is present', function(assert) { assert.expect(3); Post.reopen({ - comments: DS.hasMany('comment', { async: true, inverse: 'post' }) + comments: DS.hasMany('comment', { async: true, inverse: 'post' }), }); Comment.reopen({ - post: DS.belongsTo('post', { async: false, inverse: 'comments' }) + post: DS.belongsTo('post', { async: false, inverse: 'comments' }), }); - env.adapter.shouldBackgroundReloadRecord = () => { return false; }; + env.adapter.shouldBackgroundReloadRecord = () => { + return false; + }; env.adapter.findRecord = () => { assert.ok(false, "The adapter's findRecord method should not be called"); }; @@ -3053,10 +3266,10 @@ test("Related link should be fetched when no relationship data is present", func id: '1', type: 'comment', attributes: { - body: 'This is comment' - } - } - ] + body: 'This is comment', + }, + }, + ], }); }; @@ -3068,11 +3281,11 @@ test("Related link should be fetched when no relationship data is present", func relationships: { comments: { links: { - related: 'get-comments' - } - } - } - } + related: 'get-comments', + }, + }, + }, + }, }); return post.get('comments').then(comments => { @@ -3081,16 +3294,18 @@ test("Related link should be fetched when no relationship data is present", func }); }); -test("Related link should take precedence over relationship data when local record data is missing", function(assert) { +test('Related link should take precedence over relationship data when local record data is missing', function(assert) { assert.expect(3); Post.reopen({ - comments: DS.hasMany('comment', { async: true, inverse: 'post' }) + comments: DS.hasMany('comment', { async: true, inverse: 'post' }), }); Comment.reopen({ - post: DS.belongsTo('post', { async: false, inverse: 'comments' }) + post: DS.belongsTo('post', { async: false, inverse: 'comments' }), }); - env.adapter.shouldBackgroundReloadRecord = () => { return false; }; + env.adapter.shouldBackgroundReloadRecord = () => { + return false; + }; env.adapter.findRecord = () => { assert.ok(false, "The adapter's findRecord method should not be called"); }; @@ -3107,10 +3322,10 @@ test("Related link should take precedence over relationship data when local reco id: '1', type: 'comment', attributes: { - body: 'This is comment' - } - } - ] + body: 'This is comment', + }, + }, + ], }); }; @@ -3122,14 +3337,12 @@ test("Related link should take precedence over relationship data when local reco relationships: { comments: { links: { - related: 'get-comments' + related: 'get-comments', }, - data: [ - { type: 'comment', id: '1' } - ] - } - } - } + data: [{ type: 'comment', id: '1' }], + }, + }, + }, }); return post.get('comments').then(comments => { @@ -3138,16 +3351,18 @@ test("Related link should take precedence over relationship data when local reco }); }); -test("Local relationship data should take precedence over related link when local record data is available", function(assert) { +test('Local relationship data should take precedence over related link when local record data is available', function(assert) { assert.expect(1); Post.reopen({ - comments: DS.hasMany('comment', { async: true, inverse: 'post' }) + comments: DS.hasMany('comment', { async: true, inverse: 'post' }), }); Comment.reopen({ - post: DS.belongsTo('post', { async: false, inverse: 'comments' }) + post: DS.belongsTo('post', { async: false, inverse: 'comments' }), }); - env.adapter.shouldBackgroundReloadRecord = () => { return false; }; + env.adapter.shouldBackgroundReloadRecord = () => { + return false; + }; env.adapter.findRecord = () => { assert.ok(false, "The adapter's findRecord method should not be called"); }; @@ -3167,23 +3382,21 @@ test("Local relationship data should take precedence over related link when loca relationships: { comments: { links: { - related: 'get-comments' + related: 'get-comments', }, - data: [ - { type: 'comment', id: '1' } - ] - } - } + data: [{ type: 'comment', id: '1' }], + }, + }, }, included: [ { id: '1', type: 'comment', attributes: { - body: 'This is comment' - } - } - ] + body: 'This is comment', + }, + }, + ], }); return post.get('comments').then(comments => { @@ -3192,16 +3405,18 @@ test("Local relationship data should take precedence over related link when loca }); }); -test("Related link should take precedence over local record data when relationship data is not initially available", function(assert) { +test('Related link should take precedence over local record data when relationship data is not initially available', function(assert) { assert.expect(3); Post.reopen({ - comments: DS.hasMany('comment', { async: true, inverse: 'post' }) + comments: DS.hasMany('comment', { async: true, inverse: 'post' }), }); Comment.reopen({ - post: DS.belongsTo('post', { async: false, inverse: 'comments' }) + post: DS.belongsTo('post', { async: false, inverse: 'comments' }), }); - env.adapter.shouldBackgroundReloadRecord = () => { return false; }; + env.adapter.shouldBackgroundReloadRecord = () => { + return false; + }; env.adapter.findRecord = () => { assert.ok(false, "The adapter's findRecord method should not be called"); }; @@ -3218,10 +3433,10 @@ test("Related link should take precedence over local record data when relationsh id: '1', type: 'comment', attributes: { - body: 'This is comment fetched by link' - } - } - ] + body: 'This is comment fetched by link', + }, + }, + ], }); }; @@ -3233,49 +3448,53 @@ test("Related link should take precedence over local record data when relationsh relationships: { comments: { links: { - related: 'get-comments' - } - } - } + related: 'get-comments', + }, + }, + }, }, included: [ { id: '1', type: 'comment', attributes: { - body: 'This is comment' + body: 'This is comment', }, relationships: { post: { data: { type: 'post', - id: '1' - } - } - } - } - ] + id: '1', + }, + }, + }, + }, + ], }); return post.get('comments').then(comments => { - assert.equal(comments.get('firstObject.body'), 'This is comment fetched by link', 'comment body is correct'); + assert.equal( + comments.get('firstObject.body'), + 'This is comment fetched by link', + 'comment body is correct' + ); }); }); }); -test("Updated related link should take precedence over relationship data and local record data", function(assert) { +test('Updated related link should take precedence over relationship data and local record data', function(assert) { assert.expect(3); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); env.adapter.findHasMany = function(store, snapshot, url, relationship) { assert.equal(url, 'comments-updated-link', 'url is correct'); assert.ok(true, "The adapter's findHasMany method should be called"); - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: 'This is updated comment' } } - ]}); + return resolve({ + data: [{ id: 1, type: 'comment', attributes: { body: 'This is updated comment' } }], + }); }; env.adapter.findRecord = function(store, type, id, snapshot) { @@ -3290,14 +3509,12 @@ test("Updated related link should take precedence over relationship data and loc relationships: { comments: { links: { - related: 'comments' + related: 'comments', }, - data: [ - { type: 'comment', id: '1' } - ] - } - } - } + data: [{ type: 'comment', id: '1' }], + }, + }, + }, }); env.store.push({ @@ -3307,31 +3524,37 @@ test("Updated related link should take precedence over relationship data and loc relationships: { comments: { links: { - related: 'comments-updated-link' - } - } - } - } + related: 'comments-updated-link', + }, + }, + }, + }, }); return post.get('comments').then(comments => { - assert.equal(comments.get('firstObject.body'), 'This is updated comment', 'comment body is correct'); + assert.equal( + comments.get('firstObject.body'), + 'This is updated comment', + 'comment body is correct' + ); }); }); }); -test("PromiseArray proxies createRecord to its ManyArray before the hasMany is loaded", function(assert) { +test('PromiseArray proxies createRecord to its ManyArray before the hasMany is loaded', function(assert) { assert.expect(1); Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); env.adapter.findHasMany = function(store, record, link, relationship) { - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "First" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ]}); + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'First' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); }; return run(() => { @@ -3342,27 +3565,27 @@ test("PromiseArray proxies createRecord to its ManyArray before the hasMany is l relationships: { comments: { links: { - related: 'someLink' - } - } - } - } + related: 'someLink', + }, + }, + }, + }, }); let comments = post.get('comments'); comments.createRecord(); return comments.then(comments => { - assert.equal(comments.get('length'), 3, "comments have 3 length, including new record"); + assert.equal(comments.get('length'), 3, 'comments have 3 length, including new record'); }); }); }); -test("deleteRecord + unloadRecord fun", function(assert) { +test('deleteRecord + unloadRecord fun', function(assert) { User.reopen({ - posts: DS.hasMany('post', { inverse: null }) + posts: DS.hasMany('post', { inverse: null }), }); Post.reopen({ - user: DS.belongsTo('user', { inverse: null, async: false }) + user: DS.belongsTo('user', { inverse: null, async: false }), }); run(() => { @@ -3372,7 +3595,7 @@ test("deleteRecord + unloadRecord fun", function(assert) { type: 'user', id: 'user-1', attributes: { - name: 'Adolfo Builes' + name: 'Adolfo Builes', }, relationships: { posts: { @@ -3381,17 +3604,17 @@ test("deleteRecord + unloadRecord fun", function(assert) { { type: 'post', id: 'post-2' }, { type: 'post', id: 'post-3' }, { type: 'post', id: 'post-4' }, - { type: 'post', id: 'post-5' } - ] - } - } + { type: 'post', id: 'post-5' }, + ], + }, + }, }, { type: 'post', id: 'post-1' }, { type: 'post', id: 'post-2' }, { type: 'post', id: 'post-3' }, { type: 'post', id: 'post-4' }, - { type: 'post', id: 'post-5' } - ] + { type: 'post', id: 'post-5' }, + ], }); let user = env.store.peekRecord('user', 'user-1'); @@ -3402,51 +3625,70 @@ test("deleteRecord + unloadRecord fun", function(assert) { return { data: null }; }; - assert.deepEqual(posts.map(x => x.get('id')), ['post-1', 'post-2', 'post-3', 'post-4', 'post-5']); + assert.deepEqual(posts.map(x => x.get('id')), [ + 'post-1', + 'post-2', + 'post-3', + 'post-4', + 'post-5', + ]); return run(() => { - return env.store.peekRecord('post', 'post-2').destroyRecord().then(record => { - return env.store.unloadRecord(record); - }); - }).then(() => { - assert.deepEqual(posts.map(x => x.get('id')), ['post-1', 'post-3', 'post-4', 'post-5']); - return env.store.peekRecord('post', 'post-3').destroyRecord().then(record => { - return env.store.unloadRecord(record); - }); - }).then(() => { - assert.deepEqual(posts.map(x => x.get('id')), ['post-1', 'post-4', 'post-5']); - return env.store.peekRecord('post', 'post-4').destroyRecord().then(record => { - return env.store.unloadRecord(record); + return env.store + .peekRecord('post', 'post-2') + .destroyRecord() + .then(record => { + return env.store.unloadRecord(record); + }); + }) + .then(() => { + assert.deepEqual(posts.map(x => x.get('id')), ['post-1', 'post-3', 'post-4', 'post-5']); + return env.store + .peekRecord('post', 'post-3') + .destroyRecord() + .then(record => { + return env.store.unloadRecord(record); + }); + }) + .then(() => { + assert.deepEqual(posts.map(x => x.get('id')), ['post-1', 'post-4', 'post-5']); + return env.store + .peekRecord('post', 'post-4') + .destroyRecord() + .then(record => { + return env.store.unloadRecord(record); + }); + }) + .then(() => { + assert.deepEqual(posts.map(x => x.get('id')), ['post-1', 'post-5']); }); - }).then(() => { - assert.deepEqual(posts.map(x => x.get('id')), ['post-1', 'post-5']); - }); }); }); -test("unloading and reloading a record with hasMany relationship - #3084", function(assert) { +test('unloading and reloading a record with hasMany relationship - #3084', function(assert) { let user; let message; run(() => { env.store.push({ - data: [{ - type: 'user', - id: 'user-1', - attributes: { - name: 'Adolfo Builes' + data: [ + { + type: 'user', + id: 'user-1', + attributes: { + name: 'Adolfo Builes', + }, + relationships: { + messages: { + data: [{ type: 'message', id: 'message-1' }], + }, + }, }, - relationships: { - messages: { - data: [ - { type: 'message', id: 'message-1' } - ] - } - } - }, { - type: 'message', - id: 'message-1' - }] + { + type: 'message', + id: 'message-1', + }, + ], }); user = env.store.peekRecord('user', 'user-1'); @@ -3463,20 +3705,20 @@ test("unloading and reloading a record with hasMany relationship - #3084", funct run(() => { // The record is resurrected for some reason. env.store.push({ - data: [{ - type: 'user', - id: 'user-1', - attributes: { - name: 'Adolfo Builes' + data: [ + { + type: 'user', + id: 'user-1', + attributes: { + name: 'Adolfo Builes', + }, + relationships: { + messages: { + data: [{ type: 'message', id: 'message-1' }], + }, + }, }, - relationships: { - messages: { - data: [ - { type: 'message', id: 'message-1' } - ] - } - } - }] + ], }); user = env.store.peekRecord('user', 'user-1'); @@ -3486,7 +3728,7 @@ test("unloading and reloading a record with hasMany relationship - #3084", funct }); }); -test("deleted records should stay deleted", function(assert) { +test('deleted records should stay deleted', function(assert) { let user; let message; @@ -3496,27 +3738,28 @@ test("deleted records should stay deleted", function(assert) { run(() => { env.store.push({ - data: [{ - type: 'user', - id: 'user-1', - attributes: { - name: 'Adolfo Builes' + data: [ + { + type: 'user', + id: 'user-1', + attributes: { + name: 'Adolfo Builes', + }, + relationships: { + messages: { + data: [{ type: 'message', id: 'message-1' }, { type: 'message', id: 'message-2' }], + }, + }, }, - relationships: { - messages: { - data: [ - { type: 'message', id: 'message-1' }, - { type: 'message', id: 'message-2' } - ] - } - } - }, { - type: 'message', - id: 'message-1' - }, { - type: 'message', - id: 'message-2' - }] + { + type: 'message', + id: 'message-1', + }, + { + type: 'message', + id: 'message-2', + }, + ], }); user = env.store.peekRecord('user', 'user-1'); @@ -3531,15 +3774,17 @@ test("deleted records should stay deleted", function(assert) { // a new message is added to the user should not resurrected the // deleted message env.store.push({ - data: [{ - type: 'message', - id: 'message-3', - relationships: { - user: { - data: { type: 'user', id: 'user-1' } - } - } - }] + data: [ + { + type: 'message', + id: 'message-3', + relationships: { + user: { + data: { type: 'user', id: 'user-1' }, + }, + }, + }, + ], }); assert.deepEqual( @@ -3559,11 +3804,11 @@ test("hasMany relationship with links doesn't trigger extra change notifications relationships: { chapters: { data: [{ type: 'chapter', id: '1' }], - links: { related: '/book/1/chapters' } - } - } + links: { related: '/book/1/chapters' }, + }, + }, }, - included: [{ type: 'chapter', id: '1' }] + included: [{ type: 'chapter', id: '1' }], }); }); @@ -3581,13 +3826,13 @@ test("hasMany relationship with links doesn't trigger extra change notifications assert.equal(count, 0); }); -test("A hasMany relationship with a link will trigger the link request even if a inverse related object is pushed to the store", function(assert) { +test('A hasMany relationship with a link will trigger the link request even if a inverse related object is pushed to the store', function(assert) { Post.reopen({ - comments: DS.hasMany('comment', { async: true }) + comments: DS.hasMany('comment', { async: true }), }); Comment.reopen({ - message: DS.belongsTo('post', { async: true}) + message: DS.belongsTo('post', { async: true }), }); const postID = '1'; @@ -3601,11 +3846,11 @@ test("A hasMany relationship with a link will trigger the link request even if a relationships: { comments: { links: { - related: '/posts/1/comments' - } - } - } - } + related: '/posts/1/comments', + }, + }, + }, + }, }); // if a related comment is pushed into the store, @@ -3616,13 +3861,13 @@ test("A hasMany relationship with a link will trigger the link request even if a data: { type: 'comment', id: '1', - attributes: { body: "First" }, + attributes: { body: 'First' }, relationships: { message: { - data: { type: 'post', id: postID } - } - } - } + data: { type: 'post', id: postID }, + }, + }, + }, }); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -3631,28 +3876,33 @@ test("A hasMany relationship with a link will trigger the link request even if a let hasManyCounter = 0; env.adapter.findHasMany = function(store, snapshot, link, relationship) { - assert.equal(relationship.type, 'comment', "findHasMany relationship type was Comment"); - assert.equal(relationship.key, 'comments', "findHasMany relationship key was comments"); - assert.equal(link, "/posts/1/comments", "findHasMany link was /posts/1/comments"); + assert.equal(relationship.type, 'comment', 'findHasMany relationship type was Comment'); + assert.equal(relationship.key, 'comments', 'findHasMany relationship key was comments'); + assert.equal(link, '/posts/1/comments', 'findHasMany link was /posts/1/comments'); hasManyCounter++; - return resolve({ data: [ - { id: 1, type: 'comment', attributes: { body: "First" } }, - { id: 2, type: 'comment', attributes: { body: "Second" } } - ]}); + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'First' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); }; const post = env.store.peekRecord('post', postID); post.get('comments').then(function(comments) { - assert.equal(comments.get('isLoaded'), true, "comments are loaded"); - assert.equal(hasManyCounter, 1, "link was requested"); - assert.equal(comments.get('length'), 2, "comments have 2 length"); - - post.hasMany('comments').reload().then(function(comments) { - assert.equal(comments.get('isLoaded'), true, "comments are loaded"); - assert.equal(hasManyCounter, 2, "link was requested"); - assert.equal(comments.get('length'), 2, "comments have 2 length"); - }); + assert.equal(comments.get('isLoaded'), true, 'comments are loaded'); + assert.equal(hasManyCounter, 1, 'link was requested'); + assert.equal(comments.get('length'), 2, 'comments have 2 length'); + + post + .hasMany('comments') + .reload() + .then(function(comments) { + assert.equal(comments.get('isLoaded'), true, 'comments are loaded'); + assert.equal(hasManyCounter, 2, 'link was requested'); + assert.equal(comments.get('length'), 2, 'comments have 2 length'); + }); }); }); }); diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index 5483d77e124..1c913b5e739 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -7,23 +7,19 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; -let { - Model, - hasMany, - belongsTo -} = DS; +let { Model, hasMany, belongsTo } = DS; var Post, Comment, Message, User; module('integration/relationships/inverse_relationships - Inverse Relationships'); -test("When a record is added to a has-many relationship, the inverse belongsTo is determined automatically", function(assert) { +test('When a record is added to a has-many relationship, the inverse belongsTo is determined automatically', function(assert) { Post = DS.Model.extend({ - comments: DS.hasMany('comment', { async: false }) + comments: DS.hasMany('comment', { async: false }), }); Comment = DS.Model.extend({ - post: DS.belongsTo('post', { async: false }) + post: DS.belongsTo('post', { async: false }), }); var env = setupStore({ post: Post, comment: Comment }); @@ -32,74 +28,90 @@ test("When a record is added to a has-many relationship, the inverse belongsTo i let comment = store.createRecord('comment'); let post = store.createRecord('post'); - assert.equal(comment.get('post'), null, "no post has been set on the comment"); + assert.equal(comment.get('post'), null, 'no post has been set on the comment'); run(function() { post.get('comments').pushObject(comment); }); - assert.equal(comment.get('post'), post, "post was set on the comment"); + assert.equal(comment.get('post'), post, 'post was set on the comment'); }); -test("Inverse relationships can be explicitly nullable", function(assert) { +test('Inverse relationships can be explicitly nullable', function(assert) { User = DS.Model.extend(); Post = DS.Model.extend({ lastParticipant: DS.belongsTo('user', { inverse: null, async: false }), - participants: DS.hasMany('user', { inverse: 'posts', async: false }) + participants: DS.hasMany('user', { inverse: 'posts', async: false }), }); User.reopen({ - posts: DS.hasMany('post', { inverse: 'participants', async: false }) + posts: DS.hasMany('post', { inverse: 'participants', async: false }), }); var store = createStore({ user: User, - post: Post + post: Post, }); let user = store.createRecord('user'); let post = store.createRecord('post'); - assert.equal(user.inverseFor('posts').name, 'participants', 'User.posts inverse is Post.participants'); + assert.equal( + user.inverseFor('posts').name, + 'participants', + 'User.posts inverse is Post.participants' + ); assert.equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); - assert.equal(post.inverseFor('participants').name, 'posts', 'Post.participants inverse is User.posts'); + assert.equal( + post.inverseFor('participants').name, + 'posts', + 'Post.participants inverse is User.posts' + ); }); -test("Null inverses are excluded from potential relationship resolutions", function(assert) { +test('Null inverses are excluded from potential relationship resolutions', function(assert) { User = Model.extend(); Post = Model.extend({ lastParticipant: belongsTo('user', { inverse: null, async: false }), - participants: hasMany('user', { async: false }) + participants: hasMany('user', { async: false }), }); User.reopen({ - posts: hasMany('post', { async: false }) + posts: hasMany('post', { async: false }), }); let store = createStore({ user: User, - post: Post + post: Post, }); let user = store.createRecord('user'); let post = store.createRecord('post'); - assert.equal(user.inverseFor('posts').name, 'participants', 'User.posts inverse is Post.participants'); + assert.equal( + user.inverseFor('posts').name, + 'participants', + 'User.posts inverse is Post.participants' + ); assert.equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); - assert.equal(post.inverseFor('participants').name, 'posts', 'Post.participants inverse is User.posts'); + assert.equal( + post.inverseFor('participants').name, + 'posts', + 'Post.participants inverse is User.posts' + ); }); -test("When a record is added to a has-many relationship, the inverse belongsTo can be set explicitly", function(assert) { +test('When a record is added to a has-many relationship, the inverse belongsTo can be set explicitly', function(assert) { Post = DS.Model.extend({ - comments: DS.hasMany('comment', { inverse: 'redPost', async: false }) + comments: DS.hasMany('comment', { inverse: 'redPost', async: false }), }); Comment = DS.Model.extend({ onePost: DS.belongsTo('post', { async: false }), twoPost: DS.belongsTo('post', { async: false }), redPost: DS.belongsTo('post', { async: false }), - bluePost: DS.belongsTo('post', { async: false }) + bluePost: DS.belongsTo('post', { async: false }), }); var env = setupStore({ post: Post, comment: Comment }); @@ -108,30 +120,30 @@ test("When a record is added to a has-many relationship, the inverse belongsTo c let comment = store.createRecord('comment'); let post = store.createRecord('post'); - assert.equal(comment.get('onePost'), null, "onePost has not been set on the comment"); - assert.equal(comment.get('twoPost'), null, "twoPost has not been set on the comment"); - assert.equal(comment.get('redPost'), null, "redPost has not been set on the comment"); - assert.equal(comment.get('bluePost'), null, "bluePost has not been set on the comment"); + assert.equal(comment.get('onePost'), null, 'onePost has not been set on the comment'); + assert.equal(comment.get('twoPost'), null, 'twoPost has not been set on the comment'); + assert.equal(comment.get('redPost'), null, 'redPost has not been set on the comment'); + assert.equal(comment.get('bluePost'), null, 'bluePost has not been set on the comment'); run(function() { post.get('comments').pushObject(comment); }); - assert.equal(comment.get('onePost'), null, "onePost has not been set on the comment"); - assert.equal(comment.get('twoPost'), null, "twoPost has not been set on the comment"); - assert.equal(comment.get('redPost'), post, "redPost has been set on the comment"); - assert.equal(comment.get('bluePost'), null, "bluePost has not been set on the comment"); + assert.equal(comment.get('onePost'), null, 'onePost has not been set on the comment'); + assert.equal(comment.get('twoPost'), null, 'twoPost has not been set on the comment'); + assert.equal(comment.get('redPost'), post, 'redPost has been set on the comment'); + assert.equal(comment.get('bluePost'), null, 'bluePost has not been set on the comment'); }); test("When a record's belongsTo relationship is set, it can specify the inverse hasMany to which the new child should be added", function(assert) { Post = DS.Model.extend({ meComments: DS.hasMany('comment', { async: false }), youComments: DS.hasMany('comment', { async: false }), - everyoneWeKnowComments: DS.hasMany('comment', { async: false }) + everyoneWeKnowComments: DS.hasMany('comment', { async: false }), }); Comment = DS.Model.extend({ - post: DS.belongsTo('post', { inverse: 'youComments', async: false }) + post: DS.belongsTo('post', { inverse: 'youComments', async: false }), }); var env = setupStore({ post: Post, comment: Comment }); @@ -142,27 +154,31 @@ test("When a record's belongsTo relationship is set, it can specify the inverse comment = store.createRecord('comment'); post = store.createRecord('post'); - assert.equal(post.get('meComments.length'), 0, "meComments has no posts"); - assert.equal(post.get('youComments.length'), 0, "youComments has no posts"); - assert.equal(post.get('everyoneWeKnowComments.length'), 0, "everyoneWeKnowComments has no posts"); + assert.equal(post.get('meComments.length'), 0, 'meComments has no posts'); + assert.equal(post.get('youComments.length'), 0, 'youComments has no posts'); + assert.equal( + post.get('everyoneWeKnowComments.length'), + 0, + 'everyoneWeKnowComments has no posts' + ); comment.set('post', post); }); assert.equal(comment.get('post'), post, 'The post that was set can be retrieved'); - assert.equal(post.get('meComments.length'), 0, "meComments has no posts"); - assert.equal(post.get('youComments.length'), 1, "youComments had the post added"); - assert.equal(post.get('everyoneWeKnowComments.length'), 0, "everyoneWeKnowComments has no posts"); + assert.equal(post.get('meComments.length'), 0, 'meComments has no posts'); + assert.equal(post.get('youComments.length'), 1, 'youComments had the post added'); + assert.equal(post.get('everyoneWeKnowComments.length'), 0, 'everyoneWeKnowComments has no posts'); }); -test("When setting a belongsTo, the OneToOne invariant is respected even when other records have been previously used", function(assert) { +test('When setting a belongsTo, the OneToOne invariant is respected even when other records have been previously used', function(assert) { Post = DS.Model.extend({ - bestComment: DS.belongsTo('comment', { async: false }) + bestComment: DS.belongsTo('comment', { async: false }), }); Comment = DS.Model.extend({ - post: DS.belongsTo('post', { async: false }) + post: DS.belongsTo('post', { async: false }), }); var env = setupStore({ post: Post, comment: Comment }); @@ -190,18 +206,18 @@ test("When setting a belongsTo, the OneToOne invariant is respected even when ot assert.equal(post2.get('bestComment'), comment); }); -test("When setting a belongsTo, the OneToOne invariant is transitive", function(assert) { +test('When setting a belongsTo, the OneToOne invariant is transitive', function(assert) { Post = DS.Model.extend({ - bestComment: DS.belongsTo('comment', { async: false }) + bestComment: DS.belongsTo('comment', { async: false }), }); Comment = DS.Model.extend({ - post: DS.belongsTo('post', { async: false }) + post: DS.belongsTo('post', { async: false }), }); var store = createStore({ post: Post, - comment: Comment + comment: Comment, }); let comment = store.createRecord('comment'); @@ -225,18 +241,18 @@ test("When setting a belongsTo, the OneToOne invariant is transitive", function( assert.equal(post2.get('bestComment'), comment); }); -test("When setting a belongsTo, the OneToOne invariant is commutative", function(assert) { +test('When setting a belongsTo, the OneToOne invariant is commutative', function(assert) { Post = DS.Model.extend({ - bestComment: DS.belongsTo('comment', { async: false }) + bestComment: DS.belongsTo('comment', { async: false }), }); Comment = DS.Model.extend({ - post: DS.belongsTo('post', { async: false }) + post: DS.belongsTo('post', { async: false }), }); var store = createStore({ post: Post, - comment: Comment + comment: Comment, }); let post = store.createRecord('post'); @@ -260,14 +276,14 @@ test("When setting a belongsTo, the OneToOne invariant is commutative", function assert.equal(comment2.get('post'), post); }); -test("OneToNone relationship works", function(assert) { +test('OneToNone relationship works', function(assert) { assert.expect(3); Post = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); Comment = DS.Model.extend({ - post: DS.belongsTo('post', { async: false }) + post: DS.belongsTo('post', { async: false }), }); var env = setupStore({ post: Post, comment: Comment }); @@ -293,21 +309,20 @@ test("OneToNone relationship works", function(assert) { assert.equal(comment.get('post'), post1, 'the post is re-set to the first one'); }); - -test("When a record is added to or removed from a polymorphic has-many relationship, the inverse belongsTo can be set explicitly", function(assert) { +test('When a record is added to or removed from a polymorphic has-many relationship, the inverse belongsTo can be set explicitly', function(assert) { User = DS.Model.extend({ messages: DS.hasMany('message', { async: false, inverse: 'redUser', - polymorphic: true - }) + polymorphic: true, + }), }); Message = DS.Model.extend({ oneUser: DS.belongsTo('user', { async: false }), twoUser: DS.belongsTo('user', { async: false }), redUser: DS.belongsTo('user', { async: false }), - blueUser: DS.belongsTo('user', { async: false }) + blueUser: DS.belongsTo('user', { async: false }), }); Post = Message.extend(); @@ -318,39 +333,39 @@ test("When a record is added to or removed from a polymorphic has-many relations let post = store.createRecord('post'); let user = store.createRecord('user'); - assert.equal(post.get('oneUser'), null, "oneUser has not been set on the user"); - assert.equal(post.get('twoUser'), null, "twoUser has not been set on the user"); - assert.equal(post.get('redUser'), null, "redUser has not been set on the user"); - assert.equal(post.get('blueUser'), null, "blueUser has not been set on the user"); + assert.equal(post.get('oneUser'), null, 'oneUser has not been set on the user'); + assert.equal(post.get('twoUser'), null, 'twoUser has not been set on the user'); + assert.equal(post.get('redUser'), null, 'redUser has not been set on the user'); + assert.equal(post.get('blueUser'), null, 'blueUser has not been set on the user'); run(function() { user.get('messages').pushObject(post); }); - assert.equal(post.get('oneUser'), null, "oneUser has not been set on the user"); - assert.equal(post.get('twoUser'), null, "twoUser has not been set on the user"); - assert.equal(post.get('redUser'), user, "redUser has been set on the user"); - assert.equal(post.get('blueUser'), null, "blueUser has not been set on the user"); + assert.equal(post.get('oneUser'), null, 'oneUser has not been set on the user'); + assert.equal(post.get('twoUser'), null, 'twoUser has not been set on the user'); + assert.equal(post.get('redUser'), user, 'redUser has been set on the user'); + assert.equal(post.get('blueUser'), null, 'blueUser has not been set on the user'); run(function() { user.get('messages').popObject(); }); - assert.equal(post.get('oneUser'), null, "oneUser has not been set on the user"); - assert.equal(post.get('twoUser'), null, "twoUser has not been set on the user"); - assert.equal(post.get('redUser'), null, "redUser has bot been set on the user"); - assert.equal(post.get('blueUser'), null, "blueUser has not been set on the user"); + assert.equal(post.get('oneUser'), null, 'oneUser has not been set on the user'); + assert.equal(post.get('twoUser'), null, 'twoUser has not been set on the user'); + assert.equal(post.get('redUser'), null, 'redUser has bot been set on the user'); + assert.equal(post.get('blueUser'), null, 'blueUser has not been set on the user'); }); test("When a record's belongsTo relationship is set, it can specify the inverse polymorphic hasMany to which the new child should be added or removed", function(assert) { User = DS.Model.extend({ meMessages: DS.hasMany('message', { polymorphic: true, async: false }), youMessages: DS.hasMany('message', { polymorphic: true, async: false }), - everyoneWeKnowMessages: DS.hasMany('message', { polymorphic: true, async: false }) + everyoneWeKnowMessages: DS.hasMany('message', { polymorphic: true, async: false }), }); Message = DS.Model.extend({ - user: DS.belongsTo('user', { inverse: 'youMessages', async: false }) + user: DS.belongsTo('user', { inverse: 'youMessages', async: false }), }); Post = Message.extend(); @@ -361,32 +376,32 @@ test("When a record's belongsTo relationship is set, it can specify the inverse let user = store.createRecord('user'); let post = store.createRecord('post'); - assert.equal(user.get('meMessages.length'), 0, "meMessages has no posts"); - assert.equal(user.get('youMessages.length'), 0, "youMessages has no posts"); - assert.equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(user.get('meMessages.length'), 0, 'meMessages has no posts'); + assert.equal(user.get('youMessages.length'), 0, 'youMessages has no posts'); + assert.equal(user.get('everyoneWeKnowMessages.length'), 0, 'everyoneWeKnowMessages has no posts'); run(function() { post.set('user', user); }); - assert.equal(user.get('meMessages.length'), 0, "meMessages has no posts"); - assert.equal(user.get('youMessages.length'), 1, "youMessages had the post added"); - assert.equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(user.get('meMessages.length'), 0, 'meMessages has no posts'); + assert.equal(user.get('youMessages.length'), 1, 'youMessages had the post added'); + assert.equal(user.get('everyoneWeKnowMessages.length'), 0, 'everyoneWeKnowMessages has no posts'); run(function() { post.set('user', null); }); - assert.equal(user.get('meMessages.length'), 0, "meMessages has no posts"); - assert.equal(user.get('youMessages.length'), 0, "youMessages has no posts"); - assert.equal(user.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(user.get('meMessages.length'), 0, 'meMessages has no posts'); + assert.equal(user.get('youMessages.length'), 0, 'youMessages has no posts'); + assert.equal(user.get('everyoneWeKnowMessages.length'), 0, 'everyoneWeKnowMessages has no posts'); }); test("When a record's polymorphic belongsTo relationship is set, it can specify the inverse hasMany to which the new child should be added", function(assert) { Message = DS.Model.extend({ meMessages: DS.hasMany('comment', { inverse: null, async: false }), youMessages: DS.hasMany('comment', { inverse: 'message', async: false }), - everyoneWeKnowMessages: DS.hasMany('comment', { inverse: null, async: false }) + everyoneWeKnowMessages: DS.hasMany('comment', { inverse: null, async: false }), }); Post = Message.extend(); @@ -395,8 +410,8 @@ test("When a record's polymorphic belongsTo relationship is set, it can specify message: DS.belongsTo('message', { async: false, polymorphic: true, - inverse: 'youMessages' - }) + inverse: 'youMessages', + }), }); var env = setupStore({ comment: Comment, message: Message, post: Post }); @@ -405,33 +420,35 @@ test("When a record's polymorphic belongsTo relationship is set, it can specify let comment = store.createRecord('comment'); let post = store.createRecord('post'); - assert.equal(post.get('meMessages.length'), 0, "meMessages has no posts"); - assert.equal(post.get('youMessages.length'), 0, "youMessages has no posts"); - assert.equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(post.get('meMessages.length'), 0, 'meMessages has no posts'); + assert.equal(post.get('youMessages.length'), 0, 'youMessages has no posts'); + assert.equal(post.get('everyoneWeKnowMessages.length'), 0, 'everyoneWeKnowMessages has no posts'); run(function() { comment.set('message', post); }); - assert.equal(post.get('meMessages.length'), 0, "meMessages has no posts"); - assert.equal(post.get('youMessages.length'), 1, "youMessages had the post added"); - assert.equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(post.get('meMessages.length'), 0, 'meMessages has no posts'); + assert.equal(post.get('youMessages.length'), 1, 'youMessages had the post added'); + assert.equal(post.get('everyoneWeKnowMessages.length'), 0, 'everyoneWeKnowMessages has no posts'); run(function() { comment.set('message', null); }); - assert.equal(post.get('meMessages.length'), 0, "meMessages has no posts"); - assert.equal(post.get('youMessages.length'), 0, "youMessages has no posts"); - assert.equal(post.get('everyoneWeKnowMessages.length'), 0, "everyoneWeKnowMessages has no posts"); + assert.equal(post.get('meMessages.length'), 0, 'meMessages has no posts'); + assert.equal(post.get('youMessages.length'), 0, 'youMessages has no posts'); + assert.equal(post.get('everyoneWeKnowMessages.length'), 0, 'everyoneWeKnowMessages has no posts'); }); -testInDebug("Inverse relationships that don't exist throw a nice error for a hasMany", function(assert) { +testInDebug("Inverse relationships that don't exist throw a nice error for a hasMany", function( + assert +) { User = DS.Model.extend(); Comment = DS.Model.extend(); Post = DS.Model.extend({ - comments: DS.hasMany('comment', { inverse: 'testPost', async: false }) + comments: DS.hasMany('comment', { inverse: 'testPost', async: false }), }); var env = setupStore({ post: Post, comment: Comment, user: User }); @@ -447,12 +464,14 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a has }, /We found no inverse relationships by the name of 'testPost' on the 'comment' model/); }); -testInDebug("Inverse relationships that don't exist throw a nice error for a belongsTo", function(assert) { +testInDebug("Inverse relationships that don't exist throw a nice error for a belongsTo", function( + assert +) { User = DS.Model.extend(); Comment = DS.Model.extend(); Post = DS.Model.extend({ - user: DS.belongsTo('user', { inverse: 'testPost', async: false }) + user: DS.belongsTo('user', { inverse: 'testPost', async: false }), }); var env = setupStore({ post: Post, comment: Comment, user: User }); @@ -467,22 +486,22 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a bel }, /We found no inverse relationships by the name of 'testPost' on the 'user' model/); }); -skipRecordData("inverseFor short-circuits when inverse is null", function(assert) { +skipRecordData('inverseFor short-circuits when inverse is null', function(assert) { assert.expect(4); Post = DS.Model.extend({ - comments: DS.hasMany('comment', { async: false, inverse: null }) + comments: DS.hasMany('comment', { async: false, inverse: null }), }); Comment = DS.Model.extend({ - post: DS.belongsTo('post', { async: false, inverse: null }) + post: DS.belongsTo('post', { async: false, inverse: null }), }); User = DS.Model.extend({ - messages: DS.hasMany('message', { async: false, inverse: 'user' }) + messages: DS.hasMany('message', { async: false, inverse: 'user' }), }); Message = DS.Model.extend({ - user: DS.belongsTo('user', { async: false, inverse: 'messages' }) + user: DS.belongsTo('user', { async: false, inverse: 'messages' }), }); var env = setupStore({ post: Post, comment: Comment, user: User, message: Message }); @@ -514,16 +533,16 @@ skipRecordData("inverseFor short-circuits when inverse is null", function(assert data: [ { id: '1', - type: 'comment' + type: 'comment', }, { id: '2', - type: 'comment' - } - ] - } - } - } + type: 'comment', + }, + ], + }, + }, + }, }); store.push({ data: [ @@ -534,10 +553,10 @@ skipRecordData("inverseFor short-circuits when inverse is null", function(assert post: { data: { id: '1', - type: 'post' - } - } - } + type: 'post', + }, + }, + }, }, { id: '2', @@ -546,12 +565,12 @@ skipRecordData("inverseFor short-circuits when inverse is null", function(assert post: { data: { id: '1', - type: 'post' - } - } - } - } - ] + type: 'post', + }, + }, + }, + }, + ], }); store.push({ data: { @@ -562,16 +581,16 @@ skipRecordData("inverseFor short-circuits when inverse is null", function(assert data: [ { id: '1', - type: 'message' + type: 'message', }, { id: '2', - type: 'message' - } - ] - } - } - } + type: 'message', + }, + ], + }, + }, + }, }); store.push({ data: [ @@ -582,10 +601,10 @@ skipRecordData("inverseFor short-circuits when inverse is null", function(assert user: { data: { id: '1', - type: 'user' - } - } - } + type: 'user', + }, + }, + }, }, { id: '2', @@ -594,32 +613,32 @@ skipRecordData("inverseFor short-circuits when inverse is null", function(assert post: { data: { id: '1', - type: 'user' - } - } - } - } - ] + type: 'user', + }, + }, + }, + }, + ], }); }); }); -testRecordData("inverseFor is only called when inverse is not null", function(assert) { +testRecordData('inverseFor is only called when inverse is not null', function(assert) { assert.expect(2); Post = DS.Model.extend({ - comments: DS.hasMany('comment', { async: false, inverse: null }) + comments: DS.hasMany('comment', { async: false, inverse: null }), }); Comment = DS.Model.extend({ - post: DS.belongsTo('post', { async: false, inverse: null }) + post: DS.belongsTo('post', { async: false, inverse: null }), }); User = DS.Model.extend({ - messages: DS.hasMany('message', { async: false, inverse: 'user' }) + messages: DS.hasMany('message', { async: false, inverse: 'user' }), }); Message = DS.Model.extend({ - user: DS.belongsTo('user', { async: false, inverse: 'messages' }) + user: DS.belongsTo('user', { async: false, inverse: 'messages' }), }); var env = setupStore({ post: Post, comment: Comment, user: User, message: Message }); @@ -651,16 +670,16 @@ testRecordData("inverseFor is only called when inverse is not null", function(as data: [ { id: '1', - type: 'comment' + type: 'comment', }, { id: '2', - type: 'comment' - } - ] - } - } - } + type: 'comment', + }, + ], + }, + }, + }, }); store.push({ data: [ @@ -671,10 +690,10 @@ testRecordData("inverseFor is only called when inverse is not null", function(as post: { data: { id: '1', - type: 'post' - } - } - } + type: 'post', + }, + }, + }, }, { id: '2', @@ -683,12 +702,12 @@ testRecordData("inverseFor is only called when inverse is not null", function(as post: { data: { id: '1', - type: 'post' - } - } - } - } - ] + type: 'post', + }, + }, + }, + }, + ], }); store.push({ data: { @@ -699,16 +718,16 @@ testRecordData("inverseFor is only called when inverse is not null", function(as data: [ { id: '1', - type: 'message' + type: 'message', }, { id: '2', - type: 'message' - } - ] - } - } - } + type: 'message', + }, + ], + }, + }, + }, }); store.push({ data: [ @@ -719,10 +738,10 @@ testRecordData("inverseFor is only called when inverse is not null", function(as user: { data: { id: '1', - type: 'user' - } - } - } + type: 'user', + }, + }, + }, }, { id: '2', @@ -731,27 +750,30 @@ testRecordData("inverseFor is only called when inverse is not null", function(as post: { data: { id: '1', - type: 'user' - } - } - } - } - ] + type: 'user', + }, + }, + }, + }, + ], }); }); }); -testInDebug("Inverse null relationships with models that don't exist throw a nice error if trying to use that relationship", function(assert) { - User = DS.Model.extend({ - post: DS.belongsTo('post', { inverse: null }) - }); +testInDebug( + "Inverse null relationships with models that don't exist throw a nice error if trying to use that relationship", + function(assert) { + User = DS.Model.extend({ + post: DS.belongsTo('post', { inverse: null }), + }); - let env = setupStore({ user: User }); + let env = setupStore({ user: User }); - assert.expectAssertion(() => { - env.store.createRecord('user', { post: {}}); - }, /No model was found for/) + assert.expectAssertion(() => { + env.store.createRecord('user', { post: {} }); + }, /No model was found for/); - // but don't error if the relationship is not used - env.store.createRecord('user', {}); -}); + // but don't error if the relationship is not used + env.store.createRecord('user', {}); + } +); diff --git a/tests/integration/relationships/json-api-links-test.js b/tests/integration/relationships/json-api-links-test.js index d92ea3d1879..d875ce1ed0a 100644 --- a/tests/integration/relationships/json-api-links-test.js +++ b/tests/integration/relationships/json-api-links-test.js @@ -2,39 +2,37 @@ import { run } from '@ember/runloop'; import { get } from '@ember/object'; import { resolve } from 'rsvp'; import setupStore from 'dummy/tests/helpers/store'; -import { - reset as resetModelFactoryInjection -} from 'dummy/tests/helpers/model-factory-injection'; +import { reset as resetModelFactoryInjection } from 'dummy/tests/helpers/model-factory-injection'; import { module, test } from 'qunit'; import DS from 'ember-data'; -import JSONAPIAdapter from "ember-data/adapters/json-api"; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; import deepCopy from 'dummy/tests/helpers/deep-copy'; const { Model, attr, hasMany, belongsTo } = DS; let env, User, Organisation; -module("integration/relationship/json-api-links | Relationship state updates", { +module('integration/relationship/json-api-links | Relationship state updates', { beforeEach() {}, afterEach() { resetModelFactoryInjection(); run(env.container, 'destroy'); - } + }, }); -test("Loading link with inverse:null on other model caches the two ends separately", function (assert) { +test('Loading link with inverse:null on other model caches the two ends separately', function(assert) { User = DS.Model.extend({ - organisation: belongsTo('organisation', { inverse: null }) + organisation: belongsTo('organisation', { inverse: null }), }); Organisation = DS.Model.extend({ - adminUsers: hasMany('user', { inverse: null }) + adminUsers: hasMany('user', { inverse: null }), }); env = setupStore({ user: User, - organisation: Organisation + organisation: Organisation, }); env.registry.optionsForType('serializer', { singleton: false }); @@ -45,74 +43,89 @@ test("Loading link with inverse:null on other model caches the two ends separate User = store.modelFor('user'); Organisation = store.modelFor('organisation'); - env.registry.register('adapter:user', DS.JSONAPISerializer.extend({ - findRecord(store, type, id) { - return resolve({ - data: { - id, - type: 'user', - relationships: { - organisation: { - data: { id: 1, type: 'organisation' } - } - } - } - }); - } - })); - - env.registry.register('adapter:organisation', DS.JSONAPISerializer.extend({ - findRecord(store, type, id) { - return resolve({ - data: { - type: 'organisation', - id, - relationships: { - 'admin-users': { - links: { - related: '/org-admins' - } - } - } - } - }); - } - })); + env.registry.register( + 'adapter:user', + DS.JSONAPISerializer.extend({ + findRecord(store, type, id) { + return resolve({ + data: { + id, + type: 'user', + relationships: { + organisation: { + data: { id: 1, type: 'organisation' }, + }, + }, + }, + }); + }, + }) + ); + + env.registry.register( + 'adapter:organisation', + DS.JSONAPISerializer.extend({ + findRecord(store, type, id) { + return resolve({ + data: { + type: 'organisation', + id, + relationships: { + 'admin-users': { + links: { + related: '/org-admins', + }, + }, + }, + }, + }); + }, + }) + ); return run(() => { - return store.findRecord('user', 1) - .then(user1 => { - assert.ok(user1, 'user should be populated'); - - return store.findRecord('organisation', 2) - .then(org2FromFind => { - assert.equal(user1.belongsTo('organisation').remoteType(), 'id', `user's belongsTo is based on id`); - assert.equal(user1.belongsTo('organisation').id(), 1, `user's belongsTo has its id populated`); - - return user1.get('organisation') - .then(orgFromUser => { - assert.equal(user1.belongsTo('organisation').belongsToRelationship.relationshipIsStale, false, 'user should have loaded its belongsTo relationship'); - - assert.ok(org2FromFind, 'organisation we found should be populated'); - assert.ok(orgFromUser, 'user\'s organisation should be populated'); - }) - }) - }) + return store.findRecord('user', 1).then(user1 => { + assert.ok(user1, 'user should be populated'); + + return store.findRecord('organisation', 2).then(org2FromFind => { + assert.equal( + user1.belongsTo('organisation').remoteType(), + 'id', + `user's belongsTo is based on id` + ); + assert.equal( + user1.belongsTo('organisation').id(), + 1, + `user's belongsTo has its id populated` + ); + + return user1.get('organisation').then(orgFromUser => { + assert.equal( + user1.belongsTo('organisation').belongsToRelationship.relationshipIsStale, + false, + 'user should have loaded its belongsTo relationship' + ); + + assert.ok(org2FromFind, 'organisation we found should be populated'); + assert.ok(orgFromUser, "user's organisation should be populated"); + }); + }); + }); }); }); -test("Pushing child record should not mark parent:children as loaded", function (assert) { +test('Pushing child record should not mark parent:children as loaded', function(assert) { let Child = DS.Model.extend({ - parent: belongsTo('parent', { inverse: 'children' }) + parent: belongsTo('parent', { inverse: 'children' }), }); let Parent = DS.Model.extend({ - children: hasMany('child', { inverse: 'parent' }) + children: hasMany('child', { inverse: 'parent' }), }); env = setupStore({ parent: Parent, - child: Child + child: Child, }); env.registry.optionsForType('serializer', { singleton: false }); @@ -131,11 +144,11 @@ test("Pushing child record should not mark parent:children as loaded", function relationships: { children: { links: { - related: '/parent/1/children' - } - } - } - } + related: '/parent/1/children', + }, + }, + }, + }, }); store.push({ @@ -146,23 +159,27 @@ test("Pushing child record should not mark parent:children as loaded", function parent: { data: { id: 'p1', - type: 'parent' - } - } - } - } + type: 'parent', + }, + }, + }, + }, }); - assert.equal(parent.hasMany('children').hasManyRelationship.relationshipIsStale, true, 'parent should think that children still needs to be loaded'); + assert.equal( + parent.hasMany('children').hasManyRelationship.relationshipIsStale, + true, + 'parent should think that children still needs to be loaded' + ); }); }); -test("pushing has-many payloads with data (no links), then more data (no links) works as expected", function(assert) { +test('pushing has-many payloads with data (no links), then more data (no links) works as expected', function(assert) { const User = Model.extend({ - pets: hasMany('pet', { async: true, inverse: 'owner' }) + pets: hasMany('pet', { async: true, inverse: 'owner' }), }); const Pet = Model.extend({ - owner: belongsTo('user', { async: false, inverse: 'pets' }) + owner: belongsTo('user', { async: false, inverse: 'pets' }), }); const Adapter = JSONAPIAdapter.extend({ findHasMany() { @@ -179,63 +196,62 @@ test("pushing has-many payloads with data (no links), then more data (no links) id, relationships: { owner: { - data: { type: 'user', id: '1' } - } - } - } + data: { type: 'user', id: '1' }, + }, + }, + }, }); - } + }, }); env = setupStore({ adapter: Adapter, user: User, - pet: Pet + pet: Pet, }); let { store } = env; // push data, no links - run(() => store.push({ - data: { - type: 'user', - id: '1', - relationships: { - pets: { - data: [ - { type: 'pet', id: '1' } - ] - } - } - } - })); + run(() => + store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + data: [{ type: 'pet', id: '1' }], + }, + }, + }, + }) + ); // push links, no data - run(() => store.push({ - data: { - type: 'user', - id: '1', - relationships: { - pets: { - data: [ - { type: 'pet', id: '2' }, - { type: 'pet', id: '3' } - ] - } - } - } - })); + run(() => + store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + data: [{ type: 'pet', id: '2' }, { type: 'pet', id: '3' }], + }, + }, + }, + }) + ); let Chris = run(() => store.peekRecord('user', '1')); run(() => get(Chris, 'pets')); }); -test("pushing has-many payloads with data (no links), then links (no data) works as expected", function(assert) { +test('pushing has-many payloads with data (no links), then links (no data) works as expected', function(assert) { const User = Model.extend({ - pets: hasMany('pet', { async: true, inverse: 'owner' }) + pets: hasMany('pet', { async: true, inverse: 'owner' }), }); const Pet = Model.extend({ - owner: belongsTo('user', { async: false, inverse: 'pets' }) + owner: belongsTo('user', { async: false, inverse: 'pets' }), }); const Adapter = JSONAPIAdapter.extend({ findHasMany(_, __, link) { @@ -247,20 +263,20 @@ test("pushing has-many payloads with data (no links), then links (no data) works id: '1', relationships: { owner: { - data: { type: 'user', id: '1' } - } - } + data: { type: 'user', id: '1' }, + }, + }, }, { type: 'pet', id: '2', relationships: { owner: { - data: { type: 'user', id: '1' } - } - } - } - ] + data: { type: 'user', id: '1' }, + }, + }, + }, + ], }); }, findMany() { @@ -268,57 +284,59 @@ test("pushing has-many payloads with data (no links), then links (no data) works }, findRecord() { assert.ok(false, 'adapter findRecord called instead of using findHasMany with a link'); - } + }, }); env = setupStore({ adapter: Adapter, user: User, - pet: Pet + pet: Pet, }); let { store } = env; // push data, no links - run(() => store.push({ - data: { - type: 'user', - id: '1', - relationships: { - pets: { - data: [ - { type: 'pet', id: '1' } - ] - } - } - } - })); + run(() => + store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + data: [{ type: 'pet', id: '1' }], + }, + }, + }, + }) + ); // push links, no data - run(() => store.push({ - data: { - type: 'user', - id: '1', - relationships: { - pets: { - links: { - related: './user/1/pets' - } - } - } - } - })); + run(() => + store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + links: { + related: './user/1/pets', + }, + }, + }, + }, + }) + ); let Chris = run(() => store.peekRecord('user', '1')); run(() => get(Chris, 'pets')); }); -test("pushing has-many payloads with links (no data), then data (no links) works as expected", function(assert) { +test('pushing has-many payloads with links (no data), then data (no links) works as expected', function(assert) { const User = Model.extend({ - pets: hasMany('pet', { async: true, inverse: 'owner' }) + pets: hasMany('pet', { async: true, inverse: 'owner' }), }); const Pet = Model.extend({ - owner: belongsTo('user', { async: false, inverse: 'pets' }) + owner: belongsTo('user', { async: false, inverse: 'pets' }), }); const Adapter = JSONAPIAdapter.extend({ findHasMany(_, __, link) { @@ -330,20 +348,20 @@ test("pushing has-many payloads with links (no data), then data (no links) works id: '1', relationships: { owner: { - data: { type: 'user', id: '1' } - } - } + data: { type: 'user', id: '1' }, + }, + }, }, { type: 'pet', id: '2', relationships: { owner: { - data: { type: 'user', id: '1' } - } - } - } - ] + data: { type: 'user', id: '1' }, + }, + }, + }, + ], }); }, findMany() { @@ -351,46 +369,48 @@ test("pushing has-many payloads with links (no data), then data (no links) works }, findRecord() { assert.ok(false, 'adapter findRecord called instead of using findHasMany with a link'); - } + }, }); env = setupStore({ adapter: Adapter, user: User, - pet: Pet + pet: Pet, }); let { store } = env; // push links, no data - run(() => store.push({ - data: { - type: 'user', - id: '1', - relationships: { - pets: { - links: { - related: './user/1/pets' - } - } - } - } - })); + run(() => + store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + links: { + related: './user/1/pets', + }, + }, + }, + }, + }) + ); // push data, no links - run(() => store.push({ - data: { - type: 'user', - id: '1', - relationships: { - pets: { - data: [ - { type: 'pet', id: '1' } - ] - } - } - } - })); + run(() => + store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + data: [{ type: 'pet', id: '1' }], + }, + }, + }, + }) + ); let Chris = run(() => store.peekRecord('user', '1')); @@ -398,12 +418,12 @@ test("pushing has-many payloads with links (no data), then data (no links) works run(() => get(Chris, 'pets')); }); -test("pushing has-many payloads with links, then links again works as expected", function(assert) { +test('pushing has-many payloads with links, then links again works as expected', function(assert) { const User = Model.extend({ - pets: hasMany('pet', { async: true, inverse: 'owner' }) + pets: hasMany('pet', { async: true, inverse: 'owner' }), }); const Pet = Model.extend({ - owner: belongsTo('user', { async: false, inverse: 'pets' }) + owner: belongsTo('user', { async: false, inverse: 'pets' }), }); const Adapter = JSONAPIAdapter.extend({ findHasMany(_, __, link) { @@ -415,20 +435,20 @@ test("pushing has-many payloads with links, then links again works as expected", id: '1', relationships: { owner: { - data: { type: 'user', id: '1' } - } - } + data: { type: 'user', id: '1' }, + }, + }, }, { type: 'pet', id: '2', relationships: { owner: { - data: { type: 'user', id: '1' } - } - } - } - ] + data: { type: 'user', id: '1' }, + }, + }, + }, + ], }); }, findMany() { @@ -436,46 +456,50 @@ test("pushing has-many payloads with links, then links again works as expected", }, findRecord() { assert.ok(false, 'adapter findRecord called instead of using findHasMany with a link'); - } + }, }); env = setupStore({ adapter: Adapter, user: User, - pet: Pet + pet: Pet, }); let { store } = env; // push links, no data - run(() => store.push({ - data: { - type: 'user', - id: '1', - relationships: { - pets: { - links: { - related: './user/1/not-pets' - } - } - } - } - })); + run(() => + store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + links: { + related: './user/1/not-pets', + }, + }, + }, + }, + }) + ); // push data, no links - run(() => store.push({ - data: { - type: 'user', - id: '1', - relationships: { - pets: { - links: { - related: './user/1/pets' - } - } - } - } - })); + run(() => + store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + links: { + related: './user/1/pets', + }, + }, + }, + }, + }) + ); let Chris = run(() => store.peekRecord('user', '1')); @@ -483,12 +507,12 @@ test("pushing has-many payloads with links, then links again works as expected", run(() => get(Chris, 'pets')); }); -test("pushing has-many payloads with links and data works as expected", function(assert) { +test('pushing has-many payloads with links and data works as expected', function(assert) { const User = Model.extend({ - pets: hasMany('pet', { async: true, inverse: 'owner' }) + pets: hasMany('pet', { async: true, inverse: 'owner' }), }); const Pet = Model.extend({ - owner: belongsTo('user', { async: false, inverse: 'pets' }) + owner: belongsTo('user', { async: false, inverse: 'pets' }), }); const Adapter = JSONAPIAdapter.extend({ findHasMany(_, __, link) { @@ -500,20 +524,20 @@ test("pushing has-many payloads with links and data works as expected", function id: '1', relationships: { owner: { - data: { type: 'user', id: '1' } - } - } + data: { type: 'user', id: '1' }, + }, + }, }, { type: 'pet', id: '2', relationships: { owner: { - data: { type: 'user', id: '1' } - } - } - } - ] + data: { type: 'user', id: '1' }, + }, + }, + }, + ], }); }, findMany() { @@ -521,45 +545,45 @@ test("pushing has-many payloads with links and data works as expected", function }, findRecord() { assert.ok(false, 'adapter findRecord called instead of using findHasMany with a link'); - } + }, }); env = setupStore({ adapter: Adapter, user: User, - pet: Pet + pet: Pet, }); let { store } = env; // push data and links - run(() => store.push({ - data: { - type: 'user', - id: '1', - relationships: { - pets: { - data: [ - { type: 'pet', id: '1' } - ], - links: { - related: './user/1/pets' - } - } - } - } - })); + run(() => + store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + data: [{ type: 'pet', id: '1' }], + links: { + related: './user/1/pets', + }, + }, + }, + }, + }) + ); let Chris = run(() => store.peekRecord('user', '1')); run(() => get(Chris, 'pets')); }); -test("pushing has-many payloads with links, then one with links and data works as expected", function(assert) { +test('pushing has-many payloads with links, then one with links and data works as expected', function(assert) { const User = Model.extend({ - pets: hasMany('pet', { async: true, inverse: 'owner' }) + pets: hasMany('pet', { async: true, inverse: 'owner' }), }); const Pet = Model.extend({ - owner: belongsTo('user', { async: false, inverse: 'pets' }) + owner: belongsTo('user', { async: false, inverse: 'pets' }), }); const Adapter = JSONAPIAdapter.extend({ findHasMany(_, __, link) { @@ -571,20 +595,20 @@ test("pushing has-many payloads with links, then one with links and data works a id: '1', relationships: { owner: { - data: { type: 'user', id: '1' } - } - } + data: { type: 'user', id: '1' }, + }, + }, }, { type: 'pet', id: '2', relationships: { owner: { - data: { type: 'user', id: '1' } - } - } - } - ] + data: { type: 'user', id: '1' }, + }, + }, + }, + ], }); }, findMany() { @@ -592,70 +616,68 @@ test("pushing has-many payloads with links, then one with links and data works a }, findRecord() { assert.ok(false, 'adapter findRecord called instead of using findHasMany with a link'); - } + }, }); env = setupStore({ adapter: Adapter, user: User, - pet: Pet + pet: Pet, }); let { store } = env; // push data, no links - run(() => store.push({ - data: { - type: 'user', - id: '1', - relationships: { - pets: { - data: [ - { type: 'pet', id: '1' } - ] - } - } - } - })); + run(() => + store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + data: [{ type: 'pet', id: '1' }], + }, + }, + }, + }) + ); // push links and data - run(() => store.push({ - data: { - type: 'user', - id: '1', - relationships: { - pets: { - data: [ - { type: 'pet', id: '1' }, - { type: 'pet', id: '2' }, - { type: 'pet', id: '3' } - ], - links: { - related: './user/1/pets' - } - } - } - } - })); + run(() => + store.push({ + data: { + type: 'user', + id: '1', + relationships: { + pets: { + data: [{ type: 'pet', id: '1' }, { type: 'pet', id: '2' }, { type: 'pet', id: '3' }], + links: { + related: './user/1/pets', + }, + }, + }, + }, + }) + ); let Chris = run(() => store.peekRecord('user', '1')); run(() => get(Chris, 'pets')); }); -module("integration/relationship/json-api-links | Relationship fetching", { +module('integration/relationship/json-api-links | Relationship fetching', { beforeEach() { const User = Model.extend({ name: attr(), pets: hasMany('pet', { async: true, inverse: 'owner' }), - home: belongsTo('home', { async: true, inverse: 'owner' }) + home: belongsTo('home', { async: true, inverse: 'owner' }), }); const Home = Model.extend({ address: attr(), - owner: belongsTo('user', { async: false, inverse: 'home' }) + owner: belongsTo('user', { async: false, inverse: 'home' }), }); const Pet = Model.extend({ name: attr(), - owner: belongsTo('user', { async: false, inverse: 'pets' }) + owner: belongsTo('user', { async: false, inverse: 'pets' }), }); const Adapter = JSONAPIAdapter.extend(); @@ -663,7 +685,7 @@ module("integration/relationship/json-api-links | Relationship fetching", { adapter: Adapter, user: User, pet: Pet, - home: Home + home: Home, }); }, @@ -671,7 +693,7 @@ module("integration/relationship/json-api-links | Relationship fetching", { resetModelFactoryInjection(); run(env.container, 'destroy'); env = null; - } + }, }); /* @@ -821,8 +843,7 @@ function shouldFetchLinkTests(description, payloads) { }; adapter.findBelongsTo = (_, __, link) => { assert.ok( - !homeRelWasEmpty && - link === payloads.user.data.relationships.home.links.related, + !homeRelWasEmpty && link === payloads.user.data.relationships.home.links.related, 'We fetched the appropriate link' ); return resolve(deepCopy(payloads.home)); @@ -850,21 +871,21 @@ shouldFetchLinkTests('a link (no data)', { type: 'user', id: '1', attributes: { - name: '@runspired' + name: '@runspired', }, relationships: { pets: { links: { - related: './runspired/pets' - } + related: './runspired/pets', + }, }, home: { links: { - related: './runspired/address' - } - } - } - } + related: './runspired/address', + }, + }, + }, + }, }, pets: { data: [ @@ -872,36 +893,36 @@ shouldFetchLinkTests('a link (no data)', { type: 'pet', id: '1', attributes: { - name: 'Shen' + name: 'Shen', }, relationships: { owner: { data: { type: 'user', - id: '1' - } - } - } - } - ] + id: '1', + }, + }, + }, + }, + ], }, home: { data: { type: 'home', id: '1', attributes: { - address: 'Oakland, Ca' + address: 'Oakland, Ca', }, relationships: { owner: { data: { type: 'user', - id: '1' - } - } - } - } - } + id: '1', + }, + }, + }, + }, + }, }); shouldFetchLinkTests('a link and data (not available in the store)', { @@ -910,25 +931,23 @@ shouldFetchLinkTests('a link and data (not available in the store)', { type: 'user', id: '1', attributes: { - name: '@runspired' + name: '@runspired', }, relationships: { pets: { links: { - related: './runspired/pets' + related: './runspired/pets', }, - data: [ - { type: 'pet', id: '1' } - ] + data: [{ type: 'pet', id: '1' }], }, home: { links: { - related: './runspired/address' + related: './runspired/address', }, - data: { type: 'home', id: '1' } - } - } - } + data: { type: 'home', id: '1' }, + }, + }, + }, }, pets: { data: [ @@ -936,42 +955,42 @@ shouldFetchLinkTests('a link and data (not available in the store)', { type: 'pet', id: '1', attributes: { - name: 'Shen' + name: 'Shen', }, relationships: { owner: { data: { type: 'user', - id: '1' + id: '1', }, links: { - related: './user/1' - } - } - } - } - ] + related: './user/1', + }, + }, + }, + }, + ], }, home: { data: { type: 'home', id: '1', attributes: { - address: 'Oakland, Ca' + address: 'Oakland, Ca', }, relationships: { owner: { data: { type: 'user', - id: '1' + id: '1', }, links: { - related: './user/1' - } - } - } - } - } + related: './user/1', + }, + }, + }, + }, + }, }); /* @@ -1087,7 +1106,7 @@ function shouldReloadWithLinkTests(description, payloads) { let user = run(() => store.push(deepCopy(payloads.user))); run(() => store.push(deepCopy(payloads.home))); let home; - run(() => user.get('home').then(h => home = h)); + run(() => user.get('home').then(h => (home = h))); assert.ok(!!home, 'We found our home'); @@ -1102,25 +1121,23 @@ shouldReloadWithLinkTests('a link and data (available in the store)', { type: 'user', id: '1', attributes: { - name: '@runspired' + name: '@runspired', }, relationships: { pets: { links: { - related: './runspired/pets' + related: './runspired/pets', }, - data: [ - { type: 'pet', id: '1' } - ] + data: [{ type: 'pet', id: '1' }], }, home: { links: { - related: './runspired/address' + related: './runspired/address', }, - data: { type: 'home', id: '1' } - } - } - } + data: { type: 'home', id: '1' }, + }, + }, + }, }, pets: { data: [ @@ -1128,167 +1145,173 @@ shouldReloadWithLinkTests('a link and data (available in the store)', { type: 'pet', id: '1', attributes: { - name: 'Shen' + name: 'Shen', }, relationships: { owner: { data: { type: 'user', - id: '1' - } - } - } - } - ] + id: '1', + }, + }, + }, + }, + ], }, home: { data: { type: 'home', id: '1', attributes: { - address: 'Oakland, Ca' + address: 'Oakland, Ca', }, relationships: { owner: { data: { type: 'user', - id: '1' - } - } - } - } - } + id: '1', + }, + }, + }, + }, + }, }); -shouldReloadWithLinkTests('a link and empty data (`data: []` or `data: null`), true inverse loaded', { - user: { - data: { - type: 'user', - id: '1', - attributes: { - name: '@runspired' - }, - relationships: { - pets: { - links: { - related: './runspired/pets' +shouldReloadWithLinkTests( + 'a link and empty data (`data: []` or `data: null`), true inverse loaded', + { + user: { + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired', + }, + relationships: { + pets: { + links: { + related: './runspired/pets', + }, + data: [], + }, + home: { + links: { + related: './runspired/address', + }, + data: null, }, - data: [] }, - home: { - links: { - related: './runspired/address' + }, + }, + pets: { + data: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shen', }, - data: null - } - } - } - }, - pets: { - data: [ - { - type: 'pet', + relationships: { + owner: { + data: { + type: 'user', + id: '1', + }, + links: { + related: './user/1', + }, + }, + }, + }, + ], + }, + home: { + data: { + type: 'home', id: '1', attributes: { - name: 'Shen' + address: 'Oakland, Ca', }, relationships: { owner: { data: { type: 'user', - id: '1' + id: '1', }, links: { - related: './user/1' - } - } - } - } - ] - }, - home: { - data: { - type: 'home', - id: '1', - attributes: { - address: 'Oakland, Ca' - }, - relationships: { - owner: { - data: { - type: 'user', - id: '1' + related: './user/1', + }, }, - links: { - related: './user/1' - } - } - } - } + }, + }, + }, } -}); +); -shouldReloadWithLinkTests('a link and empty data (`data: []` or `data: null`), true inverse unloaded', { - user: { - data: { - type: 'user', - id: '1', - attributes: { - name: '@runspired' - }, - relationships: { - pets: { - links: { - related: './runspired/pets' +shouldReloadWithLinkTests( + 'a link and empty data (`data: []` or `data: null`), true inverse unloaded', + { + user: { + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired', + }, + relationships: { + pets: { + links: { + related: './runspired/pets', + }, + data: [], + }, + home: { + links: { + related: './runspired/address', + }, + data: null, }, - data: [] }, - home: { - links: { - related: './runspired/address' + }, + }, + pets: { + data: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shen', }, - data: null - } - } - } - }, - pets: { - data: [ - { - type: 'pet', + relationships: { + owner: { + data: { + type: 'user', + id: '1', + }, + }, + }, + }, + ], + }, + home: { + data: { + type: 'home', id: '1', attributes: { - name: 'Shen' + address: 'Oakland, Ca', }, relationships: { owner: { data: { type: 'user', - id: '1' - } - } - } - } - ] - }, - home: { - data: { - type: 'home', - id: '1', - attributes: { - address: 'Oakland, Ca' + id: '1', + }, + }, + }, }, - relationships: { - owner: { - data: { - type: 'user', - id: '1' - } - } - } - } + }, } -}); +); /* Ad Hoc Situations when we don't have a link @@ -1307,17 +1330,17 @@ test(`get+reload hasMany with data, no links`, function(assert) { type: 'pet', id: '1', attributes: { - name: 'Shen' + name: 'Shen', }, relationships: { owner: { data: { type: 'user', - id: '1' - } - } - } - } + id: '1', + }, + }, + }, + }, }); }; adapter.findMany = () => { @@ -1328,25 +1351,25 @@ test(`get+reload hasMany with data, no links`, function(assert) { }; // setup user - let user = run(() => store.push({ - data: { - type: 'user', - id: '1', - attributes: { - name: '@runspired' - }, - relationships: { - pets: { - data: [ - { type: 'pet', id: '1' } - ] + let user = run(() => + store.push({ + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired', }, - home: { - data: { type: 'home', id: '1' } - } - } - } - })); + relationships: { + pets: { + data: [{ type: 'pet', id: '1' }], + }, + home: { + data: { type: 'home', id: '1' }, + }, + }, + }, + }) + ); let pets = run(() => user.get('pets')); assert.ok(!!pets, 'We found our pets'); @@ -1365,17 +1388,17 @@ test(`get+unload+get hasMany with data, no links`, function(assert) { type: 'pet', id: '1', attributes: { - name: 'Shen' + name: 'Shen', }, relationships: { owner: { data: { type: 'user', - id: '1' - } - } - } - } + id: '1', + }, + }, + }, + }, }); }; adapter.findMany = () => { @@ -1386,25 +1409,25 @@ test(`get+unload+get hasMany with data, no links`, function(assert) { }; // setup user - let user = run(() => store.push({ - data: { - type: 'user', - id: '1', - attributes: { - name: '@runspired' - }, - relationships: { - pets: { - data: [ - { type: 'pet', id: '1' } - ] + let user = run(() => + store.push({ + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired', }, - home: { - data: { type: 'home', id: '1' } - } - } - } - })); + relationships: { + pets: { + data: [{ type: 'pet', id: '1' }], + }, + home: { + data: { type: 'home', id: '1' }, + }, + }, + }, + }) + ); let pets = run(() => user.get('pets')); assert.ok(!!pets, 'We found our pets'); @@ -1424,17 +1447,17 @@ test(`get+reload belongsTo with data, no links`, function(assert) { type: 'home', id: '1', attributes: { - address: 'Oakland, CA' + address: 'Oakland, CA', }, relationships: { owner: { data: { type: 'user', - id: '1' - } - } - } - } + id: '1', + }, + }, + }, + }, }); }; adapter.findMany = () => { @@ -1444,27 +1467,26 @@ test(`get+reload belongsTo with data, no links`, function(assert) { assert.ok(false, 'We should not call findHasMany'); }; - // setup user - let user = run(() => store.push({ - data: { - type: 'user', - id: '1', - attributes: { - name: '@runspired' - }, - relationships: { - pets: { - data: [ - { type: 'pet', id: '1' } - ] + let user = run(() => + store.push({ + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired', }, - home: { - data: { type: 'home', id: '1' } - } - } - } - })); + relationships: { + pets: { + data: [{ type: 'pet', id: '1' }], + }, + home: { + data: { type: 'home', id: '1' }, + }, + }, + }, + }) + ); let home = run(() => user.get('home')); assert.ok(!!home, 'We found our home'); @@ -1483,17 +1505,17 @@ test(`get+unload+get belongsTo with data, no links`, function(assert) { type: 'home', id: '1', attributes: { - address: 'Oakland, Ca' + address: 'Oakland, Ca', }, relationships: { owner: { data: { type: 'user', - id: '1' - } - } - } - } + id: '1', + }, + }, + }, + }, }); }; adapter.findMany = () => { @@ -1503,27 +1525,26 @@ test(`get+unload+get belongsTo with data, no links`, function(assert) { assert.ok(false, 'We should not call findHasMany'); }; - // setup user - let user = run(() => store.push({ - data: { - type: 'user', - id: '1', - attributes: { - name: '@runspired' - }, - relationships: { - pets: { - data: [ - { type: 'pet', id: '1' } - ] + let user = run(() => + store.push({ + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired', }, - home: { - data: { type: 'home', id: '1' } - } - } - } - })); + relationships: { + pets: { + data: [{ type: 'pet', id: '1' }], + }, + home: { + data: { type: 'home', id: '1' }, + }, + }, + }, + }) + ); let home = run(() => user.get('home')); assert.ok(!!home, 'We found our home'); @@ -1545,17 +1566,17 @@ test(`get+reload hasMany with missing data setup from the other side, no links`, type: 'pet', id: '1', attributes: { - name: 'Shen' + name: 'Shen', }, relationships: { owner: { data: { type: 'user', - id: '1' - } - } - } - } + id: '1', + }, + }, + }, + }, }); }; adapter.findMany = () => { @@ -1566,33 +1587,35 @@ test(`get+reload hasMany with missing data setup from the other side, no links`, }; // setup user and pet - let user = run(() => store.push({ - data: { - type: 'user', - id: '1', - attributes: { - name: '@runspired' - }, - relationships: {} - }, - included: [ - { - type: 'pet', + let user = run(() => + store.push({ + data: { + type: 'user', id: '1', attributes: { - name: 'Shen' + name: '@runspired', }, - relationships: { - owner: { - data: { - type: 'user', - id: '1' - } - } - } - } - ] - })); + relationships: {}, + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shen', + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1', + }, + }, + }, + }, + ], + }) + ); let pets = run(() => user.get('pets')); assert.ok(!!pets, 'We found our pets'); @@ -1610,17 +1633,17 @@ test(`get+unload+get hasMany with missing data setup from the other side, no lin type: 'pet', id: '1', attributes: { - name: 'Shen' + name: 'Shen', }, relationships: { owner: { data: { type: 'user', - id: '1' - } - } - } - } + id: '1', + }, + }, + }, + }, }); }; adapter.findMany = () => { @@ -1631,33 +1654,35 @@ test(`get+unload+get hasMany with missing data setup from the other side, no lin }; // setup user and pet - let user = run(() => store.push({ - data: { - type: 'user', - id: '1', - attributes: { - name: '@runspired' - }, - relationships: {} - }, - included: [ - { - type: 'pet', + let user = run(() => + store.push({ + data: { + type: 'user', id: '1', attributes: { - name: 'Shen' + name: '@runspired', }, - relationships: { - owner: { - data: { - type: 'user', - id: '1' - } - } - } - } - ] - })); + relationships: {}, + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shen', + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1', + }, + }, + }, + }, + ], + }) + ); let pets = run(() => user.get('pets')); assert.ok(!!pets, 'We found our pets'); @@ -1677,17 +1702,17 @@ test(`get+reload belongsTo with missing data setup from the other side, no links type: 'home', id: '1', attributes: { - address: 'Oakland, CA' + address: 'Oakland, CA', }, relationships: { owner: { data: { type: 'user', - id: '1' - } - } - } - } + id: '1', + }, + }, + }, + }, }); }; adapter.findMany = () => { @@ -1698,33 +1723,35 @@ test(`get+reload belongsTo with missing data setup from the other side, no links }; // setup user and home - let user = run(() => store.push({ - data: { - type: 'user', - id: '1', - attributes: { - name: '@runspired' - }, - relationships: {} - }, - included: [ - { - type: 'home', + let user = run(() => + store.push({ + data: { + type: 'user', id: '1', attributes: { - address: 'Oakland, CA' + name: '@runspired', }, - relationships: { - owner: { - data: { - type: 'user', - id: '1' - } - } - } - } - ] - })); + relationships: {}, + }, + included: [ + { + type: 'home', + id: '1', + attributes: { + address: 'Oakland, CA', + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1', + }, + }, + }, + }, + ], + }) + ); let home = run(() => user.get('home')); assert.ok(!!home, 'We found our home'); @@ -1743,17 +1770,17 @@ test(`get+unload+get belongsTo with missing data setup from the other side, no l type: 'home', id: '1', attributes: { - address: 'Oakland, CA' + address: 'Oakland, CA', }, relationships: { owner: { data: { type: 'user', - id: '1' - } - } - } - } + id: '1', + }, + }, + }, + }, }); }; adapter.findMany = () => { @@ -1764,33 +1791,35 @@ test(`get+unload+get belongsTo with missing data setup from the other side, no l }; // setup user and home - let user = run(() => store.push({ - data: { - type: 'user', - id: '1', - attributes: { - name: '@runspired' - }, - relationships: {} - }, - included: [ - { - type: 'home', + let user = run(() => + store.push({ + data: { + type: 'user', id: '1', attributes: { - address: 'Oakland, CA' + name: '@runspired', }, - relationships: { - owner: { - data: { - type: 'user', - id: '1' - } - } - } - } - ] - })); + relationships: {}, + }, + included: [ + { + type: 'home', + id: '1', + attributes: { + address: 'Oakland, CA', + }, + relationships: { + owner: { + data: { + type: 'user', + id: '1', + }, + }, + }, + }, + ], + }) + ); let home = run(() => user.get('home')); assert.ok(!!home, 'We found our home'); @@ -1816,23 +1845,25 @@ test(`get+reload hasMany with empty data, no links`, function(assert) { }; // setup user - let user = run(() => store.push({ - data: { - type: 'user', - id: '1', - attributes: { - name: '@runspired' - }, - relationships: { - pets: { - data: [] + let user = run(() => + store.push({ + data: { + type: 'user', + id: '1', + attributes: { + name: '@runspired', }, - home: { - data: null - } - } - } - })); + relationships: { + pets: { + data: [], + }, + home: { + data: null, + }, + }, + }, + }) + ); let pets = run(() => user.get('pets')); assert.ok(!!pets, 'We found our pets'); @@ -1852,34 +1883,34 @@ test('We should not fetch a hasMany relationship with links that we know is empt type: 'user', id: '1', attributes: { - name: '@runspired' + name: '@runspired', }, relationships: { pets: { links: { - related: './runspired/pets' + related: './runspired/pets', }, - data: [] // we are explicitly told this is empty - } - } - } + data: [], // we are explicitly told this is empty + }, + }, + }, }; let user2Payload = { data: { type: 'user', id: '2', attributes: { - name: '@hjdivad' + name: '@hjdivad', }, relationships: { pets: { links: { - related: './hjdivad/pets' - } + related: './hjdivad/pets', + }, // we have no data, so we do not know that this is empty - } - } - } + }, + }, + }, }; let requestedUser = null; let failureDescription = ''; @@ -1902,7 +1933,7 @@ test('We should not fetch a hasMany relationship with links that we know is empt } return resolve({ - data: [] + data: [], }); }; @@ -1926,6 +1957,7 @@ test('We should not fetch a hasMany relationship with links that we know is empt // should not fire a request requestedUser = null; - failureDescription = 'We fetched the link for a previously fetched and found to be empty relationship'; + failureDescription = + 'We fetched the link for a previously fetched and found to be empty relationship'; run(() => user2.get('pets')); }); diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index 5a614d08332..e0f56037619 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -19,17 +19,17 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships', User = DS.Model.extend({ name: attr('string'), topics: hasMany('topic', { async: true }), - accounts: hasMany('account', { async: false }) + accounts: hasMany('account', { async: false }), }); Account = DS.Model.extend({ state: attr(), - users: hasMany('user', { async: false }) + users: hasMany('user', { async: false }), }); Topic = DS.Model.extend({ title: attr('string'), - users: hasMany('user', { async: true }) + users: hasMany('user', { async: true }), }); env = setupStore({ @@ -37,8 +37,8 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships', topic: Topic, account: Account, adapter: DS.Adapter.extend({ - deleteRecord: () => resolve() - }) + deleteRecord: () => resolve(), + }), }); store = env.store; @@ -46,34 +46,37 @@ module('integration/relationships/many_to_many_test - ManyToMany relationships', afterEach() { run(() => env.container.destroy()); - } + }, }); /* Server loading tests */ -test("Loading from one hasMany side reflects on the other hasMany side - async", function(assert) { +test('Loading from one hasMany side reflects on the other hasMany side - async', function(assert) { run(() => { store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { topics: { - data: [{ - id: '2', - type: 'topic' - }, { - id: '3', - type: 'topic' - }] - } - } - } + data: [ + { + id: '2', + type: 'topic', + }, + { + id: '3', + type: 'topic', + }, + ], + }, + }, + }, }); }); @@ -83,9 +86,9 @@ test("Loading from one hasMany side reflects on the other hasMany side - async", id: '2', type: 'topic', attributes: { - title: 'EmberFest was great' - } - } + title: 'EmberFest was great', + }, + }, }); }); @@ -96,7 +99,7 @@ test("Loading from one hasMany side reflects on the other hasMany side - async", }); }); -test("Relationship is available from one hasMany side even if only loaded from the other hasMany side - sync", function(assert) { +test('Relationship is available from one hasMany side even if only loaded from the other hasMany side - sync', function(assert) { var account; run(() => { account = store.push({ @@ -104,26 +107,28 @@ test("Relationship is available from one hasMany side even if only loaded from t id: '2', type: 'account', attributes: { - state: 'lonely' - } - } + state: 'lonely', + }, + }, }); store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '2', - type: 'account' - }] - } - } - } + data: [ + { + id: '2', + type: 'account', + }, + ], + }, + }, + }, }); }); @@ -132,7 +137,7 @@ test("Relationship is available from one hasMany side even if only loaded from t }); }); -test("Fetching a hasMany where a record was removed reflects on the other hasMany side - async", function(assert) { +test('Fetching a hasMany where a record was removed reflects on the other hasMany side - async', function(assert) { let user, topic; run(() => { @@ -141,30 +146,28 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { topics: { - data: [ - { id: '2', type: 'topic' } - ] - } - } - } + data: [{ id: '2', type: 'topic' }], + }, + }, + }, }); topic = store.push({ data: { id: '2', type: 'topic', attributes: { - title: 'EmberFest was great' + title: 'EmberFest was great', }, relationships: { users: { - data: [] - } - } - } + data: [], + }, + }, + }, }); }); @@ -180,7 +183,7 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan }); }); -test("Fetching a hasMany where a record was removed reflects on the other hasMany side - sync", function(assert) { +test('Fetching a hasMany where a record was removed reflects on the other hasMany side - sync', function(assert) { let account, user; run(() => { account = store.push({ @@ -188,40 +191,42 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan id: '2', type: 'account', attributes: { - state: 'lonely' - } - } + state: 'lonely', + }, + }, }); user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '2', - type: 'account' - }] - } - } - } + data: [ + { + id: '2', + type: 'account', + }, + ], + }, + }, + }, }); account = store.push({ data: { id: '2', type: 'account', attributes: { - state: 'lonely' + state: 'lonely', }, relationships: { users: { - data: [] - } - } - } + data: [], + }, + }, + }, }); }); @@ -235,7 +240,7 @@ test("Fetching a hasMany where a record was removed reflects on the other hasMan Local edits */ -test("Pushing to a hasMany reflects on the other hasMany side - async", function(assert) { +test('Pushing to a hasMany reflects on the other hasMany side - async', function(assert) { assert.expect(1); let user, topic; @@ -245,23 +250,23 @@ test("Pushing to a hasMany reflects on the other hasMany side - async", function id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { topics: { - data: [] - } - } - } + data: [], + }, + }, + }, }); topic = store.push({ data: { id: '2', type: 'topic', attributes: { - title: 'EmberFest was great' - } - } + title: 'EmberFest was great', + }, + }, }); }); @@ -275,7 +280,7 @@ test("Pushing to a hasMany reflects on the other hasMany side - async", function }); }); -test("Pushing to a hasMany reflects on the other hasMany side - sync", function(assert) { +test('Pushing to a hasMany reflects on the other hasMany side - sync', function(assert) { let account, stanley; run(() => { account = store.push({ @@ -283,18 +288,18 @@ test("Pushing to a hasMany reflects on the other hasMany side - sync", function( id: '2', type: 'account', attributes: { - state: 'lonely' - } - } + state: 'lonely', + }, + }, }); stanley = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); stanley.get('accounts').pushObject(account); }); @@ -304,7 +309,7 @@ test("Pushing to a hasMany reflects on the other hasMany side - sync", function( }); }); -test("Removing a record from a hasMany reflects on the other hasMany side - async", function(assert) { +test('Removing a record from a hasMany reflects on the other hasMany side - async', function(assert) { let user, topic; run(() => { user = store.push({ @@ -312,26 +317,28 @@ test("Removing a record from a hasMany reflects on the other hasMany side - asyn id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { topics: { - data: [{ - id: '2', - type: 'topic' - }] - } - } - } + data: [ + { + id: '2', + type: 'topic', + }, + ], + }, + }, + }, }); topic = store.push({ data: { id: '2', type: 'topic', attributes: { - title: 'EmberFest was great' - } - } + title: 'EmberFest was great', + }, + }, }); }); @@ -347,7 +354,7 @@ test("Removing a record from a hasMany reflects on the other hasMany side - asyn }); }); -test("Removing a record from a hasMany reflects on the other hasMany side - sync", function(assert) { +test('Removing a record from a hasMany reflects on the other hasMany side - sync', function(assert) { let account, user; run(() => { account = store.push({ @@ -355,26 +362,28 @@ test("Removing a record from a hasMany reflects on the other hasMany side - sync id: '2', type: 'account', attributes: { - state: 'lonely' - } - } + state: 'lonely', + }, + }, }); user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '2', - type: 'account' - }] - } - } - } + data: [ + { + id: '2', + type: 'account', + }, + ], + }, + }, + }, }); }); @@ -390,7 +399,7 @@ test("Removing a record from a hasMany reflects on the other hasMany side - sync Rollback Attributes tests */ -test("Rollbacking attributes for a deleted record that has a ManyToMany relationship works correctly - async", function(assert) { +test('Rollbacking attributes for a deleted record that has a ManyToMany relationship works correctly - async', function(assert) { let user, topic; run(() => { user = store.push({ @@ -398,26 +407,28 @@ test("Rollbacking attributes for a deleted record that has a ManyToMany relation id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { topics: { - data: [{ - id: '2', - type: 'topic' - }] - } - } - } + data: [ + { + id: '2', + type: 'topic', + }, + ], + }, + }, + }, }); topic = store.push({ data: { id: '2', type: 'topic', attributes: { - title: 'EmberFest was great' - } - } + title: 'EmberFest was great', + }, + }, }); }); @@ -435,14 +446,11 @@ test("Rollbacking attributes for a deleted record that has a ManyToMany relation assert.equal(fetchedTopics.get('length'), 1, 'Topic got rollbacked into the user'); }); - return EmberPromise.all([ - users, - topics - ]); + return EmberPromise.all([users, topics]); }); }); -test("Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function(assert) { +test('Deleting a record that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync', function(assert) { let account, user; run(() => { account = store.push({ @@ -450,26 +458,28 @@ test("Deleting a record that has a hasMany relationship removes it from the othe id: '2', type: 'account', attributes: { - state: 'lonely' - } - } + state: 'lonely', + }, + }, }); user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '2', - type: 'account' - }] - } - } - } + data: [ + { + id: '2', + type: 'account', + }, + ], + }, + }, + }, }); }); @@ -481,7 +491,7 @@ test("Deleting a record that has a hasMany relationship removes it from the othe }); }); -test("Rollbacking attributes for a created record that has a ManyToMany relationship works correctly - async", function(assert) { +test('Rollbacking attributes for a created record that has a ManyToMany relationship works correctly - async', function(assert) { let user, topic; run(() => { user = store.push({ @@ -489,9 +499,9 @@ test("Rollbacking attributes for a created record that has a ManyToMany relation id: '1', type: 'user', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); topic = store.createRecord('topic'); @@ -512,15 +522,12 @@ test("Rollbacking attributes for a created record that has a ManyToMany relation assert.equal(fetchedTopics.objectAt(0), null, "Topic can't be fetched"); }); - return EmberPromise.all([ - users, - topics - ]); + return EmberPromise.all([users, topics]); }); }); }); -test("Deleting an unpersisted record via rollbackAttributes that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync", function(assert) { +test('Deleting an unpersisted record via rollbackAttributes that has a hasMany relationship removes it from the otherMany array but does not remove the other record from itself - sync', function(assert) { let account, user; run(() => { account = store.push({ @@ -528,9 +535,9 @@ test("Deleting an unpersisted record via rollbackAttributes that has a hasMany r id: '2', type: 'account', attributes: { - state: 'lonely' - } - } + state: 'lonely', + }, + }, }); user = store.createRecord('user'); @@ -545,7 +552,7 @@ test("Deleting an unpersisted record via rollbackAttributes that has a hasMany r assert.equal(user.get('accounts.length'), 0, 'Accounts got rolledback correctly'); }); -test("Re-loading a removed record should re add it to the relationship when the removed record is the last one in the relationship", function(assert) { +test('Re-loading a removed record should re add it to the relationship when the removed record is the last one in the relationship', function(assert) { let account, ada, byron; run(() => { @@ -554,43 +561,47 @@ test("Re-loading a removed record should re add it to the relationship when the id: '2', type: 'account', attributes: { - state: 'account 1' - } - } + state: 'account 1', + }, + }, }); ada = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Ada Lovelace' + name: 'Ada Lovelace', }, relationships: { accounts: { - data: [{ - id: '2', - type: 'account' - }] - } - } - } + data: [ + { + id: '2', + type: 'account', + }, + ], + }, + }, + }, }); byron = store.push({ data: { id: '2', type: 'user', attributes: { - name: 'Lord Byron' + name: 'Lord Byron', }, relationships: { accounts: { - data: [{ - id: '2', - type: 'account' - }] - } - } - } + data: [ + { + id: '2', + type: 'account', + }, + ], + }, + }, + }, }); account.get('users').removeObject(byron); account = store.push({ @@ -598,20 +609,23 @@ test("Re-loading a removed record should re add it to the relationship when the id: '2', type: 'account', attributes: { - state: 'account 1' + state: 'account 1', }, relationships: { users: { - data: [{ - id: '1', - type: 'user' - }, { - id: '2', - type: 'user' - }] - } - } - } + data: [ + { + id: '1', + type: 'user', + }, + { + id: '2', + type: 'user', + }, + ], + }, + }, + }, }); }); diff --git a/tests/integration/relationships/nested-relationship-test.js b/tests/integration/relationships/nested-relationship-test.js index f6eceffee47..6957fe16459 100644 --- a/tests/integration/relationships/nested-relationship-test.js +++ b/tests/integration/relationships/nested-relationship-test.js @@ -14,25 +14,25 @@ module('integration/relationships/nested_relationships_test - Nested relationshi beforeEach() { Elder = DS.Model.extend({ name: attr('string'), - middleAgers: hasMany('middle-ager') + middleAgers: hasMany('middle-ager'), }); MiddleAger = DS.Model.extend({ name: attr('string'), elder: belongsTo('elder'), - kids: hasMany('kid') + kids: hasMany('kid'), }); Kid = DS.Model.extend({ name: attr('string'), - middleAger: belongsTo('middle-ager') + middleAger: belongsTo('middle-ager'), }); env = setupStore({ elder: Elder, 'middle-ager': MiddleAger, kid: Kid, - adapter: DS.JSONAPIAdapter + adapter: DS.JSONAPIAdapter, }); store = env.store; @@ -40,7 +40,7 @@ module('integration/relationships/nested_relationships_test - Nested relationshi afterEach() { run(env.container, 'destroy'); - } + }, }); /* @@ -48,86 +48,88 @@ module('integration/relationships/nested_relationships_test - Nested relationshi */ test('Sideloaded nested relationships load correctly', function(assert) { - env.adapter.shouldBackgroundReloadRecord = () => { return false; }; + env.adapter.shouldBackgroundReloadRecord = () => { + return false; + }; run(() => { store.push({ data: { id: '1', type: 'kid', links: { - self: '/kids/1' + self: '/kids/1', }, attributes: { - name: 'Kid 1' + name: 'Kid 1', }, relationships: { middleAger: { links: { self: '/kids/1/relationships/middle-ager', - related: '/kids/1/middle-ager' + related: '/kids/1/middle-ager', }, - data:{ + data: { type: 'middle-ager', - id: '1' - } - } - } + id: '1', + }, + }, + }, }, included: [ { id: '1', type: 'middle-ager', links: { - self: '/middle-ager/1' + self: '/middle-ager/1', }, attributes: { - name: 'Middle Ager 1' + name: 'Middle Ager 1', }, relationships: { elder: { links: { self: '/middle-agers/1/relationships/elder', - related: '/middle-agers/1/elder' + related: '/middle-agers/1/elder', }, data: { type: 'elder', - id: '1' - } + id: '1', + }, }, kids: { links: { self: '/middle-agers/1/relationships/kids', - related: '/middle-agers/1/kids' + related: '/middle-agers/1/kids', }, data: [ { type: 'kid', - id: '1' - } - ] - } - } + id: '1', + }, + ], + }, + }, }, { id: '1', type: 'elder', links: { - self: '/elders/1' + self: '/elders/1', }, attributes: { - name: 'Elder 1' + name: 'Elder 1', }, relationships: { middleAger: { links: { self: '/elders/1/relationships/middle-agers', - related: '/elders/1/middle-agers' - } - } - } - } - ] + related: '/elders/1/middle-agers', + }, + }, + }, + }, + ], }); }); @@ -149,4 +151,3 @@ test('Sideloaded nested relationships load correctly', function(assert) { }); }); }); - diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index 2f095d0cb4a..fb32bb94ac8 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -18,17 +18,17 @@ module('integration/relationships/one_to_many_test - OneToMany relationships', { User = DS.Model.extend({ name: attr('string'), messages: hasMany('message', { async: true }), - accounts: hasMany('account', { async: false }) + accounts: hasMany('account', { async: false }), }); Account = DS.Model.extend({ state: attr(), - user: belongsTo('user', { async: false }) + user: belongsTo('user', { async: false }), }); Message = DS.Model.extend({ title: attr('string'), - user: belongsTo('user', { async: true }) + user: belongsTo('user', { async: true }), }); env = setupStore({ @@ -36,8 +36,8 @@ module('integration/relationships/one_to_many_test - OneToMany relationships', { message: Message, account: Account, adapter: DS.Adapter.extend({ - deleteRecord: () => resolve() - }) + deleteRecord: () => resolve(), + }), }); store = env.store; @@ -45,41 +45,43 @@ module('integration/relationships/one_to_many_test - OneToMany relationships', { afterEach() { run(env.container, 'destroy'); - } + }, }); /* Server loading tests */ -test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - async", function(assert) { +test('Relationship is available from the belongsTo side even if only loaded from the hasMany side - async', function(assert) { var user, message; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { messages: { - data: [{ - id: '2', - type: 'message' - }] - } - } - } + data: [ + { + id: '2', + type: 'message', + }, + ], + }, + }, + }, }); message = store.push({ data: { id: '2', type: 'message', attributes: { - title: 'EmberFest was great' - } - } + title: 'EmberFest was great', + }, + }, }); }); run(function() { @@ -89,164 +91,179 @@ test("Relationship is available from the belongsTo side even if only loaded from }); }); -test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - sync", function(assert) { +test('Relationship is available from the belongsTo side even if only loaded from the hasMany side - sync', function(assert) { var account, user; - run(function () { + run(function() { account = store.push({ data: { id: '2', type: 'account', attributes: { - state: 'lonely' - } - } + state: 'lonely', + }, + }, }); user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '2', - type: 'account' - }] - } - } - } + data: [ + { + id: '2', + type: 'account', + }, + ], + }, + }, + }, }); }); assert.equal(account.get('user'), user, 'User relationship was set up correctly'); }); -test("Relationship is available from the hasMany side even if only loaded from the belongsTo side - async", function(assert) { +test('Relationship is available from the hasMany side even if only loaded from the belongsTo side - async', function(assert) { var user, message; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); message = store.push({ data: { id: '2', type: 'message', attributes: { - title: 'EmberFest was great' + title: 'EmberFest was great', }, relationships: { user: { data: { id: '1', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); }); run(function() { user.get('messages').then(function(fetchedMessages) { - assert.equal(fetchedMessages.objectAt(0), message, 'Messages relationship was set up correctly'); + assert.equal( + fetchedMessages.objectAt(0), + message, + 'Messages relationship was set up correctly' + ); }); }); }); -test("Relationship is available from the hasMany side even if only loaded from the belongsTo side - sync", function(assert) { +test('Relationship is available from the hasMany side even if only loaded from the belongsTo side - sync', function(assert) { var user, account; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); account = store.push({ data: { id: '2', type: 'account', attributes: { - state: 'lonely' + state: 'lonely', }, relationships: { user: { data: { id: '1', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); }); run(function() { - assert.equal(user.get('accounts').objectAt(0), account, 'Accounts relationship was set up correctly'); + assert.equal( + user.get('accounts').objectAt(0), + account, + 'Accounts relationship was set up correctly' + ); }); }); -test("Fetching a belongsTo that is set to null removes the record from a relationship - async", function(assert) { +test('Fetching a belongsTo that is set to null removes the record from a relationship - async', function(assert) { var user; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { messages: { - data: [{ - id: '1', - type: 'message' - }, { - id: '2', - type: 'message' - }] - } - } - } + data: [ + { + id: '1', + type: 'message', + }, + { + id: '2', + type: 'message', + }, + ], + }, + }, + }, }); }); - run(function () { + run(function() { store.push({ - data: [{ - id: '1', - type: 'message', - attributes: { - title: 'EmberFest was great' + data: [ + { + id: '1', + type: 'message', + attributes: { + title: 'EmberFest was great', + }, + relationships: { + user: { + data: { + id: '1', + type: 'user', + }, + }, + }, }, - relationships: { - user: { - data: { - id: '1', - type: 'user' - } - } - } - }, - { - id: '2', - type: 'message', - attributes: { - title: 'EmberConf will be better' + { + id: '2', + type: 'message', + attributes: { + title: 'EmberConf will be better', + }, + relationships: { + user: { + data: null, + }, + }, }, - relationships: { - user: { - data: null - } - } - }] + ], }); }); run(function() { @@ -256,17 +273,17 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio }); }); -test("Fetching a belongsTo that is set to null removes the record from a relationship - sync", function(assert) { +test('Fetching a belongsTo that is set to null removes the record from a relationship - sync', function(assert) { var user; - run(function () { + run(function() { store.push({ data: { id: '2', type: 'account', attributes: { - state: 'lonely' - } - } + state: 'lonely', + }, + }, }); user = store.push({ @@ -274,17 +291,19 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '2', - type: 'account' - }] - } - } - } + data: [ + { + id: '2', + type: 'account', + }, + ], + }, + }, + }, }); store.push({ @@ -292,14 +311,14 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio id: '2', type: 'account', attributes: { - state: 'lonely' + state: 'lonely', }, relationships: { user: { - data: null - } - } - } + data: null, + }, + }, + }, }); }); @@ -308,53 +327,59 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio }); }); -test("Fetching a belongsTo that is not defined does not remove the record from a relationship - async", function(assert) { +test('Fetching a belongsTo that is not defined does not remove the record from a relationship - async', function(assert) { var user; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { messages: { - data: [{ - id: '1', - type: 'message' - }, { - id: '2', - type: 'message' - }] - } - } - } + data: [ + { + id: '1', + type: 'message', + }, + { + id: '2', + type: 'message', + }, + ], + }, + }, + }, }); }); - run(function () { + run(function() { store.push({ - data: [{ - id: '1', - type: 'message', - attributes: { - title: 'EmberFest was great' + data: [ + { + id: '1', + type: 'message', + attributes: { + title: 'EmberFest was great', + }, + relationships: { + user: { + data: { + id: '1', + type: 'user', + }, + }, + }, }, - relationships: { - user: { - data: { - id: '1', - type: 'user' - } - } - } - }, { - id: '2', - type: 'message', - attributes: { - title: 'EmberConf will be better' - } - }] + { + id: '2', + type: 'message', + attributes: { + title: 'EmberConf will be better', + }, + }, + ], }); }); run(function() { @@ -364,43 +389,45 @@ test("Fetching a belongsTo that is not defined does not remove the record from a }); }); -test("Fetching a belongsTo that is not defined does not remove the record from a relationship - sync", function(assert) { +test('Fetching a belongsTo that is not defined does not remove the record from a relationship - sync', function(assert) { var account, user; - run(function () { + run(function() { account = store.push({ data: { id: '2', type: 'account', attributes: { - state: 'lonely' - } - } + state: 'lonely', + }, + }, }); user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '2', - type: 'account' - }] - } - } - } + data: [ + { + id: '2', + type: 'account', + }, + ], + }, + }, + }, }); account = store.push({ data: { id: '2', type: 'account', attributes: { - state: 'lonely' - } - } + state: 'lonely', + }, + }, }); }); @@ -411,68 +438,72 @@ test("Fetching a belongsTo that is not defined does not remove the record from a test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsTo to null - async", function(assert) { var user, message, message2; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { messages: { - data: [{ - id: '1', - type: 'message' - }] - } - } - } + data: [ + { + id: '1', + type: 'message', + }, + ], + }, + }, + }, }); message = store.push({ data: { id: '1', type: 'message', attributes: { - title: 'EmberFest was great' + title: 'EmberFest was great', }, relationships: { user: { data: { id: '1', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); message2 = store.push({ data: { id: '2', type: 'message', attributes: { - title: 'EmberConf is gonna be better' - } - } + title: 'EmberConf is gonna be better', + }, + }, }); }); - run(function () { + run(function() { store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { messages: { - data: [{ - id: '2', - type: 'message' - }] - } - } - } + data: [ + { + id: '2', + type: 'message', + }, + ], + }, + }, + }, }); }); run(function() { @@ -491,23 +522,21 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT let account2; let user; - run(function () { + run(function() { // tell the store user:1 has account:1 user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [ - { id: '1', type: 'account' } - ] - } - } - } + data: [{ id: '1', type: 'account' }], + }, + }, + }, }); // tell the store account:1 has user:1 @@ -516,14 +545,14 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT id: '1', type: 'account', attributes: { - state: 'great' + state: 'great', }, relationships: { user: { - data: { id: '1', type: 'user' } - } - } - } + data: { id: '1', type: 'user' }, + }, + }, + }, }); // tell the store account:2 has no user @@ -532,9 +561,9 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT id: '2', type: 'account', attributes: { - state: 'awesome' - } - } + state: 'awesome', + }, + }, }); // tell the store user:1 has account:2 and not account:1 @@ -543,16 +572,14 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [ - { id: '2', type: 'account' } - ] - } - } - } + data: [{ id: '2', type: 'account' }], + }, + }, + }, }); }); @@ -562,51 +589,53 @@ test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsT }); }); -test("Fetching the hasMany side where the hasMany is undefined does not change the belongsTo side - async", function(assert) { +test('Fetching the hasMany side where the hasMany is undefined does not change the belongsTo side - async', function(assert) { var message, user; - run(function () { + run(function() { store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { messages: { - data: [{ - id: '1', - type: 'message' - }] - } - } - } + data: [ + { + id: '1', + type: 'message', + }, + ], + }, + }, + }, }); message = store.push({ data: { id: '1', type: 'message', attributes: { - title: 'EmberFest was great' + title: 'EmberFest was great', }, relationships: { user: { data: { id: '1', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); }); @@ -617,60 +646,62 @@ test("Fetching the hasMany side where the hasMany is undefined does not change t }); }); -test("Fetching the hasMany side where the hasMany is undefined does not change the belongsTo side - sync", function(assert) { +test('Fetching the hasMany side where the hasMany is undefined does not change the belongsTo side - sync', function(assert) { var account, user; - run(function () { + run(function() { store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '1', - type: 'account' - }] - } - } - } + data: [ + { + id: '1', + type: 'account', + }, + ], + }, + }, + }, }); account = store.push({ data: { id: '1', type: 'account', attributes: { - state: 'great' + state: 'great', }, relationships: { user: { data: { id: '1', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); store.push({ data: { id: '2', type: 'account', attributes: { - state: 'awesome' - } - } + state: 'awesome', + }, + }, }); user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); }); @@ -683,43 +714,45 @@ test("Fetching the hasMany side where the hasMany is undefined does not change t Local edits */ -test("Pushing to the hasMany reflects the change on the belongsTo side - async", function(assert) { +test('Pushing to the hasMany reflects the change on the belongsTo side - async', function(assert) { var user, message2; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { messages: { - data: [{ - id: '1', - type: 'message' - }] - } - } - } + data: [ + { + id: '1', + type: 'message', + }, + ], + }, + }, + }, }); store.push({ data: { id: '1', type: 'message', attributes: { - title: 'EmberFest was great' - } - } + title: 'EmberFest was great', + }, + }, }); message2 = store.push({ data: { id: '2', type: 'message', attributes: { - title: 'EmberFest was great' - } - } + title: 'EmberFest was great', + }, + }, }); }); @@ -727,48 +760,50 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - async", user.get('messages').then(function(fetchedMessages) { fetchedMessages.pushObject(message2); message2.get('user').then(function(fetchedUser) { - assert.equal(fetchedUser, user, "user got set correctly"); + assert.equal(fetchedUser, user, 'user got set correctly'); }); }); }); }); -test("Pushing to the hasMany reflects the change on the belongsTo side - sync", function(assert) { +test('Pushing to the hasMany reflects the change on the belongsTo side - sync', function(assert) { var user, account2; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '1', - type: 'account' - }] - } - } - } + data: [ + { + id: '1', + type: 'account', + }, + ], + }, + }, + }, }); store.push({ data: { id: '1', type: 'account', attributes: { - state: 'great' + state: 'great', }, relationships: { user: { data: { id: '1', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); account2 = store.push({ @@ -776,9 +811,9 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - sync", id: '2', type: 'account', attributes: { - state: 'awesome' - } - } + state: 'awesome', + }, + }, }); user.get('accounts').pushObject(account2); }); @@ -786,34 +821,36 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - sync", assert.equal(account2.get('user'), user, 'user got set correctly'); }); -test("Removing from the hasMany side reflects the change on the belongsTo side - async", function(assert) { +test('Removing from the hasMany side reflects the change on the belongsTo side - async', function(assert) { var user, message; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { messages: { - data: [{ - id: '1', - type: 'message' - }] - } - } - } + data: [ + { + id: '1', + type: 'message', + }, + ], + }, + }, + }, }); message = store.push({ data: { id: '1', type: 'message', attributes: { - title: 'EmberFest was great' - } - } + title: 'EmberFest was great', + }, + }, }); }); @@ -821,48 +858,50 @@ test("Removing from the hasMany side reflects the change on the belongsTo side - user.get('messages').then(function(fetchedMessages) { fetchedMessages.removeObject(message); message.get('user').then(function(fetchedUser) { - assert.equal(fetchedUser, null, "user got removed correctly"); + assert.equal(fetchedUser, null, 'user got removed correctly'); }); }); }); }); -test("Removing from the hasMany side reflects the change on the belongsTo side - sync", function(assert) { +test('Removing from the hasMany side reflects the change on the belongsTo side - sync', function(assert) { var user, account; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attirbutes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '1', - type: 'account' - }] - } - } - } + data: [ + { + id: '1', + type: 'account', + }, + ], + }, + }, + }, }); account = store.push({ data: { id: '1', type: 'account', attirbutes: { - state: 'great' + state: 'great', }, relationships: { user: { data: { id: '1', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); }); run(function() { @@ -872,44 +911,46 @@ test("Removing from the hasMany side reflects the change on the belongsTo side - assert.equal(account.get('user'), null, 'user got removed correctly'); }); -test("Pushing to the hasMany side keeps the oneToMany invariant on the belongsTo side - async", function(assert) { +test('Pushing to the hasMany side keeps the oneToMany invariant on the belongsTo side - async', function(assert) { assert.expect(2); var user, user2, message; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { messages: { - data: [{ - id: '1', - type: 'message' - }] - } - } - } + data: [ + { + id: '1', + type: 'message', + }, + ], + }, + }, + }, }); user2 = store.push({ data: { id: '2', type: 'user', attributes: { - name: 'Tomhuda' - } - } + name: 'Tomhuda', + }, + }, }); message = store.push({ data: { id: '1', type: 'message', attributes: { - title: 'EmberFest was great' - } - } + title: 'EmberFest was great', + }, + }, }); }); @@ -918,53 +959,59 @@ test("Pushing to the hasMany side keeps the oneToMany invariant on the belongsTo fetchedMessages.pushObject(message); message.get('user').then(function(fetchedUser) { - assert.equal(fetchedUser, user2, "user got set correctly"); + assert.equal(fetchedUser, user2, 'user got set correctly'); }); user.get('messages').then(function(newFetchedMessages) { - assert.equal(get(newFetchedMessages, 'length'), 0, 'message got removed from the old messages hasMany'); + assert.equal( + get(newFetchedMessages, 'length'), + 0, + 'message got removed from the old messages hasMany' + ); }); }); }); }); -test("Pushing to the hasMany side keeps the oneToMany invariant - sync", function(assert) { +test('Pushing to the hasMany side keeps the oneToMany invariant - sync', function(assert) { var user, user2, account; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '1', - type: 'account' - }] - } - } - } + data: [ + { + id: '1', + type: 'account', + }, + ], + }, + }, + }, }); user2 = store.push({ data: { id: '2', type: 'user', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); account = store.push({ data: { id: '1', type: 'account', attributes: { - state: 'great' - } - } + state: 'great', + }, + }, }); user2.get('accounts').pushObject(account); }); @@ -973,113 +1020,125 @@ test("Pushing to the hasMany side keeps the oneToMany invariant - sync", functio assert.equal(user2.get('accounts.length'), 1, 'the account got pushed correctly'); }); -test("Setting the belongsTo side keeps the oneToMany invariant on the hasMany- async", function(assert) { +test('Setting the belongsTo side keeps the oneToMany invariant on the hasMany- async', function(assert) { assert.expect(2); var user, user2, message; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { messages: { - data: [{ - id: '1', - type: 'message' - }] - } - } - } + data: [ + { + id: '1', + type: 'message', + }, + ], + }, + }, + }, }); user2 = store.push({ data: { id: '2', type: 'user', attributes: { - name: 'Tomhuda' - } - } + name: 'Tomhuda', + }, + }, }); message = store.push({ data: { id: '1', type: 'message', attributes: { - title: 'EmberFest was great' + title: 'EmberFest was great', }, relationships: { user: { data: { id: '1', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); message.set('user', user2); }); run(function() { user.get('messages').then(function(fetchedMessages) { - assert.equal(get(fetchedMessages, 'length'), 0, 'message got removed from the first user correctly'); + assert.equal( + get(fetchedMessages, 'length'), + 0, + 'message got removed from the first user correctly' + ); }); }); run(function() { user2.get('messages').then(function(fetchedMessages) { - assert.equal(get(fetchedMessages, 'length'), 1, 'message got added to the second user correctly'); + assert.equal( + get(fetchedMessages, 'length'), + 1, + 'message got added to the second user correctly' + ); }); }); }); -test("Setting the belongsTo side keeps the oneToMany invariant on the hasMany- sync", function(assert) { +test('Setting the belongsTo side keeps the oneToMany invariant on the hasMany- sync', function(assert) { var user, user2, account; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '1', - type: 'account' - }] - } - } - } + data: [ + { + id: '1', + type: 'account', + }, + ], + }, + }, + }, }); user2 = store.push({ data: { id: '2', type: 'user', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); account = store.push({ data: { id: '1', type: 'account', attributes: { - state: 'great' + state: 'great', }, relationships: { user: { data: { id: '1', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); account.set('user', user2); }); @@ -1088,50 +1147,55 @@ test("Setting the belongsTo side keeps the oneToMany invariant on the hasMany- s assert.equal(user2.get('accounts.length'), 1, 'the account got pushed correctly'); }); - -test("Setting the belongsTo side to null removes the record from the hasMany side - async", function(assert) { +test('Setting the belongsTo side to null removes the record from the hasMany side - async', function(assert) { assert.expect(2); var user, message; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { messages: { - data: [{ - id: '1', - type: 'message' - }] - } - } - } + data: [ + { + id: '1', + type: 'message', + }, + ], + }, + }, + }, }); message = store.push({ data: { id: '1', type: 'message', attributes: { - title: 'EmberFest was great' + title: 'EmberFest was great', }, relationships: { user: { data: { id: '1', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); message.set('user', null); }); run(function() { user.get('messages').then(function(fetchedMessages) { - assert.equal(get(fetchedMessages, 'length'), 0, 'message got removed from the user correctly'); + assert.equal( + get(fetchedMessages, 'length'), + 0, + 'message got removed from the user correctly' + ); }); }); @@ -1142,42 +1206,44 @@ test("Setting the belongsTo side to null removes the record from the hasMany sid }); }); -test("Setting the belongsTo side to null removes the record from the hasMany side - sync", function(assert) { +test('Setting the belongsTo side to null removes the record from the hasMany side - sync', function(assert) { var user, account; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '1', - type: 'account' - }] - } - } - } + data: [ + { + id: '1', + type: 'account', + }, + ], + }, + }, + }, }); account = store.push({ data: { id: '1', type: 'account', attributes: { - state: 'great' + state: 'great', }, relationships: { user: { data: { id: '1', - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); account.set('user', null); }); @@ -1191,34 +1257,36 @@ test("Setting the belongsTo side to null removes the record from the hasMany sid Rollback attributes from deleted state */ -test("Rollbacking attributes of a deleted record works correctly when the hasMany side has been deleted - async", function(assert) { +test('Rollbacking attributes of a deleted record works correctly when the hasMany side has been deleted - async', function(assert) { var user, message; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { messages: { - data: [{ - id: '2', - type: 'message' - }] - } - } - } + data: [ + { + id: '2', + type: 'message', + }, + ], + }, + }, + }, }); message = store.push({ data: { id: '2', type: 'message', attributes: { - title: 'EmberFest was great' - } - } + title: 'EmberFest was great', + }, + }, }); }); run(function() { @@ -1235,72 +1303,76 @@ test("Rollbacking attributes of a deleted record works correctly when the hasMan }); }); -test("Rollbacking attributes of a deleted record works correctly when the hasMany side has been deleted - sync", function(assert) { +test('Rollbacking attributes of a deleted record works correctly when the hasMany side has been deleted - sync', function(assert) { var account, user; - run(function () { + run(function() { account = store.push({ data: { id: '2', type: 'account', attributes: { - state: 'lonely' - } - } + state: 'lonely', + }, + }, }); user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '2', - type: 'account' - }] - } - } - } + data: [ + { + id: '2', + type: 'account', + }, + ], + }, + }, + }, }); }); run(function() { account.deleteRecord(); account.rollbackAttributes(); - assert.equal(user.get('accounts.length'), 1, "Accounts are rolled back"); + assert.equal(user.get('accounts.length'), 1, 'Accounts are rolled back'); assert.equal(account.get('user'), user, 'Account still has the user'); }); }); -test("Rollbacking attributes of deleted record works correctly when the belongsTo side has been deleted - async", function(assert) { +test('Rollbacking attributes of deleted record works correctly when the belongsTo side has been deleted - async', function(assert) { var user, message; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { messages: { - data: [{ - id: '2', - type: 'message' - }] - } - } - } + data: [ + { + id: '2', + type: 'message', + }, + ], + }, + }, + }, }); message = store.push({ data: { id: '2', type: 'message', attributes: { - title: 'EmberFest was great' - } - } + title: 'EmberFest was great', + }, + }, }); }); run(function() { @@ -1317,40 +1389,42 @@ test("Rollbacking attributes of deleted record works correctly when the belongsT }); }); -test("Rollbacking attributes of a deleted record works correctly when the belongsTo side has been deleted - sync", function(assert) { +test('Rollbacking attributes of a deleted record works correctly when the belongsTo side has been deleted - sync', function(assert) { var account, user; - run(function () { + run(function() { account = store.push({ data: { id: '2', type: 'account', attributes: { - state: 'lonely' - } - } + state: 'lonely', + }, + }, }); user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { accounts: { - data: [{ - id: '2', - type: 'account' - }] - } - } - } + data: [ + { + id: '2', + type: 'account', + }, + ], + }, + }, + }, }); }); run(function() { user.deleteRecord(); user.rollbackAttributes(); - assert.equal(user.get('accounts.length'), 1, "User still has the accounts"); + assert.equal(user.get('accounts.length'), 1, 'User still has the accounts'); assert.equal(account.get('user'), user, 'Account has the user again'); }); }); @@ -1359,20 +1433,20 @@ test("Rollbacking attributes of a deleted record works correctly when the belong Rollback attributes from created state */ -test("Rollbacking attributes of a created record works correctly when the hasMany side has been created - async", function(assert) { +test('Rollbacking attributes of a created record works correctly when the hasMany side has been created - async', function(assert) { var user, message; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); message = store.createRecord('message', { - user: user + user: user, }); }); run(message, 'rollbackAttributes'); @@ -1387,38 +1461,38 @@ test("Rollbacking attributes of a created record works correctly when the hasMan }); }); -test("Rollbacking attributes of a created record works correctly when the hasMany side has been created - sync", function(assert) { +test('Rollbacking attributes of a created record works correctly when the hasMany side has been created - sync', function(assert) { var user, account; - run(function () { + run(function() { user = store.push({ data: { id: '1', type: 'user', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); account = store.createRecord('account', { - user: user + user: user, }); }); run(account, 'rollbackAttributes'); - assert.equal(user.get('accounts.length'), 0, "Accounts are rolled back"); + assert.equal(user.get('accounts.length'), 0, 'Accounts are rolled back'); assert.equal(account.get('user'), null, 'Account does not have the user anymore'); }); -test("Rollbacking attributes of a created record works correctly when the belongsTo side has been created - async", function(assert) { +test('Rollbacking attributes of a created record works correctly when the belongsTo side has been created - async', function(assert) { var message, user; - run(function () { + run(function() { message = store.push({ data: { id: '2', type: 'message', attributes: { - title: 'EmberFest was great' - } - } + title: 'EmberFest was great', + }, + }, }); user = store.createRecord('user'); }); @@ -1437,17 +1511,17 @@ test("Rollbacking attributes of a created record works correctly when the belong }); }); -test("Rollbacking attributes of a created record works correctly when the belongsTo side has been created - sync", function(assert) { +test('Rollbacking attributes of a created record works correctly when the belongsTo side has been created - sync', function(assert) { var account, user; - run(function () { + run(function() { account = store.push({ data: { id: '2', type: 'account', attributes: { - state: 'lonely' - } - } + state: 'lonely', + }, + }, }); user = store.createRecord('user'); }); @@ -1455,22 +1529,23 @@ test("Rollbacking attributes of a created record works correctly when the belong user.get('accounts').pushObject(account); }); run(user, 'rollbackAttributes'); - assert.equal(user.get('accounts.length'), 0, "User does not have the account anymore"); + assert.equal(user.get('accounts.length'), 0, 'User does not have the account anymore'); assert.equal(account.get('user'), null, 'Account does not have the user anymore'); }); -test("createRecord updates inverse record array which has observers", function(assert) { - +test('createRecord updates inverse record array which has observers', function(assert) { env.adapter.findAll = () => { return { - data: [{ - id: '2', - type: 'user', - attributes: { - name: 'Stanley' - } - }] - } + data: [ + { + id: '2', + type: 'user', + attributes: { + name: 'Stanley', + }, + }, + ], + }; }; return store.findAll('user').then(users => { diff --git a/tests/integration/relationships/one-to-one-test.js b/tests/integration/relationships/one-to-one-test.js index c65f848b149..88cabe9e72f 100644 --- a/tests/integration/relationships/one-to-one-test.js +++ b/tests/integration/relationships/one-to-one-test.js @@ -17,20 +17,20 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', { User = DS.Model.extend({ name: attr('string'), bestFriend: belongsTo('user', { async: true, inverse: 'bestFriend' }), - job: belongsTo('job', { async: false }) + job: belongsTo('job', { async: false }), }); Job = DS.Model.extend({ isGood: attr(), - user: belongsTo('user', { async: false }) + user: belongsTo('user', { async: false }), }); env = setupStore({ user: User, job: Job, adapter: DS.Adapter.extend({ - deleteRecord: () => resolve() - }) + deleteRecord: () => resolve(), + }), }); store = env.store; @@ -38,14 +38,14 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', { afterEach() { run(env.container, 'destroy'); - } + }, }); /* Server loading tests */ -test("Relationship is available from both sides even if only loaded from one side - async", function(assert) { +test('Relationship is available from both sides even if only loaded from one side - async', function(assert) { var stanley, stanleysFriend; run(function() { stanley = store.push({ @@ -53,26 +53,26 @@ test("Relationship is available from both sides even if only loaded from one sid id: 1, type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { bestFriend: { data: { id: 2, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); stanleysFriend = store.push({ data: { id: 2, type: 'user', attributes: { - name: "Stanley's friend" - } - } + name: "Stanley's friend", + }, + }, }); stanleysFriend.get('bestFriend').then(function(fetchedUser) { @@ -81,8 +81,7 @@ test("Relationship is available from both sides even if only loaded from one sid }); }); - -test("Relationship is available from both sides even if only loaded from one side - sync", function(assert) { +test('Relationship is available from both sides even if only loaded from one side - sync', function(assert) { var job, user; run(function() { job = store.push({ @@ -90,32 +89,32 @@ test("Relationship is available from both sides even if only loaded from one sid id: 2, type: 'job', attributes: { - isGood: true - } - } + isGood: true, + }, + }, }); user = store.push({ data: { id: 1, type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { job: { data: { id: 2, - type: 'job' - } - } - } - } + type: 'job', + }, + }, + }, + }, }); }); assert.equal(job.get('user'), user, 'User relationship was set up correctly'); }); -test("Fetching a belongsTo that is set to null removes the record from a relationship - async", function(assert) { +test('Fetching a belongsTo that is set to null removes the record from a relationship - async', function(assert) { var stanleysFriend; run(function() { stanleysFriend = store.push({ @@ -123,31 +122,31 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio id: 2, type: 'user', attributes: { - name: "Stanley's friend" + name: "Stanley's friend", }, relationships: { bestFriend: { data: { id: 1, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); store.push({ data: { id: 1, type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { bestFriend: { - data: null - } - } - } + data: null, + }, + }, + }, }); stanleysFriend.get('bestFriend').then(function(fetchedUser) { assert.equal(fetchedUser, null, 'User relationship was removed correctly'); @@ -155,8 +154,7 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio }); }); - -test("Fetching a belongsTo that is set to null removes the record from a relationship - sync", function(assert) { +test('Fetching a belongsTo that is set to null removes the record from a relationship - sync', function(assert) { var job; run(function() { job = store.push({ @@ -164,26 +162,26 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio id: 2, type: 'job', attributes: { - isGood: true - } - } + isGood: true, + }, + }, }); store.push({ data: { id: 1, type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { job: { data: { id: 2, - type: 'job' - } - } - } - } + type: 'job', + }, + }, + }, + }, }); }); run(function() { @@ -192,21 +190,20 @@ test("Fetching a belongsTo that is set to null removes the record from a relatio id: 2, type: 'job', attributes: { - isGood: true + isGood: true, }, relationships: { user: { - data: null - } - } - } + data: null, + }, + }, + }, }); }); assert.equal(job.get('user'), null, 'User relationship was removed correctly'); }); - -test("Fetching a belongsTo that is set to a different record, sets the old relationship to null - async", function(assert) { +test('Fetching a belongsTo that is set to a different record, sets the old relationship to null - async', function(assert) { assert.expect(3); var stanley, stanleysFriend; run(function() { @@ -215,34 +212,34 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat id: 1, type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { bestFriend: { data: { id: 2, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); stanleysFriend = store.push({ data: { id: 2, type: 'user', attributes: { - name: "Stanley's friend" + name: "Stanley's friend", }, relationships: { bestFriend: { data: { id: 1, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); stanleysFriend.get('bestFriend').then(function(fetchedUser) { @@ -254,22 +251,26 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat id: 3, type: 'user', attributes: { - name: "Stanley's New friend" + name: "Stanley's New friend", }, relationships: { bestFriend: { data: { id: 1, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); }); stanley.get('bestFriend').then(function(fetchedNewFriend) { - assert.equal(fetchedNewFriend, stanleysNewFriend, 'User relationship was updated correctly'); + assert.equal( + fetchedNewFriend, + stanleysNewFriend, + 'User relationship was updated correctly' + ); }); stanleysFriend.get('bestFriend').then(function(fetchedOldFriend) { @@ -279,8 +280,7 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat }); }); - -test("Fetching a belongsTo that is set to a different record, sets the old relationship to null - sync", function(assert) { +test('Fetching a belongsTo that is set to a different record, sets the old relationship to null - sync', function(assert) { var job, user, newBetterJob; run(function() { job = store.push({ @@ -288,26 +288,26 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat id: 2, type: 'job', attributes: { - isGood: false - } - } + isGood: false, + }, + }, }); user = store.push({ data: { id: 1, type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { job: { data: { id: 2, - type: 'job' - } - } - } - } + type: 'job', + }, + }, + }, + }, }); }); assert.equal(job.get('user'), user, 'Job and user initially setup correctly'); @@ -317,17 +317,17 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat id: 3, type: 'job', attributes: { - isGood: true + isGood: true, }, relationships: { user: { data: { id: 1, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); }); @@ -340,7 +340,7 @@ test("Fetching a belongsTo that is set to a different record, sets the old relat Local edits */ -test("Setting a OneToOne relationship reflects correctly on the other side- async", function(assert) { +test('Setting a OneToOne relationship reflects correctly on the other side- async', function(assert) { var stanley, stanleysFriend; run(function() { stanley = store.push({ @@ -348,18 +348,18 @@ test("Setting a OneToOne relationship reflects correctly on the other side- asyn id: 1, type: 'user', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); stanleysFriend = store.push({ data: { id: 2, type: 'user', attributes: { - name: "Stanley's friend" - } - } + name: "Stanley's friend", + }, + }, }); }); run(function() { @@ -370,8 +370,7 @@ test("Setting a OneToOne relationship reflects correctly on the other side- asyn }); }); - -test("Setting a OneToOne relationship reflects correctly on the other side- sync", function(assert) { +test('Setting a OneToOne relationship reflects correctly on the other side- sync', function(assert) { var job, user; run(function() { job = store.push({ @@ -379,18 +378,18 @@ test("Setting a OneToOne relationship reflects correctly on the other side- sync id: 2, type: 'job', attributes: { - isGood: true - } - } + isGood: true, + }, + }, }); user = store.push({ data: { id: 1, type: 'user', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); }); run(function() { @@ -399,8 +398,7 @@ test("Setting a OneToOne relationship reflects correctly on the other side- sync assert.equal(job.get('user'), user, 'User relationship was set up correctly'); }); - -test("Setting a BelongsTo to a promise unwraps the promise before setting- async", function(assert) { +test('Setting a BelongsTo to a promise unwraps the promise before setting- async', function(assert) { var stanley, stanleysFriend, newFriend; run(function() { stanley = store.push({ @@ -408,35 +406,35 @@ test("Setting a BelongsTo to a promise unwraps the promise before setting- async id: 1, type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { bestFriend: { data: { id: 2, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); stanleysFriend = store.push({ data: { id: 2, type: 'user', attributes: { - name: "Stanley's friend" - } - } + name: "Stanley's friend", + }, + }, }); newFriend = store.push({ data: { id: 3, type: 'user', attributes: { - name: "New friend" - } - } + name: 'New friend', + }, + }, }); }); run(function() { @@ -450,8 +448,7 @@ test("Setting a BelongsTo to a promise unwraps the promise before setting- async }); }); - -test("Setting a BelongsTo to a promise works when the promise returns null- async", function(assert) { +test('Setting a BelongsTo to a promise works when the promise returns null- async', function(assert) { var igor, newFriend; run(function() { store.push({ @@ -459,35 +456,35 @@ test("Setting a BelongsTo to a promise works when the promise returns null- asyn id: 1, type: 'user', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); igor = store.push({ data: { id: 2, type: 'user', attributes: { - name: "Igor" - } - } + name: 'Igor', + }, + }, }); newFriend = store.push({ data: { id: 3, type: 'user', attributes: { - name: "New friend" + name: 'New friend', }, relationships: { bestFriend: { data: { id: 1, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); }); run(function() { @@ -498,46 +495,48 @@ test("Setting a BelongsTo to a promise works when the promise returns null- asyn }); }); - -testInDebug("Setting a BelongsTo to a promise that didn't come from a relationship errors out", function(assert) { - var stanley, igor; - run(function() { - stanley = store.push({ - data: { - id: 1, - type: 'user', - attributes: { - name: 'Stanley' +testInDebug( + "Setting a BelongsTo to a promise that didn't come from a relationship errors out", + function(assert) { + var stanley, igor; + run(function() { + stanley = store.push({ + data: { + id: 1, + type: 'user', + attributes: { + name: 'Stanley', + }, + relationships: { + bestFriend: { + data: { + id: 2, + type: 'user', + }, + }, + }, }, - relationships: { - bestFriend: { - data: { - id: 2, - type: 'user' - } - } - } - } - }); - igor = store.push({ - data: { - id: 3, - type: 'user', - attributes: { - name: 'Igor' - } - } + }); + igor = store.push({ + data: { + id: 3, + type: 'user', + attributes: { + name: 'Igor', + }, + }, + }); }); - }); - assert.expectAssertion(function() { - run(function() { - stanley.set('bestFriend', resolve(igor)); - }); - }, /You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call./); -}); + assert.expectAssertion(function() { + run(function() { + stanley.set('bestFriend', resolve(igor)); + }); + }, /You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call./); + } +); -test("Setting a BelongsTo to a promise multiple times is resistant to race conditions- async", function(assert) { +test('Setting a BelongsTo to a promise multiple times is resistant to race conditions- async', function(assert) { assert.expect(1); var stanley, igor, newFriend; run(function() { @@ -546,43 +545,43 @@ test("Setting a BelongsTo to a promise multiple times is resistant to race condi id: 1, type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { bestFriend: { data: { id: 2, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); igor = store.push({ data: { id: 3, type: 'user', attributes: { - name: "Igor" + name: 'Igor', }, relationships: { bestFriend: { data: { id: 5, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); newFriend = store.push({ data: { id: 7, type: 'user', attributes: { - name: "New friend" - } - } + name: 'New friend', + }, + }, }); }); @@ -604,12 +603,16 @@ test("Setting a BelongsTo to a promise multiple times is resistant to race condi newFriend.set('bestFriend', stanley.get('bestFriend')); newFriend.set('bestFriend', igor.get('bestFriend')); newFriend.get('bestFriend').then(function(fetchedUser) { - assert.equal(fetchedUser.get('name'), "Igor's friend", 'User relationship was updated correctly'); + assert.equal( + fetchedUser.get('name'), + "Igor's friend", + 'User relationship was updated correctly' + ); }); }); }); -test("Setting a OneToOne relationship to null reflects correctly on the other side - async", function(assert) { +test('Setting a OneToOne relationship to null reflects correctly on the other side - async', function(assert) { var stanley, stanleysFriend; run(function() { stanley = store.push({ @@ -617,34 +620,34 @@ test("Setting a OneToOne relationship to null reflects correctly on the other si id: 1, type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { bestFriend: { data: { id: 2, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); stanleysFriend = store.push({ data: { id: 2, type: 'user', attributes: { - name: "Stanley's friend" + name: "Stanley's friend", }, relationships: { bestFriend: { data: { id: 1, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); }); @@ -656,7 +659,7 @@ test("Setting a OneToOne relationship to null reflects correctly on the other si }); }); -test("Setting a OneToOne relationship to null reflects correctly on the other side - sync", function(assert) { +test('Setting a OneToOne relationship to null reflects correctly on the other side - sync', function(assert) { var job, user; run(function() { job = store.push({ @@ -664,34 +667,34 @@ test("Setting a OneToOne relationship to null reflects correctly on the other si id: 2, type: 'job', attributes: { - isGood: false + isGood: false, }, relationships: { user: { data: { id: 1, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); user = store.push({ data: { id: 1, type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { job: { data: { id: 2, - type: 'job' - } - } - } - } + type: 'job', + }, + }, + }, + }, }); }); @@ -701,7 +704,7 @@ test("Setting a OneToOne relationship to null reflects correctly on the other si assert.equal(job.get('user'), null, 'User relationship was removed correctly'); }); -test("Setting a belongsTo to a different record, sets the old relationship to null - async", function(assert) { +test('Setting a belongsTo to a different record, sets the old relationship to null - async', function(assert) { assert.expect(3); var stanley, stanleysFriend; @@ -711,37 +714,36 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu id: 1, type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { bestFriend: { data: { id: 2, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); stanleysFriend = store.push({ data: { id: 2, type: 'user', attributes: { - name: "Stanley's friend" + name: "Stanley's friend", }, relationships: { bestFriend: { data: { id: 1, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); - stanleysFriend.get('bestFriend').then(function(fetchedUser) { assert.equal(fetchedUser, stanley, 'User relationship was initally setup correctly'); var stanleysNewFriend = store.push({ @@ -749,9 +751,9 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu id: 3, type: 'user', attributes: { - name: "Stanley's New friend" - } - } + name: "Stanley's New friend", + }, + }, }); run(function() { @@ -759,7 +761,11 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu }); stanley.get('bestFriend').then(function(fetchedNewFriend) { - assert.equal(fetchedNewFriend, stanleysNewFriend, 'User relationship was updated correctly'); + assert.equal( + fetchedNewFriend, + stanleysNewFriend, + 'User relationship was updated correctly' + ); }); stanleysFriend.get('bestFriend').then(function(fetchedOldFriend) { @@ -769,7 +775,7 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu }); }); -test("Setting a belongsTo to a different record, sets the old relationship to null - sync", function(assert) { +test('Setting a belongsTo to a different record, sets the old relationship to null - sync', function(assert) { var job, user, newBetterJob; run(function() { job = store.push({ @@ -777,26 +783,26 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu id: 2, type: 'job', attributes: { - isGood: false - } - } + isGood: false, + }, + }, }); user = store.push({ data: { id: 1, type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { job: { data: { id: 2, - type: 'job' - } - } - } - } + type: 'job', + }, + }, + }, + }, }); }); @@ -808,9 +814,9 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu id: 3, type: 'job', attributes: { - isGood: true - } - } + isGood: true, + }, + }, }); newBetterJob.set('user', user); @@ -825,7 +831,7 @@ test("Setting a belongsTo to a different record, sets the old relationship to nu Rollback attributes tests */ -test("Rollbacking attributes of deleted record restores the relationship on both sides - async", function(assert) { +test('Rollbacking attributes of deleted record restores the relationship on both sides - async', function(assert) { var stanley, stanleysFriend; run(function() { stanley = store.push({ @@ -833,28 +839,27 @@ test("Rollbacking attributes of deleted record restores the relationship on both id: 1, type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { bestFriend: { data: { id: 2, - type: 'user' - } - } - } - } + type: 'user', + }, + }, + }, + }, }); stanleysFriend = store.push({ data: { id: 2, type: 'user', attributes: { - name: "Stanley's friend" - } - } + name: "Stanley's friend", + }, + }, }); - }); run(function() { stanley.deleteRecord(); @@ -870,7 +875,7 @@ test("Rollbacking attributes of deleted record restores the relationship on both }); }); -test("Rollbacking attributes of deleted record restores the relationship on both sides - sync", function(assert) { +test('Rollbacking attributes of deleted record restores the relationship on both sides - sync', function(assert) { var job, user; run(function() { job = store.push({ @@ -878,26 +883,26 @@ test("Rollbacking attributes of deleted record restores the relationship on both id: 2, type: 'job', attributes: { - isGood: true - } - } + isGood: true, + }, + }, }); user = store.push({ data: { id: 1, type: 'user', attributes: { - name: 'Stanley' + name: 'Stanley', }, relationships: { job: { data: { id: 2, - type: 'job' - } - } - } - } + type: 'job', + }, + }, + }, + }, }); }); run(function() { @@ -908,7 +913,7 @@ test("Rollbacking attributes of deleted record restores the relationship on both assert.equal(job.get('user'), user, 'Job still has the user'); }); -test("Rollbacking attributes of created record removes the relationship on both sides - async", function(assert) { +test('Rollbacking attributes of created record removes the relationship on both sides - async', function(assert) { var stanleysFriend, stanley; run(function() { stanleysFriend = store.push({ @@ -916,9 +921,9 @@ test("Rollbacking attributes of created record removes the relationship on both id: 2, type: 'user', attributes: { - name: "Stanley's friend" - } - } + name: "Stanley's friend", + }, + }, }); stanley = store.createRecord('user', { bestFriend: stanleysFriend }); @@ -934,7 +939,7 @@ test("Rollbacking attributes of created record removes the relationship on both }); }); -test("Rollbacking attributes of created record removes the relationship on both sides - sync", function(assert) { +test('Rollbacking attributes of created record removes the relationship on both sides - sync', function(assert) { var user, job; run(function() { user = store.push({ @@ -942,9 +947,9 @@ test("Rollbacking attributes of created record removes the relationship on both id: 1, type: 'user', attributes: { - name: 'Stanley' - } - } + name: 'Stanley', + }, + }, }); job = store.createRecord('job', { user: user }); diff --git a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index 38e134012fa..3259d0b8a48 100644 --- a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -1,6 +1,6 @@ import { setup as setupModelFactoryInjections, - reset as resetModelFactoryInjections + reset as resetModelFactoryInjections, } from 'dummy/tests/helpers/model-factory-injection'; import Mixin from '@ember/object/mixin'; @@ -17,67 +17,73 @@ var env, store, User, Message, Video, NotMessage; var attr = DS.attr; var belongsTo = DS.belongsTo; -module('integration/relationships/polymorphic_mixins_belongs_to_test - Polymorphic belongsTo relationships with mixins', { - beforeEach() { - User = DS.Model.extend({ - name: attr('string'), - bestMessage: belongsTo('message', { async: true, polymorphic: true }) - }); +module( + 'integration/relationships/polymorphic_mixins_belongs_to_test - Polymorphic belongsTo relationships with mixins', + { + beforeEach() { + User = DS.Model.extend({ + name: attr('string'), + bestMessage: belongsTo('message', { async: true, polymorphic: true }), + }); - Message = Mixin.create({ - title: attr('string'), - user: belongsTo('user', { async: true }) - }); + Message = Mixin.create({ + title: attr('string'), + user: belongsTo('user', { async: true }), + }); - NotMessage = DS.Model.extend({ - video: attr() - }); + NotMessage = DS.Model.extend({ + video: attr(), + }); - Video = DS.Model.extend(Message, { - video: attr() - }); + Video = DS.Model.extend(Message, { + video: attr(), + }); - env = setupStore({ - user: User, - video: Video, - notMessage: NotMessage - }); + env = setupStore({ + user: User, + video: Video, + notMessage: NotMessage, + }); - env.registry.register('mixin:message', Message); - store = env.store; - }, + env.registry.register('mixin:message', Message); + store = env.store; + }, - afterEach() { - run(env.container, 'destroy'); + afterEach() { + run(env.container, 'destroy'); + }, } -}); +); /* Server loading tests */ -test("Relationship is available from the belongsTo side even if only loaded from the inverse side - async", function(assert) { +test('Relationship is available from the belongsTo side even if only loaded from the inverse side - async', function(assert) { var user, video; run(function() { store.push({ - data: [{ - type: 'user', - id: '1', - attributes: { - name: 'Stanley' + data: [ + { + type: 'user', + id: '1', + attributes: { + name: 'Stanley', + }, + relationships: { + bestMessage: { + data: { type: 'video', id: '2' }, + }, + }, }, - relationships: { - bestMessage: { - data: { type: 'video', id: '2' } - } - } - }, { - type: 'video', - id: '2', - attributes: { - video: 'Here comes Youtube' - } - }] + { + type: 'video', + id: '2', + attributes: { + video: 'Here comes Youtube', + }, + }, + ], }); user = store.peekRecord('user', 1); video = store.peekRecord('video', 2); @@ -95,23 +101,26 @@ test("Relationship is available from the belongsTo side even if only loaded from /* Local edits */ -test("Setting the polymorphic belongsTo gets propagated to the inverse side - async", function(assert) { +test('Setting the polymorphic belongsTo gets propagated to the inverse side - async', function(assert) { var user, video; run(function() { store.push({ - data: [{ - type: 'user', - id: '1', - attributes: { - name: 'Stanley' - } - }, { - type: 'video', - id: '2', - attributes: { - video: 'Here comes Youtube' - } - }] + data: [ + { + type: 'user', + id: '1', + attributes: { + name: 'Stanley', + }, + }, + { + type: 'video', + id: '2', + attributes: { + video: 'Here comes Youtube', + }, + }, + ], }); user = store.peekRecord('user', 1); video = store.peekRecord('video', 2); @@ -120,7 +129,7 @@ test("Setting the polymorphic belongsTo gets propagated to the inverse side - as run(function() { user.set('bestMessage', video); video.get('user').then(function(fetchedUser) { - assert.equal(fetchedUser, user, "user got set correctly"); + assert.equal(fetchedUser, user, 'user got set correctly'); }); user.get('bestMessage').then(function(message) { assert.equal(message, video, 'The message was set correctly'); @@ -128,37 +137,42 @@ test("Setting the polymorphic belongsTo gets propagated to the inverse side - as }); }); -testInDebug("Setting the polymorphic belongsTo with an object that does not implement the mixin errors out", function(assert) { - var user, video; - run(function() { - store.push({ - data: [{ - type: 'user', - id: '1', - attributes: { - name: 'Stanley' - } - }, { - type: 'not-message', - id: '2', - attributes: { - video: 'Here comes Youtube' - } - }] +testInDebug( + 'Setting the polymorphic belongsTo with an object that does not implement the mixin errors out', + function(assert) { + var user, video; + run(function() { + store.push({ + data: [ + { + type: 'user', + id: '1', + attributes: { + name: 'Stanley', + }, + }, + { + type: 'not-message', + id: '2', + attributes: { + video: 'Here comes Youtube', + }, + }, + ], + }); + user = store.peekRecord('user', 1); + video = store.peekRecord('not-message', 2); }); - user = store.peekRecord('user', 1); - video = store.peekRecord('not-message', 2); - }); - - run(function() { - assert.expectAssertion(function() { - user.set('bestMessage', video); - }, /You cannot add a record of modelClass 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); - }); -}); + run(function() { + assert.expectAssertion(function() { + user.set('bestMessage', video); + }, /You cannot add a record of modelClass 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); + }); + } +); -test("Setting the polymorphic belongsTo gets propagated to the inverse side - model injections true", function(assert) { +test('Setting the polymorphic belongsTo gets propagated to the inverse side - model injections true', function(assert) { assert.expect(2); setupModelFactoryInjections(); @@ -166,19 +180,22 @@ test("Setting the polymorphic belongsTo gets propagated to the inverse side - mo var user, video; run(function() { store.push({ - data: [{ - type: 'user', - id: '1', - attributes: { - name: 'Stanley' - } - }, { - type: 'video', - id: '2', - attributes: { - video: 'Here comes Youtube' - } - }] + data: [ + { + type: 'user', + id: '1', + attributes: { + name: 'Stanley', + }, + }, + { + type: 'video', + id: '2', + attributes: { + video: 'Here comes Youtube', + }, + }, + ], }); user = store.peekRecord('user', 1); video = store.peekRecord('video', 2); @@ -187,7 +204,7 @@ test("Setting the polymorphic belongsTo gets propagated to the inverse side - mo run(function() { user.set('bestMessage', video); video.get('user').then(function(fetchedUser) { - assert.equal(fetchedUser, user, "user got set correctly"); + assert.equal(fetchedUser, user, 'user got set correctly'); }); user.get('bestMessage').then(function(message) { assert.equal(message, video, 'The message was set correctly'); @@ -198,37 +215,43 @@ test("Setting the polymorphic belongsTo gets propagated to the inverse side - mo } }); -testInDebug("Setting the polymorphic belongsTo with an object that does not implement the mixin errors out - model injections true", function(assert) { - setupModelFactoryInjections(); +testInDebug( + 'Setting the polymorphic belongsTo with an object that does not implement the mixin errors out - model injections true', + function(assert) { + setupModelFactoryInjections(); - try { - var user, video; - run(function() { - store.push({ - data: [{ - type: 'user', - id: '1', - attributes: { - name: 'Stanley' - } - }, { - type: 'not-message', - id: '2', - attributes: { - video: 'Here comes Youtube' - } - }] + try { + var user, video; + run(function() { + store.push({ + data: [ + { + type: 'user', + id: '1', + attributes: { + name: 'Stanley', + }, + }, + { + type: 'not-message', + id: '2', + attributes: { + video: 'Here comes Youtube', + }, + }, + ], + }); + user = store.peekRecord('user', 1); + video = store.peekRecord('not-message', 2); }); - user = store.peekRecord('user', 1); - video = store.peekRecord('not-message', 2); - }); - run(function() { - assert.expectAssertion(function() { - user.set('bestMessage', video); - }, /You cannot add a record of modelClass 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); - }); - } finally { - resetModelFactoryInjections(); + run(function() { + assert.expectAssertion(function() { + user.set('bestMessage', video); + }, /You cannot add a record of modelClass 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); + }); + } finally { + resetModelFactoryInjections(); + } } -}); +); diff --git a/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js index 470e3dfd146..4d3ecd0ff7d 100644 --- a/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -1,6 +1,6 @@ import { setup as setupModelFactoryInjections, - reset as resetModelFactoryInjections + reset as resetModelFactoryInjections, } from 'dummy/tests/helpers/model-factory-injection'; import Mixin from '@ember/object/mixin'; @@ -18,69 +18,73 @@ var attr = DS.attr; var hasMany = DS.hasMany; var belongsTo = DS.belongsTo; -module('integration/relationships/polymorphic_mixins_has_many_test - Polymorphic hasMany relationships with mixins', { - beforeEach() { - User = DS.Model.extend({ - name: attr('string'), - messages: hasMany('message', { async: true, polymorphic: true }) - }); +module( + 'integration/relationships/polymorphic_mixins_has_many_test - Polymorphic hasMany relationships with mixins', + { + beforeEach() { + User = DS.Model.extend({ + name: attr('string'), + messages: hasMany('message', { async: true, polymorphic: true }), + }); - Message = Mixin.create({ - title: attr('string'), - user: belongsTo('user', { async: true }) - }); + Message = Mixin.create({ + title: attr('string'), + user: belongsTo('user', { async: true }), + }); - Video = DS.Model.extend(Message, { - video: attr() - }); + Video = DS.Model.extend(Message, { + video: attr(), + }); - NotMessage = DS.Model.extend({ - video: attr() - }); + NotMessage = DS.Model.extend({ + video: attr(), + }); - env = setupStore({ - user: User, - video: Video, - notMessage: NotMessage - }); + env = setupStore({ + user: User, + video: Video, + notMessage: NotMessage, + }); - env.registry.register('mixin:message', Message); - store = env.store; - }, + env.registry.register('mixin:message', Message); + store = env.store; + }, - afterEach() { - run(env.container, 'destroy'); + afterEach() { + run(env.container, 'destroy'); + }, } -}); +); /* Server loading tests */ -test("Relationship is available from the belongsTo side even if only loaded from the hasMany side - async", function(assert) { +test('Relationship is available from the belongsTo side even if only loaded from the hasMany side - async', function(assert) { var user, video; run(function() { store.push({ - data: [{ - type: 'user', - id: '1', - attributes: { - name: 'Stanley' + data: [ + { + type: 'user', + id: '1', + attributes: { + name: 'Stanley', + }, + relationships: { + messages: { + data: [{ type: 'video', id: '2' }], + }, + }, }, - relationships: { - messages: { - data: [ - { type: 'video', id: '2' } - ] - } - } - }, { - type: 'video', - id: '2', - attributes: { - video: 'Here comes Youtube' - } - }] + { + type: 'video', + id: '2', + attributes: { + video: 'Here comes Youtube', + }, + }, + ], }); user = store.peekRecord('user', 1); video = store.peekRecord('video', 2); @@ -88,9 +92,12 @@ test("Relationship is available from the belongsTo side even if only loaded from run(function() { user.get('messages').then(function(messages) { assert.equal(messages.objectAt(0), video, 'The hasMany has loaded correctly'); - messages.objectAt(0).get('user').then(function(fetchedUser) { - assert.equal(fetchedUser, user, 'The inverse was setup correctly'); - }); + messages + .objectAt(0) + .get('user') + .then(function(fetchedUser) { + assert.equal(fetchedUser, user, 'The inverse was setup correctly'); + }); }); }); }); @@ -98,28 +105,31 @@ test("Relationship is available from the belongsTo side even if only loaded from /* Local edits */ -test("Pushing to the hasMany reflects the change on the belongsTo side - async", function(assert) { +test('Pushing to the hasMany reflects the change on the belongsTo side - async', function(assert) { var user, video; run(function() { store.push({ - data: [{ - type: 'user', - id: '1', - attributes: { - name: 'Stanley' + data: [ + { + type: 'user', + id: '1', + attributes: { + name: 'Stanley', + }, + relationships: { + messages: { + data: [], + }, + }, + }, + { + type: 'video', + id: '2', + attributes: { + video: 'Here comes Youtube', + }, }, - relationships: { - messages: { - data: [] - } - } - }, { - type: 'video', - id: '2', - attributes: { - video: 'Here comes Youtube' - } - }] + ], }); user = store.peekRecord('user', 1); video = store.peekRecord('video', 2); @@ -129,7 +139,7 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - async", user.get('messages').then(function(fetchedMessages) { fetchedMessages.pushObject(video); video.get('user').then(function(fetchedUser) { - assert.equal(fetchedUser, user, "user got set correctly"); + assert.equal(fetchedUser, user, 'user got set correctly'); }); }); }); @@ -138,67 +148,76 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - async", /* Local edits */ -testInDebug("Pushing a an object that does not implement the mixin to the mixin accepting array errors out", function(assert) { - var user,notMessage; - run(function() { - store.push({ - data: [{ - type: 'user', - id: '1', - attributes: { - name: 'Stanley' - }, - relationships: { - messages: { - data: [] - } - } - }, { - type: 'not-message', - id: '2', - attributes: { - video: 'Here comes Youtube' - } - }] +testInDebug( + 'Pushing a an object that does not implement the mixin to the mixin accepting array errors out', + function(assert) { + var user, notMessage; + run(function() { + store.push({ + data: [ + { + type: 'user', + id: '1', + attributes: { + name: 'Stanley', + }, + relationships: { + messages: { + data: [], + }, + }, + }, + { + type: 'not-message', + id: '2', + attributes: { + video: 'Here comes Youtube', + }, + }, + ], + }); + user = store.peekRecord('user', 1); + notMessage = store.peekRecord('not-message', 2); }); - user = store.peekRecord('user', 1); - notMessage = store.peekRecord('not-message', 2); - }); - run(function() { - user.get('messages').then(function(fetchedMessages) { - assert.expectAssertion(function() { - fetchedMessages.pushObject(notMessage); - }, /You cannot add a record of modelClass 'not-message' to the 'user.messages' relationship \(only 'message' allowed\)/); + run(function() { + user.get('messages').then(function(fetchedMessages) { + assert.expectAssertion(function() { + fetchedMessages.pushObject(notMessage); + }, /You cannot add a record of modelClass 'not-message' to the 'user.messages' relationship \(only 'message' allowed\)/); + }); }); - }); -}); + } +); -test("Pushing to the hasMany reflects the change on the belongsTo side - model injections true", function(assert) { +test('Pushing to the hasMany reflects the change on the belongsTo side - model injections true', function(assert) { setupModelFactoryInjections(); try { var user, video; run(function() { store.push({ - data: [{ - type: 'user', - id: '1', - attributes: { - name: 'Stanley' + data: [ + { + type: 'user', + id: '1', + attributes: { + name: 'Stanley', + }, + relationships: { + messages: { + data: [], + }, + }, }, - relationships: { - messages: { - data: [] - } - } - }, { - type: 'video', - id: '2', - attributes: { - video: 'Here comes Youtube' - } - }] + { + type: 'video', + id: '2', + attributes: { + video: 'Here comes Youtube', + }, + }, + ], }); user = store.peekRecord('user', 1); video = store.peekRecord('video', 2); @@ -208,7 +227,7 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - model i user.get('messages').then(function(fetchedMessages) { fetchedMessages.pushObject(video); video.get('user').then(function(fetchedUser) { - assert.equal(fetchedUser, user, "user got set correctly"); + assert.equal(fetchedUser, user, 'user got set correctly'); }); }); }); @@ -220,44 +239,50 @@ test("Pushing to the hasMany reflects the change on the belongsTo side - model i /* Local edits */ -testInDebug("Pushing a an object that does not implement the mixin to the mixin accepting array errors out - model injections true", function(assert) { - setupModelFactoryInjections(); +testInDebug( + 'Pushing a an object that does not implement the mixin to the mixin accepting array errors out - model injections true', + function(assert) { + setupModelFactoryInjections(); - try { - var user,notMessage; - run(function() { - store.push({ - data: [{ - type: 'user', - id: '1', - attributes: { - name: 'Stanley' - }, - relationships: { - messages: { - data: [] - } - } - }, { - type: 'not-message', - id: '2', - attributes: { - video: 'Here comes Youtube' - } - }] + try { + var user, notMessage; + run(function() { + store.push({ + data: [ + { + type: 'user', + id: '1', + attributes: { + name: 'Stanley', + }, + relationships: { + messages: { + data: [], + }, + }, + }, + { + type: 'not-message', + id: '2', + attributes: { + video: 'Here comes Youtube', + }, + }, + ], + }); + user = store.peekRecord('user', 1); + notMessage = store.peekRecord('not-message', 2); }); - user = store.peekRecord('user', 1); - notMessage = store.peekRecord('not-message', 2); - }); - run(function() { - user.get('messages').then(function(fetchedMessages) { - assert.expectAssertion(function() { - fetchedMessages.pushObject(notMessage); - }, /You cannot add a record of modelClass 'not-message' to the 'user.messages' relationship \(only 'message' allowed\)/); + run(function() { + user.get('messages').then(function(fetchedMessages) { + assert.expectAssertion(function() { + fetchedMessages.pushObject(notMessage); + }, /You cannot add a record of modelClass 'not-message' to the 'user.messages' relationship \(only 'message' allowed\)/); + }); }); - }); - } finally { - resetModelFactoryInjections(); + } finally { + resetModelFactoryInjections(); + } } -}); +); diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index ee33f3b76a9..ba87ab65165 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -8,69 +8,80 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; -var HomePlanet, SuperVillain, CommanderVillain, NormalMinion, EvilMinion, YellowMinion, RedMinion, - SecretLab, SecretWeapon, BatCave, Comment, env, LightSaber; - -module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { +var HomePlanet, + SuperVillain, + CommanderVillain, + NormalMinion, + EvilMinion, + YellowMinion, + RedMinion, + SecretLab, + SecretWeapon, + BatCave, + Comment, + env, + LightSaber; + +module('integration/embedded_records_mixin - EmbeddedRecordsMixin', { beforeEach() { SuperVillain = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - homePlanet: DS.belongsTo('home-planet', { inverse: 'villains', async: true }), - secretLab: DS.belongsTo('secret-lab', { async: false }), - secretWeapons: DS.hasMany('secret-weapon', { async: false }), - evilMinions: DS.hasMany('evil-minion', { async: false }) + firstName: DS.attr('string'), + lastName: DS.attr('string'), + homePlanet: DS.belongsTo('home-planet', { inverse: 'villains', async: true }), + secretLab: DS.belongsTo('secret-lab', { async: false }), + secretWeapons: DS.hasMany('secret-weapon', { async: false }), + evilMinions: DS.hasMany('evil-minion', { async: false }), }); HomePlanet = DS.Model.extend({ - name: DS.attr('string'), - villains: DS.hasMany('super-villain', { inverse: 'homePlanet', async: false }) + name: DS.attr('string'), + villains: DS.hasMany('super-villain', { inverse: 'homePlanet', async: false }), }); SecretLab = DS.Model.extend({ - minionCapacity: DS.attr('number'), - vicinity: DS.attr('string'), - superVillain: DS.belongsTo('super-villain', { async: false }) + minionCapacity: DS.attr('number'), + vicinity: DS.attr('string'), + superVillain: DS.belongsTo('super-villain', { async: false }), }); BatCave = SecretLab.extend({ - infiltrated: DS.attr('boolean') + infiltrated: DS.attr('boolean'), }); SecretWeapon = DS.Model.extend({ - name: DS.attr('string'), - superVillain: DS.belongsTo('super-villain', { async: false }) + name: DS.attr('string'), + superVillain: DS.belongsTo('super-villain', { async: false }), }); LightSaber = SecretWeapon.extend({ - color: DS.attr('string') + color: DS.attr('string'), }); EvilMinion = DS.Model.extend({ - superVillain: DS.belongsTo('super-villain', { async: false }), - name: DS.attr('string') + superVillain: DS.belongsTo('super-villain', { async: false }), + name: DS.attr('string'), }); NormalMinion = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); YellowMinion = NormalMinion.extend(); RedMinion = NormalMinion.extend(); CommanderVillain = DS.Model.extend({ name: DS.attr('string'), - minions: DS.hasMany('normal-minion', { polymorphic: true }) + minions: DS.hasMany('normal-minion', { polymorphic: true }), }); Comment = DS.Model.extend({ - body: DS.attr('string'), - root: DS.attr('boolean'), - children: DS.hasMany('comment', { inverse: null, async: false }) + body: DS.attr('string'), + root: DS.attr('boolean'), + children: DS.hasMany('comment', { inverse: null, async: false }), }); env = setupStore({ - superVillain: SuperVillain, + superVillain: SuperVillain, commanderVillain: CommanderVillain, - homePlanet: HomePlanet, - secretLab: SecretLab, - batCave: BatCave, - secretWeapon: SecretWeapon, - lightSaber: LightSaber, - evilMinion: EvilMinion, - normalMinion: NormalMinion, - yellowMinion: YellowMinion, - redMinion: RedMinion, - comment: Comment + homePlanet: HomePlanet, + secretLab: SecretLab, + batCave: BatCave, + secretWeapon: SecretWeapon, + lightSaber: LightSaber, + evilMinion: EvilMinion, + normalMinion: NormalMinion, + yellowMinion: YellowMinion, + redMinion: RedMinion, + comment: Comment, }); env.store.modelFor('super-villain'); env.store.modelFor('commander-villain'); @@ -83,7 +94,10 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { env.store.modelFor('comment'); env.registry.register('adapter:application', DS.RESTAdapter); - env.registry.register('serializer:application', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin)); + env.registry.register( + 'serializer:application', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin) + ); //env.amsSerializer = env.container.lookup("serializer:-active-model"); //env.amsAdapter = env.container.lookup("adapter:-active-model"); @@ -91,27 +105,32 @@ module("integration/embedded_records_mixin - EmbeddedRecordsMixin", { afterEach() { run(env.store, 'destroy'); - } + }, }); -test("normalizeResponse with embedded objects", function(assert) { - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' } - } - })); +test('normalizeResponse with embedded objects', function(assert) { + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); - var serializer = env.store.serializerFor("home-planet"); + var serializer = env.store.serializerFor('home-planet'); var json_hash = { homePlanet: { - id: "1", - name: "Umber", - villains: [{ - id: "2", - firstName: "Tom", - lastName: "Dale" - }] - } + id: '1', + name: 'Umber', + villains: [ + { + id: '2', + firstName: 'Tom', + lastName: 'Dale', + }, + ], + }, }; var json; @@ -120,61 +139,69 @@ test("normalizeResponse with embedded objects", function(assert) { }); assert.deepEqual(json, { - "data": { - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "villains": { - "data": [ - { "id": "2", "type": "super-villain" } - ] - } - } + data: { + id: '1', + type: 'home-planet', + attributes: { + name: 'Umber', + }, + relationships: { + villains: { + data: [{ id: '2', type: 'super-villain' }], + }, + }, }, - "included": [ + included: [ { - "id": "2", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" + id: '2', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale', }, - "relationships": {} - } - ] + relationships: {}, + }, + ], }); }); -test("normalizeResponse with embedded objects inside embedded objects", function(assert) { - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' } - } - })); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - evilMinions: { embedded: 'always' } - } - })); - - var serializer = env.store.serializerFor("home-planet"); +test('normalizeResponse with embedded objects inside embedded objects', function(assert) { + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + evilMinions: { embedded: 'always' }, + }, + }) + ); + + var serializer = env.store.serializerFor('home-planet'); var json_hash = { homePlanet: { - id: "1", - name: "Umber", - villains: [{ - id: "2", - firstName: "Tom", - lastName: "Dale", - evilMinions: [{ - id: "3", - name: "Alex" - }] - }] - } + id: '1', + name: 'Umber', + villains: [ + { + id: '2', + firstName: 'Tom', + lastName: 'Dale', + evilMinions: [ + { + id: '3', + name: 'Alex', + }, + ], + }, + ], + }, }; var json; @@ -183,308 +210,347 @@ test("normalizeResponse with embedded objects inside embedded objects", function }); assert.deepEqual(json, { - "data": { - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "villains": { - "data": [ - { "id": "2", "type": "super-villain" } - ] - } - } + data: { + id: '1', + type: 'home-planet', + attributes: { + name: 'Umber', + }, + relationships: { + villains: { + data: [{ id: '2', type: 'super-villain' }], + }, + }, }, - "included": [{ - "id": "2", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": { - "evilMinions": { - "data": [ - { "id": "3", "type": "evil-minion" } - ] - } - } - }, { - "id": "3", - "type": "evil-minion", - "attributes": { - "name": "Alex" + included: [ + { + id: '2', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale', + }, + relationships: { + evilMinions: { + data: [{ id: '3', type: 'evil-minion' }], + }, + }, + }, + { + id: '3', + type: 'evil-minion', + attributes: { + name: 'Alex', + }, + relationships: {}, }, - "relationships": {} - }] + ], }); }); -test("normalizeResponse with embedded objects of same type", function(assert) { - env.registry.register('serializer:comment', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - children: { embedded: 'always' } - } - })); +test('normalizeResponse with embedded objects of same type', function(assert) { + env.registry.register( + 'serializer:comment', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + children: { embedded: 'always' }, + }, + }) + ); - var serializer = env.store.serializerFor("comment"); + var serializer = env.store.serializerFor('comment'); var json_hash = { comment: { - id: "1", - body: "Hello", + id: '1', + body: 'Hello', root: true, - children: [{ - id: "2", - body: "World", - root: false - }, { - id: "3", - body: "Foo", - root: false - }] - } + children: [ + { + id: '2', + body: 'World', + root: false, + }, + { + id: '3', + body: 'Foo', + root: false, + }, + ], + }, }; var json; run(function() { json = serializer.normalizeResponse(env.store, Comment, json_hash, '1', 'findRecord'); }); - assert.deepEqual(json, { - "data": { - "id": "1", - "type": "comment", - "attributes": { - "body": "Hello", - "root": true - }, - "relationships": { - "children": { - "data": [ - { "id": "2", "type": "comment" }, - { "id": "3", "type": "comment" } - ] - } - } + assert.deepEqual( + json, + { + data: { + id: '1', + type: 'comment', + attributes: { + body: 'Hello', + root: true, + }, + relationships: { + children: { + data: [{ id: '2', type: 'comment' }, { id: '3', type: 'comment' }], + }, + }, + }, + included: [ + { + id: '2', + type: 'comment', + attributes: { + body: 'World', + root: false, + }, + relationships: {}, + }, + { + id: '3', + type: 'comment', + attributes: { + body: 'Foo', + root: false, + }, + relationships: {}, + }, + ], }, - "included": [{ - "id": "2", - "type": "comment", - "attributes": { - "body": "World", - "root": false - }, - "relationships": {} - }, { - "id": "3", - "type": "comment", - "attributes": { - "body": "Foo", - "root": false - }, - "relationships": {} - }] - }, "Primary record was correct"); + 'Primary record was correct' + ); }); -test("normalizeResponse with embedded objects inside embedded objects of same type", function(assert) { - env.registry.register('serializer:comment', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - children: { embedded: 'always' } - } - })); +test('normalizeResponse with embedded objects inside embedded objects of same type', function(assert) { + env.registry.register( + 'serializer:comment', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + children: { embedded: 'always' }, + }, + }) + ); - var serializer = env.store.serializerFor("comment"); + var serializer = env.store.serializerFor('comment'); var json_hash = { comment: { - id: "1", - body: "Hello", + id: '1', + body: 'Hello', root: true, - children: [{ - id: "2", - body: "World", - root: false, - children: [{ - id: "4", - body: "Another", - root: false - }] - }, { - id: "3", - body: "Foo", - root: false - }] - } + children: [ + { + id: '2', + body: 'World', + root: false, + children: [ + { + id: '4', + body: 'Another', + root: false, + }, + ], + }, + { + id: '3', + body: 'Foo', + root: false, + }, + ], + }, }; var json; run(function() { json = serializer.normalizeResponse(env.store, Comment, json_hash, '1', 'findRecord'); }); - assert.deepEqual(json, { - "data": { - "id": "1", - "type": "comment", - "attributes": { - "body": "Hello", - "root": true - }, - "relationships": { - "children": { - "data": [ - { "id": "2", "type": "comment" }, - { "id": "3", "type": "comment" } - ] - } - } + assert.deepEqual( + json, + { + data: { + id: '1', + type: 'comment', + attributes: { + body: 'Hello', + root: true, + }, + relationships: { + children: { + data: [{ id: '2', type: 'comment' }, { id: '3', type: 'comment' }], + }, + }, + }, + included: [ + { + id: '2', + type: 'comment', + attributes: { + body: 'World', + root: false, + }, + relationships: { + children: { + data: [{ id: '4', type: 'comment' }], + }, + }, + }, + { + id: '4', + type: 'comment', + attributes: { + body: 'Another', + root: false, + }, + relationships: {}, + }, + { + id: '3', + type: 'comment', + attributes: { + body: 'Foo', + root: false, + }, + relationships: {}, + }, + ], }, - "included": [{ - "id": "2", - "type": "comment", - "attributes": { - "body": "World", - "root": false - }, - "relationships": { - "children": { - "data": [ - { "id": "4", "type": "comment" } - ] - } - } - }, { - "id": "4", - "type": "comment", - "attributes": { - "body": "Another", - "root": false - }, - "relationships": {} - }, { - "id": "3", - "type": "comment", - "attributes": { - "body": "Foo", - "root": false - }, - "relationships": {} - }] - }, "Primary record was correct"); + 'Primary record was correct' + ); }); -test("normalizeResponse with embedded objects of same type, but from separate attributes", function(assert) { +test('normalizeResponse with embedded objects of same type, but from separate attributes', function(assert) { HomePlanet.reopen({ - reformedVillains: DS.hasMany('superVillain', { inverse: null, async: false }) + reformedVillains: DS.hasMany('superVillain', { inverse: null, async: false }), }); - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' }, - reformedVillains: { embedded: 'always' } - } - })); + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + reformedVillains: { embedded: 'always' }, + }, + }) + ); - var serializer = env.store.serializerFor("home-planet"); + var serializer = env.store.serializerFor('home-planet'); var json_hash = { homePlanet: { - id: "1", - name: "Earth", - villains: [{ - id: "1", - firstName: "Tom" - }, { - id: "3", - firstName: "Yehuda" - }], - reformedVillains: [{ - id: "2", - firstName: "Alex" - },{ - id: "4", - firstName: "Erik" - }] - } + id: '1', + name: 'Earth', + villains: [ + { + id: '1', + firstName: 'Tom', + }, + { + id: '3', + firstName: 'Yehuda', + }, + ], + reformedVillains: [ + { + id: '2', + firstName: 'Alex', + }, + { + id: '4', + firstName: 'Erik', + }, + ], + }, }; var json; run(function() { json = serializer.normalizeResponse(env.store, HomePlanet, json_hash, '1', 'findRecord'); }); - assert.deepEqual(json, { - "data": { - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Earth" - }, - "relationships": { - "villains": { - "data": [ - { "id": "1", "type": "super-villain" }, - { "id": "3", "type": "super-villain" } - ] - }, - "reformedVillains": { - "data": [ - { "id": "2", "type": "super-villain" }, - { "id": "4", "type": "super-villain" } - ] - } - } + assert.deepEqual( + json, + { + data: { + id: '1', + type: 'home-planet', + attributes: { + name: 'Earth', + }, + relationships: { + villains: { + data: [{ id: '1', type: 'super-villain' }, { id: '3', type: 'super-villain' }], + }, + reformedVillains: { + data: [{ id: '2', type: 'super-villain' }, { id: '4', type: 'super-villain' }], + }, + }, + }, + included: [ + { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + }, + relationships: {}, + }, + { + id: '3', + type: 'super-villain', + attributes: { + firstName: 'Yehuda', + }, + relationships: {}, + }, + { + id: '2', + type: 'super-villain', + attributes: { + firstName: 'Alex', + }, + relationships: {}, + }, + { + id: '4', + type: 'super-villain', + attributes: { + firstName: 'Erik', + }, + relationships: {}, + }, + ], }, - "included": [{ - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom" - }, - "relationships": {} - }, { - "id": "3", - "type": "super-villain", - "attributes": { - "firstName": "Yehuda" - }, - "relationships": {} - }, { - "id": "2", - "type": "super-villain", - "attributes": { - "firstName": "Alex" - }, - "relationships": {} - }, { - "id": "4", - "type": "super-villain", - "attributes": { - "firstName": "Erik" - }, - "relationships": {} - }] - }, "Primary hash was correct"); + 'Primary hash was correct' + ); }); -test("normalizeResponse with embedded objects", function(assert) { - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' } - } - })); +test('normalizeResponse with embedded objects', function(assert) { + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); - var serializer = env.store.serializerFor("home-planet"); + var serializer = env.store.serializerFor('home-planet'); var json_hash = { - homePlanets: [{ - id: "1", - name: "Umber", - villains: [{ - id: "1", - firstName: "Tom", - lastName: "Dale" - }] - }] + homePlanets: [ + { + id: '1', + name: 'Umber', + villains: [ + { + id: '1', + firstName: 'Tom', + lastName: 'Dale', + }, + ], + }, + ], }; var array; @@ -493,55 +559,67 @@ test("normalizeResponse with embedded objects", function(assert) { }); assert.deepEqual(array, { - "data": [{ - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "villains": { - "data": [ - { "id": "1", "type": "super-villain" } - ] - } - } - }], - "included": [{ - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" + data: [ + { + id: '1', + type: 'home-planet', + attributes: { + name: 'Umber', + }, + relationships: { + villains: { + data: [{ id: '1', type: 'super-villain' }], + }, + }, + }, + ], + included: [ + { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale', + }, + relationships: {}, }, - "relationships": {} - }] + ], }); }); -test("normalizeResponse with embedded objects with custom primary key", function(assert) { +test('normalizeResponse with embedded objects with custom primary key', function(assert) { assert.expect(1); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend({ - primaryKey: 'villain_id' - })); - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' } - } - })); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend({ + primaryKey: 'villain_id', + }) + ); + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); - var serializer = env.store.serializerFor("home-planet"); + var serializer = env.store.serializerFor('home-planet'); var json_hash = { - homePlanets: [{ - id: "1", - name: "Umber", - villains: [{ - villain_id: "2", - firstName: "Alex", - lastName: "Baizeau" - }] - }] + homePlanets: [ + { + id: '1', + name: 'Umber', + villains: [ + { + villain_id: '2', + firstName: 'Alex', + lastName: 'Baizeau', + }, + ], + }, + ], }; var array; @@ -550,56 +628,65 @@ test("normalizeResponse with embedded objects with custom primary key", function }); assert.deepEqual(array, { - "data": [{ - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "villains": { - "data": [ - { "id": "2", "type": "super-villain" } - ] - } - } - }], - "included": [{ - "id": "2", - "type": "super-villain", - "attributes": { - "firstName": "Alex", - "lastName": "Baizeau" + data: [ + { + id: '1', + type: 'home-planet', + attributes: { + name: 'Umber', + }, + relationships: { + villains: { + data: [{ id: '2', type: 'super-villain' }], + }, + }, + }, + ], + included: [ + { + id: '2', + type: 'super-villain', + attributes: { + firstName: 'Alex', + lastName: 'Baizeau', + }, + relationships: {}, }, - "relationships": {} - }] + ], }); }); -test("normalizeResponse with embedded objects with identical relationship and attribute key ", function(assert) { +test('normalizeResponse with embedded objects with identical relationship and attribute key ', function(assert) { assert.expect(1); - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' } - }, - //Makes the keyForRelationship and keyForAttribute collide. - keyForRelationship(key, type) { - return this.keyForAttribute(key, type); - } - })); + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + //Makes the keyForRelationship and keyForAttribute collide. + keyForRelationship(key, type) { + return this.keyForAttribute(key, type); + }, + }) + ); - var serializer = env.store.serializerFor("home-planet"); + var serializer = env.store.serializerFor('home-planet'); var json_hash = { - homePlanets: [{ - id: "1", - name: "Umber", - villains: [{ - id: "1", - firstName: "Alex", - lastName: "Baizeau" - }] - }] + homePlanets: [ + { + id: '1', + name: 'Umber', + villains: [ + { + id: '1', + firstName: 'Alex', + lastName: 'Baizeau', + }, + ], + }, + ], }; var array; @@ -608,56 +695,66 @@ test("normalizeResponse with embedded objects with identical relationship and at }); assert.deepEqual(array, { - "data": [{ - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "villains": { - "data": [ - { "id": "1", "type": "super-villain" } - ] - } - } - }], - "included": [{ - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Alex", - "lastName": "Baizeau" + data: [ + { + id: '1', + type: 'home-planet', + attributes: { + name: 'Umber', + }, + relationships: { + villains: { + data: [{ id: '1', type: 'super-villain' }], + }, + }, + }, + ], + included: [ + { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Alex', + lastName: 'Baizeau', + }, + relationships: {}, }, - "relationships": {} - }] + ], }); }); -test("normalizeResponse with embedded objects of same type as primary type", function(assert) { - env.registry.register('serializer:comment', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - children: { embedded: 'always' } - } - })); +test('normalizeResponse with embedded objects of same type as primary type', function(assert) { + env.registry.register( + 'serializer:comment', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + children: { embedded: 'always' }, + }, + }) + ); - var serializer = env.store.serializerFor("comment"); + var serializer = env.store.serializerFor('comment'); var json_hash = { - comments: [{ - id: "1", - body: "Hello", - root: true, - children: [{ - id: "2", - body: "World", - root: false - }, { - id: "3", - body: "Foo", - root: false - }] - }] + comments: [ + { + id: '1', + body: 'Hello', + root: true, + children: [ + { + id: '2', + body: 'World', + root: false, + }, + { + id: '3', + body: 'Foo', + root: false, + }, + ], + }, + ], }; var array; @@ -665,92 +762,116 @@ test("normalizeResponse with embedded objects of same type as primary type", fun array = serializer.normalizeResponse(env.store, Comment, json_hash, null, 'findAll'); }); - assert.deepEqual(array, { - "data": [{ - "id": "1", - "type": "comment", - "attributes": { - "body": "Hello", - "root": true - }, - "relationships": { - "children": { - "data": [ - { "id": "2", "type": "comment" }, - { "id": "3", "type": "comment" } - ] - } - } - }], - "included": [{ - "id": "2", - "type": "comment", - "attributes": { - "body": "World", - "root": false - }, - "relationships": {} - }, { - "id": "3", - "type": "comment", - "attributes": { - "body": "Foo", - "root": false - }, - "relationships": {} - }] - }, "Primary array is correct"); + assert.deepEqual( + array, + { + data: [ + { + id: '1', + type: 'comment', + attributes: { + body: 'Hello', + root: true, + }, + relationships: { + children: { + data: [{ id: '2', type: 'comment' }, { id: '3', type: 'comment' }], + }, + }, + }, + ], + included: [ + { + id: '2', + type: 'comment', + attributes: { + body: 'World', + root: false, + }, + relationships: {}, + }, + { + id: '3', + type: 'comment', + attributes: { + body: 'Foo', + root: false, + }, + relationships: {}, + }, + ], + }, + 'Primary array is correct' + ); }); -test("normalizeResponse with embedded objects of same type, but from separate attributes", function(assert) { +test('normalizeResponse with embedded objects of same type, but from separate attributes', function(assert) { HomePlanet.reopen({ - reformedVillains: DS.hasMany('superVillain', { async: false }) + reformedVillains: DS.hasMany('superVillain', { async: false }), }); - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' }, - reformedVillains: { embedded: 'always' } - } - })); + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + reformedVillains: { embedded: 'always' }, + }, + }) + ); - var serializer = env.store.serializerFor("home-planet"); + var serializer = env.store.serializerFor('home-planet'); var json_hash = { - homePlanets: [{ - id: "1", - name: "Earth", - villains: [{ - id: "1", - firstName: "Tom" - },{ - id: "3", - firstName: "Yehuda" - }], - reformedVillains: [{ - id: "2", - firstName: "Alex" - },{ - id: "4", - firstName: "Erik" - }] - },{ - id: "2", - name: "Mars", - villains: [{ - id: "1", - firstName: "Tom" - },{ - id: "3", - firstName: "Yehuda" - }], - reformedVillains: [{ - id: "5", - firstName: "Peter" - },{ - id: "6", - firstName: "Trek" - }] - }] + homePlanets: [ + { + id: '1', + name: 'Earth', + villains: [ + { + id: '1', + firstName: 'Tom', + }, + { + id: '3', + firstName: 'Yehuda', + }, + ], + reformedVillains: [ + { + id: '2', + firstName: 'Alex', + }, + { + id: '4', + firstName: 'Erik', + }, + ], + }, + { + id: '2', + name: 'Mars', + villains: [ + { + id: '1', + firstName: 'Tom', + }, + { + id: '3', + firstName: 'Yehuda', + }, + ], + reformedVillains: [ + { + id: '5', + firstName: 'Peter', + }, + { + id: '6', + firstName: 'Trek', + }, + ], + }, + ], }; var json; @@ -758,191 +879,222 @@ test("normalizeResponse with embedded objects of same type, but from separate at json = serializer.normalizeResponse(env.store, HomePlanet, json_hash, null, 'findAll'); }); - assert.deepEqual(json, { - "data": [{ - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Earth" - }, - "relationships": { - "reformedVillains": { - "data": [ - { "id": "2", "type": "super-villain" }, - { "id": "4", "type": "super-villain" } - ] - }, - "villains": { - "data": [ - { "id": "1", "type": "super-villain" }, - { "id": "3", "type": "super-villain" } - ] - } - } - }, { - "id": "2", - "type": "home-planet", - "attributes": { - "name": "Mars" - }, - "relationships": { - "reformedVillains": { - "data": [ - { "id": "5", "type": "super-villain" }, - { "id": "6", "type": "super-villain" } - ] - }, - "villains": { - "data": [ - { "id": "1", "type": "super-villain" }, - { "id": "3", "type": "super-villain" } - ] - } - } - }], - "included": [{ - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom" - }, - "relationships": {} - }, { - "id": "3", - "type": "super-villain", - "attributes": { - "firstName": "Yehuda" - }, - "relationships": {} - }, { - "id": "2", - "type": "super-villain", - "attributes": { - "firstName": "Alex" - }, - "relationships": {} - }, { - "id": "4", - "type": "super-villain", - "attributes": { - "firstName": "Erik" - }, - "relationships": {} - }, { - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom" - }, - "relationships": {} - }, { - "id": "3", - "type": "super-villain", - "attributes": { - "firstName": "Yehuda" - }, - "relationships": {} - }, { - "id": "5", - "type": "super-villain", - "attributes": { - "firstName": "Peter" - }, - "relationships": {} - }, { - "id": "6", - "type": "super-villain", - "attributes": { - "firstName": "Trek" - }, - "relationships": {} - }] - }, "Primary array was correct"); + assert.deepEqual( + json, + { + data: [ + { + id: '1', + type: 'home-planet', + attributes: { + name: 'Earth', + }, + relationships: { + reformedVillains: { + data: [{ id: '2', type: 'super-villain' }, { id: '4', type: 'super-villain' }], + }, + villains: { + data: [{ id: '1', type: 'super-villain' }, { id: '3', type: 'super-villain' }], + }, + }, + }, + { + id: '2', + type: 'home-planet', + attributes: { + name: 'Mars', + }, + relationships: { + reformedVillains: { + data: [{ id: '5', type: 'super-villain' }, { id: '6', type: 'super-villain' }], + }, + villains: { + data: [{ id: '1', type: 'super-villain' }, { id: '3', type: 'super-villain' }], + }, + }, + }, + ], + included: [ + { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + }, + relationships: {}, + }, + { + id: '3', + type: 'super-villain', + attributes: { + firstName: 'Yehuda', + }, + relationships: {}, + }, + { + id: '2', + type: 'super-villain', + attributes: { + firstName: 'Alex', + }, + relationships: {}, + }, + { + id: '4', + type: 'super-villain', + attributes: { + firstName: 'Erik', + }, + relationships: {}, + }, + { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + }, + relationships: {}, + }, + { + id: '3', + type: 'super-villain', + attributes: { + firstName: 'Yehuda', + }, + relationships: {}, + }, + { + id: '5', + type: 'super-villain', + attributes: { + firstName: 'Peter', + }, + relationships: {}, + }, + { + id: '6', + type: 'super-villain', + attributes: { + firstName: 'Trek', + }, + relationships: {}, + }, + ], + }, + 'Primary array was correct' + ); }); -test("serialize supports serialize:false on non-relationship properties", function(assert) { - let tom = env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", id: '1' }); +test('serialize supports serialize:false on non-relationship properties', function(assert) { + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + }); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - firstName: { serialize: false } - } - })); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + firstName: { serialize: false }, + }, + }) + ); var serializer, json; run(function() { - serializer = env.store.serializerFor("super-villain"); + serializer = env.store.serializerFor('super-villain'); json = serializer.serialize(tom._createSnapshot()); }); assert.deepEqual(json, { - lastName: "Dale", + lastName: 'Dale', homePlanet: null, - secretLab: null + secretLab: null, }); }); -test("serialize with embedded objects (hasMany relationship)", function(assert) { - let league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); - let tom = env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); +test('serialize with embedded objects (hasMany relationship)', function(assert) { + let league = env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }); + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: league, + id: '1', + }); - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' } - } - })); + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); var serializer, json; run(function() { - serializer = env.store.serializerFor("home-planet"); + serializer = env.store.serializerFor('home-planet'); json = serializer.serialize(league._createSnapshot()); }); assert.deepEqual(json, { - name: "Villain League", - villains: [{ - id: get(tom, "id"), - firstName: "Tom", - lastName: "Dale", - homePlanet: get(league, "id"), - secretLab: null - }] + name: 'Villain League', + villains: [ + { + id: get(tom, 'id'), + firstName: 'Tom', + lastName: 'Dale', + homePlanet: get(league, 'id'), + secretLab: null, + }, + ], }); }); -test("serialize with embedded objects and a custom keyForAttribute (hasMany relationship)", function(assert) { - let league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); - let tom = env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); +test('serialize with embedded objects and a custom keyForAttribute (hasMany relationship)', function(assert) { + let league = env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }); + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: league, + id: '1', + }); - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - keyForRelationship(key) { - return key + '-custom'; - }, - attrs: { - villains: { embedded: 'always' } - } - })); + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + keyForRelationship(key) { + return key + '-custom'; + }, + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); var serializer, json; run(function() { - serializer = env.store.serializerFor("home-planet"); + serializer = env.store.serializerFor('home-planet'); json = serializer.serialize(league._createSnapshot()); }); assert.deepEqual(json, { - "name": "Villain League", - "villains-custom": [{ - id: get(tom, "id"), - firstName: "Tom", - lastName: "Dale", - homePlanet: get(league, "id"), - secretLab: null - }] + name: 'Villain League', + 'villains-custom': [ + { + id: get(tom, 'id'), + firstName: 'Tom', + lastName: 'Dale', + homePlanet: get(league, 'id'), + secretLab: null, + }, + ], }); }); -testInDebug("serialize with embedded objects (unknown hasMany relationship)", function(assert) { +testInDebug('serialize with embedded objects (unknown hasMany relationship)', function(assert) { var league; run(function() { env.store.push({ @@ -950,623 +1102,761 @@ testInDebug("serialize with embedded objects (unknown hasMany relationship)", fu type: 'home-planet', id: '123', attributes: { - name: "Villain League" - } - } + name: 'Villain League', + }, + }, }); league = env.store.peekRecord('home-planet', 123); }); - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' } - } - })); + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); var serializer, json; assert.expectWarning(function() { run(function() { - serializer = env.store.serializerFor("home-planet"); + serializer = env.store.serializerFor('home-planet'); json = serializer.serialize(league._createSnapshot()); }); }, /The embedded relationship 'villains' is undefined for 'home-planet' with id '123'. Please include it in your original payload./); assert.deepEqual(json, { - name: "Villain League", - villains: [] + name: 'Villain League', + villains: [], }); }); -test("serialize with embedded objects (hasMany relationship) supports serialize:false", function(assert) { - let league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); - env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league, id: '1' }); +test('serialize with embedded objects (hasMany relationship) supports serialize:false', function(assert) { + let league = env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }); + env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: league, + id: '1', + }); - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { serialize: false } - } - })); + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { serialize: false }, + }, + }) + ); var serializer, json; run(function() { - serializer = env.store.serializerFor("home-planet"); + serializer = env.store.serializerFor('home-planet'); json = serializer.serialize(league._createSnapshot()); }); assert.deepEqual(json, { - name: "Villain League" + name: 'Villain League', }); }); -test("serialize with (new) embedded objects (hasMany relationship)", function(assert) { - let league = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); - env.store.createRecord('super-villain', { firstName: "Tom", lastName: "Dale", homePlanet: league }); +test('serialize with (new) embedded objects (hasMany relationship)', function(assert) { + let league = env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }); + env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: league, + }); - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' } - } - })); + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); var serializer, json; run(function() { - serializer = env.store.serializerFor("home-planet"); + serializer = env.store.serializerFor('home-planet'); json = serializer.serialize(league._createSnapshot()); }); assert.deepEqual(json, { - name: "Villain League", - villains: [{ - firstName: "Tom", - lastName: "Dale", - homePlanet: get(league, "id"), - secretLab: null - }] + name: 'Villain League', + villains: [ + { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: get(league, 'id'), + secretLab: null, + }, + ], }); }); -test("serialize with embedded objects (hasMany relationships, including related objects not embedded)", function(assert) { - let superVillain = env.store.createRecord('super-villain', { id: 1, firstName: "Super", lastName: "Villian" }); - let evilMinion = env.store.createRecord('evil-minion', { id: 1, name: "Evil Minion", superVillian: superVillain }); - let secretWeapon = env.store.createRecord('secret-weapon', { id: 1, name: "Secret Weapon", superVillain: superVillain }); +test('serialize with embedded objects (hasMany relationships, including related objects not embedded)', function(assert) { + let superVillain = env.store.createRecord('super-villain', { + id: 1, + firstName: 'Super', + lastName: 'Villian', + }); + let evilMinion = env.store.createRecord('evil-minion', { + id: 1, + name: 'Evil Minion', + superVillian: superVillain, + }); + let secretWeapon = env.store.createRecord('secret-weapon', { + id: 1, + name: 'Secret Weapon', + superVillain: superVillain, + }); run(function() { superVillain.get('evilMinions').pushObject(evilMinion); superVillain.get('secretWeapons').pushObject(secretWeapon); }); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - evilMinions: { serialize: 'records', deserialize: 'records' }, - secretWeapons: { serialize: 'ids' } - } - })); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + evilMinions: { serialize: 'records', deserialize: 'records' }, + secretWeapons: { serialize: 'ids' }, + }, + }) + ); var serializer, json; run(function() { - serializer = env.container.lookup("serializer:super-villain"); + serializer = env.container.lookup('serializer:super-villain'); json = serializer.serialize(superVillain._createSnapshot()); }); assert.deepEqual(json, { - firstName: get(superVillain, "firstName"), - lastName: get(superVillain, "lastName"), + firstName: get(superVillain, 'firstName'), + lastName: get(superVillain, 'lastName'), homePlanet: null, - evilMinions: [{ - id: get(evilMinion, "id"), - name: get(evilMinion, "name"), - superVillain: "1" - }], + evilMinions: [ + { + id: get(evilMinion, 'id'), + name: get(evilMinion, 'name'), + superVillain: '1', + }, + ], secretLab: null, - secretWeapons: ["1"] + secretWeapons: ['1'], }); }); -test("serialize has many relationship using the `ids-and-types` strategy", function(assert) { - let yellowMinion = env.store.createRecord('yellow-minion', { id: 1, name: "Yellowy" }); - let redMinion = env.store.createRecord('red-minion', { id: 1, name: "Reddy" }); - let commanderVillain = env.store.createRecord('commander-villain', { id: 1, name: "Jeff", minions: [yellowMinion, redMinion] }); +test('serialize has many relationship using the `ids-and-types` strategy', function(assert) { + let yellowMinion = env.store.createRecord('yellow-minion', { id: 1, name: 'Yellowy' }); + let redMinion = env.store.createRecord('red-minion', { id: 1, name: 'Reddy' }); + let commanderVillain = env.store.createRecord('commander-villain', { + id: 1, + name: 'Jeff', + minions: [yellowMinion, redMinion], + }); - env.registry.register('serializer:commander-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - minions: { serialize: 'ids-and-types' } - } - })); + env.registry.register( + 'serializer:commander-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + minions: { serialize: 'ids-and-types' }, + }, + }) + ); var serializer, json; run(function() { - serializer = env.container.lookup("serializer:commander-villain"); + serializer = env.container.lookup('serializer:commander-villain'); var snapshot = commanderVillain._createSnapshot(); json = serializer.serialize(snapshot); }); assert.deepEqual(json, { name: 'Jeff', - minions: [{ - id: '1', - type: 'yellow-minion' - }, { - id: '1', - type: 'red-minion' - }] + minions: [ + { + id: '1', + type: 'yellow-minion', + }, + { + id: '1', + type: 'red-minion', + }, + ], }); }); -test("normalizeResponse with embedded object (belongsTo relationship)", function(assert) { - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' } - } - })); +test('normalizeResponse with embedded object (belongsTo relationship)', function(assert) { + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); - var serializer = env.store.serializerFor("super-villain"); + var serializer = env.store.serializerFor('super-villain'); var json_hash = { super_villain: { - id: "1", - firstName: "Tom", - lastName: "Dale", - homePlanet: "123", - evilMinions: ["1", "2", "3"], + id: '1', + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + evilMinions: ['1', '2', '3'], secretLab: { minionCapacity: 5000, - vicinity: "California, USA", - id: "101" + vicinity: 'California, USA', + id: '101', }, - secretWeapons: [] - } + secretWeapons: [], + }, }; let json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); assert.deepEqual(json, { - "data": { - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": { - "evilMinions": { - "data": [ - { "id": "1", "type": "evil-minion" }, - { "id": "2", "type": "evil-minion" }, - { "id": "3", "type": "evil-minion" } - ] - }, - "homePlanet": { - "data": { "id": "123", "type": "home-planet" } - }, - "secretLab": { - "data": { "id": "101", "type": "secret-lab" } - }, - "secretWeapons": { - "data": [] - } - } + data: { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale', + }, + relationships: { + evilMinions: { + data: [ + { id: '1', type: 'evil-minion' }, + { id: '2', type: 'evil-minion' }, + { id: '3', type: 'evil-minion' }, + ], + }, + homePlanet: { + data: { id: '123', type: 'home-planet' }, + }, + secretLab: { + data: { id: '101', type: 'secret-lab' }, + }, + secretWeapons: { + data: [], + }, + }, }, - "included": [{ - "id": "101", - "type": "secret-lab", - "attributes": { - "minionCapacity": 5000, - "vicinity": "California, USA" + included: [ + { + id: '101', + type: 'secret-lab', + attributes: { + minionCapacity: 5000, + vicinity: 'California, USA', + }, + relationships: {}, }, - "relationships": {} - }] + ], }); }); -test("serialize with embedded object (belongsTo relationship)", function(assert) { - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' } - } - })); +test('serialize with embedded object (belongsTo relationship)', function(assert) { + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); // records with an id, persisted - let tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: env.store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); - let json = env.store.serializerFor("super-villain").serialize(tom._createSnapshot()); + let json = env.store.serializerFor('super-villain').serialize(tom._createSnapshot()); assert.deepEqual(json, { - firstName: get(tom, "firstName"), - lastName: get(tom, "lastName"), - homePlanet: get(tom, "homePlanet").get("id"), + firstName: get(tom, 'firstName'), + lastName: get(tom, 'lastName'), + homePlanet: get(tom, 'homePlanet').get('id'), secretLab: { - id: get(tom, "secretLab").get("id"), - minionCapacity: get(tom, "secretLab").get("minionCapacity"), - vicinity: get(tom, "secretLab").get("vicinity") - } + id: get(tom, 'secretLab').get('id'), + minionCapacity: get(tom, 'secretLab').get('minionCapacity'), + vicinity: get(tom, 'secretLab').get('vicinity'), + }, }); }); -test("serialize with embedded object (polymorphic belongsTo relationship)", function(assert) { - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' } - } - })); +test('serialize with embedded object (polymorphic belongsTo relationship)', function(assert) { + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); SuperVillain.reopen({ - secretLab: DS.belongsTo('secret-lab', { polymorphic: true }) + secretLab: DS.belongsTo('secret-lab', { polymorphic: true }), }); - let tom = env.store.createRecord( - 'super-villain', - { - id: "1", - firstName: "Tom", - lastName: "Dale", - secretLab: env.store.createRecord('bat-cave', { - id: "101", - minionCapacity: 5000, - vicinity: "California, USA", - infiltrated: true - }), - homePlanet: env.store.createRecord('home-planet', { - id: "123", - name: "Villain League" - }) - } - ); + let tom = env.store.createRecord('super-villain', { + id: '1', + firstName: 'Tom', + lastName: 'Dale', + secretLab: env.store.createRecord('bat-cave', { + id: '101', + minionCapacity: 5000, + vicinity: 'California, USA', + infiltrated: true, + }), + homePlanet: env.store.createRecord('home-planet', { + id: '123', + name: 'Villain League', + }), + }); let json = tom.serialize(); assert.deepEqual(json, { - firstName: get(tom, "firstName"), - lastName: get(tom, "lastName"), - homePlanet: get(tom, "homePlanet").get("id"), + firstName: get(tom, 'firstName'), + lastName: get(tom, 'lastName'), + homePlanet: get(tom, 'homePlanet').get('id'), secretLabType: 'batCave', secretLab: { - id: get(tom, "secretLab").get("id"), - minionCapacity: get(tom, "secretLab").get("minionCapacity"), - vicinity: get(tom, "secretLab").get("vicinity"), - infiltrated: true - } + id: get(tom, 'secretLab').get('id'), + minionCapacity: get(tom, 'secretLab').get('minionCapacity'), + vicinity: get(tom, 'secretLab').get('vicinity'), + infiltrated: true, + }, }); }); -test("serialize with embedded object (belongsTo relationship) works with different primaryKeys", function(assert) { - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - primaryKey: '_id', - attrs: { - secretLab: { embedded: 'always' } - } - })); - env.registry.register('serializer:secret-lab', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - primaryKey: 'crazy_id' - })); +test('serialize with embedded object (belongsTo relationship) works with different primaryKeys', function(assert) { + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + primaryKey: '_id', + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); + env.registry.register( + 'serializer:secret-lab', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + primaryKey: 'crazy_id', + }) + ); - var serializer = env.store.serializerFor("super-villain"); + var serializer = env.store.serializerFor('super-villain'); // records with an id, persisted - let tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: env.store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { - firstName: get(tom, "firstName"), - lastName: get(tom, "lastName"), - homePlanet: get(tom, "homePlanet").get("id"), + firstName: get(tom, 'firstName'), + lastName: get(tom, 'lastName'), + homePlanet: get(tom, 'homePlanet').get('id'), secretLab: { - crazy_id: get(tom, "secretLab").get("id"), - minionCapacity: get(tom, "secretLab").get("minionCapacity"), - vicinity: get(tom, "secretLab").get("vicinity") - } + crazy_id: get(tom, 'secretLab').get('id'), + minionCapacity: get(tom, 'secretLab').get('minionCapacity'), + vicinity: get(tom, 'secretLab').get('vicinity'), + }, }); }); -test("serialize with embedded object (belongsTo relationship, new no id)", function(assert) { - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' } - } - })); +test('serialize with embedded object (belongsTo relationship, new no id)', function(assert) { + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); - var serializer = env.store.serializerFor("super-villain"); + var serializer = env.store.serializerFor('super-villain'); // records without ids, new - let tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + secretLab: env.store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + }), + homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { - firstName: get(tom, "firstName"), - lastName: get(tom, "lastName"), - homePlanet: get(tom, "homePlanet").get("id"), + firstName: get(tom, 'firstName'), + lastName: get(tom, 'lastName'), + homePlanet: get(tom, 'homePlanet').get('id'), secretLab: { - minionCapacity: get(tom, "secretLab").get("minionCapacity"), - vicinity: get(tom, "secretLab").get("vicinity") - } + minionCapacity: get(tom, 'secretLab').get('minionCapacity'), + vicinity: get(tom, 'secretLab').get('vicinity'), + }, }); }); -test("serialize with embedded object (polymorphic belongsTo relationship) supports serialize:ids", function(assert) { +test('serialize with embedded object (polymorphic belongsTo relationship) supports serialize:ids', function(assert) { SuperVillain.reopen({ - secretLab: DS.belongsTo('secret-lab', { polymorphic: true }) + secretLab: DS.belongsTo('secret-lab', { polymorphic: true }), }); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { serialize: 'ids' } - } - })); - - let tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('bat-cave', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { serialize: 'ids' }, + }, + }) ); + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: env.store.createRecord('bat-cave', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); + let json = tom.serialize(); assert.deepEqual(json, { - firstName: get(tom, "firstName"), - lastName: get(tom, "lastName"), - homePlanet: get(tom, "homePlanet").get("id"), - secretLab: get(tom, "secretLab").get("id"), - secretLabType: 'batCave' + firstName: get(tom, 'firstName'), + lastName: get(tom, 'lastName'), + homePlanet: get(tom, 'homePlanet').get('id'), + secretLab: get(tom, 'secretLab').get('id'), + secretLabType: 'batCave', }); }); -test("serialize with embedded object (belongsTo relationship) supports serialize:id", function(assert) { +test('serialize with embedded object (belongsTo relationship) supports serialize:id', function(assert) { SuperVillain.reopen({ - secretLab: DS.belongsTo('secret-lab', { polymorphic: true }) + secretLab: DS.belongsTo('secret-lab', { polymorphic: true }), }); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { serialize: 'id' } - } - })); - - let tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('bat-cave', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { serialize: 'id' }, + }, + }) ); + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: env.store.createRecord('bat-cave', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); + let json = tom.serialize(); assert.deepEqual(json, { - firstName: get(tom, "firstName"), - lastName: get(tom, "lastName"), - homePlanet: get(tom, "homePlanet").get("id"), - secretLab: get(tom, "secretLab").get("id"), - secretLabType: 'batCave' + firstName: get(tom, 'firstName'), + lastName: get(tom, 'lastName'), + homePlanet: get(tom, 'homePlanet').get('id'), + secretLab: get(tom, 'secretLab').get('id'), + secretLabType: 'batCave', }); }); -test("serialize with embedded object (belongsTo relationship) supports serialize:id in conjunction with deserialize:records", function(assert) { +test('serialize with embedded object (belongsTo relationship) supports serialize:id in conjunction with deserialize:records', function(assert) { SuperVillain.reopen({ - secretLab: DS.belongsTo('secret-lab', { polymorphic: true }) + secretLab: DS.belongsTo('secret-lab', { polymorphic: true }), }); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { serialize: 'id', deserialize: 'records' } - } - })); - - let tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('bat-cave', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { serialize: 'id', deserialize: 'records' }, + }, + }) ); + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: env.store.createRecord('bat-cave', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); + let json = tom.serialize(); assert.deepEqual(json, { - firstName: get(tom, "firstName"), - lastName: get(tom, "lastName"), - homePlanet: get(tom, "homePlanet").get("id"), - secretLab: get(tom, "secretLab").get("id"), - secretLabType: 'batCave' + firstName: get(tom, 'firstName'), + lastName: get(tom, 'lastName'), + homePlanet: get(tom, 'homePlanet').get('id'), + secretLab: get(tom, 'secretLab').get('id'), + secretLabType: 'batCave', }); }); -test("serialize with embedded object (belongsTo relationship) supports serialize:ids", function(assert) { - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { serialize: 'ids' } - } - })); - var serializer = env.store.serializerFor("super-villain"); +test('serialize with embedded object (belongsTo relationship) supports serialize:ids', function(assert) { + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { serialize: 'ids' }, + }, + }) + ); + var serializer = env.store.serializerFor('super-villain'); // records with an id, persisted - let tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: env.store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { - firstName: get(tom, "firstName"), - lastName: get(tom, "lastName"), - homePlanet: get(tom, "homePlanet").get("id"), - secretLab: get(tom, "secretLab").get("id") + firstName: get(tom, 'firstName'), + lastName: get(tom, 'lastName'), + homePlanet: get(tom, 'homePlanet').get('id'), + secretLab: get(tom, 'secretLab').get('id'), }); }); -test("serialize with embedded object (belongsTo relationship) supports serialize:id", function(assert) { - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { serialize: 'id' } - } - })); +test('serialize with embedded object (belongsTo relationship) supports serialize:id', function(assert) { + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { serialize: 'id' }, + }, + }) + ); - var serializer = env.store.serializerFor("super-villain"); + var serializer = env.store.serializerFor('super-villain'); // records with an id, persisted - let tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: env.store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { - firstName: get(tom, "firstName"), - lastName: get(tom, "lastName"), - homePlanet: get(tom, "homePlanet").get("id"), - secretLab: get(tom, "secretLab").get("id") + firstName: get(tom, 'firstName'), + lastName: get(tom, 'lastName'), + homePlanet: get(tom, 'homePlanet').get('id'), + secretLab: get(tom, 'secretLab').get('id'), }); }); -test("serialize with embedded object (belongsTo relationship) supports serialize:id in conjunction with deserialize:records", function(assert) { - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { serialize: 'id', deserialize: 'records' } - } - })); +test('serialize with embedded object (belongsTo relationship) supports serialize:id in conjunction with deserialize:records', function(assert) { + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { serialize: 'id', deserialize: 'records' }, + }, + }) + ); - var serializer = env.store.serializerFor("super-villain"); + var serializer = env.store.serializerFor('super-villain'); // records with an id, persisted - let tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: env.store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { - firstName: get(tom, "firstName"), - lastName: get(tom, "lastName"), - homePlanet: get(tom, "homePlanet").get("id"), - secretLab: get(tom, "secretLab").get("id") + firstName: get(tom, 'firstName'), + lastName: get(tom, 'lastName'), + homePlanet: get(tom, 'homePlanet').get('id'), + secretLab: get(tom, 'secretLab').get('id'), }); }); -test("serialize with embedded object (belongsTo relationship) supports serialize:false", function(assert) { - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { serialize: false } - } - })); - var serializer = env.store.serializerFor("super-villain"); - +test('serialize with embedded object (belongsTo relationship) supports serialize:false', function(assert) { + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { serialize: false }, + }, + }) + ); + var serializer = env.store.serializerFor('super-villain'); // records with an id, persisted - let tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: env.store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { - firstName: get(tom, "firstName"), - lastName: get(tom, "lastName"), - homePlanet: get(tom, "homePlanet").get("id") + firstName: get(tom, 'firstName'), + lastName: get(tom, 'lastName'), + homePlanet: get(tom, 'homePlanet').get('id'), }); }); -test("serialize with embedded object (belongsTo relationship) serializes the id by default if no option specified", function(assert) { - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin)); - var serializer = env.store.serializerFor("super-villain"); +test('serialize with embedded object (belongsTo relationship) serializes the id by default if no option specified', function(assert) { + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin) + ); + var serializer = env.store.serializerFor('super-villain'); // records with an id, persisted - let tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - secretLab: env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }), - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } - ); + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: env.store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { - firstName: get(tom, "firstName"), - lastName: get(tom, "lastName"), - homePlanet: get(tom, "homePlanet").get("id"), - secretLab: get(tom, "secretLab").get("id") + firstName: get(tom, 'firstName'), + lastName: get(tom, 'lastName'), + homePlanet: get(tom, 'homePlanet').get('id'), + secretLab: get(tom, 'secretLab').get('id'), }); }); -test("when related record is not present, serialize embedded record (with a belongsTo relationship) as null", function(assert) { - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' } - } - })); - var serializer = env.store.serializerFor("super-villain"); - let tom = env.store.createRecord( - 'super-villain', - { firstName: "Tom", lastName: "Dale", id: "1", - homePlanet: env.store.createRecord('home-planet', { name: "Villain League", id: "123" }) - } +test('when related record is not present, serialize embedded record (with a belongsTo relationship) as null', function(assert) { + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' }, + }, + }) ); + var serializer = env.store.serializerFor('super-villain'); + let tom = env.store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); let json = serializer.serialize(tom._createSnapshot()); assert.deepEqual(json, { - firstName: get(tom, "firstName"), - lastName: get(tom, "lastName"), - homePlanet: get(tom, "homePlanet").get("id"), - secretLab: null + firstName: get(tom, 'firstName'), + lastName: get(tom, 'lastName'), + homePlanet: get(tom, 'homePlanet').get('id'), + secretLab: null, }); }); -test("normalizeResponse with multiply-nested belongsTo", function(assert) { - env.registry.register('serializer:evil-minion', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - superVillain: { embedded: 'always' } - } - })); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - homePlanet: { embedded: 'always' } - } - })); - - var serializer = env.store.serializerFor("evil-minion"); +test('normalizeResponse with multiply-nested belongsTo', function(assert) { + env.registry.register( + 'serializer:evil-minion', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + superVillain: { embedded: 'always' }, + }, + }) + ); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + homePlanet: { embedded: 'always' }, + }, + }) + ); + + var serializer = env.store.serializerFor('evil-minion'); var json_hash = { evilMinion: { - id: "1", - name: "Alex", + id: '1', + name: 'Alex', superVillain: { - id: "1", - firstName: "Tom", - lastName: "Dale", - evilMinions: ["1"], + id: '1', + firstName: 'Tom', + lastName: 'Dale', + evilMinions: ['1'], homePlanet: { - id: "1", - name: "Umber", - villains: ["1"] - } - } - } + id: '1', + name: 'Umber', + villains: ['1'], + }, + }, + }, }; var json; @@ -1574,84 +1864,90 @@ test("normalizeResponse with multiply-nested belongsTo", function(assert) { json = serializer.normalizeResponse(env.store, EvilMinion, json_hash, '1', 'findRecord'); }); - assert.deepEqual(json, { - "data": { - "id": "1", - "type": "evil-minion", - "attributes": { - "name": "Alex" - }, - "relationships": { - "superVillain": { - "data": { "id": "1", "type": "super-villain" } - } - } + assert.deepEqual( + json, + { + data: { + id: '1', + type: 'evil-minion', + attributes: { + name: 'Alex', + }, + relationships: { + superVillain: { + data: { id: '1', type: 'super-villain' }, + }, + }, + }, + included: [ + { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale', + }, + relationships: { + evilMinions: { + data: [{ id: '1', type: 'evil-minion' }], + }, + homePlanet: { + data: { id: '1', type: 'home-planet' }, + }, + }, + }, + { + id: '1', + type: 'home-planet', + attributes: { + name: 'Umber', + }, + relationships: { + villains: { + data: [{ id: '1', type: 'super-villain' }], + }, + }, + }, + ], }, - "included": [{ - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": { - "evilMinions": { - "data": [ - { "id": "1", "type": "evil-minion" } - ] - }, - "homePlanet": { - "data": { "id": "1", "type": "home-planet" } - } - } - }, { - "id": "1", - "type": "home-planet", - "attributes": { - "name": "Umber" - }, - "relationships": { - "villains": { - "data": [ - { "id": "1", "type": "super-villain" } - ] - } - } - }] - }, "Primary hash was correct"); + 'Primary hash was correct' + ); }); -test("normalizeResponse with polymorphic hasMany", function(assert) { +test('normalizeResponse with polymorphic hasMany', function(assert) { SuperVillain.reopen({ - secretWeapons: DS.hasMany("secretWeapon", { polymorphic: true, async: false }) + secretWeapons: DS.hasMany('secretWeapon', { polymorphic: true, async: false }), }); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretWeapons: { embedded: 'always' } - } - })); - var serializer = env.store.serializerFor("super-villain"); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretWeapons: { embedded: 'always' }, + }, + }) + ); + var serializer = env.store.serializerFor('super-villain'); var json_hash = { super_villain: { - id: "1", - firstName: "Tom", - lastName: "Dale", + id: '1', + firstName: 'Tom', + lastName: 'Dale', secretWeapons: [ { - id: "1", - type: "LightSaber", + id: '1', + type: 'LightSaber', name: "Tom's LightSaber", - color: "Red" + color: 'Red', }, { - id: "1", - type: "SecretWeapon", - name: "The Death Star" - } - ] - } + id: '1', + type: 'SecretWeapon', + name: 'The Death Star', + }, + ], + }, }; var json; @@ -1659,76 +1955,86 @@ test("normalizeResponse with polymorphic hasMany", function(assert) { json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findAll'); }); - assert.deepEqual(json, { - "data": { - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": { - "secretWeapons": { - "data": [ - { "id": "1", "type": "light-saber" }, - { "id": "1", "type": "secret-weapon" } - ] - } - } + assert.deepEqual( + json, + { + data: { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale', + }, + relationships: { + secretWeapons: { + data: [{ id: '1', type: 'light-saber' }, { id: '1', type: 'secret-weapon' }], + }, + }, + }, + included: [ + { + id: '1', + type: 'light-saber', + attributes: { + color: 'Red', + name: "Tom's LightSaber", + }, + relationships: {}, + }, + { + id: '1', + type: 'secret-weapon', + attributes: { + name: 'The Death Star', + }, + relationships: {}, + }, + ], }, - "included": [{ - "id": "1", - "type": "light-saber", - "attributes": { - "color": "Red", - "name": "Tom's LightSaber" - }, - "relationships": {} - }, { - "id": "1", - "type": "secret-weapon", - "attributes": { - "name": "The Death Star" - }, - "relationships": {} - }] - }, "Primary hash was correct"); + 'Primary hash was correct' + ); }); -test("normalizeResponse with polymorphic hasMany and custom primary key", function(assert) { +test('normalizeResponse with polymorphic hasMany and custom primary key', function(assert) { SuperVillain.reopen({ - secretWeapons: DS.hasMany("secretWeapon", { polymorphic: true, async: false }) + secretWeapons: DS.hasMany('secretWeapon', { polymorphic: true, async: false }), }); - env.registry.register('serializer:light-saber', DS.RESTSerializer.extend({ - primaryKey: 'custom' - })); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretWeapons: { embedded: 'always' } - } - })); - var serializer = env.store.serializerFor("super-villain"); + env.registry.register( + 'serializer:light-saber', + DS.RESTSerializer.extend({ + primaryKey: 'custom', + }) + ); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretWeapons: { embedded: 'always' }, + }, + }) + ); + var serializer = env.store.serializerFor('super-villain'); var json_hash = { super_villain: { - id: "1", - firstName: "Tom", - lastName: "Dale", + id: '1', + firstName: 'Tom', + lastName: 'Dale', secretWeapons: [ { - custom: "1", - type: "LightSaber", + custom: '1', + type: 'LightSaber', name: "Tom's LightSaber", - color: "Red" + color: 'Red', }, { - id: "1", - type: "SecretWeapon", - name: "The Death Star" - } - ] - } + id: '1', + type: 'SecretWeapon', + name: 'The Death Star', + }, + ], + }, }; var json; @@ -1736,68 +2042,72 @@ test("normalizeResponse with polymorphic hasMany and custom primary key", functi json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); }); - assert.deepEqual(json, { - "data": { - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "id": "1", - "relationships": { - "secretWeapons": { - "data": [ - { "type": "light-saber", "id": "1" }, - { "type": "secret-weapon", "id": "1" } - ] - } - }, - "type": "super-villain" - }, - "included": [ - { - "attributes": { - "color": "Red", - "name": "Tom's LightSaber" + assert.deepEqual( + json, + { + data: { + attributes: { + firstName: 'Tom', + lastName: 'Dale', + }, + id: '1', + relationships: { + secretWeapons: { + data: [{ type: 'light-saber', id: '1' }, { type: 'secret-weapon', id: '1' }], + }, }, - "id": "1", - "relationships": {}, - "type": "light-saber" + type: 'super-villain', }, - { - "attributes": { - "name": "The Death Star" + included: [ + { + attributes: { + color: 'Red', + name: "Tom's LightSaber", + }, + id: '1', + relationships: {}, + type: 'light-saber', }, - "id": "1", - "relationships": {}, - "type": "secret-weapon" - } - ] - }, "Custom primary key of embedded hasMany is correctly normalized"); + { + attributes: { + name: 'The Death Star', + }, + id: '1', + relationships: {}, + type: 'secret-weapon', + }, + ], + }, + 'Custom primary key of embedded hasMany is correctly normalized' + ); }); -test("normalizeResponse with polymorphic belongsTo", function(assert) { +test('normalizeResponse with polymorphic belongsTo', function(assert) { SuperVillain.reopen({ - secretLab: DS.belongsTo("secretLab", { polymorphic: true, async: true }) + secretLab: DS.belongsTo('secretLab', { polymorphic: true, async: true }), }); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' } - } - })); - var serializer = env.store.serializerFor("super-villain"); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); + var serializer = env.store.serializerFor('super-villain'); var json_hash = { super_villain: { - id: "1", - firstName: "Tom", - lastName: "Dale", + id: '1', + firstName: 'Tom', + lastName: 'Dale', secretLab: { - id: "1", - type: "bat-cave", - infiltrated: true - } - } + id: '1', + type: 'bat-cave', + infiltrated: true, + }, + }, }; var json; @@ -1806,59 +2116,71 @@ test("normalizeResponse with polymorphic belongsTo", function(assert) { json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); }); - assert.deepEqual(json, { - "data": { - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": { - "secretLab": { - "data": { "id": "1", "type": "bat-cave" } - } - } + assert.deepEqual( + json, + { + data: { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale', + }, + relationships: { + secretLab: { + data: { id: '1', type: 'bat-cave' }, + }, + }, + }, + included: [ + { + id: '1', + type: 'bat-cave', + attributes: { + infiltrated: true, + }, + relationships: {}, + }, + ], }, - "included": [{ - "id": "1", - "type": "bat-cave", - "attributes": { - "infiltrated": true - }, - "relationships": {} - }] - }, "Primary has was correct"); + 'Primary has was correct' + ); }); -test("normalizeResponse with polymorphic belongsTo and custom primary key", function(assert) { +test('normalizeResponse with polymorphic belongsTo and custom primary key', function(assert) { assert.expect(1); SuperVillain.reopen({ - secretLab: DS.belongsTo("secretLab", { polymorphic: true, async: true }) + secretLab: DS.belongsTo('secretLab', { polymorphic: true, async: true }), }); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' } - } - })); - env.registry.register('serializer:bat-cave', DS.RESTSerializer.extend({ - primaryKey: 'custom' - })); - var serializer = env.store.serializerFor("super-villain"); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); + env.registry.register( + 'serializer:bat-cave', + DS.RESTSerializer.extend({ + primaryKey: 'custom', + }) + ); + var serializer = env.store.serializerFor('super-villain'); var json_hash = { superVillain: { - id: "1", - firstName: "Tom", - lastName: "Dale", + id: '1', + firstName: 'Tom', + lastName: 'Dale', secretLab: { - custom: "1", - type: "bat-cave", - infiltrated: true - } - } + custom: '1', + type: 'bat-cave', + infiltrated: true, + }, + }, }; var json; @@ -1867,95 +2189,126 @@ test("normalizeResponse with polymorphic belongsTo and custom primary key", func json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); }); - assert.deepEqual(json, { - "data": { - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "id": "1", - "relationships": { - "secretLab": { - "data": { - "id": "1", - "type": "bat-cave" - } - } - }, - "type": "super-villain" - }, - "included": [ - { - "attributes": { - "infiltrated": true + assert.deepEqual( + json, + { + data: { + attributes: { + firstName: 'Tom', + lastName: 'Dale', }, - "id": "1", - "relationships": {}, - "type": "bat-cave" - } - ] - }, "Custom primary key is correctly normalized"); + id: '1', + relationships: { + secretLab: { + data: { + id: '1', + type: 'bat-cave', + }, + }, + }, + type: 'super-villain', + }, + included: [ + { + attributes: { + infiltrated: true, + }, + id: '1', + relationships: {}, + type: 'bat-cave', + }, + ], + }, + 'Custom primary key is correctly normalized' + ); }); -test("Mixin can be used with RESTSerializer which does not define keyForAttribute", function(assert) { - let homePlanet = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); - let secretLab = env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); +test('Mixin can be used with RESTSerializer which does not define keyForAttribute', function(assert) { + let homePlanet = env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }); + let secretLab = env.store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }); let superVillain = env.store.createRecord('super-villain', { - id: "1", firstName: "Super", lastName: "Villian", homePlanet: homePlanet, secretLab: secretLab + id: '1', + firstName: 'Super', + lastName: 'Villian', + homePlanet: homePlanet, + secretLab: secretLab, + }); + let secretWeapon = env.store.createRecord('secret-weapon', { + id: '1', + name: 'Secret Weapon', + superVillain: superVillain, }); - let secretWeapon = env.store.createRecord('secret-weapon', { id: "1", name: "Secret Weapon", superVillain: superVillain }); let evilMinion; run(function() { superVillain.get('secretWeapons').pushObject(secretWeapon); - evilMinion = env.store.createRecord('evil-minion', { id: "1", name: "Evil Minion", superVillian: superVillain }); + evilMinion = env.store.createRecord('evil-minion', { + id: '1', + name: 'Evil Minion', + superVillian: superVillain, + }); superVillain.get('evilMinions').pushObject(evilMinion); }); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - evilMinions: { serialize: 'records', deserialize: 'records' } - } - })); - let serializer = env.store.serializerFor("super-villain"); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + evilMinions: { serialize: 'records', deserialize: 'records' }, + }, + }) + ); + let serializer = env.store.serializerFor('super-villain'); let json = serializer.serialize(superVillain._createSnapshot()); assert.deepEqual(json, { - firstName: get(superVillain, "firstName"), - lastName: get(superVillain, "lastName"), - homePlanet: "123", - evilMinions: [{ - id: get(evilMinion, "id"), - name: get(evilMinion, "name"), - superVillain: "1" - }], - secretLab: "101" + firstName: get(superVillain, 'firstName'), + lastName: get(superVillain, 'lastName'), + homePlanet: '123', + evilMinions: [ + { + id: get(evilMinion, 'id'), + name: get(evilMinion, 'name'), + superVillain: '1', + }, + ], + secretLab: '101', // "manyToOne" relation does not serialize ids // sersecretWeapons: ["1"] }); }); -test("normalize with custom belongsTo primary key", function(assert) { - env.registry.register('serializer:evil-minion', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - superVillain: { embedded: 'always' } - } - })); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend({ - primaryKey: 'custom' - })); - - var serializer = env.store.serializerFor("evil-minion"); +test('normalize with custom belongsTo primary key', function(assert) { + env.registry.register( + 'serializer:evil-minion', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + superVillain: { embedded: 'always' }, + }, + }) + ); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend({ + primaryKey: 'custom', + }) + ); + + var serializer = env.store.serializerFor('evil-minion'); var json_hash = { evilMinion: { - id: "1", - name: "Alex", + id: '1', + name: 'Alex', superVillain: { - custom: "1", - firstName: "Tom", - lastName: "Dale" - } - } + custom: '1', + firstName: 'Tom', + lastName: 'Dale', + }, + }, }; var json; @@ -1963,43 +2316,65 @@ test("normalize with custom belongsTo primary key", function(assert) { json = serializer.normalizeResponse(env.store, EvilMinion, json_hash, '1', 'findRecord'); }); - assert.deepEqual(json, { - "data": { - "id": "1", - "type": "evil-minion", - "attributes": { - "name": "Alex" - }, - "relationships": { - "superVillain": { - "data": { "id": "1", "type": "super-villain" } - } - } + assert.deepEqual( + json, + { + data: { + id: '1', + type: 'evil-minion', + attributes: { + name: 'Alex', + }, + relationships: { + superVillain: { + data: { id: '1', type: 'super-villain' }, + }, + }, + }, + included: [ + { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale', + }, + relationships: {}, + }, + ], }, - "included": [{ - "id": "1", - "type": "super-villain", - "attributes": { - "firstName": "Tom", - "lastName": "Dale" - }, - "relationships": {} - }] - }, "Primary hash was correct"); + 'Primary hash was correct' + ); }); -test("serializing relationships with an embedded and without calls super when not attr not present", function(assert) { - let homePlanet = env.store.createRecord('home-planet', { name: "Villain League", id: "123" }); - let secretLab = env.store.createRecord('secret-lab', { minionCapacity: 5000, vicinity: "California, USA", id: "101" }); +test('serializing relationships with an embedded and without calls super when not attr not present', function(assert) { + let homePlanet = env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }); + let secretLab = env.store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }); let superVillain = env.store.createRecord('super-villain', { - id: "1", firstName: "Super", lastName: "Villian", homePlanet: homePlanet, secretLab: secretLab + id: '1', + firstName: 'Super', + lastName: 'Villian', + homePlanet: homePlanet, + secretLab: secretLab, + }); + let secretWeapon = env.store.createRecord('secret-weapon', { + id: '1', + name: 'Secret Weapon', + superVillain: superVillain, }); - let secretWeapon = env.store.createRecord('secret-weapon', { id: "1", name: "Secret Weapon", superVillain: superVillain }); let evilMinion; run(function() { superVillain.get('secretWeapons').pushObject(secretWeapon); - evilMinion = env.store.createRecord('evil-minion', { id: "1", name: "Evil Minion", superVillian: superVillain }); + evilMinion = env.store.createRecord('evil-minion', { + id: '1', + name: 'Evil Minion', + superVillian: superVillain, + }); superVillain.get('evilMinions').pushObject(evilMinion); }); @@ -2014,169 +2389,215 @@ test("serializing relationships with an embedded and without calls super when no serializeHasMany(snapshot, json, relationship) { calledSerializeHasMany = true; var key = relationship.key; - var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, "hasMany") : key; + var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, 'hasMany') : key; var relationshipType = snapshot.type.determineRelationshipType(relationship); // "manyToOne" not supported in DS.ActiveModelSerializer.prototype.serializeHasMany var relationshipTypes = w('manyToNone manyToMany manyToOne'); if (relationshipTypes.indexOf(relationshipType) > -1) { json[payloadKey] = snapshot.hasMany(key, { ids: true }); } - } + }, }); env.registry.register('serializer:evil-minion', Serializer); env.registry.register('serializer:secret-weapon', Serializer); - env.registry.register('serializer:super-villain', Serializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - evilMinions: { serialize: 'records', deserialize: 'records' } - // some relationships are not listed here, so super should be called on those - // e.g. secretWeapons: { serialize: 'ids' } - } - })); - let serializer = env.store.serializerFor("super-villain"); + env.registry.register( + 'serializer:super-villain', + Serializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + evilMinions: { serialize: 'records', deserialize: 'records' }, + // some relationships are not listed here, so super should be called on those + // e.g. secretWeapons: { serialize: 'ids' } + }, + }) + ); + let serializer = env.store.serializerFor('super-villain'); let json = serializer.serialize(superVillain._createSnapshot()); assert.deepEqual(json, { - firstName: get(superVillain, "firstName"), - lastName: get(superVillain, "lastName"), - homePlanet: "123", - evilMinions: [{ - id: get(evilMinion, "id"), - name: get(evilMinion, "name"), - superVillain: "1" - }], - secretLab: "101", + firstName: get(superVillain, 'firstName'), + lastName: get(superVillain, 'lastName'), + homePlanet: '123', + evilMinions: [ + { + id: get(evilMinion, 'id'), + name: get(evilMinion, 'name'), + superVillain: '1', + }, + ], + secretLab: '101', // customized serializeHasMany method to generate ids for "manyToOne" relation - secretWeapons: ["1"] + secretWeapons: ['1'], }); assert.ok(calledSerializeBelongsTo); assert.ok(calledSerializeHasMany); }); -test("serializing belongsTo correctly removes embedded foreign key", function(assert) { +test('serializing belongsTo correctly removes embedded foreign key', function(assert) { SecretWeapon.reopen({ - superVillain: null + superVillain: null, }); EvilMinion.reopen({ secretWeapon: DS.belongsTo('secret-weapon', { async: false }), - superVillain: null + superVillain: null, }); - let secretWeapon = env.store.createRecord('secret-weapon', { name: "Secret Weapon" }); - let evilMinion = env.store.createRecord('evil-minion', { name: "Evil Minion", secretWeapon: secretWeapon }); + let secretWeapon = env.store.createRecord('secret-weapon', { name: 'Secret Weapon' }); + let evilMinion = env.store.createRecord('evil-minion', { + name: 'Evil Minion', + secretWeapon: secretWeapon, + }); - env.registry.register('serializer:evil-minion', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretWeapon: { embedded: 'always' } - } - })); + env.registry.register( + 'serializer:evil-minion', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + secretWeapon: { embedded: 'always' }, + }, + }) + ); - let serializer = env.store.serializerFor("evil-minion"); + let serializer = env.store.serializerFor('evil-minion'); let json = serializer.serialize(evilMinion._createSnapshot()); assert.deepEqual(json, { - name: "Evil Minion", + name: 'Evil Minion', secretWeapon: { - name: "Secret Weapon" - } + name: 'Secret Weapon', + }, }); }); +test('serializing embedded belongsTo respects remapped attrs key', function(assert) { + let homePlanet = env.store.createRecord('home-planet', { name: 'Hoth' }); + let superVillain = env.store.createRecord('super-villain', { + firstName: 'Ice', + lastName: 'Creature', + homePlanet: homePlanet, + }); -test("serializing embedded belongsTo respects remapped attrs key", function(assert) { - let homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); - let superVillain = env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); - - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - homePlanet: { embedded: 'always', key: 'favorite_place' } - } - })); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + homePlanet: { embedded: 'always', key: 'favorite_place' }, + }, + }) + ); - let serializer = env.store.serializerFor("super-villain"); + let serializer = env.store.serializerFor('super-villain'); let json = serializer.serialize(superVillain._createSnapshot()); assert.deepEqual(json, { - firstName: "Ice", - lastName: "Creature", + firstName: 'Ice', + lastName: 'Creature', favorite_place: { - name: "Hoth" + name: 'Hoth', }, - secretLab: null + secretLab: null, }); }); -test("serializing embedded hasMany respects remapped attrs key", function(assert) { - let homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); - env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); +test('serializing embedded hasMany respects remapped attrs key', function(assert) { + let homePlanet = env.store.createRecord('home-planet', { name: 'Hoth' }); + env.store.createRecord('super-villain', { + firstName: 'Ice', + lastName: 'Creature', + homePlanet: homePlanet, + }); - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always', key: 'notable_persons' } - } - })); + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always', key: 'notable_persons' }, + }, + }) + ); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - homePlanet: { serialize: false }, - secretLab: { serialize: false } - } - })); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + homePlanet: { serialize: false }, + secretLab: { serialize: false }, + }, + }) + ); - let serializer = env.store.serializerFor("home-planet"); + let serializer = env.store.serializerFor('home-planet'); let json = serializer.serialize(homePlanet._createSnapshot()); assert.deepEqual(json, { - name: "Hoth", - notable_persons: [{ - firstName: 'Ice', - lastName: 'Creature' - }] + name: 'Hoth', + notable_persons: [ + { + firstName: 'Ice', + lastName: 'Creature', + }, + ], }); }); -test("serializing id belongsTo respects remapped attrs key", function(assert) { - let homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); - let superVillain = env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); +test('serializing id belongsTo respects remapped attrs key', function(assert) { + let homePlanet = env.store.createRecord('home-planet', { name: 'Hoth' }); + let superVillain = env.store.createRecord('super-villain', { + firstName: 'Ice', + lastName: 'Creature', + homePlanet: homePlanet, + }); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - homePlanet: { serialize: 'id', key: 'favorite_place' } - } - })); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + homePlanet: { serialize: 'id', key: 'favorite_place' }, + }, + }) + ); - let serializer = env.store.serializerFor("super-villain"); + let serializer = env.store.serializerFor('super-villain'); let json = serializer.serialize(superVillain._createSnapshot()); assert.deepEqual(json, { - firstName: "Ice", - lastName: "Creature", + firstName: 'Ice', + lastName: 'Creature', favorite_place: homePlanet.id, - secretLab: null + secretLab: null, }); }); -test("serializing ids hasMany respects remapped attrs key", function(assert) { - let homePlanet = env.store.createRecord('home-planet', { name: "Hoth" }); - let superVillain = env.store.createRecord('super-villain', { firstName: "Ice", lastName: "Creature", homePlanet: homePlanet }); +test('serializing ids hasMany respects remapped attrs key', function(assert) { + let homePlanet = env.store.createRecord('home-planet', { name: 'Hoth' }); + let superVillain = env.store.createRecord('super-villain', { + firstName: 'Ice', + lastName: 'Creature', + homePlanet: homePlanet, + }); - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { serialize: 'ids', key: 'notable_persons' } - } - })); + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + villains: { serialize: 'ids', key: 'notable_persons' }, + }, + }) + ); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - homePlanet: { serialize: false }, - secretLab: { serialize: false } - } - })); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + homePlanet: { serialize: false }, + secretLab: { serialize: false }, + }, + }) + ); - let serializer = env.store.serializerFor("home-planet"); + let serializer = env.store.serializerFor('home-planet'); let json = serializer.serialize(homePlanet._createSnapshot()); assert.deepEqual(json, { - name: "Hoth", - notable_persons: [superVillain.id] + name: 'Hoth', + notable_persons: [superVillain.id], }); }); diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 57512906683..8f238c1727f 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -19,28 +19,28 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', { title: DS.attr('string'), handles: DS.hasMany('handle', { async: true, polymorphic: true }), company: DS.belongsTo('company', { async: true }), - reportsTo: DS.belongsTo('user', { async: true, inverse: null }) + reportsTo: DS.belongsTo('user', { async: true, inverse: null }), }); Handle = DS.Model.extend({ - user: DS.belongsTo('user', { async: true }) + user: DS.belongsTo('user', { async: true }), }); GithubHandle = Handle.extend({ - username: DS.attr('string') + username: DS.attr('string'), }); TwitterHandle = Handle.extend({ - nickname: DS.attr('string') + nickname: DS.attr('string'), }); Company = DS.Model.extend({ name: DS.attr('string'), - employees: DS.hasMany('user', { async: true }) + employees: DS.hasMany('user', { async: true }), }); Project = DS.Model.extend({ - 'company-name': DS.attr('string') + 'company-name': DS.attr('string'), }); env = setupStore({ @@ -51,7 +51,7 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', { 'github-handle': GithubHandle, 'twitter-handle': TwitterHandle, company: Company, - project: Project + project: Project, }); store = env.store; @@ -60,7 +60,7 @@ module('integration/serializers/json-api-serializer - JSONAPISerializer', { afterEach() { run(env.store, 'destroy'); - } + }, }); test('Calling pushPayload works', function(assert) { @@ -71,39 +71,40 @@ test('Calling pushPayload works', function(assert) { id: '1', attributes: { 'first-name': 'Yehuda', - 'last-name': 'Katz' + 'last-name': 'Katz', }, relationships: { company: { - data: { type: 'companies', id: '2' } + data: { type: 'companies', id: '2' }, }, handles: { - data: [ - { type: 'github-handles', id: '3' }, - { type: 'twitter-handles', id: '4' } - ] - } - } - }, - included: [{ - type: 'companies', - id: '2', - attributes: { - name: 'Tilde Inc.' - } - }, { - type: 'github-handles', - id: '3', - attributes: { - username: 'wycats' - } - }, { - type: 'twitter-handles', - id: '4', - attributes: { - nickname: '@wycats' - } - }] + data: [{ type: 'github-handles', id: '3' }, { type: 'twitter-handles', id: '4' }], + }, + }, + }, + included: [ + { + type: 'companies', + id: '2', + attributes: { + name: 'Tilde Inc.', + }, + }, + { + type: 'github-handles', + id: '3', + attributes: { + username: 'wycats', + }, + }, + { + type: 'twitter-handles', + id: '4', + attributes: { + nickname: '@wycats', + }, + }, + ], }); var user = store.peekRecord('user', 1); @@ -111,8 +112,16 @@ test('Calling pushPayload works', function(assert) { assert.equal(get(user, 'firstName'), 'Yehuda', 'firstName is correct'); assert.equal(get(user, 'lastName'), 'Katz', 'lastName is correct'); assert.equal(get(user, 'company.name'), 'Tilde Inc.', 'company.name is correct'); - assert.equal(get(user, 'handles.firstObject.username'), 'wycats', 'handles.firstObject.username is correct'); - assert.equal(get(user, 'handles.lastObject.nickname'), '@wycats', 'handles.lastObject.nickname is correct'); + assert.equal( + get(user, 'handles.firstObject.username'), + 'wycats', + 'handles.firstObject.username is correct' + ); + assert.equal( + get(user, 'handles.lastObject.nickname'), + '@wycats', + 'handles.lastObject.nickname is correct' + ); }); }); @@ -122,14 +131,16 @@ testInDebug('Warns when normalizing an unknown type', function(assert) { type: 'UnknownType', id: '1', attributes: { - foo: 'bar' - } - } + foo: 'bar', + }, + }, }; assert.expectWarning(function() { run(function() { - env.store.serializerFor('user').normalizeResponse(env.store, User, documentHash, '1', 'findRecord'); + env.store + .serializerFor('user') + .normalizeResponse(env.store, User, documentHash, '1', 'findRecord'); }); }, /Encountered a resource object with type "UnknownType", but no model was found for model name "unknown-type"/); }); @@ -141,47 +152,55 @@ testInDebug('Warns when normalizing payload with unknown type included', functio id: '1', attributes: { 'first-name': 'Yehuda', - 'last-name': 'Katz' + 'last-name': 'Katz', }, relationships: { company: { - data: { type: 'unknown-types', id: '2' } - } - } + data: { type: 'unknown-types', id: '2' }, + }, + }, }, - included: [{ - type: 'unknown-types', - id: '2', - attributes: { - name: 'WyKittens' - } - }] + included: [ + { + type: 'unknown-types', + id: '2', + attributes: { + name: 'WyKittens', + }, + }, + ], }; assert.expectWarning(function() { run(function() { - env.store.serializerFor('user').normalizeResponse(env.store, User, documentHash, '1', 'findRecord'); + env.store + .serializerFor('user') + .normalizeResponse(env.store, User, documentHash, '1', 'findRecord'); }); }, /Encountered a resource object with type "unknown-types", but no model was found for model name "unknown-type"/); }); -testInDebug('Warns but does not fail when pushing payload with unknown type included', function(assert) { +testInDebug('Warns but does not fail when pushing payload with unknown type included', function( + assert +) { var documentHash = { data: { type: 'users', id: '1', attributes: { 'first-name': 'Yehuda', - 'last-name': 'Katz' - } + 'last-name': 'Katz', + }, }, - included: [{ - type: 'unknown-types', - id: '2', - attributes: { - name: 'WyKittens' - } - }] + included: [ + { + type: 'unknown-types', + id: '2', + attributes: { + name: 'WyKittens', + }, + }, + ], }; assert.expectWarning(function() { @@ -194,21 +213,23 @@ testInDebug('Warns but does not fail when pushing payload with unknown type incl assert.equal(get(user, 'firstName'), 'Yehuda', 'firstName is correct'); }); -testInDebug('Errors when pushing payload with unknown type included in relationship', function(assert) { +testInDebug('Errors when pushing payload with unknown type included in relationship', function( + assert +) { var documentHash = { data: { type: 'users', id: '1', attributes: { 'first-name': 'Yehuda', - 'last-name': 'Katz' + 'last-name': 'Katz', }, relationships: { company: { - data: { type: 'unknown-types', id: '2' } - } - } - } + data: { type: 'unknown-types', id: '2' }, + }, + }, + }, }; assert.expectAssertion(function() { @@ -223,65 +244,77 @@ testInDebug('Warns when normalizing with type missing', function(assert) { data: { id: '1', attributes: { - foo: 'bar' - } - } + foo: 'bar', + }, + }, }; assert.expectAssertion(function() { run(function() { - env.store.serializerFor('user').normalizeResponse(env.store, User, documentHash, '1', 'findRecord'); + env.store + .serializerFor('user') + .normalizeResponse(env.store, User, documentHash, '1', 'findRecord'); }); }, /Encountered a resource object with an undefined type/); }); test('Serializer should respect the attrs hash when extracting attributes and relationships', function(assert) { - env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ - attrs: { - firstName: 'firstname_attribute_key', - title: "title_attribute_key", - company: { key: 'company_relationship_key' } - } - })); + env.registry.register( + 'serializer:user', + DS.JSONAPISerializer.extend({ + attrs: { + firstName: 'firstname_attribute_key', + title: 'title_attribute_key', + company: { key: 'company_relationship_key' }, + }, + }) + ); var jsonHash = { data: { type: 'users', id: '1', attributes: { - 'firstname_attribute_key': 'Yehuda', - 'title_attribute_key': 'director' + firstname_attribute_key: 'Yehuda', + title_attribute_key: 'director', }, relationships: { - 'company_relationship_key': { - data: { type: 'companies', id: '2' } - } - } + company_relationship_key: { + data: { type: 'companies', id: '2' }, + }, + }, }, - included: [{ - type: 'companies', - id: '2', - attributes: { - name: 'Tilde Inc.' - } - }] + included: [ + { + type: 'companies', + id: '2', + attributes: { + name: 'Tilde Inc.', + }, + }, + ], }; - var user = env.store.serializerFor("user").normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); + var user = env.store + .serializerFor('user') + .normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); assert.equal(user.data.attributes.firstName, 'Yehuda'); - assert.equal(user.data.attributes.title, "director"); - assert.deepEqual(user.data.relationships.company.data, { id: "2", type: "company" }); + assert.equal(user.data.attributes.title, 'director'); + assert.deepEqual(user.data.relationships.company.data, { id: '2', type: 'company' }); }); test('Serializer should respect the attrs hash when serializing attributes and relationships', function(assert) { - env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ - attrs: { - firstName: 'firstname_attribute_key', - title: "title_attribute_key", - company: { key: 'company_relationship_key' } - } - })); + env.registry.register( + 'serializer:user', + DS.JSONAPISerializer.extend({ + attrs: { + firstName: 'firstname_attribute_key', + title: 'title_attribute_key', + company: { key: 'company_relationship_key' }, + }, + }) + ); var company, user; run(function() { @@ -290,49 +323,61 @@ test('Serializer should respect the attrs hash when serializing attributes and r type: 'company', id: '1', attributes: { - name: "Tilde Inc." - } - } + name: 'Tilde Inc.', + }, + }, }); company = env.store.peekRecord('company', 1); - user = env.store.createRecord('user', { firstName: "Yehuda", title: "director", company: company }); + user = env.store.createRecord('user', { + firstName: 'Yehuda', + title: 'director', + company: company, + }); }); - var payload = env.store.serializerFor("user").serialize(user._createSnapshot()); + var payload = env.store.serializerFor('user').serialize(user._createSnapshot()); - assert.equal(payload.data.relationships['company_relationship_key'].data.id, "1"); + assert.equal(payload.data.relationships['company_relationship_key'].data.id, '1'); assert.equal(payload.data.attributes['firstname_attribute_key'], 'Yehuda'); - assert.equal(payload.data.attributes['title_attribute_key'], "director"); + assert.equal(payload.data.attributes['title_attribute_key'], 'director'); }); test('Serializer should respect the attrs hash when extracting attributes with not camelized keys', function(assert) { - env.registry.register('serializer:project', DS.JSONAPISerializer.extend({ - attrs: { - 'company-name': 'company_name' - } - })); + env.registry.register( + 'serializer:project', + DS.JSONAPISerializer.extend({ + attrs: { + 'company-name': 'company_name', + }, + }) + ); var jsonHash = { data: { type: 'projects', id: '1', attributes: { - 'company_name': 'Tilde Inc.' - } - } + company_name: 'Tilde Inc.', + }, + }, }; - var project = env.store.serializerFor('project').normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); + var project = env.store + .serializerFor('project') + .normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); assert.equal(project.data.attributes['company-name'], 'Tilde Inc.'); }); test('Serializer should respect the attrs hash when serializing attributes with not camelized keys', function(assert) { - env.registry.register('serializer:project', DS.JSONAPISerializer.extend({ - attrs: { - 'company-name': 'company_name' - } - })); + env.registry.register( + 'serializer:project', + DS.JSONAPISerializer.extend({ + attrs: { + 'company-name': 'company_name', + }, + }) + ); let project = env.store.createRecord('project', { 'company-name': 'Tilde Inc.' }); let payload = env.store.serializerFor('project').serialize(project._createSnapshot()); @@ -343,16 +388,19 @@ test('Serializer should respect the attrs hash when serializing attributes with test('options are passed to transform for serialization', function(assert) { assert.expect(1); - env.registry.register('transform:custom', DS.Transform.extend({ - serialize: function(deserialized, options) { - assert.deepEqual(options, { custom: 'config' }); - } - })); + env.registry.register( + 'transform:custom', + DS.Transform.extend({ + serialize: function(deserialized, options) { + assert.deepEqual(options, { custom: 'config' }); + }, + }) + ); User.reopen({ myCustomField: DS.attr('custom', { - custom: 'config' - }) + custom: 'config', + }), }); let user = env.store.createRecord('user', { myCustomField: 'value' }); @@ -363,7 +411,7 @@ test('options are passed to transform for serialization', function(assert) { testInDebug('Warns when defining extractMeta()', function(assert) { assert.expectWarning(function() { DS.JSONAPISerializer.extend({ - extractMeta() {} + extractMeta() {}, }).create(); }, /You've defined 'extractMeta' in/); }); @@ -373,8 +421,8 @@ test('a belongsTo relationship that is not set will not be in the relationships serializer.pushPayload(store, { data: { type: 'handles', - id: 1 - } + id: 1, + }, }); let handle = store.peekRecord('handle', 1); @@ -383,8 +431,8 @@ test('a belongsTo relationship that is not set will not be in the relationships assert.deepEqual(serialized, { data: { type: 'handles', - id: '1' - } + id: '1', + }, }); }); }); @@ -394,8 +442,8 @@ test('a belongsTo relationship that is set to null will show as null in the rela serializer.pushPayload(store, { data: { type: 'handles', - id: 1 - } + id: 1, + }, }); let handle = store.peekRecord('handle', 1); @@ -408,10 +456,10 @@ test('a belongsTo relationship that is set to null will show as null in the rela id: '1', relationships: { user: { - data: null - } - } - } + data: null, + }, + }, + }, }); }); }); @@ -421,8 +469,8 @@ test('a belongsTo relationship set to a new record will not show in the relation serializer.pushPayload(store, { data: { type: 'handles', - id: 1 - } + id: 1, + }, }); let handle = store.peekRecord('handle', 1); @@ -433,18 +481,21 @@ test('a belongsTo relationship set to a new record will not show in the relation assert.deepEqual(serialized, { data: { type: 'handles', - id: '1' - } + id: '1', + }, }); }); }); test('it should serialize a hasMany relationship', function(assert) { - env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ - attrs: { - handles: { serialize: true } - } - })); + env.registry.register( + 'serializer:user', + DS.JSONAPISerializer.extend({ + attrs: { + handles: { serialize: true }, + }, + }) + ); run(function() { serializer.pushPayload(store, { @@ -453,17 +504,11 @@ test('it should serialize a hasMany relationship', function(assert) { id: 1, relationships: { handles: { - data: [ - { type: 'handles', id: 1 }, - { type: 'handles', id: 2 } - ] - } - } + data: [{ type: 'handles', id: 1 }, { type: 'handles', id: 2 }], + }, + }, }, - included: [ - { type: 'handles', id: 1 }, - { type: 'handles', id: 2 } - ] + included: [{ type: 'handles', id: 1 }, { type: 'handles', id: 2 }], }); let user = store.peekRecord('user', 1); @@ -477,27 +522,27 @@ test('it should serialize a hasMany relationship', function(assert) { attributes: { 'first-name': null, 'last-name': null, - title: null + title: null, }, relationships: { handles: { - data: [ - { type: 'handles', id: '1' }, - { type: 'handles', id: '2' } - ] - } - } - } + data: [{ type: 'handles', id: '1' }, { type: 'handles', id: '2' }], + }, + }, + }, }); }); }); test('it should not include new records when serializing a hasMany relationship', function(assert) { - env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ - attrs: { - handles: { serialize: true } - } - })); + env.registry.register( + 'serializer:user', + DS.JSONAPISerializer.extend({ + attrs: { + handles: { serialize: true }, + }, + }) + ); run(function() { serializer.pushPayload(store, { @@ -506,17 +551,11 @@ test('it should not include new records when serializing a hasMany relationship' id: 1, relationships: { handles: { - data: [ - { type: 'handles', id: 1 }, - { type: 'handles', id: 2 } - ] - } - } + data: [{ type: 'handles', id: 1 }, { type: 'handles', id: 2 }], + }, + }, }, - included: [ - { type: 'handles', id: 1 }, - { type: 'handles', id: 2 } - ] + included: [{ type: 'handles', id: 1 }, { type: 'handles', id: 2 }], }); let user = store.peekRecord('user', 1); @@ -531,34 +570,34 @@ test('it should not include new records when serializing a hasMany relationship' attributes: { 'first-name': null, 'last-name': null, - title: null + title: null, }, relationships: { handles: { - data: [ - { type: 'handles', id: '1' }, - { type: 'handles', id: '2' } - ] - } - } - } + data: [{ type: 'handles', id: '1' }, { type: 'handles', id: '2' }], + }, + }, + }, }); }); }); test('it should not include any records when serializing a hasMany relationship if they are all new', function(assert) { - env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ - attrs: { - handles: { serialize: true } - } - })); + env.registry.register( + 'serializer:user', + DS.JSONAPISerializer.extend({ + attrs: { + handles: { serialize: true }, + }, + }) + ); run(function() { serializer.pushPayload(store, { data: { type: 'users', - id: 1 - } + id: 1, + }, }); let user = store.peekRecord('user', 1); @@ -573,24 +612,27 @@ test('it should not include any records when serializing a hasMany relationship attributes: { 'first-name': null, 'last-name': null, - title: null + title: null, }, relationships: { handles: { - data: [] - } - } - } + data: [], + }, + }, + }, }); }); }); test('it should include an empty list when serializing an empty hasMany relationship', function(assert) { - env.registry.register("serializer:user", DS.JSONAPISerializer.extend({ - attrs: { - handles: { serialize: true } - } - })); + env.registry.register( + 'serializer:user', + DS.JSONAPISerializer.extend({ + attrs: { + handles: { serialize: true }, + }, + }) + ); run(function() { serializer.pushPayload(store, { @@ -599,17 +641,11 @@ test('it should include an empty list when serializing an empty hasMany relation id: 1, relationships: { handles: { - data: [ - { type: 'handles', id: 1 }, - { type: 'handles', id: 2 } - ] - } - } + data: [{ type: 'handles', id: 1 }, { type: 'handles', id: 2 }], + }, + }, }, - included: [ - { type: 'handles', id: 1 }, - { type: 'handles', id: 2 } - ] + included: [{ type: 'handles', id: 1 }, { type: 'handles', id: 2 }], }); let user = store.peekRecord('user', 1); @@ -627,14 +663,14 @@ test('it should include an empty list when serializing an empty hasMany relation attributes: { 'first-name': null, 'last-name': null, - title: null + title: null, }, relationships: { handles: { - data: [] - } - } - } + data: [], + }, + }, + }, }); }); }); @@ -645,34 +681,44 @@ testInDebug('JSON warns when combined with EmbeddedRecordsMixin', function(asser }, /The JSONAPISerializer does not work with the EmbeddedRecordsMixin/); }); -testInDebug('Asserts when normalized attribute key is not found in payload but original key is', function(assert) { - var jsonHash = { - data: { - type: 'users', - id: '1', - attributes: { - 'firstName': 'Yehuda' - } - } - }; - assert.expectAssertion(function() { - env.store.serializerFor("user").normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); - }, /Your payload for 'user' contains 'firstName', but your serializer is setup to look for 'first-name'/); -}); +testInDebug( + 'Asserts when normalized attribute key is not found in payload but original key is', + function(assert) { + var jsonHash = { + data: { + type: 'users', + id: '1', + attributes: { + firstName: 'Yehuda', + }, + }, + }; + assert.expectAssertion(function() { + env.store + .serializerFor('user') + .normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); + }, /Your payload for 'user' contains 'firstName', but your serializer is setup to look for 'first-name'/); + } +); -testInDebug('Asserts when normalized relationship key is not found in payload but original key is', function(assert) { - var jsonHash = { - data: { - type: 'users', - id: '1', - relationships: { - 'reportsTo': { - data: null - } - } - } - }; - assert.expectAssertion(function() { - env.store.serializerFor("user").normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); - }, /Your payload for 'user' contains 'reportsTo', but your serializer is setup to look for 'reports-to'/); -}); +testInDebug( + 'Asserts when normalized relationship key is not found in payload but original key is', + function(assert) { + var jsonHash = { + data: { + type: 'users', + id: '1', + relationships: { + reportsTo: { + data: null, + }, + }, + }, + }; + assert.expectAssertion(function() { + env.store + .serializerFor('user') + .normalizeResponse(env.store, User, jsonHash, '1', 'findRecord'); + }, /Your payload for 'user' contains 'reportsTo', but your serializer is setup to look for 'reports-to'/); + } +); diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index 0080703e330..c0fb9acc751 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -9,23 +9,23 @@ import DS from 'ember-data'; var Post, Comment, Favorite, env, serializer; -module("integration/serializer/json - JSONSerializer", { +module('integration/serializer/json - JSONSerializer', { beforeEach() { Post = DS.Model.extend({ title: DS.attr('string'), - comments: DS.hasMany('comment', { inverse: null, async: false }) + comments: DS.hasMany('comment', { inverse: null, async: false }), }); Comment = DS.Model.extend({ body: DS.attr('string'), - post: DS.belongsTo('post', { inverse: null, async: false }) + post: DS.belongsTo('post', { inverse: null, async: false }), }); Favorite = DS.Model.extend({ - post: DS.belongsTo('post', { inverse: null, async: true, polymorphic: true }) + post: DS.belongsTo('post', { inverse: null, async: true, polymorphic: true }), }); env = setupStore({ - post: Post, - comment: Comment, - favorite: Favorite + post: Post, + comment: Comment, + favorite: Favorite, }); env.store.modelFor('post'); env.store.modelFor('comment'); @@ -35,7 +35,7 @@ module("integration/serializer/json - JSONSerializer", { afterEach() { run(env.store, 'destroy'); - } + }, }); test("serialize doesn't include ID when includeId is false", function(assert) { @@ -43,22 +43,21 @@ test("serialize doesn't include ID when includeId is false", function(assert) { let json = serializer.serialize(post._createSnapshot(), { includeId: false }); assert.deepEqual(json, { - title: "Rails is omakase", - comments: [] + title: 'Rails is omakase', + comments: [], }); }); - test("serialize doesn't include relationship if not aware of one", function(assert) { let post = env.store.createRecord('post', { title: 'Rails is omakase' }); let json = serializer.serialize(post._createSnapshot()); assert.deepEqual(json, { - title: "Rails is omakase" + title: 'Rails is omakase', }); }); -test("serialize includes id when includeId is true", function(assert) { +test('serialize includes id when includeId is true', function(assert) { let post = env.store.createRecord('post', { title: 'Rails is omakase', comments: [] }); run(() => { @@ -70,101 +69,122 @@ test("serialize includes id when includeId is true", function(assert) { assert.deepEqual(json, { id: 'test', title: 'Rails is omakase', - comments: [] + comments: [], }); }); -test("serializeAttribute", function(assert) { - let post = env.store.createRecord('post', { title: "Rails is omakase" }); +test('serializeAttribute', function(assert) { + let post = env.store.createRecord('post', { title: 'Rails is omakase' }); let json = {}; - serializer.serializeAttribute(post._createSnapshot(), json, "title", { type: "string" }); + serializer.serializeAttribute(post._createSnapshot(), json, 'title', { type: 'string' }); assert.deepEqual(json, { - title: "Rails is omakase" + title: 'Rails is omakase', }); }); -test("serializeAttribute respects keyForAttribute", function(assert) { - env.registry.register('serializer:post', DS.JSONSerializer.extend({ - keyForAttribute(key) { - return key.toUpperCase(); - } - })); +test('serializeAttribute respects keyForAttribute', function(assert) { + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + keyForAttribute(key) { + return key.toUpperCase(); + }, + }) + ); - let post = env.store.createRecord('post', { title: "Rails is omakase" }); + let post = env.store.createRecord('post', { title: 'Rails is omakase' }); let json = {}; - env.store.serializerFor("post").serializeAttribute(post._createSnapshot(), json, "title", { type: "string" }); + env.store + .serializerFor('post') + .serializeAttribute(post._createSnapshot(), json, 'title', { type: 'string' }); - assert.deepEqual(json, { TITLE: "Rails is omakase" }); + assert.deepEqual(json, { TITLE: 'Rails is omakase' }); }); -test("serializeBelongsTo", function(assert) { - let post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); - let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); +test('serializeBelongsTo', function(assert) { + let post = env.store.createRecord('post', { title: 'Rails is omakase', id: '1' }); + let comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); let json = {}; - serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); + serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: 'post', options: {} }); - assert.deepEqual(json, { post: "1" }); + assert.deepEqual(json, { post: '1' }); }); -test("serializeBelongsTo with null", function(assert) { - let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: null }); +test('serializeBelongsTo with null', function(assert) { + let comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: null }); let json = {}; - serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); + serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: 'post', options: {} }); - assert.deepEqual(json, { - post: null - }, "Can set a belongsTo to a null value"); + assert.deepEqual( + json, + { + post: null, + }, + 'Can set a belongsTo to a null value' + ); }); -test("async serializeBelongsTo with null", function(assert) { +test('async serializeBelongsTo with null', function(assert) { Comment.reopen({ - post: DS.belongsTo('post', { async: true }) + post: DS.belongsTo('post', { async: true }), }); - let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: null }); + let comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: null }); let json = {}; - serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); + serializer.serializeBelongsTo(comment._createSnapshot(), json, { key: 'post', options: {} }); - assert.deepEqual(json, { - post: null - }, "Can set a belongsTo to a null value"); + assert.deepEqual( + json, + { + post: null, + }, + 'Can set a belongsTo to a null value' + ); }); -test("serializeBelongsTo respects keyForRelationship", function(assert) { - env.registry.register('serializer:post', DS.JSONSerializer.extend({ - keyForRelationship(key, type) { - return key.toUpperCase(); - } - })); +test('serializeBelongsTo respects keyForRelationship', function(assert) { + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + keyForRelationship(key, type) { + return key.toUpperCase(); + }, + }) + ); - let post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); - let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + let post = env.store.createRecord('post', { title: 'Rails is omakase', id: '1' }); + let comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); let json = {}; - env.store.serializerFor("post").serializeBelongsTo(comment._createSnapshot(), json, { key: "post", options: {} }); + env.store + .serializerFor('post') + .serializeBelongsTo(comment._createSnapshot(), json, { key: 'post', options: {} }); assert.deepEqual(json, { - POST: "1" + POST: '1', }); }); -test("serializeHasMany respects keyForRelationship", function(assert) { - env.registry.register('serializer:post', DS.JSONSerializer.extend({ - keyForRelationship(key, type) { - return key.toUpperCase(); - } - })); +test('serializeHasMany respects keyForRelationship', function(assert) { + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + keyForRelationship(key, type) { + return key.toUpperCase(); + }, + }) + ); - let post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); + let post = env.store.createRecord('post', { title: 'Rails is omakase', id: '1' }); let comment = env.store.createRecord('comment', { - body: "Omakase is delicious", + body: 'Omakase is delicious', post: post, - id: "1" + id: '1', }); run(function() { @@ -173,245 +193,320 @@ test("serializeHasMany respects keyForRelationship", function(assert) { let json = {}; - env.store.serializerFor("post").serializeHasMany(post._createSnapshot(), json, { key: "comments", options: {} }); + env.store + .serializerFor('post') + .serializeHasMany(post._createSnapshot(), json, { key: 'comments', options: {} }); assert.deepEqual(json, { - COMMENTS: ["1"] + COMMENTS: ['1'], }); }); -test("serializeHasMany omits unknown relationships on pushed record", function(assert) { - let post = run(() => env.store.push({ - data: { - id: "1", - type: "post", - attributes: { - title: "Rails is omakase" - } - } - })); +test('serializeHasMany omits unknown relationships on pushed record', function(assert) { + let post = run(() => + env.store.push({ + data: { + id: '1', + type: 'post', + attributes: { + title: 'Rails is omakase', + }, + }, + }) + ); let json = {}; - env.store.serializerFor("post").serializeHasMany(post._createSnapshot(), json, { key: "comments", options: {} }); + env.store + .serializerFor('post') + .serializeHasMany(post._createSnapshot(), json, { key: 'comments', options: {} }); - assert.ok(!json.hasOwnProperty("comments"), "Does not add the relationship key to json"); + assert.ok(!json.hasOwnProperty('comments'), 'Does not add the relationship key to json'); }); -test("shouldSerializeHasMany", function(assert) { - let post = env.store.createRecord('post', { title: "Rails is omakase", id: "1" }); - env.store.createRecord('comment', { body: "Omakase is delicious", post: post, id: "1" }); +test('shouldSerializeHasMany', function(assert) { + let post = env.store.createRecord('post', { title: 'Rails is omakase', id: '1' }); + env.store.createRecord('comment', { body: 'Omakase is delicious', post: post, id: '1' }); var snapshot = post._createSnapshot(); var relationship = snapshot.record.relationshipFor('comments'); var key = relationship.key; - var shouldSerialize = env.store.serializerFor("post").shouldSerializeHasMany(snapshot, relationship, key); + var shouldSerialize = env.store + .serializerFor('post') + .shouldSerializeHasMany(snapshot, relationship, key); - assert.ok(shouldSerialize, 'shouldSerializeHasMany correctly identifies with hasMany relationship'); + assert.ok( + shouldSerialize, + 'shouldSerializeHasMany correctly identifies with hasMany relationship' + ); }); -test("serializeIntoHash", function(assert) { - let post = env.store.createRecord('post', { title: "Rails is omakase", comments: [] }); +test('serializeIntoHash', function(assert) { + let post = env.store.createRecord('post', { title: 'Rails is omakase', comments: [] }); let json = {}; serializer.serializeIntoHash(json, Post, post._createSnapshot()); assert.deepEqual(json, { - title: "Rails is omakase", - comments: [] + title: 'Rails is omakase', + comments: [], }); }); -test("serializePolymorphicType sync", function(assert) { +test('serializePolymorphicType sync', function(assert) { assert.expect(1); - env.registry.register('serializer:comment', DS.JSONSerializer.extend({ - serializePolymorphicType(record, json, relationship) { - let key = relationship.key; - let belongsTo = record.belongsTo(key); - json[relationship.key + "TYPE"] = belongsTo.modelName; - - assert.ok(true, 'serializePolymorphicType is called when serialize a polymorphic belongsTo'); - } - })); + env.registry.register( + 'serializer:comment', + DS.JSONSerializer.extend({ + serializePolymorphicType(record, json, relationship) { + let key = relationship.key; + let belongsTo = record.belongsTo(key); + json[relationship.key + 'TYPE'] = belongsTo.modelName; + + assert.ok( + true, + 'serializePolymorphicType is called when serialize a polymorphic belongsTo' + ); + }, + }) + ); let post = env.store.createRecord('post', { title: 'Rails is omakase', id: 1 }); let comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); - env.store.serializerFor('comment').serializeBelongsTo(comment._createSnapshot(), {}, { key: 'post', options: { polymorphic: true } }); + env.store + .serializerFor('comment') + .serializeBelongsTo( + comment._createSnapshot(), + {}, + { key: 'post', options: { polymorphic: true } } + ); }); -test("serializePolymorphicType async", function(assert) { +test('serializePolymorphicType async', function(assert) { assert.expect(1); Comment.reopen({ - post: DS.belongsTo('post', { async: true }) + post: DS.belongsTo('post', { async: true }), }); - env.registry.register('serializer:comment', DS.JSONSerializer.extend({ - serializePolymorphicType(record, json, relationship) { - assert.ok(true, 'serializePolymorphicType is called when serialize a polymorphic belongsTo'); - } - })); + env.registry.register( + 'serializer:comment', + DS.JSONSerializer.extend({ + serializePolymorphicType(record, json, relationship) { + assert.ok( + true, + 'serializePolymorphicType is called when serialize a polymorphic belongsTo' + ); + }, + }) + ); let post = env.store.createRecord('post', { title: 'Rails is omakase', id: 1 }); let comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); - env.store.serializerFor('comment').serializeBelongsTo(comment._createSnapshot(), {}, { key: 'post', options: { async: true, polymorphic: true } }); + env.store + .serializerFor('comment') + .serializeBelongsTo( + comment._createSnapshot(), + {}, + { key: 'post', options: { async: true, polymorphic: true } } + ); }); -test("normalizeResponse normalizes each record in the array", function(assert) { +test('normalizeResponse normalizes each record in the array', function(assert) { var postNormalizeCount = 0; - var posts = [ - { id: "1", title: "Rails is omakase" }, - { id: "2", title: "Another Post" } - ]; - - env.registry.register('serializer:post', DS.JSONSerializer.extend({ - normalize() { - postNormalizeCount++; - return this._super.apply(this, arguments); - } - })); + var posts = [{ id: '1', title: 'Rails is omakase' }, { id: '2', title: 'Another Post' }]; + + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + normalize() { + postNormalizeCount++; + return this._super.apply(this, arguments); + }, + }) + ); run(function() { - env.store.serializerFor("post").normalizeResponse(env.store, Post, posts, null, 'findAll'); + env.store.serializerFor('post').normalizeResponse(env.store, Post, posts, null, 'findAll'); }); - assert.equal(postNormalizeCount, 2, "two posts are normalized"); + assert.equal(postNormalizeCount, 2, 'two posts are normalized'); }); test('Serializer should respect the attrs hash when extracting records', function(assert) { - env.registry.register("serializer:post", DS.JSONSerializer.extend({ - attrs: { - title: "title_payload_key", - comments: { key: 'my_comments' } - } - })); + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + attrs: { + title: 'title_payload_key', + comments: { key: 'my_comments' }, + }, + }) + ); var jsonHash = { - id: "1", - title_payload_key: "Rails is omakase", - my_comments: [1, 2] + id: '1', + title_payload_key: 'Rails is omakase', + my_comments: [1, 2], }; - var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); + var post = env.store + .serializerFor('post') + .normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); - assert.equal(post.data.attributes.title, "Rails is omakase"); - assert.deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }, { id: "2", type: "comment" }]); + assert.equal(post.data.attributes.title, 'Rails is omakase'); + assert.deepEqual(post.data.relationships.comments.data, [ + { id: '1', type: 'comment' }, + { id: '2', type: 'comment' }, + ]); }); test('Serializer should map `attrs` attributes directly when keyForAttribute also has a transform', function(assert) { Post = DS.Model.extend({ - authorName: DS.attr('string') + authorName: DS.attr('string'), }); env = setupStore({ - post: Post + post: Post, }); - env.registry.register("serializer:post", DS.JSONSerializer.extend({ - keyForAttribute: underscore, - attrs: { - authorName: 'author_name_key' - } - })); + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + keyForAttribute: underscore, + attrs: { + authorName: 'author_name_key', + }, + }) + ); var jsonHash = { - id: "1", - author_name_key: "DHH" + id: '1', + author_name_key: 'DHH', }; - var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); + var post = env.store + .serializerFor('post') + .normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); - assert.equal(post.data.attributes.authorName, "DHH"); + assert.equal(post.data.attributes.authorName, 'DHH'); }); test('Serializer should respect the attrs hash when serializing records', function(assert) { Post.reopen({ - parentPost: DS.belongsTo('post', { inverse: null, async: true }) + parentPost: DS.belongsTo('post', { inverse: null, async: true }), }); - env.registry.register("serializer:post", DS.JSONSerializer.extend({ - attrs: { - title: "title_payload_key", - parentPost: { key: "my_parent" } - } - })); + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + attrs: { + title: 'title_payload_key', + parentPost: { key: 'my_parent' }, + }, + }) + ); + + let parentPost = run(() => + env.store.push({ + data: { + type: 'post', + id: '2', + attributes: { + title: 'Rails is omakase', + }, + }, + }) + ); + let post = env.store.createRecord('post', { title: 'Rails is omakase', parentPost: parentPost }); + let payload = env.store.serializerFor('post').serialize(post._createSnapshot()); - let parentPost = run(() => env.store.push({ - data: { - type: 'post', - id: '2', - attributes: { - title: "Rails is omakase" - } - } - })); - let post = env.store.createRecord('post', { title: "Rails is omakase", parentPost: parentPost }); - let payload = env.store.serializerFor("post").serialize(post._createSnapshot()); - - assert.equal(payload.title_payload_key, "Rails is omakase"); + assert.equal(payload.title_payload_key, 'Rails is omakase'); assert.equal(payload.my_parent, '2'); }); test('Serializer respects if embedded model has an attribute named "type" - #3726', function(assert) { - env.registry.register("serializer:child", DS.JSONSerializer); - env.registry.register("serializer:parent", DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - child: { embedded: 'always' } - } - })); - env.registry.register("model:parent", DS.Model.extend({ - child: DS.belongsTo('child') - })); - env.registry.register("model:child", DS.Model.extend({ - type: DS.attr() - })); + env.registry.register('serializer:child', DS.JSONSerializer); + env.registry.register( + 'serializer:parent', + DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + child: { embedded: 'always' }, + }, + }) + ); + env.registry.register( + 'model:parent', + DS.Model.extend({ + child: DS.belongsTo('child'), + }) + ); + env.registry.register( + 'model:child', + DS.Model.extend({ + type: DS.attr(), + }) + ); var jsonHash = { id: 1, child: { id: 1, - type: 'first_type' - } + type: 'first_type', + }, }; var Parent = env.store.modelFor('parent'); - var payload = env.store.serializerFor('parent').normalizeResponse(env.store, Parent, jsonHash, '1', 'findRecord'); + var payload = env.store + .serializerFor('parent') + .normalizeResponse(env.store, Parent, jsonHash, '1', 'findRecord'); assert.deepEqual(payload.included, [ { id: '1', type: 'child', attributes: { - type: 'first_type' + type: 'first_type', }, - relationships: {} - } + relationships: {}, + }, ]); }); test('Serializer respects if embedded model has a relationship named "type" - #3726', function(assert) { - env.registry.register("serializer:child", DS.JSONSerializer); - env.registry.register("serializer:parent", DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - child: { embedded: 'always' } - } - })); - env.registry.register("model:parent", DS.Model.extend({ - child: DS.belongsTo('child') - })); - env.registry.register("model:child", DS.Model.extend({ - type: DS.belongsTo('le-type') - })); - env.registry.register("model:le-type", DS.Model.extend()); + env.registry.register('serializer:child', DS.JSONSerializer); + env.registry.register( + 'serializer:parent', + DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + child: { embedded: 'always' }, + }, + }) + ); + env.registry.register( + 'model:parent', + DS.Model.extend({ + child: DS.belongsTo('child'), + }) + ); + env.registry.register( + 'model:child', + DS.Model.extend({ + type: DS.belongsTo('le-type'), + }) + ); + env.registry.register('model:le-type', DS.Model.extend()); var jsonHash = { id: 1, child: { id: 1, - type: "my_type_id" - } + type: 'my_type_id', + }, }; var Parent = env.store.modelFor('parent'); - var payload = env.store.serializerFor('parent').normalizeResponse(env.store, Parent, jsonHash, '1', 'findRecord'); + var payload = env.store + .serializerFor('parent') + .normalizeResponse(env.store, Parent, jsonHash, '1', 'findRecord'); assert.deepEqual(payload.included, [ { id: '1', @@ -421,230 +516,280 @@ test('Serializer respects if embedded model has a relationship named "type" - #3 type: { data: { id: 'my_type_id', - type: 'le-type' - } - } - } - } + type: 'le-type', + }, + }, + }, + }, ]); }); test('Serializer respects `serialize: false` on the attrs hash', function(assert) { assert.expect(2); - env.registry.register("serializer:post", DS.JSONSerializer.extend({ - attrs: { - title: { serialize: false } - } - })); + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + attrs: { + title: { serialize: false }, + }, + }) + ); - let post = env.store.createRecord('post', { title: "Rails is omakase" }); - let payload = env.store.serializerFor("post").serialize(post._createSnapshot()); + let post = env.store.createRecord('post', { title: 'Rails is omakase' }); + let payload = env.store.serializerFor('post').serialize(post._createSnapshot()); - assert.ok(!payload.hasOwnProperty('title'), "Does not add the key to instance"); - assert.ok(!payload.hasOwnProperty('[object Object]'), "Does not add some random key like [object Object]"); + assert.ok(!payload.hasOwnProperty('title'), 'Does not add the key to instance'); + assert.ok( + !payload.hasOwnProperty('[object Object]'), + 'Does not add some random key like [object Object]' + ); }); test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` property', function(assert) { assert.expect(1); - env.registry.register("serializer:post", DS.JSONSerializer.extend({ - attrs: { - comments: { serialize: false } - } - })); + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + attrs: { + comments: { serialize: false }, + }, + }) + ); - let post = env.store.createRecord('post', { title: "Rails is omakase" }); - env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + let post = env.store.createRecord('post', { title: 'Rails is omakase' }); + env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); - var serializer = env.store.serializerFor("post"); + var serializer = env.store.serializerFor('post'); var serializedProperty = serializer.keyForRelationship('comments', 'hasMany'); var payload = serializer.serialize(post._createSnapshot()); - assert.ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); + assert.ok(!payload.hasOwnProperty(serializedProperty), 'Does not add the key to instance'); }); test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` property', function(assert) { assert.expect(1); - env.registry.register("serializer:comment", DS.JSONSerializer.extend({ - attrs: { - post: { serialize: false } - } - })); + env.registry.register( + 'serializer:comment', + DS.JSONSerializer.extend({ + attrs: { + post: { serialize: false }, + }, + }) + ); - let post = env.store.createRecord('post', { title: "Rails is omakase" }); - let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + let post = env.store.createRecord('post', { title: 'Rails is omakase' }); + let comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); - var serializer = env.store.serializerFor("comment"); + var serializer = env.store.serializerFor('comment'); var serializedProperty = serializer.keyForRelationship('post', 'belongsTo'); var payload = serializer.serialize(comment._createSnapshot()); - assert.ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); + assert.ok(!payload.hasOwnProperty(serializedProperty), 'Does not add the key to instance'); }); test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` property', function(assert) { assert.expect(1); - env.registry.register("serializer:post", DS.JSONSerializer.extend({ - attrs: { - comments: { serialize: false } - } - })); + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + attrs: { + comments: { serialize: false }, + }, + }) + ); - let post = env.store.createRecord('post', { title: "Rails is omakase" }); - env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + let post = env.store.createRecord('post', { title: 'Rails is omakase' }); + env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); - var serializer = env.store.serializerFor("post"); + var serializer = env.store.serializerFor('post'); var serializedProperty = serializer.keyForRelationship('comments', 'hasMany'); var payload = serializer.serialize(post._createSnapshot()); - assert.ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); + assert.ok(!payload.hasOwnProperty(serializedProperty), 'Does not add the key to instance'); }); test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` property', function(assert) { assert.expect(1); - env.registry.register("serializer:comment", DS.JSONSerializer.extend({ - attrs: { - post: { serialize: false } - } - })); + env.registry.register( + 'serializer:comment', + DS.JSONSerializer.extend({ + attrs: { + post: { serialize: false }, + }, + }) + ); - let post = env.store.createRecord('post', { title: "Rails is omakase" }); - let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + let post = env.store.createRecord('post', { title: 'Rails is omakase' }); + let comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); - var serializer = env.store.serializerFor("comment"); + var serializer = env.store.serializerFor('comment'); var serializedProperty = serializer.keyForRelationship('post', 'belongsTo'); var payload = serializer.serialize(comment._createSnapshot()); - assert.ok(!payload.hasOwnProperty(serializedProperty), "Does not add the key to instance"); + assert.ok(!payload.hasOwnProperty(serializedProperty), 'Does not add the key to instance'); }); test('Serializer respects `serialize: true` on the attrs hash for a `hasMany` property', function(assert) { assert.expect(1); - env.registry.register("serializer:post", DS.JSONSerializer.extend({ - attrs: { - comments: { serialize: true } - } - })); + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + attrs: { + comments: { serialize: true }, + }, + }) + ); - let post = env.store.createRecord('post', { title: "Rails is omakase" }); - let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + let post = env.store.createRecord('post', { title: 'Rails is omakase' }); + let comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); run(function() { post.get('comments').pushObject(comment); }); - var serializer = env.store.serializerFor("post"); + var serializer = env.store.serializerFor('post'); var serializedProperty = serializer.keyForRelationship('comments', 'hasMany'); var payload = serializer.serialize(post._createSnapshot()); - assert.ok(payload.hasOwnProperty(serializedProperty), "Add the key to instance"); + assert.ok(payload.hasOwnProperty(serializedProperty), 'Add the key to instance'); }); test('Serializer respects `serialize: true` on the attrs hash for a `belongsTo` property', function(assert) { assert.expect(1); - env.registry.register("serializer:comment", DS.JSONSerializer.extend({ - attrs: { - post: { serialize: true } - } - })); + env.registry.register( + 'serializer:comment', + DS.JSONSerializer.extend({ + attrs: { + post: { serialize: true }, + }, + }) + ); - let post = env.store.createRecord('post', { title: "Rails is omakase" }); - let comment = env.store.createRecord('comment', { body: "Omakase is delicious", post: post }); + let post = env.store.createRecord('post', { title: 'Rails is omakase' }); + let comment = env.store.createRecord('comment', { body: 'Omakase is delicious', post: post }); - var serializer = env.store.serializerFor("comment"); + var serializer = env.store.serializerFor('comment'); var serializedProperty = serializer.keyForRelationship('post', 'belongsTo'); var payload = serializer.serialize(comment._createSnapshot()); - assert.ok(payload.hasOwnProperty(serializedProperty), "Add the key to instance"); + assert.ok(payload.hasOwnProperty(serializedProperty), 'Add the key to instance'); }); -test("Serializer should merge attrs from superclasses", function(assert) { +test('Serializer should merge attrs from superclasses', function(assert) { assert.expect(4); Post.reopen({ description: DS.attr('string'), - anotherString: DS.attr('string') + anotherString: DS.attr('string'), }); var BaseSerializer = DS.JSONSerializer.extend({ attrs: { - title: "title_payload_key", - anotherString: "base_another_string_key" - } + title: 'title_payload_key', + anotherString: 'base_another_string_key', + }, }); - env.registry.register("serializer:post", BaseSerializer.extend({ - attrs: { - description: "description_payload_key", - anotherString: "overwritten_another_string_key" - } - })); + env.registry.register( + 'serializer:post', + BaseSerializer.extend({ + attrs: { + description: 'description_payload_key', + anotherString: 'overwritten_another_string_key', + }, + }) + ); - let post = env.store.createRecord("post", { title: "Rails is omakase", description: "Omakase is delicious", anotherString: "yet another string" }); - let payload = env.store.serializerFor("post").serialize(post._createSnapshot()); + let post = env.store.createRecord('post', { + title: 'Rails is omakase', + description: 'Omakase is delicious', + anotherString: 'yet another string', + }); + let payload = env.store.serializerFor('post').serialize(post._createSnapshot()); - assert.equal(payload.title_payload_key, "Rails is omakase"); - assert.equal(payload.description_payload_key, "Omakase is delicious"); - assert.equal(payload.overwritten_another_string_key, "yet another string"); - assert.ok(!payload.base_another_string_key, "overwritten key is not added"); + assert.equal(payload.title_payload_key, 'Rails is omakase'); + assert.equal(payload.description_payload_key, 'Omakase is delicious'); + assert.equal(payload.overwritten_another_string_key, 'yet another string'); + assert.ok(!payload.base_another_string_key, 'overwritten key is not added'); }); -test("Serializer should respect the primaryKey attribute when extracting records", function(assert) { - env.registry.register('serializer:post', DS.JSONSerializer.extend({ - primaryKey: '_ID_' - })); +test('Serializer should respect the primaryKey attribute when extracting records', function(assert) { + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + primaryKey: '_ID_', + }) + ); - let jsonHash = { "_ID_": 1, title: "Rails is omakase" }; - let post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); + let jsonHash = { _ID_: 1, title: 'Rails is omakase' }; + let post = env.store + .serializerFor('post') + .normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); - assert.equal(post.data.id, "1"); - assert.equal(post.data.attributes.title, "Rails is omakase"); + assert.equal(post.data.id, '1'); + assert.equal(post.data.attributes.title, 'Rails is omakase'); }); -test("Serializer should respect the primaryKey attribute when serializing records", function(assert) { - env.registry.register('serializer:post', DS.JSONSerializer.extend({ - primaryKey: '_ID_' - })); +test('Serializer should respect the primaryKey attribute when serializing records', function(assert) { + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + primaryKey: '_ID_', + }) + ); - let post = env.store.createRecord('post', { id: "1", title: "Rails is omakase" }); - let payload = env.store.serializerFor("post").serialize(post._createSnapshot(), { includeId: true }); + let post = env.store.createRecord('post', { id: '1', title: 'Rails is omakase' }); + let payload = env.store + .serializerFor('post') + .serialize(post._createSnapshot(), { includeId: true }); - assert.equal(payload._ID_, "1"); + assert.equal(payload._ID_, '1'); }); -test("Serializer should respect keyForAttribute when extracting records", function(assert) { - env.registry.register('serializer:post', DS.JSONSerializer.extend({ - keyForAttribute(key) { - return key.toUpperCase(); - } - })); +test('Serializer should respect keyForAttribute when extracting records', function(assert) { + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + keyForAttribute(key) { + return key.toUpperCase(); + }, + }) + ); let jsonHash = { id: 1, TITLE: 'Rails is omakase' }; - let post = env.store.serializerFor("post").normalize(Post, jsonHash); + let post = env.store.serializerFor('post').normalize(Post, jsonHash); - assert.equal(post.data.id, "1"); - assert.equal(post.data.attributes.title, "Rails is omakase"); + assert.equal(post.data.id, '1'); + assert.equal(post.data.attributes.title, 'Rails is omakase'); }); -test("Serializer should respect keyForRelationship when extracting records", function(assert) { - env.registry.register('serializer:post', DS.JSONSerializer.extend({ - keyForRelationship(key, type) { - return key.toUpperCase(); - } - })); +test('Serializer should respect keyForRelationship when extracting records', function(assert) { + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + keyForRelationship(key, type) { + return key.toUpperCase(); + }, + }) + ); let jsonHash = { id: 1, title: 'Rails is omakase', COMMENTS: ['1'] }; - let post = env.store.serializerFor("post").normalize(Post, jsonHash); + let post = env.store.serializerFor('post').normalize(Post, jsonHash); - assert.deepEqual(post.data.relationships.comments.data, [{ id: "1", type: "comment" }]); + assert.deepEqual(post.data.relationships.comments.data, [{ id: '1', type: 'comment' }]); }); -test("Calling normalize should normalize the payload (only the passed keys)", function(assert) { +test('Calling normalize should normalize the payload (only the passed keys)', function(assert) { assert.expect(1); var Person = DS.Model.extend({ - posts: DS.hasMany('post', { async: false }) + posts: DS.hasMany('post', { async: false }), }); - env.registry.register('serializer:post', DS.JSONSerializer.extend({ - attrs: { - notInHash: 'aCustomAttrNotInHash', - inHash: 'aCustomAttrInHash' - } - })); + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + attrs: { + notInHash: 'aCustomAttrNotInHash', + inHash: 'aCustomAttrInHash', + }, + }) + ); env.registry.register('model:person', Person); @@ -652,30 +797,30 @@ test("Calling normalize should normalize the payload (only the passed keys)", fu content: DS.attr('string'), author: DS.belongsTo('person', { async: false }), notInHash: DS.attr('string'), - inHash: DS.attr('string') + inHash: DS.attr('string'), }); - var normalizedPayload = env.store.serializerFor("post").normalize(Post, { + var normalizedPayload = env.store.serializerFor('post').normalize(Post, { id: '1', title: 'Ember rocks', author: 1, - aCustomAttrInHash: 'blah' + aCustomAttrInHash: 'blah', }); assert.deepEqual(normalizedPayload, { - "data": { - "id": "1", - "type": "post", - "attributes": { - "inHash": "blah", - "title": "Ember rocks" - }, - "relationships": { - "author": { - "data": { "id": "1", "type": "person" } - } - } - } + data: { + id: '1', + type: 'post', + attributes: { + inHash: 'blah', + title: 'Ember rocks', + }, + relationships: { + author: { + data: { id: '1', type: 'person' }, + }, + }, + }, }); }); @@ -683,47 +828,56 @@ test('serializeBelongsTo with async polymorphic', function(assert) { var json = {}; var expected = { post: '1', postTYPE: 'post' }; - env.registry.register('serializer:favorite', DS.JSONSerializer.extend({ - serializePolymorphicType(snapshot, json, relationship) { - var key = relationship.key; - json[key + 'TYPE'] = snapshot.belongsTo(key).modelName; - } - })); + env.registry.register( + 'serializer:favorite', + DS.JSONSerializer.extend({ + serializePolymorphicType(snapshot, json, relationship) { + var key = relationship.key; + json[key + 'TYPE'] = snapshot.belongsTo(key).modelName; + }, + }) + ); let post = env.store.createRecord('post', { title: 'Kitties are omakase', id: '1' }); let favorite = env.store.createRecord('favorite', { post: post, id: '3' }); - env.store.serializerFor('favorite').serializeBelongsTo(favorite._createSnapshot(), json, { key: 'post', options: { polymorphic: true, async: true } }); + env.store.serializerFor('favorite').serializeBelongsTo(favorite._createSnapshot(), json, { + key: 'post', + options: { polymorphic: true, async: true }, + }); assert.deepEqual(json, expected, 'returned JSON is correct'); }); test('extractErrors respects custom key mappings', function(assert) { - env.registry.register('serializer:post', DS.JSONSerializer.extend({ - attrs: { - title: 'le_title', - comments: { key: 'my_comments' } - } - })); + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + attrs: { + title: 'le_title', + comments: { key: 'my_comments' }, + }, + }) + ); var payload = { errors: [ { source: { pointer: 'data/attributes/le_title' }, - detail: "title errors" + detail: 'title errors', }, { source: { pointer: 'data/attributes/my_comments' }, - detail: "comments errors" - } - ] + detail: 'comments errors', + }, + ], }; var errors = env.store.serializerFor('post').extractErrors(env.store, Post, payload); assert.deepEqual(errors, { - title: ["title errors"], - comments: ["comments errors"] + title: ['title errors'], + comments: ['comments errors'], }); }); @@ -731,172 +885,194 @@ test('extractErrors expects error information located on the errors property of env.registry.register('serializer:post', DS.JSONSerializer.extend()); var payload = { - attributeWhichWillBeRemovedinExtractErrors: ["true"], + attributeWhichWillBeRemovedinExtractErrors: ['true'], errors: [ { source: { pointer: 'data/attributes/title' }, - detail: "title errors" - } - ] + detail: 'title errors', + }, + ], }; var errors = env.store.serializerFor('post').extractErrors(env.store, Post, payload); - assert.deepEqual(errors, { title: ["title errors"] }); + assert.deepEqual(errors, { title: ['title errors'] }); }); test('extractErrors leaves payload untouched if it has no errors property', function(assert) { env.registry.register('serializer:post', DS.JSONSerializer.extend()); var payload = { - untouchedSinceNoErrorsSiblingPresent: ["true"] + untouchedSinceNoErrorsSiblingPresent: ['true'], }; var errors = env.store.serializerFor('post').extractErrors(env.store, Post, payload); - assert.deepEqual(errors, { untouchedSinceNoErrorsSiblingPresent: ["true"] }); + assert.deepEqual(errors, { untouchedSinceNoErrorsSiblingPresent: ['true'] }); }); test('normalizeResponse should extract meta using extractMeta', function(assert) { - env.registry.register("serializer:post", DS.JSONSerializer.extend({ - extractMeta(store, modelClass, payload) { - let meta = this._super(...arguments); - meta.authors.push('Tomhuda'); - return meta; - } - })); + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + extractMeta(store, modelClass, payload) { + let meta = this._super(...arguments); + meta.authors.push('Tomhuda'); + return meta; + }, + }) + ); var jsonHash = { - id: "1", - title_payload_key: "Rails is omakase", + id: '1', + title_payload_key: 'Rails is omakase', my_comments: [1, 2], meta: { - authors: ['Tomster'] - } + authors: ['Tomster'], + }, }; - var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); + var post = env.store + .serializerFor('post') + .normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); assert.deepEqual(post.meta.authors, ['Tomster', 'Tomhuda']); }); test('normalizeResponse returns empty `included` payload by default', function(assert) { - env.registry.register("serializer:post", DS.JSONSerializer.extend()); + env.registry.register('serializer:post', DS.JSONSerializer.extend()); var jsonHash = { - id: "1", - title: "Rails is omakase" + id: '1', + title: 'Rails is omakase', }; - var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); + var post = env.store + .serializerFor('post') + .normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); assert.deepEqual(post.included, []); }); test('normalizeResponse returns empty `included` payload when relationship is undefined', function(assert) { - env.registry.register("serializer:post", DS.JSONSerializer.extend()); + env.registry.register('serializer:post', DS.JSONSerializer.extend()); var jsonHash = { - id: "1", - title: "Rails is omakase", - comments: null + id: '1', + title: 'Rails is omakase', + comments: null, }; - var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); + var post = env.store + .serializerFor('post') + .normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); assert.deepEqual(post.included, []); }); test('normalizeResponse respects `included` items (single response)', function(assert) { - env.registry.register("serializer:comment", DS.JSONSerializer); - env.registry.register("serializer:post", DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - comments: { embedded: 'always' } - } - })); + env.registry.register('serializer:comment', DS.JSONSerializer); + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + comments: { embedded: 'always' }, + }, + }) + ); var jsonHash = { - id: "1", - title: "Rails is omakase", - comments: [ - { id: "1", body: "comment 1" }, - { id: "2", body: "comment 2" } - ] + id: '1', + title: 'Rails is omakase', + comments: [{ id: '1', body: 'comment 1' }, { id: '2', body: 'comment 2' }], }; - var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); + var post = env.store + .serializerFor('post') + .normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); assert.deepEqual(post.included, [ - { id: "1", type: "comment", attributes: { body: "comment 1" }, relationships: {} }, - { id: "2", type: "comment", attributes: { body: "comment 2" }, relationships: {} } + { id: '1', type: 'comment', attributes: { body: 'comment 1' }, relationships: {} }, + { id: '2', type: 'comment', attributes: { body: 'comment 2' }, relationships: {} }, ]); }); test('normalizeResponse respects `included` items (array response)', function(assert) { - env.registry.register("serializer:comment", DS.JSONSerializer); - env.registry.register("serializer:post", DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - comments: { embedded: 'always' } - } - })); - - var payload = [{ - id: "1", - title: "Rails is omakase", - comments: [ - { id: "1", body: "comment 1" } - ] - }, { - id: "2", - title: "Post 2", - comments: [ - { id: "2", body: "comment 2" }, - { id: "3", body: "comment 3" } - ] - }]; - - var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, payload, '1', 'findAll'); + env.registry.register('serializer:comment', DS.JSONSerializer); + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + comments: { embedded: 'always' }, + }, + }) + ); + + var payload = [ + { + id: '1', + title: 'Rails is omakase', + comments: [{ id: '1', body: 'comment 1' }], + }, + { + id: '2', + title: 'Post 2', + comments: [{ id: '2', body: 'comment 2' }, { id: '3', body: 'comment 3' }], + }, + ]; + + var post = env.store + .serializerFor('post') + .normalizeResponse(env.store, Post, payload, '1', 'findAll'); assert.deepEqual(post.included, [ - { id: "1", type: "comment", attributes: { body: "comment 1" }, relationships: {} }, - { id: "2", type: "comment", attributes: { body: "comment 2" }, relationships: {} }, - { id: "3", type: "comment", attributes: { body: "comment 3" }, relationships: {} } + { id: '1', type: 'comment', attributes: { body: 'comment 1' }, relationships: {} }, + { id: '2', type: 'comment', attributes: { body: 'comment 2' }, relationships: {} }, + { id: '3', type: 'comment', attributes: { body: 'comment 3' }, relationships: {} }, ]); }); testInDebug('normalizeResponse ignores unmapped attributes', function(assert) { - env.registry.register("serializer:post", DS.JSONSerializer.extend({ - attrs: { - title: { serialize: false }, - notInMapping: { serialize: false } - } - })); + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + attrs: { + title: { serialize: false }, + notInMapping: { serialize: false }, + }, + }) + ); var jsonHash = { - id: "1", + id: '1', notInMapping: 'I should be ignored', - title: "Rails is omakase" + title: 'Rails is omakase', }; assert.expectWarning(function() { - var post = env.store.serializerFor("post").normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); - assert.equal(post.data.attributes.title, "Rails is omakase"); + var post = env.store + .serializerFor('post') + .normalizeResponse(env.store, Post, jsonHash, '1', 'findRecord'); + assert.equal(post.data.attributes.title, 'Rails is omakase'); }, /There is no attribute or relationship with the name/); }); test('options are passed to transform for serialization', function(assert) { assert.expect(1); - env.registry.register('transform:custom', DS.Transform.extend({ - serialize: function(deserialized, options) { - assert.deepEqual(options, { custom: 'config' }); - } - })); + env.registry.register( + 'transform:custom', + DS.Transform.extend({ + serialize: function(deserialized, options) { + assert.deepEqual(options, { custom: 'config' }); + }, + }) + ); Post.reopen({ custom: DS.attr('custom', { - custom: 'config' - }) + custom: 'config', + }), }); let post = env.store.createRecord('post', { custom: 'value' }); @@ -907,41 +1083,48 @@ test('options are passed to transform for serialization', function(assert) { test('options are passed to transform for normalization', function(assert) { assert.expect(1); - env.registry.register('transform:custom', DS.Transform.extend({ - deserialize: function(serialized, options) { - assert.deepEqual(options, { custom: 'config' }); - } - })); + env.registry.register( + 'transform:custom', + DS.Transform.extend({ + deserialize: function(serialized, options) { + assert.deepEqual(options, { custom: 'config' }); + }, + }) + ); Post.reopen({ custom: DS.attr('custom', { - custom: 'config' - }) + custom: 'config', + }), }); serializer.normalize(Post, { - custom: 'value' + custom: 'value', }); }); test('Serializer should respect the attrs hash in links', function(assert) { - env.registry.register("serializer:post", DS.JSONSerializer.extend({ - attrs: { - title: "title_payload_key", - comments: { key: 'my_comments' } - } - })); + env.registry.register( + 'serializer:post', + DS.JSONSerializer.extend({ + attrs: { + title: 'title_payload_key', + comments: { key: 'my_comments' }, + }, + }) + ); var jsonHash = { - title_payload_key: "Rails is omakase", + title_payload_key: 'Rails is omakase', links: { - my_comments: 'posts/1/comments' - } + my_comments: 'posts/1/comments', + }, }; - var post = env.container.lookup("serializer:post").normalizeSingleResponse(env.store, Post, jsonHash); + var post = env.container + .lookup('serializer:post') + .normalizeSingleResponse(env.store, Post, jsonHash); - assert.equal(post.data.attributes.title, "Rails is omakase"); + assert.equal(post.data.attributes.title, 'Rails is omakase'); assert.equal(post.data.relationships.comments.links.related, 'posts/1/comments'); }); - diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 60445918b58..25739f5e10d 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -6,54 +6,62 @@ import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; import DS from 'ember-data'; -let HomePlanet, SuperVillain, EvilMinion, YellowMinion, DoomsdayDevice, Comment, Basket, Container, env; - -module("integration/serializer/rest - RESTSerializer", { +let HomePlanet, + SuperVillain, + EvilMinion, + YellowMinion, + DoomsdayDevice, + Comment, + Basket, + Container, + env; + +module('integration/serializer/rest - RESTSerializer', { beforeEach() { HomePlanet = DS.Model.extend({ - name: DS.attr('string'), - superVillains: DS.hasMany('super-villain', { async: false }) + name: DS.attr('string'), + superVillains: DS.hasMany('super-villain', { async: false }), }); SuperVillain = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - homePlanet: DS.belongsTo('home-planet', { async: false }), - evilMinions: DS.hasMany('evil-minion', { async: false }) + firstName: DS.attr('string'), + lastName: DS.attr('string'), + homePlanet: DS.belongsTo('home-planet', { async: false }), + evilMinions: DS.hasMany('evil-minion', { async: false }), }); EvilMinion = DS.Model.extend({ superVillain: DS.belongsTo('super-villain', { async: false }), - name: DS.attr('string'), - doomsdayDevice: DS.belongsTo('doomsday-device', { async: false }) + name: DS.attr('string'), + doomsdayDevice: DS.belongsTo('doomsday-device', { async: false }), }); YellowMinion = EvilMinion.extend({ - eyes: DS.attr('number') + eyes: DS.attr('number'), }); DoomsdayDevice = DS.Model.extend({ - name: DS.attr('string'), - evilMinion: DS.belongsTo('evil-minion', { polymorphic: true, async: true }) + name: DS.attr('string'), + evilMinion: DS.belongsTo('evil-minion', { polymorphic: true, async: true }), }); Comment = DS.Model.extend({ body: DS.attr('string'), root: DS.attr('boolean'), - children: DS.hasMany('comment', { inverse: null, async: false }) + children: DS.hasMany('comment', { inverse: null, async: false }), }); Basket = DS.Model.extend({ type: DS.attr('string'), - size: DS.attr('number') + size: DS.attr('number'), }); Container = DS.Model.extend({ type: DS.belongsTo('basket', { async: true }), - volume: DS.attr('string') + volume: DS.attr('string'), }); env = setupStore({ - superVillain: SuperVillain, - homePlanet: HomePlanet, - evilMinion: EvilMinion, - yellowMinion: YellowMinion, + superVillain: SuperVillain, + homePlanet: HomePlanet, + evilMinion: EvilMinion, + yellowMinion: YellowMinion, doomsdayDevice: DoomsdayDevice, - comment: Comment, - basket: Basket, - container: Container + comment: Comment, + basket: Basket, + container: Container, }); env.store.modelFor('super-villain'); env.store.modelFor('home-planet'); @@ -67,10 +75,10 @@ module("integration/serializer/rest - RESTSerializer", { afterEach() { run(env.store, 'destroy'); - } + }, }); -test("modelNameFromPayloadKey returns always same modelName even for uncountable multi words keys", function(assert) { +test('modelNameFromPayloadKey returns always same modelName even for uncountable multi words keys', function(assert) { assert.expect(2); Inflector.inflector.uncountable('words'); var expectedModelName = 'multi-words'; @@ -79,25 +87,30 @@ test("modelNameFromPayloadKey returns always same modelName even for uncountable }); test('normalizeResponse should extract meta using extractMeta', function(assert) { - env.registry.register("serializer:home-planet", DS.RESTSerializer.extend({ - extractMeta(store, modelClass, payload) { - let meta = this._super(...arguments); - meta.authors.push('Tomhuda'); - return meta; - } - })); + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend({ + extractMeta(store, modelClass, payload) { + let meta = this._super(...arguments); + meta.authors.push('Tomhuda'); + return meta; + }, + }) + ); var jsonHash = { meta: { authors: ['Tomster'] }, - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] + home_planets: [{ id: '1', name: 'Umber', superVillains: [1] }], }; - var json = env.container.lookup("serializer:home-planet").normalizeResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); + var json = env.container + .lookup('serializer:home-planet') + .normalizeResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); assert.deepEqual(json.meta.authors, ['Tomster', 'Tomhuda']); }); -test("normalizeResponse with custom modelNameFromPayloadKey", function(assert) { +test('normalizeResponse with custom modelNameFromPayloadKey', function(assert) { assert.expect(1); env.restSerializer.modelNameFromPayloadKey = function(root) { @@ -108,22 +121,32 @@ test("normalizeResponse with custom modelNameFromPayloadKey", function(assert) { env.registry.register('serializer:super-villain', DS.JSONSerializer); var jsonHash = { - home_planets: [{ - id: "1", - name: "Umber", - superVillains: [1] - }], - super_villains: [{ - id: "1", - firstName: "Tom", - lastName: "Dale", - homePlanet: "1" - }] + home_planets: [ + { + id: '1', + name: 'Umber', + superVillains: [1], + }, + ], + super_villains: [ + { + id: '1', + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '1', + }, + ], }; var array; run(function() { - array = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, '1', 'findRecord'); + array = env.restSerializer.normalizeResponse( + env.store, + HomePlanet, + jsonHash, + '1', + 'findRecord' + ); }); assert.deepEqual(array, { @@ -131,118 +154,134 @@ test("normalizeResponse with custom modelNameFromPayloadKey", function(assert) { id: '1', type: 'home-planet', attributes: { - name: 'Umber' + name: 'Umber', }, relationships: { superVillains: { - data: [{ id: '1', type: 'super-villain' }] - } - } + data: [{ id: '1', type: 'super-villain' }], + }, + }, }, - included: [{ - id: '1', - type: 'super-villain', - attributes: { - firstName: 'Tom', - lastName: 'Dale' + included: [ + { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale', + }, + relationships: { + homePlanet: { + data: { id: '1', type: 'home-planet' }, + }, + }, }, - relationships: { - homePlanet: { - data: { id: '1', type: 'home-planet' } - } - } - }] + ], }); }); -testInDebug("normalizeResponse with type and custom modelNameFromPayloadKey", function(assert) { +testInDebug('normalizeResponse with type and custom modelNameFromPayloadKey', function(assert) { assert.expect(2); var homePlanetNormalizeCount = 0; env.restSerializer.modelNameFromPayloadKey = function(root) { - return "home-planet"; + return 'home-planet'; }; - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend({ - normalize() { - homePlanetNormalizeCount++; - return this._super.apply(this, arguments); - } - })); + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend({ + normalize() { + homePlanetNormalizeCount++; + return this._super.apply(this, arguments); + }, + }) + ); var jsonHash = { - "my-custom-type": [{ id: "1", name: "Umber", type: "my-custom-type" }] + 'my-custom-type': [{ id: '1', name: 'Umber', type: 'my-custom-type' }], }; var array; - run(function() { array = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, '1', 'findAll'); }); assert.deepEqual(array, { - data: [{ - id: '1', - type: 'home-planet', - attributes: { - name: 'Umber' + data: [ + { + id: '1', + type: 'home-planet', + attributes: { + name: 'Umber', + }, + relationships: {}, }, - relationships: {} - }], - included: [] + ], + included: [], }); - assert.equal(homePlanetNormalizeCount, 1, "homePlanet is normalized once"); + assert.equal(homePlanetNormalizeCount, 1, 'homePlanet is normalized once'); }); -testInDebug("normalizeResponse warning with custom modelNameFromPayloadKey", function(assert) { +testInDebug('normalizeResponse warning with custom modelNameFromPayloadKey', function(assert) { var homePlanet; var oldModelNameFromPayloadKey = env.restSerializer.modelNameFromPayloadKey; env.registry.register('serializer:super-villain', DS.JSONSerializer); env.registry.register('serializer:home-planet', DS.JSONSerializer); env.restSerializer.modelNameFromPayloadKey = function(root) { //return some garbage that won"t resolve in the container - return "garbage"; + return 'garbage'; }; var jsonHash = { - home_planet: { id: "1", name: "Umber", superVillains: [1] } + home_planet: { id: '1', name: 'Umber', superVillains: [1] }, }; - assert.expectWarning(bind(null, function() { - run(function() { - env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, '1', 'findRecord'); - }); - }), /Encountered "home_planet" in payload, but no model was found for model name "garbage"/); + assert.expectWarning( + bind(null, function() { + run(function() { + env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, '1', 'findRecord'); + }); + }), + /Encountered "home_planet" in payload, but no model was found for model name "garbage"/ + ); // should not warn if a model is found. env.restSerializer.modelNameFromPayloadKey = oldModelNameFromPayloadKey; jsonHash = { - home_planet: { id: "1", name: "Umber", superVillains: [1] } + home_planet: { id: '1', name: 'Umber', superVillains: [1] }, }; assert.expectNoWarning(function() { run(function() { - - homePlanet = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, 1, 'findRecord'); + homePlanet = env.restSerializer.normalizeResponse( + env.store, + HomePlanet, + jsonHash, + 1, + 'findRecord' + ); }); }); - assert.equal(homePlanet.data.attributes.name, "Umber"); - assert.deepEqual(homePlanet.data.relationships.superVillains.data, [{ id: '1', type: 'super-villain' }]); + assert.equal(homePlanet.data.attributes.name, 'Umber'); + assert.deepEqual(homePlanet.data.relationships.superVillains.data, [ + { id: '1', type: 'super-villain' }, + ]); }); -testInDebug("normalizeResponse warning with custom modelNameFromPayloadKey", function(assert) { +testInDebug('normalizeResponse warning with custom modelNameFromPayloadKey', function(assert) { var homePlanets; env.registry.register('serializer:super-villain', DS.JSONSerializer); env.registry.register('serializer:home-planet', DS.JSONSerializer); env.restSerializer.modelNameFromPayloadKey = function(root) { //return some garbage that won"t resolve in the container - return "garbage"; + return 'garbage'; }; var jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] + home_planets: [{ id: '1', name: 'Umber', superVillains: [1] }], }; assert.expectWarning(function() { @@ -255,120 +294,143 @@ testInDebug("normalizeResponse warning with custom modelNameFromPayloadKey", fun }; jsonHash = { - home_planets: [{ id: "1", name: "Umber", superVillains: [1] }] + home_planets: [{ id: '1', name: 'Umber', superVillains: [1] }], }; assert.expectNoWarning(function() { run(function() { - homePlanets = env.restSerializer.normalizeResponse(env.store, HomePlanet, jsonHash, null, 'findAll'); + homePlanets = env.restSerializer.normalizeResponse( + env.store, + HomePlanet, + jsonHash, + null, + 'findAll' + ); }); }); assert.equal(homePlanets.data.length, 1); - assert.equal(homePlanets.data[0].attributes.name, "Umber"); - assert.deepEqual(homePlanets.data[0].relationships.superVillains.data, [{ id: '1', type: 'super-villain' }]); + assert.equal(homePlanets.data[0].attributes.name, 'Umber'); + assert.deepEqual(homePlanets.data[0].relationships.superVillains.data, [ + { id: '1', type: 'super-villain' }, + ]); }); -test("serialize polymorphicType", function(assert) { - let tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); - let ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: "DeathRay" }); +test('serialize polymorphicType', function(assert) { + let tom = env.store.createRecord('yellow-minion', { name: 'Alex', id: '124' }); + let ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: 'DeathRay' }); let json = env.restSerializer.serialize(ray._createSnapshot()); assert.deepEqual(json, { - name: "DeathRay", - evilMinionType: "yellowMinion", - evilMinion: "124" + name: 'DeathRay', + evilMinionType: 'yellowMinion', + evilMinion: '124', }); }); -test("serialize polymorphicType with decamelized modelName", function(assert) { - let tom = env.store.createRecord('yellow-minion', { name: "Alex", id: "124" }); - let ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: "DeathRay" }); +test('serialize polymorphicType with decamelized modelName', function(assert) { + let tom = env.store.createRecord('yellow-minion', { name: 'Alex', id: '124' }); + let ray = env.store.createRecord('doomsday-device', { evilMinion: tom, name: 'DeathRay' }); let json = env.restSerializer.serialize(ray._createSnapshot()); - assert.deepEqual(json["evilMinionType"], "yellowMinion"); + assert.deepEqual(json['evilMinionType'], 'yellowMinion'); }); -test("serialize polymorphic when associated object is null", function(assert) { - let ray = env.store.createRecord('doomsday-device', { name: "DeathRay" }); +test('serialize polymorphic when associated object is null', function(assert) { + let ray = env.store.createRecord('doomsday-device', { name: 'DeathRay' }); let json = env.restSerializer.serialize(ray._createSnapshot()); - assert.deepEqual(json["evilMinionType"], null); + assert.deepEqual(json['evilMinionType'], null); }); -test("normalizeResponse loads secondary records with correct serializer", function(assert) { +test('normalizeResponse loads secondary records with correct serializer', function(assert) { var superVillainNormalizeCount = 0; env.registry.register('serializer:evil-minion', DS.JSONSerializer); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend({ - normalize() { - superVillainNormalizeCount++; - return this._super.apply(this, arguments); - } - })); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend({ + normalize() { + superVillainNormalizeCount++; + return this._super.apply(this, arguments); + }, + }) + ); var jsonHash = { - evilMinion: { id: "1", name: "Tom Dale", superVillain: 1 }, - superVillains: [{ id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1" }] + evilMinion: { id: '1', name: 'Tom Dale', superVillain: 1 }, + superVillains: [{ id: '1', firstName: 'Yehuda', lastName: 'Katz', homePlanet: '1' }], }; run(function() { env.restSerializer.normalizeResponse(env.store, EvilMinion, jsonHash, '1', 'findRecord'); }); - assert.equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); + assert.equal(superVillainNormalizeCount, 1, 'superVillain is normalized once'); }); -test("normalizeResponse returns null if payload contains null", function(assert) { +test('normalizeResponse returns null if payload contains null', function(assert) { assert.expect(1); var jsonHash = { - evilMinion: null + evilMinion: null, }; var value; run(function() { - value = env.restSerializer.normalizeResponse(env.store, EvilMinion, jsonHash, null, 'findRecord'); + value = env.restSerializer.normalizeResponse( + env.store, + EvilMinion, + jsonHash, + null, + 'findRecord' + ); }); - assert.deepEqual(value, { data: null, included: [] }, "returned value is null"); + assert.deepEqual(value, { data: null, included: [] }, 'returned value is null'); }); -test("normalizeResponse loads secondary records with correct serializer", function(assert) { +test('normalizeResponse loads secondary records with correct serializer', function(assert) { var superVillainNormalizeCount = 0; env.registry.register('serializer:evil-minion', DS.JSONSerializer); - env.registry.register('serializer:super-villain', DS.RESTSerializer.extend({ - normalize() { - superVillainNormalizeCount++; - return this._super.apply(this, arguments); - } - })); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend({ + normalize() { + superVillainNormalizeCount++; + return this._super.apply(this, arguments); + }, + }) + ); var jsonHash = { - evilMinions: [{ id: "1", name: "Tom Dale", superVillain: 1 }], - superVillains: [{ id: "1", firstName: "Yehuda", lastName: "Katz", homePlanet: "1" }] + evilMinions: [{ id: '1', name: 'Tom Dale', superVillain: 1 }], + superVillains: [{ id: '1', firstName: 'Yehuda', lastName: 'Katz', homePlanet: '1' }], }; run(function() { env.restSerializer.normalizeResponse(env.store, EvilMinion, jsonHash, null, 'findAll'); }); - assert.equal(superVillainNormalizeCount, 1, "superVillain is normalized once"); + assert.equal(superVillainNormalizeCount, 1, 'superVillain is normalized once'); }); test('normalize should allow for different levels of normalization', function(assert) { - env.registry.register('serializer:application', DS.RESTSerializer.extend({ - attrs: { - superVillain: 'is_super_villain' - }, - keyForAttribute(attr) { - return decamelize(attr); - } - })); + env.registry.register( + 'serializer:application', + DS.RESTSerializer.extend({ + attrs: { + superVillain: 'is_super_villain', + }, + keyForAttribute(attr) { + return decamelize(attr); + }, + }) + ); var jsonHash = { - evilMinions: [{ id: "1", name: "Tom Dale", is_super_villain: 1 }] + evilMinions: [{ id: '1', name: 'Tom Dale', is_super_villain: 1 }], }; var array; @@ -380,17 +442,20 @@ test('normalize should allow for different levels of normalization', function(as }); test('normalize should allow for different levels of normalization - attributes', function(assert) { - env.registry.register('serializer:application', DS.RESTSerializer.extend({ - attrs: { - name: 'full_name' - }, - keyForAttribute(attr) { - return decamelize(attr); - } - })); + env.registry.register( + 'serializer:application', + DS.RESTSerializer.extend({ + attrs: { + name: 'full_name', + }, + keyForAttribute(attr) { + return decamelize(attr); + }, + }) + ); var jsonHash = { - evilMinions: [{ id: "1", full_name: "Tom Dale" }] + evilMinions: [{ id: '1', full_name: 'Tom Dale' }], }; var array; @@ -401,29 +466,29 @@ test('normalize should allow for different levels of normalization - attributes' assert.equal(array.data[0].attributes.name, 'Tom Dale'); }); -test("serializeIntoHash", function(assert) { - let league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); +test('serializeIntoHash', function(assert) { + let league = env.store.createRecord('home-planet', { name: 'Umber', id: '123' }); let json = {}; env.restSerializer.serializeIntoHash(json, HomePlanet, league._createSnapshot()); assert.deepEqual(json, { homePlanet: { - name: "Umber" - } + name: 'Umber', + }, }); }); -test("serializeIntoHash with decamelized modelName", function(assert) { - let league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); +test('serializeIntoHash with decamelized modelName', function(assert) { + let league = env.store.createRecord('home-planet', { name: 'Umber', id: '123' }); let json = {}; env.restSerializer.serializeIntoHash(json, HomePlanet, league._createSnapshot()); assert.deepEqual(json, { homePlanet: { - name: "Umber" - } + name: 'Umber', + }, }); }); @@ -431,9 +496,16 @@ test('serializeBelongsTo with async polymorphic', function(assert) { let json = {}; let expected = { evilMinion: '1', evilMinionType: 'evilMinion' }; let evilMinion = env.store.createRecord('evil-minion', { id: 1, name: 'Tomster' }); - let doomsdayDevice = env.store.createRecord('doomsday-device', { id: 2, name: 'Yehuda', evilMinion: evilMinion }); + let doomsdayDevice = env.store.createRecord('doomsday-device', { + id: 2, + name: 'Yehuda', + evilMinion: evilMinion, + }); - env.restSerializer.serializeBelongsTo(doomsdayDevice._createSnapshot(), json, { key: 'evilMinion', options: { polymorphic: true, async: true } }); + env.restSerializer.serializeBelongsTo(doomsdayDevice._createSnapshot(), json, { + key: 'evilMinion', + options: { polymorphic: true, async: true }, + }); assert.deepEqual(json, expected, 'returned JSON is correct'); }); @@ -447,9 +519,16 @@ test('keyForPolymorphicType can be used to overwrite how the type of a polymorph }; let evilMinion = env.store.createRecord('evil-minion', { id: 1, name: 'Tomster' }); - let doomsdayDevice = env.store.createRecord('doomsday-device', { id: 2, name: 'Yehuda', evilMinion: evilMinion }); + let doomsdayDevice = env.store.createRecord('doomsday-device', { + id: 2, + name: 'Yehuda', + evilMinion: evilMinion, + }); - env.restSerializer.serializeBelongsTo(doomsdayDevice._createSnapshot(), json, { key: 'evilMinion', options: { polymorphic: true, async: true } }); + env.restSerializer.serializeBelongsTo(doomsdayDevice._createSnapshot(), json, { + key: 'evilMinion', + options: { polymorphic: true, async: true }, + }); assert.deepEqual(json, expected, 'returned JSON is correct'); }); @@ -459,8 +538,8 @@ test('keyForPolymorphicType can be used to overwrite how the type of a polymorph doomsdayDevice: { id: '1', evilMinion: '2', - typeForEvilMinion: 'evilMinion' - } + typeForEvilMinion: 'evilMinion', + }, }; var expected = { @@ -472,32 +551,41 @@ test('keyForPolymorphicType can be used to overwrite how the type of a polymorph evilMinion: { data: { type: 'evil-minion', - id: '2' - } - } - } + id: '2', + }, + }, + }, }, - included: [] + included: [], }; env.restSerializer.keyForPolymorphicType = function() { return 'typeForEvilMinion'; }; - var normalized = env.restSerializer.normalizeResponse(env.store, DoomsdayDevice, json, null, 'findRecord'); + var normalized = env.restSerializer.normalizeResponse( + env.store, + DoomsdayDevice, + json, + null, + 'findRecord' + ); assert.deepEqual(normalized, expected, 'normalized JSON is correct'); }); test('serializeIntoHash uses payloadKeyFromModelName to normalize the payload root key', function(assert) { - let league = env.store.createRecord('home-planet', { name: "Umber", id: "123" }); + let league = env.store.createRecord('home-planet', { name: 'Umber', id: '123' }); let json = {}; - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend({ - payloadKeyFromModelName(modelName) { - return dasherize(modelName); - } - })); + env.registry.register( + 'serializer:home-planet', + DS.RESTSerializer.extend({ + payloadKeyFromModelName(modelName) { + return dasherize(modelName); + }, + }) + ); let serializer = env.store.serializerFor('home-planet'); @@ -505,8 +593,8 @@ test('serializeIntoHash uses payloadKeyFromModelName to normalize the payload ro assert.deepEqual(json, { 'home-planet': { - name: "Umber" - } + name: 'Umber', + }, }); }); @@ -518,10 +606,10 @@ test('normalizeResponse with async polymorphic belongsTo, using { - return deathRay.get('evilMinion'); - }).then((evilMinion) => { - assert.equal(evilMinion.get('eyes'), 3); - }); + store + .findRecord('doomsday-device', 1) + .then(deathRay => { + return deathRay.get('evilMinion'); + }) + .then(evilMinion => { + assert.equal(evilMinion.get('eyes'), 3); + }); }); }); @@ -551,13 +642,15 @@ test('normalizeResponse with async polymorphic belongsTo', function(assert) { var store = env.store; env.adapter.findRecord = () => { return { - doomsdayDevices: [{ - id: 1, - name: "DeathRay", - links: { - evilMinion: '/doomsday-device/1/evil-minion' - } - }] + doomsdayDevices: [ + { + id: 1, + name: 'DeathRay', + links: { + evilMinion: '/doomsday-device/1/evil-minion', + }, + }, + ], }; }; @@ -567,63 +660,75 @@ test('normalizeResponse with async polymorphic belongsTo', function(assert) { id: 1, type: 'yellowMinion', name: 'Alex', - eyes: 3 - } + eyes: 3, + }, }; }; run(function() { - store.findRecord('doomsday-device', 1).then((deathRay) => { - return deathRay.get('evilMinion'); - }).then((evilMinion) => { - assert.equal(evilMinion.get('eyes'), 3); - }); + store + .findRecord('doomsday-device', 1) + .then(deathRay => { + return deathRay.get('evilMinion'); + }) + .then(evilMinion => { + assert.equal(evilMinion.get('eyes'), 3); + }); }); }); test('normalizeResponse with async polymorphic hasMany', function(assert) { - SuperVillain.reopen({ evilMinions: DS.hasMany('evil-minion', { async: true, polymorphic: true }) }); + SuperVillain.reopen({ + evilMinions: DS.hasMany('evil-minion', { async: true, polymorphic: true }), + }); env.registry.register('serializer:application', DS.RESTSerializer.extend()); var store = env.store; env.adapter.findRecord = () => { return { - superVillains: [{ - id: "1", - firstName: "Yehuda", - lastName: "Katz", - links: { - evilMinions: '/super-villain/1/evil-minions' - } - }] + superVillains: [ + { + id: '1', + firstName: 'Yehuda', + lastName: 'Katz', + links: { + evilMinions: '/super-villain/1/evil-minions', + }, + }, + ], }; }; env.adapter.findHasMany = () => { return { - evilMinion: [{ - id: 1, - type: 'yellowMinion', - name: 'Alex', - eyes: 3 - }] + evilMinion: [ + { + id: 1, + type: 'yellowMinion', + name: 'Alex', + eyes: 3, + }, + ], }; }; run(function() { - store.findRecord('super-villain', 1).then((superVillain) => { - return superVillain.get('evilMinions'); - }).then((evilMinions) => { - assert.ok(evilMinions.get('firstObject') instanceof YellowMinion); - assert.equal(evilMinions.get('firstObject.eyes'), 3); - }); + store + .findRecord('super-villain', 1) + .then(superVillain => { + return superVillain.get('evilMinions'); + }) + .then(evilMinions => { + assert.ok(evilMinions.get('firstObject') instanceof YellowMinion); + assert.equal(evilMinions.get('firstObject.eyes'), 3); + }); }); }); -test("normalizeResponse can load secondary records of the same type without affecting the query count", function(assert) { +test('normalizeResponse can load secondary records of the same type without affecting the query count', function(assert) { var jsonHash = { - comments: [{ id: "1", body: "Parent Comment", root: true, children: [2, 3] }], + comments: [{ id: '1', body: 'Parent Comment', root: true, children: [2, 3] }], _comments: [ - { id: "2", body: "Child Comment 1", root: false }, - { id: "3", body: "Child Comment 2", root: false } - ] + { id: '2', body: 'Child Comment 1', root: false }, + { id: '3', body: 'Child Comment 2', root: false }, + ], }; var array; env.registry.register('serializer:comment', DS.JSONSerializer); @@ -633,39 +738,39 @@ test("normalizeResponse can load secondary records of the same type without affe }); assert.deepEqual(array, { - "data": { - "id": "1", - "type": "comment", - "attributes": { - "body": "Parent Comment", - "root": true + data: { + id: '1', + type: 'comment', + attributes: { + body: 'Parent Comment', + root: true, + }, + relationships: { + children: { + data: [{ id: '2', type: 'comment' }, { id: '3', type: 'comment' }], + }, }, - "relationships": { - "children": { - "data": [ - { "id": "2", "type": "comment" }, - { "id": "3", "type": "comment" } - ] - } - } }, - "included": [{ - "id": "2", - "type": "comment", - "attributes": { - "body": "Child Comment 1", - "root": false + included: [ + { + id: '2', + type: 'comment', + attributes: { + body: 'Child Comment 1', + root: false, + }, + relationships: {}, }, - "relationships": {} - }, { - "id": "3", - "type": "comment", - "attributes": { - "body": "Child Comment 2", - "root": false + { + id: '3', + type: 'comment', + attributes: { + body: 'Child Comment 2', + root: false, + }, + relationships: {}, }, - "relationships": {} - }] + ], }); }); @@ -673,12 +778,14 @@ test("don't polymorphically deserialize base on the type key in payload when a t env.registry.register('serializer:application', DS.RESTSerializer.extend()); run(function() { - env.store.push(env.restSerializer.normalizeArrayResponse(env.store, Basket, { - basket: [ - { type: 'bamboo', size: 10, id: '1' }, - { type: 'yellowMinion', size: 10, id: '65536' } - ] - })); + env.store.push( + env.restSerializer.normalizeArrayResponse(env.store, Basket, { + basket: [ + { type: 'bamboo', size: 10, id: '1' }, + { type: 'yellowMinion', size: 10, id: '65536' }, + ], + }) + ); }); const normalRecord = env.store.peekRecord('basket', '1'); @@ -696,9 +803,16 @@ test("don't polymorphically deserialize base on the type key in payload when a t env.registry.register('serializer:application', DS.RESTSerializer.extend()); run(function() { - env.store.push(env.restSerializer.normalizeSingleResponse(env.store, Basket, { - basket: { type: 'yellowMinion', size: 10, id: '65536' } - }, '65536')); + env.store.push( + env.restSerializer.normalizeSingleResponse( + env.store, + Basket, + { + basket: { type: 'yellowMinion', size: 10, id: '65536' }, + }, + '65536' + ) + ); }); const clashingRecord = env.store.peekRecord('basket', '65536'); @@ -707,49 +821,55 @@ test("don't polymorphically deserialize base on the type key in payload when a t assert.strictEqual(clashingRecord.get('size'), 10); }); - test("don't polymorphically deserialize based on the type key in payload when a relationship exists named type", function(assert) { env.registry.register('serializer:application', DS.RESTSerializer.extend()); env.adapter.findRecord = () => { return { containers: [{ id: 42, volume: '10 liters', type: 1 }], - baskets: [{ id: 1, size: 4 }] + baskets: [{ id: 1, size: 4 }], }; }; run(function() { - env.store.findRecord('container', 42).then((container) => { - assert.strictEqual(container.get('volume'), '10 liters'); - return container.get('type'); - }).then((basket) => { - assert.ok(basket instanceof Basket); - assert.equal(basket.get('size'), 4); - }); + env.store + .findRecord('container', 42) + .then(container => { + assert.strictEqual(container.get('volume'), '10 liters'); + return container.get('type'); + }) + .then(basket => { + assert.ok(basket instanceof Basket); + assert.equal(basket.get('size'), 4); + }); }); - }); test('Serializer should respect the attrs hash in links', function(assert) { - env.registry.register("serializer:super-villain", DS.RESTSerializer.extend({ - attrs: { - evilMinions: { key: 'my_minions' } - } - })); + env.registry.register( + 'serializer:super-villain', + DS.RESTSerializer.extend({ + attrs: { + evilMinions: { key: 'my_minions' }, + }, + }) + ); var jsonHash = { - "super-villains": [ + 'super-villains': [ { firstName: 'Tom', lastName: 'Dale', links: { - my_minions: 'me/minions' - } - } - ] + my_minions: 'me/minions', + }, + }, + ], }; - var documentHash = env.container.lookup("serializer:super-villain").normalizeSingleResponse(env.store, SuperVillain, jsonHash); + var documentHash = env.container + .lookup('serializer:super-villain') + .normalizeSingleResponse(env.store, SuperVillain, jsonHash); assert.equal(documentHash.data.relationships.evilMinions.links.related, 'me/minions'); }); @@ -757,19 +877,21 @@ test('Serializer should respect the attrs hash in links', function(assert) { // https://github.com/emberjs/data/issues/3805 test('normalizes sideloaded single record so that it sideloads correctly - belongsTo - GH-3805', function(assert) { env.registry.register('serializer:evil-minion', DS.JSONSerializer); - env.registry.register("serializer:doomsday-device", DS.RESTSerializer.extend()); + env.registry.register('serializer:doomsday-device', DS.RESTSerializer.extend()); let payload = { doomsdayDevice: { id: 1, - evilMinion: 2 + evilMinion: 2, }, evilMinion: { id: 2, - doomsdayDevice: 1 - } + doomsdayDevice: 1, + }, }; - let document = env.store.serializerFor('doomsday-device').normalizeSingleResponse(env.store, DoomsdayDevice, payload); + let document = env.store + .serializerFor('doomsday-device') + .normalizeSingleResponse(env.store, DoomsdayDevice, payload); assert.equal(document.data.relationships.evilMinion.data.id, 2); assert.equal(document.included.length, 1); assert.deepEqual(document.included[0], { @@ -780,29 +902,31 @@ test('normalizes sideloaded single record so that it sideloads correctly - belon doomsdayDevice: { data: { id: '1', - type: 'doomsday-device' - } - } - } + type: 'doomsday-device', + }, + }, + }, }); }); // https://github.com/emberjs/data/issues/3805 test('normalizes sideloaded single record so that it sideloads correctly - hasMany - GH-3805', function(assert) { env.registry.register('serializer:super-villain', DS.JSONSerializer); - env.registry.register("serializer:home-planet", DS.RESTSerializer.extend()); + env.registry.register('serializer:home-planet', DS.RESTSerializer.extend()); let payload = { homePlanet: { id: 1, - superVillains: [2] + superVillains: [2], }, superVillain: { id: 2, - homePlanet: 1 - } + homePlanet: 1, + }, }; - let document = env.store.serializerFor('home-planet').normalizeSingleResponse(env.store, HomePlanet, payload); + let document = env.store + .serializerFor('home-planet') + .normalizeSingleResponse(env.store, HomePlanet, payload); assert.equal(document.data.relationships.superVillains.data.length, 1); assert.equal(document.data.relationships.superVillains.data[0].id, 2); @@ -815,9 +939,9 @@ test('normalizes sideloaded single record so that it sideloads correctly - hasMa homePlanet: { data: { id: '1', - type: 'home-planet' - } - } - } + type: 'home-planet', + }, + }, + }, }); }); diff --git a/tests/integration/setup-container-test.js b/tests/integration/setup-container-test.js index eb61d686a0b..fcf890a972b 100644 --- a/tests/integration/setup-container-test.js +++ b/tests/integration/setup-container-test.js @@ -15,7 +15,7 @@ let container, registry, application; initialization and dependency injection API. */ -module("integration/setup-container - Setting up a container", { +module('integration/setup-container - Setting up a container', { beforeEach() { application = run(() => Application.create()); @@ -35,19 +35,22 @@ module("integration/setup-container - Setting up a container", { afterEach() { run(() => application.destroy()); - } + }, }); -test("The store should be registered into a container.", function(assert) { - assert.ok(container.lookup('service:store') instanceof Store, "the custom store is instantiated"); +test('The store should be registered into a container.', function(assert) { + assert.ok(container.lookup('service:store') instanceof Store, 'the custom store is instantiated'); }); -test("The store should be registered into the container as a service.", function(assert) { - assert.ok(container.lookup('service:store') instanceof Store, "the store as a service is registered"); +test('The store should be registered into the container as a service.', function(assert) { + assert.ok( + container.lookup('service:store') instanceof Store, + 'the store as a service is registered' + ); }); -test("If a store is instantiated, it should be made available to each controller.", function(assert) { +test('If a store is instantiated, it should be made available to each controller.', function(assert) { registry.register('controller:foo', EmberObject.extend({})); let fooController = container.lookup('controller:foo'); - assert.ok(fooController.get('store') instanceof Store, "the store was injected"); + assert.ok(fooController.get('store') instanceof Store, 'the store was injected'); }); diff --git a/tests/integration/snapshot-test.js b/tests/integration/snapshot-test.js index f9e79980a00..5513e86c5e8 100644 --- a/tests/integration/snapshot-test.js +++ b/tests/integration/snapshot-test.js @@ -5,25 +5,25 @@ import setupStore from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; import DS from 'ember-data'; -const { Model, attr, hasMany,belongsTo, Snapshot } = DS; +const { Model, attr, hasMany, belongsTo, Snapshot } = DS; let env, Post, Comment; -module("integration/snapshot - Snapshot", { +module('integration/snapshot - Snapshot', { beforeEach() { Post = Model.extend({ author: attr(), title: attr(), - comments: hasMany({ async: true }) + comments: hasMany({ async: true }), }); Comment = Model.extend({ body: attr(), - post: belongsTo({ async: true }) + post: belongsTo({ async: true }), }); env = setupStore({ post: Post, - comment: Comment + comment: Comment, }); }, @@ -31,25 +31,25 @@ module("integration/snapshot - Snapshot", { run(() => { env.store.destroy(); }); - } + }, }); test('snapshot.attributes() includes defaultValues when appropriate', function(assert) { const Address = Model.extend({ street: attr(), country: attr({ defaultValue: 'USA' }), - state: attr({ defaultValue: () => 'CA' }) + state: attr({ defaultValue: () => 'CA' }), }); let { store } = setupStore({ - address: Address + address: Address, }); let newAddress = store.createRecord('address', {}); let snapshot = newAddress._createSnapshot(); let expected = { - country: "USA", - state: "CA", - street: undefined + country: 'USA', + state: 'CA', + street: undefined, }; assert.ok(snapshot instanceof Snapshot, 'snapshot is an instance of Snapshot'); @@ -58,7 +58,7 @@ test('snapshot.attributes() includes defaultValues when appropriate', function(a run(() => store.destroy()); }); -test("record._createSnapshot() returns a snapshot", function(assert) { +test('record._createSnapshot() returns a snapshot', function(assert) { assert.expect(1); run(() => { @@ -67,9 +67,9 @@ test("record._createSnapshot() returns a snapshot", function(assert) { type: 'post', id: '1', attributes: { - title: 'Hello World' - } - } + title: 'Hello World', + }, + }, }); let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); @@ -78,7 +78,7 @@ test("record._createSnapshot() returns a snapshot", function(assert) { }); }); -test("snapshot.id, snapshot.type and snapshot.modelName returns correctly", function(assert) { +test('snapshot.id, snapshot.type and snapshot.modelName returns correctly', function(assert) { assert.expect(3); run(() => { @@ -87,9 +87,9 @@ test("snapshot.id, snapshot.type and snapshot.modelName returns correctly", func type: 'post', id: '1', attributes: { - title: 'Hello World' - } - } + title: 'Hello World', + }, + }, }); let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); @@ -105,7 +105,7 @@ test('snapshot.type loads the class lazily', function(assert) { let postClassLoaded = false; let modelFactoryFor = env.store._modelFactoryFor; - env.store._modelFactoryFor = (name) => { + env.store._modelFactoryFor = name => { if (name === 'post') { postClassLoaded = true; } @@ -118,9 +118,9 @@ test('snapshot.type loads the class lazily', function(assert) { type: 'post', id: '1', attributes: { - title: 'Hello World' - } - } + title: 'Hello World', + }, + }, }); let postInternalModel = env.store._internalModelForId('post', 1); let snapshot = postInternalModel.createSnapshot(); @@ -141,9 +141,9 @@ test('an initial findRecord call has no record for internal-model when a snapsho type: 'post', id: '1', attributes: { - title: 'Hello World' - } - } + title: 'Hello World', + }, + }, }); }; @@ -153,21 +153,23 @@ test('an initial findRecord call has no record for internal-model when a snapsho test('snapshots for un-materialized internal-models generate attributes lazily', function(assert) { assert.expect(2); - run(() => env.store._push({ - data: { - type: 'post', - id: '1', - attributes: { - title: 'Hello World' - } - } - })); + run(() => + env.store._push({ + data: { + type: 'post', + id: '1', + attributes: { + title: 'Hello World', + }, + }, + }) + ); let postInternalModel = env.store._internalModelForId('post', 1); let snapshot = postInternalModel.createSnapshot(); let expected = { author: undefined, - title: 'Hello World' + title: 'Hello World', }; assert.equal(snapshot.__attributes, null, 'attributes were not populated initially'); @@ -178,27 +180,29 @@ test('snapshots for un-materialized internal-models generate attributes lazily', test('snapshots for materialized internal-models generate attributes greedily', function(assert) { assert.expect(1); - run(() => env.store.push({ - data: { - type: 'post', - id: '1', - attributes: { - title: 'Hello World' - } - } - })); + run(() => + env.store.push({ + data: { + type: 'post', + id: '1', + attributes: { + title: 'Hello World', + }, + }, + }) + ); let postInternalModel = env.store._internalModelForId('post', 1); let snapshot = postInternalModel.createSnapshot(); let expected = { author: undefined, - title: 'Hello World' + title: 'Hello World', }; assert.deepEqual(snapshot.__attributes, expected, 'attributes were populated initially'); }); -test("snapshot.attr() does not change when record changes", function(assert) { +test('snapshot.attr() does not change when record changes', function(assert) { assert.expect(2); run(() => { @@ -207,9 +211,9 @@ test("snapshot.attr() does not change when record changes", function(assert) { type: 'post', id: '1', attributes: { - title: 'Hello World' - } - } + title: 'Hello World', + }, + }, }); let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); @@ -220,7 +224,7 @@ test("snapshot.attr() does not change when record changes", function(assert) { }); }); -test("snapshot.attr() throws an error attribute not found", function(assert) { +test('snapshot.attr() throws an error attribute not found', function(assert) { assert.expect(1); run(() => { @@ -229,20 +233,24 @@ test("snapshot.attr() throws an error attribute not found", function(assert) { type: 'post', id: '1', attributes: { - title: 'Hello World' - } - } + title: 'Hello World', + }, + }, }); let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); - assert.throws(() => { - snapshot.attr('unknown'); - }, /has no attribute named 'unknown' defined/, 'attr throws error'); + assert.throws( + () => { + snapshot.attr('unknown'); + }, + /has no attribute named 'unknown' defined/, + 'attr throws error' + ); }); }); -test("snapshot.attributes() returns a copy of all attributes for the current snapshot", function(assert) { +test('snapshot.attributes() returns a copy of all attributes for the current snapshot', function(assert) { assert.expect(1); run(() => { @@ -251,20 +259,24 @@ test("snapshot.attributes() returns a copy of all attributes for the current sna type: 'post', id: '1', attributes: { - title: 'Hello World' - } - } + title: 'Hello World', + }, + }, }); let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); let attributes = snapshot.attributes(); - assert.deepEqual(attributes, { author: undefined, title: 'Hello World' }, 'attributes are returned correctly'); + assert.deepEqual( + attributes, + { author: undefined, title: 'Hello World' }, + 'attributes are returned correctly' + ); }); }); -test("snapshot.changedAttributes() returns a copy of all changed attributes for the current snapshot", function(assert) { +test('snapshot.changedAttributes() returns a copy of all changed attributes for the current snapshot', function(assert) { assert.expect(1); run(() => { @@ -273,9 +285,9 @@ test("snapshot.changedAttributes() returns a copy of all changed attributes for type: 'post', id: '1', attributes: { - title: 'Hello World' - } - } + title: 'Hello World', + }, + }, }); let post = env.store.peekRecord('post', 1); post.set('title', 'Hello World!'); @@ -283,11 +295,15 @@ test("snapshot.changedAttributes() returns a copy of all changed attributes for let changes = snapshot.changedAttributes(); - assert.deepEqual(changes.title, ['Hello World', 'Hello World!'], 'changed attributes are returned correctly'); + assert.deepEqual( + changes.title, + ['Hello World', 'Hello World!'], + 'changed attributes are returned correctly' + ); }); }); -test("snapshot.belongsTo() returns undefined if relationship is undefined", function(assert) { +test('snapshot.belongsTo() returns undefined if relationship is undefined', function(assert) { assert.expect(1); run(() => { @@ -296,9 +312,9 @@ test("snapshot.belongsTo() returns undefined if relationship is undefined", func type: 'comment', id: '1', attributes: { - body: 'This is comment' - } - } + body: 'This is comment', + }, + }, }); let comment = env.store.peekRecord('comment', 1); let snapshot = comment._createSnapshot(); @@ -308,29 +324,32 @@ test("snapshot.belongsTo() returns undefined if relationship is undefined", func }); }); -test("snapshot.belongsTo() returns null if relationship is unset", function(assert) { +test('snapshot.belongsTo() returns null if relationship is unset', function(assert) { assert.expect(1); run(() => { env.store.push({ - data: [{ - type: 'post', - id: '1', - attributes: { - title: 'Hello World' - } - }, { - type: 'comment', - id: '2', - attributes: { - body: 'This is comment' + data: [ + { + type: 'post', + id: '1', + attributes: { + title: 'Hello World', + }, }, - relationships: { - post: { - data: null - } - } - }] + { + type: 'comment', + id: '2', + attributes: { + body: 'This is comment', + }, + relationships: { + post: { + data: null, + }, + }, + }, + ], }); let comment = env.store.peekRecord('comment', 2); let snapshot = comment._createSnapshot(); @@ -340,29 +359,32 @@ test("snapshot.belongsTo() returns null if relationship is unset", function(asse }); }); -test("snapshot.belongsTo() returns a snapshot if relationship is set", function(assert) { +test('snapshot.belongsTo() returns a snapshot if relationship is set', function(assert) { assert.expect(3); run(() => { env.store.push({ - data: [{ - type: 'post', - id: '1', - attributes: { - title: 'Hello World' - } - }, { - type: 'comment', - id: '2', - attributes: { - body: 'This is comment' + data: [ + { + type: 'post', + id: '1', + attributes: { + title: 'Hello World', + }, }, - relationships: { - post: { - data: { type: 'post', id: '1' } - } - } - }] + { + type: 'comment', + id: '2', + attributes: { + body: 'This is comment', + }, + relationships: { + post: { + data: { type: 'post', id: '1' }, + }, + }, + }, + ], }); let comment = env.store.peekRecord('comment', 2); let snapshot = comment._createSnapshot(); @@ -374,29 +396,32 @@ test("snapshot.belongsTo() returns a snapshot if relationship is set", function( }); }); -test("snapshot.belongsTo() returns null if relationship is deleted", function(assert) { +test('snapshot.belongsTo() returns null if relationship is deleted', function(assert) { assert.expect(1); run(() => { env.store.push({ - data: [{ - type: 'post', - id: '1', - attributes: { - title: 'Hello World' - } - }, { - type: 'comment', - id: '2', - attributes: { - body: 'This is comment' + data: [ + { + type: 'post', + id: '1', + attributes: { + title: 'Hello World', + }, }, - relationships: { - post: { - data: { type: 'post', id: '1' } - } - } - }] + { + type: 'comment', + id: '2', + attributes: { + body: 'This is comment', + }, + relationships: { + post: { + data: { type: 'post', id: '1' }, + }, + }, + }, + ], }); let post = env.store.peekRecord('post', 1); let comment = env.store.peekRecord('comment', 2); @@ -410,7 +435,7 @@ test("snapshot.belongsTo() returns null if relationship is deleted", function(as }); }); -test("snapshot.belongsTo() returns undefined if relationship is a link", function(assert) { +test('snapshot.belongsTo() returns undefined if relationship is a link', function(assert) { assert.expect(1); run(() => { @@ -419,16 +444,16 @@ test("snapshot.belongsTo() returns undefined if relationship is a link", functio type: 'comment', id: '2', attributes: { - body: 'This is comment' + body: 'This is comment', }, relationships: { post: { links: { - related: 'post' - } - } - } - } + related: 'post', + }, + }, + }, + }, }); let comment = env.store.peekRecord('comment', 2); let snapshot = comment._createSnapshot(); @@ -447,20 +472,24 @@ test("snapshot.belongsTo() throws error if relation doesn't exist", function(ass type: 'post', id: '1', attributes: { - title: 'Hello World' - } - } + title: 'Hello World', + }, + }, }); let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); - assert.throws(() => { - snapshot.belongsTo('unknown'); - }, /has no belongsTo relationship named 'unknown'/, 'throws error'); + assert.throws( + () => { + snapshot.belongsTo('unknown'); + }, + /has no belongsTo relationship named 'unknown'/, + 'throws error' + ); }); }); -test("snapshot.belongsTo() returns a snapshot if relationship link has been fetched", function(assert) { +test('snapshot.belongsTo() returns a snapshot if relationship link has been fetched', function(assert) { assert.expect(2); env.adapter.findBelongsTo = function(store, snapshot, link, relationship) { @@ -473,16 +502,16 @@ test("snapshot.belongsTo() returns a snapshot if relationship link has been fetc type: 'comment', id: '2', attributes: { - body: 'This is comment' + body: 'This is comment', }, relationships: { post: { links: { - related: 'post' - } - } - } - } + related: 'post', + }, + }, + }, + }, }); let comment = env.store.peekRecord('comment', 2); @@ -496,24 +525,27 @@ test("snapshot.belongsTo() returns a snapshot if relationship link has been fetc }); }); -test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when adding an object to a hasMany relationship", function(assert) { +test('snapshot.belongsTo() and snapshot.hasMany() returns correctly when adding an object to a hasMany relationship', function(assert) { assert.expect(4); return run(() => { env.store.push({ - data: [{ - type: 'post', - id: '1', - attributes: { - title: 'Hello World' - } - }, { - type: 'comment', - id: '2', - attributes: { - body: 'This is comment' - } - }] + data: [ + { + type: 'post', + id: '1', + attributes: { + title: 'Hello World', + }, + }, + { + type: 'comment', + id: '2', + attributes: { + body: 'This is comment', + }, + }, + ], }); let post = env.store.peekRecord('post', 1); let comment = env.store.peekRecord('comment', 2); @@ -527,33 +559,46 @@ test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when adding let hasManyRelationship = postSnapshot.hasMany('comments'); let belongsToRelationship = commentSnapshot.belongsTo('post'); - assert.ok(hasManyRelationship instanceof Array, 'hasMany relationship is an instance of Array'); + assert.ok( + hasManyRelationship instanceof Array, + 'hasMany relationship is an instance of Array' + ); assert.equal(hasManyRelationship.length, 1, 'hasMany relationship contains related object'); - assert.ok(belongsToRelationship instanceof Snapshot, 'belongsTo relationship is an instance of Snapshot'); - assert.equal(belongsToRelationship.attr('title'), 'Hello World', 'belongsTo relationship contains related object'); + assert.ok( + belongsToRelationship instanceof Snapshot, + 'belongsTo relationship is an instance of Snapshot' + ); + assert.equal( + belongsToRelationship.attr('title'), + 'Hello World', + 'belongsTo relationship contains related object' + ); }); }); }); -test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when setting an object to a belongsTo relationship", function(assert) { +test('snapshot.belongsTo() and snapshot.hasMany() returns correctly when setting an object to a belongsTo relationship', function(assert) { assert.expect(4); run(() => { env.store.push({ - data: [{ - type: 'post', - id: '1', - attributes: { - title: 'Hello World' - } - }, { - type: 'comment', - id: '2', - attributes: { - body: 'This is comment' - } - }] + data: [ + { + type: 'post', + id: '1', + attributes: { + title: 'Hello World', + }, + }, + { + type: 'comment', + id: '2', + attributes: { + body: 'This is comment', + }, + }, + ], }); let post = env.store.peekRecord('post', 1); let comment = env.store.peekRecord('comment', 2); @@ -569,34 +614,44 @@ test("snapshot.belongsTo() and snapshot.hasMany() returns correctly when setting assert.ok(hasManyRelationship instanceof Array, 'hasMany relationship is an instance of Array'); assert.equal(hasManyRelationship.length, 1, 'hasMany relationship contains related object'); - assert.ok(belongsToRelationship instanceof Snapshot, 'belongsTo relationship is an instance of Snapshot'); - assert.equal(belongsToRelationship.attr('title'), 'Hello World', 'belongsTo relationship contains related object'); + assert.ok( + belongsToRelationship instanceof Snapshot, + 'belongsTo relationship is an instance of Snapshot' + ); + assert.equal( + belongsToRelationship.attr('title'), + 'Hello World', + 'belongsTo relationship contains related object' + ); }); }); -test("snapshot.belongsTo() returns ID if option.id is set", function(assert) { +test('snapshot.belongsTo() returns ID if option.id is set', function(assert) { assert.expect(1); run(() => { env.store.push({ - data: [{ - type: 'post', - id: '1', - attributes: { - title: 'Hello World' - } - }, { - type: 'comment', - id: '2', - attributes: { - body: 'This is comment' + data: [ + { + type: 'post', + id: '1', + attributes: { + title: 'Hello World', + }, }, - relationships: { - post: { - data: { type: 'post', id: '1' } - } - } - }] + { + type: 'comment', + id: '2', + attributes: { + body: 'This is comment', + }, + relationships: { + post: { + data: { type: 'post', id: '1' }, + }, + }, + }, + ], }); let comment = env.store.peekRecord('comment', 2); let snapshot = comment._createSnapshot(); @@ -606,29 +661,32 @@ test("snapshot.belongsTo() returns ID if option.id is set", function(assert) { }); }); -test("snapshot.belongsTo() returns null if option.id is set but relationship was deleted", function(assert) { +test('snapshot.belongsTo() returns null if option.id is set but relationship was deleted', function(assert) { assert.expect(1); run(() => { env.store.push({ - data: [{ - type: 'post', - id: '1', - attributes: { - title: 'Hello World' - } - }, { - type: 'comment', - id: '2', - attributes: { - body: 'This is comment' + data: [ + { + type: 'post', + id: '1', + attributes: { + title: 'Hello World', + }, }, - relationships: { - post: { - data: { type: 'post', id: '1' } - } - } - }] + { + type: 'comment', + id: '2', + attributes: { + body: 'This is comment', + }, + relationships: { + post: { + data: { type: 'post', id: '1' }, + }, + }, + }, + ], }); let post = env.store.peekRecord('post', 1); let comment = env.store.peekRecord('comment', 2); @@ -642,7 +700,7 @@ test("snapshot.belongsTo() returns null if option.id is set but relationship was }); }); -test("snapshot.hasMany() returns undefined if relationship is undefined", function(assert) { +test('snapshot.hasMany() returns undefined if relationship is undefined', function(assert) { assert.expect(1); run(() => { @@ -651,9 +709,9 @@ test("snapshot.hasMany() returns undefined if relationship is undefined", functi type: 'post', id: '1', attributes: { - title: 'Hello World' - } - } + title: 'Hello World', + }, + }, }); let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); @@ -663,7 +721,7 @@ test("snapshot.hasMany() returns undefined if relationship is undefined", functi }); }); -test("snapshot.hasMany() returns empty array if relationship is empty", function(assert) { +test('snapshot.hasMany() returns empty array if relationship is empty', function(assert) { assert.expect(2); run(() => { @@ -672,14 +730,14 @@ test("snapshot.hasMany() returns empty array if relationship is empty", function type: 'post', id: '1', attributes: { - title: 'Hello World' + title: 'Hello World', }, relationships: { comments: { - data: [] - } - } - } + data: [], + }, + }, + }, }); let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); @@ -690,38 +748,39 @@ test("snapshot.hasMany() returns empty array if relationship is empty", function }); }); -test("snapshot.hasMany() returns array of snapshots if relationship is set", function(assert) { +test('snapshot.hasMany() returns array of snapshots if relationship is set', function(assert) { assert.expect(5); run(() => { env.store.push({ - data: [{ - type: 'comment', - id: '1', - attributes: { - body: 'This is the first comment' - } - }, { - type: 'comment', - id: '2', - attributes: { - body: 'This is the second comment' - } - }, { - type: 'post', - id: '3', - attributes: { - title: 'Hello World' + data: [ + { + type: 'comment', + id: '1', + attributes: { + body: 'This is the first comment', + }, }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' } - ] - } - } - }] + { + type: 'comment', + id: '2', + attributes: { + body: 'This is the second comment', + }, + }, + { + type: 'post', + id: '3', + attributes: { + title: 'Hello World', + }, + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }, { type: 'comment', id: '2' }], + }, + }, + }, + ], }); let post = env.store.peekRecord('post', 3); let snapshot = post._createSnapshot(); @@ -735,42 +794,47 @@ test("snapshot.hasMany() returns array of snapshots if relationship is set", fun assert.ok(relationship1 instanceof Snapshot, 'relationship item is an instance of Snapshot'); assert.equal(relationship1.id, '1', 'relationship item id is correct'); - assert.equal(relationship1.attr('body'), 'This is the first comment', 'relationship item body is correct'); + assert.equal( + relationship1.attr('body'), + 'This is the first comment', + 'relationship item body is correct' + ); }); }); -test("snapshot.hasMany() returns empty array if relationship records are deleted", function(assert) { +test('snapshot.hasMany() returns empty array if relationship records are deleted', function(assert) { assert.expect(2); run(() => { env.store.push({ - data: [{ - type: 'comment', - id: '1', - attributes: { - body: 'This is the first comment' - } - }, { - type: 'comment', - id: '2', - attributes: { - body: 'This is the second comment' - } - }, { - type: 'post', - id: '3', - attributes: { - title: 'Hello World' + data: [ + { + type: 'comment', + id: '1', + attributes: { + body: 'This is the first comment', + }, }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' } - ] - } - } - }] + { + type: 'comment', + id: '2', + attributes: { + body: 'This is the second comment', + }, + }, + { + type: 'post', + id: '3', + attributes: { + title: 'Hello World', + }, + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }, { type: 'comment', id: '2' }], + }, + }, + }, + ], }); let comment1 = env.store.peekRecord('comment', 1); let comment2 = env.store.peekRecord('comment', 2); @@ -787,7 +851,7 @@ test("snapshot.hasMany() returns empty array if relationship records are deleted }); }); -test("snapshot.hasMany() returns array of IDs if option.ids is set", function(assert) { +test('snapshot.hasMany() returns array of IDs if option.ids is set', function(assert) { assert.expect(1); run(() => { @@ -796,17 +860,14 @@ test("snapshot.hasMany() returns array of IDs if option.ids is set", function(as type: 'post', id: '1', attributes: { - title: 'Hello World' + title: 'Hello World', }, relationships: { comments: { - data: [ - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - } + data: [{ type: 'comment', id: '2' }, { type: 'comment', id: '3' }], + }, + }, + }, }); let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); @@ -816,38 +877,39 @@ test("snapshot.hasMany() returns array of IDs if option.ids is set", function(as }); }); -test("snapshot.hasMany() returns empty array of IDs if option.ids is set but relationship records were deleted", function(assert) { +test('snapshot.hasMany() returns empty array of IDs if option.ids is set but relationship records were deleted', function(assert) { assert.expect(2); run(() => { env.store.push({ - data: [{ - type: 'comment', - id: '1', - attributes: { - body: 'This is the first comment' - } - }, { - type: 'comment', - id: '2', - attributes: { - body: 'This is the second comment' - } - }, { - type: 'post', - id: '3', - attributes: { - title: 'Hello World' + data: [ + { + type: 'comment', + id: '1', + attributes: { + body: 'This is the first comment', + }, }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' } - ] - } - } - }] + { + type: 'comment', + id: '2', + attributes: { + body: 'This is the second comment', + }, + }, + { + type: 'post', + id: '3', + attributes: { + title: 'Hello World', + }, + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }, { type: 'comment', id: '2' }], + }, + }, + }, + ], }); let comment1 = env.store.peekRecord('comment', 1); let comment2 = env.store.peekRecord('comment', 2); @@ -864,7 +926,7 @@ test("snapshot.hasMany() returns empty array of IDs if option.ids is set but rel }); }); -test("snapshot.hasMany() returns undefined if relationship is a link", function(assert) { +test('snapshot.hasMany() returns undefined if relationship is a link', function(assert) { assert.expect(1); run(() => { @@ -873,16 +935,16 @@ test("snapshot.hasMany() returns undefined if relationship is a link", function( type: 'post', id: '1', attributes: { - title: 'Hello World' + title: 'Hello World', }, relationships: { comments: { links: { - related: 'comments' - } - } - } - } + related: 'comments', + }, + }, + }, + }, }); let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); @@ -892,11 +954,11 @@ test("snapshot.hasMany() returns undefined if relationship is a link", function( }); }); -test("snapshot.hasMany() returns array of snapshots if relationship link has been fetched", function(assert) { +test('snapshot.hasMany() returns array of snapshots if relationship link has been fetched', function(assert) { assert.expect(2); env.adapter.findHasMany = function(store, snapshot, link, relationship) { - return resolve({ data: [{ id: 2, type: 'comment', attributes: { body: 'This is comment' } }]}); + return resolve({ data: [{ id: 2, type: 'comment', attributes: { body: 'This is comment' } }] }); }; return run(() => { @@ -905,16 +967,16 @@ test("snapshot.hasMany() returns array of snapshots if relationship link has bee type: 'post', id: '1', attributes: { - title: 'Hello World' + title: 'Hello World', }, relationships: { comments: { links: { - related: 'comments' - } - } - } - } + related: 'comments', + }, + }, + }, + }, }); let post = env.store.peekRecord('post', 1); @@ -938,58 +1000,67 @@ test("snapshot.hasMany() throws error if relation doesn't exist", function(asser type: 'post', id: '1', attributes: { - title: 'Hello World' - } - } + title: 'Hello World', + }, + }, }); let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); - assert.throws(() => { - snapshot.hasMany('unknown'); - }, /has no hasMany relationship named 'unknown'/, 'throws error'); + assert.throws( + () => { + snapshot.hasMany('unknown'); + }, + /has no hasMany relationship named 'unknown'/, + 'throws error' + ); }); }); -test("snapshot.hasMany() respects the order of items in the relationship", function(assert) { +test('snapshot.hasMany() respects the order of items in the relationship', function(assert) { assert.expect(3); run(() => { env.store.push({ - data: [{ - type: 'comment', - id: '1', - attributes: { - body: 'This is the first comment' - } - }, { - type: 'comment', - id: '2', - attributes: { - body: 'This is the second comment' - } - }, { - type: 'comment', - id: '3', - attributes: { - body: 'This is the third comment' - } - }, { - type: 'post', - id: '4', - attributes: { - title: 'Hello World' + data: [ + { + type: 'comment', + id: '1', + attributes: { + body: 'This is the first comment', + }, }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - }] + { + type: 'comment', + id: '2', + attributes: { + body: 'This is the second comment', + }, + }, + { + type: 'comment', + id: '3', + attributes: { + body: 'This is the third comment', + }, + }, + { + type: 'post', + id: '4', + attributes: { + title: 'Hello World', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], + }, + }, + }, + ], }); let comment3 = env.store.peekRecord('comment', 3); let post = env.store.peekRecord('post', 4); @@ -1006,7 +1077,7 @@ test("snapshot.hasMany() respects the order of items in the relationship", funct }); }); -test("snapshot.eachAttribute() proxies to record", function(assert) { +test('snapshot.eachAttribute() proxies to record', function(assert) { assert.expect(1); run(() => { @@ -1015,9 +1086,9 @@ test("snapshot.eachAttribute() proxies to record", function(assert) { type: 'post', id: '1', attributes: { - title: 'Hello World' - } - } + title: 'Hello World', + }, + }, }); let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); @@ -1028,7 +1099,7 @@ test("snapshot.eachAttribute() proxies to record", function(assert) { }); }); -test("snapshot.eachRelationship() proxies to record", function(assert) { +test('snapshot.eachRelationship() proxies to record', function(assert) { assert.expect(2); let getRelationships = function(snapshot) { @@ -1039,19 +1110,22 @@ test("snapshot.eachRelationship() proxies to record", function(assert) { run(() => { env.store.push({ - data: [{ - type: 'comment', - id: '1', - attributes: { - body: 'This is the first comment' - } - }, { - type: 'post', - id: '2', - attributes: { - title: 'Hello World' - } - }] + data: [ + { + type: 'comment', + id: '1', + attributes: { + body: 'This is the first comment', + }, + }, + { + type: 'post', + id: '2', + attributes: { + title: 'Hello World', + }, + }, + ], }); let comment = env.store.peekRecord('comment', 1); let post = env.store.peekRecord('post', 2); @@ -1061,11 +1135,15 @@ test("snapshot.eachRelationship() proxies to record", function(assert) { assert.deepEqual(getRelationships(snapshot), ['post'], 'relationships are iterated correctly'); snapshot = post._createSnapshot(); - assert.deepEqual(getRelationships(snapshot), ['comments'], 'relationships are iterated correctly'); + assert.deepEqual( + getRelationships(snapshot), + ['comments'], + 'relationships are iterated correctly' + ); }); }); -test("snapshot.belongsTo() does not trigger a call to store._scheduleFetch", function(assert) { +test('snapshot.belongsTo() does not trigger a call to store._scheduleFetch', function(assert) { assert.expect(0); env.store._scheduleFetch = function() { @@ -1078,14 +1156,14 @@ test("snapshot.belongsTo() does not trigger a call to store._scheduleFetch", fun type: 'comment', id: '1', attributes: { - body: 'This is the first comment' + body: 'This is the first comment', }, relationships: { post: { - data: { type: 'post', id: '2' } - } - } - } + data: { type: 'post', id: '2' }, + }, + }, + }, }); let comment = env.store.peekRecord('comment', 1); let snapshot = comment._createSnapshot(); @@ -1094,7 +1172,7 @@ test("snapshot.belongsTo() does not trigger a call to store._scheduleFetch", fun }); }); -test("snapshot.hasMany() does not trigger a call to store._scheduleFetch", function(assert) { +test('snapshot.hasMany() does not trigger a call to store._scheduleFetch', function(assert) { assert.expect(0); env.store._scheduleFetch = function() { @@ -1107,17 +1185,14 @@ test("snapshot.hasMany() does not trigger a call to store._scheduleFetch", funct type: 'post', id: '1', attributes: { - title: 'Hello World' + title: 'Hello World', }, relationships: { comments: { - data: [ - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' } - ] - } - } - } + data: [{ type: 'comment', id: '2' }, { type: 'comment', id: '3' }], + }, + }, + }, }); let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); @@ -1126,7 +1201,7 @@ test("snapshot.hasMany() does not trigger a call to store._scheduleFetch", funct }); }); -test("snapshot.serialize() serializes itself", function(assert) { +test('snapshot.serialize() serializes itself', function(assert) { assert.expect(2); run(() => { @@ -1135,9 +1210,9 @@ test("snapshot.serialize() serializes itself", function(assert) { type: 'post', id: '1', attributes: { - title: 'Hello World' - } - } + title: 'Hello World', + }, + }, }); let post = env.store.peekRecord('post', 1); let snapshot = post._createSnapshot(); @@ -1148,10 +1223,10 @@ test("snapshot.serialize() serializes itself", function(assert) { data: { attributes: { author: undefined, - title: 'Hello World' + title: 'Hello World', }, - type: 'posts' - } + type: 'posts', + }, }; assert.deepEqual(snapshot.serialize(), expected, 'shapshot serializes correctly'); expected.data.id = '1'; diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 50799070505..207b653e201 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -1,7 +1,4 @@ -import RSVP, { - Promise as EmberPromise, - resolve -} from 'rsvp'; +import RSVP, { Promise as EmberPromise, resolve } from 'rsvp'; import { run, next } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; @@ -15,30 +12,30 @@ let store, env; const Person = DS.Model.extend({ name: DS.attr('string'), - cars: DS.hasMany('car', { async: false }) + cars: DS.hasMany('car', { async: false }), }); Person.reopenClass({ toString() { - return 'Person' - } + return 'Person'; + }, }); const Car = DS.Model.extend({ make: DS.attr('string'), model: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); Car.reopenClass({ toString() { return 'Car'; - } + }, }); function initializeStore(adapter) { env = setupStore({ - adapter: adapter + adapter: adapter, }); store = env.store; @@ -46,14 +43,14 @@ function initializeStore(adapter) { env.registry.register('model:person', Person); } -module("integration/store - destroy", { +module('integration/store - destroy', { beforeEach() { initializeStore(DS.Adapter.extend()); }, afterEach() { store = null; env = null; - } + }, }); function tap(obj, methodName, callback) { @@ -85,18 +82,18 @@ test("destroying record during find doesn't cause error", function(assert) { reject(); }); }); - } + }, }); initializeStore(TestAdapter); - let type = "car"; + let type = 'car'; let id = 1; return run(() => store.findRecord(type, id).then(done, done)); }); -test("find calls do not resolve when the store is destroyed", function(assert) { +test('find calls do not resolve when the store is destroyed', function(assert) { assert.expect(0); let done = assert.async(); @@ -104,17 +101,16 @@ test("find calls do not resolve when the store is destroyed", function(assert) { findRecord(store, type, id, snapshot) { store.destroy(); resolve(null); - } + }, }); initializeStore(TestAdapter); - - let type = "car"; + let type = 'car'; let id = 1; store.push = function() { - assert("The test should have destroyed the store by now", store.get("isDestroyed")); + assert('The test should have destroyed the store by now', store.get('isDestroyed')); throw new Error("We shouldn't be pushing data into the store when it is destroyed"); }; @@ -124,37 +120,38 @@ test("find calls do not resolve when the store is destroyed", function(assert) { setTimeout(() => done(), 500); }); -test("destroying the store correctly cleans everything up", function(assert) { +test('destroying the store correctly cleans everything up', function(assert) { let car, person; env.adapter.shouldBackgroundReloadRecord = () => false; run(() => { store.push({ - data: [{ - type: 'car', - id: '1', - attributes: { - make: 'BMC', - model: 'Mini' + data: [ + { + type: 'car', + id: '1', + attributes: { + make: 'BMC', + model: 'Mini', + }, + relationships: { + person: { + data: { type: 'person', id: '1' }, + }, + }, }, - relationships: { - person: { - data: { type: 'person', id: '1' } - } - } - }, { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + cars: { + data: [{ type: 'car', id: '1' }], + }, + }, }, - relationships: { - cars: { - data: [ - { type: 'car', id: '1' } - ] - } - } - }] + ], }); car = store.peekRecord('car', 1); person = store.peekRecord('person', 1); @@ -170,35 +167,63 @@ test("destroying the store correctly cleans everything up", function(assert) { { id: 2, type: 'person', - attributes: { name: 'Yehuda' } - } - ] + attributes: { name: 'Yehuda' }, + }, + ], }; }; - let adapterPopulatedPeople =run(() => { - return adapterPopulatedPeople = store.query('person', { - someCrazy: 'query' - }); + let adapterPopulatedPeople = run(() => { + return (adapterPopulatedPeople = store.query('person', { + someCrazy: 'query', + })); }); let adapterPopulatedPeopleWillDestroy = tap(adapterPopulatedPeople.get('content'), 'willDestroy'); run(() => store.findRecord('person', 2)); - assert.equal(personWillDestroy.called.length, 0, 'expected person.willDestroy to not have been called'); + assert.equal( + personWillDestroy.called.length, + 0, + 'expected person.willDestroy to not have been called' + ); assert.equal(carWillDestroy.called.length, 0, 'expected car.willDestroy to not have been called'); - assert.equal(carsWillDestroy.called.length, 0, 'expected cars.willDestroy to not have been called'); - assert.equal(adapterPopulatedPeopleWillDestroy.called.length, 0, 'expected adapterPopulatedPeople.willDestroy to not have been called'); + assert.equal( + carsWillDestroy.called.length, + 0, + 'expected cars.willDestroy to not have been called' + ); + assert.equal( + adapterPopulatedPeopleWillDestroy.called.length, + 0, + 'expected adapterPopulatedPeople.willDestroy to not have been called' + ); assert.equal(car.get('person'), person, "expected car's person to be the correct person"); - assert.equal(person.get('cars.firstObject'), car, " expected persons cars's firstRecord to be the correct car"); + assert.equal( + person.get('cars.firstObject'), + car, + " expected persons cars's firstRecord to be the correct car" + ); run(store, 'destroy'); - assert.equal(personWillDestroy.called.length, 1, 'expected person to have recieved willDestroy once'); + assert.equal( + personWillDestroy.called.length, + 1, + 'expected person to have recieved willDestroy once' + ); assert.equal(carWillDestroy.called.length, 1, 'expected car to recieve willDestroy once'); - assert.equal(carsWillDestroy.called.length, 1, 'expected person.cars to recieve willDestroy once'); - assert.equal(adapterPopulatedPeopleWillDestroy.called.length, 1, 'expected adapterPopulatedPeople to recieve willDestroy once'); + assert.equal( + carsWillDestroy.called.length, + 1, + 'expected person.cars to recieve willDestroy once' + ); + assert.equal( + adapterPopulatedPeopleWillDestroy.called.length, + 1, + 'expected adapterPopulatedPeople to recieve willDestroy once' + ); }); function ajaxResponse(value) { @@ -207,20 +232,22 @@ function ajaxResponse(value) { }; } -module("integration/store - findRecord"); +module('integration/store - findRecord'); -test("store#findRecord fetches record from server when cached record is not present", function(assert) { +test('store#findRecord fetches record from server when cached record is not present', function(assert) { assert.expect(2); initializeStore(DS.RESTAdapter.extend()); env.registry.register('serializer:application', DS.RESTSerializer); ajaxResponse({ - cars: [{ - id: 20, - make: 'BMC', - model: 'Mini' - }] + cars: [ + { + id: 20, + make: 'BMC', + model: 'Mini', + }, + ], }); let cachedRecordIsPresent = store.hasRecordForId('car', 20); @@ -233,7 +260,7 @@ test("store#findRecord fetches record from server when cached record is not pres }); }); -test("store#findRecord returns cached record immediately and reloads record in the background", function(assert) { +test('store#findRecord returns cached record immediately and reloads record in the background', function(assert) { assert.expect(2); initializeStore(DS.RESTAdapter.extend()); @@ -245,18 +272,20 @@ test("store#findRecord returns cached record immediately and reloads record in t id: '1', attributes: { make: 'BMC', - model: 'Mini' - } - } + model: 'Mini', + }, + }, }); }); ajaxResponse({ - cars: [{ - id: 1, - make: 'BMC', - model: 'Princess' - }] + cars: [ + { + id: 1, + make: 'BMC', + model: 'Princess', + }, + ], }); run(() => { @@ -271,13 +300,13 @@ test("store#findRecord returns cached record immediately and reloads record in t }); }); -test("store#findRecord { reload: true } ignores cached record and reloads record from server", function(assert) { +test('store#findRecord { reload: true } ignores cached record and reloads record from server', function(assert) { assert.expect(2); const testAdapter = DS.RESTAdapter.extend({ shouldReloadRecord(store, type, id, snapshot) { assert.ok(false, 'shouldReloadRecord should not be called when { reload: true }'); - } + }, }); initializeStore(testAdapter); @@ -289,18 +318,20 @@ test("store#findRecord { reload: true } ignores cached record and reloads record id: '1', attributes: { make: 'BMC', - model: 'Mini' - } - } + model: 'Mini', + }, + }, }); }); ajaxResponse({ - cars: [{ - id: 1, - make: 'BMC', - model: 'Princess' - }] + cars: [ + { + id: 1, + make: 'BMC', + model: 'Princess', + }, + ], }); let cachedCar = store.peekRecord('car', 1); @@ -308,13 +339,16 @@ test("store#findRecord { reload: true } ignores cached record and reloads record return run(() => { return store.findRecord('car', 1, { reload: true }).then(car => { - assert.equal(car.get('model'), 'Princess', 'cached record ignored, record reloaded via server'); + assert.equal( + car.get('model'), + 'Princess', + 'cached record ignored, record reloaded via server' + ); }); }); }); - -test("store#findRecord { reload: true } ignores cached record and reloads record from server even after previous findRecord", function(assert) { +test('store#findRecord { reload: true } ignores cached record and reloads record from server even after previous findRecord', function(assert) { assert.expect(5); let calls = 0; @@ -330,11 +364,11 @@ test("store#findRecord { reload: true } ignores cached record and reloads record id: '1', attributes: { make: 'BMC', - model: calls === 1 ? 'Mini' : 'Princess' - } - } + model: calls === 1 ? 'Mini' : 'Princess', + }, + }, }); - } + }, }); initializeStore(testAdapter); @@ -354,17 +388,20 @@ test("store#findRecord { reload: true } ignores cached record and reloads record assert.equal(car.get('model'), 'Princess', 'cached record ignored, record reloaded via server'); }); -test("store#findRecord { backgroundReload: false } returns cached record and does not reload in the background", function(assert) { +test('store#findRecord { backgroundReload: false } returns cached record and does not reload in the background', function(assert) { assert.expect(2); let testAdapter = DS.RESTAdapter.extend({ shouldBackgroundReloadRecord() { - assert.ok(false, 'shouldBackgroundReloadRecord should not be called when { backgroundReload: false }'); + assert.ok( + false, + 'shouldBackgroundReloadRecord should not be called when { backgroundReload: false }' + ); }, findRecord() { assert.ok(false, 'findRecord() should not be called when { backgroundReload: false }'); - } + }, }); initializeStore(testAdapter); @@ -376,14 +413,14 @@ test("store#findRecord { backgroundReload: false } returns cached record and doe id: '1', attributes: { make: 'BMC', - model: 'Mini' - } - } + model: 'Mini', + }, + }, }); }); run(() => { - store.findRecord('car', 1, { backgroundReload: false }).then((car) => { + store.findRecord('car', 1, { backgroundReload: false }).then(car => { assert.equal(car.get('model'), 'Mini', 'cached car record is returned'); }); }); @@ -394,13 +431,16 @@ test("store#findRecord { backgroundReload: false } returns cached record and doe }); }); -test("store#findRecord { backgroundReload: true } returns cached record and reloads record in background", function(assert) { +test('store#findRecord { backgroundReload: true } returns cached record and reloads record in background', function(assert) { assert.expect(2); let testAdapter = DS.RESTAdapter.extend({ shouldBackgroundReloadRecord() { - assert.ok(false, 'shouldBackgroundReloadRecord should not be called when { backgroundReload: true }'); - } + assert.ok( + false, + 'shouldBackgroundReloadRecord should not be called when { backgroundReload: true }' + ); + }, }); initializeStore(testAdapter); @@ -412,22 +452,24 @@ test("store#findRecord { backgroundReload: true } returns cached record and relo id: '1', attributes: { make: 'BMC', - model: 'Mini' - } - } + model: 'Mini', + }, + }, }); }); ajaxResponse({ - cars: [{ - id: 1, - make: 'BMC', - model: 'Princess' - }] + cars: [ + { + id: 1, + make: 'BMC', + model: 'Princess', + }, + ], }); run(() => { - store.findRecord('car', 1, { backgroundReload: true }).then((car) => { + store.findRecord('car', 1, { backgroundReload: true }).then(car => { assert.equal(car.get('model'), 'Mini', 'cached car record is returned'); }); }); @@ -438,7 +480,7 @@ test("store#findRecord { backgroundReload: true } returns cached record and relo }); }); -test("store#findRecord { backgroundReload: false } is ignored if adapter.shouldReloadRecord is true", function(assert) { +test('store#findRecord { backgroundReload: false } is ignored if adapter.shouldReloadRecord is true', function(assert) { assert.expect(2); let testAdapter = DS.RESTAdapter.extend({ @@ -447,8 +489,11 @@ test("store#findRecord { backgroundReload: false } is ignored if adapter.shouldR }, shouldBackgroundReloadRecord() { - assert.ok(false, 'shouldBackgroundReloadRecord should not be called when adapter.shouldReloadRecord = true'); - } + assert.ok( + false, + 'shouldBackgroundReloadRecord should not be called when adapter.shouldReloadRecord = true' + ); + }, }); initializeStore(testAdapter); @@ -460,18 +505,20 @@ test("store#findRecord { backgroundReload: false } is ignored if adapter.shouldR id: '1', attributes: { make: 'BMC', - model: 'Mini' - } - } + model: 'Mini', + }, + }, }); }); ajaxResponse({ - cars: [{ - id: 1, - make: 'BMC', - model: 'Princess' - }] + cars: [ + { + id: 1, + make: 'BMC', + model: 'Princess', + }, + ], }); run(() => { @@ -480,47 +527,56 @@ test("store#findRecord { backgroundReload: false } is ignored if adapter.shouldR }); run(() => { - store.findRecord('car', 1, { backgroundReload: false }).then((car) => { - assert.equal(car.get('model'), 'Princess', 'Car record is reloaded immediately (not in the background)'); + store.findRecord('car', 1, { backgroundReload: false }).then(car => { + assert.equal( + car.get('model'), + 'Princess', + 'Car record is reloaded immediately (not in the background)' + ); }); }); }); -testInDebug('store#findRecord call with `id` of type different than non-empty string or number should trigger an assertion', assert => { - const badValues = ['', undefined, null, NaN, false]; - assert.expect(badValues.length); +testInDebug( + 'store#findRecord call with `id` of type different than non-empty string or number should trigger an assertion', + assert => { + const badValues = ['', undefined, null, NaN, false]; + assert.expect(badValues.length); - initializeStore(DS.RESTAdapter.extend()); + initializeStore(DS.RESTAdapter.extend()); - run(() => { - badValues.map(item => { - assert.expectAssertion(() => { - store.findRecord('car', item); - }, '`id` passed to `findRecord()` has to be non-empty string or number'); + run(() => { + badValues.map(item => { + assert.expectAssertion(() => { + store.findRecord('car', item); + }, '`id` passed to `findRecord()` has to be non-empty string or number'); + }); }); - }); -}); + } +); -module("integration/store - findAll", { +module('integration/store - findAll', { beforeEach() { initializeStore(DS.RESTAdapter.extend()); - } + }, }); -test("Using store#findAll with no records triggers a query", function(assert) { +test('Using store#findAll with no records triggers a query', function(assert) { assert.expect(2); ajaxResponse({ - cars: [{ - id: 1, - make: 'BMC', - model: 'Mini' - }, - { - id: 2, - make: 'BMCW', - model: 'Isetta' - }] + cars: [ + { + id: 1, + make: 'BMC', + model: 'Mini', + }, + { + id: 2, + make: 'BMCW', + model: 'Isetta', + }, + ], }); let cars = store.peekAll('car'); @@ -533,7 +589,7 @@ test("Using store#findAll with no records triggers a query", function(assert) { }); }); -test("Using store#findAll with existing records performs a query in the background, updating existing records and returning new ones", function(assert) { +test('Using store#findAll with existing records performs a query in the background, updating existing records and returning new ones', function(assert) { assert.expect(4); run(() => { @@ -543,23 +599,25 @@ test("Using store#findAll with existing records performs a query in the backgrou id: '1', attributes: { make: 'BMC', - model: 'Mini' - } - } + model: 'Mini', + }, + }, }); }); ajaxResponse({ - cars: [{ - id: 1, - make: 'BMC', - model: 'New Mini' - }, - { - id: 2, - make: 'BMCW', - model: 'Isetta' - }] + cars: [ + { + id: 1, + make: 'BMC', + model: 'New Mini', + }, + { + id: 2, + make: 'BMCW', + model: 'Isetta', + }, + ], }); let cars = store.peekAll('car'); @@ -581,17 +639,20 @@ test("Using store#findAll with existing records performs a query in the backgrou return waiter; }); -test("store#findAll { backgroundReload: false } skips shouldBackgroundReloadAll, returns cached records & does not reload in the background", function(assert) { +test('store#findAll { backgroundReload: false } skips shouldBackgroundReloadAll, returns cached records & does not reload in the background', function(assert) { assert.expect(4); let testAdapter = DS.RESTAdapter.extend({ shouldBackgroundReloadAll() { - assert.ok(false, 'shouldBackgroundReloadAll should not be called when { backgroundReload: false }'); + assert.ok( + false, + 'shouldBackgroundReloadAll should not be called when { backgroundReload: false }' + ); }, findAll() { assert.ok(false, 'findAll() should not be called when { backgroundReload: true }'); - } + }, }); initializeStore(testAdapter); @@ -603,14 +664,14 @@ test("store#findAll { backgroundReload: false } skips shouldBackgroundReloadAll, id: '1', attributes: { make: 'BMC', - model: 'Mini' - } - } + model: 'Mini', + }, + }, }); }); run(() => { - store.findAll('car', { backgroundReload: false }).then((cars) => { + store.findAll('car', { backgroundReload: false }).then(cars => { assert.equal(cars.get('length'), 1, 'single cached car record is returned'); assert.equal(cars.get('firstObject.model'), 'Mini', 'correct cached car record is returned'); }); @@ -619,17 +680,24 @@ test("store#findAll { backgroundReload: false } skips shouldBackgroundReloadAll, run(() => { let cars = store.peekAll('car'); assert.equal(cars.get('length'), 1, 'single cached car record is returned again'); - assert.equal(cars.get('firstObject.model'), 'Mini', 'correct cached car record is returned again'); + assert.equal( + cars.get('firstObject.model'), + 'Mini', + 'correct cached car record is returned again' + ); }); }); -test("store#findAll { backgroundReload: true } skips shouldBackgroundReloadAll, returns cached records, & reloads in background", function(assert) { +test('store#findAll { backgroundReload: true } skips shouldBackgroundReloadAll, returns cached records, & reloads in background', function(assert) { assert.expect(5); let testAdapter = DS.RESTAdapter.extend({ shouldBackgroundReloadAll() { - assert.ok(false, 'shouldBackgroundReloadAll should not be called when { backgroundReload: true }'); - } + assert.ok( + false, + 'shouldBackgroundReloadAll should not be called when { backgroundReload: true }' + ); + }, }); initializeStore(testAdapter); @@ -641,27 +709,29 @@ test("store#findAll { backgroundReload: true } skips shouldBackgroundReloadAll, id: '1', attributes: { make: 'BMC', - model: 'Mini' - } - } + model: 'Mini', + }, + }, }); }); ajaxResponse({ - cars: [{ - id: 1, - make: 'BMC', - model: 'New Mini' - }, - { - id: 2, - make: 'BMCW', - model: 'Isetta' - }] + cars: [ + { + id: 1, + make: 'BMC', + model: 'New Mini', + }, + { + id: 2, + make: 'BMCW', + model: 'Isetta', + }, + ], }); run(() => { - store.findAll('car', { backgroundReload: true }).then((cars) => { + store.findAll('car', { backgroundReload: true }).then(cars => { assert.equal(cars.get('length'), 1, 'single cached car record is returned'); assert.equal(cars.get('firstObject.model'), 'Mini', 'correct cached car record is returned'); }); @@ -675,7 +745,7 @@ test("store#findAll { backgroundReload: true } skips shouldBackgroundReloadAll, }); }); -test("store#findAll { backgroundReload: false } is ignored if adapter.shouldReloadAll is true", function(assert) { +test('store#findAll { backgroundReload: false } is ignored if adapter.shouldReloadAll is true', function(assert) { assert.expect(5); let testAdapter = DS.RESTAdapter.extend({ @@ -684,8 +754,11 @@ test("store#findAll { backgroundReload: false } is ignored if adapter.shouldRelo }, shouldBackgroundReloadAll() { - assert.ok(false, 'shouldBackgroundReloadAll should not be called when adapter.shouldReloadAll = true'); - } + assert.ok( + false, + 'shouldBackgroundReloadAll should not be called when adapter.shouldReloadAll = true' + ); + }, }); initializeStore(testAdapter); @@ -697,23 +770,25 @@ test("store#findAll { backgroundReload: false } is ignored if adapter.shouldRelo id: '1', attributes: { make: 'BMC', - model: 'Mini' - } - } + model: 'Mini', + }, + }, }); }); ajaxResponse({ - cars: [{ - id: 1, - make: 'BMC', - model: 'New Mini' - }, - { - id: 2, - make: 'BMCW', - model: 'Isetta' - }] + cars: [ + { + id: 1, + make: 'BMC', + model: 'New Mini', + }, + { + id: 2, + make: 'BMCW', + model: 'Isetta', + }, + ], }); run(() => { @@ -723,7 +798,7 @@ test("store#findAll { backgroundReload: false } is ignored if adapter.shouldRelo }); return run(() => { - return store.findAll('car', { backgroundReload: false }).then((cars) => { + return store.findAll('car', { backgroundReload: false }).then(cars => { assert.equal(cars.get('length'), 2, 'multiple car records are returned'); assert.equal(cars.get('firstObject.model'), 'New Mini', 'initial car record was updated'); assert.equal(cars.get('lastObject.model'), 'Isetta', 'second car record was loaded'); @@ -731,35 +806,40 @@ test("store#findAll { backgroundReload: false } is ignored if adapter.shouldRelo }); }); -test("store#findAll should eventually return all known records even if they are not in the adapter response", function(assert) { +test('store#findAll should eventually return all known records even if they are not in the adapter response', function(assert) { assert.expect(5); run(() => { store.push({ - data: [{ - type: 'car', - id: '1', - attributes: { - make: 'BMC', - model: 'Mini' - } - }, { - type: 'car', - id: '2', - attributes: { - make: 'BMCW', - model: 'Isetta' - } - }] + data: [ + { + type: 'car', + id: '1', + attributes: { + make: 'BMC', + model: 'Mini', + }, + }, + { + type: 'car', + id: '2', + attributes: { + make: 'BMCW', + model: 'Isetta', + }, + }, + ], }); }); ajaxResponse({ - cars: [{ - id: 1, - make: 'BMC', - model: 'New Mini' - }] + cars: [ + { + id: 1, + make: 'BMC', + model: 'New Mini', + }, + ], }); let cars = store.peekAll('car'); @@ -786,16 +866,17 @@ test("store#findAll should eventually return all known records even if they are return waiter; }); - -test("Using store#fetch on an empty record calls find", function(assert) { +test('Using store#fetch on an empty record calls find', function(assert) { assert.expect(2); ajaxResponse({ - cars: [{ - id: 20, - make: 'BMCW', - model: 'Mini' - }] + cars: [ + { + id: 20, + make: 'BMCW', + model: 'Mini', + }, + ], }); run(() => { @@ -804,16 +885,14 @@ test("Using store#fetch on an empty record calls find", function(assert) { type: 'person', id: '1', attributes: { - name: 'Tom Dale' + name: 'Tom Dale', }, relationships: { cars: { - data: [ - { type: 'car', id: '20' } - ] - } - } - } + data: [{ type: 'car', id: '20' }], + }, + }, + }, }); }); @@ -827,7 +906,7 @@ test("Using store#fetch on an empty record calls find", function(assert) { }); }); -test("Using store#adapterFor should not throw an error when looking up the application adapter", function(assert) { +test('Using store#adapterFor should not throw an error when looking up the application adapter', function(assert) { assert.expect(1); run(() => { @@ -836,8 +915,7 @@ test("Using store#adapterFor should not throw an error when looking up the appli }); }); - -test("Using store#serializerFor should not throw an error when looking up the application serializer", function(assert) { +test('Using store#serializerFor should not throw an error when looking up the application serializer', function(assert) { assert.expect(1); run(() => { @@ -846,13 +924,13 @@ test("Using store#serializerFor should not throw an error when looking up the ap }); }); -module("integration/store - deleteRecord", { +module('integration/store - deleteRecord', { beforeEach() { initializeStore(DS.RESTAdapter.extend()); - } + }, }); -test("Using store#deleteRecord should mark the model for removal", function(assert) { +test('Using store#deleteRecord should mark the model for removal', function(assert) { assert.expect(3); let person; @@ -862,9 +940,9 @@ test("Using store#deleteRecord should mark the model for removal", function(asse type: 'person', id: '1', attributes: { - name: 'Tom Dale' - } - } + name: 'Tom Dale', + }, + }, }); person = store.peekRecord('person', 1); }); @@ -875,26 +953,32 @@ test("Using store#deleteRecord should mark the model for removal", function(asse run(() => store.deleteRecord(person)); - assert.equal(personDeleteRecord.called.length, 1, 'expected person.deleteRecord to have been called'); + assert.equal( + personDeleteRecord.called.length, + 1, + 'expected person.deleteRecord to have been called' + ); assert.ok(person.get('isDeleted'), 'expect person to be isDeleted'); }); -test("Store should accept a null value for `data`", function(assert) { +test('Store should accept a null value for `data`', function(assert) { assert.expect(0); run(() => { store.push({ - data: null + data: null, }); }); }); testInDebug('store#findRecord that returns an array should assert', assert => { - initializeStore(DS.JSONAPIAdapter.extend({ - findRecord() { - return { data: [] }; - } - })); + initializeStore( + DS.JSONAPIAdapter.extend({ + findRecord() { + return { data: [] }; + }, + }) + ); assert.expectAssertion(() => { run(() => { @@ -903,98 +987,103 @@ testInDebug('store#findRecord that returns an array should assert', assert => { }, /expected the primary data returned from a 'findRecord' response to be an object but instead it found an array/); }); -testInDebug('store#didSaveRecord should assert when the response to a save does not include the id', function(assert) { - env.adapter.createRecord = function() { - return {}; - }; +testInDebug( + 'store#didSaveRecord should assert when the response to a save does not include the id', + function(assert) { + env.adapter.createRecord = function() { + return {}; + }; - assert.expectAssertion(() => { - run(() => { - let car = store.createRecord('car'); - car.save(); - }); - }, /Your car record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response./); -}); + assert.expectAssertion(() => { + run(() => { + let car = store.createRecord('car'); + car.save(); + }); + }, /Your car record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response./); + } +); -module("integration/store - queryRecord", { +module('integration/store - queryRecord', { beforeEach() { initializeStore(DS.Adapter.extend()); - } + }, }); -testInDebug('store#queryRecord should assert when normalized payload of adapter has an array an data', function(assert) { - env.adapter.queryRecord = function() { - return { - cars: [{ id: 1 }] +testInDebug( + 'store#queryRecord should assert when normalized payload of adapter has an array an data', + function(assert) { + env.adapter.queryRecord = function() { + return { + cars: [{ id: 1 }], + }; }; - }; - env.serializer.normalizeQueryRecordResponse = function() { - return { - data: [{ id: 1, type: 'car' }] + env.serializer.normalizeQueryRecordResponse = function() { + return { + data: [{ id: 1, type: 'car' }], + }; }; - }; - assert.expectAssertion(() => { - run(() => store.queryRecord('car', {})); - }, /Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array./); -}); + assert.expectAssertion(() => { + run(() => store.queryRecord('car', {})); + }, /Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array./); + } +); test('The store should trap exceptions that are thrown from adapter#findRecord', function(assert) { - assert.expect(1) + assert.expect(1); env.adapter.findRecord = function() { throw new Error('Refusing to find record'); }; run(() => { store.findRecord('car', 1).catch(error => { - assert.equal(error.message, 'Refusing to find record') - }) + assert.equal(error.message, 'Refusing to find record'); + }); }); }); test('The store should trap exceptions that are thrown from adapter#findAll', function(assert) { - assert.expect(1) + assert.expect(1); env.adapter.findAll = function() { throw new Error('Refusing to find all records'); }; run(() => { store.findAll('car').catch(error => { - assert.equal(error.message, 'Refusing to find all records') - }) + assert.equal(error.message, 'Refusing to find all records'); + }); }); }); test('The store should trap exceptions that are thrown from adapter#query', function(assert) { - assert.expect(1) + assert.expect(1); env.adapter.query = function() { throw new Error('Refusing to query records'); }; run(() => { store.query('car', {}).catch(error => { - assert.equal(error.message, 'Refusing to query records') - }) + assert.equal(error.message, 'Refusing to query records'); + }); }); }); test('The store should trap exceptions that are thrown from adapter#queryRecord', function(assert) { - assert.expect(1) + assert.expect(1); env.adapter.queryRecord = function() { throw new Error('Refusing to query record'); }; run(() => { store.queryRecord('car', {}).catch(error => { - assert.equal(error.message, 'Refusing to query record') - }) + assert.equal(error.message, 'Refusing to query record'); + }); }); }); - test('The store should trap exceptions that are thrown from adapter#createRecord', function(assert) { - assert.expect(1) + assert.expect(1); env.adapter.createRecord = function() { throw new Error('Refusing to serialize'); }; @@ -1003,7 +1092,7 @@ test('The store should trap exceptions that are thrown from adapter#createRecord let car = store.createRecord('car'); car.save().catch(error => { - assert.equal(error.message, 'Refusing to serialize') - }) + assert.equal(error.message, 'Refusing to serialize'); + }); }); }); diff --git a/tests/integration/store/json-api-validation-test.js b/tests/integration/store/json-api-validation-test.js index 09906f695b3..4728e67f92f 100644 --- a/tests/integration/store/json-api-validation-test.js +++ b/tests/integration/store/json-api-validation-test.js @@ -8,26 +8,36 @@ import DS from 'ember-data'; var Person, store, env; function payloadError(payload, expectedError, assert) { - env.registry.register('serializer:person', DS.Serializer.extend({ - normalizeResponse(store, type, pld) { - return pld; - } - })); - env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord() { - return resolve(payload); - } - })); - this.expectAssertion(function () { - run(function() { - store.findRecord('person', 1); - }); - }, expectedError, `Payload ${JSON.stringify(payload)} should throw error ${expectedError}`); + env.registry.register( + 'serializer:person', + DS.Serializer.extend({ + normalizeResponse(store, type, pld) { + return pld; + }, + }) + ); + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findRecord() { + return resolve(payload); + }, + }) + ); + this.expectAssertion( + function() { + run(function() { + store.findRecord('person', 1); + }); + }, + expectedError, + `Payload ${JSON.stringify(payload)} should throw error ${expectedError}` + ); env.registry.unregister('serializer:person'); env.registry.unregister('adapter:person'); } -module("integration/store/json-validation", { +module('integration/store/json-validation', { beforeEach() { QUnit.assert.payloadError = payloadError.bind(QUnit.assert); @@ -35,159 +45,193 @@ module("integration/store/json-validation", { updatedAt: DS.attr('string'), name: DS.attr('string'), firstName: DS.attr('string'), - lastName: DS.attr('string') + lastName: DS.attr('string'), }); env = setupStore({ - person: Person + person: Person, }); store = env.store; }, afterEach() { - QUnit.assert.payloadError = null + QUnit.assert.payloadError = null; run(store, 'destroy'); - } -}); - -testInDebug("when normalizeResponse returns undefined (or doesn't return), throws an error", function(assert) { - - env.registry.register('serializer:person', DS.Serializer.extend({ - normalizeResponse() {} - })); - - env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord() { - return resolve({ data: {} }); - } - })); - - assert.expectAssertion(function () { - run(function() { - store.findRecord('person', 1); - }); - }, /Top level of a JSON API document must be an object/); + }, }); -testInDebug("when normalizeResponse returns null, throws an error", function(assert) { - - env.registry.register('serializer:person', DS.Serializer.extend({ - normalizeResponse() {return null;} - })); - - env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord() { - return resolve({ data: {} }); - } - })); - - assert.expectAssertion(function () { +testInDebug( + "when normalizeResponse returns undefined (or doesn't return), throws an error", + function(assert) { + env.registry.register( + 'serializer:person', + DS.Serializer.extend({ + normalizeResponse() {}, + }) + ); + + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findRecord() { + return resolve({ data: {} }); + }, + }) + ); + + assert.expectAssertion(function() { + run(function() { + store.findRecord('person', 1); + }); + }, /Top level of a JSON API document must be an object/); + } +); + +testInDebug('when normalizeResponse returns null, throws an error', function(assert) { + env.registry.register( + 'serializer:person', + DS.Serializer.extend({ + normalizeResponse() { + return null; + }, + }) + ); + + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findRecord() { + return resolve({ data: {} }); + }, + }) + ); + + assert.expectAssertion(function() { run(function() { store.findRecord('person', 1); }); }, /Top level of a JSON API document must be an object/); }); - -testInDebug("when normalizeResponse returns an empty object, throws an error", function(assert) { - - env.registry.register('serializer:person', DS.Serializer.extend({ - normalizeResponse() {return {};} - })); - - env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord() { - return resolve({ data: {} }); - } - })); - - assert.expectAssertion(function () { +testInDebug('when normalizeResponse returns an empty object, throws an error', function(assert) { + env.registry.register( + 'serializer:person', + DS.Serializer.extend({ + normalizeResponse() { + return {}; + }, + }) + ); + + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findRecord() { + return resolve({ data: {} }); + }, + }) + ); + + assert.expectAssertion(function() { run(function() { store.findRecord('person', 1); }); }, /One or more of the following keys must be present/); }); -testInDebug("when normalizeResponse returns a document with both data and errors, throws an error", function(assert) { - - env.registry.register('serializer:person', DS.Serializer.extend({ - normalizeResponse() { - return { - data: [], - errors: [] - }; - } - })); - - env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord() { - return resolve({ data: {} }); - } - })); - - assert.expectAssertion(function () { - run(function() { - store.findRecord('person', 1); - }); - }, /cannot both be present/); -}); - -testInDebug("normalizeResponse 'data' cannot be undefined, a number, a string or a boolean", function(assert) { - - assert.payloadError({ data: undefined }, /data must be/); - assert.payloadError({ data: 1 }, /data must be/); - assert.payloadError({ data: 'lollerskates' }, /data must be/); - assert.payloadError({ data: true }, /data must be/); -}); - -testInDebug("normalizeResponse 'meta' cannot be an array, undefined, a number, a string or a boolean", function(assert) { - - assert.payloadError({ meta: undefined }, /meta must be an object/); - assert.payloadError({ meta: [] }, /meta must be an object/); - assert.payloadError({ meta: 1 }, /meta must be an object/); - assert.payloadError({ meta: 'lollerskates' }, /meta must be an object/); - assert.payloadError({ meta: true }, /meta must be an object/); - -}); - -testInDebug("normalizeResponse 'links' cannot be an array, undefined, a number, a string or a boolean", function(assert) { - - assert.payloadError({ data: [], links: undefined }, /links must be an object/); - assert.payloadError({ data: [], links: [] }, /links must be an object/); - assert.payloadError({ data: [], links: 1 }, /links must be an object/); - assert.payloadError({ data: [], links: 'lollerskates' }, /links must be an object/); - assert.payloadError({ data: [], links: true }, /links must be an object/); - -}); - -testInDebug("normalizeResponse 'jsonapi' cannot be an array, undefined, a number, a string or a boolean", function(assert) { - - assert.payloadError({ data: [], jsonapi: undefined }, /jsonapi must be an object/); - assert.payloadError({ data: [], jsonapi: [] }, /jsonapi must be an object/); - assert.payloadError({ data: [], jsonapi: 1 }, /jsonapi must be an object/); - assert.payloadError({ data: [], jsonapi: 'lollerskates' }, /jsonapi must be an object/); - assert.payloadError({ data: [], jsonapi: true }, /jsonapi must be an object/); - -}); - -testInDebug("normalizeResponse 'included' cannot be an object, undefined, a number, a string or a boolean", function(assert) { - - assert.payloadError({ included: undefined }, /included must be an array/); - assert.payloadError({ included: {} }, /included must be an array/); - assert.payloadError({ included: 1 }, /included must be an array/); - assert.payloadError({ included: 'lollerskates' }, /included must be an array/); - assert.payloadError({ included: true }, /included must be an array/); - -}); - -testInDebug("normalizeResponse 'errors' cannot be an object, undefined, a number, a string or a boolean", function(assert) { - - assert.payloadError({ errors: undefined }, /errors must be an array/); - assert.payloadError({ errors: {} }, /errors must be an array/); - assert.payloadError({ errors: 1 }, /errors must be an array/); - assert.payloadError({ errors: 'lollerskates' }, /errors must be an array/); - assert.payloadError({ errors: true }, /errors must be an array/); - -}); - - +testInDebug( + 'when normalizeResponse returns a document with both data and errors, throws an error', + function(assert) { + env.registry.register( + 'serializer:person', + DS.Serializer.extend({ + normalizeResponse() { + return { + data: [], + errors: [], + }; + }, + }) + ); + + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findRecord() { + return resolve({ data: {} }); + }, + }) + ); + + assert.expectAssertion(function() { + run(function() { + store.findRecord('person', 1); + }); + }, /cannot both be present/); + } +); + +testInDebug( + "normalizeResponse 'data' cannot be undefined, a number, a string or a boolean", + function(assert) { + assert.payloadError({ data: undefined }, /data must be/); + assert.payloadError({ data: 1 }, /data must be/); + assert.payloadError({ data: 'lollerskates' }, /data must be/); + assert.payloadError({ data: true }, /data must be/); + } +); + +testInDebug( + "normalizeResponse 'meta' cannot be an array, undefined, a number, a string or a boolean", + function(assert) { + assert.payloadError({ meta: undefined }, /meta must be an object/); + assert.payloadError({ meta: [] }, /meta must be an object/); + assert.payloadError({ meta: 1 }, /meta must be an object/); + assert.payloadError({ meta: 'lollerskates' }, /meta must be an object/); + assert.payloadError({ meta: true }, /meta must be an object/); + } +); + +testInDebug( + "normalizeResponse 'links' cannot be an array, undefined, a number, a string or a boolean", + function(assert) { + assert.payloadError({ data: [], links: undefined }, /links must be an object/); + assert.payloadError({ data: [], links: [] }, /links must be an object/); + assert.payloadError({ data: [], links: 1 }, /links must be an object/); + assert.payloadError({ data: [], links: 'lollerskates' }, /links must be an object/); + assert.payloadError({ data: [], links: true }, /links must be an object/); + } +); + +testInDebug( + "normalizeResponse 'jsonapi' cannot be an array, undefined, a number, a string or a boolean", + function(assert) { + assert.payloadError({ data: [], jsonapi: undefined }, /jsonapi must be an object/); + assert.payloadError({ data: [], jsonapi: [] }, /jsonapi must be an object/); + assert.payloadError({ data: [], jsonapi: 1 }, /jsonapi must be an object/); + assert.payloadError({ data: [], jsonapi: 'lollerskates' }, /jsonapi must be an object/); + assert.payloadError({ data: [], jsonapi: true }, /jsonapi must be an object/); + } +); + +testInDebug( + "normalizeResponse 'included' cannot be an object, undefined, a number, a string or a boolean", + function(assert) { + assert.payloadError({ included: undefined }, /included must be an array/); + assert.payloadError({ included: {} }, /included must be an array/); + assert.payloadError({ included: 1 }, /included must be an array/); + assert.payloadError({ included: 'lollerskates' }, /included must be an array/); + assert.payloadError({ included: true }, /included must be an array/); + } +); + +testInDebug( + "normalizeResponse 'errors' cannot be an object, undefined, a number, a string or a boolean", + function(assert) { + assert.payloadError({ errors: undefined }, /errors must be an array/); + assert.payloadError({ errors: {} }, /errors must be an array/); + assert.payloadError({ errors: 1 }, /errors must be an array/); + assert.payloadError({ errors: 'lollerskates' }, /errors must be an array/); + assert.payloadError({ errors: true }, /errors must be an array/); + } +); diff --git a/tests/integration/store/query-record-test.js b/tests/integration/store/query-record-test.js index b83aa9bfa69..1edff1cc00f 100644 --- a/tests/integration/store/query-record-test.js +++ b/tests/integration/store/query-record-test.js @@ -9,33 +9,33 @@ import DS from 'ember-data'; var Person, store, env; -module("integration/store/query-record - Query one record with a query hash", { +module('integration/store/query-record - Query one record with a query hash', { beforeEach() { Person = DS.Model.extend({ updatedAt: DS.attr('string'), name: DS.attr('string'), firstName: DS.attr('string'), - lastName: DS.attr('string') + lastName: DS.attr('string'), }); env = setupStore({ - person: Person + person: Person, }); store = env.store; }, afterEach() { run(store, 'destroy'); - } + }, }); -testInDebug("It raises an assertion when no type is passed", function(assert) { +testInDebug('It raises an assertion when no type is passed', function(assert) { assert.expectAssertion(function() { store.queryRecord(); }, "You need to pass a model name to the store's queryRecord method"); }); -testInDebug("It raises an assertion when no query hash is passed", function(assert) { +testInDebug('It raises an assertion when no query hash is passed', function(assert) { assert.expectAssertion(function() { store.queryRecord('person'); }, "You need to pass a query hash to the store's queryRecord method"); @@ -44,28 +44,34 @@ testInDebug("It raises an assertion when no query hash is passed", function(asse test("When a record is requested, the adapter's queryRecord method should be called.", function(assert) { assert.expect(1); - env.registry.register('adapter:person', DS.Adapter.extend({ - queryRecord(store, type, query) { - assert.equal(type, Person, "the query method is called with the correct type"); - return resolve({ data: { id: 1, type: 'person', attributes: { name: "Peter Wagenet" } } }); - } - })); + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + queryRecord(store, type, query) { + assert.equal(type, Person, 'the query method is called with the correct type'); + return resolve({ data: { id: 1, type: 'person', attributes: { name: 'Peter Wagenet' } } }); + }, + }) + ); run(function() { store.queryRecord('person', { related: 'posts' }); }); }); -test("When a record is requested, and the promise is rejected, .queryRecord() is rejected.", function(assert) { - env.registry.register('adapter:person', DS.Adapter.extend({ - queryRecord(store, type, query) { - return reject(); - } - })); +test('When a record is requested, and the promise is rejected, .queryRecord() is rejected.', function(assert) { + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + queryRecord(store, type, query) { + return reject(); + }, + }) + ); run(function() { store.queryRecord('person', {}).catch(function(reason) { - assert.ok(true, "The rejection handler was called"); + assert.ok(true, 'The rejection handler was called'); }); }); }); @@ -73,26 +79,36 @@ test("When a record is requested, and the promise is rejected, .queryRecord() is test("When a record is requested, the serializer's normalizeQueryRecordResponse method should be called.", function(assert) { assert.expect(1); - env.registry.register('serializer:person', DS.JSONAPISerializer.extend({ - normalizeQueryRecordResponse(store, primaryModelClass, payload, id, requestType) { - assert.equal(payload.data.id , '1', "the normalizeQueryRecordResponse method was called with the right payload"); - return this._super(...arguments); - } - })); - - env.registry.register('adapter:person', DS.Adapter.extend({ - queryRecord(store, type, query) { - return resolve({ - data: { - id: '1', - type: 'person', - attributes: { - name: "Peter Wagenet" - } - } - }); - } - })); + env.registry.register( + 'serializer:person', + DS.JSONAPISerializer.extend({ + normalizeQueryRecordResponse(store, primaryModelClass, payload, id, requestType) { + assert.equal( + payload.data.id, + '1', + 'the normalizeQueryRecordResponse method was called with the right payload' + ); + return this._super(...arguments); + }, + }) + ); + + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + queryRecord(store, type, query) { + return resolve({ + data: { + id: '1', + type: 'person', + attributes: { + name: 'Peter Wagenet', + }, + }, + }); + }, + }) + ); run(function() { store.queryRecord('person', { related: 'posts' }); diff --git a/tests/integration/store/query-test.js b/tests/integration/store/query-test.js index 257c07944c6..911fa49706c 100644 --- a/tests/integration/store/query-test.js +++ b/tests/integration/store/query-test.js @@ -9,12 +9,12 @@ import DS from 'ember-data'; var Person, store, env; var run = Ember.run; -module("integration/store/query", { +module('integration/store/query', { beforeEach() { Person = DS.Model.extend(); env = setupStore({ - person: Person + person: Person, }); store = env.store; @@ -22,17 +22,20 @@ module("integration/store/query", { afterEach() { run(store, 'destroy'); - } + }, }); -test("meta is proxied correctly on the PromiseArray", function(assert) { +test('meta is proxied correctly on the PromiseArray', function(assert) { let defered = RSVP.defer(); - env.registry.register('adapter:person', DS.Adapter.extend({ - query(store, type, query) { - return defered.promise; - } - })); + env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + query(store, type, query) { + return defered.promise; + }, + }) + ); let result; run(function() { diff --git a/tests/test-helper.js b/tests/test-helper.js index 360c70df4f7..0966beb4885 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -2,18 +2,12 @@ import RSVP from 'rsvp'; import Application from '@ember/application'; import resolver from './helpers/resolver'; -import { - setResolver -} from '@ember/test-helpers'; +import { setResolver } from '@ember/test-helpers'; import { start } from 'ember-qunit'; import QUnit from 'qunit'; import DS from 'ember-data'; -import { - wait, - asyncEqual, - invokeAsync -} from 'dummy/tests/helpers/async'; +import { wait, asyncEqual, invokeAsync } from 'dummy/tests/helpers/async'; import loadInitializers from 'ember-load-initializers'; setResolver(resolver); @@ -22,9 +16,9 @@ loadInitializers(Application, 'dummy'); const { assert } = QUnit; const transforms = { boolean: DS.BooleanTransform.create(), - date: DS.DateTransform.create(), - number: DS.NumberTransform.create(), - string: DS.StringTransform.create() + date: DS.DateTransform.create(), + number: DS.NumberTransform.create(), + string: DS.StringTransform.create(), }; QUnit.begin(() => { @@ -41,32 +35,33 @@ QUnit.begin(() => { DS.JSONSerializer.reopen({ transformFor(attributeType) { return this._super(attributeType, true) || transforms[attributeType]; - } + }, }); - }); assert.wait = wait; assert.asyncEqual = asyncEqual; assert.invokeAsync = invokeAsync; assert.assertClean = function(promise) { - return promise.then(this.wait(record => { - this.equal(record.get('hasDirtyAttributes'), false, 'The record is now clean'); - return record; - })); + return promise.then( + this.wait(record => { + this.equal(record.get('hasDirtyAttributes'), false, 'The record is now clean'); + return record; + }) + ); }; assert.contains = function(array, item) { this.ok(array.indexOf(item) !== -1, `array contains ${item}`); }; -assert.without = function(array, item) { +assert.without = function(array, item) { this.ok(array.indexOf(item) === -1, `array doesn't contain ${item}`); }; QUnit.config.testTimeout = 2000; QUnit.config.urlConfig.push({ id: 'enableoptionalfeatures', - label: 'Enable Opt Features' + label: 'Enable Opt Features', }); start({ setupTestIsolationValidation: true }); diff --git a/tests/unit/adapter-errors-test.js b/tests/unit/adapter-errors-test.js index 738bec5a131..aac6600afe4 100644 --- a/tests/unit/adapter-errors-test.js +++ b/tests/unit/adapter-errors-test.js @@ -107,42 +107,42 @@ test('CustomAdapterError with default message', function(assert) { const errorsHash = { name: ['is invalid', 'must be a string'], - age: ['must be a number'] + age: ['must be a number'], }; const errorsArray = [ { title: 'Invalid Attribute', detail: 'is invalid', - source: { pointer: '/data/attributes/name' } + source: { pointer: '/data/attributes/name' }, }, { title: 'Invalid Attribute', detail: 'must be a string', - source: { pointer: '/data/attributes/name' } + source: { pointer: '/data/attributes/name' }, }, { title: 'Invalid Attribute', detail: 'must be a number', - source: { pointer: '/data/attributes/age' } - } + source: { pointer: '/data/attributes/age' }, + }, ]; const errorsPrimaryHash = { - base: ['is invalid', 'error message'] + base: ['is invalid', 'error message'], }; const errorsPrimaryArray = [ { title: 'Invalid Document', detail: 'is invalid', - source: { pointer: '/data' } + source: { pointer: '/data' }, }, { title: 'Invalid Document', detail: 'error message', - source: { pointer: '/data' } - } + source: { pointer: '/data' }, + }, ]; test('errorsHashToArray', function(assert) { @@ -164,8 +164,8 @@ test('errorsArrayToHash without trailing slash', function(assert) { let result = DS.errorsArrayToHash([ { detail: 'error message', - source: { pointer: 'data/attributes/name' } - } + source: { pointer: 'data/attributes/name' }, + }, ]); assert.deepEqual(result, { name: ['error message'] }); }); diff --git a/tests/unit/adapters/build-url-mixin/build-url-test.js b/tests/unit/adapters/build-url-mixin/build-url-test.js index cc7ce50d5f5..98fdacfb172 100644 --- a/tests/unit/adapters/build-url-mixin/build-url-test.js +++ b/tests/unit/adapters/build-url-mixin/build-url-test.js @@ -5,23 +5,25 @@ import { module, test } from 'qunit'; let adapter, env; -module("unit/adapters/build-url-mixin/build-url - DS.BuildURLMixin#buildURL", { +module('unit/adapters/build-url-mixin/build-url - DS.BuildURLMixin#buildURL', { beforeEach() { const customPathForType = { pathForType(type) { - if (type === 'rootModel') { return ''; } + if (type === 'rootModel') { + return ''; + } return this._super(type); - } + }, }; const Adapter = DS.Adapter.extend(DS.BuildURLMixin, customPathForType); env = setupStore({ - adapter: Adapter + adapter: Adapter, }); adapter = env.adapter; - } + }, }); test('buildURL - works with empty paths', function(assert) { diff --git a/tests/unit/adapters/build-url-mixin/path-for-type-test.js b/tests/unit/adapters/build-url-mixin/path-for-type-test.js index 1302a3bf9ee..701bb729787 100644 --- a/tests/unit/adapters/build-url-mixin/path-for-type-test.js +++ b/tests/unit/adapters/build-url-mixin/path-for-type-test.js @@ -6,21 +6,22 @@ import { module, test } from 'qunit'; let env, adapter; -module("unit/adapters/build-url-mixin/path-for-type - DS.BuildURLMixin#pathForType", { +module('unit/adapters/build-url-mixin/path-for-type - DS.BuildURLMixin#pathForType', { beforeEach() { - // test for overriden pathForType methods which return null path values let customPathForType = { pathForType(type) { - if (type === 'rootModel') { return ''; } + if (type === 'rootModel') { + return ''; + } return this._super(type); - } + }, }; let Adapter = DS.Adapter.extend(DS.BuildURLMixin, customPathForType); env = setupStore({ - adapter: Adapter + adapter: Adapter, }); adapter = env.adapter; @@ -28,7 +29,7 @@ module("unit/adapters/build-url-mixin/path-for-type - DS.BuildURLMixin#pathForTy afterEach() { run(env.container, 'destroy'); - } + }, }); test('pathForType - works with camelized types', function(assert) { diff --git a/tests/unit/adapters/json-api-adapter/ajax-test.js b/tests/unit/adapters/json-api-adapter/ajax-test.js index 94b9036a307..8d39cf67ea7 100644 --- a/tests/unit/adapters/json-api-adapter/ajax-test.js +++ b/tests/unit/adapters/json-api-adapter/ajax-test.js @@ -7,7 +7,7 @@ import DS from 'ember-data'; let Person, Place, store, adapter, env; -module("unit/adapters/json-api-adapter/ajax - building requests", { +module('unit/adapters/json-api-adapter/ajax - building requests', { beforeEach() { Person = { modelName: 'person' }; Place = { modelName: 'place' }; @@ -21,7 +21,7 @@ module("unit/adapters/json-api-adapter/ajax - building requests", { store.destroy(); env.container.destroy(); }); - } + }, }); test('ajaxOptions() adds Accept when no other headers exist', function(assert) { @@ -32,7 +32,7 @@ test('ajaxOptions() adds Accept when no other headers exist', function(assert) { let fakeXHR = { setRequestHeader(key, value) { receivedHeaders.push([key, value]); - } + }, }; ajaxOptions.beforeSend(fakeXHR); assert.deepEqual(receivedHeaders, [['Accept', 'application/vnd.api+json']], 'headers assigned'); @@ -47,10 +47,14 @@ test('ajaxOptions() adds Accept header to existing headers', function(assert) { let fakeXHR = { setRequestHeader(key, value) { receivedHeaders.push([key, value]); - } + }, }; ajaxOptions.beforeSend(fakeXHR); - assert.deepEqual(receivedHeaders, [['Accept', 'application/vnd.api+json'], ['Other-key', 'Other Value']], 'headers assigned'); + assert.deepEqual( + receivedHeaders, + [['Accept', 'application/vnd.api+json'], ['Other-key', 'Other Value']], + 'headers assigned' + ); }); test('ajaxOptions() adds Accept header to existing computed properties headers', function(assert) { @@ -62,8 +66,12 @@ test('ajaxOptions() adds Accept header to existing computed properties headers', let fakeXHR = { setRequestHeader(key, value) { receivedHeaders.push([key, value]); - } + }, }; ajaxOptions.beforeSend(fakeXHR); - assert.deepEqual(receivedHeaders, [['Accept', 'application/vnd.api+json'], ['Other-key', 'Other Value']], 'headers assigned'); + assert.deepEqual( + receivedHeaders, + [['Accept', 'application/vnd.api+json'], ['Other-key', 'Other Value']], + 'headers assigned' + ); }); diff --git a/tests/unit/adapters/rest-adapter/ajax-test.js b/tests/unit/adapters/rest-adapter/ajax-test.js index 285707123e3..f8f82b9e53d 100644 --- a/tests/unit/adapters/rest-adapter/ajax-test.js +++ b/tests/unit/adapters/rest-adapter/ajax-test.js @@ -22,7 +22,7 @@ module('unit/adapters/rest-adapter/ajax - building requests', { store.destroy(); env.container.destroy(); }); - } + }, }); test('When an id is searched, the correct url should be generated', function(assert) { @@ -31,8 +31,12 @@ test('When an id is searched, the correct url should be generated', function(ass let count = 0; adapter.ajax = function(url, method) { - if (count === 0) { assert.equal(url, '/people/1', 'should create the correct url'); } - if (count === 1) { assert.equal(url, '/places/1', 'should create the correct url'); } + if (count === 0) { + assert.equal(url, '/people/1', 'should create the correct url'); + } + if (count === 1) { + assert.equal(url, '/places/1', 'should create the correct url'); + } count++; return resolve(); }; @@ -40,7 +44,7 @@ test('When an id is searched, the correct url should be generated', function(ass return run(() => { return EmberPromise.all([ adapter.findRecord(store, Person, 1, {}), - adapter.findRecord(store, Place, 1, {}) + adapter.findRecord(store, Place, 1, {}), ]); }); }); @@ -49,7 +53,7 @@ test(`id's should be sanatized`, function(assert) { assert.expect(1); adapter.ajax = function(url, method) { - assert.equal(url, '/people/..%2Fplace%2F1', "should create the correct url"); + assert.equal(url, '/people/..%2Fplace%2F1', 'should create the correct url'); return resolve(); }; @@ -59,7 +63,7 @@ test(`id's should be sanatized`, function(assert) { test('ajaxOptions() headers are set', function(assert) { adapter.headers = { 'Content-Type': 'application/json', - 'Other-key': 'Other Value' + 'Other-key': 'Other Value', }; let url = 'example.com'; @@ -69,13 +73,14 @@ test('ajaxOptions() headers are set', function(assert) { let fakeXHR = { setRequestHeader(key, value) { receivedHeaders.push([key, value]); - } + }, }; ajaxOptions.beforeSend(fakeXHR); - assert.deepEqual(receivedHeaders, [ - ['Content-Type', 'application/json'], - ['Other-key', 'Other Value'] - ], 'headers assigned'); + assert.deepEqual( + receivedHeaders, + [['Content-Type', 'application/json'], ['Other-key', 'Other Value']], + 'headers assigned' + ); }); test('ajaxOptions() do not serializes data when GET', function(assert) { @@ -86,11 +91,11 @@ test('ajaxOptions() do not serializes data when GET', function(assert) { assert.deepEqual(ajaxOptions, { context: adapter, data: { - key: 'value' + key: 'value', }, dataType: 'json', type: 'GET', - url: 'example.com' + url: 'example.com', }); }); @@ -105,7 +110,7 @@ test('ajaxOptions() serializes data when not GET', function(assert) { data: '{"key":"value"}', dataType: 'json', type: 'POST', - url: 'example.com' + url: 'example.com', }); }); @@ -118,6 +123,6 @@ test('ajaxOptions() empty data', function(assert) { context: adapter, dataType: 'json', type: 'POST', - url: 'example.com' + url: 'example.com', }); }); diff --git a/tests/unit/adapters/rest-adapter/detailed-message-test.js b/tests/unit/adapters/rest-adapter/detailed-message-test.js index cef3e9b4c6d..195c24b34de 100644 --- a/tests/unit/adapters/rest-adapter/detailed-message-test.js +++ b/tests/unit/adapters/rest-adapter/detailed-message-test.js @@ -6,31 +6,37 @@ import DS from 'ember-data'; let adapter, env; -module('unit/adapters/rest_adapter/detailed_message_test - DS.RESTAdapter#generatedDetailedMessage', { - beforeEach() { - env = setupStore({ adapter: DS.RESTAdapter }); - adapter = env.adapter; +module( + 'unit/adapters/rest_adapter/detailed_message_test - DS.RESTAdapter#generatedDetailedMessage', + { + beforeEach() { + env = setupStore({ adapter: DS.RESTAdapter }); + adapter = env.adapter; + }, } -}); +); test('generating a wonderfully friendly error message should work', function(assert) { assert.expect(1); let friendlyMessage = adapter.generatedDetailedMessage( 418, - { "Content-Type": "text/plain" }, + { 'Content-Type': 'text/plain' }, "I'm a little teapot, short and stout", { - url: "/teapots/testing", - method: "GET" + url: '/teapots/testing', + method: 'GET', } ); - assert.equal(friendlyMessage, [ - 'Ember Data Request GET /teapots/testing returned a 418', - 'Payload (text/plain)', - `I'm a little teapot, short and stout` - ].join('\n')); + assert.equal( + friendlyMessage, + [ + 'Ember Data Request GET /teapots/testing returned a 418', + 'Payload (text/plain)', + `I'm a little teapot, short and stout`, + ].join('\n') + ); }); test('generating a friendly error message with a missing content-type header should work', function(assert) { @@ -40,13 +46,16 @@ test('generating a friendly error message with a missing content-type header sho `I'm a little teapot, short and stout`, { url: '/teapots/testing', - method: 'GET' + method: 'GET', } ); - assert.equal(friendlyMessage, [ - 'Ember Data Request GET /teapots/testing returned a 418', - 'Payload (Empty Content-Type)', - `I'm a little teapot, short and stout` - ].join('\n')); + assert.equal( + friendlyMessage, + [ + 'Ember Data Request GET /teapots/testing returned a 418', + 'Payload (Empty Content-Type)', + `I'm a little teapot, short and stout`, + ].join('\n') + ); }); diff --git a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index 981005ea274..083f04929e6 100644 --- a/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -10,50 +10,54 @@ let GroupsAdapter, store, requests; let maxLength; let lengths; -module('unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAdapter#groupRecordsForFindMany', { - beforeEach() { - maxLength = -1; - requests = []; - lengths = []; - - GroupsAdapter = DS.RESTAdapter.extend({ - - coalesceFindRequests: true, - - findRecord(store, type, id, snapshot) { - return { id }; - } - }); - - GroupsAdapter.reopen({ - ajax(url, type, options) { - requests.push({ - url, - ids: options.data.ids - }); - - let queryString = options.data.ids.map(i => { - return encodeURIComponent('ids[]') + '=' + encodeURIComponent(i); - }).join('&'); - let fullUrl = url + '?' + queryString; - - maxLength = this.get('maxURLLength'); - lengths.push(fullUrl.length); - - let testRecords = options.data.ids.map(id => ({ id })); - return EmberPromise.resolve({ 'testRecords' : testRecords }); - } - }); - - store = createStore({ - adapter: GroupsAdapter, - testRecord: DS.Model.extend() - }); - }, - afterEach() { - run(store, 'destroy'); +module( + 'unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAdapter#groupRecordsForFindMany', + { + beforeEach() { + maxLength = -1; + requests = []; + lengths = []; + + GroupsAdapter = DS.RESTAdapter.extend({ + coalesceFindRequests: true, + + findRecord(store, type, id, snapshot) { + return { id }; + }, + }); + + GroupsAdapter.reopen({ + ajax(url, type, options) { + requests.push({ + url, + ids: options.data.ids, + }); + + let queryString = options.data.ids + .map(i => { + return encodeURIComponent('ids[]') + '=' + encodeURIComponent(i); + }) + .join('&'); + let fullUrl = url + '?' + queryString; + + maxLength = this.get('maxURLLength'); + lengths.push(fullUrl.length); + + let testRecords = options.data.ids.map(id => ({ id })); + return EmberPromise.resolve({ testRecords: testRecords }); + }, + }); + + store = createStore({ + adapter: GroupsAdapter, + testRecord: DS.Model.extend(), + }); + }, + afterEach() { + run(store, 'destroy'); + }, } -}); +); test('groupRecordsForFindMany - findMany', function(assert) { let wait = []; @@ -82,7 +86,7 @@ test('groupRecordsForFindMany works for encodeURIComponent-ified ids', function( }); test('_stripIDFromURL works with id being encoded - #4190', function(assert) { - let record = store.createRecord('testRecord', { id: "id:123" }); + let record = store.createRecord('testRecord', { id: 'id:123' }); let adapter = store.adapterFor('testRecord'); let snapshot = record._internalModel.createSnapshot(); let strippedUrl = adapter._stripIDFromURL(store, snapshot); diff --git a/tests/unit/debug-test.js b/tests/unit/debug-test.js index fe44fb27660..937ced7dbf9 100644 --- a/tests/unit/debug-test.js +++ b/tests/unit/debug-test.js @@ -11,25 +11,25 @@ module('Debug'); test('_debugInfo groups the attributes and relationships correctly', function(assert) { const MaritalStatus = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const Post = DS.Model.extend({ - title: DS.attr('string') + title: DS.attr('string'), }); const User = DS.Model.extend({ name: DS.attr('string'), isDrugAddict: DS.attr('boolean'), maritalStatus: DS.belongsTo('marital-status', { async: false }), - posts: DS.hasMany('post', { async: false }) + posts: DS.hasMany('post', { async: false }), }); let store = createStore({ adapter: TestAdapter.extend(), maritalStatus: MaritalStatus, post: Post, - user: User + user: User, }); let record = store.createRecord('user'); @@ -44,32 +44,33 @@ test('_debugInfo groups the attributes and relationships correctly', function(as test('_debugInfo supports arbitray relationship types', function(assert) { const MaritalStatus = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const Post = DS.Model.extend({ - title: DS.attr('string') + title: DS.attr('string'), }); const User = DS.Model.extend({ name: DS.attr('string'), isDrugAddict: DS.attr('boolean'), maritalStatus: DS.belongsTo('marital-status', { async: false }), - posts: computed(() => [1, 2, 3] ) - .readOnly().meta({ - options: { inverse: null }, - isRelationship: true, - kind: 'customRelationship', - name: 'posts', - type: 'post' - }) + posts: computed(() => [1, 2, 3]) + .readOnly() + .meta({ + options: { inverse: null }, + isRelationship: true, + kind: 'customRelationship', + name: 'posts', + type: 'post', + }), }); let store = createStore({ adapter: TestAdapter.extend(), maritalStatus: MaritalStatus, post: Post, - user: User + user: User, }); let record = store.createRecord('user'); @@ -81,26 +82,18 @@ test('_debugInfo supports arbitray relationship types', function(assert) { groups: [ { name: 'Attributes', - properties: [ - 'id', - 'name', - 'isDrugAddict' - ], - expand: true + properties: ['id', 'name', 'isDrugAddict'], + expand: true, }, { name: 'maritalStatus', - properties: [ - 'maritalStatus' - ], - expand: true + properties: ['maritalStatus'], + expand: true, }, { name: 'posts', - properties: [ - 'posts' - ], - expand: true + properties: ['posts'], + expand: true, }, { name: 'Flags', @@ -111,13 +104,10 @@ test('_debugInfo supports arbitray relationship types', function(assert) { 'isDeleted', 'isError', 'isNew', - 'isValid' - ] - } + 'isValid', + ], + }, ], - expensiveProperties: [ - 'maritalStatus', - 'posts' - ] - }) + expensiveProperties: ['maritalStatus', 'posts'], + }); }); diff --git a/tests/unit/diff-array-test.js b/tests/unit/diff-array-test.js index a226a2ffd07..791c710fc56 100644 --- a/tests/unit/diff-array-test.js +++ b/tests/unit/diff-array-test.js @@ -2,21 +2,20 @@ import { module, test } from 'qunit'; import { diffArray } from 'ember-data/-private'; -module('unit/diff-array Diff Array tests', { -}); - -const a = "aaa"; -const b = "bbb"; -const c = "ccc"; -const d = "ddd"; -const e = "eee"; -const f = "fff"; -const g = "ggg"; -const h = "hhh"; -const w = "www"; -const x = "xxx"; -const y = "yyy"; -const z = "zzz"; +module('unit/diff-array Diff Array tests', {}); + +const a = 'aaa'; +const b = 'bbb'; +const c = 'ccc'; +const d = 'ddd'; +const e = 'eee'; +const f = 'fff'; +const g = 'ggg'; +const h = 'hhh'; +const w = 'www'; +const x = 'xxx'; +const y = 'yyy'; +const z = 'zzz'; test('diff array returns no change given two empty arrays', function(assert) { const result = diffArray([], []); @@ -33,7 +32,7 @@ test('diff array returns no change given two identical arrays length 1', functio }); test('diff array returns no change given two identical arrays length 3', function(assert) { - const result = diffArray([a,b,c], [a,b,c]); + const result = diffArray([a, b, c], [a, b, c]); assert.strictEqual(result.firstChangeIndex, null); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 0); @@ -47,35 +46,35 @@ test('diff array returns correctly given one appended item with old length 0', f }); test('diff array returns correctly given one appended item with old length 1', function(assert) { - const result = diffArray([a], [a,b]); + const result = diffArray([a], [a, b]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 0); }); test('diff array returns correctly given one appended item with old length 2', function(assert) { - const result = diffArray([a,b], [a,b,c]); + const result = diffArray([a, b], [a, b, c]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 0); }); test('diff array returns correctly given 3 appended items with old length 0', function(assert) { - const result = diffArray([], [a,b,c]); + const result = diffArray([], [a, b, c]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 0); }); test('diff array returns correctly given 3 appended items with old length 1', function(assert) { - const result = diffArray([a], [a,b,c,d]); + const result = diffArray([a], [a, b, c, d]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 0); }); test('diff array returns correctly given 3 appended items with old length 2', function(assert) { - const result = diffArray([a,b], [a,b,c,d,e]); + const result = diffArray([a, b], [a, b, c, d, e]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 0); @@ -89,119 +88,119 @@ test('diff array returns correctly given one item removed from end with old leng }); test('diff array returns correctly given one item removed from end with old length 2', function(assert) { - const result = diffArray([a,b], [a]); + const result = diffArray([a, b], [a]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given one item removed from end with old length 3', function(assert) { - const result = diffArray([a,b,c], [a,b]); + const result = diffArray([a, b, c], [a, b]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given 3 items removed from end with old length 3', function(assert) { - const result = diffArray([a,b,c], []); + const result = diffArray([a, b, c], []); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given 3 items removed from end with old length 4', function(assert) { - const result = diffArray([a,b,c,d], [a]); + const result = diffArray([a, b, c, d], [a]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given 3 items removed from end with old length 5', function(assert) { - const result = diffArray([a,b,c,d,e], [a,b]); + const result = diffArray([a, b, c, d, e], [a, b]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given one item removed from beginning with old length 2', function(assert) { - const result = diffArray([a,b], [b]); + const result = diffArray([a, b], [b]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given one item removed from beginning with old length 3', function(assert) { - const result = diffArray([a,b,c], [b,c]); + const result = diffArray([a, b, c], [b, c]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given 3 items removed from beginning with old length 4', function(assert) { - const result = diffArray([a,b,c,d], [d]); + const result = diffArray([a, b, c, d], [d]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given 3 items removed from beginning with old length 5', function(assert) { - const result = diffArray([a,b,c,d,e], [d,e]); + const result = diffArray([a, b, c, d, e], [d, e]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given one item removed from middle with old length 3', function(assert) { - const result = diffArray([a,b,c], [a,c]); + const result = diffArray([a, b, c], [a, c]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given one item removed from middle with old length 5', function(assert) { - const result = diffArray([a,b,c,d,e], [a,b,d,e]); + const result = diffArray([a, b, c, d, e], [a, b, d, e]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given 3 items removed from middle with old length 5', function(assert) { - const result = diffArray([a,b,c,d,e], [a,e]); + const result = diffArray([a, b, c, d, e], [a, e]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given 3 items removed from middle with old length 7', function(assert) { - const result = diffArray([a,b,c,d,e,f,g], [a,b,f,g]); + const result = diffArray([a, b, c, d, e, f, g], [a, b, f, g]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 0); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given one item added to middle with old length 2', function(assert) { - const result = diffArray([a,c], [a,b,c]); + const result = diffArray([a, c], [a, b, c]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 0); }); test('diff array returns correctly given one item added to middle with old length 4', function(assert) { - const result = diffArray([a,b,d,e], [a,b,c,d,e]); + const result = diffArray([a, b, d, e], [a, b, c, d, e]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 0); }); test('diff array returns correctly given 3 items added to middle with old length 2', function(assert) { - const result = diffArray([a,e], [a,b,c,d,e]); + const result = diffArray([a, e], [a, b, c, d, e]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 0); }); test('diff array returns correctly given 3 items added to middle with old length 4', function(assert) { - const result = diffArray([a,b,f,g], [a,b,c,d,e,f,g]); + const result = diffArray([a, b, f, g], [a, b, c, d, e, f, g]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 0); @@ -215,273 +214,273 @@ test('diff array returns correctly given complete replacement with length 1', fu }); test('diff array returns correctly given complete replacement with length 3', function(assert) { - const result = diffArray([a,b,c], [x,y,z]); + const result = diffArray([a, b, c], [x, y, z]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given complete replacement with longer length', function(assert) { - const result = diffArray([a,b], [x,y,z]); + const result = diffArray([a, b], [x, y, z]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 2); }); test('diff array returns correctly given one item replaced in middle with old length 3', function(assert) { - const result = diffArray([a,b,c], [a,x,c]); + const result = diffArray([a, b, c], [a, x, c]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given one item replaced in middle with old length 5', function(assert) { - const result = diffArray([a,b,c,d,e], [a,b,x,d,e]); + const result = diffArray([a, b, c, d, e], [a, b, x, d, e]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given 3 items replaced in middle with old length 5', function(assert) { - const result = diffArray([a,b,c,d,e], [a,x,y,z,e]); + const result = diffArray([a, b, c, d, e], [a, x, y, z, e]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given 3 items replaced in middle with old length 7', function(assert) { - const result = diffArray([a,b,c,d,e,f,g], [a,b,x,y,z,f,g]); + const result = diffArray([a, b, c, d, e, f, g], [a, b, x, y, z, f, g]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given one item replaced at beginning with old length 2', function(assert) { - const result = diffArray([a,b], [x,b]); + const result = diffArray([a, b], [x, b]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given one item replaced at beginning with old length 3', function(assert) { - const result = diffArray([a,b,c], [x,b,c]); + const result = diffArray([a, b, c], [x, b, c]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given 3 items replaced at beginning with old length 4', function(assert) { - const result = diffArray([a,b,c,d], [x,y,z,d]); + const result = diffArray([a, b, c, d], [x, y, z, d]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given 3 items replaced at beginning with old length 6', function(assert) { - const result = diffArray([a,b,c,d,e,f], [x,y,z,d,e,f]); + const result = diffArray([a, b, c, d, e, f], [x, y, z, d, e, f]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given one item replaced at end with old length 2', function(assert) { - const result = diffArray([a,b], [a,x]); + const result = diffArray([a, b], [a, x]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given one item replaced at end with old length 3', function(assert) { - const result = diffArray([a,b,c], [a,b,x]); + const result = diffArray([a, b, c], [a, b, x]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given 3 items replaced at end with old length 4', function(assert) { - const result = diffArray([a,b,c,d], [a,x,y,z]); + const result = diffArray([a, b, c, d], [a, x, y, z]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given 3 items replaced at end with old length 6', function(assert) { - const result = diffArray([a,b,c,d,e,f], [a,b,c,x,y,z]); + const result = diffArray([a, b, c, d, e, f], [a, b, c, x, y, z]); assert.equal(result.firstChangeIndex, 3); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given one item replaced with two in middle with old length 3', function(assert) { - const result = diffArray([a,b,c], [a,x,y,c]); + const result = diffArray([a, b, c], [a, x, y, c]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 2); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given one item replaced with two in middle with old length 5', function(assert) { - const result = diffArray([a,b,c,d,e], [a,b,x,y,d,e]); + const result = diffArray([a, b, c, d, e], [a, b, x, y, d, e]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 2); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given 3 items replaced with 4 in middle with old length 5', function(assert) { - const result = diffArray([a,b,c,d,e], [a,w,x,y,z,e]); + const result = diffArray([a, b, c, d, e], [a, w, x, y, z, e]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 4); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given 3 items replaced with 4 in middle with old length 7', function(assert) { - const result = diffArray([a,b,c,d,e,f,g], [a,b,w,x,y,z,f,g]); + const result = diffArray([a, b, c, d, e, f, g], [a, b, w, x, y, z, f, g]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 4); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given one item replaced with two at beginning with old length 2', function(assert) { - const result = diffArray([a,b], [x,y,b]); + const result = diffArray([a, b], [x, y, b]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 2); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given one item replaced with two at beginning with old length 3', function(assert) { - const result = diffArray([a,b,c], [x,y,b,c]); + const result = diffArray([a, b, c], [x, y, b, c]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 2); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given 3 items replaced with 4 at beginning with old length 4', function(assert) { - const result = diffArray([a,b,c,d], [w,x,y,z,d]); + const result = diffArray([a, b, c, d], [w, x, y, z, d]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 4); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given 3 items replaced with 4 at beginning with old length 6', function(assert) { - const result = diffArray([a,b,c,d,e,f], [w,x,y,z,d,e,f]); + const result = diffArray([a, b, c, d, e, f], [w, x, y, z, d, e, f]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 4); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given one item replaced with two at end with old length 2', function(assert) { - const result = diffArray([a,b], [a,x,y]); + const result = diffArray([a, b], [a, x, y]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 2); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given one item replaced with two at end with old length 3', function(assert) { - const result = diffArray([a,b,c], [a,b,x,y]); + const result = diffArray([a, b, c], [a, b, x, y]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 2); assert.equal(result.removedCount, 1); }); test('diff array returns correctly given 3 items replaced with 4 at end with old length 4', function(assert) { - const result = diffArray([a,b,c,d], [a,w,x,y,z]); + const result = diffArray([a, b, c, d], [a, w, x, y, z]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 4); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given 3 items replaced with 4 at end with old length 6', function(assert) { - const result = diffArray([a,b,c,d,e,f], [a,b,c,w,x,y,z]); + const result = diffArray([a, b, c, d, e, f], [a, b, c, w, x, y, z]); assert.equal(result.firstChangeIndex, 3); assert.equal(result.addedCount, 4); assert.equal(result.removedCount, 3); }); test('diff array returns correctly given two items replaced with one in middle with old length 4', function(assert) { - const result = diffArray([a,b,c,d], [a,x,d]); + const result = diffArray([a, b, c, d], [a, x, d]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 2); }); test('diff array returns correctly given two items replaced with one in middle with old length 6', function(assert) { - const result = diffArray([a,b,c,d,e,f], [a,b,x,e,f]); + const result = diffArray([a, b, c, d, e, f], [a, b, x, e, f]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 2); }); test('diff array returns correctly given 4 items replaced with 3 in middle with old length 6', function(assert) { - const result = diffArray([a,b,c,d,e,f], [a,x,y,z,f]); + const result = diffArray([a, b, c, d, e, f], [a, x, y, z, f]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 4); }); test('diff array returns correctly given 4 items replaced with 3 in middle with old length 8', function(assert) { - const result = diffArray([a,b,c,d,e,f,g,h], [a,b,x,y,z,g,h]); + const result = diffArray([a, b, c, d, e, f, g, h], [a, b, x, y, z, g, h]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 4); }); test('diff array returns correctly given two items replaced with one at beginning with old length 3', function(assert) { - const result = diffArray([a,b,c], [x,c]); + const result = diffArray([a, b, c], [x, c]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 2); }); test('diff array returns correctly given two items replaced with one at beginning with old length 4', function(assert) { - const result = diffArray([a,b,c,d], [x,c,d]); + const result = diffArray([a, b, c, d], [x, c, d]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 2); }); test('diff array returns correctly given 4 items replaced with 3 at beginning with old length 5', function(assert) { - const result = diffArray([a,b,c,d,e], [x,y,z,e]); + const result = diffArray([a, b, c, d, e], [x, y, z, e]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 4); }); test('diff array returns correctly given 4 items replaced with 3 at beginning with old length 6', function(assert) { - const result = diffArray([a,b,c,d,e,f], [x,y,z,e,f]); + const result = diffArray([a, b, c, d, e, f], [x, y, z, e, f]); assert.equal(result.firstChangeIndex, 0); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 4); }); test('diff array returns correctly given two items replaced with one at end with old length 3', function(assert) { - const result = diffArray([a,b,c], [a,x]); + const result = diffArray([a, b, c], [a, x]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 2); }); test('diff array returns correctly given two items replaced with one at end with old length 4', function(assert) { - const result = diffArray([a,b,c,d], [a,b,x]); + const result = diffArray([a, b, c, d], [a, b, x]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 1); assert.equal(result.removedCount, 2); }); test('diff array returns correctly given 4 items replaced with 3 at end with old length 5', function(assert) { - const result = diffArray([a,b,c,d,e], [a,x,y,z]); + const result = diffArray([a, b, c, d, e], [a, x, y, z]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 4); }); test('diff array returns correctly given 4 items replaced with 3 at end with old length 6', function(assert) { - const result = diffArray([a,b,c,d,e,f], [a,b,x,y,z]); + const result = diffArray([a, b, c, d, e, f], [a, b, x, y, z]); assert.equal(result.firstChangeIndex, 2); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 4); }); test('diff array returns correctly given non-contiguous insertion', function(assert) { - const result = diffArray([a,c,e], [a,b,c,d,e]); + const result = diffArray([a, c, e], [a, b, c, d, e]); assert.equal(result.firstChangeIndex, 1); assert.equal(result.addedCount, 3); assert.equal(result.removedCount, 1); diff --git a/tests/unit/many-array-test.js b/tests/unit/many-array-test.js index d0f8b141c74..c80465b2853 100644 --- a/tests/unit/many-array-test.js +++ b/tests/unit/many-array-test.js @@ -14,29 +14,29 @@ module('unit/many_array - DS.ManyArray', { beforeEach() { Post = DS.Model.extend({ title: attr('string'), - tags: hasMany('tag', { async: false }) + tags: hasMany('tag', { async: false }), }); Post.reopenClass({ toString() { return 'Post'; - } + }, }); Tag = DS.Model.extend({ name: attr('string'), - post: belongsTo('post', { async: false }) + post: belongsTo('post', { async: false }), }); Tag.reopenClass({ toString() { return 'Tag'; - } + }, }); env = setupStore({ post: Post, - tag: Tag + tag: Tag, }); store = env.store; @@ -44,7 +44,7 @@ module('unit/many_array - DS.ManyArray', { afterEach() { run(store, 'destroy'); - } + }, }); test('manyArray.save() calls save() on all records', function(assert) { @@ -54,7 +54,7 @@ test('manyArray.save() calls save() on all records', function(assert) { save() { assert.ok(true, 'record.save() was called'); return resolve(); - } + }, }); return run(() => { @@ -64,38 +64,39 @@ test('manyArray.save() calls save() on all records', function(assert) { type: 'tag', id: '1', attributes: { - name: 'Ember.js' - } + name: 'Ember.js', + }, }, { type: 'tag', id: '2', attributes: { - name: 'Tomster' - } + name: 'Tomster', + }, }, { type: 'post', id: '3', attributes: { - title: 'A framework for creating ambitious web applications' + title: 'A framework for creating ambitious web applications', }, relationships: { tags: { - data: [ - { type: 'tag', id: '1' }, - { type: 'tag', id: '2' } - ] - } - } - }] + data: [{ type: 'tag', id: '1' }, { type: 'tag', id: '2' }], + }, + }, + }, + ], }); let post = store.peekRecord('post', 3); - return post.get('tags').save().then(() => { - assert.ok(true, 'manyArray.save() promise resolved'); - }); + return post + .get('tags') + .save() + .then(() => { + assert.ok(true, 'manyArray.save() promise resolved'); + }); }); }); @@ -111,7 +112,7 @@ test('manyArray trigger arrayContentChange functions with the correct values', f // override DS.ManyArray temp (cleanup occures in afterTest); - DS.ManyArray.proto().arrayContentWillChange = function(startIdx, removeAmt, addAmt) { + DS.ManyArray.proto().arrayContentWillChange = function(startIdx, removeAmt, addAmt) { willChangeStartIdx = startIdx; willChangeRemoveAmt = removeAmt; willChangeAddAmt = addAmt; @@ -135,31 +136,29 @@ test('manyArray trigger arrayContentChange functions with the correct values', f type: 'tag', id: '1', attributes: { - name: 'Ember.js' - } + name: 'Ember.js', + }, }, { type: 'tag', id: '2', attributes: { - name: 'Tomster' - } + name: 'Tomster', + }, }, { type: 'post', id: '3', attributes: { - title: 'A framework for creating ambitious web applications' + title: 'A framework for creating ambitious web applications', }, relationships: { tags: { - data: [ - { type: 'tag', id: '1' } - ] - } - } - } - ] + data: [{ type: 'tag', id: '1' }], + }, + }, + }, + ], }); store.peekRecord('post', 3).get('tags'); @@ -169,17 +168,14 @@ test('manyArray trigger arrayContentChange functions with the correct values', f type: 'post', id: '3', attributes: { - title: 'A framework for creating ambitious web applications' + title: 'A framework for creating ambitious web applications', }, relationships: { tags: { - data: [ - { type: 'tag', id: '1' }, - { type: 'tag', id: '2' } - ] - } - } - } + data: [{ type: 'tag', id: '1' }, { type: 'tag', id: '2' }], + }, + }, + }, }); }); } finally { diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 59e8f2896e6..9a8c00c256c 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -17,19 +17,19 @@ module('unit/model - DS.Model', { Person = DS.Model.extend({ name: DS.attr('string'), isDrugAddict: DS.attr('boolean'), - isArchived: DS.attr() + isArchived: DS.attr(), }); env = setupStore({ adapter: DS.JSONAPIAdapter, - person: Person + person: Person, }); store = env.store; }, afterEach() { run(() => store.destroy()); - } + }, }); test('can have a property set on it', function(assert) { @@ -53,18 +53,26 @@ test('setting a property on a record that has not changed does not cause it to b id: '1', attributes: { name: 'Peter', - isDrugAddict: true - } - } + isDrugAddict: true, + }, + }, }); return store.findRecord('person', 1).then(person => { - assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'precond - person record should not be dirty' + ); - person.set('name', "Peter"); + person.set('name', 'Peter'); person.set('isDrugAddict', true); - assert.equal(person.get('hasDirtyAttributes'), false, 'record does not become dirty after setting property to old value'); + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'record does not become dirty after setting property to old value' + ); }); }); }); @@ -80,17 +88,29 @@ test('resetting a property on a record cause it to become clean again', function id: '1', attributes: { name: 'Peter', - isDrugAddict: true - } - } + isDrugAddict: true, + }, + }, }); return store.findRecord('person', 1).then(person => { - assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'precond - person record should not be dirty' + ); person.set('isDrugAddict', false); - assert.equal(person.get('hasDirtyAttributes'), true, 'record becomes dirty after setting property to a new value'); + assert.equal( + person.get('hasDirtyAttributes'), + true, + 'record becomes dirty after setting property to a new value' + ); person.set('isDrugAddict', true); - assert.equal(person.get('hasDirtyAttributes'), false, 'record becomes clean after resetting property to the old value'); + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'record becomes clean after resetting property to the old value' + ); }); }); }); @@ -108,15 +128,15 @@ test('resetting a property to the current in-flight value causes it to become cl type: 'person', id: '1', attributes: { - name: 'Tom' - } - } + name: 'Tom', + }, + }, }); let person = store.peekRecord('person', 1); - person.set('name', "Thomas"); + person.set('name', 'Thomas'); - let saving = person.save() + let saving = person.save(); assert.equal(person.get('name'), 'Thomas'); @@ -143,21 +163,41 @@ test('a record becomes clean again only if all changed properties are reset', fu id: '1', attributes: { name: 'Peter', - isDrugAddict: true - } - } + isDrugAddict: true, + }, + }, }); - return store.findRecord('person', 1).then(person => { - assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); + return store.findRecord('person', 1).then(person => { + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'precond - person record should not be dirty' + ); person.set('isDrugAddict', false); - assert.equal(person.get('hasDirtyAttributes'), true, 'record becomes dirty after setting one property to a new value'); + assert.equal( + person.get('hasDirtyAttributes'), + true, + 'record becomes dirty after setting one property to a new value' + ); person.set('name', 'Mark'); - assert.equal(person.get('hasDirtyAttributes'), true, 'record stays dirty after setting another property to a new value'); + assert.equal( + person.get('hasDirtyAttributes'), + true, + 'record stays dirty after setting another property to a new value' + ); person.set('isDrugAddict', true); - assert.equal(person.get('hasDirtyAttributes'), true, 'record stays dirty after resetting only one property to the old value'); + assert.equal( + person.get('hasDirtyAttributes'), + true, + 'record stays dirty after resetting only one property to the old value' + ); person.set('name', 'Peter'); - assert.equal(person.get('hasDirtyAttributes'), false, "record becomes clean after resetting both properties to the old value"); + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'record becomes clean after resetting both properties to the old value' + ); }); }); }); @@ -177,16 +217,24 @@ test('an invalid record becomes clean again if changed property is reset', funct id: '1', attributes: { name: 'Peter', - isDrugAddict: true - } - } + isDrugAddict: true, + }, + }, }); let person = store.peekRecord('person', 1); - assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'precond - person record should not be dirty' + ); person.set('name', 'Wolf'); - assert.equal(person.get('hasDirtyAttributes'), true, 'record becomes dirty after setting one property to a new value'); + assert.equal( + person.get('hasDirtyAttributes'), + true, + 'record becomes dirty after setting one property to a new value' + ); return person.save().catch(() => { assert.equal(person.get('isValid'), false, 'record is not valid'); @@ -194,8 +242,16 @@ test('an invalid record becomes clean again if changed property is reset', funct person.set('name', 'Peter'); - assert.equal(person.get('isValid'), true, 'record is valid after resetting attribute to old value'); - assert.equal(person.get('hasDirtyAttributes'), false, "record becomes clean after resetting property to the old value"); + assert.equal( + person.get('isValid'), + true, + 'record is valid after resetting attribute to old value' + ); + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'record becomes clean after resetting property to the old value' + ); }); }); }); @@ -215,17 +271,25 @@ test('an invalid record stays dirty if only invalid property is reset', function id: '1', attributes: { name: 'Peter', - isDrugAddict: true - } - } + isDrugAddict: true, + }, + }, }); let person = store.peekRecord('person', 1); - assert.equal(person.get('hasDirtyAttributes'), false, 'precond - person record should not be dirty'); + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'precond - person record should not be dirty' + ); person.set('name', 'Wolf'); person.set('isDrugAddict', false); - assert.equal(person.get('hasDirtyAttributes'), true, 'record becomes dirty after setting one property to a new value'); + assert.equal( + person.get('hasDirtyAttributes'), + true, + 'record becomes dirty after setting one property to a new value' + ); return person.save().catch(() => { assert.equal(person.get('isValid'), false, 'record is not valid'); @@ -233,8 +297,12 @@ test('an invalid record stays dirty if only invalid property is reset', function person.set('name', 'Peter'); - assert.equal(person.get('isValid'), true, 'record is valid after resetting invalid attribute to old value'); - assert.equal(person.get('hasDirtyAttributes'), true, "record still has dirty attributes"); + assert.equal( + person.get('isValid'), + true, + 'record is valid after resetting invalid attribute to old value' + ); + assert.equal(person.get('hasDirtyAttributes'), true, 'record still has dirty attributes'); }); }); }); @@ -247,8 +315,8 @@ test('a record reports its unique id via the `id` property', function(assert) { store.push({ data: { type: 'person', - id: '1' - } + id: '1', + }, }); return store.findRecord('person', 1).then(record => { @@ -261,12 +329,14 @@ test("a record's id is included in its toString representation", function(assert assert.expect(1); env.adapter.shouldBackgroundReloadRecord = () => false; - let person = run(() => store.push({ - data: { - type: 'person', - id: '1' - } - })); + let person = run(() => + store.push({ + data: { + type: 'person', + id: '1', + }, + }) + ); assert.equal( person.toString(), @@ -278,11 +348,11 @@ test("a record's id is included in its toString representation", function(assert testInDebug('trying to set an `id` attribute should raise', function(assert) { Person = DS.Model.extend({ id: DS.attr('number'), - name: DS.attr('string') + name: DS.attr('string'), }); const store = createStore({ - person: Person + person: Person, }); assert.expectAssertion(() => { @@ -292,9 +362,9 @@ testInDebug('trying to set an `id` attribute should raise', function(assert) { type: 'person', id: '1', attributes: { - name: 'Scumdale' - } - } + name: 'Scumdale', + }, + }, }); store.findRecord('person', 1); }); @@ -314,12 +384,16 @@ test(`a collision of a record's id with object function's name`, function(assert store.push({ data: { type: 'person', - id: 'watch' - } + id: 'watch', + }, }); return store.findRecord('person', 'watch').then(record => { - assert.equal(get(record, 'id'), 'watch', 'record is successfully created and could be found by its id'); + assert.equal( + get(record, 'id'), + 'watch', + 'record is successfully created and could be found by its id' + ); }); }); } finally { @@ -335,11 +409,15 @@ test('it should use `_internalModel` and not `internalModel` to store its intern data: { type: 'person', id: 1, - attributes: {} - } + attributes: {}, + }, }); - assert.equal(store.peekRecord('person', 1).get('internalModel'), undefined, `doesn't shadow internalModel key`); + assert.equal( + store.peekRecord('person', 1).get('internalModel'), + undefined, + `doesn't shadow internalModel key` + ); }); }); @@ -347,14 +425,14 @@ test('it should cache attributes', function(assert) { assert.expect(2); const Post = DS.Model.extend({ - updatedAt: DS.attr('string') + updatedAt: DS.attr('string'), }); const store = createStore({ adapter: DS.JSONAPIAdapter.extend({ - shouldBackgroundReloadRecord: () => false + shouldBackgroundReloadRecord: () => false, }), - post: Post + post: Post, }); let dateString = 'Sat, 31 Dec 2011 00:08:16 GMT'; @@ -364,32 +442,39 @@ test('it should cache attributes', function(assert) { store.push({ data: { type: 'post', - id: '1' - } + id: '1', + }, }); - return store.findRecord('post', '1').then(record => { - record.set('updatedAt', date); - - assert.deepEqual(date, get(record, 'updatedAt'), 'setting a date returns the same date'); - assert.strictEqual(get(record, 'updatedAt'), get(record, 'updatedAt'), 'second get still returns the same object'); - }).finally(() => { - run(store, 'destroy'); - }); + return store + .findRecord('post', '1') + .then(record => { + record.set('updatedAt', date); + + assert.deepEqual(date, get(record, 'updatedAt'), 'setting a date returns the same date'); + assert.strictEqual( + get(record, 'updatedAt'), + get(record, 'updatedAt'), + 'second get still returns the same object' + ); + }) + .finally(() => { + run(store, 'destroy'); + }); }); }); -test("changedAttributes() return correct values", function(assert) { +test('changedAttributes() return correct values', function(assert) { assert.expect(4); const Mascot = DS.Model.extend({ name: DS.attr('string'), likes: DS.attr('string'), - isMascot: DS.attr('boolean') + isMascot: DS.attr('boolean'), }); let store = createStore({ - mascot: Mascot + mascot: Mascot, }); let mascot = run(() => { @@ -399,9 +484,9 @@ test("changedAttributes() return correct values", function(assert) { id: '1', attributes: { likes: 'JavaScript', - isMascot: true - } - } + isMascot: true, + }, + }, }); return store.peekRecord('mascot', 1); @@ -409,9 +494,9 @@ test("changedAttributes() return correct values", function(assert) { assert.equal(Object.keys(mascot.changedAttributes()).length, 0, 'there are no initial changes'); run(() => { - mascot.set('name', 'Tomster'); // new value + mascot.set('name', 'Tomster'); // new value mascot.set('likes', 'Ember.js'); // changed value - mascot.set('isMascot', true); // same value + mascot.set('isMascot', true); // same value }); let changedAttributes = mascot.changedAttributes(); @@ -421,7 +506,11 @@ test("changedAttributes() return correct values", function(assert) { run(() => mascot.rollbackAttributes()); - assert.equal(Object.keys(mascot.changedAttributes()).length, 0, 'after rollback attributes there are no changes'); + assert.equal( + Object.keys(mascot.changedAttributes()).length, + 0, + 'after rollback attributes there are no changes' + ); }); function toObj(obj) { @@ -441,29 +530,29 @@ test('changedAttributes() works while the record is being saved', function(asser createRecord(store, model, snapshot) { assert.deepEqual(toObj(cat.changedAttributes()), { name: [undefined, 'Argon'], - likes: [undefined, 'Cheese'] + likes: [undefined, 'Cheese'], }); return { data: { id: 1, type: 'mascot' } }; - } + }, }); const Mascot = DS.Model.extend({ name: DS.attr('string'), likes: DS.attr('string'), - isMascot: DS.attr('boolean') + isMascot: DS.attr('boolean'), }); let store = createStore({ mascot: Mascot, - adapter: Adapter + adapter: Adapter, }); return run(() => { cat = store.createRecord('mascot'); cat.setProperties({ name: 'Argon', - likes: 'Cheese' + likes: 'Cheese', }); return cat.save(); @@ -477,22 +566,22 @@ test('changedAttributes() works while the record is being updated', function(ass updateRecord(store, model, snapshot) { assert.deepEqual(toObj(cat.changedAttributes()), { name: ['Argon', 'Helia'], - likes: ['Cheese', 'Mussels'] + likes: ['Cheese', 'Mussels'], }); return { data: { id: '1', type: 'mascot' } }; - } + }, }); const Mascot = DS.Model.extend({ name: DS.attr('string'), likes: DS.attr('string'), - isMascot: DS.attr('boolean') + isMascot: DS.attr('boolean'), }); let store = createStore({ mascot: Mascot, - adapter: Adapter + adapter: Adapter, }); return run(() => { @@ -502,41 +591,41 @@ test('changedAttributes() works while the record is being updated', function(ass id: '1', attributes: { name: 'Argon', - likes: 'Cheese' - } - } + likes: 'Cheese', + }, + }, }); cat = store.peekRecord('mascot', 1); cat.setProperties({ name: 'Helia', - likes: 'Mussels' + likes: 'Mussels', }); return cat.save(); }); }); -test("a DS.Model does not require an attribute type", function(assert) { +test('a DS.Model does not require an attribute type', function(assert) { const Tag = DS.Model.extend({ - name: DS.attr() + name: DS.attr(), }); let store = createStore({ - tag: Tag + tag: Tag, }); - let tag = store.createRecord('tag', { name: "test" }); + let tag = store.createRecord('tag', { name: 'test' }); assert.equal(get(tag, 'name'), 'test', 'the value is persisted'); }); test('a DS.Model can have a defaultValue without an attribute type', function(assert) { const Tag = DS.Model.extend({ - name: DS.attr({ defaultValue: "unknown" }) + name: DS.attr({ defaultValue: 'unknown' }), }); let store = createStore({ - tag: Tag + tag: Tag, }); let tag = store.createRecord('tag'); @@ -549,25 +638,32 @@ testInDebug('Calling attr() throws a warning', function(assert) { let person = store.createRecord('person', { id: 1, name: 'TomHuda' }); - assert.throws(() => { - person.attr(); - }, /The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected/, 'attr() throws a warning'); + assert.throws( + () => { + person.attr(); + }, + /The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected/, + 'attr() throws a warning' + ); }); test('supports pushedData in root.deleted.uncommitted', function(assert) { let hash = { data: { type: 'person', - id: '1' - } + id: '1', + }, }; run(() => { let record = store.push(hash); record.deleteRecord(); store.push(hash); - assert.equal(get(record, 'currentState.stateName'), 'root.deleted.uncommitted', - 'record accepts pushedData is in root.deleted.uncommitted state'); + assert.equal( + get(record, 'currentState.stateName'), + 'root.deleted.uncommitted', + 'record accepts pushedData is in root.deleted.uncommitted state' + ); }); }); @@ -579,24 +675,31 @@ test('supports canonical updates via pushedData in root.deleted.saved', function return Ember.RSVP.resolve(); }; - let record = run(() => store.push({ - data: { - type: 'person', - id: '1', - attributes: { - isArchived: false - } - } - })); + let record = run(() => + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + isArchived: false, + }, + }, + }) + ); run(() => { record.destroyRecord().then(() => { let currentState = record._internalModel.currentState; - assert.ok(currentState.stateName === 'root.deleted.saved', - 'record is in a persisted deleted state'); + assert.ok( + currentState.stateName === 'root.deleted.saved', + 'record is in a persisted deleted state' + ); assert.equal(get(record, 'isDeleted'), true); - assert.ok(store.peekRecord('person', '1') !== null, 'the deleted person is not removed from store (no unload called)'); + assert.ok( + store.peekRecord('person', '1') !== null, + 'the deleted person is not removed from store (no unload called)' + ); }); }); @@ -606,21 +709,25 @@ test('supports canonical updates via pushedData in root.deleted.saved', function type: 'person', id: '1', attributes: { - isArchived: true - } - } + isArchived: true, + }, + }, }); let currentState = record._internalModel.currentState; - assert.ok(currentState.stateName === 'root.deleted.saved', - 'record is still in a persisted deleted state'); + assert.ok( + currentState.stateName === 'root.deleted.saved', + 'record is still in a persisted deleted state' + ); assert.ok(get(record, 'isDeleted') === true, 'The record is still deleted'); - assert.ok(get(record, 'isArchived') === true, 'The record reflects the update to canonical state'); + assert.ok( + get(record, 'isArchived') === true, + 'The record reflects the update to canonical state' + ); }); }); - test('Does not support dirtying in root.deleted.saved', function(assert) { let { adapter } = env; @@ -629,24 +736,31 @@ test('Does not support dirtying in root.deleted.saved', function(assert) { return Ember.RSVP.resolve(); }; - let record = run(() => store.push({ - data: { - type: 'person', - id: '1', - attributes: { - isArchived: false - } - } - })); + let record = run(() => + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + isArchived: false, + }, + }, + }) + ); run(() => { record.destroyRecord().then(() => { let currentState = record._internalModel.currentState; - assert.ok(currentState.stateName === 'root.deleted.saved', - 'record is in a persisted deleted state'); + assert.ok( + currentState.stateName === 'root.deleted.saved', + 'record is in a persisted deleted state' + ); assert.equal(get(record, 'isDeleted'), true); - assert.ok(store.peekRecord('person', '1') !== null, 'the deleted person is not removed from store (no unload called)'); + assert.ok( + store.peekRecord('person', '1') !== null, + 'the deleted person is not removed from store (no unload called)' + ); }); }); @@ -657,8 +771,10 @@ test('Does not support dirtying in root.deleted.saved', function(assert) { let currentState = record._internalModel.currentState; - assert.ok(currentState.stateName === 'root.deleted.saved', - 'record is still in a persisted deleted state'); + assert.ok( + currentState.stateName === 'root.deleted.saved', + 'record is still in a persisted deleted state' + ); assert.ok(get(record, 'isDeleted') === true, 'The record is still deleted'); assert.ok(get(record, 'isArchived') === false, 'The record reflects canonical state'); }); @@ -668,25 +784,28 @@ test('currentState is accessible when the record is created', function(assert) { let hash = { data: { type: 'person', - id: '1' - } + id: '1', + }, }; run(() => { let record = store.push(hash); - assert.equal(get(record, 'currentState.stateName'), 'root.loaded.saved', - 'records pushed into the store start in the loaded state'); + assert.equal( + get(record, 'currentState.stateName'), + 'root.loaded.saved', + 'records pushed into the store start in the loaded state' + ); }); }); module('unit/model - DS.Model updating', { beforeEach() { Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); env = setupStore({ - person: Person + person: Person, }); store = env.store; @@ -697,30 +816,31 @@ module('unit/model - DS.Model updating', { type: 'person', id: '1', attributes: { - name: 'Scumbag Dale' - } + name: 'Scumbag Dale', + }, }, { type: 'person', id: '2', attributes: { - name: 'Scumbag Katz' - } + name: 'Scumbag Katz', + }, }, { type: 'person', id: '3', attributes: { - name: 'Scumbag Bryn' - } - }] + name: 'Scumbag Bryn', + }, + }, + ], }); }); }, afterEach() { run(store, 'destroy'); - } + }, }); test('a DS.Model can update its attributes', function(assert) { @@ -737,11 +857,11 @@ test('a DS.Model can update its attributes', function(assert) { test('a DS.Model can have a defaultValue', function(assert) { const Tag = DS.Model.extend({ - name: DS.attr('string', { defaultValue: 'unknown' }) + name: DS.attr('string', { defaultValue: 'unknown' }), }); let store = createStore({ - tag: Tag + tag: Tag, }); let tag = store.createRecord('tag'); @@ -761,15 +881,15 @@ test(`a DS.model can define 'setUnknownProperty'`, function(assert) { if (key === 'title') { this.set('name', value); } - } + }, }); let store = createStore({ - tag: Tag + tag: Tag, }); let tag = run(() => { - tag = store.createRecord('tag', { name: "old" }); + tag = store.createRecord('tag', { name: 'old' }); set(tag, 'title', 'new'); return tag; @@ -783,12 +903,12 @@ test('a defaultValue for an attribute can be a function', function(assert) { createdAt: DS.attr('string', { defaultValue() { return 'le default value'; - } - }) + }, + }), }); let store = createStore({ - tag: Tag + tag: Tag, }); let tag = store.createRecord('tag'); @@ -804,12 +924,12 @@ test('a defaultValue function gets the record, options, and key', function(asser assert.deepEqual(record, tag, 'the record is passed in properly'); assert.equal(key, 'createdAt', 'the attribute being defaulted is passed in properly'); return 'le default value'; - } - }) + }, + }), }); let store = createStore({ - tag: Tag + tag: Tag, }); let tag = store.createRecord('tag'); @@ -819,11 +939,11 @@ test('a defaultValue function gets the record, options, and key', function(asser testInDebug('a complex object defaultValue is deprecated', function(assert) { const Tag = DS.Model.extend({ - tagInfo: DS.attr({ defaultValue: [] }) + tagInfo: DS.attr({ defaultValue: [] }), }); let store = createStore({ - tag: Tag + tag: Tag, }); let tag = store.createRecord('tag'); @@ -835,11 +955,11 @@ testInDebug('a complex object defaultValue is deprecated', function(assert) { test('setting a property to undefined on a newly created record should not impact the current state', function(assert) { const Tag = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let store = createStore({ - tag: Tag + tag: Tag, }); let tag = run(() => { @@ -851,7 +971,6 @@ test('setting a property to undefined on a newly created record should not impac return tag; }); - assert.equal(get(tag, 'currentState.stateName'), 'root.loaded.created.uncommitted'); tag = store.createRecord('tag', { name: undefined }); @@ -873,7 +992,11 @@ test('setting a property back to its original value removes the property from th set(person, 'name', 'Niceguy Dale'); - assert.equal(dataSource._attributes.name, 'Niceguy Dale', 'the `_attributes` hash contains the changed value'); + assert.equal( + dataSource._attributes.name, + 'Niceguy Dale', + 'the `_attributes` hash contains the changed value' + ); set(person, 'name', 'Scumbag Dale'); @@ -882,13 +1005,13 @@ test('setting a property back to its original value removes the property from th }); }); -module("unit/model - with a simple Person model", { +module('unit/model - with a simple Person model', { beforeEach() { Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); store = createStore({ - person: Person + person: Person, }); run(() => { @@ -898,29 +1021,30 @@ module("unit/model - with a simple Person model", { type: 'person', id: '1', attributes: { - name: 'Scumbag Dale' - } + name: 'Scumbag Dale', + }, }, { type: 'person', id: '2', attributes: { - name: 'Scumbag Katz' - } + name: 'Scumbag Katz', + }, }, { type: 'person', id: '3', attributes: { - name: 'Scumbag Bryn' - } - }] + name: 'Scumbag Bryn', + }, + }, + ], }); }); }, afterEach() { run(store, 'destroy'); - } + }, }); test('can ask if record with a given id is loaded', function(assert) { @@ -930,9 +1054,11 @@ test('can ask if record with a given id is loaded', function(assert) { assert.equal(store.hasRecordForId('person', 4), false, 'should not have person with id 4'); }); -test("a listener can be added to a record", function(assert) { +test('a listener can be added to a record', function(assert) { let count = 0; - let F = function() { count++; }; + let F = function() { + count++; + }; let record = store.createRecord('person'); @@ -948,19 +1074,23 @@ test("a listener can be added to a record", function(assert) { test('when an event is triggered on a record the method with the same name is invoked with arguments', function(assert) { let count = 0; - let F = function() { count++; }; + let F = function() { + count++; + }; let record = store.createRecord('person'); record.eventNamedMethod = F; run(() => record.trigger('eventNamedMethod')); - assert.equal(count, 1, "the corresponding method was called"); + assert.equal(count, 1, 'the corresponding method was called'); }); test('when a method is invoked from an event with the same name the arguments are passed through', function(assert) { let eventMethodArgs = null; - let F = function() { eventMethodArgs = arguments; }; + let F = function() { + eventMethodArgs = arguments; + }; let record = store.createRecord('person'); record.eventThatTriggersMethod = F; @@ -973,7 +1103,7 @@ test('when a method is invoked from an event with the same name the arguments ar function converts(assert, type, provided, expected, options = {}) { const Model = DS.Model.extend({ - name: DS.attr(type, options) + name: DS.attr(type, options), }); let registry, container; @@ -986,7 +1116,7 @@ function converts(assert, type, provided, expected, options = {}) { } let testStore = createStore({ - model: Model + model: Model, }); getOwner(testStore).register('serializer:model', DS.JSONSerializer); @@ -996,7 +1126,11 @@ function converts(assert, type, provided, expected, options = {}) { let record = testStore.peekRecord('model', 1); - assert.deepEqual(get(record, 'name'), expected, type + ' coerces ' + provided + ' to ' + expected); + assert.deepEqual( + get(record, 'name'), + expected, + type + ' coerces ' + provided + ' to ' + expected + ); }); // See: Github issue #421 @@ -1007,7 +1141,7 @@ function converts(assert, type, provided, expected, options = {}) { function convertsFromServer(assert, type, provided, expected) { const Model = DS.Model.extend({ - name: DS.attr(type) + name: DS.attr(type), }); let registry, container; @@ -1021,19 +1155,27 @@ function convertsFromServer(assert, type, provided, expected) { let testStore = createStore({ model: Model, adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord() { return false; } - }) + shouldBackgroundReloadRecord() { + return false; + }, + }), }); getOwner(testStore).register('serializer:model', DS.JSONSerializer); return run(() => { - testStore.push(testStore.normalize('model', { - id: '1', - name: provided - })); + testStore.push( + testStore.normalize('model', { + id: '1', + name: provided, + }) + ); return testStore.findRecord('model', 1).then(record => { - assert.deepEqual(get(record, 'name'), expected, type + ' coerces ' + provided + ' to ' + expected); + assert.deepEqual( + get(record, 'name'), + expected, + type + ' coerces ' + provided + ' to ' + expected + ); }); }); } @@ -1054,7 +1196,7 @@ test('a DS.Model can describe Number attributes', function(assert) { converts(assert, 'number', '0', 0); converts(assert, 'number', 1, 1); converts(assert, 'number', 0, 0); - converts(assert, 'number', "", null); + converts(assert, 'number', '', null); converts(assert, 'number', null, null); converts(assert, 'number', true, 1); converts(assert, 'number', false, 0); @@ -1062,7 +1204,7 @@ test('a DS.Model can describe Number attributes', function(assert) { test('a DS.Model can describe Boolean attributes', function(assert) { converts(assert, 'boolean', '1', true); - converts(assert, 'boolean', "", false); + converts(assert, 'boolean', '', false); converts(assert, 'boolean', 1, true); converts(assert, 'boolean', 0, false); @@ -1086,22 +1228,24 @@ test('a DS.Model can describe Date attributes', function(assert) { let date = new Date(dateString); const Person = DS.Model.extend({ - updatedAt: DS.attr('date') + updatedAt: DS.attr('date'), }); let store = createStore({ person: Person, adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord() { return false; } - }) + shouldBackgroundReloadRecord() { + return false; + }, + }), }); return run(() => { store.push({ data: { type: 'person', - id: '1' - } + id: '1', + }, }); return store.findRecord('person', 1).then(record => { @@ -1117,13 +1261,13 @@ test('a DS.Model can describe Date attributes', function(assert) { function convertsWhenSet(assert, type, provided, expected) { let testStore = createStore({ model: DS.Model.extend({ - name: DS.attr(type) + name: DS.attr(type), }), adapter: DS.Adapter.extend({ shouldBackgroundReloadRecord() { return false; - } - }) + }, + }), }); getOwner(testStore).register('serializer:model', DS.JSONSerializer); @@ -1131,13 +1275,17 @@ function convertsWhenSet(assert, type, provided, expected) { testStore.push({ data: { type: 'model', - id: '2' - } + id: '2', + }, }); return testStore.findRecord('model', 2).then(record => { set(record, 'name', provided); - assert.deepEqual(record.serialize().name, expected, type + ' saves ' + provided + ' as ' + expected); + assert.deepEqual( + record.serialize().name, + expected, + type + ' saves ' + provided + ' as ' + expected + ); }); }); } @@ -1146,7 +1294,7 @@ testInDebug(`don't allow setting`, function(assert) { const Person = DS.Model.extend(); let store = createStore({ - person: Person + person: Person, }); let record = store.createRecord('person'); @@ -1168,17 +1316,21 @@ test('ensure model exits loading state, materializes data and fulfills promise o data: { id: 1, type: 'person', - attributes: { name: 'John' } - } + attributes: { name: 'John' }, + }, }); - } + }, }), - person: Person + person: Person, }); return run(() => { return store.findRecord('person', 1).then(person => { - assert.equal(get(person, 'currentState.stateName'), 'root.loaded.saved', 'model is in loaded state'); + assert.equal( + get(person, 'currentState.stateName'), + 'root.loaded.saved', + 'model is in loaded state' + ); assert.equal(get(person, 'isLoaded'), true, 'model is loaded'); }); }); @@ -1186,7 +1338,7 @@ test('ensure model exits loading state, materializes data and fulfills promise o test('A DS.Model can be JSONified', function(assert) { const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let store = createStore({ person: Person }); @@ -1198,7 +1350,7 @@ test('A DS.Model can be JSONified', function(assert) { testInDebug('A subclass of DS.Model can not use the `data` property', function(assert) { const Person = DS.Model.extend({ data: DS.attr('string'), - name: DS.attr('string') + name: DS.attr('string'), }); let store = createStore({ person: Person }); @@ -1211,7 +1363,7 @@ testInDebug('A subclass of DS.Model can not use the `data` property', function(a testInDebug('A subclass of DS.Model can not use the `store` property', function(assert) { const Retailer = DS.Model.extend({ store: DS.attr(), - name: DS.attr() + name: DS.attr(), }); let store = createStore({ retailer: Retailer }); @@ -1223,9 +1375,7 @@ testInDebug('A subclass of DS.Model can not use the `store` property', function( testInDebug('A subclass of DS.Model can not use reserved properties', function(assert) { assert.expect(3); - [ - 'currentState', 'data', 'store' - ].forEach(reservedProperty => { + ['currentState', 'data', 'store'].forEach(reservedProperty => { let invalidExtendObject = {}; invalidExtendObject[reservedProperty] = DS.attr(); const Post = DS.Model.extend(invalidExtendObject); @@ -1240,7 +1390,7 @@ testInDebug('A subclass of DS.Model can not use reserved properties', function(a test('Pushing a record into the store should transition it to the loaded state', function(assert) { const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let store = createStore({ person: Person }); @@ -1254,32 +1404,38 @@ test('Pushing a record into the store should transition it to the loaded state', type: 'person', id: '1', attributes: { - name: 'TomHuda' - } - } + name: 'TomHuda', + }, + }, }); assert.equal(person.get('isNew'), false, 'push should put records into the loaded state'); }); }); -testInDebug('A subclass of DS.Model throws an error when calling create() directly', function(assert) { - assert.throws(() => { - Person.create(); - }, /You should not call `create` on a model/, 'Throws an error when calling create() on model'); +testInDebug('A subclass of DS.Model throws an error when calling create() directly', function( + assert +) { + assert.throws( + () => { + Person.create(); + }, + /You should not call `create` on a model/, + 'Throws an error when calling create() on model' + ); }); test('toJSON looks up the JSONSerializer using the store instead of using JSONSerializer.create', function(assert) { const Person = DS.Model.extend({ - posts: DS.hasMany('post', { async: false }) + posts: DS.hasMany('post', { async: false }), }); const Post = DS.Model.extend({ - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); let env = setupStore({ person: Person, - post: Post + post: Post, }); let { store } = env; @@ -1292,8 +1448,8 @@ test('toJSON looks up the JSONSerializer using the store instead of using JSONSe return store.push({ data: { type: 'person', - id: '1' - } + id: '1', + }, }); }); @@ -1306,7 +1462,7 @@ test('toJSON looks up the JSONSerializer using the store instead of using JSONSe } assert.ok(!errorThrown, 'error not thrown due to missing store'); - assert.deepEqual(json, { data: { type: 'people' }}); + assert.deepEqual(json, { data: { type: 'people' } }); }); test('internalModel is ready by `init`', function(assert) { @@ -1321,7 +1477,7 @@ test('internalModel is ready by `init`', function(assert) { this.set('name', 'my-name-set-in-init'); }, - nameDidChange: observer('name', () => nameDidChange++) + nameDidChange: observer('name', () => nameDidChange++), }); let { store } = setupStore({ person: Person }); @@ -1340,11 +1496,11 @@ test('accessing attributes in the initializer should not throw an error', functi init() { this._super(...arguments); assert.ok(!this.get('name')); - } + }, }); let { store } = setupStore({ - person: Person + person: Person, }); store.createRecord('person'); @@ -1354,11 +1510,11 @@ test('setting the id after model creation should correctly update the id', funct assert.expect(2); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let { store } = setupStore({ - person: Person + person: Person, }); let person = store.createRecord('person'); @@ -1372,101 +1528,112 @@ test('setting the id after model creation should correctly update the id', funct }); }); -testRecordData('updating the id with store.setRecordId should correctly when the id property is watched', function(assert) { - assert.expect(2); - - const Person = DS.Model.extend({ - name: DS.attr('string'), - idComputed: computed('id', function() {}) - }); +testRecordData( + 'updating the id with store.setRecordId should correctly when the id property is watched', + function(assert) { + assert.expect(2); - let { store } = setupStore({ - person: Person - }); + const Person = DS.Model.extend({ + name: DS.attr('string'), + idComputed: computed('id', function() {}), + }); - run(() => { - let person = store.createRecord('person'); - person.get('idComputed'); + let { store } = setupStore({ + person: Person, + }); - assert.equal(person.get('id'), null, 'initial created model id should be null'); + run(() => { + let person = store.createRecord('person'); + person.get('idComputed'); - store.setRecordId('person', 'john', person._internalModel.clientId); + assert.equal(person.get('id'), null, 'initial created model id should be null'); - assert.equal(person.id, 'john', 'new id should be correctly set.'); - }); -}); + store.setRecordId('person', 'john', person._internalModel.clientId); -skipRecordData('updating the id with store.updateId should correctly when the id property is watched', function(assert) { - assert.expect(2); + assert.equal(person.id, 'john', 'new id should be correctly set.'); + }); + } +); - const Person = DS.Model.extend({ - name: DS.attr('string'), - idComputed: computed('id', function() {}) - }); +skipRecordData( + 'updating the id with store.updateId should correctly when the id property is watched', + function(assert) { + assert.expect(2); - let { store } = setupStore({ - person: Person - }); + const Person = DS.Model.extend({ + name: DS.attr('string'), + idComputed: computed('id', function() {}), + }); - run(() => { - let person = store.createRecord('person'); - person.get('idComputed'); + let { store } = setupStore({ + person: Person, + }); - assert.equal(person.get('id'), null, 'initial created model id should be null'); + run(() => { + let person = store.createRecord('person'); + person.get('idComputed'); - store.updateId(person._internalModel, { id: 'john' }); - assert.equal(person.id, 'john', 'new id should be correctly set.'); - }); -}); + assert.equal(person.get('id'), null, 'initial created model id should be null'); -testRecordData('accessing the model id without the get function should work when id is watched', function(assert) { - assert.expect(2); + store.updateId(person._internalModel, { id: 'john' }); + assert.equal(person.id, 'john', 'new id should be correctly set.'); + }); + } +); - const Person = DS.Model.extend({ - name: DS.attr('string'), - idComputed: computed('id', function() {}) - }); +testRecordData( + 'accessing the model id without the get function should work when id is watched', + function(assert) { + assert.expect(2); - let { store } = setupStore({ - person: Person - }); + const Person = DS.Model.extend({ + name: DS.attr('string'), + idComputed: computed('id', function() {}), + }); - run(() => { - let person = store.createRecord('person'); - person.get('idComputed'); + let { store } = setupStore({ + person: Person, + }); - assert.equal(person.get('id'), null, 'initial created model id should be null'); + run(() => { + let person = store.createRecord('person'); + person.get('idComputed'); - store.setRecordId('person', 'john', person._internalModel.clientId); + assert.equal(person.get('id'), null, 'initial created model id should be null'); - assert.equal(person.id, 'john', 'new id should be correctly set.'); - }); -}); + store.setRecordId('person', 'john', person._internalModel.clientId); -skipRecordData('accessing the model id without the get function should work when id is watched', function(assert) { - assert.expect(2); + assert.equal(person.id, 'john', 'new id should be correctly set.'); + }); + } +); - const Person = DS.Model.extend({ - name: DS.attr('string'), - idComputed: computed('id', function() {}) - }); +skipRecordData( + 'accessing the model id without the get function should work when id is watched', + function(assert) { + assert.expect(2); - let { store } = setupStore({ - person: Person - }); + const Person = DS.Model.extend({ + name: DS.attr('string'), + idComputed: computed('id', function() {}), + }); - run(() => { - let person = store.createRecord('person'); - person.get('idComputed'); + let { store } = setupStore({ + person: Person, + }); - assert.equal(person.get('id'), null, 'initial created model id should be null'); + run(() => { + let person = store.createRecord('person'); + person.get('idComputed'); - store.updateId(person._internalModel, { id: 'john' }); + assert.equal(person.get('id'), null, 'initial created model id should be null'); - assert.equal(person.id, 'john', 'new id should be correctly set.'); - }); -}); + store.updateId(person._internalModel, { id: 'john' }); + assert.equal(person.id, 'john', 'new id should be correctly set.'); + }); + } +); test('ID mutation (complicated)', function(assert) { assert.expect(5); @@ -1474,11 +1641,11 @@ test('ID mutation (complicated)', function(assert) { const Person = DS.Model.extend({ name: DS.attr('string'), idComputed: Ember.computed('id', function() {}), - idDidChange: Ember.observer('id', () => idChange++) + idDidChange: Ember.observer('id', () => idChange++), }); let { store } = setupStore({ - person: Person.extend() + person: Person.extend(), }); run(() => { diff --git a/tests/unit/model/errors-test.js b/tests/unit/model/errors-test.js index d81f7dc7de4..0cffcb12fd0 100644 --- a/tests/unit/model/errors-test.js +++ b/tests/unit/model/errors-test.js @@ -9,11 +9,14 @@ let errors; module('unit/model/errors', { beforeEach() { errors = DS.Errors.create(); - } + }, }); function updateErrors(func, assert) { - assert.expectWarning(func, 'Interacting with a record errors object will no longer change the record state.'); + assert.expectWarning( + func, + 'Interacting with a record errors object will no longer change the record state.' + ); } AssertPrototype.becameInvalid = function becameInvalid(eventName) { @@ -67,11 +70,11 @@ testInDebug('get error', function(assert) { assert.deepEqual(errors.toArray(), [ { attribute: 'firstName', message: 'error' }, { attribute: 'firstName', message: 'error2' }, - { attribute: 'lastName', message: 'error3' } + { attribute: 'lastName', message: 'error3' }, ]); assert.deepEqual(errors.get('firstName'), [ { attribute: 'firstName', message: 'error' }, - { attribute: 'firstName', message: 'error2' } + { attribute: 'firstName', message: 'error2' }, ]); assert.deepEqual(errors.get('messages'), ['error', 'error2', 'error3']); }); diff --git a/tests/unit/model/init-properties-test.js b/tests/unit/model/init-properties-test.js index 5651f87679b..5cbc74d852c 100644 --- a/tests/unit/model/init-properties-test.js +++ b/tests/unit/model/init-properties-test.js @@ -11,11 +11,11 @@ function setupModels(testState) { let types; const Comment = Model.extend({ text: attr(), - post: belongsTo('post', { async: false, inverse: 'comments' }) + post: belongsTo('post', { async: false, inverse: 'comments' }), }); const Author = Model.extend({ name: attr(), - post: belongsTo('post', { async: false, inverse: 'author' }) + post: belongsTo('post', { async: false, inverse: 'author' }), }); const Post = Model.extend({ title: attr(), @@ -24,19 +24,19 @@ function setupModels(testState) { init() { this._super(...arguments); testState(types, this); - } + }, }); types = { Author, Comment, - Post + Post, }; return setupStore({ adapter: JSONAPIAdapter.extend(), post: Post, comment: Comment, - author: Author + author: Author, }); } @@ -49,9 +49,18 @@ test('createRecord(properties) makes properties available during record init', f function testState(types, record) { assert.ok(get(record, 'title') === 'My Post', 'Attrs are available as expected'); - assert.ok(get(record, 'randomProp') === 'An unknown prop', 'Unknown properties are available as expected'); - assert.ok(get(record, 'author') instanceof types.Author, 'belongsTo relationships are available as expected'); - assert.ok(get(record, 'comments.firstObject') instanceof types.Comment, 'hasMany relationships are available as expected'); + assert.ok( + get(record, 'randomProp') === 'An unknown prop', + 'Unknown properties are available as expected' + ); + assert.ok( + get(record, 'author') instanceof types.Author, + 'belongsTo relationships are available as expected' + ); + assert.ok( + get(record, 'comments.firstObject') instanceof types.Comment, + 'hasMany relationships are available as expected' + ); } let { store } = setupModels(testState); @@ -62,18 +71,18 @@ test('createRecord(properties) makes properties available during record init', f type: 'comment', id: '1', attributes: { - text: 'Hello darkness my old friend' - } - } + text: 'Hello darkness my old friend', + }, + }, }); author = store.push({ data: { type: 'author', id: '1', attributes: { - name: '@runspired' - } - } + name: '@runspired', + }, + }, }); }); @@ -82,7 +91,7 @@ test('createRecord(properties) makes properties available during record init', f title: 'My Post', randomProp: 'An unknown prop', comments: [comment], - author + author, }); }); }); @@ -92,45 +101,53 @@ test('store.push() makes properties available during record init', function(asse function testState(types, record) { assert.ok(get(record, 'title') === 'My Post', 'Attrs are available as expected'); - assert.ok(get(record, 'author') instanceof types.Author, 'belongsTo relationships are available as expected'); - assert.ok(get(record, 'comments.firstObject') instanceof types.Comment, 'hasMany relationships are available as expected'); + assert.ok( + get(record, 'author') instanceof types.Author, + 'belongsTo relationships are available as expected' + ); + assert.ok( + get(record, 'comments.firstObject') instanceof types.Comment, + 'hasMany relationships are available as expected' + ); } let { store } = setupModels(testState); - run(() => store.push({ - data: { - type: 'post', - id: '1', - attributes: { - title: 'My Post' - }, - relationships: { - comments: { - data: [{ type: 'comment', id: '1' }] - }, - author: { - data: { type: 'author', id: '1' } - } - } - }, - included: [ - { - type: 'comment', + run(() => + store.push({ + data: { + type: 'post', id: '1', attributes: { - text: 'Hello darkness my old friend' - } + title: 'My Post', + }, + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }], + }, + author: { + data: { type: 'author', id: '1' }, + }, + }, }, - { - type: 'author', - id: '1', - attributes: { - name: '@runspired' - } - } - ] - })); + included: [ + { + type: 'comment', + id: '1', + attributes: { + text: 'Hello darkness my old friend', + }, + }, + { + type: 'author', + id: '1', + attributes: { + name: '@runspired', + }, + }, + ], + }) + ); }); test('store.findRecord(type, id) makes properties available during record init', function(assert) { @@ -138,8 +155,14 @@ test('store.findRecord(type, id) makes properties available during record init', function testState(types, record) { assert.ok(get(record, 'title') === 'My Post', 'Attrs are available as expected'); - assert.ok(get(record, 'author') instanceof types.Author, 'belongsTo relationships are available as expected'); - assert.ok(get(record, 'comments.firstObject') instanceof types.Comment, 'hasMany relationships are available as expected'); + assert.ok( + get(record, 'author') instanceof types.Author, + 'belongsTo relationships are available as expected' + ); + assert.ok( + get(record, 'comments.firstObject') instanceof types.Comment, + 'hasMany relationships are available as expected' + ); } let { adapter, store } = setupModels(testState); @@ -150,33 +173,33 @@ test('store.findRecord(type, id) makes properties available during record init', type: 'post', id: '1', attributes: { - title: 'My Post' + title: 'My Post', }, relationships: { comments: { - data: [{ type: 'comment', id: '1' }] + data: [{ type: 'comment', id: '1' }], }, author: { - data: { type: 'author', id: '1' } - } - } + data: { type: 'author', id: '1' }, + }, + }, }, included: [ { type: 'comment', id: '1', attributes: { - text: 'Hello darkness my old friend' - } + text: 'Hello darkness my old friend', + }, }, { type: 'author', id: '1', attributes: { - name: '@runspired' - } - } - ] + name: '@runspired', + }, + }, + ], }); }; @@ -188,8 +211,14 @@ test('store.queryRecord(type, query) makes properties available during record in function testState(types, record) { assert.ok(get(record, 'title') === 'My Post', 'Attrs are available as expected'); - assert.ok(get(record, 'author') instanceof types.Author, 'belongsTo relationships are available as expected'); - assert.ok(get(record, 'comments.firstObject') instanceof types.Comment, 'hasMany relationships are available as expected'); + assert.ok( + get(record, 'author') instanceof types.Author, + 'belongsTo relationships are available as expected' + ); + assert.ok( + get(record, 'comments.firstObject') instanceof types.Comment, + 'hasMany relationships are available as expected' + ); } let { adapter, store } = setupModels(testState); @@ -200,33 +229,33 @@ test('store.queryRecord(type, query) makes properties available during record in type: 'post', id: '1', attributes: { - title: 'My Post' + title: 'My Post', }, relationships: { comments: { - data: [{ type: 'comment', id: '1' }] + data: [{ type: 'comment', id: '1' }], }, author: { - data: { type: 'author', id: '1' } - } - } + data: { type: 'author', id: '1' }, + }, + }, }, included: [ { type: 'comment', id: '1', attributes: { - text: 'Hello darkness my old friend' - } + text: 'Hello darkness my old friend', + }, }, { type: 'author', id: '1', attributes: { - name: '@runspired' - } - } - ] + name: '@runspired', + }, + }, + ], }); }; diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index c007aac027a..5693aeb1a5b 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -16,18 +16,18 @@ test('a record receives a didLoad callback when it has finished loading', functi name: DS.attr(), didLoad() { assert.ok('The didLoad callback was called'); - } + }, }); const Adapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; - } + }, }); let store = createStore({ adapter: Adapter, - person: Person + person: Person, }); return run(() => { @@ -45,19 +45,19 @@ test(`TEMPORARY: a record receives a didLoad callback once it materializes if it name: DS.attr(), didLoad() { didLoadCalled++; - } + }, }); let store = createStore({ - person: Person + person: Person, }); run(() => { store._pushInternalModel({ id: 1, type: 'person' }); - assert.equal(didLoadCalled, 0, "didLoad was not called"); + assert.equal(didLoadCalled, 0, 'didLoad was not called'); }); run(() => store.peekRecord('person', 1)); - assert.equal(didLoadCalled, 1, "didLoad was called"); + assert.equal(didLoadCalled, 1, 'didLoad was called'); }); test('a record receives a didUpdate callback when it has finished updating', function(assert) { @@ -73,7 +73,7 @@ test('a record receives a didUpdate callback when it has finished updating', fun callCount++; assert.equal(get(this, 'isSaving'), false, 'record should be saving'); assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); - } + }, }); const Adapter = DS.Adapter.extend({ @@ -85,12 +85,12 @@ test('a record receives a didUpdate callback when it has finished updating', fun assert.equal(callCount, 0, 'didUpdate callback was not called until didSaveRecord is called'); return resolve(); - } + }, }); let store = createStore({ adapter: Adapter, - person: Person + person: Person, }); let asyncPerson = run(() => store.findRecord('person', 1)); @@ -98,14 +98,16 @@ test('a record receives a didUpdate callback when it has finished updating', fun assert.equal(callCount, 0, 'precond - didUpdate callback was not called yet'); return run(() => { - return asyncPerson.then(person => { - return run(() => { - person.set('bar', "Bar"); - return person.save(); + return asyncPerson + .then(person => { + return run(() => { + person.set('bar', 'Bar'); + return person.save(); + }); + }) + .then(() => { + assert.equal(callCount, 1, 'didUpdate called after update'); }); - }).then(() => { - assert.equal(callCount, 1, 'didUpdate called after update'); - }); }); }); @@ -119,7 +121,7 @@ test('a record receives a didCreate callback when it has finished updating', fun callCount++; assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); - } + }, }); const Adapter = DS.Adapter.extend({ @@ -127,12 +129,12 @@ test('a record receives a didCreate callback when it has finished updating', fun assert.equal(callCount, 0, 'didCreate callback was not called until didSaveRecord is called'); return resolve(); - } + }, }); let store = createStore({ adapter: Adapter, - person: Person + person: Person, }); assert.equal(callCount, 0, 'precond - didCreate callback was not called yet'); @@ -159,7 +161,7 @@ test('a record receives a didDelete callback when it has finished deleting', fun assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); - } + }, }); const Adapter = DS.Adapter.extend({ @@ -171,26 +173,28 @@ test('a record receives a didDelete callback when it has finished deleting', fun assert.equal(callCount, 0, 'didDelete callback was not called until didSaveRecord is called'); return resolve(); - } + }, }); let store = createStore({ adapter: Adapter, - person: Person + person: Person, }); let asyncPerson = run(() => store.findRecord('person', 1)); assert.equal(callCount, 0, 'precond - didDelete callback was not called yet'); return run(() => { - return asyncPerson.then(person => { - return run(() => { - person.deleteRecord(); - return person.save(); + return asyncPerson + .then(person => { + return run(() => { + person.deleteRecord(); + return person.save(); + }); + }) + .then(() => { + assert.equal(callCount, 1, 'didDelete called after delete'); }); - }).then(() => { - assert.equal(callCount, 1, 'didDelete called after delete'); - }); }); }); @@ -207,12 +211,12 @@ test('an uncommited record also receives a didDelete callback when it is deleted callCount++; assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); - } + }, }); let store = createStore({ adapter: DS.Adapter.extend(), - person: Person + person: Person, }); let person = store.createRecord('person', { name: 'Tomster' }); @@ -238,7 +242,7 @@ test('a record receives a becameInvalid callback when it became invalid', functi assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); assert.equal(get(this, 'hasDirtyAttributes'), true, 'record should be dirty'); - } + }, }); const Adapter = DS.Adapter.extend({ @@ -247,23 +251,29 @@ test('a record receives a becameInvalid callback when it became invalid', functi }, updateRecord(store, type, snapshot) { - assert.equal(callCount, 0, 'becameInvalid callback was not called until recordWasInvalid is called'); - - return reject(new DS.InvalidError([ - { - title: 'Invalid Attribute', - detail: 'error', - source: { - pointer: '/data/attributes/bar' - } - } - ])); - } + assert.equal( + callCount, + 0, + 'becameInvalid callback was not called until recordWasInvalid is called' + ); + + return reject( + new DS.InvalidError([ + { + title: 'Invalid Attribute', + detail: 'error', + source: { + pointer: '/data/attributes/bar', + }, + }, + ]) + ); + }, }); let store = createStore({ adapter: Adapter, - person: Person + person: Person, }); let asyncPerson = run(() => store.findRecord('person', 1)); @@ -289,11 +299,11 @@ test('a record receives a becameInvalid callback when it became invalid', functi test('an ID of 0 is allowed', function(assert) { const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let store = createStore({ - person: Person + person: Person, }); run(() => { @@ -302,11 +312,18 @@ test('an ID of 0 is allowed', function(assert) { type: 'person', id: '0', attributes: { - name: 'Tom Dale' - } - } + name: 'Tom Dale', + }, + }, }); }); - assert.equal(store.peekAll('person').objectAt(0).get('name'), 'Tom Dale', 'found record with id 0'); + assert.equal( + store + .peekAll('person') + .objectAt(0) + .get('name'), + 'Tom Dale', + 'found record with id 0' + ); }); diff --git a/tests/unit/model/merge-test.js b/tests/unit/model/merge-test.js index 680db2281bd..f75315f2cc3 100644 --- a/tests/unit/model/merge-test.js +++ b/tests/unit/model/merge-test.js @@ -12,9 +12,9 @@ module('unit/model/merge - Merging', { beforeEach() { Person = DS.Model.extend({ name: DS.attr(), - city: DS.attr() + city: DS.attr(), }); - } + }, }); test('When a record is in flight, changes can be made', function(assert) { @@ -23,12 +23,12 @@ test('When a record is in flight, changes can be made', function(assert) { const Adapter = DS.Adapter.extend({ createRecord(store, type, snapshot) { return { data: { id: 1, type: 'person', attributes: { name: 'Tom Dale' } } }; - } + }, }); let store = createStore({ adapter: Adapter, - person: Person + person: Person, }); let person = store.createRecord('person', { name: 'Tom Dale' }); @@ -56,7 +56,7 @@ test('Make sure snapshot is created at save time not at flush time', function(as assert.equal(snapshot.attr('name'), 'Thomas Dale'); return resolve(); - } + }, }); let store = createStore({ adapter: Adapter, person: Person }); @@ -68,9 +68,9 @@ test('Make sure snapshot is created at save time not at flush time', function(as type: 'person', id: '1', attributes: { - name: "Tom" - } - } + name: 'Tom', + }, + }, }); person.set('name', 'Thomas Dale'); }); @@ -86,26 +86,32 @@ test('Make sure snapshot is created at save time not at flush time', function(as return promise.then(person => { assert.equal(person.get('hasDirtyAttributes'), true, 'The person is still dirty'); - assert.equal(person.get('name'), "Tomasz Dale", 'The local changes apply'); + assert.equal(person.get('name'), 'Tomasz Dale', 'The local changes apply'); }); }); }); -test("When a record is in flight, pushes are applied underneath the in flight changes", function(assert) { +test('When a record is in flight, pushes are applied underneath the in flight changes', function(assert) { assert.expect(6); const Adapter = DS.Adapter.extend({ updateRecord(store, type, snapshot) { // Make sure saving isn't resolved synchronously - return new EmberPromise(resolve => { - run.next(null, resolve, { data: { id: 1, type: 'person', attributes: { name: 'Senor Thomas Dale, Esq.', city: 'Portland' } } }); + return new EmberPromise(resolve => { + run.next(null, resolve, { + data: { + id: 1, + type: 'person', + attributes: { name: 'Senor Thomas Dale, Esq.', city: 'Portland' }, + }, + }); }); - } + }, }); let store = createStore({ adapter: Adapter, - person: Person + person: Person, }); let person; @@ -115,9 +121,9 @@ test("When a record is in flight, pushes are applied underneath the in flight ch type: 'person', id: '1', attributes: { - name: "Tom" - } - } + name: 'Tom', + }, + }, }); person.set('name', 'Thomas Dale'); }); @@ -134,10 +140,10 @@ test("When a record is in flight, pushes are applied underneath the in flight ch type: 'person', id: '1', attributes: { - name: "Tommy Dale", - city: "PDX" - } - } + name: 'Tommy Dale', + city: 'PDX', + }, + }, }); assert.equal(person.get('name'), 'Tomasz Dale', 'the local changes applied on top'); @@ -146,7 +152,11 @@ test("When a record is in flight, pushes are applied underneath the in flight ch return promise.then(person => { assert.equal(person.get('hasDirtyAttributes'), true, 'The person is still dirty'); assert.equal(person.get('name'), 'Tomasz Dale', 'The local changes apply'); - assert.equal(person.get('city'), 'Portland', 'The updates from the server apply on top of the previous pushes'); + assert.equal( + person.get('city'), + 'Portland', + 'The updates from the server apply on top of the previous pushes' + ); }); }); }); @@ -154,7 +164,7 @@ test("When a record is in flight, pushes are applied underneath the in flight ch test('When a record is dirty, pushes are overridden by local changes', function(assert) { let store = createStore({ adapter: DS.Adapter, - person: Person + person: Person, }); let person; @@ -165,9 +175,9 @@ test('When a record is dirty, pushes are overridden by local changes', function( id: '1', attributes: { name: 'Tom Dale', - city: 'San Francisco' - } - } + city: 'San Francisco', + }, + }, }); person.set('name', 'Tomasz Dale'); }); @@ -182,22 +192,26 @@ test('When a record is dirty, pushes are overridden by local changes', function( type: 'person', id: '1', attributes: { - name: "Thomas Dale", - city: "Portland" - } - } + name: 'Thomas Dale', + city: 'Portland', + }, + }, }); }); assert.equal(person.get('hasDirtyAttributes'), true, 'the local changes are reapplied'); assert.equal(person.get('name'), 'Tomasz Dale', 'the local changes are reapplied'); - assert.equal(person.get('city'), 'Portland', 'if there are no local changes, the new data applied'); + assert.equal( + person.get('city'), + 'Portland', + 'if there are no local changes, the new data applied' + ); }); test('When a record is invalid, pushes are overridden by local changes', function(assert) { let store = createStore({ adapter: DS.Adapter, - person: Person + person: Person, }); let person; @@ -208,9 +222,9 @@ test('When a record is invalid, pushes are overridden by local changes', functio id: '1', attributes: { name: 'Brendan McLoughlin', - city: 'Boston' - } - } + city: 'Boston', + }, + }, }); person.set('name', 'Brondan McLoughlin'); person.send('becameInvalid'); @@ -228,9 +242,9 @@ test('When a record is invalid, pushes are overridden by local changes', functio id: '1', attributes: { name: 'bmac', - city: 'Prague' - } - } + city: 'Prague', + }, + }, }); }); @@ -246,12 +260,12 @@ test('A record with no changes can still be saved', function(assert) { const Adapter = DS.Adapter.extend({ updateRecord(store, type, snapshot) { return { data: { id: 1, type: 'person', attributes: { name: 'Thomas Dale' } } }; - } + }, }); let store = createStore({ adapter: Adapter, - person: Person + person: Person, }); let person = run(() => { return store.push({ @@ -259,9 +273,9 @@ test('A record with no changes can still be saved', function(assert) { type: 'person', id: '1', attributeS: { - name: 'Tom Dale' - } - } + name: 'Tom Dale', + }, + }, }); }); @@ -277,13 +291,15 @@ test('A dirty record can be reloaded', function(assert) { const Adapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return { data: { id: 1, type: 'person', attributes: { name: 'Thomas Dale', city: 'Portland' } } }; - } + return { + data: { id: 1, type: 'person', attributes: { name: 'Thomas Dale', city: 'Portland' } }, + }; + }, }); let store = createStore({ adapter: Adapter, - person: Person + person: Person, }); let person; @@ -294,9 +310,9 @@ test('A dirty record can be reloaded', function(assert) { type: 'person', id: '1', attributes: { - name: 'Tom Dale' - } - } + name: 'Tom Dale', + }, + }, }); person.set('name', 'Tomasz Dale'); }); @@ -304,8 +320,8 @@ test('A dirty record can be reloaded', function(assert) { return run(() => { return person.reload().then(() => { assert.equal(person.get('hasDirtyAttributes'), true, 'the person is dirty'); - assert.equal(person.get('name'), "Tomasz Dale", 'the local changes remain'); - assert.equal(person.get('city'), "Portland", 'the new changes apply'); + assert.equal(person.get('name'), 'Tomasz Dale', 'the local changes remain'); + assert.equal(person.get('city'), 'Portland', 'the new changes apply'); }); }); }); diff --git a/tests/unit/model/relationships-test.js b/tests/unit/model/relationships-test.js index d1d1ecf609d..74a5a06546d 100644 --- a/tests/unit/model/relationships-test.js +++ b/tests/unit/model/relationships-test.js @@ -14,16 +14,16 @@ module('unit/model/relationships - DS.Model', { Person = DS.Model.extend({ occupations: DS.hasMany('occupation', { async: false }), people: DS.hasMany('person', { inverse: 'parent', async: false }), - parent: DS.belongsTo('person', { inverse: 'people', async: false }) + parent: DS.belongsTo('person', { inverse: 'people', async: false }), }); store = createStore({ occupation: Occupation, - person: Person + person: Person, }); Person = store.modelFor('person'); - } + }, }); test('exposes a hash of the relationships on a model', function(assert) { @@ -38,23 +38,25 @@ test('exposes a hash of the relationships on a model', function(assert) { return { kind: desc.kind, name: desc.name, - options: desc.options + options: desc.options, }; }); } assert.deepEqual(extractDetails('person'), [ - { name: "people", kind: "hasMany", options: { async: false, inverse: 'parent'} }, - { name: "parent", kind: "belongsTo", options: { async: false, inverse: 'people' } } + { name: 'people', kind: 'hasMany', options: { async: false, inverse: 'parent' } }, + { name: 'parent', kind: 'belongsTo', options: { async: false, inverse: 'people' } }, ]); assert.deepEqual(extractDetails('occupation'), [ - { name: "occupations", kind: "hasMany", options: { async: false } } + { name: 'occupations', kind: 'hasMany', options: { async: false } }, ]); }); test('relationshipNames a hash of the relationships on a model with type as a key', function(assert) { - assert.deepEqual(get(Person, 'relationshipNames'), - { hasMany: ['occupations', 'people'], belongsTo: ["parent"] }); + assert.deepEqual(get(Person, 'relationshipNames'), { + hasMany: ['occupations', 'people'], + belongsTo: ['parent'], + }); }); test('eachRelatedType() iterates over relations without duplication', function(assert) { diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index 9a6601b15f2..062734ebe3c 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -14,12 +14,12 @@ test('belongsTo lazily loads relationships as needed', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.hasMany('person', { async: false }) + people: DS.hasMany('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); let env = setupStore({ tag: Tag, person: Person }); @@ -29,36 +29,41 @@ test('belongsTo lazily loads relationships as needed', function(assert) { run(() => { store.push({ - data: [{ - type: 'tag', - id: '5', - attributes: { - name: 'friendly' - } - }, { - type: 'tag', - id: '2', - attributes: { - name: 'smarmy' - } - }, { - type: 'tag', - id: '12', - attributes: { - name: 'oohlala' - } - }, { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' + data: [ + { + type: 'tag', + id: '5', + attributes: { + name: 'friendly', + }, }, - relationships: { - tag: { - data: { type: 'tag', id: '5' } - } - } - }] + { + type: 'tag', + id: '2', + attributes: { + name: 'smarmy', + }, + }, + { + type: 'tag', + id: '12', + attributes: { + name: 'oohlala', + }, + }, + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + tag: { + data: { type: 'tag', id: '5' }, + }, + }, + }, + ], }); }); @@ -69,8 +74,16 @@ test('belongsTo lazily loads relationships as needed', function(assert) { assert.equal(get(person, 'tag') instanceof Tag, true, 'the tag property should return a tag'); assert.equal(get(person, 'tag.name'), 'friendly', 'the tag shuld have name'); - assert.strictEqual(get(person, 'tag'), get(person, 'tag'), 'the returned object is always the same'); - assert.asyncEqual(get(person, 'tag'), store.findRecord('tag', 5), 'relationship object is the same as object retrieved directly'); + assert.strictEqual( + get(person, 'tag'), + get(person, 'tag'), + 'the returned object is always the same' + ); + assert.asyncEqual( + get(person, 'tag'), + store.findRecord('tag', 5), + 'relationship object is the same as object retrieved directly' + ); }); }); }); @@ -80,13 +93,13 @@ test('belongsTo does not notify when it is initially reified', function(assert) const Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.hasMany('person', { async: false }) + people: DS.hasMany('person', { async: false }), }); Tag.toString = () => 'Tag'; const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); Person.toString = () => 'Person'; @@ -97,27 +110,30 @@ test('belongsTo does not notify when it is initially reified', function(assert) run(() => { store.push({ - data: [{ - type: 'tag', - id: 1, - attributes: { - name: 'whatever' - } - }, { - type: 'person', - id: 2, - attributes: { - name: 'David J. Hamilton' + data: [ + { + type: 'tag', + id: 1, + attributes: { + name: 'whatever', + }, }, - relationships: { - tag: { - data: { - type: 'tag', - id: '1' - } - } - } - }] + { + type: 'person', + id: 2, + attributes: { + name: 'David J. Hamilton', + }, + relationships: { + tag: { + data: { + type: 'tag', + id: '1', + }, + }, + }, + }, + ], }); }); @@ -125,7 +141,7 @@ test('belongsTo does not notify when it is initially reified', function(assert) let person = store.peekRecord('person', 2); person.addObserver('tag', () => { assert.ok(false, 'observer is not called'); - }) + }); assert.equal(person.get('tag.name'), 'whatever', 'relationship is correct'); }); @@ -135,12 +151,12 @@ test('async belongsTo relationships work when the data hash has not been loaded' assert.expect(5); const Tag = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: true }) + tag: DS.belongsTo('tag', { async: true }), }); let env = setupStore({ tag: Tag, person: Person }); @@ -150,7 +166,14 @@ test('async belongsTo relationships work when the data hash has not been loaded' if (type === Person) { assert.equal(id, 1, 'id should be 1'); - return { data: { id: 1, type: 'person', attributes: { name: 'Tom Dale' }, relationships: { tag: { data: { id: 2, type: 'tag' } } } } }; + return { + data: { + id: 1, + type: 'person', + attributes: { name: 'Tom Dale' }, + relationships: { tag: { data: { id: 2, type: 'tag' } } }, + }, + }; } else if (type === Tag) { assert.equal(id, 2, 'id should be 2'); @@ -159,16 +182,19 @@ test('async belongsTo relationships work when the data hash has not been loaded' }; return run(() => { - return store.findRecord('person', 1).then(person => { - assert.equal(get(person, 'name'), 'Tom Dale', 'The person is now populated'); - - return run(() => { - return get(person, 'tag'); + return store + .findRecord('person', 1) + .then(person => { + assert.equal(get(person, 'name'), 'Tom Dale', 'The person is now populated'); + + return run(() => { + return get(person, 'tag'); + }); + }) + .then(tag => { + assert.equal(get(tag, 'name'), 'friendly', 'Tom Dale is now friendly'); + assert.equal(get(tag, 'isLoaded'), true, 'Tom Dale is now loaded'); }); - }).then(tag => { - assert.equal(get(tag, 'name'), 'friendly', 'Tom Dale is now friendly'); - assert.equal(get(tag, 'isLoaded'), true, 'Tom Dale is now loaded'); - }); }); }); @@ -176,12 +202,12 @@ test('async belongsTo relationships work when the data hash has already been loa assert.expect(3); const Tag = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: true }) + tag: DS.belongsTo('tag', { async: true }), }); var env = setupStore({ tag: Tag, person: Person }); @@ -189,24 +215,27 @@ test('async belongsTo relationships work when the data hash has already been loa run(() => { store.push({ - data: [{ - type: 'tag', - id: '2', - attributes: { - name: 'friendly' - } - }, { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' + data: [ + { + type: 'tag', + id: '2', + attributes: { + name: 'friendly', + }, }, - relationships: { - tag: { - data: { type: 'tag', id: '2' } - } - } - }] + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + tag: { + data: { type: 'tag', id: '2' }, + }, + }, + }, + ], }); }); @@ -231,17 +260,18 @@ test('when response to saving a belongsTo is a success but includes changes that run(() => { store.push({ data: [ - { type: 'user', + { + type: 'user', id: '1', relationships: { tag: { - data: { type: 'tag', id: '1' } - } - } + data: { type: 'tag', id: '1' }, + }, + }, }, { type: 'tag', id: '1' }, - { type: 'tag', id: '2' } - ] + { type: 'tag', id: '2' }, + ], }); }); @@ -258,11 +288,11 @@ test('when response to saving a belongsTo is a success but includes changes that tag: { data: { id: '1', - type: 'tag' - } - } - } - } + type: 'tag', + }, + }, + }, + }, }; }; @@ -278,12 +308,12 @@ test('calling createRecord and passing in an undefined value for a relationship const Tag = DS.Model.extend({ name: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); let env = setupStore({ tag: Tag, person: Person }); @@ -294,7 +324,11 @@ test('calling createRecord and passing in an undefined value for a relationship return run(() => { return store.findRecord('person', '1').then(person => { - assert.strictEqual(person.get('tag'), null, 'undefined values should return null relationships'); + assert.strictEqual( + person.get('tag'), + null, + 'undefined values should return null relationships' + ); }); }); }); @@ -302,12 +336,12 @@ test('calling createRecord and passing in an undefined value for a relationship test('When finding a hasMany relationship the inverse belongsTo relationship is available immediately', function(assert) { const Occupation = DS.Model.extend({ description: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - occupations: DS.hasMany('occupation', { async: true }) + occupations: DS.hasMany('occupation', { async: true }), }); let env = setupStore({ occupation: Occupation, person: Person }); @@ -316,10 +350,12 @@ test('When finding a hasMany relationship the inverse belongsTo relationship is env.adapter.findMany = function(store, type, ids, snapshots) { assert.equal(snapshots[0].belongsTo('person').id, '1'); - return { data: [ - { id: 5, type: 'occupation', attributes: { description: "fifth" } }, - { id: 2, type: 'occupation', attributes: { description: "second" } } - ]}; + return { + data: [ + { id: 5, type: 'occupation', attributes: { description: 'fifth' } }, + { id: 2, type: 'occupation', attributes: { description: 'second' } }, + ], + }; }; env.adapter.coalesceFindRequests = true; @@ -330,32 +366,44 @@ test('When finding a hasMany relationship the inverse belongsTo relationship is type: 'person', id: '1', attributes: { - name: 'Tom Dale' + name: 'Tom Dale', }, relationships: { occupations: { - data: [ - { type: 'occupation', id: '5' }, - { type: 'occupation', id: '2' } - ] - } - } - } + data: [{ type: 'occupation', id: '5' }, { type: 'occupation', id: '2' }], + }, + }, + }, }); }); return run(() => { - return store.findRecord('person', 1).then(person => { - assert.equal(get(person, 'isLoaded'), true, 'isLoaded should be true'); - assert.equal(get(person, 'name'), 'Tom Dale', 'the person is still Tom Dale'); - - return get(person, 'occupations'); - }).then(occupations => { - assert.equal(get(occupations, 'length'), 2, 'the list of occupations should have the correct length'); - - assert.equal(get(occupations.objectAt(0), 'description'), 'fifth', 'the occupation is the fifth'); - assert.equal(get(occupations.objectAt(0), 'isLoaded'), true, 'the occupation is now loaded'); - }); + return store + .findRecord('person', 1) + .then(person => { + assert.equal(get(person, 'isLoaded'), true, 'isLoaded should be true'); + assert.equal(get(person, 'name'), 'Tom Dale', 'the person is still Tom Dale'); + + return get(person, 'occupations'); + }) + .then(occupations => { + assert.equal( + get(occupations, 'length'), + 2, + 'the list of occupations should have the correct length' + ); + + assert.equal( + get(occupations.objectAt(0), 'description'), + 'fifth', + 'the occupation is the fifth' + ); + assert.equal( + get(occupations.objectAt(0), 'isLoaded'), + true, + 'the occupation is now loaded' + ); + }); }); }); @@ -364,12 +412,12 @@ test('When finding a belongsTo relationship the inverse belongsTo relationship i const Occupation = DS.Model.extend({ description: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - occupation: DS.belongsTo('occupation', { async: true }) + occupation: DS.belongsTo('occupation', { async: true }), }); let env = setupStore({ occupation: Occupation, person: Person }); @@ -386,14 +434,14 @@ test('When finding a belongsTo relationship the inverse belongsTo relationship i type: 'person', id: '1', attributes: { - name: 'Tom Dale' + name: 'Tom Dale', }, relationships: { occupation: { - data: { type: 'occupation', id: '5' } - } - } - } + data: { type: 'occupation', id: '5' }, + }, + }, + }, }); }); @@ -405,12 +453,12 @@ test('belongsTo supports relationships to models with id 0', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.hasMany('person', { async: false }) + people: DS.hasMany('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); let env = setupStore({ tag: Tag, person: Person }); @@ -420,36 +468,41 @@ test('belongsTo supports relationships to models with id 0', function(assert) { run(() => { store.push({ - data: [{ - type: 'tag', - id: '0', - attributes: { - name: 'friendly' - } - }, { - type: 'tag', - id: '2', - attributes: { - name: 'smarmy' - } - }, { - type: 'tag', - id: '12', - attributes: { - name: 'oohlala' - } - }, { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' + data: [ + { + type: 'tag', + id: '0', + attributes: { + name: 'friendly', + }, }, - relationships: { - tag: { - data: { type: 'tag', id: '0' } - } - } - }] + { + type: 'tag', + id: '2', + attributes: { + name: 'smarmy', + }, + }, + { + type: 'tag', + id: '12', + attributes: { + name: 'oohlala', + }, + }, + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + tag: { + data: { type: 'tag', id: '0' }, + }, + }, + }, + ], }); }); @@ -458,22 +511,30 @@ test('belongsTo supports relationships to models with id 0', function(assert) { assert.equal(get(person, 'name'), 'Tom Dale', 'precond - retrieves person record from store'); assert.equal(get(person, 'tag') instanceof Tag, true, 'the tag property should return a tag'); - assert.equal(get(person, 'tag.name'), "friendly", 'the tag should have name'); - - assert.strictEqual(get(person, 'tag'), get(person, 'tag'), 'the returned object is always the same'); - assert.asyncEqual(get(person, 'tag'), store.findRecord('tag', 0), 'relationship object is the same as object retrieved directly'); + assert.equal(get(person, 'tag.name'), 'friendly', 'the tag should have name'); + + assert.strictEqual( + get(person, 'tag'), + get(person, 'tag'), + 'the returned object is always the same' + ); + assert.asyncEqual( + get(person, 'tag'), + store.findRecord('tag', 0), + 'relationship object is the same as object retrieved directly' + ); }); }); }); testInDebug('belongsTo gives a warning when provided with a serialize option', function(assert) { const Hobby = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const Person = DS.Model.extend({ name: DS.attr('string'), - hobby: DS.belongsTo('hobby', { serialize: true, async: true }) + hobby: DS.belongsTo('hobby', { serialize: true, async: true }), }); let env = setupStore({ hobby: Hobby, person: Person }); @@ -483,35 +544,39 @@ testInDebug('belongsTo gives a warning when provided with a serialize option', f run(() => { store.push({ - data: [{ - type: 'hobby', - id: '1', - attributes: { - name: 'fishing' - } - }, { - type: 'hobby', - id: '2', - attributes: { - name: 'coding' - } - }, { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' + data: [ + { + type: 'hobby', + id: '1', + attributes: { + name: 'fishing', + }, }, - relationships: { - hobby: { - data: { type: 'hobby', id: '1' } - } - } - }] + { + type: 'hobby', + id: '2', + attributes: { + name: 'coding', + }, + }, + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + hobby: { + data: { type: 'hobby', id: '1' }, + }, + }, + }, + ], }); }); return run(() => { - return store.findRecord('person', 1).then(person =>{ + return store.findRecord('person', 1).then(person => { assert.expectWarning(() => { get(person, 'hobby'); }, /You provided a serialize option on the "hobby" property in the "person" class, this belongs in the serializer. See DS.Serializer and it's implementations/); @@ -519,14 +584,14 @@ testInDebug('belongsTo gives a warning when provided with a serialize option', f }); }); -testInDebug("belongsTo gives a warning when provided with an embedded option", function(assert) { +testInDebug('belongsTo gives a warning when provided with an embedded option', function(assert) { const Hobby = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const Person = DS.Model.extend({ name: DS.attr('string'), - hobby: DS.belongsTo('hobby', { embedded: true, async: true }) + hobby: DS.belongsTo('hobby', { embedded: true, async: true }), }); let env = setupStore({ hobby: Hobby, person: Person }); @@ -536,30 +601,34 @@ testInDebug("belongsTo gives a warning when provided with an embedded option", f run(() => { store.push({ - data: [{ - type: 'hobby', - id: '1', - attributes: { - name: 'fishing' - } - }, { - type: 'hobby', - id: '2', - attributes: { - name: 'coding' - } - }, { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' + data: [ + { + type: 'hobby', + id: '1', + attributes: { + name: 'fishing', + }, }, - relationships: { - hobby: { - data: { type: 'hobby', id: '1' } - } - } - }] + { + type: 'hobby', + id: '2', + attributes: { + name: 'coding', + }, + }, + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + hobby: { + data: { type: 'hobby', id: '1' }, + }, + }, + }, + ], }); }); @@ -575,16 +644,16 @@ testInDebug("belongsTo gives a warning when provided with an embedded option", f test('DS.belongsTo should be async by default', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.hasMany('person', { async: false }) + people: DS.hasMany('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag') + tag: DS.belongsTo('tag'), }); let env = setupStore({ tag: Tag, person: Person }); - let { store } = env; + let { store } = env; let person = store.createRecord('person'); assert.ok(person.get('tag') instanceof DS.PromiseObject, 'tag should be an async relationship'); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 8feb6fb13aa..7f050c6fbbc 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -13,7 +13,7 @@ let env; module('unit/model/relationships - DS.hasMany', { beforeEach() { env = setupStore(); - } + }, }); test('hasMany handles pre-loaded relationships', function(assert) { @@ -21,18 +21,18 @@ test('hasMany handles pre-loaded relationships', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); const Pet = DS.Model.extend({ name: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), tags: DS.hasMany('tag', { async: false }), - pets: DS.hasMany('pet', { async: false }) + pets: DS.hasMany('pet', { async: false }), }); env.registry.register('model:tag', Tag); @@ -52,165 +52,197 @@ test('hasMany handles pre-loaded relationships', function(assert) { run(() => { store.push({ - data: [{ - type: 'tag', - id: '5', - attributes: { - name: 'friendly' - } - }, { - type: 'tag', - id: '2', - attributes: { - name: 'smarmy' - } - }, { - type: 'pet', - id: '4', - attributes: { - name: 'fluffy' - } - }, { - type: 'pet', - id: '7', - attributes: { - name: 'snowy' - } - }, { - type: 'pet', - id: '12', - attributes: { - name: 'cerberus' - } - }, { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' + data: [ + { + type: 'tag', + id: '5', + attributes: { + name: 'friendly', + }, }, - relationships: { - tags: { - data: [ - { type: 'tag', id: '5' } - ] - } - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Yehuda Katz' + { + type: 'tag', + id: '2', + attributes: { + name: 'smarmy', + }, }, - relationships: { - tags: { - data: [ - { type: 'tag', id: '12' } - ] - } - } - }] + { + type: 'pet', + id: '4', + attributes: { + name: 'fluffy', + }, + }, + { + type: 'pet', + id: '7', + attributes: { + name: 'snowy', + }, + }, + { + type: 'pet', + id: '12', + attributes: { + name: 'cerberus', + }, + }, + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + tags: { + data: [{ type: 'tag', id: '5' }], + }, + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Yehuda Katz', + }, + relationships: { + tags: { + data: [{ type: 'tag', id: '12' }], + }, + }, + }, + ], }); }); return run(() => { - return store.findRecord('person', 1).then(person => { - assert.equal(get(person, 'name'), 'Tom Dale', 'precond - retrieves person record from store'); - - let tags = get(person, 'tags'); - assert.equal(get(tags, 'length'), 1, 'the list of tags should have the correct length'); - assert.equal(get(tags.objectAt(0), 'name'), 'friendly', 'the first tag should be a Tag'); - - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' + return store + .findRecord('person', 1) + .then(person => { + assert.equal( + get(person, 'name'), + 'Tom Dale', + 'precond - retrieves person record from store' + ); + + let tags = get(person, 'tags'); + assert.equal(get(tags, 'length'), 1, 'the list of tags should have the correct length'); + assert.equal(get(tags.objectAt(0), 'name'), 'friendly', 'the first tag should be a Tag'); + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + tags: { + data: [{ type: 'tag', id: '5' }, { type: 'tag', id: '2' }], + }, + }, }, - relationships: { - tags: { - data: [ - { type: 'tag', id: '5' }, - { type: 'tag', id: '2' } - ] - } - } - } + }); }); - }); - assert.equal(tags, get(person, 'tags'), 'a relationship returns the same object every time'); - assert.equal(get(get(person, 'tags'), 'length'), 2, 'the length is updated after new data is loaded'); - - assert.strictEqual(get(person, 'tags').objectAt(0), get(person, 'tags').objectAt(0), 'the returned object is always the same'); - assert.equal(get(person, 'tags').objectAt(0), store.peekRecord('tag', 5), 'relationship objects are the same as objects retrieved directly'); - - run(() => { - store.push({ - data: { - type: 'person', - id: '3', - attributes: { - name: 'KSelden' - } - } + assert.equal( + tags, + get(person, 'tags'), + 'a relationship returns the same object every time' + ); + assert.equal( + get(get(person, 'tags'), 'length'), + 2, + 'the length is updated after new data is loaded' + ); + + assert.strictEqual( + get(person, 'tags').objectAt(0), + get(person, 'tags').objectAt(0), + 'the returned object is always the same' + ); + assert.equal( + get(person, 'tags').objectAt(0), + store.peekRecord('tag', 5), + 'relationship objects are the same as objects retrieved directly' + ); + + run(() => { + store.push({ + data: { + type: 'person', + id: '3', + attributes: { + name: 'KSelden', + }, + }, + }); }); - }); - return store.findRecord('person', 3); - }).then(kselden => { - assert.equal(get(get(kselden, 'tags'), 'length'), 0, 'a relationship that has not been supplied returns an empty array'); - - run(() => { - store.push({ - data: { - type: 'person', - id: '4', - attributes: { - name: 'Cyvid Hamluck' + return store.findRecord('person', 3); + }) + .then(kselden => { + assert.equal( + get(get(kselden, 'tags'), 'length'), + 0, + 'a relationship that has not been supplied returns an empty array' + ); + + run(() => { + store.push({ + data: { + type: 'person', + id: '4', + attributes: { + name: 'Cyvid Hamluck', + }, + relationships: { + pets: { + data: [{ type: 'pet', id: '4' }], + }, + }, }, - relationships: { - pets: { - data: [ - { type: 'pet', id: '4' } - ] - } - } - } + }); }); - }); - return store.findRecord('person', 4); - }).then(cyvid => { - assert.equal(get(cyvid, 'name'), 'Cyvid Hamluck', 'precond - retrieves person record from store'); - - let pets = get(cyvid, 'pets'); - assert.equal(get(pets, 'length'), 1, 'the list of pets should have the correct length'); - assert.equal(get(pets.objectAt(0), 'name'), 'fluffy', 'the first pet should be correct'); - - run(() => { - store.push({ - data: { - type: 'person', - id: '4', - attributes: { - name: 'Cyvid Hamluck' + return store.findRecord('person', 4); + }) + .then(cyvid => { + assert.equal( + get(cyvid, 'name'), + 'Cyvid Hamluck', + 'precond - retrieves person record from store' + ); + + let pets = get(cyvid, 'pets'); + assert.equal(get(pets, 'length'), 1, 'the list of pets should have the correct length'); + assert.equal(get(pets.objectAt(0), 'name'), 'fluffy', 'the first pet should be correct'); + + run(() => { + store.push({ + data: { + type: 'person', + id: '4', + attributes: { + name: 'Cyvid Hamluck', + }, + relationships: { + pets: { + data: [{ type: 'pet', id: '4' }, { type: 'pet', id: '12' }], + }, + }, }, - relationships: { - pets: { - data: [ - { type: 'pet', id: '4' }, - { type: 'pet', id: '12' } - ] - } - } - } + }); }); - }); - assert.equal(pets, get(cyvid, 'pets'), 'a relationship returns the same object every time'); - assert.equal(get(get(cyvid, 'pets'), 'length'), 2, 'the length is updated after new data is loaded'); - }); + assert.equal(pets, get(cyvid, 'pets'), 'a relationship returns the same object every time'); + assert.equal( + get(get(cyvid, 'pets'), 'length'), + 2, + 'the length is updated after new data is loaded' + ); + }); }); }); @@ -219,13 +251,13 @@ test('hasMany does not notify when it is initially reified', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.hasMany('person', { async: false }) + people: DS.hasMany('person', { async: false }), }); Tag.toString = () => 'Tag'; const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); Person.toString = () => 'Person'; @@ -236,27 +268,32 @@ test('hasMany does not notify when it is initially reified', function(assert) { run(() => { store.push({ - data: [{ - type: 'tag', - id: 1, - attributes: { - name: 'whatever' + data: [ + { + type: 'tag', + id: 1, + attributes: { + name: 'whatever', + }, + relationships: { + people: { + data: [ + { + id: 2, + type: 'person', + }, + ], + }, + }, }, - relationships: { - people: { - data: [{ - id: 2, - type: 'person' - }] - } - } - }, { - type: 'person', - id: 2, - attributes: { - name: 'David J. Hamilton' - } - }] + { + type: 'person', + id: 2, + attributes: { + name: 'David J. Hamilton', + }, + }, + ], }); }); @@ -269,11 +306,7 @@ test('hasMany does not notify when it is initially reified', function(assert) { assert.ok(false, 'observer is not called'); }); - assert.equal( - tag.get('people').mapBy('name'), - 'David J. Hamilton', - 'relationship is correct' - ); + assert.equal(tag.get('people').mapBy('name'), 'David J. Hamilton', 'relationship is correct'); }); }); @@ -282,12 +315,12 @@ test('hasMany can be initially reified with null', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.hasMany('person', { async: false }) + people: DS.hasMany('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); let env = setupStore({ tag: Tag, person: Person }); @@ -301,14 +334,14 @@ test('hasMany can be initially reified with null', function(assert) { type: 'tag', id: 1, attributes: { - name: 'whatever' + name: 'whatever', }, relationships: { people: { - data: null - } - } - } + data: null, + }, + }, + }, }); }); @@ -324,12 +357,12 @@ test('hasMany with explicit initial null works even when the inverse was set to const Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.hasMany('person', { async: false }) + people: DS.hasMany('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); let env = setupStore({ tag: Tag, person: Person }); @@ -344,34 +377,36 @@ test('hasMany with explicit initial null works even when the inverse was set to type: 'person', id: 1, attributes: { - name: 'David J. Hamilton' + name: 'David J. Hamilton', }, relationships: { tag: { data: { type: 'tag', - id: 1 - } - } - } + id: 1, + }, + }, + }, }, included: [ { type: 'tag', id: 1, attributes: { - name: 'whatever' + name: 'whatever', }, relationships: { people: { - data: [{ - type: 'person', - id: 1 - }] - } - } - } - ] + data: [ + { + type: 'person', + id: 1, + }, + ], + }, + }, + }, + ], }); // now we push in data for that record which says it has no relationships @@ -380,14 +415,14 @@ test('hasMany with explicit initial null works even when the inverse was set to type: 'tag', id: 1, attributes: { - name: 'whatever' + name: 'whatever', }, relationships: { people: { - data: null - } - } - } + data: null, + }, + }, + }, }); }); @@ -405,24 +440,24 @@ test('hasMany with duplicates from payload', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.hasMany('person', { async: false }) + people: DS.hasMany('person', { async: false }), }); Tag.reopenClass({ toString() { return 'tag'; - } + }, }); const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); Person.reopenClass({ toString() { return 'person'; - } + }, }); let env = setupStore({ tag: Tag, person: Person }); @@ -435,40 +470,40 @@ test('hasMany with duplicates from payload', function(assert) { type: 'person', id: 1, attributes: { - name: 'David J. Hamilton' + name: 'David J. Hamilton', }, relationships: { tag: { data: { type: 'tag', - id: 1 - } - } - } + id: 1, + }, + }, + }, }, included: [ { type: 'tag', id: 1, attributes: { - name: 'whatever' + name: 'whatever', }, relationships: { people: { data: [ { type: 'person', - id: 1 + id: 1, }, { type: 'person', - id: 1 - } - ] - } - } - } - ] + id: 1, + }, + ], + }, + }, + }, + ], }); }); @@ -483,24 +518,24 @@ test('many2many loads both sides #5140', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.hasMany('person', { async: false }) + people: DS.hasMany('person', { async: false }), }); Tag.reopenClass({ toString() { return 'tag'; - } + }, }); const Person = DS.Model.extend({ name: DS.attr('string'), - tags: DS.hasMany('tags', { async: false }) + tags: DS.hasMany('tags', { async: false }), }); Person.reopenClass({ toString() { return 'person'; - } + }, }); let env = setupStore({ tag: Tag, person: Person }); @@ -514,87 +549,91 @@ test('many2many loads both sides #5140', function(assert) { type: 'person', id: 1, attributes: { - name: 'David J. Hamilton' + name: 'David J. Hamilton', }, relationships: { - tags: [{ - data: { - type: 'tag', - id: 1 - } - }, - { - data: { - type: 'tag', - id: 2 - } - }] - } + tags: [ + { + data: { + type: 'tag', + id: 1, + }, + }, + { + data: { + type: 'tag', + id: 2, + }, + }, + ], + }, }, { type: 'person', id: 2, attributes: { - name: 'Gerald Dempsey Posey' + name: 'Gerald Dempsey Posey', }, relationships: { - tags: [{ - data: { - type: 'tag', - id: 1 - } - }, - { - data: { - type: 'tag', - id: 2 - } - }] - } + tags: [ + { + data: { + type: 'tag', + id: 1, + }, + }, + { + data: { + type: 'tag', + id: 2, + }, + }, + ], + }, }, { type: 'tag', id: 1, attributes: { - name: 'whatever' + name: 'whatever', }, relationships: { people: { data: [ { type: 'person', - id: 1 + id: 1, }, { type: 'person', - id: 2 - } - ] - } - } + id: 2, + }, + ], + }, + }, }, { type: 'tag', id: 2, attributes: { - name: 'nothing' + name: 'nothing', }, relationships: { people: { data: [ { type: 'person', - id: 1 + id: 1, }, { type: 'person', - id: 2 - } - ] - } - } - } - ] + id: 2, + }, + ], + }, + }, + }, + ], }); }); @@ -613,12 +652,12 @@ test('hasMany with explicit null works even when the inverse was set to not null const Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.hasMany('person', { async: false }) + people: DS.hasMany('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); let env = setupStore({ tag: Tag, person: Person }); @@ -633,34 +672,36 @@ test('hasMany with explicit null works even when the inverse was set to not null type: 'person', id: 1, attributes: { - name: 'David J. Hamilton' + name: 'David J. Hamilton', }, relationships: { tag: { data: { type: 'tag', - id: 1 - } - } - } + id: 1, + }, + }, + }, }, included: [ { type: 'tag', id: 1, attributes: { - name: 'whatever' + name: 'whatever', }, relationships: { people: { - data: [{ - type: 'person', - id: 1 - }] - } - } - } - ] + data: [ + { + type: 'person', + id: 1, + }, + ], + }, + }, + }, + ], }); }); @@ -678,14 +719,14 @@ test('hasMany with explicit null works even when the inverse was set to not null type: 'tag', id: 1, attributes: { - name: 'whatever' + name: 'whatever', }, relationships: { people: { - data: null - } - } - } + data: null, + }, + }, + }, }); }); @@ -693,7 +734,7 @@ test('hasMany with explicit null works even when the inverse was set to not null let person = store.peekRecord('person', 1); let tag = store.peekRecord('tag', 1); - assert.equal(person.get('tag'), null,'relationship is now empty'); + assert.equal(person.get('tag'), null, 'relationship is now empty'); assert.equal(tag.get('people.length'), 0, 'relationship is correct'); }); }); @@ -703,7 +744,7 @@ test('hasMany tolerates reflexive self-relationships', function(assert) { const Person = DS.Model.extend({ name: DS.attr(), - trueFriends: DS.hasMany('person', { async: false }) + trueFriends: DS.hasMany('person', { async: false }), }); let env = setupStore({ person: Person }); @@ -715,17 +756,19 @@ test('hasMany tolerates reflexive self-relationships', function(assert) { id: '1', type: 'person', attributes: { - name: 'Edward II' + name: 'Edward II', }, relationships: { trueFriends: { - data: [{ - id: '1', - type: 'person' - }] - } - } - } + data: [ + { + id: '1', + type: 'person', + }, + ], + }, + }, + }, }); }); @@ -742,18 +785,18 @@ test('hasMany lazily loads async relationships', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); const Pet = DS.Model.extend({ name: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), tags: DS.hasMany('tag', { async: true }), - pets: DS.hasMany('pet', { async: false }) + pets: DS.hasMany('pet', { async: false }), }); env.registry.register('model:tag', Tag); @@ -773,89 +816,117 @@ test('hasMany lazily loads async relationships', function(assert) { run(() => { store.push({ - data: [{ - type: 'tag', - id: '5', - attributes: { - name: 'friendly' - } - }, { - type: 'tag', - id: '2', - attributes: { - name: 'smarmy' - } - }, { - type: 'pet', - id: '4', - attributes: { - name: 'fluffy' - } - }, { - type: 'pet', - id: '7', - attributes: { - name: 'snowy' - } - }, { - type: 'pet', - id: '12', - attributes: { - name: 'cerberus' - } - }, { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' + data: [ + { + type: 'tag', + id: '5', + attributes: { + name: 'friendly', + }, }, - relationships: { - tags: { - data: [ - { type: 'tag', id: '5' } - ] - } - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Yehuda Katz' + { + type: 'tag', + id: '2', + attributes: { + name: 'smarmy', + }, }, - relationships: { - tags: { - data: [ - { type: 'tag', id: '12' } - ] - } - } - }] + { + type: 'pet', + id: '4', + attributes: { + name: 'fluffy', + }, + }, + { + type: 'pet', + id: '7', + attributes: { + name: 'snowy', + }, + }, + { + type: 'pet', + id: '12', + attributes: { + name: 'cerberus', + }, + }, + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + tags: { + data: [{ type: 'tag', id: '5' }], + }, + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Yehuda Katz', + }, + relationships: { + tags: { + data: [{ type: 'tag', id: '12' }], + }, + }, + }, + ], }); }); - return run(() =>{ + return run(() => { let wycats; - store.findRecord('person', 2).then(function(person) { - wycats = person; - - assert.equal(get(wycats, 'name'), 'Yehuda Katz', 'precond - retrieves person record from store'); - - return hash({ - wycats, - tags: wycats.get('tags') + store + .findRecord('person', 2) + .then(function(person) { + wycats = person; + + assert.equal( + get(wycats, 'name'), + 'Yehuda Katz', + 'precond - retrieves person record from store' + ); + + return hash({ + wycats, + tags: wycats.get('tags'), + }); + }) + .then(records => { + assert.equal( + get(records.tags, 'length'), + 1, + 'the list of tags should have the correct length' + ); + assert.equal( + get(records.tags.objectAt(0), 'name'), + 'oohlala', + 'the first tag should be a Tag' + ); + + assert.strictEqual( + records.tags.objectAt(0), + records.tags.objectAt(0), + 'the returned object is always the same' + ); + assert.equal( + records.tags.objectAt(0), + store.peekRecord('tag', 12), + 'relationship objects are the same as objects retrieved directly' + ); + + return get(wycats, 'tags'); + }) + .then(tags => { + let newTag = store.createRecord('tag'); + tags.pushObject(newTag); }); - }).then(records => { - assert.equal(get(records.tags, 'length'), 1, 'the list of tags should have the correct length'); - assert.equal(get(records.tags.objectAt(0), 'name'), 'oohlala', 'the first tag should be a Tag'); - - assert.strictEqual(records.tags.objectAt(0), records.tags.objectAt(0), 'the returned object is always the same'); - assert.equal(records.tags.objectAt(0), store.peekRecord('tag', 12), 'relationship objects are the same as objects retrieved directly'); - - return get(wycats, 'tags'); - }).then(tags => { - let newTag = store.createRecord('tag'); - tags.pushObject(newTag); - }); }); }); @@ -863,63 +934,78 @@ test('should be able to retrieve the type for a hasMany relationship without spe const Tag = DS.Model.extend({}); const Person = DS.Model.extend({ - tags: DS.hasMany('tag', { async: false }) - + tags: DS.hasMany('tag', { async: false }), }); let env = setupStore({ tag: Tag, - person: Person + person: Person, }); - assert.equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, 'returns the relationship type'); + assert.equal( + env.store.modelFor('person').typeForRelationship('tags', env.store), + Tag, + 'returns the relationship type' + ); }); test('should be able to retrieve the type for a hasMany relationship specified using a string from its metadata', function(assert) { const Tag = DS.Model.extend({}); const Person = DS.Model.extend({ - tags: DS.hasMany('tag', { async: false }) + tags: DS.hasMany('tag', { async: false }), }); let env = setupStore({ tag: Tag, - person: Person + person: Person, }); - assert.equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, 'returns the relationship type'); + assert.equal( + env.store.modelFor('person').typeForRelationship('tags', env.store), + Tag, + 'returns the relationship type' + ); }); test('should be able to retrieve the type for a belongsTo relationship without specifying a type from its metadata', function(assert) { const Tag = DS.Model.extend({}); const Person = DS.Model.extend({ - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); let env = setupStore({ tag: Tag, - person: Person + person: Person, }); - assert.equal(env.store.modelFor('person').typeForRelationship('tag', env.store), Tag, 'returns the relationship type'); + assert.equal( + env.store.modelFor('person').typeForRelationship('tag', env.store), + Tag, + 'returns the relationship type' + ); }); test('should be able to retrieve the type for a belongsTo relationship specified using a string from its metadata', function(assert) { const Tag = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const Person = DS.Model.extend({ - tags: DS.belongsTo('tag', { async: false }) + tags: DS.belongsTo('tag', { async: false }), }); let env = setupStore({ tag: Tag, - person: Person + person: Person, }); - assert.equal(env.store.modelFor('person').typeForRelationship('tags', env.store), Tag, 'returns the relationship type'); + assert.equal( + env.store.modelFor('person').typeForRelationship('tags', env.store), + Tag, + 'returns the relationship type' + ); }); test('relationships work when declared with a string path', function(assert) { @@ -927,61 +1013,67 @@ test('relationships work when declared with a string path', function(assert) { const Person = DS.Model.extend({ name: DS.attr('string'), - tags: DS.hasMany('tag', { async: false }) + tags: DS.hasMany('tag', { async: false }), }); const Tag = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let env = setupStore({ person: Person, - tag: Tag + tag: Tag, }); env.adapter.shouldBackgroundReloadRecord = () => false; run(() => { env.store.push({ - data: [{ - type: 'tag', - id: '5', - attributes: { - name: 'friendly' - } - }, { - type: 'tag', - id: '2', - attributes: { - name: 'smarmy' - } - }, { - type: 'tag', - id: '12', - attributes: { - name: 'oohlala' - } - }, { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' + data: [ + { + type: 'tag', + id: '5', + attributes: { + name: 'friendly', + }, }, - relationships: { - tags: { - data: [ - { type: 'tag', id: '5' }, - { type: 'tag', id: '2' } - ] - } - } - }] + { + type: 'tag', + id: '2', + attributes: { + name: 'smarmy', + }, + }, + { + type: 'tag', + id: '12', + attributes: { + name: 'oohlala', + }, + }, + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + tags: { + data: [{ type: 'tag', id: '5' }, { type: 'tag', id: '2' }], + }, + }, + }, + ], }); }); return run(() => { return env.store.findRecord('person', 1).then(person => { assert.equal(get(person, 'name'), 'Tom Dale', 'precond - retrieves person record from store'); - assert.equal(get(person, 'tags.length'), 2, 'the list of tags should have the correct length'); + assert.equal( + get(person, 'tags.length'), + 2, + 'the list of tags should have the correct length' + ); }); }); }); @@ -991,12 +1083,12 @@ test('hasMany relationships work when the data hash has not been loaded', functi const Tag = DS.Model.extend({ name: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tags: DS.hasMany('tag', { async: true }) + tags: DS.hasMany('tag', { async: true }), }); let env = setupStore({ tag: Tag, person: Person }); @@ -1007,10 +1099,12 @@ test('hasMany relationships work when the data hash has not been loaded', functi assert.equal(type, Tag, 'type should be Tag'); assert.deepEqual(ids, ['5', '2'], 'ids should be 5 and 2'); - return { data: [ - { id: 5, type: 'tag', attributes: { name: 'friendly' } }, - { id: 2, type: 'tag', attributes: { name: 'smarmy' } } - ]}; + return { + data: [ + { id: 5, type: 'tag', attributes: { name: 'friendly' } }, + { id: 2, type: 'tag', attributes: { name: 'smarmy' } }, + ], + }; }; env.adapter.findRecord = function(store, type, id, snapshot) { @@ -1024,23 +1118,26 @@ test('hasMany relationships work when the data hash has not been loaded', functi attributes: { name: 'Tom Dale' }, relationships: { tags: { - data: [{ id: 5, type: 'tag'}, { id: 2, type: 'tag'}] - } - } - } + data: [{ id: 5, type: 'tag' }, { id: 2, type: 'tag' }], + }, + }, + }, }; }; return run(() => { - return store.findRecord('person', 1).then(person => { - assert.equal(get(person, 'name'), 'Tom Dale', 'The person is now populated'); - - return run(() => person.get('tags')); - }).then(tags => { - assert.equal(get(tags, 'length'), 2, 'the tags object still exists'); - assert.equal(get(tags.objectAt(0), 'name'), 'friendly', 'Tom Dale is now friendly'); - assert.equal(get(tags.objectAt(0), 'isLoaded'), true, 'Tom Dale is now loaded'); - }); + return store + .findRecord('person', 1) + .then(person => { + assert.equal(get(person, 'name'), 'Tom Dale', 'The person is now populated'); + + return run(() => person.get('tags')); + }) + .then(tags => { + assert.equal(get(tags, 'length'), 2, 'the tags object still exists'); + assert.equal(get(tags.objectAt(0), 'name'), 'friendly', 'Tom Dale is now friendly'); + assert.equal(get(tags.objectAt(0), 'isLoaded'), true, 'Tom Dale is now loaded'); + }); }); }); @@ -1049,17 +1146,17 @@ test('it is possible to add a new item to a relationship', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.belongsTo('person', { async: false }) + people: DS.belongsTo('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tags: DS.hasMany('tag', { async: false }) + tags: DS.hasMany('tag', { async: false }), }); let env = setupStore({ tag: Tag, - person: Person + person: Person, }); env.adapter.shouldBackgroundReloadRecord = () => false; @@ -1067,31 +1164,32 @@ test('it is possible to add a new item to a relationship', function(assert) { run(() => { store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + tags: { + data: [{ type: 'tag', id: '1' }], + }, + }, }, - relationships: { - tags: { - data: [ - { type: 'tag', id: '1' } - ] - } - } - }, { - type: 'tag', - id: '1', - attributes: { - name: 'ember' - } - }] + { + type: 'tag', + id: '1', + attributes: { + name: 'ember', + }, + }, + ], }); }); return run(() => { - return store.findRecord('person', 1).then(person =>{ + return store.findRecord('person', 1).then(person => { let tag = get(person, 'tags').objectAt(0); assert.equal(get(tag, 'name'), 'ember', 'precond - relationships work'); @@ -1109,17 +1207,17 @@ test('new items added to a hasMany relationship are not cleared by a delete', fu const Person = DS.Model.extend({ name: DS.attr('string'), - pets: DS.hasMany('pet', { async: false, inverse: null }) + pets: DS.hasMany('pet', { async: false, inverse: null }), }); const Pet = DS.Model.extend({ name: DS.attr('string'), - person: DS.belongsTo('person', { async: false, inverse: null }) + person: DS.belongsTo('person', { async: false, inverse: null }), }); let env = setupStore({ person: Person, - pet: Pet + pet: Pet, }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.deleteRecord = () => { @@ -1134,39 +1232,37 @@ test('new items added to a hasMany relationship are not cleared by a delete', fu type: 'person', id: '1', attributes: { - name: 'Chris Thoburn' + name: 'Chris Thoburn', }, relationships: { pets: { - data: [ - { type: 'pet', id: '1' } - ] - } - } + data: [{ type: 'pet', id: '1' }], + }, + }, }, included: [ { type: 'pet', id: '1', attributes: { - name: 'Shenanigans' - } + name: 'Shenanigans', + }, }, { type: 'pet', id: '2', attributes: { - name: 'Rambunctious' - } + name: 'Rambunctious', + }, }, { type: 'pet', id: '3', attributes: { - name: 'Rebel' - } - } - ] + name: 'Rebel', + }, + }, + ], }); }); @@ -1178,22 +1274,33 @@ test('new items added to a hasMany relationship are not cleared by a delete', fu const rebel = store.peekRecord('pet', '3'); assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); - assert.deepEqual(pets.map(p => get(p, 'id')), ['1'], 'precond - relationship has the correct pets to start'); + assert.deepEqual( + pets.map(p => get(p, 'id')), + ['1'], + 'precond - relationship has the correct pets to start' + ); run(() => { pets.pushObjects([rambo, rebel]); }); - assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2', '3'], 'precond2 - relationship now has the correct three pets'); + assert.deepEqual( + pets.map(p => get(p, 'id')), + ['1', '2', '3'], + 'precond2 - relationship now has the correct three pets' + ); run(() => { - return shen.destroyRecord({}) - .then(() => { - shen.unloadRecord(); - }); + return shen.destroyRecord({}).then(() => { + shen.unloadRecord(); + }); }); - assert.deepEqual(pets.map(p => get(p, 'id')), ['2', '3'], 'relationship now has the correct two pets'); + assert.deepEqual( + pets.map(p => get(p, 'id')), + ['2', '3'], + 'relationship now has the correct two pets' + ); }); test('new items added to an async hasMany relationship are not cleared by a delete', function(assert) { @@ -1201,17 +1308,17 @@ test('new items added to an async hasMany relationship are not cleared by a dele const Person = DS.Model.extend({ name: DS.attr('string'), - pets: DS.hasMany('pet', { async: true, inverse: null }) + pets: DS.hasMany('pet', { async: true, inverse: null }), }); const Pet = DS.Model.extend({ name: DS.attr('string'), - person: DS.belongsTo('person', { async: false, inverse: null }) + person: DS.belongsTo('person', { async: false, inverse: null }), }); let env = setupStore({ person: Person, - pet: Pet + pet: Pet, }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.deleteRecord = () => { @@ -1226,39 +1333,37 @@ test('new items added to an async hasMany relationship are not cleared by a dele type: 'person', id: '1', attributes: { - name: 'Chris Thoburn' + name: 'Chris Thoburn', }, relationships: { pets: { - data: [ - { type: 'pet', id: '1' } - ] - } - } + data: [{ type: 'pet', id: '1' }], + }, + }, }, included: [ { type: 'pet', id: '1', attributes: { - name: 'Shenanigans' - } + name: 'Shenanigans', + }, }, { type: 'pet', id: '2', attributes: { - name: 'Rambunctious' - } + name: 'Rambunctious', + }, }, { type: 'pet', id: '3', attributes: { - name: 'Rebel' - } - } - ] + name: 'Rebel', + }, + }, + ], }); }); @@ -1266,27 +1371,38 @@ test('new items added to an async hasMany relationship are not cleared by a dele const person = store.peekRecord('person', '1'); const petsProxy = run(() => person.get('pets')); - return petsProxy.then((pets) => { + return petsProxy.then(pets => { const shen = pets.objectAt(0); const rambo = store.peekRecord('pet', '2'); const rebel = store.peekRecord('pet', '3'); assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); - assert.deepEqual(pets.map(p => get(p, 'id')), ['1'], 'precond - relationship has the correct pet to start'); + assert.deepEqual( + pets.map(p => get(p, 'id')), + ['1'], + 'precond - relationship has the correct pet to start' + ); assert.equal(get(petsProxy, 'length'), 1, 'precond - proxy has only one pet to start'); pets.pushObjects([rambo, rebel]); - assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2', '3'], 'precond2 - relationship now has the correct three pets'); + assert.deepEqual( + pets.map(p => get(p, 'id')), + ['1', '2', '3'], + 'precond2 - relationship now has the correct three pets' + ); assert.equal(get(petsProxy, 'length'), 3, 'precond2 - proxy now reflects three pets'); - return shen.destroyRecord({}) - .then(() => { - shen.unloadRecord(); + return shen.destroyRecord({}).then(() => { + shen.unloadRecord(); - assert.deepEqual(pets.map(p => get(p, 'id')), ['2', '3'], 'relationship now has the correct two pets'); - assert.equal(get(petsProxy, 'length'), 2, 'proxy now reflects two pets'); - }); + assert.deepEqual( + pets.map(p => get(p, 'id')), + ['2', '3'], + 'relationship now has the correct two pets' + ); + assert.equal(get(petsProxy, 'length'), 2, 'proxy now reflects two pets'); + }); }); }); }); @@ -1296,16 +1412,16 @@ test('new items added to a belongsTo relationship are not cleared by a delete', const Person = DS.Model.extend({ name: DS.attr('string'), - dog: DS.belongsTo('dog', { async: false, inverse: null }) + dog: DS.belongsTo('dog', { async: false, inverse: null }), }); const Dog = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let env = setupStore({ person: Person, - dog: Dog + dog: Dog, }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.deleteRecord = () => { @@ -1320,30 +1436,30 @@ test('new items added to a belongsTo relationship are not cleared by a delete', type: 'person', id: '1', attributes: { - name: 'Chris Thoburn' + name: 'Chris Thoburn', }, relationships: { dog: { - data: { type: 'dog', id: '1' } - } - } + data: { type: 'dog', id: '1' }, + }, + }, }, included: [ { type: 'dog', id: '1', attributes: { - name: 'Shenanigans' - } + name: 'Shenanigans', + }, }, { type: 'dog', id: '2', attributes: { - name: 'Rambunctious' - } - } - ] + name: 'Rambunctious', + }, + }, + ], }); }); @@ -1363,13 +1479,12 @@ test('new items added to a belongsTo relationship are not cleared by a delete', assert.equal(dog, rambo, 'precond2 - relationship was updated'); return run(() => { - return shen.destroyRecord({}) - .then(() => { - shen.unloadRecord(); + return shen.destroyRecord({}).then(() => { + shen.unloadRecord(); - dog = person.get('dog'); - assert.equal(dog, rambo, 'The currentState of the belongsTo was preserved after the delete'); - }); + dog = person.get('dog'); + assert.equal(dog, rambo, 'The currentState of the belongsTo was preserved after the delete'); + }); }); }); @@ -1378,16 +1493,16 @@ test('new items added to an async belongsTo relationship are not cleared by a de const Person = DS.Model.extend({ name: DS.attr('string'), - dog: DS.belongsTo('dog', { async: true, inverse: null }) + dog: DS.belongsTo('dog', { async: true, inverse: null }), }); const Dog = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let env = setupStore({ person: Person, - dog: Dog + dog: Dog, }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.deleteRecord = () => { @@ -1402,30 +1517,30 @@ test('new items added to an async belongsTo relationship are not cleared by a de type: 'person', id: '1', attributes: { - name: 'Chris Thoburn' + name: 'Chris Thoburn', }, relationships: { dog: { - data: { type: 'dog', id: '1' } - } - } + data: { type: 'dog', id: '1' }, + }, + }, }, included: [ { type: 'dog', id: '1', attributes: { - name: 'Shenanigans' - } + name: 'Shenanigans', + }, }, { type: 'dog', id: '2', attributes: { - name: 'Rambunctious' - } - } - ] + name: 'Rambunctious', + }, + }, + ], }); }); @@ -1434,7 +1549,7 @@ test('new items added to an async belongsTo relationship are not cleared by a de const shen = store.peekRecord('dog', '1'); const rambo = store.peekRecord('dog', '2'); - return person.get('dog').then((dog) => { + return person.get('dog').then(dog => { assert.ok(dog === shen, 'precond - the belongsTo points to the correct dog'); assert.equal(get(dog, 'name'), 'Shenanigans', 'precond - relationships work'); @@ -1444,13 +1559,15 @@ test('new items added to an async belongsTo relationship are not cleared by a de assert.ok(dog === rambo, 'precond2 - relationship was updated'); - return shen.destroyRecord({}) - .then(() => { - shen.unloadRecord(); + return shen.destroyRecord({}).then(() => { + shen.unloadRecord(); - dog = person.get('dog.content'); - assert.ok(dog === rambo, 'The currentState of the belongsTo was preserved after the delete'); - }); + dog = person.get('dog.content'); + assert.ok( + dog === rambo, + 'The currentState of the belongsTo was preserved after the delete' + ); + }); }); }); }); @@ -1460,16 +1577,16 @@ test('deleting an item that is the current state of a belongsTo clears currentSt const Person = DS.Model.extend({ name: DS.attr('string'), - dog: DS.belongsTo('dog', { async: false, inverse: null }) + dog: DS.belongsTo('dog', { async: false, inverse: null }), }); const Dog = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let env = setupStore({ person: Person, - dog: Dog + dog: Dog, }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.deleteRecord = () => { @@ -1484,30 +1601,30 @@ test('deleting an item that is the current state of a belongsTo clears currentSt type: 'person', id: '1', attributes: { - name: 'Chris Thoburn' + name: 'Chris Thoburn', }, relationships: { dog: { - data: { type: 'dog', id: '1' } - } - } + data: { type: 'dog', id: '1' }, + }, + }, }, included: [ { type: 'dog', id: '1', attributes: { - name: 'Shenanigans' - } + name: 'Shenanigans', + }, }, { type: 'dog', id: '2', attributes: { - name: 'Rambunctious' - } - } - ] + name: 'Rambunctious', + }, + }, + ], }); }); @@ -1527,41 +1644,40 @@ test('deleting an item that is the current state of a belongsTo clears currentSt assert.equal(dog, rambo, 'precond2 - relationship was updated'); return run(() => { - return rambo.destroyRecord({}) - .then(() => { - rambo.unloadRecord(); + return rambo.destroyRecord({}).then(() => { + rambo.unloadRecord(); - dog = person.get('dog'); - assert.equal(dog, null, 'The current state of the belongsTo was clearer'); - }); + dog = person.get('dog'); + assert.equal(dog, null, 'The current state of the belongsTo was clearer'); + }); }); }); test('hasMany.firstObject.unloadRecord should not break that hasMany', function(assert) { const Person = DS.Model.extend({ cars: DS.hasMany('car', { async: false }), - name: DS.attr() + name: DS.attr(), }); Person.reopenClass({ toString() { return 'person'; - } + }, }); const Car = DS.Model.extend({ - name: DS.attr() + name: DS.attr(), }); Car.reopenClass({ toString() { return 'car'; - } + }, }); let env = setupStore({ person: Person, - car: Car + car: Car, }); run(() => { @@ -1571,21 +1687,18 @@ test('hasMany.firstObject.unloadRecord should not break that hasMany', function( type: 'person', id: 1, attributes: { - name: 'marvin' + name: 'marvin', }, relationships: { cars: { - data: [ - { type: 'car', id: 1 }, - { type: 'car', id: 2 } - ] - } - } + data: [{ type: 'car', id: 1 }, { type: 'car', id: 2 }], + }, + }, }, { type: 'car', id: 1, attributes: { name: 'a' } }, - { type: 'car', id: 2, attributes: { name: 'b' } } - ] - }) + { type: 'car', id: 2, attributes: { name: 'b' } }, + ], + }); }); let person = env.store.peekRecord('person', 1); @@ -1616,17 +1729,17 @@ test('[ASSERTS KNOWN LIMITATION STILL EXISTS] returning new hasMany relationship const Person = DS.Model.extend({ name: DS.attr('string'), - pets: DS.hasMany('pet', { async: false, inverse: null }) + pets: DS.hasMany('pet', { async: false, inverse: null }), }); const Pet = DS.Model.extend({ name: DS.attr('string'), - person: DS.belongsTo('person', { async: false, inverse: null }) + person: DS.belongsTo('person', { async: false, inverse: null }), }); let env = setupStore({ person: Person, - pet: Pet + pet: Pet, }); env.adapter.shouldBackgroundReloadRecord = () => false; env.adapter.deleteRecord = () => { @@ -1637,17 +1750,15 @@ test('[ASSERTS KNOWN LIMITATION STILL EXISTS] returning new hasMany relationship type: 'person', id: '1', attributes: { - name: 'Chris Thoburn' + name: 'Chris Thoburn', }, relationships: { pets: { - data: [ - { type: 'pet', id: '2' } - ] - } - } - } - ] + data: [{ type: 'pet', id: '2' }], + }, + }, + }, + ], }); }; @@ -1659,40 +1770,37 @@ test('[ASSERTS KNOWN LIMITATION STILL EXISTS] returning new hasMany relationship type: 'person', id: '1', attributes: { - name: 'Chris Thoburn' + name: 'Chris Thoburn', }, relationships: { pets: { - data: [ - { type: 'pet', id: '1' }, - { type: 'pet', id: '2' } - ] - } - } + data: [{ type: 'pet', id: '1' }, { type: 'pet', id: '2' }], + }, + }, }, included: [ { type: 'pet', id: '1', attributes: { - name: 'Shenanigans' - } + name: 'Shenanigans', + }, }, { type: 'pet', id: '2', attributes: { - name: 'Rambunctious' - } + name: 'Rambunctious', + }, }, { type: 'pet', id: '3', attributes: { - name: 'Rebel' - } - } - ] + name: 'Rebel', + }, + }, + ], }); }); @@ -1703,22 +1811,33 @@ test('[ASSERTS KNOWN LIMITATION STILL EXISTS] returning new hasMany relationship const rebel = store.peekRecord('pet', '3'); assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); - assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2'], 'precond - relationship has the correct pets to start'); + assert.deepEqual( + pets.map(p => get(p, 'id')), + ['1', '2'], + 'precond - relationship has the correct pets to start' + ); run(() => { pets.pushObjects([rebel]); }); - assert.deepEqual(pets.map(p => get(p, 'id')), ['1', '2', '3'], 'precond2 - relationship now has the correct three pets'); + assert.deepEqual( + pets.map(p => get(p, 'id')), + ['1', '2', '3'], + 'precond2 - relationship now has the correct three pets' + ); return run(() => { - return shen.destroyRecord({}) - .then(() => { - shen.unloadRecord(); - - // were ember-data to now preserve local edits during a relationship push, this would be '2' - assert.deepEqual(pets.map(p => get(p, 'id')), ['2'], 'relationship now has only one pet, we lost the local change'); - }); + return shen.destroyRecord({}).then(() => { + shen.unloadRecord(); + + // were ember-data to now preserve local edits during a relationship push, this would be '2' + assert.deepEqual( + pets.map(p => get(p, 'id')), + ['2'], + 'relationship now has only one pet, we lost the local change' + ); + }); }); }); @@ -1727,12 +1846,12 @@ test('possible to replace items in a relationship using setObjects w/ Ember Enum const Tag = DS.Model.extend({ name: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tags: DS.hasMany('tag', { async: false }) + tags: DS.hasMany('tag', { async: false }), }); let env = setupStore({ tag: Tag, person: Person }); @@ -1740,45 +1859,46 @@ test('possible to replace items in a relationship using setObjects w/ Ember Enum run(() => { store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + tags: { + data: [{ type: 'tag', id: '1' }], + }, + }, }, - relationships: { - tags: { - data: [ - { type: 'tag', id: '1' } - ] - } - } - }, { - type: 'person', - id: '2', - attributes: { - name: 'Sylvain Mina' + { + type: 'person', + id: '2', + attributes: { + name: 'Sylvain Mina', + }, + relationships: { + tags: { + data: [{ type: 'tag', id: '2' }], + }, + }, }, - relationships: { - tags: { - data: [ - { type: 'tag', id: '2' } - ] - } - } - }, { - type: 'tag', - id: '1', - attributes: { - name: 'ember' - } - }, { - type: 'tag', - id: '2', - attributes: { - name: 'ember-data' - } - }] + { + type: 'tag', + id: '1', + attributes: { + name: 'ember', + }, + }, + { + type: 'tag', + id: '2', + attributes: { + name: 'ember-data', + }, + }, + ], }); }); @@ -1801,12 +1921,12 @@ test('it is possible to remove an item from a relationship', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tags: DS.hasMany('tag', { async: false }) + tags: DS.hasMany('tag', { async: false }), }); let env = setupStore({ tag: Tag, person: Person }); @@ -1816,26 +1936,27 @@ test('it is possible to remove an item from a relationship', function(assert) { run(() => { store.push({ - data: [{ - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale' + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + tags: { + data: [{ type: 'tag', id: '1' }], + }, + }, }, - relationships: { - tags: { - data: [ - { type: 'tag', id: '1' } - ] - } - } - }, { - type: 'tag', - id: '1', - attributes: { - name: 'ember' - } - }] + { + type: 'tag', + id: '1', + attributes: { + name: 'ember', + }, + }, + ], }); }); @@ -1855,12 +1976,12 @@ test('it is possible to remove an item from a relationship', function(assert) { test('it is possible to add an item to a relationship, remove it, then add it again', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tags: DS.hasMany('tag', { async: false }) + tags: DS.hasMany('tag', { async: false }), }); let env = setupStore({ tag: Tag, person: Person }); @@ -1890,15 +2011,15 @@ test('it is possible to add an item to a relationship, remove it, then add it ag assert.equal(tags.objectAt(2), tag3); }); -test("DS.hasMany is async by default", function(assert) { +test('DS.hasMany is async by default', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.hasMany('person') + people: DS.hasMany('person'), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); let { store } = setupStore({ tag: Tag, person: Person }); @@ -1910,12 +2031,12 @@ test("DS.hasMany is async by default", function(assert) { test('DS.hasMany is stable', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.hasMany('person') + people: DS.hasMany('person'), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); let { store } = setupStore({ tag: Tag, person: Person }); @@ -1931,20 +2052,18 @@ test('DS.hasMany is stable', function(assert) { assert.equal(people, notifiedPeople); - return EmberPromise.all([ - people - ]); + return EmberPromise.all([people]); }); test('DS.hasMany proxy is destroyed', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - people: DS.hasMany('person') + people: DS.hasMany('person'), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); let { store } = setupStore({ tag: Tag, person: Person }); @@ -1964,12 +2083,28 @@ test('DS.hasMany proxy is destroyed', function(assert) { // prior to RecordData, this was coupled to the destroy // of the relationship, which was async and possibly could // be cancelled were an unload to be aborted. - assert.equal(peopleProxy.isDestroying, isRecordDataBuild, 'peopleProxy is not destroying sync after unloadRecord'); - assert.equal(peopleProxy.isDestroyed, false, 'peopleProxy is NOT YET destroyed sync after unloadRecord'); + assert.equal( + peopleProxy.isDestroying, + isRecordDataBuild, + 'peopleProxy is not destroying sync after unloadRecord' + ); + assert.equal( + peopleProxy.isDestroyed, + false, + 'peopleProxy is NOT YET destroyed sync after unloadRecord' + ); }); - assert.equal(peopleProxy.isDestroying, true, 'peopleProxy is destroying after the run post unloadRecord'); - assert.equal(peopleProxy.isDestroyed, true, 'peopleProxy is destroyed after the run post unloadRecord'); + assert.equal( + peopleProxy.isDestroying, + true, + 'peopleProxy is destroying after the run post unloadRecord' + ); + assert.equal( + peopleProxy.isDestroyed, + true, + 'peopleProxy is destroyed after the run post unloadRecord' + ); }); }); @@ -1980,12 +2115,12 @@ test('DS.ManyArray is lazy', function(assert) { people: DS.hasMany('person'), peopleDidChange: observer('people', function() { peopleDidChange++; - }) + }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }) + tag: DS.belongsTo('tag', { async: false }), }); let env = setupStore({ tag: Tag, person: Person }); @@ -1996,18 +2131,34 @@ test('DS.ManyArray is lazy', function(assert) { //assert.ok(!hasManyRelationship._manyArray); run(() => { - assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (before access)'); + assert.equal( + peopleDidChange, + 0, + 'expect people hasMany to not emit a change event (before access)' + ); tag.get('people'); - assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (sync after access)'); + assert.equal( + peopleDidChange, + 0, + 'expect people hasMany to not emit a change event (sync after access)' + ); }); - assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (after access, but after the current run loop)'); + assert.equal( + peopleDidChange, + 0, + 'expect people hasMany to not emit a change event (after access, but after the current run loop)' + ); //assert.ok(hasManyRelationship._manyArray instanceof DS.ManyArray); let person = env.store.createRecord('person'); run(() => { - assert.equal(peopleDidChange, 0, 'expect people hasMany to not emit a change event (before access)'); + assert.equal( + peopleDidChange, + 0, + 'expect people hasMany to not emit a change event (before access)' + ); tag.get('people').addObject(person); assert.equal(peopleDidChange, 1, 'expect people hasMany to have changed exactly once'); }); @@ -2018,12 +2169,12 @@ test('fetch hasMany loads full relationship after a parent and child have been l const Tag = DS.Model.extend({ name: DS.attr('string'), - person: DS.belongsTo('person', { async: true, inverse: 'tags' }) + person: DS.belongsTo('person', { async: true, inverse: 'tags' }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tags: DS.hasMany('tag', { async: true, inverse: 'person' }) + tags: DS.hasMany('tag', { async: true, inverse: 'person' }), }); let env = setupStore({ tag: Tag, person: Person }); @@ -2032,11 +2183,13 @@ test('fetch hasMany loads full relationship after a parent and child have been l env.adapter.findHasMany = function(store, snapshot, url, relationship) { assert.equal(relationship.key, 'tags', 'relationship should be tags'); - return { data: [ - { id: 1, type: 'tag', attributes: { name: 'first' } }, - { id: 2, type: 'tag', attributes: { name: 'second' } }, - { id: 3, type: 'tag', attributes: { name: 'third' } } - ]}; + return { + data: [ + { id: 1, type: 'tag', attributes: { name: 'first' } }, + { id: 2, type: 'tag', attributes: { name: 'second' } }, + { id: 3, type: 'tag', attributes: { name: 'third' } }, + ], + }; }; env.adapter.findRecord = function(store, type, id, snapshot) { @@ -2047,9 +2200,9 @@ test('fetch hasMany loads full relationship after a parent and child have been l type: 'person', attributes: { name: 'Watson' }, relationships: { - tags: { links: { related: 'person/1/tags'} } - } - } + tags: { links: { related: 'person/1/tags' } }, + }, + }, }; } else if (type === Tag) { return { @@ -2059,13 +2212,13 @@ test('fetch hasMany loads full relationship after a parent and child have been l attributes: { name: 'second' }, relationships: { person: { - data: { id: 1, type: 'person'} - } - } - } + data: { id: 1, type: 'person' }, + }, + }, + }, }; } else { - assert.true(false, 'wrong type') + assert.true(false, 'wrong type'); } }; @@ -2077,9 +2230,11 @@ test('fetch hasMany loads full relationship after a parent and child have been l return store.findRecord('tag', 2).then(tag => { assert.equal(get(tag, 'name'), 'second', 'The tag is now loaded'); - return run(() => person.get('tags').then(tags => { - assert.equal(get(tags, 'length'), 3, 'the tags are all loaded'); - })); + return run(() => + person.get('tags').then(tags => { + assert.equal(get(tags, 'length'), 3, 'the tags are all loaded'); + }) + ); }); }); }); @@ -2088,10 +2243,10 @@ test('fetch hasMany loads full relationship after a parent and child have been l testInDebug('throws assertion if of not set with an array', function(assert) { const Person = DS.Model.extend(); const Tag = DS.Model.extend({ - people: DS.hasMany('person') + people: DS.hasMany('person'), }); - let { store }= setupStore({ tag: Tag, person: Person }); + let { store } = setupStore({ tag: Tag, person: Person }); let tag = store.createRecord('tag'); let person = store.createRecord('person'); @@ -2105,7 +2260,7 @@ testInDebug('throws assertion if of not set with an array', function(assert) { testInDebug('checks if passed array only contains instances of DS.Model', function(assert) { const Person = DS.Model.extend(); const Tag = DS.Model.extend({ - people: DS.hasMany('person') + people: DS.hasMany('person'), }); let env = setupStore({ tag: Tag, person: Person }); @@ -2114,8 +2269,8 @@ testInDebug('checks if passed array only contains instances of DS.Model', functi return { data: { type: 'person', - id: 1 - } + id: 1, + }, }; }; diff --git a/tests/unit/model/relationships/record-array-test.js b/tests/unit/model/relationships/record-array-test.js index 7cdf36da71c..e9711270821 100644 --- a/tests/unit/model/relationships/record-array-test.js +++ b/tests/unit/model/relationships/record-array-test.js @@ -11,7 +11,7 @@ module('unit/model/relationships - RecordArray'); test('updating the content of a RecordArray updates its content', function(assert) { let Tag = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let env = setupStore({ tag: Tag }); @@ -21,30 +21,34 @@ test('updating the content of a RecordArray updates its content', function(asser run(() => { internalModels = store._push({ - data: [{ - type: 'tag', - id: '5', - attributes: { - name: 'friendly' - } - }, { - type: 'tag', - id: '2', - attributes: { - name: 'smarmy' - } - }, { - type: 'tag', - id: '12', - attributes: { - name: 'oohlala' - } - }] + data: [ + { + type: 'tag', + id: '5', + attributes: { + name: 'friendly', + }, + }, + { + type: 'tag', + id: '2', + attributes: { + name: 'smarmy', + }, + }, + { + type: 'tag', + id: '12', + attributes: { + name: 'oohlala', + }, + }, + ], }); tags = DS.RecordArray.create({ content: A(internalModels.slice(0, 2)), store: store, - modelName: 'tag' + modelName: 'tag', }); }); @@ -62,12 +66,12 @@ test('can create child record from a hasMany relationship', function(assert) { const Tag = DS.Model.extend({ name: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); const Person = DS.Model.extend({ name: DS.attr('string'), - tags: DS.hasMany('tag', { async: false }) + tags: DS.hasMany('tag', { async: false }), }); let env = setupStore({ tag: Tag, person: Person }); @@ -81,9 +85,9 @@ test('can create child record from a hasMany relationship', function(assert) { type: 'person', id: '1', attributes: { - name: 'Tom Dale' - } - } + name: 'Tom Dale', + }, + }, }); }); @@ -93,7 +97,13 @@ test('can create child record from a hasMany relationship', function(assert) { assert.equal(get(person, 'name'), 'Tom Dale', 'precond - retrieves person record from store'); assert.equal(get(person, 'tags.length'), 1, 'tag is added to the parent record'); - assert.equal(get(person, 'tags').objectAt(0).get('name'), 'cool', 'tag values are passed along'); + assert.equal( + get(person, 'tags') + .objectAt(0) + .get('name'), + 'cool', + 'tag values are passed along' + ); }); }); }); diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index 5d25c7e7f51..9cd25a23988 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -18,13 +18,17 @@ module('unit/model/rollbackAttributes - model.rollbackAttributes()', { rolledBackCount: 0, rolledBack() { this.incrementProperty('rolledBackCount'); - } + }, + }); + Person.reopenClass({ + toString() { + return 'Person'; + }, }); - Person.reopenClass({ toString() { return 'Person'; } }); env = setupStore({ person: Person }); store = env.store; - } + }, }); test('changes to attributes can be rolled back', function(assert) { @@ -34,22 +38,22 @@ test('changes to attributes can be rolled back', function(assert) { type: 'person', id: '1', attributes: { - firstName: "Tom", - lastName: "Dale" - } - } + firstName: 'Tom', + lastName: 'Dale', + }, + }, }); person = store.peekRecord('person', 1); - person.set('firstName', "Thomas"); + person.set('firstName', 'Thomas'); return person; }); - assert.equal(person.get('firstName'), "Thomas"); + assert.equal(person.get('firstName'), 'Thomas'); assert.equal(person.get('rolledBackCount'), 0); run(() => person.rollbackAttributes()); - assert.equal(person.get('firstName'), "Tom"); + assert.equal(person.get('firstName'), 'Tom'); assert.equal(person.get('hasDirtyAttributes'), false); assert.equal(person.get('rolledBackCount'), 1); }); @@ -61,17 +65,17 @@ test('changes to unassigned attributes can be rolled back', function(assert) { type: 'person', id: '1', attributes: { - lastName: 'Dale' - } - } + lastName: 'Dale', + }, + }, }); person = store.peekRecord('person', 1); - person.set('firstName', "Thomas"); + person.set('firstName', 'Thomas'); return person; }); - assert.equal(person.get('firstName'), "Thomas"); + assert.equal(person.get('firstName'), 'Thomas'); assert.equal(person.get('rolledBackCount'), 0); run(() => person.rollbackAttributes()); @@ -93,14 +97,14 @@ test('changes to attributes made after a record is in-flight only rolls back the type: 'person', id: '1', attributes: { - firstName: "Tom", - lastName: "Dale" - } - } + firstName: 'Tom', + lastName: 'Dale', + }, + }, }); let person = store.peekRecord('person', 1); - person.set('firstName', "Thomas"); + person.set('firstName', 'Thomas'); return person; }); @@ -108,17 +112,17 @@ test('changes to attributes made after a record is in-flight only rolls back the return run(() => { let saving = person.save(); - assert.equal(person.get('firstName'), "Thomas"); + assert.equal(person.get('firstName'), 'Thomas'); - person.set('lastName', "Dolly"); + person.set('lastName', 'Dolly'); - assert.equal(person.get('lastName'), "Dolly"); + assert.equal(person.get('lastName'), 'Dolly'); assert.equal(person.get('rolledBackCount'), 0); person.rollbackAttributes(); - assert.equal(person.get('firstName'), "Thomas"); - assert.equal(person.get('lastName'), "Dale"); + assert.equal(person.get('firstName'), 'Thomas'); + assert.equal(person.get('lastName'), 'Dale'); assert.equal(person.get('isSaving'), true); return saving.then(() => { @@ -139,31 +143,31 @@ test("a record's changes can be made if it fails to save", function(assert) { type: 'person', id: '1', attributes: { - firstName: "Tom", - lastName: "Dale" - } - } + firstName: 'Tom', + lastName: 'Dale', + }, + }, }); let person = store.peekRecord('person', 1); - person.set('firstName', "Thomas"); + person.set('firstName', 'Thomas'); return person; }); - assert.deepEqual(person.changedAttributes().firstName, ["Tom", "Thomas"]); + assert.deepEqual(person.changedAttributes().firstName, ['Tom', 'Thomas']); run(function() { person.save().then(null, function() { assert.equal(person.get('isError'), true); - assert.deepEqual(person.changedAttributes().firstName, ["Tom", "Thomas"]); + assert.deepEqual(person.changedAttributes().firstName, ['Tom', 'Thomas']); assert.equal(person.get('rolledBackCount'), 0); run(function() { person.rollbackAttributes(); }); - assert.equal(person.get('firstName'), "Tom"); + assert.equal(person.get('firstName'), 'Tom'); assert.equal(person.get('isError'), false); assert.equal(Object.keys(person.changedAttributes()).length, 0); assert.equal(person.get('rolledBackCount'), 1); @@ -185,10 +189,10 @@ test(`a deleted record's attributes can be rollbacked if it fails to save, recor type: 'person', id: '1', attributes: { - firstName: "Tom", - lastName: "Dale" - } - } + firstName: 'Tom', + lastName: 'Dale', + }, + }, }); person = store.peekRecord('person', 1); people = store.peekAll('person'); @@ -196,24 +200,39 @@ test(`a deleted record's attributes can be rollbacked if it fails to save, recor run(() => person.deleteRecord()); - assert.equal(people.get('length'), 1, 'a deleted record appears in record array until it is saved'); - assert.equal(people.objectAt(0), person, 'a deleted record appears in record array until it is saved'); + assert.equal( + people.get('length'), + 1, + 'a deleted record appears in record array until it is saved' + ); + assert.equal( + people.objectAt(0), + person, + 'a deleted record appears in record array until it is saved' + ); return run(() => { - return person.save().catch(() => { - assert.equal(person.get('isError'), true); - assert.equal(person.get('isDeleted'), true); - assert.equal(person.get('rolledBackCount'), 0); - - run(() => person.rollbackAttributes()); - - assert.equal(person.get('isDeleted'), false); - assert.equal(person.get('isError'), false); - assert.equal(person.get('hasDirtyAttributes'), false, 'must be not dirty'); - assert.equal(person.get('rolledBackCount'), 1); - }).then(() => { - assert.equal(people.get('length'), 1, 'the underlying record array is updated accordingly in an asynchronous way'); - }); + return person + .save() + .catch(() => { + assert.equal(person.get('isError'), true); + assert.equal(person.get('isDeleted'), true); + assert.equal(person.get('rolledBackCount'), 0); + + run(() => person.rollbackAttributes()); + + assert.equal(person.get('isDeleted'), false); + assert.equal(person.get('isError'), false); + assert.equal(person.get('hasDirtyAttributes'), false, 'must be not dirty'); + assert.equal(person.get('rolledBackCount'), 1); + }) + .then(() => { + assert.equal( + people.get('length'), + 1, + 'the underlying record array is updated accordingly in an asynchronous way' + ); + }); }); }); @@ -236,14 +255,14 @@ test(`invalid new record's attributes can be rollbacked`, function(assert) { let error = new DS.InvalidError([ { detail: 'is invalid', - source: { pointer: 'data/attributes/name' } - } + source: { pointer: 'data/attributes/name' }, + }, ]); let adapter = DS.RESTAdapter.extend({ ajax(url, type, hash) { return reject(error); - } + }, }); env = setupStore({ person: Person, adapter: adapter }); @@ -269,12 +288,11 @@ test(`invalid new record's attributes can be rollbacked`, function(assert) { }); test(`invalid record's attributes can be rollbacked after multiple failed calls - #3677`, function(assert) { - let adapter = DS.RESTAdapter.extend({ ajax(url, type, hash) { let error = new DS.InvalidError(); return reject(error); - } + }, }); env = setupStore({ person: Person, adapter: adapter }); @@ -286,9 +304,9 @@ test(`invalid record's attributes can be rollbacked after multiple failed calls type: 'person', id: 1, attributes: { - firstName: 'original name' - } - } + firstName: 'original name', + }, + }, }); person.set('firstName', 'updated name'); @@ -297,18 +315,25 @@ test(`invalid record's attributes can be rollbacked after multiple failed calls return run(() => { assert.equal(person.get('firstName'), 'updated name', 'precondition: firstName is changed'); - return person.save().catch(() => { - assert.equal(person.get('hasDirtyAttributes'), true, 'has dirty attributes'); - assert.equal(person.get('firstName'), 'updated name', 'firstName is still changed'); - - return person.save(); - }).catch(() => { - run(() => person.rollbackAttributes()); - - assert.equal(person.get('hasDirtyAttributes'), false, 'has no dirty attributes'); - assert.equal(person.get('firstName'), 'original name', 'after rollbackAttributes() firstName has the original value'); - assert.equal(person.get('rolledBackCount'), 1); - }); + return person + .save() + .catch(() => { + assert.equal(person.get('hasDirtyAttributes'), true, 'has dirty attributes'); + assert.equal(person.get('firstName'), 'updated name', 'firstName is still changed'); + + return person.save(); + }) + .catch(() => { + run(() => person.rollbackAttributes()); + + assert.equal(person.get('hasDirtyAttributes'), false, 'has no dirty attributes'); + assert.equal( + person.get('firstName'), + 'original name', + 'after rollbackAttributes() firstName has the original value' + ); + assert.equal(person.get('rolledBackCount'), 1); + }); }); }); @@ -319,22 +344,34 @@ test(`deleted record's attributes can be rollbacked`, function(assert) { store.push({ data: { type: 'person', - id: '1' - } + id: '1', + }, }); person = store.peekRecord('person', 1); people = store.peekAll('person'); person.deleteRecord(); }); - assert.equal(people.get('length'), 1, 'a deleted record appears in the record array until it is saved'); - assert.equal(people.objectAt(0), person, 'a deleted record appears in the record array until it is saved'); + assert.equal( + people.get('length'), + 1, + 'a deleted record appears in the record array until it is saved' + ); + assert.equal( + people.objectAt(0), + person, + 'a deleted record appears in the record array until it is saved' + ); assert.equal(person.get('isDeleted'), true, 'must be deleted'); run(() => person.rollbackAttributes()); - assert.equal(people.get('length'), 1, 'the rollbacked record should appear again in the record array'); + assert.equal( + people.get('length'), + 1, + 'the rollbacked record should appear again in the record array' + ); assert.equal(person.get('isDeleted'), false, 'must not be deleted'); assert.equal(person.get('hasDirtyAttributes'), false, 'must not be dirty'); }); @@ -346,20 +383,20 @@ test("invalid record's attributes can be rollbacked", function(assert) { rolledBackCount: 0, rolledBack() { this.incrementProperty('rolledBackCount'); - } + }, }); let error = new DS.InvalidError([ { detail: 'is invalid', - source: { pointer: 'data/attributes/name' } - } + source: { pointer: 'data/attributes/name' }, + }, ]); let adapter = DS.RESTAdapter.extend({ ajax(url, type, hash) { return reject(error); - } + }, }); env = setupStore({ dog: Dog, adapter: adapter }); @@ -370,12 +407,12 @@ test("invalid record's attributes can be rollbacked", function(assert) { type: 'dog', id: '1', attributes: { - name: "Pluto" - } - } + name: 'Pluto', + }, + }, }); dog = env.store.peekRecord('dog', 1); - dog.set('name', "is a dwarf planet"); + dog.set('name', 'is a dwarf planet'); }); return run(() => { @@ -383,19 +420,24 @@ test("invalid record's attributes can be rollbacked", function(assert) { assert.ok(true, 'errors.name did change'); }); - dog.get('errors').addArrayObserver({}, { - willChange() { - assert.ok(true, 'errors will change'); - }, - didChange() { - assert.ok(true, 'errors did change'); + dog.get('errors').addArrayObserver( + {}, + { + willChange() { + assert.ok(true, 'errors will change'); + }, + didChange() { + assert.ok(true, 'errors did change'); + }, } - }); + ); return dog.save().catch(reason => { assert.equal(reason, error); - run(() => { dog.rollbackAttributes() }); + run(() => { + dog.rollbackAttributes(); + }); assert.equal(dog.get('hasDirtyAttributes'), false, 'must not be dirty'); assert.equal(dog.get('name'), 'Pluto'); @@ -410,20 +452,20 @@ test(`invalid record's attributes rolled back to correct state after set`, funct assert.expect(14); const Dog = DS.Model.extend({ name: DS.attr(), - breed: DS.attr() + breed: DS.attr(), }); let error = new DS.InvalidError([ { detail: 'is invalid', - source: { pointer: 'data/attributes/name' } - } + source: { pointer: 'data/attributes/name' }, + }, ]); let adapter = DS.RESTAdapter.extend({ ajax(url, type, hash) { return reject(error); - } + }, }); env = setupStore({ dog: Dog, adapter: adapter }); @@ -434,13 +476,13 @@ test(`invalid record's attributes rolled back to correct state after set`, funct type: 'dog', id: '1', attributes: { - name: "Pluto", - breed: "Disney" - } - } + name: 'Pluto', + breed: 'Disney', + }, + }, }); dog = env.store.peekRecord('dog', 1); - dog.set('name', "is a dwarf planet"); + dog.set('name', 'is a dwarf planet'); dog.set('breed', 'planet'); }); @@ -474,20 +516,20 @@ test(`invalid record's attributes rolled back to correct state after set`, funct test(`when destroying a record setup the record state to invalid, the record's attributes can be rollbacked`, function(assert) { const Dog = DS.Model.extend({ - name: DS.attr() + name: DS.attr(), }); let error = new DS.InvalidError([ { detail: 'is invalid', - source: { pointer: 'data/attributes/name' } - } + source: { pointer: 'data/attributes/name' }, + }, ]); let adapter = DS.RESTAdapter.extend({ ajax(url, type, hash) { return reject(error); - } + }, }); env = setupStore({ dog: Dog, adapter: adapter }); @@ -497,15 +539,15 @@ test(`when destroying a record setup the record state to invalid, the record's a type: 'dog', id: '1', attributes: { - name: "Pluto" - } - } + name: 'Pluto', + }, + }, }); return env.store.peekRecord('dog', 1); }); return run(() => { - return dog.destroyRecord().catch(reason => { + return dog.destroyRecord().catch(reason => { assert.equal(reason, error); assert.equal(dog.get('isError'), false, 'must not be error'); @@ -519,6 +561,6 @@ test(`when destroying a record setup the record state to invalid, the record's a assert.equal(dog.get('isDeleted'), false, 'must not be deleted after `rollbackAttributes`'); assert.equal(dog.get('isValid'), true, 'must be valid after `rollbackAttributes`'); assert.ok(dog.get('errors.length') === 0, 'must not have errors'); - }) + }); }); }); diff --git a/tests/unit/modules-test.js b/tests/unit/modules-test.js index e25b06233dc..9f92525aa3f 100644 --- a/tests/unit/modules-test.js +++ b/tests/unit/modules-test.js @@ -18,12 +18,7 @@ import JSONAPISerializer from 'ember-data/serializers/json-api'; import RESTSerializer from 'ember-data/serializers/rest'; import EmbeddedRecordsMixin from 'ember-data/serializers/embedded-records-mixin'; -import { - AdapterError, - InvalidError, - TimeoutError, - AbortError -} from 'ember-data/adapters/errors'; +import { AdapterError, InvalidError, TimeoutError, AbortError } from 'ember-data/adapters/errors'; module('unit/modules - public modules'); diff --git a/tests/unit/private-test.js b/tests/unit/private-test.js index b2f1c2f3515..95b1b7e0431 100644 --- a/tests/unit/private-test.js +++ b/tests/unit/private-test.js @@ -1,8 +1,5 @@ import { module, test } from 'qunit'; -import { - InternalModel, - RootState -} from 'ember-data/-private'; +import { InternalModel, RootState } from 'ember-data/-private'; module('-private'); diff --git a/tests/unit/promise-proxies-test.js b/tests/unit/promise-proxies-test.js index 1e5ab5fee69..26930f9b6bc 100644 --- a/tests/unit/promise-proxies-test.js +++ b/tests/unit/promise-proxies-test.js @@ -15,7 +15,7 @@ test('.reload should NOT leak the internal promise, rather return another promis content.reload = () => EmberPromise.resolve(content); let array = DS.PromiseManyArray.create({ - content + content, }); let reloaded = array.reload(); @@ -34,7 +34,7 @@ test('.reload should be stable', function(assert) { let promise = EmberPromise.resolve(content); let array = DS.PromiseManyArray.create({ - promise + promise, }); assert.equal(array.get('isRejected'), false, 'should NOT be rejected'); @@ -72,12 +72,12 @@ test('.reload should be stable', function(assert) { test('.set to new promise should be like reload', function(assert) { assert.expect(18); - let content = A([1,2,3]); + let content = A([1, 2, 3]); let promise = EmberPromise.resolve(content); let array = DS.PromiseManyArray.create({ - promise + promise, }); assert.equal(array.get('isRejected'), false, 'should NOT be rejected'); @@ -110,4 +110,3 @@ test('.set to new promise should be like reload', function(assert) { }); }); }); - diff --git a/tests/unit/record-arrays/adapter-populated-record-array-test.js b/tests/unit/record-arrays/adapter-populated-record-array-test.js index 3c0b4001236..a9db12d8068 100644 --- a/tests/unit/record-arrays/adapter-populated-record-array-test.js +++ b/tests/unit/record-arrays/adapter-populated-record-array-test.js @@ -3,7 +3,7 @@ import RSVP from 'rsvp'; import { run } from '@ember/runloop'; import DS from 'ember-data'; import { module, test } from 'qunit'; -const { AdapterPopulatedRecordArray , RecordArrayManager } = DS; +const { AdapterPopulatedRecordArray, RecordArrayManager } = DS; module('unit/record-arrays/adapter-populated-record-array - DS.AdapterPopulatedRecordArray'); @@ -14,7 +14,7 @@ function internalModelFor(record) { }, getRecord() { return record; - } + }, }; record._internalModel = _internalModel; @@ -42,7 +42,7 @@ test('custom initial state', function(assert) { content, store, query: 'some-query', - links: 'foo' + links: 'foo', }); assert.equal(recordArray.get('isLoaded'), true); assert.equal(recordArray.get('isUpdating'), false); @@ -56,9 +56,13 @@ test('custom initial state', function(assert) { test('#replace() throws error', function(assert) { let recordArray = AdapterPopulatedRecordArray.create({ modelName: 'recordType' }); - assert.throws(() => { - recordArray.replace(); - }, Error('The result of a server query (on recordType) is immutable.'), 'throws error'); + assert.throws( + () => { + recordArray.replace(); + }, + Error('The result of a server query (on recordType) is immutable.'), + 'throws error' + ); }); test('#update uses _update enabling query specific behavior', function(assert) { @@ -73,13 +77,13 @@ test('#update uses _update enabling query specific behavior', function(assert) { assert.equal(array, recordArray); return deferred.promise; - } + }, }; let recordArray = AdapterPopulatedRecordArray.create({ modelName: 'recordType', store, - query: 'some-query' + query: 'some-query', }); assert.equal(recordArray.get('isUpdating'), false, 'should not yet be updating'); @@ -110,7 +114,7 @@ test('#_setInternalModels', function(assert) { let recordArray = AdapterPopulatedRecordArray.create({ query: 'some-query', - manager: new RecordArrayManager({}) + manager: new RecordArrayManager({}), }); let model1 = internalModelFor({ id: 1 }); @@ -130,17 +134,22 @@ test('#_setInternalModels', function(assert) { let meta = { bar: 2 }; run(() => { - assert.equal(recordArray._setInternalModels([model1, model2], { - links, - meta - }), undefined, '_setInternalModels should have no return value'); + assert.equal( + recordArray._setInternalModels([model1, model2], { + links, + meta, + }), + undefined, + '_setInternalModels should have no return value' + ); assert.equal(didAddRecord, 2, 'two records should have been added'); - assert.deepEqual(recordArray.toArray(), [ - model1, - model2 - ].map(x => x.getRecord()), 'should now contain the loaded records'); + assert.deepEqual( + recordArray.toArray(), + [model1, model2].map(x => x.getRecord()), + 'should now contain the loaded records' + ); assert.equal(didLoad, 0, 'didLoad event should not have fired'); assert.equal(recordArray.get('links').foo, 1); @@ -167,7 +176,7 @@ test('change events when receiving a new query payload', function(assert) { let recordArray = AdapterPopulatedRecordArray.create({ query: 'some-query', - manager: new RecordArrayManager({}) + manager: new RecordArrayManager({}), }); let model1 = internalModelFor({ id: '1', name: 'Scumbag Dale' }); @@ -177,10 +186,7 @@ test('change events when receiving a new query payload', function(assert) { model2._recordArrays = { add, delete: del }; run(() => { - recordArray._setInternalModels([ - model1, - model2 - ], {}); + recordArray._setInternalModels([model1, model2], {}); }); assert.equal(didAddRecord, 2, 'expected 2 didAddRecords'); @@ -198,9 +204,9 @@ test('change events when receiving a new query payload', function(assert) { // first time invoked assert.equal(array, recordArray, 'should be same record array as above'); - assert.equal(startIdx, 0, 'expected startIdx'); + assert.equal(startIdx, 0, 'expected startIdx'); assert.equal(removeAmt, 2, 'expcted removeAmt'); - assert.equal(addAmt, 2, 'expected addAmt'); + assert.equal(addAmt, 2, 'expected addAmt'); }); assert.equal(recordArray.get('isLoaded'), true, 'should be considered loaded'); @@ -221,10 +227,7 @@ test('change events when receiving a new query payload', function(assert) { run(() => { // re-query - recordArray._setInternalModels([ - model3, - model4 - ], {}); + recordArray._setInternalModels([model3, model4], {}); }); assert.equal(didAddRecord, 2, 'expected 2 didAddRecords'); @@ -245,9 +248,9 @@ test('change events when receiving a new query payload', function(assert) { // first time invoked assert.equal(array, recordArray, 'should be same recordArray as above'); - assert.equal(startIdx, 0, 'expected startIdx'); + assert.equal(startIdx, 0, 'expected startIdx'); assert.equal(removeAmt, 2, 'expcted removeAmt'); - assert.equal(addAmt, 1, 'expected addAmt'); + assert.equal(addAmt, 1, 'expected addAmt'); }); // re-query @@ -257,14 +260,12 @@ test('change events when receiving a new query payload', function(assert) { assert.equal(arrayDidChange, 0, 'record array should not yet have omitted a change event'); assert.equal(contentDidChange, 0, 'recordArray.content should not have changed'); - let model5 = internalModelFor({ id: '3', name: 'Scumbag Penner' }) + let model5 = internalModelFor({ id: '3', name: 'Scumbag Penner' }); model5._recordArrays = { add, delete: del }; run(() => { - recordArray._setInternalModels([ - model5 - ], {}); + recordArray._setInternalModels([model5], {}); }); assert.equal(didAddRecord, 1, 'expected 0 didAddRecord'); diff --git a/tests/unit/record-arrays/record-array-test.js b/tests/unit/record-arrays/record-array-test.js index 51fbaeb5f10..4a26f37b6ab 100644 --- a/tests/unit/record-arrays/record-array-test.js +++ b/tests/unit/record-arrays/record-array-test.js @@ -27,7 +27,7 @@ test('custom initial state', function(assert) { isLoaded: true, isUpdating: true, content, - store + store, }); assert.equal(get(recordArray, 'isLoaded'), true); assert.equal(get(recordArray, 'isUpdating'), false); // cannot set as default value: @@ -39,21 +39,39 @@ test('custom initial state', function(assert) { test('#replace() throws error', function(assert) { let recordArray = RecordArray.create({ modelName: 'recordType' }); - assert.throws(() => { - recordArray.replace(); - }, Error('The result of a server query (for all recordType types) is immutable. To modify contents, use toArray()'), 'throws error'); + assert.throws( + () => { + recordArray.replace(); + }, + Error( + 'The result of a server query (for all recordType types) is immutable. To modify contents, use toArray()' + ), + 'throws error' + ); }); test('#objectAtContent', function(assert) { let content = A([ - { getRecord() { return 'foo'; }}, - { getRecord() { return 'bar'; }}, - { getRecord() { return 'baz'; }} + { + getRecord() { + return 'foo'; + }, + }, + { + getRecord() { + return 'bar'; + }, + }, + { + getRecord() { + return 'baz'; + }, + }, ]); let recordArray = RecordArray.create({ modelName: 'recordType', - content + content, }); assert.equal(get(recordArray, 'length'), 3); @@ -73,12 +91,12 @@ test('#update', function(assert) { assert.equal(modelName, 'recordType'); assert.equal(options.reload, true, 'options should contain reload: true'); return deferred.promise; - } + }, }; let recordArray = RecordArray.create({ modelName: 'recordType', - store + store, }); assert.equal(get(recordArray, 'isUpdating'), false, 'should not yet be updating'); @@ -99,7 +117,6 @@ test('#update', function(assert) { }); }); - test('#update while updating', function(assert) { let findAllCalled = 0; let deferred = RSVP.defer(); @@ -107,12 +124,12 @@ test('#update while updating', function(assert) { findAll(modelName, options) { findAllCalled++; return deferred.promise; - } + }, }; let recordArray = RecordArray.create({ modelName: { modelName: 'recordType' }, - store + store, }); assert.equal(get(recordArray, 'isUpdating'), false, 'should not be updating'); @@ -141,18 +158,41 @@ test('#update while updating', function(assert) { test('#_pushInternalModels', function(assert) { let content = A(); let recordArray = RecordArray.create({ - content + content, }); - let model1 = { id: 1, getRecord() { return 'model-1'; } }; - let model2 = { id: 2, getRecord() { return 'model-2'; } }; - let model3 = { id: 3, getRecord() { return 'model-3'; } }; + let model1 = { + id: 1, + getRecord() { + return 'model-1'; + }, + }; + let model2 = { + id: 2, + getRecord() { + return 'model-2'; + }, + }; + let model3 = { + id: 3, + getRecord() { + return 'model-3'; + }, + }; - assert.equal(recordArray._pushInternalModels([model1]), undefined, '_pushInternalModels has no return value'); + assert.equal( + recordArray._pushInternalModels([model1]), + undefined, + '_pushInternalModels has no return value' + ); assert.deepEqual(content, [model1], 'now contains model1'); recordArray._pushInternalModels([model1]); - assert.deepEqual(content, [model1, model1], 'allows duplicates, because record-array-manager via internalModel._recordArrays ensures no duplicates, this layer should not double check'); + assert.deepEqual( + content, + [model1, model1], + 'allows duplicates, because record-array-manager via internalModel._recordArrays ensures no duplicates, this layer should not double check' + ); recordArray._removeInternalModels([model1]); recordArray._pushInternalModels([model1]); @@ -165,31 +205,66 @@ test('#_pushInternalModels', function(assert) { test('#_removeInternalModels', function(assert) { let content = A(); let recordArray = RecordArray.create({ - content + content, }); - let model1 = { id: 1, getRecord() { return 'model-1'; } }; - let model2 = { id: 2, getRecord() { return 'model-2'; } }; - let model3 = { id: 3, getRecord() { return 'model-3'; } }; + let model1 = { + id: 1, + getRecord() { + return 'model-1'; + }, + }; + let model2 = { + id: 2, + getRecord() { + return 'model-2'; + }, + }; + let model3 = { + id: 3, + getRecord() { + return 'model-3'; + }, + }; assert.equal(content.length, 0); - assert.equal(recordArray._removeInternalModels([model1]), undefined, '_removeInternalModels has no return value'); + assert.equal( + recordArray._removeInternalModels([model1]), + undefined, + '_removeInternalModels has no return value' + ); assert.deepEqual(content, [], 'now contains no models'); recordArray._pushInternalModels([model1, model2]); assert.deepEqual(content, [model1, model2], 'now contains model1, model2,'); - assert.equal(recordArray._removeInternalModels([model1]), undefined, '_removeInternalModels has no return value'); + assert.equal( + recordArray._removeInternalModels([model1]), + undefined, + '_removeInternalModels has no return value' + ); assert.deepEqual(content, [model2], 'now only contains model2'); - assert.equal(recordArray._removeInternalModels([model2]), undefined, '_removeInternalModels has no return value'); + assert.equal( + recordArray._removeInternalModels([model2]), + undefined, + '_removeInternalModels has no return value' + ); assert.deepEqual(content, [], 'now contains no models'); - recordArray._pushInternalModels([model1, model2, model3]) + recordArray._pushInternalModels([model1, model2, model3]); - assert.equal(recordArray._removeInternalModels([model1, model3]), undefined, '_removeInternalModels has no return value'); + assert.equal( + recordArray._removeInternalModels([model1, model3]), + undefined, + '_removeInternalModels has no return value' + ); assert.deepEqual(content, [model2], 'now contains model2'); - assert.equal(recordArray._removeInternalModels([model2]), undefined, '_removeInternalModels has no return value'); + assert.equal( + recordArray._removeInternalModels([model2]), + undefined, + '_removeInternalModels has no return value' + ); assert.deepEqual(content, [], 'now contains no models'); }); @@ -203,7 +278,9 @@ class FakeInternalModel { return this.__recordArrays; } - getRecord() { return this._record; } + getRecord() { + return this._record; + } createSnapshot() { return this._record; @@ -215,15 +292,22 @@ function internalModelFor(record) { } test('#save', function(assert) { - let model1 = { save() { model1Saved++; return this;} }; - let model2 = { save() { model2Saved++; return this;} }; - let content = A([ - internalModelFor(model1), - internalModelFor(model2) - ]); + let model1 = { + save() { + model1Saved++; + return this; + }, + }; + let model2 = { + save() { + model2Saved++; + return this; + }, + }; + let content = A([internalModelFor(model1), internalModelFor(model2)]); let recordArray = RecordArray.create({ - content + content, }); let model1Saved = 0; @@ -244,8 +328,8 @@ test('#save', function(assert) { test('#destroy', function(assert) { let didUnregisterRecordArray = 0; - let didDissociatieFromOwnRecords = 0; - let model1 = { }; + let didDissociatieFromOwnRecords = 0; + let model1 = {}; let internalModel1 = internalModelFor(model1); // TODO: this will be removed once we fix ownership related memory leaks. @@ -253,7 +337,7 @@ test('#destroy', function(assert) { delete(array) { didDissociatieFromOwnRecords++; assert.equal(array, recordArray); - } + }, }; // end TODO: @@ -263,8 +347,8 @@ test('#destroy', function(assert) { unregisterRecordArray(_recordArray) { didUnregisterRecordArray++; assert.equal(recordArray, _recordArray); - } - } + }, + }, }); assert.equal(get(recordArray, 'isDestroyed'), false, 'should not be destroyed'); @@ -272,13 +356,29 @@ test('#destroy', function(assert) { run(() => { assert.equal(get(recordArray, 'length'), 1, 'before destroy, length should be 1'); - assert.equal(didUnregisterRecordArray, 0, 'before destroy, we should not yet have unregisterd the record array'); - assert.equal(didDissociatieFromOwnRecords, 0, 'before destroy, we should not yet have dissociated from own record array'); + assert.equal( + didUnregisterRecordArray, + 0, + 'before destroy, we should not yet have unregisterd the record array' + ); + assert.equal( + didDissociatieFromOwnRecords, + 0, + 'before destroy, we should not yet have dissociated from own record array' + ); recordArray.destroy(); }); - assert.equal(didUnregisterRecordArray, 1, 'after destroy we should have unregistered the record array'); - assert.equal(didDissociatieFromOwnRecords, 1, 'after destroy, we should have dissociated from own record array'); + assert.equal( + didUnregisterRecordArray, + 1, + 'after destroy we should have unregistered the record array' + ); + assert.equal( + didDissociatieFromOwnRecords, + 1, + 'after destroy, we should have dissociated from own record array' + ); recordArray.destroy(); assert.strictEqual(get(recordArray, 'content'), null); @@ -288,35 +388,33 @@ test('#destroy', function(assert) { test('#_createSnapshot', function(assert) { let model1 = { - id: 1 + id: 1, }; let model2 = { - id: 2 + id: 2, }; - let content = A([ - internalModelFor(model1), - internalModelFor(model2) - ]); + let content = A([internalModelFor(model1), internalModelFor(model2)]); let recordArray = RecordArray.create({ - content + content, }); let snapshot = recordArray._createSnapshot(); let snapshots = snapshot.snapshots(); - assert.deepEqual(snapshots, [ - model1, - model2 - ], 'record array snapshot should contain the internalModel.createSnapshot result'); + assert.deepEqual( + snapshots, + [model1, model2], + 'record array snapshot should contain the internalModel.createSnapshot result' + ); }); test('#destroy', function(assert) { let didUnregisterRecordArray = 0; - let didDissociatieFromOwnRecords = 0; - let model1 = { }; + let didDissociatieFromOwnRecords = 0; + let model1 = {}; let internalModel1 = internalModelFor(model1); // TODO: this will be removed once we fix ownership related memory leaks. @@ -324,7 +422,7 @@ test('#destroy', function(assert) { delete(array) { didDissociatieFromOwnRecords++; assert.equal(array, recordArray); - } + }, }; // end TODO: @@ -334,8 +432,8 @@ test('#destroy', function(assert) { unregisterRecordArray(_recordArray) { didUnregisterRecordArray++; assert.equal(recordArray, _recordArray); - } - } + }, + }, }); assert.equal(get(recordArray, 'isDestroyed'), false, 'should not be destroyed'); @@ -343,17 +441,32 @@ test('#destroy', function(assert) { run(() => { assert.equal(get(recordArray, 'length'), 1, 'before destroy, length should be 1'); - assert.equal(didUnregisterRecordArray, 0, 'before destroy, we should not yet have unregisterd the record array'); - assert.equal(didDissociatieFromOwnRecords, 0, 'before destroy, we should not yet have dissociated from own record array'); + assert.equal( + didUnregisterRecordArray, + 0, + 'before destroy, we should not yet have unregisterd the record array' + ); + assert.equal( + didDissociatieFromOwnRecords, + 0, + 'before destroy, we should not yet have dissociated from own record array' + ); recordArray.destroy(); }); - assert.equal(didUnregisterRecordArray, 1, 'after destroy we should have unregistered the record array'); - assert.equal(didDissociatieFromOwnRecords, 1, 'after destroy, we should have dissociated from own record array'); + assert.equal( + didUnregisterRecordArray, + 1, + 'after destroy we should have unregistered the record array' + ); + assert.equal( + didDissociatieFromOwnRecords, + 1, + 'after destroy, we should have dissociated from own record array' + ); recordArray.destroy(); assert.strictEqual(get(recordArray, 'content'), null); assert.equal(get(recordArray, 'length'), 0, 'after destroy we should have no length'); assert.equal(get(recordArray, 'isDestroyed'), true, 'should be destroyed'); }); - diff --git a/tests/unit/states-test.js b/tests/unit/states-test.js index c655068d54b..dd01674ee90 100644 --- a/tests/unit/states-test.js +++ b/tests/unit/states-test.js @@ -9,15 +9,23 @@ let rootState, stateName; module('unit/states - Flags for record states', { beforeEach() { rootState = DS.RootState; - } + }, }); assert.flagIsTrue = function flagIsTrue(flag) { - this.equal(get(rootState, stateName + '.' + flag), true, stateName + '.' + flag + ' should be true'); + this.equal( + get(rootState, stateName + '.' + flag), + true, + stateName + '.' + flag + ' should be true' + ); }; assert.flagIsFalse = function flagIsFalse(flag) { - this.equal(get(rootState, stateName + '.' + flag), false, stateName + '.' + flag + ' should be false'); + this.equal( + get(rootState, stateName + '.' + flag), + false, + stateName + '.' + flag + ' should be false' + ); }; test('the empty state', function(assert) { diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index e2bd5b86b9d..576faf6cfaf 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -1,9 +1,5 @@ import { A } from '@ember/array'; -import { - resolve, - all, - Promise as EmberPromise -} from 'rsvp'; +import { resolve, all, Promise as EmberPromise } from 'rsvp'; import { set, get } from '@ember/object'; import { run } from '@ember/runloop'; import { createStore } from 'dummy/tests/helpers/store'; @@ -23,9 +19,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', { afterEach() { run(() => { - if (store) { store.destroy(); } + if (store) { + store.destroy(); + } }); - } + }, }); test('Adapter can be set as a factory', function(assert) { @@ -44,7 +42,7 @@ testInDebug('Adapter can not be set as an instance', function(assert) { assert.expect(1); store = DS.Store.create({ - adapter: DS.Adapter.create() + adapter: DS.Adapter.create(), }); assert.expectAssertion(() => store.get('defaultAdapter')); }); @@ -55,26 +53,34 @@ test('Calling Store#find invokes its adapter#find', function(assert) { let currentStore; const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { - assert.ok(true, "Adapter#find was called"); - assert.equal(store, currentStore, "Adapter#find was called with the right store"); - assert.equal(type, store.modelFor('test'), "Adapter#find was called with the type passed into Store#find"); - assert.equal(id, 1, "Adapter#find was called with the id passed into Store#find"); - assert.equal(snapshot.id, '1', "Adapter#find was called with the record created from Store#find"); + assert.ok(true, 'Adapter#find was called'); + assert.equal(store, currentStore, 'Adapter#find was called with the right store'); + assert.equal( + type, + store.modelFor('test'), + 'Adapter#find was called with the type passed into Store#find' + ); + assert.equal(id, 1, 'Adapter#find was called with the id passed into Store#find'); + assert.equal( + snapshot.id, + '1', + 'Adapter#find was called with the record created from Store#find' + ); return resolve({ data: { id: 1, - type: 'test' - } + type: 'test', + }, }); - } + }, }); const Type = DS.Model.extend(); currentStore = createStore({ adapter: Adapter, - test: Type + test: Type, }); return run(() => currentStore.findRecord('test', 1)); @@ -89,23 +95,20 @@ test('Calling Store#findRecord multiple times coalesces the calls into a adapter }, findMany(store, type, ids, snapshots) { assert.ok(true, 'Adapter#findMany was called'); - assert.deepEqual(ids, ['1','2'], 'Correct ids were passed in to findMany'); + assert.deepEqual(ids, ['1', '2'], 'Correct ids were passed in to findMany'); return resolve({ data: [{ id: 1, type: 'test' }, { id: 2, type: 'test' }] }); }, - coalesceFindRequests: true + coalesceFindRequests: true, }); const Type = DS.Model.extend(); let store = createStore({ adapter: Adapter, - test: Type + test: Type, }); return run(() => { - return all([ - store.findRecord('test', 1), - store.findRecord('test', 2) - ]); + return all([store.findRecord('test', 1), store.findRecord('test', 2)]); }); }); @@ -114,17 +117,17 @@ test('Returning a promise from `findRecord` asynchronously loads data', function const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { - return resolve({ data: { id: 1, type: 'test', attributes: { name: "Scumbag Dale" } } }); - } + return resolve({ data: { id: 1, type: 'test', attributes: { name: 'Scumbag Dale' } } }); + }, }); const Type = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let store = createStore({ adapter: Adapter, - test: Type + test: Type, }); return run(() => { @@ -141,38 +144,45 @@ test('IDs provided as numbers are coerced to strings', function(assert) { findRecord(store, type, id, snapshot) { assert.equal(typeof id, 'string', 'id has been normalized to a string'); return resolve({ data: { id, type: 'test', attributes: { name: 'Scumbag Sylvain' } } }); - } + }, }); const Type = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let store = createStore({ adapter: Adapter, - test: Type + test: Type, }); return run(() => { - return store.findRecord('test', 1).then(object => { - assert.equal(typeof object.get('id'), 'string', 'id was coerced to a string'); - run(() => { - store.push({ - data: { - type: 'test', - id: '2', - attributes: { - name: 'Scumbag Sam Saffron' - } - } + return store + .findRecord('test', 1) + .then(object => { + assert.equal(typeof object.get('id'), 'string', 'id was coerced to a string'); + run(() => { + store.push({ + data: { + type: 'test', + id: '2', + attributes: { + name: 'Scumbag Sam Saffron', + }, + }, + }); }); - }); - return store.findRecord('test', 2); - }).then(object => { - assert.ok(object, 'object was found'); - assert.equal(typeof object.get('id'), 'string', 'id is a string despite being supplied and searched for as a number'); - }); + return store.findRecord('test', 2); + }) + .then(object => { + assert.ok(object, 'object was found'); + assert.equal( + typeof object.get('id'), + 'string', + 'id is a string despite being supplied and searched for as a number' + ); + }); }); }); @@ -180,7 +190,7 @@ test('can load data for the same record if it is not dirty', function(assert) { assert.expect(3); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let store = createStore({ @@ -188,8 +198,8 @@ test('can load data for the same record if it is not dirty', function(assert) { adapter: DS.Adapter.extend({ shouldBackgroundReloadRecord() { return false; - } - }) + }, + }), }); return run(() => { @@ -198,9 +208,9 @@ test('can load data for the same record if it is not dirty', function(assert) { type: 'person', id: '1', attributes: { - name: "Tom Dale" - } - } + name: 'Tom Dale', + }, + }, }); return store.findRecord('person', 1).then(tom => { @@ -212,9 +222,9 @@ test('can load data for the same record if it is not dirty', function(assert) { type: 'person', id: '1', attributes: { - name: 'Captain Underpants' - } - } + name: 'Captain Underpants', + }, + }, }); assert.equal(get(tom, 'name'), 'Captain Underpants', 'updated record with new date'); }); @@ -227,7 +237,7 @@ test('loadMany takes an optional Object and passes it on to the Adapter', functi let passedQuery = { page: 1 }; const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const Adapter = TestAdapter.extend({ @@ -235,12 +245,12 @@ test('loadMany takes an optional Object and passes it on to the Adapter', functi assert.equal(type, store.modelFor('person'), 'The type was Person'); assert.equal(query, passedQuery, 'The query was passed in'); return resolve({ data: [] }); - } + }, }); let store = createStore({ adapter: Adapter, - person: Person + person: Person, }); run(() => store.query('person', passedQuery)); @@ -250,13 +260,13 @@ test('Find with query calls the correct normalizeResponse', function(assert) { let passedQuery = { page: 1 }; const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const Adapter = TestAdapter.extend({ query(store, type, query) { return resolve([]); - } + }, }); let callCount = 0; @@ -265,12 +275,12 @@ test('Find with query calls the correct normalizeResponse', function(assert) { normalizeQueryResponse() { callCount++; return this._super(...arguments); - } + }, }); let env = setupStore({ adapter: Adapter, - person: Person + person: Person, }); let { store } = env; @@ -283,11 +293,11 @@ test('Find with query calls the correct normalizeResponse', function(assert) { test('peekAll(type) returns a record array of all records of a specific type', function(assert) { const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let store = createStore({ - person: Person + person: Person, }); run(() => { @@ -296,9 +306,9 @@ test('peekAll(type) returns a record array of all records of a specific type', f type: 'person', id: '1', attributes: { - name: "Tom Dale" - } - } + name: 'Tom Dale', + }, + }, }); }); @@ -313,24 +323,32 @@ test('peekAll(type) returns a record array of all records of a specific type', f type: 'person', id: '2', attributes: { - name: 'Yehuda Katz' - } - } + name: 'Yehuda Katz', + }, + }, }); }); assert.equal(get(results, 'length'), 2, 'record array should have the new object'); - assert.equal(get(results.objectAt(1), 'name'), 'Yehuda Katz', 'record has the correct information'); - - assert.strictEqual(results, store.peekAll('person'), 'subsequent calls to peekAll return the same recordArray)'); + assert.equal( + get(results.objectAt(1), 'name'), + 'Yehuda Katz', + 'record has the correct information' + ); + + assert.strictEqual( + results, + store.peekAll('person'), + 'subsequent calls to peekAll return the same recordArray)' + ); }); test('a new record of a particular type is created via store.createRecord(type)', function(assert) { const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let store = createStore({ - person: Person + person: Person, }); let person = store.createRecord('person'); @@ -341,38 +359,45 @@ test('a new record of a particular type is created via store.createRecord(type)' run(() => set(person, 'name', 'Braaahm Dale')); - assert.equal(get(person, 'name'), 'Braaahm Dale', 'Even if no hash is supplied, `set` still worked'); + assert.equal( + get(person, 'name'), + 'Braaahm Dale', + 'Even if no hash is supplied, `set` still worked' + ); }); -testInDebug("a new record with a specific id can't be created if this id is already used in the store", function(assert) { - const Person = DS.Model.extend({ - name: DS.attr('string') - }); - - Person.reopenClass({ - toString() { - return 'Person'; - } - }); +testInDebug( + "a new record with a specific id can't be created if this id is already used in the store", + function(assert) { + const Person = DS.Model.extend({ + name: DS.attr('string'), + }); - let store = createStore({ - person: Person - }); + Person.reopenClass({ + toString() { + return 'Person'; + }, + }); - store.createRecord('person', { id: 5 }); + let store = createStore({ + person: Person, + }); - assert.expectAssertion(() => { store.createRecord('person', { id: 5 }); - }, /The id 5 has already been used with another record for modelClass 'person'/); -}); + + assert.expectAssertion(() => { + store.createRecord('person', { id: 5 }); + }, /The id 5 has already been used with another record for modelClass 'person'/); + } +); test('an initial data hash can be provided via store.createRecord(type, hash)', function(assert) { const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let store = createStore({ - person: Person + person: Person, }); let person = store.createRecord('person', { name: 'Brohuda Katz' }); @@ -384,18 +409,18 @@ test('an initial data hash can be provided via store.createRecord(type, hash)', assert.equal(get(person, 'name'), 'Brohuda Katz', 'The initial data hash is provided'); }); -test("if an id is supplied in the initial data hash, it can be looked up using `store.find`", function(assert) { +test('if an id is supplied in the initial data hash, it can be looked up using `store.find`', function(assert) { assert.expect(1); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let store = createStore({ person: Person, adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord: () => false - }) + shouldBackgroundReloadRecord: () => false, + }), }); return run(() => { @@ -407,23 +432,23 @@ test("if an id is supplied in the initial data hash, it can be looked up using ` }); }); -test("initial values of attributes can be passed in as the third argument to find", function(assert) { +test('initial values of attributes can be passed in as the third argument to find', function(assert) { assert.expect(1); const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.attr('name'), 'Test', 'Preloaded attribtue set'); return { data: { id: '1', type: 'test', attributes: { name: 'Test' } } }; - } + }, }); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let store = createStore({ adapter: Adapter, - test: Person + test: Person, }); return run(() => store.findRecord('test', 1, { preload: { name: 'Test' } })); @@ -436,18 +461,18 @@ test('initial values of belongsTo can be passed in as the third argument to find findRecord(store, type, id, snapshot) { assert.equal(snapshot.belongsTo('friend').attr('name'), 'Tom', 'Preloaded belongsTo set'); return { data: { id, type: 'person' } }; - } + }, }); let env = setupStore({ - adapter: Adapter + adapter: Adapter, }); let { store } = env; const Person = DS.Model.extend({ name: DS.attr('string'), - friend: DS.belongsTo('person', { inverse: null, async: true }) + friend: DS.belongsTo('person', { inverse: null, async: true }), }); env.registry.register('model:person', Person); @@ -458,9 +483,9 @@ test('initial values of belongsTo can be passed in as the third argument to find type: 'person', id: '2', attributes: { - name: 'Tom' - } - } + name: 'Tom', + }, + }, }); let tom = store.peekRecord('person', 2); @@ -474,27 +499,29 @@ test('initial values of belongsTo can be passed in as the third argument to find const Adapter = TestAdapter.extend({ findRecord(store, type, id, snapshot) { return { data: { id, type: 'person' } }; - } + }, }); let env = setupStore({ - adapter: Adapter - + adapter: Adapter, }); let { store } = env; const Person = DS.Model.extend({ name: DS.attr('string'), - friend: DS.belongsTo('person', { async: true, inverse: null }) + friend: DS.belongsTo('person', { async: true, inverse: null }), }); env.registry.register('model:person', Person); return run(() => { return store.findRecord('person', 1, { preload: { friend: 2 } }).then(() => { - return store.peekRecord('person', 1).get('friend').then(friend => { - assert.equal(friend.get('id'), '2', 'Preloaded belongsTo set'); - }); + return store + .peekRecord('person', 1) + .get('friend') + .then(friend => { + assert.equal(friend.get('id'), '2', 'Preloaded belongsTo set'); + }); }); }); }); @@ -506,18 +533,18 @@ test('initial values of hasMany can be passed in as the third argument to find a findRecord(store, type, id, snapshot) { assert.equal(snapshot.hasMany('friends')[0].attr('name'), 'Tom', 'Preloaded hasMany set'); return { data: { id, type: 'person' } }; - } + }, }); let env = setupStore({ - adapter: Adapter + adapter: Adapter, }); let { store } = env; const Person = DS.Model.extend({ name: DS.attr('string'), - friends: DS.hasMany('person', { inverse: null, async: true }) + friends: DS.hasMany('person', { inverse: null, async: true }), }); env.registry.register('model:person', Person); @@ -528,9 +555,9 @@ test('initial values of hasMany can be passed in as the third argument to find a type: 'person', id: '2', attributes: { - name: 'Tom' - } - } + name: 'Tom', + }, + }, }); let tom = store.peekRecord('person', 2); @@ -545,17 +572,17 @@ test('initial values of hasMany can be passed in as the third argument to find a findRecord(store, type, id, snapshot) { assert.equal(snapshot.hasMany('friends')[0].id, '2', 'Preloaded hasMany set'); return { data: { id, type: 'person' } }; - } + }, }); let env = setupStore({ - adapter: Adapter + adapter: Adapter, }); let { store } = env; const Person = DS.Model.extend({ name: DS.attr('string'), - friends: DS.hasMany('person', { async: true, inverse: null }) + friends: DS.hasMany('person', { async: true, inverse: null }), }); env.registry.register('model:person', Person); @@ -570,18 +597,18 @@ test('initial empty values of hasMany can be passed in as the third argument to findRecord(store, type, id, snapshot) { assert.equal(snapshot.hasMany('friends').length, 0, 'Preloaded hasMany set'); return { data: { id, type: 'person' } }; - } + }, }); let env = setupStore({ - adapter: Adapter + adapter: Adapter, }); let { store } = env; const Person = DS.Model.extend({ name: DS.attr('string'), - friends: DS.hasMany('person', { inverse: null, async: true }) + friends: DS.hasMany('person', { inverse: null, async: true }), }); env.registry.register('model:person', Person); @@ -598,17 +625,17 @@ test('initial values of hasMany can be passed in as the third argument to find a findRecord(store, type, id, snapshot) { assert.equal(snapshot.hasMany('friends').length, 0, 'Preloaded hasMany set'); return { data: { id, type: 'person' } }; - } + }, }); let env = setupStore({ - adapter: Adapter + adapter: Adapter, }); let { store } = env; const Person = DS.Model.extend({ name: DS.attr('string'), - friends: DS.hasMany('person', { async: true, inverse: null }) + friends: DS.hasMany('person', { async: true, inverse: null }), }); env.registry.register('model:person', Person); @@ -620,7 +647,7 @@ test('records should have their ids updated when the adapter returns the id data assert.expect(2); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); let idCounter = 1; @@ -631,16 +658,16 @@ test('records should have their ids updated when the adapter returns the id data id: idCounter++, type: 'person', attributes: { - name: snapshot.attr('name') - } - } + name: snapshot.attr('name'), + }, + }, }; - } + }, }); let store = createStore({ adapter: Adapter, - person: Person + person: Person, }); let people = store.peekAll('person'); @@ -648,10 +675,7 @@ test('records should have their ids updated when the adapter returns the id data let yehuda = store.createRecord('person', { name: 'Yehuda Katz' }); return run(() => { - return all([ - tom.save(), - yehuda.save() - ]).then(() => { + return all([tom.save(), yehuda.save()]).then(() => { people.forEach((person, index) => { assert.equal(person.get('id'), index + 1, `The record's id should be correct.`); }); @@ -665,10 +689,10 @@ test('store.fetchMany should always return a promise', function(assert) { const Person = DS.Model.extend(); let store = createStore({ adapter: TestAdapter.extend(), - person: Person + person: Person, }); - store.createRecord('person') + store.createRecord('person'); let records = []; let results = run(() => store._scheduleFetchMany(records)); @@ -697,20 +721,20 @@ test('store._scheduleFetchMany should not resolve until all the records are reso }, findMany(store, type, ids, snapshots) { - let records = ids.map(id => ( { id, type: type.modelName }) ); + let records = ids.map(id => ({ id, type: type.modelName })); return new EmberPromise(resolve => { run.later(() => { - resolve({data: records }); + resolve({ data: records }); }, 15); }); - } + }, }); let store = createStore({ adapter: adapter, test: Person, - phone: Phone + phone: Phone, }); store.createRecord('test'); @@ -718,7 +742,7 @@ test('store._scheduleFetchMany should not resolve until all the records are reso let internalModels = [ store._internalModelForId('test', 10), store._internalModelForId('phone', 20), - store._internalModelForId('phone', 21) + store._internalModelForId('phone', 21), ]; return run(() => { @@ -737,10 +761,7 @@ test('the store calls adapter.findMany according to groupings returned by adapte const Adapter = TestAdapter.extend({ groupRecordsForFindMany(store, snapshots) { - return [ - [snapshots[0]], - [snapshots[1], snapshots[2]] - ]; + return [[snapshots[0]], [snapshots[1], snapshots[2]]]; }, findRecord(store, type, id, snapshot) { @@ -754,23 +775,23 @@ test('the store calls adapter.findMany according to groupings returned by adapte assert.deepEqual(ids, ['20', '21'], 'The second group is passed to findMany'); return { data: records }; - } + }, }); let store = createStore({ adapter: Adapter, - test: Person + test: Person, }); let internalModels = [ store._internalModelForId('test', 10), store._internalModelForId('test', 20), - store._internalModelForId('test', 21) + store._internalModelForId('test', 21), ]; return run(() => { return store._scheduleFetchMany(internalModels).then(() => { - let ids = internalModels.map(x => x.id ) + let ids = internalModels.map(x => x.id); assert.deepEqual(ids, ['10', '20', '21'], 'The promise fulfills with the records'); }); }); @@ -784,10 +805,7 @@ test('the promise returned by `_scheduleFetch`, when it resolves, does not depen const Person = DS.Model.extend(); const Adapter = TestAdapter.extend({ groupRecordsForFindMany(store, snapshots) { - return [ - [snapshots[0]], - [snapshots[1]] - ]; + return [[snapshots[0]], [snapshots[1]]]; }, findRecord(store, type, id, snapshot) { @@ -797,18 +815,18 @@ test('the promise returned by `_scheduleFetch`, when it resolves, does not depen if (id === 'igor') { resolve({ data: record }); } else { - run.later(function () { + run.later(function() { davidResolved = true; resolve({ data: record }); }, 5); } }); - } + }, }); let store = createStore({ adapter: Adapter, - test: Person + test: Person, }); return run(() => { @@ -816,13 +834,17 @@ test('the promise returned by `_scheduleFetch`, when it resolves, does not depen let igor = store.findRecord('test', 'igor'); let wait = []; - wait.push(igor.then(() => { - assert.equal(davidResolved, false, 'Igor did not need to wait for David'); - })); + wait.push( + igor.then(() => { + assert.equal(davidResolved, false, 'Igor did not need to wait for David'); + }) + ); - wait.push(david.then(() => { - assert.equal(davidResolved, true, 'David resolved'); - })); + wait.push( + david.then(() => { + assert.equal(davidResolved, true, 'David resolved'); + }) + ); return all(wait); }); @@ -836,10 +858,7 @@ test('the promise returned by `_scheduleFetch`, when it rejects, does not depend const Person = DS.Model.extend(); const Adapter = TestAdapter.extend({ groupRecordsForFindMany(store, snapshots) { - return [ - [snapshots[0]], - [snapshots[1]] - ]; + return [[snapshots[0]], [snapshots[1]]]; }, findRecord(store, type, id, snapshot) { @@ -855,12 +874,12 @@ test('the promise returned by `_scheduleFetch`, when it rejects, does not depend }, 5); } }); - } + }, }); let store = createStore({ adapter: Adapter, - test: Person + test: Person, }); return run(() => { @@ -868,48 +887,55 @@ test('the promise returned by `_scheduleFetch`, when it rejects, does not depend let igor = store.findRecord('test', 'igor'); let wait = []; - wait.push(igor.catch(() => { - assert.equal(davidResolved, false, 'Igor did not need to wait for David'); - })); + wait.push( + igor.catch(() => { + assert.equal(davidResolved, false, 'Igor did not need to wait for David'); + }) + ); - wait.push(david.then(() => { - assert.equal(davidResolved, true, 'David resolved'); - })); + wait.push( + david.then(() => { + assert.equal(davidResolved, true, 'David resolved'); + }) + ); return EmberPromise.all(wait); }); }); -testInDebug('store._fetchRecord reject records that were not found, even when those requests were coalesced with records that were found', function(assert) { - assert.expect(3); +testInDebug( + 'store._fetchRecord reject records that were not found, even when those requests were coalesced with records that were found', + function(assert) { + assert.expect(3); - const Person = DS.Model.extend(); + const Person = DS.Model.extend(); - const Adapter = TestAdapter.extend({ - findMany(store, type, ids, snapshots) { - let records = ids.map((id) => ({ id, type: 'test' })); - return { data: [records[0]] }; - } - }); + const Adapter = TestAdapter.extend({ + findMany(store, type, ids, snapshots) { + let records = ids.map(id => ({ id, type: 'test' })); + return { data: [records[0]] }; + }, + }); - let store = createStore({ - adapter: Adapter, - test: Person - }); + let store = createStore({ + adapter: Adapter, + test: Person, + }); - let wait = []; - assert.expectWarning(() => { - run(() => { - let david = store.findRecord('test', 'david'); - let igor = store.findRecord('test', 'igor'); + let wait = []; + assert.expectWarning(() => { + run(() => { + let david = store.findRecord('test', 'david'); + let igor = store.findRecord('test', 'igor'); - wait.push(david.then(() => assert.ok(true, 'David resolved'))); - wait.push(igor.catch(() => assert.ok(true, 'Igor rejected'))); - }); - }, /expected to find records with the following ids/); + wait.push(david.then(() => assert.ok(true, 'David resolved'))); + wait.push(igor.catch(() => assert.ok(true, 'Igor rejected'))); + }); + }, /expected to find records with the following ids/); - return EmberPromise.all(wait); -}); + return EmberPromise.all(wait); + } +); testInDebug('store._fetchRecord warns when records are missing', function(assert) { const Person = DS.Model.extend(); @@ -918,13 +944,13 @@ testInDebug('store._fetchRecord warns when records are missing', function(assert findMany(store, type, ids, snapshots) { let records = ids.map(id => ({ id, type: 'test' })).filter(({ id }) => id === 'david'); - return {data: [records[0]] }; - } + return { data: [records[0]] }; + }, }); let store = createStore({ adapter: Adapter, - test: Person + test: Person, }); let wait = []; @@ -933,15 +959,23 @@ testInDebug('store._fetchRecord warns when records are missing', function(assert assert.expectWarning(() => { run(() => { wait.push(store.findRecord('test', 'david')); - wait.push(store.findRecord('test', 'igor').catch(e => { - igorDidReject = true; - assert.equal(e.message, `Expected: '' to be present in the adapter provided payload, but it was not found.`); - })); + wait.push( + store.findRecord('test', 'igor').catch(e => { + igorDidReject = true; + assert.equal( + e.message, + `Expected: '' to be present in the adapter provided payload, but it was not found.` + ); + }) + ); }); }, /expected to find records with the following ids in the adapter response but they were missing/); return EmberPromise.all(wait).then(() => { - assert.ok(igorDidReject, 'expected rejection that could not be found in the payload, but no such rejection occured'); + assert.ok( + igorDidReject, + 'expected rejection that could not be found in the payload, but no such rejection occured' + ); }); }); @@ -949,7 +983,7 @@ test('store should not call shouldReloadRecord when the record is not in the sto assert.expect(1); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const TestAdapter = DS.Adapter.extend({ @@ -960,12 +994,12 @@ test('store should not call shouldReloadRecord when the record is not in the sto findRecord() { assert.ok(true, 'find is always called when the record is not in the store'); return { data: { id: 1, type: 'person' } }; - } + }, }); let store = createStore({ adapter: TestAdapter, - person: Person + person: Person, }); return run(() => store.findRecord('person', 1)); @@ -975,7 +1009,7 @@ test('store should not reload record when shouldReloadRecord returns false', fun assert.expect(1); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const TestAdapter = DS.Adapter.extend({ @@ -988,20 +1022,20 @@ test('store should not reload record when shouldReloadRecord returns false', fun }, findRecord() { assert.ok(false, 'find should not be called when shouldReloadRecord returns false'); - } + }, }); store = createStore({ adapter: TestAdapter, - person: Person + person: Person, }); return run(() => { store.push({ data: { type: 'person', - id: '1' - } + id: '1', + }, }); return store.findRecord('person', 1); @@ -1012,7 +1046,7 @@ test('store should reload record when shouldReloadRecord returns true', function assert.expect(3); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const TestAdapter = DS.Adapter.extend({ @@ -1023,20 +1057,20 @@ test('store should reload record when shouldReloadRecord returns true', function findRecord() { assert.ok(true, 'find should not be called when shouldReloadRecord returns false'); return { data: { id: 1, type: 'person', attributes: { name: 'Tom' } } }; - } + }, }); store = createStore({ adapter: TestAdapter, - person: Person + person: Person, }); return run(() => { store.push({ data: { type: 'person', - id: '1' - } + id: '1', + }, }); return store.findRecord('person', 1).then(record => { @@ -1049,7 +1083,7 @@ test('store should not call shouldBackgroundReloadRecord when the store is alrea assert.expect(2); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const TestAdapter = DS.Adapter.extend({ @@ -1057,25 +1091,28 @@ test('store should not call shouldBackgroundReloadRecord when the store is alrea return true; }, shouldBackgroundReloadRecord(store, type, id, snapshot) { - assert.ok(false, 'shouldBackgroundReloadRecord is not called when shouldReloadRecord returns true'); + assert.ok( + false, + 'shouldBackgroundReloadRecord is not called when shouldReloadRecord returns true' + ); }, findRecord() { assert.ok(true, 'find should be called'); return { data: { id: 1, type: 'person', attributes: { name: 'Tom' } } }; - } + }, }); store = createStore({ adapter: TestAdapter, - person: Person + person: Person, }); return run(() => { store.push({ data: { type: 'person', - id: '1' - } + id: '1', + }, }); return store.findRecord('person', 1).then(record => { @@ -1088,31 +1125,34 @@ test('store should not reload a record when `shouldBackgroundReloadRecord` is fa assert.expect(2); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const TestAdapter = DS.Adapter.extend({ shouldBackgroundReloadRecord(store, type, id, snapshot) { - assert.ok(true, 'shouldBackgroundReloadRecord is called when record is loaded form the cache'); + assert.ok( + true, + 'shouldBackgroundReloadRecord is called when record is loaded form the cache' + ); return false; }, findRecord() { assert.ok(false, 'find should not be called'); return { data: { id: 1, type: 'person', attributes: { name: 'Tom' } } }; - } + }, }); store = createStore({ adapter: TestAdapter, - person: Person + person: Person, }); return run(() => { store.push({ data: { type: 'person', - id: '1' - } + id: '1', + }, }); return store.findRecord('person', 1).then(record => { @@ -1121,36 +1161,38 @@ test('store should not reload a record when `shouldBackgroundReloadRecord` is fa }); }); - test('store should reload the record in the background when `shouldBackgroundReloadRecord` is true', function(assert) { assert.expect(4); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const TestAdapter = DS.Adapter.extend({ shouldBackgroundReloadRecord(store, type, id, snapshot) { - assert.ok(true, 'shouldBackgroundReloadRecord is called when record is loaded form the cache'); + assert.ok( + true, + 'shouldBackgroundReloadRecord is called when record is loaded form the cache' + ); return true; }, findRecord() { assert.ok(true, 'find should not be called'); return { data: { id: 1, type: 'person', attributes: { name: 'Tom' } } }; - } + }, }); store = createStore({ adapter: TestAdapter, - person: Person + person: Person, }); let done = run(() => { store.push({ data: { type: 'person', - id: '1' - } + id: '1', + }, }); return store.findRecord('person', 1).then(record => { @@ -1167,7 +1209,7 @@ test('store should not reload record array when shouldReloadAll returns false', assert.expect(1); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const TestAdapter = DS.Adapter.extend({ @@ -1180,12 +1222,12 @@ test('store should not reload record array when shouldReloadAll returns false', }, findAll() { assert.ok(false, 'findAll should not be called when shouldReloadAll returns false'); - } + }, }); store = createStore({ adapter: TestAdapter, - person: Person + person: Person, }); return run(() => store.findAll('person')); @@ -1195,7 +1237,7 @@ test('store should reload all records when shouldReloadAll returns true', functi assert.expect(3); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const TestAdapter = DS.Adapter.extend({ @@ -1205,13 +1247,13 @@ test('store should reload all records when shouldReloadAll returns true', functi }, findAll() { assert.ok(true, 'findAll should be called when shouldReloadAll returns true'); - return { data: [{ id: 1, type: 'person', attributes: { name: 'Tom' } }]}; - } + return { data: [{ id: 1, type: 'person', attributes: { name: 'Tom' } }] }; + }, }); store = createStore({ adapter: TestAdapter, - person: Person + person: Person, }); return run(() => { @@ -1225,7 +1267,7 @@ test('store should not call shouldBackgroundReloadAll when the store is already assert.expect(2); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const TestAdapter = DS.Adapter.extend({ @@ -1233,17 +1275,20 @@ test('store should not call shouldBackgroundReloadAll when the store is already return true; }, shouldBackgroundReloadAll(store, type, id, snapshot) { - assert.ok(false, 'shouldBackgroundReloadRecord is not called when shouldReloadRecord returns true'); + assert.ok( + false, + 'shouldBackgroundReloadRecord is not called when shouldReloadRecord returns true' + ); }, findAll() { assert.ok(true, 'find should be called'); - return { data: [{ id: 1, type: 'person', attributes: { name: 'Tom' } }]}; - } + return { data: [{ id: 1, type: 'person', attributes: { name: 'Tom' } }] }; + }, }); store = createStore({ adapter: TestAdapter, - person: Person + person: Person, }); return run(() => { @@ -1257,7 +1302,7 @@ test('store should not reload all records when `shouldBackgroundReloadAll` is fa assert.expect(3); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const TestAdapter = DS.Adapter.extend({ @@ -1272,12 +1317,12 @@ test('store should not reload all records when `shouldBackgroundReloadAll` is fa findAll() { assert.ok(false, 'findAll should not be called'); return { data: [{ id: 1, type: 'person', attributes: { name: 'Tom' } }] }; - } + }, }); store = createStore({ adapter: TestAdapter, - person: Person + person: Person, }); return run(() => { @@ -1287,12 +1332,11 @@ test('store should not reload all records when `shouldBackgroundReloadAll` is fa }); }); - test('store should reload all records in the background when `shouldBackgroundReloadAll` is true', function(assert) { assert.expect(5); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); const TestAdapter = DS.Adapter.extend({ @@ -1307,12 +1351,12 @@ test('store should reload all records in the background when `shouldBackgroundRe findAll() { assert.ok(true, 'find should not be called'); return { data: [{ id: 1, type: 'person', attributes: { name: 'Tom' } }] }; - } + }, }); store = createStore({ adapter: TestAdapter, - person: Person + person: Person, }); let done = run(() => { @@ -1330,11 +1374,11 @@ testInDebug('store should assert of the user tries to call store.filter', functi assert.expect(1); const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); store = createStore({ - person: Person + person: Person, }); assert.expectAssertion(() => { @@ -1342,13 +1386,13 @@ testInDebug('store should assert of the user tries to call store.filter', functi }, /The filter API has been moved to a plugin/); }); -testInDebug("Calling adapterFor with a model class should assert", function(assert) { +testInDebug('Calling adapterFor with a model class should assert', function(assert) { const Person = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); store = createStore({ - person: Person + person: Person, }); assert.expectAssertion(() => { diff --git a/tests/unit/store/asserts-test.js b/tests/unit/store/asserts-test.js index 279bd62dbc2..4263f541fc2 100644 --- a/tests/unit/store/asserts-test.js +++ b/tests/unit/store/asserts-test.js @@ -19,14 +19,14 @@ const MODEL_NAME_METHODS = [ '_modelFactoryFor', 'normalize', 'adapterFor', - 'serializerFor' + 'serializerFor', ]; testInDebug('Calling Store methods with no modelName asserts', function(assert) { assert.expect(MODEL_NAME_METHODS.length); let store = createStore(); - MODEL_NAME_METHODS.forEach(methodName =>{ + MODEL_NAME_METHODS.forEach(methodName => { assert.expectAssertion(() => { store[methodName](null); }, new RegExp(`You need to pass a model name to the store's ${methodName} method`)); diff --git a/tests/unit/store/create-record-test.js b/tests/unit/store/create-record-test.js index 1c87e24d29f..e2bd5e79459 100644 --- a/tests/unit/store/create-record-test.js +++ b/tests/unit/store/create-record-test.js @@ -12,40 +12,40 @@ let store, Record, Storage; module('unit/store/createRecord - Store creating records', { beforeEach() { Record = DS.Model.extend({ - title: DS.attr('string') + title: DS.attr('string'), }); Storage = DS.Model.extend({ name: DS.attr('name'), - records: DS.hasMany('record', { async: false }) + records: DS.hasMany('record', { async: false }), }); store = createStore({ adapter: DS.Adapter.extend(), record: Record, - storage: Storage + storage: Storage, }); - } + }, }); test(`doesn't modify passed in properties hash`, function(assert) { const Post = Model.extend({ title: attr(), author: belongsTo('author', { async: false, inverse: 'post' }), - comments: hasMany('comment', { async: false, inverse: 'post' }) + comments: hasMany('comment', { async: false, inverse: 'post' }), }); const Comment = Model.extend({ text: attr(), - post: belongsTo('post', { async: false, inverse: 'comments' }) + post: belongsTo('post', { async: false, inverse: 'comments' }), }); const Author = Model.extend({ name: attr(), - post: belongsTo('post', { async: false, inverse: 'author' }) + post: belongsTo('post', { async: false, inverse: 'author' }), }); let env = setupStore({ post: Post, comment: Comment, - author: Author + author: Author, }); let store = env.store; let comment, author; @@ -56,18 +56,18 @@ test(`doesn't modify passed in properties hash`, function(assert) { type: 'comment', id: '1', attributes: { - text: 'Hello darkness my old friend' - } - } + text: 'Hello darkness my old friend', + }, + }, }); author = store.push({ data: { type: 'author', id: '1', attributes: { - name: '@runspired' - } - } + name: '@runspired', + }, + }, }); }); @@ -75,13 +75,13 @@ test(`doesn't modify passed in properties hash`, function(assert) { title: 'My Post', randomProp: 'An unknown prop', comments: [comment], - author + author, }; let propertiesClone = { title: 'My Post', randomProp: 'An unknown prop', comments: [comment], - author + author, }; store.createRecord('post', properties); @@ -99,17 +99,17 @@ test('allow passing relationships as well as attributes', function(assert) { type: 'record', id: '1', attributes: { - title: "it's a beautiful day" - } + title: "it's a beautiful day", + }, }, { type: 'record', id: '2', attributes: { - title: "it's a beautiful day" - } - } - ] + title: "it's a beautiful day", + }, + }, + ], }); records = store.peekAll('record'); @@ -117,19 +117,27 @@ test('allow passing relationships as well as attributes', function(assert) { }); assert.equal(storage.get('name'), 'Great store', 'The attribute is well defined'); - assert.equal(storage.get('records').findBy('id', '1'), A(records).findBy('id', '1'), 'Defined relationships are allowed in createRecord'); - assert.equal(storage.get('records').findBy('id', '2'), A(records).findBy('id', '2'), 'Defined relationships are allowed in createRecord'); + assert.equal( + storage.get('records').findBy('id', '1'), + A(records).findBy('id', '1'), + 'Defined relationships are allowed in createRecord' + ); + assert.equal( + storage.get('records').findBy('id', '2'), + A(records).findBy('id', '2'), + 'Defined relationships are allowed in createRecord' + ); }); module('unit/store/createRecord - Store with models by dash', { beforeEach() { let env = setupStore({ someThing: DS.Model.extend({ - foo: DS.attr('string') - }) + foo: DS.attr('string'), + }), }); store = env.store; - } + }, }); test('creating a record by dasherize string finds the model', function(assert) { diff --git a/tests/unit/store/finders-test.js b/tests/unit/store/finders-test.js index 9ee8ee9b859..58d167c207f 100644 --- a/tests/unit/store/finders-test.js +++ b/tests/unit/store/finders-test.js @@ -12,11 +12,11 @@ module('unit/store/finders', { updatedAt: DS.attr('string'), name: DS.attr('string'), firstName: DS.attr('string'), - lastName: DS.attr('string') + lastName: DS.attr('string'), }); this.Dog = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); this.env = setupStore({ person: this.Person, dog: this.Dog }); @@ -26,7 +26,7 @@ module('unit/store/finders', { afterEach() { run(this.env.container, 'destroy'); - } + }, }); test('findRecord does not load a serializer until the adapter promise resolves', function(assert) { @@ -34,13 +34,16 @@ test('findRecord does not load a serializer until the adapter promise resolves', let deferedFind = defer(); - this.env.registry.register('adapter:person', DS.Adapter.extend({ - findRecord: () => deferedFind.promise - })); + this.env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findRecord: () => deferedFind.promise, + }) + ); let serializerLoaded = false; let serializerFor = this.store.serializerFor; - this.store.serializerFor = (modelName) => { + this.store.serializerFor = modelName => { if (modelName === 'person') { serializerLoaded = true; } @@ -51,7 +54,9 @@ test('findRecord does not load a serializer until the adapter promise resolves', assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); return run(() => { - deferedFind.resolve({ data: { id: 1, type: 'person', attributes: { name: 'John Churchill' } } }); + deferedFind.resolve({ + data: { id: 1, type: 'person', attributes: { name: 'John Churchill' } }, + }); return storePromise.then(() => { assert.equal(true, serializerLoaded, 'serializer is loaded'); }); @@ -63,13 +68,16 @@ test('findMany does not load a serializer until the adapter promise resolves', f let deferedFind = defer(); - this.env.registry.register('adapter:person', DS.Adapter.extend({ - findMany: () => deferedFind.promise - })); + this.env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findMany: () => deferedFind.promise, + }) + ); let serializerLoaded = false; let serializerFor = this.store.serializerFor; - this.store.serializerFor = (modelName) => { + this.store.serializerFor = modelName => { if (modelName === 'person') { serializerLoaded = true; } @@ -77,13 +85,18 @@ test('findMany does not load a serializer until the adapter promise resolves', f }; let storePromise = run(() => { - this.store.findRecord('person', 1) + this.store.findRecord('person', 1); return this.store.findRecord('person', 2); }); assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); return run(() => { - deferedFind.resolve({ data: [{ id: 1, type: 'person', attributes: { name: 'John Churchill' } }, { id: 2, type: 'person', attributes: { name: 'Louis Joseph' } }] }); + deferedFind.resolve({ + data: [ + { id: 1, type: 'person', attributes: { name: 'John Churchill' } }, + { id: 2, type: 'person', attributes: { name: 'Louis Joseph' } }, + ], + }); return storePromise.then(() => { assert.equal(true, serializerLoaded, 'serializer is loaded'); }); @@ -95,17 +108,20 @@ test('findHasMany does not load a serializer until the adapter promise resolves' let deferedFind = defer(); - this.env.registry.register('adapter:person', DS.Adapter.extend({ - findHasMany: () => deferedFind.promise - })); + this.env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findHasMany: () => deferedFind.promise, + }) + ); this.Person.reopen({ - dogs: DS.hasMany('dog', { async: true }) + dogs: DS.hasMany('dog', { async: true }), }); let serializerLoaded = false; let serializerFor = this.store.serializerFor; - this.store.serializerFor = (modelName) => { + this.store.serializerFor = modelName => { if (modelName === 'dog') { serializerLoaded = true; } @@ -118,16 +134,16 @@ test('findHasMany does not load a serializer until the adapter promise resolves' type: 'person', id: '1', attributes: { - name: 'John Churchill' + name: 'John Churchill', }, relationships: { dogs: { links: { - related: 'http://exmaple.com/person/1/dogs' - } - } - } - } + related: 'http://exmaple.com/person/1/dogs', + }, + }, + }, + }, }); return this.store.peekRecord('person', 1).get('dogs'); @@ -135,7 +151,12 @@ test('findHasMany does not load a serializer until the adapter promise resolves' assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); return run(() => { - deferedFind.resolve({ data: [{ id: 1, type: 'dog', attributes: { name: 'Scooby' } }, { id: 2, type: 'dog', attributes: { name: 'Scrappy' } }] }); + deferedFind.resolve({ + data: [ + { id: 1, type: 'dog', attributes: { name: 'Scooby' } }, + { id: 2, type: 'dog', attributes: { name: 'Scrappy' } }, + ], + }); return storePromise.then(() => { assert.equal(true, serializerLoaded, 'serializer is loaded'); }); @@ -147,17 +168,20 @@ test('findBelongsTo does not load a serializer until the adapter promise resolve let deferedFind = defer(); - this.env.registry.register('adapter:person', DS.Adapter.extend({ - findBelongsTo: () => deferedFind.promise - })); + this.env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findBelongsTo: () => deferedFind.promise, + }) + ); this.Person.reopen({ - favoriteDog: DS.belongsTo('dog', { async: true }) + favoriteDog: DS.belongsTo('dog', { async: true }), }); let serializerLoaded = false; let serializerFor = this.store.serializerFor; - this.store.serializerFor = (modelName) => { + this.store.serializerFor = modelName => { if (modelName === 'dog') { serializerLoaded = true; } @@ -170,16 +194,16 @@ test('findBelongsTo does not load a serializer until the adapter promise resolve type: 'person', id: '1', attributes: { - name: 'John Churchill' + name: 'John Churchill', }, relationships: { favoriteDog: { links: { - related: 'http://exmaple.com/person/1/favorite-dog' - } - } - } - } + related: 'http://exmaple.com/person/1/favorite-dog', + }, + }, + }, + }, }); return this.store.peekRecord('person', 1).get('favoriteDog'); @@ -199,13 +223,16 @@ test('findAll does not load a serializer until the adapter promise resolves', fu let deferedFind = defer(); - this.env.registry.register('adapter:person', DS.Adapter.extend({ - findAll: () => deferedFind.promise - })); + this.env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + findAll: () => deferedFind.promise, + }) + ); let serializerLoaded = false; let serializerFor = this.store.serializerFor; - this.store.serializerFor = (modelName) => { + this.store.serializerFor = modelName => { if (modelName === 'person') { serializerLoaded = true; } @@ -216,7 +243,9 @@ test('findAll does not load a serializer until the adapter promise resolves', fu assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); return run(() => { - deferedFind.resolve({ data: [{ id: 1, type: 'person', attributes: { name: 'John Churchill' } }] }); + deferedFind.resolve({ + data: [{ id: 1, type: 'person', attributes: { name: 'John Churchill' } }], + }); return storePromise.then(() => { assert.equal(true, serializerLoaded, 'serializer is loaded'); }); @@ -228,13 +257,16 @@ test('query does not load a serializer until the adapter promise resolves', func let deferedFind = defer(); - this.env.registry.register('adapter:person', DS.Adapter.extend({ - query: () => deferedFind.promise - })); + this.env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + query: () => deferedFind.promise, + }) + ); let serializerLoaded = false; let serializerFor = this.store.serializerFor; - this.store.serializerFor = (modelName) => { + this.store.serializerFor = modelName => { if (modelName === 'person') { serializerLoaded = true; } @@ -245,7 +277,9 @@ test('query does not load a serializer until the adapter promise resolves', func assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); return run(() => { - deferedFind.resolve({ data: [{ id: 1, type: 'person', attributes: { name: 'John Churchill' } }] }); + deferedFind.resolve({ + data: [{ id: 1, type: 'person', attributes: { name: 'John Churchill' } }], + }); return storePromise.then(() => { assert.equal(true, serializerLoaded, 'serializer is loaded'); }); @@ -257,27 +291,33 @@ test('queryRecord does not load a serializer until the adapter promise resolves' let deferedFind = defer(); - this.env.registry.register('adapter:person', DS.Adapter.extend({ - queryRecord: () => deferedFind.promise - })); + this.env.registry.register( + 'adapter:person', + DS.Adapter.extend({ + queryRecord: () => deferedFind.promise, + }) + ); let serializerLoaded = false; let serializerFor = this.store.serializerFor; - this.store.serializerFor = (modelName) => { + this.store.serializerFor = modelName => { if (modelName === 'person') { serializerLoaded = true; } return serializerFor.call(this.store, modelName); }; - let storePromise = run(() => this.store.queryRecord('person', { first_duke_of_marlborough: true })); + let storePromise = run(() => + this.store.queryRecord('person', { first_duke_of_marlborough: true }) + ); assert.equal(false, serializerLoaded, 'serializer is not eagerly loaded'); return run(() => { - deferedFind.resolve({ data: { id: 1, type: 'person', attributes: { name: 'John Churchill' } } }); + deferedFind.resolve({ + data: { id: 1, type: 'person', attributes: { name: 'John Churchill' } }, + }); return storePromise.then(() => { assert.equal(true, serializerLoaded, 'serializer is loaded'); }); }); }); - diff --git a/tests/unit/store/has-model-for-test.js b/tests/unit/store/has-model-for-test.js index 0fa53f5a2cd..47f648a2ba3 100644 --- a/tests/unit/store/has-model-for-test.js +++ b/tests/unit/store/has-model-for-test.js @@ -8,13 +8,13 @@ module('unit/store/has-model-For', { beforeEach() { store = createStore({ adapter: DS.Adapter.extend(), - 'one-foo': DS.Model.extend({}), - 'two-foo': DS.Model.extend({}) + 'one-foo': DS.Model.extend({}), + 'two-foo': DS.Model.extend({}), }); - } + }, }); test(`hasModelFor correctly normalizes`, function(assert) { assert.equal(store._hasModelFor('oneFoo'), true); - assert.equal(store._hasModelFor('twoFoo'). true); + assert.equal(store._hasModelFor('twoFoo').true); }); diff --git a/tests/unit/store/has-record-for-id-test.js b/tests/unit/store/has-record-for-id-test.js index 3aab6feb164..4fb93fc8e15 100644 --- a/tests/unit/store/has-record-for-id-test.js +++ b/tests/unit/store/has-record-for-id-test.js @@ -10,55 +10,53 @@ const { attr, hasMany, belongsTo } = DS; module('unit/store/hasRecordForId - Store hasRecordForId', { beforeEach() { - Person = DS.Model.extend({ firstName: attr('string'), lastName: attr('string'), - phoneNumbers: hasMany('phone-number', { async: false }) + phoneNumbers: hasMany('phone-number', { async: false }), }); PhoneNumber = DS.Model.extend({ number: attr('string'), - person: belongsTo('person', { async: false }) + person: belongsTo('person', { async: false }), }); env = setupStore({ person: Person, - 'phone-number': PhoneNumber + 'phone-number': PhoneNumber, }); store = env.store; - }, afterEach() { run(store, 'destroy'); - } + }, }); test('hasRecordForId should return false for records in the empty state ', function(assert) { - run(() => { store.push({ data: { type: 'person', id: '1', attributes: { - firstName: "Yehuda", - lastName: "Katz" + firstName: 'Yehuda', + lastName: 'Katz', }, relationships: { phoneNumbers: { - data: [ - { type: 'phone-number', id: '1' } - ] - } - } - } + data: [{ type: 'phone-number', id: '1' }], + }, + }, + }, }); - assert.equal(false, store.hasRecordForId('phone-number', 1), 'hasRecordForId only returns true for loaded records'); - + assert.equal( + false, + store.hasRecordForId('phone-number', 1), + 'hasRecordForId only returns true for loaded records' + ); }); }); @@ -69,19 +67,21 @@ test('hasRecordForId should return true for records in the loaded state ', funct type: 'person', id: '1', attributes: { - firstName: "Yehuda", - lastName: "Katz" + firstName: 'Yehuda', + lastName: 'Katz', }, relationships: { phoneNumbers: { - data: [ - { type: 'phone-number', id: '1' } - ] - } - } - } + data: [{ type: 'phone-number', id: '1' }], + }, + }, + }, }); - assert.equal(true, store.hasRecordForId('person', 1), 'hasRecordForId returns true for records loaded into the store'); + assert.equal( + true, + store.hasRecordForId('person', 1), + 'hasRecordForId returns true for records loaded into the store' + ); }); }); diff --git a/tests/unit/store/lookup-test.js b/tests/unit/store/lookup-test.js index 86a210d279e..ac96f6ff363 100644 --- a/tests/unit/store/lookup-test.js +++ b/tests/unit/store/lookup-test.js @@ -13,7 +13,7 @@ function resetStore() { } env = setupStore({ adapter: '-rest', - person: Person + person: Person, }); env.registry.unregister('adapter:application'); @@ -54,29 +54,29 @@ module('unit/store/lookup - Managed Instance lookups', { afterEach() { run(store, 'destroy'); - } + }, }); -test('when the adapter does not exist for a type, the fallback is returned', (assert) => { +test('when the adapter does not exist for a type, the fallback is returned', assert => { let personAdapter = lookupAdapter('person'); assert.strictEqual(personAdapter, applicationAdapter); }); -test('when the adapter for a type exists, returns that instead of the fallback', (assert) => { +test('when the adapter for a type exists, returns that instead of the fallback', assert => { registerAdapter('person', DS.Adapter.extend()); let personAdapter = lookupAdapter('person'); assert.ok(personAdapter !== applicationAdapter); }); -test('when the serializer does not exist for a type, the fallback is returned', (assert) => { +test('when the serializer does not exist for a type, the fallback is returned', assert => { let personSerializer = lookupSerializer('person'); assert.strictEqual(personSerializer, applicationSerializer); }); -test('when the serializer does exist for a type, the serializer is returned', (assert) => { +test('when the serializer does exist for a type, the serializer is returned', assert => { registerSerializer('person', DS.Serializer.extend()); let personSerializer = lookupSerializer('person'); @@ -84,7 +84,7 @@ test('when the serializer does exist for a type, the serializer is returned', (a assert.ok(personSerializer !== applicationSerializer); }); -test('adapter lookup order', (assert) => { +test('adapter lookup order', assert => { assert.expect(3); resetStore(); @@ -97,17 +97,24 @@ test('adapter lookup order', (assert) => { registerAdapter('application', DS.RESTSerializer.extend()); personAdapter = lookupAdapter('person'); - assert.strictEqual(personAdapter, lookupAdapter('application'), 'looks up application adapter before RESTAdapter if it exists'); + assert.strictEqual( + personAdapter, + lookupAdapter('application'), + 'looks up application adapter before RESTAdapter if it exists' + ); resetStore(); registerAdapter('application', DS.RESTSerializer.extend()); registerAdapter('person', DS.RESTSerializer.extend({ customThingy: true })); - assert.ok(lookupAdapter('person').get('customThingy'), 'looks up type serializer before application'); + assert.ok( + lookupAdapter('person').get('customThingy'), + 'looks up type serializer before application' + ); }); -test('serializer lookup order', (assert) => { +test('serializer lookup order', assert => { resetStore(); let personSerializer = lookupSerializer('person'); @@ -118,23 +125,40 @@ test('serializer lookup order', (assert) => { registerSerializer('application', DS.RESTSerializer.extend()); personSerializer = lookupSerializer('person'); - assert.strictEqual(personSerializer, lookupSerializer('application'), 'looks up application before default'); + assert.strictEqual( + personSerializer, + lookupSerializer('application'), + 'looks up application before default' + ); resetStore(); - registerAdapter('person', DS.Adapter.extend({ - defaultSerializer: '-rest' - })); + registerAdapter( + 'person', + DS.Adapter.extend({ + defaultSerializer: '-rest', + }) + ); personSerializer = lookupSerializer('person'); - assert.strictEqual(personSerializer, lookupSerializer('-rest'), 'uses defaultSerializer on adapterFor("model") if application not defined'); + assert.strictEqual( + personSerializer, + lookupSerializer('-rest'), + 'uses defaultSerializer on adapterFor("model") if application not defined' + ); resetStore(); - registerAdapter('person', DS.Adapter.extend({ - defaultSerializer: '-rest' - })); + registerAdapter( + 'person', + DS.Adapter.extend({ + defaultSerializer: '-rest', + }) + ); registerSerializer('application', DS.RESTSerializer.extend()); registerSerializer('person', DS.JSONSerializer.extend({ customThingy: true })); personSerializer = lookupSerializer('person'); - assert.ok(personSerializer.get('customThingy'), 'uses the person serializer before any fallbacks if it is defined'); + assert.ok( + personSerializer.get('customThingy'), + 'uses the person serializer before any fallbacks if it is defined' + ); }); diff --git a/tests/unit/store/model-for-test.js b/tests/unit/store/model-for-test.js index 0c74eeaeb2c..dbcde0aa566 100644 --- a/tests/unit/store/model-for-test.js +++ b/tests/unit/store/model-for-test.js @@ -12,7 +12,7 @@ module('unit/store/model_for - DS.Store#modelFor', { beforeEach() { env = setupStore({ blogPost: DS.Model.extend(), - 'blog.post': DS.Model.extend() + 'blog.post': DS.Model.extend(), }); store = env.store; container = env.container; @@ -24,21 +24,29 @@ module('unit/store/model_for - DS.Store#modelFor', { container.destroy(); store.destroy(); }); - } + }, }); test('when fetching factory from string, sets a normalized key as modelName', function(assert) { env.replaceContainerNormalize(key => dasherize(camelize(key))); assert.equal(registry.normalize('some.post'), 'some-post', 'precond - container camelizes'); - assert.equal(store.modelFor('blog.post').modelName, 'blog.post', 'modelName is normalized to dasherized'); + assert.equal( + store.modelFor('blog.post').modelName, + 'blog.post', + 'modelName is normalized to dasherized' + ); }); test('when fetching factory from string and dashing normalizer, sets a normalized key as modelName', function(assert) { env.replaceContainerNormalize(key => dasherize(camelize(key))); assert.equal(registry.normalize('some.post'), 'some-post', 'precond - container dasherizes'); - assert.equal(store.modelFor("blog.post").modelName, "blog.post", "modelName is normalized to dasherized"); + assert.equal( + store.modelFor('blog.post').modelName, + 'blog.post', + 'modelName is normalized to dasherized' + ); }); test(`when fetching something that doesn't exist, throws error`, function(assert) { diff --git a/tests/unit/store/peek-record-test.js b/tests/unit/store/peek-record-test.js index 4e92782bdd6..4c8fb61bc03 100644 --- a/tests/unit/store/peek-record-test.js +++ b/tests/unit/store/peek-record-test.js @@ -14,7 +14,7 @@ module('unit/store/peekRecord - Store peekRecord', { Person = DS.Model.extend(); env = setupStore({ - person: Person + person: Person, }); store = env.store; @@ -22,7 +22,7 @@ module('unit/store/peekRecord - Store peekRecord', { afterEach() { run(store, 'destroy'); - } + }, }); test('peekRecord should return the record if it is in the store ', function(assert) { @@ -30,16 +30,24 @@ test('peekRecord should return the record if it is in the store ', function(asse let person = store.push({ data: { type: 'person', - id: '1' - } + id: '1', + }, }); - assert.equal(person, store.peekRecord('person', 1), 'peekRecord only return the corresponding record in the store'); + assert.equal( + person, + store.peekRecord('person', 1), + 'peekRecord only return the corresponding record in the store' + ); }); }); test('peekRecord should return null if the record is not in the store ', function(assert) { run(() => { - assert.equal(null, store.peekRecord('person', 1), 'peekRecord returns null if the corresponding record is not in the store'); + assert.equal( + null, + store.peekRecord('person', 1), + 'peekRecord returns null if the corresponding record is not in the store' + ); }); }); @@ -51,7 +59,9 @@ testInDebug('peekRecord should assert if not passed both model name and id', fun }); }); -testInDebug('peekRecord should assert if passed a model class instead of model name', function(assert) { +testInDebug('peekRecord should assert if passed a model class instead of model name', function( + assert +) { run(() => { assert.expectAssertion(() => { let modelClass = Ember.Object.extend(); diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index 22291b6e4d2..dfcd91a2340 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -17,22 +17,22 @@ module('unit/store/push - DS.Store#push', { Person = DS.Model.extend({ firstName: attr('string'), lastName: attr('string'), - phoneNumbers: hasMany('phone-number', { async: false }) + phoneNumbers: hasMany('phone-number', { async: false }), }); PhoneNumber = DS.Model.extend({ number: attr('string'), - person: belongsTo('person', { async: false }) + person: belongsTo('person', { async: false }), }); Post = DS.Model.extend({ - postTitle: attr('string') + postTitle: attr('string'), }); env = setupStore({ post: Post, person: Person, - "phone-number": PhoneNumber + 'phone-number': PhoneNumber, }); store = env.store; @@ -42,7 +42,7 @@ module('unit/store/push - DS.Store#push', { afterEach() { run(store, 'destroy'); - } + }, }); test('Changed attributes are reset when matching data is pushed', function(assert) { @@ -52,9 +52,9 @@ test('Changed attributes are reset when matching data is pushed', function(asser type: 'person', id: 1, attributes: { - firstName: 'original first name' - } - } + firstName: 'original first name', + }, + }, }); }); @@ -66,7 +66,10 @@ test('Changed attributes are reset when matching data is pushed', function(asser assert.equal(person.get('firstName'), 'updated first name'); assert.strictEqual(person.get('lastName'), undefined); assert.equal(person.get('currentState.stateName'), 'root.loaded.updated.uncommitted'); - assert.deepEqual(person.changedAttributes().firstName, ['original first name', 'updated first name']); + assert.deepEqual(person.changedAttributes().firstName, [ + 'original first name', + 'updated first name', + ]); run(() => { store.push({ @@ -74,9 +77,9 @@ test('Changed attributes are reset when matching data is pushed', function(asser type: 'person', id: 1, attributes: { - firstName: 'updated first name' - } - } + firstName: 'updated first name', + }, + }, }); }); @@ -96,17 +99,21 @@ test('Calling push with a normalized hash returns a record', function(assert) { id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' - } - } + lastName: 'Katz', + }, + }, }); return store.findRecord('person', 'wat').then(foundPerson => { - assert.equal(foundPerson, person, 'record returned via load() is the same as the record returned from findRecord()'); + assert.equal( + foundPerson, + person, + 'record returned via load() is the same as the record returned from findRecord()' + ); assert.deepEqual(foundPerson.getProperties('id', 'firstName', 'lastName'), { id: 'wat', firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }); }); }); @@ -126,16 +133,16 @@ test('Supplying a model class for `push` is the same as supplying a string', fun id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' - } - } + lastName: 'Katz', + }, + }, }); return store.findRecord('programmer', 'wat').then(foundProgrammer => { assert.deepEqual(foundProgrammer.getProperties('id', 'firstName', 'lastName'), { id: 'wat', firstName: 'Yehuda', - lastName: 'Katz' + lastName: 'Katz', }); }); }); @@ -153,7 +160,7 @@ test(`Calling push triggers 'didLoad' even if the record hasn't been requested f } catch (e) { reject(e); } - } + }, }); }); @@ -164,9 +171,9 @@ test(`Calling push triggers 'didLoad' even if the record hasn't been requested f id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' - } - } + lastName: 'Katz', + }, + }, }); }); @@ -184,9 +191,9 @@ test('Calling push with partial records updates just those attributes', function id: 'wat', attributes: { firstName: 'Yehuda', - lastName: 'Katz' - } - } + lastName: 'Katz', + }, + }, }); let person = store.peekRecord('person', 'wat'); @@ -196,17 +203,21 @@ test('Calling push with partial records updates just those attributes', function type: 'person', id: 'wat', attributes: { - lastName: "Katz!" - } - } + lastName: 'Katz!', + }, + }, }); return store.findRecord('person', 'wat').then(foundPerson => { - assert.equal(foundPerson, person, 'record returned via load() is the same as the record returned from findRecord()'); + assert.equal( + foundPerson, + person, + 'record returned via load() is the same as the record returned from findRecord()' + ); assert.deepEqual(foundPerson.getProperties('id', 'firstName', 'lastName'), { id: 'wat', firstName: 'Yehuda', - lastName: "Katz!" + lastName: 'Katz!', }); }); }); @@ -223,15 +234,17 @@ test('Calling push on normalize allows partial updates with raw JSON', function( id: '1', attributes: { firstName: 'Robert', - lastName: 'Jackson' - } - } + lastName: 'Jackson', + }, + }, }); - store.push(store.normalize('person', { - id: '1', - firstName: "Jacquie" - })); + store.push( + store.normalize('person', { + id: '1', + firstName: 'Jacquie', + }) + ); }); assert.equal(person.get('firstName'), 'Jacquie', 'you can push raw JSON into the store'); @@ -242,10 +255,9 @@ test('Calling push with a normalized hash containing IDs of related records retu assert.expect(1); Person.reopen({ - phoneNumbers: - hasMany('phone-number', { - async: true - }) + phoneNumbers: hasMany('phone-number', { + async: true, + }), }); env.adapter.findRecord = function(store, type, id) { @@ -257,14 +269,14 @@ test('Calling push with a normalized hash containing IDs of related records retu attributes: { number: '5551212' }, relationships: { person: { - data: { id: 'wat', type: 'person' } - } - } - } + data: { id: 'wat', type: 'person' }, + }, + }, + }, }); } - if (id === "2") { + if (id === '2') { return resolve({ data: { id: 2, @@ -272,44 +284,49 @@ test('Calling push with a normalized hash containing IDs of related records retu attributes: { number: '5552121' }, relationships: { person: { - data: { id: 'wat', type: 'person' } - } - } - } + data: { id: 'wat', type: 'person' }, + }, + }, + }, }); } }; return run(() => { - let person = store.push(store.normalize('person', { - id: 'wat', - type: 'person', - attributes: { - 'first-name': 'John', - 'last-name': 'Smith' - }, - relationships: { - 'phone-numbers': { - data: [{ id: 1, type: 'phone-number' }, { id: 2, type: 'phone-number' }] - } - } - })); + let person = store.push( + store.normalize('person', { + id: 'wat', + type: 'person', + attributes: { + 'first-name': 'John', + 'last-name': 'Smith', + }, + relationships: { + 'phone-numbers': { + data: [{ id: 1, type: 'phone-number' }, { id: 2, type: 'phone-number' }], + }, + }, + }) + ); return person.get('phoneNumbers').then(phoneNumbers => { - assert.deepEqual(phoneNumbers.map(item => { - return item.getProperties('id', 'number', 'person'); - }), [ - { - id: '1', - number: '5551212', - person: person - }, - { - id: '2', - number: '5552121', - person: person - } - ]); + assert.deepEqual( + phoneNumbers.map(item => { + return item.getProperties('id', 'number', 'person'); + }), + [ + { + id: '1', + number: '5551212', + person: person, + }, + { + id: '2', + number: '5552121', + person: person, + }, + ] + ); }); }); }); @@ -317,10 +334,12 @@ test('Calling push with a normalized hash containing IDs of related records retu test('Calling pushPayload allows pushing raw JSON', function(assert) { run(() => { store.pushPayload('post', { - posts: [{ - id: '1', - postTitle: "Ember rocks" - }] + posts: [ + { + id: '1', + postTitle: 'Ember rocks', + }, + ], }); }); @@ -330,10 +349,12 @@ test('Calling pushPayload allows pushing raw JSON', function(assert) { run(() => { store.pushPayload('post', { - posts: [{ - id: '1', - postTitle: 'Ember rocks (updated)' - }] + posts: [ + { + id: '1', + postTitle: 'Ember rocks (updated)', + }, + ], }); }); @@ -345,8 +366,8 @@ test('Calling pushPayload allows pushing singular payload properties', function( store.pushPayload('post', { post: { id: '1', - postTitle: 'Ember rocks' - } + postTitle: 'Ember rocks', + }, }); }); @@ -358,8 +379,8 @@ test('Calling pushPayload allows pushing singular payload properties', function( store.pushPayload('post', { post: { id: '1', - postTitle: 'Ember rocks (updated)' - } + postTitle: 'Ember rocks (updated)', + }, }); }); @@ -369,34 +390,40 @@ test('Calling pushPayload allows pushing singular payload properties', function( test(`Calling pushPayload should use the type's serializer for normalizing`, function(assert) { assert.expect(4); - env.registry.register('serializer:post', DS.RESTSerializer.extend({ - normalize() { - assert.ok(true, 'normalized is called on Post serializer'); - return this._super(...arguments); - } - })); - - env.registry.register('serializer:person', DS.RESTSerializer.extend({ - normalize() { - assert.ok(true, 'normalized is called on Person serializer'); - return this._super(...arguments); - } - })); + env.registry.register( + 'serializer:post', + DS.RESTSerializer.extend({ + normalize() { + assert.ok(true, 'normalized is called on Post serializer'); + return this._super(...arguments); + }, + }) + ); + + env.registry.register( + 'serializer:person', + DS.RESTSerializer.extend({ + normalize() { + assert.ok(true, 'normalized is called on Person serializer'); + return this._super(...arguments); + }, + }) + ); run(() => { store.pushPayload('post', { posts: [ { id: 1, - postTitle: 'Ember rocks' - } + postTitle: 'Ember rocks', + }, ], people: [ { id: 2, - firstName: 'Yehuda' - } - ] + firstName: 'Yehuda', + }, + ], }); }); @@ -412,16 +439,19 @@ test(`Calling pushPayload should use the type's serializer for normalizing`, fun test(`Calling pushPayload without a type uses application serializer's pushPayload method`, function(assert) { assert.expect(1); - env.registry.register('serializer:application', DS.RESTSerializer.extend({ - pushPayload() { - assert.ok(true, `pushPayload is called on Application serializer`); - return this._super(...arguments); - } - })); + env.registry.register( + 'serializer:application', + DS.RESTSerializer.extend({ + pushPayload() { + assert.ok(true, `pushPayload is called on Application serializer`); + return this._super(...arguments); + }, + }) + ); run(() => { store.pushPayload({ - posts: [{ id: '1', postTitle: 'Ember rocks' }] + posts: [{ id: '1', postTitle: 'Ember rocks' }], }); }); }); @@ -429,34 +459,40 @@ test(`Calling pushPayload without a type uses application serializer's pushPaylo test(`Calling pushPayload without a type should use a model's serializer when normalizing`, function(assert) { assert.expect(4); - env.registry.register('serializer:post', DS.RESTSerializer.extend({ - normalize() { - assert.ok(true, 'normalized is called on Post serializer'); - return this._super(...arguments); - } - })); - - env.registry.register('serializer:application', DS.RESTSerializer.extend({ - normalize() { - assert.ok(true, 'normalized is called on Application serializer'); - return this._super(...arguments); - } - })); + env.registry.register( + 'serializer:post', + DS.RESTSerializer.extend({ + normalize() { + assert.ok(true, 'normalized is called on Post serializer'); + return this._super(...arguments); + }, + }) + ); + + env.registry.register( + 'serializer:application', + DS.RESTSerializer.extend({ + normalize() { + assert.ok(true, 'normalized is called on Application serializer'); + return this._super(...arguments); + }, + }) + ); run(() => { store.pushPayload({ posts: [ { id: '1', - postTitle: 'Ember rocks' - } + postTitle: 'Ember rocks', + }, ], people: [ { id: '2', - firstName: 'Yehuda' - } - ] + firstName: 'Yehuda', + }, + ], }); }); @@ -474,11 +510,13 @@ test('Calling pushPayload allows partial updates with raw JSON', function(assert run(() => { store.pushPayload('person', { - people: [{ - id: '1', - firstName: 'Robert', - lastName: 'Jackson' - }] + people: [ + { + id: '1', + firstName: 'Robert', + lastName: 'Jackson', + }, + ], }); }); @@ -489,10 +527,12 @@ test('Calling pushPayload allows partial updates with raw JSON', function(assert run(() => { store.pushPayload('person', { - people: [{ - id: '1', - firstName: 'Jacquie' - }] + people: [ + { + id: '1', + firstName: 'Jacquie', + }, + ], }); }); @@ -501,18 +541,11 @@ test('Calling pushPayload allows partial updates with raw JSON', function(assert }); testInDebug('calling push without data argument as an object raises an error', function(assert) { - let invalidValues = [ - null, - 1, - 'string', - EmberObject.create(), - EmberObject.extend(), - true - ]; + let invalidValues = [null, 1, 'string', EmberObject.create(), EmberObject.extend(), true]; assert.expect(invalidValues.length); - invalidValues.forEach((invalidValue) => { + invalidValues.forEach(invalidValue => { assert.expectAssertion(() => { run(() => { store.push('person', invalidValue); @@ -521,57 +554,60 @@ testInDebug('calling push without data argument as an object raises an error', f }); }); -testInDebug('Calling push with a link for a non async relationship should warn if no data', function(assert) { - Person.reopen({ - phoneNumbers: hasMany('phone-number', { async: false }) - }); +testInDebug( + 'Calling push with a link for a non async relationship should warn if no data', + function(assert) { + Person.reopen({ + phoneNumbers: hasMany('phone-number', { async: false }), + }); - assert.expectWarning(() => { - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - relationships: { - phoneNumbers: { - links: { - related: '/api/people/1/phone-numbers' - } - } - } - } + assert.expectWarning(() => { + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + relationships: { + phoneNumbers: { + links: { + related: '/api/people/1/phone-numbers', + }, + }, + }, + }, + }); }); - }); - }, /You pushed a record of type 'person' with a relationship 'phoneNumbers' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload./); -}); + }, /You pushed a record of type 'person' with a relationship 'phoneNumbers' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload./); + } +); -testInDebug('Calling push with a link for a non async relationship should not warn when data is present', function(assert) { - Person.reopen({ - phoneNumbers: hasMany('phone-number', { async: false }) - }); +testInDebug( + 'Calling push with a link for a non async relationship should not warn when data is present', + function(assert) { + Person.reopen({ + phoneNumbers: hasMany('phone-number', { async: false }), + }); - assert.expectNoWarning(() => { - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - relationships: { - phoneNumbers: { - data: [ - { type: 'phone-number', id: '2' }, - { type: 'phone-number', id: '3' } - ], - links: { - related: '/api/people/1/phone-numbers' - } - } - } - } + assert.expectNoWarning(() => { + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + relationships: { + phoneNumbers: { + data: [{ type: 'phone-number', id: '2' }, { type: 'phone-number', id: '3' }], + links: { + related: '/api/people/1/phone-numbers', + }, + }, + }, + }, + }); }); }); - }); -}); + } +); testInDebug('Calling push with an unknown model name throws an assertion error', function(assert) { assert.expectAssertion(() => { @@ -579,8 +615,8 @@ testInDebug('Calling push with an unknown model name throws an assertion error', store.push({ data: { id: '1', - type: 'unknown' - } + type: 'unknown', + }, }); }); }, /You tried to push data with a type 'unknown' but no model could be found with that name/); @@ -588,22 +624,24 @@ testInDebug('Calling push with an unknown model name throws an assertion error', test('Calling push with a link containing an object', function(assert) { Person.reopen({ - phoneNumbers: hasMany('phone-number', { async: true }) + phoneNumbers: hasMany('phone-number', { async: true }), }); run(() => { - store.push(store.normalize('person', { - id: '1', - type: 'person', - attributes: { - 'first-name': 'Tan' - }, - relationships: { - 'phone-numbers': { - links: { related: '/api/people/1/phone-numbers' } - } - } - })); + store.push( + store.normalize('person', { + id: '1', + type: 'person', + attributes: { + 'first-name': 'Tan', + }, + relationships: { + 'phone-numbers': { + links: { related: '/api/people/1/phone-numbers' }, + }, + }, + }) + ); }); let person = store.peekRecord('person', 1); @@ -613,20 +651,22 @@ test('Calling push with a link containing an object', function(assert) { test('Calling push with a link containing the value null', function(assert) { run(() => { - store.push(store.normalize('person', { - id: '1', - type: 'person', - attributes: { - 'first-name': 'Tan' - }, - relationships: { - 'phone-numbers': { - links: { - related: null - } - } - } - })); + store.push( + store.normalize('person', { + id: '1', + type: 'person', + attributes: { + 'first-name': 'Tan', + }, + relationships: { + 'phone-numbers': { + links: { + related: null, + }, + }, + }, + }) + ); }); let person = store.peekRecord('person', 1); @@ -643,21 +683,17 @@ testInDebug('calling push with hasMany relationship the value must be an array', id: '1', relationships: { phoneNumbers: { - data: 1 - } - } - } + data: 1, + }, + }, + }, }); }); }); }); testInDebug('calling push with missing or invalid `id` throws assertion error', function(assert) { - let invalidValues = [ - {}, - { id: null }, - { id: '' } - ]; + let invalidValues = [{}, { id: null }, { id: '' }]; assert.expect(invalidValues.length); @@ -665,14 +701,16 @@ testInDebug('calling push with missing or invalid `id` throws assertion error', assert.expectAssertion(() => { run(() => { store.push({ - data: invalidValue + data: invalidValue, }); }); }, /You must include an 'id'/); }); }); -testInDebug('calling push with belongsTo relationship the value must not be an array', function(assert) { +testInDebug('calling push with belongsTo relationship the value must not be an array', function( + assert +) { assert.expectAssertion(() => { run(() => { store.push({ @@ -681,62 +719,68 @@ testInDebug('calling push with belongsTo relationship the value must not be an a id: '1', relationships: { person: { - data: [1] - } - } - } + data: [1], + }, + }, + }, }); }); }, /must not be an array/); }); -testInDebug('Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown attributes', function(assert) { - run(() => { - let originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; - try { - Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; - assert.expectWarning(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - firstName: 'Tomster', - emailAddress: 'tomster@emberjs.com', - isMascot: true - } - } - }); - }, `The payload for 'person' contains these unknown attributes: emailAddress,isMascot. Make sure they've been defined in your model.`); - } finally { - Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = originalFlagValue; - } - }); -}); +testInDebug( + 'Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown attributes', + function(assert) { + run(() => { + let originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; + try { + Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; + assert.expectWarning(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + firstName: 'Tomster', + emailAddress: 'tomster@emberjs.com', + isMascot: true, + }, + }, + }); + }, `The payload for 'person' contains these unknown attributes: emailAddress,isMascot. Make sure they've been defined in your model.`); + } finally { + Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = originalFlagValue; + } + }); + } +); -testInDebug('Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown relationships', function(assert) { - run(() => { - var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; - try { - Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; - assert.expectWarning(() => { - store.push({ - data: { - type: 'person', - id: '1', - relationships: { - phoneNumbers: {}, - emailAddresses: {}, - mascots: {} - } - } - }); - }, `The payload for 'person' contains these unknown relationships: emailAddresses,mascots. Make sure they've been defined in your model.`); - } finally { - Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = originalFlagValue; - } - }); -}); +testInDebug( + 'Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown relationships', + function(assert) { + run(() => { + var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; + try { + Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; + assert.expectWarning(() => { + store.push({ + data: { + type: 'person', + id: '1', + relationships: { + phoneNumbers: {}, + emailAddresses: {}, + mascots: {}, + }, + }, + }); + }, `The payload for 'person' contains these unknown relationships: emailAddresses,mascots. Make sure they've been defined in your model.`); + } finally { + Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = originalFlagValue; + } + }); + } +); testInDebug('Calling push with unknown keys should not warn by default', function(assert) { assert.expectNoWarning(() => { @@ -748,9 +792,9 @@ testInDebug('Calling push with unknown keys should not warn by default', functio attributes: { firstName: 'Tomster', emailAddress: 'tomster@emberjs.com', - isMascot: true - } - } + isMascot: true, + }, + }, }); }); }, /The payload for 'person' contains these unknown .*: .* Make sure they've been defined in your model./); @@ -763,8 +807,8 @@ test('_push returns an instance of InternalModel if an object is pushed', functi pushResult = store._push({ data: { id: 1, - type: 'person' - } + type: 'person', + }, }); }); @@ -782,8 +826,8 @@ test('_push does not require a modelName to resolve to a modelClass', function(a store._push({ data: { id: 1, - type: 'person' - } + type: 'person', + }, }); }); @@ -796,10 +840,12 @@ test('_push returns an array of InternalModels if an array is pushed', function( run(() => { pushResult = store._push({ - data: [{ - id: 1, - type: 'person' - }] + data: [ + { + id: 1, + type: 'person', + }, + ], }); }); @@ -808,13 +854,12 @@ test('_push returns an array of InternalModels if an array is pushed', function( assert.notOk(pushResult[0].record, 'InternalModel is not materialized'); }); - test('_push returns null if no data is pushed', function(assert) { let pushResult; run(() => { pushResult = store._push({ - data: null + data: null, }); }); @@ -825,19 +870,19 @@ module('unit/store/push - DS.Store#push with JSON-API', { beforeEach() { const Person = DS.Model.extend({ name: DS.attr('string'), - cars: DS.hasMany('car', { async: false }) + cars: DS.hasMany('car', { async: false }), }); const Car = DS.Model.extend({ make: DS.attr('string'), model: DS.attr('string'), - person: DS.belongsTo('person', { async: false }) + person: DS.belongsTo('person', { async: false }), }); env = setupStore({ adapter: DS.Adapter, car: Car, - person: Person + person: Person, }); store = env.store; @@ -845,7 +890,7 @@ module('unit/store/push - DS.Store#push with JSON-API', { afterEach() { run(store, 'destroy'); - } + }, }); test('Should support pushing multiple models into the store', function(assert) { @@ -858,16 +903,17 @@ test('Should support pushing multiple models into the store', function(assert) { type: 'person', id: 1, attributes: { - name: 'Tom Dale' - } + name: 'Tom Dale', + }, }, { type: 'person', id: 2, attributes: { - name: "Tomster" - } - }] + name: 'Tomster', + }, + }, + ], }); }); @@ -878,7 +924,6 @@ test('Should support pushing multiple models into the store', function(assert) { assert.equal(tomster.get('name'), 'Tomster', 'Tomster should be in the store'); }); - test('Should support pushing included models into the store', function(assert) { assert.expect(2); @@ -889,18 +934,19 @@ test('Should support pushing included models into the store', function(assert) { type: 'person', id: 1, attributes: { - name: 'Tomster' + name: 'Tomster', }, relationships: { cars: [ { data: { - type: 'person', id: 1 - } - } - ] - } - } + type: 'person', + id: 1, + }, + }, + ], + }, + }, ], included: [ { @@ -908,17 +954,18 @@ test('Should support pushing included models into the store', function(assert) { id: 1, attributes: { make: 'Dodge', - model: 'Neon' + model: 'Neon', }, relationships: { person: { data: { - id: 1, type: 'person' - } - } - } - } - ] + id: 1, + type: 'person', + }, + }, + }, + }, + ], }); }); @@ -926,5 +973,5 @@ test('Should support pushing included models into the store', function(assert) { assert.equal(tomster.get('name'), 'Tomster', 'Tomster should be in the store'); let car = store.peekRecord('car', 1); - assert.equal(car.get('model'), 'Neon', 'Tomster\'s car should be in the store'); + assert.equal(car.get('model'), 'Neon', "Tomster's car should be in the store"); }); diff --git a/tests/unit/store/serializer-for-test.js b/tests/unit/store/serializer-for-test.js index 0bebe7a918a..10d1e368150 100644 --- a/tests/unit/store/serializer-for-test.js +++ b/tests/unit/store/serializer-for-test.js @@ -22,7 +22,7 @@ module('unit/store/serializer_for - DS.Store#serializerFor', { container.destroy(); store.destroy(); }); - } + }, }); test('Calling serializerFor looks up `serializer:` from the container', function(assert) { @@ -30,7 +30,10 @@ test('Calling serializerFor looks up `serializer:` from the container', fu registry.register('serializer:person', PersonSerializer); - assert.ok(store.serializerFor('person') instanceof PersonSerializer, 'serializer returned from serializerFor is an instance of the registered Serializer class'); + assert.ok( + store.serializerFor('person') instanceof PersonSerializer, + 'serializer returned from serializerFor is an instance of the registered Serializer class' + ); }); test('Calling serializerFor with a type that has not been registered looks up the default ApplicationSerializer', function(assert) { @@ -38,11 +41,17 @@ test('Calling serializerFor with a type that has not been registered looks up th registry.register('serializer:application', ApplicationSerializer); - assert.ok(store.serializerFor('person') instanceof ApplicationSerializer, 'serializer returned from serializerFor is an instance of ApplicationSerializer'); + assert.ok( + store.serializerFor('person') instanceof ApplicationSerializer, + 'serializer returned from serializerFor is an instance of ApplicationSerializer' + ); }); test('Calling serializerFor with a type that has not been registered and in an application that does not have an ApplicationSerializer looks up the default Ember Data serializer', function(assert) { - assert.ok(store.serializerFor('person') instanceof DS.JSONSerializer, 'serializer returned from serializerFor is an instance of DS.JSONSerializer'); + assert.ok( + store.serializerFor('person') instanceof DS.JSONSerializer, + 'serializer returned from serializerFor is an instance of DS.JSONSerializer' + ); }); testInDebug('Calling serializerFor with a model class should assert', function(assert) { diff --git a/tests/unit/store/unload-test.js b/tests/unit/store/unload-test.js index 772b5cd959e..2ba613a8ece 100644 --- a/tests/unit/store/unload-test.js +++ b/tests/unit/store/unload-test.js @@ -12,33 +12,34 @@ let store, tryToFind, Record; module('unit/store/unload - Store unloading records', { beforeEach() { - Record = DS.Model.extend({ title: DS.attr('string'), - wasFetched: DS.attr('boolean') + wasFetched: DS.attr('boolean'), }); Record.reopenClass({ toString() { return 'Record'; - } + }, }); store = createStore({ adapter: DS.Adapter.extend({ findRecord(store, type, id, snapshot) { tryToFind = true; - return resolve({ data: { id, type: snapshot.modelName, attributes: { 'was-fetched': true } } }); - } + return resolve({ + data: { id, type: snapshot.modelName, attributes: { 'was-fetched': true } }, + }); + }, }), - record: Record + record: Record, }); }, afterEach() { run(store, 'destroy'); - } + }, }); testInDebug('unload a dirty record asserts', function(assert) { @@ -50,9 +51,9 @@ testInDebug('unload a dirty record asserts', function(assert) { type: 'record', id: '1', attributes: { - title: 'toto' - } - } + title: 'toto', + }, + }, }); let record = store.peekRecord('record', 1); @@ -62,9 +63,15 @@ testInDebug('unload a dirty record asserts', function(assert) { assert.equal(get(record, 'hasDirtyAttributes'), true, 'record is dirty'); - assert.expectAssertion(function() { - record.unloadRecord(); - }, 'You can only unload a record which is not inFlight. `' + record._internalModel.toString() + '`', 'can not unload dirty record'); + assert.expectAssertion( + function() { + record.unloadRecord(); + }, + 'You can only unload a record which is not inFlight. `' + + record._internalModel.toString() + + '`', + 'can not unload dirty record' + ); // force back into safe to unload mode. run(() => { @@ -82,9 +89,9 @@ test('unload a record', function(assert) { type: 'record', id: '1', attributes: { - title: 'toto' - } - } + title: 'toto', + }, + }, }); return store.findRecord('record', 1).then(record => { @@ -119,38 +126,38 @@ test('can commit store after unload record with relationships', function(assert) assert.expect(1); const Brand = DS.Model.extend({ - name: DS.attr('string') + name: DS.attr('string'), }); Brand.reopenClass({ toString() { return 'Brand'; - } + }, }); const Product = DS.Model.extend({ description: DS.attr('string'), brand: DS.belongsTo('brand', { - async: false - }) + async: false, + }), }); Product.reopenClass({ toString() { return 'Product'; - } + }, }); const Like = DS.Model.extend({ product: DS.belongsTo('product', { - async: false - }) + async: false, + }), }); Like.reopenClass({ toString() { return 'Like'; - } + }, }); let store = createStore({ @@ -162,19 +169,19 @@ test('can commit store after unload record with relationships', function(assert) type: snapshot.modelName, attributes: { description: 'cuisinart', - brand: 1 - } - } + brand: 1, + }, + }, }); }, createRecord(store, type, snapshot) { return resolve(); - } + }, }), brand: Brand, product: Product, - like: Like + like: Like, }); return run(() => { @@ -184,33 +191,41 @@ test('can commit store after unload record with relationships', function(assert) type: 'brand', id: '1', attributes: { - name: 'EmberJS' - } + name: 'EmberJS', + }, }, { type: 'product', id: '1', attributes: { - description: 'toto' + description: 'toto', }, relationships: { brand: { - data: { type: 'brand', id: '1' } - } - } - }] + data: { type: 'brand', id: '1' }, + }, + }, + }, + ], }); let product = store.peekRecord('product', 1); let like = store.createRecord('like', { id: 1, product: product }); return like.save(); - }).then(() => { - // TODO: this is strange, future travelers please address - run(() => store.unloadRecord(store.peekRecord('product', 1))); - }).then(() => { - return store.findRecord('product', 1); - }).then(product => { - assert.equal(product.get('description'), 'cuisinart', "The record was unloaded and the adapter's `findRecord` was called"); - }); + }) + .then(() => { + // TODO: this is strange, future travelers please address + run(() => store.unloadRecord(store.peekRecord('product', 1))); + }) + .then(() => { + return store.findRecord('product', 1); + }) + .then(product => { + assert.equal( + product.get('description'), + 'cuisinart', + "The record was unloaded and the adapter's `findRecord` was called" + ); + }); }); diff --git a/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js b/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js index 5d73cce6798..43c2db2e5d4 100644 --- a/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js +++ b/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js @@ -11,7 +11,7 @@ module('unit/system/relationships/relationship-payloads-manager (polymorphic)', beforeEach() { const User = DS.Model.extend({ hats: hasMany('hat', { async: false, polymorphic: true, inverse: 'user' }), - sharedHats: hasMany('hat', { async: false, polymorphic: true, inverse: 'sharingUsers' }) + sharedHats: hasMany('hat', { async: false, polymorphic: true, inverse: 'sharingUsers' }), }); User.toString = () => 'User'; @@ -23,7 +23,7 @@ module('unit/system/relationships/relationship-payloads-manager (polymorphic)', user: belongsTo('user', { async: false, inverse: 'hats', polymorphic: true }), sharingUsers: belongsTo('users', { async: false, inverse: 'sharedHats', polymorphic: true }), hat: belongsTo('hat', { async: false, inverse: 'hats', polymorphic: true }), - hats: hasMany('hat', { async: false, inverse: 'hat', polymorphic: true }) + hats: hasMany('hat', { async: false, inverse: 'hat', polymorphic: true }), }); const BigHat = Hat.extend({}); const SmallHat = Hat.extend({}); @@ -33,9 +33,9 @@ module('unit/system/relationships/relationship-payloads-manager (polymorphic)', alien: Alien, hat: Hat, 'big-hat': BigHat, - 'small-hat': SmallHat + 'small-hat': SmallHat, }); - } + }, }); test('push one side is polymorphic, baseType then subTypes', function(assert) { @@ -53,9 +53,9 @@ test('push one side is polymorphic, baseType then subTypes', function(assert) { attributes: {}, relationships: { user: { - data: { id: '1' , type: 'user' } - } - } + data: { id: '1', type: 'user' }, + }, + }, }; const hatData1 = makeHat('hat', hatData), @@ -66,13 +66,9 @@ test('push one side is polymorphic, baseType then subTypes', function(assert) { data: { id: '1', type: 'user', - attributes: {} + attributes: {}, }, - included: [ - hatData1, - bigHatData1, - smallHatData1 - ] + included: [hatData1, bigHatData1, smallHatData1], }; const user = run(() => this.store.push(userData)); @@ -97,9 +93,9 @@ test('push one side is polymorphic, subType then baseType', function(assert) { attributes: {}, relationships: { user: { - data: { id: '1' , type: 'user' } - } - } + data: { id: '1', type: 'user' }, + }, + }, }; const bigHatData1 = makeHat('hat', hatData), @@ -111,14 +107,14 @@ test('push one side is polymorphic, subType then baseType', function(assert) { data: { id: '1', type: 'user', - attributes: {} + attributes: {}, }, - included + included, }; const user = run(() => this.store.push(userData)), finalResult = user.get('hats').mapBy('type'), - expectedResults = included.map(m=>m.type); + expectedResults = included.map(m => m.type); assert.deepEqual(finalResult, expectedResults, 'We got all our hats!'); }); @@ -135,32 +131,27 @@ test('push one side is polymorphic, different subtypes', function(assert) { } const hatData = { - attributes:{}, + attributes: {}, relationships: { user: { - data: { id: '1' , type: 'user' } - } - } + data: { id: '1', type: 'user' }, + }, + }, }; const bigHatData1 = makeHat('big-hat', hatData), smallHatData1 = makeHat('small-hat', hatData), bigHatData2 = makeHat('big-hat', hatData), smallHatData2 = makeHat('small-hat', hatData), - included = [ - bigHatData1, - smallHatData1, - bigHatData2, - smallHatData2 - ]; + included = [bigHatData1, smallHatData1, bigHatData2, smallHatData2]; const userData = { data: { id: '1', type: 'user', - attributes: {} + attributes: {}, }, - included + included, }; const user = run(() => this.store.push(userData)), @@ -185,9 +176,9 @@ test('push both sides are polymorphic', function(assert) { attributes: {}, relationships: { user: { - data: { id: '1' , type: 'alien' } - } - } + data: { id: '1', type: 'alien' }, + }, + }, }; const bigHatData1 = makeHat('hat', alienHatData), @@ -198,9 +189,9 @@ test('push both sides are polymorphic', function(assert) { data: { id: '1', type: 'alien', - attributes: {} + attributes: {}, }, - included: alienIncluded + included: alienIncluded, }; const expectedAlienResults = alienIncluded.map(m => m.type), @@ -220,10 +211,10 @@ test('handles relationships where both sides are polymorphic', function(assert) person: { data: { id: isForBigPerson ? '1' : '2', - type: isForBigPerson ? 'big-person' : 'small-person' - } - } - } + type: isForBigPerson ? 'big-person' : 'small-person', + }, + }, + }, }; } @@ -238,42 +229,34 @@ test('handles relationships where both sides are polymorphic', function(assert) data: { id: '1', type: 'big-person', - attributes: {} + attributes: {}, }, - included: [ - bigHatData1, - smallHatData1, - bigHatData2, - smallHatData2 - ] + included: [bigHatData1, smallHatData1, bigHatData2, smallHatData2], }; const smallPersonData = { data: { id: '2', type: 'small-person', - attributes: {} + attributes: {}, }, - included: [ - bigHatData3, - smallHatData3 - ] + included: [bigHatData3, smallHatData3], }; const PersonModel = Model.extend({ hats: hasMany('hat', { async: false, polymorphic: true, - inverse: 'person' - }) + inverse: 'person', + }), }); const HatModel = Model.extend({ type: attr('string'), person: belongsTo('person', { async: false, inverse: 'hats', - polymorphic: true - }) + polymorphic: true, + }), }); const BigHatModel = HatModel.extend({}); const SmallHatModel = HatModel.extend({}); @@ -281,14 +264,14 @@ test('handles relationships where both sides are polymorphic', function(assert) const BigPersonModel = PersonModel.extend({}); const SmallPersonModel = PersonModel.extend({}); - const store = this.store = createStore({ + const store = (this.store = createStore({ person: PersonModel, bigPerson: BigPersonModel, smallPerson: SmallPersonModel, hat: HatModel, bigHat: BigHatModel, - smallHat: SmallHatModel - }); + smallHat: SmallHatModel, + })); const bigPerson = run(() => { return store.push(bigPersonData); @@ -308,11 +291,11 @@ test('handles relationships where both sides are polymorphic', function(assert) test('handles relationships where both sides are polymorphic reflexive', function(assert) { function link(a, b, relationshipName, recurse = true) { a.relationships = a.relationships || {}; - const rel = a.relationships[relationshipName] = a.relationships[relationshipName] || {}; + const rel = (a.relationships[relationshipName] = a.relationships[relationshipName] || {}); if (Array.isArray(b)) { - rel.data = b.map((i) => { - let {type, id} = i; + rel.data = b.map(i => { + let { type, id } = i; if (recurse === true) { link(i, [a], relationshipName, false); @@ -323,7 +306,7 @@ test('handles relationships where both sides are polymorphic reflexive', functio } else { rel.data = { type: b.type, - id: b.id + id: b.id, }; if (recurse === true) { @@ -336,7 +319,7 @@ test('handles relationships where both sides are polymorphic reflexive', functio const Person = Model.extend({ name: attr(), family: hasMany('person', { async: false, polymorphic: true, inverse: 'family' }), - twin: belongsTo('person', { async: false, polymorphic: true, inverse: 'twin' }) + twin: belongsTo('person', { async: false, polymorphic: true, inverse: 'twin' }), }); const Girl = Person.extend({}); const Boy = Person.extend({}); @@ -346,29 +329,29 @@ test('handles relationships where both sides are polymorphic reflexive', functio type: 'boy', id: `${id++}`, attributes: { - name: 'Gavin' - } + name: 'Gavin', + }, }; const sisterPayload = { type: 'girl', id: `${id++}`, attributes: { - name: 'Rose' - } + name: 'Rose', + }, }; const fatherPayload = { type: 'grownup', id: `${id++}`, attributes: { - name: 'Garak' - } + name: 'Garak', + }, }; const motherPayload = { type: 'grownup', id: `${id++}`, attributes: { - name: 'Kira' - } + name: 'Kira', + }, }; link(brotherPayload, sisterPayload, 'twin'); @@ -376,32 +359,30 @@ test('handles relationships where both sides are polymorphic reflexive', functio const payload = { data: brotherPayload, - included: [ - sisterPayload, - fatherPayload, - motherPayload - ] + included: [sisterPayload, fatherPayload, motherPayload], }; const expectedFamilyReferences = [ { type: 'girl', id: sisterPayload.id }, { type: 'grownup', id: fatherPayload.id }, - { type: 'grownup', id: motherPayload.id } + { type: 'grownup', id: motherPayload.id }, ]; const expectedTwinReference = { type: 'girl', id: sisterPayload.id }; - const store = this.store = createStore({ + const store = (this.store = createStore({ person: Person, grownup: Grownup, boy: Boy, - girl: Girl - }); + girl: Girl, + })); const boyInstance = run(() => { return store.push(payload); }); - const familyResultReferences = boyInstance.get('family').toArray() - .map((i) => { + const familyResultReferences = boyInstance + .get('family') + .toArray() + .map(i => { return { type: i.constructor.modelName, id: i.id }; }); const twinResult = boyInstance.get('twin'); @@ -414,11 +395,11 @@ test('handles relationships where both sides are polymorphic reflexive', functio test('handles relationships where both sides are polymorphic reflexive but the primary payload does not include linkage', function(assert) { function link(a, b, relationshipName, recurse = true) { a.relationships = a.relationships || {}; - const rel = a.relationships[relationshipName] = a.relationships[relationshipName] || {}; + const rel = (a.relationships[relationshipName] = a.relationships[relationshipName] || {}); if (Array.isArray(b)) { - rel.data = b.map((i) => { - let {type, id} = i; + rel.data = b.map(i => { + let { type, id } = i; if (recurse === true) { link(i, [a], relationshipName, false); @@ -429,7 +410,7 @@ test('handles relationships where both sides are polymorphic reflexive but the p } else { rel.data = { type: b.type, - id: b.id + id: b.id, }; if (recurse === true) { @@ -442,7 +423,7 @@ test('handles relationships where both sides are polymorphic reflexive but the p const Person = Model.extend({ name: attr(), family: hasMany('person', { async: false, polymorphic: true, inverse: 'family' }), - twin: belongsTo('person', { async: false, polymorphic: true, inverse: 'twin' }) + twin: belongsTo('person', { async: false, polymorphic: true, inverse: 'twin' }), }); const Girl = Person.extend({}); const Boy = Person.extend({}); @@ -452,29 +433,29 @@ test('handles relationships where both sides are polymorphic reflexive but the p type: 'boy', id: `${id++}`, attributes: { - name: 'Gavin' - } + name: 'Gavin', + }, }; const sisterPayload = { type: 'girl', id: `${id++}`, attributes: { - name: 'Rose' - } + name: 'Rose', + }, }; const fatherPayload = { type: 'grownup', id: `${id++}`, attributes: { - name: 'Garak' - } + name: 'Garak', + }, }; const motherPayload = { type: 'grownup', id: `${id++}`, attributes: { - name: 'Kira' - } + name: 'Kira', + }, }; link(brotherPayload, sisterPayload, 'twin'); @@ -485,36 +466,37 @@ test('handles relationships where both sides are polymorphic reflexive but the p const payload = { data: brotherPayload, - included: [ - sisterPayload, - fatherPayload, - motherPayload - ] + included: [sisterPayload, fatherPayload, motherPayload], }; const expectedFamilyReferences = [ { type: 'girl', id: sisterPayload.id }, { type: 'grownup', id: fatherPayload.id }, - { type: 'grownup', id: motherPayload.id } + { type: 'grownup', id: motherPayload.id }, ]; const expectedTwinReference = { type: 'girl', id: sisterPayload.id }; - const store = this.store = createStore({ + const store = (this.store = createStore({ person: Person, grownup: Grownup, boy: Boy, - girl: Girl - }); + girl: Girl, + })); const boyInstance = run(() => { return store.push(payload); }); - const familyResultReferences = boyInstance.get('family').toArray() - .map((i) => { + const familyResultReferences = boyInstance + .get('family') + .toArray() + .map(i => { return { type: i.constructor.modelName, id: i.id }; }); const twinResult = boyInstance.get('twin'); - const twinResultReference = twinResult && { type: twinResult.constructor.modelName, id: twinResult.id }; + const twinResultReference = twinResult && { + type: twinResult.constructor.modelName, + id: twinResult.id, + }; assert.deepEqual(familyResultReferences, expectedFamilyReferences, 'We linked family correctly'); assert.deepEqual(twinResultReference, expectedTwinReference, 'We linked twin correctly'); @@ -526,8 +508,8 @@ test('push polymorphic self-referential non-reflexive relationship', function(as data: { id: '1', type: 'big-hat', - attributes: {} - } + attributes: {}, + }, }; const hat2Data = { data: { @@ -536,31 +518,34 @@ test('push polymorphic self-referential non-reflexive relationship', function(as attributes: {}, relationships: { hats: { - data: [{ id: '1', type: 'big-hat' }] - } - } - } + data: [{ id: '1', type: 'big-hat' }], + }, + }, + }, }; const hat1 = run(() => store.push(hat1Data)); const hat2 = run(() => store.push(hat2Data)); - const expectedHatReference = { id: '2', type: 'big-hat' }; + const expectedHatReference = { id: '2', type: 'big-hat' }; const expectedHatsReferences = [{ id: '1', type: 'big-hat' }]; - const finalHatsReferences = hat2.get('hats').toArray() - .map((i) => { + const finalHatsReferences = hat2 + .get('hats') + .toArray() + .map(i => { return { type: i.constructor.modelName, id: i.id }; }); const hatResult = hat1.get('hat'); - const finalHatReference = hatResult && { type: hatResult.constructor.modelName, id: hatResult.id }; - + const finalHatReference = hatResult && { + type: hatResult.constructor.modelName, + id: hatResult.id, + }; assert.deepEqual(finalHatReference, expectedHatReference, 'we set hat on hat:1'); assert.deepEqual(finalHatsReferences, expectedHatsReferences, 'We have hats on hat:2'); }); - test('push polymorphic self-referential circular non-reflexive relationship', function(assert) { const store = this.store; const hatData = { @@ -570,105 +555,104 @@ test('push polymorphic self-referential circular non-reflexive relationship', fu attributes: {}, relationships: { hat: { - data: { id: '1', type: 'big-hat' } + data: { id: '1', type: 'big-hat' }, }, hats: { - data: [{ id: '1', type: 'big-hat' }] - } - } - } + data: [{ id: '1', type: 'big-hat' }], + }, + }, + }, }; const hat = run(() => store.push(hatData)); - const expectedHatReference = { id: '1', type: 'big-hat' }; + const expectedHatReference = { id: '1', type: 'big-hat' }; const expectedHatsReferences = [{ id: '1', type: 'big-hat' }]; - const finalHatsReferences = hat.get('hats').toArray() - .map((i) => { + const finalHatsReferences = hat + .get('hats') + .toArray() + .map(i => { return { type: i.constructor.modelName, id: i.id }; }); const hatResult = hat.get('hat'); - const finalHatReference = hatResult && { type: hatResult.constructor.modelName, id: hatResult.id }; - + const finalHatReference = hatResult && { + type: hatResult.constructor.modelName, + id: hatResult.id, + }; assert.deepEqual(finalHatReference, expectedHatReference, 'we set hat on hat:1'); assert.deepEqual(finalHatsReferences, expectedHatsReferences, 'We have hats on hat:2'); }); test('polymorphic hasMany to types with separate id-spaces', function(assert) { - const user = run(() => this.store.push({ - data: { - id: '1', - type: 'user', - relationships: { - hats: { - data: [ - { id: '1', type: 'big-hat' }, - { id: '1', type: 'small-hat' } - ] - } - } - }, - included: [{ - id: '1', - type: 'big-hat' - }, { - id: '1', - type: 'small-hat' - }] - })); + const user = run(() => + this.store.push({ + data: { + id: '1', + type: 'user', + relationships: { + hats: { + data: [{ id: '1', type: 'big-hat' }, { id: '1', type: 'small-hat' }], + }, + }, + }, + included: [ + { + id: '1', + type: 'big-hat', + }, + { + id: '1', + type: 'small-hat', + }, + ], + }) + ); const hats = user.get('hats'); - assert.deepEqual( - hats.map(h => h.constructor.modelName), - ['big-hat', 'small-hat'] - ); - assert.deepEqual( - hats.map(h => h.id), - ['1', '1'] - ); + assert.deepEqual(hats.map(h => h.constructor.modelName), ['big-hat', 'small-hat']); + assert.deepEqual(hats.map(h => h.id), ['1', '1']); }); -test('polymorphic hasMany to types with separate id-spaces, from inverse payload', function (assert) { - const user = run(() => this.store.push({ - data: { - id: '1', - type: 'user' - }, - included: [{ - id: '1', - type: 'big-hat', - relationships: { - user: { - data: { id: '1', type: 'user' } - } - } - }, { - id: '1', - type: 'small-hat', - relationships: { - user: { - data: { id: '1', type: 'user' } - } - } - }] - })); +test('polymorphic hasMany to types with separate id-spaces, from inverse payload', function(assert) { + const user = run(() => + this.store.push({ + data: { + id: '1', + type: 'user', + }, + included: [ + { + id: '1', + type: 'big-hat', + relationships: { + user: { + data: { id: '1', type: 'user' }, + }, + }, + }, + { + id: '1', + type: 'small-hat', + relationships: { + user: { + data: { id: '1', type: 'user' }, + }, + }, + }, + ], + }) + ); const hats = user.get('hats'); - assert.deepEqual( - hats.map(h => h.constructor.modelName), - ['big-hat', 'small-hat'] - ); - assert.deepEqual( - hats.map(h => h.id), - ['1', '1'] - ); + assert.deepEqual(hats.map(h => h.constructor.modelName), ['big-hat', 'small-hat']); + assert.deepEqual(hats.map(h => h.id), ['1', '1']); }); -test('polymorphic hasMany to polymorphic hasMany types with separate id-spaces', function (assert) { +test('polymorphic hasMany to polymorphic hasMany types with separate id-spaces', function(assert) { let bigHatId = 1; let smallHatId = 1; function makePolymorphicHatForPolymorphicPerson(type, isForBigPerson = true) { @@ -680,10 +664,10 @@ test('polymorphic hasMany to polymorphic hasMany types with separate id-spaces', person: { data: { id: '1', - type: isForBigPerson ? 'big-person' : 'small-person' - } - } - } + type: isForBigPerson ? 'big-person' : 'small-person', + }, + }, + }, }; } @@ -698,42 +682,34 @@ test('polymorphic hasMany to polymorphic hasMany types with separate id-spaces', data: { id: '1', type: 'big-person', - attributes: {} + attributes: {}, }, - included: [ - bigHatData1, - smallHatData1, - bigHatData2, - smallHatData2 - ] + included: [bigHatData1, smallHatData1, bigHatData2, smallHatData2], }; const smallPersonData = { data: { id: '1', type: 'small-person', - attributes: {} + attributes: {}, }, - included: [ - bigHatData3, - smallHatData3 - ] + included: [bigHatData3, smallHatData3], }; const PersonModel = Model.extend({ hats: hasMany('hat', { async: false, polymorphic: true, - inverse: 'person' - }) + inverse: 'person', + }), }); const HatModel = Model.extend({ type: attr('string'), person: belongsTo('person', { async: false, inverse: 'hats', - polymorphic: true - }) + polymorphic: true, + }), }); const BigHatModel = HatModel.extend({}); const SmallHatModel = HatModel.extend({}); @@ -741,14 +717,14 @@ test('polymorphic hasMany to polymorphic hasMany types with separate id-spaces', const BigPersonModel = PersonModel.extend({}); const SmallPersonModel = PersonModel.extend({}); - const store = this.store = createStore({ + const store = (this.store = createStore({ person: PersonModel, bigPerson: BigPersonModel, smallPerson: SmallPersonModel, hat: HatModel, bigHat: BigHatModel, - smallHat: SmallHatModel - }); + smallHat: SmallHatModel, + })); const bigPerson = run(() => { return store.push(bigPersonData); @@ -763,27 +739,32 @@ test('polymorphic hasMany to polymorphic hasMany types with separate id-spaces', assert.deepEqual( finalBigResult.map(h => ({ type: h.constructor.modelName, id: h.get('id') })), - [{ type: 'big-hat', id: '1'}, { type: 'small-hat', id: '1'}, { type: 'big-hat', id: '2'}, { type: 'small-hat', id: '2'}], + [ + { type: 'big-hat', id: '1' }, + { type: 'small-hat', id: '1' }, + { type: 'big-hat', id: '2' }, + { type: 'small-hat', id: '2' }, + ], 'big-person hats is all good' ); assert.deepEqual( finalSmallResult.map(h => ({ type: h.constructor.modelName, id: h.get('id') })), - [{ type: 'big-hat', id: '3'}, { type: 'small-hat', id: '3'}], + [{ type: 'big-hat', id: '3' }, { type: 'small-hat', id: '3' }], 'small-person hats is all good' ); }); testInDebug('Invalid inverses throw errors', function(assert) { let PostModel = Model.extend({ - comments: hasMany('comment', { async: false, inverse: 'post' }) + comments: hasMany('comment', { async: false, inverse: 'post' }), }); let CommentModel = Model.extend({ - post: belongsTo('post', { async: false, inverse: null }) + post: belongsTo('post', { async: false, inverse: null }), }); let store = createStore({ post: PostModel, - comment: CommentModel + comment: CommentModel, }); function runInvalidPush() { @@ -794,11 +775,9 @@ testInDebug('Invalid inverses throw errors', function(assert) { id: '1', relationships: { comments: { - data: [ - { type: 'comment', id: '1' } - ] - } - } + data: [{ type: 'comment', id: '1' }], + }, + }, }, included: [ { @@ -808,15 +787,19 @@ testInDebug('Invalid inverses throw errors', function(assert) { post: { data: { type: 'post', - id: '1' - } - } - } - } - ] + id: '1', + }, + }, + }, + }, + ], }); }); } - assert.expectAssertion(runInvalidPush, /The comment:post relationship declares 'inverse: null', but it was resolved as the inverse for post:comments/, 'We detected the invalid inverse'); + assert.expectAssertion( + runInvalidPush, + /The comment:post relationship declares 'inverse: null', but it was resolved as the inverse for post:comments/, + 'We detected the invalid inverse' + ); }); diff --git a/tests/unit/system/snapshot-record-array-test.js b/tests/unit/system/snapshot-record-array-test.js index 7c8221a428c..38c25f8d73d 100644 --- a/tests/unit/system/snapshot-record-array-test.js +++ b/tests/unit/system/snapshot-record-array-test.js @@ -7,10 +7,10 @@ module('Unit - snapshot-record-array'); test('constructor', function(assert) { let array = A([1, 2]); array.type = 'some type'; - let meta = { }; + let meta = {}; let options = { adapterOptions: 'some options', - include: 'include me' + include: 'include me', }; let snapshot = new SnapshotRecordArray(array, meta, options); @@ -33,10 +33,10 @@ test('#snapshot', function(assert) { return snapshotTaken; }; - let meta = { }; + let meta = {}; let options = { adapterOptions: 'some options', - include: 'include me' + include: 'include me', }; let snapshot = new SnapshotRecordArray(array, meta, options); @@ -56,13 +56,13 @@ test('SnapshotRecordArray.type loads the class lazily', function(assert) { get() { typeLoaded = true; return 'some type'; - } + }, }); - let meta = { }; + let meta = {}; let options = { adapterOptions: 'some options', - include: 'include me' + include: 'include me', }; let snapshot = new SnapshotRecordArray(array, meta, options); diff --git a/tests/unit/transform/boolean-test.js b/tests/unit/transform/boolean-test.js index ddead45a024..6f9c206ccd2 100644 --- a/tests/unit/transform/boolean-test.js +++ b/tests/unit/transform/boolean-test.js @@ -4,7 +4,7 @@ import { module, test } from 'qunit'; module('unit/transform - DS.BooleanTransform'); -test("#serialize", function(assert) { +test('#serialize', function(assert) { let transform = new DS.BooleanTransform(); assert.strictEqual(transform.serialize(null, { allowNull: true }), null); diff --git a/tests/unit/transform/number-test.js b/tests/unit/transform/number-test.js index 10ed98761b2..d1f61ecb85c 100644 --- a/tests/unit/transform/number-test.js +++ b/tests/unit/transform/number-test.js @@ -9,7 +9,7 @@ test('#serialize', function(assert) { assert.strictEqual(transform.serialize(null), null); assert.strictEqual(transform.serialize(undefined), null); - assert.equal(transform.serialize("1.1"), 1.1); + assert.equal(transform.serialize('1.1'), 1.1); assert.equal(transform.serialize(1.1), 1.1); assert.equal(transform.serialize(new Number(1.1)), 1.1); assert.strictEqual(transform.serialize(NaN), null); diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index 6c97dbb7212..b1019afdd80 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -9,9 +9,7 @@ import DS from 'ember-data'; import Model from 'ember-data/model'; import { assertPolymorphicType } from 'ember-data/-debug'; -import { - modelHasAttributeOrRelationshipNamedType -} from 'ember-data/-private'; +import { modelHasAttributeOrRelationshipNamedType } from 'ember-data/-private'; let env, User, Message, Post, Person, Video, Medium; @@ -19,12 +17,12 @@ module('unit/utils', { beforeEach() { Person = Model.extend(); User = Model.extend({ - messages: DS.hasMany('message', { async: false }) + messages: DS.hasMany('message', { async: false }), }); Message = Model.extend(); Post = Message.extend({ - medias: DS.hasMany('medium', { async: false }) + medias: DS.hasMany('medium', { async: false }), }); Medium = Mixin.create(); @@ -35,7 +33,7 @@ module('unit/utils', { person: Person, message: Message, post: Post, - video: Video + video: Video, }); env.registry.register('mixin:medium', Medium); @@ -43,7 +41,7 @@ module('unit/utils', { afterEach() { run(env.container, 'destroy'); - } + }, }); testInDebug('assertPolymorphicType works for subclasses', function(assert) { @@ -51,21 +49,25 @@ testInDebug('assertPolymorphicType works for subclasses', function(assert) { run(() => { env.store.push({ - data: [{ - type: 'user', - id: '1', - relationships: { - messages: { - data: [] - } - } - }, { - type: 'post', - id: '1' - }, { - type: 'person', - id: '1' - }] + data: [ + { + type: 'user', + id: '1', + relationships: { + messages: { + data: [], + }, + }, + }, + { + type: 'post', + id: '1', + }, + { + type: 'person', + id: '1', + }, + ], }); user = env.store.peekRecord('user', 1); @@ -91,13 +93,13 @@ testInDebug('assertPolymorphicType works for subclasses', function(assert) { test('modelHasAttributeOrRelationshipNamedType', function(assert) { let ModelWithTypeAttribute = Model.extend({ - type: DS.attr() + type: DS.attr(), }); let ModelWithTypeBelongsTo = Model.extend({ - type: DS.belongsTo() + type: DS.belongsTo(), }); let ModelWithTypeHasMany = Model.extend({ - type: DS.hasMany() + type: DS.hasMany(), }); assert.equal(modelHasAttributeOrRelationshipNamedType(Model), false); @@ -112,16 +114,20 @@ testInDebug('assertPolymorphicType works for mixins', function(assert) { run(() => { env.store.push({ - data: [{ - type: 'post', - id: '1' - }, { - type: 'video', - id: '1' - }, { - type: 'person', - id: '1' - }] + data: [ + { + type: 'post', + id: '1', + }, + { + type: 'video', + id: '1', + }, + { + type: 'person', + id: '1', + }, + ], }); post = env.store.peekRecord('post', 1); video = env.store.peekRecord('video', 1); diff --git a/tests/unit/utils/parse-response-headers-test.js b/tests/unit/utils/parse-response-headers-test.js index d706a7b91d4..7ac9dde93dd 100644 --- a/tests/unit/utils/parse-response-headers-test.js +++ b/tests/unit/utils/parse-response-headers-test.js @@ -15,26 +15,38 @@ test('header parsing', function(assert) { let headersString = [ 'Content-Encoding: gzip', 'content-type: application/json; charset=utf-8', - 'date: Fri, 05 Feb 2016 21:47:56 GMT' + 'date: Fri, 05 Feb 2016 21:47:56 GMT', ].join(CRLF); let headers = parseResponseHeaders(headersString); assert.equal(headers['Content-Encoding'], 'gzip', 'parses basic header pair'); - assert.equal(headers['content-type'], 'application/json; charset=utf-8', 'parses header with complex value'); + assert.equal( + headers['content-type'], + 'application/json; charset=utf-8', + 'parses header with complex value' + ); assert.equal(headers['date'], 'Fri, 05 Feb 2016 21:47:56 GMT', 'parses header with date value'); }); test('field-name parsing', function(assert) { let headersString = [ ' name-with-leading-whitespace: some value', - 'name-with-whitespace-before-colon : another value' + 'name-with-whitespace-before-colon : another value', ].join(CRLF); let headers = parseResponseHeaders(headersString); - assert.equal(headers['name-with-leading-whitespace'], 'some value', 'strips leading whitespace from field-name'); - assert.equal(headers['name-with-whitespace-before-colon'], 'another value', 'strips whitespace before colon from field-name'); + assert.equal( + headers['name-with-leading-whitespace'], + 'some value', + 'strips leading whitespace from field-name' + ); + assert.equal( + headers['name-with-whitespace-before-colon'], + 'another value', + 'strips whitespace before colon from field-name' + ); }); test('field-value parsing', function(assert) { @@ -42,23 +54,39 @@ test('field-value parsing', function(assert) { 'value-with-leading-space: value with leading whitespace', 'value-without-leading-space:value without leading whitespace', 'value-with-colon: value with: a colon', - 'value-with-trailing-whitespace: banana ' + 'value-with-trailing-whitespace: banana ', ].join(CRLF); let headers = parseResponseHeaders(headersString); - assert.equal(headers['value-with-leading-space'], 'value with leading whitespace', 'strips leading whitespace in field-value'); - assert.equal(headers['value-without-leading-space'], 'value without leading whitespace', 'works without leaading whitespace in field-value'); - assert.equal(headers['value-with-colon'], 'value with: a colon', 'has correct value when value contains a colon'); - assert.equal(headers['value-with-trailing-whitespace'], 'banana', 'strips trailing whitespace from field-value'); + assert.equal( + headers['value-with-leading-space'], + 'value with leading whitespace', + 'strips leading whitespace in field-value' + ); + assert.equal( + headers['value-without-leading-space'], + 'value without leading whitespace', + 'works without leaading whitespace in field-value' + ); + assert.equal( + headers['value-with-colon'], + 'value with: a colon', + 'has correct value when value contains a colon' + ); + assert.equal( + headers['value-with-trailing-whitespace'], + 'banana', + 'strips trailing whitespace from field-value' + ); }); -"\r\nfoo: bar" +('\r\nfoo: bar'); test('ignores headers that do not contain a colon', function(assert) { let headersString = [ 'Content-Encoding: gzip', 'I am ignored because I do not contain a colon', - 'apple: pie' + 'apple: pie', ].join(CRLF); let headers = parseResponseHeaders(headersString); From 72a5c986c5fa2eb3bb4dde27bf208cfc84aac6f5 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 8 May 2018 22:20:19 -0700 Subject: [PATCH 2236/2527] ease transition period by separating changed files out thus minimizing duplication requirements --- addon/{-private => -legacy-private}/attr.js | 0 addon/{-private => -legacy-private}/index.js | 0 .../system/many-array.js | 0 .../system/model/internal-model.js | 0 .../system/model/model.js | 0 .../system/model/states.js | 0 .../system/promise-proxies.js | 0 .../system/references/belongs-to.js | 0 .../system/references/has-many.js | 0 .../system/references/reference.js | 0 .../system/relationships/belongs-to.js | 0 .../system/relationships/ext.js | 0 .../system/relationships/has-many.js | 0 .../relationship-payloads-manager.js | 0 .../relationships/relationship-payloads.js | 0 .../system/relationships/state/belongs-to.js | 0 .../system/relationships/state/create.js | 0 .../system/relationships/state/has-many.js | 0 .../relationships/state/relationship.js | 0 .../system/snapshot.js | 0 .../system/store.js | 0 .../attr.js | 0 .../index.js | 0 .../system/many-array.js | 0 .../system/model/internal-model.js | 0 .../system/model/model-data.js | 0 .../system/model/model.js | 0 .../system/model/states.js | 0 .../system/promise-proxies.js | 0 .../system/references/belongs-to.js | 0 .../system/references/has-many.js | 0 .../system/references/reference.js | 0 .../system/relationships/belongs-to.js | 0 .../system/relationships/ext.js | 0 .../system/relationships/has-many.js | 0 .../system/relationships/state/belongs-to.js | 0 .../system/relationships/state/create.js | 0 .../system/relationships/state/has-many.js | 0 .../relationships/state/relationship.js | 0 .../system/snapshot.js | 0 .../system/store.js | 0 .../system/store/model-data-wrapper.js | 0 .../adapters/build-url-mixin.js | 453 ----------------- .../adapters/errors.js | 464 ------------------ addon/-record-data-rfc-private/core.js | 29 -- addon/-record-data-rfc-private/features.js | 5 - .../system/backburner.js | 16 - .../system/clone-null.js | 7 - .../system/coerce-id.js | 15 - .../system/debug/debug-adapter.js | 133 ----- .../system/diff-array.js | 58 --- .../system/identity-map.js | 49 -- .../system/internal-model-map.js | 133 ----- .../system/is-array-like.js | 33 -- .../system/map-with-default.js | 21 - addon/-record-data-rfc-private/system/map.js | 122 ----- .../system/model/errors.js | 417 ---------------- .../system/normalize-link.js | 21 - .../system/normalize-model-name.js | 18 - .../system/ordered-set.js | 37 -- .../system/record-array-manager.js | 404 --------------- .../system/record-arrays.js | 8 - .../adapter-populated-record-array.js | 92 ---- .../system/record-arrays/record-array.js | 266 ---------- .../system/references.js | 5 - .../system/references/record.js | 162 ------ .../system/relationship-meta.js | 96 ---- .../system/snapshot-record-array.js | 165 ------- .../system/store/common.js | 57 --- .../system/store/finders.js | 335 ------------- .../system/store/serializer-response.js | 95 ---- .../system/store/serializers.js | 17 - addon/-record-data-rfc-private/utils.js | 46 -- .../utils/parse-response-headers.js | 36 -- index.js | 21 +- 75 files changed, 17 insertions(+), 3819 deletions(-) rename addon/{-private => -legacy-private}/attr.js (100%) rename addon/{-private => -legacy-private}/index.js (100%) rename addon/{-private => -legacy-private}/system/many-array.js (100%) rename addon/{-private => -legacy-private}/system/model/internal-model.js (100%) rename addon/{-private => -legacy-private}/system/model/model.js (100%) rename addon/{-private => -legacy-private}/system/model/states.js (100%) rename addon/{-private => -legacy-private}/system/promise-proxies.js (100%) rename addon/{-private => -legacy-private}/system/references/belongs-to.js (100%) rename addon/{-private => -legacy-private}/system/references/has-many.js (100%) rename addon/{-private => -legacy-private}/system/references/reference.js (100%) rename addon/{-private => -legacy-private}/system/relationships/belongs-to.js (100%) rename addon/{-private => -legacy-private}/system/relationships/ext.js (100%) rename addon/{-private => -legacy-private}/system/relationships/has-many.js (100%) rename addon/{-private => -legacy-private}/system/relationships/relationship-payloads-manager.js (100%) rename addon/{-private => -legacy-private}/system/relationships/relationship-payloads.js (100%) rename addon/{-private => -legacy-private}/system/relationships/state/belongs-to.js (100%) rename addon/{-private => -legacy-private}/system/relationships/state/create.js (100%) rename addon/{-private => -legacy-private}/system/relationships/state/has-many.js (100%) rename addon/{-private => -legacy-private}/system/relationships/state/relationship.js (100%) rename addon/{-private => -legacy-private}/system/snapshot.js (100%) rename addon/{-private => -legacy-private}/system/store.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/attr.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/index.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/many-array.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/model/internal-model.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/model/model-data.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/model/model.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/model/states.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/promise-proxies.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/references/belongs-to.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/references/has-many.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/references/reference.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/relationships/belongs-to.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/relationships/ext.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/relationships/has-many.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/relationships/state/belongs-to.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/relationships/state/create.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/relationships/state/has-many.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/relationships/state/relationship.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/snapshot.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/store.js (100%) rename addon/{-record-data-rfc-private => -record-data-private}/system/store/model-data-wrapper.js (100%) delete mode 100644 addon/-record-data-rfc-private/adapters/build-url-mixin.js delete mode 100644 addon/-record-data-rfc-private/adapters/errors.js delete mode 100644 addon/-record-data-rfc-private/core.js delete mode 100644 addon/-record-data-rfc-private/features.js delete mode 100644 addon/-record-data-rfc-private/system/backburner.js delete mode 100644 addon/-record-data-rfc-private/system/clone-null.js delete mode 100644 addon/-record-data-rfc-private/system/coerce-id.js delete mode 100644 addon/-record-data-rfc-private/system/debug/debug-adapter.js delete mode 100644 addon/-record-data-rfc-private/system/diff-array.js delete mode 100644 addon/-record-data-rfc-private/system/identity-map.js delete mode 100644 addon/-record-data-rfc-private/system/internal-model-map.js delete mode 100644 addon/-record-data-rfc-private/system/is-array-like.js delete mode 100644 addon/-record-data-rfc-private/system/map-with-default.js delete mode 100644 addon/-record-data-rfc-private/system/map.js delete mode 100644 addon/-record-data-rfc-private/system/model/errors.js delete mode 100644 addon/-record-data-rfc-private/system/normalize-link.js delete mode 100644 addon/-record-data-rfc-private/system/normalize-model-name.js delete mode 100644 addon/-record-data-rfc-private/system/ordered-set.js delete mode 100644 addon/-record-data-rfc-private/system/record-array-manager.js delete mode 100644 addon/-record-data-rfc-private/system/record-arrays.js delete mode 100644 addon/-record-data-rfc-private/system/record-arrays/adapter-populated-record-array.js delete mode 100644 addon/-record-data-rfc-private/system/record-arrays/record-array.js delete mode 100644 addon/-record-data-rfc-private/system/references.js delete mode 100644 addon/-record-data-rfc-private/system/references/record.js delete mode 100644 addon/-record-data-rfc-private/system/relationship-meta.js delete mode 100644 addon/-record-data-rfc-private/system/snapshot-record-array.js delete mode 100644 addon/-record-data-rfc-private/system/store/common.js delete mode 100644 addon/-record-data-rfc-private/system/store/finders.js delete mode 100644 addon/-record-data-rfc-private/system/store/serializer-response.js delete mode 100644 addon/-record-data-rfc-private/system/store/serializers.js delete mode 100644 addon/-record-data-rfc-private/utils.js delete mode 100644 addon/-record-data-rfc-private/utils/parse-response-headers.js diff --git a/addon/-private/attr.js b/addon/-legacy-private/attr.js similarity index 100% rename from addon/-private/attr.js rename to addon/-legacy-private/attr.js diff --git a/addon/-private/index.js b/addon/-legacy-private/index.js similarity index 100% rename from addon/-private/index.js rename to addon/-legacy-private/index.js diff --git a/addon/-private/system/many-array.js b/addon/-legacy-private/system/many-array.js similarity index 100% rename from addon/-private/system/many-array.js rename to addon/-legacy-private/system/many-array.js diff --git a/addon/-private/system/model/internal-model.js b/addon/-legacy-private/system/model/internal-model.js similarity index 100% rename from addon/-private/system/model/internal-model.js rename to addon/-legacy-private/system/model/internal-model.js diff --git a/addon/-private/system/model/model.js b/addon/-legacy-private/system/model/model.js similarity index 100% rename from addon/-private/system/model/model.js rename to addon/-legacy-private/system/model/model.js diff --git a/addon/-private/system/model/states.js b/addon/-legacy-private/system/model/states.js similarity index 100% rename from addon/-private/system/model/states.js rename to addon/-legacy-private/system/model/states.js diff --git a/addon/-private/system/promise-proxies.js b/addon/-legacy-private/system/promise-proxies.js similarity index 100% rename from addon/-private/system/promise-proxies.js rename to addon/-legacy-private/system/promise-proxies.js diff --git a/addon/-private/system/references/belongs-to.js b/addon/-legacy-private/system/references/belongs-to.js similarity index 100% rename from addon/-private/system/references/belongs-to.js rename to addon/-legacy-private/system/references/belongs-to.js diff --git a/addon/-private/system/references/has-many.js b/addon/-legacy-private/system/references/has-many.js similarity index 100% rename from addon/-private/system/references/has-many.js rename to addon/-legacy-private/system/references/has-many.js diff --git a/addon/-private/system/references/reference.js b/addon/-legacy-private/system/references/reference.js similarity index 100% rename from addon/-private/system/references/reference.js rename to addon/-legacy-private/system/references/reference.js diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-legacy-private/system/relationships/belongs-to.js similarity index 100% rename from addon/-private/system/relationships/belongs-to.js rename to addon/-legacy-private/system/relationships/belongs-to.js diff --git a/addon/-private/system/relationships/ext.js b/addon/-legacy-private/system/relationships/ext.js similarity index 100% rename from addon/-private/system/relationships/ext.js rename to addon/-legacy-private/system/relationships/ext.js diff --git a/addon/-private/system/relationships/has-many.js b/addon/-legacy-private/system/relationships/has-many.js similarity index 100% rename from addon/-private/system/relationships/has-many.js rename to addon/-legacy-private/system/relationships/has-many.js diff --git a/addon/-private/system/relationships/relationship-payloads-manager.js b/addon/-legacy-private/system/relationships/relationship-payloads-manager.js similarity index 100% rename from addon/-private/system/relationships/relationship-payloads-manager.js rename to addon/-legacy-private/system/relationships/relationship-payloads-manager.js diff --git a/addon/-private/system/relationships/relationship-payloads.js b/addon/-legacy-private/system/relationships/relationship-payloads.js similarity index 100% rename from addon/-private/system/relationships/relationship-payloads.js rename to addon/-legacy-private/system/relationships/relationship-payloads.js diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-legacy-private/system/relationships/state/belongs-to.js similarity index 100% rename from addon/-private/system/relationships/state/belongs-to.js rename to addon/-legacy-private/system/relationships/state/belongs-to.js diff --git a/addon/-private/system/relationships/state/create.js b/addon/-legacy-private/system/relationships/state/create.js similarity index 100% rename from addon/-private/system/relationships/state/create.js rename to addon/-legacy-private/system/relationships/state/create.js diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-legacy-private/system/relationships/state/has-many.js similarity index 100% rename from addon/-private/system/relationships/state/has-many.js rename to addon/-legacy-private/system/relationships/state/has-many.js diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-legacy-private/system/relationships/state/relationship.js similarity index 100% rename from addon/-private/system/relationships/state/relationship.js rename to addon/-legacy-private/system/relationships/state/relationship.js diff --git a/addon/-private/system/snapshot.js b/addon/-legacy-private/system/snapshot.js similarity index 100% rename from addon/-private/system/snapshot.js rename to addon/-legacy-private/system/snapshot.js diff --git a/addon/-private/system/store.js b/addon/-legacy-private/system/store.js similarity index 100% rename from addon/-private/system/store.js rename to addon/-legacy-private/system/store.js diff --git a/addon/-record-data-rfc-private/attr.js b/addon/-record-data-private/attr.js similarity index 100% rename from addon/-record-data-rfc-private/attr.js rename to addon/-record-data-private/attr.js diff --git a/addon/-record-data-rfc-private/index.js b/addon/-record-data-private/index.js similarity index 100% rename from addon/-record-data-rfc-private/index.js rename to addon/-record-data-private/index.js diff --git a/addon/-record-data-rfc-private/system/many-array.js b/addon/-record-data-private/system/many-array.js similarity index 100% rename from addon/-record-data-rfc-private/system/many-array.js rename to addon/-record-data-private/system/many-array.js diff --git a/addon/-record-data-rfc-private/system/model/internal-model.js b/addon/-record-data-private/system/model/internal-model.js similarity index 100% rename from addon/-record-data-rfc-private/system/model/internal-model.js rename to addon/-record-data-private/system/model/internal-model.js diff --git a/addon/-record-data-rfc-private/system/model/model-data.js b/addon/-record-data-private/system/model/model-data.js similarity index 100% rename from addon/-record-data-rfc-private/system/model/model-data.js rename to addon/-record-data-private/system/model/model-data.js diff --git a/addon/-record-data-rfc-private/system/model/model.js b/addon/-record-data-private/system/model/model.js similarity index 100% rename from addon/-record-data-rfc-private/system/model/model.js rename to addon/-record-data-private/system/model/model.js diff --git a/addon/-record-data-rfc-private/system/model/states.js b/addon/-record-data-private/system/model/states.js similarity index 100% rename from addon/-record-data-rfc-private/system/model/states.js rename to addon/-record-data-private/system/model/states.js diff --git a/addon/-record-data-rfc-private/system/promise-proxies.js b/addon/-record-data-private/system/promise-proxies.js similarity index 100% rename from addon/-record-data-rfc-private/system/promise-proxies.js rename to addon/-record-data-private/system/promise-proxies.js diff --git a/addon/-record-data-rfc-private/system/references/belongs-to.js b/addon/-record-data-private/system/references/belongs-to.js similarity index 100% rename from addon/-record-data-rfc-private/system/references/belongs-to.js rename to addon/-record-data-private/system/references/belongs-to.js diff --git a/addon/-record-data-rfc-private/system/references/has-many.js b/addon/-record-data-private/system/references/has-many.js similarity index 100% rename from addon/-record-data-rfc-private/system/references/has-many.js rename to addon/-record-data-private/system/references/has-many.js diff --git a/addon/-record-data-rfc-private/system/references/reference.js b/addon/-record-data-private/system/references/reference.js similarity index 100% rename from addon/-record-data-rfc-private/system/references/reference.js rename to addon/-record-data-private/system/references/reference.js diff --git a/addon/-record-data-rfc-private/system/relationships/belongs-to.js b/addon/-record-data-private/system/relationships/belongs-to.js similarity index 100% rename from addon/-record-data-rfc-private/system/relationships/belongs-to.js rename to addon/-record-data-private/system/relationships/belongs-to.js diff --git a/addon/-record-data-rfc-private/system/relationships/ext.js b/addon/-record-data-private/system/relationships/ext.js similarity index 100% rename from addon/-record-data-rfc-private/system/relationships/ext.js rename to addon/-record-data-private/system/relationships/ext.js diff --git a/addon/-record-data-rfc-private/system/relationships/has-many.js b/addon/-record-data-private/system/relationships/has-many.js similarity index 100% rename from addon/-record-data-rfc-private/system/relationships/has-many.js rename to addon/-record-data-private/system/relationships/has-many.js diff --git a/addon/-record-data-rfc-private/system/relationships/state/belongs-to.js b/addon/-record-data-private/system/relationships/state/belongs-to.js similarity index 100% rename from addon/-record-data-rfc-private/system/relationships/state/belongs-to.js rename to addon/-record-data-private/system/relationships/state/belongs-to.js diff --git a/addon/-record-data-rfc-private/system/relationships/state/create.js b/addon/-record-data-private/system/relationships/state/create.js similarity index 100% rename from addon/-record-data-rfc-private/system/relationships/state/create.js rename to addon/-record-data-private/system/relationships/state/create.js diff --git a/addon/-record-data-rfc-private/system/relationships/state/has-many.js b/addon/-record-data-private/system/relationships/state/has-many.js similarity index 100% rename from addon/-record-data-rfc-private/system/relationships/state/has-many.js rename to addon/-record-data-private/system/relationships/state/has-many.js diff --git a/addon/-record-data-rfc-private/system/relationships/state/relationship.js b/addon/-record-data-private/system/relationships/state/relationship.js similarity index 100% rename from addon/-record-data-rfc-private/system/relationships/state/relationship.js rename to addon/-record-data-private/system/relationships/state/relationship.js diff --git a/addon/-record-data-rfc-private/system/snapshot.js b/addon/-record-data-private/system/snapshot.js similarity index 100% rename from addon/-record-data-rfc-private/system/snapshot.js rename to addon/-record-data-private/system/snapshot.js diff --git a/addon/-record-data-rfc-private/system/store.js b/addon/-record-data-private/system/store.js similarity index 100% rename from addon/-record-data-rfc-private/system/store.js rename to addon/-record-data-private/system/store.js diff --git a/addon/-record-data-rfc-private/system/store/model-data-wrapper.js b/addon/-record-data-private/system/store/model-data-wrapper.js similarity index 100% rename from addon/-record-data-rfc-private/system/store/model-data-wrapper.js rename to addon/-record-data-private/system/store/model-data-wrapper.js diff --git a/addon/-record-data-rfc-private/adapters/build-url-mixin.js b/addon/-record-data-rfc-private/adapters/build-url-mixin.js deleted file mode 100644 index d1552ae675f..00000000000 --- a/addon/-record-data-rfc-private/adapters/build-url-mixin.js +++ /dev/null @@ -1,453 +0,0 @@ -import { camelize } from '@ember/string'; -import Mixin from '@ember/object/mixin'; -import { get } from '@ember/object'; -import { pluralize } from 'ember-inflector'; - -/** - - WARNING: This interface is likely to change in order to accomodate https://github.com/emberjs/rfcs/pull/4 - - ## Using BuildURLMixin - - To use url building, include the mixin when extending an adapter, and call `buildURL` where needed. - The default behaviour is designed for RESTAdapter. - - ### Example - - ```javascript - export default DS.Adapter.extend(BuildURLMixin, { - findRecord: function(store, type, id, snapshot) { - var url = this.buildURL(type.modelName, id, snapshot, 'findRecord'); - return this.ajax(url, 'GET'); - } - }); - ``` - - ### Attributes - - The `host` and `namespace` attributes will be used if defined, and are optional. - - @class BuildURLMixin - @namespace DS -*/ -export default Mixin.create({ - /** - Builds a URL for a given type and optional ID. - - By default, it pluralizes the type's name (for example, 'post' - becomes 'posts' and 'person' becomes 'people'). To override the - pluralization see [pathForType](#method_pathForType). - - If an ID is specified, it adds the ID to the path generated - for the type, separated by a `/`. - - When called by RESTAdapter.findMany() the `id` and `snapshot` parameters - will be arrays of ids and snapshots. - - @method buildURL - @param {String} modelName - @param {(String|Array|Object)} id single id or array of ids or query - @param {(DS.Snapshot|Array)} snapshot single snapshot or array of snapshots - @param {String} requestType - @param {Object} query object of query parameters to send for query requests. - @return {String} url - */ - buildURL(modelName, id, snapshot, requestType, query) { - switch (requestType) { - case 'findRecord': - return this.urlForFindRecord(id, modelName, snapshot); - case 'findAll': - return this.urlForFindAll(modelName, snapshot); - case 'query': - return this.urlForQuery(query, modelName); - case 'queryRecord': - return this.urlForQueryRecord(query, modelName); - case 'findMany': - return this.urlForFindMany(id, modelName, snapshot); - case 'findHasMany': - return this.urlForFindHasMany(id, modelName, snapshot); - case 'findBelongsTo': - return this.urlForFindBelongsTo(id, modelName, snapshot); - case 'createRecord': - return this.urlForCreateRecord(modelName, snapshot); - case 'updateRecord': - return this.urlForUpdateRecord(id, modelName, snapshot); - case 'deleteRecord': - return this.urlForDeleteRecord(id, modelName, snapshot); - default: - return this._buildURL(modelName, id); - } - }, - - /** - @method _buildURL - @private - @param {String} modelName - @param {String} id - @return {String} url - */ - _buildURL(modelName, id) { - let path; - let url = []; - let host = get(this, 'host'); - let prefix = this.urlPrefix(); - - if (modelName) { - path = this.pathForType(modelName); - if (path) { - url.push(path); - } - } - - if (id) { - url.push(encodeURIComponent(id)); - } - if (prefix) { - url.unshift(prefix); - } - - url = url.join('/'); - if (!host && url && url.charAt(0) !== '/') { - url = '/' + url; - } - - return url; - }, - - /** - Builds a URL for a `store.findRecord(type, id)` call. - - Example: - - ```app/adapters/user.js - import DS from 'ember-data'; - - export default DS.JSONAPIAdapter.extend({ - urlForFindRecord(id, modelName, snapshot) { - let baseUrl = this.buildURL(modelName, id, snapshot); - return `${baseUrl}/users/${snapshot.adapterOptions.user_id}/playlists/${id}`; - } - }); - ``` - - @method urlForFindRecord - @param {String} id - @param {String} modelName - @param {DS.Snapshot} snapshot - @return {String} url - - */ - urlForFindRecord(id, modelName, snapshot) { - return this._buildURL(modelName, id); - }, - - /** - Builds a URL for a `store.findAll(type)` call. - - Example: - - ```app/adapters/comment.js - import DS from 'ember-data'; - - export default DS.JSONAPIAdapter.extend({ - urlForFindAll(modelName, snapshot) { - return 'data/comments.json'; - } - }); - ``` - - @method urlForFindAll - @param {String} modelName - @param {DS.SnapshotRecordArray} snapshot - @return {String} url - */ - urlForFindAll(modelName, snapshot) { - return this._buildURL(modelName); - }, - - /** - Builds a URL for a `store.query(type, query)` call. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - host: 'https://api.github.com', - urlForQuery (query, modelName) { - switch(modelName) { - case 'repo': - return `https://api.github.com/orgs/${query.orgId}/repos`; - default: - return this._super(...arguments); - } - } - }); - ``` - - @method urlForQuery - @param {Object} query - @param {String} modelName - @return {String} url - */ - urlForQuery(query, modelName) { - return this._buildURL(modelName); - }, - - /** - Builds a URL for a `store.queryRecord(type, query)` call. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - urlForQueryRecord({ slug }, modelName) { - let baseUrl = this.buildURL(); - return `${baseUrl}/${encodeURIComponent(slug)}`; - } - }); - ``` - - @method urlForQueryRecord - @param {Object} query - @param {String} modelName - @return {String} url - */ - urlForQueryRecord(query, modelName) { - return this._buildURL(modelName); - }, - - /** - Builds a URL for coalesceing multiple `store.findRecord(type, id)` - records into 1 request when the adapter's `coalesceFindRequests` - property is true. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - urlForFindMany(ids, modelName) { - let baseUrl = this.buildURL(); - return `${baseUrl}/coalesce`; - } - }); - ``` - - @method urlForFindMany - @param {Array} ids - @param {String} modelName - @param {Array} snapshots - @return {String} url - */ - urlForFindMany(ids, modelName, snapshots) { - return this._buildURL(modelName); - }, - - /** - Builds a URL for fetching a async hasMany relationship when a url - is not provided by the server. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.JSONAPIAdapter.extend({ - urlForFindHasMany(id, modelName, snapshot) { - let baseUrl = this.buildURL(id, modelName); - return `${baseUrl}/relationships`; - } - }); - ``` - - @method urlForFindHasMany - @param {String} id - @param {String} modelName - @param {DS.Snapshot} snapshot - @return {String} url - */ - urlForFindHasMany(id, modelName, snapshot) { - return this._buildURL(modelName, id); - }, - - /** - Builds a URL for fetching a async belongsTo relationship when a url - is not provided by the server. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.JSONAPIAdapter.extend({ - urlForFindBelongsTo(id, modelName, snapshot) { - let baseUrl = this.buildURL(id, modelName); - return `${baseUrl}/relationships`; - } - }); - ``` - - @method urlForFindBelongsTo - @param {String} id - @param {String} modelName - @param {DS.Snapshot} snapshot - @return {String} url - */ - urlForFindBelongsTo(id, modelName, snapshot) { - return this._buildURL(modelName, id); - }, - - /** - Builds a URL for a `record.save()` call when the record was created - locally using `store.createRecord()`. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - urlForCreateRecord(modelName, snapshot) { - return this._super(...arguments) + '/new'; - } - }); - ``` - - @method urlForCreateRecord - @param {String} modelName - @param {DS.Snapshot} snapshot - @return {String} url - */ - urlForCreateRecord(modelName, snapshot) { - return this._buildURL(modelName); - }, - - /** - Builds a URL for a `record.save()` call when the record has been update locally. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - urlForUpdateRecord(id, modelName, snapshot) { - return `/${id}/feed?access_token=${snapshot.adapterOptions.token}`; - } - }); - ``` - - @method urlForUpdateRecord - @param {String} id - @param {String} modelName - @param {DS.Snapshot} snapshot - @return {String} url - */ - urlForUpdateRecord(id, modelName, snapshot) { - return this._buildURL(modelName, id); - }, - - /** - Builds a URL for a `record.save()` call when the record has been deleted locally. - - Example: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - urlForDeleteRecord(id, modelName, snapshot) { - return this._super(...arguments) + '/destroy'; - } - }); - ``` - - @method urlForDeleteRecord - @param {String} id - @param {String} modelName - @param {DS.Snapshot} snapshot - @return {String} url - */ - urlForDeleteRecord(id, modelName, snapshot) { - return this._buildURL(modelName, id); - }, - - /** - @method urlPrefix - @private - @param {String} path - @param {String} parentURL - @return {String} urlPrefix - */ - urlPrefix(path, parentURL) { - let host = get(this, 'host'); - let namespace = get(this, 'namespace'); - - if (!host || host === '/') { - host = ''; - } - - if (path) { - // Protocol relative url - if (/^\/\//.test(path) || /http(s)?:\/\//.test(path)) { - // Do nothing, the full host is already included. - return path; - - // Absolute path - } else if (path.charAt(0) === '/') { - return `${host}${path}`; - // Relative path - } else { - return `${parentURL}/${path}`; - } - } - - // No path provided - let url = []; - if (host) { - url.push(host); - } - if (namespace) { - url.push(namespace); - } - return url.join('/'); - }, - - /** - Determines the pathname for a given type. - - By default, it pluralizes the type's name (for example, - 'post' becomes 'posts' and 'person' becomes 'people'). - - ### Pathname customization - - For example if you have an object LineItem with an - endpoint of "/line_items/". - - ```app/adapters/application.js - import DS from 'ember-data'; - import { decamelize } from '@ember/string'; - import { pluralize } from 'ember-inflector'; - - export default DS.RESTAdapter.extend({ - pathForType: function(modelName) { - var decamelized = decamelize(modelName); - return pluralize(decamelized); - } - }); - ``` - - @method pathForType - @param {String} modelName - @return {String} path - **/ - pathForType(modelName) { - let camelized = camelize(modelName); - return pluralize(camelized); - }, -}); diff --git a/addon/-record-data-rfc-private/adapters/errors.js b/addon/-record-data-rfc-private/adapters/errors.js deleted file mode 100644 index 8cfd7b978dd..00000000000 --- a/addon/-record-data-rfc-private/adapters/errors.js +++ /dev/null @@ -1,464 +0,0 @@ -import { makeArray } from '@ember/array'; -import { isPresent } from '@ember/utils'; -import EmberError from '@ember/error'; -import { assert } from '@ember/debug'; - -const SOURCE_POINTER_REGEXP = /^\/?data\/(attributes|relationships)\/(.*)/; -const SOURCE_POINTER_PRIMARY_REGEXP = /^\/?data/; -const PRIMARY_ATTRIBUTE_KEY = 'base'; - -/** - A `DS.AdapterError` is used by an adapter to signal that an error occurred - during a request to an external API. It indicates a generic error, and - subclasses are used to indicate specific error states. The following - subclasses are provided: - - - `DS.InvalidError` - - `DS.TimeoutError` - - `DS.AbortError` - - `DS.UnauthorizedError` - - `DS.ForbiddenError` - - `DS.NotFoundError` - - `DS.ConflictError` - - `DS.ServerError` - - To create a custom error to signal a specific error state in communicating - with an external API, extend the `DS.AdapterError`. For example if the - external API exclusively used HTTP `503 Service Unavailable` to indicate - it was closed for maintenance: - - ```app/adapters/maintenance-error.js - import DS from 'ember-data'; - - export default DS.AdapterError.extend({ message: "Down for maintenance." }); - ``` - - This error would then be returned by an adapter's `handleResponse` method: - - ```app/adapters/application.js - import DS from 'ember-data'; - import MaintenanceError from './maintenance-error'; - - export default DS.JSONAPIAdapter.extend({ - handleResponse(status) { - if (503 === status) { - return new MaintenanceError(); - } - - return this._super(...arguments); - } - }); - ``` - - And can then be detected in an application and used to send the user to an - `under-maintenance` route: - - ```app/routes/application.js - import Route from '@ember/routing/route'; - import MaintenanceError from '../adapters/maintenance-error'; - - export default Route.extend({ - actions: { - error(error, transition) { - if (error instanceof MaintenanceError) { - this.transitionTo('under-maintenance'); - return; - } - - // ...other error handling logic - } - } - }); - ``` - - @class AdapterError - @namespace DS -*/ -export function AdapterError(errors, message = 'Adapter operation failed') { - this.isAdapterError = true; - EmberError.call(this, message); - - this.errors = errors || [ - { - title: 'Adapter Error', - detail: message, - }, - ]; -} - -function extendFn(ErrorClass) { - return function({ message: defaultMessage } = {}) { - return extend(ErrorClass, defaultMessage); - }; -} - -function extend(ParentErrorClass, defaultMessage) { - let ErrorClass = function(errors, message) { - assert('`AdapterError` expects json-api formatted errors array.', Array.isArray(errors || [])); - ParentErrorClass.call(this, errors, message || defaultMessage); - }; - ErrorClass.prototype = Object.create(ParentErrorClass.prototype); - ErrorClass.extend = extendFn(ErrorClass); - - return ErrorClass; -} - -AdapterError.prototype = Object.create(EmberError.prototype); - -AdapterError.extend = extendFn(AdapterError); - -/** - A `DS.InvalidError` is used by an adapter to signal the external API - was unable to process a request because the content was not - semantically correct or meaningful per the API. Usually this means a - record failed some form of server side validation. When a promise - from an adapter is rejected with a `DS.InvalidError` the record will - transition to the `invalid` state and the errors will be set to the - `errors` property on the record. - - For Ember Data to correctly map errors to their corresponding - properties on the model, Ember Data expects each error to be - a valid json-api error object with a `source/pointer` that matches - the property name. For example if you had a Post model that - looked like this. - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - title: DS.attr('string'), - content: DS.attr('string') - }); - ``` - - To show an error from the server related to the `title` and - `content` properties your adapter could return a promise that - rejects with a `DS.InvalidError` object that looks like this: - - ```app/adapters/post.js - import RSVP from 'RSVP'; - import DS from 'ember-data'; - - export default DS.RESTAdapter.extend({ - updateRecord() { - // Fictional adapter that always rejects - return RSVP.reject(new DS.InvalidError([ - { - detail: 'Must be unique', - source: { pointer: '/data/attributes/title' } - }, - { - detail: 'Must not be blank', - source: { pointer: '/data/attributes/content'} - } - ])); - } - }); - ``` - - Your backend may use different property names for your records the - store will attempt extract and normalize the errors using the - serializer's `extractErrors` method before the errors get added to - the the model. As a result, it is safe for the `InvalidError` to - wrap the error payload unaltered. - - @class InvalidError - @namespace DS -*/ -export const InvalidError = extend( - AdapterError, - 'The adapter rejected the commit because it was invalid' -); - -/** - A `DS.TimeoutError` is used by an adapter to signal that a request - to the external API has timed out. I.e. no response was received from - the external API within an allowed time period. - - An example use case would be to warn the user to check their internet - connection if an adapter operation has timed out: - - ```app/routes/application.js - import Route from '@ember/routing/route'; - import DS from 'ember-data'; - - const { TimeoutError } = DS; - - export default Route.extend({ - actions: { - error(error, transition) { - if (error instanceof TimeoutError) { - // alert the user - alert('Are you still connected to the internet?'); - return; - } - - // ...other error handling logic - } - } - }); - ``` - - @class TimeoutError - @namespace DS -*/ -export const TimeoutError = extend(AdapterError, 'The adapter operation timed out'); - -/** - A `DS.AbortError` is used by an adapter to signal that a request to - the external API was aborted. For example, this can occur if the user - navigates away from the current page after a request to the external API - has been initiated but before a response has been received. - - @class AbortError - @namespace DS -*/ -export const AbortError = extend(AdapterError, 'The adapter operation was aborted'); - -/** - A `DS.UnauthorizedError` equates to a HTTP `401 Unauthorized` response - status. It is used by an adapter to signal that a request to the external - API was rejected because authorization is required and has failed or has not - yet been provided. - - An example use case would be to redirect the user to a log in route if a - request is unauthorized: - - ```app/routes/application.js - import Route from '@ember/routing/route'; - import DS from 'ember-data'; - - const { UnauthorizedError } = DS; - - export default Route.extend({ - actions: { - error(error, transition) { - if (error instanceof UnauthorizedError) { - // go to the sign in route - this.transitionTo('login'); - return; - } - - // ...other error handling logic - } - } - }); - ``` - - @class UnauthorizedError - @namespace DS -*/ -export const UnauthorizedError = extend(AdapterError, 'The adapter operation is unauthorized'); - -/** - A `DS.ForbiddenError` equates to a HTTP `403 Forbidden` response status. - It is used by an adapter to signal that a request to the external API was - valid but the server is refusing to respond to it. If authorization was - provided and is valid, then the authenticated user does not have the - necessary permissions for the request. - - @class ForbiddenError - @namespace DS -*/ -export const ForbiddenError = extend(AdapterError, 'The adapter operation is forbidden'); - -/** - A `DS.NotFoundError` equates to a HTTP `404 Not Found` response status. - It is used by an adapter to signal that a request to the external API - was rejected because the resource could not be found on the API. - - An example use case would be to detect if the user has entered a route - for a specific model that does not exist. For example: - - ```app/routes/post.js - import Route from '@ember/routing/route'; - import DS from 'ember-data'; - - const { NotFoundError } = DS; - - export default Route.extend({ - model(params) { - return this.get('store').findRecord('post', params.post_id); - }, - - actions: { - error(error, transition) { - if (error instanceof NotFoundError) { - // redirect to a list of all posts instead - this.transitionTo('posts'); - } else { - // otherwise let the error bubble - return true; - } - } - } - }); - ``` - - @class NotFoundError - @namespace DS -*/ -export const NotFoundError = extend(AdapterError, 'The adapter could not find the resource'); - -/** - A `DS.ConflictError` equates to a HTTP `409 Conflict` response status. - It is used by an adapter to indicate that the request could not be processed - because of a conflict in the request. An example scenario would be when - creating a record with a client generated id but that id is already known - to the external API. - - @class ConflictError - @namespace DS -*/ -export const ConflictError = extend(AdapterError, 'The adapter operation failed due to a conflict'); - -/** - A `DS.ServerError` equates to a HTTP `500 Internal Server Error` response - status. It is used by the adapter to indicate that a request has failed - because of an error in the external API. - - @class ServerError - @namespace DS -*/ -export const ServerError = extend( - AdapterError, - 'The adapter operation failed due to a server error' -); - -/** - Convert an hash of errors into an array with errors in JSON-API format. - - ```javascript - import DS from 'ember-data'; - - const { errorsHashToArray } = DS; - - let errors = { - base: 'Invalid attributes on saving this record', - name: 'Must be present', - age: ['Must be present', 'Must be a number'] - }; - - let errorsArray = errorsHashToArray(errors); - // [ - // { - // title: "Invalid Document", - // detail: "Invalid attributes on saving this record", - // source: { pointer: "/data" } - // }, - // { - // title: "Invalid Attribute", - // detail: "Must be present", - // source: { pointer: "/data/attributes/name" } - // }, - // { - // title: "Invalid Attribute", - // detail: "Must be present", - // source: { pointer: "/data/attributes/age" } - // }, - // { - // title: "Invalid Attribute", - // detail: "Must be a number", - // source: { pointer: "/data/attributes/age" } - // } - // ] - ``` - - @method errorsHashToArray - @public - @namespace - @for DS - @param {Object} errors hash with errors as properties - @return {Array} array of errors in JSON-API format -*/ -export function errorsHashToArray(errors) { - let out = []; - - if (isPresent(errors)) { - Object.keys(errors).forEach(key => { - let messages = makeArray(errors[key]); - for (let i = 0; i < messages.length; i++) { - let title = 'Invalid Attribute'; - let pointer = `/data/attributes/${key}`; - if (key === PRIMARY_ATTRIBUTE_KEY) { - title = 'Invalid Document'; - pointer = `/data`; - } - out.push({ - title: title, - detail: messages[i], - source: { - pointer: pointer, - }, - }); - } - }); - } - - return out; -} - -/** - Convert an array of errors in JSON-API format into an object. - - ```javascript - import DS from 'ember-data'; - - const { errorsArrayToHash } = DS; - - let errorsArray = [ - { - title: 'Invalid Attribute', - detail: 'Must be present', - source: { pointer: '/data/attributes/name' } - }, - { - title: 'Invalid Attribute', - detail: 'Must be present', - source: { pointer: '/data/attributes/age' } - }, - { - title: 'Invalid Attribute', - detail: 'Must be a number', - source: { pointer: '/data/attributes/age' } - } - ]; - - let errors = errorsArrayToHash(errorsArray); - // { - // "name": ["Must be present"], - // "age": ["Must be present", "must be a number"] - // } - ``` - - @method errorsArrayToHash - @public - @namespace - @for DS - @param {Array} errors array of errors in JSON-API format - @return {Object} -*/ -export function errorsArrayToHash(errors) { - let out = {}; - - if (isPresent(errors)) { - errors.forEach(error => { - if (error.source && error.source.pointer) { - let key = error.source.pointer.match(SOURCE_POINTER_REGEXP); - - if (key) { - key = key[2]; - } else if (error.source.pointer.search(SOURCE_POINTER_PRIMARY_REGEXP) !== -1) { - key = PRIMARY_ATTRIBUTE_KEY; - } - - if (key) { - out[key] = out[key] || []; - out[key].push(error.detail || error.title); - } - } - }); - } - - return out; -} diff --git a/addon/-record-data-rfc-private/core.js b/addon/-record-data-rfc-private/core.js deleted file mode 100644 index 70816f3c203..00000000000 --- a/addon/-record-data-rfc-private/core.js +++ /dev/null @@ -1,29 +0,0 @@ -import Ember from 'ember'; -import VERSION from 'ember-data/version'; - -/** - @module ember-data -*/ - -/** - All Ember Data classes, methods and functions are defined inside of this namespace. - - @class DS - @static -*/ - -/** - @property VERSION - @type String - @static -*/ -const DS = Ember.Namespace.create({ - VERSION: VERSION, - name: 'DS', -}); - -if (Ember.libraries) { - Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); -} - -export default DS; diff --git a/addon/-record-data-rfc-private/features.js b/addon/-record-data-rfc-private/features.js deleted file mode 100644 index 8e023905a04..00000000000 --- a/addon/-record-data-rfc-private/features.js +++ /dev/null @@ -1,5 +0,0 @@ -import Ember from 'ember'; - -export default function isEnabled() { - return Ember.FEATURES.isEnabled(...arguments); -} diff --git a/addon/-record-data-rfc-private/system/backburner.js b/addon/-record-data-rfc-private/system/backburner.js deleted file mode 100644 index 7ac43f9b390..00000000000 --- a/addon/-record-data-rfc-private/system/backburner.js +++ /dev/null @@ -1,16 +0,0 @@ -import Ember from 'ember'; -import { DEBUG } from '@glimmer/env'; - -const backburner = new Ember._Backburner([ - 'normalizeRelationships', - 'syncRelationships', - 'finished', -]); - -if (DEBUG) { - Ember.Test.registerWaiter(() => { - return !backburner.currentInstance && !backburner.hasTimers(); - }); -} - -export default backburner; diff --git a/addon/-record-data-rfc-private/system/clone-null.js b/addon/-record-data-rfc-private/system/clone-null.js deleted file mode 100644 index 9972c430fef..00000000000 --- a/addon/-record-data-rfc-private/system/clone-null.js +++ /dev/null @@ -1,7 +0,0 @@ -export default function cloneNull(source) { - let clone = Object.create(null); - for (let key in source) { - clone[key] = source[key]; - } - return clone; -} diff --git a/addon/-record-data-rfc-private/system/coerce-id.js b/addon/-record-data-rfc-private/system/coerce-id.js deleted file mode 100644 index 18173352148..00000000000 --- a/addon/-record-data-rfc-private/system/coerce-id.js +++ /dev/null @@ -1,15 +0,0 @@ -// Used by the store to normalize IDs entering the store. Despite the fact -// that developers may provide IDs as numbers (e.g., `store.findRecord('person', 1)`), -// it is important that internally we use strings, since IDs may be serialized -// and lose type information. For example, Ember's router may put a record's -// ID into the URL, and if we later try to deserialize that URL and find the -// corresponding record, we will not know if it is a string or a number. -export default function coerceId(id) { - if (id === null || id === undefined || id === '') { - return null; - } - if (typeof id === 'string') { - return id; - } - return '' + id; -} diff --git a/addon/-record-data-rfc-private/system/debug/debug-adapter.js b/addon/-record-data-rfc-private/system/debug/debug-adapter.js deleted file mode 100644 index 2904a93427f..00000000000 --- a/addon/-record-data-rfc-private/system/debug/debug-adapter.js +++ /dev/null @@ -1,133 +0,0 @@ -/** - @module ember-data -*/ -import { addObserver, removeObserver } from '@ember/object/observers'; - -import { A } from '@ember/array'; -import DataAdapter from '@ember/debug/data-adapter'; -import { capitalize, underscore } from '@ember/string'; -import { assert } from '@ember/debug'; -import { get } from '@ember/object'; -import Model from '../model/model'; - -/* - Extend `Ember.DataAdapter` with ED specific code. - - @class DebugAdapter - @namespace DS - @extends Ember.DataAdapter - @private -*/ -export default DataAdapter.extend({ - getFilters() { - return [ - { name: 'isNew', desc: 'New' }, - { name: 'isModified', desc: 'Modified' }, - { name: 'isClean', desc: 'Clean' }, - ]; - }, - - detect(typeClass) { - return typeClass !== Model && Model.detect(typeClass); - }, - - columnsForType(typeClass) { - let columns = [ - { - name: 'id', - desc: 'Id', - }, - ]; - let count = 0; - let self = this; - get(typeClass, 'attributes').forEach((meta, name) => { - if (count++ > self.attributeLimit) { - return false; - } - let desc = capitalize(underscore(name).replace('_', ' ')); - columns.push({ name: name, desc: desc }); - }); - return columns; - }, - - getRecords(modelClass, modelName) { - if (arguments.length < 2) { - // Legacy Ember.js < 1.13 support - let containerKey = modelClass._debugContainerKey; - if (containerKey) { - let match = containerKey.match(/model:(.*)/); - if (match !== null) { - modelName = match[1]; - } - } - } - assert( - 'Cannot find model name. Please upgrade to Ember.js >= 1.13 for Ember Inspector support', - !!modelName - ); - return this.get('store').peekAll(modelName); - }, - - getRecordColumnValues(record) { - let count = 0; - let columnValues = { id: get(record, 'id') }; - - record.eachAttribute(key => { - if (count++ > this.attributeLimit) { - return false; - } - columnValues[key] = get(record, key); - }); - return columnValues; - }, - - getRecordKeywords(record) { - let keywords = []; - let keys = A(['id']); - record.eachAttribute(key => keys.push(key)); - keys.forEach(key => keywords.push(get(record, key))); - return keywords; - }, - - getRecordFilterValues(record) { - return { - isNew: record.get('isNew'), - isModified: record.get('hasDirtyAttributes') && !record.get('isNew'), - isClean: !record.get('hasDirtyAttributes'), - }; - }, - - getRecordColor(record) { - let color = 'black'; - if (record.get('isNew')) { - color = 'green'; - } else if (record.get('hasDirtyAttributes')) { - color = 'blue'; - } - return color; - }, - - observeRecord(record, recordUpdated) { - let releaseMethods = A(); - let keysToObserve = A(['id', 'isNew', 'hasDirtyAttributes']); - - record.eachAttribute(key => keysToObserve.push(key)); - let adapter = this; - - keysToObserve.forEach(function(key) { - let handler = function() { - recordUpdated(adapter.wrapRecord(record)); - }; - addObserver(record, key, handler); - releaseMethods.push(function() { - removeObserver(record, key, handler); - }); - }); - - let release = function() { - releaseMethods.forEach(fn => fn()); - }; - - return release; - }, -}); diff --git a/addon/-record-data-rfc-private/system/diff-array.js b/addon/-record-data-rfc-private/system/diff-array.js deleted file mode 100644 index e935a525b6b..00000000000 --- a/addon/-record-data-rfc-private/system/diff-array.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - @namespace - @method diffArray - @private - @param {Array} oldArray the old array - @param {Array} newArray the new array - @return {hash} { - firstChangeIndex: , // null if no change - addedCount: , // 0 if no change - removedCount: // 0 if no change - } -*/ -export default function diffArray(oldArray, newArray) { - const oldLength = oldArray.length; - const newLength = newArray.length; - - const shortestLength = Math.min(oldLength, newLength); - let firstChangeIndex = null; // null signifies no changes - - // find the first change - for (let i = 0; i < shortestLength; i++) { - // compare each item in the array - if (oldArray[i] !== newArray[i]) { - firstChangeIndex = i; - break; - } - } - - if (firstChangeIndex === null && newLength !== oldLength) { - // no change found in the overlapping block - // and array lengths differ, - // so change starts at end of overlap - firstChangeIndex = shortestLength; - } - - let addedCount = 0; - let removedCount = 0; - if (firstChangeIndex !== null) { - // we found a change, find the end of the change - let unchangedEndBlockLength = shortestLength - firstChangeIndex; - // walk back from the end of both arrays until we find a change - for (let i = 1; i <= shortestLength; i++) { - // compare each item in the array - if (oldArray[oldLength - i] !== newArray[newLength - i]) { - unchangedEndBlockLength = i - 1; - break; - } - } - addedCount = newLength - unchangedEndBlockLength - firstChangeIndex; - removedCount = oldLength - unchangedEndBlockLength - firstChangeIndex; - } - - return { - firstChangeIndex, - addedCount, - removedCount, - }; -} diff --git a/addon/-record-data-rfc-private/system/identity-map.js b/addon/-record-data-rfc-private/system/identity-map.js deleted file mode 100644 index b649e31aedf..00000000000 --- a/addon/-record-data-rfc-private/system/identity-map.js +++ /dev/null @@ -1,49 +0,0 @@ -import InternalModelMap from './internal-model-map'; - -/** - `IdentityMap` is a custom storage map for records by modelName - used by `DS.Store`. - - @class IdentityMap - @private - */ -export default class IdentityMap { - constructor() { - this._map = Object.create(null); - } - - /** - Retrieves the `InternalModelMap` for a given modelName, - creating one if one did not already exist. This is - similar to `getWithDefault` or `get` on a `MapWithDefault` - - @method retrieve - @param modelName a previously normalized modelName - @return {InternalModelMap} the InternalModelMap for the given modelName - */ - retrieve(modelName) { - let map = this._map[modelName]; - - if (map === undefined) { - map = this._map[modelName] = new InternalModelMap(modelName); - } - - return map; - } - - /** - Clears the contents of all known `RecordMaps`, but does - not remove the InternalModelMap instances. - - @method clear - */ - clear() { - let map = this._map; - let keys = Object.keys(map); - - for (let i = 0; i < keys.length; i++) { - let key = keys[i]; - map[key].clear(); - } - } -} diff --git a/addon/-record-data-rfc-private/system/internal-model-map.js b/addon/-record-data-rfc-private/system/internal-model-map.js deleted file mode 100644 index 91272048fb3..00000000000 --- a/addon/-record-data-rfc-private/system/internal-model-map.js +++ /dev/null @@ -1,133 +0,0 @@ -import { assert } from '@ember/debug'; -import InternalModel from './model/internal-model'; - -/** - `InternalModelMap` is a custom storage map for internalModels of a given modelName - used by `IdentityMap`. - - It was extracted from an implicit pojo based "internalModel map" and preserves - that interface while we work towards a more official API. - - @class InternalModelMap - @private - */ -export default class InternalModelMap { - constructor(modelName) { - this.modelName = modelName; - this._idToModel = Object.create(null); - this._models = []; - this._metadata = null; - } - - /** - * @method get - * @param id {String} - * @return {InternalModel} - */ - get(id) { - return this._idToModel[id]; - } - - has(id) { - return !!this._idToModel[id]; - } - - get length() { - return this._models.length; - } - - set(id, internalModel) { - assert(`You cannot index an internalModel by an empty id'`, id); - assert( - `You cannot set an index for an internalModel to something other than an internalModel`, - internalModel instanceof InternalModel - ); - assert( - `You cannot set an index for an internalModel that is not in the InternalModelMap`, - this.contains(internalModel) - ); - assert( - `You cannot update the id index of an InternalModel once set. Attempted to update ${id}.`, - !this.has(id) || this.get(id) === internalModel - ); - - this._idToModel[id] = internalModel; - } - - add(internalModel, id) { - assert( - `You cannot re-add an already present InternalModel to the InternalModelMap.`, - !this.contains(internalModel) - ); - - if (id) { - assert( - `Duplicate InternalModel for ${this.modelName}:${id} detected.`, - !this.has(id) || this.get(id) === internalModel - ); - - this._idToModel[id] = internalModel; - } - - this._models.push(internalModel); - } - - remove(internalModel, id) { - delete this._idToModel[id]; - - let loc = this._models.indexOf(internalModel); - - if (loc !== -1) { - this._models.splice(loc, 1); - } - } - - contains(internalModel) { - return this._models.indexOf(internalModel) !== -1; - } - - /** - An array of all models of this modelName - @property models - @type Array - */ - get models() { - return this._models; - } - - /** - * meta information about internalModels - * @property metadata - * @type Object - */ - get metadata() { - return this._metadata || (this._metadata = Object.create(null)); - } - - /** - deprecated (and unsupported) way of accessing modelClass - - @property type - @deprecated - */ - get type() { - throw new Error('InternalModelMap.type is no longer available'); - } - - /** - Destroy all models in the internalModelTest and wipe metadata. - - @method clear - */ - clear() { - let models = this._models; - this._models = []; - - for (let i = 0; i < models.length; i++) { - let model = models[i]; - model.unloadRecord(); - } - - this._metadata = null; - } -} diff --git a/addon/-record-data-rfc-private/system/is-array-like.js b/addon/-record-data-rfc-private/system/is-array-like.js deleted file mode 100644 index b1faffab15f..00000000000 --- a/addon/-record-data-rfc-private/system/is-array-like.js +++ /dev/null @@ -1,33 +0,0 @@ -import { typeOf } from '@ember/utils'; -import EmberArray from '@ember/array'; - -/* - We're using this to detect arrays and "array-like" objects. - - This is a copy of the `isArray` method found in `ember-runtime/utils` as we're - currently unable to import non-exposed modules. - - This method was previously exposed as `Ember.isArray` but since - https://github.com/emberjs/ember.js/pull/11463 `Ember.isArray` is an alias of - `Array.isArray` hence removing the "array-like" part. - */ -export default function isArrayLike(obj) { - if (!obj || obj.setInterval) { - return false; - } - if (Array.isArray(obj)) { - return true; - } - if (EmberArray.detect(obj)) { - return true; - } - - let type = typeOf(obj); - if ('array' === type) { - return true; - } - if (obj.length !== undefined && 'object' === type) { - return true; - } - return false; -} diff --git a/addon/-record-data-rfc-private/system/map-with-default.js b/addon/-record-data-rfc-private/system/map-with-default.js deleted file mode 100644 index 69f397e06f3..00000000000 --- a/addon/-record-data-rfc-private/system/map-with-default.js +++ /dev/null @@ -1,21 +0,0 @@ -import Map from './map'; - -export default class MapWithDefault extends Map { - constructor(options) { - super(); - - this.defaultValue = options.defaultValue; - } - - get(key) { - let hasValue = this.has(key); - - if (hasValue) { - return super.get(key); - } else { - let defaultValue = this.defaultValue(key); - this.set(key, defaultValue); - return defaultValue; - } - } -} diff --git a/addon/-record-data-rfc-private/system/map.js b/addon/-record-data-rfc-private/system/map.js deleted file mode 100644 index c7c0be9846b..00000000000 --- a/addon/-record-data-rfc-private/system/map.js +++ /dev/null @@ -1,122 +0,0 @@ -import { deprecate } from '@ember/debug'; - -/* - ## Why does this exist?!? - - `Ember.Map` was a private API provided by Ember (for quite some time). - Unfortunately, ember-data made `Ember.Map` part of its public API surface via - documentation blocks. - - `Ember.Map` will be deprecated and removed from Ember "soon" - (https://github.com/emberjs/rfcs/pull/237) and we would like to confirm that - Ember Data will work without deprecation before and after that happens. - - `Ember.Map` differs from native `Map` in a few ways: - - * `Ember.Map` has custom `copy` and `isEmpty` methods which are not present in native `Map` - * `Ember.Map` adds a static `create` method (which simply instantiates itself with `new Ember.Map()`) - * `Ember.Map` does not accept constructor arguments - * `Ember.Map` does not have: - * `@@species` - * `@@iterator` - * `entries` - * `values` - - This implementation adds a deprecated backwards compatibility for: - - * `copy` - * `isEmpty` - - ## Why is this written this way?!? - - This is needed because `Map` requires instantiation with `new` and by default - Babel transpilation will do `superConstructor.apply(this, arguments)` which - throws an error with native `Map`. - - The desired code (if we lived in an "only native class" world) would be: - - ```js - export default class MapWithDeprecations extends Map { - constructor(options) { - super(); - this.defaultValue = options.defaultValue; - } - - get(key) { - let hasValue = this.has(key); - - if (hasValue) { - return super.get(key); - } else { - let defaultValue = this.defaultValue(key); - this.set(key, defaultValue); - return defaultValue; - } - } - } - ``` -*/ -export default class MapWithDeprecations { - constructor(options) { - this._map = new Map(); - } - - copy() { - deprecate( - 'Calling `.copy()` on a map generated by ember-data is deprecated, please migrate to using native Map functionality only.', - false, - { id: 'ember-data.map.copy', until: '3.5.0' } - ); - - // can't just pass `this._map` here because IE11 doesn't accept - // constructor args with its `Map` - let newMap = new MapWithDeprecations(); - this._map.forEach(function(value, key) { - newMap.set(key, value); - }); - - return newMap; - } - - isEmpty() { - deprecate( - 'Calling `.isEmpty()` on a map generated by ember-data is deprecated, please migrate to using native Map functionality only.', - false, - { id: 'ember-data.map.isEmpty', until: '3.5.0' } - ); - - return this.size === 0; - } - - // proxy all normal Map methods to the underlying Map - get size() { - return this._map.size; - } - clear() { - return this._map.clear(...arguments); - } - delete() { - return this._map.delete(...arguments); - } - entries() { - return this._map.entries(...arguments); - } - forEach() { - return this._map.forEach(...arguments); - } - get() { - return this._map.get(...arguments); - } - has() { - return this._map.has(...arguments); - } - keys() { - return this._map.keys(...arguments); - } - set() { - return this._map.set(...arguments); - } - values() { - return this._map.values(...arguments); - } -} diff --git a/addon/-record-data-rfc-private/system/model/errors.js b/addon/-record-data-rfc-private/system/model/errors.js deleted file mode 100644 index 005fb9ec7ca..00000000000 --- a/addon/-record-data-rfc-private/system/model/errors.js +++ /dev/null @@ -1,417 +0,0 @@ -import { mapBy, not } from '@ember/object/computed'; -import Evented from '@ember/object/evented'; -import ArrayProxy from '@ember/array/proxy'; -import { set, get, computed } from '@ember/object'; -import { makeArray, A } from '@ember/array'; -import MapWithDefault from '../map-with-default'; -import { warn } from '@ember/debug'; - -/** -@module ember-data -*/ - -/** - Holds validation errors for a given record, organized by attribute names. - - Every `DS.Model` has an `errors` property that is an instance of - `DS.Errors`. This can be used to display validation error - messages returned from the server when a `record.save()` rejects. - - For Example, if you had a `User` model that looked like this: - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - username: DS.attr('string'), - email: DS.attr('string') - }); - ``` - And you attempted to save a record that did not validate on the backend: - - ```javascript - let user = store.createRecord('user', { - username: 'tomster', - email: 'invalidEmail' - }); - user.save(); - ``` - - Your backend would be expected to return an error response that described - the problem, so that error messages can be generated on the app. - - API responses will be translated into instances of `DS.Errors` differently, - depending on the specific combination of adapter and serializer used. You - may want to check the documentation or the source code of the libraries - that you are using, to know how they expect errors to be communicated. - - Errors can be displayed to the user by accessing their property name - to get an array of all the error objects for that property. Each - error object is a JavaScript object with two keys: - - - `message` A string containing the error message from the backend - - `attribute` The name of the property associated with this error message - - ```handlebars - - {{#each model.errors.username as |error|}} -
      - {{error.message}} -
      - {{/each}} - - - {{#each model.errors.email as |error|}} -
      - {{error.message}} -
      - {{/each}} - ``` - - You can also access the special `messages` property on the error - object to get an array of all the error strings. - - ```handlebars - {{#each model.errors.messages as |message|}} -
      - {{message}} -
      - {{/each}} - ``` - - @class Errors - @namespace DS - @extends Ember.Object - @uses Ember.Enumerable - @uses Ember.Evented - */ -export default ArrayProxy.extend(Evented, { - /** - Register with target handler - - @method _registerHandlers - @private - */ - _registerHandlers(target, becameInvalid, becameValid) { - this.on('becameInvalid', target, becameInvalid); - this.on('becameValid', target, becameValid); - }, - - /** - @property errorsByAttributeName - @type {MapWithDefault} - @private - */ - errorsByAttributeName: computed(function() { - return new MapWithDefault({ - defaultValue() { - return A(); - }, - }); - }), - - /** - Returns errors for a given attribute - - ```javascript - let user = store.createRecord('user', { - username: 'tomster', - email: 'invalidEmail' - }); - user.save().catch(function(){ - user.get('errors').errorsFor('email'); // returns: - // [{attribute: "email", message: "Doesn't look like a valid email."}] - }); - ``` - - @method errorsFor - @param {String} attribute - @return {Array} - */ - errorsFor(attribute) { - return get(this, 'errorsByAttributeName').get(attribute); - }, - - /** - An array containing all of the error messages for this - record. This is useful for displaying all errors to the user. - - ```handlebars - {{#each model.errors.messages as |message|}} -
      - {{message}} -
      - {{/each}} - ``` - - @property messages - @type {Array} - */ - messages: mapBy('content', 'message'), - - /** - @property content - @type {Array} - @private - */ - content: computed(function() { - return A(); - }), - - /** - @method unknownProperty - @private - */ - unknownProperty(attribute) { - let errors = this.errorsFor(attribute); - if (errors.length === 0) { - return undefined; - } - return errors; - }, - - /** - Total number of errors. - - @property length - @type {Number} - @readOnly - */ - - /** - @property isEmpty - @type {Boolean} - @readOnly - */ - isEmpty: not('length').readOnly(), - - /** - Adds error messages to a given attribute and sends - `becameInvalid` event to the record. - - Example: - - ```javascript - if (!user.get('username') { - user.get('errors').add('username', 'This field is required'); - } - ``` - - @method add - @param {String} attribute - @param {(Array|String)} messages - @deprecated - */ - add(attribute, messages) { - warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.add', - }); - - let wasEmpty = get(this, 'isEmpty'); - - this._add(attribute, messages); - - if (wasEmpty && !get(this, 'isEmpty')) { - this.trigger('becameInvalid'); - } - }, - - /** - Adds error messages to a given attribute without sending event. - - @method _add - @private - */ - _add(attribute, messages) { - messages = this._findOrCreateMessages(attribute, messages); - this.addObjects(messages); - get(this, 'errorsByAttributeName') - .get(attribute) - .addObjects(messages); - - this.notifyPropertyChange(attribute); - }, - - /** - @method _findOrCreateMessages - @private - */ - _findOrCreateMessages(attribute, messages) { - let errors = this.errorsFor(attribute); - let messagesArray = makeArray(messages); - let _messages = new Array(messagesArray.length); - - for (let i = 0; i < messagesArray.length; i++) { - let message = messagesArray[i]; - let err = errors.findBy('message', message); - if (err) { - _messages[i] = err; - } else { - _messages[i] = { - attribute: attribute, - message: message, - }; - } - } - - return _messages; - }, - - /** - Removes all error messages from the given attribute and sends - `becameValid` event to the record if there no more errors left. - - Example: - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - email: DS.attr('string'), - twoFactorAuth: DS.attr('boolean'), - phone: DS.attr('string') - }); - ``` - - ```app/routes/user/edit.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - actions: { - save: function(user) { - if (!user.get('twoFactorAuth')) { - user.get('errors').remove('phone'); - } - user.save(); - } - } - }); - ``` - - @method remove - @param {String} attribute - @deprecated - */ - remove(attribute) { - warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.remove', - }); - - if (get(this, 'isEmpty')) { - return; - } - - this._remove(attribute); - - if (get(this, 'isEmpty')) { - this.trigger('becameValid'); - } - }, - - /** - Removes all error messages from the given attribute without sending event. - - @method _remove - @private - */ - _remove(attribute) { - if (get(this, 'isEmpty')) { - return; - } - - let content = this.rejectBy('attribute', attribute); - set(this, 'content', content); - get(this, 'errorsByAttributeName').delete(attribute); - - this.notifyPropertyChange(attribute); - this.notifyPropertyChange('length'); - }, - - /** - Removes all error messages and sends `becameValid` event - to the record. - - Example: - - ```app/routes/user/edit.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - actions: { - retrySave: function(user) { - user.get('errors').clear(); - user.save(); - } - } - }); - ``` - - @method clear - @deprecated - */ - clear() { - warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.clear', - }); - - if (get(this, 'isEmpty')) { - return; - } - - this._clear(); - this.trigger('becameValid'); - }, - - /** - Removes all error messages. - to the record. - - @method _clear - @private - */ - _clear() { - if (get(this, 'isEmpty')) { - return; - } - - let errorsByAttributeName = get(this, 'errorsByAttributeName'); - let attributes = A(); - - errorsByAttributeName.forEach(function(_, attribute) { - attributes.push(attribute); - }); - - errorsByAttributeName.clear(); - attributes.forEach(function(attribute) { - this.notifyPropertyChange(attribute); - }, this); - - ArrayProxy.prototype.clear.call(this); - }, - - /** - Checks if there is error messages for the given attribute. - - ```app/routes/user/edit.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - actions: { - save: function(user) { - if (user.get('errors').has('email')) { - return alert('Please update your email before attempting to save.'); - } - user.save(); - } - } - }); - ``` - - @method has - @param {String} attribute - @return {Boolean} true if there some errors on given attribute - */ - has(attribute) { - return this.errorsFor(attribute).length > 0; - }, -}); diff --git a/addon/-record-data-rfc-private/system/normalize-link.js b/addon/-record-data-rfc-private/system/normalize-link.js deleted file mode 100644 index 33e7a31ad97..00000000000 --- a/addon/-record-data-rfc-private/system/normalize-link.js +++ /dev/null @@ -1,21 +0,0 @@ -/* - This method normalizes a link to an "links object". If the passed link is - already an object it's returned without any modifications. - - See http://jsonapi.org/format/#document-links for more information. - - @method _normalizeLink - @private - @param {String} link - @return {Object|null} - @for DS -*/ -export default function _normalizeLink(link) { - switch (typeof link) { - case 'object': - return link; - case 'string': - return { href: link }; - } - return null; -} diff --git a/addon/-record-data-rfc-private/system/normalize-model-name.js b/addon/-record-data-rfc-private/system/normalize-model-name.js deleted file mode 100644 index 7ff61d9841d..00000000000 --- a/addon/-record-data-rfc-private/system/normalize-model-name.js +++ /dev/null @@ -1,18 +0,0 @@ -import { dasherize } from '@ember/string'; - -// All modelNames are dasherized internally. Changing this function may -// require changes to other normalization hooks (such as typeForRoot). - -/** - This method normalizes a modelName into the format Ember Data uses - internally. - - @method normalizeModelName - @public - @param {String} modelName - @return {String} normalizedModelName - @for DS -*/ -export default function normalizeModelName(modelName) { - return dasherize(modelName); -} diff --git a/addon/-record-data-rfc-private/system/ordered-set.js b/addon/-record-data-rfc-private/system/ordered-set.js deleted file mode 100644 index 27a6205057c..00000000000 --- a/addon/-record-data-rfc-private/system/ordered-set.js +++ /dev/null @@ -1,37 +0,0 @@ -import EmberOrderedSet from '@ember/ordered-set'; -import { guidFor } from '@ember/object/internals'; - -export default function OrderedSet() { - this._super$constructor(); -} - -OrderedSet.create = function() { - let Constructor = this; - return new Constructor(); -}; - -OrderedSet.prototype = Object.create(EmberOrderedSet.prototype); -OrderedSet.prototype.constructor = OrderedSet; -OrderedSet.prototype._super$constructor = EmberOrderedSet; - -OrderedSet.prototype.addWithIndex = function(obj, idx) { - let guid = guidFor(obj); - let presenceSet = this.presenceSet; - let list = this.list; - - if (presenceSet[guid] === true) { - return; - } - - presenceSet[guid] = true; - - if (idx === undefined || idx === null) { - list.push(obj); - } else { - list.splice(idx, 0, obj); - } - - this.size += 1; - - return this; -}; diff --git a/addon/-record-data-rfc-private/system/record-array-manager.js b/addon/-record-data-rfc-private/system/record-array-manager.js deleted file mode 100644 index e8e3ae6c5b8..00000000000 --- a/addon/-record-data-rfc-private/system/record-array-manager.js +++ /dev/null @@ -1,404 +0,0 @@ -/** - @module ember-data -*/ - -import { A } from '@ember/array'; -import { set, get } from '@ember/object'; -import { run as emberRun } from '@ember/runloop'; -import { assert } from '@ember/debug'; -import cloneNull from './clone-null'; -import { RecordArray, AdapterPopulatedRecordArray } from './record-arrays'; - -const { - _flush, - array_remove, - create, - createAdapterPopulatedRecordArray, - createRecordArray, - liveRecordArrayFor, - recordDidChange, - unregisterRecordArray, -} = heimdall.registerMonitor( - 'recordArrayManager', - '_flush', - 'array_remove', - 'create', - 'createAdapterPopulatedRecordArray', - 'createRecordArray', - 'liveRecordArrayFor', - 'recordDidChange', - 'unregisterRecordArray' -); - -/** - @class RecordArrayManager - @namespace DS - @private -*/ -export default class RecordArrayManager { - constructor(options) { - heimdall.increment(create); - this.store = options.store; - this.isDestroying = false; - this.isDestroyed = false; - this._liveRecordArrays = Object.create(null); - this._pending = Object.create(null); - this._adapterPopulatedRecordArrays = []; - } - - recordDidChange(internalModel) { - // TODO: change name - // TODO: track that it was also a change - this.internalModelDidChange(internalModel); - } - - recordWasLoaded(internalModel) { - // TODO: change name - // TODO: track that it was also that it was first loaded - this.internalModelDidChange(internalModel); - } - - internalModelDidChange(internalModel) { - heimdall.increment(recordDidChange); - - let modelName = internalModel.modelName; - - if (internalModel._pendingRecordArrayManagerFlush) { - return; - } - - internalModel._pendingRecordArrayManagerFlush = true; - - let pending = this._pending; - let models = (pending[modelName] = pending[modelName] || []); - if (models.push(internalModel) !== 1) { - return; - } - - emberRun.schedule('actions', this, this._flush); - } - - _flushPendingInternalModelsForModelName(modelName, internalModels) { - let modelsToRemove = []; - - for (let j = 0; j < internalModels.length; j++) { - let internalModel = internalModels[j]; - // mark internalModels, so they can once again be processed by the - // recordArrayManager - internalModel._pendingRecordArrayManagerFlush = false; - // build up a set of models to ensure we have purged correctly; - if (internalModel.isHiddenFromRecordArrays()) { - modelsToRemove.push(internalModel); - } - } - - let array = this._liveRecordArrays[modelName]; - if (array) { - // TODO: skip if it only changed - // process liveRecordArrays - this.updateLiveRecordArray(array, internalModels); - } - - // process adapterPopulatedRecordArrays - if (modelsToRemove.length > 0) { - removeFromAdapterPopulatedRecordArrays(modelsToRemove); - } - } - - _flush() { - heimdall.increment(_flush); - - let pending = this._pending; - this._pending = Object.create(null); - - for (let modelName in pending) { - this._flushPendingInternalModelsForModelName(modelName, pending[modelName]); - } - } - - updateLiveRecordArray(array, internalModels) { - return updateLiveRecordArray(array, internalModels); - } - - _syncLiveRecordArray(array, modelName) { - assert( - `recordArrayManger.syncLiveRecordArray expects modelName not modelClass as the second param`, - typeof modelName === 'string' - ); - let pending = this._pending[modelName]; - let hasPendingChanges = Array.isArray(pending); - let hasNoPotentialDeletions = !hasPendingChanges || pending.length === 0; - let map = this.store._internalModelsFor(modelName); - let hasNoInsertionsOrRemovals = get(map, 'length') === get(array, 'length'); - - /* - Ideally the recordArrayManager has knowledge of the changes to be applied to - liveRecordArrays, and is capable of strategically flushing those changes and applying - small diffs if desired. However, until we've refactored recordArrayManager, this dirty - check prevents us from unnecessarily wiping out live record arrays returned by peekAll. - */ - if (hasNoPotentialDeletions && hasNoInsertionsOrRemovals) { - return; - } - - if (hasPendingChanges) { - this._flushPendingInternalModelsForModelName(modelName, pending); - delete pending[modelName]; - } - - let internalModels = this._visibleInternalModelsByType(modelName); - let modelsToAdd = []; - for (let i = 0; i < internalModels.length; i++) { - let internalModel = internalModels[i]; - let recordArrays = internalModel._recordArrays; - if (recordArrays.has(array) === false) { - recordArrays.add(array); - modelsToAdd.push(internalModel); - } - } - - if (modelsToAdd.length) { - array._pushInternalModels(modelsToAdd); - } - } - - _didUpdateAll(modelName) { - let recordArray = this._liveRecordArrays[modelName]; - if (recordArray) { - set(recordArray, 'isUpdating', false); - } - } - - /** - Get the `DS.RecordArray` for a modelName, which contains all loaded records of - given modelName. - - @method liveRecordArrayFor - @param {String} modelName - @return {DS.RecordArray} - */ - liveRecordArrayFor(modelName) { - assert( - `recordArrayManger.liveRecordArrayFor expects modelName not modelClass as the param`, - typeof modelName === 'string' - ); - - heimdall.increment(liveRecordArrayFor); - - let array = this._liveRecordArrays[modelName]; - - if (array) { - // if the array already exists, synchronize - this._syncLiveRecordArray(array, modelName); - } else { - // if the array is being newly created merely create it with its initial - // content already set. This prevents unneeded change events. - let internalModels = this._visibleInternalModelsByType(modelName); - array = this.createRecordArray(modelName, internalModels); - this._liveRecordArrays[modelName] = array; - } - - return array; - } - - _visibleInternalModelsByType(modelName) { - let all = this.store._internalModelsFor(modelName)._models; - let visible = []; - for (let i = 0; i < all.length; i++) { - let model = all[i]; - if (model.isHiddenFromRecordArrays() === false) { - visible.push(model); - } - } - return visible; - } - - /** - Create a `DS.RecordArray` for a modelName. - - @method createRecordArray - @param {String} modelName - @param {Array} _content (optional|private) - @return {DS.RecordArray} - */ - createRecordArray(modelName, content) { - assert( - `recordArrayManger.createRecordArray expects modelName not modelClass as the param`, - typeof modelName === 'string' - ); - heimdall.increment(createRecordArray); - - let array = RecordArray.create({ - modelName, - content: A(content || []), - store: this.store, - isLoaded: true, - manager: this, - }); - - if (Array.isArray(content)) { - associateWithRecordArray(content, array); - } - - return array; - } - - /** - Create a `DS.AdapterPopulatedRecordArray` for a modelName with given query. - - @method createAdapterPopulatedRecordArray - @param {String} modelName - @param {Object} query - @return {DS.AdapterPopulatedRecordArray} - */ - createAdapterPopulatedRecordArray(modelName, query, internalModels, payload) { - heimdall.increment(createAdapterPopulatedRecordArray); - assert( - `recordArrayManger.createAdapterPopulatedRecordArray expects modelName not modelClass as the first param, received ${modelName}`, - typeof modelName === 'string' - ); - - let array; - if (Array.isArray(internalModels)) { - array = AdapterPopulatedRecordArray.create({ - modelName, - query: query, - content: A(internalModels), - store: this.store, - manager: this, - isLoaded: true, - isUpdating: false, - meta: cloneNull(payload.meta), - links: cloneNull(payload.links), - }); - - associateWithRecordArray(internalModels, array); - } else { - array = AdapterPopulatedRecordArray.create({ - modelName, - query: query, - content: A(), - store: this.store, - manager: this, - }); - } - - this._adapterPopulatedRecordArrays.push(array); - - return array; - } - - /** - Unregister a RecordArray. - So manager will not update this array. - - @method unregisterRecordArray - @param {DS.RecordArray} array - */ - unregisterRecordArray(array) { - heimdall.increment(unregisterRecordArray); - - let modelName = array.modelName; - - // remove from adapter populated record array - let removedFromAdapterPopulated = remove(this._adapterPopulatedRecordArrays, array); - - if (!removedFromAdapterPopulated) { - let liveRecordArrayForType = this._liveRecordArrays[modelName]; - // unregister live record array - if (liveRecordArrayForType) { - if (array === liveRecordArrayForType) { - delete this._liveRecordArrays[modelName]; - } - } - } - } - - _associateWithRecordArray(internalModels, array) { - associateWithRecordArray(internalModels, array); - } - - willDestroy() { - Object.keys(this._liveRecordArrays).forEach(modelName => - this._liveRecordArrays[modelName].destroy() - ); - this._adapterPopulatedRecordArrays.forEach(destroy); - this.isDestroyed = true; - } - - destroy() { - this.isDestroying = true; - emberRun.schedule('actions', this, this.willDestroy); - } -} - -function destroy(entry) { - entry.destroy(); -} - -function remove(array, item) { - heimdall.increment(array_remove); - let index = array.indexOf(item); - - if (index !== -1) { - array.splice(index, 1); - return true; - } - - return false; -} - -function updateLiveRecordArray(array, internalModels) { - let modelsToAdd = []; - let modelsToRemove = []; - - for (let i = 0; i < internalModels.length; i++) { - let internalModel = internalModels[i]; - let isDeleted = internalModel.isHiddenFromRecordArrays(); - let recordArrays = internalModel._recordArrays; - - if (!isDeleted && !internalModel.isEmpty()) { - if (!recordArrays.has(array)) { - modelsToAdd.push(internalModel); - recordArrays.add(array); - } - } - - if (isDeleted) { - modelsToRemove.push(internalModel); - recordArrays.delete(array); - } - } - - if (modelsToAdd.length > 0) { - array._pushInternalModels(modelsToAdd); - } - if (modelsToRemove.length > 0) { - array._removeInternalModels(modelsToRemove); - } - - // return whether we performed an update. - // Necessary until 3.5 allows us to finish off ember-data-filter support. - return (modelsToAdd.length || modelsToRemove.length) > 0; -} - -function removeFromAdapterPopulatedRecordArrays(internalModels) { - for (let i = 0; i < internalModels.length; i++) { - let internalModel = internalModels[i]; - let list = internalModel._recordArrays.list; - - for (let j = 0; j < list.length; j++) { - // TODO: group by arrays, so we can batch remove - list[j]._removeInternalModels([internalModel]); - } - - internalModel._recordArrays.clear(); - } -} - -export function associateWithRecordArray(internalModels, array) { - for (let i = 0, l = internalModels.length; i < l; i++) { - let internalModel = internalModels[i]; - internalModel._recordArrays.add(array); - } -} diff --git a/addon/-record-data-rfc-private/system/record-arrays.js b/addon/-record-data-rfc-private/system/record-arrays.js deleted file mode 100644 index 5439899ad81..00000000000 --- a/addon/-record-data-rfc-private/system/record-arrays.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - @module ember-data -*/ - -import RecordArray from './record-arrays/record-array'; -import AdapterPopulatedRecordArray from './record-arrays/adapter-populated-record-array'; - -export { RecordArray, AdapterPopulatedRecordArray }; diff --git a/addon/-record-data-rfc-private/system/record-arrays/adapter-populated-record-array.js b/addon/-record-data-rfc-private/system/record-arrays/adapter-populated-record-array.js deleted file mode 100644 index d3cc1e68a91..00000000000 --- a/addon/-record-data-rfc-private/system/record-arrays/adapter-populated-record-array.js +++ /dev/null @@ -1,92 +0,0 @@ -import { once } from '@ember/runloop'; -import { A } from '@ember/array'; -import { get } from '@ember/object'; -import RecordArray from './record-array'; -import cloneNull from '../clone-null'; - -/** - Represents an ordered list of records whose order and membership is - determined by the adapter. For example, a query sent to the adapter - may trigger a search on the server, whose results would be loaded - into an instance of the `AdapterPopulatedRecordArray`. - - --- - - If you want to update the array and get the latest records from the - adapter, you can invoke [`update()`](#method_update): - - Example - - ```javascript - // GET /users?isAdmin=true - var admins = store.query('user', { isAdmin: true }); - - admins.then(function() { - console.log(admins.get("length")); // 42 - }); - - // somewhere later in the app code, when new admins have been created - // in the meantime - // - // GET /users?isAdmin=true - admins.update().then(function() { - admins.get('isUpdating'); // false - console.log(admins.get("length")); // 123 - }); - - admins.get('isUpdating'); // true - ``` - - @class AdapterPopulatedRecordArray - @namespace DS - @extends DS.RecordArray -*/ -export default RecordArray.extend({ - init() { - // yes we are touching `this` before super, but ArrayProxy has a bug that requires this. - this.set('content', this.get('content') || A()); - - this._super(...arguments); - this.query = this.query || null; - this.links = this.links || null; - }, - - replace() { - throw new Error(`The result of a server query (on ${this.modelName}) is immutable.`); - }, - - _update() { - let store = get(this, 'store'); - let query = get(this, 'query'); - - return store._query(this.modelName, query, this); - }, - - /** - @method _setInternalModels - @param {Array} internalModels - @param {Object} payload normalized payload - @private - */ - _setInternalModels(internalModels, payload) { - let token = heimdall.start('AdapterPopulatedRecordArray._setInternalModels'); - - // TODO: initial load should not cause change events at all, only - // subsequent. This requires changing the public api of adapter.query, but - // hopefully we can do that soon. - this.get('content').setObjects(internalModels); - - this.setProperties({ - isLoaded: true, - isUpdating: false, - meta: cloneNull(payload.meta), - links: cloneNull(payload.links), - }); - - this.manager._associateWithRecordArray(internalModels, this); - - // TODO: should triggering didLoad event be the last action of the runLoop? - once(this, 'trigger', 'didLoad'); - heimdall.stop(token); - }, -}); diff --git a/addon/-record-data-rfc-private/system/record-arrays/record-array.js b/addon/-record-data-rfc-private/system/record-arrays/record-array.js deleted file mode 100644 index 78afefda737..00000000000 --- a/addon/-record-data-rfc-private/system/record-arrays/record-array.js +++ /dev/null @@ -1,266 +0,0 @@ -/** - @module ember-data -*/ - -import Evented from '@ember/object/evented'; - -import ArrayProxy from '@ember/array/proxy'; -import { set, get, computed } from '@ember/object'; -import { Promise } from 'rsvp'; -import { PromiseArray } from '../promise-proxies'; -import SnapshotRecordArray from '../snapshot-record-array'; - -/** - A record array is an array that contains records of a certain modelName. The record - array materializes records as needed when they are retrieved for the first - time. You should not create record arrays yourself. Instead, an instance of - `DS.RecordArray` or its subclasses will be returned by your application's store - in response to queries. - - @class RecordArray - @namespace DS - @extends Ember.ArrayProxy - @uses Ember.Evented -*/ - -export default ArrayProxy.extend(Evented, { - init() { - this._super(...arguments); - - /** - The array of client ids backing the record array. When a - record is requested from the record array, the record - for the client id at the same index is materialized, if - necessary, by the store. - - @property content - @private - @type Ember.Array - */ - this.set('content', this.content || null); - - /** - The flag to signal a `RecordArray` is finished loading data. - - Example - - ```javascript - var people = store.peekAll('person'); - people.get('isLoaded'); // true - ``` - - @property isLoaded - @type Boolean - */ - this.isLoaded = this.isLoaded || false; - /** - The flag to signal a `RecordArray` is currently loading data. - - Example - - ```javascript - var people = store.peekAll('person'); - people.get('isUpdating'); // false - people.update(); - people.get('isUpdating'); // true - ``` - - @property isUpdating - @type Boolean - */ - this.isUpdating = false; - - /** - The store that created this record array. - - @property store - @private - @type DS.Store - */ - this.store = this.store || null; - this._updatingPromise = null; - }, - - replace() { - throw new Error( - `The result of a server query (for all ${ - this.modelName - } types) is immutable. To modify contents, use toArray()` - ); - }, - - /** - The modelClass represented by this record array. - - @property type - @type DS.Model - */ - type: computed('modelName', function() { - if (!this.modelName) { - return null; - } - return this.store.modelFor(this.modelName); - }).readOnly(), - - /** - Retrieves an object from the content by index. - - @method objectAtContent - @private - @param {Number} index - @return {DS.Model} record - */ - objectAtContent(index) { - let internalModel = get(this, 'content').objectAt(index); - return internalModel && internalModel.getRecord(); - }, - - /** - Used to get the latest version of all of the records in this array - from the adapter. - - Example - - ```javascript - var people = store.peekAll('person'); - people.get('isUpdating'); // false - - people.update().then(function() { - people.get('isUpdating'); // false - }); - - people.get('isUpdating'); // true - ``` - - @method update - */ - update() { - if (get(this, 'isUpdating')) { - return this._updatingPromise; - } - - this.set('isUpdating', true); - - let updatingPromise = this._update().finally(() => { - this._updatingPromise = null; - if (this.get('isDestroying') || this.get('isDestroyed')) { - return; - } - this.set('isUpdating', false); - }); - - this._updatingPromise = updatingPromise; - - return updatingPromise; - }, - - /* - Update this RecordArray and return a promise which resolves once the update - is finished. - */ - _update() { - return this.store.findAll(this.modelName, { reload: true }); - }, - - /** - Adds an internal model to the `RecordArray` without duplicates - - @method _pushInternalModels - @private - @param {InternalModel} internalModel - */ - _pushInternalModels(internalModels) { - // pushObjects because the internalModels._recordArrays set was already - // consulted for inclusion, so addObject and its on .contains call is not - // required. - get(this, 'content').pushObjects(internalModels); - }, - - /** - Removes an internalModel to the `RecordArray`. - - @method removeInternalModel - @private - @param {InternalModel} internalModel - */ - _removeInternalModels(internalModels) { - get(this, 'content').removeObjects(internalModels); - }, - - /** - Saves all of the records in the `RecordArray`. - - Example - - ```javascript - var messages = store.peekAll('message'); - messages.forEach(function(message) { - message.set('hasBeenSeen', true); - }); - messages.save(); - ``` - - @method save - @return {DS.PromiseArray} promise - */ - save() { - let promiseLabel = `DS: RecordArray#save ${this.modelName}`; - let promise = Promise.all(this.invoke('save'), promiseLabel).then( - () => this, - null, - 'DS: RecordArray#save return RecordArray' - ); - - return PromiseArray.create({ promise }); - }, - - _dissociateFromOwnRecords() { - this.get('content').forEach(internalModel => { - let recordArrays = internalModel.__recordArrays; - - if (recordArrays) { - recordArrays.delete(this); - } - }); - }, - - /** - @method _unregisterFromManager - @private - */ - _unregisterFromManager() { - this.manager.unregisterRecordArray(this); - }, - - willDestroy() { - this._unregisterFromManager(); - this._dissociateFromOwnRecords(); - // TODO: we should not do work during destroy: - // * when objects are destroyed, they should simply be left to do - // * if logic errors do to this, that logic needs to be more careful during - // teardown (ember provides isDestroying/isDestroyed) for this reason - // * the exception being: if an dominator has a reference to this object, - // and must be informed to release e.g. e.g. removing itself from th - // recordArrayMananger - set(this, 'content', null); - set(this, 'length', 0); - this._super(...arguments); - }, - - /* - @method _createSnapshot - @private - */ - _createSnapshot(options) { - // this is private for users, but public for ember-data internals - return new SnapshotRecordArray(this, this.get('meta'), options); - }, - - /* - @method _takeSnapshot - @private - */ - _takeSnapshot() { - return get(this, 'content').map(internalModel => internalModel.createSnapshot()); - }, -}); diff --git a/addon/-record-data-rfc-private/system/references.js b/addon/-record-data-rfc-private/system/references.js deleted file mode 100644 index ad073f586ca..00000000000 --- a/addon/-record-data-rfc-private/system/references.js +++ /dev/null @@ -1,5 +0,0 @@ -import RecordReference from './references/record'; -import BelongsToReference from './references/belongs-to'; -import HasManyReference from './references/has-many'; - -export { RecordReference, BelongsToReference, HasManyReference }; diff --git a/addon/-record-data-rfc-private/system/references/record.js b/addon/-record-data-rfc-private/system/references/record.js deleted file mode 100644 index 56bb3338192..00000000000 --- a/addon/-record-data-rfc-private/system/references/record.js +++ /dev/null @@ -1,162 +0,0 @@ -import { resolve } from 'rsvp'; -import Reference from './reference'; - -/** - An RecordReference is a low level API that allows users and - addon author to perform meta-operations on a record. - - @class RecordReference - @namespace DS -*/ -export default class RecordReference extends Reference { - constructor(store, internalModel) { - super(store, internalModel); - this.type = internalModel.modelName; - this._id = internalModel.id; - } - - /** - The `id` of the record that this reference refers to. - - Together, the `type` and `id` properties form a composite key for - the identity map. - - Example - - ```javascript - let userRef = store.getReference('user', 1); - - userRef.id(); // '1' - ``` - - @method id - @return {String} The id of the record. - */ - id() { - return this._id; - } - - /** - How the reference will be looked up when it is loaded: Currently - this always return `identity` to signifying that a record will be - loaded by the `type` and `id`. - - Example - - ```javascript - const userRef = store.getReference('user', 1); - - userRef.remoteType(); // 'identity' - ``` - - @method remoteType - @return {String} 'identity' - */ - remoteType() { - return 'identity'; - } - - /** - This API allows you to provide a reference with new data. The - simplest usage of this API is similar to `store.push`: you provide a - normalized hash of data and the object represented by the reference - will update. - - If you pass a promise to `push`, Ember Data will not ask the adapter - for the data if another attempt to fetch it is made in the - interim. When the promise resolves, the underlying object is updated - with the new data, and the promise returned by *this function* is resolved - with that object. - - For example, `recordReference.push(promise)` will be resolved with a - record. - - Example - - ```javascript - let userRef = store.getReference('user', 1); - - // provide data for reference - userRef.push({ data: { id: 1, username: "@user" }}).then(function(user) { - userRef.value() === user; - }); - ``` - - @method push - @param objectOrPromise {Promise|Object} - @return Promise a promise for the value (record or relationship) - */ - push(objectOrPromise) { - return resolve(objectOrPromise).then(data => { - return this.store.push(data); - }); - } - - /** - If the entity referred to by the reference is already loaded, it is - present as `reference.value`. Otherwise the value returned by this function - is `null`. - - Example - - ```javascript - let userRef = store.getReference('user', 1); - - userRef.value(); // user - ``` - - @method value - @return {DS.Model} the record for this RecordReference - */ - value() { - if (this.internalModel.hasRecord) { - return this.internalModel.getRecord(); - } - return null; - } - - /** - Triggers a fetch for the backing entity based on its `remoteType` - (see `remoteType` definitions per reference type). - - Example - - ```javascript - let userRef = store.getReference('user', 1); - - // load user (via store.find) - userRef.load().then(...) - ``` - - @method load - @return {Promise} the record for this RecordReference - */ - load() { - return this.store.findRecord(this.type, this._id); - } - - /** - Reloads the record if it is already loaded. If the record is not - loaded it will load the record via `store.findRecord` - - Example - - ```javascript - let userRef = store.getReference('user', 1); - - // or trigger a reload - userRef.reload().then(...) - ``` - - @method reload - @return {Promise} the record for this RecordReference - */ - reload() { - let record = this.value(); - if (record) { - return record.reload(); - } - - return this.load(); - } -} diff --git a/addon/-record-data-rfc-private/system/relationship-meta.js b/addon/-record-data-rfc-private/system/relationship-meta.js deleted file mode 100644 index 2951df4c616..00000000000 --- a/addon/-record-data-rfc-private/system/relationship-meta.js +++ /dev/null @@ -1,96 +0,0 @@ -import { singularize } from 'ember-inflector'; -import { DEBUG } from '@glimmer/env'; -import normalizeModelName from './normalize-model-name'; - -export function typeForRelationshipMeta(meta) { - let modelName; - - modelName = meta.type || meta.key; - if (meta.kind === 'hasMany') { - modelName = singularize(normalizeModelName(modelName)); - } - return modelName; -} - -function shouldFindInverse(relationshipMeta) { - let options = relationshipMeta.options; - return !(options && options.inverse === null); -} - -class RelationshipDefinition { - constructor(meta) { - this.meta = meta; - this._type = ''; - this.__inverseKey = ''; - this.__inverseIsAsync = null; - this.modelClass = meta.parentType; - this.store = null; - } - - get key() { - return this.meta.key; - } - get kind() { - return this.meta.kind; - } - get type() { - if (this._type) { - return this._type; - } - this._type = typeForRelationshipMeta(this.meta); - return this._type; - } - get options() { - return this.meta.options; - } - get name() { - return this.meta.name; - } - get parentType() { - return this.meta.parentType; - } - - _inverseKey(store, modelClass) { - if (this.__inverseKey === '') { - this._calculateInverse(store, modelClass); - } - return this.__inverseKey; - } - - _inverseIsAsync(store, modelClass) { - if (this.__inverseIsAsync === null) { - this._calculateInverse(store, modelClass); - } - return this.__inverseIsAsync; - } - - _calculateInverse(store, modelClass) { - let inverseKey, inverseIsAsync; - let inverse = null; - - if (shouldFindInverse(this.meta)) { - inverse = modelClass.inverseFor(this.key, store); - } else if (DEBUG) { - modelClass.typeForRelationship(this.key, store); - } - - if (inverse) { - inverseKey = inverse.name; - inverseIsAsync = isInverseAsync(inverse); - } else { - inverseKey = null; - inverseIsAsync = false; - } - this.__inverseKey = inverseKey; - this.__inverseIsAsync = inverseIsAsync; - } -} - -function isInverseAsync(meta) { - let inverseAsync = meta.options && meta.options.async; - return typeof inverseAsync === 'undefined' ? true : inverseAsync; -} - -export function relationshipFromMeta(meta) { - return new RelationshipDefinition(meta); -} diff --git a/addon/-record-data-rfc-private/system/snapshot-record-array.js b/addon/-record-data-rfc-private/system/snapshot-record-array.js deleted file mode 100644 index 9afe2408670..00000000000 --- a/addon/-record-data-rfc-private/system/snapshot-record-array.js +++ /dev/null @@ -1,165 +0,0 @@ -/** - @module ember-data -*/ - -/** - @class SnapshotRecordArray - @namespace DS - @private - @constructor - @param {Array} snapshots An array of snapshots - @param {Object} meta -*/ -export default class SnapshotRecordArray { - constructor(recordArray, meta, options = {}) { - /** - An array of snapshots - @private - @property _snapshots - @type {Array} - */ - this._snapshots = null; - - /** - An array of records - @private - @property _recordArray - @type {Array} - */ - this._recordArray = recordArray; - - /** - Number of records in the array - - Example - - ```app/adapters/post.js - import DS from 'ember-data' - - export default DS.JSONAPIAdapter.extend({ - shouldReloadAll(store, snapshotRecordArray) { - return !snapshotRecordArray.length; - }, - }); - ``` - - @property length - @type {Number} - */ - this.length = recordArray.get('length'); - - this._type = null; - - /** - Meta objects for the record array. - - Example - - ```app/adapters/post.js - import DS from 'ember-data' - - export default DS.JSONAPIAdapter.extend({ - shouldReloadAll(store, snapshotRecordArray) { - var lastRequestTime = snapshotRecordArray.meta.lastRequestTime; - var twentyMinutes = 20 * 60 * 1000; - return Date.now() > lastRequestTime + twentyMinutes; - }, - }); - ``` - - @property meta - @type {Object} - */ - this.meta = meta; - - /** - A hash of adapter options passed into the store method for this request. - - Example - - ```app/adapters/post.js - import MyCustomAdapter from './custom-adapter'; - - export default MyCustomAdapter.extend({ - findAll(store, type, sinceToken, snapshotRecordArray) { - if (snapshotRecordArray.adapterOptions.subscribe) { - // ... - } - // ... - } - }); - ``` - - @property adapterOptions - @type {Object} - */ - this.adapterOptions = options.adapterOptions; - - /** - The relationships to include for this request. - - Example - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - findAll(store, type, snapshotRecordArray) { - var url = `/${type.modelName}?include=${encodeURIComponent(snapshotRecordArray.include)}`; - - return fetch(url).then((response) => response.json()) - } - }); - - @property include - @type {String|Array} - */ - this.include = options.include; - } - - /** - The type of the underlying records for the snapshots in the array, as a DS.Model - @property type - @type {DS.Model} - */ - get type() { - return this._type || (this._type = this._recordArray.get('type')); - } - - /** - Get snapshots of the underlying record array - - Example - - ```app/adapters/post.js - import DS from 'ember-data' - - export default DS.JSONAPIAdapter.extend({ - shouldReloadAll(store, snapshotArray) { - var snapshots = snapshotArray.snapshots(); - - return snapshots.any(function(ticketSnapshot) { - var timeDiff = moment().diff(ticketSnapshot.attr('lastAccessedAt'), 'minutes'); - if (timeDiff > 20) { - return true; - } else { - return false; - } - }); - } - }); - ``` - - @method snapshots - @return {Array} Array of snapshots - */ - snapshots() { - if (this._snapshots !== null) { - return this._snapshots; - } - - this._snapshots = this._recordArray._takeSnapshot(); - - return this._snapshots; - } -} diff --git a/addon/-record-data-rfc-private/system/store/common.js b/addon/-record-data-rfc-private/system/store/common.js deleted file mode 100644 index c095fe701c8..00000000000 --- a/addon/-record-data-rfc-private/system/store/common.js +++ /dev/null @@ -1,57 +0,0 @@ -import { get } from '@ember/object'; -import { DEBUG } from '@glimmer/env'; -import Ember from 'ember'; -import { Promise } from 'rsvp'; - -const { __bind, __guard, __objectIsAlive } = heimdall.registerMonitor( - 'system.store.common', - '_bind', - '_guard', - '_objectIsAlive' -); - -export function _bind(fn, ...args) { - heimdall.increment(__bind); - - return function() { - return fn.apply(undefined, args); - }; -} - -export function _guard(promise, test) { - heimdall.increment(__guard); - let guarded = promise['finally'](function() { - if (!test()) { - guarded._subscribers.length = 0; - } - }); - - return guarded; -} - -export function _objectIsAlive(object) { - heimdall.increment(__objectIsAlive); - return !(get(object, 'isDestroyed') || get(object, 'isDestroying')); -} - -let ASYNC_REQUEST_COUNT = 0; -export function incrementRequestCount() { - ASYNC_REQUEST_COUNT++; -} - -if (DEBUG) { - Ember.Test.registerWaiter(() => { - return ASYNC_REQUEST_COUNT === 0; - }); -} - -export function guardDestroyedStore(promise, store, label) { - promise = Promise.resolve(promise, label); - - return _guard(promise, () => { - if (DEBUG) { - ASYNC_REQUEST_COUNT--; - } - return _objectIsAlive(store); - }); -} diff --git a/addon/-record-data-rfc-private/system/store/finders.js b/addon/-record-data-rfc-private/system/store/finders.js deleted file mode 100644 index 1709a79cb39..00000000000 --- a/addon/-record-data-rfc-private/system/store/finders.js +++ /dev/null @@ -1,335 +0,0 @@ -import { A } from '@ember/array'; -import { Promise } from 'rsvp'; -import { assert, warn } from '@ember/debug'; -import { DEBUG } from '@glimmer/env'; - -import { - _bind, - _guard, - _objectIsAlive, - guardDestroyedStore, - incrementRequestCount, -} from './common'; - -import { normalizeResponseHelper } from './serializer-response'; -import { serializerForAdapter } from './serializers'; - -function payloadIsNotBlank(adapterPayload) { - if (Array.isArray(adapterPayload)) { - return true; - } else { - return Object.keys(adapterPayload || {}).length; - } -} - -export function _find(adapter, store, modelClass, id, internalModel, options) { - if (DEBUG) { - incrementRequestCount(); - } - let snapshot = internalModel.createSnapshot(options); - let { modelName } = internalModel; - let promise = Promise.resolve().then(() => adapter.findRecord(store, modelClass, id, snapshot)); - let label = `DS: Handle Adapter#findRecord of '${modelName}' with id: '${id}'`; - - promise = guardDestroyedStore(promise, store, label); - - return promise.then( - adapterPayload => { - assert( - `You made a 'findRecord' request for a '${modelName}' with id '${id}', but the adapter's response did not have any data`, - payloadIsNotBlank(adapterPayload) - ); - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper( - serializer, - store, - modelClass, - adapterPayload, - id, - 'findRecord' - ); - assert( - `Ember Data expected the primary data returned from a 'findRecord' response to be an object but instead it found an array.`, - !Array.isArray(payload.data) - ); - - warn( - `You requested a record of type '${modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${ - payload.data.id - }'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead https://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, - payload.data.id === id, - { - id: 'ds.store.findRecord.id-mismatch', - } - ); - - return store._push(payload); - }, - error => { - internalModel.notFound(); - if (internalModel.isEmpty()) { - internalModel.unloadRecord(); - } - - throw error; - }, - `DS: Extract payload of '${modelName}'` - ); -} - -export function _findMany(adapter, store, modelName, ids, internalModels) { - if (DEBUG) { - incrementRequestCount(); - } - let snapshots = A(internalModels).invoke('createSnapshot'); - let modelClass = store.modelFor(modelName); // `adapter.findMany` gets the modelClass still - let promise = adapter.findMany(store, modelClass, ids, snapshots); - let label = `DS: Handle Adapter#findMany of '${modelName}'`; - - if (promise === undefined) { - throw new Error('adapter.findMany returned undefined, this was very likely a mistake'); - } - - promise = guardDestroyedStore(promise, store, label); - - return promise.then( - adapterPayload => { - assert( - `You made a 'findMany' request for '${modelName}' records with ids '[${ids}]', but the adapter's response did not have any data`, - payloadIsNotBlank(adapterPayload) - ); - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper( - serializer, - store, - modelClass, - adapterPayload, - null, - 'findMany' - ); - return store._push(payload); - }, - null, - `DS: Extract payload of ${modelName}` - ); -} - -export function _findHasMany(adapter, store, internalModel, link, relationship) { - if (DEBUG) { - incrementRequestCount(); - } - let snapshot = internalModel.createSnapshot(); - let modelClass = store.modelFor(relationship.type); - let promise = adapter.findHasMany(store, snapshot, link, relationship); - let label = `DS: Handle Adapter#findHasMany of '${internalModel.modelName}' : '${ - relationship.type - }'`; - - promise = guardDestroyedStore(promise, store, label); - promise = _guard(promise, _bind(_objectIsAlive, internalModel)); - - return promise.then( - adapterPayload => { - assert( - `You made a 'findHasMany' request for a ${internalModel.modelName}'s '${ - relationship.key - }' relationship, using link '${link}' , but the adapter's response did not have any data`, - payloadIsNotBlank(adapterPayload) - ); - let serializer = serializerForAdapter(store, adapter, relationship.type); - let payload = normalizeResponseHelper( - serializer, - store, - modelClass, - adapterPayload, - null, - 'findHasMany' - ); - let internalModelArray = store._push(payload); - - internalModelArray.meta = payload.meta; - return internalModelArray; - }, - null, - `DS: Extract payload of '${internalModel.modelName}' : hasMany '${relationship.type}'` - ); -} - -export function _findBelongsTo(adapter, store, internalModel, link, relationship) { - if (DEBUG) { - incrementRequestCount(); - } - let snapshot = internalModel.createSnapshot(); - let modelClass = store.modelFor(relationship.type); - let promise = adapter.findBelongsTo(store, snapshot, link, relationship); - let label = `DS: Handle Adapter#findBelongsTo of ${internalModel.modelName} : ${ - relationship.type - }`; - - promise = guardDestroyedStore(promise, store, label); - promise = _guard(promise, _bind(_objectIsAlive, internalModel)); - - return promise.then( - adapterPayload => { - let serializer = serializerForAdapter(store, adapter, relationship.type); - let payload = normalizeResponseHelper( - serializer, - store, - modelClass, - adapterPayload, - null, - 'findBelongsTo' - ); - - if (!payload.data) { - return null; - } - - return store._push(payload); - }, - null, - `DS: Extract payload of ${internalModel.modelName} : ${relationship.type}` - ); -} - -export function _findAll(adapter, store, modelName, sinceToken, options) { - if (DEBUG) { - incrementRequestCount(); - } - let modelClass = store.modelFor(modelName); // adapter.findAll depends on the class - let recordArray = store.peekAll(modelName); - let snapshotArray = recordArray._createSnapshot(options); - let promise = Promise.resolve().then(() => - adapter.findAll(store, modelClass, sinceToken, snapshotArray) - ); - let label = 'DS: Handle Adapter#findAll of ' + modelClass; - - promise = guardDestroyedStore(promise, store, label); - - return promise.then( - adapterPayload => { - assert( - `You made a 'findAll' request for '${modelName}' records, but the adapter's response did not have any data`, - payloadIsNotBlank(adapterPayload) - ); - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper( - serializer, - store, - modelClass, - adapterPayload, - null, - 'findAll' - ); - - store._push(payload); - store._didUpdateAll(modelName); - - return recordArray; - }, - null, - 'DS: Extract payload of findAll ${modelName}' - ); -} - -export function _query(adapter, store, modelName, query, recordArray, options) { - if (DEBUG) { - incrementRequestCount(); - } - let modelClass = store.modelFor(modelName); // adapter.query needs the class - - let promise; - let createRecordArray = - adapter.query.length > 3 || - (adapter.query.wrappedFunction && adapter.query.wrappedFunction.length > 3); - - if (createRecordArray) { - recordArray = - recordArray || store.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query); - promise = Promise.resolve().then(() => - adapter.query(store, modelClass, query, recordArray, options) - ); - } else { - promise = Promise.resolve().then(() => adapter.query(store, modelClass, query)); - } - - let label = `DS: Handle Adapter#query of ${modelName}`; - promise = guardDestroyedStore(promise, store, label); - - return promise.then( - adapterPayload => { - let serializerToken = heimdall.start('initial-serializerFor-lookup'); - let serializer = serializerForAdapter(store, adapter, modelName); - heimdall.stop(serializerToken); - let normalizeToken = heimdall.start('finders#_query::normalizeResponseHelper'); - let payload = normalizeResponseHelper( - serializer, - store, - modelClass, - adapterPayload, - null, - 'query' - ); - heimdall.stop(normalizeToken); - let internalModels = store._push(payload); - - assert( - 'The response to store.query is expected to be an array but it was a single record. Please wrap your response in an array or use `store.queryRecord` to query for a single record.', - Array.isArray(internalModels) - ); - if (recordArray) { - recordArray._setInternalModels(internalModels, payload); - } else { - recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray( - modelName, - query, - internalModels, - payload - ); - } - - return recordArray; - }, - null, - `DS: Extract payload of query ${modelName}` - ); -} - -export function _queryRecord(adapter, store, modelName, query, options) { - if (DEBUG) { - incrementRequestCount(); - } - let modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class - let promise = Promise.resolve().then(() => - adapter.queryRecord(store, modelClass, query, options) - ); - - let label = `DS: Handle Adapter#queryRecord of ${modelName}`; - promise = guardDestroyedStore(promise, store, label); - - return promise.then( - adapterPayload => { - let serializer = serializerForAdapter(store, adapter, modelName); - let payload = normalizeResponseHelper( - serializer, - store, - modelClass, - adapterPayload, - null, - 'queryRecord' - ); - - assert( - `Expected the primary data returned by the serializer for a 'queryRecord' response to be a single object or null but instead it was an array.`, - !Array.isArray(payload.data), - { - id: 'ds.store.queryRecord-array-response', - } - ); - - return store._push(payload); - }, - null, - `DS: Extract payload of queryRecord ${modelName}` - ); -} diff --git a/addon/-record-data-rfc-private/system/store/serializer-response.js b/addon/-record-data-rfc-private/system/store/serializer-response.js deleted file mode 100644 index c4a08c6b5cf..00000000000 --- a/addon/-record-data-rfc-private/system/store/serializer-response.js +++ /dev/null @@ -1,95 +0,0 @@ -import { assert } from '@ember/debug'; -import { DEBUG } from '@glimmer/env'; - -/* - This is a helper method that validates a JSON API top-level document - - The format of a document is described here: - http://jsonapi.org/format/#document-top-level - - @method validateDocumentStructure - @param {Object} doc JSON API document - @return {array} An array of errors found in the document structure -*/ -export function validateDocumentStructure(doc) { - let errors = []; - if (!doc || typeof doc !== 'object') { - errors.push('Top level of a JSON API document must be an object'); - } else { - if (!('data' in doc) && !('errors' in doc) && !('meta' in doc)) { - errors.push('One or more of the following keys must be present: "data", "errors", "meta".'); - } else { - if ('data' in doc && 'errors' in doc) { - errors.push( - 'Top level keys "errors" and "data" cannot both be present in a JSON API document' - ); - } - } - if ('data' in doc) { - if (!(doc.data === null || Array.isArray(doc.data) || typeof doc.data === 'object')) { - errors.push('data must be null, an object, or an array'); - } - } - if ('meta' in doc) { - if (typeof doc.meta !== 'object') { - errors.push('meta must be an object'); - } - } - if ('errors' in doc) { - if (!Array.isArray(doc.errors)) { - errors.push('errors must be an array'); - } - } - if ('links' in doc) { - if (typeof doc.links !== 'object') { - errors.push('links must be an object'); - } - } - if ('jsonapi' in doc) { - if (typeof doc.jsonapi !== 'object') { - errors.push('jsonapi must be an object'); - } - } - if ('included' in doc) { - if (typeof doc.included !== 'object') { - errors.push('included must be an array'); - } - } - } - - return errors; -} - -/* - This is a helper method that always returns a JSON-API Document. - - @method normalizeResponseHelper - @param {DS.Serializer} serializer - @param {DS.Store} store - @param {subclass of DS.Model} modelClass - @param {Object} payload - @param {String|Number} id - @param {String} requestType - @return {Object} JSON-API Document -*/ -export function normalizeResponseHelper(serializer, store, modelClass, payload, id, requestType) { - let normalizedResponse = serializer.normalizeResponse( - store, - modelClass, - payload, - id, - requestType - ); - let validationErrors = []; - if (DEBUG) { - validationErrors = validateDocumentStructure(normalizedResponse); - } - assert( - `normalizeResponse must return a valid JSON API document:\n\t* ${validationErrors.join( - '\n\t* ' - )}`, - validationErrors.length === 0 - ); - - return normalizedResponse; -} diff --git a/addon/-record-data-rfc-private/system/store/serializers.js b/addon/-record-data-rfc-private/system/store/serializers.js deleted file mode 100644 index d6788427061..00000000000 --- a/addon/-record-data-rfc-private/system/store/serializers.js +++ /dev/null @@ -1,17 +0,0 @@ -export function serializerForAdapter(store, adapter, modelName) { - let serializer = adapter.serializer; - - if (serializer === undefined) { - serializer = store.serializerFor(modelName); - } - - if (serializer === null || serializer === undefined) { - serializer = { - extract(store, type, payload) { - return payload; - }, - }; - } - - return serializer; -} diff --git a/addon/-record-data-rfc-private/utils.js b/addon/-record-data-rfc-private/utils.js deleted file mode 100644 index f3bd4ed6aaf..00000000000 --- a/addon/-record-data-rfc-private/utils.js +++ /dev/null @@ -1,46 +0,0 @@ -import { getOwner as emberGetOwner } from '@ember/application'; -import { get } from '@ember/object'; - -/* - Check if the passed model has a `type` attribute or a relationship named `type`. - - @method modelHasAttributeOrRelationshipNamedType - @param modelClass - */ -function modelHasAttributeOrRelationshipNamedType(modelClass) { - return ( - get(modelClass, 'attributes').has('type') || get(modelClass, 'relationshipsByName').has('type') - ); -} - -/* - ember-container-inject-owner is a new feature in Ember 2.3 that finally provides a public - API for looking items up. This function serves as a super simple polyfill to avoid - triggering deprecations. - */ -function getOwner(context) { - let owner; - - if (emberGetOwner) { - owner = emberGetOwner(context); - } else if (context.container) { - owner = context.container; - } - - if (owner && owner.lookupFactory && !owner._lookupFactory) { - // `owner` is a container, we are just making this work - owner._lookupFactory = function() { - return owner.lookupFactory(...arguments); - }; - - owner.register = function() { - let registry = owner.registry || owner._registry || owner; - - return registry.register(...arguments); - }; - } - - return owner; -} - -export { modelHasAttributeOrRelationshipNamedType, getOwner }; diff --git a/addon/-record-data-rfc-private/utils/parse-response-headers.js b/addon/-record-data-rfc-private/utils/parse-response-headers.js deleted file mode 100644 index 3e02ab16fc8..00000000000 --- a/addon/-record-data-rfc-private/utils/parse-response-headers.js +++ /dev/null @@ -1,36 +0,0 @@ -const CLRF = '\u000d\u000a'; - -export default function parseResponseHeaders(headersString) { - let headers = Object.create(null); - - if (!headersString) { - return headers; - } - - let headerPairs = headersString.split(CLRF); - for (let i = 0; i < headerPairs.length; i++) { - let header = headerPairs[i]; - let j = 0; - let foundSep = false; - - for (; j < header.length; j++) { - if (header.charCodeAt(j) === 58 /* ':' */) { - foundSep = true; - break; - } - } - - if (foundSep === false) { - continue; - } - - let field = header.substring(0, j).trim(); - let value = header.substring(j + 1, header.length).trim(); - - if (value) { - headers[field] = value; - } - } - - return headers; -} diff --git a/index.js b/index.js index 0cee37ca2af..a307983002e 100644 --- a/index.js +++ b/index.js @@ -105,20 +105,33 @@ module.exports = { version(), // compile the VERSION into the build ]); + let corePrivate = new Funnel(tree, { + include: ['-private/**'] + }); let withPrivate; if (USE_RECORD_DATA_RFC) { withPrivate = new Funnel(tree, { - include: ['-record-data-rfc-private/**'], + srcDir: '-record-data-private', + destDir: '-private' }); } else { - withPrivate = new Funnel(tree, { include: ['-private/**'] }); + withPrivate = new Funnel(tree, { + srcDir: '-legacy-private', + destDir: '-private' + }); } + // do not allow overwrite, conflicts should error + // overwrite: false is default, but we are being explicit here + // since this is very important + withPrivate = merge([corePrivate, withPrivate], { overwrite: false }); + let withoutPrivate = new Funnel(treeWithVersion, { exclude: [ '-private', - '-record-data-rfc-private', + '-record-data-private', + '-legacy-private', isProductionEnv() && !isInstrumentedBuild() ? '-debug' : false, ].filter(Boolean), @@ -141,7 +154,7 @@ module.exports = { privateTree = new Rollup(privateTree, { rollup: { - input: USE_RECORD_DATA_RFC ? '-record-data-rfc-private/index.js' : '-private/index.js', + input: '-private/index.js', output: [ { file: 'ember-data/-private.js', From 4a4e0165cef991742a45bd59205955dd826c046b Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 8 May 2018 22:27:52 -0700 Subject: [PATCH 2237/2527] prettier index.js --- index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index a307983002e..79ee357143c 100644 --- a/index.js +++ b/index.js @@ -106,19 +106,19 @@ module.exports = { ]); let corePrivate = new Funnel(tree, { - include: ['-private/**'] + include: ['-private/**'], }); let withPrivate; if (USE_RECORD_DATA_RFC) { withPrivate = new Funnel(tree, { srcDir: '-record-data-private', - destDir: '-private' + destDir: '-private', }); } else { withPrivate = new Funnel(tree, { srcDir: '-legacy-private', - destDir: '-private' + destDir: '-private', }); } From 090a06bc52564b9ce98c24680db794b287292eba Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 8 May 2018 22:56:19 -0700 Subject: [PATCH 2238/2527] [CHORE] cull unnecessary files left from previous build setups --- lib/babel-build.js | 84 ------------------- lib/enable-optional-features-via-url/index.js | 35 -------- .../package.json | 6 -- ...allow-multiple-var-decl-with-assignment.js | 43 ---------- .../disallow-space-before-semicolon.js | 29 ------- ...-inside-round-braces-in-call-expression.js | 71 ---------------- ...ing-parenthesis-in-function-declaration.js | 57 ------------- lib/stripped-build.js | 8 -- package.json | 3 - tests/index.html | 1 - 10 files changed, 337 deletions(-) delete mode 100644 lib/babel-build.js delete mode 100644 lib/enable-optional-features-via-url/index.js delete mode 100644 lib/enable-optional-features-via-url/package.json delete mode 100644 lib/jscs-rules/disallow-multiple-var-decl-with-assignment.js delete mode 100644 lib/jscs-rules/disallow-space-before-semicolon.js delete mode 100644 lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js delete mode 100644 lib/jscs-rules/require-spaces-after-closing-parenthesis-in-function-declaration.js delete mode 100644 lib/stripped-build.js diff --git a/lib/babel-build.js b/lib/babel-build.js deleted file mode 100644 index 89ac0e7854c..00000000000 --- a/lib/babel-build.js +++ /dev/null @@ -1,84 +0,0 @@ -'use strict'; - -var babel = require('broccoli-babel-transpiler'); -var moduleResolve = require('amd-name-resolver').moduleResolve; - -function getDebugMacroPlugins() { - const DebugMacros = require('babel-plugin-debug-macros').default; - const isProduction = process.env.EMBER_ENV === 'production'; - - let options = { - envFlags: { - source: '@glimmer/env', - flags: { DEBUG: !isProduction, CI: !!process.env.CI }, - }, - - externalizeHelpers: { - global: 'Ember', - }, - - debugTools: { - source: '@ember/debug', - }, - }; - - return [DebugMacros, options]; -} - -function babelOptions(libraryName, _options) { - _options = _options || {}; - - var options = { - plugins: [], - postTransformPlugins: [], - sourceMaps: false, - moduleRoot: libraryName, - moduleIds: true, - // Transforms /index.js files to use their containing directory name - getModuleId: function(name) { - return name.replace(/\/index$/g, ''); - }, - resolveModuleSource: function(source, fileName) { - return moduleResolve.call(this, source, libraryName + '/' + fileName); - }, - }; - - Object.keys(_options).forEach(function(opt) { - options[opt] = _options[opt]; - }); - - options.plugins = options.plugins - .concat( - [ - getDebugMacroPlugins(), - [ - 'ember-modules-api-polyfill', - { blacklist: { '@ember/debug': ['assert', 'deprecate', 'warn'] } }, - ], - ['transform-es2015-modules-amd', { noInterop: true, loose: true }], - 'transform-es2015-arrow-functions', - 'transform-es2015-computed-properties', - 'transform-es2015-shorthand-properties', - 'transform-es2015-template-literals', - 'transform-es2015-parameters', - 'transform-es2015-destructuring', - 'transform-es2015-spread', - 'transform-es2015-block-scoping', - 'transform-es2015-constants', - ['transform-es2015-classes', { loose: true }], - ], - options.postTransformPlugins - ) - .filter(Boolean); - - // this is not a "real" babel option, so we delete it - delete options.postTransformPlugins; - - return options; -} - -module.exports = function(packageName, tree, _options) { - var options = babelOptions(packageName, _options); - - return babel(tree, options); -}; diff --git a/lib/enable-optional-features-via-url/index.js b/lib/enable-optional-features-via-url/index.js deleted file mode 100644 index 2819bec72c2..00000000000 --- a/lib/enable-optional-features-via-url/index.js +++ /dev/null @@ -1,35 +0,0 @@ -module.exports = { - name: 'enable-optional-features-via-url', - - /** - So the ENABLE_OPTIONAL_FEATURES flag is considered correctly within the - index.html, it needs to be set before Ember.js is loaded. Since there is - currently no way to access the `window` object within config/environment.js - (and hereby check if there is a query parameter present for the checkbox), - a script is injected, before Ember.js is loaded. The script checks if there - is no value yet for the ENABLE_OPTIONAL_FEATURES flag, and if so, it sets - the flag to true when there is a `enableoptionalfeatures` query parameter. - */ - contentFor: function(name) { - if (name === 'enable-optional-features') { - var array = [ - '', - ]; - - return array.join('\n'); - } - }, -}; diff --git a/lib/enable-optional-features-via-url/package.json b/lib/enable-optional-features-via-url/package.json deleted file mode 100644 index ea6c08dab4d..00000000000 --- a/lib/enable-optional-features-via-url/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "enable-optional-features-via-url", - "keywords": [ - "ember-addon" - ] -} diff --git a/lib/jscs-rules/disallow-multiple-var-decl-with-assignment.js b/lib/jscs-rules/disallow-multiple-var-decl-with-assignment.js deleted file mode 100644 index dd851874a4d..00000000000 --- a/lib/jscs-rules/disallow-multiple-var-decl-with-assignment.js +++ /dev/null @@ -1,43 +0,0 @@ -var assert = require('assert'); - -module.exports = function() {}; - -module.exports.prototype = { - configure: function(disallowMultipleVarDeclWithAssignment) { - assert( - typeof disallowMultipleVarDeclWithAssignment === 'boolean', - 'disallowMultipleVarDeclWithAssignment option requires boolean value' - ); - assert( - disallowMultipleVarDeclWithAssignment === true, - 'disallowMultipleVarDeclWithAssignment option requires true value or should be removed' - ); - }, - - getOptionName: function() { - return 'disallowMultipleVarDeclWithAssignment'; - }, - - check: function(file, errors) { - file.iterateNodesByType('VariableDeclaration', function(node) { - // allow multiple var declarations in for statement - // for (var i = 0, j = myArray.length; i < j; i++) {} - if (node.parentNode.type === 'ForStatement') { - return; - } - - var hasAssignment = false; - var multiDeclaration = node.declarations.length > 1; - - node.declarations.forEach(function(declaration) { - if (declaration.init) { - hasAssignment = true; - } - }); - - if (hasAssignment && multiDeclaration) { - errors.add('Multiple assigning variable declarations', node.loc.start); - } - }); - }, -}; diff --git a/lib/jscs-rules/disallow-space-before-semicolon.js b/lib/jscs-rules/disallow-space-before-semicolon.js deleted file mode 100644 index c7c711b38c2..00000000000 --- a/lib/jscs-rules/disallow-space-before-semicolon.js +++ /dev/null @@ -1,29 +0,0 @@ -var assert = require('assert'); - -module.exports = function() {}; - -module.exports.prototype = { - configure: function(disallowSpacesBeforeSemicolons) { - assert( - typeof disallowSpacesBeforeSemicolons === 'boolean', - 'disallowSpacesBeforeSemicolons option requires boolean value' - ); - assert( - disallowSpacesBeforeSemicolons === true, - 'disallowSpacesBeforeSemicolons option requires true value or should be removed' - ); - }, - - getOptionName: function() { - return 'disallowSpacesBeforeSemicolons'; - }, - - check: function(file, errors) { - var lines = file.getLines(); - for (var i = 0; i < lines.length; i++) { - if (lines[i].match(/\s+;$/)) { - errors.add('Spaces are disallowed before semicolons.', i + 1, lines[i].length - 2); - } - } - }, -}; diff --git a/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js b/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js deleted file mode 100644 index cae0a4d67b1..00000000000 --- a/lib/jscs-rules/disallow-space-inside-round-braces-in-call-expression.js +++ /dev/null @@ -1,71 +0,0 @@ -var assert = require('assert'); - -function spaceAfterBrace(arg, braceToken) { - if (arg) { - var supportedArgs = arg.type !== 'UnaryExpression' && arg.type !== 'BinaryExpression'; - - return supportedArgs && braceToken.value === '(' && braceToken.range[1] + 1 === arg.range[0]; - } - - return false; -} - -function spaceBeforeBrace(arg, braceToken) { - if (arg) { - var supportedArgs = arg.type !== 'UnaryExpression' && arg.type !== 'BinaryExpression'; - - return supportedArgs && braceToken.value === ')' && braceToken.range[0] === arg.range[1] + 1; - } - - return false; -} - -module.exports = function() {}; - -module.exports.prototype = { - configure: function(requireSpacesInsideRoundBracesInCallExpression) { - assert( - requireSpacesInsideRoundBracesInCallExpression === true, - 'disallowSpacesInsideRoundBracesInCallExpression option requires true value or should be removed' - ); - }, - - getOptionName: function() { - return 'disallowSpacesInsideRoundBracesInCallExpression'; - }, - - check: function(file, errors) { - file.iterateNodesByType('CallExpression', function(node) { - var nodeBeforeRoundBrace = node; - - if (node.callee) { - nodeBeforeRoundBrace = node.callee; - } - - var roundBraceTokenStart = file.getTokenByRangeStart(nodeBeforeRoundBrace.range[0]); - var roundBraceTokenEnd = file.getTokenByRangeStart(nodeBeforeRoundBrace.range[0]); - - do { - roundBraceTokenStart = file.findNextToken(roundBraceTokenStart, 'Punctuator', '('); - roundBraceTokenEnd = file.findNextToken(roundBraceTokenEnd, 'Punctuator', ')'); - } while (roundBraceTokenStart.range[0] < nodeBeforeRoundBrace.range[1]); - - var firstArg = nodeBeforeRoundBrace.parentNode.arguments[0]; - var lastArg = - nodeBeforeRoundBrace.parentNode.arguments[ - nodeBeforeRoundBrace.parentNode.arguments.length - 1 - ]; - - var spaceAfterOpeningRoundBraceExists = spaceAfterBrace(firstArg, roundBraceTokenStart); - var spaceBeforeClosingRoundBraceExists = spaceBeforeBrace(lastArg, roundBraceTokenEnd); - - if (spaceAfterOpeningRoundBraceExists) { - errors.add('Illegal space after opening round brace', roundBraceTokenStart.loc.start); - } - - if (spaceBeforeClosingRoundBraceExists) { - errors.add('Illegal space before closing round brace', roundBraceTokenEnd.loc.start); - } - }); - }, -}; diff --git a/lib/jscs-rules/require-spaces-after-closing-parenthesis-in-function-declaration.js b/lib/jscs-rules/require-spaces-after-closing-parenthesis-in-function-declaration.js deleted file mode 100644 index 62120235446..00000000000 --- a/lib/jscs-rules/require-spaces-after-closing-parenthesis-in-function-declaration.js +++ /dev/null @@ -1,57 +0,0 @@ -var assert = require('assert'); - -module.exports = function() {}; - -module.exports.prototype = { - configure: function(options) { - assert( - typeof options === 'object', - 'requireSpacesAfterClosingParenthesisInFunctionDeclaration option must be the object' - ); - - assert( - options.beforeOpeningCurlyBrace || options.beforeOpeningRoundBrace, - 'requireSpacesAfterClosingParenthesisInFunctionDeclaration must have beforeOpeningCurlyBrace or beforeOpeningRoundBrace property' - ); - - this._beforeOpeningRoundBrace = Boolean(options.beforeOpeningRoundBrace); - this._beforeOpeningCurlyBrace = Boolean(options.beforeOpeningCurlyBrace); - }, - - getOptionName: function() { - return 'requireSpacesAfterClosingParenthesisInFunctionDeclaration'; - }, - - check: function(file, errors) { - var beforeOpeningRoundBrace = this._beforeOpeningRoundBrace; - var beforeOpeningCurlyBrace = this._beforeOpeningCurlyBrace; - - file.iterateNodesByType(['FunctionDeclaration'], function(node) { - var functionToken = file.getFirstNodeToken(node.id || node); - var nextToken = file.getNextToken(functionToken); - - if (beforeOpeningRoundBrace) { - if (nextToken) { - errors.add('Missing space before opening round brace', nextToken.loc.start); - } - } else { - if (!nextToken) { - errors.add('Illegal space before opening round brace', functionToken.loc.end); - } - } - - // errors if no token is found unless `includeComments` is passed - var tokenBeforeBody = file.getPrevToken(node.body, { includeComments: true }); - - if (beforeOpeningCurlyBrace) { - if (tokenBeforeBody) { - errors.add('Missing space before opening curly brace', tokenBeforeBody.loc.start); - } - } else { - if (!tokenBeforeBody) { - errors.add('Illegal space before opening curly brace', node.body.loc.end); - } - } - }); - }, -}; diff --git a/lib/stripped-build.js b/lib/stripped-build.js deleted file mode 100644 index f70e7a8723c..00000000000 --- a/lib/stripped-build.js +++ /dev/null @@ -1,8 +0,0 @@ -var babelBuild = require('./babel-build'); -var strippedBuildPlugins = require('./stripped-build-plugins'); - -module.exports = function(packageName, tree, environmentBuildingFor) { - var options = strippedBuildPlugins(environmentBuildingFor); - - return babelBuild(packageName, tree, options); -}; diff --git a/package.json b/package.json index 375a360cd77..a6723173982 100644 --- a/package.json +++ b/package.json @@ -122,9 +122,6 @@ ], "ember-addon": { "configPath": "tests/dummy/config", - "paths": [ - "lib/enable-optional-features-via-url" - ], "after": "ember-cli-mocha" } } diff --git a/tests/index.html b/tests/index.html index 1f02805e3bf..5209b852321 100644 --- a/tests/index.html +++ b/tests/index.html @@ -20,7 +20,6 @@ {{content-for "body"}} {{content-for "test-body"}} - {{content-for "enable-optional-features"}} From 5a67afa840b6b3ed51b1b23eb39cd5973a82b03f Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 8 May 2018 22:58:25 -0700 Subject: [PATCH 2239/2527] dont need to be after mocha for detection --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index a6723173982..52c9b27ac05 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,6 @@ "ember-addon" ], "ember-addon": { - "configPath": "tests/dummy/config", - "after": "ember-cli-mocha" + "configPath": "tests/dummy/config" } } From f2caef84e917fc3014aafac0bfd474e4b343459e Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 1 May 2018 02:09:46 -0700 Subject: [PATCH 2240/2527] [BUGFIX] ensure ManyArray state is in-sync with relationship state port tests but skip them make a TODO that works with testem leave explanation print failed assertions if possible granular todos remove dead loop --- addon/-legacy-private/system/many-array.js | 17 +- .../system/relationships/state/has-many.js | 10 +- .../relationships/state/relationship.js | 2 +- package.json | 1 + tests/helpers/todo.js | 95 +++++++ .../records/relationship-changes-test.js | 12 +- .../relationships/many-to-many-test.js | 164 ++++++------ .../unit/model/relationships/has-many-test.js | 240 +++++++++++++++++- yarn.lock | 15 +- 9 files changed, 452 insertions(+), 104 deletions(-) create mode 100644 tests/helpers/todo.js diff --git a/addon/-legacy-private/system/many-array.js b/addon/-legacy-private/system/many-array.js index 50fcc56c5d5..43e65056b28 100644 --- a/addon/-legacy-private/system/many-array.js +++ b/addon/-legacy-private/system/many-array.js @@ -136,9 +136,7 @@ export default EmberObject.extend(MutableArray, Evented, { }, objectAt(index) { - if (this.relationship._willUpdateManyArray) { - this.relationship._flushPendingManyArrayUpdates(); - } + this.relationship._flushPendingManyArrayUpdates(); let internalModel = this.currentState[index]; if (internalModel === undefined) { return; @@ -152,17 +150,8 @@ export default EmberObject.extend(MutableArray, Evented, { if (!_objectIsAlive(this)) { return; } - let toSet = this.canonicalState; - - //a hack for not removing new records - //TODO remove once we have proper diffing - let newInternalModels = this.currentState.filter( - // only add new internalModels which are not yet in the canonical state of this - // relationship (a new internalModel can be in the canonical state if it has - // been 'acknowleged' to be in the relationship via a store.push) - internalModel => internalModel.isNew() && toSet.indexOf(internalModel) === -1 - ); - toSet = toSet.concat(newInternalModels); + + let toSet = this.relationship.members.list.slice(); // diff to find changes let diff = diffArray(this.currentState, toSet); diff --git a/addon/-legacy-private/system/relationships/state/has-many.js b/addon/-legacy-private/system/relationships/state/has-many.js index 54253422634..ea6eaefb072 100755 --- a/addon/-legacy-private/system/relationships/state/has-many.js +++ b/addon/-legacy-private/system/relationships/state/has-many.js @@ -119,11 +119,9 @@ export default class ManyRelationship extends Relationship { } scheduleManyArrayUpdate(internalModel, idx) { - // ideally we would early exit here, but some tests - // currently suggest that we cannot. - // if (!this._manyArray) { - // return; - // } + if (!this._manyArray) { + return; + } let pending = (this._pendingManyArrayUpdates = this._pendingManyArrayUpdates || []); pending.push(internalModel, idx); @@ -198,10 +196,10 @@ export default class ManyRelationship extends Relationship { } flushCanonical() { + super.flushCanonical(); if (this._manyArray) { this._manyArray.flushCanonical(); } - super.flushCanonical(); } removeInternalModelFromOwn(internalModel, idx) { diff --git a/addon/-legacy-private/system/relationships/state/relationship.js b/addon/-legacy-private/system/relationships/state/relationship.js index e8a842e7478..9ba5dc7b7a6 100644 --- a/addon/-legacy-private/system/relationships/state/relationship.js +++ b/addon/-legacy-private/system/relationships/state/relationship.js @@ -263,7 +263,7 @@ export default class Relationship { addCanonicalInternalModel(internalModel, idx) { heimdall.increment(addCanonicalInternalModel); if (!this.canonicalMembers.has(internalModel)) { - this.canonicalMembers.add(internalModel); + this.canonicalMembers.addWithIndex(internalModel, idx); this.setupInverseRelationship(internalModel); } this.flushCanonicalLater(); diff --git a/package.json b/package.json index 375a360cd77..06b29351fd5 100644 --- a/package.json +++ b/package.json @@ -92,6 +92,7 @@ "ember-disable-proxy-controllers": "^1.0.0", "ember-export-application-global": "^1.0.5", "ember-load-initializers": "^0.6.0", + "ember-maybe-import-regenerator": "^0.1.6", "ember-publisher": "0.0.7", "ember-qunit": "^3.4.0", "ember-qunit-assert-helpers": "^0.2.1", diff --git a/tests/helpers/todo.js b/tests/helpers/todo.js new file mode 100644 index 00000000000..b6d62518b9b --- /dev/null +++ b/tests/helpers/todo.js @@ -0,0 +1,95 @@ +/* global Proxy */ +import QUnit, { test } from 'qunit'; + +export default function todo(description, callback) { + test(`[TODO] ${description}`, async function todoTest(assert) { + let todos = []; + hijackAssert(assert, todos); + + await callback(assert); + + assertTestStatus(assert, todos); + }); +} + +function hijackAssert(assert, todos) { + const pushResult = assert.pushResult; + + assert.pushResult = function hijackedPushResult(assertion) { + let result = assertion.result; + if (!assertion.isTodo && result === false) { + assertion.message = `[REGRESSION ENCOUNTERED] ${assertion.message}`; + } + + return pushResult.call(assert, assertion); + }; + let handler = { + get(target, propKey /*, receiver*/) { + const origMethod = target[propKey]; + + if (typeof origMethod === 'function' && propKey === 'pushResult') { + return function captureResult(assertion) { + let result = assertion.result; + assertion.isTodo = true; + assertion.message = `[TODO ${result === true ? 'COMPLETED' : 'INCOMPLETE'}] ${ + assertion.message + }`; + + todos.push(assertion); + origMethod.call(target, assertion); + }; + } else { + return origMethod; + } + }, + }; + + assert.todo = new Proxy(assert, handler); +} + +function assertTestStatus(assert, todos) { + assert.todo = false; + const totalTodoFailures = todos.reduce((c, r) => { + return r.result === false ? c + 1 : c; + }, 0); + const results = QUnit.config.current.assertions; + const totalFailures = results.reduce((c, r) => { + return r.result === false ? c + 1 : c; + }, 0); + const hasNonTodoFailures = totalFailures > totalTodoFailures; + const hasSomeCompletedTodos = totalTodoFailures < todos.length; + const totalWasMet = assert.test.expected === null || assert.test.expected === results.length; + const todoIsComplete = totalWasMet && totalTodoFailures === 0; + + if (todoIsComplete) { + assert.pushResult({ + isTodo: true, + actual: true, + expected: false, + message: + '[TODO COMPLETED] This TODO is now complete (all "todo" assertions pass) and MUST be converted from todo() to test()', + result: false, + }); + } else if (hasNonTodoFailures) { + assert.pushResult({ + isTodo: true, + actual: false, + expected: true, + message: + '[REGRESSION MUST-FIX] This TODO is has regressed (a non "todo" assertion has failed) and MUST be fixed', + result: false, + }); + } else if (hasSomeCompletedTodos) { + assert.pushResult({ + isTodo: true, + actual: false, + expected: true, + message: + '[TODOS COMPLETED] Some assert.todos assertions have been completed and MUST now be converted from assert.todo to assert.', + result: false, + }); + } else { + assert.test.skip = true; + assert.test.testReport.skipped = true; + } +} diff --git a/tests/integration/records/relationship-changes-test.js b/tests/integration/records/relationship-changes-test.js index b7c1d38d764..d6b38002966 100644 --- a/tests/integration/records/relationship-changes-test.js +++ b/tests/integration/records/relationship-changes-test.js @@ -643,16 +643,16 @@ test('Calling push with relationship triggers willChange and didChange with deta let observer = { arrayWillChange(array, start, removing, adding) { willChangeCount++; - assert.equal(start, 0); - assert.equal(removing, 0); - assert.equal(adding, 1); + assert.equal(start, 0, 'change will start at the beginning'); + assert.equal(removing, 0, 'we have no removals'); + assert.equal(adding, 1, 'we have one insertion'); }, arrayDidChange(array, start, removed, added) { didChangeCount++; - assert.equal(start, 0); - assert.equal(removed, 0); - assert.equal(added, 1); + assert.equal(start, 0, 'change did start at the beginning'); + assert.equal(removed, 0, 'change had no removals'); + assert.equal(added, 1, 'change had one insertion'); }, }; diff --git a/tests/integration/relationships/many-to-many-test.js b/tests/integration/relationships/many-to-many-test.js index e0f56037619..e8ca4bcbfe1 100644 --- a/tests/integration/relationships/many-to-many-test.js +++ b/tests/integration/relationships/many-to-many-test.js @@ -1,13 +1,11 @@ /*eslint no-unused-vars: ["error", { "varsIgnorePattern": "(ada)" }]*/ import { resolve, Promise as EmberPromise } from 'rsvp'; - import { run } from '@ember/runloop'; - +import { get } from '@ember/object'; import setupStore from 'dummy/tests/helpers/store'; - import { module, test } from 'qunit'; - +import todo from '../../helpers/todo'; import DS from 'ember-data'; const { attr, hasMany } = DS; @@ -552,82 +550,100 @@ test('Deleting an unpersisted record via rollbackAttributes that has a hasMany r assert.equal(user.get('accounts.length'), 0, 'Accounts got rolledback correctly'); }); -test('Re-loading a removed record should re add it to the relationship when the removed record is the last one in the relationship', function(assert) { - let account, ada, byron; - - run(() => { - account = store.push({ - data: { - id: '2', - type: 'account', - attributes: { - state: 'account 1', - }, - }, - }); - ada = store.push({ - data: { - id: '1', - type: 'user', - attributes: { - name: 'Ada Lovelace', - }, - relationships: { - accounts: { - data: [ - { - id: '2', - type: 'account', - }, - ], +todo( + 'Re-loading a removed record should re add it to the relationship when the removed record is the last one in the relationship', + function(assert) { + assert.expect(4); + let account, ada, byron; + + run(() => { + account = store.push({ + data: { + id: '2', + type: 'account', + attributes: { + state: 'account 1', }, }, - }, - }); - byron = store.push({ - data: { - id: '2', - type: 'user', - attributes: { - name: 'Lord Byron', - }, - relationships: { - accounts: { - data: [ - { - id: '2', - type: 'account', - }, - ], + }); + ada = store.push({ + data: { + id: '1', + type: 'user', + attributes: { + name: 'Ada Lovelace', + }, + relationships: { + accounts: { + data: [ + { + id: '2', + type: 'account', + }, + ], + }, }, }, - }, - }); - account.get('users').removeObject(byron); - account = store.push({ - data: { - id: '2', - type: 'account', - attributes: { - state: 'account 1', + }); + byron = store.push({ + data: { + id: '2', + type: 'user', + attributes: { + name: 'Lord Byron', + }, + relationships: { + accounts: { + data: [ + { + id: '2', + type: 'account', + }, + ], + }, + }, }, - relationships: { - users: { - data: [ - { - id: '1', - type: 'user', - }, - { - id: '2', - type: 'user', - }, - ], + }); + account.get('users').removeObject(byron); + account = store.push({ + data: { + id: '2', + type: 'account', + attributes: { + state: 'account 1', + }, + relationships: { + users: { + data: [ + { + id: '1', + type: 'user', + }, + { + id: '2', + type: 'user', + }, + ], + }, }, }, - }, + }); }); - }); - assert.equal(account.get('users.length'), 2, 'Accounts were updated correctly'); -}); + let state = account.hasMany('users').hasManyRelationship.canonicalMembers.list; + let users = account.get('users'); + + assert.todo.equal(users.get('length'), 1, 'Accounts were updated correctly (ui state)'); + assert.todo.deepEqual( + users.map(r => get(r, 'id')), + ['1'], + 'Accounts were updated correctly (ui state)' + ); + assert.equal(state.length, 2, 'Accounts were updated correctly (server state)'); + assert.deepEqual( + state.map(r => r.id), + ['1', '2'], + 'Accounts were updated correctly (server state)' + ); + } +); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 7f050c6fbbc..dafd8e78df7 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -2,11 +2,10 @@ import { hash, Promise as EmberPromise } from 'rsvp'; import { get, observer } from '@ember/object'; import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; - import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; - import DS from 'ember-data'; +import todo from '../../../helpers/todo'; let env; @@ -1303,6 +1302,242 @@ test('new items added to a hasMany relationship are not cleared by a delete', fu ); }); +todo( + '[push hasMany] new items added to a hasMany relationship are not cleared by a store.push', + function(assert) { + assert.expect(5); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + pets: DS.hasMany('pet', { async: false, inverse: null }), + }); + + const Pet = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person', { async: false, inverse: null }), + }); + + let env = setupStore({ + person: Person, + pet: Pet, + }); + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.deleteRecord = () => { + return EmberPromise.resolve({ data: null }); + }; + + let { store } = env; + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn', + }, + relationships: { + pets: { + data: [{ type: 'pet', id: '1' }], + }, + }, + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shenanigans', + }, + }, + { + type: 'pet', + id: '2', + attributes: { + name: 'Rambunctious', + }, + }, + { + type: 'pet', + id: '3', + attributes: { + name: 'Rebel', + }, + }, + ], + }); + }); + + const person = store.peekRecord('person', '1'); + const pets = run(() => person.get('pets')); + + const shen = pets.objectAt(0); + const rebel = store.peekRecord('pet', '3'); + + assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); + assert.deepEqual( + pets.map(p => get(p, 'id')), + ['1'], + 'precond - relationship has the correct pets to start' + ); + + run(() => { + pets.pushObjects([rebel]); + }); + + assert.deepEqual( + pets.map(p => get(p, 'id')), + ['1', '3'], + 'precond2 - relationship now has the correct two pets' + ); + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + relationships: { + pets: { + data: [{ type: 'pet', id: '2' }], + }, + }, + }, + }); + }); + + let hasManyCanonical = person.hasMany('pets').hasManyRelationship.canonicalMembers.list; + + assert.todo.deepEqual( + pets.map(p => get(p, 'id')), + ['2', '3'], + 'relationship now has the correct current pets' + ); + assert.deepEqual( + hasManyCanonical.map(p => get(p, 'id')), + ['2'], + 'relationship now has the correct canonical pets' + ); + } +); + +todo( + '[push hasMany] items removed from a hasMany relationship are not cleared by a store.push', + function(assert) { + assert.expect(5); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + pets: DS.hasMany('pet', { async: false, inverse: null }), + }); + + const Pet = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person', { async: false, inverse: null }), + }); + + let env = setupStore({ + person: Person, + pet: Pet, + }); + env.adapter.shouldBackgroundReloadRecord = () => false; + env.adapter.deleteRecord = () => { + return EmberPromise.resolve({ data: null }); + }; + + let { store } = env; + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris Thoburn', + }, + relationships: { + pets: { + data: [{ type: 'pet', id: '1' }, { type: 'pet', id: '3' }], + }, + }, + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { + name: 'Shenanigans', + }, + }, + { + type: 'pet', + id: '2', + attributes: { + name: 'Rambunctious', + }, + }, + { + type: 'pet', + id: '3', + attributes: { + name: 'Rebel', + }, + }, + ], + }); + }); + + const person = store.peekRecord('person', '1'); + const pets = run(() => person.get('pets')); + + const shen = pets.objectAt(0); + const rebel = store.peekRecord('pet', '3'); + + assert.equal(get(shen, 'name'), 'Shenanigans', 'precond - relationships work'); + assert.deepEqual( + pets.map(p => get(p, 'id')), + ['1', '3'], + 'precond - relationship has the correct pets to start' + ); + + run(() => { + pets.removeObject(rebel); + }); + + assert.deepEqual( + pets.map(p => get(p, 'id')), + ['1'], + 'precond2 - relationship now has the correct pet' + ); + + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + relationships: { + pets: { + data: [{ type: 'pet', id: '2' }, { type: 'pet', id: '3' }], + }, + }, + }, + }); + }); + + let hasManyCanonical = person.hasMany('pets').hasManyRelationship.canonicalMembers.list; + + assert.todo.deepEqual( + pets.map(p => get(p, 'id')), + ['2'], + 'relationship now has the correct current pets' + ); + assert.deepEqual( + hasManyCanonical.map(p => get(p, 'id')), + ['2', '3'], + 'relationship now has the correct canonical pets' + ); + } +); + test('new items added to an async hasMany relationship are not cleared by a delete', function(assert) { assert.expect(7); @@ -1715,6 +1950,7 @@ test('hasMany.firstObject.unloadRecord should not break that hasMany', function( assert.equal(cars.get('length'), 1); // unload now.. assert.equal(person.get('cars.length'), 1); // unload now.. }); + /* This test, when passing, affirms that a known limitation of ember-data still exists. diff --git a/yarn.lock b/yarn.lock index 27aafafdff9..b0f33026c71 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2520,7 +2520,7 @@ ember-cli-app-version@^3.0.0: ember-cli-babel "^6.8.0" git-repo-version "^1.0.0" -ember-cli-babel@6.12.0, ember-cli-babel@^6.0.0, ember-cli-babel@^6.10.0, ember-cli-babel@^6.3.0, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: +ember-cli-babel@6.12.0, ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.10.0, ember-cli-babel@^6.3.0, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: version "6.12.0" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.12.0.tgz#3adcdbe1278da1fcd0b9038f1360cb4ac5d4414c" dependencies: @@ -2933,6 +2933,15 @@ ember-load-initializers@^0.6.0: dependencies: ember-cli-babel "^5.1.6" +ember-maybe-import-regenerator@^0.1.6: + version "0.1.6" + resolved "https://registry.npmjs.org/ember-maybe-import-regenerator/-/ember-maybe-import-regenerator-0.1.6.tgz#35d41828afa6d6a59bc0da3ce47f34c573d776ca" + dependencies: + broccoli-funnel "^1.0.1" + broccoli-merge-trees "^1.0.0" + ember-cli-babel "^6.0.0-beta.4" + regenerator-runtime "^0.9.5" + ember-publisher@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" @@ -6406,6 +6415,10 @@ regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" +regenerator-runtime@^0.9.5: + version "0.9.6" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" + regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" From 719ca5cab5e02fb9334ad17dda2e3423a64c0feb Mon Sep 17 00:00:00 2001 From: Valentin Federer Date: Tue, 5 Jun 2018 16:58:15 +0200 Subject: [PATCH 2241/2527] Update url to customizing adapters page --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3efd95d35b9..6b31d835501 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ By default, Ember Data will use the `JSONAPIAdapter`, which adheres to the [JSON To learn more about adapters, including what conventions the various adapters follow and how to build your own, see the Ember.js -Guides: [Customizing Adapters](https://emberjs.com/guides/models/customizing-adapters). +Guides: [Customizing Adapters](https://guides.emberjs.com/release/models/customizing-adapters/). ### Fetching a Collection of Models From 201f35a391677864e4e343e4b78edd8f7b2e5005 Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Wed, 23 May 2018 21:26:24 +0100 Subject: [PATCH 2242/2527] [Feature] added module-unification adapter and adapter-test blueprints --- blueprints/adapter-test/index.js | 34 +- .../unit => __root__}/__path__/__test__.js | 0 .../unit => __root__}/__path__/__test__.js | 0 blueprints/adapter/index.js | 23 +- .../extend-from-application-entity.js | 54 ++- lib/utilities/module-unification.js | 7 + node-tests/blueprints/adapter-test.js | 262 ++++++++---- package.json | 3 +- yarn.lock | 390 ++++++++++++------ 9 files changed, 557 insertions(+), 216 deletions(-) rename blueprints/adapter-test/mocha-files/{tests/unit => __root__}/__path__/__test__.js (100%) rename blueprints/adapter-test/qunit-files/{tests/unit => __root__}/__path__/__test__.js (100%) create mode 100644 lib/utilities/module-unification.js diff --git a/blueprints/adapter-test/index.js b/blueprints/adapter-test/index.js index 8fb29a4621d..cc4511cc854 100644 --- a/blueprints/adapter-test/index.js +++ b/blueprints/adapter-test/index.js @@ -1,10 +1,38 @@ -var testInfo = require('ember-cli-test-info'); -var useTestFrameworkDetector = require('../test-framework-detector'); +const testInfo = require('ember-cli-test-info'); +const useTestFrameworkDetector = require('../test-framework-detector'); +const isModuleUnificationProject = require('../../lib/utilities/module-unification') + .isModuleUnificationProject; +const path = require('path'); module.exports = useTestFrameworkDetector({ description: 'Generates an ember-data adapter unit test', - locals: function(options) { + fileMapTokens(options) { + if (isModuleUnificationProject(this.project)) { + return { + __root__() { + return 'src'; + }, + __path__(options) { + return path.join('data', 'models', options.dasherizedModuleName); + }, + __test__() { + return 'adapter-test'; + }, + }; + } else { + return { + __root__() { + return 'tests'; + }, + __path__() { + return path.join('unit', 'adapters'); + }, + }; + } + }, + + locals(options) { return { friendlyTestDescription: testInfo.description(options.entity.name, 'Unit', 'Adapter'), }; diff --git a/blueprints/adapter-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/adapter-test/mocha-files/__root__/__path__/__test__.js similarity index 100% rename from blueprints/adapter-test/mocha-files/tests/unit/__path__/__test__.js rename to blueprints/adapter-test/mocha-files/__root__/__path__/__test__.js diff --git a/blueprints/adapter-test/qunit-files/tests/unit/__path__/__test__.js b/blueprints/adapter-test/qunit-files/__root__/__path__/__test__.js similarity index 100% rename from blueprints/adapter-test/qunit-files/tests/unit/__path__/__test__.js rename to blueprints/adapter-test/qunit-files/__root__/__path__/__test__.js diff --git a/blueprints/adapter/index.js b/blueprints/adapter/index.js index d8db9642bb3..43269d3cdb9 100644 --- a/blueprints/adapter/index.js +++ b/blueprints/adapter/index.js @@ -1,11 +1,30 @@ -var extendFromApplicationEntity = require('../../lib/utilities/extend-from-application-entity'); +const extendFromApplicationEntity = require('../../lib/utilities/extend-from-application-entity'); +const isModuleUnificationProject = require('../../lib/utilities/module-unification') + .isModuleUnificationProject; +const path = require('path'); module.exports = { description: 'Generates an ember-data adapter.', availableOptions: [{ name: 'base-class', type: String }], - locals: function(options) { + fileMapTokens(options) { + if (isModuleUnificationProject(this.project)) { + return { + __root__() { + return 'src'; + }, + __path__(options) { + return path.join('data', 'models', options.dasherizedModuleName); + }, + __name__() { + return 'adapter'; + }, + }; + } + }, + + locals(options) { return extendFromApplicationEntity('adapter', 'DS.JSONAPIAdapter', options); }, }; diff --git a/lib/utilities/extend-from-application-entity.js b/lib/utilities/extend-from-application-entity.js index 0cdcac2431c..17511fbdaa2 100644 --- a/lib/utilities/extend-from-application-entity.js +++ b/lib/utilities/extend-from-application-entity.js @@ -1,26 +1,35 @@ -var stringUtil = require('ember-cli-string-utils'); -var SilentError = require('silent-error'); -var pathUtil = require('ember-cli-path-utils'); -var fs = require('fs'); -var path = require('path'); +const stringUtil = require('ember-cli-string-utils'); +const SilentError = require('silent-error'); +const pathUtil = require('ember-cli-path-utils'); +const fs = require('fs'); +const path = require('path'); +const isModuleUnificationProject = require('./module-unification').isModuleUnificationProject; module.exports = function(type, baseClass, options) { - var entityName = options.entity.name; - var isAddon = options.inRepoAddon || options.project.isEmberCLIAddon(); - var relativePath = pathUtil.getRelativePath(options.entity.name); + let entityName = options.entity.name; + let isAddon = options.inRepoAddon || options.project.isEmberCLIAddon(); + let relativePath = pathUtil.getRelativePath(options.entity.name); + let isModuleUnification = isModuleUnificationProject(options.project); if (options.pod && options.podPath) { relativePath = pathUtil.getRelativePath(options.podPath + options.entity.name); } - var entityDirectory = type + 's'; - var applicationEntityPath = path.join( - options.project.root, - 'app', - entityDirectory, - 'application.js' - ); - var hasApplicationEntity = fs.existsSync(applicationEntityPath); + let applicationEntityPath; + if (isModuleUnification) { + applicationEntityPath = path.join( + options.project.root, + 'src', + 'data', + 'models', + 'application', + 'adapter.js' + ); + } else { + applicationEntityPath = path.join(options.project.root, 'app', `${type}s`, 'application.js'); + } + + let hasApplicationEntity = fs.existsSync(applicationEntityPath); if (!isAddon && !options.baseClass && entityName !== 'application' && hasApplicationEntity) { options.baseClass = 'application'; } @@ -31,12 +40,19 @@ module.exports = function(type, baseClass, options) { 's cannot extend from themself. To resolve this, remove the `--base-class` option or change to a different base-class.' ); } - var importStatement = "import DS from 'ember-data';"; + let importStatement = "import DS from 'ember-data';"; if (options.baseClass) { - baseClass = stringUtil.classify(options.baseClass.replace('/', '-')); + let baseClassPath = options.baseClass; + baseClass = stringUtil.classify(baseClassPath.replace('/', '-')); baseClass = baseClass + stringUtil.classify(type); - importStatement = 'import ' + baseClass + " from '" + relativePath + options.baseClass + "';"; + + if (isModuleUnification) { + relativePath = `../${options.baseClass}/`; + baseClassPath = 'adapter'; + } + + importStatement = `import ${baseClass} from '${relativePath}${baseClassPath}';`; } return { diff --git a/lib/utilities/module-unification.js b/lib/utilities/module-unification.js new file mode 100644 index 00000000000..aa7f4683ae7 --- /dev/null +++ b/lib/utilities/module-unification.js @@ -0,0 +1,7 @@ +'use strict'; + +module.exports = { + isModuleUnificationProject(project) { + return project && project.isModuleUnification && project.isModuleUnification(); + }, +}; diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 23dbcc55f76..146f4a2ed43 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -9,6 +9,7 @@ const modifyPackages = blueprintHelpers.modifyPackages; const chai = require('ember-cli-blueprint-test-helpers/chai'); const expect = chai.expect; +const fs = require('fs-extra'); const SilentError = require('silent-error'); @@ -18,118 +19,237 @@ const fixture = require('../helpers/fixture'); describe('Acceptance: generate and destroy adapter blueprints', function() { setupTestHooks(this); - beforeEach(function() { - return emberNew(); - }); + describe('classic', function() { + beforeEach(function() { + return emberNew(); + }); - it('adapter', function() { - let args = ['adapter', 'foo']; + it('adapter', function() { + let args = ['adapter', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('app/adapters/foo.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.JSONAPIAdapter.extend({'); - return emberGenerateDestroy(args, _file => { - expect(_file('app/adapters/foo.js')) - .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.JSONAPIAdapter.extend({'); + expect(_file('tests/unit/adapters/foo-test.js')).to.equal( + fixture('adapter-test/foo-default.js') + ); + }); + }); - expect(_file('tests/unit/adapters/foo-test.js')).to.equal( - fixture('adapter-test/foo-default.js') + it('adapter extends application adapter if it exists', function() { + let args = ['adapter', 'foo']; + + return emberGenerate(['adapter', 'application']).then(() => + emberGenerateDestroy(args, _file => { + expect(_file('app/adapters/foo.js')) + .to.contain("import ApplicationAdapter from './application';") + .to.contain('export default ApplicationAdapter.extend({'); + + expect(_file('tests/unit/adapters/foo-test.js')).to.equal( + fixture('adapter-test/foo-default.js') + ); + }) ); }); - }); - it('adapter extends application adapter if it exists', function() { - let args = ['adapter', 'foo']; + it('adapter with --base-class', function() { + let args = ['adapter', 'foo', '--base-class=bar']; - return emberGenerate(['adapter', 'application']).then(() => - emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('app/adapters/foo.js')) - .to.contain("import ApplicationAdapter from './application';") - .to.contain('export default ApplicationAdapter.extend({'); + .to.contain("import BarAdapter from './bar';") + .to.contain('export default BarAdapter.extend({'); expect(_file('tests/unit/adapters/foo-test.js')).to.equal( fixture('adapter-test/foo-default.js') ); - }) - ); - }); - - it('adapter with --base-class', function() { - let args = ['adapter', 'foo', '--base-class=bar']; + }); + }); - return emberGenerateDestroy(args, _file => { - expect(_file('app/adapters/foo.js')) - .to.contain("import BarAdapter from './bar';") - .to.contain('export default BarAdapter.extend({'); + xit('adapter throws when --base-class is same as name', function() { + let args = ['adapter', 'foo', '--base-class=foo']; - expect(_file('tests/unit/adapters/foo-test.js')).to.equal( - fixture('adapter-test/foo-default.js') + return expect(emberGenerate(args)).to.be.rejectedWith( + SilentError, + /Adapters cannot extend from themself/ ); }); - }); - xit('adapter throws when --base-class is same as name', function() { - let args = ['adapter', 'foo', '--base-class=foo']; + it('adapter when is named "application"', function() { + let args = ['adapter', 'application']; - return expect(emberGenerate(args)).to.be.rejectedWith( - SilentError, - /Adapters cannot extend from themself/ - ); - }); + return emberGenerateDestroy(args, _file => { + expect(_file('app/adapters/application.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.JSONAPIAdapter.extend({'); - it('adapter when is named "application"', function() { - let args = ['adapter', 'application']; + expect(_file('tests/unit/adapters/application-test.js')).to.equal( + fixture('adapter-test/application-default.js') + ); + }); + }); - return emberGenerateDestroy(args, _file => { - expect(_file('app/adapters/application.js')) - .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.JSONAPIAdapter.extend({'); + it('adapter-test', function() { + let args = ['adapter-test', 'foo']; - expect(_file('tests/unit/adapters/application-test.js')).to.equal( - fixture('adapter-test/application-default.js') - ); + return emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/adapters/foo-test.js')).to.equal( + fixture('adapter-test/foo-default.js') + ); + }); }); - }); - it('adapter-test', function() { - let args = ['adapter-test', 'foo']; + describe('adapter-test with ember-cli-qunit@4.2.0', function() { + beforeEach(function() { + generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + }); - return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/adapters/foo-test.js')).to.equal( - fixture('adapter-test/foo-default.js') - ); + it('adapter-test-test foo', function() { + return emberGenerateDestroy(['adapter-test', 'foo'], _file => { + expect(_file('tests/unit/adapters/foo-test.js')).to.equal( + fixture('adapter-test/rfc232.js') + ); + }); + }); + }); + + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('adapter-test for mocha v0.12+', function() { + let args = ['adapter-test', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/adapters/foo-test.js')).to.equal( + fixture('adapter-test/foo-mocha-0.12.js') + ); + }); + }); }); }); - describe('adapter-test with ember-cli-qunit@4.2.0', function() { + describe('module unification', function() { beforeEach(function() { - generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + return emberNew().then(() => fs.ensureDirSync('src')); }); - it('adapter-test-test foo', function() { - return emberGenerateDestroy(['adapter-test', 'foo'], _file => { - expect(_file('tests/unit/adapters/foo-test.js')).to.equal( - fixture('adapter-test/rfc232.js') + it('adapter', function() { + let args = ['adapter', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('src/data/models/foo/adapter.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.JSONAPIAdapter.extend({'); + + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/foo-default.js') ); }); }); - }); - describe('with ember-cli-mocha v0.12+', function() { - beforeEach(function() { - modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-cli-mocha', dev: true }, - ]); - generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + it('adapter extends application adapter if it exists', function() { + let args = ['adapter', 'foo']; + + return emberGenerate(['adapter', 'application']).then(() => + emberGenerateDestroy(args, _file => { + expect(_file('src/data/models/foo/adapter.js')) + .to.contain("import ApplicationAdapter from '../application/adapter';") + .to.contain('export default ApplicationAdapter.extend({'); + + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/foo-default.js') + ); + }) + ); + }); + + it('adapter with --base-class', function() { + let args = ['adapter', 'foo', '--base-class=bar']; + + return emberGenerateDestroy(args, _file => { + expect(_file('src/data/models/foo/adapter.js')) + .to.contain("import BarAdapter from '../bar/adapter';") + .to.contain('export default BarAdapter.extend({'); + + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/foo-default.js') + ); + }); + }); + + xit('adapter throws when --base-class is same as name', function() { + let args = ['adapter', 'foo', '--base-class=foo']; + + return expect(emberGenerate(args)).to.be.rejectedWith( + SilentError, + /Adapters cannot extend from themself/ + ); }); - it('adapter-test for mocha v0.12+', function() { + it('adapter when is named "application"', function() { + let args = ['adapter', 'application']; + + return emberGenerateDestroy(args, _file => { + expect(_file('src/data/models/application/adapter.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.JSONAPIAdapter.extend({'); + + expect(_file('src/data/models/application/adapter-test.js')).to.equal( + fixture('adapter-test/application-default.js') + ); + }); + }); + + it('adapter-test', function() { let args = ['adapter-test', 'foo']; return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/adapters/foo-test.js')).to.equal( - fixture('adapter-test/foo-mocha-0.12.js') + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/foo-default.js') ); }); }); + + describe('adapter-test with ember-cli-qunit@4.2.0', function() { + beforeEach(function() { + generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + }); + + it('adapter-test-test foo', function() { + return emberGenerateDestroy(['adapter-test', 'foo'], _file => { + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/rfc232.js') + ); + }); + }); + }); + + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('adapter-test for mocha v0.12+', function() { + let args = ['adapter-test', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/foo-mocha-0.12.js') + ); + }); + }); + }); }); }); diff --git a/package.json b/package.json index 7570d65f4c6..45360b04663 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "broccoli-yuidoc": "^3.0.0", "co": "^4.6.0", "common-tags": "^1.4.0", - "ember-cli": "^2.11.1", + "ember-cli": "https://github.com/ember-cli/ember-cli#f724919b2d0455899411908531c9179240f5ef41", "ember-cli-app-version": "^3.0.0", "ember-cli-blueprint-test-helpers": "^0.18.3", "ember-cli-dependency-checker": "^2.1.0", @@ -104,6 +104,7 @@ "eslint-config-prettier": "^2.9.0", "eslint-plugin-node": "^6.0.1", "eslint-plugin-prettier": "^2.6.0", + "fs-extra": "^6.0.1", "github": "^1.1.1", "glob": "^5.0.13", "loader.js": "^4.5.0", diff --git a/yarn.lock b/yarn.lock index b0f33026c71..fab3191ed6b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -95,6 +95,10 @@ after@0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + agent-base@2: version "2.1.1" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" @@ -142,12 +146,6 @@ amd-name-resolver@0.0.7: dependencies: ensure-posix-path "^1.0.1" -amd-name-resolver@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-1.0.0.tgz#0e593b28d6fa3326ab1798107edaea961046e8d8" - dependencies: - ensure-posix-path "^1.0.1" - amd-name-resolver@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz#fc41b3848824b557313897d71f8d5a0184fbe679" @@ -288,6 +286,10 @@ arraybuffer.slice@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" +arraybuffer.slice@~0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -352,6 +354,10 @@ async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + async-promise-queue@^1.0.3, async-promise-queue@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/async-promise-queue/-/async-promise-queue-1.0.4.tgz#308baafbc74aff66a0bb6e7f4a18d4fe8434440c" @@ -1072,6 +1078,10 @@ base64id@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" +base64id@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -1218,6 +1228,13 @@ breakable@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" +broccoli-amd-funnel@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/broccoli-amd-funnel/-/broccoli-amd-funnel-1.3.0.tgz#c4426b4fce976e44295bd74f34725f53bdeb08e3" + dependencies: + broccoli-plugin "^1.3.0" + symlink-or-copy "^1.2.0" + broccoli-asset-rev@^2.4.5: version "2.6.0" resolved "https://registry.yarnpkg.com/broccoli-asset-rev/-/broccoli-asset-rev-2.6.0.tgz#0633fc3a0b2ba0c2c1d56fa9feb7b331fc83be6d" @@ -1264,12 +1281,6 @@ broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2: rsvp "^3.5.0" workerpool "^2.3.0" -broccoli-brocfile-loader@^0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/broccoli-brocfile-loader/-/broccoli-brocfile-loader-0.18.0.tgz#2e86021c805c34ffc8d29a2fb721cf273e819e4b" - dependencies: - findup-sync "^0.4.2" - broccoli-builder@^0.18.8: version "0.18.11" resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.11.tgz#a42393c7b10bb0380df255a616307945f5e26efb" @@ -1467,13 +1478,30 @@ broccoli-merge-trees@^2.0.0: broccoli-plugin "^1.3.0" merge-trees "^1.0.1" -broccoli-middleware@^1.0.0: +broccoli-middleware@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-1.2.1.tgz#a21f255f8bfe5a21c2f0fbf2417addd9d24c9436" dependencies: handlebars "^4.0.4" mime-types "^2.1.18" +broccoli-module-normalizer@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/broccoli-module-normalizer/-/broccoli-module-normalizer-1.3.0.tgz#f9982d9cbb776b4ed754161cc6547784d3eb19de" + dependencies: + broccoli-plugin "^1.3.0" + merge-trees "^1.0.1" + rimraf "^2.6.2" + symlink-or-copy "^1.1.8" + +broccoli-module-unification-reexporter@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/broccoli-module-unification-reexporter/-/broccoli-module-unification-reexporter-1.0.0.tgz#031909c5d3f159ec11d5f9e2346f2861db8acb3e" + dependencies: + broccoli-plugin "^1.3.0" + mkdirp "^0.5.1" + walk-sync "^0.3.2" + broccoli-node-info@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" @@ -1851,7 +1879,7 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" dependencies: @@ -1888,6 +1916,10 @@ chokidar@1.7.0: optionalDependencies: fsevents "^1.0.0" +ci-info@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" + circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" @@ -2165,7 +2197,7 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" -console-ui@^2.0.0: +console-ui@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-2.2.2.tgz#b294a2934de869dd06789ab4be69555411edef29" dependencies: @@ -2236,7 +2268,7 @@ core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -cross-spawn@^5.0.1, cross-spawn@^5.1.0: +cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -2244,6 +2276,16 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0: shebang-command "^1.2.0" which "^1.2.9" +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + cryptiles@0.2.x: version "0.2.2" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" @@ -2310,7 +2352,7 @@ debug@2.3.3: dependencies: ms "0.7.2" -debug@^3.0.0, debug@^3.1.0: +debug@^3.0.0, debug@^3.1.0, debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -2593,10 +2635,6 @@ ember-cli-get-component-path-option@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" -ember-cli-get-dependency-depth@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-get-dependency-depth/-/ember-cli-get-dependency-depth-1.0.0.tgz#e0afecf82a2d52f00f28ab468295281aec368d11" - ember-cli-htmlbars-inline-precompile@^0.4.3: version "0.4.4" resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.4.tgz#24a7617152630d64a047e553b72e00963a4f8d73" @@ -2668,28 +2706,6 @@ ember-cli-is-package-missing@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" -ember-cli-legacy-blueprints@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/ember-cli-legacy-blueprints/-/ember-cli-legacy-blueprints-0.2.1.tgz#480f37cb83f1eda2d46bbc7d07c59ea2e8ce9b84" - dependencies: - chalk "^2.3.0" - ember-cli-get-component-path-option "^1.0.0" - ember-cli-get-dependency-depth "^1.0.0" - ember-cli-is-package-missing "^1.0.0" - ember-cli-lodash-subset "^2.0.1" - ember-cli-normalize-entity-name "^1.0.0" - ember-cli-path-utils "^1.0.0" - ember-cli-string-utils "^1.0.0" - ember-cli-test-info "^1.0.0" - ember-cli-valid-component-name "^1.0.0" - ember-cli-version-checker "^2.1.0" - ember-router-generator "^1.0.0" - exists-sync "0.0.3" - fs-extra "^4.0.0" - inflection "^1.7.1" - rsvp "^4.7.0" - silent-error "^1.0.0" - ember-cli-lodash-subset@^1.0.7: version "1.0.12" resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" @@ -2808,16 +2824,16 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0: resolve "^1.3.3" semver "^5.3.0" -ember-cli@^2.11.1: - version "2.18.2" - resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-2.18.2.tgz#bb15313a15139a85248a86d203643f918ba40f57" +"ember-cli@https://github.com/ember-cli/ember-cli#f724919b2d0455899411908531c9179240f5ef41": + version "3.1.2" + resolved "https://github.com/ember-cli/ember-cli#f724919b2d0455899411908531c9179240f5ef41" dependencies: - amd-name-resolver "1.0.0" + amd-name-resolver "^1.2.0" babel-plugin-transform-es2015-modules-amd "^6.24.0" bower-config "^1.3.0" bower-endpoint-parser "0.2.2" + broccoli-amd-funnel "^1.3.0" broccoli-babel-transpiler "^6.0.0" - broccoli-brocfile-loader "^0.18.0" broccoli-builder "^0.18.8" broccoli-concat "^3.2.2" broccoli-config-loader "^1.0.0" @@ -2826,41 +2842,42 @@ ember-cli@^2.11.1: broccoli-funnel "^2.0.0" broccoli-funnel-reducer "^1.0.0" broccoli-merge-trees "^2.0.0" - broccoli-middleware "^1.0.0" + broccoli-middleware "^1.2.1" + broccoli-module-normalizer "^1.3.0" + broccoli-module-unification-reexporter "^1.0.0" broccoli-source "^1.1.0" broccoli-stew "^1.2.0" calculate-cache-key-for-tree "^1.0.0" capture-exit "^1.1.0" chalk "^2.0.1" + ci-info "^1.1.2" clean-base-url "^1.0.0" compression "^1.4.4" configstore "^3.0.0" - console-ui "^2.0.0" + console-ui "^2.2.2" core-object "^3.1.3" dag-map "^2.0.2" diff "^3.2.0" ember-cli-broccoli-sane-watcher "^2.0.4" ember-cli-is-package-missing "^1.0.0" - ember-cli-legacy-blueprints "^0.2.0" ember-cli-lodash-subset "^2.0.1" ember-cli-normalize-entity-name "^1.0.0" ember-cli-preprocess-registry "^3.1.0" ember-cli-string-utils "^1.0.0" - ember-try "^0.2.15" ensure-posix-path "^1.0.2" - execa "^0.8.0" - exists-sync "0.0.4" + execa "^0.10.0" exit "^0.1.2" express "^4.12.3" filesize "^3.1.3" find-up "^2.1.0" - fs-extra "^4.0.0" + find-yarn-workspace-root "^1.0.0" + fs-extra "^5.0.0" fs-tree-diff "^0.5.2" get-caller-file "^1.0.0" - git-repo-info "^1.4.1" - glob "7.1.1" + git-repo-info "^2.0.0" + glob "^7.1.2" heimdalljs "^0.2.3" - heimdalljs-fs-monitor "^0.1.0" + heimdalljs-fs-monitor "^0.2.0" heimdalljs-graph "^0.3.1" heimdalljs-logger "^0.1.7" http-proxy "^1.9.0" @@ -2889,13 +2906,14 @@ ember-cli@^2.11.1: sort-package-json "^1.4.0" symlink-or-copy "^1.1.8" temp "0.8.3" - testem "^2.0.0" + testem "^2.2.0" tiny-lr "^1.0.3" tree-sync "^1.2.1" uuid "^3.0.0" validate-npm-package-name "^3.0.0" walk-sync "^0.3.0" - yam "0.0.22" + watch-detector "^0.1.0" + yam "^0.0.24" ember-compatibility-helpers@^1.0.0-beta.2: version "1.0.0-beta.2" @@ -2987,7 +3005,7 @@ ember-rfc176-data@^0.3.0, ember-rfc176-data@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.1.tgz#6a5a4b8b82ec3af34f3010965fa96b936ca94519" -ember-router-generator@^1.0.0, ember-router-generator@^1.2.3: +ember-router-generator@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" dependencies: @@ -3033,7 +3051,7 @@ ember-try-config@^2.2.0: rsvp "^3.2.1" semver "^5.1.0" -ember-try@^0.2.15, ember-try@^0.2.23: +ember-try@^0.2.23: version "0.2.23" resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.23.tgz#39b57141b4907541d0ac8b503d211e6946b08718" dependencies: @@ -3089,6 +3107,22 @@ engine.io-client@1.8.0: xmlhttprequest-ssl "1.5.3" yeast "0.1.2" +engine.io-client@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~3.1.0" + engine.io-parser "~2.1.1" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~3.3.1" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + engine.io-parser@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" @@ -3100,6 +3134,16 @@ engine.io-parser@1.3.1: has-binary "0.1.6" wtf-8 "1.0.0" +engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196" + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.4" + has-binary2 "~1.0.2" + engine.io@1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" @@ -3111,6 +3155,17 @@ engine.io@1.8.0: engine.io-parser "1.3.1" ws "1.1.1" +engine.io@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.0.tgz#54332506f42f2edc71690d2f2a42349359f3bf7d" + dependencies: + accepts "~1.3.4" + base64id "1.0.0" + cookie "0.3.1" + debug "~3.1.0" + engine.io-parser "~2.1.0" + ws "~3.3.1" + ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" @@ -3359,23 +3414,11 @@ exec-sh@^0.2.0: dependencies: merge "^1.1.3" -execa@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -execa@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.9.0.tgz#adb7ce62cf985071f60580deb4a88b9e34712d01" +execa@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" dependencies: - cross-spawn "^5.0.1" + cross-spawn "^6.0.0" get-stream "^3.0.0" is-stream "^1.1.0" npm-run-path "^2.0.0" @@ -3654,6 +3697,13 @@ find-up@^2.1.0: dependencies: locate-path "^2.0.0" +find-yarn-workspace-root@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-1.1.0.tgz#9817b6748cb90719f4dc37b4538bb200c697356f" + dependencies: + fs-extra "^4.0.3" + micromatch "^3.1.4" + findup-sync@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" @@ -3663,15 +3713,6 @@ findup-sync@2.0.0: micromatch "^3.0.4" resolve-dir "^1.0.1" -findup-sync@^0.4.2: - version "0.4.3" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" - dependencies: - detect-file "^0.1.0" - is-glob "^2.0.1" - micromatch "^2.3.7" - resolve-dir "^0.1.0" - findup-sync@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-1.0.0.tgz#6f7e4b57b6ee3a4037b4414eaedea3f58f71e0ec" @@ -3817,7 +3858,7 @@ fs-extra@^2.0.0: graceful-fs "^4.1.2" jsonfile "^2.1.0" -fs-extra@^4.0.0: +fs-extra@^4.0.0, fs-extra@^4.0.2, fs-extra@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" dependencies: @@ -3825,6 +3866,22 @@ fs-extra@^4.0.0: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-readdir-recursive@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" @@ -3927,6 +3984,10 @@ git-repo-info@^1.1.2, git-repo-info@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" +git-repo-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-2.0.0.tgz#2e7a68ba3d0253e8e885c4138f922e6561de59bb" + git-repo-version@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-1.0.2.tgz#2c8e9bee5d970cafc0dd58480f9dc56d9afe8e4f" @@ -3967,17 +4028,6 @@ glob@3.2.11: inherits "2" minimatch "0.3" -glob@7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.2" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@^4.3.2: version "4.5.3" resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" @@ -4136,6 +4186,12 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" +has-binary2@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + dependencies: + isarray "2.0.1" + has-binary@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" @@ -4224,9 +4280,9 @@ hawk@3.1.3, hawk@~3.1.3: hoek "2.x.x" sntp "1.x.x" -heimdalljs-fs-monitor@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.1.0.tgz#d404a65688c6714c485469ed3495da4853440272" +heimdalljs-fs-monitor@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.2.1.tgz#b4079cfb85fb8326b8c75a7538fdbfa3d8afaa63" dependencies: heimdalljs "^0.2.0" heimdalljs-logger "^0.1.7" @@ -4235,7 +4291,7 @@ heimdalljs-graph@^0.3.1: version "0.3.4" resolved "https://registry.yarnpkg.com/heimdalljs-graph/-/heimdalljs-graph-0.3.4.tgz#0bd75797beeaa20b0ed59017aed3b2d95312acee" -heimdalljs-logger@^0.1.7: +heimdalljs-logger@^0.1.7, heimdalljs-logger@^0.1.9: version "0.1.9" resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz#d76ada4e45b7bb6f786fc9c010a68eb2e2faf176" dependencies: @@ -4370,7 +4426,7 @@ inflected@^1.1.6: version "1.1.7" resolved "https://registry.yarnpkg.com/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" -inflection@^1.12.0, inflection@^1.7.0, inflection@^1.7.1, inflection@^1.8.0: +inflection@^1.12.0, inflection@^1.7.0, inflection@^1.8.0: version "1.12.0" resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" @@ -4708,6 +4764,10 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" +isarray@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + isbinaryfile@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" @@ -5225,7 +5285,7 @@ lodash.keys@~2.3.0: lodash._shimkeys "~2.3.0" lodash.isobject "~2.3.0" -lodash.merge@^4.3.0, lodash.merge@^4.4.0, lodash.merge@^4.5.1, lodash.merge@^4.6.0: +lodash.merge@^4.3.0, lodash.merge@^4.5.1, lodash.merge@^4.6.0: version "4.6.1" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" @@ -5513,6 +5573,24 @@ micromatch@^3.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" +micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + "mime-db@>= 1.33.0 < 2", mime-db@~1.33.0: version "1.33.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" @@ -5699,6 +5777,10 @@ negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" +nice-try@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" + node-fetch@^1.3.3: version "1.7.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" @@ -6061,7 +6143,7 @@ path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" -path-key@^2.0.0: +path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" @@ -6626,7 +6708,7 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: +rimraf@2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: @@ -6761,7 +6843,7 @@ sax@>=0.6.0: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -"semver@2 || 3 || 4 || 5", semver@^5.4.1: +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" @@ -6944,6 +7026,10 @@ socket.io-adapter@0.5.0: debug "2.3.3" socket.io-parser "2.3.1" +socket.io-adapter@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" + socket.io-client@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" @@ -6960,6 +7046,25 @@ socket.io-client@1.6.0: socket.io-parser "2.3.1" to-array "0.1.4" +socket.io-client@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" + dependencies: + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~3.1.0" + engine.io-client "~3.2.0" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.2.0" + to-array "0.1.4" + socket.io-parser@2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" @@ -6969,6 +7074,14 @@ socket.io-parser@2.3.1: isarray "0.0.1" json3 "3.3.2" +socket.io-parser@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + socket.io@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" @@ -6981,6 +7094,17 @@ socket.io@1.6.0: socket.io-client "1.6.0" socket.io-parser "2.3.1" +socket.io@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" + dependencies: + debug "~3.1.0" + engine.io "~3.2.0" + has-binary2 "~1.0.2" + socket.io-adapter "~1.1.0" + socket.io-client "2.1.1" + socket.io-parser "~3.2.0" + sort-keys@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" @@ -7280,7 +7404,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: +symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" @@ -7372,16 +7496,16 @@ testem@^1.15.0: tap-parser "^5.1.0" xmldom "^0.1.19" -testem@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/testem/-/testem-2.0.0.tgz#b05c96200c7ac98bae998d71c94c0c5345907d13" +testem@^2.2.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/testem/-/testem-2.6.0.tgz#96c022c61bfd4d3b37738dc7483c1e678427d85b" dependencies: backbone "^1.1.2" bluebird "^3.4.6" charm "^1.0.0" commander "^2.6.0" consolidate "^0.14.0" - execa "^0.9.0" + execa "^0.10.0" express "^4.10.7" fireworm "^0.7.0" glob "^7.0.4" @@ -7398,7 +7522,7 @@ testem@^2.0.0: npmlog "^4.0.0" printf "^0.2.3" rimraf "^2.4.4" - socket.io "1.6.0" + socket.io "^2.1.0" spawn-args "^0.2.0" styled_string "0.0.1" tap-parser "^5.1.0" @@ -7495,7 +7619,7 @@ to-regex-range@^2.1.0: is-number "^3.0.0" repeat-string "^1.6.1" -to-regex@^3.0.1: +to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" dependencies: @@ -7611,6 +7735,10 @@ ultron@1.0.x: version "1.0.2" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + underscore.string@^3.2.2, underscore.string@~3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" @@ -7778,6 +7906,16 @@ walker@~1.0.5: dependencies: makeerror "1.0.x" +watch-detector@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/watch-detector/-/watch-detector-0.1.0.tgz#e37b410d149e2a8bf263a4f8b71e2f667633dbf8" + dependencies: + heimdalljs-logger "^0.1.9" + quick-temp "^0.1.8" + rsvp "^4.7.0" + semver "^5.4.1" + silent-error "^1.1.0" + watch@~0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" @@ -7877,6 +8015,14 @@ ws@1.1.1: options ">=0.0.5" ultron "1.0.x" +ws@~3.3.1: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + wtf-8@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" @@ -7912,6 +8058,10 @@ xmlhttprequest-ssl@1.5.3: version "1.5.3" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" +xmlhttprequest-ssl@~1.5.4: + version "1.5.5" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + xtend@^4.0.0, xtend@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" @@ -7924,12 +8074,12 @@ yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" -yam@0.0.22: - version "0.0.22" - resolved "https://registry.yarnpkg.com/yam/-/yam-0.0.22.tgz#38a76cb79a19284d9206ed49031e359a1340bd06" +yam@^0.0.24: + version "0.0.24" + resolved "https://registry.yarnpkg.com/yam/-/yam-0.0.24.tgz#11e9630444735f66a561d29221407de6d037cd95" dependencies: - fs-extra "^0.30.0" - lodash.merge "^4.4.0" + fs-extra "^4.0.2" + lodash.merge "^4.6.0" yargs@~3.10.0: version "3.10.0" From afdef84027ffeffd465a79fa1447c597eff8df09 Mon Sep 17 00:00:00 2001 From: Dinesh Nalagatla Date: Thu, 14 Jun 2018 09:40:27 -0700 Subject: [PATCH 2243/2527] Added check for implicitRelationships and relationships present in modelData --- .../relationships/state/relationship.js | 59 ++++-- .../relationships/belongs-to-test.js | 175 +++++++++++++++++- 2 files changed, 219 insertions(+), 15 deletions(-) diff --git a/addon/-record-data-private/system/relationships/state/relationship.js b/addon/-record-data-private/system/relationships/state/relationship.js index 179a0552b79..ee42f528748 100644 --- a/addon/-record-data-private/system/relationships/state/relationship.js +++ b/addon/-record-data-private/system/relationships/state/relationship.js @@ -179,6 +179,16 @@ export default class Relationship { return this.inverseKey && !this.inverseIsAsync; } + _hasSupportForImplicitRelationships(modelData) { + return ( + modelData._implicitRelationships !== undefined && modelData._implicitRelationships !== null + ); + } + + _hasSupportForRelationships(modelData) { + return modelData._relationships !== undefined && modelData._relationships !== null; + } + get _inverseMeta() { if (this.__inverseMeta === undefined) { let inverseMeta = null; @@ -205,6 +215,9 @@ export default class Relationship { // we actually want a union of members and canonicalMembers // they should be disjoint but currently are not due to a bug this.forAllMembers(inverseModelData => { + if (!this._hasSupportForRelationships(inverseModelData)) { + return; + } let relationship = inverseModelData._relationships.get(this.inverseKey); relationship.inverseDidDematerialize(this.modelData); }); @@ -313,6 +326,9 @@ export default class Relationship { setupInverseRelationship(modelData) { if (this.inverseKey) { + if (!this._hasSupportForRelationships(modelData)) { + return; + } let relationships = modelData._relationships; let relationship = relationships.get(this.inverseKey); // if we have only just initialized the inverse relationship, then it @@ -322,6 +338,9 @@ export default class Relationship { // relationships cannot efficiently find their inverse payloads. relationship.addCanonicalModelData(this.modelData); } else { + if (!this._hasSupportForImplicitRelationships(modelData)) { + return; + } let relationships = modelData._implicitRelationships; let relationship = relationships[this.inverseKeyForImplicit]; if (!relationship) { @@ -354,7 +373,10 @@ export default class Relationship { if (this.inverseKey) { this.removeCanonicalModelDataFromInverse(modelData); } else { - if (modelData._implicitRelationships[this.inverseKeyForImplicit]) { + if ( + this._hasSupportForImplicitRelationships(modelData) && + modelData._implicitRelationships[this.inverseKeyForImplicit] + ) { modelData._implicitRelationships[this.inverseKeyForImplicit].removeCanonicalModelData( this.modelData ); @@ -369,19 +391,21 @@ export default class Relationship { if (!this.members.has(modelData)) { this.members.addWithIndex(modelData, idx); this.notifyRecordRelationshipAdded(modelData, idx); - if (this.inverseKey) { + if (this._hasSupportForRelationships(modelData) && this.inverseKey) { modelData._relationships.get(this.inverseKey).addModelData(this.modelData); } else { - if (!modelData._implicitRelationships[this.inverseKeyForImplicit]) { - modelData._implicitRelationships[this.inverseKeyForImplicit] = new Relationship( - this.store, - this.key, - { options: { async: this.isAsync } }, - modelData, - this.isAsync - ); + if (this._hasSupportForImplicitRelationships(modelData)) { + if (!modelData._implicitRelationships[this.inverseKeyForImplicit]) { + modelData._implicitRelationships[this.inverseKeyForImplicit] = new Relationship( + this.store, + this.key, + { options: { async: this.isAsync } }, + modelData, + this.isAsync + ); + } + modelData._implicitRelationships[this.inverseKeyForImplicit].addModelData(this.modelData); } - modelData._implicitRelationships[this.inverseKeyForImplicit].addModelData(this.modelData); } } this.setHasAnyRelationshipData(true); @@ -394,7 +418,10 @@ export default class Relationship { if (this.inverseKey) { this.removeModelDataFromInverse(modelData); } else { - if (modelData._implicitRelationships[this.inverseKeyForImplicit]) { + if ( + this._hasSupportForImplicitRelationships(modelData) && + modelData._implicitRelationships[this.inverseKeyForImplicit] + ) { modelData._implicitRelationships[this.inverseKeyForImplicit].removeModelData( this.modelData ); @@ -405,6 +432,9 @@ export default class Relationship { removeModelDataFromInverse(modelData) { heimdall.increment(removeModelDataFromInverse); + if (!this._hasSupportForRelationships(modelData)) { + return; + } let inverseRelationship = modelData._relationships.get(this.inverseKey); //Need to check for existence, as the record might unloading at the moment if (inverseRelationship) { @@ -419,6 +449,9 @@ export default class Relationship { removeCanonicalModelDataFromInverse(modelData) { heimdall.increment(removeCanonicalModelDataFromInverse); + if (!this._hasSupportForRelationships(modelData)) { + return; + } let inverseRelationship = modelData._relationships.get(this.inverseKey); //Need to check for existence, as the record might unloading at the moment if (inverseRelationship) { @@ -453,7 +486,7 @@ export default class Relationship { const unload = inverseModelData => { const id = guidFor(inverseModelData); - if (seen[id] === undefined) { + if (this._hasSupportForRelationships(inverseModelData) && seen[id] === undefined) { const relationship = inverseModelData._relationships.get(this.inverseKey); relationship.removeCompletelyFromOwn(modelData); seen[id] = true; diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 605e2a8353d..ee5efd99c01 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -3,7 +3,7 @@ import { run } from '@ember/runloop'; import RSVP, { resolve } from 'rsvp'; import setupStore from 'dummy/tests/helpers/store'; -import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import testInDebug, { testRecordData } from 'dummy/tests/helpers/test-in-debug'; import { setup as setupModelFactoryInjections, reset as resetModelFactoryInjection, @@ -11,11 +11,12 @@ import { import { module, test } from 'qunit'; import DS from 'ember-data'; +import { ModelData } from 'ember-data/-private'; const { attr, hasMany, belongsTo } = DS; const { hash } = RSVP; -let env, store, User, Message, Post, Comment, Book, Chapter, Author, NewMessage; +let env, store, User, Message, Post, Comment, Book, Book1, Chapter, Author, NewMessage, Section; module('integration/relationship/belongs_to Belongs-To Relationships', { beforeEach() { @@ -46,6 +47,10 @@ module('integration/relationship/belongs_to Belongs-To Relationships', { chapters: hasMany('chapters', { async: false, inverse: 'book' }), }); + Book1 = DS.Model.extend({ + name: attr('string'), + }); + Chapter = DS.Model.extend({ title: attr('string'), book: belongsTo('book', { async: false, inverse: 'chapters' }), @@ -56,14 +61,20 @@ module('integration/relationship/belongs_to Belongs-To Relationships', { books: hasMany('books', { async: false }), }); + Section = DS.Model.extend({ + name: attr('string'), + }); + env = setupStore({ user: User, post: Post, comment: Comment, message: Message, book: Book, + book1: Book1, chapter: Chapter, author: Author, + section: Section, }); env.registry.optionsForType('serializer', { singleton: false }); @@ -1725,3 +1736,163 @@ test("belongsTo relationship with links doesn't trigger extra change notificatio assert.equal(count, 0); }); + +testRecordData( + "belongsTo relationship doesn't trigger when model data doesn't support implicit relationship", + function(assert) { + class TestModelData extends ModelData { + constructor(modelName, id, clientId, storeWrapper, store) { + super(modelName, id, clientId, storeWrapper, store); + delete this.__implicitRelationships; + delete this.__relationships; + } + + _destroyRelationships() {} + + _allRelatedModelDatas() {} + + _cleanupOrphanedModelDatas() {} + + _directlyRelatedModelDatas() { + return []; + } + + destroy() { + this.isDestroyed = true; + this.storeWrapper.disconnectRecord(this.modelName, this.id, this.clientId); + } + + get _implicitRelationships() { + return undefined; + } + get _relationships() { + return undefined; + } + } + + Chapter.reopen({ + book1: DS.belongsTo({ async: false }), + sections: DS.hasMany('section', { async: false }), + book: DS.belongsTo({ async: false, inverse: 'book' }), + }); + + const createModelDataFor = env.store.createModelDataFor; + env.store.createModelDataFor = function(modelName, id, clientId, storeWrapper) { + if (modelName === 'book1' || modelName === 'book' || modelName === 'section') { + return new TestModelData(modelName, id, clientId, storeWrapper, this); + } + return createModelDataFor.call(this, modelName, id, clientId, storeWrapper); + }; + + const data = { + data: { + type: 'chapter', + id: '1', + relationships: { + book1: { + data: { type: 'book1', id: '1' }, + }, + book: { + data: { type: 'book', id: '1' }, + }, + sections: { + data: [ + { + type: 'section', + id: 1, + }, + { + type: 'section', + id: 2, + }, + ], + }, + }, + }, + included: [ + { type: 'book1', id: '1' }, + { type: 'section', id: '1' }, + { type: 'book', id: '1' }, + { type: 'section', id: '2' }, + ], + }; + + // Expect assertion failure as Book Model Data + // doesn't have relationship attribute + // and inverse is not set to null in + // belongsTo + assert.expectAssertion(() => { + run(() => { + env.store.push(data); + }); + }, `Assertion Failed: We found no inverse relationships by the name of 'book' on the 'book' model. This is most likely due to a missing attribute on your model definition.`); + + //Update setup + // with inverse set to null + // no errors thrown + Chapter.reopen({ + book1: DS.belongsTo({ async: false }), + sections: DS.hasMany('section', { async: false }), + book: DS.belongsTo({ async: false, inverse: null }), + }); + + run(() => { + env.store.push(data); + }); + + let chapter = env.store.peekRecord('chapter', '1'); + let book1 = env.store.peekRecord('book1', '1'); + let book = env.store.peekRecord('book', '1'); + let section1 = env.store.peekRecord('section', '1'); + let section2 = env.store.peekRecord('section', '2'); + + let sections = chapter.get('sections'); + + assert.equal(chapter.get('book1.id'), '1'); + assert.equal(chapter.get('book.id'), '1'); + + // No inverse setup created for book1 + // as Model-Data of book1 doesn't support this + // functionality. + assert.notOk(book1.get('chapter')); + assert.notOk(book.get('chapter')); + assert.notOk( + book1._internalModel._modelData._implicitRelationships, + 'no support for implicit relationship in Model Data' + ); + assert.notOk( + book._internalModel._modelData._implicitRelationships, + 'no support for implicit relationship in Model Data' + ); + + // No inverse setup is created for section + assert.notOk(section1.get('chapter')); + assert.notOk(section2.get('chapter')); + + // Removing the sections + // shouldnot throw error + // as Model-data of section + // doesn't support implicit Relationship + run(() => { + chapter.get('sections').removeObject(section1); + assert.notOk(section1._internalModel._modelData._implicitRelationships); + + chapter.get('sections').removeObject(section2); + assert.notOk(section2._internalModel._modelData._implicitRelationships); + }); + + assert.equal(chapter.get('sections.length'), 0); + + // Update the current state of chapter by + // adding new sections + // shouldnot throw error during + // setup of implicit inverse + run(() => { + sections.addObject(env.store.createRecord('section', { id: 3 })); + sections.addObject(env.store.createRecord('section', { id: 4 })); + sections.addObject(env.store.createRecord('section', { id: 5 })); + }); + assert.equal(chapter.get('sections.length'), 3); + assert.notOk(sections.get('firstObject')._internalModel._modelData._implicitRelationships); + } +); From 9834c7a5b1012a8623be90348576b05e3f812084 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 19 Jun 2018 15:49:36 -0700 Subject: [PATCH 2244/2527] test cleanup --- .../relationships/belongs-to-test.js | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index ee5efd99c01..6abcf75f6ea 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1771,14 +1771,15 @@ testRecordData( } Chapter.reopen({ - book1: DS.belongsTo({ async: false }), + // book is still an inverse from prior to the reopen sections: DS.hasMany('section', { async: false }), - book: DS.belongsTo({ async: false, inverse: 'book' }), + book1: DS.belongsTo('book1', { async: false, inverse: 'chapters' }), // incorrect inverse + book2: DS.belongsTo('book1', { async: false, inverse: null }), // correct inverse }); const createModelDataFor = env.store.createModelDataFor; env.store.createModelDataFor = function(modelName, id, clientId, storeWrapper) { - if (modelName === 'book1' || modelName === 'book' || modelName === 'section') { + if (modelName === 'book1' || modelName === 'section') { return new TestModelData(modelName, id, clientId, storeWrapper, this); } return createModelDataFor.call(this, modelName, id, clientId, storeWrapper); @@ -1792,6 +1793,9 @@ testRecordData( book1: { data: { type: 'book1', id: '1' }, }, + book2: { + data: { type: 'book1', id: '2' }, + }, book: { data: { type: 'book', id: '1' }, }, @@ -1811,13 +1815,14 @@ testRecordData( }, included: [ { type: 'book1', id: '1' }, + { type: 'book1', id: '2' }, { type: 'section', id: '1' }, { type: 'book', id: '1' }, { type: 'section', id: '2' }, ], }; - // Expect assertion failure as Book Model Data + // Expect assertion failure as Book1 ModelData // doesn't have relationship attribute // and inverse is not set to null in // belongsTo @@ -1825,7 +1830,7 @@ testRecordData( run(() => { env.store.push(data); }); - }, `Assertion Failed: We found no inverse relationships by the name of 'book' on the 'book' model. This is most likely due to a missing attribute on your model definition.`); + }, `Assertion Failed: We found no inverse relationships by the name of 'chapters' on the 'book1' model. This is most likely due to a missing attribute on your model definition.`); //Update setup // with inverse set to null @@ -1842,6 +1847,7 @@ testRecordData( let chapter = env.store.peekRecord('chapter', '1'); let book1 = env.store.peekRecord('book1', '1'); + let book2 = env.store.peekRecord('book1', '2'); let book = env.store.peekRecord('book', '1'); let section1 = env.store.peekRecord('section', '1'); let section2 = env.store.peekRecord('section', '2'); @@ -1849,20 +1855,22 @@ testRecordData( let sections = chapter.get('sections'); assert.equal(chapter.get('book1.id'), '1'); + assert.equal(chapter.get('book2.id'), '2'); assert.equal(chapter.get('book.id'), '1'); // No inverse setup created for book1 // as Model-Data of book1 doesn't support this // functionality. assert.notOk(book1.get('chapter')); + assert.notOk(book2.get('chapter')); assert.notOk(book.get('chapter')); assert.notOk( book1._internalModel._modelData._implicitRelationships, - 'no support for implicit relationship in Model Data' + 'no support for implicit relationship in custom RecordData' ); - assert.notOk( + assert.ok( book._internalModel._modelData._implicitRelationships, - 'no support for implicit relationship in Model Data' + 'support for implicit relationship in default RecordData' ); // No inverse setup is created for section From fd7279f7c92d65a9a901cafa8d9146e908d18f72 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 19 Jun 2018 15:53:51 -0700 Subject: [PATCH 2245/2527] add assertion --- tests/integration/relationships/belongs-to-test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 6abcf75f6ea..6049031bd9f 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1868,6 +1868,10 @@ testRecordData( book1._internalModel._modelData._implicitRelationships, 'no support for implicit relationship in custom RecordData' ); + assert.notOk( + book2._internalModel._modelData._implicitRelationships, + 'no support for implicit relationship in custom RecordData' + ); assert.ok( book._internalModel._modelData._implicitRelationships, 'support for implicit relationship in default RecordData' From d725553f4f70d00b8bb96ca3112811664b338709 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 8 Jun 2018 10:21:09 -0700 Subject: [PATCH 2246/2527] adds tests and fix for infinite re-render skip record-data failures for now --- .eslintrc.js | 1 + .gitignore | 1 + addon/-legacy-private/system/many-array.js | 2 +- .../system/model/internal-model.js | 9 +- addon/-legacy-private/system/model/states.js | 4 +- .../system/references/belongs-to.js | 12 +- .../system/references/has-many.js | 3 +- .../system/relationships/belongs-to.js | 4 +- .../system/relationships/has-many.js | 4 +- .../system/relationships/state/belongs-to.js | 173 +++-- .../system/relationships/state/has-many.js | 194 ++--- .../relationships/state/relationship.js | 152 +++- addon/-legacy-private/system/store.js | 12 +- addon/-private/system/record-array-manager.js | 4 +- addon/-private/system/store/common.js | 8 +- addon/-private/system/store/finders.js | 4 +- .../system/model/internal-model.js | 2 +- .../system/model/states.js | 4 +- .../system/relationships/state/has-many.js | 4 +- .../relationships/state/relationship.js | 6 +- addon/-record-data-private/system/store.js | 19 +- node-tests/blueprints/adapter-test.js | 2 +- package.json | 6 +- testem.js | 5 +- .../acceptance/relationships/has-many-test.js | 664 ++++++++++++++++++ tests/helpers/model-factory-injection.js | 2 +- .../adapter/json-api-adapter-test.js | 30 +- .../relationships/has-many-test.js | 226 +++--- .../relationships/json-api-links-test.js | 10 +- .../relationships/one-to-one-test.js | 12 +- yarn.lock | 444 ++++++++++-- 31 files changed, 1594 insertions(+), 429 deletions(-) create mode 100644 tests/acceptance/relationships/has-many-test.js diff --git a/.eslintrc.js b/.eslintrc.js index eec3bbc74e7..f3b603c017e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,6 +4,7 @@ module.exports = { ecmaVersion: 2017, sourceType: 'module', }, + parser: 'babel-eslint', extends: ['eslint:recommended', 'prettier'], plugins: ['prettier'], rules: { diff --git a/.gitignore b/.gitignore index 8d89d47e86c..2d7eb569745 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ tmp/ tests/source/ dist/ *.iml +yarn-error.log benchmarks/results/*.json diff --git a/addon/-legacy-private/system/many-array.js b/addon/-legacy-private/system/many-array.js index 43e65056b28..fe9a9c2a5ae 100644 --- a/addon/-legacy-private/system/many-array.js +++ b/addon/-legacy-private/system/many-array.js @@ -63,7 +63,7 @@ export default EmberObject.extend(MutableArray, Evented, { @property {Boolean} isLoaded */ - this.isLoaded = false; + this.isLoaded = this.isLoaded || false; this.length = 0; /** diff --git a/addon/-legacy-private/system/model/internal-model.js b/addon/-legacy-private/system/model/internal-model.js index e94bb3623d3..0f4f7968950 100644 --- a/addon/-legacy-private/system/model/internal-model.js +++ b/addon/-legacy-private/system/model/internal-model.js @@ -130,7 +130,7 @@ export default class InternalModel { this.store = store; this.modelName = modelName; - this._loadingPromise = null; + this._promiseProxy = null; this._record = null; this._isDestroyed = false; this.isError = false; @@ -544,13 +544,6 @@ export default class InternalModel { this.dematerializeRecord(); if (this._scheduledDestroy === null) { - // TODO: use run.schedule once we drop 1.13 - if (!run.currentRunLoop) { - assert( - "You have turned on testing mode, which disabled the run-loop's autorun.\n You will need to wrap any code with asynchronous side-effects in a run", - Ember.testing - ); - } this._scheduledDestroy = run.backburner.schedule( 'destroy', this, diff --git a/addon/-legacy-private/system/model/states.js b/addon/-legacy-private/system/model/states.js index ad7562b5659..7697a1f1fd9 100644 --- a/addon/-legacy-private/system/model/states.js +++ b/addon/-legacy-private/system/model/states.js @@ -496,7 +496,7 @@ const RootState = { // EVENTS loadingData(internalModel, promise) { - internalModel._loadingPromise = promise; + internalModel._promiseProxy = promise; internalModel.transitionTo('loading'); }, @@ -523,7 +523,7 @@ const RootState = { isLoading: true, exit(internalModel) { - internalModel._loadingPromise = null; + internalModel._promiseProxy = null; }, // EVENTS diff --git a/addon/-legacy-private/system/references/belongs-to.js b/addon/-legacy-private/system/references/belongs-to.js index 24c9ad6cddf..07368d8ef64 100644 --- a/addon/-legacy-private/system/references/belongs-to.js +++ b/addon/-legacy-private/system/references/belongs-to.js @@ -350,15 +350,17 @@ export default class BelongsToReference extends Reference { @return {Promise} a promise that resolves with the record in this belongs-to relationship. */ load() { - if (this.remoteType() === 'id') { - return this.belongsToRelationship.getRecord(); - } + let rel = this.belongsToRelationship; + + rel.getData(); - if (this.remoteType() === 'link') { - return this.belongsToRelationship.findLink().then(internalModel => { + if (rel.fetchPromise !== null) { + return rel.fetchPromise.then(() => { return this.value(); }); } + + return resolve(this.value()); } /** diff --git a/addon/-legacy-private/system/references/has-many.js b/addon/-legacy-private/system/references/has-many.js index 60b7acb75fd..264103708e6 100644 --- a/addon/-legacy-private/system/references/has-many.js +++ b/addon/-legacy-private/system/references/has-many.js @@ -359,8 +359,9 @@ export default class HasManyReference extends Reference { this has-many relationship. */ load() { + // TODO this can be simplified if (!this._isLoaded()) { - return this.hasManyRelationship.getRecords(); + return this.hasManyRelationship.getData(); } return resolve(this.hasManyRelationship.manyArray); diff --git a/addon/-legacy-private/system/relationships/belongs-to.js b/addon/-legacy-private/system/relationships/belongs-to.js index 3fe47ee9cc7..155551c025b 100644 --- a/addon/-legacy-private/system/relationships/belongs-to.js +++ b/addon/-legacy-private/system/relationships/belongs-to.js @@ -132,12 +132,12 @@ export default function belongsTo(modelName, options) { ); } - return this._internalModel._relationships.get(key).getRecord(); + return this._internalModel._relationships.get(key).getData(); }, set(key, value) { this._internalModel.setDirtyBelongsTo(key, value); - return this._internalModel._relationships.get(key).getRecord(); + return this._internalModel._relationships.get(key).getData(); }, }).meta(meta); } diff --git a/addon/-legacy-private/system/relationships/has-many.js b/addon/-legacy-private/system/relationships/has-many.js index 56546c69e89..e64d566ff08 100644 --- a/addon/-legacy-private/system/relationships/has-many.js +++ b/addon/-legacy-private/system/relationships/has-many.js @@ -145,12 +145,12 @@ export default function hasMany(type, options) { return computed({ get(key) { - return this._internalModel._relationships.get(key).getRecords(); + return this._internalModel._relationships.get(key).getData(); }, set(key, records) { this._internalModel.setDirtyHasMany(key, records); - return this._internalModel._relationships.get(key).getRecords(); + return this._internalModel._relationships.get(key).getData(); }, }).meta(meta); } diff --git a/addon/-legacy-private/system/relationships/state/belongs-to.js b/addon/-legacy-private/system/relationships/state/belongs-to.js index ba907947725..6e50e40d4e3 100644 --- a/addon/-legacy-private/system/relationships/state/belongs-to.js +++ b/addon/-legacy-private/system/relationships/state/belongs-to.js @@ -1,7 +1,7 @@ -import { Promise as EmberPromise } from 'rsvp'; +import { resolve } from 'rsvp'; import { assert } from '@ember/debug'; import { assertPolymorphicType } from 'ember-data/-debug'; -import { PromiseBelongsTo } from '../../promise-proxies'; +import { PromiseBelongsTo, PromiseObject } from '../../promise-proxies'; import Relationship from './relationship'; export default class BelongsToRelationship extends Relationship { @@ -9,7 +9,23 @@ export default class BelongsToRelationship extends Relationship { super(store, internalModel, inverseKey, relationshipMeta); this.inverseInternalModel = null; this.canonicalState = null; - this._loadingPromise = null; + this._promiseProxy = null; + } + + /** + * Flag indicating whether all inverse records are available + * + * true if the inverse exists and is loaded (not empty) + * true if there is no inverse + * false if the inverse exists and is not loaded (empty) + * + * @returns {boolean} + */ + get allInverseRecordsAreLoaded() { + let internalModel = this.inverseInternalModel; + let isEmpty = internalModel !== null && internalModel.isEmpty(); + + return !isEmpty; } setInternalModel(internalModel) { @@ -21,7 +37,6 @@ export default class BelongsToRelationship extends Relationship { this.setHasAnyRelationshipData(true); this.setRelationshipIsStale(false); this.setRelationshipIsEmpty(false); - this.setHasRelatedResources(!this.localStateIsEmpty()); } setCanonicalInternalModel(internalModel) { @@ -92,6 +107,7 @@ export default class BelongsToRelationship extends Relationship { } if (this.inverseInternalModel !== this.canonicalState) { this.inverseInternalModel = this.canonicalState; + this._promiseProxy = null; this.notifyBelongsToChanged(); } @@ -114,13 +130,17 @@ export default class BelongsToRelationship extends Relationship { this.notifyBelongsToChanged(); } - setRecordPromise(newPromise) { - let content = newPromise.get && newPromise.get('content'); + setRecordPromise(belongsToPromise) { assert( 'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.', - content !== undefined + belongsToPromise instanceof PromiseObject ); + + let content = belongsToPromise.get('content'); + let promise = belongsToPromise.get('promise'); + this.setInternalModel(content ? content._internalModel : content); + this._updateLoadingPromise(promise, content); } removeInternalModelFromOwn(internalModel) { @@ -128,6 +148,7 @@ export default class BelongsToRelationship extends Relationship { return; } this.inverseInternalModel = null; + this._promiseProxy = null; super.removeInternalModelFromOwn(internalModel); this.notifyBelongsToChanged(); } @@ -135,6 +156,7 @@ export default class BelongsToRelationship extends Relationship { removeAllInternalModelsFromOwn() { super.removeAllInternalModelsFromOwn(); this.inverseInternalModel = null; + this._promiseProxy = null; this.notifyBelongsToChanged(); } @@ -155,15 +177,32 @@ export default class BelongsToRelationship extends Relationship { this.canonicalState = null; } - findRecord() { - if (this.inverseInternalModel) { - return this.store._findByInternalModel(this.inverseInternalModel); - } else { - return EmberPromise.resolve(null); + // called by `getData()` when a request is needed + // but no link is available + _fetchRecord() { + let { inverseInternalModel, shouldForceReload } = this; + + if (inverseInternalModel) { + let promise; + + if (shouldForceReload && !inverseInternalModel.isEmpty() && inverseInternalModel.hasRecord) { + // reload record, if it is already loaded + // if we have a link, we would already be in `findLink()` + promise = inverseInternalModel.getRecord().reload(); + } else { + promise = this.store._findByInternalModel(inverseInternalModel); + } + + return promise; } + + // TODO is this actually an error case? + return resolve(null); } - fetchLink() { + // called by `getData()` when a request is needed + // and a link is available + _fetchLink() { return this.store .findBelongsTo(this.internalModel, this.link, this.relationshipMeta) .then(internalModel => { @@ -174,25 +213,39 @@ export default class BelongsToRelationship extends Relationship { }); } - getRecord() { + getData() { //TODO(Igor) flushCanonical here once our syncing is not stupid - if (this.isAsync) { + let record = this.inverseInternalModel ? this.inverseInternalModel.getRecord() : null; + + if (this.shouldMakeRequest()) { let promise; - if (this._shouldFindViaLink()) { - promise = this.findLink().then(() => this.findRecord()); + if (this.link) { + promise = this._fetchLink(); } else { - promise = this.findRecord(); + promise = this._fetchRecord(); } - let record = this.inverseInternalModel ? this.inverseInternalModel.getRecord() : null; + promise = promise.then(() => handleCompletedFind(this), e => handleCompletedFind(this, e)); - return this._updateLoadingPromise(promise, record); - } else { - if (this.inverseInternalModel === null) { - return null; + promise = promise.then(internalModel => { + return internalModel ? internalModel.getRecord() : null; + }); + + this.fetchPromise = promise; + this._updateLoadingPromise(promise); + } + + if (this.isAsync) { + if (this._promiseProxy === null) { + let promise = resolve(this.inverseInternalModel).then(internalModel => { + return internalModel ? internalModel.getRecord() : null; + }); + this._updateLoadingPromise(promise, record); } - let toReturn = this.inverseInternalModel.getRecord(); + + return this._promiseProxy; + } else { assert( "You looked up the '" + this.key + @@ -201,56 +254,18 @@ export default class BelongsToRelationship extends Relationship { "' with id " + this.internalModel.id + ' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)', - toReturn === null || !toReturn.get('isEmpty') + record === null || !record.get('isEmpty') ); - return toReturn; + return record; } } - _updateLoadingPromise(promise, content) { - if (this._loadingPromise) { - if (content !== undefined) { - this._loadingPromise.set('content', content); - } - this._loadingPromise.set('promise', promise); - } else { - this._loadingPromise = PromiseBelongsTo.create({ - _belongsToState: this, - promise, - content, - }); - } - - return this._loadingPromise; - } - - reload() { - // we've already fired off a request - if (this._loadingPromise) { - if (this._loadingPromise.get('isPending')) { - return this._loadingPromise; - } - } - - let promise; - this.setRelationshipIsStale(true); - - if (this.link) { - promise = this.fetchLink(); - } else if (this.inverseInternalModel && this.inverseInternalModel.hasRecord) { - // reload record, if it is already loaded - promise = this.inverseInternalModel.getRecord().reload(); - } else { - promise = this.findRecord(); - } - - return this._updateLoadingPromise(promise); - } - - localStateIsEmpty() { - let internalModel = this.inverseInternalModel; - - return !internalModel || internalModel.isEmpty(); + _createProxy(promise, content) { + return PromiseBelongsTo.create({ + _belongsToState: this, + promise, + content, + }); } updateData(data, initial) { @@ -262,3 +277,21 @@ export default class BelongsToRelationship extends Relationship { } } } + +function handleCompletedFind(relationship, error) { + let internalModel = relationship.inverseInternalModel; + + relationship.fetchPromise = null; + relationship.setShouldForceReload(false); + + if (error) { + relationship.setHasFailedLoadAttempt(true); + throw error; + } + + relationship.setHasFailedLoadAttempt(false); + // only set to not stale if no error is thrown + relationship.setRelationshipIsStale(false); + + return internalModel; +} diff --git a/addon/-legacy-private/system/relationships/state/has-many.js b/addon/-legacy-private/system/relationships/state/has-many.js index ea6eaefb072..12d08be0afa 100755 --- a/addon/-legacy-private/system/relationships/state/has-many.js +++ b/addon/-legacy-private/system/relationships/state/has-many.js @@ -4,6 +4,7 @@ import { PromiseManyArray } from '../../promise-proxies'; import Relationship from './relationship'; import OrderedSet from '../../ordered-set'; import ManyArray from '../../many-array'; +import { resolve } from 'rsvp'; export default class ManyRelationship extends Relationship { constructor(store, internalModel, inverseKey, relationshipMeta) { @@ -16,25 +17,45 @@ export default class ManyRelationship extends Relationship { // we create a new many array, but in the interim it will be updated if // inverse internal models are unloaded. this._retainedManyArray = null; - this._loadingPromise = null; + this._promiseProxy = null; this._willUpdateManyArray = false; this._pendingManyArrayUpdates = null; } - _updateLoadingPromise(promise, content) { - if (this._loadingPromise) { - if (content) { - this._loadingPromise.set('content', content); - } - this._loadingPromise.set('promise', promise); - } else { - this._loadingPromise = PromiseManyArray.create({ - promise, - content, - }); - } + get currentState() { + return this.members.list; + } - return this._loadingPromise; + /** + * Flag indicating whether all inverse records are available + * + * true if inverse records exist and are all loaded (all not empty) + * true if there are no inverse records + * false if the inverse records exist and any are not loaded (any empty) + * + * @returns {boolean} + */ + get allInverseRecordsAreLoaded() { + // check currentState for unloaded records + let hasEmptyRecords = this.currentState.reduce((hasEmptyModel, i) => { + return hasEmptyModel || i.isEmpty(); + }, false); + + // check un-synced state for unloaded records + if (!hasEmptyRecords && this.willSync) { + hasEmptyRecords = this.canonicalState.reduce((hasEmptyModel, i) => { + return hasEmptyModel || !i.isEmpty(); + }, false); + } + + return !hasEmptyRecords; + } + + _createProxy(promise, content) { + return PromiseManyArray.create({ + promise, + content, + }); } get manyArray() { @@ -46,6 +67,8 @@ export default class ManyRelationship extends Relationship { ); if (!this._manyArray && !this.isDestroying) { + let isLoaded = this.hasFailedLoadAttempt || this.isNew || this.allInverseRecordsAreLoaded; + this._manyArray = ManyArray.create({ canonicalState: this.canonicalState, store: this.store, @@ -54,6 +77,7 @@ export default class ManyRelationship extends Relationship { record: this.internalModel, meta: this.meta, isPolymorphic: this.isPolymorphic, + isLoaded, }); if (this._retainedManyArray !== null) { @@ -72,8 +96,8 @@ export default class ManyRelationship extends Relationship { this._manyArray = null; } - if (this._loadingPromise) { - this._loadingPromise.destroy(); + if (this._promiseProxy) { + this._promiseProxy.destroy(); } } @@ -246,28 +270,6 @@ export default class ManyRelationship extends Relationship { this.internalModel.notifyHasManyAdded(this.key, internalModel, idx); } - reload() { - let manyArray = this.manyArray; - - if (this._loadingPromise) { - if (this._loadingPromise.get('isPending')) { - return this._loadingPromise; - } - } - - this.setRelationshipIsStale(true); - - let promise; - if (this.link) { - promise = this.fetchLink(); - } else { - promise = this.store._scheduleFetchMany(manyArray.currentState).then(() => manyArray); - } - - this._updateLoadingPromise(promise); - return this._loadingPromise; - } - computeChanges(internalModels = []) { let members = this.canonicalMembers; let internalModelsToRemove = []; @@ -309,7 +311,25 @@ export default class ManyRelationship extends Relationship { this.canonicalState = this.canonicalMembers.toArray(); } - fetchLink() { + // called by `getData()` when a request is needed + // but no link is available + _fetchRecords() { + let internalModels = this.currentState; + let { shouldForceReload } = this; + let promise; + + if (shouldForceReload === true) { + promise = this.store._scheduleFetchMany(internalModels); + } else { + promise = this.store.findMany(internalModels); + } + + return promise; + } + + // called by `getData()` when a request is needed + // and a link is available + _fetchLink() { return this.store .findHasMany(this.internalModel, this.link, this.relationshipMeta) .then(records => { @@ -318,60 +338,57 @@ export default class ManyRelationship extends Relationship { } this.store._backburner.join(() => { this.updateInternalModelsFromAdapter(records); - this.manyArray.set('isLoaded', true); }); - return this.manyArray; + return records; }); } - findRecords() { + getData() { + //TODO(Igor) sync server here, once our syncing is not stupid let manyArray = this.manyArray; - let internalModels = manyArray.currentState; - //TODO CLEANUP - return this.store.findMany(internalModels).then(() => { - if (!manyArray.get('isDestroyed')) { - //Goes away after the manyArray refactor - manyArray.set('isLoaded', true); + if (this.shouldMakeRequest()) { + let promise; + + if (this.link) { + promise = this._fetchLink(); + } else { + promise = this._fetchRecords(); } - return manyArray; - }); - } - notifyHasManyChanged() { - this.internalModel.notifyHasManyAdded(this.key); - } + promise = promise.then( + () => handleCompletedRequest(this), + e => handleCompletedRequest(this, e) + ); - getRecords() { - //TODO(Igor) sync server here, once our syncing is not stupid - let manyArray = this.manyArray; + this.fetchPromise = promise; + this._updateLoadingPromise(promise, manyArray); + } if (this.isAsync) { - let promise; - - if (this._shouldFindViaLink()) { - promise = this.findLink().then(() => this.findRecords()); - } else { - promise = this.findRecords(); + if (this._promiseProxy === null) { + this._updateLoadingPromise(resolve(manyArray), manyArray); } - return this._updateLoadingPromise(promise, manyArray); + return this._promiseProxy; } else { assert( `You looked up the '${this.key}' relationship on a '${ this.internalModel.type.modelName }' with id ${ this.internalModel.id - } but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async ('DS.hasMany({ async: true })')`, - manyArray.isEvery('isEmpty', false) + } but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (\`DS.hasMany({ async: true })\`)`, + this.allInverseRecordsAreLoaded ); - manyArray.set('isLoaded', true); - return manyArray; } } + notifyHasManyChanged() { + this.internalModel.notifyHasManyAdded(this.key); + } + updateData(data, initial) { let internalModels = this.store._pushResourceIdentifiers(this, data); if (initial) { @@ -381,20 +398,6 @@ export default class ManyRelationship extends Relationship { } } - localStateIsEmpty() { - let manyArray = this.manyArray; - let internalModels = manyArray.currentState; - let manyArrayIsLoaded = manyArray.get('isLoaded'); - - if (!manyArrayIsLoaded && internalModels.length) { - manyArrayIsLoaded = internalModels.reduce((hasNoEmptyModel, i) => { - return hasNoEmptyModel && !i.isEmpty(); - }, true); - } - - return !manyArrayIsLoaded; - } - destroy() { this.isDestroying = true; super.destroy(); @@ -404,16 +407,39 @@ export default class ManyRelationship extends Relationship { this._manyArray = null; } - let proxy = this._loadingPromise; + let proxy = this._promiseProxy; if (proxy) { proxy.destroy(); - this._loadingPromise = null; + this._promiseProxy = null; } this.isDestroyed = true; } } +function handleCompletedRequest(relationship, error) { + let manyArray = relationship.manyArray; + + //Goes away after the manyArray refactor + if (!manyArray.get('isDestroyed')) { + relationship.manyArray.set('isLoaded', true); + } + + relationship.fetchPromise = null; + relationship.setShouldForceReload(false); + + if (error) { + relationship.setHasFailedLoadAttempt(true); + throw error; + } + + relationship.setHasFailedLoadAttempt(false); + // only set to not stale if no error is thrown + relationship.setRelationshipIsStale(false); + + return manyArray; +} + function setForArray(array) { var set = new OrderedSet(); diff --git a/addon/-legacy-private/system/relationships/state/relationship.js b/addon/-legacy-private/system/relationships/state/relationship.js index 9ba5dc7b7a6..9f48256ee16 100644 --- a/addon/-legacy-private/system/relationships/state/relationship.js +++ b/addon/-legacy-private/system/relationships/state/relationship.js @@ -12,7 +12,6 @@ const { addInternalModel, addInternalModels, clear, - findLink, flushCanonical, flushCanonicalLater, newRelationship, @@ -35,7 +34,6 @@ const { 'addInternalModel', 'addInternalModels', 'clear', - 'findLink', 'flushCanonical', 'flushCanonicalLater', 'newRelationship', @@ -70,15 +68,34 @@ export default class Relationship { //This probably breaks for polymorphic relationship in complex scenarios, due to //multiple possible modelNames this.inverseKeyForImplicit = this.internalModel.modelName + this.key; - this.linkPromise = null; + this.fetchPromise = null; + this._promiseProxy = null; this.meta = null; this.__inverseMeta = undefined; + /* + This flag forces fetch. `true` for a single request once `reload()` + has been called `false` at all other times. + */ + this.shouldForceReload = false; + /* This flag indicates whether we should re-fetch the relationship the next time it is accessed. + The difference between this flag and `shouldForceReload` + is in how we treat the presence of partially missing data: + - for a forced reload, we will reload the link or EVERY record + - for a stale reload, we will reload the link (if present) else only MISSING records + + Ideally these flags could be merged, but because we don't give the + request layer the option of deciding how to resolve the data being queried + we are forced to differentiate for now. + + It is also possible for a relationship to remain stale after a forced reload; however, + in this case `hasFailedLoadAttempt` ought to be `true`. + false when => internalModel.isNew() on initial setup => a previously triggered request has resolved @@ -87,10 +104,9 @@ export default class Relationship { true when => !internalModel.isNew() on initial setup => an inverse has been unloaded - => relationship.reload() has been called => we get a new link for the relationship */ - this.relationshipIsStale = !internalModel.isNew(); + this.relationshipIsStale = !this.isNew; /* This flag indicates whether we should consider the content @@ -138,6 +154,12 @@ export default class Relationship { */ this.relationshipIsEmpty = true; + /* + Flag that indicates whether we have explicitly attempted a load for the relationship + (which may have failed) + */ + this.hasFailedLoadAttempt = false; + /* true when => hasAnyRelationshipData is true @@ -146,7 +168,10 @@ export default class Relationship { TODO, consider changing the conditional here from !isEmpty to !hiddenFromRecordArrays */ - this.hasRelatedResources = false; + } + + get isNew() { + return this.internalModel.isNew(); } _inverseIsSync() { @@ -191,7 +216,7 @@ export default class Relationship { } inverseDidDematerialize(inverseInternalModel) { - this.linkPromise = null; + this.fetchPromise = null; this.setRelationshipIsStale(true); if (!this.isAsync) { @@ -515,7 +540,7 @@ export default class Relationship { ); this.link = link; - this.linkPromise = null; + this.fetchPromise = null; this.setRelationshipIsStale(true); if (!initial) { @@ -523,23 +548,99 @@ export default class Relationship { } } - _shouldFindViaLink() { - if (!this.link) { + reload() { + if (this._promiseProxy) { + if (this._promiseProxy.get('isPending')) { + return this._promiseProxy; + } + } + + this.setHasFailedLoadAttempt(false); + this.setShouldForceReload(true); + this.getData(); + + return this._promiseProxy; + } + + shouldMakeRequest() { + let { + relationshipIsStale, + hasFailedLoadAttempt, + allInverseRecordsAreLoaded, + hasAnyRelationshipData, + shouldForceReload, + relationshipIsEmpty, + isAsync, + isNew, + fetchPromise, + } = this; + + // never make a request if this record doesn't exist server side yet + if (isNew === true) { + return false; + } + + // do not re-request if we are already awaiting a request + if (fetchPromise !== null) { return false; } - return this.relationshipIsStale || !this.hasRelatedResources; + // Always make a request when forced + // failed attempts must call `reload()`. + // + // For legacy reasons, when a relationship is missing only + // some of it's data we rely on individual `findRecord` + // calls which may resolve from cache in the non-link case. + // This determination is made elsewhere. + // + if (shouldForceReload === true || relationshipIsStale === true) { + return !hasFailedLoadAttempt; + } + + // never make a request if we've explicitly attempted to at least once + // since the last update to canonical state + // this includes failed attempts + // e.g. to re-attempt `reload()` must be called force the attempt. + if (hasFailedLoadAttempt === true) { + return false; + } + + // we were explicitly told that there is no inverse relationship + if (relationshipIsEmpty === true) { + return false; + } + + // we were explicitly told what the inverse is, and we have the inverse records available + if (hasAnyRelationshipData === true && allInverseRecordsAreLoaded === true) { + return false; + } + + // if this is a sync relationship, we should not need to fetch, so getting here is an error + assert( + `You looked up the '${this.key}' relationship on a '${ + this.internalModel.type.modelName + }' with id ${ + this.internalModel.id + } but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (\`DS.${ + this.relationshipMeta.kind + }({ async: true })\`)`, + isAsync === true + ); + + return true; } - findLink() { - heimdall.increment(findLink); - if (this.linkPromise) { - return this.linkPromise; + _updateLoadingPromise(promise, content) { + if (this._promiseProxy) { + if (content !== undefined) { + this._promiseProxy.set('content', content); + } + this._promiseProxy.set('promise', promise); } else { - let promise = this.fetchLink(); - this.linkPromise = promise; - return promise.then(result => result); + this._promiseProxy = this._createProxy(promise, content); } + + return this._promiseProxy; } updateInternalModelsFromAdapter(internalModels) { @@ -556,8 +657,8 @@ export default class Relationship { this.hasAnyRelationshipData = value; } - setHasRelatedResources(v) { - this.hasRelatedResources = v; + setHasFailedLoadAttempt(value) { + this.hasFailedLoadAttempt = value; } setRelationshipIsStale(value) { @@ -568,6 +669,10 @@ export default class Relationship { this.relationshipIsEmpty = value; } + setShouldForceReload(value) { + this.shouldForceReload = value; + } + /* `push` for a relationship allows the store to push a JSON API Relationship Object onto the relationship. The relationship will then extract and set the @@ -610,12 +715,12 @@ export default class Relationship { relationshipIsEmpty -> true if is empty array (has-many) or is null (belongs-to) hasAnyRelationshipData -> true relationshipIsStale -> false - hasRelatedResources -> run-check-to-determine + allInverseRecordsAreLoaded -> run-check-to-determine IF contains only links relationshipIsStale -> true */ - + this.setHasFailedLoadAttempt(false); if (hasRelationshipDataProperty) { let relationshipIsEmpty = payload.data === null || (Array.isArray(payload.data) && payload.data.length === 0); @@ -623,12 +728,13 @@ export default class Relationship { this.setHasAnyRelationshipData(true); this.setRelationshipIsStale(false); this.setRelationshipIsEmpty(relationshipIsEmpty); - this.setHasRelatedResources(relationshipIsEmpty || !this.localStateIsEmpty()); } else if (hasLink) { this.setRelationshipIsStale(true); } } + _createProxy() {} + updateData() {} destroy() {} diff --git a/addon/-legacy-private/system/store.js b/addon/-legacy-private/system/store.js index 3ca251ae158..e9612191bdd 100644 --- a/addon/-legacy-private/system/store.js +++ b/addon/-legacy-private/system/store.js @@ -5,7 +5,7 @@ import { A } from '@ember/array'; import EmberError from '@ember/error'; import MapWithDefault from './map-with-default'; -import { run as emberRun } from '@ember/runloop'; +import { run as emberRunLoop } from '@ember/runloop'; import { set, get, computed } from '@ember/object'; import { assign } from '@ember/polyfills'; import { default as RSVP, Promise } from 'rsvp'; @@ -52,7 +52,7 @@ import InternalModel from './model/internal-model'; import edBackburner from './backburner'; const badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; - +const emberRun = emberRunLoop.backburner; const { ENV } = Ember; //Get the materialized model from the internalModel/promise that returns @@ -749,7 +749,7 @@ Store = Service.extend({ //TODO double check about reloading if (internalModel.isLoading()) { - return internalModel._loadingPromise; + return internalModel._promiseProxy; } return Promise.resolve(internalModel); @@ -819,8 +819,8 @@ Store = Service.extend({ }, _scheduleFetch(internalModel, options) { - if (internalModel._loadingPromise) { - return internalModel._loadingPromise; + if (internalModel._promiseProxy) { + return internalModel._promiseProxy; } let { id, modelName } = internalModel; @@ -1871,7 +1871,7 @@ Store = Service.extend({ snapshot: snapshot, resolver: resolver, }); - emberRun.once(this, this.flushPendingSave); + emberRun.scheduleOnce('actions', this, this.flushPendingSave); }, /** diff --git a/addon/-private/system/record-array-manager.js b/addon/-private/system/record-array-manager.js index e8e3ae6c5b8..c1a6687db44 100644 --- a/addon/-private/system/record-array-manager.js +++ b/addon/-private/system/record-array-manager.js @@ -4,11 +4,13 @@ import { A } from '@ember/array'; import { set, get } from '@ember/object'; -import { run as emberRun } from '@ember/runloop'; +import { run as emberRunloop } from '@ember/runloop'; import { assert } from '@ember/debug'; import cloneNull from './clone-null'; import { RecordArray, AdapterPopulatedRecordArray } from './record-arrays'; +const emberRun = emberRunloop.backburner; + const { _flush, array_remove, diff --git a/addon/-private/system/store/common.js b/addon/-private/system/store/common.js index c095fe701c8..f2448a444ff 100644 --- a/addon/-private/system/store/common.js +++ b/addon/-private/system/store/common.js @@ -1,7 +1,7 @@ import { get } from '@ember/object'; import { DEBUG } from '@glimmer/env'; import Ember from 'ember'; -import { Promise } from 'rsvp'; +import { resolve } from 'rsvp'; const { __bind, __guard, __objectIsAlive } = heimdall.registerMonitor( 'system.store.common', @@ -20,7 +20,7 @@ export function _bind(fn, ...args) { export function _guard(promise, test) { heimdall.increment(__guard); - let guarded = promise['finally'](function() { + let guarded = promise.finally(() => { if (!test()) { guarded._subscribers.length = 0; } @@ -46,9 +46,9 @@ if (DEBUG) { } export function guardDestroyedStore(promise, store, label) { - promise = Promise.resolve(promise, label); + let wrapperPromise = resolve(promise, label).then(v => promise); - return _guard(promise, () => { + return _guard(wrapperPromise, () => { if (DEBUG) { ASYNC_REQUEST_COUNT--; } diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 1709a79cb39..87da5c87dc3 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -28,7 +28,9 @@ export function _find(adapter, store, modelClass, id, internalModel, options) { } let snapshot = internalModel.createSnapshot(options); let { modelName } = internalModel; - let promise = Promise.resolve().then(() => adapter.findRecord(store, modelClass, id, snapshot)); + let promise = Promise.resolve().then(() => { + return adapter.findRecord(store, modelClass, id, snapshot); + }); let label = `DS: Handle Adapter#findRecord of '${modelName}' with id: '${id}'`; promise = guardDestroyedStore(promise, store, label); diff --git a/addon/-record-data-private/system/model/internal-model.js b/addon/-record-data-private/system/model/internal-model.js index 37c119c26e7..568d052e643 100644 --- a/addon/-record-data-private/system/model/internal-model.js +++ b/addon/-record-data-private/system/model/internal-model.js @@ -96,7 +96,7 @@ export default class InternalModel { // this ensure ordered set can quickly identify this as unique this[Ember.GUID_KEY] = InternalModelReferenceId++ + 'internal-model'; - this._loadingPromise = null; + this._promiseProxy = null; this._record = null; this._isDestroyed = false; this.isError = false; diff --git a/addon/-record-data-private/system/model/states.js b/addon/-record-data-private/system/model/states.js index 55438b134f6..98cf914167e 100644 --- a/addon/-record-data-private/system/model/states.js +++ b/addon/-record-data-private/system/model/states.js @@ -494,7 +494,7 @@ const RootState = { // EVENTS loadingData(internalModel, promise) { - internalModel._loadingPromise = promise; + internalModel._promiseProxy = promise; internalModel.transitionTo('loading'); }, @@ -521,7 +521,7 @@ const RootState = { isLoading: true, exit(internalModel) { - internalModel._loadingPromise = null; + internalModel._promiseProxy = null; }, // EVENTS diff --git a/addon/-record-data-private/system/relationships/state/has-many.js b/addon/-record-data-private/system/relationships/state/has-many.js index 2a0e2df719e..8af92a99f13 100755 --- a/addon/-record-data-private/system/relationships/state/has-many.js +++ b/addon/-record-data-private/system/relationships/state/has-many.js @@ -16,8 +16,8 @@ export default class ManyRelationship extends Relationship { super.removeInverseRelationships(); /* TODO Igor make sure this is still working - if (this._loadingPromise) { - this._loadingPromise.destroy(); + if (this._promiseProxy) { + this._promiseProxy.destroy(); } */ } diff --git a/addon/-record-data-private/system/relationships/state/relationship.js b/addon/-record-data-private/system/relationships/state/relationship.js index ee42f528748..00b421b8b9b 100644 --- a/addon/-record-data-private/system/relationships/state/relationship.js +++ b/addon/-record-data-private/system/relationships/state/relationship.js @@ -158,7 +158,7 @@ export default class Relationship { TODO, consider changing the conditional here from !isEmpty to !hiddenFromRecordArrays */ - // this.hasRelatedResources = false; + // this.allInverseRecordsAreLoaded = false; // TODO do we want this anymore? Seems somewhat useful // especially if we rename to `hasUpdatedLink` @@ -167,7 +167,7 @@ export default class Relationship { // this.updatedLink = false; } - get hasRelatedResources() { + get allInverseRecordsAreLoaded() { return !this.localStateIsEmpty(); } @@ -643,7 +643,7 @@ export default class Relationship { hasAnyRelationshipData -> true hasDematerializedInverse -> false relationshipIsStale -> false - hasRelatedResources -> run-check-to-determine + allInverseRecordsAreLoaded -> run-check-to-determine IF contains only links relationshipIsStale -> true diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index f0bc6a7ff38..105ded43e56 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -754,7 +754,7 @@ Store = Service.extend({ //TODO double check about reloading if (internalModel.isLoading()) { - return internalModel._loadingPromise; + return internalModel._promiseProxy; } return Promise.resolve(internalModel); @@ -824,8 +824,8 @@ Store = Service.extend({ }, _scheduleFetch(internalModel, options) { - if (internalModel._loadingPromise) { - return internalModel._loadingPromise; + if (internalModel._promiseProxy) { + return internalModel._promiseProxy; } let { id, modelName } = internalModel; @@ -1270,7 +1270,7 @@ Store = Service.extend({ let { relationshipIsStale, - hasRelatedResources, + allInverseRecordsAreLoaded, hasDematerializedInverse, hasAnyRelationshipData, relationshipIsEmpty, @@ -1281,7 +1281,7 @@ Store = Service.extend({ resource.links.related && (hasDematerializedInverse || relationshipIsStale || - (!hasRelatedResources && !relationshipIsEmpty)); + (!allInverseRecordsAreLoaded && !relationshipIsEmpty)); // fetch via link if (shouldFindViaLink) { @@ -1299,7 +1299,7 @@ Store = Service.extend({ let preferLocalCache = hasAnyRelationshipData && - // hasRelatedResources && + // allInverseRecordsAreLoaded && !relationshipIsEmpty; let hasLocalPartialData = hasDematerializedInverse || @@ -1384,7 +1384,7 @@ Store = Service.extend({ let { relationshipIsStale, - hasRelatedResources, + allInverseRecordsAreLoaded, hasDematerializedInverse, hasAnyRelationshipData, relationshipIsEmpty, @@ -1395,14 +1395,15 @@ Store = Service.extend({ resource.links.related && (hasDematerializedInverse || relationshipIsStale || - (!hasRelatedResources && !relationshipIsEmpty)); + (!allInverseRecordsAreLoaded && !relationshipIsEmpty)); // fetch via link if (shouldFindViaLink) { return this._fetchBelongsToLinkFromResource(resource, parentInternalModel, relationshipMeta); } - let preferLocalCache = hasAnyRelationshipData && hasRelatedResources && !relationshipIsEmpty; + let preferLocalCache = + hasAnyRelationshipData && allInverseRecordsAreLoaded && !relationshipIsEmpty; let hasLocalPartialData = hasDematerializedInverse || (relationshipIsEmpty && resource.data); // fetch using data, pulling from local cache if possible diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 146f4a2ed43..ce3d75b8ef9 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -136,7 +136,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { }); }); - describe('module unification', function() { + describe.skip('module unification', function() { beforeEach(function() { return emberNew().then(() => fs.ensureDirSync('src')); }); diff --git a/package.json b/package.json index 45360b04663..ab4037a5c37 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,9 @@ "silent-error": "^1.0.0" }, "devDependencies": { + "@ember-decorators/babel-transforms": "^2.0.0", + "@ember-decorators/data": "^2.1.0", + "babel-eslint": "^8.0.0", "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", "babel-plugin-transform-es2015-classes": "^6.23.0", "babel-plugin-transform-es2015-computed-properties": "^6.22.0", @@ -73,7 +76,7 @@ "broccoli-yuidoc": "^3.0.0", "co": "^4.6.0", "common-tags": "^1.4.0", - "ember-cli": "https://github.com/ember-cli/ember-cli#f724919b2d0455899411908531c9179240f5ef41", + "ember-cli": "^3.1.4", "ember-cli-app-version": "^3.0.0", "ember-cli-blueprint-test-helpers": "^0.18.3", "ember-cli-dependency-checker": "^2.1.0", @@ -88,6 +91,7 @@ "ember-cli-sri": "^2.1.0", "ember-cli-test-loader": "^1.1.0", "ember-cli-uglify": "2.0.0-beta.1", + "ember-decorators": "^2.1.0", "ember-disable-prototype-extensions": "^1.1.0", "ember-disable-proxy-controllers": "^1.0.0", "ember-export-application-global": "^1.0.5", diff --git a/testem.js b/testem.js index cc773d51c58..d67f5e4b449 100644 --- a/testem.js +++ b/testem.js @@ -9,8 +9,11 @@ module.exports = { Chrome: { mode: 'ci', args: [ - '--disable-gpu', '--headless', + '--disable-gpu', + '--disable-dev-shm-usage', + '--disable-software-rasterizer', + '--mute-audio', '--remote-debugging-port=0', '--window-size=1440,900', '--no-sandbox', diff --git a/tests/acceptance/relationships/has-many-test.js b/tests/acceptance/relationships/has-many-test.js new file mode 100644 index 00000000000..d93f914c532 --- /dev/null +++ b/tests/acceptance/relationships/has-many-test.js @@ -0,0 +1,664 @@ +import { module } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import Model from 'ember-data/model'; +import { render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; +import { attr, hasMany, belongsTo } from '@ember-decorators/data'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; +import Store from 'ember-data/store'; +import { resolve, reject } from 'rsvp'; +import { ServerError } from 'ember-data/adapters/errors'; +import Ember from 'ember'; +import { skipRecordData as test } from '../../helpers/test-in-debug'; + +function domListToArray(domList) { + return Array.prototype.slice.call(domList); +} + +class Person extends Model { + @attr name; + @hasMany('person', { async: true, inverse: 'parent' }) + children; + @belongsTo('person', { async: true, inverse: 'children' }) + parent; +} + +class TestAdapter extends JSONAPIAdapter { + setupPayloads(assert, arr) { + this.assert = assert; + this._payloads = arr; + } + + shouldBackgroundReload() { + return false; + } + + _nextPayload() { + let payload = this._payloads.shift(); + + if (payload === undefined) { + this.assert.ok(false, 'Too many adapter requests have been made!'); + return resolve({ data: null }); + } + + if (payload instanceof ServerError) { + return reject(payload); + } + return resolve(payload); + } + + // find by link + findHasMany() { + return this._nextPayload(); + } + + // find by data with coalesceFindRequests set to true + findMany() { + return this._nextPayload(); + } + + // find by partial data / individual records + findRecord() { + return this._nextPayload(); + } +} + +function makePeopleWithRelationshipData() { + let people = [ + { + type: 'person', + id: '1:no-children-or-parent', + attributes: { name: 'Chris Has No Children or Parent' }, + relationships: { + children: { data: [] }, + parent: { data: null }, + }, + }, + { + type: 'person', + id: '2:has-1-child-no-parent', + attributes: { + name: 'James has one child and no parent', + }, + relationships: { + children: { + data: [{ type: 'person', id: '3:has-2-children-and-parent' }], + }, + parent: { data: null }, + }, + }, + { + type: 'person', + id: '3:has-2-children-and-parent', + attributes: { + name: 'Kevin has two children and one parent', + }, + relationships: { + children: { + data: [ + { type: 'person', id: '4:has-parent-no-children' }, + { type: 'person', id: '5:has-parent-no-children' }, + ], + }, + parent: { + data: { + type: 'person', + id: '2:has-1-child-no-parent', + }, + }, + }, + }, + { + type: 'person', + id: '4:has-parent-no-children', + attributes: { + name: 'Selena has a parent', + }, + relationships: { + children: { + data: [], + }, + parent: { + data: { + type: 'person', + id: '3:has-2-children-and-parent', + }, + }, + }, + }, + { + type: 'person', + id: '5:has-parent-no-children', + attributes: { + name: 'Sedona has a parent', + }, + relationships: { + children: { + data: [], + }, + parent: { + data: { + type: 'person', + id: '3:has-2-children-and-parent', + }, + }, + }, + }, + ]; + + let peopleHash = {}; + people.forEach(person => { + peopleHash[person.id] = person; + }); + + return { + dict: peopleHash, + all: people, + }; +} + +function makePeopleWithRelationshipLinks(removeData = true) { + let people = makePeopleWithRelationshipData(); + let linkPayloads = (people.links = {}); + + people.all.map(person => { + Object.keys(person.relationships).forEach(relName => { + let rel = person.relationships[relName]; + let data = rel.data; + + if (removeData === true) { + delete rel.data; + } + + if (Array.isArray(data)) { + data = data.map(ref => people.dict[ref.id]); + } else { + if (data !== null) { + data = people.dict[data.id]; + } + } + + rel.links = { + related: `./${person.type}/${person.id}/${relName}`, + }; + linkPayloads[rel.links.related] = { + data, + }; + }); + }); + + return people; +} + +module('async has-many rendering tests', function(hooks) { + let store; + let adapter; + setupRenderingTest(hooks); + + hooks.beforeEach(function() { + let { owner } = this; + owner.register('model:person', Person); + owner.register('adapter:application', TestAdapter); + owner.register('serializer:application', JSONAPISerializer); + owner.register('service:store', Store); + store = owner.lookup('service:store'); + adapter = store.adapterFor('application'); + }); + + module('for data-no-link scenarios', function() { + test('We can render an async hasMany', async function(assert) { + let people = makePeopleWithRelationshipData(); + let parent = store.push({ + data: people.dict['3:has-2-children-and-parent'], + }); + + adapter.setupPayloads(assert, [ + { data: people.dict['4:has-parent-no-children'] }, + { data: people.dict['5:has-parent-no-children'] }, + ]); + + // render + this.set('parent', parent); + + await render(hbs` +
        + {{#each parent.children as |child|}} +
      • {{child.name}}
      • + {{/each}} +
      + `); + + let items = this.element.querySelectorAll('li'); + let names = domListToArray(items).map(e => e.textContent); + + assert.deepEqual( + names, + ['Selena has a parent', 'Sedona has a parent'], + 'We rendered the names' + ); + }); + + test('Re-rendering an async hasMany does not cause a new fetch', async function(assert) { + let people = makePeopleWithRelationshipData(); + let parent = store.push({ + data: people.dict['3:has-2-children-and-parent'], + }); + + adapter.setupPayloads(assert, [ + { data: people.dict['4:has-parent-no-children'] }, + { data: people.dict['5:has-parent-no-children'] }, + ]); + + // render + this.set('parent', parent); + + await render(hbs` +
        + {{#each parent.children as |child|}} +
      • {{child.name}}
      • + {{/each}} +
      + `); + + let items = this.element.querySelectorAll('li'); + let names = domListToArray(items).map(e => e.textContent); + + assert.deepEqual( + names, + ['Selena has a parent', 'Sedona has a parent'], + 'We rendered the names' + ); + + this.set('parent', null); + + items = this.element.querySelectorAll('li'); + assert.ok(items.length === 0, 'We have no items'); + + this.set('parent', parent); + + items = this.element.querySelectorAll('li'); + names = domListToArray(items).map(e => e.textContent); + + assert.deepEqual( + names, + ['Selena has a parent', 'Sedona has a parent'], + 'We rendered the names' + ); + }); + + test('Rendering an async hasMany whose fetch fails does not trigger a new request', async function(assert) { + assert.expect(12); + let people = makePeopleWithRelationshipData(); + let parent = store.push({ + data: people.dict['3:has-2-children-and-parent'], + }); + + adapter.setupPayloads(assert, [ + { data: people.dict['4:has-parent-no-children'] }, + new ServerError([], 'hard error while finding 5:has-parent-no-children'), + ]); + + // render + this.set('parent', parent); + + let originalOnError = Ember.onerror; + Ember.onerror = function(e) { + assert.ok(true, 'Children promise did reject'); + assert.equal( + e.message, + 'hard error while finding 5:has-parent-no-children', + 'Rejection has the correct message' + ); + }; + + // needed for LTS 2.12 and 2.16 + Ember.Test.adapter.exception = e => { + assert.ok(true, 'Children promise did reject'); + assert.equal( + e.message, + 'hard error while finding 5:has-parent-no-children', + 'Rejection has the correct message' + ); + }; + + await render(hbs` +
        + {{#each parent.children as |child|}} +
      • {{child.name}}
      • + {{/each}} +
      + `); + + let items = this.element.querySelectorAll('li'); + let names = domListToArray(items).map(e => e.textContent); + + assert.deepEqual( + names, + ['Selena has a parent'], + 'We rendered only the names for successful requests' + ); + + let relationshipState = parent.hasMany('children').hasManyRelationship; + + assert.equal(relationshipState.isAsync, true, 'The relationship is async'); + assert.equal(relationshipState.relationshipIsEmpty, false, 'The relationship is not empty'); + assert.equal(relationshipState.relationshipIsStale, true, 'The relationship is still stale'); + assert.equal( + relationshipState.allInverseRecordsAreLoaded, + false, + 'The relationship is missing some or all related resources' + ); + assert.equal( + relationshipState.hasAnyRelationshipData, + true, + 'The relationship knows which record it needs' + ); + assert.equal( + relationshipState.fetchPromise === null, + true, + 'The relationship has no fetchPromise' + ); + assert.equal( + relationshipState.hasFailedLoadAttempt === true, + true, + 'The relationship has attempted a load' + ); + assert.equal( + relationshipState._promiseProxy !== null, + true, + 'The relationship has a loadingPromise' + ); + assert.equal(!!relationshipState.link, false, 'The relationship does not have a link'); + + Ember.onerror = originalOnError; + }); + }); + + module('for link-no-data scenarios', function() { + test('We can render an async hasMany with a link', async function(assert) { + let people = makePeopleWithRelationshipLinks(true); + let parent = store.push({ + data: people.dict['3:has-2-children-and-parent'], + }); + + adapter.setupPayloads(assert, [ + people.links['./person/3:has-2-children-and-parent/children'], + ]); + + // render + this.set('parent', parent); + + await render(hbs` +
        + {{#each parent.children as |child|}} +
      • {{child.name}}
      • + {{/each}} +
      + `); + + let items = this.element.querySelectorAll('li'); + let names = domListToArray(items).map(e => e.textContent); + + assert.deepEqual( + names, + ['Selena has a parent', 'Sedona has a parent'], + 'We rendered the names' + ); + }); + + test('Re-rendering an async hasMany with a link does not cause a new fetch', async function(assert) { + let people = makePeopleWithRelationshipLinks(true); + let parent = store.push({ + data: people.dict['3:has-2-children-and-parent'], + }); + + adapter.setupPayloads(assert, [ + people.links['./person/3:has-2-children-and-parent/children'], + ]); + + // render + this.set('parent', parent); + + await render(hbs` +
        + {{#each parent.children as |child|}} +
      • {{child.name}}
      • + {{/each}} +
      + `); + + let items = this.element.querySelectorAll('li'); + let names = domListToArray(items).map(e => e.textContent); + + assert.deepEqual( + names, + ['Selena has a parent', 'Sedona has a parent'], + 'We rendered the names' + ); + + this.set('parent', null); + + items = this.element.querySelectorAll('li'); + assert.ok(items.length === 0, 'We have no items'); + + this.set('parent', parent); + + items = this.element.querySelectorAll('li'); + names = domListToArray(items).map(e => e.textContent); + + assert.deepEqual( + names, + ['Selena has a parent', 'Sedona has a parent'], + 'We rendered the names' + ); + }); + + test('Rendering an async hasMany with a link whose fetch fails does not trigger a new request', async function(assert) { + assert.expect(12); + let people = makePeopleWithRelationshipLinks(true); + let parent = store.push({ + data: people.dict['3:has-2-children-and-parent'], + }); + + adapter.setupPayloads(assert, [ + people.links['./person/3:has-2-children-and-parent/children'], + ]); + + adapter.setupPayloads(assert, [ + new ServerError( + [], + 'hard error while finding link ./person/3:has-2-children-and-parent/children' + ), + ]); + + // render + this.set('parent', parent); + + let originalOnError = Ember.onerror; + Ember.onerror = function(e) { + assert.ok(true, 'Children promise did reject'); + assert.equal( + e.message, + 'hard error while finding link ./person/3:has-2-children-and-parent/children', + 'Rejection has the correct message' + ); + }; + + // needed for LTS 2.12 and 2.16 + Ember.Test.adapter.exception = e => { + assert.ok(true, 'Children promise did reject'); + assert.equal( + e.message, + 'hard error while finding link ./person/3:has-2-children-and-parent/children', + 'Rejection has the correct message' + ); + }; + + await render(hbs` +
        + {{#each parent.children as |child|}} +
      • {{child.name}}
      • + {{/each}} +
      + `); + + let items = this.element.querySelectorAll('li'); + let names = domListToArray(items).map(e => e.textContent); + + assert.deepEqual(names, [], 'We rendered no names'); + + let relationshipState = parent.hasMany('children').hasManyRelationship; + + assert.equal(relationshipState.isAsync, true, 'The relationship is async'); + assert.equal( + relationshipState.relationshipIsEmpty, + true, + 'The relationship is empty because no signal has been received as to true state' + ); + assert.equal(relationshipState.relationshipIsStale, true, 'The relationship is still stale'); + assert.equal( + relationshipState.allInverseRecordsAreLoaded, + true, + 'The relationship is missing some or all related resources' + ); + assert.equal( + relationshipState.hasAnyRelationshipData, + false, + 'The relationship knows which record it needs' + ); + assert.equal( + relationshipState.fetchPromise === null, + true, + 'The relationship has no fetchPromise' + ); + assert.equal( + relationshipState.hasFailedLoadAttempt === true, + true, + 'The relationship has attempted a load' + ); + assert.equal( + relationshipState._promiseProxy !== null, + true, + 'The relationship has a loadingPromise' + ); + assert.equal(!!relationshipState.link, true, 'The relationship has a link'); + + Ember.onerror = originalOnError; + }); + }); + + module('for link-and-data scenarios', function() { + test('We can render an async hasMany with a link and data', async function(assert) { + let people = makePeopleWithRelationshipLinks(false); + let parent = store.push({ + data: people.dict['3:has-2-children-and-parent'], + }); + + adapter.setupPayloads(assert, [ + people.links['./person/3:has-2-children-and-parent/children'], + ]); + + // render + this.set('parent', parent); + + await render(hbs` +
        + {{#each parent.children as |child|}} +
      • {{child.name}}
      • + {{/each}} +
      + `); + + let items = this.element.querySelectorAll('li'); + let names = domListToArray(items).map(e => e.textContent); + + assert.deepEqual( + names, + ['Selena has a parent', 'Sedona has a parent'], + 'We rendered the names' + ); + }); + + test('Rendering an async hasMany with a link and data where data has been side-loaded does not fetch the link', async function(assert) { + let people = makePeopleWithRelationshipLinks(false); + let parent = store.push({ + data: people.dict['3:has-2-children-and-parent'], + included: [ + people.dict['4:has-parent-no-children'], + people.dict['5:has-parent-no-children'], + ], + }); + + // no requests should be made + adapter.setupPayloads(assert, []); + + // render + this.set('parent', parent); + + await render(hbs` +
        + {{#each parent.children as |child|}} +
      • {{child.name}}
      • + {{/each}} +
      + `); + + let items = this.element.querySelectorAll('li'); + let names = domListToArray(items).map(e => e.textContent); + + assert.deepEqual( + names, + ['Selena has a parent', 'Sedona has a parent'], + 'We rendered the names' + ); + }); + + test('Re-rendering an async hasMany with a link and data does not cause a new fetch', async function(assert) { + let people = makePeopleWithRelationshipLinks(false); + let parent = store.push({ + data: people.dict['3:has-2-children-and-parent'], + }); + + adapter.setupPayloads(assert, [ + people.links['./person/3:has-2-children-and-parent/children'], + ]); + + // render + this.set('parent', parent); + + await render(hbs` +
        + {{#each parent.children as |child|}} +
      • {{child.name}}
      • + {{/each}} +
      + `); + + let items = this.element.querySelectorAll('li'); + let names = domListToArray(items).map(e => e.textContent); + + assert.deepEqual( + names, + ['Selena has a parent', 'Sedona has a parent'], + 'We rendered the names' + ); + + this.set('parent', null); + + items = this.element.querySelectorAll('li'); + assert.ok(items.length === 0, 'We have no items'); + + this.set('parent', parent); + + items = this.element.querySelectorAll('li'); + names = domListToArray(items).map(e => e.textContent); + + assert.deepEqual( + names, + ['Selena has a parent', 'Sedona has a parent'], + 'We rendered the names' + ); + }); + }); +}); diff --git a/tests/helpers/model-factory-injection.js b/tests/helpers/model-factory-injection.js index 1a364a43163..1096af16f2e 100644 --- a/tests/helpers/model-factory-injection.js +++ b/tests/helpers/model-factory-injection.js @@ -1,5 +1,5 @@ import Ember from 'ember'; -import hasEmberVersion from 'ember-test-helpers/has-ember-version'; +import hasEmberVersion from '@ember/test-helpers/has-ember-version'; const ORIGINAL_MODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS; diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index 67e49141b8c..b74450b0a52 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -330,13 +330,21 @@ test('find a single record with belongsTo link as object { related }', function( return run(() => { return store.findRecord('post', 1).then(post => { - assert.equal(passedUrl[0], '/posts/1'); + assert.equal( + passedUrl[0], + '/posts/1', + 'The primary record post:1 was fetched by the correct url' + ); assert.equal(post.get('id'), '1'); assert.equal(post.get('title'), 'Ember.js rocks'); return post.get('author').then(author => { - assert.equal(passedUrl[1], 'http://example.com/user/2'); + assert.equal( + passedUrl[1], + 'http://example.com/user/2', + 'The relationship user:2 was fetched by the correct url' + ); assert.equal(author.get('id'), '2'); assert.equal(author.get('firstName'), 'Yehuda'); @@ -378,13 +386,21 @@ test('find a single record with belongsTo link as object { data }', function(ass return run(() => { return store.findRecord('post', 1).then(post => { - assert.equal(passedUrl[0], '/posts/1'); + assert.equal( + passedUrl[0], + '/posts/1', + 'The primary record post:1 was fetched by the correct url' + ); assert.equal(post.get('id'), '1'); assert.equal(post.get('title'), 'Ember.js rocks'); return post.get('author').then(author => { - assert.equal(passedUrl[1], '/users/2'); + assert.equal( + passedUrl[1], + '/users/2', + 'The relationship user:2 was fetched by the correct url' + ); assert.equal(author.get('id'), '2'); assert.equal(author.get('firstName'), 'Yehuda'); @@ -476,7 +492,11 @@ test('find a single record with sideloaded belongsTo link as object { data }', f return run(() => { return store.findRecord('post', 1).then(post => { - assert.equal(passedUrl[0], '/posts/1'); + assert.equal( + passedUrl[0], + '/posts/1', + 'The primary record post:1 was fetched by the correct url' + ); assert.equal(post.get('id'), '1'); assert.equal(post.get('title'), 'Ember.js rocks'); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index ac4efc97327..2a44b221369 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -5,17 +5,14 @@ import { reset as resetModelFactoryInjections, } from 'dummy/tests/helpers/model-factory-injection'; import { A } from '@ember/array'; - import { resolve, Promise as EmberPromise, all, reject, hash } from 'rsvp'; import { get } from '@ember/object'; import { run } from '@ember/runloop'; - import setupStore from 'dummy/tests/helpers/store'; - import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import { module, test } from 'qunit'; - +import { module, test, skip } from 'qunit'; import DS from 'ember-data'; +import { skipRecordData } from '../../helpers/test-in-debug'; let env, store, User, Contact, Email, Phone, Message, Post, Comment; let Book, Chapter, Page; @@ -963,73 +960,75 @@ test('A hasMany relationship can be reloaded if it was fetched via ids', functio }); }); -test('A hasMany relationship can be reloaded even if it failed at the first time', function(assert) { - assert.expect(4); +skipRecordData( + 'A hasMany relationship can be reloaded even if it failed at the first time', + async function(assert) { + assert.expect(6); - Post.reopen({ - comments: DS.hasMany('comment', { async: true }), - }); + const { store, adapter } = env; - env.adapter.findRecord = function(store, type, id) { - return resolve({ - data: { - id: 1, - type: 'post', - relationships: { - comments: { - links: { related: '/posts/1/comments' }, - }, - }, - }, + Post.reopen({ + comments: DS.hasMany('comment', { async: true }), }); - }; - let loadingCount = -1; - env.adapter.findHasMany = function(store, record, link, relationship) { - loadingCount++; - if (loadingCount % 2 === 0) { - return reject(); - } else { + adapter.findRecord = function(store, type, id) { return resolve({ - data: [ - { id: 1, type: 'comment', attributes: { body: 'FirstUpdated' } }, - { id: 2, type: 'comment', attributes: { body: 'Second' } }, - ], + data: { + id: 1, + type: 'post', + relationships: { + comments: { + links: { related: '/posts/1/comments' }, + }, + }, + }, }); - } - }; - run(function() { - env.store.findRecord('post', 1).then(function(post) { - let comments = post.get('comments'); - return comments - .catch(function() { - return comments.reload(); - }) - .then(function(manyArray) { - assert.equal( - manyArray.get('isLoaded'), - true, - 'the reload worked, comments are now loaded' - ); - return manyArray.reload().catch(function() { - assert.equal( - manyArray.get('isLoaded'), - true, - 'the second reload failed, comments are still loaded though' - ); - return manyArray.reload().then(function(reloadedManyArray) { - assert.equal( - reloadedManyArray.get('isLoaded'), - true, - 'the third reload worked, comments are loaded again' - ); - assert.ok(reloadedManyArray === manyArray, 'the many array stays the same'); - }); - }); + }; + + let loadingCount = -1; + adapter.findHasMany = function(store, record, link, relationship) { + loadingCount++; + if (loadingCount % 2 === 0) { + return reject({ data: null }); + } else { + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'FirstUpdated' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], }); + } + }; + + let post = await store.findRecord('post', 1); + let comments = post.get('comments'); + let manyArray = await comments.catch(() => { + assert.ok(true, 'An error was thrown on the first reload of comments'); + return comments.reload(); }); - }); -}); + + assert.equal(manyArray.get('isLoaded'), true, 'the reload worked, comments are now loaded'); + + await manyArray.reload().catch(() => { + assert.ok(true, 'An error was thrown on the second reload via manyArray'); + }); + + assert.equal( + manyArray.get('isLoaded'), + true, + 'the second reload failed, comments are still loaded though' + ); + + let reloadedManyArray = await manyArray.reload(); + + assert.equal( + reloadedManyArray.get('isLoaded'), + true, + 'the third reload worked, comments are loaded again' + ); + assert.ok(reloadedManyArray === manyArray, 'the many array stays the same'); + } +); test('A hasMany relationship can be directly reloaded if it was fetched via links', function(assert) { assert.expect(6); @@ -2070,16 +2069,18 @@ test('dual non-async HM <-> BT', function(assert) { }); }); -test('When an unloaded record is added to the hasMany, it gets fetched once the hasMany is accessed even if the hasMany has been already fetched', function(assert) { +test('When an unloaded record is added to the hasMany, it gets fetched once the hasMany is accessed even if the hasMany has been already fetched', async function(assert) { assert.expect(6); Post.reopen({ comments: DS.hasMany('comment', { async: true }), }); + const { store, adapter } = env; + let findManyCalls = 0; let findRecordCalls = 0; - env.adapter.findMany = function(store, type, ids, snapshots) { + adapter.findMany = function(store, type, ids, snapshots) { assert.ok(true, `findMany called ${++findManyCalls}x`); return resolve({ data: [ @@ -2089,69 +2090,60 @@ test('When an unloaded record is added to the hasMany, it gets fetched once the }); }; - env.adapter.findRecord = function(store, type, id, snapshot) { + adapter.findRecord = function(store, type, id, snapshot) { assert.ok(true, `findRecord called ${++findRecordCalls}x`); + return resolve({ data: { id: 3, type: 'comment', attributes: { body: 'third' } } }); }; - let post; - run(() => { - env.store.push({ - data: { - type: 'post', - id: '1', - relationships: { - comments: { - data: [{ type: 'comment', id: '1' }, { type: 'comment', id: '2' }], - }, + let post = store.push({ + data: { + type: 'post', + id: '1', + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }, { type: 'comment', id: '2' }], }, }, - }); - post = env.store.peekRecord('post', 1); + }, }); - return run(() => { - return post.get('comments').then(fetchedComments => { - assert.equal(fetchedComments.get('length'), 2, 'comments fetched successfully'); - assert.equal( - fetchedComments.objectAt(0).get('body'), - 'first', - 'first comment loaded successfully' - ); + let fetchedComments = await post.get('comments'); - env.store.push({ - data: { - type: 'post', - id: '1', - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], - }, - }, - }, - }); + assert.equal(fetchedComments.get('length'), 2, 'comments fetched successfully'); + assert.equal( + fetchedComments.objectAt(0).get('body'), + 'first', + 'first comment loaded successfully' + ); - return post.get('comments').then(newlyFetchedComments => { - assert.equal( - newlyFetchedComments.get('length'), - 3, - 'all three comments fetched successfully' - ); - assert.equal( - newlyFetchedComments.objectAt(2).get('body'), - 'third', - 'third comment loaded successfully' - ); - }); - }); + store.push({ + data: { + type: 'post', + id: '1', + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], + }, + }, + }, }); + + let newlyFetchedComments = await post.get('comments'); + + assert.equal(newlyFetchedComments.get('length'), 3, 'all three comments fetched successfully'); + assert.equal( + newlyFetchedComments.objectAt(2).get('body'), + 'third', + 'third comment loaded successfully' + ); }); -testInDebug('A sync hasMany errors out if there are unlaoded records in it', function(assert) { +skip('A sync hasMany errors out if there are unloaded records in it', function(assert) { let post = run(() => { env.store.push({ data: { @@ -2169,7 +2161,7 @@ testInDebug('A sync hasMany errors out if there are unlaoded records in it', fun assert.expectAssertion(() => { run(post, 'get', 'comments'); - }, /You looked up the 'comments' relationship on a 'post' with id 1 but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async \('DS.hasMany\({ async: true }\)'\)/); + }, /You looked up the 'comments' relationship on a 'post' with id 1 but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async \(`DS.hasMany\({ async: true }\)`\)/); }); test('After removing and unloading a record, a hasMany relationship should still be valid', function(assert) { diff --git a/tests/integration/relationships/json-api-links-test.js b/tests/integration/relationships/json-api-links-test.js index d875ce1ed0a..72110bf59ce 100644 --- a/tests/integration/relationships/json-api-links-test.js +++ b/tests/integration/relationships/json-api-links-test.js @@ -1683,11 +1683,15 @@ test(`get+unload+get hasMany with missing data setup from the other side, no lin ], }) ); + + // should trigger a fetch bc we don't consider `pets` to have complete knowledge let pets = run(() => user.get('pets')); assert.ok(!!pets, 'We found our pets'); run(() => pets.objectAt(0).unloadRecord()); + + // should trigger a findRecord for the unloaded pet run(() => user.get('pets')); }); test(`get+reload belongsTo with missing data setup from the other side, no links`, function(assert) { @@ -1943,12 +1947,12 @@ test('We should not fetch a hasMany relationship with links that we know is empt // should not fire a request requestedUser = null; - failureDescription = 'We fetched the link for a known empty relationship'; + failureDescription = 'We improperly fetched the link for a known empty relationship'; run(() => user1.get('pets')); // still should not fire a request requestedUser = null; - failureDescription = 'We fetched the link (again) for a known empty relationship'; + failureDescription = 'We improperly fetched the link (again) for a known empty relationship'; run(() => user1.get('pets')); // should fire a request @@ -1958,6 +1962,6 @@ test('We should not fetch a hasMany relationship with links that we know is empt // should not fire a request requestedUser = null; failureDescription = - 'We fetched the link for a previously fetched and found to be empty relationship'; + 'We improperly fetched the link for a previously fetched and found to be empty relationship'; run(() => user2.get('pets')); }); diff --git a/tests/integration/relationships/one-to-one-test.js b/tests/integration/relationships/one-to-one-test.js index 88cabe9e72f..89d4831785e 100644 --- a/tests/integration/relationships/one-to-one-test.js +++ b/tests/integration/relationships/one-to-one-test.js @@ -440,10 +440,18 @@ test('Setting a BelongsTo to a promise unwraps the promise before setting- async run(function() { newFriend.set('bestFriend', stanleysFriend.get('bestFriend')); stanley.get('bestFriend').then(function(fetchedUser) { - assert.equal(fetchedUser, newFriend, 'User relationship was updated correctly'); + assert.equal( + fetchedUser, + newFriend, + `Stanley's bestFriend relationship was updated correctly to newFriend` + ); }); newFriend.get('bestFriend').then(function(fetchedUser) { - assert.equal(fetchedUser, stanley, 'User relationship was updated correctly'); + assert.equal( + fetchedUser, + stanley, + `newFriend's bestFriend relationship was updated correctly to be Stanley` + ); }); }); }); diff --git a/yarn.lock b/yarn.lock index fab3191ed6b..e04637e74de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,134 @@ # yarn lockfile v1 +"@babel/code-frame@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" + dependencies: + "@babel/highlight" "7.0.0-beta.44" + +"@babel/generator@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" + dependencies: + "@babel/types" "7.0.0-beta.44" + jsesc "^2.5.1" + lodash "^4.2.0" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-function-name@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" + dependencies: + "@babel/helper-get-function-arity" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-get-function-arity@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-split-export-declaration@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/highlight@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +"@babel/template@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + lodash "^4.2.0" + +"@babel/traverse@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/generator" "7.0.0-beta.44" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-split-export-declaration" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + debug "^3.1.0" + globals "^11.1.0" + invariant "^2.2.0" + lodash "^4.2.0" + +"@babel/types@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" + +"@ember-decorators/babel-transforms@^2.0.0": + version "2.0.1" + resolved "https://registry.npmjs.org/@ember-decorators/babel-transforms/-/babel-transforms-2.0.1.tgz#75b668cfe996fa920c940ad723be015cddf904db" + dependencies: + babel-plugin-transform-class-properties "^6.24.1" + babel-plugin-transform-decorators-legacy "^1.3.4" + ember-cli-babel "^6.6.0" + ember-cli-version-checker "^2.1.0" + +"@ember-decorators/component@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@ember-decorators/component/-/component-2.1.0.tgz#846ad4197a06c9814d02654e947c023d35107cee" + dependencies: + "@ember-decorators/utils" "^2.1.0" + ember-cli-babel "^6.6.0" + +"@ember-decorators/controller@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@ember-decorators/controller/-/controller-2.1.0.tgz#57a7be3d4eaa18e5021096d404417b1b943e7124" + dependencies: + "@ember-decorators/utils" "^2.1.0" + ember-cli-babel "^6.6.0" + +"@ember-decorators/data@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@ember-decorators/data/-/data-2.1.0.tgz#df29cc4bb21b7f246a02f810e2c7b56bd6f25294" + dependencies: + "@ember-decorators/utils" "^2.1.0" + ember-cli-babel "^6.6.0" + +"@ember-decorators/object@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@ember-decorators/object/-/object-2.1.0.tgz#725c790c030299a4bc8c15f21048c3c0abc1499c" + dependencies: + "@ember-decorators/utils" "^2.1.0" + ember-cli-babel "^6.6.0" + ember-compatibility-helpers "^1.0.0" + +"@ember-decorators/service@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@ember-decorators/service/-/service-2.1.0.tgz#c6bbfd34fbb9fb19317ab2be351d8577701e5315" + dependencies: + "@ember-decorators/utils" "^2.1.0" + ember-cli-babel "^6.6.0" + +"@ember-decorators/utils@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@ember-decorators/utils/-/utils-2.1.0.tgz#cd354ff59ce0d5faa74880c15db0f72fefe6dc70" + dependencies: + ember-cli-babel "^6.6.0" + ember-compatibility-helpers "^1.0.0" + "@ember/ordered-set@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@ember/ordered-set/-/ordered-set-1.0.0.tgz#cf9ab5fd7510bcad370370ebcded705f6d1c542b" @@ -146,7 +274,7 @@ amd-name-resolver@0.0.7: dependencies: ensure-posix-path "^1.0.1" -amd-name-resolver@^1.2.0: +amd-name-resolver@1.2.0, amd-name-resolver@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz#fc41b3848824b557313897d71f8d5a0184fbe679" dependencies: @@ -500,6 +628,17 @@ babel-core@^6.14.0, babel-core@^6.26.0: slash "^1.0.0" source-map "^0.5.6" +babel-eslint@^8.0.0: + version "8.2.3" + resolved "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.3.tgz#1a2e6681cc9bc4473c32899e59915e19cd6733cf" + dependencies: + "@babel/code-frame" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + eslint-scope "~3.7.1" + eslint-visitor-keys "^1.0.0" + babel-generator@^6.26.0: version "6.26.1" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" @@ -714,6 +853,14 @@ babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + +babel-plugin-syntax-decorators@^6.1.18: + version "6.13.0" + resolved "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" + babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" @@ -730,6 +877,23 @@ babel-plugin-transform-async-to-generator@^6.22.0: babel-plugin-syntax-async-functions "^6.8.0" babel-runtime "^6.22.0" +babel-plugin-transform-class-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + dependencies: + babel-helper-function-name "^6.24.1" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-decorators-legacy@^1.3.4: + version "1.3.5" + resolved "https://registry.npmjs.org/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.5.tgz#0e492dffa0edd70529072887f8aa86d4dd8b40a1" + dependencies: + babel-plugin-syntax-decorators "^6.1.18" + babel-runtime "^6.2.0" + babel-template "^6.3.0" + babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" @@ -935,7 +1099,7 @@ babel-plugin-undefined-to-void@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" -babel-polyfill@^6.16.0: +babel-polyfill@^6.16.0, babel-polyfill@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" dependencies: @@ -978,6 +1142,41 @@ babel-preset-env@^1.5.1: invariant "^2.2.2" semver "^5.3.0" +babel-preset-env@^1.7.0: + version "1.7.0" + resolved "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^3.2.6" + invariant "^2.2.2" + semver "^5.3.0" + babel-register@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" @@ -996,14 +1195,14 @@ babel-runtime@^5.0.0: dependencies: core-js "^1.0.0" -babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: +babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: core-js "^2.4.0" regenerator-runtime "^0.11.0" -babel-template@^6.24.1, babel-template@^6.26.0: +babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" dependencies: @@ -1044,6 +1243,10 @@ babel6-plugin-strip-heimdall@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" +babylon@7.0.0-beta.44: + version "7.0.0-beta.44" + resolved "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" + babylon@^5.8.38: version "5.8.38" resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" @@ -1228,13 +1431,6 @@ breakable@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" -broccoli-amd-funnel@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/broccoli-amd-funnel/-/broccoli-amd-funnel-1.3.0.tgz#c4426b4fce976e44295bd74f34725f53bdeb08e3" - dependencies: - broccoli-plugin "^1.3.0" - symlink-or-copy "^1.2.0" - broccoli-asset-rev@^2.4.5: version "2.6.0" resolved "https://registry.yarnpkg.com/broccoli-asset-rev/-/broccoli-asset-rev-2.6.0.tgz#0633fc3a0b2ba0c2c1d56fa9feb7b331fc83be6d" @@ -1281,6 +1477,21 @@ broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2: rsvp "^3.5.0" workerpool "^2.3.0" +broccoli-babel-transpiler@^6.4.2: + version "6.4.3" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.4.3.tgz#06e399298d41700cdc10d675b1d808a89ef6b2d0" + dependencies: + babel-core "^6.26.0" + broccoli-funnel "^2.0.1" + broccoli-merge-trees "^2.0.0" + broccoli-persistent-filter "^1.4.3" + clone "^2.0.0" + hash-for-dep "^1.2.3" + heimdalljs-logger "^0.1.7" + json-stable-stringify "^1.0.0" + rsvp "^4.8.2" + workerpool "^2.3.0" + broccoli-builder@^0.18.8: version "0.18.11" resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.11.tgz#a42393c7b10bb0380df255a616307945f5e26efb" @@ -1355,7 +1566,7 @@ broccoli-config-replace@^1.1.2: debug "^2.2.0" fs-extra "^0.24.0" -broccoli-debug@^0.6.1, broccoli-debug@^0.6.2, broccoli-debug@^0.6.3: +broccoli-debug@^0.6.1, broccoli-debug@^0.6.2, broccoli-debug@^0.6.3, broccoli-debug@^0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/broccoli-debug/-/broccoli-debug-0.6.4.tgz#986eb3d2005e00e3bb91f9d0a10ab137210cd150" dependencies: @@ -1485,23 +1696,6 @@ broccoli-middleware@^1.2.1: handlebars "^4.0.4" mime-types "^2.1.18" -broccoli-module-normalizer@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/broccoli-module-normalizer/-/broccoli-module-normalizer-1.3.0.tgz#f9982d9cbb776b4ed754161cc6547784d3eb19de" - dependencies: - broccoli-plugin "^1.3.0" - merge-trees "^1.0.1" - rimraf "^2.6.2" - symlink-or-copy "^1.1.8" - -broccoli-module-unification-reexporter@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/broccoli-module-unification-reexporter/-/broccoli-module-unification-reexporter-1.0.0.tgz#031909c5d3f159ec11d5f9e2346f2861db8acb3e" - dependencies: - broccoli-plugin "^1.3.0" - mkdirp "^0.5.1" - walk-sync "^0.3.2" - broccoli-node-info@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" @@ -1693,6 +1887,13 @@ browserslist@^2.1.2: caniuse-lite "^1.0.30000792" electron-to-chromium "^1.3.30" +browserslist@^3.2.6: + version "3.2.8" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" + dependencies: + caniuse-lite "^1.0.30000844" + electron-to-chromium "^1.3.47" + bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" @@ -1798,6 +1999,10 @@ caniuse-lite@^1.0.30000792: version "1.0.30000813" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000813.tgz#7b25e27fdfb8d133f3c932b01f77452140fcc6c9" +caniuse-lite@^1.0.30000844: + version "1.0.30000855" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000855.tgz#d5a26a9093b932d6266bf4ed9294b41b84945d14" + capture-exit@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" @@ -1916,10 +2121,6 @@ chokidar@1.7.0: optionalDependencies: fsevents "^1.0.0" -ci-info@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" - circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" @@ -2197,9 +2398,9 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" -console-ui@^2.2.2: +console-ui@^2.1.0: version "2.2.2" - resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-2.2.2.tgz#b294a2934de869dd06789ab4be69555411edef29" + resolved "https://registry.npmjs.org/console-ui/-/console-ui-2.2.2.tgz#b294a2934de869dd06789ab4be69555411edef29" dependencies: chalk "^2.1.0" inquirer "^2" @@ -2214,6 +2415,12 @@ consolidate@^0.14.0: dependencies: bluebird "^3.1.1" +consolidate@^0.15.1: + version "0.15.1" + resolved "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7" + dependencies: + bluebird "^3.1.1" + content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" @@ -2268,9 +2475,9 @@ core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -cross-spawn@^5.1.0: +cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: lru-cache "^4.0.1" shebang-command "^1.2.0" @@ -2555,6 +2762,10 @@ electron-to-chromium@^1.3.30: version "1.3.36" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.36.tgz#0eabf71a9ebea9013fb1cc35a390e068624f27e8" +electron-to-chromium@^1.3.47: + version "1.3.48" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.48.tgz#d3b0d8593814044e092ece2108fc3ac9aea4b900" + ember-cli-app-version@^3.0.0: version "3.1.3" resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-3.1.3.tgz#26d25f5e653ff0106f0b39da6d75518ba8ed282d" @@ -2590,6 +2801,24 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.6, ember-c ember-cli-version-checker "^1.0.2" resolve "^1.1.2" +ember-cli-babel@^6.6.0: + version "6.14.1" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.14.1.tgz#796339229035910b625593caffbc2683792ada68" + dependencies: + amd-name-resolver "1.2.0" + babel-plugin-debug-macros "^0.1.11" + babel-plugin-ember-modules-api-polyfill "^2.3.0" + babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-polyfill "^6.26.0" + babel-preset-env "^1.7.0" + broccoli-babel-transpiler "^6.4.2" + broccoli-debug "^0.6.4" + broccoli-funnel "^2.0.0" + broccoli-source "^1.1.0" + clone "^2.0.0" + ember-cli-version-checker "^2.1.2" + semver "^5.5.0" + ember-cli-blueprint-test-helpers@^0.18.3: version "0.18.3" resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.18.3.tgz#945c606d855f0263f5e8c03522e4040a74f259cc" @@ -2824,15 +3053,21 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0: resolve "^1.3.3" semver "^5.3.0" -"ember-cli@https://github.com/ember-cli/ember-cli#f724919b2d0455899411908531c9179240f5ef41": - version "3.1.2" - resolved "https://github.com/ember-cli/ember-cli#f724919b2d0455899411908531c9179240f5ef41" +ember-cli-version-checker@^2.1.1, ember-cli-version-checker@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-2.1.2.tgz#305ce102390c66e4e0f1432dea9dc5c7c19fed98" + dependencies: + resolve "^1.3.3" + semver "^5.3.0" + +ember-cli@^3.1.4: + version "3.1.4" + resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-3.1.4.tgz#95f7ff4302d535619b5d5ff1c7040877a67d4468" dependencies: amd-name-resolver "^1.2.0" babel-plugin-transform-es2015-modules-amd "^6.24.0" bower-config "^1.3.0" bower-endpoint-parser "0.2.2" - broccoli-amd-funnel "^1.3.0" broccoli-babel-transpiler "^6.0.0" broccoli-builder "^0.18.8" broccoli-concat "^3.2.2" @@ -2843,18 +3078,15 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0: broccoli-funnel-reducer "^1.0.0" broccoli-merge-trees "^2.0.0" broccoli-middleware "^1.2.1" - broccoli-module-normalizer "^1.3.0" - broccoli-module-unification-reexporter "^1.0.0" broccoli-source "^1.1.0" broccoli-stew "^1.2.0" calculate-cache-key-for-tree "^1.0.0" capture-exit "^1.1.0" chalk "^2.0.1" - ci-info "^1.1.2" clean-base-url "^1.0.0" compression "^1.4.4" configstore "^3.0.0" - console-ui "^2.2.2" + console-ui "^2.1.0" core-object "^3.1.3" dag-map "^2.0.2" diff "^3.2.0" @@ -2865,7 +3097,8 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0: ember-cli-preprocess-registry "^3.1.0" ember-cli-string-utils "^1.0.0" ensure-posix-path "^1.0.2" - execa "^0.10.0" + execa "^0.9.0" + exists-sync "0.0.4" exit "^0.1.2" express "^4.12.3" filesize "^3.1.3" @@ -2874,7 +3107,7 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0: fs-extra "^5.0.0" fs-tree-diff "^0.5.2" get-caller-file "^1.0.0" - git-repo-info "^2.0.0" + git-repo-info "^1.4.1" glob "^7.1.2" heimdalljs "^0.2.3" heimdalljs-fs-monitor "^0.2.0" @@ -2906,7 +3139,7 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0: sort-package-json "^1.4.0" symlink-or-copy "^1.1.8" temp "0.8.3" - testem "^2.2.0" + testem "^2.0.0" tiny-lr "^1.0.3" tree-sync "^1.2.1" uuid "^3.0.0" @@ -2915,6 +3148,14 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0: watch-detector "^0.1.0" yam "^0.0.24" +ember-compatibility-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/ember-compatibility-helpers/-/ember-compatibility-helpers-1.0.0.tgz#616b22d2e14b4c6a1f4441e5390a49abf52b3c68" + dependencies: + babel-plugin-debug-macros "^0.1.11" + ember-cli-version-checker "^2.1.1" + semver "^5.4.1" + ember-compatibility-helpers@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.0.0-beta.2.tgz#00cb134af45f9562fa47a23f4da81a63aad41943" @@ -2923,6 +3164,18 @@ ember-compatibility-helpers@^1.0.0-beta.2: ember-cli-version-checker "^2.0.0" semver "^5.4.1" +ember-decorators@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/ember-decorators/-/ember-decorators-2.1.0.tgz#4910835da3517c633532c8d6fcfcf026e13701c0" + dependencies: + "@ember-decorators/component" "^2.1.0" + "@ember-decorators/controller" "^2.1.0" + "@ember-decorators/data" "^2.1.0" + "@ember-decorators/object" "^2.1.0" + "@ember-decorators/service" "^2.1.0" + ember-cli-babel "^6.0.0" + semver "^5.5.0" + ember-disable-prototype-extensions@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" @@ -3264,9 +3517,9 @@ eslint-plugin-prettier@^2.6.0: fast-diff "^1.1.1" jest-docblock "^21.0.0" -eslint-scope@^3.7.1: +eslint-scope@^3.7.1, eslint-scope@~3.7.1: version "3.7.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" @@ -3426,6 +3679,18 @@ execa@^0.10.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +execa@^0.9.0: + version "0.9.0" + resolved "https://registry.npmjs.org/execa/-/execa-0.9.0.tgz#adb7ce62cf985071f60580deb4a88b9e34712d01" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + exists-stat@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/exists-stat/-/exists-stat-1.0.0.tgz#0660e3525a2e89d9e446129440c272edfa24b529" @@ -3868,7 +4133,7 @@ fs-extra@^4.0.0, fs-extra@^4.0.2, fs-extra@^4.0.3: fs-extra@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -3876,7 +4141,7 @@ fs-extra@^5.0.0: fs-extra@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b" dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -3984,10 +4249,6 @@ git-repo-info@^1.1.2, git-repo-info@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" -git-repo-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-2.0.0.tgz#2e7a68ba3d0253e8e885c4138f922e6561de59bb" - git-repo-version@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-1.0.2.tgz#2c8e9bee5d970cafc0dd58480f9dc56d9afe8e4f" @@ -4092,9 +4353,9 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" -globals@^11.0.1: +globals@^11.0.1, globals@^11.1.0: version "11.5.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.5.0.tgz#6bc840de6771173b191f13d3a9c94d441ee92642" + resolved "https://registry.npmjs.org/globals/-/globals-11.5.0.tgz#6bc840de6771173b191f13d3a9c94d441ee92642" globals@^6.4.0: version "6.4.1" @@ -4253,7 +4514,7 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -hash-for-dep@^1.0.2: +hash-for-dep@^1.0.2, hash-for-dep@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.2.3.tgz#5ec69fca32c23523972d52acb5bb65ffc3664cab" dependencies: @@ -4500,6 +4761,12 @@ into-stream@^3.1.0: from2 "^2.1.1" p-is-promise "^1.1.0" +invariant@^2.2.0: + version "2.2.4" + resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + dependencies: + loose-envify "^1.0.0" + invariant@^2.2.2: version "2.2.3" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.3.tgz#1a827dfde7dcbd7c323f0ca826be8fa7c5e9d688" @@ -4851,9 +5118,9 @@ jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" -jsesc@^2.5.0: +jsesc@^2.5.0, jsesc@^2.5.1: version "2.5.1" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" jsesc@~0.3.x: version "0.3.0" @@ -5361,6 +5628,10 @@ lodash@^4.0.0, lodash@^4.14.0, lodash@^4.16.1, lodash@^4.17.2, lodash@^4.17.4, l version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" +lodash@^4.2.0: + version "4.17.10" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" @@ -5656,6 +5927,13 @@ minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" +minipass@^2.2.0: + version "2.3.3" + resolved "https://registry.npmjs.org/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + mixin-deep@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" @@ -6249,6 +6527,10 @@ printf@^0.2.3: version "0.2.5" resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" +printf@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/printf/-/printf-0.3.0.tgz#6918ca5237c047e19cf004b69e6bcfafbef1ce82" + private@^0.1.6, private@^0.1.7, private@~0.1.5: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -6708,7 +6990,7 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: +rimraf@2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: @@ -6759,9 +7041,9 @@ rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0. version "3.6.2" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" -rsvp@^4.6.1, rsvp@^4.7.0: +rsvp@^4.6.1, rsvp@^4.7.0, rsvp@^4.8.2: version "4.8.2" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.2.tgz#9d5647108735784eb13418cdddb56f75b919d722" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.2.tgz#9d5647108735784eb13418cdddb56f75b919d722" rsvp@~3.0.6: version "3.0.21" @@ -6795,6 +7077,10 @@ safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, s version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" +safe-buffer@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + safe-json-parse@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" @@ -7404,7 +7690,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0: +symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: version "1.2.0" resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" @@ -7428,6 +7714,14 @@ tap-parser@^5.1.0: optionalDependencies: readable-stream "^2" +tap-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/tap-parser/-/tap-parser-7.0.0.tgz#54db35302fda2c2ccc21954ad3be22b2cba42721" + dependencies: + events-to-array "^1.0.1" + js-yaml "^3.2.7" + minipass "^2.2.0" + tar-pack@^3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" @@ -7496,15 +7790,15 @@ testem@^1.15.0: tap-parser "^5.1.0" xmldom "^0.1.19" -testem@^2.2.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/testem/-/testem-2.6.0.tgz#96c022c61bfd4d3b37738dc7483c1e678427d85b" +testem@^2.0.0: + version "2.8.2" + resolved "https://registry.npmjs.org/testem/-/testem-2.8.2.tgz#0d51801cbcdfe411e2e24ae7e63e2eca779dfe89" dependencies: backbone "^1.1.2" bluebird "^3.4.6" charm "^1.0.0" commander "^2.6.0" - consolidate "^0.14.0" + consolidate "^0.15.1" execa "^0.10.0" express "^4.10.7" fireworm "^0.7.0" @@ -7520,12 +7814,12 @@ testem@^2.2.0: mustache "^2.2.1" node-notifier "^5.0.1" npmlog "^4.0.0" - printf "^0.2.3" + printf "^0.3.0" rimraf "^2.4.4" socket.io "^2.1.0" spawn-args "^0.2.0" styled_string "0.0.1" - tap-parser "^5.1.0" + tap-parser "^7.0.0" xmldom "^0.1.19" text-table@~0.2.0: @@ -7602,6 +7896,10 @@ to-fast-properties@^1.0.0, to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + to-iso-string@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" @@ -8074,6 +8372,10 @@ yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" +yallist@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" + yam@^0.0.24: version "0.0.24" resolved "https://registry.yarnpkg.com/yam/-/yam-0.0.24.tgz#11e9630444735f66a561d29221407de6d037cd95" From 5d5b99bb9e0cc879f5dee27b8531a7210a02f3c4 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 20 Jun 2018 17:01:49 -0700 Subject: [PATCH 2247/2527] drop explicit testing for 2.12 --- config/ember-try.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/config/ember-try.js b/config/ember-try.js index fdaa5362d1b..e6b728b1e85 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -16,14 +16,6 @@ module.exports = function() { bower: {}, npm: {}, }, - { - name: 'ember-lts-2.12', - npm: { - devDependencies: { - 'ember-source': '~2.12.0', - }, - }, - }, { name: 'ember-lts-2.16', npm: { From 7c01c603c8345589261fdcf1a09e6e8ce3b529ef Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 20 Jun 2018 17:33:42 -0700 Subject: [PATCH 2248/2527] add 2.18 LTS --- .travis.yml | 4 ++-- config/ember-try.js | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7503f1bb1c1..08df190252f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,8 +57,8 @@ jobs: # runs tests against each supported Ember version - stage: older version tests - env: EMBER_TRY_SCENARIO=ember-lts-2.12 - - env: EMBER_TRY_SCENARIO=ember-lts-2.16 + env: EMBER_TRY_SCENARIO=ember-lts-2.16 + - env: EMBER_TRY_SCENARIO=ember-lts-2.18 - env: EMBER_TRY_SCENARIO=ember-release - env: EMBER_TRY_SCENARIO=ember-beta - env: EMBER_TRY_SCENARIO=ember-canary diff --git a/config/ember-try.js b/config/ember-try.js index e6b728b1e85..c60101b0aae 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -24,6 +24,14 @@ module.exports = function() { }, }, }, + { + name: 'ember-lts-2.18', + npm: { + devDependencies: { + 'ember-source': '~2.18.0', + }, + }, + }, { name: 'ember-release', npm: { From 5e31af381eb3b3b9b7eeb1b1868554f937d109c0 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 20 Jun 2018 22:31:59 -0700 Subject: [PATCH 2249/2527] [FEAT RecordData] add feature flag to enable record-data at build time (#5498) * make flag configurable * fix flag lookup --- index.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 79ee357143c..25dad8beab5 100644 --- a/index.js +++ b/index.js @@ -84,9 +84,15 @@ module.exports = { }, config() { + let optionFlag = + this.app && + this.app.options && + this.app.options.emberData && + this.app.options.emberData.enableRecordDataRFCBuild; + return { emberData: { - enableRecordDataRFCBuild: USE_RECORD_DATA_RFC, + enableRecordDataRFCBuild: USE_RECORD_DATA_RFC || optionFlag || false, }, }; }, @@ -99,6 +105,7 @@ module.exports = { tree = this.debugTree(tree, 'input'); let babel = this.addons.find(addon => addon.name === 'ember-cli-babel'); + let config = this.config(); let treeWithVersion = merge([ tree, @@ -110,7 +117,7 @@ module.exports = { }); let withPrivate; - if (USE_RECORD_DATA_RFC) { + if (config.emberData.enableRecordDataRFCBuild) { withPrivate = new Funnel(tree, { srcDir: '-record-data-private', destDir: '-private', From c18fa41b66f2a83871fe151a81648ca568ea206c Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 25 Jun 2018 22:59:51 -0700 Subject: [PATCH 2250/2527] Refactor init setup into record-data (#5500) * refactor init setup into record-data * convert to passing in only modelDatas as much as possible * address @hjdivad feedback * fix build drift * make things right --- addon/-record-data-private/attr.js | 1 + .../system/model/internal-model.js | 121 +- .../system/model/model-data.js | 90 +- addon/-record-data-private/system/store.js | 30 + .../system/store/model-data-wrapper.js | 19 +- package.json | 4 +- tests/helpers/resolver.js | 14 +- .../adapter/json-api-adapter-test.js | 4 + .../inverse-relationships-test.js | 2 +- .../serializers/json-serializer-test.js | 5 +- yarn.lock | 3448 ++++++++--------- 11 files changed, 1726 insertions(+), 2012 deletions(-) diff --git a/addon/-record-data-private/attr.js b/addon/-record-data-private/attr.js index e2df4230ae3..b8352fd29df 100644 --- a/addon/-record-data-private/attr.js +++ b/addon/-record-data-private/attr.js @@ -118,6 +118,7 @@ export default function attr(type, options) { let meta = { type: type, isAttribute: true, + kind: 'attribute', options: options, }; diff --git a/addon/-record-data-private/system/model/internal-model.js b/addon/-record-data-private/system/model/internal-model.js index 568d052e643..c18c6f7ddbe 100644 --- a/addon/-record-data-private/system/model/internal-model.js +++ b/addon/-record-data-private/system/model/internal-model.js @@ -1,6 +1,6 @@ -import { A } from '@ember/array'; import { set, get } from '@ember/object'; import EmberError from '@ember/error'; +import { A } from '@ember/array'; import { setOwner } from '@ember/application'; import { run } from '@ember/runloop'; import RSVP, { Promise } from 'rsvp'; @@ -10,10 +10,10 @@ import { assert, inspect } from '@ember/debug'; import RootState from './states'; import Snapshot from '../snapshot'; import OrderedSet from '../ordered-set'; -import isArrayLike from '../is-array-like'; import ManyArray from '../many-array'; import { PromiseBelongsTo, PromiseManyArray } from '../promise-proxies'; import { getOwner } from '../../utils'; +import isArrayLike from '../is-array-like'; import { RecordReference, BelongsToReference, HasManyReference } from '../references'; @@ -232,11 +232,12 @@ export default class InternalModel { if (!this._record && !this._isDematerializing) { heimdall.increment(materializeRecord); let token = heimdall.start('InternalModel.getRecord'); + let { store } = this; // lookupFactory should really return an object that creates // instances with the injections applied let createOptions = { - store: this.store, + store, _internalModel: this, currentState: this.currentState, isError: this.isError, @@ -248,49 +249,46 @@ export default class InternalModel { `You passed '${properties}' as properties for record creation instead of an object.`, typeof properties === 'object' && properties !== null ); - let classFields = this.getFields(); - // TODO disentangle post-rebase - let relationships = this._modelData._relationships; - let propertyNames = Object.keys(properties); - - for (let i = 0; i < propertyNames.length; i++) { - let name = propertyNames[i]; - let fieldType = classFields.get(name); - let propertyValue = properties[name]; - - if (name === 'id') { - this.setId(propertyValue); - continue; - } - switch (fieldType) { - case 'attribute': - this.setDirtyAttribute(name, propertyValue); - break; - case 'belongsTo': - this.setDirtyBelongsTo(name, propertyValue); - relationships.get(name).setHasAnyRelationshipData(true); - relationships.get(name).setRelationshipIsEmpty(false); - break; - case 'hasMany': - this.setDirtyHasMany(name, propertyValue); - relationships.get(name).setHasAnyRelationshipData(true); - relationships.get(name).setRelationshipIsEmpty(false); - break; - default: - createOptions[name] = propertyValue; + if ('id' in properties) { + this.setId(properties.id); + } + + // convert relationship Records to ModelDatas before passing to ModelData + let defs = store._relationshipsDefinitionFor(this.modelName); + let keys = Object.keys(properties); + let relationshipValue; + + for (let i = 0; i < keys.length; i++) { + let prop = keys[i]; + let def = defs[prop]; + + if (def !== undefined) { + if (def.kind === 'hasMany') { + if (DEBUG) { + assertRecordsPassedToHasMany(properties[prop]); + } + relationshipValue = extractRecordDatasFromRecords(properties[prop]); + } else { + relationshipValue = extractRecordDataFromRecord(properties[prop]); + } + + properties[prop] = relationshipValue; } } } + let additionalCreateOptions = this._modelData._initRecordCreateOptions(properties); + Object.assign(createOptions, additionalCreateOptions); + if (setOwner) { // ensure that `getOwner(this)` works inside a model instance - setOwner(createOptions, getOwner(this.store)); + setOwner(createOptions, getOwner(store)); } else { - createOptions.container = this.store.container; + createOptions.container = store.container; } - this._record = this.store._modelFactoryFor(this.modelName).create(createOptions); + this._record = store._modelFactoryFor(this.modelName).create(createOptions); this._triggerDeferredTriggers(); heimdall.stop(token); @@ -299,10 +297,6 @@ export default class InternalModel { return this._record; } - getFields() { - return get(this.modelClass, 'fields'); - } - resetRecord() { this._record = null; this.isReloading = false; @@ -697,25 +691,14 @@ export default class InternalModel { } setDirtyHasMany(key, records) { - assert(`You must pass an array of records to set a hasMany relationship`, isArrayLike(records)); - assert( - `All elements of a hasMany relationship must be instances of DS.Model, you passed ${inspect( - records - )}`, - (function() { - return A(records).every(record => record.hasOwnProperty('_internalModel') === true); - })() - ); - - // TODO this seems like unnecessary churn - this._modelData.setDirtyHasMany( - key, - records.map(record => record.get('_internalModel._modelData').getResourceIdentifier()) - ); + assertRecordsPassedToHasMany(records); + return this._modelData.setDirtyHasMany(key, extractRecordDatasFromRecords(records)); } setDirtyBelongsTo(key, value) { - // TODO this seems like a digression from the pattern in setDirtyHasMany + if (value && !value.then) { + value = extractRecordDataFromRecord(value); + } return this._modelData.setDirtyBelongsTo(key, value); } @@ -1240,3 +1223,29 @@ export default class InternalModel { return reference; } } + +function assertRecordsPassedToHasMany(records) { + assert(`You must pass an array of records to set a hasMany relationship`, isArrayLike(records)); + assert( + `All elements of a hasMany relationship must be instances of DS.Model, you passed ${inspect( + records + )}`, + (function() { + return A(records).every(record => record.hasOwnProperty('_internalModel') === true); + })() + ); +} + +function extractRecordDatasFromRecords(records) { + return records.map(extractRecordDataFromRecord); +} + +function extractRecordDataFromRecord(recordOrPromiseProxy) { + // TODO @runspired async createRecord would resolve this issue + // we leak record promises to ModelData by necessity :'( + if (!recordOrPromiseProxy || (recordOrPromiseProxy && recordOrPromiseProxy.then)) { + return recordOrPromiseProxy; + } + + return recordOrPromiseProxy._internalModel._modelData; +} diff --git a/addon/-record-data-private/system/model/model-data.js b/addon/-record-data-private/system/model/model-data.js index ac677577dae..4b8aafe0d21 100644 --- a/addon/-record-data-private/system/model/model-data.js +++ b/addon/-record-data-private/system/model/model-data.js @@ -1,11 +1,11 @@ -import isEnabled from '../../features'; import { DEBUG } from '@glimmer/env'; -import Relationships from '../relationships/state/create'; import { assign } from '@ember/polyfills'; import { isEqual } from '@ember/utils'; import { assert, warn, inspect } from '@ember/debug'; -import coerceId from '../coerce-id'; import { run } from '@ember/runloop'; +import isEnabled from '../../features'; +import Relationships from '../relationships/state/create'; +import coerceId from '../coerce-id'; let nextBfsId = 1; export default class ModelData { @@ -246,31 +246,23 @@ export default class ModelData { } // get ResourceIdentifiers for "current state" - // TODO should this return ModelDatas for API consistency? getHasMany(key) { return this._relationships.get(key).getData(); } // set a new "current state" via ResourceIdentifiers - // TODO should this take in ModelDatas for API consistency? - setDirtyHasMany(key, resources) { + setDirtyHasMany(key, modelDatas) { let relationship = this._relationships.get(key); relationship.clear(); - relationship.addModelDatas( - resources.map(resource => - this.storeWrapper.modelDataFor(resource.type, resource.id, resource.clientId) - ) - ); + relationship.addModelDatas(modelDatas); } // append to "current state" via ModelDatas - // TODO should this take in ResourceIdentifiers for API consistency? addToHasMany(key, modelDatas, idx) { this._relationships.get(key).addModelDatas(modelDatas, idx); } // remove from "current state" via ModelDatas - // TODO should this take in ResourceIdentifiers for API consistency? removeFromHasMany(key, modelDatas) { this._relationships.get(key).removeModelDatas(modelDatas); } @@ -292,17 +284,15 @@ export default class ModelData { return this._relationships.get(key).getData(); } - setDirtyBelongsTo(key, value) { - if (value === undefined) { - value = null; + setDirtyBelongsTo(key, modelDataOrPromise) { + if (modelDataOrPromise === undefined) { + modelDataOrPromise = null; } - if (value && value.then) { - this._relationships.get(key).setRecordPromise(value); - } else if (value) { - this._relationships.get(key).setModelData(value._internalModel._modelData); + if (modelDataOrPromise && modelDataOrPromise.then) { + this._relationships.get(key).setRecordPromise(modelDataOrPromise); } else { - this._relationships.get(key).setModelData(value); + this._relationships.get(key).setModelData(modelDataOrPromise); } } @@ -514,6 +504,64 @@ export default class ModelData { this.__inFlightAttributes = v; } + /** + * Receives options passed to `store.createRecord` and is given the opportunity + * to handle them. + * + * The return value is an object of options to pass to `Record.create()` + * + * @param options + * @private + */ + _initRecordCreateOptions(options) { + let createOptions = {}; + + if (options !== undefined) { + let { modelName, storeWrapper } = this; + let attributeDefs = storeWrapper.attributesDefinitionFor(modelName); + let relationshipDefs = storeWrapper.relationshipsDefinitionFor(modelName); + let relationships = this._relationships; + let propertyNames = Object.keys(options); + + for (let i = 0; i < propertyNames.length; i++) { + let name = propertyNames[i]; + let propertyValue = options[name]; + + if (name === 'id') { + this.id = propertyValue; + continue; + } + + let fieldType = relationshipDefs[name] || attributeDefs[name]; + let kind = fieldType !== undefined ? fieldType.kind : null; + let relationship; + + switch (kind) { + case 'attribute': + this.setDirtyAttribute(name, propertyValue); + break; + case 'belongsTo': + this.setDirtyBelongsTo(name, propertyValue); + relationship = relationships.get(name); + relationship.setHasAnyRelationshipData(true); + relationship.setRelationshipIsEmpty(false); + break; + case 'hasMany': + this.setDirtyHasMany(name, propertyValue); + relationship = relationships.get(name); + relationship.setHasAnyRelationshipData(true); + relationship.setRelationshipIsEmpty(false); + break; + default: + // reflect back (pass-thru) unknown properties + createOptions[name] = propertyValue; + } + } + } + + return createOptions; + } + /* diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index 105ded43e56..fd255845a0e 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -199,6 +199,8 @@ Store = Service.extend({ this._newlyCreated = new IdentityMap(); this._pendingSave = []; this._modelFactoryCache = Object.create(null); + this._relationshipsDefCache = Object.create(null); + this._attributesDefCache = Object.create(null); /* Ember Data uses several specialized micro-queues for organizing @@ -2705,6 +2707,34 @@ Store = Service.extend({ return relationshipsByName.get(key); }, + _attributesDefinitionFor(modelName) { + let attributes = this._attributesDefCache[modelName]; + + if (attributes === undefined) { + let modelClass = this.modelFor(modelName); + let attributeMap = get(modelClass, 'attributes'); + + attributes = Object.create(null); + attributeMap.forEach((meta, name) => (attributes[name] = meta)); + this._attributesDefCache[modelName] = attributes; + } + + return attributes; + }, + + _relationshipsDefinitionFor(modelName) { + let relationships = this._relationshipsDefCache[modelName]; + + if (relationships === undefined) { + let modelClass = this.modelFor(modelName); + relationships = get(modelClass, 'relationshipsObject'); + + this._relationshipsDefCache[modelName] = relationships; + } + + return relationships; + }, + _internalModelForResource(resource) { let internalModel; if (resource.clientId) { diff --git a/addon/-record-data-private/system/store/model-data-wrapper.js b/addon/-record-data-private/system/store/model-data-wrapper.js index 0ddb9cf94aa..a92afe13bc7 100644 --- a/addon/-record-data-private/system/store/model-data-wrapper.js +++ b/addon/-record-data-private/system/store/model-data-wrapper.js @@ -1,10 +1,6 @@ -import { get } from '@ember/object'; - export default class ModelDataWrapper { constructor(store) { this.store = store; - this._relationshipsDefCache = Object.create(null); - this._attributesDefCache = Object.create(null); this._willUpdateManyArrays = false; this._pendingManyArrayUpdates = null; } @@ -46,22 +42,11 @@ export default class ModelDataWrapper { } attributesDefinitionFor(modelName) { - let attributes = this._attributesDefCache[modelName]; - if (attributes) { - return attributes; - } else { - // TODO IGOR DAVID - } + return this.store._attributesDefinitionFor(modelName); } relationshipsDefinitionFor(modelName) { - let relationships = this._relationshipsDefCache[modelName]; - if (!relationships) { - let modelClass = this.store.modelFor(modelName); - relationships = get(modelClass, 'relationshipsObject'); - this._relationshipsDefCache[modelName] = relationships; - } - return relationships; + return this.store._relationshipsDefinitionFor(modelName); } inverseForRelationship(modelName, key) { diff --git a/package.json b/package.json index ab4037a5c37..4a620c61162 100644 --- a/package.json +++ b/package.json @@ -107,14 +107,14 @@ "ember-watson": "^0.7.0", "eslint-config-prettier": "^2.9.0", "eslint-plugin-node": "^6.0.1", - "eslint-plugin-prettier": "^2.6.0", + "eslint-plugin-prettier": "2.6.0", "fs-extra": "^6.0.1", "github": "^1.1.1", "glob": "^5.0.13", "loader.js": "^4.5.0", "mocha": "^2.4.5", "mocha-only-detector": "0.0.2", - "prettier": "^1.12.1", + "prettier": "^1.13.6", "rimraf": "2.5.2", "rsvp": "4.8.0", "testdouble": "^3.2.6", diff --git a/tests/helpers/resolver.js b/tests/helpers/resolver.js index 319b45fc1c2..fa5d4579739 100644 --- a/tests/helpers/resolver.js +++ b/tests/helpers/resolver.js @@ -1,11 +1,9 @@ import Resolver from '../../resolver'; import config from '../../config/environment'; -const resolver = Resolver.create(); - -resolver.namespace = { - modulePrefix: config.modulePrefix, - podModulePrefix: config.podModulePrefix, -}; - -export default resolver; +export default Resolver.create({ + namespace: { + modulePrefix: config.modulePrefix, + podModulePrefix: config.podModulePrefix, + }, +}); diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index b74450b0a52..9c117d358bc 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -841,6 +841,8 @@ test('create record', function(assert) { return user.save().then(() => { assert.equal(passedUrl[0], '/users'); assert.equal(passedVerb[0], 'POST'); + + // TODO @runspired seems mega-bad that we expect an extra `data` key assert.deepEqual(passedHash[0], { data: { data: { @@ -915,6 +917,7 @@ test('update record', function(assert) { return user.save().then(() => { assert.equal(passedUrl[0], '/users/1'); assert.equal(passedVerb[0], 'PATCH'); + // TODO @runspired seems mega-bad that we expect an extra `data` key assert.deepEqual(passedHash[0], { data: { data: { @@ -999,6 +1002,7 @@ test('update record - serialize hasMany', function(assert) { return user.save().then(() => { assert.equal(passedUrl[0], '/users/1'); assert.equal(passedVerb[0], 'PATCH'); + // TODO @runspired seems mega-bad that we expect an extra `data` key assert.deepEqual(passedHash[0], { data: { data: { diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index 1c913b5e739..f7d5e944bd6 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -770,7 +770,7 @@ testInDebug( let env = setupStore({ user: User }); assert.expectAssertion(() => { - env.store.createRecord('user', { post: {} }); + env.store.createRecord('user', { post: null }); }, /No model was found for/); // but don't error if the relationship is not used diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index c0fb9acc751..bdec9fbc215 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -39,7 +39,10 @@ module('integration/serializer/json - JSONSerializer', { }); test("serialize doesn't include ID when includeId is false", function(assert) { - let post = env.store.createRecord('post', { title: 'Rails is omakase', comments: [] }); + let post = env.store.createRecord('post', { + title: 'Rails is omakase', + comments: [], + }); let json = serializer.serialize(post._createSnapshot(), { includeId: false }); assert.deepEqual(json, { diff --git a/yarn.lock b/yarn.lock index e04637e74de..fcaa5e2babe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -131,33 +131,33 @@ ember-compatibility-helpers "^1.0.0" "@ember/ordered-set@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@ember/ordered-set/-/ordered-set-1.0.0.tgz#cf9ab5fd7510bcad370370ebcded705f6d1c542b" + version "1.0.1" + resolved "https://registry.npmjs.org/@ember/ordered-set/-/ordered-set-1.0.1.tgz#f1a8c731168fb0ce25f868118ffef266ace29bac" dependencies: ember-cli-babel "6.12.0" - ember-compatibility-helpers "^1.0.0-beta.2" + ember-compatibility-helpers "^1.0.0" "@ember/test-helpers@^0.7.18": - version "0.7.18" - resolved "https://registry.yarnpkg.com/@ember/test-helpers/-/test-helpers-0.7.18.tgz#a0c474c3029588ec46d2e406252fc072b7f9aa3c" + version "0.7.25" + resolved "https://registry.npmjs.org/@ember/test-helpers/-/test-helpers-0.7.25.tgz#b4014c108b40ffaf74f3c4d5918800917541541d" dependencies: broccoli-funnel "^2.0.1" - ember-cli-babel "^6.10.0" + ember-cli-babel "^6.12.0" ember-cli-htmlbars-inline-precompile "^1.0.0" "@glimmer/di@^0.2.0": version "0.2.0" - resolved "https://registry.yarnpkg.com/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" + resolved "https://registry.npmjs.org/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" "@glimmer/resolver@^0.4.1": version "0.4.3" - resolved "https://registry.yarnpkg.com/@glimmer/resolver/-/resolver-0.4.3.tgz#b1baae5c3291b4621002ccf8d7870466097e841d" + resolved "https://registry.npmjs.org/@glimmer/resolver/-/resolver-0.4.3.tgz#b1baae5c3291b4621002ccf8d7870466097e841d" dependencies: "@glimmer/di" "^0.2.0" "@sindresorhus/is@^0.7.0": version "0.7.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" + resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" "@types/acorn@^4.0.3": version "4.0.3" @@ -174,23 +174,23 @@ resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.38.tgz#c1be40aa933723c608820a99a373a16d215a1ca2" "@types/node@^9.6.0": - version "9.6.12" - resolved "https://registry.npmjs.org/@types/node/-/node-9.6.12.tgz#ab2d716505858ebc8ee94b347b5c9d311eb81b72" + version "9.6.22" + resolved "https://registry.npmjs.org/@types/node/-/node-9.6.22.tgz#05b55093faaadedea7a4b3f76e9a61346a6dd209" abbrev@1: version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" accepts@1.3.3: version "1.3.3" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" dependencies: mime-types "~2.1.11" negotiator "0.6.1" -accepts@~1.3.4: +accepts@~1.3.4, accepts@~1.3.5: version "1.3.5" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" dependencies: mime-types "~2.1.18" negotiator "0.6.1" @@ -203,51 +203,40 @@ acorn-dynamic-import@^3.0.0: acorn-jsx@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" dependencies: acorn "^3.0.4" acorn@^3.0.4: version "3.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" - -acorn@^5.0.0, acorn@^5.5.3: - version "5.5.3" - resolved "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" + resolved "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" -acorn@^5.2.1, acorn@^5.5.0: - version "5.5.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.1.tgz#84e05a9ea0acbe131227da50301e62464dc9c1d8" +acorn@^5.0.0, acorn@^5.2.1, acorn@^5.5.0, acorn@^5.5.3: + version "5.7.1" + resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" after@0.8.1: version "0.8.1" - resolved "https://registry.yarnpkg.com/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" + resolved "https://registry.npmjs.org/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" after@0.8.2: version "0.8.2" - resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + resolved "https://registry.npmjs.org/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" agent-base@2: version "2.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" dependencies: extend "~3.0.0" semver "~5.0.1" ajv-keywords@^2.1.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" - -ajv@^4.9.1: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" - dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" + resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" ajv@^5.2.3, ajv@^5.3.0: version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + resolved "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" dependencies: co "^4.6.0" fast-deep-equal "^1.0.0" @@ -256,7 +245,7 @@ ajv@^5.2.3, ajv@^5.3.0: align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" - resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + resolved "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" dependencies: kind-of "^3.0.2" longest "^1.0.1" @@ -264,13 +253,13 @@ align-text@^0.1.1, align-text@^0.1.3: alter@~0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" + resolved "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" dependencies: stable "~0.1.3" amd-name-resolver@0.0.7: version "0.0.7" - resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-0.0.7.tgz#814301adfe8a2f109f6e84d5e935196efb669615" + resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.7.tgz#814301adfe8a2f109f6e84d5e935196efb669615" dependencies: ensure-posix-path "^1.0.1" @@ -282,193 +271,180 @@ amd-name-resolver@1.2.0, amd-name-resolver@^1.2.0: amdefine@>=0.0.4: version "1.0.1" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" ansi-escapes@^1.1.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" ansi-escapes@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" - -ansi-regex@^0.2.0, ansi-regex@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" ansi-regex@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" ansi-regex@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - -ansi-styles@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" ansi-styles@^2.2.1: version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" ansi-styles@^3.0.0, ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" dependencies: color-convert "^1.9.0" ansicolors@~0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" + resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" anymatch@^1.3.0: version "1.3.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" dependencies: micromatch "^2.1.5" normalize-path "^2.0.0" +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + aot-test-generators@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/aot-test-generators/-/aot-test-generators-0.1.0.tgz#43f0f615f97cb298d7919c1b0b4e6b7310b03cd0" + resolved "https://registry.npmjs.org/aot-test-generators/-/aot-test-generators-0.1.0.tgz#43f0f615f97cb298d7919c1b0b4e6b7310b03cd0" dependencies: jsesc "^2.5.0" aproba@^1.0.3: version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" are-we-there-yet@~1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + version "1.1.5" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" dependencies: delegates "^1.0.0" readable-stream "^2.0.6" argparse@^1.0.7, argparse@~1.0.2: version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" dependencies: sprintf-js "~1.0.2" arr-diff@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" dependencies: arr-flatten "^1.0.1" arr-diff@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" arr-union@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + resolved "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" array-equal@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + resolved "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" array-find-index@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + resolved "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" array-flatten@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" array-to-error@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" + resolved "https://registry.npmjs.org/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" dependencies: array-to-sentence "^1.1.0" array-to-sentence@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" + resolved "https://registry.npmjs.org/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" array-union@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" dependencies: array-uniq "^1.0.1" array-uniq@^1.0.1: version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" array-unique@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" array-unique@^0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" arraybuffer.slice@0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" + resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" arraybuffer.slice@~0.0.7: version "0.0.7" - resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" arrify@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" asn1@0.1.11: version "0.1.11" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" - -asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" assert-plus@^0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" - -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" assertion-error@^1.0.1: version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" assign-symbols@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" ast-traverse@~0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" + resolved "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" ast-types@0.8.12: version "0.8.12" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" ast-types@0.8.15: version "0.8.15" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" ast-types@0.9.6: version "0.9.6" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" async-disk-cache@^1.2.1: version "1.3.3" - resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.3.3.tgz#6040486660b370e4051cd9fa9fee275e1fae3728" + resolved "https://registry.npmjs.org/async-disk-cache/-/async-disk-cache-1.3.3.tgz#6040486660b370e4051cd9fa9fee275e1fae3728" dependencies: debug "^2.1.3" heimdalljs "^0.2.3" @@ -480,74 +456,62 @@ async-disk-cache@^1.2.1: async-each@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + resolved "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" async-limiter@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + resolved "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" async-promise-queue@^1.0.3, async-promise-queue@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/async-promise-queue/-/async-promise-queue-1.0.4.tgz#308baafbc74aff66a0bb6e7f4a18d4fe8434440c" + resolved "https://registry.npmjs.org/async-promise-queue/-/async-promise-queue-1.0.4.tgz#308baafbc74aff66a0bb6e7f4a18d4fe8434440c" dependencies: async "^2.4.1" debug "^2.6.8" async@^1.4.0, async@^1.5.2: version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" async@^2.4.1: - version "2.6.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" + version "2.6.1" + resolved "https://registry.npmjs.org/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" dependencies: - lodash "^4.14.0" + lodash "^4.17.10" async@~0.2.9: version "0.2.10" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + resolved "https://registry.npmjs.org/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" async@~0.9.0: version "0.9.2" - resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - -atob@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d" +atob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" aws-sdk@^2.0.9: - version "2.205.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.205.0.tgz#1a93730253e2be027a4bd3af9248cbda0573de80" + version "2.263.1" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.263.1.tgz#217e2459ebff3702cc72260bcafca0bf16edc4cd" dependencies: buffer "4.9.1" - events "^1.1.1" + events "1.1.1" + ieee754 "1.1.8" jmespath "0.15.0" querystring "0.2.0" sax "1.2.1" url "0.10.3" uuid "3.1.0" xml2js "0.4.17" - xmlbuilder "4.2.1" aws-sign2@~0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" - -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - -aws4@^1.2.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: chalk "^1.1.3" esutils "^2.0.2" @@ -555,7 +519,7 @@ babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: babel-core@^5.0.0, babel-core@^5.8.22: version "5.8.38" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" + resolved "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" dependencies: babel-plugin-constant-folding "^1.0.1" babel-plugin-dead-code-elimination "^1.0.2" @@ -604,9 +568,9 @@ babel-core@^5.0.0, babel-core@^5.8.22: trim-right "^1.0.0" try-resolve "^1.0.0" -babel-core@^6.14.0, babel-core@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" +babel-core@^6.26.0: + version "6.26.3" + resolved "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" dependencies: babel-code-frame "^6.26.0" babel-generator "^6.26.0" @@ -618,19 +582,19 @@ babel-core@^6.14.0, babel-core@^6.26.0: babel-traverse "^6.26.0" babel-types "^6.26.0" babylon "^6.18.0" - convert-source-map "^1.5.0" - debug "^2.6.8" + convert-source-map "^1.5.1" + debug "^2.6.9" json5 "^0.5.1" lodash "^4.17.4" minimatch "^3.0.4" path-is-absolute "^1.0.1" - private "^0.1.7" + private "^0.1.8" slash "^1.0.0" - source-map "^0.5.6" + source-map "^0.5.7" babel-eslint@^8.0.0: - version "8.2.3" - resolved "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.3.tgz#1a2e6681cc9bc4473c32899e59915e19cd6733cf" + version "8.2.5" + resolved "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.5.tgz#dc2331c259d36782aa189da510c43dedd5adc7a3" dependencies: "@babel/code-frame" "7.0.0-beta.44" "@babel/traverse" "7.0.0-beta.44" @@ -641,7 +605,7 @@ babel-eslint@^8.0.0: babel-generator@^6.26.0: version "6.26.1" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + resolved "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" dependencies: babel-messages "^6.23.0" babel-runtime "^6.26.0" @@ -654,7 +618,7 @@ babel-generator@^6.26.0: babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + resolved "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" dependencies: babel-helper-explode-assignable-expression "^6.24.1" babel-runtime "^6.22.0" @@ -662,7 +626,7 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: babel-helper-call-delegate@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + resolved "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" dependencies: babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" @@ -671,7 +635,7 @@ babel-helper-call-delegate@^6.24.1: babel-helper-define-map@^6.24.1: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + resolved "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.26.0" @@ -680,7 +644,7 @@ babel-helper-define-map@^6.24.1: babel-helper-explode-assignable-expression@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + resolved "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" dependencies: babel-runtime "^6.22.0" babel-traverse "^6.24.1" @@ -688,7 +652,7 @@ babel-helper-explode-assignable-expression@^6.24.1: babel-helper-function-name@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + resolved "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" dependencies: babel-helper-get-function-arity "^6.24.1" babel-runtime "^6.22.0" @@ -698,28 +662,28 @@ babel-helper-function-name@^6.24.1: babel-helper-get-function-arity@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + resolved "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-helper-hoist-variables@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + resolved "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-helper-optimise-call-expression@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + resolved "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-helper-regex@^6.24.1: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + resolved "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" dependencies: babel-runtime "^6.26.0" babel-types "^6.26.0" @@ -727,7 +691,7 @@ babel-helper-regex@^6.24.1: babel-helper-remap-async-to-generator@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + resolved "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" @@ -737,7 +701,7 @@ babel-helper-remap-async-to-generator@^6.24.1: babel-helper-replace-supers@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + resolved "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" dependencies: babel-helper-optimise-call-expression "^6.24.1" babel-messages "^6.23.0" @@ -748,110 +712,110 @@ babel-helper-replace-supers@^6.24.1: babel-helpers@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + resolved "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" babel-messages@^6.23.0: version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + resolved "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" dependencies: babel-runtime "^6.22.0" babel-plugin-check-es2015-constants@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + resolved "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" dependencies: babel-runtime "^6.22.0" babel-plugin-constant-folding@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" + resolved "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" babel-plugin-dead-code-elimination@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" + resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.11: version "0.1.11" - resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" + resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" dependencies: semver "^5.3.0" babel-plugin-ember-modules-api-polyfill@^1.4.2: version "1.6.0" - resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-1.6.0.tgz#abd1afa4237b3121cb51222f9bf3283cad8990aa" + resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-1.6.0.tgz#abd1afa4237b3121cb51222f9bf3283cad8990aa" dependencies: ember-rfc176-data "^0.2.0" babel-plugin-ember-modules-api-polyfill@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.3.0.tgz#0c01f359658cfb9c797f705af6b09f6220205ae0" + version "2.3.2" + resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.3.2.tgz#56ea34bea963498d070a2b7dc2ce18a92c434093" dependencies: ember-rfc176-data "^0.3.0" babel-plugin-eval@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" + resolved "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" babel-plugin-feature-flags@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" + resolved "https://registry.npmjs.org/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" babel-plugin-filter-imports@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.3.1.tgz#e7859b56886b175dd2616425d277b219e209ea8b" + resolved "https://registry.npmjs.org/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.3.1.tgz#e7859b56886b175dd2616425d277b219e209ea8b" -babel-plugin-htmlbars-inline-precompile@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.3.tgz#cd365e278af409bfa6be7704c4354beee742446b" +babel-plugin-htmlbars-inline-precompile@^0.2.3, babel-plugin-htmlbars-inline-precompile@^0.2.5: + version "0.2.5" + resolved "https://registry.npmjs.org/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.5.tgz#7a7c37cf22c73fb57a1f828c76520f0360c5c5f3" babel-plugin-inline-environment-variables@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" + resolved "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" babel-plugin-jscript@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" + resolved "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" babel-plugin-member-expression-literals@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" + resolved "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" babel-plugin-property-literals@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" + resolved "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" babel-plugin-proto-to-assign@^1.0.3: version "1.0.4" - resolved "https://registry.yarnpkg.com/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" + resolved "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" dependencies: lodash "^3.9.3" babel-plugin-react-constant-elements@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" + resolved "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" babel-plugin-react-display-name@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" + resolved "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" babel-plugin-remove-console@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" + resolved "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" babel-plugin-remove-debugger@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" + resolved "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" babel-plugin-runtime@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" + resolved "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + resolved "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" babel-plugin-syntax-class-properties@^6.8.0: version "6.13.0" @@ -863,15 +827,15 @@ babel-plugin-syntax-decorators@^6.1.18: babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + resolved "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + resolved "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" babel-plugin-transform-async-to-generator@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + resolved "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" dependencies: babel-helper-remap-async-to-generator "^6.24.1" babel-plugin-syntax-async-functions "^6.8.0" @@ -896,19 +860,19 @@ babel-plugin-transform-decorators-legacy@^1.3.4: babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" dependencies: babel-runtime "^6.26.0" babel-template "^6.26.0" @@ -918,7 +882,7 @@ babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es20 babel-plugin-transform-es2015-classes@^6.23.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" dependencies: babel-helper-define-map "^6.24.1" babel-helper-function-name "^6.24.1" @@ -932,39 +896,39 @@ babel-plugin-transform-es2015-classes@^6.23.0: babel-plugin-transform-es2015-computed-properties@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" babel-plugin-transform-es2015-constants@^6.1.4: version "6.1.4" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-constants/-/babel-plugin-transform-es2015-constants-6.1.4.tgz#e4b8c78fb48ab98b0107f329fab6040e79c35a33" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-constants/-/babel-plugin-transform-es2015-constants-6.1.4.tgz#e4b8c78fb48ab98b0107f329fab6040e79c35a33" dependencies: babel-runtime "^5.0.0" babel-plugin-transform-es2015-destructuring@^6.23.0: version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-duplicate-keys@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-plugin-transform-es2015-for-of@^6.23.0: version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-function-name@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" @@ -972,21 +936,21 @@ babel-plugin-transform-es2015-function-name@^6.22.0: babel-plugin-transform-es2015-literals@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" dependencies: babel-plugin-transform-es2015-modules-commonjs "^6.24.1" babel-runtime "^6.22.0" babel-template "^6.24.1" babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz#0d8394029b7dc6abe1a97ef181e00758dd2e5d8a" + version "6.26.2" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" dependencies: babel-plugin-transform-strict-mode "^6.24.1" babel-runtime "^6.26.0" @@ -995,7 +959,7 @@ babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-e babel-plugin-transform-es2015-modules-systemjs@^6.23.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" dependencies: babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" @@ -1003,7 +967,7 @@ babel-plugin-transform-es2015-modules-systemjs@^6.23.0: babel-plugin-transform-es2015-modules-umd@^6.23.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" dependencies: babel-plugin-transform-es2015-modules-amd "^6.24.1" babel-runtime "^6.22.0" @@ -1011,14 +975,14 @@ babel-plugin-transform-es2015-modules-umd@^6.23.0: babel-plugin-transform-es2015-object-super@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" dependencies: babel-helper-replace-supers "^6.24.1" babel-runtime "^6.22.0" babel-plugin-transform-es2015-parameters@^6.23.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" dependencies: babel-helper-call-delegate "^6.24.1" babel-helper-get-function-arity "^6.24.1" @@ -1029,20 +993,20 @@ babel-plugin-transform-es2015-parameters@^6.23.0: babel-plugin-transform-es2015-shorthand-properties@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-plugin-transform-es2015-spread@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-sticky-regex@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" dependencies: babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" @@ -1050,19 +1014,19 @@ babel-plugin-transform-es2015-sticky-regex@^6.22.0: babel-plugin-transform-es2015-template-literals@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-typeof-symbol@^6.23.0: version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-unicode-regex@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" dependencies: babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" @@ -1070,7 +1034,7 @@ babel-plugin-transform-es2015-unicode-regex@^6.22.0: babel-plugin-transform-exponentiation-operator@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + resolved "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" dependencies: babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" babel-plugin-syntax-exponentiation-operator "^6.8.0" @@ -1078,71 +1042,36 @@ babel-plugin-transform-exponentiation-operator@^6.22.0: babel-plugin-transform-regenerator@^6.22.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + resolved "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" dependencies: regenerator-transform "^0.10.0" babel-plugin-transform-strict-mode@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + resolved "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-plugin-undeclared-variables-check@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" + resolved "https://registry.npmjs.org/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" dependencies: leven "^1.0.2" babel-plugin-undefined-to-void@^1.1.6: version "1.1.6" - resolved "https://registry.yarnpkg.com/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" + resolved "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" babel-polyfill@^6.16.0, babel-polyfill@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + resolved "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" dependencies: babel-runtime "^6.26.0" core-js "^2.5.0" regenerator-runtime "^0.10.5" -babel-preset-env@^1.5.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48" - dependencies: - babel-plugin-check-es2015-constants "^6.22.0" - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-to-generator "^6.22.0" - babel-plugin-transform-es2015-arrow-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.23.0" - babel-plugin-transform-es2015-classes "^6.23.0" - babel-plugin-transform-es2015-computed-properties "^6.22.0" - babel-plugin-transform-es2015-destructuring "^6.23.0" - babel-plugin-transform-es2015-duplicate-keys "^6.22.0" - babel-plugin-transform-es2015-for-of "^6.23.0" - babel-plugin-transform-es2015-function-name "^6.22.0" - babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.22.0" - babel-plugin-transform-es2015-modules-commonjs "^6.23.0" - babel-plugin-transform-es2015-modules-systemjs "^6.23.0" - babel-plugin-transform-es2015-modules-umd "^6.23.0" - babel-plugin-transform-es2015-object-super "^6.22.0" - babel-plugin-transform-es2015-parameters "^6.23.0" - babel-plugin-transform-es2015-shorthand-properties "^6.22.0" - babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.22.0" - babel-plugin-transform-es2015-template-literals "^6.22.0" - babel-plugin-transform-es2015-typeof-symbol "^6.23.0" - babel-plugin-transform-es2015-unicode-regex "^6.22.0" - babel-plugin-transform-exponentiation-operator "^6.22.0" - babel-plugin-transform-regenerator "^6.22.0" - browserslist "^2.1.2" - invariant "^2.2.2" - semver "^5.3.0" - -babel-preset-env@^1.7.0: +babel-preset-env@^1.5.1, babel-preset-env@^1.7.0: version "1.7.0" resolved "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" dependencies: @@ -1179,7 +1108,7 @@ babel-preset-env@^1.7.0: babel-register@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + resolved "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" dependencies: babel-core "^6.26.0" babel-runtime "^6.26.0" @@ -1191,20 +1120,20 @@ babel-register@^6.26.0: babel-runtime@^5.0.0: version "5.8.38" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-5.8.38.tgz#1c0b02eb63312f5f087ff20450827b425c9d4c19" + resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz#1c0b02eb63312f5f087ff20450827b425c9d4c19" dependencies: core-js "^1.0.0" babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: core-js "^2.4.0" regenerator-runtime "^0.11.0" babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + resolved "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" dependencies: babel-runtime "^6.26.0" babel-traverse "^6.26.0" @@ -1214,7 +1143,7 @@ babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + resolved "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" dependencies: babel-code-frame "^6.26.0" babel-messages "^6.23.0" @@ -1228,7 +1157,7 @@ babel-traverse@^6.24.1, babel-traverse@^6.26.0: babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + resolved "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" dependencies: babel-runtime "^6.26.0" esutils "^2.0.2" @@ -1237,11 +1166,11 @@ babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: babel6-plugin-strip-class-callcheck@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" + resolved "https://registry.npmjs.org/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" babel6-plugin-strip-heimdall@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" + resolved "https://registry.npmjs.org/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" babylon@7.0.0-beta.44: version "7.0.0-beta.44" @@ -1249,45 +1178,45 @@ babylon@7.0.0-beta.44: babylon@^5.8.38: version "5.8.38" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" + resolved "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" babylon@^6.18.0: version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" backbone@^1.1.2: version "1.3.3" - resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" + resolved "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" dependencies: underscore ">=1.8.3" backo2@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" balanced-match@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" base64-arraybuffer@0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" base64-js@^1.0.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.3.tgz#fb13668233d9614cf5fb4bce95a9ba4096cdf801" + version "1.3.0" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" base64id@0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" + resolved "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" base64id@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + resolved "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" base@^0.11.1: version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" dependencies: cache-base "^1.0.1" class-utils "^0.3.5" @@ -1299,55 +1228,43 @@ base@^0.11.1: basic-auth@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.0.tgz#015db3f353e02e56377755f962742e8981e7bbba" + resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz#015db3f353e02e56377755f962742e8981e7bbba" dependencies: safe-buffer "5.1.1" -bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - dependencies: - tweetnacl "^0.14.3" - better-assert@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + resolved "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" dependencies: callsite "1.0.0" binary-extensions@^1.0.0: version "1.11.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" "binaryextensions@1 || 2": version "2.1.1" - resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" + resolved "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" blank-object@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" + resolved "https://registry.npmjs.org/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" blob@0.0.4: version "0.0.4" - resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" - -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - dependencies: - inherits "~2.0.0" + resolved "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" bluebird@^2.9.33: version "2.11.0" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" bluebird@^3.1.1, bluebird@^3.4.6: version "3.5.1" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" body-parser@1.18.2: version "1.18.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" dependencies: bytes "3.0.0" content-type "~1.0.4" @@ -1362,7 +1279,7 @@ body-parser@1.18.2: body@^5.1.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" + resolved "https://registry.npmjs.org/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" dependencies: continuable-cache "^0.3.1" error "^7.0.0" @@ -1371,19 +1288,13 @@ body@^5.1.0: boom@0.4.x: version "0.4.2" - resolved "https://registry.yarnpkg.com/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" + resolved "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" dependencies: hoek "0.9.x" -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - dependencies: - hoek "2.x.x" - bower-config@^1.3.0: version "1.4.1" - resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc" + resolved "https://registry.npmjs.org/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc" dependencies: graceful-fs "^4.1.3" mout "^1.0.0" @@ -1393,34 +1304,32 @@ bower-config@^1.3.0: bower-endpoint-parser@0.2.2: version "0.2.2" - resolved "https://registry.yarnpkg.com/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" + resolved "https://registry.npmjs.org/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" brace-expansion@^1.0.0, brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" dependencies: balanced-match "^1.0.0" concat-map "0.0.1" braces@^1.8.2: version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + resolved "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" dependencies: expand-range "^1.8.1" preserve "^0.2.0" repeat-element "^1.1.2" braces@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.1.tgz#7086c913b4e5a08dbe37ac0ee6a2500c4ba691bb" + version "2.3.2" + resolved "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" dependencies: arr-flatten "^1.1.0" array-unique "^0.3.2" - define-property "^1.0.0" extend-shallow "^2.0.1" fill-range "^4.0.0" isobject "^3.0.1" - kind-of "^6.0.2" repeat-element "^1.1.2" snapdragon "^0.8.1" snapdragon-node "^2.0.1" @@ -1429,27 +1338,28 @@ braces@^2.3.1: breakable@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" + resolved "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" broccoli-asset-rev@^2.4.5: - version "2.6.0" - resolved "https://registry.yarnpkg.com/broccoli-asset-rev/-/broccoli-asset-rev-2.6.0.tgz#0633fc3a0b2ba0c2c1d56fa9feb7b331fc83be6d" + version "2.7.0" + resolved "https://registry.npmjs.org/broccoli-asset-rev/-/broccoli-asset-rev-2.7.0.tgz#c73da1d97c4180366fa442a87624ca1b7fb99161" dependencies: broccoli-asset-rewrite "^1.1.0" broccoli-filter "^1.2.2" + broccoli-persistent-filter "^1.4.3" json-stable-stringify "^1.0.0" minimatch "^3.0.4" rsvp "^3.0.6" broccoli-asset-rewrite@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" + resolved "https://registry.npmjs.org/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" dependencies: broccoli-filter "^1.2.3" broccoli-babel-transpiler@^5.6.2: version "5.7.4" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.4.tgz#2b0611ce9e5d98b8d8d2b49ae1219af2f52767e3" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.4.tgz#2b0611ce9e5d98b8d8d2b49ae1219af2f52767e3" dependencies: babel-core "^5.0.0" broccoli-funnel "^1.0.0" @@ -1462,22 +1372,7 @@ broccoli-babel-transpiler@^5.6.2: rsvp "^3.5.0" workerpool "^2.3.0" -broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2: - version "6.1.4" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.1.4.tgz#8be8074c42abf2e17ff79b2d2a21df5c51143c82" - dependencies: - babel-core "^6.14.0" - broccoli-funnel "^1.0.0" - broccoli-merge-trees "^1.0.0" - broccoli-persistent-filter "^1.4.0" - clone "^2.0.0" - hash-for-dep "^1.0.2" - heimdalljs-logger "^0.1.7" - json-stable-stringify "^1.0.0" - rsvp "^3.5.0" - workerpool "^2.3.0" - -broccoli-babel-transpiler@^6.4.2: +broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2, broccoli-babel-transpiler@^6.4.2: version "6.4.3" resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.4.3.tgz#06e399298d41700cdc10d675b1d808a89ef6b2d0" dependencies: @@ -1493,9 +1388,10 @@ broccoli-babel-transpiler@^6.4.2: workerpool "^2.3.0" broccoli-builder@^0.18.8: - version "0.18.11" - resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.11.tgz#a42393c7b10bb0380df255a616307945f5e26efb" + version "0.18.14" + resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.14.tgz#4b79e2f844de11a4e1b816c3f49c6df4776c312d" dependencies: + broccoli-node-info "^1.1.0" heimdalljs "^0.2.0" promise-map-series "^0.2.1" quick-temp "^0.1.2" @@ -1505,7 +1401,7 @@ broccoli-builder@^0.18.8: broccoli-caching-writer@^2.2.0: version "2.3.1" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" @@ -1516,7 +1412,7 @@ broccoli-caching-writer@^2.2.0: broccoli-caching-writer@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.1" @@ -1527,7 +1423,7 @@ broccoli-caching-writer@^3.0.3: broccoli-clean-css@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" + resolved "https://registry.npmjs.org/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" dependencies: broccoli-persistent-filter "^1.1.6" clean-css-promise "^0.1.0" @@ -1536,7 +1432,7 @@ broccoli-clean-css@^1.1.0: broccoli-concat@^3.2.2: version "3.2.2" - resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" + resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.3.0" @@ -1553,13 +1449,13 @@ broccoli-concat@^3.2.2: broccoli-config-loader@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/broccoli-config-loader/-/broccoli-config-loader-1.0.1.tgz#d10aaf8ebc0cb45c1da5baa82720e1d88d28c80a" + resolved "https://registry.npmjs.org/broccoli-config-loader/-/broccoli-config-loader-1.0.1.tgz#d10aaf8ebc0cb45c1da5baa82720e1d88d28c80a" dependencies: broccoli-caching-writer "^3.0.3" broccoli-config-replace@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" + resolved "https://registry.npmjs.org/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.0" @@ -1568,7 +1464,7 @@ broccoli-config-replace@^1.1.2: broccoli-debug@^0.6.1, broccoli-debug@^0.6.2, broccoli-debug@^0.6.3, broccoli-debug@^0.6.4: version "0.6.4" - resolved "https://registry.yarnpkg.com/broccoli-debug/-/broccoli-debug-0.6.4.tgz#986eb3d2005e00e3bb91f9d0a10ab137210cd150" + resolved "https://registry.npmjs.org/broccoli-debug/-/broccoli-debug-0.6.4.tgz#986eb3d2005e00e3bb91f9d0a10ab137210cd150" dependencies: broccoli-plugin "^1.2.1" fs-tree-diff "^0.5.2" @@ -1578,19 +1474,15 @@ broccoli-debug@^0.6.1, broccoli-debug@^0.6.2, broccoli-debug@^0.6.3, broccoli-de tree-sync "^1.2.2" broccoli-file-creator@^1.0.0, broccoli-file-creator@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-1.1.1.tgz#1b35b67d215abdfadd8d49eeb69493c39e6c3450" + version "1.2.0" + resolved "https://registry.npmjs.org/broccoli-file-creator/-/broccoli-file-creator-1.2.0.tgz#27f1b25b1b00e7bb7bf3d5d7abed5f4d5388df4d" dependencies: - broccoli-kitchen-sink-helpers "~0.2.0" broccoli-plugin "^1.1.0" - broccoli-writer "~0.1.1" mkdirp "^0.5.1" - rsvp "~3.0.6" - symlink-or-copy "^1.0.1" broccoli-filter@^1.0.1, broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: version "1.3.0" - resolved "https://registry.yarnpkg.com/broccoli-filter/-/broccoli-filter-1.3.0.tgz#71e3a8e32a17f309e12261919c5b1006d6766de6" + resolved "https://registry.npmjs.org/broccoli-filter/-/broccoli-filter-1.3.0.tgz#71e3a8e32a17f309e12261919c5b1006d6766de6" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.0.0" @@ -1604,11 +1496,11 @@ broccoli-filter@^1.0.1, broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: broccoli-funnel-reducer@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" + resolved "https://registry.npmjs.org/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.1.0, broccoli-funnel@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" + resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" dependencies: array-equal "^1.0.0" blank-object "^1.0.1" @@ -1627,7 +1519,7 @@ broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.1.0, broccoli broccoli-funnel@^2.0.0, broccoli-funnel@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-2.0.1.tgz#6823c73b675ef78fffa7ab800f083e768b51d449" + resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-2.0.1.tgz#6823c73b675ef78fffa7ab800f083e768b51d449" dependencies: array-equal "^1.0.0" blank-object "^1.0.1" @@ -1643,23 +1535,23 @@ broccoli-funnel@^2.0.0, broccoli-funnel@^2.0.1: symlink-or-copy "^1.0.0" walk-sync "^0.3.1" -broccoli-kitchen-sink-helpers@^0.2.5, broccoli-kitchen-sink-helpers@~0.2.0: +broccoli-kitchen-sink-helpers@^0.2.5: version "0.2.9" - resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" + resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" dependencies: glob "^5.0.10" mkdirp "^0.5.1" broccoli-kitchen-sink-helpers@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" + resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" dependencies: glob "^5.0.10" mkdirp "^0.5.1" broccoli-lint-eslint@^4.2.1: version "4.2.1" - resolved "https://registry.yarnpkg.com/broccoli-lint-eslint/-/broccoli-lint-eslint-4.2.1.tgz#f780dc083a7357a9746a9cfa8f76feb092777477" + resolved "https://registry.npmjs.org/broccoli-lint-eslint/-/broccoli-lint-eslint-4.2.1.tgz#f780dc083a7357a9746a9cfa8f76feb092777477" dependencies: aot-test-generators "^0.1.0" broccoli-concat "^3.2.2" @@ -1671,7 +1563,7 @@ broccoli-lint-eslint@^4.2.1: broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.2.1: version "1.2.4" - resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" + resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" dependencies: broccoli-plugin "^1.3.0" can-symlink "^1.0.0" @@ -1684,25 +1576,25 @@ broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.2.1: broccoli-merge-trees@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-2.0.0.tgz#10aea46dd5cebcc8b8f7d5a54f0a84a4f0bb90b9" + resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-2.0.0.tgz#10aea46dd5cebcc8b8f7d5a54f0a84a4f0bb90b9" dependencies: broccoli-plugin "^1.3.0" merge-trees "^1.0.1" broccoli-middleware@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-1.2.1.tgz#a21f255f8bfe5a21c2f0fbf2417addd9d24c9436" + resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-1.2.1.tgz#a21f255f8bfe5a21c2f0fbf2417addd9d24c9436" dependencies: handlebars "^4.0.4" mime-types "^2.1.18" -broccoli-node-info@1.1.0: +broccoli-node-info@1.1.0, broccoli-node-info@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" + resolved "https://registry.npmjs.org/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" -broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.4.0, broccoli-persistent-filter@^1.4.2, broccoli-persistent-filter@^1.4.3: +broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.4.2, broccoli-persistent-filter@^1.4.3: version "1.4.3" - resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz#3511bc52fc53740cda51621f58a28152d9911bc1" + resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz#3511bc52fc53740cda51621f58a28152d9911bc1" dependencies: async-disk-cache "^1.2.1" async-promise-queue "^1.0.3" @@ -1720,7 +1612,7 @@ broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-p broccoli-plugin@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" + resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -1729,7 +1621,7 @@ broccoli-plugin@1.1.0: broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" + resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -1737,8 +1629,8 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli symlink-or-copy "^1.1.8" broccoli-rollup@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/broccoli-rollup/-/broccoli-rollup-2.1.0.tgz#94d703625c24dbad2e57789508f63ccfcbb13c00" + version "2.1.1" + resolved "https://registry.npmjs.org/broccoli-rollup/-/broccoli-rollup-2.1.1.tgz#0b77dc4b7560a53e998ea85f3b56772612d4988d" dependencies: "@types/node" "^9.6.0" amd-name-resolver "^1.2.0" @@ -1754,21 +1646,21 @@ broccoli-rollup@^2.1.0: broccoli-slow-trees@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-2.0.0.tgz#9741afe992787add64aec7f7c8211dfcc058278d" + resolved "https://registry.npmjs.org/broccoli-slow-trees/-/broccoli-slow-trees-2.0.0.tgz#9741afe992787add64aec7f7c8211dfcc058278d" broccoli-slow-trees@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" + resolved "https://registry.npmjs.org/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" dependencies: heimdalljs "^0.2.1" broccoli-source@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" + resolved "https://registry.npmjs.org/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" broccoli-sri-hash@^2.1.0: version "2.1.2" - resolved "https://registry.yarnpkg.com/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" + resolved "https://registry.npmjs.org/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" dependencies: broccoli-caching-writer "^2.2.0" mkdirp "^0.5.1" @@ -1778,7 +1670,7 @@ broccoli-sri-hash@^2.1.0: broccoli-stew@^1.2.0, broccoli-stew@^1.3.3, broccoli-stew@^1.4.2: version "1.5.0" - resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-1.5.0.tgz#d7af8c18511dce510e49d308a62e5977f461883c" + resolved "https://registry.npmjs.org/broccoli-stew/-/broccoli-stew-1.5.0.tgz#d7af8c18511dce510e49d308a62e5977f461883c" dependencies: broccoli-debug "^0.6.1" broccoli-funnel "^1.0.1" @@ -1797,14 +1689,14 @@ broccoli-stew@^1.2.0, broccoli-stew@^1.3.3, broccoli-stew@^1.4.2: broccoli-string-replace@^0.1.1: version "0.1.2" - resolved "https://registry.yarnpkg.com/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" + resolved "https://registry.npmjs.org/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" dependencies: broccoli-persistent-filter "^1.1.5" minimatch "^3.0.3" broccoli-test-helper@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/broccoli-test-helper/-/broccoli-test-helper-1.2.0.tgz#d01005d8611fd73ebe1b29552bf052ff59badfb4" + version "1.3.0" + resolved "https://registry.npmjs.org/broccoli-test-helper/-/broccoli-test-helper-1.3.0.tgz#ba673418b3963b2cc466be66092a5928700c827f" dependencies: broccoli "^1.1.0" fixturify "^0.3.2" @@ -1815,7 +1707,7 @@ broccoli-test-helper@^1.2.0: broccoli-uglify-sourcemap@^1.0.1: version "1.5.2" - resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.2.tgz#04f84ab0db539031fa868ccfa563c9932d50cedb" + resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.2.tgz#04f84ab0db539031fa868ccfa563c9932d50cedb" dependencies: broccoli-plugin "^1.2.1" debug "^2.2.0" @@ -1828,8 +1720,8 @@ broccoli-uglify-sourcemap@^1.0.1: walk-sync "^0.1.3" broccoli-uglify-sourcemap@^2.0.0-beta.1: - version "2.1.1" - resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-2.1.1.tgz#33005537e18a322a181a5aea3e46d145b3355630" + version "2.2.0" + resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-2.2.0.tgz#2ff49389bdf342a550c3596750ba2dde95a8f7d4" dependencies: async-promise-queue "^1.0.4" broccoli-plugin "^1.2.1" @@ -1839,20 +1731,13 @@ broccoli-uglify-sourcemap@^2.0.0-beta.1: mkdirp "^0.5.0" source-map-url "^0.4.0" symlink-or-copy "^1.0.1" - uglify-es "^3.1.3" + terser "^3.7.5" walk-sync "^0.3.2" workerpool "^2.3.0" -broccoli-writer@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/broccoli-writer/-/broccoli-writer-0.1.1.tgz#d4d71aa8f2afbc67a3866b91a2da79084b96ab2d" - dependencies: - quick-temp "^0.1.0" - rsvp "^3.0.6" - broccoli-yuidoc@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/broccoli-yuidoc/-/broccoli-yuidoc-3.0.0.tgz#e436588ddfb6ae81ce82d87e894333d0fdd10487" + resolved "https://registry.npmjs.org/broccoli-yuidoc/-/broccoli-yuidoc-3.0.0.tgz#e436588ddfb6ae81ce82d87e894333d0fdd10487" dependencies: broccoli-caching-writer "^3.0.3" broccoli-merge-trees "^2.0.0" @@ -1862,7 +1747,7 @@ broccoli-yuidoc@^3.0.0: broccoli@^1.1.0: version "1.1.4" - resolved "https://registry.yarnpkg.com/broccoli/-/broccoli-1.1.4.tgz#b023b028b866f447ed14341007961efd03f7251c" + resolved "https://registry.npmjs.org/broccoli/-/broccoli-1.1.4.tgz#b023b028b866f447ed14341007961efd03f7251c" dependencies: broccoli-node-info "1.1.0" broccoli-slow-trees "2.0.0" @@ -1880,13 +1765,6 @@ broccoli@^1.1.0: tmp "0.0.31" underscore.string "^3.2.2" -browserslist@^2.1.2: - version "2.11.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.11.3.tgz#fe36167aed1bbcde4827ebfe71347a2cc70b99b2" - dependencies: - caniuse-lite "^1.0.30000792" - electron-to-chromium "^1.3.30" - browserslist@^3.2.6: version "3.2.8" resolved "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" @@ -1896,17 +1774,17 @@ browserslist@^3.2.6: bser@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" + resolved "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" dependencies: node-int64 "^0.4.0" buffer-from@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" + version "1.1.0" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" buffer@4.9.1: version "4.9.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -1918,19 +1796,19 @@ builtin-modules@^1.0.0: builtins@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + resolved "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" bytes@1: version "1.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" + resolved "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" bytes@3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" cache-base@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" dependencies: collection-visit "^1.0.0" component-emitter "^1.2.1" @@ -1944,7 +1822,7 @@ cache-base@^1.0.1: cacheable-request@^2.1.1: version "2.1.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" + resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" dependencies: clone-response "1.0.2" get-stream "3.0.0" @@ -1956,98 +1834,90 @@ cacheable-request@^2.1.1: calculate-cache-key-for-tree@^1.0.0, calculate-cache-key-for-tree@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" + resolved "https://registry.npmjs.org/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" dependencies: json-stable-stringify "^1.0.1" caller-path@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + resolved "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" dependencies: callsites "^0.2.0" callsite@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + resolved "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" callsites@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + resolved "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" camelcase-keys@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" dependencies: camelcase "^2.0.0" map-obj "^1.0.0" camelcase@^1.0.2, camelcase@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" camelcase@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" can-symlink@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" + resolved "https://registry.npmjs.org/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" dependencies: tmp "0.0.28" -caniuse-lite@^1.0.30000792: - version "1.0.30000813" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000813.tgz#7b25e27fdfb8d133f3c932b01f77452140fcc6c9" - caniuse-lite@^1.0.30000844: - version "1.0.30000855" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000855.tgz#d5a26a9093b932d6266bf4ed9294b41b84945d14" + version "1.0.30000858" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000858.tgz#f6f203a9128bac507136de1cf6cfd966d2df027c" -capture-exit@^1.1.0: +capture-exit@^1.1.0, capture-exit@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" + resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" dependencies: rsvp "^3.3.3" cardinal@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" + resolved "https://registry.npmjs.org/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" dependencies: ansicolors "~0.2.1" redeyed "~1.0.0" -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - center-align@^0.1.1: version "0.1.3" - resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + resolved "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" dependencies: align-text "^0.1.3" lazy-cache "^1.0.3" chai-as-promised@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" + resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" dependencies: check-error "^1.0.2" chai-as-promised@^7.0.0: version "7.1.1" - resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" + resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" dependencies: check-error "^1.0.2" chai-files@^1.0.0, chai-files@^1.1.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" + resolved "https://registry.npmjs.org/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" dependencies: assertion-error "^1.0.1" chai@^3.3.0: version "3.5.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" + resolved "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" dependencies: assertion-error "^1.0.1" deep-eql "^0.1.3" @@ -2055,7 +1925,7 @@ chai@^3.3.0: chai@^4.1.0: version "4.1.2" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c" + resolved "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c" dependencies: assertion-error "^1.0.1" check-error "^1.0.1" @@ -2064,19 +1934,9 @@ chai@^4.1.0: pathval "^1.0.0" type-detect "^4.0.0" -chalk@^0.5.1: - version "0.5.1" - resolved "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" - dependencies: - ansi-styles "^1.1.0" - escape-string-regexp "^1.0.0" - has-ansi "^0.1.0" - strip-ansi "^0.3.0" - supports-color "^0.2.0" - chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -2084,9 +1944,9 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1: + version "2.4.1" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" @@ -2094,21 +1954,21 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1: chardet@^0.4.0: version "0.4.2" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + resolved "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" charm@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" + resolved "https://registry.npmjs.org/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" dependencies: inherits "^2.0.1" check-error@^1.0.1, check-error@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" chokidar@1.7.0: version "1.7.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" dependencies: anymatch "^1.3.0" async-each "^1.0.0" @@ -2121,13 +1981,17 @@ chokidar@1.7.0: optionalDependencies: fsevents "^1.0.0" +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + circular-json@^0.3.1: version "0.3.3" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" + resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" class-utils@^0.3.5: version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" dependencies: arr-union "^3.1.0" define-property "^0.2.5" @@ -2136,11 +2000,11 @@ class-utils@^0.3.5: clean-base-url@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" + resolved "https://registry.npmjs.org/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" clean-css-promise@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" + resolved "https://registry.npmjs.org/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" dependencies: array-to-error "^1.0.0" clean-css "^3.4.5" @@ -2148,30 +2012,30 @@ clean-css-promise@^0.1.0: clean-css@^3.4.5: version "3.4.28" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" + resolved "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" dependencies: commander "2.8.x" source-map "0.4.x" cli-cursor@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" dependencies: restore-cursor "^1.0.1" cli-cursor@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: restore-cursor "^2.0.0" cli-spinners@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.1.0.tgz#f1847b168844d917a671eb9d147e3df497c90d06" + version "1.3.1" + resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" cli-table2@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" + resolved "https://registry.npmjs.org/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" dependencies: lodash "^3.10.1" string-width "^1.0.1" @@ -2180,17 +2044,17 @@ cli-table2@^0.2.0: cli-table@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + resolved "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" dependencies: colors "1.0.3" cli-width@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" cliui@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + resolved "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" dependencies: center-align "^0.1.1" right-align "^0.1.1" @@ -2198,102 +2062,94 @@ cliui@^2.1.0: clone-response@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" dependencies: mimic-response "^1.0.0" clone@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" + resolved "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" clone@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f" + version "1.0.4" + resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" clone@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" + resolved "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" co@^4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" code-point-at@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" collection-visit@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + resolved "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" dependencies: map-visit "^1.0.0" object-visit "^1.0.0" color-convert@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" + version "1.9.2" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" dependencies: - color-name "^1.1.1" + color-name "1.1.1" -color-name@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" +color-name@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" colors@1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" colors@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" - -combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" - dependencies: - delayed-stream "~1.0.0" + version "1.3.0" + resolved "https://registry.npmjs.org/colors/-/colors-1.3.0.tgz#5f20c9fef6945cb1134260aab33bfbdc8295e04e" combined-stream@~0.0.4: version "0.0.7" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" dependencies: delayed-stream "0.0.5" commander@0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" + resolved "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" commander@2.12.2: version "2.12.2" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" + resolved "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" commander@2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" + resolved "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" commander@2.8.x: version "2.8.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + resolved "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" dependencies: graceful-readlink ">= 1.0.0" commander@^2.5.0, commander@^2.6.0: - version "2.14.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" + version "2.15.1" + resolved "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" -commander@~2.13.0: - version "2.13.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" +commander@~2.14.1: + version "2.14.1" + resolved "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" common-tags@^1.4.0: - version "1.7.2" - resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.7.2.tgz#24d9768c63d253a56ecff93845b44b4df1d52771" - dependencies: - babel-runtime "^6.26.0" + version "1.8.0" + resolved "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" commoner@~0.10.3: version "0.10.8" - resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" + resolved "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" dependencies: commander "^2.5.0" detective "^4.3.1" @@ -2307,29 +2163,29 @@ commoner@~0.10.3: component-bind@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + resolved "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" component-emitter@1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" + resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" component-emitter@1.2.1, component-emitter@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" component-inherit@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + resolved "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" compressible@~2.0.13: - version "2.0.13" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.13.tgz#0d1020ab924b2fdb4d6279875c7d6daba6baa7a9" + version "2.0.14" + resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7" dependencies: - mime-db ">= 1.33.0 < 2" + mime-db ">= 1.34.0 < 2" compression@^1.4.4: version "1.7.2" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.2.tgz#aaffbcd6aaf854b44ebb280353d5ad1651f59a69" + resolved "http://registry.npmjs.org/compression/-/compression-1.7.2.tgz#aaffbcd6aaf854b44ebb280353d5ad1651f59a69" dependencies: accepts "~1.3.4" bytes "3.0.0" @@ -2341,19 +2197,11 @@ compression@^1.4.4: concat-map@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.7: - version "1.6.1" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.1.tgz#261b8f518301f1d834e36342b9fea095d2620a26" - dependencies: - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -concat-stream@^1.6.0: +concat-stream@^1.4.7, concat-stream@^1.6.0: version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" dependencies: buffer-from "^1.0.0" inherits "^2.0.3" @@ -2362,7 +2210,7 @@ concat-stream@^1.6.0: configstore@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" + resolved "https://registry.npmjs.org/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" dependencies: dot-prop "^3.0.0" graceful-fs "^4.1.2" @@ -2375,8 +2223,8 @@ configstore@^2.0.0: xdg-basedir "^2.0.0" configstore@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.1.tgz#094ee662ab83fad9917678de114faaea8fcdca90" + version "3.1.2" + resolved "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" dependencies: dot-prop "^4.1.0" graceful-fs "^4.1.2" @@ -2387,7 +2235,7 @@ configstore@^3.0.0: connect@^3.3.3: version "3.6.6" - resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" + resolved "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" dependencies: debug "2.6.9" finalhandler "1.1.0" @@ -2396,7 +2244,7 @@ connect@^3.3.3: console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" console-ui@^2.1.0: version "2.2.2" @@ -2411,7 +2259,7 @@ console-ui@^2.1.0: consolidate@^0.14.0: version "0.14.5" - resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" + resolved "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" dependencies: bluebird "^3.1.1" @@ -2423,57 +2271,57 @@ consolidate@^0.15.1: content-disposition@0.5.2: version "0.5.2" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" content-type@~1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" continuable-cache@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" + resolved "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" -convert-source-map@^1.1.0, convert-source-map@^1.5.0: +convert-source-map@^1.1.0, convert-source-map@^1.5.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" cookie-signature@1.0.6: version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" cookie@0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" copy-dereference@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" + resolved "https://registry.npmjs.org/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" copy-descriptor@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" core-js@^1.0.0: version "1.2.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + resolved "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" core-js@^2.4.0, core-js@^2.5.0: - version "2.5.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" + version "2.5.7" + resolved "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" core-object@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" + resolved "https://registry.npmjs.org/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" core-object@^3.1.3: version "3.1.5" - resolved "https://registry.yarnpkg.com/core-object/-/core-object-3.1.5.tgz#fa627b87502adc98045e44678e9a8ec3b9c0d2a9" + resolved "https://registry.npmjs.org/core-object/-/core-object-3.1.5.tgz#fa627b87502adc98045e44678e9a8ec3b9c0d2a9" dependencies: chalk "^2.0.0" -core-util-is@1.0.2, core-util-is@~1.0.0: +core-util-is@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" @@ -2485,7 +2333,7 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0: cross-spawn@^6.0.0: version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" dependencies: nice-try "^1.0.4" path-key "^2.0.1" @@ -2495,45 +2343,33 @@ cross-spawn@^6.0.0: cryptiles@0.2.x: version "0.2.2" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" + resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" dependencies: boom "0.4.x" -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - dependencies: - boom "2.x.x" - crypto-random-string@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" ctype@0.5.3: version "0.5.3" - resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" + resolved "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" currently-unhandled@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + resolved "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" dependencies: array-find-index "^1.0.1" d@1: version "1.0.0" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + resolved "https://registry.npmjs.org/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" dependencies: es5-ext "^0.10.9" dag-map@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" + resolved "https://registry.npmjs.org/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" date-time@^2.1.0: version "2.1.0" @@ -2541,96 +2377,96 @@ date-time@^2.1.0: dependencies: time-zone "^1.0.0" -debug@2, debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.4.0, debug@^2.6.8: +debug@2, debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.4.0, debug@^2.6.8, debug@^2.6.9: version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: ms "2.0.0" debug@2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + resolved "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" dependencies: ms "0.7.1" debug@2.3.3: version "2.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" + resolved "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" dependencies: ms "0.7.2" debug@^3.0.0, debug@^3.1.0, debug@~3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: ms "2.0.0" decamelize@^1.0.0, decamelize@^1.1.2: version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" decode-uri-component@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" decompress-response@^3.3.0: version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" dependencies: mimic-response "^1.0.0" deep-eql@^0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" + resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" dependencies: type-detect "0.1.1" deep-eql@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" dependencies: type-detect "^4.0.0" -deep-extend@~0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" deep-is@~0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" defaults@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" dependencies: clone "^1.0.2" define-property@^0.2.5: version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" dependencies: is-descriptor "^1.0.0" define-property@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + resolved "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" dependencies: is-descriptor "^1.0.2" isobject "^3.0.1" defined@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + resolved "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" defs@~1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" + resolved "https://registry.npmjs.org/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" dependencies: alter "~0.2.0" ast-traverse "~0.1.1" @@ -2645,7 +2481,7 @@ defs@~1.1.0: del@^2.0.2: version "2.2.2" - resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + resolved "https://registry.npmjs.org/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" dependencies: globby "^5.0.0" is-path-cwd "^1.0.0" @@ -2657,41 +2493,37 @@ del@^2.0.2: delayed-stream@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" delegates@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" depd@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" -depd@~1.1.1: +depd@~1.1.1, depd@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" destroy@~1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" detect-file@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" + resolved "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" dependencies: fs-exists-sync "^0.1.0" detect-file@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + resolved "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" detect-indent@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" dependencies: get-stdin "^4.0.1" minimist "^1.1.0" @@ -2699,83 +2531,77 @@ detect-indent@^3.0.0: detect-indent@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" dependencies: repeating "^2.0.0" +detect-indent@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" + detect-libc@^1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" detective@^4.3.1: version "4.7.1" - resolved "https://registry.yarnpkg.com/detective/-/detective-4.7.1.tgz#0eca7314338442febb6d65da54c10bb1c82b246e" + resolved "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz#0eca7314338442febb6d65da54c10bb1c82b246e" dependencies: acorn "^5.2.1" defined "^1.0.0" diff@1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" + resolved "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" diff@^3.2.0: version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" doctrine@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" dependencies: esutils "^2.0.2" dot-prop@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" dependencies: is-obj "^1.0.0" dot-prop@^4.1.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" dependencies: is-obj "^1.0.0" duplexer3@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - -ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - dependencies: - jsbn "~0.1.0" + resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" editions@^1.1.1: version "1.3.4" - resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" + resolved "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" ee-first@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - -electron-to-chromium@^1.3.30: - version "1.3.36" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.36.tgz#0eabf71a9ebea9013fb1cc35a390e068624f27e8" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" electron-to-chromium@^1.3.47: - version "1.3.48" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.48.tgz#d3b0d8593814044e092ece2108fc3ac9aea4b900" + version "1.3.50" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.50.tgz#7438b76f92b41b919f3fbdd350fbd0757dacddf7" ember-cli-app-version@^3.0.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-3.1.3.tgz#26d25f5e653ff0106f0b39da6d75518ba8ed282d" + version "3.2.0" + resolved "https://registry.npmjs.org/ember-cli-app-version/-/ember-cli-app-version-3.2.0.tgz#7b9ad0e1b63ae0518648356ee24c703e922bc26e" dependencies: - ember-cli-babel "^6.8.0" - git-repo-version "^1.0.0" + ember-cli-babel "^6.12.0" + git-repo-version "^1.0.2" -ember-cli-babel@6.12.0, ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.10.0, ember-cli-babel@^6.3.0, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: +ember-cli-babel@6.12.0: version "6.12.0" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.12.0.tgz#3adcdbe1278da1fcd0b9038f1360cb4ac5d4414c" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.12.0.tgz#3adcdbe1278da1fcd0b9038f1360cb4ac5d4414c" dependencies: amd-name-resolver "0.0.7" babel-plugin-debug-macros "^0.1.11" @@ -2792,8 +2618,8 @@ ember-cli-babel@6.12.0, ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, e semver "^5.4.1" ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.6, ember-cli-babel@^5.2.1: - version "5.2.4" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-5.2.4.tgz#5ce4f46b08ed6f6d21e878619fb689719d6e8e13" + version "5.2.8" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.8.tgz#0356b03cc3fdff5d0f2ecaa46a0e1cfaebffd876" dependencies: broccoli-babel-transpiler "^5.6.2" broccoli-funnel "^1.0.0" @@ -2801,7 +2627,7 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.6, ember-c ember-cli-version-checker "^1.0.2" resolve "^1.1.2" -ember-cli-babel@^6.6.0: +ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.12.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: version "6.14.1" resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.14.1.tgz#796339229035910b625593caffbc2683792ada68" dependencies: @@ -2821,7 +2647,7 @@ ember-cli-babel@^6.6.0: ember-cli-blueprint-test-helpers@^0.18.3: version "0.18.3" - resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.18.3.tgz#945c606d855f0263f5e8c03522e4040a74f259cc" + resolved "https://registry.npmjs.org/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.18.3.tgz#945c606d855f0263f5e8c03522e4040a74f259cc" dependencies: chai "^4.1.0" chai-as-promised "^7.0.0" @@ -2834,7 +2660,7 @@ ember-cli-blueprint-test-helpers@^0.18.3: ember-cli-broccoli-sane-watcher@^2.0.4: version "2.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.1.1.tgz#1687adada9022de26053fba833dc7dd10f03dd08" + resolved "https://registry.npmjs.org/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.1.1.tgz#1687adada9022de26053fba833dc7dd10f03dd08" dependencies: broccoli-slow-trees "^3.0.1" heimdalljs "^0.2.1" @@ -2843,17 +2669,18 @@ ember-cli-broccoli-sane-watcher@^2.0.4: sane "^2.4.1" ember-cli-dependency-checker@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/ember-cli-dependency-checker/-/ember-cli-dependency-checker-2.1.0.tgz#9d66286a7c778e94733eaf21320d129c4fd0dd64" + version "2.1.1" + resolved "https://registry.npmjs.org/ember-cli-dependency-checker/-/ember-cli-dependency-checker-2.1.1.tgz#0421f9ca53fe8b237a53575be7dbe36e88ac83a6" dependencies: - chalk "^1.1.3" + chalk "^2.3.0" + find-yarn-workspace-root "^1.1.0" is-git-url "^1.0.0" resolve "^1.5.0" semver "^5.3.0" ember-cli-eslint@^4.2.3: version "4.2.3" - resolved "https://registry.yarnpkg.com/ember-cli-eslint/-/ember-cli-eslint-4.2.3.tgz#2844d3f5e8184f19b2d7132ba99eb0b370b55598" + resolved "https://registry.npmjs.org/ember-cli-eslint/-/ember-cli-eslint-4.2.3.tgz#2844d3f5e8184f19b2d7132ba99eb0b370b55598" dependencies: broccoli-lint-eslint "^4.2.1" ember-cli-version-checker "^2.1.0" @@ -2862,11 +2689,11 @@ ember-cli-eslint@^4.2.3: ember-cli-get-component-path-option@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" + resolved "https://registry.npmjs.org/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" ember-cli-htmlbars-inline-precompile@^0.4.3: version "0.4.4" - resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.4.tgz#24a7617152630d64a047e553b72e00963a4f8d73" + resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.4.tgz#24a7617152630d64a047e553b72e00963a4f8d73" dependencies: babel-plugin-htmlbars-inline-precompile "^0.2.3" ember-cli-version-checker "^2.0.0" @@ -2874,18 +2701,18 @@ ember-cli-htmlbars-inline-precompile@^0.4.3: silent-error "^1.1.0" ember-cli-htmlbars-inline-precompile@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.2.tgz#5b544f664d5d9911f08cd979c5f70d8cb0ca2add" + version "1.0.3" + resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.3.tgz#332ff96c06fc522965162f1090d78a615379c3c2" dependencies: - babel-plugin-htmlbars-inline-precompile "^0.2.3" - ember-cli-version-checker "^2.0.0" - hash-for-dep "^1.0.2" - heimdalljs-logger "^0.1.7" + babel-plugin-htmlbars-inline-precompile "^0.2.5" + ember-cli-version-checker "^2.1.2" + hash-for-dep "^1.2.3" + heimdalljs-logger "^0.1.9" silent-error "^1.1.0" ember-cli-htmlbars@^2.0.1: version "2.0.3" - resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-2.0.3.tgz#e116e1500dba12f29c94b05b9ec90f52cb8bb042" + resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-2.0.3.tgz#e116e1500dba12f29c94b05b9ec90f52cb8bb042" dependencies: broccoli-persistent-filter "^1.0.3" hash-for-dep "^1.0.2" @@ -2894,11 +2721,11 @@ ember-cli-htmlbars@^2.0.1: ember-cli-inject-live-reload@^1.4.1: version "1.7.0" - resolved "https://registry.yarnpkg.com/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.7.0.tgz#af94336e015336127dfb98080ad442bb233e37ed" + resolved "https://registry.npmjs.org/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.7.0.tgz#af94336e015336127dfb98080ad442bb233e37ed" ember-cli-internal-test-helpers@^0.8.1: version "0.8.3" - resolved "https://registry.yarnpkg.com/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.8.3.tgz#e9b7db67f3fda4db736d1a319a282c04beada495" + resolved "https://registry.npmjs.org/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.8.3.tgz#e9b7db67f3fda4db736d1a319a282c04beada495" dependencies: chai "^3.3.0" chai-as-promised "^6.0.0" @@ -2916,7 +2743,7 @@ ember-cli-internal-test-helpers@^0.8.1: ember-cli-internal-test-helpers@^0.9.1: version "0.9.1" - resolved "https://registry.yarnpkg.com/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.9.1.tgz#d54a9124bb6408ceba83f049ba8479f4b96cdd19" + resolved "https://registry.npmjs.org/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.9.1.tgz#d54a9124bb6408ceba83f049ba8479f4b96cdd19" dependencies: chai "^3.3.0" chai-as-promised "^6.0.0" @@ -2933,29 +2760,29 @@ ember-cli-internal-test-helpers@^0.9.1: ember-cli-is-package-missing@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" + resolved "https://registry.npmjs.org/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" ember-cli-lodash-subset@^1.0.7: version "1.0.12" - resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" + resolved "https://registry.npmjs.org/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" ember-cli-lodash-subset@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-2.0.1.tgz#20cb68a790fe0fde2488ddfd8efbb7df6fe766f2" + resolved "https://registry.npmjs.org/ember-cli-lodash-subset/-/ember-cli-lodash-subset-2.0.1.tgz#20cb68a790fe0fde2488ddfd8efbb7df6fe766f2" ember-cli-normalize-entity-name@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" + resolved "https://registry.npmjs.org/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" dependencies: silent-error "^1.0.0" ember-cli-path-utils@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" + resolved "https://registry.npmjs.org/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" ember-cli-preprocess-registry@^3.1.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.1.tgz#38456c21c4d2b64945850cf9ec68db6ba769288a" + resolved "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.1.tgz#38456c21c4d2b64945850cf9ec68db6ba769288a" dependencies: broccoli-clean-css "^1.1.0" broccoli-funnel "^1.0.0" @@ -2968,7 +2795,7 @@ ember-cli-preprocess-registry@^3.1.0: ember-cli-pretender@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/ember-cli-pretender/-/ember-cli-pretender-1.0.1.tgz#35540babddef6f2778e91c627d190c73505103cd" + resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-1.0.1.tgz#35540babddef6f2778e91c627d190c73505103cd" dependencies: broccoli-funnel "^1.1.0" broccoli-merge-trees "^1.2.1" @@ -2977,7 +2804,7 @@ ember-cli-pretender@^1.0.1: ember-cli-release@^0.2.9: version "0.2.9" - resolved "https://registry.yarnpkg.com/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" + resolved "https://registry.npmjs.org/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" dependencies: chalk "^1.0.0" git-tools "^0.1.4" @@ -2991,7 +2818,7 @@ ember-cli-release@^0.2.9: ember-cli-shims@^1.0.2: version "1.2.0" - resolved "https://registry.yarnpkg.com/ember-cli-shims/-/ember-cli-shims-1.2.0.tgz#0f53aff0aab80b5f29da3a9731bac56169dd941f" + resolved "https://registry.npmjs.org/ember-cli-shims/-/ember-cli-shims-1.2.0.tgz#0f53aff0aab80b5f29da3a9731bac56169dd941f" dependencies: broccoli-file-creator "^1.1.1" broccoli-merge-trees "^2.0.0" @@ -3001,29 +2828,29 @@ ember-cli-shims@^1.0.2: ember-cli-sri@^2.1.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" + resolved "https://registry.npmjs.org/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" dependencies: broccoli-sri-hash "^2.1.0" ember-cli-string-utils@^1.0.0, ember-cli-string-utils@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" + resolved "https://registry.npmjs.org/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" ember-cli-test-info@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" + resolved "https://registry.npmjs.org/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" dependencies: ember-cli-string-utils "^1.0.0" ember-cli-test-loader@^1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-test-loader/-/ember-cli-test-loader-1.1.1.tgz#333311209b18185d0e0e95f918349da10cacf0b1" + resolved "https://registry.npmjs.org/ember-cli-test-loader/-/ember-cli-test-loader-1.1.1.tgz#333311209b18185d0e0e95f918349da10cacf0b1" dependencies: ember-cli-babel "^5.2.1" ember-cli-test-loader@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/ember-cli-test-loader/-/ember-cli-test-loader-2.2.0.tgz#3fb8d5d1357e4460d3f0a092f5375e71b6f7c243" + resolved "https://registry.npmjs.org/ember-cli-test-loader/-/ember-cli-test-loader-2.2.0.tgz#3fb8d5d1357e4460d3f0a092f5375e71b6f7c243" dependencies: ember-cli-babel "^6.8.1" @@ -3036,24 +2863,17 @@ ember-cli-uglify@2.0.0-beta.1: ember-cli-valid-component-name@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" + resolved "https://registry.npmjs.org/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" dependencies: silent-error "^1.0.0" ember-cli-version-checker@^1.0.2: version "1.3.1" - resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz#0bc2d134c830142da64bf9627a0eded10b61ae72" - dependencies: - semver "^5.3.0" - -ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.1.0.tgz#fc79a56032f3717cf844ada7cbdec1a06fedb604" + resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz#0bc2d134c830142da64bf9627a0eded10b61ae72" dependencies: - resolve "^1.3.3" semver "^5.3.0" -ember-cli-version-checker@^2.1.1, ember-cli-version-checker@^2.1.2: +ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-version-checker@^2.1.1, ember-cli-version-checker@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-2.1.2.tgz#305ce102390c66e4e0f1432dea9dc5c7c19fed98" dependencies: @@ -3156,14 +2976,6 @@ ember-compatibility-helpers@^1.0.0: ember-cli-version-checker "^2.1.1" semver "^5.4.1" -ember-compatibility-helpers@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.0.0-beta.2.tgz#00cb134af45f9562fa47a23f4da81a63aad41943" - dependencies: - babel-plugin-debug-macros "^0.1.11" - ember-cli-version-checker "^2.0.0" - semver "^5.4.1" - ember-decorators@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/ember-decorators/-/ember-decorators-2.1.0.tgz#4910835da3517c633532c8d6fcfcf026e13701c0" @@ -3178,29 +2990,29 @@ ember-decorators@^2.1.0: ember-disable-prototype-extensions@^1.1.0: version "1.1.3" - resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" + resolved "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" ember-disable-proxy-controllers@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" + resolved "https://registry.npmjs.org/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" dependencies: ember-cli-babel "^5.0.0" ember-export-application-global@^1.0.5: version "1.1.1" - resolved "https://registry.yarnpkg.com/ember-export-application-global/-/ember-export-application-global-1.1.1.tgz#f257d5271268932a89d7392679ce4db89d7154af" + resolved "https://registry.npmjs.org/ember-export-application-global/-/ember-export-application-global-1.1.1.tgz#f257d5271268932a89d7392679ce4db89d7154af" dependencies: ember-cli-babel "^5.1.10" ember-inflector@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ember-inflector/-/ember-inflector-2.1.0.tgz#afcb92d022a4eab58f08ff4578eafc3a1de2d09b" + version "2.3.0" + resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-2.3.0.tgz#94797eba0eea98d902aa1e5da0f0aeef6053317f" dependencies: ember-cli-babel "^6.0.0" ember-load-initializers@^0.6.0: version "0.6.3" - resolved "https://registry.yarnpkg.com/ember-load-initializers/-/ember-load-initializers-0.6.3.tgz#f47396ad271ba77294068c98f992a5f19705441a" + resolved "https://registry.npmjs.org/ember-load-initializers/-/ember-load-initializers-0.6.3.tgz#f47396ad271ba77294068c98f992a5f19705441a" dependencies: ember-cli-babel "^5.1.6" @@ -3215,32 +3027,32 @@ ember-maybe-import-regenerator@^0.1.6: ember-publisher@0.0.7: version "0.0.7" - resolved "https://registry.yarnpkg.com/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" + resolved "https://registry.npmjs.org/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" dependencies: aws-sdk "^2.0.9" ember-qunit-assert-helpers@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/ember-qunit-assert-helpers/-/ember-qunit-assert-helpers-0.2.1.tgz#4a77f8ff252e47cc53db6fa7fb4becb426de8d29" + resolved "https://registry.npmjs.org/ember-qunit-assert-helpers/-/ember-qunit-assert-helpers-0.2.1.tgz#4a77f8ff252e47cc53db6fa7fb4becb426de8d29" dependencies: broccoli-filter "^1.0.1" ember-cli-babel "^6.9.0" ember-qunit@^3.4.0: - version "3.4.0" - resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-3.4.0.tgz#47a60c2b889cd4b4a46380bf9da2b10115c0eae7" + version "3.4.1" + resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-3.4.1.tgz#204a2d39a5d44d494c56bf17cf3fd12f06210359" dependencies: "@ember/test-helpers" "^0.7.18" broccoli-funnel "^2.0.1" broccoli-merge-trees "^2.0.0" common-tags "^1.4.0" - ember-cli-babel "^6.3.0" + ember-cli-babel "^6.8.2" ember-cli-test-loader "^2.2.0" qunit "^2.5.0" ember-resolver@^4.1.0: - version "4.5.2" - resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-4.5.2.tgz#9f6d1cae036ebd2cf573e0e20a41849e12df7a4c" + version "4.5.6" + resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-4.5.6.tgz#61cecc683fbe3464d759e6d0c2bab97b3914ee4b" dependencies: "@glimmer/resolver" "^0.4.1" babel-plugin-debug-macros "^0.1.10" @@ -3252,28 +3064,28 @@ ember-resolver@^4.1.0: ember-rfc176-data@^0.2.0: version "0.2.7" - resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.2.7.tgz#bd355bc9b473e08096b518784170a23388bc973b" + resolved "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.2.7.tgz#bd355bc9b473e08096b518784170a23388bc973b" ember-rfc176-data@^0.3.0, ember-rfc176-data@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.1.tgz#6a5a4b8b82ec3af34f3010965fa96b936ca94519" + version "0.3.3" + resolved "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.3.3.tgz#27fba08d540a7463a4366c48eaa19c5a44971a39" ember-router-generator@^1.2.3: version "1.2.3" - resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" + resolved "https://registry.npmjs.org/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" dependencies: recast "^0.11.3" ember-runtime-enumerable-includes-polyfill@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-2.1.0.tgz#dc6d4a028471e4acc350dfd2a149874fb20913f5" + resolved "https://registry.npmjs.org/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-2.1.0.tgz#dc6d4a028471e4acc350dfd2a149874fb20913f5" dependencies: ember-cli-babel "^6.9.0" ember-cli-version-checker "^2.1.0" ember-source-channel-url@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ember-source-channel-url/-/ember-source-channel-url-1.0.1.tgz#93517ccbd97a26220184b7986a5325317065308b" + version "1.1.0" + resolved "https://registry.npmjs.org/ember-source-channel-url/-/ember-source-channel-url-1.1.0.tgz#73de5cc6ebc25b2120e932ec1d8f82677bfaf6ef" dependencies: got "^8.0.1" @@ -3297,7 +3109,7 @@ ember-source@~3.0.0: ember-try-config@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/ember-try-config/-/ember-try-config-2.2.0.tgz#6be0af6c71949813e02ac793564fddbf8336b807" + resolved "https://registry.npmjs.org/ember-try-config/-/ember-try-config-2.2.0.tgz#6be0af6c71949813e02ac793564fddbf8336b807" dependencies: lodash "^4.6.1" node-fetch "^1.3.3" @@ -3306,7 +3118,7 @@ ember-try-config@^2.2.0: ember-try@^0.2.23: version "0.2.23" - resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.23.tgz#39b57141b4907541d0ac8b503d211e6946b08718" + resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.23.tgz#39b57141b4907541d0ac8b503d211e6946b08718" dependencies: chalk "^1.0.0" cli-table2 "^0.2.0" @@ -3323,7 +3135,7 @@ ember-try@^0.2.23: ember-watson@^0.7.0: version "0.7.0" - resolved "https://registry.yarnpkg.com/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" + resolved "https://registry.npmjs.org/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" dependencies: babel-core "^5.8.22" chalk "^1.0.0" @@ -3333,19 +3145,19 @@ ember-watson@^0.7.0: recast "^0.10.29" walk-sync "^0.1.3" -encodeurl@~1.0.1: +encodeurl@~1.0.1, encodeurl@~1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" encoding@^0.1.11: version "0.1.12" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" dependencies: iconv-lite "~0.4.13" engine.io-client@1.8.0: version "1.8.0" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-1.8.0.tgz#7b730e4127414087596d9be3c88d2bc5fdb6cf5c" + resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.0.tgz#7b730e4127414087596d9be3c88d2bc5fdb6cf5c" dependencies: component-emitter "1.2.1" component-inherit "0.0.3" @@ -3362,7 +3174,7 @@ engine.io-client@1.8.0: engine.io-client@~3.2.0: version "3.2.1" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" + resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" dependencies: component-emitter "1.2.1" component-inherit "0.0.3" @@ -3378,7 +3190,7 @@ engine.io-client@~3.2.0: engine.io-parser@1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" + resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" dependencies: after "0.8.1" arraybuffer.slice "0.0.6" @@ -3389,7 +3201,7 @@ engine.io-parser@1.3.1: engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: version "2.1.2" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196" + resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196" dependencies: after "0.8.2" arraybuffer.slice "~0.0.7" @@ -3399,7 +3211,7 @@ engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: engine.io@1.8.0: version "1.8.0" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" + resolved "https://registry.npmjs.org/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" dependencies: accepts "1.3.3" base64id "0.1.0" @@ -3410,7 +3222,7 @@ engine.io@1.8.0: engine.io@~3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.0.tgz#54332506f42f2edc71690d2f2a42349359f3bf7d" + resolved "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz#54332506f42f2edc71690d2f2a42349359f3bf7d" dependencies: accepts "~1.3.4" base64id "1.0.0" @@ -3421,35 +3233,36 @@ engine.io@~3.2.0: ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" + resolved "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" entities@~1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + resolved "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" error-ex@^1.2.0: - version "1.3.1" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + version "1.3.2" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" dependencies: is-arrayish "^0.2.1" error@^7.0.0: version "7.0.2" - resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" + resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" dependencies: string-template "~0.2.1" xtend "~4.0.0" es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.39" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.39.tgz#fca21b67559277ca4ac1a1ed7048b107b6f76d87" + version "0.10.45" + resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz#0bfdf7b473da5919d5adf3bd25ceb754fccc3653" dependencies: es6-iterator "~2.0.3" es6-symbol "~3.1.1" + next-tick "1" es6-iterator@~2.0.1, es6-iterator@~2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" dependencies: d "1" es5-ext "^0.10.35" @@ -3457,7 +3270,7 @@ es6-iterator@~2.0.1, es6-iterator@~2.0.3: es6-map@^0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" + resolved "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" dependencies: d "1" es5-ext "~0.10.14" @@ -3468,7 +3281,7 @@ es6-map@^0.1.5: es6-set@~0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" + resolved "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" dependencies: d "1" es5-ext "~0.10.14" @@ -3478,41 +3291,41 @@ es6-set@~0.1.5: es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" dependencies: d "1" es5-ext "~0.10.14" escape-html@~1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" escape-string-regexp@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" -escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" eslint-config-prettier@^2.9.0: version "2.9.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" + resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" dependencies: get-stdin "^5.0.1" eslint-plugin-node@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz#bf19642298064379315d7a4b2a75937376fa05e4" + resolved "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz#bf19642298064379315d7a4b2a75937376fa05e4" dependencies: ignore "^3.3.6" minimatch "^3.0.4" resolve "^1.3.3" semver "^5.4.1" -eslint-plugin-prettier@^2.6.0: +eslint-plugin-prettier@2.6.0: version "2.6.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz#33e4e228bdb06142d03c560ce04ec23f6c767dd7" + resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz#33e4e228bdb06142d03c560ce04ec23f6c767dd7" dependencies: fast-diff "^1.1.1" jest-docblock "^21.0.0" @@ -3526,11 +3339,11 @@ eslint-scope@^3.7.1, eslint-scope@~3.7.1: eslint-visitor-keys@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" eslint@^4.0.0: version "4.19.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" + resolved "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" dependencies: ajv "^5.3.0" babel-code-frame "^6.22.0" @@ -3573,89 +3386,89 @@ eslint@^4.0.0: espree@^3.5.4: version "3.5.4" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" + resolved "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" dependencies: acorn "^5.5.0" acorn-jsx "^3.0.0" esprima-fb@~15001.1001.0-dev-harmony-fb: version "15001.1001.0-dev-harmony-fb" - resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" + resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" esprima@^1.2.2: version "1.2.5" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" + resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" esprima@^2.6.0: version "2.7.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + resolved "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" esprima@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" esprima@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" + resolved "https://registry.npmjs.org/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" esprima@~3.1.0: version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + resolved "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" esprimaq@^0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" + resolved "https://registry.npmjs.org/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" esquery@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" dependencies: estraverse "^4.0.0" esrecurse@^4.1.0: version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" dependencies: estraverse "^4.1.0" estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" -estree-walker@^0.3.0: - version "0.3.1" - resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-0.3.1.tgz#e6b1a51cf7292524e7237c312e5fe6660c1ce1aa" +estree-walker@^0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-0.5.2.tgz#d3850be7529c9580d815600b53126515e146dd39" esutils@^2.0.0, esutils@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" etag@~1.8.1: version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" event-emitter@~0.3.5: version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" dependencies: d "1" es5-ext "~0.10.14" -eventemitter3@1.x.x: - version "1.2.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" +eventemitter3@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" events-to-array@^1.0.1: version "1.1.2" - resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" + resolved "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" -events@^1.1.1: +events@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + resolved "https://registry.npmjs.org/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" exec-file-sync@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/exec-file-sync/-/exec-file-sync-2.0.2.tgz#58d441db46e40de6d1f30de5be022785bd89e328" + resolved "https://registry.npmjs.org/exec-file-sync/-/exec-file-sync-2.0.2.tgz#58d441db46e40de6d1f30de5be022785bd89e328" dependencies: is-obj "^1.0.0" object-assign "^4.0.1" @@ -3663,13 +3476,13 @@ exec-file-sync@^2.0.0: exec-sh@^0.2.0: version "0.2.1" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" + resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" dependencies: merge "^1.1.3" execa@^0.10.0: version "0.10.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + resolved "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" dependencies: cross-spawn "^6.0.0" get-stream "^3.0.0" @@ -3693,33 +3506,33 @@ execa@^0.9.0: exists-stat@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/exists-stat/-/exists-stat-1.0.0.tgz#0660e3525a2e89d9e446129440c272edfa24b529" + resolved "https://registry.npmjs.org/exists-stat/-/exists-stat-1.0.0.tgz#0660e3525a2e89d9e446129440c272edfa24b529" exists-sync@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" + resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" exists-sync@0.0.4: version "0.0.4" - resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" + resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" exit-hook@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" exit@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" expand-brackets@^0.1.4: version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" dependencies: is-posix-bracket "^0.1.0" expand-brackets@^2.1.4: version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" dependencies: debug "^2.3.3" define-property "^0.2.5" @@ -3731,27 +3544,27 @@ expand-brackets@^2.1.4: expand-range@^1.8.1: version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + resolved "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" dependencies: fill-range "^2.1.0" expand-tilde@^1.2.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" + resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" dependencies: os-homedir "^1.0.1" expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" dependencies: homedir-polyfill "^1.0.1" express@^4.10.7, express@^4.12.3, express@^4.13.1: - version "4.16.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" + version "4.16.3" + resolved "https://registry.npmjs.org/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" dependencies: - accepts "~1.3.4" + accepts "~1.3.5" array-flatten "1.1.1" body-parser "1.18.2" content-disposition "0.5.2" @@ -3759,49 +3572,49 @@ express@^4.10.7, express@^4.12.3, express@^4.13.1: cookie "0.3.1" cookie-signature "1.0.6" debug "2.6.9" - depd "~1.1.1" - encodeurl "~1.0.1" + depd "~1.1.2" + encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.1.0" + finalhandler "1.1.1" fresh "0.5.2" merge-descriptors "1.0.1" methods "~1.1.2" on-finished "~2.3.0" parseurl "~1.3.2" path-to-regexp "0.1.7" - proxy-addr "~2.0.2" + proxy-addr "~2.0.3" qs "6.5.1" range-parser "~1.2.0" safe-buffer "5.1.1" - send "0.16.1" - serve-static "1.13.1" + send "0.16.2" + serve-static "1.13.2" setprototypeof "1.1.0" - statuses "~1.3.1" - type-is "~1.6.15" + statuses "~1.4.0" + type-is "~1.6.16" utils-merge "1.0.1" vary "~1.1.2" extend-shallow@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" dependencies: assign-symbols "^1.0.0" is-extendable "^1.0.1" extend@3, extend@^3.0.0, extend@~3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + resolved "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" external-editor@^1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" + resolved "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" dependencies: extend "^3.0.0" spawn-sync "^1.0.15" @@ -3809,7 +3622,7 @@ external-editor@^1.1.0: external-editor@^2.0.4: version "2.2.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + resolved "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" dependencies: chardet "^0.4.0" iconv-lite "^0.4.17" @@ -3817,13 +3630,13 @@ external-editor@^2.0.4: extglob@^0.3.1: version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + resolved "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" dependencies: is-extglob "^1.0.0" extglob@^2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + resolved "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" dependencies: array-unique "^0.3.2" define-property "^1.0.0" @@ -3834,45 +3647,37 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - fake-xml-http-request@^1.6.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-1.6.0.tgz#bd0ac79ae3e2660098282048a12c730a6f64d550" + resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-1.6.0.tgz#bd0ac79ae3e2660098282048a12c730a6f64d550" fast-deep-equal@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" fast-diff@^1.1.1: version "1.1.2" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" + resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" fast-json-stable-stringify@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" fast-levenshtein@~2.0.4: version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" + resolved "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" dependencies: blank-object "^1.0.1" fast-sourcemap-concat@^1.0.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/fast-sourcemap-concat/-/fast-sourcemap-concat-1.2.4.tgz#dec83ec49fb3674bb750b92cec53b79bb7c46f67" + version "1.3.0" + resolved "https://registry.npmjs.org/fast-sourcemap-concat/-/fast-sourcemap-concat-1.3.0.tgz#cc618e4d6f68106b598a532e174076075bb82400" dependencies: - chalk "^0.5.1" + chalk "^2.0.0" fs-extra "^0.30.0" heimdalljs-logger "^0.1.7" memory-streams "^0.1.0" @@ -3883,50 +3688,50 @@ fast-sourcemap-concat@^1.0.1: faye-websocket@~0.10.0: version "0.10.0" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" dependencies: websocket-driver ">=0.5.1" fb-watchman@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" dependencies: bser "^2.0.0" figures@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + resolved "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" dependencies: escape-string-regexp "^1.0.5" file-entry-cache@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" dependencies: flat-cache "^1.2.1" object-assign "^4.0.1" filename-regex@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + resolved "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" filesize@^3.1.3: - version "3.6.0" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.0.tgz#22d079615624bb6fd3c04026120628a41b3f4efa" + version "3.6.1" + resolved "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" fill-range@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + version "2.2.4" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" dependencies: is-number "^2.1.0" isobject "^2.0.0" - randomatic "^1.1.3" + randomatic "^3.0.0" repeat-element "^1.1.2" repeat-string "^1.5.2" fill-range@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" dependencies: extend-shallow "^2.0.1" is-number "^3.0.0" @@ -3935,7 +3740,7 @@ fill-range@^4.0.0: finalhandler@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" dependencies: debug "2.6.9" encodeurl "~1.0.1" @@ -3945,9 +3750,21 @@ finalhandler@1.1.0: statuses "~1.3.1" unpipe "~1.0.0" +finalhandler@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.4.0" + unpipe "~1.0.0" + find-index@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" + resolved "https://registry.npmjs.org/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" find-up@^1.0.0: version "1.1.2" @@ -3958,20 +3775,20 @@ find-up@^1.0.0: find-up@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" dependencies: locate-path "^2.0.0" -find-yarn-workspace-root@^1.0.0: +find-yarn-workspace-root@^1.0.0, find-yarn-workspace-root@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-1.1.0.tgz#9817b6748cb90719f4dc37b4538bb200c697356f" + resolved "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-1.1.0.tgz#9817b6748cb90719f4dc37b4538bb200c697356f" dependencies: fs-extra "^4.0.3" micromatch "^3.1.4" findup-sync@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" + resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" dependencies: detect-file "^1.0.0" is-glob "^3.1.0" @@ -3980,7 +3797,7 @@ findup-sync@2.0.0: findup-sync@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-1.0.0.tgz#6f7e4b57b6ee3a4037b4414eaedea3f58f71e0ec" + resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-1.0.0.tgz#6f7e4b57b6ee3a4037b4414eaedea3f58f71e0ec" dependencies: detect-file "^0.1.0" is-glob "^2.0.1" @@ -3989,7 +3806,7 @@ findup-sync@^1.0.0: fireworm@^0.7.0: version "0.7.1" - resolved "https://registry.yarnpkg.com/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" + resolved "https://registry.npmjs.org/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" dependencies: async "~0.2.9" is-type "0.0.1" @@ -3999,14 +3816,14 @@ fireworm@^0.7.0: fixturify@^0.3.2: version "0.3.4" - resolved "https://registry.yarnpkg.com/fixturify/-/fixturify-0.3.4.tgz#c676de404a7f8ee8e64d0b76118e62ec95ab7b25" + resolved "https://registry.npmjs.org/fixturify/-/fixturify-0.3.4.tgz#c676de404a7f8ee8e64d0b76118e62ec95ab7b25" dependencies: fs-extra "^0.30.0" matcher-collection "^1.0.4" flat-cache@^1.2.1: version "1.3.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" dependencies: circular-json "^0.3.1" del "^2.0.2" @@ -4015,73 +3832,67 @@ flat-cache@^1.2.1: follow-redirects@0.0.7: version "0.0.7" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" dependencies: debug "^2.2.0" stream-consume "^0.1.0" +follow-redirects@^1.0.0: + version "1.5.0" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.0.tgz#234f49cf770b7f35b40e790f636ceba0c3a0ab77" + dependencies: + debug "^3.1.0" + for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" for-own@^0.1.4: version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + resolved "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" dependencies: for-in "^1.0.1" forever-agent@~0.5.0: version "0.5.2" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" form-data@~0.1.0: version "0.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" + resolved "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" dependencies: async "~0.9.0" combined-stream "~0.0.4" mime "~1.2.11" -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - forwarded@~0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" fragment-cache@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + resolved "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" dependencies: map-cache "^0.2.2" fresh@0.5.2: version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" from2@^2.1.1: version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + resolved "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" dependencies: inherits "^2.0.1" readable-stream "^2.0.0" fs-exists-sync@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + resolved "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" fs-extra@^0.24.0: version "0.24.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -4090,7 +3901,7 @@ fs-extra@^0.24.0: fs-extra@^0.26.0: version "0.26.7" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -4100,7 +3911,7 @@ fs-extra@^0.26.0: fs-extra@^0.30.0: version "0.30.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -4110,7 +3921,7 @@ fs-extra@^0.30.0: fs-extra@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -4118,14 +3929,14 @@ fs-extra@^1.0.0: fs-extra@^2.0.0: version "2.1.2" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" fs-extra@^4.0.0, fs-extra@^4.0.2, fs-extra@^4.0.3: version "4.0.3" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -4147,13 +3958,19 @@ fs-extra@^6.0.1: jsonfile "^4.0.0" universalify "^0.1.0" +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + dependencies: + minipass "^2.2.1" + fs-readdir-recursive@^0.1.0: version "0.1.2" - resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" + resolved "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" fs-sync@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" + resolved "https://registry.npmjs.org/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" dependencies: glob "^7.1.0" iconv-lite "^0.4.13" @@ -4163,7 +3980,7 @@ fs-sync@^1.0.4: fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6: version "0.5.7" - resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-0.5.7.tgz#315e2b098d5fe7f622880ac965b1b051868ac871" + resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.7.tgz#315e2b098d5fe7f622880ac965b1b051868ac871" dependencies: heimdalljs-logger "^0.1.7" object-assign "^4.1.0" @@ -4172,39 +3989,22 @@ fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5 fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -fsevents@^1.0.0, fsevents@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" - dependencies: - nan "^2.3.0" - node-pre-gyp "^0.6.39" - -fstream-ignore@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" +fsevents@^1.0.0, fsevents@^1.2.3: + version "1.2.4" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" + nan "^2.9.2" + node-pre-gyp "^0.10.0" functional-red-black-tree@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" gauge@~2.7.3: version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -4217,53 +4017,47 @@ gauge@~2.7.3: get-caller-file@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" get-func-name@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" get-stdin@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" get-stdin@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" + resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" + resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" git-repo-info@^1.1.2, git-repo-info@^1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" + resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" -git-repo-version@^1.0.0: +git-repo-version@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-1.0.2.tgz#2c8e9bee5d970cafc0dd58480f9dc56d9afe8e4f" + resolved "https://registry.npmjs.org/git-repo-version/-/git-repo-version-1.0.2.tgz#2c8e9bee5d970cafc0dd58480f9dc56d9afe8e4f" dependencies: git-repo-info "^1.4.1" git-tools@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" + resolved "https://registry.npmjs.org/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" dependencies: spawnback "~1.0.0" github@^1.1.1: version "1.4.0" - resolved "https://registry.yarnpkg.com/github/-/github-1.4.0.tgz#60aed8f16ffe381a3ca6dc6dba5bdd64445b7856" + resolved "https://registry.npmjs.org/github/-/github-1.4.0.tgz#60aed8f16ffe381a3ca6dc6dba5bdd64445b7856" dependencies: follow-redirects "0.0.7" https-proxy-agent "^1.0.0" @@ -4271,27 +4065,27 @@ github@^1.1.1: glob-base@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + resolved "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" dependencies: glob-parent "^2.0.0" is-glob "^2.0.0" glob-parent@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" dependencies: is-glob "^2.0.0" glob@3.2.11: version "3.2.11" - resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" + resolved "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" dependencies: inherits "2" minimatch "0.3" glob@^4.3.2: version "4.5.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" + resolved "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" dependencies: inflight "^1.0.4" inherits "2" @@ -4300,7 +4094,7 @@ glob@^4.3.2: glob@^5.0.10, glob@^5.0.13, glob@^5.0.15: version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: inflight "^1.0.4" inherits "2" @@ -4310,7 +4104,7 @@ glob@^5.0.10, glob@^5.0.13, glob@^5.0.15: glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -4321,14 +4115,14 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: global-modules@^0.2.3: version "0.2.3" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" + resolved "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" dependencies: global-prefix "^0.1.4" is-windows "^0.2.0" global-modules@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + resolved "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" dependencies: global-prefix "^1.0.1" is-windows "^1.0.1" @@ -4336,7 +4130,7 @@ global-modules@^1.0.0: global-prefix@^0.1.4: version "0.1.5" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" + resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" dependencies: homedir-polyfill "^1.0.0" ini "^1.3.4" @@ -4345,7 +4139,7 @@ global-prefix@^0.1.4: global-prefix@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" dependencies: expand-tilde "^2.0.2" homedir-polyfill "^1.0.1" @@ -4354,20 +4148,20 @@ global-prefix@^1.0.1: which "^1.2.14" globals@^11.0.1, globals@^11.1.0: - version "11.5.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.5.0.tgz#6bc840de6771173b191f13d3a9c94d441ee92642" + version "11.7.0" + resolved "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" globals@^6.4.0: version "6.4.1" - resolved "https://registry.yarnpkg.com/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" + resolved "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" globals@^9.18.0: version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + resolved "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" globby@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + resolved "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" dependencies: array-union "^1.0.1" arrify "^1.0.0" @@ -4377,8 +4171,8 @@ globby@^5.0.0: pinkie-promise "^2.0.0" got@^8.0.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/got/-/got-8.2.0.tgz#0d11a071d05046348a2f5c0a5fa047fb687fdfc6" + version "8.3.1" + resolved "https://registry.npmjs.org/got/-/got-8.3.1.tgz#093324403d4d955f5a16a7a8d39955d055ae10ed" dependencies: "@sindresorhus/is" "^0.7.0" cacheable-request "^2.1.1" @@ -4390,7 +4184,7 @@ got@^8.0.1: isurl "^1.0.0-alpha5" lowercase-keys "^1.0.0" mimic-response "^1.0.0" - p-cancelable "^0.3.0" + p-cancelable "^0.4.0" p-timeout "^2.0.1" pify "^3.0.0" safe-buffer "^5.1.1" @@ -4400,23 +4194,23 @@ got@^8.0.1: graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" "graceful-readlink@>= 1.0.0": version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + resolved "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" growl@1.9.2: version "1.9.2" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" + resolved "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" growly@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" handlebars@^4.0.4: version "4.0.11" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" + resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" dependencies: async "^1.4.0" optimist "^0.6.1" @@ -4424,72 +4218,55 @@ handlebars@^4.0.4: optionalDependencies: uglify-js "^2.6" -har-schema@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" - -har-validator@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" - dependencies: - ajv "^4.9.1" - har-schema "^1.0.5" - -has-ansi@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" - dependencies: - ansi-regex "^0.2.0" - has-ansi@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" dependencies: ansi-regex "^2.0.0" has-binary2@~1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + resolved "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" dependencies: isarray "2.0.1" has-binary@0.1.6: version "0.1.6" - resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" + resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" dependencies: isarray "0.0.1" has-binary@0.1.7: version "0.1.7" - resolved "https://registry.yarnpkg.com/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" + resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" dependencies: isarray "0.0.1" has-cors@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + resolved "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" has-symbol-support-x@^1.4.1: version "1.4.2" - resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + resolved "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" has-to-string-tag-x@^1.2.0: version "1.4.1" - resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + resolved "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" dependencies: has-symbol-support-x "^1.4.1" has-unicode@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" has-value@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + resolved "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" dependencies: get-value "^2.0.3" has-values "^0.1.4" @@ -4497,7 +4274,7 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + resolved "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" dependencies: get-value "^2.0.6" has-values "^1.0.0" @@ -4505,18 +4282,18 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + resolved "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" has-values@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + resolved "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" dependencies: is-number "^3.0.0" kind-of "^4.0.0" hash-for-dep@^1.0.2, hash-for-dep@^1.2.3: version "1.2.3" - resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.2.3.tgz#5ec69fca32c23523972d52acb5bb65ffc3664cab" + resolved "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.2.3.tgz#5ec69fca32c23523972d52acb5bb65ffc3664cab" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" heimdalljs "^0.2.3" @@ -4525,190 +4302,189 @@ hash-for-dep@^1.0.2, hash-for-dep@^1.2.3: hawk@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" + resolved "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" dependencies: boom "0.4.x" cryptiles "0.2.x" hoek "0.9.x" sntp "0.2.x" -hawk@3.1.3, hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - heimdalljs-fs-monitor@^0.2.0: version "0.2.1" - resolved "https://registry.yarnpkg.com/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.2.1.tgz#b4079cfb85fb8326b8c75a7538fdbfa3d8afaa63" + resolved "https://registry.npmjs.org/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.2.1.tgz#b4079cfb85fb8326b8c75a7538fdbfa3d8afaa63" dependencies: heimdalljs "^0.2.0" heimdalljs-logger "^0.1.7" heimdalljs-graph@^0.3.1: version "0.3.4" - resolved "https://registry.yarnpkg.com/heimdalljs-graph/-/heimdalljs-graph-0.3.4.tgz#0bd75797beeaa20b0ed59017aed3b2d95312acee" + resolved "https://registry.npmjs.org/heimdalljs-graph/-/heimdalljs-graph-0.3.4.tgz#0bd75797beeaa20b0ed59017aed3b2d95312acee" heimdalljs-logger@^0.1.7, heimdalljs-logger@^0.1.9: version "0.1.9" - resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz#d76ada4e45b7bb6f786fc9c010a68eb2e2faf176" + resolved "https://registry.npmjs.org/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz#d76ada4e45b7bb6f786fc9c010a68eb2e2faf176" dependencies: debug "^2.2.0" heimdalljs "^0.2.0" heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3: version "0.2.5" - resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.5.tgz#6aa54308eee793b642cff9cf94781445f37730ac" + resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.2.5.tgz#6aa54308eee793b642cff9cf94781445f37730ac" dependencies: rsvp "~3.2.1" heimdalljs@^0.3.0: version "0.3.3" - resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" + resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" dependencies: rsvp "~3.2.1" hoek@0.9.x: version "0.9.1" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" - -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + resolved "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" home-or-tmp@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" + resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" dependencies: os-tmpdir "^1.0.1" user-home "^1.1.1" home-or-tmp@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.1" homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" dependencies: parse-passwd "^1.0.0" -hosted-git-info@^2.1.4, hosted-git-info@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" +hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: + version "2.6.1" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.1.tgz#6e4cee78b01bb849dcf93527708c69fdbee410df" http-cache-semantics@3.8.1: version "3.8.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" -http-errors@1.6.2, http-errors@~1.6.2: +http-errors@1.6.2: version "1.6.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" dependencies: depd "1.1.1" inherits "2.0.3" setprototypeof "1.0.3" statuses ">= 1.3.1 < 2" +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + http-parser-js@>=0.4.0: - version "0.4.10" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4" + version "0.4.13" + resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.13.tgz#3bd6d6fde6e3172c9334c3b33b6c193d80fe1137" http-proxy@^1.13.1, http-proxy@^1.9.0: - version "1.16.2" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" + version "1.17.0" + resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" dependencies: - eventemitter3 "1.x.x" - requires-port "1.x.x" + eventemitter3 "^3.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" http-signature@~0.10.0: version "0.10.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" dependencies: asn1 "0.1.11" assert-plus "^0.1.5" ctype "0.5.3" -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - https-proxy-agent@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" dependencies: agent-base "2" debug "2" extend "3" -iconv-lite@0.4.19, iconv-lite@^0.4.13, iconv-lite@^0.4.5, iconv-lite@~0.4.13: +iconv-lite@0.4.19: version "0.4.19" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" -iconv-lite@^0.4.17: +iconv-lite@^0.4.13, iconv-lite@^0.4.17, iconv-lite@^0.4.4, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.23" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@^1.1.4: +ieee754@1.1.8: version "1.1.8" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + +ieee754@^1.1.4: + version "1.1.12" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + dependencies: + minimatch "^3.0.4" ignore@^3.3.3, ignore@^3.3.6: - version "3.3.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.8.tgz#3f8e9c35d38708a3a7e0e9abb6c73e7ee7707b2b" + version "3.3.10" + resolved "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" indent-string@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" dependencies: repeating "^2.0.0" indexof@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" inflected@^1.1.6: version "1.1.7" - resolved "https://registry.yarnpkg.com/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" + resolved "https://registry.npmjs.org/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" inflection@^1.12.0, inflection@^1.7.0, inflection@^1.8.0: version "1.12.0" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" + resolved "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" inflight@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" dependencies: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" ini@^1.3.4, ini@~1.3.0: version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" inline-source-map-comment@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" + resolved "https://registry.npmjs.org/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" dependencies: chalk "^1.0.0" get-stdin "^4.0.1" @@ -4718,7 +4494,7 @@ inline-source-map-comment@^1.0.5: inquirer@^2: version "2.0.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-2.0.0.tgz#e1351687b90d150ca403ceaa3cefb1e3065bef4b" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-2.0.0.tgz#e1351687b90d150ca403ceaa3cefb1e3065bef4b" dependencies: ansi-escapes "^1.1.0" chalk "^1.0.0" @@ -4737,7 +4513,7 @@ inquirer@^2: inquirer@^3.0.6: version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" @@ -4756,82 +4532,72 @@ inquirer@^3.0.6: into-stream@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" + resolved "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" dependencies: from2 "^2.1.1" p-is-promise "^1.1.0" -invariant@^2.2.0: +invariant@^2.2.0, invariant@^2.2.2: version "2.2.4" resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" dependencies: loose-envify "^1.0.0" -invariant@^2.2.2: - version "2.2.3" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.3.tgz#1a827dfde7dcbd7c323f0ca826be8fa7c5e9d688" - dependencies: - loose-envify "^1.0.0" - invert-kv@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" ipaddr.js@1.6.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" - -irregular-plurals@^1.0.0: - version "1.4.0" - resolved "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.4.0.tgz#2ca9b033651111855412f16be5d77c62a458a766" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" is-accessor-descriptor@^0.1.6: version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" dependencies: kind-of "^3.0.2" is-accessor-descriptor@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" dependencies: kind-of "^6.0.0" is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" is-binary-path@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" dependencies: binary-extensions "^1.0.0" is-buffer@^1.1.5: version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" is-builtin-module@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" dependencies: builtin-modules "^1.0.0" is-data-descriptor@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" dependencies: kind-of "^3.0.2" is-data-descriptor@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" dependencies: kind-of "^6.0.0" is-descriptor@^0.1.0: version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" dependencies: is-accessor-descriptor "^0.1.6" is-data-descriptor "^0.1.4" @@ -4839,7 +4605,7 @@ is-descriptor@^0.1.0: is-descriptor@^1.0.0, is-descriptor@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" dependencies: is-accessor-descriptor "^1.0.0" is-data-descriptor "^1.0.0" @@ -4847,137 +4613,137 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-dotfile@^1.0.0: version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + resolved "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" is-equal-shallow@^0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + resolved "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" dependencies: is-primitive "^2.0.0" is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" is-extendable@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" dependencies: is-plain-object "^2.0.4" is-extglob@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" is-extglob@^2.1.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" is-finite@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + resolved "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" is-git-url@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-1.0.0.tgz#53f684cd143285b52c3244b4e6f28253527af66b" + resolved "https://registry.npmjs.org/is-git-url/-/is-git-url-1.0.0.tgz#53f684cd143285b52c3244b4e6f28253527af66b" is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" dependencies: is-extglob "^1.0.0" is-glob@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" dependencies: is-extglob "^2.1.0" is-integer@^1.0.4: version "1.0.7" - resolved "https://registry.yarnpkg.com/is-integer/-/is-integer-1.0.7.tgz#6bde81aacddf78b659b6629d629cadc51a886d5c" + resolved "https://registry.npmjs.org/is-integer/-/is-integer-1.0.7.tgz#6bde81aacddf78b659b6629d629cadc51a886d5c" dependencies: is-finite "^1.0.0" is-number@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + resolved "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" dependencies: kind-of "^3.0.2" is-number@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" dependencies: kind-of "^3.0.2" is-number@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + resolved "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" is-obj@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" is-object@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" + resolved "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" is-odd@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" + resolved "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" dependencies: is-number "^4.0.0" is-path-cwd@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" is-path-in-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + version "1.0.1" + resolved "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" dependencies: is-path-inside "^1.0.0" is-path-inside@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" dependencies: path-is-inside "^1.0.1" is-plain-obj@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" dependencies: isobject "^3.0.1" is-posix-bracket@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + resolved "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" is-primitive@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + resolved "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" is-promise@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" is-reference@^1.1.0: version "1.1.0" @@ -4987,79 +4753,71 @@ is-reference@^1.1.0: is-regexp@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + resolved "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" is-resolvable@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" is-retry-allowed@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + resolved "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" is-type@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" + resolved "https://registry.npmjs.org/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" dependencies: core-util-is "~1.0.0" -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - is-utf8@^0.2.0: version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" is-windows@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" + resolved "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" isarray@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" isarray@2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" isbinaryfile@^3.0.0: version "3.0.2" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" + resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" isexe@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" isobject@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" istextorbinary@2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" + resolved "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" dependencies: binaryextensions "1 || 2" editions "^1.1.1" @@ -5067,25 +4825,25 @@ istextorbinary@2.1.0: isurl@^1.0.0-alpha5: version "1.0.0" - resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + resolved "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" dependencies: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" jade@0.26.3: version "0.26.3" - resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" + resolved "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" dependencies: commander "0.6.1" mkdirp "0.3.0" jest-docblock@^21.0.0: version "21.2.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" jmespath@0.15.0: version "0.15.0" - resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" jquery@^3.2.1: version "3.3.1" @@ -5093,30 +4851,26 @@ jquery@^3.2.1: js-reporters@1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b" + resolved "https://registry.npmjs.org/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b" js-tokens@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.6.1, js-yaml@^3.9.1: - version "3.11.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" + version "3.12.0" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" dependencies: argparse "^1.0.7" esprima "^4.0.0" -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - jsesc@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" jsesc@^2.5.0, jsesc@^2.5.1: version "2.5.1" @@ -5124,126 +4878,107 @@ jsesc@^2.5.0, jsesc@^2.5.1: jsesc@~0.3.x: version "0.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.3.0.tgz#1bf5ee63b4539fe2e26d0c1e99c240b97a457972" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.3.0.tgz#1bf5ee63b4539fe2e26d0c1e99c240b97a457972" jsesc@~0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" json-buffer@3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" json-schema-traverse@^0.3.0: version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: jsonify "~0.0.0" -json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: +json-stringify-safe@~5.0.0: version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" json3@3.3.2: version "3.3.2" - resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + resolved "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" json5@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" + resolved "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" json5@^0.5.1: version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + resolved "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" jsonfile@^2.1.0: version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" optionalDependencies: graceful-fs "^4.1.6" jsonfile@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" optionalDependencies: graceful-fs "^4.1.6" jsonify@~0.0.0: version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" + resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" keyv@3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" + resolved "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" dependencies: json-buffer "3.0.0" kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" dependencies: is-buffer "^1.1.5" kind-of@^5.0.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" klaw@^1.0.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + resolved "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" optionalDependencies: graceful-fs "^4.1.9" lazy-cache@^1.0.3: version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" - -lazy-cache@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264" - dependencies: - set-getter "^0.1.0" + resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" lcid@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + resolved "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" dependencies: invert-kv "^1.0.0" leek@0.0.24: version "0.0.24" - resolved "https://registry.yarnpkg.com/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" + resolved "https://registry.npmjs.org/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" dependencies: debug "^2.1.0" lodash.assign "^3.2.0" @@ -5251,30 +4986,30 @@ leek@0.0.24: leven@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" + resolved "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" levn@^0.3.0, levn@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" linkify-it@^2.0.0: version "2.0.3" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" dependencies: uc.micro "^1.0.1" linkify-it@~1.2.0: version "1.2.4" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" dependencies: uc.micro "^1.0.1" livereload-js@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.3.0.tgz#c3ab22e8aaf5bf3505d80d098cbad67726548c9a" + resolved "https://registry.npmjs.org/livereload-js/-/livereload-js-2.3.0.tgz#c3ab22e8aaf5bf3505d80d098cbad67726548c9a" load-json-file@^1.0.0: version "1.1.0" @@ -5287,8 +5022,8 @@ load-json-file@^1.0.0: strip-bom "^2.0.0" loader.js@^4.5.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.6.0.tgz#b965663ddbe2d80da482454cb865efe496e93e22" + version "4.7.0" + resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.7.0.tgz#a1a52902001c83631efde9688b8ab3799325ef1f" locate-character@^2.0.5: version "2.0.5" @@ -5296,21 +5031,21 @@ locate-character@^2.0.5: locate-path@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" dependencies: p-locate "^2.0.0" path-exists "^3.0.0" lodash._baseassign@^3.0.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + resolved "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" dependencies: lodash._basecopy "^3.0.0" lodash.keys "^3.0.0" lodash._basebind@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._basebind/-/lodash._basebind-2.3.0.tgz#2b5bc452a0e106143b21869f233bdb587417d248" + resolved "https://registry.npmjs.org/lodash._basebind/-/lodash._basebind-2.3.0.tgz#2b5bc452a0e106143b21869f233bdb587417d248" dependencies: lodash._basecreate "~2.3.0" lodash._setbinddata "~2.3.0" @@ -5318,11 +5053,11 @@ lodash._basebind@~2.3.0: lodash._basecopy@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + resolved "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" lodash._basecreate@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz#9b88a86a4dcff7b7f3c61d83a2fcfc0671ec9de0" + resolved "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz#9b88a86a4dcff7b7f3c61d83a2fcfc0671ec9de0" dependencies: lodash._renative "~2.3.0" lodash.isobject "~2.3.0" @@ -5330,7 +5065,7 @@ lodash._basecreate@~2.3.0: lodash._basecreatecallback@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz#37b2ab17591a339e988db3259fcd46019d7ac362" + resolved "https://registry.npmjs.org/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz#37b2ab17591a339e988db3259fcd46019d7ac362" dependencies: lodash._setbinddata "~2.3.0" lodash.bind "~2.3.0" @@ -5339,7 +5074,7 @@ lodash._basecreatecallback@~2.3.0: lodash._basecreatewrapper@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz#aa0c61ad96044c3933376131483a9759c3651247" + resolved "https://registry.npmjs.org/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz#aa0c61ad96044c3933376131483a9759c3651247" dependencies: lodash._basecreate "~2.3.0" lodash._setbinddata "~2.3.0" @@ -5348,18 +5083,18 @@ lodash._basecreatewrapper@~2.3.0: lodash._baseflatten@^3.0.0: version "3.1.4" - resolved "https://registry.yarnpkg.com/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" + resolved "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" dependencies: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" lodash._bindcallback@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" lodash._createassigner@^3.0.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + resolved "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" dependencies: lodash._bindcallback "^3.0.0" lodash._isiterateecall "^3.0.0" @@ -5367,7 +5102,7 @@ lodash._createassigner@^3.0.0: lodash._createwrapper@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" + resolved "https://registry.npmjs.org/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" dependencies: lodash._basebind "~2.3.0" lodash._basecreatewrapper "~2.3.0" @@ -5375,69 +5110,69 @@ lodash._createwrapper@~2.3.0: lodash._escapehtmlchar@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.3.0.tgz#d03da6bd82eedf38dc0a5b503d740ecd0e894592" + resolved "https://registry.npmjs.org/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.3.0.tgz#d03da6bd82eedf38dc0a5b503d740ecd0e894592" dependencies: lodash._htmlescapes "~2.3.0" lodash._escapestringchar@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._escapestringchar/-/lodash._escapestringchar-2.3.0.tgz#cce73ae60fc6da55d2bf8a0679c23ca2bab149fc" + resolved "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.3.0.tgz#cce73ae60fc6da55d2bf8a0679c23ca2bab149fc" lodash._getnative@^3.0.0: version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" lodash._htmlescapes@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._htmlescapes/-/lodash._htmlescapes-2.3.0.tgz#1ca98863cadf1fa1d82c84f35f31e40556a04f3a" + resolved "https://registry.npmjs.org/lodash._htmlescapes/-/lodash._htmlescapes-2.3.0.tgz#1ca98863cadf1fa1d82c84f35f31e40556a04f3a" lodash._isiterateecall@^3.0.0: version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + resolved "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" lodash._objecttypes@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz#6a3ea3987dd6eeb8021b2d5c9c303549cc2bae1e" + resolved "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz#6a3ea3987dd6eeb8021b2d5c9c303549cc2bae1e" lodash._reinterpolate@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-2.3.0.tgz#03ee9d85c0e55cbd590d71608a295bdda51128ec" + resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-2.3.0.tgz#03ee9d85c0e55cbd590d71608a295bdda51128ec" lodash._reinterpolate@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" lodash._renative@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._renative/-/lodash._renative-2.3.0.tgz#77d8edd4ced26dd5971f9e15a5f772e4e317fbd3" + resolved "https://registry.npmjs.org/lodash._renative/-/lodash._renative-2.3.0.tgz#77d8edd4ced26dd5971f9e15a5f772e4e317fbd3" lodash._reunescapedhtml@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.3.0.tgz#db920b55ac7f3ff825939aceb9ba2c231713d24d" + resolved "https://registry.npmjs.org/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.3.0.tgz#db920b55ac7f3ff825939aceb9ba2c231713d24d" dependencies: lodash._htmlescapes "~2.3.0" lodash.keys "~2.3.0" lodash._setbinddata@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz#e5610490acd13277d59858d95b5f2727f1508f04" + resolved "https://registry.npmjs.org/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz#e5610490acd13277d59858d95b5f2727f1508f04" dependencies: lodash._renative "~2.3.0" lodash.noop "~2.3.0" lodash._shimkeys@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz#611f93149e3e6c721096b48769ef29537ada8ba9" + resolved "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz#611f93149e3e6c721096b48769ef29537ada8ba9" dependencies: lodash._objecttypes "~2.3.0" lodash._slice@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._slice/-/lodash._slice-2.3.0.tgz#147198132859972e4680ca29a5992c855669aa5c" + resolved "https://registry.npmjs.org/lodash._slice/-/lodash._slice-2.3.0.tgz#147198132859972e4680ca29a5992c855669aa5c" lodash.assign@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" dependencies: lodash._baseassign "^3.0.0" lodash._createassigner "^3.0.0" @@ -5445,11 +5180,11 @@ lodash.assign@^3.2.0: lodash.assignin@^4.1.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + resolved "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" lodash.bind@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-2.3.0.tgz#c2a8e18b68e5ecc152e2b168266116fea5b016cc" + resolved "https://registry.npmjs.org/lodash.bind/-/lodash.bind-2.3.0.tgz#c2a8e18b68e5ecc152e2b168266116fea5b016cc" dependencies: lodash._createwrapper "~2.3.0" lodash._renative "~2.3.0" @@ -5457,21 +5192,21 @@ lodash.bind@~2.3.0: lodash.castarray@^4.4.0: version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" + resolved "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" lodash.clonedeep@^4.4.1: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" lodash.debounce@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" + resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" dependencies: lodash._getnative "^3.0.0" lodash.defaults@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-2.3.0.tgz#a832b001f138f3bb9721c2819a2a7cc5ae21ed25" + resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-2.3.0.tgz#a832b001f138f3bb9721c2819a2a7cc5ae21ed25" dependencies: lodash._objecttypes "~2.3.0" lodash.keys "~2.3.0" @@ -5482,7 +5217,7 @@ lodash.defaultsdeep@^4.6.0: lodash.escape@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-2.3.0.tgz#844c38c58f844e1362ebe96726159b62cf5f2a58" + resolved "https://registry.npmjs.org/lodash.escape/-/lodash.escape-2.3.0.tgz#844c38c58f844e1362ebe96726159b62cf5f2a58" dependencies: lodash._escapehtmlchar "~2.3.0" lodash._reunescapedhtml "~2.3.0" @@ -5490,25 +5225,25 @@ lodash.escape@~2.3.0: lodash.find@^4.5.1: version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" + resolved "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" lodash.flatten@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" + resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" dependencies: lodash._baseflatten "^3.0.0" lodash._isiterateecall "^3.0.0" lodash.foreach@~2.3.x: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-2.3.0.tgz#083404c91e846ee77245fdf9d76519c68b2af168" + resolved "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-2.3.0.tgz#083404c91e846ee77245fdf9d76519c68b2af168" dependencies: lodash._basecreatecallback "~2.3.0" lodash.forown "~2.3.0" lodash.forown@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.forown/-/lodash.forown-2.3.0.tgz#24fb4aaf800d45fc2dc60bfec3ce04c836a3ad7f" + resolved "https://registry.npmjs.org/lodash.forown/-/lodash.forown-2.3.0.tgz#24fb4aaf800d45fc2dc60bfec3ce04c836a3ad7f" dependencies: lodash._basecreatecallback "~2.3.0" lodash._objecttypes "~2.3.0" @@ -5516,29 +5251,29 @@ lodash.forown@~2.3.0: lodash.identity@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.identity/-/lodash.identity-2.3.0.tgz#6b01a210c9485355c2a913b48b6711219a173ded" + resolved "https://registry.npmjs.org/lodash.identity/-/lodash.identity-2.3.0.tgz#6b01a210c9485355c2a913b48b6711219a173ded" lodash.isarguments@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" lodash.isarray@^3.0.0: version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" lodash.isfunction@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz#6b2973e47a647cf12e70d676aea13643706e5267" + resolved "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz#6b2973e47a647cf12e70d676aea13643706e5267" lodash.isobject@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-2.3.0.tgz#2e16d3fc583da9831968953f2d8e6d73434f6799" + resolved "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.3.0.tgz#2e16d3fc583da9831968953f2d8e6d73434f6799" dependencies: lodash._objecttypes "~2.3.0" lodash.keys@^3.0.0: version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" dependencies: lodash._getnative "^3.0.0" lodash.isarguments "^3.0.0" @@ -5546,7 +5281,7 @@ lodash.keys@^3.0.0: lodash.keys@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-2.3.0.tgz#b350f4f92caa9f45a4a2ecf018454cf2f28ae253" + resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.3.0.tgz#b350f4f92caa9f45a4a2ecf018454cf2f28ae253" dependencies: lodash._renative "~2.3.0" lodash._shimkeys "~2.3.0" @@ -5554,36 +5289,36 @@ lodash.keys@~2.3.0: lodash.merge@^4.3.0, lodash.merge@^4.5.1, lodash.merge@^4.6.0: version "4.6.1" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" lodash.noop@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-2.3.0.tgz#3059d628d51bbf937cd2a0b6fc3a7f212a669c2c" + resolved "https://registry.npmjs.org/lodash.noop/-/lodash.noop-2.3.0.tgz#3059d628d51bbf937cd2a0b6fc3a7f212a669c2c" lodash.omit@^4.1.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" + resolved "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" lodash.restparam@^3.0.0: version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" lodash.support@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.support/-/lodash.support-2.3.0.tgz#7eaf038af4f0d6aab776b44aa6dcfc80334c9bfd" + resolved "https://registry.npmjs.org/lodash.support/-/lodash.support-2.3.0.tgz#7eaf038af4f0d6aab776b44aa6dcfc80334c9bfd" dependencies: lodash._renative "~2.3.0" lodash.template@^4.2.5: version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" + resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings "^4.0.0" lodash.template@~2.3.x: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-2.3.0.tgz#4e3e29c433b4cfea675ec835e6f12391c61fd22b" + resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-2.3.0.tgz#4e3e29c433b4cfea675ec835e6f12391c61fd22b" dependencies: lodash._escapestringchar "~2.3.0" lodash._reinterpolate "~2.3.0" @@ -5595,120 +5330,120 @@ lodash.template@~2.3.x: lodash.templatesettings@^4.0.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" + resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-2.3.0.tgz#303d132c342710040d5a18efaa2d572fd03f8cdc" + resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-2.3.0.tgz#303d132c342710040d5a18efaa2d572fd03f8cdc" dependencies: lodash._reinterpolate "~2.3.0" lodash.escape "~2.3.0" lodash.uniq@^4.2.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" lodash.uniqby@^4.7.0: version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" + resolved "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" lodash.values@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-2.3.0.tgz#ca96fbe60a20b0b0ec2ba2ba5fc6a765bd14a3ba" + resolved "https://registry.npmjs.org/lodash.values/-/lodash.values-2.3.0.tgz#ca96fbe60a20b0b0ec2ba2ba5fc6a765bd14a3ba" dependencies: lodash.keys "~2.3.0" lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" - -lodash@^4.0.0, lodash@^4.14.0, lodash@^4.16.1, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1: - version "4.17.4" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.2.0: +lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: version "4.17.10" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" log-symbols@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" dependencies: chalk "^2.0.1" longest@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" loose-envify@^1.0.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: js-tokens "^3.0.0" loud-rejection@^1.0.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + resolved "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" dependencies: currently-unhandled "^0.4.1" signal-exit "^3.0.0" -lowercase-keys@1.0.0, lowercase-keys@^1.0.0: +lowercase-keys@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" lru-cache@2: version "2.7.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" lru-cache@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.1.tgz#622e32e82488b49279114a4f9ecf45e7cd6bba55" + version "4.1.3" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" dependencies: pseudomap "^1.0.2" yallist "^2.1.2" magic-string@^0.24.0: - version "0.24.0" - resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.24.0.tgz#1b396d26406188f1fa3730a68229562d36a1c2f2" + version "0.24.1" + resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.24.1.tgz#7e38e5f126cae9f15e71f0cf8e450818ca7d5a8f" dependencies: sourcemap-codec "^1.4.1" make-array@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" + resolved "https://registry.npmjs.org/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" make-dir@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b" + version "1.3.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" dependencies: pify "^3.0.0" makeerror@1.0.x: version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" dependencies: tmpl "1.0.x" map-cache@^0.2.2: version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" map-visit@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + resolved "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" dependencies: object-visit "^1.0.0" markdown-it-terminal@0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/markdown-it-terminal/-/markdown-it-terminal-0.1.0.tgz#545abd8dd01c3d62353bfcea71db580b51d22bd9" + resolved "https://registry.npmjs.org/markdown-it-terminal/-/markdown-it-terminal-0.1.0.tgz#545abd8dd01c3d62353bfcea71db580b51d22bd9" dependencies: ansi-styles "^3.0.0" cardinal "^1.0.0" @@ -5718,7 +5453,7 @@ markdown-it-terminal@0.1.0: markdown-it@^4.3.0: version "4.4.0" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" dependencies: argparse "~1.0.2" entities "~1.1.1" @@ -5728,7 +5463,7 @@ markdown-it@^4.3.0: markdown-it@^8.3.0, markdown-it@^8.3.1: version "8.4.1" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.1.tgz#206fe59b0e4e1b78a7c73250af9b34a4ad0aaf44" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.1.tgz#206fe59b0e4e1b78a7c73250af9b34a4ad0aaf44" dependencies: argparse "^1.0.7" entities "~1.1.1" @@ -5738,41 +5473,45 @@ markdown-it@^8.3.0, markdown-it@^8.3.1: matcher-collection@^1.0.0, matcher-collection@^1.0.4, matcher-collection@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-1.0.5.tgz#2ee095438372cb8884f058234138c05c644ec339" + resolved "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.5.tgz#2ee095438372cb8884f058234138c05c644ec339" dependencies: minimatch "^3.0.2" +math-random@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" + md5-hex@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-2.0.0.tgz#d0588e9f1c74954492ecd24ac0ac6ce997d92e33" + resolved "https://registry.npmjs.org/md5-hex/-/md5-hex-2.0.0.tgz#d0588e9f1c74954492ecd24ac0ac6ce997d92e33" dependencies: md5-o-matic "^0.1.1" md5-o-matic@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" + resolved "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" mdn-links@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" + resolved "https://registry.npmjs.org/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" mdurl@^1.0.1, mdurl@~1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + resolved "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" media-typer@0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" memory-streams@^0.1.0: version "0.1.3" - resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.3.tgz#d9b0017b4b87f1d92f55f2745c9caacb1dc93ceb" + resolved "https://registry.npmjs.org/memory-streams/-/memory-streams-0.1.3.tgz#d9b0017b4b87f1d92f55f2745c9caacb1dc93ceb" dependencies: readable-stream "~1.0.2" meow@^3.4.0: version "3.7.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + resolved "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" dependencies: camelcase-keys "^2.0.0" decamelize "^1.1.2" @@ -5787,11 +5526,11 @@ meow@^3.4.0: merge-descriptors@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" merge-trees@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-trees/-/merge-trees-1.0.1.tgz#ccbe674569787f9def17fd46e6525f5700bbd23e" + resolved "https://registry.npmjs.org/merge-trees/-/merge-trees-1.0.1.tgz#ccbe674569787f9def17fd46e6525f5700bbd23e" dependencies: can-symlink "^1.0.0" fs-tree-diff "^0.5.4" @@ -5802,11 +5541,11 @@ merge-trees@^1.0.1: merge@^1.1.3, merge@^1.2.0, merge@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + resolved "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" methods@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7: version "2.3.11" @@ -5826,27 +5565,9 @@ micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7: parse-glob "^3.0.4" regex-cache "^0.4.2" -micromatch@^3.0.4: - version "3.1.9" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.9.tgz#15dc93175ae39e52e93087847096effc73efcf89" - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -micromatch@^3.1.4: +micromatch@^3.0.4, micromatch@^3.1.4: version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" @@ -5862,102 +5583,112 @@ micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -"mime-db@>= 1.33.0 < 2", mime-db@~1.33.0: +"mime-db@>= 1.34.0 < 2": + version "1.34.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.34.0.tgz#452d0ecff5c30346a6dc1e64b1eaee0d3719ff9a" + +mime-db@~1.33.0: version "1.33.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" -mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.11, mime-types@~2.1.18, mime-types@~2.1.7: +mime-types@^2.1.18, mime-types@~2.1.11, mime-types@~2.1.18: version "2.1.18" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" dependencies: mime-db "~1.33.0" mime-types@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" mime@1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + resolved "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" mime@^1.2.11: version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" mime@~1.2.11: version "1.2.11" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + resolved "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" mimic-fn@^1.0.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" mimic-response@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" minimatch@0.3: version "0.3.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" dependencies: lru-cache "2" sigmund "~1.0.0" "minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: brace-expansion "^1.1.7" minimatch@^2.0.1, minimatch@^2.0.3: version "2.0.10" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" dependencies: brace-expansion "^1.0.0" minimist@0.0.8: version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" minimist@~0.0.1: version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" -minipass@^2.2.0: +minipass@^2.2.0, minipass@^2.2.1, minipass@^2.3.3: version "2.3.3" resolved "https://registry.npmjs.org/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" dependencies: safe-buffer "^5.1.2" yallist "^3.0.0" +minizlib@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + dependencies: + minipass "^2.2.1" + mixin-deep@^1.2.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" dependencies: for-in "^1.0.2" is-extendable "^1.0.1" mkdirp@0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" -mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: +mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" mktemp@^0.4.0, mktemp@~0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" + resolved "https://registry.npmjs.org/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" mocha-only-detector@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/mocha-only-detector/-/mocha-only-detector-0.0.2.tgz#00f7dde6f949cf68a3cc92bdacff997b87e4b1d1" + resolved "https://registry.npmjs.org/mocha-only-detector/-/mocha-only-detector-0.0.2.tgz#00f7dde6f949cf68a3cc92bdacff997b87e4b1d1" dependencies: esprima "^1.2.2" esprimaq "^0.0.1" @@ -5965,7 +5696,7 @@ mocha-only-detector@0.0.2: mocha@^2.4.5: version "2.5.3" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58" + resolved "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58" dependencies: commander "2.3.0" debug "2.2.0" @@ -5980,17 +5711,17 @@ mocha@^2.4.5: moment-timezone@^0.3.0: version "0.3.1" - resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" + resolved "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" dependencies: moment ">= 2.6.0" "moment@>= 2.6.0": - version "2.21.0" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.21.0.tgz#2a114b51d2a6ec9e6d83cf803f838a878d8a023a" + version "2.22.2" + resolved "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" morgan@^1.8.1: version "1.9.0" - resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.0.tgz#d01fa6c65859b76fcf31b3cb53a3821a311d8051" + resolved "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz#d01fa6c65859b76fcf31b3cb53a3821a311d8051" dependencies: basic-auth "~2.0.0" debug "2.6.9" @@ -6000,39 +5731,39 @@ morgan@^1.8.1: mout@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/mout/-/mout-1.1.0.tgz#0b29d41e6a80fa9e2d4a5be9d602e1d9d02177f6" + resolved "https://registry.npmjs.org/mout/-/mout-1.1.0.tgz#0b29d41e6a80fa9e2d4a5be9d602e1d9d02177f6" ms@0.7.1: version "0.7.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + resolved "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" ms@0.7.2: version "0.7.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + resolved "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" ms@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" mustache@^2.2.1: version "2.3.0" - resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" + resolved "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" mute-stream@0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" mute-stream@0.0.7: version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" -nan@^2.3.0: - version "2.9.2" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.9.2.tgz#f564d75f5f8f36a6d9456cca7a6c4fe488ab7866" +nan@^2.9.2: + version "2.10.0" + resolved "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" nanomatch@^1.2.9: version "1.2.9" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" + resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" @@ -6049,118 +5780,140 @@ nanomatch@^1.2.9: natural-compare@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +needle@^2.2.0: + version "2.2.1" + resolved "https://registry.npmjs.org/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" negotiator@0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +next-tick@1: + version "1.0.0" + resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" nice-try@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" + resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" node-fetch@^1.3.3: version "1.7.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" dependencies: encoding "^0.1.11" is-stream "^1.0.1" node-int64@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" node-modules-path@^1.0.0, node-modules-path@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" + resolved "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" node-notifier@^5.0.1: version "5.2.1" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" + resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" dependencies: growly "^1.3.0" semver "^5.4.1" shellwords "^0.1.1" which "^1.3.0" -node-pre-gyp@^0.6.39: - version "0.6.39" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" +node-pre-gyp@^0.10.0: + version "0.10.2" + resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.2.tgz#e8945c20ef6795a20aac2b44f036eb13cf5146e3" dependencies: detect-libc "^1.0.2" - hawk "3.1.3" mkdirp "^0.5.1" + needle "^2.2.0" nopt "^4.0.1" + npm-packlist "^1.1.6" npmlog "^4.0.2" - rc "^1.1.7" - request "2.81.0" + rc "^1.2.7" rimraf "^2.6.1" semver "^5.3.0" - tar "^2.2.1" - tar-pack "^3.4.0" + tar "^4" node-uuid@~1.4.0: version "1.4.8" - resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" + resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" nopt@^3.0.3, nopt@^3.0.6: version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: abbrev "1" nopt@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" dependencies: abbrev "1" osenv "^0.1.4" normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: version "2.4.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.0, normalize-path@^2.0.1: +normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: remove-trailing-separator "^1.0.1" normalize-url@2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" dependencies: prepend-http "^2.0.0" query-string "^5.0.1" sort-keys "^2.0.0" +npm-bundled@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + npm-git-info@^1.0.0: version "1.0.3" - resolved "https://registry.yarnpkg.com/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" + resolved "https://registry.npmjs.org/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" npm-package-arg@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.0.0.tgz#8cce04b49d3f9faec3f56b0fe5f4391aeb9d2fac" + version "6.1.0" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" dependencies: - hosted-git-info "^2.5.0" - osenv "^0.1.4" - semver "^5.4.1" + hosted-git-info "^2.6.0" + osenv "^0.1.5" + semver "^5.5.0" validate-npm-package-name "^3.0.0" +npm-packlist@^1.1.6: + version "1.1.10" + resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npm-run-path@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" dependencies: path-key "^2.0.0" npmlog@^4.0.0, npmlog@^4.0.2: version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" @@ -6169,31 +5922,27 @@ npmlog@^4.0.0, npmlog@^4.0.2: number-is-nan@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" oauth-sign@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" - -oauth-sign@~0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" object-assign@4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" object-component@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + resolved "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" object-copy@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" @@ -6201,59 +5950,59 @@ object-copy@^0.1.0: object-visit@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + resolved "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" dependencies: isobject "^3.0.0" object.omit@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + resolved "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" dependencies: for-own "^0.1.4" is-extendable "^0.1.1" object.pick@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + resolved "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" dependencies: isobject "^3.0.1" on-finished@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" dependencies: ee-first "1.1.1" on-headers@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" -once@^1.3.0, once@^1.3.3: +once@^1.3.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" onetime@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" onetime@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + resolved "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" dependencies: mimic-fn "^1.0.0" optimist@^0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + resolved "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" dependencies: minimist "~0.0.1" wordwrap "~0.0.2" optionator@^0.8.2: version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: deep-is "~0.1.3" fast-levenshtein "~2.0.4" @@ -6264,11 +6013,11 @@ optionator@^0.8.2: options@>=0.0.5: version "0.0.6" - resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" + resolved "https://registry.npmjs.org/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" ora@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-2.0.0.tgz#8ec3a37fa7bffb54a3a0c188a1f6798e7e1827cd" + version "2.1.0" + resolved "https://registry.npmjs.org/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" dependencies: chalk "^2.3.1" cli-cursor "^2.1.0" @@ -6279,74 +6028,74 @@ ora@^2.0.0: os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" os-locale@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + resolved "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" dependencies: lcid "^1.0.0" os-shim@^0.1.2: version "0.1.3" - resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + resolved "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4: +osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4, osenv@^0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" output-file-sync@^1.1.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + resolved "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" dependencies: graceful-fs "^4.1.4" mkdirp "^0.5.1" object-assign "^4.1.0" -p-cancelable@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" +p-cancelable@^0.4.0: + version "0.4.1" + resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" p-finally@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" p-is-promise@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + resolved "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" p-limit@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" + version "1.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" dependencies: p-try "^1.0.0" p-locate@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" dependencies: p-limit "^1.1.0" p-timeout@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" + resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" dependencies: p-finally "^1.0.0" p-try@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" parse-glob@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + resolved "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" dependencies: glob-base "^0.3.0" is-dotfile "^1.0.0" @@ -6365,43 +6114,43 @@ parse-ms@^1.0.0: parse-passwd@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" parsejson@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" + resolved "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" dependencies: better-assert "~1.0.0" parseqs@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + resolved "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" dependencies: better-assert "~1.0.0" parseuri@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + resolved "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" dependencies: better-assert "~1.0.0" parseurl@~1.3.2: version "1.3.2" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" pascalcase@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" passwd-user@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/passwd-user/-/passwd-user-1.2.1.tgz#a01a5dc639ef007dc56364b8178569080ad3a7b8" + resolved "https://registry.npmjs.org/passwd-user/-/passwd-user-1.2.1.tgz#a01a5dc639ef007dc56364b8178569080ad3a7b8" dependencies: exec-file-sync "^2.0.0" path-exists@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" path-exists@^2.0.0: version "2.1.0" @@ -6411,31 +6160,31 @@ path-exists@^2.0.0: path-exists@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" path-parse@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" path-posix@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + resolved "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" path-to-regexp@0.1.7: version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" path-type@^1.0.0: version "1.1.0" @@ -6447,43 +6196,33 @@ path-type@^1.0.0: pathval@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" - -performance-now@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + resolved "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" pify@^2.0.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" pify@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" pinkie-promise@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - -plur@^2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/plur/-/plur-2.1.2.tgz#7482452c1a0f508e3e344eaec312c91c29dc655a" - dependencies: - irregular-plurals "^1.0.0" + resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" pluralize@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + resolved "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" portfinder@^1.0.7: version "1.0.13" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" + resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" dependencies: async "^1.5.2" debug "^2.2.0" @@ -6491,112 +6230,111 @@ portfinder@^1.0.7: posix-character-classes@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + resolved "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" prelude-ls@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" prepend-http@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" preserve@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + resolved "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" pretender@^1.4.2: version "1.6.1" - resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.6.1.tgz#77d1e42ac8c6b298f5cd43534a87645df035db8c" + resolved "https://registry.npmjs.org/pretender/-/pretender-1.6.1.tgz#77d1e42ac8c6b298f5cd43534a87645df035db8c" dependencies: fake-xml-http-request "^1.6.0" route-recognizer "^0.3.3" -prettier@^1.12.1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325" +prettier@^1.13.6: + version "1.13.6" + resolved "https://registry.npmjs.org/prettier/-/prettier-1.13.6.tgz#00ae0b777ad92f81a9e7a1df2f0470b6dab0cb44" pretty-ms@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/pretty-ms/-/pretty-ms-3.1.0.tgz#e9cac9c76bf6ee52fe942dd9c6c4213153b12881" + version "3.2.0" + resolved "https://registry.npmjs.org/pretty-ms/-/pretty-ms-3.2.0.tgz#87a8feaf27fc18414d75441467d411d6e6098a25" dependencies: parse-ms "^1.0.0" - plur "^2.1.2" printf@^0.2.3: version "0.2.5" - resolved "https://registry.yarnpkg.com/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" + resolved "https://registry.npmjs.org/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" printf@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/printf/-/printf-0.3.0.tgz#6918ca5237c047e19cf004b69e6bcfafbef1ce82" -private@^0.1.6, private@^0.1.7, private@~0.1.5: +private@^0.1.6, private@^0.1.8, private@~0.1.5: version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + resolved "https://registry.npmjs.org/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" process-nextick-args@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" process-relative-require@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" + resolved "https://registry.npmjs.org/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" dependencies: node-modules-path "^1.0.0" progress@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" + resolved "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" promise-map-series@^0.2.1: version "0.2.3" - resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" + resolved "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" dependencies: rsvp "^3.0.14" -proxy-addr@~2.0.2: +proxy-addr@~2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" dependencies: forwarded "~0.1.2" ipaddr.js "1.6.0" pseudomap@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +psl@^1.1.24: + version "1.1.28" + resolved "https://registry.npmjs.org/psl/-/psl-1.1.28.tgz#4fb6ceb08a1e2214d4fd4de0ca22dae13740bc7b" punycode@1.3.2: version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" punycode@^1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" q@^1.1.2: version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" -qs@6.5.1, qs@^6.4.0: +qs@6.5.1: version "6.5.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + +qs@^6.4.0: + version "6.5.2" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" qs@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" - -qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + resolved "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" query-string@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.0.tgz#9583b15fd1307f899e973ed418886426a9976469" + version "5.1.1" + resolved "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" dependencies: decode-uri-component "^0.2.0" object-assign "^4.1.0" @@ -6604,26 +6342,26 @@ query-string@^5.0.1: querystring@0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" -quibble@^0.5.1: - version "0.5.3" - resolved "https://registry.yarnpkg.com/quibble/-/quibble-0.5.3.tgz#3dfd53206fc6873f61c96f3bece63b69747b4d0c" +quibble@^0.5.5: + version "0.5.5" + resolved "https://registry.npmjs.org/quibble/-/quibble-0.5.5.tgz#669fb731520a923e0a98f8076b7eb55e409f73f9" dependencies: lodash "^4.17.2" - resolve "^1.5.0" + resolve "^1.7.1" -quick-temp@^0.1.0, quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: +quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: version "0.1.8" - resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" + resolved "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" dependencies: mktemp "~0.4.0" rimraf "^2.5.4" underscore.string "~3.3.4" qunit@^2.5.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/qunit/-/qunit-2.5.1.tgz#739b0ea9595bbf508b0600d5af04dcb2ba2a74e5" + version "2.6.1" + resolved "https://registry.npmjs.org/qunit/-/qunit-2.6.1.tgz#3a2a5f05307f873174e0f5859010fb7380380e3c" dependencies: chokidar "1.7.0" commander "2.12.2" @@ -6631,23 +6369,23 @@ qunit@^2.5.0: findup-sync "2.0.0" js-reporters "1.2.1" resolve "1.5.0" - shelljs "^0.2.6" walk-sync "0.3.2" -randomatic@^1.1.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" +randomatic@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz#d35490030eb4f7578de292ce6dfb04a91a128923" dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" range-parser@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" raw-body@2.3.2: version "2.3.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" dependencies: bytes "3.0.0" http-errors "1.6.2" @@ -6656,62 +6394,50 @@ raw-body@2.3.2: raw-body@~1.1.0: version "1.1.7" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" dependencies: bytes "1" string_decoder "0.10" -rc@^1.1.7: - version "1.2.5" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.5.tgz#275cd687f6e3b36cc756baa26dfee80a790301fd" +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" dependencies: - deep-extend "~0.4.0" + deep-extend "^0.6.0" ini "~1.3.0" minimist "^1.2.0" strip-json-comments "~2.0.1" read-pkg-up@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" dependencies: find-up "^1.0.0" read-pkg "^1.0.0" read-pkg@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^2, readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.2.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - safe-buffer "~5.1.1" - string_decoder "~1.0.3" - util-deprecate "~1.0.1" - -readable-stream@^2.0.2, readable-stream@^2.1.4: - version "2.3.5" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.5.tgz#b4f85003a938cbb6ecbce2a124fb1012bd1a838d" +readable-stream@^2, readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: + version "2.3.6" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: core-util-is "~1.0.0" inherits "~2.0.3" isarray "~1.0.0" process-nextick-args "~2.0.0" safe-buffer "~5.1.1" - string_decoder "~1.0.3" + string_decoder "~1.1.1" util-deprecate "~1.0.1" readable-stream@~1.0.2: version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -6720,7 +6446,7 @@ readable-stream@~1.0.2: readdirp@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" dependencies: graceful-fs "^4.1.2" minimatch "^3.0.2" @@ -6729,7 +6455,7 @@ readdirp@^2.0.0: recast@0.10.33: version "0.10.33" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" + resolved "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" dependencies: ast-types "0.8.12" esprima-fb "~15001.1001.0-dev-harmony-fb" @@ -6738,7 +6464,7 @@ recast@0.10.33: recast@^0.10.10, recast@^0.10.29: version "0.10.43" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" + resolved "https://registry.npmjs.org/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" dependencies: ast-types "0.8.15" esprima-fb "~15001.1001.0-dev-harmony-fb" @@ -6747,7 +6473,7 @@ recast@^0.10.10, recast@^0.10.29: recast@^0.11.17, recast@^0.11.3: version "0.11.23" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" + resolved "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" dependencies: ast-types "0.9.6" esprima "~3.1.0" @@ -6756,28 +6482,28 @@ recast@^0.11.17, recast@^0.11.3: redent@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + resolved "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" dependencies: indent-string "^2.1.0" strip-indent "^1.0.1" redeyed@~1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" + resolved "https://registry.npmjs.org/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" dependencies: esprima "~3.0.0" regenerate@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" + version "1.4.0" + resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" regenerator-runtime@^0.10.5: version "0.10.5" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" regenerator-runtime@^0.11.0: version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" regenerator-runtime@^0.9.5: version "0.9.6" @@ -6785,7 +6511,7 @@ regenerator-runtime@^0.9.5: regenerator-transform@^0.10.0: version "0.10.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" dependencies: babel-runtime "^6.18.0" babel-types "^6.19.0" @@ -6793,7 +6519,7 @@ regenerator-transform@^0.10.0: regenerator@0.8.40: version "0.8.40" - resolved "https://registry.yarnpkg.com/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" + resolved "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" dependencies: commoner "~0.10.3" defs "~1.1.0" @@ -6804,24 +6530,24 @@ regenerator@0.8.40: regex-cache@^0.4.2: version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + resolved "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" dependencies: is-equal-shallow "^0.1.3" regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + resolved "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" dependencies: extend-shallow "^3.0.2" safe-regex "^1.1.0" regexpp@^1.0.1: version "1.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" + resolved "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" regexpu-core@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" dependencies: regenerate "^1.2.1" regjsgen "^0.2.0" @@ -6829,7 +6555,7 @@ regexpu-core@^2.0.0: regexpu@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" + resolved "https://registry.npmjs.org/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" dependencies: esprima "^2.6.0" recast "^0.10.10" @@ -6839,68 +6565,41 @@ regexpu@^1.3.0: regjsgen@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" regjsparser@^0.1.4: version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" dependencies: jsesc "~0.5.0" remove-trailing-separator@^1.0.1: version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" repeat-element@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" repeating@^1.1.0, repeating@^1.1.2: version "1.1.3" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" + resolved "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" dependencies: is-finite "^1.0.0" repeating@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + resolved "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" dependencies: is-finite "^1.0.0" -request@2.81.0: - version "2.81.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~4.2.1" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - performance-now "^0.2.0" - qs "~6.4.0" - safe-buffer "^5.0.1" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "^0.6.0" - uuid "^3.0.0" - request@~2.40.0: version "2.40.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" + resolved "https://registry.npmjs.org/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" dependencies: forever-agent "~0.5.0" json-stringify-safe "~5.0.0" @@ -6923,94 +6622,100 @@ require-relative@^0.8.7: require-uncached@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + resolved "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" dependencies: caller-path "^0.1.0" resolve-from "^1.0.0" -requires-port@1.x.x: +requires-port@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" resolve-dir@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" + resolved "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" dependencies: expand-tilde "^1.2.2" global-modules "^0.2.3" resolve-dir@^1.0.0, resolve-dir@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + resolved "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" dependencies: expand-tilde "^2.0.0" global-modules "^1.0.0" resolve-from@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" resolve-url@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" -resolve@1.5.0, resolve@^1.1.2, resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0: +resolve@1.5.0: version "1.5.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" + dependencies: + path-parse "^1.0.5" + +resolve@^1.1.2, resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.7.1: + version "1.8.1" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" dependencies: path-parse "^1.0.5" responselike@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" dependencies: lowercase-keys "^1.0.0" restore-cursor@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" dependencies: exit-hook "^1.0.0" onetime "^1.0.0" restore-cursor@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" dependencies: onetime "^2.0.0" signal-exit "^3.0.2" ret@~0.1.10: version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" right-align@^0.1.1: version "0.1.3" - resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + resolved "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - dependencies: - glob "^7.0.5" - rimraf@2.5.2: version "2.5.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" dependencies: glob "^7.0.0" +rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: + version "2.6.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + rimraf@~2.2.6: version "2.2.8" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" rollup-pluginutils@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.0.1.tgz#7ec95b3573f6543a46a6461bd9a7c544525d0fc0" + version "2.3.0" + resolved "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.3.0.tgz#478ace04bd7f6da2e724356ca798214884738fc4" dependencies: - estree-walker "^0.3.0" + estree-walker "^0.5.2" micromatch "^2.3.11" rollup@^0.57.1: @@ -7031,73 +6736,69 @@ rollup@^0.57.1: route-recognizer@^0.3.3: version "0.3.3" - resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" + resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" rsvp@4.8.0: version "4.8.0" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.0.tgz#dc1dc400e2d48bcf3b1991f2a3b714f038fc432e" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.0.tgz#dc1dc400e2d48bcf3b1991f2a3b714f038fc432e" rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.5.0: version "3.6.2" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" rsvp@^4.6.1, rsvp@^4.7.0, rsvp@^4.8.2: version "4.8.2" resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.2.tgz#9d5647108735784eb13418cdddb56f75b919d722" -rsvp@~3.0.6: - version "3.0.21" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.21.tgz#49c588fe18ef293bcd0ab9f4e6756e6ac433359f" - rsvp@~3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" run-async@^2.2.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + resolved "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" dependencies: is-promise "^2.1.0" rx-lite-aggregates@^4.0.8: version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + resolved "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" dependencies: rx-lite "*" rx-lite@*, rx-lite@^4.0.8: version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + resolved "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" rx@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + resolved "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" -safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -safe-buffer@^5.1.2: +safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" safe-json-parse@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" + resolved "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" safe-regex@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" dependencies: ret "~0.1.10" "safer-buffer@>= 2.1.2 < 3": version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" sane@^1.4.1: version "1.7.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-1.7.0.tgz#b3579bccb45c94cf20355cc81124990dfd346e30" + resolved "https://registry.npmjs.org/sane/-/sane-1.7.0.tgz#b3579bccb45c94cf20355cc81124990dfd346e30" dependencies: anymatch "^1.3.0" exec-sh "^0.2.0" @@ -7108,51 +6809,48 @@ sane@^1.4.1: watch "~0.10.0" sane@^2.2.0, sane@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/sane/-/sane-2.4.1.tgz#29f991208cf28636720efdc584293e7fd66663a5" + version "2.5.2" + resolved "https://registry.npmjs.org/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" dependencies: - anymatch "^1.3.0" + anymatch "^2.0.0" + capture-exit "^1.2.0" exec-sh "^0.2.0" fb-watchman "^2.0.0" - minimatch "^3.0.2" + micromatch "^3.1.4" minimist "^1.1.1" walker "~1.0.5" watch "~0.18.0" optionalDependencies: - fsevents "^1.1.1" + fsevents "^1.2.3" sax@1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" -sax@>=0.6.0: +sax@>=0.6.0, sax@^1.2.4: version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0: +"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: version "5.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + resolved "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" semver@^4.3.1: version "4.3.6" - resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" - -semver@^5.1.0, semver@^5.1.1, semver@^5.3.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + resolved "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" semver@~5.0.1: version "5.0.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" + resolved "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" -send@0.16.1: - version "0.16.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" +send@0.16.2: + version "0.16.2" + resolved "https://registry.npmjs.org/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" dependencies: debug "2.6.9" - depd "~1.1.1" + depd "~1.1.2" destroy "~1.0.4" - encodeurl "~1.0.1" + encodeurl "~1.0.2" escape-html "~1.0.3" etag "~1.8.1" fresh "0.5.2" @@ -7161,34 +6859,28 @@ send@0.16.1: ms "2.0.0" on-finished "~2.3.0" range-parser "~1.2.0" - statuses "~1.3.1" + statuses "~1.4.0" -serve-static@1.13.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.1.tgz#4c57d53404a761d8f2e7c1e8a18a47dbf278a719" +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" dependencies: - encodeurl "~1.0.1" + encodeurl "~1.0.2" escape-html "~1.0.3" parseurl "~1.3.2" - send "0.16.1" + send "0.16.2" set-blocking@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - -set-getter@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376" - dependencies: - to-object-path "^0.3.0" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" set-immediate-shim@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + resolved "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" set-value@^0.4.3: version "0.4.3" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + resolved "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -7197,7 +6889,7 @@ set-value@^0.4.3: set-value@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + resolved "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -7206,69 +6898,65 @@ set-value@^2.0.0: setprototypeof@1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" setprototypeof@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" shebang-command@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - -shelljs@^0.2.6: - version "0.2.6" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.2.6.tgz#90492d72ffcc8159976baba62fb0f6884f0c3378" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" shellwords@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" sigmund@~1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + resolved "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" silent-error@^1.0.0, silent-error@^1.0.1, silent-error@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/silent-error/-/silent-error-1.1.0.tgz#2209706f1c850a9f1d10d0d840918b46f26e1bc9" + resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.1.0.tgz#2209706f1c850a9f1d10d0d840918b46f26e1bc9" dependencies: debug "^2.2.0" simple-fmt@~0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" + resolved "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" simple-is@~0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" + resolved "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" slash@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" slice-ansi@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" dependencies: is-fullwidth-code-point "^2.0.0" slide@^1.1.5: version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" snapdragon-node@^2.0.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" dependencies: define-property "^1.0.0" isobject "^3.0.0" @@ -7276,13 +6964,13 @@ snapdragon-node@^2.0.1: snapdragon-util@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + resolved "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" dependencies: kind-of "^3.2.0" snapdragon@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.1.tgz#e12b5487faded3e3dea0ac91e9400bf75b401370" + version "0.8.2" + resolved "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" dependencies: base "^0.11.1" debug "^2.2.0" @@ -7291,34 +6979,28 @@ snapdragon@^0.8.1: map-cache "^0.2.2" source-map "^0.5.6" source-map-resolve "^0.5.0" - use "^2.0.0" + use "^3.1.0" sntp@0.2.x: version "0.2.4" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" + resolved "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" dependencies: hoek "0.9.x" -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - dependencies: - hoek "2.x.x" - socket.io-adapter@0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" + resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" dependencies: debug "2.3.3" socket.io-parser "2.3.1" socket.io-adapter@~1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" + resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" socket.io-client@1.6.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" + resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" dependencies: backo2 "1.0.2" component-bind "1.0.0" @@ -7334,7 +7016,7 @@ socket.io-client@1.6.0: socket.io-client@2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" + resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" dependencies: backo2 "1.0.2" base64-arraybuffer "0.1.5" @@ -7353,7 +7035,7 @@ socket.io-client@2.1.1: socket.io-parser@2.3.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" + resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" dependencies: component-emitter "1.1.2" debug "2.2.0" @@ -7362,7 +7044,7 @@ socket.io-parser@2.3.1: socket.io-parser@~3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" + resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" dependencies: component-emitter "1.2.1" debug "~3.1.0" @@ -7370,7 +7052,7 @@ socket.io-parser@~3.2.0: socket.io@1.6.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" + resolved "https://registry.npmjs.org/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" dependencies: debug "2.3.3" engine.io "1.8.0" @@ -7382,7 +7064,7 @@ socket.io@1.6.0: socket.io@^2.1.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" + resolved "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" dependencies: debug "~3.1.0" engine.io "~3.2.0" @@ -7393,25 +7075,26 @@ socket.io@^2.1.0: sort-keys@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" dependencies: is-plain-obj "^1.0.0" sort-object-keys@^1.1.1: version "1.1.2" - resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" + resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" sort-package-json@^1.4.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.11.0.tgz#b7b59ebdfaf3f8719ec0bc2056264e937868cbfb" + version "1.15.0" + resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.15.0.tgz#3c732cc8312eb4aa12f6eccab1bc3dea89b11dff" dependencies: + detect-indent "^5.0.0" sort-object-keys "^1.1.1" source-map-resolve@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a" + version "0.5.2" + resolved "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" dependencies: - atob "^2.0.0" + atob "^2.1.1" decode-uri-component "^0.2.0" resolve-url "^0.2.1" source-map-url "^0.4.0" @@ -7419,43 +7102,43 @@ source-map-resolve@^0.5.0: source-map-support@^0.2.10: version "0.2.10" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" dependencies: source-map "0.1.32" source-map-support@^0.4.15: version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" dependencies: source-map "^0.5.6" source-map-url@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" + resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" source-map-url@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" source-map@0.1.32: version "0.1.32" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" dependencies: amdefine ">=0.0.4" source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: version "0.4.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: amdefine ">=0.0.4" source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0, source-map@~0.5.1: version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" source-map@~0.1.x: version "0.1.43" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" dependencies: amdefine ">=0.0.4" @@ -7468,8 +7151,8 @@ sourcemap-codec@^1.4.1: resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.1.tgz#c8fd92d91889e902a07aee392bdd2c5863958ba2" sourcemap-validator@^1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/sourcemap-validator/-/sourcemap-validator-1.0.7.tgz#d76aaadbe2c6ec269293b5f212100fad91eef260" + version "1.1.0" + resolved "https://registry.npmjs.org/sourcemap-validator/-/sourcemap-validator-1.1.0.tgz#00454547d1682186e1498a7208e022e8dfa8738f" dependencies: jsesc "~0.3.x" lodash.foreach "~2.3.x" @@ -7478,163 +7161,147 @@ sourcemap-validator@^1.0.5: spawn-args@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" + resolved "https://registry.npmjs.org/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" spawn-sync@^1.0.11, spawn-sync@^1.0.15: version "1.0.15" - resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + resolved "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" dependencies: concat-stream "^1.4.7" os-shim "^0.1.2" spawnback@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" + resolved "https://registry.npmjs.org/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" spdx-correct@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" + resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" + resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" spdx-expression-parse@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + resolved "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" dependencies: extend-shallow "^3.0.0" sprintf-js@^1.0.3: version "1.1.1" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" sri-toolbox@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" - -sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jsbn "~0.1.0" - tweetnacl "~0.14.0" + resolved "https://registry.npmjs.org/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" stable@~0.1.3: - version "0.1.6" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10" + version "0.1.8" + resolved "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" static-extend@^0.1.1: version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + resolved "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" dependencies: define-property "^0.2.5" object-copy "^0.1.0" -"statuses@>= 1.3.1 < 2": - version "1.4.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" +"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" statuses@~1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" stream-consume@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.1.tgz#d3bdb598c2bd0ae82b8cac7ac50b1107a7996c48" + resolved "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz#d3bdb598c2bd0ae82b8cac7ac50b1107a7996c48" strict-uri-encode@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" string-template@~0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" -string-width@^1.0.1, string-width@^1.0.2: +string-width@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" -string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" dependencies: safe-buffer "~5.1.0" stringify-object-es5@^2.5.0: version "2.5.0" - resolved "https://registry.yarnpkg.com/stringify-object-es5/-/stringify-object-es5-2.5.0.tgz#057c3c9a90a127339bb9d1704a290bb7bd0a1ec5" + resolved "https://registry.npmjs.org/stringify-object-es5/-/stringify-object-es5-2.5.0.tgz#057c3c9a90a127339bb9d1704a290bb7bd0a1ec5" dependencies: is-plain-obj "^1.0.0" is-regexp "^1.0.0" stringmap@~0.2.2: version "0.2.2" - resolved "https://registry.yarnpkg.com/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" + resolved "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" stringset@~0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" + resolved "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" stringstream@~0.0.4: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - -strip-ansi@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" - dependencies: - ansi-regex "^0.2.1" + version "0.0.6" + resolved "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: ansi-regex "^2.0.0" strip-ansi@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" dependencies: ansi-regex "^3.0.0" @@ -7646,57 +7313,53 @@ strip-bom@^2.0.0: strip-bom@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" strip-eof@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" strip-indent@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" dependencies: get-stdin "^4.0.1" strip-json-comments@~2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" styled_string@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" + resolved "https://registry.npmjs.org/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" sum-up@^1.0.1: version "1.0.3" - resolved "https://registry.yarnpkg.com/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" + resolved "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" dependencies: chalk "^1.0.0" supports-color@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" - -supports-color@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" supports-color@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" supports-color@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" + version "5.4.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" dependencies: has-flag "^3.0.0" symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: version "1.2.0" - resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" + resolved "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" table@4.0.2: version "4.0.2" - resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" + resolved "https://registry.npmjs.org/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" dependencies: ajv "^5.2.3" ajv-keywords "^2.1.0" @@ -7707,7 +7370,7 @@ table@4.0.2: tap-parser@^5.1.0: version "5.4.0" - resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-5.4.0.tgz#6907e89725d7b7fa6ae41ee2c464c3db43188aec" + resolved "https://registry.npmjs.org/tap-parser/-/tap-parser-5.4.0.tgz#6907e89725d7b7fa6ae41ee2c464c3db43188aec" dependencies: events-to-array "^1.0.1" js-yaml "^3.2.7" @@ -7722,46 +7385,45 @@ tap-parser@^7.0.0: js-yaml "^3.2.7" minipass "^2.2.0" -tar-pack@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" - dependencies: - debug "^2.2.0" - fstream "^1.0.10" - fstream-ignore "^1.0.5" - once "^1.3.3" - readable-stream "^2.1.4" - rimraf "^2.5.1" - tar "^2.2.1" - uid-number "^0.0.6" - -tar@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" +tar@^4: + version "4.4.4" + resolved "https://registry.npmjs.org/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" + chownr "^1.0.1" + fs-minipass "^1.2.5" + minipass "^2.3.3" + minizlib "^1.1.0" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" temp@0.8.3: version "0.8.3" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" + resolved "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" dependencies: os-tmpdir "^1.0.0" rimraf "~2.2.6" +terser@^3.7.5: + version "3.7.6" + resolved "https://registry.npmjs.org/terser/-/terser-3.7.6.tgz#0b3c609f22278c089780ac1cdc63627071e3b96a" + dependencies: + commander "~2.14.1" + source-map "~0.6.1" + testdouble@^3.2.6: - version "3.5.2" - resolved "https://registry.yarnpkg.com/testdouble/-/testdouble-3.5.2.tgz#7ac91d08be05bac3b2acba57c430f6c62d0ad8af" + version "3.8.1" + resolved "https://registry.npmjs.org/testdouble/-/testdouble-3.8.1.tgz#8c74b6807f82fb07c2387a0640b4ae594b09b964" dependencies: es6-map "^0.1.5" lodash "^4.17.4" - quibble "^0.5.1" + quibble "^0.5.5" stringify-object-es5 "^2.5.0" + theredoc "^1.0.0" testem@^1.15.0: - version "1.18.4" - resolved "https://registry.yarnpkg.com/testem/-/testem-1.18.4.tgz#e45fed922bec2f54a616c43f11922598ac97eb41" + version "1.18.5" + resolved "https://registry.npmjs.org/testem/-/testem-1.18.5.tgz#912f3bfd4773519fa3cce0a8fd0e354763cbd545" dependencies: backbone "^1.1.2" bluebird "^3.4.6" @@ -7824,15 +7486,19 @@ testem@^2.0.0: text-table@~0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" "textextensions@1 || 2": version "2.2.0" - resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" + resolved "https://registry.npmjs.org/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" + +theredoc@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/theredoc/-/theredoc-1.0.0.tgz#bcace376af6feb1873efbdd0f91ed026570ff062" through@^2.3.6, through@^2.3.8, through@~2.3.8: version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" time-zone@^1.0.0: version "1.0.0" @@ -7840,11 +7506,11 @@ time-zone@^1.0.0: timed-out@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" tiny-lr@^1.0.3: version "1.1.1" - resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" + resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" dependencies: body "^5.1.0" debug "^3.1.0" @@ -7855,46 +7521,46 @@ tiny-lr@^1.0.3: tmp-sync@^1.0.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" + resolved "https://registry.npmjs.org/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" dependencies: fs-sync "^1.0.4" osenv "^0.1.0" tmp@0.0.28: version "0.0.28" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" dependencies: os-tmpdir "~1.0.1" tmp@0.0.31: version "0.0.31" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" dependencies: os-tmpdir "~1.0.1" tmp@^0.0.29: version "0.0.29" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" dependencies: os-tmpdir "~1.0.1" tmp@^0.0.33: version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" dependencies: os-tmpdir "~1.0.2" tmpl@1.0.x: version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" to-array@0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + resolved "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" to-fast-properties@^1.0.0, to-fast-properties@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" to-fast-properties@^2.0.0: version "2.0.0" @@ -7902,39 +7568,40 @@ to-fast-properties@^2.0.0: to-iso-string@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" + resolved "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" to-object-path@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" dependencies: kind-of "^3.0.2" to-regex-range@^2.1.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" dependencies: is-number "^3.0.0" repeat-string "^1.6.1" to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + resolved "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" dependencies: define-property "^2.0.2" extend-shallow "^3.0.2" regex-not "^1.0.2" safe-regex "^1.1.0" -tough-cookie@>=0.12.0, tough-cookie@~2.3.0: - version "2.3.4" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" +tough-cookie@>=0.12.0: + version "2.4.3" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" dependencies: + psl "^1.1.24" punycode "^1.4.1" tree-sync@^1.2.1, tree-sync@^1.2.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" + resolved "https://registry.npmjs.org/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" dependencies: debug "^2.2.0" fs-tree-diff "^0.5.6" @@ -7944,77 +7611,60 @@ tree-sync@^1.2.1, tree-sync@^1.2.2: trim-newlines@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" trim-right@^1.0.0, trim-right@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" try-resolve@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" + resolved "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" tryor@~0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" + resolved "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" tunnel-agent@~0.4.0: version "0.4.3" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" type-check@~0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" dependencies: prelude-ls "~1.1.2" type-detect@0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" type-detect@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" type-detect@^4.0.0: version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" -type-is@~1.6.15: +type-is@~1.6.15, type-is@~1.6.16: version "1.6.16" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" dependencies: media-typer "0.3.0" mime-types "~2.1.18" typedarray@^0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" - -uglify-es@^3.1.3: - version "3.3.9" - resolved "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" - dependencies: - commander "~2.13.0" - source-map "~0.6.1" + resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" uglify-js@^2.6, uglify-js@^2.7.0: version "2.8.29" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" + resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" dependencies: source-map "~0.5.1" yargs "~3.10.0" @@ -8023,34 +7673,30 @@ uglify-js@^2.6, uglify-js@^2.7.0: uglify-to-browserify@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" - -uid-number@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + resolved "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" ultron@1.0.x: version "1.0.2" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" + resolved "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" ultron@~1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + resolved "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" underscore.string@^3.2.2, underscore.string@~3.3.4: version "3.3.4" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" + resolved "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" dependencies: sprintf-js "^1.0.3" util-deprecate "^1.0.2" underscore@>=1.8.3: - version "1.8.3" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + version "1.9.1" + resolved "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" union-value@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + resolved "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" dependencies: arr-union "^3.1.0" get-value "^2.0.6" @@ -8059,67 +7705,65 @@ union-value@^1.0.0: unique-string@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + resolved "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" dependencies: crypto-random-string "^1.0.0" universalify@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" + version "0.1.2" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" unset-value@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + resolved "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" dependencies: has-value "^0.3.1" isobject "^3.0.0" untildify@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" + resolved "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" dependencies: os-homedir "^1.0.0" urix@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" url-parse-lax@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" dependencies: prepend-http "^2.0.0" url-to-options@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + resolved "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" url@0.10.3: version "0.10.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + resolved "https://registry.npmjs.org/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" dependencies: punycode "1.3.2" querystring "0.2.0" -use@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/use/-/use-2.0.2.tgz#ae28a0d72f93bf22422a18a2e379993112dec8e8" +use@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/use/-/use-3.1.0.tgz#14716bf03fdfefd03040aef58d8b4b85f3a7c544" dependencies: - define-property "^0.2.5" - isobject "^3.0.0" - lazy-cache "^2.0.2" + kind-of "^6.0.2" user-home@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + resolved "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" user-info@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/user-info/-/user-info-1.0.0.tgz#81c82b7ed63e674c2475667653413b3c76fde239" + resolved "https://registry.npmjs.org/user-info/-/user-info-1.0.0.tgz#81c82b7ed63e674c2475667653413b3c76fde239" dependencies: os-homedir "^1.0.1" passwd-user "^1.2.1" @@ -8127,86 +7771,78 @@ user-info@^1.0.0: username-sync@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/username-sync/-/username-sync-1.0.1.tgz#1cde87eefcf94b8822984d938ba2b797426dae1f" + resolved "https://registry.npmjs.org/username-sync/-/username-sync-1.0.1.tgz#1cde87eefcf94b8822984d938ba2b797426dae1f" username@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/username/-/username-1.0.1.tgz#e1f72295e3e58e06f002c6327ce06897a99cd67f" + resolved "https://registry.npmjs.org/username/-/username-1.0.1.tgz#e1f72295e3e58e06f002c6327ce06897a99cd67f" dependencies: meow "^3.4.0" util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" utils-merge@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" uuid@3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" uuid@^2.0.1: version "2.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" + resolved "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" uuid@^3.0.0: version "3.2.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" validate-npm-package-license@^3.0.1: version "3.0.3" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" + resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" dependencies: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" validate-npm-package-name@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" dependencies: builtins "^1.0.3" vary@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" walk-sync@0.3.2, walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" walk-sync@^0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" walk-sync@^0.2.5, walk-sync@^0.2.7: version "0.2.7" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" walker@~1.0.5: version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" dependencies: makeerror "1.0.x" watch-detector@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/watch-detector/-/watch-detector-0.1.0.tgz#e37b410d149e2a8bf263a4f8b71e2f667633dbf8" + resolved "https://registry.npmjs.org/watch-detector/-/watch-detector-0.1.0.tgz#e37b410d149e2a8bf263a4f8b71e2f667633dbf8" dependencies: heimdalljs-logger "^0.1.9" quick-temp "^0.1.8" @@ -8216,77 +7852,77 @@ watch-detector@^0.1.0: watch@~0.10.0: version "0.10.0" - resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" + resolved "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" watch@~0.18.0: version "0.18.0" - resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + resolved "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" dependencies: exec-sh "^0.2.0" minimist "^1.2.0" wcwidth@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" dependencies: defaults "^1.0.3" websocket-driver@>=0.5.1: version "0.7.0" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" + resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" dependencies: http-parser-js ">=0.4.0" websocket-extensions ">=0.1.1" websocket-extensions@>=0.1.1: version "0.1.3" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + version "1.3.1" + resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" dependencies: isexe "^2.0.0" wide-align@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + version "1.1.3" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" dependencies: - string-width "^1.0.2" + string-width "^1.0.2 || 2" window-size@0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" window-size@^0.1.2: version "0.1.4" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" + resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" wordwrap@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" wordwrap@~0.0.2: version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" wordwrap@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" workerpool@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-2.3.0.tgz#86c5cbe946b55e7dc9d12b1936c8801a6e2d744d" + resolved "https://registry.npmjs.org/workerpool/-/workerpool-2.3.0.tgz#86c5cbe946b55e7dc9d12b1936c8801a6e2d744d" dependencies: object-assign "4.1.1" wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" write-file-atomic@^1.1.2: version "1.3.4" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -8294,7 +7930,7 @@ write-file-atomic@^1.1.2: write-file-atomic@^2.0.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -8302,20 +7938,20 @@ write-file-atomic@^2.0.0: write@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + resolved "https://registry.npmjs.org/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" dependencies: mkdirp "^0.5.1" ws@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" + resolved "https://registry.npmjs.org/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" dependencies: options ">=0.0.5" ultron "1.0.x" ws@~3.3.1: version "3.3.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + resolved "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" dependencies: async-limiter "~1.0.0" safe-buffer "~5.1.0" @@ -8323,69 +7959,69 @@ ws@~3.3.1: wtf-8@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" + resolved "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" xdg-basedir@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" + resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" dependencies: os-homedir "^1.0.0" xdg-basedir@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" xml2js@0.4.17: version "0.4.17" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" + resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" dependencies: sax ">=0.6.0" xmlbuilder "^4.1.0" -xmlbuilder@4.2.1, xmlbuilder@^4.1.0: +xmlbuilder@^4.1.0: version "4.2.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" + resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" dependencies: lodash "^4.0.0" xmldom@^0.1.19: version "0.1.27" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" + resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" xmlhttprequest-ssl@1.5.3: version "1.5.3" - resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" + resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" xmlhttprequest-ssl@~1.5.4: version "1.5.5" - resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" xtend@^4.0.0, xtend@~4.0.0: version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" y18n@^3.2.0: version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" yallist@^2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" -yallist@^3.0.0: +yallist@^3.0.0, yallist@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" yam@^0.0.24: version "0.0.24" - resolved "https://registry.yarnpkg.com/yam/-/yam-0.0.24.tgz#11e9630444735f66a561d29221407de6d037cd95" + resolved "https://registry.npmjs.org/yam/-/yam-0.0.24.tgz#11e9630444735f66a561d29221407de6d037cd95" dependencies: fs-extra "^4.0.2" lodash.merge "^4.6.0" yargs@~3.10.0: version "3.10.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + resolved "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" dependencies: camelcase "^1.0.2" cliui "^2.1.0" @@ -8394,7 +8030,7 @@ yargs@~3.10.0: yargs@~3.27.0: version "3.27.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" + resolved "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" dependencies: camelcase "^1.2.1" cliui "^2.1.0" @@ -8405,17 +8041,17 @@ yargs@~3.27.0: yeast@0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + resolved "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" yui@^3.18.1: version "3.18.1" - resolved "https://registry.yarnpkg.com/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" + resolved "https://registry.npmjs.org/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" dependencies: request "~2.40.0" yuidocjs@^0.10.2: version "0.10.2" - resolved "https://registry.yarnpkg.com/yuidocjs/-/yuidocjs-0.10.2.tgz#33924967ce619024cd70ef694e267d2f988f73f6" + resolved "https://registry.npmjs.org/yuidocjs/-/yuidocjs-0.10.2.tgz#33924967ce619024cd70ef694e267d2f988f73f6" dependencies: express "^4.13.1" graceful-fs "^4.1.2" From cd99c94921e67ac512a8a43dad3ac0987f11b473 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 26 Jun 2018 12:36:14 -0700 Subject: [PATCH 2251/2527] [BUGFIX] allow for models with custom RecordData to have no relationships (#5503) * allow for 'no relationships' to be a thing * fix assignment --- .../system/model/internal-model.js | 33 ++++++++++--------- addon/-record-data-private/system/store.js | 2 +- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/addon/-record-data-private/system/model/internal-model.js b/addon/-record-data-private/system/model/internal-model.js index c18c6f7ddbe..e33265ffbd1 100644 --- a/addon/-record-data-private/system/model/internal-model.js +++ b/addon/-record-data-private/system/model/internal-model.js @@ -256,24 +256,27 @@ export default class InternalModel { // convert relationship Records to ModelDatas before passing to ModelData let defs = store._relationshipsDefinitionFor(this.modelName); - let keys = Object.keys(properties); - let relationshipValue; - for (let i = 0; i < keys.length; i++) { - let prop = keys[i]; - let def = defs[prop]; - - if (def !== undefined) { - if (def.kind === 'hasMany') { - if (DEBUG) { - assertRecordsPassedToHasMany(properties[prop]); + if (defs !== null) { + let keys = Object.keys(properties); + let relationshipValue; + + for (let i = 0; i < keys.length; i++) { + let prop = keys[i]; + let def = defs[prop]; + + if (def !== undefined) { + if (def.kind === 'hasMany') { + if (DEBUG) { + assertRecordsPassedToHasMany(properties[prop]); + } + relationshipValue = extractRecordDatasFromRecords(properties[prop]); + } else { + relationshipValue = extractRecordDataFromRecord(properties[prop]); } - relationshipValue = extractRecordDatasFromRecords(properties[prop]); - } else { - relationshipValue = extractRecordDataFromRecord(properties[prop]); - } - properties[prop] = relationshipValue; + properties[prop] = relationshipValue; + } } } } diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index fd255845a0e..be5d94f52bc 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -2727,7 +2727,7 @@ Store = Service.extend({ if (relationships === undefined) { let modelClass = this.modelFor(modelName); - relationships = get(modelClass, 'relationshipsObject'); + relationships = get(modelClass, 'relationshipsObject') || null; this._relationshipsDefCache[modelName] = relationships; } From efe9d61301b817f8ebe94d987b9f7519e5939cc3 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 27 Jun 2018 10:38:14 -0700 Subject: [PATCH 2252/2527] [CHORE] update broccoli-funnel --- package.json | 2 +- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4a620c61162..d1b7c65b26e 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "broccoli-babel-transpiler": "^6.0.0", "broccoli-debug": "^0.6.2", "broccoli-file-creator": "^1.0.0", - "broccoli-funnel": "^1.2.0", + "broccoli-funnel": "^2.0.1", "broccoli-merge-trees": "^2.0.0", "broccoli-rollup": "^2.1.0", "calculate-cache-key-for-tree": "^1.1.0", diff --git a/yarn.lock b/yarn.lock index fcaa5e2babe..4c0f503225c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1498,7 +1498,7 @@ broccoli-funnel-reducer@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" -broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.1.0, broccoli-funnel@^1.2.0: +broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.1.0: version "1.2.0" resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" dependencies: From ae2f6618ceb3b42fceefc6110e66866391ec8a9e Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 27 Jun 2018 10:40:54 -0700 Subject: [PATCH 2253/2527] bump deps to avoid deprecation warnings --- package.json | 8 ++++---- yarn.lock | 28 +++++++++++----------------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index d1b7c65b26e..0f803c95d2a 100644 --- a/package.json +++ b/package.json @@ -89,13 +89,13 @@ "ember-cli-release": "^0.2.9", "ember-cli-shims": "^1.0.2", "ember-cli-sri": "^2.1.0", - "ember-cli-test-loader": "^1.1.0", + "ember-cli-test-loader": "^2.2.0", "ember-cli-uglify": "2.0.0-beta.1", "ember-decorators": "^2.1.0", "ember-disable-prototype-extensions": "^1.1.0", - "ember-disable-proxy-controllers": "^1.0.0", - "ember-export-application-global": "^1.0.5", - "ember-load-initializers": "^0.6.0", + "ember-disable-proxy-controllers": "^1.0.1", + "ember-export-application-global": "^2.0.0", + "ember-load-initializers": "^1.1.0", "ember-maybe-import-regenerator": "^0.1.6", "ember-publisher": "0.0.7", "ember-qunit": "^3.4.0", diff --git a/yarn.lock b/yarn.lock index 4c0f503225c..8b6ee9d51aa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2617,7 +2617,7 @@ ember-cli-babel@6.12.0: ember-cli-version-checker "^2.1.0" semver "^5.4.1" -ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.6, ember-cli-babel@^5.2.1: +ember-cli-babel@^5.0.0: version "5.2.8" resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.8.tgz#0356b03cc3fdff5d0f2ecaa46a0e1cfaebffd876" dependencies: @@ -2627,7 +2627,7 @@ ember-cli-babel@^5.0.0, ember-cli-babel@^5.1.10, ember-cli-babel@^5.1.6, ember-c ember-cli-version-checker "^1.0.2" resolve "^1.1.2" -ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.12.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: +ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: version "6.14.1" resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.14.1.tgz#796339229035910b625593caffbc2683792ada68" dependencies: @@ -2842,12 +2842,6 @@ ember-cli-test-info@^1.0.0: dependencies: ember-cli-string-utils "^1.0.0" -ember-cli-test-loader@^1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/ember-cli-test-loader/-/ember-cli-test-loader-1.1.1.tgz#333311209b18185d0e0e95f918349da10cacf0b1" - dependencies: - ember-cli-babel "^5.2.1" - ember-cli-test-loader@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/ember-cli-test-loader/-/ember-cli-test-loader-2.2.0.tgz#3fb8d5d1357e4460d3f0a092f5375e71b6f7c243" @@ -2992,17 +2986,17 @@ ember-disable-prototype-extensions@^1.1.0: version "1.1.3" resolved "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" -ember-disable-proxy-controllers@^1.0.0: +ember-disable-proxy-controllers@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" dependencies: ember-cli-babel "^5.0.0" -ember-export-application-global@^1.0.5: - version "1.1.1" - resolved "https://registry.npmjs.org/ember-export-application-global/-/ember-export-application-global-1.1.1.tgz#f257d5271268932a89d7392679ce4db89d7154af" +ember-export-application-global@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ember-export-application-global/-/ember-export-application-global-2.0.0.tgz#8d6d7619ac8a1a3f8c43003549eb21ebed685bd2" dependencies: - ember-cli-babel "^5.1.10" + ember-cli-babel "^6.0.0-beta.7" ember-inflector@^2.0.0: version "2.3.0" @@ -3010,11 +3004,11 @@ ember-inflector@^2.0.0: dependencies: ember-cli-babel "^6.0.0" -ember-load-initializers@^0.6.0: - version "0.6.3" - resolved "https://registry.npmjs.org/ember-load-initializers/-/ember-load-initializers-0.6.3.tgz#f47396ad271ba77294068c98f992a5f19705441a" +ember-load-initializers@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/ember-load-initializers/-/ember-load-initializers-1.1.0.tgz#4edacc0f3a14d9f53d241ac3e5561804c8377978" dependencies: - ember-cli-babel "^5.1.6" + ember-cli-babel "^6.6.0" ember-maybe-import-regenerator@^0.1.6: version "0.1.6" From d69804ba4793d523d7e46a8bd510add173f37a89 Mon Sep 17 00:00:00 2001 From: Frederic ST Date: Thu, 28 Jun 2018 05:50:29 +1200 Subject: [PATCH 2254/2527] delete docs/ directory (#5507) --- docs/diagrams/Ember Data diagrams.graffle | 6032 --------------------- docs/images/ember-data-in-progress.png | Bin 32701 -> 0 bytes 2 files changed, 6032 deletions(-) delete mode 100644 docs/diagrams/Ember Data diagrams.graffle delete mode 100644 docs/images/ember-data-in-progress.png diff --git a/docs/diagrams/Ember Data diagrams.graffle b/docs/diagrams/Ember Data diagrams.graffle deleted file mode 100644 index 91fca23f489..00000000000 --- a/docs/diagrams/Ember Data diagrams.graffle +++ /dev/null @@ -1,6032 +0,0 @@ - - - - - ApplicationVersion - - com.omnigroup.OmniGrafflePro.MacAppStore - 138.33 - - CreationDate - 2012-02-08 00:47:44 +0000 - Creator - tomhuda - GraphDocumentVersion - 8 - GuidesLocked - NO - GuidesVisible - YES - ImageCounter - 1 - LinksVisible - NO - MagnetsVisible - NO - MasterSheets - - ModificationDate - 2012-04-17 22:16:22 +0000 - Modifier - tomhuda - NotesVisible - NO - OriginVisible - NO - PageBreaks - YES - PrintInfo - - NSBottomMargin - - float - 41 - - NSHorizonalPagination - - int - 0 - - NSLeftMargin - - float - 18 - - NSPaperSize - - coded - BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAx7X05TU2l6ZT1mZn2WgWQCgRgDhg== - - NSPrintReverseOrientation - - int - 0 - - NSRightMargin - - float - 18 - - NSTopMargin - - float - 18 - - - ReadOnly - NO - Sheets - - - ActiveLayerIndex - 0 - AutoAdjust - - BackgroundGraphic - - Bounds - {{0, 0}, {1466, 1152}} - Class - SolidGraphic - ID - 2 - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - - CanvasOrigin - {0, 0} - ColumnAlign - 1 - ColumnSpacing - 36 - DisplayScale - 1 0/72 in = 1.0000 in - GraphicsList - - - Class - LineGraphic - Head - - ID - 81 - - ID - 82 - Points - - {142.6377, 908.26709} - {211.87775, 841.95874} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 77 - - - - Class - TableGroup - Graphics - - - Bounds - {{174.54837, 813.61292}, {90, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 80 - Shape - Rectangle - Style - - fill - - GradientCenter - {-0.29411799, -0.26470599} - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc - -\f0\b\fs24 \cf0 Post 2} - VerticalPad - 0 - - TextPlacement - 0 - - - Bounds - {{174.54837, 827.61292}, {90, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 81 - Shape - Rectangle - Style - - fill - - GradientCenter - {-0.29411799, -0.26470599} - - - Text - - Align - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 - -\f0\fs24 \cf0 isLoaded} - VerticalPad - 0 - - TextPlacement - 0 - - - GridH - - 80 - 81 - - - ID - 79 - - - Class - TableGroup - Graphics - - - Bounds - {{89.967072, 908.61292}, {90, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 77 - Shape - Rectangle - Style - - fill - - GradientCenter - {-0.29411799, -0.26470599} - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc - -\f0\b\fs24 \cf0 Comment} - VerticalPad - 0 - - TextPlacement - 0 - - - Bounds - {{89.967072, 922.61292}, {90, 28}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 78 - Shape - Rectangle - Style - - fill - - GradientCenter - {-0.29411799, -0.26470599} - - - Text - - Align - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 - -\f0\fs24 \cf0 isLoaded\ -i} - VerticalPad - 0 - - TextPlacement - 0 - - - GridH - - 77 - 78 - - - ID - 76 - - - Class - TableGroup - Graphics - - - Bounds - {{22.948357, 813.61292}, {90, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 74 - Shape - Rectangle - Style - - fill - - GradientCenter - {-0.29411799, -0.26470599} - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc - -\f0\b\fs24 \cf0 Post 1} - VerticalPad - 0 - - TextPlacement - 0 - - - Bounds - {{22.948357, 827.61292}, {90, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 75 - Shape - Rectangle - Style - - fill - - GradientCenter - {-0.29411799, -0.26470599} - - - Text - - Align - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 - -\f0\fs24 \cf0 isLoaded} - VerticalPad - 0 - - TextPlacement - 0 - - - GridH - - 74 - 75 - - - ID - 73 - - - Class - LineGraphic - Head - - ID - 40 - - ID - 72 - Points - - {127.8566, 720.22766} - {73.058868, 653.99817} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 42 - - - - Class - TableGroup - Graphics - - - Bounds - {{173.54837, 625.61292}, {90, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 46 - Shape - Rectangle - Style - - fill - - GradientCenter - {-0.29411799, -0.26470599} - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc - -\f0\b\fs24 \cf0 Post 2} - VerticalPad - 0 - - TextPlacement - 0 - - - Bounds - {{173.54837, 639.61292}, {90, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 47 - Shape - Rectangle - Style - - fill - - GradientCenter - {-0.29411799, -0.26470599} - - - Text - - Align - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 - -\f0\fs24 \cf0 isLoaded} - VerticalPad - 0 - - TextPlacement - 0 - - - GridH - - 46 - 47 - - - ID - 45 - - - Class - TableGroup - Graphics - - - Bounds - {{88.967072, 720.61292}, {90.000008, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 42 - Shape - Rectangle - Style - - fill - - GradientCenter - {-0.29411799, -0.26470599} - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc - -\f0\b\fs24 \cf0 Comment} - VerticalPad - 0 - - TextPlacement - 0 - - - Bounds - {{88.967072, 734.61292}, {90.000008, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 43 - Shape - Rectangle - Style - - fill - - GradientCenter - {-0.29411799, -0.26470599} - - - Text - - Align - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 - -\f0\fs24 \cf0 isLoaded} - VerticalPad - 0 - - TextPlacement - 0 - - - GridH - - 42 - 43 - - - ID - 41 - - - Class - TableGroup - Graphics - - - Bounds - {{21.948357, 625.61292}, {90, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 39 - Shape - Rectangle - Style - - fill - - GradientCenter - {-0.29411799, -0.26470599} - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc - -\f0\b\fs24 \cf0 Post 1} - VerticalPad - 0 - - TextPlacement - 0 - - - Bounds - {{21.948357, 639.61292}, {90, 14}} - Class - ShapedGraphic - FitText - Vertical - Flow - Resize - ID - 40 - Shape - Rectangle - Style - - fill - - GradientCenter - {-0.29411799, -0.26470599} - - - Text - - Align - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 - -\f0\fs24 \cf0 isLoaded} - VerticalPad - 0 - - TextPlacement - 0 - - - GridH - - 39 - 40 - - - ID - 38 - - - Class - TableGroup - Graphics - - - Bounds - {{29.639343, 27.251616}, {200.23227, 31.438694}} - Class - ShapedGraphic - ID - 5 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Type} - - - - Bounds - {{29.639343, 58.690308}, {200.23227, 31.438694}} - Class - ShapedGraphic - ID - 6 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Has Many /\ -Belongs To} - - - - Bounds - {{29.639343, 90.128998}, {200.23227, 31.43869}} - Class - ShapedGraphic - ID - 24 - Shape - Rectangle - - - Bounds - {{29.639343, 121.5677}, {200.23227, 31.438698}} - Class - ShapedGraphic - ID - 22 - Shape - Rectangle - - - Bounds - {{29.639343, 153.00641}, {200.23227, 31.438675}} - Class - ShapedGraphic - ID - 21 - Shape - Rectangle - - - Bounds - {{29.639343, 184.44507}, {200.23227, 31.438705}} - Class - ShapedGraphic - ID - 10 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Has and Belongs To Many} - - - - Bounds - {{229.8716, 90.128998}, {200.23227, 31.43869}} - Class - ShapedGraphic - ID - 11 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 New Post adds existing Tag} - - - - Bounds - {{229.8716, 184.44507}, {200.23227, 31.438705}} - Class - ShapedGraphic - ID - 12 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Existing Tag added to two new Posts} - - - - Bounds - {{229.8716, 58.690308}, {200.23227, 31.438694}} - Class - ShapedGraphic - ID - 13 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Existing Post adds existing Tag} - - - - Bounds - {{229.8716, 27.251616}, {200.23227, 31.438694}} - Class - ShapedGraphic - ID - 14 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Examples} - - - - Bounds - {{229.8716, 121.5677}, {200.23227, 31.438698}} - Class - ShapedGraphic - ID - 15 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Existing Post adds new Tag} - - - - Bounds - {{229.8716, 153.00641}, {200.23227, 31.438675}} - Class - ShapedGraphic - ID - 16 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 New Post adds new Tag} - - - - Bounds - {{29.639343, 215.88376}, {200.23227, 31.438705}} - Class - ShapedGraphic - ID - 25 - Shape - Rectangle - - - Bounds - {{229.8716, 215.88376}, {200.23227, 31.438705}} - Class - ShapedGraphic - ID - 26 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 New Tag added to two new Posts} - - - - Bounds - {{29.639343, 247.32248}, {200.23227, 31.438705}} - Class - ShapedGraphic - ID - 27 - Shape - Rectangle - - - Bounds - {{229.8716, 247.32248}, {200.23227, 31.438705}} - Class - ShapedGraphic - ID - 28 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Existing Tag added to two new Posts} - - - - Bounds - {{229.8716, 278.76117}, {200.23227, 31.438705}} - Class - ShapedGraphic - ID - 29 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 New Tag added to one new Post and one existing Post} - - - - Bounds - {{29.639343, 278.76117}, {200.23227, 31.438705}} - Class - ShapedGraphic - ID - 30 - Shape - Rectangle - - - Bounds - {{29.639343, 310.19989}, {200.23227, 31.43869}} - Class - ShapedGraphic - ID - 31 - Shape - Rectangle - - - Bounds - {{229.8716, 310.19989}, {200.23227, 31.43869}} - Class - ShapedGraphic - ID - 32 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Existing Tag added to one new Post and one existing Post} - - - - Bounds - {{29.639343, 341.63861}, {200.23227, 31.43869}} - Class - ShapedGraphic - ID - 33 - Shape - Rectangle - - - Bounds - {{229.8716, 341.63861}, {200.23227, 31.43869}} - Class - ShapedGraphic - ID - 34 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 New Tag added to two existing Posts} - - - - Bounds - {{229.8716, 373.07727}, {200.23227, 31.43869}} - Class - ShapedGraphic - ID - 35 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Existing Tag added to two existing Posts} - - - - Bounds - {{29.639343, 373.07727}, {200.23227, 31.43869}} - Class - ShapedGraphic - ID - 36 - Shape - Rectangle - - - GridH - - - 5 - 14 - - - 6 - 13 - - - 24 - 11 - - - 22 - 15 - - - 21 - 16 - - - 10 - 12 - - - 25 - 26 - - - 27 - 28 - - - 29 - 30 - - - 31 - 32 - - - 33 - 34 - - - 35 - 36 - - - - GridV - - - 5 - 6 - 24 - 22 - 21 - 10 - 25 - 27 - 30 - 31 - 33 - 36 - - - 11 - 12 - 13 - 14 - 15 - 16 - 26 - 28 - 29 - 32 - 34 - 35 - - - - ID - 4 - - - GridInfo - - HPages - 2 - KeepToScale - - Layers - - - Lock - NO - Name - Layer 1 - Print - YES - View - YES - - - LayoutInfo - - Animate - NO - circoMinDist - 18 - circoSeparation - 0.0 - layoutEngine - dot - neatoSeparation - 0.0 - twopiSeparation - 0.0 - - Orientation - 1 - PrintOnePage - - RowAlign - 1 - RowSpacing - 36 - SheetTitle - Canvas 1 - UniqueID - 1 - VPages - 2 - - - ActiveLayerIndex - 0 - AutoAdjust - - BackgroundGraphic - - Bounds - {{0, 0}, {1466, 1152}} - Class - SolidGraphic - ID - 2 - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - - CanvasOrigin - {0, 0} - ColumnAlign - 1 - ColumnSpacing - 36 - DisplayScale - 1 0/72 in = 1.0000 in - GraphicsList - - - Class - LineGraphic - Head - - ID - 38 - - ID - 39 - Points - - {776.41559, 573.5} - {776.48346, 706.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 36 - - - - Bounds - {{674, 707}, {205, 64}} - Class - ShapedGraphic - ID - 38 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 items moved out of pending are now saved} - - - - Class - LineGraphic - Head - - ID - 36 - - ID - 37 - Points - - {776.48346, 375.5} - {776.41559, 508.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 27 - - - - Bounds - {{673.89905, 509}, {205, 64}} - Class - ShapedGraphic - ID - 36 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 customer didCreate\ -customer isLoaded\ -party waitingOn=[] not isPending} - - - - Bounds - {{1161, 229.00244}, {121, 28}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - ID - 35 - Shape - Rectangle - Style - - fill - - Draws - NO - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Align - 0 - Pad - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural - -\f0\fs24 \cf0 when isPending, not in\ -the list of dirty models} - VerticalPad - 0 - - Wrap - NO - - - Bounds - {{943, 186.00243}, {205, 118}} - Class - ShapedGraphic - ID - 34 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Party\ -isNew\ -isPending\ -\ -waitingOn=[customer]} - - - - Bounds - {{943, 22}, {205, 118}} - Class - ShapedGraphic - ID - 33 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Customer\ -isNew} - - - - Bounds - {{733, 233.00243}, {87, 24}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 12 - - ID - 30 - Line - - ID - 29 - Position - 0.50753706693649292 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 store.commit()} - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 27 - - ID - 29 - Points - - {776.5, 177.5} - {776.5, 310.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 25 - - - - Bounds - {{674, 311}, {205, 64}} - Class - ShapedGraphic - ID - 27 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 commit customer\ -\ -customer => isSaving} - - - - Bounds - {{444.79541, 43}, {147, 14}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - ID - 26 - Shape - Rectangle - Style - - fill - - Draws - NO - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Party belongsTo(Customer)} - VerticalPad - 0 - - Wrap - NO - - - Bounds - {{674, 113}, {205, 64}} - Class - ShapedGraphic - ID - 25 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 customer = store.create(Customer)\ -party = customer.parties.build()} - - - - Bounds - {{459.29541, 225.00388}, {118, 24}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 12 - - ID - 24 - Line - - ID - 22 - Position - 0.44739758968353271 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 party.get('customer')} - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 21 - - ID - 22 - Points - - {519.07452, 177.49995} - {517.33313, 310.50003} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 19 - - - - Bounds - {{414.40765, 311}, {205, 64}} - Class - ShapedGraphic - ID - 21 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 return null} - - - - Bounds - {{417, 113}, {205, 64}} - Class - ShapedGraphic - ID - 19 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Party hash loaded\ -customer_id is null} - - - - Bounds - {{273.01114, 445.54449}, {171, 24}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 12 - - ID - 17 - Line - - ID - 16 - Position - 0.40274342894554138 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 store.load(Customer, id, hash)} - - Wrap - NO - - - Class - LineGraphic - ControlPoints - - {22.999512, -35.678528} - {-1, 37} - {1, -37} - {27.607697, 31.690033} - - Head - - ID - 9 - - ID - 16 - Points - - {294.6972, 508.6456} - {364.99985, 438} - {297.39301, 375.33987} - - Style - - stroke - - Bezier - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 13 - - - - Bounds - {{187.99994, 412.00238}, {149, 24}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 12 - - ID - 15 - Line - - ID - 14 - Position - 0.36467960476875305 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 adapter.find(Customer, id)} - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 13 - - ID - 14 - Points - - {262.49997, 375.5} - {262.49988, 508.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 9 - - - - Bounds - {{159.99985, 509}, {205, 64}} - Class - ShapedGraphic - ID - 13 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 make HTTP request} - - - - Bounds - {{203.5, 223}, {118, 24}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 12 - - ID - 12 - Line - - ID - 10 - Position - 0.43233081698417664 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 party.get('customer')} - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 9 - - ID - 10 - Points - - {262.5, 177.5} - {262.5, 310.5} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 3 - - - - Bounds - {{160, 311}, {205, 64}} - Class - ShapedGraphic - ID - 9 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 return Customer\ -ask adapter for Customer} - - - - Bounds - {{160, 113}, {205, 64}} - Class - ShapedGraphic - ID - 3 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 Party hash loaded\ -customer_id in hash} - - - - GridInfo - - HPages - 2 - KeepToScale - - Layers - - - Lock - NO - Name - Layer 1 - Print - YES - View - YES - - - LayoutInfo - - Animate - NO - circoMinDist - 18 - circoSeparation - 0.0 - layoutEngine - dot - neatoSeparation - 0.0 - twopiSeparation - 0.0 - - Orientation - 1 - PrintOnePage - - RowAlign - 1 - RowSpacing - 36 - SheetTitle - hasOne/belongsTo - UniqueID - 2 - VPages - 2 - - - ActiveLayerIndex - 0 - AutoAdjust - - BackgroundGraphic - - Bounds - {{0, 0}, {1466, 1728}} - Class - SolidGraphic - ID - 2 - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - - CanvasOrigin - {0, 0} - ColumnAlign - 1 - ColumnSpacing - 36 - DisplayScale - 1 0/72 in = 1.0000 in - GraphicsList - - - Bounds - {{750.79596, 1236.792}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 53 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 by: store\ -\ -didDeleteRecords\ -didDeleteRecord} - - - - Bounds - {{556.79596, 1444.792}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 12 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 doneWaitingOn} - - - - Bounds - {{556.79596, 1340.792}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 10 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 waitingOn} - - - - Bounds - {{556.79596, 1236.792}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 15 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 didDelete} - - - - Bounds - {{750.79596, 1132.792}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 51 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 by: store\ -\ -didUpdateRecord\ -didCreateRecord\ -didCreateRecords} - - - - Bounds - {{556.79596, 1132.792}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 14 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 didUpdate} - - - - Bounds - {{750.79596, 1028.792}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 49 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 by: store\ -recordWasInvalid} - - - - Bounds - {{556.79596, 1028.792}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 13 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 wasInvalid} - - - - Bounds - {{750.79596, 924.79199}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 47 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 by: store\ -\ -load\ -before setData} - - - - Bounds - {{556.79596, 924.79199}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 11 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 willLoadData} - - - - Bounds - {{750.79596, 820.79199}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 45 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 by: store\ -\ -createModel\ -materializing model} - - - - Bounds - {{556.79596, 820.79199}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 9 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 loadingData} - - - - Bounds - {{750.79596, 716.79199}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 43 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 by: store\ -createRecord} - - - - Bounds - {{556.79596, 716.79199}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 8 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 didCreate} - - - - Bounds - {{750.79596, 612.79199}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 35 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 by: store\ -when materializing\ -\ -findByClientId\ -load} - - - - Bounds - {{556.79596, 612.79199}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 7 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 setData} - - - - Bounds - {{750.79596, 508.79199}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 33 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 by: DS.attr\ -in the setter} - - - - Bounds - {{556.79596, 508.79199}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 6 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 setProperty} - - - - Bounds - {{750.79596, 404.79199}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 25 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 by: store\ -app deletes} - - - - Bounds - {{556.79596, 404.79199}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 5 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 delete} - - - - Bounds - {{750.79596, 300.79199}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 23 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 by: states\ -exiting dirty state} - - - - Bounds - {{556.79596, 300.79199}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 4 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 notifyModel} - - - - Bounds - {{750.79596, 196.79201}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 17 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 by: adapter\ -\ -via store-provided iterator\ -committing} - - - - Bounds - {{556.79596, 196.79201}, {158.40001, 86.400002}} - Class - ShapedGraphic - ID - 3 - Shape - Rectangle - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs24 \cf0 willCommit} - - - - Class - LineGraphic - Head - - ID - 17 - - ID - 18 - Points - - {715.69598, 239.98952} - {750.29596, 239.98843} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 3 - - - - Class - LineGraphic - Head - - ID - 23 - - ID - 24 - Points - - {715.69598, 343.98947} - {750.29596, 343.9884} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 4 - - - - Class - LineGraphic - Head - - ID - 25 - - ID - 26 - Points - - {715.69598, 447.98947} - {750.29596, 447.9884} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 5 - - - - Class - LineGraphic - Head - - ID - 33 - - ID - 34 - Points - - {715.69598, 551.98944} - {750.29596, 551.98834} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 6 - - - - Class - LineGraphic - Head - - ID - 35 - - ID - 36 - Points - - {715.69598, 655.98944} - {750.29596, 655.98834} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 7 - - - - Class - LineGraphic - Head - - ID - 43 - - ID - 44 - Points - - {715.69598, 759.98944} - {750.29596, 759.98834} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 8 - - - - Class - LineGraphic - Head - - ID - 45 - - ID - 46 - Points - - {715.69598, 863.98944} - {750.29596, 863.98834} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 9 - - - - Class - LineGraphic - Head - - ID - 47 - - ID - 48 - Points - - {715.69598, 967.99115} - {750.29596, 967.99078} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 11 - - - - Class - LineGraphic - Head - - ID - 49 - - ID - 50 - Points - - {715.69598, 1071.9934} - {750.29596, 1071.994} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 13 - - - - Class - LineGraphic - Head - - ID - 51 - - ID - 52 - Points - - {715.69598, 1175.9934} - {750.29596, 1175.994} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 14 - - - - Class - LineGraphic - Head - - ID - 53 - - ID - 54 - Points - - {715.69598, 1279.9934} - {750.29596, 1279.994} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 15 - - - - GridInfo - - HPages - 2 - KeepToScale - - Layers - - - Lock - NO - Name - Layer 1 - Print - YES - View - YES - - - LayoutInfo - - Animate - NO - AutoLayout - 2 - HierarchicalOrientation - 0 - circoMinDist - 18 - circoSeparation - 0.0 - layoutEngine - dot - neatoSeparation - 0.0 - twopiSeparation - 0.0 - - Orientation - 1 - PrintOnePage - - RowAlign - 1 - RowSpacing - 36 - SheetTitle - Canvas 3 - UniqueID - 3 - VPages - 3 - - - ActiveLayerIndex - 0 - AutoAdjust - - BackgroundGraphic - - Bounds - {{0, 0}, {1466, 1728}} - Class - SolidGraphic - FontInfo - - Font - Helvetica - Size - 11 - - ID - 2 - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - - CanvasOrigin - {0, 0} - ColumnAlign - 1 - ColumnSpacing - 36 - DisplayScale - 1 0/72 in = 1.0000 in - GraphicsList - - - Bounds - {{527.79272, 318.95544}, {57, 21}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 73 - Line - - ID - 72 - Position - 0.68339651823043823 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 didRollback} - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 35 - - ID - 72 - Points - - {566.69312, 394.24487} - {551.47443, 299.43985} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 17 - - - - Bounds - {{701.57288, 91.389076}, {112.49997, 52.5}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 71 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs26 \cf0 error} - - - - Bounds - {{663.58777, 833.24249}, {43, 15}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 70 - Line - - ID - 69 - Position - 0.45133817195892334 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 2 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 didDelete} - VerticalPad - 2 - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 63 - - ID - 69 - Points - - {653.06879, 840.74249} - {724.01111, 840.74249} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 62 - - - - Bounds - {{473.06424, 833.24249}, {48, 15}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 68 - Line - - ID - 67 - Position - 0.40505129098892212 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 2 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 willCommit} - VerticalPad - 2 - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 62 - - ID - 67 - Points - - {468.1264, 840.74249} - {539.56879, 840.74249} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 64 - - - - Bounds - {{410.83997, 321.18542}, {35, 21}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 66 - Line - - ID - 65 - Position - 0.15360260009765625 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 delete} - - Wrap - NO - - - Class - LineGraphic - ControlPoints - - {-150.56992, 78.851074} - {-138.70332, -59.973206} - - Head - - ID - 64 - Info - 4 - - ID - 65 - Points - - {495.22443, 273.18985} - {355.6264, 840.74249} - - Style - - stroke - - Bezier - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 35 - Info - 4 - - - - Bounds - {{355.62643, 814.49249}, {112.49997, 52.5}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 64 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs26 \cf0 start} - - - - Bounds - {{724.51111, 814.49249}, {112.49997, 52.5}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 63 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs26 \cf0 saved} - - - - Bounds - {{540.06879, 814.49249}, {112.49997, 52.5}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 62 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs26 \cf0 saving} - - - - Bounds - {{331.66327, 760.00995}, {519.33472, 139.47375}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 61 - Magnets - - {-0.47074008, -0.31451178} - - Shape - Rectangle - Style - - Text - - Align - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural - -\f0\fs26 \cf0 deleted} - - TextPlacement - 0 - - - Bounds - {{513.04779, 178.80846}, {90, 15}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 60 - Line - - ID - 59 - Position - 0.40897589921951294 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 2 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 setData->loadedData} - VerticalPad - 2 - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 35 - - ID - 59 - Points - - {562.59644, 144.35286} - {551.47443, 246.93983} - - Style - - stroke - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 10 - - - - Bounds - {{336.71387, 280.45663}, {36, 15}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 58 - Line - - ID - 56 - Position - 0.37786188721656799 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 2 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 setData} - VerticalPad - 2 - - Wrap - NO - - - Class - LineGraphic - ControlPoints - - {0, 116.88016} - {-193.13083, 18.796387} - - Head - - ID - 16 - Info - 1 - - ID - 56 - Points - - {357.02802, 143.8891} - {510.4201, 417.81549} - - Style - - stroke - - Bezier - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 5 - - - - Bounds - {{750.69751, 367.15741}, {110, 15}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 55 - Line - - ID - 54 - Position - 0.34351608157157898 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 2 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 setProperty->becameValid} - VerticalPad - 2 - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 17 - - ID - 54 - Points - - {894.71777, 405.67636} - {799.23083, 374.61542} - {623.06561, 410.3493} - - Style - - stroke - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 23 - - - - Bounds - {{596.83459, 512.82654}, {60, 21}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 53 - Line - - ID - 52 - Position - 0.40613371133804321 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 doneWaiting} - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 17 - - ID - 52 - Points - - {596.2926, 576.21649} - {627.22418, 515.55969} - {586.26611, 446.64499} - - Style - - stroke - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 21 - - - - Bounds - {{551.0542, 496.25592}, {51, 21}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 48 - Line - - ID - 47 - Position - 0.46240440011024475 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 waitingOn} - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 21 - - ID - 47 - Points - - {572.71234, 447.65259} - {581.02081, 575.46997} - - Style - - stroke - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 17 - - - - Bounds - {{647.35614, 495.69312}, {60, 21}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 46 - Line - - ID - 45 - Position - 0.54053938388824463 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 doneWaiting} - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 17 - - ID - 45 - Points - - {769.45844, 579.26044} - {599.06879, 444.08563} - - Style - - stroke - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 22 - - - - Bounds - {{655.89526, 591.70239}, {54, 21}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 43 - Line - - ID - 42 - Position - 0.42326962947845459 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 willCommit} - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 22 - - ID - 42 - Points - - {639.7912, 602.20239} - {741.62714, 602.20239} - - Style - - stroke - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 21 - - - - Bounds - {{821.13397, 413.38153}, {47, 15}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 41 - Line - - ID - 40 - Position - 0.44253307580947876 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 2 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 wasInvalid} - VerticalPad - 2 - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 23 - - ID - 40 - Points - - {812.91046, 420.89377} - {884.59662, 420.86612} - - Style - - stroke - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 18 - - - - Bounds - {{636.5033, 317.2066}, {52, 21}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 12 - - ID - 37 - Line - - ID - 36 - Position - 0.5589253306388855 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 didUpdate} - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 35 - - ID - 36 - Points - - {731.91852, 396.7897} - {607.72443, 273.18985} - - Style - - stroke - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 18 - - - - Bounds - {{495.22443, 246.93985}, {112.49997, 52.5}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 35 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs26 \cf0 saved} - - - - Bounds - {{633.52472, 413.44717}, {48, 15}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 34 - Line - - ID - 31 - Position - 0.41570550203323364 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 2 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 willCommit} - VerticalPad - 2 - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 18 - - ID - 31 - Points - - {627.72443, 420.93631} - {699.41052, 420.96243} - - Style - - stroke - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 17 - - - - Bounds - {{885.09662, 394.59424}, {112.49997, 52.5}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 23 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs26 \cf0 invalid} - - - - Bounds - {{742.12714, 575.95239}, {112.49997, 52.5}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 22 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs26 \cf0 saving} - - - - Bounds - {{526.7912, 575.95239}, {112.49997, 52.5}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 21 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs26 \cf0 start} - - - - Bounds - {{514.72443, 542.39136}, {364.49646, 104.58447}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 20 - Shape - Rectangle - Style - - Text - - Align - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural - -\f0\fs26 \cf0 pending} - - TextPlacement - 0 - - - Bounds - {{699.91046, 394.66565}, {112.49997, 52.5}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 18 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs26 \cf0 inFlight} - - - - Bounds - {{514.72443, 394.66565}, {112.49997, 52.5}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 17 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs26 \cf0 start} - - - - Bounds - {{495.22443, 356.91315}, {519.33472, 328.33527}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 16 - Magnets - - {-0.47074008, -0.31451178} - - Shape - Rectangle - Style - - Text - - Align - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural - -\f0\fs26 \cf0 created} - - TextPlacement - 0 - - - Bounds - {{429.14441, 110.13908}, {53, 15}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 12 - - ID - 14 - Line - - ID - 13 - Position - 0.44379192590713501 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Pad - 2 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 loadingData} - VerticalPad - 2 - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 10 - - ID - 13 - Points - - {413.27802, 117.63908} - {508.74258, 117.63908} - - Style - - stroke - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 5 - - - - Bounds - {{465.60791, 208.2534}, {576.01892, 506.15411}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 12 - Shape - Rectangle - Style - - Text - - Align - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural - -\f0\fs26 \cf0 loaded} - - TextPlacement - 0 - - - Bounds - {{509.24261, 91.389084}, {112.49997, 52.5}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 10 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs26 \cf0 loading} - - - - Class - LineGraphic - Head - - ID - 5 - - ID - 9 - Points - - {306.7373, 75.92234} - {309.77802, 85.889099} - {316.45663, 98.901741} - - Style - - stroke - - HeadArrow - FilledArrow - HopLines - - HopType - 1 - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 7 - - - - Bounds - {{300.77802, 66.639099}, {9, 9}} - Class - ShapedGraphic - ID - 7 - Shape - Circle - Style - - fill - - Color - - b - 0 - g - 0 - r - 0 - - - - - - Bounds - {{300.77802, 91.389084}, {112.49997, 52.5}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 5 - Magnets - - {0, 1} - {0, -1} - {1, 0} - {-1, 0} - {-0.35226268, -0.32194734} - - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs26 \cf0 empty} - - - - Bounds - {{270, 36}, {837, 1089}} - Class - ShapedGraphic - FontInfo - - Font - Helvetica - Size - 12 - - ID - 3 - Shape - Rectangle - Style - - Text - - Align - 0 - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural - -\f0\fs26 \cf0 root} - - TextPlacement - 0 - - - GridInfo - - HPages - 2 - KeepToScale - - Layers - - - Lock - NO - Name - Layer 1 - Print - YES - View - YES - - - LayoutInfo - - Animate - NO - HierarchicalOrientation - 0 - circoMinDist - 18 - circoSeparation - 0.0 - layoutEngine - dot - neatoSeparation - 0.0 - twopiSeparation - 0.0 - - Orientation - 1 - PrintOnePage - - RowAlign - 1 - RowSpacing - 36 - SheetTitle - Canvas 4 - UniqueID - 4 - VPages - 3 - - - ActiveLayerIndex - 0 - AutoAdjust - - BackgroundGraphic - - Bounds - {{0, 0}, {1466, 1728}} - Class - SolidGraphic - ID - 2 - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - - CanvasOrigin - {0, 0} - ColumnAlign - 1 - ColumnSpacing - 36 - DisplayScale - 1 0/72 in = 1.0000 in - GraphicsList - - - Bounds - {{503.69226, 443.26892}, {28, 21}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 22 - Line - - ID - 21 - Position - 0.39902853965759277 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 load} - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 20 - - ID - 21 - Points - - {476.65378, 453.76892} - {579.49976, 453.76892} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 16 - - - - Bounds - {{579.99976, 384.92276}, {137.69232, 137.69232}} - Class - ShapedGraphic - ID - 20 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 setData} - - - - Bounds - {{252.92319, 443.2688}, {48, 21}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 19 - Line - - ID - 17 - Position - 0.40650826692581177 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 not found} - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 16 - - ID - 17 - Points - - {235.11548, 453.76886} - {337.9614, 453.76874} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 13 - - - - Bounds - {{338.46143, 384.92276}, {137.69232, 137.69232}} - Class - ShapedGraphic - ID - 16 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 insert null in data cache\ -materializeRecord} - - - - Bounds - {{489.92053, 241.4231}, {66, 21}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 15 - Line - - ID - 14 - Position - 0.44986462593078613 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 findByClientId} - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 10 - - ID - 14 - Points - - {476.65378, 251.9231} - {579.49976, 251.92308} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 6 - - - - Bounds - {{96.923119, 384.92276}, {137.69232, 137.69232}} - Class - ShapedGraphic - ID - 13 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 findByClientId} - - - - Bounds - {{579.99976, 183.07692}, {137.69232, 137.69232}} - Class - ShapedGraphic - ID - 10 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 materializeRecord\ -setData} - - - - Bounds - {{245.44879, 235.92314}, {59, 32}} - Class - ShapedGraphic - FitText - YES - Flow - Resize - FontInfo - - Color - - w - 0 - - Font - Helvetica - Size - 9 - - ID - 9 - Line - - ID - 7 - Position - 0.3873106837272644 - RotationType - 0 - - Shape - Rectangle - Style - - shadow - - Draws - NO - - stroke - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 record not\ -materialized} - - Wrap - NO - - - Class - LineGraphic - Head - - ID - 6 - - ID - 7 - Points - - {235.11546, 251.92313} - {337.9614, 251.92317} - - Style - - stroke - - HeadArrow - FilledArrow - LineType - 1 - TailArrow - 0 - - - Tail - - ID - 3 - - - - Bounds - {{338.46143, 183.07693}, {137.69232, 137.69232}} - Class - ShapedGraphic - ID - 6 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 store in data cache} - - - - Bounds - {{96.923111, 183.07693}, {137.69232, 137.69232}} - Class - ShapedGraphic - ID - 3 - Shape - Circle - Style - - Text - - Text - {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf320 -{\fonttbl\f0\fswiss\fcharset0 Helvetica;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs18 \cf0 load} - - - - GridInfo - - HPages - 2 - KeepToScale - - Layers - - - Lock - NO - Name - Layer 1 - Print - YES - View - YES - - - LayoutInfo - - Animate - NO - HierarchicalOrientation - 0 - circoMinDist - 18 - circoSeparation - 0.0 - layoutEngine - dot - neatoSeparation - 0.0 - twopiSeparation - 0.0 - - Orientation - 1 - PrintOnePage - - RowAlign - 1 - RowSpacing - 36 - SheetTitle - Canvas 5 - UniqueID - 5 - VPages - 3 - - - SmartAlignmentGuidesActive - YES - SmartDistanceGuidesActive - YES - UseEntirePage - - WindowInfo - - CurrentSheet - 3 - ExpandedCanvases - - - name - Canvas 1 - - - Frame - {{480, 111}, {1600, 1307}} - ListView - - OutlineWidth - 142 - RightSidebar - - Sidebar - - SidebarWidth - 120 - VisibleRegion - {{-295.46155, -53.923157}, {2056.9233, 1840}} - Zoom - 0.64999997615814209 - ZoomValues - - - Canvas 1 - 0.0 - 1 - - - hasOne/belongsTo - 0.0 - 1 - - - Canvas 3 - 0.0 - 1 - - - Canvas 4 - 0.64999997615814209 - 1.2999999523162842 - - - Canvas 5 - 1.2999999523162842 - 1 - - - - saveQuickLookFiles - YES - - diff --git a/docs/images/ember-data-in-progress.png b/docs/images/ember-data-in-progress.png deleted file mode 100644 index a41442849addfaf2258682cf450d5fb65ef41646..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32701 zcmZ^K19W6-ws4Y8$F_}*lZtKIwrwY!j@3yz?uu>OHaoU$TYv7%y!U4QcVDelwGO_` zv%k$#;Rn;u+DUfS-z-# zAyST`iG;Z~rX-`Nrg{KHVC(`z`{CfpskAXP6o5wn zB0**&w{>s{Am#%HnIDQDaRMbmzLzoImx6ACFp|ZFL)w-CgAH{c^;ZsYILV@*7$LMm z1Nk=9qyt0(@j~2P^5h||>&+6hq1=ijN0R@s7)iN(O`HLH^?PiL7VIKm5wHiz-9yNj zoO(S@kxcU%5;_3pEi?$ajb{nre!n^RQ9CmBtJepf52C7IFHbzQn;mxF79$213%;7I zuT%s~?vYWSeEcpFXFn#wnUe|0T43ReJ3$Oe_fd?X_Xi0O z4E!wK8!>`{$0IFBrbgHnfHUqr6{-1!ye^)?)Kp-oPb)?dLvn2Z<5(hqBE9=-6ZUBp zgrt#?QiBr;Oo!+T*e@`$EZizVj!Q_;URK;|l%XpDjG-T*18Vq|#Jt3=zX;+g;?eR} zNbycN%f1+Og?bFlBfb$6!e4i1{wV?3{pr!`>d3JA1u?W9krtte=A3PMetzZ;b3mvu zdQV3~Z^K(i?qncF=g&j4Fw9Z0ONYz^d){|!Wh4(cW+FVr#kpnI6<>m*58u9B0Vfd7 zAUu(Vo+M+)YUf4CQ!qC)YY>}L@cFQMqd_PhyoE4KdXum+BYaFj@2y(I;>Y*77fkl3;69|_fV6=K173j}Q!8=tVEVcA2MTzlRe2w_gPK%O2b!P{%IdRfXmk)ARFG&M z&>v6d+~(If?+^}^Jo6Lrqt_uW99JZu)C$3V!3c~X6kRB0eV`m)5I4Vo34RL$VIo47 z3ANS$2N?D-ck5I^q5UAKg0KP4H^5zlcJpuF1hD`S@0N7H&;dK!N@apfrqTSL&;kd zFMQQ3hCh682Gm%v%snSKhFU2#<^G9lxGFx5t7U@M`l-Sr;m$_BiP;%Psb9og() z%>m#s{hl6de1!Vp$=j`$Uau_Q(J%VEuPVv7Bx6j3ohTh8pvj0WDT;rn$dr)aQ>6QU zIAb2+17*x&>4xYX>M7%9hMb3JhP8)Wcg>t2pOBklgt8A6Y`$eAK*1!(NmFIn6r5(K zW$9$QDDr(P{)SD>`RyweIhAAr1`RsRnHpDxi|A3YQfEy{4X~!wDF~qN*>G*OC$&eh zH#(v_@}}Zi@^vmAM_4wOJ|{`xL2**yLUE(0s0gdHsaQr0xs+CgN^z;uNiSb{k5o3$ zO!lTwHh)?jf6U%K51Dko8vi7V;Jmj>4EWuy>OggK-4w?kCO9 zJ@Erq6QRz5^ECftU1<*5@!^ZT6YJf?`R+ixuj1;_amT{8t_7vNcb}byO zo%-!MGs{Fv{28Sx#w5CgV_kh7cpJzJ3a5ZhL{F{R)to% zmzH}<{06x!xt0m7bcpnqmZpmObCWe-i?-|J;r-8fyfda0_7;a*|0(xd1zzj+Z|$63 z+;>`c&$sZmfp_`Osdw^64_H-jK5)};Y*={ghioP|Uf2=v>{uC$J`?jsFEz}Ios_N^!Y zD<*Cer|r$bo^4Nn8;BcojAabGNS{cpNbe*UY5P%|QJ7I{H4_^3QkPOXwX^x6`uO^x zma*p=c&i;7(uO6Y8Kw}H0o$J@GX1|(8(6gUS9n&mRwk;;s<(_WV{EZroYIb(@*J%P z({Uf>CWh&IE2hsY+CzMc-i%%-UKSAM5qLrYq1MqZgG7U0qoblL2UdP!{@mbtPePrs z%$WfcViYn=&`$skd?(iE3+RXG_vqPmS#?Qu)mt*$Nt>UV=^VI^@2A$5co*J&yyz1& z5F8P-@@B|Z{U-XYz_}G$SWUU$99q~Dd6sxuzb3t9yE}eYarynwc)RzZ_}cT>dM|aq zb?_lSGd*+cqH4q2&;7&meH>Inz(K%JKs!s!z{bFGGmvP9$WXyn!M;lQGHr7oNl8Lu zX!%zvo-aa-a_5u}iU?vJ~>sX*z6Ak_o=Et3}RJV~5yNt+^ZhkNsuQ&A8UsG%>c}%2BB}>ZlKV zd_>=M+ei#`dfI}d!&}0)`v%CQlysC-l{ON(sBjBiWL;CV81DvHA}wnRbbnWH^BO-_ zW0x>DF(XjK$L++sQ~K?TInXruQl%waC+KDH+oN85-3aaU-=MohD?{axy_3;RewI0; z(qTBo@QjQQ>(LZ?_s2-Oz%uSRwRuEUlmNi$;d!JRf9-mw<@M`fp`o2NjhxEYPvrjB~WPA8r zHOS7&Udu+rUB(TJ7o;xOyz5X?x9jbztEpG0cjUajVZ0~NX!|ytuM~8aTdWkGZJ#x| zfnO9=GFE^1A__!SpVms6KKE729JoklFXwhZJKm^H4S&(&L$w>5ZA z&hnmlf4OHnuU%`*jaF5!BRoyM@O!tuu4G3D!nfc&^m5oBt`*)31%|?BrIRI)4fVr)(Y{m6%{3jYi!SGrsxPfbv~Bur+Y6qZ)CRXY>9U-{5bFN z&hrj_m^;Vh|KqK26*@=g3S-`1J@I2=K6DE4f^VDG>x$#x>YyTD{!l(56Nj(dbN}+x z!d=1r<%VjqRZl|y_5tm+_}%mKXYp?8Zl_uPDl_AL@>S+Z=eqw`dS;=j@&N(>36ZCR?S4u7qZ>z7_UooA zYa1qcPpvRFh|0j9H46oQxU~Z!u@G3n4@`m~6d zxM;}Aa2ea%(i@uC8=2C3*gAZ!1_9ym;QBnYHFYs0^02kBbLR5kCHcn+uFvDYE;Eo2 z{bPxXH7|*VtOAj+y^|>sD?JlEfP@c*h=_>C$;6CHNkr^l;Gbu_Bo;0%4qOZj?(XjN z?#%S|PUZ|uoSd8ti~t4zfbMezowKK%i=hXdoiph_k^C1P5mRSlCrbwxOM5$_zwjCw z*}J;%l92pG=)XVz3y7l+H7A^fGsASL$x& z<~FT$->j9pbbPE{srS}WQlQ_dUfJYg5>ORLe2FJ6uyA)nx5*LUEIXr$4jrHz!0;Sp zL+Y6EJ0A-S4m1Qr_y=(pk^vMW_~)sA3klJDBChcOQWGQ8Z!WSDb{DCh8x^#o6pXic z%ioy$_f=Zh{|S{L4>d*&>?I|gEL5v)0Q`mJ|3eBIB9M-3fe_rqWPVo6Y(5bEKlJ{6 zWkw;?m~--(PNp6g)@FT}sgnloAnx~{((0%?WBAjyjj%AWlQIr1b!?Ic0`DIvHSl(VG5q4FgzA~Jw_FWCyqXmrX`u{ zyZr|mO`#8jbz1Co@&NEt#_d0q^j}P5LD7z<$XLX+Ky+$64(xXn$CMSsPfZo8a7mjn zdup&tKkql*)YwUI)BC;!{b>X24dz*#>zVIe{qsOQJ z?`Pw&PNE=B9-l(81u6~BN%N4-7k}!VCLd+eUq#y*eDsb!E?kb=wEL&4I6e@$JnAvN zq*0vQNF_RR@9}WUECbsrV3~K6eaw_DR(4XCI@_c%lDH))~P~zanlrraDxkf95mJ*Xm<{UOD0u#T!~WBxE_sBq zD9BNt$yo%VQMao_T#D??Hp2q>w_M>DQ=x!JVFKt1thv8rFwQISe#Xb;nXAx|J6nYa z2N6onhlM@XA`o6UPzS|uQW~MgD*`9)ovXX9S=X}&8+(fOJYD29l>c5x4FBZ>8Cl^X zf;!*Vv0;ga3`w84q`8!tHm>Qq)pBHR{n|0x7;;zmNJiD1#jtXJ z=TOe!?rx^1{FGWKMOIWul*FuAfD6nf#LqN)}rQJ2qsLSPe3p8mI=|BFKfHZXJ=U~LQb z+*Q-m785UPRSvJ5)+!ELuMF9pO$zEJ)hP1#Ky$kfqks)hvUV8f!Es6?O=J%knv@`> zu85+`T&yxoCD;X>QVKT$Ht>a-+}WCjH&8y30{)BRNC4OQa?;kV@bjo zjF#JjLD1hZlLY{${xgI01F}KD3Nf!hLN9hNR(bHWn6G9^(72BR)r$?*nyj2~!JL)z z*MXcuUllKodemsvo+yc=2nsaVADkpH4eTq#0U2CkJzmy1ewV|nQ%g9B=!UYxM$d%e zBSZRhiyHgICZ(ZZeClN*EZU=WYL<7~bFM*DpRqugzz_|mF=^WWBl66VDEP-oCM)-( ze50w>;7J@25rvAMv;|8w5p~{sv^*Mv-IC(yf6t;~}qE-VStwIyM2{t_=m0<^Hb4)&!` zCj}jkvr2UKF8!^}47A}vL7!_HI!QT1;{`38G1N1K{<|I5g;WF!wnq)*+>2TUm(M)A z;QP)7;KWxEo9B4ZUX=t7??0BZD#`nBW|Og^R4HOb@rxuN`q5ez6#^Cz0v%XjNRnUI z)Mv>vctRzrUIzkniA2^D+RVxlj?VJJ;$I2a%1Wy#RH3n#_|2R&p&DM>{8)SBvj3QU zKDLOhZq#M14wx{@cbrL)JvnvLkY4&fbm=N=;7A^CrySlc#X--C9+gHg9i4s$FXzNO zoMp|j%6fJ`f+G{{Bv+p+g|BAZ15(^w5^llkpb-oPtkvF6Gb{!RpGzJ>EefIP9!)yb z=nY4YpM95rPo3?7rvFA`%^1{@5AK*BHY$lm7%u91rn64CG+5>N?(;i)v6L0E(pr32k(# zq%?OafxMvm_zf;lGQcSYY)e zRZVf><9rIkySpwFaaKq?<11W}I3-!}7M3J&KTrrB2R5Jmpgc}OIFPEhWAZ@N4VvOt2Bl^467%CKk2C5IYDd{%~<`H#EZ z@v5a`LCk@1gfg@%OC1YT-q%=vl@>&E6m(oce~)!zXGr|`;>X*r!xUB;T8k>O{~iAS zO5bOL1hAzjcnqL1p*%zzg;>JBdCA)h6d-){ZP$am6;O8ro2Ul3NMlhHlZ5UiM2wKO zl%-71LRE+3F_hxW%0*QS=B?-ihy-U^pQFWEp!4GQcBF`OX~}ZTIQ0nzLM(MD5Iafz z%+L1_!^%tpZh198$>DM$h~N*F6qWEEIxAzg0}==r#iWS>%c1ogYDQ-rO1;?T|hS%my&nmp+Z zKB53{#`0`GuVdzN_CgcuX5K;7+P5$+=^QU(v#S+}wO{pezIzkE&DE%il6#Ia<^if0^usCK~A{2i> z!dUZfE+#?Vh2)%N3YBb_zbQHGT)lENFDz}ISK$16 z06p?rP25U*^k>~ZE;w-#z{>_|zD6NFOMr@p^RsAi3{_3V?eA+FfpRF?3KN`c*G-7g zP@Y$(P5?87$QCXx7cT~O*fDC##fY?aPn4USqKE&?G|&S8sylt;Ah0p33WUl@3s7Xj zi5%oqb&F{0yNL}-Q4p|A*W$94U4kHY>C`5^klu!rtc@7;S!LnN zHa~$&nx29}E^Mjh(*k*RU@~s?W(5E^;m9q=O5+7aucVMc9mrez*0b{v=N>VPs0YXq zMeg7)4%Z~|NvyH9rIJm^vEeH6x#x-@=5fX~%jAl}G~9om1!k#%W2ghn7if;XgoiFx zo6Q1h;fIz)O1`XDAZDIsIt8iexYTbfneCuW7)IXS;qm*)L_rm88Eb$~hUAFU0NmW8{6iLTfi)!y9Grb#OM zn<}FV$zz@L)9qUdf!ogPIo8|ig(OB<4ije*9N{MR9w`ho2O`>vfDp=}-1DQnUD-pb zm1{L`m6VFch)#N|tw8DS>5Ju0wlGxheq+@is$kWO8>29486XGhVyEq9N2EH+5Va%`&6E& zHPbeDw%9U1#&mS!zzF>_h>I`r=$v`_8v+G||8VzMH=lq|7bP1+a7fqFShEW9bF=io zMle~OQexAKT21hDFu(z!b$0n%k8`^XikA21zO#G4Q6e1(M+b% zlsk1M;S^I@yI|wKEX8W%wPAuhSWxy+KI3vmYnHu9>0M~egpM&s!#y3+On|rOTrS_m zI=Ym0GJz485<;U8_Sm*qPn+@*^FhLtq{%k>M2Dd&0njsrcct>Dj6w~_cZ!yuuh-VY zxs$?UW%(94)7Uk~FB+4S?N4+}Qxm<}IkDP1$}>LU7@Rcf!+9N*E|5raHkT~t8nL^# zmx9_|e{79nTf52dOM;SUouWHGCts*S16|<5kYH5i>$r3dEPH#7d+Pmb^U(MbPE4O0@c>aj=nY%irw|@@Q)XM4)m4OWm>5MO}1NicI`wN zW}%B0G*RglHMcsA1Q{CN zotO3f)%IoyDpmZK)5g7Z;vJ;V+-L?8++U^ z&+I9D2_~@ijX&P$c%HC*g#11RL|J7N==;XUAZ1-|Kv*X(%iPxDH_XEq3Vu_L8t99QKr&^avK8T>5L4Z!RJn##=T2=ruQz>)K<65 ztWHX&lzC##%l|!0XaDmz8F0pTV3H{Vw2WV#h;fwUZLF?GE0-#pHFkkU>Q6Ejrdo(t z3k9F)Lqv(V?|Qqo!t%101RpJVGu^jdJj@%pVPWHV{b%GF&&JZ7laB!LOU^h?Kgy0< zVN(YDIU;KaO7ST+;mMFGc43#XNumPBU0JYMoL_GaiP!lfu@#siK~*?; zj~F9URC0P1-X}Sowv6T!vbx&U>^vx+A=w2pY=|l=w^^kq)wSnfK#HbW;GOfs5)hk~ zk%17rs@+&|bULOjrvL!C%Bj)62k8p?QOyTvFK>%lj4!?Wi8QZ5#_dK zcek8=9AO4PCl~i_uI+v8gX2fvDKs}BkGDklma0xws#V}KOh6u`Ah39H1BO@70V=A9 zjWeDskfbb6$PQ5Ujv->RCjcEN$u``c8fh*KJC0lS>zQR#WP3jtyx~Z2E-?o%yT5xL zzGcqD7w6n6Z#>ll#5N4(u8IOELGYd~KV*3>O|nCvyX!=#uZCuT=gzKZH85)N`X4|w z115;fqs%p9tKaC=!R0ouwHuN=ZH+lfd#ImAJZjD=9p0SfXR__Qf#12qEt<`UJ)i%O zvI>JLJxG{~UOu|ONbFyc|Bxv`n0p^26{D4>o8wt<8#bDDi2e4czVpDVs3=WyXrB@h zYNp%^*KsHIfX+=*QVQ;fej^WUC(6)W!}63*h%@;n3VjX06e>t+RcNuvcitC5*=NnW zwahmzRC=DS$5k)IwRSyWHl6&nSC_Apa-c(VJbm(GI>)Ev1l{vdo$L4}VlrdCF?2Q@ zcOA!B&Z^vBEP0v#Wiy46pVfGuMTV!QrE)pZ-8EcJdeUj`O^(is@Y9YOzj3(YHb>5@ zKnq^6!;5lat>-zZC6Ot*EX~{KHoM*&56RqLcE62sFVDNVN`f`JJgCLQKRo%c$x*cY zlF3KJ=c;>{g6x}p9I3JfE?{D`@g$>vX#n*TI?v#m@!fu`HqP$KXOnc|NMC8R_nS%G zfQzU42^<(*tL1HPHv*@rxTC?W6s}mf&|rhzsm=r7d-~IO)RR(13p~aA{D(7+j`+{I zJMQlnJmr9DbH7Wv%8;0#L<)wp#Tv0=i(%7a07j?V!}wI-saPSr!%bSyW0m;c}b0(WC;24<&-H8hAUse z&-!uu+5!@#H2T*jORF!@a1iu5i3vNmFXM;r5omH}wJGj)x1crco)0?dX^nOhX1wzo zs;sV<7iw!(*{$IxZul{Ky4xZ~wldZ8(v;iCQXjVwuWI1>(ngOKt41110>uqZwxFAY z&E?gfQgSgYlT9+Je{xJ%KIqir)}mfGT3w-?JKdg(Ga7HUFU~G}hao%)ZY#7pvRD4_ zHMiPO+=+g)Z<&9&rWtAGHl0@C`Jf%Zv_l(cE3u{?u-R83?1yxIG=@asX2&QQ+#^vQ z)vZb>H=3YT@8L8V0Y*~)&sYm zzh+W!EWb@H<(1T2aF~!zzB2Do})h1!V6VhN8$F==&^H_(FPL z_--27Gp;t*%us}#o#8(geKt&IbEgi6XA1ppUikUi4v0h9>dRT{scfOTZP;ocdLI>mE;^5eMtyyOabDiG04s{Lvc`wW);PG|ow=&QD)d1~b z(HnXkkY+--$F;pQUtg_ANBj`QF%b=ANjow2t4!uuOp>a|B5~ z&Qf6<;4mfP0Tpnc8ACT*#i1w`INP!MLZ(<(ZZV#5B+d|&apZZG|F!Obc{N#ox8r&H z=Aeb3^Fxw{iiGlMQSj};ZvV95M*Tp^0XlO1?#D%l^*-SEvXLaCN(l#t!t2wB*Ha+T z@}S$Eyq;DWGxCp#mhfO@cyFpwMj75P*|{7)PzwT?R2Ys;lrre>E6G;X$2vZ4bY8$* zNdS)znR%wF@ReWiRwfyISWSvldXCS(AKkaO*`t8o;JOnq*0xqs?%9jR@kO2KjVLo`Lk$1m&p0O zVa(f>PPMhpHPd_ydGLj2{9|Kdzuf&!&;4o9&xhOh5?l+E#`k7$-Ox4~Skcls{`yLA z1Dw2x!+f;=-aK5Z7ap;nDN5t2+hLqRQCzZ<`9fa+hSuls+ns8#RK~=r8P;s+cz+B) z&Js&yPG913sv>0%qfDYWs!>`oslqOtWFZuloH4AHFhf%|UR<}JIjS|2cwJnfuEKR( zj-oYlcSbztNOK_PS<$hm0Qd}gGuzO#M0E{d7kH@NhuaKzSu7}?8+)^H>Up=toTGEs z+^TE7WqXp9TzDgR&8qyYi6JeAb1(!=+3W$q*&(i(IGZ)o`P}Zd8-F-i7kwu$&Y!O) zzh4c$5c-@Jx6AXje{Au_Y&?~2yl$(zza6W)^SW$g8uyy3vHy~#`yOND-jDBJwoLwXw{NJBB& zb3Bm<990;3fx~)Qy{B;q*Hsd;s5$L>cLKvWt zRw=4l99g#aV{ec#2Fue!IbdN+Y+04|R_?WfGHOt>C~IB4Z77Q+bBy+Sfx~oUd4Whk8emLN5!w4_T7>(-*dB9jBo)4FbmDI$$JtZZ!lp1sfE*f-p#?u!UOvHS(y2v>5m%j;gO=7OV30}nhZYj1%$y@;kp%PUR2wDyDN0G{JJ zZpH8nWASay;^loRQWS_J?Y-D;_A3QCFGFRgAxi4g5+OW9g>)n9>zu48P&Hk%|5e#h z7s}LOoLr2GtC*haiS~yKoqIQ}_IR4+;^tQ}S~A*L<)g*ogbtCp{rpeQ%KHMRJ`ZOJ zqchm&T#0^n=!(|W|ERJ+b8Ro1pUc1h5@fRMqG zlhu8O5Mj4IN6y7+-t6@*N9Xph^x+P#IZ{mxTJWnB1^Z}nyy^HrD=w~DolDtrTg6Rq z>PpBY-s|fD-$yp0?`|OB;{jsZMRD{sFj^Sp$zR{^ENW!KM8vU1x7~j_oyUw?dkIPWL*H4s>_c4C2_bVTF zp&M_}zwnxEjAxe7w@i2(k1Zbl{0S;PakD+Vt#cFIrf1EEu#pUxH#M2Npukl-Tv<45 zoj*=5H?axnw2ryV*LUJ?MU)nvSy@){yD_?B&?^dUhZ0J)j*-DLY9U@j9fO-NqkA^i zhwj+>LvlTCgNCFl%`2<_iVK-$yhRepQh@``Nm-iFd_q=#@%zdm;881#*l>T6!UY~f zg7mEU*ys=#(#mrR3>%D>Z(D5MO!Xzr7en=|tI$ndQ@@@to+fkIu2PUlGvJIwEd8`QNDb0!(3?%eKnB96ZkkgK6nY`s3NmV#@*2;W25 z9UZtTcYpNLIu~qwGi1h~Q&(z}Sw?a1ltBnK`Lr&!v{FMoF|1>sfR_7ppM4H}srUPe zJ+Y{z+Ap)*MLf8!$i(AiUJ}|Hp8Kz1I~)&*{pvzFV$20BB#6LrO%}zL&Te1hW86;0 z-(3fEuZX5!Uo`8KXaw_bV(M+4EC&bXAeemG>c6>q>E8|sf2Oex9kgXI=o3Kl-Ld#8 zaMLO2#OQRXqewL_hT7$7wFkc1AvjL?!b z#@OBjq!@V&tj(w{SS+ZdjdE)c&>)I$q7T2R)oJ%Dl-d|<;Xk5_5L**J&tXlH{2b$1 zI{c)J3w$$nn_8%|;=ZugZ1!5aV`#mPz(2vU#inP9OD9mu>D4h(i9ozG7U!86TzJ`T zRfkYxgA|Ejv6Y6C+Cfz!qcYL4ds%k-fL&nKsh;lWXUG4EKbq#5=YBy*__{WE(RxB@ zPSDBicueemJG*aYH(KJ*bs^ce{iU!abOJslN$k`G#pX<=R4|mj)57<7j$284d4^A$ zD^<}5x}Tm}_B&_#$T@G4=eEPWgS**>DdB&@RFT=i76V%WLXaWsp zFlqTmUkr9IXvSYzLJcfJG_maBXZTyZuS@xvpuj5qfYlC;e7^6RZU*4)N#7ChV&1PO zb2A@PkfWdm>K#!Uvz#|0NzaJfkNOJLX75J3JEb8H8(X|buQ57rJwcoB zhuV+RS@Eyh$*Yt{bf*4i{qsF=n%P8g>m=?8t}!P~Pq9Te-&^;nX12y$_fmzg6uD=bSGlVuh5%=cK;@Xrk!PbfX<-3RBvbFVd3LM zoqrhD2|Satgg03PD9UqV>(tEbZxtu#4FB5^e1j^}@p?oojF(;n||-1Oime5@N&YOAYcR zk?-X$o?vV_k&G+~C?{Mz@+mN6iuP)#V^d#G-^DV&`_F4gN($eUFt3gCy`+r~Wj#Ak zeH`2-Z_B;i@ODQ(B&~XbcXzqD8YWaAJ~g%|tndknCWJN>spPmzeUf*6rHn%gw^(xpo_+p?`HU%Yo z(Vno6G6ux1OP25nS1th7<6SX0h$0ej(IKgC3C8V%lO2;7JKW}LdOYndJybjUn!5fm zUoG#8I_g0b$i<5Pw%7i+>A(0gJzBKm6|a^^E-w4zp3otY6iwxC}l$M~zZH=xqK`V7zOe>I7dI5Gd( zZ;ep-U13@_*FKr>n;4e7QhkDXHR7|AIyIj-a}t3uHmZ{#PuFgwrJH4c3EVh>-(`V6^hSso-E*#Qa1j}tQ8qS4MJ*PY z-l+>+OT7g~&5)WKE0e|+7Y|FY5JY_rStqEAZP?P4s&)!YYH!+pCnlEVh$$~y{EVb- z5F^x_*8OO+{{PFb_XoHYp{%lRYG&&kbwaV^KqjlW&Ix4ug&4n6UvZGsCea*G~REk(o}nhz8d zT9kFdI&DJZzL=1hLAQOo3h1l0wv`@6T(tehbrs z`EbxD#r#=Kk=!HRj(zrI9aqdZtk+a#b`=$Kd@{6b=EE_&c_!7fPoVOB-(A=eJ1?i{v_x@~jc6%Tz=$8MMte%T%?knY@5Gw{;ymzhe7m&|* zq8rvOn{K?Q=$VBppZ1vRs2>0EwbDPcu5TpVP(2I<36)a z3cn$B(uTH@N#_4ZP)1h!HvHC`pfs~}`U8922jp7UPn9^->DQ+(O=Hl0O0$&Ejt&Yw z(_$%{u2!b$%X>vOGPaTgCe^Vb0+JmEB>g$vF zwz#}`K}4TfA%bj@R6?})M`@4(s5hQ5_qb?63m}l41b>q&7QMfYkH1!N0??tV9+*ar zQv0YOGp8jb)epJ2*-&udB$86aP51pCYlPrcw}sPh%g-&(pW1R7*kNLg?&4F7Ua;k{ z$pfo2LAlBccqQ8;*H*KlNvYeiZ1={(HFi3py{Nmfg$I}C zzz&A>x-DfdRks7D=^-U3?4k0Ym$N48r84R|XCd%3tZWB?1j7*bb7i2GJLiQVXMXA< z7KWPXh3Bgd*@CsJQve(Vd>UPVSkH5M(+8Dtc(JcC=Fk3p^2x;3Lcd4uw1IP9A7b+O zmYnecb-*aHhX-5R8Eb`fL;57O#8)y)wA5K)2su#7|48&>DKW>xZ_t8!V_vB&d5IDYK$5L-h@K z+GATEx969R>FQd&hd_DItU9d7cC)v`Jo{Z2_bxK5d(iyV+g~(Sf)&-KL+k9Ap1026 zk%k>0ywk0(a)K}0%n!hz} z-Ag_vRd?}va~!jdyBJ`qq7&Ov6nLi2W-@j@JkuNO%j>fOI^{*-GjS^IyXFh*Fab0D z>@1ExYN!u9)fZhCgmUI+mBJ}FM-SKG<+`$TXYklYH_&dOqrv4;1BJ$j{NF8X%DhR& zDbX_GZA6rDa8v0!k4Hu;nuh3G40dG-m0)Or%Du{O;(Nn-safQxSK-x?r>=3R0W)fR!rBEXIA;QW z&4vs-7PSjMxN~s3)zRi^KP9?p=YUH)E8qhPO{O7ZSL^`n3{0*P7OAyT`#Yh3qOu}! z0?;&nh0BVcd#^S{G({iSeYejZa!3wkgJK`;k!FOrZkCmrwOCak+g$&19o{*3svyC` zAdc4iIiT4>^aagFK|Jr*##?XDi1plyOivh8w#rb=gMS#+6bmq5RlMJLHvDGXe_X`J zaM_YfUsRgBJF;}vWwo2D?{uEg*)Be;)C8rz+lFIEfc-S&M*@a)7tnDBabud-U91E> z+VGc>in?l^l#Yk=3!4Z#Nh9 zRNvTOTi=~9_nS-56eQI#V$uta_ruod0A;P5*TD-=y@|)4(#%WH(Ld)$ner2jQ3WGs z?ROde(lO6Z0Q&E0il2$9uB9FNDwSSWEAx&&+tnuDH{eyM+4%2@wN#mhq?~IN1?j2l z8|HD%ih+&dC!Hfr;6wE>W&5#X(Z&#+jVn6m=Sx@nUqoEEQo>A`9gN6f8h!_z#l2U| z^ry5Sq!QuLux?+6;;72a-}84o3>7o`$`v|OBrVod7{8tG*{(Dk2dwP5uz~x^(x}V9 z$GFB6%&ht#vr7?}Vh2!A_(>UhIfyvvFBEe=V4FC@$_+q2}b| z6HPYFDNmUQ$HTC_-r6^bSz$%aUal%~#yLO>Z;f?fv7|{I9u@>EHKVPtwO5>Hu~JeS z|LGv5RC6RmeKNw8G~P7t6osobUkO=CjZ~(N3|@^S^!;^xC*EUIvh5MnJP45~u)E94 z5~-^c1AG~-9&Ac9j%NAVM1qjhl*?#OwA7;-=EAsWEq$&k5j*yzf%>8!2y?k1U&++ zE`?9%ZGX@~0=3QqG#idNYw@5*1zZR4=JYRkeH2F$6t`gWJ$>8b!i z?#0Un+-i=Qq54ZIz?0N-BaM7t1zPHFWr$1_O1IPm=*d9!LG?wu3W32_B+@26?D3| z4V4=0e5Jl7ldv328reY&slX=1Y@o z{ld8y(_{;Gszs(X;6kLFLyv9n=98k}9dt-&i1-x5_DsprGvx9WMUC9P>Ql!aKb^toP@?O5-=bf%9k*^nKw z4+6!cVFhCwH?R2l4HJ4sjA?tuKE{A(+lc(SCMRJxcgU0V3=THh<|YQ9f!Xs~6`1nR zdcKLs`)KQzv1!(JjxAD7mTrXu12%PwL{VBDm^l=k zpC@a#R*b*i5(HvRS(L&0p3He;#+ej9<30P=*jKsvWG73&cx|x7KwHD@kZ) zdJX`#3osXt5?Z8h;ir1#WoGc+$;ut0nl^lj0^^o6SSreCd_TOMDP zA>6gixzo504|1ZE%)Kq)XGSW~0QIY1rI&CH#*|RBw3WnK{+S>mA9K%JeI|&LzhGGf zQ6a?*+Q)L zljtmm9iY;beuRN4+5Y@RJ4(j{`YXSbU~hpFh($76cu_6aV0W3Q3~~UPfB6ba7*{35 zwbldIcbS4Tr_@v=j8!js|8Hf`Vv#3ALdcHg09&I;XYu(58NoIdy|?9Y?3H=WRUB+N zJ~qt96FNx*X`2^zmDo;ujk=E_I{Mscf!v>zEfkETew0jG>ZLGu4K2bBoR!0>sac3F z=Tp;Si3Nl;GV^D{{@hn(6F629&&nlR74vH=nlu>hy#_X}s2;ueEKU!-@O{uK1~fxV zd44hItuN7tptsYK&`@2_&jSx@W^H$@(#D+#_IKEspU@-7-WKs6;#>E%(!CL%TRXqI zT^Rp>h_Jmr;WhX8u)L{6>jD^u8b z6}lV)+p;%)k?@*Jj^z&QMs*6zDOh_2nJBSWig?7YzUfI3n$`x=2!{c7;ot8=UEocypXVJb^QsEo=|==BN@gPYDN z2^YYRKbA%u(?D|r?Ozw!bZCA4(EbW}VnuK{fZMs#Dy-2)+W}g-Kk7ssS5(&tw*GiM znrxqJV0@`Tch!$u=W)ypg|3KJQoZ`hu%BtCrX-{S@`nnmw-B=bsYfU-sw%2U@DJzY zjbCZOyG&`#SbY39)Nqu?K_rZ@17DrdHm^7G^T`5+yU`Y+;#INro83G&#qNZA1z9)J z)?vvjb7ccczCU@Ba;0`7eCG2*s4t0PtelR;31Dm*=R0GBW74A|UCmfJER~`}M%}ob z<5Rl2UC4?2k2%6dntF{SU~#4V#Nw)6?a~!$a-(ZVN(!1ooHiH=3n~JW(40g6{!Q80 zv4tt5eG5&`omN7+fkDqBsE;osk_k(3te7#0ZOBIL&;FVjnu|;qo@FcxOGx)N9({Xx zN^;l|#I8K@-8eC@4HoCgGwa*C+VrlPR)*1raL1IpVGkWX0Ap|>Nd}!mx zQ{uXLmuI(%8xJfH6X?;H=PBA=l*=W!<+D1UmBfL6PdmvFhTm2lqp(wqB&`A;IXx zR(AF*Xajc{qW)F&jZnkX_a*Kr-pL0L*P!xT;#)ZD5kMJ$+$!yfUtOZ0s&}_+h8*9f zh{a-PKGZC_s-@Msd`(p5WB1&|Y6XQlR!ElY<_^B%*}BcmNn#kw)YIKMn@D2p!y_Wp zx838i+a}hoJ2Sr6v<#mK{IHa_Ia{W)IznRb(~!f z?vC*79hC;lr#bgp94NIdRln#Zabk}`$nRR`*XvUH7hA8X4GmQrN$q@lhkTk>tDxyr z2ymnplFnyC9+7NW#Ki34&tN zqiK=fph#jk;9BwL7!gvn1V+WA{dLM`4z8QA0Zm=$eJK;7SX^2X>XFLgc0m^f?cFT}di~cSqtviAi&rdQ8y8MYpchTp&}UO; zyd2l|oGO-T#3pbEjUyqmBnt}k`D5S^i@WzAuFO-}iUlCc)T>>~Cmv4eHTF~DANsF= zpmr=`^AJN6wxwoo6HMG@ql~o-$ty6hz%oWRn&ZB16#F)R3gla0OSa)p>HCo{gafGL zP?Lxz*}&{KI%bZf=Yh)PYMFYsZ$5nQb1~sh@YR4JijhLwYKd#;&X=*@@G=s*P-_f# zx7GablcP|KrQ_Z14jzzUy?$+UwKVM4n`ArzWmSEpS8vwTqm^=haIu5(sS=kN2Xpl57l9cO);hE^JD)d6>(yv=T;?daZ_7Snj)VqB0v2^Nr% z;7Q;`g0BYj92hH|0VancZ)P*pfxkphD zAT1V(I3};_L|dLi@YPj2VK$}#7zfvjCgyE6sRYngb-5z&Z0W9L7N8b+T%Eez!RHnn zHz~Ol(y^>1TC!%U+&FQl7LCQv`|7B+<4tlWX?#IaH)g-Ad~-I#-#SUsp@;21rm^2e zrA)~z6pDq1Xs(50d0Gfdo8V|cZD!yNqlj)6klS_mdJ=3$yL01!N#>z=w8Q=*>x6L* zS}Y%nX0SjBo3;GHLrUbtY)blT;GICwaP^F#ZXhRXev~BA`VaNx$BMaB+BL`i^YpW^ zu^Q+gjWJoA;%EQ(WVX-7hv}hMVNwDSFw6l};Ir@{4fu)B0U&A`hqrNIlHkQf2I6O@ zwOSmr?D3PK1xX>5uYG1AHL`o82>YO+f?igZ2Vs}U{(+rt zmNP*gU%R==Gu&M?d|W0o&~%nPUN|*)UplxDE_>Tv2Q$0B$@ID=X6zLv^p8ij@ly!4)pv4^v-6UAKnv3ez z$8&73P51=(F4%!tVfC`j+uNgyNE@drZ)%=qJPv4^3}|XwTqsP;Bu1Ci zb$06zKJKfahgZK@M*yHCpqhqW6PBp>^L|E8^Z|zJ4vgZq*Cd zSk3?KDXtcoUf7Uv%hCxSGi-((a&7(`Y!Nn~V*@f?^PEFUkU z;>g~+0v03A)$(wZ-TtjnB*$F$LlD7&H292M%L*hwp?e?&qnbUqYi4vG&lCosQKP## zbbCGO(0Xvld`m19MY{D8<)fGa)MX6fA$>H+O8$7rJ~!e#9XzZ z7~D5W()i+aUIzB#==_AnYR&N}GOnHZ*aVKo9BKmWt{|so$2H(n!nrV#4fQ^^G#ieF z0D!AfS2v=46Fdt^{{yiNWN1Ze-xo^R`18In)tTPNwL>!_*Z4LSR#o&z(Tq;s$cK>H>|8!{ zVaSIN^-n21aH_zrTI&Q2$?bzv$3@a=9hIl;RxT$s+yfW?J=>hPf`KZ-Y2e(Q3W$i` zZlmIY3NG5v%*^)SyED~kc?`i{CFX=&q)Tmr0z$>H&5L1>Fp5ofJgqFkq2dviiRTTc z?<^dQ3aU$ByqX-MN%ZFsqj;+<*k{E{(n?Cm#vwO0c%N%GPT6g0yvI`J&@45K8#{im zCQX9np8kC^un)1|CnpgTZD3qwk_d*}7v??ivaY01e%Q8l~imjrny&^!88U9 zdZv&DykvKhn;|Zjv}!w?1ZU;EEvXO}J<~2@0<-jGZ_(W*c4* zqNTJ%FgVMxOlzs$G(LNtzc)N`jIHa(W{~^9u;Nd1k(oJK_4bNV1PZGP3{gSC_5H;v z+P`aZ?1EQy1Er`jve`B+@MZK+3V_Ok?K0SJD5s?wPbhzsPUfEnmL@%3kH zc>~`blh4iXJGh_wB^UD!0L#r^F8HJbFWpcToWu4`kU*sbB^PcLQ+(29I7l!tG+QOf z08p-fdIKlQor0lbUT2O=;aEdLFtjGJU6~InI4v}wyI+Sfp?JRP8Sz0C@4fStsG}hhp^BG z5hD>H_3N!JAY!*^Yb8YPFd0-HE6=z#It-O+;fcfkyQbz}_%@&6Radp<;UP!xp~EJT ztJQ+F5TkIhv2emH)~kkB>H-go)4JsYd_`4c_Tz+0`1m98?!`(h`LELE-m;YBg<{OI z2roy9!#tTTg(e{I} zHIm@9x=Td+z;afS`PxTK!)FJ?!UR;9wbZ(43(b0jP%)EbY1Ld72y&>l>dO+sB_GmK za8f0&Visrjp&IK=dM1-&i?ewcX!IDzhP$JC)rPa1s!tg&S+*Vf+Fj0>0%PffIfutg$qdAAR}b#p~bmYcd8Y=g%9%B9#^K9eL!?Vl#i zQY14<%HJV!5HV}+$FKv4O{!*y9g~%8!6+F`ZPca4?5>U^KbE#$E;#K=NT=rKu3}CW z8q3WRo30W9Lv}=FJM;=qg*dcpey|@Jgfqd*a3)LM{n9 zqQqcO-M6UfW;ZgwTE_!#q1Ik=vv`ydD-zY3+0r>96cdywZLxf?w20r(h)6%$oa*At zXXC<-(T++Y-dhL0$0$&Pt|TO>4wIUsn zWXWZhXY4>VS(9UaRx?l_Yru$p$7)z8fOr&ky=DO9hWKB!T-hQsp^N7hkkwKMW0(NM zzvIkJemq(6;k< z*?`C826h|eMJ|FM1Q|MKe86yx3J_spylDg6u_z*~Dr<#Z}uM z`I@HLC6@cX8(tVF?~Z?I==gV2YJ3iuLGpp)EEK@}UFPmgn5LY666N|kYfT%OBz@V5 z-SOn^*y>`B@Ns+|o@;`j~2pwtt8apay9fHNWJ zl_jyXvhrfn+Pe~$yKTw9eo$Twe`_htt}F~{I&N2dY1L`npt1DzSX2{>!~T3zn|hLn z{FI{Y=J^R#Su=7MuPbH?AXjV2zbIC*lQ zXmZ)AcMB`e z7jE&@pXPDFGa+MiD3QEpkhjj3%TL!Q39LauIl}_qB4K%6Z7vtPEi`fk5R@9F6Kp{S z!(e_$-*yM5G_(#C*_VshQ--`n@p7GmpDou@wt1W>I`t^^qr%O#u2{EeckXb2x0FDuqx2hmuDsEUaA;Q^S<=fHh75Pz=KUd>u1R{Kz^CF& zJi-itIcss~rL1U8GEKU%CgU{tyB1|ML?56(8`#AKf-FE2D-M&%fx_wRl+1V{0eAag z2p2r=;tRl9USM#d!Mbibtw0C8w>6hf3ikSeb{cw0&_?w1#a9bCJv0a5REPXplQT11 zkdz<@mRmAUVKA!sS-R5U8qh8!7nz8n4evmmF)BSI-#Wx>*HB0GY&1>+C0(hapgce_ zIF7~b{&aDu{d5wU(69O&3#dBFgql0DlKQJcyp+MLxzx&k%+&BM}!7G}3O%d6Ll2WAk{0*-jMG zLiiuW7N^4^xTm&YyUD|fB=uHOC(n23POa7S`>!n3jDL?Gn)twxRTvIfu<=t$Ooo%I zM8qitNm@z-3n#*j$Bk0v9w8ICEo+TpK@be_`A*BZE=aDyqY2wEQ0mIE0Bv8H6$;Jr z_-}ui1R;*VL-rfeg~=TBg-i2&$(L7QC#JBY$?2ghx#}}*tT)6qSW+bbh@|T^ zk`^1oJ)~oeffK6bXD@xknA0w|x!!?+l)umMTy}L#O^IE$KW+mPQVnRzbaZqr#uGnw zS(zSnu45!1AvU*O7Y%}>GX(ka5h@qz?Tl9P6Rk|m&8hO3PAJ+8cc~Nu#6EUoMcmv1 zZCdn&D9z|^#`=mCJYOC%`;IEKFjXqg>41OPiNZZU!5kp3@cjy*K!N1L?G6hK9iA*C zPQ+rN+U$6e!Vf!7U|^u|u+fPI^pL&!DQOzD)tR`tv0vUU9&R6^q$MR^JkICmFH@KS zG_4k?MAS?kLr5}MM`!u)_}f?J+V*$+N^uG3`Jw9%&jbcTs8OUB%?I>#wjLfBZ-vdx zTSBxgMThN-hf>2=IR^unl?)6w9YH~)IBtigh9Gr`ogO&*#uKnyceC_<@9~u$*@HVZ z3FUhw@o*AyM z4xx=}4OwBX8WM>!6aGi;OG1}|GAVF;lfR*>5Pl!7O}Q;csuq_u5?T3IPLk1djO`f$ z{_=#q`Xv6CG@7NpDl2oTFo96SDSbhkm8P&@mhTb|_KS&A>@}U_KV)6mNZ` z?=KxM86XGNo+k!E@secJjjPvs@O;FSiVWUwC*OFVrz){{JeDaiu`()K&!=U)uC-Pg z%Io)29n~1ikJ33=k(Kp`7aK47I5(b5cgwU|w|9qiRB6$Vyq^*)-yR3O1)nXg-I>)D zMQu*X8wC)A-dQ`JdE_uK0%J-hEnCs?vKDo)w}ZUCU+Mk!ExQUm@&5dc2alRaK-x6< zhwN>~0$Q>t(ewI)*H$6#n*u@f2-0;ZrIW|8!bQvL^_lCF@^JKkRNGktCZs7W7MrPV zWaB4S@qM6!)pj@UO&WGyA0`mr&mM z^qTZAE9t)8loI)Ny55!P7+S(-#dTPtXulCM7dDMteRHYhMB-CGOeBh!i1A3s#BrXz z()3cAqYFw9r}+c1kheT^o{+ctWdW#+`t47!=z({+pIM&Q{IWIm;yF6_nkMctnIuqy@EGNN&#_9{hTadY+`=S=y(Fcsprq2bz!s9(O_k2)k+#x_jG0`KiPLq@6F4s$XJEq~es$%9 zwbzY}oasf!i=09)X!k=^|{ zbmn+9gE_h z#%9<&r^1~4dq1BLo4cJY?T0u8xtz^Sqfdp1xC=%ji>Yot<@?NeI3i7+HG z+YIgR!ODqF_Z&Hg#Vrs{QON{N1BR2|(w%BpVzFbV3btOH+}S7;>-~bWoju4fBdJ^Q01xz>A}+kf2N&X8U+*m5v2y{~NW_=2KRTCFtf50ggmfAhcCIKX&esxJ98!~;-#AR^bG4ZjM*&+!& zEwe0K#OdbWRu3jDjWjH_J>qhj#NwsI8i|HFgi8xcrze*8^)a)0JDwn<*Oy6q7QVAI z%`9Q-XKi&-q$|w{5_1xbB-?%>52x%Lj0&rfx8ZsZ7Db1*re=XXK1SBA7$gjOo-NlS z>CGpO?+kanBDmcC0bwN0-v=cH@}ol><1b5DAO;2rqqv>E7t+DeAkz&Hb^HqP{&=`R zulL^k(uiu76!$}jlU*g>P0`oQ2+G9sWcw6o6?MTLZ@b|Y7y^O#R zk2c-s>qOo|hvn!2Up+y0hTxkH>!vMn!UF@`ml8d*aY8aTGj#?j&uMXGfD$Ec!e0jK zG~t2A$ume%ZuRwrBjTQ!%&RZEZf`MJu;)Moe=7y}ktqZvE+sK?6()g*H)Qe!uVn~YtRML1Rm;>uRd3hxDHLvwr8r$- zPthWeAb$meQQRZzMfIVpD^AJ18Shf-QXC;{?zi4X$Iiyb`-S)-^$8_K4wB_Y2P{{% zY%(RCE#!e}(-47A>DSNv;TSA30>3ui@AU*kMc1dMEDU*8I;#1mRGA^W-zPp?4W72M zP4^*%RYS6kpWkqhy^o7?gMAfvGL3&RBug6DQc?Iu0WEGvjY&ik;Aa<(pgV>57vh_S zl_GAe$a}89z8X4Dz^_!p;{!3Q2<{l8a8D z6?@E_quNYOiZm}poB#?$$u~20OL%nx9@$UDP}H!m0aCN)d6+3fZ!tXiY_JkkuBw9739-w~Cdk>EORELxEz$;41QoK%Hs;jtyH~ZwgCZnNQUE(< zF7HlwN|cmOJr%m;c=P?9z|6N7KttR0W{j4cNfJe$iG#!O*}+?zC*z`emw~qS5ZLe> zxD7f(Ou=j-siQ`vFZhiP{I{tvS%7=_57TA-FosIvT9ei)G|?xnF*+6-e%Jt1O=k5W z_!Bu8QVlAk{%7GsYaj@k25MtzS%TMz#Lm}=03jO1$fbdT0^Jan3RU{n^|{5mf}%Q| z#~$~KPH)`rIP7->$-F#=I{XIfnC+Gr!anfe50c9`$cH5D4Roy^=H%$N?kO2JN{A z($*RYnke!^{`?H++}QwfC8=XGewFGq(S#yXRc3qKc)wwU)}-AAqR&xjKVnjdLRO?B z;*Jos#cb80VrnSCUkG(GCF?LliIJs4Y*@-J1)K1S(kEGtLM29i6;g7s|JdY9nF}7N zwAz0mR4}vai@WjFeV{771-=+`Pa`z!G&OOyxaW23Mvw7W%HD;`pgGW-vtm3{7Zu?? zPbOXtxB5$A18-1abWIkL$tLa*Kummp93<84_jM+=3Ti$Auh^c&`xWCli2VU7?oa-_ zgNw`BwB|6wEVMMAp;o7bQqAq|#G-6Ab!I4D#qec#-R-0_oQ$o?7(<*SXO{oPuKC(; zHEy#ZFL9J5p@B4&XK}IB4&Sxv?$Ei@{Y6RTjT*W+^Wzn+vhzJuD7{WI-65JY7S~d?X%*u$8jt1ypURz#LvEWxGAo3K9&urlC~WhG!xP5Dl`J`a z7@v#SAgj}OUKp3&K5)*gOKad+y4B<^lIZd(^2FOKU1Th`$tGpDes= ziM)klol-%LQ`&USygXJmYyiJ8$4D@>K^Eb)&3BuxWJiKRf)t7~p@NeIkDs7H2#9

      i#Y--&flGhB;I)eafA5WPZPnjQ2X=CXxYa16IFXSO*1*+Wxj^_=p zE)O9b7SwnGp_5g>H#*H1ydwz2o7?cE#+es9?v4sG2OGUj ze(fb;GVo_hlk|vhop@aj>vUXrqMfcZ;&xXzDZ9T6lxwhNKFHM!mZ-GCnusp!B@QX1+4I5+H8rH=hD%aruX1fxbm2 zTDqy}`%F?{ez;knElF(JUR+B{85hQq3iH76hI!>1Af59A8yB0*x5fM8+(NkzVxsPc zg&*QOGy?FR7j+!K)QIgO$!A2oe=RnA(2_7oe1z&^^^U_^>?0Vs`)|aw9#Q}}bt@bk zi8bdd7`Ykv9SVI7Aw;yR$d7&oafDrUt8LD_--$h?At;HeiXkp43nGZ>?sy3RD4D2y z@(i{gY+QiAZ7I+ZvyPG{elv^=Gd{iN78H}=$zp{uizKV7`J;V+7WV{?dsT5UOKkEM zP2cZQ10*A@5e@V?3;Rea$_RCh)bq9*T<7z)=c_?)NS*E6sCPj#_Bwn{;}IxGQk2ki z#Yn&V0;!=T&J7s)YSs-8+%g1EsOYE5Ufu*_VQuk8Mk6P5Hb#5~N`0e5Ktu?HVmoad zrq5-@L4?qG>xf;VeTMsn=Z456!|3`=25*srkG9uSrndJR_F+(_edthl#{PE3OPWGT zKVHep^c23wCZnb7__eGdZ|t5FtJYI5?zuqA4(s}1$MdnqMd!yrGSyU+4D^r$k#NQF zFjqout!7-1=r7PeS0tPd`);yz;%nr3fvw`ts?e14xNRJUThPh4N4GKzJ(HpybBIJx zhAvR}XdhB#gRca%XM*2Gr?3NYPGu!$;3B%{;89PCe;%e9br!-W+4zLQJj+u}3kFjS z^gDWB2e6@hn_&uwRj60wMm4#E{fbNF0GFf%_7c9NMZc$~@~m+S!*iW2m2A5!5=vG0 zT^H>=Gs^3>-Q~ykRh!;)IIhd@9MNdVYR2Q-58+4mIZvR>JrG_91tp?L?6~YPzuXoM$|-cEn&8H;{1I`8gP%t)@Z_9xMCjmj4;UZv zYKb`g(RS+x=XJDd{{dM&^SJgh8MIE!I5Td@OU_XGA{VuHD5+w|3-SBYzgE{3ewI=@ zG-%$bGgQ9?&BkGWnn#;zjVu}?j!IdRwR)uWvTHxiWoWxqb*>`U_F{U+3OYr4$#ikC zizB+a%IIMvx|VG%CC*9BrPV#=a~8&J^HasNXb|W6)&ZxVexm%T;$G=w1b>ovHLJr{ z6mLn0Q`tLNK;KkEPH}{qm&_;+GJqQw_a$P>aWTId;akPjTqk~+;yUQDw{m-G5pPYI z83|`#xvmZeORO_?Dh_iBmq95>{)<%OU32=&9z3Iv=;YpTa--ka(k%*?VwmsFx{ZIuCH7 zLCKbL3emYY4u4w+zD4gL`w3lacV~l=NjIL!?~N8h2Rn4v6i%~p_LD648?+x4bjG%- zXkJxb+lq)3GUdTBs(Us2ixfilYyGd1!1LLW%xWQJv@;KfjX-bahuo<5tJ)>_R;Ca7 z*@M%S_PdQAkIos?EPv7RWJy7GzJf4Au{wSKq=3}i74|$`)iNT4!4^3^^W4MhxMp^t zx9Y_ayQaf*NK?Exu;}HmNCDBm1GfdIW1&?0yTWW-iQea*=`K%>X5W#{rN$zh186N$mzVd9~a6!wtwe4$L;#B`-n7<@{>=cFKogxvCmd7U## z8N9z;;~?lnC|EUZMF!zKkKEdCxy9$xQd2rz^;qY^sURIH++n>V{XJXL( z`E9%+Nh_Q<_9q8~Pzm0d47-}_=JStgS&ZWenA?3j15tg(Ul1GoO_f4h&XKCHJz5w&O2T*vy^u0@dzthj#1UVe_1ay zY0l+>MB8>f(0X5*(01!b@rH%V7G20A%Q)b^okViKf6c55c@4F5Hr>D{&mZdJ+8c@| zK;mAEC$J~+%TJ$>j|fcCAZPHtj@9uzx97BOyRyc_Jjv;fUf(Y+%<$uH-Am{cG1l3b zeCTLY!FfA(b{4)l)nI21A34#L-aW4ik6$1>~>O?8}AT#ejo`YEHw&0H`0eURU^ll zNM6MLQ-z}o?(gzvT8Zq`OE0`ld~}Q>RyAevT?ed^d~kQY&7l z&sT43WVLcj#gQPptl5YzD8He&axz0- z&4O!WLH3RvY~$hkxCcz@wu4B{4(5EMR#E6y^98Aym(qJpm#vkoAVPK@j8rsDo7p|x zPp$DuX~ zA(F_RB{&Hel0r(!Tf)!RMv0!E_+c#tM}-M)R5LgOIR?(ota)#yC1?YC`q&n<9++Pl z(!AeUR&y;mY11&%K>mg^se~F;M#JU2X;_B z%z^VG`sJc5`0Td>g4Iq5NN(~IBh~p-b#!hXcN)j)PGQt6FH;!soQ$0bq^g6if_Pug zfm3}1?{(~k-3!uS4=A8>^4RE-$ocI?hDbe}7b<9(nP%4=7aHl2-~$g!IEcxr-7nHb zpX{IZkm4l@G;)eUkdt{|mMX833`5Y8sLz{aaJ_B0fwwtAy$gRriI^#U=fRVj0wSvw zuC=5oES|e!IKqD0I7znSD2&P7YiBt0ww&=ITPl&1Jp#@>#aej>vpuj z#Jjbg4OzwDvBCa;h5kv(qU+dvtF(BUx0&7G{Ot36nY;K{w&RlVPW8EBPx5RpY3L@R z_QOr)N8kI~hQB=oF;gC5FDJiYb@0{G!AEWhD?|lgd>nVxX@&Q6(UzkIAROy+bNPJo z@jR!}2^D2B+bkI|^0-J=X|Y$o&s4;u&2HI*8_nQ6k-^D(U(Gv^(>D^b^;yexFJIQ= zP;gyc4GYYU!%j{a1HhtawA&LQSj<%ye8A)R+JCo+bJ240T=D>}Lu2K=(ebh$du{wY z7wtv?`IO-m$4$fs^5?SF11aIAI^J}A0FRmshIhMAp$eTv3$6tzS8(*a9=8VZ}2KD$M_(<$Ap|!6AOC?&IviN1&Ywq=b~qkPRf5-U#yTUI){R6I0P}R zqhx;#@1iulSNfnyd8KB{FY$Hi{w#H`ZbSUSCcS&^O8|Q;Zq4x+K_C*;$EI^h`IsWJ z?!h+rrjDTZ2l(aBT5^9-l?pA*)nAP1^-TvnGbT{SQRfJ*ItvwA3Qw$IU=aca|Bf;? z1VAc3lwI29nZv^K=7dPNk_is!p+$u4H{QqB#}B+5f0A?-ld~)GS*cJ}A(vDhqYCju z;-hB`8Bt|a_>G4fW9}roaicCsL7lYqbUlcJHL@vVVUk7O@9ZrJfqiZ?GNSy}4KAXU z(^kmuKw&1;^L@D0Q{B??rGeMuf|DV6RxV)`|KF6yKY5-l5|l#d=N)r$tUCRuVGLSY za(aY-ChCq)$%H@=#v)RBc9Fz~paH^NNdGD2Z0pAwRk3MfiZ z*$tSs7!3-Sd;(BXBJ!F~rlA3vbtNSRtK^AE4hj1GS^E7BGcYqtDFyS6ib*28U(Tcd z#J2z3bcGPn1r7Bv)GDyl$F-=tzrgKVOa#qB_1ldNje&ROBz3qz<;N-v35bdT=(fd7 z$yXDa5je4WOnW4);G+qSQE?R3#OF7O=!=lEV)g4S*pw`uJLK)&G^fHE=jZ1avZzAK zR_N)ey#F1D{Bxhi_76DXk@Zc9I9Z&jq3mq>R9J|YJJ z+*JKMgw9GyVJB*pIxs-F`e1e6cUQw*kva^Y!IxRoTgqjQk^C|ApWG z^|EO;AhjWqifEI}2+d{%)2`He;d>{w2}Z{OG2gn`lpvK?LvID8%U1l;L*0lLNj#HK z5~jbY-|Iu_?B7ahk|BTF-E)w$XZ()kJRm@+q|xZ{q*5^9{~sduPg%1^EYj`~%pjQ; zO=z49KY^hZB81Q(5ZsrWDzn$tBZu~v6=EyT!2qvPn$uHxV2BWB$8shQJox^nr2e^) z5YT0j+0Pq-KAE4*aJp9uI+b(Zyt4oaBVz^|_NJ&KvAd7U)s99YgQuuEbwloM;4gsu zR&a_i2I*|n|0zc!98ceb)H83p4gRVcyrJKFTT+SHk@%9IP-DSmzu~zcFki1r?oT)J z&rL#bS6PN6dKbpmq9o_}`xy<^bf#kp!e&H%Wg+5db`}%CCq$>o*liT%kya5nS=dnS z7Kt=6H~&+r1917Xm<3i%6LzB=bk2qv8&V%J7O9lq_2kmR|n=feSp8Wj}n?x`ph{|c;z~R%$--j3izBm>Yao&}WrLM?PX-h|4{7KM1HNDP;uU2WNkyteU zRoFg3l;MHcheI5Z zs)|Px8eFMTB{S(K_;6JP(wvTjBFH0)&)Rbh+H$q-E(%SIoA+1mV^GG|Wr;;EqK5GV z)Wyry`AoA~MLi4e%-?a2Z*=o5q1!ahu1&8`%7(o|3>K$hZTvg>{U_%s zfAx6^l^hanLcu3pnOH6R`d;cTlIBsl1IF_XwUv$RC{n5esu&7)A%;AfYDfb*U&U<%8Dmh>!aEL3f2i7} z{cv9$DO+oLD+}CT3JnwW43^|y{EbhBfga%k1p5*}ZF==I3g-RW9Vh4*s~NDX>Br0S zGYu94bChRG{~jXyr(~$gfua&H7!8%>9A+=4nMusf{j7E5$jh=ck4y(d;7)z5dv-K^ z#6xR=NX#GF&TZ*7jVL5(OGtSZX4VUEn&LCGT*pDjr7oDk2sN@J{4XP;+6{_I#sF|e zbo&vjmbqjXh!~aI5F$@SM$D;3#&mxVV{SIBI+TPMF?2;JSfJvdu?;i7vWy%@+08H! zQ;uv|t8MC(CU07$XroLgCLQs=VWyHSpEpXbGob`K?MSik+S80}33-RR0t-vXqKInn)T$+2xpjY3V=t6U!O| z3NaZemQg{un3-AKCX~>i!ZNW`kK!s^Z6-!)mh^77r`IR|O~K;ILcfV55%cW+Yv7#6 zu;Sb&W;q)lK`t${3B#D_@V^uO*e+keeScI*zSHyqmE|`yKIT7;G@;( zsSRDZpLUh4-_-rbN0y1ml;mwauErV~>hJED1FErNKAEZ(73U}x>XSV<|k@psv zOsx2Ob(nI1Te!onU?G>H9-XJ?KY}-1C4`qBAqbI)s{ImTf83xcCL}Fb!LRH4{{X8W BcZ>i4 From d584076f9e2c24beaf50b6fc006a6b3e49d4705b Mon Sep 17 00:00:00 2001 From: Ryan T Date: Wed, 27 Jun 2018 17:47:44 -0400 Subject: [PATCH 2255/2527] Update parseResponseHeaders to work in fastboot. (#5502) * Update parseResponseHeaders so it works in fastboot. On nix systems the headers will be delimited with only a newline (\n) character. This PR changes the split to \r?\n, which will work for all fastboot environments as well as browsers. * Fix eslint errors --- .../-private/utils/parse-response-headers.js | 5 +++-- .../unit/utils/parse-response-headers-test.js | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/addon/-private/utils/parse-response-headers.js b/addon/-private/utils/parse-response-headers.js index 3e02ab16fc8..ef8e8fa7d20 100644 --- a/addon/-private/utils/parse-response-headers.js +++ b/addon/-private/utils/parse-response-headers.js @@ -1,4 +1,4 @@ -const CLRF = '\u000d\u000a'; +const newline = /\r?\n/; export default function parseResponseHeaders(headersString) { let headers = Object.create(null); @@ -7,7 +7,8 @@ export default function parseResponseHeaders(headersString) { return headers; } - let headerPairs = headersString.split(CLRF); + let headerPairs = headersString.split(newline); + for (let i = 0; i < headerPairs.length; i++) { let header = headerPairs[i]; let j = 0; diff --git a/tests/unit/utils/parse-response-headers-test.js b/tests/unit/utils/parse-response-headers-test.js index 7ac9dde93dd..b74eef497a5 100644 --- a/tests/unit/utils/parse-response-headers-test.js +++ b/tests/unit/utils/parse-response-headers-test.js @@ -2,6 +2,7 @@ import { parseResponseHeaders } from 'ember-data/-private'; import { module, test } from 'qunit'; const CRLF = '\u000d\u000a'; +const LF = '\u000a'; module('unit/adapters/parse-response-headers'); @@ -103,3 +104,21 @@ test('tollerate extra new-lines', function(assert) { assert.deepEqual(headers['foo'], 'bar', 'parses basic header pair'); assert.equal(Object.keys(headers).length, 1, 'only has the one valid header'); }); + +test('works with only line feeds', function(assert) { + let headersString = [ + 'Content-Encoding: gzip', + 'content-type: application/json; charset=utf-8', + 'date: Fri, 05 Feb 2016 21:47:56 GMT', + ].join(LF); + + let headers = parseResponseHeaders(headersString); + + assert.equal(headers['Content-Encoding'], 'gzip', 'parses basic header pair'); + assert.equal( + headers['content-type'], + 'application/json; charset=utf-8', + 'parses header with complex value' + ); + assert.equal(headers['date'], 'Fri, 05 Feb 2016 21:47:56 GMT', 'parses header with date value'); +}); From 50b2fead8f7e7abc7de1308e7a0d57a54119b001 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 29 Jun 2018 12:49:07 -0400 Subject: [PATCH 2256/2527] Add 3.2.0 to CHANGELOG.md. [ci skip] --- CHANGELOG.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f65519aff2..75598ace537 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,47 @@ ### Master +### Release 3.2.0 (June 29, 2018) + +- [#5497](https://github.com/emberjs/data/pull/5497) [BUGFIX] Make snapshot lazier and fix defaultValue. +- [#5499](https://github.com/emberjs/data/pull/5499) [BUGFIX] Backport fix infinite relationship retry issue from #5492. +- [#5508](https://github.com/emberjs/data/pull/5508) [CHORE] Update Dependencies to avoid `broccoli-funnel` deprecation. +- [#5432](https://github.com/emberjs/data/pull/5432) [CHORE] Remove `exists-sync` dependency. +- [#5436](https://github.com/emberjs/data/pull/5436) [CHORE] Remove all usage of `Ember.copy` to avoid future deprecation. +- [#5437](https://github.com/emberjs/data/pull/5437) / [#5459](https://github.com/emberjs/data/pull/5459) [CHORE] Removes deprecated `store.filter` feature, must migrate to `ember-data-filter@2.0.0` for similar API usage. +- [#5461](https://github.com/emberjs/data/pull/5461) [BUGFIX] Update content of proxy for async belongs-to relationships when null data received +- [#5467](https://github.com/emberjs/data/pull/5467) [BUGFIX] Avoid unnecessary work during destruction process. +- [#5439](https://github.com/emberjs/data/pull/5439) [FEAT] FASTBOOT SHOEBOX - Use actions queue so rehydration works +- [#5412](https://github.com/emberjs/data/pull/5412) Fix npmignore and cleanup test artifacts before publishing +- [#4977](https://github.com/emberjs/data/pull/4977) Trap exceptions that are thrown from adapter methods +- [#4856](https://github.com/emberjs/data/pull/4856) [BUGFIX #4497] query/queryRecord/filter now support adapter options +- [#5408](https://github.com/emberjs/data/pull/5408) [FEAT BUGFIX] enable canonical state updates to deleted records +- [#5336](https://github.com/emberjs/data/pull/5336) [CHORE] remove all benchmark related code +- [#5324](https://github.com/emberjs/data/pull/5324) Don't serialize new has many relationships +- [#5405](https://github.com/emberjs/data/pull/5405) [CHORE] remove dead methods left behind from ff removal +- [#5406](https://github.com/emberjs/data/pull/5406) [BUGFIX release] Fix `Model.modelName` inheritance with Ember 3.2+. +- [#5366](https://github.com/emberjs/data/pull/5366) fix initial polymorphic attribute +- [#5345](https://github.com/emberjs/data/pull/5345) Check if adapter#query is a wrapped function +- [#5385](https://github.com/emberjs/data/pull/5385) Use `najax` in `fastboot` and some refactoring to isolate `jQuery.ajax` +- [#5399](https://github.com/emberjs/data/pull/5399) Remove unneeded feature flagged tests +- [#5410](https://github.com/emberjs/data/pull/5410) [FEAT BUGFIX] resolves issues with links and data in relationships (#5410) +- [#5413](https://github.com/emberjs/data/pull/5413) [BUGFIX] Fix availability of properties in createRecord init +- [#5414](https://github.com/emberjs/data/pull/5414) [FEAT BUGFIX] adds adapterOptions ability to model.reload() +- [#5415](https://github.com/emberjs/data/pull/5415) make createRecord sync and remove unnecessary run usage in tests +- [#5416](https://github.com/emberjs/data/pull/5416) adds a more robust test around reload +- [#5418](https://github.com/emberjs/data/pull/5418) Limit CI runs on branches to master, beta, release +- [#5422](https://github.com/emberjs/data/pull/5422) [FEAT] Prevent async test leakage (feat. adds test waiters) +- [#4977](https://github.com/emberjs/data/pull/4977) Trap exceptions that are thrown from adapter methods and reject the (#4977) +- [#5379](https://github.com/emberjs/data/pull/5379) minor typo +- [#5382](https://github.com/emberjs/data/pull/5382) [FIX] update ember-cli-dependency-checker to avoid deprecation warning +- [#5371](https://github.com/emberjs/data/pull/5371) Upgrade to ember-cli-qunit 4.0 and replace ember-dev with ember-qunit… (#5371) +- [#5369](https://github.com/emberjs/data/pull/5369) [BUGFIX beta] Fix createRecord creating two records +- [#5375](https://github.com/emberjs/data/pull/5375) Remove jQuery usage from tests (#5375) +- [#5378](https://github.com/emberjs/data/pull/5378) [BUGFIX] resolve issues with RecordArray sync for peekAll (#5378) +- [#5381](https://github.com/emberjs/data/pull/5381) [FEAT BREAKING] remove globals build for 3.x (#5381) +- [#5383](https://github.com/emberjs/data/pull/5383) fix external ordered set dependency +- [#5384](https://github.com/emberjs/data/pull/5384) [FEAT] remove all stale feature flags (#5384) + ### Release 3.1.1 (March 27, 2018) - [#5383](https://github.com/emberjs/data/pull/5383) Remove '@ember/ordered-set' warning when building Ember Data From 50a3a8c15956f1169a8a69cb425a4e317c1a4308 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 29 Jun 2018 12:54:15 -0400 Subject: [PATCH 2257/2527] Add v3.3.0-beta.1 to CHANGELOG.md. (cherry picked from commit 88adfef1bb3c4332f456cf77918bbdfc1e7d6f72) --- CHANGELOG.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75598ace537..df5982b94cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,27 @@ ### Master +### Release 3.3.0-beta.1 (June 29, 2018) + +- [#5467](https://github.com/emberjs/data/pull/5467) [BUGFIX] don't cause unnecessary work during destroy +- [#5411](https://github.com/emberjs/data/pull/5411) Remove deprecations scheduled for 3.0 +- [#5117](https://github.com/emberjs/data/pull/5117) Give Model a static toString method +- [#5429](https://github.com/emberjs/data/pull/5429) improve tests for unloading relationships +- [#5469](https://github.com/emberjs/data/pull/5469) Revamp eslint configuration. +- [#5439](https://github.com/emberjs/data/pull/5439) [FEAT] FASTBOOT SHOEBOX - Use actions queue so rehydration works +- [#5432](https://github.com/emberjs/data/pull/5432) Remove exists-sync dependency +- [#5436](https://github.com/emberjs/data/pull/5436) [CHORE] remove all usage of Ember.copy +- [#5438](https://github.com/emberjs/data/pull/5438) [BUGFIX] ensure destroy-sync cleanup is correct +- [#5437](https://github.com/emberjs/data/pull/5437) [CHORE] removes deprecated Store.filter feature +- [#5462](https://github.com/emberjs/data/pull/5462) [BUGFIX] ensure ManyArray state is in-sync with relationship state +- [#5446](https://github.com/emberjs/data/pull/5446) [CLEANUP] fix model and factory lookup +- [#5466](https://github.com/emberjs/data/pull/5466) Serialize empty hasMany relationships +- [#5461](https://github.com/emberjs/data/pull/5461) [BUGFIX] update content of proxy for async belongs-to relationships when null data received +- [#5471](https://github.com/emberjs/data/pull/5471) [CHORE] cull unnecessary files left from previous build setups +- [#5476](https://github.com/emberjs/data/pull/5476) [Feature] added module-unification adapter and adapter-test blueprints +- [#5508](https://github.com/emberjs/data/pull/5508) [CHORE] Update Dependencies + + ### Release 3.2.0 (June 29, 2018) - [#5497](https://github.com/emberjs/data/pull/5497) [BUGFIX] Make snapshot lazier and fix defaultValue. From 498c533d386085412ac97d0061022ef032d950ae Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Fri, 29 Jun 2018 12:57:07 -0400 Subject: [PATCH 2258/2527] Post release version bump. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0f803c95d2a..c98a90c584f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "3.3.0-canary", + "version": "3.4.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From c204e756bd2917b48400b42f56601830eb56d393 Mon Sep 17 00:00:00 2001 From: Pete Date: Mon, 2 Jul 2018 13:54:19 -0700 Subject: [PATCH 2259/2527] [BUGFIX] Adding tests to assert exception when saving unloaded record (#5512) --- tests/integration/records/save-test.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/integration/records/save-test.js b/tests/integration/records/save-test.js index 86abd1f34fa..58164fd38ac 100644 --- a/tests/integration/records/save-test.js +++ b/tests/integration/records/save-test.js @@ -182,3 +182,25 @@ test('Will reject save on invalid', function(assert) { ); }); }); + +test('Will error when saving after unloading record via the store', function(assert) { + assert.expect(1); + let post = env.store.createRecord('post', { title: 'toto' }); + run(function() { + env.store.unloadAll('post'); + assert.throws(function() { + post.save(); + }, 'Attempting to save the unloaded record threw an error'); + }); +}); + +test('Will error when saving after unloading record', function(assert) { + assert.expect(1); + let post = env.store.createRecord('post', { title: 'toto' }); + run(function() { + post.unloadRecord(); + assert.throws(function() { + post.save(); + }, 'Attempting to save the unloaded record threw an error'); + }); +}); From a802eadc1cc66b0b5965594633a57c3e0404c23e Mon Sep 17 00:00:00 2001 From: Frederic ST Date: Mon, 2 Jul 2018 22:54:39 +0200 Subject: [PATCH 2260/2527] install ember-cli-yuidoc addon (#5505) --- .npmignore | 1 - ember-cli-build.js | 10 +------- lib/yuidoc.js | 19 ---------------- package.json | 2 +- yarn.lock | 57 ++++++++++++++++++++++++++++++++++------------ yuidoc.json | 15 ++++++++++++ 6 files changed, 59 insertions(+), 45 deletions(-) delete mode 100644 lib/yuidoc.js create mode 100644 yuidoc.json diff --git a/.npmignore b/.npmignore index 4a0e13d6067..4c46690a01b 100644 --- a/.npmignore +++ b/.npmignore @@ -25,5 +25,4 @@ testem.js *.gemspec **/*.rb node-tests/ -lib/yuidoc.js lib/version-replace.js diff --git a/ember-cli-build.js b/ember-cli-build.js index 432afc11cd1..b50c370c723 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -1,8 +1,6 @@ 'use strict'; const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); -const merge = require('broccoli-merge-trees'); -const yuidoc = require('./lib/yuidoc'); module.exports = function(defaults) { let app = new EmberAddon(defaults, {}); @@ -14,11 +12,5 @@ module.exports = function(defaults) { behave. You most likely want to be modifying `./index.js` or app's build file */ - let appTree = app.toTree(); - - if (process.env.EMBER_ENV === 'production') { - return merge([appTree, yuidoc()]); - } else { - return appTree; - } + return app.toTree(); }; diff --git a/lib/yuidoc.js b/lib/yuidoc.js deleted file mode 100644 index 7b560eb2ee5..00000000000 --- a/lib/yuidoc.js +++ /dev/null @@ -1,19 +0,0 @@ -var YUIDoc = require('broccoli-yuidoc'); -var calculateVersion = require('./calculate-version'); - -module.exports = function yui() { - return new YUIDoc(['addon', 'node_modules/ember-inflector/addon'], { - destDir: 'docs', - yuidoc: { - name: 'The ember-data API', - description: 'The ember-data API: a data persistence library for Ember.js', - version: calculateVersion(), - logo: 'http://f.cl.ly/items/1A1L432s022u1O1q1V3p/ember%20logo.png', - url: 'https://github.com/emberjs/data', - options: { - exclude: 'vendor', - outdir: 'docs/build', - }, - }, - }); -}; diff --git a/package.json b/package.json index c98a90c584f..29a81056319 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,6 @@ "broccoli-string-replace": "^0.1.1", "broccoli-test-helper": "^1.2.0", "broccoli-uglify-sourcemap": "^1.0.1", - "broccoli-yuidoc": "^3.0.0", "co": "^4.6.0", "common-tags": "^1.4.0", "ember-cli": "^3.1.4", @@ -91,6 +90,7 @@ "ember-cli-sri": "^2.1.0", "ember-cli-test-loader": "^2.2.0", "ember-cli-uglify": "2.0.0-beta.1", + "ember-cli-yuidoc": "^0.8.8", "ember-decorators": "^2.1.0", "ember-disable-prototype-extensions": "^1.1.0", "ember-disable-proxy-controllers": "^1.0.1", diff --git a/yarn.lock b/yarn.lock index 8b6ee9d51aa..5f53f6e0be6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1421,6 +1421,19 @@ broccoli-caching-writer@^3.0.3: rsvp "^3.0.17" walk-sync "^0.3.0" +broccoli-caching-writer@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" + dependencies: + broccoli-kitchen-sink-helpers "^0.2.5" + broccoli-plugin "1.1.0" + debug "^2.1.1" + lodash-node "^3.2.0" + rimraf "^2.2.8" + rsvp "^3.0.17" + symlink-or-copy "^1.0.0" + walk-sync "^0.2.0" + broccoli-clean-css@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" @@ -1561,7 +1574,7 @@ broccoli-lint-eslint@^4.2.1: lodash.defaultsdeep "^4.6.0" md5-hex "^2.0.0" -broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.2.1: +broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.1, broccoli-merge-trees@^1.2.1: version "1.2.4" resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" dependencies: @@ -1735,16 +1748,6 @@ broccoli-uglify-sourcemap@^2.0.0-beta.1: walk-sync "^0.3.2" workerpool "^2.3.0" -broccoli-yuidoc@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/broccoli-yuidoc/-/broccoli-yuidoc-3.0.0.tgz#e436588ddfb6ae81ce82d87e894333d0fdd10487" - dependencies: - broccoli-caching-writer "^3.0.3" - broccoli-merge-trees "^2.0.0" - merge "~1.2.0" - rsvp "^3.5.0" - yuidocjs "^0.10.2" - broccoli@^1.1.0: version "1.1.4" resolved "https://registry.npmjs.org/broccoli/-/broccoli-1.1.4.tgz#b023b028b866f447ed14341007961efd03f7251c" @@ -2874,6 +2877,16 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-ve resolve "^1.3.3" semver "^5.3.0" +ember-cli-yuidoc@^0.8.8: + version "0.8.8" + resolved "https://registry.yarnpkg.com/ember-cli-yuidoc/-/ember-cli-yuidoc-0.8.8.tgz#3858baaf85388a976024f9de40f1075fea58f606" + dependencies: + broccoli-caching-writer "~2.0.4" + broccoli-merge-trees "^1.1.1" + git-repo-version "0.2.0" + rsvp "3.0.14" + yuidocjs "^0.10.0" + ember-cli@^3.1.4: version "3.1.4" resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-3.1.4.tgz#95f7ff4302d535619b5d5ff1c7040877a67d4468" @@ -4033,10 +4046,16 @@ get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" -git-repo-info@^1.1.2, git-repo-info@^1.4.1: +git-repo-info@^1.0.4, git-repo-info@^1.1.2, git-repo-info@^1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" +git-repo-version@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-0.2.0.tgz#9a1d0019a50fc9e623c43d1c0fcc437391207d0d" + dependencies: + git-repo-info "^1.0.4" + git-repo-version@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/git-repo-version/-/git-repo-version-1.0.2.tgz#2c8e9bee5d970cafc0dd58480f9dc56d9afe8e4f" @@ -5030,6 +5049,10 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" +lodash-node@^3.2.0: + version "3.10.2" + resolved "https://registry.yarnpkg.com/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" + lodash._baseassign@^3.0.0: version "3.2.0" resolved "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" @@ -5533,7 +5556,7 @@ merge-trees@^1.0.1: rimraf "^2.4.3" symlink-or-copy "^1.0.0" -merge@^1.1.3, merge@^1.2.0, merge@~1.2.0: +merge@^1.1.3, merge@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" @@ -6732,6 +6755,10 @@ route-recognizer@^0.3.3: version "0.3.3" resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" +rsvp@3.0.14: + version "3.0.14" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.14.tgz#9d2968cf36d878d3bb9a9a5a4b8e1ff55a76dd31" + rsvp@4.8.0: version "4.8.0" resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.0.tgz#dc1dc400e2d48bcf3b1991f2a3b714f038fc432e" @@ -7821,7 +7848,7 @@ walk-sync@^0.1.3: version "0.1.3" resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" -walk-sync@^0.2.5, walk-sync@^0.2.7: +walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: version "0.2.7" resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" dependencies: @@ -8043,7 +8070,7 @@ yui@^3.18.1: dependencies: request "~2.40.0" -yuidocjs@^0.10.2: +yuidocjs@^0.10.0: version "0.10.2" resolved "https://registry.npmjs.org/yuidocjs/-/yuidocjs-0.10.2.tgz#33924967ce619024cd70ef694e267d2f988f73f6" dependencies: diff --git a/yuidoc.json b/yuidoc.json new file mode 100644 index 00000000000..c77156e0d5a --- /dev/null +++ b/yuidoc.json @@ -0,0 +1,15 @@ +{ + "name": "The ember-data API", + "description": "The ember-data API: a data persistence library for Ember.js", + "url": "https://github.com/emberjs/data", + "options": { + "enabledEnvironments": ["production"], + "extension": ".js,.ts", + "paths": [ + "addon", + "node_modules/ember-inflector/addon" + ], + "exclude": "vendor", + "outdir": "docs" + } +} From eb23128829f6b19f523a88861a6aa914acd54eef Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 6 Jul 2018 08:56:59 -0400 Subject: [PATCH 2261/2527] Add 2.18.3 release to the changelog on master --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index df5982b94cb..24312b9ee7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,6 +121,9 @@ - [#5305](https://github.com/emberjs/data/pull/5305) Serializers and adapters should be unique per store - [#5308](https://github.com/emberjs/data/pull/5308) Simplify the getDescriptor test helper +### Release 2.18.3 (July 6, 2018) +- [#5519](https://github.com/emberjs/data/pull/5519) Do not publish `.node_modules.ember-try` folder to npm + ### Release 2.18.2 (March 1, 2018) - [#5230](https://github.com/emberjs/data/pull/5230) [BUGFIX] enable lazy-relationship payloads to work with polymorphic relationships From 5f8ff88aecadb2bbfd597088a0a0251fb917323e Mon Sep 17 00:00:00 2001 From: Pete Date: Tue, 10 Jul 2018 09:38:02 -0700 Subject: [PATCH 2262/2527] [BUGFIX] Clarifying error message for polymorphic types (#5518) * [BUGFIX] Adding tests to assert exception when saving unloaded record * Clarifying error message for polymorphic types --- addon/-debug/index.js | 3 ++- tests/integration/references/belongs-to-test.js | 2 +- tests/integration/references/has-many-test.js | 2 +- tests/integration/relationships/belongs-to-test.js | 4 ++-- tests/integration/relationships/has-many-test.js | 4 ++-- .../relationships/polymorphic-mixins-belongs-to-test.js | 4 ++-- .../relationships/polymorphic-mixins-has-many-test.js | 4 ++-- tests/unit/utils-test.js | 4 ++-- 8 files changed, 14 insertions(+), 13 deletions(-) diff --git a/addon/-debug/index.js b/addon/-debug/index.js index 240e5031959..900c34edf6b 100644 --- a/addon/-debug/index.js +++ b/addon/-debug/index.js @@ -52,7 +52,8 @@ if (DEBUG) { let relationshipModelName = relationshipMeta.type; let relationshipClass = store.modelFor(relationshipModelName); let addedClass = store.modelFor(addedInternalModel.modelName); - let assertionMessage = `You cannot add a record of modelClass '${addedModelName}' to the '${parentModelName}.${key}' relationship (only '${relationshipModelName}' allowed)`; + + let assertionMessage = `The '${addedModelName}' type does not implement '${relationshipModelName}' and thus cannot be assigned to the '${key}' relationship in '${parentModelName}'. Make it a descendant of '${relationshipModelName}' or use a mixin of the same name.`; assert(assertionMessage, checkPolymorphic(relationshipClass, addedClass)); }; diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index cda9590dff6..c8ce17a0ddb 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -316,7 +316,7 @@ testInDebug('push(record) asserts for invalid modelClass', function(assert) { run(function() { familyReference.push(anotherPerson); }); - }, "You cannot add a record of modelClass 'person' to the 'person.family' relationship (only 'family' allowed)"); + }, "The 'person' type does not implement 'family' and thus cannot be assigned to the 'family' relationship in 'person'. Make it a descendant of 'family' or use a mixin of the same name."); }); testInDebug('push(record) works with polymorphic modelClass', function(assert) { diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 9682b97754c..3491a24fbb8 100755 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -245,7 +245,7 @@ testInDebug('push(array) asserts polymorphic type', function(assert) { personsReference.push(data); }); - }, "You cannot add a record of modelClass 'family' to the 'family.persons' relationship (only 'person' allowed)"); + }, "The 'family' type does not implement 'person' and thus cannot be assigned to the 'persons' relationship in 'family'. Make it a descendant of 'person' or use a mixin of the same name."); }); testInDebug('push(object) supports legacy, non-JSON-API-conform payload', function(assert) { diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 6049031bd9f..3616e0efe2b 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -317,7 +317,7 @@ testInDebug( }).then(records => { assert.expectAssertion(() => { records.post.set('user', records.comment); - }, /You cannot add a record of modelClass 'comment' to the 'post.user' relationship/); + }, /The 'comment' type does not implement 'user' and thus cannot be assigned to the 'user' relationship in 'post'/); }); }); } @@ -372,7 +372,7 @@ testInDebug( assert.expectAssertion(() => { comment.set('message', records.user); - }, /You cannot add a record of modelClass 'user' to the 'comment.message' relationship \(only 'message' allowed\)/); + }, /The 'user' type does not implement 'message' and thus cannot be assigned to the 'message' relationship in 'comment'. Make it a descendant of 'message'/); }); }); } diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 2a44b221369..86f00bffc7f 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1751,7 +1751,7 @@ testInDebug( ) { assert.expectAssertion(function() { records[0].get('comments').pushObject(records[1]); - }, /You cannot add a record of modelClass 'post' to the 'post.comments' relationship \(only 'comment' allowed\)/); + }, /The 'post' type does not implement 'comment' and thus cannot be assigned to the 'comments' relationship in 'post'/); }); }); } @@ -1823,7 +1823,7 @@ testInDebug( assert.expectAssertion(function() { records.messages.pushObject(records.anotherUser); - }, /You cannot add a record of modelClass 'user' to the 'user.messages' relationship \(only 'message' allowed\)/); + }, /The 'user' type does not implement 'message' and thus cannot be assigned to the 'messages' relationship in 'user'. Make it a descendant of 'message'/); }); }); } diff --git a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index 3259d0b8a48..1f1167783f3 100644 --- a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -167,7 +167,7 @@ testInDebug( run(function() { assert.expectAssertion(function() { user.set('bestMessage', video); - }, /You cannot add a record of modelClass 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); + }, /The 'not-message' type does not implement 'message' and thus cannot be assigned to the 'bestMessage' relationship in 'user'. Make it a descendant of 'message'/); }); } ); @@ -248,7 +248,7 @@ testInDebug( run(function() { assert.expectAssertion(function() { user.set('bestMessage', video); - }, /You cannot add a record of modelClass 'not-message' to the 'user.bestMessage' relationship \(only 'message' allowed\)/); + }, /The 'not-message' type does not implement 'message' and thus cannot be assigned to the 'bestMessage' relationship in 'user'. Make it a descendant of 'message'/); }); } finally { resetModelFactoryInjections(); diff --git a/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js index 4d3ecd0ff7d..39a343b0803 100644 --- a/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -184,7 +184,7 @@ testInDebug( user.get('messages').then(function(fetchedMessages) { assert.expectAssertion(function() { fetchedMessages.pushObject(notMessage); - }, /You cannot add a record of modelClass 'not-message' to the 'user.messages' relationship \(only 'message' allowed\)/); + }, /The 'not-message' type does not implement 'message' and thus cannot be assigned to the 'messages' relationship in 'user'. Make it a descendant of 'message/); }); }); } @@ -278,7 +278,7 @@ testInDebug( user.get('messages').then(function(fetchedMessages) { assert.expectAssertion(function() { fetchedMessages.pushObject(notMessage); - }, /You cannot add a record of modelClass 'not-message' to the 'user.messages' relationship \(only 'message' allowed\)/); + }, /The 'not-message' type does not implement 'message' and thus cannot be assigned to the 'messages' relationship in 'user'. Make it a descendant of 'message'/); }); }); } finally { diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index b1019afdd80..3bddc49fb10 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -88,7 +88,7 @@ testInDebug('assertPolymorphicType works for subclasses', function(assert) { assert.expectAssertion(() => { assertPolymorphicType(user, relationship, person, env.store); - }, "You cannot add a record of modelClass 'person' to the 'user.messages' relationship (only 'message' allowed)"); + }, "The 'person' type does not implement 'message' and thus cannot be assigned to the 'messages' relationship in 'user'. Make it a descendant of 'message' or use a mixin of the same name."); }); test('modelHasAttributeOrRelationshipNamedType', function(assert) { @@ -147,5 +147,5 @@ testInDebug('assertPolymorphicType works for mixins', function(assert) { assert.expectAssertion(() => { assertPolymorphicType(post, relationship, person, env.store); - }, "You cannot add a record of modelClass 'person' to the 'post.medias' relationship (only 'medium' allowed)"); + }, "The 'person' type does not implement 'medium' and thus cannot be assigned to the 'medias' relationship in 'post'. Make it a descendant of 'medium' or use a mixin of the same name."); }); From 8e28ddcca943ae3ac768cff9ffff626ff682fa51 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 13 Jul 2018 16:22:27 -0400 Subject: [PATCH 2263/2527] Update changelog for 3.3.0 release --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24312b9ee7e..4e8c72641e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ### Master +### Release 3.3.0 (July 13, 2018) + +- Re-release of Ember Data 3.2.0 + ### Release 3.3.0-beta.1 (June 29, 2018) - [#5467](https://github.com/emberjs/data/pull/5467) [BUGFIX] don't cause unnecessary work during destroy From e4978d347490008ab5a147b978d650f24f307c83 Mon Sep 17 00:00:00 2001 From: bmac Date: Fri, 13 Jul 2018 16:52:11 -0400 Subject: [PATCH 2264/2527] Bump the canary version to 3.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29a81056319..67493cb5391 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "3.4.0-canary", + "version": "3.5.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From f2b72539acc308a9ebac8c5ba856e707ce447a9b Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Fri, 13 Jul 2018 17:24:03 -0400 Subject: [PATCH 2265/2527] Update links to builds page fixtures --- RELEASE.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index ce6301e96dd..5ff8d2619e7 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -25,9 +25,7 @@ STEPS: * `npm publish` or `npm publish --tag beta` or `npm publish --tag release-1-13` * Update the `/builds/` page on the website * `cd ../website` - * Edit [lastRelease, futureVersion and date](https://github.com/emberjs/website/blob/master/source/javascripts/app/builds/app.js#L238-L241) values for the release channel we are releasing. - * Commit updated `javascripts/app/builds/app.js` file - * `rake deploy` + * Edit `lastRelease`, `futureVersion` and `date` values for the release channel we are releasing ([beta](https://github.com/ember-learn/builds/blob/master/app/fixtures/ember-data/beta.js) or [release](https://github.com/ember-learn/builds/blob/master/app/fixtures/ember-data/release.js). * Write a Release Blog Post (Does not happen for beta releases) * Commits since last release: `git log --oneline release..beta | wc -l`. * Contributors since last release: `git shortlog -s -n release...beta | wc -l` From 43f2077a9e78f882f2e480d5db6b92825c6c82fb Mon Sep 17 00:00:00 2001 From: jelhan Date: Sat, 14 Jul 2018 04:28:43 +0200 Subject: [PATCH 2266/2527] [DOC]: default behaviour of serializers/json shouldSerializeHasMany method (#5516) --- addon/serializers/json.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 8fd59410393..8fef55ccf0a 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -135,8 +135,8 @@ const JSONSerializer = Serializer.extend({ }); ``` - You can also remove attributes by setting the `serialize` key to - `false` in your mapping object. + You can also remove attributes and relationships by setting the `serialize` + key to `false` in your mapping object. Example @@ -163,6 +163,10 @@ const JSONSerializer = Serializer.extend({ Note that the `admin` is now not included in the payload. + Setting `serialize` to `true` enforces serialization for hasMany + relationships even if it's neither a many-to-many nor many-to-none + relationship. + @property attrs @type {Object} */ @@ -845,6 +849,9 @@ const JSONSerializer = Serializer.extend({ /** Check if the given hasMany relationship should be serialized + By default only many-to-many and many-to-none relationships are serialized. + This could be configured per relationship by Serializer's `attrs` object. + @method shouldSerializeHasMany @param {DS.Snapshot} snapshot @param {String} key From aa4dfa44b4f2b395ff8f6cf5aef84b0a36f924cc Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 28 Jun 2018 15:16:12 -0700 Subject: [PATCH 2267/2527] pairing with Gabby for createRecord + unloadRecord tests --- .../integration/records/create-record-test.js | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tests/integration/records/create-record-test.js diff --git a/tests/integration/records/create-record-test.js b/tests/integration/records/create-record-test.js new file mode 100644 index 00000000000..80e9085854e --- /dev/null +++ b/tests/integration/records/create-record-test.js @@ -0,0 +1,72 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import Store from 'ember-data/store'; +import Model from 'ember-data/model'; +import { attr, belongsTo, hasMany } from '@ember-decorators/data'; + +class Person extends Model { + @hasMany('pet', { inverse: 'owner', async: false }) + pets; + @attr name; +} + +class Pet extends Model { + @belongsTo('person', { inverse: 'pets', async: false }) + owner; + @attr name; +} + +module('Store.createRecord() coverage', function(hooks) { + let store; + setupTest(hooks); + + hooks.beforeEach(function() { + let { owner } = this; + owner.register('service:store', Store); + owner.register('model:person', Person); + owner.register('model:pet', Pet); + store = owner.lookup('service:store'); + }); + + test('unloading a newly created a record with a relationship', function (assert) { + let chris = store.push({ + data: { + id: '1', + type: 'person', + attributes: { + name: 'Chris' + }, + relationships: { + pets: { + data: [] + } + } + } + }); + + let pet = store.createRecord('pet', { + name: 'Shen', + owner: chris + }); + + // check that we are properly configured + assert.ok(pet.get('owner') === chris, 'Precondition: Our owner is Chris'); + + let pets = chris.get('pets').toArray().map((pet => pet.get('name'))); + assert.deepEqual(pets, ['Shen'], 'Precondition: Chris has Shen as a pet'); + + pet.unloadRecord(); + + debugger; + + assert.ok(pet.get('owner') === null, 'Shen no longer has an owner'); + + // check that the relationship has been dissolved + pets = chris.get('pets').toArray().map((pet => pet.get('name'))); + assert.deepEqual(pets, [], 'Chris no longer has any pets'); + }); + + test('unloading a record related to a newly created record', function (assert) { + + }); +}); From 3d6a2033496b602c2a5191172ab9d4d03636d0af Mon Sep 17 00:00:00 2001 From: Gabby Josebachvili Date: Thu, 5 Jul 2018 11:00:50 -0400 Subject: [PATCH 2268/2527] added test for unloading --- .../integration/records/create-record-test.js | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/tests/integration/records/create-record-test.js b/tests/integration/records/create-record-test.js index 80e9085854e..ed443e10edd 100644 --- a/tests/integration/records/create-record-test.js +++ b/tests/integration/records/create-record-test.js @@ -57,8 +57,6 @@ module('Store.createRecord() coverage', function(hooks) { pet.unloadRecord(); - debugger; - assert.ok(pet.get('owner') === null, 'Shen no longer has an owner'); // check that the relationship has been dissolved @@ -67,6 +65,39 @@ module('Store.createRecord() coverage', function(hooks) { }); test('unloading a record related to a newly created record', function (assert) { + let chris = store.push({ + data: { + id: '1', + type: 'person', + attributes: { + name: 'Chris' + }, + relationships: { + pets: { + data: [] + } + } + } + }); + + let pet = store.createRecord('pet', { + name: 'Shen', + owner: chris + }); + + // check that we are properly configured + assert.ok(pet.get('owner') === chris, 'Precondition: Our owner is Chris'); + + let pets = chris.get('pets').toArray().map((pet => pet.get('name'))); + assert.deepEqual(pets, ['Shen'], 'Precondition: Chris has Shen as a pet'); + + chris.unloadRecord(); + + assert.ok(pet.get('owner') === null, 'Shen no longer has an owner'); + + // check that the relationship has been dissolved + pets = chris.get('pets').toArray().map((pet => pet.get('name'))); + assert.deepEqual(pets, [], 'Chris no longer has any pets'); }); }); From 966fbc564d2bd72ad8c8f9385d9bde552fbdb99a Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 16 Jul 2018 14:05:00 -0700 Subject: [PATCH 2269/2527] prettier the new test file --- .../integration/records/create-record-test.js | 49 ++++++++++++------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/tests/integration/records/create-record-test.js b/tests/integration/records/create-record-test.js index ed443e10edd..78e0bc88b2b 100644 --- a/tests/integration/records/create-record-test.js +++ b/tests/integration/records/create-record-test.js @@ -28,31 +28,34 @@ module('Store.createRecord() coverage', function(hooks) { store = owner.lookup('service:store'); }); - test('unloading a newly created a record with a relationship', function (assert) { + test('unloading a newly created a record with a relationship', function(assert) { let chris = store.push({ data: { id: '1', type: 'person', attributes: { - name: 'Chris' + name: 'Chris', }, relationships: { pets: { - data: [] - } - } - } + data: [], + }, + }, + }, }); let pet = store.createRecord('pet', { name: 'Shen', - owner: chris + owner: chris, }); // check that we are properly configured assert.ok(pet.get('owner') === chris, 'Precondition: Our owner is Chris'); - let pets = chris.get('pets').toArray().map((pet => pet.get('name'))); + let pets = chris + .get('pets') + .toArray() + .map(pet => pet.get('name')); assert.deepEqual(pets, ['Shen'], 'Precondition: Chris has Shen as a pet'); pet.unloadRecord(); @@ -60,35 +63,41 @@ module('Store.createRecord() coverage', function(hooks) { assert.ok(pet.get('owner') === null, 'Shen no longer has an owner'); // check that the relationship has been dissolved - pets = chris.get('pets').toArray().map((pet => pet.get('name'))); + pets = chris + .get('pets') + .toArray() + .map(pet => pet.get('name')); assert.deepEqual(pets, [], 'Chris no longer has any pets'); }); - test('unloading a record related to a newly created record', function (assert) { + test('unloading a record related to a newly created record', function(assert) { let chris = store.push({ data: { id: '1', type: 'person', attributes: { - name: 'Chris' + name: 'Chris', }, relationships: { pets: { - data: [] - } - } - } + data: [], + }, + }, + }, }); let pet = store.createRecord('pet', { name: 'Shen', - owner: chris + owner: chris, }); // check that we are properly configured assert.ok(pet.get('owner') === chris, 'Precondition: Our owner is Chris'); - let pets = chris.get('pets').toArray().map((pet => pet.get('name'))); + let pets = chris + .get('pets') + .toArray() + .map(pet => pet.get('name')); assert.deepEqual(pets, ['Shen'], 'Precondition: Chris has Shen as a pet'); chris.unloadRecord(); @@ -96,8 +105,10 @@ module('Store.createRecord() coverage', function(hooks) { assert.ok(pet.get('owner') === null, 'Shen no longer has an owner'); // check that the relationship has been dissolved - pets = chris.get('pets').toArray().map((pet => pet.get('name'))); + pets = chris + .get('pets') + .toArray() + .map(pet => pet.get('name')); assert.deepEqual(pets, [], 'Chris no longer has any pets'); - }); }); From 7364cce5b46adf7c3b9ff3d2231e16d2bca47e9a Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 16 Jul 2018 14:27:23 -0700 Subject: [PATCH 2270/2527] new style tests should be async --- tests/integration/records/create-record-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/records/create-record-test.js b/tests/integration/records/create-record-test.js index 78e0bc88b2b..98f2725ed83 100644 --- a/tests/integration/records/create-record-test.js +++ b/tests/integration/records/create-record-test.js @@ -28,7 +28,7 @@ module('Store.createRecord() coverage', function(hooks) { store = owner.lookup('service:store'); }); - test('unloading a newly created a record with a relationship', function(assert) { + test('unloading a newly created a record with a relationship', async function(assert) { let chris = store.push({ data: { id: '1', @@ -70,7 +70,7 @@ module('Store.createRecord() coverage', function(hooks) { assert.deepEqual(pets, [], 'Chris no longer has any pets'); }); - test('unloading a record related to a newly created record', function(assert) { + test('unloading a record related to a newly created record', async function(assert) { let chris = store.push({ data: { id: '1', From 4017bae1ff4ac81aaeec870cab36d0d440c3adb3 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 17 Jul 2018 12:36:15 -0700 Subject: [PATCH 2271/2527] improve messages --- addon/-legacy-private/system/model/internal-model.js | 2 +- tests/integration/records/create-record-test.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/-legacy-private/system/model/internal-model.js b/addon/-legacy-private/system/model/internal-model.js index 0f4f7968950..f00bbb0d3b2 100644 --- a/addon/-legacy-private/system/model/internal-model.js +++ b/addon/-legacy-private/system/model/internal-model.js @@ -53,7 +53,7 @@ function areAllModelsUnloaded(internalModels) { } // Handle dematerialization for relationship `rel`. In all cases, notify the -// relatinoship of the dematerialization: this is done so the relationship can +// relationship of the dematerialization: this is done so the relationship can // notify its inverse which needs to update state // // If the inverse is sync, unloading this record is treated as a client-side diff --git a/tests/integration/records/create-record-test.js b/tests/integration/records/create-record-test.js index 98f2725ed83..59b0040c433 100644 --- a/tests/integration/records/create-record-test.js +++ b/tests/integration/records/create-record-test.js @@ -28,7 +28,7 @@ module('Store.createRecord() coverage', function(hooks) { store = owner.lookup('service:store'); }); - test('unloading a newly created a record with a relationship', async function(assert) { + test('unloading a newly created a record with a sync belongsTo relationship', async function(assert) { let chris = store.push({ data: { id: '1', @@ -70,7 +70,7 @@ module('Store.createRecord() coverage', function(hooks) { assert.deepEqual(pets, [], 'Chris no longer has any pets'); }); - test('unloading a record related to a newly created record', async function(assert) { + test('unloading a record with a sync hasMany relationship to a newly created record', async function(assert) { let chris = store.push({ data: { id: '1', From b4f1c8dda113c5b98ad05c497af25b2c5f53ae98 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 17 Jul 2018 14:51:24 -0700 Subject: [PATCH 2272/2527] ensure flag state is correct for belongsTo when canonical records are changed --- .../system/relationships/state/belongs-to.js | 13 +++++++++ .../system/relationships/state/belongs-to.js | 27 +++++++++++++++++-- .../relationships/state/relationship.js | 1 + addon/-record-data-private/system/store.js | 6 ++--- .../relationships/one-to-many-test.js | 2 +- 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/addon/-legacy-private/system/relationships/state/belongs-to.js b/addon/-legacy-private/system/relationships/state/belongs-to.js index 6e50e40d4e3..7e924bdfa5a 100644 --- a/addon/-legacy-private/system/relationships/state/belongs-to.js +++ b/addon/-legacy-private/system/relationships/state/belongs-to.js @@ -72,6 +72,8 @@ export default class BelongsToRelationship extends Relationship { } this.canonicalState = internalModel; + this.setHasAnyRelationshipData(true); + this.setRelationshipIsEmpty(false); super.addCanonicalInternalModel(internalModel); } @@ -169,6 +171,17 @@ export default class BelongsToRelationship extends Relationship { return; } this.canonicalState = null; + /* + This isn't exactly correct because another record's payload + may tell us that this relationship is no longer correct + but that is not enough to tell us that this relationship is + now empty for sure. Likely we should be stale here but + that is probably a breaking change. + + - @runspired + */ + this.setHasAnyRelationshipData(true); + this.setRelationshipIsEmpty(true); super.removeCanonicalInternalModelFromOwn(internalModel); } diff --git a/addon/-record-data-private/system/relationships/state/belongs-to.js b/addon/-record-data-private/system/relationships/state/belongs-to.js index 231c9e78d5f..ccd008f15b3 100644 --- a/addon/-record-data-private/system/relationships/state/belongs-to.js +++ b/addon/-record-data-private/system/relationships/state/belongs-to.js @@ -57,6 +57,8 @@ export default class BelongsToRelationship extends Relationship { this.canonicalState = modelData; super.addCanonicalModelData(modelData); + this.setHasAnyRelationshipData(true); + this.setRelationshipIsEmpty(false); } inverseDidDematerialize() { @@ -155,6 +157,17 @@ export default class BelongsToRelationship extends Relationship { return; } this.canonicalState = null; + /* + This isn't exactly correct because another record's payload + may tell us that this relationship is no longer correct + but that is not enough to tell us that this relationship is + now empty for sure. Likely we should be stale here but + that is probably a breaking change. + + - @runspired + */ + this.setHasAnyRelationshipData(true); + this.setRelationshipIsEmpty(true); super.removeCanonicalModelDataFromOwn(modelData); } @@ -188,10 +201,20 @@ export default class BelongsToRelationship extends Relationship { return payload; } - localStateIsEmpty() { + /** + * Flag indicating whether all inverse records are available + * + * true if the inverse exists and is loaded (not empty) + * true if there is no inverse + * false if the inverse exists and is not loaded (empty) + * + * @returns {boolean} + */ + get allInverseRecordsAreLoaded() { let modelData = this.inverseModelData; + let isEmpty = modelData !== null && modelData.isEmpty(); - return !modelData || modelData.isEmpty(); + return !isEmpty; } updateData(data, initial) { diff --git a/addon/-record-data-private/system/relationships/state/relationship.js b/addon/-record-data-private/system/relationships/state/relationship.js index 00b421b8b9b..4bc4e200b47 100644 --- a/addon/-record-data-private/system/relationships/state/relationship.js +++ b/addon/-record-data-private/system/relationships/state/relationship.js @@ -280,6 +280,7 @@ export default class Relationship { } removeAllModelDatasFromOwn() { + this.setRelationshipIsStale(true); this.members.clear(); } diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index be5d94f52bc..f614eeedd96 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -1299,10 +1299,8 @@ Store = Service.extend({ ); } - let preferLocalCache = - hasAnyRelationshipData && - // allInverseRecordsAreLoaded && - !relationshipIsEmpty; + let preferLocalCache = hasAnyRelationshipData && !relationshipIsEmpty; + let hasLocalPartialData = hasDematerializedInverse || (relationshipIsEmpty && Array.isArray(resource.data) && resource.data.length > 0); diff --git a/tests/integration/relationships/one-to-many-test.js b/tests/integration/relationships/one-to-many-test.js index fb32bb94ac8..fd82252b2f8 100644 --- a/tests/integration/relationships/one-to-many-test.js +++ b/tests/integration/relationships/one-to-many-test.js @@ -437,7 +437,7 @@ test('Fetching a belongsTo that is not defined does not remove the record from a }); test("Fetching the hasMany that doesn't contain the belongsTo, sets the belongsTo to null - async", function(assert) { - var user, message, message2; + let user, message, message2; run(function() { user = store.push({ data: { From b8359c74a4ca6ecd01e0347e7da06fd902a591c0 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 17 Jul 2018 15:08:31 -0700 Subject: [PATCH 2273/2527] fix local empty state case --- .../system/relationships/state/relationship.js | 3 +++ addon/-record-data-private/system/store.js | 11 +++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/addon/-record-data-private/system/relationships/state/relationship.js b/addon/-record-data-private/system/relationships/state/relationship.js index 4bc4e200b47..46391cf3ac0 100644 --- a/addon/-record-data-private/system/relationships/state/relationship.js +++ b/addon/-record-data-private/system/relationships/state/relationship.js @@ -212,6 +212,9 @@ export default class Relationship { if (!this.inverseKey) { return; } + // TODO @runspired fairly sure we need to become stale here + // this.setRelationshipIsStale(true); + // we actually want a union of members and canonicalMembers // they should be disjoint but currently are not due to a bug this.forAllMembers(inverseModelData => { diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index f614eeedd96..7b47948cba7 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -1405,16 +1405,23 @@ Store = Service.extend({ let preferLocalCache = hasAnyRelationshipData && allInverseRecordsAreLoaded && !relationshipIsEmpty; let hasLocalPartialData = hasDematerializedInverse || (relationshipIsEmpty && resource.data); + // null is explicit empty, undefined is "we don't know anything" + let localDataIsEmpty = resource.data === undefined || resource.data === null; // fetch using data, pulling from local cache if possible if (!relationshipIsStale && (preferLocalCache || hasLocalPartialData)) { + /* + We have canonical data, but our local state is empty + */ + if (localDataIsEmpty) { + return RSVP.resolve(null); + } + let internalModel = this._internalModelForResource(resource.data); return this._findByInternalModel(internalModel); } - // null is explicit empty, undefined is "we don't know anything" - let localDataIsEmpty = resource.data === undefined || resource.data === null; let resourceIsLocal = !localDataIsEmpty && resource.data.id === null; if (resourceIsLocal) { From 0fc75c42dac971d3e82fe5c8affc8f14da0abf87 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 17 Jul 2018 15:11:24 -0700 Subject: [PATCH 2274/2527] fix dematerialization ordering --- .../system/model/internal-model.js | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/addon/-record-data-private/system/model/internal-model.js b/addon/-record-data-private/system/model/internal-model.js index e33265ffbd1..803cb4b5668 100644 --- a/addon/-record-data-private/system/model/internal-model.js +++ b/addon/-record-data-private/system/model/internal-model.js @@ -315,24 +315,24 @@ export default class InternalModel { this._doNotDestroy = false; if (this._record) { - Object.keys(this._relationshipPromisesCache).forEach(key => { - // TODO Igor cleanup the guard - // TODO there is probably relationship cleanup to do outside of the _record check - if (this._relationshipPromisesCache[key].destroy) { - this._relationshipPromisesCache[key].destroy(); - } - delete this._relationshipPromisesCache[key]; - }); - Object.keys(this._manyArrayCache).forEach(key => { - this._retainedManyArrayCache[key] = this._manyArrayCache[key]; - delete this._manyArrayCache[key]; - }); this._record.destroy(); } + Object.keys(this._relationshipPromisesCache).forEach(key => { + // TODO Igor cleanup the guard + if (this._relationshipPromisesCache[key].destroy) { + this._relationshipPromisesCache[key].destroy(); + } + delete this._relationshipPromisesCache[key]; + }); + Object.keys(this._manyArrayCache).forEach(key => { + this._retainedManyArrayCache[key] = this._manyArrayCache[key]; + delete this._manyArrayCache[key]; + }); + // move to an empty never-loaded state - this.resetRecord(); this._modelData.unloadRecord(); + this.resetRecord(); this.updateRecordArrays(); } From a28b9cbcb93ad0683567bd1867d8faeb00228103 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 17 Jul 2018 15:15:52 -0700 Subject: [PATCH 2275/2527] cleanup flag for hasMany --- .../system/model/internal-model.js | 10 ++----- .../system/relationships/state/has-many.js | 29 +++++++++++++------ .../relationships/state/relationship.js | 7 +---- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/addon/-record-data-private/system/model/internal-model.js b/addon/-record-data-private/system/model/internal-model.js index 803cb4b5668..6e4dbb76ce3 100644 --- a/addon/-record-data-private/system/model/internal-model.js +++ b/addon/-record-data-private/system/model/internal-model.js @@ -120,6 +120,9 @@ export default class InternalModel { this._recordReference = null; this._manyArrayCache = Object.create(null); + // The previous ManyArrays for this relationship which will be destroyed when + // we create a new ManyArray, but in the interim the retained version will be + // updated if inverse internal models are unloaded. this._retainedManyArrayCache = Object.create(null); this._relationshipPromisesCache = Object.create(null); } @@ -412,13 +415,6 @@ export default class InternalModel { this.send('unloadRecord'); this.dematerializeRecord(); if (this._scheduledDestroy === null) { - // TODO: use run.schedule once we drop 1.13 - if (!run.currentRunLoop) { - assert( - "You have turned on testing mode, which disabled the run-loop's autorun.\n You will need to wrap any code with asynchronous side-effects in a run", - Ember.testing - ); - } this._scheduledDestroy = run.backburner.schedule( 'destroy', this, diff --git a/addon/-record-data-private/system/relationships/state/has-many.js b/addon/-record-data-private/system/relationships/state/has-many.js index 8af92a99f13..33c5833a56c 100755 --- a/addon/-record-data-private/system/relationships/state/has-many.js +++ b/addon/-record-data-private/system/relationships/state/has-many.js @@ -242,17 +242,28 @@ export default class ManyRelationship extends Relationship { } } - localStateIsEmpty() { - let modelDatas = this.canonicalState; - let isLoaded = false; - - if (modelDatas.length) { - isLoaded = modelDatas.reduce((hasNoEmptyModel, i) => { - return hasNoEmptyModel && !i.isEmpty(); - }, true); + /** + * Flag indicating whether all inverse records are available + * + * true if inverse records exist and are all loaded (all not empty) + * true if there are no inverse records + * false if the inverse records exist and any are not loaded (any empty) + * + * @returns {boolean} + */ + get allInverseRecordsAreLoaded() { + // check currentState for unloaded records + let hasEmptyRecords = this.currentState.reduce((hasEmptyModel, i) => { + return hasEmptyModel || i.isEmpty(); + }, false); + // check un-synced state for unloaded records + if (!hasEmptyRecords && this.willSync) { + hasEmptyRecords = this.canonicalState.reduce((hasEmptyModel, i) => { + return hasEmptyModel || !i.isEmpty(); + }, false); } - return !isLoaded; + return !hasEmptyRecords; } } diff --git a/addon/-record-data-private/system/relationships/state/relationship.js b/addon/-record-data-private/system/relationships/state/relationship.js index 46391cf3ac0..2bac32ffc91 100644 --- a/addon/-record-data-private/system/relationships/state/relationship.js +++ b/addon/-record-data-private/system/relationships/state/relationship.js @@ -149,7 +149,7 @@ export default class Relationship { this.relationshipIsEmpty = true; /* - Flag def here for reference, defined as getter below + Flag def here for reference, defined as getter in has-many.js / belongs-to.js true when => hasAnyRelationshipData is true @@ -158,7 +158,6 @@ export default class Relationship { TODO, consider changing the conditional here from !isEmpty to !hiddenFromRecordArrays */ - // this.allInverseRecordsAreLoaded = false; // TODO do we want this anymore? Seems somewhat useful // especially if we rename to `hasUpdatedLink` @@ -167,10 +166,6 @@ export default class Relationship { // this.updatedLink = false; } - get allInverseRecordsAreLoaded() { - return !this.localStateIsEmpty(); - } - _inverseIsAsync() { return this.inverseIsAsync; } From 438fab763bfc39705ab76015187db93bc4c848ee Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 17 Jul 2018 15:18:05 -0700 Subject: [PATCH 2276/2527] fix method name --- addon/-record-data-private/system/model/internal-model.js | 4 ++-- .../system/relationships/state/belongs-to.js | 2 +- .../system/relationships/state/has-many.js | 2 +- .../system/store/model-data-wrapper.js | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/addon/-record-data-private/system/model/internal-model.js b/addon/-record-data-private/system/model/internal-model.js index 6e4dbb76ce3..479460f8b5d 100644 --- a/addon/-record-data-private/system/model/internal-model.js +++ b/addon/-record-data-private/system/model/internal-model.js @@ -827,7 +827,7 @@ export default class InternalModel { } } - notifyHasManyChange(key, record, idx) { + notifyHasManyChanged(key, record, idx) { if (this.hasRecord) { let manyArray = this._manyArrayCache[key]; if (manyArray) { @@ -849,7 +849,7 @@ export default class InternalModel { } } - notifyBelongsToChange(key, record) { + notifyBelongsToChanged(key, record) { if (this.hasRecord) { this._record.notifyBelongsToChanged(key, record); this.updateRecordArrays(); diff --git a/addon/-record-data-private/system/relationships/state/belongs-to.js b/addon/-record-data-private/system/relationships/state/belongs-to.js index ccd008f15b3..4be66c436ed 100644 --- a/addon/-record-data-private/system/relationships/state/belongs-to.js +++ b/addon/-record-data-private/system/relationships/state/belongs-to.js @@ -144,7 +144,7 @@ export default class BelongsToRelationship extends Relationship { notifyBelongsToChanged() { let modelData = this.modelData; let storeWrapper = this.modelData.storeWrapper; - storeWrapper.notifyBelongsToChange( + storeWrapper.notifyBelongsToChanged( modelData.modelName, modelData.id, modelData.clientId, diff --git a/addon/-record-data-private/system/relationships/state/has-many.js b/addon/-record-data-private/system/relationships/state/has-many.js index 33c5833a56c..bb27ca6e920 100755 --- a/addon/-record-data-private/system/relationships/state/has-many.js +++ b/addon/-record-data-private/system/relationships/state/has-many.js @@ -196,7 +196,7 @@ export default class ManyRelationship extends Relationship { notifyHasManyChanged() { let modelData = this.modelData; let storeWrapper = this.modelData.storeWrapper; - storeWrapper.notifyHasManyChange( + storeWrapper.notifyHasManyChanged( modelData.modelName, modelData.id, modelData.clientId, diff --git a/addon/-record-data-private/system/store/model-data-wrapper.js b/addon/-record-data-private/system/store/model-data-wrapper.js index a92afe13bc7..66e69e3b056 100644 --- a/addon/-record-data-private/system/store/model-data-wrapper.js +++ b/addon/-record-data-private/system/store/model-data-wrapper.js @@ -37,7 +37,7 @@ export default class ModelDataWrapper { let clientId = pending[i + 2]; let key = pending[i + 3]; let internalModel = store._getInternalModelForId(modelName, id, clientId); - internalModel.notifyHasManyChange(key); + internalModel.notifyHasManyChanged(key); } } @@ -65,13 +65,13 @@ export default class ModelDataWrapper { internalModel.notifyPropertyChange(key); } - notifyHasManyChange(modelName, id, clientId, key) { + notifyHasManyChanged(modelName, id, clientId, key) { this._scheduleManyArrayUpdate(modelName, id, clientId, key); } - notifyBelongsToChange(modelName, id, clientId, key) { + notifyBelongsToChanged(modelName, id, clientId, key) { let internalModel = this.store._getInternalModelForId(modelName, id, clientId); - internalModel.notifyBelongsToChange(key); + internalModel.notifyBelongsToChanged(key); } modelDataFor(modelName, id, clientId) { From f33cec33e3fc3c8c95da999892b61d02eaaf816f Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 17 Jul 2018 15:21:38 -0700 Subject: [PATCH 2277/2527] tidy up to clarify role of notifyManyArrayIsStale --- .../system/relationships/state/has-many.js | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/addon/-record-data-private/system/relationships/state/has-many.js b/addon/-record-data-private/system/relationships/state/has-many.js index bb27ca6e920..de5a3214e70 100755 --- a/addon/-record-data-private/system/relationships/state/has-many.js +++ b/addon/-record-data-private/system/relationships/state/has-many.js @@ -41,17 +41,6 @@ export default class ManyRelationship extends Relationship { } } - notifyManyArrayIsStale() { - let storeWrapper = this.modelData.storeWrapper; - let modelData = this.modelData; - storeWrapper.notifyPropertyChange( - modelData.modelName, - modelData.id, - modelData.clientId, - this.key - ); - } - addModelData(modelData, idx) { if (this.members.has(modelData)) { return; @@ -193,9 +182,27 @@ export default class ManyRelationship extends Relationship { this.canonicalState = this.canonicalMembers.toArray(); } + /* + This is essentially a "sync" version of + notifyHasManyChanged. We should work to unify + these worlds + + - @runspired + */ + notifyManyArrayIsStale() { + let modelData = this.modelData; + let storeWrapper = modelData.storeWrapper; + storeWrapper.notifyPropertyChange( + modelData.modelName, + modelData.id, + modelData.clientId, + this.key + ); + } + notifyHasManyChanged() { let modelData = this.modelData; - let storeWrapper = this.modelData.storeWrapper; + let storeWrapper = modelData.storeWrapper; storeWrapper.notifyHasManyChanged( modelData.modelName, modelData.id, From f8e6de44f21adf5666979aa1b78599b28168b94c Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 17 Jul 2018 15:35:00 -0700 Subject: [PATCH 2278/2527] fix clearing of retained many array --- .../system/model/internal-model.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/addon/-record-data-private/system/model/internal-model.js b/addon/-record-data-private/system/model/internal-model.js index 479460f8b5d..e29330a4f2a 100644 --- a/addon/-record-data-private/system/model/internal-model.js +++ b/addon/-record-data-private/system/model/internal-model.js @@ -328,9 +328,20 @@ export default class InternalModel { } delete this._relationshipPromisesCache[key]; }); + // if the manyArray is for a sync relationship + // we should clear it Object.keys(this._manyArrayCache).forEach(key => { - this._retainedManyArrayCache[key] = this._manyArrayCache[key]; + let manyArray = (this._retainedManyArrayCache[key] = this._manyArrayCache[key]); delete this._manyArrayCache[key]; + + /* + It is likely in this case instead of retaining we should destroy + + - @runspired + */ + if (manyArray && !manyArray._inverseIsAsync) { + manyArray.clear(); + } }); // move to an empty never-loaded state @@ -539,6 +550,7 @@ export default class InternalModel { key, isPolymorphic: relationshipMeta.options.polymorphic, initialState: initialState.slice(), + _inverseIsAsync: jsonApi._relationship._inverseIsAsync(), internalModel: this, }); this._manyArrayCache[key] = manyArray; From 3efc0a73909dbd5301ba4fad2250c21c5baec951 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 18 Jul 2018 09:42:43 -0700 Subject: [PATCH 2279/2527] move back within guard --- .../system/model/internal-model.js | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/addon/-record-data-private/system/model/internal-model.js b/addon/-record-data-private/system/model/internal-model.js index e29330a4f2a..0067b7333c1 100644 --- a/addon/-record-data-private/system/model/internal-model.js +++ b/addon/-record-data-private/system/model/internal-model.js @@ -319,30 +319,30 @@ export default class InternalModel { if (this._record) { this._record.destroy(); - } - Object.keys(this._relationshipPromisesCache).forEach(key => { - // TODO Igor cleanup the guard - if (this._relationshipPromisesCache[key].destroy) { - this._relationshipPromisesCache[key].destroy(); - } - delete this._relationshipPromisesCache[key]; - }); - // if the manyArray is for a sync relationship - // we should clear it - Object.keys(this._manyArrayCache).forEach(key => { - let manyArray = (this._retainedManyArrayCache[key] = this._manyArrayCache[key]); - delete this._manyArrayCache[key]; - - /* - It is likely in this case instead of retaining we should destroy - - - @runspired - */ - if (manyArray && !manyArray._inverseIsAsync) { - manyArray.clear(); - } - }); + Object.keys(this._relationshipPromisesCache).forEach(key => { + // TODO Igor cleanup the guard + if (this._relationshipPromisesCache[key].destroy) { + this._relationshipPromisesCache[key].destroy(); + } + delete this._relationshipPromisesCache[key]; + }); + Object.keys(this._manyArrayCache).forEach(key => { + let manyArray = (this._retainedManyArrayCache[key] = this._manyArrayCache[key]); + delete this._manyArrayCache[key]; + + if (manyArray && !manyArray._inverseIsAsync) { + /* + If the manyArray is for a sync relationship, we should clear it + to preserve the semantics of client-side delete. + + It is likely in this case instead of retaining we should destroy + - @runspired + */ + manyArray.clear(); + } + }); + } // move to an empty never-loaded state this._modelData.unloadRecord(); From 09c319b753f14f7e001cdcca7057473b73befe02 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 18 Jul 2018 18:20:27 -0700 Subject: [PATCH 2280/2527] add test and rename methods to keep public api stable --- addon/-legacy-private/system/many-array.js | 2 +- .../system/model/internal-model.js | 4 +- addon/-legacy-private/system/model/model.js | 2 +- .../system/relationships/state/belongs-to.js | 25 +- .../system/relationships/state/has-many.js | 4 +- .../system/model/internal-model.js | 6 +- .../system/model/model.js | 2 +- .../system/relationships/state/belongs-to.js | 25 +- .../system/relationships/state/has-many.js | 14 +- .../relationships/state/relationship.js | 29 +- .../system/store/model-data-wrapper.js | 8 +- .../relationships/one-to-one-test.js | 258 +++++++++++------- 12 files changed, 222 insertions(+), 157 deletions(-) diff --git a/addon/-legacy-private/system/many-array.js b/addon/-legacy-private/system/many-array.js index fe9a9c2a5ae..f5c1ac297fa 100644 --- a/addon/-legacy-private/system/many-array.js +++ b/addon/-legacy-private/system/many-array.js @@ -166,7 +166,7 @@ export default EmberObject.extend(MutableArray, Evented, { if (isInitialized && diff.addedCount > 0) { //notify only on additions //TODO only notify if unloaded - this.relationship.notifyHasManyChanged(); + this.relationship.notifyHasManyChange(); } } }, diff --git a/addon/-legacy-private/system/model/internal-model.js b/addon/-legacy-private/system/model/internal-model.js index f00bbb0d3b2..b162c058317 100644 --- a/addon/-legacy-private/system/model/internal-model.js +++ b/addon/-legacy-private/system/model/internal-model.js @@ -883,9 +883,9 @@ export default class InternalModel { } } - notifyBelongsToChanged(key, record) { + notifyBelongsToChange(key, record) { if (this.hasRecord) { - this._record.notifyBelongsToChanged(key, record); + this._record.notifyBelongsToChange(key, record); } } diff --git a/addon/-legacy-private/system/model/model.js b/addon/-legacy-private/system/model/model.js index 2c1c45e0f1a..b6218147c56 100644 --- a/addon/-legacy-private/system/model/model.js +++ b/addon/-legacy-private/system/model/model.js @@ -1063,7 +1063,7 @@ const Model = EmberObject.extend(Evented, { }; }, - notifyBelongsToChanged(key) { + notifyBelongsToChange(key) { this.notifyPropertyChange(key); }, /** diff --git a/addon/-legacy-private/system/relationships/state/belongs-to.js b/addon/-legacy-private/system/relationships/state/belongs-to.js index 7e924bdfa5a..78733dbe78c 100644 --- a/addon/-legacy-private/system/relationships/state/belongs-to.js +++ b/addon/-legacy-private/system/relationships/state/belongs-to.js @@ -79,7 +79,7 @@ export default class BelongsToRelationship extends Relationship { inverseDidDematerialize() { super.inverseDidDematerialize(this.inverseInternalModel); - this.notifyBelongsToChanged(); + this.notifyBelongsToChange(); } removeCompletelyFromOwn(internalModel) { @@ -91,7 +91,7 @@ export default class BelongsToRelationship extends Relationship { if (this.inverseInternalModel === internalModel) { this.inverseInternalModel = null; - this.notifyBelongsToChanged(); + this.notifyBelongsToChange(); } } @@ -110,7 +110,7 @@ export default class BelongsToRelationship extends Relationship { if (this.inverseInternalModel !== this.canonicalState) { this.inverseInternalModel = this.canonicalState; this._promiseProxy = null; - this.notifyBelongsToChanged(); + this.notifyBelongsToChange(); } super.flushCanonical(); @@ -129,7 +129,7 @@ export default class BelongsToRelationship extends Relationship { this.inverseInternalModel = internalModel; super.addInternalModel(internalModel); - this.notifyBelongsToChanged(); + this.notifyBelongsToChange(); } setRecordPromise(belongsToPromise) { @@ -152,18 +152,18 @@ export default class BelongsToRelationship extends Relationship { this.inverseInternalModel = null; this._promiseProxy = null; super.removeInternalModelFromOwn(internalModel); - this.notifyBelongsToChanged(); + this.notifyBelongsToChange(); } removeAllInternalModelsFromOwn() { super.removeAllInternalModelsFromOwn(); this.inverseInternalModel = null; this._promiseProxy = null; - this.notifyBelongsToChanged(); + this.notifyBelongsToChange(); } - notifyBelongsToChanged() { - this.internalModel.notifyBelongsToChanged(this.key); + notifyBelongsToChange() { + this.internalModel.notifyBelongsToChange(this.key); } removeCanonicalInternalModelFromOwn(internalModel) { @@ -171,15 +171,6 @@ export default class BelongsToRelationship extends Relationship { return; } this.canonicalState = null; - /* - This isn't exactly correct because another record's payload - may tell us that this relationship is no longer correct - but that is not enough to tell us that this relationship is - now empty for sure. Likely we should be stale here but - that is probably a breaking change. - - - @runspired - */ this.setHasAnyRelationshipData(true); this.setRelationshipIsEmpty(true); super.removeCanonicalInternalModelFromOwn(internalModel); diff --git a/addon/-legacy-private/system/relationships/state/has-many.js b/addon/-legacy-private/system/relationships/state/has-many.js index 12d08be0afa..339cdc9ebce 100755 --- a/addon/-legacy-private/system/relationships/state/has-many.js +++ b/addon/-legacy-private/system/relationships/state/has-many.js @@ -129,7 +129,7 @@ export default class ManyRelationship extends Relationship { } this._removeInternalModelFromManyArray(this._retainedManyArray, inverseInternalModel); } - this.notifyHasManyChanged(); + this.notifyHasManyChange(); } addInternalModel(internalModel, idx) { @@ -385,7 +385,7 @@ export default class ManyRelationship extends Relationship { } } - notifyHasManyChanged() { + notifyHasManyChange() { this.internalModel.notifyHasManyAdded(this.key); } diff --git a/addon/-record-data-private/system/model/internal-model.js b/addon/-record-data-private/system/model/internal-model.js index 0067b7333c1..38ace8ec672 100644 --- a/addon/-record-data-private/system/model/internal-model.js +++ b/addon/-record-data-private/system/model/internal-model.js @@ -839,7 +839,7 @@ export default class InternalModel { } } - notifyHasManyChanged(key, record, idx) { + notifyHasManyChange(key, record, idx) { if (this.hasRecord) { let manyArray = this._manyArrayCache[key]; if (manyArray) { @@ -861,9 +861,9 @@ export default class InternalModel { } } - notifyBelongsToChanged(key, record) { + notifyBelongsToChange(key, record) { if (this.hasRecord) { - this._record.notifyBelongsToChanged(key, record); + this._record.notifyBelongsToChange(key, record); this.updateRecordArrays(); } } diff --git a/addon/-record-data-private/system/model/model.js b/addon/-record-data-private/system/model/model.js index 772b6efa7ff..d73851bc31a 100644 --- a/addon/-record-data-private/system/model/model.js +++ b/addon/-record-data-private/system/model/model.js @@ -1064,7 +1064,7 @@ const Model = EmberObject.extend(Evented, { }; }, - notifyBelongsToChanged(key) { + notifyBelongsToChange(key) { this.notifyPropertyChange(key); }, /** diff --git a/addon/-record-data-private/system/relationships/state/belongs-to.js b/addon/-record-data-private/system/relationships/state/belongs-to.js index 4be66c436ed..e11cda74aae 100644 --- a/addon/-record-data-private/system/relationships/state/belongs-to.js +++ b/addon/-record-data-private/system/relationships/state/belongs-to.js @@ -63,7 +63,7 @@ export default class BelongsToRelationship extends Relationship { inverseDidDematerialize() { super.inverseDidDematerialize(this.inverseModelData); - this.notifyBelongsToChanged(); + this.notifyBelongsToChange(); } removeCompletelyFromOwn(modelData) { @@ -75,7 +75,7 @@ export default class BelongsToRelationship extends Relationship { if (this.inverseModelData === modelData) { this.inverseModelData = null; - this.notifyBelongsToChanged(); + this.notifyBelongsToChange(); } } @@ -94,7 +94,7 @@ export default class BelongsToRelationship extends Relationship { } if (this.inverseModelData !== this.canonicalState) { this.inverseModelData = this.canonicalState; - this.notifyBelongsToChanged(); + this.notifyBelongsToChange(); } super.flushCanonical(); } @@ -113,7 +113,7 @@ export default class BelongsToRelationship extends Relationship { this.inverseModelData = modelData; super.addModelData(modelData); - this.notifyBelongsToChanged(); + this.notifyBelongsToChange(); } setRecordPromise(newPromise) { @@ -132,19 +132,19 @@ export default class BelongsToRelationship extends Relationship { } this.inverseModelData = null; super.removeModelDataFromOwn(modelData); - this.notifyBelongsToChanged(); + this.notifyBelongsToChange(); } removeAllModelDatasFromOwn() { super.removeAllModelDatasFromOwn(); this.inverseModelData = null; - this.notifyBelongsToChanged(); + this.notifyBelongsToChange(); } - notifyBelongsToChanged() { + notifyBelongsToChange() { let modelData = this.modelData; let storeWrapper = this.modelData.storeWrapper; - storeWrapper.notifyBelongsToChanged( + storeWrapper.notifyBelongsToChange( modelData.modelName, modelData.id, modelData.clientId, @@ -157,15 +157,6 @@ export default class BelongsToRelationship extends Relationship { return; } this.canonicalState = null; - /* - This isn't exactly correct because another record's payload - may tell us that this relationship is no longer correct - but that is not enough to tell us that this relationship is - now empty for sure. Likely we should be stale here but - that is probably a breaking change. - - - @runspired - */ this.setHasAnyRelationshipData(true); this.setRelationshipIsEmpty(true); super.removeCanonicalModelDataFromOwn(modelData); diff --git a/addon/-record-data-private/system/relationships/state/has-many.js b/addon/-record-data-private/system/relationships/state/has-many.js index de5a3214e70..dea44b7f7e8 100755 --- a/addon/-record-data-private/system/relationships/state/has-many.js +++ b/addon/-record-data-private/system/relationships/state/has-many.js @@ -56,7 +56,7 @@ export default class ManyRelationship extends Relationship { // TODO Igor consider making direct to remove the indirection // We are not lazily accessing the manyArray here because the change is coming from app side // this.manyArray.flushCanonical(this.currentState); - this.notifyHasManyChanged(); + this.notifyHasManyChange(); } removeCanonicalModelDataFromOwn(modelData, idx) { @@ -118,7 +118,7 @@ export default class ManyRelationship extends Relationship { this.currentState = toSet; super.flushCanonical(); // Once we clean up all the flushing, we will be left with at least the notifying part - this.notifyHasManyChanged(); + this.notifyHasManyChange(); } //TODO(Igor) idx not used currently, fix @@ -133,12 +133,12 @@ export default class ManyRelationship extends Relationship { this.currentState.splice(index, 1); // TODO Igor consider making direct to remove the indirection // We are not lazily accessing the manyArray here because the change is coming from app side - this.notifyHasManyChanged(); + this.notifyHasManyChange(); // this.manyArray.flushCanonical(this.currentState); } notifyRecordRelationshipAdded() { - this.notifyHasManyChanged(); + this.notifyHasManyChange(); } computeChanges(modelDatas = []) { @@ -184,7 +184,7 @@ export default class ManyRelationship extends Relationship { /* This is essentially a "sync" version of - notifyHasManyChanged. We should work to unify + notifyHasManyChange. We should work to unify these worlds - @runspired @@ -200,10 +200,10 @@ export default class ManyRelationship extends Relationship { ); } - notifyHasManyChanged() { + notifyHasManyChange() { let modelData = this.modelData; let storeWrapper = modelData.storeWrapper; - storeWrapper.notifyHasManyChanged( + storeWrapper.notifyHasManyChange( modelData.modelName, modelData.id, modelData.clientId, diff --git a/addon/-record-data-private/system/relationships/state/relationship.js b/addon/-record-data-private/system/relationships/state/relationship.js index 2bac32ffc91..fe4f5a933b6 100644 --- a/addon/-record-data-private/system/relationships/state/relationship.js +++ b/addon/-record-data-private/system/relationships/state/relationship.js @@ -72,19 +72,40 @@ export default class Relationship { this.meta = null; this.__inverseMeta = undefined; + /* + This flag forces fetch. `true` for a single request once `reload()` + has been called `false` at all other times. + */ + this.shouldForceReload = false; + /* This flag indicates whether we should re-fetch the relationship the next time it is accessed. + The difference between this flag and `shouldForceReload` + is in how we treat the presence of partially missing data: + - for a forced reload, we will reload the link or EVERY record + - for a stale reload, we will reload the link (if present) else only MISSING records + + Ideally these flags could be merged, but because we don't give the + request layer the option of deciding how to resolve the data being queried + we are forced to differentiate for now. + + It is also possible for a relationship to remain stale after a forced reload; however, + in this case `hasFailedLoadAttempt` ought to be `true`. + false when - => initial setup + => modelData.isNew() on initial setup => a previously triggered request has resolved => we get relationship data via push true when - => relationship.reload() has been called + => !modelData.isNew() on initial setup + => an inverse has been unloaded => we get a new link for the relationship + + TODO @runspired unskip the acceptance tests and fix these flags */ this.relationshipIsStale = false; @@ -166,6 +187,10 @@ export default class Relationship { // this.updatedLink = false; } + get isNew() { + return this.modelData.isNew(); + } + _inverseIsAsync() { return this.inverseIsAsync; } diff --git a/addon/-record-data-private/system/store/model-data-wrapper.js b/addon/-record-data-private/system/store/model-data-wrapper.js index 66e69e3b056..a92afe13bc7 100644 --- a/addon/-record-data-private/system/store/model-data-wrapper.js +++ b/addon/-record-data-private/system/store/model-data-wrapper.js @@ -37,7 +37,7 @@ export default class ModelDataWrapper { let clientId = pending[i + 2]; let key = pending[i + 3]; let internalModel = store._getInternalModelForId(modelName, id, clientId); - internalModel.notifyHasManyChanged(key); + internalModel.notifyHasManyChange(key); } } @@ -65,13 +65,13 @@ export default class ModelDataWrapper { internalModel.notifyPropertyChange(key); } - notifyHasManyChanged(modelName, id, clientId, key) { + notifyHasManyChange(modelName, id, clientId, key) { this._scheduleManyArrayUpdate(modelName, id, clientId, key); } - notifyBelongsToChanged(modelName, id, clientId, key) { + notifyBelongsToChange(modelName, id, clientId, key) { let internalModel = this.store._getInternalModelForId(modelName, id, clientId); - internalModel.notifyBelongsToChanged(key); + internalModel.notifyBelongsToChange(key); } modelDataFor(modelName, id, clientId) { diff --git a/tests/integration/relationships/one-to-one-test.js b/tests/integration/relationships/one-to-one-test.js index 89d4831785e..e5eaa0bda6f 100644 --- a/tests/integration/relationships/one-to-one-test.js +++ b/tests/integration/relationships/one-to-one-test.js @@ -21,6 +21,7 @@ module('integration/relationships/one_to_one_test - OneToOne relationships', { }); Job = DS.Model.extend({ + name: attr(), isGood: attr(), user: belongsTo('user', { async: false }), }); @@ -203,137 +204,194 @@ test('Fetching a belongsTo that is set to null removes the record from a relatio assert.equal(job.get('user'), null, 'User relationship was removed correctly'); }); -test('Fetching a belongsTo that is set to a different record, sets the old relationship to null - async', function(assert) { - assert.expect(3); - var stanley, stanleysFriend; - run(function() { - stanley = store.push({ - data: { - id: 1, - type: 'user', - attributes: { - name: 'Stanley', +test('Fetching a belongsTo that is set to a different record, sets the old relationship to null - async', async function(assert) { + let user1 = store.push({ + data: { + type: 'user', + id: '1', + attributes: { name: 'Chris' }, + relationships: { + bestFriend: { + data: { type: 'user', id: '2' }, }, + }, + }, + included: [ + { + type: 'user', + id: '2', + attributes: { name: 'Igor' }, relationships: { bestFriend: { - data: { - id: 2, - type: 'user', - }, + data: { type: 'user', id: '1' }, }, }, }, - }); - stanleysFriend = store.push({ - data: { - id: 2, - type: 'user', - attributes: { - name: "Stanley's friend", + ], + }); + + let user2 = store.peekRecord('user', '2'); + let user1Friend = await user1.get('bestFriend'); + + assert.equal(user1Friend, user2, '.bestFriend is '); + + /* + Now we "reload" but with a new bestFriend. While this only gives + us new canonical information for and , it also severs + the previous canonical relationship with . We infer from this + that the new canonical state for .bestFriend is `null`. + + Users for whom this is not true should either + + - include information for user:1 in the payload severing this link + - manually reload user:1 or use the belongsToReference to reload user:1.bestFriend + */ + store.push({ + data: { + type: 'user', + id: '2', + attributes: { name: 'Igor' }, + relationships: { + bestFriend: { + data: { type: 'user', id: '3' }, }, + }, + }, + included: [ + { + type: 'user', + id: '3', + attributes: { name: 'Evan' }, relationships: { bestFriend: { - data: { - id: 1, - type: 'user', - }, + data: { type: 'user', id: '2' }, }, }, }, - }); + ], + }); - stanleysFriend.get('bestFriend').then(function(fetchedUser) { - assert.equal(fetchedUser, stanley, 'User relationship was initally setup correctly'); - var stanleysNewFriend; - run(function() { - stanleysNewFriend = store.push({ - data: { - id: 3, - type: 'user', - attributes: { - name: "Stanley's New friend", - }, - relationships: { - bestFriend: { - data: { - id: 1, - type: 'user', - }, - }, - }, - }, - }); - }); + let user3 = store.peekRecord('user', '3'); + let user1bestFriend = await user1.get('bestFriend'); + let user2bestFriend = await user2.get('bestFriend'); + let user3bestFriend = await user3.get('bestFriend'); - stanley.get('bestFriend').then(function(fetchedNewFriend) { - assert.equal( - fetchedNewFriend, - stanleysNewFriend, - 'User relationship was updated correctly' - ); - }); + assert.equal(user3bestFriend, user2, '.bestFriend is '); + assert.equal(user2bestFriend, user3, '.bestFriend is '); + assert.equal(user1bestFriend, null, '.bestFriend is null'); - stanleysFriend.get('bestFriend').then(function(fetchedOldFriend) { - assert.equal(fetchedOldFriend, null, 'The old relationship was set to null correctly'); - }); - }); - }); + let user1bestFriendState = user1.belongsTo('bestFriend').belongsToRelationship; + + assert.equal(user1bestFriendState.canonicalState, null, '.job is canonically empty'); + assert.equal(user1bestFriendState.currentState, null, '.job is locally empty'); + assert.equal(user1bestFriendState.relationshipIsEmpty, true, 'The relationship is empty'); + assert.equal(user1bestFriendState.relationshipIsStale, false, 'The relationship is not stale'); + assert.equal( + user1bestFriendState.shouldForceReload, + false, + 'The relationship does not require reload' + ); + assert.equal( + user1bestFriendState.hasAnyRelationshipData, + true, + 'The relationship considers its canonical data complete' + ); + assert.equal( + user1bestFriendState.allInverseRecordsAreLoaded, + true, + 'The relationship has all required data' + ); }); -test('Fetching a belongsTo that is set to a different record, sets the old relationship to null - sync', function(assert) { - var job, user, newBetterJob; - run(function() { - job = store.push({ - data: { - id: 2, - type: 'job', - attributes: { - isGood: false, +test('Fetching a belongsTo that is set to a different record, sets the old relationship to null - sync', async function(assert) { + let user1 = store.push({ + data: { + type: 'user', + id: '1', + attributes: { name: 'Chris' }, + relationships: { + job: { + data: { type: 'job', id: '1' }, }, }, - }); - user = store.push({ - data: { - id: 1, - type: 'user', - attributes: { - name: 'Stanley', - }, + }, + included: [ + { + type: 'job', + id: '1', + attributes: { name: 'Golf Picker Mechanic' }, relationships: { - job: { - data: { - id: 2, - type: 'job', - }, + user: { + data: { type: 'user', id: '1' }, }, }, }, - }); + ], }); - assert.equal(job.get('user'), user, 'Job and user initially setup correctly'); - run(function() { - newBetterJob = store.push({ - data: { - id: 3, - type: 'job', - attributes: { - isGood: true, + + let job1 = store.peekRecord('job', '1'); + + assert.equal(user1.get('job'), job1, '.job is '); + + /* + Now we "reload" but with a new user. While this only gives + us new canonical information for and , it also severs + the previous canonical relationship with . We infer from this + that the new canonical state for .job is `null`. + + Users for whom this is not true should either + + - include information for user:1 in the payload severing this link + - manually reload user:1 or use the belongsToReference to reload user:1.job + */ + store.push({ + data: { + type: 'job', + id: '1', + attributes: { name: 'Golf Picker Mechanic' }, + relationships: { + user: { + data: { type: 'user', id: '2' }, }, + }, + }, + included: [ + { + type: 'user', + id: '2', + attributes: { name: 'Evan' }, relationships: { - user: { - data: { - id: 1, - type: 'user', - }, + job: { + data: { type: 'job', id: '1' }, }, }, }, - }); + ], }); - assert.equal(user.get('job'), newBetterJob, 'Job updated correctly'); - assert.equal(job.get('user'), null, 'Old relationship nulled out correctly'); - assert.equal(newBetterJob.get('user'), user, 'New job setup correctly'); + let user2 = store.peekRecord('user', '2'); + + assert.equal(user2.get('job'), job1, '.job is '); + assert.equal(job1.get('user'), user2, '.user is '); + assert.equal(user1.get('job'), null, '.job is null'); + + let user1JobState = user1.belongsTo('job').belongsToRelationship; + + assert.equal(user1JobState.canonicalState, null, '.job is canonically empty'); + assert.equal(user1JobState.currentState, null, '.job is locally empty'); + assert.equal(user1JobState.relationshipIsEmpty, true, 'The relationship is empty'); + assert.equal(user1JobState.relationshipIsStale, false, 'The relationship is not stale'); + assert.equal(user1JobState.shouldForceReload, false, 'The relationship does not require reload'); + assert.equal( + user1JobState.hasAnyRelationshipData, + true, + 'The relationship considers its canonical data complete' + ); + assert.equal( + user1JobState.allInverseRecordsAreLoaded, + true, + 'The relationship has all required data' + ); }); /* From b044d59165ac9ca6575368d03e861867bdfe2abc Mon Sep 17 00:00:00 2001 From: Alex Robbin Date: Wed, 18 Jul 2018 22:01:17 -0400 Subject: [PATCH 2281/2527] [BUGFIX] normalize model name for belongs to relationships (#5477) Given these models: ```ruby const User = DS.Model.extend({ userProfile: DS.belongsTo(), streamItems: DS.hasMany() }); const UserProfile = DS.Model.extend({ user: DS.belongsTo() }); const StreamItem = DS.Model.extend({ user: DS.belongsTo() }); ``` The inferred model type of `User.streamItems` will be `stream-item` while the type of `User.userProfile` will be `userProfile`. This goes against the concept of all model types being dasherized. With this change, `User.userProfile` will be converted into `user-profile`. --- addon/-private/system/relationship-meta.js | 5 ++- tests/unit/model/relationships-test.js | 50 ++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/relationship-meta.js b/addon/-private/system/relationship-meta.js index 2951df4c616..7288d70c3b6 100644 --- a/addon/-private/system/relationship-meta.js +++ b/addon/-private/system/relationship-meta.js @@ -6,9 +6,12 @@ export function typeForRelationshipMeta(meta) { let modelName; modelName = meta.type || meta.key; + modelName = normalizeModelName(modelName); + if (meta.kind === 'hasMany') { - modelName = singularize(normalizeModelName(modelName)); + modelName = singularize(modelName); } + return modelName; } diff --git a/tests/unit/model/relationships-test.js b/tests/unit/model/relationships-test.js index 74a5a06546d..8ed63037127 100644 --- a/tests/unit/model/relationships-test.js +++ b/tests/unit/model/relationships-test.js @@ -66,3 +66,53 @@ test('eachRelatedType() iterates over relations without duplication', function(a assert.deepEqual(relations, ['occupation', 'person']); }); + +test('normalizing belongsTo relationship names', function(assert) { + const UserProfile = DS.Model.extend({ + user: DS.belongsTo(), + }); + + let User = DS.Model.extend({ + userProfile: DS.belongsTo(), + }); + + store = createStore({ + user: User, + userProfile: UserProfile, + }); + + User = store.modelFor('user'); + + const relationships = get(User, 'relationships'); + + assert.ok(relationships.has('user-profile'), 'relationship key has been normalized'); + + const relationship = relationships.get('user-profile')[0]; + + assert.equal(relationship.meta.name, 'userProfile', 'relationship name has not been changed'); +}); + +test('normalizing hasMany relationship names', function(assert) { + const StreamItem = DS.Model.extend({ + user: DS.belongsTo(), + }); + + let User = DS.Model.extend({ + streamItems: DS.hasMany(), + }); + + store = createStore({ + user: User, + streamItem: StreamItem, + }); + + User = store.modelFor('user'); + + const relationships = get(User, 'relationships'); + + assert.ok(relationships.has('stream-item'), 'relationship key has been normalized'); + + const relationship = relationships.get('stream-item')[0]; + + assert.equal(relationship.meta.name, 'streamItems', 'relationship name has not been changed'); +}); From 6580dbfd7868c08c005a127775bdb1d348bd78ee Mon Sep 17 00:00:00 2001 From: Sumeet Attree Date: Mon, 23 Jul 2018 11:37:14 +0530 Subject: [PATCH 2282/2527] [BUGFIX beta] Upgrading ember-inflector to v3.3.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 67493cb5391..fc855f51a04 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "ember-cli-string-utils": "^1.0.0", "ember-cli-test-info": "^1.0.0", "ember-cli-version-checker": "^2.1.0", - "ember-inflector": "^2.0.0", + "ember-inflector": "^3.0.0", "ember-runtime-enumerable-includes-polyfill": "^2.0.0", "git-repo-info": "^1.1.2", "heimdalljs": "^0.3.0", diff --git a/yarn.lock b/yarn.lock index 5f53f6e0be6..1b1f17c8435 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3011,11 +3011,11 @@ ember-export-application-global@^2.0.0: dependencies: ember-cli-babel "^6.0.0-beta.7" -ember-inflector@^2.0.0: - version "2.3.0" - resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-2.3.0.tgz#94797eba0eea98d902aa1e5da0f0aeef6053317f" +ember-inflector@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ember-inflector/-/ember-inflector-3.0.0.tgz#7e1ee8aaa0fa773ba0905d8b7c0786354d890ee1" dependencies: - ember-cli-babel "^6.0.0" + ember-cli-babel "^6.6.0" ember-load-initializers@^1.1.0: version "1.1.0" From 39c8238d2b123c0921d013fe0f5f8d3577bed0f2 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 23 Jul 2018 11:21:00 -1000 Subject: [PATCH 2283/2527] [BUGFIX] fix and tests for belongs-to proxy not properly updating (#5533) * adds failing tests for #5511 and #5517 * add a test for #5525 that suspiciously passes * adds test for #5522 isEmpty issue * run prettier * fix issue with proxy * upgrade test for potential issue with create, still passes * fix emberobserver issue for missing data member in payloads --- addon/-legacy-private/system/model/states.js | 1 + .../system/relationships/state/belongs-to.js | 17 +- .../relationships/state/relationship.js | 8 +- addon/-legacy-private/system/store.js | 2 +- .../system/model/model-data.js | 2 +- .../system/model/states.js | 1 + .../relationships/state/relationship.js | 8 +- addon/-record-data-private/system/store.js | 5 +- .../integration/records/create-record-test.js | 84 +++++ tests/integration/records/edit-record-test.js | 344 ++++++++++++++++++ tests/integration/records/load-test.js | 205 +++++++++-- .../relationships/json-api-links-test.js | 90 +++++ tests/unit/store/push-test.js | 2 +- 13 files changed, 734 insertions(+), 35 deletions(-) create mode 100644 tests/integration/records/edit-record-test.js diff --git a/addon/-legacy-private/system/model/states.js b/addon/-legacy-private/system/model/states.js index 7697a1f1fd9..33aefc63e1b 100644 --- a/addon/-legacy-private/system/model/states.js +++ b/addon/-legacy-private/system/model/states.js @@ -521,6 +521,7 @@ const RootState = { loading: { // FLAGS isLoading: true, + isEmpty: true, exit(internalModel) { internalModel._promiseProxy = null; diff --git a/addon/-legacy-private/system/relationships/state/belongs-to.js b/addon/-legacy-private/system/relationships/state/belongs-to.js index 78733dbe78c..ddd07937733 100644 --- a/addon/-legacy-private/system/relationships/state/belongs-to.js +++ b/addon/-legacy-private/system/relationships/state/belongs-to.js @@ -34,6 +34,7 @@ export default class BelongsToRelationship extends Relationship { } else if (this.inverseInternalModel) { this.removeInternalModel(this.inverseInternalModel); } + this.setHasAnyRelationshipData(true); this.setRelationshipIsStale(false); this.setRelationshipIsEmpty(false); @@ -163,6 +164,12 @@ export default class BelongsToRelationship extends Relationship { } notifyBelongsToChange() { + if (this._promiseProxy !== null) { + let iM = this.inverseInternalModel; + + this._updateLoadingPromise(proxyRecord(iM), iM ? iM.getRecord() : null); + } + this.internalModel.notifyBelongsToChange(this.key); } @@ -242,9 +249,7 @@ export default class BelongsToRelationship extends Relationship { if (this.isAsync) { if (this._promiseProxy === null) { - let promise = resolve(this.inverseInternalModel).then(internalModel => { - return internalModel ? internalModel.getRecord() : null; - }); + let promise = proxyRecord(this.inverseInternalModel); this._updateLoadingPromise(promise, record); } @@ -282,6 +287,12 @@ export default class BelongsToRelationship extends Relationship { } } +function proxyRecord(internalModel) { + return resolve(internalModel).then(resolvedInternalModel => { + return resolvedInternalModel ? resolvedInternalModel.getRecord() : null; + }); +} + function handleCompletedFind(relationship, error) { let internalModel = relationship.inverseInternalModel; diff --git a/addon/-legacy-private/system/relationships/state/relationship.js b/addon/-legacy-private/system/relationships/state/relationship.js index 9f48256ee16..e53e2f1c76c 100644 --- a/addon/-legacy-private/system/relationships/state/relationship.js +++ b/addon/-legacy-private/system/relationships/state/relationship.js @@ -60,6 +60,7 @@ export default class Relationship { this.canonicalMembers = new OrderedSet(); this.store = store; this.key = relationshipMeta.key; + this.kind = relationshipMeta.kind; this.inverseKey = inverseKey; this.internalModel = internalModel; this.isAsync = typeof async === 'undefined' ? true : async; @@ -526,7 +527,7 @@ export default class Relationship { warn( `You pushed a record of type '${this.internalModel.modelName}' with a relationship '${ this.key - }' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, + }' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload. EmberData will treat this relationship as known-to-be-empty.`, this.isAsync || this.hasAnyRelationshipData, { id: 'ds.store.push-link-for-sync-relationship', @@ -696,6 +697,11 @@ export default class Relationship { this.updateData(payload.data, initial); } else if (payload._partialData !== undefined) { this.updateData(payload._partialData, initial); + } else if (this.isAsync === false) { + hasRelationshipDataProperty = true; + let data = this.kind === 'hasMany' ? [] : null; + + this.updateData(data, initial); } if (payload.links && payload.links.related) { diff --git a/addon/-legacy-private/system/store.js b/addon/-legacy-private/system/store.js index e9612191bdd..793ed7d4712 100644 --- a/addon/-legacy-private/system/store.js +++ b/addon/-legacy-private/system/store.js @@ -3162,7 +3162,7 @@ function setupRelationships(store, internalModel, data, modelNameToInverseMap) { warn( `You pushed a record of type '${ internalModel.modelName - }' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, + }' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload. EmberData will treat this relationship as known-to-be-empty.`, isAsync || relationshipData.data, { id: 'ds.store.push-link-for-sync-relationship', diff --git a/addon/-record-data-private/system/model/model-data.js b/addon/-record-data-private/system/model/model-data.js index 4b8aafe0d21..6c6e0262a71 100644 --- a/addon/-record-data-private/system/model/model-data.js +++ b/addon/-record-data-private/system/model/model-data.js @@ -106,7 +106,7 @@ export default class ModelData { warn( `You pushed a record of type '${ this.modelName - }' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, + }' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload. EmberData will treat this relationship as known-to-be-empty.`, isAsync || relationshipData.data, { id: 'ds.store.push-link-for-sync-relationship', diff --git a/addon/-record-data-private/system/model/states.js b/addon/-record-data-private/system/model/states.js index 98cf914167e..035da6d7b47 100644 --- a/addon/-record-data-private/system/model/states.js +++ b/addon/-record-data-private/system/model/states.js @@ -518,6 +518,7 @@ const RootState = { // XHR to retrieve the data. loading: { // FLAGS + isEmpty: true, isLoading: true, exit(internalModel) { diff --git a/addon/-record-data-private/system/relationships/state/relationship.js b/addon/-record-data-private/system/relationships/state/relationship.js index fe4f5a933b6..5122d633e31 100644 --- a/addon/-record-data-private/system/relationships/state/relationship.js +++ b/addon/-record-data-private/system/relationships/state/relationship.js @@ -55,6 +55,7 @@ export default class Relationship { constructor(store, inverseKey, relationshipMeta, modelData, inverseIsAsync) { heimdall.increment(newRelationship); this.inverseIsAsync = inverseIsAsync; + this.kind = relationshipMeta.kind; let async = relationshipMeta.options.async; let polymorphic = relationshipMeta.options.polymorphic; this.modelData = modelData; @@ -572,7 +573,7 @@ export default class Relationship { warn( `You pushed a record of type '${this.modelData.modelName}' with a relationship '${ this.key - }' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, + }' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload. EmberData will treat this relationship as known-to-be-empty.`, this.isAsync || this.hasAnyRelationshipData, { id: 'ds.store.push-link-for-sync-relationship', @@ -647,6 +648,11 @@ export default class Relationship { if (payload.data !== undefined) { hasRelationshipDataProperty = true; this.updateData(payload.data, initial); + } else if (this.isAsync === false) { + hasRelationshipDataProperty = true; + let data = this.kind === 'hasMany' ? [] : null; + + this.updateData(data, initial); } if (payload.links && payload.links.related) { diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index 7b47948cba7..2ffecb36026 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -4,7 +4,7 @@ import { A } from '@ember/array'; import EmberError from '@ember/error'; import MapWithDefault from './map-with-default'; -import { run as emberRun } from '@ember/runloop'; +import { run as emberRunLoop } from '@ember/runloop'; import { set, get, computed } from '@ember/object'; import { assign } from '@ember/polyfills'; import { default as RSVP, Promise } from 'rsvp'; @@ -52,6 +52,7 @@ import ModelData from './model/model-data'; import edBackburner from './backburner'; const badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; +const emberRun = emberRunLoop.backburner; const { ENV } = Ember; let globalClientIdCounter = 1; @@ -2033,7 +2034,7 @@ Store = Service.extend({ snapshot: snapshot, resolver: resolver, }); - emberRun.once(this, this.flushPendingSave); + emberRun.scheduleOnce('actions', this, this.flushPendingSave); }, /** diff --git a/tests/integration/records/create-record-test.js b/tests/integration/records/create-record-test.js index 59b0040c433..1b11ba3da50 100644 --- a/tests/integration/records/create-record-test.js +++ b/tests/integration/records/create-record-test.js @@ -1,18 +1,25 @@ import { module, test } from 'qunit'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; import { setupTest } from 'ember-qunit'; import Store from 'ember-data/store'; import Model from 'ember-data/model'; +import { resolve } from 'rsvp'; import { attr, belongsTo, hasMany } from '@ember-decorators/data'; class Person extends Model { @hasMany('pet', { inverse: 'owner', async: false }) pets; + @belongsTo('pet', { inverse: 'bestHuman', async: true }) + bestDog; @attr name; } class Pet extends Model { @belongsTo('person', { inverse: 'pets', async: false }) owner; + @belongsTo('person', { inverse: 'bestDog', async: false }) + bestHuman; @attr name; } @@ -111,4 +118,81 @@ module('Store.createRecord() coverage', function(hooks) { .map(pet => pet.get('name')); assert.deepEqual(pets, [], 'Chris no longer has any pets'); }); + + test('creating and saving a record with relationships puts them into the correct state', async function(assert) { + this.owner.register( + 'serializer:application', + JSONAPISerializer.extend({ + normalizeResponse(_, __, data) { + return data; + }, + }) + ); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + shouldBackgroundReload() { + return false; + }, + findRecord() { + assert.ok(false, 'Adapter should not make any findRecord Requests'); + }, + findBelongsTo() { + assert.ok(false, 'Adapter should not make any findBelongsTo Requests'); + }, + createRecord() { + return resolve({ + data: { + type: 'pet', + id: '2', + attributes: { name: 'Shen' }, + relationships: { + bestHuman: { + data: { type: 'person', id: '1' }, + links: { self: './person', related: './person' }, + }, + }, + }, + }); + }, + }) + ); + + let chris = store.push({ + data: { + id: '1', + type: 'person', + attributes: { + name: 'Chris', + }, + relationships: { + bestDog: { + data: null, + links: { self: './dog', related: './dog' }, + }, + }, + }, + }); + + let shen = store.createRecord('pet', { + name: 'Shen', + bestHuman: chris, + }); + + let bestHuman = shen.get('bestHuman'); + let bestDog = await chris.get('bestDog'); + + // check that we are properly configured + assert.ok(bestHuman === chris, 'Precondition: Shen has bestHuman as Chris'); + assert.ok(bestDog === shen, 'Precondition: Chris has Shen as his bestDog'); + + await shen.save(); + + bestHuman = shen.get('bestHuman'); + bestDog = await chris.get('bestDog'); + + // check that the relationship has remained established + assert.ok(bestHuman === chris, 'Shen bestHuman is still Chris'); + assert.ok(bestDog === shen, 'Chris still has Shen as bestDog'); + }); }); diff --git a/tests/integration/records/edit-record-test.js b/tests/integration/records/edit-record-test.js new file mode 100644 index 00000000000..3a8e837cc63 --- /dev/null +++ b/tests/integration/records/edit-record-test.js @@ -0,0 +1,344 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import Store from 'ember-data/store'; +import Model from 'ember-data/model'; +import { attr, belongsTo, hasMany } from '@ember-decorators/data'; + +class Person extends Model { + @hasMany('pet', { inverse: 'owner', async: false }) + pets; + @hasMany('person', { inverse: 'friends', async: true }) + friends; + @belongsTo('person', { inverse: 'bestFriend', async: true }) + bestFriend; + @attr name; +} + +class Pet extends Model { + @belongsTo('person', { inverse: 'pets', async: false }) + owner; + @attr name; +} + +module('Editing a Record', function(hooks) { + let store; + setupTest(hooks); + + hooks.beforeEach(function() { + let { owner } = this; + owner.register('service:store', Store); + owner.register('model:person', Person); + owner.register('model:pet', Pet); + store = owner.lookup('service:store'); + }); + + module('Simple relationship addition case', function() { + module('Adding a sync belongsTo relationship to a record', function() { + test('We can add to a record', async function(assert) { + let chris = store.push({ + data: { + id: '1', + type: 'person', + attributes: { name: 'Chris' }, + relationships: { + pets: { + data: [], + }, + }, + }, + }); + + let pet = store.push({ + data: { + id: '1', + type: 'pet', + attributes: { name: 'Shen' }, + relationships: { + owner: { + data: null, + }, + }, + }, + }); + + // check that we are properly configured + assert.ok(pet.get('owner') === null, 'Precondition: Our owner is null'); + + let pets = chris + .get('pets') + .toArray() + .map(pet => pet.get('name')); + assert.deepEqual(pets, [], 'Precondition: Chris has no pets'); + + pet.set('owner', chris); + + assert.ok(pet.get('owner') === chris, 'Shen has Chris as an owner'); + + // check that the relationship has been established + pets = chris + .get('pets') + .toArray() + .map(pet => pet.get('name')); + assert.deepEqual(pets, ['Shen'], 'Chris has Shen as a pet'); + }); + + test('We can add a new record to a record', async function(assert) { + let chris = store.createRecord('person', { + name: 'Chris', + pets: [], + }); + + let pet = store.push({ + data: { + id: '1', + type: 'pet', + attributes: { name: 'Shen' }, + relationships: { + owner: { + data: null, + }, + }, + }, + }); + + // check that we are properly configured + assert.ok(pet.get('owner') === null, 'Precondition: Our owner is null'); + + let pets = chris + .get('pets') + .toArray() + .map(pet => pet.get('name')); + assert.deepEqual(pets, [], 'Precondition: Chris has no pets'); + + pet.set('owner', chris); + + assert.ok(pet.get('owner') === chris, 'Shen has Chris as an owner'); + + // check that the relationship has been established + pets = chris + .get('pets') + .toArray() + .map(pet => pet.get('name')); + assert.deepEqual(pets, ['Shen'], 'Chris has Shen as a pet'); + }); + + test('We can add a new record to a new record', async function(assert) { + let chris = store.createRecord('person', { + name: 'Chris', + pets: [], + }); + + let pet = store.createRecord('pet', { + name: 'Shen', + owner: null, + }); + + // check that we are properly configured + assert.ok(pet.get('owner') === null, 'Precondition: Our owner is null'); + + let pets = chris + .get('pets') + .toArray() + .map(pet => pet.get('name')); + assert.deepEqual(pets, [], 'Precondition: Chris has no pets'); + + pet.set('owner', chris); + + assert.ok(pet.get('owner') === chris, 'Shen has Chris as an owner'); + + // check that the relationship has been established + pets = chris + .get('pets') + .toArray() + .map(pet => pet.get('name')); + assert.deepEqual(pets, ['Shen'], 'Chris has Shen as a pet'); + }); + + test('We can add to a new record', async function(assert) { + let chris = store.push({ + data: { + id: '1', + type: 'person', + attributes: { name: 'Chris' }, + relationships: { + pets: { + data: [], + }, + }, + }, + }); + + let pet = store.createRecord('pet', { + name: 'Shen', + owner: null, + }); + + // check that we are properly configured + assert.ok(pet.get('owner') === null, 'Precondition: Our owner is null'); + + let pets = chris + .get('pets') + .toArray() + .map(pet => pet.get('name')); + assert.deepEqual(pets, [], 'Precondition: Chris has no pets'); + + pet.set('owner', chris); + + assert.ok(pet.get('owner') === chris, 'Shen has Chris as an owner'); + + // check that the relationship has been established + pets = chris + .get('pets') + .toArray() + .map(pet => pet.get('name')); + assert.deepEqual(pets, ['Shen'], 'Chris has Shen as a pet'); + }); + }); + + module('Adding an async belongsTo relationship to a record', function() { + test('We can add to a record', async function(assert) { + let chris = store.push({ + data: { + id: '1', + type: 'person', + attributes: { name: 'Chris' }, + relationships: { + bestFriend: { + data: null, + }, + }, + }, + }); + + let james = store.push({ + data: { + id: '1', + type: 'person', + attributes: { name: 'James' }, + relationships: { + bestFriend: { + data: null, + }, + }, + }, + }); + + // check that we are properly configured + let chrisBestFriend = await chris.get('bestFriend'); + let jamesBestFriend = await james.get('bestFriend'); + + assert.ok(chrisBestFriend === null, 'Precondition: Chris has no best friend'); + assert.ok(jamesBestFriend === null, 'Precondition: James has no best friend'); + + chris.set('bestFriend', james); + + // check that the relationship has been established + chrisBestFriend = await chris.get('bestFriend'); + jamesBestFriend = await james.get('bestFriend'); + + assert.ok(chrisBestFriend === james, 'Chris has James as a best friend'); + assert.ok(jamesBestFriend === chris, 'James has Chris as a best friend'); + }); + + test('We can add a new record to a record', async function(assert) { + let chris = store.push({ + data: { + id: '1', + type: 'person', + attributes: { name: 'Chris' }, + relationships: { + bestFriend: { + data: null, + }, + }, + }, + }); + + let james = store.createRecord('person', { + name: 'James', + bestFriend: null, + }); + + // check that we are properly configured + let chrisBestFriend = await chris.get('bestFriend'); + let jamesBestFriend = await james.get('bestFriend'); + + assert.ok(chrisBestFriend === null, 'Precondition: Chris has no best friend'); + assert.ok(jamesBestFriend === null, 'Precondition: James has no best friend'); + + chris.set('bestFriend', james); + + // check that the relationship has been established + chrisBestFriend = await chris.get('bestFriend'); + jamesBestFriend = await james.get('bestFriend'); + + assert.ok(chrisBestFriend === james, 'Chris has James as a best friend'); + assert.ok(jamesBestFriend === chris, 'James has Chris as a best friend'); + }); + + test('We can add a new record to a new record', async function(assert) { + let chris = store.createRecord('person', { + name: 'Chris', + bestFriend: null, + }); + + let james = store.createRecord('person', { + name: 'James', + bestFriend: null, + }); + + // check that we are properly configured + let chrisBestFriend = await chris.get('bestFriend'); + let jamesBestFriend = await james.get('bestFriend'); + + assert.ok(chrisBestFriend === null, 'Precondition: Chris has no best friend'); + assert.ok(jamesBestFriend === null, 'Precondition: James has no best friend'); + + chris.set('bestFriend', james); + + // check that the relationship has been established + chrisBestFriend = await chris.get('bestFriend'); + jamesBestFriend = await james.get('bestFriend'); + + assert.ok(chrisBestFriend === james, 'Chris has James as a best friend'); + assert.ok(jamesBestFriend === chris, 'James has Chris as a best friend'); + }); + + test('We can add to a new record', async function(assert) { + let chris = store.createRecord('person', { + name: 'Chris', + bestFriend: null, + }); + + let james = store.push({ + data: { + id: '1', + type: 'person', + attributes: { name: 'James' }, + relationships: { + bestFriend: { + data: null, + }, + }, + }, + }); + + // check that we are properly configured + let chrisBestFriend = await chris.get('bestFriend'); + let jamesBestFriend = await james.get('bestFriend'); + + assert.ok(chrisBestFriend === null, 'Precondition: Chris has no best friend'); + assert.ok(jamesBestFriend === null, 'Precondition: James has no best friend'); + + chris.set('bestFriend', james); + + // check that the relationship has been established + chrisBestFriend = await chris.get('bestFriend'); + jamesBestFriend = await james.get('bestFriend'); + + assert.ok(chrisBestFriend === james, 'Chris has James as a best friend'); + assert.ok(jamesBestFriend === chris, 'James has Chris as a best friend'); + }); + }); + }); +}); diff --git a/tests/integration/records/load-test.js b/tests/integration/records/load-test.js index f7836cc2d33..9d4a4105054 100644 --- a/tests/integration/records/load-test.js +++ b/tests/integration/records/load-test.js @@ -1,39 +1,194 @@ -import { reject } from 'rsvp'; +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { reject, resolve } from 'rsvp'; +import Store from 'ember-data/store'; +import Model from 'ember-data/model'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; +import { attr, belongsTo } from '@ember-decorators/data'; import { run } from '@ember/runloop'; -import setupStore from 'dummy/tests/helpers/store'; -import { module, test } from 'qunit'; +class Person extends Model { + @attr name; + @belongsTo('person', { async: true, inverse: 'bestFriend' }) + bestFriend; +} -import DS from 'ember-data'; +module('integration/load - Loading Records', function(hooks) { + let store; + setupTest(hooks); -const { hasMany } = DS; + hooks.beforeEach(function() { + let { owner } = this; + owner.register('service:store', Store); + owner.register('model:person', Person); + store = owner.lookup('service:store'); + }); -let Post, Comment, env; + test('When loading a record fails, the record is not left behind', async function(assert) { + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + return reject(); + }, + }) + ); -module('integration/load - Loading Records', { - beforeEach() { - Post = DS.Model.extend({ - comments: hasMany({ async: true }), + await store.findRecord('person', '1').catch(() => { + assert.equal(store.hasRecordForId('person', '1'), false); }); + }); - Comment = DS.Model.extend(); + test('Empty records remain in the empty state while data is being fetched', async function(assert) { + let payloads = [ + { + data: { + type: 'person', + id: '1', + attributes: { name: 'Chris' }, + relationships: { + bestFriend: { + data: { type: 'person', id: '2' }, + }, + }, + }, + included: [ + { + type: 'person', + id: '2', + attributes: { name: 'Shen' }, + relationships: { + bestFriend: { + data: { type: 'person', id: '1' }, + }, + }, + }, + ], + }, + { + data: { + type: 'person', + id: '1', + attributes: { name: 'Chris' }, + relationships: { + bestFriend: { + data: { type: 'person', id: '2' }, + }, + }, + }, + }, + { + data: { + type: 'person', + id: '1', + attributes: { name: 'Chris' }, + relationships: { + bestFriend: { + data: { type: 'person', id: '2' }, + }, + }, + }, + }, + ]; - env = setupStore({ post: Post, comment: Comment }); - }, + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + let payload = payloads.shift(); - afterEach() { - run(env.container, 'destroy'); - }, -}); + if (payload === undefined) { + return reject(new Error('Invalid Request')); + } -test('When loading a record fails, the record is not left behind', function(assert) { - env.adapter.findRecord = function(store, type, id, snapshot) { - return reject(); - }; + return resolve(payload); + }, + }) + ); + this.owner.register( + 'serializer:application', + JSONAPISerializer.extend({ + normalizeResponse(_, __, data) { + return data; + }, + }) + ); - return run(() => { - return env.store.findRecord('post', 1).catch(() => { - assert.equal(env.store.hasRecordForId('post', 1), false); - }); + let internalModel = store._internalModelForId('person', '1'); + + // test that our initial state is correct + assert.equal(internalModel.isEmpty(), true, 'We begin in the empty state'); + assert.equal(internalModel.isLoading(), false, 'We have not triggered a load'); + assert.equal(internalModel.isReloading, false, 'We are not reloading'); + + let recordPromise = store.findRecord('person', '1'); + + // test that during the initial load our state is correct + assert.equal( + internalModel.isEmpty(), + true, + 'awaiting first fetch: We remain in the empty state' + ); + assert.equal( + internalModel.isLoading(), + true, + 'awaiting first fetch: We have now triggered a load' + ); + assert.equal(internalModel.isReloading, false, 'awaiting first fetch: We are not reloading'); + + let record = await recordPromise; + + // test that after the initial load our state is correct + assert.equal(internalModel.isEmpty(), false, 'after first fetch: We are no longer empty'); + assert.equal(internalModel.isLoading(), false, 'after first fetch: We have loaded'); + assert.equal(internalModel.isReloading, false, 'after first fetch: We are not reloading'); + + let bestFriend = await record.get('bestFriend'); + let trueBestFriend = await bestFriend.get('bestFriend'); + + // shen is our retainer for the record we are testing + // that ensures unloadRecord later in this test does not fully + // discard the internalModel + let shen = store.peekRecord('person', '2'); + + assert.ok(bestFriend === shen, 'Precond: bestFriend is correct'); + assert.ok(trueBestFriend === record, 'Precond: bestFriend of bestFriend is correct'); + + recordPromise = record.reload(); + + // test that during a reload our state is correct + assert.equal(internalModel.isEmpty(), false, 'awaiting reload: We remain non-empty'); + assert.equal(internalModel.isLoading(), false, 'awaiting reload: We are not loading again'); + assert.equal(internalModel.isReloading, true, 'awaiting reload: We are reloading'); + + await recordPromise; + + // test that after a reload our state is correct + assert.equal(internalModel.isEmpty(), false, 'after reload: We remain non-empty'); + assert.equal(internalModel.isLoading(), false, 'after reload: We have loaded'); + assert.equal(internalModel.isReloading, false, 'after reload:: We are not reloading'); + + run(() => record.unloadRecord()); + + // test that after an unload our state is correct + assert.equal(internalModel.isEmpty(), true, 'after unload: We are empty again'); + assert.equal(internalModel.isLoading(), false, 'after unload: We are not loading'); + assert.equal(internalModel.isReloading, false, 'after unload:: We are not reloading'); + + recordPromise = store.findRecord('person', '1'); + + // test that during a reload-due-to-unload our state is correct + // This requires a retainer (the async bestFriend relationship) + assert.equal(internalModel.isEmpty(), true, 'awaiting second find: We remain empty'); + assert.equal(internalModel.isLoading(), true, 'awaiting second find: We are loading again'); + assert.equal(internalModel.isReloading, false, 'awaiting second find: We are not reloading'); + + await recordPromise; + + // test that after the reload-due-to-unload our state is correct + assert.equal(internalModel.isEmpty(), false, 'after second find: We are no longer empty'); + assert.equal(internalModel.isLoading(), false, 'after second find: We have loaded'); + assert.equal(internalModel.isReloading, false, 'after second find: We are not reloading'); }); }); diff --git a/tests/integration/relationships/json-api-links-test.js b/tests/integration/relationships/json-api-links-test.js index 72110bf59ce..1655e7ff434 100644 --- a/tests/integration/relationships/json-api-links-test.js +++ b/tests/integration/relationships/json-api-links-test.js @@ -678,6 +678,7 @@ module('integration/relationship/json-api-links | Relationship fetching', { const Pet = Model.extend({ name: attr(), owner: belongsTo('user', { async: false, inverse: 'pets' }), + friends: hasMany('pet', { async: false, inverse: 'friends' }), }); const Adapter = JSONAPIAdapter.extend(); @@ -1965,3 +1966,92 @@ test('We should not fetch a hasMany relationship with links that we know is empt 'We improperly fetched the link for a previously fetched and found to be empty relationship'; run(() => user2.get('pets')); }); + +test('We should not fetch a sync hasMany relationship with a link that is missing the data member', function(assert) { + assert.expect(1); + let { store, adapter } = env; + + let petPayload = { + data: { + type: 'pet', + id: '1', + attributes: { + name: 'Shen', + }, + relationships: { + friends: { + links: { + related: './shen/friends', + }, + }, + }, + }, + }; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(false, 'We should not call findRecord'); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = () => { + assert.ok(false, 'We should not call findHasMany'); + }; + adapter.findBelongsTo = () => { + assert.ok(false, 'We should not call findBelongsTo'); + }; + + // setup users + let shen = run(() => store.push(petPayload)); + + // should not fire a request + run(() => shen.get('pets')); + + assert.ok(true, 'We reached the end of the test'); +}); + +test('We should not fetch a sync belongsTo relationship with a link that is missing the data member', function(assert) { + assert.expect(1); + let { store, adapter } = env; + + let petPayload = { + data: { + type: 'pet', + id: '1', + attributes: { + name: 'Shen', + }, + relationships: { + owner: { + links: { + related: './shen/owner', + self: './owner/a', + }, + }, + }, + }, + }; + + adapter.shouldBackgroundReloadRecord = () => false; + adapter.findRecord = () => { + assert.ok(false, 'We should not call findRecord'); + }; + adapter.findMany = () => { + assert.ok(false, 'We should not call findMany'); + }; + adapter.findHasMany = () => { + assert.ok(false, 'We should not call findHasMany'); + }; + adapter.findBelongsTo = () => { + assert.ok(false, 'We should not call findBelongsTo'); + }; + + // setup users + let shen = run(() => store.push(petPayload)); + + // should not fire a request + run(() => shen.get('owner')); + + assert.ok(true, 'We reached the end of the test'); +}); diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index dfcd91a2340..ba547923e51 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -577,7 +577,7 @@ testInDebug( }, }); }); - }, /You pushed a record of type 'person' with a relationship 'phoneNumbers' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload./); + }, /You pushed a record of type 'person' with a relationship 'phoneNumbers' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload. EmberData will treat this relationship as known-to-be-empty./); } ); From 4cf7003f7300d0efb61b7ac5bf33932b3b4908c1 Mon Sep 17 00:00:00 2001 From: bmac Date: Tue, 24 Jul 2018 14:36:35 -0400 Subject: [PATCH 2284/2527] Update changelog for 2.18.4 release --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e8c72641e5..18eeac5c30f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ### Master +### Release 2.18.4 (July 24, 2018) +- [#5376](https://github.com/emberjs/data/pull/5376) [bugfix beta] Fetch cancels unload + ### Release 3.3.0 (July 13, 2018) - Re-release of Ember Data 3.2.0 From a3428127c782474103868b952ffcf4987260376c Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 17 Jul 2018 14:15:15 -0700 Subject: [PATCH 2285/2527] broccoli-babel-transpiler appears only used in tests, otherwise it uses ember-cli-babel --- package.json | 2 +- yarn.lock | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index fc855f51a04..4c9192808a9 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "babel-plugin-transform-es2015-block-scoping": "^6.24.1", "babel6-plugin-strip-class-callcheck": "^6.0.0", "babel6-plugin-strip-heimdall": "^6.0.1", - "broccoli-babel-transpiler": "^6.0.0", "broccoli-debug": "^0.6.2", "broccoli-file-creator": "^1.0.0", "broccoli-funnel": "^2.0.1", @@ -68,6 +67,7 @@ "babel-plugin-transform-es2015-spread": "^6.22.0", "babel-plugin-transform-es2015-template-literals": "^6.22.0", "broccoli-asset-rev": "^2.4.5", + "broccoli-babel-transpiler": "^6.4.3", "broccoli-concat": "^3.2.2", "broccoli-stew": "^1.4.2", "broccoli-string-replace": "^0.1.1", diff --git a/yarn.lock b/yarn.lock index 1b1f17c8435..7f466a24aa1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1387,6 +1387,21 @@ broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2, broccoli-bab rsvp "^4.8.2" workerpool "^2.3.0" +broccoli-babel-transpiler@^6.4.3: + version "6.4.3" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.4.3.tgz#06e399298d41700cdc10d675b1d808a89ef6b2d0" + dependencies: + babel-core "^6.26.0" + broccoli-funnel "^2.0.1" + broccoli-merge-trees "^2.0.0" + broccoli-persistent-filter "^1.4.3" + clone "^2.0.0" + hash-for-dep "^1.2.3" + heimdalljs-logger "^0.1.7" + json-stable-stringify "^1.0.0" + rsvp "^4.8.2" + workerpool "^2.3.0" + broccoli-builder@^0.18.8: version "0.18.14" resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.14.tgz#4b79e2f844de11a4e1b816c3f49c6df4776c312d" From 975264616ebbca1cdbb6aad027492e8c811acc05 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Tue, 17 Jul 2018 14:17:13 -0700 Subject: [PATCH 2286/2527] Upgrade ember-cli-babel --- package.json | 2 +- yarn.lock | 41 +++++++++++++++++++++++++---------------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 4c9192808a9..7bb3e3c71eb 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "broccoli-rollup": "^2.1.0", "calculate-cache-key-for-tree": "^1.1.0", "chalk": "^1.1.1", - "ember-cli-babel": "^6.8.2", + "ember-cli-babel": "^6.15.0", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.0.0", "ember-cli-test-info": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 7f466a24aa1..bd85e1c202d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -743,6 +743,12 @@ babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.11: dependencies: semver "^5.3.0" +babel-plugin-debug-macros@^0.2.0-beta.6: + version "0.2.0-beta.6" + resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0-beta.6.tgz#ecdf6e408d5c863ab21740d7ad7f43f027d2f912" + dependencies: + semver "^5.3.0" + babel-plugin-ember-modules-api-polyfill@^1.4.2: version "1.6.0" resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-1.6.0.tgz#abd1afa4237b3121cb51222f9bf3283cad8990aa" @@ -1372,7 +1378,7 @@ broccoli-babel-transpiler@^5.6.2: rsvp "^3.5.0" workerpool "^2.3.0" -broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2, broccoli-babel-transpiler@^6.4.2: +broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2, broccoli-babel-transpiler@^6.4.2, broccoli-babel-transpiler@^6.4.3: version "6.4.3" resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.4.3.tgz#06e399298d41700cdc10d675b1d808a89ef6b2d0" dependencies: @@ -1387,21 +1393,6 @@ broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2, broccoli-bab rsvp "^4.8.2" workerpool "^2.3.0" -broccoli-babel-transpiler@^6.4.3: - version "6.4.3" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.4.3.tgz#06e399298d41700cdc10d675b1d808a89ef6b2d0" - dependencies: - babel-core "^6.26.0" - broccoli-funnel "^2.0.1" - broccoli-merge-trees "^2.0.0" - broccoli-persistent-filter "^1.4.3" - clone "^2.0.0" - hash-for-dep "^1.2.3" - heimdalljs-logger "^0.1.7" - json-stable-stringify "^1.0.0" - rsvp "^4.8.2" - workerpool "^2.3.0" - broccoli-builder@^0.18.8: version "0.18.14" resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.14.tgz#4b79e2f844de11a4e1b816c3f49c6df4776c312d" @@ -2663,6 +2654,24 @@ ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-be ember-cli-version-checker "^2.1.2" semver "^5.5.0" +ember-cli-babel@^6.15.0: + version "6.15.0" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.15.0.tgz#86114b7e94afa058b02e59bfd85794c48cc56090" + dependencies: + amd-name-resolver "1.2.0" + babel-plugin-debug-macros "^0.2.0-beta.6" + babel-plugin-ember-modules-api-polyfill "^2.3.0" + babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-polyfill "^6.26.0" + babel-preset-env "^1.7.0" + broccoli-babel-transpiler "^6.4.2" + broccoli-debug "^0.6.4" + broccoli-funnel "^2.0.0" + broccoli-source "^1.1.0" + clone "^2.0.0" + ember-cli-version-checker "^2.1.2" + semver "^5.5.0" + ember-cli-blueprint-test-helpers@^0.18.3: version "0.18.3" resolved "https://registry.npmjs.org/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.18.3.tgz#945c606d855f0263f5e8c03522e4040a74f259cc" From 76c8a94033db772a29a72f39e5503fa197d09dfd Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 26 Jul 2018 09:48:42 -0400 Subject: [PATCH 2287/2527] Update changelog for Ember Data 3.3.1 release --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18eeac5c30f..47664ba5a88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ### Master +### Release 3.3.1 (July 26, 2018) +- [#5541](https://github.com/emberjs/data/pull/5541) [BUGFIX] backport fix for belongsTo proxy update + ### Release 2.18.4 (July 24, 2018) - [#5376](https://github.com/emberjs/data/pull/5376) [bugfix beta] Fetch cancels unload From c754fd6493f32b1af3cdd88c805d1c419216843c Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 26 Jul 2018 09:54:45 -0400 Subject: [PATCH 2288/2527] Update changelog for 3.2.1 release --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47664ba5a88..a58afe38161 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ ### Release 3.3.1 (July 26, 2018) - [#5541](https://github.com/emberjs/data/pull/5541) [BUGFIX] backport fix for belongsTo proxy update +### Release 3.2.1 (July 26, 2018) +- [#5541](https://github.com/emberjs/data/pull/5541) [BUGFIX] backport fix for belongsTo proxy update + ### Release 2.18.4 (July 24, 2018) - [#5376](https://github.com/emberjs/data/pull/5376) [bugfix beta] Fetch cancels unload @@ -32,7 +35,6 @@ - [#5476](https://github.com/emberjs/data/pull/5476) [Feature] added module-unification adapter and adapter-test blueprints - [#5508](https://github.com/emberjs/data/pull/5508) [CHORE] Update Dependencies - ### Release 3.2.0 (June 29, 2018) - [#5497](https://github.com/emberjs/data/pull/5497) [BUGFIX] Make snapshot lazier and fix defaultValue. From 387cf9298ed93ae0fdb3bd5a7dcc0c3552accc50 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 26 Jul 2018 12:09:07 -1000 Subject: [PATCH 2289/2527] revert is-empty flag change, leave todo (#5540) * revert is-empty flag change, leave todo * fix tests --- addon/-legacy-private/system/model/states.js | 1 - addon/-record-data-private/system/model/states.js | 1 - tests/helpers/todo.js | 2 +- tests/integration/records/load-test.js | 9 ++++++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/addon/-legacy-private/system/model/states.js b/addon/-legacy-private/system/model/states.js index 33aefc63e1b..7697a1f1fd9 100644 --- a/addon/-legacy-private/system/model/states.js +++ b/addon/-legacy-private/system/model/states.js @@ -521,7 +521,6 @@ const RootState = { loading: { // FLAGS isLoading: true, - isEmpty: true, exit(internalModel) { internalModel._promiseProxy = null; diff --git a/addon/-record-data-private/system/model/states.js b/addon/-record-data-private/system/model/states.js index 035da6d7b47..98cf914167e 100644 --- a/addon/-record-data-private/system/model/states.js +++ b/addon/-record-data-private/system/model/states.js @@ -518,7 +518,6 @@ const RootState = { // XHR to retrieve the data. loading: { // FLAGS - isEmpty: true, isLoading: true, exit(internalModel) { diff --git a/tests/helpers/todo.js b/tests/helpers/todo.js index b6d62518b9b..41a570184cd 100644 --- a/tests/helpers/todo.js +++ b/tests/helpers/todo.js @@ -6,7 +6,7 @@ export default function todo(description, callback) { let todos = []; hijackAssert(assert, todos); - await callback(assert); + await callback.call(this, assert); assertTestStatus(assert, todos); }); diff --git a/tests/integration/records/load-test.js b/tests/integration/records/load-test.js index 9d4a4105054..3b657ea7a75 100644 --- a/tests/integration/records/load-test.js +++ b/tests/integration/records/load-test.js @@ -7,6 +7,7 @@ import JSONAPIAdapter from 'ember-data/adapters/json-api'; import JSONAPISerializer from 'ember-data/serializers/json-api'; import { attr, belongsTo } from '@ember-decorators/data'; import { run } from '@ember/runloop'; +import todo from '../../helpers/todo'; class Person extends Model { @attr name; @@ -40,7 +41,9 @@ module('integration/load - Loading Records', function(hooks) { }); }); - test('Empty records remain in the empty state while data is being fetched', async function(assert) { + todo('Empty records remain in the empty state while data is being fetched', async function( + assert + ) { let payloads = [ { data: { @@ -125,7 +128,7 @@ module('integration/load - Loading Records', function(hooks) { let recordPromise = store.findRecord('person', '1'); // test that during the initial load our state is correct - assert.equal( + assert.todo.equal( internalModel.isEmpty(), true, 'awaiting first fetch: We remain in the empty state' @@ -180,7 +183,7 @@ module('integration/load - Loading Records', function(hooks) { // test that during a reload-due-to-unload our state is correct // This requires a retainer (the async bestFriend relationship) - assert.equal(internalModel.isEmpty(), true, 'awaiting second find: We remain empty'); + assert.todo.equal(internalModel.isEmpty(), true, 'awaiting second find: We remain empty'); assert.equal(internalModel.isLoading(), true, 'awaiting second find: We are loading again'); assert.equal(internalModel.isReloading, false, 'awaiting second find: We are not reloading'); From a5f1d41b8690123a1402048f5379e6fc0bdc88c0 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 26 Jul 2018 13:59:35 -1000 Subject: [PATCH 2290/2527] remove test waiter (#5544) * remove test waiter * Add store encapsulated waiter * dont leak waiters * if debug add bugs * make calls symetrical --- addon/-legacy-private/system/store.js | 26 ++++++++++--------- addon/-private/system/store/common.js | 17 +++--------- addon/-private/system/store/finders.js | 30 +--------------------- addon/-record-data-private/system/store.js | 25 ++++++++++-------- 4 files changed, 33 insertions(+), 65 deletions(-) diff --git a/addon/-legacy-private/system/store.js b/addon/-legacy-private/system/store.js index 793ed7d4712..ae75e920ac8 100644 --- a/addon/-legacy-private/system/store.js +++ b/addon/-legacy-private/system/store.js @@ -11,7 +11,6 @@ import { assign } from '@ember/polyfills'; import { default as RSVP, Promise } from 'rsvp'; import Service from '@ember/service'; import { typeOf, isPresent, isNone } from '@ember/utils'; - import Ember from 'ember'; import { InvalidError } from '../adapters/errors'; import { instrument } from 'ember-data/-debug'; @@ -23,13 +22,7 @@ import IdentityMap from './identity-map'; import { promiseArray, promiseObject } from './promise-proxies'; -import { - _bind, - _guard, - _objectIsAlive, - guardDestroyedStore, - incrementRequestCount, -} from './store/common'; +import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './store/common'; import { normalizeResponseHelper } from './store/serializer-response'; import { serializerForAdapter } from './store/serializers'; @@ -225,6 +218,15 @@ Store = Service.extend({ this._adapterCache = Object.create(null); this._serializerCache = Object.create(null); + + if (DEBUG) { + this.__asyncRequestCount = 0; + this.__asyncWaiter = () => { + return this.__asyncRequestCount === 0; + }; + + Ember.Test.registerWaiter(this.__asyncWaiter); + } }, /** @@ -2835,6 +2837,10 @@ Store = Service.extend({ this._serializerCache = null; this.unloadAll(); + + if (DEBUG) { + Ember.Test.unregisterWaiter(this.__asyncWaiter); + } }, _updateRelationshipState(relationship) { @@ -2929,10 +2935,6 @@ function _commit(adapter, store, operation, snapshot) { typeof adapter[operation] === 'function' ); - if (DEBUG) { - incrementRequestCount(); - } - let promise = Promise.resolve().then(() => adapter[operation](store, modelClass, snapshot)); let serializer = serializerForAdapter(store, adapter, modelName); let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; diff --git a/addon/-private/system/store/common.js b/addon/-private/system/store/common.js index f2448a444ff..ac56b0a8797 100644 --- a/addon/-private/system/store/common.js +++ b/addon/-private/system/store/common.js @@ -1,6 +1,5 @@ import { get } from '@ember/object'; import { DEBUG } from '@glimmer/env'; -import Ember from 'ember'; import { resolve } from 'rsvp'; const { __bind, __guard, __objectIsAlive } = heimdall.registerMonitor( @@ -34,23 +33,15 @@ export function _objectIsAlive(object) { return !(get(object, 'isDestroyed') || get(object, 'isDestroying')); } -let ASYNC_REQUEST_COUNT = 0; -export function incrementRequestCount() { - ASYNC_REQUEST_COUNT++; -} - -if (DEBUG) { - Ember.Test.registerWaiter(() => { - return ASYNC_REQUEST_COUNT === 0; - }); -} - export function guardDestroyedStore(promise, store, label) { + if (DEBUG) { + store.__asyncRequestCount++; + } let wrapperPromise = resolve(promise, label).then(v => promise); return _guard(wrapperPromise, () => { if (DEBUG) { - ASYNC_REQUEST_COUNT--; + store.__asyncRequestCount--; } return _objectIsAlive(store); }); diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 87da5c87dc3..5998682afa3 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -1,15 +1,8 @@ import { A } from '@ember/array'; import { Promise } from 'rsvp'; import { assert, warn } from '@ember/debug'; -import { DEBUG } from '@glimmer/env'; -import { - _bind, - _guard, - _objectIsAlive, - guardDestroyedStore, - incrementRequestCount, -} from './common'; +import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './common'; import { normalizeResponseHelper } from './serializer-response'; import { serializerForAdapter } from './serializers'; @@ -23,9 +16,6 @@ function payloadIsNotBlank(adapterPayload) { } export function _find(adapter, store, modelClass, id, internalModel, options) { - if (DEBUG) { - incrementRequestCount(); - } let snapshot = internalModel.createSnapshot(options); let { modelName } = internalModel; let promise = Promise.resolve().then(() => { @@ -80,9 +70,6 @@ export function _find(adapter, store, modelClass, id, internalModel, options) { } export function _findMany(adapter, store, modelName, ids, internalModels) { - if (DEBUG) { - incrementRequestCount(); - } let snapshots = A(internalModels).invoke('createSnapshot'); let modelClass = store.modelFor(modelName); // `adapter.findMany` gets the modelClass still let promise = adapter.findMany(store, modelClass, ids, snapshots); @@ -117,9 +104,6 @@ export function _findMany(adapter, store, modelName, ids, internalModels) { } export function _findHasMany(adapter, store, internalModel, link, relationship) { - if (DEBUG) { - incrementRequestCount(); - } let snapshot = internalModel.createSnapshot(); let modelClass = store.modelFor(relationship.type); let promise = adapter.findHasMany(store, snapshot, link, relationship); @@ -158,9 +142,6 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) } export function _findBelongsTo(adapter, store, internalModel, link, relationship) { - if (DEBUG) { - incrementRequestCount(); - } let snapshot = internalModel.createSnapshot(); let modelClass = store.modelFor(relationship.type); let promise = adapter.findBelongsTo(store, snapshot, link, relationship); @@ -195,9 +176,6 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship } export function _findAll(adapter, store, modelName, sinceToken, options) { - if (DEBUG) { - incrementRequestCount(); - } let modelClass = store.modelFor(modelName); // adapter.findAll depends on the class let recordArray = store.peekAll(modelName); let snapshotArray = recordArray._createSnapshot(options); @@ -235,9 +213,6 @@ export function _findAll(adapter, store, modelName, sinceToken, options) { } export function _query(adapter, store, modelName, query, recordArray, options) { - if (DEBUG) { - incrementRequestCount(); - } let modelClass = store.modelFor(modelName); // adapter.query needs the class let promise; @@ -298,9 +273,6 @@ export function _query(adapter, store, modelName, query, recordArray, options) { } export function _queryRecord(adapter, store, modelName, query, options) { - if (DEBUG) { - incrementRequestCount(); - } let modelClass = store.modelFor(modelName); // adapter.queryRecord needs the class let promise = Promise.resolve().then(() => adapter.queryRecord(store, modelClass, query, options) diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index 2ffecb36026..afd1e347b81 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -23,13 +23,7 @@ import ModelDataWrapper from './store/model-data-wrapper'; import { promiseArray, promiseObject } from './promise-proxies'; -import { - _bind, - _guard, - _objectIsAlive, - guardDestroyedStore, - incrementRequestCount, -} from './store/common'; +import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './store/common'; import { normalizeResponseHelper } from './store/serializer-response'; import { serializerForAdapter } from './store/serializers'; @@ -230,6 +224,15 @@ Store = Service.extend({ this._serializerCache = Object.create(null); this.modelDataWrapper = new ModelDataWrapper(this); + + if (DEBUG) { + this.__asyncRequestCount = 0; + this.__asyncWaiter = () => { + return this.__asyncRequestCount === 0; + }; + + Ember.Test.registerWaiter(this.__asyncWaiter); + } }, /** @@ -3054,6 +3057,10 @@ Store = Service.extend({ this._serializerCache = null; this.unloadAll(); + + if (DEBUG) { + Ember.Test.unregisterWaiter(this.__asyncWaiter); + } }, _updateRelationshipState(relationship) { @@ -3154,10 +3161,6 @@ function _commit(adapter, store, operation, snapshot) { typeof adapter[operation] === 'function' ); - if (DEBUG) { - incrementRequestCount(); - } - let promise = Promise.resolve().then(() => adapter[operation](store, modelClass, snapshot)); let serializer = serializerForAdapter(store, adapter, modelName); let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; From ae19d17f988eff9560667807ac06ce360453678c Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Thu, 26 Jul 2018 20:00:13 -0400 Subject: [PATCH 2291/2527] Do not publish yarn.lock to npm (#5543) --- .npmignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.npmignore b/.npmignore index 4c46690a01b..f7a501ab832 100644 --- a/.npmignore +++ b/.npmignore @@ -20,6 +20,7 @@ bower.json ember-cli-build.js testem.js +yarn.lock *.gem *.gemspec From db9946ac7e5ee4c82e89f4c5d88ee360813c228d Mon Sep 17 00:00:00 2001 From: James Martinez Date: Thu, 14 Jun 2018 10:58:38 -0400 Subject: [PATCH 2292/2527] [BUGFIX] Lowercase header field names --- addon/-private/utils/parse-response-headers.js | 3 +++ addon/adapters/rest.js | 2 +- tests/unit/adapters/rest-adapter/detailed-message-test.js | 2 +- tests/unit/utils/parse-response-headers-test.js | 8 +++++--- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/addon/-private/utils/parse-response-headers.js b/addon/-private/utils/parse-response-headers.js index ef8e8fa7d20..b4cde35cb38 100644 --- a/addon/-private/utils/parse-response-headers.js +++ b/addon/-private/utils/parse-response-headers.js @@ -29,6 +29,9 @@ export default function parseResponseHeaders(headersString) { let value = header.substring(j + 1, header.length).trim(); if (value) { + let lowerCasedField = field.toLowerCase(); + + headers[lowerCasedField] = value; headers[field] = value; } } diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index a8cd88d2532..e8710af193c 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1156,7 +1156,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { */ generatedDetailedMessage: function(status, headers, payload, requestData) { let shortenedPayload; - let payloadContentType = headers['Content-Type'] || 'Empty Content-Type'; + let payloadContentType = headers['content-type'] || 'Empty Content-Type'; if (payloadContentType === 'text/html' && payload.length > 250) { shortenedPayload = '[Omitted Lengthy HTML]'; diff --git a/tests/unit/adapters/rest-adapter/detailed-message-test.js b/tests/unit/adapters/rest-adapter/detailed-message-test.js index 195c24b34de..3971e3b85b8 100644 --- a/tests/unit/adapters/rest-adapter/detailed-message-test.js +++ b/tests/unit/adapters/rest-adapter/detailed-message-test.js @@ -21,7 +21,7 @@ test('generating a wonderfully friendly error message should work', function(ass let friendlyMessage = adapter.generatedDetailedMessage( 418, - { 'Content-Type': 'text/plain' }, + { 'content-type': 'text/plain' }, "I'm a little teapot, short and stout", { url: '/teapots/testing', diff --git a/tests/unit/utils/parse-response-headers-test.js b/tests/unit/utils/parse-response-headers-test.js index b74eef497a5..20e8801953c 100644 --- a/tests/unit/utils/parse-response-headers-test.js +++ b/tests/unit/utils/parse-response-headers-test.js @@ -21,7 +21,7 @@ test('header parsing', function(assert) { let headers = parseResponseHeaders(headersString); - assert.equal(headers['Content-Encoding'], 'gzip', 'parses basic header pair'); + assert.equal(headers['content-encoding'], 'gzip', 'parses basic header pair'); assert.equal( headers['content-type'], 'application/json; charset=utf-8', @@ -34,6 +34,7 @@ test('field-name parsing', function(assert) { let headersString = [ ' name-with-leading-whitespace: some value', 'name-with-whitespace-before-colon : another value', + 'Uppercase-Name: yet another value', ].join(CRLF); let headers = parseResponseHeaders(headersString); @@ -48,6 +49,7 @@ test('field-name parsing', function(assert) { 'another value', 'strips whitespace before colon from field-name' ); + assert.equal(headers['uppercase-name'], 'yet another value', 'lowercases the field-name'); }); test('field-value parsing', function(assert) { @@ -92,9 +94,9 @@ test('ignores headers that do not contain a colon', function(assert) { let headers = parseResponseHeaders(headersString); - assert.deepEqual(headers['Content-Encoding'], 'gzip', 'parses basic header pair'); + assert.deepEqual(headers['content-encoding'], 'gzip', 'parses basic header pair'); assert.deepEqual(headers['apple'], 'pie', 'parses basic header pair'); - assert.equal(Object.keys(headers).length, 2, 'only has the one valid header'); + assert.equal(Object.keys(headers).length, 3, 'only has the three valid headers'); }); test('tollerate extra new-lines', function(assert) { From ce0e0ee9d72649f47ee9050dc02910b8da1c8afe Mon Sep 17 00:00:00 2001 From: Nathaniel Furniss Date: Tue, 31 Jul 2018 10:31:12 -0700 Subject: [PATCH 2293/2527] [BUGFIX beta] Replace Object.assign with Ember polyfill assign (#5549) --- addon/-record-data-private/system/model/internal-model.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/-record-data-private/system/model/internal-model.js b/addon/-record-data-private/system/model/internal-model.js index 38ace8ec672..b13bf977129 100644 --- a/addon/-record-data-private/system/model/internal-model.js +++ b/addon/-record-data-private/system/model/internal-model.js @@ -3,6 +3,7 @@ import EmberError from '@ember/error'; import { A } from '@ember/array'; import { setOwner } from '@ember/application'; import { run } from '@ember/runloop'; +import { assign } from '@ember/polyfills'; import RSVP, { Promise } from 'rsvp'; import Ember from 'ember'; import { DEBUG } from '@glimmer/env'; @@ -285,7 +286,7 @@ export default class InternalModel { } let additionalCreateOptions = this._modelData._initRecordCreateOptions(properties); - Object.assign(createOptions, additionalCreateOptions); + assign(createOptions, additionalCreateOptions); if (setOwner) { // ensure that `getOwner(this)` works inside a model instance From 1abc3bb38ddba37d68b4cf9c14f4486628746d89 Mon Sep 17 00:00:00 2001 From: Cyrille David Date: Tue, 31 Jul 2018 21:58:05 +0000 Subject: [PATCH 2294/2527] Fix `floating dependencies` test suite (#5551) You may want to have a look to this prettier release note: https://prettier.io/blog/2018/07/29/1.14.0.html#javascript --- package.json | 2 +- tests/acceptance/relationships/has-many-test.js | 3 ++- tests/integration/records/create-record-test.js | 6 ++++-- tests/integration/records/edit-record-test.js | 6 ++++-- tests/integration/records/load-test.js | 3 ++- yarn.lock | 6 +++--- 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 7bb3e3c71eb..08262dfaa9a 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "loader.js": "^4.5.0", "mocha": "^2.4.5", "mocha-only-detector": "0.0.2", - "prettier": "^1.13.6", + "prettier": "^1.14.0", "rimraf": "2.5.2", "rsvp": "4.8.0", "testdouble": "^3.2.6", diff --git a/tests/acceptance/relationships/has-many-test.js b/tests/acceptance/relationships/has-many-test.js index d93f914c532..dc40dc717f6 100644 --- a/tests/acceptance/relationships/has-many-test.js +++ b/tests/acceptance/relationships/has-many-test.js @@ -17,7 +17,8 @@ function domListToArray(domList) { } class Person extends Model { - @attr name; + @attr + name; @hasMany('person', { async: true, inverse: 'parent' }) children; @belongsTo('person', { async: true, inverse: 'children' }) diff --git a/tests/integration/records/create-record-test.js b/tests/integration/records/create-record-test.js index 1b11ba3da50..51477ae2a9c 100644 --- a/tests/integration/records/create-record-test.js +++ b/tests/integration/records/create-record-test.js @@ -12,7 +12,8 @@ class Person extends Model { pets; @belongsTo('pet', { inverse: 'bestHuman', async: true }) bestDog; - @attr name; + @attr + name; } class Pet extends Model { @@ -20,7 +21,8 @@ class Pet extends Model { owner; @belongsTo('person', { inverse: 'bestDog', async: false }) bestHuman; - @attr name; + @attr + name; } module('Store.createRecord() coverage', function(hooks) { diff --git a/tests/integration/records/edit-record-test.js b/tests/integration/records/edit-record-test.js index 3a8e837cc63..c407535a36a 100644 --- a/tests/integration/records/edit-record-test.js +++ b/tests/integration/records/edit-record-test.js @@ -11,13 +11,15 @@ class Person extends Model { friends; @belongsTo('person', { inverse: 'bestFriend', async: true }) bestFriend; - @attr name; + @attr + name; } class Pet extends Model { @belongsTo('person', { inverse: 'pets', async: false }) owner; - @attr name; + @attr + name; } module('Editing a Record', function(hooks) { diff --git a/tests/integration/records/load-test.js b/tests/integration/records/load-test.js index 3b657ea7a75..6d36e05e0ac 100644 --- a/tests/integration/records/load-test.js +++ b/tests/integration/records/load-test.js @@ -10,7 +10,8 @@ import { run } from '@ember/runloop'; import todo from '../../helpers/todo'; class Person extends Model { - @attr name; + @attr + name; @belongsTo('person', { async: true, inverse: 'bestFriend' }) bestFriend; } diff --git a/yarn.lock b/yarn.lock index bd85e1c202d..c9e11b01ad1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6292,9 +6292,9 @@ pretender@^1.4.2: fake-xml-http-request "^1.6.0" route-recognizer "^0.3.3" -prettier@^1.13.6: - version "1.13.6" - resolved "https://registry.npmjs.org/prettier/-/prettier-1.13.6.tgz#00ae0b777ad92f81a9e7a1df2f0470b6dab0cb44" +prettier@^1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.14.0.tgz#847c235522035fd988100f1f43cf20a7d24f9372" pretty-ms@^3.1.0: version "3.2.0" From df42f8bf301cb7a9b5c85372b31b4b9e622aa330 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 8 Aug 2018 10:47:48 -0400 Subject: [PATCH 2295/2527] [BUGFIX beta] Update dependencies to latest versions. --- package.json | 124 ++--- yarn.lock | 1288 +++++++++++++++++++++++++------------------------- 2 files changed, 713 insertions(+), 699 deletions(-) diff --git a/package.json b/package.json index 08262dfaa9a..9de79b000e2 100644 --- a/package.json +++ b/package.json @@ -21,104 +21,104 @@ "author": "", "license": "MIT", "dependencies": { - "@ember/ordered-set": "^1.0.0", - "amd-name-resolver": "0.0.7", + "@ember/ordered-set": "^2.0.0", + "amd-name-resolver": "1.2.0", "babel-plugin-debug-macros": "^0.1.11", - "babel-plugin-ember-modules-api-polyfill": "^1.4.2", + "babel-plugin-ember-modules-api-polyfill": "^2.3.2", "babel-plugin-feature-flags": "^0.3.1", "babel-plugin-filter-imports": "^0.3.1", - "babel-plugin-transform-es2015-block-scoping": "^6.24.1", + "babel-plugin-transform-es2015-block-scoping": "^6.26.0", "babel6-plugin-strip-class-callcheck": "^6.0.0", "babel6-plugin-strip-heimdall": "^6.0.1", - "broccoli-debug": "^0.6.2", - "broccoli-file-creator": "^1.0.0", + "broccoli-debug": "^0.6.4", + "broccoli-file-creator": "^2.1.1", "broccoli-funnel": "^2.0.1", - "broccoli-merge-trees": "^2.0.0", - "broccoli-rollup": "^2.1.0", + "broccoli-merge-trees": "^3.0.0", + "broccoli-rollup": "^2.1.1", "calculate-cache-key-for-tree": "^1.1.0", - "chalk": "^1.1.1", - "ember-cli-babel": "^6.15.0", + "chalk": "^2.4.1", + "ember-cli-babel": "^6.16.0", "ember-cli-path-utils": "^1.0.0", - "ember-cli-string-utils": "^1.0.0", + "ember-cli-string-utils": "^1.1.0", "ember-cli-test-info": "^1.0.0", - "ember-cli-version-checker": "^2.1.0", + "ember-cli-version-checker": "^2.1.2", "ember-inflector": "^3.0.0", - "ember-runtime-enumerable-includes-polyfill": "^2.0.0", - "git-repo-info": "^1.1.2", + "ember-runtime-enumerable-includes-polyfill": "^2.1.0", + "git-repo-info": "^2.0.0", "heimdalljs": "^0.3.0", - "inflection": "^1.8.0", - "npm-git-info": "^1.0.0", - "resolve": "^1.5.0", - "semver": "^5.1.0", - "silent-error": "^1.0.0" + "inflection": "^1.12.0", + "npm-git-info": "^1.0.3", + "resolve": "^1.8.1", + "semver": "^5.5.0", + "silent-error": "^1.1.0" }, "devDependencies": { - "@ember-decorators/babel-transforms": "^2.0.0", - "@ember-decorators/data": "^2.1.0", - "babel-eslint": "^8.0.0", + "@ember-decorators/babel-transforms": "^2.0.2", + "@ember-decorators/data": "^2.3.1", + "babel-eslint": "^8.2.6", "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-classes": "^6.23.0", - "babel-plugin-transform-es2015-computed-properties": "^6.22.0", + "babel-plugin-transform-es2015-classes": "^6.24.1", + "babel-plugin-transform-es2015-computed-properties": "^6.24.1", "babel-plugin-transform-es2015-constants": "^6.1.4", "babel-plugin-transform-es2015-destructuring": "^6.23.0", - "babel-plugin-transform-es2015-modules-amd": "^6.24.0", - "babel-plugin-transform-es2015-parameters": "^6.23.0", - "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-plugin-transform-es2015-parameters": "^6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", "babel-plugin-transform-es2015-spread": "^6.22.0", "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "broccoli-asset-rev": "^2.4.5", - "broccoli-babel-transpiler": "^6.4.3", - "broccoli-concat": "^3.2.2", - "broccoli-stew": "^1.4.2", - "broccoli-string-replace": "^0.1.1", - "broccoli-test-helper": "^1.2.0", - "broccoli-uglify-sourcemap": "^1.0.1", + "broccoli-asset-rev": "^2.7.0", + "broccoli-babel-transpiler": "^6.5.0", + "broccoli-concat": "^3.5.1", + "broccoli-stew": "^2.0.0", + "broccoli-string-replace": "^0.1.2", + "broccoli-test-helper": "^1.4.0", + "broccoli-uglify-sourcemap": "^2.2.0", "co": "^4.6.0", - "common-tags": "^1.4.0", - "ember-cli": "^3.1.4", - "ember-cli-app-version": "^3.0.0", + "common-tags": "^1.8.0", + "ember-cli": "^3.3.0", + "ember-cli-app-version": "^3.2.0", "ember-cli-blueprint-test-helpers": "^0.18.3", - "ember-cli-dependency-checker": "^2.1.0", + "ember-cli-dependency-checker": "^3.0.0", "ember-cli-eslint": "^4.2.3", - "ember-cli-htmlbars": "^2.0.1", - "ember-cli-htmlbars-inline-precompile": "^0.4.3", - "ember-cli-inject-live-reload": "^1.4.1", - "ember-cli-internal-test-helpers": "^0.8.1", + "ember-cli-htmlbars": "^3.0.0", + "ember-cli-htmlbars-inline-precompile": "^1.0.3", + "ember-cli-inject-live-reload": "^1.8.2", + "ember-cli-internal-test-helpers": "^0.9.1", "ember-cli-pretender": "^1.0.1", "ember-cli-release": "^0.2.9", - "ember-cli-shims": "^1.0.2", - "ember-cli-sri": "^2.1.0", + "ember-cli-shims": "^1.2.0", + "ember-cli-sri": "^2.1.1", "ember-cli-test-loader": "^2.2.0", - "ember-cli-uglify": "2.0.0-beta.1", + "ember-cli-uglify": "2.1.0", "ember-cli-yuidoc": "^0.8.8", - "ember-decorators": "^2.1.0", - "ember-disable-prototype-extensions": "^1.1.0", + "ember-decorators": "^2.3.1", + "ember-disable-prototype-extensions": "^1.1.3", "ember-disable-proxy-controllers": "^1.0.1", "ember-export-application-global": "^2.0.0", "ember-load-initializers": "^1.1.0", "ember-maybe-import-regenerator": "^0.1.6", "ember-publisher": "0.0.7", - "ember-qunit": "^3.4.0", + "ember-qunit": "^3.4.1", "ember-qunit-assert-helpers": "^0.2.1", - "ember-resolver": "^4.1.0", + "ember-resolver": "^5.0.1", "ember-source": "~3.0.0", - "ember-source-channel-url": "^1.0.1", + "ember-source-channel-url": "^1.1.0", "ember-try": "^0.2.23", - "ember-watson": "^0.7.0", + "ember-watson": "^0.9.1", "eslint-config-prettier": "^2.9.0", - "eslint-plugin-node": "^6.0.1", - "eslint-plugin-prettier": "2.6.0", - "fs-extra": "^6.0.1", + "eslint-plugin-node": "^7.0.1", + "eslint-plugin-prettier": "2.6.2", + "fs-extra": "^7.0.0", "github": "^1.1.1", - "glob": "^5.0.13", - "loader.js": "^4.5.0", - "mocha": "^2.4.5", - "mocha-only-detector": "0.0.2", + "glob": "^7.1.2", + "loader.js": "^4.7.0", + "mocha": "^5.2.0", + "mocha-only-detector": "1.0.0", "prettier": "^1.14.0", - "rimraf": "2.5.2", - "rsvp": "4.8.0", - "testdouble": "^3.2.6", - "testem": "^1.15.0" + "rimraf": "2.6.2", + "rsvp": "4.8.3", + "testdouble": "^3.8.1", + "testem": "^2.9.2" }, "engines": { "node": ">= 6.0.0" diff --git a/yarn.lock b/yarn.lock index c9e11b01ad1..537d0dcce1c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -78,63 +78,63 @@ lodash "^4.2.0" to-fast-properties "^2.0.0" -"@ember-decorators/babel-transforms@^2.0.0": - version "2.0.1" - resolved "https://registry.npmjs.org/@ember-decorators/babel-transforms/-/babel-transforms-2.0.1.tgz#75b668cfe996fa920c940ad723be015cddf904db" +"@ember-decorators/babel-transforms@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@ember-decorators/babel-transforms/-/babel-transforms-2.0.2.tgz#f73b4af32bc9aa2253cc8d2e72b984ab85e432db" dependencies: babel-plugin-transform-class-properties "^6.24.1" babel-plugin-transform-decorators-legacy "^1.3.4" ember-cli-babel "^6.6.0" ember-cli-version-checker "^2.1.0" -"@ember-decorators/component@^2.1.0": - version "2.1.0" - resolved "https://registry.npmjs.org/@ember-decorators/component/-/component-2.1.0.tgz#846ad4197a06c9814d02654e947c023d35107cee" +"@ember-decorators/component@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@ember-decorators/component/-/component-2.3.1.tgz#4e692c78f4ce69ba107759e5f8e2ed59c55dc232" dependencies: - "@ember-decorators/utils" "^2.1.0" + "@ember-decorators/utils" "^2.3.1" ember-cli-babel "^6.6.0" -"@ember-decorators/controller@^2.1.0": - version "2.1.0" - resolved "https://registry.npmjs.org/@ember-decorators/controller/-/controller-2.1.0.tgz#57a7be3d4eaa18e5021096d404417b1b943e7124" +"@ember-decorators/controller@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@ember-decorators/controller/-/controller-2.3.1.tgz#0b64320b037d413d5a351129fb1269e0b9f955f8" dependencies: - "@ember-decorators/utils" "^2.1.0" + "@ember-decorators/utils" "^2.3.1" ember-cli-babel "^6.6.0" -"@ember-decorators/data@^2.1.0": - version "2.1.0" - resolved "https://registry.npmjs.org/@ember-decorators/data/-/data-2.1.0.tgz#df29cc4bb21b7f246a02f810e2c7b56bd6f25294" +"@ember-decorators/data@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@ember-decorators/data/-/data-2.3.1.tgz#a2f28a56f0190217b863846808fbee9ec14c2fd9" dependencies: - "@ember-decorators/utils" "^2.1.0" + "@ember-decorators/utils" "^2.3.1" ember-cli-babel "^6.6.0" -"@ember-decorators/object@^2.1.0": - version "2.1.0" - resolved "https://registry.npmjs.org/@ember-decorators/object/-/object-2.1.0.tgz#725c790c030299a4bc8c15f21048c3c0abc1499c" +"@ember-decorators/object@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@ember-decorators/object/-/object-2.3.1.tgz#1886911154a58e1d5e5bd1be883249d05d52c918" dependencies: - "@ember-decorators/utils" "^2.1.0" + "@ember-decorators/utils" "^2.3.1" ember-cli-babel "^6.6.0" ember-compatibility-helpers "^1.0.0" -"@ember-decorators/service@^2.1.0": - version "2.1.0" - resolved "https://registry.npmjs.org/@ember-decorators/service/-/service-2.1.0.tgz#c6bbfd34fbb9fb19317ab2be351d8577701e5315" +"@ember-decorators/service@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@ember-decorators/service/-/service-2.3.1.tgz#84734f22ba295929ba5d506971535358e9e2a432" dependencies: - "@ember-decorators/utils" "^2.1.0" + "@ember-decorators/utils" "^2.3.1" ember-cli-babel "^6.6.0" -"@ember-decorators/utils@^2.1.0": - version "2.1.0" - resolved "https://registry.npmjs.org/@ember-decorators/utils/-/utils-2.1.0.tgz#cd354ff59ce0d5faa74880c15db0f72fefe6dc70" +"@ember-decorators/utils@^2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@ember-decorators/utils/-/utils-2.3.1.tgz#1da06a8f11062b0176dac5b427b27b4eabff3604" dependencies: ember-cli-babel "^6.6.0" ember-compatibility-helpers "^1.0.0" -"@ember/ordered-set@^1.0.0": - version "1.0.1" - resolved "https://registry.npmjs.org/@ember/ordered-set/-/ordered-set-1.0.1.tgz#f1a8c731168fb0ce25f868118ffef266ace29bac" +"@ember/ordered-set@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@ember/ordered-set/-/ordered-set-2.0.0.tgz#54f34aba3a1fb75b7c2912a39ab41a4a2e9d266d" dependencies: - ember-cli-babel "6.12.0" + ember-cli-babel "^6.16.0" ember-compatibility-helpers "^1.0.0" "@ember/test-helpers@^0.7.18": @@ -181,13 +181,6 @@ abbrev@1: version "1.1.1" resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" -accepts@1.3.3: - version "1.3.3" - resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" - dependencies: - mime-types "~2.1.11" - negotiator "0.6.1" - accepts@~1.3.4, accepts@~1.3.5: version "1.3.5" resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" @@ -215,10 +208,6 @@ acorn@^5.0.0, acorn@^5.2.1, acorn@^5.5.0, acorn@^5.5.3: version "5.7.1" resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" -after@0.8.1: - version "0.8.1" - resolved "https://registry.npmjs.org/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" - after@0.8.2: version "0.8.2" resolved "https://registry.npmjs.org/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" @@ -257,12 +246,6 @@ alter@~0.2.0: dependencies: stable "~0.1.3" -amd-name-resolver@0.0.7: - version "0.0.7" - resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-0.0.7.tgz#814301adfe8a2f109f6e84d5e935196efb669615" - dependencies: - ensure-posix-path "^1.0.1" - amd-name-resolver@1.2.0, amd-name-resolver@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz#fc41b3848824b557313897d71f8d5a0184fbe679" @@ -299,6 +282,10 @@ ansi-styles@^3.0.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +ansi-styles@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" + ansicolors@~0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" @@ -398,10 +385,6 @@ array-unique@^0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" -arraybuffer.slice@0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca" - arraybuffer.slice@~0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" @@ -430,6 +413,10 @@ ast-traverse@~0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" +ast-types@0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.1.tgz#f52fca9715579a14f841d67d7f8d25432ab6a3dd" + ast-types@0.8.12: version "0.8.12" resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" @@ -469,7 +456,7 @@ async-promise-queue@^1.0.3, async-promise-queue@^1.0.4: async "^2.4.1" debug "^2.6.8" -async@^1.4.0, async@^1.5.2: +async@^1.4.0, async@^1.5.0, async@^1.5.2: version "1.5.2" resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -517,7 +504,7 @@ babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-core@^5.0.0, babel-core@^5.8.22: +babel-core@^5, babel-core@^5.0.0, babel-core@^5.8.22: version "5.8.38" resolved "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" dependencies: @@ -592,15 +579,15 @@ babel-core@^6.26.0: slash "^1.0.0" source-map "^0.5.7" -babel-eslint@^8.0.0: - version "8.2.5" - resolved "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.5.tgz#dc2331c259d36782aa189da510c43dedd5adc7a3" +babel-eslint@^8.2.6: + version "8.2.6" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.6.tgz#6270d0c73205628067c0f7ae1693a9e797acefd9" dependencies: "@babel/code-frame" "7.0.0-beta.44" "@babel/traverse" "7.0.0-beta.44" "@babel/types" "7.0.0-beta.44" babylon "7.0.0-beta.44" - eslint-scope "~3.7.1" + eslint-scope "3.7.1" eslint-visitor-keys "^1.0.0" babel-generator@^6.26.0: @@ -616,6 +603,14 @@ babel-generator@^6.26.0: source-map "^0.5.7" trim-right "^1.0.1" +babel-helper-bindify-decorators@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" @@ -650,6 +645,15 @@ babel-helper-explode-assignable-expression@^6.24.1: babel-traverse "^6.24.1" babel-types "^6.24.1" +babel-helper-explode-class@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" + dependencies: + babel-helper-bindify-decorators "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + babel-helper-function-name@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" @@ -749,15 +753,9 @@ babel-plugin-debug-macros@^0.2.0-beta.6: dependencies: semver "^5.3.0" -babel-plugin-ember-modules-api-polyfill@^1.4.2: - version "1.6.0" - resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-1.6.0.tgz#abd1afa4237b3121cb51222f9bf3283cad8990aa" - dependencies: - ember-rfc176-data "^0.2.0" - -babel-plugin-ember-modules-api-polyfill@^2.3.0: +babel-plugin-ember-modules-api-polyfill@^2.3.0, babel-plugin-ember-modules-api-polyfill@^2.3.2: version "2.3.2" - resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.3.2.tgz#56ea34bea963498d070a2b7dc2ce18a92c434093" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.3.2.tgz#56ea34bea963498d070a2b7dc2ce18a92c434093" dependencies: ember-rfc176-data "^0.3.0" @@ -773,7 +771,7 @@ babel-plugin-filter-imports@^0.3.1: version "0.3.1" resolved "https://registry.npmjs.org/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.3.1.tgz#e7859b56886b175dd2616425d277b219e209ea8b" -babel-plugin-htmlbars-inline-precompile@^0.2.3, babel-plugin-htmlbars-inline-precompile@^0.2.5: +babel-plugin-htmlbars-inline-precompile@^0.2.5: version "0.2.5" resolved "https://registry.npmjs.org/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.5.tgz#7a7c37cf22c73fb57a1f828c76520f0360c5c5f3" @@ -823,23 +821,55 @@ babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" +babel-plugin-syntax-async-generators@^6.5.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" + +babel-plugin-syntax-class-constructor-call@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" + babel-plugin-syntax-class-properties@^6.8.0: version "6.13.0" resolved "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" -babel-plugin-syntax-decorators@^6.1.18: +babel-plugin-syntax-decorators@^6.1.18, babel-plugin-syntax-decorators@^6.13.0: version "6.13.0" resolved "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" +babel-plugin-syntax-export-extensions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" + +babel-plugin-syntax-flow@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" + +babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" resolved "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" -babel-plugin-transform-async-to-generator@^6.22.0: +babel-plugin-transform-async-generator-functions@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-generators "^6.5.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" dependencies: @@ -847,6 +877,14 @@ babel-plugin-transform-async-to-generator@^6.22.0: babel-plugin-syntax-async-functions "^6.8.0" babel-runtime "^6.22.0" +babel-plugin-transform-class-constructor-call@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9" + dependencies: + babel-plugin-syntax-class-constructor-call "^6.18.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-plugin-transform-class-properties@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" @@ -864,6 +902,16 @@ babel-plugin-transform-decorators-legacy@^1.3.4: babel-runtime "^6.2.0" babel-template "^6.3.0" +babel-plugin-transform-decorators@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d" + dependencies: + babel-helper-explode-class "^6.24.1" + babel-plugin-syntax-decorators "^6.13.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-types "^6.24.1" + babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" @@ -876,7 +924,7 @@ babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1: +babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1, babel-plugin-transform-es2015-block-scoping@^6.26.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" dependencies: @@ -886,7 +934,7 @@ babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es20 babel-types "^6.26.0" lodash "^4.17.4" -babel-plugin-transform-es2015-classes@^6.23.0: +babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-classes@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" dependencies: @@ -900,7 +948,7 @@ babel-plugin-transform-es2015-classes@^6.23.0: babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-computed-properties@^6.22.0: +babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transform-es2015-computed-properties@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" dependencies: @@ -913,26 +961,26 @@ babel-plugin-transform-es2015-constants@^6.1.4: dependencies: babel-runtime "^5.0.0" -babel-plugin-transform-es2015-destructuring@^6.23.0: +babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es2015-destructuring@^6.23.0: version "6.23.0" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-duplicate-keys@^6.22.0: +babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2015-duplicate-keys@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-plugin-transform-es2015-for-of@^6.23.0: +babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.23.0: version "6.23.0" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-function-name@^6.22.0: +babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es2015-function-name@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" dependencies: @@ -963,7 +1011,7 @@ babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-e babel-template "^6.26.0" babel-types "^6.26.0" -babel-plugin-transform-es2015-modules-systemjs@^6.23.0: +babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-es2015-modules-systemjs@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" dependencies: @@ -971,7 +1019,7 @@ babel-plugin-transform-es2015-modules-systemjs@^6.23.0: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-modules-umd@^6.23.0: +babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015-modules-umd@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" dependencies: @@ -979,14 +1027,14 @@ babel-plugin-transform-es2015-modules-umd@^6.23.0: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-object-super@^6.22.0: +babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es2015-object-super@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" dependencies: babel-helper-replace-supers "^6.24.1" babel-runtime "^6.22.0" -babel-plugin-transform-es2015-parameters@^6.23.0: +babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015-parameters@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" dependencies: @@ -997,7 +1045,7 @@ babel-plugin-transform-es2015-parameters@^6.23.0: babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-shorthand-properties@^6.22.0: +babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transform-es2015-shorthand-properties@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" dependencies: @@ -1010,7 +1058,7 @@ babel-plugin-transform-es2015-spread@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-sticky-regex@^6.22.0: +babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es2015-sticky-regex@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" dependencies: @@ -1024,13 +1072,13 @@ babel-plugin-transform-es2015-template-literals@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-typeof-symbol@^6.23.0: +babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es2015-typeof-symbol@^6.23.0: version "6.23.0" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-unicode-regex@^6.22.0: +babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es2015-unicode-regex@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" dependencies: @@ -1038,7 +1086,7 @@ babel-plugin-transform-es2015-unicode-regex@^6.22.0: babel-runtime "^6.22.0" regexpu-core "^2.0.0" -babel-plugin-transform-exponentiation-operator@^6.22.0: +babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" dependencies: @@ -1046,7 +1094,28 @@ babel-plugin-transform-exponentiation-operator@^6.22.0: babel-plugin-syntax-exponentiation-operator "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-regenerator@^6.22.0: +babel-plugin-transform-export-extensions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" + dependencies: + babel-plugin-syntax-export-extensions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-flow-strip-types@^6.8.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" + dependencies: + babel-plugin-syntax-flow "^6.18.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-object-rest-spread@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.26.0" + +babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.24.1: version "6.26.0" resolved "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" dependencies: @@ -1069,7 +1138,7 @@ babel-plugin-undefined-to-void@^1.1.6: version "1.1.6" resolved "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" -babel-polyfill@^6.16.0, babel-polyfill@^6.26.0: +babel-polyfill@^6.26.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" dependencies: @@ -1077,7 +1146,7 @@ babel-polyfill@^6.16.0, babel-polyfill@^6.26.0: core-js "^2.5.0" regenerator-runtime "^0.10.5" -babel-preset-env@^1.5.1, babel-preset-env@^1.7.0: +babel-preset-env@^1.7.0: version "1.7.0" resolved "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" dependencies: @@ -1112,7 +1181,63 @@ babel-preset-env@^1.5.1, babel-preset-env@^1.7.0: invariant "^2.2.2" semver "^5.3.0" -babel-register@^6.26.0: +babel-preset-es2015@^6.9.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.24.1" + babel-plugin-transform-es2015-classes "^6.24.1" + babel-plugin-transform-es2015-computed-properties "^6.24.1" + babel-plugin-transform-es2015-destructuring "^6.22.0" + babel-plugin-transform-es2015-duplicate-keys "^6.24.1" + babel-plugin-transform-es2015-for-of "^6.22.0" + babel-plugin-transform-es2015-function-name "^6.24.1" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-plugin-transform-es2015-modules-systemjs "^6.24.1" + babel-plugin-transform-es2015-modules-umd "^6.24.1" + babel-plugin-transform-es2015-object-super "^6.24.1" + babel-plugin-transform-es2015-parameters "^6.24.1" + babel-plugin-transform-es2015-shorthand-properties "^6.24.1" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.24.1" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.22.0" + babel-plugin-transform-es2015-unicode-regex "^6.24.1" + babel-plugin-transform-regenerator "^6.24.1" + +babel-preset-stage-1@^6.5.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz#7692cd7dcd6849907e6ae4a0a85589cfb9e2bfb0" + dependencies: + babel-plugin-transform-class-constructor-call "^6.24.1" + babel-plugin-transform-export-extensions "^6.22.0" + babel-preset-stage-2 "^6.24.1" + +babel-preset-stage-2@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-plugin-transform-class-properties "^6.24.1" + babel-plugin-transform-decorators "^6.24.1" + babel-preset-stage-3 "^6.24.1" + +babel-preset-stage-3@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395" + dependencies: + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-generator-functions "^6.24.1" + babel-plugin-transform-async-to-generator "^6.24.1" + babel-plugin-transform-exponentiation-operator "^6.24.1" + babel-plugin-transform-object-rest-spread "^6.22.0" + +babel-register@^6.26.0, babel-register@^6.9.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" dependencies: @@ -1186,7 +1311,7 @@ babylon@^5.8.38: version "5.8.38" resolved "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" -babylon@^6.18.0: +babylon@^6.17.3, babylon@^6.18.0: version "6.18.0" resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" @@ -1212,10 +1337,6 @@ base64-js@^1.0.2: version "1.3.0" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" -base64id@0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz#02ce0fdeee0cef4f40080e1e73e834f0b1bfce3f" - base64id@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" @@ -1346,9 +1467,16 @@ breakable@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" -broccoli-asset-rev@^2.4.5: +broccoli-amd-funnel@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/broccoli-amd-funnel/-/broccoli-amd-funnel-1.3.0.tgz#c4426b4fce976e44295bd74f34725f53bdeb08e3" + dependencies: + broccoli-plugin "^1.3.0" + symlink-or-copy "^1.2.0" + +broccoli-asset-rev@^2.7.0: version "2.7.0" - resolved "https://registry.npmjs.org/broccoli-asset-rev/-/broccoli-asset-rev-2.7.0.tgz#c73da1d97c4180366fa442a87624ca1b7fb99161" + resolved "https://registry.yarnpkg.com/broccoli-asset-rev/-/broccoli-asset-rev-2.7.0.tgz#c73da1d97c4180366fa442a87624ca1b7fb99161" dependencies: broccoli-asset-rewrite "^1.1.0" broccoli-filter "^1.2.2" @@ -1378,7 +1506,7 @@ broccoli-babel-transpiler@^5.6.2: rsvp "^3.5.0" workerpool "^2.3.0" -broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2, broccoli-babel-transpiler@^6.4.2, broccoli-babel-transpiler@^6.4.3: +broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.4.2: version "6.4.3" resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.4.3.tgz#06e399298d41700cdc10d675b1d808a89ef6b2d0" dependencies: @@ -1393,6 +1521,21 @@ broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.1.2, broccoli-bab rsvp "^4.8.2" workerpool "^2.3.0" +broccoli-babel-transpiler@^6.4.5, broccoli-babel-transpiler@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.5.0.tgz#aa501a227b298a99742fdd0309b1eaad7124bba0" + dependencies: + babel-core "^6.26.0" + broccoli-funnel "^2.0.1" + broccoli-merge-trees "^2.0.0" + broccoli-persistent-filter "^1.4.3" + clone "^2.0.0" + hash-for-dep "^1.2.3" + heimdalljs-logger "^0.1.7" + json-stable-stringify "^1.0.0" + rsvp "^4.8.2" + workerpool "^2.3.0" + broccoli-builder@^0.18.8: version "0.18.14" resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.14.tgz#4b79e2f844de11a4e1b816c3f49c6df4776c312d" @@ -1466,6 +1609,23 @@ broccoli-concat@^3.2.2: lodash.uniq "^4.2.0" walk-sync "^0.3.1" +broccoli-concat@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.5.1.tgz#25d5bff467e451a03ae2a93b3fc8701b3955a732" + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-plugin "^1.3.0" + broccoli-stew "^1.5.0" + ensure-posix-path "^1.0.2" + fast-sourcemap-concat "^1.3.1" + find-index "^1.1.0" + fs-extra "^4.0.3" + fs-tree-diff "^0.5.7" + lodash.merge "^4.3.1" + lodash.omit "^4.1.0" + lodash.uniq "^4.2.0" + walk-sync "^0.3.2" + broccoli-config-loader@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/broccoli-config-loader/-/broccoli-config-loader-1.0.1.tgz#d10aaf8ebc0cb45c1da5baa82720e1d88d28c80a" @@ -1481,7 +1641,7 @@ broccoli-config-replace@^1.1.2: debug "^2.2.0" fs-extra "^0.24.0" -broccoli-debug@^0.6.1, broccoli-debug@^0.6.2, broccoli-debug@^0.6.3, broccoli-debug@^0.6.4: +broccoli-debug@^0.6.1, broccoli-debug@^0.6.3, broccoli-debug@^0.6.4: version "0.6.4" resolved "https://registry.npmjs.org/broccoli-debug/-/broccoli-debug-0.6.4.tgz#986eb3d2005e00e3bb91f9d0a10ab137210cd150" dependencies: @@ -1492,13 +1652,20 @@ broccoli-debug@^0.6.1, broccoli-debug@^0.6.2, broccoli-debug@^0.6.3, broccoli-de symlink-or-copy "^1.1.8" tree-sync "^1.2.2" -broccoli-file-creator@^1.0.0, broccoli-file-creator@^1.1.1: +broccoli-file-creator@^1.1.1: version "1.2.0" resolved "https://registry.npmjs.org/broccoli-file-creator/-/broccoli-file-creator-1.2.0.tgz#27f1b25b1b00e7bb7bf3d5d7abed5f4d5388df4d" dependencies: broccoli-plugin "^1.1.0" mkdirp "^0.5.1" +broccoli-file-creator@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-2.1.1.tgz#7351dd2496c762cfce7736ce9b49e3fce0c7b7db" + dependencies: + broccoli-plugin "^1.1.0" + mkdirp "^0.5.1" + broccoli-filter@^1.0.1, broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: version "1.3.0" resolved "https://registry.npmjs.org/broccoli-filter/-/broccoli-filter-1.3.0.tgz#71e3a8e32a17f309e12261919c5b1006d6766de6" @@ -1600,6 +1767,13 @@ broccoli-merge-trees@^2.0.0: broccoli-plugin "^1.3.0" merge-trees "^1.0.1" +broccoli-merge-trees@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-3.0.0.tgz#90e4959f9e3c57cf1f04fab35152f3d849468d8b" + dependencies: + broccoli-plugin "^1.3.0" + merge-trees "^2.0.0" + broccoli-middleware@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-1.2.1.tgz#a21f255f8bfe5a21c2f0fbf2417addd9d24c9436" @@ -1607,11 +1781,28 @@ broccoli-middleware@^1.2.1: handlebars "^4.0.4" mime-types "^2.1.18" +broccoli-module-normalizer@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/broccoli-module-normalizer/-/broccoli-module-normalizer-1.3.0.tgz#f9982d9cbb776b4ed754161cc6547784d3eb19de" + dependencies: + broccoli-plugin "^1.3.0" + merge-trees "^1.0.1" + rimraf "^2.6.2" + symlink-or-copy "^1.1.8" + +broccoli-module-unification-reexporter@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/broccoli-module-unification-reexporter/-/broccoli-module-unification-reexporter-1.0.0.tgz#031909c5d3f159ec11d5f9e2346f2861db8acb3e" + dependencies: + broccoli-plugin "^1.3.0" + mkdirp "^0.5.1" + walk-sync "^0.3.2" + broccoli-node-info@1.1.0, broccoli-node-info@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" -broccoli-persistent-filter@^1.0.3, broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.4.2, broccoli-persistent-filter@^1.4.3: +broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.4.2, broccoli-persistent-filter@^1.4.3: version "1.4.3" resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz#3511bc52fc53740cda51621f58a28152d9911bc1" dependencies: @@ -1647,9 +1838,9 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli rimraf "^2.3.4" symlink-or-copy "^1.1.8" -broccoli-rollup@^2.1.0: +broccoli-rollup@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/broccoli-rollup/-/broccoli-rollup-2.1.1.tgz#0b77dc4b7560a53e998ea85f3b56772612d4988d" + resolved "https://registry.yarnpkg.com/broccoli-rollup/-/broccoli-rollup-2.1.1.tgz#0b77dc4b7560a53e998ea85f3b56772612d4988d" dependencies: "@types/node" "^9.6.0" amd-name-resolver "^1.2.0" @@ -1687,7 +1878,7 @@ broccoli-sri-hash@^2.1.0: sri-toolbox "^0.2.0" symlink-or-copy "^1.0.1" -broccoli-stew@^1.2.0, broccoli-stew@^1.3.3, broccoli-stew@^1.4.2: +broccoli-stew@^1.2.0, broccoli-stew@^1.3.3: version "1.5.0" resolved "https://registry.npmjs.org/broccoli-stew/-/broccoli-stew-1.5.0.tgz#d7af8c18511dce510e49d308a62e5977f461883c" dependencies: @@ -1706,16 +1897,54 @@ broccoli-stew@^1.2.0, broccoli-stew@^1.3.3, broccoli-stew@^1.4.2: symlink-or-copy "^1.1.8" walk-sync "^0.3.0" -broccoli-string-replace@^0.1.1: +broccoli-stew@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-1.6.0.tgz#01f6d92806ed6679ddbe48d405066a0e164dfbef" + dependencies: + broccoli-debug "^0.6.1" + broccoli-funnel "^2.0.0" + broccoli-merge-trees "^2.0.0" + broccoli-persistent-filter "^1.1.6" + broccoli-plugin "^1.3.0" + chalk "^2.4.1" + debug "^3.1.0" + ensure-posix-path "^1.0.1" + fs-extra "^5.0.0" + minimatch "^3.0.4" + resolve "^1.8.1" + rsvp "^4.8.3" + symlink-or-copy "^1.2.0" + walk-sync "^0.3.0" + +broccoli-stew@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-2.0.0.tgz#68f3d94f13b4a79aa15d582703574fb4c3215e50" + dependencies: + broccoli-debug "^0.6.1" + broccoli-funnel "^2.0.0" + broccoli-merge-trees "^3.0.0" + broccoli-persistent-filter "^1.1.6" + broccoli-plugin "^1.3.0" + chalk "^2.4.1" + debug "^3.1.0" + ensure-posix-path "^1.0.1" + fs-extra "^6.0.1" + minimatch "^3.0.4" + resolve "^1.8.1" + rsvp "^4.8.3" + symlink-or-copy "^1.2.0" + walk-sync "^0.3.0" + +broccoli-string-replace@^0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" + resolved "https://registry.yarnpkg.com/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" dependencies: broccoli-persistent-filter "^1.1.5" minimatch "^3.0.3" -broccoli-test-helper@^1.2.0: - version "1.3.0" - resolved "https://registry.npmjs.org/broccoli-test-helper/-/broccoli-test-helper-1.3.0.tgz#ba673418b3963b2cc466be66092a5928700c827f" +broccoli-test-helper@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/broccoli-test-helper/-/broccoli-test-helper-1.4.0.tgz#9c2f0529424d61536a68e410bf24e5a66b8f815c" dependencies: broccoli "^1.1.0" fixturify "^0.3.2" @@ -1724,23 +1953,9 @@ broccoli-test-helper@^1.2.0: rimraf "^2.5.4" walk-sync "^0.3.1" -broccoli-uglify-sourcemap@^1.0.1: - version "1.5.2" - resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-1.5.2.tgz#04f84ab0db539031fa868ccfa563c9932d50cedb" - dependencies: - broccoli-plugin "^1.2.1" - debug "^2.2.0" - lodash.merge "^4.5.1" - matcher-collection "^1.0.0" - mkdirp "^0.5.0" - source-map-url "^0.3.0" - symlink-or-copy "^1.0.1" - uglify-js "^2.7.0" - walk-sync "^0.1.3" - -broccoli-uglify-sourcemap@^2.0.0-beta.1: +broccoli-uglify-sourcemap@^2.1.1, broccoli-uglify-sourcemap@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-2.2.0.tgz#2ff49389bdf342a550c3596750ba2dde95a8f7d4" + resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-2.2.0.tgz#2ff49389bdf342a550c3596750ba2dde95a8f7d4" dependencies: async-promise-queue "^1.0.4" broccoli-plugin "^1.2.1" @@ -1774,6 +1989,10 @@ broccoli@^1.1.0: tmp "0.0.31" underscore.string "^3.2.2" +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + browserslist@^3.2.6: version "3.2.8" resolved "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" @@ -1953,14 +2172,22 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1: version "2.4.1" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" + dependencies: + ansi-styles "~1.0.0" + has-color "~0.1.0" + strip-ansi "~0.1.0" + chardet@^0.4.0: version "0.4.2" resolved "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" @@ -1994,6 +2221,10 @@ chownr@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" +ci-info@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" + circular-json@^0.3.1: version "0.3.3" resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" @@ -2026,6 +2257,10 @@ clean-css@^3.4.5: commander "2.8.x" source-map "0.4.x" +clean-up-path@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clean-up-path/-/clean-up-path-1.0.0.tgz#de9e8196519912e749c9eaf67c13d64fac72a3e5" + cli-cursor@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" @@ -2126,17 +2361,13 @@ combined-stream@~0.0.4: dependencies: delayed-stream "0.0.5" -commander@0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" - commander@2.12.2: version "2.12.2" resolved "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" -commander@2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" +commander@2.15.1, commander@^2.5.0, commander@^2.6.0: + version "2.15.1" + resolved "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" commander@2.8.x: version "2.8.1" @@ -2144,17 +2375,13 @@ commander@2.8.x: dependencies: graceful-readlink ">= 1.0.0" -commander@^2.5.0, commander@^2.6.0: - version "2.15.1" - resolved "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" - commander@~2.14.1: version "2.14.1" resolved "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" -common-tags@^1.4.0: +common-tags@^1.4.0, common-tags@^1.8.0: version "1.8.0" - resolved "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" commoner@~0.10.3: version "0.10.8" @@ -2174,10 +2401,6 @@ component-bind@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" -component-emitter@1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" - component-emitter@1.2.1, component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" @@ -2217,20 +2440,6 @@ concat-stream@^1.4.7, concat-stream@^1.6.0: readable-stream "^2.2.2" typedarray "^0.0.6" -configstore@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1" - dependencies: - dot-prop "^3.0.0" - graceful-fs "^4.1.2" - mkdirp "^0.5.0" - object-assign "^4.0.1" - os-tmpdir "^1.0.0" - osenv "^0.1.0" - uuid "^2.0.1" - write-file-atomic "^1.1.2" - xdg-basedir "^2.0.0" - configstore@^3.0.0: version "3.1.2" resolved "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" @@ -2255,9 +2464,9 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" -console-ui@^2.1.0: +console-ui@^2.2.2: version "2.2.2" - resolved "https://registry.npmjs.org/console-ui/-/console-ui-2.2.2.tgz#b294a2934de869dd06789ab4be69555411edef29" + resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-2.2.2.tgz#b294a2934de869dd06789ab4be69555411edef29" dependencies: chalk "^2.1.0" inquirer "^2" @@ -2266,12 +2475,6 @@ console-ui@^2.1.0: through "^2.3.8" user-info "^1.0.0" -consolidate@^0.14.0: - version "0.14.5" - resolved "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" - dependencies: - bluebird "^3.1.1" - consolidate@^0.15.1: version "0.15.1" resolved "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7" @@ -2314,7 +2517,7 @@ core-js@^1.0.0: version "1.2.7" resolved "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" -core-js@^2.4.0, core-js@^2.5.0: +core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0: version "2.5.7" resolved "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" @@ -2332,7 +2535,7 @@ core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -cross-spawn@^5.0.1, cross-spawn@^5.1.0: +cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -2392,19 +2595,7 @@ debug@2, debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.2, debug@^2.1.3, de dependencies: ms "2.0.0" -debug@2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" - dependencies: - ms "0.7.1" - -debug@2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" - dependencies: - ms "0.7.2" - -debug@^3.0.0, debug@^3.1.0, debug@~3.1.0: +debug@3.1.0, debug@^3.0.0, debug@^3.1.0, debug@~3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -2559,11 +2750,7 @@ detective@^4.3.1: acorn "^5.2.1" defined "^1.0.0" -diff@1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" - -diff@^3.2.0: +diff@3.5.0, diff@^3.2.0: version "3.5.0" resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -2573,12 +2760,6 @@ doctrine@^2.1.0: dependencies: esutils "^2.0.2" -dot-prop@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" - dependencies: - is-obj "^1.0.0" - dot-prop@^4.1.0: version "4.2.0" resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" @@ -2601,31 +2782,13 @@ electron-to-chromium@^1.3.47: version "1.3.50" resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.50.tgz#7438b76f92b41b919f3fbdd350fbd0757dacddf7" -ember-cli-app-version@^3.0.0: +ember-cli-app-version@^3.2.0: version "3.2.0" - resolved "https://registry.npmjs.org/ember-cli-app-version/-/ember-cli-app-version-3.2.0.tgz#7b9ad0e1b63ae0518648356ee24c703e922bc26e" + resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-3.2.0.tgz#7b9ad0e1b63ae0518648356ee24c703e922bc26e" dependencies: ember-cli-babel "^6.12.0" git-repo-version "^1.0.2" -ember-cli-babel@6.12.0: - version "6.12.0" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.12.0.tgz#3adcdbe1278da1fcd0b9038f1360cb4ac5d4414c" - dependencies: - amd-name-resolver "0.0.7" - babel-plugin-debug-macros "^0.1.11" - babel-plugin-ember-modules-api-polyfill "^2.3.0" - babel-plugin-transform-es2015-modules-amd "^6.24.0" - babel-polyfill "^6.16.0" - babel-preset-env "^1.5.1" - broccoli-babel-transpiler "^6.1.2" - broccoli-debug "^0.6.2" - broccoli-funnel "^1.0.0" - broccoli-source "^1.1.0" - clone "^2.0.0" - ember-cli-version-checker "^2.1.0" - semver "^5.4.1" - ember-cli-babel@^5.0.0: version "5.2.8" resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.8.tgz#0356b03cc3fdff5d0f2ecaa46a0e1cfaebffd876" @@ -2654,17 +2817,17 @@ ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-be ember-cli-version-checker "^2.1.2" semver "^5.5.0" -ember-cli-babel@^6.15.0: - version "6.15.0" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.15.0.tgz#86114b7e94afa058b02e59bfd85794c48cc56090" +ember-cli-babel@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.16.0.tgz#623b4a2764ece72b65f1572fc8aeb5714a450228" dependencies: amd-name-resolver "1.2.0" babel-plugin-debug-macros "^0.2.0-beta.6" - babel-plugin-ember-modules-api-polyfill "^2.3.0" + babel-plugin-ember-modules-api-polyfill "^2.3.2" babel-plugin-transform-es2015-modules-amd "^6.24.0" babel-polyfill "^6.26.0" babel-preset-env "^1.7.0" - broccoli-babel-transpiler "^6.4.2" + broccoli-babel-transpiler "^6.4.5" broccoli-debug "^0.6.4" broccoli-funnel "^2.0.0" broccoli-source "^1.1.0" @@ -2695,9 +2858,9 @@ ember-cli-broccoli-sane-watcher@^2.0.4: rsvp "^3.0.18" sane "^2.4.1" -ember-cli-dependency-checker@^2.1.0: - version "2.1.1" - resolved "https://registry.npmjs.org/ember-cli-dependency-checker/-/ember-cli-dependency-checker-2.1.1.tgz#0421f9ca53fe8b237a53575be7dbe36e88ac83a6" +ember-cli-dependency-checker@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-dependency-checker/-/ember-cli-dependency-checker-3.0.0.tgz#61245f5f79f881dece043303111d5f41efb8621f" dependencies: chalk "^2.3.0" find-yarn-workspace-root "^1.1.0" @@ -2718,18 +2881,9 @@ ember-cli-get-component-path-option@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" -ember-cli-htmlbars-inline-precompile@^0.4.3: - version "0.4.4" - resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-0.4.4.tgz#24a7617152630d64a047e553b72e00963a4f8d73" - dependencies: - babel-plugin-htmlbars-inline-precompile "^0.2.3" - ember-cli-version-checker "^2.0.0" - hash-for-dep "^1.0.2" - silent-error "^1.1.0" - -ember-cli-htmlbars-inline-precompile@^1.0.0: +ember-cli-htmlbars-inline-precompile@^1.0.0, ember-cli-htmlbars-inline-precompile@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.3.tgz#332ff96c06fc522965162f1090d78a615379c3c2" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.3.tgz#332ff96c06fc522965162f1090d78a615379c3c2" dependencies: babel-plugin-htmlbars-inline-precompile "^0.2.5" ember-cli-version-checker "^2.1.2" @@ -2737,36 +2891,20 @@ ember-cli-htmlbars-inline-precompile@^1.0.0: heimdalljs-logger "^0.1.9" silent-error "^1.1.0" -ember-cli-htmlbars@^2.0.1: - version "2.0.3" - resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-2.0.3.tgz#e116e1500dba12f29c94b05b9ec90f52cb8bb042" +ember-cli-htmlbars@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-3.0.0.tgz#4977b9eddbc725f8da25090ecdbba64533b2eadc" dependencies: - broccoli-persistent-filter "^1.0.3" - hash-for-dep "^1.0.2" + broccoli-persistent-filter "^1.4.3" + hash-for-dep "^1.2.3" json-stable-stringify "^1.0.0" strip-bom "^3.0.0" -ember-cli-inject-live-reload@^1.4.1: - version "1.7.0" - resolved "https://registry.npmjs.org/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.7.0.tgz#af94336e015336127dfb98080ad442bb233e37ed" - -ember-cli-internal-test-helpers@^0.8.1: - version "0.8.3" - resolved "https://registry.npmjs.org/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.8.3.tgz#e9b7db67f3fda4db736d1a319a282c04beada495" +ember-cli-inject-live-reload@^1.8.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.8.2.tgz#29f875ad921e9a1dec65d2d75018891972d240bc" dependencies: - chai "^3.3.0" - chai-as-promised "^6.0.0" - chai-files "^1.1.0" - chalk "^1.1.1" - configstore "^2.0.0" - debug "^2.2.0" - exists-sync "0.0.3" - fs-extra "^0.30.0" - lodash "^4.0.0" - rsvp "^3.0.17" - symlink-or-copy "^1.0.1" - through "^2.3.8" - walk-sync "^0.3.1" + clean-base-url "^1.0.0" ember-cli-internal-test-helpers@^0.9.1: version "0.9.1" @@ -2843,9 +2981,9 @@ ember-cli-release@^0.2.9: semver "^4.3.1" silent-error "^1.0.0" -ember-cli-shims@^1.0.2: +ember-cli-shims@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/ember-cli-shims/-/ember-cli-shims-1.2.0.tgz#0f53aff0aab80b5f29da3a9731bac56169dd941f" + resolved "https://registry.yarnpkg.com/ember-cli-shims/-/ember-cli-shims-1.2.0.tgz#0f53aff0aab80b5f29da3a9731bac56169dd941f" dependencies: broccoli-file-creator "^1.1.1" broccoli-merge-trees "^2.0.0" @@ -2853,9 +2991,9 @@ ember-cli-shims@^1.0.2: ember-rfc176-data "^0.3.1" silent-error "^1.0.1" -ember-cli-sri@^2.1.0: +ember-cli-sri@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" + resolved "https://registry.yarnpkg.com/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" dependencies: broccoli-sri-hash "^2.1.0" @@ -2875,11 +3013,11 @@ ember-cli-test-loader@^2.2.0: dependencies: ember-cli-babel "^6.8.1" -ember-cli-uglify@2.0.0-beta.1: - version "2.0.0-beta.1" - resolved "https://registry.npmjs.org/ember-cli-uglify/-/ember-cli-uglify-2.0.0-beta.1.tgz#9cb509f7f3f3342271df4a59b41176f0ffbda48a" +ember-cli-uglify@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ember-cli-uglify/-/ember-cli-uglify-2.1.0.tgz#4a0641fe4768d7ab7d4807aca9924cc77c544184" dependencies: - broccoli-uglify-sourcemap "^2.0.0-beta.1" + broccoli-uglify-sourcemap "^2.1.1" lodash.defaultsdeep "^4.6.0" ember-cli-valid-component-name@^1.0.0: @@ -2911,14 +3049,15 @@ ember-cli-yuidoc@^0.8.8: rsvp "3.0.14" yuidocjs "^0.10.0" -ember-cli@^3.1.4: - version "3.1.4" - resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-3.1.4.tgz#95f7ff4302d535619b5d5ff1c7040877a67d4468" +ember-cli@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-3.3.0.tgz#534ebe72453a4fb064a34077a0874ad69ea84be4" dependencies: amd-name-resolver "^1.2.0" babel-plugin-transform-es2015-modules-amd "^6.24.0" bower-config "^1.3.0" bower-endpoint-parser "0.2.2" + broccoli-amd-funnel "^1.3.0" broccoli-babel-transpiler "^6.0.0" broccoli-builder "^0.18.8" broccoli-concat "^3.2.2" @@ -2929,15 +3068,18 @@ ember-cli@^3.1.4: broccoli-funnel-reducer "^1.0.0" broccoli-merge-trees "^2.0.0" broccoli-middleware "^1.2.1" + broccoli-module-normalizer "^1.3.0" + broccoli-module-unification-reexporter "^1.0.0" broccoli-source "^1.1.0" broccoli-stew "^1.2.0" calculate-cache-key-for-tree "^1.0.0" capture-exit "^1.1.0" chalk "^2.0.1" + ci-info "^1.1.2" clean-base-url "^1.0.0" compression "^1.4.4" configstore "^3.0.0" - console-ui "^2.1.0" + console-ui "^2.2.2" core-object "^3.1.3" dag-map "^2.0.2" diff "^3.2.0" @@ -2948,8 +3090,7 @@ ember-cli@^3.1.4: ember-cli-preprocess-registry "^3.1.0" ember-cli-string-utils "^1.0.0" ensure-posix-path "^1.0.2" - execa "^0.9.0" - exists-sync "0.0.4" + execa "^0.10.0" exit "^0.1.2" express "^4.12.3" filesize "^3.1.3" @@ -2958,7 +3099,7 @@ ember-cli@^3.1.4: fs-extra "^5.0.0" fs-tree-diff "^0.5.2" get-caller-file "^1.0.0" - git-repo-info "^1.4.1" + git-repo-info "^2.0.0" glob "^7.1.2" heimdalljs "^0.2.3" heimdalljs-fs-monitor "^0.2.0" @@ -2988,9 +3129,9 @@ ember-cli@^3.1.4: semver "^5.1.1" silent-error "^1.0.0" sort-package-json "^1.4.0" - symlink-or-copy "^1.1.8" + symlink-or-copy "^1.2.0" temp "0.8.3" - testem "^2.0.0" + testem "^2.2.0" tiny-lr "^1.0.3" tree-sync "^1.2.1" uuid "^3.0.0" @@ -3007,21 +3148,21 @@ ember-compatibility-helpers@^1.0.0: ember-cli-version-checker "^2.1.1" semver "^5.4.1" -ember-decorators@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/ember-decorators/-/ember-decorators-2.1.0.tgz#4910835da3517c633532c8d6fcfcf026e13701c0" +ember-decorators@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/ember-decorators/-/ember-decorators-2.3.1.tgz#aef98f6a3e15666bd414576d07cbfc15d39cfe97" dependencies: - "@ember-decorators/component" "^2.1.0" - "@ember-decorators/controller" "^2.1.0" - "@ember-decorators/data" "^2.1.0" - "@ember-decorators/object" "^2.1.0" - "@ember-decorators/service" "^2.1.0" + "@ember-decorators/component" "^2.3.1" + "@ember-decorators/controller" "^2.3.1" + "@ember-decorators/data" "^2.3.1" + "@ember-decorators/object" "^2.3.1" + "@ember-decorators/service" "^2.3.1" ember-cli-babel "^6.0.0" semver "^5.5.0" -ember-disable-prototype-extensions@^1.1.0: +ember-disable-prototype-extensions@^1.1.3: version "1.1.3" - resolved "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" + resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" ember-disable-proxy-controllers@^1.0.1: version "1.0.1" @@ -3041,6 +3182,13 @@ ember-inflector@^3.0.0: dependencies: ember-cli-babel "^6.6.0" +ember-k-codemod@^0.1.0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/ember-k-codemod/-/ember-k-codemod-0.1.7.tgz#c35bd6016e3d7cdac1325f86fa9f75f2eef338c3" + dependencies: + glob "^7.1.1" + jscodeshift "^0.3.29" + ember-load-initializers@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/ember-load-initializers/-/ember-load-initializers-1.1.0.tgz#4edacc0f3a14d9f53d241ac3e5561804c8377978" @@ -3069,9 +3217,9 @@ ember-qunit-assert-helpers@^0.2.1: broccoli-filter "^1.0.1" ember-cli-babel "^6.9.0" -ember-qunit@^3.4.0: +ember-qunit@^3.4.1: version "3.4.1" - resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-3.4.1.tgz#204a2d39a5d44d494c56bf17cf3fd12f06210359" + resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-3.4.1.tgz#204a2d39a5d44d494c56bf17cf3fd12f06210359" dependencies: "@ember/test-helpers" "^0.7.18" broccoli-funnel "^2.0.1" @@ -3081,22 +3229,18 @@ ember-qunit@^3.4.0: ember-cli-test-loader "^2.2.0" qunit "^2.5.0" -ember-resolver@^4.1.0: - version "4.5.6" - resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-4.5.6.tgz#61cecc683fbe3464d759e6d0c2bab97b3914ee4b" +ember-resolver@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-5.0.1.tgz#21740b92e1e4a65f94018de22aa1c73434dc3b2f" dependencies: "@glimmer/resolver" "^0.4.1" babel-plugin-debug-macros "^0.1.10" - broccoli-funnel "^1.1.0" - broccoli-merge-trees "^2.0.0" + broccoli-funnel "^2.0.1" + broccoli-merge-trees "^3.0.0" ember-cli-babel "^6.8.1" ember-cli-version-checker "^2.0.0" resolve "^1.3.3" -ember-rfc176-data@^0.2.0: - version "0.2.7" - resolved "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.2.7.tgz#bd355bc9b473e08096b518784170a23388bc973b" - ember-rfc176-data@^0.3.0, ember-rfc176-data@^0.3.1: version "0.3.3" resolved "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.3.3.tgz#27fba08d540a7463a4366c48eaa19c5a44971a39" @@ -3107,16 +3251,16 @@ ember-router-generator@^1.2.3: dependencies: recast "^0.11.3" -ember-runtime-enumerable-includes-polyfill@^2.0.0: +ember-runtime-enumerable-includes-polyfill@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-2.1.0.tgz#dc6d4a028471e4acc350dfd2a149874fb20913f5" + resolved "https://registry.yarnpkg.com/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-2.1.0.tgz#dc6d4a028471e4acc350dfd2a149874fb20913f5" dependencies: ember-cli-babel "^6.9.0" ember-cli-version-checker "^2.1.0" -ember-source-channel-url@^1.0.1: +ember-source-channel-url@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/ember-source-channel-url/-/ember-source-channel-url-1.1.0.tgz#73de5cc6ebc25b2120e932ec1d8f82677bfaf6ef" + resolved "https://registry.yarnpkg.com/ember-source-channel-url/-/ember-source-channel-url-1.1.0.tgz#73de5cc6ebc25b2120e932ec1d8f82677bfaf6ef" dependencies: got "^8.0.1" @@ -3164,13 +3308,14 @@ ember-try@^0.2.23: rsvp "^3.0.17" semver "^5.1.0" -ember-watson@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/ember-watson/-/ember-watson-0.7.0.tgz#e7243ba128fb39a6205cddb61774043d093c5163" +ember-watson@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/ember-watson/-/ember-watson-0.9.1.tgz#77ad64740c339b21d52fffd4487fca7c84173109" dependencies: babel-core "^5.8.22" chalk "^1.0.0" commander "^2.6.0" + ember-k-codemod "^0.1.0" exists-sync "0.0.3" inflected "^1.1.6" recast "^0.10.29" @@ -3186,23 +3331,6 @@ encoding@^0.1.11: dependencies: iconv-lite "~0.4.13" -engine.io-client@1.8.0: - version "1.8.0" - resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.0.tgz#7b730e4127414087596d9be3c88d2bc5fdb6cf5c" - dependencies: - component-emitter "1.2.1" - component-inherit "0.0.3" - debug "2.3.3" - engine.io-parser "1.3.1" - has-cors "1.1.0" - indexof "0.0.1" - parsejson "0.0.3" - parseqs "0.0.5" - parseuri "0.0.5" - ws "1.1.1" - xmlhttprequest-ssl "1.5.3" - yeast "0.1.2" - engine.io-client@~3.2.0: version "3.2.1" resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" @@ -3219,17 +3347,6 @@ engine.io-client@~3.2.0: xmlhttprequest-ssl "~1.5.4" yeast "0.1.2" -engine.io-parser@1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.1.tgz#9554f1ae33107d6fbd170ca5466d2f833f6a07cf" - dependencies: - after "0.8.1" - arraybuffer.slice "0.0.6" - base64-arraybuffer "0.1.5" - blob "0.0.4" - has-binary "0.1.6" - wtf-8 "1.0.0" - engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: version "2.1.2" resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196" @@ -3240,17 +3357,6 @@ engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: blob "0.0.4" has-binary2 "~1.0.2" -engine.io@1.8.0: - version "1.8.0" - resolved "https://registry.npmjs.org/engine.io/-/engine.io-1.8.0.tgz#3eeb5f264cb75dbbec1baaea26d61f5a4eace2aa" - dependencies: - accepts "1.3.3" - base64id "0.1.0" - cookie "0.3.1" - debug "2.3.3" - engine.io-parser "1.3.1" - ws "1.1.1" - engine.io@~3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz#54332506f42f2edc71690d2f2a42349359f3bf7d" @@ -3331,11 +3437,7 @@ escape-html@~1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" -escape-string-regexp@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -3345,29 +3447,42 @@ eslint-config-prettier@^2.9.0: dependencies: get-stdin "^5.0.1" -eslint-plugin-node@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz#bf19642298064379315d7a4b2a75937376fa05e4" +eslint-plugin-es@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-1.3.1.tgz#5acb2565db4434803d1d46a9b4cbc94b345bd028" + dependencies: + eslint-utils "^1.3.0" + regexpp "^2.0.0" + +eslint-plugin-node@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-7.0.1.tgz#a6e054e50199b2edd85518b89b4e7b323c9f36db" dependencies: - ignore "^3.3.6" + eslint-plugin-es "^1.3.1" + eslint-utils "^1.3.1" + ignore "^4.0.2" minimatch "^3.0.4" - resolve "^1.3.3" - semver "^5.4.1" + resolve "^1.8.1" + semver "^5.5.0" -eslint-plugin-prettier@2.6.0: - version "2.6.0" - resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz#33e4e228bdb06142d03c560ce04ec23f6c767dd7" +eslint-plugin-prettier@2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.2.tgz#71998c60aedfa2141f7bfcbf9d1c459bf98b4fad" dependencies: fast-diff "^1.1.1" jest-docblock "^21.0.0" -eslint-scope@^3.7.1, eslint-scope@~3.7.1: +eslint-scope@3.7.1, eslint-scope@^3.7.1: version "3.7.1" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-utils@^1.3.0, eslint-utils@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" + eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" @@ -3426,10 +3541,6 @@ esprima-fb@~15001.1001.0-dev-harmony-fb: version "15001.1001.0-dev-harmony-fb" resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" -esprima@^1.2.2: - version "1.2.5" - resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" - esprima@^2.6.0: version "2.7.3" resolved "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" @@ -3446,6 +3557,10 @@ esprima@~3.1.0: version "3.1.3" resolved "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" +esprima@~4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + esprimaq@^0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" @@ -3523,18 +3638,6 @@ execa@^0.10.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@^0.9.0: - version "0.9.0" - resolved "https://registry.npmjs.org/execa/-/execa-0.9.0.tgz#adb7ce62cf985071f60580deb4a88b9e34712d01" - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - exists-stat@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/exists-stat/-/exists-stat-1.0.0.tgz#0660e3525a2e89d9e446129440c272edfa24b529" @@ -3717,6 +3820,19 @@ fast-sourcemap-concat@^1.0.1: source-map-url "^0.3.0" sourcemap-validator "^1.0.5" +fast-sourcemap-concat@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fast-sourcemap-concat/-/fast-sourcemap-concat-1.3.2.tgz#148a3e15260177f9e4d3ad90a8bcad0c47b8d073" + dependencies: + chalk "^2.0.0" + fs-extra "^5.0.0" + heimdalljs-logger "^0.1.9" + memory-streams "^0.1.3" + mkdirp "^0.5.0" + source-map "^0.4.2" + source-map-url "^0.3.0" + sourcemap-validator "^1.1.0" + faye-websocket@~0.10.0: version "0.10.0" resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" @@ -3861,6 +3977,10 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" +flow-parser@^0.*: + version "0.78.0" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.78.0.tgz#4ec829a97fa68cff6e97691dfff7b6ddebbc187c" + follow-redirects@0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" @@ -3989,6 +4109,14 @@ fs-extra@^6.0.1: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.0.tgz#8cc3f47ce07ef7b3593a11b9fb245f7e34c041d6" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" @@ -4009,7 +4137,7 @@ fs-sync@^1.0.4: mkdirp "^0.5.1" rimraf "^2.1.4" -fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6: +fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6, fs-tree-diff@^0.5.7: version "0.5.7" resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.7.tgz#315e2b098d5fe7f622880ac965b1b051868ac871" dependencies: @@ -4018,6 +4146,16 @@ fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5 path-posix "^1.0.0" symlink-or-copy "^1.1.8" +fs-updater@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fs-updater/-/fs-updater-1.0.4.tgz#2329980f99ae9176e9a0e84f7637538a182ce63b" + dependencies: + can-symlink "^1.0.0" + clean-up-path "^1.0.0" + heimdalljs "^0.2.5" + heimdalljs-logger "^0.1.9" + rimraf "^2.6.2" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -4070,10 +4208,14 @@ get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" -git-repo-info@^1.0.4, git-repo-info@^1.1.2, git-repo-info@^1.4.1: +git-repo-info@^1.0.4, git-repo-info@^1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" +git-repo-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-2.0.0.tgz#2e7a68ba3d0253e8e885c4138f922e6561de59bb" + git-repo-version@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-0.2.0.tgz#9a1d0019a50fc9e623c43d1c0fcc437391207d0d" @@ -4113,12 +4255,16 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@3.2.11: - version "3.2.11" - resolved "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" +glob@7.1.2, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2: + version "7.1.2" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" inherits "2" - minimatch "0.3" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" glob@^4.3.2: version "4.5.3" @@ -4129,7 +4275,7 @@ glob@^4.3.2: minimatch "^2.0.1" once "^1.3.0" -glob@^5.0.10, glob@^5.0.13, glob@^5.0.15: +glob@^5.0.10, glob@^5.0.15: version "5.0.15" resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: @@ -4139,17 +4285,6 @@ glob@^5.0.10, glob@^5.0.13, glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: - version "7.1.2" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - global-modules@^0.2.3: version "0.2.3" resolved "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" @@ -4237,9 +4372,9 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, version "1.0.1" resolved "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" -growl@1.9.2: - version "1.9.2" - resolved "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" growly@^1.3.0: version "1.3.0" @@ -4267,17 +4402,9 @@ has-binary2@~1.0.2: dependencies: isarray "2.0.1" -has-binary@0.1.6: - version "0.1.6" - resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz#25326f39cfa4f616ad8787894e3af2cfbc7b6e10" - dependencies: - isarray "0.0.1" - -has-binary@0.1.7: +has-color@~0.1.0: version "0.1.7" - resolved "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz#68e61eb16210c9545a0a5cce06a873912fe1e68c" - dependencies: - isarray "0.0.1" + resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" has-cors@1.1.0: version "1.1.0" @@ -4346,6 +4473,10 @@ hawk@1.1.1: hoek "0.9.x" sntp "0.2.x" +he@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + heimdalljs-fs-monitor@^0.2.0: version "0.2.1" resolved "https://registry.npmjs.org/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.2.1.tgz#b4079cfb85fb8326b8c75a7538fdbfa3d8afaa63" @@ -4364,7 +4495,7 @@ heimdalljs-logger@^0.1.7, heimdalljs-logger@^0.1.9: debug "^2.2.0" heimdalljs "^0.2.0" -heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3: +heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3, heimdalljs@^0.2.5: version "0.2.5" resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.2.5.tgz#6aa54308eee793b642cff9cf94781445f37730ac" dependencies: @@ -4478,10 +4609,14 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" -ignore@^3.3.3, ignore@^3.3.6: +ignore@^3.3.3: version "3.3.10" resolved "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" +ignore@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.3.tgz#e2d58c9654d75b542529fa28d80ac95b29e4f467" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -4500,7 +4635,7 @@ inflected@^1.1.6: version "1.1.7" resolved "https://registry.npmjs.org/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" -inflection@^1.12.0, inflection@^1.7.0, inflection@^1.8.0: +inflection@^1.12.0, inflection@^1.7.0: version "1.12.0" resolved "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" @@ -4867,13 +5002,6 @@ isurl@^1.0.0-alpha5: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" -jade@0.26.3: - version "0.26.3" - resolved "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" - dependencies: - commander "0.6.1" - mkdirp "0.3.0" - jest-docblock@^21.0.0: version "21.2.0" resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" @@ -4905,6 +5033,27 @@ js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.6.1, js-yaml@^3.9.1: argparse "^1.0.7" esprima "^4.0.0" +jscodeshift@^0.3.29: + version "0.3.32" + resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.3.32.tgz#dece5eb602f16340d8d954c7f96ac907c502eabb" + dependencies: + async "^1.5.0" + babel-core "^5" + babel-plugin-transform-flow-strip-types "^6.8.0" + babel-preset-es2015 "^6.9.0" + babel-preset-stage-1 "^6.5.0" + babel-register "^6.9.0" + babylon "^6.17.3" + colors "^1.1.2" + flow-parser "^0.*" + lodash "^4.13.1" + micromatch "^2.3.7" + node-dir "0.1.8" + nomnom "^1.8.1" + recast "^0.12.5" + temp "^0.8.1" + write-file-atomic "^1.2.0" + jsesc@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" @@ -4943,10 +5092,6 @@ json-stringify-safe@~5.0.0: version "5.0.1" resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" -json3@3.3.2: - version "3.3.2" - resolved "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" - json5@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" @@ -5058,9 +5203,9 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -loader.js@^4.5.0: +loader.js@^4.7.0: version "4.7.0" - resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.7.0.tgz#a1a52902001c83631efde9688b8ab3799325ef1f" + resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.7.0.tgz#a1a52902001c83631efde9688b8ab3799325ef1f" locate-character@^2.0.5: version "2.0.5" @@ -5328,9 +5473,9 @@ lodash.keys@~2.3.0: lodash._shimkeys "~2.3.0" lodash.isobject "~2.3.0" -lodash.merge@^4.3.0, lodash.merge@^4.5.1, lodash.merge@^4.6.0: +lodash.merge@^4.3.0, lodash.merge@^4.3.1, lodash.merge@^4.6.0: version "4.6.1" - resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" lodash.noop@~2.3.0: version "2.3.0" @@ -5400,7 +5545,7 @@ lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: +lodash@^4.0.0, lodash@^4.13.1, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: version "4.17.10" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -5435,10 +5580,6 @@ lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" -lru-cache@2: - version "2.7.3" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" - lru-cache@^4.0.1: version "4.1.3" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" @@ -5544,9 +5685,9 @@ media-typer@0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" -memory-streams@^0.1.0: +memory-streams@^0.1.0, memory-streams@^0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/memory-streams/-/memory-streams-0.1.3.tgz#d9b0017b4b87f1d92f55f2745c9caacb1dc93ceb" + resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.3.tgz#d9b0017b4b87f1d92f55f2745c9caacb1dc93ceb" dependencies: readable-stream "~1.0.2" @@ -5580,6 +5721,13 @@ merge-trees@^1.0.1: rimraf "^2.4.3" symlink-or-copy "^1.0.0" +merge-trees@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-trees/-/merge-trees-2.0.0.tgz#a560d796e566c5d9b2c40472a2967cca48d85161" + dependencies: + fs-updater "^1.0.4" + heimdalljs "^0.2.5" + merge@^1.1.3, merge@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" @@ -5632,7 +5780,7 @@ mime-db@~1.33.0: version "1.33.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" -mime-types@^2.1.18, mime-types@~2.1.11, mime-types@~2.1.18: +mime-types@^2.1.18, mime-types@~2.1.18: version "2.1.18" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" dependencies: @@ -5662,14 +5810,7 @@ mimic-response@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" -minimatch@0.3: - version "0.3.0" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" - dependencies: - lru-cache "2" - sigmund "~1.0.0" - -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: +"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -5713,10 +5854,6 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" - mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -5727,28 +5864,29 @@ mktemp@^0.4.0, mktemp@~0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" -mocha-only-detector@0.0.2: - version "0.0.2" - resolved "https://registry.npmjs.org/mocha-only-detector/-/mocha-only-detector-0.0.2.tgz#00f7dde6f949cf68a3cc92bdacff997b87e4b1d1" +mocha-only-detector@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mocha-only-detector/-/mocha-only-detector-1.0.0.tgz#183c710afffcca79df172daf76c45afca3b8e37d" dependencies: - esprima "^1.2.2" + esprima "^4.0.0" esprimaq "^0.0.1" glob "^4.3.2" -mocha@^2.4.5: - version "2.5.3" - resolved "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58" - dependencies: - commander "2.3.0" - debug "2.2.0" - diff "1.4.0" - escape-string-regexp "1.0.2" - glob "3.2.11" - growl "1.9.2" - jade "0.26.3" +mocha@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" + dependencies: + browser-stdout "1.3.1" + commander "2.15.1" + debug "3.1.0" + diff "3.5.0" + escape-string-regexp "1.0.5" + glob "7.1.2" + growl "1.10.5" + he "1.1.1" + minimatch "3.0.4" mkdirp "0.5.1" - supports-color "1.2.0" - to-iso-string "0.0.2" + supports-color "5.4.0" moment-timezone@^0.3.0: version "0.3.1" @@ -5774,14 +5912,6 @@ mout@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/mout/-/mout-1.1.0.tgz#0b29d41e6a80fa9e2d4a5be9d602e1d9d02177f6" -ms@0.7.1: - version "0.7.1" - resolved "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" - -ms@0.7.2: - version "0.7.2" - resolved "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" - ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -5843,6 +5973,10 @@ nice-try@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" +node-dir@0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.8.tgz#55fb8deb699070707fb67f91a460f0448294c77d" + node-fetch@^1.3.3: version "1.7.3" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" @@ -5886,6 +6020,13 @@ node-uuid@~1.4.0: version "1.4.8" resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" +nomnom@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7" + dependencies: + chalk "~0.4.0" + underscore "~1.6.0" + nopt@^3.0.3, nopt@^3.0.6: version "3.0.6" resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" @@ -5926,9 +6067,9 @@ npm-bundled@^1.0.1: version "1.0.3" resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" -npm-git-info@^1.0.0: +npm-git-info@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" + resolved "https://registry.yarnpkg.com/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" npm-package-arg@^6.0.0: version "6.1.0" @@ -5969,10 +6110,6 @@ oauth-sign@~0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" -object-assign@4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" - object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -6052,10 +6189,6 @@ optionator@^0.8.2: type-check "~0.3.2" wordwrap "~1.0.0" -options@>=0.0.5: - version "0.0.6" - resolved "https://registry.npmjs.org/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" - ora@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" @@ -6157,12 +6290,6 @@ parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" -parsejson@0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" - dependencies: - better-assert "~1.0.0" - parseqs@0.0.5: version "0.0.5" resolved "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" @@ -6302,10 +6429,6 @@ pretty-ms@^3.1.0: dependencies: parse-ms "^1.0.0" -printf@^0.2.3: - version "0.2.5" - resolved "https://registry.npmjs.org/printf/-/printf-0.2.5.tgz#c438ca2ca33e3927671db4ab69c0e52f936a4f0f" - printf@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/printf/-/printf-0.3.0.tgz#6918ca5237c047e19cf004b69e6bcfafbef1ce82" @@ -6464,7 +6587,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^2, readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: +readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: version "2.3.6" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -6521,6 +6644,16 @@ recast@^0.11.17, recast@^0.11.3: private "~0.1.5" source-map "~0.5.0" +recast@^0.12.5: + version "0.12.9" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.12.9.tgz#e8e52bdb9691af462ccbd7c15d5a5113647a15f1" + dependencies: + ast-types "0.10.1" + core-js "^2.4.1" + esprima "~4.0.0" + private "~0.1.5" + source-map "~0.6.1" + redent@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" @@ -6586,6 +6719,10 @@ regexpp@^1.0.1: version "1.1.0" resolved "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" +regexpp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.0.tgz#b2a7534a85ca1b033bcf5ce9ff8e56d4e0755365" + regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -6700,7 +6837,7 @@ resolve@1.5.0: dependencies: path-parse "^1.0.5" -resolve@^1.1.2, resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.7.1: +resolve@^1.1.2, resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.7.1, resolve@^1.8.1: version "1.8.1" resolved "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" dependencies: @@ -6736,13 +6873,7 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2.5.2: - version "2.5.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz#62ba947fa4c0b4363839aefecd4f0fbad6059726" - dependencies: - glob "^7.0.0" - -rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1: +rimraf@2.6.2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: version "2.6.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: @@ -6783,9 +6914,9 @@ rsvp@3.0.14: version "3.0.14" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.14.tgz#9d2968cf36d878d3bb9a9a5a4b8e1ff55a76dd31" -rsvp@4.8.0: - version "4.8.0" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.0.tgz#dc1dc400e2d48bcf3b1991f2a3b714f038fc432e" +rsvp@4.8.3, rsvp@^4.8.3: + version "4.8.3" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.3.tgz#25d4b9fdd0f95e216eb5884d9b3767d3fbfbe2cd" rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.5.0: version "3.6.2" @@ -6963,10 +7094,6 @@ shellwords@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" -sigmund@~1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" - signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -7032,33 +7159,10 @@ sntp@0.2.x: dependencies: hoek "0.9.x" -socket.io-adapter@0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz#cb6d4bb8bec81e1078b99677f9ced0046066bb8b" - dependencies: - debug "2.3.3" - socket.io-parser "2.3.1" - socket.io-adapter@~1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" -socket.io-client@1.6.0: - version "1.6.0" - resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.6.0.tgz#5b668f4f771304dfeed179064708386fa6717853" - dependencies: - backo2 "1.0.2" - component-bind "1.0.0" - component-emitter "1.2.1" - debug "2.3.3" - engine.io-client "1.8.0" - 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" - socket.io-client@2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" @@ -7078,15 +7182,6 @@ socket.io-client@2.1.1: socket.io-parser "~3.2.0" to-array "0.1.4" -socket.io-parser@2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz#dd532025103ce429697326befd64005fcfe5b4a0" - dependencies: - component-emitter "1.1.2" - debug "2.2.0" - isarray "0.0.1" - json3 "3.3.2" - socket.io-parser@~3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" @@ -7095,18 +7190,6 @@ socket.io-parser@~3.2.0: debug "~3.1.0" isarray "2.0.1" -socket.io@1.6.0: - version "1.6.0" - resolved "https://registry.npmjs.org/socket.io/-/socket.io-1.6.0.tgz#3e40d932637e6bd923981b25caf7c53e83b6e2e1" - dependencies: - debug "2.3.3" - engine.io "1.8.0" - has-binary "0.1.7" - object-assign "4.1.0" - socket.io-adapter "0.5.0" - socket.io-client "1.6.0" - socket.io-parser "2.3.1" - socket.io@^2.1.0: version "2.1.1" resolved "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" @@ -7195,9 +7278,9 @@ sourcemap-codec@^1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.1.tgz#c8fd92d91889e902a07aee392bdd2c5863958ba2" -sourcemap-validator@^1.0.5: +sourcemap-validator@^1.0.5, sourcemap-validator@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/sourcemap-validator/-/sourcemap-validator-1.1.0.tgz#00454547d1682186e1498a7208e022e8dfa8738f" + resolved "https://registry.yarnpkg.com/sourcemap-validator/-/sourcemap-validator-1.1.0.tgz#00454547d1682186e1498a7208e022e8dfa8738f" dependencies: jsesc "~0.3.x" lodash.foreach "~2.3.x" @@ -7350,6 +7433,10 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -7384,21 +7471,17 @@ sum-up@^1.0.1: dependencies: chalk "^1.0.0" -supports-color@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - -supports-color@^5.3.0: +supports-color@5.4.0, supports-color@^5.3.0: version "5.4.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" dependencies: has-flag "^3.0.0" -symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8: +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" @@ -7413,15 +7496,6 @@ table@4.0.2: slice-ansi "1.0.0" string-width "^2.1.1" -tap-parser@^5.1.0: - version "5.4.0" - resolved "https://registry.npmjs.org/tap-parser/-/tap-parser-5.4.0.tgz#6907e89725d7b7fa6ae41ee2c464c3db43188aec" - dependencies: - events-to-array "^1.0.1" - js-yaml "^3.2.7" - optionalDependencies: - readable-stream "^2" - tap-parser@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/tap-parser/-/tap-parser-7.0.0.tgz#54db35302fda2c2ccc21954ad3be22b2cba42721" @@ -7442,7 +7516,7 @@ tar@^4: safe-buffer "^5.1.2" yallist "^3.0.2" -temp@0.8.3: +temp@0.8.3, temp@^0.8.1: version "0.8.3" resolved "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" dependencies: @@ -7456,7 +7530,7 @@ terser@^3.7.5: commander "~2.14.1" source-map "~0.6.1" -testdouble@^3.2.6: +testdouble@^3.2.6, testdouble@^3.8.1: version "3.8.1" resolved "https://registry.npmjs.org/testdouble/-/testdouble-3.8.1.tgz#8c74b6807f82fb07c2387a0640b4ae594b09b964" dependencies: @@ -7466,40 +7540,9 @@ testdouble@^3.2.6: stringify-object-es5 "^2.5.0" theredoc "^1.0.0" -testem@^1.15.0: - version "1.18.5" - resolved "https://registry.npmjs.org/testem/-/testem-1.18.5.tgz#912f3bfd4773519fa3cce0a8fd0e354763cbd545" - dependencies: - backbone "^1.1.2" - bluebird "^3.4.6" - charm "^1.0.0" - commander "^2.6.0" - consolidate "^0.14.0" - cross-spawn "^5.1.0" - express "^4.10.7" - fireworm "^0.7.0" - glob "^7.0.4" - http-proxy "^1.13.1" - js-yaml "^3.2.5" - lodash.assignin "^4.1.0" - lodash.clonedeep "^4.4.1" - lodash.find "^4.5.1" - lodash.uniqby "^4.7.0" - mkdirp "^0.5.1" - mustache "^2.2.1" - node-notifier "^5.0.1" - npmlog "^4.0.0" - printf "^0.2.3" - rimraf "^2.4.4" - socket.io "1.6.0" - spawn-args "^0.2.0" - styled_string "0.0.1" - tap-parser "^5.1.0" - xmldom "^0.1.19" - -testem@^2.0.0: - version "2.8.2" - resolved "https://registry.npmjs.org/testem/-/testem-2.8.2.tgz#0d51801cbcdfe411e2e24ae7e63e2eca779dfe89" +testem@^2.2.0, testem@^2.9.2: + version "2.9.2" + resolved "https://registry.yarnpkg.com/testem/-/testem-2.9.2.tgz#d61c638fd7fff6d9bc2f771c673dc10cb1df3d21" dependencies: backbone "^1.1.2" bluebird "^3.4.6" @@ -7611,10 +7654,6 @@ to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" -to-iso-string@0.0.2: - version "0.0.2" - resolved "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" - to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -7707,7 +7746,7 @@ uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" -uglify-js@^2.6, uglify-js@^2.7.0: +uglify-js@^2.6: version "2.8.29" resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" dependencies: @@ -7720,10 +7759,6 @@ uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" -ultron@1.0.x: - version "1.0.2" - resolved "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" - ultron@~1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" @@ -7739,6 +7774,10 @@ underscore@>=1.8.3: version "1.9.1" resolved "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" +underscore@~1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8" + union-value@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" @@ -7836,10 +7875,6 @@ uuid@3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" -uuid@^2.0.1: - version "2.0.3" - resolved "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" - uuid@^3.0.0: version "3.2.1" resolved "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" @@ -7965,9 +8000,9 @@ wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" -write-file-atomic@^1.1.2: +write-file-atomic@^1.2.0: version "1.3.4" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -7987,13 +8022,6 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" -ws@1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/ws/-/ws-1.1.1.tgz#082ddb6c641e85d4bb451f03d52f06eabdb1f018" - dependencies: - options ">=0.0.5" - ultron "1.0.x" - ws@~3.3.1: version "3.3.3" resolved "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" @@ -8002,16 +8030,6 @@ ws@~3.3.1: safe-buffer "~5.1.0" ultron "~1.1.0" -wtf-8@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" - -xdg-basedir@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" - dependencies: - os-homedir "^1.0.0" - xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" @@ -8033,10 +8051,6 @@ xmldom@^0.1.19: version "0.1.27" resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" -xmlhttprequest-ssl@1.5.3: - version "1.5.3" - resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" - xmlhttprequest-ssl@~1.5.4: version "1.5.5" resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" From 0febf03bd91e2ee70e227f42b15cbfa76dac4a7c Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 8 Aug 2018 11:04:34 -0400 Subject: [PATCH 2296/2527] Remove unused dependencies. --- package.json | 18 +-- yarn.lock | 336 +++++---------------------------------------------- 2 files changed, 32 insertions(+), 322 deletions(-) diff --git a/package.json b/package.json index 9de79b000e2..1ad4624c0e7 100644 --- a/package.json +++ b/package.json @@ -22,9 +22,6 @@ "license": "MIT", "dependencies": { "@ember/ordered-set": "^2.0.0", - "amd-name-resolver": "1.2.0", - "babel-plugin-debug-macros": "^0.1.11", - "babel-plugin-ember-modules-api-polyfill": "^2.3.2", "babel-plugin-feature-flags": "^0.3.1", "babel-plugin-filter-imports": "^0.3.1", "babel-plugin-transform-es2015-block-scoping": "^6.26.0", @@ -56,16 +53,6 @@ "@ember-decorators/babel-transforms": "^2.0.2", "@ember-decorators/data": "^2.3.1", "babel-eslint": "^8.2.6", - "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-classes": "^6.24.1", - "babel-plugin-transform-es2015-computed-properties": "^6.24.1", - "babel-plugin-transform-es2015-constants": "^6.1.4", - "babel-plugin-transform-es2015-destructuring": "^6.23.0", - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-plugin-transform-es2015-parameters": "^6.24.1", - "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-template-literals": "^6.22.0", "broccoli-asset-rev": "^2.7.0", "broccoli-babel-transpiler": "^6.5.0", "broccoli-concat": "^3.5.1", @@ -104,7 +91,6 @@ "ember-source": "~3.0.0", "ember-source-channel-url": "^1.1.0", "ember-try": "^0.2.23", - "ember-watson": "^0.9.1", "eslint-config-prettier": "^2.9.0", "eslint-plugin-node": "^7.0.1", "eslint-plugin-prettier": "2.6.2", @@ -116,9 +102,7 @@ "mocha-only-detector": "1.0.0", "prettier": "^1.14.0", "rimraf": "2.6.2", - "rsvp": "4.8.3", - "testdouble": "^3.8.1", - "testem": "^2.9.2" + "rsvp": "4.8.3" }, "engines": { "node": ">= 6.0.0" diff --git a/yarn.lock b/yarn.lock index 537d0dcce1c..79c40c23383 100644 --- a/yarn.lock +++ b/yarn.lock @@ -282,10 +282,6 @@ ansi-styles@^3.0.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" - ansicolors@~0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" @@ -413,10 +409,6 @@ ast-traverse@~0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" -ast-types@0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.1.tgz#f52fca9715579a14f841d67d7f8d25432ab6a3dd" - ast-types@0.8.12: version "0.8.12" resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" @@ -456,7 +448,7 @@ async-promise-queue@^1.0.3, async-promise-queue@^1.0.4: async "^2.4.1" debug "^2.6.8" -async@^1.4.0, async@^1.5.0, async@^1.5.2: +async@^1.4.0, async@^1.5.2: version "1.5.2" resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -504,7 +496,7 @@ babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-core@^5, babel-core@^5.0.0, babel-core@^5.8.22: +babel-core@^5.0.0: version "5.8.38" resolved "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" dependencies: @@ -603,14 +595,6 @@ babel-generator@^6.26.0: source-map "^0.5.7" trim-right "^1.0.1" -babel-helper-bindify-decorators@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330" - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" @@ -645,15 +629,6 @@ babel-helper-explode-assignable-expression@^6.24.1: babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-helper-explode-class@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" - dependencies: - babel-helper-bindify-decorators "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - babel-helper-function-name@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" @@ -821,55 +796,23 @@ babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" -babel-plugin-syntax-async-generators@^6.5.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" - -babel-plugin-syntax-class-constructor-call@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" - babel-plugin-syntax-class-properties@^6.8.0: version "6.13.0" resolved "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" -babel-plugin-syntax-decorators@^6.1.18, babel-plugin-syntax-decorators@^6.13.0: +babel-plugin-syntax-decorators@^6.1.18: version "6.13.0" resolved "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" -babel-plugin-syntax-dynamic-import@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" - babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" -babel-plugin-syntax-export-extensions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" - -babel-plugin-syntax-flow@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" - -babel-plugin-syntax-object-rest-spread@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" - babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" resolved "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" -babel-plugin-transform-async-generator-functions@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-generators "^6.5.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1: +babel-plugin-transform-async-to-generator@^6.22.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" dependencies: @@ -877,14 +820,6 @@ babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async- babel-plugin-syntax-async-functions "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-class-constructor-call@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9" - dependencies: - babel-plugin-syntax-class-constructor-call "^6.18.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-plugin-transform-class-properties@^6.24.1: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" @@ -902,16 +837,6 @@ babel-plugin-transform-decorators-legacy@^1.3.4: babel-runtime "^6.2.0" babel-template "^6.3.0" -babel-plugin-transform-decorators@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d" - dependencies: - babel-helper-explode-class "^6.24.1" - babel-plugin-syntax-decorators "^6.13.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-types "^6.24.1" - babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" @@ -924,7 +849,7 @@ babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.24.1, babel-plugin-transform-es2015-block-scoping@^6.26.0: +babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.26.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" dependencies: @@ -934,7 +859,7 @@ babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es20 babel-types "^6.26.0" lodash "^4.17.4" -babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-classes@^6.24.1: +babel-plugin-transform-es2015-classes@^6.23.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" dependencies: @@ -948,39 +873,33 @@ babel-plugin-transform-es2015-classes@^6.23.0, babel-plugin-transform-es2015-cla babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-computed-properties@^6.22.0, babel-plugin-transform-es2015-computed-properties@^6.24.1: +babel-plugin-transform-es2015-computed-properties@^6.22.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-constants@^6.1.4: - version "6.1.4" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-constants/-/babel-plugin-transform-es2015-constants-6.1.4.tgz#e4b8c78fb48ab98b0107f329fab6040e79c35a33" - dependencies: - babel-runtime "^5.0.0" - -babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es2015-destructuring@^6.23.0: +babel-plugin-transform-es2015-destructuring@^6.23.0: version "6.23.0" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-duplicate-keys@^6.22.0, babel-plugin-transform-es2015-duplicate-keys@^6.24.1: +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.23.0: +babel-plugin-transform-es2015-for-of@^6.23.0: version "6.23.0" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-function-name@^6.22.0, babel-plugin-transform-es2015-function-name@^6.24.1: +babel-plugin-transform-es2015-function-name@^6.22.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" dependencies: @@ -1011,7 +930,7 @@ babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-e babel-template "^6.26.0" babel-types "^6.26.0" -babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-es2015-modules-systemjs@^6.24.1: +babel-plugin-transform-es2015-modules-systemjs@^6.23.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" dependencies: @@ -1019,7 +938,7 @@ babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-e babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015-modules-umd@^6.24.1: +babel-plugin-transform-es2015-modules-umd@^6.23.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" dependencies: @@ -1027,14 +946,14 @@ babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015 babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-object-super@^6.22.0, babel-plugin-transform-es2015-object-super@^6.24.1: +babel-plugin-transform-es2015-object-super@^6.22.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" dependencies: babel-helper-replace-supers "^6.24.1" babel-runtime "^6.22.0" -babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015-parameters@^6.24.1: +babel-plugin-transform-es2015-parameters@^6.23.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" dependencies: @@ -1045,7 +964,7 @@ babel-plugin-transform-es2015-parameters@^6.23.0, babel-plugin-transform-es2015- babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-shorthand-properties@^6.22.0, babel-plugin-transform-es2015-shorthand-properties@^6.24.1: +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" dependencies: @@ -1058,7 +977,7 @@ babel-plugin-transform-es2015-spread@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-sticky-regex@^6.22.0, babel-plugin-transform-es2015-sticky-regex@^6.24.1: +babel-plugin-transform-es2015-sticky-regex@^6.22.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" dependencies: @@ -1072,13 +991,13 @@ babel-plugin-transform-es2015-template-literals@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es2015-typeof-symbol@^6.23.0: +babel-plugin-transform-es2015-typeof-symbol@^6.23.0: version "6.23.0" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es2015-unicode-regex@^6.24.1: +babel-plugin-transform-es2015-unicode-regex@^6.22.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" dependencies: @@ -1086,7 +1005,7 @@ babel-plugin-transform-es2015-unicode-regex@^6.22.0, babel-plugin-transform-es20 babel-runtime "^6.22.0" regexpu-core "^2.0.0" -babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.24.1: +babel-plugin-transform-exponentiation-operator@^6.22.0: version "6.24.1" resolved "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" dependencies: @@ -1094,28 +1013,7 @@ babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-e babel-plugin-syntax-exponentiation-operator "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-export-extensions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" - dependencies: - babel-plugin-syntax-export-extensions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-flow-strip-types@^6.8.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" - dependencies: - babel-plugin-syntax-flow "^6.18.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-object-rest-spread@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" - dependencies: - babel-plugin-syntax-object-rest-spread "^6.8.0" - babel-runtime "^6.26.0" - -babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.24.1: +babel-plugin-transform-regenerator@^6.22.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" dependencies: @@ -1181,63 +1079,7 @@ babel-preset-env@^1.7.0: invariant "^2.2.2" semver "^5.3.0" -babel-preset-es2015@^6.9.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" - dependencies: - babel-plugin-check-es2015-constants "^6.22.0" - babel-plugin-transform-es2015-arrow-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.24.1" - babel-plugin-transform-es2015-classes "^6.24.1" - babel-plugin-transform-es2015-computed-properties "^6.24.1" - babel-plugin-transform-es2015-destructuring "^6.22.0" - babel-plugin-transform-es2015-duplicate-keys "^6.24.1" - babel-plugin-transform-es2015-for-of "^6.22.0" - babel-plugin-transform-es2015-function-name "^6.24.1" - babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-plugin-transform-es2015-modules-systemjs "^6.24.1" - babel-plugin-transform-es2015-modules-umd "^6.24.1" - babel-plugin-transform-es2015-object-super "^6.24.1" - babel-plugin-transform-es2015-parameters "^6.24.1" - babel-plugin-transform-es2015-shorthand-properties "^6.24.1" - babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.24.1" - babel-plugin-transform-es2015-template-literals "^6.22.0" - babel-plugin-transform-es2015-typeof-symbol "^6.22.0" - babel-plugin-transform-es2015-unicode-regex "^6.24.1" - babel-plugin-transform-regenerator "^6.24.1" - -babel-preset-stage-1@^6.5.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz#7692cd7dcd6849907e6ae4a0a85589cfb9e2bfb0" - dependencies: - babel-plugin-transform-class-constructor-call "^6.24.1" - babel-plugin-transform-export-extensions "^6.22.0" - babel-preset-stage-2 "^6.24.1" - -babel-preset-stage-2@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1" - dependencies: - babel-plugin-syntax-dynamic-import "^6.18.0" - babel-plugin-transform-class-properties "^6.24.1" - babel-plugin-transform-decorators "^6.24.1" - babel-preset-stage-3 "^6.24.1" - -babel-preset-stage-3@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395" - dependencies: - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-generator-functions "^6.24.1" - babel-plugin-transform-async-to-generator "^6.24.1" - babel-plugin-transform-exponentiation-operator "^6.24.1" - babel-plugin-transform-object-rest-spread "^6.22.0" - -babel-register@^6.26.0, babel-register@^6.9.0: +babel-register@^6.26.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" dependencies: @@ -1249,12 +1091,6 @@ babel-register@^6.26.0, babel-register@^6.9.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@^5.0.0: - version "5.8.38" - resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz#1c0b02eb63312f5f087ff20450827b425c9d4c19" - dependencies: - core-js "^1.0.0" - babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" @@ -1311,7 +1147,7 @@ babylon@^5.8.38: version "5.8.38" resolved "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" -babylon@^6.17.3, babylon@^6.18.0: +babylon@^6.18.0: version "6.18.0" resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" @@ -2180,14 +2016,6 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4 escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" - dependencies: - ansi-styles "~1.0.0" - has-color "~0.1.0" - strip-ansi "~0.1.0" - chardet@^0.4.0: version "0.4.2" resolved "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" @@ -2517,7 +2345,7 @@ core-js@^1.0.0: version "1.2.7" resolved "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" -core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0: +core-js@^2.4.0, core-js@^2.5.0: version "2.5.7" resolved "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" @@ -3182,13 +3010,6 @@ ember-inflector@^3.0.0: dependencies: ember-cli-babel "^6.6.0" -ember-k-codemod@^0.1.0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/ember-k-codemod/-/ember-k-codemod-0.1.7.tgz#c35bd6016e3d7cdac1325f86fa9f75f2eef338c3" - dependencies: - glob "^7.1.1" - jscodeshift "^0.3.29" - ember-load-initializers@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/ember-load-initializers/-/ember-load-initializers-1.1.0.tgz#4edacc0f3a14d9f53d241ac3e5561804c8377978" @@ -3293,7 +3114,7 @@ ember-try-config@^2.2.0: ember-try@^0.2.23: version "0.2.23" - resolved "https://registry.npmjs.org/ember-try/-/ember-try-0.2.23.tgz#39b57141b4907541d0ac8b503d211e6946b08718" + resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.23.tgz#39b57141b4907541d0ac8b503d211e6946b08718" dependencies: chalk "^1.0.0" cli-table2 "^0.2.0" @@ -3308,19 +3129,6 @@ ember-try@^0.2.23: rsvp "^3.0.17" semver "^5.1.0" -ember-watson@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/ember-watson/-/ember-watson-0.9.1.tgz#77ad64740c339b21d52fffd4487fca7c84173109" - dependencies: - babel-core "^5.8.22" - chalk "^1.0.0" - commander "^2.6.0" - ember-k-codemod "^0.1.0" - exists-sync "0.0.3" - inflected "^1.1.6" - recast "^0.10.29" - walk-sync "^0.1.3" - encodeurl@~1.0.1, encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -3557,10 +3365,6 @@ esprima@~3.1.0: version "3.1.3" resolved "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" -esprima@~4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - esprimaq@^0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" @@ -3977,10 +3781,6 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" -flow-parser@^0.*: - version "0.78.0" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.78.0.tgz#4ec829a97fa68cff6e97691dfff7b6ddebbc187c" - follow-redirects@0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" @@ -4255,7 +4055,7 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@7.1.2, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2: +glob@7.1.2, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: version "7.1.2" resolved "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -4402,10 +4202,6 @@ has-binary2@~1.0.2: dependencies: isarray "2.0.1" -has-color@~0.1.0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" - has-cors@1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" @@ -4631,10 +4427,6 @@ indexof@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" -inflected@^1.1.6: - version "1.1.7" - resolved "https://registry.npmjs.org/inflected/-/inflected-1.1.7.tgz#c393df6e28472d0d77b3082ec3aa2091f4bc96f9" - inflection@^1.12.0, inflection@^1.7.0: version "1.12.0" resolved "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" @@ -5033,27 +4825,6 @@ js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.6.1, js-yaml@^3.9.1: argparse "^1.0.7" esprima "^4.0.0" -jscodeshift@^0.3.29: - version "0.3.32" - resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.3.32.tgz#dece5eb602f16340d8d954c7f96ac907c502eabb" - dependencies: - async "^1.5.0" - babel-core "^5" - babel-plugin-transform-flow-strip-types "^6.8.0" - babel-preset-es2015 "^6.9.0" - babel-preset-stage-1 "^6.5.0" - babel-register "^6.9.0" - babylon "^6.17.3" - colors "^1.1.2" - flow-parser "^0.*" - lodash "^4.13.1" - micromatch "^2.3.7" - node-dir "0.1.8" - nomnom "^1.8.1" - recast "^0.12.5" - temp "^0.8.1" - write-file-atomic "^1.2.0" - jsesc@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" @@ -5545,7 +5316,7 @@ lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.13.1, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: +lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: version "4.17.10" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -5973,10 +5744,6 @@ nice-try@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" -node-dir@0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.8.tgz#55fb8deb699070707fb67f91a460f0448294c77d" - node-fetch@^1.3.3: version "1.7.3" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" @@ -6020,13 +5787,6 @@ node-uuid@~1.4.0: version "1.4.8" resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" -nomnom@^1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7" - dependencies: - chalk "~0.4.0" - underscore "~1.6.0" - nopt@^3.0.3, nopt@^3.0.6: version "3.0.6" resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" @@ -6626,7 +6386,7 @@ recast@0.10.33: private "~0.1.5" source-map "~0.5.0" -recast@^0.10.10, recast@^0.10.29: +recast@^0.10.10: version "0.10.43" resolved "https://registry.npmjs.org/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" dependencies: @@ -6644,16 +6404,6 @@ recast@^0.11.17, recast@^0.11.3: private "~0.1.5" source-map "~0.5.0" -recast@^0.12.5: - version "0.12.9" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.12.9.tgz#e8e52bdb9691af462ccbd7c15d5a5113647a15f1" - dependencies: - ast-types "0.10.1" - core-js "^2.4.1" - esprima "~4.0.0" - private "~0.1.5" - source-map "~0.6.1" - redent@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" @@ -7122,10 +6872,6 @@ slice-ansi@1.0.0: dependencies: is-fullwidth-code-point "^2.0.0" -slide@^1.1.5: - version "1.1.6" - resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -7433,10 +7179,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991" - strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -7516,7 +7258,7 @@ tar@^4: safe-buffer "^5.1.2" yallist "^3.0.2" -temp@0.8.3, temp@^0.8.1: +temp@0.8.3: version "0.8.3" resolved "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" dependencies: @@ -7530,7 +7272,7 @@ terser@^3.7.5: commander "~2.14.1" source-map "~0.6.1" -testdouble@^3.2.6, testdouble@^3.8.1: +testdouble@^3.2.6: version "3.8.1" resolved "https://registry.npmjs.org/testdouble/-/testdouble-3.8.1.tgz#8c74b6807f82fb07c2387a0640b4ae594b09b964" dependencies: @@ -7540,7 +7282,7 @@ testdouble@^3.2.6, testdouble@^3.8.1: stringify-object-es5 "^2.5.0" theredoc "^1.0.0" -testem@^2.2.0, testem@^2.9.2: +testem@^2.2.0: version "2.9.2" resolved "https://registry.yarnpkg.com/testem/-/testem-2.9.2.tgz#d61c638fd7fff6d9bc2f771c673dc10cb1df3d21" dependencies: @@ -7774,10 +7516,6 @@ underscore@>=1.8.3: version "1.9.1" resolved "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" -underscore@~1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8" - union-value@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" @@ -7903,10 +7641,6 @@ walk-sync@0.3.2, walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" -walk-sync@^0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.1.3.tgz#8a07261a00bda6cfb1be25e9f100fad57546f583" - walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: version "0.2.7" resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" @@ -8000,14 +7734,6 @@ wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" -write-file-atomic@^1.2.0: - version "1.3.4" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - slide "^1.1.5" - write-file-atomic@^2.0.0: version "2.3.0" resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" From 1c00a5f9aa41eb627e3511ab0bac2533df15d299 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 8 Aug 2018 11:05:10 -0400 Subject: [PATCH 2297/2527] Update ember-try to latest... --- package.json | 2 +- yarn.lock | 227 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 175 insertions(+), 54 deletions(-) diff --git a/package.json b/package.json index 1ad4624c0e7..9ca094d2fa1 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "ember-resolver": "^5.0.1", "ember-source": "~3.0.0", "ember-source-channel-url": "^1.1.0", - "ember-try": "^0.2.23", + "ember-try": "^1.0.0-beta.3", "eslint-config-prettier": "^2.9.0", "eslint-plugin-node": "^7.0.1", "eslint-plugin-prettier": "2.6.2", diff --git a/yarn.lock b/yarn.lock index 79c40c23383..73e6782853c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1169,6 +1169,10 @@ base64-arraybuffer@0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" +base64-js@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.2.tgz#024f0f72afa25b75f9c0ee73cd4f55ec1bed9784" + base64-js@^1.0.2: version "1.3.0" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" @@ -1255,6 +1259,13 @@ boom@0.4.x: dependencies: hoek "0.9.x" +bops@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/bops/-/bops-0.0.3.tgz#c5cbf6fea8be7401ca5ea6d1679e6c4e8b407c79" + dependencies: + base64-js "0.0.2" + to-utf8 "0.0.1" + bower-config@^1.3.0: version "1.4.1" resolved "https://registry.npmjs.org/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc" @@ -1947,6 +1958,10 @@ capture-exit@^1.1.0, capture-exit@^1.2.0: dependencies: rsvp "^3.3.3" +capture-stack-trace@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" + cardinal@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" @@ -2349,11 +2364,7 @@ core-js@^2.4.0, core-js@^2.5.0: version "2.5.7" resolved "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" -core-object@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/core-object/-/core-object-1.1.0.tgz#86d63918733cf9da1a5aae729e62c0a88e66ad0a" - -core-object@^3.1.3: +core-object@^3.1.3, core-object@^3.1.5: version "3.1.5" resolved "https://registry.npmjs.org/core-object/-/core-object-3.1.5.tgz#fa627b87502adc98045e44678e9a8ec3b9c0d2a9" dependencies: @@ -2363,6 +2374,12 @@ core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" +create-error-class@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" + dependencies: + capture-stack-trace "^1.0.0" + cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -2594,6 +2611,10 @@ dot-prop@^4.1.0: dependencies: is-obj "^1.0.0" +duplex@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/duplex/-/duplex-1.0.0.tgz#6abc5c16ec17e4c578578727126700590d3a2dda" + duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -3079,7 +3100,7 @@ ember-runtime-enumerable-includes-polyfill@^2.1.0: ember-cli-babel "^6.9.0" ember-cli-version-checker "^2.1.0" -ember-source-channel-url@^1.1.0: +ember-source-channel-url@^1.0.1, ember-source-channel-url@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ember-source-channel-url/-/ember-source-channel-url-1.1.0.tgz#73de5cc6ebc25b2120e932ec1d8f82677bfaf6ef" dependencies: @@ -3103,42 +3124,42 @@ ember-source@~3.0.0: jquery "^3.2.1" resolve "^1.3.3" -ember-try-config@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/ember-try-config/-/ember-try-config-2.2.0.tgz#6be0af6c71949813e02ac793564fddbf8336b807" +ember-try-config@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ember-try-config/-/ember-try-config-3.0.0.tgz#012d8c90cae9eb624e2b62040bf7e76a1aa58edc" dependencies: + ember-source-channel-url "^1.0.1" lodash "^4.6.1" - node-fetch "^1.3.3" - rsvp "^3.2.1" - semver "^5.1.0" + package-json "^4.0.1" + remote-git-tags "^2.0.0" + rsvp "^4.8.1" + semver "^5.5.0" -ember-try@^0.2.23: - version "0.2.23" - resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-0.2.23.tgz#39b57141b4907541d0ac8b503d211e6946b08718" +ember-try@^1.0.0-beta.3: + version "1.0.0-beta.3" + resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-1.0.0-beta.3.tgz#04da09ba2d57f0fe3a7174acff0dc1add2760855" dependencies: - chalk "^1.0.0" + chalk "^2.3.0" cli-table2 "^0.2.0" - core-object "^1.1.0" - debug "^2.2.0" - ember-try-config "^2.2.0" + core-object "^3.1.5" + debug "^3.1.0" + ember-try-config "^3.0.0" + execa "^0.10.0" extend "^3.0.0" - fs-extra "^0.26.0" + fs-extra "^5.0.0" promise-map-series "^0.2.1" resolve "^1.1.6" rimraf "^2.3.2" - rsvp "^3.0.17" - semver "^5.1.0" + rsvp "^4.7.0" + +emit-function@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/emit-function/-/emit-function-0.0.2.tgz#e3a50b3d61be1bf8ca88b924bf713157a5bec124" encodeurl@~1.0.1, encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" -encoding@^0.1.11: - version "0.1.12" - resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" - dependencies: - iconv-lite "~0.4.13" - engine.io-client@~3.2.0: version "3.2.1" resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" @@ -3850,16 +3871,6 @@ fs-extra@^0.24.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" -fs-extra@^0.26.0: - version "0.26.7" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - fs-extra@^0.30.0: version "0.30.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" @@ -4008,6 +4019,29 @@ get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" +git-fetch-pack@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/git-fetch-pack/-/git-fetch-pack-0.1.1.tgz#7703a32cf0db80f060d2766a34ac00d02cebcdf5" + dependencies: + bops "0.0.3" + emit-function "0.0.2" + git-packed-ref-parse "0.0.0" + through "~2.2.7" + +git-packed-ref-parse@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/git-packed-ref-parse/-/git-packed-ref-parse-0.0.0.tgz#b85046931f3e4a65679b5de54af3a5d3df372646" + dependencies: + line-stream "0.0.0" + through "~2.2.7" + +git-read-pkt-line@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/git-read-pkt-line/-/git-read-pkt-line-0.0.8.tgz#494037854ed57bd90cd55676540d86ab0cb36caa" + dependencies: + bops "0.0.3" + through "~2.2.7" + git-repo-info@^1.0.4, git-repo-info@^1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" @@ -4034,6 +4068,23 @@ git-tools@^0.1.4: dependencies: spawnback "~1.0.0" +git-transport-protocol@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/git-transport-protocol/-/git-transport-protocol-0.1.0.tgz#99f4dd6389b9161eded74a9e617d6ba5ed0a6c2c" + dependencies: + duplex "~1.0.0" + emit-function "0.0.2" + git-read-pkt-line "0.0.8" + git-write-pkt-line "0.1.0" + through "~2.2.7" + +git-write-pkt-line@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/git-write-pkt-line/-/git-write-pkt-line-0.1.0.tgz#a84c1856c09011908389b2f06f911d91f6394694" + dependencies: + bops "0.0.3" + through "~2.2.7" + github@^1.1.1: version "1.4.0" resolved "https://registry.npmjs.org/github/-/github-1.4.0.tgz#60aed8f16ffe381a3ca6dc6dba5bdd64445b7856" @@ -4142,6 +4193,22 @@ globby@^5.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" +got@^6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" + dependencies: + create-error-class "^3.0.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-redirect "^1.0.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + unzip-response "^2.0.1" + url-parse-lax "^1.0.0" + got@^8.0.1: version "8.3.1" resolved "https://registry.npmjs.org/got/-/got-8.3.1.tgz#093324403d4d955f5a16a7a8d39955d055ae10ed" @@ -4385,7 +4452,7 @@ iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" -iconv-lite@^0.4.13, iconv-lite@^0.4.17, iconv-lite@^0.4.4, iconv-lite@^0.4.5, iconv-lite@~0.4.13: +iconv-lite@^0.4.13, iconv-lite@^0.4.17, iconv-lite@^0.4.4, iconv-lite@^0.4.5: version "0.4.23" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: @@ -4709,6 +4776,10 @@ is-promise@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + is-reference@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/is-reference/-/is-reference-1.1.0.tgz#50e6ef3f64c361e2c53c0416cdc9420037f2685b" @@ -4723,11 +4794,11 @@ is-resolvable@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" -is-retry-allowed@^1.1.0: +is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" -is-stream@^1.0.1, is-stream@^1.1.0: +is-stream@^1.0.0, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -4948,6 +5019,12 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +line-stream@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/line-stream/-/line-stream-0.0.0.tgz#888b7cc7951c6a05ce4d696dd1e6b8262371bb45" + dependencies: + through "~2.2.0" + linkify-it@^2.0.0: version "2.0.3" resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" @@ -5744,13 +5821,6 @@ nice-try@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" -node-fetch@^1.3.3: - version "1.7.3" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" - node-int64@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -6027,6 +6097,15 @@ p-try@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" +package-json@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" + dependencies: + got "^6.7.1" + registry-auth-token "^3.0.1" + registry-url "^3.0.3" + semver "^5.1.0" + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -6164,6 +6243,10 @@ prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + prepend-http@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" @@ -6323,7 +6406,7 @@ raw-body@~1.1.0: bytes "1" string_decoder "0.10" -rc@^1.2.7: +rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: version "1.2.8" resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" dependencies: @@ -6491,6 +6574,19 @@ regexpu@^1.3.0: regjsgen "^0.2.0" regjsparser "^0.1.4" +registry-auth-token@^3.0.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" + dependencies: + rc "^1.1.6" + safe-buffer "^5.0.1" + +registry-url@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + dependencies: + rc "^1.0.1" + regjsgen@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" @@ -6501,6 +6597,13 @@ regjsparser@^0.1.4: dependencies: jsesc "~0.5.0" +remote-git-tags@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/remote-git-tags/-/remote-git-tags-2.0.0.tgz#1152f39cf8b5268ae0e4307636ef741ec341664c" + dependencies: + git-fetch-pack "^0.1.1" + git-transport-protocol "^0.1.0" + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -6664,11 +6767,11 @@ rsvp@3.0.14: version "3.0.14" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.14.tgz#9d2968cf36d878d3bb9a9a5a4b8e1ff55a76dd31" -rsvp@4.8.3, rsvp@^4.8.3: +rsvp@4.8.3, rsvp@^4.8.1, rsvp@^4.8.3: version "4.8.3" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.3.tgz#25d4b9fdd0f95e216eb5884d9b3767d3fbfbe2cd" -rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.2.1, rsvp@^3.3.3, rsvp@^3.5.0: +rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.3.3, rsvp@^3.5.0: version "3.6.2" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" @@ -6704,7 +6807,7 @@ safe-buffer@5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -7330,11 +7433,15 @@ through@^2.3.6, through@^2.3.8, through@~2.3.8: version "2.3.8" resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" +through@~2.2.0, through@~2.2.7: + version "2.2.7" + resolved "https://registry.yarnpkg.com/through/-/through-2.2.7.tgz#6e8e21200191d4eb6a99f6f010df46aa1c6eb2bd" + time-zone@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz#99c5bf55958966af6d06d83bdf3800dc82faec5d" -timed-out@^4.0.1: +timed-out@^4.0.0, timed-out@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" @@ -7418,6 +7525,10 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +to-utf8@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" + tough-cookie@>=0.12.0: version "2.4.3" resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" @@ -7552,10 +7663,20 @@ untildify@^2.1.0: dependencies: os-homedir "^1.0.0" +unzip-response@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" + urix@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + dependencies: + prepend-http "^1.0.1" + url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" From df9bb18393a4fc8cd4047cd01b33ac30d8aa350c Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 8 Aug 2018 11:22:20 -0400 Subject: [PATCH 2298/2527] Replace ember-cli-eslint with direct eslint usage. `yarn lint:js` is used by CI to enforce linting, removing ember-cli-eslint effectively means that no linting tests will be done as part of the build. This works around a long standing issue in ember-cli-eslint where the directory provided to eslint when linting is incorrect, which throws an error when `eslint-config-prettier` attempts to read the `.editorconfig` file to infer base settings. --- package.json | 2 +- yarn.lock | 412 +++++++++++++++++++++++++++------------------------ 2 files changed, 220 insertions(+), 194 deletions(-) diff --git a/package.json b/package.json index 9ca094d2fa1..ec43230ce36 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,6 @@ "ember-cli-app-version": "^3.2.0", "ember-cli-blueprint-test-helpers": "^0.18.3", "ember-cli-dependency-checker": "^3.0.0", - "ember-cli-eslint": "^4.2.3", "ember-cli-htmlbars": "^3.0.0", "ember-cli-htmlbars-inline-precompile": "^1.0.3", "ember-cli-inject-live-reload": "^1.8.2", @@ -91,6 +90,7 @@ "ember-source": "~3.0.0", "ember-source-channel-url": "^1.1.0", "ember-try": "^1.0.0-beta.3", + "eslint": "^5.3.0", "eslint-config-prettier": "^2.9.0", "eslint-plugin-node": "^7.0.1", "eslint-plugin-prettier": "2.6.2", diff --git a/yarn.lock b/yarn.lock index 73e6782853c..06b9b5dce52 100644 --- a/yarn.lock +++ b/yarn.lock @@ -194,17 +194,13 @@ acorn-dynamic-import@^3.0.0: dependencies: acorn "^5.0.0" -acorn-jsx@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" +acorn-jsx@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-4.1.1.tgz#e8e41e48ea2fe0c896740610ab6a4ffd8add225e" dependencies: - acorn "^3.0.4" - -acorn@^3.0.4: - version "3.3.0" - resolved "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + acorn "^5.0.3" -acorn@^5.0.0, acorn@^5.2.1, acorn@^5.5.0, acorn@^5.5.3: +acorn@^5.0.0, acorn@^5.0.3, acorn@^5.2.1, acorn@^5.5.3, acorn@^5.6.0: version "5.7.1" resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" @@ -219,18 +215,18 @@ agent-base@2: extend "~3.0.0" semver "~5.0.1" -ajv-keywords@^2.1.0: - version "2.1.1" - resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" +ajv-keywords@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" -ajv@^5.2.3, ajv@^5.3.0: - version "5.5.2" - resolved "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" +ajv@^6.0.1, ajv@^6.5.0: + version "6.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.2.tgz#678495f9b82f7cca6be248dd92f59bff5e1f4360" dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" + fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.1" align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" @@ -262,7 +258,7 @@ ansi-escapes@^1.1.0: ansi-escapes@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" ansi-regex@^2.0.0: version "2.1.1" @@ -300,12 +296,6 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -aot-test-generators@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/aot-test-generators/-/aot-test-generators-0.1.0.tgz#43f0f615f97cb298d7919c1b0b4e6b7310b03cd0" - dependencies: - jsesc "^2.5.0" - aproba@^1.0.3: version "1.2.0" resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -365,13 +355,13 @@ array-to-sentence@^1.1.0: array-union@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" dependencies: array-uniq "^1.0.1" array-uniq@^1.0.1: version "1.0.3" - resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" array-unique@^0.2.1: version "0.2.1" @@ -387,7 +377,7 @@ arraybuffer.slice@~0.0.7: arrify@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" asn1@0.1.11: version "0.1.11" @@ -488,7 +478,7 @@ aws-sign2@~0.5.0: version "0.5.0" resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" -babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: +babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: @@ -1582,18 +1572,6 @@ broccoli-kitchen-sink-helpers@^0.3.1: glob "^5.0.10" mkdirp "^0.5.1" -broccoli-lint-eslint@^4.2.1: - version "4.2.1" - resolved "https://registry.npmjs.org/broccoli-lint-eslint/-/broccoli-lint-eslint-4.2.1.tgz#f780dc083a7357a9746a9cfa8f76feb092777477" - dependencies: - aot-test-generators "^0.1.0" - broccoli-concat "^3.2.2" - broccoli-persistent-filter "^1.4.3" - eslint "^4.0.0" - json-stable-stringify "^1.0.1" - lodash.defaultsdeep "^4.6.0" - md5-hex "^2.0.0" - broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.1, broccoli-merge-trees@^1.2.1: version "1.2.4" resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" @@ -1915,7 +1893,7 @@ calculate-cache-key-for-tree@^1.0.0, calculate-cache-key-for-tree@^1.1.0: caller-path@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" dependencies: callsites "^0.2.0" @@ -1925,7 +1903,7 @@ callsite@1.0.0: callsites@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" camelcase-keys@^2.0.0: version "2.1.0" @@ -2033,7 +2011,7 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4 chardet@^0.4.0: version "0.4.2" - resolved "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" charm@^1.0.0: version "1.0.2" @@ -2070,7 +2048,7 @@ ci-info@^1.1.2: circular-json@^0.3.1: version "0.3.3" - resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" class-utils@^0.3.5: version "0.3.6" @@ -2274,7 +2252,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.7, concat-stream@^1.6.0: +concat-stream@^1.4.7: version "1.6.2" resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" dependencies: @@ -2380,15 +2358,7 @@ create-error-class@^3.0.0: dependencies: capture-stack-trace "^1.0.0" -cross-spawn@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^6.0.0: +cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" dependencies: @@ -2478,7 +2448,7 @@ deep-extend@^0.6.0: deep-is@~0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" defaults@^1.0.3: version "1.0.3" @@ -2486,6 +2456,13 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + define-property@^0.2.5: version "0.2.5" resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" @@ -2526,7 +2503,7 @@ defs@~1.1.0: del@^2.0.2: version "2.2.2" - resolved "https://registry.npmjs.org/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" dependencies: globby "^5.0.0" is-path-cwd "^1.0.0" @@ -2601,7 +2578,7 @@ diff@3.5.0, diff@^3.2.0: doctrine@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" dependencies: esutils "^2.0.2" @@ -2717,15 +2694,6 @@ ember-cli-dependency-checker@^3.0.0: resolve "^1.5.0" semver "^5.3.0" -ember-cli-eslint@^4.2.3: - version "4.2.3" - resolved "https://registry.npmjs.org/ember-cli-eslint/-/ember-cli-eslint-4.2.3.tgz#2844d3f5e8184f19b2d7132ba99eb0b370b55598" - dependencies: - broccoli-lint-eslint "^4.2.1" - ember-cli-version-checker "^2.1.0" - rsvp "^4.6.1" - walk-sync "^0.3.0" - ember-cli-get-component-path-option@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" @@ -3218,6 +3186,24 @@ error@^7.0.0: string-template "~0.2.1" xtend "~4.0.0" +es-abstract@^1.10.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: version "0.10.45" resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz#0bfdf7b473da5919d5adf3bd25ceb754fccc3653" @@ -3301,13 +3287,20 @@ eslint-plugin-prettier@2.6.2: fast-diff "^1.1.1" jest-docblock "^21.0.0" -eslint-scope@3.7.1, eslint-scope@^3.7.1: +eslint-scope@3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + eslint-utils@^1.3.0, eslint-utils@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" @@ -3316,55 +3309,56 @@ eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@^4.0.0: - version "4.19.1" - resolved "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" +eslint@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.3.0.tgz#53695aca5213968aacdf970ccb231e42a2b285f8" dependencies: - ajv "^5.3.0" - babel-code-frame "^6.22.0" + ajv "^6.5.0" + babel-code-frame "^6.26.0" chalk "^2.1.0" - concat-stream "^1.6.0" - cross-spawn "^5.1.0" + cross-spawn "^6.0.5" debug "^3.1.0" doctrine "^2.1.0" - eslint-scope "^3.7.1" + eslint-scope "^4.0.0" + eslint-utils "^1.3.1" eslint-visitor-keys "^1.0.0" - espree "^3.5.4" - esquery "^1.0.0" + espree "^4.0.0" + esquery "^1.0.1" esutils "^2.0.2" file-entry-cache "^2.0.0" functional-red-black-tree "^1.0.1" glob "^7.1.2" - globals "^11.0.1" - ignore "^3.3.3" + globals "^11.7.0" + ignore "^4.0.2" imurmurhash "^0.1.4" - inquirer "^3.0.6" - is-resolvable "^1.0.0" - js-yaml "^3.9.1" + inquirer "^5.2.0" + is-resolvable "^1.1.0" + js-yaml "^3.11.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" - lodash "^4.17.4" - minimatch "^3.0.2" + lodash "^4.17.5" + minimatch "^3.0.4" mkdirp "^0.5.1" natural-compare "^1.4.0" optionator "^0.8.2" path-is-inside "^1.0.2" pluralize "^7.0.0" progress "^2.0.0" - regexpp "^1.0.1" + regexpp "^2.0.0" require-uncached "^1.0.3" - semver "^5.3.0" + semver "^5.5.0" + string.prototype.matchall "^2.0.0" strip-ansi "^4.0.0" - strip-json-comments "~2.0.1" - table "4.0.2" - text-table "~0.2.0" + strip-json-comments "^2.0.1" + table "^4.0.3" + text-table "^0.2.0" -espree@^3.5.4: - version "3.5.4" - resolved "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" +espree@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-4.0.0.tgz#253998f20a0f82db5d866385799d912a83a36634" dependencies: - acorn "^5.5.0" - acorn-jsx "^3.0.0" + acorn "^5.6.0" + acorn-jsx "^4.1.1" esprima-fb@~15001.1001.0-dev-harmony-fb: version "15001.1001.0-dev-harmony-fb" @@ -3390,9 +3384,9 @@ esprimaq@^0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" -esquery@^1.0.0: +esquery@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" dependencies: estraverse "^4.0.0" @@ -3579,9 +3573,9 @@ external-editor@^1.1.0: spawn-sync "^1.0.15" tmp "^0.0.29" -external-editor@^2.0.4: +external-editor@^2.1.0: version "2.2.0" - resolved "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" dependencies: chardet "^0.4.0" iconv-lite "^0.4.17" @@ -3610,9 +3604,9 @@ fake-xml-http-request@^1.6.0: version "1.6.0" resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-1.6.0.tgz#bd0ac79ae3e2660098282048a12c730a6f64d550" -fast-deep-equal@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" fast-diff@^1.1.1: version "1.1.2" @@ -3620,11 +3614,11 @@ fast-diff@^1.1.1: fast-json-stable-stringify@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" fast-levenshtein@~2.0.4: version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: version "1.0.3" @@ -3678,7 +3672,7 @@ figures@^2.0.0: file-entry-cache@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" dependencies: flat-cache "^1.2.1" object-assign "^4.0.1" @@ -3795,7 +3789,7 @@ fixturify@^0.3.2: flat-cache@^1.2.1: version "1.3.0" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" dependencies: circular-json "^0.3.1" del "^2.0.2" @@ -3825,6 +3819,10 @@ for-own@^0.1.4: dependencies: for-in "^1.0.1" +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + forever-agent@~0.5.0: version "0.5.2" resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" @@ -3978,9 +3976,13 @@ fsevents@^1.0.0, fsevents@^1.2.3: nan "^2.9.2" node-pre-gyp "^0.10.0" +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + functional-red-black-tree@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" gauge@~2.7.3: version "2.7.4" @@ -4170,7 +4172,7 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" -globals@^11.0.1, globals@^11.1.0: +globals@^11.1.0, globals@^11.7.0: version "11.7.0" resolved "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" @@ -4184,7 +4186,7 @@ globals@^9.18.0: globby@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" dependencies: array-union "^1.0.1" arrify "^1.0.0" @@ -4281,6 +4283,10 @@ has-symbol-support-x@^1.4.1: version "1.4.2" resolved "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + has-to-string-tag-x@^1.2.0: version "1.4.1" resolved "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" @@ -4318,6 +4324,12 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" +has@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + dependencies: + function-bind "^1.1.1" + hash-for-dep@^1.0.2, hash-for-dep@^1.2.3: version "1.2.3" resolved "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.2.3.tgz#5ec69fca32c23523972d52acb5bb65ffc3664cab" @@ -4472,10 +4484,6 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" -ignore@^3.3.3: - version "3.3.10" - resolved "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" - ignore@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.3.tgz#e2d58c9654d75b542529fa28d80ac95b29e4f467" @@ -4542,21 +4550,20 @@ inquirer@^2: strip-ansi "^3.0.0" through "^2.3.6" -inquirer@^3.0.6: - version "3.3.0" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" +inquirer@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726" dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" cli-cursor "^2.1.0" cli-width "^2.0.0" - external-editor "^2.0.4" + external-editor "^2.1.0" figures "^2.0.0" lodash "^4.3.0" mute-stream "0.0.7" run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" + rxjs "^5.5.2" string-width "^2.1.0" strip-ansi "^4.0.0" through "^2.3.6" @@ -4614,6 +4621,10 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" +is-callable@^1.1.1, is-callable@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -4626,6 +4637,10 @@ is-data-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" @@ -4740,17 +4755,17 @@ is-odd@^2.0.0: is-path-cwd@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" is-path-in-cwd@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" dependencies: is-path-inside "^1.0.0" is-path-inside@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" dependencies: path-is-inside "^1.0.1" @@ -4786,13 +4801,19 @@ is-reference@^1.1.0: dependencies: "@types/estree" "0.0.38" +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" + is-regexp@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" -is-resolvable@^1.0.0: +is-resolvable@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: version "1.1.0" @@ -4802,6 +4823,10 @@ is-stream@^1.0.0, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + is-type@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" @@ -4889,7 +4914,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" -js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.6.1, js-yaml@^3.9.1: +js-yaml@^3.11.0, js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.6.1: version "3.12.0" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" dependencies: @@ -4900,7 +4925,7 @@ jsesc@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" -jsesc@^2.5.0, jsesc@^2.5.1: +jsesc@^2.5.1: version "2.5.1" resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" @@ -4916,13 +4941,13 @@ json-buffer@3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" @@ -5014,7 +5039,7 @@ leven@^1.0.2: levn@^0.3.0, levn@~0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" @@ -5393,7 +5418,7 @@ lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: version "3.10.1" resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: +lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: version "4.17.10" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -5428,13 +5453,6 @@ lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" -lru-cache@^4.0.1: - version "4.1.3" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - magic-string@^0.24.0: version "0.24.1" resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.24.1.tgz#7e38e5f126cae9f15e71f0cf8e450818ca7d5a8f" @@ -5511,16 +5529,6 @@ math-random@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" -md5-hex@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/md5-hex/-/md5-hex-2.0.0.tgz#d0588e9f1c74954492ecd24ac0ac6ce997d92e33" - dependencies: - md5-o-matic "^0.1.1" - -md5-o-matic@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" - mdn-links@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" @@ -5774,7 +5782,7 @@ mute-stream@0.0.6: mute-stream@0.0.7: version "0.0.7" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" nan@^2.9.2: version "2.10.0" @@ -5799,7 +5807,7 @@ nanomatch@^1.2.9: natural-compare@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" needle@^2.2.0: version "2.2.1" @@ -5956,6 +5964,10 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" +object-keys@^1.0.8: + version "1.0.12" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" + object-visit@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" @@ -6010,7 +6022,7 @@ optimist@^0.6.1: optionator@^0.8.2: version "0.8.2" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: deep-is "~0.1.3" fast-levenshtein "~2.0.4" @@ -6175,7 +6187,7 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" @@ -6225,7 +6237,7 @@ pinkie@^2.0.0: pluralize@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" portfinder@^1.0.7: version "1.0.13" @@ -6241,7 +6253,7 @@ posix-character-classes@^0.1.0: prelude-ls@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" prepend-http@^1.0.1: version "1.0.4" @@ -6292,7 +6304,7 @@ process-relative-require@^1.0.0: progress@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" promise-map-series@^0.2.1: version "0.2.3" @@ -6307,10 +6319,6 @@ proxy-addr@~2.0.3: forwarded "~0.1.2" ipaddr.js "1.6.0" -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - psl@^1.1.24: version "1.1.28" resolved "https://registry.npmjs.org/psl/-/psl-1.1.28.tgz#4fb6ceb08a1e2214d4fd4de0ca22dae13740bc7b" @@ -6323,6 +6331,10 @@ punycode@^1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + q@^1.1.2: version "1.5.1" resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -6548,9 +6560,11 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexpp@^1.0.1: - version "1.1.0" - resolved "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" +regexp.prototype.flags@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz#6b30724e306a27833eeb171b66ac8890ba37e41c" + dependencies: + define-properties "^1.1.2" regexpp@^2.0.0: version "2.0.0" @@ -6653,7 +6667,7 @@ require-relative@^0.8.7: require-uncached@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" dependencies: caller-path "^0.1.0" resolve-from "^1.0.0" @@ -6678,7 +6692,7 @@ resolve-dir@^1.0.0, resolve-dir@^1.0.1: resolve-from@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" resolve-url@^0.2.1: version "0.2.1" @@ -6775,7 +6789,7 @@ rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0. version "3.6.2" resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" -rsvp@^4.6.1, rsvp@^4.7.0, rsvp@^4.8.2: +rsvp@^4.7.0, rsvp@^4.8.2: version "4.8.2" resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.2.tgz#9d5647108735784eb13418cdddb56f75b919d722" @@ -6789,20 +6803,16 @@ run-async@^2.2.0: dependencies: is-promise "^2.1.0" -rx-lite-aggregates@^4.0.8: - version "4.0.8" - resolved "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" - dependencies: - rx-lite "*" - -rx-lite@*, rx-lite@^4.0.8: - version "4.0.8" - resolved "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" - rx@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" +rxjs@^5.5.2: + version "5.5.11" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.11.tgz#f733027ca43e3bec6b994473be4ab98ad43ced87" + dependencies: + symbol-observable "1.0.1" + safe-buffer@5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -6971,7 +6981,7 @@ slash@^1.0.0: slice-ansi@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" dependencies: is-fullwidth-code-point "^2.0.0" @@ -7241,6 +7251,16 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string.prototype.matchall@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-2.0.0.tgz#2af8fe3d2d6dc53ca2a59bd376b089c3c152b3c8" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.10.0" + function-bind "^1.1.1" + has-symbols "^1.0.0" + regexp.prototype.flags "^1.2.0" + string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" @@ -7302,7 +7322,7 @@ strip-indent@^1.0.1: dependencies: get-stdin "^4.0.1" -strip-json-comments@~2.0.1: +strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -7326,16 +7346,20 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" +symbol-observable@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" + symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" -table@4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" +table@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" dependencies: - ajv "^5.2.3" - ajv-keywords "^2.1.0" + ajv "^6.0.1" + ajv-keywords "^3.0.0" chalk "^2.1.0" lodash "^4.17.4" slice-ansi "1.0.0" @@ -7417,9 +7441,9 @@ testem@^2.2.0: tap-parser "^7.0.0" xmldom "^0.1.19" -text-table@~0.2.0: +text-table@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" "textextensions@1 || 2": version "2.2.0" @@ -7483,7 +7507,7 @@ tmp@^0.0.29: tmp@^0.0.33: version "0.0.33" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" dependencies: os-tmpdir "~1.0.2" @@ -7568,7 +7592,7 @@ tunnel-agent@~0.4.0: type-check@~0.3.2: version "0.3.2" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" dependencies: prelude-ls "~1.1.2" @@ -7667,6 +7691,12 @@ unzip-response@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" +uri-js@^4.2.1: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + dependencies: + punycode "^2.1.0" + urix@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" @@ -7843,7 +7873,7 @@ wordwrap@~0.0.2: wordwrap@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" workerpool@^2.3.0: version "2.3.0" @@ -7865,7 +7895,7 @@ write-file-atomic@^2.0.0: write@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" dependencies: mkdirp "^0.5.1" @@ -7910,10 +7940,6 @@ y18n@^3.2.0: version "3.2.1" resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - yallist@^3.0.0, yallist@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" From 99d363523e2948d38ed8e99dd2d399830f85efc5 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 8 Aug 2018 14:04:43 -0400 Subject: [PATCH 2299/2527] Fixup transpilation issues with @ember/ordered-set. (#5557) * Ensure tests run minimally transpiled. * Add specific test run for full transpilation. * [BUGFIX beta] Prevent transpilation issues with @ember/ordered-set. * Fix ES compatibility issues. These cases were all previously working due to transpilation from `let` to `var`. You *cannot* reference a block scoped variable (`let` / `const`) during the variables own initializer. --- .travis.yml | 5 ++ .../system/model/internal-model.js | 2 +- addon/-private/system/ordered-set.js | 47 ++++++++----------- .../system/model/internal-model.js | 2 +- tests/dummy/config/targets.js | 13 +++++ tests/integration/store-test.js | 4 +- tests/unit/model-test.js | 14 +++--- tests/unit/model/rollback-attributes-test.js | 8 +++- 8 files changed, 55 insertions(+), 40 deletions(-) create mode 100644 tests/dummy/config/targets.js diff --git a/.travis.yml b/.travis.yml index 08df190252f..27582faad4e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,6 +47,11 @@ jobs: install: yarn install --no-lockfile --non-interactive script: yarn test + - name: "Max Transpilation" + install: yarn install + env: TARGET_IE11=true + script: yarn test + - env: NAME=production # used only to make Travis UI show description install: yarn install script: yarn test:production diff --git a/addon/-legacy-private/system/model/internal-model.js b/addon/-legacy-private/system/model/internal-model.js index b162c058317..73d53c4c2cd 100644 --- a/addon/-legacy-private/system/model/internal-model.js +++ b/addon/-legacy-private/system/model/internal-model.js @@ -181,7 +181,7 @@ export default class InternalModel { get _recordArrays() { if (this.__recordArrays === null) { - this.__recordArrays = OrderedSet.create(); + this.__recordArrays = new OrderedSet(); } return this.__recordArrays; } diff --git a/addon/-private/system/ordered-set.js b/addon/-private/system/ordered-set.js index 27a6205057c..0dcf16433fa 100644 --- a/addon/-private/system/ordered-set.js +++ b/addon/-private/system/ordered-set.js @@ -1,37 +1,30 @@ import EmberOrderedSet from '@ember/ordered-set'; import { guidFor } from '@ember/object/internals'; -export default function OrderedSet() { - this._super$constructor(); -} +export default class EmberDataOrderedSet extends EmberOrderedSet { + static create() { + return new this(); + } -OrderedSet.create = function() { - let Constructor = this; - return new Constructor(); -}; + addWithIndex(obj, idx) { + let guid = guidFor(obj); + let presenceSet = this.presenceSet; + let list = this.list; -OrderedSet.prototype = Object.create(EmberOrderedSet.prototype); -OrderedSet.prototype.constructor = OrderedSet; -OrderedSet.prototype._super$constructor = EmberOrderedSet; + if (presenceSet[guid] === true) { + return; + } -OrderedSet.prototype.addWithIndex = function(obj, idx) { - let guid = guidFor(obj); - let presenceSet = this.presenceSet; - let list = this.list; + presenceSet[guid] = true; - if (presenceSet[guid] === true) { - return; - } + if (idx === undefined || idx === null) { + list.push(obj); + } else { + list.splice(idx, 0, obj); + } - presenceSet[guid] = true; + this.size += 1; - if (idx === undefined || idx === null) { - list.push(obj); - } else { - list.splice(idx, 0, obj); + return this; } - - this.size += 1; - - return this; -}; +} diff --git a/addon/-record-data-private/system/model/internal-model.js b/addon/-record-data-private/system/model/internal-model.js index b13bf977129..39728e2b0b5 100644 --- a/addon/-record-data-private/system/model/internal-model.js +++ b/addon/-record-data-private/system/model/internal-model.js @@ -145,7 +145,7 @@ export default class InternalModel { get _recordArrays() { if (this.__recordArrays === null) { - this.__recordArrays = OrderedSet.create(); + this.__recordArrays = new OrderedSet(); } return this.__recordArrays; } diff --git a/tests/dummy/config/targets.js b/tests/dummy/config/targets.js new file mode 100644 index 00000000000..2e8b5f14f4a --- /dev/null +++ b/tests/dummy/config/targets.js @@ -0,0 +1,13 @@ +'use strict'; + +const browsers = ['last 1 Chrome versions', 'last 1 Firefox versions', 'last 1 Safari versions']; + +const needsIE11 = !!process.env.TARGET_IE11; + +if (needsIE11) { + browsers.push('ie 11'); +} + +module.exports = { + browsers, +}; diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 207b653e201..175bf80c4da 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -174,9 +174,9 @@ test('destroying the store correctly cleans everything up', function(assert) { }; let adapterPopulatedPeople = run(() => { - return (adapterPopulatedPeople = store.query('person', { + return store.query('person', { someCrazy: 'query', - })); + }); }); let adapterPopulatedPeopleWillDestroy = tap(adapterPopulatedPeople.get('content'), 'willDestroy'); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 9a8c00c256c..22fcbc35d1e 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -889,10 +889,10 @@ test(`a DS.model can define 'setUnknownProperty'`, function(assert) { }); let tag = run(() => { - tag = store.createRecord('tag', { name: 'old' }); - set(tag, 'title', 'new'); + let record = store.createRecord('tag', { name: 'old' }); + set(record, 'title', 'new'); - return tag; + return record; }); assert.equal(get(tag, 'name'), 'new', 'setUnknownProperty not triggered'); @@ -963,12 +963,12 @@ test('setting a property to undefined on a newly created record should not impac }); let tag = run(() => { - tag = store.createRecord('tag'); + let record = store.createRecord('tag'); - set(tag, 'name', 'testing'); - set(tag, 'name', undefined); + set(record, 'name', 'testing'); + set(record, 'name', undefined); - return tag; + return record; }); assert.equal(get(tag, 'currentState.stateName'), 'root.loaded.created.uncommitted'); diff --git a/tests/unit/model/rollback-attributes-test.js b/tests/unit/model/rollback-attributes-test.js index 9cd25a23988..13aa1f365c1 100644 --- a/tests/unit/model/rollback-attributes-test.js +++ b/tests/unit/model/rollback-attributes-test.js @@ -32,7 +32,9 @@ module('unit/model/rollbackAttributes - model.rollbackAttributes()', { }); test('changes to attributes can be rolled back', function(assert) { - let person = run(() => { + let person; + + run(() => { store.push({ data: { type: 'person', @@ -59,7 +61,9 @@ test('changes to attributes can be rolled back', function(assert) { }); test('changes to unassigned attributes can be rolled back', function(assert) { - let person = run(() => { + let person; + + run(() => { store.push({ data: { type: 'person', From 35fc8fe8ef30c2c9e0862a91c227ccadea4b3623 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 8 Aug 2018 12:10:22 -0400 Subject: [PATCH 2300/2527] Remove deps supporting non-supported Ember versions. Ember Data's "official" (citation needed :troll:) policy is to support "supported Ember versions". Currently that means 2.16, 2.18, and 3.3. Both of these dependencies are supporting Ember versions _older_ than 2.16: - `ember-runtime-enumerable-includes-polyfill` supports Ember < 2.8 - `ember-disable-proxy-controllers` disables a feature that has been disabled by default since Ember 2.0 (`Ember.ObjectController` and `Ember.ArrayController`) :wave: farewell old friends... --- package.json | 2 - yarn.lock | 458 ++------------------------------------------------- 2 files changed, 16 insertions(+), 444 deletions(-) diff --git a/package.json b/package.json index ec43230ce36..b61d4ecdf84 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,6 @@ "ember-cli-test-info": "^1.0.0", "ember-cli-version-checker": "^2.1.2", "ember-inflector": "^3.0.0", - "ember-runtime-enumerable-includes-polyfill": "^2.1.0", "git-repo-info": "^2.0.0", "heimdalljs": "^0.3.0", "inflection": "^1.12.0", @@ -79,7 +78,6 @@ "ember-cli-yuidoc": "^0.8.8", "ember-decorators": "^2.3.1", "ember-disable-prototype-extensions": "^1.1.3", - "ember-disable-proxy-controllers": "^1.0.1", "ember-export-application-global": "^2.0.0", "ember-load-initializers": "^1.1.0", "ember-maybe-import-regenerator": "^0.1.6", diff --git a/yarn.lock b/yarn.lock index 06b9b5dce52..1d0bad8686f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -200,7 +200,7 @@ acorn-jsx@^4.1.1: dependencies: acorn "^5.0.3" -acorn@^5.0.0, acorn@^5.0.3, acorn@^5.2.1, acorn@^5.5.3, acorn@^5.6.0: +acorn@^5.0.0, acorn@^5.0.3, acorn@^5.5.3, acorn@^5.6.0: version "5.7.1" resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" @@ -236,12 +236,6 @@ align-text@^0.1.1, align-text@^0.1.3: longest "^1.0.1" repeat-string "^1.5.2" -alter@~0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" - dependencies: - stable "~0.1.3" - amd-name-resolver@1.2.0, amd-name-resolver@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz#fc41b3848824b557313897d71f8d5a0184fbe679" @@ -395,18 +389,6 @@ assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" -ast-traverse@~0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" - -ast-types@0.8.12: - version "0.8.12" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" - -ast-types@0.8.15: - version "0.8.15" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz#8eef0827f04dff0ec8857ba925abe3fea6194e52" - ast-types@0.9.6: version "0.9.6" resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" @@ -486,57 +468,6 @@ babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-core@^5.0.0: - version "5.8.38" - resolved "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" - dependencies: - babel-plugin-constant-folding "^1.0.1" - babel-plugin-dead-code-elimination "^1.0.2" - babel-plugin-eval "^1.0.1" - babel-plugin-inline-environment-variables "^1.0.1" - babel-plugin-jscript "^1.0.4" - babel-plugin-member-expression-literals "^1.0.1" - babel-plugin-property-literals "^1.0.1" - babel-plugin-proto-to-assign "^1.0.3" - babel-plugin-react-constant-elements "^1.0.3" - babel-plugin-react-display-name "^1.0.3" - babel-plugin-remove-console "^1.0.1" - babel-plugin-remove-debugger "^1.0.1" - babel-plugin-runtime "^1.0.7" - babel-plugin-undeclared-variables-check "^1.0.2" - babel-plugin-undefined-to-void "^1.1.6" - babylon "^5.8.38" - bluebird "^2.9.33" - chalk "^1.0.0" - convert-source-map "^1.1.0" - core-js "^1.0.0" - debug "^2.1.1" - detect-indent "^3.0.0" - esutils "^2.0.0" - fs-readdir-recursive "^0.1.0" - globals "^6.4.0" - home-or-tmp "^1.0.0" - is-integer "^1.0.4" - js-tokens "1.0.1" - json5 "^0.4.0" - lodash "^3.10.0" - minimatch "^2.0.3" - output-file-sync "^1.1.0" - path-exists "^1.0.0" - path-is-absolute "^1.0.0" - private "^0.1.6" - regenerator "0.8.40" - regexpu "^1.3.0" - repeating "^1.1.2" - resolve "^1.1.6" - shebang-regex "^1.0.0" - slash "^1.0.0" - source-map "^0.5.0" - source-map-support "^0.2.10" - to-fast-properties "^1.0.0" - trim-right "^1.0.0" - try-resolve "^1.0.0" - babel-core@^6.26.0: version "6.26.3" resolved "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" @@ -698,14 +629,6 @@ babel-plugin-check-es2015-constants@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-constant-folding@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" - -babel-plugin-dead-code-elimination@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" - babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.11: version "0.1.11" resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" @@ -724,10 +647,6 @@ babel-plugin-ember-modules-api-polyfill@^2.3.0, babel-plugin-ember-modules-api-p dependencies: ember-rfc176-data "^0.3.0" -babel-plugin-eval@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" - babel-plugin-feature-flags@^0.3.1: version "0.3.1" resolved "https://registry.npmjs.org/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" @@ -740,48 +659,6 @@ babel-plugin-htmlbars-inline-precompile@^0.2.5: version "0.2.5" resolved "https://registry.npmjs.org/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.5.tgz#7a7c37cf22c73fb57a1f828c76520f0360c5c5f3" -babel-plugin-inline-environment-variables@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" - -babel-plugin-jscript@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" - -babel-plugin-member-expression-literals@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" - -babel-plugin-property-literals@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" - -babel-plugin-proto-to-assign@^1.0.3: - version "1.0.4" - resolved "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" - dependencies: - lodash "^3.9.3" - -babel-plugin-react-constant-elements@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" - -babel-plugin-react-display-name@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" - -babel-plugin-remove-console@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" - -babel-plugin-remove-debugger@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" - -babel-plugin-runtime@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" - babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" @@ -1016,16 +893,6 @@ babel-plugin-transform-strict-mode@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-plugin-undeclared-variables-check@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" - dependencies: - leven "^1.0.2" - -babel-plugin-undefined-to-void@^1.1.6: - version "1.1.6" - resolved "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" - babel-polyfill@^6.26.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" @@ -1133,10 +1000,6 @@ babylon@7.0.0-beta.44: version "7.0.0-beta.44" resolved "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" -babylon@^5.8.38: - version "5.8.38" - resolved "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" - babylon@^6.18.0: version "6.18.0" resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" @@ -1211,10 +1074,6 @@ blob@0.0.4: version "0.0.4" resolved "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" -bluebird@^2.9.33: - version "2.11.0" - resolved "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" - bluebird@^3.1.1, bluebird@^3.4.6: version "3.5.1" resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" @@ -1300,10 +1159,6 @@ braces@^2.3.1: split-string "^3.0.2" to-regex "^3.0.1" -breakable@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" - broccoli-amd-funnel@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/broccoli-amd-funnel/-/broccoli-amd-funnel-1.3.0.tgz#c4426b4fce976e44295bd74f34725f53bdeb08e3" @@ -1328,21 +1183,6 @@ broccoli-asset-rewrite@^1.1.0: dependencies: broccoli-filter "^1.2.3" -broccoli-babel-transpiler@^5.6.2: - version "5.7.4" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-5.7.4.tgz#2b0611ce9e5d98b8d8d2b49ae1219af2f52767e3" - dependencies: - babel-core "^5.0.0" - broccoli-funnel "^1.0.0" - broccoli-merge-trees "^1.0.0" - broccoli-persistent-filter "^1.4.2" - clone "^0.2.0" - hash-for-dep "^1.0.2" - heimdalljs-logger "^0.1.7" - json-stable-stringify "^1.0.0" - rsvp "^3.5.0" - workerpool "^2.3.0" - broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.4.2: version "6.4.3" resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.4.3.tgz#06e399298d41700cdc10d675b1d808a89ef6b2d0" @@ -1627,7 +1467,7 @@ broccoli-node-info@1.1.0, broccoli-node-info@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" -broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.4.2, broccoli-persistent-filter@^1.4.3: +broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.4.3: version "1.4.3" resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz#3511bc52fc53740cda51621f58a28152d9911bc1" dependencies: @@ -1912,7 +1752,7 @@ camelcase-keys@^2.0.0: camelcase "^2.0.0" map-obj "^1.0.0" -camelcase@^1.0.2, camelcase@^1.2.1: +camelcase@^1.0.2: version "1.2.1" resolved "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" @@ -2131,10 +1971,6 @@ clone-response@1.0.2: dependencies: mimic-response "^1.0.0" -clone@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" - clone@^1.0.2: version "1.0.4" resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" @@ -2204,20 +2040,6 @@ common-tags@^1.4.0, common-tags@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" -commoner@~0.10.3: - version "0.10.8" - resolved "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" - dependencies: - commander "^2.5.0" - detective "^4.3.1" - glob "^5.0.15" - graceful-fs "^4.1.2" - iconv-lite "^0.4.5" - mkdirp "^0.5.0" - private "^0.1.6" - q "^1.1.2" - recast "^0.11.17" - component-bind@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" @@ -2314,7 +2136,7 @@ continuable-cache@^0.3.1: version "0.3.1" resolved "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" -convert-source-map@^1.1.0, convert-source-map@^1.5.1: +convert-source-map@^1.5.1: version "1.5.1" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" @@ -2334,10 +2156,6 @@ copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" -core-js@^1.0.0: - version "1.2.7" - resolved "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" - core-js@^2.4.0, core-js@^2.5.0: version "2.5.7" resolved "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" @@ -2482,25 +2300,6 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -defined@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - -defs@~1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" - dependencies: - alter "~0.2.0" - ast-traverse "~0.1.1" - breakable "~1.0.0" - esprima-fb "~15001.1001.0-dev-harmony-fb" - simple-fmt "~0.1.0" - simple-is "~0.2.0" - stringmap "~0.2.2" - stringset "~0.2.1" - tryor "~0.1.2" - yargs "~3.27.0" - del@^2.0.2: version "2.2.2" resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" @@ -2543,14 +2342,6 @@ detect-file@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" -detect-indent@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" - dependencies: - get-stdin "^4.0.1" - minimist "^1.1.0" - repeating "^1.1.0" - detect-indent@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" @@ -2565,13 +2356,6 @@ detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" -detective@^4.3.1: - version "4.7.1" - resolved "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz#0eca7314338442febb6d65da54c10bb1c82b246e" - dependencies: - acorn "^5.2.1" - defined "^1.0.0" - diff@3.5.0, diff@^3.2.0: version "3.5.0" resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -2615,16 +2399,6 @@ ember-cli-app-version@^3.2.0: ember-cli-babel "^6.12.0" git-repo-version "^1.0.2" -ember-cli-babel@^5.0.0: - version "5.2.8" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-5.2.8.tgz#0356b03cc3fdff5d0f2ecaa46a0e1cfaebffd876" - dependencies: - broccoli-babel-transpiler "^5.6.2" - broccoli-funnel "^1.0.0" - clone "^2.0.0" - ember-cli-version-checker "^1.0.2" - resolve "^1.1.2" - ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: version "6.14.1" resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.14.1.tgz#796339229035910b625593caffbc2683792ada68" @@ -2843,12 +2617,6 @@ ember-cli-valid-component-name@^1.0.0: dependencies: silent-error "^1.0.0" -ember-cli-version-checker@^1.0.2: - version "1.3.1" - resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-1.3.1.tgz#0bc2d134c830142da64bf9627a0eded10b61ae72" - dependencies: - semver "^5.3.0" - ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-version-checker@^2.1.1, ember-cli-version-checker@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-2.1.2.tgz#305ce102390c66e4e0f1432dea9dc5c7c19fed98" @@ -2981,12 +2749,6 @@ ember-disable-prototype-extensions@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" -ember-disable-proxy-controllers@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/ember-disable-proxy-controllers/-/ember-disable-proxy-controllers-1.0.1.tgz#1254eeec0ba025c24eb9e8da611afa7b38754281" - dependencies: - ember-cli-babel "^5.0.0" - ember-export-application-global@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ember-export-application-global/-/ember-export-application-global-2.0.0.tgz#8d6d7619ac8a1a3f8c43003549eb21ebed685bd2" @@ -3061,13 +2823,6 @@ ember-router-generator@^1.2.3: dependencies: recast "^0.11.3" -ember-runtime-enumerable-includes-polyfill@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ember-runtime-enumerable-includes-polyfill/-/ember-runtime-enumerable-includes-polyfill-2.1.0.tgz#dc6d4a028471e4acc350dfd2a149874fb20913f5" - dependencies: - ember-cli-babel "^6.9.0" - ember-cli-version-checker "^2.1.0" - ember-source-channel-url@^1.0.1, ember-source-channel-url@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ember-source-channel-url/-/ember-source-channel-url-1.1.0.tgz#73de5cc6ebc25b2120e932ec1d8f82677bfaf6ef" @@ -3360,14 +3115,6 @@ espree@^4.0.0: acorn "^5.6.0" acorn-jsx "^4.1.1" -esprima-fb@~15001.1001.0-dev-harmony-fb: - version "15001.1001.0-dev-harmony-fb" - resolved "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" - -esprima@^2.6.0: - version "2.7.3" - resolved "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" - esprima@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" @@ -3404,7 +3151,7 @@ estree-walker@^0.5.2: version "0.5.2" resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-0.5.2.tgz#d3850be7529c9580d815600b53126515e146dd39" -esutils@^2.0.0, esutils@^2.0.2: +esutils@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -3932,10 +3679,6 @@ fs-minipass@^1.2.5: dependencies: minipass "^2.2.1" -fs-readdir-recursive@^0.1.0: - version "0.1.2" - resolved "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" - fs-sync@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" @@ -4128,7 +3871,7 @@ glob@^4.3.2: minimatch "^2.0.1" once "^1.3.0" -glob@^5.0.10, glob@^5.0.15: +glob@^5.0.10: version "5.0.15" resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: @@ -4176,10 +3919,6 @@ globals@^11.1.0, globals@^11.7.0: version "11.7.0" resolved "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" -globals@^6.4.0: - version "6.4.1" - resolved "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" - globals@^9.18.0: version "9.18.0" resolved "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -4233,7 +3972,7 @@ got@^8.0.1: url-parse-lax "^3.0.0" url-to-options "^1.0.1" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -4386,13 +4125,6 @@ hoek@0.9.x: version "0.9.1" resolved "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" -home-or-tmp@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" - dependencies: - os-tmpdir "^1.0.1" - user-home "^1.1.1" - home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -4464,7 +4196,7 @@ iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" -iconv-lite@^0.4.13, iconv-lite@^0.4.17, iconv-lite@^0.4.4, iconv-lite@^0.4.5: +iconv-lite@^0.4.13, iconv-lite@^0.4.17, iconv-lite@^0.4.4: version "0.4.23" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: @@ -4581,10 +4313,6 @@ invariant@^2.2.0, invariant@^2.2.2: dependencies: loose-envify "^1.0.0" -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - ipaddr.js@1.6.0: version "1.6.0" resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" @@ -4717,12 +4445,6 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-integer@^1.0.4: - version "1.0.7" - resolved "https://registry.npmjs.org/is-integer/-/is-integer-1.0.7.tgz#6bde81aacddf78b659b6629d629cadc51a886d5c" - dependencies: - is-finite "^1.0.0" - is-number@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" @@ -4906,10 +4628,6 @@ js-reporters@1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b" -js-tokens@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" - js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" @@ -4959,10 +4677,6 @@ json-stringify-safe@~5.0.0: version "5.0.1" resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" -json5@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" - json5@^0.5.1: version "0.5.1" resolved "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" @@ -5019,12 +4733,6 @@ lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - dependencies: - invert-kv "^1.0.0" - leek@0.0.24: version "0.0.24" resolved "https://registry.npmjs.org/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" @@ -5033,10 +4741,6 @@ leek@0.0.24: lodash.assign "^3.2.0" rsvp "^3.0.21" -leven@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" - levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -5414,7 +5118,7 @@ lodash.values@~2.3.0: dependencies: lodash.keys "~2.3.0" -lodash@^3.10.0, lodash@^3.10.1, lodash@^3.9.3: +lodash@^3.10.1: version "3.10.1" resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" @@ -5672,7 +5376,7 @@ mimic-response@^1.0.0: dependencies: brace-expansion "^1.1.7" -minimatch@^2.0.1, minimatch@^2.0.3: +minimatch@^2.0.1: version "2.0.10" resolved "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" dependencies: @@ -5682,7 +5386,7 @@ minimist@0.0.8: version "0.0.8" resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: +minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -6046,12 +5750,6 @@ os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" -os-locale@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" - dependencies: - lcid "^1.0.0" - os-shim@^0.1.2: version "0.1.3" resolved "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" @@ -6067,14 +5765,6 @@ osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4, osenv@^0.1.5: os-homedir "^1.0.0" os-tmpdir "^1.0.0" -output-file-sync@^1.1.0: - version "1.1.2" - resolved "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" - dependencies: - graceful-fs "^4.1.4" - mkdirp "^0.5.1" - object-assign "^4.1.0" - p-cancelable@^0.4.0: version "0.4.1" resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" @@ -6167,10 +5857,6 @@ passwd-user@^1.2.1: dependencies: exec-file-sync "^2.0.0" -path-exists@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" - path-exists@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" @@ -6335,10 +6021,6 @@ punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" -q@^1.1.2: - version "1.5.1" - resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - qs@6.5.1: version "6.5.1" resolved "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" @@ -6472,25 +6154,7 @@ readdirp@^2.0.0: readable-stream "^2.0.2" set-immediate-shim "^1.0.1" -recast@0.10.33: - version "0.10.33" - resolved "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" - dependencies: - ast-types "0.8.12" - esprima-fb "~15001.1001.0-dev-harmony-fb" - private "~0.1.5" - source-map "~0.5.0" - -recast@^0.10.10: - version "0.10.43" - resolved "https://registry.npmjs.org/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" - dependencies: - ast-types "0.8.15" - esprima-fb "~15001.1001.0-dev-harmony-fb" - private "~0.1.5" - source-map "~0.5.0" - -recast@^0.11.17, recast@^0.11.3: +recast@^0.11.3: version "0.11.23" resolved "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" dependencies: @@ -6536,17 +6200,6 @@ regenerator-transform@^0.10.0: babel-types "^6.19.0" private "^0.1.6" -regenerator@0.8.40: - version "0.8.40" - resolved "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" - dependencies: - commoner "~0.10.3" - defs "~1.1.0" - esprima-fb "~15001.1001.0-dev-harmony-fb" - private "~0.1.5" - recast "0.10.33" - through "~2.3.8" - regex-cache@^0.4.2: version "0.4.4" resolved "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" @@ -6578,16 +6231,6 @@ regexpu-core@^2.0.0: regjsgen "^0.2.0" regjsparser "^0.1.4" -regexpu@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" - dependencies: - esprima "^2.6.0" - recast "^0.10.10" - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - registry-auth-token@^3.0.1: version "3.3.2" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" @@ -6630,12 +6273,6 @@ repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" -repeating@^1.1.0, repeating@^1.1.2: - version "1.1.3" - resolved "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" - dependencies: - is-finite "^1.0.0" - repeating@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" @@ -6704,7 +6341,7 @@ resolve@1.5.0: dependencies: path-parse "^1.0.5" -resolve@^1.1.2, resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.7.1, resolve@^1.8.1: +resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.7.1, resolve@^1.8.1: version "1.8.1" resolved "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" dependencies: @@ -6967,14 +6604,6 @@ silent-error@^1.0.0, silent-error@^1.0.1, silent-error@^1.1.0: dependencies: debug "^2.2.0" -simple-fmt@~0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" - -simple-is@~0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" - slash@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" @@ -7087,12 +6716,6 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.2.10: - version "0.2.10" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" - dependencies: - source-map "0.1.32" - source-map-support@^0.4.15: version "0.4.18" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" @@ -7107,12 +6730,6 @@ source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" -source-map@0.1.32: - version "0.1.32" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" - dependencies: - amdefine ">=0.0.4" - source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: version "0.4.4" resolved "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" @@ -7201,10 +6818,6 @@ sri-toolbox@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" -stable@~0.1.3: - version "0.1.8" - resolved "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" - static-extend@^0.1.1: version "0.1.2" resolved "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -7278,14 +6891,6 @@ stringify-object-es5@^2.5.0: is-plain-obj "^1.0.0" is-regexp "^1.0.0" -stringmap@~0.2.2: - version "0.2.2" - resolved "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" - -stringset@~0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" - stringstream@~0.0.4: version "0.0.6" resolved "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" @@ -7453,7 +7058,7 @@ theredoc@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/theredoc/-/theredoc-1.0.0.tgz#bcace376af6feb1873efbdd0f91ed026570ff062" -through@^2.3.6, through@^2.3.8, through@~2.3.8: +through@^2.3.6, through@^2.3.8: version "2.3.8" resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -7519,7 +7124,7 @@ to-array@0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" -to-fast-properties@^1.0.0, to-fast-properties@^1.0.3: +to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" @@ -7574,18 +7179,10 @@ trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" -trim-right@^1.0.0, trim-right@^1.0.1: +trim-right@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" -try-resolve@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" - -tryor@~0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" - tunnel-agent@~0.4.0: version "0.4.3" resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" @@ -7730,10 +7327,6 @@ use@^3.1.0: dependencies: kind-of "^6.0.2" -user-home@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" - user-info@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/user-info/-/user-info-1.0.0.tgz#81c82b7ed63e674c2475667653413b3c76fde239" @@ -7859,10 +7452,6 @@ window-size@0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" -window-size@^0.1.2: - version "0.1.4" - resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" - wordwrap@0.0.2: version "0.0.2" resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" @@ -7936,10 +7525,6 @@ xtend@^4.0.0, xtend@~4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" -y18n@^3.2.0: - version "3.2.1" - resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - yallist@^3.0.0, yallist@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" @@ -7960,17 +7545,6 @@ yargs@~3.10.0: decamelize "^1.0.0" window-size "0.1.0" -yargs@~3.27.0: - version "3.27.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" - dependencies: - camelcase "^1.2.1" - cliui "^2.1.0" - decamelize "^1.0.0" - os-locale "^1.4.0" - window-size "^0.1.2" - y18n "^3.2.0" - yeast@0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" From ece04949ecfd84c491490dd9a110e02d2ff0afa4 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 23 Jul 2018 15:13:59 -0700 Subject: [PATCH 2301/2527] fix createRecord re-fetch --- .../relationships/state/relationship.js | 12 ++++----- .../relationships/state/relationship.js | 27 +++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/addon/-legacy-private/system/relationships/state/relationship.js b/addon/-legacy-private/system/relationships/state/relationship.js index e53e2f1c76c..77e26f374a6 100644 --- a/addon/-legacy-private/system/relationships/state/relationship.js +++ b/addon/-legacy-private/system/relationships/state/relationship.js @@ -522,7 +522,7 @@ export default class Relationship { this.store._updateRelationshipState(this); } - updateLink(link, initial) { + updateLink(link) { heimdall.increment(updateLink); warn( `You pushed a record of type '${this.internalModel.modelName}' with a relationship '${ @@ -543,10 +543,6 @@ export default class Relationship { this.link = link; this.fetchPromise = null; this.setRelationshipIsStale(true); - - if (!initial) { - this.internalModel.notifyPropertyChange(this.key); - } } reload() { @@ -708,7 +704,7 @@ export default class Relationship { let relatedLink = _normalizeLink(payload.links.related); if (relatedLink && relatedLink.href && relatedLink.href !== this.link) { hasLink = true; - this.updateLink(relatedLink.href, initial); + this.updateLink(relatedLink.href); } } @@ -736,6 +732,10 @@ export default class Relationship { this.setRelationshipIsEmpty(relationshipIsEmpty); } else if (hasLink) { this.setRelationshipIsStale(true); + + if (!initial) { + this.internalModel.notifyPropertyChange(this.key); + } } } diff --git a/addon/-record-data-private/system/relationships/state/relationship.js b/addon/-record-data-private/system/relationships/state/relationship.js index 5122d633e31..48f5d57f7cc 100644 --- a/addon/-record-data-private/system/relationships/state/relationship.js +++ b/addon/-record-data-private/system/relationships/state/relationship.js @@ -568,7 +568,7 @@ export default class Relationship { this.store._updateRelationshipState(this); } - updateLink(link, initial) { + updateLink(link) { heimdall.increment(updateLink); warn( `You pushed a record of type '${this.modelData.modelName}' with a relationship '${ @@ -587,18 +587,6 @@ export default class Relationship { ); this.link = link; - this.setRelationshipIsStale(true); - - if (!initial) { - let modelData = this.modelData; - let storeWrapper = this.modelData.storeWrapper; - storeWrapper.notifyPropertyChange( - modelData.modelName, - modelData.id, - modelData.clientId, - this.key - ); - } } updateModelDatasFromAdapter(modelDatas) { @@ -659,7 +647,7 @@ export default class Relationship { let relatedLink = _normalizeLink(payload.links.related); if (relatedLink && relatedLink.href && relatedLink.href !== this.link) { hasLink = true; - this.updateLink(relatedLink.href, initial); + this.updateLink(relatedLink.href); } } @@ -688,6 +676,17 @@ export default class Relationship { this.setRelationshipIsEmpty(relationshipIsEmpty); } else if (hasLink) { this.setRelationshipIsStale(true); + + if (!initial) { + let modelData = this.modelData; + let storeWrapper = this.modelData.storeWrapper; + storeWrapper.notifyPropertyChange( + modelData.modelName, + modelData.id, + modelData.clientId, + this.key + ); + } } } From 4ca3437c8d952ea5e8f948d12f032bc7af35f330 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 8 Aug 2018 11:51:27 -0700 Subject: [PATCH 2302/2527] Ensure that CI runs for backports to old releases --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 27582faad4e..e01679e06b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,8 @@ branches: - master - beta - release + # release branches + - /^release-.*/ # npm version tags - /^v\d+\.\d+\.\d+/ From 9ebd2fe49b993e07399f4f998d6707420bf4e52b Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Wed, 8 Aug 2018 11:08:36 -0400 Subject: [PATCH 2303/2527] Bump default scenario ember-source version. --- package.json | 2 +- yarn.lock | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index b61d4ecdf84..2c77a780595 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "ember-qunit": "^3.4.1", "ember-qunit-assert-helpers": "^0.2.1", "ember-resolver": "^5.0.1", - "ember-source": "~3.0.0", + "ember-source": "~3.3.0", "ember-source-channel-url": "^1.1.0", "ember-try": "^1.0.0-beta.3", "eslint": "^5.3.0", diff --git a/yarn.lock b/yarn.lock index 1d0bad8686f..29a9a783e4e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2829,12 +2829,13 @@ ember-source-channel-url@^1.0.1, ember-source-channel-url@^1.1.0: dependencies: got "^8.0.1" -ember-source@~3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/ember-source/-/ember-source-3.0.0.tgz#51811cae98d2ceec53bcfbaa876d02b2b5b2159f" +ember-source@~3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-3.3.1.tgz#bcac785b32d5e99867e236979c3fb34536659ecd" dependencies: broccoli-funnel "^2.0.1" broccoli-merge-trees "^2.0.0" + chalk "^2.3.0" ember-cli-get-component-path-option "^1.0.0" ember-cli-is-package-missing "^1.0.0" ember-cli-normalize-entity-name "^1.0.0" @@ -2844,8 +2845,8 @@ ember-source@~3.0.0: ember-cli-version-checker "^2.1.0" ember-router-generator "^1.2.3" inflection "^1.12.0" - jquery "^3.2.1" - resolve "^1.3.3" + jquery "^3.3.1" + resolve "^1.6.0" ember-try-config@^3.0.0: version "3.0.0" @@ -4620,9 +4621,9 @@ jmespath@0.15.0: version "0.15.0" resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" -jquery@^3.2.1: +jquery@^3.3.1: version "3.3.1" - resolved "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" js-reporters@1.2.1: version "1.2.1" @@ -6341,7 +6342,7 @@ resolve@1.5.0: dependencies: path-parse "^1.0.5" -resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.7.1, resolve@^1.8.1: +resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.7.1, resolve@^1.8.1: version "1.8.1" resolved "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" dependencies: From 5dad50b6ac3015ac86d102b5fa8c46020ca6364a Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 8 Aug 2018 17:00:34 -0700 Subject: [PATCH 2304/2527] [BUGFIX] use internalModel promise if already loading (#5562) * use internalModel promise if already loading * add tests * prettier to the prettier gods --- .../system/relationships/state/belongs-to.js | 7 +- addon/-record-data-private/system/store.js | 14 +- .../relationships/belongs-to-test.js | 159 ++++++++++++++---- 3 files changed, 144 insertions(+), 36 deletions(-) diff --git a/addon/-legacy-private/system/relationships/state/belongs-to.js b/addon/-legacy-private/system/relationships/state/belongs-to.js index ddd07937733..56a33bde298 100644 --- a/addon/-legacy-private/system/relationships/state/belongs-to.js +++ b/addon/-legacy-private/system/relationships/state/belongs-to.js @@ -288,7 +288,12 @@ export default class BelongsToRelationship extends Relationship { } function proxyRecord(internalModel) { - return resolve(internalModel).then(resolvedInternalModel => { + let promise = internalModel; + if (internalModel && internalModel.isLoading()) { + promise = internalModel._promiseProxy; + } + + return resolve(promise).then(resolvedInternalModel => { return resolvedInternalModel ? resolvedInternalModel.getRecord() : null; }); } diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index afd1e347b81..6e4e609370d 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -1386,6 +1386,7 @@ Store = Service.extend({ return RSVP.resolve(null); } + let internalModel = resource.data ? this._internalModelForResource(resource.data) : null; let { relationshipIsStale, allInverseRecordsAreLoaded, @@ -1401,6 +1402,13 @@ Store = Service.extend({ relationshipIsStale || (!allInverseRecordsAreLoaded && !relationshipIsEmpty)); + // short circuit if we are already loading + if (internalModel && internalModel.isLoading()) { + return internalModel._promiseProxy.then(() => { + return internalModel.getRecord(); + }); + } + // fetch via link if (shouldFindViaLink) { return this._fetchBelongsToLinkFromResource(resource, parentInternalModel, relationshipMeta); @@ -1421,23 +1429,17 @@ Store = Service.extend({ return RSVP.resolve(null); } - let internalModel = this._internalModelForResource(resource.data); - return this._findByInternalModel(internalModel); } let resourceIsLocal = !localDataIsEmpty && resource.data.id === null; if (resourceIsLocal) { - let internalModel = this._internalModelForResource(resource.data); - return RSVP.resolve(internalModel.getRecord()); } // fetch by data if (!localDataIsEmpty) { - let internalModel = this._internalModelForResource(resource.data); - return this._fetchRecord(internalModel).then(() => { return internalModel.getRecord(); }); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 3616e0efe2b..47459fdc6e0 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -2,38 +2,139 @@ import { get } from '@ember/object'; import { run } from '@ember/runloop'; import RSVP, { resolve } from 'rsvp'; import setupStore from 'dummy/tests/helpers/store'; - +import { module, test } from 'qunit'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; +import { setupTest } from 'ember-qunit'; +import Store from 'ember-data/store'; +import Model from 'ember-data/model'; +import { attr, belongsTo } from '@ember-decorators/data'; import testInDebug, { testRecordData } from 'dummy/tests/helpers/test-in-debug'; import { setup as setupModelFactoryInjections, reset as resetModelFactoryInjection, } from 'dummy/tests/helpers/model-factory-injection'; -import { module, test } from 'qunit'; - import DS from 'ember-data'; import { ModelData } from 'ember-data/-private'; -const { attr, hasMany, belongsTo } = DS; +const { attr: DSattr, hasMany: DShasMany, belongsTo: DSbelongsTo } = DS; const { hash } = RSVP; let env, store, User, Message, Post, Comment, Book, Book1, Chapter, Author, NewMessage, Section; +module('integration/relationship/belongs-to BelongsTo Relationships (new-style)', function(hooks) { + let store; + setupTest(hooks); + + class Person extends Model { + @belongsTo('pet', { inverse: 'bestHuman', async: true }) + bestDog; + @attr + name; + } + + class Pet extends Model { + @belongsTo('person', { inverse: 'bestDog', async: false }) + bestHuman; + @attr + name; + } + + hooks.beforeEach(function() { + let { owner } = this; + owner.register('service:store', Store); + owner.register('model:person', Person); + owner.register('model:pet', Pet); + owner.register( + 'serializer:application', + JSONAPISerializer.extend({ + normalizeResponse(_, __, payload) { + return payload; + }, + }) + ); + store = owner.lookup('service:store'); + }); + + test("async belongsTo chains the related record's loading promise when present", async function(assert) { + let petFindRecordCalls = 0; + this.owner.register( + 'adapter:pet', + JSONAPIAdapter.extend({ + findRecord() { + assert.equal(++petFindRecordCalls, 1, 'We call findRecord only once for our pet'); + return resolve({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + bestHuman: { + data: { type: 'person', id: '1' }, + }, + }, + }, + }); + }, + findBelongsTo() { + return this.store.adapterFor('person').findRecord(); + }, + }) + ); + let personFindRecordCalls = 0; + this.owner.register( + 'adapter:person', + JSONAPIAdapter.extend({ + findRecord() { + assert.equal(++personFindRecordCalls, 1, 'We call findRecord only once for our person'); + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { name: 'Chris' }, + relationships: { + bestDog: { + data: { type: 'pet', id: '1' }, + links: { + related: './pet/1', + }, + }, + }, + }, + }); + }, + findBelongsTo() { + return this.store.adapterFor('pet').findRecord(); + }, + }) + ); + + let person = await store.findRecord('person', '1'); + let petRequest = store.findRecord('pet', '1'); + let personPetRequest = person.get('bestDog'); + let personPet = await personPetRequest; + let pet = await petRequest; + + assert.ok(personPet === pet, 'We ended up in the same state'); + }); +}); + module('integration/relationship/belongs_to Belongs-To Relationships', { beforeEach() { User = DS.Model.extend({ - name: attr('string'), - messages: hasMany('message', { polymorphic: true, async: false }), - favouriteMessage: belongsTo('message', { polymorphic: true, inverse: null, async: false }), + name: DSattr('string'), + messages: DShasMany('message', { polymorphic: true, async: false }), + favouriteMessage: DSbelongsTo('message', { polymorphic: true, inverse: null, async: false }), }); Message = DS.Model.extend({ - user: belongsTo('user', { inverse: 'messages', async: false }), - created_at: attr('date'), + user: DSbelongsTo('user', { inverse: 'messages', async: false }), + created_at: DSattr('date'), }); Post = Message.extend({ - title: attr('string'), - comments: hasMany('comment', { async: false, inverse: null }), + title: DSattr('string'), + comments: DShasMany('comment', { async: false, inverse: null }), }); Comment = Message.extend({ @@ -42,27 +143,27 @@ module('integration/relationship/belongs_to Belongs-To Relationships', { }); Book = DS.Model.extend({ - name: attr('string'), - author: belongsTo('author', { async: false }), - chapters: hasMany('chapters', { async: false, inverse: 'book' }), + name: DSattr('string'), + author: DSbelongsTo('author', { async: false }), + chapters: DShasMany('chapters', { async: false, inverse: 'book' }), }); Book1 = DS.Model.extend({ - name: attr('string'), + name: DSattr('string'), }); Chapter = DS.Model.extend({ - title: attr('string'), - book: belongsTo('book', { async: false, inverse: 'chapters' }), + title: DSattr('string'), + book: DSbelongsTo('book', { async: false, inverse: 'chapters' }), }); Author = DS.Model.extend({ - name: attr('string'), - books: hasMany('books', { async: false }), + name: DSattr('string'), + books: DShasMany('books', { async: false }), }); Section = DS.Model.extend({ - name: attr('string'), + name: DSattr('string'), }); env = setupStore({ @@ -110,14 +211,14 @@ test('returning a null relationship from payload sets the relationship to null o env.registry.register( 'model:app', DS.Model.extend({ - name: attr('string'), - team: belongsTo('team', { async: true }), + name: DSattr('string'), + team: DSbelongsTo('team', { async: true }), }) ); env.registry.register( 'model:team', DS.Model.extend({ - apps: hasMany('app', { async: true }), + apps: DShasMany('app', { async: true }), }) ); run(() => { @@ -854,7 +955,7 @@ test('Destroying a record with an unloaded aync belongsTo association does not f run(post, 'destroyRecord'); }); -testInDebug('A sync belongsTo errors out if the record is unlaoded', function(assert) { +testInDebug('A sync belongsTo errors out if the record is unloaded', function(assert) { let message; run(() => { message = env.store.push({ @@ -969,7 +1070,7 @@ testInDebug('Passing a model as type to belongsTo should not work', function(ass User = DS.Model.extend(); DS.Model.extend({ - user: belongsTo(User, { async: false }), + user: DSbelongsTo(User, { async: false }), }); }, /The first argument to DS.belongsTo must be a string/); }); @@ -978,7 +1079,7 @@ test('belongsTo hasAnyRelationshipData async loaded', function(assert) { assert.expect(1); Book.reopen({ - author: belongsTo('author', { async: true }), + author: DSbelongsTo('author', { async: true }), }); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -1030,7 +1131,7 @@ test('belongsTo hasAnyRelationshipData async not loaded', function(assert) { assert.expect(1); Book.reopen({ - author: belongsTo('author', { async: true }), + author: DSbelongsTo('author', { async: true }), }); env.adapter.findRecord = function(store, type, id, snapshot) { @@ -1079,7 +1180,7 @@ test('belongsTo hasAnyRelationshipData NOT created', function(assert) { assert.expect(2); Book.reopen({ - author: belongsTo('author', { async: true }), + author: DSbelongsTo('author', { async: true }), }); run(() => { @@ -1825,7 +1926,7 @@ testRecordData( // Expect assertion failure as Book1 ModelData // doesn't have relationship attribute // and inverse is not set to null in - // belongsTo + // DSbelongsTo assert.expectAssertion(() => { run(() => { env.store.push(data); From 650c7c2752d67a33778d09a6981429fa7fdfe3b9 Mon Sep 17 00:00:00 2001 From: Stefan Penner Date: Thu, 9 Aug 2018 12:32:04 -0700 Subject: [PATCH 2305/2527] [BUGFIX beta] Fix parallel builds (#5535) --- ember-cli-build.js | 6 +- lib/stripped-build-plugins.js | 51 +- lib/transforms/babel-plugin-remove-imports.js | 26 +- yarn.lock | 2205 ++++++++--------- 4 files changed, 1097 insertions(+), 1191 deletions(-) diff --git a/ember-cli-build.js b/ember-cli-build.js index b50c370c723..aa2951398b8 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -3,7 +3,11 @@ const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); module.exports = function(defaults) { - let app = new EmberAddon(defaults, {}); + let app = new EmberAddon(defaults, { + 'ember-cli-babel': { + throwUnlessParallelizable: true, + }, + }); /* This build file specifies the options for the dummy test app of this diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 4806655243e..65624ac08a0 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -1,20 +1,18 @@ 'use strict'; -var path = require('path'); -var fs = require('fs'); -var resolve = require('resolve'); +const fs = require('fs'); -var FilterImports = requireBabelPlugin('babel-plugin-filter-imports'); -var FeatureFlags = requireBabelPlugin('babel-plugin-feature-flags'); -var StripHeimdall = requireBabelPlugin('babel6-plugin-strip-heimdall'); -var StripClassCallCheck = requireBabelPlugin('babel6-plugin-strip-class-callcheck'); -var StripFilteredImports = require('./transforms/babel-plugin-remove-imports'); -var TransformBlockScoping = requireBabelPlugin('babel-plugin-transform-es2015-block-scoping'); +const FilterImports = requireBabelPlugin('babel-plugin-filter-imports'); +const FeatureFlags = requireBabelPlugin('babel-plugin-feature-flags'); +const StripHeimdall = requireBabelPlugin('babel6-plugin-strip-heimdall'); +const StripClassCallCheck = requireBabelPlugin('babel6-plugin-strip-class-callcheck'); +const StripFilteredImports = requireBabelPlugin('./transforms/babel-plugin-remove-imports'); +const TransformBlockScoping = requireBabelPlugin('babel-plugin-transform-es2015-block-scoping'); function uniqueAdd(obj, key, values) { - var a = (obj[key] = obj[key] || []); + const a = (obj[key] = obj[key] || []); - for (var i = 0; i < values.length; i++) { + for (let i = 0; i < values.length; i++) { if (a.indexOf(values[i]) === -1) { a.push(values[i]); } @@ -25,41 +23,26 @@ function uniqueAdd(obj, key, values) { // that we will be using, this prevents ember-cli-babel/broccoli-babel-transpiler // from opting out of caching (and printing a giant warning) function requireBabelPlugin(packageName) { - var Plugin = require(packageName); - var PluginPath = resolve.sync(packageName + '/package.json', { basedir: __dirname }); - - return addBaseDir(Plugin, path.dirname(PluginPath)); -} - -function addBaseDir(Plugin, baseDir) { - let type = typeof Plugin; - - if (type === 'function' && !Plugin.baseDir) { - Plugin.baseDir = () => baseDir; - } else if (type === 'object' && Plugin !== null && Plugin.default) { - addBaseDir(Plugin.default, baseDir); - } - - return Plugin; + return require.resolve(packageName); } module.exports = function(environment) { - var featuresJsonPath = __dirname + '/../config/features.json'; - var featuresJson = fs.readFileSync(featuresJsonPath, { encoding: 'utf8' }); - var features = JSON.parse(featuresJson); - var filteredImports = {}; + let featuresJsonPath = __dirname + '/../config/features.json'; + let featuresJson = fs.readFileSync(featuresJsonPath, { encoding: 'utf8' }); + let features = JSON.parse(featuresJson); + let filteredImports = {}; // TODO explicitly set all features which are not enabled to `false`, so // they are stripped --> make this configurable or pass features // - // for (var feature in features) { + // for (let feature in features) { // if (features[feature] !== true) { // features[feature] = false; // } // } - var postTransformPlugins = []; - var plugins = [ + let postTransformPlugins = []; + let plugins = [ [ FeatureFlags, { diff --git a/lib/transforms/babel-plugin-remove-imports.js b/lib/transforms/babel-plugin-remove-imports.js index 4d39e5b59bb..480a2f1abaf 100644 --- a/lib/transforms/babel-plugin-remove-imports.js +++ b/lib/transforms/babel-plugin-remove-imports.js @@ -1,30 +1,28 @@ 'use strict'; -function PluginRemoveFilteredImports() { - var importDeclarationsToRemove; - var filteredImports; - var filteredImportNames; +module.exports = function PluginRemoveFilteredImports() { + let importDeclarationsToRemove; + let filteredImports; + let filteredImportNames; return { name: 'remove-filtered-imports', visitor: { Program: { - enter: function(_, state) { + enter(_, state) { filteredImports = state.opts || {}; filteredImportNames = Object.keys(filteredImports); importDeclarationsToRemove = []; }, - exit: function() { - importDeclarationsToRemove.forEach(function(declaration) { - declaration.remove(); - }); + exit() { + importDeclarationsToRemove.forEach(declaration => declaration.remove()); importDeclarationsToRemove = undefined; }, }, - ImportDeclaration: function(path) { - var name = path.node.source.value; + ImportDeclaration(path) { + let name = path.node.source.value; if (filteredImportNames.indexOf(name) !== -1) { if (filteredImports[name] === true || filteredImports[name] === '*') { @@ -59,10 +57,4 @@ function PluginRemoveFilteredImports() { }, }, }; -} - -PluginRemoveFilteredImports.baseDir = function() { - return __dirname; }; - -module.exports = PluginRemoveFilteredImports; diff --git a/yarn.lock b/yarn.lock index 29a9a783e4e..f4bc2465fb9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4,13 +4,13 @@ "@babel/code-frame@7.0.0-beta.44": version "7.0.0-beta.44" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" dependencies: "@babel/highlight" "7.0.0-beta.44" "@babel/generator@7.0.0-beta.44": version "7.0.0-beta.44" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" dependencies: "@babel/types" "7.0.0-beta.44" jsesc "^2.5.1" @@ -20,7 +20,7 @@ "@babel/helper-function-name@7.0.0-beta.44": version "7.0.0-beta.44" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" dependencies: "@babel/helper-get-function-arity" "7.0.0-beta.44" "@babel/template" "7.0.0-beta.44" @@ -28,19 +28,19 @@ "@babel/helper-get-function-arity@7.0.0-beta.44": version "7.0.0-beta.44" - resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" dependencies: "@babel/types" "7.0.0-beta.44" "@babel/helper-split-export-declaration@7.0.0-beta.44": version "7.0.0-beta.44" - resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" dependencies: "@babel/types" "7.0.0-beta.44" "@babel/highlight@7.0.0-beta.44": version "7.0.0-beta.44" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" dependencies: chalk "^2.0.0" esutils "^2.0.2" @@ -48,7 +48,7 @@ "@babel/template@7.0.0-beta.44": version "7.0.0-beta.44" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" dependencies: "@babel/code-frame" "7.0.0-beta.44" "@babel/types" "7.0.0-beta.44" @@ -57,7 +57,7 @@ "@babel/traverse@7.0.0-beta.44": version "7.0.0-beta.44" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" dependencies: "@babel/code-frame" "7.0.0-beta.44" "@babel/generator" "7.0.0-beta.44" @@ -72,7 +72,7 @@ "@babel/types@7.0.0-beta.44": version "7.0.0-beta.44" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" dependencies: esutils "^2.0.2" lodash "^4.2.0" @@ -139,7 +139,7 @@ "@ember/test-helpers@^0.7.18": version "0.7.25" - resolved "https://registry.npmjs.org/@ember/test-helpers/-/test-helpers-0.7.25.tgz#b4014c108b40ffaf74f3c4d5918800917541541d" + resolved "https://registry.yarnpkg.com/@ember/test-helpers/-/test-helpers-0.7.25.tgz#b4014c108b40ffaf74f3c4d5918800917541541d" dependencies: broccoli-funnel "^2.0.1" ember-cli-babel "^6.12.0" @@ -147,50 +147,50 @@ "@glimmer/di@^0.2.0": version "0.2.0" - resolved "https://registry.npmjs.org/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" + resolved "https://registry.yarnpkg.com/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" "@glimmer/resolver@^0.4.1": version "0.4.3" - resolved "https://registry.npmjs.org/@glimmer/resolver/-/resolver-0.4.3.tgz#b1baae5c3291b4621002ccf8d7870466097e841d" + resolved "https://registry.yarnpkg.com/@glimmer/resolver/-/resolver-0.4.3.tgz#b1baae5c3291b4621002ccf8d7870466097e841d" dependencies: "@glimmer/di" "^0.2.0" "@sindresorhus/is@^0.7.0": version "0.7.0" - resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" "@types/acorn@^4.0.3": version "4.0.3" - resolved "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.3.tgz#d1f3e738dde52536f9aad3d3380d14e448820afd" + resolved "https://registry.yarnpkg.com/@types/acorn/-/acorn-4.0.3.tgz#d1f3e738dde52536f9aad3d3380d14e448820afd" dependencies: "@types/estree" "*" "@types/estree@*": version "0.0.39" - resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" "@types/estree@0.0.38": version "0.0.38" - resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.38.tgz#c1be40aa933723c608820a99a373a16d215a1ca2" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.38.tgz#c1be40aa933723c608820a99a373a16d215a1ca2" "@types/node@^9.6.0": - version "9.6.22" - resolved "https://registry.npmjs.org/@types/node/-/node-9.6.22.tgz#05b55093faaadedea7a4b3f76e9a61346a6dd209" + version "9.6.23" + resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.23.tgz#fc429962c1b75f32bd66214a3997f660e8434f0d" abbrev@1: version "1.1.1" - resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" accepts@~1.3.4, accepts@~1.3.5: version "1.3.5" - resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" dependencies: mime-types "~2.1.18" negotiator "0.6.1" acorn-dynamic-import@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" dependencies: acorn "^5.0.0" @@ -202,15 +202,15 @@ acorn-jsx@^4.1.1: acorn@^5.0.0, acorn@^5.0.3, acorn@^5.5.3, acorn@^5.6.0: version "5.7.1" - resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" after@0.8.2: version "0.8.2" - resolved "https://registry.npmjs.org/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" agent-base@2: version "2.1.1" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" dependencies: extend "~3.0.0" semver "~5.0.1" @@ -230,7 +230,7 @@ ajv@^6.0.1, ajv@^6.5.0: align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" - resolved "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" dependencies: kind-of "^3.0.2" longest "^1.0.1" @@ -238,17 +238,17 @@ align-text@^0.1.1, align-text@^0.1.3: amd-name-resolver@1.2.0, amd-name-resolver@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz#fc41b3848824b557313897d71f8d5a0184fbe679" + resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz#fc41b3848824b557313897d71f8d5a0184fbe679" dependencies: ensure-posix-path "^1.0.1" amdefine@>=0.0.4: version "1.0.1" - resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" ansi-escapes@^1.1.0: version "1.4.0" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" ansi-escapes@^3.0.0: version "3.1.0" @@ -256,96 +256,96 @@ ansi-escapes@^3.0.0: ansi-regex@^2.0.0: version "2.1.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" ansi-regex@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" ansi-styles@^2.2.1: version "2.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" ansi-styles@^3.0.0, ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" dependencies: color-convert "^1.9.0" ansicolors@~0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" anymatch@^1.3.0: version "1.3.2" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" dependencies: micromatch "^2.1.5" normalize-path "^2.0.0" anymatch@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" dependencies: micromatch "^3.1.4" normalize-path "^2.1.1" aproba@^1.0.3: version "1.2.0" - resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" are-we-there-yet@~1.1.2: version "1.1.5" - resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" dependencies: delegates "^1.0.0" readable-stream "^2.0.6" argparse@^1.0.7, argparse@~1.0.2: version "1.0.10" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" dependencies: sprintf-js "~1.0.2" arr-diff@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" dependencies: arr-flatten "^1.0.1" arr-diff@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" arr-union@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" array-equal@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" array-find-index@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" array-flatten@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" array-to-error@^1.0.0: version "1.1.1" - resolved "https://registry.npmjs.org/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" + resolved "https://registry.yarnpkg.com/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" dependencies: array-to-sentence "^1.1.0" array-to-sentence@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" + resolved "https://registry.yarnpkg.com/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" array-union@^1.0.1: version "1.0.2" @@ -359,15 +359,15 @@ array-uniq@^1.0.1: array-unique@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" array-unique@^0.3.2: version "0.3.2" - resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" arraybuffer.slice@~0.0.7: version "0.0.7" - resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" arrify@^1.0.0: version "1.0.1" @@ -375,27 +375,27 @@ arrify@^1.0.0: asn1@0.1.11: version "0.1.11" - resolved "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" assert-plus@^0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" assertion-error@^1.0.1: version "1.1.0" - resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" assign-symbols@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" ast-types@0.9.6: version "0.9.6" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" async-disk-cache@^1.2.1: version "1.3.3" - resolved "https://registry.npmjs.org/async-disk-cache/-/async-disk-cache-1.3.3.tgz#6040486660b370e4051cd9fa9fee275e1fae3728" + resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.3.3.tgz#6040486660b370e4051cd9fa9fee275e1fae3728" dependencies: debug "^2.1.3" heimdalljs "^0.2.3" @@ -407,44 +407,44 @@ async-disk-cache@^1.2.1: async-each@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" async-limiter@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" async-promise-queue@^1.0.3, async-promise-queue@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/async-promise-queue/-/async-promise-queue-1.0.4.tgz#308baafbc74aff66a0bb6e7f4a18d4fe8434440c" + resolved "https://registry.yarnpkg.com/async-promise-queue/-/async-promise-queue-1.0.4.tgz#308baafbc74aff66a0bb6e7f4a18d4fe8434440c" dependencies: async "^2.4.1" debug "^2.6.8" async@^1.4.0, async@^1.5.2: version "1.5.2" - resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" async@^2.4.1: version "2.6.1" - resolved "https://registry.npmjs.org/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" dependencies: lodash "^4.17.10" async@~0.2.9: version "0.2.10" - resolved "https://registry.npmjs.org/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" async@~0.9.0: version "0.9.2" - resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" atob@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" aws-sdk@^2.0.9: - version "2.263.1" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.263.1.tgz#217e2459ebff3702cc72260bcafca0bf16edc4cd" + version "2.279.1" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.279.1.tgz#3a4fd4167932e4361dbdcfcb174ce4840ffcbf20" dependencies: buffer "4.9.1" events "1.1.1" @@ -454,15 +454,15 @@ aws-sdk@^2.0.9: sax "1.2.1" url "0.10.3" uuid "3.1.0" - xml2js "0.4.17" + xml2js "0.4.19" aws-sign2@~0.5.0: version "0.5.0" - resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" babel-code-frame@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: chalk "^1.1.3" esutils "^2.0.2" @@ -470,7 +470,7 @@ babel-code-frame@^6.26.0: babel-core@^6.26.0: version "6.26.3" - resolved "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" dependencies: babel-code-frame "^6.26.0" babel-generator "^6.26.0" @@ -505,7 +505,7 @@ babel-eslint@^8.2.6: babel-generator@^6.26.0: version "6.26.1" - resolved "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" dependencies: babel-messages "^6.23.0" babel-runtime "^6.26.0" @@ -518,7 +518,7 @@ babel-generator@^6.26.0: babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" dependencies: babel-helper-explode-assignable-expression "^6.24.1" babel-runtime "^6.22.0" @@ -526,7 +526,7 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: babel-helper-call-delegate@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" dependencies: babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" @@ -535,7 +535,7 @@ babel-helper-call-delegate@^6.24.1: babel-helper-define-map@^6.24.1: version "6.26.0" - resolved "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.26.0" @@ -544,7 +544,7 @@ babel-helper-define-map@^6.24.1: babel-helper-explode-assignable-expression@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" dependencies: babel-runtime "^6.22.0" babel-traverse "^6.24.1" @@ -552,7 +552,7 @@ babel-helper-explode-assignable-expression@^6.24.1: babel-helper-function-name@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" dependencies: babel-helper-get-function-arity "^6.24.1" babel-runtime "^6.22.0" @@ -562,28 +562,28 @@ babel-helper-function-name@^6.24.1: babel-helper-get-function-arity@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-helper-hoist-variables@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-helper-optimise-call-expression@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-helper-regex@^6.24.1: version "6.26.0" - resolved "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" dependencies: babel-runtime "^6.26.0" babel-types "^6.26.0" @@ -591,7 +591,7 @@ babel-helper-regex@^6.24.1: babel-helper-remap-async-to-generator@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" @@ -601,7 +601,7 @@ babel-helper-remap-async-to-generator@^6.24.1: babel-helper-replace-supers@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" dependencies: babel-helper-optimise-call-expression "^6.24.1" babel-messages "^6.23.0" @@ -612,26 +612,26 @@ babel-helper-replace-supers@^6.24.1: babel-helpers@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" babel-messages@^6.23.0: version "6.23.0" - resolved "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" dependencies: babel-runtime "^6.22.0" babel-plugin-check-es2015-constants@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" dependencies: babel-runtime "^6.22.0" babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.11: version "0.1.11" - resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" + resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" dependencies: semver "^5.3.0" @@ -641,7 +641,7 @@ babel-plugin-debug-macros@^0.2.0-beta.6: dependencies: semver "^5.3.0" -babel-plugin-ember-modules-api-polyfill@^2.3.0, babel-plugin-ember-modules-api-polyfill@^2.3.2: +babel-plugin-ember-modules-api-polyfill@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.3.2.tgz#56ea34bea963498d070a2b7dc2ce18a92c434093" dependencies: @@ -649,39 +649,39 @@ babel-plugin-ember-modules-api-polyfill@^2.3.0, babel-plugin-ember-modules-api-p babel-plugin-feature-flags@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" + resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" babel-plugin-filter-imports@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.3.1.tgz#e7859b56886b175dd2616425d277b219e209ea8b" + resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.3.1.tgz#e7859b56886b175dd2616425d277b219e209ea8b" babel-plugin-htmlbars-inline-precompile@^0.2.5: - version "0.2.5" - resolved "https://registry.npmjs.org/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.5.tgz#7a7c37cf22c73fb57a1f828c76520f0360c5c5f3" + version "0.2.6" + resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.6.tgz#c00b8a3f4b32ca04bf0f0d5169fcef3b5a66d69d" babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" babel-plugin-syntax-class-properties@^6.8.0: version "6.13.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" babel-plugin-syntax-decorators@^6.1.18: version "6.13.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" babel-plugin-transform-async-to-generator@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" dependencies: babel-helper-remap-async-to-generator "^6.24.1" babel-plugin-syntax-async-functions "^6.8.0" @@ -689,7 +689,7 @@ babel-plugin-transform-async-to-generator@^6.22.0: babel-plugin-transform-class-properties@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" dependencies: babel-helper-function-name "^6.24.1" babel-plugin-syntax-class-properties "^6.8.0" @@ -698,7 +698,7 @@ babel-plugin-transform-class-properties@^6.24.1: babel-plugin-transform-decorators-legacy@^1.3.4: version "1.3.5" - resolved "https://registry.npmjs.org/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.5.tgz#0e492dffa0edd70529072887f8aa86d4dd8b40a1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.5.tgz#0e492dffa0edd70529072887f8aa86d4dd8b40a1" dependencies: babel-plugin-syntax-decorators "^6.1.18" babel-runtime "^6.2.0" @@ -706,19 +706,19 @@ babel-plugin-transform-decorators-legacy@^1.3.4: babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" dependencies: babel-runtime "^6.26.0" babel-template "^6.26.0" @@ -728,7 +728,7 @@ babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es20 babel-plugin-transform-es2015-classes@^6.23.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" dependencies: babel-helper-define-map "^6.24.1" babel-helper-function-name "^6.24.1" @@ -742,33 +742,33 @@ babel-plugin-transform-es2015-classes@^6.23.0: babel-plugin-transform-es2015-computed-properties@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" babel-plugin-transform-es2015-destructuring@^6.23.0: version "6.23.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-duplicate-keys@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-plugin-transform-es2015-for-of@^6.23.0: version "6.23.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-function-name@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" @@ -776,13 +776,13 @@ babel-plugin-transform-es2015-function-name@^6.22.0: babel-plugin-transform-es2015-literals@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" dependencies: babel-plugin-transform-es2015-modules-commonjs "^6.24.1" babel-runtime "^6.22.0" @@ -790,7 +790,7 @@ babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015 babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: version "6.26.2" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" dependencies: babel-plugin-transform-strict-mode "^6.24.1" babel-runtime "^6.26.0" @@ -799,7 +799,7 @@ babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-e babel-plugin-transform-es2015-modules-systemjs@^6.23.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" dependencies: babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" @@ -807,7 +807,7 @@ babel-plugin-transform-es2015-modules-systemjs@^6.23.0: babel-plugin-transform-es2015-modules-umd@^6.23.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" dependencies: babel-plugin-transform-es2015-modules-amd "^6.24.1" babel-runtime "^6.22.0" @@ -815,14 +815,14 @@ babel-plugin-transform-es2015-modules-umd@^6.23.0: babel-plugin-transform-es2015-object-super@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" dependencies: babel-helper-replace-supers "^6.24.1" babel-runtime "^6.22.0" babel-plugin-transform-es2015-parameters@^6.23.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" dependencies: babel-helper-call-delegate "^6.24.1" babel-helper-get-function-arity "^6.24.1" @@ -833,20 +833,20 @@ babel-plugin-transform-es2015-parameters@^6.23.0: babel-plugin-transform-es2015-shorthand-properties@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-plugin-transform-es2015-spread@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-sticky-regex@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" dependencies: babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" @@ -854,19 +854,19 @@ babel-plugin-transform-es2015-sticky-regex@^6.22.0: babel-plugin-transform-es2015-template-literals@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-typeof-symbol@^6.23.0: version "6.23.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-unicode-regex@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" dependencies: babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" @@ -874,7 +874,7 @@ babel-plugin-transform-es2015-unicode-regex@^6.22.0: babel-plugin-transform-exponentiation-operator@^6.22.0: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" dependencies: babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" babel-plugin-syntax-exponentiation-operator "^6.8.0" @@ -882,20 +882,20 @@ babel-plugin-transform-exponentiation-operator@^6.22.0: babel-plugin-transform-regenerator@^6.22.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" dependencies: regenerator-transform "^0.10.0" babel-plugin-transform-strict-mode@^6.24.1: version "6.24.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-polyfill@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" dependencies: babel-runtime "^6.26.0" core-js "^2.5.0" @@ -903,7 +903,7 @@ babel-polyfill@^6.26.0: babel-preset-env@^1.7.0: version "1.7.0" - resolved "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" dependencies: babel-plugin-check-es2015-constants "^6.22.0" babel-plugin-syntax-trailing-function-commas "^6.22.0" @@ -938,7 +938,7 @@ babel-preset-env@^1.7.0: babel-register@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" dependencies: babel-core "^6.26.0" babel-runtime "^6.26.0" @@ -950,14 +950,14 @@ babel-register@^6.26.0: babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: core-js "^2.4.0" regenerator-runtime "^0.11.0" babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" dependencies: babel-runtime "^6.26.0" babel-traverse "^6.26.0" @@ -967,7 +967,7 @@ babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" dependencies: babel-code-frame "^6.26.0" babel-messages "^6.23.0" @@ -981,7 +981,7 @@ babel-traverse@^6.24.1, babel-traverse@^6.26.0: babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" - resolved "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" dependencies: babel-runtime "^6.26.0" esutils "^2.0.2" @@ -990,37 +990,37 @@ babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: babel6-plugin-strip-class-callcheck@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" + resolved "https://registry.yarnpkg.com/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" babel6-plugin-strip-heimdall@^6.0.1: version "6.0.1" - resolved "https://registry.npmjs.org/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" + resolved "https://registry.yarnpkg.com/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" babylon@7.0.0-beta.44: version "7.0.0-beta.44" - resolved "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" babylon@^6.18.0: version "6.18.0" - resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" backbone@^1.1.2: version "1.3.3" - resolved "https://registry.npmjs.org/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" + resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" dependencies: underscore ">=1.8.3" backo2@1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" balanced-match@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" base64-arraybuffer@0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" base64-js@0.0.2: version "0.0.2" @@ -1028,15 +1028,15 @@ base64-js@0.0.2: base64-js@^1.0.2: version "1.3.0" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" base64id@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" base@^0.11.1: version "0.11.2" - resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" dependencies: cache-base "^1.0.1" class-utils "^0.3.5" @@ -1048,39 +1048,39 @@ base@^0.11.1: basic-auth@~2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz#015db3f353e02e56377755f962742e8981e7bbba" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.0.tgz#015db3f353e02e56377755f962742e8981e7bbba" dependencies: safe-buffer "5.1.1" better-assert@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" dependencies: callsite "1.0.0" binary-extensions@^1.0.0: version "1.11.0" - resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" "binaryextensions@1 || 2": version "2.1.1" - resolved "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" + resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" blank-object@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" + resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" blob@0.0.4: version "0.0.4" - resolved "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" bluebird@^3.1.1, bluebird@^3.4.6: version "3.5.1" - resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" body-parser@1.18.2: version "1.18.2" - resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" dependencies: bytes "3.0.0" content-type "~1.0.4" @@ -1095,7 +1095,7 @@ body-parser@1.18.2: body@^5.1.0: version "5.1.0" - resolved "https://registry.npmjs.org/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" + resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" dependencies: continuable-cache "^0.3.1" error "^7.0.0" @@ -1104,7 +1104,7 @@ body@^5.1.0: boom@0.4.x: version "0.4.2" - resolved "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" + resolved "https://registry.yarnpkg.com/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" dependencies: hoek "0.9.x" @@ -1117,7 +1117,7 @@ bops@0.0.3: bower-config@^1.3.0: version "1.4.1" - resolved "https://registry.npmjs.org/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc" + resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc" dependencies: graceful-fs "^4.1.3" mout "^1.0.0" @@ -1127,18 +1127,18 @@ bower-config@^1.3.0: bower-endpoint-parser@0.2.2: version "0.2.2" - resolved "https://registry.npmjs.org/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" + resolved "https://registry.yarnpkg.com/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" brace-expansion@^1.0.0, brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" dependencies: balanced-match "^1.0.0" concat-map "0.0.1" braces@^1.8.2: version "1.8.5" - resolved "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" dependencies: expand-range "^1.8.1" preserve "^0.2.0" @@ -1146,7 +1146,7 @@ braces@^1.8.2: braces@^2.3.1: version "2.3.2" - resolved "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" dependencies: arr-flatten "^1.1.0" array-unique "^0.3.2" @@ -1179,13 +1179,13 @@ broccoli-asset-rev@^2.7.0: broccoli-asset-rewrite@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" + resolved "https://registry.yarnpkg.com/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" dependencies: broccoli-filter "^1.2.3" -broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.4.2: - version "6.4.3" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.4.3.tgz#06e399298d41700cdc10d675b1d808a89ef6b2d0" +broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.4.5: + version "6.4.5" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.4.5.tgz#caab4a3b18d2a819fdd56e1ac3a37e8164ad4272" dependencies: babel-core "^6.26.0" broccoli-funnel "^2.0.1" @@ -1198,7 +1198,7 @@ broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.4.2: rsvp "^4.8.2" workerpool "^2.3.0" -broccoli-babel-transpiler@^6.4.5, broccoli-babel-transpiler@^6.5.0: +broccoli-babel-transpiler@^6.5.0: version "6.5.0" resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.5.0.tgz#aa501a227b298a99742fdd0309b1eaad7124bba0" dependencies: @@ -1215,7 +1215,7 @@ broccoli-babel-transpiler@^6.4.5, broccoli-babel-transpiler@^6.5.0: broccoli-builder@^0.18.8: version "0.18.14" - resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.14.tgz#4b79e2f844de11a4e1b816c3f49c6df4776c312d" + resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.14.tgz#4b79e2f844de11a4e1b816c3f49c6df4776c312d" dependencies: broccoli-node-info "^1.1.0" heimdalljs "^0.2.0" @@ -1227,7 +1227,7 @@ broccoli-builder@^0.18.8: broccoli-caching-writer@^2.2.0: version "2.3.1" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" @@ -1238,7 +1238,7 @@ broccoli-caching-writer@^2.2.0: broccoli-caching-writer@^3.0.3: version "3.0.3" - resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.1" @@ -1262,7 +1262,7 @@ broccoli-caching-writer@~2.0.4: broccoli-clean-css@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" + resolved "https://registry.yarnpkg.com/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" dependencies: broccoli-persistent-filter "^1.1.6" clean-css-promise "^0.1.0" @@ -1270,21 +1270,21 @@ broccoli-clean-css@^1.1.0: json-stable-stringify "^1.0.0" broccoli-concat@^3.2.2: - version "3.2.2" - resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-3.2.2.tgz#86ffdc52606eb590ba9f6b894c5ec7a016f5b7b9" + version "3.4.0" + resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.4.0.tgz#1b7cd73995cbff170d958b3c81496e59313ed14f" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.3.0" - broccoli-stew "^1.3.3" + broccoli-stew "^1.5.0" ensure-posix-path "^1.0.2" - fast-sourcemap-concat "^1.0.1" + fast-sourcemap-concat "^1.3.1" find-index "^1.1.0" - fs-extra "^1.0.0" - fs-tree-diff "^0.5.6" - lodash.merge "^4.3.0" + fs-extra "^4.0.3" + fs-tree-diff "^0.5.7" + lodash.merge "^4.3.1" lodash.omit "^4.1.0" lodash.uniq "^4.2.0" - walk-sync "^0.3.1" + walk-sync "^0.3.2" broccoli-concat@^3.5.1: version "3.5.1" @@ -1305,13 +1305,13 @@ broccoli-concat@^3.5.1: broccoli-config-loader@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/broccoli-config-loader/-/broccoli-config-loader-1.0.1.tgz#d10aaf8ebc0cb45c1da5baa82720e1d88d28c80a" + resolved "https://registry.yarnpkg.com/broccoli-config-loader/-/broccoli-config-loader-1.0.1.tgz#d10aaf8ebc0cb45c1da5baa82720e1d88d28c80a" dependencies: broccoli-caching-writer "^3.0.3" broccoli-config-replace@^1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" + resolved "https://registry.yarnpkg.com/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.0" @@ -1320,7 +1320,7 @@ broccoli-config-replace@^1.1.2: broccoli-debug@^0.6.1, broccoli-debug@^0.6.3, broccoli-debug@^0.6.4: version "0.6.4" - resolved "https://registry.npmjs.org/broccoli-debug/-/broccoli-debug-0.6.4.tgz#986eb3d2005e00e3bb91f9d0a10ab137210cd150" + resolved "https://registry.yarnpkg.com/broccoli-debug/-/broccoli-debug-0.6.4.tgz#986eb3d2005e00e3bb91f9d0a10ab137210cd150" dependencies: broccoli-plugin "^1.2.1" fs-tree-diff "^0.5.2" @@ -1331,7 +1331,7 @@ broccoli-debug@^0.6.1, broccoli-debug@^0.6.3, broccoli-debug@^0.6.4: broccoli-file-creator@^1.1.1: version "1.2.0" - resolved "https://registry.npmjs.org/broccoli-file-creator/-/broccoli-file-creator-1.2.0.tgz#27f1b25b1b00e7bb7bf3d5d7abed5f4d5388df4d" + resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-1.2.0.tgz#27f1b25b1b00e7bb7bf3d5d7abed5f4d5388df4d" dependencies: broccoli-plugin "^1.1.0" mkdirp "^0.5.1" @@ -1345,7 +1345,7 @@ broccoli-file-creator@^2.1.1: broccoli-filter@^1.0.1, broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: version "1.3.0" - resolved "https://registry.npmjs.org/broccoli-filter/-/broccoli-filter-1.3.0.tgz#71e3a8e32a17f309e12261919c5b1006d6766de6" + resolved "https://registry.yarnpkg.com/broccoli-filter/-/broccoli-filter-1.3.0.tgz#71e3a8e32a17f309e12261919c5b1006d6766de6" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.0.0" @@ -1359,11 +1359,11 @@ broccoli-filter@^1.0.1, broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: broccoli-funnel-reducer@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" + resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.1.0: version "1.2.0" - resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" + resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" dependencies: array-equal "^1.0.0" blank-object "^1.0.1" @@ -1382,7 +1382,7 @@ broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.1.0: broccoli-funnel@^2.0.0, broccoli-funnel@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-2.0.1.tgz#6823c73b675ef78fffa7ab800f083e768b51d449" + resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-2.0.1.tgz#6823c73b675ef78fffa7ab800f083e768b51d449" dependencies: array-equal "^1.0.0" blank-object "^1.0.1" @@ -1400,21 +1400,21 @@ broccoli-funnel@^2.0.0, broccoli-funnel@^2.0.1: broccoli-kitchen-sink-helpers@^0.2.5: version "0.2.9" - resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" + resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" dependencies: glob "^5.0.10" mkdirp "^0.5.1" broccoli-kitchen-sink-helpers@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" + resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" dependencies: glob "^5.0.10" mkdirp "^0.5.1" broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.1, broccoli-merge-trees@^1.2.1: version "1.2.4" - resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" dependencies: broccoli-plugin "^1.3.0" can-symlink "^1.0.0" @@ -1427,7 +1427,7 @@ broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.1, broccoli-merge-trees@^ broccoli-merge-trees@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-2.0.0.tgz#10aea46dd5cebcc8b8f7d5a54f0a84a4f0bb90b9" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-2.0.0.tgz#10aea46dd5cebcc8b8f7d5a54f0a84a4f0bb90b9" dependencies: broccoli-plugin "^1.3.0" merge-trees "^1.0.1" @@ -1441,7 +1441,7 @@ broccoli-merge-trees@^3.0.0: broccoli-middleware@^1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-1.2.1.tgz#a21f255f8bfe5a21c2f0fbf2417addd9d24c9436" + resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-1.2.1.tgz#a21f255f8bfe5a21c2f0fbf2417addd9d24c9436" dependencies: handlebars "^4.0.4" mime-types "^2.1.18" @@ -1465,11 +1465,11 @@ broccoli-module-unification-reexporter@^1.0.0: broccoli-node-info@1.1.0, broccoli-node-info@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" + resolved "https://registry.yarnpkg.com/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.4.3: version "1.4.3" - resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz#3511bc52fc53740cda51621f58a28152d9911bc1" + resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz#3511bc52fc53740cda51621f58a28152d9911bc1" dependencies: async-disk-cache "^1.2.1" async-promise-queue "^1.0.3" @@ -1487,7 +1487,7 @@ broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-p broccoli-plugin@1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -1496,7 +1496,7 @@ broccoli-plugin@1.1.0: broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -1521,21 +1521,21 @@ broccoli-rollup@^2.1.1: broccoli-slow-trees@2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/broccoli-slow-trees/-/broccoli-slow-trees-2.0.0.tgz#9741afe992787add64aec7f7c8211dfcc058278d" + resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-2.0.0.tgz#9741afe992787add64aec7f7c8211dfcc058278d" broccoli-slow-trees@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" + resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" dependencies: heimdalljs "^0.2.1" broccoli-source@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" + resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" broccoli-sri-hash@^2.1.0: version "2.1.2" - resolved "https://registry.npmjs.org/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" + resolved "https://registry.yarnpkg.com/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" dependencies: broccoli-caching-writer "^2.2.0" mkdirp "^0.5.1" @@ -1543,26 +1543,7 @@ broccoli-sri-hash@^2.1.0: sri-toolbox "^0.2.0" symlink-or-copy "^1.0.1" -broccoli-stew@^1.2.0, broccoli-stew@^1.3.3: - version "1.5.0" - resolved "https://registry.npmjs.org/broccoli-stew/-/broccoli-stew-1.5.0.tgz#d7af8c18511dce510e49d308a62e5977f461883c" - dependencies: - broccoli-debug "^0.6.1" - broccoli-funnel "^1.0.1" - broccoli-merge-trees "^1.0.0" - broccoli-persistent-filter "^1.1.6" - broccoli-plugin "^1.3.0" - chalk "^1.1.3" - debug "^2.4.0" - ensure-posix-path "^1.0.1" - fs-extra "^2.0.0" - minimatch "^3.0.2" - resolve "^1.1.6" - rsvp "^3.0.16" - symlink-or-copy "^1.1.8" - walk-sync "^0.3.0" - -broccoli-stew@^1.5.0: +broccoli-stew@^1.2.0, broccoli-stew@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-1.6.0.tgz#01f6d92806ed6679ddbe48d405066a0e164dfbef" dependencies: @@ -1636,7 +1617,7 @@ broccoli-uglify-sourcemap@^2.1.1, broccoli-uglify-sourcemap@^2.2.0: broccoli@^1.1.0: version "1.1.4" - resolved "https://registry.npmjs.org/broccoli/-/broccoli-1.1.4.tgz#b023b028b866f447ed14341007961efd03f7251c" + resolved "https://registry.yarnpkg.com/broccoli/-/broccoli-1.1.4.tgz#b023b028b866f447ed14341007961efd03f7251c" dependencies: broccoli-node-info "1.1.0" broccoli-slow-trees "2.0.0" @@ -1660,24 +1641,24 @@ browser-stdout@1.3.1: browserslist@^3.2.6: version "3.2.8" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" dependencies: caniuse-lite "^1.0.30000844" electron-to-chromium "^1.3.47" bser@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" dependencies: node-int64 "^0.4.0" buffer-from@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" buffer@4.9.1: version "4.9.1" - resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -1685,23 +1666,23 @@ buffer@4.9.1: builtin-modules@^1.0.0: version "1.1.1" - resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" builtins@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" bytes@1: version "1.0.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" bytes@3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" cache-base@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" dependencies: collection-visit "^1.0.0" component-emitter "^1.2.1" @@ -1715,7 +1696,7 @@ cache-base@^1.0.1: cacheable-request@^2.1.1: version "2.1.4" - resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" dependencies: clone-response "1.0.2" get-stream "3.0.0" @@ -1727,7 +1708,7 @@ cacheable-request@^2.1.1: calculate-cache-key-for-tree@^1.0.0, calculate-cache-key-for-tree@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" + resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" dependencies: json-stable-stringify "^1.0.1" @@ -1739,7 +1720,7 @@ caller-path@^0.1.0: callsite@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" callsites@^0.2.0: version "0.2.0" @@ -1747,32 +1728,32 @@ callsites@^0.2.0: camelcase-keys@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" dependencies: camelcase "^2.0.0" map-obj "^1.0.0" camelcase@^1.0.2: version "1.2.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" camelcase@^2.0.0: version "2.1.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" can-symlink@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" + resolved "https://registry.yarnpkg.com/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" dependencies: tmp "0.0.28" caniuse-lite@^1.0.30000844: - version "1.0.30000858" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000858.tgz#f6f203a9128bac507136de1cf6cfd966d2df027c" + version "1.0.30000865" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000865.tgz#70026616e8afe6e1442f8bb4e1092987d81a2f25" capture-exit@^1.1.0, capture-exit@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" dependencies: rsvp "^3.3.3" @@ -1782,39 +1763,39 @@ capture-stack-trace@^1.0.0: cardinal@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" + resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" dependencies: ansicolors "~0.2.1" redeyed "~1.0.0" center-align@^0.1.1: version "0.1.3" - resolved "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" dependencies: align-text "^0.1.3" lazy-cache "^1.0.3" chai-as-promised@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" + resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" dependencies: check-error "^1.0.2" chai-as-promised@^7.0.0: version "7.1.1" - resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" + resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" dependencies: check-error "^1.0.2" chai-files@^1.0.0, chai-files@^1.1.0: version "1.4.0" - resolved "https://registry.npmjs.org/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" + resolved "https://registry.yarnpkg.com/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" dependencies: assertion-error "^1.0.1" chai@^3.3.0: version "3.5.0" - resolved "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" + resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" dependencies: assertion-error "^1.0.1" deep-eql "^0.1.3" @@ -1822,7 +1803,7 @@ chai@^3.3.0: chai@^4.1.0: version "4.1.2" - resolved "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c" dependencies: assertion-error "^1.0.1" check-error "^1.0.1" @@ -1833,7 +1814,7 @@ chai@^4.1.0: chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" - resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -1855,17 +1836,17 @@ chardet@^0.4.0: charm@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" + resolved "https://registry.yarnpkg.com/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" dependencies: inherits "^2.0.1" check-error@^1.0.1, check-error@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" chokidar@1.7.0: version "1.7.0" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" dependencies: anymatch "^1.3.0" async-each "^1.0.0" @@ -1880,7 +1861,7 @@ chokidar@1.7.0: chownr@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" ci-info@^1.1.2: version "1.1.3" @@ -1892,7 +1873,7 @@ circular-json@^0.3.1: class-utils@^0.3.5: version "0.3.6" - resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" dependencies: arr-union "^3.1.0" define-property "^0.2.5" @@ -1901,11 +1882,11 @@ class-utils@^0.3.5: clean-base-url@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" + resolved "https://registry.yarnpkg.com/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" clean-css-promise@^0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" + resolved "https://registry.yarnpkg.com/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" dependencies: array-to-error "^1.0.0" clean-css "^3.4.5" @@ -1913,7 +1894,7 @@ clean-css-promise@^0.1.0: clean-css@^3.4.5: version "3.4.28" - resolved "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" dependencies: commander "2.8.x" source-map "0.4.x" @@ -1924,23 +1905,23 @@ clean-up-path@^1.0.0: cli-cursor@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" dependencies: restore-cursor "^1.0.1" cli-cursor@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: restore-cursor "^2.0.0" cli-spinners@^1.1.0: version "1.3.1" - resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" cli-table2@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" + resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" dependencies: lodash "^3.10.1" string-width "^1.0.1" @@ -1949,17 +1930,17 @@ cli-table2@^0.2.0: cli-table@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" dependencies: colors "1.0.3" cli-width@^2.0.0: version "2.2.0" - resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" cliui@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" dependencies: center-align "^0.1.1" right-align "^0.1.1" @@ -1967,74 +1948,74 @@ cliui@^2.1.0: clone-response@1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" dependencies: mimic-response "^1.0.0" clone@^1.0.2: version "1.0.4" - resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" clone@^2.0.0: version "2.1.1" - resolved "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" co@^4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" code-point-at@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" collection-visit@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" dependencies: map-visit "^1.0.0" object-visit "^1.0.0" color-convert@^1.9.0: version "1.9.2" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" dependencies: color-name "1.1.1" color-name@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" colors@1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" colors@^1.1.2: - version "1.3.0" - resolved "https://registry.npmjs.org/colors/-/colors-1.3.0.tgz#5f20c9fef6945cb1134260aab33bfbdc8295e04e" + version "1.3.1" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.1.tgz#4accdb89cf2cabc7f982771925e9468784f32f3d" combined-stream@~0.0.4: version "0.0.7" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" dependencies: delayed-stream "0.0.5" commander@2.12.2: version "2.12.2" - resolved "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" -commander@2.15.1, commander@^2.5.0, commander@^2.6.0: +commander@2.15.1: version "2.15.1" resolved "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" commander@2.8.x: version "2.8.1" - resolved "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" dependencies: graceful-readlink ">= 1.0.0" -commander@~2.14.1: - version "2.14.1" - resolved "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" +commander@^2.5.0, commander@^2.6.0, commander@~2.16.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" common-tags@^1.4.0, common-tags@^1.8.0: version "1.8.0" @@ -2042,41 +2023,41 @@ common-tags@^1.4.0, common-tags@^1.8.0: component-bind@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" component-emitter@1.2.1, component-emitter@^1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" component-inherit@0.0.3: version "0.0.3" - resolved "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" -compressible@~2.0.13: +compressible@~2.0.14: version "2.0.14" - resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7" dependencies: mime-db ">= 1.34.0 < 2" compression@^1.4.4: - version "1.7.2" - resolved "http://registry.npmjs.org/compression/-/compression-1.7.2.tgz#aaffbcd6aaf854b44ebb280353d5ad1651f59a69" + version "1.7.3" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" dependencies: - accepts "~1.3.4" + accepts "~1.3.5" bytes "3.0.0" - compressible "~2.0.13" + compressible "~2.0.14" debug "2.6.9" on-headers "~1.0.1" - safe-buffer "5.1.1" + safe-buffer "5.1.2" vary "~1.1.2" concat-map@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" concat-stream@^1.4.7: version "1.6.2" - resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" dependencies: buffer-from "^1.0.0" inherits "^2.0.3" @@ -2085,7 +2066,7 @@ concat-stream@^1.4.7: configstore@^3.0.0: version "3.1.2" - resolved "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" dependencies: dot-prop "^4.1.0" graceful-fs "^4.1.2" @@ -2096,7 +2077,7 @@ configstore@^3.0.0: connect@^3.3.3: version "3.6.6" - resolved "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" dependencies: debug "2.6.9" finalhandler "1.1.0" @@ -2105,7 +2086,7 @@ connect@^3.3.3: console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" console-ui@^2.2.2: version "2.2.2" @@ -2120,55 +2101,55 @@ console-ui@^2.2.2: consolidate@^0.15.1: version "0.15.1" - resolved "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7" + resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7" dependencies: bluebird "^3.1.1" content-disposition@0.5.2: version "0.5.2" - resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" content-type@~1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" continuable-cache@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" + resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" convert-source-map@^1.5.1: version "1.5.1" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" cookie-signature@1.0.6: version "1.0.6" - resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" cookie@0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" copy-dereference@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" + resolved "https://registry.yarnpkg.com/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" copy-descriptor@^0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" core-js@^2.4.0, core-js@^2.5.0: version "2.5.7" - resolved "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" core-object@^3.1.3, core-object@^3.1.5: version "3.1.5" - resolved "https://registry.npmjs.org/core-object/-/core-object-3.1.5.tgz#fa627b87502adc98045e44678e9a8ec3b9c0d2a9" + resolved "https://registry.yarnpkg.com/core-object/-/core-object-3.1.5.tgz#fa627b87502adc98045e44678e9a8ec3b9c0d2a9" dependencies: chalk "^2.0.0" core-util-is@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" create-error-class@^3.0.0: version "3.0.2" @@ -2178,7 +2159,7 @@ create-error-class@^3.0.0: cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" dependencies: nice-try "^1.0.4" path-key "^2.0.1" @@ -2188,81 +2169,81 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: cryptiles@0.2.x: version "0.2.2" - resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" dependencies: boom "0.4.x" crypto-random-string@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" ctype@0.5.3: version "0.5.3" - resolved "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" + resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" currently-unhandled@^0.4.1: version "0.4.1" - resolved "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" dependencies: array-find-index "^1.0.1" d@1: version "1.0.0" - resolved "https://registry.npmjs.org/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" dependencies: es5-ext "^0.10.9" dag-map@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" + resolved "https://registry.yarnpkg.com/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" date-time@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/date-time/-/date-time-2.1.0.tgz#0286d1b4c769633b3ca13e1e62558d2dbdc2eba2" + resolved "https://registry.yarnpkg.com/date-time/-/date-time-2.1.0.tgz#0286d1b4c769633b3ca13e1e62558d2dbdc2eba2" dependencies: time-zone "^1.0.0" -debug@2, debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.4.0, debug@^2.6.8, debug@^2.6.9: +debug@2, debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: ms "2.0.0" debug@3.1.0, debug@^3.0.0, debug@^3.1.0, debug@~3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: ms "2.0.0" decamelize@^1.0.0, decamelize@^1.1.2: version "1.2.0" - resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" decode-uri-component@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" decompress-response@^3.3.0: version "3.3.0" - resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" dependencies: mimic-response "^1.0.0" deep-eql@^0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" dependencies: type-detect "0.1.1" deep-eql@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" dependencies: type-detect "^4.0.0" deep-extend@^0.6.0: version "0.6.0" - resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" deep-is@~0.1.3: version "0.1.3" @@ -2270,7 +2251,7 @@ deep-is@~0.1.3: defaults@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" dependencies: clone "^1.0.2" @@ -2283,19 +2264,19 @@ define-properties@^1.1.2: define-property@^0.2.5: version "0.2.5" - resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" dependencies: is-descriptor "^1.0.0" define-property@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" dependencies: is-descriptor "^1.0.2" isobject "^3.0.1" @@ -2314,51 +2295,51 @@ del@^2.0.2: delayed-stream@0.0.5: version "0.0.5" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" delegates@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" depd@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" depd@~1.1.1, depd@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" destroy@~1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" detect-file@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" dependencies: fs-exists-sync "^0.1.0" detect-file@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" detect-indent@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" dependencies: repeating "^2.0.0" detect-indent@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" detect-libc@^1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" diff@3.5.0, diff@^3.2.0: version "3.5.0" - resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" doctrine@^2.1.0: version "2.1.0" @@ -2368,7 +2349,7 @@ doctrine@^2.1.0: dot-prop@^4.1.0: version "4.2.0" - resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" dependencies: is-obj "^1.0.0" @@ -2378,19 +2359,19 @@ duplex@~1.0.0: duplexer3@^0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" editions@^1.1.1: version "1.3.4" - resolved "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" + resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" ee-first@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" electron-to-chromium@^1.3.47: - version "1.3.50" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.50.tgz#7438b76f92b41b919f3fbdd350fbd0757dacddf7" + version "1.3.52" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz#d2d9f1270ba4a3b967b831c40ef71fb4d9ab5ce0" ember-cli-app-version@^3.2.0: version "3.2.0" @@ -2399,25 +2380,7 @@ ember-cli-app-version@^3.2.0: ember-cli-babel "^6.12.0" git-repo-version "^1.0.2" -ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: - version "6.14.1" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.14.1.tgz#796339229035910b625593caffbc2683792ada68" - dependencies: - amd-name-resolver "1.2.0" - babel-plugin-debug-macros "^0.1.11" - babel-plugin-ember-modules-api-polyfill "^2.3.0" - babel-plugin-transform-es2015-modules-amd "^6.24.0" - babel-polyfill "^6.26.0" - babel-preset-env "^1.7.0" - broccoli-babel-transpiler "^6.4.2" - broccoli-debug "^0.6.4" - broccoli-funnel "^2.0.0" - broccoli-source "^1.1.0" - clone "^2.0.0" - ember-cli-version-checker "^2.1.2" - semver "^5.5.0" - -ember-cli-babel@^6.16.0: +ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: version "6.16.0" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.16.0.tgz#623b4a2764ece72b65f1572fc8aeb5714a450228" dependencies: @@ -2437,7 +2400,7 @@ ember-cli-babel@^6.16.0: ember-cli-blueprint-test-helpers@^0.18.3: version "0.18.3" - resolved "https://registry.npmjs.org/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.18.3.tgz#945c606d855f0263f5e8c03522e4040a74f259cc" + resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.18.3.tgz#945c606d855f0263f5e8c03522e4040a74f259cc" dependencies: chai "^4.1.0" chai-as-promised "^7.0.0" @@ -2450,7 +2413,7 @@ ember-cli-blueprint-test-helpers@^0.18.3: ember-cli-broccoli-sane-watcher@^2.0.4: version "2.1.1" - resolved "https://registry.npmjs.org/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.1.1.tgz#1687adada9022de26053fba833dc7dd10f03dd08" + resolved "https://registry.yarnpkg.com/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.1.1.tgz#1687adada9022de26053fba833dc7dd10f03dd08" dependencies: broccoli-slow-trees "^3.0.1" heimdalljs "^0.2.1" @@ -2470,7 +2433,7 @@ ember-cli-dependency-checker@^3.0.0: ember-cli-get-component-path-option@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" + resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" ember-cli-htmlbars-inline-precompile@^1.0.0, ember-cli-htmlbars-inline-precompile@^1.0.3: version "1.0.3" @@ -2499,7 +2462,7 @@ ember-cli-inject-live-reload@^1.8.2: ember-cli-internal-test-helpers@^0.9.1: version "0.9.1" - resolved "https://registry.npmjs.org/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.9.1.tgz#d54a9124bb6408ceba83f049ba8479f4b96cdd19" + resolved "https://registry.yarnpkg.com/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.9.1.tgz#d54a9124bb6408ceba83f049ba8479f4b96cdd19" dependencies: chai "^3.3.0" chai-as-promised "^6.0.0" @@ -2516,42 +2479,41 @@ ember-cli-internal-test-helpers@^0.9.1: ember-cli-is-package-missing@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" + resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" ember-cli-lodash-subset@^1.0.7: version "1.0.12" - resolved "https://registry.npmjs.org/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" + resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" ember-cli-lodash-subset@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/ember-cli-lodash-subset/-/ember-cli-lodash-subset-2.0.1.tgz#20cb68a790fe0fde2488ddfd8efbb7df6fe766f2" + resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-2.0.1.tgz#20cb68a790fe0fde2488ddfd8efbb7df6fe766f2" ember-cli-normalize-entity-name@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" + resolved "https://registry.yarnpkg.com/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" dependencies: silent-error "^1.0.0" ember-cli-path-utils@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" + resolved "https://registry.yarnpkg.com/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" ember-cli-preprocess-registry@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.1.tgz#38456c21c4d2b64945850cf9ec68db6ba769288a" + version "3.1.2" + resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.2.tgz#083efb21fd922c021ceba9e08f4d9278249fc4db" dependencies: broccoli-clean-css "^1.1.0" broccoli-funnel "^1.0.0" broccoli-merge-trees "^1.0.0" debug "^2.2.0" ember-cli-lodash-subset "^1.0.7" - exists-sync "0.0.3" process-relative-require "^1.0.0" silent-error "^1.0.0" ember-cli-pretender@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-1.0.1.tgz#35540babddef6f2778e91c627d190c73505103cd" + resolved "https://registry.yarnpkg.com/ember-cli-pretender/-/ember-cli-pretender-1.0.1.tgz#35540babddef6f2778e91c627d190c73505103cd" dependencies: broccoli-funnel "^1.1.0" broccoli-merge-trees "^1.2.1" @@ -2560,7 +2522,7 @@ ember-cli-pretender@^1.0.1: ember-cli-release@^0.2.9: version "0.2.9" - resolved "https://registry.npmjs.org/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" + resolved "https://registry.yarnpkg.com/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" dependencies: chalk "^1.0.0" git-tools "^0.1.4" @@ -2590,17 +2552,17 @@ ember-cli-sri@^2.1.1: ember-cli-string-utils@^1.0.0, ember-cli-string-utils@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" + resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" ember-cli-test-info@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" + resolved "https://registry.yarnpkg.com/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" dependencies: ember-cli-string-utils "^1.0.0" ember-cli-test-loader@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/ember-cli-test-loader/-/ember-cli-test-loader-2.2.0.tgz#3fb8d5d1357e4460d3f0a092f5375e71b6f7c243" + resolved "https://registry.yarnpkg.com/ember-cli-test-loader/-/ember-cli-test-loader-2.2.0.tgz#3fb8d5d1357e4460d3f0a092f5375e71b6f7c243" dependencies: ember-cli-babel "^6.8.1" @@ -2613,13 +2575,13 @@ ember-cli-uglify@2.1.0: ember-cli-valid-component-name@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" + resolved "https://registry.yarnpkg.com/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" dependencies: silent-error "^1.0.0" ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-version-checker@^2.1.1, ember-cli-version-checker@^2.1.2: version "2.1.2" - resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-2.1.2.tgz#305ce102390c66e4e0f1432dea9dc5c7c19fed98" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.1.2.tgz#305ce102390c66e4e0f1432dea9dc5c7c19fed98" dependencies: resolve "^1.3.3" semver "^5.3.0" @@ -2726,8 +2688,8 @@ ember-cli@^3.3.0: yam "^0.0.24" ember-compatibility-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/ember-compatibility-helpers/-/ember-compatibility-helpers-1.0.0.tgz#616b22d2e14b4c6a1f4441e5390a49abf52b3c68" + version "1.0.2" + resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.0.2.tgz#a7eb8969747d063720fe44658af5448589b437ba" dependencies: babel-plugin-debug-macros "^0.1.11" ember-cli-version-checker "^2.1.1" @@ -2751,7 +2713,7 @@ ember-disable-prototype-extensions@^1.1.3: ember-export-application-global@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/ember-export-application-global/-/ember-export-application-global-2.0.0.tgz#8d6d7619ac8a1a3f8c43003549eb21ebed685bd2" + resolved "https://registry.yarnpkg.com/ember-export-application-global/-/ember-export-application-global-2.0.0.tgz#8d6d7619ac8a1a3f8c43003549eb21ebed685bd2" dependencies: ember-cli-babel "^6.0.0-beta.7" @@ -2763,13 +2725,13 @@ ember-inflector@^3.0.0: ember-load-initializers@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/ember-load-initializers/-/ember-load-initializers-1.1.0.tgz#4edacc0f3a14d9f53d241ac3e5561804c8377978" + resolved "https://registry.yarnpkg.com/ember-load-initializers/-/ember-load-initializers-1.1.0.tgz#4edacc0f3a14d9f53d241ac3e5561804c8377978" dependencies: ember-cli-babel "^6.6.0" ember-maybe-import-regenerator@^0.1.6: version "0.1.6" - resolved "https://registry.npmjs.org/ember-maybe-import-regenerator/-/ember-maybe-import-regenerator-0.1.6.tgz#35d41828afa6d6a59bc0da3ce47f34c573d776ca" + resolved "https://registry.yarnpkg.com/ember-maybe-import-regenerator/-/ember-maybe-import-regenerator-0.1.6.tgz#35d41828afa6d6a59bc0da3ce47f34c573d776ca" dependencies: broccoli-funnel "^1.0.1" broccoli-merge-trees "^1.0.0" @@ -2778,13 +2740,13 @@ ember-maybe-import-regenerator@^0.1.6: ember-publisher@0.0.7: version "0.0.7" - resolved "https://registry.npmjs.org/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" + resolved "https://registry.yarnpkg.com/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" dependencies: aws-sdk "^2.0.9" ember-qunit-assert-helpers@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/ember-qunit-assert-helpers/-/ember-qunit-assert-helpers-0.2.1.tgz#4a77f8ff252e47cc53db6fa7fb4becb426de8d29" + resolved "https://registry.yarnpkg.com/ember-qunit-assert-helpers/-/ember-qunit-assert-helpers-0.2.1.tgz#4a77f8ff252e47cc53db6fa7fb4becb426de8d29" dependencies: broccoli-filter "^1.0.1" ember-cli-babel "^6.9.0" @@ -2815,11 +2777,11 @@ ember-resolver@^5.0.1: ember-rfc176-data@^0.3.0, ember-rfc176-data@^0.3.1: version "0.3.3" - resolved "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.3.3.tgz#27fba08d540a7463a4366c48eaa19c5a44971a39" + resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.3.tgz#27fba08d540a7463a4366c48eaa19c5a44971a39" ember-router-generator@^1.2.3: version "1.2.3" - resolved "https://registry.npmjs.org/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" + resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" dependencies: recast "^0.11.3" @@ -2882,11 +2844,11 @@ emit-function@0.0.2: encodeurl@~1.0.1, encodeurl@~1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" engine.io-client@~3.2.0: version "3.2.1" - resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" dependencies: component-emitter "1.2.1" component-inherit "0.0.3" @@ -2902,7 +2864,7 @@ engine.io-client@~3.2.0: engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: version "2.1.2" - resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196" dependencies: after "0.8.2" arraybuffer.slice "~0.0.7" @@ -2912,7 +2874,7 @@ engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: engine.io@~3.2.0: version "3.2.0" - resolved "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz#54332506f42f2edc71690d2f2a42349359f3bf7d" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.0.tgz#54332506f42f2edc71690d2f2a42349359f3bf7d" dependencies: accepts "~1.3.4" base64id "1.0.0" @@ -2923,21 +2885,21 @@ engine.io@~3.2.0: ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" + resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" entities@~1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" error-ex@^1.2.0: version "1.3.2" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" dependencies: is-arrayish "^0.2.1" error@^7.0.0: version "7.0.2" - resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" + resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" dependencies: string-template "~0.2.1" xtend "~4.0.0" @@ -2962,7 +2924,7 @@ es-to-primitive@^1.1.1: es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: version "0.10.45" - resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz#0bfdf7b473da5919d5adf3bd25ceb754fccc3653" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.45.tgz#0bfdf7b473da5919d5adf3bd25ceb754fccc3653" dependencies: es6-iterator "~2.0.3" es6-symbol "~3.1.1" @@ -2970,7 +2932,7 @@ es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: es6-iterator@~2.0.1, es6-iterator@~2.0.3: version "2.0.3" - resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" dependencies: d "1" es5-ext "^0.10.35" @@ -2978,7 +2940,7 @@ es6-iterator@~2.0.1, es6-iterator@~2.0.3: es6-map@^0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" dependencies: d "1" es5-ext "~0.10.14" @@ -2989,7 +2951,7 @@ es6-map@^0.1.5: es6-set@~0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" dependencies: d "1" es5-ext "~0.10.14" @@ -2999,22 +2961,22 @@ es6-set@~0.1.5: es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" dependencies: d "1" es5-ext "~0.10.14" escape-html@~1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" eslint-config-prettier@^2.9.0: version "2.9.0" - resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" dependencies: get-stdin "^5.0.1" @@ -3063,7 +3025,7 @@ eslint-utils@^1.3.0, eslint-utils@^1.3.1: eslint-visitor-keys@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" eslint@^5.3.0: version "5.3.0" @@ -3117,20 +3079,20 @@ espree@^4.0.0: acorn-jsx "^4.1.1" esprima@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" esprima@~3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" esprima@~3.1.0: version "3.1.3" - resolved "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" esprimaq@^0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" + resolved "https://registry.yarnpkg.com/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" esquery@^1.0.1: version "1.0.1" @@ -3140,62 +3102,62 @@ esquery@^1.0.1: esrecurse@^4.1.0: version "4.2.1" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" dependencies: estraverse "^4.1.0" estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" estree-walker@^0.5.2: version "0.5.2" - resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-0.5.2.tgz#d3850be7529c9580d815600b53126515e146dd39" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.5.2.tgz#d3850be7529c9580d815600b53126515e146dd39" esutils@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" etag@~1.8.1: version "1.8.1" - resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" event-emitter@~0.3.5: version "0.3.5" - resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" dependencies: d "1" es5-ext "~0.10.14" eventemitter3@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" events-to-array@^1.0.1: version "1.1.2" - resolved "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" + resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" events@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" exec-file-sync@^2.0.0: version "2.0.2" - resolved "https://registry.npmjs.org/exec-file-sync/-/exec-file-sync-2.0.2.tgz#58d441db46e40de6d1f30de5be022785bd89e328" + resolved "https://registry.yarnpkg.com/exec-file-sync/-/exec-file-sync-2.0.2.tgz#58d441db46e40de6d1f30de5be022785bd89e328" dependencies: is-obj "^1.0.0" object-assign "^4.0.1" spawn-sync "^1.0.11" exec-sh@^0.2.0: - version "0.2.1" - resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" + version "0.2.2" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" dependencies: - merge "^1.1.3" + merge "^1.2.0" execa@^0.10.0: version "0.10.0" - resolved "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" dependencies: cross-spawn "^6.0.0" get-stream "^3.0.0" @@ -3207,33 +3169,33 @@ execa@^0.10.0: exists-stat@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/exists-stat/-/exists-stat-1.0.0.tgz#0660e3525a2e89d9e446129440c272edfa24b529" + resolved "https://registry.yarnpkg.com/exists-stat/-/exists-stat-1.0.0.tgz#0660e3525a2e89d9e446129440c272edfa24b529" exists-sync@0.0.3: version "0.0.3" - resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" + resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" exists-sync@0.0.4: version "0.0.4" - resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" + resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" exit-hook@^1.0.0: version "1.1.1" - resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" exit@^0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" expand-brackets@^0.1.4: version "0.1.5" - resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" dependencies: is-posix-bracket "^0.1.0" expand-brackets@^2.1.4: version "2.1.4" - resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" dependencies: debug "^2.3.3" define-property "^0.2.5" @@ -3245,25 +3207,25 @@ expand-brackets@^2.1.4: expand-range@^1.8.1: version "1.8.2" - resolved "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" dependencies: fill-range "^2.1.0" expand-tilde@^1.2.2: version "1.2.2" - resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" dependencies: os-homedir "^1.0.1" expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" dependencies: homedir-polyfill "^1.0.1" express@^4.10.7, express@^4.12.3, express@^4.13.1: version "4.16.3" - resolved "https://registry.npmjs.org/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" dependencies: accepts "~1.3.5" array-flatten "1.1.1" @@ -3298,24 +3260,24 @@ express@^4.10.7, express@^4.12.3, express@^4.13.1: extend-shallow@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" dependencies: assign-symbols "^1.0.0" is-extendable "^1.0.1" extend@3, extend@^3.0.0, extend@~3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" external-editor@^1.1.0: version "1.1.1" - resolved "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" dependencies: extend "^3.0.0" spawn-sync "^1.0.15" @@ -3331,13 +3293,13 @@ external-editor@^2.1.0: extglob@^0.3.1: version "0.3.2" - resolved "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" dependencies: is-extglob "^1.0.0" extglob@^2.0.4: version "2.0.4" - resolved "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" dependencies: array-unique "^0.3.2" define-property "^1.0.0" @@ -3350,7 +3312,7 @@ extglob@^2.0.4: fake-xml-http-request@^1.6.0: version "1.6.0" - resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-1.6.0.tgz#bd0ac79ae3e2660098282048a12c730a6f64d550" + resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-1.6.0.tgz#bd0ac79ae3e2660098282048a12c730a6f64d550" fast-deep-equal@^2.0.1: version "2.0.1" @@ -3358,7 +3320,7 @@ fast-deep-equal@^2.0.1: fast-diff@^1.1.1: version "1.1.2" - resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" fast-json-stable-stringify@^2.0.0: version "2.0.0" @@ -3370,23 +3332,10 @@ fast-levenshtein@~2.0.4: fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" + resolved "https://registry.yarnpkg.com/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" dependencies: blank-object "^1.0.1" -fast-sourcemap-concat@^1.0.1: - version "1.3.0" - resolved "https://registry.npmjs.org/fast-sourcemap-concat/-/fast-sourcemap-concat-1.3.0.tgz#cc618e4d6f68106b598a532e174076075bb82400" - dependencies: - chalk "^2.0.0" - fs-extra "^0.30.0" - heimdalljs-logger "^0.1.7" - memory-streams "^0.1.0" - mkdirp "^0.5.0" - source-map "^0.4.2" - source-map-url "^0.3.0" - sourcemap-validator "^1.0.5" - fast-sourcemap-concat@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/fast-sourcemap-concat/-/fast-sourcemap-concat-1.3.2.tgz#148a3e15260177f9e4d3ad90a8bcad0c47b8d073" @@ -3402,19 +3351,19 @@ fast-sourcemap-concat@^1.3.1: faye-websocket@~0.10.0: version "0.10.0" - resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" dependencies: websocket-driver ">=0.5.1" fb-watchman@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" dependencies: bser "^2.0.0" figures@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" dependencies: escape-string-regexp "^1.0.5" @@ -3427,15 +3376,15 @@ file-entry-cache@^2.0.0: filename-regex@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" filesize@^3.1.3: version "3.6.1" - resolved "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" fill-range@^2.1.0: version "2.2.4" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" dependencies: is-number "^2.1.0" isobject "^2.0.0" @@ -3445,7 +3394,7 @@ fill-range@^2.1.0: fill-range@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" dependencies: extend-shallow "^2.0.1" is-number "^3.0.0" @@ -3454,7 +3403,7 @@ fill-range@^4.0.0: finalhandler@1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" dependencies: debug "2.6.9" encodeurl "~1.0.1" @@ -3466,7 +3415,7 @@ finalhandler@1.1.0: finalhandler@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" dependencies: debug "2.6.9" encodeurl "~1.0.2" @@ -3478,31 +3427,31 @@ finalhandler@1.1.1: find-index@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" + resolved "https://registry.yarnpkg.com/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" find-up@^1.0.0: version "1.1.2" - resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" find-up@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" dependencies: locate-path "^2.0.0" find-yarn-workspace-root@^1.0.0, find-yarn-workspace-root@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-1.1.0.tgz#9817b6748cb90719f4dc37b4538bb200c697356f" + resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-1.1.0.tgz#9817b6748cb90719f4dc37b4538bb200c697356f" dependencies: fs-extra "^4.0.3" micromatch "^3.1.4" findup-sync@2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" dependencies: detect-file "^1.0.0" is-glob "^3.1.0" @@ -3511,7 +3460,7 @@ findup-sync@2.0.0: findup-sync@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-1.0.0.tgz#6f7e4b57b6ee3a4037b4414eaedea3f58f71e0ec" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-1.0.0.tgz#6f7e4b57b6ee3a4037b4414eaedea3f58f71e0ec" dependencies: detect-file "^0.1.0" is-glob "^2.0.1" @@ -3520,7 +3469,7 @@ findup-sync@^1.0.0: fireworm@^0.7.0: version "0.7.1" - resolved "https://registry.npmjs.org/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" + resolved "https://registry.yarnpkg.com/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" dependencies: async "~0.2.9" is-type "0.0.1" @@ -3530,7 +3479,7 @@ fireworm@^0.7.0: fixturify@^0.3.2: version "0.3.4" - resolved "https://registry.npmjs.org/fixturify/-/fixturify-0.3.4.tgz#c676de404a7f8ee8e64d0b76118e62ec95ab7b25" + resolved "https://registry.yarnpkg.com/fixturify/-/fixturify-0.3.4.tgz#c676de404a7f8ee8e64d0b76118e62ec95ab7b25" dependencies: fs-extra "^0.30.0" matcher-collection "^1.0.4" @@ -3546,24 +3495,24 @@ flat-cache@^1.2.1: follow-redirects@0.0.7: version "0.0.7" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" dependencies: debug "^2.2.0" stream-consume "^0.1.0" follow-redirects@^1.0.0: - version "1.5.0" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.0.tgz#234f49cf770b7f35b40e790f636ceba0c3a0ab77" + version "1.5.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.1.tgz#67a8f14f5a1f67f962c2c46469c79eaec0a90291" dependencies: debug "^3.1.0" for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" for-own@^0.1.4: version "0.1.5" - resolved "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" dependencies: for-in "^1.0.1" @@ -3573,11 +3522,11 @@ foreach@^2.0.5: forever-agent@~0.5.0: version "0.5.2" - resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" form-data@~0.1.0: version "0.1.4" - resolved "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" dependencies: async "~0.9.0" combined-stream "~0.0.4" @@ -3585,32 +3534,32 @@ form-data@~0.1.0: forwarded@~0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" fragment-cache@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" dependencies: map-cache "^0.2.2" fresh@0.5.2: version "0.5.2" - resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" from2@^2.1.1: version "2.3.0" - resolved "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" dependencies: inherits "^2.0.1" readable-stream "^2.0.0" fs-exists-sync@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" fs-extra@^0.24.0: version "0.24.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -3619,7 +3568,7 @@ fs-extra@^0.24.0: fs-extra@^0.30.0: version "0.30.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -3627,24 +3576,9 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" -fs-extra@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - -fs-extra@^2.0.0: - version "2.1.2" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - fs-extra@^4.0.0, fs-extra@^4.0.2, fs-extra@^4.0.3: version "4.0.3" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -3652,7 +3586,7 @@ fs-extra@^4.0.0, fs-extra@^4.0.2, fs-extra@^4.0.3: fs-extra@^5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -3660,7 +3594,7 @@ fs-extra@^5.0.0: fs-extra@^6.0.1: version "6.0.1" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b" dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -3676,13 +3610,13 @@ fs-extra@^7.0.0: fs-minipass@^1.2.5: version "1.2.5" - resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" dependencies: minipass "^2.2.1" fs-sync@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" + resolved "https://registry.yarnpkg.com/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" dependencies: glob "^7.1.0" iconv-lite "^0.4.13" @@ -3692,7 +3626,7 @@ fs-sync@^1.0.4: fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6, fs-tree-diff@^0.5.7: version "0.5.7" - resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.7.tgz#315e2b098d5fe7f622880ac965b1b051868ac871" + resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-0.5.7.tgz#315e2b098d5fe7f622880ac965b1b051868ac871" dependencies: heimdalljs-logger "^0.1.7" object-assign "^4.1.0" @@ -3711,11 +3645,11 @@ fs-updater@^1.0.4: fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" fsevents@^1.0.0, fsevents@^1.2.3: version "1.2.4" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" dependencies: nan "^2.9.2" node-pre-gyp "^0.10.0" @@ -3730,7 +3664,7 @@ functional-red-black-tree@^1.0.1: gauge@~2.7.3: version "2.7.4" - resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -3742,28 +3676,28 @@ gauge@~2.7.3: wide-align "^1.1.0" get-caller-file@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" get-func-name@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" get-stdin@^4.0.1: version "4.0.1" - resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" get-stdin@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" - resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" git-fetch-pack@^0.1.1: version "0.1.1" @@ -3790,7 +3724,7 @@ git-read-pkt-line@0.0.8: git-repo-info@^1.0.4, git-repo-info@^1.4.1: version "1.4.1" - resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" + resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" git-repo-info@^2.0.0: version "2.0.0" @@ -3804,13 +3738,13 @@ git-repo-version@0.2.0: git-repo-version@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/git-repo-version/-/git-repo-version-1.0.2.tgz#2c8e9bee5d970cafc0dd58480f9dc56d9afe8e4f" + resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-1.0.2.tgz#2c8e9bee5d970cafc0dd58480f9dc56d9afe8e4f" dependencies: git-repo-info "^1.4.1" git-tools@^0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" + resolved "https://registry.yarnpkg.com/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" dependencies: spawnback "~1.0.0" @@ -3833,7 +3767,7 @@ git-write-pkt-line@0.1.0: github@^1.1.1: version "1.4.0" - resolved "https://registry.npmjs.org/github/-/github-1.4.0.tgz#60aed8f16ffe381a3ca6dc6dba5bdd64445b7856" + resolved "https://registry.yarnpkg.com/github/-/github-1.4.0.tgz#60aed8f16ffe381a3ca6dc6dba5bdd64445b7856" dependencies: follow-redirects "0.0.7" https-proxy-agent "^1.0.0" @@ -3841,20 +3775,20 @@ github@^1.1.1: glob-base@^0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" dependencies: glob-parent "^2.0.0" is-glob "^2.0.0" glob-parent@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" dependencies: is-glob "^2.0.0" glob@7.1.2, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: version "7.1.2" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -3865,7 +3799,7 @@ glob@7.1.2, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: glob@^4.3.2: version "4.5.3" - resolved "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" + resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" dependencies: inflight "^1.0.4" inherits "2" @@ -3874,7 +3808,7 @@ glob@^4.3.2: glob@^5.0.10: version "5.0.15" - resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: inflight "^1.0.4" inherits "2" @@ -3884,14 +3818,14 @@ glob@^5.0.10: global-modules@^0.2.3: version "0.2.3" - resolved "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" dependencies: global-prefix "^0.1.4" is-windows "^0.2.0" global-modules@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" dependencies: global-prefix "^1.0.1" is-windows "^1.0.1" @@ -3899,7 +3833,7 @@ global-modules@^1.0.0: global-prefix@^0.1.4: version "0.1.5" - resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" dependencies: homedir-polyfill "^1.0.0" ini "^1.3.4" @@ -3908,7 +3842,7 @@ global-prefix@^0.1.4: global-prefix@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" dependencies: expand-tilde "^2.0.2" homedir-polyfill "^1.0.1" @@ -3918,11 +3852,11 @@ global-prefix@^1.0.1: globals@^11.1.0, globals@^11.7.0: version "11.7.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" globals@^9.18.0: version "9.18.0" - resolved "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" globby@^5.0.0: version "5.0.0" @@ -3952,8 +3886,8 @@ got@^6.7.1: url-parse-lax "^1.0.0" got@^8.0.1: - version "8.3.1" - resolved "https://registry.npmjs.org/got/-/got-8.3.1.tgz#093324403d4d955f5a16a7a8d39955d055ae10ed" + version "8.3.2" + resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" dependencies: "@sindresorhus/is" "^0.7.0" cacheable-request "^2.1.1" @@ -3975,11 +3909,11 @@ got@^8.0.1: graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" "graceful-readlink@>= 1.0.0": version "1.0.1" - resolved "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" growl@1.10.5: version "1.10.5" @@ -3987,11 +3921,11 @@ growl@1.10.5: growly@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" handlebars@^4.0.4: version "4.0.11" - resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" dependencies: async "^1.4.0" optimist "^0.6.1" @@ -4001,27 +3935,27 @@ handlebars@^4.0.4: has-ansi@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" dependencies: ansi-regex "^2.0.0" has-binary2@~1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" dependencies: isarray "2.0.1" has-cors@1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" has-symbol-support-x@^1.4.1: version "1.4.2" - resolved "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" has-symbols@^1.0.0: version "1.0.0" @@ -4029,17 +3963,17 @@ has-symbols@^1.0.0: has-to-string-tag-x@^1.2.0: version "1.4.1" - resolved "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" dependencies: has-symbol-support-x "^1.4.1" has-unicode@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" has-value@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" dependencies: get-value "^2.0.3" has-values "^0.1.4" @@ -4047,7 +3981,7 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" dependencies: get-value "^2.0.6" has-values "^1.0.0" @@ -4055,11 +3989,11 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" has-values@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" dependencies: is-number "^3.0.0" kind-of "^4.0.0" @@ -4072,7 +4006,7 @@ has@^1.0.1: hash-for-dep@^1.0.2, hash-for-dep@^1.2.3: version "1.2.3" - resolved "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.2.3.tgz#5ec69fca32c23523972d52acb5bb65ffc3664cab" + resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.2.3.tgz#5ec69fca32c23523972d52acb5bb65ffc3664cab" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" heimdalljs "^0.2.3" @@ -4081,7 +4015,7 @@ hash-for-dep@^1.0.2, hash-for-dep@^1.2.3: hawk@1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" dependencies: boom "0.4.x" cryptiles "0.2.x" @@ -4094,62 +4028,62 @@ he@1.1.1: heimdalljs-fs-monitor@^0.2.0: version "0.2.1" - resolved "https://registry.npmjs.org/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.2.1.tgz#b4079cfb85fb8326b8c75a7538fdbfa3d8afaa63" + resolved "https://registry.yarnpkg.com/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.2.1.tgz#b4079cfb85fb8326b8c75a7538fdbfa3d8afaa63" dependencies: heimdalljs "^0.2.0" heimdalljs-logger "^0.1.7" heimdalljs-graph@^0.3.1: version "0.3.4" - resolved "https://registry.npmjs.org/heimdalljs-graph/-/heimdalljs-graph-0.3.4.tgz#0bd75797beeaa20b0ed59017aed3b2d95312acee" + resolved "https://registry.yarnpkg.com/heimdalljs-graph/-/heimdalljs-graph-0.3.4.tgz#0bd75797beeaa20b0ed59017aed3b2d95312acee" heimdalljs-logger@^0.1.7, heimdalljs-logger@^0.1.9: version "0.1.9" - resolved "https://registry.npmjs.org/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz#d76ada4e45b7bb6f786fc9c010a68eb2e2faf176" + resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz#d76ada4e45b7bb6f786fc9c010a68eb2e2faf176" dependencies: debug "^2.2.0" heimdalljs "^0.2.0" heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3, heimdalljs@^0.2.5: version "0.2.5" - resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.2.5.tgz#6aa54308eee793b642cff9cf94781445f37730ac" + resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.5.tgz#6aa54308eee793b642cff9cf94781445f37730ac" dependencies: rsvp "~3.2.1" heimdalljs@^0.3.0: version "0.3.3" - resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" + resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" dependencies: rsvp "~3.2.1" hoek@0.9.x: version "0.9.1" - resolved "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" home-or-tmp@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.1" homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" dependencies: parse-passwd "^1.0.0" hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: - version "2.6.1" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.1.tgz#6e4cee78b01bb849dcf93527708c69fdbee410df" + version "2.7.1" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" http-cache-semantics@3.8.1: version "3.8.1" - resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" http-errors@1.6.2: version "1.6.2" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" dependencies: depd "1.1.1" inherits "2.0.3" @@ -4158,7 +4092,7 @@ http-errors@1.6.2: http-errors@~1.6.2: version "1.6.3" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" dependencies: depd "~1.1.2" inherits "2.0.3" @@ -4167,11 +4101,11 @@ http-errors@~1.6.2: http-parser-js@>=0.4.0: version "0.4.13" - resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.13.tgz#3bd6d6fde6e3172c9334c3b33b6c193d80fe1137" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.13.tgz#3bd6d6fde6e3172c9334c3b33b6c193d80fe1137" http-proxy@^1.13.1, http-proxy@^1.9.0: version "1.17.0" - resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" dependencies: eventemitter3 "^3.0.0" follow-redirects "^1.0.0" @@ -4179,7 +4113,7 @@ http-proxy@^1.13.1, http-proxy@^1.9.0: http-signature@~0.10.0: version "0.10.1" - resolved "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" dependencies: asn1 "0.1.11" assert-plus "^0.1.5" @@ -4187,7 +4121,7 @@ http-signature@~0.10.0: https-proxy-agent@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" dependencies: agent-base "2" debug "2" @@ -4195,25 +4129,25 @@ https-proxy-agent@^1.0.0: iconv-lite@0.4.19: version "0.4.19" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" iconv-lite@^0.4.13, iconv-lite@^0.4.17, iconv-lite@^0.4.4: version "0.4.23" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: safer-buffer ">= 2.1.2 < 3" ieee754@1.1.8: version "1.1.8" - resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" ieee754@^1.1.4: version "1.1.12" - resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" ignore-walk@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" dependencies: minimatch "^3.0.4" @@ -4223,40 +4157,40 @@ ignore@^4.0.2: imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" indent-string@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" dependencies: repeating "^2.0.0" indexof@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" inflection@^1.12.0, inflection@^1.7.0: version "1.12.0" - resolved "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" inflight@^1.0.4: version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" dependencies: once "^1.3.0" wrappy "1" inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" ini@^1.3.4, ini@~1.3.0: version "1.3.5" - resolved "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" inline-source-map-comment@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" + resolved "https://registry.yarnpkg.com/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" dependencies: chalk "^1.0.0" get-stdin "^4.0.1" @@ -4266,7 +4200,7 @@ inline-source-map-comment@^1.0.5: inquirer@^2: version "2.0.0" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-2.0.0.tgz#e1351687b90d150ca403ceaa3cefb1e3065bef4b" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-2.0.0.tgz#e1351687b90d150ca403ceaa3cefb1e3065bef4b" dependencies: ansi-escapes "^1.1.0" chalk "^1.0.0" @@ -4303,50 +4237,50 @@ inquirer@^5.2.0: into-stream@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" + resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" dependencies: from2 "^2.1.1" p-is-promise "^1.1.0" invariant@^2.2.0, invariant@^2.2.2: version "2.2.4" - resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" dependencies: loose-envify "^1.0.0" ipaddr.js@1.6.0: version "1.6.0" - resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" is-accessor-descriptor@^0.1.6: version "0.1.6" - resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" dependencies: kind-of "^3.0.2" is-accessor-descriptor@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" dependencies: kind-of "^6.0.0" is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" is-binary-path@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" dependencies: binary-extensions "^1.0.0" is-buffer@^1.1.5: version "1.1.6" - resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" is-builtin-module@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" dependencies: builtin-modules "^1.0.0" @@ -4356,13 +4290,13 @@ is-callable@^1.1.1, is-callable@^1.1.3: is-data-descriptor@^0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" dependencies: kind-of "^3.0.2" is-data-descriptor@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" dependencies: kind-of "^6.0.0" @@ -4372,7 +4306,7 @@ is-date-object@^1.0.1: is-descriptor@^0.1.0: version "0.1.6" - resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" dependencies: is-accessor-descriptor "^0.1.6" is-data-descriptor "^0.1.4" @@ -4380,7 +4314,7 @@ is-descriptor@^0.1.0: is-descriptor@^1.0.0, is-descriptor@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" dependencies: is-accessor-descriptor "^1.0.0" is-data-descriptor "^1.0.0" @@ -4388,93 +4322,87 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-dotfile@^1.0.0: version "1.0.3" - resolved "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" is-equal-shallow@^0.1.3: version "0.1.3" - resolved "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" dependencies: is-primitive "^2.0.0" is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" is-extendable@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" dependencies: is-plain-object "^2.0.4" is-extglob@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" is-extglob@^2.1.0: version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" is-finite@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" is-git-url@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-git-url/-/is-git-url-1.0.0.tgz#53f684cd143285b52c3244b4e6f28253527af66b" + resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-1.0.0.tgz#53f684cd143285b52c3244b4e6f28253527af66b" is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" dependencies: is-extglob "^1.0.0" is-glob@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" dependencies: is-extglob "^2.1.0" is-number@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" dependencies: kind-of "^3.0.2" is-number@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" dependencies: kind-of "^3.0.2" is-number@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" is-obj@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" is-object@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" - -is-odd@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" - dependencies: - is-number "^4.0.0" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" is-path-cwd@^1.0.0: version "1.0.0" @@ -4494,25 +4422,25 @@ is-path-inside@^1.0.0: is-plain-obj@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" - resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" dependencies: isobject "^3.0.1" is-posix-bracket@^0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" is-primitive@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" is-promise@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" is-redirect@^1.0.0: version "1.0.0" @@ -4520,7 +4448,7 @@ is-redirect@^1.0.0: is-reference@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/is-reference/-/is-reference-1.1.0.tgz#50e6ef3f64c361e2c53c0416cdc9420037f2685b" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.1.0.tgz#50e6ef3f64c361e2c53c0416cdc9420037f2685b" dependencies: "@types/estree" "0.0.38" @@ -4532,7 +4460,7 @@ is-regex@^1.0.4: is-regexp@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" is-resolvable@^1.1.0: version "1.1.0" @@ -4540,11 +4468,11 @@ is-resolvable@^1.1.0: is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" is-stream@^1.0.0, is-stream@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" is-symbol@^1.0.1: version "1.0.1" @@ -4552,55 +4480,55 @@ is-symbol@^1.0.1: is-type@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" + resolved "https://registry.yarnpkg.com/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" dependencies: core-util-is "~1.0.0" is-utf8@^0.2.0: version "0.2.1" - resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" is-windows@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" isarray@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" isarray@2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" isbinaryfile@^3.0.0: version "3.0.2" - resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" isexe@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" isobject@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" istextorbinary@2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" + resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" dependencies: binaryextensions "1 || 2" editions "^1.1.1" @@ -4608,18 +4536,18 @@ istextorbinary@2.1.0: isurl@^1.0.0-alpha5: version "1.0.0" - resolved "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" dependencies: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" jest-docblock@^21.0.0: version "21.2.0" - resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" jmespath@0.15.0: version "0.15.0" - resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" jquery@^3.3.1: version "3.3.1" @@ -4627,38 +4555,42 @@ jquery@^3.3.1: js-reporters@1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b" + resolved "https://registry.yarnpkg.com/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b" js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" js-yaml@^3.11.0, js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.6.1: version "3.12.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" dependencies: argparse "^1.0.7" esprima "^4.0.0" jsesc@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" jsesc@^2.5.1: version "2.5.1" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" jsesc@~0.3.x: version "0.3.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.3.0.tgz#1bf5ee63b4539fe2e26d0c1e99c240b97a457972" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.3.0.tgz#1bf5ee63b4539fe2e26d0c1e99c240b97a457972" jsesc@~0.5.0: version "0.5.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" json-buffer@3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" json-schema-traverse@^0.4.1: version "0.4.1" @@ -4670,73 +4602,73 @@ json-stable-stringify-without-jsonify@^1.0.1: json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: jsonify "~0.0.0" json-stringify-safe@~5.0.0: version "5.0.1" - resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" json5@^0.5.1: version "0.5.1" - resolved "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" jsonfile@^2.1.0: version "2.4.0" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" optionalDependencies: graceful-fs "^4.1.6" jsonfile@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" optionalDependencies: graceful-fs "^4.1.6" jsonify@~0.0.0: version "0.0.0" - resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" keyv@3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" dependencies: json-buffer "3.0.0" kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" dependencies: is-buffer "^1.1.5" kind-of@^5.0.0: version "5.1.0" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.2" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" klaw@^1.0.0: version "1.3.1" - resolved "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" optionalDependencies: graceful-fs "^4.1.9" lazy-cache@^1.0.3: version "1.0.4" - resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" leek@0.0.24: version "0.0.24" - resolved "https://registry.npmjs.org/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" + resolved "https://registry.yarnpkg.com/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" dependencies: debug "^2.1.0" lodash.assign "^3.2.0" @@ -4757,23 +4689,23 @@ line-stream@0.0.0: linkify-it@^2.0.0: version "2.0.3" - resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" dependencies: uc.micro "^1.0.1" linkify-it@~1.2.0: version "1.2.4" - resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" dependencies: uc.micro "^1.0.1" livereload-js@^2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/livereload-js/-/livereload-js-2.3.0.tgz#c3ab22e8aaf5bf3505d80d098cbad67726548c9a" + resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.3.0.tgz#c3ab22e8aaf5bf3505d80d098cbad67726548c9a" load-json-file@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -4787,11 +4719,11 @@ loader.js@^4.7.0: locate-character@^2.0.5: version "2.0.5" - resolved "https://registry.npmjs.org/locate-character/-/locate-character-2.0.5.tgz#f2d2614d49820ecb3c92d80d193b8db755f74c0f" + resolved "https://registry.yarnpkg.com/locate-character/-/locate-character-2.0.5.tgz#f2d2614d49820ecb3c92d80d193b8db755f74c0f" locate-path@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" dependencies: p-locate "^2.0.0" path-exists "^3.0.0" @@ -4802,14 +4734,14 @@ lodash-node@^3.2.0: lodash._baseassign@^3.0.0: version "3.2.0" - resolved "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" dependencies: lodash._basecopy "^3.0.0" lodash.keys "^3.0.0" lodash._basebind@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._basebind/-/lodash._basebind-2.3.0.tgz#2b5bc452a0e106143b21869f233bdb587417d248" + resolved "https://registry.yarnpkg.com/lodash._basebind/-/lodash._basebind-2.3.0.tgz#2b5bc452a0e106143b21869f233bdb587417d248" dependencies: lodash._basecreate "~2.3.0" lodash._setbinddata "~2.3.0" @@ -4817,11 +4749,11 @@ lodash._basebind@~2.3.0: lodash._basecopy@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" lodash._basecreate@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz#9b88a86a4dcff7b7f3c61d83a2fcfc0671ec9de0" + resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz#9b88a86a4dcff7b7f3c61d83a2fcfc0671ec9de0" dependencies: lodash._renative "~2.3.0" lodash.isobject "~2.3.0" @@ -4829,7 +4761,7 @@ lodash._basecreate@~2.3.0: lodash._basecreatecallback@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz#37b2ab17591a339e988db3259fcd46019d7ac362" + resolved "https://registry.yarnpkg.com/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz#37b2ab17591a339e988db3259fcd46019d7ac362" dependencies: lodash._setbinddata "~2.3.0" lodash.bind "~2.3.0" @@ -4838,7 +4770,7 @@ lodash._basecreatecallback@~2.3.0: lodash._basecreatewrapper@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz#aa0c61ad96044c3933376131483a9759c3651247" + resolved "https://registry.yarnpkg.com/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz#aa0c61ad96044c3933376131483a9759c3651247" dependencies: lodash._basecreate "~2.3.0" lodash._setbinddata "~2.3.0" @@ -4847,18 +4779,18 @@ lodash._basecreatewrapper@~2.3.0: lodash._baseflatten@^3.0.0: version "3.1.4" - resolved "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" + resolved "https://registry.yarnpkg.com/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" dependencies: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" lodash._bindcallback@^3.0.0: version "3.0.1" - resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" lodash._createassigner@^3.0.0: version "3.1.1" - resolved "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" dependencies: lodash._bindcallback "^3.0.0" lodash._isiterateecall "^3.0.0" @@ -4866,7 +4798,7 @@ lodash._createassigner@^3.0.0: lodash._createwrapper@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" + resolved "https://registry.yarnpkg.com/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" dependencies: lodash._basebind "~2.3.0" lodash._basecreatewrapper "~2.3.0" @@ -4874,69 +4806,69 @@ lodash._createwrapper@~2.3.0: lodash._escapehtmlchar@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.3.0.tgz#d03da6bd82eedf38dc0a5b503d740ecd0e894592" + resolved "https://registry.yarnpkg.com/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.3.0.tgz#d03da6bd82eedf38dc0a5b503d740ecd0e894592" dependencies: lodash._htmlescapes "~2.3.0" lodash._escapestringchar@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.3.0.tgz#cce73ae60fc6da55d2bf8a0679c23ca2bab149fc" + resolved "https://registry.yarnpkg.com/lodash._escapestringchar/-/lodash._escapestringchar-2.3.0.tgz#cce73ae60fc6da55d2bf8a0679c23ca2bab149fc" lodash._getnative@^3.0.0: version "3.9.1" - resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" lodash._htmlescapes@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._htmlescapes/-/lodash._htmlescapes-2.3.0.tgz#1ca98863cadf1fa1d82c84f35f31e40556a04f3a" + resolved "https://registry.yarnpkg.com/lodash._htmlescapes/-/lodash._htmlescapes-2.3.0.tgz#1ca98863cadf1fa1d82c84f35f31e40556a04f3a" lodash._isiterateecall@^3.0.0: version "3.0.9" - resolved "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" lodash._objecttypes@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz#6a3ea3987dd6eeb8021b2d5c9c303549cc2bae1e" + resolved "https://registry.yarnpkg.com/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz#6a3ea3987dd6eeb8021b2d5c9c303549cc2bae1e" lodash._reinterpolate@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-2.3.0.tgz#03ee9d85c0e55cbd590d71608a295bdda51128ec" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-2.3.0.tgz#03ee9d85c0e55cbd590d71608a295bdda51128ec" lodash._reinterpolate@~3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" lodash._renative@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._renative/-/lodash._renative-2.3.0.tgz#77d8edd4ced26dd5971f9e15a5f772e4e317fbd3" + resolved "https://registry.yarnpkg.com/lodash._renative/-/lodash._renative-2.3.0.tgz#77d8edd4ced26dd5971f9e15a5f772e4e317fbd3" lodash._reunescapedhtml@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.3.0.tgz#db920b55ac7f3ff825939aceb9ba2c231713d24d" + resolved "https://registry.yarnpkg.com/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.3.0.tgz#db920b55ac7f3ff825939aceb9ba2c231713d24d" dependencies: lodash._htmlescapes "~2.3.0" lodash.keys "~2.3.0" lodash._setbinddata@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz#e5610490acd13277d59858d95b5f2727f1508f04" + resolved "https://registry.yarnpkg.com/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz#e5610490acd13277d59858d95b5f2727f1508f04" dependencies: lodash._renative "~2.3.0" lodash.noop "~2.3.0" lodash._shimkeys@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz#611f93149e3e6c721096b48769ef29537ada8ba9" + resolved "https://registry.yarnpkg.com/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz#611f93149e3e6c721096b48769ef29537ada8ba9" dependencies: lodash._objecttypes "~2.3.0" lodash._slice@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash._slice/-/lodash._slice-2.3.0.tgz#147198132859972e4680ca29a5992c855669aa5c" + resolved "https://registry.yarnpkg.com/lodash._slice/-/lodash._slice-2.3.0.tgz#147198132859972e4680ca29a5992c855669aa5c" lodash.assign@^3.2.0: version "3.2.0" - resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" dependencies: lodash._baseassign "^3.0.0" lodash._createassigner "^3.0.0" @@ -4944,11 +4876,11 @@ lodash.assign@^3.2.0: lodash.assignin@^4.1.0: version "4.2.0" - resolved "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" lodash.bind@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.bind/-/lodash.bind-2.3.0.tgz#c2a8e18b68e5ecc152e2b168266116fea5b016cc" + resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-2.3.0.tgz#c2a8e18b68e5ecc152e2b168266116fea5b016cc" dependencies: lodash._createwrapper "~2.3.0" lodash._renative "~2.3.0" @@ -4956,32 +4888,32 @@ lodash.bind@~2.3.0: lodash.castarray@^4.4.0: version "4.4.0" - resolved "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" + resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" lodash.clonedeep@^4.4.1: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" lodash.debounce@^3.1.1: version "3.1.1" - resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" dependencies: lodash._getnative "^3.0.0" lodash.defaults@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-2.3.0.tgz#a832b001f138f3bb9721c2819a2a7cc5ae21ed25" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-2.3.0.tgz#a832b001f138f3bb9721c2819a2a7cc5ae21ed25" dependencies: lodash._objecttypes "~2.3.0" lodash.keys "~2.3.0" lodash.defaultsdeep@^4.6.0: version "4.6.0" - resolved "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.0.tgz#bec1024f85b1bd96cbea405b23c14ad6443a6f81" + resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.0.tgz#bec1024f85b1bd96cbea405b23c14ad6443a6f81" lodash.escape@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.escape/-/lodash.escape-2.3.0.tgz#844c38c58f844e1362ebe96726159b62cf5f2a58" + resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-2.3.0.tgz#844c38c58f844e1362ebe96726159b62cf5f2a58" dependencies: lodash._escapehtmlchar "~2.3.0" lodash._reunescapedhtml "~2.3.0" @@ -4989,25 +4921,25 @@ lodash.escape@~2.3.0: lodash.find@^4.5.1: version "4.6.0" - resolved "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" + resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" lodash.flatten@^3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" dependencies: lodash._baseflatten "^3.0.0" lodash._isiterateecall "^3.0.0" lodash.foreach@~2.3.x: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-2.3.0.tgz#083404c91e846ee77245fdf9d76519c68b2af168" + resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-2.3.0.tgz#083404c91e846ee77245fdf9d76519c68b2af168" dependencies: lodash._basecreatecallback "~2.3.0" lodash.forown "~2.3.0" lodash.forown@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.forown/-/lodash.forown-2.3.0.tgz#24fb4aaf800d45fc2dc60bfec3ce04c836a3ad7f" + resolved "https://registry.yarnpkg.com/lodash.forown/-/lodash.forown-2.3.0.tgz#24fb4aaf800d45fc2dc60bfec3ce04c836a3ad7f" dependencies: lodash._basecreatecallback "~2.3.0" lodash._objecttypes "~2.3.0" @@ -5015,29 +4947,29 @@ lodash.forown@~2.3.0: lodash.identity@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.identity/-/lodash.identity-2.3.0.tgz#6b01a210c9485355c2a913b48b6711219a173ded" + resolved "https://registry.yarnpkg.com/lodash.identity/-/lodash.identity-2.3.0.tgz#6b01a210c9485355c2a913b48b6711219a173ded" lodash.isarguments@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" lodash.isarray@^3.0.0: version "3.0.4" - resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" lodash.isfunction@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz#6b2973e47a647cf12e70d676aea13643706e5267" + resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz#6b2973e47a647cf12e70d676aea13643706e5267" lodash.isobject@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.3.0.tgz#2e16d3fc583da9831968953f2d8e6d73434f6799" + resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-2.3.0.tgz#2e16d3fc583da9831968953f2d8e6d73434f6799" dependencies: lodash._objecttypes "~2.3.0" lodash.keys@^3.0.0: version "3.1.2" - resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" dependencies: lodash._getnative "^3.0.0" lodash.isarguments "^3.0.0" @@ -5045,44 +4977,44 @@ lodash.keys@^3.0.0: lodash.keys@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.3.0.tgz#b350f4f92caa9f45a4a2ecf018454cf2f28ae253" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-2.3.0.tgz#b350f4f92caa9f45a4a2ecf018454cf2f28ae253" dependencies: lodash._renative "~2.3.0" lodash._shimkeys "~2.3.0" lodash.isobject "~2.3.0" -lodash.merge@^4.3.0, lodash.merge@^4.3.1, lodash.merge@^4.6.0: +lodash.merge@^4.3.1, lodash.merge@^4.6.0: version "4.6.1" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" lodash.noop@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.noop/-/lodash.noop-2.3.0.tgz#3059d628d51bbf937cd2a0b6fc3a7f212a669c2c" + resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-2.3.0.tgz#3059d628d51bbf937cd2a0b6fc3a7f212a669c2c" lodash.omit@^4.1.0: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" + resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" lodash.restparam@^3.0.0: version "3.6.1" - resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" lodash.support@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.support/-/lodash.support-2.3.0.tgz#7eaf038af4f0d6aab776b44aa6dcfc80334c9bfd" + resolved "https://registry.yarnpkg.com/lodash.support/-/lodash.support-2.3.0.tgz#7eaf038af4f0d6aab776b44aa6dcfc80334c9bfd" dependencies: lodash._renative "~2.3.0" lodash.template@^4.2.5: version "4.4.0" - resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings "^4.0.0" lodash.template@~2.3.x: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-2.3.0.tgz#4e3e29c433b4cfea675ec835e6f12391c61fd22b" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-2.3.0.tgz#4e3e29c433b4cfea675ec835e6f12391c61fd22b" dependencies: lodash._escapestringchar "~2.3.0" lodash._reinterpolate "~2.3.0" @@ -5094,109 +5026,109 @@ lodash.template@~2.3.x: lodash.templatesettings@^4.0.0: version "4.1.0" - resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-2.3.0.tgz#303d132c342710040d5a18efaa2d572fd03f8cdc" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-2.3.0.tgz#303d132c342710040d5a18efaa2d572fd03f8cdc" dependencies: lodash._reinterpolate "~2.3.0" lodash.escape "~2.3.0" lodash.uniq@^4.2.0: version "4.5.0" - resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" lodash.uniqby@^4.7.0: version "4.7.0" - resolved "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" + resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" lodash.values@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/lodash.values/-/lodash.values-2.3.0.tgz#ca96fbe60a20b0b0ec2ba2ba5fc6a765bd14a3ba" + resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-2.3.0.tgz#ca96fbe60a20b0b0ec2ba2ba5fc6a765bd14a3ba" dependencies: lodash.keys "~2.3.0" lodash@^3.10.1: version "3.10.1" - resolved "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: version "4.17.10" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" log-symbols@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" dependencies: chalk "^2.0.1" longest@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" loose-envify@^1.0.0: - version "1.3.1" - resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" dependencies: - js-tokens "^3.0.0" + js-tokens "^3.0.0 || ^4.0.0" loud-rejection@^1.0.0: version "1.6.0" - resolved "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" dependencies: currently-unhandled "^0.4.1" signal-exit "^3.0.0" lowercase-keys@1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" lowercase-keys@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" magic-string@^0.24.0: version "0.24.1" - resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.24.1.tgz#7e38e5f126cae9f15e71f0cf8e450818ca7d5a8f" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.24.1.tgz#7e38e5f126cae9f15e71f0cf8e450818ca7d5a8f" dependencies: sourcemap-codec "^1.4.1" make-array@^0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" + resolved "https://registry.yarnpkg.com/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" make-dir@^1.0.0: version "1.3.0" - resolved "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" dependencies: pify "^3.0.0" makeerror@1.0.x: version "1.0.11" - resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" dependencies: tmpl "1.0.x" map-cache@^0.2.2: version "0.2.2" - resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" map-visit@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" dependencies: object-visit "^1.0.0" markdown-it-terminal@0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/markdown-it-terminal/-/markdown-it-terminal-0.1.0.tgz#545abd8dd01c3d62353bfcea71db580b51d22bd9" + resolved "https://registry.yarnpkg.com/markdown-it-terminal/-/markdown-it-terminal-0.1.0.tgz#545abd8dd01c3d62353bfcea71db580b51d22bd9" dependencies: ansi-styles "^3.0.0" cardinal "^1.0.0" @@ -5206,7 +5138,7 @@ markdown-it-terminal@0.1.0: markdown-it@^4.3.0: version "4.4.0" - resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" dependencies: argparse "~1.0.2" entities "~1.1.1" @@ -5215,8 +5147,8 @@ markdown-it@^4.3.0: uc.micro "^1.0.0" markdown-it@^8.3.0, markdown-it@^8.3.1: - version "8.4.1" - resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.1.tgz#206fe59b0e4e1b78a7c73250af9b34a4ad0aaf44" + version "8.4.2" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54" dependencies: argparse "^1.0.7" entities "~1.1.1" @@ -5226,27 +5158,27 @@ markdown-it@^8.3.0, markdown-it@^8.3.1: matcher-collection@^1.0.0, matcher-collection@^1.0.4, matcher-collection@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.5.tgz#2ee095438372cb8884f058234138c05c644ec339" + resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-1.0.5.tgz#2ee095438372cb8884f058234138c05c644ec339" dependencies: minimatch "^3.0.2" math-random@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" + resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" mdn-links@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" + resolved "https://registry.yarnpkg.com/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" mdurl@^1.0.1, mdurl@~1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" media-typer@0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" -memory-streams@^0.1.0, memory-streams@^0.1.3: +memory-streams@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.3.tgz#d9b0017b4b87f1d92f55f2745c9caacb1dc93ceb" dependencies: @@ -5254,7 +5186,7 @@ memory-streams@^0.1.0, memory-streams@^0.1.3: meow@^3.4.0: version "3.7.0" - resolved "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" dependencies: camelcase-keys "^2.0.0" decamelize "^1.1.2" @@ -5269,11 +5201,11 @@ meow@^3.4.0: merge-descriptors@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" merge-trees@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/merge-trees/-/merge-trees-1.0.1.tgz#ccbe674569787f9def17fd46e6525f5700bbd23e" + resolved "https://registry.yarnpkg.com/merge-trees/-/merge-trees-1.0.1.tgz#ccbe674569787f9def17fd46e6525f5700bbd23e" dependencies: can-symlink "^1.0.0" fs-tree-diff "^0.5.4" @@ -5289,17 +5221,17 @@ merge-trees@^2.0.0: fs-updater "^1.0.4" heimdalljs "^0.2.5" -merge@^1.1.3, merge@^1.2.0: +merge@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" methods@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7: version "2.3.11" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" dependencies: arr-diff "^2.0.0" array-unique "^0.2.1" @@ -5317,7 +5249,7 @@ micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7: micromatch@^3.0.4, micromatch@^3.1.4: version "3.1.10" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" @@ -5333,97 +5265,93 @@ micromatch@^3.0.4, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -"mime-db@>= 1.34.0 < 2": - version "1.34.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.34.0.tgz#452d0ecff5c30346a6dc1e64b1eaee0d3719ff9a" - -mime-db@~1.33.0: - version "1.33.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" +"mime-db@>= 1.34.0 < 2", mime-db@~1.35.0: + version "1.35.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" mime-types@^2.1.18, mime-types@~2.1.18: - version "2.1.18" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + version "2.1.19" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" dependencies: - mime-db "~1.33.0" + mime-db "~1.35.0" mime-types@~1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" mime@1.4.1: version "1.4.1" - resolved "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" mime@^1.2.11: version "1.6.0" - resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" mime@~1.2.11: version "1.2.11" - resolved "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" mimic-fn@^1.0.0: version "1.2.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" mimic-response@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" "minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: brace-expansion "^1.1.7" minimatch@^2.0.1: version "2.0.10" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" dependencies: brace-expansion "^1.0.0" minimist@0.0.8: version "0.0.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" minimist@~0.0.1: version "0.0.10" - resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" minipass@^2.2.0, minipass@^2.2.1, minipass@^2.3.3: version "2.3.3" - resolved "https://registry.npmjs.org/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" dependencies: safe-buffer "^5.1.2" yallist "^3.0.0" minizlib@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" dependencies: minipass "^2.2.1" mixin-deep@^1.2.0: version "1.3.1" - resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" dependencies: for-in "^1.0.2" is-extendable "^1.0.1" mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" mktemp@^0.4.0, mktemp@~0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" + resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" mocha-only-detector@1.0.0: version "1.0.0" @@ -5451,17 +5379,17 @@ mocha@^5.2.0: moment-timezone@^0.3.0: version "0.3.1" - resolved "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" + resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" dependencies: moment ">= 2.6.0" "moment@>= 2.6.0": version "2.22.2" - resolved "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" morgan@^1.8.1: version "1.9.0" - resolved "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz#d01fa6c65859b76fcf31b3cb53a3821a311d8051" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.0.tgz#d01fa6c65859b76fcf31b3cb53a3821a311d8051" dependencies: basic-auth "~2.0.0" debug "2.6.9" @@ -5471,19 +5399,19 @@ morgan@^1.8.1: mout@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/mout/-/mout-1.1.0.tgz#0b29d41e6a80fa9e2d4a5be9d602e1d9d02177f6" + resolved "https://registry.yarnpkg.com/mout/-/mout-1.1.0.tgz#0b29d41e6a80fa9e2d4a5be9d602e1d9d02177f6" ms@2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" mustache@^2.2.1: version "2.3.0" - resolved "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" + resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" mute-stream@0.0.6: version "0.0.6" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" mute-stream@0.0.7: version "0.0.7" @@ -5491,18 +5419,17 @@ mute-stream@0.0.7: nan@^2.9.2: version "2.10.0" - resolved "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" nanomatch@^1.2.9: - version "1.2.9" - resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" define-property "^2.0.2" extend-shallow "^3.0.2" fragment-cache "^0.2.1" - is-odd "^2.0.0" is-windows "^1.0.2" kind-of "^6.0.2" object.pick "^1.3.0" @@ -5514,9 +5441,9 @@ natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" -needle@^2.2.0: +needle@^2.2.1: version "2.2.1" - resolved "https://registry.npmjs.org/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" dependencies: debug "^2.1.2" iconv-lite "^0.4.4" @@ -5524,27 +5451,27 @@ needle@^2.2.0: negotiator@0.6.1: version "0.6.1" - resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" next-tick@1: version "1.0.0" - resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" nice-try@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" node-int64@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" node-modules-path@^1.0.0, node-modules-path@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" + resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" node-notifier@^5.0.1: version "5.2.1" - resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" dependencies: growly "^1.3.0" semver "^5.4.1" @@ -5552,12 +5479,12 @@ node-notifier@^5.0.1: which "^1.3.0" node-pre-gyp@^0.10.0: - version "0.10.2" - resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.2.tgz#e8945c20ef6795a20aac2b44f036eb13cf5146e3" + version "0.10.3" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" dependencies: detect-libc "^1.0.2" mkdirp "^0.5.1" - needle "^2.2.0" + needle "^2.2.1" nopt "^4.0.1" npm-packlist "^1.1.6" npmlog "^4.0.2" @@ -5568,24 +5495,24 @@ node-pre-gyp@^0.10.0: node-uuid@~1.4.0: version "1.4.8" - resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" nopt@^3.0.3, nopt@^3.0.6: version "3.0.6" - resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: abbrev "1" nopt@^4.0.1: version "4.0.1" - resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" dependencies: abbrev "1" osenv "^0.1.4" normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: version "2.4.0" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -5594,13 +5521,13 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: remove-trailing-separator "^1.0.1" normalize-url@2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" dependencies: prepend-http "^2.0.0" query-string "^5.0.1" @@ -5608,7 +5535,7 @@ normalize-url@2.0.1: npm-bundled@^1.0.1: version "1.0.3" - resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" npm-git-info@^1.0.3: version "1.0.3" @@ -5616,7 +5543,7 @@ npm-git-info@^1.0.3: npm-package-arg@^6.0.0: version "6.1.0" - resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" dependencies: hosted-git-info "^2.6.0" osenv "^0.1.5" @@ -5625,20 +5552,20 @@ npm-package-arg@^6.0.0: npm-packlist@^1.1.6: version "1.1.10" - resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" dependencies: ignore-walk "^3.0.1" npm-bundled "^1.0.1" npm-run-path@^2.0.0: version "2.0.2" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" dependencies: path-key "^2.0.0" npmlog@^4.0.0, npmlog@^4.0.2: version "4.1.2" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" @@ -5647,23 +5574,23 @@ npmlog@^4.0.0, npmlog@^4.0.2: number-is-nan@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" oauth-sign@~0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" object-component@0.0.3: version "0.0.3" - resolved "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" object-copy@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" @@ -5675,36 +5602,36 @@ object-keys@^1.0.8: object-visit@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" dependencies: isobject "^3.0.0" object.omit@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" dependencies: for-own "^0.1.4" is-extendable "^0.1.1" object.pick@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" dependencies: isobject "^3.0.1" on-finished@~2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" dependencies: ee-first "1.1.1" on-headers@~1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" once@^1.3.0: version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" @@ -5714,13 +5641,13 @@ onetime@^1.0.0: onetime@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" dependencies: mimic-fn "^1.0.0" optimist@^0.6.1: version "0.6.1" - resolved "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" dependencies: minimist "~0.0.1" wordwrap "~0.0.2" @@ -5738,7 +5665,7 @@ optionator@^0.8.2: ora@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" + resolved "https://registry.yarnpkg.com/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" dependencies: chalk "^2.3.1" cli-cursor "^2.1.0" @@ -5749,56 +5676,56 @@ ora@^2.0.0: os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" os-shim@^0.1.2: version "0.1.3" - resolved "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4, osenv@^0.1.5: version "0.1.5" - resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" p-cancelable@^0.4.0: version "0.4.1" - resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" p-finally@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" p-is-promise@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" p-limit@^1.1.0: version "1.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" dependencies: p-try "^1.0.0" p-locate@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" dependencies: p-limit "^1.1.0" p-timeout@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" dependencies: p-finally "^1.0.0" p-try@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" package-json@^4.0.1: version "4.0.1" @@ -5811,7 +5738,7 @@ package-json@^4.0.1: parse-glob@^3.0.4: version "3.0.4" - resolved "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" dependencies: glob-base "^0.3.0" is-dotfile "^1.0.0" @@ -5820,57 +5747,57 @@ parse-glob@^3.0.4: parse-json@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" dependencies: error-ex "^1.2.0" parse-ms@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d" + resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d" parse-passwd@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" parseqs@0.0.5: version "0.0.5" - resolved "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" dependencies: better-assert "~1.0.0" parseuri@0.0.5: version "0.0.5" - resolved "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" dependencies: better-assert "~1.0.0" parseurl@~1.3.2: version "1.3.2" - resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" pascalcase@^0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" passwd-user@^1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/passwd-user/-/passwd-user-1.2.1.tgz#a01a5dc639ef007dc56364b8178569080ad3a7b8" + resolved "https://registry.yarnpkg.com/passwd-user/-/passwd-user-1.2.1.tgz#a01a5dc639ef007dc56364b8178569080ad3a7b8" dependencies: exec-file-sync "^2.0.0" path-exists@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" dependencies: pinkie-promise "^2.0.0" path-exists@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" @@ -5878,23 +5805,23 @@ path-is-inside@^1.0.1, path-is-inside@^1.0.2: path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" path-parse@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" path-posix@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" path-to-regexp@0.1.7: version "0.1.7" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" path-type@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" dependencies: graceful-fs "^4.1.2" pify "^2.0.0" @@ -5902,25 +5829,25 @@ path-type@^1.0.0: pathval@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" pify@^2.0.0: version "2.3.0" - resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" pify@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" pinkie-promise@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" - resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" pluralize@^7.0.0: version "7.0.0" @@ -5928,7 +5855,7 @@ pluralize@^7.0.0: portfinder@^1.0.7: version "1.0.13" - resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" dependencies: async "^1.5.2" debug "^2.2.0" @@ -5936,7 +5863,7 @@ portfinder@^1.0.7: posix-character-classes@^0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" prelude-ls@~1.1.2: version "1.1.2" @@ -5948,15 +5875,15 @@ prepend-http@^1.0.1: prepend-http@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" preserve@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" pretender@^1.4.2: version "1.6.1" - resolved "https://registry.npmjs.org/pretender/-/pretender-1.6.1.tgz#77d1e42ac8c6b298f5cd43534a87645df035db8c" + resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.6.1.tgz#77d1e42ac8c6b298f5cd43534a87645df035db8c" dependencies: fake-xml-http-request "^1.6.0" route-recognizer "^0.3.3" @@ -5967,25 +5894,25 @@ prettier@^1.14.0: pretty-ms@^3.1.0: version "3.2.0" - resolved "https://registry.npmjs.org/pretty-ms/-/pretty-ms-3.2.0.tgz#87a8feaf27fc18414d75441467d411d6e6098a25" + resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-3.2.0.tgz#87a8feaf27fc18414d75441467d411d6e6098a25" dependencies: parse-ms "^1.0.0" printf@^0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/printf/-/printf-0.3.0.tgz#6918ca5237c047e19cf004b69e6bcfafbef1ce82" + resolved "https://registry.yarnpkg.com/printf/-/printf-0.3.0.tgz#6918ca5237c047e19cf004b69e6bcfafbef1ce82" private@^0.1.6, private@^0.1.8, private@~0.1.5: version "0.1.8" - resolved "https://registry.npmjs.org/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" process-nextick-args@~2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" process-relative-require@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" + resolved "https://registry.yarnpkg.com/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" dependencies: node-modules-path "^1.0.0" @@ -5995,28 +5922,28 @@ progress@^2.0.0: promise-map-series@^0.2.1: version "0.2.3" - resolved "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" + resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" dependencies: rsvp "^3.0.14" proxy-addr@~2.0.3: version "2.0.3" - resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" dependencies: forwarded "~0.1.2" ipaddr.js "1.6.0" psl@^1.1.24: version "1.1.28" - resolved "https://registry.npmjs.org/psl/-/psl-1.1.28.tgz#4fb6ceb08a1e2214d4fd4de0ca22dae13740bc7b" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.28.tgz#4fb6ceb08a1e2214d4fd4de0ca22dae13740bc7b" punycode@1.3.2: version "1.3.2" - resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" punycode@^1.4.1: version "1.4.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" punycode@^2.1.0: version "2.1.1" @@ -6024,19 +5951,19 @@ punycode@^2.1.0: qs@6.5.1: version "6.5.1" - resolved "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" qs@^6.4.0: version "6.5.2" - resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" qs@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" + resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" query-string@^5.0.1: version "5.1.1" - resolved "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" dependencies: decode-uri-component "^0.2.0" object-assign "^4.1.0" @@ -6044,18 +5971,18 @@ query-string@^5.0.1: querystring@0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" quibble@^0.5.5: version "0.5.5" - resolved "https://registry.npmjs.org/quibble/-/quibble-0.5.5.tgz#669fb731520a923e0a98f8076b7eb55e409f73f9" + resolved "https://registry.yarnpkg.com/quibble/-/quibble-0.5.5.tgz#669fb731520a923e0a98f8076b7eb55e409f73f9" dependencies: lodash "^4.17.2" resolve "^1.7.1" quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: version "0.1.8" - resolved "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" + resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" dependencies: mktemp "~0.4.0" rimraf "^2.5.4" @@ -6063,7 +5990,7 @@ quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: qunit@^2.5.0: version "2.6.1" - resolved "https://registry.npmjs.org/qunit/-/qunit-2.6.1.tgz#3a2a5f05307f873174e0f5859010fb7380380e3c" + resolved "https://registry.yarnpkg.com/qunit/-/qunit-2.6.1.tgz#3a2a5f05307f873174e0f5859010fb7380380e3c" dependencies: chokidar "1.7.0" commander "2.12.2" @@ -6075,7 +6002,7 @@ qunit@^2.5.0: randomatic@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz#d35490030eb4f7578de292ce6dfb04a91a128923" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.0.0.tgz#d35490030eb4f7578de292ce6dfb04a91a128923" dependencies: is-number "^4.0.0" kind-of "^6.0.0" @@ -6083,11 +6010,11 @@ randomatic@^3.0.0: range-parser@~1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" raw-body@2.3.2: version "2.3.2" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" dependencies: bytes "3.0.0" http-errors "1.6.2" @@ -6096,14 +6023,14 @@ raw-body@2.3.2: raw-body@~1.1.0: version "1.1.7" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" dependencies: bytes "1" string_decoder "0.10" rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: version "1.2.8" - resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" dependencies: deep-extend "^0.6.0" ini "~1.3.0" @@ -6112,14 +6039,14 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: read-pkg-up@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" dependencies: find-up "^1.0.0" read-pkg "^1.0.0" read-pkg@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" @@ -6127,7 +6054,7 @@ read-pkg@^1.0.0: readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: version "2.3.6" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -6139,7 +6066,7 @@ readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.6, readable readable-stream@~1.0.2: version "1.0.34" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -6148,7 +6075,7 @@ readable-stream@~1.0.2: readdirp@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" dependencies: graceful-fs "^4.1.2" minimatch "^3.0.2" @@ -6157,7 +6084,7 @@ readdirp@^2.0.0: recast@^0.11.3: version "0.11.23" - resolved "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" dependencies: ast-types "0.9.6" esprima "~3.1.0" @@ -6166,36 +6093,36 @@ recast@^0.11.3: redent@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" dependencies: indent-string "^2.1.0" strip-indent "^1.0.1" redeyed@~1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" + resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" dependencies: esprima "~3.0.0" regenerate@^1.2.1: version "1.4.0" - resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" regenerator-runtime@^0.10.5: version "0.10.5" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" regenerator-runtime@^0.11.0: version "0.11.1" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" regenerator-runtime@^0.9.5: version "0.9.6" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" regenerator-transform@^0.10.0: version "0.10.1" - resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" dependencies: babel-runtime "^6.18.0" babel-types "^6.19.0" @@ -6203,13 +6130,13 @@ regenerator-transform@^0.10.0: regex-cache@^0.4.2: version "0.4.4" - resolved "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" dependencies: is-equal-shallow "^0.1.3" regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" dependencies: extend-shallow "^3.0.2" safe-regex "^1.1.0" @@ -6226,7 +6153,7 @@ regexpp@^2.0.0: regexpu-core@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" dependencies: regenerate "^1.2.1" regjsgen "^0.2.0" @@ -6247,11 +6174,11 @@ registry-url@^3.0.3: regjsgen@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" regjsparser@^0.1.4: version "0.1.5" - resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" dependencies: jsesc "~0.5.0" @@ -6264,25 +6191,25 @@ remote-git-tags@^2.0.0: remove-trailing-separator@^1.0.1: version "1.1.0" - resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" repeat-element@^1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" - resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" repeating@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" dependencies: is-finite "^1.0.0" request@~2.40.0: version "2.40.0" - resolved "https://registry.npmjs.org/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" + resolved "https://registry.yarnpkg.com/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" dependencies: forever-agent "~0.5.0" json-stringify-safe "~5.0.0" @@ -6301,7 +6228,7 @@ request@~2.40.0: require-relative@^0.8.7: version "0.8.7" - resolved "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" + resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" require-uncached@^1.0.3: version "1.0.3" @@ -6312,18 +6239,18 @@ require-uncached@^1.0.3: requires-port@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" resolve-dir@^0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" dependencies: expand-tilde "^1.2.2" global-modules "^0.2.3" resolve-dir@^1.0.0, resolve-dir@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" dependencies: expand-tilde "^2.0.0" global-modules "^1.0.0" @@ -6334,70 +6261,70 @@ resolve-from@^1.0.0: resolve-url@^0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" resolve@1.5.0: version "1.5.0" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: path-parse "^1.0.5" resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.7.1, resolve@^1.8.1: version "1.8.1" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" dependencies: path-parse "^1.0.5" responselike@1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" dependencies: lowercase-keys "^1.0.0" restore-cursor@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" dependencies: exit-hook "^1.0.0" onetime "^1.0.0" restore-cursor@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" dependencies: onetime "^2.0.0" signal-exit "^3.0.2" ret@~0.1.10: version "0.1.15" - resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" right-align@^0.1.1: version "0.1.3" - resolved "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" dependencies: align-text "^0.1.1" rimraf@2.6.2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: version "2.6.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: glob "^7.0.5" rimraf@~2.2.6: version "2.2.8" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" rollup-pluginutils@^2.0.1: version "2.3.0" - resolved "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.3.0.tgz#478ace04bd7f6da2e724356ca798214884738fc4" + resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.3.0.tgz#478ace04bd7f6da2e724356ca798214884738fc4" dependencies: estree-walker "^0.5.2" micromatch "^2.3.11" rollup@^0.57.1: version "0.57.1" - resolved "https://registry.npmjs.org/rollup/-/rollup-0.57.1.tgz#0bb28be6151d253f67cf4a00fea48fb823c74027" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.57.1.tgz#0bb28be6151d253f67cf4a00fea48fb823c74027" dependencies: "@types/acorn" "^4.0.3" acorn "^5.5.3" @@ -6413,37 +6340,33 @@ rollup@^0.57.1: route-recognizer@^0.3.3: version "0.3.3" - resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" + resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" rsvp@3.0.14: version "3.0.14" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.14.tgz#9d2968cf36d878d3bb9a9a5a4b8e1ff55a76dd31" -rsvp@4.8.3, rsvp@^4.8.1, rsvp@^4.8.3: +rsvp@4.8.3, rsvp@^4.7.0, rsvp@^4.8.1, rsvp@^4.8.2, rsvp@^4.8.3: version "4.8.3" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.3.tgz#25d4b9fdd0f95e216eb5884d9b3767d3fbfbe2cd" -rsvp@^3.0.14, rsvp@^3.0.16, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.3.3, rsvp@^3.5.0: +rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.3.3, rsvp@^3.5.0: version "3.6.2" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" - -rsvp@^4.7.0, rsvp@^4.8.2: - version "4.8.2" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.2.tgz#9d5647108735784eb13418cdddb56f75b919d722" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" rsvp@~3.2.1: version "3.2.1" - resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" run-async@^2.2.0: version "2.3.0" - resolved "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" dependencies: is-promise "^2.1.0" rx@^4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" rxjs@^5.5.2: version "5.5.11" @@ -6453,29 +6376,29 @@ rxjs@^5.5.2: safe-buffer@5.1.1: version "5.1.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" safe-json-parse@~1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" + resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" safe-regex@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" dependencies: ret "~0.1.10" "safer-buffer@>= 2.1.2 < 3": version "2.1.2" - resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" sane@^1.4.1: version "1.7.0" - resolved "https://registry.npmjs.org/sane/-/sane-1.7.0.tgz#b3579bccb45c94cf20355cc81124990dfd346e30" + resolved "https://registry.yarnpkg.com/sane/-/sane-1.7.0.tgz#b3579bccb45c94cf20355cc81124990dfd346e30" dependencies: anymatch "^1.3.0" exec-sh "^0.2.0" @@ -6487,7 +6410,7 @@ sane@^1.4.1: sane@^2.2.0, sane@^2.4.1: version "2.5.2" - resolved "https://registry.npmjs.org/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" + resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" dependencies: anymatch "^2.0.0" capture-exit "^1.2.0" @@ -6502,27 +6425,27 @@ sane@^2.2.0, sane@^2.4.1: sax@1.2.1: version "1.2.1" - resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" sax@>=0.6.0, sax@^1.2.4: version "1.2.4" - resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" "semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: version "5.5.0" - resolved "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" semver@^4.3.1: version "4.3.6" - resolved "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" semver@~5.0.1: version "5.0.3" - resolved "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" send@0.16.2: version "0.16.2" - resolved "https://registry.npmjs.org/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" dependencies: debug "2.6.9" depd "~1.1.2" @@ -6540,7 +6463,7 @@ send@0.16.2: serve-static@1.13.2: version "1.13.2" - resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" @@ -6549,15 +6472,15 @@ serve-static@1.13.2: set-blocking@~2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" set-immediate-shim@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" set-value@^0.4.3: version "0.4.3" - resolved "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -6566,7 +6489,7 @@ set-value@^0.4.3: set-value@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -6575,39 +6498,39 @@ set-value@^2.0.0: setprototypeof@1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" setprototypeof@1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" shebang-command@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" shellwords@^0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" silent-error@^1.0.0, silent-error@^1.0.1, silent-error@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.1.0.tgz#2209706f1c850a9f1d10d0d840918b46f26e1bc9" + resolved "https://registry.yarnpkg.com/silent-error/-/silent-error-1.1.0.tgz#2209706f1c850a9f1d10d0d840918b46f26e1bc9" dependencies: debug "^2.2.0" slash@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" slice-ansi@1.0.0: version "1.0.0" @@ -6617,7 +6540,7 @@ slice-ansi@1.0.0: snapdragon-node@^2.0.1: version "2.1.1" - resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" dependencies: define-property "^1.0.0" isobject "^3.0.0" @@ -6625,13 +6548,13 @@ snapdragon-node@^2.0.1: snapdragon-util@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" dependencies: kind-of "^3.2.0" snapdragon@^0.8.1: version "0.8.2" - resolved "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" dependencies: base "^0.11.1" debug "^2.2.0" @@ -6644,17 +6567,17 @@ snapdragon@^0.8.1: sntp@0.2.x: version "0.2.4" - resolved "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" dependencies: hoek "0.9.x" socket.io-adapter@~1.1.0: version "1.1.1" - resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" socket.io-client@2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" dependencies: backo2 "1.0.2" base64-arraybuffer "0.1.5" @@ -6673,7 +6596,7 @@ socket.io-client@2.1.1: socket.io-parser@~3.2.0: version "3.2.0" - resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" dependencies: component-emitter "1.2.1" debug "~3.1.0" @@ -6681,7 +6604,7 @@ socket.io-parser@~3.2.0: socket.io@^2.1.0: version "2.1.1" - resolved "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" dependencies: debug "~3.1.0" engine.io "~3.2.0" @@ -6692,24 +6615,24 @@ socket.io@^2.1.0: sort-keys@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" dependencies: is-plain-obj "^1.0.0" sort-object-keys@^1.1.1: version "1.1.2" - resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" + resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" sort-package-json@^1.4.0: version "1.15.0" - resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.15.0.tgz#3c732cc8312eb4aa12f6eccab1bc3dea89b11dff" + resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.15.0.tgz#3c732cc8312eb4aa12f6eccab1bc3dea89b11dff" dependencies: detect-indent "^5.0.0" sort-object-keys "^1.1.1" source-map-resolve@^0.5.0: version "0.5.2" - resolved "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" dependencies: atob "^2.1.1" decode-uri-component "^0.2.0" @@ -6719,43 +6642,50 @@ source-map-resolve@^0.5.0: source-map-support@^0.4.15: version "0.4.18" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" dependencies: source-map "^0.5.6" +source-map-support@~0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.6.tgz#4435cee46b1aab62b8e8610ce60f788091c51c13" + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-url@^0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" source-map-url@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: version "0.4.4" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: amdefine ">=0.0.4" source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0, source-map@~0.5.1: version "0.5.7" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +source-map@^0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" source-map@~0.1.x: version "0.1.43" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" dependencies: amdefine ">=0.0.4" -source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - sourcemap-codec@^1.4.1: version "1.4.1" - resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.1.tgz#c8fd92d91889e902a07aee392bdd2c5863958ba2" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.1.tgz#c8fd92d91889e902a07aee392bdd2c5863958ba2" -sourcemap-validator@^1.0.5, sourcemap-validator@^1.1.0: +sourcemap-validator@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/sourcemap-validator/-/sourcemap-validator-1.1.0.tgz#00454547d1682186e1498a7208e022e8dfa8738f" dependencies: @@ -6766,93 +6696,93 @@ sourcemap-validator@^1.0.5, sourcemap-validator@^1.1.0: spawn-args@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" + resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" spawn-sync@^1.0.11, spawn-sync@^1.0.15: version "1.0.15" - resolved "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" dependencies: concat-stream "^1.4.7" os-shim "^0.1.2" spawnback@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" + resolved "https://registry.yarnpkg.com/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" spdx-correct@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" spdx-expression-parse@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" - resolved "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" dependencies: extend-shallow "^3.0.0" sprintf-js@^1.0.3: version "1.1.1" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" sri-toolbox@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" + resolved "https://registry.yarnpkg.com/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" static-extend@^0.1.1: version "0.1.2" - resolved "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" dependencies: define-property "^0.2.5" object-copy "^0.1.0" "statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2": version "1.5.0" - resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" statuses@~1.3.1: version "1.3.1" - resolved "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" statuses@~1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" stream-consume@^0.1.0: version "0.1.1" - resolved "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz#d3bdb598c2bd0ae82b8cac7ac50b1107a7996c48" + resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.1.tgz#d3bdb598c2bd0ae82b8cac7ac50b1107a7996c48" strict-uri-encode@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" string-template@~0.2.1: version "0.2.1" - resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" string-width@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -6860,7 +6790,7 @@ string-width@^1.0.1: "string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" @@ -6877,80 +6807,80 @@ string.prototype.matchall@^2.0.0: string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" string_decoder@~1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" dependencies: safe-buffer "~5.1.0" stringify-object-es5@^2.5.0: version "2.5.0" - resolved "https://registry.npmjs.org/stringify-object-es5/-/stringify-object-es5-2.5.0.tgz#057c3c9a90a127339bb9d1704a290bb7bd0a1ec5" + resolved "https://registry.yarnpkg.com/stringify-object-es5/-/stringify-object-es5-2.5.0.tgz#057c3c9a90a127339bb9d1704a290bb7bd0a1ec5" dependencies: is-plain-obj "^1.0.0" is-regexp "^1.0.0" stringstream@~0.0.4: version "0.0.6" - resolved "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: ansi-regex "^2.0.0" strip-ansi@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" dependencies: ansi-regex "^3.0.0" strip-bom@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" dependencies: is-utf8 "^0.2.0" strip-bom@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" strip-eof@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" strip-indent@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" dependencies: get-stdin "^4.0.1" strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" styled_string@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" + resolved "https://registry.yarnpkg.com/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" sum-up@^1.0.1: version "1.0.3" - resolved "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" + resolved "https://registry.yarnpkg.com/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" dependencies: chalk "^1.0.0" supports-color@5.4.0, supports-color@^5.3.0: version "5.4.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" dependencies: has-flag "^3.0.0" supports-color@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" symbol-observable@1.0.1: version "1.0.1" @@ -6958,7 +6888,7 @@ symbol-observable@1.0.1: symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" + resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" table@^4.0.3: version "4.0.3" @@ -6973,7 +6903,7 @@ table@^4.0.3: tap-parser@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/tap-parser/-/tap-parser-7.0.0.tgz#54db35302fda2c2ccc21954ad3be22b2cba42721" + resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-7.0.0.tgz#54db35302fda2c2ccc21954ad3be22b2cba42721" dependencies: events-to-array "^1.0.1" js-yaml "^3.2.7" @@ -6981,7 +6911,7 @@ tap-parser@^7.0.0: tar@^4: version "4.4.4" - resolved "https://registry.npmjs.org/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" dependencies: chownr "^1.0.1" fs-minipass "^1.2.5" @@ -6993,21 +6923,22 @@ tar@^4: temp@0.8.3: version "0.8.3" - resolved "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" + resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" dependencies: os-tmpdir "^1.0.0" rimraf "~2.2.6" terser@^3.7.5: - version "3.7.6" - resolved "https://registry.npmjs.org/terser/-/terser-3.7.6.tgz#0b3c609f22278c089780ac1cdc63627071e3b96a" + version "3.8.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-3.8.1.tgz#cb70070ac9e0a71add169dfb63c0a64fca2738ac" dependencies: - commander "~2.14.1" + commander "~2.16.0" source-map "~0.6.1" + source-map-support "~0.5.6" testdouble@^3.2.6: version "3.8.1" - resolved "https://registry.npmjs.org/testdouble/-/testdouble-3.8.1.tgz#8c74b6807f82fb07c2387a0640b4ae594b09b964" + resolved "https://registry.yarnpkg.com/testdouble/-/testdouble-3.8.1.tgz#8c74b6807f82fb07c2387a0640b4ae594b09b964" dependencies: es6-map "^0.1.5" lodash "^4.17.4" @@ -7016,8 +6947,8 @@ testdouble@^3.2.6: theredoc "^1.0.0" testem@^2.2.0: - version "2.9.2" - resolved "https://registry.yarnpkg.com/testem/-/testem-2.9.2.tgz#d61c638fd7fff6d9bc2f771c673dc10cb1df3d21" + version "2.9.0" + resolved "https://registry.yarnpkg.com/testem/-/testem-2.9.0.tgz#7ce11c11b4eec4192ec3d2ea7eaa216e08c34273" dependencies: backbone "^1.1.2" bluebird "^3.4.6" @@ -7053,15 +6984,15 @@ text-table@^0.2.0: "textextensions@1 || 2": version "2.2.0" - resolved "https://registry.npmjs.org/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" + resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" theredoc@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/theredoc/-/theredoc-1.0.0.tgz#bcace376af6feb1873efbdd0f91ed026570ff062" + resolved "https://registry.yarnpkg.com/theredoc/-/theredoc-1.0.0.tgz#bcace376af6feb1873efbdd0f91ed026570ff062" through@^2.3.6, through@^2.3.8: version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" through@~2.2.0, through@~2.2.7: version "2.2.7" @@ -7069,15 +7000,15 @@ through@~2.2.0, through@~2.2.7: time-zone@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz#99c5bf55958966af6d06d83bdf3800dc82faec5d" + resolved "https://registry.yarnpkg.com/time-zone/-/time-zone-1.0.0.tgz#99c5bf55958966af6d06d83bdf3800dc82faec5d" timed-out@^4.0.0, timed-out@^4.0.1: version "4.0.1" - resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" tiny-lr@^1.0.3: version "1.1.1" - resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" + resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" dependencies: body "^5.1.0" debug "^3.1.0" @@ -7088,26 +7019,26 @@ tiny-lr@^1.0.3: tmp-sync@^1.0.0: version "1.1.2" - resolved "https://registry.npmjs.org/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" + resolved "https://registry.yarnpkg.com/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" dependencies: fs-sync "^1.0.4" osenv "^0.1.0" tmp@0.0.28: version "0.0.28" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" dependencies: os-tmpdir "~1.0.1" tmp@0.0.31: version "0.0.31" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" dependencies: os-tmpdir "~1.0.1" tmp@^0.0.29: version "0.0.29" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" dependencies: os-tmpdir "~1.0.1" @@ -7119,36 +7050,36 @@ tmp@^0.0.33: tmpl@1.0.x: version "1.0.4" - resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" to-array@0.1.4: version "0.1.4" - resolved "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" to-fast-properties@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" to-object-path@^0.3.0: version "0.3.0" - resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" dependencies: kind-of "^3.0.2" to-regex-range@^2.1.0: version "2.1.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" dependencies: is-number "^3.0.0" repeat-string "^1.6.1" to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" dependencies: define-property "^2.0.2" extend-shallow "^3.0.2" @@ -7161,14 +7092,14 @@ to-utf8@0.0.1: tough-cookie@>=0.12.0: version "2.4.3" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" dependencies: psl "^1.1.24" punycode "^1.4.1" tree-sync@^1.2.1, tree-sync@^1.2.2: version "1.2.2" - resolved "https://registry.npmjs.org/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" + resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" dependencies: debug "^2.2.0" fs-tree-diff "^0.5.6" @@ -7178,15 +7109,15 @@ tree-sync@^1.2.1, tree-sync@^1.2.2: trim-newlines@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" trim-right@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" tunnel-agent@~0.4.0: version "0.4.3" - resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" type-check@~0.3.2: version "0.3.2" @@ -7196,34 +7127,34 @@ type-check@~0.3.2: type-detect@0.1.1: version "0.1.1" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" type-detect@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" type-detect@^4.0.0: version "4.0.8" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" type-is@~1.6.15, type-is@~1.6.16: version "1.6.16" - resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" dependencies: media-typer "0.3.0" mime-types "~2.1.18" typedarray@^0.0.6: version "0.0.6" - resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" uglify-js@^2.6: version "2.8.29" - resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" dependencies: source-map "~0.5.1" yargs "~3.10.0" @@ -7232,26 +7163,26 @@ uglify-js@^2.6: uglify-to-browserify@~1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" ultron@~1.1.0: version "1.1.1" - resolved "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" underscore.string@^3.2.2, underscore.string@~3.3.4: version "3.3.4" - resolved "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" dependencies: sprintf-js "^1.0.3" util-deprecate "^1.0.2" underscore@>=1.8.3: version "1.9.1" - resolved "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" union-value@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" dependencies: arr-union "^3.1.0" get-value "^2.0.6" @@ -7260,28 +7191,28 @@ union-value@^1.0.0: unique-string@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" dependencies: crypto-random-string "^1.0.0" universalify@^0.1.0: version "0.1.2" - resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" unset-value@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" dependencies: has-value "^0.3.1" isobject "^3.0.0" untildify@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" dependencies: os-homedir "^1.0.0" @@ -7297,7 +7228,7 @@ uri-js@^4.2.1: urix@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" url-parse-lax@^1.0.0: version "1.0.0" @@ -7307,30 +7238,28 @@ url-parse-lax@^1.0.0: url-parse-lax@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" dependencies: prepend-http "^2.0.0" url-to-options@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" url@0.10.3: version "0.10.3" - resolved "https://registry.npmjs.org/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" dependencies: punycode "1.3.2" querystring "0.2.0" use@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/use/-/use-3.1.0.tgz#14716bf03fdfefd03040aef58d8b4b85f3a7c544" - dependencies: - kind-of "^6.0.2" + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" user-info@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/user-info/-/user-info-1.0.0.tgz#81c82b7ed63e674c2475667653413b3c76fde239" + resolved "https://registry.yarnpkg.com/user-info/-/user-info-1.0.0.tgz#81c82b7ed63e674c2475667653413b3c76fde239" dependencies: os-homedir "^1.0.1" passwd-user "^1.2.1" @@ -7338,70 +7267,70 @@ user-info@^1.0.0: username-sync@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/username-sync/-/username-sync-1.0.1.tgz#1cde87eefcf94b8822984d938ba2b797426dae1f" + resolved "https://registry.yarnpkg.com/username-sync/-/username-sync-1.0.1.tgz#1cde87eefcf94b8822984d938ba2b797426dae1f" username@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/username/-/username-1.0.1.tgz#e1f72295e3e58e06f002c6327ce06897a99cd67f" + resolved "https://registry.yarnpkg.com/username/-/username-1.0.1.tgz#e1f72295e3e58e06f002c6327ce06897a99cd67f" dependencies: meow "^3.4.0" util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" utils-merge@1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" uuid@3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" uuid@^3.0.0: - version "3.2.1" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" validate-npm-package-license@^3.0.1: version "3.0.3" - resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" dependencies: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" validate-npm-package-name@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" dependencies: builtins "^1.0.3" vary@~1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" walk-sync@0.3.2, walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2: version "0.3.2" - resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: version "0.2.7" - resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" walker@~1.0.5: version "1.0.7" - resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" dependencies: makeerror "1.0.x" watch-detector@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/watch-detector/-/watch-detector-0.1.0.tgz#e37b410d149e2a8bf263a4f8b71e2f667633dbf8" + resolved "https://registry.yarnpkg.com/watch-detector/-/watch-detector-0.1.0.tgz#e37b410d149e2a8bf263a4f8b71e2f667633dbf8" dependencies: heimdalljs-logger "^0.1.9" quick-temp "^0.1.8" @@ -7411,55 +7340,55 @@ watch-detector@^0.1.0: watch@~0.10.0: version "0.10.0" - resolved "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" watch@~0.18.0: version "0.18.0" - resolved "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" dependencies: exec-sh "^0.2.0" minimist "^1.2.0" wcwidth@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" dependencies: defaults "^1.0.3" websocket-driver@>=0.5.1: version "0.7.0" - resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" dependencies: http-parser-js ">=0.4.0" websocket-extensions ">=0.1.1" websocket-extensions@>=0.1.1: version "0.1.3" - resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0: version "1.3.1" - resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" dependencies: isexe "^2.0.0" wide-align@^1.1.0: version "1.1.3" - resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" dependencies: string-width "^1.0.2 || 2" window-size@0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" wordwrap@0.0.2: version "0.0.2" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" wordwrap@~0.0.2: version "0.0.3" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" wordwrap@~1.0.0: version "1.0.0" @@ -7467,17 +7396,17 @@ wordwrap@~1.0.0: workerpool@^2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/workerpool/-/workerpool-2.3.0.tgz#86c5cbe946b55e7dc9d12b1936c8801a6e2d744d" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-2.3.0.tgz#86c5cbe946b55e7dc9d12b1936c8801a6e2d744d" dependencies: object-assign "4.1.1" wrappy@1: version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" write-file-atomic@^2.0.0: version "2.3.0" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -7491,7 +7420,7 @@ write@^0.2.1: ws@~3.3.1: version "3.3.3" - resolved "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" dependencies: async-limiter "~1.0.0" safe-buffer "~5.1.0" @@ -7499,47 +7428,45 @@ ws@~3.3.1: xdg-basedir@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" -xml2js@0.4.17: - version "0.4.17" - resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" +xml2js@0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" dependencies: sax ">=0.6.0" - xmlbuilder "^4.1.0" + xmlbuilder "~9.0.1" -xmlbuilder@^4.1.0: - version "4.2.1" - resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" - dependencies: - lodash "^4.0.0" +xmlbuilder@~9.0.1: + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" xmldom@^0.1.19: version "0.1.27" - resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" + resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" xmlhttprequest-ssl@~1.5.4: version "1.5.5" - resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" xtend@^4.0.0, xtend@~4.0.0: version "4.0.1" - resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" yallist@^3.0.0, yallist@^3.0.2: version "3.0.2" - resolved "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" yam@^0.0.24: version "0.0.24" - resolved "https://registry.npmjs.org/yam/-/yam-0.0.24.tgz#11e9630444735f66a561d29221407de6d037cd95" + resolved "https://registry.yarnpkg.com/yam/-/yam-0.0.24.tgz#11e9630444735f66a561d29221407de6d037cd95" dependencies: fs-extra "^4.0.2" lodash.merge "^4.6.0" yargs@~3.10.0: version "3.10.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" dependencies: camelcase "^1.0.2" cliui "^2.1.0" @@ -7548,17 +7475,17 @@ yargs@~3.10.0: yeast@0.1.2: version "0.1.2" - resolved "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" yui@^3.18.1: version "3.18.1" - resolved "https://registry.npmjs.org/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" + resolved "https://registry.yarnpkg.com/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" dependencies: request "~2.40.0" yuidocjs@^0.10.0: version "0.10.2" - resolved "https://registry.npmjs.org/yuidocjs/-/yuidocjs-0.10.2.tgz#33924967ce619024cd70ef694e267d2f988f73f6" + resolved "https://registry.yarnpkg.com/yuidocjs/-/yuidocjs-0.10.2.tgz#33924967ce619024cd70ef694e267d2f988f73f6" dependencies: express "^4.13.1" graceful-fs "^4.1.2" From 52d545d8f9ae531ed325392e3551b8260c800ce3 Mon Sep 17 00:00:00 2001 From: selvaa89 Date: Thu, 19 Jul 2018 21:20:50 +0800 Subject: [PATCH 2306/2527] Adding acceptence test for belongs-to --- .../relationships/belongs-to-test.js | 217 ++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 tests/acceptance/relationships/belongs-to-test.js diff --git a/tests/acceptance/relationships/belongs-to-test.js b/tests/acceptance/relationships/belongs-to-test.js new file mode 100644 index 00000000000..e90785a9434 --- /dev/null +++ b/tests/acceptance/relationships/belongs-to-test.js @@ -0,0 +1,217 @@ +import { module } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import Model from 'ember-data/model'; +import { render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; +import { attr, hasMany, belongsTo } from '@ember-decorators/data'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; +import Store from 'ember-data/store'; +import { resolve, reject } from 'rsvp'; +import { ServerError } from 'ember-data/adapters/errors'; +import { skipRecordData as test } from '../../helpers/test-in-debug'; + +class Person extends Model { + @attr name; + @hasMany('person', { async: true, inverse: 'parent' }) + children; + @belongsTo('person', { async: true, inverse: 'children' }) + parent; +} + +class TestAdapter extends JSONAPIAdapter { + setupPayloads(assert, arr) { + this.assert = assert; + this._payloads = arr; + } + + shouldBackgroundReload() { + return false; + } + + _nextPayload() { + let payload = this._payloads.shift(); + + if (payload === undefined) { + this.assert.ok(false, 'Too many adapter requests have been made!'); + return resolve({ data: null }); + } + + if (payload instanceof ServerError) { + return reject(payload); + } + return resolve(payload); + } + + // find by link + findHasMany() { + return this._nextPayload(); + } + + // find by data with coalesceFindRequests set to true + findMany() { + return this._nextPayload(); + } + + // find by partial data / individual records + findRecord() { + return this._nextPayload(); + } + + deleteRecord() { + resolve(); + } +} + +function makePeopleWithRelationshipData() { + let people = [ + { + type: 'person', + id: '1:no-children-or-parent', + attributes: { name: 'Chris Has No Children or Parent' }, + relationships: { + children: { data: [] }, + parent: { data: null }, + }, + }, + { + type: 'person', + id: '2:has-1-child-no-parent', + attributes: { + name: 'James has one child and no parent', + }, + relationships: { + children: { + data: [{ type: 'person', id: '3:has-2-children-and-parent' }], + }, + parent: { data: null }, + }, + }, + { + type: 'person', + id: '3:has-2-children-and-parent', + attributes: { + name: 'Kevin has two children and one parent', + }, + relationships: { + children: { + data: [ + { type: 'person', id: '4:has-parent-no-children' }, + { type: 'person', id: '5:has-parent-no-children' }, + ], + }, + parent: { + data: { + type: 'person', + id: '2:has-1-child-no-parent', + }, + }, + }, + }, + { + type: 'person', + id: '4:has-parent-no-children', + attributes: { + name: 'Selena has a parent', + }, + relationships: { + children: { + data: [], + }, + parent: { + data: { + type: 'person', + id: '3:has-2-children-and-parent', + }, + }, + }, + }, + { + type: 'person', + id: '5:has-parent-no-children', + attributes: { + name: 'Sedona has a parent', + }, + relationships: { + children: { + data: [], + }, + parent: { + data: { + type: 'person', + id: '3:has-2-children-and-parent', + }, + }, + }, + }, + ]; + + let peopleHash = {}; + people.forEach(person => { + peopleHash[person.id] = person; + }); + + return { + dict: peopleHash, + all: people, + }; +} + +module('async belongs-to rendering tests', function(hooks) { + let store; + let adapter; + setupRenderingTest(hooks); + + hooks.beforeEach(function() { + let { owner } = this; + owner.register('model:person', Person); + owner.register('adapter:application', TestAdapter); + owner.register('serializer:application', JSONAPISerializer); + owner.register('service:store', Store); + store = owner.lookup('service:store'); + adapter = store.adapterFor('application'); + }); + + module('for data-no-link scenarios', function() { + test('We can render an async belongs-to', async function(assert) { + let people = makePeopleWithRelationshipData(); + let sedona = store.push({ + data: people.dict['5:has-parent-no-children'], + }); + + adapter.setupPayloads(assert, [{ data: people.dict['3:has-2-children-and-parent'] }]); + + // render + this.set('sedona', sedona); + + await render(hbs` +

      {{sedona.parent.name}}

      + `); + + assert.equal(this.element.textContent.trim(), 'Kevin has two children and one parent'); + }); + + // Failing test for https://github.com/emberjs/data/issues/5523 + test('We can delete async belongs-to', async function(assert) { + let people = makePeopleWithRelationshipData(); + let sedona = store.push({ + data: people.dict['5:has-parent-no-children'], + }); + + adapter.setupPayloads(assert, [{ data: people.dict['3:has-2-children-and-parent'] }]); + + // render + this.set('sedona', sedona); + await render(hbs` +

      {{sedona.parent.name}}

      + `); + + await sedona + .belongsTo('parent') + .value() + .destroyRecord(); + assert.equal(this.element.textContent.trim(), ''); + }); + + }); +}); From fa9ec1cdc652a8b30a340a71a00a56858d71767b Mon Sep 17 00:00:00 2001 From: selvaa89 Date: Fri, 20 Jul 2018 00:23:00 +0800 Subject: [PATCH 2307/2527] Removed unnecessary newline --- tests/acceptance/relationships/belongs-to-test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/acceptance/relationships/belongs-to-test.js b/tests/acceptance/relationships/belongs-to-test.js index e90785a9434..7a0e5b86b2e 100644 --- a/tests/acceptance/relationships/belongs-to-test.js +++ b/tests/acceptance/relationships/belongs-to-test.js @@ -212,6 +212,5 @@ module('async belongs-to rendering tests', function(hooks) { .destroyRecord(); assert.equal(this.element.textContent.trim(), ''); }); - }); }); From 7358186c72ad21ff9221be803d98b067539457e6 Mon Sep 17 00:00:00 2001 From: selvaa89 Date: Fri, 20 Jul 2018 01:25:57 +0800 Subject: [PATCH 2308/2527] added failing test for failing test for #5517 --- .../relationships/belongs-to-test.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/acceptance/relationships/belongs-to-test.js b/tests/acceptance/relationships/belongs-to-test.js index 7a0e5b86b2e..9de4be8267f 100644 --- a/tests/acceptance/relationships/belongs-to-test.js +++ b/tests/acceptance/relationships/belongs-to-test.js @@ -212,5 +212,30 @@ module('async belongs-to rendering tests', function(hooks) { .destroyRecord(); assert.equal(this.element.textContent.trim(), ''); }); + + // failing test for https://github.com/emberjs/data/issues/5517 + test('Re-rendering an async belongsTo does not cause a new fetch', async function(assert) { + let people = makePeopleWithRelationshipData(); + let sedona = store.push({ + data: people.dict['5:has-parent-no-children'], + }); + + adapter.setupPayloads(assert, [{ data: people.dict['3:has-2-children-and-parent'] }]); + + // render + this.set('sedona', sedona); + + await render(hbs` +

      {{sedona.parent.name}}

      + `); + + assert.equal(this.element.textContent.trim(), 'Kevin has two children and one parent'); + + this.set('sedona.parent', null); + assert.equal(this.element.textContent.trim(), ''); + + this.set('sedona.parent', { data: people.dict['3:has-2-children-and-parent'] }); + assert.equal(this.element.textContent.trim(), 'Kevin has two children and one parent'); + }); }); }); From b9c9155eeb3669e26cb92313471af89ee859240d Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 13 Aug 2018 13:29:00 -0700 Subject: [PATCH 2309/2527] cleanup belongsTo tests --- .../relationships/belongs-to-test.js | 125 +++++++++++++++--- 1 file changed, 110 insertions(+), 15 deletions(-) diff --git a/tests/acceptance/relationships/belongs-to-test.js b/tests/acceptance/relationships/belongs-to-test.js index 9de4be8267f..323afd41372 100644 --- a/tests/acceptance/relationships/belongs-to-test.js +++ b/tests/acceptance/relationships/belongs-to-test.js @@ -2,7 +2,7 @@ import { module } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import JSONAPIAdapter from 'ember-data/adapters/json-api'; import Model from 'ember-data/model'; -import { render } from '@ember/test-helpers'; +import { render, settled } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; import { attr, hasMany, belongsTo } from '@ember-decorators/data'; import JSONAPISerializer from 'ember-data/serializers/json-api'; @@ -10,6 +10,7 @@ import Store from 'ember-data/store'; import { resolve, reject } from 'rsvp'; import { ServerError } from 'ember-data/adapters/errors'; import { skipRecordData as test } from '../../helpers/test-in-debug'; +import Ember from 'ember'; class Person extends Model { @attr name; @@ -59,7 +60,7 @@ class TestAdapter extends JSONAPIAdapter { } deleteRecord() { - resolve(); + return resolve({ data: null }); } } @@ -166,7 +167,9 @@ module('async belongs-to rendering tests', function(hooks) { let { owner } = this; owner.register('model:person', Person); owner.register('adapter:application', TestAdapter); - owner.register('serializer:application', JSONAPISerializer); + owner.register('serializer:application', JSONAPISerializer.extend({ + normalizeResponse(_, __, jsonApi) { return jsonApi } + })); owner.register('service:store', Store); store = owner.lookup('service:store'); adapter = store.adapterFor('application'); @@ -191,36 +194,44 @@ module('async belongs-to rendering tests', function(hooks) { assert.equal(this.element.textContent.trim(), 'Kevin has two children and one parent'); }); - // Failing test for https://github.com/emberjs/data/issues/5523 - test('We can delete async belongs-to', async function(assert) { + test('We can delete an async belongs-to', async function(assert) { let people = makePeopleWithRelationshipData(); let sedona = store.push({ data: people.dict['5:has-parent-no-children'], }); - adapter.setupPayloads(assert, [{ data: people.dict['3:has-2-children-and-parent'] }]); + adapter.setupPayloads(assert, [ + { data: people.dict['3:has-2-children-and-parent'] } + ]); // render this.set('sedona', sedona); + await render(hbs`

      {{sedona.parent.name}}

      `); - await sedona - .belongsTo('parent') - .value() - .destroyRecord(); - assert.equal(this.element.textContent.trim(), ''); + let parent = await sedona.get('parent'); + await parent.destroyRecord(); + + let newParent = await sedona.get('parent'); + + await settled(); + + assert.ok(newParent === null, 'We no longer have a parent'); + assert.equal(this.element.textContent.trim(), '', "We no longer render our parent's name because we no longer have a parent"); + }); - // failing test for https://github.com/emberjs/data/issues/5517 test('Re-rendering an async belongsTo does not cause a new fetch', async function(assert) { let people = makePeopleWithRelationshipData(); let sedona = store.push({ data: people.dict['5:has-parent-no-children'], }); - adapter.setupPayloads(assert, [{ data: people.dict['3:has-2-children-and-parent'] }]); + adapter.setupPayloads(assert, [ + { data: people.dict['3:has-2-children-and-parent'] } + ]); // render this.set('sedona', sedona); @@ -231,11 +242,95 @@ module('async belongs-to rendering tests', function(hooks) { assert.equal(this.element.textContent.trim(), 'Kevin has two children and one parent'); - this.set('sedona.parent', null); + this.set('sedona', null); assert.equal(this.element.textContent.trim(), ''); - this.set('sedona.parent', { data: people.dict['3:has-2-children-and-parent'] }); + this.set('sedona', sedona); assert.equal(this.element.textContent.trim(), 'Kevin has two children and one parent'); }); + + + test('Rendering an async belongs-to whose fetch fails does not trigger a new request', async function(assert) { + assert.expect(15); + let people = makePeopleWithRelationshipData(); + let sedona = store.push({ + data: people.dict['5:has-parent-no-children'], + }); + + adapter.setupPayloads(assert, [ + new ServerError([], 'hard error while finding 5:has-parent-no-children'), + ]); + + // render + this.set('sedona', sedona); + + let originalOnError = Ember.onerror; + Ember.onerror = function(e) { + assert.ok(true, 'Children promise did reject'); + assert.equal( + e.message, + 'hard error while finding 5:has-parent-no-children', + 'Rejection has the correct message' + ); + }; + + // needed for LTS 2.12 and 2.16 + Ember.Test.adapter.exception = e => { + assert.ok(true, 'Children promise did reject'); + assert.equal( + e.message, + 'hard error while finding 5:has-parent-no-children', + 'Rejection has the correct message' + ); + }; + + await render(hbs` +

      {{sedona.parent.name}}

      + `); + + assert.equal(this.element.textContent.trim(), '', 'we have no parent'); + + let relationshipState = sedona.belongsTo('parent').belongsToRelationship; + + assert.equal(relationshipState.isAsync, true, 'The relationship is async'); + assert.equal(relationshipState.relationshipIsEmpty, false, 'The relationship is not empty'); + assert.equal(relationshipState.relationshipIsStale, true, 'The relationship is still stale'); + assert.equal( + relationshipState.allInverseRecordsAreLoaded, + false, + 'The relationship is missing some or all related resources' + ); + assert.equal( + relationshipState.hasAnyRelationshipData, + true, + 'The relationship knows which record it needs' + ); + assert.equal( + relationshipState.fetchPromise === null, + true, + 'The relationship has no fetchPromise' + ); + assert.equal( + relationshipState.hasFailedLoadAttempt === true, + true, + 'The relationship has attempted a load' + ); + assert.equal( + relationshipState.shouldForceReload === false, + true, + 'The relationship will not force a reload' + ); + assert.equal( + relationshipState._promiseProxy !== null, + true, + 'The relationship has a loadingPromise' + ); + assert.equal(!!relationshipState.link, false, 'The relationship does not have a link'); + assert.equal(relationshipState.shouldMakeRequest(), false, 'The relationship does not need to make a request'); + let result = await sedona.get('parent'); + assert.ok(result === null, 're-access is safe'); + + Ember.onerror = originalOnError; + }); }); }); From 52e479432828ddd786c74247fdee64273459efcd Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 13 Aug 2018 13:40:25 -0700 Subject: [PATCH 2310/2527] prettier to the prettier gods --- .../relationships/belongs-to-test.js | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/tests/acceptance/relationships/belongs-to-test.js b/tests/acceptance/relationships/belongs-to-test.js index 323afd41372..afa9c6c8e86 100644 --- a/tests/acceptance/relationships/belongs-to-test.js +++ b/tests/acceptance/relationships/belongs-to-test.js @@ -13,7 +13,8 @@ import { skipRecordData as test } from '../../helpers/test-in-debug'; import Ember from 'ember'; class Person extends Model { - @attr name; + @attr + name; @hasMany('person', { async: true, inverse: 'parent' }) children; @belongsTo('person', { async: true, inverse: 'children' }) @@ -167,9 +168,14 @@ module('async belongs-to rendering tests', function(hooks) { let { owner } = this; owner.register('model:person', Person); owner.register('adapter:application', TestAdapter); - owner.register('serializer:application', JSONAPISerializer.extend({ - normalizeResponse(_, __, jsonApi) { return jsonApi } - })); + owner.register( + 'serializer:application', + JSONAPISerializer.extend({ + normalizeResponse(_, __, jsonApi) { + return jsonApi; + }, + }) + ); owner.register('service:store', Store); store = owner.lookup('service:store'); adapter = store.adapterFor('application'); @@ -200,9 +206,7 @@ module('async belongs-to rendering tests', function(hooks) { data: people.dict['5:has-parent-no-children'], }); - adapter.setupPayloads(assert, [ - { data: people.dict['3:has-2-children-and-parent'] } - ]); + adapter.setupPayloads(assert, [{ data: people.dict['3:has-2-children-and-parent'] }]); // render this.set('sedona', sedona); @@ -219,8 +223,11 @@ module('async belongs-to rendering tests', function(hooks) { await settled(); assert.ok(newParent === null, 'We no longer have a parent'); - assert.equal(this.element.textContent.trim(), '', "We no longer render our parent's name because we no longer have a parent"); - + assert.equal( + this.element.textContent.trim(), + '', + "We no longer render our parent's name because we no longer have a parent" + ); }); test('Re-rendering an async belongsTo does not cause a new fetch', async function(assert) { @@ -229,9 +236,7 @@ module('async belongs-to rendering tests', function(hooks) { data: people.dict['5:has-parent-no-children'], }); - adapter.setupPayloads(assert, [ - { data: people.dict['3:has-2-children-and-parent'] } - ]); + adapter.setupPayloads(assert, [{ data: people.dict['3:has-2-children-and-parent'] }]); // render this.set('sedona', sedona); @@ -249,7 +254,6 @@ module('async belongs-to rendering tests', function(hooks) { assert.equal(this.element.textContent.trim(), 'Kevin has two children and one parent'); }); - test('Rendering an async belongs-to whose fetch fails does not trigger a new request', async function(assert) { assert.expect(15); let people = makePeopleWithRelationshipData(); @@ -326,7 +330,11 @@ module('async belongs-to rendering tests', function(hooks) { 'The relationship has a loadingPromise' ); assert.equal(!!relationshipState.link, false, 'The relationship does not have a link'); - assert.equal(relationshipState.shouldMakeRequest(), false, 'The relationship does not need to make a request'); + assert.equal( + relationshipState.shouldMakeRequest(), + false, + 'The relationship does not need to make a request' + ); let result = await sedona.get('parent'); assert.ok(result === null, 're-access is safe'); From 8bcb606a6b96ad1c10fdb5fb9a28220750fdcd4e Mon Sep 17 00:00:00 2001 From: Kenneth Larsen Date: Wed, 15 Aug 2018 03:58:09 +0200 Subject: [PATCH 2311/2527] Updated broken link to Ember guides (#5564) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b31d835501..f442ebb26da 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ promise will be rejected. ### Even More Documentation For much more detail on how to use Ember Data, see the [Ember.js Guides -on models](https://emberjs.com/guides/models/). +on models](https://guides.emberjs.com/release/models/). # Building Ember Data From cb9d740a7b931b45f31464407e9d4ed37e40660e Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 13 Aug 2018 18:23:39 -0700 Subject: [PATCH 2312/2527] enable external partner testing add names to external partner tests use shallow cloning, use bower if necessary, add more external partners nice names smoke tests prettier and storefront use execa fix bower command use node 10 in travis --- .travis.yml | 52 ++++++++++++---- lib/scripts/test-external.js | 116 +++++++++++++++++++++++++++++++++++ package.json | 11 +++- yarn.lock | 2 +- 4 files changed, 166 insertions(+), 15 deletions(-) create mode 100644 lib/scripts/test-external.js diff --git a/.travis.yml b/.travis.yml index e01679e06b4..a3b694cf20a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: node_js sudo: false dist: trusty node_js: - - "6" + - "10" addons: chrome: stable @@ -24,7 +24,8 @@ branches: stages: - test - additional tests - - older version tests + - ember version tests + - external partner tests - name: deploy if: type = push AND (branch IN (master, beta, release) OR tag IS present) @@ -34,18 +35,18 @@ jobs: include: # runs tests with current locked deps and linting - stage: test - env: NAME=test # used only to make Travis UI show description + name: "Basic Tests" script: - ./bin/lint-features - yarn lint:js - yarn test - stage: additional tests - env: NAME=optional-features # used only to make Travis UI show description + name: "Optional Features" install: yarn install script: yarn test:optional-features - - env: NAME=floating dependencies # used only to make Travis UI show description + - name: "Floating Dependencies" install: yarn install --no-lockfile --non-interactive script: yarn test @@ -54,24 +55,48 @@ jobs: env: TARGET_IE11=true script: yarn test - - env: NAME=production # used only to make Travis UI show description + - name: "Production" install: yarn install script: yarn test:production - - env: NAME=node-tests # used only to make Travis UI show description + - name: "Node Tests" install: yarn install script: yarn test:node # runs tests against each supported Ember version - - stage: older version tests + - stage: ember version tests + name: "Ember LTS 2.16" env: EMBER_TRY_SCENARIO=ember-lts-2.16 - - env: EMBER_TRY_SCENARIO=ember-lts-2.18 - - env: EMBER_TRY_SCENARIO=ember-release - - env: EMBER_TRY_SCENARIO=ember-beta - - env: EMBER_TRY_SCENARIO=ember-canary + - name: "Ember LTS 2.18" + env: EMBER_TRY_SCENARIO=ember-lts-2.18 + - name: "Ember Release" + env: EMBER_TRY_SCENARIO=ember-release + - name: "Ember Beta" + env: EMBER_TRY_SCENARIO=ember-beta + - name: "Ember Canary" + env: EMBER_TRY_SCENARIO=ember-canary + + # runs tests against various open-source projects for early-warning regression analysis + - stage: external partner tests + name: "Ember Data Model Fragments" + script: yarn test-external:model-fragments + - name: "Ember Observer" + script: yarn test-external:ember-observer + - name: "Travis Web" + script: yarn test-external:travis-web + - name: "emberaddons.com" + script: yarn test-external:emberaddons.com + - name: "Ember Data Change Tracker" + script: yarn test-external:ember-data-change-tracker + - name: "ember-m3" + script: yarn test-external:ember-m3 + - name: "Ember Data Storefront" + script: yarn test-external:storefront + - name: "Ember Data Factory Guy" + script: yarn test-external:factory-guy - stage: deploy - env: NAME=publish # used only to make Travis UI show description + name: "Publish" install: yarn install script: - node_modules/.bin/ember try:reset @@ -85,6 +110,7 @@ before_install: install: - yarn install + - yarn add global bower script: - node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO --skip-cleanup diff --git a/lib/scripts/test-external.js b/lib/scripts/test-external.js new file mode 100644 index 00000000000..67c2625cdf0 --- /dev/null +++ b/lib/scripts/test-external.js @@ -0,0 +1,116 @@ +'use strict'; +/* eslint-disable no-console, node/no-extraneous-require, node/no-unpublished-require */ +const fs = require('fs'); +const path = require('path'); +const { shellSync } = require('execa'); +// apparently violates no-extraneous require? /shrug +const debug = require('debug')('test-external'); +const rimraf = require('rimraf'); + +const projectRoot = path.resolve(__dirname, '../../'); +const externalProjectName = process.argv[2]; +const gitUrl = process.argv[3]; +const tempDir = path.join(projectRoot, '../__external-test-cache'); +const projectTempDir = path.join(tempDir, externalProjectName); + +if (!gitUrl) { + throw new Error( + 'No git url provided to `node ./lib/scripts/test-external`. An https git url should be the first argument.' + ); +} else if (gitUrl.indexOf('https') !== 0) { + throw new Error( + `The git url provided to \`node ./lib/scripts/test-external\` should use https. Received '${gitUrl}'` + ); +} + +console.log( + `Preparing to test external project ${externalProjectName} located at ${gitUrl} against this ember-data commit.` +); + +function execWithLog(command, force) { + if (debug.enabled || force) { + return shellSync(command, { stdio: [0, 1, 2] }); + } + + return shellSync(command); +} + +if (!fs.existsSync(tempDir)) { + fs.mkdirSync(tempDir); +} + +if (fs.existsSync(projectTempDir)) { + rimraf.sync(projectTempDir); +} + +// install the project +try { + execWithLog( + `cd ../__external-test-cache && git clone --depth=1 ${gitUrl} ./${externalProjectName}` + ); +} catch (e) { + debug(e); + throw new Error( + `Install of ${gitUrl} for external project ${externalProjectName} testing failed.` + ); +} + +const useYarn = fs.existsSync(path.join(projectTempDir, 'yarn.lock')); +const useBower = fs.existsSync(path.join(projectTempDir, 'bower.json')); + +// install project dependencies and link our local version of ember-data +try { + execWithLog( + `${ + useYarn ? 'yarn link' : 'npm link' + } && cd ../__external-test-cache/${externalProjectName} && ${useYarn ? 'yarn' : 'npm install'}${ + useBower ? ' && bower install' : '' + }` + ); +} catch (e) { + debug(e); + throw new Error( + `Unable to complete install of dependencies for external project ${externalProjectName}` + ); +} + +// run project tests +console.log(`Running tests for ${externalProjectName}`); + +let smokeTestPassed = true; +let commitTestPassed = true; + +try { + debug('Running Smoke Test'); + execWithLog(`cd ../__external-test-cache/${externalProjectName} && ember test`); +} catch (e) { + smokeTestPassed = false; +} + +try { + execWithLog(`${useYarn ? 'yarn link ember-data' : 'npm link ember-data'}`); +} catch (e) { + debug(e); + throw new Error( + `Unable to \`${useYarn ? 'yarn' : 'npm'} link ember-data\` for ${externalProjectName}` + ); +} + +try { + debug('Re-running tests against EmberData commit'); + execWithLog(`cd ../__external-test-cache/${externalProjectName} && ember test`, true); +} catch (e) { + commitTestPassed = false; +} + +if (!smokeTestPassed && !commitTestPassed) { + throw new Error( + `Commit may result in a regression, but the smoke test for ${externalProjectName} also failed.` + ); +} else if (smokeTestPassed && !commitTestPassed) { + throw new Error(`Commit results in a regression in ${externalProjectName}`); +} else if (!smokeTestPassed) { + console.log(`Commit may resolve issues present in the smoke test for ${externalProjectName}`); +} else { + console.log(`Commit does not regress ${externalProjectName}`); +} diff --git a/package.json b/package.json index 2c77a780595..6d998d9ba94 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,15 @@ "test:all": "ember try:each", "test:node": "node node-tests/nodetest-runner.js", "test:production": "ember test -e production && ember test -e production --record-data-rfc-build", - "test:optional-features": "ember test -e test-optional-features && ember test -e test-optional-features --record-data-rfc-build" + "test:optional-features": "ember test -e test-optional-features && ember test -e test-optional-features --record-data-rfc-build", + "test-external:ember-m3": "node ./lib/scripts/test-external ember-m3 https://github.com/hjdivad/ember-m3.git", + "test-external:ember-data-change-tracker": "node ./lib/scripts/test-external ember-data-change-tracker https://github.com/danielspaniel/ember-data-change-tracker.git", + "test-external:emberaddons.com": "node ./lib/scripts/test-external ember-cli-addon-search https://github.com/gcollazo/ember-cli-addon-search.git", + "test-external:model-fragments": "node ./lib/scripts/test-external ember-data-model-fragments https://github.com/lytics/ember-data-model-fragments.git", + "test-external:ember-observer": "node ./lib/scripts/test-external ember-observer https://github.com/emberobserver/client.git", + "test-external:travis-web": "node ./lib/scripts/test-external travis-web https://github.com/travis-ci/travis-web.git", + "test-external:storefront": "node ./lib/scripts/test-external storefront https://github.com/embermap/ember-data-storefront.git", + "test-external:factory-guy": "node ./lib/scripts/test-external factory-guy https://github.com/danielspaniel/ember-data-factory-guy.git" }, "author": "", "license": "MIT", @@ -92,6 +100,7 @@ "eslint-config-prettier": "^2.9.0", "eslint-plugin-node": "^7.0.1", "eslint-plugin-prettier": "2.6.2", + "execa": "^0.10.0", "fs-extra": "^7.0.0", "github": "^1.1.1", "glob": "^7.1.2", diff --git a/yarn.lock b/yarn.lock index f4bc2465fb9..ed542ce154f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3157,7 +3157,7 @@ exec-sh@^0.2.0: execa@^0.10.0: version "0.10.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + resolved "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" dependencies: cross-spawn "^6.0.0" get-stream "^3.0.0" From bc1bdac8b9142948563b82472090decae9af0832 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 26 Jul 2018 17:15:35 -0700 Subject: [PATCH 2313/2527] [FEAT] TrackableRequests for when async leakage is detected improve waiter erroring improve trace infra and add tests only run waiter tests in dev --- .../system/relationships/state/belongs-to.js | 3 +- .../system/relationships/state/has-many.js | 3 +- addon/-legacy-private/system/store.js | 90 ++++- addon/-private/system/store/common.js | 5 +- .../system/relationships/state/belongs-to.js | 2 +- .../system/relationships/state/has-many.js | 2 +- addon/-record-data-private/system/store.js | 88 ++++- tests/integration/store-test.js | 54 ++- tests/unit/store/async-leak-test.js | 361 ++++++++++++++++++ 9 files changed, 581 insertions(+), 27 deletions(-) create mode 100644 tests/unit/store/async-leak-test.js diff --git a/addon/-legacy-private/system/relationships/state/belongs-to.js b/addon/-legacy-private/system/relationships/state/belongs-to.js index 56a33bde298..a85df168cab 100644 --- a/addon/-legacy-private/system/relationships/state/belongs-to.js +++ b/addon/-legacy-private/system/relationships/state/belongs-to.js @@ -19,7 +19,8 @@ export default class BelongsToRelationship extends Relationship { * true if there is no inverse * false if the inverse exists and is not loaded (empty) * - * @returns {boolean} + * @property + * @return {boolean} */ get allInverseRecordsAreLoaded() { let internalModel = this.inverseInternalModel; diff --git a/addon/-legacy-private/system/relationships/state/has-many.js b/addon/-legacy-private/system/relationships/state/has-many.js index 339cdc9ebce..7a164d92958 100755 --- a/addon/-legacy-private/system/relationships/state/has-many.js +++ b/addon/-legacy-private/system/relationships/state/has-many.js @@ -33,7 +33,8 @@ export default class ManyRelationship extends Relationship { * true if there are no inverse records * false if the inverse records exist and any are not loaded (any empty) * - * @returns {boolean} + * @property + * @return {boolean} */ get allInverseRecordsAreLoaded() { // check currentState for unloaded records diff --git a/addon/-legacy-private/system/store.js b/addon/-legacy-private/system/store.js index ae75e920ac8..56bf66b635e 100644 --- a/addon/-legacy-private/system/store.js +++ b/addon/-legacy-private/system/store.js @@ -220,9 +220,52 @@ Store = Service.extend({ this._serializerCache = Object.create(null); if (DEBUG) { - this.__asyncRequestCount = 0; + if (this.shouldTrackAsyncRequests === undefined) { + this.shouldTrackAsyncRequests = false; + } + if (this.generateStackTracesForTrackedRequests === undefined) { + this.generateStackTracesForTrackedRequests = false; + } + + this._trackedAsyncRequests = []; + this._trackAsyncRequestStart = label => { + let trace = + 'set `store.generateStackTracesForTrackedRequests = true;` to get a detailed trace for where this request originated'; + + if (this.generateStackTracesForTrackedRequests) { + try { + throw new Error(`EmberData TrackedRequest: ${label}`); + } catch (e) { + trace = e; + } + } + + let token = Object.freeze({ + label, + trace, + }); + + this._trackedAsyncRequests.push(token); + return token; + }; + this._trackAsyncRequestEnd = token => { + let index = this._trackedAsyncRequests.indexOf(token); + + if (index === -1) { + throw new Error( + `Attempted to end tracking for the following request but it was not being tracked:\n${token}` + ); + } + + this._trackedAsyncRequests.splice(index, 1); + }; + this.__asyncWaiter = () => { - return this.__asyncRequestCount === 0; + let shouldTrack = this.shouldTrackAsyncRequests; + let tracked = this._trackedAsyncRequests; + let isSettled = tracked.length === 0; + + return shouldTrack !== true || isSettled; }; Ember.Test.registerWaiter(this.__asyncWaiter); @@ -833,6 +876,24 @@ Store = Service.extend({ options, }; + if (DEBUG) { + if (this.generateStackTracesForTrackedRequests === true) { + let trace; + + try { + throw new Error(`Trace Origin for scheduled fetch for ${modelName}:${id}.`); + } catch (e) { + trace = e; + } + + // enable folks to discover the origin of this findRecord call when + // debugging. Ideally we would have a tracked queue for requests with + // labels or local IDs that could be used to merge this trace with + // the trace made available when we detect an async leak + pendingFetchItem.trace = trace; + } + } + let promise = resolver.promise; internalModel.loadingData(promise); @@ -2840,6 +2901,27 @@ Store = Service.extend({ if (DEBUG) { Ember.Test.unregisterWaiter(this.__asyncWaiter); + let shouldTrack = this.shouldTrackAsyncRequests; + let tracked = this._trackedAsyncRequests; + let isSettled = tracked.length === 0; + + if (!isSettled) { + if (shouldTrack) { + throw new Error( + 'Async Request leaks detected. Add a breakpoint here and set `store.generateStackTracesForTrackedRequests = true;`to inspect traces for leak origins:\n\t - ' + + tracked.map(o => o.label).join('\n\t - ') + ); + } else { + warn( + 'Async Request leaks detected. Add a breakpoint here and set `store.generateStackTracesForTrackedRequests = true;`to inspect traces for leak origins:\n\t - ' + + tracked.map(o => o.label).join('\n\t - '), + false, + { + id: 'ds.async.leak.detected', + } + ); + } + } } }, @@ -3043,11 +3125,11 @@ function isInverseRelationshipInitialized(store, internalModel, data, key, model } /** - * + * @function * @param store * @param cache modelFactoryCache * @param normalizedModelName already normalized modelName - * @returns {*} + * @return {*} */ function getModelFactory(store, cache, normalizedModelName) { let factory = cache[normalizedModelName]; diff --git a/addon/-private/system/store/common.js b/addon/-private/system/store/common.js index ac56b0a8797..7eb81f77f18 100644 --- a/addon/-private/system/store/common.js +++ b/addon/-private/system/store/common.js @@ -34,14 +34,15 @@ export function _objectIsAlive(object) { } export function guardDestroyedStore(promise, store, label) { + let token; if (DEBUG) { - store.__asyncRequestCount++; + token = store._trackAsyncRequestStart(label); } let wrapperPromise = resolve(promise, label).then(v => promise); return _guard(wrapperPromise, () => { if (DEBUG) { - store.__asyncRequestCount--; + store._trackAsyncRequestEnd(token); } return _objectIsAlive(store); }); diff --git a/addon/-record-data-private/system/relationships/state/belongs-to.js b/addon/-record-data-private/system/relationships/state/belongs-to.js index e11cda74aae..1f82fee9f55 100644 --- a/addon/-record-data-private/system/relationships/state/belongs-to.js +++ b/addon/-record-data-private/system/relationships/state/belongs-to.js @@ -199,7 +199,7 @@ export default class BelongsToRelationship extends Relationship { * true if there is no inverse * false if the inverse exists and is not loaded (empty) * - * @returns {boolean} + * @return {boolean} */ get allInverseRecordsAreLoaded() { let modelData = this.inverseModelData; diff --git a/addon/-record-data-private/system/relationships/state/has-many.js b/addon/-record-data-private/system/relationships/state/has-many.js index dea44b7f7e8..be2e44c5e07 100755 --- a/addon/-record-data-private/system/relationships/state/has-many.js +++ b/addon/-record-data-private/system/relationships/state/has-many.js @@ -256,7 +256,7 @@ export default class ManyRelationship extends Relationship { * true if there are no inverse records * false if the inverse records exist and any are not loaded (any empty) * - * @returns {boolean} + * @return {boolean} */ get allInverseRecordsAreLoaded() { // check currentState for unloaded records diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index 6e4e609370d..dd2aae570b0 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -226,9 +226,52 @@ Store = Service.extend({ this.modelDataWrapper = new ModelDataWrapper(this); if (DEBUG) { - this.__asyncRequestCount = 0; + if (this.shouldTrackAsyncRequests === undefined) { + this.shouldTrackAsyncRequests = false; + } + if (this.generateStackTracesForTrackedRequests === undefined) { + this.generateStackTracesForTrackedRequests = false; + } + + this._trackedAsyncRequests = []; + this._trackAsyncRequestStart = label => { + let trace = + 'set `store.generateStackTracesForTrackedRequests = true;` to get a detailed trace for where this request originated'; + + if (this.generateStackTracesForTrackedRequests) { + try { + throw new Error(`EmberData TrackedRequest: ${label}`); + } catch (e) { + trace = e; + } + } + + let token = Object.freeze({ + label, + trace, + }); + + this._trackedAsyncRequests.push(token); + return token; + }; + this._trackAsyncRequestEnd = token => { + let index = this._trackedAsyncRequests.indexOf(token); + + if (index === -1) { + throw new Error( + `Attempted to end tracking for the following request but it was not being tracked:\n${token}` + ); + } + + this._trackedAsyncRequests.splice(index, 1); + }; + this.__asyncWaiter = () => { - return this.__asyncRequestCount === 0; + let shouldTrack = this.shouldTrackAsyncRequests; + let tracked = this._trackedAsyncRequests; + let isSettled = tracked.length === 0; + + return shouldTrack !== true || isSettled; }; Ember.Test.registerWaiter(this.__asyncWaiter); @@ -842,6 +885,24 @@ Store = Service.extend({ options, }; + if (DEBUG) { + if (this.generateStackTracesForTrackedRequests === true) { + let trace; + + try { + throw new Error(`Trace Origin for scheduled fetch for ${modelName}:${id}.`); + } catch (e) { + trace = e; + } + + // enable folks to discover the origin of this findRecord call when + // debugging. Ideally we would have a tracked queue for requests with + // labels or local IDs that could be used to merge this trace with + // the trace made available when we detect an async leak + pendingFetchItem.trace = trace; + } + } + let promise = resolver.promise; internalModel.loadingData(promise); @@ -3062,6 +3123,27 @@ Store = Service.extend({ if (DEBUG) { Ember.Test.unregisterWaiter(this.__asyncWaiter); + let shouldTrack = this.shouldTrackAsyncRequests; + let tracked = this._trackedAsyncRequests; + let isSettled = tracked.length === 0; + + if (!isSettled) { + if (shouldTrack) { + throw new Error( + 'Async Request leaks detected. Add a breakpoint here and set `store.generateStackTracesForTrackedRequests = true;`to inspect traces for leak origins:\n\t - ' + + tracked.map(o => o.label).join('\n\t - ') + ); + } else { + warn( + 'Async Request leaks detected. Add a breakpoint here and set `store.generateStackTracesForTrackedRequests = true;`to inspect traces for leak origins:\n\t - ' + + tracked.map(o => o.label).join('\n\t - '), + false, + { + id: 'ds.async.leak.detected', + } + ); + } + } } }, @@ -3231,7 +3313,7 @@ function _commit(adapter, store, operation, snapshot) { * @param store * @param cache modelFactoryCache * @param normalizedModelName already normalized modelName - * @returns {*} + * @return {*} */ function getModelFactory(store, cache, normalizedModelName) { let factory = cache[normalizedModelName]; diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 175bf80c4da..47f0931cd60 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -1,7 +1,7 @@ -import RSVP, { Promise as EmberPromise, resolve } from 'rsvp'; +import { Promise, resolve } from 'rsvp'; import { run, next } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; - +import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import deepCopy from 'dummy/tests/helpers/deep-copy'; import { module, test } from 'qunit'; @@ -76,7 +76,7 @@ test("destroying record during find doesn't cause error", function(assert) { let TestAdapter = DS.Adapter.extend({ findRecord(store, type, id, snapshot) { - return new EmberPromise((resolve, reject) => { + return new Promise((resolve, reject) => { next(() => { store.unloadAll(type.modelName); reject(); @@ -93,31 +93,57 @@ test("destroying record during find doesn't cause error", function(assert) { return run(() => store.findRecord(type, id).then(done, done)); }); -test('find calls do not resolve when the store is destroyed', function(assert) { - assert.expect(0); +testInDebug('find calls do not resolve when the store is destroyed', async function(assert) { + assert.expect(2); let done = assert.async(); - + let next; + let nextPromise = new Promise(resolve => { + next = resolve; + }); let TestAdapter = DS.Adapter.extend({ - findRecord(store, type, id, snapshot) { - store.destroy(); - resolve(null); + findRecord() { + next(); + nextPromise = new Promise(resolve => { + next = resolve; + }).then(() => { + return { + data: { type: 'car', id: '1' }, + }; + }); + return nextPromise; }, }); initializeStore(TestAdapter); - let type = 'car'; - let id = 1; + // needed for LTS 2.16 + Ember.Test.adapter.exception = e => { + throw e; + }; + store.shouldTrackAsyncRequests = true; store.push = function() { assert('The test should have destroyed the store by now', store.get('isDestroyed')); throw new Error("We shouldn't be pushing data into the store when it is destroyed"); }; + store.findRecord('car', '1'); + + await nextPromise; + + assert.throws(() => { + run(() => store.destroy()); + }, /Async Request leaks detected/); - run(() => store.findRecord(type, id)); + next(); + await nextPromise; - setTimeout(() => done(), 500); + // ensure we allow the internal store promises + // to flush, potentially pushing data into the store + setTimeout(() => { + assert.ok(true, 'We made it to the end'); + done(); + }, 0); }); test('destroying the store correctly cleans everything up', function(assert) { @@ -228,7 +254,7 @@ test('destroying the store correctly cleans everything up', function(assert) { function ajaxResponse(value) { env.adapter.ajax = function(url, verb, hash) { - return run(RSVP, 'resolve', deepCopy(value)); + return run(() => resolve(deepCopy(value))); }; } diff --git a/tests/unit/store/async-leak-test.js b/tests/unit/store/async-leak-test.js new file mode 100644 index 00000000000..3c3da72c9c7 --- /dev/null +++ b/tests/unit/store/async-leak-test.js @@ -0,0 +1,361 @@ +import { module } from 'qunit'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; +import { setupTest } from 'ember-qunit'; +import Store from 'ember-data/store'; +import Model from 'ember-data/model'; +import { Promise } from 'rsvp'; +import { attr } from '@ember-decorators/data'; +import { run } from '@ember/runloop'; +import Ember from 'ember'; +import { testInDebug as test } from '../../helpers/test-in-debug'; + +class Person extends Model { + @attr + name; +} + +module('unit/store async-waiter and leak detection', function(hooks) { + let store; + setupTest(hooks); + + hooks.beforeEach(function() { + let { owner } = this; + owner.register('service:store', Store); + owner.register('model:person', Person); + owner.register( + 'serializer:application', + JSONAPISerializer.extend({ + normalizeResponse(_, __, jsonApiPayload) { + return jsonApiPayload; + }, + }) + ); + store = owner.lookup('service:store'); + store.shouldTrackAsyncRequests = true; + }); + + test('the waiter properly waits for pending requests', async function(assert) { + let findRecordWasInvoked; + let findRecordWasInvokedPromise = new Promise(resolveStep => { + findRecordWasInvoked = resolveStep; + }); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + return new Promise(resolve => { + findRecordWasInvoked(); + + setTimeout(() => { + resolve({ data: { type: 'person', id: '1' } }); + }, 50); // intentionally longer than the 10ms polling interval of `wait()` + }); + }, + }) + ); + + let request = store.findRecord('person', '1'); + let waiter = store.__asyncWaiter; + + assert.equal( + waiter(), + true, + 'We return true when no requests have been initiated yet (pending queue flush is async)' + ); + + await findRecordWasInvokedPromise; + + assert.equal(waiter(), false, 'We return false to keep waiting while requests are pending'); + + await request; + + assert.equal(waiter(), true, 'We return true to end waiting when no requests are pending'); + }); + + test('waiter can be turned off', async function(assert) { + let findRecordWasInvoked; + let findRecordWasInvokedPromise = new Promise(resolveStep => { + findRecordWasInvoked = resolveStep; + }); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + return new Promise(resolve => { + findRecordWasInvoked(); + + setTimeout(() => { + resolve({ data: { type: 'person', id: '1' } }); + }, 50); // intentionally longer than the 10ms polling interval of `wait()` + }); + }, + }) + ); + + // turn off the waiter + store.shouldTrackAsyncRequests = false; + + let request = store.findRecord('person', '1'); + let waiter = store.__asyncWaiter; + + assert.equal( + waiter(), + true, + 'We return true when no requests have been initiated yet (pending queue flush is async)' + ); + + await findRecordWasInvokedPromise; + + assert.equal( + store._trackedAsyncRequests.length, + 1, + 'We return true even though a request is pending' + ); + assert.equal(waiter(), true, 'We return true even though a request is pending'); + + await request; + + assert.equal(waiter(), true, 'We return true to end waiting when no requests are pending'); + }); + + test('waiter works even when the adapter rejects', async function(assert) { + assert.expect(4); + let findRecordWasInvoked; + let findRecordWasInvokedPromise = new Promise(resolveStep => { + findRecordWasInvoked = resolveStep; + }); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + return new Promise((resolve, reject) => { + findRecordWasInvoked(); + + setTimeout(() => { + reject({ errors: [] }); + }, 50); // intentionally longer than the 10ms polling interval of `wait()` + }); + }, + }) + ); + + let request = store.findRecord('person', '1'); + let waiter = store.__asyncWaiter; + + assert.equal( + waiter(), + true, + 'We return true when no requests have been initiated yet (pending queue flush is async)' + ); + + await findRecordWasInvokedPromise; + + assert.equal(waiter(), false, 'We return false to keep waiting while requests are pending'); + + await assert.rejects(request); + + assert.equal(waiter(), true, 'We return true to end waiting when no requests are pending'); + }); + + test('waiter works even when the adapter throws', async function(assert) { + assert.expect(4); + let waiter = store.__asyncWaiter; + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + assert.equal( + waiter(), + false, + 'We return false to keep waiting while requests are pending' + ); + throw new Error('Invalid Request!'); + }, + }) + ); + + let request = store.findRecord('person', '1'); + + assert.equal( + waiter(), + true, + 'We return true when no requests have been initiated yet (pending queue flush is async)' + ); + + await assert.rejects(request); + + assert.equal(waiter(), true, 'We return true to end waiting when no requests are pending'); + }); + + test('when the store is torn down too early, we throw an error', async function(assert) { + let next; + let stepPromise = new Promise(resolveStep => { + next = resolveStep; + }); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + next(); + stepPromise = new Promise(resolveStep => { + next = resolveStep; + }).then(() => { + return { data: { type: 'person', id: '1' } }; + }); + return stepPromise; + }, + }) + ); + + store.findRecord('person', '1'); + let waiter = store.__asyncWaiter; + + assert.equal( + waiter(), + true, + 'We return true when no requests have been initiated yet (pending queue flush is async)' + ); + + await stepPromise; + + assert.equal(waiter(), false, 'We return false to keep waiting while requests are pending'); + + // needed for LTS 2.16 + Ember.Test.adapter.exception = e => { + throw e; + }; + + assert.throws(() => { + run(() => store.destroy()); + }, /Async Request leaks detected/); + + assert.equal(waiter(), false, 'We return false because we still have a pending request'); + + // make the waiter complete + run(() => next()); + assert.equal(store._trackedAsyncRequests.length, 0, 'Our pending request is cleaned up'); + assert.equal(waiter(), true, 'We return true because the waiter is cleared'); + }); + + test('when the store is torn down too early, but the waiter behavior is turned off, we emit a warning', async function(assert) { + let next; + let stepPromise = new Promise(resolveStep => { + next = resolveStep; + }); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + next(); + stepPromise = new Promise(resolveStep => { + next = resolveStep; + }).then(() => { + return { data: { type: 'person', id: '1' } }; + }); + return stepPromise; + }, + }) + ); + + // turn off the waiter + store.shouldTrackAsyncRequests = false; + + store.findRecord('person', '1'); + let waiter = store.__asyncWaiter; + + assert.equal(store._trackedAsyncRequests.length, 0, 'We have no requests yet'); + assert.equal( + waiter(), + true, + 'We return true when no requests have been initiated yet (pending queue flush is async)' + ); + + await stepPromise; + + assert.equal(store._trackedAsyncRequests.length, 1, 'We have a pending request'); + assert.equal(waiter(), true, 'We return true because the waiter is turned off'); + assert.expectWarning(() => { + run(() => { + store.destroy(); + }); + }, /Async Request leaks detected/); + + assert.equal(waiter(), true, 'We return true because the waiter is turned off'); + + // make the waiter complete + run(() => next()); + assert.equal(store._trackedAsyncRequests.length, 0, 'Our pending request is cleaned up'); + assert.equal(waiter(), true, 'We return true because the waiter is cleared'); + }); + + test('when configured, pending requests have useful stack traces', async function(assert) { + let stepResolve; + let stepPromise = new Promise(resolveStep => { + stepResolve = resolveStep; + }); + let fakeId = 1; + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + return new Promise(resolve => { + stepResolve(); + + setTimeout(() => { + resolve({ data: { type: 'person', id: `${fakeId++}` } }); + }, 50); // intentionally longer than the 10ms polling interval of `wait()` + }); + }, + }) + ); + let request = store.findRecord('person', '1'); + let waiter = store.__asyncWaiter; + + assert.equal( + waiter(), + true, + 'We return true when no requests have been initiated yet (pending queue flush is async)' + ); + + await stepPromise; + + assert.equal(waiter(), false, 'We return false to keep waiting while requests are pending'); + assert.equal( + store._trackedAsyncRequests[0].trace, + 'set `store.generateStackTracesForTrackedRequests = true;` to get a detailed trace for where this request originated', + 'We provide a useful default message in place of a trace' + ); + + await request; + + assert.equal(waiter(), true, 'We return true to end waiting when no requests are pending'); + + store.generateStackTracesForTrackedRequests = true; + request = store.findRecord('person', '2'); + + assert.equal( + waiter(), + true, + 'We return true when no requests have been initiated yet (pending queue flush is async)' + ); + + await stepPromise; + + assert.equal(waiter(), false, 'We return false to keep waiting while requests are pending'); + /* + TODO this just traces back to the `flushPendingFetches`, + we should do something similar to capture where the fetch was scheduled + from. + */ + assert.equal( + store._trackedAsyncRequests[0].trace.message, + "EmberData TrackedRequest: DS: Handle Adapter#findRecord of 'person' with id: '2'", + 'We captured a trace' + ); + + await request; + + assert.equal(waiter(), true, 'We return true to end waiting when no requests are pending'); + }); +}); From 4e38d556de204069e9e5adb7181ec73d80038eec Mon Sep 17 00:00:00 2001 From: Lukas Kohler Date: Fri, 24 Aug 2018 21:18:37 +0200 Subject: [PATCH 2314/2527] [DOC beta] fix broken link because the new API website does not support the anchor --- addon/adapters/rest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index a8cd88d2532..80c816f835f 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -445,7 +445,7 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { key. Arbitrary headers can be set as key/value pairs on the `RESTAdapter`'s `headers` object and Ember Data will send them along with each ajax request. For dynamic headers see [headers - customization](/api/data/classes/DS.RESTAdapter.html#toc_headers-customization). + customization](/api/data/classes/DS.RESTAdapter.html). ```app/adapters/application.js import DS from 'ember-data'; From 223233fa2b0a58aba5f6180a6b5adc95bc584a96 Mon Sep 17 00:00:00 2001 From: Kenneth Larsen Date: Sun, 26 Aug 2018 15:28:50 +0200 Subject: [PATCH 2315/2527] Fixes #4761: Add doc param for preload on findRecord (#5587) --- addon/-record-data-private/system/store.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index dd2aae570b0..0717d5decfb 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -725,6 +725,7 @@ Store = Service.extend({ @method findRecord @param {String} modelName @param {(String|Integer)} id + @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models @param {Object} options @return {Promise} promise */ From 3f3b4794c11f360e9d7c58b60bcf23087c3a1082 Mon Sep 17 00:00:00 2001 From: Kenneth Larsen Date: Mon, 27 Aug 2018 14:08:09 +0200 Subject: [PATCH 2316/2527] Fixed broken link to defining relationships in guides (#5590) --- addon/serializers/embedded-records-mixin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index 9868f15033c..bbc21faa7a6 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -77,7 +77,7 @@ import { warn } from '@ember/debug'; To successfully extract and serialize embedded records the model relationships must be setup correcty. See the - [defining relationships](/guides/models/defining-models/#toc_defining-relationships) + [defining relationships](/guides/models/relationships) section of the **Defining Models** guide page. Records without an `id` property are not considered embedded records, model From ae9c3f34133d6e61f03c19c91f8f57f66795846e Mon Sep 17 00:00:00 2001 From: Kenneth Larsen Date: Mon, 27 Aug 2018 15:00:13 +0200 Subject: [PATCH 2317/2527] Grammar fixes --- addon/-legacy-private/system/many-array.js | 2 +- addon/-legacy-private/system/model/states.js | 6 +++--- .../system/references/belongs-to.js | 6 +++--- .../system/references/has-many.js | 6 +++--- addon/-legacy-private/system/store.js | 2 +- addon/-private/adapters/build-url-mixin.js | 20 +++++++++---------- addon/-private/adapters/errors.js | 18 ++++++++--------- addon/-private/system/model/errors.js | 2 +- addon/-private/system/references/record.js | 2 +- .../-record-data-private/system/many-array.js | 2 +- .../system/model/states.js | 6 +++--- .../system/references/belongs-to.js | 2 +- .../system/references/has-many.js | 6 +++--- addon/-record-data-private/system/store.js | 2 +- addon/adapter.js | 14 ++++++------- addon/adapters/json-api.js | 2 +- addon/adapters/rest.js | 6 +++--- addon/serializers/embedded-records-mixin.js | 16 +++++++-------- addon/serializers/rest.js | 2 +- addon/transforms/boolean.js | 2 +- addon/transforms/transform.js | 2 +- 21 files changed, 63 insertions(+), 63 deletions(-) diff --git a/addon/-legacy-private/system/many-array.js b/addon/-legacy-private/system/many-array.js index f5c1ac297fa..47a1ca379a4 100644 --- a/addon/-legacy-private/system/many-array.js +++ b/addon/-legacy-private/system/many-array.js @@ -46,7 +46,7 @@ import diffArray from './diff-array'; property to be set to the post that contained the has-many. - We call the record to which a relationship belongs the + We call the record to which a relationship belongs-to the relationship's _owner_. @class ManyArray diff --git a/addon/-legacy-private/system/model/states.js b/addon/-legacy-private/system/model/states.js index 7697a1f1fd9..893a1680a35 100644 --- a/addon/-legacy-private/system/model/states.js +++ b/addon/-legacy-private/system/model/states.js @@ -16,7 +16,7 @@ import { assert } from '@ember/debug'; it would be in the `root.loaded.created.uncommitted` state. If a record has had local modifications made to it that are in the process of being saved, the record would be in the - `root.loaded.updated.inFlight` state. (This state paths will be + `root.loaded.updated.inFlight` state. (This state path will be explained in more detail below.) Events are sent by the record or its store to the record's @@ -24,9 +24,9 @@ import { assert } from '@ember/debug'; dependent on which state it is in. In some states, certain events will be invalid and will cause an exception to be raised. - States are hierarchical and every state is a substate of the + States are hierarchical and every state is a sub-state of the `RootState`. For example, a record can be in the - `root.deleted.uncommitted` state, then transition into the + `root.deleted.uncommitted` state then transitions into the `root.deleted.inFlight` state. If a child state does not implement an event handler, the state manager will attempt to invoke the event on all parent states until the root state is reached. The state diff --git a/addon/-legacy-private/system/references/belongs-to.js b/addon/-legacy-private/system/references/belongs-to.js index 07368d8ef64..6d836fa0300 100644 --- a/addon/-legacy-private/system/references/belongs-to.js +++ b/addon/-legacy-private/system/references/belongs-to.js @@ -5,7 +5,7 @@ import Reference from './reference'; import { assertPolymorphicType } from 'ember-data/-debug'; /** - A BelongsToReference is a low level API that allows users and + A BelongsToReference is a low-level API that allows users and addon author to perform meta-operations on a belongs-to relationship. @@ -314,7 +314,7 @@ export default class BelongsToReference extends Reference { } /** - Loads a record in a belongs to relationship if it is not already + Loads a record in a belongs to-relationship if it is not already loaded. If the relationship is already loaded this method does not trigger a new load. @@ -366,7 +366,7 @@ export default class BelongsToReference extends Reference { /** Triggers a reload of the value in this relationship. If the remoteType is `"link"` Ember Data will use the relationship link to - reload the relationship. Otherwise it will reload the record by its + reload the relationship. Otherwise, it will reload the record by its id. Example diff --git a/addon/-legacy-private/system/references/has-many.js b/addon/-legacy-private/system/references/has-many.js index 264103708e6..425ae243354 100644 --- a/addon/-legacy-private/system/references/has-many.js +++ b/addon/-legacy-private/system/references/has-many.js @@ -5,7 +5,7 @@ import { DEBUG } from '@glimmer/env'; import { assertPolymorphicType } from 'ember-data/-debug'; /** - A HasManyReference is a low level API that allows users and addon + A HasManyReference is a low-level API that allows users and addon author to perform meta-operations on a has-many relationship. @class HasManyReference @@ -107,7 +107,7 @@ export default class HasManyReference extends Reference { } /** - `ids()` returns an array of the record ids in this relationship. + `ids()` returns an array of the record IDs in this relationship. Example @@ -147,7 +147,7 @@ export default class HasManyReference extends Reference { } /** - The meta data for the has-many relationship. + The metadata for the has-many relationship. Example diff --git a/addon/-legacy-private/system/store.js b/addon/-legacy-private/system/store.js index 56bf66b635e..919e158d39c 100644 --- a/addon/-legacy-private/system/store.js +++ b/addon/-legacy-private/system/store.js @@ -153,7 +153,7 @@ const { [createRecord](#method_createRecord) is used for creating new records on the client side. This will return a new record in the `created.uncommitted` state. In order to persist this record to the - backend you will need to call `record.save()`. + backend, you will need to call `record.save()`. [push](#method_push) is used to notify Ember Data's store of new or updated records that exist in the backend. This will return a record diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index d1552ae675f..4fd90fcbd1c 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -5,11 +5,11 @@ import { pluralize } from 'ember-inflector'; /** - WARNING: This interface is likely to change in order to accomodate https://github.com/emberjs/rfcs/pull/4 + WARNING: This interface is likely to change in order to accommodate [RFC: Ember Data url templates](https://github.com/emberjs/rfcs/pull/4) ## Using BuildURLMixin - To use url building, include the mixin when extending an adapter, and call `buildURL` where needed. + To use URL building, include the mixin when extending an adapter, and call `buildURL` where needed. The default behaviour is designed for RESTAdapter. ### Example @@ -41,7 +41,7 @@ export default Mixin.create({ If an ID is specified, it adds the ID to the path generated for the type, separated by a `/`. - When called by RESTAdapter.findMany() the `id` and `snapshot` parameters + When called by `RESTAdapter.findMany()` the `id` and `snapshot` parameters will be arrays of ids and snapshots. @method buildURL @@ -221,9 +221,9 @@ export default Mixin.create({ }, /** - Builds a URL for coalesceing multiple `store.findRecord(type, id)` + Builds a URL for coalescing multiple `store.findRecord(type, id)` records into 1 request when the adapter's `coalesceFindRequests` - property is true. + property is `true`. Example: @@ -249,7 +249,7 @@ export default Mixin.create({ }, /** - Builds a URL for fetching a async hasMany relationship when a url + Builds a URL for fetching an async `hasMany` relationship when a URL is not provided by the server. Example: @@ -276,7 +276,7 @@ export default Mixin.create({ }, /** - Builds a URL for fetching a async belongsTo relationship when a url + Builds a URL for fetching an async `belongsTo` relationship when a url is not provided by the server. Example: @@ -328,7 +328,7 @@ export default Mixin.create({ }, /** - Builds a URL for a `record.save()` call when the record has been update locally. + Builds a URL for a `record.save()` call when the record has been updated locally. Example: @@ -426,8 +426,8 @@ export default Mixin.create({ ### Pathname customization - For example if you have an object LineItem with an - endpoint of "/line_items/". + For example, if you have an object `LineItem` with an + endpoint of `/line_items/`. ```app/adapters/application.js import DS from 'ember-data'; diff --git a/addon/-private/adapters/errors.js b/addon/-private/adapters/errors.js index 8cfd7b978dd..4591522e587 100644 --- a/addon/-private/adapters/errors.js +++ b/addon/-private/adapters/errors.js @@ -23,7 +23,7 @@ const PRIMARY_ATTRIBUTE_KEY = 'base'; - `DS.ServerError` To create a custom error to signal a specific error state in communicating - with an external API, extend the `DS.AdapterError`. For example if the + with an external API, extend the `DS.AdapterError`. For example, if the external API exclusively used HTTP `503 Service Unavailable` to indicate it was closed for maintenance: @@ -110,16 +110,16 @@ AdapterError.extend = extendFn(AdapterError); /** A `DS.InvalidError` is used by an adapter to signal the external API was unable to process a request because the content was not - semantically correct or meaningful per the API. Usually this means a - record failed some form of server side validation. When a promise + semantically correct or meaningful per the API. Usually, this means a + record failed some form of server-side validation. When a promise from an adapter is rejected with a `DS.InvalidError` the record will transition to the `invalid` state and the errors will be set to the `errors` property on the record. For Ember Data to correctly map errors to their corresponding properties on the model, Ember Data expects each error to be - a valid json-api error object with a `source/pointer` that matches - the property name. For example if you had a Post model that + a valid JSON-API error object with a `source/pointer` that matches + the property name. For example, if you had a Post model that looked like this. ```app/models/post.js @@ -157,9 +157,9 @@ AdapterError.extend = extendFn(AdapterError); ``` Your backend may use different property names for your records the - store will attempt extract and normalize the errors using the + store will attempt to extract and normalize the errors using the serializer's `extractErrors` method before the errors get added to - the the model. As a result, it is safe for the `InvalidError` to + the model. As a result, it is safe for the `InvalidError` to wrap the error payload unaltered. @class InvalidError @@ -221,7 +221,7 @@ export const AbortError = extend(AdapterError, 'The adapter operation was aborte API was rejected because authorization is required and has failed or has not yet been provided. - An example use case would be to redirect the user to a log in route if a + An example use case would be to redirect the user to a login route if a request is unauthorized: ```app/routes/application.js @@ -304,7 +304,7 @@ export const NotFoundError = extend(AdapterError, 'The adapter could not find th A `DS.ConflictError` equates to a HTTP `409 Conflict` response status. It is used by an adapter to indicate that the request could not be processed because of a conflict in the request. An example scenario would be when - creating a record with a client generated id but that id is already known + creating a record with a client-generated ID but that ID is already known to the external API. @class ConflictError diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index 005fb9ec7ca..e718fc06168 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -390,7 +390,7 @@ export default ArrayProxy.extend(Evented, { }, /** - Checks if there is error messages for the given attribute. + Checks if there are error messages for the given attribute. ```app/routes/user/edit.js import Route from '@ember/routing/route'; diff --git a/addon/-private/system/references/record.js b/addon/-private/system/references/record.js index 56bb3338192..ebc08a5680c 100644 --- a/addon/-private/system/references/record.js +++ b/addon/-private/system/references/record.js @@ -2,7 +2,7 @@ import { resolve } from 'rsvp'; import Reference from './reference'; /** - An RecordReference is a low level API that allows users and + An RecordReference is a low-level API that allows users and addon author to perform meta-operations on a record. @class RecordReference diff --git a/addon/-record-data-private/system/many-array.js b/addon/-record-data-private/system/many-array.js index 24e75beae59..a7ee046030b 100644 --- a/addon/-record-data-private/system/many-array.js +++ b/addon/-record-data-private/system/many-array.js @@ -46,7 +46,7 @@ import diffArray from './diff-array'; property to be set to the post that contained the has-many. - We call the record to which a relationship belongs the + We call the record to which a relationship belongs-to the relationship's _owner_. @class ManyArray diff --git a/addon/-record-data-private/system/model/states.js b/addon/-record-data-private/system/model/states.js index 98cf914167e..64af14ba330 100644 --- a/addon/-record-data-private/system/model/states.js +++ b/addon/-record-data-private/system/model/states.js @@ -16,7 +16,7 @@ import { assert } from '@ember/debug'; it would be in the `root.loaded.created.uncommitted` state. If a record has had local modifications made to it that are in the process of being saved, the record would be in the - `root.loaded.updated.inFlight` state. (This state paths will be + `root.loaded.updated.inFlight` state. (This state path will be explained in more detail below.) Events are sent by the record or its store to the record's @@ -24,9 +24,9 @@ import { assert } from '@ember/debug'; dependent on which state it is in. In some states, certain events will be invalid and will cause an exception to be raised. - States are hierarchical and every state is a substate of the + States are hierarchical and every state is a sub-state of the `RootState`. For example, a record can be in the - `root.deleted.uncommitted` state, then transition into the + `root.deleted.uncommitted` state then transitions into the `root.deleted.inFlight` state. If a child state does not implement an event handler, the state manager will attempt to invoke the event on all parent states until the root state is reached. The state diff --git a/addon/-record-data-private/system/references/belongs-to.js b/addon/-record-data-private/system/references/belongs-to.js index 29a679eea92..2a20eb3d6a0 100644 --- a/addon/-record-data-private/system/references/belongs-to.js +++ b/addon/-record-data-private/system/references/belongs-to.js @@ -7,7 +7,7 @@ import { deprecate } from '@ember/debug'; import { assertPolymorphicType } from 'ember-data/-debug'; /** - A BelongsToReference is a low level API that allows users and + A BelongsToReference is a low-level API that allows users and addon author to perform meta-operations on a belongs-to relationship. diff --git a/addon/-record-data-private/system/references/has-many.js b/addon/-record-data-private/system/references/has-many.js index d74fe7871dc..7ac204b993c 100644 --- a/addon/-record-data-private/system/references/has-many.js +++ b/addon/-record-data-private/system/references/has-many.js @@ -5,7 +5,7 @@ import { DEBUG } from '@glimmer/env'; import { assertPolymorphicType } from 'ember-data/-debug'; /** - A HasManyReference is a low level API that allows users and addon + A HasManyReference is a low-level API that allows users and addon author to perform meta-operations on a has-many relationship. @class HasManyReference @@ -64,7 +64,7 @@ export default class HasManyReference extends Reference { ``` @method remoteType - @return {String} The name of the remote type. This should either be "link" or "ids" + @return {String} The name of the remote type. This should either be `link` or `ids` */ remoteType() { let value = this._resource(); @@ -76,7 +76,7 @@ export default class HasManyReference extends Reference { } /** - `ids()` returns an array of the record ids in this relationship. + `ids()` returns an array of the record IDs in this relationship. Example diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index 0717d5decfb..a6afccd6c46 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -154,7 +154,7 @@ const { [createRecord](#method_createRecord) is used for creating new records on the client side. This will return a new record in the `created.uncommitted` state. In order to persist this record to the - backend you will need to call `record.save()`. + backend, you will need to call `record.save()`. [push](#method_push) is used to notify Ember Data's store of new or updated records that exist in the backend. This will return a record diff --git a/addon/adapter.js b/addon/adapter.js index fec86b72db6..f6560223268 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -7,7 +7,7 @@ import EmberObject from '@ember/object'; /** An adapter is an object that receives requests from a store and translates them into the appropriate action to take against your - persistence layer. The persistence layer is usually an HTTP API, but + persistence layer. The persistence layer is usually an HTTP API but may be anything, such as the browser's local storage. Typically the adapter is not invoked directly instead its functionality is accessed through the `store`. @@ -52,7 +52,7 @@ import EmberObject from '@ember/object'; * `findMany()` - For an example implementation, see `DS.RESTAdapter`, the + For an example of the implementation, see `DS.RESTAdapter`, the included REST adapter. @class Adapter @@ -90,7 +90,7 @@ export default EmberObject.extend({ method should return a promise that will resolve to a JavaScript object that will be normalized by the serializer. - Here is an example `findRecord` implementation: + Here is an example of the `findRecord` implementation: ```app/adapters/application.js import DS from 'ember-data'; @@ -477,7 +477,7 @@ export default EmberObject.extend({ Organize records into groups, each of which is to be passed to separate calls to `findMany`. - For example, if your api has nested URLs that depend on the parent, you will + For example, if your API has nested URLs that depend on the parent, you will want to group records by their parent. The default implementation returns the records as a single group. @@ -578,9 +578,9 @@ export default EmberObject.extend({ case a cached version is more than 20 minutes old, `findAll` will not resolve until you fetched the latest versions. - By default this methods returns `true` if the passed `snapshotRecordArray` + By default, this method returns `true` if the passed `snapshotRecordArray` is empty (meaning that there are no records locally available yet), - otherwise it returns `false`. + otherwise, it returns `false`. Note that, with default settings, `shouldBackgroundReloadAll` will always re-fetch all the records in the background even if `shouldReloadAll` returns @@ -624,7 +624,7 @@ export default EmberObject.extend({ } ``` - By default this hook returns `true` so the data for the record is updated + By default, this hook returns `true` so the data for the record is updated in the background. @since 1.13.0 diff --git a/addon/adapters/json-api.js b/addon/adapters/json-api.js index f23aa34eb20..7b5f2e8b1ed 100644 --- a/addon/adapters/json-api.js +++ b/addon/adapters/json-api.js @@ -15,7 +15,7 @@ import { pluralize } from 'ember-inflector'; ## JSON API Conventions - The JSONAPIAdapter uses JSON API conventions for building the url + The JSONAPIAdapter uses JSON API conventions for building the URL for a record and selecting the HTTP verb to use with a request. The actions you can take on a record map onto the following URLs in the JSON API adapter: diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index a8cd88d2532..ee69443b110 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -161,9 +161,9 @@ const Promise = EmberPromise; ``` If the records in the relationship are not known when the response - is serialized its also possible to represent the relationship as a - url using the `links` key in the response. Ember Data will fetch - this url to resolve the relationship when it is accessed for the + is serialized it's also possible to represent the relationship as a + URL using the `links` key in the response. Ember Data will fetch + this URL to resolve the relationship when it is accessed for the first time. ```js diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index bbc21faa7a6..f8b4e66a228 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -30,7 +30,7 @@ import { warn } from '@ember/debug'; Note that this use of `{ embedded: 'always' }` is unrelated to the `{ embedded: 'always' }` that is defined as an option on `DS.attr` as part of defining a model while working with the `ActiveModelSerializer`. Nevertheless, - using `{ embedded: 'always' }` as an option to `DS.attr` is not a valid way to setup + using `{ embedded: 'always' }` as an option to `DS.attr` is not a valid way to set up embedded records. The `attrs` option for a resource `{ embedded: 'always' }` is shorthand for: @@ -52,7 +52,7 @@ import { warn } from '@ember/debug'; In the case where embedded JSON is expected while extracting a payload (reading) the setting is `deserialize: 'records'`, there is no need to use `ids` when - extracting as that is the default behavior without this mixin if you are using + extracting as that is the default behaviour without this mixin if you are using the vanilla `EmbeddedRecordsMixin`. Likewise, to embed JSON in the payload while serializing `serialize: 'records'` is the setting to use. There is an option of not embedding JSON in the serialized payload by using `serialize: 'ids'`. If you @@ -76,8 +76,8 @@ import { warn } from '@ember/debug'; then do not use `async: true`. To successfully extract and serialize embedded records the model relationships - must be setup correcty. See the - [defining relationships](/guides/models/relationships) + must be set up correctly. See the + [defining relationships](/guides/models/defining-models/#toc_defining-relationships) section of the **Defining Models** guide page. Records without an `id` property are not considered embedded records, model @@ -89,7 +89,7 @@ import { warn } from '@ember/debug'; are. Please read the docs for the methods this mixin provides, in case you need to modify it to fit your specific needs.** - For example review the docs for each method of this mixin: + For example, review the docs for each method of this mixin: * [normalize](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_normalize) * [serializeBelongsTo](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeBelongsTo) * [serializeHasMany](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeHasMany) @@ -326,7 +326,7 @@ export default Mixin.create({ This is particularly useful for polymorphic relationships where records don't share the same table and the `id` is not enough information. - By example having a user that has many pets: + For example having a user that has many pets: ```js User = DS.Model.extend({ @@ -455,8 +455,8 @@ export default Mixin.create({ }, /** - When serializing an embedded record, modify the property (in the json payload) - that refers to the parent record (foreign key for relationship). + When serializing an embedded record, modify the property (in the `JSON` payload) + that refers to the parent record (foreign key for the relationship). Serializing a `belongsTo` relationship removes the property that refers to the parent record diff --git a/addon/serializers/rest.js b/addon/serializers/rest.js index 8987067e4f7..cda13a82dd2 100644 --- a/addon/serializers/rest.js +++ b/addon/serializers/rest.js @@ -21,7 +21,7 @@ import { Normally, applications will use the `RESTSerializer` by implementing the `normalize` method. - This allows you to do whatever kind of munging you need, and is + This allows you to do whatever kind of munging you need and is especially useful if your server is inconsistent and you need to do munging differently for many different kinds of responses. diff --git a/addon/transforms/boolean.js b/addon/transforms/boolean.js index 241084ba3a0..28268fa4c18 100644 --- a/addon/transforms/boolean.js +++ b/addon/transforms/boolean.js @@ -19,7 +19,7 @@ import Transform from './transform'; }); ``` - By default the boolean transform only allows for values of `true` or + By default, the boolean transform only allows for values of `true` or `false`. You can opt into allowing `null` values for boolean attributes via `DS.attr('boolean', { allowNull: true })` diff --git a/addon/transforms/transform.js b/addon/transforms/transform.js index 5cbdb20a1ce..7a87f0256e1 100644 --- a/addon/transforms/transform.js +++ b/addon/transforms/transform.js @@ -90,7 +90,7 @@ export default EmberObject.extend({ serialize: null, /** - When given a serialize value from a JSON object this method must + When given a serialized value from a JSON object this method must return the deserialized value for the record attribute. Example From 1b2a1a3fa532b5da125d8e38d3b422a91f4426c6 Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 27 Aug 2018 18:07:53 -0400 Subject: [PATCH 2318/2527] Update changelog for the Ember Data 3.4.0 release --- CHANGELOG.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a58afe38161..eb62ddcd2b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,46 @@ ### Master +### Release 3.4.0 (August 27, 2018) +- [#5540](https://github.com/emberjs/data/pull/5540) revert is-empty flag change, leave todo (#5540) +- [#5545](https://github.com/emberjs/data/pull/5545) [FEAT] TrackableRequests for when async leakage is detected +- [#5551](https://github.com/emberjs/data/pull/5551) Fix `floating dependencies` test suite (#5551) +- [#5557](https://github.com/emberjs/data/pull/5557) Fixup transpilation issues with @ember/ordered-set. (#5557) +- [#5559](https://github.com/emberjs/data/pull/5559) Dependency roundup! +- [#5562](https://github.com/emberjs/data/pull/5562) [BUGFIX] use internalModel promise if already loading (#5562) +- [#5566](https://github.com/emberjs/data/pull/5566) Acceptance Tests for belongsTo +- [#5567](https://github.com/emberjs/data/pull/5567) [FEAT] enable external partner testing +- [#5549](https://github.com/emberjs/data/pull/5549) [BUGFIX beta] Replace Object.assign with Ember polyfill assign (#5549) +- [#5540](https://github.com/emberjs/data/pull/5540) revert is-empty flag change, leave todo (#5540) +- [#5544](https://github.com/emberjs/data/pull/5544) remove test waiter (#5544) +- [#5543](https://github.com/emberjs/data/pull/5543) Do not publish yarn.lock to npm +- [#5477](https://github.com/emberjs/data/pull/5477) [BUGFIX] normalize model name for belongs to relationships (#5477) +- [#5518](https://github.com/emberjs/data/pull/5518) [BUGFIX] Clarifying error message for polymorphic types (#5518) +- [#5520](https://github.com/emberjs/data/pull/5520) Add 2.18.3 release to the changelog on master +- [#5526](https://github.com/emberjs/data/pull/5526) Update links to builds page fixtures +- [#5528](https://github.com/emberjs/data/pull/5528) Add tests for createRecord+unloadRecord +- [#5531](https://github.com/emberjs/data/pull/5531) broccoli-babel-transpiler appears only used in tests, otherwise it uses +- [#5531](https://github.com/emberjs/data/pull/5531) broccoli-babel-transpiler appears only used in tests, otherwise it uses +- [#5533](https://github.com/emberjs/data/pull/5533) [BUGFIX] fix and tests for belongs-to proxy not properly updating (#5533) +- [#5536](https://github.com/emberjs/data/pull/5536) [BUGFIX beta] Upgrading ember-inflector to v3.3.0 +- [#5467](https://github.com/emberjs/data/pull/5467) [BUGFIX] don't cause unnecessary work during destroy +- [#5411](https://github.com/emberjs/data/pull/5411) Remove deprecations scheduled for 3.0 +- [#5117](https://github.com/emberjs/data/pull/5117) Give Model a static toString method +- [#5429](https://github.com/emberjs/data/pull/5429) improve tests for unloading relationships +- [#5469](https://github.com/emberjs/data/pull/5469) Revamp eslint configuration. +- [#5439](https://github.com/emberjs/data/pull/5439) [FEAT] FASTBOOT SHOEBOX - Use actions queue so rehydration works +- [#5432](https://github.com/emberjs/data/pull/5432) Remove exists-sync dependency +- [#5436](https://github.com/emberjs/data/pull/5436) [CHORE] remove all usage of Ember.copy +- [#5438](https://github.com/emberjs/data/pull/5438) [BUGFIX] ensure destroy-sync cleanup is correct +- [#5437](https://github.com/emberjs/data/pull/5437) [CHORE] removes deprecated Store.filter feature +- [#5462](https://github.com/emberjs/data/pull/5462) [BUGFIX] ensure ManyArray state is in-sync with relationship state +- [#5446](https://github.com/emberjs/data/pull/5446) [CLEANUP] fix model and factory lookup +- [#5466](https://github.com/emberjs/data/pull/5466) Serialize empty hasMany relationships +- [#5461](https://github.com/emberjs/data/pull/5461) [BUGFIX] update content of proxy for async belongs-to relationships when null data received +- [#5471](https://github.com/emberjs/data/pull/5471) [CHORE] cull unnecessary files left from previous build setups +- [#5476](https://github.com/emberjs/data/pull/5476) [Feature] added module-unification adapter and adapter-test blueprints +- [#5508](https://github.com/emberjs/data/pull/5508) [CHORE] Update Dependencies + ### Release 3.3.1 (July 26, 2018) - [#5541](https://github.com/emberjs/data/pull/5541) [BUGFIX] backport fix for belongsTo proxy update From 52f30be0a53a4a8e37d99448376af7e120489a0f Mon Sep 17 00:00:00 2001 From: bmac Date: Mon, 27 Aug 2018 18:12:01 -0400 Subject: [PATCH 2319/2527] Bump package.json to 3.6.0-canary --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6d998d9ba94..a9d84eacdbf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "3.5.0-canary", + "version": "3.6.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From f5618a41dfb1ab17ac5ce66781bf9e4f9f1218e4 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 27 Aug 2018 15:14:17 -0700 Subject: [PATCH 2320/2527] [BUGFIX] Reference.reload should not cause sync-relationship assertion (#5582) * refactor reload tests and add tests for reference reloading * dont assert loaded state if reloading * only disable data integrity checks for the forced reload itself --- .../system/relationships/state/belongs-to.js | 10 +- .../system/relationships/state/has-many.js | 4 +- .../relationships/state/relationship.js | 2 +- .../relationships/belongs-to-test.js | 2 +- .../acceptance/relationships/has-many-test.js | 2 +- .../integration/records/create-record-test.js | 2 +- tests/integration/records/reload-test.js | 867 +++++++++++++----- 7 files changed, 675 insertions(+), 214 deletions(-) diff --git a/addon/-legacy-private/system/relationships/state/belongs-to.js b/addon/-legacy-private/system/relationships/state/belongs-to.js index a85df168cab..86af77eb11f 100644 --- a/addon/-legacy-private/system/relationships/state/belongs-to.js +++ b/addon/-legacy-private/system/relationships/state/belongs-to.js @@ -225,7 +225,13 @@ export default class BelongsToRelationship extends Relationship { }); } - getData() { + /* + While the `shouldForceReload` flag will also be true when `isForcedReload` is true, + `isForcedReload` is only `true` for an initial `getData` call during a forced reload. + Other calls must conform to the typical expectations, for instance, sync relationships + expect that their data is already loaded. + */ + getData(isForcedReload = false) { //TODO(Igor) flushCanonical here once our syncing is not stupid let record = this.inverseInternalModel ? this.inverseInternalModel.getRecord() : null; @@ -264,7 +270,7 @@ export default class BelongsToRelationship extends Relationship { "' with id " + this.internalModel.id + ' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)', - record === null || !record.get('isEmpty') + record === null || !record.get('isEmpty') || isForcedReload ); return record; } diff --git a/addon/-legacy-private/system/relationships/state/has-many.js b/addon/-legacy-private/system/relationships/state/has-many.js index 7a164d92958..c6b8449cb06 100755 --- a/addon/-legacy-private/system/relationships/state/has-many.js +++ b/addon/-legacy-private/system/relationships/state/has-many.js @@ -344,7 +344,7 @@ export default class ManyRelationship extends Relationship { }); } - getData() { + getData(isForcedReload = false) { //TODO(Igor) sync server here, once our syncing is not stupid let manyArray = this.manyArray; @@ -379,7 +379,7 @@ export default class ManyRelationship extends Relationship { }' with id ${ this.internalModel.id } but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (\`DS.hasMany({ async: true })\`)`, - this.allInverseRecordsAreLoaded + this.allInverseRecordsAreLoaded || isForcedReload ); return manyArray; diff --git a/addon/-legacy-private/system/relationships/state/relationship.js b/addon/-legacy-private/system/relationships/state/relationship.js index 77e26f374a6..2448ff392e9 100644 --- a/addon/-legacy-private/system/relationships/state/relationship.js +++ b/addon/-legacy-private/system/relationships/state/relationship.js @@ -554,7 +554,7 @@ export default class Relationship { this.setHasFailedLoadAttempt(false); this.setShouldForceReload(true); - this.getData(); + this.getData(true); return this._promiseProxy; } diff --git a/tests/acceptance/relationships/belongs-to-test.js b/tests/acceptance/relationships/belongs-to-test.js index afa9c6c8e86..f3b9c5cccb0 100644 --- a/tests/acceptance/relationships/belongs-to-test.js +++ b/tests/acceptance/relationships/belongs-to-test.js @@ -27,7 +27,7 @@ class TestAdapter extends JSONAPIAdapter { this._payloads = arr; } - shouldBackgroundReload() { + shouldBackgroundReloadRecord() { return false; } diff --git a/tests/acceptance/relationships/has-many-test.js b/tests/acceptance/relationships/has-many-test.js index dc40dc717f6..29ad420597a 100644 --- a/tests/acceptance/relationships/has-many-test.js +++ b/tests/acceptance/relationships/has-many-test.js @@ -31,7 +31,7 @@ class TestAdapter extends JSONAPIAdapter { this._payloads = arr; } - shouldBackgroundReload() { + shouldBackgroundReloadRecord() { return false; } diff --git a/tests/integration/records/create-record-test.js b/tests/integration/records/create-record-test.js index 51477ae2a9c..a063a7838c3 100644 --- a/tests/integration/records/create-record-test.js +++ b/tests/integration/records/create-record-test.js @@ -133,7 +133,7 @@ module('Store.createRecord() coverage', function(hooks) { this.owner.register( 'adapter:application', JSONAPIAdapter.extend({ - shouldBackgroundReload() { + shouldBackgroundReloadRecord() { return false; }, findRecord() { diff --git a/tests/integration/records/reload-test.js b/tests/integration/records/reload-test.js index e764cd4cb56..29318234f97 100644 --- a/tests/integration/records/reload-test.js +++ b/tests/integration/records/reload-test.js @@ -1,121 +1,103 @@ import { resolve, reject } from 'rsvp'; -import { run } from '@ember/runloop'; import { get } from '@ember/object'; -import setupStore from 'dummy/tests/helpers/store'; - +import { setupTest } from 'ember-qunit'; import { module, test } from 'qunit'; +import Store from 'ember-data/store'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; +import Model from 'ember-data/model'; +import { attr, belongsTo, hasMany } from '@ember-decorators/data'; + +module('integration/reload - Reloading Records', function(hooks) { + let store; + setupTest(hooks); + + hooks.beforeEach(function() { + class Person extends Model { + @attr + updatedAt; + @attr + name; + @attr + firstName; + @attr + lastName; + } -import DS from 'ember-data'; + let { owner } = this; + owner.register('service:store', Store); + owner.register('model:person', Person); + owner.register( + 'serializer:application', + JSONAPISerializer.extend({ + normalizeResponse(_, __, jsonApiPayload) { + return jsonApiPayload; + }, + }) + ); + store = owner.lookup('service:store'); + }); -var attr = DS.attr; -var Person, env; + test("When a single record is requested, the adapter's find method should be called unless it's loaded.", async function(assert) { + let count = 0; + let reloadOptions = { + adapterOptions: { + makeSnazzy: true, + }, + }; -module('integration/reload - Reloading Records', { - beforeEach() { - Person = DS.Model.extend({ - updatedAt: attr('string'), - name: attr('string'), - firstName: attr('string'), - lastName: attr('string'), - }); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + shouldBackgroundReloadRecord() { + return false; + }, - env = setupStore({ person: Person }); - }, + findRecord(store, type, id, snapshot) { + if (count === 0) { + count++; + return resolve({ data: { id: id, type: 'person', attributes: { name: 'Tom Dale' } } }); + } else if (count === 1) { + assert.equal( + snapshot.adapterOptions, + reloadOptions.adapterOptions, + 'We passed adapterOptions via reload' + ); + count++; + return resolve({ + data: { id: id, type: 'person', attributes: { name: 'Braaaahm Dale' } }, + }); + } else { + assert.ok(false, 'Should not get here'); + } + }, + }) + ); - afterEach() { - run(env.container, 'destroy'); - }, -}); + let person = await store.findRecord('person', '1'); -test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function(assert) { - var count = 0; - - env.adapter.findRecord = function(store, type, id, snapshot) { - if (count === 0) { - count++; - return resolve({ data: { id: id, type: 'person', attributes: { name: 'Tom Dale' } } }); - } else if (count === 1) { - count++; - return resolve({ data: { id: id, type: 'person', attributes: { name: 'Braaaahm Dale' } } }); - } else { - assert.ok(false, 'Should not get here'); - } - }; - - run(function() { - env.store - .findRecord('person', 1) - .then(function(person) { - assert.equal(get(person, 'name'), 'Tom Dale', 'The person is loaded with the right name'); - assert.equal(get(person, 'isLoaded'), true, 'The person is now loaded'); - var promise = person.reload(); - assert.equal(get(person, 'isReloading'), true, 'The person is now reloading'); - return promise; - }) - .then(function(person) { - assert.equal(get(person, 'isReloading'), false, 'The person is no longer reloading'); - assert.equal( - get(person, 'name'), - 'Braaaahm Dale', - 'The person is now updated with the right name' - ); - }); - }); -}); + assert.equal(get(person, 'name'), 'Tom Dale', 'The person is loaded with the right name'); + assert.equal(get(person, 'isLoaded'), true, 'The person is now loaded'); -test("When a single record is requested, the adapter's find method should be called unless it's loaded.", function(assert) { - let count = 0; - let reloadOptions = { - adapterOptions: { - makeSnazzy: true, - }, - }; - - env.adapter.findRecord = function(store, type, id, snapshot) { - if (count === 0) { - count++; - return resolve({ data: { id: id, type: 'person', attributes: { name: 'Tom Dale' } } }); - } else if (count === 1) { - assert.equal( - snapshot.adapterOptions, - reloadOptions.adapterOptions, - 'We passed adapterOptions via reload' - ); - count++; - return resolve({ data: { id: id, type: 'person', attributes: { name: 'Braaaahm Dale' } } }); - } else { - assert.ok(false, 'Should not get here'); - } - }; + let promise = person.reload(reloadOptions); - run(function() { - env.store - .findRecord('person', 1) - .then(function(person) { - assert.equal(get(person, 'name'), 'Tom Dale', 'The person is loaded with the right name'); - assert.equal(get(person, 'isLoaded'), true, 'The person is now loaded'); + assert.equal(get(person, 'isReloading'), true, 'The person is now reloading'); - let promise = person.reload(reloadOptions); + await promise; - assert.equal(get(person, 'isReloading'), true, 'The person is now reloading'); + assert.equal(get(person, 'isReloading'), false, 'The person is no longer reloading'); + assert.equal( + get(person, 'name'), + 'Braaaahm Dale', + 'The person is now updated with the right name' + ); - return promise; - }) - .then(function(person) { - assert.equal(get(person, 'isReloading'), false, 'The person is no longer reloading'); - assert.equal( - get(person, 'name'), - 'Braaaahm Dale', - 'The person is now updated with the right name' - ); - }); + // ensure we won't call adapter.findRecord again + await store.findRecord('person', '1'); }); -}); -test('When a record is reloaded and fails, it can try again', function(assert) { - var tom; - run(function() { - env.store.push({ + test('When a record is reloaded and fails, it can try again', async function(assert) { + let tom = store.push({ data: { type: 'person', id: '1', @@ -124,134 +106,607 @@ test('When a record is reloaded and fails, it can try again', function(assert) { }, }, }); - tom = env.store.peekRecord('person', 1); + let count = 0; + + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + shouldBackgroundReloadRecord() { + return true; + }, + + findRecord() { + assert.equal(tom.get('isReloading'), true, 'Tom is reloading'); + if (count++ === 0) { + return reject(); + } else { + return resolve({ + data: { id: 1, type: 'person', attributes: { name: 'Thomas Dale' } }, + }); + } + }, + }) + ); + + await tom.reload().catch(() => { + assert.ok(true, 'we throw an error'); + }); + + assert.equal(tom.get('isError'), true, 'Tom is now errored'); + assert.equal(tom.get('isReloading'), false, 'Tom is no longer reloading'); + + let person = await tom.reload(); + + assert.equal(person, tom, 'The resolved value is the record'); + assert.equal(tom.get('isError'), false, 'Tom is no longer errored'); + assert.equal(tom.get('isReloading'), false, 'Tom is no longer reloading'); + assert.equal(tom.get('name'), 'Thomas Dale', 'the updates apply'); }); - var count = 0; - env.adapter.findRecord = function(store, type, id, snapshot) { - assert.equal(tom.get('isReloading'), true, 'Tom is reloading'); - if (count++ === 0) { - return reject(); - } else { - return resolve({ data: { id: 1, type: 'person', attributes: { name: 'Thomas Dale' } } }); + test('When a record is loaded a second time, isLoaded stays true', async function(assert) { + assert.expect(3); + function getTomDale() { + return { + data: { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + }, + }; } - }; - - run(function() { - tom - .reload() - .then(null, function() { - assert.equal(tom.get('isError'), true, 'Tom is now errored'); - assert.equal(tom.get('isReloading'), false, 'Tom is no longer reloading'); - return tom.reload(); + + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + shouldBackgroundReloadRecord() { + return true; + }, + + findRecord(store, type, id, snapshot) { + assert.ok(true, 'We should call findRecord'); + return resolve(getTomDale()); + }, }) - .then(function(person) { - assert.equal(person, tom, 'The resolved value is the record'); - assert.equal(tom.get('isError'), false, 'Tom is no longer errored'); - assert.equal(tom.get('isReloading'), false, 'Tom is no longer reloading'); - assert.equal(tom.get('name'), 'Thomas Dale', 'the updates apply'); - }); + ); + + function isLoadedDidChange() { + // This observer should never fire + assert.ok(false, 'We should not trigger the isLoaded observer'); + // but if it does we should still have the same isLoaded state + assert.equal(get(this, 'isLoaded'), true, 'The person is still loaded after change'); + } + + store.push(getTomDale()); + + let person = await store.findRecord('person', '1'); + + person.addObserver('isLoaded', isLoadedDidChange); + assert.equal(get(person, 'isLoaded'), true, 'The person is loaded'); + + // Reload the record + store.push(getTomDale()); + + assert.equal(get(person, 'isLoaded'), true, 'The person is still loaded after load'); + + person.removeObserver('isLoaded', isLoadedDidChange); }); -}); -test('When a record is loaded a second time, isLoaded stays true', function(assert) { - let record = { - data: { - type: 'person', - id: '1', - attributes: { - name: 'Tom Dale', - }, - }, - }; - env.adapter.findRecord = function(store, type, id, snapshot) { - return record; - }; - run(function() { - env.store.push(record); + test('When a record is reloaded, its async hasMany relationships still work', async function(assert) { + class Person extends Model { + @attr + name; + @hasMany('tag', { async: true, inverse: null }) + tags; + } + class Tag extends Model { + @attr + name; + } + + this.owner.unregister('model:person'); + this.owner.register('model:person', Person); + this.owner.register('model:tag', Tag); + + let tagsById = { 1: 'hipster', 2: 'hair' }; + + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + shouldBackgroundReloadRecord() { + return false; + }, + + findRecord(store, type, id, snapshot) { + switch (type.modelName) { + case 'person': + return resolve({ + data: { + id: '1', + type: 'person', + attributes: { name: 'Tom' }, + relationships: { + tags: { + data: [{ id: '1', type: 'tag' }, { id: '2', type: 'tag' }], + }, + }, + }, + }); + case 'tag': + return resolve({ data: { id: id, type: 'tag', attributes: { name: tagsById[id] } } }); + } + }, + }) + ); + + let tom; + let person = await store.findRecord('person', '1'); + + tom = person; + assert.equal(person.get('name'), 'Tom', 'precond'); + + let tags = await person.get('tags'); + + assert.deepEqual(tags.mapBy('name'), ['hipster', 'hair']); + + person = await tom.reload(); + assert.equal(person.get('name'), 'Tom', 'precond'); + + tags = await person.get('tags'); + + assert.deepEqual(tags.mapBy('name'), ['hipster', 'hair'], 'The tags are still there'); }); - run(function() { - env.store.findRecord('person', 1).then(function(person) { - assert.equal(get(person, 'isLoaded'), true, 'The person is loaded'); - person.addObserver('isLoaded', isLoadedDidChange); + module('Reloading via relationship reference and { type, id }', function() { + test('When a sync belongsTo relationship has been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @belongsTo('person', { async: false, inverse: null }) + owner; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + assert.ok('We called findRecord'); + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + }); + }, + }) + ); + + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owner: { + data: { type: 'person', id: '1' }, + }, + }, + }, + included: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + ], + }); + + let ownerRef = shen.belongsTo('owner'); + let owner = shen.get('owner'); + let ownerViaRef = await ownerRef.reload(); + + assert.ok(owner === ownerViaRef, 'We received the same reference via reload'); + }); + + test('When a sync belongsTo relationship has not been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @belongsTo('person', { async: false, inverse: null }) + owner; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + assert.ok('We called findRecord'); + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + }); + }, + }) + ); + + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owner: { + data: { type: 'person', id: '1' }, + }, + }, + }, + }); + + let ownerRef = shen.belongsTo('owner'); + let ownerViaRef = await ownerRef.reload(); + let owner = shen.get('owner'); + + assert.ok(owner === ownerViaRef, 'We received the same reference via reload'); + }); + + test('When a sync hasMany relationship has been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @hasMany('person', { async: false, inverse: null }) + owners; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + assert.ok('We called findRecord'); + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + }); + }, + }) + ); + + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owners: { + data: [{ type: 'person', id: '1' }], + }, + }, + }, + included: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + ], + }); + + let ownersRef = shen.hasMany('owners'); + let owners = shen.get('owners'); + let ownersViaRef = await ownersRef.reload(); + + assert.ok( + owners.objectAt(0) === ownersViaRef.objectAt(0), + 'We received the same reference via reload' + ); + }); - // Reload the record - env.store.push(record); + test('When a sync hasMany relationship has not been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @hasMany('person', { async: false, inverse: null }) + owners; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findRecord() { + assert.ok('We called findRecord'); + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + }); + }, + }) + ); - assert.equal(get(person, 'isLoaded'), true, 'The person is still loaded after load'); + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owners: { + data: [{ type: 'person', id: '1' }], + }, + }, + }, + }); - person.removeObserver('isLoaded', isLoadedDidChange); + let ownersRef = shen.hasMany('owners'); + let ownersViaRef = await ownersRef.reload(); + let owners = shen.get('owners'); + + assert.ok( + owners.objectAt(0) === ownersViaRef.objectAt(0), + 'We received the same reference via reload' + ); }); }); - function isLoadedDidChange() { - // This shouldn't be hit - assert.equal(get(this, 'isLoaded'), true, 'The person is still loaded after change'); - } -}); + module('Reloading via relationship reference and links', function() { + test('When a sync belongsTo relationship has been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @belongsTo('person', { async: false, inverse: null }) + owner; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findBelongsTo() { + assert.ok('We called findRecord'); + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + }); + }, + }) + ); -test('When a record is reloaded, its async hasMany relationships still work', function(assert) { - env.registry.register( - 'model:person', - DS.Model.extend({ - name: DS.attr(), - tags: DS.hasMany('tag', { async: true }), - }) - ); - - env.registry.register( - 'model:tag', - DS.Model.extend({ - name: DS.attr(), - }) - ); - - var tags = { 1: 'hipster', 2: 'hair' }; - - env.adapter.findRecord = function(store, type, id, snapshot) { - switch (type.modelName) { - case 'person': - return resolve({ - data: { - id: 1, + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owner: { + data: { type: 'person', id: '1' }, + links: { + related: './owner', + }, + }, + }, + }, + included: [ + { type: 'person', - attributes: { name: 'Tom' }, - relationships: { - tags: { - data: [{ id: 1, type: 'tag' }, { id: 2, type: 'tag' }], + id: '1', + attributes: { + name: 'Chris', + }, + }, + ], + }); + + let ownerRef = shen.belongsTo('owner'); + let owner = shen.get('owner'); + let ownerViaRef = await ownerRef.reload(); + + assert.ok(owner === ownerViaRef, 'We received the same reference via reload'); + }); + + test('When a sync belongsTo relationship has not been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @belongsTo('person', { async: false, inverse: null }) + owner; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findBelongsTo() { + assert.ok('We called findRecord'); + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + }); + }, + }) + ); + + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owner: { + data: { type: 'person', id: '1' }, + links: { + related: './owner', }, }, }, - }); - case 'tag': - return resolve({ data: { id: id, type: 'tag', attributes: { name: tags[id] } } }); - } - }; + }, + }); - var tom; + let ownerRef = shen.belongsTo('owner'); + let ownerViaRef = await ownerRef.reload(); + let owner = shen.get('owner'); - run(function() { - env.store - .findRecord('person', 1) - .then(function(person) { - tom = person; - assert.equal(person.get('name'), 'Tom', 'precond'); + assert.ok(owner === ownerViaRef, 'We received the same reference via reload'); + }); - return person.get('tags'); - }) - .then(function(tags) { - assert.deepEqual(tags.mapBy('name'), ['hipster', 'hair']); + test('When a sync hasMany relationship has been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @hasMany('person', { async: false, inverse: null }) + owners; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findHasMany() { + assert.ok('We called findRecord'); + return resolve({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + ], + }); + }, + }) + ); - return tom.reload(); - }) - .then(function(person) { - assert.equal(person.get('name'), 'Tom', 'precond'); + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owners: { + data: [{ type: 'person', id: '1' }], + links: { + related: './owners', + }, + }, + }, + }, + included: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + ], + }); - return person.get('tags'); - }) - .then(function(tags) { - assert.deepEqual(tags.mapBy('name'), ['hipster', 'hair'], 'The tags are still there'); + let ownersRef = shen.hasMany('owners'); + let owners = shen.get('owners'); + let ownersViaRef = await ownersRef.reload(); + + assert.ok( + owners.objectAt(0) === ownersViaRef.objectAt(0), + 'We received the same reference via reload' + ); + }); + + test('When a sync hasMany relationship has not been loaded, it can still be reloaded via the reference', async function(assert) { + assert.expect(2); + class Pet extends Model { + @hasMany('person', { async: false, inverse: null }) + owners; + @attr + name; + } + + this.owner.register('model:pet', Pet); + this.owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + findHasMany() { + assert.ok('We called findRecord'); + return resolve({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Chris', + }, + }, + ], + }); + }, + }) + ); + + let shen = store.push({ + data: { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owners: { + data: [{ type: 'person', id: '1' }], + links: { + related: './owners', + }, + }, + }, + }, }); + + let ownersRef = shen.hasMany('owners'); + let ownersViaRef = await ownersRef.reload(); + let owners = shen.get('owners'); + + assert.ok( + owners.objectAt(0) === ownersViaRef.objectAt(0), + 'We received the same reference via reload' + ); + }); }); }); From 98215edd29173491060ca90748a479729765d236 Mon Sep 17 00:00:00 2001 From: Sivakumar Kailasam Date: Tue, 28 Aug 2018 10:15:24 +0530 Subject: [PATCH 2321/2527] Publish docs to npm (#5602) * Publish yuidoc json file to npm * Remove the build step that publishes docs to s3 --- .npmignore | 7 +++- .travis.yml | 1 - bin/publish-builds | 8 ---- bin/publish-to-s3.js | 21 ---------- config/s3ProjectConfig.js | 49 ---------------------- package.json | 1 - yarn.lock | 86 +-------------------------------------- 7 files changed, 8 insertions(+), 165 deletions(-) delete mode 100755 bin/publish-builds delete mode 100755 bin/publish-to-s3.js delete mode 100644 config/s3ProjectConfig.js diff --git a/.npmignore b/.npmignore index f7a501ab832..364e1202de9 100644 --- a/.npmignore +++ b/.npmignore @@ -1,6 +1,5 @@ /bower_components /config/ember-try.js -/dist /node-tests /tests /tmp @@ -8,6 +7,12 @@ /docs /.node_modules.ember-try +# Ignore all assets except /dist/docs folder +/dist/assets/ +/dist/crossdomain.xml +/dist/index.html +/dist/robots.txt + **/.gitkeep .appveyor.yml .bowerrc diff --git a/.travis.yml b/.travis.yml index a3b694cf20a..928d33cc3e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -101,7 +101,6 @@ jobs: script: - node_modules/.bin/ember try:reset - yarn build:production - - "./bin/publish-builds" before_install: diff --git a/bin/publish-builds b/bin/publish-builds deleted file mode 100755 index 6d23a328c40..00000000000 --- a/bin/publish-builds +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -echo -e "CURRENT_BRANCH: ${TRAVIS_BRANCH}\n" -echo -e "PULL_REQUEST: ${TRAVIS_PULL_REQUEST}\n" - -if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then - node ./bin/publish-to-s3.js -fi diff --git a/bin/publish-to-s3.js b/bin/publish-to-s3.js deleted file mode 100755 index 80d9b39d07b..00000000000 --- a/bin/publish-to-s3.js +++ /dev/null @@ -1,21 +0,0 @@ -// This publish script remains in order to publish the yui-docs to S3, builds no -// longer need to be published to S3. -// -// To invoke this from the commandline you need the following to env vars to exist: -// -// S3_BUCKET_NAME -// TRAVIS_BRANCH -// TRAVIS_TAG -// TRAVIS_COMMIT -// S3_SECRET_ACCESS_KEY -// S3_ACCESS_KEY_ID -// -// Once you have those you execute with the following: -// -// ```sh -// ./bin/publish_to_s3.js -// ``` -var S3Publisher = require('ember-publisher'); -var configPath = require('path').join(__dirname, '../config/s3ProjectConfig.js'); -var publisher = new S3Publisher({ projectConfigPath: configPath }); -publisher.publish(); diff --git a/config/s3ProjectConfig.js b/config/s3ProjectConfig.js deleted file mode 100644 index 40f5e770d64..00000000000 --- a/config/s3ProjectConfig.js +++ /dev/null @@ -1,49 +0,0 @@ -function fileMap(revision, tag, date) { - return { - 'docs/data.json': fileObject( - 'ember-data-docs', - '.json', - 'application/json', - revision, - tag, - date - ), - }; -} - -function fileObject(baseName, extension, contentType, currentRevision, tag, date) { - var fullName = '/' + baseName + extension; - var obj = { - contentType: contentType, - destinations: { - canary: [ - 'latest' + fullName, - 'canary' + fullName, - 'canary/daily/' + date + fullName, - 'canary/shas/' + currentRevision + fullName, - ], - release: [ - 'stable' + fullName, - 'release' + fullName, - 'release/daily/' + date + fullName, - 'release/shas/' + currentRevision + fullName, - ], - beta: [ - 'beta' + fullName, - 'beta/daily/' + date + fullName, - 'beta/shas/' + currentRevision + fullName, - ], - wildcard: [], - }, - }; - - if (tag) { - for (var key in obj.destinations) { - obj.destinations[key].push('tags/' + tag + fullName); - } - } - - return obj; -} - -module.exports = fileMap; diff --git a/package.json b/package.json index a9d84eacdbf..dae39bd2376 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,6 @@ "ember-export-application-global": "^2.0.0", "ember-load-initializers": "^1.1.0", "ember-maybe-import-regenerator": "^0.1.6", - "ember-publisher": "0.0.7", "ember-qunit": "^3.4.1", "ember-qunit-assert-helpers": "^0.2.1", "ember-resolver": "^5.0.1", diff --git a/yarn.lock b/yarn.lock index ed542ce154f..cc11aa4d775 100644 --- a/yarn.lock +++ b/yarn.lock @@ -442,20 +442,6 @@ atob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" -aws-sdk@^2.0.9: - version "2.279.1" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.279.1.tgz#3a4fd4167932e4361dbdcfcb174ce4840ffcbf20" - dependencies: - buffer "4.9.1" - events "1.1.1" - ieee754 "1.1.8" - jmespath "0.15.0" - querystring "0.2.0" - sax "1.2.1" - url "0.10.3" - uuid "3.1.0" - xml2js "0.4.19" - aws-sign2@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" @@ -1026,10 +1012,6 @@ base64-js@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.2.tgz#024f0f72afa25b75f9c0ee73cd4f55ec1bed9784" -base64-js@^1.0.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" - base64id@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" @@ -1656,14 +1638,6 @@ buffer-from@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" -buffer@4.9.1: - version "4.9.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -2738,12 +2712,6 @@ ember-maybe-import-regenerator@^0.1.6: ember-cli-babel "^6.0.0-beta.4" regenerator-runtime "^0.9.5" -ember-publisher@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ember-publisher/-/ember-publisher-0.0.7.tgz#865ca69ef47bafb38120a84244aa58b950ca4850" - dependencies: - aws-sdk "^2.0.9" - ember-qunit-assert-helpers@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ember-qunit-assert-helpers/-/ember-qunit-assert-helpers-0.2.1.tgz#4a77f8ff252e47cc53db6fa7fb4becb426de8d29" @@ -3137,10 +3105,6 @@ events-to-array@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" -events@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" - exec-file-sync@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/exec-file-sync/-/exec-file-sync-2.0.2.tgz#58d441db46e40de6d1f30de5be022785bd89e328" @@ -4137,14 +4101,6 @@ iconv-lite@^0.4.13, iconv-lite@^0.4.17, iconv-lite@^0.4.4: dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" - -ieee754@^1.1.4: - version "1.1.12" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" - ignore-walk@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" @@ -4500,7 +4456,7 @@ isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: +isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -4545,10 +4501,6 @@ jest-docblock@^21.0.0: version "21.2.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" -jmespath@0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" - jquery@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" @@ -5937,10 +5889,6 @@ psl@^1.1.24: version "1.1.28" resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.28.tgz#4fb6ceb08a1e2214d4fd4de0ca22dae13740bc7b" -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -5969,10 +5917,6 @@ query-string@^5.0.1: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - quibble@^0.5.5: version "0.5.5" resolved "https://registry.yarnpkg.com/quibble/-/quibble-0.5.5.tgz#669fb731520a923e0a98f8076b7eb55e409f73f9" @@ -6423,11 +6367,7 @@ sane@^2.2.0, sane@^2.4.1: optionalDependencies: fsevents "^1.2.3" -sax@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" - -sax@>=0.6.0, sax@^1.2.4: +sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -7246,13 +7186,6 @@ url-to-options@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" -url@0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" - dependencies: - punycode "1.3.2" - querystring "0.2.0" - use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" @@ -7283,10 +7216,6 @@ utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" -uuid@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" - uuid@^3.0.0: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" @@ -7430,17 +7359,6 @@ xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" -xml2js@0.4.19: - version "0.4.19" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" - dependencies: - sax ">=0.6.0" - xmlbuilder "~9.0.1" - -xmlbuilder@~9.0.1: - version "9.0.7" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" - xmldom@^0.1.19: version "0.1.27" resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" From 402ce0ec79cbbaed96d2c4cb1316ab592780cb55 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 28 Aug 2018 09:45:04 -0700 Subject: [PATCH 2322/2527] [BUGFIX] use xhr.textStatus not xhr.statusText --- addon/adapters/rest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index c4cb3eb0d2c..d5c25a003b9 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1269,7 +1269,7 @@ function ajaxErrorHandler(adapter, jqXHR, errorThrown, requestData) { function ajaxResponseData(jqXHR) { return { status: jqXHR.status, - textStatus: jqXHR.textStatus, + textStatus: jqXHR.statusText, headers: parseResponseHeaders(jqXHR.getAllResponseHeaders()), }; } From bee48f0d763f9451b98d6b28e977255ab116ede6 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 28 Aug 2018 13:04:50 -0700 Subject: [PATCH 2323/2527] [FEAT] assert when methods are called on a destroyed store instance --- addon/-legacy-private/system/store.js | 207 ++++++++++++++++----- addon/-record-data-private/system/store.js | 126 ++++++++++++- tests/unit/store/asserts-test.js | 140 +++++++++++--- 3 files changed, 385 insertions(+), 88 deletions(-) diff --git a/addon/-legacy-private/system/store.js b/addon/-legacy-private/system/store.js index 919e158d39c..240cba1e94c 100644 --- a/addon/-legacy-private/system/store.js +++ b/addon/-legacy-private/system/store.js @@ -352,6 +352,9 @@ Store = Service.extend({ @return {DS.Model} record */ createRecord(modelName, inputProperties) { + if (DEBUG) { + assertDestroyingStore(this, 'createRecord'); + } assert( `You need to pass a model name to the store's createRecord method`, isPresent(modelName) @@ -432,6 +435,9 @@ Store = Service.extend({ @param {DS.Model} record */ deleteRecord(record) { + if (DEBUG) { + assertDestroyingStore(this, 'deleteRecord'); + } record.deleteRecord(); }, @@ -451,6 +457,9 @@ Store = Service.extend({ @param {DS.Model} record */ unloadRecord(record) { + if (DEBUG) { + assertDestroyingStore(this, 'unloadRecord'); + } record.unloadRecord(); }, @@ -467,6 +476,9 @@ Store = Service.extend({ @private */ find(modelName, id, options) { + if (DEBUG) { + assertDestroyingStore(this, 'find'); + } // The default `model` hook in Route calls `find(modelName, id)`, // that's why we have to keep this method around even though `findRecord` is // the public way to get a record by modelName and id. @@ -720,6 +732,9 @@ Store = Service.extend({ @return {Promise} promise */ findRecord(modelName, id, options) { + if (DEBUG) { + assertDestroyingStore(this, 'findRecord'); + } assert(`You need to pass a model name to the store's findRecord method`, isPresent(modelName)); assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, @@ -811,6 +826,9 @@ Store = Service.extend({ @return {Promise} promise */ findByIds(modelName, ids) { + if (DEBUG) { + assertDestroyingStore(this, 'findByIds'); + } assert(`You need to pass a model name to the store's findByIds method`, isPresent(modelName)); assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, @@ -1102,6 +1120,9 @@ Store = Service.extend({ @return {RecordReference} */ getReference(modelName, id) { + if (DEBUG) { + assertDestroyingStore(this, 'getReference'); + } let normalizedModelName = normalizeModelName(modelName); return this._internalModelForId(normalizedModelName, id).recordReference; @@ -1131,6 +1152,9 @@ Store = Service.extend({ @return {DS.Model|null} record */ peekRecord(modelName, id) { + if (DEBUG) { + assertDestroyingStore(this, 'peekRecord'); + } heimdall.increment(peekRecord); assert(`You need to pass a model name to the store's peekRecord method`, isPresent(modelName)); assert( @@ -1197,6 +1221,9 @@ Store = Service.extend({ @return {Boolean} */ hasRecordForId(modelName, id) { + if (DEBUG) { + assertDestroyingStore(this, 'hasRecordForId'); + } assert( `You need to pass a model name to the store's hasRecordForId method`, isPresent(modelName) @@ -1225,6 +1252,9 @@ Store = Service.extend({ @return {DS.Model} record */ recordForId(modelName, id) { + if (DEBUG) { + assertDestroyingStore(this, 'recordForId'); + } assert(`You need to pass a model name to the store's recordForId method`, isPresent(modelName)); assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, @@ -1275,6 +1305,9 @@ Store = Service.extend({ @return {Promise} promise */ findMany(internalModels) { + if (DEBUG) { + assertDestroyingStore(this, 'findMany'); + } let finds = new Array(internalModels.length); for (let i = 0; i < internalModels.length; i++) { @@ -1303,6 +1336,9 @@ Store = Service.extend({ @return {Promise} promise */ findHasMany(internalModel, link, relationship) { + if (DEBUG) { + assertDestroyingStore(this, 'findHasMany'); + } let adapter = this.adapterFor(internalModel.modelName); assert( @@ -1328,6 +1364,9 @@ Store = Service.extend({ @return {Promise} promise */ findBelongsTo(internalModel, link, relationship) { + if (DEBUG) { + assertDestroyingStore(this, 'findBelongsTo'); + } let adapter = this.adapterFor(internalModel.modelName); assert( @@ -1398,6 +1437,9 @@ Store = Service.extend({ @return {Promise} promise */ query(modelName, query, options) { + if (DEBUG) { + assertDestroyingStore(this, 'query'); + } assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); assert(`You need to pass a query hash to the store's query method`, query); assert( @@ -1544,6 +1586,9 @@ Store = Service.extend({ @return {Promise} promise which resolves with the found record or `null` */ queryRecord(modelName, query, options) { + if (DEBUG) { + assertDestroyingStore(this, 'queryRecord'); + } assert(`You need to pass a model name to the store's queryRecord method`, isPresent(modelName)); assert(`You need to pass a query hash to the store's queryRecord method`, query); assert( @@ -1770,6 +1815,9 @@ Store = Service.extend({ @return {Promise} promise */ findAll(modelName, options) { + if (DEBUG) { + assertDestroyingStore(this, 'findAll'); + } assert(`You need to pass a model name to the store's findAll method`, isPresent(modelName)); assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, @@ -1865,6 +1913,9 @@ Store = Service.extend({ @return {DS.RecordArray} */ peekAll(modelName) { + if (DEBUG) { + assertDestroyingStore(this, 'peekAll'); + } heimdall.increment(peekAll); assert(`You need to pass a model name to the store's peekAll method`, isPresent(modelName)); assert( @@ -1890,6 +1941,9 @@ Store = Service.extend({ @param {String} modelName */ unloadAll(modelName) { + if (DEBUG) { + assertDestroyedStoreOnly(this, 'unloadAll'); + } assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, !modelName || typeof modelName === 'string' @@ -1985,6 +2039,9 @@ Store = Service.extend({ @param {Object} data optional data (see above) */ didSaveRecord(internalModel, dataArg) { + if (DEBUG) { + assertDestroyingStore(this, 'didSaveRecord'); + } let data; if (dataArg) { data = dataArg.data; @@ -2018,6 +2075,9 @@ Store = Service.extend({ @param {Object} errors */ recordWasInvalid(internalModel, errors) { + if (DEBUG) { + assertDestroyingStore(this, 'recordWasInvalid'); + } internalModel.adapterDidInvalidate(errors); }, @@ -2032,6 +2092,9 @@ Store = Service.extend({ @param {Error} error */ recordWasError(internalModel, error) { + if (DEBUG) { + assertDestroyingStore(this, 'recordWasError'); + } internalModel.adapterDidError(error); }, @@ -2046,6 +2109,9 @@ Store = Service.extend({ @param {Object} data */ updateId(internalModel, data) { + if (DEBUG) { + assertDestroyingStore(this, 'updateId'); + } let oldId = internalModel.id; let modelName = internalModel.modelName; let id = coerceId(data.id); @@ -2165,6 +2231,9 @@ Store = Service.extend({ @return {DS.Model} */ modelFor(modelName) { + if (DEBUG) { + assertDestroyedStoreOnly(this, 'modelFor'); + } assert(`You need to pass a model name to the store's modelFor method`, isPresent(modelName)); assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, @@ -2190,6 +2259,9 @@ Store = Service.extend({ }, _modelFactoryFor(modelName) { + if (DEBUG) { + assertDestroyedStoreOnly(this, '_modelFactoryFor'); + } assert( `You need to pass a model name to the store's _modelFactoryFor method`, isPresent(modelName) @@ -2232,6 +2304,9 @@ Store = Service.extend({ @private */ _hasModelFor(modelName) { + if (DEBUG) { + assertDestroyingStore(this, '_hasModelFor'); + } assert(`You need to pass a model name to the store's hasModelFor method`, isPresent(modelName)); assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, @@ -2394,6 +2469,9 @@ Store = Service.extend({ updated. */ push(data) { + if (DEBUG) { + assertDestroyingStore(this, 'push'); + } let token = heimdall.start('store.push'); let pushed = this._push(data); @@ -2423,6 +2501,9 @@ Store = Service.extend({ @return {DS.InternalModel|Array} pushed InternalModel(s) */ _push(jsonApiDoc) { + if (DEBUG) { + assertDestroyingStore(this, '_push'); + } let token = heimdall.start('store._push'); let internalModelOrModels = this._backburner.join(() => { let included = jsonApiDoc.included; @@ -2601,11 +2682,14 @@ Store = Service.extend({ @param {Object} inputPayload */ pushPayload(modelName, inputPayload) { + if (DEBUG) { + assertDestroyingStore(this, 'pushPayload'); + } let serializer; let payload; if (!inputPayload) { payload = modelName; - serializer = defaultSerializer(this); + serializer = this.serializerFor('application'); assert( `You cannot use 'store#pushPayload' without a modelName unless your default serializer defines 'pushPayload'`, typeof serializer.pushPayload === 'function' @@ -2642,6 +2726,9 @@ Store = Service.extend({ @return {Object} The normalized payload */ normalize(modelName, payload) { + if (DEBUG) { + assertDestroyingStore(this, 'normalize'); + } heimdall.increment(normalize); assert(`You need to pass a model name to the store's normalize method`, isPresent(modelName)); assert( @@ -2709,6 +2796,9 @@ Store = Service.extend({ //Called by the state machine to notify the store that the record is ready to be interacted with recordWasLoaded(record) { + if (DEBUG) { + assertDestroyingStore(this, 'recordWasLoaded'); + } this.recordArrayManager.recordWasLoaded(record); }, @@ -2753,6 +2843,9 @@ Store = Service.extend({ @return DS.Adapter */ adapterFor(modelName) { + if (DEBUG) { + assertDestroyingStore(this, 'adapterFor'); + } heimdall.increment(adapterFor); assert(`You need to pass a model name to the store's adapterFor method`, isPresent(modelName)); assert( @@ -2831,6 +2924,9 @@ Store = Service.extend({ @return {DS.Serializer} */ serializerFor(modelName) { + if (DEBUG) { + assertDestroyingStore(this, 'serializerFor'); + } heimdall.increment(serializerFor); assert( `You need to pass a model name to the store's serializerFor method`, @@ -2967,12 +3063,14 @@ Store = Service.extend({ if (isNone(resourceIdentifier)) { return; } - assertRelationshipData( - this, - relationship.internalModel, - resourceIdentifier, - relationship.relationshipMeta - ); + if (DEBUG) { + assertRelationshipData( + this, + relationship.internalModel, + resourceIdentifier, + relationship.relationshipMeta + ); + } return this._internalModelForId(resourceIdentifier.type, resourceIdentifier.id); }, @@ -3001,12 +3099,6 @@ Store = Service.extend({ }, }); -// Delegation to the adapter and promise management - -function defaultSerializer(store) { - return store.serializerFor('application'); -} - function _commit(adapter, store, operation, snapshot) { let internalModel = snapshot._internalModel; let modelName = snapshot.modelName; @@ -3280,42 +3372,59 @@ function setupRelationships(store, internalModel, data, modelNameToInverseMap) { }); } -function assertRelationshipData(store, internalModel, data, meta) { - assert( - `A ${internalModel.modelName} record was pushed into the store with the value of ${ - meta.key - } being '${JSON.stringify(data)}', but ${ - meta.key - } is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, - !Array.isArray(data) - ); - assert( - `Encountered a relationship identifier without a type for the ${meta.kind} relationship '${ - meta.key - }' on ${internalModel}, expected a json-api identifier with type '${ - meta.type - }' but found '${JSON.stringify( - data - )}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, - data === null || (typeof data.type === 'string' && data.type.length) - ); - assert( - `Encountered a relationship identifier without an id for the ${meta.kind} relationship '${ - meta.key - }' on ${internalModel}, expected a json-api identifier but found '${JSON.stringify( - data - )}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, - data === null || coerceId(data.id) - ); - assert( - `Encountered a relationship identifier with type '${data.type}' for the ${ - meta.kind - } relationship '${meta.key}' on ${internalModel}, Expected a json-api identifier with type '${ - meta.type - }'. No model was found for '${data.type}'.`, - data === null || !data.type || store._hasModelFor(data.type) - ); +let assertRelationshipData; +let assertDestroyingStore; +let assertDestroyedStoreOnly; + +if (DEBUG) { + assertRelationshipData = function assertRelationshipData(store, internalModel, data, meta) { + assert( + `A ${internalModel.modelName} record was pushed into the store with the value of ${ + meta.key + } being '${JSON.stringify(data)}', but ${ + meta.key + } is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, + !Array.isArray(data) + ); + assert( + `Encountered a relationship identifier without a type for the ${meta.kind} relationship '${ + meta.key + }' on ${internalModel}, expected a json-api identifier with type '${ + meta.type + }' but found '${JSON.stringify( + data + )}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, + data === null || (typeof data.type === 'string' && data.type.length) + ); + assert( + `Encountered a relationship identifier without an id for the ${meta.kind} relationship '${ + meta.key + }' on ${internalModel}, expected a json-api identifier but found '${JSON.stringify( + data + )}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, + data === null || coerceId(data.id) + ); + assert( + `Encountered a relationship identifier with type '${data.type}' for the ${ + meta.kind + } relationship '${meta.key}' on ${internalModel}, Expected a json-api identifier with type '${ + meta.type + }'. No model was found for '${data.type}'.`, + data === null || !data.type || store._hasModelFor(data.type) + ); + }; + assertDestroyingStore = function assertDestroyedStore(store, method) { + assert( + `Attempted to call store.${method}(), but the store instance has already been destroyed.`, + !(store.isDestroying || store.isDestroyed) + ); + }; + assertDestroyedStoreOnly = function assertDestroyedStoreOnly(store, method) { + assert( + `Attempted to call store.${method}(), but the store instance has already been destroyed.`, + !store.isDestroyed + ); + }; } -export { Store }; export default Store; diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index a6afccd6c46..0edac2fcca5 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -358,6 +358,9 @@ Store = Service.extend({ @return {DS.Model} record */ createRecord(modelName, inputProperties) { + if (DEBUG) { + assertDestroyingStore(this, 'createRecord'); + } assert( `You need to pass a model name to the store's createRecord method`, isPresent(modelName) @@ -441,6 +444,9 @@ Store = Service.extend({ @param {DS.Model} record */ deleteRecord(record) { + if (DEBUG) { + assertDestroyingStore(this, 'deleteRecord'); + } record.deleteRecord(); }, @@ -460,6 +466,9 @@ Store = Service.extend({ @param {DS.Model} record */ unloadRecord(record) { + if (DEBUG) { + assertDestroyingStore(this, 'unloadRecord'); + } record.unloadRecord(); }, @@ -476,6 +485,9 @@ Store = Service.extend({ @private */ find(modelName, id, options) { + if (DEBUG) { + assertDestroyingStore(this, 'find'); + } // The default `model` hook in Route calls `find(modelName, id)`, // that's why we have to keep this method around even though `findRecord` is // the public way to get a record by modelName and id. @@ -730,6 +742,9 @@ Store = Service.extend({ @return {Promise} promise */ findRecord(modelName, id, options) { + if (DEBUG) { + assertDestroyingStore(this, 'findRecord'); + } assert(`You need to pass a model name to the store's findRecord method`, isPresent(modelName)); assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, @@ -821,6 +836,9 @@ Store = Service.extend({ @return {Promise} promise */ findByIds(modelName, ids) { + if (DEBUG) { + assertDestroyingStore(this, 'findByIds'); + } assert(`You need to pass a model name to the store's findByIds method`, isPresent(modelName)); assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, @@ -1112,6 +1130,9 @@ Store = Service.extend({ @return {RecordReference} */ getReference(modelName, id) { + if (DEBUG) { + assertDestroyingStore(this, 'getReference'); + } let normalizedModelName = normalizeModelName(modelName); return this._internalModelForId(normalizedModelName, id).recordReference; @@ -1141,6 +1162,9 @@ Store = Service.extend({ @return {DS.Model|null} record */ peekRecord(modelName, id) { + if (DEBUG) { + assertDestroyingStore(this, 'peekRecord'); + } heimdall.increment(peekRecord); assert(`You need to pass a model name to the store's peekRecord method`, isPresent(modelName)); assert( @@ -1207,6 +1231,9 @@ Store = Service.extend({ @return {Boolean} */ hasRecordForId(modelName, id) { + if (DEBUG) { + assertDestroyingStore(this, 'hasRecordForId'); + } assert( `You need to pass a model name to the store's hasRecordForId method`, isPresent(modelName) @@ -1235,6 +1262,9 @@ Store = Service.extend({ @return {DS.Model} record */ recordForId(modelName, id) { + if (DEBUG) { + assertDestroyingStore(this, 'recordForId'); + } assert(`You need to pass a model name to the store's recordForId method`, isPresent(modelName)); assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, @@ -1287,6 +1317,9 @@ Store = Service.extend({ @return {Promise} promise */ findMany(internalModels) { + if (DEBUG) { + assertDestroyingStore(this, 'findMany'); + } let finds = new Array(internalModels.length); for (let i = 0; i < internalModels.length; i++) { @@ -1315,6 +1348,9 @@ Store = Service.extend({ @return {Promise} promise */ findHasMany(internalModel, link, relationship) { + if (DEBUG) { + assertDestroyingStore(this, 'findHasMany'); + } let adapter = this.adapterFor(internalModel.modelName); assert( @@ -1409,6 +1445,9 @@ Store = Service.extend({ @return {Promise} promise */ findBelongsTo(internalModel, link, relationship) { + if (DEBUG) { + assertDestroyingStore(this, 'findBelongsTo'); + } let adapter = this.adapterFor(internalModel.modelName); assert( @@ -1566,6 +1605,9 @@ Store = Service.extend({ @return {Promise} promise */ query(modelName, query, options) { + if (DEBUG) { + assertDestroyingStore(this, 'query'); + } assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); assert(`You need to pass a query hash to the store's query method`, query); assert( @@ -1712,6 +1754,9 @@ Store = Service.extend({ @return {Promise} promise which resolves with the found record or `null` */ queryRecord(modelName, query, options) { + if (DEBUG) { + assertDestroyingStore(this, 'queryRecord'); + } assert(`You need to pass a model name to the store's queryRecord method`, isPresent(modelName)); assert(`You need to pass a query hash to the store's queryRecord method`, query); assert( @@ -1938,6 +1983,9 @@ Store = Service.extend({ @return {Promise} promise */ findAll(modelName, options) { + if (DEBUG) { + assertDestroyingStore(this, 'findAll'); + } assert(`You need to pass a model name to the store's findAll method`, isPresent(modelName)); assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, @@ -2034,6 +2082,9 @@ Store = Service.extend({ */ peekAll(modelName) { heimdall.increment(peekAll); + if (DEBUG) { + assertDestroyingStore(this, 'peekAll'); + } assert(`You need to pass a model name to the store's peekAll method`, isPresent(modelName)); assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, @@ -2058,6 +2109,9 @@ Store = Service.extend({ @param {String} modelName */ unloadAll(modelName) { + if (DEBUG) { + assertDestroyedStoreOnly(this, 'unloadAll'); + } assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, !modelName || typeof modelName === 'string' @@ -2152,6 +2206,9 @@ Store = Service.extend({ @param {Object} data optional data (see above) */ didSaveRecord(internalModel, dataArg) { + if (DEBUG) { + assertDestroyingStore(this, 'didSaveRecord'); + } let data; if (dataArg) { data = dataArg.data; @@ -2181,6 +2238,9 @@ Store = Service.extend({ @param {Object} errors */ recordWasInvalid(internalModel, errors) { + if (DEBUG) { + assertDestroyingStore(this, 'recordWasInvalid'); + } internalModel.adapterDidInvalidate(errors); }, @@ -2195,6 +2255,9 @@ Store = Service.extend({ @param {Error} error */ recordWasError(internalModel, error) { + if (DEBUG) { + assertDestroyingStore(this, 'recordWasError'); + } internalModel.adapterDidError(error); }, @@ -2215,6 +2278,9 @@ Store = Service.extend({ }, updateId(internalModel, data) { + if (DEBUG) { + assertDestroyingStore(this, 'updateId'); + } deprecate('store.updateId was documented as private and will be removed.', false, { id: 'ds.store.updateId', until: '3.5', @@ -2223,6 +2289,9 @@ Store = Service.extend({ }, _setRecordId(internalModel, id, clientId) { + if (DEBUG) { + assertDestroyingStore(this, 'setRecordId'); + } let oldId = internalModel.id; let modelName = internalModel.modelName; @@ -2346,6 +2415,9 @@ Store = Service.extend({ @return {DS.Model} */ modelFor(modelName) { + if (DEBUG) { + assertDestroyedStoreOnly(this, 'modelFor'); + } assert(`You need to pass a model name to the store's modelFor method`, isPresent(modelName)); assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, @@ -2371,6 +2443,9 @@ Store = Service.extend({ }, _modelFactoryFor(modelName) { + if (DEBUG) { + assertDestroyedStoreOnly(this, '_modelFactoryFor'); + } assert( `You need to pass a model name to the store's _modelFactoryFor method`, isPresent(modelName) @@ -2413,6 +2488,9 @@ Store = Service.extend({ @private */ _hasModelFor(modelName) { + if (DEBUG) { + assertDestroyingStore(this, '_hasModelFor'); + } assert(`You need to pass a model name to the store's hasModelFor method`, isPresent(modelName)); assert( `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, @@ -2575,6 +2653,9 @@ Store = Service.extend({ updated. */ push(data) { + if (DEBUG) { + assertDestroyingStore(this, 'push'); + } let token = heimdall.start('store.push'); let pushed = this._push(data); @@ -2604,6 +2685,9 @@ Store = Service.extend({ @return {DS.InternalModel|Array} pushed InternalModel(s) */ _push(jsonApiDoc) { + if (DEBUG) { + assertDestroyingStore(this, '_push'); + } let token = heimdall.start('store._push'); let internalModelOrModels = this._backburner.join(() => { let included = jsonApiDoc.included; @@ -2745,11 +2829,14 @@ Store = Service.extend({ @param {Object} inputPayload */ pushPayload(modelName, inputPayload) { + if (DEBUG) { + assertDestroyingStore(this, 'pushPayload'); + } let serializer; let payload; if (!inputPayload) { payload = modelName; - serializer = defaultSerializer(this); + serializer = this.serializerFor('application'); assert( `You cannot use 'store#pushPayload' without a modelName unless your default serializer defines 'pushPayload'`, typeof serializer.pushPayload === 'function' @@ -2856,6 +2943,9 @@ Store = Service.extend({ @return {Object} The normalized payload */ normalize(modelName, payload) { + if (DEBUG) { + assertDestroyingStore(this, 'normalize'); + } heimdall.increment(normalize); assert(`You need to pass a model name to the store's normalize method`, isPresent(modelName)); assert( @@ -2932,6 +3022,9 @@ Store = Service.extend({ //Called by the state machine to notify the store that the record is ready to be interacted with recordWasLoaded(record) { + if (DEBUG) { + assertDestroyingStore(this, 'recordWasLoaded'); + } this.recordArrayManager.recordWasLoaded(record); }, @@ -2977,6 +3070,9 @@ Store = Service.extend({ @return DS.Adapter */ adapterFor(modelName) { + if (DEBUG) { + assertDestroyingStore(this, 'adapterFor'); + } heimdall.increment(adapterFor); assert(`You need to pass a model name to the store's adapterFor method`, isPresent(modelName)); assert( @@ -3055,6 +3151,9 @@ Store = Service.extend({ @return {DS.Serializer} */ serializerFor(modelName) { + if (DEBUG) { + assertDestroyingStore(this, 'serializerFor'); + } heimdall.increment(serializerFor); assert( `You need to pass a model name to the store's serializerFor method`, @@ -3230,12 +3329,6 @@ Store = Service.extend({ }, }); -// Delegation to the adapter and promise management - -function defaultSerializer(store) { - return store.serializerFor('application'); -} - function _commit(adapter, store, operation, snapshot) { let internalModel = snapshot._internalModel; let modelName = snapshot.modelName; @@ -3401,5 +3494,22 @@ function _modelForMixin(store, normalizedModelName) { return _lookupModelFactory(store, normalizedModelName); } -export { Store }; +let assertDestroyingStore; +let assertDestroyedStoreOnly; + +if (DEBUG) { + assertDestroyingStore = function assertDestroyedStore(store, method) { + assert( + `Attempted to call store.${method}(), but the store instance has already been destroyed.`, + !(store.isDestroying || store.isDestroyed) + ); + }; + assertDestroyedStoreOnly = function assertDestroyedStoreOnly(store, method) { + assert( + `Attempted to call store.${method}(), but the store instance has already been destroyed.`, + !store.isDestroyed + ); + }; +} + export default Store; diff --git a/tests/unit/store/asserts-test.js b/tests/unit/store/asserts-test.js index 4263f541fc2..29af62f5b20 100644 --- a/tests/unit/store/asserts-test.js +++ b/tests/unit/store/asserts-test.js @@ -1,34 +1,112 @@ import { module } from 'qunit'; -import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import { createStore } from 'dummy/tests/helpers/store'; - -module('unit/store/asserts - DS.Store methods produce useful assertion messages'); - -const MODEL_NAME_METHODS = [ - 'createRecord', - 'findRecord', - 'findByIds', - 'peekRecord', - 'hasRecordForId', - 'recordForId', - 'query', - 'queryRecord', - 'findAll', - 'peekAll', - 'modelFor', - '_modelFactoryFor', - 'normalize', - 'adapterFor', - 'serializerFor', -]; - -testInDebug('Calling Store methods with no modelName asserts', function(assert) { - assert.expect(MODEL_NAME_METHODS.length); - let store = createStore(); - - MODEL_NAME_METHODS.forEach(methodName => { - assert.expectAssertion(() => { - store[methodName](null); - }, new RegExp(`You need to pass a model name to the store's ${methodName} method`)); +import test from 'dummy/tests/helpers/test-in-debug'; +import { run } from '@ember/runloop'; +import { setupTest } from 'ember-qunit'; +import Store from 'ember-data/store'; +import Model from 'ember-data/model'; + +module('unit/store/asserts - DS.Store methods produce useful assertion messages', function(hooks) { + let store; + + setupTest(hooks); + hooks.beforeEach(function() { + let { owner } = this; + owner.register('model:foo', Model.extend()); + owner.register('service:store', Store); + store = owner.lookup('service:store'); + }); + + const MODEL_NAME_METHODS = [ + 'createRecord', + 'findRecord', + 'findByIds', + 'peekRecord', + 'hasRecordForId', + 'recordForId', + 'query', + 'queryRecord', + 'findAll', + 'peekAll', + 'modelFor', + '_modelFactoryFor', + 'normalize', + 'adapterFor', + 'serializerFor', + ]; + + test('Calling Store methods with no modelName asserts', function(assert) { + assert.expect(MODEL_NAME_METHODS.length); + + MODEL_NAME_METHODS.forEach(methodName => { + assert.expectAssertion(() => { + store[methodName](null); + }, new RegExp(`You need to pass a model name to the store's ${methodName} method`)); + }); + }); + + const STORE_ENTRY_METHODS = [ + 'createRecord', + 'deleteRecord', + 'unloadRecord', + 'find', + 'findRecord', + 'findByIds', + 'getReference', + 'peekRecord', + 'hasRecordForId', + 'recordForId', + 'findMany', + 'findHasMany', + 'findBelongsTo', + 'query', + 'queryRecord', + 'findAll', + 'peekAll', + 'unloadAll', + 'didSaveRecord', + 'recordWasInvalid', + 'recordWasError', + 'updateId', + 'modelFor', + '_modelFactoryFor', + '_hasModelFor', + 'push', + '_push', + 'pushPayload', + 'normalize', + 'recordWasLoaded', + 'adapterFor', + 'serializerFor', + ]; + + test('Calling Store methods after the store has been destroyed asserts', function(assert) { + assert.expect(STORE_ENTRY_METHODS.length); + run(() => store.destroy()); + + STORE_ENTRY_METHODS.forEach(methodName => { + assert.expectAssertion(() => { + store[methodName](); + }, `Attempted to call store.${methodName}(), but the store instance has already been destroyed.`); + }); + }); + + const STORE_TEARDOWN_METHODS = ['unloadAll', 'modelFor', '_modelFactoryFor']; + + test('Calling Store teardown methods during destroy does not assert, but calling other methods does', function(assert) { + assert.expect(STORE_ENTRY_METHODS.length - STORE_TEARDOWN_METHODS.length); + + run(() => { + store.destroy(); + + STORE_ENTRY_METHODS.forEach(methodName => { + if (STORE_TEARDOWN_METHODS.indexOf(methodName) !== -1) { + store[methodName]('foo'); + } else { + assert.expectAssertion(() => { + store[methodName](); + }, `Attempted to call store.${methodName}(), but the store instance has already been destroyed.`); + } + }); + }); }); }); From baf2c3a47ee9cfb5f6ce538c7bb5ec7e86989e8c Mon Sep 17 00:00:00 2001 From: jlami Date: Wed, 29 Aug 2018 03:10:59 +0200 Subject: [PATCH 2324/2527] Additional test coverage for async belongsTo mutation (#5584) * Added failing test for #5575 * add integration and acceptance tests for editing an async belongsTo --- .../relationships/belongs-to-test.js | 103 ++++++++++++++++++ .../relationships/belongs-to-test.js | 72 ++++++++++++ 2 files changed, 175 insertions(+) diff --git a/tests/acceptance/relationships/belongs-to-test.js b/tests/acceptance/relationships/belongs-to-test.js index f3b9c5cccb0..5a705deaabc 100644 --- a/tests/acceptance/relationships/belongs-to-test.js +++ b/tests/acceptance/relationships/belongs-to-test.js @@ -19,6 +19,15 @@ class Person extends Model { children; @belongsTo('person', { async: true, inverse: 'children' }) parent; + @belongsTo('pet', { inverse: 'bestHuman', async: true }) + bestDog; +} + +class Pet extends Model { + @belongsTo('person', { inverse: 'bestDog', async: false }) + bestHuman; + @attr + name; } class TestAdapter extends JSONAPIAdapter { @@ -181,6 +190,100 @@ module('async belongs-to rendering tests', function(hooks) { adapter = store.adapterFor('application'); }); + module('for local changes', function(hooks) { + hooks.beforeEach(function() { + let { owner } = this; + owner.register('model:person', Person); + owner.register('model:pet', Pet); + }); + + test('async belongsTo returns correct new value after a local change', async function(assert) { + let chris = store.push({ + data: { + type: 'person', + id: '1', + attributes: { name: 'Chris' }, + relationships: { + bestDog: { + data: null, + }, + }, + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + bestHuman: { + data: null, + }, + }, + }, + { + type: 'pet', + id: '2', + attributes: { name: 'Pirate' }, + relationships: { + bestHuman: { + data: null, + }, + }, + }, + ], + }); + + let shen = store.peekRecord('pet', '1'); + let pirate = store.peekRecord('pet', '2'); + let bestDog = await chris.get('bestDog'); + + this.set('chris', chris); + + await render(hbs` +

      {{chris.bestDog.name}}

      + `); + await settled(); + + assert.equal(this.element.textContent.trim(), ''); + assert.ok(shen.get('bestHuman') === null, 'precond - Shen has no best human'); + assert.ok(pirate.get('bestHuman') === null, 'precond - pirate has no best human'); + assert.ok(bestDog === null, 'precond - Chris has no best dog'); + + chris.set('bestDog', shen); + bestDog = await chris.get('bestDog'); + await settled(); + + assert.equal(this.element.textContent.trim(), 'Shen'); + assert.ok(shen.get('bestHuman') === chris, "scene 1 - Chris is Shen's best human"); + assert.ok(pirate.get('bestHuman') === null, 'scene 1 - pirate has no best human'); + assert.ok(bestDog === shen, "scene 1 - Shen is Chris's best dog"); + + chris.set('bestDog', pirate); + bestDog = await chris.get('bestDog'); + await settled(); + + assert.equal(this.element.textContent.trim(), 'Pirate'); + assert.ok(shen.get('bestHuman') === null, "scene 2 - Chris is no longer Shen's best human"); + assert.ok(pirate.get('bestHuman') === chris, 'scene 2 - pirate now has Chris as best human'); + assert.ok(bestDog === pirate, "scene 2 - Pirate is now Chris's best dog"); + + chris.set('bestDog', null); + bestDog = await chris.get('bestDog'); + await settled(); + + assert.equal(this.element.textContent.trim(), ''); + assert.ok( + shen.get('bestHuman') === null, + "scene 3 - Chris remains no longer Shen's best human" + ); + assert.ok( + pirate.get('bestHuman') === null, + 'scene 3 - pirate no longer has Chris as best human' + ); + assert.ok(bestDog === null, 'scene 3 - Chris has no best dog'); + }); + }); + module('for data-no-link scenarios', function() { test('We can render an async belongs-to', async function(assert) { let people = makePeopleWithRelationshipData(); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 47459fdc6e0..ad0360946f8 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -117,6 +117,78 @@ module('integration/relationship/belongs-to BelongsTo Relationships (new-style)' assert.ok(personPet === pet, 'We ended up in the same state'); }); + + test('async belongsTo returns correct new value after a local change', async function(assert) { + let chris = store.push({ + data: { + type: 'person', + id: '1', + attributes: { name: 'Chris' }, + relationships: { + bestDog: { + data: null, + }, + }, + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + bestHuman: { + data: null, + }, + }, + }, + { + type: 'pet', + id: '2', + attributes: { name: 'Pirate' }, + relationships: { + bestHuman: { + data: null, + }, + }, + }, + ], + }); + + let shen = store.peekRecord('pet', '1'); + let pirate = store.peekRecord('pet', '2'); + let bestDog = await chris.get('bestDog'); + + assert.ok(shen.get('bestHuman') === null, 'precond - Shen has no best human'); + assert.ok(pirate.get('bestHuman') === null, 'precond - pirate has no best human'); + assert.ok(bestDog === null, 'precond - Chris has no best dog'); + + chris.set('bestDog', shen); + bestDog = await chris.get('bestDog'); + + assert.ok(shen.get('bestHuman') === chris, "scene 1 - Chris is Shen's best human"); + assert.ok(pirate.get('bestHuman') === null, 'scene 1 - pirate has no best human'); + assert.ok(bestDog === shen, "scene 1 - Shen is Chris's best dog"); + + chris.set('bestDog', pirate); + bestDog = await chris.get('bestDog'); + + assert.ok(shen.get('bestHuman') === null, "scene 2 - Chris is no longer Shen's best human"); + assert.ok(pirate.get('bestHuman') === chris, 'scene 2 - pirate now has Chris as best human'); + assert.ok(bestDog === pirate, "scene 2 - Pirate is now Chris's best dog"); + + chris.set('bestDog', null); + bestDog = await chris.get('bestDog'); + + assert.ok( + shen.get('bestHuman') === null, + "scene 3 - Chris remains no longer Shen's best human" + ); + assert.ok( + pirate.get('bestHuman') === null, + 'scene 3 - pirate no longer has Chris as best human' + ); + assert.ok(bestDog === null, 'scene 3 - Chris has no best dog'); + }); }); module('integration/relationship/belongs_to Belongs-To Relationships', { From 721826edb86ee272c0a5dbbcdc70b40d2e9831e5 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 29 Aug 2018 18:02:20 -0700 Subject: [PATCH 2325/2527] bump ember-source version to latest --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index dae39bd2376..3822ffb6b78 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "ember-qunit": "^3.4.1", "ember-qunit-assert-helpers": "^0.2.1", "ember-resolver": "^5.0.1", - "ember-source": "~3.3.0", + "ember-source": "~3.4.0", "ember-source-channel-url": "^1.1.0", "ember-try": "^1.0.0-beta.3", "eslint": "^5.3.0", diff --git a/yarn.lock b/yarn.lock index cc11aa4d775..5726264fa7a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2759,9 +2759,9 @@ ember-source-channel-url@^1.0.1, ember-source-channel-url@^1.1.0: dependencies: got "^8.0.1" -ember-source@~3.3.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-3.3.1.tgz#bcac785b32d5e99867e236979c3fb34536659ecd" +ember-source@~3.4.0: + version "3.4.0" + resolved "https://registry.npmjs.org/ember-source/-/ember-source-3.4.0.tgz#12de2461de6ce5e02de824ac45c81cb17bf5523b" dependencies: broccoli-funnel "^2.0.1" broccoli-merge-trees "^2.0.0" From b908b3af705309c17f2aadc9c44f9de069dc1c37 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 29 Aug 2018 18:02:47 -0700 Subject: [PATCH 2326/2527] [FEAT] ensure release builds only perform necessary jobs --- .travis.yml | 13 ++++++++++--- RELEASE.md | 5 +++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 928d33cc3e1..301146d3120 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,8 @@ stages: - test - additional tests - ember version tests - - external partner tests + - name: external partner tests + if: NOT (branch ~= /^release.*/) - name: deploy if: type = push AND (branch IN (master, beta, release) OR tag IS present) @@ -35,14 +36,17 @@ jobs: include: # runs tests with current locked deps and linting - stage: test - name: "Basic Tests" + name: "Linting" + if: NOT (branch ~= /^release.*/) script: - ./bin/lint-features - yarn lint:js - - yarn test + - name: "Basic Tests" + script: yarn test - stage: additional tests name: "Optional Features" + if: NOT (branch ~= /^release.*/) install: yarn install script: yarn test:optional-features @@ -70,10 +74,13 @@ jobs: - name: "Ember LTS 2.18" env: EMBER_TRY_SCENARIO=ember-lts-2.18 - name: "Ember Release" + if: NOT (branch ~= /^release.*/) env: EMBER_TRY_SCENARIO=ember-release - name: "Ember Beta" + if: NOT (branch ~= /^release.*/) env: EMBER_TRY_SCENARIO=ember-beta - name: "Ember Canary" + if: NOT (branch ~= /^release.*/) env: EMBER_TRY_SCENARIO=ember-canary # runs tests against various open-source projects for early-warning regression analysis diff --git a/RELEASE.md b/RELEASE.md index 5ff8d2619e7..2beb5c2b892 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -9,6 +9,11 @@ release. STEPS: ------ +* ensure that the `ember-source` version in `package.json` matches only the minor range for the `ember-data` version we are releasing + * E.G. `"ember-data": "3.4.1"` should have `"ember-source": "~3.4.0"`. For betas/canary, pointing at the last minor release is OK. + * See https://github.com/emberjs/data/issues/5607 for the importance of this step. +* ensure that the last two LTS releases of Ember (and only the last two) are included in `travis.yml`. + * See https://github.com/emberjs/data/issues/5607 for the importance of this step. * generate changelog (`PRIOR_VERSION=v2.0.0 HEAD=release ./bin/changelog`) * prepend changelog output to `CHANGELOG.md` * edit changelog output to be as user-friendly as possible (drop [INTERNAL] changes, non-code changes, etc.) From ad5ee89cf807ed31fac46f409a46e77d3cd38834 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 30 Aug 2018 15:50:46 -0700 Subject: [PATCH 2327/2527] [FEAT RecordData] turn on the build-flag by default --- index.js | 4 +++- package.json | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 25dad8beab5..d816a45ac5c 100644 --- a/index.js +++ b/index.js @@ -89,10 +89,12 @@ module.exports = { this.app.options && this.app.options.emberData && this.app.options.emberData.enableRecordDataRFCBuild; + let isEmberDataItself = this.isDevelopingAddon(); + let useLegacyBuild = (isEmberDataItself && (USE_RECORD_DATA_RFC || optionFlag === false)); return { emberData: { - enableRecordDataRFCBuild: USE_RECORD_DATA_RFC || optionFlag || false, + enableRecordDataRFCBuild: !useLegacyBuild || true, }, }; }, diff --git a/package.json b/package.json index 3822ffb6b78..79f436c70ee 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,11 @@ "build:production": "ember build --environment=production", "lint:js": "eslint .", "start": "ember server", - "test": "ember test && ember test --record-data-rfc-build", + "test": "ember test", "test:all": "ember try:each", "test:node": "node node-tests/nodetest-runner.js", - "test:production": "ember test -e production && ember test -e production --record-data-rfc-build", - "test:optional-features": "ember test -e test-optional-features && ember test -e test-optional-features --record-data-rfc-build", + "test:production": "ember test -e production", + "test:optional-features": "ember test -e test-optional-features", "test-external:ember-m3": "node ./lib/scripts/test-external ember-m3 https://github.com/hjdivad/ember-m3.git", "test-external:ember-data-change-tracker": "node ./lib/scripts/test-external ember-data-change-tracker https://github.com/danielspaniel/ember-data-change-tracker.git", "test-external:emberaddons.com": "node ./lib/scripts/test-external ember-cli-addon-search https://github.com/gcollazo/ember-cli-addon-search.git", From 3e7b239fcf83456e8a573edd2cabc08f78b6238e Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 30 Aug 2018 16:16:37 -0700 Subject: [PATCH 2328/2527] prettier to the prettier gods --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index d816a45ac5c..42a68129a3e 100644 --- a/index.js +++ b/index.js @@ -90,7 +90,7 @@ module.exports = { this.app.options.emberData && this.app.options.emberData.enableRecordDataRFCBuild; let isEmberDataItself = this.isDevelopingAddon(); - let useLegacyBuild = (isEmberDataItself && (USE_RECORD_DATA_RFC || optionFlag === false)); + let useLegacyBuild = isEmberDataItself && (USE_RECORD_DATA_RFC || optionFlag === false); return { emberData: { From 298a26eecb423627a38e3f25ad3a87c632013d9a Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 30 Aug 2018 19:30:59 -0700 Subject: [PATCH 2329/2527] [FEAT] deprecate instead of assert method calls on a destroyed store instance (#5619) --- addon/-legacy-private/system/store.js | 40 +++++++++++++++++----- addon/-record-data-private/system/store.js | 40 +++++++++++++++++----- tests/unit/store/asserts-test.js | 2 ++ 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/addon/-legacy-private/system/store.js b/addon/-legacy-private/system/store.js index 240cba1e94c..0348d12e516 100644 --- a/addon/-legacy-private/system/store.js +++ b/addon/-legacy-private/system/store.js @@ -220,6 +220,8 @@ Store = Service.extend({ this._serializerCache = Object.create(null); if (DEBUG) { + this.shouldAssertMethodCallsOnDestroyedStore = + this.shouldAssertMethodCallsOnDestroyedStore || false; if (this.shouldTrackAsyncRequests === undefined) { this.shouldTrackAsyncRequests = false; } @@ -3414,16 +3416,38 @@ if (DEBUG) { ); }; assertDestroyingStore = function assertDestroyedStore(store, method) { - assert( - `Attempted to call store.${method}(), but the store instance has already been destroyed.`, - !(store.isDestroying || store.isDestroyed) - ); + if (!store.shouldAssertMethodCallsOnDestroyedStore) { + deprecate( + `Attempted to call store.${method}(), but the store instance has already been destroyed.`, + !(store.isDestroying || store.isDestroyed), + { + id: 'ember-data:method-calls-on-destroyed-store', + until: '3.8', + } + ); + } else { + assert( + `Attempted to call store.${method}(), but the store instance has already been destroyed.`, + !(store.isDestroying || store.isDestroyed) + ); + } }; assertDestroyedStoreOnly = function assertDestroyedStoreOnly(store, method) { - assert( - `Attempted to call store.${method}(), but the store instance has already been destroyed.`, - !store.isDestroyed - ); + if (!store.shouldAssertMethodCallsOnDestroyedStore) { + deprecate( + `Attempted to call store.${method}(), but the store instance has already been destroyed.`, + !(store.isDestroying || store.isDestroyed), + { + id: 'ember-data:method-calls-on-destroyed-store', + until: '3.8', + } + ); + } else { + assert( + `Attempted to call store.${method}(), but the store instance has already been destroyed.`, + !store.isDestroyed + ); + } }; } diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index 0edac2fcca5..5c92ae3bd87 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -226,6 +226,8 @@ Store = Service.extend({ this.modelDataWrapper = new ModelDataWrapper(this); if (DEBUG) { + this.shouldAssertMethodCallsOnDestroyedStore = + this.shouldAssertMethodCallsOnDestroyedStore || false; if (this.shouldTrackAsyncRequests === undefined) { this.shouldTrackAsyncRequests = false; } @@ -3499,16 +3501,38 @@ let assertDestroyedStoreOnly; if (DEBUG) { assertDestroyingStore = function assertDestroyedStore(store, method) { - assert( - `Attempted to call store.${method}(), but the store instance has already been destroyed.`, - !(store.isDestroying || store.isDestroyed) - ); + if (!store.shouldAssertMethodCallsOnDestroyedStore) { + deprecate( + `Attempted to call store.${method}(), but the store instance has already been destroyed.`, + !(store.isDestroying || store.isDestroyed), + { + id: 'ember-data:method-calls-on-destroyed-store', + until: '3.8', + } + ); + } else { + assert( + `Attempted to call store.${method}(), but the store instance has already been destroyed.`, + !(store.isDestroying || store.isDestroyed) + ); + } }; assertDestroyedStoreOnly = function assertDestroyedStoreOnly(store, method) { - assert( - `Attempted to call store.${method}(), but the store instance has already been destroyed.`, - !store.isDestroyed - ); + if (!store.shouldAssertMethodCallsOnDestroyedStore) { + deprecate( + `Attempted to call store.${method}(), but the store instance has already been destroyed.`, + !(store.isDestroying || store.isDestroyed), + { + id: 'ember-data:method-calls-on-destroyed-store', + until: '3.8', + } + ); + } else { + assert( + `Attempted to call store.${method}(), but the store instance has already been destroyed.`, + !store.isDestroyed + ); + } }; } diff --git a/tests/unit/store/asserts-test.js b/tests/unit/store/asserts-test.js index 29af62f5b20..902e9204f57 100644 --- a/tests/unit/store/asserts-test.js +++ b/tests/unit/store/asserts-test.js @@ -80,6 +80,7 @@ module('unit/store/asserts - DS.Store methods produce useful assertion messages' ]; test('Calling Store methods after the store has been destroyed asserts', function(assert) { + store.shouldAssertMethodCallsOnDestroyedStore = true; assert.expect(STORE_ENTRY_METHODS.length); run(() => store.destroy()); @@ -93,6 +94,7 @@ module('unit/store/asserts - DS.Store methods produce useful assertion messages' const STORE_TEARDOWN_METHODS = ['unloadAll', 'modelFor', '_modelFactoryFor']; test('Calling Store teardown methods during destroy does not assert, but calling other methods does', function(assert) { + store.shouldAssertMethodCallsOnDestroyedStore = true; assert.expect(STORE_ENTRY_METHODS.length - STORE_TEARDOWN_METHODS.length); run(() => { From 56f6301717fac97f10e9a9c9da69fa7312767b71 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Fri, 31 Aug 2018 21:39:40 -0700 Subject: [PATCH 2330/2527] Add partner test for the ilios frontend Ilios is an open source application built to manage the curriculum of medical, pharmacy, dental, and nursing health science degrees. It is sponsored by UCSF and used at universities around the world. --- .travis.yml | 2 ++ package.json | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 928d33cc3e1..0010d6b13b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -94,6 +94,8 @@ jobs: script: yarn test-external:storefront - name: "Ember Data Factory Guy" script: yarn test-external:factory-guy + - name: "Ilios Frontend" + script: yarn test-external:ilios-frontend - stage: deploy name: "Publish" diff --git a/package.json b/package.json index dae39bd2376..0c4fba23856 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "test-external:ember-observer": "node ./lib/scripts/test-external ember-observer https://github.com/emberobserver/client.git", "test-external:travis-web": "node ./lib/scripts/test-external travis-web https://github.com/travis-ci/travis-web.git", "test-external:storefront": "node ./lib/scripts/test-external storefront https://github.com/embermap/ember-data-storefront.git", - "test-external:factory-guy": "node ./lib/scripts/test-external factory-guy https://github.com/danielspaniel/ember-data-factory-guy.git" + "test-external:factory-guy": "node ./lib/scripts/test-external factory-guy https://github.com/danielspaniel/ember-data-factory-guy.git", + "test-external:ilios-frontend": "node ./lib/scripts/test-external ilios-frontend https://github.com/ilios/frontend.git" }, "author": "", "license": "MIT", From f8c0983dcc1af51ecdfba157afd5b16a95ae76c4 Mon Sep 17 00:00:00 2001 From: Don Denton Date: Sat, 1 Sep 2018 11:21:39 -0500 Subject: [PATCH 2331/2527] [DOC release] Fix misleading documentation: AdapterPopulatedRecordArray In my experimentation, I've discovered that though the promise returned from `store.query()` does have array-like methods on it, the actual `AdapterPopulatedRecordArray` is what the promise *resolves to*. For example, the `length` property of the object returned from `store.query` will always be `0`. The object which the promise resolves to will represent the actual length of the records that were queried. The documentation for `store.query` states plainly that the AdapterPopulatedRecordArray is the *resolution* of the promise, but the documentation here misrepresented that. For example, the original code actually would behave like this: ```javascript // GET /users?isAdmin=true var admins = store.query('user', { isAdmin: true }); admins.then(function() { console.log(admins.get("length")); // Throws: "admins.get" is not a function }); ``` --- .../adapter-populated-record-array.js | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/addon/-private/system/record-arrays/adapter-populated-record-array.js b/addon/-private/system/record-arrays/adapter-populated-record-array.js index d3cc1e68a91..f323a4060a9 100644 --- a/addon/-private/system/record-arrays/adapter-populated-record-array.js +++ b/addon/-private/system/record-arrays/adapter-populated-record-array.js @@ -19,22 +19,23 @@ import cloneNull from '../clone-null'; ```javascript // GET /users?isAdmin=true - var admins = store.query('user', { isAdmin: true }); + store.query('user', { isAdmin: true }).then(function(admins) { - admins.then(function() { - console.log(admins.get("length")); // 42 - }); + admins.then(function() { + console.log(admins.get("length")); // 42 + }); - // somewhere later in the app code, when new admins have been created - // in the meantime - // - // GET /users?isAdmin=true - admins.update().then(function() { - admins.get('isUpdating'); // false - console.log(admins.get("length")); // 123 - }); + // somewhere later in the app code, when new admins have been created + // in the meantime + // + // GET /users?isAdmin=true + admins.update().then(function() { + admins.get('isUpdating'); // false + console.log(admins.get("length")); // 123 + }); - admins.get('isUpdating'); // true + admins.get('isUpdating'); // true + } ``` @class AdapterPopulatedRecordArray From 411ab8a22113c433d7273a79244d56391a4b708d Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Sun, 2 Sep 2018 11:03:35 -0700 Subject: [PATCH 2332/2527] Show output for smoke tests This prevents a timeout if build and test take longer than 10 minutes. --- lib/scripts/test-external.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scripts/test-external.js b/lib/scripts/test-external.js index 67c2625cdf0..c1906e108f8 100644 --- a/lib/scripts/test-external.js +++ b/lib/scripts/test-external.js @@ -82,7 +82,7 @@ let commitTestPassed = true; try { debug('Running Smoke Test'); - execWithLog(`cd ../__external-test-cache/${externalProjectName} && ember test`); + execWithLog(`cd ../__external-test-cache/${externalProjectName} && ember test`, true); } catch (e) { smokeTestPassed = false; } From b6af72110aed2e0ce69101d22ef1df1f595b1a5d Mon Sep 17 00:00:00 2001 From: Kyle Turney Date: Mon, 3 Sep 2018 20:57:34 -0500 Subject: [PATCH 2333/2527] remove deletes (#5622) I was mucking about with google-closure-compiler and it tripped up on these deletes that are not for properties. Looking at the blame, looks like they may have been left over from some find/replacing. --- .../system/relationships/relationship-payloads.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-legacy-private/system/relationships/relationship-payloads.js b/addon/-legacy-private/system/relationships/relationship-payloads.js index 07b051dd14f..478c345eee8 100644 --- a/addon/-legacy-private/system/relationships/relationship-payloads.js +++ b/addon/-legacy-private/system/relationships/relationship-payloads.js @@ -172,7 +172,7 @@ export default class RelationshipPayloads { this._flushPending(); if (this._isLHS(modelName, relationshipName)) { - delete this.lhs_payloads.delete(modelName, id); + this.lhs_payloads.delete(modelName, id); } else { assert( `${modelName}:${relationshipName} is not either side of this relationship, ${ @@ -182,7 +182,7 @@ export default class RelationshipPayloads { }`, this._isRHS(modelName, relationshipName) ); - delete this.rhs_payloads.delete(modelName, id); + this.rhs_payloads.delete(modelName, id); } } From 5ad7df238c1350bdfe773b892762ea9edfcf6c6d Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 6 Sep 2018 08:12:16 -0700 Subject: [PATCH 2334/2527] fix labels --- addon/-legacy-private/system/store.js | 2 +- addon/-record-data-private/system/store.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-legacy-private/system/store.js b/addon/-legacy-private/system/store.js index 0348d12e516..5ddd2bd314e 100644 --- a/addon/-legacy-private/system/store.js +++ b/addon/-legacy-private/system/store.js @@ -1616,7 +1616,7 @@ Store = Service.extend({ ); return promiseObject( - _queryRecord(adapter, this, modelName, query, adapterOptionsWrapper).then(internalModel => { + _queryRecord(adapter, this, normalizedModelName, query, adapterOptionsWrapper).then(internalModel => { // the promise returned by store.queryRecord is expected to resolve with // an instance of DS.Model if (internalModel) { diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index 5c92ae3bd87..6dca895016e 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -1784,7 +1784,7 @@ Store = Service.extend({ ); return promiseObject( - _queryRecord(adapter, this, modelName, query, adapterOptionsWrapper).then(internalModel => { + _queryRecord(adapter, this, normalizedModelName, query, adapterOptionsWrapper).then(internalModel => { // the promise returned by store.queryRecord is expected to resolve with // an instance of DS.Model if (internalModel) { From c1f050b5b39447194ee7ae27fb5a08cf684c4299 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 6 Sep 2018 08:59:22 -0700 Subject: [PATCH 2335/2527] prettier :/ --- addon/-legacy-private/system/store.js | 18 ++++++++++-------- addon/-record-data-private/system/store.js | 18 ++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/addon/-legacy-private/system/store.js b/addon/-legacy-private/system/store.js index 5ddd2bd314e..156f1672d09 100644 --- a/addon/-legacy-private/system/store.js +++ b/addon/-legacy-private/system/store.js @@ -1616,15 +1616,17 @@ Store = Service.extend({ ); return promiseObject( - _queryRecord(adapter, this, normalizedModelName, query, adapterOptionsWrapper).then(internalModel => { - // the promise returned by store.queryRecord is expected to resolve with - // an instance of DS.Model - if (internalModel) { - return internalModel.getRecord(); - } + _queryRecord(adapter, this, normalizedModelName, query, adapterOptionsWrapper).then( + internalModel => { + // the promise returned by store.queryRecord is expected to resolve with + // an instance of DS.Model + if (internalModel) { + return internalModel.getRecord(); + } - return null; - }) + return null; + } + ) ); }, diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index 6dca895016e..ea46419445a 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -1784,15 +1784,17 @@ Store = Service.extend({ ); return promiseObject( - _queryRecord(adapter, this, normalizedModelName, query, adapterOptionsWrapper).then(internalModel => { - // the promise returned by store.queryRecord is expected to resolve with - // an instance of DS.Model - if (internalModel) { - return internalModel.getRecord(); - } + _queryRecord(adapter, this, normalizedModelName, query, adapterOptionsWrapper).then( + internalModel => { + // the promise returned by store.queryRecord is expected to resolve with + // an instance of DS.Model + if (internalModel) { + return internalModel.getRecord(); + } - return null; - }) + return null; + } + ) ); }, From 7df04db20772a8b90644d2564aab49c6178bb727 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 12 Sep 2018 18:34:03 -0700 Subject: [PATCH 2336/2527] cleanup code climate config --- .codeclimate.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.codeclimate.yml b/.codeclimate.yml index 8a27d7029a0..c5626c297d2 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -4,3 +4,29 @@ languages: exclude_paths: - "tests/*" + - "generators/*" + - "blueprints/*" + - "bin/*" + - "lib/*" + - "node-tests/*" + +version: "2" # required to adjust maintainability checks +checks: + argument-count: + config: + threshold: 4 + complex-logic: + config: + threshold: 4 + file-lines: + enabled: false # we should re-enable this and slowly reduce to ~750 over time + method-complexity: + enabled: false # we should re-enable this and slowly reduce to ~10 over time + method-count: + config: + threshold: 50 + method-lines: + config: + threshold: 100 + identical-code: + enabled: false # we should re-enable this once we no longer have a separate build step for RecordData From 71b3d90e3471d61dbc3a935d1638c07c895d5667 Mon Sep 17 00:00:00 2001 From: Nathan Hammond Date: Wed, 12 Sep 2018 18:41:56 -0700 Subject: [PATCH 2337/2527] [FEAT adapterOptions] Ensure adapterOptions use is possible throughout (#5627) * Feed options through HasManyReference. * Feed options through BelongsToReference. * Record Data: Feed options through HasManyReference. * Record Data: Feed options through BelongsToReference. * Test HasManyReference. * Test BelongsToReference. * Improve documentation. --- .eslintrc.js | 1 + addon/-legacy-private/system/many-array.js | 4 +- .../system/references/belongs-to.js | 42 +++++++- .../system/references/has-many.js | 43 +++++++- .../system/relationships/state/belongs-to.js | 16 +-- .../system/relationships/state/has-many.js | 16 +-- .../relationships/state/relationship.js | 4 +- addon/-legacy-private/system/store.js | 26 ++--- addon/-private/system/store/finders.js | 14 +-- .../-record-data-private/system/many-array.js | 9 +- .../system/model/internal-model.js | 26 +++-- .../system/promise-proxies.js | 8 +- .../system/references/belongs-to.js | 47 +++++++-- .../system/references/has-many.js | 43 +++++++- addon/-record-data-private/system/store.js | 99 +++++++++++-------- .../integration/references/belongs-to-test.js | 34 +++++-- tests/integration/references/has-many-test.js | 30 ++++-- 17 files changed, 333 insertions(+), 129 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index f3b603c017e..e8cb3d64082 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -79,6 +79,7 @@ module.exports = { globals: { heimdall: true, Map: false, + WeakMap: true, } }, diff --git a/addon/-legacy-private/system/many-array.js b/addon/-legacy-private/system/many-array.js index 47a1ca379a4..0812659d8bb 100644 --- a/addon/-legacy-private/system/many-array.js +++ b/addon/-legacy-private/system/many-array.js @@ -231,8 +231,8 @@ export default EmberObject.extend(MutableArray, Evented, { @method reload @public */ - reload() { - return this.relationship.reload(); + reload(options) { + return this.relationship.reload(options); }, /** diff --git a/addon/-legacy-private/system/references/belongs-to.js b/addon/-legacy-private/system/references/belongs-to.js index 6d836fa0300..1506b1d2d39 100644 --- a/addon/-legacy-private/system/references/belongs-to.js +++ b/addon/-legacy-private/system/references/belongs-to.js @@ -346,13 +346,35 @@ export default class BelongsToReference extends Reference { }); ``` + You may also pass in an options object whose properties will be + fed forward. This enables you to pass `adapterOptions` into the + request given to the adapter via the reference. + + Example + + ```javascript + userRef.load({ adapterOptions: { isPrivate: true } }).then(function(user) { + userRef.value() === user; + }); + ``` + + ```app/adapters/user.js + export default ApplicationAdapter.extend({ + findRecord(store, type, id, snapshot) { + // In the adapter you will have access to adapterOptions. + let adapterOptions = snapshot.adapterOptions; + } + }); + ``` + @method load + @param {Object} options the options to pass in. @return {Promise} a promise that resolves with the record in this belongs-to relationship. */ - load() { + load(options) { let rel = this.belongsToRelationship; - rel.getData(); + rel.getData(options); if (rel.fetchPromise !== null) { return rel.fetchPromise.then(() => { @@ -395,11 +417,23 @@ export default class BelongsToReference extends Reference { }); ``` + You may also pass in an options object whose properties will be + fed forward. This enables you to pass `adapterOptions` into the + request given to the adapter via the reference. A full example + can be found in the `load` method. + + Example + + ```javascript + userRef.reload({ adapterOptions: { isPrivate: true } }) + ``` + @method reload + @param {Object} options the options to pass in. @return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed. */ - reload() { - return this.belongsToRelationship.reload().then(internalModel => { + reload(options) { + return this.belongsToRelationship.reload(options).then(internalModel => { return this.value(); }); } diff --git a/addon/-legacy-private/system/references/has-many.js b/addon/-legacy-private/system/references/has-many.js index 425ae243354..8201e03fed0 100644 --- a/addon/-legacy-private/system/references/has-many.js +++ b/addon/-legacy-private/system/references/has-many.js @@ -354,14 +354,37 @@ export default class HasManyReference extends Reference { }); ``` + You may also pass in an options object whose properties will be + fed forward. This enables you to pass `adapterOptions` into the + request given to the adapter via the reference. + + Example + + ```javascript + commentsRef.load({ adapterOptions: { isPrivate: true } }) + .then(function(comments) { + //... + }); + ``` + + ```app/adapters/comment.js + export default ApplicationAdapter.extend({ + findMany(store, type, id, snapshots) { + // In the adapter you will have access to adapterOptions. + let adapterOptions = snapshots[0].adapterOptions; + } + }); + ``` + @method load + @param {Object} options the options to pass in. @return {Promise} a promise that resolves with the ManyArray in this has-many relationship. */ - load() { + load(options) { // TODO this can be simplified if (!this._isLoaded()) { - return this.hasManyRelationship.getData(); + return this.hasManyRelationship.getData(options); } return resolve(this.hasManyRelationship.manyArray); @@ -398,10 +421,22 @@ export default class HasManyReference extends Reference { }); ``` + You may also pass in an options object whose properties will be + fed forward. This enables you to pass `adapterOptions` into the + request given to the adapter via the reference. A full example + can be found in the `load` method. + + Example + + ```javascript + commentsRef.reload({ adapterOptions: { isPrivate: true } }) + ``` + @method reload + @param {Object} options the options to pass in. @return {Promise} a promise that resolves with the ManyArray in this has-many relationship. */ - reload() { - return this.hasManyRelationship.reload(); + reload(options) { + return this.hasManyRelationship.reload(options); } } diff --git a/addon/-legacy-private/system/relationships/state/belongs-to.js b/addon/-legacy-private/system/relationships/state/belongs-to.js index 86af77eb11f..8c7d0001c79 100644 --- a/addon/-legacy-private/system/relationships/state/belongs-to.js +++ b/addon/-legacy-private/system/relationships/state/belongs-to.js @@ -191,7 +191,7 @@ export default class BelongsToRelationship extends Relationship { // called by `getData()` when a request is needed // but no link is available - _fetchRecord() { + _fetchRecord(options) { let { inverseInternalModel, shouldForceReload } = this; if (inverseInternalModel) { @@ -200,9 +200,9 @@ export default class BelongsToRelationship extends Relationship { if (shouldForceReload && !inverseInternalModel.isEmpty() && inverseInternalModel.hasRecord) { // reload record, if it is already loaded // if we have a link, we would already be in `findLink()` - promise = inverseInternalModel.getRecord().reload(); + promise = inverseInternalModel.getRecord().reload(options); } else { - promise = this.store._findByInternalModel(inverseInternalModel); + promise = this.store._findByInternalModel(inverseInternalModel, options); } return promise; @@ -214,9 +214,9 @@ export default class BelongsToRelationship extends Relationship { // called by `getData()` when a request is needed // and a link is available - _fetchLink() { + _fetchLink(options) { return this.store - .findBelongsTo(this.internalModel, this.link, this.relationshipMeta) + .findBelongsTo(this.internalModel, this.link, this.relationshipMeta, options) .then(internalModel => { if (internalModel) { this.addInternalModel(internalModel); @@ -231,7 +231,7 @@ export default class BelongsToRelationship extends Relationship { Other calls must conform to the typical expectations, for instance, sync relationships expect that their data is already loaded. */ - getData(isForcedReload = false) { + getData(options, isForcedReload = false) { //TODO(Igor) flushCanonical here once our syncing is not stupid let record = this.inverseInternalModel ? this.inverseInternalModel.getRecord() : null; @@ -239,9 +239,9 @@ export default class BelongsToRelationship extends Relationship { let promise; if (this.link) { - promise = this._fetchLink(); + promise = this._fetchLink(options); } else { - promise = this._fetchRecord(); + promise = this._fetchRecord(options); } promise = promise.then(() => handleCompletedFind(this), e => handleCompletedFind(this, e)); diff --git a/addon/-legacy-private/system/relationships/state/has-many.js b/addon/-legacy-private/system/relationships/state/has-many.js index c6b8449cb06..19a581f7020 100755 --- a/addon/-legacy-private/system/relationships/state/has-many.js +++ b/addon/-legacy-private/system/relationships/state/has-many.js @@ -314,15 +314,15 @@ export default class ManyRelationship extends Relationship { // called by `getData()` when a request is needed // but no link is available - _fetchRecords() { + _fetchRecords(options) { let internalModels = this.currentState; let { shouldForceReload } = this; let promise; if (shouldForceReload === true) { - promise = this.store._scheduleFetchMany(internalModels); + promise = this.store._scheduleFetchMany(internalModels, options); } else { - promise = this.store.findMany(internalModels); + promise = this.store.findMany(internalModels, options); } return promise; @@ -330,9 +330,9 @@ export default class ManyRelationship extends Relationship { // called by `getData()` when a request is needed // and a link is available - _fetchLink() { + _fetchLink(options) { return this.store - .findHasMany(this.internalModel, this.link, this.relationshipMeta) + .findHasMany(this.internalModel, this.link, this.relationshipMeta, options) .then(records => { if (records.hasOwnProperty('meta')) { this.updateMeta(records.meta); @@ -344,7 +344,7 @@ export default class ManyRelationship extends Relationship { }); } - getData(isForcedReload = false) { + getData(options, isForcedReload = false) { //TODO(Igor) sync server here, once our syncing is not stupid let manyArray = this.manyArray; @@ -352,9 +352,9 @@ export default class ManyRelationship extends Relationship { let promise; if (this.link) { - promise = this._fetchLink(); + promise = this._fetchLink(options); } else { - promise = this._fetchRecords(); + promise = this._fetchRecords(options); } promise = promise.then( diff --git a/addon/-legacy-private/system/relationships/state/relationship.js b/addon/-legacy-private/system/relationships/state/relationship.js index 2448ff392e9..5752b0fb0f7 100644 --- a/addon/-legacy-private/system/relationships/state/relationship.js +++ b/addon/-legacy-private/system/relationships/state/relationship.js @@ -545,7 +545,7 @@ export default class Relationship { this.setRelationshipIsStale(true); } - reload() { + reload(options) { if (this._promiseProxy) { if (this._promiseProxy.get('isPending')) { return this._promiseProxy; @@ -554,7 +554,7 @@ export default class Relationship { this.setHasFailedLoadAttempt(false); this.setShouldForceReload(true); - this.getData(true); + this.getData(options, true); return this._promiseProxy; } diff --git a/addon/-legacy-private/system/store.js b/addon/-legacy-private/system/store.js index 156f1672d09..6795c3375a2 100644 --- a/addon/-legacy-private/system/store.js +++ b/addon/-legacy-private/system/store.js @@ -873,11 +873,11 @@ Store = Service.extend({ return _find(adapter, this, internalModel.type, internalModel.id, internalModel, options); }, - _scheduleFetchMany(internalModels) { + _scheduleFetchMany(internalModels, options) { let fetches = new Array(internalModels.length); for (let i = 0; i < internalModels.length; i++) { - fetches[i] = this._scheduleFetch(internalModels[i]); + fetches[i] = this._scheduleFetch(internalModels[i], options); } return Promise.all(fetches); @@ -943,10 +943,13 @@ Store = Service.extend({ let internalModels = new Array(totalItems); let seeking = Object.create(null); + let optionsMap = new WeakMap(); + for (let i = 0; i < totalItems; i++) { let pendingItem = pendingFetchItems[i]; let internalModel = pendingItem.internalModel; internalModels[i] = internalModel; + optionsMap.set(internalModel, pendingItem.options); seeking[internalModel.id] = pendingItem; } @@ -966,7 +969,7 @@ Store = Service.extend({ let recordFetch = store._fetchRecord( recordResolverPair.internalModel, recordResolverPair.options - ); // TODO adapter options + ); recordResolverPair.resolver.resolve(recordFetch); } @@ -1039,7 +1042,8 @@ Store = Service.extend({ // will once again convert the records to snapshots for adapter.findMany() let snapshots = new Array(totalItems); for (let i = 0; i < totalItems; i++) { - snapshots[i] = internalModels[i].createSnapshot(); + let internalModel = internalModels[i]; + snapshots[i] = internalModel.createSnapshot(optionsMap.get(internalModel)); } let groups = adapter.groupRecordsForFindMany(this, snapshots); @@ -1059,7 +1063,7 @@ Store = Service.extend({ if (totalInGroup > 1) { (function(groupedInternalModels) { - _findMany(adapter, store, modelName, ids, groupedInternalModels) + _findMany(adapter, store, modelName, ids, groupedInternalModels, optionsMap) .then(function(foundInternalModels) { handleFoundRecords(foundInternalModels, groupedInternalModels); }) @@ -1306,14 +1310,14 @@ Store = Service.extend({ @param {Array} internalModels @return {Promise} promise */ - findMany(internalModels) { + findMany(internalModels, options) { if (DEBUG) { assertDestroyingStore(this, 'findMany'); } let finds = new Array(internalModels.length); for (let i = 0; i < internalModels.length; i++) { - finds[i] = this._findEmptyInternalModel(internalModels[i]); + finds[i] = this._findEmptyInternalModel(internalModels[i], options); } return Promise.all(finds); @@ -1337,7 +1341,7 @@ Store = Service.extend({ @param {(Relationship)} relationship @return {Promise} promise */ - findHasMany(internalModel, link, relationship) { + findHasMany(internalModel, link, relationship, options) { if (DEBUG) { assertDestroyingStore(this, 'findHasMany'); } @@ -1354,7 +1358,7 @@ Store = Service.extend({ typeof adapter.findHasMany === 'function' ); - return _findHasMany(adapter, this, internalModel, link, relationship); + return _findHasMany(adapter, this, internalModel, link, relationship, options); }, /** @@ -1365,7 +1369,7 @@ Store = Service.extend({ @param {Relationship} relationship @return {Promise} promise */ - findBelongsTo(internalModel, link, relationship) { + findBelongsTo(internalModel, link, relationship, options) { if (DEBUG) { assertDestroyingStore(this, 'findBelongsTo'); } @@ -1382,7 +1386,7 @@ Store = Service.extend({ typeof adapter.findBelongsTo === 'function' ); - return _findBelongsTo(adapter, this, internalModel, link, relationship); + return _findBelongsTo(adapter, this, internalModel, link, relationship, options); }, /** diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 5998682afa3..ffb4599e54a 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -69,8 +69,10 @@ export function _find(adapter, store, modelClass, id, internalModel, options) { ); } -export function _findMany(adapter, store, modelName, ids, internalModels) { - let snapshots = A(internalModels).invoke('createSnapshot'); +export function _findMany(adapter, store, modelName, ids, internalModels, optionsMap) { + let snapshots = A( + internalModels.map(internalModel => internalModel.createSnapshot(optionsMap.get(internalModel))) + ); let modelClass = store.modelFor(modelName); // `adapter.findMany` gets the modelClass still let promise = adapter.findMany(store, modelClass, ids, snapshots); let label = `DS: Handle Adapter#findMany of '${modelName}'`; @@ -103,8 +105,8 @@ export function _findMany(adapter, store, modelName, ids, internalModels) { ); } -export function _findHasMany(adapter, store, internalModel, link, relationship) { - let snapshot = internalModel.createSnapshot(); +export function _findHasMany(adapter, store, internalModel, link, relationship, options) { + let snapshot = internalModel.createSnapshot(options); let modelClass = store.modelFor(relationship.type); let promise = adapter.findHasMany(store, snapshot, link, relationship); let label = `DS: Handle Adapter#findHasMany of '${internalModel.modelName}' : '${ @@ -141,8 +143,8 @@ export function _findHasMany(adapter, store, internalModel, link, relationship) ); } -export function _findBelongsTo(adapter, store, internalModel, link, relationship) { - let snapshot = internalModel.createSnapshot(); +export function _findBelongsTo(adapter, store, internalModel, link, relationship, options) { + let snapshot = internalModel.createSnapshot(options); let modelClass = store.modelFor(relationship.type); let promise = adapter.findBelongsTo(store, snapshot, link, relationship); let label = `DS: Handle Adapter#findBelongsTo of ${internalModel.modelName} : ${ diff --git a/addon/-record-data-private/system/many-array.js b/addon/-record-data-private/system/many-array.js index a7ee046030b..931356ed03a 100644 --- a/addon/-record-data-private/system/many-array.js +++ b/addon/-record-data-private/system/many-array.js @@ -246,9 +246,14 @@ export default EmberObject.extend(MutableArray, Evented, { @method reload @public */ - reload() { + reload(options) { // TODO this is odd, we don't ask the store for anything else like this? - return this.get('store').reloadManyArray(this, this.get('internalModel'), this.get('key')); + return this.get('store').reloadManyArray( + this, + this.get('internalModel'), + this.get('key'), + options + ); }, /** diff --git a/addon/-record-data-private/system/model/internal-model.js b/addon/-record-data-private/system/model/internal-model.js index 39728e2b0b5..59d11ce44b4 100644 --- a/addon/-record-data-private/system/model/internal-model.js +++ b/addon/-record-data-private/system/model/internal-model.js @@ -488,7 +488,7 @@ export default class InternalModel { return this.modelClass.eachRelationship(callback, binding); } - getBelongsTo(key) { + getBelongsTo(key, options) { let resource = this._modelData.getBelongsTo(key); let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key); let store = this.store; @@ -504,7 +504,8 @@ export default class InternalModel { promise: store._findBelongsToByJsonApiResource( resource, parentInternalModel, - relationshipMeta + relationshipMeta, + options ), content: internalModel ? internalModel.getRecord() : null, }); @@ -565,8 +566,13 @@ export default class InternalModel { return manyArray; } - fetchAsyncHasMany(relationshipMeta, jsonApi, manyArray) { - let promise = this.store._findHasManyByJsonApiResource(jsonApi, this, relationshipMeta); + fetchAsyncHasMany(relationshipMeta, jsonApi, manyArray, options) { + let promise = this.store._findHasManyByJsonApiResource( + jsonApi, + this, + relationshipMeta, + options + ); promise = promise.then(initialState => { // TODO why don't we do this in the store method manyArray.retrieveLatest(); @@ -577,7 +583,7 @@ export default class InternalModel { return promise; } - getHasMany(key) { + getHasMany(key, options) { let jsonApi = this._modelData.getHasMany(key); let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key); let async = relationshipMeta.options.async; @@ -589,7 +595,7 @@ export default class InternalModel { if (!promiseArray) { promiseArray = PromiseManyArray.create({ - promise: this.fetchAsyncHasMany(relationshipMeta, jsonApi, manyArray), + promise: this.fetchAsyncHasMany(relationshipMeta, jsonApi, manyArray, options), content: manyArray, }); this._relationshipPromisesCache[key] = promiseArray; @@ -626,7 +632,7 @@ export default class InternalModel { return this._relationshipPromisesCache[key]; } - reloadHasMany(key) { + reloadHasMany(key, options) { let loadingPromise = this._relationshipPromisesCache[key]; if (loadingPromise) { if (loadingPromise.get('isPending')) { @@ -643,19 +649,19 @@ export default class InternalModel { jsonApi._relationship.setRelationshipIsStale(true); let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key); let manyArray = this.getManyArray(key); - let promise = this.fetchAsyncHasMany(relationshipMeta, jsonApi, manyArray); + let promise = this.fetchAsyncHasMany(relationshipMeta, jsonApi, manyArray, options); // TODO igor Seems like this would mess with promiseArray wrapping, investigate this._updateLoadingPromiseForHasMany(key, promise); return promise; } - reloadBelongsTo(key) { + reloadBelongsTo(key, options) { let resource = this._modelData.getBelongsTo(key); resource._relationship.setRelationshipIsStale(true); let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key); - return this.store._findBelongsToByJsonApiResource(resource, this, relationshipMeta); + return this.store._findBelongsToByJsonApiResource(resource, this, relationshipMeta, options); } destroyFromModelData() { diff --git a/addon/-record-data-private/system/promise-proxies.js b/addon/-record-data-private/system/promise-proxies.js index a34330d0c59..26fcff25cba 100644 --- a/addon/-record-data-private/system/promise-proxies.js +++ b/addon/-record-data-private/system/promise-proxies.js @@ -97,7 +97,7 @@ export const PromiseBelongsTo = PromiseObject.extend({ ); }), - reload() { + reload(options) { assert( 'You are trying to reload an async belongsTo before it has been created', this.get('content') !== undefined @@ -108,7 +108,7 @@ export const PromiseBelongsTo = PromiseObject.extend({ let resource = state.modelData.getResourceIdentifier(); let internalModel = store._internalModelForResource(resource); - return store.reloadBelongsTo(this, internalModel, key).then(() => this); + return store.reloadBelongsTo(this, internalModel, key, options).then(() => this); }, }); @@ -137,12 +137,12 @@ export function proxyToContent(method) { } export const PromiseManyArray = PromiseArray.extend({ - reload() { + reload(options) { assert( 'You are trying to reload an async manyArray before it has been created', get(this, 'content') ); - this.set('promise', this.get('content').reload()); + this.set('promise', this.get('content').reload(options)); return this; }, diff --git a/addon/-record-data-private/system/references/belongs-to.js b/addon/-record-data-private/system/references/belongs-to.js index 2a20eb3d6a0..1033324fc60 100644 --- a/addon/-record-data-private/system/references/belongs-to.js +++ b/addon/-record-data-private/system/references/belongs-to.js @@ -248,11 +248,33 @@ export default class BelongsToReference extends Reference { }); ``` + You may also pass in an options object whose properties will be + fed forward. This enables you to pass `adapterOptions` into the + request given to the adapter via the reference. + + Example + + ```javascript + userRef.load({ adapterOptions: { isPrivate: true } }).then(function(user) { + userRef.value() === user; + }); + ``` + + ```app/adapters/user.js + export default ApplicationAdapter.extend({ + findRecord(store, type, id, snapshot) { + // In the adapter you will have access to adapterOptions. + let adapterOptions = snapshot.adapterOptions; + } + }); + ``` + @method load + @param {Object} options the options to pass in. @return {Promise} a promise that resolves with the record in this belongs-to relationship. */ - load() { - return this.parentInternalModel.getBelongsTo(this.key); + load(options) { + return this.parentInternalModel.getBelongsTo(this.key, options); } /** @@ -287,31 +309,44 @@ export default class BelongsToReference extends Reference { }); ``` + You may also pass in an options object whose properties will be + fed forward. This enables you to pass `adapterOptions` into the + request given to the adapter via the reference. A full example + can be found in the `load` method. + + Example + + ```javascript + userRef.reload({ adapterOptions: { isPrivate: true } }) + ``` + @method reload + @param {Object} options the options to pass in. @return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed. */ // TODO IGOR CHECK FOR OBJECT PROXIES - reload() { + reload(options) { let resource = this._resource(); if (resource && resource.links && resource.links.related) { return this.store._fetchBelongsToLinkFromResource( resource, this.parentInternalModel, - this.belongsToRelationship.relationshipMeta + this.belongsToRelationship.relationshipMeta, + options ); } if (resource && resource.data) { if (resource.data && (resource.data.id || resource.data.clientId)) { let internalModel = this.store._internalModelForResource(resource.data); if (internalModel.isLoaded()) { - return internalModel.reload().then(internalModel => { + return internalModel.reload(options).then(internalModel => { if (internalModel) { return internalModel.getRecord(); } return null; }); } else { - return this.store._findByInternalModel(internalModel); + return this.store._findByInternalModel(internalModel, options); } } } diff --git a/addon/-record-data-private/system/references/has-many.js b/addon/-record-data-private/system/references/has-many.js index 7ac204b993c..fb813b1b6b3 100644 --- a/addon/-record-data-private/system/references/has-many.js +++ b/addon/-record-data-private/system/references/has-many.js @@ -286,12 +286,35 @@ export default class HasManyReference extends Reference { }); ``` + You may also pass in an options object whose properties will be + fed forward. This enables you to pass `adapterOptions` into the + request given to the adapter via the reference. + + Example + + ```javascript + commentsRef.load({ adapterOptions: { isPrivate: true } }) + .then(function(comments) { + //... + }); + ``` + + ```app/adapters/comment.js + export default ApplicationAdapter.extend({ + findMany(store, type, id, snapshots) { + // In the adapter you will have access to adapterOptions. + let adapterOptions = snapshots[0].adapterOptions; + } + }); + ``` + @method load + @param {Object} options the options to pass in. @return {Promise} a promise that resolves with the ManyArray in this has-many relationship. */ - load() { - return this.internalModel.getHasMany(this.key); + load(options) { + return this.internalModel.getHasMany(this.key, options); } /** @@ -325,10 +348,22 @@ export default class HasManyReference extends Reference { }); ``` + You may also pass in an options object whose properties will be + fed forward. This enables you to pass `adapterOptions` into the + request given to the adapter via the reference. A full example + can be found in the `load` method. + + Example + + ```javascript + commentsRef.reload({ adapterOptions: { isPrivate: true } }) + ``` + @method reload + @param {Object} options the options to pass in. @return {Promise} a promise that resolves with the ManyArray in this has-many relationship. */ - reload() { - return this.internalModel.reloadHasMany(this.key); + reload(options) { + return this.internalModel.reloadHasMany(this.key, options); } } diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index ea46419445a..a6ff19fb216 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -49,6 +49,7 @@ const badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty const emberRun = emberRunLoop.backburner; const { ENV } = Ember; + let globalClientIdCounter = 1; //Get the materialized model from the internalModel/promise that returns @@ -883,11 +884,11 @@ Store = Service.extend({ return _find(adapter, this, internalModel.type, internalModel.id, internalModel, options); }, - _scheduleFetchMany(internalModels) { + _scheduleFetchMany(internalModels, options) { let fetches = new Array(internalModels.length); for (let i = 0; i < internalModels.length; i++) { - fetches[i] = this._scheduleFetch(internalModels[i]); + fetches[i] = this._scheduleFetch(internalModels[i], options); } return Promise.all(fetches); @@ -953,10 +954,13 @@ Store = Service.extend({ let internalModels = new Array(totalItems); let seeking = Object.create(null); + let optionsMap = new WeakMap(); + for (let i = 0; i < totalItems; i++) { let pendingItem = pendingFetchItems[i]; let internalModel = pendingItem.internalModel; internalModels[i] = internalModel; + optionsMap.set(internalModel, pendingItem.options); seeking[internalModel.id] = pendingItem; } @@ -976,7 +980,7 @@ Store = Service.extend({ let recordFetch = store._fetchRecord( recordResolverPair.internalModel, recordResolverPair.options - ); // TODO adapter options + ); recordResolverPair.resolver.resolve(recordFetch); } @@ -1049,7 +1053,7 @@ Store = Service.extend({ // will once again convert the records to snapshots for adapter.findMany() let snapshots = new Array(totalItems); for (let i = 0; i < totalItems; i++) { - snapshots[i] = internalModels[i].createSnapshot(); + snapshots[i] = internalModels[i].createSnapshot(optionsMap.get(internalModel)); } let groups = adapter.groupRecordsForFindMany(this, snapshots); @@ -1069,7 +1073,7 @@ Store = Service.extend({ if (totalInGroup > 1) { (function(groupedInternalModels) { - _findMany(adapter, store, modelName, ids, groupedInternalModels) + _findMany(adapter, store, modelName, ids, groupedInternalModels, optionsMap) .then(function(foundInternalModels) { handleFoundRecords(foundInternalModels, groupedInternalModels); }) @@ -1318,14 +1322,14 @@ Store = Service.extend({ @param {Array} internalModels @return {Promise} promise */ - findMany(internalModels) { + findMany(internalModels, options) { if (DEBUG) { assertDestroyingStore(this, 'findMany'); } let finds = new Array(internalModels.length); for (let i = 0; i < internalModels.length; i++) { - finds[i] = this._findEmptyInternalModel(internalModels[i]); + finds[i] = this._findEmptyInternalModel(internalModels[i], options); } return Promise.all(finds); @@ -1349,7 +1353,7 @@ Store = Service.extend({ @param {(Relationship)} relationship @return {Promise} promise */ - findHasMany(internalModel, link, relationship) { + findHasMany(internalModel, link, relationship, options) { if (DEBUG) { assertDestroyingStore(this, 'findHasMany'); } @@ -1366,10 +1370,10 @@ Store = Service.extend({ typeof adapter.findHasMany === 'function' ); - return _findHasMany(adapter, this, internalModel, link, relationship); + return _findHasMany(adapter, this, internalModel, link, relationship, options); }, - _findHasManyByJsonApiResource(resource, parentInternalModel, relationshipMeta) { + _findHasManyByJsonApiResource(resource, parentInternalModel, relationshipMeta, options) { if (!resource) { return RSVP.resolve([]); } @@ -1391,16 +1395,19 @@ Store = Service.extend({ // fetch via link if (shouldFindViaLink) { - return this.findHasMany(parentInternalModel, resource.links.related, relationshipMeta).then( - internalModels => { - let payload = { data: internalModels.map(im => im._modelData.getResourceIdentifier()) }; - if (internalModels.meta !== undefined) { - payload.meta = internalModels.meta; - } - parentInternalModel.linkWasLoadedForRelationship(relationshipMeta.key, payload); - return internalModels; + return this.findHasMany( + parentInternalModel, + resource.links.related, + relationshipMeta, + options + ).then(internalModels => { + let payload = { data: internalModels.map(im => im._modelData.getResourceIdentifier()) }; + if (internalModels.meta !== undefined) { + payload.meta = internalModels.meta; } - ); + parentInternalModel.linkWasLoadedForRelationship(relationshipMeta.key, payload); + return internalModels; + }); } let preferLocalCache = hasAnyRelationshipData && !relationshipIsEmpty; @@ -1413,7 +1420,7 @@ Store = Service.extend({ if (!relationshipIsStale && (preferLocalCache || hasLocalPartialData)) { let internalModels = resource.data.map(json => this._internalModelForResource(json)); - return this.findMany(internalModels); + return this.findMany(internalModels, options); } let hasData = hasAnyRelationshipData && !relationshipIsEmpty; @@ -1422,7 +1429,7 @@ Store = Service.extend({ if (hasData || hasLocalPartialData) { let internalModels = resource.data.map(json => this._internalModelForResource(json)); - return this._scheduleFetchMany(internalModels); + return this._scheduleFetchMany(internalModels, options); } // we were explicitly told we have no data and no links. @@ -1446,7 +1453,7 @@ Store = Service.extend({ @param {Relationship} relationship @return {Promise} promise */ - findBelongsTo(internalModel, link, relationship) { + findBelongsTo(internalModel, link, relationship, options) { if (DEBUG) { assertDestroyingStore(this, 'findBelongsTo'); } @@ -1463,28 +1470,31 @@ Store = Service.extend({ typeof adapter.findBelongsTo === 'function' ); - return _findBelongsTo(adapter, this, internalModel, link, relationship); + return _findBelongsTo(adapter, this, internalModel, link, relationship, options); }, - _fetchBelongsToLinkFromResource(resource, parentInternalModel, relationshipMeta) { + _fetchBelongsToLinkFromResource(resource, parentInternalModel, relationshipMeta, options) { if (!resource || !resource.links || !resource.links.related) { // should we warn here, not sure cause its an internal method return RSVP.resolve(null); } - return this.findBelongsTo(parentInternalModel, resource.links.related, relationshipMeta).then( - internalModel => { - let response = internalModel && internalModel._modelData.getResourceIdentifier(); - parentInternalModel.linkWasLoadedForRelationship(relationshipMeta.key, { data: response }); - if (internalModel === null) { - return null; - } - // TODO Igor this doesn't seem like the right boundary, probably the caller method should extract the record out - return internalModel.getRecord(); + return this.findBelongsTo( + parentInternalModel, + resource.links.related, + relationshipMeta, + options + ).then(internalModel => { + let response = internalModel && internalModel._modelData.getResourceIdentifier(); + parentInternalModel.linkWasLoadedForRelationship(relationshipMeta.key, { data: response }); + if (internalModel === null) { + return null; } - ); + // TODO Igor this doesn't seem like the right boundary, probably the caller method should extract the record out + return internalModel.getRecord(); + }); }, - _findBelongsToByJsonApiResource(resource, parentInternalModel, relationshipMeta) { + _findBelongsToByJsonApiResource(resource, parentInternalModel, relationshipMeta, options) { if (!resource) { return RSVP.resolve(null); } @@ -1514,7 +1524,12 @@ Store = Service.extend({ // fetch via link if (shouldFindViaLink) { - return this._fetchBelongsToLinkFromResource(resource, parentInternalModel, relationshipMeta); + return this._fetchBelongsToLinkFromResource( + resource, + parentInternalModel, + relationshipMeta, + options + ); } let preferLocalCache = @@ -1532,7 +1547,7 @@ Store = Service.extend({ return RSVP.resolve(null); } - return this._findByInternalModel(internalModel); + return this._findByInternalModel(internalModel, options); } let resourceIsLocal = !localDataIsEmpty && resource.data.id === null; @@ -1543,7 +1558,7 @@ Store = Service.extend({ // fetch by data if (!localDataIsEmpty) { - return this._fetchRecord(internalModel).then(() => { + return this._fetchRecord(internalModel, options).then(() => { return internalModel.getRecord(); }); } @@ -2857,12 +2872,12 @@ Store = Service.extend({ serializer.pushPayload(this, payload); }, - reloadManyArray(manyArray, internalModel, key) { - return internalModel.reloadHasMany(key); + reloadManyArray(manyArray, internalModel, key, options) { + return internalModel.reloadHasMany(key, options); }, - reloadBelongsTo(belongsToProxy, internalModel, key) { - return internalModel.reloadBelongsTo(key); + reloadBelongsTo(belongsToProxy, internalModel, key, options) { + return internalModel.reloadBelongsTo(key, options); }, _relationshipMetaFor(modelName, id, key) { diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index c8ce17a0ddb..818cf9aa566 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -433,7 +433,10 @@ test('value() returns the referenced record when loaded even if links are presen test('load() fetches the record', function(assert) { var done = assert.async(); - env.adapter.findRecord = function(store, type, id) { + const adapterOptions = { thing: 'one' }; + + env.adapter.findRecord = function(store, type, id, snapshot) { + assert.equal(snapshot.adapterOptions, adapterOptions, 'adapterOptions are passed in'); return resolve({ data: { id: 1, @@ -461,7 +464,7 @@ test('load() fetches the record', function(assert) { var familyReference = person.belongsTo('family'); run(function() { - familyReference.load().then(function(record) { + familyReference.load({ adapterOptions }).then(function(record) { assert.equal(get(record, 'name'), 'Coreleone'); done(); @@ -472,7 +475,10 @@ test('load() fetches the record', function(assert) { test('load() fetches link when remoteType is link', function(assert) { var done = assert.async(); + const adapterOptions = { thing: 'one' }; + env.adapter.findBelongsTo = function(store, snapshot, link) { + assert.equal(snapshot.adapterOptions, adapterOptions, 'adapterOptions are passed in'); assert.equal(link, '/families/1'); return resolve({ @@ -503,7 +509,7 @@ test('load() fetches link when remoteType is link', function(assert) { assert.equal(familyReference.remoteType(), 'link'); run(function() { - familyReference.load().then(function(record) { + familyReference.load({ adapterOptions }).then(function(record) { assert.equal(get(record, 'name'), 'Coreleone'); done(); @@ -514,8 +520,12 @@ test('load() fetches link when remoteType is link', function(assert) { test('reload() - loads the record when not yet loaded', function(assert) { var done = assert.async(); + const adapterOptions = { thing: 'one' }; + var count = 0; - env.adapter.findRecord = function(store, type, id) { + env.adapter.findRecord = function(store, type, id, snapshot) { + assert.equal(snapshot.adapterOptions, adapterOptions, 'adapterOptions are passed in'); + count++; assert.equal(count, 1); @@ -546,7 +556,7 @@ test('reload() - loads the record when not yet loaded', function(assert) { var familyReference = person.belongsTo('family'); run(function() { - familyReference.reload().then(function(record) { + familyReference.reload({ adapterOptions }).then(function(record) { assert.equal(get(record, 'name'), 'Coreleone'); done(); @@ -557,8 +567,12 @@ test('reload() - loads the record when not yet loaded', function(assert) { test('reload() - reloads the record when already loaded', function(assert) { var done = assert.async(); + const adapterOptions = { thing: 'one' }; + var count = 0; - env.adapter.findRecord = function(store, type, id) { + env.adapter.findRecord = function(store, type, id, snapshot) { + assert.equal(snapshot.adapterOptions, adapterOptions, 'adapterOptions are passed in'); + count++; assert.equal(count, 1); @@ -595,7 +609,7 @@ test('reload() - reloads the record when already loaded', function(assert) { var familyReference = person.belongsTo('family'); run(function() { - familyReference.reload().then(function(record) { + familyReference.reload({ adapterOptions }).then(function(record) { assert.equal(get(record, 'name'), 'Coreleone'); done(); @@ -606,7 +620,11 @@ test('reload() - reloads the record when already loaded', function(assert) { test('reload() - uses link to reload record', function(assert) { var done = assert.async(); + const adapterOptions = { thing: 'one' }; + env.adapter.findBelongsTo = function(store, snapshot, link) { + assert.equal(snapshot.adapterOptions, adapterOptions, 'adapterOptions are passed in'); + assert.equal(link, '/families/1'); return resolve({ @@ -636,7 +654,7 @@ test('reload() - uses link to reload record', function(assert) { var familyReference = person.belongsTo('family'); run(function() { - familyReference.reload().then(function(record) { + familyReference.reload({ adapterOptions }).then(function(record) { assert.equal(get(record, 'name'), 'Coreleone'); done(); diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 3491a24fbb8..76c06b30cf5 100755 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -429,7 +429,10 @@ test('_isLoaded() returns an true array when the reference is loaded and empty', test('load() fetches the referenced records', function(assert) { var done = assert.async(); - env.adapter.findMany = function(store, type, id) { + const adapterOptions = { thing: 'one' }; + + env.adapter.findMany = function(store, type, id, snapshots) { + assert.equal(snapshots[0].adapterOptions, adapterOptions, 'adapterOptions are passed in'); return resolve({ data: [ { id: 1, type: 'person', attributes: { name: 'Vito' } }, @@ -456,7 +459,7 @@ test('load() fetches the referenced records', function(assert) { var personsReference = family.hasMany('persons'); run(function() { - personsReference.load().then(function(records) { + personsReference.load({ adapterOptions }).then(function(records) { assert.ok(records instanceof DS.ManyArray, 'push resolves with the referenced records'); assert.equal(get(records, 'length'), 2); assert.equal(records.objectAt(0).get('name'), 'Vito'); @@ -470,7 +473,10 @@ test('load() fetches the referenced records', function(assert) { test('load() fetches link when remoteType is link', function(assert) { var done = assert.async(); + const adapterOptions = { thing: 'one' }; + env.adapter.findHasMany = function(store, snapshot, link) { + assert.equal(snapshot.adapterOptions, adapterOptions, 'adapterOptions are passed in'); assert.equal(link, '/families/1/persons'); return resolve({ @@ -500,7 +506,7 @@ test('load() fetches link when remoteType is link', function(assert) { assert.equal(personsReference.remoteType(), 'link'); run(function() { - personsReference.load().then(function(records) { + personsReference.load({ adapterOptions }).then(function(records) { assert.ok(records instanceof DS.ManyArray, 'push resolves with the referenced records'); assert.equal(get(records, 'length'), 2); assert.equal(records.objectAt(0).get('name'), 'Vito'); @@ -512,7 +518,10 @@ test('load() fetches link when remoteType is link', function(assert) { }); test('load() fetches link when remoteType is link but an empty set of records is returned', function(assert) { + const adapterOptions = { thing: 'one' }; + env.adapter.findHasMany = function(store, snapshot, link) { + assert.equal(snapshot.adapterOptions, adapterOptions, 'adapterOptions are passed in'); assert.equal(link, '/families/1/persons'); return resolve({ data: [] }); @@ -537,7 +546,7 @@ test('load() fetches link when remoteType is link but an empty set of records is assert.equal(personsReference.remoteType(), 'link'); return run(() => { - return personsReference.load().then(records => { + return personsReference.load({ adapterOptions }).then(records => { assert.ok(records instanceof DS.ManyArray, 'push resolves with the referenced records'); assert.equal(get(records, 'length'), 0); assert.equal(get(personsReference.value(), 'length'), 0); @@ -603,7 +612,10 @@ test('load() - only a single find is triggered', function(assert) { test('reload()', function(assert) { var done = assert.async(); - env.adapter.findMany = function(store, type, id) { + const adapterOptions = { thing: 'one' }; + + env.adapter.findMany = function(store, type, id, snapshots) { + assert.equal(snapshots[0].adapterOptions, adapterOptions, 'adapterOptions are passed in'); return resolve({ data: [ { id: 1, type: 'person', attributes: { name: 'Vito Coreleone' } }, @@ -632,7 +644,7 @@ test('reload()', function(assert) { var personsReference = family.hasMany('persons'); run(function() { - personsReference.reload().then(function(records) { + personsReference.reload({ adapterOptions }).then(function(records) { assert.ok(records instanceof DS.ManyArray, 'push resolves with the referenced records'); assert.equal(get(records, 'length'), 2); assert.equal(records.objectAt(0).get('name'), 'Vito Coreleone'); @@ -645,9 +657,11 @@ test('reload()', function(assert) { test('reload() fetches link when remoteType is link', function(assert) { var done = assert.async(); + const adapterOptions = { thing: 'one' }; var count = 0; env.adapter.findHasMany = function(store, snapshot, link) { + assert.equal(snapshot.adapterOptions, adapterOptions, 'adapterOptions are passed in'); count++; assert.equal(link, '/families/1/persons'); @@ -688,9 +702,9 @@ test('reload() fetches link when remoteType is link', function(assert) { run(function() { personsReference - .load() + .load({ adapterOptions }) .then(function() { - return personsReference.reload(); + return personsReference.reload({ adapterOptions }); }) .then(function(records) { assert.ok(records instanceof DS.ManyArray, 'push resolves with the referenced records'); From e17365afad9492f9024cb56958e97e86db712f62 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 14 Sep 2018 10:52:14 -0700 Subject: [PATCH 2338/2527] Release Ember Data 3.4.1 --- CHANGELOG.md | 13 +++++++++++++ package.json | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb62ddcd2b9..db8308d1659 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ ### Master +### Release 3.4.1 (September 14, 2018) +- [#5621](https://github.com/emberjs/data/pull/5621) Add partner test for the ilios frontend +- [#5589](https://github.com/emberjs/data/pull/5589) fix broken link because the new API website does not support the anchor +- [#5582](https://github.com/emberjs/data/pull/5582) [BUGFIX] Reference.reload should not cause sync-relationship assertion (#5582) +- [#5584](https://github.com/emberjs/data/pull/5584) Additional test coverage for async belongsTo mutation (#5584) +- [#5592](https://github.com/emberjs/data/pull/5592) Grammar fixes +- [#5602](https://github.com/emberjs/data/pull/5602) Publish docs to npm (#5602) +- [#5620](https://github.com/emberjs/data/pull/5620) [DOC release] Change misleading documentation for AdapterPopulatedRecordArray +- [#5622](https://github.com/emberjs/data/pull/5622) remove deletes (#5622) +- [#5624](https://github.com/emberjs/data/pull/5624) [BUGFIX] fix promise labels +- [#5627](https://github.com/emberjs/data/pull/5627) [FEAT adapterOptions] Ensure adapterOptions use is possible throughout (#5627) +- [#5632](https://github.com/emberjs/data/pull/5632) cleanup code climate config + ### Release 3.4.0 (August 27, 2018) - [#5540](https://github.com/emberjs/data/pull/5540) revert is-empty flag change, leave todo (#5540) - [#5545](https://github.com/emberjs/data/pull/5545) [FEAT] TrackableRequests for when async leakage is detected diff --git a/package.json b/package.json index 3fe41673047..46cd104dd1f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "3.6.0-canary", + "version": "3.4.1", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From c0eb4d8a52c7e59e1952aea769226f732c764a27 Mon Sep 17 00:00:00 2001 From: Bill Heaton Date: Fri, 14 Sep 2018 14:27:33 -0700 Subject: [PATCH 2339/2527] Include request/response info with Abort error - Add test for capturing error details --- addon/adapters/rest.js | 11 ++++++++++- tests/integration/adapter/rest-adapter-test.js | 17 ++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index d5c25a003b9..d4f2cf4bfdb 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -1228,7 +1228,7 @@ function ajaxError(adapter, payload, requestData, responseData) { } else if (responseData.textStatus === 'timeout') { error = new TimeoutError(); } else if (responseData.textStatus === 'abort' || responseData.status === 0) { - error = new AbortError(); + error = handleAbort(requestData, responseData); } else { try { error = adapter.handleResponse( @@ -1245,6 +1245,15 @@ function ajaxError(adapter, payload, requestData, responseData) { return error; } +// Adapter abort error to include any relevent info, e.g. request/response: +function handleAbort(requestData, responseData) { + let { method, url, errorThrown } = requestData; + let { status } = responseData; + let msg = `Request failed: ${method} ${url} ${errorThrown || ''}`; + let errors = [{ title: 'Adapter Error', detail: msg.trim(), status }]; + return new AbortError(errors); +} + //From http://stackoverflow.com/questions/280634/endswith-in-javascript function endsWith(string, suffix) { if (typeof String.prototype.endsWith !== 'function') { diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index af83bc8ff4d..cff9708d1da 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -2551,7 +2551,7 @@ test('gracefully handles exceptions in handleResponse where the ajax request err }); test('treats status code 0 as an abort', function(assert) { - assert.expect(1); + assert.expect(3); adapter._ajaxRequest = function(hash) { hash.error({ @@ -2568,6 +2568,21 @@ test('treats status code 0 as an abort', function(assert) { return run(() => { return store.findRecord('post', '1').catch(err => { assert.ok(err instanceof DS.AbortError, 'reason should be an instance of DS.AbortError'); + assert.equal( + err.errors.length, + 1, + 'AbortError includes errors with request/response details' + ); + let expectedError = { + title: 'Adapter Error', + detail: 'Request failed: GET /posts/1', + status: 0, + }; + assert.deepEqual( + err.errors[0], + expectedError, + 'method, url and, status are captured as details' + ); }); }); }); From c839691689142990e3b0af8066caec860b4ebdf2 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 14 Sep 2018 23:16:58 -0700 Subject: [PATCH 2340/2527] [BUGFIX] fix deprecation for store entry methods --- addon/-legacy-private/system/store.js | 2 +- addon/-record-data-private/system/store.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-legacy-private/system/store.js b/addon/-legacy-private/system/store.js index 6795c3375a2..378b1c788e8 100644 --- a/addon/-legacy-private/system/store.js +++ b/addon/-legacy-private/system/store.js @@ -3442,7 +3442,7 @@ if (DEBUG) { if (!store.shouldAssertMethodCallsOnDestroyedStore) { deprecate( `Attempted to call store.${method}(), but the store instance has already been destroyed.`, - !(store.isDestroying || store.isDestroyed), + !store.isDestroyed, { id: 'ember-data:method-calls-on-destroyed-store', until: '3.8', diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index a6ff19fb216..8fa3a46b27c 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -3538,7 +3538,7 @@ if (DEBUG) { if (!store.shouldAssertMethodCallsOnDestroyedStore) { deprecate( `Attempted to call store.${method}(), but the store instance has already been destroyed.`, - !(store.isDestroying || store.isDestroyed), + !store.isDestroyed, { id: 'ember-data:method-calls-on-destroyed-store', until: '3.8', From d739b57d001ee056a9985fa813a9a7f533b4fc13 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Sat, 15 Sep 2018 00:12:53 -0700 Subject: [PATCH 2341/2527] fix version in package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 46cd104dd1f..3fe41673047 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "3.4.1", + "version": "3.6.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { From 584ad77fa9bfc902ddb451d83b238b6f390bd797 Mon Sep 17 00:00:00 2001 From: Balint Erdi Date: Tue, 18 Sep 2018 11:07:48 +0200 Subject: [PATCH 2342/2527] Add a couple of ED-related add-ons as external partner tests --- .travis.yml | 4 ++++ package.json | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6ff3b36f773..ccb2550ca2a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -103,6 +103,10 @@ jobs: script: yarn test-external:factory-guy - name: "Ilios Frontend" script: yarn test-external:ilios-frontend + - name: "Ember Resource Metadata" + script: yarn test-external:ember-resource-metadata + - name: "Ember Data Relationship Tracker" + script: yarn test-external:ember-data-relationship-tracker - stage: deploy name: "Publish" diff --git a/package.json b/package.json index 3fe41673047..78f065e97bb 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,9 @@ "test-external:travis-web": "node ./lib/scripts/test-external travis-web https://github.com/travis-ci/travis-web.git", "test-external:storefront": "node ./lib/scripts/test-external storefront https://github.com/embermap/ember-data-storefront.git", "test-external:factory-guy": "node ./lib/scripts/test-external factory-guy https://github.com/danielspaniel/ember-data-factory-guy.git", - "test-external:ilios-frontend": "node ./lib/scripts/test-external ilios-frontend https://github.com/ilios/frontend.git" + "test-external:ilios-frontend": "node ./lib/scripts/test-external ilios-frontend https://github.com/ilios/frontend.git", + "test-external:ember-resource-metadata": "node ./lib/scripts/test-external ember-resource-metadata https://github.com/ef4/ember-resource-metadata.git", + "test-external:ember-data-relationship-tracker": "node ./lib/scripts/test-external ember-data-relationship-tracker https://github.com/ef4/ember-data-relationship-tracker.git" }, "author": "", "license": "MIT", From 2437b13283316bc18f236a6b5698ee8a737c5b43 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 19 Sep 2018 11:54:41 -0700 Subject: [PATCH 2343/2527] [CHORE] improve CI time by optimizing job order (#5643) * [CHORE] move ilios external-partner test to first in queue * [CHORE] organize all jobs longest to shortest * move production job up a slot * update comments --- .travis.yml | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/.travis.yml b/.travis.yml index ccb2550ca2a..c8f38d0f8a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -54,15 +54,15 @@ jobs: install: yarn install --no-lockfile --non-interactive script: yarn test + - name: "Production" + install: yarn install + script: yarn test:production + - name: "Max Transpilation" install: yarn install env: TARGET_IE11=true script: yarn test - - name: "Production" - install: yarn install - script: yarn test:production - - name: "Node Tests" install: yarn install script: yarn test:node @@ -84,29 +84,31 @@ jobs: env: EMBER_TRY_SCENARIO=ember-canary # runs tests against various open-source projects for early-warning regression analysis + # We typically have 4 concurrent jobs, these jobs below are ordered to optimize total completion time + # By running longer jobs first, we allow the shorter jobs to complete within the same time block in parallel - stage: external partner tests - name: "Ember Data Model Fragments" - script: yarn test-external:model-fragments - - name: "Ember Observer" - script: yarn test-external:ember-observer - - name: "Travis Web" + name: "Ilios Frontend" # ~30min job + script: yarn test-external:ilios-frontend + - name: "Travis Web" # ~10min job script: yarn test-external:travis-web - - name: "emberaddons.com" - script: yarn test-external:emberaddons.com - - name: "Ember Data Change Tracker" - script: yarn test-external:ember-data-change-tracker - - name: "ember-m3" - script: yarn test-external:ember-m3 - - name: "Ember Data Storefront" + - name: "Ember Data Storefront" # ~5min job script: yarn test-external:storefront - - name: "Ember Data Factory Guy" + - name: "Ember Data Factory Guy" # ~5min job script: yarn test-external:factory-guy - - name: "Ilios Frontend" - script: yarn test-external:ilios-frontend - - name: "Ember Resource Metadata" + - name: "Ember Observer" # ~5min job + script: yarn test-external:ember-observer + - name: "Ember Resource Metadata" # ~4.25min job script: yarn test-external:ember-resource-metadata - - name: "Ember Data Relationship Tracker" + - name: "Ember Data Relationship Tracker" # ~4.25min job script: yarn test-external:ember-data-relationship-tracker + - name: "Ember Data Model Fragments" # ~3.5min job + script: yarn test-external:model-fragments + - name: "emberaddons.com" # ~3.5min job + script: yarn test-external:emberaddons.com + - name: "Ember Data Change Tracker" # ~3.5min job + script: yarn test-external:ember-data-change-tracker + - name: "ember-m3" # ~3.5min job + script: yarn test-external:ember-m3 - stage: deploy name: "Publish" From 5de712c24f8420b8b23877d53379d034edcc054c Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 19 Sep 2018 15:02:01 -0700 Subject: [PATCH 2344/2527] [BUGFIX] ensure external-partner tests correctly symlink --- lib/scripts/test-external.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/lib/scripts/test-external.js b/lib/scripts/test-external.js index c1906e108f8..b64ebaf425c 100644 --- a/lib/scripts/test-external.js +++ b/lib/scripts/test-external.js @@ -27,6 +27,11 @@ console.log( `Preparing to test external project ${externalProjectName} located at ${gitUrl} against this ember-data commit.` ); +function execExternal(command, force) { + command = `cd ../__external-test-cache/${externalProjectName} && ${command}`; + return execWithLog(command, force); +} + function execWithLog(command, force) { if (debug.enabled || force) { return shellSync(command, { stdio: [0, 1, 2] }); @@ -45,9 +50,7 @@ if (fs.existsSync(projectTempDir)) { // install the project try { - execWithLog( - `cd ../__external-test-cache && git clone --depth=1 ${gitUrl} ./${externalProjectName}` - ); + execWithLog(`git clone --depth=1 ${gitUrl} ../__external-test-cache/${externalProjectName}`); } catch (e) { debug(e); throw new Error( @@ -60,13 +63,8 @@ const useBower = fs.existsSync(path.join(projectTempDir, 'bower.json')); // install project dependencies and link our local version of ember-data try { - execWithLog( - `${ - useYarn ? 'yarn link' : 'npm link' - } && cd ../__external-test-cache/${externalProjectName} && ${useYarn ? 'yarn' : 'npm install'}${ - useBower ? ' && bower install' : '' - }` - ); + execWithLog(`${useYarn ? 'yarn link' : 'npm link'}`); + execExternal(`${useYarn ? 'yarn' : 'npm install'}${useBower ? ' && bower install' : ''}`); } catch (e) { debug(e); throw new Error( @@ -82,13 +80,13 @@ let commitTestPassed = true; try { debug('Running Smoke Test'); - execWithLog(`cd ../__external-test-cache/${externalProjectName} && ember test`, true); + execExternal(`ember test`, true); } catch (e) { smokeTestPassed = false; } try { - execWithLog(`${useYarn ? 'yarn link ember-data' : 'npm link ember-data'}`); + execExternal(`${useYarn ? 'yarn link ember-data' : 'npm link ember-data'}`); } catch (e) { debug(e); throw new Error( @@ -98,7 +96,7 @@ try { try { debug('Re-running tests against EmberData commit'); - execWithLog(`cd ../__external-test-cache/${externalProjectName} && ember test`, true); + execExternal(`ember test`, true); } catch (e) { commitTestPassed = false; } From 0de3b97fa26400262e490185a72025addecd6022 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 19 Sep 2018 15:32:22 -0700 Subject: [PATCH 2345/2527] fix up module imports --- MODULE_REPORT.md | 1022 -------------------- addon/-legacy-private/system/store.js | 6 +- addon/-private/core.js | 3 +- addon/-private/features.js | 6 +- addon/-private/system/backburner.js | 3 +- addon/-record-data-private/system/store.js | 6 +- addon/index.js | 6 +- lib/calculate-version.js | 6 +- tests/helpers/watch-property.js | 4 +- tests/integration/application-test.js | 6 +- tests/integration/store/query-test.js | 3 +- tests/unit/model-test.js | 8 +- tests/unit/store/peek-record-test.js | 4 +- 13 files changed, 30 insertions(+), 1053 deletions(-) delete mode 100644 MODULE_REPORT.md diff --git a/MODULE_REPORT.md b/MODULE_REPORT.md deleted file mode 100644 index edffb75b083..00000000000 --- a/MODULE_REPORT.md +++ /dev/null @@ -1,1022 +0,0 @@ -## Module Report -### Unknown Global - -**Global**: `Ember.VERSION` - -**Location**: `addon/index.js` at line 11 - -```js -*/ - -if (Ember.VERSION.match(/^1\.([0-9]|1[0-2])\./)) { - throw new EmberError("Ember Data requires at least Ember 1.13.0, but you have " + - Ember.VERSION + -``` - -### Unknown Global - -**Global**: `Ember.VERSION` - -**Location**: `addon/index.js` at line 13 - -```js -if (Ember.VERSION.match(/^1\.([0-9]|1[0-2])\./)) { - throw new EmberError("Ember Data requires at least Ember 1.13.0, but you have " + - Ember.VERSION + - ". Please upgrade your version of Ember, then upgrade Ember Data."); -} -``` - -### Unknown Global - -**Global**: `Ember.MODEL_FACTORY_INJECTIONS` - -**Location**: `addon/-debug/index.js` at line 37 - -```js - return modelClass.__mixin.detect(addedModelClass.PrototypeMixin); - } - if (Ember.MODEL_FACTORY_INJECTIONS) { - modelClass = modelClass.superclass; - } -``` - -### Unknown Global - -**Global**: `Ember.Namespace` - -**Location**: `addon/-private/core.js` at line 20 - -```js - @static -*/ -const DS = Ember.Namespace.create({ - VERSION: VERSION, - name: "DS" -``` - -### Unknown Global - -**Global**: `Ember.libraries` - -**Location**: `addon/-private/core.js` at line 25 - -```js -}); - -if (Ember.libraries) { - Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); -} -``` - -### Unknown Global - -**Global**: `Ember.libraries` - -**Location**: `addon/-private/core.js` at line 26 - -```js - -if (Ember.libraries) { - Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); -} - -``` - -### Unknown Global - -**Global**: `Ember.FEATURES` - -**Location**: `addon/-private/features.js` at line 4 - -```js - -export default function isEnabled() { - return Ember.FEATURES.isEnabled(...arguments); -} - -``` - -### Unknown Global - -**Global**: `Ember.Date` - -**Location**: `addon/transforms/date.js` at line 5 - -```js -import { deprecate } from '@ember/debug'; - -Ember.Date = Ember.Date || {}; - -/** -``` - -### Unknown Global - -**Global**: `Ember.Date` - -**Location**: `addon/transforms/date.js` at line 5 - -```js -import { deprecate } from '@ember/debug'; - -Ember.Date = Ember.Date || {}; - -/** -``` - -### Unknown Global - -**Global**: `Ember.Date` - -**Location**: `addon/transforms/date.js` at line 19 - -```js - @deprecated - */ -Ember.Date.parse = function(date) { - // throw deprecation - deprecate(`Ember.Date.parse is deprecated because Safari 5-, IE8-, and -``` - -### Unknown Global - -**Global**: `Ember.OrderedSet` - -**Location**: `addon/-private/system/ordered-set.js` at line 4 - -```js -import Ember from 'ember'; - -const EmberOrderedSet = Ember.OrderedSet; - -export default function OrderedSet() { -``` - -### Unknown Global - -**Global**: `Ember.OrderedSet` - -**Location**: `addon/-private/system/ordered-set.js` at line 4 - -```js -import Ember from 'ember'; - -const EmberOrderedSet = Ember.OrderedSet; - -export default function OrderedSet() { -``` - -### Unknown Global - -**Global**: `Ember.ENV` - -**Location**: `tests/unit/store/adapter-interop-test.js` at line 23 - -```js - beforeEach() { - TestAdapter = DS.Adapter.extend(); - oldFilterEnabled = Ember.ENV.ENABLE_DS_FILTER; - Ember.ENV.ENABLE_DS_FILTER = false; - }, -``` - -### Unknown Global - -**Global**: `Ember.ENV` - -**Location**: `tests/unit/store/adapter-interop-test.js` at line 24 - -```js - TestAdapter = DS.Adapter.extend(); - oldFilterEnabled = Ember.ENV.ENABLE_DS_FILTER; - Ember.ENV.ENABLE_DS_FILTER = false; - }, - -``` - -### Unknown Global - -**Global**: `Ember.ENV` - -**Location**: `tests/unit/store/adapter-interop-test.js` at line 30 - -```js - run(() => { - if (store) { store.destroy(); } - Ember.ENV.ENABLE_DS_FILTER = oldFilterEnabled; - }); - } -``` - -### Unknown Global - -**Global**: `Ember.ENV` - -**Location**: `tests/unit/store/push-test.js` at line 715 - -```js -testInDebug('Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown attributes', function(assert) { - run(() => { - let originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; - try { - Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; -``` - -### Unknown Global - -**Global**: `Ember.ENV` - -**Location**: `tests/unit/store/push-test.js` at line 717 - -```js - let originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; - try { - Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; - assert.expectWarning(() => { - store.push({ -``` - -### Unknown Global - -**Global**: `Ember.ENV` - -**Location**: `tests/unit/store/push-test.js` at line 732 - -```js - }, `The payload for 'person' contains these unknown attributes: emailAddress,isMascot. Make sure they've been defined in your model.`); - } finally { - Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = originalFlagValue; - } - }); -``` - -### Unknown Global - -**Global**: `Ember.ENV` - -**Location**: `tests/unit/store/push-test.js` at line 739 - -```js -testInDebug('Enabling Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS should warn on unknown relationships', function(assert) { - run(() => { - var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; - try { - Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; -``` - -### Unknown Global - -**Global**: `Ember.ENV` - -**Location**: `tests/unit/store/push-test.js` at line 741 - -```js - var originalFlagValue = Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS; - try { - Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = true; - assert.expectWarning(() => { - store.push({ -``` - -### Unknown Global - -**Global**: `Ember.ENV` - -**Location**: `tests/unit/store/push-test.js` at line 756 - -```js - }, `The payload for 'person' contains these unknown relationships: emailAddresses,mascots. Make sure they've been defined in your model.`); - } finally { - Ember.ENV.DS_WARN_ON_UNKNOWN_KEYS = originalFlagValue; - } - }); -``` - -### Unknown Global - -**Global**: `Ember.Date` - -**Location**: `tests/unit/transform/date-test.js` at line 61 - -```js -testInDebug('Ember.Date.parse has been deprecated', function(assert) { - assert.expectDeprecation(() => { - Ember.Date.parse(dateString); - }, /Ember.Date.parse is deprecated/); -}); -``` - -### Unknown Global - -**Global**: `Ember.ENV` - -**Location**: `addon/-private/system/store.js` at line 61 - -```js -const { - _Backburner: Backburner, - ENV -} = Ember; - -``` - -### Unknown Global - -**Global**: `Ember._Backburner` - -**Location**: `addon/-private/system/store.js` at line 60 - -```js - -const { - _Backburner: Backburner, - ENV -} = Ember; -``` - -### Unknown Global - -**Global**: `Ember.GUID_KEY` - -**Location**: `addon/-private/system/model/internal-model.js` at line 126 - -```js - - // this ensure ordered set can quickly identify this as unique - this[Ember.GUID_KEY] = InternalModelReferenceId++ + 'internal-model'; - - this.store = store; -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `addon/-private/system/model/internal-model.js` at line 495 - -```js - // TODO: use run.schedule once we drop 1.13 - if (!run.currentRunLoop) { - assert('You have turned on testing mode, which disabled the run-loop\'s autorun.\n You will need to wrap any code with asynchronous side-effects in a run', Ember.testing); - } - this._scheduledDestroy = run.backburner.schedule('destroy', this, '_checkForOrphanedInternalModels') -``` - -### Unknown Global - -**Global**: `Ember.beginPropertyChanges` - -**Location**: `addon/-private/system/model/model.js` at line 640 - -```js - */ - _notifyProperties(keys) { - Ember.beginPropertyChanges(); - let key; - for (let i = 0, length = keys.length; i < length; i++) { -``` - -### Unknown Global - -**Global**: `Ember.endPropertyChanges` - -**Location**: `addon/-private/system/model/model.js` at line 646 - -```js - this.notifyPropertyChange(key); - } - Ember.endPropertyChanges(); - }, - -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `addon/-private/system/relationships/ext.js` at line 13 - -```js - -export const relationshipsDescriptor = computed(function() { - if (Ember.testing === true && relationshipsDescriptor._cacheable === true) { - relationshipsDescriptor._cacheable = false; - } -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `addon/-private/system/relationships/ext.js` at line 40 - -```js - -export const relatedTypesDescriptor = computed(function() { - if (Ember.testing === true && relatedTypesDescriptor._cacheable === true) { - relatedTypesDescriptor._cacheable = false; - } -``` - -### Unknown Global - -**Global**: `Ember.Logger` - -**Location**: `tests/test-helper.js` at line 42 - -```js - // handle the error. - if (reason && reason instanceof Error) { - Ember.Logger.log(reason, reason.stack); - throw reason; - } -``` - -### Unknown Global - -**Global**: `Ember.MODEL_FACTORY_INJECTIONS` - -**Location**: `tests/helpers/model-factory-injection.js` at line 4 - -```js -import hasEmberVersion from 'ember-test-helpers/has-ember-version'; - -const ORIGINAL_MODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS; - -export function setup(value) { -``` - -### Unknown Global - -**Global**: `Ember.MODEL_FACTORY_INJECTIONS` - -**Location**: `tests/helpers/model-factory-injection.js` at line 4 - -```js -import hasEmberVersion from 'ember-test-helpers/has-ember-version'; - -const ORIGINAL_MODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS; - -export function setup(value) { -``` - -### Unknown Global - -**Global**: `Ember.MODEL_FACTORY_INJECTIONS` - -**Location**: `tests/helpers/model-factory-injection.js` at line 14 - -```js - - if (!hasEmberVersion(2, 14)) { - Ember.MODEL_FACTORY_INJECTIONS = value; - } -} -``` - -### Unknown Global - -**Global**: `Ember._RegistryProxyMixin` - -**Location**: `tests/helpers/owner.js` at line 6 - -```js -let Owner; - -if (Ember._RegistryProxyMixin && Ember._ContainerProxyMixin) { - Owner = EmberObject.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin); -} else { -``` - -### Unknown Global - -**Global**: `Ember._ContainerProxyMixin` - -**Location**: `tests/helpers/owner.js` at line 6 - -```js -let Owner; - -if (Ember._RegistryProxyMixin && Ember._ContainerProxyMixin) { - Owner = EmberObject.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin); -} else { -``` - -### Unknown Global - -**Global**: `Ember._RegistryProxyMixin` - -**Location**: `tests/helpers/owner.js` at line 7 - -```js - -if (Ember._RegistryProxyMixin && Ember._ContainerProxyMixin) { - Owner = EmberObject.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin); -} else { - Owner = EmberObject.extend(); -``` - -### Unknown Global - -**Global**: `Ember._ContainerProxyMixin` - -**Location**: `tests/helpers/owner.js` at line 7 - -```js - -if (Ember._RegistryProxyMixin && Ember._ContainerProxyMixin) { - Owner = EmberObject.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin); -} else { - Owner = EmberObject.extend(); -``` - -### Unknown Global - -**Global**: `Ember.__loader` - -**Location**: `tests/helpers/setup-ember-dev.js` at line 9 - -```js -// Maintain backwards compatiblity with older versions of ember. -let emberDebugModule; -if (Ember.__loader && Ember.__loader.registry && Ember.__loader.registry["ember-metal/debug"]) { - emberDebugModule = Ember.__loader.require('ember-metal/debug'); -} -``` - -### Unknown Global - -**Global**: `Ember.__loader` - -**Location**: `tests/helpers/setup-ember-dev.js` at line 9 - -```js -// Maintain backwards compatiblity with older versions of ember. -let emberDebugModule; -if (Ember.__loader && Ember.__loader.registry && Ember.__loader.registry["ember-metal/debug"]) { - emberDebugModule = Ember.__loader.require('ember-metal/debug'); -} -``` - -### Unknown Global - -**Global**: `Ember.__loader` - -**Location**: `tests/helpers/setup-ember-dev.js` at line 9 - -```js -// Maintain backwards compatiblity with older versions of ember. -let emberDebugModule; -if (Ember.__loader && Ember.__loader.registry && Ember.__loader.registry["ember-metal/debug"]) { - emberDebugModule = Ember.__loader.require('ember-metal/debug'); -} -``` - -### Unknown Global - -**Global**: `Ember.__loader` - -**Location**: `tests/helpers/setup-ember-dev.js` at line 10 - -```js -let emberDebugModule; -if (Ember.__loader && Ember.__loader.registry && Ember.__loader.registry["ember-metal/debug"]) { - emberDebugModule = Ember.__loader.require('ember-metal/debug'); -} - -``` - -### Unknown Global - -**Global**: `Ember.name` - -**Location**: `tests/helpers/setup-ember-dev.js` at line 17 - -```js - return emberDebugModule.getDebugFunction(name); - } else { - return Ember[name]; - } -} -``` - -### Unknown Global - -**Global**: `Ember.name` - -**Location**: `tests/helpers/setup-ember-dev.js` at line 25 - -```js - emberDebugModule.setDebugFunction(name, func); - } else { - Ember[name] = func; - } -} -``` - -### Unknown Global - -**Global**: `Ember.Registry` - -**Location**: `tests/helpers/store.js` at line 11 - -```js - options = options || {}; - - if (Ember.Registry) { - registry = env.registry = new Ember.Registry(); - owner = Owner.create({ -``` - -### Unknown Global - -**Global**: `Ember.Registry` - -**Location**: `tests/helpers/store.js` at line 12 - -```js - - if (Ember.Registry) { - registry = env.registry = new Ember.Registry(); - owner = Owner.create({ - __registry__: registry -``` - -### Unknown Global - -**Global**: `Ember.Container` - -**Location**: `tests/helpers/store.js` at line 21 - -```js - owner.__container__ = container; - } else { - container = env.container = new Ember.Container(); - registry = env.registry = container; - } -``` - -### Unknown Global - -**Global**: `Ember.Namespace` - -**Location**: `tests/integration/application-test.js` at line 13 - -```js - -const Store = DS.Store; -const Namespace = Ember.Namespace; - -let app, App, container; -``` - -### Unknown Global - -**Global**: `Ember.Namespace` - -**Location**: `tests/integration/application-test.js` at line 13 - -```js - -const Store = DS.Store; -const Namespace = Ember.Namespace; - -let app, App, container; -``` - -### Unknown Global - -**Global**: `Ember.BOOTED` - -**Location**: `tests/integration/application-test.js` at line 47 - -```js - afterEach() { - run(app, app.destroy); - Ember.BOOTED = false; - } -}); -``` - -### Unknown Global - -**Global**: `Ember.BOOTED` - -**Location**: `tests/integration/application-test.js` at line 87 - -```js - afterEach() { - run(app, 'destroy'); - Ember.BOOTED = false; - } -}); -``` - -### Unknown Global - -**Global**: `Ember.inject` - -**Location**: `tests/integration/application-test.js` at line 108 - -```js -}); - -if (Ember.inject && service) { - module("integration/application - Using the store as a service", { - beforeEach() { -``` - -### Unknown Global - -**Global**: `Ember.BOOTED` - -**Location**: `tests/integration/application-test.js` at line 122 - -```js - afterEach() { - run(app, 'destroy'); - Ember.BOOTED = false; - } - }); -``` - -### Unknown Global - -**Global**: `Ember.BOOTED` - -**Location**: `tests/integration/application-test.js` at line 143 - -```js - run(app, app.destroy); - } - Ember.BOOTED = false; - } -}); -``` - -### Unknown Global - -**Global**: `Ember.OrderedSet` - -**Location**: `tests/integration/record-array-manager-test.js` at line 307 - -```js - let record = {}; - let internalModel = { - _recordArrays: new Ember.OrderedSet(), - getRecord() { - return record; -``` - -### Unknown Global - -**Global**: `Ember.Registry` - -**Location**: `tests/unit/model-test.js` at line 1001 - -```js - - let registry, container; - if (Ember.Registry) { - registry = new Ember.Registry(); - container = registry.container(); -``` - -### Unknown Global - -**Global**: `Ember.Registry` - -**Location**: `tests/unit/model-test.js` at line 1002 - -```js - let registry, container; - if (Ember.Registry) { - registry = new Ember.Registry(); - container = registry.container(); - } else { -``` - -### Unknown Global - -**Global**: `Ember.Container` - -**Location**: `tests/unit/model-test.js` at line 1005 - -```js - container = registry.container(); - } else { - container = new Ember.Container(); - registry = container; - } -``` - -### Unknown Global - -**Global**: `Ember.Registry` - -**Location**: `tests/unit/model-test.js` at line 1035 - -```js - - let registry, container; - if (Ember.Registry) { - registry = new Ember.Registry(); - container = registry.container(); -``` - -### Unknown Global - -**Global**: `Ember.Registry` - -**Location**: `tests/unit/model-test.js` at line 1036 - -```js - let registry, container; - if (Ember.Registry) { - registry = new Ember.Registry(); - container = registry.container(); - } else { -``` - -### Unknown Global - -**Global**: `Ember.Container` - -**Location**: `tests/unit/model-test.js` at line 1039 - -```js - container = registry.container(); - } else { - container = new Ember.Container(); - registry = container; - } -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `tests/integration/relationships/belongs-to-test.js` at line 547 - -```js -test("relationshipsByName is cached in production", function(assert) { - let model = store.modelFor('user'); - let oldTesting = Ember.testing; - //We set the cacheable to true because that is the default state for any CP and then assert that it - //did not get dynamically changed when accessed -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `tests/integration/relationships/belongs-to-test.js` at line 565 - -```js -test("relatedTypes is cached in production", function(assert) { - let model = store.modelFor('user'); - let oldTesting = Ember.testing; - //We set the cacheable to true because that is the default state for any CP and then assert that it - //did not get dynamically changed when accessed -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `tests/integration/relationships/belongs-to-test.js` at line 583 - -```js -test("relationships is cached in production", function(assert) { - let model = store.modelFor('user'); - let oldTesting = Ember.testing; - //We set the cacheable to true because that is the default state for any CP and then assert that it - //did not get dynamically changed when accessed -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `tests/integration/relationships/belongs-to-test.js` at line 547 - -```js -test("relationshipsByName is cached in production", function(assert) { - let model = store.modelFor('user'); - let oldTesting = Ember.testing; - //We set the cacheable to true because that is the default state for any CP and then assert that it - //did not get dynamically changed when accessed -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `tests/integration/relationships/belongs-to-test.js` at line 553 - -```js - let oldCacheable = relationshipsByName._cacheable; - relationshipsByName._cacheable = true; - Ember.testing = false; - try { - assert.equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached'); -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `tests/integration/relationships/belongs-to-test.js` at line 558 - -```js - assert.equal(get(model, 'relationshipsByName'), get(model, 'relationshipsByName'), 'relationshipsByName are cached'); - } finally { - Ember.testing = oldTesting; - relationshipsByName._cacheable = oldCacheable; - } -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `tests/integration/relationships/belongs-to-test.js` at line 565 - -```js -test("relatedTypes is cached in production", function(assert) { - let model = store.modelFor('user'); - let oldTesting = Ember.testing; - //We set the cacheable to true because that is the default state for any CP and then assert that it - //did not get dynamically changed when accessed -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `tests/integration/relationships/belongs-to-test.js` at line 571 - -```js - let oldCacheable = relatedTypes._cacheable; - relatedTypes._cacheable = true; - Ember.testing = false; - try { - assert.equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached'); -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `tests/integration/relationships/belongs-to-test.js` at line 576 - -```js - assert.equal(get(model, 'relatedTypes'), get(model, 'relatedTypes'), 'relatedTypes are cached'); - } finally { - Ember.testing = oldTesting; - relatedTypes._cacheable = oldCacheable; - } -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `tests/integration/relationships/belongs-to-test.js` at line 583 - -```js -test("relationships is cached in production", function(assert) { - let model = store.modelFor('user'); - let oldTesting = Ember.testing; - //We set the cacheable to true because that is the default state for any CP and then assert that it - //did not get dynamically changed when accessed -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `tests/integration/relationships/belongs-to-test.js` at line 589 - -```js - let oldCacheable = relationships._cacheable; - relationships._cacheable = true; - Ember.testing = false; - try { - assert.equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached'); -``` - -### Unknown Global - -**Global**: `Ember.testing` - -**Location**: `tests/integration/relationships/belongs-to-test.js` at line 594 - -```js - assert.equal(get(model, 'relationships'), get(model, 'relationships'), 'relationships are cached'); - } finally { - Ember.testing = oldTesting; - relationships._cacheable = oldCacheable; - } -``` diff --git a/addon/-legacy-private/system/store.js b/addon/-legacy-private/system/store.js index 378b1c788e8..e0e61c1a94d 100644 --- a/addon/-legacy-private/system/store.js +++ b/addon/-legacy-private/system/store.js @@ -2,6 +2,8 @@ @module ember-data */ +import { registerWaiter, unregisterWaiter } from '@ember/test'; + import { A } from '@ember/array'; import EmberError from '@ember/error'; import MapWithDefault from './map-with-default'; @@ -270,7 +272,7 @@ Store = Service.extend({ return shouldTrack !== true || isSettled; }; - Ember.Test.registerWaiter(this.__asyncWaiter); + registerWaiter(this.__asyncWaiter); } }, @@ -3004,7 +3006,7 @@ Store = Service.extend({ this.unloadAll(); if (DEBUG) { - Ember.Test.unregisterWaiter(this.__asyncWaiter); + unregisterWaiter(this.__asyncWaiter); let shouldTrack = this.shouldTrackAsyncRequests; let tracked = this._trackedAsyncRequests; let isSettled = tracked.length === 0; diff --git a/addon/-private/core.js b/addon/-private/core.js index 70816f3c203..4e81db312a2 100644 --- a/addon/-private/core.js +++ b/addon/-private/core.js @@ -1,3 +1,4 @@ +import Namespace from '@ember/application/namespace'; import Ember from 'ember'; import VERSION from 'ember-data/version'; @@ -17,7 +18,7 @@ import VERSION from 'ember-data/version'; @type String @static */ -const DS = Ember.Namespace.create({ +const DS = Namespace.create({ VERSION: VERSION, name: 'DS', }); diff --git a/addon/-private/features.js b/addon/-private/features.js index 8e023905a04..3e34adff8c3 100644 --- a/addon/-private/features.js +++ b/addon/-private/features.js @@ -1,5 +1,5 @@ -import Ember from 'ember'; +import { isEnabled } from '@ember/canary-features'; -export default function isEnabled() { - return Ember.FEATURES.isEnabled(...arguments); +export default function featureIsEnabled() { + return isEnabled(...arguments); } diff --git a/addon/-private/system/backburner.js b/addon/-private/system/backburner.js index 7ac43f9b390..fbf3ffdea4a 100644 --- a/addon/-private/system/backburner.js +++ b/addon/-private/system/backburner.js @@ -1,3 +1,4 @@ +import { registerWaiter } from '@ember/test'; import Ember from 'ember'; import { DEBUG } from '@glimmer/env'; @@ -8,7 +9,7 @@ const backburner = new Ember._Backburner([ ]); if (DEBUG) { - Ember.Test.registerWaiter(() => { + registerWaiter(() => { return !backburner.currentInstance && !backburner.hasTimers(); }); } diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index 8fa3a46b27c..aba06158884 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -1,6 +1,8 @@ /** @module ember-data */ +import { registerWaiter, unregisterWaiter } from '@ember/test'; + import { A } from '@ember/array'; import EmberError from '@ember/error'; import MapWithDefault from './map-with-default'; @@ -277,7 +279,7 @@ Store = Service.extend({ return shouldTrack !== true || isSettled; }; - Ember.Test.registerWaiter(this.__asyncWaiter); + registerWaiter(this.__asyncWaiter); } }, @@ -3241,7 +3243,7 @@ Store = Service.extend({ this.unloadAll(); if (DEBUG) { - Ember.Test.unregisterWaiter(this.__asyncWaiter); + unregisterWaiter(this.__asyncWaiter); let shouldTrack = this.shouldTrackAsyncRequests; let tracked = this._trackedAsyncRequests; let isSettled = tracked.length === 0; diff --git a/addon/index.js b/addon/index.js index 0064e81d076..081a24bf967 100644 --- a/addon/index.js +++ b/addon/index.js @@ -1,5 +1,5 @@ +import { VERSION } from '@ember/version'; import EmberError from '@ember/error'; -import Ember from 'ember'; /** Ember Data @@ -7,10 +7,10 @@ import Ember from 'ember'; @main ember-data */ -if (Ember.VERSION.match(/^1\.([0-9]|1[0-2])\./)) { +if (VERSION.match(/^1\.([0-9]|1[0-2])\./)) { throw new EmberError( 'Ember Data requires at least Ember 1.13.0, but you have ' + - Ember.VERSION + + VERSION + '. Please upgrade your version of Ember, then upgrade Ember Data.' ); } diff --git a/lib/calculate-version.js b/lib/calculate-version.js index 4ad045dd94f..4aab74ba2ed 100644 --- a/lib/calculate-version.js +++ b/lib/calculate-version.js @@ -5,8 +5,8 @@ var npmGitInfo = require('npm-git-info'); module.exports = function() { var gitPath = path.join(__dirname, '..', '.git'); - var package = require('../package.json'); - var packageVersion = package.version; + var pkg = require('../package.json'); + var packageVersion = pkg.version; var suffix = ''; var info; @@ -18,7 +18,7 @@ module.exports = function() { suffix = '+' + info.sha.slice(0, 10); } else { - info = npmGitInfo(package); + info = npmGitInfo(pkg); if (info.isInstalledAsNpmPackage() && !info.hasVersionInRef()) { suffix = '+' + info.abbreviatedSha; } diff --git a/tests/helpers/watch-property.js b/tests/helpers/watch-property.js index d8df6e9e898..8a210b9a4d0 100644 --- a/tests/helpers/watch-property.js +++ b/tests/helpers/watch-property.js @@ -1,8 +1,6 @@ -import Ember from 'ember'; +import { removeObserver, addObserver } from '@ember/object/observers'; import QUnit from 'qunit'; -const { addObserver, removeObserver } = Ember; - function makeCounter() { let count = 0; const counter = Object.create(null); diff --git a/tests/integration/application-test.js b/tests/integration/application-test.js index fdbcc0ed0d3..25132ace179 100644 --- a/tests/integration/application-test.js +++ b/tests/integration/application-test.js @@ -1,3 +1,4 @@ +import Namespace from '@ember/application/namespace'; import Service, { inject as service } from '@ember/service'; import Controller from '@ember/controller'; import Application from '@ember/application'; @@ -9,7 +10,6 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; const Store = DS.Store; -const Namespace = Ember.Namespace; let app, App, container; @@ -43,7 +43,6 @@ module('integration/application - Injecting a Custom Store', { afterEach() { run(app, app.destroy); - Ember.BOOTED = false; }, }); @@ -83,7 +82,6 @@ module('integration/application - Injecting the Default Store', { afterEach() { run(app, 'destroy'); - Ember.BOOTED = false; }, }); @@ -118,7 +116,6 @@ if (Ember.inject && service) { afterEach() { run(app, 'destroy'); - Ember.BOOTED = false; }, }); @@ -139,7 +136,6 @@ module('integration/application - Attaching initializer', { if (app) { run(app, app.destroy); } - Ember.BOOTED = false; }, }); diff --git a/tests/integration/store/query-test.js b/tests/integration/store/query-test.js index 911fa49706c..411e2aac19a 100644 --- a/tests/integration/store/query-test.js +++ b/tests/integration/store/query-test.js @@ -1,5 +1,5 @@ +import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import RSVP from 'rsvp'; import { module, test } from 'qunit'; @@ -7,7 +7,6 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; var Person, store, env; -var run = Ember.run; module('integration/store/query', { beforeEach() { diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 22fcbc35d1e..8c8f87ba250 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -672,7 +672,7 @@ test('supports canonical updates via pushedData in root.deleted.saved', function adapter.shouldBackgroundReloadRecord = () => false; adapter.deleteRecord = () => { - return Ember.RSVP.resolve(); + return resolve(); }; let record = run(() => @@ -733,7 +733,7 @@ test('Does not support dirtying in root.deleted.saved', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; adapter.deleteRecord = () => { - return Ember.RSVP.resolve(); + return resolve(); }; let record = run(() => @@ -1640,8 +1640,8 @@ test('ID mutation (complicated)', function(assert) { let idChange = 0; const Person = DS.Model.extend({ name: DS.attr('string'), - idComputed: Ember.computed('id', function() {}), - idDidChange: Ember.observer('id', () => idChange++), + idComputed: computed('id', function() {}), + idDidChange: observer('id', () => idChange++), }); let { store } = setupStore({ diff --git a/tests/unit/store/peek-record-test.js b/tests/unit/store/peek-record-test.js index 4c8fb61bc03..f3feee116ee 100644 --- a/tests/unit/store/peek-record-test.js +++ b/tests/unit/store/peek-record-test.js @@ -1,6 +1,6 @@ +import EmberObject from '@ember/object'; import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; @@ -64,7 +64,7 @@ testInDebug('peekRecord should assert if passed a model class instead of model n ) { run(() => { assert.expectAssertion(() => { - let modelClass = Ember.Object.extend(); + let modelClass = EmberObject.extend(); store.peekRecord(modelClass, 'id'); }, /Passing classes to store methods has been removed/); }); From 87410d8d5a9dbea2082f67f384dbdc46b7577044 Mon Sep 17 00:00:00 2001 From: Cyrille David Date: Wed, 8 Aug 2018 14:09:05 +0200 Subject: [PATCH 2346/2527] Unskip adapter tests * with upgrading ember-cli-blueprint-test-helpers --- node-tests/blueprints/adapter-test.js | 138 +++++++++++++++----------- package.json | 3 +- yarn.lock | 20 ++-- 3 files changed, 85 insertions(+), 76 deletions(-) diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index ce3d75b8ef9..03c03eed6eb 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -9,7 +9,6 @@ const modifyPackages = blueprintHelpers.modifyPackages; const chai = require('ember-cli-blueprint-test-helpers/chai'); const expect = chai.expect; -const fs = require('fs-extra'); const SilentError = require('silent-error'); @@ -136,86 +135,97 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { }); }); - describe.skip('module unification', function() { + describe('module unification', function() { beforeEach(function() { - return emberNew().then(() => fs.ensureDirSync('src')); + return emberNew({ isModuleUnification: true }); }); it('adapter', function() { let args = ['adapter', 'foo']; - return emberGenerateDestroy(args, _file => { - expect(_file('src/data/models/foo/adapter.js')) - .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.JSONAPIAdapter.extend({'); + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/adapter.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.JSONAPIAdapter.extend({'); - expect(_file('src/data/models/foo/adapter-test.js')).to.equal( - fixture('adapter-test/foo-default.js') - ); - }); + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/foo-default.js') + ); + }, + { isModuleUnification: true } + ); }); it('adapter extends application adapter if it exists', function() { let args = ['adapter', 'foo']; - return emberGenerate(['adapter', 'application']).then(() => - emberGenerateDestroy(args, _file => { - expect(_file('src/data/models/foo/adapter.js')) - .to.contain("import ApplicationAdapter from '../application/adapter';") - .to.contain('export default ApplicationAdapter.extend({'); - - expect(_file('src/data/models/foo/adapter-test.js')).to.equal( - fixture('adapter-test/foo-default.js') - ); - }) + return emberGenerate(['adapter', 'application'], { isModuleUnification: true }).then(() => + emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/adapter.js')) + .to.contain("import ApplicationAdapter from '../application/adapter';") + .to.contain('export default ApplicationAdapter.extend({'); + + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/foo-default.js') + ); + }, + { isModuleUnification: true } + ) ); }); it('adapter with --base-class', function() { let args = ['adapter', 'foo', '--base-class=bar']; - return emberGenerateDestroy(args, _file => { - expect(_file('src/data/models/foo/adapter.js')) - .to.contain("import BarAdapter from '../bar/adapter';") - .to.contain('export default BarAdapter.extend({'); - - expect(_file('src/data/models/foo/adapter-test.js')).to.equal( - fixture('adapter-test/foo-default.js') - ); - }); - }); - - xit('adapter throws when --base-class is same as name', function() { - let args = ['adapter', 'foo', '--base-class=foo']; + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/adapter.js')) + .to.contain("import BarAdapter from '../bar/adapter';") + .to.contain('export default BarAdapter.extend({'); - return expect(emberGenerate(args)).to.be.rejectedWith( - SilentError, - /Adapters cannot extend from themself/ + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/foo-default.js') + ); + }, + { isModuleUnification: true } ); }); it('adapter when is named "application"', function() { let args = ['adapter', 'application']; - return emberGenerateDestroy(args, _file => { - expect(_file('src/data/models/application/adapter.js')) - .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.JSONAPIAdapter.extend({'); + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/application/adapter.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.JSONAPIAdapter.extend({'); - expect(_file('src/data/models/application/adapter-test.js')).to.equal( - fixture('adapter-test/application-default.js') - ); - }); + expect(_file('src/data/models/application/adapter-test.js')).to.equal( + fixture('adapter-test/application-default.js') + ); + }, + { isModuleUnification: true } + ); }); it('adapter-test', function() { let args = ['adapter-test', 'foo']; - return emberGenerateDestroy(args, _file => { - expect(_file('src/data/models/foo/adapter-test.js')).to.equal( - fixture('adapter-test/foo-default.js') - ); - }); + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/foo-default.js') + ); + }, + { isModuleUnification: true } + ); }); describe('adapter-test with ember-cli-qunit@4.2.0', function() { @@ -224,11 +234,15 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { }); it('adapter-test-test foo', function() { - return emberGenerateDestroy(['adapter-test', 'foo'], _file => { - expect(_file('src/data/models/foo/adapter-test.js')).to.equal( - fixture('adapter-test/rfc232.js') - ); - }); + return emberGenerateDestroy( + ['adapter-test', 'foo'], + _file => { + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ); }); }); @@ -244,11 +258,15 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { it('adapter-test for mocha v0.12+', function() { let args = ['adapter-test', 'foo']; - return emberGenerateDestroy(args, _file => { - expect(_file('src/data/models/foo/adapter-test.js')).to.equal( - fixture('adapter-test/foo-mocha-0.12.js') - ); - }); + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/foo-mocha-0.12.js') + ); + }, + { isModuleUnification: true } + ); }); }); }); diff --git a/package.json b/package.json index 78f065e97bb..6fca166adbc 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "common-tags": "^1.8.0", "ember-cli": "^3.3.0", "ember-cli-app-version": "^3.2.0", - "ember-cli-blueprint-test-helpers": "^0.18.3", + "ember-cli-blueprint-test-helpers": "^0.19.1", "ember-cli-dependency-checker": "^3.0.0", "ember-cli-htmlbars": "^3.0.0", "ember-cli-htmlbars-inline-precompile": "^1.0.3", @@ -103,7 +103,6 @@ "eslint-plugin-node": "^7.0.1", "eslint-plugin-prettier": "2.6.2", "execa": "^0.10.0", - "fs-extra": "^7.0.0", "github": "^1.1.1", "glob": "^7.1.2", "loader.js": "^4.7.0", diff --git a/yarn.lock b/yarn.lock index 5726264fa7a..483647344e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2372,16 +2372,16 @@ ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-be ember-cli-version-checker "^2.1.2" semver "^5.5.0" -ember-cli-blueprint-test-helpers@^0.18.3: - version "0.18.3" - resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.18.3.tgz#945c606d855f0263f5e8c03522e4040a74f259cc" +ember-cli-blueprint-test-helpers@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.19.1.tgz#26df9724a6cb48f7acfa391dec7ec772888b0929" dependencies: chai "^4.1.0" chai-as-promised "^7.0.0" chai-files "^1.0.0" debug "^3.0.0" ember-cli-internal-test-helpers "^0.9.1" - fs-extra "^4.0.0" + fs-extra "^5.0.0" testdouble "^3.2.6" tmp-sync "^1.0.0" @@ -3249,7 +3249,7 @@ external-editor@^1.1.0: external-editor@^2.1.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + resolved "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" dependencies: chardet "^0.4.0" iconv-lite "^0.4.17" @@ -3540,7 +3540,7 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" -fs-extra@^4.0.0, fs-extra@^4.0.2, fs-extra@^4.0.3: +fs-extra@^4.0.2, fs-extra@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" dependencies: @@ -3564,14 +3564,6 @@ fs-extra@^6.0.1: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.0.tgz#8cc3f47ce07ef7b3593a11b9fb245f7e34c041d6" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" From 36a2263393eb9700fbb313a1002c9049ef6ba7c2 Mon Sep 17 00:00:00 2001 From: Cyrille David Date: Sat, 22 Sep 2018 21:08:40 +0200 Subject: [PATCH 2347/2527] Upgrade ember-cli-blueprint-test-helpers --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 78f065e97bb..ea2938b6c52 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "common-tags": "^1.8.0", "ember-cli": "^3.3.0", "ember-cli-app-version": "^3.2.0", - "ember-cli-blueprint-test-helpers": "^0.18.3", + "ember-cli-blueprint-test-helpers": "^0.19.1", "ember-cli-dependency-checker": "^3.0.0", "ember-cli-htmlbars": "^3.0.0", "ember-cli-htmlbars-inline-precompile": "^1.0.3", diff --git a/yarn.lock b/yarn.lock index 5726264fa7a..a8dbaa1cc40 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2372,16 +2372,16 @@ ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-be ember-cli-version-checker "^2.1.2" semver "^5.5.0" -ember-cli-blueprint-test-helpers@^0.18.3: - version "0.18.3" - resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.18.3.tgz#945c606d855f0263f5e8c03522e4040a74f259cc" +ember-cli-blueprint-test-helpers@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.19.1.tgz#26df9724a6cb48f7acfa391dec7ec772888b0929" dependencies: chai "^4.1.0" chai-as-promised "^7.0.0" chai-files "^1.0.0" debug "^3.0.0" ember-cli-internal-test-helpers "^0.9.1" - fs-extra "^4.0.0" + fs-extra "^5.0.0" testdouble "^3.2.6" tmp-sync "^1.0.0" @@ -3540,7 +3540,7 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" -fs-extra@^4.0.0, fs-extra@^4.0.2, fs-extra@^4.0.3: +fs-extra@^4.0.2, fs-extra@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" dependencies: From 39b582cee014024926b7c05e31856b1cf0ce7d16 Mon Sep 17 00:00:00 2001 From: Cyrille David Date: Sat, 22 Sep 2018 21:08:40 +0200 Subject: [PATCH 2348/2527] Upgrade ember-cli-blueprint-test-helpers --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 46cd104dd1f..7a77adcfa0f 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "common-tags": "^1.8.0", "ember-cli": "^3.3.0", "ember-cli-app-version": "^3.2.0", - "ember-cli-blueprint-test-helpers": "^0.18.3", + "ember-cli-blueprint-test-helpers": "^0.19.1", "ember-cli-dependency-checker": "^3.0.0", "ember-cli-htmlbars": "^3.0.0", "ember-cli-htmlbars-inline-precompile": "^1.0.3", diff --git a/yarn.lock b/yarn.lock index 5726264fa7a..a8dbaa1cc40 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2372,16 +2372,16 @@ ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-be ember-cli-version-checker "^2.1.2" semver "^5.5.0" -ember-cli-blueprint-test-helpers@^0.18.3: - version "0.18.3" - resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.18.3.tgz#945c606d855f0263f5e8c03522e4040a74f259cc" +ember-cli-blueprint-test-helpers@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.19.1.tgz#26df9724a6cb48f7acfa391dec7ec772888b0929" dependencies: chai "^4.1.0" chai-as-promised "^7.0.0" chai-files "^1.0.0" debug "^3.0.0" ember-cli-internal-test-helpers "^0.9.1" - fs-extra "^4.0.0" + fs-extra "^5.0.0" testdouble "^3.2.6" tmp-sync "^1.0.0" @@ -3540,7 +3540,7 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" -fs-extra@^4.0.0, fs-extra@^4.0.2, fs-extra@^4.0.3: +fs-extra@^4.0.2, fs-extra@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" dependencies: From 88aca8adb509ad2bd31ee83117593a2da4b4a727 Mon Sep 17 00:00:00 2001 From: Cyrille David Date: Sat, 22 Sep 2018 23:59:00 +0200 Subject: [PATCH 2349/2527] [Feature] Add MU serializer{,-test} blueprints --- blueprints/serializer-test/index.js | 34 +- .../unit => __root__}/__path__/__test__.js | 0 .../unit => __root__}/__path__/__test__.js | 0 blueprints/serializer/index.js | 23 +- .../extend-from-application-entity.js | 9 +- node-tests/blueprints/serializer-test.js | 291 +++++++++++++----- 6 files changed, 276 insertions(+), 81 deletions(-) rename blueprints/serializer-test/mocha-files/{tests/unit => __root__}/__path__/__test__.js (100%) rename blueprints/serializer-test/qunit-files/{tests/unit => __root__}/__path__/__test__.js (100%) diff --git a/blueprints/serializer-test/index.js b/blueprints/serializer-test/index.js index a7388eb4efc..c38c753d07b 100644 --- a/blueprints/serializer-test/index.js +++ b/blueprints/serializer-test/index.js @@ -1,10 +1,38 @@ -var testInfo = require('ember-cli-test-info'); -var useTestFrameworkDetector = require('../test-framework-detector'); +const testInfo = require('ember-cli-test-info'); +const useTestFrameworkDetector = require('../test-framework-detector'); +const isModuleUnificationProject = require('../../lib/utilities/module-unification') + .isModuleUnificationProject; +const path = require('path'); module.exports = useTestFrameworkDetector({ description: 'Generates a serializer unit test.', - locals: function(options) { + fileMapTokens(options) { + if (isModuleUnificationProject(this.project)) { + return { + __root__() { + return 'src'; + }, + __path__(options) { + return path.join('data', 'models', options.dasherizedModuleName); + }, + __test__() { + return 'serializer-test'; + }, + }; + } else { + return { + __root__() { + return 'tests'; + }, + __path__() { + return path.join('unit', 'serializers'); + }, + }; + } + }, + + locals(options) { return { friendlyTestDescription: testInfo.description(options.entity.name, 'Unit', 'Serializer'), }; diff --git a/blueprints/serializer-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/mocha-files/__root__/__path__/__test__.js similarity index 100% rename from blueprints/serializer-test/mocha-files/tests/unit/__path__/__test__.js rename to blueprints/serializer-test/mocha-files/__root__/__path__/__test__.js diff --git a/blueprints/serializer-test/qunit-files/tests/unit/__path__/__test__.js b/blueprints/serializer-test/qunit-files/__root__/__path__/__test__.js similarity index 100% rename from blueprints/serializer-test/qunit-files/tests/unit/__path__/__test__.js rename to blueprints/serializer-test/qunit-files/__root__/__path__/__test__.js diff --git a/blueprints/serializer/index.js b/blueprints/serializer/index.js index 704014851f4..98ad38a9443 100644 --- a/blueprints/serializer/index.js +++ b/blueprints/serializer/index.js @@ -1,11 +1,30 @@ -var extendFromApplicationEntity = require('../../lib/utilities/extend-from-application-entity'); +const extendFromApplicationEntity = require('../../lib/utilities/extend-from-application-entity'); +const isModuleUnificationProject = require('../../lib/utilities/module-unification') + .isModuleUnificationProject; +const path = require('path'); module.exports = { description: 'Generates an ember-data serializer.', availableOptions: [{ name: 'base-class', type: String }], - locals: function(options) { + fileMapTokens(options) { + if (isModuleUnificationProject(this.project)) { + return { + __root__() { + return 'src'; + }, + __path__(options) { + return path.join('data', 'models', options.dasherizedModuleName); + }, + __name__() { + return 'serializer'; + }, + }; + } + }, + + locals(options) { return extendFromApplicationEntity('serializer', 'DS.JSONAPISerializer', options); }, }; diff --git a/lib/utilities/extend-from-application-entity.js b/lib/utilities/extend-from-application-entity.js index 17511fbdaa2..589229a5ff5 100644 --- a/lib/utilities/extend-from-application-entity.js +++ b/lib/utilities/extend-from-application-entity.js @@ -6,11 +6,12 @@ const path = require('path'); const isModuleUnificationProject = require('./module-unification').isModuleUnificationProject; module.exports = function(type, baseClass, options) { - let entityName = options.entity.name; let isAddon = options.inRepoAddon || options.project.isEmberCLIAddon(); - let relativePath = pathUtil.getRelativePath(options.entity.name); let isModuleUnification = isModuleUnificationProject(options.project); + let entityName = options.entity.name; + let relativePath = pathUtil.getRelativePath(options.entity.name); + if (options.pod && options.podPath) { relativePath = pathUtil.getRelativePath(options.podPath + options.entity.name); } @@ -23,7 +24,7 @@ module.exports = function(type, baseClass, options) { 'data', 'models', 'application', - 'adapter.js' + `${type}.js` ); } else { applicationEntityPath = path.join(options.project.root, 'app', `${type}s`, 'application.js'); @@ -49,7 +50,7 @@ module.exports = function(type, baseClass, options) { if (isModuleUnification) { relativePath = `../${options.baseClass}/`; - baseClassPath = 'adapter'; + baseClassPath = type; } importStatement = `import ${baseClass} from '${relativePath}${baseClassPath}';`; diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index 0c67640092a..058b4c157ca 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -18,116 +18,263 @@ const fixture = require('../helpers/fixture'); describe('Acceptance: generate and destroy serializer blueprints', function() { setupTestHooks(this); - beforeEach(function() { - return emberNew(); - }); + describe('classic', function() { + beforeEach(function() { + return emberNew(); + }); + + it('serializer', function() { + let args = ['serializer', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('app/serializers/foo.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.JSONAPISerializer.extend('); + + expect(_file('tests/unit/serializers/foo-test.js')).to.equal( + fixture('serializer-test/foo-default.js') + ); + }); + }); - it('serializer', function() { - let args = ['serializer', 'foo']; + it('serializer extends application serializer if it exists', function() { + let args = ['serializer', 'foo']; - return emberGenerateDestroy(args, _file => { - expect(_file('app/serializers/foo.js')) - .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.JSONAPISerializer.extend('); + return emberGenerate(['serializer', 'application']).then(() => + emberGenerateDestroy(args, _file => { + expect(_file('app/serializers/foo.js')) + .to.contain("import ApplicationSerializer from './application';") + .to.contain('export default ApplicationSerializer.extend({'); - expect(_file('tests/unit/serializers/foo-test.js')).to.equal( - fixture('serializer-test/foo-default.js') + expect(_file('tests/unit/serializers/foo-test.js')).to.equal( + fixture('serializer-test/foo-default.js') + ); + }) ); }); - }); - it('serializer extends application serializer if it exists', function() { - let args = ['serializer', 'foo']; + it('serializer with --base-class', function() { + let args = ['serializer', 'foo', '--base-class=bar']; - return emberGenerate(['serializer', 'application']).then(() => - emberGenerateDestroy(args, _file => { + return emberGenerateDestroy(args, _file => { expect(_file('app/serializers/foo.js')) - .to.contain("import ApplicationSerializer from './application';") - .to.contain('export default ApplicationSerializer.extend({'); + .to.contain("import BarSerializer from './bar';") + .to.contain('export default BarSerializer.extend({'); expect(_file('tests/unit/serializers/foo-test.js')).to.equal( fixture('serializer-test/foo-default.js') ); - }) - ); + }); + }); + + xit('serializer throws when --base-class is same as name', function() { + let args = ['serializer', 'foo', '--base-class=foo']; + + return expect(emberGenerate(args)).to.be.rejectedWith( + SilentError, + /Serializers cannot extend from themself/ + ); + }); + + it('serializer when is named "application"', function() { + let args = ['serializer', 'application']; + + return emberGenerateDestroy(args, _file => { + expect(_file('app/serializers/application.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.JSONAPISerializer.extend({'); + + expect(_file('tests/unit/serializers/application-test.js')).to.equal( + fixture('serializer-test/application-default.js') + ); + }); + }); + + it('serializer-test', function() { + let args = ['serializer-test', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/serializers/foo-test.js')).to.equal( + fixture('serializer-test/foo-default.js') + ); + }); + }); + + describe('serializer-test with ember-cli-qunit@4.2.0', function() { + beforeEach(function() { + generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + }); + + it('serializer-test-test foo', function() { + return emberGenerateDestroy(['serializer-test', 'foo'], _file => { + expect(_file('tests/unit/serializers/foo-test.js')).to.equal( + fixture('serializer-test/rfc232.js') + ); + }); + }); + }); + + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('serializer-test for mocha v0.12+', function() { + let args = ['serializer-test', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/serializers/foo-test.js')).to.equal( + fixture('serializer-test/foo-mocha-0.12.js') + ); + }); + }); + }); }); - it('serializer with --base-class', function() { - let args = ['serializer', 'foo', '--base-class=bar']; + describe('module unification', function() { + beforeEach(function() { + return emberNew({ isModuleUnification: true }); + }); + + it('serializer', function() { + let args = ['serializer', 'foo']; - return emberGenerateDestroy(args, _file => { - expect(_file('app/serializers/foo.js')) - .to.contain("import BarSerializer from './bar';") - .to.contain('export default BarSerializer.extend({'); + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/serializer.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.JSONAPISerializer.extend('); - expect(_file('tests/unit/serializers/foo-test.js')).to.equal( - fixture('serializer-test/foo-default.js') + expect(_file('src/data/models/foo/serializer-test.js')).to.equal( + fixture('serializer-test/foo-default.js') + ); + }, + { isModuleUnification: true } ); }); - }); - xit('serializer throws when --base-class is same as name', function() { - let args = ['serializer', 'foo', '--base-class=foo']; + it('serializer extends application serializer if it exists', function() { + let args = ['serializer', 'foo']; - return expect(emberGenerate(args)).to.be.rejectedWith( - SilentError, - /Serializers cannot extend from themself/ - ); - }); + return emberGenerate(['serializer', 'application'], { isModuleUnification: true }).then(() => + emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/serializer.js')) + .to.contain("import ApplicationSerializer from '../application/serializer';") + .to.contain('export default ApplicationSerializer.extend({'); - it('serializer when is named "application"', function() { - let args = ['serializer', 'application']; + expect(_file('src/data/models/foo/serializer-test.js')).to.equal( + fixture('serializer-test/foo-default.js') + ); + }, + { isModuleUnification: true } + ) + ); + }); + + it('serializer with --base-class', function() { + let args = ['serializer', 'foo', '--base-class=bar']; - return emberGenerateDestroy(args, _file => { - expect(_file('app/serializers/application.js')) - .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.JSONAPISerializer.extend({'); + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/serializer.js')) + .to.contain("import BarSerializer from '../bar/serializer';") + .to.contain('export default BarSerializer.extend({'); - expect(_file('tests/unit/serializers/application-test.js')).to.equal( - fixture('serializer-test/application-default.js') + expect(_file('src/data/models/foo/serializer-test.js')).to.equal( + fixture('serializer-test/foo-default.js') + ); + }, + { isModuleUnification: true } ); }); - }); - it('serializer-test', function() { - let args = ['serializer-test', 'foo']; + xit('serializer throws when --base-class is same as name', function() { + let args = ['serializer', 'foo', '--base-class=foo']; - return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/serializers/foo-test.js')).to.equal( - fixture('serializer-test/foo-default.js') + return expect(emberGenerate(args, { isModuleUnification: true })).to.be.rejectedWith( + SilentError, + /Serializers cannot extend from themself/ ); }); - }); - describe('serializer-test with ember-cli-qunit@4.2.0', function() { - beforeEach(function() { - generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + it('serializer when is named "application"', function() { + let args = ['serializer', 'application']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/application/serializer.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.JSONAPISerializer.extend({'); + + expect(_file('src/data/models/application/serializer-test.js')).to.equal( + fixture('serializer-test/application-default.js') + ); + }, + { isModuleUnification: true } + ); }); - it('serializer-test-test foo', function() { - return emberGenerateDestroy(['serializer-test', 'foo'], _file => { - expect(_file('tests/unit/serializers/foo-test.js')).to.equal( - fixture('serializer-test/rfc232.js') + it('serializer-test', function() { + let args = ['serializer-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/serializer-test.js')).to.equal( + fixture('serializer-test/foo-default.js') + ); + }, + { isModuleUnification: true } + ); + }); + + describe('serializer-test with ember-cli-qunit@4.2.0', function() { + beforeEach(function() { + generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + }); + + it('serializer-test-test foo', function() { + return emberGenerateDestroy( + ['serializer-test', 'foo'], + _file => { + expect(_file('src/data/models/foo/serializer-test.js')).to.equal( + fixture('serializer-test/rfc232.js') + ); + }, + { isModuleUnification: true } ); }); }); - }); - describe('with ember-cli-mocha v0.12+', function() { - beforeEach(function() { - modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-cli-mocha', dev: true }, - ]); - generateFakePackageManifest('ember-cli-mocha', '0.12.0'); - }); + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); - it('serializer-test for mocha v0.12+', function() { - let args = ['serializer-test', 'foo']; + it('serializer-test for mocha v0.12+', function() { + let args = ['serializer-test', 'foo']; - return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/serializers/foo-test.js')).to.equal( - fixture('serializer-test/foo-mocha-0.12.js') + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/serializer-test.js')).to.equal( + fixture('serializer-test/foo-mocha-0.12.js') + ); + }, + { isModuleUnification: true } ); }); }); From e3398430deb889bbe231e2a86562147d25398248 Mon Sep 17 00:00:00 2001 From: Cyrille David Date: Sat, 22 Sep 2018 21:08:40 +0200 Subject: [PATCH 2350/2527] Upgrade ember-cli-blueprint-test-helpers --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 78f065e97bb..ea2938b6c52 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "common-tags": "^1.8.0", "ember-cli": "^3.3.0", "ember-cli-app-version": "^3.2.0", - "ember-cli-blueprint-test-helpers": "^0.18.3", + "ember-cli-blueprint-test-helpers": "^0.19.1", "ember-cli-dependency-checker": "^3.0.0", "ember-cli-htmlbars": "^3.0.0", "ember-cli-htmlbars-inline-precompile": "^1.0.3", diff --git a/yarn.lock b/yarn.lock index 5726264fa7a..a8dbaa1cc40 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2372,16 +2372,16 @@ ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-be ember-cli-version-checker "^2.1.2" semver "^5.5.0" -ember-cli-blueprint-test-helpers@^0.18.3: - version "0.18.3" - resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.18.3.tgz#945c606d855f0263f5e8c03522e4040a74f259cc" +ember-cli-blueprint-test-helpers@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.19.1.tgz#26df9724a6cb48f7acfa391dec7ec772888b0929" dependencies: chai "^4.1.0" chai-as-promised "^7.0.0" chai-files "^1.0.0" debug "^3.0.0" ember-cli-internal-test-helpers "^0.9.1" - fs-extra "^4.0.0" + fs-extra "^5.0.0" testdouble "^3.2.6" tmp-sync "^1.0.0" @@ -3540,7 +3540,7 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" -fs-extra@^4.0.0, fs-extra@^4.0.2, fs-extra@^4.0.3: +fs-extra@^4.0.2, fs-extra@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" dependencies: From 45e7f198c56cdafa8edee7520b859ce31924a16e Mon Sep 17 00:00:00 2001 From: Cyrille David Date: Sun, 23 Sep 2018 09:58:42 +0200 Subject: [PATCH 2351/2527] [Feature] Add MU transform{,-test} blueprint --- blueprints/transform-test/index.js | 34 +++- .../unit => __root__}/__path__/__test__.js | 0 .../unit => __root__}/__path__/__test__.js | 0 blueprints/transform/index.js | 20 +++ node-tests/blueprints/transform-test.js | 168 +++++++++++++----- 5 files changed, 178 insertions(+), 44 deletions(-) rename blueprints/transform-test/mocha-files/{tests/unit => __root__}/__path__/__test__.js (100%) rename blueprints/transform-test/qunit-files/{tests/unit => __root__}/__path__/__test__.js (100%) diff --git a/blueprints/transform-test/index.js b/blueprints/transform-test/index.js index 35d846c0d64..4b6c993309f 100644 --- a/blueprints/transform-test/index.js +++ b/blueprints/transform-test/index.js @@ -1,10 +1,38 @@ -var testInfo = require('ember-cli-test-info'); -var useTestFrameworkDetector = require('../test-framework-detector'); +const testInfo = require('ember-cli-test-info'); +const useTestFrameworkDetector = require('../test-framework-detector'); +const isModuleUnificationProject = require('../../lib/utilities/module-unification') + .isModuleUnificationProject; +const path = require('path'); module.exports = useTestFrameworkDetector({ description: 'Generates a transform unit test.', - locals: function(options) { + fileMapTokens(options) { + if (isModuleUnificationProject(this.project)) { + return { + __root__() { + return 'src'; + }, + __path__(options) { + return path.join('data', 'transforms'); + }, + __test__() { + return `${options.dasherizedModuleName}-test`; + }, + }; + } else { + return { + __root__() { + return 'tests'; + }, + __path__() { + return path.join('unit', 'transforms'); + }, + }; + } + }, + + locals(options) { return { friendlyTestDescription: testInfo.description(options.entity.name, 'Unit', 'Transform'), }; diff --git a/blueprints/transform-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/transform-test/mocha-files/__root__/__path__/__test__.js similarity index 100% rename from blueprints/transform-test/mocha-files/tests/unit/__path__/__test__.js rename to blueprints/transform-test/mocha-files/__root__/__path__/__test__.js diff --git a/blueprints/transform-test/qunit-files/tests/unit/__path__/__test__.js b/blueprints/transform-test/qunit-files/__root__/__path__/__test__.js similarity index 100% rename from blueprints/transform-test/qunit-files/tests/unit/__path__/__test__.js rename to blueprints/transform-test/qunit-files/__root__/__path__/__test__.js diff --git a/blueprints/transform/index.js b/blueprints/transform/index.js index 476ff90924a..07908a5d3bc 100644 --- a/blueprints/transform/index.js +++ b/blueprints/transform/index.js @@ -1,3 +1,23 @@ +const isModuleUnificationProject = require('../../lib/utilities/module-unification') + .isModuleUnificationProject; +const path = require('path'); + module.exports = { description: 'Generates an ember-data value transform.', + + fileMapTokens(options) { + if (isModuleUnificationProject(this.project)) { + return { + __root__() { + return 'src'; + }, + __path__(options) { + return path.join('data', 'transforms'); + }, + __name__() { + return options.dasherizedModuleName; + }, + }; + } + }, }; diff --git a/node-tests/blueprints/transform-test.js b/node-tests/blueprints/transform-test.js index 29add489003..31f879d5d40 100644 --- a/node-tests/blueprints/transform-test.js +++ b/node-tests/blueprints/transform-test.js @@ -15,66 +15,152 @@ const fixture = require('../helpers/fixture'); describe('Acceptance: generate and destroy transform blueprints', function() { setupTestHooks(this); - describe('in app', function() { - beforeEach(function() { - return emberNew(); - }); + describe('classic', function() { + describe('in app', function() { + beforeEach(function() { + return emberNew(); + }); - it('transform', function() { - let args = ['transform', 'foo']; + it('transform', function() { + let args = ['transform', 'foo']; - return emberGenerateDestroy(args, _file => { - expect(_file('app/transforms/foo.js')) - .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.Transform.extend(') - .to.contain('deserialize(serialized) {') - .to.contain('serialize(deserialized) {'); + return emberGenerateDestroy(args, _file => { + expect(_file('app/transforms/foo.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.Transform.extend(') + .to.contain('deserialize(serialized) {') + .to.contain('serialize(deserialized) {'); - expect(_file('tests/unit/transforms/foo-test.js')).to.equal( - fixture('transform-test/default.js') - ); + expect(_file('tests/unit/transforms/foo-test.js')).to.equal( + fixture('transform-test/default.js') + ); + }); }); - }); - it('transform-test', function() { - let args = ['transform-test', 'foo']; + it('transform-test', function() { + let args = ['transform-test', 'foo']; - return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/transforms/foo-test.js')).to.equal( - fixture('transform-test/default.js') - ); + return emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/transforms/foo-test.js')).to.equal( + fixture('transform-test/default.js') + ); + }); }); - }); - describe('transform-test with ember-cli-qunit@4.2.0', function() { - beforeEach(function() { - generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + describe('transform-test with ember-cli-qunit@4.2.0', function() { + beforeEach(function() { + generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + }); + + it('transform-test-test foo', function() { + return emberGenerateDestroy(['transform-test', 'foo'], _file => { + expect(_file('tests/unit/transforms/foo-test.js')).to.equal( + fixture('transform-test/rfc232.js') + ); + }); + }); }); - it('transform-test-test foo', function() { - return emberGenerateDestroy(['transform-test', 'foo'], _file => { - expect(_file('tests/unit/transforms/foo-test.js')).to.equal( - fixture('transform-test/rfc232.js') - ); + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('transform-test for mocha v0.12+', function() { + let args = ['transform-test', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/transforms/foo-test.js')).to.equal( + fixture('transform-test/mocha-0.12.js') + ); + }); }); }); }); + }); - describe('with ember-cli-mocha v0.12+', function() { + describe('module unification', function() { + describe('in app', function() { beforeEach(function() { - modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-cli-mocha', dev: true }, - ]); - generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + return emberNew({ isModuleUnification: true }); }); - it('transform-test for mocha v0.12+', function() { + it('transform', function() { + let args = ['transform', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/transforms/foo.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.Transform.extend(') + .to.contain('deserialize(serialized) {') + .to.contain('serialize(deserialized) {'); + + expect(_file('src/data/transforms/foo-test.js')).to.equal( + fixture('transform-test/default.js') + ); + }, + { isModuleUnification: true } + ); + }); + + it('transform-test', function() { let args = ['transform-test', 'foo']; - return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/transforms/foo-test.js')).to.equal( - fixture('transform-test/mocha-0.12.js') + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/transforms/foo-test.js')).to.equal( + fixture('transform-test/default.js') + ); + }, + { isModuleUnification: true } + ); + }); + + describe('transform-test with ember-cli-qunit@4.2.0', function() { + beforeEach(function() { + generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + }); + + it('transform-test-test foo', function() { + return emberGenerateDestroy( + ['transform-test', 'foo'], + _file => { + expect(_file('src/data/transforms/foo-test.js')).to.equal( + fixture('transform-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); + + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('transform-test for mocha v0.12+', function() { + let args = ['transform-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/transforms/foo-test.js')).to.equal( + fixture('transform-test/mocha-0.12.js') + ); + }, + { isModuleUnification: true } ); }); }); From eab78234c563a2bbf9777175c3cd096a4cbfa01a Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Fri, 21 Sep 2018 00:31:08 -0700 Subject: [PATCH 2352/2527] Add firefox addon Needed for external partner ilios-frontend where Firefox is the CI browser of choice. The alias 'latest' refers to the most recent released version. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index c8f38d0f8a3..31716b7e991 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ node_js: addons: chrome: stable + firefox: latest cache: yarn: true From 74890b7e4395a76a69b9b02904dcd2ce36372e75 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 24 Sep 2018 11:02:09 -0700 Subject: [PATCH 2353/2527] [FEAT transforms] makes the assertion for missing transforms clearer --- addon/serializers/json.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 8fef55ccf0a..c5d2677a5f3 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1482,7 +1482,10 @@ const JSONSerializer = Serializer.extend({ transformFor(attributeType, skipAssertion) { let transform = getOwner(this).lookup('transform:' + attributeType); - assert("Unable to find transform for '" + attributeType + "'", skipAssertion || !!transform); + assert( + `Unable to find the transform for \`attr('${attributeType}')\``, + skipAssertion || !!transform + ); return transform; }, From 36b88d17cd6938d8cf617a49ef7c8a599598a163 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 24 Sep 2018 11:39:16 -0700 Subject: [PATCH 2354/2527] [FEAT record-data] rename model-data => record-data --- addon/-record-data-private/attr.js | 2 +- addon/-record-data-private/index.js | 2 +- .../-record-data-private/system/many-array.js | 10 +- .../system/model/internal-model.js | 66 ++-- .../system/model/model.js | 2 +- .../model/{model-data.js => record-data.js} | 92 +++--- .../system/promise-proxies.js | 2 +- .../system/references/belongs-to.js | 4 +- .../system/references/has-many.js | 8 +- .../system/references/reference.js | 2 +- .../system/relationships/state/belongs-to.js | 140 ++++---- .../system/relationships/state/create.js | 24 +- .../system/relationships/state/has-many.js | 132 ++++---- .../relationships/state/relationship.js | 298 +++++++++--------- addon/-record-data-private/system/snapshot.js | 4 +- addon/-record-data-private/system/store.js | 28 +- ...data-wrapper.js => record-data-wrapper.js} | 8 +- tests/integration/records/unload-test.js | 8 +- .../relationships/belongs-to-test.js | 32 +- tests/unit/model-test.js | 2 +- .../unit/model/relationships/has-many-test.js | 2 +- 21 files changed, 434 insertions(+), 434 deletions(-) rename addon/-record-data-private/system/model/{model-data.js => record-data.js} (89%) rename addon/-record-data-private/system/store/{model-data-wrapper.js => record-data-wrapper.js} (93%) diff --git a/addon/-record-data-private/attr.js b/addon/-record-data-private/attr.js index b8352fd29df..db413e2eadd 100644 --- a/addon/-record-data-private/attr.js +++ b/addon/-record-data-private/attr.js @@ -19,7 +19,7 @@ function getDefaultValue(record, options, key) { } function hasValue(internalModel, key) { - return internalModel._modelData.hasAttr(key); + return internalModel._recordData.hasAttr(key); } /** diff --git a/addon/-record-data-private/index.js b/addon/-record-data-private/index.js index 15e211a9de9..e9eedd50e26 100644 --- a/addon/-record-data-private/index.js +++ b/addon/-record-data-private/index.js @@ -32,7 +32,7 @@ export { default as isEnabled } from './features'; // `ember-data-model-fragments` relies on `RootState` and `InternalModel` export { default as RootState } from './system/model/states'; export { default as InternalModel } from './system/model/internal-model'; -export { default as ModelData } from './system/model/model-data'; +export { default as RecordData } from './system/model/record-data'; export { PromiseArray, PromiseObject, PromiseManyArray } from './system/promise-proxies'; diff --git a/addon/-record-data-private/system/many-array.js b/addon/-record-data-private/system/many-array.js index 931356ed03a..f21374882ca 100644 --- a/addon/-record-data-private/system/many-array.js +++ b/addon/-record-data-private/system/many-array.js @@ -195,15 +195,15 @@ export default EmberObject.extend(MutableArray, Evented, { let internalModels; if (amt > 0) { internalModels = this.currentState.slice(idx, idx + amt); - this.get('modelData').removeFromHasMany( + this.get('recordData').removeFromHasMany( this.get('key'), - internalModels.map(im => im._modelData) + internalModels.map(im => im._recordData) ); } if (objects) { - this.get('modelData').addToHasMany( + this.get('recordData').addToHasMany( this.get('key'), - objects.map(obj => obj._internalModel._modelData), + objects.map(obj => obj._internalModel._recordData), idx ); //this.get('relationship').addInternalModels(objects.map(obj => obj._internalModel), idx); @@ -214,7 +214,7 @@ export default EmberObject.extend(MutableArray, Evented, { // Ok this is kinda funky because if buggy we might lose positions, etc. // but current code is this way so shouldn't be too big of a problem retrieveLatest() { - let jsonApi = this.get('modelData').getHasMany(this.get('key')); + let jsonApi = this.get('recordData').getHasMany(this.get('key')); // TODO this is odd, why should ManyArray ever tell itself to resync? let internalModels = this.store._getHasManyByJsonApiResource(jsonApi); if (jsonApi.meta) { diff --git a/addon/-record-data-private/system/model/internal-model.js b/addon/-record-data-private/system/model/internal-model.js index 59d11ce44b4..af126b1117c 100644 --- a/addon/-record-data-private/system/model/internal-model.js +++ b/addon/-record-data-private/system/model/internal-model.js @@ -92,7 +92,7 @@ export default class InternalModel { this.modelName = modelName; this.clientId = clientId; - this._modelData = store._createModelData(modelName, id, clientId, this); + this._recordData = store._createRecordData(modelName, id, clientId, this); // this ensure ordered set can quickly identify this as unique this[Ember.GUID_KEY] = InternalModelReferenceId++ + 'internal-model'; @@ -224,12 +224,12 @@ export default class InternalModel { // DO NOT USE : purely to ease the transition in tests get _attributes() { - return this._modelData._attributes; + return this._recordData._attributes; } // DO NOT USE : purely to ease the transition in tests get _relationships() { - return this._modelData._relationships; + return this._recordData._relationships; } getRecord(properties) { @@ -258,7 +258,7 @@ export default class InternalModel { this.setId(properties.id); } - // convert relationship Records to ModelDatas before passing to ModelData + // convert relationship Records to RecordDatas before passing to RecordData let defs = store._relationshipsDefinitionFor(this.modelName); if (defs !== null) { @@ -285,7 +285,7 @@ export default class InternalModel { } } - let additionalCreateOptions = this._modelData._initRecordCreateOptions(properties); + let additionalCreateOptions = this._recordData._initRecordCreateOptions(properties); assign(createOptions, additionalCreateOptions); if (setOwner) { @@ -346,7 +346,7 @@ export default class InternalModel { } // move to an empty never-loaded state - this._modelData.unloadRecord(); + this._recordData.unloadRecord(); this.resetRecord(); this.updateRecordArrays(); } @@ -373,7 +373,7 @@ export default class InternalModel { linkWasLoadedForRelationship(key, data) { let relationships = {}; relationships[key] = data; - this._modelData.pushData({ id: this.id, type: this.modelName, relationships }); + this._recordData.pushData({ id: this.id, type: this.modelName, relationships }); } finishedReloading() { @@ -489,7 +489,7 @@ export default class InternalModel { } getBelongsTo(key, options) { - let resource = this._modelData.getBelongsTo(key); + let resource = this._recordData.getBelongsTo(key); let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key); let store = this.store; let parentInternalModel = this; @@ -533,7 +533,7 @@ export default class InternalModel { // TODO Igor consider getting rid of initial state getManyArray(key) { let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key); - let jsonApi = this._modelData.getHasMany(key); + let jsonApi = this._recordData.getHasMany(key); let manyArray = this._manyArrayCache[key]; assert( @@ -547,7 +547,7 @@ export default class InternalModel { manyArray = ManyArray.create({ store: this.store, type: this.store.modelFor(relationshipMeta.type), - modelData: this._modelData, + recordData: this._recordData, meta: jsonApi.meta, key, isPolymorphic: relationshipMeta.options.polymorphic, @@ -584,7 +584,7 @@ export default class InternalModel { } getHasMany(key, options) { - let jsonApi = this._modelData.getHasMany(key); + let jsonApi = this._recordData.getHasMany(key); let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key); let async = relationshipMeta.options.async; let isAsync = typeof async === 'undefined' ? true : async; @@ -645,7 +645,7 @@ export default class InternalModel { */ } - let jsonApi = this._modelData.getHasMany(key); + let jsonApi = this._recordData.getHasMany(key); jsonApi._relationship.setRelationshipIsStale(true); let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key); let manyArray = this.getManyArray(key); @@ -657,14 +657,14 @@ export default class InternalModel { } reloadBelongsTo(key, options) { - let resource = this._modelData.getBelongsTo(key); + let resource = this._recordData.getBelongsTo(key); resource._relationship.setRelationshipIsStale(true); let relationshipMeta = this.store._relationshipMetaFor(this.modelName, null, key); return this.store._findBelongsToByJsonApiResource(resource, this, relationshipMeta, options); } - destroyFromModelData() { + destroyFromRecordData() { if (this._doNotDestroy) { this._doNotDestroy = false; return; @@ -697,7 +697,7 @@ export default class InternalModel { setupData(data) { heimdall.increment(setupData); - let changedKeys = this._modelData.pushData(data, this.hasRecord); + let changedKeys = this._recordData.pushData(data, this.hasRecord); if (this.hasRecord) { this._record._notifyProperties(changedKeys); } @@ -705,19 +705,19 @@ export default class InternalModel { } getAttributeValue(key) { - return this._modelData.getAttr(key); + return this._recordData.getAttr(key); } setDirtyHasMany(key, records) { assertRecordsPassedToHasMany(records); - return this._modelData.setDirtyHasMany(key, extractRecordDatasFromRecords(records)); + return this._recordData.setDirtyHasMany(key, extractRecordDatasFromRecords(records)); } setDirtyBelongsTo(key, value) { if (value && !value.then) { value = extractRecordDataFromRecord(value); } - return this._modelData.setDirtyBelongsTo(key, value); + return this._recordData.setDirtyBelongsTo(key, value); } setDirtyAttribute(key, value) { @@ -727,8 +727,8 @@ export default class InternalModel { let currentValue = this.getAttributeValue(key); if (currentValue !== value) { - this._modelData.setDirtyAttribute(key, value); - let isDirty = this._modelData.isAttrDirty(key); + this._recordData.setDirtyAttribute(key, value); + let isDirty = this._recordData.isAttrDirty(key); this.send('didSetProperty', { name: key, isDirty: isDirty, @@ -790,7 +790,7 @@ export default class InternalModel { hasChangedAttributes() { heimdall.increment(hasChangedAttributes); - return this._modelData.hasChangedAttributes(); + return this._recordData.hasChangedAttributes(); } /* @@ -802,7 +802,7 @@ export default class InternalModel { */ changedAttributes() { heimdall.increment(changedAttributes); - return this._modelData.changedAttributes(); + return this._recordData.changedAttributes(); } /* @@ -810,7 +810,7 @@ export default class InternalModel { @private */ adapterWillCommit() { - this._modelData.willCommit(); + this._recordData.willCommit(); this.send('willCommit'); } @@ -895,11 +895,11 @@ export default class InternalModel { } didCreateRecord() { - this._modelData.clientDidCreate(); + this._recordData.clientDidCreate(); } rollbackAttributes() { - let dirtyKeys = this._modelData.rollbackAttributes(); + let dirtyKeys = this._recordData.rollbackAttributes(); if (get(this, 'isError')) { this.didCleanError(); } @@ -1017,7 +1017,7 @@ export default class InternalModel { } removeFromInverseRelationships(isNew = false) { - this._modelData.removeFromInverseRelationships(isNew); + this._recordData.removeFromInverseRelationships(isNew); } /* @@ -1053,7 +1053,7 @@ export default class InternalModel { jsonPayload.attributes[key] = preloadValue; } }); - this._modelData.pushData(jsonPayload); + this._recordData.pushData(jsonPayload); } _preloadRelationship(key, preloadValue) { @@ -1143,7 +1143,7 @@ export default class InternalModel { adapterDidCommit(data) { this.didCleanError(); - let changedKeys = this._modelData.didCommit(data); + let changedKeys = this._recordData.didCommit(data); this.send('didCommit'); this.updateRecordArrays(); @@ -1190,7 +1190,7 @@ export default class InternalModel { this.send('becameInvalid'); - this._modelData.commitWasRejected(); + this._recordData.commitWasRejected(); } /* @@ -1201,7 +1201,7 @@ export default class InternalModel { this.send('becameError'); this.didError(error); - this._modelData.commitWasRejected(); + this._recordData.commitWasRejected(); } toString() { @@ -1213,7 +1213,7 @@ export default class InternalModel { if (!reference) { // TODO IGOR AND DAVID REFACTOR - let relationship = this._modelData._relationships.get(name); + let relationship = this._recordData._relationships.get(name); if (DEBUG) { let modelName = this.modelName; @@ -1260,10 +1260,10 @@ function extractRecordDatasFromRecords(records) { function extractRecordDataFromRecord(recordOrPromiseProxy) { // TODO @runspired async createRecord would resolve this issue - // we leak record promises to ModelData by necessity :'( + // we leak record promises to RecordData by necessity :'( if (!recordOrPromiseProxy || (recordOrPromiseProxy && recordOrPromiseProxy.then)) { return recordOrPromiseProxy; } - return recordOrPromiseProxy._internalModel._modelData; + return recordOrPromiseProxy._internalModel._recordData; } diff --git a/addon/-record-data-private/system/model/model.js b/addon/-record-data-private/system/model/model.js index d73851bc31a..a770fb766f1 100644 --- a/addon/-record-data-private/system/model/model.js +++ b/addon/-record-data-private/system/model/model.js @@ -1152,7 +1152,7 @@ Object.defineProperty(Model.prototype, 'data', { configurable: false, get() { // TODO deprecate this!!!!!!!!!!! it's private but intimate - return this._internalModel._modelData._data; + return this._internalModel._recordData._data; }, }); diff --git a/addon/-record-data-private/system/model/model-data.js b/addon/-record-data-private/system/model/record-data.js similarity index 89% rename from addon/-record-data-private/system/model/model-data.js rename to addon/-record-data-private/system/model/record-data.js index 6c6e0262a71..b64b902ac66 100644 --- a/addon/-record-data-private/system/model/model-data.js +++ b/addon/-record-data-private/system/model/record-data.js @@ -8,7 +8,7 @@ import Relationships from '../relationships/state/create'; import coerceId from '../coerce-id'; let nextBfsId = 1; -export default class ModelData { +export default class RecordData { constructor(modelName, id, clientId, storeWrapper, store) { this.store = store; this.modelName = modelName; @@ -95,7 +95,7 @@ export default class ModelData { let relationshipData = data.relationships[relationshipName]; if (DEBUG) { let store = this.store; - let modelData = this; + let recordData = this; let relationshipMeta = relationships[relationshipName]; if (!relationshipData || !relationshipMeta) { continue; @@ -122,7 +122,7 @@ export default class ModelData { )}, but ${relationshipName} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(relationshipData.data) ); - assertRelationshipData(store, modelData, relationshipData.data, relationshipMeta); + assertRelationshipData(store, recordData, relationshipData.data, relationshipMeta); } else if (relationshipMeta.kind === 'hasMany') { assert( `A ${ @@ -136,7 +136,7 @@ export default class ModelData { for (let i = 0; i < relationshipData.data.length; i++) { assertRelationshipData( store, - modelData, + recordData, relationshipData.data[i], relationshipMeta ); @@ -251,20 +251,20 @@ export default class ModelData { } // set a new "current state" via ResourceIdentifiers - setDirtyHasMany(key, modelDatas) { + setDirtyHasMany(key, recordDatas) { let relationship = this._relationships.get(key); relationship.clear(); - relationship.addModelDatas(modelDatas); + relationship.addRecordDatas(recordDatas); } - // append to "current state" via ModelDatas - addToHasMany(key, modelDatas, idx) { - this._relationships.get(key).addModelDatas(modelDatas, idx); + // append to "current state" via RecordDatas + addToHasMany(key, recordDatas, idx) { + this._relationships.get(key).addRecordDatas(recordDatas, idx); } - // remove from "current state" via ModelDatas - removeFromHasMany(key, modelDatas) { - this._relationships.get(key).removeModelDatas(modelDatas); + // remove from "current state" via RecordDatas + removeFromHasMany(key, recordDatas) { + this._relationships.get(key).removeRecordDatas(recordDatas); } commitWasRejected() { @@ -284,15 +284,15 @@ export default class ModelData { return this._relationships.get(key).getData(); } - setDirtyBelongsTo(key, modelDataOrPromise) { - if (modelDataOrPromise === undefined) { - modelDataOrPromise = null; + setDirtyBelongsTo(key, recordDataOrPromise) { + if (recordDataOrPromise === undefined) { + recordDataOrPromise = null; } - if (modelDataOrPromise && modelDataOrPromise.then) { - this._relationships.get(key).setRecordPromise(modelDataOrPromise); + if (recordDataOrPromise && recordDataOrPromise.then) { + this._relationships.get(key).setRecordPromise(recordDataOrPromise); } else { - this._relationships.get(key).setModelData(modelDataOrPromise); + this._relationships.get(key).setRecordData(recordDataOrPromise); } } @@ -336,18 +336,18 @@ export default class ModelData { this._scheduledDestroy = run.backburner.schedule( 'destroy', this, - '_cleanupOrphanedModelDatas' + '_cleanupOrphanedRecordDatas' ); } } - _cleanupOrphanedModelDatas() { - let relatedModelDatas = this._allRelatedModelDatas(); - if (areAllModelsUnloaded(relatedModelDatas)) { - for (let i = 0; i < relatedModelDatas.length; ++i) { - let modelData = relatedModelDatas[i]; - if (!modelData.isDestroyed) { - modelData.destroy(); + _cleanupOrphanedRecordDatas() { + let relatedRecordDatas = this._allRelatedRecordDatas(); + if (areAllModelsUnloaded(relatedRecordDatas)) { + for (let i = 0; i < relatedRecordDatas.length; ++i) { + let recordData = relatedRecordDatas[i]; + if (!recordData.isDestroyed) { + recordData.destroy(); } } } @@ -372,7 +372,7 @@ export default class ModelData { to or has many. */ - _directlyRelatedModelDatas() { + _directlyRelatedRecordDatas() { let array = []; this._relationships.forEach((name, rel) => { @@ -393,7 +393,7 @@ export default class ModelData { @return {Array} An array including `this` and all internal models reachable from `this`. */ - _allRelatedModelDatas() { + _allRelatedRecordDatas() { let array = []; let queue = []; let bfsId = nextBfsId++; @@ -402,13 +402,13 @@ export default class ModelData { while (queue.length > 0) { let node = queue.shift(); array.push(node); - let related = node._directlyRelatedModelDatas(); + let related = node._directlyRelatedRecordDatas(); for (let i = 0; i < related.length; ++i) { - let modelData = related[i]; - assert('Internal Error: seen a future bfs iteration', modelData._bfsId <= bfsId); - if (modelData._bfsId < bfsId) { - queue.push(modelData); - modelData._bfsId = bfsId; + let recordData = related[i]; + assert('Internal Error: seen a future bfs iteration', recordData._bfsId <= bfsId); + if (recordData._bfsId < bfsId) { + queue.push(recordData); + recordData._bfsId = bfsId; } } } @@ -710,7 +710,7 @@ if (isEnabled('ds-rollback-attribute')) { @method lastAcknowledgedValue @private */ - ModelData.prototype.lastAcknowledgedValue = function lastAcknowledgedValue(key) { + RecordData.prototype.lastAcknowledgedValue = function lastAcknowledgedValue(key) { if (key in this._inFlightAttributes) { return this._inFlightAttributes[key]; } else { @@ -719,9 +719,9 @@ if (isEnabled('ds-rollback-attribute')) { }; } -function assertRelationshipData(store, modelData, data, meta) { +function assertRelationshipData(store, recordData, data, meta) { assert( - `A ${modelData.modelName} record was pushed into the store with the value of ${ + `A ${recordData.modelName} record was pushed into the store with the value of ${ meta.key } being '${JSON.stringify(data)}', but ${ meta.key @@ -731,7 +731,7 @@ function assertRelationshipData(store, modelData, data, meta) { assert( `Encountered a relationship identifier without a type for the ${meta.kind} relationship '${ meta.key - }' on ${modelData}, expected a json-api identifier with type '${ + }' on ${recordData}, expected a json-api identifier with type '${ meta.type }' but found '${JSON.stringify( data @@ -741,7 +741,7 @@ function assertRelationshipData(store, modelData, data, meta) { assert( `Encountered a relationship identifier without an id for the ${meta.kind} relationship '${ meta.key - }' on ${modelData}, expected a json-api identifier but found '${JSON.stringify( + }' on ${recordData}, expected a json-api identifier but found '${JSON.stringify( data )}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || coerceId(data.id) @@ -749,7 +749,7 @@ function assertRelationshipData(store, modelData, data, meta) { assert( `Encountered a relationship identifier with type '${data.type}' for the ${ meta.kind - } relationship '${meta.key}' on ${modelData}, Expected a json-api identifier with type '${ + } relationship '${meta.key}' on ${recordData}, Expected a json-api identifier with type '${ meta.type }'. No model was found for '${data.type}'.`, data === null || !data.type || store._hasModelFor(data.type) @@ -767,17 +767,17 @@ function assertRelationshipData(store, modelData, data, meta) { // disconnected we can actually destroy the internalModel when checking for // orphaned models. function destroyRelationship(rel) { - rel.modelDataDidDematerialize(); + rel.recordDataDidDematerialize(); if (rel._inverseIsSync()) { - rel.removeAllModelDatasFromOwn(); - rel.removeAllCanonicalModelDatasFromOwn(); + rel.removeAllRecordDatasFromOwn(); + rel.removeAllCanonicalRecordDatasFromOwn(); } } -function areAllModelsUnloaded(modelDatas) { - for (let i = 0; i < modelDatas.length; ++i) { - if (modelDatas[i].isRecordInUse()) { +function areAllModelsUnloaded(recordDatas) { + for (let i = 0; i < recordDatas.length; ++i) { + if (recordDatas[i].isRecordInUse()) { return false; } } diff --git a/addon/-record-data-private/system/promise-proxies.js b/addon/-record-data-private/system/promise-proxies.js index 26fcff25cba..ed4fdfd4a90 100644 --- a/addon/-record-data-private/system/promise-proxies.js +++ b/addon/-record-data-private/system/promise-proxies.js @@ -105,7 +105,7 @@ export const PromiseBelongsTo = PromiseObject.extend({ let state = this.get('_belongsToState'); let key = state.key; let store = state.store; - let resource = state.modelData.getResourceIdentifier(); + let resource = state.recordData.getResourceIdentifier(); let internalModel = store._internalModelForResource(resource); return store.reloadBelongsTo(this, internalModel, key, options).then(() => this); diff --git a/addon/-record-data-private/system/references/belongs-to.js b/addon/-record-data-private/system/references/belongs-to.js index 1033324fc60..9f99b4aefd0 100644 --- a/addon/-record-data-private/system/references/belongs-to.js +++ b/addon/-record-data-private/system/references/belongs-to.js @@ -74,7 +74,7 @@ export default class BelongsToReference extends Reference { } _resource() { - return this.modelData.getBelongsTo(this.key); + return this.recordData.getBelongsTo(this.key); } /** @@ -149,7 +149,7 @@ export default class BelongsToReference extends Reference { ); //TODO Igor cleanup, maybe move to relationship push - this.belongsToRelationship.setCanonicalModelData(record._internalModel._modelData); + this.belongsToRelationship.setCanonicalRecordData(record._internalModel._recordData); return record; }); diff --git a/addon/-record-data-private/system/references/has-many.js b/addon/-record-data-private/system/references/has-many.js index fb813b1b6b3..4c455a09dee 100644 --- a/addon/-record-data-private/system/references/has-many.js +++ b/addon/-record-data-private/system/references/has-many.js @@ -24,7 +24,7 @@ export default class HasManyReference extends Reference { } _resource() { - return this.modelData.getHasMany(this.key); + return this.recordData.getHasMany(this.key); } /** @@ -180,7 +180,7 @@ export default class HasManyReference extends Reference { this.store ); } - return record._internalModel._modelData; + return record._internalModel._recordData; }); this.hasManyRelationship.computeChanges(internalModels); @@ -200,9 +200,9 @@ export default class HasManyReference extends Reference { let members = this.hasManyRelationship.members.toArray(); //TODO Igor cleanup - return members.every(modelData => { + return members.every(recordData => { let store = this.parentInternalModel.store; - let internalModel = store._internalModelForModelData(modelData); + let internalModel = store._internalModelForRecordData(recordData); return internalModel.isLoaded() === true; }); } diff --git a/addon/-record-data-private/system/references/reference.js b/addon/-record-data-private/system/references/reference.js index a764bd83293..db90d552136 100644 --- a/addon/-record-data-private/system/references/reference.js +++ b/addon/-record-data-private/system/references/reference.js @@ -1,7 +1,7 @@ var Reference = function(store, internalModel) { this.store = store; this.internalModel = internalModel; - this.modelData = internalModel._modelData; + this.recordData = internalModel._recordData; }; Reference.prototype = { diff --git a/addon/-record-data-private/system/relationships/state/belongs-to.js b/addon/-record-data-private/system/relationships/state/belongs-to.js index 1f82fee9f55..d8dcfe15c87 100644 --- a/addon/-record-data-private/system/relationships/state/belongs-to.js +++ b/addon/-record-data-private/system/relationships/state/belongs-to.js @@ -4,18 +4,18 @@ import { isNone } from '@ember/utils'; import Relationship from './relationship'; export default class BelongsToRelationship extends Relationship { - constructor(store, inverseKey, relationshipMeta, modelData, inverseIsAsync) { - super(store, inverseKey, relationshipMeta, modelData, inverseIsAsync); + constructor(store, inverseKey, relationshipMeta, recordData, inverseIsAsync) { + super(store, inverseKey, relationshipMeta, recordData, inverseIsAsync); this.key = relationshipMeta.key; - this.inverseModelData = null; + this.inverseRecordData = null; this.canonicalState = null; } - setModelData(modelData) { - if (modelData) { - this.addModelData(modelData); - } else if (this.inverseModelData) { - this.removeModelData(this.inverseModelData); + setRecordData(recordData) { + if (recordData) { + this.addRecordData(recordData); + } else if (this.inverseRecordData) { + this.removeRecordData(this.inverseRecordData); } this.setHasAnyRelationshipData(true); @@ -23,58 +23,58 @@ export default class BelongsToRelationship extends Relationship { this.setRelationshipIsEmpty(false); } - setCanonicalModelData(modelData) { - if (modelData) { - this.addCanonicalModelData(modelData); + setCanonicalRecordData(recordData) { + if (recordData) { + this.addCanonicalRecordData(recordData); } else if (this.canonicalState) { - this.removeCanonicalModelData(this.canonicalState); + this.removeCanonicalRecordData(this.canonicalState); } this.flushCanonicalLater(); } - setInitialCanonicalModelData(modelData) { - if (!modelData) { + setInitialCanonicalRecordData(recordData) { + if (!recordData) { return; } // When we initialize a belongsTo relationship, we want to avoid work like // notifying our internalModel that we've "changed" and excessive thrash on // setting up inverse relationships - this.canonicalMembers.add(modelData); - this.members.add(modelData); - this.inverseModelData = this.canonicalState = modelData; - this.setupInverseRelationship(modelData); + this.canonicalMembers.add(recordData); + this.members.add(recordData); + this.inverseRecordData = this.canonicalState = recordData; + this.setupInverseRelationship(recordData); } - addCanonicalModelData(modelData) { - if (this.canonicalMembers.has(modelData)) { + addCanonicalRecordData(recordData) { + if (this.canonicalMembers.has(recordData)) { return; } if (this.canonicalState) { - this.removeCanonicalModelData(this.canonicalState); + this.removeCanonicalRecordData(this.canonicalState); } - this.canonicalState = modelData; - super.addCanonicalModelData(modelData); + this.canonicalState = recordData; + super.addCanonicalRecordData(recordData); this.setHasAnyRelationshipData(true); this.setRelationshipIsEmpty(false); } inverseDidDematerialize() { - super.inverseDidDematerialize(this.inverseModelData); + super.inverseDidDematerialize(this.inverseRecordData); this.notifyBelongsToChange(); } - removeCompletelyFromOwn(modelData) { - super.removeCompletelyFromOwn(modelData); + removeCompletelyFromOwn(recordData) { + super.removeCompletelyFromOwn(recordData); - if (this.canonicalState === modelData) { + if (this.canonicalState === recordData) { this.canonicalState = null; } - if (this.inverseModelData === modelData) { - this.inverseModelData = null; + if (this.inverseRecordData === recordData) { + this.inverseRecordData = null; this.notifyBelongsToChange(); } } @@ -82,37 +82,37 @@ export default class BelongsToRelationship extends Relationship { removeCompletelyFromInverse() { super.removeCompletelyFromInverse(); - this.inverseModelData = null; + this.inverseRecordData = null; } flushCanonical() { //temporary fix to not remove newly created records if server returned null. //TODO remove once we have proper diffing - if (this.inverseModelData && this.inverseModelData.isNew() && !this.canonicalState) { + if (this.inverseRecordData && this.inverseRecordData.isNew() && !this.canonicalState) { this.willSync = false; return; } - if (this.inverseModelData !== this.canonicalState) { - this.inverseModelData = this.canonicalState; + if (this.inverseRecordData !== this.canonicalState) { + this.inverseRecordData = this.canonicalState; this.notifyBelongsToChange(); } super.flushCanonical(); } - addModelData(modelData) { - if (this.members.has(modelData)) { + addRecordData(recordData) { + if (this.members.has(recordData)) { return; } // TODO Igor cleanup - assertPolymorphicType(this.modelData, this.relationshipMeta, modelData, this.store); + assertPolymorphicType(this.recordData, this.relationshipMeta, recordData, this.store); - if (this.inverseModelData) { - this.removeModelData(this.inverseModelData); + if (this.inverseRecordData) { + this.removeRecordData(this.inverseRecordData); } - this.inverseModelData = modelData; - super.addModelData(modelData); + this.inverseRecordData = recordData; + super.addRecordData(recordData); this.notifyBelongsToChange(); } @@ -123,57 +123,57 @@ export default class BelongsToRelationship extends Relationship { content !== undefined ); // TODO Igor deal with this - this.setModelData(content ? content._internalModel._modelData : content); + this.setRecordData(content ? content._internalModel._recordData : content); } - removeModelDataFromOwn(modelData) { - if (!this.members.has(modelData)) { + removeRecordDataFromOwn(recordData) { + if (!this.members.has(recordData)) { return; } - this.inverseModelData = null; - super.removeModelDataFromOwn(modelData); + this.inverseRecordData = null; + super.removeRecordDataFromOwn(recordData); this.notifyBelongsToChange(); } - removeAllModelDatasFromOwn() { - super.removeAllModelDatasFromOwn(); - this.inverseModelData = null; + removeAllRecordDatasFromOwn() { + super.removeAllRecordDatasFromOwn(); + this.inverseRecordData = null; this.notifyBelongsToChange(); } notifyBelongsToChange() { - let modelData = this.modelData; - let storeWrapper = this.modelData.storeWrapper; + let recordData = this.recordData; + let storeWrapper = this.recordData.storeWrapper; storeWrapper.notifyBelongsToChange( - modelData.modelName, - modelData.id, - modelData.clientId, + recordData.modelName, + recordData.id, + recordData.clientId, this.key ); } - removeCanonicalModelDataFromOwn(modelData) { - if (!this.canonicalMembers.has(modelData)) { + removeCanonicalRecordDataFromOwn(recordData) { + if (!this.canonicalMembers.has(recordData)) { return; } this.canonicalState = null; this.setHasAnyRelationshipData(true); this.setRelationshipIsEmpty(true); - super.removeCanonicalModelDataFromOwn(modelData); + super.removeCanonicalRecordDataFromOwn(recordData); } - removeAllCanonicalModelDatasFromOwn() { - super.removeAllCanonicalModelDatasFromOwn(); + removeAllCanonicalRecordDatasFromOwn() { + super.removeAllCanonicalRecordDatasFromOwn(); this.canonicalState = null; } getData() { let data; let payload = {}; - if (this.inverseModelData) { - data = this.inverseModelData.getResourceIdentifier(); + if (this.inverseRecordData) { + data = this.inverseRecordData.getResourceIdentifier(); } - if (this.inverseModelData === null && this.hasAnyRelationshipData) { + if (this.inverseRecordData === null && this.hasAnyRelationshipData) { data = null; } if (this.link) { @@ -202,33 +202,33 @@ export default class BelongsToRelationship extends Relationship { * @return {boolean} */ get allInverseRecordsAreLoaded() { - let modelData = this.inverseModelData; - let isEmpty = modelData !== null && modelData.isEmpty(); + let recordData = this.inverseRecordData; + let isEmpty = recordData !== null && recordData.isEmpty(); return !isEmpty; } updateData(data, initial) { - let modelData; + let recordData; if (isNone(data)) { - modelData = null; + recordData = null; } assert( `Ember Data expected the data for the ${ this.key - } relationship on a ${this.modelData.toString()} to be in a JSON API format and include an \`id\` and \`type\` property but it found ${inspect( + } relationship on a ${this.recordData.toString()} to be in a JSON API format and include an \`id\` and \`type\` property but it found ${inspect( data )}. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || (data.id !== undefined && data.type !== undefined) ); - if (modelData !== null) { - modelData = this.modelData.storeWrapper.modelDataFor(data.type, data.id); + if (recordData !== null) { + recordData = this.recordData.storeWrapper.recordDataFor(data.type, data.id); } if (initial) { - this.setInitialCanonicalModelData(modelData); + this.setInitialCanonicalRecordData(recordData); } else { - this.setCanonicalModelData(modelData); + this.setCanonicalRecordData(recordData); } } } diff --git a/addon/-record-data-private/system/relationships/state/create.js b/addon/-record-data-private/system/relationships/state/create.js index 61e20400804..bb0505c4fcc 100644 --- a/addon/-record-data-private/system/relationships/state/create.js +++ b/addon/-record-data-private/system/relationships/state/create.js @@ -1,29 +1,29 @@ import ManyRelationship from './has-many'; import BelongsToRelationship from './belongs-to'; -function createRelationshipFor(relationshipMeta, store, modelData, key) { - let inverseKey = modelData.storeWrapper.inverseForRelationship(modelData.modelName, key); - let inverseIsAsync = modelData.storeWrapper.inverseIsAsyncForRelationship( - modelData.modelName, +function createRelationshipFor(relationshipMeta, store, recordData, key) { + let inverseKey = recordData.storeWrapper.inverseForRelationship(recordData.modelName, key); + let inverseIsAsync = recordData.storeWrapper.inverseIsAsyncForRelationship( + recordData.modelName, key ); if (relationshipMeta.kind === 'hasMany') { - return new ManyRelationship(store, inverseKey, relationshipMeta, modelData, inverseIsAsync); + return new ManyRelationship(store, inverseKey, relationshipMeta, recordData, inverseIsAsync); } else { return new BelongsToRelationship( store, inverseKey, relationshipMeta, - modelData, + recordData, inverseIsAsync ); } } export default class Relationships { - constructor(modelData) { - this.modelData = modelData; + constructor(recordData) { + this.recordData = recordData; this.initializedRelationships = Object.create(null); } @@ -43,16 +43,16 @@ export default class Relationships { let relationship = relationships[key]; if (!relationship) { - let modelData = this.modelData; - let rel = this.modelData.storeWrapper.relationshipsDefinitionFor(this.modelData.modelName)[ + let recordData = this.recordData; + let rel = this.recordData.storeWrapper.relationshipsDefinitionFor(this.recordData.modelName)[ key ]; if (rel) { relationship = relationships[key] = createRelationshipFor( rel, - modelData.store, - modelData, + recordData.store, + recordData, key ); } diff --git a/addon/-record-data-private/system/relationships/state/has-many.js b/addon/-record-data-private/system/relationships/state/has-many.js index be2e44c5e07..c5c2c48caba 100755 --- a/addon/-record-data-private/system/relationships/state/has-many.js +++ b/addon/-record-data-private/system/relationships/state/has-many.js @@ -4,8 +4,8 @@ import OrderedSet from '../../ordered-set'; import { isNone } from '@ember/utils'; export default class ManyRelationship extends Relationship { - constructor(store, inverseKey, relationshipMeta, modelData, inverseIsAsync) { - super(store, inverseKey, relationshipMeta, modelData, inverseIsAsync); + constructor(store, inverseKey, relationshipMeta, recordData, inverseIsAsync) { + super(store, inverseKey, relationshipMeta, recordData, inverseIsAsync); this.canonicalState = []; this.currentState = []; this._willUpdateManyArray = false; @@ -22,77 +22,77 @@ export default class ManyRelationship extends Relationship { */ } - addCanonicalModelData(modelData, idx) { - if (this.canonicalMembers.has(modelData)) { + addCanonicalRecordData(recordData, idx) { + if (this.canonicalMembers.has(recordData)) { return; } if (idx !== undefined) { - this.canonicalState.splice(idx, 0, modelData); + this.canonicalState.splice(idx, 0, recordData); } else { - this.canonicalState.push(modelData); + this.canonicalState.push(recordData); } - super.addCanonicalModelData(modelData, idx); + super.addCanonicalRecordData(recordData, idx); } - inverseDidDematerialize(inverseModelData) { - super.inverseDidDematerialize(inverseModelData); + inverseDidDematerialize(inverseRecordData) { + super.inverseDidDematerialize(inverseRecordData); if (this.isAsync) { this.notifyManyArrayIsStale(); } } - addModelData(modelData, idx) { - if (this.members.has(modelData)) { + addRecordData(recordData, idx) { + if (this.members.has(recordData)) { return; } - assertPolymorphicType(this.modelData, this.relationshipMeta, modelData, this.store); - super.addModelData(modelData, idx); + assertPolymorphicType(this.recordData, this.relationshipMeta, recordData, this.store); + super.addRecordData(recordData, idx); // make lazy later if (idx === undefined) { idx = this.currentState.length; } - this.currentState.splice(idx, 0, modelData); + this.currentState.splice(idx, 0, recordData); // TODO Igor consider making direct to remove the indirection // We are not lazily accessing the manyArray here because the change is coming from app side // this.manyArray.flushCanonical(this.currentState); this.notifyHasManyChange(); } - removeCanonicalModelDataFromOwn(modelData, idx) { + removeCanonicalRecordDataFromOwn(recordData, idx) { let i = idx; - if (!this.canonicalMembers.has(modelData)) { + if (!this.canonicalMembers.has(recordData)) { return; } if (i === undefined) { - i = this.canonicalState.indexOf(modelData); + i = this.canonicalState.indexOf(recordData); } if (i > -1) { this.canonicalState.splice(i, 1); } - super.removeCanonicalModelDataFromOwn(modelData, idx); + super.removeCanonicalRecordDataFromOwn(recordData, idx); //TODO(Igor) Figure out what to do here } - removeAllCanonicalModelDatasFromOwn() { - super.removeAllCanonicalModelDatasFromOwn(); + removeAllCanonicalRecordDatasFromOwn() { + super.removeAllCanonicalRecordDatasFromOwn(); this.canonicalMembers.clear(); this.canonicalState.splice(0, this.canonicalState.length); - super.removeAllCanonicalModelDatasFromOwn(); + super.removeAllCanonicalRecordDatasFromOwn(); } //TODO(Igor) DO WE NEED THIS? - removeCompletelyFromOwn(modelData) { - super.removeCompletelyFromOwn(modelData); + removeCompletelyFromOwn(recordData) { + super.removeCompletelyFromOwn(recordData); // TODO SkEPTICAL - const canonicalIndex = this.canonicalState.indexOf(modelData); + const canonicalIndex = this.canonicalState.indexOf(recordData); if (canonicalIndex !== -1) { this.canonicalState.splice(canonicalIndex, 1); } - this.removeModelDataFromOwn(modelData); + this.removeRecordDataFromOwn(recordData); } flushCanonical() { @@ -100,15 +100,15 @@ export default class ManyRelationship extends Relationship { //a hack for not removing new records //TODO remove once we have proper diffing - let newModelDatas = this.currentState.filter( + let newRecordDatas = this.currentState.filter( // only add new internalModels which are not yet in the canonical state of this // relationship (a new internalModel can be in the canonical state if it has // been 'acknowleged' to be in the relationship via a store.push) //TODO Igor deal with this - modelData => modelData.isNew() && toSet.indexOf(modelData) === -1 + recordData => recordData.isNew() && toSet.indexOf(recordData) === -1 ); - toSet = toSet.concat(newModelDatas); + toSet = toSet.concat(newRecordDatas); /* if (this._manyArray) { @@ -122,9 +122,9 @@ export default class ManyRelationship extends Relationship { } //TODO(Igor) idx not used currently, fix - removeModelDataFromOwn(modelData, idx) { - super.removeModelDataFromOwn(modelData, idx); - let index = idx || this.currentState.indexOf(modelData); + removeRecordDataFromOwn(recordData, idx) { + super.removeRecordDataFromOwn(recordData, idx); + let index = idx || this.currentState.indexOf(recordData); //TODO IGOR DAVID INVESTIGATE if (index === -1) { @@ -141,42 +141,42 @@ export default class ManyRelationship extends Relationship { this.notifyHasManyChange(); } - computeChanges(modelDatas = []) { + computeChanges(recordDatas = []) { let members = this.canonicalMembers; - let modelDatasToRemove = []; - let modelDatasSet = setForArray(modelDatas); + let recordDatasToRemove = []; + let recordDatasSet = setForArray(recordDatas); members.forEach(member => { - if (modelDatasSet.has(member)) { + if (recordDatasSet.has(member)) { return; } - modelDatasToRemove.push(member); + recordDatasToRemove.push(member); }); - this.removeCanonicalModelDatas(modelDatasToRemove); + this.removeCanonicalRecordDatas(recordDatasToRemove); - for (let i = 0, l = modelDatas.length; i < l; i++) { - let modelData = modelDatas[i]; - this.removeCanonicalModelData(modelData); - this.addCanonicalModelData(modelData, i); + for (let i = 0, l = recordDatas.length; i < l; i++) { + let recordData = recordDatas[i]; + this.removeCanonicalRecordData(recordData); + this.addCanonicalRecordData(recordData, i); } } - setInitialModelDatas(modelDatas) { - if (Array.isArray(modelDatas) === false || modelDatas.length === 0) { + setInitialRecordDatas(recordDatas) { + if (Array.isArray(recordDatas) === false || recordDatas.length === 0) { return; } - for (let i = 0; i < modelDatas.length; i++) { - let modelData = modelDatas[i]; - if (this.canonicalMembers.has(modelData)) { + for (let i = 0; i < recordDatas.length; i++) { + let recordData = recordDatas[i]; + if (this.canonicalMembers.has(recordData)) { continue; } - this.canonicalMembers.add(modelData); - this.members.add(modelData); - this.setupInverseRelationship(modelData); + this.canonicalMembers.add(recordData); + this.members.add(recordData); + this.setupInverseRelationship(recordData); } this.canonicalState = this.canonicalMembers.toArray(); @@ -190,23 +190,23 @@ export default class ManyRelationship extends Relationship { - @runspired */ notifyManyArrayIsStale() { - let modelData = this.modelData; - let storeWrapper = modelData.storeWrapper; + let recordData = this.recordData; + let storeWrapper = recordData.storeWrapper; storeWrapper.notifyPropertyChange( - modelData.modelName, - modelData.id, - modelData.clientId, + recordData.modelName, + recordData.id, + recordData.clientId, this.key ); } notifyHasManyChange() { - let modelData = this.modelData; - let storeWrapper = modelData.storeWrapper; + let recordData = this.recordData; + let storeWrapper = recordData.storeWrapper; storeWrapper.notifyHasManyChange( - modelData.modelName, - modelData.id, - modelData.clientId, + recordData.modelName, + recordData.id, + recordData.clientId, this.key ); } @@ -214,7 +214,7 @@ export default class ManyRelationship extends Relationship { getData() { let payload = {}; if (this.hasAnyRelationshipData) { - payload.data = this.currentState.map(modelData => modelData.getResourceIdentifier()); + payload.data = this.currentState.map(recordData => recordData.getResourceIdentifier()); } if (this.link) { payload.links = { @@ -233,19 +233,19 @@ export default class ManyRelationship extends Relationship { } updateData(data, initial) { - let modelDatas; + let recordDatas; if (isNone(data)) { - modelDatas = undefined; + recordDatas = undefined; } else { - modelDatas = new Array(data.length); + recordDatas = new Array(data.length); for (let i = 0; i < data.length; i++) { - modelDatas[i] = this.modelData.storeWrapper.modelDataFor(data[i].type, data[i].id); + recordDatas[i] = this.recordData.storeWrapper.recordDataFor(data[i].type, data[i].id); } } if (initial) { - this.setInitialModelDatas(modelDatas); + this.setInitialRecordDatas(recordDatas); } else { - this.updateModelDatasFromAdapter(modelDatas); + this.updateRecordDatasFromAdapter(recordDatas); } } diff --git a/addon/-record-data-private/system/relationships/state/relationship.js b/addon/-record-data-private/system/relationships/state/relationship.js index 48f5d57f7cc..0e98d0493a2 100644 --- a/addon/-record-data-private/system/relationships/state/relationship.js +++ b/addon/-record-data-private/system/relationships/state/relationship.js @@ -7,58 +7,58 @@ import OrderedSet from '../../ordered-set'; import _normalizeLink from '../../normalize-link'; const { - addCanonicalModelData, - addCanonicalModelDatas, - addModelData, - addModelDatas, + addCanonicalRecordData, + addCanonicalRecordDatas, + addRecordData, + addRecordDatas, clear, flushCanonical, flushCanonicalLater, newRelationship, push, - removeCanonicalModelData, - removeCanonicalModelDataFromInverse, - removeCanonicalModelDataFromOwn, - removeCanonicalModelDatas, - removeModelData, - removeModelDataFromInverse, - removeModelDataFromOwn, - removeModelDatas, + removeCanonicalRecordData, + removeCanonicalRecordDataFromInverse, + removeCanonicalRecordDataFromOwn, + removeCanonicalRecordDatas, + removeRecordData, + removeRecordDataFromInverse, + removeRecordDataFromOwn, + removeRecordDatas, updateLink, updateMeta, - updateModelDatasFromAdapter, + updateRecordDatasFromAdapter, } = heimdall.registerMonitor( 'system.relationships.state.relationship', - 'addCanonicalModelData', - 'addCanonicalModelDatas', - 'addModelData', - 'addModelDatas', + 'addCanonicalRecordData', + 'addCanonicalRecordDatas', + 'addRecordData', + 'addRecordDatas', 'clear', 'flushCanonical', 'flushCanonicalLater', 'newRelationship', 'push', - 'removeCanonicalModelData', - 'removeCanonicalModelDataFromInverse', - 'removeCanonicalModelDataFromOwn', - 'removeCanonicalModelDatas', - 'removeModelData', - 'removeModelDataFromInverse', - 'removeModelDataFromOwn', - 'removeModelDatas', + 'removeCanonicalRecordData', + 'removeCanonicalRecordDataFromInverse', + 'removeCanonicalRecordDataFromOwn', + 'removeCanonicalRecordDatas', + 'removeRecordData', + 'removeRecordDataFromInverse', + 'removeRecordDataFromOwn', + 'removeRecordDatas', 'updateLink', 'updateMeta', - 'updateModelDatasFromAdapter' + 'updateRecordDatasFromAdapter' ); export default class Relationship { - constructor(store, inverseKey, relationshipMeta, modelData, inverseIsAsync) { + constructor(store, inverseKey, relationshipMeta, recordData, inverseIsAsync) { heimdall.increment(newRelationship); this.inverseIsAsync = inverseIsAsync; this.kind = relationshipMeta.kind; let async = relationshipMeta.options.async; let polymorphic = relationshipMeta.options.polymorphic; - this.modelData = modelData; + this.recordData = recordData; this.members = new OrderedSet(); this.canonicalMembers = new OrderedSet(); this.store = store; @@ -97,12 +97,12 @@ export default class Relationship { in this case `hasFailedLoadAttempt` ought to be `true`. false when - => modelData.isNew() on initial setup + => recordData.isNew() on initial setup => a previously triggered request has resolved => we get relationship data via push true when - => !modelData.isNew() on initial setup + => !recordData.isNew() on initial setup => an inverse has been unloaded => we get a new link for the relationship @@ -189,7 +189,7 @@ export default class Relationship { } get isNew() { - return this.modelData.isNew(); + return this.recordData.isNew(); } _inverseIsAsync() { @@ -200,14 +200,14 @@ export default class Relationship { return this.inverseKey && !this.inverseIsAsync; } - _hasSupportForImplicitRelationships(modelData) { + _hasSupportForImplicitRelationships(recordData) { return ( - modelData._implicitRelationships !== undefined && modelData._implicitRelationships !== null + recordData._implicitRelationships !== undefined && recordData._implicitRelationships !== null ); } - _hasSupportForRelationships(modelData) { - return modelData._relationships !== undefined && modelData._relationships !== null; + _hasSupportForRelationships(recordData) { + return recordData._relationships !== undefined && recordData._relationships !== null; } get _inverseMeta() { @@ -229,7 +229,7 @@ export default class Relationship { return this.internalModel.modelName; } - modelDataDidDematerialize() { + recordDataDidDematerialize() { if (!this.inverseKey) { return; } @@ -238,12 +238,12 @@ export default class Relationship { // we actually want a union of members and canonicalMembers // they should be disjoint but currently are not due to a bug - this.forAllMembers(inverseModelData => { - if (!this._hasSupportForRelationships(inverseModelData)) { + this.forAllMembers(inverseRecordData => { + if (!this._hasSupportForRelationships(inverseRecordData)) { return; } - let relationship = inverseModelData._relationships.get(this.inverseKey); - relationship.inverseDidDematerialize(this.modelData); + let relationship = inverseRecordData._relationships.get(this.inverseKey); + relationship.inverseDidDematerialize(this.recordData); }); } @@ -269,13 +269,13 @@ export default class Relationship { } } - inverseDidDematerialize(inverseModelData) { + inverseDidDematerialize(inverseRecordData) { if (!this.isAsync) { // unloading inverse of a sync relationship is treated as a client-side // delete, so actually remove the models don't merely invalidate the cp // cache. - this.removeModelDataFromOwn(inverseModelData); - this.removeCanonicalModelDataFromOwn(inverseModelData); + this.removeRecordDataFromOwn(inverseRecordData); + this.removeCanonicalRecordDataFromOwn(inverseRecordData); this.setRelationshipIsEmpty(true); } else { this.setHasDematerializedInverse(true); @@ -293,117 +293,117 @@ export default class Relationship { let members = this.members.list; while (members.length > 0) { let member = members[0]; - this.removeModelData(member); + this.removeRecordData(member); } let canonicalMembers = this.canonicalMembers.list; while (canonicalMembers.length > 0) { let member = canonicalMembers[0]; - this.removeCanonicalModelData(member); + this.removeCanonicalRecordData(member); } } - removeAllModelDatasFromOwn() { + removeAllRecordDatasFromOwn() { this.setRelationshipIsStale(true); this.members.clear(); } - removeAllCanonicalModelDatasFromOwn() { + removeAllCanonicalRecordDatasFromOwn() { this.canonicalMembers.clear(); this.flushCanonicalLater(); } - removeModelDatas(modelDatas) { - heimdall.increment(removeModelDatas); - modelDatas.forEach(modelData => this.removeModelData(modelData)); + removeRecordDatas(recordDatas) { + heimdall.increment(removeRecordDatas); + recordDatas.forEach(recordData => this.removeRecordData(recordData)); } - addModelDatas(modelDatas, idx) { - heimdall.increment(addModelDatas); - modelDatas.forEach(modelData => { - this.addModelData(modelData, idx); + addRecordDatas(recordDatas, idx) { + heimdall.increment(addRecordDatas); + recordDatas.forEach(recordData => { + this.addRecordData(recordData, idx); if (idx !== undefined) { idx++; } }); } - addCanonicalModelDatas(modelDatas, idx) { - heimdall.increment(addCanonicalModelDatas); - for (let i = 0; i < modelDatas.length; i++) { + addCanonicalRecordDatas(recordDatas, idx) { + heimdall.increment(addCanonicalRecordDatas); + for (let i = 0; i < recordDatas.length; i++) { if (idx !== undefined) { - this.addCanonicalModelData(modelDatas[i], i + idx); + this.addCanonicalRecordData(recordDatas[i], i + idx); } else { - this.addCanonicalModelData(modelDatas[i]); + this.addCanonicalRecordData(recordDatas[i]); } } } - addCanonicalModelData(modelData, idx) { - heimdall.increment(addCanonicalModelData); - if (!this.canonicalMembers.has(modelData)) { - this.canonicalMembers.add(modelData); - this.setupInverseRelationship(modelData); + addCanonicalRecordData(recordData, idx) { + heimdall.increment(addCanonicalRecordData); + if (!this.canonicalMembers.has(recordData)) { + this.canonicalMembers.add(recordData); + this.setupInverseRelationship(recordData); } this.flushCanonicalLater(); this.setHasAnyRelationshipData(true); } - setupInverseRelationship(modelData) { + setupInverseRelationship(recordData) { if (this.inverseKey) { - if (!this._hasSupportForRelationships(modelData)) { + if (!this._hasSupportForRelationships(recordData)) { return; } - let relationships = modelData._relationships; + let relationships = recordData._relationships; let relationship = relationships.get(this.inverseKey); // if we have only just initialized the inverse relationship, then it - // already has this.modelData in its canonicalMembers, so skip the + // already has this.recordData in its canonicalMembers, so skip the // unnecessary work. The exception to this is polymorphic // relationships whose members are determined by their inverse, as those // relationships cannot efficiently find their inverse payloads. - relationship.addCanonicalModelData(this.modelData); + relationship.addCanonicalRecordData(this.recordData); } else { - if (!this._hasSupportForImplicitRelationships(modelData)) { + if (!this._hasSupportForImplicitRelationships(recordData)) { return; } - let relationships = modelData._implicitRelationships; + let relationships = recordData._implicitRelationships; let relationship = relationships[this.inverseKeyForImplicit]; if (!relationship) { relationship = relationships[this.inverseKeyForImplicit] = new Relationship( this.store, this.key, { options: { async: this.isAsync } }, - modelData + recordData ); } - relationship.addCanonicalModelData(this.modelData); + relationship.addCanonicalRecordData(this.recordData); } } - removeCanonicalModelDatas(modelDatas, idx) { - heimdall.increment(removeCanonicalModelDatas); - for (let i = 0; i < modelDatas.length; i++) { + removeCanonicalRecordDatas(recordDatas, idx) { + heimdall.increment(removeCanonicalRecordDatas); + for (let i = 0; i < recordDatas.length; i++) { if (idx !== undefined) { - this.removeCanonicalModelData(modelDatas[i], i + idx); + this.removeCanonicalRecordData(recordDatas[i], i + idx); } else { - this.removeCanonicalModelData(modelDatas[i]); + this.removeCanonicalRecordData(recordDatas[i]); } } } - removeCanonicalModelData(modelData, idx) { - heimdall.increment(removeCanonicalModelData); - if (this.canonicalMembers.has(modelData)) { - this.removeCanonicalModelDataFromOwn(modelData); + removeCanonicalRecordData(recordData, idx) { + heimdall.increment(removeCanonicalRecordData); + if (this.canonicalMembers.has(recordData)) { + this.removeCanonicalRecordDataFromOwn(recordData); if (this.inverseKey) { - this.removeCanonicalModelDataFromInverse(modelData); + this.removeCanonicalRecordDataFromInverse(recordData); } else { if ( - this._hasSupportForImplicitRelationships(modelData) && - modelData._implicitRelationships[this.inverseKeyForImplicit] + this._hasSupportForImplicitRelationships(recordData) && + recordData._implicitRelationships[this.inverseKeyForImplicit] ) { - modelData._implicitRelationships[this.inverseKeyForImplicit].removeCanonicalModelData( - this.modelData + recordData._implicitRelationships[this.inverseKeyForImplicit].removeCanonicalRecordData( + this.recordData ); } } @@ -411,82 +411,82 @@ export default class Relationship { this.flushCanonicalLater(); } - addModelData(modelData, idx) { - heimdall.increment(addModelData); - if (!this.members.has(modelData)) { - this.members.addWithIndex(modelData, idx); - this.notifyRecordRelationshipAdded(modelData, idx); - if (this._hasSupportForRelationships(modelData) && this.inverseKey) { - modelData._relationships.get(this.inverseKey).addModelData(this.modelData); + addRecordData(recordData, idx) { + heimdall.increment(addRecordData); + if (!this.members.has(recordData)) { + this.members.addWithIndex(recordData, idx); + this.notifyRecordRelationshipAdded(recordData, idx); + if (this._hasSupportForRelationships(recordData) && this.inverseKey) { + recordData._relationships.get(this.inverseKey).addRecordData(this.recordData); } else { - if (this._hasSupportForImplicitRelationships(modelData)) { - if (!modelData._implicitRelationships[this.inverseKeyForImplicit]) { - modelData._implicitRelationships[this.inverseKeyForImplicit] = new Relationship( + if (this._hasSupportForImplicitRelationships(recordData)) { + if (!recordData._implicitRelationships[this.inverseKeyForImplicit]) { + recordData._implicitRelationships[this.inverseKeyForImplicit] = new Relationship( this.store, this.key, { options: { async: this.isAsync } }, - modelData, + recordData, this.isAsync ); } - modelData._implicitRelationships[this.inverseKeyForImplicit].addModelData(this.modelData); + recordData._implicitRelationships[this.inverseKeyForImplicit].addRecordData(this.recordData); } } } this.setHasAnyRelationshipData(true); } - removeModelData(modelData) { - heimdall.increment(removeModelData); - if (this.members.has(modelData)) { - this.removeModelDataFromOwn(modelData); + removeRecordData(recordData) { + heimdall.increment(removeRecordData); + if (this.members.has(recordData)) { + this.removeRecordDataFromOwn(recordData); if (this.inverseKey) { - this.removeModelDataFromInverse(modelData); + this.removeRecordDataFromInverse(recordData); } else { if ( - this._hasSupportForImplicitRelationships(modelData) && - modelData._implicitRelationships[this.inverseKeyForImplicit] + this._hasSupportForImplicitRelationships(recordData) && + recordData._implicitRelationships[this.inverseKeyForImplicit] ) { - modelData._implicitRelationships[this.inverseKeyForImplicit].removeModelData( - this.modelData + recordData._implicitRelationships[this.inverseKeyForImplicit].removeRecordData( + this.recordData ); } } } } - removeModelDataFromInverse(modelData) { - heimdall.increment(removeModelDataFromInverse); - if (!this._hasSupportForRelationships(modelData)) { + removeRecordDataFromInverse(recordData) { + heimdall.increment(removeRecordDataFromInverse); + if (!this._hasSupportForRelationships(recordData)) { return; } - let inverseRelationship = modelData._relationships.get(this.inverseKey); + let inverseRelationship = recordData._relationships.get(this.inverseKey); //Need to check for existence, as the record might unloading at the moment if (inverseRelationship) { - inverseRelationship.removeModelDataFromOwn(this.modelData); + inverseRelationship.removeRecordDataFromOwn(this.recordData); } } - removeModelDataFromOwn(modelData) { - heimdall.increment(removeModelDataFromOwn); - this.members.delete(modelData); + removeRecordDataFromOwn(recordData) { + heimdall.increment(removeRecordDataFromOwn); + this.members.delete(recordData); } - removeCanonicalModelDataFromInverse(modelData) { - heimdall.increment(removeCanonicalModelDataFromInverse); - if (!this._hasSupportForRelationships(modelData)) { + removeCanonicalRecordDataFromInverse(recordData) { + heimdall.increment(removeCanonicalRecordDataFromInverse); + if (!this._hasSupportForRelationships(recordData)) { return; } - let inverseRelationship = modelData._relationships.get(this.inverseKey); + let inverseRelationship = recordData._relationships.get(this.inverseKey); //Need to check for existence, as the record might unloading at the moment if (inverseRelationship) { - inverseRelationship.removeCanonicalModelDataFromOwn(this.modelData); + inverseRelationship.removeCanonicalRecordDataFromOwn(this.recordData); } } - removeCanonicalModelDataFromOwn(modelData) { - heimdall.increment(removeCanonicalModelDataFromOwn); - this.canonicalMembers.delete(modelData); + removeCanonicalRecordDataFromOwn(recordData) { + heimdall.increment(removeCanonicalRecordDataFromOwn); + this.canonicalMembers.delete(recordData); this.flushCanonicalLater(); } @@ -506,14 +506,14 @@ export default class Relationship { // we actually want a union of members and canonicalMembers // they should be disjoint but currently are not due to a bug let seen = Object.create(null); - const modelData = this.modelData; + const recordData = this.recordData; - const unload = inverseModelData => { - const id = guidFor(inverseModelData); + const unload = inverseRecordData => { + const id = guidFor(inverseRecordData); - if (this._hasSupportForRelationships(inverseModelData) && seen[id] === undefined) { - const relationship = inverseModelData._relationships.get(this.inverseKey); - relationship.removeCompletelyFromOwn(modelData); + if (this._hasSupportForRelationships(inverseRecordData) && seen[id] === undefined) { + const relationship = inverseRecordData._relationships.get(this.inverseKey); + relationship.removeCompletelyFromOwn(recordData); seen[id] = true; } }; @@ -527,34 +527,34 @@ export default class Relationship { } /* - Removes the given ModelData from BOTH canonical AND current state. + Removes the given RecordData from BOTH canonical AND current state. This method is useful when either a deletion or a rollback on a new record needs to entirely purge itself from an inverse relationship. */ - removeCompletelyFromOwn(modelData) { - this.canonicalMembers.delete(modelData); - this.members.delete(modelData); + removeCompletelyFromOwn(recordData) { + this.canonicalMembers.delete(recordData); + this.members.delete(recordData); } flushCanonical() { heimdall.increment(flushCanonical); let list = this.members.list; this.willSync = false; - //a hack for not removing new ModelDatas + //a hack for not removing new RecordDatas //TODO remove once we have proper diffing - let newModelDatas = []; + let newRecordDatas = []; for (let i = 0; i < list.length; i++) { // TODO Igor deal with this if (list[i].isNew()) { - newModelDatas.push(list[i]); + newRecordDatas.push(list[i]); } } //TODO(Igor) make this less abysmally slow this.members = this.canonicalMembers.copy(); - for (let i = 0; i < newModelDatas.length; i++) { - this.members.add(newModelDatas[i]); + for (let i = 0; i < newRecordDatas.length; i++) { + this.members.add(newRecordDatas[i]); } } @@ -571,7 +571,7 @@ export default class Relationship { updateLink(link) { heimdall.increment(updateLink); warn( - `You pushed a record of type '${this.modelData.modelName}' with a relationship '${ + `You pushed a record of type '${this.recordData.modelName}' with a relationship '${ this.key }' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload. EmberData will treat this relationship as known-to-be-empty.`, this.isAsync || this.hasAnyRelationshipData, @@ -580,7 +580,7 @@ export default class Relationship { } ); assert( - `You have pushed a record of type '${this.modelData.modelName}' with '${ + `You have pushed a record of type '${this.recordData.modelName}' with '${ this.key }' as a link, but the value of that link is not a string.`, typeof link === 'string' || link === null @@ -589,12 +589,12 @@ export default class Relationship { this.link = link; } - updateModelDatasFromAdapter(modelDatas) { - heimdall.increment(updateModelDatasFromAdapter); + updateRecordDatasFromAdapter(recordDatas) { + heimdall.increment(updateRecordDatasFromAdapter); this.setHasAnyRelationshipData(true); //TODO(Igor) move this to a proper place //TODO Once we have adapter support, we need to handle updated and canonical changes - this.computeChanges(modelDatas); + this.computeChanges(recordDatas); } notifyRecordRelationshipAdded() {} @@ -678,12 +678,12 @@ export default class Relationship { this.setRelationshipIsStale(true); if (!initial) { - let modelData = this.modelData; - let storeWrapper = this.modelData.storeWrapper; + let recordData = this.recordData; + let storeWrapper = this.recordData.storeWrapper; storeWrapper.notifyPropertyChange( - modelData.modelName, - modelData.id, - modelData.clientId, + recordData.modelName, + recordData.id, + recordData.clientId, this.key ); } diff --git a/addon/-record-data-private/system/snapshot.js b/addon/-record-data-private/system/snapshot.js index f61b9591660..88b208e0bc9 100644 --- a/addon/-record-data-private/system/snapshot.js +++ b/addon/-record-data-private/system/snapshot.js @@ -240,7 +240,7 @@ export default class Snapshot { ); } - relationship = this._internalModel._modelData._relationships.get(keyName); + relationship = this._internalModel._recordData._relationships.get(keyName); let value = relationship.getData(); let data = value && value.data; @@ -322,7 +322,7 @@ export default class Snapshot { ); } - relationship = this._internalModel._modelData._relationships.get(keyName); + relationship = this._internalModel._recordData._relationships.get(keyName); let value = relationship.getData(); diff --git a/addon/-record-data-private/system/store.js b/addon/-record-data-private/system/store.js index aba06158884..8dc63d72868 100644 --- a/addon/-record-data-private/system/store.js +++ b/addon/-record-data-private/system/store.js @@ -21,7 +21,7 @@ import { DEBUG } from '@glimmer/env'; import Model from './model/model'; import normalizeModelName from './normalize-model-name'; import IdentityMap from './identity-map'; -import ModelDataWrapper from './store/model-data-wrapper'; +import RecordDataWrapper from './store/record-data-wrapper'; import { promiseArray, promiseObject } from './promise-proxies'; @@ -44,7 +44,7 @@ import { getOwner } from '../utils'; import coerceId from './coerce-id'; import RecordArrayManager from './record-array-manager'; import InternalModel from './model/internal-model'; -import ModelData from './model/model-data'; +import RecordData from './model/record-data'; import edBackburner from './backburner'; const badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; @@ -226,7 +226,7 @@ Store = Service.extend({ this._adapterCache = Object.create(null); this._serializerCache = Object.create(null); - this.modelDataWrapper = new ModelDataWrapper(this); + this.recordDataWrapper = new RecordDataWrapper(this); if (DEBUG) { this.shouldAssertMethodCallsOnDestroyedStore = @@ -399,7 +399,7 @@ Store = Service.extend({ let internalModel = this._buildInternalModel(normalizedModelName, properties.id); internalModel.loadedData(); - // TODO this exists just to proxy `isNew` to ModelData which is weird + // TODO this exists just to proxy `isNew` to RecordData which is weird internalModel.didCreateRecord(); return internalModel.getRecord(properties); @@ -1403,7 +1403,7 @@ Store = Service.extend({ relationshipMeta, options ).then(internalModels => { - let payload = { data: internalModels.map(im => im._modelData.getResourceIdentifier()) }; + let payload = { data: internalModels.map(im => im._recordData.getResourceIdentifier()) }; if (internalModels.meta !== undefined) { payload.meta = internalModels.meta; } @@ -1486,7 +1486,7 @@ Store = Service.extend({ relationshipMeta, options ).then(internalModel => { - let response = internalModel && internalModel._modelData.getResourceIdentifier(); + let response = internalModel && internalModel._recordData.getResourceIdentifier(); parentInternalModel.linkWasLoadedForRelationship(relationshipMeta.key, { data: response }); if (internalModel === null) { return null; @@ -2927,21 +2927,21 @@ Store = Service.extend({ return internalModel; }, - _createModelData(modelName, id, clientId, internalModel) { - return this.createModelDataFor(modelName, id, clientId, this.modelDataWrapper); + _createRecordData(modelName, id, clientId, internalModel) { + return this.createRecordDataFor(modelName, id, clientId, this.recordDataWrapper); }, - createModelDataFor(modelName, id, clientId, storeWrapper) { - return new ModelData(modelName, id, clientId, storeWrapper, this); + createRecordDataFor(modelName, id, clientId, storeWrapper) { + return new RecordData(modelName, id, clientId, storeWrapper, this); }, - modelDataFor(modelName, id, clientId) { + recordDataFor(modelName, id, clientId) { let internalModel = this._internalModelForId(modelName, id, clientId); - return internalModel._modelData; + return internalModel._recordData; }, - _internalModelForModelData(modelData) { - let resource = modelData.getResourceIdentifier(); + _internalModelForRecordData(recordData) { + let resource = recordData.getResourceIdentifier(); return this._internalModelForId(resource.type, resource.id, resource.clientId); }, /** diff --git a/addon/-record-data-private/system/store/model-data-wrapper.js b/addon/-record-data-private/system/store/record-data-wrapper.js similarity index 93% rename from addon/-record-data-private/system/store/model-data-wrapper.js rename to addon/-record-data-private/system/store/record-data-wrapper.js index a92afe13bc7..01747c1a36c 100644 --- a/addon/-record-data-private/system/store/model-data-wrapper.js +++ b/addon/-record-data-private/system/store/record-data-wrapper.js @@ -1,4 +1,4 @@ -export default class ModelDataWrapper { +export default class RecordDataWrapper { constructor(store) { this.store = store; this._willUpdateManyArrays = false; @@ -74,8 +74,8 @@ export default class ModelDataWrapper { internalModel.notifyBelongsToChange(key); } - modelDataFor(modelName, id, clientId) { - return this.store.modelDataFor(modelName, id, clientId); + recordDataFor(modelName, id, clientId) { + return this.store.recordDataFor(modelName, id, clientId); } setRecordId(modelName, id, clientId) { @@ -93,7 +93,7 @@ export default class ModelDataWrapper { disconnectRecord(modelName, id, clientId) { let internalModel = this.store._getInternalModelForId(modelName, id, clientId); if (internalModel) { - internalModel.destroyFromModelData(); + internalModel.destroyFromRecordData(); } } } diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 6caa286b03d..26b750bfd7a 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -798,17 +798,17 @@ testRecordData('unloading a disconnected subgraph clears the relevant internal m let internalModel = record._internalModel; let origCheck = internalModel._checkForOrphanedInternalModels; - let modelData = internalModel._modelData; - let origCleanup = modelData._cleanupOrphanedModelDatas; + let recordData = internalModel._recordData; + let origCleanup = recordData._cleanupOrphanedRecordDatas; internalModel._checkForOrphanedInternalModels = function() { ++checkOrphanCalls; return origCheck.apply(record._internalModel, arguments); }; - modelData._cleanupOrphanedModelDatas = function() { + recordData._cleanupOrphanedRecordDatas = function() { ++cleanupOrphanCalls; - return origCleanup.apply(modelData, arguments); + return origCleanup.apply(recordData, arguments); }; } countOrphanCalls(env.store.peekRecord('person', 1)); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index ad0360946f8..82caea6d374 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -15,7 +15,7 @@ import { reset as resetModelFactoryInjection, } from 'dummy/tests/helpers/model-factory-injection'; import DS from 'ember-data'; -import { ModelData } from 'ember-data/-private'; +import { RecordData } from 'ember-data/-private'; const { attr: DSattr, hasMany: DShasMany, belongsTo: DSbelongsTo } = DS; const { hash } = RSVP; @@ -1913,7 +1913,7 @@ test("belongsTo relationship with links doesn't trigger extra change notificatio testRecordData( "belongsTo relationship doesn't trigger when model data doesn't support implicit relationship", function(assert) { - class TestModelData extends ModelData { + class TestRecordData extends RecordData { constructor(modelName, id, clientId, storeWrapper, store) { super(modelName, id, clientId, storeWrapper, store); delete this.__implicitRelationships; @@ -1922,11 +1922,11 @@ testRecordData( _destroyRelationships() {} - _allRelatedModelDatas() {} + _allRelatedRecordDatas() {} - _cleanupOrphanedModelDatas() {} + _cleanupOrphanedRecordDatas() {} - _directlyRelatedModelDatas() { + _directlyRelatedRecordDatas() { return []; } @@ -1950,12 +1950,12 @@ testRecordData( book2: DS.belongsTo('book1', { async: false, inverse: null }), // correct inverse }); - const createModelDataFor = env.store.createModelDataFor; - env.store.createModelDataFor = function(modelName, id, clientId, storeWrapper) { + const createRecordDataFor = env.store.createRecordDataFor; + env.store.createRecordDataFor = function(modelName, id, clientId, storeWrapper) { if (modelName === 'book1' || modelName === 'section') { - return new TestModelData(modelName, id, clientId, storeWrapper, this); + return new TestRecordData(modelName, id, clientId, storeWrapper, this); } - return createModelDataFor.call(this, modelName, id, clientId, storeWrapper); + return createRecordDataFor.call(this, modelName, id, clientId, storeWrapper); }; const data = { @@ -1995,7 +1995,7 @@ testRecordData( ], }; - // Expect assertion failure as Book1 ModelData + // Expect assertion failure as Book1 RecordData // doesn't have relationship attribute // and inverse is not set to null in // DSbelongsTo @@ -2038,15 +2038,15 @@ testRecordData( assert.notOk(book2.get('chapter')); assert.notOk(book.get('chapter')); assert.notOk( - book1._internalModel._modelData._implicitRelationships, + book1._internalModel._recordData._implicitRelationships, 'no support for implicit relationship in custom RecordData' ); assert.notOk( - book2._internalModel._modelData._implicitRelationships, + book2._internalModel._recordData._implicitRelationships, 'no support for implicit relationship in custom RecordData' ); assert.ok( - book._internalModel._modelData._implicitRelationships, + book._internalModel._recordData._implicitRelationships, 'support for implicit relationship in default RecordData' ); @@ -2060,10 +2060,10 @@ testRecordData( // doesn't support implicit Relationship run(() => { chapter.get('sections').removeObject(section1); - assert.notOk(section1._internalModel._modelData._implicitRelationships); + assert.notOk(section1._internalModel._recordData._implicitRelationships); chapter.get('sections').removeObject(section2); - assert.notOk(section2._internalModel._modelData._implicitRelationships); + assert.notOk(section2._internalModel._recordData._implicitRelationships); }); assert.equal(chapter.get('sections.length'), 0); @@ -2078,6 +2078,6 @@ testRecordData( sections.addObject(env.store.createRecord('section', { id: 5 })); }); assert.equal(chapter.get('sections.length'), 3); - assert.notOk(sections.get('firstObject')._internalModel._modelData._implicitRelationships); + assert.notOk(sections.get('firstObject')._internalModel._recordData._implicitRelationships); } ); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 8c8f87ba250..a1c7d38b7a1 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -987,7 +987,7 @@ test('setting a property back to its original value removes the property from th return run(() => { return store.findRecord('person', 1).then(person => { let internalModel = person._internalModel; - let dataSource = internalModel._modelData || internalModel; + let dataSource = internalModel._recordData || internalModel; assert.equal(dataSource._attributes.name, undefined, 'the `_attributes` hash is clean'); set(person, 'name', 'Niceguy Dale'); diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index dafd8e78df7..20546fc8b76 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -2309,7 +2309,7 @@ test('DS.hasMany proxy is destroyed', function(assert) { return peopleProxy.then(people => { run(() => { - let isRecordDataBuild = people.modelData !== undefined; + let isRecordDataBuild = people.recordData !== undefined; tag.unloadRecord(); // TODO Check all unloading behavior assert.equal(people.isDestroying, false, 'people is NOT destroying sync after unloadRecord'); From 8510eb90ffae5fcf88a08ea4d91aca2de34b50f4 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 24 Sep 2018 14:07:56 -0700 Subject: [PATCH 2355/2527] prettier --- .../system/relationships/state/relationship.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addon/-record-data-private/system/relationships/state/relationship.js b/addon/-record-data-private/system/relationships/state/relationship.js index 0e98d0493a2..a2b008a353c 100644 --- a/addon/-record-data-private/system/relationships/state/relationship.js +++ b/addon/-record-data-private/system/relationships/state/relationship.js @@ -429,7 +429,9 @@ export default class Relationship { this.isAsync ); } - recordData._implicitRelationships[this.inverseKeyForImplicit].addRecordData(this.recordData); + recordData._implicitRelationships[this.inverseKeyForImplicit].addRecordData( + this.recordData + ); } } } From b8a9fe2f608848a72f516c9588d2cf7a29f34f94 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 24 Sep 2018 17:55:39 -0600 Subject: [PATCH 2356/2527] [Docs] Update buildUrl syntax in docs --- addon/-private/adapters/build-url-mixin.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/adapters/build-url-mixin.js b/addon/-private/adapters/build-url-mixin.js index 4fd90fcbd1c..72b23910cce 100644 --- a/addon/-private/adapters/build-url-mixin.js +++ b/addon/-private/adapters/build-url-mixin.js @@ -259,7 +259,7 @@ export default Mixin.create({ export default DS.JSONAPIAdapter.extend({ urlForFindHasMany(id, modelName, snapshot) { - let baseUrl = this.buildURL(id, modelName); + let baseUrl = this.buildURL(modelName, id); return `${baseUrl}/relationships`; } }); @@ -286,7 +286,7 @@ export default Mixin.create({ export default DS.JSONAPIAdapter.extend({ urlForFindBelongsTo(id, modelName, snapshot) { - let baseUrl = this.buildURL(id, modelName); + let baseUrl = this.buildURL(modelName, id); return `${baseUrl}/relationships`; } }); From c085b100c8d3166a85a6afd166c3ee117b50b7e2 Mon Sep 17 00:00:00 2001 From: Cyrille David Date: Sat, 22 Sep 2018 21:06:40 +0200 Subject: [PATCH 2357/2527] [Feature] Add MU model{,-test} blueprint --- blueprints/model-test/index.js | 38 +- .../unit => __root__}/__path__/__test__.js | 0 .../unit => __root__}/__path__/__test__.js | 0 blueprints/model/index.js | 55 ++- node-tests/blueprints/model-test.js | 335 +++++++++++++----- 5 files changed, 320 insertions(+), 108 deletions(-) rename blueprints/model-test/mocha-files/{tests/unit => __root__}/__path__/__test__.js (100%) rename blueprints/model-test/qunit-files/{tests/unit => __root__}/__path__/__test__.js (100%) diff --git a/blueprints/model-test/index.js b/blueprints/model-test/index.js index d8e0f7f1092..2956ab7bb19 100644 --- a/blueprints/model-test/index.js +++ b/blueprints/model-test/index.js @@ -1,12 +1,40 @@ -var ModelBlueprint = require('../model'); -var testInfo = require('ember-cli-test-info'); -var useTestFrameworkDetector = require('../test-framework-detector'); +const ModelBlueprint = require('../model'); +const testInfo = require('ember-cli-test-info'); +const useTestFrameworkDetector = require('../test-framework-detector'); +const isModuleUnificationProject = require('../../lib/utilities/module-unification') + .isModuleUnificationProject; +const path = require('path'); module.exports = useTestFrameworkDetector({ description: 'Generates a model unit test.', - locals: function(options) { - var result = ModelBlueprint.locals.apply(this, arguments); + fileMapTokens(options) { + if (isModuleUnificationProject(this.project)) { + return { + __root__() { + return 'src'; + }, + __path__(options) { + return path.join('data', 'models', options.dasherizedModuleName); + }, + __test__() { + return 'model-test'; + }, + }; + } else { + return { + __root__() { + return 'tests'; + }, + __path__() { + return path.join('unit', 'models'); + }, + }; + } + }, + + locals(options) { + const result = ModelBlueprint.locals.apply(this, arguments); result.friendlyTestDescription = testInfo.description(options.entity.name, 'Unit', 'Model'); diff --git a/blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js b/blueprints/model-test/mocha-files/__root__/__path__/__test__.js similarity index 100% rename from blueprints/model-test/mocha-files/tests/unit/__path__/__test__.js rename to blueprints/model-test/mocha-files/__root__/__path__/__test__.js diff --git a/blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js b/blueprints/model-test/qunit-files/__root__/__path__/__test__.js similarity index 100% rename from blueprints/model-test/qunit-files/tests/unit/__path__/__test__.js rename to blueprints/model-test/qunit-files/__root__/__path__/__test__.js diff --git a/blueprints/model/index.js b/blueprints/model/index.js index 9ea731000dd..102322acdec 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -1,33 +1,52 @@ -var inflection = require('inflection'); -var stringUtils = require('ember-cli-string-utils'); -var EOL = require('os').EOL; +const inflection = require('inflection'); +const stringUtils = require('ember-cli-string-utils'); +const EOL = require('os').EOL; +const isModuleUnificationProject = require('../../lib/utilities/module-unification') + .isModuleUnificationProject; +const path = require('path'); module.exports = { description: 'Generates an ember-data model.', anonymousOptions: ['name', 'attr:type'], - locals: function(options) { - var attrs = []; - var needs = []; - var entityOptions = options.entity.options; + fileMapTokens(options) { + if (isModuleUnificationProject(this.project)) { + return { + __root__() { + return 'src'; + }, + __path__(options) { + return path.join('data', 'models', options.dasherizedModuleName); + }, + __name__() { + return 'model'; + }, + }; + } + }, + + locals(options) { + let attrs = []; + let needs = []; + let entityOptions = options.entity.options; - for (var name in entityOptions) { - var type = entityOptions[name] || ''; - var foreignModel = name; + for (let name in entityOptions) { + let type = entityOptions[name] || ''; + let foreignModel = name; if (type.indexOf(':') > -1) { foreignModel = type.split(':')[1]; type = type.split(':')[0]; } - var dasherizedName = stringUtils.dasherize(name); - var camelizedName = stringUtils.camelize(name); - var dasherizedType = stringUtils.dasherize(type); - var dasherizedForeignModel = stringUtils.dasherize(foreignModel); - var dasherizedForeignModelSingular = inflection.singularize(dasherizedForeignModel); + let dasherizedName = stringUtils.dasherize(name); + let camelizedName = stringUtils.camelize(name); + let dasherizedType = stringUtils.dasherize(type); + let dasherizedForeignModel = stringUtils.dasherize(foreignModel); + let dasherizedForeignModelSingular = inflection.singularize(dasherizedForeignModel); - var attr; + let attr; if (/has-many/.test(dasherizedType)) { - var camelizedNamePlural = inflection.pluralize(camelizedName); + let camelizedNamePlural = inflection.pluralize(camelizedName); attr = dsAttr(dasherizedForeignModelSingular, dasherizedType); attrs.push(camelizedNamePlural + ': ' + attr); } else if (/belongs-to/.test(dasherizedType)) { @@ -43,7 +62,7 @@ module.exports = { } } - var needsDeduplicated = needs.filter(function(need, i) { + let needsDeduplicated = needs.filter(function(need, i) { return needs.indexOf(need) === i; }); diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index 820411b1d27..cc480a79e78 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -15,120 +15,285 @@ const fixture = require('../helpers/fixture'); describe('Acceptance: generate and destroy model blueprints', function() { setupTestHooks(this); - beforeEach(function() { - return emberNew(); - }); + describe('classic', function() { + beforeEach(function() { + return emberNew(); + }); - it('model', function() { - let args = ['model', 'foo']; + it('model', function() { + let args = ['model', 'foo']; - return emberGenerateDestroy(args, _file => { - expect(_file('app/models/foo.js')) - .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.Model.extend('); + return emberGenerateDestroy(args, _file => { + expect(_file('app/models/foo.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.Model.extend('); - expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/foo-default.js')); + expect(_file('tests/unit/models/foo-test.js')).to.equal( + fixture('model-test/foo-default.js') + ); + }); }); - }); - it('model with attrs', function() { - let args = [ - 'model', - 'foo', - 'misc', - 'skills:array', - 'isActive:boolean', - 'birthday:date', - 'someObject:object', - 'age:number', - 'name:string', - 'customAttr:custom-transform', - ]; - - return emberGenerateDestroy(args, _file => { - expect(_file('app/models/foo.js')) - .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.Model.extend(') - .to.contain('misc: DS.attr()') - .to.contain("skills: DS.attr('array')") - .to.contain("isActive: DS.attr('boolean')") - .to.contain("birthday: DS.attr('date')") - .to.contain("someObject: DS.attr('object')") - .to.contain("age: DS.attr('number')") - .to.contain("name: DS.attr('string')") - .to.contain("customAttr: DS.attr('custom-transform')"); - - expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/foo-default.js')); + it('model with attrs', function() { + let args = [ + 'model', + 'foo', + 'misc', + 'skills:array', + 'isActive:boolean', + 'birthday:date', + 'someObject:object', + 'age:number', + 'name:string', + 'customAttr:custom-transform', + ]; + + return emberGenerateDestroy(args, _file => { + expect(_file('app/models/foo.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.Model.extend(') + .to.contain('misc: DS.attr()') + .to.contain("skills: DS.attr('array')") + .to.contain("isActive: DS.attr('boolean')") + .to.contain("birthday: DS.attr('date')") + .to.contain("someObject: DS.attr('object')") + .to.contain("age: DS.attr('number')") + .to.contain("name: DS.attr('string')") + .to.contain("customAttr: DS.attr('custom-transform')"); + + expect(_file('tests/unit/models/foo-test.js')).to.equal( + fixture('model-test/foo-default.js') + ); + }); }); - }); - it('model with belongsTo', function() { - let args = ['model', 'comment', 'post:belongs-to', 'author:belongs-to:user']; + it('model with belongsTo', function() { + let args = ['model', 'comment', 'post:belongs-to', 'author:belongs-to:user']; - return emberGenerateDestroy(args, _file => { - expect(_file('app/models/comment.js')) - .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.Model.extend(') - .to.contain("post: DS.belongsTo('post')") - .to.contain("author: DS.belongsTo('user')"); + return emberGenerateDestroy(args, _file => { + expect(_file('app/models/comment.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.Model.extend(') + .to.contain("post: DS.belongsTo('post')") + .to.contain("author: DS.belongsTo('user')"); - expect(_file('tests/unit/models/comment-test.js')).to.equal( - fixture('model-test/comment-default.js') - ); + expect(_file('tests/unit/models/comment-test.js')).to.equal( + fixture('model-test/comment-default.js') + ); + }); }); - }); - it('model with hasMany', function() { - let args = ['model', 'post', 'comments:has-many', 'otherComments:has-many:comment']; + it('model with hasMany', function() { + let args = ['model', 'post', 'comments:has-many', 'otherComments:has-many:comment']; - return emberGenerateDestroy(args, _file => { - expect(_file('app/models/post.js')) - .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.Model.extend(') - .to.contain("comments: DS.hasMany('comment')") - .to.contain("otherComments: DS.hasMany('comment')"); + return emberGenerateDestroy(args, _file => { + expect(_file('app/models/post.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.Model.extend(') + .to.contain("comments: DS.hasMany('comment')") + .to.contain("otherComments: DS.hasMany('comment')"); - expect(_file('tests/unit/models/post-test.js')).to.equal( - fixture('model-test/post-default.js') - ); + expect(_file('tests/unit/models/post-test.js')).to.equal( + fixture('model-test/post-default.js') + ); + }); }); - }); - it('model-test', function() { - let args = ['model-test', 'foo']; + it('model-test', function() { + let args = ['model-test', 'foo']; - return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/foo-default.js')); + return emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/models/foo-test.js')).to.equal( + fixture('model-test/foo-default.js') + ); + }); }); - }); - describe('model-test with ember-cli-qunit@4.2.0', function() { - beforeEach(function() { - generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + describe('model-test with ember-cli-qunit@4.2.0', function() { + beforeEach(function() { + generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + }); + + it('model-test-test foo', function() { + return emberGenerateDestroy(['model-test', 'foo'], _file => { + expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/rfc232.js')); + }); + }); }); - it('model-test-test foo', function() { - return emberGenerateDestroy(['model-test', 'foo'], _file => { - expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/rfc232.js')); + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('model-test for mocha v0.12+', function() { + let args = ['model-test', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/models/foo-test.js')).to.equal( + fixture('model-test/foo-mocha-0.12.js') + ); + }); }); }); }); - describe('with ember-cli-mocha v0.12+', function() { + describe('module unification', function() { beforeEach(function() { - modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-cli-mocha', dev: true }, - ]); - generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + return emberNew({ isModuleUnification: true }); + }); + + it('model', function() { + let args = ['model', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/model.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.Model.extend('); + + expect(_file('src/data/models/foo/model-test.js')).to.equal( + fixture('model-test/foo-default.js') + ); + }, + { isModuleUnification: true } + ); + }); + + it('model with attrs', function() { + let args = [ + 'model', + 'foo', + 'misc', + 'skills:array', + 'isActive:boolean', + 'birthday:date', + 'someObject:object', + 'age:number', + 'name:string', + 'customAttr:custom-transform', + ]; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/model.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.Model.extend(') + .to.contain('misc: DS.attr()') + .to.contain("skills: DS.attr('array')") + .to.contain("isActive: DS.attr('boolean')") + .to.contain("birthday: DS.attr('date')") + .to.contain("someObject: DS.attr('object')") + .to.contain("age: DS.attr('number')") + .to.contain("name: DS.attr('string')") + .to.contain("customAttr: DS.attr('custom-transform')"); + + expect(_file('src/data/models/foo/model-test.js')).to.equal( + fixture('model-test/foo-default.js') + ); + }, + { isModuleUnification: true } + ); + }); + + it('model with belongsTo', function() { + let args = ['model', 'comment', 'post:belongs-to', 'author:belongs-to:user']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/comment/model.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.Model.extend(') + .to.contain("post: DS.belongsTo('post')") + .to.contain("author: DS.belongsTo('user')"); + + expect(_file('src/data/models/comment/model-test.js')).to.equal( + fixture('model-test/comment-default.js') + ); + }, + { isModuleUnification: true } + ); + }); + + it('model with hasMany', function() { + let args = ['model', 'post', 'comments:has-many', 'otherComments:has-many:comment']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/post/model.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default DS.Model.extend(') + .to.contain("comments: DS.hasMany('comment')") + .to.contain("otherComments: DS.hasMany('comment')"); + + expect(_file('src/data/models/post/model-test.js')).to.equal( + fixture('model-test/post-default.js') + ); + }, + { isModuleUnification: true } + ); }); - it('model-test for mocha v0.12+', function() { + it('model-test', function() { let args = ['model-test', 'foo']; - return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/models/foo-test.js')).to.equal( - fixture('model-test/foo-mocha-0.12.js') + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/model-test.js')).to.equal( + fixture('model-test/foo-default.js') + ); + }, + { isModuleUnification: true } + ); + }); + + describe('model-test with ember-cli-qunit@4.2.0', function() { + beforeEach(function() { + generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + }); + + it('model-test-test foo', function() { + return emberGenerateDestroy( + ['model-test', 'foo'], + _file => { + expect(_file('src/data/models/foo/model-test.js')).to.equal( + fixture('model-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); + + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('model-test for mocha v0.12+', function() { + let args = ['model-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/model-test.js')).to.equal( + fixture('model-test/foo-mocha-0.12.js') + ); + }, + { isModuleUnification: true } ); }); }); From 25dade7130d71c89747f6d1d9467fecf43cbf9fe Mon Sep 17 00:00:00 2001 From: Brian Runnells Date: Thu, 27 Sep 2018 09:50:49 -0500 Subject: [PATCH 2358/2527] add mocha rfc232 blueprint detector --- blueprints/test-framework-detector.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/blueprints/test-framework-detector.js b/blueprints/test-framework-detector.js index 2fa3da77255..549a96cdc47 100644 --- a/blueprints/test-framework-detector.js +++ b/blueprints/test-framework-detector.js @@ -25,6 +25,16 @@ module.exports = function(blueprint) { } else { type = 'qunit'; } + } else if ('ember-mocha' in dependencies) { + let checker = new VersionChecker(this.project); + if ( + fs.existsSync(this.path + '/mocha-rfc-232-files') && + checker.for('ember-mocha', 'npm').gte('0.14.0') + ) { + type = 'mocha-rfc-232'; + } else { + type = 'mocha'; + } } else if ('ember-cli-mocha' in dependencies) { type = 'mocha'; } else { From 68f26e562879a8cbc1e3d0d248944fff3bf93b5e Mon Sep 17 00:00:00 2001 From: Brian Runnells Date: Thu, 27 Sep 2018 09:51:04 -0500 Subject: [PATCH 2359/2527] add mocha rfc232 adapter tests --- .../__root__/__path__/__test__.js | 13 +++++++++++++ node-tests/blueprints/adapter-test.js | 18 ++++++++++++++++++ .../fixtures/adapter-test/mocha-rfc232.js | 13 +++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 blueprints/adapter-test/mocha-rfc-232-files/__root__/__path__/__test__.js create mode 100644 node-tests/fixtures/adapter-test/mocha-rfc232.js diff --git a/blueprints/adapter-test/mocha-rfc-232-files/__root__/__path__/__test__.js b/blueprints/adapter-test/mocha-rfc-232-files/__root__/__path__/__test__.js new file mode 100644 index 00000000000..ac8efb6274d --- /dev/null +++ b/blueprints/adapter-test/mocha-rfc-232-files/__root__/__path__/__test__.js @@ -0,0 +1,13 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupTest } from 'ember-mocha'; + +describe('<%= friendlyTestDescription %>', function() { + setupTest(); + + // Replace this with your real tests. + it('exists', function() { + let adapter = this.owner.lookup('adapter:<%= dasherizedModuleName %>'); + expect(adapter).to.be.ok; + }); +}); diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 03c03eed6eb..4c7ebc16fe1 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -133,6 +133,24 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { }); }); }); + + describe.only('with ember-mocha v0.14+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-mocha', '0.14.0'); + }); + + it('adapter-test for mocha v0.14+', function() { + return emberGenerateDestroy(['adapter-test', 'foo'], _file => { + expect(_file('tests/unit/adapters/foo-test.js')).to.equal( + fixture('adapter-test/mocha-rfc232.js') + ); + }); + }); + }); }); describe('module unification', function() { diff --git a/node-tests/fixtures/adapter-test/mocha-rfc232.js b/node-tests/fixtures/adapter-test/mocha-rfc232.js new file mode 100644 index 00000000000..823755276b3 --- /dev/null +++ b/node-tests/fixtures/adapter-test/mocha-rfc232.js @@ -0,0 +1,13 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupTest } from 'ember-mocha'; + +describe('Unit | Adapter | foo', function() { + setupTest(); + + // Replace this with your real tests. + it('exists', function() { + let adapter = this.owner.lookup('adapter:foo'); + expect(adapter).to.be.ok; + }); +}); From 11ae9f382f43b80864b342a7418afb2ed4b0a5b7 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 19 Sep 2018 16:20:11 -0700 Subject: [PATCH 2360/2527] [CHORE] update contribution guidelines - cleanup PR label guide - add issue/PR templates - describe the RFC process - improve language of the CONTRIBUTOR guidelines --- .github/ISSUE_TEMPLATE/bug.md | 38 +++ .../first-time-contributor.md | 3 + .npmignore | 1 + CODE_OF_CONDUCT.md | 12 +- CONTRIBUTING.md | 320 ++++++++---------- notes/.gitkeep | 0 6 files changed, 184 insertions(+), 190 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug.md create mode 100644 .github/PULL_REQUEST_TEMPLATE/first-time-contributor.md create mode 100644 notes/.gitkeep diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md new file mode 100644 index 00000000000..4cc61ebc863 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -0,0 +1,38 @@ +# Thank you for opening this issue! + +Hopefully, this issue template will help you provide us with enough information to assist in resolving the issue. + +If you haven't already browsed recent issues (or less recent issues if this is for a past release), please do + so first to see if your issue already has a ticket created for it. It is usually best to first ask about the + issue you are observing in the `#ember-data` channel on [Discord](https://discord.gg/zT3asNS), doing so may + help you discover existing issues or provide a clearer reproduction. + +### Reproduction + +Please provide one of the following: + +- a PR linking to this issue with a failing test showing the issue +- a [Twiddle](https://ember-twiddle.com/) with a simplified reproduction and instructions for how to + observe the unexpected result. +- a github repository with a simplified reproduction and instructions for how to observe the unexpected result + +### Description + +Describe the issue in a few sentences, include both the *expected* result and the observed *unexpected* result. +If a previous version of `ember-data` worked as `expected`, which was the most recent version that worked? + +### Versions + +Run the following command and paste the output below: `npm ls ember-source && npm ls ember-cli && npm ls ember-data`. + +```cli +[Replace this line with the output] +``` + +*P.S. If any of the packages show more than one installed version, that may be the root cause of the issue!* + +-------------------------------------------------------------- + +Thanks again! + +The `ember-data` Team <3 diff --git a/.github/PULL_REQUEST_TEMPLATE/first-time-contributor.md b/.github/PULL_REQUEST_TEMPLATE/first-time-contributor.md new file mode 100644 index 00000000000..39271b7c656 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/first-time-contributor.md @@ -0,0 +1,3 @@ +// ... please delete this default text after reading + +If this is your first PR to `ember-data`, you may want to read our [Contributor Guide](https://github.com/emberjs/data/blob/master/CONTRIBUTING.md). diff --git a/.npmignore b/.npmignore index 364e1202de9..a032d9a0a41 100644 --- a/.npmignore +++ b/.npmignore @@ -6,6 +6,7 @@ /bin /docs /.node_modules.ember-try +/notes # Ignore all assets except /dist/docs folder /dist/assets/ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index aa49557b09f..e40f0abf1d9 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,9 +1,7 @@ -The Ember team and community are committed to everyone having a safe and inclusive experience. +# Code Of Conduct -**Our Community Guidelines / Code of Conduct can be found here**: +The `ember-data` core team and and the broader `Ember` community are committed to everyone + having a safe and inclusive experience. -https://emberjs.com/guidelines/ - -For a history of updates, see the page history here: - -https://github.com/emberjs/website/commits/master/source/guidelines.html.erb +- Our **Community Guidelines / Code of Conduct** can be found at [emberjs.com/guidelines](https://emberjs.com/guidelines/) +- A history of updates to this page is located at [https://github.com/emberjs/website/commits/master/source/guidelines.html.erb](https://github.com/emberjs/website/commits/master/source/guidelines.html.erb) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4ab0a43ae93..63e1282a981 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,238 +1,192 @@ -# Questions +# Contributing -This is the issue tracker for Ember Data. The Ember.js community uses this site -to collect and track bugs and discussions of new features. If you are having -difficulties using Ember Data or have a question about usage please ask a -question on StackOverflow: -[http://stackoverflow.com/questions/ask](http://stackoverflow.com/questions/ask?tags=ember.js&tags=ember-data) -and tag your question with `ember.js` and `ember-data`. +## Welcome! -The Ember.js community is very active on StackOverflow and most questions -receive attention the same day they're posted: -http://stackoverflow.com/questions/tagged/ember.js -http://stackoverflow.com/questions/tagged/ember-data +We are so glad you are considering contributing to `ember-data`. Below you'll find sections +detailing how to become involved to best ensure your contributions are successful! -# Issues +### Reporting Bugs -Think you've found a bug or have a new feature to suggest? Let us know! +Report issues you've discovered via the [issue tracker](https://github.com/emberjs/data/issues). +We have provided an [issue template](./.github/ISSUE_TEMPLATE/bug.md) what will help guide you through the process. +If you are unsure if something is a bug, the `#ember-data` channel on [Discord](https://discord.gg/zT3asNS) is +a great place to ask for help! -## Reporting a Bug -1. Update to the most recent master release if possible. We may have already -fixed your bug. +### Discussion -2. Search for similar issues. It's possible somebody has encountered -this bug already. +Before embarking on a fix, a new feature, or a refactor it is usually best to discuss the +intended work with other contributors. In addition to holding discussions on individual [issues](https://github.com/emberjs/data/issues) +or [RFCs](https://github.com/emberjs/rfcs/labels/T-ember-data), you will find most contributors +and [core team members](https://emberjs.com/team/) hangout in the `#dev-ember-data` channel on [Discord](https://discord.gg/zT3asNS) -3. Provide JSFiddle or JSBin demo that specifically shows the problem. This -demo should be fully operational with the exception of the bug you want to -demonstrate. The more pared down, the better. A preconfigured [EmberTwiddle (RESTAdapter)][rest] | [EmberTwiddle (JSONAPIAdapter)][json-api] | -[EmberTwiddle][2] with mocked requests is available. +### Weekly Meeting (video conference) +Members of the `ember-data` core team meet weekly to discuss pull-requests, issues, and road-map items. These +meetings are open to all contributors and interested parties, but only team members may vote when a vote +is necessary. -[rest]: https://ember-twiddle.com/abbc9e9e9165e5ae05804f165fa5388c/copy -[json-api]: https://ember-twiddle.com/aa59b876f393e4d1573f7cad911ec5ad/copy -[2]: https://ember-twiddle.com/0e1a24aabb8fa7c1fdd8/copy?fileTreeShown=false&numColumns=2&openFiles=routes.application.js%2Ctemplates.application.hbs +Currently meetings are Wednesdays at 2pm Pacific Time. A video conference link is posted in the +`#dev-ember-data` channel on [Discord](https://discord.gg/zT3asNS) a few minutes prior to each meeting. -4. If possible, submit a Pull Request with a failing test. Better yet, take -a stab at fixing the bug yourself if you can! +### Requesting Features or Deprecations -The more information you provide, the easier it is for us to validate that -there is a bug and the faster we'll be able to take action. +`ember-data` participates in the [RFC process (GitHub emberjs/rfcs)](https://github.com/emberjs/rfcs/). +Most changes to the public API including new features, changes in behavior, or deprecations require +community discussion and must go through this process. -## Requesting a Feature -1. Ember and Ember Data have an RFC process for feature requests. To begin the discussion either -[gather feedback](https://github.com/emberjs/rfcs/blob/master/README.md#gathering-feedback-before-submitting) -on the emberjs/rfcs repository. Or, draft an [Ember Data RFC](https://github.com/emberjs/rfcs/pulls?q=is%3Apr+is%3Aopen+label%3Aember-data) - - Use RFC pull request for well formed ideas. - - Use the `ember-data` label on it. - - Use RFC issues to propose a rough idea, basically a great place to test - the waters. +While there is no guarantee that an RFC will be accepted, successful RFCs typically follow a pattern +of iteration while gathering requirements, addressing feedback, and consensus building. The best RFCs +are narrowly scoped with clear understanding of alternatives, drawbacks, and their effect on the community. -2. Provide a clear and detailed explanation of the feature you want and why -it's important to add. Keep in mind that we want features that will be useful -to the majority of our users and not just a small subset. If you're just -targeting a minority of users, consider writing an add-on library for Ember. + Here are a few suggestions of **steps to take before drafting your RFC** to best make your RFC successful. + Often this process will complete quickly, but when it does not, don't despair! Often the best ideas + take the longest to bake. -3. If the feature is complex, consider writing an Ember RFC document. If we do -end up accepting the feature, the RFC provides the needed documentation for -contributors to develop the feature according the specification accepted by the core team. +1. Bring up your idea in the `#dev-ember-data` channel on [Discord](https://discord.gg/zT3asNS) or + with individual [team members](https://emberjs.com/team/) +2. Reflect on any concerns, alternatives, or questions that arise from these discussions. +3. Continue to discuss the idea, giving time for everyone to digest and think about it. +4. Attend the weekly team meeting to discuss your idea +5. Open an [RFC issue](https://github.com/emberjs/rfcs/issues?q=is%3Aissue+is%3Aopen+label%3AT-ember-data) + to broaden and record the discussion if the idea needs more time for discussion and iteration. + * label your issue with `T-ember-data` (or ask someone in `#dev-ember-data` to add the label if you lack the permission) + * announce your issue in `#dev-ember-data` and anywhere else desired such as `#news-and-announcements` and `twitter`. +6. [Draft an RFC](https://github.com/emberjs/rfcs#what-the-process-is) and share it with those you have + been discussing the ideas with. +7. Publish your RFC by opening a PR to [emberjs/rfcs/](https://github.com/emberjs/rfcs/pulls?q=is%3Apr+is%3Aopen+label%3AT-ember-data) + * label your PR with `T-ember-data` (or ask someone in `#dev-ember-data` to add the label if you lack the permission) + * announce your PR in `#dev-ember-data` and anywhere else desired such as `#news-and-announcements` and `twitter`. +8. Attend weekly team meetings to discuss the RFC, continue iterating on the RFC, and help shepherd it to completion. +9. Build a proof-of-concept. Sometimes this is best if it occurs alongside drafting the RFC, as it often informs + the RFC design, known drawbacks, and alternatives. Often it will become incorporated in the final implementation. +10. If you are able, help land the work in a release! It is not required that you implement your own RFC but often + this is the best way to ensure that accepted RFCs are implemented in a timely manner. -4. After discussing the feature you may choose to attempt a Pull Request. If -you're at all able, start writing some code. We always have more work to do -than time to do it. If you can write some code then that will speed the process -along. +### Submitting Work -In short, if you have an idea that would be nice to have, create an issue on the -emberjs/rfcs repo and label it as `ember-data`. If you have a question about -requesting a feature, start a discussion at [discuss.emberjs.com](http://discuss.emberjs.com) +Before implementing a feature or a fix, it is usually best to discuss the proposed changes with +[team members](https://emberjs.com/team/). Some fixes might require new public API or changes to +existing public APIs. If this is the case, it is even more important to discuss the issue's problem +space and the proposed changes before diving too deep into the implementation. -## Using Feature Flags +* Submissions should be made as PRs against the `master` branch. -Feature flags allow new features to be tested easily and strips them out of -production builds automatically. +#### Writing Tests -1. Add your new feature flag to the [config/features.json](https://github.com/emberjs/data/blob/master/config/features.json) file. - - ```js - { - "ds-boolean-transform-allow-null": null, - "ds-mynew-feature": null - } - ``` - - Give it a default of `null` so it will not be used in production builds. - -2. Import `isEnabled` from `ember-data/-private`, wrapping any new - code with your feature: - - ```js - import { isEnabled } from 'ember-data/-private'; +All PRs should have accompanying tests. For bug-fixes, this should include tests that demonstrate + the issue being fixed and test that the solution works. - if (isEnabled('ds-mynew-feature')) { - // ... any additional code - } else { - // ... any previous code that may have been overwritten - } - ``` - -3. Similarly, you will want to wrap any new or edited tests with the same - feature flag. +* We do write tests for our warns and assertion messages, using the `assert.expectAssertion()` and `assert.expectWarning()` helpers. +* Because Travis runs tests in the `production` environment, assertions and warnings are stripped out. To avoid tests on + warning/assertion messages failing for your PR, use the `testInDebug` function instead of `qunit` `test` to skip them in production. +* Include tests that fail without your code, and pass with it +* Update the documentation, examples, and guides when affected by your contribution - ```js - import { isEnabled } from 'ember-data/-private'; +#### Running Tests - if (isEnabled('ds-mynew-feature')) { - test('test for new feature', function(assert) { - // ... - }) - } - ``` +* PRs will automatically run an extensive set of test scenarios for your work +* `ember-data` is an `ember-addon` and uses `ember-cli`. To run tests locally + use `ember test` or `ember test --serve`. For additional test commands see the list + of commands in [./package.json](./package.json) - This will allow the test suite to run as normal. +#### Commit Tagging -4. Running tests with all feature flags enabled is possible via - `ember test --environment=test-optional-features` This is also possible while - running tests in the browser via the `Enable Opt Feature` checkbox. +All commits should be tagged. Tags are denoted by square brackets (`[]`) and come at the start of the commit message. -5. Add your feature to the [Features](https://github.com/emberjs/data/blob/master/FEATURES.md) file. - Be sure to leave a description of the feature and possible example of how to - use it (if necessary). +* `[CLEANUP]`: commits that remove deprecated functionality +* `[CHORE]`: commits that refactor code or update dependencies +* `[TEST ]`: commits that add tests for a feature +* `[FEAT ]`: commits that add features +* `[DOC ]` | `[DOC]`: commits that add or fix documentation for a feature +* `[SECURITY ]`: commits that address security vulnerabilities. Please do not submit security related PRs without + coordinating with the security team. See the [Security Policy](https://emberjs.com/security/) for more information. +* `[BUGFIX ]`: commits that fix an issue. The PR should also specify the github issue # of the + issue being resolved. -## Benchmarking +In general almost all commits should fall into one of the above categories. In the cases where they don't please submit +your PR untagged. -Ember Data is instrumented with [heimdalljs](https://github.com/heimdalljs/heimdalljs-lib) - Top level scenarios for benchmarking are available via the `query` route in - the dummy app, and desired scenarios to be run can be configured via `benchmarks/config.js`. +#### Developing a New Feature with Feature Flags - The scenarios are configured to interop with [heimdall-query](https://github.com/heimdalljs/heimdall-query) - for analysis. To run scenarios: +Sometimes a new feature will require use of a feature flag. - 1. Start the dummy app with instrumentation on: `ember s --instrument` +Feature flags allow new features to be tested in dev builds, but +the features are stripped out of production builds automatically. - 2. Configure `benchmarks/config.js` with desired scenarios +1. Add your new feature flag to the [config/features.json](https://github.com/emberjs/data/blob/master/config/features.json) file. - 3. To run both the benchmarks and the analysis: `node ./benchmarks` +```js +{ + "ds-boolean-transform-allow-null": null, + "ds-mynew-feature": null +} +``` - a.) To just collect data (no analysis): `node ./benchmarks/bash-run.js` - b.) To just run analysis (w/cached data): `node ./benchmarks/bash-analyze.js` - c.) To cache a data set or use a cached data set, all commands accept `-c ./path/to/cache/dir` +Give it a default of `null` so it will not be used in production builds. - 4. Do not commit cached data results, these should be git ignored already. +2. Import `isEnabled` from `ember-data/-private`, wrapping any new + code with your feature: -# Pull Requests +```js +import { isEnabled } from 'ember-data/-private'; -We love pull requests. Here's a quick guide: +if (isEnabled('ds-mynew-feature')) { + // ... any additional code +} else { + // ... any previous code that may have been overwritten +} +``` -1. Fork the repo. +3. Similarly, you will want to wrap any new or edited tests with the same + feature flag. -2. Run the tests. We only take pull requests with passing tests, and it's great -to know that you have a clean slate, see notes on how to run unit tests [here](https://github.com/emberjs/data#how-to-run-unit-tests). (To see tests in the browser, -run `npm start` and open `http://localhost:4200/tests`.) +```js +import { isEnabled } from 'ember-data/-private'; -3. Add a test for your change. Only refactoring and documentation changes -require no new tests. If you are adding functionality or fixing a bug, we need -a test! +if (isEnabled('ds-mynew-feature')) { + test('test for new feature', function(assert) { + // ... + }); +} +``` -4. Make the test pass. +This will ensure these feature tests are only run when then feature is included in the build for `ember-data`. -5. Commit your changes. Please use an appropriate commit prefix. -If your pull request fixes an issue specify it in the commit message. Some examples: +4. Running tests with all feature flags enabled is possible via + `ember test --environment=test-optional-features` This is also possible while + running tests in the browser via the `Enable Opt Feature` checkbox. - ``` - [DOC beta] Update CONTRIBUTING.md for commit prefixes - [FEATURE ds-pushpayload-return] Change `pushPayload` to return a value. #4110 - [BUGFIX beta] Allow optional spaces when parsing response headers - ``` +5. Add your feature to the [Features](https://github.com/emberjs/data/blob/master/FEATURES.md) file. + Be sure to leave a description of the feature and possible example of how to + use it (if necessary). - For more information about commit prefixes see [Commit Tagging](#commit-tagging). +For more information about commit prefixes see [Commit Tagging](#commit-tagging). 6. Push to your fork and submit a pull request. Please provide us with some -explanation of why you made the changes you made. For new features make sure to -explain a standard use case to us. - -We try to be quick about responding to tickets but sometimes we get a bit -backlogged. If the response is slow, try to find someone on IRC (#emberjs) to -give the ticket a review. + explanation of why you made the changes you made. For new features make sure to + explain a standard use case to us. -Some things that will increase the chance that your pull request is accepted, -taken straight from the Ruby on Rails guide: - -* Use Ember idioms and helpers -* Include tests that fail without your code, and pass with it -* Update the documentation, the surrounding one, examples elsewhere, guides, - whatever is affected by your contribution - -## Syntax: - -* Two spaces, no tabs. -* No trailing whitespace. Blank lines should not have any space. -* a = b and not a=b. -* Follow the conventions you see used in the source already. - -And in case we didn't emphasize it enough: we love tests! - - -## Writing Tests - -* We do write tests for our warns and assertion messages, using the `assert.expectAssertion()` and `assert.expectWarning()` helpers. -* Because Travis runs tests in the `production` environment, assertions and warnings are stripped out. To avoid tests on warning/assertion messages failing for your PR, use the `testInDebug` helper to skip them in production. See [this](https://github.com/emberjs/data/blob/b3eb9c098ef8c2cf9ff3378ed079769782c02bb5/tests/integration/adapter/queries-test.js#L32) example. - -## Commit Tagging - -All commits should be tagged. Tags are denoted by square brackets (`[]`) and come at the start of the commit message. - -### Bug Fixes - -In general bug fixes are pulled into the beta branch. As such, the prefix is: `[BUGFIX beta]`. If a bug fix is a serious regression that requires a new patch release, `[BUGFIX release]` can be used instead. - -For bugs related to canary features, follow the prefixing rules for features. - -The vast majority of bug fixes apply to the current stable or beta releases, so submit your PR against the `master` branch with one of the above mentioned BUGFIX tags. -(In the unusual case of a bug fix specifically for a past release, tag for that release `[BUGFIX release-1-13]` and submit the PR against the stable branch for that release: `stable-1-13`.) - -### Cleanup - -Cleanup commits are for removing deprecated functionality and should be tagged -as `[CLEANUP beta]`. - -### Features +## Benchmarking -All additions and fixes for features in canary should be tagged as `[FEATURE name]` where name is the same as the flag for that feature. +Ember Data is instrumented with [heimdalljs](https://github.com/heimdalljs/heimdalljs-lib) +Top level scenarios for benchmarking are available via the `query` route in +the dummy app, and desired scenarios to be run can be configured via `benchmarks/config.js`. -### Documentation +The scenarios are configured to interop with [heimdall-query](https://github.com/heimdalljs/heimdall-query) +for analysis. To run scenarios: -Documentation commits are tagged as `[DOC channel]` where channel is `canary`, -`beta`, or `release`. If no release is provided `canary` is assumed. The channel should be the most stable release that this documentation change applies to. +1. Start the dummy app with instrumentation on: `ember s --instrument` -### Security +2. Configure `benchmarks/config.js` with desired scenarios -Security commits will be tagged as `[SECURITY cve]`. Please do not submit security related PRs without coordinating with the security team. See the [Security Policy](https://emberjs.com/security/) for more information. +3. To run both the benchmarks and the analysis: `node ./benchmarks` -### Other + a.) To just collect data (no analysis): `node ./benchmarks/bash-run.js` + b.) To just run analysis (w/cached data): `node ./benchmarks/bash-analyze.js` + c.) To cache a data set or use a cached data set, all commands accept `-c ./path/to/cache/dir` -In general almost all commits should fall into one of these categories. In the cases where they don't please submit your PR untagged. An ember-data contributor will let you know if tagging is required. +4. Do not commit cached data results, these should be git ignored already. +## Notes -NOTE: -* Partially copied from https://raw.github.com/thoughtbot/factory_girl_rails/master/CONTRIBUTING.md * Commit tagging section taken from [ember.js](https://github.com/emberjs/ember.js/blob/5641c3089180bdd1d4fa54e9dd2d3ac285f088e4/CONTRIBUTING.md#commit-tagging) diff --git a/notes/.gitkeep b/notes/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d From 925638953c9af9e75aa04a3b75203764e13b6ad5 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Mon, 1 Oct 2018 11:45:40 -0400 Subject: [PATCH 2361/2527] Refactor argument parsing for --instrument and --record-data-rfc-build This simplifies and reorganizes the process.argv processing that needs to be done for the two flags that we support. This commit migrates the instrument flag handling to a single file (`lib/heimdall-utils.js`) and uses that single exported function throughout the rest of the code. It also removes the reliance on `process.env` string coercion (which apparently _can_ be broken when you've reassigned `process.env`). It also changes around the details of the previous `--record-data-rfc-build` flag. Instead, we add a `--disable-record-data-rfc-build` flag (because as of 3.5 beta's the record data code is enabled by default). During this refactor, the `config` hook was migrated into the dummy app itself, so that ember-data no longer adds that flag to all consuming app's runtime config. --- index.js | 45 ++----------------------------- lib/cli-flags.js | 26 ++++++++++++++++++ lib/stripped-build-plugins.js | 5 ++-- tests/dummy/config/environment.js | 5 ++++ 4 files changed, 36 insertions(+), 45 deletions(-) create mode 100644 lib/cli-flags.js diff --git a/index.js b/index.js index 42a68129a3e..28139e2aa48 100644 --- a/index.js +++ b/index.js @@ -5,30 +5,10 @@ const Funnel = require('broccoli-funnel'); const Rollup = require('broccoli-rollup'); const merge = require('broccoli-merge-trees'); const version = require('./lib/version'); +const { isInstrumentedBuild, useRecordData } = require('./lib/cli-flags'); const BroccoliDebug = require('broccoli-debug'); const calculateCacheKeyForTree = require('calculate-cache-key-for-tree'); -// allow toggling of heimdall instrumentation -let INSTRUMENT_HEIMDALL = false; -let USE_RECORD_DATA_RFC = false; -let args = process.argv; - -for (let i = 1; i < args.length; i++) { - if (args[i] === '--instrument') { - INSTRUMENT_HEIMDALL = true; - if (USE_RECORD_DATA_RFC) { - break; - } - } else if (args[i] === '--record-data-rfc-build') { - USE_RECORD_DATA_RFC = true; - if (INSTRUMENT_HEIMDALL) { - break; - } - } -} - -process.env.INSTRUMENT_HEIMDALL = INSTRUMENT_HEIMDALL; - function isProductionEnv() { let isProd = /production/.test(process.env.EMBER_ENV); let isTest = process.env.EMBER_CLI_TEST_COMMAND; @@ -36,10 +16,6 @@ function isProductionEnv() { return isProd && !isTest; } -function isInstrumentedBuild() { - return INSTRUMENT_HEIMDALL; -} - module.exports = { name: 'ember-data', @@ -83,22 +59,6 @@ module.exports = { this.options = this.options || {}; }, - config() { - let optionFlag = - this.app && - this.app.options && - this.app.options.emberData && - this.app.options.emberData.enableRecordDataRFCBuild; - let isEmberDataItself = this.isDevelopingAddon(); - let useLegacyBuild = isEmberDataItself && (USE_RECORD_DATA_RFC || optionFlag === false); - - return { - emberData: { - enableRecordDataRFCBuild: !useLegacyBuild || true, - }, - }; - }, - blueprintsPath() { return path.join(__dirname, 'blueprints'); }, @@ -107,7 +67,6 @@ module.exports = { tree = this.debugTree(tree, 'input'); let babel = this.addons.find(addon => addon.name === 'ember-cli-babel'); - let config = this.config(); let treeWithVersion = merge([ tree, @@ -119,7 +78,7 @@ module.exports = { }); let withPrivate; - if (config.emberData.enableRecordDataRFCBuild) { + if (useRecordData()) { withPrivate = new Funnel(tree, { srcDir: '-record-data-private', destDir: '-private', diff --git a/lib/cli-flags.js b/lib/cli-flags.js new file mode 100644 index 00000000000..71324ca4514 --- /dev/null +++ b/lib/cli-flags.js @@ -0,0 +1,26 @@ +'use strict'; + +function isInstrumentedBuild() { + return process.argv.includes('--instrument'); +} + +function useRecordData() { + try { + let currentProjectName = require(`${process.cwd()}/package`); + if ( + currentProjectName === 'ember-data' && + process.argv.includes('--disable-record-data-rfc-build') + ) { + return false; + } + } catch (e) { + // swallow any errors for missing package.json in CWD. + } + + return true; +} + +module.exports = { + isInstrumentedBuild, + useRecordData, +}; diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 65624ac08a0..99d0e1c223a 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -8,6 +8,7 @@ const StripHeimdall = requireBabelPlugin('babel6-plugin-strip-heimdall'); const StripClassCallCheck = requireBabelPlugin('babel6-plugin-strip-class-callcheck'); const StripFilteredImports = requireBabelPlugin('./transforms/babel-plugin-remove-imports'); const TransformBlockScoping = requireBabelPlugin('babel-plugin-transform-es2015-block-scoping'); +const { isInstrumentedBuild } = require('./cli-flags'); function uniqueAdd(obj, key, values) { const a = (obj[key] = obj[key] || []); @@ -52,7 +53,7 @@ module.exports = function(environment) { ], ]; - if (process.env.INSTRUMENT_HEIMDALL === 'false') { + if (!isInstrumentedBuild()) { plugins.push([StripHeimdall]); uniqueAdd(filteredImports, 'ember-data/-debug', ['instrument']); } else { @@ -60,7 +61,7 @@ module.exports = function(environment) { console.warn('NOT STRIPPING HEIMDALL'); } - if (/production/.test(environment) || process.env.INSTRUMENT_HEIMDALL === 'true') { + if (/production/.test(environment) || isInstrumentedBuild()) { postTransformPlugins.push([StripClassCallCheck]); uniqueAdd(filteredImports, 'ember-data/-debug', ['assertPolymorphicType']); } diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index 8f6ea148349..365fd179067 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -5,6 +5,7 @@ var path = require('path'); var featuresJsonPath = path.join(__dirname, '../../../config/features.json'); var featuresJson = fs.readFileSync(featuresJsonPath, { encoding: 'utf8' }); var featureFlags = JSON.parse(featuresJson); +let { useRecordData } = require('../../../lib/cli-flags'); module.exports = function(environment) { var ENV = { @@ -47,5 +48,9 @@ module.exports = function(environment) { ENV.APP.rootElement = '#ember-testing'; } + ENV.emberData = { + enableRecordDataRFCBuild: useRecordData(), + }; + return ENV; }; From 11e893e7042b89574446294c1687acb9fd8f29ae Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 1 Oct 2018 10:09:17 +0200 Subject: [PATCH 2362/2527] fix(blueprints): remove second string argument from transform tests fixes #5656 --- .../transform-test/qunit-files/__root__/__path__/__test__.js | 2 +- node-tests/fixtures/transform-test/default.js | 2 +- node-tests/fixtures/transform-test/rfc232.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/blueprints/transform-test/qunit-files/__root__/__path__/__test__.js b/blueprints/transform-test/qunit-files/__root__/__path__/__test__.js index e4f745717d3..bace94d06e2 100644 --- a/blueprints/transform-test/qunit-files/__root__/__path__/__test__.js +++ b/blueprints/transform-test/qunit-files/__root__/__path__/__test__.js @@ -1,7 +1,7 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -module('transform:<%= dasherizedModuleName %>', '<%= friendlyTestDescription %>', function(hooks) { +module('<%= friendlyTestDescription %>', function(hooks) { setupTest(hooks); // Replace this with your real tests. diff --git a/node-tests/fixtures/transform-test/default.js b/node-tests/fixtures/transform-test/default.js index 23d10b815cd..5d9582c8f86 100644 --- a/node-tests/fixtures/transform-test/default.js +++ b/node-tests/fixtures/transform-test/default.js @@ -1,7 +1,7 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -module('transform:foo', 'Unit | Transform | foo', function(hooks) { +module('Unit | Transform | foo', function(hooks) { setupTest(hooks); // Replace this with your real tests. diff --git a/node-tests/fixtures/transform-test/rfc232.js b/node-tests/fixtures/transform-test/rfc232.js index 23d10b815cd..5d9582c8f86 100644 --- a/node-tests/fixtures/transform-test/rfc232.js +++ b/node-tests/fixtures/transform-test/rfc232.js @@ -1,7 +1,7 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -module('transform:foo', 'Unit | Transform | foo', function(hooks) { +module('Unit | Transform | foo', function(hooks) { setupTest(hooks); // Replace this with your real tests. From b942dad216181b861ab000478e133a7c4b067cfe Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 2 Oct 2018 09:38:27 -0700 Subject: [PATCH 2363/2527] [CHORE readme] modernize our readme --- README.md | 191 +++++++----------------------------------------------- 1 file changed, 25 insertions(+), 166 deletions(-) diff --git a/README.md b/README.md index f442ebb26da..2c17b25cb40 100644 --- a/README.md +++ b/README.md @@ -1,179 +1,38 @@ -## Ember Data [![Build Status](https://secure.travis-ci.org/emberjs/data.svg?branch=master)](http://travis-ci.org/emberjs/data) [![Code Climate](https://codeclimate.com/github/emberjs/data/badges/gpa.svg)](https://codeclimate.com/github/emberjs/data) +## ember-data -Ember Data is a library for robustly managing model data in your -Ember.js applications. +[![Build Status](https://secure.travis-ci.org/emberjs/data.svg?branch=master)](http://travis-ci.org/emberjs/data) +[![Code Climate](https://codeclimate.com/github/emberjs/data/badges/gpa.svg)](https://codeclimate.com/github/emberjs/data) +[![Discord Community Server](https://img.shields.io/discord/480462759797063690.svg?logo=discord)](https://discord.gg/zT3asNS) -Ember Data is designed to be agnostic to the underlying persistence -mechanism, so it works just as well with JSON APIs over HTTP as it does -with streaming WebSockets or local IndexedDB storage. +`ember-data` is a library for robustly managing data in applications built with +[Ember.js](https://github.com/emberjs/ember.js/). -It provides many of the facilities you'd find in server-side ORMs like -ActiveRecord, but is designed specifically for the unique environment of -JavaScript in the browser. +`ember-data` is designed to be agnostic to the underlying persistence +mechanism, so it works just as well with `JSON API` over `HTTP` as it does +with streaming `WebSockets` or local `IndexedDB` storage. -In particular, Ember Data uses Promises/A+-compatible promises from the -ground up to manage loading and saving records, so integrating with -other JavaScript APIs is easy. +It provides many of the facilities you'd find in server-side `ORM`s like +`ActiveRecord`, but is designed specifically for the unique environment of +`JavaScript` in the browser. -Igor Terzic is currently the lead maintainer of Ember Data, while the rest -of the core team include Yehuda Katz, Tom Dale, Brendan McLoughlin, -Christoffer Persson and Stanley Stuart. +- [Usage Guide](https://guides.emberjs.com/release/models/) +- [API Documentation](https://emberjs.com/api/ember-data/release/modules/ember-data) +- [Contributing Guide](./CONTRIBUTING.md) +- [RFCs](https://github.com/emberjs/rfcs/labels/T-ember-data) +- [Community](https://emberjs.com/community) +- [Team](https://emberjs.com/team) +- [Blog](https://emberjs.com/blog) -## Using Ember Data +### Installation -### Getting Ember Data +`ember-data` is installed by default for new applications generated with `ember-cli`. -Since version `2.3` ember-data is a proper Ember-CLI addon which can be added -to your app via: +If you wish to add `ember-data` to an `addon` or `application`, you can do so by running +the following command, which will use `yarn` or `npm` to install `ember-data` as a `devDependency`. ```no-highlight ember install ember-data ``` -If you need to use a version of ember-data package `< 2.3`, you need to add the -npm package and add the dependency via bower: - -```no-highlight -npm install ember-data@v2.2.1 --save-dev -bower install ember-data --save -``` - -The latest passing build from the "master" branch is available on -[https://emberjs.com/builds/#/canary](https://emberjs.com/builds/#/canary). - -Similarly, the latest passing build from the "beta" branch can be found -on [https://emberjs.com/builds/#/beta](https://emberjs.com/builds/#/beta) - -Or build ember-data.js yourself. Clone the repository and run `npm run production` -after [setup](#setup). You'll find ember-data.js in the `dist` directory. - -#### Internet Explorer 8 - -**Internet Explorer 8 is no longer supported by Ember Data on versions -2.0 and later.** - -If you require IE8 support, you can use the `1.13` series of releases. -The source code is available on the `release-1-13` branch. - -Internet Explorer 8 support requires Ember 1.8.1 (which provides a polyfill for `Object.create`). - -### Instantiating the Store - -In Ember Data, the _store_ is responsible for managing the lifecycle of -your models. Every time you need a model or a collection of models, -you'll ask the store for it. - -To create a store, you don't need to do anything. Just by loading the -Ember Data library, all of the routes and controllers in your -application will get a new `store` property. This property is an -instance of `DS.Store` that will be shared across all of the routes and -controllers in your app. - -### Defining Your Models - -First things first: tell Ember Data about the models in your -application. For example, imagine we're writing a blog reader app. - -Here's what your model definition would look like if you're using -ES6 modules (via ember-cli): - -```js -// app/models/blog-post.js -import DS from 'ember-data'; - -const { attr, hasMany } = DS; - -export default DS.Model.extend({ - title: attr('string'), - createdAt: attr('date'), - - comments: hasMany('comment') -}); - -// app/models/comment.js -import DS from 'ember-data'; - -const { attr, belongsTo } = DS; - -export default DS.Model.extend({ - body: attr('string'), - username: attr('string'), - - post: belongsTo('blog-post') -}); -``` - -### A Brief Note on Adapters - -Without immediately diving in to the depths of the architecture, one -thing you _should_ know is that Ember Data uses an object called an -_adapter_ to know how to talk to your server. - -An adapter is just an object that knows how to translate requests from -Ember Data into requests on your server. For example, if I ask the Ember -Data store for a record of type `person` with an ID of `123`, the -adapter translates that into an XHR request to (for example) -`api.example.com/v3/person/123.json`. - -By default, Ember Data will use the `JSONAPIAdapter`, which adheres to the [JSON-API spec](http://jsonapi.org/). - -To learn more about adapters, including what conventions the -various adapters follow and how to build your own, see the Ember.js -Guides: [Customizing Adapters](https://guides.emberjs.com/release/models/customizing-adapters/). - -### Fetching a Collection of Models - -From your route or controller: - -```js -this.store.findAll('blog-post'); -``` - -This returns a promise that resolves to the collection of records. - -### Fetching a Single Model - -```js -this.store.findRecord('blog-post', 123); -``` - -This returns a promise that resolves to the requested record. If the -record can't be found or there was an error during the request, the -promise will be rejected. - -### Even More Documentation - -For much more detail on how to use Ember Data, see the [Ember.js Guides -on models](https://guides.emberjs.com/release/models/). - -# Building Ember Data - -1. Ensure that [Node.js](http://nodejs.org/) and [yarn](https://yarnpkg.com/en/docs/install) are installed. -2. Run `yarn install` to ensure the required dependencies are installed. -3. Run `npm run production` to build Ember Data. The builds will be placed in the `dist/` directory. - -# Contribution - -See [CONTRIBUTING.md](https://github.com/emberjs/data/blob/master/CONTRIBUTING.md) - -## How to Run Unit Tests - -### Setup - -1. Install Node.js from http://nodejs.org or your favorite package manager. - -2. Install Ember CLI. `npm install -g ember-cli` - -3. Run `yarn install` inside the project root to install the JS dependencies. - -### In Your Browser - -1. To start the development server, run `npm start`. - -2. Visit `http://localhost:4200/tests` - -### From the CLI - -1. Install phantomjs from http://phantomjs.org - -2. Run `npm test` +Similarly, if you have generated a new `Ember` application using `ember-cli` but do +not wish to use `ember-data`, remove `ember-data` from your `package.json`. From f52a12d60b3df735c39dbe6b2b9b475dfd105c77 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 2 Oct 2018 10:07:33 -0700 Subject: [PATCH 2364/2527] [FEAT github-templates] ensure our templates work as defaults --- .github/{ISSUE_TEMPLATE/bug.md => ISSUE_TEMPLATE.md} | 0 .../first-time-contributor.md => PULL_REQUEST_TEMPLATE.md} | 0 CONTRIBUTING.md | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename .github/{ISSUE_TEMPLATE/bug.md => ISSUE_TEMPLATE.md} (100%) rename .github/{PULL_REQUEST_TEMPLATE/first-time-contributor.md => PULL_REQUEST_TEMPLATE.md} (100%) diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE.md similarity index 100% rename from .github/ISSUE_TEMPLATE/bug.md rename to .github/ISSUE_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE/first-time-contributor.md b/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE/first-time-contributor.md rename to .github/PULL_REQUEST_TEMPLATE.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 63e1282a981..02013674702 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,7 @@ detailing how to become involved to best ensure your contributions are successfu ### Reporting Bugs Report issues you've discovered via the [issue tracker](https://github.com/emberjs/data/issues). -We have provided an [issue template](./.github/ISSUE_TEMPLATE/bug.md) what will help guide you through the process. +We have provided an [issue template](.github/bug.md) what will help guide you through the process. If you are unsure if something is a bug, the `#ember-data` channel on [Discord](https://discord.gg/zT3asNS) is a great place to ask for help! From 8184519134615f709e18a29ba18b0cd638a7fcde Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Tue, 2 Oct 2018 17:59:46 -0700 Subject: [PATCH 2365/2527] [bugfix beta] Add inverse relationship on payload when missing (#5608) * failing tests for missing info on relationship finders * push leftHandSide relationship info for findHasMany/belongsTo * refactor inverse relationship load tests to new test style * add more tests for deprecations and many-to-many scenarios * add more test cases for loading records through links/ids * push relationship on both sides in findHasMany/findBelongsTo --- addon/-private/system/store/finders.js | 214 +- .../inverse-relationship-load-test.js | 4895 +++++++++++++++++ 2 files changed, 5107 insertions(+), 2 deletions(-) create mode 100644 tests/integration/relationships/inverse-relationship-load-test.js diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index ffb4599e54a..7d3a7aa2419 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -1,11 +1,14 @@ import { A } from '@ember/array'; import { Promise } from 'rsvp'; -import { assert, warn } from '@ember/debug'; +import { assert, warn, deprecate } from '@ember/debug'; +import { DEBUG } from '@glimmer/env'; +import Ember from 'ember'; import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './common'; import { normalizeResponseHelper } from './serializer-response'; import { serializerForAdapter } from './serializers'; +import { merge } from '@ember/polyfills'; function payloadIsNotBlank(adapterPayload) { if (Array.isArray(adapterPayload)) { @@ -105,6 +108,209 @@ export function _findMany(adapter, store, modelName, ids, internalModels, option ); } +function iterateData(data, fn) { + if (Array.isArray(data)) { + return data.map(fn); + } else { + return fn(data); + } +} + +// sync +// iterate over records in payload.data +// for each record +// assert that record.relationships[inverse] is either undefined (so we can fix it) +// or provide a data: {id, type} that matches the record that requested it +// return the relationship data for the parent +function syncRelationshipDataFromLink(store, payload, parentInternalModel, relationship) { + // ensure the right hand side (incoming payload) points to the parent record that + // requested this relationship + let relationshipData = iterateData(payload.data, (data, index) => { + const { id, type } = data; + ensureRelationshipIsSetToParent(data, parentInternalModel, store, relationship, index); + return { id, type }; + }); + + // now, push the left hand side (the parent record) to ensure things are in sync, since + // the payload will be pushed with store._push + store.push({ + data: { + id: parentInternalModel.id, + type: parentInternalModel.modelName, + relationships: { + [relationship.key]: { + data: relationshipData, + }, + }, + }, + }); +} + +function ensureRelationshipIsSetToParent( + payload, + parentInternalModel, + store, + parentRelationship, + index +) { + let { id, type } = payload; + + if (!payload.relationships) { + payload.relationships = {}; + } + let { relationships } = payload; + + let inverse = getInverse(store, parentInternalModel, parentRelationship, type); + if (inverse) { + let { inverseKey, kind } = inverse; + + let relationshipData = relationships[inverseKey] && relationships[inverseKey].data; + + if ( + DEBUG && + typeof relationshipData !== 'undefined' && + !relationshipDataPointsToParent(relationshipData, parentInternalModel) + ) { + let quotedType = Ember.inspect(type); + let quotedInverse = Ember.inspect(inverseKey); + let expected = Ember.inspect({ + id: parentInternalModel.id, + type: parentInternalModel.modelName, + }); + let expectedModel = Ember.inspect(parentInternalModel); + let got = Ember.inspect(relationshipData); + let prefix = typeof index === 'number' ? `data[${index}]` : `data`; + let path = `${prefix}.relationships.${inverse}.data`; + let other = relationshipData ? `<${relationshipData.type}:${relationshipData.id}>` : null; + let relationshipFetched = `${Ember.inspect(parentInternalModel)}.${ + parentRelationship.kind + }("${parentRelationship.name}")`; + let includedRecord = `<${type}:${id}>`; + let message = [ + `Encountered mismatched relationship: Ember Data expected ${path} in the payload from ${relationshipFetched} to include ${expected} but got ${got} instead.\n`, + `The ${includedRecord} record loaded at ${prefix} in the payload specified ${other} as its ${quotedInverse}, but should have specified ${expectedModel} (the record the relationship is being loaded from) as its ${quotedInverse} instead.`, + `This could mean that the response for ${relationshipFetched} may have accidentally returned ${quotedType} records that aren't related to ${expectedModel} and could be related to a different ${ + parentInternalModel.modelName + } record instead.`, + `Ember Data has corrected the ${includedRecord} record's ${quotedInverse} relationship to ${expectedModel} so that ${relationshipFetched} will include ${includedRecord}.`, + `Please update the response from the server or change your serializer to either ensure that the response for only includes ${quotedType} records that specify ${expectedModel} as their ${quotedInverse}, or omit the ${quotedInverse} relationship from the response.`, + ].join('\n'); + + // this should eventually throw instead of deprecating. + deprecate(message + '\n', false, { + id: 'mismatched-inverse-relationship-data-from-payload', + until: '3.8', + }); + } + relationships[inverseKey] = relationships[inverseKey] || {}; + relationships[inverseKey].data = fixRelationshipData( + relationshipData, + kind, + parentInternalModel + ); + } +} + +function getInverse(store, parentInternalModel, parentRelationship, type) { + if (store.recordDataWrapper) { + return recordDataFindInverseRelationshipInfo( + store, + parentInternalModel, + parentRelationship, + type + ); + } else { + return legacyFindInverseRelationshipInfo(store, parentInternalModel, parentRelationship); + } +} + +function recordDataFindInverseRelationshipInfo( + { recordDataWrapper }, + parentInternalModel, + parentRelationship, + type +) { + let { name: lhs_relationshipName } = parentRelationship; + let { modelName } = parentInternalModel; + let inverseKey = recordDataWrapper.inverseForRelationship(modelName, lhs_relationshipName); + + if (inverseKey) { + let { + meta: { kind }, + } = recordDataWrapper.relationshipsDefinitionFor(type)[inverseKey]; + return { + inverseKey, + kind, + }; + } +} + +function legacyFindInverseRelationshipInfo(store, parentInternalModel, parentRelationship) { + let { name: lhs_relationshipName } = parentRelationship; + let { modelName } = parentInternalModel; + + let relationshipInfo = store._relationshipsPayloads.getRelationshipInfo( + modelName, + lhs_relationshipName + ); + let { hasInverse, rhs_relationshipName: inverseKey, rhs_relationshipMeta } = relationshipInfo; + + if (hasInverse) { + let { + meta: { kind }, + } = rhs_relationshipMeta; + return { + inverseKey, + kind, + }; + } +} + +function relationshipDataPointsToParent(relationshipData, internalModel) { + if (relationshipData === null) { + return false; + } + + if (Array.isArray(relationshipData)) { + if (relationshipData.length === 0) { + return false; + } + for (let i = 0; i < relationshipData.length; i++) { + let entry = relationshipData[i]; + if (validateRelationshipEntry(entry, internalModel)) { + return true; + } + } + } else { + return validateRelationshipEntry(relationshipData, internalModel); + } + + return false; +} + +function fixRelationshipData(relationshipData, relationshipKind, { id, modelName }) { + let parentRelationshipData = { + id, + type: modelName, + }; + + let payload; + + if (relationshipKind === 'hasMany') { + payload = relationshipData || []; + payload.push(parentRelationshipData); + } else { + payload = relationshipData || {}; + merge(payload, parentRelationshipData); + } + + return payload; +} + +function validateRelationshipEntry({ id }, { id: parentModelID }) { + return id && id.toString() === parentModelID; +} + export function _findHasMany(adapter, store, internalModel, link, relationship, options) { let snapshot = internalModel.createSnapshot(options); let modelClass = store.modelFor(relationship.type); @@ -133,8 +339,10 @@ export function _findHasMany(adapter, store, internalModel, link, relationship, null, 'findHasMany' ); - let internalModelArray = store._push(payload); + syncRelationshipDataFromLink(store, payload, internalModel, relationship); + + let internalModelArray = store._push(payload); internalModelArray.meta = payload.meta; return internalModelArray; }, @@ -170,6 +378,8 @@ export function _findBelongsTo(adapter, store, internalModel, link, relationship return null; } + syncRelationshipDataFromLink(store, payload, internalModel, relationship); + return store._push(payload); }, null, diff --git a/tests/integration/relationships/inverse-relationship-load-test.js b/tests/integration/relationships/inverse-relationship-load-test.js new file mode 100644 index 00000000000..a4628d13cd6 --- /dev/null +++ b/tests/integration/relationships/inverse-relationship-load-test.js @@ -0,0 +1,4895 @@ +import { module, test } from 'qunit'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; +import { setupTest } from 'ember-qunit'; +import Store from 'ember-data/store'; +import Model from 'ember-data/model'; +import { resolve } from 'rsvp'; +import { attr, belongsTo, hasMany } from '@ember-decorators/data'; +import { testInDebug } from '../../helpers/test-in-debug'; + +module('inverse relationship load test', function(hooks) { + let store; + setupTest(hooks); + + hooks.beforeEach(function() { + let { owner } = this; + owner.register('service:store', Store); + store = owner.lookup('service:store'); + owner.register( + 'serializer:application', + JSONAPISerializer.extend({ + normalizeResponse(_, __, payload) { + return payload; + }, + }) + ); + }); + + test('one-to-many - findHasMany/implicit inverse - adds parent relationship information to the payload if it is not included/added by the serializer', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(dogs.get('length'), 2, 'hasMany relationship has correct number of records'); + let dog1 = dogs.get('firstObject'); + let dogPerson1 = await dog1.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + let dogPerson2 = await dogs.objectAt(1).get('person'); + assert.equal( + dogPerson2.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1, 'record removed from hasMany relationship after deletion'); + assert.equal(dogs.get('firstObject.id'), '2', 'hasMany relationship has correct records'); + }); + + test('one-to-many (left hand async, right hand sync) - findHasMany/implicit inverse - adds parent relationship information to the payload if it is not included/added by the serializer', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: false, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(dogs.get('length'), 2, 'hasMany relationship has correct number of records'); + let dog1 = dogs.get('firstObject'); + let dogPerson1 = await dog1.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + let dogPerson2 = await dogs.objectAt(1).get('person'); + assert.equal( + dogPerson2.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1, 'record removed from hasMany relationship after deletion'); + assert.equal(dogs.get('firstObject.id'), '2', 'hasMany relationship has correct records'); + }); + + test('one-to-many - findHasMany/explicit inverse - adds parent relationship information to the payload if it is not included/added by the serializer', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + inverse: 'pal', + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + pal; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(dogs.get('length'), 2, 'hasMany relationship has correct number of records'); + let dog1 = dogs.get('firstObject'); + let dogPerson1 = await dog1.get('pal'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + let dogPerson2 = await dogs.objectAt(1).get('pal'); + assert.equal( + dogPerson2.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1, 'record removed from hasMany relationship after deletion'); + assert.equal(dogs.get('firstObject.id'), '2', 'hasMany relationship has correct records'); + }); + + test('one-to-many (left hand async, right hand sync) - findHasMany/explicit inverse - adds parent relationship information to the payload if it is not included/added by the serializer', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + inverse: 'pal', + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: false, + inverse: 'dogs', + }) + pal; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(dogs.get('length'), 2, 'hasMany relationship has correct number of records'); + let dog1 = dogs.get('firstObject'); + let dogPerson1 = await dog1.get('pal'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + let dogPerson2 = await dogs.objectAt(1).get('pal'); + assert.equal( + dogPerson2.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1, 'record removed from hasMany relationship after deletion'); + assert.equal(dogs.get('firstObject.id'), '2', 'hasMany relationship has correct records'); + }); + + test('one-to-many - findHasMany/null inverse - adds parent relationship information to the payload if it is not included/added by the serializer', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord() { + return resolve({ + data: null, + }); + }, + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dogs', { + inverse: null, + async: true, + }) + dogs; + @attr + name; + } + owner.register('model:person', Person); + + class Dog extends Model { + @attr + name; + } + + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal(person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + assert.equal(dogs.get('length'), 2); + assert.deepEqual(dogs.mapBy('id'), ['1', '2']); + + let dog1 = dogs.get('firstObject'); + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), '1'); + assert.equal(dogs.get('firstObject.id'), '2'); + }); + + test('one-to-one - findBelongsTo/implicit inverse - ensures inverse relationship is set up when payload does not return parent relationship info', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord() { + return resolve({ + data: null, + }); + }, + findBelongsTo() { + return resolve({ + data: { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @attr + name; + @belongsTo('dog', { async: true }) + favoriteDog; + } + owner.register('model:person', Person); + + class Dog extends Model { + @attr + name; + @belongsTo('person', { async: true }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + favoriteDog: { + links: { + related: 'http://example.com/person/1/favorite-dog', + }, + }, + }, + }, + }); + + let favoriteDog = await person.get('favoriteDog'); + assert.equal(person.belongsTo('favoriteDog').belongsToRelationship.relationshipIsEmpty, false); + assert.equal(favoriteDog.get('id'), '1', 'favoriteDog id is set correctly'); + let favoriteDogPerson = await favoriteDog.get('person'); + assert.equal( + favoriteDogPerson.get('id'), + '1', + 'favoriteDog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + await favoriteDog.destroyRecord(); + favoriteDog = await person.get('favoriteDog'); + assert.equal(favoriteDog, null); + }); + + test('one-to-one (left hand async, right hand sync) - findBelongsTo/implicit inverse - ensures inverse relationship is set up when payload does not return parent relationship info', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord() { + return resolve({ + data: null, + }); + }, + findBelongsTo() { + return resolve({ + data: { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @attr + name; + @belongsTo('dog', { async: true }) + favoriteDog; + } + owner.register('model:person', Person); + + class Dog extends Model { + @attr + name; + @belongsTo('person', { async: true }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + favoriteDog: { + links: { + related: 'http://example.com/person/1/favorite-dog', + }, + }, + }, + }, + }); + + let favoriteDog = await person.get('favoriteDog'); + assert.equal(person.belongsTo('favoriteDog').belongsToRelationship.relationshipIsEmpty, false); + assert.equal(favoriteDog.get('id'), '1', 'favoriteDog id is set correctly'); + let favoriteDogPerson = await favoriteDog.get('person'); + assert.equal( + favoriteDogPerson.get('id'), + '1', + 'favoriteDog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + await favoriteDog.destroyRecord(); + favoriteDog = await person.get('favoriteDog'); + assert.equal(favoriteDog, null); + }); + + test('one-to-one - findBelongsTo/explicit inverse - ensures inverse relationship is set up when payload does not return parent relationship info', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord() { + return resolve({ + data: null, + }); + }, + findBelongsTo() { + return resolve({ + data: { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @attr + name; + @belongsTo('dog', { async: true, inverse: 'pal' }) + favoriteDog; + } + owner.register('model:person', Person); + + class Dog extends Model { + @attr + name; + @belongsTo('person', { async: true }) + pal; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + favoriteDog: { + links: { + related: 'http://example.com/person/1/favorite-dog', + }, + }, + }, + }, + }); + + let favoriteDog = await person.get('favoriteDog'); + assert.equal(person.belongsTo('favoriteDog').belongsToRelationship.relationshipIsEmpty, false); + assert.equal(favoriteDog.get('id'), '1', 'favoriteDog id is set correctly'); + let favoriteDogPerson = await favoriteDog.get('pal'); + assert.equal( + favoriteDogPerson.get('id'), + '1', + 'favoriteDog.pal inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + await favoriteDog.destroyRecord(); + favoriteDog = await person.get('favoriteDog'); + assert.equal(favoriteDog, null); + }); + + test('one-to-one (left hand async, right hand sync) - findBelongsTo/explicit inverse - ensures inverse relationship is set up when payload does not return parent relationship info', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord() { + return resolve({ + data: null, + }); + }, + findBelongsTo() { + return resolve({ + data: { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @attr + name; + @belongsTo('dog', { async: true, inverse: 'pal' }) + favoriteDog; + } + owner.register('model:person', Person); + + class Dog extends Model { + @attr + name; + @belongsTo('person', { async: true }) + pal; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + favoriteDog: { + links: { + related: 'http://example.com/person/1/favorite-dog', + }, + }, + }, + }, + }); + + let favoriteDog = await person.get('favoriteDog'); + assert.equal(person.belongsTo('favoriteDog').belongsToRelationship.relationshipIsEmpty, false); + assert.equal(favoriteDog.get('id'), '1', 'favoriteDog id is set correctly'); + let favoriteDogPerson = await favoriteDog.get('pal'); + assert.equal( + favoriteDogPerson.get('id'), + '1', + 'favoriteDog.pal inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + await favoriteDog.destroyRecord(); + favoriteDog = await person.get('favoriteDog'); + assert.equal(favoriteDog, null); + }); + + test('one-to-one - findBelongsTo/null inverse - ensures inverse relationship is set up when payload does not return parent relationship info', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord() { + return resolve({ + data: null, + }); + }, + findBelongsTo() { + return resolve({ + data: { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @attr + name; + @belongsTo('dog', { async: true }) + favoriteDog; + } + owner.register('model:person', Person); + + class Dog extends Model { + @attr + name; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + favoriteDog: { + links: { + related: 'http://example.com/person/1/favorite-dog', + }, + }, + }, + }, + }); + + let favoriteDog = await person.get('favoriteDog'); + assert.equal(person.belongsTo('favoriteDog').belongsToRelationship.relationshipIsEmpty, false); + assert.equal(favoriteDog.get('id'), '1', 'favoriteDog id is set correctly'); + await favoriteDog.destroyRecord(); + favoriteDog = await person.get('favoriteDog'); + assert.equal(favoriteDog, null); + }); + + test('many-to-many - findHasMany/implicit inverse - adds parent relationship information to the payload if it is not included/added by the serializer', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @hasMany('person', { + async: true, + }) + walkers; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal(person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + + assert.equal( + dogs.get('length'), + 2, + 'left hand side relationship is set up with correct number of records' + ); + let [dog1, dog2] = dogs.toArray(); + let dog1Walkers = await dog1.get('walkers'); + assert.equal( + dog1Walkers.length, + 1, + 'dog1.walkers inverse relationship includes correct number of records' + ); + assert.equal( + dog1Walkers.get('firstObject.id'), + '1', + 'dog1.walkers inverse relationship is set up correctly' + ); + + let dog2Walkers = await dog2.get('walkers'); + assert.equal( + dog2Walkers.length, + 1, + 'dog2.walkers inverse relationship includes correct number of records' + ); + assert.equal( + dog2Walkers.get('firstObject.id'), + '1', + 'dog2.walkers inverse relationship is set up correctly' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1, 'person.dogs relationship was updated when record removed'); + assert.equal( + dogs.get('firstObject.id'), + '2', + 'person.dogs relationship has the correct records' + ); + }); + + test('many-to-many (left hand async, right hand sync) - findHasMany/implicit inverse - adds parent relationship information to the payload if it is not included/added by the serializer', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @hasMany('person', { + async: false, + }) + walkers; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal(person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + + assert.equal( + dogs.get('length'), + 2, + 'left hand side relationship is set up with correct number of records' + ); + let [dog1, dog2] = dogs.toArray(); + let dog1Walkers = await dog1.get('walkers'); + assert.equal( + dog1Walkers.length, + 1, + 'dog1.walkers inverse relationship includes correct number of records' + ); + assert.equal( + dog1Walkers.get('firstObject.id'), + '1', + 'dog1.walkers inverse relationship is set up correctly' + ); + + let dog2Walkers = await dog2.get('walkers'); + assert.equal( + dog2Walkers.length, + 1, + 'dog2.walkers inverse relationship includes correct number of records' + ); + assert.equal( + dog2Walkers.get('firstObject.id'), + '1', + 'dog2.walkers inverse relationship is set up correctly' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1, 'person.dogs relationship was updated when record removed'); + assert.equal( + dogs.get('firstObject.id'), + '2', + 'person.dogs relationship has the correct records' + ); + }); + + test('many-to-many - findHasMany/explicit inverse - adds parent relationship information to the payload if it is not included/added by the serializer', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + inverse: 'pals', + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @hasMany('person', { + async: true, + }) + pals; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal(person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + + assert.equal( + dogs.get('length'), + 2, + 'left hand side relationship is set up with correct number of records' + ); + let [dog1, dog2] = dogs.toArray(); + let dog1Pals = await dog1.get('pals'); + assert.equal( + dog1Pals.length, + 1, + 'dog1.pals inverse relationship includes correct number of records' + ); + assert.equal( + dog1Pals.get('firstObject.id'), + '1', + 'dog1.pals inverse relationship is set up correctly' + ); + + let dog2Pals = await dog2.get('pals'); + assert.equal( + dog2Pals.length, + 1, + 'dog2.pals inverse relationship includes correct number of records' + ); + assert.equal( + dog2Pals.get('firstObject.id'), + '1', + 'dog2.pals inverse relationship is set up correctly' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1, 'person.dogs relationship was updated when record removed'); + assert.equal( + dogs.get('firstObject.id'), + '2', + 'person.dogs relationship has the correct records' + ); + }); + + test('many-to-many (left hand async, right hand sync) - findHasMany/explicit inverse - adds parent relationship information to the payload if it is not included/added by the serializer', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + inverse: 'pals', + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @hasMany('person', { + async: false, + }) + pals; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal(person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + + assert.equal( + dogs.get('length'), + 2, + 'left hand side relationship is set up with correct number of records' + ); + let [dog1, dog2] = dogs.toArray(); + let dog1Pals = await dog1.get('pals'); + assert.equal( + dog1Pals.length, + 1, + 'dog1.pals inverse relationship includes correct number of records' + ); + assert.equal( + dog1Pals.get('firstObject.id'), + '1', + 'dog1.pals inverse relationship is set up correctly' + ); + + let dog2Pals = await dog2.get('pals'); + assert.equal( + dog2Pals.length, + 1, + 'dog2.pals inverse relationship includes correct number of records' + ); + assert.equal( + dog2Pals.get('firstObject.id'), + '1', + 'dog2.pals inverse relationship is set up correctly' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1, 'person.dogs relationship was updated when record removed'); + assert.equal( + dogs.get('firstObject.id'), + '2', + 'person.dogs relationship has the correct records' + ); + }); + + test('many-to-one - findBelongsTo/implicit inverse - adds parent relationship information to the payload if it is not included/added by the serializer', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findBelongsTo: () => { + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + } + owner.register('model:dog', Dog); + + let dog = store.push({ + data: { + type: 'dog', + id: '1', + attributes: { + name: 'A Really Good Dog', + }, + relationships: { + person: { + links: { + related: 'http://example.com/person/1', + }, + }, + }, + }, + }); + + let person = await dog.get('person'); + assert.equal( + dog.belongsTo('person').belongsToRelationship.relationshipIsEmpty, + false, + 'belongsTo relationship state was populated' + ); + assert.equal(person.get('id'), '1', 'dog.person relationship is correctly set up'); + + let dogs = await person.get('dogs'); + + assert.equal( + dogs.get('length'), + 1, + 'person.dogs inverse relationship includes correct number of records' + ); + let [dog1] = dogs.toArray(); + assert.equal(dog1.id, '1', 'dog1.person inverse relationship is set up correctly'); + + await person.destroyRecord(); + dog = await dog.get('person'); + assert.equal(dog, null, 'record deleted removed from belongsTo relationship'); + }); + + test('many-to-one (left hand async, right hand sync) - findBelongsTo/implicit inverse - adds parent relationship information to the payload if it is not included/added by the serializer', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findBelongsTo: () => { + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: false, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + } + owner.register('model:dog', Dog); + + let dog = store.push({ + data: { + type: 'dog', + id: '1', + attributes: { + name: 'A Really Good Dog', + }, + relationships: { + person: { + links: { + related: 'http://example.com/person/1', + }, + }, + }, + }, + }); + + let person = await dog.get('person'); + assert.equal( + dog.belongsTo('person').belongsToRelationship.relationshipIsEmpty, + false, + 'belongsTo relationship state was populated' + ); + assert.equal(person.get('id'), '1', 'dog.person relationship is correctly set up'); + + let dogs = await person.get('dogs'); + + assert.equal( + dogs.get('length'), + 1, + 'person.dogs inverse relationship includes correct number of records' + ); + let [dog1] = dogs.toArray(); + assert.equal(dog1.id, '1', 'dog1.person inverse relationship is set up correctly'); + + await person.destroyRecord(); + dog = await dog.get('person'); + assert.equal(dog, null, 'record deleted removed from belongsTo relationship'); + }); + + test('many-to-one - findBelongsTo/explicit inverse - adds parent relationship information to the payload if it is not included/added by the serializer', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findBelongsTo: () => { + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + inverse: 'pal', + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + pal; + } + owner.register('model:dog', Dog); + + let dog = store.push({ + data: { + type: 'dog', + id: '1', + attributes: { + name: 'A Really Good Dog', + }, + relationships: { + pal: { + links: { + related: 'http://example.com/person/1', + }, + }, + }, + }, + }); + + let person = await dog.get('pal'); + assert.equal( + dog.belongsTo('pal').belongsToRelationship.relationshipIsEmpty, + false, + 'belongsTo relationship state was populated' + ); + assert.equal(person.get('id'), '1', 'dog.person relationship is correctly set up'); + + let dogs = await person.get('dogs'); + + assert.equal( + dogs.get('length'), + 1, + 'person.dogs inverse relationship includes correct number of records' + ); + let [dog1] = dogs.toArray(); + assert.equal(dog1.id, '1', 'dog1.person inverse relationship is set up correctly'); + + await person.destroyRecord(); + dog = await dog.get('pal'); + assert.equal(dog, null, 'record deleted removed from belongsTo relationship'); + }); + + test('many-to-one (left hand async, right hand sync) - findBelongsTo/explicit inverse - adds parent relationship information to the payload if it is not included/added by the serializer', async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findBelongsTo: () => { + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: false, + inverse: 'pal', + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + pal; + } + owner.register('model:dog', Dog); + + let dog = store.push({ + data: { + type: 'dog', + id: '1', + attributes: { + name: 'A Really Good Dog', + }, + relationships: { + pal: { + links: { + related: 'http://example.com/person/1', + }, + }, + }, + }, + }); + + let person = await dog.get('pal'); + assert.equal( + dog.belongsTo('pal').belongsToRelationship.relationshipIsEmpty, + false, + 'belongsTo relationship state was populated' + ); + assert.equal(person.get('id'), '1', 'dog.person relationship is correctly set up'); + + let dogs = await person.get('dogs'); + + assert.equal( + dogs.get('length'), + 1, + 'person.dogs inverse relationship includes correct number of records' + ); + let [dog1] = dogs.toArray(); + assert.equal(dog1.id, '1', 'dog1.person inverse relationship is set up correctly'); + + await person.destroyRecord(); + dog = await dog.get('pal'); + assert.equal(dog, null, 'record deleted removed from belongsTo relationship'); + }); + + testInDebug( + 'one-to-many - findHasMany/implicit inverse - fixes mismatched parent relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + person: { + data: { + id: '2', + type: 'person', + }, + }, + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + person: { + data: { + id: '2', + type: 'person', + }, + }, + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.expectDeprecation(/Encountered mismatched relationship/); + assert.equal(person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + assert.equal(dogs.get('length'), 2); + + let dog1 = dogs.get('firstObject'); + let dogPerson1 = await dog1.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + let dogPerson2 = await dogs.objectAt(1).get('person'); + assert.equal( + dogPerson2.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1); + assert.equal(dogs.get('firstObject.id'), '2'); + } + ); + + testInDebug( + 'one-to-many (left hand async, right hand sync) - findHasMany/implicit inverse - fixes mismatched parent relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + person: { + data: { + id: '2', + type: 'person', + }, + }, + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + person: { + data: { + id: '2', + type: 'person', + }, + }, + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: false, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.expectDeprecation(/Encountered mismatched relationship/); + assert.equal(person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + assert.equal(dogs.get('length'), 2); + + let dog1 = dogs.get('firstObject'); + let dogPerson1 = await dog1.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + let dogPerson2 = await dogs.objectAt(1).get('person'); + assert.equal( + dogPerson2.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1); + assert.equal(dogs.get('firstObject.id'), '2'); + } + ); + + testInDebug( + 'one-to-many - findHasMany/implicit inverse - fixes null relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + person: { + data: null, + }, + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + person: { + data: null, + }, + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.expectDeprecation(/Encountered mismatched relationship/); + assert.equal(person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + assert.equal(dogs.get('length'), 2); + + let dog1 = dogs.get('firstObject'); + let dogPerson1 = await dog1.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + let dogPerson2 = await dogs.objectAt(1).get('person'); + assert.equal( + dogPerson2.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1); + assert.equal(dogs.get('firstObject.id'), '2'); + } + ); + + testInDebug( + 'one-to-many (left hand async, right hand sync) - findHasMany/implicit inverse - fixes null relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + person: { + data: null, + }, + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + person: { + data: null, + }, + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: false, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.expectDeprecation(/Encountered mismatched relationship/); + assert.equal(person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + assert.equal(dogs.get('length'), 2); + + let dog1 = dogs.get('firstObject'); + let dogPerson1 = await dog1.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + let dogPerson2 = await dogs.objectAt(1).get('person'); + assert.equal( + dogPerson2.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1); + assert.equal(dogs.get('firstObject.id'), '2'); + } + ); + + testInDebug( + 'one-to-one - findBelongsTo/implicit inverse - fixes mismatched parent relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findBelongsTo: () => { + return resolve({ + data: { + id: '1', + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + person: { + data: { + id: '2', + type: 'person', + }, + }, + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @belongsTo('dog', { + async: true, + }) + dog; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dog: { + links: { + related: 'http://example.com/person/1/dog', + }, + }, + }, + }, + }); + + let dog = await person.get('dog'); + assert.expectDeprecation(/Encountered mismatched relationship/); + + let dogFromStore = await store.peekRecord('dog', '1'); + + // weirdly these pass + assert.equal(dogFromStore.belongsTo('person').id(), '1'); + assert.equal(person.belongsTo('dog').id(), '1'); + assert.equal(dog.id, '1', 'dog.person relationship loaded correctly'); + assert.equal( + person.belongsTo('dog').belongsToRelationship.relationshipIsEmpty, + false, + 'relationship is not empty' + ); + + let dogPerson1 = await dog.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog.destroyRecord(); + dog = await person.get('dog'); + assert.equal(dog, null, 'record was removed from belongsTo relationship'); + } + ); + + testInDebug( + 'one-to-one (left hand async, right hand sync) - findBelongsTo/implicit inverse - fixes mismatched parent relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findBelongsTo: () => { + return resolve({ + data: { + id: '1', + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + person: { + data: { + id: '2', + type: 'person', + }, + }, + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @belongsTo('dog', { + async: true, + }) + dog; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: false, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dog: { + links: { + related: 'http://example.com/person/1/dog', + }, + }, + }, + }, + }); + + let dog = await person.get('dog'); + assert.expectDeprecation(/Encountered mismatched relationship/); + + let dogFromStore = await store.peekRecord('dog', '1'); + + // weirdly these pass + assert.equal(dogFromStore.belongsTo('person').id(), '1'); + assert.equal(person.belongsTo('dog').id(), '1'); + assert.equal(dog.id, '1', 'dog.person relationship loaded correctly'); + + assert.equal( + person.belongsTo('dog').belongsToRelationship.relationshipIsEmpty, + false, + 'relationship is not empty' + ); + + let dogPerson1 = await dog.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog.destroyRecord(); + dog = await person.get('dog'); + assert.equal(dog, null, 'record was removed from belongsTo relationship'); + } + ); + + testInDebug( + 'one-to-one - findBelongsTo/implicit inverse - fixes null relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findBelongsTo: () => { + return resolve({ + data: { + id: '1', + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + person: { + data: null, + }, + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @belongsTo('dog', { + async: true, + }) + dog; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dog: { + links: { + related: 'http://example.com/person/1/dog', + }, + }, + }, + }, + }); + + let dog = await person.get('dog'); + assert.expectDeprecation(/Encountered mismatched relationship/); + + let dogFromStore = await store.peekRecord('dog', '1'); + + // weirdly these pass + assert.equal(dogFromStore.belongsTo('person').id(), '1'); + assert.equal(person.belongsTo('dog').id(), '1'); + assert.equal(dog.id, '1', 'dog.person relationship loaded correctly'); + + assert.equal( + person.belongsTo('dog').belongsToRelationship.relationshipIsEmpty, + false, + 'relationship is not empty' + ); + + let dogPerson1 = await dog.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog.destroyRecord(); + dog = await person.get('dog'); + assert.equal(dog, null, 'record was removed from belongsTo relationship'); + } + ); + + testInDebug( + 'one-to-one (left hand async, right hand sync) - findBelongsTo/implicit inverse - fixes null relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findBelongsTo: () => { + return resolve({ + data: { + id: '1', + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + person: { + data: null, + }, + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @belongsTo('dog', { + async: true, + }) + dog; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: false, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dog: { + links: { + related: 'http://example.com/person/1/dog', + }, + }, + }, + }, + }); + + let dog = await person.get('dog'); + assert.expectDeprecation(/Encountered mismatched relationship/); + + let dogFromStore = await store.peekRecord('dog', '1'); + + // weirdly these pass + assert.equal(dogFromStore.belongsTo('person').id(), '1'); + assert.equal(person.belongsTo('dog').id(), '1'); + assert.equal(dog.id, '1', 'dog.person relationship loaded correctly'); + + assert.equal( + person.belongsTo('dog').belongsToRelationship.relationshipIsEmpty, + false, + 'relationship is not empty' + ); + + let dogPerson1 = await dog.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog.destroyRecord(); + dog = await person.get('dog'); + assert.equal(dog, null, 'record was removed from belongsTo relationship'); + } + ); + + testInDebug( + 'many-to-one - findBelongsTo/implicitInverse - fixes mismatched parent relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findBelongsTo: () => { + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [ + { + id: '2', + type: 'dog', + }, + ], + }, + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + } + owner.register('model:dog', Dog); + + let dog = store.push({ + data: { + type: 'dog', + id: '1', + attributes: { + name: 'A Really Good Dog', + }, + relationships: { + person: { + links: { + related: 'http://example.com/person/1', + }, + }, + }, + }, + }); + + let person = await dog.get('person'); + assert.expectDeprecation(/Encountered mismatched relationship/); + let dogFromStore = await store.peekRecord('dog', '1'); + + assert.equal( + dogFromStore.belongsTo('person').id(), + '1', + 'dog relationship is set up correctly' + ); + let dogPerson1 = await dog.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship is not empty' + ); + + await dog.destroyRecord(); + dog = await person.get('dog'); + assert.equal(dog, null, 'record was removed from belongsTo relationship'); + } + ); + + testInDebug( + 'many-to-one (left hand async, right hand sync) - findBelongsTo/implicitInverse - fixes mismatched parent relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findBelongsTo: () => { + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [ + { + id: '2', + type: 'dog', + }, + ], + }, + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: false, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + } + owner.register('model:dog', Dog); + + let dog = store.push({ + data: { + type: 'dog', + id: '1', + attributes: { + name: 'A Really Good Dog', + }, + relationships: { + person: { + links: { + related: 'http://example.com/person/1', + }, + }, + }, + }, + }); + + let person = await dog.get('person'); + assert.expectDeprecation(/Encountered mismatched relationship/); + let dogFromStore = await store.peekRecord('dog', '1'); + + assert.equal( + dogFromStore.belongsTo('person').id(), + '1', + 'dog relationship is set up correctly' + ); + let dogPerson1 = await dog.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship is not empty' + ); + + await dog.destroyRecord(); + dog = await person.get('dog'); + assert.equal(dog, null, 'record was removed from belongsTo relationship'); + } + ); + + testInDebug( + 'many-to-one - findBelongsTo/implicitInverse - fixes null relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findBelongsTo: () => { + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [], + }, + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + } + owner.register('model:dog', Dog); + + let dog = store.push({ + data: { + type: 'dog', + id: '1', + attributes: { + name: 'A Really Good Dog', + }, + relationships: { + person: { + links: { + related: 'http://example.com/person/1', + }, + }, + }, + }, + }); + + let person = await dog.get('person'); + assert.expectDeprecation(/Encountered mismatched relationship/); + let dogFromStore = await store.peekRecord('dog', '1'); + + assert.equal( + dogFromStore.belongsTo('person').id(), + '1', + 'dog relationship is set up correctly' + ); + let dogPerson1 = await dog.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship is not empty' + ); + + await dog.destroyRecord(); + dog = await person.get('dog'); + assert.equal(dog, null, 'record was removed from belongsTo relationship'); + } + ); + + testInDebug( + 'many-to-one (left hand async, right hand sync) - findBelongsTo/implicitInverse - fixes null relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findBelongsTo: () => { + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [], + }, + }, + }, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: false, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + } + owner.register('model:dog', Dog); + + let dog = store.push({ + data: { + type: 'dog', + id: '1', + attributes: { + name: 'A Really Good Dog', + }, + relationships: { + person: { + links: { + related: 'http://example.com/person/1', + }, + }, + }, + }, + }); + + let person = await dog.get('person'); + assert.expectDeprecation(/Encountered mismatched relationship/); + let dogFromStore = await store.peekRecord('dog', '1'); + + assert.equal( + dogFromStore.belongsTo('person').id(), + '1', + 'dog relationship is set up correctly' + ); + let dogPerson1 = await dog.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship is not empty' + ); + + await dog.destroyRecord(); + dog = await person.get('dog'); + assert.equal(dog, null, 'record was removed from belongsTo relationship'); + } + ); + + testInDebug( + 'many-to-many - findHasMany/implicitInverse - fixes mismatched parent relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + walkers: { + data: [ + { + id: '2', + type: 'person', + }, + ], + }, + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + walkers: { + data: [ + { + id: '2', + type: 'person', + }, + ], + }, + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @hasMany('person', { + async: true, + }) + walkers; + } + owner.register('model:dog', Dog); + + let person1 = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + let person2 = store.push({ + data: { + type: 'person', + id: '2', + attributes: { + name: 'Fond Memories', + }, + }, + }); + + let person1Dogs = await person1.get('dogs'); + + assert.expectDeprecation(/Encountered mismatched relationship/); + assert.equal(person1.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + + let dog1 = store.peekRecord('dog', '1'); + let dog2 = store.peekRecord('dog', '2'); + + for (let person of [person1, person2]) { + const dogs = await person.get('dogs'); + assert.equal( + dogs.get('length'), + 2, + 'left hand side relationship is set up with correct number of records' + ); + assert.ok( + dogs.indexOf(dog1) >= 0, + 'relationship includes the parent even though it was not specified' + ); + assert.ok( + dogs.indexOf(dog2) >= 0, + 'relationship also includes records the payload specified' + ); + + for (let dog of [dog1, dog2]) { + let walkers = await dog.get('walkers'); + assert.equal( + walkers.length, + 2, + 'dog1.walkers inverse relationship includes correct number of records' + ); + assert.ok( + walkers.indexOf(person1) >= 0, + 'dog1Walkers includes the record that requested the relationship but was not specified in the relationships of the records in the response' + ); + assert.ok( + walkers.indexOf(person2) >= 0, + 'dog1Walkers includes records the response returned in data.relationships' + ); + } + } + + await dog1.destroyRecord(); + + for (let person of [person1, person2]) { + let dogs = await person.get('dogs'); + assert.equal( + dogs.get('length'), + 1, + 'person1.dogs relationship was updated when record removed' + ); + assert.equal( + dogs.get('firstObject.id'), + '2', + 'person.dogs relationship has the correct records' + ); + } + + let dog2Walkers = await dog2.get('walkers'); + assert.equal( + dog2Walkers.get('length'), + 2, + 'dog2 still has correct number of records for hasMany relationship' + ); + assert.ok( + dog2Walkers.indexOf(person1) >= 0, + 'dog2Walkers includes the record that requested the relationship but was not specified in the relationships of the records in the response' + ); + assert.ok( + dog2Walkers.indexOf(person2) >= 0, + 'dog2Walkers includes records the response returned in data.relationships' + ); + + // now delete another side of the many-to-many + + await person2.destroyRecord(); + + assert.equal(person1Dogs.get('length'), 1, 'person1 has correct # of dogs'); + assert.equal( + person1Dogs.get('firstObject.id'), + dog2.get('id'), + 'person1 has dog2 in its hasMany relationship; dog1 is not present because it was destroyed.' + ); + assert.equal( + dog2Walkers.get('length'), + 1, + 'dog2 has correct # of records after record specified by server response is destroyed' + ); + assert.equal( + dog2Walkers.get('firstObject.id'), + person1.get('id'), + 'dog2 has person1 in its hasMany relationship; person2 is not present because it was destroyed.' + ); + + // finally, destroy person1, the record that loaded all this data through the relationship + + await person1.destroyRecord(); + assert.equal( + dog2Walkers.get('length'), + 0, + 'dog2 hasMany relationship is empty after all person records are destroyed' + ); + } + ); + + testInDebug( + 'many-to-many (left hand async, right hand sync) - findHasMany/implicitInverse - fixes mismatched parent relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + walkers: { + data: [ + { + id: '2', + type: 'person', + }, + ], + }, + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + walkers: { + data: [ + { + id: '2', + type: 'person', + }, + ], + }, + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @hasMany('person', { + async: false, + }) + walkers; + } + owner.register('model:dog', Dog); + + let person1 = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + let person2 = store.push({ + data: { + type: 'person', + id: '2', + attributes: { + name: 'Fond Memories', + }, + }, + }); + + let person1Dogs = await person1.get('dogs'); + + assert.expectDeprecation(/Encountered mismatched relationship/); + assert.equal(person1.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + + let dog1 = store.peekRecord('dog', '1'); + let dog2 = store.peekRecord('dog', '2'); + + for (let person of [person1, person2]) { + const dogs = await person.get('dogs'); + assert.equal( + dogs.get('length'), + 2, + 'left hand side relationship is set up with correct number of records' + ); + assert.ok( + dogs.indexOf(dog1) >= 0, + 'relationship includes the parent even though it was not specified' + ); + assert.ok( + dogs.indexOf(dog2) >= 0, + 'relationship also includes records the payload specified' + ); + + for (let dog of [dog1, dog2]) { + let walkers = await dog.get('walkers'); + assert.equal( + walkers.length, + 2, + 'dog1.walkers inverse relationship includes correct number of records' + ); + assert.ok( + walkers.indexOf(person1) >= 0, + 'dog1Walkers includes the record that requested the relationship but was not specified in the relationships of the records in the response' + ); + assert.ok( + walkers.indexOf(person2) >= 0, + 'dog1Walkers includes records the response returned in data.relationships' + ); + } + } + + await dog1.destroyRecord(); + + for (let person of [person1, person2]) { + let dogs = await person.get('dogs'); + assert.equal( + dogs.get('length'), + 1, + 'person1.dogs relationship was updated when record removed' + ); + assert.equal( + dogs.get('firstObject.id'), + '2', + 'person.dogs relationship has the correct records' + ); + } + + let dog2Walkers = await dog2.get('walkers'); + assert.equal( + dog2Walkers.get('length'), + 2, + 'dog2 still has correct number of records for hasMany relationship' + ); + assert.ok( + dog2Walkers.indexOf(person1) >= 0, + 'dog2Walkers includes the record that requested the relationship but was not specified in the relationships of the records in the response' + ); + assert.ok( + dog2Walkers.indexOf(person2) >= 0, + 'dog2Walkers includes records the response returned in data.relationships' + ); + + // now delete another side of the many-to-many + + await person2.destroyRecord(); + + assert.equal(person1Dogs.get('length'), 1, 'person1 has correct # of dogs'); + assert.equal( + person1Dogs.get('firstObject.id'), + dog2.get('id'), + 'person1 has dog2 in its hasMany relationship; dog1 is not present because it was destroyed.' + ); + assert.equal( + dog2Walkers.get('length'), + 1, + 'dog2 has correct # of records after record specified by server response is destroyed' + ); + assert.equal( + dog2Walkers.get('firstObject.id'), + person1.get('id'), + 'dog2 has person1 in its hasMany relationship; person2 is not present because it was destroyed.' + ); + + // finally, destroy person1, the record that loaded all this data through the relationship + + await person1.destroyRecord(); + assert.equal( + dog2Walkers.get('length'), + 0, + 'dog2 hasMany relationship is empty after all person records are destroyed' + ); + } + ); + + testInDebug( + 'many-to-many - findHasMany/implicitInverse - fixes empty relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + walkers: { + data: [], + }, + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + walkers: { + data: [], + }, + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @hasMany('person', { + async: true, + }) + walkers; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + await person.get('dogs'); + + assert.expectDeprecation(/Encountered mismatched relationship/); + assert.equal(person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + + let dog1 = store.peekRecord('dog', '1'); + let dog2 = store.peekRecord('dog', '2'); + + const dogs = await person.get('dogs'); + assert.equal( + dogs.get('length'), + 2, + 'left hand side relationship is set up with correct number of records' + ); + assert.ok( + dogs.indexOf(dog1) >= 0, + 'relationship includes the parent even though it was not specified' + ); + assert.ok( + dogs.indexOf(dog2) >= 0, + 'relationship also includes records the payload specified' + ); + + for (let dog of [dog1, dog2]) { + let walkers = await dog.get('walkers'); + assert.equal( + walkers.length, + 1, + 'dog1.walkers inverse relationship includes correct number of records' + ); + assert.ok( + walkers.indexOf(person) >= 0, + 'dog1Walkers includes the record that requested the relationship but was not specified in the relationships of the records in the response' + ); + } + + await dog1.destroyRecord(); + + assert.equal( + dogs.get('length'), + 1, + 'person1.dogs relationship was updated when record removed' + ); + assert.equal( + dogs.get('firstObject.id'), + '2', + 'person.dogs relationship has the correct records' + ); + + let dog2Walkers = await dog2.get('walkers'); + assert.equal( + dog2Walkers.get('length'), + 1, + 'dog2 still has correct number of records for hasMany relationship' + ); + assert.ok( + dog2Walkers.indexOf(person) >= 0, + 'dog2Walkers includes the record that requested the relationship but was not specified in the relationships of the records in the response' + ); + + // finally, destroy person1, the record that loaded all this data through the relationship + await person.destroyRecord(); + assert.equal( + dog2Walkers.get('length'), + 0, + 'dog2 hasMany relationship is empty after all person records are destroyed' + ); + } + ); + + testInDebug( + 'many-to-many (left hand async, right hand sync) - findHasMany/implicitInverse - fixes empty relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + walkers: { + data: [], + }, + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + walkers: { + data: [], + }, + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @hasMany('person', { + async: false, + }) + walkers; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + await person.get('dogs'); + + assert.expectDeprecation(/Encountered mismatched relationship/); + assert.equal(person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + + let dog1 = store.peekRecord('dog', '1'); + let dog2 = store.peekRecord('dog', '2'); + + const dogs = await person.get('dogs'); + assert.equal( + dogs.get('length'), + 2, + 'left hand side relationship is set up with correct number of records' + ); + assert.ok( + dogs.indexOf(dog1) >= 0, + 'relationship includes the parent even though it was not specified' + ); + assert.ok( + dogs.indexOf(dog2) >= 0, + 'relationship also includes records the payload specified' + ); + + for (let dog of [dog1, dog2]) { + let walkers = await dog.get('walkers'); + assert.equal( + walkers.length, + 1, + 'dog1.walkers inverse relationship includes correct number of records' + ); + assert.ok( + walkers.indexOf(person) >= 0, + 'dog1Walkers includes the record that requested the relationship but was not specified in the relationships of the records in the response' + ); + } + + await dog1.destroyRecord(); + + assert.equal( + dogs.get('length'), + 1, + 'person1.dogs relationship was updated when record removed' + ); + assert.equal( + dogs.get('firstObject.id'), + '2', + 'person.dogs relationship has the correct records' + ); + + let dog2Walkers = await dog2.get('walkers'); + assert.equal( + dog2Walkers.get('length'), + 1, + 'dog2 still has correct number of records for hasMany relationship' + ); + assert.ok( + dog2Walkers.indexOf(person) >= 0, + 'dog2Walkers includes the record that requested the relationship but was not specified in the relationships of the records in the response' + ); + + // finally, destroy person1, the record that loaded all this data through the relationship + await person.destroyRecord(); + assert.equal( + dog2Walkers.get('length'), + 0, + 'dog2 hasMany relationship is empty after all person records are destroyed' + ); + } + ); + + testInDebug( + 'many-to-many - findHasMany/implicitInverse - fixes null relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + walkers: { + data: null, + }, + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + walkers: { + data: null, + }, + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @hasMany('person', { + async: true, + }) + walkers; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + + assert.expectDeprecation(/Encountered mismatched relationship/); + assert.equal(person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + + let dog1 = store.peekRecord('dog', '1'); + let dog2 = store.peekRecord('dog', '2'); + + assert.equal( + dogs.get('length'), + 2, + 'left hand side relationship is set up with correct number of records' + ); + assert.ok( + dogs.indexOf(dog1) >= 0, + 'relationship includes the parent even though it was not specified' + ); + assert.ok( + dogs.indexOf(dog2) >= 0, + 'relationship also includes records the payload specified' + ); + + for (let dog of [dog1, dog2]) { + let walkers = await dog.get('walkers'); + assert.equal( + walkers.length, + 1, + 'dog1.walkers inverse relationship includes correct number of records' + ); + assert.ok( + walkers.indexOf(person) >= 0, + 'dog1Walkers includes the record that requested the relationship but was not specified in the relationships of the records in the response' + ); + } + + await dog1.destroyRecord(); + + assert.equal( + dogs.get('length'), + 1, + 'person1.dogs relationship was updated when record removed' + ); + assert.equal( + dogs.get('firstObject.id'), + '2', + 'person.dogs relationship has the correct records' + ); + + let dog2Walkers = await dog2.get('walkers'); + assert.equal( + dog2Walkers.get('length'), + 1, + 'dog2 still has correct number of records for hasMany relationship' + ); + assert.ok( + dog2Walkers.indexOf(person) >= 0, + 'dog2Walkers includes the record that requested the relationship but was not specified in the relationships of the records in the response' + ); + + // finally, destroy person1, the record that loaded all this data through the relationship + await person.destroyRecord(); + assert.equal( + dog2Walkers.get('length'), + 0, + 'dog2 hasMany relationship is empty after all person records are destroyed' + ); + } + ); + + testInDebug( + 'many-to-many (left hand async, right hand sync) - findHasMany/implicitInverse - fixes null relationship information from the payload and deprecates', + async function(assert) { + let { owner } = this; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findHasMany: () => { + return resolve({ + data: [ + { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + walkers: { + data: null, + }, + }, + }, + { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + walkers: { + data: null, + }, + }, + }, + ], + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @hasMany('person', { + async: false, + }) + walkers; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + + assert.expectDeprecation(/Encountered mismatched relationship/); + assert.equal(person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, false); + + let dog1 = store.peekRecord('dog', '1'); + let dog2 = store.peekRecord('dog', '2'); + + assert.equal( + dogs.get('length'), + 2, + 'left hand side relationship is set up with correct number of records' + ); + assert.ok( + dogs.indexOf(dog1) >= 0, + 'relationship includes the parent even though it was not specified' + ); + assert.ok( + dogs.indexOf(dog2) >= 0, + 'relationship also includes records the payload specified' + ); + + for (let dog of [dog1, dog2]) { + let walkers = await dog.get('walkers'); + assert.equal( + walkers.length, + 1, + 'dog1.walkers inverse relationship includes correct number of records' + ); + assert.ok( + walkers.indexOf(person) >= 0, + 'dog1Walkers includes the record that requested the relationship but was not specified in the relationships of the records in the response' + ); + } + + await dog1.destroyRecord(); + + assert.equal( + dogs.get('length'), + 1, + 'person1.dogs relationship was updated when record removed' + ); + assert.equal( + dogs.get('firstObject.id'), + '2', + 'person.dogs relationship has the correct records' + ); + + let dog2Walkers = await dog2.get('walkers'); + assert.equal( + dog2Walkers.get('length'), + 1, + 'dog2 still has correct number of records for hasMany relationship' + ); + assert.ok( + dog2Walkers.indexOf(person) >= 0, + 'dog2Walkers includes the record that requested the relationship but was not specified in the relationships of the records in the response' + ); + + // finally, destroy person1, the record that loaded all this data through the relationship + await person.destroyRecord(); + assert.equal( + dog2Walkers.get('length'), + 0, + 'dog2 hasMany relationship is empty after all person records are destroyed' + ); + } + ); + + test('one-to-many - ids/non-link/implicit inverse - ids - records loaded through ids/findRecord are linked to the parent if the response from the server does not include relationship information', async function(assert) { + let { owner } = this; + + const scooby = { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }; + + const scrappy = { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + }; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findRecord: (_store, _type, id) => { + const dog = id === '1' ? scooby : scrappy; + return resolve({ + data: dog, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [ + { + id: '1', + type: 'dog', + }, + { + id: '2', + type: 'dog', + }, + ], + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(dogs.get('length'), 2, 'hasMany relationship has correct number of records'); + let dog1 = dogs.get('firstObject'); + let dogPerson1 = await dog1.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + let dogPerson2 = await dogs.objectAt(1).get('person'); + assert.equal( + dogPerson2.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1, 'record removed from hasMany relationship after deletion'); + assert.equal(dogs.get('firstObject.id'), '2', 'hasMany relationship has correct records'); + }); + + test('one-to-many (left hand async, right hand sync) - ids/non-link/implicit inverse - ids - records loaded through ids/findRecord are linked to the parent if the response from the server does not include relationship information', async function(assert) { + let { owner } = this; + + const scooby = { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }; + + const scrappy = { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + }; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findRecord: (_store, _type, id) => { + const dog = id === '1' ? scooby : scrappy; + return resolve({ + data: dog, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: false, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [ + { + id: '1', + type: 'dog', + }, + { + id: '2', + type: 'dog', + }, + ], + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(dogs.get('length'), 2, 'hasMany relationship has correct number of records'); + let dog1 = dogs.get('firstObject'); + let dogPerson1 = await dog1.get('person'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + let dogPerson2 = await dogs.objectAt(1).get('person'); + assert.equal( + dogPerson2.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1, 'record removed from hasMany relationship after deletion'); + assert.equal(dogs.get('firstObject.id'), '2', 'hasMany relationship has correct records'); + }); + + test('one-to-many - ids/non-link/explicit inverse - ids - records loaded through ids/findRecord are linked to the parent if the response from the server does not include relationship information', async function(assert) { + let { owner } = this; + + const scooby = { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }; + + const scrappy = { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + }; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findRecord: (_store, _type, id) => { + const dog = id === '1' ? scooby : scrappy; + return resolve({ + data: dog, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + inverse: 'pal', + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + pal; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [ + { + id: '1', + type: 'dog', + }, + { + id: '2', + type: 'dog', + }, + ], + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(dogs.get('length'), 2, 'hasMany relationship has correct number of records'); + let dog1 = dogs.get('firstObject'); + let dogPerson1 = await dog1.get('pal'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + let dogPerson2 = await dogs.objectAt(1).get('pal'); + assert.equal( + dogPerson2.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1, 'record removed from hasMany relationship after deletion'); + assert.equal(dogs.get('firstObject.id'), '2', 'hasMany relationship has correct records'); + }); + + test('one-to-many (left hand async, right hand sync) - ids/non-link/explicit inverse - ids - records loaded through ids/findRecord are linked to the parent if the response from the server does not include relationship information', async function(assert) { + let { owner } = this; + + const scooby = { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }; + + const scrappy = { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + }; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findRecord: (_store, _type, id) => { + const dog = id === '1' ? scooby : scrappy; + return resolve({ + data: dog, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + inverse: 'pal', + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: false, + }) + pal; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [ + { + id: '1', + type: 'dog', + }, + { + id: '2', + type: 'dog', + }, + ], + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(dogs.get('length'), 2, 'hasMany relationship has correct number of records'); + let dog1 = dogs.get('firstObject'); + let dogPerson1 = await dog1.get('pal'); + assert.equal( + dogPerson1.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + let dogPerson2 = await dogs.objectAt(1).get('pal'); + assert.equal( + dogPerson2.get('id'), + '1', + 'dog.person inverse relationship is set up correctly when adapter does not include parent relationships in data.relationships' + ); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1, 'record removed from hasMany relationship after deletion'); + assert.equal(dogs.get('firstObject.id'), '2', 'hasMany relationship has correct records'); + }); + + test('one-to-many - ids/non-link/null inverse - ids - records loaded through ids/findRecord are linked to the parent if the response from the server does not include relationship information', async function(assert) { + let { owner } = this; + + const scooby = { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + }; + + const scrappy = { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + }; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findRecord: (_store, _type, id) => { + const dog = id === '1' ? scooby : scrappy; + return resolve({ + data: dog, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + inverse: null, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model {} + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [ + { + id: '1', + type: 'dog', + }, + { + id: '2', + type: 'dog', + }, + ], + }, + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(dogs.get('length'), 2, 'hasMany relationship has correct number of records'); + let dog1 = dogs.get('firstObject'); + + await dog1.destroyRecord(); + assert.equal(dogs.get('length'), 1, 'record removed from hasMany relationship after deletion'); + assert.equal(dogs.get('firstObject.id'), '2', 'hasMany relationship has correct records'); + }); + + test('one-to-many - ids/non-link/implicit inverse - records loaded through ids/findRecord do not get associated with the parent if the server specifies another resource as the relationship value in the response', async function(assert) { + let { owner } = this; + + const scooby = { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + person: { + data: { + id: '2', + type: 'person', + }, + }, + }, + }; + + const scrappy = { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + person: { + data: { + id: '2', + type: 'person', + }, + }, + }, + }; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findRecord: (_store, _type, id) => { + const dog = id === '1' ? scooby : scrappy; + return resolve({ + data: dog, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [ + { + id: '1', + type: 'dog', + }, + { + id: '2', + type: 'dog', + }, + ], + }, + }, + }, + }); + + let person2 = store.push({ + data: { + type: 'person', + id: '2', + attributes: { + name: 'ok', + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(dogs.get('length'), 0, 'hasMany relationship for parent is empty'); + + let person2Dogs = await person2.get('dogs'); + assert.equal( + person2Dogs.get('length'), + 2, + 'hasMany relationship on specified record has correct number of associated records' + ); + + for (let dog of store.peekAll('dogs').toArray()) { + let dogPerson = await dog.get('person'); + assert.equal( + dogPerson.get('id'), + person2.get('id'), + 'right hand side has correct belongsTo value' + ); + } + + let dog1 = store.peekRecord('dog', '1'); + await dog1.destroyRecord(); + assert.equal( + person2Dogs.get('length'), + 1, + 'record removed from hasMany relationship after deletion' + ); + assert.equal( + person2Dogs.get('firstObject.id'), + '2', + 'hasMany relationship has correct records' + ); + }); + + test('one-to-many (left hand async, right hand sync) - ids/non-link/implicit inverse - records loaded through ids/findRecord do not get associated with the parent if the server specifies another resource as the relationship value in the response', async function(assert) { + let { owner } = this; + + const scooby = { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + person: { + data: { + id: '2', + type: 'person', + }, + }, + }, + }; + + const scrappy = { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + person: { + data: { + id: '2', + type: 'person', + }, + }, + }, + }; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findRecord: (_store, _type, id) => { + const dog = id === '1' ? scooby : scrappy; + return resolve({ + data: dog, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: false, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [ + { + id: '1', + type: 'dog', + }, + { + id: '2', + type: 'dog', + }, + ], + }, + }, + }, + }); + + let person2 = store.push({ + data: { + type: 'person', + id: '2', + attributes: { + name: 'ok', + }, + }, + }); + + let dogs = await person.get('dogs'); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(dogs.get('length'), 0, 'hasMany relationship for parent is empty'); + + let person2Dogs = await person2.get('dogs'); + assert.equal( + person2Dogs.get('length'), + 2, + 'hasMany relationship on specified record has correct number of associated records' + ); + + for (let dog of store.peekAll('dogs').toArray()) { + let dogPerson = await dog.get('person'); + assert.equal( + dogPerson.get('id'), + person2.get('id'), + 'right hand side has correct belongsTo value' + ); + } + + let dog1 = store.peekRecord('dog', '1'); + await dog1.destroyRecord(); + assert.equal( + person2Dogs.get('length'), + 1, + 'record removed from hasMany relationship after deletion' + ); + assert.equal( + person2Dogs.get('firstObject.id'), + '2', + 'hasMany relationship has correct records' + ); + }); + + test('one-to-many - ids/non-link/implicit inverse - records loaded through ids/findRecord do not get associated with the parent if the server specifies null as the relationship value in the response', async function(assert) { + let { owner } = this; + + const scooby = { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + person: { + data: null, + }, + }, + }; + + const scrappy = { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + person: { + data: null, + }, + }, + }; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findRecord: (_store, _type, id) => { + const dog = id === '1' ? scooby : scrappy; + return resolve({ + data: dog, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [ + { + id: '1', + type: 'dog', + }, + { + id: '2', + type: 'dog', + }, + ], + }, + }, + }, + }); + + let personDogs = await person.get('dogs'); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(personDogs.get('length'), 0, 'hasMany relationship for parent is empty'); + + for (let dog of store.peekAll('dogs').toArray()) { + let dogPerson = await dog.get('person'); + assert.equal(dogPerson, null, 'right hand side has correct belongsTo value'); + } + + let dog1 = store.peekRecord('dog', '1'); + await dog1.destroyRecord(); + + assert.equal(personDogs.get('length'), 0); + }); + + test('one-to-many (left hand async, right hand sync) - ids/non-link/implicit inverse - records loaded through ids/findRecord do not get associated with the parent if the server specifies null as the relationship value in the response', async function(assert) { + let { owner } = this; + + const scooby = { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + person: { + data: null, + }, + }, + }; + + const scrappy = { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + person: { + data: null, + }, + }, + }; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findRecord: (_store, _type, id) => { + const dog = id === '1' ? scooby : scrappy; + return resolve({ + data: dog, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: false, + }) + person; + } + owner.register('model:dog', Dog); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [ + { + id: '1', + type: 'dog', + }, + { + id: '2', + type: 'dog', + }, + ], + }, + }, + }, + }); + + let personDogs = await person.get('dogs'); + assert.equal( + person.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(personDogs.get('length'), 0, 'hasMany relationship for parent is empty'); + + for (let dog of store.peekAll('dogs').toArray()) { + let dogPerson = await dog.get('person'); + assert.equal(dogPerson, null, 'right hand side has correct belongsTo value'); + } + + let dog1 = store.peekRecord('dog', '1'); + await dog1.destroyRecord(); + + assert.equal(personDogs.get('length'), 0); + }); + + test('one-to-many - ids/non-link/explicit inverse - records loaded through ids/findRecord do not get associated with the parent if the server specifies another resource as the relationship value in the response', async function(assert) { + let { owner } = this; + + const scooby = { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + pal: { + data: { + id: '2', + type: 'pal', + }, + }, + }, + }; + + const scrappy = { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + pal: { + data: { + id: '2', + type: 'pal', + }, + }, + }, + }; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findRecord: (_store, _type, id) => { + const dog = id === '1' ? scooby : scrappy; + return resolve({ + data: dog, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:pal', Person); + + class Dog extends Model { + @belongsTo('pal', { + async: true, + }) + pal; + } + owner.register('model:dog', Dog); + + let pal = store.push({ + data: { + type: 'pal', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [ + { + id: '1', + type: 'dog', + }, + { + id: '2', + type: 'dog', + }, + ], + }, + }, + }, + }); + + let pal2 = store.push({ + data: { + type: 'pal', + id: '2', + attributes: { + name: 'ok', + }, + }, + }); + + let dogs = await pal.get('dogs'); + assert.equal( + pal.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(dogs.get('length'), 0, 'hasMany relationship for parent is empty'); + + let pal2Dogs = await pal2.get('dogs'); + assert.equal( + pal2Dogs.get('length'), + 2, + 'hasMany relationship on specified record has correct number of associated records' + ); + + for (let dog of store.peekAll('dogs').toArray()) { + let dogPerson = await dog.get('pal'); + assert.equal( + dogPerson.get('id'), + pal2.get('id'), + 'right hand side has correct belongsTo value' + ); + } + + let dog1 = store.peekRecord('dog', '1'); + await dog1.destroyRecord(); + assert.equal( + pal2Dogs.get('length'), + 1, + 'record removed from hasMany relationship after deletion' + ); + assert.equal(pal2Dogs.get('firstObject.id'), '2', 'hasMany relationship has correct records'); + }); + + test('one-to-many (left hand async, right hand sync) - ids/non-link/explicit inverse - records loaded through ids/findRecord do not get associated with the parent if the server specifies another resource as the relationship value in the response', async function(assert) { + let { owner } = this; + + const scooby = { + id: 1, + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + pal: { + data: { + id: '2', + type: 'pal', + }, + }, + }, + }; + + const scrappy = { + id: 2, + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + pal: { + data: { + id: '2', + type: 'pal', + }, + }, + }, + }; + + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findRecord: (_store, _type, id) => { + const dog = id === '1' ? scooby : scrappy; + return resolve({ + data: dog, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: true, + }) + dogs; + } + owner.register('model:pal', Person); + + class Dog extends Model { + @belongsTo('pal', { + async: false, + }) + pal; + } + owner.register('model:dog', Dog); + + let pal = store.push({ + data: { + type: 'pal', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + data: [ + { + id: '1', + type: 'dog', + }, + { + id: '2', + type: 'dog', + }, + ], + }, + }, + }, + }); + + let pal2 = store.push({ + data: { + type: 'pal', + id: '2', + attributes: { + name: 'ok', + }, + }, + }); + + let dogs = await pal.get('dogs'); + assert.equal( + pal.hasMany('dogs').hasManyRelationship.relationshipIsEmpty, + false, + 'relationship state was set up correctly' + ); + + assert.equal(dogs.get('length'), 0, 'hasMany relationship for parent is empty'); + + let pal2Dogs = await pal2.get('dogs'); + assert.equal( + pal2Dogs.get('length'), + 2, + 'hasMany relationship on specified record has correct number of associated records' + ); + + for (let dog of store.peekAll('dogs').toArray()) { + let dogPerson = await dog.get('pal'); + assert.equal( + dogPerson.get('id'), + pal2.get('id'), + 'right hand side has correct belongsTo value' + ); + } + + let dog1 = store.peekRecord('dog', '1'); + await dog1.destroyRecord(); + assert.equal( + pal2Dogs.get('length'), + 1, + 'record removed from hasMany relationship after deletion' + ); + assert.equal(pal2Dogs.get('firstObject.id'), '2', 'hasMany relationship has correct records'); + }); +}); From 91127903cf5b46696844665604c0e77e1291abf6 Mon Sep 17 00:00:00 2001 From: Brian Runnells Date: Wed, 3 Oct 2018 15:05:29 -0600 Subject: [PATCH 2366/2527] remove .only (#5664) --- node-tests/blueprints/adapter-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 4c7ebc16fe1..7e37e5cc458 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -134,7 +134,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { }); }); - describe.only('with ember-mocha v0.14+', function() { + describe('with ember-mocha v0.14+', function() { beforeEach(function() { modifyPackages([ { name: 'ember-cli-qunit', delete: true }, From 625235303e69439d50fb2e9affe9d57e8215fbc1 Mon Sep 17 00:00:00 2001 From: Brian Runnells Date: Thu, 4 Oct 2018 12:25:37 -0600 Subject: [PATCH 2367/2527] add remaining mocha rfc 232 blueprints (#5665) * add mocha rfc232 serializer tests * add MU adapter test * add model mocha rfc 232 blueprints * add transform mocha rfc 232 blueprints --- .../__root__/__path__/__test__.js | 14 ++++++ .../__root__/__path__/__test__.js | 24 ++++++++++ .../__root__/__path__/__test__.js | 13 ++++++ node-tests/blueprints/adapter-test.js | 24 ++++++++++ node-tests/blueprints/model-test.js | 44 +++++++++++++++++++ node-tests/blueprints/serializer-test.js | 44 +++++++++++++++++++ node-tests/blueprints/transform-test.js | 44 +++++++++++++++++++ .../fixtures/model-test/mocha-rfc232.js | 14 ++++++ .../fixtures/serializer-test/mocha-rfc232.js | 24 ++++++++++ .../fixtures/transform-test/mocha-rfc232.js | 13 ++++++ 10 files changed, 258 insertions(+) create mode 100644 blueprints/model-test/mocha-rfc-232-files/__root__/__path__/__test__.js create mode 100644 blueprints/serializer-test/mocha-rfc-232-files/__root__/__path__/__test__.js create mode 100644 blueprints/transform-test/mocha-rfc-232-files/__root__/__path__/__test__.js create mode 100644 node-tests/fixtures/model-test/mocha-rfc232.js create mode 100644 node-tests/fixtures/serializer-test/mocha-rfc232.js create mode 100644 node-tests/fixtures/transform-test/mocha-rfc232.js diff --git a/blueprints/model-test/mocha-rfc-232-files/__root__/__path__/__test__.js b/blueprints/model-test/mocha-rfc-232-files/__root__/__path__/__test__.js new file mode 100644 index 00000000000..77576d6d45f --- /dev/null +++ b/blueprints/model-test/mocha-rfc-232-files/__root__/__path__/__test__.js @@ -0,0 +1,14 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupTest } from 'ember-mocha'; + +describe('<%= friendlyTestDescription %>', function() { + setupTest(); + + // Replace this with your real tests. + it('exists', function() { + let store = this.owner.lookup('service:store'); + let model = store.createRecord('<%= dasherizedModuleName %>', {}); + expect(model).to.be.ok; + }); +}); diff --git a/blueprints/serializer-test/mocha-rfc-232-files/__root__/__path__/__test__.js b/blueprints/serializer-test/mocha-rfc-232-files/__root__/__path__/__test__.js new file mode 100644 index 00000000000..fcf277e607e --- /dev/null +++ b/blueprints/serializer-test/mocha-rfc-232-files/__root__/__path__/__test__.js @@ -0,0 +1,24 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupTest } from 'ember-mocha'; + +describe('<%= friendlyTestDescription %>', function() { + setupTest(); + + // Replace this with your real tests. + it('exists', function() { + let store = this.owner.lookup('service:store'); + let serializer = store.serializerFor('<%= dasherizedModuleName %>'); + + expect(serializer).to.be.ok; + }); + + it('serializes records', function() { + let store = this.owner.lookup('service:store'); + let record = store.createRecord('<%= dasherizedModuleName %>', {}); + + let serializedRecord = record.serialize(); + + expect(serializedRecord).to.be.ok; + }); +}); diff --git a/blueprints/transform-test/mocha-rfc-232-files/__root__/__path__/__test__.js b/blueprints/transform-test/mocha-rfc-232-files/__root__/__path__/__test__.js new file mode 100644 index 00000000000..a7fbabdb805 --- /dev/null +++ b/blueprints/transform-test/mocha-rfc-232-files/__root__/__path__/__test__.js @@ -0,0 +1,13 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupTest } from 'ember-mocha'; + +describe('<%= friendlyTestDescription %>', function() { + setupTest(); + + // Replace this with your real tests. + it('exists', function() { + let transform = this.owner.lookup('transform:<%= dasherizedModuleName %>'); + expect(transform).to.be.ok; + }); +}); diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 7e37e5cc458..5366e86dea8 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -287,5 +287,29 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { ); }); }); + + describe('with ember-mocha v0.14+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-mocha', '0.14.0'); + }); + + it('adapter-test for mocha v0.14+', function() { + let args = ['adapter-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/mocha-rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); }); }); diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index cc480a79e78..b1c7f6f78c9 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -140,6 +140,26 @@ describe('Acceptance: generate and destroy model blueprints', function() { }); }); }); + + describe('with ember-mocha v0.14+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-mocha', '0.14.0'); + }); + + it('model-test for mocha v0.14+', function() { + let args = ['model-test', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/models/foo-test.js')).to.equal( + fixture('model-test/mocha-rfc232.js') + ); + }); + }); + }); }); describe('module unification', function() { @@ -297,5 +317,29 @@ describe('Acceptance: generate and destroy model blueprints', function() { ); }); }); + + describe('with ember-mocha v0.14+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-mocha', '0.14.0'); + }); + + it('model-test for mocha v0.14+', function() { + let args = ['model-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/model-test.js')).to.equal( + fixture('model-test/mocha-rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); }); }); diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index 058b4c157ca..5f6766342d5 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -133,6 +133,26 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { }); }); }); + + describe('with ember-mocha v0.14+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-mocha', '0.14.0'); + }); + + it('serializer-test for mocha v0.14+', function() { + let args = ['serializer-test', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/serializers/foo-test.js')).to.equal( + fixture('serializer-test/mocha-rfc232.js') + ); + }); + }); + }); }); describe('module unification', function() { @@ -278,5 +298,29 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { ); }); }); + + describe('with ember-mocha v0.14+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-mocha', '0.14.0'); + }); + + it('serializer-test for mocha v0.14+', function() { + let args = ['serializer-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/serializer-test.js')).to.equal( + fixture('serializer-test/mocha-rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); }); }); diff --git a/node-tests/blueprints/transform-test.js b/node-tests/blueprints/transform-test.js index 31f879d5d40..f6ac63d27fe 100644 --- a/node-tests/blueprints/transform-test.js +++ b/node-tests/blueprints/transform-test.js @@ -80,6 +80,26 @@ describe('Acceptance: generate and destroy transform blueprints', function() { }); }); }); + + describe('with ember-mocha v0.14+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-mocha', '0.14.0'); + }); + + it('transform-test for mocha v0.14+', function() { + let args = ['transform-test', 'foo']; + + return emberGenerateDestroy(args, _file => { + expect(_file('tests/unit/transforms/foo-test.js')).to.equal( + fixture('transform-test/mocha-rfc232.js') + ); + }); + }); + }); }); }); @@ -164,6 +184,30 @@ describe('Acceptance: generate and destroy transform blueprints', function() { ); }); }); + + describe('with ember-mocha v0.14+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-mocha', '0.14.0'); + }); + + it('transform-test for mocha v0.14+', function() { + let args = ['transform-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/transforms/foo-test.js')).to.equal( + fixture('transform-test/mocha-rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); }); }); }); diff --git a/node-tests/fixtures/model-test/mocha-rfc232.js b/node-tests/fixtures/model-test/mocha-rfc232.js new file mode 100644 index 00000000000..9c94ea35029 --- /dev/null +++ b/node-tests/fixtures/model-test/mocha-rfc232.js @@ -0,0 +1,14 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupTest } from 'ember-mocha'; + +describe('Unit | Model | foo', function() { + setupTest(); + + // Replace this with your real tests. + it('exists', function() { + let store = this.owner.lookup('service:store'); + let model = store.createRecord('foo', {}); + expect(model).to.be.ok; + }); +}); diff --git a/node-tests/fixtures/serializer-test/mocha-rfc232.js b/node-tests/fixtures/serializer-test/mocha-rfc232.js new file mode 100644 index 00000000000..02a450df483 --- /dev/null +++ b/node-tests/fixtures/serializer-test/mocha-rfc232.js @@ -0,0 +1,24 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupTest } from 'ember-mocha'; + +describe('Unit | Serializer | foo', function() { + setupTest(); + + // Replace this with your real tests. + it('exists', function() { + let store = this.owner.lookup('service:store'); + let serializer = store.serializerFor('foo'); + + expect(serializer).to.be.ok; + }); + + it('serializes records', function() { + let store = this.owner.lookup('service:store'); + let record = store.createRecord('foo', {}); + + let serializedRecord = record.serialize(); + + expect(serializedRecord).to.be.ok; + }); +}); diff --git a/node-tests/fixtures/transform-test/mocha-rfc232.js b/node-tests/fixtures/transform-test/mocha-rfc232.js new file mode 100644 index 00000000000..5ad1979debc --- /dev/null +++ b/node-tests/fixtures/transform-test/mocha-rfc232.js @@ -0,0 +1,13 @@ +import { expect } from 'chai'; +import { describe, it } from 'mocha'; +import { setupTest } from 'ember-mocha'; + +describe('Unit | Transform | foo', function() { + setupTest(); + + // Replace this with your real tests. + it('exists', function() { + let transform = this.owner.lookup('transform:foo'); + expect(transform).to.be.ok; + }); +}); From 550052e47ad47a168c63e3f9afc6dbcaac2cd309 Mon Sep 17 00:00:00 2001 From: Chris Parry Date: Thu, 4 Oct 2018 22:25:22 +0100 Subject: [PATCH 2368/2527] Added conditional check to extract polymorphic relationship for hasMany (#5623) Added conditional check to extract polymorphic relationship for hasMany (#5623) Added extract polymorphic for hasMany relationship --- addon/serializers/json.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index c5d2677a5f3..5de6c37f478 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -686,9 +686,20 @@ const JSONSerializer = Serializer.extend({ } else if (relationshipMeta.kind === 'hasMany') { if (!isNone(relationshipHash)) { data = new Array(relationshipHash.length); - for (let i = 0, l = relationshipHash.length; i < l; i++) { - let item = relationshipHash[i]; - data[i] = this.extractRelationship(relationshipMeta.type, item); + if (relationshipMeta.options.polymorphic) { + for (let i = 0, l = relationshipHash.length; i < l; i++) { + let item = relationshipHash[i]; + data[i] = this.extractPolymorphicRelationship(relationshipMeta.type, item, { + key, + resourceHash, + relationshipMeta, + }); + } + } else { + for (let i = 0, l = relationshipHash.length; i < l; i++) { + let item = relationshipHash[i]; + data[i] = this.extractRelationship(relationshipMeta.type, item); + } } } } From 0929425a2d969fa0406209d2dc4efa6d2718c54e Mon Sep 17 00:00:00 2001 From: btecu Date: Thu, 4 Oct 2018 18:15:45 -0400 Subject: [PATCH 2369/2527] Remove unused code (#5666) --- config/environment.js | 1 - node-tests/nodetest-runner.js | 4 ---- 2 files changed, 5 deletions(-) diff --git a/config/environment.js b/config/environment.js index b5300869ad2..9707ea62a74 100644 --- a/config/environment.js +++ b/config/environment.js @@ -1,4 +1,3 @@ -/*jshint node:true*/ 'use strict'; module.exports = function(/* environment, appConfig */) { diff --git a/node-tests/nodetest-runner.js b/node-tests/nodetest-runner.js index e909e06564d..c9c35b03940 100644 --- a/node-tests/nodetest-runner.js +++ b/node-tests/nodetest-runner.js @@ -26,11 +26,7 @@ var mocha = new Mocha({ reporter: 'spec', }); var testFiles = glob.sync(root + '/**/*-test.js'); -/*var jshintPosition = testFiles.indexOf('tests/unit/jshint-test.js'); -var jshint = testFiles.splice(jshintPosition, 1); -testFiles = jshint.concat(testFiles); -*/ if (optionOrFile === 'all') { addFiles(mocha, testFiles); addFiles(mocha, 'node-tests/**/*-test.js'); From 0826f81569feb28b4604f53200615febeea704ea Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 4 Oct 2018 15:50:19 -0700 Subject: [PATCH 2370/2527] remove legacy build --- addon/-legacy-private/attr.js | 137 - addon/-legacy-private/index.js | 56 - addon/-legacy-private/system/many-array.js | 290 -- .../system/model/internal-model.js | 1404 ------- addon/-legacy-private/system/model/model.js | 1994 ---------- addon/-legacy-private/system/model/states.js | 766 ---- .../-legacy-private/system/promise-proxies.js | 162 - .../system/references/belongs-to.js | 440 --- .../system/references/has-many.js | 442 --- .../system/references/reference.js | 10 - .../system/relationships/belongs-to.js | 143 - .../system/relationships/ext.js | 70 - .../system/relationships/has-many.js | 156 - .../relationship-payloads-manager.js | 346 -- .../relationships/relationship-payloads.js | 499 --- .../system/relationships/state/belongs-to.js | 324 -- .../system/relationships/state/create.js | 86 - .../system/relationships/state/has-many.js | 454 --- .../relationships/state/relationship.js | 747 ---- addon/-legacy-private/system/snapshot.js | 409 -- addon/-legacy-private/system/store.js | 3462 ----------------- .../attr.js | 0 .../index.js | 0 .../system/many-array.js | 0 .../system/model/internal-model.js | 0 .../system/model/model.js | 0 .../system/model/record-data.js | 0 .../system/model/states.js | 0 .../system/promise-proxies.js | 0 .../system/references/belongs-to.js | 0 .../system/references/has-many.js | 0 .../system/references/reference.js | 0 .../system/relationships/belongs-to.js | 0 .../system/relationships/ext.js | 0 .../system/relationships/has-many.js | 0 .../system/relationships/state/belongs-to.js | 0 .../system/relationships/state/create.js | 0 .../system/relationships/state/has-many.js | 0 .../relationships/state/relationship.js | 0 .../system/snapshot.js | 0 .../system/store.js | 0 .../system/store/record-data-wrapper.js | 0 index.js | 24 +- lib/cli-flags.js | 17 - tests/dummy/config/environment.js | 5 - tests/helpers/test-in-debug.js | 15 +- 46 files changed, 4 insertions(+), 12454 deletions(-) delete mode 100644 addon/-legacy-private/attr.js delete mode 100644 addon/-legacy-private/index.js delete mode 100644 addon/-legacy-private/system/many-array.js delete mode 100644 addon/-legacy-private/system/model/internal-model.js delete mode 100644 addon/-legacy-private/system/model/model.js delete mode 100644 addon/-legacy-private/system/model/states.js delete mode 100644 addon/-legacy-private/system/promise-proxies.js delete mode 100644 addon/-legacy-private/system/references/belongs-to.js delete mode 100644 addon/-legacy-private/system/references/has-many.js delete mode 100644 addon/-legacy-private/system/references/reference.js delete mode 100644 addon/-legacy-private/system/relationships/belongs-to.js delete mode 100644 addon/-legacy-private/system/relationships/ext.js delete mode 100644 addon/-legacy-private/system/relationships/has-many.js delete mode 100644 addon/-legacy-private/system/relationships/relationship-payloads-manager.js delete mode 100644 addon/-legacy-private/system/relationships/relationship-payloads.js delete mode 100644 addon/-legacy-private/system/relationships/state/belongs-to.js delete mode 100644 addon/-legacy-private/system/relationships/state/create.js delete mode 100755 addon/-legacy-private/system/relationships/state/has-many.js delete mode 100644 addon/-legacy-private/system/relationships/state/relationship.js delete mode 100644 addon/-legacy-private/system/snapshot.js delete mode 100644 addon/-legacy-private/system/store.js rename addon/{-record-data-private => -private}/attr.js (100%) rename addon/{-record-data-private => -private}/index.js (100%) rename addon/{-record-data-private => -private}/system/many-array.js (100%) rename addon/{-record-data-private => -private}/system/model/internal-model.js (100%) rename addon/{-record-data-private => -private}/system/model/model.js (100%) rename addon/{-record-data-private => -private}/system/model/record-data.js (100%) rename addon/{-record-data-private => -private}/system/model/states.js (100%) rename addon/{-record-data-private => -private}/system/promise-proxies.js (100%) rename addon/{-record-data-private => -private}/system/references/belongs-to.js (100%) rename addon/{-record-data-private => -private}/system/references/has-many.js (100%) rename addon/{-record-data-private => -private}/system/references/reference.js (100%) rename addon/{-record-data-private => -private}/system/relationships/belongs-to.js (100%) rename addon/{-record-data-private => -private}/system/relationships/ext.js (100%) rename addon/{-record-data-private => -private}/system/relationships/has-many.js (100%) rename addon/{-record-data-private => -private}/system/relationships/state/belongs-to.js (100%) rename addon/{-record-data-private => -private}/system/relationships/state/create.js (100%) rename addon/{-record-data-private => -private}/system/relationships/state/has-many.js (100%) rename addon/{-record-data-private => -private}/system/relationships/state/relationship.js (100%) rename addon/{-record-data-private => -private}/system/snapshot.js (100%) rename addon/{-record-data-private => -private}/system/store.js (100%) rename addon/{-record-data-private => -private}/system/store/record-data-wrapper.js (100%) diff --git a/addon/-legacy-private/attr.js b/addon/-legacy-private/attr.js deleted file mode 100644 index 47d2947c6e6..00000000000 --- a/addon/-legacy-private/attr.js +++ /dev/null @@ -1,137 +0,0 @@ -import { computed } from '@ember/object'; -import { assert } from '@ember/debug'; - -/** - @module ember-data -*/ - -function getDefaultValue(record, options, key) { - if (typeof options.defaultValue === 'function') { - return options.defaultValue.apply(null, arguments); - } else { - let defaultValue = options.defaultValue; - assert( - `Non primitive defaultValues are not supported because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.`, - typeof defaultValue !== 'object' || defaultValue === null - ); - return defaultValue; - } -} - -function hasValue(record, key) { - return key in record._attributes || key in record._inFlightAttributes || key in record._data; -} - -/** - `DS.attr` defines an attribute on a [DS.Model](/api/data/classes/DS.Model.html). - By default, attributes are passed through as-is, however you can specify an - optional type to have the value automatically transformed. - Ember Data ships with four basic transform types: `string`, `number`, - `boolean` and `date`. You can define your own transforms by subclassing - [DS.Transform](/api/data/classes/DS.Transform.html). - - Note that you cannot use `attr` to define an attribute of `id`. - - `DS.attr` takes an optional hash as a second parameter, currently - supported options are: - - - `defaultValue`: Pass a string or a function to be called to set the attribute - to a default value if none is supplied. - - Example - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - username: DS.attr('string'), - email: DS.attr('string'), - verified: DS.attr('boolean', { defaultValue: false }) - }); - ``` - - Default value can also be a function. This is useful it you want to return - a new object for each attribute. - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - username: DS.attr('string'), - email: DS.attr('string'), - settings: DS.attr({ - defaultValue() { - return {}; - } - }) - }); - ``` - - The `options` hash is passed as second argument to a transforms' - `serialize` and `deserialize` method. This allows to configure a - transformation and adapt the corresponding value, based on the config: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - text: DS.attr('text', { - uppercase: true - }) - }); - ``` - - ```app/transforms/text.js - import DS from 'ember-data'; - - export default DS.Transform.extend({ - serialize(value, options) { - if (options.uppercase) { - return value.toUpperCase(); - } - - return value; - }, - - deserialize(value) { - return value; - } - }) - ``` - - @namespace - @method attr - @for DS - @param {String|Object} type the attribute type - @param {Object} options a hash of options - @return {Attribute} -*/ - -export default function attr(type, options) { - if (typeof type === 'object') { - options = type; - type = undefined; - } else { - options = options || {}; - } - - let meta = { - type: type, - isAttribute: true, - options: options, - }; - - return computed({ - get(key) { - let internalModel = this._internalModel; - if (hasValue(internalModel, key)) { - return internalModel.getAttributeValue(key); - } else { - return getDefaultValue(this, options, key); - } - }, - set(key, value) { - return this._internalModel.setDirtyAttribute(key, value); - }, - }).meta(meta); -} diff --git a/addon/-legacy-private/index.js b/addon/-legacy-private/index.js deleted file mode 100644 index a1addb6ec09..00000000000 --- a/addon/-legacy-private/index.js +++ /dev/null @@ -1,56 +0,0 @@ -// public -export { default as Model } from './system/model/model'; -export { default as Errors } from './system/model/errors'; -export { default as Store } from './system/store'; -export { default as DS } from './core'; -export { default as belongsTo } from './system/relationships/belongs-to'; -export { default as hasMany } from './system/relationships/has-many'; -export { default as BuildURLMixin } from './adapters/build-url-mixin'; -export { default as Snapshot } from './system/snapshot'; -export { default as attr } from './attr'; -export { - AdapterError, - InvalidError, - UnauthorizedError, - ForbiddenError, - NotFoundError, - ConflictError, - ServerError, - TimeoutError, - AbortError, - errorsHashToArray, - errorsArrayToHash, -} from './adapters/errors'; - -// maybe public ? -export { default as normalizeModelName } from './system/normalize-model-name'; -export { getOwner, modelHasAttributeOrRelationshipNamedType } from './utils'; -export { default as coerceId } from './system/coerce-id'; -export { default as parseResponseHeaders } from './utils/parse-response-headers'; - -export { default as isEnabled } from './features'; -// `ember-data-model-fragments` relies on `RootState` and `InternalModel` -export { default as RootState } from './system/model/states'; -export { default as InternalModel } from './system/model/internal-model'; - -export { PromiseArray, PromiseObject, PromiseManyArray } from './system/promise-proxies'; - -export { RecordArray, AdapterPopulatedRecordArray } from './system/record-arrays'; - -export { default as ManyArray } from './system/many-array'; -export { default as RecordArrayManager } from './system/record-array-manager'; -export { default as Relationship } from './system/relationships/state/relationship'; - -export { default as Map } from './system/map'; -export { default as MapWithDefault } from './system/map-with-default'; - -// Should be a different Repo ? -export { default as DebugAdapter } from './system/debug/debug-adapter'; - -// Used by tests -export { default as diffArray } from './system/diff-array'; -export { - default as RelationshipPayloadsManager, -} from './system/relationships/relationship-payloads-manager'; -export { default as RelationshipPayloads } from './system/relationships/relationship-payloads'; -export { default as SnapshotRecordArray } from './system/snapshot-record-array'; diff --git a/addon/-legacy-private/system/many-array.js b/addon/-legacy-private/system/many-array.js deleted file mode 100644 index 0812659d8bb..00000000000 --- a/addon/-legacy-private/system/many-array.js +++ /dev/null @@ -1,290 +0,0 @@ -/** - @module ember-data -*/ -import { all } from 'rsvp'; - -import Evented from '@ember/object/evented'; -import MutableArray from '@ember/array/mutable'; -import EmberObject, { get } from '@ember/object'; -import { assert } from '@ember/debug'; -import { PromiseArray } from './promise-proxies'; -import { _objectIsAlive } from './store/common'; -import diffArray from './diff-array'; - -/** - A `ManyArray` is a `MutableArray` that represents the contents of a has-many - relationship. - - The `ManyArray` is instantiated lazily the first time the relationship is - requested. - - ### Inverses - - Often, the relationships in Ember Data applications will have - an inverse. For example, imagine the following models are - defined: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - comments: DS.hasMany('comment') - }); - ``` - - ```app/models/comment.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - post: DS.belongsTo('post') - }); - ``` - - If you created a new instance of `App.Post` and added - a `App.Comment` record to its `comments` has-many - relationship, you would expect the comment's `post` - property to be set to the post that contained - the has-many. - - We call the record to which a relationship belongs-to the - relationship's _owner_. - - @class ManyArray - @namespace DS - @extends Ember.Object - @uses Ember.MutableArray, Ember.Evented -*/ -export default EmberObject.extend(MutableArray, Evented, { - init() { - this._super(...arguments); - - /** - The loading state of this array - - @property {Boolean} isLoaded - */ - this.isLoaded = this.isLoaded || false; - this.length = 0; - - /** - Used for async `hasMany` arrays - to keep track of when they will resolve. - - @property {Ember.RSVP.Promise} promise - @private - */ - this.promise = null; - - /** - Metadata associated with the request for async hasMany relationships. - - Example - - Given that the server returns the following JSON payload when fetching a - hasMany relationship: - - ```js - { - "comments": [{ - "id": 1, - "comment": "This is the first comment", - }, { - // ... - }], - - "meta": { - "page": 1, - "total": 5 - } - } - ``` - - You can then access the metadata via the `meta` property: - - ```js - post.get('comments').then(function(comments) { - var meta = comments.get('meta'); - - // meta.page => 1 - // meta.total => 5 - }); - ``` - - @property {Object} meta - @public - */ - this.meta = this.meta || null; - - /** - `true` if the relationship is polymorphic, `false` otherwise. - - @property {Boolean} isPolymorphic - @private - */ - this.isPolymorphic = this.isPolymorphic || false; - - /** - The relationship which manages this array. - - @property {ManyRelationship} relationship - @private - */ - this.relationship = this.relationship || null; - - this.currentState = []; - this.flushCanonical(false); - }, - - objectAt(index) { - this.relationship._flushPendingManyArrayUpdates(); - let internalModel = this.currentState[index]; - if (internalModel === undefined) { - return; - } - - return internalModel.getRecord(); - }, - - flushCanonical(isInitialized = true) { - // It’s possible the parent side of the relationship may have been unloaded by this point - if (!_objectIsAlive(this)) { - return; - } - - let toSet = this.relationship.members.list.slice(); - - // diff to find changes - let diff = diffArray(this.currentState, toSet); - - if (diff.firstChangeIndex !== null) { - // it's null if no change found - // we found a change - this.arrayContentWillChange(diff.firstChangeIndex, diff.removedCount, diff.addedCount); - this.set('length', toSet.length); - this.currentState = toSet; - this.arrayContentDidChange(diff.firstChangeIndex, diff.removedCount, diff.addedCount); - if (isInitialized && diff.addedCount > 0) { - //notify only on additions - //TODO only notify if unloaded - this.relationship.notifyHasManyChange(); - } - } - }, - - internalReplace(idx, amt, objects) { - if (!objects) { - objects = []; - } - this.arrayContentWillChange(idx, amt, objects.length); - this.currentState.splice.apply(this.currentState, [idx, amt].concat(objects)); - this.set('length', this.currentState.length); - this.arrayContentDidChange(idx, amt, objects.length); - }, - - //TODO(Igor) optimize - _removeInternalModels(internalModels) { - for (let i = 0; i < internalModels.length; i++) { - let index = this.currentState.indexOf(internalModels[i]); - this.internalReplace(index, 1); - } - }, - - //TODO(Igor) optimize - _addInternalModels(internalModels, idx) { - if (idx === undefined) { - idx = this.currentState.length; - } - this.internalReplace(idx, 0, internalModels); - }, - - replace(idx, amt, objects) { - let internalModels; - if (amt > 0) { - internalModels = this.currentState.slice(idx, idx + amt); - this.get('relationship').removeInternalModels(internalModels); - } - if (objects) { - this.get('relationship').addInternalModels(objects.map(obj => obj._internalModel), idx); - } - }, - - /** - Reloads all of the records in the manyArray. If the manyArray - holds a relationship that was originally fetched using a links url - Ember Data will revisit the original links url to repopulate the - relationship. - - If the manyArray holds the result of a `store.query()` reload will - re-run the original query. - - Example - - ```javascript - var user = store.peekRecord('user', 1) - user.login().then(function() { - user.get('permissions').then(function(permissions) { - return permissions.reload(); - }); - }); - ``` - - @method reload - @public - */ - reload(options) { - return this.relationship.reload(options); - }, - - /** - Saves all of the records in the `ManyArray`. - - Example - - ```javascript - store.findRecord('inbox', 1).then(function(inbox) { - inbox.get('messages').then(function(messages) { - messages.forEach(function(message) { - message.set('isRead', true); - }); - messages.save() - }); - }); - ``` - - @method save - @return {DS.PromiseArray} promise - */ - save() { - let manyArray = this; - let promiseLabel = 'DS: ManyArray#save ' + get(this, 'type'); - let promise = all(this.invoke('save'), promiseLabel).then( - () => manyArray, - null, - 'DS: ManyArray#save return ManyArray' - ); - - return PromiseArray.create({ promise }); - }, - - /** - Create a child record within the owner - - @method createRecord - @private - @param {Object} hash - @return {DS.Model} record - */ - createRecord(hash) { - const store = get(this, 'store'); - const type = get(this, 'type'); - - assert( - `You cannot add '${type.modelName}' records to this polymorphic relationship.`, - !get(this, 'isPolymorphic') - ); - let record = store.createRecord(type.modelName, hash); - this.pushObject(record); - - return record; - }, -}); diff --git a/addon/-legacy-private/system/model/internal-model.js b/addon/-legacy-private/system/model/internal-model.js deleted file mode 100644 index 73d53c4c2cd..00000000000 --- a/addon/-legacy-private/system/model/internal-model.js +++ /dev/null @@ -1,1404 +0,0 @@ -import { A } from '@ember/array'; -import { set, get } from '@ember/object'; -import { assign } from '@ember/polyfills'; -import EmberError from '@ember/error'; -import { isEqual } from '@ember/utils'; -import { setOwner } from '@ember/application'; -import { run } from '@ember/runloop'; -import RSVP, { Promise } from 'rsvp'; -import Ember from 'ember'; -import { DEBUG } from '@glimmer/env'; -import { assert, inspect } from '@ember/debug'; -import RootState from './states'; -import Relationships from '../relationships/state/create'; -import Snapshot from '../snapshot'; -import OrderedSet from '../ordered-set'; -import isArrayLike from '../is-array-like'; - -import { getOwner } from '../../utils'; - -import { RecordReference, BelongsToReference, HasManyReference } from '../references'; - -/* - The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached - when transitioning from one state to another, so that future transitions can replay the - transition without needing to walk the state tree, collect these hook calls and determine - the state to transition into. - - A future optimization would be to build a single chained method out of the collected enters - and setups. It may also be faster to do a two level cache (from: { to }) instead of caching based - on a key that adds the two together. - */ -const TransitionChainMap = Object.create(null); - -const _extractPivotNameCache = Object.create(null); -const _splitOnDotCache = Object.create(null); - -function splitOnDot(name) { - return _splitOnDotCache[name] || (_splitOnDotCache[name] = name.split('.')); -} - -function extractPivotName(name) { - return _extractPivotNameCache[name] || (_extractPivotNameCache[name] = splitOnDot(name)[0]); -} - -function areAllModelsUnloaded(internalModels) { - for (let i = 0; i < internalModels.length; ++i) { - let record = internalModels[i]._record; - if (record && !(record.get('isDestroyed') || record.get('isDestroying'))) { - return false; - } - } - return true; -} - -// Handle dematerialization for relationship `rel`. In all cases, notify the -// relationship of the dematerialization: this is done so the relationship can -// notify its inverse which needs to update state -// -// If the inverse is sync, unloading this record is treated as a client-side -// delete, so we remove the inverse records from this relationship to -// disconnect the graph. Because it's not async, we don't need to keep around -// the internalModel as an id-wrapper for references and because the graph is -// disconnected we can actually destroy the internalModel when checking for -// orphaned models. -function destroyRelationship(rel) { - rel.internalModelDidDematerialize(); - - if (rel._inverseIsSync()) { - // disconnect the graph so that the sync inverse relationship does not - // prevent us from cleaning up during `_cleanupOrphanedInternalModels` - rel.removeAllInternalModelsFromOwn(); - rel.removeAllCanonicalInternalModelsFromOwn(); - } -} -// this (and all heimdall instrumentation) will be stripped by a babel transform -// https://github.com/heimdalljs/babel5-plugin-strip-heimdall -const { - _triggerDeferredTriggers, - changedAttributes, - createSnapshot, - flushChangedAttributes, - hasChangedAttributes, - materializeRecord, - new_InternalModel, - send, - setupData, - transitionTo, - updateChangedAttributes, -} = heimdall.registerMonitor( - 'InternalModel', - '_triggerDeferredTriggers', - 'changedAttributes', - 'createSnapshot', - 'flushChangedAttributes', - 'hasChangedAttributes', - 'materializeRecord', - 'new_InternalModel', - 'send', - 'setupData', - 'transitionTo', - 'updateChangedAttributes' -); - -let InternalModelReferenceId = 1; -let nextBfsId = 1; - -/* - `InternalModel` is the Model class that we use internally inside Ember Data to represent models. - Internal ED methods should only deal with `InternalModel` objects. It is a fast, plain Javascript class. - - We expose `DS.Model` to application code, by materializing a `DS.Model` from `InternalModel` lazily, as - a performance optimization. - - `InternalModel` should never be exposed to application code. At the boundaries of the system, in places - like `find`, `push`, etc. we convert between Models and InternalModels. - - We need to make sure that the properties from `InternalModel` are correctly exposed/proxied on `Model` - if they are needed. - - @private - @class InternalModel -*/ -export default class InternalModel { - constructor(modelName, id, store, data) { - heimdall.increment(new_InternalModel); - this.id = id; - - // this ensure ordered set can quickly identify this as unique - this[Ember.GUID_KEY] = InternalModelReferenceId++ + 'internal-model'; - - this.store = store; - this.modelName = modelName; - this._promiseProxy = null; - this._record = null; - this._isDestroyed = false; - this.isError = false; - this._pendingRecordArrayManagerFlush = false; // used by the recordArrayManager - - // During dematerialization we don't want to rematerialize the record. The - // reason this might happen is that dematerialization removes records from - // record arrays, and Ember arrays will always `objectAt(0)` and - // `objectAt(len - 1)` to test whether or not `firstObject` or `lastObject` - // have changed. - this._isDematerializing = false; - this._scheduledDestroy = null; - - this.resetRecord(); - - if (data) { - this.__data = data; - } - - // caches for lazy getters - this._modelClass = null; - this.__deferredTriggers = null; - this.__recordArrays = null; - this._references = null; - this._recordReference = null; - this.__relationships = null; - this.__implicitRelationships = null; - - // Used during the mark phase of unloading to avoid checking the same internal - // model twice in the same scan - this._bfsId = 0; - } - - get modelClass() { - return this._modelClass || (this._modelClass = this.store.modelFor(this.modelName)); - } - - get type() { - return this.modelClass; - } - - get recordReference() { - if (this._recordReference === null) { - this._recordReference = new RecordReference(this.store, this); - } - return this._recordReference; - } - - get _recordArrays() { - if (this.__recordArrays === null) { - this.__recordArrays = new OrderedSet(); - } - return this.__recordArrays; - } - - get references() { - if (this._references === null) { - this._references = Object.create(null); - } - return this._references; - } - - get _deferredTriggers() { - if (this.__deferredTriggers === null) { - this.__deferredTriggers = []; - } - return this.__deferredTriggers; - } - - get _attributes() { - if (this.__attributes === null) { - this.__attributes = Object.create(null); - } - return this.__attributes; - } - - set _attributes(v) { - this.__attributes = v; - } - - get _relationships() { - if (this.__relationships === null) { - this.__relationships = new Relationships(this); - } - - return this.__relationships; - } - - get _inFlightAttributes() { - if (this.__inFlightAttributes === null) { - this.__inFlightAttributes = Object.create(null); - } - return this.__inFlightAttributes; - } - - set _inFlightAttributes(v) { - this.__inFlightAttributes = v; - } - - get _data() { - if (this.__data === null) { - this.__data = Object.create(null); - } - return this.__data; - } - - set _data(v) { - this.__data = v; - } - - /* - implicit relationships are relationship which have not been declared but the inverse side exists on - another record somewhere - For example if there was - - ```app/models/comment.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - name: DS.attr() - }) - ``` - - but there is also - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - name: DS.attr(), - comments: DS.hasMany('comment') - }) - ``` - - would have a implicit post relationship in order to be do things like remove ourselves from the post - when we are deleted - */ - get _implicitRelationships() { - if (this.__implicitRelationships === null) { - this.__implicitRelationships = Object.create(null); - } - return this.__implicitRelationships; - } - - isHiddenFromRecordArrays() { - // During dematerialization we don't want to rematerialize the record. - // recordWasDeleted can cause other records to rematerialize because it - // removes the internal model from the array and Ember arrays will always - // `objectAt(0)` and `objectAt(len -1)` to check whether `firstObject` or - // `lastObject` have changed. When this happens we don't want those - // models to rematerialize their records. - - return ( - this._isDematerializing || - this.hasScheduledDestroy() || - this.isDestroyed || - this.currentState.stateName === 'root.deleted.saved' || - this.isEmpty() - ); - } - - isEmpty() { - return this.currentState.isEmpty; - } - - isLoading() { - return this.currentState.isLoading; - } - - isLoaded() { - return this.currentState.isLoaded; - } - - hasDirtyAttributes() { - return this.currentState.hasDirtyAttributes; - } - - isSaving() { - return this.currentState.isSaving; - } - - isDeleted() { - return this.currentState.isDeleted; - } - - isNew() { - return this.currentState.isNew; - } - - isValid() { - return this.currentState.isValid; - } - - dirtyType() { - return this.currentState.dirtyType; - } - - getRecord(properties) { - if (!this._record && !this._isDematerializing) { - heimdall.increment(materializeRecord); - let token = heimdall.start('InternalModel.getRecord'); - - // lookupFactory should really return an object that creates - // instances with the injections applied - let createOptions = { - store: this.store, - _internalModel: this, - currentState: this.currentState, - isError: this.isError, - adapterError: this.error, - }; - - if (properties !== undefined) { - assert( - `You passed '${properties}' as properties for record creation instead of an object.`, - typeof properties === 'object' && properties !== null - ); - let classFields = this.getFields(); - let relationships = this._relationships; - let propertyNames = Object.keys(properties); - - for (let i = 0; i < propertyNames.length; i++) { - let name = propertyNames[i]; - let fieldType = classFields.get(name); - let propertyValue = properties[name]; - - if (name === 'id') { - this.setId(propertyValue); - continue; - } - - switch (fieldType) { - case 'attribute': - this.setDirtyAttribute(name, propertyValue); - break; - case 'belongsTo': - this.setDirtyBelongsTo(name, propertyValue); - relationships.get(name).setHasAnyRelationshipData(true); - relationships.get(name).setRelationshipIsEmpty(false); - break; - case 'hasMany': - this.setDirtyHasMany(name, propertyValue); - relationships.get(name).setHasAnyRelationshipData(true); - relationships.get(name).setRelationshipIsEmpty(false); - break; - default: - createOptions[name] = propertyValue; - } - } - } - - if (setOwner) { - // ensure that `getOwner(this)` works inside a model instance - setOwner(createOptions, getOwner(this.store)); - } else { - createOptions.container = this.store.container; - } - - this._record = this.store._modelFactoryFor(this.modelName).create(createOptions); - - this._triggerDeferredTriggers(); - heimdall.stop(token); - } - - return this._record; - } - - getFields() { - return get(this.modelClass, 'fields'); - } - - resetRecord() { - this._record = null; - this.isReloading = false; - this.error = null; - this.currentState = RootState.empty; - this.__attributes = null; - this.__inFlightAttributes = null; - this._data = null; - } - - dematerializeRecord() { - this._isDematerializing = true; - - if (this._record) { - this._record.destroy(); - } - - // move to an empty never-loaded state - this.destroyRelationships(); - this.resetRecord(); - this.updateRecordArrays(); - } - - deleteRecord() { - this.send('deleteRecord'); - } - - save(options) { - let promiseLabel = 'DS: Model#save ' + this; - let resolver = RSVP.defer(promiseLabel); - - this.store.scheduleSave(this, resolver, options); - return resolver.promise; - } - - startedReloading() { - this.isReloading = true; - if (this.hasRecord) { - set(this._record, 'isReloading', true); - } - } - - finishedReloading() { - this.isReloading = false; - if (this.hasRecord) { - set(this._record, 'isReloading', false); - } - } - - reload(options) { - this.startedReloading(); - let internalModel = this; - let promiseLabel = 'DS: Model#reload of ' + this; - - return new Promise(function(resolve) { - internalModel.send('reloadRecord', { resolve, options }); - }, promiseLabel) - .then( - function() { - internalModel.didCleanError(); - return internalModel; - }, - function(error) { - internalModel.didError(error); - throw error; - }, - 'DS: Model#reload complete, update flags' - ) - .finally(function() { - internalModel.finishedReloading(); - internalModel.updateRecordArrays(); - }); - } - - /* - Computes the set of internal models reachable from `this` across exactly one - relationship. - - @return {Array} An array containing the internal models that `this` belongs - to or has many. - */ - _directlyRelatedInternalModels() { - let array = []; - - this._relationships.forEach((name, rel) => { - array = array.concat(rel.members.list, rel.canonicalMembers.list); - }); - return array; - } - - /* - Computes the set of internal models reachable from this internal model. - - Reachability is determined over the relationship graph (ie a graph where - nodes are internal models and edges are belongs to or has many - relationships). - - @return {Array} An array including `this` and all internal models reachable - from `this`. - */ - _allRelatedInternalModels() { - let array = []; - let queue = []; - let bfsId = nextBfsId++; - queue.push(this); - this._bfsId = bfsId; - while (queue.length > 0) { - let node = queue.shift(); - array.push(node); - let related = node._directlyRelatedInternalModels(); - for (let i = 0; i < related.length; ++i) { - let internalModel = related[i]; - assert('Internal Error: seen a future bfs iteration', internalModel._bfsId <= bfsId); - if (internalModel._bfsId < bfsId) { - queue.push(internalModel); - internalModel._bfsId = bfsId; - } - } - } - return array; - } - - /* - Unload the record for this internal model. This will cause the record to be - destroyed and freed up for garbage collection. It will also do a check - for cleaning up internal models. - - This check is performed by first computing the set of related internal - models. If all records in this set are unloaded, then the entire set is - destroyed. Otherwise, nothing in the set is destroyed. - - This means that this internal model will be freed up for garbage collection - once all models that refer to it via some relationship are also unloaded. - */ - unloadRecord() { - if (this.isDestroyed) { - return; - } - this.send('unloadRecord'); - this.dematerializeRecord(); - - if (this._scheduledDestroy === null) { - this._scheduledDestroy = run.backburner.schedule( - 'destroy', - this, - '_checkForOrphanedInternalModels' - ); - } - } - - hasScheduledDestroy() { - return !!this._scheduledDestroy; - } - - cancelDestroy() { - assert( - `You cannot cancel the destruction of an InternalModel once it has already been destroyed`, - !this.isDestroyed - ); - - this._isDematerializing = false; - run.cancel(this._scheduledDestroy); - this._scheduledDestroy = null; - } - - // typically, we prefer to async destroy this lets us batch cleanup work. - // Unfortunately, some scenarios where that is not possible. Such as: - // - // ```js - // const record = store.find(‘record’, 1); - // record.unloadRecord(); - // store.createRecord(‘record’, 1); - // ``` - // - // In those scenarios, we make that model's cleanup work, sync. - // - destroySync() { - if (this._isDematerializing) { - this.cancelDestroy(); - } - this._checkForOrphanedInternalModels(); - if (this.isDestroyed || this.isDestroying) { - return; - } - - // just in-case we are not one of the orphaned, we should still - // still destroy ourselves - this.destroy(); - } - - _checkForOrphanedInternalModels() { - this._isDematerializing = false; - this._scheduledDestroy = null; - if (this.isDestroyed) { - return; - } - - this._cleanupOrphanedInternalModels(); - } - - _cleanupOrphanedInternalModels() { - let relatedInternalModels = this._allRelatedInternalModels(); - if (areAllModelsUnloaded(relatedInternalModels)) { - for (let i = 0; i < relatedInternalModels.length; ++i) { - let internalModel = relatedInternalModels[i]; - if (!internalModel.isDestroyed) { - internalModel.destroy(); - } - } - } - } - - eachRelationship(callback, binding) { - return this.modelClass.eachRelationship(callback, binding); - } - - destroy() { - assert( - 'Cannot destroy an internalModel while its record is materialized', - !this._record || this._record.get('isDestroyed') || this._record.get('isDestroying') - ); - this.isDestroying = true; - this.store._internalModelDestroyed(this); - - this._relationships.forEach((name, rel) => rel.destroy()); - - this._isDestroyed = true; - } - - eachAttribute(callback, binding) { - return this.modelClass.eachAttribute(callback, binding); - } - - inverseFor(key) { - return this.modelClass.inverseFor(key); - } - - setupData(data) { - heimdall.increment(setupData); - this.store._internalModelDidReceiveRelationshipData( - this.modelName, - this.id, - data.relationships - ); - - let changedKeys; - - if (this.hasRecord) { - changedKeys = this._changedKeys(data.attributes); - } - - assign(this._data, data.attributes); - this.pushedData(); - - if (this.hasRecord) { - this._record._notifyProperties(changedKeys); - } - } - - getAttributeValue(key) { - if (key in this._attributes) { - return this._attributes[key]; - } else if (key in this._inFlightAttributes) { - return this._inFlightAttributes[key]; - } else { - return this._data[key]; - } - } - - setDirtyHasMany(key, records) { - assert(`You must pass an array of records to set a hasMany relationship`, isArrayLike(records)); - assert( - `All elements of a hasMany relationship must be instances of DS.Model, you passed ${inspect( - records - )}`, - (function() { - return A(records).every(record => record.hasOwnProperty('_internalModel') === true); - })() - ); - - let relationship = this._relationships.get(key); - relationship.clear(); - relationship.addInternalModels(records.map(record => get(record, '_internalModel'))); - } - - setDirtyBelongsTo(key, value) { - if (value === undefined) { - value = null; - } - if (value && value.then) { - this._relationships.get(key).setRecordPromise(value); - } else if (value) { - this._relationships.get(key).setInternalModel(value._internalModel); - } else { - this._relationships.get(key).setInternalModel(value); - } - } - - setDirtyAttribute(key, value) { - if (this.isDeleted()) { - throw new EmberError(`Attempted to set '${key}' to '${value}' on the deleted record ${this}`); - } - - let oldValue = this.getAttributeValue(key); - let originalValue; - - if (value !== oldValue) { - // Add the new value to the changed attributes hash; it will get deleted by - // the 'didSetProperty' handler if it is no different from the original value - this._attributes[key] = value; - - if (key in this._inFlightAttributes) { - originalValue = this._inFlightAttributes[key]; - } else { - originalValue = this._data[key]; - } - - this.send('didSetProperty', { - name: key, - oldValue: oldValue, - originalValue: originalValue, - value: value, - }); - } - - return value; - } - - get isDestroyed() { - return this._isDestroyed; - } - - get hasRecord() { - return !!this._record; - } - - /* - @method createSnapshot - @private - */ - createSnapshot(options) { - heimdall.increment(createSnapshot); - return new Snapshot(this, options); - } - - /* - @method loadingData - @private - @param {Promise} promise - */ - loadingData(promise) { - this.send('loadingData', promise); - } - - /* - @method loadedData - @private - */ - loadedData() { - this.send('loadedData'); - } - - /* - @method notFound - @private - */ - notFound() { - this.send('notFound'); - } - - /* - @method pushedData - @private - */ - pushedData() { - this.send('pushedData'); - } - - flushChangedAttributes() { - heimdall.increment(flushChangedAttributes); - this._inFlightAttributes = this._attributes; - this._attributes = null; - } - - hasChangedAttributes() { - heimdall.increment(hasChangedAttributes); - return this.__attributes !== null && Object.keys(this.__attributes).length > 0; - } - - /* - Checks if the attributes which are considered as changed are still - different to the state which is acknowledged by the server. - - This method is needed when data for the internal model is pushed and the - pushed data might acknowledge dirty attributes as confirmed. - - @method updateChangedAttributes - @private - */ - updateChangedAttributes() { - heimdall.increment(updateChangedAttributes); - let changedAttributes = this.changedAttributes(); - let changedAttributeNames = Object.keys(changedAttributes); - let attrs = this._attributes; - - for (let i = 0, length = changedAttributeNames.length; i < length; i++) { - let attribute = changedAttributeNames[i]; - let data = changedAttributes[attribute]; - let oldData = data[0]; - let newData = data[1]; - - if (oldData === newData) { - delete attrs[attribute]; - } - } - } - - /* - Returns an object, whose keys are changed properties, and value is an - [oldProp, newProp] array. - - @method changedAttributes - @private - */ - changedAttributes() { - heimdall.increment(changedAttributes); - let oldData = this._data; - let currentData = this._attributes; - let inFlightData = this._inFlightAttributes; - let newData = assign({}, inFlightData, currentData); - let diffData = Object.create(null); - let newDataKeys = Object.keys(newData); - - for (let i = 0, length = newDataKeys.length; i < length; i++) { - let key = newDataKeys[i]; - diffData[key] = [oldData[key], newData[key]]; - } - - return diffData; - } - - /* - @method adapterWillCommit - @private - */ - adapterWillCommit() { - this.send('willCommit'); - } - - /* - @method adapterDidDirty - @private - */ - adapterDidDirty() { - this.send('becomeDirty'); - this.updateRecordArrays(); - } - - /* - @method send - @private - @param {String} name - @param {Object} context - */ - send(name, context) { - heimdall.increment(send); - let currentState = this.currentState; - - if (!currentState[name]) { - this._unhandledEvent(currentState, name, context); - } - - return currentState[name](this, context); - } - - notifyHasManyAdded(key, record, idx) { - if (this.hasRecord) { - this._record.notifyHasManyAdded(key, record, idx); - } - } - - notifyBelongsToChange(key, record) { - if (this.hasRecord) { - this._record.notifyBelongsToChange(key, record); - } - } - - notifyPropertyChange(key) { - if (this.hasRecord) { - this._record.notifyPropertyChange(key); - } - } - - rollbackAttributes() { - let dirtyKeys; - if (this.hasChangedAttributes()) { - dirtyKeys = Object.keys(this._attributes); - this._attributes = null; - } - - if (get(this, 'isError')) { - this._inFlightAttributes = null; - this.didCleanError(); - } - - if (this.isNew()) { - this.removeFromInverseRelationships(); - } - - if (this.isValid()) { - this._inFlightAttributes = null; - } - - this.send('rolledBack'); - - if (dirtyKeys && dirtyKeys.length > 0) { - this._record._notifyProperties(dirtyKeys); - } - } - - /* - @method transitionTo - @private - @param {String} name - */ - transitionTo(name) { - heimdall.increment(transitionTo); - // POSSIBLE TODO: Remove this code and replace with - // always having direct reference to state objects - - let pivotName = extractPivotName(name); - let state = this.currentState; - let transitionMapId = `${state.stateName}->${name}`; - - do { - if (state.exit) { - state.exit(this); - } - state = state.parentState; - } while (!state[pivotName]); - - let setups; - let enters; - let i; - let l; - let map = TransitionChainMap[transitionMapId]; - - if (map) { - setups = map.setups; - enters = map.enters; - state = map.state; - } else { - setups = []; - enters = []; - - let path = splitOnDot(name); - - for (i = 0, l = path.length; i < l; i++) { - state = state[path[i]]; - - if (state.enter) { - enters.push(state); - } - if (state.setup) { - setups.push(state); - } - } - - TransitionChainMap[transitionMapId] = { setups, enters, state }; - } - - for (i = 0, l = enters.length; i < l; i++) { - enters[i].enter(this); - } - - this.currentState = state; - if (this.hasRecord) { - set(this._record, 'currentState', state); - } - - for (i = 0, l = setups.length; i < l; i++) { - setups[i].setup(this); - } - - this.updateRecordArrays(); - } - - _unhandledEvent(state, name, context) { - let errorMessage = 'Attempted to handle event `' + name + '` '; - errorMessage += 'on ' + String(this) + ' while in state '; - errorMessage += state.stateName + '. '; - - if (context !== undefined) { - errorMessage += 'Called with ' + inspect(context) + '.'; - } - - throw new EmberError(errorMessage); - } - - triggerLater(...args) { - if (this._deferredTriggers.push(args) !== 1) { - return; - } - - this.store._updateInternalModel(this); - } - - _triggerDeferredTriggers() { - heimdall.increment(_triggerDeferredTriggers); - //TODO: Before 1.0 we want to remove all the events that happen on the pre materialized record, - //but for now, we queue up all the events triggered before the record was materialized, and flush - //them once we have the record - if (!this.hasRecord) { - return; - } - let triggers = this._deferredTriggers; - let record = this._record; - let trigger = record.trigger; - for (let i = 0, l = triggers.length; i < l; i++) { - trigger.apply(record, triggers[i]); - } - - triggers.length = 0; - } - - /* - This method should only be called by records in the `isNew()` state OR once the record - has been deleted and that deletion has been persisted. - - It will remove this record from any associated relationships. - - @method removeFromInverseRelationships - @private - */ - removeFromInverseRelationships() { - this._relationships.forEach((name, rel) => { - rel.removeCompletelyFromInverse(); - rel.clear(); - }); - - let implicitRelationships = this._implicitRelationships; - this.__implicitRelationships = null; - - Object.keys(implicitRelationships).forEach(key => { - let rel = implicitRelationships[key]; - - rel.removeCompletelyFromInverse(); - rel.clear(); - }); - } - - /* - Notify all inverses that this internalModel has been dematerialized - and destroys any ManyArrays. - */ - destroyRelationships() { - let relationships = this._relationships; - relationships.forEach((name, rel) => destroyRelationship(rel)); - - let implicitRelationships = this._implicitRelationships; - this.__implicitRelationships = null; - Object.keys(implicitRelationships).forEach(key => { - let rel = implicitRelationships[key]; - destroyRelationship(rel); - }); - } - - /* - When a find request is triggered on the store, the user can optionally pass in - attributes and relationships to be preloaded. These are meant to behave as if they - came back from the server, except the user obtained them out of band and is informing - the store of their existence. The most common use case is for supporting client side - nested URLs, such as `/posts/1/comments/2` so the user can do - `store.findRecord('comment', 2, { preload: { post: 1 } })` without having to fetch the post. - - Preloaded data can be attributes and relationships passed in either as IDs or as actual - models. - - @method preloadData - @private - @param {Object} preload - */ - preloadData(preload) { - //TODO(Igor) consider the polymorphic case - Object.keys(preload).forEach(key => { - let preloadValue = get(preload, key); - let relationshipMeta = this.modelClass.metaForProperty(key); - if (relationshipMeta.isRelationship) { - this._preloadRelationship(key, preloadValue); - } else { - this._data[key] = preloadValue; - } - }); - } - - _preloadRelationship(key, preloadValue) { - let relationshipMeta = this.modelClass.metaForProperty(key); - let modelClass = relationshipMeta.type; - if (relationshipMeta.kind === 'hasMany') { - this._preloadHasMany(key, preloadValue, modelClass); - } else { - this._preloadBelongsTo(key, preloadValue, modelClass); - } - } - - _preloadHasMany(key, preloadValue, modelClass) { - assert( - 'You need to pass in an array to set a hasMany property on a record', - Array.isArray(preloadValue) - ); - let recordsToSet = new Array(preloadValue.length); - - for (let i = 0; i < preloadValue.length; i++) { - let recordToPush = preloadValue[i]; - recordsToSet[i] = this._convertStringOrNumberIntoInternalModel(recordToPush, modelClass); - } - - //We use the pathway of setting the hasMany as if it came from the adapter - //because the user told us that they know this relationships exists already - this._relationships.get(key).updateInternalModelsFromAdapter(recordsToSet); - } - - _preloadBelongsTo(key, preloadValue, modelClass) { - let internalModelToSet = this._convertStringOrNumberIntoInternalModel(preloadValue, modelClass); - - //We use the pathway of setting the hasMany as if it came from the adapter - //because the user told us that they know this relationships exists already - this._relationships.get(key).setInternalModel(internalModelToSet); - } - - _convertStringOrNumberIntoInternalModel(value, modelClass) { - if (typeof value === 'string' || typeof value === 'number') { - return this.store._internalModelForId(modelClass, value); - } - if (value._internalModel) { - return value._internalModel; - } - return value; - } - - /* - Used to notify the store to update FilteredRecordArray membership. - - @method updateRecordArrays - @private - */ - updateRecordArrays() { - this.store.recordArrayManager.recordDidChange(this); - } - - setId(id) { - assert( - "A record's id cannot be changed once it is in the loaded state", - this.id === null || this.id === id || this.isNew() - ); - let didChange = id !== this.id; - this.id = id; - - if (didChange && this.hasRecord) { - this._record.notifyPropertyChange('id'); - } - } - - didError(error) { - this.error = error; - this.isError = true; - - if (this.hasRecord) { - this._record.setProperties({ - isError: true, - adapterError: error, - }); - } - } - - didCleanError() { - this.error = null; - this.isError = false; - - if (this.hasRecord) { - this._record.setProperties({ - isError: false, - adapterError: null, - }); - } - } - - /* - If the adapter did not return a hash in response to a commit, - merge the changed attributes and relationships into the existing - saved data. - - @method adapterDidCommit - */ - adapterDidCommit(data) { - if (data) { - this.store._internalModelDidReceiveRelationshipData( - this.modelName, - this.id, - data.relationships - ); - - data = data.attributes; - } - - this.didCleanError(); - let changedKeys = this._changedKeys(data); - - assign(this._data, this._inFlightAttributes); - if (data) { - assign(this._data, data); - } - - this._inFlightAttributes = null; - - this.send('didCommit'); - this.updateRecordArrays(); - - if (!data) { - return; - } - - this._record._notifyProperties(changedKeys); - } - - addErrorMessageToAttribute(attribute, message) { - get(this.getRecord(), 'errors')._add(attribute, message); - } - - removeErrorMessageFromAttribute(attribute) { - get(this.getRecord(), 'errors')._remove(attribute); - } - - clearErrorMessages() { - get(this.getRecord(), 'errors')._clear(); - } - - hasErrors() { - let errors = get(this.getRecord(), 'errors'); - - return errors.get('length') > 0; - } - - // FOR USE DURING COMMIT PROCESS - - /* - @method adapterDidInvalidate - @private - */ - adapterDidInvalidate(errors) { - let attribute; - - for (attribute in errors) { - if (errors.hasOwnProperty(attribute)) { - this.addErrorMessageToAttribute(attribute, errors[attribute]); - } - } - - this.send('becameInvalid'); - - this._saveWasRejected(); - } - - /* - @method adapterDidError - @private - */ - adapterDidError(error) { - this.send('becameError'); - this.didError(error); - this._saveWasRejected(); - } - - _saveWasRejected() { - let keys = Object.keys(this._inFlightAttributes); - if (keys.length > 0) { - let attrs = this._attributes; - for (let i = 0; i < keys.length; i++) { - if (attrs[keys[i]] === undefined) { - attrs[keys[i]] = this._inFlightAttributes[keys[i]]; - } - } - } - this._inFlightAttributes = null; - } - - /* - Ember Data has 3 buckets for storing the value of an attribute on an internalModel. - - `_data` holds all of the attributes that have been acknowledged by - a backend via the adapter. When rollbackAttributes is called on a model all - attributes will revert to the record's state in `_data`. - - `_attributes` holds any change the user has made to an attribute - that has not been acknowledged by the adapter. Any values in - `_attributes` are have priority over values in `_data`. - - `_inFlightAttributes`. When a record is being synced with the - backend the values in `_attributes` are copied to - `_inFlightAttributes`. This way if the backend acknowledges the - save but does not return the new state Ember Data can copy the - values from `_inFlightAttributes` to `_data`. Without having to - worry about changes made to `_attributes` while the save was - happenign. - - - Changed keys builds a list of all of the values that may have been - changed by the backend after a successful save. - - It does this by iterating over each key, value pair in the payload - returned from the server after a save. If the `key` is found in - `_attributes` then the user has a local changed to the attribute - that has not been synced with the server and the key is not - included in the list of changed keys. - - - - If the value, for a key differs from the value in what Ember Data - believes to be the truth about the backend state (A merger of the - `_data` and `_inFlightAttributes` objects where - `_inFlightAttributes` has priority) then that means the backend - has updated the value and the key is added to the list of changed - keys. - - @method _changedKeys - @private - */ - _changedKeys(updates) { - let changedKeys = []; - - if (updates) { - let original, i, value, key; - let keys = Object.keys(updates); - let length = keys.length; - let hasAttrs = this.hasChangedAttributes(); - let attrs; - if (hasAttrs) { - attrs = this._attributes; - } - - original = Object.create(null); - assign(original, this._data, this._inFlightAttributes); - - for (i = 0; i < length; i++) { - key = keys[i]; - value = updates[key]; - - // A value in _attributes means the user has a local change to - // this attributes. We never override this value when merging - // updates from the backend so we should not sent a change - // notification if the server value differs from the original. - if (hasAttrs === true && attrs[key] !== undefined) { - continue; - } - - if (!isEqual(original[key], value)) { - changedKeys.push(key); - } - } - } - - return changedKeys; - } - - toString() { - return `<${this.modelName}:${this.id}>`; - } - - referenceFor(kind, name) { - let reference = this.references[name]; - - if (!reference) { - let relationship = this._relationships.get(name); - - if (DEBUG) { - let modelName = this.modelName; - assert( - `There is no ${kind} relationship named '${name}' on a model of modelClass '${modelName}'`, - relationship - ); - - let actualRelationshipKind = relationship.relationshipMeta.kind; - assert( - `You tried to get the '${name}' relationship on a '${modelName}' via record.${kind}('${name}'), but the relationship is of kind '${actualRelationshipKind}'. Use record.${actualRelationshipKind}('${name}') instead.`, - actualRelationshipKind === kind - ); - } - - if (kind === 'belongsTo') { - reference = new BelongsToReference(this.store, this, relationship); - } else if (kind === 'hasMany') { - reference = new HasManyReference(this.store, this, relationship); - } - - this.references[name] = reference; - } - - return reference; - } -} diff --git a/addon/-legacy-private/system/model/model.js b/addon/-legacy-private/system/model/model.js deleted file mode 100644 index b6218147c56..00000000000 --- a/addon/-legacy-private/system/model/model.js +++ /dev/null @@ -1,1994 +0,0 @@ -import ComputedProperty from '@ember/object/computed'; -import { isNone } from '@ember/utils'; -import EmberError from '@ember/error'; -import Evented from '@ember/object/evented'; -import EmberObject, { computed, get } from '@ember/object'; -import Map from '../map'; -import { DEBUG } from '@glimmer/env'; -import { assert, warn } from '@ember/debug'; -import { PromiseObject } from '../promise-proxies'; -import Errors from '../model/errors'; -import RootState from '../model/states'; -import { - relationshipsByNameDescriptor, - relatedTypesDescriptor, - relationshipsDescriptor, -} from '../relationships/ext'; - -import Ember from 'ember'; -const { changeProperties } = Ember; - -/** - @module ember-data -*/ - -function findPossibleInverses(type, inverseType, name, relationshipsSoFar) { - let possibleRelationships = relationshipsSoFar || []; - - let relationshipMap = get(inverseType, 'relationships'); - if (!relationshipMap) { - return possibleRelationships; - } - - let relationships = relationshipMap.get(type.modelName).filter(relationship => { - let optionsForRelationship = inverseType.metaForProperty(relationship.name).options; - - if (!optionsForRelationship.inverse && optionsForRelationship.inverse !== null) { - return true; - } - - return name === optionsForRelationship.inverse; - }); - - if (relationships) { - possibleRelationships.push.apply(possibleRelationships, relationships); - } - - //Recurse to support polymorphism - if (type.superclass) { - findPossibleInverses(type.superclass, inverseType, name, possibleRelationships); - } - - return possibleRelationships; -} - -function intersection(array1, array2) { - let result = []; - array1.forEach(element => { - if (array2.indexOf(element) >= 0) { - result.push(element); - } - }); - - return result; -} - -const RESERVED_MODEL_PROPS = ['currentState', 'data', 'store']; - -const retrieveFromCurrentState = computed('currentState', function(key) { - return get(this._internalModel.currentState, key); -}).readOnly(); - -/** - - The model class that all Ember Data records descend from. - This is the public API of Ember Data models. If you are using Ember Data - in your application, this is the class you should use. - If you are working on Ember Data internals, you most likely want to be dealing - with `InternalModel` - - @class Model - @namespace DS - @extends Ember.Object - @uses Ember.Evented -*/ -const Model = EmberObject.extend(Evented, { - _internalModel: null, - store: null, - __defineNonEnumerable(property) { - this[property.name] = property.descriptor.value; - }, - - /** - If this property is `true` the record is in the `empty` - state. Empty is the first state all records enter after they have - been created. Most records created by the store will quickly - transition to the `loading` state if data needs to be fetched from - the server or the `created` state if the record is created on the - client. A record can also enter the empty state if the adapter is - unable to locate the record. - - @property isEmpty - @type {Boolean} - @readOnly - */ - isEmpty: retrieveFromCurrentState, - /** - If this property is `true` the record is in the `loading` state. A - record enters this state when the store asks the adapter for its - data. It remains in this state until the adapter provides the - requested data. - - @property isLoading - @type {Boolean} - @readOnly - */ - isLoading: retrieveFromCurrentState, - /** - If this property is `true` the record is in the `loaded` state. A - record enters this state when its data is populated. Most of a - record's lifecycle is spent inside substates of the `loaded` - state. - - Example - - ```javascript - let record = store.createRecord('model'); - record.get('isLoaded'); // true - - store.findRecord('model', 1).then(function(model) { - model.get('isLoaded'); // true - }); - ``` - - @property isLoaded - @type {Boolean} - @readOnly - */ - isLoaded: retrieveFromCurrentState, - /** - If this property is `true` the record is in the `dirty` state. The - record has local changes that have not yet been saved by the - adapter. This includes records that have been created (but not yet - saved) or deleted. - - Example - - ```javascript - let record = store.createRecord('model'); - record.get('hasDirtyAttributes'); // true - - store.findRecord('model', 1).then(function(model) { - model.get('hasDirtyAttributes'); // false - model.set('foo', 'some value'); - model.get('hasDirtyAttributes'); // true - }); - ``` - - @since 1.13.0 - @property hasDirtyAttributes - @type {Boolean} - @readOnly - */ - hasDirtyAttributes: computed('currentState.isDirty', function() { - return this.get('currentState.isDirty'); - }), - /** - If this property is `true` the record is in the `saving` state. A - record enters the saving state when `save` is called, but the - adapter has not yet acknowledged that the changes have been - persisted to the backend. - - Example - - ```javascript - let record = store.createRecord('model'); - record.get('isSaving'); // false - let promise = record.save(); - record.get('isSaving'); // true - promise.then(function() { - record.get('isSaving'); // false - }); - ``` - - @property isSaving - @type {Boolean} - @readOnly - */ - isSaving: retrieveFromCurrentState, - /** - If this property is `true` the record is in the `deleted` state - and has been marked for deletion. When `isDeleted` is true and - `hasDirtyAttributes` is true, the record is deleted locally but the deletion - was not yet persisted. When `isSaving` is true, the change is - in-flight. When both `hasDirtyAttributes` and `isSaving` are false, the - change has persisted. - - Example - - ```javascript - let record = store.createRecord('model'); - record.get('isDeleted'); // false - record.deleteRecord(); - - // Locally deleted - record.get('isDeleted'); // true - record.get('hasDirtyAttributes'); // true - record.get('isSaving'); // false - - // Persisting the deletion - let promise = record.save(); - record.get('isDeleted'); // true - record.get('isSaving'); // true - - // Deletion Persisted - promise.then(function() { - record.get('isDeleted'); // true - record.get('isSaving'); // false - record.get('hasDirtyAttributes'); // false - }); - ``` - - @property isDeleted - @type {Boolean} - @readOnly - */ - isDeleted: retrieveFromCurrentState, - /** - If this property is `true` the record is in the `new` state. A - record will be in the `new` state when it has been created on the - client and the adapter has not yet report that it was successfully - saved. - - Example - - ```javascript - let record = store.createRecord('model'); - record.get('isNew'); // true - - record.save().then(function(model) { - model.get('isNew'); // false - }); - ``` - - @property isNew - @type {Boolean} - @readOnly - */ - isNew: retrieveFromCurrentState, - /** - If this property is `true` the record is in the `valid` state. - - A record will be in the `valid` state when the adapter did not report any - server-side validation failures. - - @property isValid - @type {Boolean} - @readOnly - */ - isValid: retrieveFromCurrentState, - /** - If the record is in the dirty state this property will report what - kind of change has caused it to move into the dirty - state. Possible values are: - - - `created` The record has been created by the client and not yet saved to the adapter. - - `updated` The record has been updated by the client and not yet saved to the adapter. - - `deleted` The record has been deleted by the client and not yet saved to the adapter. - - Example - - ```javascript - let record = store.createRecord('model'); - record.get('dirtyType'); // 'created' - ``` - - @property dirtyType - @type {String} - @readOnly - */ - dirtyType: retrieveFromCurrentState, - - /** - If `true` the adapter reported that it was unable to save local - changes to the backend for any reason other than a server-side - validation error. - - Example - - ```javascript - record.get('isError'); // false - record.set('foo', 'valid value'); - record.save().then(null, function() { - record.get('isError'); // true - }); - ``` - - @property isError - @type {Boolean} - @readOnly - */ - isError: false, - - /** - If `true` the store is attempting to reload the record from the adapter. - - Example - - ```javascript - record.get('isReloading'); // false - record.reload(); - record.get('isReloading'); // true - ``` - - @property isReloading - @type {Boolean} - @readOnly - */ - isReloading: false, - - /** - All ember models have an id property. This is an identifier - managed by an external source. These are always coerced to be - strings before being used internally. Note when declaring the - attributes for a model it is an error to declare an id - attribute. - - ```javascript - let record = store.createRecord('model'); - record.get('id'); // null - - store.findRecord('model', 1).then(function(model) { - model.get('id'); // '1' - }); - ``` - - @property id - @type {String} - */ - - /** - @property currentState - @private - @type {Object} - */ - currentState: RootState.empty, - - /** - When the record is in the `invalid` state this object will contain - any errors returned by the adapter. When present the errors hash - contains keys corresponding to the invalid property names - and values which are arrays of Javascript objects with two keys: - - - `message` A string containing the error message from the backend - - `attribute` The name of the property associated with this error message - - ```javascript - record.get('errors.length'); // 0 - record.set('foo', 'invalid value'); - record.save().catch(function() { - record.get('errors').get('foo'); - // [{message: 'foo should be a number.', attribute: 'foo'}] - }); - ``` - - The `errors` property us useful for displaying error messages to - the user. - - ```handlebars - - {{#each model.errors.username as |error|}} -
      - {{error.message}} -
      - {{/each}} - - {{#each model.errors.email as |error|}} -
      - {{error.message}} -
      - {{/each}} - ``` - - - You can also access the special `messages` property on the error - object to get an array of all the error strings. - - ```handlebars - {{#each model.errors.messages as |message|}} -
      - {{message}} -
      - {{/each}} - ``` - - @property errors - @type {DS.Errors} - */ - errors: computed(function() { - let errors = Errors.create(); - - errors._registerHandlers( - this._internalModel, - function() { - this.send('becameInvalid'); - }, - function() { - this.send('becameValid'); - } - ); - return errors; - }).readOnly(), - - /** - This property holds the `DS.AdapterError` object with which - last adapter operation was rejected. - - @property adapterError - @type {DS.AdapterError} - */ - adapterError: null, - - /** - Create a JSON representation of the record, using the serialization - strategy of the store's adapter. - - `serialize` takes an optional hash as a parameter, currently - supported options are: - - - `includeId`: `true` if the record's ID should be included in the - JSON representation. - - @method serialize - @param {Object} options - @return {Object} an object whose values are primitive JSON values only - */ - serialize(options) { - return this._internalModel.createSnapshot().serialize(options); - }, - - /** - Use [DS.JSONSerializer](DS.JSONSerializer.html) to - get the JSON representation of a record. - - `toJSON` takes an optional hash as a parameter, currently - supported options are: - - - `includeId`: `true` if the record's ID should be included in the - JSON representation. - - @method toJSON - @param {Object} options - @return {Object} A JSON representation of the object. - */ - toJSON(options) { - // container is for lazy transform lookups - let serializer = this.store.serializerFor('-default'); - let snapshot = this._internalModel.createSnapshot(); - - return serializer.serialize(snapshot, options); - }, - - /** - Fired when the record is ready to be interacted with, - that is either loaded from the server or created locally. - - @event ready - */ - ready: null, - - /** - Fired when the record is loaded from the server. - - @event didLoad - */ - didLoad: null, - - /** - Fired when the record is updated. - - @event didUpdate - */ - didUpdate: null, - - /** - Fired when a new record is commited to the server. - - @event didCreate - */ - didCreate: null, - - /** - Fired when the record is deleted. - - @event didDelete - */ - didDelete: null, - - /** - Fired when the record becomes invalid. - - @event becameInvalid - */ - becameInvalid: null, - - /** - Fired when the record enters the error state. - - @event becameError - */ - becameError: null, - - /** - Fired when the record is rolled back. - - @event rolledBack - */ - rolledBack: null, - - //TODO Do we want to deprecate these? - /** - @method send - @private - @param {String} name - @param {Object} context - */ - send(name, context) { - return this._internalModel.send(name, context); - }, - - /** - @method transitionTo - @private - @param {String} name - */ - transitionTo(name) { - return this._internalModel.transitionTo(name); - }, - - /** - Marks the record as deleted but does not save it. You must call - `save` afterwards if you want to persist it. You might use this - method if you want to allow the user to still `rollbackAttributes()` - after a delete was made. - - Example - - ```app/routes/model/delete.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - actions: { - softDelete() { - this.get('controller.model').deleteRecord(); - }, - confirm() { - this.get('controller.model').save(); - }, - undo() { - this.get('controller.model').rollbackAttributes(); - } - } - }); - ``` - - @method deleteRecord - */ - deleteRecord() { - this._internalModel.deleteRecord(); - }, - - /** - Same as `deleteRecord`, but saves the record immediately. - - Example - - ```app/routes/model/delete.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - actions: { - delete() { - this.get('controller.model').destroyRecord().then(function() { - controller.transitionToRoute('model.index'); - }); - } - } - }); - ``` - - If you pass an object on the `adapterOptions` property of the options - argument it will be passed to your adapter via the snapshot - - ```js - record.destroyRecord({ adapterOptions: { subscribe: false } }); - ``` - - ```app/adapters/post.js - import MyCustomAdapter from './custom-adapter'; - - export default MyCustomAdapter.extend({ - deleteRecord(store, type, snapshot) { - if (snapshot.adapterOptions.subscribe) { - // ... - } - // ... - } - }); - ``` - - @method destroyRecord - @param {Object} options - @return {Promise} a promise that will be resolved when the adapter returns - successfully or rejected if the adapter returns with an error. - */ - destroyRecord(options) { - this.deleteRecord(); - return this.save(options); - }, - - /** - Unloads the record from the store. This will cause the record to be destroyed and freed up for garbage collection. - - @method unloadRecord - */ - unloadRecord() { - if (this.isDestroyed) { - return; - } - this._internalModel.unloadRecord(); - }, - - /** - @method _notifyProperties - @private - */ - _notifyProperties(keys) { - // changeProperties defers notifications until after the delegate - // and protects with a try...finally block - // previously used begin...endPropertyChanges but this is private API - changeProperties(() => { - let key; - for (let i = 0, length = keys.length; i < length; i++) { - key = keys[i]; - this.notifyPropertyChange(key); - } - }); - }, - - /** - Returns an object, whose keys are changed properties, and value is - an [oldProp, newProp] array. - - The array represents the diff of the canonical state with the local state - of the model. Note: if the model is created locally, the canonical state is - empty since the adapter hasn't acknowledged the attributes yet: - - Example - - ```app/models/mascot.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - name: DS.attr('string'), - isAdmin: DS.attr('boolean', { - defaultValue: false - }) - }); - ``` - - ```javascript - let mascot = store.createRecord('mascot'); - - mascot.changedAttributes(); // {} - - mascot.set('name', 'Tomster'); - mascot.changedAttributes(); // { name: [undefined, 'Tomster'] } - - mascot.set('isAdmin', true); - mascot.changedAttributes(); // { isAdmin: [undefined, true], name: [undefined, 'Tomster'] } - - mascot.save().then(function() { - mascot.changedAttributes(); // {} - - mascot.set('isAdmin', false); - mascot.changedAttributes(); // { isAdmin: [true, false] } - }); - ``` - - @method changedAttributes - @return {Object} an object, whose keys are changed properties, - and value is an [oldProp, newProp] array. - */ - changedAttributes() { - return this._internalModel.changedAttributes(); - }, - - //TODO discuss with tomhuda about events/hooks - //Bring back as hooks? - /** - @method adapterWillCommit - @private - adapterWillCommit: function() { - this.send('willCommit'); - }, - - /** - @method adapterDidDirty - @private - adapterDidDirty: function() { - this.send('becomeDirty'); - this.updateRecordArraysLater(); - }, - */ - - /** - If the model `hasDirtyAttributes` this function will discard any unsaved - changes. If the model `isNew` it will be removed from the store. - - Example - - ```javascript - record.get('name'); // 'Untitled Document' - record.set('name', 'Doc 1'); - record.get('name'); // 'Doc 1' - record.rollbackAttributes(); - record.get('name'); // 'Untitled Document' - ``` - - @since 1.13.0 - @method rollbackAttributes - */ - rollbackAttributes() { - this._internalModel.rollbackAttributes(); - }, - - /* - @method _createSnapshot - @private - */ - _createSnapshot() { - return this._internalModel.createSnapshot(); - }, - - toStringExtension() { - // the _internalModel guard exists, because some dev-only deprecation code - // (addListener via validatePropertyInjections) invokes toString before the - // object is real. - return this._internalModel && this._internalModel.id; - }, - - /** - Save the record and persist any changes to the record to an - external source via the adapter. - - Example - - ```javascript - record.set('name', 'Tomster'); - record.save().then(function() { - // Success callback - }, function() { - // Error callback - }); - ``` - - If you pass an object using the `adapterOptions` property of the options - argument it will be passed to your adapter via the snapshot. - - ```js - record.save({ adapterOptions: { subscribe: false } }); - ``` - - ```app/adapters/post.js - import MyCustomAdapter from './custom-adapter'; - - export default MyCustomAdapter.extend({ - updateRecord(store, type, snapshot) { - if (snapshot.adapterOptions.subscribe) { - // ... - } - // ... - } - }); - ``` - - @method save - @param {Object} options - @return {Promise} a promise that will be resolved when the adapter returns - successfully or rejected if the adapter returns with an error. - */ - save(options) { - return PromiseObject.create({ - promise: this._internalModel.save(options).then(() => this), - }); - }, - - /** - Reload the record from the adapter. - - This will only work if the record has already finished loading. - - Example - - ```app/routes/model/view.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - actions: { - reload() { - this.controller.get('model').reload().then(function(model) { - // do something with the reloaded model - }); - } - } - }); - ``` - - @method reload - @param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter request - - @return {Promise} a promise that will be resolved with the record when the - adapter returns successfully or rejected if the adapter returns - with an error. - */ - reload(options) { - let wrappedAdapterOptions; - - if (typeof options === 'object' && options !== null && options.adapterOptions) { - wrappedAdapterOptions = { - adapterOptions: options.adapterOptions, - }; - } - - return PromiseObject.create({ - promise: this._internalModel.reload(wrappedAdapterOptions).then(() => this), - }); - }, - - /** - Override the default event firing from Ember.Evented to - also call methods with the given name. - - @method trigger - @private - @param {String} name - */ - trigger(name) { - let fn = this[name]; - - if (typeof fn === 'function') { - let length = arguments.length; - let args = new Array(length - 1); - - for (let i = 1; i < length; i++) { - args[i - 1] = arguments[i]; - } - fn.apply(this, args); - } - - this._super(...arguments); - }, - - attr() { - assert( - 'The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected. Are you passing a DS.Model instead of a DS.Snapshot to your serializer?', - false - ); - }, - - /** - Get the reference for the specified belongsTo relationship. - - Example - - ```app/models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - ``` - - ```javascript - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - } - }); - let userRef = blog.belongsTo('user'); - - // check if the user relationship is loaded - let isLoaded = userRef.value() !== null; - - // get the record of the reference (null if not yet available) - let user = userRef.value(); - - // get the identifier of the reference - if (userRef.remoteType() === "id") { - let id = userRef.id(); - } else if (userRef.remoteType() === "link") { - let link = userRef.link(); - } - - // load user (via store.findRecord or store.findBelongsTo) - userRef.load().then(...) - - // or trigger a reload - userRef.reload().then(...) - - // provide data for reference - userRef.push({ - type: 'user', - id: 1, - attributes: { - username: "@user" - } - }).then(function(user) { - userRef.value() === user; - }); - ``` - - @method belongsTo - @param {String} name of the relationship - @since 2.5.0 - @return {BelongsToReference} reference for this relationship - */ - belongsTo(name) { - return this._internalModel.referenceFor('belongsTo', name); - }, - - /** - Get the reference for the specified hasMany relationship. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - comments: { - data: [ - { type: 'comment', id: 1 }, - { type: 'comment', id: 2 } - ] - } - } - } - }); - let commentsRef = blog.hasMany('comments'); - - // check if the comments are loaded already - let isLoaded = commentsRef.value() !== null; - - // get the records of the reference (null if not yet available) - let comments = commentsRef.value(); - - // get the identifier of the reference - if (commentsRef.remoteType() === "ids") { - let ids = commentsRef.ids(); - } else if (commentsRef.remoteType() === "link") { - let link = commentsRef.link(); - } - - // load comments (via store.findMany or store.findHasMany) - commentsRef.load().then(...) - - // or trigger a reload - commentsRef.reload().then(...) - - // provide data for reference - commentsRef.push([{ type: 'comment', id: 1 }, { type: 'comment', id: 2 }]).then(function(comments) { - commentsRef.value() === comments; - }); - ``` - - @method hasMany - @param {String} name of the relationship - @since 2.5.0 - @return {HasManyReference} reference for this relationship - */ - hasMany(name) { - return this._internalModel.referenceFor('hasMany', name); - }, - - /** - Provides info about the model for debugging purposes - by grouping the properties into more semantic groups. - - Meant to be used by debugging tools such as the Chrome Ember Extension. - - - Groups all attributes in "Attributes" group. - - Groups all belongsTo relationships in "Belongs To" group. - - Groups all hasMany relationships in "Has Many" group. - - Groups all flags in "Flags" group. - - Flags relationship CPs as expensive properties. - - @method _debugInfo - @for DS.Model - @private - */ - _debugInfo() { - let attributes = ['id']; - let relationships = {}; - let expensiveProperties = []; - - this.eachAttribute((name, meta) => attributes.push(name)); - - let groups = [ - { - name: 'Attributes', - properties: attributes, - expand: true, - }, - ]; - - this.eachRelationship((name, relationship) => { - let properties = relationships[relationship.kind]; - - if (properties === undefined) { - properties = relationships[relationship.kind] = []; - groups.push({ - name: relationship.name, - properties, - expand: true, - }); - } - properties.push(name); - expensiveProperties.push(name); - }); - - groups.push({ - name: 'Flags', - properties: [ - 'isLoaded', - 'hasDirtyAttributes', - 'isSaving', - 'isDeleted', - 'isError', - 'isNew', - 'isValid', - ], - }); - - return { - propertyInfo: { - // include all other mixins / properties (not just the grouped ones) - includeOtherProperties: true, - groups: groups, - // don't pre-calculate unless cached - expensiveProperties: expensiveProperties, - }, - }; - }, - - notifyBelongsToChange(key) { - this.notifyPropertyChange(key); - }, - /** - Given a callback, iterates over each of the relationships in the model, - invoking the callback with the name of each relationship and its relationship - descriptor. - - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, descriptor); - ``` - - - `name` the name of the current property in the iteration - - `descriptor` the meta object that describes this relationship - - The relationship descriptor argument is an object with the following properties. - - - **key** String the name of this relationship on the Model - - **kind** String "hasMany" or "belongsTo" - - **options** Object the original options hash passed when the relationship was declared - - **parentType** DS.Model the type of the Model that owns this relationship - - **type** String the type name of the related Model - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.JSONSerializer.extend({ - serialize: function(record, options) { - let json = {}; - - record.eachRelationship(function(name, descriptor) { - if (descriptor.kind === 'hasMany') { - let serializedHasManyName = name.toUpperCase() + '_IDS'; - json[serializedHasManyName] = record.get(name).mapBy('id'); - } - }); - - return json; - } - }); - ``` - - @method eachRelationship - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelationship(callback, binding) { - this.constructor.eachRelationship(callback, binding); - }, - - relationshipFor(name) { - return get(this.constructor, 'relationshipsByName').get(name); - }, - - inverseFor(key) { - return this.constructor.inverseFor(key, this.store); - }, - - notifyHasManyAdded(key) { - //We need to notifyPropertyChange in the adding case because we need to make sure - //we fetch the newly added record in case it is unloaded - //TODO(Igor): Consider whether we could do this only if the record state is unloaded - - //Goes away once hasMany is double promisified - this.notifyPropertyChange(key); - }, - - eachAttribute(callback, binding) { - this.constructor.eachAttribute(callback, binding); - }, -}); - -/** - @property data - @private - @type {Object} - */ -Object.defineProperty(Model.prototype, 'data', { - configurable: false, - get() { - return this._internalModel._data; - }, -}); - -Object.defineProperty(Model.prototype, 'id', { - configurable: false, - set(id) { - this._internalModel.setId(id); - }, - - get() { - // the _internalModel guard exists, because some dev-only deprecation code - // (addListener via validatePropertyInjections) invokes toString before the - // object is real. - return this._internalModel && this._internalModel.id; - }, -}); - -if (DEBUG) { - Model.reopen({ - init() { - this._super(...arguments); - - if (!this._internalModel) { - throw new EmberError( - 'You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.' - ); - } - }, - }); -} - -Model.reopenClass({ - isModel: true, - - /** - Override the class' `create()` method to raise an error. This - prevents end users from inadvertently calling `create()` instead - of `createRecord()`. The store is still able to create instances - by calling the `_create()` method. To create an instance of a - `DS.Model` use [store.createRecord](DS.Store.html#method_createRecord). - - @method create - @private - @static - */ - /** - Represents the model's class name as a string. This can be used to look up the model's class name through - `DS.Store`'s modelFor method. - - `modelName` is generated for you by Ember Data. It will be a lowercased, dasherized string. - For example: - - ```javascript - store.modelFor('post').modelName; // 'post' - store.modelFor('blog-post').modelName; // 'blog-post' - ``` - - The most common place you'll want to access `modelName` is in your serializer's `payloadKeyFromModelName` method. For example, to change payload - keys to underscore (instead of dasherized), you might use the following code: - - ```javascript - import { underscore } from '@ember/string'; - - export default const PostSerializer = DS.RESTSerializer.extend({ - payloadKeyFromModelName(modelName) { - return underscore(modelName); - } - }); - ``` - @property modelName - @type String - @readonly - @static - */ - modelName: null, - - /* - These class methods below provide relationship - introspection abilities about relationships. - - A note about the computed properties contained here: - - **These properties are effectively sealed once called for the first time.** - To avoid repeatedly doing expensive iteration over a model's fields, these - values are computed once and then cached for the remainder of the runtime of - your application. - - If your application needs to modify a class after its initial definition - (for example, using `reopen()` to add additional attributes), make sure you - do it before using your model with the store, which uses these properties - extensively. - */ - - /** - For a given relationship name, returns the model type of the relationship. - - For example, if you define a model like this: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - comments: DS.hasMany('comment') - }); - ``` - - Calling `store.modelFor('post').typeForRelationship('comments', store)` will return `Comment`. - - @method typeForRelationship - @static - @param {String} name the name of the relationship - @param {store} store an instance of DS.Store - @return {DS.Model} the type of the relationship, or undefined - */ - typeForRelationship(name, store) { - let relationship = get(this, 'relationshipsByName').get(name); - return relationship && store.modelFor(relationship.type); - }, - - inverseMap: computed(function() { - return Object.create(null); - }), - - /** - Find the relationship which is the inverse of the one asked for. - - For example, if you define models like this: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - comments: DS.hasMany('message') - }); - ``` - - ```app/models/message.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - owner: DS.belongsTo('post') - }); - ``` - - ``` js - store.modelFor('post').inverseFor('comments', store) // { type: App.Message, name: 'owner', kind: 'belongsTo' } - store.modelFor('message').inverseFor('owner', store) // { type: App.Post, name: 'comments', kind: 'hasMany' } - ``` - - @method inverseFor - @static - @param {String} name the name of the relationship - @param {DS.Store} store - @return {Object} the inverse relationship, or null - */ - inverseFor(name, store) { - let inverseMap = get(this, 'inverseMap'); - if (inverseMap[name] !== undefined) { - return inverseMap[name]; - } - - let relationship = get(this, 'relationshipsByName').get(name); - if ( - !relationship || - // populate the cache with a miss entry so we can skip getting and going - // through `relationshipsByName` - (relationship.options && relationship.options.inverse === null) - ) { - return (inverseMap[name] = null); - } - - return (inverseMap[name] = this._findInverseFor(name, store)); - }, - - //Calculate the inverse, ignoring the cache - _findInverseFor(name, store) { - let inverseType = this.typeForRelationship(name, store); - if (!inverseType) { - return null; - } - - let propertyMeta = this.metaForProperty(name); - //If inverse is manually specified to be null, like `comments: DS.hasMany('message', { inverse: null })` - let options = propertyMeta.options; - if (options.inverse === null) { - return null; - } - - let inverseName, inverseKind, inverse, inverseOptions; - - //If inverse is specified manually, return the inverse - if (options.inverse) { - inverseName = options.inverse; - inverse = get(inverseType, 'relationshipsByName').get(inverseName); - - assert( - "We found no inverse relationships by the name of '" + - inverseName + - "' on the '" + - inverseType.modelName + - "' model. This is most likely due to a missing attribute on your model definition.", - !isNone(inverse) - ); - - // TODO probably just return the whole inverse here - inverseKind = inverse.kind; - inverseOptions = inverse.options; - } else { - //No inverse was specified manually, we need to use a heuristic to guess one - if (propertyMeta.parentType && propertyMeta.type === propertyMeta.parentType.modelName) { - warn( - `Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at https://guides.emberjs.com/current/models/relationships/#toc_reflexive-relations for how to explicitly specify inverses.`, - false, - { - id: 'ds.model.reflexive-relationship-without-inverse', - } - ); - } - - let possibleRelationships = findPossibleInverses(this, inverseType, name); - - if (possibleRelationships.length === 0) { - return null; - } - - let filteredRelationships = possibleRelationships.filter(possibleRelationship => { - let optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options; - return name === optionsForRelationship.inverse; - }); - - assert( - "You defined the '" + - name + - "' relationship on " + - this + - ', but you defined the inverse relationships of type ' + - inverseType.toString() + - ' multiple times. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses', - filteredRelationships.length < 2 - ); - - if (filteredRelationships.length === 1) { - possibleRelationships = filteredRelationships; - } - - assert( - "You defined the '" + - name + - "' relationship on " + - this + - ', but multiple possible inverse relationships of type ' + - this + - ' were found on ' + - inverseType + - '. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses', - possibleRelationships.length === 1 - ); - - inverseName = possibleRelationships[0].name; - inverseKind = possibleRelationships[0].kind; - inverseOptions = possibleRelationships[0].options; - } - - assert( - `The ${ - inverseType.modelName - }:${inverseName} relationship declares 'inverse: null', but it was resolved as the inverse for ${ - this.modelName - }:${name}.`, - !inverseOptions || inverseOptions.inverse !== null - ); - - return { - type: inverseType, - name: inverseName, - kind: inverseKind, - options: inverseOptions, - }; - }, - - /** - The model's relationships as a map, keyed on the type of the - relationship. The value of each entry is an array containing a descriptor - for each relationship with that type, describing the name of the relationship - as well as the type. - - For example, given the following model definition: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - posts: DS.hasMany('post') - }); - ``` - - This computed property would return a map describing these - relationships, like this: - - ```javascript - import Ember from 'ember'; - import Blog from 'app/models/blog'; - import User from 'app/models/user'; - import Post from 'app/models/post'; - - let relationships = Ember.get(Blog, 'relationships'); - relationships.get(User); - //=> [ { name: 'users', kind: 'hasMany' }, - // { name: 'owner', kind: 'belongsTo' } ] - relationships.get(Post); - //=> [ { name: 'posts', kind: 'hasMany' } ] - ``` - - @property relationships - @static - @type Map - @readOnly - */ - - relationships: relationshipsDescriptor, - - /** - A hash containing lists of the model's relationships, grouped - by the relationship kind. For example, given a model with this - definition: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - import Ember from 'ember'; - import Blog from 'app/models/blog'; - - let relationshipNames = Ember.get(Blog, 'relationshipNames'); - relationshipNames.hasMany; - //=> ['users', 'posts'] - relationshipNames.belongsTo; - //=> ['owner'] - ``` - - @property relationshipNames - @static - @type Object - @readOnly - */ - relationshipNames: computed(function() { - let names = { - hasMany: [], - belongsTo: [], - }; - - this.eachComputedProperty((name, meta) => { - if (meta.isRelationship) { - names[meta.kind].push(name); - } - }); - - return names; - }), - - /** - An array of types directly related to a model. Each type will be - included once, regardless of the number of relationships it has with - the model. - - For example, given a model with this definition: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - import Ember from 'ember'; - import Blog from 'app/models/blog'; - - let relatedTypes = Ember.get(Blog, 'relatedTypes'); - //=> [ User, Post ] - ``` - - @property relatedTypes - @static - @type Ember.Array - @readOnly - */ - relatedTypes: relatedTypesDescriptor, - - /** - A map whose keys are the relationships of a model and whose values are - relationship descriptors. - - For example, given a model with this - definition: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - import Ember from 'ember'; - import Blog from 'app/models/blog'; - - let relationshipsByName = Ember.get(Blog, 'relationshipsByName'); - relationshipsByName.get('users'); - //=> { key: 'users', kind: 'hasMany', type: 'user', options: Object, isRelationship: true } - relationshipsByName.get('owner'); - //=> { key: 'owner', kind: 'belongsTo', type: 'user', options: Object, isRelationship: true } - ``` - - @property relationshipsByName - @static - @type Map - @readOnly - */ - relationshipsByName: relationshipsByNameDescriptor, - - /** - A map whose keys are the fields of the model and whose values are strings - describing the kind of the field. A model's fields are the union of all of its - attributes and relationships. - - For example: - - ```app/models/blog.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post'), - - title: DS.attr('string') - }); - ``` - - ```js - import Ember from 'ember'; - import Blog from 'app/models/blog'; - - let fields = Ember.get(Blog, 'fields'); - fields.forEach(function(kind, field) { - console.log(field, kind); - }); - - // prints: - // users, hasMany - // owner, belongsTo - // posts, hasMany - // title, attribute - ``` - - @property fields - @static - @type Map - @readOnly - */ - fields: computed(function() { - let map = new Map(); - - this.eachComputedProperty((name, meta) => { - if (meta.isRelationship) { - map.set(name, meta.kind); - } else if (meta.isAttribute) { - map.set(name, 'attribute'); - } - }); - - return map; - }).readOnly(), - - /** - Given a callback, iterates over each of the relationships in the model, - invoking the callback with the name of each relationship and its relationship - descriptor. - - @method eachRelationship - @static - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelationship(callback, binding) { - get(this, 'relationshipsByName').forEach((relationship, name) => { - callback.call(binding, name, relationship); - }); - }, - - /** - Given a callback, iterates over each of the types related to a model, - invoking the callback with the related type's class. Each type will be - returned just once, regardless of how many different relationships it has - with a model. - - @method eachRelatedType - @static - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelatedType(callback, binding) { - let relationshipTypes = get(this, 'relatedTypes'); - - for (let i = 0; i < relationshipTypes.length; i++) { - let type = relationshipTypes[i]; - callback.call(binding, type); - } - }, - - determineRelationshipType(knownSide, store) { - let knownKey = knownSide.key; - let knownKind = knownSide.kind; - let inverse = this.inverseFor(knownKey, store); - // let key; - let otherKind; - - if (!inverse) { - return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone'; - } - - // key = inverse.name; - otherKind = inverse.kind; - - if (otherKind === 'belongsTo') { - return knownKind === 'belongsTo' ? 'oneToOne' : 'manyToOne'; - } else { - return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany'; - } - }, - - /** - A map whose keys are the attributes of the model (properties - described by DS.attr) and whose values are the meta object for the - property. - - Example - - ```app/models/person.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - birthday: DS.attr('date') - }); - ``` - - ```javascript - import Ember from 'ember'; - import Person from 'app/models/person'; - - let attributes = Ember.get(Person, 'attributes') - - attributes.forEach(function(meta, name) { - console.log(name, meta); - }); - - // prints: - // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} - // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} - // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} - ``` - - @property attributes - @static - @type {Map} - @readOnly - */ - attributes: computed(function() { - let map = new Map(); - - this.eachComputedProperty((name, meta) => { - if (meta.isAttribute) { - assert( - "You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + - this.toString(), - name !== 'id' - ); - - meta.name = name; - map.set(name, meta); - } - }); - - return map; - }).readOnly(), - - /** - A map whose keys are the attributes of the model (properties - described by DS.attr) and whose values are type of transformation - applied to each attribute. This map does not include any - attributes that do not have an transformation type. - - Example - - ```app/models/person.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - firstName: DS.attr(), - lastName: DS.attr('string'), - birthday: DS.attr('date') - }); - ``` - - ```javascript - import Ember from 'ember'; - import Person from 'app/models/person'; - - let transformedAttributes = Ember.get(Person, 'transformedAttributes') - - transformedAttributes.forEach(function(field, type) { - console.log(field, type); - }); - - // prints: - // lastName string - // birthday date - ``` - - @property transformedAttributes - @static - @type {Map} - @readOnly - */ - transformedAttributes: computed(function() { - let map = new Map(); - - this.eachAttribute((key, meta) => { - if (meta.type) { - map.set(key, meta.type); - } - }); - - return map; - }).readOnly(), - - /** - Iterates through the attributes of the model, calling the passed function on each - attribute. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, meta); - ``` - - - `name` the name of the current property in the iteration - - `meta` the meta object for the attribute property in the iteration - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```javascript - import DS from 'ember-data'; - - let Person = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - birthday: DS.attr('date') - }); - - Person.eachAttribute(function(name, meta) { - console.log(name, meta); - }); - - // prints: - // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} - // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} - // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} - ``` - - @method eachAttribute - @param {Function} callback The callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - @static - */ - eachAttribute(callback, binding) { - get(this, 'attributes').forEach((meta, name) => { - callback.call(binding, name, meta); - }); - }, - - /** - Iterates through the transformedAttributes of the model, calling - the passed function on each attribute. Note the callback will not be - called for any attributes that do not have an transformation type. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, type); - ``` - - - `name` the name of the current property in the iteration - - `type` a string containing the name of the type of transformed - applied to the attribute - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```javascript - import DS from 'ember-data'; - - let Person = DS.Model.extend({ - firstName: DS.attr(), - lastName: DS.attr('string'), - birthday: DS.attr('date') - }); - - Person.eachTransformedAttribute(function(name, type) { - console.log(name, type); - }); - - // prints: - // lastName string - // birthday date - ``` - - @method eachTransformedAttribute - @param {Function} callback The callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - @static - */ - eachTransformedAttribute(callback, binding) { - get(this, 'transformedAttributes').forEach((type, name) => { - callback.call(binding, name, type); - }); - }, - - /** - Returns the name of the model class. - - @method toString - @static - */ - toString() { - return `model:${get(this, 'modelName')}`; - }, -}); - -if (DEBUG) { - Model.reopen({ - // This is a temporary solution until we refactor DS.Model to not - // rely on the data property. - willMergeMixin(props) { - let constructor = this.constructor; - assert( - '`' + - intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + - '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + - constructor.toString(), - !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] - ); - assert( - "You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + - constructor.toString(), - Object.keys(props).indexOf('id') === -1 - ); - }, - - /** - This Ember.js hook allows an object to be notified when a property - is defined. - - In this case, we use it to be notified when an Ember Data user defines a - belongs-to relationship. In that case, we need to set up observers for - each one, allowing us to track relationship changes and automatically - reflect changes in the inverse has-many array. - - This hook passes the class being set up, as well as the key and value - being defined. So, for example, when the user does this: - - ```javascript - DS.Model.extend({ - parent: DS.belongsTo('user') - }); - ``` - - This hook would be called with "parent" as the key and the computed - property returned by `DS.belongsTo` as the value. - - @method didDefineProperty - @param {Object} proto - @param {String} key - @param {Ember.ComputedProperty} value - */ - didDefineProperty(proto, key, value) { - // Check if the value being set is a computed property. - if (value instanceof ComputedProperty) { - // If it is, get the metadata for the relationship. This is - // populated by the `DS.belongsTo` helper when it is creating - // the computed property. - let meta = value.meta(); - - /* - This is buggy because if the parent has never been looked up - via `modelFor` it will not have `modelName` set. - */ - meta.parentType = proto.constructor; - } - }, - }); -} - -export default Model; diff --git a/addon/-legacy-private/system/model/states.js b/addon/-legacy-private/system/model/states.js deleted file mode 100644 index 893a1680a35..00000000000 --- a/addon/-legacy-private/system/model/states.js +++ /dev/null @@ -1,766 +0,0 @@ -/** - @module ember-data -*/ -import { assert } from '@ember/debug'; - -/* - This file encapsulates the various states that a record can transition - through during its lifecycle. -*/ -/** - ### State - - Each record has a `currentState` property that explicitly tracks what - state a record is in at any given time. For instance, if a record is - newly created and has not yet been sent to the adapter to be saved, - it would be in the `root.loaded.created.uncommitted` state. If a - record has had local modifications made to it that are in the - process of being saved, the record would be in the - `root.loaded.updated.inFlight` state. (This state path will be - explained in more detail below.) - - Events are sent by the record or its store to the record's - `currentState` property. How the state reacts to these events is - dependent on which state it is in. In some states, certain events - will be invalid and will cause an exception to be raised. - - States are hierarchical and every state is a sub-state of the - `RootState`. For example, a record can be in the - `root.deleted.uncommitted` state then transitions into the - `root.deleted.inFlight` state. If a child state does not implement - an event handler, the state manager will attempt to invoke the event - on all parent states until the root state is reached. The state - hierarchy of a record is described in terms of a path string. You - can determine a record's current state by getting the state's - `stateName` property: - - ```javascript - record.get('currentState.stateName'); - //=> "root.created.uncommitted" - ``` - - The hierarchy of valid states that ship with ember data looks like - this: - - ```text - * root - * deleted - * saved - * uncommitted - * inFlight - * empty - * loaded - * created - * uncommitted - * inFlight - * saved - * updated - * uncommitted - * inFlight - * loading - ``` - - The `DS.Model` states are themselves stateless. What that means is - that, the hierarchical states that each of *those* points to is a - shared data structure. For performance reasons, instead of each - record getting its own copy of the hierarchy of states, each record - points to this global, immutable shared instance. How does a state - know which record it should be acting on? We pass the record - instance into the state's event handlers as the first argument. - - The record passed as the first parameter is where you should stash - state about the record if needed; you should never store data on the state - object itself. - - ### Events and Flags - - A state may implement zero or more events and flags. - - #### Events - - Events are named functions that are invoked when sent to a record. The - record will first look for a method with the given name on the - current state. If no method is found, it will search the current - state's parent, and then its grandparent, and so on until reaching - the top of the hierarchy. If the root is reached without an event - handler being found, an exception will be raised. This can be very - helpful when debugging new features. - - Here's an example implementation of a state with a `myEvent` event handler: - - ```javascript - aState: DS.State.create({ - myEvent: function(manager, param) { - console.log("Received myEvent with", param); - } - }) - ``` - - To trigger this event: - - ```javascript - record.send('myEvent', 'foo'); - //=> "Received myEvent with foo" - ``` - - Note that an optional parameter can be sent to a record's `send()` method, - which will be passed as the second parameter to the event handler. - - Events should transition to a different state if appropriate. This can be - done by calling the record's `transitionTo()` method with a path to the - desired state. The state manager will attempt to resolve the state path - relative to the current state. If no state is found at that path, it will - attempt to resolve it relative to the current state's parent, and then its - parent, and so on until the root is reached. For example, imagine a hierarchy - like this: - - * created - * uncommitted <-- currentState - * inFlight - * updated - * inFlight - - If we are currently in the `uncommitted` state, calling - `transitionTo('inFlight')` would transition to the `created.inFlight` state, - while calling `transitionTo('updated.inFlight')` would transition to - the `updated.inFlight` state. - - Remember that *only events* should ever cause a state transition. You should - never call `transitionTo()` from outside a state's event handler. If you are - tempted to do so, create a new event and send that to the state manager. - - #### Flags - - Flags are Boolean values that can be used to introspect a record's current - state in a more user-friendly way than examining its state path. For example, - instead of doing this: - - ```javascript - var statePath = record.get('stateManager.currentPath'); - if (statePath === 'created.inFlight') { - doSomething(); - } - ``` - - You can say: - - ```javascript - if (record.get('isNew') && record.get('isSaving')) { - doSomething(); - } - ``` - - If your state does not set a value for a given flag, the value will - be inherited from its parent (or the first place in the state hierarchy - where it is defined). - - The current set of flags are defined below. If you want to add a new flag, - in addition to the area below, you will also need to declare it in the - `DS.Model` class. - - - * [isEmpty](DS.Model.html#property_isEmpty) - * [isLoading](DS.Model.html#property_isLoading) - * [isLoaded](DS.Model.html#property_isLoaded) - * [hasDirtyAttributes](DS.Model.html#property_hasDirtyAttributes) - * [isSaving](DS.Model.html#property_isSaving) - * [isDeleted](DS.Model.html#property_isDeleted) - * [isNew](DS.Model.html#property_isNew) - * [isValid](DS.Model.html#property_isValid) - - @namespace DS - @class RootState -*/ - -function didSetProperty(internalModel, context) { - if (context.value === context.originalValue) { - delete internalModel._attributes[context.name]; - internalModel.send('propertyWasReset', context.name); - } else if (context.value !== context.oldValue) { - internalModel.send('becomeDirty'); - } - - internalModel.updateRecordArrays(); -} - -// Implementation notes: -// -// Each state has a boolean value for all of the following flags: -// -// * isLoaded: The record has a populated `data` property. When a -// record is loaded via `store.find`, `isLoaded` is false -// until the adapter sets it. When a record is created locally, -// its `isLoaded` property is always true. -// * isDirty: The record has local changes that have not yet been -// saved by the adapter. This includes records that have been -// created (but not yet saved) or deleted. -// * isSaving: The record has been committed, but -// the adapter has not yet acknowledged that the changes have -// been persisted to the backend. -// * isDeleted: The record was marked for deletion. When `isDeleted` -// is true and `isDirty` is true, the record is deleted locally -// but the deletion was not yet persisted. When `isSaving` is -// true, the change is in-flight. When both `isDirty` and -// `isSaving` are false, the change has persisted. -// * isNew: The record was created on the client and the adapter -// did not yet report that it was successfully saved. -// * isValid: The adapter did not report any server-side validation -// failures. - -// The dirty state is a abstract state whose functionality is -// shared between the `created` and `updated` states. -// -// The deleted state shares the `isDirty` flag with the -// subclasses of `DirtyState`, but with a very different -// implementation. -// -// Dirty states have three child states: -// -// `uncommitted`: the store has not yet handed off the record -// to be saved. -// `inFlight`: the store has handed off the record to be saved, -// but the adapter has not yet acknowledged success. -// `invalid`: the record has invalid information and cannot be -// sent to the adapter yet. -const DirtyState = { - initialState: 'uncommitted', - - // FLAGS - isDirty: true, - - // SUBSTATES - - // When a record first becomes dirty, it is `uncommitted`. - // This means that there are local pending changes, but they - // have not yet begun to be saved, and are not invalid. - uncommitted: { - // EVENTS - didSetProperty, - - //TODO(Igor) reloading now triggers a - //loadingData event, though it seems fine? - loadingData() {}, - - propertyWasReset(internalModel, name) { - if (!internalModel.hasChangedAttributes()) { - internalModel.send('rolledBack'); - } - }, - - pushedData(internalModel) { - let token = heimdall.start('stats.uncommitted.pushedData'); - internalModel.updateChangedAttributes(); - - if (!internalModel.hasChangedAttributes()) { - internalModel.transitionTo('loaded.saved'); - } - heimdall.stop(token); - }, - - becomeDirty() {}, - - willCommit(internalModel) { - internalModel.transitionTo('inFlight'); - }, - - reloadRecord(internalModel, { resolve, options }) { - resolve(internalModel.store._reloadRecord(internalModel, options)); - }, - - rolledBack(internalModel) { - internalModel.transitionTo('loaded.saved'); - internalModel.triggerLater('rolledBack'); - }, - - becameInvalid(internalModel) { - internalModel.transitionTo('invalid'); - }, - - rollback(internalModel) { - internalModel.rollbackAttributes(); - internalModel.triggerLater('ready'); - }, - }, - - // Once a record has been handed off to the adapter to be - // saved, it is in the 'in flight' state. Changes to the - // record cannot be made during this window. - inFlight: { - // FLAGS - isSaving: true, - - // EVENTS - didSetProperty, - becomeDirty() {}, - pushedData() {}, - - unloadRecord: assertAgainstUnloadRecord, - - // TODO: More robust semantics around save-while-in-flight - willCommit() {}, - - didCommit(internalModel) { - internalModel.transitionTo('saved'); - internalModel.send('invokeLifecycleCallbacks', this.dirtyType); - }, - - rolledBack(internalModel) { - internalModel.triggerLater('rolledBack'); - }, - - becameInvalid(internalModel) { - internalModel.transitionTo('invalid'); - internalModel.send('invokeLifecycleCallbacks'); - }, - - becameError(internalModel) { - internalModel.transitionTo('uncommitted'); - internalModel.triggerLater('becameError', internalModel); - }, - }, - - // A record is in the `invalid` if the adapter has indicated - // the the record failed server-side invalidations. - invalid: { - // FLAGS - isValid: false, - - // EVENTS - deleteRecord(internalModel) { - internalModel.transitionTo('deleted.uncommitted'); - }, - - didSetProperty(internalModel, context) { - internalModel.removeErrorMessageFromAttribute(context.name); - - didSetProperty(internalModel, context); - - if (!internalModel.hasErrors()) { - this.becameValid(internalModel); - } - }, - - becameInvalid() {}, - becomeDirty() {}, - pushedData() {}, - - willCommit(internalModel) { - internalModel.clearErrorMessages(); - internalModel.transitionTo('inFlight'); - }, - - rolledBack(internalModel) { - internalModel.clearErrorMessages(); - internalModel.transitionTo('loaded.saved'); - internalModel.triggerLater('ready'); - }, - - becameValid(internalModel) { - internalModel.transitionTo('uncommitted'); - }, - - invokeLifecycleCallbacks(internalModel) { - internalModel.triggerLater('becameInvalid', internalModel); - }, - }, -}; - -// The created and updated states are created outside the state -// chart so we can reopen their substates and add mixins as -// necessary. - -function deepClone(object) { - const clone = {}; - let value; - - for (let prop in object) { - value = object[prop]; - if (value && typeof value === 'object') { - clone[prop] = deepClone(value); - } else { - clone[prop] = value; - } - } - - return clone; -} - -function mixin(original, hash) { - for (let prop in hash) { - original[prop] = hash[prop]; - } - - return original; -} - -function dirtyState(options) { - var newState = deepClone(DirtyState); - return mixin(newState, options); -} - -const createdState = dirtyState({ - dirtyType: 'created', - // FLAGS - isNew: true, -}); - -createdState.invalid.rolledBack = function(internalModel) { - internalModel.transitionTo('deleted.saved'); - internalModel.triggerLater('rolledBack'); -}; - -createdState.uncommitted.rolledBack = function(internalModel) { - internalModel.transitionTo('deleted.saved'); - internalModel.triggerLater('rolledBack'); -}; - -const updatedState = dirtyState({ - dirtyType: 'updated', -}); - -function createdStateDeleteRecord(internalModel) { - internalModel.transitionTo('deleted.saved'); - internalModel.send('invokeLifecycleCallbacks'); -} - -createdState.uncommitted.deleteRecord = createdStateDeleteRecord; - -createdState.invalid.deleteRecord = createdStateDeleteRecord; - -createdState.uncommitted.rollback = function(internalModel) { - DirtyState.uncommitted.rollback.apply(this, arguments); - internalModel.transitionTo('deleted.saved'); -}; - -createdState.uncommitted.pushedData = function(internalModel) { - internalModel.transitionTo('loaded.updated.uncommitted'); - internalModel.triggerLater('didLoad'); -}; - -createdState.uncommitted.propertyWasReset = function() {}; - -function assertAgainstUnloadRecord(internalModel) { - assert('You can only unload a record which is not inFlight. `' + internalModel + '`', false); -} - -updatedState.invalid.becameValid = function(internalModel) { - // we're eagerly transition into the loaded.saved state, even though we could - // be still dirty; but the setup hook of the loaded.saved state checks for - // dirty attributes and transitions into the corresponding dirty state - internalModel.transitionTo('loaded.saved'); -}; - -updatedState.inFlight.unloadRecord = assertAgainstUnloadRecord; - -updatedState.uncommitted.deleteRecord = function(internalModel) { - internalModel.transitionTo('deleted.uncommitted'); -}; - -updatedState.invalid.rolledBack = function(internalModel) { - internalModel.clearErrorMessages(); - internalModel.transitionTo('loaded.saved'); - internalModel.triggerLater('rolledBack'); -}; - -const RootState = { - // FLAGS - isEmpty: false, - isLoading: false, - isLoaded: false, - isDirty: false, - isSaving: false, - isDeleted: false, - isNew: false, - isValid: true, - - // DEFAULT EVENTS - - // Trying to roll back if you're not in the dirty state - // doesn't change your state. For example, if you're in the - // in-flight state, rolling back the record doesn't move - // you out of the in-flight state. - rolledBack() {}, - unloadRecord(internalModel) {}, - - propertyWasReset() {}, - - // SUBSTATES - - // A record begins its lifecycle in the `empty` state. - // If its data will come from the adapter, it will - // transition into the `loading` state. Otherwise, if - // the record is being created on the client, it will - // transition into the `created` state. - empty: { - isEmpty: true, - - // EVENTS - loadingData(internalModel, promise) { - internalModel._promiseProxy = promise; - internalModel.transitionTo('loading'); - }, - - loadedData(internalModel) { - internalModel.transitionTo('loaded.created.uncommitted'); - internalModel.triggerLater('ready'); - }, - - pushedData(internalModel) { - internalModel.transitionTo('loaded.saved'); - internalModel.triggerLater('didLoad'); - internalModel.triggerLater('ready'); - }, - }, - - // A record enters this state when the store asks - // the adapter for its data. It remains in this state - // until the adapter provides the requested data. - // - // Usually, this process is asynchronous, using an - // XHR to retrieve the data. - loading: { - // FLAGS - isLoading: true, - - exit(internalModel) { - internalModel._promiseProxy = null; - }, - - // EVENTS - pushedData(internalModel) { - internalModel.transitionTo('loaded.saved'); - internalModel.triggerLater('didLoad'); - internalModel.triggerLater('ready'); - //TODO this seems out of place here - internalModel.didCleanError(); - }, - - becameError(internalModel) { - internalModel.triggerLater('becameError', internalModel); - }, - - notFound(internalModel) { - internalModel.transitionTo('empty'); - }, - }, - - // A record enters this state when its data is populated. - // Most of a record's lifecycle is spent inside substates - // of the `loaded` state. - loaded: { - initialState: 'saved', - - // FLAGS - isLoaded: true, - - //TODO(Igor) Reloading now triggers a loadingData event, - //but it should be ok? - loadingData() {}, - - // SUBSTATES - - // If there are no local changes to a record, it remains - // in the `saved` state. - saved: { - setup(internalModel) { - if (internalModel.hasChangedAttributes()) { - internalModel.adapterDidDirty(); - } - }, - - // EVENTS - didSetProperty, - - pushedData() {}, - - becomeDirty(internalModel) { - internalModel.transitionTo('updated.uncommitted'); - }, - - willCommit(internalModel) { - internalModel.transitionTo('updated.inFlight'); - }, - - reloadRecord(internalModel, { resolve, options }) { - resolve(internalModel.store._reloadRecord(internalModel, options)); - }, - - deleteRecord(internalModel) { - internalModel.transitionTo('deleted.uncommitted'); - }, - - unloadRecord(internalModel) {}, - - didCommit() {}, - - // loaded.saved.notFound would be triggered by a failed - // `reload()` on an unchanged record - notFound() {}, - }, - - // A record is in this state after it has been locally - // created but before the adapter has indicated that - // it has been saved. - created: createdState, - - // A record is in this state if it has already been - // saved to the server, but there are new local changes - // that have not yet been saved. - updated: updatedState, - }, - - // A record is in this state if it was deleted from the store. - deleted: { - initialState: 'uncommitted', - dirtyType: 'deleted', - - // FLAGS - isDeleted: true, - isLoaded: true, - isDirty: true, - - // TRANSITIONS - setup(internalModel) { - internalModel.updateRecordArrays(); - }, - - // SUBSTATES - - // When a record is deleted, it enters the `start` - // state. It will exit this state when the record - // starts to commit. - uncommitted: { - // EVENTS - - willCommit(internalModel) { - internalModel.transitionTo('inFlight'); - }, - - rollback(internalModel) { - internalModel.rollbackAttributes(); - internalModel.triggerLater('ready'); - }, - - pushedData() {}, - becomeDirty() {}, - deleteRecord() {}, - - rolledBack(internalModel) { - internalModel.transitionTo('loaded.saved'); - internalModel.triggerLater('ready'); - internalModel.triggerLater('rolledBack'); - }, - }, - - // After a record starts committing, but - // before the adapter indicates that the deletion - // has saved to the server, a record is in the - // `inFlight` substate of `deleted`. - inFlight: { - // FLAGS - isSaving: true, - - // EVENTS - - unloadRecord: assertAgainstUnloadRecord, - - // TODO: More robust semantics around save-while-in-flight - willCommit() {}, - didCommit(internalModel) { - internalModel.transitionTo('saved'); - - internalModel.send('invokeLifecycleCallbacks'); - }, - - becameError(internalModel) { - internalModel.transitionTo('uncommitted'); - internalModel.triggerLater('becameError', internalModel); - }, - - becameInvalid(internalModel) { - internalModel.transitionTo('invalid'); - internalModel.triggerLater('becameInvalid', internalModel); - }, - }, - - // Once the adapter indicates that the deletion has - // been saved, the record enters the `saved` substate - // of `deleted`. - saved: { - // FLAGS - isDirty: false, - - setup(internalModel) { - internalModel.removeFromInverseRelationships(); - }, - - invokeLifecycleCallbacks(internalModel) { - internalModel.triggerLater('didDelete', internalModel); - internalModel.triggerLater('didCommit', internalModel); - }, - - willCommit() {}, - didCommit() {}, - pushedData() {}, - }, - - invalid: { - isValid: false, - - didSetProperty(internalModel, context) { - internalModel.removeErrorMessageFromAttribute(context.name); - - didSetProperty(internalModel, context); - - if (!internalModel.hasErrors()) { - this.becameValid(internalModel); - } - }, - - becameInvalid() {}, - becomeDirty() {}, - deleteRecord() {}, - willCommit() {}, - - rolledBack(internalModel) { - internalModel.clearErrorMessages(); - internalModel.transitionTo('loaded.saved'); - internalModel.triggerLater('ready'); - }, - - becameValid(internalModel) { - internalModel.transitionTo('uncommitted'); - }, - }, - }, - - invokeLifecycleCallbacks(internalModel, dirtyType) { - if (dirtyType === 'created') { - internalModel.triggerLater('didCreate', internalModel); - } else { - internalModel.triggerLater('didUpdate', internalModel); - } - - internalModel.triggerLater('didCommit', internalModel); - }, -}; - -function wireState(object, parent, name) { - // TODO: Use Object.create and copy instead - object = mixin(parent ? Object.create(parent) : {}, object); - object.parentState = parent; - object.stateName = name; - - for (let prop in object) { - if (!object.hasOwnProperty(prop) || prop === 'parentState' || prop === 'stateName') { - continue; - } - if (typeof object[prop] === 'object') { - object[prop] = wireState(object[prop], object, name + '.' + prop); - } - } - - return object; -} - -export default wireState(RootState, null, 'root'); diff --git a/addon/-legacy-private/system/promise-proxies.js b/addon/-legacy-private/system/promise-proxies.js deleted file mode 100644 index 4a419ac7a01..00000000000 --- a/addon/-legacy-private/system/promise-proxies.js +++ /dev/null @@ -1,162 +0,0 @@ -import ObjectProxy from '@ember/object/proxy'; -import PromiseProxyMixin from '@ember/object/promise-proxy-mixin'; -import ArrayProxy from '@ember/array/proxy'; -import { get, computed } from '@ember/object'; -import { reads } from '@ember/object/computed'; -import { Promise } from 'rsvp'; -import { assert } from '@ember/debug'; - -/** - A `PromiseArray` is an object that acts like both an `Ember.Array` - and a promise. When the promise is resolved the resulting value - will be set to the `PromiseArray`'s `content` property. This makes - it easy to create data bindings with the `PromiseArray` that will be - updated when the promise resolves. - - For more information see the [Ember.PromiseProxyMixin - documentation](/api/classes/Ember.PromiseProxyMixin.html). - - Example - - ```javascript - let promiseArray = DS.PromiseArray.create({ - promise: $.getJSON('/some/remote/data.json') - }); - - promiseArray.get('length'); // 0 - - promiseArray.then(function() { - promiseArray.get('length'); // 100 - }); - ``` - - @class PromiseArray - @namespace DS - @extends Ember.ArrayProxy - @uses Ember.PromiseProxyMixin -*/ -export const PromiseArray = ArrayProxy.extend(PromiseProxyMixin, { - meta: reads('content.meta'), -}); - -/** - A `PromiseObject` is an object that acts like both an `Ember.Object` - and a promise. When the promise is resolved, then the resulting value - will be set to the `PromiseObject`'s `content` property. This makes - it easy to create data bindings with the `PromiseObject` that will - be updated when the promise resolves. - - For more information see the [Ember.PromiseProxyMixin - documentation](/api/classes/Ember.PromiseProxyMixin.html). - - Example - - ```javascript - let promiseObject = DS.PromiseObject.create({ - promise: $.getJSON('/some/remote/data.json') - }); - - promiseObject.get('name'); // null - - promiseObject.then(function() { - promiseObject.get('name'); // 'Tomster' - }); - ``` - - @class PromiseObject - @namespace DS - @extends Ember.ObjectProxy - @uses Ember.PromiseProxyMixin -*/ -export let PromiseObject = ObjectProxy.extend(PromiseProxyMixin); - -export function promiseObject(promise, label) { - return PromiseObject.create({ - promise: Promise.resolve(promise, label), - }); -} - -export function promiseArray(promise, label) { - return PromiseArray.create({ - promise: Promise.resolve(promise, label), - }); -} - -export const PromiseBelongsTo = PromiseObject.extend({ - // we don't proxy meta because we would need to proxy it to the relationship state container - // however, meta on relationships does not trigger change notifications. - // if you need relationship meta, you should do `record.belongsTo(relationshipName).meta()` - meta: computed(function() { - assert( - 'You attempted to access meta on the promise for the async belongsTo relationship ' + - `${this.get('_belongsToState').internalModel.modelName}:${ - this.get('_belongsToState').key - }'.` + - '\nUse `record.belongsTo(relationshipName).meta()` instead.', - false - ); - }), - - reload() { - assert( - 'You are trying to reload an async belongsTo before it has been created', - this.get('content') !== undefined - ); - this.get('_belongsToState').reload(); - - return this; - }, -}); - -/** - A PromiseManyArray is a PromiseArray that also proxies certain method calls - to the underlying manyArray. - Right now we proxy: - - * `reload()` - * `createRecord()` - * `on()` - * `one()` - * `trigger()` - * `off()` - * `has()` - - @class PromiseManyArray - @namespace DS - @extends Ember.ArrayProxy -*/ - -export function proxyToContent(method) { - return function() { - return get(this, 'content')[method](...arguments); - }; -} - -export const PromiseManyArray = PromiseArray.extend({ - reload() { - assert( - 'You are trying to reload an async manyArray before it has been created', - get(this, 'content') - ); - this.set('promise', this.get('content').reload()); - return this; - }, - - createRecord: proxyToContent('createRecord'), - - on: proxyToContent('on'), - - one: proxyToContent('one'), - - trigger: proxyToContent('trigger'), - - off: proxyToContent('off'), - - has: proxyToContent('has'), -}); - -export function promiseManyArray(promise, label) { - return PromiseManyArray.create({ - promise: Promise.resolve(promise, label), - }); -} diff --git a/addon/-legacy-private/system/references/belongs-to.js b/addon/-legacy-private/system/references/belongs-to.js deleted file mode 100644 index 1506b1d2d39..00000000000 --- a/addon/-legacy-private/system/references/belongs-to.js +++ /dev/null @@ -1,440 +0,0 @@ -import { resolve } from 'rsvp'; -import Model from '../model/model'; -import Reference from './reference'; - -import { assertPolymorphicType } from 'ember-data/-debug'; - -/** - A BelongsToReference is a low-level API that allows users and - addon author to perform meta-operations on a belongs-to - relationship. - - @class BelongsToReference - @namespace DS - @extends DS.Reference -*/ -export default class BelongsToReference extends Reference { - constructor(store, parentInternalModel, belongsToRelationship) { - super(store, parentInternalModel); - this.belongsToRelationship = belongsToRelationship; - this.type = belongsToRelationship.relationshipMeta.type; - this.parent = parentInternalModel.recordReference; - // TODO inverse - } - - /** - This returns a string that represents how the reference will be - looked up when it is loaded. If the relationship has a link it will - use the "link" otherwise it defaults to "id". - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - }); - let userRef = blog.belongsTo('user'); - - // get the identifier of the reference - if (userRef.remoteType() === "id") { - let id = userRef.id(); - } else if (userRef.remoteType() === "link") { - let link = userRef.link(); - } - ``` - - @method remoteType - @return {String} The name of the remote type. This should either be "link" or "id" - */ - remoteType() { - if (this.belongsToRelationship.link) { - return 'link'; - } - - return 'id'; - } - - /** - The `id` of the record that this reference refers to. Together, the - `type()` and `id()` methods form a composite key for the identity - map. This can be used to access the id of an async relationship - without triggering a fetch that would normally happen if you - attempted to use `record.get('relationship.id')`. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - } - }); - let userRef = blog.belongsTo('user'); - - // get the identifier of the reference - if (userRef.remoteType() === "id") { - let id = userRef.id(); - } - ``` - - @method id - @return {String} The id of the record in this belongsTo relationship. - */ - id() { - let inverseInternalModel = this.belongsToRelationship.inverseInternalModel; - return inverseInternalModel && inverseInternalModel.id; - } - - /** - The link Ember Data will use to fetch or reload this belongs-to - relationship. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - links: { - related: '/articles/1/author' - } - } - } - } - }); - let userRef = blog.belongsTo('user'); - - // get the identifier of the reference - if (userRef.remoteType() === "link") { - let link = userRef.link(); - } - ``` - - @method link - @return {String} The link Ember Data will use to fetch or reload this belongs-to relationship. - */ - link() { - return this.belongsToRelationship.link; - } - - /** - The meta data for the belongs-to relationship. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - links: { - related: { - href: '/articles/1/author', - meta: { - lastUpdated: 1458014400000 - } - } - } - } - } - } - }); - - let userRef = blog.belongsTo('user'); - - userRef.meta() // { lastUpdated: 1458014400000 } - ``` - - @method meta - @return {Object} The meta information for the belongs-to relationship. - */ - meta() { - return this.belongsToRelationship.meta; - } - - /** - `push` can be used to update the data in the relationship and Ember - Data will treat the new data as the conanical value of this - relationship on the backend. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - } - }); - let userRef = blog.belongsTo('user'); - - // provide data for reference - userRef.push({ - data: { - type: 'user', - id: 1, - attributes: { - username: "@user" - } - } - }).then(function(user) { - userRef.value() === user; - }); - ``` - - @method push - @param {Object|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. - @return {Promise} A promise that resolves with the new value in this belongs-to relationship. - */ - push(objectOrPromise) { - return resolve(objectOrPromise).then(data => { - let record; - - if (data instanceof Model) { - record = data; - } else { - record = this.store.push(data); - } - - assertPolymorphicType( - this.internalModel, - this.belongsToRelationship.relationshipMeta, - record._internalModel, - this.store - ); - - this.belongsToRelationship.setCanonicalInternalModel(record._internalModel); - - return record; - }); - } - - /** - `value()` synchronously returns the current value of the belongs-to - relationship. Unlike `record.get('relationshipName')`, calling - `value()` on a reference does not trigger a fetch if the async - relationship is not yet loaded. If the relationship is not loaded - it will always return `null`. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - } - }); - let userRef = blog.belongsTo('user'); - - userRef.value(); // null - - // provide data for reference - userRef.push({ - data: { - type: 'user', - id: 1, - attributes: { - username: "@user" - } - } - }).then(function(user) { - userRef.value(); // user - }); - ``` - - @method value - @return {DS.Model} the record in this relationship - */ - value() { - let inverseInternalModel = this.belongsToRelationship.inverseInternalModel; - - if (inverseInternalModel && inverseInternalModel.isLoaded()) { - return inverseInternalModel.getRecord(); - } - - return null; - } - - /** - Loads a record in a belongs to-relationship if it is not already - loaded. If the relationship is already loaded this method does not - trigger a new load. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - } - }); - let userRef = blog.belongsTo('user'); - - userRef.value(); // null - - userRef.load().then(function(user) { - userRef.value() === user - }); - ``` - - You may also pass in an options object whose properties will be - fed forward. This enables you to pass `adapterOptions` into the - request given to the adapter via the reference. - - Example - - ```javascript - userRef.load({ adapterOptions: { isPrivate: true } }).then(function(user) { - userRef.value() === user; - }); - ``` - - ```app/adapters/user.js - export default ApplicationAdapter.extend({ - findRecord(store, type, id, snapshot) { - // In the adapter you will have access to adapterOptions. - let adapterOptions = snapshot.adapterOptions; - } - }); - ``` - - @method load - @param {Object} options the options to pass in. - @return {Promise} a promise that resolves with the record in this belongs-to relationship. - */ - load(options) { - let rel = this.belongsToRelationship; - - rel.getData(options); - - if (rel.fetchPromise !== null) { - return rel.fetchPromise.then(() => { - return this.value(); - }); - } - - return resolve(this.value()); - } - - /** - Triggers a reload of the value in this relationship. If the - remoteType is `"link"` Ember Data will use the relationship link to - reload the relationship. Otherwise, it will reload the record by its - id. - - Example - - ```javascript - // models/blog.js - export default DS.Model.extend({ - user: DS.belongsTo({ async: true }) - }); - - let blog = store.push({ - data: { - type: 'blog', - id: 1, - relationships: { - user: { - data: { type: 'user', id: 1 } - } - } - } - }); - let userRef = blog.belongsTo('user'); - - userRef.reload().then(function(user) { - userRef.value() === user - }); - ``` - - You may also pass in an options object whose properties will be - fed forward. This enables you to pass `adapterOptions` into the - request given to the adapter via the reference. A full example - can be found in the `load` method. - - Example - - ```javascript - userRef.reload({ adapterOptions: { isPrivate: true } }) - ``` - - @method reload - @param {Object} options the options to pass in. - @return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed. - */ - reload(options) { - return this.belongsToRelationship.reload(options).then(internalModel => { - return this.value(); - }); - } -} diff --git a/addon/-legacy-private/system/references/has-many.js b/addon/-legacy-private/system/references/has-many.js deleted file mode 100644 index 8201e03fed0..00000000000 --- a/addon/-legacy-private/system/references/has-many.js +++ /dev/null @@ -1,442 +0,0 @@ -import { resolve } from 'rsvp'; -import { get } from '@ember/object'; -import Reference from './reference'; -import { DEBUG } from '@glimmer/env'; -import { assertPolymorphicType } from 'ember-data/-debug'; - -/** - A HasManyReference is a low-level API that allows users and addon - author to perform meta-operations on a has-many relationship. - - @class HasManyReference - @namespace DS -*/ -export default class HasManyReference extends Reference { - constructor(store, parentInternalModel, hasManyRelationship) { - super(store, parentInternalModel); - this.hasManyRelationship = hasManyRelationship; - this.type = hasManyRelationship.relationshipMeta.type; - this.parent = parentInternalModel.recordReference; - // TODO inverse - } - - /** - This returns a string that represents how the reference will be - looked up when it is loaded. If the relationship has a link it will - use the "link" otherwise it defaults to "id". - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - // get the identifier of the reference - if (commentsRef.remoteType() === "ids") { - let ids = commentsRef.ids(); - } else if (commentsRef.remoteType() === "link") { - let link = commentsRef.link(); - } - ``` - - @method remoteType - @return {String} The name of the remote type. This should either be "link" or "ids" - */ - remoteType() { - if (this.hasManyRelationship.link) { - return 'link'; - } - - return 'ids'; - } - - /** - The link Ember Data will use to fetch or reload this has-many - relationship. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - links: { - related: '/posts/1/comments' - } - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - commentsRef.link(); // '/posts/1/comments' - ``` - - @method link - @return {String} The link Ember Data will use to fetch or reload this has-many relationship. - */ - link() { - return this.hasManyRelationship.link; - } - - /** - `ids()` returns an array of the record IDs in this relationship. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - commentsRef.ids(); // ['1'] - ``` - - @method ids - @return {Array} The ids in this has-many relationship - */ - ids() { - let members = this.hasManyRelationship.members.toArray(); - - return members.map(function(internalModel) { - return internalModel.id; - }); - } - - /** - The metadata for the has-many relationship. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - links: { - related: { - href: '/posts/1/comments', - meta: { - count: 10 - } - } - } - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - commentsRef.meta(); // { count: 10 } - ``` - - @method meta - @return {Object} The meta information for the has-many relationship. - */ - meta() { - return this.hasManyRelationship.meta; - } - - /** - `push` can be used to update the data in the relationship and Ember - Data will treat the new data as the canonical value of this - relationship on the backend. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ``` - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - commentsRef.ids(); // ['1'] - - commentsRef.push([ - [{ type: 'comment', id: 2 }], - [{ type: 'comment', id: 3 }], - ]) - - commentsRef.ids(); // ['2', '3'] - ``` - - @method push - @param {Array|Promise} objectOrPromise a promise that resolves to a JSONAPI document object describing the new value of this relationship. - @return {DS.ManyArray} - */ - push(objectOrPromise) { - return resolve(objectOrPromise).then(payload => { - let array = payload; - - if (typeof payload === 'object' && payload.data) { - array = payload.data; - } - - let internalModels; - internalModels = array.map(obj => { - let record = this.store.push(obj); - - if (DEBUG) { - let relationshipMeta = this.hasManyRelationship.relationshipMeta; - assertPolymorphicType( - this.internalModel, - relationshipMeta, - record._internalModel, - this.store - ); - } - - return record._internalModel; - }); - - this.hasManyRelationship.computeChanges(internalModels); - - return this.hasManyRelationship.manyArray; - }); - } - - _isLoaded() { - let hasRelationshipDataProperty = get(this.hasManyRelationship, 'hasAnyRelationshipData'); - if (!hasRelationshipDataProperty) { - return false; - } - - let members = this.hasManyRelationship.members.toArray(); - - return members.every(function(internalModel) { - return internalModel.isLoaded() === true; - }); - } - - /** - `value()` synchronously returns the current value of the has-many - relationship. Unlike `record.get('relationshipName')`, calling - `value()` on a reference does not trigger a fetch if the async - relationship is not yet loaded. If the relationship is not loaded - it will always return `null`. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - post.get('comments').then(function(comments) { - commentsRef.value() === comments - }) - ``` - - @method value - @return {DS.ManyArray} - */ - value() { - if (this._isLoaded()) { - return this.hasManyRelationship.manyArray; - } - - return null; - } - - /** - Loads the relationship if it is not already loaded. If the - relationship is already loaded this method does not trigger a new - load. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - commentsRef.load().then(function(comments) { - //... - }); - ``` - - You may also pass in an options object whose properties will be - fed forward. This enables you to pass `adapterOptions` into the - request given to the adapter via the reference. - - Example - - ```javascript - commentsRef.load({ adapterOptions: { isPrivate: true } }) - .then(function(comments) { - //... - }); - ``` - - ```app/adapters/comment.js - export default ApplicationAdapter.extend({ - findMany(store, type, id, snapshots) { - // In the adapter you will have access to adapterOptions. - let adapterOptions = snapshots[0].adapterOptions; - } - }); - ``` - - @method load - @param {Object} options the options to pass in. - @return {Promise} a promise that resolves with the ManyArray in - this has-many relationship. - */ - load(options) { - // TODO this can be simplified - if (!this._isLoaded()) { - return this.hasManyRelationship.getData(options); - } - - return resolve(this.hasManyRelationship.manyArray); - } - - /** - Reloads this has-many relationship. - - Example - - ```app/models/post.js - export default DS.Model.extend({ - comments: DS.hasMany({ async: true }) - }); - ``` - - ```javascript - let post = store.push({ - data: { - type: 'post', - id: 1, - relationships: { - comments: { - data: [{ type: 'comment', id: 1 }] - } - } - } - }); - - let commentsRef = post.hasMany('comments'); - - commentsRef.reload().then(function(comments) { - //... - }); - ``` - - You may also pass in an options object whose properties will be - fed forward. This enables you to pass `adapterOptions` into the - request given to the adapter via the reference. A full example - can be found in the `load` method. - - Example - - ```javascript - commentsRef.reload({ adapterOptions: { isPrivate: true } }) - ``` - - @method reload - @param {Object} options the options to pass in. - @return {Promise} a promise that resolves with the ManyArray in this has-many relationship. - */ - reload(options) { - return this.hasManyRelationship.reload(options); - } -} diff --git a/addon/-legacy-private/system/references/reference.js b/addon/-legacy-private/system/references/reference.js deleted file mode 100644 index bdf669d3ae4..00000000000 --- a/addon/-legacy-private/system/references/reference.js +++ /dev/null @@ -1,10 +0,0 @@ -var Reference = function(store, internalModel) { - this.store = store; - this.internalModel = internalModel; -}; - -Reference.prototype = { - constructor: Reference, -}; - -export default Reference; diff --git a/addon/-legacy-private/system/relationships/belongs-to.js b/addon/-legacy-private/system/relationships/belongs-to.js deleted file mode 100644 index 155551c025b..00000000000 --- a/addon/-legacy-private/system/relationships/belongs-to.js +++ /dev/null @@ -1,143 +0,0 @@ -import { computed } from '@ember/object'; -import { assert, warn, inspect } from '@ember/debug'; -import normalizeModelName from '../normalize-model-name'; - -/** - `DS.belongsTo` is used to define One-To-One and One-To-Many - relationships on a [DS.Model](/api/data/classes/DS.Model.html). - - - `DS.belongsTo` takes an optional hash as a second parameter, currently - supported options are: - - - `async`: A boolean value used to explicitly declare this to be an async relationship. - - `inverse`: A string used to identify the inverse property on a - related model in a One-To-Many relationship. See [Explicit Inverses](#toc_explicit-inverses) - - #### One-To-One - To declare a one-to-one relationship between two models, use - `DS.belongsTo`: - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - profile: DS.belongsTo('profile') - }); - ``` - - ```app/models/profile.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - user: DS.belongsTo('user') - }); - ``` - - #### One-To-Many - To declare a one-to-many relationship between two models, use - `DS.belongsTo` in combination with `DS.hasMany`, like this: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - comments: DS.hasMany('comment') - }); - ``` - - ```app/models/comment.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - post: DS.belongsTo('post') - }); - ``` - - You can avoid passing a string as the first parameter. In that case Ember Data - will infer the type from the key name. - - ```app/models/comment.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - post: DS.belongsTo() - }); - ``` - - will lookup for a Post type. - - @namespace - @method belongsTo - @for DS - @param {String} modelName (optional) type of the relationship - @param {Object} options (optional) a hash of options - @return {Ember.computed} relationship -*/ -export default function belongsTo(modelName, options) { - let opts, userEnteredModelName; - if (typeof modelName === 'object') { - opts = modelName; - userEnteredModelName = undefined; - } else { - opts = options; - userEnteredModelName = modelName; - } - - if (typeof userEnteredModelName === 'string') { - userEnteredModelName = normalizeModelName(userEnteredModelName); - } - - assert( - 'The first argument to DS.belongsTo must be a string representing a model type key, not an instance of ' + - inspect(userEnteredModelName) + - ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", - typeof userEnteredModelName === 'string' || typeof userEnteredModelName === 'undefined' - ); - - opts = opts || {}; - - let meta = { - type: userEnteredModelName, - isRelationship: true, - options: opts, - kind: 'belongsTo', - name: 'Belongs To', - key: null, - }; - - return computed({ - get(key) { - if (opts.hasOwnProperty('serialize')) { - warn( - `You provided a serialize option on the "${key}" property in the "${ - this._internalModel.modelName - }" class, this belongs in the serializer. See DS.Serializer and it's implementations https://emberjs.com/api/data/classes/DS.Serializer.html`, - false, - { - id: 'ds.model.serialize-option-in-belongs-to', - } - ); - } - - if (opts.hasOwnProperty('embedded')) { - warn( - `You provided an embedded option on the "${key}" property in the "${ - this._internalModel.modelName - }" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin https://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html`, - false, - { - id: 'ds.model.embedded-option-in-belongs-to', - } - ); - } - - return this._internalModel._relationships.get(key).getData(); - }, - set(key, value) { - this._internalModel.setDirtyBelongsTo(key, value); - - return this._internalModel._relationships.get(key).getData(); - }, - }).meta(meta); -} diff --git a/addon/-legacy-private/system/relationships/ext.js b/addon/-legacy-private/system/relationships/ext.js deleted file mode 100644 index d35608b5583..00000000000 --- a/addon/-legacy-private/system/relationships/ext.js +++ /dev/null @@ -1,70 +0,0 @@ -import { A } from '@ember/array'; -import { computed, get } from '@ember/object'; -import MapWithDefault from '../map-with-default'; -import Map from '../map'; -import { assert } from '@ember/debug'; -import { typeForRelationshipMeta, relationshipFromMeta } from '../relationship-meta'; - -export const relationshipsDescriptor = computed(function() { - let map = new MapWithDefault({ - defaultValue() { - return []; - }, - }); - - let relationshipsByName = get(this, 'relationshipsByName'); - - // Loop through each computed property on the class - relationshipsByName.forEach(desc => { - let relationshipsForType = map.get(desc.type); - relationshipsForType.push(desc); - }); - - return map; -}).readOnly(); - -export const relatedTypesDescriptor = computed(function() { - let modelName; - let types = A(); - - // Loop through each computed property on the class, - // and create an array of the unique types involved - // in relationships - this.eachComputedProperty((name, meta) => { - if (meta.isRelationship) { - meta.key = name; - modelName = typeForRelationshipMeta(meta); - - assert( - `You specified a hasMany (${meta.type}) on ${meta.parentType} but ${ - meta.type - } was not found.`, - modelName - ); - - if (!types.includes(modelName)) { - assert( - `Trying to sideload ${name} on ${this.toString()} but the type doesn't exist.`, - !!modelName - ); - types.push(modelName); - } - } - }); - - return types; -}).readOnly(); - -export const relationshipsByNameDescriptor = computed(function() { - let map = new Map(); - - this.eachComputedProperty((name, meta) => { - if (meta.isRelationship) { - meta.key = name; - meta.name = name; - map.set(name, relationshipFromMeta(meta)); - } - }); - - return map; -}).readOnly(); diff --git a/addon/-legacy-private/system/relationships/has-many.js b/addon/-legacy-private/system/relationships/has-many.js deleted file mode 100644 index e64d566ff08..00000000000 --- a/addon/-legacy-private/system/relationships/has-many.js +++ /dev/null @@ -1,156 +0,0 @@ -/** - @module ember-data -*/ -import { computed } from '@ember/object'; -import { assert, inspect } from '@ember/debug'; -import normalizeModelName from '../normalize-model-name'; - -/** - `DS.hasMany` is used to define One-To-Many and Many-To-Many - relationships on a [DS.Model](/api/data/classes/DS.Model.html). - - `DS.hasMany` takes an optional hash as a second parameter, currently - supported options are: - - - `async`: A boolean value used to explicitly declare this to be an async relationship. - - `inverse`: A string used to identify the inverse property on a related model. - - #### One-To-Many - To declare a one-to-many relationship between two models, use - `DS.belongsTo` in combination with `DS.hasMany`, like this: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - comments: DS.hasMany('comment') - }); - ``` - - ```app/models/comment.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - post: DS.belongsTo('post') - }); - ``` - - #### Many-To-Many - To declare a many-to-many relationship between two models, use - `DS.hasMany`: - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - tags: DS.hasMany('tag') - }); - ``` - - ```app/models/tag.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - posts: DS.hasMany('post') - }); - ``` - - You can avoid passing a string as the first parameter. In that case Ember Data - will infer the type from the singularized key name. - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - tags: DS.hasMany() - }); - ``` - - will lookup for a Tag type. - - #### Explicit Inverses - - Ember Data will do its best to discover which relationships map to - one another. In the one-to-many code above, for example, Ember Data - can figure out that changing the `comments` relationship should update - the `post` relationship on the inverse because post is the only - relationship to that model. - - However, sometimes you may have multiple `belongsTo`/`hasMany` for the - same type. You can specify which property on the related model is - the inverse using `DS.hasMany`'s `inverse` option: - - ```app/models/comment.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - onePost: DS.belongsTo('post'), - twoPost: DS.belongsTo('post'), - redPost: DS.belongsTo('post'), - bluePost: DS.belongsTo('post') - }); - ``` - - ```app/models/post.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - comments: DS.hasMany('comment', { - inverse: 'redPost' - }) - }); - ``` - - You can also specify an inverse on a `belongsTo`, which works how - you'd expect. - - @namespace - @method hasMany - @for DS - @param {String} type (optional) type of the relationship - @param {Object} options (optional) a hash of options - @return {Ember.computed} relationship -*/ -export default function hasMany(type, options) { - if (typeof type === 'object') { - options = type; - type = undefined; - } - - assert( - `The first argument to DS.hasMany must be a string representing a model type key, not an instance of ${inspect( - type - )}. E.g., to define a relation to the Comment model, use DS.hasMany('comment')`, - typeof type === 'string' || typeof type === 'undefined' - ); - - options = options || {}; - - if (typeof type === 'string') { - type = normalizeModelName(type); - } - - // Metadata about relationships is stored on the meta of - // the relationship. This is used for introspection and - // serialization. Note that `key` is populated lazily - // the first time the CP is called. - let meta = { - type, - options, - isRelationship: true, - kind: 'hasMany', - name: 'Has Many', - key: null, - }; - - return computed({ - get(key) { - return this._internalModel._relationships.get(key).getData(); - }, - set(key, records) { - this._internalModel.setDirtyHasMany(key, records); - - return this._internalModel._relationships.get(key).getData(); - }, - }).meta(meta); -} diff --git a/addon/-legacy-private/system/relationships/relationship-payloads-manager.js b/addon/-legacy-private/system/relationships/relationship-payloads-manager.js deleted file mode 100644 index 64282e729cf..00000000000 --- a/addon/-legacy-private/system/relationships/relationship-payloads-manager.js +++ /dev/null @@ -1,346 +0,0 @@ -import { get } from '@ember/object'; -// import { DEBUG } from '@glimmer/env'; -import { assert } from '@ember/debug'; -import { default as RelationshipPayloads, TypeCache } from './relationship-payloads'; - -/** - Manages relationship payloads for a given store, for uninitialized - relationships. Acts as a single source of truth (of payloads) for both sides - of an uninitialized relationship so they can agree on the most up-to-date - payload received without needing too much eager processing when those payloads - are pushed into the store. - - This minimizes the work spent on relationships that are never initialized. - - Once relationships are initialized, their state is managed in a relationship - state object (eg BelongsToRelationship or ManyRelationship). - - - @example - - let relationshipPayloadsManager = new RelationshipPayloadsManager(store); - - const User = DS.Model.extend({ - hobbies: DS.hasMany('hobby') - }); - - const Hobby = DS.Model.extend({ - user: DS.belongsTo('user') - }); - - let userPayload = { - data: { - id: 1, - type: 'user', - relationships: { - hobbies: { - data: [{ - id: 2, - type: 'hobby' - }] - } - } - }, - }; - relationshipPayloadsManager.push('user', 1, userPayload.data.relationships); - - relationshipPayloadsManager.get('hobby', 2, 'user') === { - { - data: { - id: 1, - type: 'user' - } - } - } - - @private - @class RelationshipPayloadsManager -*/ -export default class RelationshipPayloadsManager { - constructor(store) { - this._store = store; - // cache of `RelationshipPayload`s - this._cache = Object.create(null); - this._inverseLookupCache = new TypeCache(); - } - - /** - Find the payload for the given relationship of the given model. - - Returns the payload for the given relationship, whether raw or computed from - the payload of the inverse relationship. - - @example - - relationshipPayloadsManager.get('hobby', 2, 'user') === { - { - data: { - id: 1, - type: 'user' - } - } - } - - @method - */ - get(modelName, id, relationshipName) { - let relationshipPayloads = this._getRelationshipPayloads(modelName, relationshipName, false); - return relationshipPayloads && relationshipPayloads.get(modelName, id, relationshipName); - } - - /** - Push a model's relationships payload into this cache. - - @example - - let userPayload = { - data: { - id: 1, - type: 'user', - relationships: { - hobbies: { - data: [{ - id: 2, - type: 'hobby' - }] - } - } - }, - }; - relationshipPayloadsManager.push('user', 1, userPayload.data.relationships); - - @method - */ - push(modelName, id, relationshipsData) { - if (!relationshipsData) { - return; - } - - Object.keys(relationshipsData).forEach(key => { - let relationshipPayloads = this._getRelationshipPayloads(modelName, key, true); - if (relationshipPayloads) { - relationshipPayloads.push(modelName, id, key, relationshipsData[key]); - } - }); - } - - /** - Unload a model's relationships payload. - - @method - */ - unload(modelName, id) { - let modelClass = this._store.modelFor(modelName); - let relationshipsByName = get(modelClass, 'relationshipsByName'); - relationshipsByName.forEach((_, relationshipName) => { - let relationshipPayloads = this._getRelationshipPayloads(modelName, relationshipName, false); - if (relationshipPayloads) { - relationshipPayloads.unload(modelName, id, relationshipName); - } - }); - } - - /** - Find the RelationshipPayloads object for the given relationship. The same - RelationshipPayloads object is returned for either side of a relationship. - - @example - - const User = DS.Model.extend({ - hobbies: DS.hasMany('hobby') - }); - - const Hobby = DS.Model.extend({ - user: DS.belongsTo('user') - }); - - relationshipPayloads.get('user', 'hobbies') === relationshipPayloads.get('hobby', 'user'); - - The signature has a somewhat large arity to avoid extra work, such as - a) string manipulation & allocation with `modelName` and - `relationshipName` - b) repeatedly getting `relationshipsByName` via `Ember.get` - - - @private - @method - */ - _getRelationshipPayloads(modelName, relationshipName, init) { - let relInfo = this.getRelationshipInfo(modelName, relationshipName); - - if (relInfo === null) { - return; - } - - let cache = this._cache[relInfo.lhs_key]; - - if (!cache && init) { - return this._initializeRelationshipPayloads(relInfo); - } - - return cache; - } - - getRelationshipInfo(modelName, relationshipName) { - let inverseCache = this._inverseLookupCache; - let store = this._store; - let cached = inverseCache.get(modelName, relationshipName); - - // CASE: We have a cached resolution (null if no relationship exists) - if (cached !== undefined) { - return cached; - } - - let modelClass = store.modelFor(modelName); - let relationshipsByName = get(modelClass, 'relationshipsByName'); - - // CASE: We don't have a relationship at all - if (!relationshipsByName.has(relationshipName)) { - inverseCache.set(modelName, relationshipName, null); - return null; - } - - let relationshipMeta = relationshipsByName.get(relationshipName); - let inverseMeta; - - // CASE: Inverse is explicitly null - if (relationshipMeta.options && relationshipMeta.options.inverse === null) { - inverseMeta = null; - } else { - inverseMeta = modelClass.inverseFor(relationshipName, store); - } - - let selfIsPolymorphic = - relationshipMeta.options !== undefined && relationshipMeta.options.polymorphic === true; - let inverseBaseModelName = relationshipMeta.type; - - // CASE: We have no inverse - if (!inverseMeta) { - let info = { - lhs_key: `${modelName}:${relationshipName}`, - lhs_modelNames: [modelName], - lhs_baseModelName: modelName, - lhs_relationshipName: relationshipName, - lhs_relationshipMeta: relationshipMeta, - lhs_isPolymorphic: selfIsPolymorphic, - rhs_key: '', - rhs_modelNames: [], - rhs_baseModelName: inverseBaseModelName, - rhs_relationshipName: '', - rhs_relationshipMeta: null, - rhs_isPolymorphic: false, - hasInverse: false, - isSelfReferential: false, // modelName === inverseBaseModelName, - isReflexive: false, - }; - - inverseCache.set(modelName, relationshipName, info); - - return info; - } - - // CASE: We do have an inverse - - let inverseRelationshipName = inverseMeta.name; - let inverseRelationshipMeta = get(inverseMeta.type, 'relationshipsByName').get( - inverseRelationshipName - ); - let baseModelName = inverseRelationshipMeta.type; - let isSelfReferential = baseModelName === inverseBaseModelName; - - // TODO we want to assert this but this breaks all of our shoddily written tests - /* - if (DEBUG) { - let inverseDoubleCheck = inverseMeta.type.inverseFor(inverseRelationshipName, store); - - assert(`The ${inverseBaseModelName}:${inverseRelationshipName} relationship declares 'inverse: null', but it was resolved as the inverse for ${baseModelName}:${relationshipName}.`, inverseDoubleCheck); - } - */ - - // CASE: We may have already discovered the inverse for the baseModelName - // CASE: We have already discovered the inverse - cached = - inverseCache.get(baseModelName, relationshipName) || - inverseCache.get(inverseBaseModelName, inverseRelationshipName); - if (cached) { - // TODO this assert can be removed if the above assert is enabled - assert( - `The ${inverseBaseModelName}:${inverseRelationshipName} relationship declares 'inverse: null', but it was resolved as the inverse for ${baseModelName}:${relationshipName}.`, - cached.hasInverse !== false - ); - - let isLHS = cached.lhs_baseModelName === baseModelName; - let modelNames = isLHS ? cached.lhs_modelNames : cached.rhs_modelNames; - // make this lookup easier in the future by caching the key - modelNames.push(modelName); - inverseCache.set(modelName, relationshipName, cached); - - return cached; - } - - let info = { - lhs_key: `${baseModelName}:${relationshipName}`, - lhs_modelNames: [modelName], - lhs_baseModelName: baseModelName, - lhs_relationshipName: relationshipName, - lhs_relationshipMeta: relationshipMeta, - lhs_isPolymorphic: selfIsPolymorphic, - rhs_key: `${inverseBaseModelName}:${inverseRelationshipName}`, - rhs_modelNames: [], - rhs_baseModelName: inverseBaseModelName, - rhs_relationshipName: inverseRelationshipName, - rhs_relationshipMeta: inverseRelationshipMeta, - rhs_isPolymorphic: - inverseRelationshipMeta.options !== undefined && - inverseRelationshipMeta.options.polymorphic === true, - hasInverse: true, - isSelfReferential, - isReflexive: isSelfReferential && relationshipName === inverseRelationshipName, - }; - - // Create entries for the baseModelName as well as modelName to speed up - // inverse lookups - inverseCache.set(baseModelName, relationshipName, info); - inverseCache.set(modelName, relationshipName, info); - - // Greedily populate the inverse - inverseCache.set(inverseBaseModelName, inverseRelationshipName, info); - - return info; - } - - /** - Create the `RelationshipsPayload` for the relationship `modelName`, `relationshipName`, and its inverse. - - @private - @method - */ - _initializeRelationshipPayloads(relInfo) { - let lhsKey = relInfo.lhs_key; - let rhsKey = relInfo.rhs_key; - let existingPayloads = this._cache[lhsKey]; - - if (relInfo.hasInverse === true && relInfo.rhs_isPolymorphic === true) { - existingPayloads = this._cache[rhsKey]; - - if (existingPayloads !== undefined) { - this._cache[lhsKey] = existingPayloads; - return existingPayloads; - } - } - - // populate the cache for both sides of the relationship, as they both use - // the same `RelationshipPayloads`. - // - // This works out better than creating a single common key, because to - // compute that key we would need to do work to look up the inverse - // - let cache = (this._cache[lhsKey] = new RelationshipPayloads(relInfo)); - - if (relInfo.hasInverse === true) { - this._cache[rhsKey] = cache; - } - - return cache; - } -} diff --git a/addon/-legacy-private/system/relationships/relationship-payloads.js b/addon/-legacy-private/system/relationships/relationship-payloads.js deleted file mode 100644 index 478c345eee8..00000000000 --- a/addon/-legacy-private/system/relationships/relationship-payloads.js +++ /dev/null @@ -1,499 +0,0 @@ -import { assert } from '@ember/debug'; - -/** - * Merge data,meta,links information forward to the next payload - * if required. Latest data will always win. - * - * @param oldPayload - * @param newPayload - */ -function mergeForwardPayload(oldPayload, newPayload) { - if (oldPayload && oldPayload.data !== undefined && newPayload.data === undefined) { - newPayload.data = oldPayload.data; - } - - /* - _partialData is has-many relationship data that has been discovered via - inverses in the absence of canonical `data` availability from the primary - payload. - - We can't merge this data into `data` as that would trick has-many relationships - into believing they know their complete membership. Anytime we find canonical - data from the primary record, this partial data is discarded. If no canonical - data is ever discovered, the partial data will be loaded by the relationship - in a way that correctly preserves the `stale` relationship state. - */ - if (newPayload.data === undefined && oldPayload && oldPayload._partialData !== undefined) { - newPayload._partialData = oldPayload._partialData; - } - - if (oldPayload && oldPayload.meta !== undefined && newPayload.meta === undefined) { - newPayload.meta = oldPayload.meta; - } - - if (oldPayload && oldPayload.links !== undefined && newPayload.links === undefined) { - newPayload.links = oldPayload.links; - } -} - -// TODO this is now VERY similar to the identity/internal-model map -// so we should probably generalize -export class TypeCache { - constructor() { - this.types = Object.create(null); - } - get(modelName, id) { - let { types } = this; - - if (types[modelName] !== undefined) { - return types[modelName][id]; - } - } - - set(modelName, id, payload) { - let { types } = this; - let typeMap = types[modelName]; - - if (typeMap === undefined) { - typeMap = types[modelName] = Object.create(null); - } - - typeMap[id] = payload; - } - - delete(modelName, id) { - let { types } = this; - - if (types[modelName] !== undefined) { - delete types[modelName][id]; - } - } -} - -/** - Manages the payloads for both sides of a single relationship, across all model - instances. - - For example, with - - const User = DS.Model.extend({ - hobbies: DS.hasMany('hobby') - }); - - const Hobby = DS.Model.extend({ - user: DS.belongsTo('user') - }); - - let relationshipPayloads = new RelationshipPayloads('user', 'hobbies', 'hobby', 'user'); - - let userPayload = { - data: { - id: 1, - type: 'user', - relationships: { - hobbies: { - data: [{ - id: 2, - type: 'hobby', - }] - } - } - } - }; - - // here we expect the payload of the individual relationship - relationshipPayloads.push('user', 1, 'hobbies', userPayload.data.relationships.hobbies); - - relationshipPayloads.get('user', 1, 'hobbies'); - relationshipPayloads.get('hobby', 2, 'user'); - - @class RelationshipPayloads - @private - */ -export default class RelationshipPayloads { - constructor(relInfo) { - this._relInfo = relInfo; - - // a map of id -> payloads for the left hand side of the relationship. - this.lhs_payloads = new TypeCache(); - this.rhs_payloads = relInfo.isReflexive ? this.lhs_payloads : new TypeCache(); - - // When we push relationship payloads, just stash them in a queue until - // somebody actually asks for one of them. - // - // This is a queue of the relationship payloads that have been pushed for - // either side of this relationship - this._pendingPayloads = []; - } - - /** - Get the payload for the relationship of an individual record. - - This might return the raw payload as pushed into the store, or one computed - from the payload of the inverse relationship. - - @method - */ - get(modelName, id, relationshipName) { - this._flushPending(); - - if (this._isLHS(modelName, relationshipName)) { - return this.lhs_payloads.get(modelName, id); - } else { - assert( - `${modelName}:${relationshipName} is not either side of this relationship, ${ - this._relInfo.lhs_key - }<->${this._relInfo.rhs_key}`, - this._isRHS(modelName, relationshipName) - ); - return this.rhs_payloads.get(modelName, id); - } - } - - /** - Push a relationship payload for an individual record. - - This will make the payload available later for both this relationship and its inverse. - - @method - */ - push(modelName, id, relationshipName, relationshipData) { - this._pendingPayloads.push([modelName, id, relationshipName, relationshipData]); - } - - /** - Unload the relationship payload for an individual record. - - This does not unload the inverse relationship payload. - - @method - */ - unload(modelName, id, relationshipName) { - this._flushPending(); - - if (this._isLHS(modelName, relationshipName)) { - this.lhs_payloads.delete(modelName, id); - } else { - assert( - `${modelName}:${relationshipName} is not either side of this relationship, ${ - this._relInfo.lhs_baseModelName - }:${this._relInfo.lhs_relationshipName}<->${this._relInfo.rhs_baseModelName}:${ - this._relInfo.rhs_relationshipName - }`, - this._isRHS(modelName, relationshipName) - ); - this.rhs_payloads.delete(modelName, id); - } - } - - /** - @return {boolean} true iff `modelName` and `relationshipName` refer to the - left hand side of this relationship, as opposed to the right hand side. - - @method - */ - _isLHS(modelName, relationshipName) { - let relInfo = this._relInfo; - let isSelfReferential = relInfo.isSelfReferential; - let isRelationship = relationshipName === relInfo.lhs_relationshipName; - - if (isRelationship === true) { - return ( - isSelfReferential === true || // itself - modelName === relInfo.lhs_baseModelName || // base or non-polymorphic - relInfo.lhs_modelNames.indexOf(modelName) !== -1 - ); // polymorphic - } - - return false; - } - - /** - @return {boolean} true iff `modelName` and `relationshipName` refer to the - right hand side of this relationship, as opposed to the left hand side. - - @method - */ - _isRHS(modelName, relationshipName) { - let relInfo = this._relInfo; - let isSelfReferential = relInfo.isSelfReferential; - let isRelationship = relationshipName === relInfo.rhs_relationshipName; - - if (isRelationship === true) { - return ( - isSelfReferential === true || // itself - modelName === relInfo.rhs_baseModelName || // base or non-polymorphic - relInfo.rhs_modelNames.indexOf(modelName) !== -1 - ); // polymorphic - } - - return false; - } - - _flushPending() { - if (this._pendingPayloads.length === 0) { - return; - } - - let payloadsToBeProcessed = this._pendingPayloads.splice(0, this._pendingPayloads.length); - for (let i = 0; i < payloadsToBeProcessed.length; ++i) { - let modelName = payloadsToBeProcessed[i][0]; - let id = payloadsToBeProcessed[i][1]; - let relationshipName = payloadsToBeProcessed[i][2]; - let relationshipData = payloadsToBeProcessed[i][3]; - - // TODO: maybe delay this allocation slightly? - let inverseRelationshipData = { - data: { - id: id, - type: modelName, - }, - }; - - // start flushing this individual payload. The logic is the same whether - // it's for the left hand side of the relationship or the right hand side, - // except the role of primary and inverse idToPayloads is reversed - // - let previousPayload; - let payloadMap; - let inversePayloadMap; - let inverseIsMany; - if (this._isLHS(modelName, relationshipName)) { - previousPayload = this.lhs_payloads.get(modelName, id); - payloadMap = this.lhs_payloads; - inversePayloadMap = this.rhs_payloads; - inverseIsMany = this._rhsRelationshipIsMany; - } else { - assert( - `${modelName}:${relationshipName} is not either side of this relationship, ${ - this._relInfo.lhs_key - }<->${this._relInfo.rhs_key}`, - this._isRHS(modelName, relationshipName) - ); - previousPayload = this.rhs_payloads.get(modelName, id); - payloadMap = this.rhs_payloads; - inversePayloadMap = this.lhs_payloads; - inverseIsMany = this._lhsRelationshipIsMany; - } - - // actually flush this individual payload - // - // We remove the previous inverse before populating our current one - // because we may have multiple payloads for the same relationship, in - // which case the last one wins. - // - // eg if user hasMany helicopters, and helicopter belongsTo user and we see - // - // [{ - // data: { - // id: 1, - // type: 'helicopter', - // relationships: { - // user: { - // id: 2, - // type: 'user' - // } - // } - // } - // }, { - // data: { - // id: 1, - // type: 'helicopter', - // relationships: { - // user: { - // id: 4, - // type: 'user' - // } - // } - // } - // }] - // - // Then we will initially have set user:2 as having helicopter:1, which we - // need to remove before adding helicopter:1 to user:4 - // - // only remove relationship information before adding if there is relationshipData.data - // * null is considered new information "empty", and it should win - // * undefined is NOT considered new information, we should keep original state - // * anything else is considered new information, and it should win - let isMatchingIdentifier = this._isMatchingIdentifier( - relationshipData && relationshipData.data, - previousPayload && previousPayload.data - ); - - if (relationshipData.data !== undefined) { - if (!isMatchingIdentifier) { - this._removeInverse(id, previousPayload, inversePayloadMap); - } - } - - mergeForwardPayload(previousPayload, relationshipData); - payloadMap.set(modelName, id, relationshipData); - - if (!isMatchingIdentifier) { - this._populateInverse( - relationshipData, - inverseRelationshipData, - inversePayloadMap, - inverseIsMany - ); - } - } - } - - _isMatchingIdentifier(a, b) { - return a && b && a.type === b.type && a.id === b.id && !Array.isArray(a) && !Array.isArray(b); - } - - /** - Populate the inverse relationship for `relationshipData`. - - If `relationshipData` is an array (eg because the relationship is hasMany) - this means populate each inverse, otherwise populate only the single - inverse. - - @private - @method - */ - _populateInverse(relationshipData, inversePayload, inversePayloadMap, inverseIsMany) { - if (!relationshipData.data) { - // This id doesn't have an inverse, eg a belongsTo with a payload - // { data: null }, so there's nothing to populate - return; - } - - if (Array.isArray(relationshipData.data)) { - for (let i = 0; i < relationshipData.data.length; ++i) { - let resourceIdentifier = relationshipData.data[i]; - this._addToInverse(inversePayload, resourceIdentifier, inversePayloadMap, inverseIsMany); - } - } else { - let resourceIdentifier = relationshipData.data; - this._addToInverse(inversePayload, resourceIdentifier, inversePayloadMap, inverseIsMany); - } - } - - /** - Actually add `inversePayload` to `inverseIdToPayloads`. This is part of - `_populateInverse` after we've normalized the case of `relationshipData` - being either an array or a pojo. - - We still have to handle the case that the *inverse* relationship payload may - be an array or pojo. - - @private - @method - */ - _addToInverse(inversePayload, resourceIdentifier, inversePayloadMap, inverseIsMany) { - let relInfo = this._relInfo; - let inverseData = inversePayload.data; - - if (relInfo.isReflexive && inverseData && inverseData.id === resourceIdentifier.id) { - // eg .friends = [{ id: 1, type: 'user' }] - return; - } - - let existingPayload = inversePayloadMap.get(resourceIdentifier.type, resourceIdentifier.id); - - if (existingPayload) { - // There already is an inverse, either add or overwrite depending on - // whether the inverse is a many relationship or not - // - if (inverseIsMany) { - let existingData = existingPayload.data; - - // in the case of a hasMany - // we do not want create a `data` array where there was none before - // if we also have links, which this would indicate - if (existingData) { - existingData.push(inversePayload.data); - } else { - existingPayload._partialData = existingPayload._partialData || []; - existingPayload._partialData.push(inversePayload.data); - } - } else { - mergeForwardPayload(existingPayload, inversePayload); - inversePayloadMap.set(resourceIdentifier.type, resourceIdentifier.id, inversePayload); - } - } else { - // first time we're populating the inverse side - // - if (inverseIsMany) { - inversePayloadMap.set(resourceIdentifier.type, resourceIdentifier.id, { - _partialData: [inversePayload.data], - }); - } else { - inversePayloadMap.set(resourceIdentifier.type, resourceIdentifier.id, inversePayload); - } - } - } - - get _lhsRelationshipIsMany() { - let meta = this._relInfo.lhs_relationshipMeta; - return meta !== null && meta.kind === 'hasMany'; - } - - get _rhsRelationshipIsMany() { - let meta = this._relInfo.rhs_relationshipMeta; - return meta !== null && meta.kind === 'hasMany'; - } - - /** - Remove the relationship in `previousPayload` from its inverse(s), because - this relationship payload has just been updated (eg because the same - relationship had multiple payloads pushed before the relationship was - initialized). - - @method - */ - _removeInverse(id, previousPayload, inversePayloadMap) { - let data = previousPayload && previousPayload.data; - let partialData = previousPayload && previousPayload._partialData; - let maybeData = data || partialData; - - if (!maybeData) { - // either this is the first time we've seen a payload for this id, or its - // previous payload indicated that it had no inverse, eg a belongsTo - // relationship with payload { data: null } - // - // In either case there's nothing that needs to be removed from the - // inverse map of payloads - return; - } - - if (Array.isArray(maybeData)) { - // TODO: diff rather than removeall addall? - for (let i = 0; i < maybeData.length; ++i) { - const resourceIdentifier = maybeData[i]; - this._removeFromInverse(id, resourceIdentifier, inversePayloadMap); - } - } else { - this._removeFromInverse(id, data, inversePayloadMap); - } - } - - /** - Remove `id` from its inverse record with id `inverseId`. If the inverse - relationship is a belongsTo, this means just setting it to null, if the - inverse relationship is a hasMany, then remove that id from its array of ids. - - @method - */ - _removeFromInverse(id, resourceIdentifier, inversePayloads) { - let inversePayload = inversePayloads.get(resourceIdentifier.type, resourceIdentifier.id); - let data = inversePayload && inversePayload.data; - let partialData = inversePayload && inversePayload._partialData; - - if (!data && !partialData) { - return; - } - - if (Array.isArray(data)) { - inversePayload.data = data.filter(x => x.id !== id); - } else if (Array.isArray(partialData)) { - inversePayload._partialData = partialData.filter(x => x.id !== id); - } else { - // this merges forward links and meta - inversePayload.data = null; - } - } -} diff --git a/addon/-legacy-private/system/relationships/state/belongs-to.js b/addon/-legacy-private/system/relationships/state/belongs-to.js deleted file mode 100644 index 8c7d0001c79..00000000000 --- a/addon/-legacy-private/system/relationships/state/belongs-to.js +++ /dev/null @@ -1,324 +0,0 @@ -import { resolve } from 'rsvp'; -import { assert } from '@ember/debug'; -import { assertPolymorphicType } from 'ember-data/-debug'; -import { PromiseBelongsTo, PromiseObject } from '../../promise-proxies'; -import Relationship from './relationship'; - -export default class BelongsToRelationship extends Relationship { - constructor(store, internalModel, inverseKey, relationshipMeta) { - super(store, internalModel, inverseKey, relationshipMeta); - this.inverseInternalModel = null; - this.canonicalState = null; - this._promiseProxy = null; - } - - /** - * Flag indicating whether all inverse records are available - * - * true if the inverse exists and is loaded (not empty) - * true if there is no inverse - * false if the inverse exists and is not loaded (empty) - * - * @property - * @return {boolean} - */ - get allInverseRecordsAreLoaded() { - let internalModel = this.inverseInternalModel; - let isEmpty = internalModel !== null && internalModel.isEmpty(); - - return !isEmpty; - } - - setInternalModel(internalModel) { - if (internalModel) { - this.addInternalModel(internalModel); - } else if (this.inverseInternalModel) { - this.removeInternalModel(this.inverseInternalModel); - } - - this.setHasAnyRelationshipData(true); - this.setRelationshipIsStale(false); - this.setRelationshipIsEmpty(false); - } - - setCanonicalInternalModel(internalModel) { - if (internalModel) { - this.addCanonicalInternalModel(internalModel); - } else if (this.canonicalState) { - this.removeCanonicalInternalModel(this.canonicalState); - } - this.flushCanonicalLater(); - } - - setInitialCanonicalInternalModel(internalModel) { - if (!internalModel) { - return; - } - - // When we initialize a belongsTo relationship, we want to avoid work like - // notifying our internalModel that we've "changed" and excessive thrash on - // setting up inverse relationships - this.canonicalMembers.add(internalModel); - this.members.add(internalModel); - this.inverseInternalModel = this.canonicalState = internalModel; - this.setupInverseRelationship(internalModel); - } - - addCanonicalInternalModel(internalModel) { - if (this.canonicalMembers.has(internalModel)) { - return; - } - - if (this.canonicalState) { - this.removeCanonicalInternalModel(this.canonicalState); - } - - this.canonicalState = internalModel; - this.setHasAnyRelationshipData(true); - this.setRelationshipIsEmpty(false); - super.addCanonicalInternalModel(internalModel); - } - - inverseDidDematerialize() { - super.inverseDidDematerialize(this.inverseInternalModel); - this.notifyBelongsToChange(); - } - - removeCompletelyFromOwn(internalModel) { - super.removeCompletelyFromOwn(internalModel); - - if (this.canonicalState === internalModel) { - this.canonicalState = null; - } - - if (this.inverseInternalModel === internalModel) { - this.inverseInternalModel = null; - this.notifyBelongsToChange(); - } - } - - removeCompletelyFromInverse() { - super.removeCompletelyFromInverse(); - - this.inverseInternalModel = null; - } - - flushCanonical() { - //temporary fix to not remove newly created records if server returned null. - //TODO remove once we have proper diffing - if (this.inverseInternalModel && this.inverseInternalModel.isNew() && !this.canonicalState) { - return; - } - if (this.inverseInternalModel !== this.canonicalState) { - this.inverseInternalModel = this.canonicalState; - this._promiseProxy = null; - this.notifyBelongsToChange(); - } - - super.flushCanonical(); - } - - addInternalModel(internalModel) { - if (this.members.has(internalModel)) { - return; - } - - assertPolymorphicType(this.internalModel, this.relationshipMeta, internalModel, this.store); - - if (this.inverseInternalModel) { - this.removeInternalModel(this.inverseInternalModel); - } - - this.inverseInternalModel = internalModel; - super.addInternalModel(internalModel); - this.notifyBelongsToChange(); - } - - setRecordPromise(belongsToPromise) { - assert( - 'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.', - belongsToPromise instanceof PromiseObject - ); - - let content = belongsToPromise.get('content'); - let promise = belongsToPromise.get('promise'); - - this.setInternalModel(content ? content._internalModel : content); - this._updateLoadingPromise(promise, content); - } - - removeInternalModelFromOwn(internalModel) { - if (!this.members.has(internalModel)) { - return; - } - this.inverseInternalModel = null; - this._promiseProxy = null; - super.removeInternalModelFromOwn(internalModel); - this.notifyBelongsToChange(); - } - - removeAllInternalModelsFromOwn() { - super.removeAllInternalModelsFromOwn(); - this.inverseInternalModel = null; - this._promiseProxy = null; - this.notifyBelongsToChange(); - } - - notifyBelongsToChange() { - if (this._promiseProxy !== null) { - let iM = this.inverseInternalModel; - - this._updateLoadingPromise(proxyRecord(iM), iM ? iM.getRecord() : null); - } - - this.internalModel.notifyBelongsToChange(this.key); - } - - removeCanonicalInternalModelFromOwn(internalModel) { - if (!this.canonicalMembers.has(internalModel)) { - return; - } - this.canonicalState = null; - this.setHasAnyRelationshipData(true); - this.setRelationshipIsEmpty(true); - super.removeCanonicalInternalModelFromOwn(internalModel); - } - - removeAllCanonicalInternalModelsFromOwn() { - super.removeAllCanonicalInternalModelsFromOwn(); - this.canonicalState = null; - } - - // called by `getData()` when a request is needed - // but no link is available - _fetchRecord(options) { - let { inverseInternalModel, shouldForceReload } = this; - - if (inverseInternalModel) { - let promise; - - if (shouldForceReload && !inverseInternalModel.isEmpty() && inverseInternalModel.hasRecord) { - // reload record, if it is already loaded - // if we have a link, we would already be in `findLink()` - promise = inverseInternalModel.getRecord().reload(options); - } else { - promise = this.store._findByInternalModel(inverseInternalModel, options); - } - - return promise; - } - - // TODO is this actually an error case? - return resolve(null); - } - - // called by `getData()` when a request is needed - // and a link is available - _fetchLink(options) { - return this.store - .findBelongsTo(this.internalModel, this.link, this.relationshipMeta, options) - .then(internalModel => { - if (internalModel) { - this.addInternalModel(internalModel); - } - return internalModel; - }); - } - - /* - While the `shouldForceReload` flag will also be true when `isForcedReload` is true, - `isForcedReload` is only `true` for an initial `getData` call during a forced reload. - Other calls must conform to the typical expectations, for instance, sync relationships - expect that their data is already loaded. - */ - getData(options, isForcedReload = false) { - //TODO(Igor) flushCanonical here once our syncing is not stupid - let record = this.inverseInternalModel ? this.inverseInternalModel.getRecord() : null; - - if (this.shouldMakeRequest()) { - let promise; - - if (this.link) { - promise = this._fetchLink(options); - } else { - promise = this._fetchRecord(options); - } - - promise = promise.then(() => handleCompletedFind(this), e => handleCompletedFind(this, e)); - - promise = promise.then(internalModel => { - return internalModel ? internalModel.getRecord() : null; - }); - - this.fetchPromise = promise; - this._updateLoadingPromise(promise); - } - - if (this.isAsync) { - if (this._promiseProxy === null) { - let promise = proxyRecord(this.inverseInternalModel); - this._updateLoadingPromise(promise, record); - } - - return this._promiseProxy; - } else { - assert( - "You looked up the '" + - this.key + - "' relationship on a '" + - this.internalModel.modelName + - "' with id " + - this.internalModel.id + - ' but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)', - record === null || !record.get('isEmpty') || isForcedReload - ); - return record; - } - } - - _createProxy(promise, content) { - return PromiseBelongsTo.create({ - _belongsToState: this, - promise, - content, - }); - } - - updateData(data, initial) { - let internalModel = this.store._pushResourceIdentifier(this, data); - if (initial) { - this.setInitialCanonicalInternalModel(internalModel); - } else { - this.setCanonicalInternalModel(internalModel); - } - } -} - -function proxyRecord(internalModel) { - let promise = internalModel; - if (internalModel && internalModel.isLoading()) { - promise = internalModel._promiseProxy; - } - - return resolve(promise).then(resolvedInternalModel => { - return resolvedInternalModel ? resolvedInternalModel.getRecord() : null; - }); -} - -function handleCompletedFind(relationship, error) { - let internalModel = relationship.inverseInternalModel; - - relationship.fetchPromise = null; - relationship.setShouldForceReload(false); - - if (error) { - relationship.setHasFailedLoadAttempt(true); - throw error; - } - - relationship.setHasFailedLoadAttempt(false); - // only set to not stale if no error is thrown - relationship.setRelationshipIsStale(false); - - return internalModel; -} diff --git a/addon/-legacy-private/system/relationships/state/create.js b/addon/-legacy-private/system/relationships/state/create.js deleted file mode 100644 index ed82b773f7c..00000000000 --- a/addon/-legacy-private/system/relationships/state/create.js +++ /dev/null @@ -1,86 +0,0 @@ -import { get } from '@ember/object'; -import ManyRelationship from './has-many'; -import BelongsToRelationship from './belongs-to'; -import { DEBUG } from '@glimmer/env'; - -function shouldFindInverse(relationshipMeta) { - let options = relationshipMeta.options; - return !(options && options.inverse === null); -} - -function createRelationshipFor(internalModel, relationshipMeta, store) { - let inverseKey; - let inverse = null; - - if (shouldFindInverse(relationshipMeta)) { - inverse = internalModel.type.inverseFor(relationshipMeta.key, store); - } else if (DEBUG) { - internalModel.type.typeForRelationship(relationshipMeta.key, store); - } - - if (inverse) { - inverseKey = inverse.name; - } - - if (relationshipMeta.kind === 'hasMany') { - return new ManyRelationship(store, internalModel, inverseKey, relationshipMeta); - } else { - return new BelongsToRelationship(store, internalModel, inverseKey, relationshipMeta); - } -} - -export default class Relationships { - constructor(internalModel) { - this.internalModel = internalModel; - this.initializedRelationships = Object.create(null); - } - - // TODO @runspired deprecate this as it was never truly a record instance - get record() { - return this.internalModel; - } - - has(key) { - return !!this.initializedRelationships[key]; - } - - forEach(cb) { - let rels = this.initializedRelationships; - Object.keys(rels).forEach(name => { - cb(name, rels[name]); - }); - } - - get(key) { - let relationships = this.initializedRelationships; - let relationship = relationships[key]; - let internalModel = this.internalModel; - - if (!relationship) { - let relationshipsByName = get(internalModel.type, 'relationshipsByName'); - let rel = relationshipsByName.get(key); - - if (!rel) { - return undefined; - } - - let relationshipPayload = internalModel.store._relationshipsPayloads.get( - internalModel.modelName, - internalModel.id, - key - ); - - relationship = relationships[key] = createRelationshipFor( - internalModel, - rel, - internalModel.store - ); - - if (relationshipPayload) { - relationship.push(relationshipPayload, true); - } - } - - return relationship; - } -} diff --git a/addon/-legacy-private/system/relationships/state/has-many.js b/addon/-legacy-private/system/relationships/state/has-many.js deleted file mode 100755 index 19a581f7020..00000000000 --- a/addon/-legacy-private/system/relationships/state/has-many.js +++ /dev/null @@ -1,454 +0,0 @@ -import { assert } from '@ember/debug'; -import { assertPolymorphicType } from 'ember-data/-debug'; -import { PromiseManyArray } from '../../promise-proxies'; -import Relationship from './relationship'; -import OrderedSet from '../../ordered-set'; -import ManyArray from '../../many-array'; -import { resolve } from 'rsvp'; - -export default class ManyRelationship extends Relationship { - constructor(store, internalModel, inverseKey, relationshipMeta) { - super(store, internalModel, inverseKey, relationshipMeta); - this.belongsToType = relationshipMeta.type; - this.canonicalState = []; - // The ManyArray for this relationship - this._manyArray = null; - // The previous ManyArray for this relationship. It will be destroyed when - // we create a new many array, but in the interim it will be updated if - // inverse internal models are unloaded. - this._retainedManyArray = null; - this._promiseProxy = null; - this._willUpdateManyArray = false; - this._pendingManyArrayUpdates = null; - } - - get currentState() { - return this.members.list; - } - - /** - * Flag indicating whether all inverse records are available - * - * true if inverse records exist and are all loaded (all not empty) - * true if there are no inverse records - * false if the inverse records exist and any are not loaded (any empty) - * - * @property - * @return {boolean} - */ - get allInverseRecordsAreLoaded() { - // check currentState for unloaded records - let hasEmptyRecords = this.currentState.reduce((hasEmptyModel, i) => { - return hasEmptyModel || i.isEmpty(); - }, false); - - // check un-synced state for unloaded records - if (!hasEmptyRecords && this.willSync) { - hasEmptyRecords = this.canonicalState.reduce((hasEmptyModel, i) => { - return hasEmptyModel || !i.isEmpty(); - }, false); - } - - return !hasEmptyRecords; - } - - _createProxy(promise, content) { - return PromiseManyArray.create({ - promise, - content, - }); - } - - get manyArray() { - assert( - `Error: relationship ${this.parentType}:${ - this.key - } has both many array and retained many array`, - this._manyArray === null || this._retainedManyArray === null - ); - - if (!this._manyArray && !this.isDestroying) { - let isLoaded = this.hasFailedLoadAttempt || this.isNew || this.allInverseRecordsAreLoaded; - - this._manyArray = ManyArray.create({ - canonicalState: this.canonicalState, - store: this.store, - relationship: this, - type: this.store.modelFor(this.belongsToType), - record: this.internalModel, - meta: this.meta, - isPolymorphic: this.isPolymorphic, - isLoaded, - }); - - if (this._retainedManyArray !== null) { - this._retainedManyArray.destroy(); - this._retainedManyArray = null; - } - } - - return this._manyArray; - } - - removeInverseRelationships() { - super.removeInverseRelationships(); - if (this._manyArray) { - this._manyArray.destroy(); - this._manyArray = null; - } - - if (this._promiseProxy) { - this._promiseProxy.destroy(); - } - } - - updateMeta(meta) { - super.updateMeta(meta); - if (this._manyArray) { - this._manyArray.set('meta', meta); - } - } - - addCanonicalInternalModel(internalModel, idx) { - if (this.canonicalMembers.has(internalModel)) { - return; - } - if (idx !== undefined) { - this.canonicalState.splice(idx, 0, internalModel); - } else { - this.canonicalState.push(internalModel); - } - super.addCanonicalInternalModel(internalModel, idx); - } - - inverseDidDematerialize(inverseInternalModel) { - super.inverseDidDematerialize(inverseInternalModel); - if (this.isAsync) { - if (this._manyArray) { - this._retainedManyArray = this._manyArray; - this._manyArray = null; - } - this._removeInternalModelFromManyArray(this._retainedManyArray, inverseInternalModel); - } - this.notifyHasManyChange(); - } - - addInternalModel(internalModel, idx) { - if (this.members.has(internalModel)) { - return; - } - - assertPolymorphicType(this.internalModel, this.relationshipMeta, internalModel, this.store); - super.addInternalModel(internalModel, idx); - this.scheduleManyArrayUpdate(internalModel, idx); - } - - scheduleManyArrayUpdate(internalModel, idx) { - if (!this._manyArray) { - return; - } - - let pending = (this._pendingManyArrayUpdates = this._pendingManyArrayUpdates || []); - pending.push(internalModel, idx); - - if (this._willUpdateManyArray === true) { - return; - } - - this._willUpdateManyArray = true; - let backburner = this.store._backburner; - - backburner.join(() => { - backburner.schedule('syncRelationships', this, this._flushPendingManyArrayUpdates); - }); - } - - _flushPendingManyArrayUpdates() { - if (this._willUpdateManyArray === false) { - return; - } - - let pending = this._pendingManyArrayUpdates; - this._pendingManyArrayUpdates = []; - this._willUpdateManyArray = false; - - for (let i = 0; i < pending.length; i += 2) { - let internalModel = pending[i]; - let idx = pending[i + 1]; - - this.manyArray._addInternalModels([internalModel], idx); - } - } - - removeCanonicalInternalModelFromOwn(internalModel, idx) { - let i = idx; - if (!this.canonicalMembers.has(internalModel)) { - return; - } - if (i === undefined) { - i = this.canonicalState.indexOf(internalModel); - } - if (i > -1) { - this.canonicalState.splice(i, 1); - } - super.removeCanonicalInternalModelFromOwn(internalModel, idx); - } - - removeAllCanonicalInternalModelsFromOwn() { - this.canonicalMembers.clear(); - this.canonicalState.splice(0, this.canonicalState.length); - super.removeAllCanonicalInternalModelsFromOwn(); - } - - removeCompletelyFromOwn(internalModel) { - super.removeCompletelyFromOwn(internalModel); - - const canonicalIndex = this.canonicalState.indexOf(internalModel); - - if (canonicalIndex !== -1) { - this.canonicalState.splice(canonicalIndex, 1); - } - - const manyArray = this._manyArray; - - if (manyArray) { - const idx = manyArray.currentState.indexOf(internalModel); - - if (idx !== -1) { - manyArray.internalReplace(idx, 1); - } - } - } - - flushCanonical() { - super.flushCanonical(); - if (this._manyArray) { - this._manyArray.flushCanonical(); - } - } - - removeInternalModelFromOwn(internalModel, idx) { - if (!this.members.has(internalModel)) { - return; - } - super.removeInternalModelFromOwn(internalModel, idx); - // note that ensuring the many array is created, via `this.manyArray` - // (instead of `this._manyArray`) is intentional. - // - // Because we're removing from local, and not canonical, state, it is - // important that the many array is initialized now with those changes, - // otherwise it will be initialized with canonical state and we'll have - // lost the fact that this internalModel was removed. - this._removeInternalModelFromManyArray(this.manyArray, internalModel, idx); - this._removeInternalModelFromManyArray(this._retainedManyArray, internalModel, idx); - } - - removeAllInternalModelsFromOwn() { - super.removeAllInternalModelsFromOwn(); - // as with removeInternalModelFromOwn, we make sure the many array is - // instantiated, or we'll lose local removals, as we're not updating - // canonical state here. - this.manyArray.clear(); - if (this._retainedManyArray) { - this._retainedManyArray.clear(); - } - } - - _removeInternalModelFromManyArray(manyArray, internalModel, idx) { - if (manyArray === null) { - return; - } - - if (idx !== undefined) { - //TODO(Igor) not used currently, fix - manyArray.currentState.removeAt(idx); - } else { - manyArray._removeInternalModels([internalModel]); - } - } - - notifyRecordRelationshipAdded(internalModel, idx) { - this.internalModel.notifyHasManyAdded(this.key, internalModel, idx); - } - - computeChanges(internalModels = []) { - let members = this.canonicalMembers; - let internalModelsToRemove = []; - let internalModelSet = setForArray(internalModels); - - members.forEach(member => { - if (internalModelSet.has(member)) { - return; - } - - internalModelsToRemove.push(member); - }); - - this.removeCanonicalInternalModels(internalModelsToRemove); - - for (let i = 0, l = internalModels.length; i < l; i++) { - let internalModel = internalModels[i]; - this.removeCanonicalInternalModel(internalModel); - this.addCanonicalInternalModel(internalModel, i); - } - } - - setInitialInternalModels(internalModels) { - if (Array.isArray(internalModels) === false || internalModels.length === 0) { - return; - } - - for (let i = 0; i < internalModels.length; i++) { - let internalModel = internalModels[i]; - if (this.canonicalMembers.has(internalModel)) { - continue; - } - - this.canonicalMembers.add(internalModel); - this.members.add(internalModel); - this.setupInverseRelationship(internalModel); - } - - this.canonicalState = this.canonicalMembers.toArray(); - } - - // called by `getData()` when a request is needed - // but no link is available - _fetchRecords(options) { - let internalModels = this.currentState; - let { shouldForceReload } = this; - let promise; - - if (shouldForceReload === true) { - promise = this.store._scheduleFetchMany(internalModels, options); - } else { - promise = this.store.findMany(internalModels, options); - } - - return promise; - } - - // called by `getData()` when a request is needed - // and a link is available - _fetchLink(options) { - return this.store - .findHasMany(this.internalModel, this.link, this.relationshipMeta, options) - .then(records => { - if (records.hasOwnProperty('meta')) { - this.updateMeta(records.meta); - } - this.store._backburner.join(() => { - this.updateInternalModelsFromAdapter(records); - }); - return records; - }); - } - - getData(options, isForcedReload = false) { - //TODO(Igor) sync server here, once our syncing is not stupid - let manyArray = this.manyArray; - - if (this.shouldMakeRequest()) { - let promise; - - if (this.link) { - promise = this._fetchLink(options); - } else { - promise = this._fetchRecords(options); - } - - promise = promise.then( - () => handleCompletedRequest(this), - e => handleCompletedRequest(this, e) - ); - - this.fetchPromise = promise; - this._updateLoadingPromise(promise, manyArray); - } - - if (this.isAsync) { - if (this._promiseProxy === null) { - this._updateLoadingPromise(resolve(manyArray), manyArray); - } - - return this._promiseProxy; - } else { - assert( - `You looked up the '${this.key}' relationship on a '${ - this.internalModel.type.modelName - }' with id ${ - this.internalModel.id - } but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (\`DS.hasMany({ async: true })\`)`, - this.allInverseRecordsAreLoaded || isForcedReload - ); - - return manyArray; - } - } - - notifyHasManyChange() { - this.internalModel.notifyHasManyAdded(this.key); - } - - updateData(data, initial) { - let internalModels = this.store._pushResourceIdentifiers(this, data); - if (initial) { - this.setInitialInternalModels(internalModels); - } else { - this.updateInternalModelsFromAdapter(internalModels); - } - } - - destroy() { - this.isDestroying = true; - super.destroy(); - let manyArray = this._manyArray; - if (manyArray) { - manyArray.destroy(); - this._manyArray = null; - } - - let proxy = this._promiseProxy; - - if (proxy) { - proxy.destroy(); - this._promiseProxy = null; - } - this.isDestroyed = true; - } -} - -function handleCompletedRequest(relationship, error) { - let manyArray = relationship.manyArray; - - //Goes away after the manyArray refactor - if (!manyArray.get('isDestroyed')) { - relationship.manyArray.set('isLoaded', true); - } - - relationship.fetchPromise = null; - relationship.setShouldForceReload(false); - - if (error) { - relationship.setHasFailedLoadAttempt(true); - throw error; - } - - relationship.setHasFailedLoadAttempt(false); - // only set to not stale if no error is thrown - relationship.setRelationshipIsStale(false); - - return manyArray; -} - -function setForArray(array) { - var set = new OrderedSet(); - - if (array) { - for (var i = 0, l = array.length; i < l; i++) { - set.add(array[i]); - } - } - - return set; -} diff --git a/addon/-legacy-private/system/relationships/state/relationship.js b/addon/-legacy-private/system/relationships/state/relationship.js deleted file mode 100644 index 5752b0fb0f7..00000000000 --- a/addon/-legacy-private/system/relationships/state/relationship.js +++ /dev/null @@ -1,747 +0,0 @@ -/* global heimdall */ -import { guidFor } from '@ember/object/internals'; -import { get } from '@ember/object'; - -import { assert, warn } from '@ember/debug'; -import OrderedSet from '../../ordered-set'; -import _normalizeLink from '../../normalize-link'; - -const { - addCanonicalInternalModel, - addCanonicalInternalModels, - addInternalModel, - addInternalModels, - clear, - flushCanonical, - flushCanonicalLater, - newRelationship, - push, - removeCanonicalInternalModel, - removeCanonicalInternalModelFromInverse, - removeCanonicalInternalModelFromOwn, - removeCanonicalInternalModels, - removeInternalModel, - removeInternalModelFromInverse, - removeInternalModelFromOwn, - removeInternalModels, - updateLink, - updateMeta, - updateInternalModelsFromAdapter, -} = heimdall.registerMonitor( - 'system.relationships.state.relationship', - 'addCanonicalInternalModel', - 'addCanonicalInternalModels', - 'addInternalModel', - 'addInternalModels', - 'clear', - 'flushCanonical', - 'flushCanonicalLater', - 'newRelationship', - 'push', - 'removeCanonicalInternalModel', - 'removeCanonicalInternalModelFromInverse', - 'removeCanonicalInternalModelFromOwn', - 'removeCanonicalInternalModels', - 'removeInternalModel', - 'removeInternalModelFromInverse', - 'removeInternalModelFromOwn', - 'removeInternalModels', - 'updateLink', - 'updateMeta', - 'updateInternalModelsFromAdapter' -); - -export default class Relationship { - constructor(store, internalModel, inverseKey, relationshipMeta) { - heimdall.increment(newRelationship); - let async = relationshipMeta.options.async; - let polymorphic = relationshipMeta.options.polymorphic; - this.members = new OrderedSet(); - this.canonicalMembers = new OrderedSet(); - this.store = store; - this.key = relationshipMeta.key; - this.kind = relationshipMeta.kind; - this.inverseKey = inverseKey; - this.internalModel = internalModel; - this.isAsync = typeof async === 'undefined' ? true : async; - this.isPolymorphic = typeof polymorphic === 'undefined' ? false : polymorphic; - this.relationshipMeta = relationshipMeta; - //This probably breaks for polymorphic relationship in complex scenarios, due to - //multiple possible modelNames - this.inverseKeyForImplicit = this.internalModel.modelName + this.key; - this.fetchPromise = null; - this._promiseProxy = null; - this.meta = null; - this.__inverseMeta = undefined; - - /* - This flag forces fetch. `true` for a single request once `reload()` - has been called `false` at all other times. - */ - this.shouldForceReload = false; - - /* - This flag indicates whether we should - re-fetch the relationship the next time - it is accessed. - - The difference between this flag and `shouldForceReload` - is in how we treat the presence of partially missing data: - - for a forced reload, we will reload the link or EVERY record - - for a stale reload, we will reload the link (if present) else only MISSING records - - Ideally these flags could be merged, but because we don't give the - request layer the option of deciding how to resolve the data being queried - we are forced to differentiate for now. - - It is also possible for a relationship to remain stale after a forced reload; however, - in this case `hasFailedLoadAttempt` ought to be `true`. - - false when - => internalModel.isNew() on initial setup - => a previously triggered request has resolved - => we get relationship data via push - - true when - => !internalModel.isNew() on initial setup - => an inverse has been unloaded - => we get a new link for the relationship - */ - this.relationshipIsStale = !this.isNew; - - /* - This flag indicates whether we should consider the content - of this relationship "known". - - If we have no relationship knowledge, and the relationship - is `async`, we will attempt to fetch the relationship on - access if it is also stale. - - Snapshot uses this to tell the difference between unknown - (`undefined`) or empty (`null`). The reason for this is that - we wouldn't want to serialize unknown relationships as `null` - as that might overwrite remote state. - - All relationships for a newly created (`store.createRecord()`) are - considered known (`hasAnyRelationshipData === true`). - - true when - => we receive a push with either new data or explicit empty (`[]` or `null`) - => the relationship is a belongsTo and we have received data from - the other side. - - false when - => we have received no signal about what data belongs in this relationship - => the relationship is a hasMany and we have only received data from - the other side. - */ - this.hasAnyRelationshipData = false; - - /* - Flag that indicates whether an empty relationship is explicitly empty - (signaled by push giving us an empty array or null relationship) - e.g. an API response has told us that this relationship is empty. - - Thus far, it does not appear that we actually need this flag; however, - @runspired has found it invaluable when debugging relationship tests - to determine whether (and why if so) we are in an incorrect state. - - true when - => we receive a push with explicit empty (`[]` or `null`) - => we have received no signal about what data belongs in this relationship - => on initial create (as no signal is known yet) - - false at all other times - */ - this.relationshipIsEmpty = true; - - /* - Flag that indicates whether we have explicitly attempted a load for the relationship - (which may have failed) - */ - this.hasFailedLoadAttempt = false; - - /* - true when - => hasAnyRelationshipData is true - AND - => members (NOT canonicalMembers) @each !isEmpty - - TODO, consider changing the conditional here from !isEmpty to !hiddenFromRecordArrays - */ - } - - get isNew() { - return this.internalModel.isNew(); - } - - _inverseIsSync() { - let inverseMeta = this._inverseMeta; - if (!inverseMeta) { - return false; - } - - let inverseAsync = inverseMeta.options.async; - return typeof inverseAsync === 'undefined' ? false : !inverseAsync; - } - - get _inverseMeta() { - if (this.__inverseMeta === undefined) { - let inverseMeta = null; - - if (this.inverseKey) { - let inverseModelClass = this.store.modelFor(this.relationshipMeta.type); - let inverseRelationships = get(inverseModelClass, 'relationshipsByName'); - inverseMeta = inverseRelationships.get(this.inverseKey); - } - - this.__inverseMeta = inverseMeta; - } - - return this.__inverseMeta; - } - - get parentType() { - return this.internalModel.modelName; - } - - internalModelDidDematerialize() { - if (!this.inverseKey) { - return; - } - - this.forAllMembers(inverseInternalModel => { - let relationship = inverseInternalModel._relationships.get(this.inverseKey); - relationship.inverseDidDematerialize(this.internalModel); - }); - } - - inverseDidDematerialize(inverseInternalModel) { - this.fetchPromise = null; - this.setRelationshipIsStale(true); - - if (!this.isAsync) { - // unloading inverse of a sync relationship is treated as a client-side - // delete, so actually remove the models don't merely invalidate the cp - // cache. - this.removeInternalModelFromOwn(inverseInternalModel); - this.removeCanonicalInternalModelFromOwn(inverseInternalModel); - } - } - - updateMeta(meta) { - heimdall.increment(updateMeta); - this.meta = meta; - } - - clear() { - heimdall.increment(clear); - - let members = this.members.list; - while (members.length > 0) { - let member = members[0]; - this.removeInternalModel(member); - } - - let canonicalMembers = this.canonicalMembers.list; - while (canonicalMembers.length > 0) { - let member = canonicalMembers[0]; - this.removeCanonicalInternalModel(member); - } - } - - removeAllInternalModelsFromOwn() { - this.members.clear(); - this.internalModel.updateRecordArrays(); - } - - removeAllCanonicalInternalModelsFromOwn() { - this.canonicalMembers.clear(); - this.flushCanonicalLater(); - } - - removeInternalModels(internalModels) { - heimdall.increment(removeInternalModels); - internalModels.forEach(internalModel => this.removeInternalModel(internalModel)); - } - - addInternalModels(internalModels, idx) { - heimdall.increment(addInternalModels); - internalModels.forEach(internalModel => { - this.addInternalModel(internalModel, idx); - if (idx !== undefined) { - idx++; - } - }); - } - - addCanonicalInternalModels(internalModels, idx) { - heimdall.increment(addCanonicalInternalModels); - for (let i = 0; i < internalModels.length; i++) { - if (idx !== undefined) { - this.addCanonicalInternalModel(internalModels[i], i + idx); - } else { - this.addCanonicalInternalModel(internalModels[i]); - } - } - } - - addCanonicalInternalModel(internalModel, idx) { - heimdall.increment(addCanonicalInternalModel); - if (!this.canonicalMembers.has(internalModel)) { - this.canonicalMembers.addWithIndex(internalModel, idx); - this.setupInverseRelationship(internalModel); - } - this.flushCanonicalLater(); - this.setHasAnyRelationshipData(true); - } - - setupInverseRelationship(internalModel) { - if (this.inverseKey) { - let relationships = internalModel._relationships; - let relationshipExisted = relationships.has(this.inverseKey); - let relationship = relationships.get(this.inverseKey); - if (relationshipExisted || this.isPolymorphic) { - // if we have only just initialized the inverse relationship, then it - // already has this.internalModel in its canonicalMembers, so skip the - // unnecessary work. The exception to this is polymorphic - // relationships whose members are determined by their inverse, as those - // relationships cannot efficiently find their inverse payloads. - relationship.addCanonicalInternalModel(this.internalModel); - } - } else { - let relationships = internalModel._implicitRelationships; - let relationship = relationships[this.inverseKeyForImplicit]; - if (!relationship) { - relationship = relationships[this.inverseKeyForImplicit] = new Relationship( - this.store, - internalModel, - this.key, - { options: { async: this.isAsync }, type: this.parentType } - ); - } - relationship.addCanonicalInternalModel(this.internalModel); - } - } - - removeCanonicalInternalModels(internalModels, idx) { - heimdall.increment(removeCanonicalInternalModels); - for (let i = 0; i < internalModels.length; i++) { - if (idx !== undefined) { - this.removeCanonicalInternalModel(internalModels[i], i + idx); - } else { - this.removeCanonicalInternalModel(internalModels[i]); - } - } - } - - removeCanonicalInternalModel(internalModel, idx) { - heimdall.increment(removeCanonicalInternalModel); - if (this.canonicalMembers.has(internalModel)) { - this.removeCanonicalInternalModelFromOwn(internalModel); - if (this.inverseKey) { - this.removeCanonicalInternalModelFromInverse(internalModel); - } else { - if (internalModel._implicitRelationships[this.inverseKeyForImplicit]) { - internalModel._implicitRelationships[ - this.inverseKeyForImplicit - ].removeCanonicalInternalModel(this.internalModel); - } - } - } - this.flushCanonicalLater(); - } - - addInternalModel(internalModel, idx) { - heimdall.increment(addInternalModel); - if (!this.members.has(internalModel)) { - this.members.addWithIndex(internalModel, idx); - this.notifyRecordRelationshipAdded(internalModel, idx); - if (this.inverseKey) { - internalModel._relationships.get(this.inverseKey).addInternalModel(this.internalModel); - } else { - if (!internalModel._implicitRelationships[this.inverseKeyForImplicit]) { - internalModel._implicitRelationships[this.inverseKeyForImplicit] = new Relationship( - this.store, - internalModel, - this.key, - { options: { async: this.isAsync }, type: this.parentType } - ); - } - internalModel._implicitRelationships[this.inverseKeyForImplicit].addInternalModel( - this.internalModel - ); - } - this.internalModel.updateRecordArrays(); - } - this.setHasAnyRelationshipData(true); - } - - removeInternalModel(internalModel) { - heimdall.increment(removeInternalModel); - if (this.members.has(internalModel)) { - this.removeInternalModelFromOwn(internalModel); - if (this.inverseKey) { - this.removeInternalModelFromInverse(internalModel); - } else { - if (internalModel._implicitRelationships[this.inverseKeyForImplicit]) { - internalModel._implicitRelationships[this.inverseKeyForImplicit].removeInternalModel( - this.internalModel - ); - } - } - } - } - - removeInternalModelFromInverse(internalModel) { - heimdall.increment(removeInternalModelFromInverse); - let inverseRelationship = internalModel._relationships.get(this.inverseKey); - //Need to check for existence, as the record might unloading at the moment - if (inverseRelationship) { - inverseRelationship.removeInternalModelFromOwn(this.internalModel); - } - } - - removeInternalModelFromOwn(internalModel) { - heimdall.increment(removeInternalModelFromOwn); - this.members.delete(internalModel); - this.internalModel.updateRecordArrays(); - } - - removeCanonicalInternalModelFromInverse(internalModel) { - heimdall.increment(removeCanonicalInternalModelFromInverse); - let inverseRelationship = internalModel._relationships.get(this.inverseKey); - //Need to check for existence, as the record might unloading at the moment - if (inverseRelationship) { - inverseRelationship.removeCanonicalInternalModelFromOwn(this.internalModel); - } - } - - removeCanonicalInternalModelFromOwn(internalModel) { - heimdall.increment(removeCanonicalInternalModelFromOwn); - this.canonicalMembers.delete(internalModel); - this.flushCanonicalLater(); - } - - /* - Call this method once a record deletion has been persisted - to purge it from BOTH current and canonical state of all - relationships. - - @method removeCompletelyFromInverse - @private - */ - removeCompletelyFromInverse() { - if (!this.inverseKey) { - return; - } - - // we actually want a union of members and canonicalMembers - // they should be disjoint but currently are not due to a bug - let seen = Object.create(null); - const internalModel = this.internalModel; - - const unload = inverseInternalModel => { - const id = guidFor(inverseInternalModel); - - if (seen[id] === undefined) { - const relationship = inverseInternalModel._relationships.get(this.inverseKey); - relationship.removeCompletelyFromOwn(internalModel); - seen[id] = true; - } - }; - - this.members.forEach(unload); - this.canonicalMembers.forEach(unload); - - if (!this.isAsync) { - this.clear(); - } - } - - forAllMembers(callback) { - let seen = Object.create(null); - - for (let i = 0; i < this.members.list.length; i++) { - const inverseInternalModel = this.members.list[i]; - const id = guidFor(inverseInternalModel); - if (!seen[id]) { - seen[id] = true; - callback(inverseInternalModel); - } - } - - for (let i = 0; i < this.canonicalMembers.list.length; i++) { - const inverseInternalModel = this.canonicalMembers.list[i]; - const id = guidFor(inverseInternalModel); - if (!seen[id]) { - seen[id] = true; - callback(inverseInternalModel); - } - } - } - - /* - Removes the given internalModel from BOTH canonical AND current state. - - This method is useful when either a deletion or a rollback on a new record - needs to entirely purge itself from an inverse relationship. - */ - removeCompletelyFromOwn(internalModel) { - this.canonicalMembers.delete(internalModel); - this.members.delete(internalModel); - this.internalModel.updateRecordArrays(); - } - - flushCanonical() { - heimdall.increment(flushCanonical); - let list = this.members.list; - this.willSync = false; - //a hack for not removing new internalModels - //TODO remove once we have proper diffing - let newInternalModels = []; - for (let i = 0; i < list.length; i++) { - if (list[i].isNew()) { - newInternalModels.push(list[i]); - } - } - - //TODO(Igor) make this less abysmally slow - this.members = this.canonicalMembers.copy(); - for (let i = 0; i < newInternalModels.length; i++) { - this.members.add(newInternalModels[i]); - } - } - - flushCanonicalLater() { - heimdall.increment(flushCanonicalLater); - if (this.willSync) { - return; - } - this.willSync = true; - this.store._updateRelationshipState(this); - } - - updateLink(link) { - heimdall.increment(updateLink); - warn( - `You pushed a record of type '${this.internalModel.modelName}' with a relationship '${ - this.key - }' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload. EmberData will treat this relationship as known-to-be-empty.`, - this.isAsync || this.hasAnyRelationshipData, - { - id: 'ds.store.push-link-for-sync-relationship', - } - ); - assert( - `You have pushed a record of type '${this.internalModel.modelName}' with '${ - this.key - }' as a link, but the value of that link is not a string.`, - typeof link === 'string' || link === null - ); - - this.link = link; - this.fetchPromise = null; - this.setRelationshipIsStale(true); - } - - reload(options) { - if (this._promiseProxy) { - if (this._promiseProxy.get('isPending')) { - return this._promiseProxy; - } - } - - this.setHasFailedLoadAttempt(false); - this.setShouldForceReload(true); - this.getData(options, true); - - return this._promiseProxy; - } - - shouldMakeRequest() { - let { - relationshipIsStale, - hasFailedLoadAttempt, - allInverseRecordsAreLoaded, - hasAnyRelationshipData, - shouldForceReload, - relationshipIsEmpty, - isAsync, - isNew, - fetchPromise, - } = this; - - // never make a request if this record doesn't exist server side yet - if (isNew === true) { - return false; - } - - // do not re-request if we are already awaiting a request - if (fetchPromise !== null) { - return false; - } - - // Always make a request when forced - // failed attempts must call `reload()`. - // - // For legacy reasons, when a relationship is missing only - // some of it's data we rely on individual `findRecord` - // calls which may resolve from cache in the non-link case. - // This determination is made elsewhere. - // - if (shouldForceReload === true || relationshipIsStale === true) { - return !hasFailedLoadAttempt; - } - - // never make a request if we've explicitly attempted to at least once - // since the last update to canonical state - // this includes failed attempts - // e.g. to re-attempt `reload()` must be called force the attempt. - if (hasFailedLoadAttempt === true) { - return false; - } - - // we were explicitly told that there is no inverse relationship - if (relationshipIsEmpty === true) { - return false; - } - - // we were explicitly told what the inverse is, and we have the inverse records available - if (hasAnyRelationshipData === true && allInverseRecordsAreLoaded === true) { - return false; - } - - // if this is a sync relationship, we should not need to fetch, so getting here is an error - assert( - `You looked up the '${this.key}' relationship on a '${ - this.internalModel.type.modelName - }' with id ${ - this.internalModel.id - } but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (\`DS.${ - this.relationshipMeta.kind - }({ async: true })\`)`, - isAsync === true - ); - - return true; - } - - _updateLoadingPromise(promise, content) { - if (this._promiseProxy) { - if (content !== undefined) { - this._promiseProxy.set('content', content); - } - this._promiseProxy.set('promise', promise); - } else { - this._promiseProxy = this._createProxy(promise, content); - } - - return this._promiseProxy; - } - - updateInternalModelsFromAdapter(internalModels) { - heimdall.increment(updateInternalModelsFromAdapter); - this.setHasAnyRelationshipData(true); - //TODO(Igor) move this to a proper place - //TODO Once we have adapter support, we need to handle updated and canonical changes - this.computeChanges(internalModels); - } - - notifyRecordRelationshipAdded() {} - - setHasAnyRelationshipData(value) { - this.hasAnyRelationshipData = value; - } - - setHasFailedLoadAttempt(value) { - this.hasFailedLoadAttempt = value; - } - - setRelationshipIsStale(value) { - this.relationshipIsStale = value; - } - - setRelationshipIsEmpty(value) { - this.relationshipIsEmpty = value; - } - - setShouldForceReload(value) { - this.shouldForceReload = value; - } - - /* - `push` for a relationship allows the store to push a JSON API Relationship - Object onto the relationship. The relationship will then extract and set the - meta, data and links of that relationship. - - `push` use `updateMeta`, `updateData` and `updateLink` to update the state - of the relationship. - */ - push(payload, initial) { - heimdall.increment(push); - - let hasRelationshipDataProperty = false; - let hasLink = false; - - if (payload.meta) { - this.updateMeta(payload.meta); - } - - if (payload.data !== undefined) { - hasRelationshipDataProperty = true; - this.updateData(payload.data, initial); - } else if (payload._partialData !== undefined) { - this.updateData(payload._partialData, initial); - } else if (this.isAsync === false) { - hasRelationshipDataProperty = true; - let data = this.kind === 'hasMany' ? [] : null; - - this.updateData(data, initial); - } - - if (payload.links && payload.links.related) { - let relatedLink = _normalizeLink(payload.links.related); - if (relatedLink && relatedLink.href && relatedLink.href !== this.link) { - hasLink = true; - this.updateLink(relatedLink.href); - } - } - - /* - Data being pushed into the relationship might contain only data or links, - or a combination of both. - - IF contains only data - IF contains both links and data - relationshipIsEmpty -> true if is empty array (has-many) or is null (belongs-to) - hasAnyRelationshipData -> true - relationshipIsStale -> false - allInverseRecordsAreLoaded -> run-check-to-determine - - IF contains only links - relationshipIsStale -> true - */ - this.setHasFailedLoadAttempt(false); - if (hasRelationshipDataProperty) { - let relationshipIsEmpty = - payload.data === null || (Array.isArray(payload.data) && payload.data.length === 0); - - this.setHasAnyRelationshipData(true); - this.setRelationshipIsStale(false); - this.setRelationshipIsEmpty(relationshipIsEmpty); - } else if (hasLink) { - this.setRelationshipIsStale(true); - - if (!initial) { - this.internalModel.notifyPropertyChange(this.key); - } - } - } - - _createProxy() {} - - updateData() {} - - destroy() {} -} diff --git a/addon/-legacy-private/system/snapshot.js b/addon/-legacy-private/system/snapshot.js deleted file mode 100644 index 2ff17d9d7de..00000000000 --- a/addon/-legacy-private/system/snapshot.js +++ /dev/null @@ -1,409 +0,0 @@ -/** - @module ember-data -*/ -import { inspect } from '@ember/debug'; -import EmberError from '@ember/error'; -import { get } from '@ember/object'; -import { assign } from '@ember/polyfills'; - -/** - @class Snapshot - @namespace DS - @private - @constructor - @param {DS.Model} internalModel The model to create a snapshot from -*/ -export default class Snapshot { - constructor(internalModel, options = {}) { - this.__attributes = null; - this._belongsToRelationships = Object.create(null); - this._belongsToIds = Object.create(null); - this._hasManyRelationships = Object.create(null); - this._hasManyIds = Object.create(null); - this._internalModel = internalModel; - - /* - If the internalModel does not yet have a record, then we are - likely a snapshot being provided to a find request, so we - populate __attributes lazily. Else, to preserve the "moment - in time" in which a snapshot is created, we greedily grab - the values. - */ - if (internalModel.hasRecord) { - this._attributes; - } - - /**O - The id of the snapshot's underlying record - - Example - - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postSnapshot.id; // => '1' - ``` - - @property id - @type {String} - */ - this.id = internalModel.id; - - /** - A hash of adapter options - @property adapterOptions - @type {Object} - */ - this.adapterOptions = options.adapterOptions; - this.include = options.include; - - /** - The name of the type of the underlying record for this snapshot, as a string. - - @property modelName - @type {String} - */ - this.modelName = internalModel.modelName; - - this._changedAttributes = internalModel.changedAttributes(); - } - - /** - The underlying record for this snapshot. Can be used to access methods and - properties defined on the record. - - Example - - ```javascript - let json = snapshot.record.toJSON(); - ``` - - @property record - @type {DS.Model} - */ - get record() { - return this._internalModel.getRecord(); - } - - get _attributes() { - let attributes = this.__attributes; - - if (attributes === null) { - let record = this.record; - attributes = this.__attributes = Object.create(null); - - record.eachAttribute(keyName => (attributes[keyName] = get(record, keyName))); - } - - return attributes; - } - - /** - The type of the underlying record for this snapshot, as a DS.Model. - - @property type - @type {DS.Model} - */ - get type() { - // TODO @runspired we should deprecate this in favor of modelClass but only once - // we've cleaned up the internals enough that a public change to follow suite is - // uncontroversial. - return this._internalModel.modelClass; - } - - /** - Returns the value of an attribute. - - Example - - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postSnapshot.attr('author'); // => 'Tomster' - postSnapshot.attr('title'); // => 'Ember.js rocks' - ``` - - Note: Values are loaded eagerly and cached when the snapshot is created. - - @method attr - @param {String} keyName - @return {Object} The attribute value or undefined - */ - attr(keyName) { - if (keyName in this._attributes) { - return this._attributes[keyName]; - } - throw new EmberError( - "Model '" + inspect(this.record) + "' has no attribute named '" + keyName + "' defined." - ); - } - - /** - Returns all attributes and their corresponding values. - - Example - - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postSnapshot.attributes(); // => { author: 'Tomster', title: 'Ember.js rocks' } - ``` - - @method attributes - @return {Object} All attributes of the current snapshot - */ - attributes() { - return assign({}, this._attributes); - } - - /** - Returns all changed attributes and their old and new values. - - Example - - ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); - postModel.set('title', 'Ember.js rocks!'); - postSnapshot.changedAttributes(); // => { title: ['Ember.js rocks', 'Ember.js rocks!'] } - ``` - - @method changedAttributes - @return {Object} All changed attributes of the current snapshot - */ - changedAttributes() { - let changedAttributes = Object.create(null); - let changedAttributeKeys = Object.keys(this._changedAttributes); - - for (let i = 0, length = changedAttributeKeys.length; i < length; i++) { - let key = changedAttributeKeys[i]; - changedAttributes[key] = this._changedAttributes[key].slice(); - } - - return changedAttributes; - } - - /** - Returns the current value of a belongsTo relationship. - - `belongsTo` takes an optional hash of options as a second parameter, - currently supported options are: - - - `id`: set to `true` if you only want the ID of the related record to be - returned. - - Example - - ```javascript - // store.push('post', { id: 1, title: 'Hello World' }); - // store.createRecord('comment', { body: 'Lorem ipsum', post: post }); - commentSnapshot.belongsTo('post'); // => DS.Snapshot - commentSnapshot.belongsTo('post', { id: true }); // => '1' - - // store.push('comment', { id: 1, body: 'Lorem ipsum' }); - commentSnapshot.belongsTo('post'); // => undefined - ``` - - Calling `belongsTo` will return a new Snapshot as long as there's any known - data for the relationship available, such as an ID. If the relationship is - known but unset, `belongsTo` will return `null`. If the contents of the - relationship is unknown `belongsTo` will return `undefined`. - - Note: Relationships are loaded lazily and cached upon first access. - - @method belongsTo - @param {String} keyName - @param {Object} [options] - @return {(DS.Snapshot|String|null|undefined)} A snapshot or ID of a known - relationship or null if the relationship is known but unset. undefined - will be returned if the contents of the relationship is unknown. - */ - belongsTo(keyName, options) { - let id = options && options.id; - let relationship; - let result; - - if (id && keyName in this._belongsToIds) { - return this._belongsToIds[keyName]; - } - - if (!id && keyName in this._belongsToRelationships) { - return this._belongsToRelationships[keyName]; - } - - relationship = this._internalModel._relationships.get(keyName); - if (!(relationship && relationship.relationshipMeta.kind === 'belongsTo')) { - throw new EmberError( - "Model '" + - inspect(this.record) + - "' has no belongsTo relationship named '" + - keyName + - "' defined." - ); - } - - let { hasAnyRelationshipData, inverseInternalModel } = relationship; - - if (hasAnyRelationshipData) { - if (inverseInternalModel && !inverseInternalModel.isDeleted()) { - if (id) { - result = get(inverseInternalModel, 'id'); - } else { - result = inverseInternalModel.createSnapshot(); - } - } else { - result = null; - } - } - - if (id) { - this._belongsToIds[keyName] = result; - } else { - this._belongsToRelationships[keyName] = result; - } - - return result; - } - - /** - Returns the current value of a hasMany relationship. - - `hasMany` takes an optional hash of options as a second parameter, - currently supported options are: - - - `ids`: set to `true` if you only want the IDs of the related records to be - returned. - - Example - - ```javascript - // store.push('post', { id: 1, title: 'Hello World', comments: [2, 3] }); - postSnapshot.hasMany('comments'); // => [DS.Snapshot, DS.Snapshot] - postSnapshot.hasMany('comments', { ids: true }); // => ['2', '3'] - - // store.push('post', { id: 1, title: 'Hello World' }); - postSnapshot.hasMany('comments'); // => undefined - ``` - - Note: Relationships are loaded lazily and cached upon first access. - - @method hasMany - @param {String} keyName - @param {Object} [options] - @return {(Array|undefined)} An array of snapshots or IDs of a known - relationship or an empty array if the relationship is known but unset. - undefined will be returned if the contents of the relationship is unknown. - */ - hasMany(keyName, options) { - let ids = options && options.ids; - let relationship; - let results; - - if (ids && keyName in this._hasManyIds) { - return this._hasManyIds[keyName]; - } - - if (!ids && keyName in this._hasManyRelationships) { - return this._hasManyRelationships[keyName]; - } - - relationship = this._internalModel._relationships.get(keyName); - if (!(relationship && relationship.relationshipMeta.kind === 'hasMany')) { - throw new EmberError( - "Model '" + - inspect(this.record) + - "' has no hasMany relationship named '" + - keyName + - "' defined." - ); - } - - let { hasAnyRelationshipData, members } = relationship; - - if (hasAnyRelationshipData) { - results = []; - members.forEach(member => { - if (!member.isDeleted()) { - if (ids) { - results.push(member.id); - } else { - results.push(member.createSnapshot()); - } - } - }); - } - - if (ids) { - this._hasManyIds[keyName] = results; - } else { - this._hasManyRelationships[keyName] = results; - } - - return results; - } - - /** - Iterates through all the attributes of the model, calling the passed - function on each attribute. - - Example - - ```javascript - snapshot.eachAttribute(function(name, meta) { - // ... - }); - ``` - - @method eachAttribute - @param {Function} callback the callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - */ - eachAttribute(callback, binding) { - this.record.eachAttribute(callback, binding); - } - - /** - Iterates through all the relationships of the model, calling the passed - function on each relationship. - - Example - - ```javascript - snapshot.eachRelationship(function(name, relationship) { - // ... - }); - ``` - - @method eachRelationship - @param {Function} callback the callback to execute - @param {Object} [binding] the value to which the callback's `this` should be bound - */ - eachRelationship(callback, binding) { - this.record.eachRelationship(callback, binding); - } - - /** - Serializes the snapshot using the serializer for the model. - - Example - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - createRecord(store, type, snapshot) { - var data = snapshot.serialize({ includeId: true }); - var url = `/${type.modelName}`; - - return fetch(url, { - method: 'POST', - body: data, - }).then((response) => response.json()) - } - }); - ``` - - @method serialize - @param {Object} options - @return {Object} an object whose values are primitive JSON values only - */ - serialize(options) { - return this.record.store.serializerFor(this.modelName).serialize(this, options); - } -} diff --git a/addon/-legacy-private/system/store.js b/addon/-legacy-private/system/store.js deleted file mode 100644 index e0e61c1a94d..00000000000 --- a/addon/-legacy-private/system/store.js +++ /dev/null @@ -1,3462 +0,0 @@ -/** - @module ember-data -*/ - -import { registerWaiter, unregisterWaiter } from '@ember/test'; - -import { A } from '@ember/array'; -import EmberError from '@ember/error'; -import MapWithDefault from './map-with-default'; -import { run as emberRunLoop } from '@ember/runloop'; -import { set, get, computed } from '@ember/object'; -import { assign } from '@ember/polyfills'; -import { default as RSVP, Promise } from 'rsvp'; -import Service from '@ember/service'; -import { typeOf, isPresent, isNone } from '@ember/utils'; -import Ember from 'ember'; -import { InvalidError } from '../adapters/errors'; -import { instrument } from 'ember-data/-debug'; -import { assert, deprecate, warn, inspect } from '@ember/debug'; -import { DEBUG } from '@glimmer/env'; -import Model from './model/model'; -import normalizeModelName from './normalize-model-name'; -import IdentityMap from './identity-map'; - -import { promiseArray, promiseObject } from './promise-proxies'; - -import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './store/common'; - -import { normalizeResponseHelper } from './store/serializer-response'; -import { serializerForAdapter } from './store/serializers'; -import RelationshipPayloadsManager from './relationships/relationship-payloads-manager'; - -import { - _find, - _findMany, - _findHasMany, - _findBelongsTo, - _findAll, - _query, - _queryRecord, -} from './store/finders'; - -import { getOwner } from '../utils'; -import coerceId from './coerce-id'; -import RecordArrayManager from './record-array-manager'; -import InternalModel from './model/internal-model'; -import edBackburner from './backburner'; - -const badIdFormatAssertion = '`id` passed to `findRecord()` has to be non-empty string or number'; -const emberRun = emberRunLoop.backburner; -const { ENV } = Ember; - -//Get the materialized model from the internalModel/promise that returns -//an internal model and return it in a promiseObject. Useful for returning -//from find methods -function promiseRecord(internalModelPromise, label) { - let toReturn = internalModelPromise.then(internalModel => internalModel.getRecord()); - - return promiseObject(toReturn, label); -} - -let Store; - -// Implementors Note: -// -// The variables in this file are consistently named according to the following -// scheme: -// -// * +id+ means an identifier managed by an external source, provided inside -// the data provided by that source. These are always coerced to be strings -// before being used internally. -// * +clientId+ means a transient numerical identifier generated at runtime by -// the data store. It is important primarily because newly created objects may -// not yet have an externally generated id. -// * +internalModel+ means a record internalModel object, which holds metadata about a -// record, even if it has not yet been fully materialized. -// * +type+ means a DS.Model. - -const { - _generateId, - _internalModelForId, - _load, - _pushInternalModel, - _setupRelationships, - adapterFor, - _buildInternalModel, - _didUpdateAll, - normalize, - peekAll, - peekRecord, - serializerFor, - _internalModelsFor, -} = heimdall.registerMonitor( - 'store', - '_generateId', - '_internalModelForId', - '_load', - '_pushInternalModel', - '_setupRelationships', - 'adapterFor', - '_buildInternalModel', - '_didUpdateAll', - 'normalize', - 'peekAll', - 'peekRecord', - 'serializerFor', - '_internalModelsFor' -); - -/** - The store contains all of the data for records loaded from the server. - It is also responsible for creating instances of `DS.Model` that wrap - the individual data for a record, so that they can be bound to in your - Handlebars templates. - - Define your application's store like this: - - ```app/services/store.js - import DS from 'ember-data'; - - export default DS.Store.extend({ - }); - ``` - - Most Ember.js applications will only have a single `DS.Store` that is - automatically created by their `Ember.Application`. - - You can retrieve models from the store in several ways. To retrieve a record - for a specific id, use `DS.Store`'s `findRecord()` method: - - ```javascript - store.findRecord('person', 123).then(function (person) { - }); - ``` - - By default, the store will talk to your backend using a standard - REST mechanism. You can customize how the store talks to your - backend by specifying a custom adapter: - - ```app/adapters/application.js - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - }); - ``` - - You can learn more about writing a custom adapter by reading the `DS.Adapter` - documentation. - - ### Store createRecord() vs. push() vs. pushPayload() - - The store provides multiple ways to create new record objects. They have - some subtle differences in their use which are detailed below: - - [createRecord](#method_createRecord) is used for creating new - records on the client side. This will return a new record in the - `created.uncommitted` state. In order to persist this record to the - backend, you will need to call `record.save()`. - - [push](#method_push) is used to notify Ember Data's store of new or - updated records that exist in the backend. This will return a record - in the `loaded.saved` state. The primary use-case for `store#push` is - to notify Ember Data about record updates (full or partial) that happen - outside of the normal adapter methods (for example - [SSE](http://dev.w3.org/html5/eventsource/) or [Web - Sockets](http://www.w3.org/TR/2009/WD-websockets-20091222/)). - - [pushPayload](#method_pushPayload) is a convenience wrapper for - `store#push` that will deserialize payloads if the - Serializer implements a `pushPayload` method. - - Note: When creating a new record using any of the above methods - Ember Data will update `DS.RecordArray`s such as those returned by - `store#peekAll()` or `store#findAll()`. This means any - data bindings or computed properties that depend on the RecordArray - will automatically be synced to include the new or updated record - values. - - @class Store - @namespace DS - @extends Ember.Service -*/ -Store = Service.extend({ - /** - @method init - @private - */ - init() { - this._super(...arguments); - this._backburner = edBackburner; - // internal bookkeeping; not observable - this.recordArrayManager = new RecordArrayManager({ store: this }); - this._identityMap = new IdentityMap(); - this._pendingSave = []; - this._modelFactoryCache = Object.create(null); - this._relationshipsPayloads = new RelationshipPayloadsManager(this); - - /* - Ember Data uses several specialized micro-queues for organizing - and coalescing similar async work. - - These queues are currently controlled by a flush scheduled into - ember-data's custom backburner instance. - */ - // used for coalescing record save requests - this._pendingSave = []; - // used for coalescing relationship updates - this._updatedRelationships = []; - // used for coalescing relationship setup needs - this._pushedInternalModels = []; - // used for coalescing internal model updates - this._updatedInternalModels = []; - - // used to keep track of all the find requests that need to be coalesced - this._pendingFetch = new MapWithDefault({ - defaultValue() { - return []; - }, - }); - - this._adapterCache = Object.create(null); - this._serializerCache = Object.create(null); - - if (DEBUG) { - this.shouldAssertMethodCallsOnDestroyedStore = - this.shouldAssertMethodCallsOnDestroyedStore || false; - if (this.shouldTrackAsyncRequests === undefined) { - this.shouldTrackAsyncRequests = false; - } - if (this.generateStackTracesForTrackedRequests === undefined) { - this.generateStackTracesForTrackedRequests = false; - } - - this._trackedAsyncRequests = []; - this._trackAsyncRequestStart = label => { - let trace = - 'set `store.generateStackTracesForTrackedRequests = true;` to get a detailed trace for where this request originated'; - - if (this.generateStackTracesForTrackedRequests) { - try { - throw new Error(`EmberData TrackedRequest: ${label}`); - } catch (e) { - trace = e; - } - } - - let token = Object.freeze({ - label, - trace, - }); - - this._trackedAsyncRequests.push(token); - return token; - }; - this._trackAsyncRequestEnd = token => { - let index = this._trackedAsyncRequests.indexOf(token); - - if (index === -1) { - throw new Error( - `Attempted to end tracking for the following request but it was not being tracked:\n${token}` - ); - } - - this._trackedAsyncRequests.splice(index, 1); - }; - - this.__asyncWaiter = () => { - let shouldTrack = this.shouldTrackAsyncRequests; - let tracked = this._trackedAsyncRequests; - let isSettled = tracked.length === 0; - - return shouldTrack !== true || isSettled; - }; - - registerWaiter(this.__asyncWaiter); - } - }, - - /** - The default adapter to use to communicate to a backend server or - other persistence layer. This will be overridden by an application - adapter if present. - - If you want to specify `app/adapters/custom.js` as a string, do: - - ```js - import DS from 'ember-data'; - - export default DS.Store.extend({ - adapter: 'custom', - }); - ``` - - @property adapter - @default '-json-api' - @type {String} - */ - adapter: '-json-api', - - /** - This property returns the adapter, after resolving a possible - string key. - - If the supplied `adapter` was a class, or a String property - path resolved to a class, this property will instantiate the - class. - - This property is cacheable, so the same instance of a specified - adapter class should be used for the lifetime of the store. - - @property defaultAdapter - @private - @return DS.Adapter - */ - defaultAdapter: computed('adapter', function() { - let adapter = get(this, 'adapter'); - - assert( - 'You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name', - typeof adapter === 'string' - ); - - return this.adapterFor(adapter); - }), - - // ..................... - // . CREATE NEW RECORD . - // ..................... - - /** - Create a new record in the current store. The properties passed - to this method are set on the newly created record. - - To create a new instance of a `Post`: - - ```js - store.createRecord('post', { - title: 'Rails is omakase' - }); - ``` - - To create a new instance of a `Post` that has a relationship with a `User` record: - - ```js - let user = this.store.peekRecord('user', 1); - store.createRecord('post', { - title: 'Rails is omakase', - user: user - }); - ``` - - @method createRecord - @param {String} modelName - @param {Object} inputProperties a hash of properties to set on the - newly created record. - @return {DS.Model} record - */ - createRecord(modelName, inputProperties) { - if (DEBUG) { - assertDestroyingStore(this, 'createRecord'); - } - assert( - `You need to pass a model name to the store's createRecord method`, - isPresent(modelName) - ); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - - // This is wrapped in a `run.join` so that in test environments users do not need to manually wrap - // calls to `createRecord`. The run loop usage here is because we batch the joining and updating - // of record-arrays via ember's run loop, not our own. - // - // to remove this, we would need to move to a new `async` API. - return emberRun.join(() => { - return this._backburner.join(() => { - let normalizedModelName = normalizeModelName(modelName); - let properties = assign({}, inputProperties); - - // If the passed properties do not include a primary key, - // give the adapter an opportunity to generate one. Typically, - // client-side ID generators will use something like uuid.js - // to avoid conflicts. - - if (isNone(properties.id)) { - properties.id = this._generateId(normalizedModelName, properties); - } - - // Coerce ID to a string - properties.id = coerceId(properties.id); - - let internalModel = this._buildInternalModel(normalizedModelName, properties.id); - internalModel.loadedData(); - return internalModel.getRecord(properties); - }); - }); - }, - - /** - If possible, this method asks the adapter to generate an ID for - a newly created record. - - @method _generateId - @private - @param {String} modelName - @param {Object} properties from the new record - @return {String} if the adapter can generate one, an ID - */ - _generateId(modelName, properties) { - heimdall.increment(_generateId); - let adapter = this.adapterFor(modelName); - - if (adapter && adapter.generateIdForRecord) { - return adapter.generateIdForRecord(this, modelName, properties); - } - - return null; - }, - - // ................. - // . DELETE RECORD . - // ................. - - /** - For symmetry, a record can be deleted via the store. - - Example - - ```javascript - let post = store.createRecord('post', { - title: 'Rails is omakase' - }); - - store.deleteRecord(post); - ``` - - @method deleteRecord - @param {DS.Model} record - */ - deleteRecord(record) { - if (DEBUG) { - assertDestroyingStore(this, 'deleteRecord'); - } - record.deleteRecord(); - }, - - /** - For symmetry, a record can be unloaded via the store. - This will cause the record to be destroyed and freed up for garbage collection. - - Example - - ```javascript - store.findRecord('post', 1).then(function(post) { - store.unloadRecord(post); - }); - ``` - - @method unloadRecord - @param {DS.Model} record - */ - unloadRecord(record) { - if (DEBUG) { - assertDestroyingStore(this, 'unloadRecord'); - } - record.unloadRecord(); - }, - - // ................ - // . FIND RECORDS . - // ................ - - /** - @method find - @param {String} modelName - @param {String|Integer} id - @param {Object} options - @return {Promise} promise - @private - */ - find(modelName, id, options) { - if (DEBUG) { - assertDestroyingStore(this, 'find'); - } - // The default `model` hook in Route calls `find(modelName, id)`, - // that's why we have to keep this method around even though `findRecord` is - // the public way to get a record by modelName and id. - assert( - `Using store.find(type) has been removed. Use store.findAll(modelName) to retrieve all records for a given type.`, - arguments.length !== 1 - ); - assert( - `Calling store.find(modelName, id, { preload: preload }) is no longer supported. Use store.findRecord(modelName, id, { preload: preload }) instead.`, - !options - ); - assert( - `You need to pass the model name and id to the store's find method`, - arguments.length === 2 - ); - assert( - `You cannot pass '${id}' as id to the store's find method`, - typeof id === 'string' || typeof id === 'number' - ); - assert( - `Calling store.find() with a query object is no longer supported. Use store.query() instead.`, - typeof id !== 'object' - ); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - - return this.findRecord(modelName, id); - }, - - /** - This method returns a record for a given type and id combination. - - The `findRecord` method will always resolve its promise with the same - object for a given type and `id`. - - The `findRecord` method will always return a **promise** that will be - resolved with the record. - - Example - - ```app/routes/post.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - model(params) { - return this.store.findRecord('post', params.post_id); - } - }); - ``` - - If the record is not yet available, the store will ask the adapter's `find` - method to find the necessary data. If the record is already present in the - store, it depends on the reload behavior _when_ the returned promise - resolves. - - ### Preloading - - You can optionally `preload` specific attributes and relationships that you know of - by passing them via the passed `options`. - - For example, if your Ember route looks like `/posts/1/comments/2` and your API route - for the comment also looks like `/posts/1/comments/2` if you want to fetch the comment - without fetching the post you can pass in the post to the `findRecord` call: - - ```javascript - store.findRecord('comment', 2, { preload: { post: 1 } }); - ``` - - If you have access to the post model you can also pass the model itself: - - ```javascript - store.findRecord('post', 1).then(function (myPostModel) { - store.findRecord('comment', 2, { post: myPostModel }); - }); - ``` - - ### Reloading - - The reload behavior is configured either via the passed `options` hash or - the result of the adapter's `shouldReloadRecord`. - - If `{ reload: true }` is passed or `adapter.shouldReloadRecord` evaluates - to `true`, then the returned promise resolves once the adapter returns - data, regardless if the requested record is already in the store: - - ```js - store.push({ - data: { - id: 1, - type: 'post', - revision: 1 - } - }); - - // adapter#findRecord resolves with - // [ - // { - // id: 1, - // type: 'post', - // revision: 2 - // } - // ] - store.findRecord('post', 1, { reload: true }).then(function(post) { - post.get('revision'); // 2 - }); - ``` - - If no reload is indicated via the abovementioned ways, then the promise - immediately resolves with the cached version in the store. - - ### Background Reloading - - Optionally, if `adapter.shouldBackgroundReloadRecord` evaluates to `true`, - then a background reload is started, which updates the records' data, once - it is available: - - ```js - // app/adapters/post.js - import ApplicationAdapter from "./application"; - - export default ApplicationAdapter.extend({ - shouldReloadRecord(store, snapshot) { - return false; - }, - - shouldBackgroundReloadRecord(store, snapshot) { - return true; - } - }); - - // ... - - store.push({ - data: { - id: 1, - type: 'post', - revision: 1 - } - }); - - let blogPost = store.findRecord('post', 1).then(function(post) { - post.get('revision'); // 1 - }); - - // later, once adapter#findRecord resolved with - // [ - // { - // id: 1, - // type: 'post', - // revision: 2 - // } - // ] - - blogPost.get('revision'); // 2 - ``` - - If you would like to force or prevent background reloading, you can set a - boolean value for `backgroundReload` in the options object for - `findRecord`. - - ```app/routes/post/edit.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - model(params) { - return this.store.findRecord('post', params.post_id, { backgroundReload: false }); - } - }); - ``` - - If you pass an object on the `adapterOptions` property of the options - argument it will be passed to you adapter via the snapshot - - ```app/routes/post/edit.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - model(params) { - return this.store.findRecord('post', params.post_id, { - adapterOptions: { subscribe: false } - }); - } - }); - ``` - - ```app/adapters/post.js - import MyCustomAdapter from './custom-adapter'; - - export default MyCustomAdapter.extend({ - findRecord(store, type, id, snapshot) { - if (snapshot.adapterOptions.subscribe) { - // ... - } - // ... - } - }); - ``` - - See [peekRecord](#method_peekRecord) to get the cached version of a record. - - ### Retrieving Related Model Records - - If you use an adapter such as Ember's default - [`JSONAPIAdapter`](https://emberjs.com/api/data/classes/DS.JSONAPIAdapter.html) - that supports the [JSON API specification](http://jsonapi.org/) and if your server - endpoint supports the use of an - ['include' query parameter](http://jsonapi.org/format/#fetching-includes), - you can use `findRecord()` to automatically retrieve additional records related to - the one you request by supplying an `include` parameter in the `options` object. - - For example, given a `post` model that has a `hasMany` relationship with a `comment` - model, when we retrieve a specific post we can have the server also return that post's - comments in the same request: - - ```app/routes/post.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - model(params) { - return this.store.findRecord('post', params.post_id, { include: 'comments' }); - } - }); - - ``` - In this case, the post's comments would then be available in your template as - `model.comments`. - - Multiple relationships can be requested using an `include` parameter consisting of a - comma-separated list (without white-space) while nested relationships can be specified - using a dot-separated sequence of relationship names. So to request both the post's - comments and the authors of those comments the request would look like this: - - ```app/routes/post.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - model(params) { - return this.store.findRecord('post', params.post_id, { include: 'comments,comments.author' }); - } - }); - - ``` - - @since 1.13.0 - @method findRecord - @param {String} modelName - @param {(String|Integer)} id - @param {Object} options - @return {Promise} promise - */ - findRecord(modelName, id, options) { - if (DEBUG) { - assertDestroyingStore(this, 'findRecord'); - } - assert(`You need to pass a model name to the store's findRecord method`, isPresent(modelName)); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - assert( - badIdFormatAssertion, - (typeof id === 'string' && id.length > 0) || (typeof id === 'number' && !isNaN(id)) - ); - - let normalizedModelName = normalizeModelName(modelName); - - let internalModel = this._internalModelForId(normalizedModelName, id); - options = options || {}; - - if (!this.hasRecordForId(normalizedModelName, id)) { - return this._findByInternalModel(internalModel, options); - } - - let fetchedInternalModel = this._findRecord(internalModel, options); - - return promiseRecord( - fetchedInternalModel, - `DS: Store#findRecord ${normalizedModelName} with id: ${id}` - ); - }, - - _findRecord(internalModel, options) { - // Refetch if the reload option is passed - if (options.reload) { - return this._scheduleFetch(internalModel, options); - } - - let snapshot = internalModel.createSnapshot(options); - let adapter = this.adapterFor(internalModel.modelName); - - // Refetch the record if the adapter thinks the record is stale - if (adapter.shouldReloadRecord(this, snapshot)) { - return this._scheduleFetch(internalModel, options); - } - - if (options.backgroundReload === false) { - return Promise.resolve(internalModel); - } - - // Trigger the background refetch if backgroundReload option is passed - if (options.backgroundReload || adapter.shouldBackgroundReloadRecord(this, snapshot)) { - this._scheduleFetch(internalModel, options); - } - - // Return the cached record - return Promise.resolve(internalModel); - }, - - _findByInternalModel(internalModel, options = {}) { - if (options.preload) { - internalModel.preloadData(options.preload); - } - - let fetchedInternalModel = this._findEmptyInternalModel(internalModel, options); - - return promiseRecord( - fetchedInternalModel, - `DS: Store#findRecord ${internalModel.modelName} with id: ${internalModel.id}` - ); - }, - - _findEmptyInternalModel(internalModel, options) { - if (internalModel.isEmpty()) { - return this._scheduleFetch(internalModel, options); - } - - //TODO double check about reloading - if (internalModel.isLoading()) { - return internalModel._promiseProxy; - } - - return Promise.resolve(internalModel); - }, - - /** - This method makes a series of requests to the adapter's `find` method - and returns a promise that resolves once they are all loaded. - - @private - @method findByIds - @param {String} modelName - @param {Array} ids - @return {Promise} promise - */ - findByIds(modelName, ids) { - if (DEBUG) { - assertDestroyingStore(this, 'findByIds'); - } - assert(`You need to pass a model name to the store's findByIds method`, isPresent(modelName)); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - - let promises = new Array(ids.length); - - let normalizedModelName = normalizeModelName(modelName); - - for (let i = 0; i < ids.length; i++) { - promises[i] = this.findRecord(normalizedModelName, ids[i]); - } - - return promiseArray( - RSVP.all(promises).then(A, null, `DS: Store#findByIds of ${normalizedModelName} complete`) - ); - }, - - /** - This method is called by `findRecord` if it discovers that a particular - type/id pair hasn't been loaded yet to kick off a request to the - adapter. - - @method _fetchRecord - @private - @param {InternalModel} internalModel model - @return {Promise} promise - */ - _fetchRecord(internalModel, options) { - let modelName = internalModel.modelName; - let adapter = this.adapterFor(modelName); - - assert(`You tried to find a record but you have no adapter (for ${modelName})`, adapter); - assert( - `You tried to find a record but your adapter (for ${modelName}) does not implement 'findRecord'`, - typeof adapter.findRecord === 'function' - ); - - return _find(adapter, this, internalModel.type, internalModel.id, internalModel, options); - }, - - _scheduleFetchMany(internalModels, options) { - let fetches = new Array(internalModels.length); - - for (let i = 0; i < internalModels.length; i++) { - fetches[i] = this._scheduleFetch(internalModels[i], options); - } - - return Promise.all(fetches); - }, - - _scheduleFetch(internalModel, options) { - if (internalModel._promiseProxy) { - return internalModel._promiseProxy; - } - - let { id, modelName } = internalModel; - let resolver = RSVP.defer(`Fetching ${modelName}' with id: ${id}`); - let pendingFetchItem = { - internalModel, - resolver, - options, - }; - - if (DEBUG) { - if (this.generateStackTracesForTrackedRequests === true) { - let trace; - - try { - throw new Error(`Trace Origin for scheduled fetch for ${modelName}:${id}.`); - } catch (e) { - trace = e; - } - - // enable folks to discover the origin of this findRecord call when - // debugging. Ideally we would have a tracked queue for requests with - // labels or local IDs that could be used to merge this trace with - // the trace made available when we detect an async leak - pendingFetchItem.trace = trace; - } - } - - let promise = resolver.promise; - - internalModel.loadingData(promise); - if (this._pendingFetch.size === 0) { - emberRun.schedule('actions', this, this.flushAllPendingFetches); - } - - this._pendingFetch.get(modelName).push(pendingFetchItem); - - return promise; - }, - - flushAllPendingFetches() { - if (this.isDestroyed || this.isDestroying) { - return; - } - - this._pendingFetch.forEach(this._flushPendingFetchForType, this); - this._pendingFetch.clear(); - }, - - _flushPendingFetchForType(pendingFetchItems, modelName) { - let store = this; - let adapter = store.adapterFor(modelName); - let shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; - let totalItems = pendingFetchItems.length; - let internalModels = new Array(totalItems); - let seeking = Object.create(null); - - let optionsMap = new WeakMap(); - - for (let i = 0; i < totalItems; i++) { - let pendingItem = pendingFetchItems[i]; - let internalModel = pendingItem.internalModel; - internalModels[i] = internalModel; - optionsMap.set(internalModel, pendingItem.options); - seeking[internalModel.id] = pendingItem; - } - - for (let i = 0; i < totalItems; i++) { - let internalModel = internalModels[i]; - // We may have unloaded the record after scheduling this fetch, in which - // case we must cancel the destroy. This is because we require a record - // to build a snapshot. This is not fundamental: this cancelation code - // can be removed when snapshots can be created for internal models that - // have no records. - if (internalModel.hasScheduledDestroy()) { - internalModels[i].cancelDestroy(); - } - } - - function _fetchRecord(recordResolverPair) { - let recordFetch = store._fetchRecord( - recordResolverPair.internalModel, - recordResolverPair.options - ); - - recordResolverPair.resolver.resolve(recordFetch); - } - - function handleFoundRecords(foundInternalModels, expectedInternalModels) { - // resolve found records - let found = Object.create(null); - for (let i = 0, l = foundInternalModels.length; i < l; i++) { - let internalModel = foundInternalModels[i]; - let pair = seeking[internalModel.id]; - found[internalModel.id] = internalModel; - - if (pair) { - let resolver = pair.resolver; - resolver.resolve(internalModel); - } - } - - // reject missing records - let missingInternalModels = []; - - for (let i = 0, l = expectedInternalModels.length; i < l; i++) { - let internalModel = expectedInternalModels[i]; - - if (!found[internalModel.id]) { - missingInternalModels.push(internalModel); - } - } - - if (missingInternalModels.length) { - warn( - 'Ember Data expected to find records with the following ids in the adapter response but they were missing: [ "' + - missingInternalModels.map(r => r.id).join('", "') + - '" ]', - false, - { - id: 'ds.store.missing-records-from-adapter', - } - ); - rejectInternalModels(missingInternalModels); - } - } - - function rejectInternalModels(internalModels, error) { - for (let i = 0, l = internalModels.length; i < l; i++) { - let internalModel = internalModels[i]; - let pair = seeking[internalModel.id]; - - if (pair) { - pair.resolver.reject( - error || - new Error( - `Expected: '${internalModel}' to be present in the adapter provided payload, but it was not found.` - ) - ); - } - } - } - - if (shouldCoalesce) { - // TODO: Improve records => snapshots => records => snapshots - // - // We want to provide records to all store methods and snapshots to all - // adapter methods. To make sure we're doing that we're providing an array - // of snapshots to adapter.groupRecordsForFindMany(), which in turn will - // return grouped snapshots instead of grouped records. - // - // But since the _findMany() finder is a store method we need to get the - // records from the grouped snapshots even though the _findMany() finder - // will once again convert the records to snapshots for adapter.findMany() - let snapshots = new Array(totalItems); - for (let i = 0; i < totalItems; i++) { - let internalModel = internalModels[i]; - snapshots[i] = internalModel.createSnapshot(optionsMap.get(internalModel)); - } - - let groups = adapter.groupRecordsForFindMany(this, snapshots); - - for (var i = 0, l = groups.length; i < l; i++) { - var group = groups[i]; - var totalInGroup = groups[i].length; - var ids = new Array(totalInGroup); - var groupedInternalModels = new Array(totalInGroup); - - for (var j = 0; j < totalInGroup; j++) { - var internalModel = group[j]._internalModel; - - groupedInternalModels[j] = internalModel; - ids[j] = internalModel.id; - } - - if (totalInGroup > 1) { - (function(groupedInternalModels) { - _findMany(adapter, store, modelName, ids, groupedInternalModels, optionsMap) - .then(function(foundInternalModels) { - handleFoundRecords(foundInternalModels, groupedInternalModels); - }) - .catch(function(error) { - rejectInternalModels(groupedInternalModels, error); - }); - })(groupedInternalModels); - } else if (ids.length === 1) { - var pair = seeking[groupedInternalModels[0].id]; - _fetchRecord(pair); - } else { - assert( - "You cannot return an empty array from adapter's method groupRecordsForFindMany", - false - ); - } - } - } else { - for (let i = 0; i < totalItems; i++) { - _fetchRecord(pendingFetchItems[i]); - } - } - }, - - /** - Get the reference for the specified record. - - Example - - ```javascript - let userRef = store.getReference('user', 1); - - // check if the user is loaded - let isLoaded = userRef.value() !== null; - - // get the record of the reference (null if not yet available) - let user = userRef.value(); - - // get the identifier of the reference - if (userRef.remoteType() === 'id') { - let id = userRef.id(); - } - - // load user (via store.find) - userRef.load().then(...) - - // or trigger a reload - userRef.reload().then(...) - - // provide data for reference - userRef.push({ id: 1, username: '@user' }).then(function(user) { - userRef.value() === user; - }); - ``` - - @method getReference - @param {String} modelName - @param {String|Integer} id - @since 2.5.0 - @return {RecordReference} - */ - getReference(modelName, id) { - if (DEBUG) { - assertDestroyingStore(this, 'getReference'); - } - let normalizedModelName = normalizeModelName(modelName); - - return this._internalModelForId(normalizedModelName, id).recordReference; - }, - - /** - Get a record by a given type and ID without triggering a fetch. - - This method will synchronously return the record if it is available in the store, - otherwise it will return `null`. A record is available if it has been fetched earlier, or - pushed manually into the store. - - See [findRecord](#method_findRecord) if you would like to request this record from the backend. - - _Note: This is a synchronous method and does not return a promise._ - - ```js - let post = store.peekRecord('post', 1); - - post.get('id'); // 1 - ``` - - @since 1.13.0 - @method peekRecord - @param {String} modelName - @param {String|Integer} id - @return {DS.Model|null} record - */ - peekRecord(modelName, id) { - if (DEBUG) { - assertDestroyingStore(this, 'peekRecord'); - } - heimdall.increment(peekRecord); - assert(`You need to pass a model name to the store's peekRecord method`, isPresent(modelName)); - assert( - `You need to pass both a model name and id to the store's peekRecord method`, - isPresent(modelName) && isPresent(id) - ); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - let normalizedModelName = normalizeModelName(modelName); - - if (this.hasRecordForId(normalizedModelName, id)) { - return this._internalModelForId(normalizedModelName, id).getRecord(); - } else { - return null; - } - }, - - /** - This method is called by the record's `reload` method. - - This method calls the adapter's `find` method, which returns a promise. When - **that** promise resolves, `_reloadRecord` will resolve the promise returned - by the record's `reload`. - - @method _reloadRecord - @private - @param {DS.Model} internalModel - @param options optional to include adapterOptions - @return {Promise} promise - */ - _reloadRecord(internalModel, options) { - let { id, modelName } = internalModel; - let adapter = this.adapterFor(modelName); - - assert(`You cannot reload a record without an ID`, id); - assert(`You tried to reload a record but you have no adapter (for ${modelName})`, adapter); - assert( - `You tried to reload a record but your adapter does not implement 'findRecord'`, - typeof adapter.findRecord === 'function' || typeof adapter.find === 'function' - ); - - return this._scheduleFetch(internalModel, options); - }, - - /** - This method returns true if a record for a given modelName and id is already - loaded in the store. Use this function to know beforehand if a findRecord() - will result in a request or that it will be a cache hit. - - Example - - ```javascript - store.hasRecordForId('post', 1); // false - store.findRecord('post', 1).then(function() { - store.hasRecordForId('post', 1); // true - }); - ``` - - @method hasRecordForId - @param {String} modelName - @param {(String|Integer)} id - @return {Boolean} - */ - hasRecordForId(modelName, id) { - if (DEBUG) { - assertDestroyingStore(this, 'hasRecordForId'); - } - assert( - `You need to pass a model name to the store's hasRecordForId method`, - isPresent(modelName) - ); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - - let normalizedModelName = normalizeModelName(modelName); - - let trueId = coerceId(id); - let internalModel = this._internalModelsFor(normalizedModelName).get(trueId); - - return !!internalModel && internalModel.isLoaded(); - }, - - /** - Returns id record for a given type and ID. If one isn't already loaded, - it builds a new record and leaves it in the `empty` state. - - @method recordForId - @private - @param {String} modelName - @param {(String|Integer)} id - @return {DS.Model} record - */ - recordForId(modelName, id) { - if (DEBUG) { - assertDestroyingStore(this, 'recordForId'); - } - assert(`You need to pass a model name to the store's recordForId method`, isPresent(modelName)); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - - return this._internalModelForId(modelName, id).getRecord(); - }, - - _internalModelForId(modelName, id) { - heimdall.increment(_internalModelForId); - let trueId = coerceId(id); - let internalModel = this._internalModelsFor(modelName).get(trueId); - - if (internalModel) { - // unloadRecord is async, if one attempts to unload + then sync push, - // we must ensure the unload is canceled before continuing - // The createRecord path will take _existingInternalModelForId() - // which will call `destroySync` instead for this unload + then - // sync createRecord scenario. Once we have true client-side - // delete signaling, we should never call destroySync - if (internalModel.hasScheduledDestroy()) { - internalModel.cancelDestroy(); - } - - return internalModel; - } - - return this._buildInternalModel(modelName, trueId); - }, - - _internalModelDidReceiveRelationshipData(modelName, id, relationshipData) { - this._relationshipsPayloads.push(modelName, id, relationshipData); - }, - - _internalModelDestroyed(internalModel) { - this._removeFromIdMap(internalModel); - - if (!this.isDestroying) { - this._relationshipsPayloads.unload(internalModel.modelName, internalModel.id); - } - }, - - /** - @method findMany - @private - @param {Array} internalModels - @return {Promise} promise - */ - findMany(internalModels, options) { - if (DEBUG) { - assertDestroyingStore(this, 'findMany'); - } - let finds = new Array(internalModels.length); - - for (let i = 0; i < internalModels.length; i++) { - finds[i] = this._findEmptyInternalModel(internalModels[i], options); - } - - return Promise.all(finds); - }, - - /** - If a relationship was originally populated by the adapter as a link - (as opposed to a list of IDs), this method is called when the - relationship is fetched. - - The link (which is usually a URL) is passed through unchanged, so the - adapter can make whatever request it wants. - - The usual use-case is for the server to register a URL as a link, and - then use that URL in the future to make a request for the relationship. - - @method findHasMany - @private - @param {InternalModel} internalModel - @param {any} link - @param {(Relationship)} relationship - @return {Promise} promise - */ - findHasMany(internalModel, link, relationship, options) { - if (DEBUG) { - assertDestroyingStore(this, 'findHasMany'); - } - let adapter = this.adapterFor(internalModel.modelName); - - assert( - `You tried to load a hasMany relationship but you have no adapter (for ${ - internalModel.modelName - })`, - adapter - ); - assert( - `You tried to load a hasMany relationship from a specified 'link' in the original payload but your adapter does not implement 'findHasMany'`, - typeof adapter.findHasMany === 'function' - ); - - return _findHasMany(adapter, this, internalModel, link, relationship, options); - }, - - /** - @method findBelongsTo - @private - @param {InternalModel} internalModel - @param {any} link - @param {Relationship} relationship - @return {Promise} promise - */ - findBelongsTo(internalModel, link, relationship, options) { - if (DEBUG) { - assertDestroyingStore(this, 'findBelongsTo'); - } - let adapter = this.adapterFor(internalModel.modelName); - - assert( - `You tried to load a belongsTo relationship but you have no adapter (for ${ - internalModel.modelName - })`, - adapter - ); - assert( - `You tried to load a belongsTo relationship from a specified 'link' in the original payload but your adapter does not implement 'findBelongsTo'`, - typeof adapter.findBelongsTo === 'function' - ); - - return _findBelongsTo(adapter, this, internalModel, link, relationship, options); - }, - - /** - This method delegates a query to the adapter. This is the one place where - adapter-level semantics are exposed to the application. - - Each time this method is called a new request is made through the adapter. - - Exposing queries this way seems preferable to creating an abstract query - language for all server-side queries, and then require all adapters to - implement them. - - --- - - If you do something like this: - - ```javascript - store.query('person', { page: 1 }); - ``` - - The call made to the server, using a Rails backend, will look something like this: - - ``` - Started GET "/api/v1/person?page=1" - Processing by Api::V1::PersonsController#index as HTML - Parameters: { "page"=>"1" } - ``` - - --- - - If you do something like this: - - ```javascript - store.query('person', { ids: [1, 2, 3] }); - ``` - - The call to the server, using a Rails backend, will look something like this: - - ``` - Started GET "/api/v1/person?ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3" - Processing by Api::V1::PersonsController#index as HTML - Parameters: { "ids" => ["1", "2", "3"] } - ``` - - This method returns a promise, which is resolved with an - [`AdapterPopulatedRecordArray`](https://emberjs.com/api/data/classes/DS.AdapterPopulatedRecordArray.html) - once the server returns. - - @since 1.13.0 - @method query - @param {String} modelName - @param {any} query an opaque query to be used by the adapter - @param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.query - @return {Promise} promise - */ - query(modelName, query, options) { - if (DEBUG) { - assertDestroyingStore(this, 'query'); - } - assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); - assert(`You need to pass a query hash to the store's query method`, query); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - - let adapterOptionsWrapper = {}; - - if (options && options.adapterOptions) { - adapterOptionsWrapper.adapterOptions = options.adapterOptions; - } - - let normalizedModelName = normalizeModelName(modelName); - return this._query(normalizedModelName, query, null, adapterOptionsWrapper); - }, - - _query(modelName, query, array, options) { - let token = heimdall.start('store._query'); - assert(`You need to pass a model name to the store's query method`, isPresent(modelName)); - assert(`You need to pass a query hash to the store's query method`, query); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - - let modelToken = heimdall.start('initial-modelFor-lookup'); - heimdall.stop(modelToken); - - let adapterToken = heimdall.start('initial-adapterFor-lookup'); - let adapter = this.adapterFor(modelName); - heimdall.stop(adapterToken); - - assert(`You tried to load a query but you have no adapter (for ${modelName})`, adapter); - assert( - `You tried to load a query but your adapter does not implement 'query'`, - typeof adapter.query === 'function' - ); - - let pA = promiseArray(_query(adapter, this, modelName, query, array, options)); - instrument(() => { - pA.finally(() => { - heimdall.stop(token); - }); - }); - return pA; - }, - - /** - This method makes a request for one record, where the `id` is not known - beforehand (if the `id` is known, use [`findRecord`](#method_findRecord) - instead). - - This method can be used when it is certain that the server will return a - single object for the primary data. - - Each time this method is called a new request is made through the adapter. - - Let's assume our API provides an endpoint for the currently logged in user - via: - - ``` - // GET /api/current_user - { - user: { - id: 1234, - username: 'admin' - } - } - ``` - - Since the specific `id` of the `user` is not known beforehand, we can use - `queryRecord` to get the user: - - ```javascript - store.queryRecord('user', {}).then(function(user) { - let username = user.get('username'); - console.log(`Currently logged in as ${username}`); - }); - ``` - - The request is made through the adapters' `queryRecord`: - - ```app/adapters/user.js - import $ from 'jquery'; - import DS from 'ember-data'; - - export default DS.Adapter.extend({ - queryRecord(modelName, query) { - return $.getJSON('/api/current_user'); - } - }); - ``` - - Note: the primary use case for `store.queryRecord` is when a single record - is queried and the `id` is not known beforehand. In all other cases - `store.query` and using the first item of the array is likely the preferred - way: - - ``` - // GET /users?username=unique - { - data: [{ - id: 1234, - type: 'user', - attributes: { - username: "unique" - } - }] - } - ``` - - ```javascript - store.query('user', { username: 'unique' }).then(function(users) { - return users.get('firstObject'); - }).then(function(user) { - let id = user.get('id'); - }); - ``` - - This method returns a promise, which resolves with the found record. - - If the adapter returns no data for the primary data of the payload, then - `queryRecord` resolves with `null`: - - ``` - // GET /users?username=unique - { - data: null - } - ``` - - ```javascript - store.queryRecord('user', { username: 'unique' }).then(function(user) { - console.log(user); // null - }); - ``` - - @since 1.13.0 - @method queryRecord - @param {String} modelName - @param {any} query an opaque query to be used by the adapter - @param {Object} options optional, may include `adapterOptions` hash which will be passed to adapter.queryRecord - @return {Promise} promise which resolves with the found record or `null` - */ - queryRecord(modelName, query, options) { - if (DEBUG) { - assertDestroyingStore(this, 'queryRecord'); - } - assert(`You need to pass a model name to the store's queryRecord method`, isPresent(modelName)); - assert(`You need to pass a query hash to the store's queryRecord method`, query); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - - let normalizedModelName = normalizeModelName(modelName); - let adapter = this.adapterFor(normalizedModelName); - let adapterOptionsWrapper = {}; - - if (options && options.adapterOptions) { - adapterOptionsWrapper.adapterOptions = options.adapterOptions; - } - - assert( - `You tried to make a query but you have no adapter (for ${normalizedModelName})`, - adapter - ); - assert( - `You tried to make a query but your adapter does not implement 'queryRecord'`, - typeof adapter.queryRecord === 'function' - ); - - return promiseObject( - _queryRecord(adapter, this, normalizedModelName, query, adapterOptionsWrapper).then( - internalModel => { - // the promise returned by store.queryRecord is expected to resolve with - // an instance of DS.Model - if (internalModel) { - return internalModel.getRecord(); - } - - return null; - } - ) - ); - }, - - /** - `findAll` asks the adapter's `findAll` method to find the records for the - given type, and returns a promise which will resolve with all records of - this type present in the store, even if the adapter only returns a subset - of them. - - ```app/routes/authors.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - model(params) { - return this.store.findAll('author'); - } - }); - ``` - - _When_ the returned promise resolves depends on the reload behavior, - configured via the passed `options` hash and the result of the adapter's - `shouldReloadAll` method. - - ### Reloading - - If `{ reload: true }` is passed or `adapter.shouldReloadAll` evaluates to - `true`, then the returned promise resolves once the adapter returns data, - regardless if there are already records in the store: - - ```js - store.push({ - data: { - id: 'first', - type: 'author' - } - }); - - // adapter#findAll resolves with - // [ - // { - // id: 'second', - // type: 'author' - // } - // ] - store.findAll('author', { reload: true }).then(function(authors) { - authors.getEach('id'); // ['first', 'second'] - }); - ``` - - If no reload is indicated via the abovementioned ways, then the promise - immediately resolves with all the records currently loaded in the store. - - ### Background Reloading - - Optionally, if `adapter.shouldBackgroundReloadAll` evaluates to `true`, - then a background reload is started. Once this resolves, the array with - which the promise resolves, is updated automatically so it contains all the - records in the store: - - ```app/adapters/application.js - import DS from 'ember-data'; - export default DS.Adapter.extend({ - shouldReloadAll(store, snapshotsArray) { - return false; - }, - - shouldBackgroundReloadAll(store, snapshotsArray) { - return true; - } - }); - - // ... - - store.push({ - data: { - id: 'first', - type: 'author' - } - }); - - let allAuthors; - store.findAll('author').then(function(authors) { - authors.getEach('id'); // ['first'] - - allAuthors = authors; - }); - - // later, once adapter#findAll resolved with - // [ - // { - // id: 'second', - // type: 'author' - // } - // ] - - allAuthors.getEach('id'); // ['first', 'second'] - ``` - - If you would like to force or prevent background reloading, you can set a - boolean value for `backgroundReload` in the options object for - `findAll`. - - ```app/routes/post/edit.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - model() { - return this.store.findAll('post', { backgroundReload: false }); - } - }); - ``` - - If you pass an object on the `adapterOptions` property of the options - argument it will be passed to you adapter via the `snapshotRecordArray` - - ```app/routes/posts.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - model(params) { - return this.store.findAll('post', { - adapterOptions: { subscribe: false } - }); - } - }); - ``` - - ```app/adapters/post.js - import MyCustomAdapter from './custom-adapter'; - - export default MyCustomAdapter.extend({ - findAll(store, type, sinceToken, snapshotRecordArray) { - if (snapshotRecordArray.adapterOptions.subscribe) { - // ... - } - // ... - } - }); - ``` - - See [peekAll](#method_peekAll) to get an array of current records in the - store, without waiting until a reload is finished. - - ### Retrieving Related Model Records - - If you use an adapter such as Ember's default - [`JSONAPIAdapter`](https://emberjs.com/api/data/classes/DS.JSONAPIAdapter.html) - that supports the [JSON API specification](http://jsonapi.org/) and if your server - endpoint supports the use of an - ['include' query parameter](http://jsonapi.org/format/#fetching-includes), - you can use `findAll()` to automatically retrieve additional records related to - those requested by supplying an `include` parameter in the `options` object. - - For example, given a `post` model that has a `hasMany` relationship with a `comment` - model, when we retrieve all of the post records we can have the server also return - all of the posts' comments in the same request: - - ```app/routes/posts.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - model() { - return this.store.findAll('post', { include: 'comments' }); - } - }); - - ``` - Multiple relationships can be requested using an `include` parameter consisting of a - comma-separated list (without white-space) while nested relationships can be specified - using a dot-separated sequence of relationship names. So to request both the posts' - comments and the authors of those comments the request would look like this: - - ```app/routes/posts.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - model() { - return this.store.findAll('post', { include: 'comments,comments.author' }); - } - }); - - ``` - - See [query](#method_query) to only get a subset of records from the server. - - @since 1.13.0 - @method findAll - @param {String} modelName - @param {Object} options - @return {Promise} promise - */ - findAll(modelName, options) { - if (DEBUG) { - assertDestroyingStore(this, 'findAll'); - } - assert(`You need to pass a model name to the store's findAll method`, isPresent(modelName)); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - - let token = heimdall.start('store.findAll'); - let normalizedModelName = normalizeModelName(modelName); - let fetch = this._fetchAll(normalizedModelName, this.peekAll(normalizedModelName), options); - - instrument(() => { - fetch.finally(() => { - heimdall.stop(token); - }); - }); - - return fetch; - }, - - /** - @method _fetchAll - @private - @param {DS.Model} modelName - @param {DS.RecordArray} array - @return {Promise} promise - */ - _fetchAll(modelName, array, options = {}) { - let adapter = this.adapterFor(modelName); - let sinceToken = this._internalModelsFor(modelName).metadata.since; - - assert(`You tried to load all records but you have no adapter (for ${modelName})`, adapter); - assert( - `You tried to load all records but your adapter does not implement 'findAll'`, - typeof adapter.findAll === 'function' - ); - - if (options.reload) { - set(array, 'isUpdating', true); - return promiseArray(_findAll(adapter, this, modelName, sinceToken, options)); - } - - let snapshotArray = array._createSnapshot(options); - - if (adapter.shouldReloadAll(this, snapshotArray)) { - set(array, 'isUpdating', true); - return promiseArray(_findAll(adapter, this, modelName, sinceToken, options)); - } - - if (options.backgroundReload === false) { - return promiseArray(Promise.resolve(array)); - } - - if (options.backgroundReload || adapter.shouldBackgroundReloadAll(this, snapshotArray)) { - set(array, 'isUpdating', true); - _findAll(adapter, this, modelName, sinceToken, options); - } - - return promiseArray(Promise.resolve(array)); - }, - - /** - @method _didUpdateAll - @param {String} modelName - @private - */ - _didUpdateAll(modelName) { - heimdall.increment(_didUpdateAll); - this.recordArrayManager._didUpdateAll(modelName); - }, - - /** - This method returns a filtered array that contains all of the - known records for a given type in the store. - - Note that because it's just a filter, the result will contain any - locally created records of the type, however, it will not make a - request to the backend to retrieve additional records. If you - would like to request all the records from the backend please use - [store.findAll](#method_findAll). - - Also note that multiple calls to `peekAll` for a given type will always - return the same `RecordArray`. - - Example - - ```javascript - let localPosts = store.peekAll('post'); - ``` - - @since 1.13.0 - @method peekAll - @param {String} modelName - @return {DS.RecordArray} - */ - peekAll(modelName) { - if (DEBUG) { - assertDestroyingStore(this, 'peekAll'); - } - heimdall.increment(peekAll); - assert(`You need to pass a model name to the store's peekAll method`, isPresent(modelName)); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - let normalizedModelName = normalizeModelName(modelName); - return this.recordArrayManager.liveRecordArrayFor(normalizedModelName); - }, - - /** - This method unloads all records in the store. - It schedules unloading to happen during the next run loop. - - Optionally you can pass a type which unload all records for a given type. - - ```javascript - store.unloadAll(); - store.unloadAll('post'); - ``` - - @method unloadAll - @param {String} modelName - */ - unloadAll(modelName) { - if (DEBUG) { - assertDestroyedStoreOnly(this, 'unloadAll'); - } - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - !modelName || typeof modelName === 'string' - ); - - if (arguments.length === 0) { - this._identityMap.clear(); - } else { - let normalizedModelName = normalizeModelName(modelName); - this._internalModelsFor(normalizedModelName).clear(); - } - }, - - filter() { - assert( - 'The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page. https://github.com/ember-data/ember-data-filter', - false - ); - }, - - // .............. - // . PERSISTING . - // .............. - - /** - This method is called by `record.save`, and gets passed a - resolver for the promise that `record.save` returns. - - It schedules saving to happen at the end of the run loop. - - @method scheduleSave - @private - @param {InternalModel} internalModel - @param {Resolver} resolver - @param {Object} options - */ - scheduleSave(internalModel, resolver, options) { - let snapshot = internalModel.createSnapshot(options); - internalModel.flushChangedAttributes(); - internalModel.adapterWillCommit(); - this._pendingSave.push({ - snapshot: snapshot, - resolver: resolver, - }); - emberRun.scheduleOnce('actions', this, this.flushPendingSave); - }, - - /** - This method is called at the end of the run loop, and - flushes any records passed into `scheduleSave` - - @method flushPendingSave - @private - */ - flushPendingSave() { - let pending = this._pendingSave.slice(); - this._pendingSave = []; - - for (let i = 0, j = pending.length; i < j; i++) { - let pendingItem = pending[i]; - let snapshot = pendingItem.snapshot; - let resolver = pendingItem.resolver; - let internalModel = snapshot._internalModel; - let adapter = this.adapterFor(internalModel.modelName); - let operation; - - if (internalModel.currentState.stateName === 'root.deleted.saved') { - resolver.resolve(); - continue; - } else if (internalModel.isNew()) { - operation = 'createRecord'; - } else if (internalModel.isDeleted()) { - operation = 'deleteRecord'; - } else { - operation = 'updateRecord'; - } - - resolver.resolve(_commit(adapter, this, operation, snapshot)); - } - }, - - /** - This method is called once the promise returned by an - adapter's `createRecord`, `updateRecord` or `deleteRecord` - is resolved. - - If the data provides a server-generated ID, it will - update the record and the store's indexes. - - @method didSaveRecord - @private - @param {InternalModel} internalModel the in-flight internal model - @param {Object} data optional data (see above) - */ - didSaveRecord(internalModel, dataArg) { - if (DEBUG) { - assertDestroyingStore(this, 'didSaveRecord'); - } - let data; - if (dataArg) { - data = dataArg.data; - } - if (data) { - // normalize relationship IDs into records - this.updateId(internalModel, data); - this._setupRelationshipsForModel(internalModel, data); - } else { - assert( - `Your ${ - internalModel.modelName - } record was saved to the server, but the response does not have an id and no id has been set client side. Records must have ids. Please update the server response to provide an id in the response or generate the id on the client side either before saving the record or while normalizing the response.`, - internalModel.id - ); - } - - //We first make sure the primary data has been updated - //TODO try to move notification to the user to the end of the runloop - internalModel.adapterDidCommit(data); - }, - - /** - This method is called once the promise returned by an - adapter's `createRecord`, `updateRecord` or `deleteRecord` - is rejected with a `DS.InvalidError`. - - @method recordWasInvalid - @private - @param {InternalModel} internalModel - @param {Object} errors - */ - recordWasInvalid(internalModel, errors) { - if (DEBUG) { - assertDestroyingStore(this, 'recordWasInvalid'); - } - internalModel.adapterDidInvalidate(errors); - }, - - /** - This method is called once the promise returned by an - adapter's `createRecord`, `updateRecord` or `deleteRecord` - is rejected (with anything other than a `DS.InvalidError`). - - @method recordWasError - @private - @param {InternalModel} internalModel - @param {Error} error - */ - recordWasError(internalModel, error) { - if (DEBUG) { - assertDestroyingStore(this, 'recordWasError'); - } - internalModel.adapterDidError(error); - }, - - /** - When an adapter's `createRecord`, `updateRecord` or `deleteRecord` - resolves with data, this method extracts the ID from the supplied - data. - - @method updateId - @private - @param {InternalModel} internalModel - @param {Object} data - */ - updateId(internalModel, data) { - if (DEBUG) { - assertDestroyingStore(this, 'updateId'); - } - let oldId = internalModel.id; - let modelName = internalModel.modelName; - let id = coerceId(data.id); - - // ID absolutely can't be missing if the oldID is empty (missing Id in response for a new record) - assert( - `'${modelName}' was saved to the server, but the response does not have an id and your record does not either.`, - !(id === null && oldId === null) - ); - - // ID absolutely can't be different than oldID if oldID is not null - assert( - `'${modelName}:${oldId}' was saved to the server, but the response returned the new id '${id}'. The store cannot assign a new id to a record that already has an id.`, - !(oldId !== null && id !== oldId) - ); - - // ID can be null if oldID is not null (altered ID in response for a record) - // however, this is more than likely a developer error. - if (oldId !== null && id === null) { - warn( - `Your ${modelName} record was saved to the server, but the response does not have an id.`, - !(oldId !== null && id === null) - ); - return; - } - - let existingInternalModel = this._existingInternalModelForId(modelName, id); - - assert( - `'${modelName}' was saved to the server, but the response returned the new id '${id}', which has already been used with another record.'`, - isNone(existingInternalModel) || existingInternalModel === internalModel - ); - - this._internalModelsFor(internalModel.modelName).set(id, internalModel); - - internalModel.setId(id); - }, - - /** - Returns a map of IDs to client IDs for a given modelName. - - @method _internalModelsFor - @private - @param {String} modelName - @return {Object} recordMap - */ - _internalModelsFor(modelName) { - heimdall.increment(_internalModelsFor); - return this._identityMap.retrieve(modelName); - }, - - // ................ - // . LOADING DATA . - // ................ - - /** - This internal method is used by `push`. - - @method _load - @private - @param {Object} data - */ - _load(data) { - heimdall.increment(_load); - let modelName = normalizeModelName(data.type); - let internalModel = this._internalModelForId(modelName, data.id); - - let isUpdate = internalModel.currentState.isEmpty === false; - - internalModel.setupData(data); - - if (isUpdate) { - this.recordArrayManager.recordDidChange(internalModel); - } else { - this.recordArrayManager.recordWasLoaded(internalModel); - } - - return internalModel; - }, - - /* - @deprecated - @private - */ - _modelForMixin(modelName) { - deprecate( - '_modelForMixin is private and deprecated and should never be used directly, use modelFor instead', - false, - { - id: 'ember-data:_modelForMixin', - until: '3.5', - } - ); - assert( - `You need to pass a model name to the store's _modelForMixin method`, - isPresent(modelName) - ); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - let normalizedModelName = normalizeModelName(modelName); - - return _modelForMixin(this, normalizedModelName); - }, - - /** - Returns the model class for the particular `modelName`. - - The class of a model might be useful if you want to get a list of all the - relationship names of the model, see - [`relationshipNames`](https://emberjs.com/api/data/classes/DS.Model.html#property_relationshipNames) - for example. - - @method modelFor - @param {String} modelName - @return {DS.Model} - */ - modelFor(modelName) { - if (DEBUG) { - assertDestroyedStoreOnly(this, 'modelFor'); - } - assert(`You need to pass a model name to the store's modelFor method`, isPresent(modelName)); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - - let maybeFactory = this._modelFactoryFor(modelName); - - // for factorFor factory/class split - return maybeFactory.class ? maybeFactory.class : maybeFactory; - }, - - /* - @deprecated - @private - */ - _modelFor(modelName) { - deprecate('_modelFor is private and deprecated, you should use modelFor instead', false, { - id: 'ember-data:_modelFor', - until: '3.5', - }); - return this.modelFor(modelName); - }, - - _modelFactoryFor(modelName) { - if (DEBUG) { - assertDestroyedStoreOnly(this, '_modelFactoryFor'); - } - assert( - `You need to pass a model name to the store's _modelFactoryFor method`, - isPresent(modelName) - ); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - let normalizedModelName = normalizeModelName(modelName); - let factory = getModelFactory(this, this._modelFactoryCache, normalizedModelName); - - if (factory === null) { - throw new EmberError(`No model was found for '${normalizedModelName}'`); - } - - return factory; - }, - - /* - @deprecated - @private - */ - modelFactoryFor(modelName) { - deprecate('modelFactoryFor is private and deprecated', false, { - id: 'ember-data:modelFactoryFor', - until: '3.5', - }); - return this._modelFactoryFor(modelName); - }, - - /* - Returns whether a ModelClass exists for a given modelName - This exists for legacy support for the RESTSerializer, - which due to how it must guess whether a key is a model - must query for whether a match exists. - - We should investigate an RFC to make this public or removing - this requirement. - - @private - */ - _hasModelFor(modelName) { - if (DEBUG) { - assertDestroyingStore(this, '_hasModelFor'); - } - assert(`You need to pass a model name to the store's hasModelFor method`, isPresent(modelName)); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - let normalizedModelName = normalizeModelName(modelName); - let factory = getModelFactory(this, this._modelFactoryCache, normalizedModelName); - - return factory !== null; - }, - - /** - Push some data for a given type into the store. - - This method expects normalized [JSON API](http://jsonapi.org/) document. This means you have to follow [JSON API specification](http://jsonapi.org/format/) with few minor adjustments: - - record's `type` should always be in singular, dasherized form - - members (properties) should be camelCased - - [Your primary data should be wrapped inside `data` property](http://jsonapi.org/format/#document-top-level): - - ```js - store.push({ - data: { - // primary data for single record of type `Person` - id: '1', - type: 'person', - attributes: { - firstName: 'Daniel', - lastName: 'Kmak' - } - } - }); - ``` - - [Demo.](http://ember-twiddle.com/fb99f18cd3b4d3e2a4c7) - - `data` property can also hold an array (of records): - - ```js - store.push({ - data: [ - // an array of records - { - id: '1', - type: 'person', - attributes: { - firstName: 'Daniel', - lastName: 'Kmak' - } - }, - { - id: '2', - type: 'person', - attributes: { - firstName: 'Tom', - lastName: 'Dale' - } - } - ] - }); - ``` - - [Demo.](http://ember-twiddle.com/69cdbeaa3702159dc355) - - There are some typical properties for `JSONAPI` payload: - * `id` - mandatory, unique record's key - * `type` - mandatory string which matches `model`'s dasherized name in singular form - * `attributes` - object which holds data for record attributes - `DS.attr`'s declared in model - * `relationships` - object which must contain any of the following properties under each relationships' respective key (example path is `relationships.achievements.data`): - - [`links`](http://jsonapi.org/format/#document-links) - - [`data`](http://jsonapi.org/format/#document-resource-object-linkage) - place for primary data - - [`meta`](http://jsonapi.org/format/#document-meta) - object which contains meta-information about relationship - - For this model: - - ```app/models/person.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - - children: DS.hasMany('person') - }); - ``` - - To represent the children as IDs: - - ```js - { - data: { - id: '1', - type: 'person', - attributes: { - firstName: 'Tom', - lastName: 'Dale' - }, - relationships: { - children: { - data: [ - { - id: '2', - type: 'person' - }, - { - id: '3', - type: 'person' - }, - { - id: '4', - type: 'person' - } - ] - } - } - } - } - ``` - - [Demo.](http://ember-twiddle.com/343e1735e034091f5bde) - - To represent the children relationship as a URL: - - ```js - { - data: { - id: '1', - type: 'person', - attributes: { - firstName: 'Tom', - lastName: 'Dale' - }, - relationships: { - children: { - links: { - related: '/people/1/children' - } - } - } - } - } - ``` - - If you're streaming data or implementing an adapter, make sure - that you have converted the incoming data into this form. The - store's [normalize](#method_normalize) method is a convenience - helper for converting a json payload into the form Ember Data - expects. - - ```js - store.push(store.normalize('person', data)); - ``` - - This method can be used both to push in brand new - records, as well as to update existing records. - - @method push - @param {Object} data - @return {DS.Model|Array} the record(s) that was created or - updated. - */ - push(data) { - if (DEBUG) { - assertDestroyingStore(this, 'push'); - } - let token = heimdall.start('store.push'); - let pushed = this._push(data); - - if (Array.isArray(pushed)) { - let records = pushed.map(internalModel => internalModel.getRecord()); - heimdall.stop(token); - return records; - } - - if (pushed === null) { - heimdall.stop(token); - return null; - } - - let record = pushed.getRecord(); - heimdall.stop(token); - return record; - }, - - /* - Push some data in the form of a json-api document into the store, - without creating materialized records. - - @method _push - @private - @param {Object} jsonApiDoc - @return {DS.InternalModel|Array} pushed InternalModel(s) - */ - _push(jsonApiDoc) { - if (DEBUG) { - assertDestroyingStore(this, '_push'); - } - let token = heimdall.start('store._push'); - let internalModelOrModels = this._backburner.join(() => { - let included = jsonApiDoc.included; - let i, length; - - if (included) { - for (i = 0, length = included.length; i < length; i++) { - this._pushInternalModel(included[i]); - } - } - - if (Array.isArray(jsonApiDoc.data)) { - length = jsonApiDoc.data.length; - let internalModels = new Array(length); - - for (i = 0; i < length; i++) { - internalModels[i] = this._pushInternalModel(jsonApiDoc.data[i]); - } - return internalModels; - } - - if (jsonApiDoc.data === null) { - return null; - } - - assert( - `Expected an object in the 'data' property in a call to 'push' for ${ - jsonApiDoc.type - }, but was ${typeOf(jsonApiDoc.data)}`, - typeOf(jsonApiDoc.data) === 'object' - ); - - return this._pushInternalModel(jsonApiDoc.data); - }); - heimdall.stop(token); - return internalModelOrModels; - }, - - _pushInternalModel(data) { - heimdall.increment(_pushInternalModel); - let modelName = data.type; - assert( - `You must include an 'id' for ${modelName} in an object passed to 'push'`, - data.id !== null && data.id !== undefined && data.id !== '' - ); - assert( - `You tried to push data with a type '${modelName}' but no model could be found with that name.`, - this._hasModelFor(modelName) - ); - - if (DEBUG) { - // If ENV.DS_WARN_ON_UNKNOWN_KEYS is set to true and the payload - // contains unknown attributes or relationships, log a warning. - - if (ENV.DS_WARN_ON_UNKNOWN_KEYS) { - let modelClass = this.modelFor(modelName); - - // Check unknown attributes - let unknownAttributes = Object.keys(data.attributes || {}).filter(key => { - return !get(modelClass, 'fields').has(key); - }); - let unknownAttributesMessage = `The payload for '${modelName}' contains these unknown attributes: ${unknownAttributes}. Make sure they've been defined in your model.`; - warn(unknownAttributesMessage, unknownAttributes.length === 0, { - id: 'ds.store.unknown-keys-in-payload', - }); - - // Check unknown relationships - let unknownRelationships = Object.keys(data.relationships || {}).filter(key => { - return !get(modelClass, 'fields').has(key); - }); - let unknownRelationshipsMessage = `The payload for '${modelName}' contains these unknown relationships: ${unknownRelationships}. Make sure they've been defined in your model.`; - warn(unknownRelationshipsMessage, unknownRelationships.length === 0, { - id: 'ds.store.unknown-keys-in-payload', - }); - } - } - - // Actually load the record into the store. - let internalModel = this._load(data); - - this._setupRelationshipsForModel(internalModel, data); - - return internalModel; - }, - - _setupRelationshipsForModel(internalModel, data) { - if (data.relationships === undefined) { - return; - } - - if (this._pushedInternalModels.push(internalModel, data) !== 2) { - return; - } - - this._backburner.schedule('normalizeRelationships', this, this._setupRelationships); - }, - - _setupRelationships() { - heimdall.increment(_setupRelationships); - let setupToken = heimdall.start('store._setupRelationships'); - let pushed = this._pushedInternalModels; - - // Cache the inverse maps for each modelClass that we visit during this - // payload push. In the common case where we are pushing many more - // instances than types we want to minimize the cost of looking up the - // inverse map and the overhead of Ember.get adds up. - let modelNameToInverseMap; - - for (let i = 0, l = pushed.length; i < l; i += 2) { - modelNameToInverseMap = modelNameToInverseMap || Object.create(null); - // This will convert relationships specified as IDs into DS.Model instances - // (possibly unloaded) and also create the data structures used to track - // relationships. - let internalModel = pushed[i]; - let data = pushed[i + 1]; - setupRelationships(this, internalModel, data, modelNameToInverseMap); - } - - pushed.length = 0; - heimdall.stop(setupToken); - }, - - /** - Push some raw data into the store. - - This method can be used both to push in brand new - records, as well as to update existing records. You - can push in more than one type of object at once. - All objects should be in the format expected by the - serializer. - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.ActiveModelSerializer; - ``` - - ```js - let pushData = { - posts: [ - { id: 1, post_title: "Great post", comment_ids: [2] } - ], - comments: [ - { id: 2, comment_body: "Insightful comment" } - ] - } - - store.pushPayload(pushData); - ``` - - By default, the data will be deserialized using a default - serializer (the application serializer if it exists). - - Alternatively, `pushPayload` will accept a model type which - will determine which serializer will process the payload. - - ```app/serializers/application.js - import DS from 'ember-data'; - - export default DS.ActiveModelSerializer; - ``` - - ```app/serializers/post.js - import DS from 'ember-data'; - - export default DS.JSONSerializer; - ``` - - ```js - store.pushPayload(pushData); // Will use the application serializer - store.pushPayload('post', pushData); // Will use the post serializer - ``` - - @method pushPayload - @param {String} modelName Optionally, a model type used to determine which serializer will be used - @param {Object} inputPayload - */ - pushPayload(modelName, inputPayload) { - if (DEBUG) { - assertDestroyingStore(this, 'pushPayload'); - } - let serializer; - let payload; - if (!inputPayload) { - payload = modelName; - serializer = this.serializerFor('application'); - assert( - `You cannot use 'store#pushPayload' without a modelName unless your default serializer defines 'pushPayload'`, - typeof serializer.pushPayload === 'function' - ); - } else { - payload = inputPayload; - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - let normalizedModelName = normalizeModelName(modelName); - serializer = this.serializerFor(normalizedModelName); - } - serializer.pushPayload(this, payload); - }, - - /** - `normalize` converts a json payload into the normalized form that - [push](#method_push) expects. - - Example - - ```js - socket.on('message', function(message) { - let modelName = message.model; - let data = message.data; - store.push(store.normalize(modelName, data)); - }); - ``` - - @method normalize - @param {String} modelName The name of the model type for this payload - @param {Object} payload - @return {Object} The normalized payload - */ - normalize(modelName, payload) { - if (DEBUG) { - assertDestroyingStore(this, 'normalize'); - } - heimdall.increment(normalize); - assert(`You need to pass a model name to the store's normalize method`, isPresent(modelName)); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${inspect( - modelName - )}`, - typeof modelName === 'string' - ); - let normalizedModelName = normalizeModelName(modelName); - let serializer = this.serializerFor(normalizedModelName); - let model = this.modelFor(normalizedModelName); - return serializer.normalize(model, payload); - }, - - /** - Build a brand new record for a given type, ID, and - initial data. - - @method _buildInternalModel - @private - @param {String} modelName - @param {String} id - @param {Object} data - @return {InternalModel} internal model - */ - _buildInternalModel(modelName, id, data) { - heimdall.increment(_buildInternalModel); - - assert( - `You can no longer pass a modelClass as the first argument to store._buildInternalModel. Pass modelName instead.`, - typeof modelName === 'string' - ); - - let existingInternalModel = this._existingInternalModelForId(modelName, id); - - assert( - `The id ${id} has already been used with another record for modelClass '${modelName}'.`, - !existingInternalModel - ); - - // lookupFactory should really return an object that creates - // instances with the injections applied - let internalModel = new InternalModel(modelName, id, this, data); - - this._internalModelsFor(modelName).add(internalModel, id); - - return internalModel; - }, - - _existingInternalModelForId(modelName, id) { - let internalModel = this._internalModelsFor(modelName).get(id); - - if (internalModel && internalModel.hasScheduledDestroy()) { - // unloadRecord is async, if one attempts to unload + then sync create, - // we must ensure the unload is complete before starting the create - // The push path will take _internalModelForId() - // which will call `cancelDestroy` instead for this unload + then - // sync push scenario. Once we have true client-side - // delete signaling, we should never call destroySync - internalModel.destroySync(); - internalModel = null; - } - return internalModel; - }, - - //Called by the state machine to notify the store that the record is ready to be interacted with - recordWasLoaded(record) { - if (DEBUG) { - assertDestroyingStore(this, 'recordWasLoaded'); - } - this.recordArrayManager.recordWasLoaded(record); - }, - - // ............... - // . DESTRUCTION . - // ............... - - /** - When a record is destroyed, this un-indexes it and - removes it from any record arrays so it can be GCed. - - @method _removeFromIdMap - @private - @param {InternalModel} internalModel - */ - _removeFromIdMap(internalModel) { - let recordMap = this._internalModelsFor(internalModel.modelName); - let id = internalModel.id; - - recordMap.remove(internalModel, id); - }, - - // ...................... - // . PER-TYPE ADAPTERS - // ...................... - - /** - Returns an instance of the adapter for a given type. For - example, `adapterFor('person')` will return an instance of - `App.PersonAdapter`. - - If no `App.PersonAdapter` is found, this method will look - for an `App.ApplicationAdapter` (the default adapter for - your entire application). - - If no `App.ApplicationAdapter` is found, it will return - the value of the `defaultAdapter`. - - @method adapterFor - @public - @param {String} modelName - @return DS.Adapter - */ - adapterFor(modelName) { - if (DEBUG) { - assertDestroyingStore(this, 'adapterFor'); - } - heimdall.increment(adapterFor); - assert(`You need to pass a model name to the store's adapterFor method`, isPresent(modelName)); - assert( - `Passing classes to store.adapterFor has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - let normalizedModelName = normalizeModelName(modelName); - - let { _adapterCache } = this; - let adapter = _adapterCache[normalizedModelName]; - if (adapter) { - return adapter; - } - - let owner = getOwner(this); - - adapter = owner.lookup(`adapter:${normalizedModelName}`); - if (adapter !== undefined) { - set(adapter, 'store', this); - _adapterCache[normalizedModelName] = adapter; - return adapter; - } - - // no adapter found for the specific model, fallback and check for application adapter - adapter = _adapterCache.application || owner.lookup('adapter:application'); - if (adapter !== undefined) { - set(adapter, 'store', this); - _adapterCache[normalizedModelName] = adapter; - _adapterCache.application = adapter; - return adapter; - } - - // no model specific adapter or application adapter, check for an `adapter` - // property defined on the store - let adapterName = this.get('adapter'); - adapter = _adapterCache[adapterName] || owner.lookup(`adapter:${adapterName}`); - if (adapter !== undefined) { - set(adapter, 'store', this); - _adapterCache[normalizedModelName] = adapter; - _adapterCache[adapterName] = adapter; - return adapter; - } - - // final fallback, no model specific adapter, no application adapter, no - // `adapter` property on store: use json-api adapter - adapter = _adapterCache['-json-api'] || owner.lookup('adapter:-json-api'); - set(adapter, 'store', this); - _adapterCache[normalizedModelName] = adapter; - _adapterCache['-json-api'] = adapter; - return adapter; - }, - - // .............................. - // . RECORD CHANGE NOTIFICATION . - // .............................. - - /** - Returns an instance of the serializer for a given type. For - example, `serializerFor('person')` will return an instance of - `App.PersonSerializer`. - - If no `App.PersonSerializer` is found, this method will look - for an `App.ApplicationSerializer` (the default serializer for - your entire application). - - if no `App.ApplicationSerializer` is found, it will attempt - to get the `defaultSerializer` from the `PersonAdapter` - (`adapterFor('person')`). - - If a serializer cannot be found on the adapter, it will fall back - to an instance of `DS.JSONSerializer`. - - @method serializerFor - @public - @param {String} modelName the record to serialize - @return {DS.Serializer} - */ - serializerFor(modelName) { - if (DEBUG) { - assertDestroyingStore(this, 'serializerFor'); - } - heimdall.increment(serializerFor); - assert( - `You need to pass a model name to the store's serializerFor method`, - isPresent(modelName) - ); - assert( - `Passing classes to store.serializerFor has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - let normalizedModelName = normalizeModelName(modelName); - - let { _serializerCache } = this; - let serializer = _serializerCache[normalizedModelName]; - if (serializer) { - return serializer; - } - - let owner = getOwner(this); - - serializer = owner.lookup(`serializer:${normalizedModelName}`); - if (serializer !== undefined) { - set(serializer, 'store', this); - _serializerCache[normalizedModelName] = serializer; - return serializer; - } - - // no serializer found for the specific model, fallback and check for application serializer - serializer = _serializerCache.application || owner.lookup('serializer:application'); - if (serializer !== undefined) { - set(serializer, 'store', this); - _serializerCache[normalizedModelName] = serializer; - _serializerCache.application = serializer; - return serializer; - } - - // no model specific serializer or application serializer, check for the `defaultSerializer` - // property defined on the adapter - let adapter = this.adapterFor(modelName); - let serializerName = get(adapter, 'defaultSerializer'); - serializer = _serializerCache[serializerName] || owner.lookup(`serializer:${serializerName}`); - if (serializer !== undefined) { - set(serializer, 'store', this); - _serializerCache[normalizedModelName] = serializer; - _serializerCache[serializerName] = serializer; - return serializer; - } - - // final fallback, no model specific serializer, no application serializer, no - // `serializer` property on store: use json-api serializer - serializer = _serializerCache['-default'] || owner.lookup('serializer:-default'); - set(serializer, 'store', this); - _serializerCache[normalizedModelName] = serializer; - _serializerCache['-default'] = serializer; - - return serializer; - }, - - willDestroy() { - this._super(...arguments); - this._pushedInternalModels = null; - this.recordArrayManager.destroy(); - - this._relationshipsPayloads = null; - this._adapterCache = null; - this._serializerCache = null; - - this.unloadAll(); - - if (DEBUG) { - unregisterWaiter(this.__asyncWaiter); - let shouldTrack = this.shouldTrackAsyncRequests; - let tracked = this._trackedAsyncRequests; - let isSettled = tracked.length === 0; - - if (!isSettled) { - if (shouldTrack) { - throw new Error( - 'Async Request leaks detected. Add a breakpoint here and set `store.generateStackTracesForTrackedRequests = true;`to inspect traces for leak origins:\n\t - ' + - tracked.map(o => o.label).join('\n\t - ') - ); - } else { - warn( - 'Async Request leaks detected. Add a breakpoint here and set `store.generateStackTracesForTrackedRequests = true;`to inspect traces for leak origins:\n\t - ' + - tracked.map(o => o.label).join('\n\t - '), - false, - { - id: 'ds.async.leak.detected', - } - ); - } - } - } - }, - - _updateRelationshipState(relationship) { - if (this._updatedRelationships.push(relationship) !== 1) { - return; - } - - this._backburner.join(() => { - this._backburner.schedule('syncRelationships', this, this._flushUpdatedRelationships); - }); - }, - - _flushUpdatedRelationships() { - let updated = this._updatedRelationships; - - for (let i = 0, l = updated.length; i < l; i++) { - updated[i].flushCanonical(); - } - - updated.length = 0; - }, - - _updateInternalModel(internalModel) { - if (this._updatedInternalModels.push(internalModel) !== 1) { - return; - } - - emberRun.schedule('actions', this, this._flushUpdatedInternalModels); - }, - - _flushUpdatedInternalModels() { - let updated = this._updatedInternalModels; - - for (let i = 0, l = updated.length; i < l; i++) { - updated[i]._triggerDeferredTriggers(); - } - - updated.length = 0; - }, - - _pushResourceIdentifier(relationship, resourceIdentifier) { - if (isNone(resourceIdentifier)) { - return; - } - if (DEBUG) { - assertRelationshipData( - this, - relationship.internalModel, - resourceIdentifier, - relationship.relationshipMeta - ); - } - - return this._internalModelForId(resourceIdentifier.type, resourceIdentifier.id); - }, - - _pushResourceIdentifiers(relationship, resourceIdentifiers) { - if (isNone(resourceIdentifiers)) { - return; - } - - assert( - `A ${ - relationship.internalModel.modelName - } record was pushed into the store with the value of ${relationship.key} being '${inspect( - resourceIdentifiers - )}', but ${ - relationship.key - } is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, - Array.isArray(resourceIdentifiers) - ); - - let _internalModels = new Array(resourceIdentifiers.length); - for (let i = 0; i < resourceIdentifiers.length; i++) { - _internalModels[i] = this._pushResourceIdentifier(relationship, resourceIdentifiers[i]); - } - return _internalModels; - }, -}); - -function _commit(adapter, store, operation, snapshot) { - let internalModel = snapshot._internalModel; - let modelName = snapshot.modelName; - let modelClass = store.modelFor(modelName); - assert(`You tried to update a record but you have no adapter (for ${modelName})`, adapter); - assert( - `You tried to update a record but your adapter (for ${modelName}) does not implement '${operation}'`, - typeof adapter[operation] === 'function' - ); - - let promise = Promise.resolve().then(() => adapter[operation](store, modelClass, snapshot)); - let serializer = serializerForAdapter(store, adapter, modelName); - let label = `DS: Extract and notify about ${operation} completion of ${internalModel}`; - - assert( - `Your adapter's '${operation}' method must return a value, but it returned 'undefined'`, - promise !== undefined - ); - - promise = guardDestroyedStore(promise, store, label); - promise = _guard(promise, _bind(_objectIsAlive, internalModel)); - - return promise.then( - adapterPayload => { - /* - Note to future spelunkers hoping to optimize. - We rely on this `run` to create a run loop if needed - that `store._push` and `store.didSaveRecord` will both share. - - We use `join` because it is often the case that we - have an outer run loop available still from the first - call to `store._push`; - */ - store._backburner.join(() => { - let payload, data; - if (adapterPayload) { - payload = normalizeResponseHelper( - serializer, - store, - modelClass, - adapterPayload, - snapshot.id, - operation - ); - if (payload.included) { - store._push({ data: null, included: payload.included }); - } - data = payload.data; - } - store.didSaveRecord(internalModel, { data }); - }); - - return internalModel; - }, - function(error) { - if (error instanceof InvalidError) { - let errors = serializer.extractErrors(store, modelClass, error, snapshot.id); - - store.recordWasInvalid(internalModel, errors); - } else { - store.recordWasError(internalModel, error); - } - - throw error; - }, - label - ); -} - -function isInverseRelationshipInitialized(store, internalModel, data, key, modelNameToInverseMap) { - let relationshipData = data.relationships[key].data; - - if (!relationshipData) { - // can't check inverse for eg { comments: { links: { related: URL }}} - return false; - } - - let inverseMap = modelNameToInverseMap[internalModel.modelName]; - if (!inverseMap) { - inverseMap = modelNameToInverseMap[internalModel.modelName] = get( - internalModel.type, - 'inverseMap' - ); - } - let inverseRelationshipMetadata = inverseMap[key]; - if (inverseRelationshipMetadata === undefined) { - inverseRelationshipMetadata = internalModel.type.inverseFor(key, store); - } - - if (!inverseRelationshipMetadata) { - return false; - } - - let { name: inverseRelationshipName } = inverseRelationshipMetadata; - - if (Array.isArray(relationshipData)) { - for (let i = 0; i < relationshipData.length; ++i) { - let inverseInternalModel = store - ._internalModelsFor(relationshipData[i].type) - .get(relationshipData[i].id); - if ( - inverseInternalModel && - inverseInternalModel._relationships.has(inverseRelationshipName) - ) { - return true; - } - } - - return false; - } else { - let inverseInternalModel = store - ._internalModelsFor(relationshipData.type) - .get(relationshipData.id); - return inverseInternalModel && inverseInternalModel._relationships.has(inverseRelationshipName); - } -} - -/** - * @function - * @param store - * @param cache modelFactoryCache - * @param normalizedModelName already normalized modelName - * @return {*} - */ -function getModelFactory(store, cache, normalizedModelName) { - let factory = cache[normalizedModelName]; - - if (!factory) { - factory = _lookupModelFactory(store, normalizedModelName); - - if (!factory) { - //Support looking up mixins as base types for polymorphic relationships - factory = _modelForMixin(store, normalizedModelName); - } - - if (!factory) { - // we don't cache misses in case someone wants to register a missing model - return null; - } - - // interopt with the future - let klass = getOwner(store).factoryFor ? factory.class : factory; - assert(`'${inspect(klass)}' does not appear to be an ember-data model`, klass.isModel); - - // TODO: deprecate this - let hasOwnModelNameSet = klass.modelName && klass.hasOwnProperty('modelName'); - if (!hasOwnModelNameSet) { - klass.modelName = normalizedModelName; - } - - cache[normalizedModelName] = factory; - } - - return factory; -} - -function _lookupModelFactory(store, normalizedModelName) { - let owner = getOwner(store); - - if (owner.factoryFor) { - return owner.factoryFor(`model:${normalizedModelName}`); - } else { - return owner._lookupFactory(`model:${normalizedModelName}`); - } -} - -/* - In case someone defined a relationship to a mixin, for example: - ``` - let Comment = DS.Model.extend({ - owner: belongsTo('commentable'. { polymorphic: true }) - }); - let Commentable = Ember.Mixin.create({ - comments: hasMany('comment') - }); - ``` - we want to look up a Commentable class which has all the necessary - relationship metadata. Thus, we look up the mixin and create a mock - DS.Model, so we can access the relationship CPs of the mixin (`comments`) - in this case -*/ -function _modelForMixin(store, normalizedModelName) { - // container.registry = 2.1 - // container._registry = 1.11 - 2.0 - // container = < 1.11 - let owner = getOwner(store); - let mixin; - - if (owner.factoryFor) { - let MaybeMixin = owner.factoryFor(`mixin:${normalizedModelName}`); - mixin = MaybeMixin && MaybeMixin.class; - } else { - mixin = owner._lookupFactory(`mixin:${normalizedModelName}`); - } - - if (mixin) { - let ModelForMixin = Model.extend(mixin); - ModelForMixin.reopenClass({ - __isMixin: true, - __mixin: mixin, - }); - - //Cache the class as a model - owner.register('model:' + normalizedModelName, ModelForMixin); - } - - return _lookupModelFactory(store, normalizedModelName); -} - -function setupRelationships(store, internalModel, data, modelNameToInverseMap) { - Object.keys(data.relationships).forEach(relationshipName => { - let relationships = internalModel._relationships; - let relationshipRequiresNotification = - relationships.has(relationshipName) || - isInverseRelationshipInitialized( - store, - internalModel, - data, - relationshipName, - modelNameToInverseMap - ); - - if (relationshipRequiresNotification) { - let relationshipData = data.relationships[relationshipName]; - relationships.get(relationshipName).push(relationshipData, false); - } - - if (DEBUG) { - let relationshipMeta = get(internalModel.type, 'relationshipsByName').get(relationshipName); - let relationshipData = data.relationships[relationshipName]; - if (!relationshipData || !relationshipMeta) { - return; - } - - if (relationshipData.links) { - let isAsync = relationshipMeta.options && relationshipMeta.options.async !== false; - warn( - `You pushed a record of type '${ - internalModel.modelName - }' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload. EmberData will treat this relationship as known-to-be-empty.`, - isAsync || relationshipData.data, - { - id: 'ds.store.push-link-for-sync-relationship', - } - ); - } else if (relationshipData.data) { - if (relationshipMeta.kind === 'belongsTo') { - assertRelationshipData(store, internalModel, relationshipData.data, relationshipMeta); - } else if (relationshipMeta.kind === 'hasMany') { - assert( - `A ${ - internalModel.modelName - } record was pushed into the store with the value of ${relationshipName} being '${inspect( - relationshipData.data - )}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, - Array.isArray(relationshipData.data) - ); - if (Array.isArray(relationshipData.data)) { - for (let i = 0; i < relationshipData.data.length; i++) { - assertRelationshipData( - store, - internalModel, - relationshipData.data[i], - relationshipMeta - ); - } - } - } - } - } - }); -} - -let assertRelationshipData; -let assertDestroyingStore; -let assertDestroyedStoreOnly; - -if (DEBUG) { - assertRelationshipData = function assertRelationshipData(store, internalModel, data, meta) { - assert( - `A ${internalModel.modelName} record was pushed into the store with the value of ${ - meta.key - } being '${JSON.stringify(data)}', but ${ - meta.key - } is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, - !Array.isArray(data) - ); - assert( - `Encountered a relationship identifier without a type for the ${meta.kind} relationship '${ - meta.key - }' on ${internalModel}, expected a json-api identifier with type '${ - meta.type - }' but found '${JSON.stringify( - data - )}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, - data === null || (typeof data.type === 'string' && data.type.length) - ); - assert( - `Encountered a relationship identifier without an id for the ${meta.kind} relationship '${ - meta.key - }' on ${internalModel}, expected a json-api identifier but found '${JSON.stringify( - data - )}'. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, - data === null || coerceId(data.id) - ); - assert( - `Encountered a relationship identifier with type '${data.type}' for the ${ - meta.kind - } relationship '${meta.key}' on ${internalModel}, Expected a json-api identifier with type '${ - meta.type - }'. No model was found for '${data.type}'.`, - data === null || !data.type || store._hasModelFor(data.type) - ); - }; - assertDestroyingStore = function assertDestroyedStore(store, method) { - if (!store.shouldAssertMethodCallsOnDestroyedStore) { - deprecate( - `Attempted to call store.${method}(), but the store instance has already been destroyed.`, - !(store.isDestroying || store.isDestroyed), - { - id: 'ember-data:method-calls-on-destroyed-store', - until: '3.8', - } - ); - } else { - assert( - `Attempted to call store.${method}(), but the store instance has already been destroyed.`, - !(store.isDestroying || store.isDestroyed) - ); - } - }; - assertDestroyedStoreOnly = function assertDestroyedStoreOnly(store, method) { - if (!store.shouldAssertMethodCallsOnDestroyedStore) { - deprecate( - `Attempted to call store.${method}(), but the store instance has already been destroyed.`, - !store.isDestroyed, - { - id: 'ember-data:method-calls-on-destroyed-store', - until: '3.8', - } - ); - } else { - assert( - `Attempted to call store.${method}(), but the store instance has already been destroyed.`, - !store.isDestroyed - ); - } - }; -} - -export default Store; diff --git a/addon/-record-data-private/attr.js b/addon/-private/attr.js similarity index 100% rename from addon/-record-data-private/attr.js rename to addon/-private/attr.js diff --git a/addon/-record-data-private/index.js b/addon/-private/index.js similarity index 100% rename from addon/-record-data-private/index.js rename to addon/-private/index.js diff --git a/addon/-record-data-private/system/many-array.js b/addon/-private/system/many-array.js similarity index 100% rename from addon/-record-data-private/system/many-array.js rename to addon/-private/system/many-array.js diff --git a/addon/-record-data-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js similarity index 100% rename from addon/-record-data-private/system/model/internal-model.js rename to addon/-private/system/model/internal-model.js diff --git a/addon/-record-data-private/system/model/model.js b/addon/-private/system/model/model.js similarity index 100% rename from addon/-record-data-private/system/model/model.js rename to addon/-private/system/model/model.js diff --git a/addon/-record-data-private/system/model/record-data.js b/addon/-private/system/model/record-data.js similarity index 100% rename from addon/-record-data-private/system/model/record-data.js rename to addon/-private/system/model/record-data.js diff --git a/addon/-record-data-private/system/model/states.js b/addon/-private/system/model/states.js similarity index 100% rename from addon/-record-data-private/system/model/states.js rename to addon/-private/system/model/states.js diff --git a/addon/-record-data-private/system/promise-proxies.js b/addon/-private/system/promise-proxies.js similarity index 100% rename from addon/-record-data-private/system/promise-proxies.js rename to addon/-private/system/promise-proxies.js diff --git a/addon/-record-data-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js similarity index 100% rename from addon/-record-data-private/system/references/belongs-to.js rename to addon/-private/system/references/belongs-to.js diff --git a/addon/-record-data-private/system/references/has-many.js b/addon/-private/system/references/has-many.js similarity index 100% rename from addon/-record-data-private/system/references/has-many.js rename to addon/-private/system/references/has-many.js diff --git a/addon/-record-data-private/system/references/reference.js b/addon/-private/system/references/reference.js similarity index 100% rename from addon/-record-data-private/system/references/reference.js rename to addon/-private/system/references/reference.js diff --git a/addon/-record-data-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js similarity index 100% rename from addon/-record-data-private/system/relationships/belongs-to.js rename to addon/-private/system/relationships/belongs-to.js diff --git a/addon/-record-data-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js similarity index 100% rename from addon/-record-data-private/system/relationships/ext.js rename to addon/-private/system/relationships/ext.js diff --git a/addon/-record-data-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js similarity index 100% rename from addon/-record-data-private/system/relationships/has-many.js rename to addon/-private/system/relationships/has-many.js diff --git a/addon/-record-data-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js similarity index 100% rename from addon/-record-data-private/system/relationships/state/belongs-to.js rename to addon/-private/system/relationships/state/belongs-to.js diff --git a/addon/-record-data-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js similarity index 100% rename from addon/-record-data-private/system/relationships/state/create.js rename to addon/-private/system/relationships/state/create.js diff --git a/addon/-record-data-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js similarity index 100% rename from addon/-record-data-private/system/relationships/state/has-many.js rename to addon/-private/system/relationships/state/has-many.js diff --git a/addon/-record-data-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js similarity index 100% rename from addon/-record-data-private/system/relationships/state/relationship.js rename to addon/-private/system/relationships/state/relationship.js diff --git a/addon/-record-data-private/system/snapshot.js b/addon/-private/system/snapshot.js similarity index 100% rename from addon/-record-data-private/system/snapshot.js rename to addon/-private/system/snapshot.js diff --git a/addon/-record-data-private/system/store.js b/addon/-private/system/store.js similarity index 100% rename from addon/-record-data-private/system/store.js rename to addon/-private/system/store.js diff --git a/addon/-record-data-private/system/store/record-data-wrapper.js b/addon/-private/system/store/record-data-wrapper.js similarity index 100% rename from addon/-record-data-private/system/store/record-data-wrapper.js rename to addon/-private/system/store/record-data-wrapper.js diff --git a/index.js b/index.js index 28139e2aa48..3d04de9be16 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,7 @@ const Funnel = require('broccoli-funnel'); const Rollup = require('broccoli-rollup'); const merge = require('broccoli-merge-trees'); const version = require('./lib/version'); -const { isInstrumentedBuild, useRecordData } = require('./lib/cli-flags'); +const { isInstrumentedBuild } = require('./lib/cli-flags'); const BroccoliDebug = require('broccoli-debug'); const calculateCacheKeyForTree = require('calculate-cache-key-for-tree'); @@ -73,33 +73,13 @@ module.exports = { version(), // compile the VERSION into the build ]); - let corePrivate = new Funnel(tree, { + let withPrivate = new Funnel(tree, { include: ['-private/**'], }); - let withPrivate; - - if (useRecordData()) { - withPrivate = new Funnel(tree, { - srcDir: '-record-data-private', - destDir: '-private', - }); - } else { - withPrivate = new Funnel(tree, { - srcDir: '-legacy-private', - destDir: '-private', - }); - } - - // do not allow overwrite, conflicts should error - // overwrite: false is default, but we are being explicit here - // since this is very important - withPrivate = merge([corePrivate, withPrivate], { overwrite: false }); let withoutPrivate = new Funnel(treeWithVersion, { exclude: [ '-private', - '-record-data-private', - '-legacy-private', isProductionEnv() && !isInstrumentedBuild() ? '-debug' : false, ].filter(Boolean), diff --git a/lib/cli-flags.js b/lib/cli-flags.js index 71324ca4514..aaa8be2e8e0 100644 --- a/lib/cli-flags.js +++ b/lib/cli-flags.js @@ -4,23 +4,6 @@ function isInstrumentedBuild() { return process.argv.includes('--instrument'); } -function useRecordData() { - try { - let currentProjectName = require(`${process.cwd()}/package`); - if ( - currentProjectName === 'ember-data' && - process.argv.includes('--disable-record-data-rfc-build') - ) { - return false; - } - } catch (e) { - // swallow any errors for missing package.json in CWD. - } - - return true; -} - module.exports = { isInstrumentedBuild, - useRecordData, }; diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js index 365fd179067..8f6ea148349 100644 --- a/tests/dummy/config/environment.js +++ b/tests/dummy/config/environment.js @@ -5,7 +5,6 @@ var path = require('path'); var featuresJsonPath = path.join(__dirname, '../../../config/features.json'); var featuresJson = fs.readFileSync(featuresJsonPath, { encoding: 'utf8' }); var featureFlags = JSON.parse(featuresJson); -let { useRecordData } = require('../../../lib/cli-flags'); module.exports = function(environment) { var ENV = { @@ -48,9 +47,5 @@ module.exports = function(environment) { ENV.APP.rootElement = '#ember-testing'; } - ENV.emberData = { - enableRecordDataRFCBuild: useRecordData(), - }; - return ENV; }; diff --git a/tests/helpers/test-in-debug.js b/tests/helpers/test-in-debug.js index 561b1d4cbae..a5bbdce0894 100644 --- a/tests/helpers/test-in-debug.js +++ b/tests/helpers/test-in-debug.js @@ -1,8 +1,5 @@ import { DEBUG } from '@glimmer/env'; import { test, skip } from 'qunit'; -import config from 'dummy/config/environment'; - -const IS_RECORD_DATA = config.emberData.enableRecordDataRFCBuild; export function testInDebug() { if (DEBUG) { @@ -15,17 +12,9 @@ export function testInDebug() { export default testInDebug; export function testRecordData() { - if (IS_RECORD_DATA) { - test(...arguments); - } else { - skip(...arguments); - } + test(...arguments); } export function skipRecordData() { - if (IS_RECORD_DATA) { - skip(...arguments); - } else { - test(...arguments); - } + skip(...arguments); } From b13a6eaf45c61bc2f454e5c76246b3092a3e5657 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 4 Oct 2018 15:58:15 -0700 Subject: [PATCH 2371/2527] cleanup test skipping --- .../relationships/belongs-to-test.js | 3 +- .../acceptance/relationships/has-many-test.js | 3 +- tests/helpers/test-in-debug.js | 12 +- tests/integration/records/unload-test.js | 114 +------------- .../relationships/belongs-to-test.js | 4 +- .../relationships/has-many-test.js | 3 +- .../inverse-relationship-load-test.js | 2 +- .../inverse-relationships-test.js | 142 +----------------- tests/unit/model-test.js | 59 +------- tests/unit/store/async-leak-test.js | 2 +- 10 files changed, 14 insertions(+), 330 deletions(-) diff --git a/tests/acceptance/relationships/belongs-to-test.js b/tests/acceptance/relationships/belongs-to-test.js index 5a705deaabc..07c734ea5b2 100644 --- a/tests/acceptance/relationships/belongs-to-test.js +++ b/tests/acceptance/relationships/belongs-to-test.js @@ -1,4 +1,4 @@ -import { module } from 'qunit'; +import { module, skip as test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import JSONAPIAdapter from 'ember-data/adapters/json-api'; import Model from 'ember-data/model'; @@ -9,7 +9,6 @@ import JSONAPISerializer from 'ember-data/serializers/json-api'; import Store from 'ember-data/store'; import { resolve, reject } from 'rsvp'; import { ServerError } from 'ember-data/adapters/errors'; -import { skipRecordData as test } from '../../helpers/test-in-debug'; import Ember from 'ember'; class Person extends Model { diff --git a/tests/acceptance/relationships/has-many-test.js b/tests/acceptance/relationships/has-many-test.js index 29ad420597a..8246239c0a7 100644 --- a/tests/acceptance/relationships/has-many-test.js +++ b/tests/acceptance/relationships/has-many-test.js @@ -1,4 +1,4 @@ -import { module } from 'qunit'; +import { module, skip as test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import JSONAPIAdapter from 'ember-data/adapters/json-api'; import Model from 'ember-data/model'; @@ -10,7 +10,6 @@ import Store from 'ember-data/store'; import { resolve, reject } from 'rsvp'; import { ServerError } from 'ember-data/adapters/errors'; import Ember from 'ember'; -import { skipRecordData as test } from '../../helpers/test-in-debug'; function domListToArray(domList) { return Array.prototype.slice.call(domList); diff --git a/tests/helpers/test-in-debug.js b/tests/helpers/test-in-debug.js index a5bbdce0894..949b64daac2 100644 --- a/tests/helpers/test-in-debug.js +++ b/tests/helpers/test-in-debug.js @@ -1,20 +1,10 @@ import { DEBUG } from '@glimmer/env'; import { test, skip } from 'qunit'; -export function testInDebug() { +export default function testInDebug() { if (DEBUG) { test(...arguments); } else { skip(...arguments); } } - -export default testInDebug; - -export function testRecordData() { - test(...arguments); -} - -export function skipRecordData() { - skip(...arguments); -} diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 26b750bfd7a..153740d5517 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -6,7 +6,6 @@ import { run } from '@ember/runloop'; import { module, test } from 'qunit'; import DS from 'ember-data'; import setupStore from 'dummy/tests/helpers/store'; -import { testRecordData, skipRecordData } from 'dummy/tests/helpers/test-in-debug'; function idsFromOrderedSet(set) { return set.list.map(i => i.id); @@ -721,7 +720,7 @@ test('(regression) unloadRecord followed by push in the same run-loop', function ); }); -testRecordData('unloading a disconnected subgraph clears the relevant internal models', function( +test('unloading a disconnected subgraph clears the relevant internal models', function( assert ) { env.adapter.shouldBackgroundReloadRecord = () => false; @@ -834,117 +833,6 @@ testRecordData('unloading a disconnected subgraph clears the relevant internal m }); }); -skipRecordData('unloading a disconnected subgraph clears the relevant internal models', function( - assert -) { - env.adapter.shouldBackgroundReloadRecord = () => false; - - run(() => { - env.store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Could be Anybody', - }, - relationships: { - boats: { - data: [{ type: 'boat', id: '1' }, { type: 'boat', id: '2' }], - }, - }, - }, - }); - }); - - run(() => { - env.store.push({ - data: { - type: 'boat', - id: '1', - attributes: { - name: 'Boaty McBoatface', - }, - relationships: { - person: { - data: { type: 'person', id: '1' }, - }, - }, - }, - }); - }); - - run(() => { - env.store.push({ - data: { - type: 'boat', - id: '2', - attributes: { - name: 'The jackson', - }, - relationships: { - person: { - data: { type: 'person', id: '1' }, - }, - }, - }, - }); - }); - - assert.equal( - env.store._internalModelsFor('person').models.length, - 1, - 'one person record is loaded' - ); - assert.equal( - env.store._internalModelsFor('boat').models.length, - 2, - 'two boat records are loaded' - ); - assert.equal(env.store.hasRecordForId('person', 1), true); - assert.equal(env.store.hasRecordForId('boat', 1), true); - assert.equal(env.store.hasRecordForId('boat', 2), true); - - let checkOrphanCalls = 0; - let cleanupOrphanCalls = 0; - - function countOrphanCalls(record) { - let internalModel = record._internalModel; - let origCheck = internalModel._checkForOrphanedInternalModels; - let origCleanup = internalModel._cleanupOrphanedInternalModels; - - internalModel._checkForOrphanedInternalModels = function() { - ++checkOrphanCalls; - return origCheck.apply(record._internalModel, arguments); - }; - - internalModel._cleanupOrphanedInternalModels = function() { - ++cleanupOrphanCalls; - return origCleanup.apply(internalModel, arguments); - }; - } - countOrphanCalls(env.store.peekRecord('person', 1)); - countOrphanCalls(env.store.peekRecord('boat', 1)); - countOrphanCalls(env.store.peekRecord('boat', 2)); - - // make sure relationships are initialized - return env.store - .peekRecord('person', 1) - .get('boats') - .then(() => { - run(() => { - env.store.peekRecord('person', 1).unloadRecord(); - env.store.peekRecord('boat', 1).unloadRecord(); - env.store.peekRecord('boat', 2).unloadRecord(); - }); - - assert.equal(env.store._internalModelsFor('person').models.length, 0); - assert.equal(env.store._internalModelsFor('boat').models.length, 0); - - assert.equal(checkOrphanCalls, 3, 'each internalModel checks for cleanup'); - assert.equal(cleanupOrphanCalls, 1, 'each model data tries to cleanup'); - }); -}); - test('Unloading a record twice only schedules destroy once', function(assert) { const store = env.store; let record; diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 82caea6d374..939e9b47acb 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -9,7 +9,7 @@ import { setupTest } from 'ember-qunit'; import Store from 'ember-data/store'; import Model from 'ember-data/model'; import { attr, belongsTo } from '@ember-decorators/data'; -import testInDebug, { testRecordData } from 'dummy/tests/helpers/test-in-debug'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { setup as setupModelFactoryInjections, reset as resetModelFactoryInjection, @@ -1910,7 +1910,7 @@ test("belongsTo relationship with links doesn't trigger extra change notificatio assert.equal(count, 0); }); -testRecordData( +test( "belongsTo relationship doesn't trigger when model data doesn't support implicit relationship", function(assert) { class TestRecordData extends RecordData { diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 86f00bffc7f..f2a2f73dd0f 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -12,7 +12,6 @@ import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test, skip } from 'qunit'; import DS from 'ember-data'; -import { skipRecordData } from '../../helpers/test-in-debug'; let env, store, User, Contact, Email, Phone, Message, Post, Comment; let Book, Chapter, Page; @@ -960,7 +959,7 @@ test('A hasMany relationship can be reloaded if it was fetched via ids', functio }); }); -skipRecordData( +skip( 'A hasMany relationship can be reloaded even if it failed at the first time', async function(assert) { assert.expect(6); diff --git a/tests/integration/relationships/inverse-relationship-load-test.js b/tests/integration/relationships/inverse-relationship-load-test.js index a4628d13cd6..45791d91175 100644 --- a/tests/integration/relationships/inverse-relationship-load-test.js +++ b/tests/integration/relationships/inverse-relationship-load-test.js @@ -6,7 +6,7 @@ import Store from 'ember-data/store'; import Model from 'ember-data/model'; import { resolve } from 'rsvp'; import { attr, belongsTo, hasMany } from '@ember-decorators/data'; -import { testInDebug } from '../../helpers/test-in-debug'; +import testInDebug from '../../helpers/test-in-debug'; module('inverse relationship load test', function(hooks) { let store; diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index f7d5e944bd6..1ffa0c46681 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -1,8 +1,7 @@ import { run } from '@ember/runloop'; import { createStore } from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; - -import { testInDebug, testRecordData, skipRecordData } from 'dummy/tests/helpers/test-in-debug'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; import DS from 'ember-data'; @@ -486,144 +485,7 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a bel }, /We found no inverse relationships by the name of 'testPost' on the 'user' model/); }); -skipRecordData('inverseFor short-circuits when inverse is null', function(assert) { - assert.expect(4); - Post = DS.Model.extend({ - comments: DS.hasMany('comment', { async: false, inverse: null }), - }); - - Comment = DS.Model.extend({ - post: DS.belongsTo('post', { async: false, inverse: null }), - }); - - User = DS.Model.extend({ - messages: DS.hasMany('message', { async: false, inverse: 'user' }), - }); - - Message = DS.Model.extend({ - user: DS.belongsTo('user', { async: false, inverse: 'messages' }), - }); - - var env = setupStore({ post: Post, comment: Comment, user: User, message: Message }); - var store = env.store; - - Post._findInverseFor = function() { - assert.notOk(true, 'Post model _findInverseFor is not called'); - }; - - Comment._findInverseFor = function() { - assert.notOk(true, 'Comment model _findInverseFor is not called'); - }; - - Message._findInverseFor = function() { - assert.ok(true, 'Message model _findInverseFor is called'); - }; - - User._findInverseFor = function() { - assert.ok(true, 'User model _findInverseFor is called'); - }; - - run(function() { - store.push({ - data: { - id: '1', - type: 'post', - relationships: { - comments: { - data: [ - { - id: '1', - type: 'comment', - }, - { - id: '2', - type: 'comment', - }, - ], - }, - }, - }, - }); - store.push({ - data: [ - { - id: '1', - type: 'comment', - relationships: { - post: { - data: { - id: '1', - type: 'post', - }, - }, - }, - }, - { - id: '2', - type: 'comment', - relationships: { - post: { - data: { - id: '1', - type: 'post', - }, - }, - }, - }, - ], - }); - store.push({ - data: { - id: '1', - type: 'user', - relationships: { - messages: { - data: [ - { - id: '1', - type: 'message', - }, - { - id: '2', - type: 'message', - }, - ], - }, - }, - }, - }); - store.push({ - data: [ - { - id: '1', - type: 'message', - relationships: { - user: { - data: { - id: '1', - type: 'user', - }, - }, - }, - }, - { - id: '2', - type: 'message', - relationships: { - post: { - data: { - id: '1', - type: 'user', - }, - }, - }, - }, - ], - }); - }); -}); - -testRecordData('inverseFor is only called when inverse is not null', function(assert) { +test('inverseFor is only called when inverse is not null', function(assert) { assert.expect(2); Post = DS.Model.extend({ comments: DS.hasMany('comment', { async: false, inverse: null }), diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index a1c7d38b7a1..f73a1512204 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -5,7 +5,7 @@ import { run } from '@ember/runloop'; import { createStore } from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; import Ember from 'ember'; -import { testInDebug, testRecordData, skipRecordData } from 'dummy/tests/helpers/test-in-debug'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; import DS from 'ember-data'; import { getOwner } from 'ember-data/-private'; @@ -1528,7 +1528,7 @@ test('setting the id after model creation should correctly update the id', funct }); }); -testRecordData( +test( 'updating the id with store.setRecordId should correctly when the id property is watched', function(assert) { assert.expect(2); @@ -1555,33 +1555,7 @@ testRecordData( } ); -skipRecordData( - 'updating the id with store.updateId should correctly when the id property is watched', - function(assert) { - assert.expect(2); - - const Person = DS.Model.extend({ - name: DS.attr('string'), - idComputed: computed('id', function() {}), - }); - - let { store } = setupStore({ - person: Person, - }); - - run(() => { - let person = store.createRecord('person'); - person.get('idComputed'); - - assert.equal(person.get('id'), null, 'initial created model id should be null'); - - store.updateId(person._internalModel, { id: 'john' }); - assert.equal(person.id, 'john', 'new id should be correctly set.'); - }); - } -); - -testRecordData( +test( 'accessing the model id without the get function should work when id is watched', function(assert) { assert.expect(2); @@ -1608,33 +1582,6 @@ testRecordData( } ); -skipRecordData( - 'accessing the model id without the get function should work when id is watched', - function(assert) { - assert.expect(2); - - const Person = DS.Model.extend({ - name: DS.attr('string'), - idComputed: computed('id', function() {}), - }); - - let { store } = setupStore({ - person: Person, - }); - - run(() => { - let person = store.createRecord('person'); - person.get('idComputed'); - - assert.equal(person.get('id'), null, 'initial created model id should be null'); - - store.updateId(person._internalModel, { id: 'john' }); - - assert.equal(person.id, 'john', 'new id should be correctly set.'); - }); - } -); - test('ID mutation (complicated)', function(assert) { assert.expect(5); let idChange = 0; diff --git a/tests/unit/store/async-leak-test.js b/tests/unit/store/async-leak-test.js index 3c3da72c9c7..814beec3c80 100644 --- a/tests/unit/store/async-leak-test.js +++ b/tests/unit/store/async-leak-test.js @@ -8,7 +8,7 @@ import { Promise } from 'rsvp'; import { attr } from '@ember-decorators/data'; import { run } from '@ember/runloop'; import Ember from 'ember'; -import { testInDebug as test } from '../../helpers/test-in-debug'; +import test from '../../helpers/test-in-debug'; class Person extends Model { @attr From 4f6c9ed2ac720d14b24e04c59e21783b8a9f51a0 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 4 Oct 2018 16:42:55 -0700 Subject: [PATCH 2372/2527] prettier --- index.js | 7 +- tests/integration/records/unload-test.js | 4 +- .../relationships/belongs-to-test.js | 307 +++++++++--------- .../relationships/has-many-test.js | 111 +++---- tests/unit/model-test.js | 74 ++--- 5 files changed, 244 insertions(+), 259 deletions(-) diff --git a/index.js b/index.js index 3d04de9be16..37e23ebcdaa 100644 --- a/index.js +++ b/index.js @@ -78,10 +78,9 @@ module.exports = { }); let withoutPrivate = new Funnel(treeWithVersion, { - exclude: [ - '-private', - isProductionEnv() && !isInstrumentedBuild() ? '-debug' : false, - ].filter(Boolean), + exclude: ['-private', isProductionEnv() && !isInstrumentedBuild() ? '-debug' : false].filter( + Boolean + ), destDir: 'ember-data', }); diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 153740d5517..5cae3b46152 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -720,9 +720,7 @@ test('(regression) unloadRecord followed by push in the same run-loop', function ); }); -test('unloading a disconnected subgraph clears the relevant internal models', function( - assert -) { +test('unloading a disconnected subgraph clears the relevant internal models', function(assert) { env.adapter.shouldBackgroundReloadRecord = () => false; run(() => { diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 939e9b47acb..ef959776d65 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -1910,174 +1910,171 @@ test("belongsTo relationship with links doesn't trigger extra change notificatio assert.equal(count, 0); }); -test( - "belongsTo relationship doesn't trigger when model data doesn't support implicit relationship", - function(assert) { - class TestRecordData extends RecordData { - constructor(modelName, id, clientId, storeWrapper, store) { - super(modelName, id, clientId, storeWrapper, store); - delete this.__implicitRelationships; - delete this.__relationships; - } - - _destroyRelationships() {} - - _allRelatedRecordDatas() {} - - _cleanupOrphanedRecordDatas() {} - - _directlyRelatedRecordDatas() { - return []; - } - - destroy() { - this.isDestroyed = true; - this.storeWrapper.disconnectRecord(this.modelName, this.id, this.clientId); - } - - get _implicitRelationships() { - return undefined; - } - get _relationships() { - return undefined; - } +test("belongsTo relationship doesn't trigger when model data doesn't support implicit relationship", function(assert) { + class TestRecordData extends RecordData { + constructor(modelName, id, clientId, storeWrapper, store) { + super(modelName, id, clientId, storeWrapper, store); + delete this.__implicitRelationships; + delete this.__relationships; } - Chapter.reopen({ - // book is still an inverse from prior to the reopen - sections: DS.hasMany('section', { async: false }), - book1: DS.belongsTo('book1', { async: false, inverse: 'chapters' }), // incorrect inverse - book2: DS.belongsTo('book1', { async: false, inverse: null }), // correct inverse - }); + _destroyRelationships() {} - const createRecordDataFor = env.store.createRecordDataFor; - env.store.createRecordDataFor = function(modelName, id, clientId, storeWrapper) { - if (modelName === 'book1' || modelName === 'section') { - return new TestRecordData(modelName, id, clientId, storeWrapper, this); - } - return createRecordDataFor.call(this, modelName, id, clientId, storeWrapper); - }; + _allRelatedRecordDatas() {} - const data = { - data: { - type: 'chapter', - id: '1', - relationships: { - book1: { - data: { type: 'book1', id: '1' }, - }, - book2: { - data: { type: 'book1', id: '2' }, - }, - book: { - data: { type: 'book', id: '1' }, - }, - sections: { - data: [ - { - type: 'section', - id: 1, - }, - { - type: 'section', - id: 2, - }, - ], - }, - }, - }, - included: [ - { type: 'book1', id: '1' }, - { type: 'book1', id: '2' }, - { type: 'section', id: '1' }, - { type: 'book', id: '1' }, - { type: 'section', id: '2' }, - ], - }; + _cleanupOrphanedRecordDatas() {} - // Expect assertion failure as Book1 RecordData - // doesn't have relationship attribute - // and inverse is not set to null in - // DSbelongsTo - assert.expectAssertion(() => { - run(() => { - env.store.push(data); - }); - }, `Assertion Failed: We found no inverse relationships by the name of 'chapters' on the 'book1' model. This is most likely due to a missing attribute on your model definition.`); + _directlyRelatedRecordDatas() { + return []; + } - //Update setup - // with inverse set to null - // no errors thrown - Chapter.reopen({ - book1: DS.belongsTo({ async: false }), - sections: DS.hasMany('section', { async: false }), - book: DS.belongsTo({ async: false, inverse: null }), - }); + destroy() { + this.isDestroyed = true; + this.storeWrapper.disconnectRecord(this.modelName, this.id, this.clientId); + } + get _implicitRelationships() { + return undefined; + } + get _relationships() { + return undefined; + } + } + + Chapter.reopen({ + // book is still an inverse from prior to the reopen + sections: DS.hasMany('section', { async: false }), + book1: DS.belongsTo('book1', { async: false, inverse: 'chapters' }), // incorrect inverse + book2: DS.belongsTo('book1', { async: false, inverse: null }), // correct inverse + }); + + const createRecordDataFor = env.store.createRecordDataFor; + env.store.createRecordDataFor = function(modelName, id, clientId, storeWrapper) { + if (modelName === 'book1' || modelName === 'section') { + return new TestRecordData(modelName, id, clientId, storeWrapper, this); + } + return createRecordDataFor.call(this, modelName, id, clientId, storeWrapper); + }; + + const data = { + data: { + type: 'chapter', + id: '1', + relationships: { + book1: { + data: { type: 'book1', id: '1' }, + }, + book2: { + data: { type: 'book1', id: '2' }, + }, + book: { + data: { type: 'book', id: '1' }, + }, + sections: { + data: [ + { + type: 'section', + id: 1, + }, + { + type: 'section', + id: 2, + }, + ], + }, + }, + }, + included: [ + { type: 'book1', id: '1' }, + { type: 'book1', id: '2' }, + { type: 'section', id: '1' }, + { type: 'book', id: '1' }, + { type: 'section', id: '2' }, + ], + }; + + // Expect assertion failure as Book1 RecordData + // doesn't have relationship attribute + // and inverse is not set to null in + // DSbelongsTo + assert.expectAssertion(() => { run(() => { env.store.push(data); }); + }, `Assertion Failed: We found no inverse relationships by the name of 'chapters' on the 'book1' model. This is most likely due to a missing attribute on your model definition.`); - let chapter = env.store.peekRecord('chapter', '1'); - let book1 = env.store.peekRecord('book1', '1'); - let book2 = env.store.peekRecord('book1', '2'); - let book = env.store.peekRecord('book', '1'); - let section1 = env.store.peekRecord('section', '1'); - let section2 = env.store.peekRecord('section', '2'); - - let sections = chapter.get('sections'); - - assert.equal(chapter.get('book1.id'), '1'); - assert.equal(chapter.get('book2.id'), '2'); - assert.equal(chapter.get('book.id'), '1'); - - // No inverse setup created for book1 - // as Model-Data of book1 doesn't support this - // functionality. - assert.notOk(book1.get('chapter')); - assert.notOk(book2.get('chapter')); - assert.notOk(book.get('chapter')); - assert.notOk( - book1._internalModel._recordData._implicitRelationships, - 'no support for implicit relationship in custom RecordData' - ); - assert.notOk( - book2._internalModel._recordData._implicitRelationships, - 'no support for implicit relationship in custom RecordData' - ); - assert.ok( - book._internalModel._recordData._implicitRelationships, - 'support for implicit relationship in default RecordData' - ); + //Update setup + // with inverse set to null + // no errors thrown + Chapter.reopen({ + book1: DS.belongsTo({ async: false }), + sections: DS.hasMany('section', { async: false }), + book: DS.belongsTo({ async: false, inverse: null }), + }); + + run(() => { + env.store.push(data); + }); - // No inverse setup is created for section - assert.notOk(section1.get('chapter')); - assert.notOk(section2.get('chapter')); + let chapter = env.store.peekRecord('chapter', '1'); + let book1 = env.store.peekRecord('book1', '1'); + let book2 = env.store.peekRecord('book1', '2'); + let book = env.store.peekRecord('book', '1'); + let section1 = env.store.peekRecord('section', '1'); + let section2 = env.store.peekRecord('section', '2'); + + let sections = chapter.get('sections'); + + assert.equal(chapter.get('book1.id'), '1'); + assert.equal(chapter.get('book2.id'), '2'); + assert.equal(chapter.get('book.id'), '1'); + + // No inverse setup created for book1 + // as Model-Data of book1 doesn't support this + // functionality. + assert.notOk(book1.get('chapter')); + assert.notOk(book2.get('chapter')); + assert.notOk(book.get('chapter')); + assert.notOk( + book1._internalModel._recordData._implicitRelationships, + 'no support for implicit relationship in custom RecordData' + ); + assert.notOk( + book2._internalModel._recordData._implicitRelationships, + 'no support for implicit relationship in custom RecordData' + ); + assert.ok( + book._internalModel._recordData._implicitRelationships, + 'support for implicit relationship in default RecordData' + ); - // Removing the sections - // shouldnot throw error - // as Model-data of section - // doesn't support implicit Relationship - run(() => { - chapter.get('sections').removeObject(section1); - assert.notOk(section1._internalModel._recordData._implicitRelationships); + // No inverse setup is created for section + assert.notOk(section1.get('chapter')); + assert.notOk(section2.get('chapter')); - chapter.get('sections').removeObject(section2); - assert.notOk(section2._internalModel._recordData._implicitRelationships); - }); + // Removing the sections + // shouldnot throw error + // as Model-data of section + // doesn't support implicit Relationship + run(() => { + chapter.get('sections').removeObject(section1); + assert.notOk(section1._internalModel._recordData._implicitRelationships); - assert.equal(chapter.get('sections.length'), 0); + chapter.get('sections').removeObject(section2); + assert.notOk(section2._internalModel._recordData._implicitRelationships); + }); - // Update the current state of chapter by - // adding new sections - // shouldnot throw error during - // setup of implicit inverse - run(() => { - sections.addObject(env.store.createRecord('section', { id: 3 })); - sections.addObject(env.store.createRecord('section', { id: 4 })); - sections.addObject(env.store.createRecord('section', { id: 5 })); - }); - assert.equal(chapter.get('sections.length'), 3); - assert.notOk(sections.get('firstObject')._internalModel._recordData._implicitRelationships); - } -); + assert.equal(chapter.get('sections.length'), 0); + + // Update the current state of chapter by + // adding new sections + // shouldnot throw error during + // setup of implicit inverse + run(() => { + sections.addObject(env.store.createRecord('section', { id: 3 })); + sections.addObject(env.store.createRecord('section', { id: 4 })); + sections.addObject(env.store.createRecord('section', { id: 5 })); + }); + assert.equal(chapter.get('sections.length'), 3); + assert.notOk(sections.get('firstObject')._internalModel._recordData._implicitRelationships); +}); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index f2a2f73dd0f..cde132ce40a 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -959,75 +959,72 @@ test('A hasMany relationship can be reloaded if it was fetched via ids', functio }); }); -skip( - 'A hasMany relationship can be reloaded even if it failed at the first time', - async function(assert) { - assert.expect(6); +skip('A hasMany relationship can be reloaded even if it failed at the first time', async function(assert) { + assert.expect(6); - const { store, adapter } = env; + const { store, adapter } = env; - Post.reopen({ - comments: DS.hasMany('comment', { async: true }), - }); + Post.reopen({ + comments: DS.hasMany('comment', { async: true }), + }); - adapter.findRecord = function(store, type, id) { - return resolve({ - data: { - id: 1, - type: 'post', - relationships: { - comments: { - links: { related: '/posts/1/comments' }, - }, + adapter.findRecord = function(store, type, id) { + return resolve({ + data: { + id: 1, + type: 'post', + relationships: { + comments: { + links: { related: '/posts/1/comments' }, }, }, - }); - }; + }, + }); + }; - let loadingCount = -1; - adapter.findHasMany = function(store, record, link, relationship) { - loadingCount++; - if (loadingCount % 2 === 0) { - return reject({ data: null }); - } else { - return resolve({ - data: [ - { id: 1, type: 'comment', attributes: { body: 'FirstUpdated' } }, - { id: 2, type: 'comment', attributes: { body: 'Second' } }, - ], - }); - } - }; + let loadingCount = -1; + adapter.findHasMany = function(store, record, link, relationship) { + loadingCount++; + if (loadingCount % 2 === 0) { + return reject({ data: null }); + } else { + return resolve({ + data: [ + { id: 1, type: 'comment', attributes: { body: 'FirstUpdated' } }, + { id: 2, type: 'comment', attributes: { body: 'Second' } }, + ], + }); + } + }; - let post = await store.findRecord('post', 1); - let comments = post.get('comments'); - let manyArray = await comments.catch(() => { - assert.ok(true, 'An error was thrown on the first reload of comments'); - return comments.reload(); - }); + let post = await store.findRecord('post', 1); + let comments = post.get('comments'); + let manyArray = await comments.catch(() => { + assert.ok(true, 'An error was thrown on the first reload of comments'); + return comments.reload(); + }); - assert.equal(manyArray.get('isLoaded'), true, 'the reload worked, comments are now loaded'); + assert.equal(manyArray.get('isLoaded'), true, 'the reload worked, comments are now loaded'); - await manyArray.reload().catch(() => { - assert.ok(true, 'An error was thrown on the second reload via manyArray'); - }); + await manyArray.reload().catch(() => { + assert.ok(true, 'An error was thrown on the second reload via manyArray'); + }); - assert.equal( - manyArray.get('isLoaded'), - true, - 'the second reload failed, comments are still loaded though' - ); + assert.equal( + manyArray.get('isLoaded'), + true, + 'the second reload failed, comments are still loaded though' + ); - let reloadedManyArray = await manyArray.reload(); + let reloadedManyArray = await manyArray.reload(); - assert.equal( - reloadedManyArray.get('isLoaded'), - true, - 'the third reload worked, comments are loaded again' - ); - assert.ok(reloadedManyArray === manyArray, 'the many array stays the same'); - } -); + assert.equal( + reloadedManyArray.get('isLoaded'), + true, + 'the third reload worked, comments are loaded again' + ); + assert.ok(reloadedManyArray === manyArray, 'the many array stays the same'); +}); test('A hasMany relationship can be directly reloaded if it was fetched via links', function(assert) { assert.expect(6); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index f73a1512204..730c478cdf1 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -1528,59 +1528,53 @@ test('setting the id after model creation should correctly update the id', funct }); }); -test( - 'updating the id with store.setRecordId should correctly when the id property is watched', - function(assert) { - assert.expect(2); +test('updating the id with store.setRecordId should correctly when the id property is watched', function(assert) { + assert.expect(2); - const Person = DS.Model.extend({ - name: DS.attr('string'), - idComputed: computed('id', function() {}), - }); + const Person = DS.Model.extend({ + name: DS.attr('string'), + idComputed: computed('id', function() {}), + }); - let { store } = setupStore({ - person: Person, - }); + let { store } = setupStore({ + person: Person, + }); - run(() => { - let person = store.createRecord('person'); - person.get('idComputed'); + run(() => { + let person = store.createRecord('person'); + person.get('idComputed'); - assert.equal(person.get('id'), null, 'initial created model id should be null'); + assert.equal(person.get('id'), null, 'initial created model id should be null'); - store.setRecordId('person', 'john', person._internalModel.clientId); + store.setRecordId('person', 'john', person._internalModel.clientId); - assert.equal(person.id, 'john', 'new id should be correctly set.'); - }); - } -); + assert.equal(person.id, 'john', 'new id should be correctly set.'); + }); +}); -test( - 'accessing the model id without the get function should work when id is watched', - function(assert) { - assert.expect(2); +test('accessing the model id without the get function should work when id is watched', function(assert) { + assert.expect(2); - const Person = DS.Model.extend({ - name: DS.attr('string'), - idComputed: computed('id', function() {}), - }); + const Person = DS.Model.extend({ + name: DS.attr('string'), + idComputed: computed('id', function() {}), + }); - let { store } = setupStore({ - person: Person, - }); + let { store } = setupStore({ + person: Person, + }); - run(() => { - let person = store.createRecord('person'); - person.get('idComputed'); + run(() => { + let person = store.createRecord('person'); + person.get('idComputed'); - assert.equal(person.get('id'), null, 'initial created model id should be null'); + assert.equal(person.get('id'), null, 'initial created model id should be null'); - store.setRecordId('person', 'john', person._internalModel.clientId); + store.setRecordId('person', 'john', person._internalModel.clientId); - assert.equal(person.id, 'john', 'new id should be correctly set.'); - }); - } -); + assert.equal(person.id, 'john', 'new id should be correctly set.'); + }); +}); test('ID mutation (complicated)', function(assert) { assert.expect(5); From ee654cb6fd08497058d4fd6af8089d063294f82a Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Tue, 9 Oct 2018 23:27:37 -0700 Subject: [PATCH 2373/2527] Allow skipping of smoke tests in long running partner tests The Ilios-frontend tests run very long and often fail to finish before the Travis 50 minutes timeout. Skipping the smoke tests at least ensures that passing builds pass. Failing builds will need to be investigated separately to ensure that smoke tests are not failing as well. --- lib/scripts/test-external.js | 15 +++++++++++---- package.json | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/scripts/test-external.js b/lib/scripts/test-external.js index b64ebaf425c..61c67e0fd68 100644 --- a/lib/scripts/test-external.js +++ b/lib/scripts/test-external.js @@ -10,6 +10,7 @@ const rimraf = require('rimraf'); const projectRoot = path.resolve(__dirname, '../../'); const externalProjectName = process.argv[2]; const gitUrl = process.argv[3]; +const skipSmokeTest = process.argv[4] && process.argv[4] === '--skip-smoke-test'; const tempDir = path.join(projectRoot, '../__external-test-cache'); const projectTempDir = path.join(tempDir, externalProjectName); @@ -79,8 +80,12 @@ let smokeTestPassed = true; let commitTestPassed = true; try { - debug('Running Smoke Test'); - execExternal(`ember test`, true); + if (skipSmokeTest) { + debug('Skipping Smoke Test'); + } else { + debug('Running Smoke Test'); + execExternal(`ember test`, true); + } } catch (e) { smokeTestPassed = false; } @@ -95,13 +100,15 @@ try { } try { - debug('Re-running tests against EmberData commit'); + debug('Running tests against EmberData commit'); execExternal(`ember test`, true); } catch (e) { commitTestPassed = false; } -if (!smokeTestPassed && !commitTestPassed) { +if (skipSmokeTest && !commitTestPassed) { + throw new Error('Commit may result in a regression, but the smoke test was skipped.'); +} else if (!smokeTestPassed && !commitTestPassed) { throw new Error( `Commit may result in a regression, but the smoke test for ${externalProjectName} also failed.` ); diff --git a/package.json b/package.json index 6fca166adbc..fa5949db28d 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "test-external:travis-web": "node ./lib/scripts/test-external travis-web https://github.com/travis-ci/travis-web.git", "test-external:storefront": "node ./lib/scripts/test-external storefront https://github.com/embermap/ember-data-storefront.git", "test-external:factory-guy": "node ./lib/scripts/test-external factory-guy https://github.com/danielspaniel/ember-data-factory-guy.git", - "test-external:ilios-frontend": "node ./lib/scripts/test-external ilios-frontend https://github.com/ilios/frontend.git", + "test-external:ilios-frontend": "node ./lib/scripts/test-external ilios-frontend https://github.com/ilios/frontend.git --skip-smoke-test", "test-external:ember-resource-metadata": "node ./lib/scripts/test-external ember-resource-metadata https://github.com/ef4/ember-resource-metadata.git", "test-external:ember-data-relationship-tracker": "node ./lib/scripts/test-external ember-data-relationship-tracker https://github.com/ef4/ember-data-relationship-tracker.git" }, From 7dccaf8c53d39b6b81edd2e32d9a3467529a7fa1 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 12 Oct 2018 09:03:20 -0700 Subject: [PATCH 2374/2527] update travis config for lts --- .travis.yml | 22 +++++++++++----------- config/ember-try.js | 8 ++++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 31716b7e991..942538b69c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,8 +17,8 @@ branches: - master - beta - release - # release branches - - /^release-.*/ + # release and LTS branches + - /^(release|lts)-.*/ # npm version tags - /^v\d+\.\d+\.\d+/ @@ -27,7 +27,7 @@ stages: - additional tests - ember version tests - name: external partner tests - if: NOT (branch ~= /^release.*/) + if: NOT (branch ~= /^(release|lts).*/) - name: deploy if: type = push AND (branch IN (master, beta, release) OR tag IS present) @@ -38,7 +38,7 @@ jobs: # runs tests with current locked deps and linting - stage: test name: "Linting" - if: NOT (branch ~= /^release.*/) + if: NOT (branch ~= /^(release|lts).*/) script: - ./bin/lint-features - yarn lint:js @@ -47,7 +47,7 @@ jobs: - stage: additional tests name: "Optional Features" - if: NOT (branch ~= /^release.*/) + if: NOT (branch ~= /^(release|lts).*/) install: yarn install script: yarn test:optional-features @@ -70,18 +70,18 @@ jobs: # runs tests against each supported Ember version - stage: ember version tests - name: "Ember LTS 2.16" - env: EMBER_TRY_SCENARIO=ember-lts-2.16 - - name: "Ember LTS 2.18" + name: "Ember LTS 2.18" env: EMBER_TRY_SCENARIO=ember-lts-2.18 + - name: "Ember LTS 3.4" + env: EMBER_TRY_SCENARIO=ember-lts-3.4 - name: "Ember Release" - if: NOT (branch ~= /^release.*/) + if: NOT (branch ~= /^(release|lts).*/) env: EMBER_TRY_SCENARIO=ember-release - name: "Ember Beta" - if: NOT (branch ~= /^release.*/) + if: NOT (branch ~= /^(release|lts).*/) env: EMBER_TRY_SCENARIO=ember-beta - name: "Ember Canary" - if: NOT (branch ~= /^release.*/) + if: NOT (branch ~= /^(release|lts).*/) env: EMBER_TRY_SCENARIO=ember-canary # runs tests against various open-source projects for early-warning regression analysis diff --git a/config/ember-try.js b/config/ember-try.js index c60101b0aae..63aec9222f2 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -17,18 +17,18 @@ module.exports = function() { npm: {}, }, { - name: 'ember-lts-2.16', + name: 'ember-lts-2.18', npm: { devDependencies: { - 'ember-source': '~2.16.0', + 'ember-source': '~2.18.0', }, }, }, { - name: 'ember-lts-2.18', + name: 'ember-lts-3.4', npm: { devDependencies: { - 'ember-source': '~2.18.0', + 'ember-source': '~3.4.0', }, }, }, From 8c083fafbd70149a53218fe165d7044bf0560506 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 12 Oct 2018 09:33:13 -0700 Subject: [PATCH 2375/2527] Release Ember Data 3.5.0 --- CHANGELOG.md | 19 +++++++++++++++++++ package.json | 4 ++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db8308d1659..3881cba04f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,25 @@ ### Master +### Release 3.5.0 (October 12, 2018) + +- [#5491](https://github.com/emberjs/data/pull/5491) [Feature] Add MU support for model and model-test blueprints +- [#5616](https://github.com/emberjs/data/pull/5616) [FEAT RecordData] turn on the build-flag by default +- [#5608](https://github.com/emberjs/data/pull/5608) [BUGFIX] Add inverse relationship on payload when missing (#5608) +- [#5489](https://github.com/emberjs/data/pull/5489) [BUGFIX] Lowercase header names in parseResponseHeaders +- [#5494](https://github.com/emberjs/data/pull/5494) [Feature] Add MU support for serializer and serializer-test blueprints +- [#5495](https://github.com/emberjs/data/pull/5495) [Feature] Add MU transform{,-test} blueprints +- [#5657](https://github.com/emberjs/data/pull/5657) [BUGFIX blueprints] remove second string argument from transform tests +- [#5652](https://github.com/emberjs/data/pull/5652) [Docs] Update buildUrl syntax in docs +- [#5639](https://github.com/emberjs/data/pull/5639) Include request/response info with Abort error +- [#5646](https://github.com/emberjs/data/pull/5646) [CHORE] update contribution guidelines +- [#5623](https://github.com/emberjs/data/pull/5623) Added conditional check to extract polymorphic relationship for hasMany (#5623) +- [#5650](https://github.com/emberjs/data/pull/5650) [FEAT transforms] makes the assertion for missing transforms clearer +- [#5640](https://github.com/emberjs/data/pull/5640) [BUGFIX] fix deprecation for store entry methods +- [#5654](https://github.com/emberjs/data/pull/5654) add mocha rfc232 blueprints +- [#5665](https://github.com/emberjs/data/pull/5665) add remaining mocha rfc 232 blueprints (#5665) +- [#5667](https://github.com/emberjs/data/pull/5667) Added check to extract polymorphic relationship for hasMany (#5623) + ### Release 3.4.1 (September 14, 2018) - [#5621](https://github.com/emberjs/data/pull/5621) Add partner test for the ilios frontend - [#5589](https://github.com/emberjs/data/pull/5589) fix broken link because the new API website does not support the anchor diff --git a/package.json b/package.json index fa5949db28d..892ebb4bbd6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "3.6.0-canary", + "version": "3.5.0", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { @@ -95,7 +95,7 @@ "ember-qunit": "^3.4.1", "ember-qunit-assert-helpers": "^0.2.1", "ember-resolver": "^5.0.1", - "ember-source": "~3.4.0", + "ember-source": "~3.5.0", "ember-source-channel-url": "^1.1.0", "ember-try": "^1.0.0-beta.3", "eslint": "^5.3.0", From effd7a8e9ae2dc95c51dbed68d23cf701a234f22 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 12 Oct 2018 09:34:55 -0700 Subject: [PATCH 2376/2527] mysterious yarn update --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 483647344e5..8c78d277cdd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2759,9 +2759,9 @@ ember-source-channel-url@^1.0.1, ember-source-channel-url@^1.1.0: dependencies: got "^8.0.1" -ember-source@~3.4.0: - version "3.4.0" - resolved "https://registry.npmjs.org/ember-source/-/ember-source-3.4.0.tgz#12de2461de6ce5e02de824ac45c81cb17bf5523b" +ember-source@~3.5.0: + version "3.5.0" + resolved "https://registry.npmjs.org/ember-source/-/ember-source-3.5.0.tgz#2322e393125684e1e043d0eedad8fd79c6de78a8" dependencies: broccoli-funnel "^2.0.1" broccoli-merge-trees "^2.0.0" From 90af687185fde0c423bd36217cdcc18a93c6dbb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Duque?= Date: Sun, 14 Oct 2018 20:23:02 +0100 Subject: [PATCH 2377/2527] Link to Discord instead of Slack --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 2beb5c2b892..215ac40859f 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -52,4 +52,4 @@ Tag the release Announce release! 1. on Twitter -* then crosslink Twitter post on slack #dev-ember-data and #ember-data +* then crosslink Twitter post on Discord [#dev-ember-data](https://discordapp.com/channels/480462759797063690/480501977931972608) and [#ember-data](https://discordapp.com/channels/480462759797063690/486549196837486592) From 0fb3d28ac023d9f25fde901a9040725dc49d6d22 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 17 Oct 2018 16:18:38 -0700 Subject: [PATCH 2378/2527] [CHORE reference] update reference to be ES2015 --- addon/-private/system/references/reference.js | 98 +++++++++---------- 1 file changed, 48 insertions(+), 50 deletions(-) diff --git a/addon/-private/system/references/reference.js b/addon/-private/system/references/reference.js index db90d552136..6bb9d75eb7a 100644 --- a/addon/-private/system/references/reference.js +++ b/addon/-private/system/references/reference.js @@ -1,14 +1,13 @@ -var Reference = function(store, internalModel) { - this.store = store; - this.internalModel = internalModel; - this.recordData = internalModel._recordData; -}; +export default class Reference { + constructor(store, internalModel) { + this.store = store; + this.internalModel = internalModel; + this.recordData = internalModel._recordData; + } -Reference.prototype = { - constructor: Reference, -}; + _resource() {} -/** + /** This returns a string that represents how the reference will be looked up when it is loaded. If the relationship has a link it will use the "link" otherwise it defaults to "id". @@ -46,29 +45,29 @@ Reference.prototype = { @method remoteType @return {String} The name of the remote type. This should either be "link" or "ids" -*/ -Reference.prototype.remoteType = function() { - let value = this._resource(); - if (value && value.links && value.links.related) { - return 'link'; - } + */ + remoteType() { + let value = this._resource(); + if (value && value.links && value.links.related) { + return 'link'; + } - return 'id'; -}; + return 'id'; + } -/** + /** The link Ember Data will use to fetch or reload this belongs-to relationship. Example ```javascript - // models/blog.js - export default DS.Model.extend({ + // models/blog.js + export default DS.Model.extend({ user: DS.belongsTo({ async: true }) }); - let blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, @@ -81,39 +80,39 @@ Reference.prototype.remoteType = function() { } } }); - let userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); - // get the identifier of the reference - if (userRef.remoteType() === "link") { + // get the identifier of the reference + if (userRef.remoteType() === "link") { let link = userRef.link(); } - ``` + ``` @method link @return {String} The link Ember Data will use to fetch or reload this belongs-to relationship. -*/ -Reference.prototype.link = function() { - let link = null; - let resource = this._resource(); + */ + link() { + let link = null; + let resource = this._resource(); - if (resource && resource.links && resource.links.related) { - link = resource.links.related; + if (resource && resource.links && resource.links.related) { + link = resource.links.related; + } + return link; } - return link; -}; -/** + /** The meta data for the belongs-to relationship. Example ```javascript - // models/blog.js - export default DS.Model.extend({ + // models/blog.js + export default DS.Model.extend({ user: DS.belongsTo({ async: true }) }); - let blog = store.push({ + let blog = store.push({ data: { type: 'blog', id: 1, @@ -132,21 +131,20 @@ Reference.prototype.link = function() { } }); - let userRef = blog.belongsTo('user'); + let userRef = blog.belongsTo('user'); - userRef.meta() // { lastUpdated: 1458014400000 } - ``` + userRef.meta() // { lastUpdated: 1458014400000 } + ``` @method meta @return {Object} The meta information for the belongs-to relationship. -*/ -Reference.prototype.meta = function() { - let meta = null; - let resource = this._resource(); - if (resource && resource.meta) { - meta = resource.meta; + */ + meta() { + let meta = null; + let resource = this._resource(); + if (resource && resource.meta) { + meta = resource.meta; + } + return meta; } - return meta; -}; - -export default Reference; +} From 099d066eab8985f76aa6656aaba797fb184e7d8b Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 17 Oct 2018 21:21:29 -0700 Subject: [PATCH 2379/2527] [CHORE] remove deprecations targeted for 3.5 (#5700) * [CHORE] remove deprecations targeted for 3.5 * remove updateId * make MapWithDefault die a thousand deaths --- addon/-private/index.js | 3 - addon/-private/system/map-with-default.js | 21 --- addon/-private/system/map.js | 122 ------------------ addon/-private/system/model/errors.js | 26 ++-- addon/-private/system/model/model.js | 18 +-- .../-private/system/references/belongs-to.js | 16 +-- addon/-private/system/relationships/ext.js | 18 ++- addon/-private/system/store.js | 75 +---------- addon/adapters/rest.js | 11 +- tests/unit/model-test.js | 2 +- tests/unit/model/relationships-test.js | 3 +- tests/unit/store/asserts-test.js | 1 - 12 files changed, 47 insertions(+), 269 deletions(-) delete mode 100644 addon/-private/system/map-with-default.js delete mode 100644 addon/-private/system/map.js diff --git a/addon/-private/index.js b/addon/-private/index.js index e9eedd50e26..e8da57915cd 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -42,9 +42,6 @@ export { default as ManyArray } from './system/many-array'; export { default as RecordArrayManager } from './system/record-array-manager'; export { default as Relationship } from './system/relationships/state/relationship'; -export { default as Map } from './system/map'; -export { default as MapWithDefault } from './system/map-with-default'; - // Should be a different Repo ? export { default as DebugAdapter } from './system/debug/debug-adapter'; diff --git a/addon/-private/system/map-with-default.js b/addon/-private/system/map-with-default.js deleted file mode 100644 index 69f397e06f3..00000000000 --- a/addon/-private/system/map-with-default.js +++ /dev/null @@ -1,21 +0,0 @@ -import Map from './map'; - -export default class MapWithDefault extends Map { - constructor(options) { - super(); - - this.defaultValue = options.defaultValue; - } - - get(key) { - let hasValue = this.has(key); - - if (hasValue) { - return super.get(key); - } else { - let defaultValue = this.defaultValue(key); - this.set(key, defaultValue); - return defaultValue; - } - } -} diff --git a/addon/-private/system/map.js b/addon/-private/system/map.js deleted file mode 100644 index c7c0be9846b..00000000000 --- a/addon/-private/system/map.js +++ /dev/null @@ -1,122 +0,0 @@ -import { deprecate } from '@ember/debug'; - -/* - ## Why does this exist?!? - - `Ember.Map` was a private API provided by Ember (for quite some time). - Unfortunately, ember-data made `Ember.Map` part of its public API surface via - documentation blocks. - - `Ember.Map` will be deprecated and removed from Ember "soon" - (https://github.com/emberjs/rfcs/pull/237) and we would like to confirm that - Ember Data will work without deprecation before and after that happens. - - `Ember.Map` differs from native `Map` in a few ways: - - * `Ember.Map` has custom `copy` and `isEmpty` methods which are not present in native `Map` - * `Ember.Map` adds a static `create` method (which simply instantiates itself with `new Ember.Map()`) - * `Ember.Map` does not accept constructor arguments - * `Ember.Map` does not have: - * `@@species` - * `@@iterator` - * `entries` - * `values` - - This implementation adds a deprecated backwards compatibility for: - - * `copy` - * `isEmpty` - - ## Why is this written this way?!? - - This is needed because `Map` requires instantiation with `new` and by default - Babel transpilation will do `superConstructor.apply(this, arguments)` which - throws an error with native `Map`. - - The desired code (if we lived in an "only native class" world) would be: - - ```js - export default class MapWithDeprecations extends Map { - constructor(options) { - super(); - this.defaultValue = options.defaultValue; - } - - get(key) { - let hasValue = this.has(key); - - if (hasValue) { - return super.get(key); - } else { - let defaultValue = this.defaultValue(key); - this.set(key, defaultValue); - return defaultValue; - } - } - } - ``` -*/ -export default class MapWithDeprecations { - constructor(options) { - this._map = new Map(); - } - - copy() { - deprecate( - 'Calling `.copy()` on a map generated by ember-data is deprecated, please migrate to using native Map functionality only.', - false, - { id: 'ember-data.map.copy', until: '3.5.0' } - ); - - // can't just pass `this._map` here because IE11 doesn't accept - // constructor args with its `Map` - let newMap = new MapWithDeprecations(); - this._map.forEach(function(value, key) { - newMap.set(key, value); - }); - - return newMap; - } - - isEmpty() { - deprecate( - 'Calling `.isEmpty()` on a map generated by ember-data is deprecated, please migrate to using native Map functionality only.', - false, - { id: 'ember-data.map.isEmpty', until: '3.5.0' } - ); - - return this.size === 0; - } - - // proxy all normal Map methods to the underlying Map - get size() { - return this._map.size; - } - clear() { - return this._map.clear(...arguments); - } - delete() { - return this._map.delete(...arguments); - } - entries() { - return this._map.entries(...arguments); - } - forEach() { - return this._map.forEach(...arguments); - } - get() { - return this._map.get(...arguments); - } - has() { - return this._map.has(...arguments); - } - keys() { - return this._map.keys(...arguments); - } - set() { - return this._map.set(...arguments); - } - values() { - return this._map.values(...arguments); - } -} diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index e718fc06168..8a8fd2e5d3d 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -3,7 +3,6 @@ import Evented from '@ember/object/evented'; import ArrayProxy from '@ember/array/proxy'; import { set, get, computed } from '@ember/object'; import { makeArray, A } from '@ember/array'; -import MapWithDefault from '../map-with-default'; import { warn } from '@ember/debug'; /** @@ -103,11 +102,7 @@ export default ArrayProxy.extend(Evented, { @private */ errorsByAttributeName: computed(function() { - return new MapWithDefault({ - defaultValue() { - return A(); - }, - }); + return new Map(); }), /** @@ -129,7 +124,13 @@ export default ArrayProxy.extend(Evented, { @return {Array} */ errorsFor(attribute) { - return get(this, 'errorsByAttributeName').get(attribute); + let map = get(this, 'errorsByAttributeName'); + + if (!map.has(attribute)) { + map.set(attribute, new A()); + } + + return map.get(attribute); }, /** @@ -225,9 +226,8 @@ export default ArrayProxy.extend(Evented, { _add(attribute, messages) { messages = this._findOrCreateMessages(attribute, messages); this.addObjects(messages); - get(this, 'errorsByAttributeName') - .get(attribute) - .addObjects(messages); + + this.errorsFor(attribute).addObjects(messages); this.notifyPropertyChange(attribute); }, @@ -375,16 +375,16 @@ export default ArrayProxy.extend(Evented, { } let errorsByAttributeName = get(this, 'errorsByAttributeName'); - let attributes = A(); + let attributes = []; errorsByAttributeName.forEach(function(_, attribute) { attributes.push(attribute); }); errorsByAttributeName.clear(); - attributes.forEach(function(attribute) { + attributes.forEach(attribute => { this.notifyPropertyChange(attribute); - }, this); + }); ArrayProxy.prototype.clear.call(this); }, diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index a770fb766f1..098d8f70e9b 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -3,7 +3,6 @@ import { isNone } from '@ember/utils'; import EmberError from '@ember/error'; import Evented from '@ember/object/evented'; import EmberObject, { computed, get } from '@ember/object'; -import Map from '../map'; import { DEBUG } from '@glimmer/env'; import { assert, warn } from '@ember/debug'; import { PromiseObject } from '../promise-proxies'; @@ -31,15 +30,18 @@ function findPossibleInverses(type, inverseType, name, relationshipsSoFar) { return possibleRelationships; } - let relationships = relationshipMap.get(type.modelName).filter(relationship => { - let optionsForRelationship = inverseType.metaForProperty(relationship.name).options; + let relationshipsForType = relationshipMap.get(type.modelName); + let relationships = Array.isArray(relationshipsForType) + ? relationshipsForType.filter(relationship => { + let optionsForRelationship = inverseType.metaForProperty(relationship.name).options; - if (!optionsForRelationship.inverse && optionsForRelationship.inverse !== null) { - return true; - } + if (!optionsForRelationship.inverse && optionsForRelationship.inverse !== null) { + return true; + } - return name === optionsForRelationship.inverse; - }); + return name === optionsForRelationship.inverse; + }) + : null; if (relationships) { possibleRelationships.push.apply(possibleRelationships, relationships); diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index 9f99b4aefd0..e0c0ea10c10 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -1,11 +1,8 @@ import { resolve } from 'rsvp'; +import { assertPolymorphicType } from 'ember-data/-debug'; import Model from '../model/model'; import Reference from './reference'; -import isEnabled from '../../features'; -import { deprecate } from '@ember/debug'; -import { assertPolymorphicType } from 'ember-data/-debug'; - /** A BelongsToReference is a low-level API that allows users and addon author to perform meta-operations on a belongs-to @@ -125,17 +122,8 @@ export default class BelongsToReference extends Reference { return resolve(objectOrPromise).then(data => { let record; + // TODO deprecate data as Model if (data instanceof Model) { - if (isEnabled('ds-overhaul-references')) { - deprecate( - "BelongsToReference#push(DS.Model) is deprecated. Update relationship via `model.set('relationshipName', value)` instead.", - false, - { - id: 'ds.references.belongs-to.push-record', - until: '4.0.0', - } - ); - } record = data; } else { record = this.store.push(data); diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index d1087e680a9..98a5a3d0b9b 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -1,23 +1,21 @@ import { A } from '@ember/array'; import { computed, get } from '@ember/object'; -import MapWithDefault from '../map-with-default'; -import Map from '../map'; import { assert } from '@ember/debug'; import { typeForRelationshipMeta, relationshipFromMeta } from '../relationship-meta'; export const relationshipsDescriptor = computed(function() { - let map = new MapWithDefault({ - defaultValue() { - return []; - }, - }); - + let map = new Map(); let relationshipsByName = get(this, 'relationshipsByName'); // Loop through each computed property on the class relationshipsByName.forEach(desc => { - let relationshipsForType = map.get(desc.type); - relationshipsForType.push(desc); + let { type } = desc; + + if (!map.has(type)) { + map.set(type, []); + } + + map.get(type).push(desc); }); return map; diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 8dc63d72868..145bea4d712 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -5,7 +5,6 @@ import { registerWaiter, unregisterWaiter } from '@ember/test'; import { A } from '@ember/array'; import EmberError from '@ember/error'; -import MapWithDefault from './map-with-default'; import { run as emberRunLoop } from '@ember/runloop'; import { set, get, computed } from '@ember/object'; import { assign } from '@ember/polyfills'; @@ -217,11 +216,7 @@ Store = Service.extend({ this._updatedInternalModels = []; // used to keep track of all the find requests that need to be coalesced - this._pendingFetch = new MapWithDefault({ - defaultValue() { - return []; - }, - }); + this._pendingFetch = new Map(); this._adapterCache = Object.create(null); this._serializerCache = Object.create(null); @@ -934,7 +929,12 @@ Store = Service.extend({ emberRun.schedule('actions', this, this.flushAllPendingFetches); } - this._pendingFetch.get(modelName).push(pendingFetchItem); + let fetches = this._pendingFetch; + if (!fetches.has(modelName)) { + fetches.set(modelName, []); + } + + fetches.get(modelName).push(pendingFetchItem); return promise; }, @@ -2298,17 +2298,6 @@ Store = Service.extend({ this._setRecordId(internalModel, newId, clientId); }, - updateId(internalModel, data) { - if (DEBUG) { - assertDestroyingStore(this, 'updateId'); - } - deprecate('store.updateId was documented as private and will be removed.', false, { - id: 'ds.store.updateId', - until: '3.5', - }); - this._setRecordId(internalModel, coerceId(data.id)); - }, - _setRecordId(internalModel, id, clientId) { if (DEBUG) { assertDestroyingStore(this, 'setRecordId'); @@ -2397,32 +2386,6 @@ Store = Service.extend({ return internalModel; }, - /* - @deprecated - @private - */ - _modelForMixin(modelName) { - deprecate( - '_modelForMixin is private and deprecated and should never be used directly, use modelFor instead', - false, - { - id: 'ember-data:_modelForMixin', - until: '3.5', - } - ); - assert( - `You need to pass a model name to the store's _modelForMixin method`, - isPresent(modelName) - ); - assert( - `Passing classes to store methods has been removed. Please pass a dasherized string instead of ${modelName}`, - typeof modelName === 'string' - ); - let normalizedModelName = normalizeModelName(modelName); - - return _modelForMixin(this, normalizedModelName); - }, - /** Returns the model class for the particular `modelName`. @@ -2451,18 +2414,6 @@ Store = Service.extend({ return maybeFactory.class ? maybeFactory.class : maybeFactory; }, - /* - @deprecated - @private - */ - _modelFor(modelName) { - deprecate('_modelFor is private and deprecated, you should use modelFor instead', false, { - id: 'ember-data:_modelFor', - until: '3.5', - }); - return this.modelFor(modelName); - }, - _modelFactoryFor(modelName) { if (DEBUG) { assertDestroyedStoreOnly(this, '_modelFactoryFor'); @@ -2485,18 +2436,6 @@ Store = Service.extend({ return factory; }, - /* - @deprecated - @private - */ - modelFactoryFor(modelName) { - deprecate('modelFactoryFor is private and deprecated', false, { - id: 'ember-data:modelFactoryFor', - until: '3.5', - }); - return this._modelFactoryFor(modelName); - }, - /* Returns whether a ModelClass exists for a given modelName This exists for legacy support for the RESTSerializer, diff --git a/addon/adapters/rest.js b/addon/adapters/rest.js index 5a5aebd1752..f7267eafa52 100644 --- a/addon/adapters/rest.js +++ b/addon/adapters/rest.js @@ -23,7 +23,6 @@ import { ServerError, TimeoutError, AbortError, - MapWithDefault, } from '../-private'; import { instrument } from 'ember-data/-debug'; import { warn } from '@ember/debug'; @@ -817,16 +816,16 @@ const RESTAdapter = Adapter.extend(BuildURLMixin, { loaded separately by `findMany`. */ groupRecordsForFindMany(store, snapshots) { - let groups = new MapWithDefault({ - defaultValue() { - return []; - }, - }); + let groups = new Map(); let adapter = this; let maxURLLength = this.maxURLLength; snapshots.forEach(snapshot => { let baseUrl = adapter._stripIDFromURL(store, snapshot); + if (!groups.has(baseUrl)) { + groups.set(baseUrl, []); + } + groups.get(baseUrl).push(snapshot); }); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 730c478cdf1..32bbb937a2c 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -1596,7 +1596,7 @@ test('ID mutation (complicated)', function(assert) { assert.equal(person.get('id'), null, 'initial created model id should be null'); assert.equal(idChange, 0); - store.updateId(person._internalModel, { id: 'john' }); + store._setRecordId(person._internalModel, 'john'); assert.equal(idChange, 1); assert.equal(person.get('id'), 'john', 'new id should be correctly set.'); }); diff --git a/tests/unit/model/relationships-test.js b/tests/unit/model/relationships-test.js index 8ed63037127..c355489e6e2 100644 --- a/tests/unit/model/relationships-test.js +++ b/tests/unit/model/relationships-test.js @@ -27,8 +27,7 @@ module('unit/model/relationships - DS.Model', { }); test('exposes a hash of the relationships on a model', function(assert) { - store.createRecord('person'); - store.createRecord('occupation'); + let Person = store.modelFor('person'); let relationships = get(Person, 'relationships'); function extractDetails(key) { diff --git a/tests/unit/store/asserts-test.js b/tests/unit/store/asserts-test.js index 902e9204f57..b3032c36934 100644 --- a/tests/unit/store/asserts-test.js +++ b/tests/unit/store/asserts-test.js @@ -66,7 +66,6 @@ module('unit/store/asserts - DS.Store methods produce useful assertion messages' 'didSaveRecord', 'recordWasInvalid', 'recordWasError', - 'updateId', 'modelFor', '_modelFactoryFor', '_hasModelFor', From a0a4131fa5dddd8a0e620141b7c8fefe57311d3c Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 18 Oct 2018 13:23:40 -0700 Subject: [PATCH 2380/2527] [BUGFIX unloadRecord] bfs compatibility for custom RecordData (#5703) --- addon/-private/system/model/record-data.js | 14 +- tests/integration/records/record-data-test.js | 233 ++++++++++++++++++ 2 files changed, 243 insertions(+), 4 deletions(-) create mode 100644 tests/integration/records/record-data-test.js diff --git a/addon/-private/system/model/record-data.js b/addon/-private/system/model/record-data.js index b64b902ac66..cebd7af39b4 100644 --- a/addon/-private/system/model/record-data.js +++ b/addon/-private/system/model/record-data.js @@ -402,16 +402,22 @@ export default class RecordData { while (queue.length > 0) { let node = queue.shift(); array.push(node); + let related = node._directlyRelatedRecordDatas(); + for (let i = 0; i < related.length; ++i) { let recordData = related[i]; - assert('Internal Error: seen a future bfs iteration', recordData._bfsId <= bfsId); - if (recordData._bfsId < bfsId) { - queue.push(recordData); - recordData._bfsId = bfsId; + + if (recordData instanceof RecordData) { + assert('Internal Error: seen a future bfs iteration', recordData._bfsId <= bfsId); + if (recordData._bfsId < bfsId) { + queue.push(recordData); + recordData._bfsId = bfsId; + } } } } + return array; } diff --git a/tests/integration/records/record-data-test.js b/tests/integration/records/record-data-test.js new file mode 100644 index 00000000000..a9b9c3f9765 --- /dev/null +++ b/tests/integration/records/record-data-test.js @@ -0,0 +1,233 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import Model from 'ember-data/model'; +import { run } from '@ember/runloop'; +import { attr, belongsTo, hasMany } from '@ember-decorators/data'; +import { assign } from '@ember/polyfills'; +import { RecordData } from 'ember-data/-private'; + +class Person extends Model { + @hasMany('pet', { inverse: null, async: false }) + pets; + @attr + name; +} + +class Pet extends Model { + @belongsTo('person', { inverse: null, async: false }) + owner; + @attr + name; +} + +function recordDataForRecord(record) { + return record._internalModel._recordData; +} + +module('RecordData Compatibility', function(hooks) { + let store; + setupTest(hooks); + + hooks.beforeEach(function() { + let { owner } = this; + owner.register('model:person', Person); + owner.register('model:pet', Pet); + store = owner.lookup('service:store'); + }); + + class CustomRecordData { + constructor(modelName, id, clientId, storeWrapper) { + this.type = modelName; + this.id = id || null; + this.clientId = clientId; + this.storeWrapper = storeWrapper; + this.attributes = null; + this.relationships = null; + } + + pushData(jsonApiResource, shouldCalculateChanges) { + let oldAttrs = this.attributes; + let changedKeys; + + this.attributes = jsonApiResource.attributes || null; + + if (shouldCalculateChanges) { + changedKeys = Object.keys(assign({}, oldAttrs, this.attributes)); + } + + return changedKeys || []; + } + + getAttr(member) { + return this.attributes !== null ? this.attributes[member] : undefined; + } + + hasAttr(key) { + return key in this.attributes; + } + + // TODO missing from RFC but required to implement + _initRecordCreateOptions(options) { + return options !== undefined ? options : {}; + } + // TODO missing from RFC but required to implement + getResourceIdentifier() { + return { + id: this.id, + type: this.type, + clientId: this.clientId, + }; + } + // TODO missing from RFC but required to implement + unloadRecord() { + this.attributes = null; + this.relationships = null; + } + // TODO missing from RFC but required to implement + isNew() { + return this.id === null; + } + + adapterDidCommit() {} + didCreateLocally() {} + adapterWillCommit() {} + saveWasRejected() {} + adapterDidDelete() {} + recordUnloaded() {} + rollbackAttributes() {} + rollbackAttribute() {} + changedAttributes() {} + hasChangedAttributes() {} + setAttr() {} + setHasMany() {} + getHasMany() {} + addToHasMany() {} + removeFromHasMany() {} + setBelongsTo() {} + getBelongsTo() {} + } + + test(`store.unloadRecord on a record with default RecordData with relationship to a record with custom RecordData does not error`, async function(assert) { + const originalCreateRecordDataFor = store.createRecordDataFor; + store.createRecordDataFor = function provideCustomRecordData( + modelName, + id, + clientId, + storeWrapper + ) { + if (modelName === 'pet') { + return new CustomRecordData(modelName, id, clientId, storeWrapper); + } else { + return originalCreateRecordDataFor.call(this, modelName, id, clientId, storeWrapper); + } + }; + + let chris = store.push({ + data: { + type: 'person', + id: '1', + attributes: { name: 'Chris' }, + relationships: { + pets: { + data: [{ type: 'pet', id: '1' }, { type: 'pet', id: '2' }], + }, + }, + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owner: { data: { type: 'person', id: '1' } }, + }, + }, + { + type: 'pet', + id: '2', + attributes: { name: 'Prince' }, + relationships: { + owner: { data: { type: 'person', id: '1' } }, + }, + }, + ], + }); + let pets = chris.get('pets'); + let shen = pets.objectAt(0); + + assert.equal(shen.get('name'), 'Shen', 'We found Shen'); + assert.ok( + recordDataForRecord(chris) instanceof RecordData, + 'We used the default record-data for person' + ); + assert.ok( + recordDataForRecord(shen) instanceof CustomRecordData, + 'We used the custom record-data for pets' + ); + + try { + run(() => chris.unloadRecord()); + assert.ok(true, 'expected `unloadRecord()` not to throw'); + } catch (e) { + assert.ok(false, 'expected `unloadRecord()` not to throw'); + } + }); + + test(`store.unloadRecord on a record with custom RecordData with relationship to a record with default RecordData does not error`, async function(assert) { + const originalCreateRecordDataFor = store.createModelDataFor; + store.createModelDataFor = function provideCustomRecordData( + modelName, + id, + clientId, + storeWrapper + ) { + if (modelName === 'pet') { + return new CustomRecordData(modelName, id, clientId, storeWrapper); + } else { + return originalCreateRecordDataFor.call(this, modelName, id, clientId, storeWrapper); + } + }; + + let chris = store.push({ + data: { + type: 'person', + id: '1', + attributes: { name: 'Chris' }, + relationships: { + pets: { + data: [{ type: 'pet', id: '1' }, { type: 'pet', id: '2' }], + }, + }, + }, + included: [ + { + type: 'pet', + id: '1', + attributes: { name: 'Shen' }, + relationships: { + owner: { data: { type: 'person', id: '1' } }, + }, + }, + { + type: 'pet', + id: '2', + attributes: { name: 'Prince' }, + relationships: { + owner: { data: { type: 'person', id: '1' } }, + }, + }, + ], + }); + let pets = chris.get('pets'); + let shen = pets.objectAt(0); + + assert.equal(shen.get('name'), 'Shen', 'We found Shen'); + + try { + run(() => shen.unloadRecord()); + assert.ok(true, 'expected `unloadRecord()` not to throw'); + } catch (e) { + assert.ok(false, 'expected `unloadRecord()` not to throw'); + } + }); +}); From f14ceb814e11bbd42b094658186fc00f65f7ecec Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 19 Oct 2018 04:28:44 +0200 Subject: [PATCH 2381/2527] Use _scheduleFetch instead of _fetchRecord for belongsTo relationship (#5671) * Use _scheduleFetch instead of _fetchRecord for belongsTo relationship In order to ensure coalesceFindRequests works for this case. * Add tests for coalescing of belongsTo relationships --- addon/-private/system/store.js | 2 +- .../model/relationships/belongs-to-test.js | 163 ++++++++++++++++++ 2 files changed, 164 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 145bea4d712..4b6caa9f6bc 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1560,7 +1560,7 @@ Store = Service.extend({ // fetch by data if (!localDataIsEmpty) { - return this._fetchRecord(internalModel, options).then(() => { + return this._scheduleFetch(internalModel, options).then(() => { return internalModel.getRecord(); }); } diff --git a/tests/unit/model/relationships/belongs-to-test.js b/tests/unit/model/relationships/belongs-to-test.js index 062734ebe3c..ee494ee7f92 100644 --- a/tests/unit/model/relationships/belongs-to-test.js +++ b/tests/unit/model/relationships/belongs-to-test.js @@ -1,6 +1,7 @@ import { get } from '@ember/object'; import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; +import { Promise } from 'rsvp'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; @@ -198,6 +199,168 @@ test('async belongsTo relationships work when the data hash has not been loaded' }); }); +test('async belongsTo relationships are not grouped with coalesceFindRequests=false', async function(assert) { + assert.expect(6); + + const Tag = DS.Model.extend({ + name: DS.attr('string'), + }); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: true }), + }); + + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + + env.adapter.coalesceFindRequests = false; + + store.push({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + tag: { + data: { type: 'tag', id: '3' }, + }, + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Bob Dylan', + }, + relationships: { + tag: { + data: { type: 'tag', id: '4' }, + }, + }, + }, + ], + }); + + env.adapter.findMany = function() { + throw new Error('findMany should not be called'); + }; + + env.adapter.findRecord = function(store, type, id) { + assert.equal(type.modelName, 'tag', 'modelName is tag'); + + if (id === '3') { + return Promise.resolve({ + data: { + id: '3', + type: 'tag', + attributes: { name: 'friendly' }, + }, + }); + } else if (id === '4') { + return Promise.resolve({ + data: { + id: '4', + type: 'tag', + attributes: { name: 'nice' }, + }, + }); + } + }; + + let persons = [store.peekRecord('person', '1'), store.peekRecord('person', '2')]; + let [tag1, tag2] = await Promise.all(persons.map(person => get(person, 'tag'))); + + assert.equal(get(tag1, 'name'), 'friendly', 'Tom Dale is now friendly'); + assert.equal(get(tag1, 'isLoaded'), true, "Tom Dale's tag is now loaded"); + + assert.equal(get(tag2, 'name'), 'nice', 'Bob Dylan is now nice'); + assert.equal(get(tag2, 'isLoaded'), true, "Bob Dylan's tag is now loaded"); +}); + +test('async belongsTo relationships are grouped with coalesceFindRequests=true', async function(assert) { + assert.expect(6); + + const Tag = DS.Model.extend({ + name: DS.attr('string'), + }); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + tag: DS.belongsTo('tag', { async: true }), + }); + + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + + env.adapter.coalesceFindRequests = true; + + store.push({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + tag: { + data: { type: 'tag', id: '3' }, + }, + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Bob Dylan', + }, + relationships: { + tag: { + data: { type: 'tag', id: '4' }, + }, + }, + }, + ], + }); + + env.adapter.findMany = function(store, type, ids, snapshots) { + assert.equal(type.modelName, 'tag', 'modelName is tag'); + assert.deepEqual(ids, ['3', '4'], 'it coalesces the find requests correctly'); + + return Promise.resolve({ + data: [ + { + id: '3', + type: 'tag', + attributes: { name: 'friendly' }, + }, + { + id: '4', + type: 'tag', + attributes: { name: 'nice' }, + }, + ], + }); + }; + + env.adapter.findRecord = function() { + throw new Error('findRecord should not be called'); + }; + + let persons = [store.peekRecord('person', '1'), store.peekRecord('person', '2')]; + let [tag1, tag2] = await Promise.all(persons.map(person => get(person, 'tag'))); + + assert.equal(get(tag1, 'name'), 'friendly', 'Tom Dale is now friendly'); + assert.equal(get(tag1, 'isLoaded'), true, "Tom Dale's tag is now loaded"); + + assert.equal(get(tag2, 'name'), 'nice', 'Bob Dylan is now nice'); + assert.equal(get(tag2, 'isLoaded'), true, "Bob Dylan's tag is now loaded"); +}); + test('async belongsTo relationships work when the data hash has already been loaded', function(assert) { assert.expect(3); From 6dddb2dbf3f2d292d8f54a365b0436ff437e1c46 Mon Sep 17 00:00:00 2001 From: Chris de Almeida Date: Tue, 23 Oct 2018 13:16:56 -0500 Subject: [PATCH 2382/2527] update/remove rails/backend references (#5676) --- addon/-private/system/store.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 4b6caa9f6bc..1dc458d048f 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -337,7 +337,7 @@ Store = Service.extend({ ```js store.createRecord('post', { - title: 'Rails is omakase' + title: 'Ember is awesome!' }); ``` @@ -346,7 +346,7 @@ Store = Service.extend({ ```js let user = this.store.peekRecord('user', 1); store.createRecord('post', { - title: 'Rails is omakase', + title: 'Ember is awesome!', user: user }); ``` @@ -434,7 +434,7 @@ Store = Service.extend({ ```javascript let post = store.createRecord('post', { - title: 'Rails is omakase' + title: 'Ember is awesome!' }); store.deleteRecord(post); @@ -1588,12 +1588,10 @@ Store = Service.extend({ store.query('person', { page: 1 }); ``` - The call made to the server, using a Rails backend, will look something like this: + The request made to the server will look something like this: ``` - Started GET "/api/v1/person?page=1" - Processing by Api::V1::PersonsController#index as HTML - Parameters: { "page"=>"1" } + GET "/api/v1/person?page=1" ``` --- @@ -1604,12 +1602,11 @@ Store = Service.extend({ store.query('person', { ids: [1, 2, 3] }); ``` - The call to the server, using a Rails backend, will look something like this: + The request made to the server will look something like this: ``` - Started GET "/api/v1/person?ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3" - Processing by Api::V1::PersonsController#index as HTML - Parameters: { "ids" => ["1", "2", "3"] } + GET "/api/v1/person?ids%5B%5D=1&ids%5B%5D=2&ids%5B%5D=3" + decoded: "/api/v1/person?ids[]=1&ids[]=2&ids[]=3" ``` This method returns a promise, which is resolved with an From 0bbdbadd16f3ae7fc84e9492defd7618e8e2d21e Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 25 Oct 2018 15:38:03 -0700 Subject: [PATCH 2383/2527] remove old feature-flag --- addon/-private/system/model/record-data.js | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/addon/-private/system/model/record-data.js b/addon/-private/system/model/record-data.js index cebd7af39b4..3132ddbdc22 100644 --- a/addon/-private/system/model/record-data.js +++ b/addon/-private/system/model/record-data.js @@ -708,23 +708,6 @@ export default class RecordData { } } -if (isEnabled('ds-rollback-attribute')) { - /* - Returns the latest truth for an attribute - the canonical value, or the - in-flight value. - - @method lastAcknowledgedValue - @private - */ - RecordData.prototype.lastAcknowledgedValue = function lastAcknowledgedValue(key) { - if (key in this._inFlightAttributes) { - return this._inFlightAttributes[key]; - } else { - return this._data[key]; - } - }; -} - function assertRelationshipData(store, recordData, data, meta) { assert( `A ${recordData.modelName} record was pushed into the store with the value of ${ From f578abc2a55133be4ee3d268edf72623ad5c0289 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 25 Oct 2018 15:46:58 -0700 Subject: [PATCH 2384/2527] fix unnecessary import for linter --- addon/-private/system/model/record-data.js | 1 - 1 file changed, 1 deletion(-) diff --git a/addon/-private/system/model/record-data.js b/addon/-private/system/model/record-data.js index 3132ddbdc22..4c5406e241f 100644 --- a/addon/-private/system/model/record-data.js +++ b/addon/-private/system/model/record-data.js @@ -3,7 +3,6 @@ import { assign } from '@ember/polyfills'; import { isEqual } from '@ember/utils'; import { assert, warn, inspect } from '@ember/debug'; import { run } from '@ember/runloop'; -import isEnabled from '../../features'; import Relationships from '../relationships/state/create'; import coerceId from '../coerce-id'; From 3a688a8f3e2e90f8a2180c517b85014da3404b57 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 25 Oct 2018 15:28:24 -0700 Subject: [PATCH 2385/2527] [CHORE deps] upgrades all dependencies to latest (babel7!) downgrade ember-cli to 3.4 because 3.5 breaks node-tests --- index.js | 2 +- lib/stripped-build-plugins.js | 4 +- package.json | 64 +- yarn.lock | 3278 +++++++++++++++++++++++++-------- 4 files changed, 2591 insertions(+), 757 deletions(-) diff --git a/index.js b/index.js index 37e23ebcdaa..530064c35c3 100644 --- a/index.js +++ b/index.js @@ -139,7 +139,7 @@ module.exports = { loose: true, plugins: customPlugins.plugins, postTransformPlugins: customPlugins.postTransformPlugins, - exclude: ['transform-es2015-block-scoping', 'transform-es2015-typeof-symbol'], + exclude: ['transform-block-scoping', 'transform-typeof-symbol'], }; }, diff --git a/lib/stripped-build-plugins.js b/lib/stripped-build-plugins.js index 99d0e1c223a..2ac0046035d 100644 --- a/lib/stripped-build-plugins.js +++ b/lib/stripped-build-plugins.js @@ -7,7 +7,7 @@ const FeatureFlags = requireBabelPlugin('babel-plugin-feature-flags'); const StripHeimdall = requireBabelPlugin('babel6-plugin-strip-heimdall'); const StripClassCallCheck = requireBabelPlugin('babel6-plugin-strip-class-callcheck'); const StripFilteredImports = requireBabelPlugin('./transforms/babel-plugin-remove-imports'); -const TransformBlockScoping = requireBabelPlugin('babel-plugin-transform-es2015-block-scoping'); +const TransformBlockScoping = requireBabelPlugin('@babel/plugin-transform-block-scoping'); const { isInstrumentedBuild } = require('./cli-flags'); function uniqueAdd(obj, key, values) { @@ -67,7 +67,7 @@ module.exports = function(environment) { } plugins.push( - [FilterImports, filteredImports], + [FilterImports, { imports: filteredImports }], [StripFilteredImports, filteredImports], [TransformBlockScoping, { throwIfClosureRequired: true }] ); diff --git a/package.json b/package.json index 892ebb4bbd6..8f3d2d3721c 100644 --- a/package.json +++ b/package.json @@ -32,20 +32,19 @@ "author": "", "license": "MIT", "dependencies": { - "@ember/ordered-set": "^2.0.0", + "@ember/ordered-set": "^2.0.3", "babel-plugin-feature-flags": "^0.3.1", - "babel-plugin-filter-imports": "^0.3.1", - "babel-plugin-transform-es2015-block-scoping": "^6.26.0", + "babel-plugin-filter-imports": "^2.0.3", "babel6-plugin-strip-class-callcheck": "^6.0.0", "babel6-plugin-strip-heimdall": "^6.0.1", - "broccoli-debug": "^0.6.4", + "broccoli-debug": "^0.6.5", "broccoli-file-creator": "^2.1.1", "broccoli-funnel": "^2.0.1", - "broccoli-merge-trees": "^3.0.0", + "broccoli-merge-trees": "^3.0.1", "broccoli-rollup": "^2.1.1", "calculate-cache-key-for-tree": "^1.1.0", "chalk": "^2.4.1", - "ember-cli-babel": "^6.16.0", + "ember-cli-babel": "^7.1.2", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.1.0", "ember-cli-test-info": "^1.0.0", @@ -56,61 +55,60 @@ "inflection": "^1.12.0", "npm-git-info": "^1.0.3", "resolve": "^1.8.1", - "semver": "^5.5.0", - "silent-error": "^1.1.0" + "semver": "^5.6.0", + "silent-error": "^1.1.1" }, "devDependencies": { - "@ember-decorators/babel-transforms": "^2.0.2", - "@ember-decorators/data": "^2.3.1", - "babel-eslint": "^8.2.6", - "broccoli-asset-rev": "^2.7.0", - "broccoli-babel-transpiler": "^6.5.0", - "broccoli-concat": "^3.5.1", + "@ember-decorators/babel-transforms": "^2.1.2", + "@ember-decorators/data": "^3.0.0", + "babel-eslint": "^10.0.1", + "broccoli-babel-transpiler": "^7.0.0", + "broccoli-concat": "^3.7.3", "broccoli-stew": "^2.0.0", "broccoli-string-replace": "^0.1.2", - "broccoli-test-helper": "^1.4.0", + "broccoli-test-helper": "^2.0.0", "broccoli-uglify-sourcemap": "^2.2.0", "co": "^4.6.0", "common-tags": "^1.8.0", - "ember-cli": "^3.3.0", + "ember-cli": "~3.4.3", "ember-cli-app-version": "^3.2.0", "ember-cli-blueprint-test-helpers": "^0.19.1", "ember-cli-dependency-checker": "^3.0.0", - "ember-cli-htmlbars": "^3.0.0", - "ember-cli-htmlbars-inline-precompile": "^1.0.3", - "ember-cli-inject-live-reload": "^1.8.2", + "ember-cli-htmlbars": "^3.0.1", + "ember-cli-htmlbars-inline-precompile": "^1.0.5", + "ember-cli-inject-live-reload": "^2.0.1", "ember-cli-internal-test-helpers": "^0.9.1", - "ember-cli-pretender": "^1.0.1", - "ember-cli-release": "^0.2.9", + "ember-cli-pretender": "^3.0.0", + "ember-cli-release": "^1.0.0-beta.2", "ember-cli-shims": "^1.2.0", "ember-cli-sri": "^2.1.1", "ember-cli-test-loader": "^2.2.0", "ember-cli-uglify": "2.1.0", "ember-cli-yuidoc": "^0.8.8", - "ember-decorators": "^2.3.1", + "ember-decorators": "^3.0.0", "ember-disable-prototype-extensions": "^1.1.3", "ember-export-application-global": "^2.0.0", "ember-load-initializers": "^1.1.0", "ember-maybe-import-regenerator": "^0.1.6", - "ember-qunit": "^3.4.1", + "ember-qunit": "^3.5.3", "ember-qunit-assert-helpers": "^0.2.1", "ember-resolver": "^5.0.1", "ember-source": "~3.5.0", "ember-source-channel-url": "^1.1.0", - "ember-try": "^1.0.0-beta.3", - "eslint": "^5.3.0", - "eslint-config-prettier": "^2.9.0", + "ember-try": "^1.1.0", + "eslint": "^5.7.0", + "eslint-config-prettier": "^3.1.0", "eslint-plugin-node": "^7.0.1", - "eslint-plugin-prettier": "2.6.2", - "execa": "^0.10.0", - "github": "^1.1.1", - "glob": "^7.1.2", + "eslint-plugin-prettier": "^3.0.0", + "execa": "^1.0.0", + "github": "^14.0.0", + "glob": "^7.1.3", "loader.js": "^4.7.0", "mocha": "^5.2.0", "mocha-only-detector": "1.0.0", - "prettier": "^1.14.0", - "rimraf": "2.6.2", - "rsvp": "4.8.3" + "prettier": "^1.14.3", + "rimraf": "^2.6.2", + "rsvp": "^4.8.4" }, "engines": { "node": ">= 6.0.0" diff --git a/yarn.lock b/yarn.lock index 8c78d277cdd..a13c2f27415 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,146 +2,629 @@ # yarn lockfile v1 -"@babel/code-frame@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" +"@babel/code-frame@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" dependencies: - "@babel/highlight" "7.0.0-beta.44" + "@babel/highlight" "^7.0.0" + +"@babel/core@^7.0.0": + version "7.1.2" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.1.2.tgz#f8d2a9ceb6832887329a7b60f9d035791400ba4e" + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.1.2" + "@babel/helpers" "^7.1.2" + "@babel/parser" "^7.1.2" + "@babel/template" "^7.1.2" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.1.2" + convert-source-map "^1.1.0" + debug "^3.1.0" + json5 "^0.5.0" + lodash "^4.17.10" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" -"@babel/generator@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" +"@babel/generator@^7.1.2", "@babel/generator@^7.1.3": + version "7.1.3" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.1.3.tgz#2103ec9c42d9bdad9190a6ad5ff2d456fd7b8673" dependencies: - "@babel/types" "7.0.0-beta.44" + "@babel/types" "^7.1.3" jsesc "^2.5.1" - lodash "^4.2.0" + lodash "^4.17.10" source-map "^0.5.0" trim-right "^1.0.1" -"@babel/helper-function-name@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" +"@babel/helper-annotate-as-pure@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" + dependencies: + "@babel/helper-explode-assignable-expression" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-call-delegate@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz#6a957f105f37755e8645343d3038a22e1449cc4a" + dependencies: + "@babel/helper-hoist-variables" "^7.0.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-define-map@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz#3b74caec329b3c80c116290887c0dd9ae468c20c" + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/types" "^7.0.0" + lodash "^4.17.10" + +"@babel/helper-explode-assignable-expression@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" + dependencies: + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-function-name@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" + dependencies: + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-get-function-arity@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-hoist-variables@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz#46adc4c5e758645ae7a45deb92bab0918c23bb88" + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-member-expression-to-functions@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f" + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-module-imports@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-module-transforms@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.1.0.tgz#470d4f9676d9fad50b324cdcce5fbabbc3da5787" dependencies: - "@babel/helper-get-function-arity" "7.0.0-beta.44" - "@babel/template" "7.0.0-beta.44" - "@babel/types" "7.0.0-beta.44" + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-simple-access" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + lodash "^4.17.10" + +"@babel/helper-optimise-call-expression@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-plugin-utils@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" + +"@babel/helper-regex@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.0.0.tgz#2c1718923b57f9bbe64705ffe5640ac64d9bdb27" + dependencies: + lodash "^4.17.10" -"@babel/helper-get-function-arity@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" +"@babel/helper-remap-async-to-generator@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f" dependencies: - "@babel/types" "7.0.0-beta.44" + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-wrap-function" "^7.1.0" + "@babel/template" "^7.1.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" -"@babel/helper-split-export-declaration@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" +"@babel/helper-replace-supers@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.1.0.tgz#5fc31de522ec0ef0899dc9b3e7cf6a5dd655f362" dependencies: - "@babel/types" "7.0.0-beta.44" + "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" -"@babel/highlight@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" +"@babel/helper-simple-access@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" + dependencies: + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-split-export-declaration@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813" + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-wrap-function@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.1.0.tgz#8cf54e9190706067f016af8f75cb3df829cc8c66" + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/template" "^7.1.0" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helpers@^7.1.2": + version "7.1.2" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.1.2.tgz#ab752e8c35ef7d39987df4e8586c63b8846234b5" + dependencies: + "@babel/template" "^7.1.2" + "@babel/traverse" "^7.1.0" + "@babel/types" "^7.1.2" + +"@babel/highlight@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" dependencies: chalk "^2.0.0" esutils "^2.0.2" - js-tokens "^3.0.0" - -"@babel/template@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" - dependencies: - "@babel/code-frame" "7.0.0-beta.44" - "@babel/types" "7.0.0-beta.44" - babylon "7.0.0-beta.44" - lodash "^4.2.0" - -"@babel/traverse@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" - dependencies: - "@babel/code-frame" "7.0.0-beta.44" - "@babel/generator" "7.0.0-beta.44" - "@babel/helper-function-name" "7.0.0-beta.44" - "@babel/helper-split-export-declaration" "7.0.0-beta.44" - "@babel/types" "7.0.0-beta.44" - babylon "7.0.0-beta.44" + js-tokens "^4.0.0" + +"@babel/parser@^7.0.0", "@babel/parser@^7.1.2", "@babel/parser@^7.1.3": + version "7.1.3" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.1.3.tgz#2c92469bac2b7fbff810b67fca07bd138b48af77" + +"@babel/plugin-proposal-async-generator-functions@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.1.0.tgz#41c1a702e10081456e23a7b74d891922dd1bb6ce" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.1.0" + "@babel/plugin-syntax-async-generators" "^7.0.0" + +"@babel/plugin-proposal-class-properties@^7.0.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.1.0.tgz#9af01856b1241db60ec8838d84691aa0bd1e8df4" + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.1.0" + "@babel/plugin-syntax-class-properties" "^7.0.0" + +"@babel/plugin-proposal-decorators@^7.0.0": + version "7.1.2" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.1.2.tgz#79829bd75fced6581ec6c7ab1930e8d738e892e7" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/plugin-syntax-decorators" "^7.1.0" + +"@babel/plugin-proposal-json-strings@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.0.0.tgz#3b4d7b5cf51e1f2e70f52351d28d44fc2970d01e" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-json-strings" "^7.0.0" + +"@babel/plugin-proposal-object-rest-spread@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0.tgz#9a17b547f64d0676b6c9cecd4edf74a82ab85e7e" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.0.0" + +"@babel/plugin-proposal-optional-catch-binding@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.0.0.tgz#b610d928fe551ff7117d42c8bb410eec312a6425" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.0.0" + +"@babel/plugin-proposal-unicode-property-regex@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0.tgz#498b39cd72536cd7c4b26177d030226eba08cd33" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + regexpu-core "^4.2.0" + +"@babel/plugin-syntax-async-generators@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.0.0.tgz#bf0891dcdbf59558359d0c626fdc9490e20bc13c" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-class-properties@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.0.0.tgz#e051af5d300cbfbcec4a7476e37a803489881634" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-decorators@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.1.0.tgz#2fa7c1a7905a299c9853ebcef340306675f9cbdc" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-json-strings@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.0.0.tgz#0d259a68090e15b383ce3710e01d5b23f3770cbd" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-object-rest-spread@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0.tgz#37d8fbcaf216bd658ea1aebbeb8b75e88ebc549b" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.0.0.tgz#886f72008b3a8b185977f7cb70713b45e51ee475" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-arrow-functions@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0.tgz#a6c14875848c68a3b4b3163a486535ef25c7e749" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-async-to-generator@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.1.0.tgz#109e036496c51dd65857e16acab3bafdf3c57811" + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.1.0" + +"@babel/plugin-transform-block-scoped-functions@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0.tgz#482b3f75103927e37288b3b67b65f848e2aa0d07" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-block-scoping@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.0.0.tgz#1745075edffd7cdaf69fab2fb6f9694424b7e9bc" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + lodash "^4.17.10" + +"@babel/plugin-transform-classes@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.1.0.tgz#ab3f8a564361800cbc8ab1ca6f21108038432249" + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-define-map" "^7.1.0" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0.tgz#2fbb8900cd3e8258f2a2ede909b90e7556185e31" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-destructuring@^7.0.0": + version "7.1.3" + resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.1.3.tgz#e69ff50ca01fac6cb72863c544e516c2b193012f" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-dotall-regex@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.0.0.tgz#73a24da69bc3c370251f43a3d048198546115e58" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + regexpu-core "^4.1.3" + +"@babel/plugin-transform-duplicate-keys@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0.tgz#a0601e580991e7cace080e4cf919cfd58da74e86" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-exponentiation-operator@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.1.0.tgz#9c34c2ee7fd77e02779cfa37e403a2e1003ccc73" + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-for-of@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0.tgz#f2ba4eadb83bd17dc3c7e9b30f4707365e1c3e39" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-function-name@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.1.0.tgz#29c5550d5c46208e7f730516d41eeddd4affadbb" + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-literals@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0.tgz#2aec1d29cdd24c407359c930cdd89e914ee8ff86" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-modules-amd@^7.0.0", "@babel/plugin-transform-modules-amd@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.1.0.tgz#f9e0a7072c12e296079b5a59f408ff5b97bf86a8" + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-modules-commonjs@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.1.0.tgz#0a9d86451cbbfb29bd15186306897c67f6f9a05c" + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-simple-access" "^7.1.0" + +"@babel/plugin-transform-modules-systemjs@^7.0.0": + version "7.1.3" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.1.3.tgz#2119a3e3db612fd74a19d88652efbfe9613a5db0" + dependencies: + "@babel/helper-hoist-variables" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-modules-umd@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.1.0.tgz#a29a7d85d6f28c3561c33964442257cc6a21f2a8" + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-new-target@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz#ae8fbd89517fa7892d20e6564e641e8770c3aa4a" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-object-super@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.1.0.tgz#b1ae194a054b826d8d4ba7ca91486d4ada0f91bb" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.1.0" + +"@babel/plugin-transform-parameters@^7.1.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.1.0.tgz#44f492f9d618c9124026e62301c296bf606a7aed" + dependencies: + "@babel/helper-call-delegate" "^7.1.0" + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-regenerator@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz#5b41686b4ed40bef874d7ed6a84bdd849c13e0c1" + dependencies: + regenerator-transform "^0.13.3" + +"@babel/plugin-transform-shorthand-properties@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0.tgz#85f8af592dcc07647541a0350e8c95c7bf419d15" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-spread@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0.tgz#93583ce48dd8c85e53f3a46056c856e4af30b49b" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-sticky-regex@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0.tgz#30a9d64ac2ab46eec087b8530535becd90e73366" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + +"@babel/plugin-transform-template-literals@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0.tgz#084f1952efe5b153ddae69eb8945f882c7a97c65" + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-typeof-symbol@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0.tgz#4dcf1e52e943e5267b7313bff347fdbe0f81cec9" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-unicode-regex@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0.tgz#c6780e5b1863a76fe792d90eded9fcd5b51d68fc" + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-regex" "^7.0.0" + regexpu-core "^4.1.3" + +"@babel/polyfill@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.0.0.tgz#c8ff65c9ec3be6a1ba10113ebd40e8750fb90bff" + dependencies: + core-js "^2.5.7" + regenerator-runtime "^0.11.1" + +"@babel/preset-env@^7.0.0": + version "7.1.0" + resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.1.0.tgz#e67ea5b0441cfeab1d6f41e9b5c79798800e8d11" + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-async-generator-functions" "^7.1.0" + "@babel/plugin-proposal-json-strings" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.0.0" + "@babel/plugin-syntax-async-generators" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.0.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.0.0" + "@babel/plugin-transform-arrow-functions" "^7.0.0" + "@babel/plugin-transform-async-to-generator" "^7.1.0" + "@babel/plugin-transform-block-scoped-functions" "^7.0.0" + "@babel/plugin-transform-block-scoping" "^7.0.0" + "@babel/plugin-transform-classes" "^7.1.0" + "@babel/plugin-transform-computed-properties" "^7.0.0" + "@babel/plugin-transform-destructuring" "^7.0.0" + "@babel/plugin-transform-dotall-regex" "^7.0.0" + "@babel/plugin-transform-duplicate-keys" "^7.0.0" + "@babel/plugin-transform-exponentiation-operator" "^7.1.0" + "@babel/plugin-transform-for-of" "^7.0.0" + "@babel/plugin-transform-function-name" "^7.1.0" + "@babel/plugin-transform-literals" "^7.0.0" + "@babel/plugin-transform-modules-amd" "^7.1.0" + "@babel/plugin-transform-modules-commonjs" "^7.1.0" + "@babel/plugin-transform-modules-systemjs" "^7.0.0" + "@babel/plugin-transform-modules-umd" "^7.1.0" + "@babel/plugin-transform-new-target" "^7.0.0" + "@babel/plugin-transform-object-super" "^7.1.0" + "@babel/plugin-transform-parameters" "^7.1.0" + "@babel/plugin-transform-regenerator" "^7.0.0" + "@babel/plugin-transform-shorthand-properties" "^7.0.0" + "@babel/plugin-transform-spread" "^7.0.0" + "@babel/plugin-transform-sticky-regex" "^7.0.0" + "@babel/plugin-transform-template-literals" "^7.0.0" + "@babel/plugin-transform-typeof-symbol" "^7.0.0" + "@babel/plugin-transform-unicode-regex" "^7.0.0" + browserslist "^4.1.0" + invariant "^2.2.2" + js-levenshtein "^1.1.3" + semver "^5.3.0" + +"@babel/template@^7.1.0", "@babel/template@^7.1.2": + version "7.1.2" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.1.2.tgz#090484a574fef5a2d2d7726a674eceda5c5b5644" + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.1.2" + "@babel/types" "^7.1.2" + +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0": + version "7.1.4" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.4.tgz#f4f83b93d649b4b2c91121a9087fa2fa949ec2b4" + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.1.3" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/parser" "^7.1.3" + "@babel/types" "^7.1.3" debug "^3.1.0" globals "^11.1.0" - invariant "^2.2.0" - lodash "^4.2.0" + lodash "^4.17.10" -"@babel/types@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" +"@babel/types@^7.0.0", "@babel/types@^7.1.2", "@babel/types@^7.1.3": + version "7.1.3" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.1.3.tgz#3a767004567060c2f40fca49a304712c525ee37d" dependencies: esutils "^2.0.2" - lodash "^4.2.0" + lodash "^4.17.10" to-fast-properties "^2.0.0" -"@ember-decorators/babel-transforms@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@ember-decorators/babel-transforms/-/babel-transforms-2.0.2.tgz#f73b4af32bc9aa2253cc8d2e72b984ab85e432db" +"@ember-decorators/babel-transforms@^2.1.2": + version "2.1.2" + resolved "https://registry.npmjs.org/@ember-decorators/babel-transforms/-/babel-transforms-2.1.2.tgz#b646e53ece7c18ae42cd03f320146cb1f26f4ebf" dependencies: + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-decorators" "^7.0.0" babel-plugin-transform-class-properties "^6.24.1" babel-plugin-transform-decorators-legacy "^1.3.4" - ember-cli-babel "^6.6.0" + ember-cli-babel-plugin-helpers "^1.0.0" ember-cli-version-checker "^2.1.0" -"@ember-decorators/component@^2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@ember-decorators/component/-/component-2.3.1.tgz#4e692c78f4ce69ba107759e5f8e2ed59c55dc232" +"@ember-decorators/component@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@ember-decorators/component/-/component-3.0.0.tgz#9f31cc4eac800bedebf69ef8e432519092cd0430" dependencies: - "@ember-decorators/utils" "^2.3.1" + "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" -"@ember-decorators/controller@^2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@ember-decorators/controller/-/controller-2.3.1.tgz#0b64320b037d413d5a351129fb1269e0b9f955f8" +"@ember-decorators/controller@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@ember-decorators/controller/-/controller-3.0.0.tgz#1f5b0e88f7456bc869775f70cd86a56cb690f301" dependencies: - "@ember-decorators/utils" "^2.3.1" + "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" -"@ember-decorators/data@^2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@ember-decorators/data/-/data-2.3.1.tgz#a2f28a56f0190217b863846808fbee9ec14c2fd9" +"@ember-decorators/data@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@ember-decorators/data/-/data-3.0.0.tgz#78c6cb8b9b14eeee4bfd265cd00c95dc09416420" dependencies: - "@ember-decorators/utils" "^2.3.1" + "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" -"@ember-decorators/object@^2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@ember-decorators/object/-/object-2.3.1.tgz#1886911154a58e1d5e5bd1be883249d05d52c918" +"@ember-decorators/object@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@ember-decorators/object/-/object-3.0.0.tgz#84c5d3e62d3b211ffd17a795c0c4a65c3fe52f8d" dependencies: - "@ember-decorators/utils" "^2.3.1" + "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" ember-compatibility-helpers "^1.0.0" -"@ember-decorators/service@^2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@ember-decorators/service/-/service-2.3.1.tgz#84734f22ba295929ba5d506971535358e9e2a432" +"@ember-decorators/service@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@ember-decorators/service/-/service-3.0.0.tgz#90fe410b8b2b80ad7227a85259e3a8c3852000a2" dependencies: - "@ember-decorators/utils" "^2.3.1" + "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" -"@ember-decorators/utils@^2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@ember-decorators/utils/-/utils-2.3.1.tgz#1da06a8f11062b0176dac5b427b27b4eabff3604" +"@ember-decorators/utils@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@ember-decorators/utils/-/utils-3.0.0.tgz#f8e82ead2c75a8eaf2cef5b1811ab54fcb28bcee" dependencies: + babel-plugin-debug-macros "^0.1.11" ember-cli-babel "^6.6.0" ember-compatibility-helpers "^1.0.0" -"@ember/ordered-set@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@ember/ordered-set/-/ordered-set-2.0.0.tgz#54f34aba3a1fb75b7c2912a39ab41a4a2e9d266d" +"@ember/ordered-set@^2.0.3": + version "2.0.3" + resolved "https://registry.npmjs.org/@ember/ordered-set/-/ordered-set-2.0.3.tgz#2ac1ca73b3bd116063cae814898832ef434a57f9" dependencies: ember-cli-babel "^6.16.0" - ember-compatibility-helpers "^1.0.0" + ember-compatibility-helpers "^1.1.1" -"@ember/test-helpers@^0.7.18": - version "0.7.25" - resolved "https://registry.yarnpkg.com/@ember/test-helpers/-/test-helpers-0.7.25.tgz#b4014c108b40ffaf74f3c4d5918800917541541d" +"@ember/test-helpers@^0.7.26": + version "0.7.27" + resolved "https://registry.npmjs.org/@ember/test-helpers/-/test-helpers-0.7.27.tgz#c622cabd0cbb95b34efc1e1b6274ab5a14edc138" dependencies: broccoli-funnel "^2.0.1" + ember-assign-polyfill "~2.4.0" ember-cli-babel "^6.12.0" ember-cli-htmlbars-inline-precompile "^1.0.0" @@ -177,10 +660,26 @@ version "9.6.23" resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.23.tgz#fc429962c1b75f32bd66214a3997f660e8434f0d" +"@types/tmp@^0.0.33": + version "0.0.33" + resolved "https://registry.npmjs.org/@types/tmp/-/tmp-0.0.33.tgz#1073c4bc824754ae3d10cfab88ab0237ba964e4d" + +"@xg-wang/whatwg-fetch@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@xg-wang/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#f7b222c012a238e7d6e89ed3d72a1e0edb58453d" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" +abbrev@~1.0.7: + version "1.0.9" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + +abortcontroller-polyfill@^1.1.9: + version "1.1.9" + resolved "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.1.9.tgz#9fefe359fda2e9e0932dc85e6106453ac393b2da" + accepts@~1.3.4, accepts@~1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" @@ -208,25 +707,23 @@ after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" -agent-base@2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" +ajv@^5.3.0: + version "5.5.2" + resolved "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" dependencies: - extend "~3.0.0" - semver "~5.0.1" - -ajv-keywords@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" -ajv@^6.0.1, ajv@^6.5.0: - version "6.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.2.tgz#678495f9b82f7cca6be248dd92f59bff5e1f4360" +ajv@^6.5.3: + version "6.5.4" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz#247d5274110db653706b550fcc2b797ca28cfc59" dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" - uri-js "^4.2.1" + uri-js "^4.2.2" align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" @@ -272,16 +769,21 @@ ansi-styles@^3.0.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +ansi@^0.3.0, ansi@~0.3.0, ansi@~0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz#0c42d4fb17160d5a9af1e484bace1c66922c1b21" + ansicolors@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" -anymatch@^1.3.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" - dependencies: - micromatch "^2.1.5" - normalize-path "^2.0.0" +ansicolors@~0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" + +ansistyles@~0.1.3: + version "0.1.3" + resolved "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" anymatch@^2.0.0: version "2.0.0" @@ -294,6 +796,21 @@ aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" +aproba@~1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + +archy@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + +are-we-there-yet@~1.0.0: + version "1.0.6" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.6.tgz#a2d28c93102aa6cc96245a26cb954de06ec53f0c" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.0 || ^1.1.13" + are-we-there-yet@~1.1.2: version "1.1.5" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" @@ -337,6 +854,13 @@ array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" +array-index@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/array-index/-/array-index-1.0.0.tgz#ec56a749ee103e4e08c790b9c353df16055b97f9" + dependencies: + debug "^2.2.0" + es6-symbol "^3.0.2" + array-to-error@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" @@ -373,14 +897,32 @@ arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" +asap@^2.0.0: + version "2.0.6" + resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + asn1@0.1.11: version "0.1.11" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + assert-plus@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + assertion-error@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" @@ -405,10 +947,6 @@ async-disk-cache@^1.2.1: rsvp "^3.0.18" username-sync "1.0.1" -async-each@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" - async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" @@ -420,11 +958,17 @@ async-promise-queue@^1.0.3, async-promise-queue@^1.0.4: async "^2.4.1" debug "^2.6.8" +async-some@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/async-some/-/async-some-1.0.2.tgz#4d8a81620d5958791b5b98f802d3207776e95509" + dependencies: + dezalgo "^1.0.2" + async@^1.4.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@^2.4.1: +async@^2.0.1, async@^2.4.1, async@^2.5.0: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" dependencies: @@ -438,6 +982,10 @@ async@~0.9.0: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + atob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" @@ -446,6 +994,18 @@ aws-sign2@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.8.0: + version "1.8.0" + resolved "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" + babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -478,14 +1038,14 @@ babel-core@^6.26.0: slash "^1.0.0" source-map "^0.5.7" -babel-eslint@^8.2.6: - version "8.2.6" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.6.tgz#6270d0c73205628067c0f7ae1693a9e797acefd9" +babel-eslint@^10.0.1: + version "10.0.1" + resolved "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz#919681dc099614cd7d31d45c8908695092a1faed" dependencies: - "@babel/code-frame" "7.0.0-beta.44" - "@babel/traverse" "7.0.0-beta.44" - "@babel/types" "7.0.0-beta.44" - babylon "7.0.0-beta.44" + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@babel/types" "^7.0.0" eslint-scope "3.7.1" eslint-visitor-keys "^1.0.0" @@ -621,6 +1181,12 @@ babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.11: dependencies: semver "^5.3.0" +babel-plugin-debug-macros@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0.tgz#0120ac20ce06ccc57bf493b667cf24b85c28da7a" + dependencies: + semver "^5.3.0" + babel-plugin-debug-macros@^0.2.0-beta.6: version "0.2.0-beta.6" resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0-beta.6.tgz#ecdf6e408d5c863ab21740d7ad7f43f027d2f912" @@ -633,18 +1199,37 @@ babel-plugin-ember-modules-api-polyfill@^2.3.2: dependencies: ember-rfc176-data "^0.3.0" +babel-plugin-ember-modules-api-polyfill@^2.5.0: + version "2.5.0" + resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.5.0.tgz#860aab9fecbf38c10d1fe0779c6979a854fff154" + dependencies: + ember-rfc176-data "^0.3.5" + babel-plugin-feature-flags@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" -babel-plugin-filter-imports@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-0.3.1.tgz#e7859b56886b175dd2616425d277b219e209ea8b" +babel-plugin-filter-imports@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/babel-plugin-filter-imports/-/babel-plugin-filter-imports-2.0.3.tgz#21f2773d0d74558986dd7af89f6f753d5fa92da3" + dependencies: + "@babel/types" "^7.0.0" + lodash "^4.17.11" babel-plugin-htmlbars-inline-precompile@^0.2.5: version "0.2.6" resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.6.tgz#c00b8a3f4b32ca04bf0f0d5169fcef3b5a66d69d" +babel-plugin-module-resolver@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.1.1.tgz#881cf67e3d4b8400d5eaaefc1be44d2dc1fe404f" + dependencies: + find-babel-config "^1.1.0" + glob "^7.1.2" + pkg-up "^2.0.0" + reselect "^3.0.1" + resolve "^1.4.0" + babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" @@ -702,7 +1287,7 @@ babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-es2015-block-scoping@^6.23.0, babel-plugin-transform-es2015-block-scoping@^6.26.0: +babel-plugin-transform-es2015-block-scoping@^6.23.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" dependencies: @@ -982,10 +1567,6 @@ babel6-plugin-strip-heimdall@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" -babylon@7.0.0-beta.44: - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" - babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" @@ -1034,20 +1615,28 @@ basic-auth@~2.0.0: dependencies: safe-buffer "5.1.1" +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + dependencies: + tweetnacl "^0.14.3" + better-assert@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" dependencies: callsite "1.0.0" -binary-extensions@^1.0.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" - "binaryextensions@1 || 2": version "2.1.1" resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" +bl@~1.0.0: + version "1.0.3" + resolved "http://registry.npmjs.org/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e" + dependencies: + readable-stream "~2.0.5" + blank-object@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" @@ -1056,6 +1645,12 @@ blob@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" +block-stream@*: + version "0.0.9" + resolved "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + bluebird@^3.1.1, bluebird@^3.4.6: version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" @@ -1075,6 +1670,21 @@ body-parser@1.18.2: raw-body "2.3.2" type-is "~1.6.15" +body-parser@1.18.3: + version "1.18.3" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "~1.6.3" + iconv-lite "0.4.23" + on-finished "~2.3.0" + qs "6.5.2" + raw-body "2.3.3" + type-is "~1.6.16" + body@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" @@ -1090,6 +1700,12 @@ boom@0.4.x: dependencies: hoek "0.9.x" +boom@2.x.x: + version "2.10.1" + resolved "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + bops@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/bops/-/bops-0.0.3.tgz#c5cbf6fea8be7401ca5ea6d1679e6c4e8b407c79" @@ -1143,29 +1759,12 @@ braces@^2.3.1: broccoli-amd-funnel@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/broccoli-amd-funnel/-/broccoli-amd-funnel-1.3.0.tgz#c4426b4fce976e44295bd74f34725f53bdeb08e3" + resolved "https://registry.npmjs.org/broccoli-amd-funnel/-/broccoli-amd-funnel-1.3.0.tgz#c4426b4fce976e44295bd74f34725f53bdeb08e3" dependencies: broccoli-plugin "^1.3.0" symlink-or-copy "^1.2.0" -broccoli-asset-rev@^2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/broccoli-asset-rev/-/broccoli-asset-rev-2.7.0.tgz#c73da1d97c4180366fa442a87624ca1b7fb99161" - dependencies: - broccoli-asset-rewrite "^1.1.0" - broccoli-filter "^1.2.2" - broccoli-persistent-filter "^1.4.3" - json-stable-stringify "^1.0.0" - minimatch "^3.0.4" - rsvp "^3.0.6" - -broccoli-asset-rewrite@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-asset-rewrite/-/broccoli-asset-rewrite-1.1.0.tgz#77a5da56157aa318c59113245e8bafb4617f8830" - dependencies: - broccoli-filter "^1.2.3" - -broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.4.5: +broccoli-babel-transpiler@^6.4.5: version "6.4.5" resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.4.5.tgz#caab4a3b18d2a819fdd56e1ac3a37e8164ad4272" dependencies: @@ -1182,7 +1781,7 @@ broccoli-babel-transpiler@^6.0.0, broccoli-babel-transpiler@^6.4.5: broccoli-babel-transpiler@^6.5.0: version "6.5.0" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.5.0.tgz#aa501a227b298a99742fdd0309b1eaad7124bba0" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.5.0.tgz#aa501a227b298a99742fdd0309b1eaad7124bba0" dependencies: babel-core "^6.26.0" broccoli-funnel "^2.0.1" @@ -1195,9 +1794,24 @@ broccoli-babel-transpiler@^6.5.0: rsvp "^4.8.2" workerpool "^2.3.0" -broccoli-builder@^0.18.8: +broccoli-babel-transpiler@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.0.0.tgz#bc9d0e93d70d9515b799144b54b0b958e88b6f19" + dependencies: + "@babel/core" "^7.0.0" + broccoli-funnel "^2.0.1" + broccoli-merge-trees "^3.0.0" + broccoli-persistent-filter "^1.4.3" + clone "^2.1.2" + hash-for-dep "^1.2.3" + heimdalljs-logger "^0.1.9" + json-stable-stringify "^1.0.1" + rsvp "^4.8.3" + workerpool "^2.3.1" + +broccoli-builder@^0.18.14: version "0.18.14" - resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.14.tgz#4b79e2f844de11a4e1b816c3f49c6df4776c312d" + resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.14.tgz#4b79e2f844de11a4e1b816c3f49c6df4776c312d" dependencies: broccoli-node-info "^1.1.0" heimdalljs "^0.2.0" @@ -1251,15 +1865,15 @@ broccoli-clean-css@^1.1.0: inline-source-map-comment "^1.0.5" json-stable-stringify "^1.0.0" -broccoli-concat@^3.2.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.4.0.tgz#1b7cd73995cbff170d958b3c81496e59313ed14f" +broccoli-concat@^3.5.1, broccoli-concat@^3.7.3: + version "3.7.3" + resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-3.7.3.tgz#0dca01311567ffb13180e6b4eb111824628e4885" dependencies: + broccoli-debug "^0.6.5" broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.3.0" - broccoli-stew "^1.5.0" ensure-posix-path "^1.0.2" - fast-sourcemap-concat "^1.3.1" + fast-sourcemap-concat "^1.4.0" find-index "^1.1.0" fs-extra "^4.0.3" fs-tree-diff "^0.5.7" @@ -1268,26 +1882,9 @@ broccoli-concat@^3.2.2: lodash.uniq "^4.2.0" walk-sync "^0.3.2" -broccoli-concat@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.5.1.tgz#25d5bff467e451a03ae2a93b3fc8701b3955a732" - dependencies: - broccoli-kitchen-sink-helpers "^0.3.1" - broccoli-plugin "^1.3.0" - broccoli-stew "^1.5.0" - ensure-posix-path "^1.0.2" - fast-sourcemap-concat "^1.3.1" - find-index "^1.1.0" - fs-extra "^4.0.3" - fs-tree-diff "^0.5.7" - lodash.merge "^4.3.1" - lodash.omit "^4.1.0" - lodash.uniq "^4.2.0" - walk-sync "^0.3.2" - -broccoli-config-loader@^1.0.0: +broccoli-config-loader@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/broccoli-config-loader/-/broccoli-config-loader-1.0.1.tgz#d10aaf8ebc0cb45c1da5baa82720e1d88d28c80a" + resolved "https://registry.npmjs.org/broccoli-config-loader/-/broccoli-config-loader-1.0.1.tgz#d10aaf8ebc0cb45c1da5baa82720e1d88d28c80a" dependencies: broccoli-caching-writer "^3.0.3" @@ -1300,7 +1897,7 @@ broccoli-config-replace@^1.1.2: debug "^2.2.0" fs-extra "^0.24.0" -broccoli-debug@^0.6.1, broccoli-debug@^0.6.3, broccoli-debug@^0.6.4: +broccoli-debug@^0.6.1, broccoli-debug@^0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/broccoli-debug/-/broccoli-debug-0.6.4.tgz#986eb3d2005e00e3bb91f9d0a10ab137210cd150" dependencies: @@ -1311,6 +1908,17 @@ broccoli-debug@^0.6.1, broccoli-debug@^0.6.3, broccoli-debug@^0.6.4: symlink-or-copy "^1.1.8" tree-sync "^1.2.2" +broccoli-debug@^0.6.5: + version "0.6.5" + resolved "https://registry.npmjs.org/broccoli-debug/-/broccoli-debug-0.6.5.tgz#164a5cdafd8936e525e702bf8f91f39d758e2e78" + dependencies: + broccoli-plugin "^1.2.1" + fs-tree-diff "^0.5.2" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + symlink-or-copy "^1.1.8" + tree-sync "^1.2.2" + broccoli-file-creator@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-1.2.0.tgz#27f1b25b1b00e7bb7bf3d5d7abed5f4d5388df4d" @@ -1325,7 +1933,7 @@ broccoli-file-creator@^2.1.1: broccoli-plugin "^1.1.0" mkdirp "^0.5.1" -broccoli-filter@^1.0.1, broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: +broccoli-filter@^1.0.1: version "1.3.0" resolved "https://registry.yarnpkg.com/broccoli-filter/-/broccoli-filter-1.3.0.tgz#71e3a8e32a17f309e12261919c5b1006d6766de6" dependencies: @@ -1343,7 +1951,7 @@ broccoli-funnel-reducer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" -broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1, broccoli-funnel@^1.1.0: +broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1: version "1.2.0" resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" dependencies: @@ -1394,7 +2002,7 @@ broccoli-kitchen-sink-helpers@^0.3.1: glob "^5.0.10" mkdirp "^0.5.1" -broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.1, broccoli-merge-trees@^1.2.1: +broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.1: version "1.2.4" resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" dependencies: @@ -1421,9 +2029,16 @@ broccoli-merge-trees@^3.0.0: broccoli-plugin "^1.3.0" merge-trees "^2.0.0" -broccoli-middleware@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-1.2.1.tgz#a21f255f8bfe5a21c2f0fbf2417addd9d24c9436" +broccoli-merge-trees@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-3.0.1.tgz#545dfe9f695cec43372b3ee7e63c7203713ea554" + dependencies: + broccoli-plugin "^1.3.0" + merge-trees "^2.0.0" + +broccoli-middleware@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-2.0.1.tgz#093314f13e52fad7fa8c4254a4e4a4560c857a65" dependencies: handlebars "^4.0.4" mime-types "^2.1.18" @@ -1501,10 +2116,6 @@ broccoli-rollup@^2.1.1: symlink-or-copy "^1.1.8" walk-sync "^0.3.1" -broccoli-slow-trees@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-2.0.0.tgz#9741afe992787add64aec7f7c8211dfcc058278d" - broccoli-slow-trees@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" @@ -1525,25 +2136,6 @@ broccoli-sri-hash@^2.1.0: sri-toolbox "^0.2.0" symlink-or-copy "^1.0.1" -broccoli-stew@^1.2.0, broccoli-stew@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-1.6.0.tgz#01f6d92806ed6679ddbe48d405066a0e164dfbef" - dependencies: - broccoli-debug "^0.6.1" - broccoli-funnel "^2.0.0" - broccoli-merge-trees "^2.0.0" - broccoli-persistent-filter "^1.1.6" - broccoli-plugin "^1.3.0" - chalk "^2.4.1" - debug "^3.1.0" - ensure-posix-path "^1.0.1" - fs-extra "^5.0.0" - minimatch "^3.0.4" - resolve "^1.8.1" - rsvp "^4.8.3" - symlink-or-copy "^1.2.0" - walk-sync "^0.3.0" - broccoli-stew@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-2.0.0.tgz#68f3d94f13b4a79aa15d582703574fb4c3215e50" @@ -1570,16 +2162,16 @@ broccoli-string-replace@^0.1.2: broccoli-persistent-filter "^1.1.5" minimatch "^3.0.3" -broccoli-test-helper@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/broccoli-test-helper/-/broccoli-test-helper-1.4.0.tgz#9c2f0529424d61536a68e410bf24e5a66b8f815c" +broccoli-test-helper@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/broccoli-test-helper/-/broccoli-test-helper-2.0.0.tgz#1cfbb76f7e856ad8df96d55ee2f5e0dddddf5d4f" dependencies: - broccoli "^1.1.0" + "@types/tmp" "^0.0.33" + broccoli "^2.0.0" fixturify "^0.3.2" - fs-tree-diff "^0.5.6" - mktemp "^0.4.0" - rimraf "^2.5.4" - walk-sync "^0.3.1" + fs-tree-diff "^0.5.9" + tmp "^0.0.33" + walk-sync "^0.3.3" broccoli-uglify-sourcemap@^2.1.1, broccoli-uglify-sourcemap@^2.2.0: version "2.2.0" @@ -1597,25 +2189,28 @@ broccoli-uglify-sourcemap@^2.1.1, broccoli-uglify-sourcemap@^2.2.0: walk-sync "^0.3.2" workerpool "^2.3.0" -broccoli@^1.1.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/broccoli/-/broccoli-1.1.4.tgz#b023b028b866f447ed14341007961efd03f7251c" +broccoli@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/broccoli/-/broccoli-2.0.0.tgz#7b95d6173865184697e4dab9f477591057b9410e" dependencies: broccoli-node-info "1.1.0" - broccoli-slow-trees "2.0.0" + broccoli-slow-trees "^3.0.1" broccoli-source "^1.1.0" - commander "^2.5.0" - connect "^3.3.3" - copy-dereference "^1.0.0" - findup-sync "^1.0.0" - handlebars "^4.0.4" - heimdalljs-logger "^0.1.7" - mime "^1.2.11" - rimraf "^2.4.3" - rsvp "^3.5.0" - sane "^1.4.1" - tmp "0.0.31" + commander "^2.15.1" + connect "^3.6.6" + findup-sync "^2.0.0" + handlebars "^4.0.11" + heimdalljs "^0.2.5" + heimdalljs-logger "^0.1.9" + mime-types "^2.1.19" + promise.prototype.finally "^3.1.0" + resolve-path "^1.4.0" + rimraf "^2.6.2" + sane "^4.0.0" + tmp "0.0.33" + tree-sync "^1.2.2" underscore.string "^3.2.2" + watch-detector "^0.1.0" browser-stdout@1.3.1: version "1.3.1" @@ -1628,12 +2223,35 @@ browserslist@^3.2.6: caniuse-lite "^1.0.30000844" electron-to-chromium "^1.3.47" +browserslist@^4.1.0: + version "4.3.3" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.3.3.tgz#88a7d9ce2e5db561e160ab660bc59cb406a0c41d" + dependencies: + caniuse-lite "^1.0.30000898" + electron-to-chromium "^1.3.81" + node-releases "^1.0.0-alpha.15" + bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" dependencies: node-int64 "^0.4.0" +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + buffer-from@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" @@ -1642,6 +2260,10 @@ builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" +builtins@0.0.7: + version "0.0.7" + resolved "https://registry.npmjs.org/builtins/-/builtins-0.0.7.tgz#355219cd6cf18dbe7c01cc7fd2dce765cfdc549a" + builtins@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" @@ -1680,7 +2302,7 @@ cacheable-request@^2.1.1: normalize-url "2.0.1" responselike "1.0.2" -calculate-cache-key-for-tree@^1.0.0, calculate-cache-key-for-tree@^1.1.0: +calculate-cache-key-for-tree@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" dependencies: @@ -1725,7 +2347,11 @@ caniuse-lite@^1.0.30000844: version "1.0.30000865" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000865.tgz#70026616e8afe6e1442f8bb4e1092987d81a2f25" -capture-exit@^1.1.0, capture-exit@^1.2.0: +caniuse-lite@^1.0.30000898: + version "1.0.30000899" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000899.tgz#6febdbbc388a7982f620ee0e3d09aab0c061389e" + +capture-exit@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" dependencies: @@ -1742,6 +2368,14 @@ cardinal@^1.0.0: ansicolors "~0.2.1" redeyed "~1.0.0" +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + center-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" @@ -1804,9 +2438,9 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4 escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chardet@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" charm@^1.0.0: version "1.0.2" @@ -1818,28 +2452,13 @@ check-error@^1.0.1, check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" -chokidar@1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" - dependencies: - anymatch "^1.3.0" - async-each "^1.0.0" - glob-parent "^2.0.0" - inherits "^2.0.1" - is-binary-path "^1.0.0" - is-glob "^2.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.0.0" - optionalDependencies: - fsevents "^1.0.0" - -chownr@^1.0.1: +chownr@^1.0.1, chownr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" -ci-info@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" +ci-info@^1.1.3: + version "1.6.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" circular-json@^0.3.1: version "0.3.3" @@ -1893,12 +2512,12 @@ cli-spinners@^1.1.0: version "1.3.1" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" -cli-table2@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/cli-table2/-/cli-table2-0.2.0.tgz#2d1ef7f218a0e786e214540562d4bd177fe32d97" +cli-table3@^0.5.1: + version "0.5.1" + resolved "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" dependencies: - lodash "^3.10.1" - string-width "^1.0.1" + object-assign "^4.1.0" + string-width "^2.1.1" optionalDependencies: colors "^1.1.2" @@ -1934,6 +2553,17 @@ clone@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" +clone@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + +cmd-shim@~2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb" + dependencies: + graceful-fs "^4.1.2" + mkdirp "~0.5.0" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -1967,6 +2597,19 @@ colors@^1.1.2: version "1.3.1" resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.1.tgz#4accdb89cf2cabc7f982771925e9468784f32f3d" +columnify@~1.5.4: + version "1.5.4" + resolved "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" + dependencies: + strip-ansi "^3.0.0" + wcwidth "^1.0.0" + +combined-stream@^1.0.5, combined-stream@^1.0.6, combined-stream@~1.0.5, combined-stream@~1.0.6: + version "1.0.7" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" + dependencies: + delayed-stream "~1.0.0" + combined-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" @@ -1987,10 +2630,18 @@ commander@2.8.x: dependencies: graceful-readlink ">= 1.0.0" -commander@^2.5.0, commander@^2.6.0, commander@~2.16.0: +commander@^2.15.1, commander@^2.9.0: + version "2.19.0" + resolved "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" + +commander@^2.6.0, commander@~2.16.0: version "2.16.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" +commander@~2.17.1: + version "2.17.1" + resolved "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + common-tags@^1.4.0, common-tags@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" @@ -2013,9 +2664,9 @@ compressible@~2.0.14: dependencies: mime-db ">= 1.34.0 < 2" -compression@^1.4.4: +compression@^1.7.3: version "1.7.3" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" + resolved "https://registry.npmjs.org/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" dependencies: accepts "~1.3.5" bytes "3.0.0" @@ -2029,7 +2680,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.7: +concat-stream@^1.4.6, concat-stream@^1.4.7: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" dependencies: @@ -2038,9 +2689,16 @@ concat-stream@^1.4.7: readable-stream "^2.2.2" typedarray "^0.0.6" -configstore@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" +config-chain@~1.1.9: + version "1.1.12" + resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +configstore@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz#5933311e95d3687efb592c528b922d9262d227e7" dependencies: dot-prop "^4.1.0" graceful-fs "^4.1.2" @@ -2049,7 +2707,7 @@ configstore@^3.0.0: write-file-atomic "^2.0.0" xdg-basedir "^3.0.0" -connect@^3.3.3: +connect@^3.6.6: version "3.6.6" resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" dependencies: @@ -2091,6 +2749,12 @@ continuable-cache@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" +convert-source-map@^1.1.0: + version "1.6.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" + dependencies: + safe-buffer "~5.1.1" + convert-source-map@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" @@ -2111,17 +2775,17 @@ copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" -core-js@^2.4.0, core-js@^2.5.0: +core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.7: version "2.5.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" -core-object@^3.1.3, core-object@^3.1.5: +core-object@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/core-object/-/core-object-3.1.5.tgz#fa627b87502adc98045e44678e9a8ec3b9c0d2a9" dependencies: chalk "^2.0.0" -core-util-is@~1.0.0: +core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -2147,6 +2811,12 @@ cryptiles@0.2.x: dependencies: boom "0.4.x" +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" @@ -2171,13 +2841,19 @@ dag-map@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + date-time@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/date-time/-/date-time-2.1.0.tgz#0286d1b4c769633b3ca13e1e62558d2dbdc2eba2" dependencies: time-zone "^1.0.0" -debug@2, debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: +debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -2189,6 +2865,16 @@ debug@3.1.0, debug@^3.0.0, debug@^3.1.0, debug@~3.1.0: dependencies: ms "2.0.0" +debug@^4.0.1: + version "4.1.0" + resolved "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" + dependencies: + ms "^2.1.1" + +debuglog@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" + decamelize@^1.0.0, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -2271,6 +2957,10 @@ delayed-stream@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -2287,12 +2977,6 @@ destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" -detect-file@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" - dependencies: - fs-exists-sync "^0.1.0" - detect-file@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" @@ -2311,9 +2995,16 @@ detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" -diff@3.5.0, diff@^3.2.0: +dezalgo@^1.0.0, dezalgo@^1.0.1, dezalgo@^1.0.2, dezalgo@~1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + dependencies: + asap "^2.0.0" + wrappy "1" + +diff@3.5.0, diff@^3.5.0: version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" doctrine@^2.1.0: version "2.1.0" @@ -2335,10 +3026,21 @@ duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + editions@^1.1.1: version "1.3.4" resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" +editor@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -2347,6 +3049,17 @@ electron-to-chromium@^1.3.47: version "1.3.52" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz#d2d9f1270ba4a3b967b831c40ef71fb4d9ab5ce0" +electron-to-chromium@^1.3.81: + version "1.3.82" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.82.tgz#7d13ae4437d2a783de3f4efba96b186c540b67b1" + +ember-assign-polyfill@~2.4.0: + version "2.4.0" + resolved "https://registry.npmjs.org/ember-assign-polyfill/-/ember-assign-polyfill-2.4.0.tgz#acb00466f7d674b3e6b030acfe255b3b1f6472e1" + dependencies: + ember-cli-babel "^6.6.0" + ember-cli-version-checker "^2.0.0" + ember-cli-app-version@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-3.2.0.tgz#7b9ad0e1b63ae0518648356ee24c703e922bc26e" @@ -2354,22 +3067,47 @@ ember-cli-app-version@^3.2.0: ember-cli-babel "^6.12.0" git-repo-version "^1.0.2" +ember-cli-babel-plugin-helpers@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/ember-cli-babel-plugin-helpers/-/ember-cli-babel-plugin-helpers-1.0.2.tgz#d4bec0f32febc530e621ea8d66d3365727cb5e6c" + ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: version "6.16.0" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.16.0.tgz#623b4a2764ece72b65f1572fc8aeb5714a450228" dependencies: amd-name-resolver "1.2.0" babel-plugin-debug-macros "^0.2.0-beta.6" - babel-plugin-ember-modules-api-polyfill "^2.3.2" - babel-plugin-transform-es2015-modules-amd "^6.24.0" - babel-polyfill "^6.26.0" - babel-preset-env "^1.7.0" - broccoli-babel-transpiler "^6.4.5" + babel-plugin-ember-modules-api-polyfill "^2.3.2" + babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-polyfill "^6.26.0" + babel-preset-env "^1.7.0" + broccoli-babel-transpiler "^6.4.5" + broccoli-debug "^0.6.4" + broccoli-funnel "^2.0.0" + broccoli-source "^1.1.0" + clone "^2.0.0" + ember-cli-version-checker "^2.1.2" + semver "^5.5.0" + +ember-cli-babel@^7.1.2: + version "7.1.2" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-7.1.2.tgz#543c64368d6138d12656db1143c02df1f2b0ee9c" + dependencies: + "@babel/core" "^7.0.0" + "@babel/plugin-transform-modules-amd" "^7.0.0" + "@babel/polyfill" "^7.0.0" + "@babel/preset-env" "^7.0.0" + amd-name-resolver "1.2.0" + babel-plugin-debug-macros "^0.2.0-beta.6" + babel-plugin-ember-modules-api-polyfill "^2.5.0" + babel-plugin-module-resolver "^3.1.1" + broccoli-babel-transpiler "^7.0.0" broccoli-debug "^0.6.4" - broccoli-funnel "^2.0.0" + broccoli-funnel "^2.0.1" broccoli-source "^1.1.0" - clone "^2.0.0" + clone "^2.1.2" ember-cli-version-checker "^2.1.2" + ensure-posix-path "^1.0.2" semver "^5.5.0" ember-cli-blueprint-test-helpers@^0.19.1: @@ -2385,9 +3123,9 @@ ember-cli-blueprint-test-helpers@^0.19.1: testdouble "^3.2.6" tmp-sync "^1.0.0" -ember-cli-broccoli-sane-watcher@^2.0.4: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.1.1.tgz#1687adada9022de26053fba833dc7dd10f03dd08" +ember-cli-broccoli-sane-watcher@^2.1.1: + version "2.2.2" + resolved "https://registry.npmjs.org/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.2.2.tgz#9bb1b04ddeb2c086aecd8693cbaeca1d88dc160c" dependencies: broccoli-slow-trees "^3.0.1" heimdalljs "^0.2.1" @@ -2409,7 +3147,7 @@ ember-cli-get-component-path-option@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" -ember-cli-htmlbars-inline-precompile@^1.0.0, ember-cli-htmlbars-inline-precompile@^1.0.3: +ember-cli-htmlbars-inline-precompile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.3.tgz#332ff96c06fc522965162f1090d78a615379c3c2" dependencies: @@ -2419,20 +3157,31 @@ ember-cli-htmlbars-inline-precompile@^1.0.0, ember-cli-htmlbars-inline-precompil heimdalljs-logger "^0.1.9" silent-error "^1.1.0" -ember-cli-htmlbars@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-3.0.0.tgz#4977b9eddbc725f8da25090ecdbba64533b2eadc" +ember-cli-htmlbars-inline-precompile@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.5.tgz#312e050c9e3dd301c55fb399fd706296cd0b1d6a" + dependencies: + babel-plugin-htmlbars-inline-precompile "^0.2.5" + ember-cli-version-checker "^2.1.2" + hash-for-dep "^1.2.3" + heimdalljs-logger "^0.1.9" + silent-error "^1.1.0" + +ember-cli-htmlbars@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-3.0.1.tgz#01e21f0fd05e0a6489154f26614b1041769e3e58" dependencies: broccoli-persistent-filter "^1.4.3" hash-for-dep "^1.2.3" json-stable-stringify "^1.0.0" strip-bom "^3.0.0" -ember-cli-inject-live-reload@^1.8.2: - version "1.8.2" - resolved "https://registry.yarnpkg.com/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-1.8.2.tgz#29f875ad921e9a1dec65d2d75018891972d240bc" +ember-cli-inject-live-reload@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-2.0.1.tgz#1bf3a6ea1747bceddc9f62f7ca8575de6b53ddaf" dependencies: clean-base-url "^1.0.0" + ember-cli-version-checker "^2.1.2" ember-cli-internal-test-helpers@^0.9.1: version "0.9.1" @@ -2473,9 +3222,9 @@ ember-cli-path-utils@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" -ember-cli-preprocess-registry@^3.1.0: +ember-cli-preprocess-registry@^3.1.2: version "3.1.2" - resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.2.tgz#083efb21fd922c021ceba9e08f4d9278249fc4db" + resolved "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.2.tgz#083efb21fd922c021ceba9e08f4d9278249fc4db" dependencies: broccoli-clean-css "^1.1.0" broccoli-funnel "^1.0.0" @@ -2485,18 +3234,23 @@ ember-cli-preprocess-registry@^3.1.0: process-relative-require "^1.0.0" silent-error "^1.0.0" -ember-cli-pretender@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ember-cli-pretender/-/ember-cli-pretender-1.0.1.tgz#35540babddef6f2778e91c627d190c73505103cd" +ember-cli-pretender@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-3.0.0.tgz#dcaf772332a1e6b0fc91e4b9a7e793a1283c85ac" dependencies: - broccoli-funnel "^1.1.0" - broccoli-merge-trees "^1.2.1" - pretender "^1.4.2" + "@xg-wang/whatwg-fetch" "^3.0.0" + abortcontroller-polyfill "^1.1.9" + broccoli-funnel "^2.0.1" + broccoli-merge-trees "^3.0.0" + ember-cli-babel "^6.6.0" + fake-xml-http-request "^2.0.0" + pretender "^2.1.0" resolve "^1.2.0" + route-recognizer "^0.3.3" -ember-cli-release@^0.2.9: - version "0.2.9" - resolved "https://registry.yarnpkg.com/ember-cli-release/-/ember-cli-release-0.2.9.tgz#5e8de3d034c65597933748023058470ec1231adb" +ember-cli-release@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.npmjs.org/ember-cli-release/-/ember-cli-release-1.0.0-beta.2.tgz#cb72d341293e94a1a8bcf4b73f7a6396f5b7e0c5" dependencies: chalk "^1.0.0" git-tools "^0.1.4" @@ -2504,6 +3258,8 @@ ember-cli-release@^0.2.9: merge "^1.2.0" moment-timezone "^0.3.0" nopt "^3.0.3" + npm "~3.5.2" + require-dir "^0.3.0" rsvp "^3.0.17" semver "^4.3.1" silent-error "^1.0.0" @@ -2570,94 +3326,95 @@ ember-cli-yuidoc@^0.8.8: rsvp "3.0.14" yuidocjs "^0.10.0" -ember-cli@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-3.3.0.tgz#534ebe72453a4fb064a34077a0874ad69ea84be4" +ember-cli@~3.4.3: + version "3.4.3" + resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-3.4.3.tgz#33560c6416612bd8dc56858cffb2c81897ec8822" dependencies: amd-name-resolver "^1.2.0" - babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-plugin-transform-es2015-modules-amd "^6.24.1" bower-config "^1.3.0" bower-endpoint-parser "0.2.2" broccoli-amd-funnel "^1.3.0" - broccoli-babel-transpiler "^6.0.0" - broccoli-builder "^0.18.8" - broccoli-concat "^3.2.2" - broccoli-config-loader "^1.0.0" + broccoli-babel-transpiler "^6.5.0" + broccoli-builder "^0.18.14" + broccoli-concat "^3.5.1" + broccoli-config-loader "^1.0.1" broccoli-config-replace "^1.1.2" - broccoli-debug "^0.6.3" - broccoli-funnel "^2.0.0" + broccoli-debug "^0.6.4" + broccoli-funnel "^2.0.1" broccoli-funnel-reducer "^1.0.0" - broccoli-merge-trees "^2.0.0" - broccoli-middleware "^1.2.1" + broccoli-merge-trees "^3.0.0" + broccoli-middleware "^2.0.1" broccoli-module-normalizer "^1.3.0" broccoli-module-unification-reexporter "^1.0.0" broccoli-source "^1.1.0" - broccoli-stew "^1.2.0" - calculate-cache-key-for-tree "^1.0.0" - capture-exit "^1.1.0" - chalk "^2.0.1" - ci-info "^1.1.2" + broccoli-stew "^2.0.0" + calculate-cache-key-for-tree "^1.1.0" + capture-exit "^1.2.0" + chalk "^2.4.1" + ci-info "^1.1.3" clean-base-url "^1.0.0" - compression "^1.4.4" - configstore "^3.0.0" + compression "^1.7.3" + configstore "^4.0.0" console-ui "^2.2.2" - core-object "^3.1.3" + core-object "^3.1.5" dag-map "^2.0.2" - diff "^3.2.0" - ember-cli-broccoli-sane-watcher "^2.0.4" + diff "^3.5.0" + ember-cli-broccoli-sane-watcher "^2.1.1" ember-cli-is-package-missing "^1.0.0" ember-cli-lodash-subset "^2.0.1" ember-cli-normalize-entity-name "^1.0.0" - ember-cli-preprocess-registry "^3.1.0" - ember-cli-string-utils "^1.0.0" + ember-cli-preprocess-registry "^3.1.2" + ember-cli-string-utils "^1.1.0" ensure-posix-path "^1.0.2" execa "^0.10.0" exit "^0.1.2" - express "^4.12.3" - filesize "^3.1.3" - find-up "^2.1.0" - find-yarn-workspace-root "^1.0.0" - fs-extra "^5.0.0" - fs-tree-diff "^0.5.2" + express "^4.16.3" + filesize "^3.6.1" + find-up "^3.0.0" + find-yarn-workspace-root "^1.1.0" + fixturify-project "^1.5.3" + fs-extra "^7.0.0" + fs-tree-diff "^0.5.7" get-caller-file "^1.0.0" git-repo-info "^2.0.0" glob "^7.1.2" - heimdalljs "^0.2.3" - heimdalljs-fs-monitor "^0.2.0" - heimdalljs-graph "^0.3.1" - heimdalljs-logger "^0.1.7" - http-proxy "^1.9.0" - inflection "^1.7.0" + heimdalljs "^0.2.5" + heimdalljs-fs-monitor "^0.2.2" + heimdalljs-graph "^0.3.4" + heimdalljs-logger "^0.1.9" + http-proxy "^1.17.0" + inflection "^1.12.0" is-git-url "^1.0.0" - isbinaryfile "^3.0.0" - js-yaml "^3.6.1" + isbinaryfile "^3.0.3" + js-yaml "^3.12.0" json-stable-stringify "^1.0.1" leek "0.0.24" - lodash.template "^4.2.5" - markdown-it "^8.3.0" + lodash.template "^4.4.0" + markdown-it "^8.4.2" markdown-it-terminal "0.1.0" - minimatch "^3.0.0" - morgan "^1.8.1" - node-modules-path "^1.0.0" + minimatch "^3.0.4" + morgan "^1.9.0" + node-modules-path "^1.0.1" nopt "^3.0.6" - npm-package-arg "^6.0.0" - portfinder "^1.0.7" - promise-map-series "^0.2.1" + npm-package-arg "^6.1.0" + portfinder "^1.0.15" + promise-map-series "^0.2.3" quick-temp "^0.1.8" - resolve "^1.3.0" - rsvp "^4.7.0" - sane "^2.2.0" - semver "^5.1.1" - silent-error "^1.0.0" - sort-package-json "^1.4.0" + resolve "^1.8.1" + rsvp "^4.8.3" + sane "^3.0.0" + semver "^5.5.0" + silent-error "^1.1.0" + sort-package-json "^1.15.0" symlink-or-copy "^1.2.0" temp "0.8.3" - testem "^2.2.0" - tiny-lr "^1.0.3" - tree-sync "^1.2.1" - uuid "^3.0.0" + testem "^2.9.2" + tiny-lr "^1.1.1" + tree-sync "^1.2.2" + uuid "^3.3.2" validate-npm-package-name "^3.0.0" - walk-sync "^0.3.0" + walk-sync "^0.3.2" watch-detector "^0.1.0" yam "^0.0.24" @@ -2669,15 +3426,23 @@ ember-compatibility-helpers@^1.0.0: ember-cli-version-checker "^2.1.1" semver "^5.4.1" -ember-decorators@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/ember-decorators/-/ember-decorators-2.3.1.tgz#aef98f6a3e15666bd414576d07cbfc15d39cfe97" +ember-compatibility-helpers@^1.1.1: + version "1.1.2" + resolved "https://registry.npmjs.org/ember-compatibility-helpers/-/ember-compatibility-helpers-1.1.2.tgz#ae0ee4a7a2858b5ffdf79b428c23aee85c47d93d" dependencies: - "@ember-decorators/component" "^2.3.1" - "@ember-decorators/controller" "^2.3.1" - "@ember-decorators/data" "^2.3.1" - "@ember-decorators/object" "^2.3.1" - "@ember-decorators/service" "^2.3.1" + babel-plugin-debug-macros "^0.2.0" + ember-cli-version-checker "^2.1.1" + semver "^5.4.1" + +ember-decorators@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/ember-decorators/-/ember-decorators-3.0.0.tgz#23cee0ebea3f86806cd15b638bf5ffb40870ccf4" + dependencies: + "@ember-decorators/component" "^3.0.0" + "@ember-decorators/controller" "^3.0.0" + "@ember-decorators/data" "^3.0.0" + "@ember-decorators/object" "^3.0.0" + "@ember-decorators/service" "^3.0.0" ember-cli-babel "^6.0.0" semver "^5.5.0" @@ -2719,17 +3484,17 @@ ember-qunit-assert-helpers@^0.2.1: broccoli-filter "^1.0.1" ember-cli-babel "^6.9.0" -ember-qunit@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-3.4.1.tgz#204a2d39a5d44d494c56bf17cf3fd12f06210359" +ember-qunit@^3.5.3: + version "3.5.3" + resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-3.5.3.tgz#bfd0bff8298c78c77e870cca43fe0826e78a0d09" dependencies: - "@ember/test-helpers" "^0.7.18" + "@ember/test-helpers" "^0.7.26" broccoli-funnel "^2.0.1" broccoli-merge-trees "^2.0.0" common-tags "^1.4.0" ember-cli-babel "^6.8.2" ember-cli-test-loader "^2.2.0" - qunit "^2.5.0" + qunit "~2.6.0" ember-resolver@^5.0.1: version "5.0.1" @@ -2747,6 +3512,10 @@ ember-rfc176-data@^0.3.0, ember-rfc176-data@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.3.tgz#27fba08d540a7463a4366c48eaa19c5a44971a39" +ember-rfc176-data@^0.3.5: + version "0.3.5" + resolved "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.3.5.tgz#f630e550572c81a5e5c7220f864c0f06eee9e977" + ember-router-generator@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" @@ -2789,22 +3558,23 @@ ember-try-config@^3.0.0: rsvp "^4.8.1" semver "^5.5.0" -ember-try@^1.0.0-beta.3: - version "1.0.0-beta.3" - resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-1.0.0-beta.3.tgz#04da09ba2d57f0fe3a7174acff0dc1add2760855" +ember-try@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/ember-try/-/ember-try-1.1.0.tgz#194d5843a79b5a9fc0e4c07445ebc18c08a91e78" dependencies: chalk "^2.3.0" - cli-table2 "^0.2.0" + cli-table3 "^0.5.1" core-object "^3.1.5" debug "^3.1.0" ember-try-config "^3.0.0" - execa "^0.10.0" + execa "^1.0.0" extend "^3.0.0" fs-extra "^5.0.0" promise-map-series "^0.2.1" resolve "^1.1.6" rimraf "^2.3.2" rsvp "^4.7.0" + walk-sync "^0.3.3" emit-function@0.0.2: version "0.0.2" @@ -2814,6 +3584,12 @@ encodeurl@~1.0.1, encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" +end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + dependencies: + once "^1.4.0" + engine.io-client@~3.2.0: version "3.2.1" resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" @@ -2872,9 +3648,9 @@ error@^7.0.0: string-template "~0.2.1" xtend "~4.0.0" -es-abstract@^1.10.0: +es-abstract@^1.9.0: version "1.12.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" dependencies: es-to-primitive "^1.1.1" function-bind "^1.1.1" @@ -2927,7 +3703,7 @@ es6-set@~0.1.5: es6-symbol "3.1.1" event-emitter "~0.3.5" -es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: +es6-symbol@3.1.1, es6-symbol@^3.0.2, es6-symbol@^3.1.1, es6-symbol@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" dependencies: @@ -2942,11 +3718,11 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1 version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -eslint-config-prettier@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" +eslint-config-prettier@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-3.1.0.tgz#2c26d2cdcfa3a05f0642cd7e6e4ef3316cdabfa2" dependencies: - get-stdin "^5.0.1" + get-stdin "^6.0.0" eslint-plugin-es@^1.3.1: version "1.3.1" @@ -2966,12 +3742,11 @@ eslint-plugin-node@^7.0.1: resolve "^1.8.1" semver "^5.5.0" -eslint-plugin-prettier@2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.2.tgz#71998c60aedfa2141f7bfcbf9d1c459bf98b4fad" +eslint-plugin-prettier@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.0.tgz#f6b823e065f8c36529918cdb766d7a0e975ec30c" dependencies: - fast-diff "^1.1.1" - jest-docblock "^21.0.0" + prettier-linter-helpers "^1.0.0" eslint-scope@3.7.1: version "3.7.1" @@ -2995,15 +3770,15 @@ eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.3.0.tgz#53695aca5213968aacdf970ccb231e42a2b285f8" +eslint@^5.7.0: + version "5.7.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-5.7.0.tgz#55c326d6fb2ad45fcbd0ce17c3846f025d1d819c" dependencies: - ajv "^6.5.0" - babel-code-frame "^6.26.0" + "@babel/code-frame" "^7.0.0" + ajv "^6.5.3" chalk "^2.1.0" cross-spawn "^6.0.5" - debug "^3.1.0" + debug "^4.0.1" doctrine "^2.1.0" eslint-scope "^4.0.0" eslint-utils "^1.3.1" @@ -3015,11 +3790,11 @@ eslint@^5.3.0: functional-red-black-tree "^1.0.1" glob "^7.1.2" globals "^11.7.0" - ignore "^4.0.2" + ignore "^4.0.6" imurmurhash "^0.1.4" - inquirer "^5.2.0" + inquirer "^6.1.0" is-resolvable "^1.1.0" - js-yaml "^3.11.0" + js-yaml "^3.12.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" lodash "^4.17.5" @@ -3030,13 +3805,12 @@ eslint@^5.3.0: path-is-inside "^1.0.2" pluralize "^7.0.0" progress "^2.0.0" - regexpp "^2.0.0" + regexpp "^2.0.1" require-uncached "^1.0.3" - semver "^5.5.0" - string.prototype.matchall "^2.0.0" + semver "^5.5.1" strip-ansi "^4.0.0" strip-json-comments "^2.0.1" - table "^4.0.3" + table "^5.0.2" text-table "^0.2.0" espree@^4.0.0: @@ -3131,6 +3905,18 @@ execa@^0.10.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + exists-stat@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/exists-stat/-/exists-stat-1.0.0.tgz#0660e3525a2e89d9e446129440c272edfa24b529" @@ -3175,19 +3961,13 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" -expand-tilde@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" - dependencies: - os-homedir "^1.0.1" - expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" dependencies: homedir-polyfill "^1.0.1" -express@^4.10.7, express@^4.12.3, express@^4.13.1: +express@^4.10.7, express@^4.13.1: version "4.16.3" resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" dependencies: @@ -3222,6 +4002,41 @@ express@^4.10.7, express@^4.12.3, express@^4.13.1: utils-merge "1.0.1" vary "~1.1.2" +express@^4.16.3: + version "4.16.4" + resolved "https://registry.npmjs.org/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" + dependencies: + accepts "~1.3.5" + array-flatten "1.1.1" + body-parser "1.18.3" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.1.1" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.4" + qs "6.5.2" + range-parser "~1.2.0" + safe-buffer "5.1.2" + send "0.16.2" + serve-static "1.13.2" + setprototypeof "1.1.0" + statuses "~1.4.0" + type-is "~1.6.16" + utils-merge "1.0.1" + vary "~1.1.2" + extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -3235,7 +4050,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@3, extend@^3.0.0, extend@~3.0.0: +extend@^3.0.0, extend@~3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -3247,12 +4062,12 @@ external-editor@^1.1.0: spawn-sync "^1.0.15" tmp "^0.0.29" -external-editor@^2.1.0: - version "2.2.0" - resolved "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" +external-editor@^3.0.0: + version "3.0.3" + resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" dependencies: - chardet "^0.4.0" - iconv-lite "^0.4.17" + chardet "^0.7.0" + iconv-lite "^0.4.24" tmp "^0.0.33" extglob@^0.3.1: @@ -3274,17 +4089,29 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -fake-xml-http-request@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-1.6.0.tgz#bd0ac79ae3e2660098282048a12c730a6f64d550" +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + +fake-xml-http-request@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-2.0.0.tgz#41a92f0ca539477700cb1dafd2df251d55dac8ff" + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" -fast-diff@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" fast-json-stable-stringify@^2.0.0: version "2.0.0" @@ -3300,9 +4127,9 @@ fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: dependencies: blank-object "^1.0.1" -fast-sourcemap-concat@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/fast-sourcemap-concat/-/fast-sourcemap-concat-1.3.2.tgz#148a3e15260177f9e4d3ad90a8bcad0c47b8d073" +fast-sourcemap-concat@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/fast-sourcemap-concat/-/fast-sourcemap-concat-1.4.0.tgz#122c330d4a2afaff16ad143bc9674b87cd76c8ad" dependencies: chalk "^2.0.0" fs-extra "^5.0.0" @@ -3342,9 +4169,9 @@ filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" -filesize@^3.1.3: +filesize@^3.6.1: version "3.6.1" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" + resolved "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" fill-range@^2.1.0: version "2.2.4" @@ -3389,6 +4216,13 @@ finalhandler@1.1.1: statuses "~1.4.0" unpipe "~1.0.0" +find-babel-config@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.1.0.tgz#acc01043a6749fec34429be6b64f542ebb5d6355" + dependencies: + json5 "^0.5.1" + path-exists "^3.0.0" + find-index@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" @@ -3406,31 +4240,28 @@ find-up@^2.1.0: dependencies: locate-path "^2.0.0" -find-yarn-workspace-root@^1.0.0, find-yarn-workspace-root@^1.1.0: +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + dependencies: + locate-path "^3.0.0" + +find-yarn-workspace-root@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-1.1.0.tgz#9817b6748cb90719f4dc37b4538bb200c697356f" dependencies: fs-extra "^4.0.3" micromatch "^3.1.4" -findup-sync@2.0.0: +findup-sync@2.0.0, findup-sync@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" + resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" dependencies: detect-file "^1.0.0" is-glob "^3.1.0" micromatch "^3.0.4" resolve-dir "^1.0.1" -findup-sync@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-1.0.0.tgz#6f7e4b57b6ee3a4037b4414eaedea3f58f71e0ec" - dependencies: - detect-file "^0.1.0" - is-glob "^2.0.1" - micromatch "^2.3.7" - resolve-dir "^0.1.0" - fireworm@^0.7.0: version "0.7.1" resolved "https://registry.yarnpkg.com/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" @@ -3441,7 +4272,14 @@ fireworm@^0.7.0: lodash.flatten "^3.0.2" minimatch "^3.0.2" -fixturify@^0.3.2: +fixturify-project@^1.5.3: + version "1.5.3" + resolved "https://registry.npmjs.org/fixturify-project/-/fixturify-project-1.5.3.tgz#2ba4ffec59c1d79ae6638f818c0847eb974d179b" + dependencies: + fixturify "^0.3.4" + tmp "^0.0.33" + +fixturify@^0.3.2, fixturify@^0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/fixturify/-/fixturify-0.3.4.tgz#c676de404a7f8ee8e64d0b76118e62ec95ab7b25" dependencies: @@ -3457,13 +4295,6 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" -follow-redirects@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" - dependencies: - debug "^2.2.0" - stream-consume "^0.1.0" - follow-redirects@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.1.tgz#67a8f14f5a1f67f962c2c46469c79eaec0a90291" @@ -3488,6 +4319,10 @@ forever-agent@~0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + form-data@~0.1.0: version "0.1.4" resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" @@ -3496,6 +4331,22 @@ form-data@~0.1.0: combined-stream "~0.0.4" mime "~1.2.11" +form-data@~1.0.0-rc3: + version "1.0.1" + resolved "http://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" + dependencies: + async "^2.0.1" + combined-stream "^1.0.5" + mime-types "^2.1.11" + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -3517,10 +4368,6 @@ from2@^2.1.1: inherits "^2.0.1" readable-stream "^2.0.0" -fs-exists-sync@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" - fs-extra@^0.24.0: version "0.24.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" @@ -3564,6 +4411,14 @@ fs-extra@^6.0.1: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.0.tgz#8cc3f47ce07ef7b3593a11b9fb245f7e34c041d6" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" @@ -3589,6 +4444,15 @@ fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5 path-posix "^1.0.0" symlink-or-copy "^1.1.8" +fs-tree-diff@^0.5.9: + version "0.5.9" + resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.9.tgz#a4ec6182c2f5bd80b9b83c8e23e4522e6f5fd946" + dependencies: + heimdalljs-logger "^0.1.7" + object-assign "^4.1.0" + path-posix "^1.0.0" + symlink-or-copy "^1.1.8" + fs-updater@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/fs-updater/-/fs-updater-1.0.4.tgz#2329980f99ae9176e9a0e84f7637538a182ce63b" @@ -3599,17 +4463,58 @@ fs-updater@^1.0.4: heimdalljs-logger "^0.1.9" rimraf "^2.6.2" +fs-vacuum@~1.2.7: + version "1.2.10" + resolved "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36" + dependencies: + graceful-fs "^4.1.2" + path-is-inside "^1.0.1" + rimraf "^2.5.2" + +fs-write-stream-atomic@~1.0.8: + version "1.0.10" + resolved "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" -fsevents@^1.0.0, fsevents@^1.2.3: +fsevents@^1.2.3: version "1.2.4" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" dependencies: nan "^2.9.2" node-pre-gyp "^0.10.0" +fstream-ignore@^1.0.0: + version "1.0.5" + resolved "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream-npm@~1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/fstream-npm/-/fstream-npm-1.0.7.tgz#7ed0d1ac13d7686dd9e1bf6ceb8be273bf6d2f86" + dependencies: + fstream-ignore "^1.0.0" + inherits "2" + +fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.8: + version "1.0.11" + resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -3618,6 +4523,16 @@ functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" +gauge@~1.2.0, gauge@~1.2.5: + version "1.2.7" + resolved "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz#e9cec5483d3d4ee0ef44b60a7d99e4935e136d93" + dependencies: + ansi "^0.3.0" + has-unicode "^2.0.0" + lodash.pad "^4.1.0" + lodash.padend "^4.1.0" + lodash.padstart "^4.1.0" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -3631,6 +4546,18 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" +generate-function@^2.0.0: + version "2.3.1" + resolved "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" + dependencies: + is-property "^1.0.2" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + get-caller-file@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" @@ -3643,18 +4570,30 @@ get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" -get-stdin@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" +get-stdin@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + dependencies: + pump "^3.0.0" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + git-fetch-pack@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/git-fetch-pack/-/git-fetch-pack-0.1.1.tgz#7703a32cf0db80f060d2766a34ac00d02cebcdf5" @@ -3721,13 +4660,9 @@ git-write-pkt-line@0.1.0: bops "0.0.3" through "~2.2.7" -github@^1.1.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/github/-/github-1.4.0.tgz#60aed8f16ffe381a3ca6dc6dba5bdd64445b7856" - dependencies: - follow-redirects "0.0.7" - https-proxy-agent "^1.0.0" - mime "^1.2.11" +github@^14.0.0: + version "14.0.0" + resolved "https://registry.npmjs.org/github/-/github-14.0.0.tgz#b707ed88c33cd05e155c785d289aa6229c59a850" glob-base@^0.3.0: version "0.3.0" @@ -3742,6 +4677,15 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" +"glob@3 || 4", glob@^4.3.2: + version "4.5.3" + resolved "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "^2.0.1" + once "^1.3.0" + glob@7.1.2, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" @@ -3753,31 +4697,36 @@ glob@7.1.2, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^4.3.2: - version "4.5.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" +glob@^5.0.10: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: inflight "^1.0.4" inherits "2" - minimatch "^2.0.1" + minimatch "2 || 3" once "^1.3.0" + path-is-absolute "^1.0.0" -glob@^5.0.10: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" +glob@^7.1.1, glob@^7.1.3: + version "7.1.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" dependencies: + fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "2 || 3" + minimatch "^3.0.4" once "^1.3.0" path-is-absolute "^1.0.0" -global-modules@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" +glob@~6.0.3: + version "6.0.4" + resolved "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" dependencies: - global-prefix "^0.1.4" - is-windows "^0.2.0" + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" global-modules@^1.0.0: version "1.0.0" @@ -3787,15 +4736,6 @@ global-modules@^1.0.0: is-windows "^1.0.1" resolve-dir "^1.0.0" -global-prefix@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" - dependencies: - homedir-polyfill "^1.0.0" - ini "^1.3.4" - is-windows "^0.2.0" - which "^1.2.12" - global-prefix@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" @@ -3863,7 +4803,7 @@ got@^8.0.1: url-parse-lax "^3.0.0" url-to-options "^1.0.1" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -3879,6 +4819,16 @@ growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" +handlebars@^4.0.11: + version "4.0.12" + resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" + dependencies: + async "^2.5.0" + optimist "^0.6.1" + source-map "^0.6.1" + optionalDependencies: + uglify-js "^3.1.4" + handlebars@^4.0.4: version "4.0.11" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" @@ -3889,6 +4839,26 @@ handlebars@^4.0.4: optionalDependencies: uglify-js "^2.6" +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~2.0.2: + version "2.0.6" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + +har-validator@~5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29" + dependencies: + ajv "^5.3.0" + har-schema "^2.0.0" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -3913,17 +4883,13 @@ has-symbol-support-x@^1.4.1: version "1.4.2" resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" -has-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - has-to-string-tag-x@^1.2.0: version "1.4.1" resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" dependencies: has-symbol-support-x "^1.4.1" -has-unicode@^2.0.0: +has-unicode@^2.0.0, has-unicode@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -3978,20 +4944,29 @@ hawk@1.1.1: hoek "0.9.x" sntp "0.2.x" +hawk@~3.1.0: + version "3.1.3" + resolved "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + he@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" -heimdalljs-fs-monitor@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.2.1.tgz#b4079cfb85fb8326b8c75a7538fdbfa3d8afaa63" +heimdalljs-fs-monitor@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.2.2.tgz#a76d98f52dbf3aa1b7c20cebb0132e2f5eeb9204" dependencies: - heimdalljs "^0.2.0" + heimdalljs "^0.2.3" heimdalljs-logger "^0.1.7" -heimdalljs-graph@^0.3.1: - version "0.3.4" - resolved "https://registry.yarnpkg.com/heimdalljs-graph/-/heimdalljs-graph-0.3.4.tgz#0bd75797beeaa20b0ed59017aed3b2d95312acee" +heimdalljs-graph@^0.3.4: + version "0.3.5" + resolved "https://registry.npmjs.org/heimdalljs-graph/-/heimdalljs-graph-0.3.5.tgz#420fbbc8fc3aec5963ddbbf1a5fb47921c4a5927" heimdalljs-logger@^0.1.7, heimdalljs-logger@^0.1.9: version "0.1.9" @@ -4016,6 +4991,10 @@ hoek@0.9.x: version "0.9.1" resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -4023,16 +5002,20 @@ home-or-tmp@^2.0.0: os-homedir "^1.0.0" os-tmpdir "^1.0.1" -homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: +homedir-polyfill@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" dependencies: parse-passwd "^1.0.0" -hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: +hosted-git-info@^2.1.4, hosted-git-info@^2.1.5, hosted-git-info@^2.4.2, hosted-git-info@^2.6.0: version "2.7.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" +hosted-git-info@~2.1.4: + version "2.1.5" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" + http-cache-semantics@3.8.1: version "3.8.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" @@ -4046,7 +5029,7 @@ http-errors@1.6.2: setprototypeof "1.0.3" statuses ">= 1.3.1 < 2" -http-errors@~1.6.2: +http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: version "1.6.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" dependencies: @@ -4059,9 +5042,9 @@ http-parser-js@>=0.4.0: version "0.4.13" resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.13.tgz#3bd6d6fde6e3172c9334c3b33b6c193d80fe1137" -http-proxy@^1.13.1, http-proxy@^1.9.0: +http-proxy@^1.13.1, http-proxy@^1.17.0: version "1.17.0" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" + resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" dependencies: eventemitter3 "^3.0.0" follow-redirects "^1.0.0" @@ -4075,24 +5058,42 @@ http-signature@~0.10.0: assert-plus "^0.1.5" ctype "0.5.3" -https-proxy-agent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" dependencies: - agent-base "2" - debug "2" - extend "3" + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" -iconv-lite@^0.4.13, iconv-lite@^0.4.17, iconv-lite@^0.4.4: +iconv-lite@0.4.23, iconv-lite@^0.4.13, iconv-lite@^0.4.4: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iferr@^0.1.5, iferr@~0.1.5: + version "0.1.5" + resolved "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + ignore-walk@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" @@ -4103,6 +5104,10 @@ ignore@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.3.tgz#e2d58c9654d75b542529fa28d80ac95b29e4f467" +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -4117,25 +5122,38 @@ indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" -inflection@^1.12.0, inflection@^1.7.0: +inflection@^1.12.0: version "1.12.0" resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" -inflight@^1.0.4: +inflight@^1.0.4, inflight@~1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" dependencies: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" -ini@^1.3.4, ini@~1.3.0: +ini@^1.3.4, ini@~1.3.0, ini@~1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" +init-package-json@~1.9.1: + version "1.9.6" + resolved "https://registry.npmjs.org/init-package-json/-/init-package-json-1.9.6.tgz#789fc2b74466a4952b9ea77c0575bc78ebd60a61" + dependencies: + glob "^7.1.1" + npm-package-arg "^4.0.0 || ^5.0.0" + promzard "^0.3.0" + read "~1.0.1" + read-package-json "1 || 2" + semver "2.x || 3.x || 4 || 5" + validate-npm-package-license "^3.0.1" + validate-npm-package-name "^3.0.0" + inline-source-map-comment@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" @@ -4165,20 +5183,20 @@ inquirer@^2: strip-ansi "^3.0.0" through "^2.3.6" -inquirer@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726" +inquirer@^6.1.0: + version "6.2.0" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8" dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" cli-cursor "^2.1.0" cli-width "^2.0.0" - external-editor "^2.1.0" + external-editor "^3.0.0" figures "^2.0.0" - lodash "^4.3.0" + lodash "^4.17.10" mute-stream "0.0.7" run-async "^2.2.0" - rxjs "^5.5.2" + rxjs "^6.1.0" string-width "^2.1.0" strip-ansi "^4.0.0" through "^2.3.6" @@ -4190,7 +5208,7 @@ into-stream@^3.1.0: from2 "^2.1.1" p-is-promise "^1.1.0" -invariant@^2.2.0, invariant@^2.2.2: +invariant@^2.2.2: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" dependencies: @@ -4200,6 +5218,10 @@ ipaddr.js@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" +ipaddr.js@1.8.0: + version "1.8.0" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -4216,12 +5238,6 @@ is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - dependencies: - binary-extensions "^1.0.0" - is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -4328,6 +5344,20 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" +is-my-ip-valid@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824" + +is-my-json-valid@^2.12.4: + version "2.19.0" + resolved "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz#8fd6e40363cd06b963fa877d444bfb5eddc62175" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + is-my-ip-valid "^1.0.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" @@ -4390,6 +5420,10 @@ is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" +is-property@^1.0.0, is-property@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + is-redirect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" @@ -4432,14 +5466,14 @@ is-type@0.0.1: dependencies: core-util-is "~1.0.0" +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" -is-windows@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" - is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -4456,9 +5490,11 @@ isarray@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" -isbinaryfile@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" +isbinaryfile@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80" + dependencies: + buffer-alloc "^1.2.0" isexe@^2.0.0: version "2.0.0" @@ -4474,6 +5510,10 @@ isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + istextorbinary@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" @@ -4489,33 +5529,37 @@ isurl@^1.0.0-alpha5: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" -jest-docblock@^21.0.0: - version "21.2.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" - jquery@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" +js-levenshtein@^1.1.3: + version "1.1.4" + resolved "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.4.tgz#3a56e3cbf589ca0081eb22cd9ba0b1290a16d26e" + js-reporters@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b" -js-tokens@^3.0.0, js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - -"js-tokens@^3.0.0 || ^4.0.0": +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" -js-yaml@^3.11.0, js-yaml@^3.2.5, js-yaml@^3.2.7, js-yaml@^3.6.1: +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + +js-yaml@^3.12.0, js-yaml@^3.2.5, js-yaml@^3.2.7: version "3.12.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" dependencies: argparse "^1.0.7" esprima "^4.0.0" +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" @@ -4536,10 +5580,22 @@ json-buffer@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -4550,11 +5606,11 @@ json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: dependencies: jsonify "~0.0.0" -json-stringify-safe@~5.0.0: +json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" -json5@^0.5.1: +json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" @@ -4574,6 +5630,19 @@ jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + keyv@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" @@ -4672,10 +5741,31 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +lockfile@~1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" + dependencies: + signal-exit "^3.0.2" + lodash-node@^3.2.0: version "3.10.2" resolved "https://registry.yarnpkg.com/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" +lodash._arraycopy@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" + +lodash._arrayeach@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" + lodash._baseassign@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" @@ -4691,6 +5781,26 @@ lodash._basebind@~2.3.0: lodash._setbinddata "~2.3.0" lodash.isobject "~2.3.0" +lodash._basecallback@^3.0.0: + version "3.3.1" + resolved "https://registry.npmjs.org/lodash._basecallback/-/lodash._basecallback-3.3.1.tgz#b7b2bb43dc2160424a21ccf26c57e443772a8e27" + dependencies: + lodash._baseisequal "^3.0.0" + lodash._bindcallback "^3.0.0" + lodash.isarray "^3.0.0" + lodash.pairs "^3.0.0" + +lodash._baseclone@^3.0.0: + version "3.3.0" + resolved "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz#303519bf6393fe7e42f34d8b630ef7794e3542b7" + dependencies: + lodash._arraycopy "^3.0.0" + lodash._arrayeach "^3.0.0" + lodash._baseassign "^3.0.0" + lodash._basefor "^3.0.0" + lodash.isarray "^3.0.0" + lodash.keys "^3.0.0" + lodash._basecopy@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" @@ -4721,6 +5831,14 @@ lodash._basecreatewrapper@~2.3.0: lodash._slice "~2.3.0" lodash.isobject "~2.3.0" +lodash._basedifference@^3.0.0: + version "3.0.3" + resolved "https://registry.npmjs.org/lodash._basedifference/-/lodash._basedifference-3.0.3.tgz#f2c204296c2a78e02b389081b6edcac933cf629c" + dependencies: + lodash._baseindexof "^3.0.0" + lodash._cacheindexof "^3.0.0" + lodash._createcache "^3.0.0" + lodash._baseflatten@^3.0.0: version "3.1.4" resolved "https://registry.yarnpkg.com/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" @@ -4728,10 +5846,38 @@ lodash._baseflatten@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" +lodash._basefor@^3.0.0: + version "3.0.3" + resolved "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" + +lodash._baseindexof@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" + +lodash._baseisequal@^3.0.0: + version "3.0.7" + resolved "https://registry.npmjs.org/lodash._baseisequal/-/lodash._baseisequal-3.0.7.tgz#d8025f76339d29342767dcc887ce5cb95a5b51f1" + dependencies: + lodash.isarray "^3.0.0" + lodash.istypedarray "^3.0.0" + lodash.keys "^3.0.0" + +lodash._baseuniq@^3.0.0: + version "3.0.3" + resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-3.0.3.tgz#2123fa0db2d69c28d5beb1c1f36d61522a740234" + dependencies: + lodash._baseindexof "^3.0.0" + lodash._cacheindexof "^3.0.0" + lodash._createcache "^3.0.0" + lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" +lodash._cacheindexof@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" + lodash._createassigner@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" @@ -4740,6 +5886,12 @@ lodash._createassigner@^3.0.0: lodash._isiterateecall "^3.0.0" lodash.restparam "^3.0.0" +lodash._createcache@^3.0.0: + version "3.1.2" + resolved "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" + dependencies: + lodash._getnative "^3.0.0" + lodash._createwrapper@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" @@ -4838,6 +5990,13 @@ lodash.clonedeep@^4.4.1: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" +lodash.clonedeep@~3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz#a0a1e40d82a5ea89ff5b147b8444ed63d92827db" + dependencies: + lodash._baseclone "^3.0.0" + lodash._bindcallback "^3.0.0" + lodash.debounce@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" @@ -4911,6 +6070,10 @@ lodash.isobject@~2.3.0: dependencies: lodash._objecttypes "~2.3.0" +lodash.istypedarray@^3.0.0: + version "3.0.6" + resolved "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" + lodash.keys@^3.0.0: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" @@ -4939,6 +6102,24 @@ lodash.omit@^4.1.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" +lodash.pad@^4.1.0: + version "4.5.1" + resolved "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz#4330949a833a7c8da22cc20f6a26c4d59debba70" + +lodash.padend@^4.1.0: + version "4.6.1" + resolved "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e" + +lodash.padstart@^4.1.0: + version "4.6.1" + resolved "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b" + +lodash.pairs@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/lodash.pairs/-/lodash.pairs-3.0.1.tgz#bbe08d5786eeeaa09a15c91ebf0dcb7d2be326a9" + dependencies: + lodash.keys "^3.0.0" + lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" @@ -4949,9 +6130,9 @@ lodash.support@~2.3.0: dependencies: lodash._renative "~2.3.0" -lodash.template@^4.2.5: +lodash.template@^4.4.0: version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" + resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings "^4.0.0" @@ -4981,10 +6162,28 @@ lodash.templatesettings@~2.3.0: lodash._reinterpolate "~2.3.0" lodash.escape "~2.3.0" +lodash.union@~3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-3.1.0.tgz#a4a3066fc15d6a7f8151cce9bdfe63dce7f5bcff" + dependencies: + lodash._baseflatten "^3.0.0" + lodash._baseuniq "^3.0.0" + lodash.restparam "^3.0.0" + lodash.uniq@^4.2.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" +lodash.uniq@~3.2.2: + version "3.2.2" + resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-3.2.2.tgz#146c36f25e75d19501ba402e88ba14937f63cd8b" + dependencies: + lodash._basecallback "^3.0.0" + lodash._baseuniq "^3.0.0" + lodash._getnative "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash.isarray "^3.0.0" + lodash.uniqby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" @@ -4995,14 +6194,21 @@ lodash.values@~2.3.0: dependencies: lodash.keys "~2.3.0" -lodash@^3.10.1: - version "3.10.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" +lodash.without@~3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/lodash.without/-/lodash.without-3.2.1.tgz#d69614b3512e52294b6abab782e7ca96538ce816" + dependencies: + lodash._basedifference "^3.0.0" + lodash.restparam "^3.0.0" -lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.1: +lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.6.1: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" +lodash@^4.17.11: + version "4.17.11" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" @@ -5034,6 +6240,10 @@ lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" +lru-cache@2: + version "2.7.3" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + magic-string@^0.24.0: version "0.24.1" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.24.1.tgz#7e38e5f126cae9f15e71f0cf8e450818ca7d5a8f" @@ -5090,7 +6300,7 @@ markdown-it@^4.3.0: mdurl "~1.0.0" uc.micro "^1.0.0" -markdown-it@^8.3.0, markdown-it@^8.3.1: +markdown-it@^8.3.1, markdown-it@^8.4.2: version "8.4.2" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54" dependencies: @@ -5173,7 +6383,7 @@ methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" -micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7: +micromatch@^2.3.11: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" dependencies: @@ -5213,6 +6423,16 @@ micromatch@^3.0.4, micromatch@^3.1.4: version "1.35.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" +mime-db@~1.37.0: + version "1.37.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" + +mime-types@^2.1.11, mime-types@^2.1.12, mime-types@^2.1.19, mime-types@~2.1.19, mime-types@~2.1.7: + version "2.1.21" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" + dependencies: + mime-db "~1.37.0" + mime-types@^2.1.18, mime-types@~2.1.18: version "2.1.19" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" @@ -5227,10 +6447,6 @@ mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" -mime@^1.2.11: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - mime@~1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" @@ -5243,6 +6459,13 @@ mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" +minimatch@1: + version "1.0.0" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz#e0dd2120b49e1b724ce8d714c520822a9438576d" + dependencies: + lru-cache "2" + sigmund "~1.0.0" + "minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -5287,13 +6510,13 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: +mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" -mktemp@^0.4.0, mktemp@~0.4.0: +mktemp@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" @@ -5331,13 +6554,13 @@ moment-timezone@^0.3.0: version "2.22.2" resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" -morgan@^1.8.1: - version "1.9.0" - resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.0.tgz#d01fa6c65859b76fcf31b3cb53a3821a311d8051" +morgan@^1.9.0: + version "1.9.1" + resolved "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz#0a8d16734a1d9afbc824b99df87e738e58e2da59" dependencies: basic-auth "~2.0.0" debug "2.6.9" - depd "~1.1.1" + depd "~1.1.2" on-finished "~2.3.0" on-headers "~1.0.1" @@ -5349,17 +6572,21 @@ ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" -mustache@^2.2.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.0.tgz#4028f7778b17708a489930a6e52ac3bca0da41d0" +ms@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + +mustache@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/mustache/-/mustache-3.0.0.tgz#3de22dd9ba38152f7355399a953dd4528c403338" mute-stream@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" -mute-stream@0.0.7: +mute-stream@0.0.7, mute-stream@~0.0.4: version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" nan@^2.9.2: version "2.10.0" @@ -5405,6 +6632,25 @@ nice-try@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" +node-gyp@~3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-3.2.1.tgz#f5dd569970a508464cc3c15d7e9e8d2de8638dd5" + dependencies: + fstream "^1.0.0" + glob "3 || 4" + graceful-fs "^4.1.2" + minimatch "1" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1" + osenv "0" + path-array "^1.0.0" + request "2" + rimraf "2" + semver "2.x || 3.x || 4 || 5" + tar "^2.0.0" + which "1" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -5437,11 +6683,17 @@ node-pre-gyp@^0.10.0: semver "^5.3.0" tar "^4" -node-uuid@~1.4.0: +node-releases@^1.0.0-alpha.15: + version "1.0.0-alpha.15" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.0.0-alpha.15.tgz#bdb08730287cc50ddbfa3c1a358366a4a2f5d397" + dependencies: + semver "^5.3.0" + +node-uuid@~1.4.0, node-uuid@~1.4.7: version "1.4.8" - resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" + resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" -nopt@^3.0.3, nopt@^3.0.6: +"nopt@2 || 3", nopt@^3.0.3, nopt@^3.0.6, nopt@~3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: @@ -5454,7 +6706,11 @@ nopt@^4.0.1: abbrev "1" osenv "^0.1.4" -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: +normalize-git-url@~3.0.1: + version "3.0.2" + resolved "https://registry.npmjs.org/normalize-git-url/-/normalize-git-url-3.0.2.tgz#8e5f14be0bdaedb73e07200310aa416c27350fc4" + +normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, "normalize-package-data@~1.0.1 || ^2.0.0": version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: @@ -5463,7 +6719,16 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: +normalize-package-data@~2.3.5: + version "2.3.8" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: @@ -5481,19 +6746,53 @@ npm-bundled@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" +npm-cache-filename@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" + npm-git-info@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" -npm-package-arg@^6.0.0: +npm-install-checks@~2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-2.0.1.tgz#a93540b53f04fa9d916d2733d6541f6db7d88e46" + dependencies: + npmlog "0.1 || 1" + semver "^2.3.0 || 3.x || 4 || 5" + +"npm-package-arg@^3.0.0 || ^4.0.0", npm-package-arg@^4.1.1: + version "4.2.1" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" + dependencies: + hosted-git-info "^2.1.5" + semver "^5.1.0" + +"npm-package-arg@^4.0.0 || ^5.0.0": + version "5.1.2" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-5.1.2.tgz#fb18d17bb61e60900d6312619919bd753755ab37" + dependencies: + hosted-git-info "^2.4.2" + osenv "^0.1.4" + semver "^5.1.0" + validate-npm-package-name "^3.0.0" + +npm-package-arg@^6.1.0: version "6.1.0" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" dependencies: hosted-git-info "^2.6.0" osenv "^0.1.5" semver "^5.5.0" validate-npm-package-name "^3.0.0" +npm-package-arg@~4.1.0: + version "4.1.1" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.1.1.tgz#86d9dca985b4c5e5d59772dfd5de6919998a495a" + dependencies: + hosted-git-info "^2.1.4" + semver "4 || 5" + npm-packlist@^1.1.6: version "1.1.10" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" @@ -5501,12 +6800,117 @@ npm-packlist@^1.1.6: ignore-walk "^3.0.1" npm-bundled "^1.0.1" +npm-registry-client@~7.0.9: + version "7.0.9" + resolved "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-7.0.9.tgz#1baf86ee5285c4e6d38d4556208ded56049231bb" + dependencies: + chownr "^1.0.1" + concat-stream "^1.4.6" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + normalize-package-data "~1.0.1 || ^2.0.0" + npm-package-arg "^3.0.0 || ^4.0.0" + once "^1.3.0" + request "^2.47.0" + retry "^0.8.0" + rimraf "2" + semver "2 >=2.2.1 || 3.x || 4 || 5" + slide "^1.1.3" + optionalDependencies: + npmlog "~2.0.0" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" dependencies: path-key "^2.0.0" +npm-user-validate@~0.1.2: + version "0.1.5" + resolved "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-0.1.5.tgz#52465d50c2d20294a57125b996baedbf56c5004b" + +npm@~3.5.2: + version "3.5.4" + resolved "http://registry.npmjs.org/npm/-/npm-3.5.4.tgz#db2f71d3daa0e7a99077edd4c213919834e95eb2" + dependencies: + abbrev "~1.0.7" + ansicolors "~0.3.2" + ansistyles "~0.1.3" + aproba "~1.0.1" + archy "~1.0.0" + async-some "~1.0.2" + chownr "~1.0.1" + cmd-shim "~2.0.1" + columnify "~1.5.4" + config-chain "~1.1.9" + dezalgo "~1.0.3" + editor "~1.0.0" + fs-vacuum "~1.2.7" + fs-write-stream-atomic "~1.0.8" + fstream "~1.0.8" + fstream-npm "~1.0.7" + glob "~6.0.3" + graceful-fs "~4.1.2" + has-unicode "~2.0.0" + hosted-git-info "~2.1.4" + iferr "~0.1.5" + inflight "~1.0.4" + inherits "~2.0.1" + ini "~1.3.4" + init-package-json "~1.9.1" + lockfile "~1.0.1" + lodash.clonedeep "~3.0.2" + lodash.union "~3.1.0" + lodash.uniq "~3.2.2" + lodash.without "~3.2.1" + mkdirp "~0.5.1" + node-gyp "~3.2.1" + nopt "~3.0.6" + normalize-git-url "~3.0.1" + normalize-package-data "~2.3.5" + npm-cache-filename "~1.0.2" + npm-install-checks "~2.0.1" + npm-package-arg "~4.1.0" + npm-registry-client "~7.0.9" + npm-user-validate "~0.1.2" + npmlog "~2.0.0" + once "~1.3.3" + opener "~1.4.1" + osenv "~0.1.3" + path-is-inside "~1.0.1" + read "~1.0.7" + read-cmd-shim "~1.0.1" + read-installed "~4.0.3" + read-package-json "~2.0.2" + read-package-tree "~5.1.2" + readable-stream "~2.0.5" + realize-package-specifier "~3.0.1" + request "~2.67.0" + retry "~0.8.0" + rimraf "~2.5.0" + semver "~5.1.0" + sha "~2.0.1" + slide "~1.1.6" + sorted-object "~1.0.0" + tar "~2.2.1" + text-table "~0.2.0" + uid-number "0.0.6" + umask "~1.1.0" + unique-filename "~1.1.0" + unpipe "~1.0.0" + validate-npm-package-name "~2.2.2" + which "~1.2.1" + wrappy "~1.0.1" + write-file-atomic "~1.1.4" + +"npmlog@0 || 1", "npmlog@0.1 || 1": + version "1.2.1" + resolved "http://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz#28e7be619609b53f7ad1dd300a10d64d716268b6" + dependencies: + ansi "~0.3.0" + are-we-there-yet "~1.0.0" + gauge "~1.2.0" + npmlog@^4.0.0, npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -5516,6 +6920,14 @@ npmlog@^4.0.0, npmlog@^4.0.2: gauge "~2.7.3" set-blocking "~2.0.0" +npmlog@~2.0.0: + version "2.0.4" + resolved "http://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz#98b52530f2514ca90d09ec5b22c8846722375692" + dependencies: + ansi "~0.3.1" + are-we-there-yet "~1.1.2" + gauge "~1.2.5" + number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -5524,6 +6936,14 @@ oauth-sign@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" +oauth-sign@~0.8.0: + version "0.8.2" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -5573,12 +6993,18 @@ on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" -once@^1.3.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" +once@~1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" + dependencies: + wrappy "1" + onetime@^1.0.0: version "1.1.0" resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" @@ -5589,6 +7015,10 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" +opener@~1.4.1: + version "1.4.3" + resolved "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" + optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" @@ -5630,7 +7060,7 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4, osenv@^0.1.5: +osenv@0, osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4, osenv@^0.1.5, osenv@~0.1.3: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" dependencies: @@ -5655,12 +7085,24 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" +p-limit@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec" + dependencies: + p-try "^2.0.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" dependencies: p-limit "^1.1.0" +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + dependencies: + p-limit "^2.0.0" + p-timeout@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" @@ -5671,6 +7113,10 @@ p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" +p-try@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" + package-json@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" @@ -5727,7 +7173,13 @@ passwd-user@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/passwd-user/-/passwd-user-1.2.1.tgz#a01a5dc639ef007dc56364b8178569080ad3a7b8" dependencies: - exec-file-sync "^2.0.0" + exec-file-sync "^2.0.0" + +path-array@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271" + dependencies: + array-index "^1.0.0" path-exists@^2.0.0: version "2.1.0" @@ -5739,11 +7191,11 @@ path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" -path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: +path-is-absolute@1.0.1, path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-is-inside@^1.0.1, path-is-inside@^1.0.2: +path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" @@ -5775,6 +7227,10 @@ pathval@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -5793,13 +7249,19 @@ pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" +pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" + dependencies: + find-up "^2.1.0" + pluralize@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" -portfinder@^1.0.7: - version "1.0.13" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" +portfinder@^1.0.15: + version "1.0.19" + resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.19.tgz#07e87914a55242dcda5b833d42f018d6875b595f" dependencies: async "^1.5.2" debug "^2.2.0" @@ -5825,16 +7287,23 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -pretender@^1.4.2: - version "1.6.1" - resolved "https://registry.yarnpkg.com/pretender/-/pretender-1.6.1.tgz#77d1e42ac8c6b298f5cd43534a87645df035db8c" +pretender@^2.1.0: + version "2.1.1" + resolved "https://registry.npmjs.org/pretender/-/pretender-2.1.1.tgz#5085f0a1272c31d5b57c488386f69e6ca207cb35" dependencies: - fake-xml-http-request "^1.6.0" + "@xg-wang/whatwg-fetch" "^3.0.0" + fake-xml-http-request "^2.0.0" route-recognizer "^0.3.3" -prettier@^1.14.0: - version "1.14.0" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.14.0.tgz#847c235522035fd988100f1f43cf20a7d24f9372" +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + dependencies: + fast-diff "^1.1.2" + +prettier@^1.14.3: + version "1.14.3" + resolved "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz#90238dd4c0684b7edce5f83b0fb7328e48bd0895" pretty-ms@^3.1.0: version "3.2.0" @@ -5842,14 +7311,18 @@ pretty-ms@^3.1.0: dependencies: parse-ms "^1.0.0" -printf@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/printf/-/printf-0.3.0.tgz#6918ca5237c047e19cf004b69e6bcfafbef1ce82" +printf@^0.5.1: + version "0.5.1" + resolved "https://registry.npmjs.org/printf/-/printf-0.5.1.tgz#e0466788260859ed153006dc6867f09ddf240cf3" private@^0.1.6, private@^0.1.8, private@~0.1.5: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + process-nextick-args@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" @@ -5864,12 +7337,30 @@ progress@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" -promise-map-series@^0.2.1: +promise-map-series@^0.2.1, promise-map-series@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" dependencies: rsvp "^3.0.14" +promise.prototype.finally@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz#66f161b1643636e50e7cf201dc1b84a857f3864e" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.9.0" + function-bind "^1.1.1" + +promzard@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" + dependencies: + read "1" + +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + proxy-addr@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" @@ -5877,10 +7368,24 @@ proxy-addr@~2.0.3: forwarded "~0.1.2" ipaddr.js "1.6.0" +proxy-addr@~2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.8.0" + psl@^1.1.24: version "1.1.28" resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.28.tgz#4fb6ceb08a1e2214d4fd4de0ca22dae13740bc7b" +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -5893,7 +7398,7 @@ qs@6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" -qs@^6.4.0: +qs@6.5.2, qs@^6.4.0, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -5901,6 +7406,10 @@ qs@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" +qs@~5.2.0: + version "5.2.1" + resolved "https://registry.npmjs.org/qs/-/qs-5.2.1.tgz#801fee030e0b9450d6385adc48a4cc55b44aedfc" + query-string@^5.0.1: version "5.1.1" resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" @@ -5924,16 +7433,16 @@ quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: rimraf "^2.5.4" underscore.string "~3.3.4" -qunit@^2.5.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/qunit/-/qunit-2.6.1.tgz#3a2a5f05307f873174e0f5859010fb7380380e3c" +qunit@~2.6.0: + version "2.6.2" + resolved "https://registry.npmjs.org/qunit/-/qunit-2.6.2.tgz#551210c5cf857258a4fe39a7fe15d9e14dfef22c" dependencies: - chokidar "1.7.0" commander "2.12.2" exists-stat "1.0.0" findup-sync "2.0.0" js-reporters "1.2.1" resolve "1.5.0" + sane "^2.5.2" walk-sync "0.3.2" randomatic@^3.0.0: @@ -5957,6 +7466,15 @@ raw-body@2.3.2: iconv-lite "0.4.19" unpipe "1.0.0" +raw-body@2.3.3: + version "2.3.3" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + dependencies: + bytes "3.0.0" + http-errors "1.6.3" + iconv-lite "0.4.23" + unpipe "1.0.0" + raw-body@~1.1.0: version "1.1.7" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" @@ -5973,6 +7491,46 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +read-cmd-shim@~1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b" + dependencies: + graceful-fs "^4.1.2" + +read-installed@~4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" + dependencies: + debuglog "^1.0.1" + read-package-json "^2.0.0" + readdir-scoped-modules "^1.0.0" + semver "2 || 3 || 4 || 5" + slide "~1.1.3" + util-extend "^1.0.1" + optionalDependencies: + graceful-fs "^4.1.2" + +"read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@~2.0.2: + version "2.0.13" + resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-2.0.13.tgz#2e82ebd9f613baa6d2ebe3aa72cefe3f68e41f4a" + dependencies: + glob "^7.1.1" + json-parse-better-errors "^1.0.1" + normalize-package-data "^2.0.0" + slash "^1.0.0" + optionalDependencies: + graceful-fs "^4.1.2" + +read-package-tree@~5.1.2: + version "5.1.6" + resolved "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.1.6.tgz#4f03e83d0486856fb60d97c94882841c2a7b1b7a" + dependencies: + debuglog "^1.0.1" + dezalgo "^1.0.0" + once "^1.3.0" + read-package-json "^2.0.0" + readdir-scoped-modules "^1.0.0" + read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -5988,7 +7546,13 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: +read@1, read@~1.0.1, read@~1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" + dependencies: + mute-stream "~0.0.4" + +"readable-stream@1 || 2", readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -6009,14 +7573,32 @@ readable-stream@~1.0.2: isarray "0.0.1" string_decoder "~0.10.x" -readdirp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" +readable-stream@~2.0.5: + version "2.0.6" + resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdir-scoped-modules@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" dependencies: + debuglog "^1.0.1" + dezalgo "^1.0.0" graceful-fs "^4.1.2" - minimatch "^3.0.2" - readable-stream "^2.0.2" - set-immediate-shim "^1.0.1" + once "^1.3.0" + +realize-package-specifier@~3.0.1: + version "3.0.3" + resolved "https://registry.npmjs.org/realize-package-specifier/-/realize-package-specifier-3.0.3.tgz#d0def882952b8de3f67eba5e91199661271f41f4" + dependencies: + dezalgo "^1.0.1" + npm-package-arg "^4.1.1" recast@^0.11.3: version "0.11.23" @@ -6040,7 +7622,13 @@ redeyed@~1.0.0: dependencies: esprima "~3.0.0" -regenerate@^1.2.1: +regenerate-unicode-properties@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz#107405afcc4a190ec5ed450ecaa00ed0cafa7a4c" + dependencies: + regenerate "^1.4.0" + +regenerate@^1.2.1, regenerate@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" @@ -6048,7 +7636,7 @@ regenerator-runtime@^0.10.5: version "0.10.5" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" -regenerator-runtime@^0.11.0: +regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" @@ -6064,6 +7652,12 @@ regenerator-transform@^0.10.0: babel-types "^6.19.0" private "^0.1.6" +regenerator-transform@^0.13.3: + version "0.13.3" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.3.tgz#264bd9ff38a8ce24b06e0636496b2c856b57bcbb" + dependencies: + private "^0.1.6" + regex-cache@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" @@ -6077,16 +7671,14 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexp.prototype.flags@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz#6b30724e306a27833eeb171b66ac8890ba37e41c" - dependencies: - define-properties "^1.1.2" - regexpp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.0.tgz#b2a7534a85ca1b033bcf5ce9ff8e56d4e0755365" +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -6095,6 +7687,17 @@ regexpu-core@^2.0.0: regjsgen "^0.2.0" regjsparser "^0.1.4" +regexpu-core@^4.1.3, regexpu-core@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.2.0.tgz#a3744fa03806cffe146dea4421a3e73bdcc47b1d" + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^7.0.0" + regjsgen "^0.4.0" + regjsparser "^0.3.0" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.0.2" + registry-auth-token@^3.0.1: version "3.3.2" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" @@ -6112,12 +7715,22 @@ regjsgen@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" +regjsgen@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.4.0.tgz#c1eb4c89a209263f8717c782591523913ede2561" + regjsparser@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" dependencies: jsesc "~0.5.0" +regjsparser@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.3.0.tgz#3c326da7fcfd69fa0d332575a41c8c0cdf588c96" + dependencies: + jsesc "~0.5.0" + remote-git-tags@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/remote-git-tags/-/remote-git-tags-2.0.0.tgz#1152f39cf8b5268ae0e4307636ef741ec341664c" @@ -6143,6 +7756,31 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" +request@2, request@^2.47.0: + version "2.88.0" + resolved "https://registry.npmjs.org/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.0" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.4.3" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + request@~2.40.0: version "2.40.0" resolved "https://registry.yarnpkg.com/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" @@ -6162,6 +7800,35 @@ request@~2.40.0: tough-cookie ">=0.12.0" tunnel-agent "~0.4.0" +request@~2.67.0: + version "2.67.0" + resolved "http://registry.npmjs.org/request/-/request-2.67.0.tgz#8af74780e2bf11ea0ae9aa965c11f11afd272742" + dependencies: + aws-sign2 "~0.6.0" + bl "~1.0.0" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~1.0.0-rc3" + har-validator "~2.0.2" + hawk "~3.1.0" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + node-uuid "~1.4.7" + oauth-sign "~0.8.0" + qs "~5.2.0" + stringstream "~0.0.4" + tough-cookie "~2.2.0" + tunnel-agent "~0.4.1" + +require-dir@^0.3.0: + version "0.3.2" + resolved "https://registry.npmjs.org/require-dir/-/require-dir-0.3.2.tgz#c1d5c75e9fbffde9f2e6b33e383db4f594b5a6a9" + require-relative@^0.8.7: version "0.8.7" resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" @@ -6177,12 +7844,9 @@ requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" -resolve-dir@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" - dependencies: - expand-tilde "^1.2.2" - global-modules "^0.2.3" +reselect@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147" resolve-dir@^1.0.0, resolve-dir@^1.0.1: version "1.0.1" @@ -6195,6 +7859,13 @@ resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" +resolve-path@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7" + dependencies: + http-errors "~1.6.2" + path-is-absolute "1.0.1" + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -6205,7 +7876,7 @@ resolve@1.5.0: dependencies: path-parse "^1.0.5" -resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.0, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.7.1, resolve@^1.8.1: +resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.7.1, resolve@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" dependencies: @@ -6235,13 +7906,17 @@ ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" +retry@^0.8.0, retry@~0.8.0: + version "0.8.0" + resolved "https://registry.npmjs.org/retry/-/retry-0.8.0.tgz#2367628dc0edb247b1eab649dc53ac8628ac2d5f" + right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" dependencies: align-text "^0.1.1" -rimraf@2.6.2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: +rimraf@2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: @@ -6251,6 +7926,12 @@ rimraf@~2.2.6: version "2.2.8" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" +rimraf@~2.5.0: + version "2.5.4" + resolved "http://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + dependencies: + glob "^7.0.5" + rollup-pluginutils@^2.0.1: version "2.3.0" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.3.0.tgz#478ace04bd7f6da2e724356ca798214884738fc4" @@ -6282,13 +7963,17 @@ rsvp@3.0.14: version "3.0.14" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.14.tgz#9d2968cf36d878d3bb9a9a5a4b8e1ff55a76dd31" -rsvp@4.8.3, rsvp@^4.7.0, rsvp@^4.8.1, rsvp@^4.8.2, rsvp@^4.8.3: +rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3: + version "3.6.2" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" + +rsvp@^4.7.0, rsvp@^4.8.1, rsvp@^4.8.2, rsvp@^4.8.3: version "4.8.3" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.3.tgz#25d4b9fdd0f95e216eb5884d9b3767d3fbfbe2cd" -rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0, rsvp@^3.3.3, rsvp@^3.5.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" +rsvp@^4.8.4: + version "4.8.4" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.4.tgz#b50e6b34583f3dd89329a2f23a8a2be072845911" rsvp@~3.2.1: version "3.2.1" @@ -6304,11 +7989,11 @@ rx@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" -rxjs@^5.5.2: - version "5.5.11" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.11.tgz#f733027ca43e3bec6b994473be4ab98ad43ced87" +rxjs@^6.1.0: + version "6.3.3" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz#3c6a7fa420e844a81390fb1158a9ec614f4bad55" dependencies: - symbol-observable "1.0.1" + tslib "^1.9.0" safe-buffer@5.1.1: version "5.1.1" @@ -6328,29 +8013,33 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" -sane@^1.4.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-1.7.0.tgz#b3579bccb45c94cf20355cc81124990dfd346e30" +sane@^2.4.1, sane@^2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" dependencies: - anymatch "^1.3.0" + anymatch "^2.0.0" + capture-exit "^1.2.0" exec-sh "^0.2.0" fb-watchman "^2.0.0" - minimatch "^3.0.2" + micromatch "^3.1.4" minimist "^1.1.1" walker "~1.0.5" - watch "~0.10.0" + watch "~0.18.0" + optionalDependencies: + fsevents "^1.2.3" -sane@^2.2.0, sane@^2.4.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" +sane@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/sane/-/sane-3.1.0.tgz#995193b7dc1445ef1fe41ddfca2faf9f111854c6" dependencies: anymatch "^2.0.0" capture-exit "^1.2.0" exec-sh "^0.2.0" + execa "^1.0.0" fb-watchman "^2.0.0" micromatch "^3.1.4" minimist "^1.1.1" @@ -6359,11 +8048,29 @@ sane@^2.2.0, sane@^2.4.1: optionalDependencies: fsevents "^1.2.3" +sane@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/sane/-/sane-4.0.1.tgz#af1e10466e924e1b888c104bb9925a0f1beb46dd" + dependencies: + anymatch "^2.0.0" + capture-exit "^1.2.0" + exec-sh "^0.2.0" + execa "^1.0.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.18.0" + sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.1.1, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: +"semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.5.1, semver@^5.6.0: + version "5.6.0" + resolved "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + +"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" @@ -6371,9 +8078,9 @@ semver@^4.3.1: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" -semver@~5.0.1: - version "5.0.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" +semver@~5.1.0: + version "5.1.1" + resolved "http://registry.npmjs.org/semver/-/semver-5.1.1.tgz#a3292a373e6f3e0798da0b20641b9a9c5bc47e19" send@0.16.2: version "0.16.2" @@ -6406,10 +8113,6 @@ set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - set-value@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" @@ -6436,6 +8139,13 @@ setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" +sha@~2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae" + dependencies: + graceful-fs "^4.1.2" + readable-stream "^2.0.2" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -6450,6 +8160,10 @@ shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" +sigmund@~1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -6460,6 +8174,12 @@ silent-error@^1.0.0, silent-error@^1.0.1, silent-error@^1.1.0: dependencies: debug "^2.2.0" +silent-error@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.1.1.tgz#f72af5b0d73682a2ba1778b7e32cd8aa7c2d8662" + dependencies: + debug "^2.2.0" + slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" @@ -6470,6 +8190,10 @@ slice-ansi@1.0.0: dependencies: is-fullwidth-code-point "^2.0.0" +slide@^1.1.3, slide@^1.1.5, slide@~1.1.3, slide@~1.1.6: + version "1.1.6" + resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -6503,6 +8227,12 @@ sntp@0.2.x: dependencies: hoek "0.9.x" +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + socket.io-adapter@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" @@ -6551,16 +8281,20 @@ sort-keys@^2.0.0: dependencies: is-plain-obj "^1.0.0" -sort-object-keys@^1.1.1: +sort-object-keys@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" + resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" -sort-package-json@^1.4.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.15.0.tgz#3c732cc8312eb4aa12f6eccab1bc3dea89b11dff" +sort-package-json@^1.15.0: + version "1.16.0" + resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.16.0.tgz#087f5ce05b6faca373312e7124918e0d68492d7b" dependencies: detect-indent "^5.0.0" - sort-object-keys "^1.1.1" + sort-object-keys "^1.1.2" + +sorted-object@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/sorted-object/-/sorted-object-1.0.0.tgz#5d1f4f9c1fb2cd48965967304e212eb44cfb6d05" source-map-resolve@^0.5.0: version "0.5.2" @@ -6603,7 +8337,7 @@ source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0, sour version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" -source-map@^0.6.0, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -6681,6 +8415,20 @@ sri-toolbox@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" +sshpk@^1.7.0: + version "1.15.1" + resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.15.1.tgz#b79a089a732e346c6e0714830f36285cd38191a2" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -6700,10 +8448,6 @@ statuses@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" -stream-consume@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.1.tgz#d3bdb598c2bd0ae82b8cac7ac50b1107a7996c48" - strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" @@ -6727,16 +8471,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string.prototype.matchall@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-2.0.0.tgz#2af8fe3d2d6dc53ca2a59bd376b089c3c152b3c8" - dependencies: - define-properties "^1.1.2" - es-abstract "^1.10.0" - function-bind "^1.1.1" - has-symbols "^1.0.0" - regexp.prototype.flags "^1.2.0" - string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" @@ -6814,22 +8548,16 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -symbol-observable@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" - symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" -table@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" +table@^5.0.2: + version "5.1.0" + resolved "https://registry.npmjs.org/table/-/table-5.1.0.tgz#69a54644f6f01ad1628f8178715b408dc6bf11f7" dependencies: - ajv "^6.0.1" - ajv-keywords "^3.0.0" - chalk "^2.1.0" - lodash "^4.17.4" + ajv "^6.5.3" + lodash "^4.17.10" slice-ansi "1.0.0" string-width "^2.1.1" @@ -6841,6 +8569,14 @@ tap-parser@^7.0.0: js-yaml "^3.2.7" minipass "^2.2.0" +tar@^2.0.0, tar@~2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + tar@^4: version "4.4.4" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" @@ -6878,16 +8614,16 @@ testdouble@^3.2.6: stringify-object-es5 "^2.5.0" theredoc "^1.0.0" -testem@^2.2.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/testem/-/testem-2.9.0.tgz#7ce11c11b4eec4192ec3d2ea7eaa216e08c34273" +testem@^2.9.2: + version "2.13.0" + resolved "https://registry.npmjs.org/testem/-/testem-2.13.0.tgz#587f3460a923779949804efac0fcc2015835dd63" dependencies: backbone "^1.1.2" bluebird "^3.4.6" charm "^1.0.0" commander "^2.6.0" consolidate "^0.15.1" - execa "^0.10.0" + execa "^1.0.0" express "^4.10.7" fireworm "^0.7.0" glob "^7.0.4" @@ -6899,20 +8635,21 @@ testem@^2.2.0: lodash.find "^4.5.1" lodash.uniqby "^4.7.0" mkdirp "^0.5.1" - mustache "^2.2.1" + mustache "^3.0.0" node-notifier "^5.0.1" npmlog "^4.0.0" - printf "^0.3.0" + printf "^0.5.1" rimraf "^2.4.4" socket.io "^2.1.0" spawn-args "^0.2.0" styled_string "0.0.1" tap-parser "^7.0.0" + tmp "0.0.33" xmldom "^0.1.19" -text-table@^0.2.0: +text-table@^0.2.0, text-table@~0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" "textextensions@1 || 2": version "2.2.0" @@ -6938,9 +8675,9 @@ timed-out@^4.0.0, timed-out@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" -tiny-lr@^1.0.3: +tiny-lr@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" + resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" dependencies: body "^5.1.0" debug "^3.1.0" @@ -6962,11 +8699,11 @@ tmp@0.0.28: dependencies: os-tmpdir "~1.0.1" -tmp@0.0.31: - version "0.0.31" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" +tmp@0.0.33, tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" dependencies: - os-tmpdir "~1.0.1" + os-tmpdir "~1.0.2" tmp@^0.0.29: version "0.0.29" @@ -6974,12 +8711,6 @@ tmp@^0.0.29: dependencies: os-tmpdir "~1.0.1" -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - dependencies: - os-tmpdir "~1.0.2" - tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -7022,14 +8753,18 @@ to-utf8@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" -tough-cookie@>=0.12.0: +tough-cookie@>=0.12.0, tough-cookie@~2.4.3: version "2.4.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" dependencies: psl "^1.1.24" punycode "^1.4.1" -tree-sync@^1.2.1, tree-sync@^1.2.2: +tough-cookie@~2.2.0: + version "2.2.2" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz#c83a1830f4e5ef0b93ef2a3488e724f8de016ac7" + +tree-sync@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" dependencies: @@ -7047,9 +8782,23 @@ trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" -tunnel-agent@~0.4.0: +tslib@^1.9.0: + version "1.9.3" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tunnel-agent@~0.4.0, tunnel-agent@~0.4.1: version "0.4.3" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" type-check@~0.3.2: version "0.3.2" @@ -7093,14 +8842,29 @@ uglify-js@^2.6: optionalDependencies: uglify-to-browserify "~1.0.0" +uglify-js@^3.1.4: + version "3.4.9" + resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" + dependencies: + commander "~2.17.1" + source-map "~0.6.1" + uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" +uid-number@0.0.6: + version "0.0.6" + resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" +umask@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" + underscore.string@^3.2.2, underscore.string@~3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" @@ -7112,6 +8876,25 @@ underscore@>=1.8.3: version "1.9.1" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz#9f1dc76926d6ccf452310564fd834ace059663d4" + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz#5a533f31b4317ea76f17d807fa0d116546111dd0" + union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" @@ -7121,6 +8904,18 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^0.4.3" +unique-filename@~1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz#5e9edc6d1ce8fb264db18a507ef9bd8544451ca6" + dependencies: + imurmurhash "^0.1.4" + unique-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" @@ -7152,9 +8947,9 @@ unzip-response@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" -uri-js@^4.2.1: +uri-js@^4.2.2: version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" dependencies: punycode "^2.1.0" @@ -7204,13 +8999,17 @@ util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" +util-extend@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" -uuid@^3.0.0: +uuid@^3.3.2: version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" validate-npm-package-license@^3.0.1: version "3.0.3" @@ -7225,10 +9024,24 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" +validate-npm-package-name@~2.2.2: + version "2.2.2" + resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-2.2.2.tgz#f65695b22f7324442019a3c7fa39a6e7fd299085" + dependencies: + builtins "0.0.7" + vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" +verror@1.10.0: + version "1.10.0" + resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + walk-sync@0.3.2, walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" @@ -7243,6 +9056,13 @@ walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" +walk-sync@^0.3.3: + version "0.3.3" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.3.tgz#1e9f12cd4fe6e0e6d4a0715b5cc7e30711d43cd1" + dependencies: + ensure-posix-path "^1.0.0" + matcher-collection "^1.0.0" + walker@~1.0.5: version "1.0.7" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" @@ -7259,10 +9079,6 @@ watch-detector@^0.1.0: semver "^5.4.1" silent-error "^1.1.0" -watch@~0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" - watch@~0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" @@ -7270,7 +9086,7 @@ watch@~0.18.0: exec-sh "^0.2.0" minimist "^1.2.0" -wcwidth@^1.0.1: +wcwidth@^1.0.0, wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" dependencies: @@ -7287,12 +9103,18 @@ websocket-extensions@>=0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" -which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0: +which@1, which@^1.2.14, which@^1.2.9, which@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" dependencies: isexe "^2.0.0" +which@~1.2.1: + version "1.2.14" + resolved "https://registry.npmjs.org/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" + dependencies: + isexe "^2.0.0" + wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" @@ -7321,7 +9143,13 @@ workerpool@^2.3.0: dependencies: object-assign "4.1.1" -wrappy@1: +workerpool@^2.3.1: + version "2.3.3" + resolved "https://registry.npmjs.org/workerpool/-/workerpool-2.3.3.tgz#49a70089bd55e890d68cc836a19419451d7c81d7" + dependencies: + object-assign "4.1.1" + +wrappy@1, wrappy@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -7333,6 +9161,14 @@ write-file-atomic@^2.0.0: imurmurhash "^0.1.4" signal-exit "^3.0.2" +write-file-atomic@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.1.4.tgz#b1f52dc2e8dc0e3cb04d187a25f758a38a90ca3b" + dependencies: + graceful-fs "^4.1.2" + imurmurhash "^0.1.4" + slide "^1.1.5" + write@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" From 6076a7fbc471de53492452d9c332a6dd39f77d32 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 25 Oct 2018 11:14:48 -0700 Subject: [PATCH 2386/2527] [CHORE tests] modernize integration/store/adapter-for-test * fix adapter-for-test for Ember 2.18 * [CHORE adapterFor] add test coverage for single instance per store instance --- addon/-private/system/store.js | 8 +- tests/integration/records/load-test.js | 1 + tests/integration/store/adapter-for-test.js | 329 ++++++++++++++++++++ tests/unit/store/lookup-test.js | 50 +-- 4 files changed, 338 insertions(+), 50 deletions(-) create mode 100644 tests/integration/store/adapter-for-test.js diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 1dc458d048f..68d042a587f 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -3065,7 +3065,9 @@ Store = Service.extend({ // no model specific adapter or application adapter, check for an `adapter` // property defined on the store let adapterName = this.get('adapter'); - adapter = _adapterCache[adapterName] || owner.lookup(`adapter:${adapterName}`); + adapter = adapterName + ? _adapterCache[adapterName] || owner.lookup(`adapter:${adapterName}`) + : undefined; if (adapter !== undefined) { set(adapter, 'store', this); _adapterCache[normalizedModelName] = adapter; @@ -3076,6 +3078,10 @@ Store = Service.extend({ // final fallback, no model specific adapter, no application adapter, no // `adapter` property on store: use json-api adapter adapter = _adapterCache['-json-api'] || owner.lookup('adapter:-json-api'); + assert( + `No adapter was found for '${modelName}' and no 'application', store.adapter = 'adapter-fallback-name', or '-json-api' adapter were found as fallbacks.`, + adapter !== undefined + ); set(adapter, 'store', this); _adapterCache[normalizedModelName] = adapter; _adapterCache['-json-api'] = adapter; diff --git a/tests/integration/records/load-test.js b/tests/integration/records/load-test.js index 6d36e05e0ac..95aa84775a4 100644 --- a/tests/integration/records/load-test.js +++ b/tests/integration/records/load-test.js @@ -12,6 +12,7 @@ import todo from '../../helpers/todo'; class Person extends Model { @attr name; + @belongsTo('person', { async: true, inverse: 'bestFriend' }) bestFriend; } diff --git a/tests/integration/store/adapter-for-test.js b/tests/integration/store/adapter-for-test.js new file mode 100644 index 00000000000..56b1ee64265 --- /dev/null +++ b/tests/integration/store/adapter-for-test.js @@ -0,0 +1,329 @@ +import { setupTest } from 'ember-qunit'; +import { module, test } from 'qunit'; +import Store from 'ember-data/store'; +import { run } from '@ember/runloop'; + +class TestAdapter { + constructor(args) { + Object.assign(this, args); + this.didInit(); + } + + didInit() {} + + static create(args) { + return new this(args); + } +} + +module('integration/store - adapterFor', function(hooks) { + setupTest(hooks); + let store; + + hooks.beforeEach(function() { + let { owner } = this; + store = owner.lookup('service:store'); + }); + + test('when no adapter is available we throw an error', async function(assert) { + let { owner } = this; + /* + ensure our store instance does not specify a fallback + we use an empty string as that would cause `owner.lookup` to blow up if not guarded properly + whereas `null` `undefined` `false` would not. + */ + store.adapter = ''; + /* + adapter:-json-api is the "last chance" fallback and is + registered automatically. + unregistering it will cause adapterFor to return `undefined`. + */ + owner.unregister('adapter:-json-api'); + + assert.expectAssertion(() => { + store.adapterFor('person'); + }, /No adapter was found for 'person' and no 'application', store\.adapter = 'adapter-fallback-name', or '-json-api' adapter were found as fallbacks\./); + }); + + test('we find and instantiate the application adapter', async function(assert) { + let { owner } = this; + let didInstantiate = false; + + class AppAdapter extends TestAdapter { + didInit() { + didInstantiate = true; + } + } + + owner.register('adapter:application', AppAdapter); + + let adapter = store.adapterFor('application'); + + assert.ok(adapter instanceof AppAdapter, 'We found the correct adapter'); + assert.ok(didInstantiate, 'We instantiated the adapter'); + didInstantiate = false; + + let adapterAgain = store.adapterFor('application'); + + assert.ok(adapterAgain instanceof AppAdapter, 'We found the correct adapter'); + assert.ok(!didInstantiate, 'We did not instantiate the adapter again'); + assert.ok(adapter === adapterAgain, 'Repeated calls to adapterFor return the same instance'); + }); + + test('multiple stores do not share adapters', async function(assert) { + let { owner } = this; + let didInstantiate = false; + + class AppAdapter extends TestAdapter { + didInit() { + didInstantiate = true; + } + } + + owner.register('adapter:application', AppAdapter); + owner.register('service:other-store', Store); + + let otherStore = owner.lookup('service:other-store'); + let adapter = store.adapterFor('application'); + + assert.ok(adapter instanceof AppAdapter, 'We found the correct adapter'); + assert.ok(didInstantiate, 'We instantiated the adapter'); + didInstantiate = false; + + let otherAdapter = otherStore.adapterFor('application'); + assert.ok(otherAdapter instanceof AppAdapter, 'We found the correct adapter again'); + assert.ok(didInstantiate, 'We instantiated the other adapter'); + assert.ok(otherAdapter !== adapter, 'We have a different adapter instance'); + + // Ember 2.18 requires us to wrap destroy in a run. Use `await settled()` for newer versions. + run(() => otherStore.destroy()); + }); + + test('we can find and instantiate per-type adapters', async function(assert) { + let { owner } = this; + let didInstantiateAppAdapter = false; + let didInstantiatePersonAdapter = false; + + class AppAdapter extends TestAdapter { + didInit() { + didInstantiateAppAdapter = true; + } + } + + class PersonAdapter extends TestAdapter { + didInit() { + didInstantiatePersonAdapter = true; + } + } + + owner.register('adapter:application', AppAdapter); + owner.register('adapter:person', PersonAdapter); + + let adapter = store.adapterFor('person'); + + assert.ok(adapter instanceof PersonAdapter, 'We found the correct adapter'); + assert.ok(didInstantiatePersonAdapter, 'We instantiated the person adapter'); + assert.ok(!didInstantiateAppAdapter, 'We did not instantiate the application adapter'); + + let appAdapter = store.adapterFor('application'); + assert.ok(appAdapter instanceof AppAdapter, 'We found the correct adapter'); + assert.ok(didInstantiateAppAdapter, 'We instantiated the application adapter'); + assert.ok(appAdapter !== adapter, 'We have separate adapters'); + }); + + test('we fallback to the application adapter when a per-type adapter is not found', async function(assert) { + let { owner } = this; + let didInstantiateAppAdapter = false; + + class AppAdapter extends TestAdapter { + didInit() { + didInstantiateAppAdapter = true; + } + } + + owner.register('adapter:application', AppAdapter); + + let adapter = store.adapterFor('person'); + + assert.ok(adapter instanceof AppAdapter, 'We found the adapter'); + assert.ok(didInstantiateAppAdapter, 'We instantiated the adapter'); + didInstantiateAppAdapter = false; + + let appAdapter = store.adapterFor('application'); + assert.ok(appAdapter instanceof AppAdapter, 'We found the correct adapter'); + assert.ok(!didInstantiateAppAdapter, 'We did not instantiate the adapter again'); + assert.ok(appAdapter === adapter, 'We fell back to the application adapter instance'); + }); + + test('we can specify a fallback adapter by name in place of the application adapter', async function(assert) { + store.adapter = '-rest'; + let { owner } = this; + + let didInstantiateRestAdapter = false; + + class RestAdapter extends TestAdapter { + didInit() { + didInstantiateRestAdapter = true; + } + } + owner.register('adapter:-rest', RestAdapter); + + let adapter = store.adapterFor('person'); + + assert.ok(adapter instanceof RestAdapter, 'We found the fallback -rest adapter for person'); + assert.ok(didInstantiateRestAdapter, 'We instantiated the adapter'); + didInstantiateRestAdapter = false; + + let appAdapter = store.adapterFor('application'); + + assert.ok( + appAdapter instanceof RestAdapter, + 'We found the fallback -rest adapter for application' + ); + assert.ok(!didInstantiateRestAdapter, 'We did not instantiate the adapter again'); + didInstantiateRestAdapter = false; + + let restAdapter = store.adapterFor('-rest'); + assert.ok(restAdapter instanceof RestAdapter, 'We found the correct adapter'); + assert.ok(!didInstantiateRestAdapter, 'We did not instantiate the adapter again'); + assert.ok( + restAdapter === adapter, + 'We fell back to the -rest adapter instance for the person adapters' + ); + assert.ok( + restAdapter === appAdapter, + 'We fell back to the -rest adapter instance for the application adapter' + ); + }); + + test('the application adapter has higher precedence than a fallback adapter defined via store.adapter', async function(assert) { + store.adapter = '-rest'; + let { owner } = this; + + let didInstantiateAppAdapter = false; + let didInstantiateRestAdapter = false; + + class AppAdapter extends TestAdapter { + didInit() { + didInstantiateAppAdapter = true; + } + } + + class RestAdapter extends TestAdapter { + didInit() { + didInstantiateRestAdapter = true; + } + } + + owner.register('adapter:application', AppAdapter); + owner.register('adapter:-rest', RestAdapter); + + let adapter = store.adapterFor('person'); + + assert.ok(adapter instanceof AppAdapter, 'We found the store specified fallback adapter'); + assert.ok( + !didInstantiateRestAdapter, + 'We did not instantiate the store.adapter (-rest) adapter' + ); + assert.ok(didInstantiateAppAdapter, 'We instantiated the application adapter'); + didInstantiateRestAdapter = false; + didInstantiateAppAdapter = false; + + let appAdapter = store.adapterFor('application'); + assert.ok(appAdapter instanceof AppAdapter, 'We found the correct adapter for application'); + assert.ok(!didInstantiateRestAdapter, 'We did not instantiate the store fallback adapter'); + assert.ok(!didInstantiateAppAdapter, 'We did not instantiate the application adapter again'); + assert.ok(appAdapter === adapter, 'We used the application adapter as the person adapter'); + didInstantiateRestAdapter = false; + didInstantiateAppAdapter = false; + + let restAdapter = store.adapterFor('-rest'); + assert.ok(restAdapter instanceof RestAdapter, 'We found the correct adapter for -rest'); + assert.ok(!didInstantiateAppAdapter, 'We did not instantiate the application adapter again'); + assert.ok(didInstantiateRestAdapter, 'We instantiated the fallback adapter'); + assert.ok(restAdapter !== appAdapter, `We did not use the application adapter instance`); + }); + + test('we can specify a fallback adapter by name in place of the application adapter', async function(assert) { + store.adapter = '-rest'; + let { owner } = this; + + let didInstantiateRestAdapter = false; + + class RestAdapter extends TestAdapter { + didInit() { + didInstantiateRestAdapter = true; + } + } + owner.register('adapter:-rest', RestAdapter); + + let adapter = store.adapterFor('application'); + + assert.ok(adapter instanceof RestAdapter, 'We found the adapter'); + assert.ok(didInstantiateRestAdapter, 'We instantiated the adapter'); + didInstantiateRestAdapter = false; + + let restAdapter = store.adapterFor('-rest'); + assert.ok(restAdapter instanceof RestAdapter, 'We found the correct adapter'); + assert.ok(!didInstantiateRestAdapter, 'We did not instantiate the adapter again'); + assert.ok( + restAdapter === adapter, + 'We fell back to the -rest adapter instance for the application adapter' + ); + }); + + test('When the per-type, application and specified fallback adapters do not exist, we fallback to the -json-api adapter', async function(assert) { + store.adapter = '-not-a-real-adapter'; + let { owner } = this; + + let didInstantiateAdapter = false; + + class JsonApiAdapter extends TestAdapter { + didInit() { + didInstantiateAdapter = true; + } + } + owner.unregister('adapter:-json-api'); + owner.register('adapter:-json-api', JsonApiAdapter); + + let adapter = store.adapterFor('person'); + + assert.ok(adapter instanceof JsonApiAdapter, 'We found the adapter'); + assert.ok(didInstantiateAdapter, 'We instantiated the adapter'); + didInstantiateAdapter = false; + + let appAdapter = store.adapterFor('application'); + + assert.ok( + appAdapter instanceof JsonApiAdapter, + 'We found the fallback -json-api adapter for application' + ); + assert.ok(!didInstantiateAdapter, 'We did not instantiate the adapter again'); + didInstantiateAdapter = false; + + let fallbackAdapter = store.adapterFor('-not-a-real-adapter'); + + assert.ok( + fallbackAdapter instanceof JsonApiAdapter, + 'We found the fallback -json-api adapter for application' + ); + assert.ok(!didInstantiateAdapter, 'We did not instantiate the adapter again'); + didInstantiateAdapter = false; + + let jsonApiAdapter = store.adapterFor('-json-api'); + assert.ok(jsonApiAdapter instanceof JsonApiAdapter, 'We found the correct adapter'); + assert.ok(!didInstantiateAdapter, 'We did not instantiate the adapter again'); + assert.ok( + jsonApiAdapter === appAdapter, + 'We fell back to the -json-api adapter instance for application' + ); + assert.ok( + jsonApiAdapter === fallbackAdapter, + 'We fell back to the -json-api adapter instance for the fallback -not-a-real-adapter' + ); + assert.ok( + jsonApiAdapter === adapter, + 'We fell back to the -json-api adapter instance for the per-type adapter' + ); + }); +}); diff --git a/tests/unit/store/lookup-test.js b/tests/unit/store/lookup-test.js index ac96f6ff363..4901663fb53 100644 --- a/tests/unit/store/lookup-test.js +++ b/tests/unit/store/lookup-test.js @@ -5,7 +5,7 @@ import { module, test } from 'qunit'; import DS from 'ember-data'; -let store, env, applicationAdapter, applicationSerializer, Person; +let store, env, applicationSerializer, Person; function resetStore() { if (store) { @@ -25,10 +25,6 @@ function resetStore() { store = env.store; } -function lookupAdapter(adapterName) { - return run(store, 'adapterFor', adapterName); -} - function lookupSerializer(serializerName) { return run(store, 'serializerFor', serializerName); } @@ -48,7 +44,6 @@ module('unit/store/lookup - Managed Instance lookups', { env.registry.register('adapter:application', DS.Adapter.extend()); env.registry.register('adapter:serializer', DS.Adapter.extend()); - applicationAdapter = run(store, 'adapterFor', 'application'); applicationSerializer = run(store, 'serializerFor', 'application'); }, @@ -57,19 +52,6 @@ module('unit/store/lookup - Managed Instance lookups', { }, }); -test('when the adapter does not exist for a type, the fallback is returned', assert => { - let personAdapter = lookupAdapter('person'); - - assert.strictEqual(personAdapter, applicationAdapter); -}); - -test('when the adapter for a type exists, returns that instead of the fallback', assert => { - registerAdapter('person', DS.Adapter.extend()); - let personAdapter = lookupAdapter('person'); - - assert.ok(personAdapter !== applicationAdapter); -}); - test('when the serializer does not exist for a type, the fallback is returned', assert => { let personSerializer = lookupSerializer('person'); @@ -84,36 +66,6 @@ test('when the serializer does exist for a type, the serializer is returned', as assert.ok(personSerializer !== applicationSerializer); }); -test('adapter lookup order', assert => { - assert.expect(3); - - resetStore(); - - let personAdapter = lookupAdapter('person'); - - assert.strictEqual(personAdapter, lookupAdapter('-rest'), 'looks up the RESTAdapter first'); - resetStore(); - - registerAdapter('application', DS.RESTSerializer.extend()); - personAdapter = lookupAdapter('person'); - - assert.strictEqual( - personAdapter, - lookupAdapter('application'), - 'looks up application adapter before RESTAdapter if it exists' - ); - - resetStore(); - - registerAdapter('application', DS.RESTSerializer.extend()); - registerAdapter('person', DS.RESTSerializer.extend({ customThingy: true })); - - assert.ok( - lookupAdapter('person').get('customThingy'), - 'looks up type serializer before application' - ); -}); - test('serializer lookup order', assert => { resetStore(); From f9876d600d9ca1ff9dc9a57283cfee890fb95bd8 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 25 Oct 2018 19:34:02 -0700 Subject: [PATCH 2387/2527] bump ember-cli to 3.5 and upgrade blueprint compat --- blueprints/test-framework-detector.js | 7 ++- node-tests/blueprints/adapter-test.js | 50 +++++++++++----------- node-tests/blueprints/model-test.js | 54 ++++++++++++------------ node-tests/blueprints/serializer-test.js | 50 +++++++++++----------- node-tests/blueprints/transform-test.js | 36 ++++++++++------ package.json | 2 +- yarn.lock | 34 +++++---------- 7 files changed, 117 insertions(+), 116 deletions(-) diff --git a/blueprints/test-framework-detector.js b/blueprints/test-framework-detector.js index 549a96cdc47..181291750fd 100644 --- a/blueprints/test-framework-detector.js +++ b/blueprints/test-framework-detector.js @@ -13,8 +13,13 @@ module.exports = function(blueprint) { let type; let dependencies = this.project.dependencies(); + if ('ember-qunit' in dependencies) { - type = 'qunit-rfc-232'; + if (fs.existsSync(this.path + '/qunit-rfc-232-files')) { + type = 'qunit-rfc-232'; + } else { + type = 'qunit'; + } } else if ('ember-cli-qunit' in dependencies) { let checker = new VersionChecker(this.project); if ( diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 5366e86dea8..72cdab0bf93 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -32,7 +32,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { .to.contain('export default DS.JSONAPIAdapter.extend({'); expect(_file('tests/unit/adapters/foo-test.js')).to.equal( - fixture('adapter-test/foo-default.js') + fixture('adapter-test/rfc232.js') ); }); }); @@ -47,7 +47,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { .to.contain('export default ApplicationAdapter.extend({'); expect(_file('tests/unit/adapters/foo-test.js')).to.equal( - fixture('adapter-test/foo-default.js') + fixture('adapter-test/rfc232.js') ); }) ); @@ -62,7 +62,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { .to.contain('export default BarAdapter.extend({'); expect(_file('tests/unit/adapters/foo-test.js')).to.equal( - fixture('adapter-test/foo-default.js') + fixture('adapter-test/rfc232.js') ); }); }); @@ -95,20 +95,24 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { return emberGenerateDestroy(args, _file => { expect(_file('tests/unit/adapters/foo-test.js')).to.equal( - fixture('adapter-test/foo-default.js') + fixture('adapter-test/rfc232.js') ); }); }); - describe('adapter-test with ember-cli-qunit@4.2.0', function() { + describe('adapter-test with ember-cli-qunit@4.1.0', function() { beforeEach(function() { - generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-qunit', delete: true }, + ]); + generateFakePackageManifest('ember-cli-qunit', '4.1.0'); }); it('adapter-test-test foo', function() { return emberGenerateDestroy(['adapter-test', 'foo'], _file => { expect(_file('tests/unit/adapters/foo-test.js')).to.equal( - fixture('adapter-test/rfc232.js') + fixture('adapter-test/foo-default.js') ); }); }); @@ -117,7 +121,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { describe('with ember-cli-mocha v0.12+', function() { beforeEach(function() { modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-qunit', delete: true }, { name: 'ember-cli-mocha', dev: true }, ]); generateFakePackageManifest('ember-cli-mocha', '0.12.0'); @@ -136,10 +140,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { describe('with ember-mocha v0.14+', function() { beforeEach(function() { - modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-mocha', dev: true }, - ]); + modifyPackages([{ name: 'ember-qunit', delete: true }, { name: 'ember-mocha', dev: true }]); generateFakePackageManifest('ember-mocha', '0.14.0'); }); @@ -169,7 +170,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { .to.contain('export default DS.JSONAPIAdapter.extend({'); expect(_file('src/data/models/foo/adapter-test.js')).to.equal( - fixture('adapter-test/foo-default.js') + fixture('adapter-test/rfc232.js') ); }, { isModuleUnification: true } @@ -188,7 +189,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { .to.contain('export default ApplicationAdapter.extend({'); expect(_file('src/data/models/foo/adapter-test.js')).to.equal( - fixture('adapter-test/foo-default.js') + fixture('adapter-test/rfc232.js') ); }, { isModuleUnification: true } @@ -207,7 +208,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { .to.contain('export default BarAdapter.extend({'); expect(_file('src/data/models/foo/adapter-test.js')).to.equal( - fixture('adapter-test/foo-default.js') + fixture('adapter-test/rfc232.js') ); }, { isModuleUnification: true } @@ -239,16 +240,20 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { args, _file => { expect(_file('src/data/models/foo/adapter-test.js')).to.equal( - fixture('adapter-test/foo-default.js') + fixture('adapter-test/rfc232.js') ); }, { isModuleUnification: true } ); }); - describe('adapter-test with ember-cli-qunit@4.2.0', function() { + describe('adapter-test with ember-cli-qunit@4.1.0', function() { beforeEach(function() { - generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-qunit', delete: true }, + ]); + generateFakePackageManifest('ember-cli-qunit', '4.1.0'); }); it('adapter-test-test foo', function() { @@ -256,7 +261,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { ['adapter-test', 'foo'], _file => { expect(_file('src/data/models/foo/adapter-test.js')).to.equal( - fixture('adapter-test/rfc232.js') + fixture('adapter-test/foo-default.js') ); }, { isModuleUnification: true } @@ -267,7 +272,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { describe('with ember-cli-mocha v0.12+', function() { beforeEach(function() { modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-qunit', delete: true }, { name: 'ember-cli-mocha', dev: true }, ]); generateFakePackageManifest('ember-cli-mocha', '0.12.0'); @@ -290,10 +295,7 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { describe('with ember-mocha v0.14+', function() { beforeEach(function() { - modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-mocha', dev: true }, - ]); + modifyPackages([{ name: 'ember-qunit', delete: true }, { name: 'ember-mocha', dev: true }]); generateFakePackageManifest('ember-mocha', '0.14.0'); }); diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index b1c7f6f78c9..c4e6db794c7 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -28,9 +28,7 @@ describe('Acceptance: generate and destroy model blueprints', function() { .to.contain("import DS from 'ember-data';") .to.contain('export default DS.Model.extend('); - expect(_file('tests/unit/models/foo-test.js')).to.equal( - fixture('model-test/foo-default.js') - ); + expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/rfc232.js')); }); }); @@ -61,9 +59,7 @@ describe('Acceptance: generate and destroy model blueprints', function() { .to.contain("name: DS.attr('string')") .to.contain("customAttr: DS.attr('custom-transform')"); - expect(_file('tests/unit/models/foo-test.js')).to.equal( - fixture('model-test/foo-default.js') - ); + expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/rfc232.js')); }); }); @@ -103,20 +99,24 @@ describe('Acceptance: generate and destroy model blueprints', function() { let args = ['model-test', 'foo']; return emberGenerateDestroy(args, _file => { - expect(_file('tests/unit/models/foo-test.js')).to.equal( - fixture('model-test/foo-default.js') - ); + expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/rfc232.js')); }); }); - describe('model-test with ember-cli-qunit@4.2.0', function() { + describe('model-test with ember-cli-qunit@4.1.0', function() { beforeEach(function() { - generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-qunit', delete: true }, + ]); + generateFakePackageManifest('ember-cli-qunit', '4.1.0'); }); it('model-test-test foo', function() { return emberGenerateDestroy(['model-test', 'foo'], _file => { - expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/rfc232.js')); + expect(_file('tests/unit/models/foo-test.js')).to.equal( + fixture('model-test/foo-default.js') + ); }); }); }); @@ -124,7 +124,7 @@ describe('Acceptance: generate and destroy model blueprints', function() { describe('with ember-cli-mocha v0.12+', function() { beforeEach(function() { modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-qunit', delete: true }, { name: 'ember-cli-mocha', dev: true }, ]); generateFakePackageManifest('ember-cli-mocha', '0.12.0'); @@ -143,10 +143,7 @@ describe('Acceptance: generate and destroy model blueprints', function() { describe('with ember-mocha v0.14+', function() { beforeEach(function() { - modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-mocha', dev: true }, - ]); + modifyPackages([{ name: 'ember-qunit', delete: true }, { name: 'ember-mocha', dev: true }]); generateFakePackageManifest('ember-mocha', '0.14.0'); }); @@ -178,7 +175,7 @@ describe('Acceptance: generate and destroy model blueprints', function() { .to.contain('export default DS.Model.extend('); expect(_file('src/data/models/foo/model-test.js')).to.equal( - fixture('model-test/foo-default.js') + fixture('model-test/rfc232.js') ); }, { isModuleUnification: true } @@ -215,7 +212,7 @@ describe('Acceptance: generate and destroy model blueprints', function() { .to.contain("customAttr: DS.attr('custom-transform')"); expect(_file('src/data/models/foo/model-test.js')).to.equal( - fixture('model-test/foo-default.js') + fixture('model-test/rfc232.js') ); }, { isModuleUnification: true } @@ -269,16 +266,20 @@ describe('Acceptance: generate and destroy model blueprints', function() { args, _file => { expect(_file('src/data/models/foo/model-test.js')).to.equal( - fixture('model-test/foo-default.js') + fixture('model-test/rfc232.js') ); }, { isModuleUnification: true } ); }); - describe('model-test with ember-cli-qunit@4.2.0', function() { + describe('model-test with ember-cli-qunit@4.1.0', function() { beforeEach(function() { - generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-qunit', delete: true }, + ]); + generateFakePackageManifest('ember-cli-qunit', '4.1.0'); }); it('model-test-test foo', function() { @@ -286,7 +287,7 @@ describe('Acceptance: generate and destroy model blueprints', function() { ['model-test', 'foo'], _file => { expect(_file('src/data/models/foo/model-test.js')).to.equal( - fixture('model-test/rfc232.js') + fixture('model-test/foo-default.js') ); }, { isModuleUnification: true } @@ -297,7 +298,7 @@ describe('Acceptance: generate and destroy model blueprints', function() { describe('with ember-cli-mocha v0.12+', function() { beforeEach(function() { modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-qunit', delete: true }, { name: 'ember-cli-mocha', dev: true }, ]); generateFakePackageManifest('ember-cli-mocha', '0.12.0'); @@ -320,10 +321,7 @@ describe('Acceptance: generate and destroy model blueprints', function() { describe('with ember-mocha v0.14+', function() { beforeEach(function() { - modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-mocha', dev: true }, - ]); + modifyPackages([{ name: 'ember-qunit', delete: true }, { name: 'ember-mocha', dev: true }]); generateFakePackageManifest('ember-mocha', '0.14.0'); }); diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index 5f6766342d5..23169cc78a7 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -32,7 +32,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { .to.contain('export default DS.JSONAPISerializer.extend('); expect(_file('tests/unit/serializers/foo-test.js')).to.equal( - fixture('serializer-test/foo-default.js') + fixture('serializer-test/rfc232.js') ); }); }); @@ -47,7 +47,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { .to.contain('export default ApplicationSerializer.extend({'); expect(_file('tests/unit/serializers/foo-test.js')).to.equal( - fixture('serializer-test/foo-default.js') + fixture('serializer-test/rfc232.js') ); }) ); @@ -62,7 +62,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { .to.contain('export default BarSerializer.extend({'); expect(_file('tests/unit/serializers/foo-test.js')).to.equal( - fixture('serializer-test/foo-default.js') + fixture('serializer-test/rfc232.js') ); }); }); @@ -95,20 +95,24 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { return emberGenerateDestroy(args, _file => { expect(_file('tests/unit/serializers/foo-test.js')).to.equal( - fixture('serializer-test/foo-default.js') + fixture('serializer-test/rfc232.js') ); }); }); - describe('serializer-test with ember-cli-qunit@4.2.0', function() { + describe('serializer-test with ember-cli-qunit@4.1.0', function() { beforeEach(function() { - generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-qunit', delete: true }, + ]); + generateFakePackageManifest('ember-cli-qunit', '4.1.0'); }); it('serializer-test-test foo', function() { return emberGenerateDestroy(['serializer-test', 'foo'], _file => { expect(_file('tests/unit/serializers/foo-test.js')).to.equal( - fixture('serializer-test/rfc232.js') + fixture('serializer-test/foo-default.js') ); }); }); @@ -117,7 +121,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { describe('with ember-cli-mocha v0.12+', function() { beforeEach(function() { modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-qunit', delete: true }, { name: 'ember-cli-mocha', dev: true }, ]); generateFakePackageManifest('ember-cli-mocha', '0.12.0'); @@ -136,10 +140,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { describe('with ember-mocha v0.14+', function() { beforeEach(function() { - modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-mocha', dev: true }, - ]); + modifyPackages([{ name: 'ember-qunit', delete: true }, { name: 'ember-mocha', dev: true }]); generateFakePackageManifest('ember-mocha', '0.14.0'); }); @@ -171,7 +172,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { .to.contain('export default DS.JSONAPISerializer.extend('); expect(_file('src/data/models/foo/serializer-test.js')).to.equal( - fixture('serializer-test/foo-default.js') + fixture('serializer-test/rfc232.js') ); }, { isModuleUnification: true } @@ -190,7 +191,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { .to.contain('export default ApplicationSerializer.extend({'); expect(_file('src/data/models/foo/serializer-test.js')).to.equal( - fixture('serializer-test/foo-default.js') + fixture('serializer-test/rfc232.js') ); }, { isModuleUnification: true } @@ -209,7 +210,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { .to.contain('export default BarSerializer.extend({'); expect(_file('src/data/models/foo/serializer-test.js')).to.equal( - fixture('serializer-test/foo-default.js') + fixture('serializer-test/rfc232.js') ); }, { isModuleUnification: true } @@ -250,16 +251,20 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { args, _file => { expect(_file('src/data/models/foo/serializer-test.js')).to.equal( - fixture('serializer-test/foo-default.js') + fixture('serializer-test/rfc232.js') ); }, { isModuleUnification: true } ); }); - describe('serializer-test with ember-cli-qunit@4.2.0', function() { + describe('serializer-test with ember-cli-qunit@4.1.0', function() { beforeEach(function() { - generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-qunit', delete: true }, + ]); + generateFakePackageManifest('ember-cli-qunit', '4.1.0'); }); it('serializer-test-test foo', function() { @@ -267,7 +272,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { ['serializer-test', 'foo'], _file => { expect(_file('src/data/models/foo/serializer-test.js')).to.equal( - fixture('serializer-test/rfc232.js') + fixture('serializer-test/foo-default.js') ); }, { isModuleUnification: true } @@ -278,7 +283,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { describe('with ember-cli-mocha v0.12+', function() { beforeEach(function() { modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-qunit', delete: true }, { name: 'ember-cli-mocha', dev: true }, ]); generateFakePackageManifest('ember-cli-mocha', '0.12.0'); @@ -301,10 +306,7 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { describe('with ember-mocha v0.14+', function() { beforeEach(function() { - modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, - { name: 'ember-mocha', dev: true }, - ]); + modifyPackages([{ name: 'ember-qunit', delete: true }, { name: 'ember-mocha', dev: true }]); generateFakePackageManifest('ember-mocha', '0.14.0'); }); diff --git a/node-tests/blueprints/transform-test.js b/node-tests/blueprints/transform-test.js index f6ac63d27fe..987893e267d 100644 --- a/node-tests/blueprints/transform-test.js +++ b/node-tests/blueprints/transform-test.js @@ -32,7 +32,7 @@ describe('Acceptance: generate and destroy transform blueprints', function() { .to.contain('serialize(deserialized) {'); expect(_file('tests/unit/transforms/foo-test.js')).to.equal( - fixture('transform-test/default.js') + fixture('transform-test/rfc232.js') ); }); }); @@ -42,20 +42,24 @@ describe('Acceptance: generate and destroy transform blueprints', function() { return emberGenerateDestroy(args, _file => { expect(_file('tests/unit/transforms/foo-test.js')).to.equal( - fixture('transform-test/default.js') + fixture('transform-test/rfc232.js') ); }); }); - describe('transform-test with ember-cli-qunit@4.2.0', function() { + describe('transform-test with ember-cli-qunit@4.1.0', function() { beforeEach(function() { - generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-qunit', delete: true }, + ]); + generateFakePackageManifest('ember-cli-qunit', '4.1.0'); }); it('transform-test-test foo', function() { return emberGenerateDestroy(['transform-test', 'foo'], _file => { expect(_file('tests/unit/transforms/foo-test.js')).to.equal( - fixture('transform-test/rfc232.js') + fixture('transform-test/default.js') ); }); }); @@ -64,7 +68,7 @@ describe('Acceptance: generate and destroy transform blueprints', function() { describe('with ember-cli-mocha v0.12+', function() { beforeEach(function() { modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-qunit', delete: true }, { name: 'ember-cli-mocha', dev: true }, ]); generateFakePackageManifest('ember-cli-mocha', '0.12.0'); @@ -84,7 +88,7 @@ describe('Acceptance: generate and destroy transform blueprints', function() { describe('with ember-mocha v0.14+', function() { beforeEach(function() { modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-qunit', delete: true }, { name: 'ember-mocha', dev: true }, ]); generateFakePackageManifest('ember-mocha', '0.14.0'); @@ -122,7 +126,7 @@ describe('Acceptance: generate and destroy transform blueprints', function() { .to.contain('serialize(deserialized) {'); expect(_file('src/data/transforms/foo-test.js')).to.equal( - fixture('transform-test/default.js') + fixture('transform-test/rfc232.js') ); }, { isModuleUnification: true } @@ -136,16 +140,20 @@ describe('Acceptance: generate and destroy transform blueprints', function() { args, _file => { expect(_file('src/data/transforms/foo-test.js')).to.equal( - fixture('transform-test/default.js') + fixture('transform-test/rfc232.js') ); }, { isModuleUnification: true } ); }); - describe('transform-test with ember-cli-qunit@4.2.0', function() { + describe('transform-test with ember-cli-qunit@4.1.0', function() { beforeEach(function() { - generateFakePackageManifest('ember-cli-qunit', '4.2.0'); + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-qunit', delete: true }, + ]); + generateFakePackageManifest('ember-cli-qunit', '4.1.0'); }); it('transform-test-test foo', function() { @@ -153,7 +161,7 @@ describe('Acceptance: generate and destroy transform blueprints', function() { ['transform-test', 'foo'], _file => { expect(_file('src/data/transforms/foo-test.js')).to.equal( - fixture('transform-test/rfc232.js') + fixture('transform-test/default.js') ); }, { isModuleUnification: true } @@ -164,7 +172,7 @@ describe('Acceptance: generate and destroy transform blueprints', function() { describe('with ember-cli-mocha v0.12+', function() { beforeEach(function() { modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-qunit', delete: true }, { name: 'ember-cli-mocha', dev: true }, ]); generateFakePackageManifest('ember-cli-mocha', '0.12.0'); @@ -188,7 +196,7 @@ describe('Acceptance: generate and destroy transform blueprints', function() { describe('with ember-mocha v0.14+', function() { beforeEach(function() { modifyPackages([ - { name: 'ember-cli-qunit', delete: true }, + { name: 'ember-qunit', delete: true }, { name: 'ember-mocha', dev: true }, ]); generateFakePackageManifest('ember-mocha', '0.14.0'); diff --git a/package.json b/package.json index 8f3d2d3721c..9f2a3ded657 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "broccoli-uglify-sourcemap": "^2.2.0", "co": "^4.6.0", "common-tags": "^1.8.0", - "ember-cli": "~3.4.3", + "ember-cli": "^3.5.0", "ember-cli-app-version": "^3.2.0", "ember-cli-blueprint-test-helpers": "^0.19.1", "ember-cli-dependency-checker": "^3.0.0", diff --git a/yarn.lock b/yarn.lock index a13c2f27415..d1e5f4fbb1e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1757,9 +1757,9 @@ braces@^2.3.1: split-string "^3.0.2" to-regex "^3.0.1" -broccoli-amd-funnel@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/broccoli-amd-funnel/-/broccoli-amd-funnel-1.3.0.tgz#c4426b4fce976e44295bd74f34725f53bdeb08e3" +broccoli-amd-funnel@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/broccoli-amd-funnel/-/broccoli-amd-funnel-2.0.1.tgz#dbdbfd28841731342d538126567c25bea3f15310" dependencies: broccoli-plugin "^1.3.0" symlink-or-copy "^1.2.0" @@ -3326,15 +3326,16 @@ ember-cli-yuidoc@^0.8.8: rsvp "3.0.14" yuidocjs "^0.10.0" -ember-cli@~3.4.3: - version "3.4.3" - resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-3.4.3.tgz#33560c6416612bd8dc56858cffb2c81897ec8822" +ember-cli@^3.5.0: + version "3.5.0" + resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-3.5.0.tgz#978031042611008dce82c79226b8b677d325072c" dependencies: amd-name-resolver "^1.2.0" babel-plugin-transform-es2015-modules-amd "^6.24.1" bower-config "^1.3.0" bower-endpoint-parser "0.2.2" - broccoli-amd-funnel "^1.3.0" + broccoli "^2.0.0" + broccoli-amd-funnel "^2.0.1" broccoli-babel-transpiler "^6.5.0" broccoli-builder "^0.18.14" broccoli-concat "^3.5.1" @@ -3373,6 +3374,7 @@ ember-cli@~3.4.3: filesize "^3.6.1" find-up "^3.0.0" find-yarn-workspace-root "^1.1.0" + fixturify "^0.3.4" fixturify-project "^1.5.3" fs-extra "^7.0.0" fs-tree-diff "^0.5.7" @@ -3403,7 +3405,7 @@ ember-cli@~3.4.3: quick-temp "^0.1.8" resolve "^1.8.1" rsvp "^4.8.3" - sane "^3.0.0" + sane "^4.0.0" semver "^5.5.0" silent-error "^1.1.0" sort-package-json "^1.15.0" @@ -8032,22 +8034,6 @@ sane@^2.4.1, sane@^2.5.2: optionalDependencies: fsevents "^1.2.3" -sane@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/sane/-/sane-3.1.0.tgz#995193b7dc1445ef1fe41ddfca2faf9f111854c6" - dependencies: - anymatch "^2.0.0" - capture-exit "^1.2.0" - exec-sh "^0.2.0" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - watch "~0.18.0" - optionalDependencies: - fsevents "^1.2.3" - sane@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/sane/-/sane-4.0.1.tgz#af1e10466e924e1b888c104bb9925a0f1beb46dd" From e34cb5a37391ce2e5d25401ca189a9bd19a29340 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 23 Oct 2018 15:00:44 -0700 Subject: [PATCH 2388/2527] [CHORE tests] modernize integration/peek-all-test --- tests/integration/peek-all-test.js | 75 ++++++++++++++---------------- 1 file changed, 34 insertions(+), 41 deletions(-) diff --git a/tests/integration/peek-all-test.js b/tests/integration/peek-all-test.js index 28560111ac6..4290f4295f6 100644 --- a/tests/integration/peek-all-test.js +++ b/tests/integration/peek-all-test.js @@ -1,16 +1,29 @@ import { get } from '@ember/object'; -import { run } from '@ember/runloop'; -import { createStore } from 'dummy/tests/helpers/store'; - +import { setupTest } from 'ember-qunit'; +import Model from 'ember-data/model'; +import { attr } from '@ember-decorators/data'; import { module, test } from 'qunit'; +import { settled } from '@ember/test-helpers'; + +class Person extends Model { + @attr + name; +} + +module('integration/peek-all - DS.Store#peekAll()', function(hooks) { + setupTest(hooks); -import DS from 'ember-data'; + let store; -let Person, store, array, moreArray; + hooks.beforeEach(function() { + let { owner } = this; + + owner.register('model:person', Person); + store = owner.lookup('service:store'); + }); -module('integration/peek-all - DS.Store#peekAll()', { - beforeEach() { - array = { + test("store.peekAll('person') should return all records and should update with new ones", async function(assert) { + store.push({ data: [ { type: 'person', @@ -27,8 +40,12 @@ module('integration/peek-all - DS.Store#peekAll()', { }, }, ], - }; - moreArray = { + }); + + let all = store.peekAll('person'); + assert.equal(get(all, 'length'), 2); + + store.push({ data: [ { type: 'person', @@ -38,38 +55,16 @@ module('integration/peek-all - DS.Store#peekAll()', { }, }, ], - }; - - Person = DS.Model.extend({ name: DS.attr('string') }); - - store = createStore({ person: Person }); - }, - afterEach() { - run(store, 'destroy'); - Person = null; - array = null; - }, -}); - -test("store.peekAll('person') should return all records and should update with new ones", function(assert) { - run(() => { - store.push(array); - }); + }); - let all = store.peekAll('person'); - assert.equal(get(all, 'length'), 2); + await settled(); - run(() => { - store.push(moreArray); + assert.equal(get(all, 'length'), 3); }); - assert.equal(get(all, 'length'), 3); -}); - -test('Calling store.peekAll() multiple times should update immediately inside the runloop', function(assert) { - assert.expect(3); + test('Calling store.peekAll() multiple times should update immediately', async function(assert) { + assert.expect(3); - run(() => { assert.equal(get(store.peekAll('person'), 'length'), 0, 'should initially be empty'); store.createRecord('person', { name: 'Tomster' }); assert.equal(get(store.peekAll('person'), 'length'), 1, 'should contain one person'); @@ -84,12 +79,10 @@ test('Calling store.peekAll() multiple times should update immediately inside th }); assert.equal(get(store.peekAll('person'), 'length'), 2, 'should contain two people'); }); -}); -test('Calling store.peekAll() after creating a record should return correct data', function(assert) { - assert.expect(1); + test('Calling store.peekAll() after creating a record should return correct data', async function(assert) { + assert.expect(1); - run(() => { store.createRecord('person', { name: 'Tomster' }); assert.equal(get(store.peekAll('person'), 'length'), 1, 'should contain one person'); }); From 52761fc88020778ff780f40f6d6ed7c39b4f11c8 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 24 Oct 2018 15:37:23 -0700 Subject: [PATCH 2389/2527] cleanup unnecessary await --- .../relationships/inverse-relationship-load-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/relationships/inverse-relationship-load-test.js b/tests/integration/relationships/inverse-relationship-load-test.js index 45791d91175..e224fbdb471 100644 --- a/tests/integration/relationships/inverse-relationship-load-test.js +++ b/tests/integration/relationships/inverse-relationship-load-test.js @@ -2124,7 +2124,7 @@ module('inverse relationship load test', function(hooks) { let dog = await person.get('dog'); assert.expectDeprecation(/Encountered mismatched relationship/); - let dogFromStore = await store.peekRecord('dog', '1'); + let dogFromStore = store.peekRecord('dog', '1'); // weirdly these pass assert.equal(dogFromStore.belongsTo('person').id(), '1'); @@ -2137,7 +2137,7 @@ module('inverse relationship load test', function(hooks) { 'relationship is not empty' ); - let dogPerson1 = await dog.get('person'); + let dogPerson1 = dog.get('person'); assert.equal( dogPerson1.get('id'), '1', From 9b42925b79dfba3f2943ca413c364bd86a432020 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Thu, 25 Oct 2018 12:10:51 -0700 Subject: [PATCH 2390/2527] [BUGFIX serializerFor] error nicely if no serializer is found at all * [CHORE tests] modernize integration/store/serializer-for-test --- addon/-private/system/store.js | 8 +- .../integration/store/serializer-for-test.js | 462 ++++++++++++++++++ tests/unit/store/lookup-test.js | 116 ----- 3 files changed, 469 insertions(+), 117 deletions(-) create mode 100644 tests/integration/store/serializer-for-test.js delete mode 100644 tests/unit/store/lookup-test.js diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 68d042a587f..0cb0b2bcb15 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -3156,7 +3156,9 @@ Store = Service.extend({ // property defined on the adapter let adapter = this.adapterFor(modelName); let serializerName = get(adapter, 'defaultSerializer'); - serializer = _serializerCache[serializerName] || owner.lookup(`serializer:${serializerName}`); + serializer = serializerName + ? _serializerCache[serializerName] || owner.lookup(`serializer:${serializerName}`) + : undefined; if (serializer !== undefined) { set(serializer, 'store', this); _serializerCache[normalizedModelName] = serializer; @@ -3167,6 +3169,10 @@ Store = Service.extend({ // final fallback, no model specific serializer, no application serializer, no // `serializer` property on store: use json-api serializer serializer = _serializerCache['-default'] || owner.lookup('serializer:-default'); + assert( + `No serializer was found for '${modelName}' and no 'application', Adapter.defaultSerializer, or '-default' serializer were found as fallbacks.`, + serializer !== undefined + ); set(serializer, 'store', this); _serializerCache[normalizedModelName] = serializer; _serializerCache['-default'] = serializer; diff --git a/tests/integration/store/serializer-for-test.js b/tests/integration/store/serializer-for-test.js new file mode 100644 index 00000000000..01878d67046 --- /dev/null +++ b/tests/integration/store/serializer-for-test.js @@ -0,0 +1,462 @@ +import { setupTest } from 'ember-qunit'; +import { module, test } from 'qunit'; +import Store from 'ember-data/store'; +import { run } from '@ember/runloop'; + +class TestAdapter { + constructor(args) { + Object.assign(this, args); + this.didInit(); + } + + didInit() {} + + static create(args) { + return new this(args); + } +} + +class TestSerializer { + constructor(args) { + Object.assign(this, args); + this.didInit(); + } + + didInit() {} + + static create(args) { + return new this(args); + } +} + +/* + Serializer Fallback Rules + + 1. per-type + 2. application + 3. Adapter.defaultSerializer + 4. serializer:-default (json-api serializer) + */ +module('integration/store - serializerFor', function(hooks) { + setupTest(hooks); + let store; + + hooks.beforeEach(function() { + let { owner } = this; + + store = owner.lookup('service:store'); + }); + + test('when no serializer is available we throw an error', async function(assert) { + let { owner } = this; + /* + serializer:-default is the "last chance" fallback and is + registered automatically as the json-api serializer. + unregistering it will cause serializerFor to return `undefined`. + */ + owner.unregister('serializer:-default'); + /* + we fallback to -json-api adapter by default when no other adapter is present. + This adapter specifies a defaultSerializer. We register our own to ensure + that this does not occur. + */ + class AppAdapter extends TestAdapter { + constructor() { + super(...arguments); + // ensure our adapter instance does not specify a fallback + // we use an empty string as that would cause `owner.lookup` to blow up if not guarded properly + // whereas `null` `undefined` `false` would not. + this.defaultSerializer = ''; + } + } + owner.register('adapter:application', AppAdapter); + + assert.expectAssertion(() => { + store.serializerFor('person'); + }, /No serializer was found for 'person' and no 'application', Adapter\.defaultSerializer, or '-default' serializer were found as fallbacks\./); + }); + + test('we find and instantiate the application serializer', async function(assert) { + let { owner } = this; + let didInstantiate = false; + + class AppSerializer extends TestSerializer { + didInit() { + didInstantiate = true; + } + } + + owner.register('serializer:application', AppSerializer); + + let serializer = store.serializerFor('application'); + + assert.ok(serializer instanceof AppSerializer, 'We found the correct serializer'); + assert.ok(didInstantiate, 'We instantiated the serializer'); + didInstantiate = false; + + let serializerAgain = store.serializerFor('application'); + + assert.ok(serializerAgain instanceof AppSerializer, 'We found the correct serializer'); + assert.ok(!didInstantiate, 'We did not instantiate the serializer again'); + assert.ok( + serializer === serializerAgain, + 'Repeated calls to serializerFor return the same instance' + ); + }); + + test('multiple stores do not share serializers', async function(assert) { + let { owner } = this; + let didInstantiate = false; + + class AppSerializer extends TestSerializer { + didInit() { + didInstantiate = true; + } + } + + owner.register('serializer:application', AppSerializer); + owner.register('service:other-store', Store); + + let otherStore = owner.lookup('service:other-store'); + let serializer = store.serializerFor('application'); + + assert.ok(serializer instanceof AppSerializer, 'We found the correct serializer'); + assert.ok(didInstantiate, 'We instantiated the serializer'); + didInstantiate = false; + + let otherSerializer = otherStore.serializerFor('application'); + assert.ok(otherSerializer instanceof AppSerializer, 'We found the correct serializer again'); + assert.ok(didInstantiate, 'We instantiated the other serializer'); + assert.ok(otherSerializer !== serializer, 'We have a different serializer instance'); + + // Ember 2.18 requires us to wrap destroy in a run. Use `await settled()` for newer versions. + run(() => otherStore.destroy()); + }); + + test('we can find and instantiate per-type serializers', async function(assert) { + let { owner } = this; + let didInstantiateAppSerializer = false; + let didInstantiatePersonSerializer = false; + + class AppSerializer extends TestSerializer { + didInit() { + didInstantiateAppSerializer = true; + } + } + + class PersonSerializer extends TestSerializer { + didInit() { + didInstantiatePersonSerializer = true; + } + } + + owner.register('serializer:application', AppSerializer); + owner.register('serializer:person', PersonSerializer); + + let serializer = store.serializerFor('person'); + + assert.ok(serializer instanceof PersonSerializer, 'We found the correct serializer'); + assert.ok(didInstantiatePersonSerializer, 'We instantiated the person serializer'); + assert.ok(!didInstantiateAppSerializer, 'We did not instantiate the application serializer'); + + let appSerializer = store.serializerFor('application'); + assert.ok(appSerializer instanceof AppSerializer, 'We found the correct serializer'); + assert.ok(didInstantiateAppSerializer, 'We instantiated the application serializer'); + assert.ok(appSerializer !== serializer, 'We have separate serializers'); + }); + + test('we fallback to the application serializer when a per-type serializer is not found', async function(assert) { + let { owner } = this; + let didInstantiateAppSerializer = false; + + class AppSerializer extends TestSerializer { + didInit() { + didInstantiateAppSerializer = true; + } + } + + owner.register('serializer:application', AppSerializer); + + let serializer = store.serializerFor('person'); + + assert.ok(serializer instanceof AppSerializer, 'We found the serializer'); + assert.ok(didInstantiateAppSerializer, 'We instantiated the serializer'); + didInstantiateAppSerializer = false; + + let appSerializer = store.serializerFor('application'); + assert.ok(appSerializer instanceof AppSerializer, 'We found the correct serializer'); + assert.ok(!didInstantiateAppSerializer, 'We did not instantiate the serializer again'); + assert.ok(appSerializer === serializer, 'We fell back to the application serializer instance'); + }); + + module('Adapter Fallback', function() { + test('we can specify a fallback serializer on the adapter when there is no application serializer', async function(assert) { + let { owner } = this; + let personAdapterDidInit = false; + let fallbackSerializerDidInit = false; + + class PersonAdapter extends TestAdapter { + constructor() { + super(...arguments); + this.defaultSerializer = '-fallback'; + } + + didInit() { + personAdapterDidInit = true; + } + } + class FallbackSerializer extends TestSerializer { + didInit() { + fallbackSerializerDidInit = true; + } + } + + owner.register('adapter:person', PersonAdapter); + owner.register('serializer:-fallback', FallbackSerializer); + + let serializer = store.serializerFor('person'); + + assert.ok(serializer instanceof FallbackSerializer, 'We found the serializer'); + assert.ok(personAdapterDidInit, 'We instantiated the adapter'); + assert.ok(fallbackSerializerDidInit, 'We instantiated the serializer'); + personAdapterDidInit = false; + fallbackSerializerDidInit = false; + + let fallbackSerializer = store.serializerFor('-fallback'); + assert.ok( + fallbackSerializer instanceof FallbackSerializer, + 'We found the correct serializer' + ); + assert.ok(!fallbackSerializerDidInit, 'We did not instantiate the serializer again'); + assert.ok(!personAdapterDidInit, 'We did not instantiate the adapter again'); + assert.ok( + fallbackSerializer === serializer, + 'We fell back to the fallback-serializer instance' + ); + }); + + test('specifying defaultSerializer on application serializer when there is a per-type serializer does not work', async function(assert) { + let { owner } = this; + let appAdapterDidInit = false; + let personAdapterDidInit = false; + let fallbackSerializerDidInit = false; + let defaultSerializerDidInit = false; + + class AppAdapter extends TestAdapter { + constructor() { + super(...arguments); + this.defaultSerializer = '-fallback'; + } + + didInit() { + appAdapterDidInit = true; + } + } + class PersonAdapter extends TestAdapter { + constructor() { + super(...arguments); + this.defaultSerializer = null; + } + + didInit() { + personAdapterDidInit = true; + } + } + class FallbackSerializer extends TestSerializer { + didInit() { + fallbackSerializerDidInit = true; + } + } + class DefaultSerializer extends TestSerializer { + didInit() { + defaultSerializerDidInit = true; + } + } + + owner.register('adapter:application', AppAdapter); + owner.register('adapter:person', PersonAdapter); + owner.register('serializer:-fallback', FallbackSerializer); + /* + serializer:-default is the "last chance" fallback and is + registered automatically as the json-api serializer. + */ + owner.unregister('serializer:-default'); + owner.register('serializer:-default', DefaultSerializer); + + let serializer = store.serializerFor('person'); + + assert.ok(serializer instanceof DefaultSerializer, 'We found the serializer'); + assert.ok(personAdapterDidInit, 'We instantiated the person adapter'); + assert.ok(!appAdapterDidInit, 'We did not instantiate the application adapter'); + assert.ok( + !fallbackSerializerDidInit, + 'We did not instantiate the application adapter fallback serializer' + ); + assert.ok(defaultSerializerDidInit, 'We instantiated the `-default` fallback serializer'); + personAdapterDidInit = false; + appAdapterDidInit = false; + fallbackSerializerDidInit = false; + defaultSerializerDidInit = false; + + let defaultSerializer = store.serializerFor('-default'); + assert.ok(defaultSerializer instanceof DefaultSerializer, 'We found the correct serializer'); + assert.ok(!defaultSerializerDidInit, 'We did not instantiate the serializer again'); + assert.ok(!appAdapterDidInit, 'We did not instantiate the application adapter'); + assert.ok( + !fallbackSerializerDidInit, + 'We did not instantiate the application adapter fallback serializer' + ); + assert.ok(!personAdapterDidInit, 'We did not instantiate the adapter again'); + assert.ok( + defaultSerializer === serializer, + 'We fell back to the fallback-serializer instance' + ); + }); + + test('specifying defaultSerializer on a fallback serializer when there is no per-type serializer does work', async function(assert) { + let { owner } = this; + let appAdapterDidInit = false; + let fallbackSerializerDidInit = false; + let defaultSerializerDidInit = false; + + class AppAdapter extends TestAdapter { + constructor() { + super(...arguments); + this.defaultSerializer = '-fallback'; + } + + didInit() { + appAdapterDidInit = true; + } + } + class FallbackSerializer extends TestSerializer { + didInit() { + fallbackSerializerDidInit = true; + } + } + class DefaultSerializer extends TestSerializer { + didInit() { + defaultSerializerDidInit = true; + } + } + + owner.register('adapter:application', AppAdapter); + owner.register('serializer:-fallback', FallbackSerializer); + /* + serializer:-default is the "last chance" fallback and is + registered automatically as the json-api serializer. + */ + owner.unregister('serializer:-default'); + owner.register('serializer:-default', DefaultSerializer); + + let serializer = store.serializerFor('person'); + + assert.ok(serializer instanceof FallbackSerializer, 'We found the serializer'); + assert.ok(appAdapterDidInit, 'We instantiated the fallback application adapter'); + assert.ok( + fallbackSerializerDidInit, + 'We instantiated the application adapter fallback defaultSerializer' + ); + assert.ok( + !defaultSerializerDidInit, + 'We did not instantiate the `-default` fallback serializer' + ); + appAdapterDidInit = false; + fallbackSerializerDidInit = false; + defaultSerializerDidInit = false; + + let fallbackSerializer = store.serializerFor('-fallback'); + assert.ok( + fallbackSerializer instanceof FallbackSerializer, + 'We found the correct serializer' + ); + assert.ok(!defaultSerializerDidInit, 'We did not instantiate the default serializer'); + assert.ok(!appAdapterDidInit, 'We did not instantiate the application adapter again'); + assert.ok( + !fallbackSerializerDidInit, + 'We did not instantiate the application adapter fallback serializer again' + ); + assert.ok( + fallbackSerializer === serializer, + 'We fell back to the fallback-serializer instance' + ); + }); + }); + + test('When the per-type, application and adapter specified fallback serializer do not exist, we fallback to the -default serializer', async function(assert) { + let { owner } = this; + let appAdapterDidInit = false; + let defaultSerializerDidInit = false; + + class AppAdapter extends TestAdapter { + constructor() { + super(...arguments); + this.defaultSerializer = '-not-a-real-fallback'; + } + + didInit() { + appAdapterDidInit = true; + } + } + class DefaultSerializer extends TestSerializer { + didInit() { + defaultSerializerDidInit = true; + } + } + + owner.register('adapter:application', AppAdapter); + /* + serializer:-default is the "last chance" fallback and is + registered automatically as the json-api serializer. + */ + owner.unregister('serializer:-default'); + owner.register('serializer:-default', DefaultSerializer); + + let serializer = store.serializerFor('person'); + + assert.ok(serializer instanceof DefaultSerializer, 'We found the serializer'); + assert.ok(appAdapterDidInit, 'We instantiated the fallback application adapter'); + assert.ok(defaultSerializerDidInit, 'We instantiated the `-default` fallback serializer'); + appAdapterDidInit = false; + defaultSerializerDidInit = false; + + let appSerializer = store.serializerFor('application'); + + assert.ok(appSerializer instanceof DefaultSerializer, 'We found the serializer'); + assert.ok(!appAdapterDidInit, 'We did not instantiate the application adapter again'); + assert.ok( + !defaultSerializerDidInit, + 'We did not instantiate the `-default` fallback serializer again' + ); + appAdapterDidInit = false; + defaultSerializerDidInit = false; + + let fallbackSerializer = store.serializerFor('-not-a-real-fallback'); + + assert.ok(fallbackSerializer instanceof DefaultSerializer, 'We found the serializer'); + assert.ok(!appAdapterDidInit, 'We did not instantiate the application adapter again'); + assert.ok( + !defaultSerializerDidInit, + 'We did not instantiate the `-default` fallback serializer again' + ); + appAdapterDidInit = false; + defaultSerializerDidInit = false; + + let defaultSerializer = store.serializerFor('-default'); + assert.ok(defaultSerializer instanceof DefaultSerializer, 'We found the correct serializer'); + assert.ok(!defaultSerializerDidInit, 'We did not instantiate the default serializer again'); + assert.ok(!appAdapterDidInit, 'We did not instantiate the application adapter again'); + assert.ok( + defaultSerializer === serializer, + 'We fell back to the -default serializer instance for the per-type serializer' + ); + assert.ok( + defaultSerializer === appSerializer, + 'We fell back to the -default serializer instance for the application serializer' + ); + assert.ok( + defaultSerializer === fallbackSerializer, + 'We fell back to the -default serializer instance for the adapter defaultSerializer' + ); + }); +}); diff --git a/tests/unit/store/lookup-test.js b/tests/unit/store/lookup-test.js deleted file mode 100644 index 4901663fb53..00000000000 --- a/tests/unit/store/lookup-test.js +++ /dev/null @@ -1,116 +0,0 @@ -import { run } from '@ember/runloop'; -import setupStore from 'dummy/tests/helpers/store'; - -import { module, test } from 'qunit'; - -import DS from 'ember-data'; - -let store, env, applicationSerializer, Person; - -function resetStore() { - if (store) { - run(store, 'destroy'); - } - env = setupStore({ - adapter: '-rest', - person: Person, - }); - - env.registry.unregister('adapter:application'); - env.registry.unregister('serializer:application'); - - env.registry.optionsForType('serializer', { singleton: true }); - env.registry.optionsForType('adapter', { singleton: true }); - - store = env.store; -} - -function lookupSerializer(serializerName) { - return run(store, 'serializerFor', serializerName); -} - -function registerAdapter(adapterName, adapter) { - env.registry.register(`adapter:${adapterName}`, adapter); -} - -function registerSerializer(serializerName, serializer) { - env.registry.register(`serializer:${serializerName}`, serializer); -} - -module('unit/store/lookup - Managed Instance lookups', { - beforeEach() { - Person = DS.Model.extend(); - resetStore(); - env.registry.register('adapter:application', DS.Adapter.extend()); - env.registry.register('adapter:serializer', DS.Adapter.extend()); - - applicationSerializer = run(store, 'serializerFor', 'application'); - }, - - afterEach() { - run(store, 'destroy'); - }, -}); - -test('when the serializer does not exist for a type, the fallback is returned', assert => { - let personSerializer = lookupSerializer('person'); - - assert.strictEqual(personSerializer, applicationSerializer); -}); - -test('when the serializer does exist for a type, the serializer is returned', assert => { - registerSerializer('person', DS.Serializer.extend()); - - let personSerializer = lookupSerializer('person'); - - assert.ok(personSerializer !== applicationSerializer); -}); - -test('serializer lookup order', assert => { - resetStore(); - - let personSerializer = lookupSerializer('person'); - - assert.strictEqual(personSerializer, lookupSerializer('-rest')); - - resetStore(); - - registerSerializer('application', DS.RESTSerializer.extend()); - personSerializer = lookupSerializer('person'); - assert.strictEqual( - personSerializer, - lookupSerializer('application'), - 'looks up application before default' - ); - - resetStore(); - registerAdapter( - 'person', - DS.Adapter.extend({ - defaultSerializer: '-rest', - }) - ); - personSerializer = lookupSerializer('person'); - - assert.strictEqual( - personSerializer, - lookupSerializer('-rest'), - 'uses defaultSerializer on adapterFor("model") if application not defined' - ); - - resetStore(); - registerAdapter( - 'person', - DS.Adapter.extend({ - defaultSerializer: '-rest', - }) - ); - registerSerializer('application', DS.RESTSerializer.extend()); - registerSerializer('person', DS.JSONSerializer.extend({ customThingy: true })); - personSerializer = lookupSerializer('person'); - - assert.ok( - personSerializer.get('customThingy'), - 'uses the person serializer before any fallbacks if it is defined' - ); -}); From 6b78ab76485e83f07ce524d19032946408f2feb8 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 24 Oct 2018 20:10:12 -0700 Subject: [PATCH 2391/2527] [CHORE tests] modernize integration/client-id-generation-test --- .../integration/client-id-generation-test.js | 187 ++++++++++-------- 1 file changed, 101 insertions(+), 86 deletions(-) diff --git a/tests/integration/client-id-generation-test.js b/tests/integration/client-id-generation-test.js index f9929264304..af9d97e23a2 100644 --- a/tests/integration/client-id-generation-test.js +++ b/tests/integration/client-id-generation-test.js @@ -1,101 +1,116 @@ import { resolve } from 'rsvp'; import { get } from '@ember/object'; -import { run } from '@ember/runloop'; -import setupStore from 'dummy/tests/helpers/store'; - +import { setupTest } from 'ember-qunit'; import { module, test } from 'qunit'; +import Model from 'ember-data/model'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import { attr, belongsTo, hasMany } from '@ember-decorators/data'; + +module('integration - Client Id Generation', function(hooks) { + setupTest(hooks); + let store; + let adapter; + + hooks.beforeEach(function() { + let { owner } = this; + + class Comment extends Model { + @attr + text; + @belongsTo('post', { async: false, inverse: 'comments' }) + post; + } + class Post extends Model { + @attr + title; + @hasMany('comment', { async: false, inverse: 'post' }) + comments; + } + class Misc extends Model { + @attr('string') + foo; + } -import DS from 'ember-data'; - -let Post, Comment, Misc, env; - -module('integration/client_id_generation - Client-side ID Generation', { - beforeEach() { - Comment = DS.Model.extend({ - post: DS.belongsTo('post', { async: false }), - }); - - Post = DS.Model.extend({ - comments: DS.hasMany('comment', { async: false }), - }); - - Misc = DS.Model.extend({ - foo: DS.attr('string'), - }); - - env = setupStore({ - post: Post, - comment: Comment, - misc: Misc, - }); - }, - - afterEach() { - run(env.container, 'destroy'); - }, -}); + owner.register('model:comment', Comment); + owner.register('model:post', Post); + owner.register('model:misc', Misc); + owner.register('adapter:application', JSONAPIAdapter); -test('If an adapter implements the `generateIdForRecord` method, the store should be able to assign IDs without saving to the persistence layer.', function(assert) { - assert.expect(6); + store = owner.lookup('service:store'); + adapter = store.adapterFor('application'); + }); - let idCount = 1; + test('If an adapter implements the `generateIdForRecord` method, the store should be able to assign IDs without saving to the persistence layer.', async function(assert) { + assert.expect(6); + + let idCount = 1; + + adapter.generateIdForRecord = function(passedStore, record) { + assert.ok(store === passedStore, 'store is the first parameter'); + + return 'id-' + idCount++; + }; + + adapter.createRecord = function(store, modelClass, snapshot) { + let type = modelClass.modelName; + + if (type === 'comment') { + assert.equal(snapshot.id, 'id-1', "Comment passed to `createRecord` has 'id-1' assigned"); + return resolve({ + data: { + type, + id: snapshot.id, + }, + }); + } else { + assert.equal(snapshot.id, 'id-2', "Post passed to `createRecord` has 'id-2' assigned"); + return resolve({ + data: { + type, + id: snapshot.id, + }, + }); + } + }; + + let comment = store.createRecord('comment'); + let post = store.createRecord('post'); + + assert.equal(get(comment, 'id'), 'id-1', "comment is assigned id 'id-1'"); + assert.equal(get(post, 'id'), 'id-2', "post is assigned id 'id-2'"); + + // Despite client-generated IDs, calling save() on the store should still + // invoke the adapter's `createRecord` method. + await comment.save(); + await post.save(); + }); - env.adapter.generateIdForRecord = function(passedStore, record) { - assert.equal(env.store, passedStore, 'store is the first parameter'); + test('empty string and undefined ids should coerce to null', async function(assert) { + assert.expect(6); + let idCount = 0; + let id = 1; + let ids = [undefined, '']; - return 'id-' + idCount++; - }; + adapter.generateIdForRecord = function(passedStore, record) { + assert.ok(store === passedStore, 'store is the first parameter'); - env.adapter.createRecord = function(store, type, snapshot) { - if (type === Comment) { - assert.equal(snapshot.id, 'id-1', "Comment passed to `createRecord` has 'id-1' assigned"); - return resolve(); - } else { - assert.equal(snapshot.id, 'id-2', "Post passed to `createRecord` has 'id-2' assigned"); - return resolve(); - } - }; + return ids[idCount++]; + }; - let comment = env.store.createRecord('comment'); - let post = env.store.createRecord('post'); + adapter.createRecord = function(store, type, record) { + assert.equal(typeof get(record, 'id'), 'object', 'correct type'); + return resolve({ data: { id: id++, type: type.modelName } }); + }; - assert.equal(get(comment, 'id'), 'id-1', "comment is assigned id 'id-1'"); - assert.equal(get(post, 'id'), 'id-2', "post is assigned id 'id-2'"); + let comment = store.createRecord('misc'); + let post = store.createRecord('misc'); - // Despite client-generated IDs, calling commit() on the store should still - // invoke the adapter's `createRecord` method. - run(function() { - comment.save(); - post.save(); - }); -}); + assert.equal(get(comment, 'id'), null, "comment is assigned id 'null'"); + assert.equal(get(post, 'id'), null, "post is assigned id 'null'"); -test('empty string and undefined ids should coerce to null', function(assert) { - assert.expect(6); - let idCount = 0; - let id = 1; - let ids = [undefined, '']; - env.adapter.generateIdForRecord = function(passedStore, record) { - assert.equal(env.store, passedStore, 'store is the first parameter'); - - return ids[idCount++]; - }; - - env.adapter.createRecord = function(store, type, record) { - assert.equal(typeof get(record, 'id'), 'object', 'correct type'); - return resolve({ data: { id: id++, type: type.modelName } }); - }; - - let comment = env.store.createRecord('misc'); - let post = env.store.createRecord('misc'); - - assert.equal(get(comment, 'id'), null, "comment is assigned id 'null'"); - assert.equal(get(post, 'id'), null, "post is assigned id 'null'"); - - // Despite client-generated IDs, calling commit() on the store should still - // invoke the adapter's `createRecord` method. - run(() => { - comment.save(); - post.save(); + // Despite client-generated IDs, calling commit() on the store should still + // invoke the adapter's `createRecord` method. + await comment.save(); + await post.save(); }); }); From 288a944be47ba446b4f55a098f66a168d1c802c5 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 24 Oct 2018 12:41:02 -0700 Subject: [PATCH 2392/2527] updates to support native-classes --- addon/-private/attr.js | 15 ++ addon/-private/system/model/model.js | 221 +++++++++--------- addon/-private/system/relationship-meta.js | 6 +- .../system/relationships/belongs-to.js | 59 +++-- addon/-private/system/relationships/ext.js | 8 +- .../-private/system/relationships/has-many.js | 15 ++ 6 files changed, 180 insertions(+), 144 deletions(-) diff --git a/addon/-private/attr.js b/addon/-private/attr.js index db413e2eadd..6c1cd94a0a9 100644 --- a/addon/-private/attr.js +++ b/addon/-private/attr.js @@ -1,5 +1,6 @@ import { computed } from '@ember/object'; import { assert } from '@ember/debug'; +import { DEBUG } from '@glimmer/env'; /** @module ember-data @@ -124,6 +125,13 @@ export default function attr(type, options) { return computed({ get(key) { + if (DEBUG) { + if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) { + throw new Error( + `'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your attr on ${this.constructor.toString()}` + ); + } + } let internalModel = this._internalModel; if (hasValue(internalModel, key)) { return internalModel.getAttributeValue(key); @@ -132,6 +140,13 @@ export default function attr(type, options) { } }, set(key, value) { + if (DEBUG) { + if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) { + throw new Error( + `'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your attr on ${this.constructor.toString()}` + ); + } + } return this._internalModel.setDirtyAttribute(key, value); }, }).meta(meta); diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 098d8f70e9b..cf660691241 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1,13 +1,11 @@ -import ComputedProperty from '@ember/object/computed'; import { isNone } from '@ember/utils'; import EmberError from '@ember/error'; import Evented from '@ember/object/evented'; import EmberObject, { computed, get } from '@ember/object'; import { DEBUG } from '@glimmer/env'; -import { assert, warn } from '@ember/debug'; +import { assert, warn, deprecate } from '@ember/debug'; import { PromiseObject } from '../promise-proxies'; import Errors from '../model/errors'; -import RootState from '../model/states'; import { relationshipsByNameDescriptor, relationshipsObjectDescriptor, @@ -16,6 +14,8 @@ import { } from '../relationships/ext'; import Ember from 'ember'; +import InternalModel from './internal-model'; +import RootState from './states'; const { changeProperties } = Ember; /** @@ -55,19 +55,6 @@ function findPossibleInverses(type, inverseType, name, relationshipsSoFar) { return possibleRelationships; } -function intersection(array1, array2) { - let result = []; - array1.forEach(element => { - if (array2.indexOf(element) >= 0) { - result.push(element); - } - }); - - return result; -} - -const RESERVED_MODEL_PROPS = ['currentState', 'data', 'store']; - const retrieveFromCurrentState = computed('currentState', function(key) { return get(this._internalModel.currentState, key); }).readOnly(); @@ -77,8 +64,6 @@ const retrieveFromCurrentState = computed('currentState', function(key) { The model class that all Ember Data records descend from. This is the public API of Ember Data models. If you are using Ember Data in your application, this is the class you should use. - If you are working on Ember Data internals, you most likely want to be dealing - with `InternalModel` @class Model @namespace DS @@ -86,8 +71,7 @@ const retrieveFromCurrentState = computed('currentState', function(key) { @uses Ember.Evented */ const Model = EmberObject.extend(Evented, { - _internalModel: null, - store: null, + // until: "3.9" as we need to support 2.18 __defineNonEnumerable(property) { this[property.name] = property.descriptor.value; }, @@ -345,7 +329,26 @@ const Model = EmberObject.extend(Evented, { @private @type {Object} */ - currentState: RootState.empty, + currentState: RootState.empty, // defined here to avoid triggering setUnknownProperty + + /** + @property _internalModel + @private + @type {Object} + */ + _internalModel: null, // defined here to avoid triggering setUnknownProperty + + /** + @property recordData + @private + @type undefined (reserved) + */ + // will be defined here to avoid triggering setUnknownProperty + + /** + @property store + */ + store: null, // defined here to avoid triggering setUnknownProperty /** When the record is in the `invalid` state this object will contain @@ -456,7 +459,7 @@ const Model = EmberObject.extend(Evented, { */ toJSON(options) { // container is for lazy transform lookups - let serializer = this.store.serializerFor('-default'); + let serializer = this._internalModel.store.serializerFor('-default'); let snapshot = this._internalModel.createSnapshot(); return serializer.serialize(snapshot, options); @@ -697,24 +700,6 @@ const Model = EmberObject.extend(Evented, { return this._internalModel.changedAttributes(); }, - //TODO discuss with tomhuda about events/hooks - //Bring back as hooks? - /** - @method adapterWillCommit - @private - adapterWillCommit: function() { - this.send('willCommit'); - }, - - /** - @method adapterDidDirty - @private - adapterDidDirty: function() { - this.send('becomeDirty'); - this.updateRecordArraysLater(); - }, - */ - /** If the model `hasDirtyAttributes` this function will discard any unsaved changes. If the model `isNew` it will be removed from the store. @@ -1130,7 +1115,7 @@ const Model = EmberObject.extend(Evented, { }, inverseFor(key) { - return this.constructor.inverseFor(key, this.store); + return this.constructor.inverseFor(key, this._internalModel.store); }, notifyHasManyAdded(key) { @@ -1148,17 +1133,25 @@ const Model = EmberObject.extend(Evented, { /** @property data @private + @deprecated @type {Object} */ Object.defineProperty(Model.prototype, 'data', { configurable: false, get() { - // TODO deprecate this!!!!!!!!!!! it's private but intimate + deprecate( + `Model.data was private and it's use has been deprecated. For public access, use the RecordData API or iterate attributes`, + false, + { + id: 'ember-data:Model.data', + until: '3.9', + } + ); return this._internalModel._recordData._data; }, }); -Object.defineProperty(Model.prototype, 'id', { +const ID_DESCRIPTOR = { configurable: false, set(id) { this._internalModel.setId(id); @@ -1170,9 +1163,37 @@ Object.defineProperty(Model.prototype, 'id', { // object is real. return this._internalModel && this._internalModel.id; }, -}); +}; + +Object.defineProperty(Model.prototype, 'id', ID_DESCRIPTOR); if (DEBUG) { + let lookupDescriptor = function lookupDescriptor(obj, keyName) { + let current = obj; + do { + let descriptor = Object.getOwnPropertyDescriptor(current, keyName); + if (descriptor !== undefined) { + return descriptor; + } + current = Object.getPrototypeOf(current); + } while (current !== null); + return null; + }; + let isBasicDesc = function isBasicDesc(desc) { + return ( + !desc || + (!desc.get && + !desc.set && + desc.enumerable === true && + desc.writable === true && + desc.configurable === true) + ); + }; + let isDefaultEmptyDescriptor = function isDefaultEmptyDescriptor(obj, keyName) { + let instanceDesc = lookupDescriptor(obj, keyName); + return isBasicDesc(instanceDesc) && lookupDescriptor(obj.constructor, keyName) === null; + }; + Model.reopen({ init() { this._super(...arguments); @@ -1182,6 +1203,42 @@ if (DEBUG) { 'You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.' ); } + + if ( + !isDefaultEmptyDescriptor(this, '_internalModel') || + !(this._internalModel instanceof InternalModel) + ) { + throw new Error( + `'_internalModel' is a reserved property name on instances of classes extending Model. Please choose a different property name for ${this.constructor.toString()}` + ); + } + + if ( + !isDefaultEmptyDescriptor(this, 'recordData') || + this.recordData !== undefined || + this.recordData !== this._internalModel.recordData + ) { + throw new Error( + `'recordData' is a reserved property name on instances of classes extending Model. Please choose a different property name for ${this.constructor.toString()}` + ); + } + + if ( + !isDefaultEmptyDescriptor(this, 'currentState') || + this.get('currentState') !== this._internalModel.currentState + ) { + throw new Error( + `'currentState' is a reserved property name on instances of classes extending Model. Please choose a different property name for ${this.constructor.toString()}` + ); + } + + let idDesc = lookupDescriptor(this, 'id'); + + if (idDesc.get !== ID_DESCRIPTOR.get) { + throw new EmberError( + `You may not set 'id' as an attribute on your model. Please remove any lines that look like: \`id: DS.attr('')\` from ${this.constructor.toString()}` + ); + } }, }); } @@ -1190,16 +1247,16 @@ Model.reopenClass({ isModel: true, /** - Override the class' `create()` method to raise an error. This - prevents end users from inadvertently calling `create()` instead - of `createRecord()`. The store is still able to create instances - by calling the `_create()` method. To create an instance of a - `DS.Model` use [store.createRecord](DS.Store.html#method_createRecord). + Create should only ever be called by the store. To create an instance of a + `DS.Model` in a dirty state use `store.createRecord`. + + To create instances of `DS.Model` in a clean state, use `store.push` @method create @private @static */ + /** Represents the model's class name as a string. This can be used to look up the model's class name through `DS.Store`'s modelFor method. @@ -1356,7 +1413,7 @@ Model.reopenClass({ inverseOptions = inverse.options; } else { //No inverse was specified manually, we need to use a heuristic to guess one - if (propertyMeta.parentType && propertyMeta.type === propertyMeta.parentType.modelName) { + if (propertyMeta.type === propertyMeta.parentModelName) { warn( `Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at https://guides.emberjs.com/current/models/relationships/#toc_reflexive-relations for how to explicitly specify inverses.`, false, @@ -1923,68 +1980,4 @@ Model.reopenClass({ }, }); -if (DEBUG) { - Model.reopen({ - // This is a temporary solution until we refactor DS.Model to not - // rely on the data property. - willMergeMixin(props) { - let constructor = this.constructor; - assert( - '`' + - intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] + - '` is a reserved property name on DS.Model objects. Please choose a different property name for ' + - constructor.toString(), - !intersection(Object.keys(props), RESERVED_MODEL_PROPS)[0] - ); - assert( - "You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + - constructor.toString(), - Object.keys(props).indexOf('id') === -1 - ); - }, - - /** - This Ember.js hook allows an object to be notified when a property - is defined. - - In this case, we use it to be notified when an Ember Data user defines a - belongs-to relationship. In that case, we need to set up observers for - each one, allowing us to track relationship changes and automatically - reflect changes in the inverse has-many array. - - This hook passes the class being set up, as well as the key and value - being defined. So, for example, when the user does this: - - ```javascript - DS.Model.extend({ - parent: DS.belongsTo('user') - }); - ``` - - This hook would be called with "parent" as the key and the computed - property returned by `DS.belongsTo` as the value. - - @method didDefineProperty - @param {Object} proto - @param {String} key - @param {Ember.ComputedProperty} value - */ - didDefineProperty(proto, key, value) { - // Check if the value being set is a computed property. - if (value instanceof ComputedProperty) { - // If it is, get the metadata for the relationship. This is - // populated by the `DS.belongsTo` helper when it is creating - // the computed property. - let meta = value.meta(); - - /* - This is buggy because if the parent has never been looked up - via `modelFor` it will not have `modelName` set. - */ - meta.parentType = proto.constructor; - } - }, - }); -} - export default Model; diff --git a/addon/-private/system/relationship-meta.js b/addon/-private/system/relationship-meta.js index 7288d70c3b6..357d6be9b73 100644 --- a/addon/-private/system/relationship-meta.js +++ b/addon/-private/system/relationship-meta.js @@ -26,8 +26,7 @@ class RelationshipDefinition { this._type = ''; this.__inverseKey = ''; this.__inverseIsAsync = null; - this.modelClass = meta.parentType; - this.store = null; + this.parentModelName = meta.parentModelName; } get key() { @@ -49,9 +48,6 @@ class RelationshipDefinition { get name() { return this.meta.name; } - get parentType() { - return this.meta.parentType; - } _inverseKey(store, modelClass) { if (this.__inverseKey === '') { diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 5cd2516357f..121c8b82f36 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -1,6 +1,7 @@ import { computed } from '@ember/object'; import { assert, warn, inspect } from '@ember/debug'; import normalizeModelName from '../normalize-model-name'; +import { DEBUG } from '@glimmer/env'; /** `DS.belongsTo` is used to define One-To-One and One-To-Many @@ -108,33 +109,47 @@ export default function belongsTo(modelName, options) { return computed({ get(key) { - if (opts.hasOwnProperty('serialize')) { - warn( - `You provided a serialize option on the "${key}" property in the "${ - this._internalModel.modelName - }" class, this belongs in the serializer. See DS.Serializer and it's implementations https://emberjs.com/api/data/classes/DS.Serializer.html`, - false, - { - id: 'ds.model.serialize-option-in-belongs-to', - } - ); - } - - if (opts.hasOwnProperty('embedded')) { - warn( - `You provided an embedded option on the "${key}" property in the "${ - this._internalModel.modelName - }" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin https://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html`, - false, - { - id: 'ds.model.embedded-option-in-belongs-to', - } - ); + if (DEBUG) { + if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) { + throw new Error( + `'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your belongsTo on ${this.constructor.toString()}` + ); + } + if (opts.hasOwnProperty('serialize')) { + warn( + `You provided a serialize option on the "${key}" property in the "${ + this._internalModel.modelName + }" class, this belongs in the serializer. See DS.Serializer and it's implementations https://emberjs.com/api/data/classes/DS.Serializer.html`, + false, + { + id: 'ds.model.serialize-option-in-belongs-to', + } + ); + } + + if (opts.hasOwnProperty('embedded')) { + warn( + `You provided an embedded option on the "${key}" property in the "${ + this._internalModel.modelName + }" class, this belongs in the serializer. See DS.EmbeddedRecordsMixin https://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html`, + false, + { + id: 'ds.model.embedded-option-in-belongs-to', + } + ); + } } return this._internalModel.getBelongsTo(key); }, set(key, value) { + if (DEBUG) { + if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) { + throw new Error( + `'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your belongsTo on ${this.constructor.toString()}` + ); + } + } this._internalModel.setDirtyBelongsTo(key, value); return this._internalModel.getBelongsTo(key); diff --git a/addon/-private/system/relationships/ext.js b/addon/-private/system/relationships/ext.js index 98a5a3d0b9b..d5482bdf740 100644 --- a/addon/-private/system/relationships/ext.js +++ b/addon/-private/system/relationships/ext.js @@ -22,7 +22,7 @@ export const relationshipsDescriptor = computed(function() { }).readOnly(); export const relatedTypesDescriptor = computed(function() { - let modelName; + let parentModelName = this.modelName; let types = A(); // Loop through each computed property on the class, @@ -31,10 +31,10 @@ export const relatedTypesDescriptor = computed(function() { this.eachComputedProperty((name, meta) => { if (meta.isRelationship) { meta.key = name; - modelName = typeForRelationshipMeta(meta); + let modelName = typeForRelationshipMeta(meta); assert( - `You specified a hasMany (${meta.type}) on ${meta.parentType} but ${ + `You specified a hasMany (${meta.type}) on ${parentModelName} but ${ meta.type } was not found.`, modelName @@ -55,10 +55,12 @@ export const relatedTypesDescriptor = computed(function() { export const relationshipsObjectDescriptor = computed(function() { let relationships = Object.create(null); + let modelName = this.modelName; this.eachComputedProperty((name, meta) => { if (meta.isRelationship) { meta.key = name; meta.name = name; + meta.parentModelName = modelName; relationships[name] = relationshipFromMeta(meta); } }); diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index b4e782bbf49..fc79e0ab45b 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -4,6 +4,7 @@ import { computed } from '@ember/object'; import { assert, inspect } from '@ember/debug'; import normalizeModelName from '../normalize-model-name'; +import { DEBUG } from '@glimmer/env'; /** `DS.hasMany` is used to define One-To-Many and Many-To-Many @@ -145,9 +146,23 @@ export default function hasMany(type, options) { return computed({ get(key) { + if (DEBUG) { + if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) { + throw new Error( + `'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your hasMany on ${this.constructor.toString()}` + ); + } + } return this._internalModel.getHasMany(key); }, set(key, records) { + if (DEBUG) { + if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) { + throw new Error( + `'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your hasMany on ${this.constructor.toString()}` + ); + } + } let internalModel = this._internalModel; internalModel.setDirtyHasMany(key, records); From f1f36af7806798f39448337c3a79056a8f68dcb0 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 24 Oct 2018 13:54:38 -0700 Subject: [PATCH 2393/2527] [CHORE tests] modernize unit/model-test --- tests/unit/model-test.js | 2515 +++++++++--------- tests/unit/model/lifecycle-callbacks-test.js | 30 - 2 files changed, 1188 insertions(+), 1357 deletions(-) diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 32bbb937a2c..431aa3c618b 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -1,815 +1,276 @@ import { guidFor } from '@ember/object/internals'; -import { Promise as EmberPromise, resolve } from 'rsvp'; +import { resolve, reject } from 'rsvp'; import { set, get, observer, computed } from '@ember/object'; -import { run } from '@ember/runloop'; -import { createStore } from 'dummy/tests/helpers/store'; -import setupStore from 'dummy/tests/helpers/store'; -import Ember from 'ember'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; -import DS from 'ember-data'; -import { getOwner } from 'ember-data/-private'; - -let Person, store, env; - -module('unit/model - DS.Model', { - beforeEach() { - Person = DS.Model.extend({ - name: DS.attr('string'), - isDrugAddict: DS.attr('boolean'), - isArchived: DS.attr(), - }); - - env = setupStore({ - adapter: DS.JSONAPIAdapter, - person: Person, - }); - store = env.store; - }, +import { settled } from '@ember/test-helpers'; +import { setupTest } from 'ember-qunit'; +import Model from 'ember-data/model'; +import { InvalidError } from 'ember-data/adapters/errors'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; +import JSONSerializer from 'ember-data/serializers/json'; +import { attr, hasMany, belongsTo } from '@ember-decorators/data'; +import DSattr from 'ember-data/attr'; + +module('unit/model - Model', function(hooks) { + setupTest(hooks); + let store, adapter; + + hooks.beforeEach(function() { + let { owner } = this; + + class Person extends Model { + @attr('string') + name; + @attr('boolean') + isDrugAddict; + @attr() + isArchived; + } - afterEach() { - run(() => store.destroy()); - }, -}); + owner.register('model:person', Person); + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + shouldBackgroundReloadRecord: () => false, + }) + ); + owner.register('serializer:-default', JSONAPISerializer); -test('can have a property set on it', function(assert) { - let record = run(() => { - let record = store.createRecord('person'); - set(record, 'name', 'bar'); - return record; + store = owner.lookup('service:store'); + adapter = store.adapterFor('application'); }); - assert.equal(get(record, 'name'), 'bar', 'property was set on the record'); -}); - -test('setting a property on a record that has not changed does not cause it to become dirty', function(assert) { - assert.expect(2); - env.adapter.shouldBackgroundReloadRecord = () => false; - - return run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Peter', - isDrugAddict: true, + module('currentState', function() { + test('supports pushedData in root.deleted.uncommitted', async function(assert) { + let record = store.push({ + data: { + type: 'person', + id: '1', }, - }, - }); - - return store.findRecord('person', 1).then(person => { - assert.equal( - person.get('hasDirtyAttributes'), - false, - 'precond - person record should not be dirty' - ); - - person.set('name', 'Peter'); - person.set('isDrugAddict', true); + }); - assert.equal( - person.get('hasDirtyAttributes'), - false, - 'record does not become dirty after setting property to old value' - ); - }); - }); -}); + record.deleteRecord(); -test('resetting a property on a record cause it to become clean again', function(assert) { - assert.expect(3); - env.adapter.shouldBackgroundReloadRecord = () => false; - - return run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Peter', - isDrugAddict: true, + store.push({ + data: { + type: 'person', + id: '1', }, - }, - }); + }); - return store.findRecord('person', 1).then(person => { - assert.equal( - person.get('hasDirtyAttributes'), - false, - 'precond - person record should not be dirty' - ); - person.set('isDrugAddict', false); assert.equal( - person.get('hasDirtyAttributes'), - true, - 'record becomes dirty after setting property to a new value' + get(record, 'currentState.stateName'), + 'root.deleted.uncommitted', + 'record accepts pushedData is in root.deleted.uncommitted state' ); - person.set('isDrugAddict', true); - assert.equal( - person.get('hasDirtyAttributes'), - false, - 'record becomes clean after resetting property to the old value' - ); - }); - }); -}); - -test('resetting a property to the current in-flight value causes it to become clean when the save completes', function(assert) { - assert.expect(4); - - env.adapter.updateRecord = function(store, type, snapshot) { - return EmberPromise.resolve(); - }; - - return run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Tom', - }, - }, }); - let person = store.peekRecord('person', 1); - person.set('name', 'Thomas'); - - let saving = person.save(); + test('supports canonical updates via pushedData in root.deleted.saved', async function(assert) { + adapter.deleteRecord = () => { + return resolve({ data: null }); + }; - assert.equal(person.get('name'), 'Thomas'); - - person.set('name', 'Tomathy'); - assert.equal(person.get('name'), 'Tomathy'); - - person.set('name', 'Thomas'); - assert.equal(person.get('name'), 'Thomas'); - - return saving.then(() => { - assert.equal(person.get('hasDirtyAttributes'), false, 'The person is now clean'); - }); - }); -}); - -test('a record becomes clean again only if all changed properties are reset', function(assert) { - assert.expect(5); - env.adapter.shouldBackgroundReloadRecord = () => false; - - return run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Peter', - isDrugAddict: true, - }, - }, - }); - - return store.findRecord('person', 1).then(person => { - assert.equal( - person.get('hasDirtyAttributes'), - false, - 'precond - person record should not be dirty' - ); - person.set('isDrugAddict', false); - assert.equal( - person.get('hasDirtyAttributes'), - true, - 'record becomes dirty after setting one property to a new value' - ); - person.set('name', 'Mark'); - assert.equal( - person.get('hasDirtyAttributes'), - true, - 'record stays dirty after setting another property to a new value' - ); - person.set('isDrugAddict', true); - assert.equal( - person.get('hasDirtyAttributes'), - true, - 'record stays dirty after resetting only one property to the old value' - ); - person.set('name', 'Peter'); - assert.equal( - person.get('hasDirtyAttributes'), - false, - 'record becomes clean after resetting both properties to the old value' - ); - }); - }); -}); - -test('an invalid record becomes clean again if changed property is reset', function(assert) { - env.adapter.shouldBackgroundReloadRecord = () => false; - env.adapter.updateRecord = () => { - var error = new DS.InvalidError([{ name: 'not valid' }]); - - return EmberPromise.reject(error); - }; - - return run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Peter', - isDrugAddict: true, + let record = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + isArchived: false, + }, }, - }, - }); - - let person = store.peekRecord('person', 1); - - assert.equal( - person.get('hasDirtyAttributes'), - false, - 'precond - person record should not be dirty' - ); - person.set('name', 'Wolf'); - assert.equal( - person.get('hasDirtyAttributes'), - true, - 'record becomes dirty after setting one property to a new value' - ); + }); - return person.save().catch(() => { - assert.equal(person.get('isValid'), false, 'record is not valid'); - assert.equal(person.get('hasDirtyAttributes'), true, 'record still has dirty attributes'); + await record.destroyRecord(); - person.set('name', 'Peter'); + let currentState = record._internalModel.currentState; - assert.equal( - person.get('isValid'), - true, - 'record is valid after resetting attribute to old value' - ); - assert.equal( - person.get('hasDirtyAttributes'), - false, - 'record becomes clean after resetting property to the old value' + assert.ok( + currentState.stateName === 'root.deleted.saved', + 'record is in a persisted deleted state' ); - }); - }); -}); - -test('an invalid record stays dirty if only invalid property is reset', function(assert) { - env.adapter.shouldBackgroundReloadRecord = () => false; - env.adapter.updateRecord = () => { - var error = new DS.InvalidError([{ name: 'not valid' }]); - - return EmberPromise.reject(error); - }; - - return run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Peter', - isDrugAddict: true, - }, - }, - }); - - let person = store.peekRecord('person', 1); - - assert.equal( - person.get('hasDirtyAttributes'), - false, - 'precond - person record should not be dirty' - ); - person.set('name', 'Wolf'); - person.set('isDrugAddict', false); - assert.equal( - person.get('hasDirtyAttributes'), - true, - 'record becomes dirty after setting one property to a new value' - ); - - return person.save().catch(() => { - assert.equal(person.get('isValid'), false, 'record is not valid'); - assert.equal(person.get('hasDirtyAttributes'), true, 'record still has dirty attributes'); - - person.set('name', 'Peter'); - - assert.equal( - person.get('isValid'), - true, - 'record is valid after resetting invalid attribute to old value' + assert.equal(get(record, 'isDeleted'), true); + assert.ok( + store.peekRecord('person', '1') !== null, + 'the deleted person is not removed from store (no unload called)' ); - assert.equal(person.get('hasDirtyAttributes'), true, 'record still has dirty attributes'); - }); - }); -}); - -test('a record reports its unique id via the `id` property', function(assert) { - assert.expect(1); - env.adapter.shouldBackgroundReloadRecord = () => false; - - return run(() => { - store.push({ - data: { - type: 'person', - id: '1', - }, - }); - - return store.findRecord('person', 1).then(record => { - assert.equal(get(record, 'id'), 1, 'reports id as id by default'); - }); - }); -}); - -test("a record's id is included in its toString representation", function(assert) { - assert.expect(1); - env.adapter.shouldBackgroundReloadRecord = () => false; - - let person = run(() => - store.push({ - data: { - type: 'person', - id: '1', - }, - }) - ); - - assert.equal( - person.toString(), - ``, - 'reports id in toString' - ); -}); - -testInDebug('trying to set an `id` attribute should raise', function(assert) { - Person = DS.Model.extend({ - id: DS.attr('number'), - name: DS.attr('string'), - }); - - const store = createStore({ - person: Person, - }); - assert.expectAssertion(() => { - run(() => { store.push({ data: { type: 'person', id: '1', attributes: { - name: 'Scumdale', + isArchived: true, }, }, }); - store.findRecord('person', 1); + + currentState = record._internalModel.currentState; + + assert.ok( + currentState.stateName === 'root.deleted.saved', + 'record is still in a persisted deleted state' + ); + assert.ok(get(record, 'isDeleted') === true, 'The record is still deleted'); + assert.ok( + get(record, 'isArchived') === true, + 'The record reflects the update to canonical state' + ); }); - }, /You may not set `id`/); -}); -test(`a collision of a record's id with object function's name`, function(assert) { - assert.expect(1); - env.adapter.shouldBackgroundReloadRecord = () => false; + test('Does not support dirtying in root.deleted.saved', async function(assert) { + adapter.deleteRecord = () => { + return resolve({ data: null }); + }; - let hasWatchMethod = Object.prototype.watch; - try { - if (!hasWatchMethod) { - Object.prototype.watch = function() {}; - } - return run(() => { - store.push({ + let record = store.push({ data: { type: 'person', - id: 'watch', + id: '1', + attributes: { + isArchived: false, + }, }, }); - return store.findRecord('person', 'watch').then(record => { - assert.equal( - get(record, 'id'), - 'watch', - 'record is successfully created and could be found by its id' - ); - }); - }); - } finally { - if (!hasWatchMethod) { - delete Object.prototype.watch; - } - } -}); - -test('it should use `_internalModel` and not `internalModel` to store its internalModel', function(assert) { - run(() => { - store.push({ - data: { - type: 'person', - id: 1, - attributes: {}, - }, - }); - - assert.equal( - store.peekRecord('person', 1).get('internalModel'), - undefined, - `doesn't shadow internalModel key` - ); - }); -}); + await record.destroyRecord(); -test('it should cache attributes', function(assert) { - assert.expect(2); + let currentState = record._internalModel.currentState; - const Post = DS.Model.extend({ - updatedAt: DS.attr('string'), - }); + assert.ok( + currentState.stateName === 'root.deleted.saved', + 'record is in a persisted deleted state' + ); + assert.equal(get(record, 'isDeleted'), true); + assert.ok( + store.peekRecord('person', '1') !== null, + 'the deleted person is not removed from store (no unload called)' + ); - const store = createStore({ - adapter: DS.JSONAPIAdapter.extend({ - shouldBackgroundReloadRecord: () => false, - }), - post: Post, - }); + assert.expectAssertion(() => { + set(record, 'isArchived', true); + }, /Attempted to set 'isArchived' to 'true' on the deleted record /); - let dateString = 'Sat, 31 Dec 2011 00:08:16 GMT'; - let date = new Date(dateString); + currentState = record._internalModel.currentState; - return run(() => { - store.push({ - data: { - type: 'post', - id: '1', - }, + assert.ok( + currentState.stateName === 'root.deleted.saved', + 'record is still in a persisted deleted state' + ); + assert.ok(get(record, 'isDeleted') === true, 'The record is still deleted'); + assert.ok(get(record, 'isArchived') === false, 'The record reflects canonical state'); }); - return store - .findRecord('post', '1') - .then(record => { - record.set('updatedAt', date); - - assert.deepEqual(date, get(record, 'updatedAt'), 'setting a date returns the same date'); - assert.strictEqual( - get(record, 'updatedAt'), - get(record, 'updatedAt'), - 'second get still returns the same object' - ); - }) - .finally(() => { - run(store, 'destroy'); - }); - }); -}); - -test('changedAttributes() return correct values', function(assert) { - assert.expect(4); - - const Mascot = DS.Model.extend({ - name: DS.attr('string'), - likes: DS.attr('string'), - isMascot: DS.attr('boolean'), - }); - - let store = createStore({ - mascot: Mascot, - }); - - let mascot = run(() => { - store.push({ - data: { - type: 'mascot', - id: '1', - attributes: { - likes: 'JavaScript', - isMascot: true, + test('currentState is accessible when the record is created', async function(assert) { + let record = store.push({ + data: { + type: 'person', + id: '1', }, - }, - }); - - return store.peekRecord('mascot', 1); - }); - - assert.equal(Object.keys(mascot.changedAttributes()).length, 0, 'there are no initial changes'); - run(() => { - mascot.set('name', 'Tomster'); // new value - mascot.set('likes', 'Ember.js'); // changed value - mascot.set('isMascot', true); // same value - }); - - let changedAttributes = mascot.changedAttributes(); - - assert.deepEqual(changedAttributes.name, [undefined, 'Tomster']); - assert.deepEqual(changedAttributes.likes, ['JavaScript', 'Ember.js']); - - run(() => mascot.rollbackAttributes()); - - assert.equal( - Object.keys(mascot.changedAttributes()).length, - 0, - 'after rollback attributes there are no changes' - ); -}); - -function toObj(obj) { - // https://github.com/jquery/qunit/issues/851 - let result = Object.create(null); - for (let key in obj) { - result[key] = obj[key]; - } - return result; -} - -test('changedAttributes() works while the record is being saved', function(assert) { - assert.expect(1); - - let cat; - const Adapter = DS.Adapter.extend({ - createRecord(store, model, snapshot) { - assert.deepEqual(toObj(cat.changedAttributes()), { - name: [undefined, 'Argon'], - likes: [undefined, 'Cheese'], }); - return { data: { id: 1, type: 'mascot' } }; - }, - }); - - const Mascot = DS.Model.extend({ - name: DS.attr('string'), - likes: DS.attr('string'), - isMascot: DS.attr('boolean'), - }); - - let store = createStore({ - mascot: Mascot, - adapter: Adapter, - }); - - return run(() => { - cat = store.createRecord('mascot'); - cat.setProperties({ - name: 'Argon', - likes: 'Cheese', + assert.equal( + get(record, 'currentState.stateName'), + 'root.loaded.saved', + 'records pushed into the store start in the loaded state' + ); }); - - return cat.save(); }); -}); -test('changedAttributes() works while the record is being updated', function(assert) { - assert.expect(1); - let cat; - const Adapter = DS.Adapter.extend({ - updateRecord(store, model, snapshot) { - assert.deepEqual(toObj(cat.changedAttributes()), { - name: ['Argon', 'Helia'], - likes: ['Cheese', 'Mussels'], + module('ID', function() { + test('a record reports its unique id via the `id` property', async function(assert) { + store.push({ + data: { + type: 'person', + id: '1', + }, }); - return { data: { id: '1', type: 'mascot' } }; - }, - }); - - const Mascot = DS.Model.extend({ - name: DS.attr('string'), - likes: DS.attr('string'), - isMascot: DS.attr('boolean'), - }); - - let store = createStore({ - mascot: Mascot, - adapter: Adapter, - }); + let record = await store.findRecord('person', '1'); - return run(() => { - store.push({ - data: { - type: 'mascot', - id: '1', - attributes: { - name: 'Argon', - likes: 'Cheese', - }, - }, - }); - - cat = store.peekRecord('mascot', 1); - cat.setProperties({ - name: 'Helia', - likes: 'Mussels', + assert.equal(get(record, 'id'), 1, 'reports id as id by default'); }); - return cat.save(); - }); -}); - -test('a DS.Model does not require an attribute type', function(assert) { - const Tag = DS.Model.extend({ - name: DS.attr(), - }); - - let store = createStore({ - tag: Tag, - }); - let tag = store.createRecord('tag', { name: 'test' }); - - assert.equal(get(tag, 'name'), 'test', 'the value is persisted'); -}); - -test('a DS.Model can have a defaultValue without an attribute type', function(assert) { - const Tag = DS.Model.extend({ - name: DS.attr({ defaultValue: 'unknown' }), - }); - - let store = createStore({ - tag: Tag, - }); - - let tag = store.createRecord('tag'); - - assert.equal(get(tag, 'name'), 'unknown', 'the default value is found'); -}); - -testInDebug('Calling attr() throws a warning', function(assert) { - assert.expect(1); - - let person = store.createRecord('person', { id: 1, name: 'TomHuda' }); - - assert.throws( - () => { - person.attr(); - }, - /The `attr` method is not available on DS.Model, a DS.Snapshot was probably expected/, - 'attr() throws a warning' - ); -}); - -test('supports pushedData in root.deleted.uncommitted', function(assert) { - let hash = { - data: { - type: 'person', - id: '1', - }, - }; - - run(() => { - let record = store.push(hash); - record.deleteRecord(); - store.push(hash); - assert.equal( - get(record, 'currentState.stateName'), - 'root.deleted.uncommitted', - 'record accepts pushedData is in root.deleted.uncommitted state' - ); - }); -}); - -test('supports canonical updates via pushedData in root.deleted.saved', function(assert) { - let { adapter } = env; - - adapter.shouldBackgroundReloadRecord = () => false; - adapter.deleteRecord = () => { - return resolve(); - }; - - let record = run(() => - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - isArchived: false, + test("a record's id is included in its toString representation", async function(assert) { + let person = store.push({ + data: { + type: 'person', + id: '1', }, - }, - }) - ); - - run(() => { - record.destroyRecord().then(() => { - let currentState = record._internalModel.currentState; + }); - assert.ok( - currentState.stateName === 'root.deleted.saved', - 'record is in a persisted deleted state' - ); - assert.equal(get(record, 'isDeleted'), true); - assert.ok( - store.peekRecord('person', '1') !== null, - 'the deleted person is not removed from store (no unload called)' + assert.equal( + person.toString(), + ``, + 'reports id in toString' ); }); - }); - - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - isArchived: true, - }, - }, - }); - - let currentState = record._internalModel.currentState; - assert.ok( - currentState.stateName === 'root.deleted.saved', - 'record is still in a persisted deleted state' - ); - assert.ok(get(record, 'isDeleted') === true, 'The record is still deleted'); - assert.ok( - get(record, 'isArchived') === true, - 'The record reflects the update to canonical state' - ); - }); -}); + testInDebug('trying to use `id` as an attribute should raise', async function(assert) { + class TestModel extends Model { + @attr('number') + id; + @attr('string') + name; + } -test('Does not support dirtying in root.deleted.saved', function(assert) { - let { adapter } = env; - - adapter.shouldBackgroundReloadRecord = () => false; - adapter.deleteRecord = () => { - return resolve(); - }; - - let record = run(() => - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - isArchived: false, - }, - }, - }) - ); + this.owner.register('model:test-model', TestModel); - run(() => { - record.destroyRecord().then(() => { - let currentState = record._internalModel.currentState; + assert.expectAssertion(() => { + let ModelClass = store.modelFor('test-model'); + get(ModelClass, 'attributes'); + }, /You may not set `id` as an attribute on your model/); - assert.ok( - currentState.stateName === 'root.deleted.saved', - 'record is in a persisted deleted state' - ); - assert.equal(get(record, 'isDeleted'), true); - assert.ok( - store.peekRecord('person', '1') !== null, - 'the deleted person is not removed from store (no unload called)' - ); + assert.expectAssertion(() => { + store.push({ + data: { + id: '1', + type: 'test-model', + attributes: { + id: 'foo', + name: 'bar', + }, + }, + }); + }, /You may not set 'id' as an attribute on your model/); }); - }); - - run(() => { - assert.expectAssertion(() => { - set(record, 'isArchived', true); - }, /Attempted to set 'isArchived' to 'true' on the deleted record /); - let currentState = record._internalModel.currentState; + test(`a collision of a record's id with object function's name`, async function(assert) { + // see https://github.com/emberjs/ember.js/issues/4792 for an explanation of this test + // and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/watch + // this effectively tests that our identityMap does not choke on IDs that are method names + // such as `watch` which is particularly problematic + assert.expect(1); - assert.ok( - currentState.stateName === 'root.deleted.saved', - 'record is still in a persisted deleted state' - ); - assert.ok(get(record, 'isDeleted') === true, 'The record is still deleted'); - assert.ok(get(record, 'isArchived') === false, 'The record reflects canonical state'); - }); -}); + let hasWatchMethod = Object.prototype.watch; + try { + if (!hasWatchMethod) { + Object.prototype.watch = function() {}; + } -test('currentState is accessible when the record is created', function(assert) { - let hash = { - data: { - type: 'person', - id: '1', - }, - }; - - run(() => { - let record = store.push(hash); - assert.equal( - get(record, 'currentState.stateName'), - 'root.loaded.saved', - 'records pushed into the store start in the loaded state' - ); - }); -}); + store.push({ + data: { + type: 'person', + id: 'watch', + }, + }); -module('unit/model - DS.Model updating', { - beforeEach() { - Person = DS.Model.extend({ - name: DS.attr('string'), - }); + let record = await store.findRecord('person', 'watch'); - env = setupStore({ - person: Person, + assert.equal( + get(record, 'id'), + 'watch', + 'record is successfully created and could be found by its id' + ); + } finally { + if (!hasWatchMethod) { + delete Object.prototype.watch; + } + } }); - store = env.store; - run(() => { + test('can ask if record with a given id is loaded', async function(assert) { store.push({ data: [ { @@ -835,769 +296,1169 @@ module('unit/model - DS.Model updating', { }, ], }); + + assert.equal(store.hasRecordForId('person', 1), true, 'should have person with id 1'); + assert.equal(store.hasRecordForId('person', 1), true, 'should have person with id 1'); + assert.equal(store.hasRecordForId('person', 4), false, 'should not have person with id 4'); + assert.equal(store.hasRecordForId('person', 4), false, 'should not have person with id 4'); }); - }, - afterEach() { - run(store, 'destroy'); - }, -}); + test('setting the id during createRecord should correctly update the id', async function(assert) { + let person = store.createRecord('person', { id: 'john' }); -test('a DS.Model can update its attributes', function(assert) { - assert.expect(1); - env.adapter.shouldBackgroundReloadRecord = () => false; + assert.equal(person.get('id'), 'john', 'new id should be correctly set.'); - return run(() => { - return store.findRecord('person', 2).then(person => { - set(person, 'name', 'Brohuda Katz'); - assert.equal(get(person, 'name'), 'Brohuda Katz', 'setting took hold'); + let record = store.peekRecord('person', 'john'); + + assert.ok(person === record, 'The cache has an entry for john'); }); - }); -}); -test('a DS.Model can have a defaultValue', function(assert) { - const Tag = DS.Model.extend({ - name: DS.attr('string', { defaultValue: 'unknown' }), - }); + test('updating the id with store.setRecordId should work correctly when the id property is watched', async function(assert) { + const OddPerson = Model.extend({ + name: DSattr('string'), + idComputed: computed('id', function() { + return this.get('id'); + }), + }); + this.owner.register('model:odd-person', OddPerson); + + let person = store.createRecord('odd-person'); + let oddId = person.get('idComputed'); + + assert.equal(oddId, null, 'initial computed get is null'); + // test .get access of id + assert.equal(person.get('id'), null, 'initial created model id should be null'); + + store.setRecordId('odd-person', 'john', person._internalModel.clientId); + + oddId = person.get('idComputed'); + assert.equal(oddId, 'john', 'computed get is correct'); + // test direct access of id + assert.equal(person.id, 'john', 'new id should be correctly set.'); + }); + + test('ID mutation (complicated)', async function(assert) { + let idChange = 0; + const OddPerson = Model.extend({ + name: DSattr('string'), + idComputed: computed('id', function() {}), + idDidChange: observer('id', () => idChange++), + }); + this.owner.register('model:odd-person', OddPerson); + + let person = store.createRecord('odd-person'); + person.get('idComputed'); + assert.equal(idChange, 0); + + assert.equal(person.get('id'), null, 'initial created model id should be null'); + assert.equal(idChange, 0); + store._setRecordId(person._internalModel, 'john'); + assert.equal(idChange, 1); + assert.equal(person.get('id'), 'john', 'new id should be correctly set.'); + }); + + test('an ID of 0 is allowed', async function(assert) { + store.push({ + data: { + type: 'person', + id: 0, // explicit number 0 to make this as risky as possible + attributes: { + name: 'Tom Dale', + }, + }, + }); - let store = createStore({ - tag: Tag, + // we peek it instead of getting the return of push to make sure + // we can locate it in the identity map + let record = store.peekRecord('person', 0); + + assert.equal(record.get('name'), 'Tom Dale', 'found record with id 0'); + }); }); - let tag = store.createRecord('tag'); + module('@attr()', function() { + test('a Model does not require an attribute type', async function(assert) { + class NativeTag extends Model { + @attr() + name; + } + const LegacyTag = Model.extend({ + name: DSattr(), + }); - assert.equal(get(tag, 'name'), 'unknown', 'the default value is found'); + this.owner.register('model:native-tag', NativeTag); + this.owner.register('model:legacy-tag', LegacyTag); - run(() => set(tag, 'name', null)); + let nativeTag = store.createRecord('native-tag', { name: 'test native' }); + let legacyTag = store.createRecord('legacy-tag', { name: 'test legacy' }); - assert.equal(get(tag, 'name'), null, `null doesn't shadow defaultValue`); -}); + assert.equal(get(nativeTag, 'name'), 'test native', 'the value is persisted'); + assert.equal(get(legacyTag, 'name'), 'test legacy', 'the value is persisted'); + }); + + test('a Model can have a defaultValue without an attribute type', async function(assert) { + class NativeTag extends Model { + @attr({ defaultValue: 'unknown native tag' }) + name; + } + const LegacyTag = Model.extend({ + name: DSattr({ defaultValue: 'unknown legacy tag' }), + }); + + this.owner.register('model:native-tag', NativeTag); + this.owner.register('model:legacy-tag', LegacyTag); -test(`a DS.model can define 'setUnknownProperty'`, function(assert) { - const Tag = DS.Model.extend({ - name: DS.attr('string'), + let nativeTag = store.createRecord('native-tag'); + let legacyTag = store.createRecord('legacy-tag'); - setUnknownProperty(key, value) { - if (key === 'title') { - this.set('name', value); + assert.equal(get(nativeTag, 'name'), 'unknown native tag', 'the default value is found'); + assert.equal(get(legacyTag, 'name'), 'unknown legacy tag', 'the default value is found'); + }); + + test('a defaultValue for an attribute can be a function', async function(assert) { + class Tag extends Model { + @attr('string', { + defaultValue() { + return 'le default value'; + }, + }) + createdAt; } - }, - }); + this.owner.register('model:tag', Tag); - let store = createStore({ - tag: Tag, - }); + let tag = store.createRecord('tag'); + assert.equal( + get(tag, 'createdAt'), + 'le default value', + 'the defaultValue function is evaluated' + ); + }); - let tag = run(() => { - let record = store.createRecord('tag', { name: 'old' }); - set(record, 'title', 'new'); + test('a defaultValue function gets the record, options, and key', async function(assert) { + assert.expect(2); + class Tag extends Model { + @attr('string', { + defaultValue(record, options, key) { + assert.deepEqual(record, tag, 'the record is passed in properly'); + assert.equal(key, 'createdAt', 'the attribute being defaulted is passed in properly'); + return 'le default value'; + }, + }) + createdAt; + } + this.owner.register('model:tag', Tag); - return record; - }); + let tag = store.createRecord('tag'); - assert.equal(get(tag, 'name'), 'new', 'setUnknownProperty not triggered'); -}); + get(tag, 'createdAt'); + }); -test('a defaultValue for an attribute can be a function', function(assert) { - const Tag = DS.Model.extend({ - createdAt: DS.attr('string', { - defaultValue() { - return 'le default value'; - }, - }), - }); + testInDebug('We assert when defaultValue is a constant non-primitive instance', async function( + assert + ) { + class Tag extends Model { + @attr({ defaultValue: [] }) + tagInfo; + } + this.owner.register('model:tag', Tag); + + let tag = store.createRecord('tag'); - let store = createStore({ - tag: Tag, + assert.expectAssertion(() => { + get(tag, 'tagInfo'); + }, /Non primitive defaultValues are not supported/); + }); }); - let tag = store.createRecord('tag'); - assert.equal(get(tag, 'createdAt'), 'le default value', 'the defaultValue function is evaluated'); -}); + module('Attribute Transforms', function() { + function converts(testName, type, provided, expected, options = {}) { + test(testName, async function(assert) { + let { owner } = this; + class TestModel extends Model { + @attr(type, options) + name; + } -test('a defaultValue function gets the record, options, and key', function(assert) { - assert.expect(2); - - const Tag = DS.Model.extend({ - createdAt: DS.attr('string', { - defaultValue(record, options, key) { - assert.deepEqual(record, tag, 'the record is passed in properly'); - assert.equal(key, 'createdAt', 'the attribute being defaulted is passed in properly'); - return 'le default value'; - }, - }), - }); + owner.register('model:model', TestModel); + owner.register('serializer:model', JSONSerializer); + store.push(store.normalize('model', { id: 1, name: provided })); + store.push(store.normalize('model', { id: 2 })); - let store = createStore({ - tag: Tag, - }); + let record = store.peekRecord('model', 1); - let tag = store.createRecord('tag'); + assert.deepEqual( + get(record, 'name'), + expected, + type + ' coerces ' + provided + ' to ' + expected + ); + }); + } - get(tag, 'createdAt'); -}); + function convertsFromServer(testName, type, provided, expected) { + test(testName, async function(assert) { + let { owner } = this; + class TestModel extends Model { + @attr(type) + name; + } -testInDebug('a complex object defaultValue is deprecated', function(assert) { - const Tag = DS.Model.extend({ - tagInfo: DS.attr({ defaultValue: [] }), - }); + owner.register('model:model', TestModel); + owner.register('serializer:model', JSONSerializer); - let store = createStore({ - tag: Tag, - }); + let record = store.push( + store.normalize('model', { + id: '1', + name: provided, + }) + ); - let tag = store.createRecord('tag'); + assert.deepEqual( + get(record, 'name'), + expected, + type + ' coerces ' + provided + ' to ' + expected + ); + }); + } - assert.expectAssertion(() => { - get(tag, 'tagInfo'); - }, /Non primitive defaultValues are not supported/); -}); + function convertsWhenSet(testName, type, provided, expected) { + test(testName, async function(assert) { + let { owner } = this; + class TestModel extends Model { + @attr(type) + name; + } -test('setting a property to undefined on a newly created record should not impact the current state', function(assert) { - const Tag = DS.Model.extend({ - name: DS.attr('string'), - }); + owner.register('model:model', TestModel); + owner.register('serializer:model', JSONSerializer); - let store = createStore({ - tag: Tag, - }); + let record = store.push({ + data: { + type: 'model', + id: '2', + }, + }); + + set(record, 'name', provided); + assert.deepEqual( + record.serialize().name, + expected, + type + ' saves ' + provided + ' as ' + expected + ); + }); + } + + module('String', function() { + converts('string-to-string', 'string', 'Scumbag Tom', 'Scumbag Tom'); + converts('number-to-string', 'string', 1, '1'); + converts('empty-string-to-empty-string', 'string', '', ''); + converts('null-to-null', 'string', null, null); + }); + + module('Number', function() { + converts('string-1-to-number-1', 'number', '1', 1); + converts('string-0-to-number-0', 'number', '0', 0); + converts('1-to-1', 'number', 1, 1); + converts('0-to-0', 'number', 0, 0); + converts('empty-string-to-null', 'number', '', null); + converts('null-to-null', 'number', null, null); + converts('boolean-true-to-1', 'number', true, 1); + converts('boolean-false-to-0', 'number', false, 0); + }); + + module('Boolean', function() { + converts('string-1-to-true', 'boolean', '1', true); + converts('empty-string-to-false', 'boolean', '', false); + converts('number-1-to-true', 'boolean', 1, true); + converts('number-0-to-false', 'boolean', 0, false); + + converts('null-to-null { allowNull: true }', 'boolean', null, null, { allowNull: true }); + converts('null-to-false { allowNull: false }', 'boolean', null, false, { allowNull: false }); + converts('null-to-false', 'boolean', null, false); - let tag = run(() => { - let record = store.createRecord('tag'); + converts('boolean-true-to-true', 'boolean', true, true); + converts('boolean-false-to-false', 'boolean', false, false); + }); + + module('Date', function() { + converts('null-to-null', 'date', null, null); + converts('undefined-to-undefined', 'date', undefined, undefined); - set(record, 'name', 'testing'); - set(record, 'name', undefined); + let dateString = '2011-12-31T00:08:16.000Z'; + let date = new Date(dateString); - return record; + convertsFromServer('string-to-Date', 'date', dateString, date); + convertsWhenSet('Date-to-string', 'date', date, dateString); + }); }); - assert.equal(get(tag, 'currentState.stateName'), 'root.loaded.created.uncommitted'); + module('Evented', function() { + test('an event listener can be added to a record', async function(assert) { + let count = 0; + let F = function() { + count++; + }; - tag = store.createRecord('tag', { name: undefined }); + let record = store.createRecord('person'); - assert.equal(get(tag, 'currentState.stateName'), 'root.loaded.created.uncommitted'); -}); + record.on('event!', F); + record.trigger('event!'); -// NOTE: this is a 'backdoor' test that ensures internal consistency, and should be -// thrown out if/when the current `_attributes` hash logic is removed. -test('setting a property back to its original value removes the property from the `_attributes` hash', function(assert) { - assert.expect(3); - env.adapter.shouldBackgroundReloadRecord = () => false; + await settled(); - return run(() => { - return store.findRecord('person', 1).then(person => { - let internalModel = person._internalModel; - let dataSource = internalModel._recordData || internalModel; - assert.equal(dataSource._attributes.name, undefined, 'the `_attributes` hash is clean'); + assert.equal(count, 1, 'the event was triggered'); + record.trigger('event!'); - set(person, 'name', 'Niceguy Dale'); + await settled(); - assert.equal( - dataSource._attributes.name, - 'Niceguy Dale', - 'the `_attributes` hash contains the changed value' - ); + assert.equal(count, 2, 'the event was triggered'); + }); - set(person, 'name', 'Scumbag Dale'); + test('when an event is triggered on a record the method with the same name is invoked with arguments', async function(assert) { + let count = 0; + let F = function() { + count++; + }; + let record = store.createRecord('person'); + + record.eventNamedMethod = F; - assert.equal(dataSource._attributes.name, undefined, 'the `_attributes` hash is reset'); + record.trigger('eventNamedMethod'); + + await settled(); + + assert.equal(count, 1, 'the corresponding method was called'); }); - }); -}); -module('unit/model - with a simple Person model', { - beforeEach() { - Person = DS.Model.extend({ - name: DS.attr('string'), + test('when a method is invoked from an event with the same name the arguments are passed through', async function(assert) { + let eventMethodArgs = null; + let F = function() { + eventMethodArgs = arguments; + }; + let record = store.createRecord('person'); + + record.eventThatTriggersMethod = F; + record.trigger('eventThatTriggersMethod', 1, 2); + + await settled(); + + assert.equal(eventMethodArgs[0], 1); + assert.equal(eventMethodArgs[1], 2); }); - store = createStore({ - person: Person, + }); + + module('Reserved Props', function() { + testInDebug(`don't allow setting of readOnly state props`, async function(assert) { + let record = store.createRecord('person'); + + assert.expectAssertion(() => { + record.set('isLoaded', true); + }, /Cannot set read-only property "isLoaded"/); }); - run(() => { - store.push({ - data: [ - { - type: 'person', - id: '1', - attributes: { - name: 'Scumbag Dale', - }, + class NativePostWithInternalModel extends Model { + @attr('string') + _internalModel; + @attr('string') + name; + } + class NativePostWithRecordData extends Model { + @attr('string', { defaultValue: 'hello' }) + recordData; + @attr('string') + name; + } + class NativePostWithCurrentState extends Model { + @attr('string') + currentState; + @attr('string') + name; + } + const PROP_MAP = { + _internalModel: NativePostWithInternalModel, + recordData: NativePostWithRecordData, + currentState: NativePostWithCurrentState, + }; + + function testReservedProperty(prop) { + let testName = `A subclass of Model cannot use the reserved property '${prop}'`; + + testInDebug(testName, async function(assert) { + const NativePost = PROP_MAP[prop]; + const LegacyPost = Model.extend({ + [prop]: DSattr('string'), + name: DSattr('string'), + }); + this.owner.register('model:native-post', NativePost); + this.owner.register('model:legacy-post', LegacyPost); + + const msg = `'${prop}' is a reserved property name on instances of classes extending Model.`; + + assert.throws( + () => { + store.createRecord('native-post', { name: 'TomHuda' }); }, - { - type: 'person', - id: '2', - attributes: { - name: 'Scumbag Katz', - }, + function(e) { + return e.message.indexOf(msg) === 0; }, - { - type: 'person', - id: '3', - attributes: { - name: 'Scumbag Bryn', - }, + 'We throw for native-style classes' + ); + + assert.throws( + () => { + store.createRecord('legacy-post', { name: 'TomHuda' }); }, - ], + function(e) { + return e.message.indexOf(msg) === 0; + }, + 'We throw for legacy-style classes' + ); }); - }); - }, - afterEach() { - run(store, 'destroy'); - }, -}); + } -test('can ask if record with a given id is loaded', function(assert) { - assert.equal(store.hasRecordForId('person', 1), true, 'should have person with id 1'); - assert.equal(store.hasRecordForId('person', 1), true, 'should have person with id 1'); - assert.equal(store.hasRecordForId('person', 4), false, 'should not have person with id 4'); - assert.equal(store.hasRecordForId('person', 4), false, 'should not have person with id 4'); -}); + ['recordData', '_internalModel', 'currentState'].forEach(testReservedProperty); -test('a listener can be added to a record', function(assert) { - let count = 0; - let F = function() { - count++; - }; + testInDebug( + 'A subclass of Model throws an error when calling create() directly', + async function(assert) { + class NativePerson extends Model {} + const LegacyPerson = Model.extend({}); - let record = store.createRecord('person'); + assert.throws( + () => { + NativePerson.create(); + }, + /You should not call `create` on a model/, + 'Throws an error when calling create() on model' + ); - record.on('event!', F); - run(() => record.trigger('event!')); + assert.throws( + () => { + new NativePerson(); + }, + /You should not call `create` on a model/, + 'Throws an error when calling instantiating via new Model' + ); - assert.equal(count, 1, 'the event was triggered'); + assert.throws( + () => { + LegacyPerson.create(); + }, + /You should not call `create` on a model/, + 'Throws an error when calling create() on model' + ); - run(() => record.trigger('event!')); + assert.throws( + () => { + new LegacyPerson(); + }, + /You should not call `create` on a model/, + 'Throws an error when calling instantiating view new Model()' + ); + } + ); + }); - assert.equal(count, 2, 'the event was triggered'); -}); + module('init()', function() { + test('ensure model exits loading state, materializes data and fulfills promise only after data is available', async function(assert) { + assert.expect(2); + adapter.findRecord = () => + resolve({ + data: { + id: 1, + type: 'person', + attributes: { name: 'John' }, + }, + }); + + let person = await store.findRecord('person', 1); -test('when an event is triggered on a record the method with the same name is invoked with arguments', function(assert) { - let count = 0; - let F = function() { - count++; - }; - let record = store.createRecord('person'); + assert.equal( + get(person, 'currentState.stateName'), + 'root.loaded.saved', + 'model is in loaded state' + ); + assert.equal(get(person, 'isLoaded'), true, 'model is loaded'); + }); - record.eventNamedMethod = F; + test('Pushing a record into the store should transition new records to the loaded state', async function(assert) { + let person = store.createRecord('person', { id: 1, name: 'TomHuda' }); - run(() => record.trigger('eventNamedMethod')); + assert.equal(person.get('isNew'), true, 'createRecord should put records into the new state'); - assert.equal(count, 1, 'the corresponding method was called'); -}); + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'TomHuda', + }, + }, + }); -test('when a method is invoked from an event with the same name the arguments are passed through', function(assert) { - let eventMethodArgs = null; - let F = function() { - eventMethodArgs = arguments; - }; - let record = store.createRecord('person'); + assert.equal( + person.get('isNew'), + false, + 'push should put move the record into the loaded state' + ); + // TODO either this is a bug or being able to push a record with the same ID as a client created one is a bug + // probably the bug is the former + assert.equal( + get(person, 'currentState.stateName'), + 'root.loaded.updated.uncommitted', + 'model is in loaded state' + ); + }); - record.eventThatTriggersMethod = F; + test('internalModel is ready by `init`', async function(assert) { + let nameDidChange = 0; - run(() => record.trigger('eventThatTriggersMethod', 1, 2)); + class OddNativePerson extends Model { + @attr('string') + name; + init() { + super.init(...arguments); + this.set('name', 'my-name-set-in-init'); + } + } + const OddLegacyPerson = Model.extend({ + name: DSattr('string'), - assert.equal(eventMethodArgs[0], 1); - assert.equal(eventMethodArgs[1], 2); -}); + init() { + this._super(...arguments); + this.set('name', 'my-name-set-in-init'); + }, -function converts(assert, type, provided, expected, options = {}) { - const Model = DS.Model.extend({ - name: DS.attr(type, options), - }); + nameDidChange: observer('name', () => nameDidChange++), + }); + this.owner.register('model:native-person', OddNativePerson); + this.owner.register('model:legacy-person', OddLegacyPerson); - let registry, container; - if (Ember.Registry) { - registry = new Ember.Registry(); - container = registry.container(); - } else { - container = new Ember.Container(); - registry = container; - } - - let testStore = createStore({ - model: Model, - }); - getOwner(testStore).register('serializer:model', DS.JSONSerializer); + assert.equal(nameDidChange, 0, 'observer should not trigger on create'); + let person = store.createRecord('legacy-person'); + assert.equal(nameDidChange, 0, 'observer should not trigger on create'); + assert.equal(person.get('name'), 'my-name-set-in-init'); - run(() => { - testStore.push(testStore.normalize('model', { id: 1, name: provided })); - testStore.push(testStore.normalize('model', { id: 2 })); + person = store.createRecord('native-person'); + assert.equal(person.get('name'), 'my-name-set-in-init'); + }); - let record = testStore.peekRecord('model', 1); + test('accessing attributes during init should not throw an error', async function(assert) { + const Person = Model.extend({ + name: DSattr('string'), - assert.deepEqual( - get(record, 'name'), - expected, - type + ' coerces ' + provided + ' to ' + expected - ); + init() { + this._super(...arguments); + assert.ok(this.get('name') === 'bam!', 'We all good here'); + }, + }); + this.owner.register('model:odd-person', Person); + + store.createRecord('odd-person', { name: 'bam!' }); + }); }); - // See: Github issue #421 - // record = testStore.find(Model, 2); - // set(record, 'name', provided); - // deepEqual(get(record, 'name'), expected, type + " coerces " + provided + " to " + expected); -} + module('toJSON()', function(hooks) { + test('A Model can be JSONified', async function(assert) { + let record = store.createRecord('person', { name: 'TomHuda' }); -function convertsFromServer(assert, type, provided, expected) { - const Model = DS.Model.extend({ - name: DS.attr(type), - }); + assert.deepEqual(record.toJSON(), { + data: { + type: 'people', + attributes: { + name: 'TomHuda', + 'is-archived': undefined, + 'is-drug-addict': false, + }, + }, + }); + }); - let registry, container; - if (Ember.Registry) { - registry = new Ember.Registry(); - container = registry.container(); - } else { - container = new Ember.Container(); - registry = container; - } - let testStore = createStore({ - model: Model, - adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord() { - return false; - }, - }), - }); - getOwner(testStore).register('serializer:model', DS.JSONSerializer); + test('toJSON looks up the JSONSerializer using the store instead of using JSONSerializer.create', async function(assert) { + class Author extends Model { + @hasMany('post', { async: false, inverse: 'author' }) + posts; + } + class Post extends Model { + @belongsTo('author', { async: false, inverse: 'posts' }) + author; + } + this.owner.register('model:author', Author); + this.owner.register('model:post', Post); + + // Loading the person without explicitly + // loading its relationships seems to trigger the + // original bug where `this.store` was not + // present on the serializer due to using .create + // instead of `store.serializerFor`. + let person = store.push({ + data: { + type: 'author', + id: '1', + }, + }); - return run(() => { - testStore.push( - testStore.normalize('model', { - id: '1', - name: provided, - }) - ); + let errorThrown = false; + let json; + try { + json = person.toJSON(); + } catch (e) { + errorThrown = true; + } - return testStore.findRecord('model', 1).then(record => { - assert.deepEqual( - get(record, 'name'), - expected, - type + ' coerces ' + provided + ' to ' + expected - ); + assert.ok(!errorThrown, 'error not thrown due to missing store'); + assert.deepEqual(json, { data: { type: 'authors' } }); }); }); -} -test('a DS.Model can describe String attributes', function(assert) { - assert.expect(4); + module('Updating', function() { + test('a Model can update its attributes', async function(assert) { + assert.expect(1); + + let person = store.push({ + data: { + type: 'person', + id: '2', + attributes: { + name: 'Scumbag Katz', + }, + }, + }); + + set(person, 'name', 'Brohuda Katz'); + assert.equal(get(person, 'name'), 'Brohuda Katz', 'setting took hold'); + }); + + test(`clearing the value when a Model's defaultValue was in use works`, async function(assert) { + class Tag extends Model { + @attr('string', { defaultValue: 'unknown' }) + name; + } + + this.owner.register('model:tag', Tag); + + let tag = store.createRecord('tag'); + assert.equal(get(tag, 'name'), 'unknown', 'the default value is found'); + + set(tag, 'name', null); + assert.equal(get(tag, 'name'), null, `null doesn't shadow defaultValue`); + }); + + test(`a Model can define 'setUnknownProperty'`, async function(assert) { + class NativeTag extends Model { + @attr('string') + name; + + setUnknownProperty(key, value) { + if (key === 'title') { + this.set('name', value); + } + } + } + const LegacyTag = Model.extend({ + name: DSattr('string'), + + setUnknownProperty(key, value) { + if (key === 'title') { + this.set('name', value); + } + }, + }); + this.owner.register('model:native-tag', NativeTag); + this.owner.register('model:legacy-tag', LegacyTag); + + let legacyTag = store.createRecord('legacy-tag', { name: 'old' }); + assert.equal(get(legacyTag, 'name'), 'old', 'precond - name is correct'); - converts(assert, 'string', 'Scumbag Tom', 'Scumbag Tom'); - converts(assert, 'string', 1, '1'); - converts(assert, 'string', '', ''); - converts(assert, 'string', null, null); -}); + set(legacyTag, 'name', 'edited'); + assert.equal(get(legacyTag, 'name'), 'edited', 'setUnknownProperty was not triggered'); -test('a DS.Model can describe Number attributes', function(assert) { - assert.expect(8); - - converts(assert, 'number', '1', 1); - converts(assert, 'number', '0', 0); - converts(assert, 'number', 1, 1); - converts(assert, 'number', 0, 0); - converts(assert, 'number', '', null); - converts(assert, 'number', null, null); - converts(assert, 'number', true, 1); - converts(assert, 'number', false, 0); -}); + set(legacyTag, 'title', 'new'); + assert.equal(get(legacyTag, 'name'), 'new', 'setUnknownProperty was triggered'); -test('a DS.Model can describe Boolean attributes', function(assert) { - converts(assert, 'boolean', '1', true); - converts(assert, 'boolean', '', false); - converts(assert, 'boolean', 1, true); - converts(assert, 'boolean', 0, false); + let nativeTag = store.createRecord('native-tag', { name: 'old' }); + assert.equal(get(nativeTag, 'name'), 'old', 'precond - name is correct'); - converts(assert, 'boolean', null, null, { allowNull: true }); + set(nativeTag, 'name', 'edited'); + assert.equal(get(nativeTag, 'name'), 'edited', 'setUnknownProperty was not triggered'); - converts(assert, 'boolean', null, false, { allowNull: false }); + set(nativeTag, 'title', 'new'); + assert.equal(get(nativeTag, 'name'), 'new', 'setUnknownProperty was triggered'); + }); - converts(assert, 'boolean', null, false); + test('setting a property to undefined on a newly created record should not impact the current state', async function(assert) { + class Tag extends Model { + @attr('string') + tagInfo; + } + this.owner.register('model:tag', Tag); - converts(assert, 'boolean', true, true); - converts(assert, 'boolean', false, false); -}); + let tag = store.createRecord('tag'); -test('a DS.Model can describe Date attributes', function(assert) { - assert.expect(5); + set(tag, 'name', 'testing'); - converts(assert, 'date', null, null); - converts(assert, 'date', undefined, undefined); + assert.equal(get(tag, 'currentState.stateName'), 'root.loaded.created.uncommitted'); - let dateString = '2011-12-31T00:08:16.000Z'; - let date = new Date(dateString); + set(tag, 'name', undefined); - const Person = DS.Model.extend({ - updatedAt: DS.attr('date'), - }); + assert.equal(get(tag, 'currentState.stateName'), 'root.loaded.created.uncommitted'); - let store = createStore({ - person: Person, - adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord() { - return false; - }, - }), - }); + tag = store.createRecord('tag', { name: undefined }); - return run(() => { - store.push({ - data: { - type: 'person', - id: '1', - }, + assert.equal(get(tag, 'currentState.stateName'), 'root.loaded.created.uncommitted'); }); - return store.findRecord('person', 1).then(record => { - record.set('updatedAt', date); - assert.deepEqual(date, get(record, 'updatedAt'), 'setting a date returns the same date'); - }); - }).then(() => { - convertsFromServer(assert, 'date', dateString, date); - convertsWhenSet(assert, 'date', date, dateString); - }); -}); + test('setting a property back to its original value removes the property from the `_attributes` hash', async function(assert) { + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Scumbag Dale', + }, + }, + }); -function convertsWhenSet(assert, type, provided, expected) { - let testStore = createStore({ - model: DS.Model.extend({ - name: DS.attr(type), - }), - adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord() { - return false; - }, - }), - }); - getOwner(testStore).register('serializer:model', DS.JSONSerializer); - - return run(() => { - testStore.push({ - data: { - type: 'model', - id: '2', - }, - }); + let recordData = person._internalModel._recordData; + assert.equal(recordData._attributes.name, undefined, 'the `_attributes` hash is clean'); + + set(person, 'name', 'Niceguy Dale'); - return testStore.findRecord('model', 2).then(record => { - set(record, 'name', provided); - assert.deepEqual( - record.serialize().name, - expected, - type + ' saves ' + provided + ' as ' + expected + assert.equal( + recordData._attributes.name, + 'Niceguy Dale', + 'the `_attributes` hash contains the changed value' ); - }); - }); -} -testInDebug(`don't allow setting`, function(assert) { - const Person = DS.Model.extend(); + set(person, 'name', 'Scumbag Dale'); - let store = createStore({ - person: Person, + assert.equal(recordData._attributes.name, undefined, 'the `_attributes` hash is reset'); + }); }); - let record = store.createRecord('person'); + module('Mutation', function() { + test('can have properties and non-specified properties set on it', async function(assert) { + let record = store.createRecord('person', { isDrugAddict: false, notAnAttr: 'my value' }); + set(record, 'name', 'bar'); + set(record, 'anotherNotAnAttr', 'my other value'); - assert.expectAssertion(() => { - run(() => { - record.set('isLoaded', true); + assert.equal(get(record, 'notAnAttr'), 'my value', 'property was set on the record'); + assert.equal( + get(record, 'anotherNotAnAttr'), + 'my other value', + 'property was set on the record' + ); + assert.strictEqual(get(record, 'isDrugAddict'), false, 'property was set on the record'); + assert.equal(get(record, 'name'), 'bar', 'property was set on the record'); }); - }, /Cannot set read-only property "isLoaded"/); -}); - -test('ensure model exits loading state, materializes data and fulfills promise only after data is available', function(assert) { - assert.expect(2); - let store = createStore({ - adapter: DS.Adapter.extend({ - findRecord(store, type, id, snapshot) { - return resolve({ - data: { - id: 1, - type: 'person', - attributes: { name: 'John' }, + test('setting a property on a record that has not changed does not cause it to become dirty', async function(assert) { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Peter', + isDrugAddict: true, }, - }); - }, - }), - person: Person, - }); + }, + }); + + let person = await store.findRecord('person', '1'); - return run(() => { - return store.findRecord('person', 1).then(person => { assert.equal( - get(person, 'currentState.stateName'), - 'root.loaded.saved', - 'model is in loaded state' + person.get('hasDirtyAttributes'), + false, + 'precond - person record should not be dirty' + ); + + person.set('name', 'Peter'); + person.set('isDrugAddict', true); + + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'record does not become dirty after setting property to old value' ); - assert.equal(get(person, 'isLoaded'), true, 'model is loaded'); }); - }); -}); -test('A DS.Model can be JSONified', function(assert) { - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); + test('resetting a property on a record cause it to become clean again', async function(assert) { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Peter', + isDrugAddict: true, + }, + }, + }); - let store = createStore({ person: Person }); - let record = store.createRecord('person', { name: 'TomHuda' }); + let person = await store.findRecord('person', '1'); - assert.deepEqual(record.toJSON(), { data: { type: 'people', attributes: { name: 'TomHuda' } } }); -}); + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'precond - person record should not be dirty' + ); -testInDebug('A subclass of DS.Model can not use the `data` property', function(assert) { - const Person = DS.Model.extend({ - data: DS.attr('string'), - name: DS.attr('string'), - }); + person.set('isDrugAddict', false); - let store = createStore({ person: Person }); + assert.equal( + person.get('hasDirtyAttributes'), + true, + 'record becomes dirty after setting property to a new value' + ); - assert.expectAssertion(() => { - store.createRecord('person', { name: 'TomHuda' }); - }, /`data` is a reserved property name on DS.Model objects/); -}); + person.set('isDrugAddict', true); -testInDebug('A subclass of DS.Model can not use the `store` property', function(assert) { - const Retailer = DS.Model.extend({ - store: DS.attr(), - name: DS.attr(), - }); + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'record becomes clean after resetting property to the old value' + ); + }); - let store = createStore({ retailer: Retailer }); + test('resetting a property to the current in-flight value causes it to become clean when the save completes', async function(assert) { + adapter.updateRecord = function() { + return resolve(); + }; - assert.expectAssertion(() => { - store.createRecord('retailer', { name: 'Buy n Large' }); - }, /`store` is a reserved property name on DS.Model objects/); -}); + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Tom', + }, + }, + }); -testInDebug('A subclass of DS.Model can not use reserved properties', function(assert) { - assert.expect(3); - ['currentState', 'data', 'store'].forEach(reservedProperty => { - let invalidExtendObject = {}; - invalidExtendObject[reservedProperty] = DS.attr(); - const Post = DS.Model.extend(invalidExtendObject); + let person = store.peekRecord('person', 1); + person.set('name', 'Thomas'); - let store = createStore({ post: Post }); + let saving = person.save(); - assert.expectAssertion(() => { - store.createRecord('post', {}); - }, /is a reserved property name on DS.Model objects/); - }); -}); + assert.equal(person.get('name'), 'Thomas'); -test('Pushing a record into the store should transition it to the loaded state', function(assert) { - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); + person.set('name', 'Tomathy'); + assert.equal(person.get('name'), 'Tomathy'); - let store = createStore({ person: Person }); - let person = store.createRecord('person', { id: 1, name: 'TomHuda' }); + person.set('name', 'Thomas'); + assert.equal(person.get('name'), 'Thomas'); - assert.equal(person.get('isNew'), true, 'createRecord should put records into the new state'); + await saving; - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'TomHuda', - }, - }, + assert.equal(person.get('hasDirtyAttributes'), false, 'The person is now clean'); }); - assert.equal(person.get('isNew'), false, 'push should put records into the loaded state'); - }); -}); - -testInDebug('A subclass of DS.Model throws an error when calling create() directly', function( - assert -) { - assert.throws( - () => { - Person.create(); - }, - /You should not call `create` on a model/, - 'Throws an error when calling create() on model' - ); -}); + test('a record becomes clean again only if all changed properties are reset', async function(assert) { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Peter', + isDrugAddict: true, + }, + }, + }); -test('toJSON looks up the JSONSerializer using the store instead of using JSONSerializer.create', function(assert) { - const Person = DS.Model.extend({ - posts: DS.hasMany('post', { async: false }), - }); - const Post = DS.Model.extend({ - person: DS.belongsTo('person', { async: false }), - }); + let person = await store.findRecord('person', 1); - let env = setupStore({ - person: Person, - post: Post, - }); - let { store } = env; - - // Loading the person without explicitly - // loading its relationships seems to trigger the - // original bug where `this.store` was not - // present on the serializer due to using .create - // instead of `store.serializerFor`. - let person = run(() => { - return store.push({ - data: { - type: 'person', - id: '1', - }, + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'precond - person record should not be dirty' + ); + person.set('isDrugAddict', false); + assert.equal( + person.get('hasDirtyAttributes'), + true, + 'record becomes dirty after setting one property to a new value' + ); + person.set('name', 'Mark'); + assert.equal( + person.get('hasDirtyAttributes'), + true, + 'record stays dirty after setting another property to a new value' + ); + person.set('isDrugAddict', true); + assert.equal( + person.get('hasDirtyAttributes'), + true, + 'record stays dirty after resetting only one property to the old value' + ); + person.set('name', 'Peter'); + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'record becomes clean after resetting both properties to the old value' + ); }); - }); - let errorThrown = false; - let json; - try { - json = run(person, 'toJSON'); - } catch (e) { - errorThrown = true; - } + test('an invalid record becomes clean again if changed property is reset', async function(assert) { + adapter.updateRecord = () => { + return reject(new InvalidError([{ name: 'not valid' }])); + }; - assert.ok(!errorThrown, 'error not thrown due to missing store'); - assert.deepEqual(json, { data: { type: 'people' } }); -}); + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Peter', + isDrugAddict: true, + }, + }, + }); + + let person = store.peekRecord('person', 1); -test('internalModel is ready by `init`', function(assert) { - assert.expect(2); - let nameDidChange = 0; + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'precond - person record should not be dirty' + ); + person.set('name', 'Wolf'); + assert.equal( + person.get('hasDirtyAttributes'), + true, + 'record becomes dirty after setting one property to a new value' + ); - const Person = DS.Model.extend({ - name: DS.attr('string'), + await person + .save() + .then(() => { + assert.ok(false, 'We should reject the save'); + }) + .catch(() => { + assert.equal(person.get('isValid'), false, 'record is not valid'); + assert.equal(person.get('hasDirtyAttributes'), true, 'record still has dirty attributes'); + + person.set('name', 'Peter'); + + assert.equal( + person.get('isValid'), + true, + 'record is valid after resetting attribute to old value' + ); + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'record becomes clean after resetting property to the old value' + ); + }); + }); - init() { - this._super(...arguments); - this.set('name', 'my-name-set-in-init'); - }, + test('an invalid record stays dirty if only invalid property is reset', async function(assert) { + adapter.updateRecord = () => { + return reject(new InvalidError([{ name: 'not valid' }])); + }; - nameDidChange: observer('name', () => nameDidChange++), - }); + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Peter', + isDrugAddict: true, + }, + }, + }); - let { store } = setupStore({ person: Person }); + let person = store.peekRecord('person', 1); - assert.equal(nameDidChange, 0, 'observer should not trigger on create'); - let person = store.createRecord('person'); - assert.equal(person.get('name'), 'my-name-set-in-init'); -}); + assert.equal( + person.get('hasDirtyAttributes'), + false, + 'precond - person record should not be dirty' + ); + person.set('name', 'Wolf'); + person.set('isDrugAddict', false); + assert.equal( + person.get('hasDirtyAttributes'), + true, + 'record becomes dirty after setting one property to a new value' + ); -test('accessing attributes in the initializer should not throw an error', function(assert) { - assert.expect(1); + await person + .save() + .then(() => { + assert.ok(false, 'save should have rejected'); + }) + .catch(() => { + assert.equal(person.get('isValid'), false, 'record is not valid'); + assert.equal(person.get('hasDirtyAttributes'), true, 'record still has dirty attributes'); + + person.set('name', 'Peter'); + + assert.equal( + person.get('isValid'), + true, + 'record is valid after resetting invalid attribute to old value' + ); + assert.equal(person.get('hasDirtyAttributes'), true, 'record still has dirty attributes'); + }); + }); - const Person = DS.Model.extend({ - name: DS.attr('string'), + test('it should cache attributes', async function(assert) { + class Post extends Model { + @attr('string') + updatedAt; + } + this.owner.register('model:post', Post); - init() { - this._super(...arguments); - assert.ok(!this.get('name')); - }, - }); + let dateString = 'Sat, 31 Dec 2011 00:08:16 GMT'; + let date = new Date(dateString); - let { store } = setupStore({ - person: Person, - }); + store.push({ + data: { + type: 'post', + id: '1', + }, + }); - store.createRecord('person'); -}); + let record = await store.findRecord('post', '1'); -test('setting the id after model creation should correctly update the id', function(assert) { - assert.expect(2); + record.set('updatedAt', date); - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); + assert.deepEqual(date, get(record, 'updatedAt'), 'setting a date returns the same date'); + assert.strictEqual( + get(record, 'updatedAt'), + get(record, 'updatedAt'), + 'second get still returns the same object' + ); + }); - let { store } = setupStore({ - person: Person, - }); + test('changedAttributes() return correct values', async function(assert) { + class Mascot extends Model { + @attr('string') + name; + @attr('string') + likes; + @attr('boolean') + isMascot; + } - let person = store.createRecord('person'); + this.owner.register('model:mascot', Mascot); - assert.equal(person.get('id'), null, 'initial created model id should be null'); + let mascot = store.push({ + data: { + type: 'mascot', + id: '1', + attributes: { + likes: 'JavaScript', + isMascot: true, + }, + }, + }); - run(() => { - person.set('id', 'john'); + assert.equal( + Object.keys(mascot.changedAttributes()).length, + 0, + 'there are no initial changes' + ); - assert.equal(person.get('id'), 'john', 'new id should be correctly set.'); - }); -}); + mascot.set('name', 'Tomster'); // new value + mascot.set('likes', 'Ember.js'); // changed value + mascot.set('isMascot', true); // same value -test('updating the id with store.setRecordId should correctly when the id property is watched', function(assert) { - assert.expect(2); + let changedAttributes = mascot.changedAttributes(); - const Person = DS.Model.extend({ - name: DS.attr('string'), - idComputed: computed('id', function() {}), - }); + assert.deepEqual(changedAttributes.name, [undefined, 'Tomster']); + assert.deepEqual(changedAttributes.likes, ['JavaScript', 'Ember.js']); - let { store } = setupStore({ - person: Person, - }); + mascot.rollbackAttributes(); - run(() => { - let person = store.createRecord('person'); - person.get('idComputed'); + assert.equal( + Object.keys(mascot.changedAttributes()).length, + 0, + 'after rollback attributes there are no changes' + ); + }); - assert.equal(person.get('id'), null, 'initial created model id should be null'); + test('changedAttributes() works while the record is being saved', async function(assert) { + assert.expect(1); + class Mascot extends Model { + @attr('string') + name; + @attr('string') + likes; + @attr('boolean') + isMascot; + } - store.setRecordId('person', 'john', person._internalModel.clientId); + this.owner.register('model:mascot', Mascot); + adapter.createRecord = function() { + assert.deepEqual(cat.changedAttributes(), { + name: [undefined, 'Argon'], + likes: [undefined, 'Cheese'], + }); - assert.equal(person.id, 'john', 'new id should be correctly set.'); - }); -}); + return resolve({ data: { id: 1, type: 'mascot' } }); + }; -test('accessing the model id without the get function should work when id is watched', function(assert) { - assert.expect(2); + let cat; - const Person = DS.Model.extend({ - name: DS.attr('string'), - idComputed: computed('id', function() {}), - }); + cat = store.createRecord('mascot'); + cat.setProperties({ + name: 'Argon', + likes: 'Cheese', + }); - let { store } = setupStore({ - person: Person, - }); + await cat.save(); + }); - run(() => { - let person = store.createRecord('person'); - person.get('idComputed'); + test('changedAttributes() works while the record is being updated', async function(assert) { + assert.expect(1); + let cat; + + class Mascot extends Model { + @attr('string') + name; + @attr('string') + likes; + @attr('boolean') + isMascot; + } - assert.equal(person.get('id'), null, 'initial created model id should be null'); + this.owner.register('model:mascot', Mascot); + adapter.updateRecord = function() { + assert.deepEqual(cat.changedAttributes(), { + name: ['Argon', 'Helia'], + likes: ['Cheese', 'Mussels'], + }); - store.setRecordId('person', 'john', person._internalModel.clientId); + return { data: { id: '1', type: 'mascot' } }; + }; - assert.equal(person.id, 'john', 'new id should be correctly set.'); - }); -}); + cat = store.push({ + data: { + type: 'mascot', + id: '1', + attributes: { + name: 'Argon', + likes: 'Cheese', + }, + }, + }); -test('ID mutation (complicated)', function(assert) { - assert.expect(5); - let idChange = 0; - const Person = DS.Model.extend({ - name: DS.attr('string'), - idComputed: computed('id', function() {}), - idDidChange: observer('id', () => idChange++), - }); + cat.setProperties({ + name: 'Helia', + likes: 'Mussels', + }); - let { store } = setupStore({ - person: Person.extend(), + await cat.save(); + }); }); - run(() => { - let person = store.createRecord('person'); - person.get('idComputed'); - assert.equal(idChange, 0); + module('Misc', function() { + testInDebug('Calling record.attr() asserts', async function(assert) { + let person = store.createRecord('person', { id: 1, name: 'TomHuda' }); - assert.equal(person.get('id'), null, 'initial created model id should be null'); - assert.equal(idChange, 0); - store._setRecordId(person._internalModel, 'john'); - assert.equal(idChange, 1); - assert.equal(person.get('id'), 'john', 'new id should be correctly set.'); + assert.expectAssertion(() => { + person.attr(); + }, /Assertion Failed: The `attr` method is not available on DS\.Model, a DS\.Snapshot was probably expected\. Are you passing a DS\.Model instead of a DS\.Snapshot to your serializer\?/); + }); }); }); diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index 5693aeb1a5b..ff510852b44 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -297,33 +297,3 @@ test('a record receives a becameInvalid callback when it became invalid', functi }); }); -test('an ID of 0 is allowed', function(assert) { - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); - - let store = createStore({ - person: Person, - }); - - run(() => { - store.push({ - data: { - type: 'person', - id: '0', - attributes: { - name: 'Tom Dale', - }, - }, - }); - }); - - assert.equal( - store - .peekAll('person') - .objectAt(0) - .get('name'), - 'Tom Dale', - 'found record with id 0' - ); -}); From 3515ac7213ea878b12d12affb614845b198bbce9 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 24 Oct 2018 13:00:44 -0700 Subject: [PATCH 2394/2527] update cache entry when ID is set late: resolves #5679 --- addon/-private/system/model/internal-model.js | 5 +++++ tests/unit/model-test.js | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index af126b1117c..e7dea5d390c 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -1102,8 +1102,13 @@ export default class InternalModel { this.id === null || this.id === id || this.isNew() ); let didChange = id !== this.id; + this.id = id; + if (didChange && id !== null) { + this.store._setRecordId(this, id, this.clientId); + } + if (didChange && this.hasRecord) { this._record.notifyPropertyChange('id'); } diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 431aa3c618b..796852419ee 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -313,6 +313,20 @@ module('unit/model - Model', function(hooks) { assert.ok(person === record, 'The cache has an entry for john'); }); + test('setting the id after createRecord should correctly update the id', async function(assert) { + let person = store.createRecord('person'); + + assert.equal(person.get('id'), null, 'initial created model id should be null'); + + person.set('id', 'john'); + + assert.equal(person.get('id'), 'john', 'new id should be correctly set.'); + + let record = store.peekRecord('person', 'john'); + + assert.ok(person === record, 'The cache has an entry for john'); + }); + test('updating the id with store.setRecordId should work correctly when the id property is watched', async function(assert) { const OddPerson = Model.extend({ name: DSattr('string'), From f2e5638bc234e06f08de76d3e08801df410556e7 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 23 Oct 2018 15:59:14 -0700 Subject: [PATCH 2395/2527] [CHORE tests] modernize integration/record-array-test --- tests/integration/record-array-test.js | 481 ++++++++++++------------- 1 file changed, 237 insertions(+), 244 deletions(-) diff --git a/tests/integration/record-array-test.js b/tests/integration/record-array-test.js index cb2bd5c2963..3c0a89f7630 100644 --- a/tests/integration/record-array-test.js +++ b/tests/integration/record-array-test.js @@ -1,53 +1,55 @@ import { get } from '@ember/object'; import { run } from '@ember/runloop'; -import { Promise, hash } from 'rsvp'; -import { createStore } from 'dummy/tests/helpers/store'; -import setupStore from 'dummy/tests/helpers/store'; - +import { resolve } from 'rsvp'; +import { setupTest } from 'ember-qunit'; +import { settled } from '@ember/test-helpers'; +import Model from 'ember-data/model'; +import { attr, belongsTo, hasMany } from '@ember-decorators/data'; import { module, test } from 'qunit'; +import Adapter from 'ember-data/adapter'; -import DS from 'ember-data'; - -let results; +class Person extends Model { + @attr + name; + @belongsTo('tag', { async: false, inverse: 'people' }) + tag; +} -const Person = DS.Model.extend({ - name: DS.attr('string'), - tag: DS.belongsTo('tag', { async: false }), -}); +class Tag extends Model { + @hasMany('person', { async: false, inverse: 'tag' }) + people; +} -const Tag = DS.Model.extend({ - people: DS.hasMany('person', { async: false }), -}); +class Tool extends Model { + @belongsTo('person', { async: false, inverse: null }) + person; +} -const Tool = DS.Model.extend({ - person: DS.belongsTo('person', { async: false }), -}); +module('unit/record-array - RecordArray', function(hooks) { + setupTest(hooks); + let store; -module('unit/record_array - DS.RecordArray', { - beforeEach() { - results = { - data: [ - { id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }, - { id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } }, - { id: '3', type: 'person', attributes: { name: 'Scumbag Bryn' } }, - ], - }; - }, -}); + hooks.beforeEach(function() { + let { owner } = this; -test('a record array is backed by records', function(assert) { - assert.expect(3); + owner.register('model:person', Person); + owner.register('model:tag', Tag); + owner.register('model:tool', Tool); - let store = createStore({ - person: Person, - adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord() { - return false; - }, - }), + store = owner.lookup('service:store'); }); - run(() => { + test('a record array is backed by records', async function(assert) { + assert.expect(3); + this.owner.register( + 'adapter:application', + Adapter.extend({ + shouldBackgroundReloadRecord() { + return false; + }, + }) + ); + store.push({ data: [ { @@ -73,33 +75,33 @@ test('a record array is backed by records', function(assert) { }, ], }); - }); - return run(() => { - return store.findByIds('person', [1, 2, 3]).then(records => { - for (let i = 0, l = get(results, 'data.length'); i < l; i++) { - let { - id, - attributes: { name }, - } = results.data[i]; - assert.deepEqual( - records[i].getProperties('id', 'name'), - { id, name }, - 'a record array materializes objects on demand' - ); - } - }); - }); -}); + let records = await store.findByIds('person', [1, 2, 3]); + let expectedResults = { + data: [ + { id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }, + { id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } }, + { id: '3', type: 'person', attributes: { name: 'Scumbag Bryn' } }, + ], + }; + + for (let i = 0, l = expectedResults.data.length; i < l; i++) { + let { + id, + attributes: { name }, + } = expectedResults.data[i]; -test('acts as a live query', function(assert) { - let store = createStore({ - person: Person, + assert.deepEqual( + records[i].getProperties('id', 'name'), + { id, name }, + 'a record array materializes objects on demand' + ); + } }); - let recordArray = store.peekAll('person'); + test('acts as a live query', async function(assert) { + let recordArray = store.peekAll('person'); - run(() => { store.push({ data: { type: 'person', @@ -109,11 +111,11 @@ test('acts as a live query', function(assert) { }, }, }); - }); - assert.equal(get(recordArray, 'lastObject.name'), 'wycats'); + await settled(); + + assert.equal(get(recordArray, 'lastObject.name'), 'wycats'); - run(() => { store.push({ data: { type: 'person', @@ -123,19 +125,20 @@ test('acts as a live query', function(assert) { }, }, }); - }); - assert.equal(get(recordArray, 'lastObject.name'), 'brohuda'); -}); -test('acts as a live query (normalized names)', function(assert) { - let store = createStore({ - person: Person, - Person: Person, + await settled(); + + assert.equal(get(recordArray, 'lastObject.name'), 'brohuda'); }); - let recordArray = store.peekAll('Person'); + test('acts as a live query (normalized names)', async function(assert) { + this.owner.register('model:Person', Person); + + let recordArray = store.peekAll('Person'); + let otherRecordArray = store.peekAll('person'); + + assert.ok(recordArray === otherRecordArray, 'Person and person are the same record-array'); - run(() => { store.push({ data: { type: 'Person', @@ -145,11 +148,11 @@ test('acts as a live query (normalized names)', function(assert) { }, }, }); - }); - assert.deepEqual(recordArray.mapBy('name'), ['John Churchill']); + await settled(); + + assert.deepEqual(recordArray.mapBy('name'), ['John Churchill']); - run(() => { store.push({ data: { type: 'Person', @@ -159,19 +162,17 @@ test('acts as a live query (normalized names)', function(assert) { }, }, }); - }); - assert.deepEqual(recordArray.mapBy('name'), ['John Churchill', 'Winston Churchill']); -}); -test('stops updating when destroyed', function(assert) { - assert.expect(3); + await settled(); - let store = createStore({ - person: Person, + assert.deepEqual(recordArray.mapBy('name'), ['John Churchill', 'Winston Churchill']); }); - let recordArray = store.peekAll('person'); - run(() => { + test('stops updating when destroyed', async function(assert) { + assert.expect(3); + + let recordArray = store.peekAll('person'); + store.push({ data: { type: 'person', @@ -181,11 +182,15 @@ test('stops updating when destroyed', function(assert) { }, }, }); - }); - run(() => recordArray.destroy()); + await settled(); + + // Ember 2.18 requires wrapping destroy in a run. Once we drop support with 3.8 LTS + // we can remove this. + run(() => recordArray.destroy()); + + await settled(); - run(() => { assert.equal(recordArray.get('length'), 0, 'Has no more records'); store.push({ data: { @@ -196,31 +201,27 @@ test('stops updating when destroyed', function(assert) { }, }, }); - }); - - assert.equal(recordArray.get('length'), 0, 'Has not been updated'); - assert.equal(recordArray.get('content'), undefined, 'Has not been updated'); -}); -test('a loaded record is removed from a record array when it is deleted', function(assert) { - assert.expect(5); + await settled(); - let env = setupStore({ - tag: Tag, - person: Person, - adapter: DS.Adapter.extend({ - deleteRecord() { - return Promise.resolve(); - }, - shouldBackgroundReloadRecord() { - return false; - }, - }), + assert.equal(recordArray.get('length'), 0, 'Has not been updated'); + assert.equal(recordArray.get('content'), undefined, 'Has not been updated'); }); - let store = env.store; + test('a loaded record is removed from a record array when it is deleted', async function(assert) { + assert.expect(5); + this.owner.register( + 'adapter:application', + Adapter.extend({ + deleteRecord() { + return resolve({ data: null }); + }, + shouldBackgroundReloadRecord() { + return false; + }, + }) + ); - run(() => { store.push({ data: [ { @@ -247,66 +248,66 @@ test('a loaded record is removed from a record array when it is deleted', functi { type: 'tag', id: '1', + attributes: {}, }, ], }); - }); - - return run(() => { - return hash({ - scumbag: store.findRecord('person', 1), - tag: store.findRecord('tag', 1), - }).then(records => { - let scumbag = records.scumbag; - let tag = records.tag; - run(() => tag.get('people').addObject(scumbag)); + let scumbag = await store.findRecord('person', 1); + let tag = await store.findRecord('tag', 1); + let recordArray = tag.get('people'); - assert.equal(get(scumbag, 'tag'), tag, "precond - the scumbag's tag has been set"); + recordArray.addObject(scumbag); - let recordArray = tag.get('people'); + assert.ok(scumbag.get('tag') === tag, "precond - the scumbag's tag has been set"); + assert.equal(get(recordArray, 'length'), 1, 'precond - record array has one item'); + assert.equal( + get(recordArray.objectAt(0), 'name'), + 'Scumbag Dale', + 'item at index 0 is record with id 1' + ); - assert.equal(get(recordArray, 'length'), 1, 'precond - record array has one item'); - assert.equal( - get(recordArray.objectAt(0), 'name'), - 'Scumbag Dale', - 'item at index 0 is record with id 1' - ); - - scumbag.deleteRecord(); + scumbag.deleteRecord(); - assert.equal( - get(recordArray, 'length'), - 1, - 'record is still in the record array until it is saved' - ); + assert.equal( + get(recordArray, 'length'), + 1, + 'record is still in the record array until it is saved' + ); - run(scumbag, 'save'); + await scumbag.save(); - assert.equal( - get(recordArray, 'length'), - 0, - 'record is removed from the array when it is saved' - ); - }); - }); -}); - -test("a loaded record is not removed from a record array when it is deleted even if the belongsTo side isn't defined", function(assert) { - let env = setupStore({ - tag: Tag, - person: Person.reopen({ tags: null }), - adapter: DS.Adapter.extend({ - deleteRecord() { - return Promise.resolve(); - }, - }), + assert.equal( + get(recordArray, 'length'), + 0, + 'record is removed from the array when it is saved' + ); }); - let store = env.store; - let scumbag, tag; + test("a loaded record is not removed from a record array when it is deleted even if the belongsTo side isn't defined", async function(assert) { + class Person extends Model { + @attr + name; + } + + class Tag extends Model { + @hasMany('person', { async: false, inverse: null }) + people; + } + + this.owner.unregister('model:person'); + this.owner.unregister('model:tag'); + this.owner.register('model:person', Person); + this.owner.register('model:tag', Tag); + this.owner.register( + 'adapter:application', + Adapter.extend({ + deleteRecord() { + return resolve({ data: null }); + }, + }) + ); - run(() => { store.push({ data: [ { @@ -327,34 +328,26 @@ test("a loaded record is not removed from a record array when it is deleted even }, ], }); - scumbag = store.peekRecord('person', 1); - tag = store.peekRecord('tag', 1); + + let scumbag = store.peekRecord('person', 1); + let tag = store.peekRecord('tag', 1); scumbag.deleteRecord(); - }); - run(() => { assert.equal(tag.get('people.length'), 1, 'record is not removed from the record array'); assert.equal(tag.get('people').objectAt(0), scumbag, 'tag still has the scumbag'); }); -}); - -test("a loaded record is not removed from both the record array and from the belongs to, even if the belongsTo side isn't defined", function(assert) { - let env = setupStore({ - tag: Tag, - person: Person, - tool: Tool, - adapter: DS.Adapter.extend({ - deleteRecord() { - return Promise.resolve(); - }, - }), - }); - let store = env.store; - let scumbag, tag, tool; + test("a loaded record is not removed from both the record array and from the belongs to, even if the belongsTo side isn't defined", async function(assert) { + this.owner.register( + 'adapter:application', + Adapter.extend({ + deleteRecord() { + return resolve({ data: null }); + }, + }) + ); - run(() => { store.push({ data: [ { @@ -384,57 +377,49 @@ test("a loaded record is not removed from both the record array and from the bel }, ], }); - scumbag = store.peekRecord('person', 1); - tag = store.peekRecord('tag', 1); - tool = store.peekRecord('tool', 1); - }); - run(() => { + let scumbag = store.peekRecord('person', 1); + let tag = store.peekRecord('tag', 1); + let tool = store.peekRecord('tool', 1); + assert.equal(tag.get('people.length'), 1, 'record is in the record array'); assert.equal(tool.get('person'), scumbag, 'the tool belongs to the record'); - }); - - run(() => scumbag.deleteRecord()); - assert.equal(tag.get('people.length'), 1, 'record is stil in the record array'); - assert.equal(tool.get('person'), scumbag, 'the tool still belongs to the record'); -}); + scumbag.deleteRecord(); -// GitHub Issue #168 -test('a newly created record is removed from a record array when it is deleted', function(assert) { - let store = createStore({ - person: Person, - tag: Tag, - }); - let recordArray = store.peekAll('person'); - let scumbag = store.createRecord('person', { - name: 'Scumbag Dale', + assert.equal(tag.get('people.length'), 1, 'record is stil in the record array'); + assert.equal(tool.get('person'), scumbag, 'the tool still belongs to the record'); }); - assert.equal( - get(recordArray, 'length'), - 1, - 'precond - record array already has the first created item' - ); + // GitHub Issue #168 + test('a newly created record is removed from a record array when it is deleted', async function(assert) { + let recordArray = store.peekAll('person'); + let scumbag = store.createRecord('person', { + name: 'Scumbag Dale', + }); - store.createRecord('person', { name: 'p1' }); - store.createRecord('person', { name: 'p2' }); - store.createRecord('person', { name: 'p3' }); + assert.equal( + get(recordArray, 'length'), + 1, + 'precond - record array already has the first created item' + ); - assert.equal(get(recordArray, 'length'), 4, 'precond - record array has the created item'); - assert.equal(recordArray.objectAt(0), scumbag, 'item at index 0 is record with id 1'); + store.createRecord('person', { name: 'p1' }); + store.createRecord('person', { name: 'p2' }); + store.createRecord('person', { name: 'p3' }); - run(() => scumbag.deleteRecord()); + assert.equal(get(recordArray, 'length'), 4, 'precond - record array has the created item'); + assert.equal(recordArray.objectAt(0), scumbag, 'item at index 0 is record with id 1'); - assert.equal(get(recordArray, 'length'), 3, 'record array still has the created item'); -}); + scumbag.deleteRecord(); + assert.equal(get(recordArray, 'length'), 4, 'record array still has the created item'); -test("a record array returns undefined when asking for a member outside of its content Array's range", function(assert) { - let store = createStore({ - person: Person, + await settled(); + + assert.equal(get(recordArray, 'length'), 3, 'record array no longer has the created item'); }); - run(() => { + test("a record array returns undefined when asking for a member outside of its content Array's range", async function(assert) { store.push({ data: [ { @@ -460,24 +445,18 @@ test("a record array returns undefined when asking for a member outside of its c }, ], }); - }); - - let recordArray = store.peekAll('person'); - assert.strictEqual( - recordArray.objectAt(20), - undefined, - 'objects outside of the range just return undefined' - ); -}); + let recordArray = store.peekAll('person'); -// This tests for a bug in the recordCache, where the records were being cached in the incorrect order. -test('a record array should be able to be enumerated in any order', function(assert) { - let store = createStore({ - person: Person, + assert.strictEqual( + recordArray.objectAt(20), + undefined, + 'objects outside of the range just return undefined' + ); }); - run(() => { + // This tests for a bug in the recordCache, where the records were being cached in the incorrect order. + test('a record array should be able to be enumerated in any order', async function(assert) { store.push({ data: [ { @@ -503,28 +482,42 @@ test('a record array should be able to be enumerated in any order', function(ass }, ], }); - }); - - let recordArray = store.peekAll('person'); - assert.equal(get(recordArray.objectAt(2), 'id'), 3, 'should retrieve correct record at index 2'); - assert.equal(get(recordArray.objectAt(1), 'id'), 2, 'should retrieve correct record at index 1'); - assert.equal(get(recordArray.objectAt(0), 'id'), 1, 'should retrieve correct record at index 0'); -}); - -test("an AdapterPopulatedRecordArray knows if it's loaded or not", function(assert) { - assert.expect(1); + let recordArray = store.peekAll('person'); + + assert.equal( + get(recordArray.objectAt(2), 'id'), + '3', + 'should retrieve correct record at index 2' + ); + assert.equal( + get(recordArray.objectAt(1), 'id'), + '2', + 'should retrieve correct record at index 1' + ); + assert.equal( + get(recordArray.objectAt(0), 'id'), + '1', + 'should retrieve correct record at index 0' + ); + }); - let env = setupStore({ person: Person }); - let store = env.store; + test("an AdapterPopulatedRecordArray knows if it's loaded or not", async function(assert) { + assert.expect(1); + let adapter = store.adapterFor('person'); + + adapter.query = function(store, type, query, recordArray) { + return resolve({ + data: [ + { id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }, + { id: '2', type: 'person', attributes: { name: 'Scumbag Katz' } }, + { id: '3', type: 'person', attributes: { name: 'Scumbag Bryn' } }, + ], + }); + }; - env.adapter.query = function(store, type, query, recordArray) { - return Promise.resolve(results); - }; + let people = await store.query('person', { page: 1 }); - return run(() => { - return store.query('person', { page: 1 }).then(people => { - assert.equal(get(people, 'isLoaded'), true, 'The array is now loaded'); - }); + assert.equal(get(people, 'isLoaded'), true, 'The array is now loaded'); }); }); From 9a5e2c398844e6482929ef69e4cce4e89c9386ad Mon Sep 17 00:00:00 2001 From: Scott Batson Date: Fri, 26 Oct 2018 16:26:08 -0400 Subject: [PATCH 2396/2527] assert that replacing has-many with non-array throws assertion --- addon/-private/system/many-array.js | 3 +- tests/unit/model/lifecycle-callbacks-test.js | 1 - .../unit/model/relationships/has-many-test.js | 59 +++++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index f21374882ca..abf9448ed8d 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -10,6 +10,7 @@ import { assert } from '@ember/debug'; import { PromiseArray } from './promise-proxies'; import { _objectIsAlive } from './store/common'; import diffArray from './diff-array'; +import isArrayLike from './is-array-like'; /** A `ManyArray` is a `MutableArray` that represents the contents of a has-many @@ -201,12 +202,12 @@ export default EmberObject.extend(MutableArray, Evented, { ); } if (objects) { + assert('The third argument to replace needs to be an array.', isArrayLike(objects)); this.get('recordData').addToHasMany( this.get('key'), objects.map(obj => obj._internalModel._recordData), idx ); - //this.get('relationship').addInternalModels(objects.map(obj => obj._internalModel), idx); } this.retrieveLatest(); }, diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index ff510852b44..ac3aab1ada3 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -296,4 +296,3 @@ test('a record receives a becameInvalid callback when it became invalid', functi }); }); }); - diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 20546fc8b76..44190d467be 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -2152,6 +2152,65 @@ test('possible to replace items in a relationship using setObjects w/ Ember Enum assert.equal(tom.get('tags.firstObject'), store.peekRecord('tag', 2)); }); +test('Replacing `has-many` with non-array will throw assertion', function(assert) { + assert.expect(1); + + const Tag = DS.Model.extend({ + name: DS.attr('string'), + person: DS.belongsTo('person', { async: false }), + }); + + const Person = DS.Model.extend({ + name: DS.attr('string'), + tags: DS.hasMany('tag', { async: false }), + }); + + let env = setupStore({ tag: Tag, person: Person }); + let { store } = env; + + run(() => { + store.push({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Tom Dale', + }, + relationships: { + tags: { + data: [{ type: 'tag', id: '1' }], + }, + }, + }, + { + type: 'tag', + id: '1', + attributes: { + name: 'ember', + }, + }, + { + type: 'tag', + id: '2', + attributes: { + name: 'ember-data', + }, + }, + ], + }); + }); + + let tom; + + run(() => { + tom = store.peekRecord('person', '1'); + assert.expectAssertion(() => { + tom.get('tags').setObjects(store.peekRecord('tag', '2')); + }, /The third argument to replace needs to be an array./); + }); +}); + test('it is possible to remove an item from a relationship', function(assert) { assert.expect(2); From 7c721dd29e541624fe8144d19ff8a0150ccbd36a Mon Sep 17 00:00:00 2001 From: Mike North Date: Fri, 26 Oct 2018 17:07:28 -0700 Subject: [PATCH 2397/2527] TS support (#5719) * chore: typescript support * convert something simple-ish within -private * get it working with the addon directory * Update addon/-private/attr.ts * chore(types): misc. fixes * fix lint --- addon/-private/{attr.js => attr.ts} | 8 +- .../system/{clone-null.js => clone-null.ts} | 2 +- index.js | 11 +- package.json | 18 +- tests/dummy/app/{app.js => app.ts} | 0 tests/dummy/app/config/environment.d.ts | 16 + tests/dummy/app/{resolver.js => resolver.ts} | 0 tests/dummy/app/{router.js => router.ts} | 0 .../routes/application/{route.js => route.ts} | 0 tsconfig.json | 34 + types/dummy/index.d.ts | 5 + yarn.lock | 1701 ++++++++++++++++- 12 files changed, 1784 insertions(+), 11 deletions(-) rename addon/-private/{attr.js => attr.ts} (96%) rename addon/-private/system/{clone-null.js => clone-null.ts} (55%) rename tests/dummy/app/{app.js => app.ts} (100%) create mode 100644 tests/dummy/app/config/environment.d.ts rename tests/dummy/app/{resolver.js => resolver.ts} (100%) rename tests/dummy/app/{router.js => router.ts} (100%) rename tests/dummy/app/routes/application/{route.js => route.ts} (100%) create mode 100644 tsconfig.json create mode 100644 types/dummy/index.d.ts diff --git a/addon/-private/attr.js b/addon/-private/attr.ts similarity index 96% rename from addon/-private/attr.js rename to addon/-private/attr.ts index 6c1cd94a0a9..7eb1698e67d 100644 --- a/addon/-private/attr.js +++ b/addon/-private/attr.ts @@ -1,7 +1,6 @@ import { computed } from '@ember/object'; import { assert } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; - /** @module ember-data */ @@ -23,6 +22,10 @@ function hasValue(internalModel, key) { return internalModel._recordData.hasAttr(key); } +interface AttrOptions { + defaultValue?: string | null | (() => any); +} + /** `DS.attr` defines an attribute on a [DS.Model](/api/data/classes/DS.Model.html). By default, attributes are passed through as-is, however you can specify an @@ -107,8 +110,7 @@ function hasValue(internalModel, key) { @param {Object} options a hash of options @return {Attribute} */ - -export default function attr(type, options) { +export default function attr(type?: string | AttrOptions, options?: AttrOptions) { if (typeof type === 'object') { options = type; type = undefined; diff --git a/addon/-private/system/clone-null.js b/addon/-private/system/clone-null.ts similarity index 55% rename from addon/-private/system/clone-null.js rename to addon/-private/system/clone-null.ts index 9972c430fef..0f922c3970d 100644 --- a/addon/-private/system/clone-null.js +++ b/addon/-private/system/clone-null.ts @@ -1,4 +1,4 @@ -export default function cloneNull(source) { +export default function cloneNull(source: T): { [K in keyof T]: T[K] } { let clone = Object.create(null); for (let key in source) { clone[key] = source[key]; diff --git a/index.js b/index.js index 530064c35c3..b0153fd117d 100644 --- a/index.js +++ b/index.js @@ -65,6 +65,7 @@ module.exports = { treeForAddon(tree) { tree = this.debugTree(tree, 'input'); + this._setupBabelOptions(); let babel = this.addons.find(addon => addon.name === 'ember-cli-babel'); @@ -86,9 +87,10 @@ module.exports = { }); let privateTree = babel.transpileTree(this.debugTree(withPrivate, 'babel-private:input'), { - babel: this.buildBabelOptions(), + babel: this.options.babel, 'ember-cli-babel': { compileModules: false, + extensions: ['js', 'ts'], }, }); @@ -133,11 +135,16 @@ module.exports = { }, buildBabelOptions() { + let existing = this.options.babel; let customPlugins = require('./lib/stripped-build-plugins')(process.env.EMBER_ENV); + let plugins = existing.plugins.map(plugin => { + return Array.isArray(plugin) ? plugin : [plugin]; + }); + plugins = plugins.concat(customPlugins.plugins); return { loose: true, - plugins: customPlugins.plugins, + plugins, postTransformPlugins: customPlugins.postTransformPlugins, exclude: ['transform-block-scoping', 'transform-typeof-symbol'], }; diff --git a/package.json b/package.json index 9f2a3ded657..dfe029169ab 100644 --- a/package.json +++ b/package.json @@ -27,12 +27,15 @@ "test-external:factory-guy": "node ./lib/scripts/test-external factory-guy https://github.com/danielspaniel/ember-data-factory-guy.git", "test-external:ilios-frontend": "node ./lib/scripts/test-external ilios-frontend https://github.com/ilios/frontend.git --skip-smoke-test", "test-external:ember-resource-metadata": "node ./lib/scripts/test-external ember-resource-metadata https://github.com/ef4/ember-resource-metadata.git", - "test-external:ember-data-relationship-tracker": "node ./lib/scripts/test-external ember-data-relationship-tracker https://github.com/ef4/ember-data-relationship-tracker.git" + "test-external:ember-data-relationship-tracker": "node ./lib/scripts/test-external ember-data-relationship-tracker https://github.com/ef4/ember-data-relationship-tracker.git", + "prepublishOnly": "ember ts:precompile", + "postpublish": "ember ts:clean" }, "author": "", "license": "MIT", "dependencies": { "@ember/ordered-set": "^2.0.3", + "@glimmer/env": "^0.1.7", "babel-plugin-feature-flags": "^0.3.1", "babel-plugin-filter-imports": "^2.0.3", "babel6-plugin-strip-class-callcheck": "^6.0.0", @@ -48,6 +51,7 @@ "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.1.0", "ember-cli-test-info": "^1.0.0", + "ember-cli-typescript": "^2.0.0-beta.2", "ember-cli-version-checker": "^2.1.2", "ember-inflector": "^3.0.0", "git-repo-info": "^2.0.0", @@ -59,8 +63,16 @@ "silent-error": "^1.1.1" }, "devDependencies": { + "@babel/plugin-transform-typescript": "^7.1.0", "@ember-decorators/babel-transforms": "^2.1.2", "@ember-decorators/data": "^3.0.0", + "@types/ember": "~3.0.25", + "@types/ember-qunit": "~3.4.3", + "@types/ember-test-helpers": "~1.0.4", + "@types/ember-testing-helpers": "~0.0.3", + "@types/ember__test-helpers": "~0.7.6", + "@types/qunit": "^2.5.3", + "@types/rsvp": "^4.0.2", "babel-eslint": "^10.0.1", "broccoli-babel-transpiler": "^7.0.0", "broccoli-concat": "^3.7.3", @@ -83,6 +95,7 @@ "ember-cli-shims": "^1.2.0", "ember-cli-sri": "^2.1.1", "ember-cli-test-loader": "^2.2.0", + "ember-cli-typescript-blueprints": "^2.0.0-beta.1", "ember-cli-uglify": "2.1.0", "ember-cli-yuidoc": "^0.8.8", "ember-decorators": "^3.0.0", @@ -108,7 +121,8 @@ "mocha-only-detector": "1.0.0", "prettier": "^1.14.3", "rimraf": "^2.6.2", - "rsvp": "^4.8.4" + "rsvp": "^4.8.4", + "typescript": "~3.1.3" }, "engines": { "node": ">= 6.0.0" diff --git a/tests/dummy/app/app.js b/tests/dummy/app/app.ts similarity index 100% rename from tests/dummy/app/app.js rename to tests/dummy/app/app.ts diff --git a/tests/dummy/app/config/environment.d.ts b/tests/dummy/app/config/environment.d.ts new file mode 100644 index 00000000000..3252cc3dec4 --- /dev/null +++ b/tests/dummy/app/config/environment.d.ts @@ -0,0 +1,16 @@ +export default config; + +/** + * Type declarations for + * import config from './config/environment' + * + * For now these need to be managed by the developer + * since different ember addons can materialize new entries. + */ +declare const config: { + environment: any; + modulePrefix: string; + podModulePrefix: string; + locationType: string; + rootURL: string; +}; diff --git a/tests/dummy/app/resolver.js b/tests/dummy/app/resolver.ts similarity index 100% rename from tests/dummy/app/resolver.js rename to tests/dummy/app/resolver.ts diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.ts similarity index 100% rename from tests/dummy/app/router.js rename to tests/dummy/app/router.ts diff --git a/tests/dummy/app/routes/application/route.js b/tests/dummy/app/routes/application/route.ts similarity index 100% rename from tests/dummy/app/routes/application/route.js rename to tests/dummy/app/routes/application/route.ts diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000000..30fb4d382c5 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "es2017", + "allowJs": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "noImplicitAny": false, + "noEmitOnError": false, + "noEmit": true, + "skipLibCheck": true, + "inlineSourceMap": true, + "inlineSources": true, + "baseUrl": ".", + "module": "esnext", + "paths": { + "dummy/tests/*": ["tests/*"], + "dummy/*": ["tests/dummy/app/*", "app/*"], + "ember-data": ["addon"], + "ember-data/*": ["addon/*"], + "ember-data/test-support": ["addon-test-support"], + "ember-data/test-support/*": ["addon-test-support/*"], + "*": ["types/*"] + } + }, + "include": [ + "app/**/*", + "addon/**/*", + "tests/**/*", + "types/**/*", + "test-support/**/*", + "addon-test-support/**/*" + ], + "exclude": ["node_modules"] +} diff --git a/types/dummy/index.d.ts b/types/dummy/index.d.ts new file mode 100644 index 00000000000..1ca50c1f99d --- /dev/null +++ b/types/dummy/index.d.ts @@ -0,0 +1,5 @@ +/** + * Any types defined here are only for the purposes of building and testing + * ember-data. They will not be shipped to consumers. Ember-data still relies + * on some private Ember APIs -- those should be defined here as we encounter them. + */ diff --git a/yarn.lock b/yarn.lock index d1e5f4fbb1e..b395a39a2c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,12 +5,14 @@ "@babel/code-frame@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" + integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== dependencies: "@babel/highlight" "^7.0.0" "@babel/core@^7.0.0": version "7.1.2" resolved "https://registry.npmjs.org/@babel/core/-/core-7.1.2.tgz#f8d2a9ceb6832887329a7b60f9d035791400ba4e" + integrity sha512-IFeSSnjXdhDaoysIlev//UzHZbdEmm7D0EIH2qtse9xK7mXEZQpYjs2P00XlP1qYsYvid79p+Zgg6tz1mp6iVw== dependencies: "@babel/code-frame" "^7.0.0" "@babel/generator" "^7.1.2" @@ -30,6 +32,7 @@ "@babel/generator@^7.1.2", "@babel/generator@^7.1.3": version "7.1.3" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.1.3.tgz#2103ec9c42d9bdad9190a6ad5ff2d456fd7b8673" + integrity sha512-ZoCZGcfIJFJuZBqxcY9OjC1KW2lWK64qrX1o4UYL3yshVhwKFYgzpWZ0vvtGMNJdTlvkw0W+HR1VnYN8q3QPFQ== dependencies: "@babel/types" "^7.1.3" jsesc "^2.5.1" @@ -40,12 +43,14 @@ "@babel/helper-annotate-as-pure@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" + integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q== dependencies: "@babel/types" "^7.0.0" "@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" + integrity sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w== dependencies: "@babel/helper-explode-assignable-expression" "^7.1.0" "@babel/types" "^7.0.0" @@ -53,6 +58,7 @@ "@babel/helper-call-delegate@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz#6a957f105f37755e8645343d3038a22e1449cc4a" + integrity sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ== dependencies: "@babel/helper-hoist-variables" "^7.0.0" "@babel/traverse" "^7.1.0" @@ -61,6 +67,7 @@ "@babel/helper-define-map@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz#3b74caec329b3c80c116290887c0dd9ae468c20c" + integrity sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg== dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/types" "^7.0.0" @@ -69,6 +76,7 @@ "@babel/helper-explode-assignable-expression@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" + integrity sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA== dependencies: "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" @@ -76,6 +84,7 @@ "@babel/helper-function-name@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" + integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== dependencies: "@babel/helper-get-function-arity" "^7.0.0" "@babel/template" "^7.1.0" @@ -84,30 +93,35 @@ "@babel/helper-get-function-arity@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" + integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== dependencies: "@babel/types" "^7.0.0" "@babel/helper-hoist-variables@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz#46adc4c5e758645ae7a45deb92bab0918c23bb88" + integrity sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w== dependencies: "@babel/types" "^7.0.0" "@babel/helper-member-expression-to-functions@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f" + integrity sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg== dependencies: "@babel/types" "^7.0.0" "@babel/helper-module-imports@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" + integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A== dependencies: "@babel/types" "^7.0.0" "@babel/helper-module-transforms@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.1.0.tgz#470d4f9676d9fad50b324cdcce5fbabbc3da5787" + integrity sha512-0JZRd2yhawo79Rcm4w0LwSMILFmFXjugG3yqf+P/UsKsRS1mJCmMwwlHDlMg7Avr9LrvSpp4ZSULO9r8jpCzcw== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-simple-access" "^7.1.0" @@ -119,22 +133,26 @@ "@babel/helper-optimise-call-expression@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" + integrity sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g== dependencies: "@babel/types" "^7.0.0" "@babel/helper-plugin-utils@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" + integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== "@babel/helper-regex@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.0.0.tgz#2c1718923b57f9bbe64705ffe5640ac64d9bdb27" + integrity sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg== dependencies: lodash "^4.17.10" "@babel/helper-remap-async-to-generator@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f" + integrity sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg== dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-wrap-function" "^7.1.0" @@ -145,6 +163,7 @@ "@babel/helper-replace-supers@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.1.0.tgz#5fc31de522ec0ef0899dc9b3e7cf6a5dd655f362" + integrity sha512-BvcDWYZRWVuDeXTYZWxekQNO5D4kO55aArwZOTFXw6rlLQA8ZaDicJR1sO47h+HrnCiDFiww0fSPV0d713KBGQ== dependencies: "@babel/helper-member-expression-to-functions" "^7.0.0" "@babel/helper-optimise-call-expression" "^7.0.0" @@ -154,6 +173,7 @@ "@babel/helper-simple-access@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" + integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w== dependencies: "@babel/template" "^7.1.0" "@babel/types" "^7.0.0" @@ -161,12 +181,14 @@ "@babel/helper-split-export-declaration@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813" + integrity sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag== dependencies: "@babel/types" "^7.0.0" "@babel/helper-wrap-function@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.1.0.tgz#8cf54e9190706067f016af8f75cb3df829cc8c66" + integrity sha512-R6HU3dete+rwsdAfrOzTlE9Mcpk4RjU3aX3gi9grtmugQY0u79X7eogUvfXA5sI81Mfq1cn6AgxihfN33STjJA== dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/template" "^7.1.0" @@ -176,6 +198,7 @@ "@babel/helpers@^7.1.2": version "7.1.2" resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.1.2.tgz#ab752e8c35ef7d39987df4e8586c63b8846234b5" + integrity sha512-Myc3pUE8eswD73aWcartxB16K6CGmHDv9KxOmD2CeOs/FaEAQodr3VYGmlvOmog60vNQ2w8QbatuahepZwrHiA== dependencies: "@babel/template" "^7.1.2" "@babel/traverse" "^7.1.0" @@ -184,6 +207,7 @@ "@babel/highlight@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" + integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== dependencies: chalk "^2.0.0" esutils "^2.0.2" @@ -192,18 +216,21 @@ "@babel/parser@^7.0.0", "@babel/parser@^7.1.2", "@babel/parser@^7.1.3": version "7.1.3" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.1.3.tgz#2c92469bac2b7fbff810b67fca07bd138b48af77" + integrity sha512-gqmspPZOMW3MIRb9HlrnbZHXI1/KHTOroBwN1NcLL6pWxzqzEKGvRTq0W/PxS45OtQGbaFikSQpkS5zbnsQm2w== "@babel/plugin-proposal-async-generator-functions@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.1.0.tgz#41c1a702e10081456e23a7b74d891922dd1bb6ce" + integrity sha512-Fq803F3Jcxo20MXUSDdmZZXrPe6BWyGcWBPPNB/M7WaUYESKDeKMOGIxEzQOjGSmW/NWb6UaPZrtTB2ekhB/ew== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-remap-async-to-generator" "^7.1.0" "@babel/plugin-syntax-async-generators" "^7.0.0" -"@babel/plugin-proposal-class-properties@^7.0.0": +"@babel/plugin-proposal-class-properties@^7.0.0", "@babel/plugin-proposal-class-properties@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.1.0.tgz#9af01856b1241db60ec8838d84691aa0bd1e8df4" + integrity sha512-/PCJWN+CKt5v1xcGn4vnuu13QDoV+P7NcICP44BoonAJoPSGwVkgrXihFIQGiEjjPlUDBIw1cM7wYFLARS2/hw== dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/helper-member-expression-to-functions" "^7.0.0" @@ -215,6 +242,7 @@ "@babel/plugin-proposal-decorators@^7.0.0": version "7.1.2" resolved "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.1.2.tgz#79829bd75fced6581ec6c7ab1930e8d738e892e7" + integrity sha512-YooynBO6PmBgHvAd0fl5e5Tq/a0pEC6RqF62ouafme8FzdIVH41Mz/u1dn8fFVm4jzEJ+g/MsOxouwybJPuP8Q== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-replace-supers" "^7.1.0" @@ -224,6 +252,7 @@ "@babel/plugin-proposal-json-strings@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.0.0.tgz#3b4d7b5cf51e1f2e70f52351d28d44fc2970d01e" + integrity sha512-kfVdUkIAGJIVmHmtS/40i/fg/AGnw/rsZBCaapY5yjeO5RA9m165Xbw9KMOu2nqXP5dTFjEjHdfNdoVcHv133Q== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-json-strings" "^7.0.0" @@ -231,6 +260,7 @@ "@babel/plugin-proposal-object-rest-spread@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0.tgz#9a17b547f64d0676b6c9cecd4edf74a82ab85e7e" + integrity sha512-14fhfoPcNu7itSen7Py1iGN0gEm87hX/B+8nZPqkdmANyyYWYMY2pjA3r8WXbWVKMzfnSNS0xY8GVS0IjXi/iw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread" "^7.0.0" @@ -238,6 +268,7 @@ "@babel/plugin-proposal-optional-catch-binding@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.0.0.tgz#b610d928fe551ff7117d42c8bb410eec312a6425" + integrity sha512-JPqAvLG1s13B/AuoBjdBYvn38RqW6n1TzrQO839/sIpqLpbnXKacsAgpZHzLD83Sm8SDXMkkrAvEnJ25+0yIpw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-optional-catch-binding" "^7.0.0" @@ -245,6 +276,7 @@ "@babel/plugin-proposal-unicode-property-regex@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0.tgz#498b39cd72536cd7c4b26177d030226eba08cd33" + integrity sha512-tM3icA6GhC3ch2SkmSxv7J/hCWKISzwycub6eGsDrFDgukD4dZ/I+x81XgW0YslS6mzNuQ1Cbzh5osjIMgepPQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" @@ -253,48 +285,63 @@ "@babel/plugin-syntax-async-generators@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.0.0.tgz#bf0891dcdbf59558359d0c626fdc9490e20bc13c" + integrity sha512-im7ged00ddGKAjcZgewXmp1vxSZQQywuQXe2B1A7kajjZmDeY/ekMPmWr9zJgveSaQH0k7BcGrojQhcK06l0zA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-class-properties@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.0.0.tgz#e051af5d300cbfbcec4a7476e37a803489881634" + integrity sha512-cR12g0Qzn4sgkjrbrzWy2GE7m9vMl/sFkqZ3gIpAQdrvPDnLM8180i+ANDFIXfjHo9aqp0ccJlQ0QNZcFUbf9w== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-decorators@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.1.0.tgz#2fa7c1a7905a299c9853ebcef340306675f9cbdc" + integrity sha512-uQvRSbgQ0nQg3jsmIixXXDCgSpkBolJ9X7NYThMKCcjvE8dN2uWJUzTUNNAeuKOjARTd+wUQV0ztXpgunZYKzQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-json-strings@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.0.0.tgz#0d259a68090e15b383ce3710e01d5b23f3770cbd" + integrity sha512-UlSfNydC+XLj4bw7ijpldc1uZ/HB84vw+U6BTuqMdIEmz/LDe63w/GHtpQMdXWdqQZFeAI9PjnHe/vDhwirhKA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0.tgz#37d8fbcaf216bd658ea1aebbeb8b75e88ebc549b" + integrity sha512-5A0n4p6bIiVe5OvQPxBnesezsgFJdHhSs3uFSvaPdMqtsovajLZ+G2vZyvNe10EzJBWWo3AcHGKhAFUxqwp2dw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-optional-catch-binding@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.0.0.tgz#886f72008b3a8b185977f7cb70713b45e51ee475" + integrity sha512-Wc+HVvwjcq5qBg1w5RG9o9RVzmCaAg/Vp0erHCKpAYV8La6I94o4GQAmFYNmkzoMO6gzoOSulpKeSSz6mPEoZw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-syntax-typescript@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.0.0.tgz#90f4fe0a741ae9c0dcdc3017717c05a0cbbd5158" + integrity sha512-5fxmdqiAQVQTIS+KSvYeZuTt91wKtBTYi6JlIkvbQ6hmO+9fZE81ezxmMiFMIsxE7CdRSgzn7nQ1BChcvK9OpA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-arrow-functions@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0.tgz#a6c14875848c68a3b4b3163a486535ef25c7e749" + integrity sha512-2EZDBl1WIO/q4DIkIp4s86sdp4ZifL51MoIviLY/gG/mLSuOIEg7J8o6mhbxOTvUJkaN50n+8u41FVsr5KLy/w== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-async-to-generator@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.1.0.tgz#109e036496c51dd65857e16acab3bafdf3c57811" + integrity sha512-rNmcmoQ78IrvNCIt/R9U+cixUHeYAzgusTFgIAv+wQb9HJU4szhpDD6e5GCACmj/JP5KxuCwM96bX3L9v4ZN/g== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -303,12 +350,14 @@ "@babel/plugin-transform-block-scoped-functions@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0.tgz#482b3f75103927e37288b3b67b65f848e2aa0d07" + integrity sha512-AOBiyUp7vYTqz2Jibe1UaAWL0Hl9JUXEgjFvvvcSc9MVDItv46ViXFw2F7SVt1B5k+KWjl44eeXOAk3UDEaJjQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-block-scoping@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.0.0.tgz#1745075edffd7cdaf69fab2fb6f9694424b7e9bc" + integrity sha512-GWEMCrmHQcYWISilUrk9GDqH4enf3UmhOEbNbNrlNAX1ssH3MsS1xLOS6rdjRVPgA7XXVPn87tRkdTEoA/dxEg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" lodash "^4.17.10" @@ -316,6 +365,7 @@ "@babel/plugin-transform-classes@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.1.0.tgz#ab3f8a564361800cbc8ab1ca6f21108038432249" + integrity sha512-rNaqoD+4OCBZjM7VaskladgqnZ1LO6o2UxuWSDzljzW21pN1KXkB7BstAVweZdxQkHAujps5QMNOTWesBciKFg== dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-define-map" "^7.1.0" @@ -329,18 +379,21 @@ "@babel/plugin-transform-computed-properties@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0.tgz#2fbb8900cd3e8258f2a2ede909b90e7556185e31" + integrity sha512-ubouZdChNAv4AAWAgU7QKbB93NU5sHwInEWfp+/OzJKA02E6Woh9RVoX4sZrbRwtybky/d7baTUqwFx+HgbvMA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-destructuring@^7.0.0": version "7.1.3" resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.1.3.tgz#e69ff50ca01fac6cb72863c544e516c2b193012f" + integrity sha512-Mb9M4DGIOspH1ExHOUnn2UUXFOyVTiX84fXCd+6B5iWrQg/QMeeRmSwpZ9lnjYLSXtZwiw80ytVMr3zue0ucYw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-dotall-regex@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.0.0.tgz#73a24da69bc3c370251f43a3d048198546115e58" + integrity sha512-00THs8eJxOJUFVx1w8i1MBF4XH4PsAjKjQ1eqN/uCH3YKwP21GCKfrn6YZFZswbOk9+0cw1zGQPHVc1KBlSxig== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" @@ -349,12 +402,14 @@ "@babel/plugin-transform-duplicate-keys@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0.tgz#a0601e580991e7cace080e4cf919cfd58da74e86" + integrity sha512-w2vfPkMqRkdxx+C71ATLJG30PpwtTpW7DDdLqYt2acXU7YjztzeWW2Jk1T6hKqCLYCcEA5UQM/+xTAm+QCSnuQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-exponentiation-operator@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.1.0.tgz#9c34c2ee7fd77e02779cfa37e403a2e1003ccc73" + integrity sha512-uZt9kD1Pp/JubkukOGQml9tqAeI8NkE98oZnHZ2qHRElmeKCodbTZgOEUtujSCSLhHSBWbzNiFSDIMC4/RBTLQ== dependencies: "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -362,12 +417,14 @@ "@babel/plugin-transform-for-of@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0.tgz#f2ba4eadb83bd17dc3c7e9b30f4707365e1c3e39" + integrity sha512-TlxKecN20X2tt2UEr2LNE6aqA0oPeMT1Y3cgz8k4Dn1j5ObT8M3nl9aA37LLklx0PBZKETC9ZAf9n/6SujTuXA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-function-name@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.1.0.tgz#29c5550d5c46208e7f730516d41eeddd4affadbb" + integrity sha512-VxOa1TMlFMtqPW2IDYZQaHsFrq/dDoIjgN098NowhexhZcz3UGlvPgZXuE1jEvNygyWyxRacqDpCZt+par1FNg== dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -375,12 +432,14 @@ "@babel/plugin-transform-literals@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0.tgz#2aec1d29cdd24c407359c930cdd89e914ee8ff86" + integrity sha512-1NTDBWkeNXgpUcyoVFxbr9hS57EpZYXpje92zv0SUzjdu3enaRwF/l3cmyRnXLtIdyJASyiS6PtybK+CgKf7jA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-modules-amd@^7.0.0", "@babel/plugin-transform-modules-amd@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.1.0.tgz#f9e0a7072c12e296079b5a59f408ff5b97bf86a8" + integrity sha512-wt8P+xQ85rrnGNr2x1iV3DW32W8zrB6ctuBkYBbf5/ZzJY99Ob4MFgsZDFgczNU76iy9PWsy4EuxOliDjdKw6A== dependencies: "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -388,6 +447,7 @@ "@babel/plugin-transform-modules-commonjs@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.1.0.tgz#0a9d86451cbbfb29bd15186306897c67f6f9a05c" + integrity sha512-wtNwtMjn1XGwM0AXPspQgvmE6msSJP15CX2RVfpTSTNPLhKhaOjaIfBaVfj4iUZ/VrFSodcFedwtPg/NxwQlPA== dependencies: "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -396,6 +456,7 @@ "@babel/plugin-transform-modules-systemjs@^7.0.0": version "7.1.3" resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.1.3.tgz#2119a3e3db612fd74a19d88652efbfe9613a5db0" + integrity sha512-PvTxgjxQAq4pvVUZF3mD5gEtVDuId8NtWkJsZLEJZMZAW3TvgQl1pmydLLN1bM8huHFVVU43lf0uvjQj9FRkKw== dependencies: "@babel/helper-hoist-variables" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -403,6 +464,7 @@ "@babel/plugin-transform-modules-umd@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.1.0.tgz#a29a7d85d6f28c3561c33964442257cc6a21f2a8" + integrity sha512-enrRtn5TfRhMmbRwm7F8qOj0qEYByqUvTttPEGimcBH4CJHphjyK1Vg7sdU7JjeEmgSpM890IT/efS2nMHwYig== dependencies: "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -410,12 +472,14 @@ "@babel/plugin-transform-new-target@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz#ae8fbd89517fa7892d20e6564e641e8770c3aa4a" + integrity sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-object-super@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.1.0.tgz#b1ae194a054b826d8d4ba7ca91486d4ada0f91bb" + integrity sha512-/O02Je1CRTSk2SSJaq0xjwQ8hG4zhZGNjE8psTsSNPXyLRCODv7/PBozqT5AmQMzp7MI3ndvMhGdqp9c96tTEw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-replace-supers" "^7.1.0" @@ -423,6 +487,7 @@ "@babel/plugin-transform-parameters@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.1.0.tgz#44f492f9d618c9124026e62301c296bf606a7aed" + integrity sha512-vHV7oxkEJ8IHxTfRr3hNGzV446GAb+0hgbA7o/0Jd76s+YzccdWuTU296FOCOl/xweU4t/Ya4g41yWz80RFCRw== dependencies: "@babel/helper-call-delegate" "^7.1.0" "@babel/helper-get-function-arity" "^7.0.0" @@ -431,24 +496,28 @@ "@babel/plugin-transform-regenerator@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz#5b41686b4ed40bef874d7ed6a84bdd849c13e0c1" + integrity sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw== dependencies: regenerator-transform "^0.13.3" "@babel/plugin-transform-shorthand-properties@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0.tgz#85f8af592dcc07647541a0350e8c95c7bf419d15" + integrity sha512-g/99LI4vm5iOf5r1Gdxq5Xmu91zvjhEG5+yZDJW268AZELAu4J1EiFLnkSG3yuUsZyOipVOVUKoGPYwfsTymhw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-spread@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0.tgz#93583ce48dd8c85e53f3a46056c856e4af30b49b" + integrity sha512-L702YFy2EvirrR4shTj0g2xQp7aNwZoWNCkNu2mcoU0uyzMl0XRwDSwzB/xp6DSUFiBmEXuyAyEN16LsgVqGGQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-sticky-regex@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0.tgz#30a9d64ac2ab46eec087b8530535becd90e73366" + integrity sha512-LFUToxiyS/WD+XEWpkx/XJBrUXKewSZpzX68s+yEOtIbdnsRjpryDw9U06gYc6klYEij/+KQVRnD3nz3AoKmjw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" @@ -456,6 +525,7 @@ "@babel/plugin-transform-template-literals@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0.tgz#084f1952efe5b153ddae69eb8945f882c7a97c65" + integrity sha512-vA6rkTCabRZu7Nbl9DfLZE1imj4tzdWcg5vtdQGvj+OH9itNNB6hxuRMHuIY8SGnEt1T9g5foqs9LnrHzsqEFg== dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -463,12 +533,22 @@ "@babel/plugin-transform-typeof-symbol@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0.tgz#4dcf1e52e943e5267b7313bff347fdbe0f81cec9" + integrity sha512-1r1X5DO78WnaAIvs5uC48t41LLckxsYklJrZjNKcevyz83sF2l4RHbw29qrCPr/6ksFsdfRpT/ZgxNWHXRnffg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +"@babel/plugin-transform-typescript@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.1.0.tgz#81e7b4be90e7317cbd04bf1163ebf06b2adee60b" + integrity sha512-TOTtVeT+fekAesiCHnPz+PSkYSdOSLyLn42DI45nxg6iCdlQY6LIj/tYqpMB0y+YicoTUiYiXqF8rG6SKfhw6Q== dependencies: "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-typescript" "^7.0.0" "@babel/plugin-transform-unicode-regex@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0.tgz#c6780e5b1863a76fe792d90eded9fcd5b51d68fc" + integrity sha512-uJBrJhBOEa3D033P95nPHu3nbFwFE9ZgXsfEitzoIXIwqAZWk7uXcg06yFKXz9FSxBH5ucgU/cYdX0IV8ldHKw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" @@ -477,6 +557,7 @@ "@babel/polyfill@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.0.0.tgz#c8ff65c9ec3be6a1ba10113ebd40e8750fb90bff" + integrity sha512-dnrMRkyyr74CRelJwvgnnSUDh2ge2NCTyHVwpOdvRMHtJUyxLtMAfhBN3s64pY41zdw0kgiLPh6S20eb1NcX6Q== dependencies: core-js "^2.5.7" regenerator-runtime "^0.11.1" @@ -484,6 +565,7 @@ "@babel/preset-env@^7.0.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.1.0.tgz#e67ea5b0441cfeab1d6f41e9b5c79798800e8d11" + integrity sha512-ZLVSynfAoDHB/34A17/JCZbyrzbQj59QC1Anyueb4Bwjh373nVPq5/HMph0z+tCmcDjXDe+DlKQq9ywQuvWrQg== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -530,6 +612,7 @@ "@babel/template@^7.1.0", "@babel/template@^7.1.2": version "7.1.2" resolved "https://registry.npmjs.org/@babel/template/-/template-7.1.2.tgz#090484a574fef5a2d2d7726a674eceda5c5b5644" + integrity sha512-SY1MmplssORfFiLDcOETrW7fCLl+PavlwMh92rrGcikQaRq4iWPVH0MpwPpY3etVMx6RnDjXtr6VZYr/IbP/Ag== dependencies: "@babel/code-frame" "^7.0.0" "@babel/parser" "^7.1.2" @@ -538,6 +621,7 @@ "@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0": version "7.1.4" resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.4.tgz#f4f83b93d649b4b2c91121a9087fa2fa949ec2b4" + integrity sha512-my9mdrAIGdDiSVBuMjpn/oXYpva0/EZwWL3sm3Wcy/AVWO2eXnsoZruOT9jOGNRXU8KbCIu5zsKnXcAJ6PcV6Q== dependencies: "@babel/code-frame" "^7.0.0" "@babel/generator" "^7.1.3" @@ -552,6 +636,7 @@ "@babel/types@^7.0.0", "@babel/types@^7.1.2", "@babel/types@^7.1.3": version "7.1.3" resolved "https://registry.npmjs.org/@babel/types/-/types-7.1.3.tgz#3a767004567060c2f40fca49a304712c525ee37d" + integrity sha512-RpPOVfK+yatXyn8n4PB1NW6k9qjinrXrRR8ugBN8fD6hCy5RXI6PSbVqpOJBO9oSaY7Nom4ohj35feb0UR9hSA== dependencies: esutils "^2.0.2" lodash "^4.17.10" @@ -560,6 +645,7 @@ "@ember-decorators/babel-transforms@^2.1.2": version "2.1.2" resolved "https://registry.npmjs.org/@ember-decorators/babel-transforms/-/babel-transforms-2.1.2.tgz#b646e53ece7c18ae42cd03f320146cb1f26f4ebf" + integrity sha512-Sfa4bjtRpWytbBZK3fAaUp6/2QpMDds6uGA5K7S+Iz1JGX+PHTLDjl1/5t1UaOMokEB1Z9jMtwp4yRcullfFdg== dependencies: "@babel/plugin-proposal-class-properties" "^7.0.0" "@babel/plugin-proposal-decorators" "^7.0.0" @@ -571,6 +657,7 @@ "@ember-decorators/component@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@ember-decorators/component/-/component-3.0.0.tgz#9f31cc4eac800bedebf69ef8e432519092cd0430" + integrity sha512-974O2OQZvZNJBHqRnl/tAu15O6NAhbNU8UhQ5WggFCubojrXSwMXj8wk79aLT7Z3lcZTpNfPb5g16O0WlyXYpg== dependencies: "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" @@ -578,6 +665,7 @@ "@ember-decorators/controller@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@ember-decorators/controller/-/controller-3.0.0.tgz#1f5b0e88f7456bc869775f70cd86a56cb690f301" + integrity sha512-BESK+lVJGgTfQ6+6fygZeSqedltTHUJyX9tHzOtlRBg3MJOR0xrsS8Yh27ikJ3tlswZ21GoIV6CTsQ40pIlmLg== dependencies: "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" @@ -585,6 +673,7 @@ "@ember-decorators/data@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@ember-decorators/data/-/data-3.0.0.tgz#78c6cb8b9b14eeee4bfd265cd00c95dc09416420" + integrity sha512-VsalfSnz7a8N7AEfu8Kuzc9pFAZ1Oh/M9NNMP5lts7tmZctRPsi7u3HLYAv5Iz7etseW0DFq8hcAobZIDOPWFw== dependencies: "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" @@ -592,6 +681,7 @@ "@ember-decorators/object@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@ember-decorators/object/-/object-3.0.0.tgz#84c5d3e62d3b211ffd17a795c0c4a65c3fe52f8d" + integrity sha512-cvQDoZM+vJJniT0sZZZHS1TWdG9V9XmPBfeiaAlS1YTNQmLmNyDfmqd+/OUJUP0er/im8GjGCzMUifuZWhqdmQ== dependencies: "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" @@ -600,6 +690,7 @@ "@ember-decorators/service@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@ember-decorators/service/-/service-3.0.0.tgz#90fe410b8b2b80ad7227a85259e3a8c3852000a2" + integrity sha512-YcyH/+2AlAmOyVeKMSbc3rvT+n1ts2mPsZRGS1nKvIWB/M8cfOQrssdBj+kbQS7RTxC/sPRAnBZsvTRhRsua8g== dependencies: "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" @@ -607,6 +698,7 @@ "@ember-decorators/utils@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@ember-decorators/utils/-/utils-3.0.0.tgz#f8e82ead2c75a8eaf2cef5b1811ab54fcb28bcee" + integrity sha512-ghvNpiS9p8y/3whKB5J8PK2ESXeyk4oKYgJHyks8799lgi2MgbFeFyls6weJNKRp5Wcjen2KEBzTaf/zExZlgA== dependencies: babel-plugin-debug-macros "^0.1.11" ember-cli-babel "^6.6.0" @@ -615,6 +707,7 @@ "@ember/ordered-set@^2.0.3": version "2.0.3" resolved "https://registry.npmjs.org/@ember/ordered-set/-/ordered-set-2.0.3.tgz#2ac1ca73b3bd116063cae814898832ef434a57f9" + integrity sha512-F4yfVk6WMc4AUHxeZsC3CaKyTvO0qSZJy7WWHCFTlVDQw6vubn+FvnGdhzpN1F00EiXMI4Tv1tJdSquHcCnYrA== dependencies: ember-cli-babel "^6.16.0" ember-compatibility-helpers "^1.1.1" @@ -622,6 +715,7 @@ "@ember/test-helpers@^0.7.26": version "0.7.27" resolved "https://registry.npmjs.org/@ember/test-helpers/-/test-helpers-0.7.27.tgz#c622cabd0cbb95b34efc1e1b6274ab5a14edc138" + integrity sha512-AQESk0FTFxRY6GyZ8PharR4SC7Fju0rXqNkfNYIntAjzefZ8xEqEM4iXDj5h7gAvfx/8dA69AQ9+p7ubc+KvJg== dependencies: broccoli-funnel "^2.0.1" ember-assign-polyfill "~2.4.0" @@ -631,58 +725,249 @@ "@glimmer/di@^0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" + integrity sha1-c7/Upu5BSKgL8JLopdKbysnUzn4= + +"@glimmer/env@^0.1.7": + version "0.1.7" + resolved "https://registry.npmjs.org/@glimmer/env/-/env-0.1.7.tgz#fd2d2b55a9029c6b37a6c935e8c8871ae70dfa07" + integrity sha1-/S0rVakCnGs3psk16MiHGucN+gc= "@glimmer/resolver@^0.4.1": version "0.4.3" resolved "https://registry.yarnpkg.com/@glimmer/resolver/-/resolver-0.4.3.tgz#b1baae5c3291b4621002ccf8d7870466097e841d" + integrity sha512-UhX6vlZbWRMq6pCquSC3wfWLM9kO0PhQPD1dZ3XnyZkmsvEE94Cq+EncA9JalUuevKoJrfUFRvrZ0xaz+yar3g== dependencies: "@glimmer/di" "^0.2.0" "@sindresorhus/is@^0.7.0": version "0.7.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" + integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== "@types/acorn@^4.0.3": version "4.0.3" resolved "https://registry.yarnpkg.com/@types/acorn/-/acorn-4.0.3.tgz#d1f3e738dde52536f9aad3d3380d14e448820afd" + integrity sha512-gou/kWQkGPMZjdCKNZGDpqxLm9+ErG/pFZKPX4tvCjr0Xf4FCYYX3nAsu7aDVKJV3KUe27+mvqqyWT/9VZoM/A== dependencies: "@types/estree" "*" +"@types/ember-qunit@~3.4.3": + version "3.4.3" + resolved "https://registry.yarnpkg.com/@types/ember-qunit/-/ember-qunit-3.4.3.tgz#ad8532e735c7a46af764f5cb7d852896e6d28bfd" + integrity sha512-dBlWUh7XMHT3dr96P2c5U5hx8dLE4RZmtwKhUeaHycsgJyH4pCX1C462Bk308fWXFN1TWasZtkl+MhtW/mj3RA== + dependencies: + "@types/ember" "*" + "@types/ember-test-helpers" "*" + +"@types/ember-test-helpers@*", "@types/ember-test-helpers@~1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/ember-test-helpers/-/ember-test-helpers-1.0.4.tgz#db08190659339cd6018ff8f842c6df6f24d7679a" + integrity sha512-9UnLaDSRiNHZtj3Bn46kRkQKbbnb50ClpzQQ0p/raZYzHjDjUZfLpI4KOuVRfibgEj4LI+lsUKx5LQeLD09wcw== + dependencies: + "@types/ember" "*" + "@types/htmlbars-inline-precompile" "*" + "@types/jquery" "*" + "@types/rsvp" "*" + +"@types/ember-testing-helpers@~0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@types/ember-testing-helpers/-/ember-testing-helpers-0.0.3.tgz#1a6cfc484b63d19ddd822c87e4dd710597db17d9" + integrity sha512-QG3QBBR7PFzz3zhLTbsZWBgk3cNQIZYVG6rbXKMM36+YP3dcSkkWQ6CRTyQImUIfgAkYPMaWqGlGEtkuanq3Bg== + dependencies: + "@types/jquery" "*" + "@types/rsvp" "*" + +"@types/ember@*", "@types/ember@~3.0.25": + version "3.0.25" + resolved "https://registry.yarnpkg.com/@types/ember/-/ember-3.0.25.tgz#9ab6a8be3d03a72176824bb7a59583648b6b1ced" + integrity sha512-+M4yzJ0v+Ly62clAoxmAxViFg+/2HiktQnzKh825/y9Ra3k7o4PFsas0Z7xERmRVleqtPikehwdi6BuEnPUVkw== + dependencies: + "@types/ember__application" "*" + "@types/ember__array" "*" + "@types/ember__component" "*" + "@types/ember__controller" "*" + "@types/ember__debug" "*" + "@types/ember__engine" "*" + "@types/ember__error" "*" + "@types/ember__object" "*" + "@types/ember__polyfills" "*" + "@types/ember__routing" "*" + "@types/ember__runloop" "*" + "@types/ember__service" "*" + "@types/ember__string" "*" + "@types/ember__test" "*" + "@types/ember__utils" "*" + "@types/handlebars" "*" + "@types/htmlbars-inline-precompile" "*" + "@types/jquery" "*" + "@types/rsvp" "*" + +"@types/ember__application@*": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/ember__application/-/ember__application-3.0.5.tgz#e171c5f44f58fb5600952bfde25c1dfe3785a08e" + integrity sha512-lRZZInE7g5//UQyJ2ro/wql6AcjYeFTo69SYrL2qdgHSwGemSv/A/6u5Q73OMuKZL22nNyCLoCy/Q7TrEhM/mQ== + +"@types/ember__array@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/ember__array/-/ember__array-3.0.3.tgz#87887852b16b7572441b9723994098f939f2a386" + integrity sha512-9RVCedNGxkXrCwOVvDaD5/RB4FbOzZLA5+BV5kcRkxjNcAQMx29BwM6/nipAKGppi1wmoPPkVpsHcJcbiuUgbQ== + +"@types/ember__component@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/ember__component/-/ember__component-3.0.4.tgz#e671213269bbf974445fb9fdd600d52ef0ae1e2a" + integrity sha512-SgUAtEqbTdexNFJsvC0EJ0wfQ3+a66xGEFojwjoeilVUaBDAhcfGzlai6Y101xfyax9kYdBX3XJ2YmtRh32rPw== + dependencies: + "@types/jquery" "*" + +"@types/ember__controller@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/ember__controller/-/ember__controller-3.0.3.tgz#622440d41ce0ae46f2610ed22670be9088cc9c2b" + integrity sha512-jJ/4SmRfAQuLS+dxB7GdS9BU1dpqA8QzKq84d1+aZkpcDiu0pD7/Xwu5FN4pbU1kBfX2w6jdQQRlnorOpuYltQ== + +"@types/ember__debug@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/ember__debug/-/ember__debug-3.0.3.tgz#b8c3481e2305b636dca4524331efd4112071902b" + integrity sha512-6cOPb5S9IX4tU4b8YwkxbnlF+mql/ejTgpMtuyNmFyp4irBV9fdKn6y1K6hvml7yDSJnhdw37/6Gs+nGi95eKQ== + +"@types/ember__engine@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/ember__engine/-/ember__engine-3.0.3.tgz#440e656f825f73240419367ee7637ca94b4a1780" + integrity sha512-mXaUam9NbU7mOxRDBNcnW3GYpo+NVYQPSRor6ghdABOl+Lik8frX0oqgSnknauoCVW34Q75oH3xAd1cjNWEsPA== + +"@types/ember__error@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/ember__error/-/ember__error-3.0.2.tgz#a30c0e51215feaaa7a32e341c5a04bd601a01d1b" + integrity sha512-U1IsKAfoqgNTAQ7rojbAmF8ynQaovfHP9Kff1lCB1A1FLq+vtQ81CzaiEHgWWAlPfbqrFtBIYD0rwehEQ1ofRg== + +"@types/ember__object@*": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/ember__object/-/ember__object-3.0.5.tgz#c4957cad68fffdd0959c6ca0d3469df8878b750c" + integrity sha512-0sgaktxsu86OqRNOe9lxLhqWnGGk+gNM+iuAbi7BKc5OZQHlOtAGPgHv7hUozWCW5cVK/3hMbr3ciD/vu25xsg== + dependencies: + "@types/rsvp" "*" + +"@types/ember__polyfills@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/ember__polyfills/-/ember__polyfills-3.0.2.tgz#ccd9f510a4895abf92435c968f9e582e86a81b25" + integrity sha512-b+FT7EFsyqgRBHYLq71SJm88iLOfz/QYjdOJi72hYWXG8sBoK6GYcUzGlaQwCFgz/HFp/KH68jCDx+sHIq+kxQ== + +"@types/ember__routing@*": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/ember__routing/-/ember__routing-3.0.5.tgz#9b193178a1cc29560992c57b04fd7d83a70f831d" + integrity sha512-G2e7WYNsLHQaoKeJUIFyVlzQUToCDm2omP9jaXHS1vzz5UYN1FXI+w2PPTC3eqcb9py/B6SzmthokaTy0VEdCA== + +"@types/ember__runloop@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/ember__runloop/-/ember__runloop-3.0.3.tgz#c23c9d4327ca811482422505a1f5bf1c48458f53" + integrity sha512-JQ9SK0pmdXcIpy++FpIC3tJeHtEn9sxO2QRNDR3Xe8KVnq7+ld4lmNF6DMIx9UvoyV2lJstrv/sjDqhMvIadwA== + +"@types/ember__service@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/ember__service/-/ember__service-3.0.2.tgz#8265c94a599c865f633361b0e3b1efbeef393d7d" + integrity sha512-HxruUU/U3wIFk6YTX1Yl57WjosuPpawr3JJHUZktPHjFwe9uHEIoO8yc7QUeQTB9OIk3NVt05391TtOJrKON7g== + +"@types/ember__string@*": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/ember__string/-/ember__string-3.0.2.tgz#2ffdf09baab6a641c94c0149a8ff3670f793788d" + integrity sha512-VN6HgEs7VJzPFmfVN2riQ4oroIh650YWsNOWFiq5uKzYD8kCtfrkpyRJjzGoTmS3mm8F3qIVw6Ev6KGXxQU8+A== + dependencies: + "@types/handlebars" "*" + +"@types/ember__test-helpers@~0.7.6": + version "0.7.6" + resolved "https://registry.yarnpkg.com/@types/ember__test-helpers/-/ember__test-helpers-0.7.6.tgz#f26050fc74cd8ce111ee9e01864a293d6a9ac7ac" + integrity sha512-TEIitF7M984drIuK1iKHWfU7BLvdp4qakC7Qwmz88HoJxjdMKHHYAIIVO+SPZdXBCmPjOmCs87bz2okMs9nU2Q== + dependencies: + "@types/ember" "*" + "@types/ember__error" "*" + "@types/htmlbars-inline-precompile" "*" + +"@types/ember__test@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/ember__test/-/ember__test-3.0.3.tgz#dda4721609e9e80d62af784757b8b3b76b49a07d" + integrity sha512-pedzxJh7BZBIL4tgnWv74f3EuRqbm7sRroWFhcIRhNliFUTN0GZ9p7poAp7gnwOxpYLcXOvUjkdaeaWP6rxYMA== + +"@types/ember__utils@*": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/ember__utils/-/ember__utils-3.0.1.tgz#f08aa24920515400fec869cbf29df69c4773f6d0" + integrity sha512-seA9IX2DCrkHxgVmtoKUVEBj6to8vqlPG7AzwB2oodLlQZiRwmrnn+fjOn+wKA5btIVIiRdxn/f41qFZXcPy6w== + "@types/estree@*": version "0.0.39" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" + integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== "@types/estree@0.0.38": version "0.0.38" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.38.tgz#c1be40aa933723c608820a99a373a16d215a1ca2" + integrity sha512-F/v7t1LwS4vnXuPooJQGBRKRGIoxWUTmA4VHfqjOccFsNDThD5bfUNpITive6s352O7o384wcpEaDV8rHCehDA== + +"@types/handlebars@*": + version "4.0.39" + resolved "https://registry.yarnpkg.com/@types/handlebars/-/handlebars-4.0.39.tgz#961fb54db68030890942e6aeffe9f93a957807bd" + integrity sha512-vjaS7Q0dVqFp85QhyPSZqDKnTTCemcSHNHFvDdalO1s0Ifz5KuE64jQD5xoUkfdWwF4WpqdJEl7LsWH8rzhKJA== + +"@types/htmlbars-inline-precompile@*": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/htmlbars-inline-precompile/-/htmlbars-inline-precompile-1.0.0.tgz#4c283da1a7e303b269de3c6aa953acc8d8736949" + integrity sha512-J7+MkDbUl/Sb57OuniuvVr4HLlHV2ub2y31HmD9QiepLEMj0zGIv4hbyOfGHTKWCcU0r7lxcDdHdLyUjpuL21w== + +"@types/jquery@*": + version "3.3.22" + resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.22.tgz#cde55dc8f83207dffd16205b05f97ce824581735" + integrity sha512-a4JDcIhJhHYnoWCkG3xT2CZxXZeA92JeREESorg0DMQ3ZsjuKF48h7XK4l5Gl2GRa/ItGRpKMT0pyK88yRgqXQ== + dependencies: + "@types/sizzle" "*" "@types/node@^9.6.0": version "9.6.23" resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.23.tgz#fc429962c1b75f32bd66214a3997f660e8434f0d" + integrity sha512-d2SJJpwkiPudEQ3+9ysANN2Nvz4QJKUPoe/WL5zyQzI0RaEeZWH5K5xjvUIGszTItHQpFPdH+u51f6G/LkS8Cg== + +"@types/qunit@^2.5.3": + version "2.5.3" + resolved "https://registry.yarnpkg.com/@types/qunit/-/qunit-2.5.3.tgz#e7df363b5e1d1ba034b5fdd34b560d5ec0914225" + integrity sha512-b9xNH1wBOnY+yiCT2DiAC0yi7GCF5g6whiAFA/dpd9RtL/Jn2XR7e4yyeAQwH3TUeF00zikmYqYxS0K8+EKTKQ== + +"@types/rsvp@*", "@types/rsvp@^4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/rsvp/-/rsvp-4.0.2.tgz#bf9f72eaa6771292638a85bb8ce1db97e754b371" + integrity sha512-48ZwxFD1hdBj8QMOSNGA2kYuo3+SKh8OEYh5cMi7cPRZXBF9jwVPV4yqA7EcJTNlAJL0v99pEUYetl0TsufMQA== + +"@types/sizzle@*": + version "2.3.2" + resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" + integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg== "@types/tmp@^0.0.33": version "0.0.33" resolved "https://registry.npmjs.org/@types/tmp/-/tmp-0.0.33.tgz#1073c4bc824754ae3d10cfab88ab0237ba964e4d" + integrity sha1-EHPEvIJHVK49EM+riKsCN7qWTk0= "@xg-wang/whatwg-fetch@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@xg-wang/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#f7b222c012a238e7d6e89ed3d72a1e0edb58453d" + integrity sha512-ULtqA6L75RLzTNW68IiOja0XYv4Ebc3OGMzfia1xxSEMpD0mk/pMvkQX0vbCFyQmKc5xGp80Ms2WiSlXLh8hbA== abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== abbrev@~1.0.7: version "1.0.9" resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU= abortcontroller-polyfill@^1.1.9: version "1.1.9" resolved "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.1.9.tgz#9fefe359fda2e9e0932dc85e6106453ac393b2da" + integrity sha512-omvG7zOHIs3BphdH62Kh3xy8nlftAsTyp7PDa9EmC3Jz9pa6sZFYk7UhNgu9Y4sIBhj6jF0RgeFZYvPnsP5sBw== accepts@~1.3.4, accepts@~1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= dependencies: mime-types "~2.1.18" negotiator "0.6.1" @@ -690,26 +975,31 @@ accepts@~1.3.4, accepts@~1.3.5: acorn-dynamic-import@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" + integrity sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg== dependencies: acorn "^5.0.0" acorn-jsx@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-4.1.1.tgz#e8e41e48ea2fe0c896740610ab6a4ffd8add225e" + integrity sha512-JY+iV6r+cO21KtntVvFkD+iqjtdpRUpGqKWgfkCdZq1R+kbreEl8EcdcJR4SmiIgsIQT33s6QzheQ9a275Q8xw== dependencies: acorn "^5.0.3" acorn@^5.0.0, acorn@^5.0.3, acorn@^5.5.3, acorn@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" + integrity sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ== after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= ajv@^5.3.0: version "5.5.2" resolved "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= dependencies: co "^4.6.0" fast-deep-equal "^1.0.0" @@ -719,6 +1009,7 @@ ajv@^5.3.0: ajv@^6.5.3: version "6.5.4" resolved "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz#247d5274110db653706b550fcc2b797ca28cfc59" + integrity sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg== dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" @@ -728,6 +1019,7 @@ ajv@^6.5.3: align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc= dependencies: kind-of "^3.0.2" longest "^1.0.1" @@ -736,58 +1028,78 @@ align-text@^0.1.1, align-text@^0.1.3: amd-name-resolver@1.2.0, amd-name-resolver@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz#fc41b3848824b557313897d71f8d5a0184fbe679" + integrity sha512-hlSTWGS1t6/xq5YCed7YALg7tKZL3rkl7UwEZ/eCIkn8JxmM6fU6Qs/1hwtjQqfuYxlffuUcgYEm0f5xP4YKaA== dependencies: ensure-posix-path "^1.0.1" amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + integrity sha1-06ioOzGapneTZisT52HHkRQiMG4= ansi-escapes@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" + integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw== ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= ansi-styles@^3.0.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" +ansi-to-html@^0.6.6: + version "0.6.8" + resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.6.8.tgz#2a4468b45a5d2a2c1a51eb1a1175eda8acb4f07a" + integrity sha512-wXwNl185AIu1QXuNApBiYNaWx0q+Ma1tLDVgc0HbA43GFWG8p1gcWLKKIBjQqamKe3rUkEILb6QMu9G/V14mzQ== + dependencies: + entities "^1.1.1" + ansi@^0.3.0, ansi@~0.3.0, ansi@~0.3.1: version "0.3.1" resolved "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz#0c42d4fb17160d5a9af1e484bace1c66922c1b21" + integrity sha1-DELU+xcWDVqa8eSEus4cZpIsGyE= ansicolors@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" + integrity sha1-vgiVmQl7dKXJxKhKDNvNtivYeu8= ansicolors@~0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" + integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk= ansistyles@~0.1.3: version "0.1.3" resolved "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" + integrity sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk= anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== dependencies: micromatch "^3.1.4" normalize-path "^2.1.1" @@ -795,18 +1107,22 @@ anymatch@^2.0.0: aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== aproba@~1.0.1: version "1.0.4" resolved "https://registry.npmjs.org/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + integrity sha1-JxNoB3XnYUyLoYbAZdTi5S0QcsA= archy@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= are-we-there-yet@~1.0.0: version "1.0.6" resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.6.tgz#a2d28c93102aa6cc96245a26cb954de06ec53f0c" + integrity sha1-otKMkxAqpsyWJFomy5VN4G7FPww= dependencies: delegates "^1.0.0" readable-stream "^2.0.0 || ^1.1.13" @@ -814,6 +1130,7 @@ are-we-there-yet@~1.0.0: are-we-there-yet@~1.1.2: version "1.1.5" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== dependencies: delegates "^1.0.0" readable-stream "^2.0.6" @@ -821,42 +1138,51 @@ are-we-there-yet@~1.1.2: argparse@^1.0.7, argparse@~1.0.2: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" arr-diff@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= dependencies: arr-flatten "^1.0.1" arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== arr-union@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= array-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= array-index@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/array-index/-/array-index-1.0.0.tgz#ec56a749ee103e4e08c790b9c353df16055b97f9" + integrity sha1-7FanSe4QPk4Ix5C5w1PfFgVbl/k= dependencies: debug "^2.2.0" es6-symbol "^3.0.2" @@ -864,80 +1190,98 @@ array-index@^1.0.0: array-to-error@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" + integrity sha1-1ogSkm0UCXogVXmmZ+6vGFakTAc= dependencies: array-to-sentence "^1.1.0" array-to-sentence@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" + integrity sha1-yASVba+lMjJJWyBalFJ1OiWNOfw= array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= dependencies: array-uniq "^1.0.1" array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= arraybuffer.slice@~0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= asap@^2.0.0: version "2.0.6" resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= asn1@0.1.11: version "0.1.11" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" + integrity sha1-VZvhg3bQik7E2+gId9J4GGObLfc= asn1@~0.2.3: version "0.2.4" resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== dependencies: safer-buffer "~2.1.0" assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= assert-plus@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" + integrity sha1-7nQAlBMALYTOxyGcasgRgS5yMWA= assert-plus@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + integrity sha1-104bh+ev/A24qttwIfP+SBAasjQ= assertion-error@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= ast-types@0.9.6: version "0.9.6" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" + integrity sha1-ECyenpAF0+fjgpvwxPok7oYu6bk= async-disk-cache@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.3.3.tgz#6040486660b370e4051cd9fa9fee275e1fae3728" + integrity sha512-GyaWSbDAZCltxSobtj1m1ptXa0+zSdjWs3sM4IqnvhoRwMDHW5786sXQ1RiXbR3ZGuQe6NXMB4N0vUmW163cew== dependencies: debug "^2.1.3" heimdalljs "^0.2.3" @@ -950,10 +1294,12 @@ async-disk-cache@^1.2.1: async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== async-promise-queue@^1.0.3, async-promise-queue@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/async-promise-queue/-/async-promise-queue-1.0.4.tgz#308baafbc74aff66a0bb6e7f4a18d4fe8434440c" + integrity sha512-GQ5X3DT+TefYuFPHdvIPXFTlKnh39U7dwtl+aUBGeKjMea9nBpv3c91DXgeyBQmY07vQ97f3Sr9XHqkamEameQ== dependencies: async "^2.4.1" debug "^2.6.8" @@ -961,54 +1307,66 @@ async-promise-queue@^1.0.3, async-promise-queue@^1.0.4: async-some@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/async-some/-/async-some-1.0.2.tgz#4d8a81620d5958791b5b98f802d3207776e95509" + integrity sha1-TYqBYg1ZWHkbW5j4AtMgd3bpVQk= dependencies: dezalgo "^1.0.2" async@^1.4.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= async@^2.0.1, async@^2.4.1, async@^2.5.0: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" + integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ== dependencies: lodash "^4.17.10" async@~0.2.9: version "0.2.10" resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E= async@~0.9.0: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= asynckit@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= atob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" + integrity sha1-ri1acpR38onWDdf5amMUoi3Wwio= aws-sign2@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" + integrity sha1-xXED96F/wDfwLXwuZLYC6iI/fWM= aws-sign2@~0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + integrity sha1-FDQt0428yU0OW4fXY81jYSwOeU8= aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: version "1.8.0" resolved "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" + integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= dependencies: chalk "^1.1.3" esutils "^2.0.2" @@ -1017,6 +1375,7 @@ babel-code-frame@^6.26.0: babel-core@^6.26.0: version "6.26.3" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + integrity sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA== dependencies: babel-code-frame "^6.26.0" babel-generator "^6.26.0" @@ -1041,6 +1400,7 @@ babel-core@^6.26.0: babel-eslint@^10.0.1: version "10.0.1" resolved "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz#919681dc099614cd7d31d45c8908695092a1faed" + integrity sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ== dependencies: "@babel/code-frame" "^7.0.0" "@babel/parser" "^7.0.0" @@ -1052,6 +1412,7 @@ babel-eslint@^10.0.1: babel-generator@^6.26.0: version "6.26.1" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== dependencies: babel-messages "^6.23.0" babel-runtime "^6.26.0" @@ -1065,6 +1426,7 @@ babel-generator@^6.26.0: babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + integrity sha1-zORReto1b0IgvK6KAsKzRvmlZmQ= dependencies: babel-helper-explode-assignable-expression "^6.24.1" babel-runtime "^6.22.0" @@ -1073,6 +1435,7 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: babel-helper-call-delegate@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + integrity sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340= dependencies: babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" @@ -1082,6 +1445,7 @@ babel-helper-call-delegate@^6.24.1: babel-helper-define-map@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + integrity sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8= dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.26.0" @@ -1091,6 +1455,7 @@ babel-helper-define-map@^6.24.1: babel-helper-explode-assignable-expression@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + integrity sha1-8luCz33BBDPFX3BZLVdGQArCLKo= dependencies: babel-runtime "^6.22.0" babel-traverse "^6.24.1" @@ -1099,6 +1464,7 @@ babel-helper-explode-assignable-expression@^6.24.1: babel-helper-function-name@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + integrity sha1-00dbjAPtmCQqJbSDUasYOZ01gKk= dependencies: babel-helper-get-function-arity "^6.24.1" babel-runtime "^6.22.0" @@ -1109,6 +1475,7 @@ babel-helper-function-name@^6.24.1: babel-helper-get-function-arity@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + integrity sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -1116,6 +1483,7 @@ babel-helper-get-function-arity@^6.24.1: babel-helper-hoist-variables@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + integrity sha1-HssnaJydJVE+rbyZFKc/VAi+enY= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -1123,6 +1491,7 @@ babel-helper-hoist-variables@^6.24.1: babel-helper-optimise-call-expression@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + integrity sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -1130,6 +1499,7 @@ babel-helper-optimise-call-expression@^6.24.1: babel-helper-regex@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + integrity sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI= dependencies: babel-runtime "^6.26.0" babel-types "^6.26.0" @@ -1138,6 +1508,7 @@ babel-helper-regex@^6.24.1: babel-helper-remap-async-to-generator@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + integrity sha1-XsWBgnrXI/7N04HxySg5BnbkVRs= dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" @@ -1148,6 +1519,7 @@ babel-helper-remap-async-to-generator@^6.24.1: babel-helper-replace-supers@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + integrity sha1-v22/5Dk40XNpohPKiov3S2qQqxo= dependencies: babel-helper-optimise-call-expression "^6.24.1" babel-messages "^6.23.0" @@ -1159,6 +1531,7 @@ babel-helper-replace-supers@^6.24.1: babel-helpers@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + integrity sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI= dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" @@ -1166,52 +1539,61 @@ babel-helpers@^6.24.1: babel-messages@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= dependencies: babel-runtime "^6.22.0" babel-plugin-check-es2015-constants@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + integrity sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o= dependencies: babel-runtime "^6.22.0" babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.11: version "0.1.11" resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" + integrity sha512-hZw5qNNGAR02Y+yBUrtsnJHh8OXavkayPRqKGAXnIm4t5rWVpj3ArwsC7TWdpZsBguQvHAeyTxZ7s23yY60HHg== dependencies: semver "^5.3.0" babel-plugin-debug-macros@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0.tgz#0120ac20ce06ccc57bf493b667cf24b85c28da7a" + integrity sha512-Wpmw4TbhR3Eq2t3W51eBAQSdKlr+uAyF0GI4GtPfMCD12Y4cIdpKC9l0RjNTH/P9isFypSqqewMPm7//fnZlNA== dependencies: semver "^5.3.0" babel-plugin-debug-macros@^0.2.0-beta.6: version "0.2.0-beta.6" resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0-beta.6.tgz#ecdf6e408d5c863ab21740d7ad7f43f027d2f912" + integrity sha1-7N9uQI1chjqyF0DXrX9D8CfS+RI= dependencies: semver "^5.3.0" babel-plugin-ember-modules-api-polyfill@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.3.2.tgz#56ea34bea963498d070a2b7dc2ce18a92c434093" + integrity sha512-mi9gaYasj2Bd6FYD1XCvuU1RL3n4DPn+VdOORyC2nqrvK50cLHkPaq/NdsqfxtZ0WNCIigrwnTHXU3XZI80tPg== dependencies: ember-rfc176-data "^0.3.0" babel-plugin-ember-modules-api-polyfill@^2.5.0: version "2.5.0" resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.5.0.tgz#860aab9fecbf38c10d1fe0779c6979a854fff154" + integrity sha512-o1rOgWFHR0IRBjC9Dvqc2V4MKE2UvdMv/fD/c5GUMAkS6DlTjQV54iMH9sdQ3TGfXPukPKBIOpoSoH/hdfGiMg== dependencies: ember-rfc176-data "^0.3.5" babel-plugin-feature-flags@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" + integrity sha1-nIJ8+aTrmhn3JcyyOehcqwIDb8E= babel-plugin-filter-imports@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/babel-plugin-filter-imports/-/babel-plugin-filter-imports-2.0.3.tgz#21f2773d0d74558986dd7af89f6f753d5fa92da3" + integrity sha512-s2vbul45NHOI665jcJvvIdzZLMIKgUdhofGEbxXn7GxfEB6SePCUbj2qBPjV9oqHuYBQucih/tRhO/GJu8mPkg== dependencies: "@babel/types" "^7.0.0" lodash "^4.17.11" @@ -1219,10 +1601,12 @@ babel-plugin-filter-imports@^2.0.3: babel-plugin-htmlbars-inline-precompile@^0.2.5: version "0.2.6" resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.6.tgz#c00b8a3f4b32ca04bf0f0d5169fcef3b5a66d69d" + integrity sha512-H4H75TKGUFij8ukwEYWEERAgrUf16R8NSK1uDPe3QwxT8mnE1K8+/s6DVjUqbM5Pv6lSIcE4XufXdlSX+DTB6g== babel-plugin-module-resolver@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.1.1.tgz#881cf67e3d4b8400d5eaaefc1be44d2dc1fe404f" + integrity sha512-1Q77Al4ydp6nYApJ7sQ2fmgz30WuQgJZegIYuyOdbdpxenB/bSezQ3hDPsumIXGlUS4vUIv+EwFjzzXZNWtARw== dependencies: find-babel-config "^1.1.0" glob "^7.1.2" @@ -1233,26 +1617,32 @@ babel-plugin-module-resolver@^3.1.1: babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + integrity sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU= babel-plugin-syntax-class-properties@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + integrity sha1-1+sjt5oxf4VDlixQW4J8fWysJ94= babel-plugin-syntax-decorators@^6.1.18: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" + integrity sha1-MSVjtNvePMgGzuPkFszurd0RrAs= babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + integrity sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4= babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + integrity sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM= babel-plugin-transform-async-to-generator@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + integrity sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E= dependencies: babel-helper-remap-async-to-generator "^6.24.1" babel-plugin-syntax-async-functions "^6.8.0" @@ -1261,6 +1651,7 @@ babel-plugin-transform-async-to-generator@^6.22.0: babel-plugin-transform-class-properties@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + integrity sha1-anl2PqYdM9NvN7YRqp3vgagbRqw= dependencies: babel-helper-function-name "^6.24.1" babel-plugin-syntax-class-properties "^6.8.0" @@ -1270,6 +1661,7 @@ babel-plugin-transform-class-properties@^6.24.1: babel-plugin-transform-decorators-legacy@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.5.tgz#0e492dffa0edd70529072887f8aa86d4dd8b40a1" + integrity sha512-jYHwjzRXRelYQ1uGm353zNzf3QmtdCfvJbuYTZ4gKveK7M9H1fs3a5AKdY1JUDl0z97E30ukORW1dzhWvsabtA== dependencies: babel-plugin-syntax-decorators "^6.1.18" babel-runtime "^6.2.0" @@ -1278,18 +1670,21 @@ babel-plugin-transform-decorators-legacy@^1.3.4: babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + integrity sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + integrity sha1-u8UbSflk1wy42OC5ToICRs46YUE= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoping@^6.23.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + integrity sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8= dependencies: babel-runtime "^6.26.0" babel-template "^6.26.0" @@ -1300,6 +1695,7 @@ babel-plugin-transform-es2015-block-scoping@^6.23.0: babel-plugin-transform-es2015-classes@^6.23.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + integrity sha1-WkxYpQyclGHlZLSyo7+ryXolhNs= dependencies: babel-helper-define-map "^6.24.1" babel-helper-function-name "^6.24.1" @@ -1314,6 +1710,7 @@ babel-plugin-transform-es2015-classes@^6.23.0: babel-plugin-transform-es2015-computed-properties@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + integrity sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM= dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" @@ -1321,12 +1718,14 @@ babel-plugin-transform-es2015-computed-properties@^6.22.0: babel-plugin-transform-es2015-destructuring@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + integrity sha1-mXux8auWf2gtKwh2/jWNYOdlxW0= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-duplicate-keys@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + integrity sha1-c+s9MQypaePvnskcU3QabxV2Qj4= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -1334,12 +1733,14 @@ babel-plugin-transform-es2015-duplicate-keys@^6.22.0: babel-plugin-transform-es2015-for-of@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + integrity sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-function-name@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + integrity sha1-g0yJhTvDaxrw86TF26qU/Y6sqos= dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" @@ -1348,12 +1749,14 @@ babel-plugin-transform-es2015-function-name@^6.22.0: babel-plugin-transform-es2015-literals@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + integrity sha1-T1SgLWzWbPkVKAAZox0xklN3yi4= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + integrity sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ= dependencies: babel-plugin-transform-es2015-modules-commonjs "^6.24.1" babel-runtime "^6.22.0" @@ -1362,6 +1765,7 @@ babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015 babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: version "6.26.2" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + integrity sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q== dependencies: babel-plugin-transform-strict-mode "^6.24.1" babel-runtime "^6.26.0" @@ -1371,6 +1775,7 @@ babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-e babel-plugin-transform-es2015-modules-systemjs@^6.23.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + integrity sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM= dependencies: babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" @@ -1379,6 +1784,7 @@ babel-plugin-transform-es2015-modules-systemjs@^6.23.0: babel-plugin-transform-es2015-modules-umd@^6.23.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + integrity sha1-rJl+YoXNGO1hdq22B9YCNErThGg= dependencies: babel-plugin-transform-es2015-modules-amd "^6.24.1" babel-runtime "^6.22.0" @@ -1387,6 +1793,7 @@ babel-plugin-transform-es2015-modules-umd@^6.23.0: babel-plugin-transform-es2015-object-super@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + integrity sha1-JM72muIcuDp/hgPa0CH1cusnj40= dependencies: babel-helper-replace-supers "^6.24.1" babel-runtime "^6.22.0" @@ -1394,6 +1801,7 @@ babel-plugin-transform-es2015-object-super@^6.22.0: babel-plugin-transform-es2015-parameters@^6.23.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + integrity sha1-V6w1GrScrxSpfNE7CfZv3wpiXys= dependencies: babel-helper-call-delegate "^6.24.1" babel-helper-get-function-arity "^6.24.1" @@ -1405,6 +1813,7 @@ babel-plugin-transform-es2015-parameters@^6.23.0: babel-plugin-transform-es2015-shorthand-properties@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + integrity sha1-JPh11nIch2YbvZmkYi5R8U3jiqA= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -1412,12 +1821,14 @@ babel-plugin-transform-es2015-shorthand-properties@^6.22.0: babel-plugin-transform-es2015-spread@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + integrity sha1-1taKmfia7cRTbIGlQujdnxdG+NE= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-sticky-regex@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + integrity sha1-AMHNsaynERLN8M9hJsLta0V8zbw= dependencies: babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" @@ -1426,18 +1837,21 @@ babel-plugin-transform-es2015-sticky-regex@^6.22.0: babel-plugin-transform-es2015-template-literals@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + integrity sha1-qEs0UPfp+PH2g51taH2oS7EjbY0= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-typeof-symbol@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + integrity sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-unicode-regex@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + integrity sha1-04sS9C6nMj9yk4fxinxa4frrNek= dependencies: babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" @@ -1446,6 +1860,7 @@ babel-plugin-transform-es2015-unicode-regex@^6.22.0: babel-plugin-transform-exponentiation-operator@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + integrity sha1-KrDJx/MJj6SJB3cruBP+QejeOg4= dependencies: babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" babel-plugin-syntax-exponentiation-operator "^6.8.0" @@ -1454,12 +1869,14 @@ babel-plugin-transform-exponentiation-operator@^6.22.0: babel-plugin-transform-regenerator@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + integrity sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8= dependencies: regenerator-transform "^0.10.0" babel-plugin-transform-strict-mode@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + integrity sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -1467,6 +1884,7 @@ babel-plugin-transform-strict-mode@^6.24.1: babel-polyfill@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + integrity sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM= dependencies: babel-runtime "^6.26.0" core-js "^2.5.0" @@ -1475,6 +1893,7 @@ babel-polyfill@^6.26.0: babel-preset-env@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" + integrity sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg== dependencies: babel-plugin-check-es2015-constants "^6.22.0" babel-plugin-syntax-trailing-function-commas "^6.22.0" @@ -1510,6 +1929,7 @@ babel-preset-env@^1.7.0: babel-register@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + integrity sha1-btAhFz4vy0htestFxgCahW9kcHE= dependencies: babel-core "^6.26.0" babel-runtime "^6.26.0" @@ -1522,6 +1942,7 @@ babel-register@^6.26.0: babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= dependencies: core-js "^2.4.0" regenerator-runtime "^0.11.0" @@ -1529,6 +1950,7 @@ babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtim babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= dependencies: babel-runtime "^6.26.0" babel-traverse "^6.26.0" @@ -1539,6 +1961,7 @@ babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= dependencies: babel-code-frame "^6.26.0" babel-messages "^6.23.0" @@ -1553,6 +1976,7 @@ babel-traverse@^6.24.1, babel-traverse@^6.26.0: babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= dependencies: babel-runtime "^6.26.0" esutils "^2.0.2" @@ -1562,44 +1986,54 @@ babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: babel6-plugin-strip-class-callcheck@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" + integrity sha1-3oQcGr6705943gr/ssmlLuIo/d8= babel6-plugin-strip-heimdall@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" + integrity sha1-NfgO3ewff//cAJgR371G2ZZQcrY= babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== backbone@^1.1.2: version "1.3.3" resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" + integrity sha1-TMgOp8sWMaxHSInOQPL4vGg7KZk= dependencies: underscore ">=1.8.3" backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= base64-arraybuffer@0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= base64-js@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.2.tgz#024f0f72afa25b75f9c0ee73cd4f55ec1bed9784" + integrity sha1-Ak8Pcq+iW3X5wO5zzU9V7Bvtl4Q= base64id@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY= base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== dependencies: cache-base "^1.0.1" class-utils "^0.3.5" @@ -1612,52 +2046,62 @@ base@^0.11.1: basic-auth@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.0.tgz#015db3f353e02e56377755f962742e8981e7bbba" + integrity sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o= dependencies: safe-buffer "5.1.1" bcrypt-pbkdf@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= dependencies: tweetnacl "^0.14.3" better-assert@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI= dependencies: callsite "1.0.0" "binaryextensions@1 || 2": version "2.1.1" resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" + integrity sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA== bl@~1.0.0: version "1.0.3" resolved "http://registry.npmjs.org/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e" + integrity sha1-/FQhoo/UImA2w7OJGmaiW8ZNIm4= dependencies: readable-stream "~2.0.5" blank-object@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" + integrity sha1-+ZB5P76ajI3QE/syGUIL7IHV9Lk= blob@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" + integrity sha1-vPEwUspURj8w+fx+lbmkdjCpSSE= block-stream@*: version "0.0.9" resolved "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= dependencies: inherits "~2.0.0" bluebird@^3.1.1, bluebird@^3.4.6: version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA== body-parser@1.18.2: version "1.18.2" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" + integrity sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ= dependencies: bytes "3.0.0" content-type "~1.0.4" @@ -1673,6 +2117,7 @@ body-parser@1.18.2: body-parser@1.18.3: version "1.18.3" resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= dependencies: bytes "3.0.0" content-type "~1.0.4" @@ -1688,6 +2133,7 @@ body-parser@1.18.3: body@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" + integrity sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk= dependencies: continuable-cache "^0.3.1" error "^7.0.0" @@ -1697,18 +2143,21 @@ body@^5.1.0: boom@0.4.x: version "0.4.2" resolved "https://registry.yarnpkg.com/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" + integrity sha1-emNune1O/O+xnO9JR6PGffrukRs= dependencies: hoek "0.9.x" boom@2.x.x: version "2.10.1" resolved "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + integrity sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8= dependencies: hoek "2.x.x" bops@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/bops/-/bops-0.0.3.tgz#c5cbf6fea8be7401ca5ea6d1679e6c4e8b407c79" + integrity sha1-xcv2/qi+dAHKXqbRZ55sTotAfHk= dependencies: base64-js "0.0.2" to-utf8 "0.0.1" @@ -1716,6 +2165,7 @@ bops@0.0.3: bower-config@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc" + integrity sha1-hf2d82fCuNu9DKpMXyutQM2Ewsw= dependencies: graceful-fs "^4.1.3" mout "^1.0.0" @@ -1726,10 +2176,12 @@ bower-config@^1.3.0: bower-endpoint-parser@0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" + integrity sha1-ALVlrb+rby01rd3pd+l5Yqy8s/Y= brace-expansion@^1.0.0, brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" @@ -1737,6 +2189,7 @@ brace-expansion@^1.0.0, brace-expansion@^1.1.7: braces@^1.8.2: version "1.8.5" resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= dependencies: expand-range "^1.8.1" preserve "^0.2.0" @@ -1745,6 +2198,7 @@ braces@^1.8.2: braces@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: arr-flatten "^1.1.0" array-unique "^0.3.2" @@ -1760,6 +2214,7 @@ braces@^2.3.1: broccoli-amd-funnel@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/broccoli-amd-funnel/-/broccoli-amd-funnel-2.0.1.tgz#dbdbfd28841731342d538126567c25bea3f15310" + integrity sha512-VRE+0PYAN4jQfkIq3GKRj4U/4UV9rVpLan5ll6fVYV4ziVg4OEfR5GUnILEg++QtR4xSaugRxCPU5XJLDy3bNQ== dependencies: broccoli-plugin "^1.3.0" symlink-or-copy "^1.2.0" @@ -1767,6 +2222,7 @@ broccoli-amd-funnel@^2.0.1: broccoli-babel-transpiler@^6.4.5: version "6.4.5" resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.4.5.tgz#caab4a3b18d2a819fdd56e1ac3a37e8164ad4272" + integrity sha512-HY5KrCdPR8Y86HE8xElmy3ERJpOVzINDR8vgQN2niy++gMERKKOZ3UyFF+cB6ne1ykZ8EYm7yc7yiRGWP341jA== dependencies: babel-core "^6.26.0" broccoli-funnel "^2.0.1" @@ -1782,6 +2238,7 @@ broccoli-babel-transpiler@^6.4.5: broccoli-babel-transpiler@^6.5.0: version "6.5.0" resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.5.0.tgz#aa501a227b298a99742fdd0309b1eaad7124bba0" + integrity sha512-c5OLGY40Sdmv6rP230Jt8yoK49BHfOw1LXiDMu9EC9k2U6sqlpNRK78SzvByQ8IzKtBYUfeWCxeZHcvW+gH7VQ== dependencies: babel-core "^6.26.0" broccoli-funnel "^2.0.1" @@ -1797,6 +2254,7 @@ broccoli-babel-transpiler@^6.5.0: broccoli-babel-transpiler@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.0.0.tgz#bc9d0e93d70d9515b799144b54b0b958e88b6f19" + integrity sha512-EvuExT9MYCW7ulpWdO8+7xLuQYlBNBvjXF5GXrX93aor25eGVCb+xDZe+KWEcd77QMYwnYCezXvF01JRlagBrg== dependencies: "@babel/core" "^7.0.0" broccoli-funnel "^2.0.1" @@ -1812,6 +2270,7 @@ broccoli-babel-transpiler@^7.0.0: broccoli-builder@^0.18.14: version "0.18.14" resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.14.tgz#4b79e2f844de11a4e1b816c3f49c6df4776c312d" + integrity sha1-S3ni+ETeEaThuBbD9Jxt9HdsMS0= dependencies: broccoli-node-info "^1.1.0" heimdalljs "^0.2.0" @@ -1824,6 +2283,7 @@ broccoli-builder@^0.18.14: broccoli-caching-writer@^2.2.0: version "2.3.1" resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" + integrity sha1-uTz1j5Jk8AMHWGjbBXdPTn8lvQc= dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" @@ -1835,6 +2295,7 @@ broccoli-caching-writer@^2.2.0: broccoli-caching-writer@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" + integrity sha1-C9LJapc41qarWQ8HujXFFX19tHY= dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.1" @@ -1846,6 +2307,7 @@ broccoli-caching-writer@^3.0.3: broccoli-caching-writer@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" + integrity sha1-2ZXX0ZdykuSY943wWIcjD8tKXiw= dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" @@ -1859,6 +2321,7 @@ broccoli-caching-writer@~2.0.4: broccoli-clean-css@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" + integrity sha1-nbFD2a9+CuecJuOsWpuy1yDqGfo= dependencies: broccoli-persistent-filter "^1.1.6" clean-css-promise "^0.1.0" @@ -1868,6 +2331,7 @@ broccoli-clean-css@^1.1.0: broccoli-concat@^3.5.1, broccoli-concat@^3.7.3: version "3.7.3" resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-3.7.3.tgz#0dca01311567ffb13180e6b4eb111824628e4885" + integrity sha512-2Ma9h81EJ0PRb9n4sW0i8KZlcnpTQfKxcj87zvi5DFe1fd8CTDEdseHDotK2beuA2l+LbgVPfd8EHaBJKm/Y8g== dependencies: broccoli-debug "^0.6.5" broccoli-kitchen-sink-helpers "^0.3.1" @@ -1885,12 +2349,14 @@ broccoli-concat@^3.5.1, broccoli-concat@^3.7.3: broccoli-config-loader@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/broccoli-config-loader/-/broccoli-config-loader-1.0.1.tgz#d10aaf8ebc0cb45c1da5baa82720e1d88d28c80a" + integrity sha512-MDKYQ50rxhn+g17DYdfzfEM9DjTuSGu42Db37A8TQHQe8geYEcUZ4SQqZRgzdAI3aRQNlA1yBHJfOeGmOjhLIg== dependencies: broccoli-caching-writer "^3.0.3" broccoli-config-replace@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" + integrity sha1-bqh52SpbrWNNETKbUfxfSq/anAA= dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.0" @@ -1900,6 +2366,7 @@ broccoli-config-replace@^1.1.2: broccoli-debug@^0.6.1, broccoli-debug@^0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/broccoli-debug/-/broccoli-debug-0.6.4.tgz#986eb3d2005e00e3bb91f9d0a10ab137210cd150" + integrity sha512-CixMUndBqTljCc26i6ubhBrGbAWXpWBsGJFce6ZOr76Tul2Ev1xxM0tmf7OjSzdYhkr5BrPd/CNbR9VMPi+NBg== dependencies: broccoli-plugin "^1.2.1" fs-tree-diff "^0.5.2" @@ -1911,6 +2378,7 @@ broccoli-debug@^0.6.1, broccoli-debug@^0.6.4: broccoli-debug@^0.6.5: version "0.6.5" resolved "https://registry.npmjs.org/broccoli-debug/-/broccoli-debug-0.6.5.tgz#164a5cdafd8936e525e702bf8f91f39d758e2e78" + integrity sha512-RIVjHvNar9EMCLDW/FggxFRXqpjhncM/3qq87bn/y+/zR9tqEkHvTqbyOc4QnB97NO2m6342w4wGkemkaeOuWg== dependencies: broccoli-plugin "^1.2.1" fs-tree-diff "^0.5.2" @@ -1922,6 +2390,7 @@ broccoli-debug@^0.6.5: broccoli-file-creator@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-1.2.0.tgz#27f1b25b1b00e7bb7bf3d5d7abed5f4d5388df4d" + integrity sha512-l9zthHg6bAtnOfRr/ieZ1srRQEsufMZID7xGYRW3aBDv3u/3Eux+Iawl10tAGYE5pL9YB4n5X4vxkp6iNOoZ9g== dependencies: broccoli-plugin "^1.1.0" mkdirp "^0.5.1" @@ -1929,6 +2398,7 @@ broccoli-file-creator@^1.1.1: broccoli-file-creator@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-2.1.1.tgz#7351dd2496c762cfce7736ce9b49e3fce0c7b7db" + integrity sha512-YpjOExWr92C5vhnK0kmD81kM7U09kdIRZk9w4ZDCDHuHXW+VE/x6AGEOQQW3loBQQ6Jk+k+TSm8dESy4uZsnjw== dependencies: broccoli-plugin "^1.1.0" mkdirp "^0.5.1" @@ -1936,6 +2406,7 @@ broccoli-file-creator@^2.1.1: broccoli-filter@^1.0.1: version "1.3.0" resolved "https://registry.yarnpkg.com/broccoli-filter/-/broccoli-filter-1.3.0.tgz#71e3a8e32a17f309e12261919c5b1006d6766de6" + integrity sha512-VXJXw7eBfG82CFxaBDjYmyN7V72D4In2zwLVQJd/h3mBfF3CMdRTsv2L20lmRTtCv1sAHcB+LgMso90e/KYiLw== dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.0.0" @@ -1950,10 +2421,12 @@ broccoli-filter@^1.0.1: broccoli-funnel-reducer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" + integrity sha1-ETZbKnha7JsXlyo234fu8kxcwOo= broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1: version "1.2.0" resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" + integrity sha1-zdw6/F/xaFqAI0iP/3TOb7WlEpY= dependencies: array-equal "^1.0.0" blank-object "^1.0.1" @@ -1973,6 +2446,7 @@ broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1: broccoli-funnel@^2.0.0, broccoli-funnel@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-2.0.1.tgz#6823c73b675ef78fffa7ab800f083e768b51d449" + integrity sha512-C8Lnp9TVsSSiZMGEF16C0dCiNg2oJqUKwuZ1K4kVC6qRPG/2Cj/rtB5kRCC9qEbwqhX71bDbfHROx0L3J7zXQg== dependencies: array-equal "^1.0.0" blank-object "^1.0.1" @@ -1991,6 +2465,7 @@ broccoli-funnel@^2.0.0, broccoli-funnel@^2.0.1: broccoli-kitchen-sink-helpers@^0.2.5: version "0.2.9" resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" + integrity sha1-peCYbtjXb7WYS2jD8EUNOpbjbsw= dependencies: glob "^5.0.10" mkdirp "^0.5.1" @@ -1998,6 +2473,7 @@ broccoli-kitchen-sink-helpers@^0.2.5: broccoli-kitchen-sink-helpers@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" + integrity sha1-d8fBgZS5ZkFj7E/O4nk0RJJuDAY= dependencies: glob "^5.0.10" mkdirp "^0.5.1" @@ -2005,6 +2481,7 @@ broccoli-kitchen-sink-helpers@^0.3.1: broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.1: version "1.2.4" resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" + integrity sha1-oAFRm7UGfwZYnZGvopQkRaLQ/bU= dependencies: broccoli-plugin "^1.3.0" can-symlink "^1.0.0" @@ -2018,6 +2495,7 @@ broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.1: broccoli-merge-trees@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-2.0.0.tgz#10aea46dd5cebcc8b8f7d5a54f0a84a4f0bb90b9" + integrity sha1-EK6kbdXOvMi499WlTwqEpPC7kLk= dependencies: broccoli-plugin "^1.3.0" merge-trees "^1.0.1" @@ -2025,6 +2503,7 @@ broccoli-merge-trees@^2.0.0: broccoli-merge-trees@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-3.0.0.tgz#90e4959f9e3c57cf1f04fab35152f3d849468d8b" + integrity sha512-yyk4J3KSeohlzsmVaRx7ZgAq57K2wzyVtGDaARLG/WuTNlRjKeYEW+atxblvrf0zAOsYMOi8YCpMLRBQUa9jjg== dependencies: broccoli-plugin "^1.3.0" merge-trees "^2.0.0" @@ -2032,6 +2511,7 @@ broccoli-merge-trees@^3.0.0: broccoli-merge-trees@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-3.0.1.tgz#545dfe9f695cec43372b3ee7e63c7203713ea554" + integrity sha512-EFPBLbCoyCLdjJx0lxn+acWXK/GAZesXokS4OsF7HuB+WdnV76HVJPdfwp9TaXaUkrtb7eU+ymh9tY9wOGQjMQ== dependencies: broccoli-plugin "^1.3.0" merge-trees "^2.0.0" @@ -2039,6 +2519,7 @@ broccoli-merge-trees@^3.0.1: broccoli-middleware@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-2.0.1.tgz#093314f13e52fad7fa8c4254a4e4a4560c857a65" + integrity sha512-V/K5uozcEH/XJ09ZAL8aJt/W2UwJU8I8fA2FAg3u9gzs5dQrehHDtgSoKS2QjPjurRC1GSiYLcsMp36sezaQQg== dependencies: handlebars "^4.0.4" mime-types "^2.1.18" @@ -2046,6 +2527,7 @@ broccoli-middleware@^2.0.1: broccoli-module-normalizer@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/broccoli-module-normalizer/-/broccoli-module-normalizer-1.3.0.tgz#f9982d9cbb776b4ed754161cc6547784d3eb19de" + integrity sha512-0idZCOtdVG6xXoQ36Psc1ApMCr3lW5DB+WEAOEwHcUoESIBHzwcRPQTxheGIjZ5o0hxpsRYAUH5x0ErtNezbrQ== dependencies: broccoli-plugin "^1.3.0" merge-trees "^1.0.1" @@ -2055,6 +2537,7 @@ broccoli-module-normalizer@^1.3.0: broccoli-module-unification-reexporter@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/broccoli-module-unification-reexporter/-/broccoli-module-unification-reexporter-1.0.0.tgz#031909c5d3f159ec11d5f9e2346f2861db8acb3e" + integrity sha512-HTi9ua520M20aBZomaiBopsSt3yjL7J/paR3XPjieygK7+ShATBiZdn0B+ZPiniBi4I8JuMn1q0fNFUevtP//A== dependencies: broccoli-plugin "^1.3.0" mkdirp "^0.5.1" @@ -2063,10 +2546,12 @@ broccoli-module-unification-reexporter@^1.0.0: broccoli-node-info@1.1.0, broccoli-node-info@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" + integrity sha1-OqLjHgflvbUW3SUhT3xFuhxFlBI= broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz#3511bc52fc53740cda51621f58a28152d9911bc1" + integrity sha512-JwNLDvvXJlhUmr+CHcbVhCyp33NbCIAITjQZmJY9e8QzANXh3jpFWlhSFvkWghwKA8rTAKcXkW12agtiZjxr4g== dependencies: async-disk-cache "^1.2.1" async-promise-queue "^1.0.3" @@ -2085,6 +2570,7 @@ broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-p broccoli-plugin@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" + integrity sha1-c+LPoF+OoeP8FCDEDD2efcckvwI= dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -2094,6 +2580,7 @@ broccoli-plugin@1.1.0: broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" + integrity sha1-vucEqOQtoIy1jlE6qkNu+38O8e4= dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -2103,6 +2590,7 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli broccoli-rollup@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/broccoli-rollup/-/broccoli-rollup-2.1.1.tgz#0b77dc4b7560a53e998ea85f3b56772612d4988d" + integrity sha512-aky/Ovg5DbsrsJEx2QCXxHLA6ZR+9u1TNVTf85soP4gL8CjGGKQ/JU8R3BZ2ntkWzo6/83RCKzX6O+nlNKR5MQ== dependencies: "@types/node" "^9.6.0" amd-name-resolver "^1.2.0" @@ -2119,16 +2607,19 @@ broccoli-rollup@^2.1.1: broccoli-slow-trees@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" + integrity sha1-m/Kp4vjrPtOj8qvd6YjaQ3zNybQ= dependencies: heimdalljs "^0.2.1" broccoli-source@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" + integrity sha1-VPDoLItz9GWAy7xPV48LMvyo+Ak= broccoli-sri-hash@^2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" + integrity sha1-vGmQXtejga0yXMDQLe0HEyjr8/M= dependencies: broccoli-caching-writer "^2.2.0" mkdirp "^0.5.1" @@ -2139,6 +2630,7 @@ broccoli-sri-hash@^2.1.0: broccoli-stew@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-2.0.0.tgz#68f3d94f13b4a79aa15d582703574fb4c3215e50" + integrity sha512-9dtyFlWEYHI36e4wXNTo6JReCaCssx+Jq1GpkTQZaJA/2buJn+HeGzguoYPdR2VKNb3vX13fpWJFQP0TAwa7WA== dependencies: broccoli-debug "^0.6.1" broccoli-funnel "^2.0.0" @@ -2158,6 +2650,7 @@ broccoli-stew@^2.0.0: broccoli-string-replace@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" + integrity sha1-HtkvhWgK+NUDAjkl51Tk4zZ2uR8= dependencies: broccoli-persistent-filter "^1.1.5" minimatch "^3.0.3" @@ -2165,6 +2658,7 @@ broccoli-string-replace@^0.1.2: broccoli-test-helper@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/broccoli-test-helper/-/broccoli-test-helper-2.0.0.tgz#1cfbb76f7e856ad8df96d55ee2f5e0dddddf5d4f" + integrity sha512-TKwh8dBT+RcxKEG+vAoaRRhZsCMwZIHPZbCzBNCA0nUi1aoFB/LVosqwMC6H9Ipe06FxY5hpQxDLFbnBMdUPsA== dependencies: "@types/tmp" "^0.0.33" broccoli "^2.0.0" @@ -2176,6 +2670,7 @@ broccoli-test-helper@^2.0.0: broccoli-uglify-sourcemap@^2.1.1, broccoli-uglify-sourcemap@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-2.2.0.tgz#2ff49389bdf342a550c3596750ba2dde95a8f7d4" + integrity sha1-L/STib3zQqVQw1lnULot3pWo99Q= dependencies: async-promise-queue "^1.0.4" broccoli-plugin "^1.2.1" @@ -2192,6 +2687,7 @@ broccoli-uglify-sourcemap@^2.1.1, broccoli-uglify-sourcemap@^2.2.0: broccoli@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/broccoli/-/broccoli-2.0.0.tgz#7b95d6173865184697e4dab9f477591057b9410e" + integrity sha512-gCS1/nXaJpATboLpNeTPOgdqSSEauJ6bUS4+fNKNsf/m7CIxOS9MclT7DNn3VI9DARiGZxFi6hZmIEF1mD04eA== dependencies: broccoli-node-info "1.1.0" broccoli-slow-trees "^3.0.1" @@ -2215,10 +2711,12 @@ broccoli@^2.0.0: browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== browserslist@^3.2.6: version "3.2.8" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" + integrity sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ== dependencies: caniuse-lite "^1.0.30000844" electron-to-chromium "^1.3.47" @@ -2226,6 +2724,7 @@ browserslist@^3.2.6: browserslist@^4.1.0: version "4.3.3" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.3.3.tgz#88a7d9ce2e5db561e160ab660bc59cb406a0c41d" + integrity sha512-6h84UD1mmHeuQ9IucX6yzBc+KBYcBBTLYt2CXtY7GYCra6iE5kOm7oM+zuGw/0tjGtbJxjm58OvxSBmogEMCRQ== dependencies: caniuse-lite "^1.0.30000898" electron-to-chromium "^1.3.81" @@ -2234,16 +2733,19 @@ browserslist@^4.1.0: bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" + integrity sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk= dependencies: node-int64 "^0.4.0" buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== buffer-alloc@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== dependencies: buffer-alloc-unsafe "^1.1.0" buffer-fill "^1.0.0" @@ -2251,34 +2753,42 @@ buffer-alloc@^1.2.0: buffer-fill@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= buffer-from@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" + integrity sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ== builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= builtins@0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/builtins/-/builtins-0.0.7.tgz#355219cd6cf18dbe7c01cc7fd2dce765cfdc549a" + integrity sha1-NVIZzWzxjb58Acx/0tznZc/cVJo= builtins@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= bytes@1: version "1.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" + integrity sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g= bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== dependencies: collection-visit "^1.0.0" component-emitter "^1.2.1" @@ -2293,6 +2803,7 @@ cache-base@^1.0.1: cacheable-request@^2.1.1: version "2.1.4" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" + integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= dependencies: clone-response "1.0.2" get-stream "3.0.0" @@ -2305,26 +2816,31 @@ cacheable-request@^2.1.1: calculate-cache-key-for-tree@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" + integrity sha1-DD5CycE088neU1jA8WeTYn6pdtY= dependencies: json-stable-stringify "^1.0.1" caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8= dependencies: callsites "^0.2.0" callsite@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= callsites@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo= camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= dependencies: camelcase "^2.0.0" map-obj "^1.0.0" @@ -2332,38 +2848,46 @@ camelcase-keys@^2.0.0: camelcase@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk= camelcase@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= can-symlink@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" + integrity sha1-l7YH2KhLtsbiKLkC2GTstZS50hk= dependencies: tmp "0.0.28" caniuse-lite@^1.0.30000844: version "1.0.30000865" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000865.tgz#70026616e8afe6e1442f8bb4e1092987d81a2f25" + integrity sha512-vs79o1mOSKRGv/1pSkp4EXgl4ZviWeYReXw60XfacPU64uQWZwJT6vZNmxRF9O+6zu71sJwMxLK5JXxbzuVrLw== caniuse-lite@^1.0.30000898: version "1.0.30000899" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000899.tgz#6febdbbc388a7982f620ee0e3d09aab0c061389e" + integrity sha512-enC3zKfUCJxxwvUIsBkbHd54CtJw1KtIWvrK0JZxWD/fEN2knHaai45lndJ4xXAkyRAPyk60J3yagkKDWhfeMA== capture-exit@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" + integrity sha1-HF/MSJ/QqwDU8ax64QcuMXP7q28= dependencies: rsvp "^3.3.3" capture-stack-trace@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" + integrity sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0= cardinal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" + integrity sha1-UOIcGwqjdyn5N33vGWtanOyTLuk= dependencies: ansicolors "~0.2.1" redeyed "~1.0.0" @@ -2371,14 +2895,17 @@ cardinal@^1.0.0: caseless@~0.11.0: version "0.11.0" resolved "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + integrity sha1-cVuW6phBWTzDMGeSP17GDr2k99c= caseless@~0.12.0: version "0.12.0" resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= center-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60= dependencies: align-text "^0.1.3" lazy-cache "^1.0.3" @@ -2386,24 +2913,28 @@ center-align@^0.1.1: chai-as-promised@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" + integrity sha1-GgKkM6byTa+sY7nJb6FoTbGqjaY= dependencies: check-error "^1.0.2" chai-as-promised@^7.0.0: version "7.1.1" resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" + integrity sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA== dependencies: check-error "^1.0.2" chai-files@^1.0.0, chai-files@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" + integrity sha1-DiVhD63FUbHq55wvTuefry+EIpY= dependencies: assertion-error "^1.0.1" chai@^3.3.0: version "3.5.0" resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" + integrity sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc= dependencies: assertion-error "^1.0.1" deep-eql "^0.1.3" @@ -2412,6 +2943,7 @@ chai@^3.3.0: chai@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c" + integrity sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw= dependencies: assertion-error "^1.0.1" check-error "^1.0.1" @@ -2423,6 +2955,7 @@ chai@^4.1.0: chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -2433,6 +2966,7 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" @@ -2441,32 +2975,39 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4 chardet@^0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== charm@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" + integrity sha1-it02cVOm2aWBMxBSxAkJkdqZXjU= dependencies: inherits "^2.0.1" check-error@^1.0.1, check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= chownr@^1.0.1, chownr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + integrity sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE= ci-info@^1.1.3: version "1.6.0" resolved "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" + integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" + integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== dependencies: arr-union "^3.1.0" define-property "^0.2.5" @@ -2476,10 +3017,12 @@ class-utils@^0.3.5: clean-base-url@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" + integrity sha1-yQHPCiC5ckNbDszVLQVoJKQ1G3s= clean-css-promise@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" + integrity sha1-Q/PSyN/LK/BxSBJSzZt2QzwI7ss= dependencies: array-to-error "^1.0.0" clean-css "^3.4.5" @@ -2488,6 +3031,7 @@ clean-css-promise@^0.1.0: clean-css@^3.4.5: version "3.4.28" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" + integrity sha1-vxlF6C/ICPVWlebd6uwBQA79A/8= dependencies: commander "2.8.x" source-map "0.4.x" @@ -2495,26 +3039,31 @@ clean-css@^3.4.5: clean-up-path@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clean-up-path/-/clean-up-path-1.0.0.tgz#de9e8196519912e749c9eaf67c13d64fac72a3e5" + integrity sha512-PHGlEF0Z6976qQyN6gM7kKH6EH0RdfZcc8V+QhFe36eRxV0SMH5OUBZG7Bxa9YcreNzyNbK63cGiZxdSZgosRw== cli-cursor@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + integrity sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc= dependencies: restore-cursor "^1.0.1" cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= dependencies: restore-cursor "^2.0.0" cli-spinners@^1.1.0: version "1.3.1" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" + integrity sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg== cli-table3@^0.5.1: version "0.5.1" resolved "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" + integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== dependencies: object-assign "^4.1.0" string-width "^2.1.1" @@ -2524,16 +3073,19 @@ cli-table3@^0.5.1: cli-table@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM= dependencies: colors "1.0.3" cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= cliui@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE= dependencies: center-align "^0.1.1" right-align "^0.1.1" @@ -2542,24 +3094,29 @@ cliui@^2.1.0: clone-response@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= dependencies: mimic-response "^1.0.0" clone@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= clone@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" + integrity sha1-0hfR6WERjjrJpLi7oyhVU79kfNs= clone@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= cmd-shim@~2.0.1: version "2.0.2" resolved "https://registry.npmjs.org/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb" + integrity sha1-b8vamUg6j9FdfTChlspp1oii79s= dependencies: graceful-fs "^4.1.2" mkdirp "~0.5.0" @@ -2567,14 +3124,17 @@ cmd-shim@~2.0.1: co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= dependencies: map-visit "^1.0.0" object-visit "^1.0.0" @@ -2582,24 +3142,29 @@ collection-visit@^1.0.0: color-convert@^1.9.0: version "1.9.2" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" + integrity sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg== dependencies: color-name "1.1.1" color-name@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" + integrity sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok= colors@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= colors@^1.1.2: version "1.3.1" resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.1.tgz#4accdb89cf2cabc7f982771925e9468784f32f3d" + integrity sha512-jg/vxRmv430jixZrC+La5kMbUWqIg32/JsYNZb94+JEmzceYbWKTsv1OuTp+7EaqiaWRR2tPcykibwCRgclIsw== columnify@~1.5.4: version "1.5.4" resolved "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" + integrity sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs= dependencies: strip-ansi "^3.0.0" wcwidth "^1.0.0" @@ -2607,66 +3172,80 @@ columnify@~1.5.4: combined-stream@^1.0.5, combined-stream@^1.0.6, combined-stream@~1.0.5, combined-stream@~1.0.6: version "1.0.7" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" + integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== dependencies: delayed-stream "~1.0.0" combined-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" + integrity sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8= dependencies: delayed-stream "0.0.5" commander@2.12.2: version "2.12.2" resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" + integrity sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA== commander@2.15.1: version "2.15.1" resolved "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" + integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== commander@2.8.x: version "2.8.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + integrity sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ= dependencies: graceful-readlink ">= 1.0.0" commander@^2.15.1, commander@^2.9.0: version "2.19.0" resolved "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" + integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== commander@^2.6.0, commander@~2.16.0: version "2.16.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" + integrity sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew== commander@~2.17.1: version "2.17.1" resolved "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== common-tags@^1.4.0, common-tags@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" + integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw== component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= component-emitter@1.2.1, component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= component-inherit@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= compressible@~2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7" + integrity sha1-MmxfUH+7BV9UEWeCuWmoG2einac= dependencies: mime-db ">= 1.34.0 < 2" compression@^1.7.3: version "1.7.3" resolved "https://registry.npmjs.org/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" + integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg== dependencies: accepts "~1.3.5" bytes "3.0.0" @@ -2679,10 +3258,12 @@ compression@^1.7.3: concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= concat-stream@^1.4.6, concat-stream@^1.4.7: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== dependencies: buffer-from "^1.0.0" inherits "^2.0.3" @@ -2692,6 +3273,7 @@ concat-stream@^1.4.6, concat-stream@^1.4.7: config-chain@~1.1.9: version "1.1.12" resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" + integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== dependencies: ini "^1.3.4" proto-list "~1.2.1" @@ -2699,6 +3281,7 @@ config-chain@~1.1.9: configstore@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz#5933311e95d3687efb592c528b922d9262d227e7" + integrity sha512-CmquAXFBocrzaSM8mtGPMM/HiWmyIpr4CcJl/rgY2uCObZ/S7cKU0silxslqJejl+t/T9HS8E0PUNQD81JGUEQ== dependencies: dot-prop "^4.1.0" graceful-fs "^4.1.2" @@ -2710,6 +3293,7 @@ configstore@^4.0.0: connect@^3.6.6: version "3.6.6" resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" + integrity sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ= dependencies: debug "2.6.9" finalhandler "1.1.0" @@ -2719,10 +3303,12 @@ connect@^3.6.6: console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= console-ui@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-2.2.2.tgz#b294a2934de869dd06789ab4be69555411edef29" + integrity sha1-spSik03oad0GeJq0vmlVVBHt7yk= dependencies: chalk "^2.1.0" inquirer "^2" @@ -2734,70 +3320,94 @@ console-ui@^2.2.2: consolidate@^0.15.1: version "0.15.1" resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7" + integrity sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw== dependencies: bluebird "^3.1.1" content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== continuable-cache@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" + integrity sha1-vXJ6f67XfnH/OYWskzUakSczrQ8= convert-source-map@^1.1.0: version "1.6.0" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" + integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== dependencies: safe-buffer "~5.1.1" convert-source-map@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" + integrity sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU= cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= copy-dereference@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" + integrity sha1-axMYZUIP2BtBO6mUtE02VTERUrY= copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.7: version "2.5.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" + integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw== core-object@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/core-object/-/core-object-3.1.5.tgz#fa627b87502adc98045e44678e9a8ec3b9c0d2a9" + integrity sha512-sA2/4+/PZ/KV6CKgjrVrrUVBKCkdDO02CUlQ0YKTQoYUwPYNOtOAcWlbYhd5v/1JqYaA6oZ4sDlOU4ppVw6Wbg== dependencies: chalk "^2.0.0" core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= create-error-class@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" + integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y= dependencies: capture-stack-trace "^1.0.0" +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== dependencies: nice-try "^1.0.4" path-key "^2.0.1" @@ -2808,116 +3418,138 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: cryptiles@0.2.x: version "0.2.2" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" + integrity sha1-7ZH/HxetE9N0gohZT4pIoNJvMlw= dependencies: boom "0.4.x" cryptiles@2.x.x: version "2.0.5" resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + integrity sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g= dependencies: boom "2.x.x" crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= ctype@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" + integrity sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8= currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= dependencies: array-find-index "^1.0.1" d@1: version "1.0.0" resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + integrity sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8= dependencies: es5-ext "^0.10.9" dag-map@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" + integrity sha1-lxS0ct6CoYQ94vuptodpOMq0TGg= dashdash@^1.12.0: version "1.14.1" resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= dependencies: assert-plus "^1.0.0" date-time@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/date-time/-/date-time-2.1.0.tgz#0286d1b4c769633b3ca13e1e62558d2dbdc2eba2" + integrity sha512-/9+C44X7lot0IeiyfgJmETtRMhBidBYM2QFFIkGa0U1k+hSyY87Nw7PY3eDqpvCBm7I3WCSfPeZskW/YYq6m4g== dependencies: time-zone "^1.0.0" debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" debug@3.1.0, debug@^3.0.0, debug@^3.1.0, debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== dependencies: ms "2.0.0" -debug@^4.0.1: +debug@^4.0.1, debug@^4.1.0: version "4.1.0" - resolved "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" + integrity sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg== dependencies: ms "^2.1.1" debuglog@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" + integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= decamelize@^1.0.0, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= decompress-response@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= dependencies: mimic-response "^1.0.0" deep-eql@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" + integrity sha1-71WKyrjeJSBs1xOQbXTlaTDrafI= dependencies: type-detect "0.1.1" deep-eql@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== dependencies: type-detect "^4.0.0" deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= defaults@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= dependencies: clone "^1.0.2" define-properties@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + integrity sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ= dependencies: foreach "^2.0.5" object-keys "^1.0.8" @@ -2925,18 +3557,21 @@ define-properties@^1.1.2: define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= dependencies: is-descriptor "^1.0.0" define-property@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== dependencies: is-descriptor "^1.0.2" isobject "^3.0.1" @@ -2944,6 +3579,7 @@ define-property@^2.0.2: del@^2.0.2: version "2.2.2" resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + integrity sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag= dependencies: globby "^5.0.0" is-path-cwd "^1.0.0" @@ -2956,48 +3592,59 @@ del@^2.0.2: delayed-stream@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" + integrity sha1-1LH0OpPoKW3+AmlPRoC8N6MTxz8= delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= depd@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + integrity sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k= depd@~1.1.1, depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= detect-file@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= detect-indent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg= dependencies: repeating "^2.0.0" detect-indent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" + integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= dezalgo@^1.0.0, dezalgo@^1.0.1, dezalgo@^1.0.2, dezalgo@~1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" + integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= dependencies: asap "^2.0.0" wrappy "1" @@ -3005,30 +3652,36 @@ dezalgo@^1.0.0, dezalgo@^1.0.1, dezalgo@^1.0.2, dezalgo@~1.0.3: diff@3.5.0, diff@^3.5.0: version "3.5.0" resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== dependencies: esutils "^2.0.2" dot-prop@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== dependencies: is-obj "^1.0.0" duplex@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/duplex/-/duplex-1.0.0.tgz#6abc5c16ec17e4c578578727126700590d3a2dda" + integrity sha1-arxcFuwX5MV4V4cnEmcAWQ06Ldo= duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= dependencies: jsbn "~0.1.0" safer-buffer "^2.1.0" @@ -3036,26 +3689,32 @@ ecc-jsbn@~0.1.1: editions@^1.1.1: version "1.3.4" resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" + integrity sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg== editor@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" + integrity sha1-YMf4e9YrzGqJT6jM1q+3gjok90I= ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= electron-to-chromium@^1.3.47: version "1.3.52" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz#d2d9f1270ba4a3b967b831c40ef71fb4d9ab5ce0" + integrity sha1-0tnxJwuko7lnuDHEDvcftNmrXOA= electron-to-chromium@^1.3.81: version "1.3.82" resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.82.tgz#7d13ae4437d2a783de3f4efba96b186c540b67b1" + integrity sha512-NI4nB2IWGcU4JVT1AE8kBb/dFor4zjLHMLsOROPahppeHrR0FG5uslxMmkp/thO1MvPjM2xhlKoY29/I60s0ew== ember-assign-polyfill@~2.4.0: version "2.4.0" resolved "https://registry.npmjs.org/ember-assign-polyfill/-/ember-assign-polyfill-2.4.0.tgz#acb00466f7d674b3e6b030acfe255b3b1f6472e1" + integrity sha512-0SnGQb9CenRqbZdIa1KFsEjT+1ijGWfAbCSaDbg5uVa5l6HPdppuTzOXK6sfEQMsd2nbrp27QWFy7W5VX6l4Ag== dependencies: ember-cli-babel "^6.6.0" ember-cli-version-checker "^2.0.0" @@ -3063,6 +3722,7 @@ ember-assign-polyfill@~2.4.0: ember-cli-app-version@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-3.2.0.tgz#7b9ad0e1b63ae0518648356ee24c703e922bc26e" + integrity sha512-fHWOJElSw8JL03FNCHrT0RdWhGpWEQ4VQ10unEwwhVZ+OANNcOLz8O2dA3D5iuB4bb0fMLwjEwYZGM62+TBs1Q== dependencies: ember-cli-babel "^6.12.0" git-repo-version "^1.0.2" @@ -3070,10 +3730,12 @@ ember-cli-app-version@^3.2.0: ember-cli-babel-plugin-helpers@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/ember-cli-babel-plugin-helpers/-/ember-cli-babel-plugin-helpers-1.0.2.tgz#d4bec0f32febc530e621ea8d66d3365727cb5e6c" + integrity sha512-tTWmHiIvadgtu0i+Zlb5Jnue69qO6dtACcddkRhhV+m9NfAr+2XNoTKRSeGL8QyRDhfWeo4rsK9dqPrU4PQ+8g== ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: version "6.16.0" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.16.0.tgz#623b4a2764ece72b65f1572fc8aeb5714a450228" + integrity sha512-rzWkVdKVk2KSbQ81TxmLli+LWdBEqF+FHE83rUQXVOV4FguJDtP1w2AW08f8QjuztbnQ5+VUGCb7H0dL8UwOVw== dependencies: amd-name-resolver "1.2.0" babel-plugin-debug-macros "^0.2.0-beta.6" @@ -3092,6 +3754,7 @@ ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-be ember-cli-babel@^7.1.2: version "7.1.2" resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-7.1.2.tgz#543c64368d6138d12656db1143c02df1f2b0ee9c" + integrity sha512-VEWn1jYlP0XYUNkMG4wHSpq4IPKO04lIuSwnH0elLwV3RcwbUstRExi3slmax+SjtlgjJTPMko8QvQ/Ul1/4rg== dependencies: "@babel/core" "^7.0.0" "@babel/plugin-transform-modules-amd" "^7.0.0" @@ -3113,6 +3776,7 @@ ember-cli-babel@^7.1.2: ember-cli-blueprint-test-helpers@^0.19.1: version "0.19.1" resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.19.1.tgz#26df9724a6cb48f7acfa391dec7ec772888b0929" + integrity sha512-lyfCvR5gxbNn5mJKfVAUj3Q5K1VyJo3miAaQ9zk2dL7ijs281C3j73WYyCK7tWBoBJ04jOzkb+YXV6jFwVpvsA== dependencies: chai "^4.1.0" chai-as-promised "^7.0.0" @@ -3126,6 +3790,7 @@ ember-cli-blueprint-test-helpers@^0.19.1: ember-cli-broccoli-sane-watcher@^2.1.1: version "2.2.2" resolved "https://registry.npmjs.org/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.2.2.tgz#9bb1b04ddeb2c086aecd8693cbaeca1d88dc160c" + integrity sha512-9OLy8x3pdNKC/6xR00IjTL8XyiQU3rb2HLyQSAqHuaZpZcSTKkbAse2ERTsELSINoo/zi/W7qPP5vd5SsHsraw== dependencies: broccoli-slow-trees "^3.0.1" heimdalljs "^0.2.1" @@ -3136,6 +3801,7 @@ ember-cli-broccoli-sane-watcher@^2.1.1: ember-cli-dependency-checker@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ember-cli-dependency-checker/-/ember-cli-dependency-checker-3.0.0.tgz#61245f5f79f881dece043303111d5f41efb8621f" + integrity sha512-Fq9PXFaZfpSHssJwt20cpHMT0AKHMKMBMGiz+Y8BsIvvY1ILaM5bzpUP8V6czm0RU5y7VxM+z7zTN9Cn1iotOA== dependencies: chalk "^2.3.0" find-yarn-workspace-root "^1.1.0" @@ -3146,10 +3812,12 @@ ember-cli-dependency-checker@^3.0.0: ember-cli-get-component-path-option@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" + integrity sha1-DXtZVVni+QUKvtgE8djv8bCLx3E= ember-cli-htmlbars-inline-precompile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.3.tgz#332ff96c06fc522965162f1090d78a615379c3c2" + integrity sha1-My/5bAb8UillFi8QkNeKYVN5w8I= dependencies: babel-plugin-htmlbars-inline-precompile "^0.2.5" ember-cli-version-checker "^2.1.2" @@ -3160,6 +3828,7 @@ ember-cli-htmlbars-inline-precompile@^1.0.0: ember-cli-htmlbars-inline-precompile@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.5.tgz#312e050c9e3dd301c55fb399fd706296cd0b1d6a" + integrity sha512-/CNEqPxroIcbY6qejrt704ZaghHLCntZKYLizFfJ2esirXoJx6fuYKBY1YyJ8GOgjfbHHKjBZuK4vFFJpkGqkQ== dependencies: babel-plugin-htmlbars-inline-precompile "^0.2.5" ember-cli-version-checker "^2.1.2" @@ -3170,6 +3839,7 @@ ember-cli-htmlbars-inline-precompile@^1.0.5: ember-cli-htmlbars@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-3.0.1.tgz#01e21f0fd05e0a6489154f26614b1041769e3e58" + integrity sha512-pyyB2s52vKTXDC5svU3IjU7GRLg2+5O81o9Ui0ZSiBS14US/bZl46H2dwcdSJAK+T+Za36ZkQM9eh1rNwOxfoA== dependencies: broccoli-persistent-filter "^1.4.3" hash-for-dep "^1.2.3" @@ -3179,6 +3849,7 @@ ember-cli-htmlbars@^3.0.1: ember-cli-inject-live-reload@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-2.0.1.tgz#1bf3a6ea1747bceddc9f62f7ca8575de6b53ddaf" + integrity sha512-vrW/3KSrku+Prqmp7ZkpCxYkabnLrTHDEvV9B1yphTP++dhiV7n7Dv9NrmyubkoF3Inm0xrbbhB5mScvvuTQSg== dependencies: clean-base-url "^1.0.0" ember-cli-version-checker "^2.1.2" @@ -3186,6 +3857,7 @@ ember-cli-inject-live-reload@^2.0.1: ember-cli-internal-test-helpers@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.9.1.tgz#d54a9124bb6408ceba83f049ba8479f4b96cdd19" + integrity sha1-1UqRJLtkCM66g/BJuoR59Lls3Rk= dependencies: chai "^3.3.0" chai-as-promised "^6.0.0" @@ -3203,28 +3875,34 @@ ember-cli-internal-test-helpers@^0.9.1: ember-cli-is-package-missing@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" + integrity sha1-bmGEyvuSY13ZPKbJRrEEKS1OM5A= ember-cli-lodash-subset@^1.0.7: version "1.0.12" resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" + integrity sha1-ry5366XcsNd/MwjTpv19NFD25Tc= ember-cli-lodash-subset@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-2.0.1.tgz#20cb68a790fe0fde2488ddfd8efbb7df6fe766f2" + integrity sha1-IMtop5D+D94kiN39jvu332/nZvI= ember-cli-normalize-entity-name@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" + integrity sha1-CxT3vLxZmqEXtf3cgeT9A8S61bc= dependencies: silent-error "^1.0.0" ember-cli-path-utils@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" + integrity sha1-Tjmvi1UwHN3FAXc5t3qAT7ogce0= ember-cli-preprocess-registry@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.2.tgz#083efb21fd922c021ceba9e08f4d9278249fc4db" + integrity sha512-YJfcDHMBEjtD505CIhM8dtu5FO2Ku+0OTs/0kdLlj9mhXlbzC+k0JAS5c/0AQ+Nh2f+qZZJ8G19ySdzWwTLSCQ== dependencies: broccoli-clean-css "^1.1.0" broccoli-funnel "^1.0.0" @@ -3237,6 +3915,7 @@ ember-cli-preprocess-registry@^3.1.2: ember-cli-pretender@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-3.0.0.tgz#dcaf772332a1e6b0fc91e4b9a7e793a1283c85ac" + integrity sha512-WpcXEiAStYFrPUfy6RElkm9EcJFjRAdD6LmMFoORG/fLjcWZya/pMSemzykZpCPMjMLHabR5ltmfvUjb4MR1ZQ== dependencies: "@xg-wang/whatwg-fetch" "^3.0.0" abortcontroller-polyfill "^1.1.9" @@ -3251,6 +3930,7 @@ ember-cli-pretender@^3.0.0: ember-cli-release@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.npmjs.org/ember-cli-release/-/ember-cli-release-1.0.0-beta.2.tgz#cb72d341293e94a1a8bcf4b73f7a6396f5b7e0c5" + integrity sha1-y3LTQSk+lKGovPS3P3pjlvW34MU= dependencies: chalk "^1.0.0" git-tools "^0.1.4" @@ -3267,6 +3947,7 @@ ember-cli-release@^1.0.0-beta.2: ember-cli-shims@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/ember-cli-shims/-/ember-cli-shims-1.2.0.tgz#0f53aff0aab80b5f29da3a9731bac56169dd941f" + integrity sha1-D1Ov8Kq4C18p2jqXMbrFYWndlB8= dependencies: broccoli-file-creator "^1.1.1" broccoli-merge-trees "^2.0.0" @@ -3277,28 +3958,72 @@ ember-cli-shims@^1.2.0: ember-cli-sri@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" + integrity sha1-lxYgk0pLkYPPeSPMA+F4uDqpB/0= dependencies: broccoli-sri-hash "^2.1.0" ember-cli-string-utils@^1.0.0, ember-cli-string-utils@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" + integrity sha1-ObZ3/CgF9VFzc1N2/O8njqpEUqE= ember-cli-test-info@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" + integrity sha1-7U6WDySel1I8+JHkrtIHLOhFd7Q= dependencies: ember-cli-string-utils "^1.0.0" ember-cli-test-loader@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/ember-cli-test-loader/-/ember-cli-test-loader-2.2.0.tgz#3fb8d5d1357e4460d3f0a092f5375e71b6f7c243" + integrity sha512-mlSXX9SciIRwGkFTX6XGyJYp4ry6oCFZRxh5jJ7VH8UXLTNx2ZACtDTwaWtNhYrWXgKyiDUvmD8enD56aePWRA== dependencies: ember-cli-babel "^6.8.1" +ember-cli-typescript-blueprints@^2.0.0-beta.1: + version "2.0.0-beta.1" + resolved "https://registry.yarnpkg.com/ember-cli-typescript-blueprints/-/ember-cli-typescript-blueprints-2.0.0-beta.1.tgz#2db2e34ad01b5a50a4459c2f7cfc8f132b21fcea" + integrity sha512-tU1hN9Wj/nzWrSArogr/n9j8kfsv+2wueRuaIr7X+h4klb/Vb92bVkyW1xx8SW9hsWkv8n7ct8PzMmW033ws8g== + dependencies: + chalk "^2.4.1" + ember-cli-babel "^6.6.0" + ember-cli-get-component-path-option "^1.0.0" + ember-cli-is-package-missing "^1.0.0" + ember-cli-normalize-entity-name "^1.0.0" + ember-cli-path-utils "^1.0.0" + ember-cli-string-utils "^1.1.0" + ember-cli-test-info "^1.0.0" + ember-cli-valid-component-name "^1.0.0" + ember-cli-version-checker "^2.1.2" + ember-router-generator "^1.2.3" + exists-sync "^0.1.0" + fs-extra "^7.0.0" + inflection "^1.12.0" + silent-error "^1.1.0" + +ember-cli-typescript@^2.0.0-beta.2: + version "2.0.0-beta.2" + resolved "https://registry.yarnpkg.com/ember-cli-typescript/-/ember-cli-typescript-2.0.0-beta.2.tgz#29bd0a7eff45b54e01d2cbc2fba05b3991a9c0d3" + integrity sha512-Wxopeo/ShTO7P9ja+CYwXM6+tww2kSMJFHCEFemWjB+tFR0318Pqa7EEYJ/lHAkIjE214B13A/qsWwhIGf3zxw== + dependencies: + "@babel/plugin-proposal-class-properties" "^7.1.0" + "@babel/plugin-transform-typescript" "^7.1.0" + ansi-to-html "^0.6.6" + debug "^3.1.0" + ember-cli-babel-plugin-helpers "^1.0.0" + execa "^0.9.0" + fs-extra "^5.0.0" + resolve "^1.5.0" + rsvp "^4.8.1" + semver "^5.5.1" + stagehand "^1.0.0" + walk-sync "^0.3.2" + ember-cli-uglify@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ember-cli-uglify/-/ember-cli-uglify-2.1.0.tgz#4a0641fe4768d7ab7d4807aca9924cc77c544184" + integrity sha512-lDzdAUfhGx5AMBsgyR54ibENVp/LRQuHNWNaP2SDjkAXDyuYFgW0iXIAfGbxF6+nYaesJ9Tr9AKOfTPlwxZDSg== dependencies: broccoli-uglify-sourcemap "^2.1.1" lodash.defaultsdeep "^4.6.0" @@ -3306,12 +4031,14 @@ ember-cli-uglify@2.1.0: ember-cli-valid-component-name@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" + integrity sha1-cVUM44fgIzBl8wswsVEKot++h+8= dependencies: silent-error "^1.0.0" ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-version-checker@^2.1.1, ember-cli-version-checker@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.1.2.tgz#305ce102390c66e4e0f1432dea9dc5c7c19fed98" + integrity sha512-sjkHGr4IGXnO3EUcY21380Xo9Qf6bC8HWH4D62bVnrQop/8uha5XgMQRoAflMCeH6suMrezQL287JUoYc2smEw== dependencies: resolve "^1.3.3" semver "^5.3.0" @@ -3319,6 +4046,7 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-ve ember-cli-yuidoc@^0.8.8: version "0.8.8" resolved "https://registry.yarnpkg.com/ember-cli-yuidoc/-/ember-cli-yuidoc-0.8.8.tgz#3858baaf85388a976024f9de40f1075fea58f606" + integrity sha1-OFi6r4U4ipdgJPneQPEHX+pY9gY= dependencies: broccoli-caching-writer "~2.0.4" broccoli-merge-trees "^1.1.1" @@ -3329,6 +4057,7 @@ ember-cli-yuidoc@^0.8.8: ember-cli@^3.5.0: version "3.5.0" resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-3.5.0.tgz#978031042611008dce82c79226b8b677d325072c" + integrity sha512-AW5eb1SG7szuSnai3CIPL9fE7eyPQS2oycyDZAGLs+An57ytK9lm1NFQWqXm3nGnvdSh1AIsoCwc683tISUozQ== dependencies: amd-name-resolver "^1.2.0" babel-plugin-transform-es2015-modules-amd "^6.24.1" @@ -3423,6 +4152,7 @@ ember-cli@^3.5.0: ember-compatibility-helpers@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.0.2.tgz#a7eb8969747d063720fe44658af5448589b437ba" + integrity sha512-pN1ezLiAM+uIKI4/BMp2hIBi6LQKxOedxKcu2mHDK+HEYuhlwki8Y2YwFSwb1w3c2YhesbkwaAJx/dvNHQGq5g== dependencies: babel-plugin-debug-macros "^0.1.11" ember-cli-version-checker "^2.1.1" @@ -3431,6 +4161,7 @@ ember-compatibility-helpers@^1.0.0: ember-compatibility-helpers@^1.1.1: version "1.1.2" resolved "https://registry.npmjs.org/ember-compatibility-helpers/-/ember-compatibility-helpers-1.1.2.tgz#ae0ee4a7a2858b5ffdf79b428c23aee85c47d93d" + integrity sha512-yN163MzERpotO8M0b+q+kXs4i3Nx6aIriiZHWv+yXQzr2TAtYlVwg9V7/3+jcurOa3oDEYDpN7y9UZ6q3mnoTg== dependencies: babel-plugin-debug-macros "^0.2.0" ember-cli-version-checker "^2.1.1" @@ -3439,6 +4170,7 @@ ember-compatibility-helpers@^1.1.1: ember-decorators@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/ember-decorators/-/ember-decorators-3.0.0.tgz#23cee0ebea3f86806cd15b638bf5ffb40870ccf4" + integrity sha512-+ELAcA5ExbXVStb3AUrqEGrH303CrbcwNfaHVe9pKxK5RxQwQmHBSLHMTOoYsObYlCgpIxhhT6WKHOn3LeYlvA== dependencies: "@ember-decorators/component" "^3.0.0" "@ember-decorators/controller" "^3.0.0" @@ -3451,28 +4183,33 @@ ember-decorators@^3.0.0: ember-disable-prototype-extensions@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" + integrity sha1-GWkTUhdlS14nj5/i2dTkm1cgMp4= ember-export-application-global@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ember-export-application-global/-/ember-export-application-global-2.0.0.tgz#8d6d7619ac8a1a3f8c43003549eb21ebed685bd2" + integrity sha1-jW12GayKGj+MQwA1Sesh6+1oW9I= dependencies: ember-cli-babel "^6.0.0-beta.7" ember-inflector@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ember-inflector/-/ember-inflector-3.0.0.tgz#7e1ee8aaa0fa773ba0905d8b7c0786354d890ee1" + integrity sha512-tLWfYolZAkLnkTvvBkjizy4Wmj8yI8wqHZFK+leh0iScHiC3r1Yh5C4qO+OMGiBTMLwfTy+YqVoE/Nu3hGNkcA== dependencies: ember-cli-babel "^6.6.0" ember-load-initializers@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ember-load-initializers/-/ember-load-initializers-1.1.0.tgz#4edacc0f3a14d9f53d241ac3e5561804c8377978" + integrity sha512-WiciFi8IXOqjyJ65M4iBNIthqcy4uXXQq5n3WxeMMhvJVk5JNSd9hynNECNz3nqfEYuZQ9c04UWkmFIQXRfl4Q== dependencies: ember-cli-babel "^6.6.0" ember-maybe-import-regenerator@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ember-maybe-import-regenerator/-/ember-maybe-import-regenerator-0.1.6.tgz#35d41828afa6d6a59bc0da3ce47f34c573d776ca" + integrity sha1-NdQYKK+m1qWbwNo85H80xXPXdso= dependencies: broccoli-funnel "^1.0.1" broccoli-merge-trees "^1.0.0" @@ -3482,6 +4219,7 @@ ember-maybe-import-regenerator@^0.1.6: ember-qunit-assert-helpers@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ember-qunit-assert-helpers/-/ember-qunit-assert-helpers-0.2.1.tgz#4a77f8ff252e47cc53db6fa7fb4becb426de8d29" + integrity sha512-3h7jdwp/Lzpri04hrSzUz0hguzzF7ldnCEb+tB+5MianGiFusYjPEu8QsUqJ6BhzXlljyX+pmMVyNe7HL6lsjA== dependencies: broccoli-filter "^1.0.1" ember-cli-babel "^6.9.0" @@ -3489,6 +4227,7 @@ ember-qunit-assert-helpers@^0.2.1: ember-qunit@^3.5.3: version "3.5.3" resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-3.5.3.tgz#bfd0bff8298c78c77e870cca43fe0826e78a0d09" + integrity sha512-FmXsI1bGsZ5th25x4KEle2fLCVURTptsQODfBt+Pg8tk9rX7y79cqny91PrhtkhE+giZ8p029tnq94SdpJ4ojg== dependencies: "@ember/test-helpers" "^0.7.26" broccoli-funnel "^2.0.1" @@ -3501,6 +4240,7 @@ ember-qunit@^3.5.3: ember-resolver@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-5.0.1.tgz#21740b92e1e4a65f94018de22aa1c73434dc3b2f" + integrity sha512-Svhs/eseIVQ6Yik+4mFpixT639FREZW2UkIYo7197bRuSL63tofKDMfE+gOXUSSudQlQSaFHFeKDr9oD+0C2GQ== dependencies: "@glimmer/resolver" "^0.4.1" babel-plugin-debug-macros "^0.1.10" @@ -3513,26 +4253,31 @@ ember-resolver@^5.0.1: ember-rfc176-data@^0.3.0, ember-rfc176-data@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.3.tgz#27fba08d540a7463a4366c48eaa19c5a44971a39" + integrity sha1-J/ugjVQKdGOkNmxI6qGcWkSXGjk= ember-rfc176-data@^0.3.5: version "0.3.5" resolved "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.3.5.tgz#f630e550572c81a5e5c7220f864c0f06eee9e977" + integrity sha512-5NfL1iTkIQDYs16/IZ7/jWCEglNsUrigLelBkBMsNcib9T3XzQwmhhVTjoSsk66s57LmWJ1bQu+2c1CAyYCV7A== ember-router-generator@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" + integrity sha1-jtLKhv8yM2MSD8FCeBkeno8TFe4= dependencies: recast "^0.11.3" ember-source-channel-url@^1.0.1, ember-source-channel-url@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ember-source-channel-url/-/ember-source-channel-url-1.1.0.tgz#73de5cc6ebc25b2120e932ec1d8f82677bfaf6ef" + integrity sha512-y1RVXmyqrdX6zq9ZejpPt7ohKNGuLMBEKaOUyxFWcYAM5gvLuo6xFerwNmXEBbu4e3//GaoasjodXi6Cl+ddUQ== dependencies: got "^8.0.1" ember-source@~3.5.0: version "3.5.0" resolved "https://registry.npmjs.org/ember-source/-/ember-source-3.5.0.tgz#2322e393125684e1e043d0eedad8fd79c6de78a8" + integrity sha512-q7GAQZI1NAxMdgqxJGKsOgmwFAmvSet33Ub5C/Cn5bkQYWlAgjR7oKiP0DlHTFSbiwmGnZZF9a/sHB7W/XIjPg== dependencies: broccoli-funnel "^2.0.1" broccoli-merge-trees "^2.0.0" @@ -3552,6 +4297,7 @@ ember-source@~3.5.0: ember-try-config@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ember-try-config/-/ember-try-config-3.0.0.tgz#012d8c90cae9eb624e2b62040bf7e76a1aa58edc" + integrity sha512-pNwHS29O1ACczkrxBKRtDY0TzTb7uPnA5eHEe+4NF6qpLK5FVnL3EtgZ8+yVYtnm1If5mZ07rIubw45vaSek7w== dependencies: ember-source-channel-url "^1.0.1" lodash "^4.6.1" @@ -3563,6 +4309,7 @@ ember-try-config@^3.0.0: ember-try@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/ember-try/-/ember-try-1.1.0.tgz#194d5843a79b5a9fc0e4c07445ebc18c08a91e78" + integrity sha512-NL1rKPz2LuyVEqwoNV+SQD4c2w1/A0rrdeT6jqTYqlt/P7y3+SWcsxyReBnImebaIu7Drtz6p9yiAsrJq5Chyg== dependencies: chalk "^2.3.0" cli-table3 "^0.5.1" @@ -3581,20 +4328,24 @@ ember-try@^1.1.0: emit-function@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/emit-function/-/emit-function-0.0.2.tgz#e3a50b3d61be1bf8ca88b924bf713157a5bec124" + integrity sha1-46ULPWG+G/jKiLkkv3ExV6W+wSQ= encodeurl@~1.0.1, encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= end-of-stream@^1.1.0: version "1.4.1" resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== dependencies: once "^1.4.0" engine.io-client@~3.2.0: version "3.2.1" resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" + integrity sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw== dependencies: component-emitter "1.2.1" component-inherit "0.0.3" @@ -3611,6 +4362,7 @@ engine.io-client@~3.2.0: engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196" + integrity sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw== dependencies: after "0.8.2" arraybuffer.slice "~0.0.7" @@ -3621,6 +4373,7 @@ engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: engine.io@~3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.0.tgz#54332506f42f2edc71690d2f2a42349359f3bf7d" + integrity sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw== dependencies: accepts "~1.3.4" base64id "1.0.0" @@ -3632,20 +4385,29 @@ engine.io@~3.2.0: ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" + integrity sha1-pls+QtC3HPxYXrd0+ZQ8jZuRsMI= + +entities@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA= error-ex@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" error@^7.0.0: version "7.0.2" resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" + integrity sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI= dependencies: string-template "~0.2.1" xtend "~4.0.0" @@ -3653,6 +4415,7 @@ error@^7.0.0: es-abstract@^1.9.0: version "1.12.0" resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" + integrity sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA== dependencies: es-to-primitive "^1.1.1" function-bind "^1.1.1" @@ -3663,6 +4426,7 @@ es-abstract@^1.9.0: es-to-primitive@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + integrity sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0= dependencies: is-callable "^1.1.1" is-date-object "^1.0.1" @@ -3671,6 +4435,7 @@ es-to-primitive@^1.1.1: es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: version "0.10.45" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.45.tgz#0bfdf7b473da5919d5adf3bd25ceb754fccc3653" + integrity sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ== dependencies: es6-iterator "~2.0.3" es6-symbol "~3.1.1" @@ -3679,6 +4444,7 @@ es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: es6-iterator@~2.0.1, es6-iterator@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= dependencies: d "1" es5-ext "^0.10.35" @@ -3687,6 +4453,7 @@ es6-iterator@~2.0.1, es6-iterator@~2.0.3: es6-map@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" + integrity sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA= dependencies: d "1" es5-ext "~0.10.14" @@ -3698,6 +4465,7 @@ es6-map@^0.1.5: es6-set@~0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" + integrity sha1-0rPsXU2ADO2BjbU40ol02wpzzLE= dependencies: d "1" es5-ext "~0.10.14" @@ -3708,6 +4476,7 @@ es6-set@~0.1.5: es6-symbol@3.1.1, es6-symbol@^3.0.2, es6-symbol@^3.1.1, es6-symbol@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + integrity sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc= dependencies: d "1" es5-ext "~0.10.14" @@ -3715,20 +4484,24 @@ es6-symbol@3.1.1, es6-symbol@^3.0.2, es6-symbol@^3.1.1, es6-symbol@~3.1.1: escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= eslint-config-prettier@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-3.1.0.tgz#2c26d2cdcfa3a05f0642cd7e6e4ef3316cdabfa2" + integrity sha512-QYGfmzuc4q4J6XIhlp8vRKdI/fI0tQfQPy1dME3UOLprE+v4ssH/3W9LM2Q7h5qBcy5m0ehCrBDU2YF8q6OY8w== dependencies: get-stdin "^6.0.0" eslint-plugin-es@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-1.3.1.tgz#5acb2565db4434803d1d46a9b4cbc94b345bd028" + integrity sha512-9XcVyZiQRVeFjqHw8qHNDAZcQLqaHlOGGpeYqzYh8S4JYCWTCO3yzyen8yVmA5PratfzTRWDwCOFphtDEG+w/w== dependencies: eslint-utils "^1.3.0" regexpp "^2.0.0" @@ -3736,6 +4509,7 @@ eslint-plugin-es@^1.3.1: eslint-plugin-node@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-7.0.1.tgz#a6e054e50199b2edd85518b89b4e7b323c9f36db" + integrity sha512-lfVw3TEqThwq0j2Ba/Ckn2ABdwmL5dkOgAux1rvOk6CO7A6yGyPI2+zIxN6FyNkp1X1X/BSvKOceD6mBWSj4Yw== dependencies: eslint-plugin-es "^1.3.1" eslint-utils "^1.3.1" @@ -3747,12 +4521,14 @@ eslint-plugin-node@^7.0.1: eslint-plugin-prettier@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.0.tgz#f6b823e065f8c36529918cdb766d7a0e975ec30c" + integrity sha512-4g11opzhqq/8+AMmo5Vc2Gn7z9alZ4JqrbZ+D4i8KlSyxeQhZHlmIrY8U9Akf514MoEhogPa87Jgkq87aZ2Ohw== dependencies: prettier-linter-helpers "^1.0.0" eslint-scope@3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + integrity sha1-PWPD7f2gLgbgGkUq2IyqzHzctug= dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" @@ -3760,6 +4536,7 @@ eslint-scope@3.7.1: eslint-scope@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" + integrity sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA== dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" @@ -3767,14 +4544,17 @@ eslint-scope@^4.0.0: eslint-utils@^1.3.0, eslint-utils@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" + integrity sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q== eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== eslint@^5.7.0: version "5.7.0" resolved "https://registry.npmjs.org/eslint/-/eslint-5.7.0.tgz#55c326d6fb2ad45fcbd0ce17c3846f025d1d819c" + integrity sha512-zYCeFQahsxffGl87U2aJ7DPyH8CbWgxBC213Y8+TCanhUTf2gEvfq3EKpHmEcozTLyPmGe9LZdMAwC/CpJBM5A== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.5.3" @@ -3818,6 +4598,7 @@ eslint@^5.7.0: espree@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/espree/-/espree-4.0.0.tgz#253998f20a0f82db5d866385799d912a83a36634" + integrity sha512-kapdTCt1bjmspxStVKX6huolXVV5ZfyZguY1lcfhVVZstce3bqxH9mcLzNn3/mlgW6wQ732+0fuG9v7h0ZQoKg== dependencies: acorn "^5.6.0" acorn-jsx "^4.1.1" @@ -3825,50 +4606,61 @@ espree@^4.0.0: esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esprima@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" + integrity sha1-U88kes2ncxPlUcOqLnM0LT+099k= esprima@~3.1.0: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= esprimaq@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" + integrity sha1-PqOkH1W6CrmPw1ZMh1gYvYkKoqM= esquery@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== dependencies: estraverse "^4.0.0" esrecurse@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== dependencies: estraverse "^4.1.0" estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= estree-walker@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.5.2.tgz#d3850be7529c9580d815600b53126515e146dd39" + integrity sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig== esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= event-emitter@~0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= dependencies: d "1" es5-ext "~0.10.14" @@ -3876,14 +4668,17 @@ event-emitter@~0.3.5: eventemitter3@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" + integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA== events-to-array@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" + integrity sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y= exec-file-sync@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/exec-file-sync/-/exec-file-sync-2.0.2.tgz#58d441db46e40de6d1f30de5be022785bd89e328" + integrity sha1-WNRB20bkDebR8w3lvgInhb2J4yg= dependencies: is-obj "^1.0.0" object-assign "^4.0.1" @@ -3892,12 +4687,14 @@ exec-file-sync@^2.0.0: exec-sh@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" + integrity sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== dependencies: merge "^1.2.0" execa@^0.10.0: version "0.10.0" resolved "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== dependencies: cross-spawn "^6.0.0" get-stream "^3.0.0" @@ -3907,9 +4704,23 @@ execa@^0.10.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +execa@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.9.0.tgz#adb7ce62cf985071f60580deb4a88b9e34712d01" + integrity sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA== + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + execa@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== dependencies: cross-spawn "^6.0.0" get-stream "^4.0.0" @@ -3922,32 +4733,44 @@ execa@^1.0.0: exists-stat@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/exists-stat/-/exists-stat-1.0.0.tgz#0660e3525a2e89d9e446129440c272edfa24b529" + integrity sha1-BmDjUlouidnkRhKUQMJy7foktSk= exists-sync@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" + integrity sha1-uRAAC+27ETs3i4L19adjgQdiLc8= exists-sync@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" + integrity sha1-l0TCxCjMA7AQYNtFTUsS8O88iHk= + +exists-sync@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.1.0.tgz#318d545213d2b2a31499e92c35f74c94196a22f7" + integrity sha512-qEfFekfBVid4b14FNug/RNY1nv+BADnlzKGHulc+t6ZLqGY4kdHGh1iFha8lnE3sJU/1WzMzKRNxS6EvSakJUg== exit-hook@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + integrity sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g= exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= dependencies: is-posix-bracket "^0.1.0" expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= dependencies: debug "^2.3.3" define-property "^0.2.5" @@ -3960,18 +4783,21 @@ expand-brackets@^2.1.4: expand-range@^1.8.1: version "1.8.2" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= dependencies: fill-range "^2.1.0" expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= dependencies: homedir-polyfill "^1.0.1" express@^4.10.7, express@^4.13.1: version "4.16.3" resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" + integrity sha1-avilAjUNsyRuzEvs9rWjTSL37VM= dependencies: accepts "~1.3.5" array-flatten "1.1.1" @@ -4007,6 +4833,7 @@ express@^4.10.7, express@^4.13.1: express@^4.16.3: version "4.16.4" resolved "https://registry.npmjs.org/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" + integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== dependencies: accepts "~1.3.5" array-flatten "1.1.1" @@ -4042,12 +4869,14 @@ express@^4.16.3: extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= dependencies: assign-symbols "^1.0.0" is-extendable "^1.0.1" @@ -4055,10 +4884,12 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: extend@^3.0.0, extend@~3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== external-editor@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" + integrity sha1-Etew24UPf/fnCBuvQAVwAGDEYAs= dependencies: extend "^3.0.0" spawn-sync "^1.0.15" @@ -4067,6 +4898,7 @@ external-editor@^1.1.0: external-editor@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" + integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== dependencies: chardet "^0.7.0" iconv-lite "^0.4.24" @@ -4075,12 +4907,14 @@ external-editor@^3.0.0: extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= dependencies: is-extglob "^1.0.0" extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== dependencies: array-unique "^0.3.2" define-property "^1.0.0" @@ -4094,44 +4928,54 @@ extglob@^2.0.4: extsprintf@1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= fake-xml-http-request@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-2.0.0.tgz#41a92f0ca539477700cb1dafd2df251d55dac8ff" + integrity sha512-UjNnynb6eLAB0lyh2PlTEkjRJORnNsVF1hbzU+PQv89/cyBV9GDRCy7JAcLQgeCLYT+3kaumWWZKEJvbaK74eQ== fast-deep-equal@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= fast-diff@^1.1.2: version "1.2.0" resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" + integrity sha1-P7s2Y097555PftvbSjV97iXRhOs= dependencies: blank-object "^1.0.1" fast-sourcemap-concat@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/fast-sourcemap-concat/-/fast-sourcemap-concat-1.4.0.tgz#122c330d4a2afaff16ad143bc9674b87cd76c8ad" + integrity sha512-x90Wlx/2C83lfyg7h4oguTZN4MyaVfaiUSJQNpU+YEA0Odf9u659Opo44b0LfoVg9G/bOE++GdID/dkyja+XcA== dependencies: chalk "^2.0.0" fs-extra "^5.0.0" @@ -4145,24 +4989,28 @@ fast-sourcemap-concat@^1.4.0: faye-websocket@~0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= dependencies: websocket-driver ">=0.5.1" fb-watchman@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + integrity sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg= dependencies: bser "^2.0.0" figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= dependencies: escape-string-regexp "^1.0.5" file-entry-cache@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E= dependencies: flat-cache "^1.2.1" object-assign "^4.0.1" @@ -4170,14 +5018,17 @@ file-entry-cache@^2.0.0: filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= filesize@^3.6.1: version "3.6.1" resolved "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" + integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== fill-range@^2.1.0: version "2.2.4" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== dependencies: is-number "^2.1.0" isobject "^2.0.0" @@ -4188,6 +5039,7 @@ fill-range@^2.1.0: fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= dependencies: extend-shallow "^2.0.1" is-number "^3.0.0" @@ -4197,6 +5049,7 @@ fill-range@^4.0.0: finalhandler@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" + integrity sha1-zgtoVbRYU+eRsvzGgARtiCU91/U= dependencies: debug "2.6.9" encodeurl "~1.0.1" @@ -4209,6 +5062,7 @@ finalhandler@1.1.0: finalhandler@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== dependencies: debug "2.6.9" encodeurl "~1.0.2" @@ -4221,6 +5075,7 @@ finalhandler@1.1.1: find-babel-config@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.1.0.tgz#acc01043a6749fec34429be6b64f542ebb5d6355" + integrity sha1-rMAQQ6Z0n+w0Qpvmtk9ULrtdY1U= dependencies: json5 "^0.5.1" path-exists "^3.0.0" @@ -4228,10 +5083,12 @@ find-babel-config@^1.1.0: find-index@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" + integrity sha1-UwB8ec0wBA1oFteUWOiDfVxXBe8= find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" @@ -4239,18 +5096,21 @@ find-up@^1.0.0: find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= dependencies: locate-path "^2.0.0" find-up@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== dependencies: locate-path "^3.0.0" find-yarn-workspace-root@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-1.1.0.tgz#9817b6748cb90719f4dc37b4538bb200c697356f" + integrity sha512-Ete1eGKj7EEcbIyKCOZDIVvANKmBma5kCB+pOLnHFQzfn98QdQ2UEw+9yFkciOoPScuj2O7vUswIrBdI2ueAAw== dependencies: fs-extra "^4.0.3" micromatch "^3.1.4" @@ -4258,6 +5118,7 @@ find-yarn-workspace-root@^1.1.0: findup-sync@2.0.0, findup-sync@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" + integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw= dependencies: detect-file "^1.0.0" is-glob "^3.1.0" @@ -4267,6 +5128,7 @@ findup-sync@2.0.0, findup-sync@^2.0.0: fireworm@^0.7.0: version "0.7.1" resolved "https://registry.yarnpkg.com/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" + integrity sha1-zPIPeUHxCIg/zduZOD2+bhhhx1g= dependencies: async "~0.2.9" is-type "0.0.1" @@ -4277,6 +5139,7 @@ fireworm@^0.7.0: fixturify-project@^1.5.3: version "1.5.3" resolved "https://registry.npmjs.org/fixturify-project/-/fixturify-project-1.5.3.tgz#2ba4ffec59c1d79ae6638f818c0847eb974d179b" + integrity sha512-vgH+Uo+pC6jHg7mt+FDz+j08bKFugnP6guBWeumYllQDbvxT7NQ/sf6zO4nC0XKRRsSNWsOHkO0AppaHvwF69A== dependencies: fixturify "^0.3.4" tmp "^0.0.33" @@ -4284,6 +5147,7 @@ fixturify-project@^1.5.3: fixturify@^0.3.2, fixturify@^0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/fixturify/-/fixturify-0.3.4.tgz#c676de404a7f8ee8e64d0b76118e62ec95ab7b25" + integrity sha512-Gx+KSB25b6gMc4bf7UFRTA85uE0iZR+RYur0JHh6dg4AGBh0EksOv4FCHyM7XpGmiJO7Bc7oV7vxENQBT+2WEQ== dependencies: fs-extra "^0.30.0" matcher-collection "^1.0.4" @@ -4291,6 +5155,7 @@ fixturify@^0.3.2, fixturify@^0.3.4: flat-cache@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" + integrity sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE= dependencies: circular-json "^0.3.1" del "^2.0.2" @@ -4300,34 +5165,41 @@ flat-cache@^1.2.1: follow-redirects@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.1.tgz#67a8f14f5a1f67f962c2c46469c79eaec0a90291" + integrity sha512-v9GI1hpaqq1ZZR6pBD1+kI7O24PhDvNGNodjS3MdcEqyrahCp8zbtpv+2B/krUnSmUH80lbAS7MrdeK5IylgKg== dependencies: debug "^3.1.0" for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= for-own@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= dependencies: for-in "^1.0.1" foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= forever-agent@~0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" + integrity sha1-bQ4JxJIflKJ/Y9O0nF/v8epMUTA= forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= form-data@~0.1.0: version "0.1.4" resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" + integrity sha1-kavXiKupcCsaq/qLwBAxoqyeOxI= dependencies: async "~0.9.0" combined-stream "~0.0.4" @@ -4336,6 +5208,7 @@ form-data@~0.1.0: form-data@~1.0.0-rc3: version "1.0.1" resolved "http://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" + integrity sha1-rjFduaSQf6BlUCMEpm13M0de43w= dependencies: async "^2.0.1" combined-stream "^1.0.5" @@ -4344,6 +5217,7 @@ form-data@~1.0.0-rc3: form-data@~2.3.2: version "2.3.3" resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== dependencies: asynckit "^0.4.0" combined-stream "^1.0.6" @@ -4352,20 +5226,24 @@ form-data@~2.3.2: forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= dependencies: map-cache "^0.2.2" fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= from2@^2.1.1: version "2.3.0" resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= dependencies: inherits "^2.0.1" readable-stream "^2.0.0" @@ -4373,6 +5251,7 @@ from2@^2.1.1: fs-extra@^0.24.0: version "0.24.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" + integrity sha1-1OQ0KpZnXLeEZjOmCZJJMytTmVI= dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -4382,6 +5261,7 @@ fs-extra@^0.24.0: fs-extra@^0.30.0: version "0.30.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + integrity sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A= dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -4392,6 +5272,7 @@ fs-extra@^0.30.0: fs-extra@^4.0.2, fs-extra@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -4400,6 +5281,7 @@ fs-extra@^4.0.2, fs-extra@^4.0.3: fs-extra@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" + integrity sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ== dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -4408,6 +5290,7 @@ fs-extra@^5.0.0: fs-extra@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b" + integrity sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA== dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -4416,6 +5299,7 @@ fs-extra@^6.0.1: fs-extra@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.0.tgz#8cc3f47ce07ef7b3593a11b9fb245f7e34c041d6" + integrity sha512-EglNDLRpmaTWiD/qraZn6HREAEAHJcJOmxNEYwq6xeMKnVMAy3GUcFB+wXt2C6k4CNvB/mP1y/U3dzvKKj5OtQ== dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -4424,12 +5308,14 @@ fs-extra@^7.0.0: fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== dependencies: minipass "^2.2.1" fs-sync@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" + integrity sha1-L5Tq3jGGLsCp8zocJUbfsaPz0a4= dependencies: glob "^7.1.0" iconv-lite "^0.4.13" @@ -4440,6 +5326,7 @@ fs-sync@^1.0.4: fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6, fs-tree-diff@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-0.5.7.tgz#315e2b098d5fe7f622880ac965b1b051868ac871" + integrity sha512-dJwDX6NBH7IfdfFjZAdHCZ6fIKc8LwR7kzqUhYRFJuX4g9ctG/7cuqJuwegGQsyLEykp6Z4krq+yIFMQlt7d9Q== dependencies: heimdalljs-logger "^0.1.7" object-assign "^4.1.0" @@ -4449,6 +5336,7 @@ fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5 fs-tree-diff@^0.5.9: version "0.5.9" resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.9.tgz#a4ec6182c2f5bd80b9b83c8e23e4522e6f5fd946" + integrity sha512-872G8ax0kHh01m9n/2KDzgYwouKza0Ad9iFltBpNykvROvf2AGtoOzPJgGx125aolGPER3JuC7uZFrQ7bG1AZw== dependencies: heimdalljs-logger "^0.1.7" object-assign "^4.1.0" @@ -4458,6 +5346,7 @@ fs-tree-diff@^0.5.9: fs-updater@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/fs-updater/-/fs-updater-1.0.4.tgz#2329980f99ae9176e9a0e84f7637538a182ce63b" + integrity sha512-0pJX4mJF/qLsNEwTct8CdnnRdagfb+LmjRPJ8sO+nCnAZLW0cTmz4rTgU25n+RvTuWSITiLKrGVJceJPBIPlKg== dependencies: can-symlink "^1.0.0" clean-up-path "^1.0.0" @@ -4468,6 +5357,7 @@ fs-updater@^1.0.4: fs-vacuum@~1.2.7: version "1.2.10" resolved "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36" + integrity sha1-t2Kb7AekAxolSP35n17PHMizHjY= dependencies: graceful-fs "^4.1.2" path-is-inside "^1.0.1" @@ -4476,6 +5366,7 @@ fs-vacuum@~1.2.7: fs-write-stream-atomic@~1.0.8: version "1.0.10" resolved "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= dependencies: graceful-fs "^4.1.2" iferr "^0.1.5" @@ -4485,10 +5376,12 @@ fs-write-stream-atomic@~1.0.8: fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fsevents@^1.2.3: version "1.2.4" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== dependencies: nan "^2.9.2" node-pre-gyp "^0.10.0" @@ -4496,6 +5389,7 @@ fsevents@^1.2.3: fstream-ignore@^1.0.0: version "1.0.5" resolved "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + integrity sha1-nDHa40dnAY/h0kmyTa2mfQktoQU= dependencies: fstream "^1.0.0" inherits "2" @@ -4504,6 +5398,7 @@ fstream-ignore@^1.0.0: fstream-npm@~1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/fstream-npm/-/fstream-npm-1.0.7.tgz#7ed0d1ac13d7686dd9e1bf6ceb8be273bf6d2f86" + integrity sha1-ftDRrBPXaG3Z4b9s64vic79tL4Y= dependencies: fstream-ignore "^1.0.0" inherits "2" @@ -4511,6 +5406,7 @@ fstream-npm@~1.0.7: fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.8: version "1.0.11" resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= dependencies: graceful-fs "^4.1.2" inherits "~2.0.0" @@ -4520,14 +5416,17 @@ fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.8: function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= gauge@~1.2.0, gauge@~1.2.5: version "1.2.7" resolved "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz#e9cec5483d3d4ee0ef44b60a7d99e4935e136d93" + integrity sha1-6c7FSD09TuDvRLYKfZnkk14TbZM= dependencies: ansi "^0.3.0" has-unicode "^2.0.0" @@ -4538,6 +5437,7 @@ gauge@~1.2.0, gauge@~1.2.5: gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -4551,54 +5451,65 @@ gauge@~2.7.3: generate-function@^2.0.0: version "2.3.1" resolved "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" + integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== dependencies: is-property "^1.0.2" generate-object-property@^1.1.0: version "1.2.0" resolved "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + integrity sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA= dependencies: is-property "^1.0.0" get-caller-file@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== get-func-name@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= get-stdin@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" + integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= get-stream@^4.0.0: version "4.1.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== dependencies: pump "^3.0.0" get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= getpass@^0.1.1: version "0.1.7" resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= dependencies: assert-plus "^1.0.0" git-fetch-pack@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/git-fetch-pack/-/git-fetch-pack-0.1.1.tgz#7703a32cf0db80f060d2766a34ac00d02cebcdf5" + integrity sha1-dwOjLPDbgPBg0nZqNKwA0CzrzfU= dependencies: bops "0.0.3" emit-function "0.0.2" @@ -4608,6 +5519,7 @@ git-fetch-pack@^0.1.1: git-packed-ref-parse@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/git-packed-ref-parse/-/git-packed-ref-parse-0.0.0.tgz#b85046931f3e4a65679b5de54af3a5d3df372646" + integrity sha1-uFBGkx8+SmVnm13lSvOl0983JkY= dependencies: line-stream "0.0.0" through "~2.2.7" @@ -4615,6 +5527,7 @@ git-packed-ref-parse@0.0.0: git-read-pkt-line@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/git-read-pkt-line/-/git-read-pkt-line-0.0.8.tgz#494037854ed57bd90cd55676540d86ab0cb36caa" + integrity sha1-SUA3hU7Ve9kM1VZ2VA2GqwyzbKo= dependencies: bops "0.0.3" through "~2.2.7" @@ -4622,32 +5535,38 @@ git-read-pkt-line@0.0.8: git-repo-info@^1.0.4, git-repo-info@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" + integrity sha1-KgcoIyVKr2L88HZgB9e2ZRvUGUM= git-repo-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-2.0.0.tgz#2e7a68ba3d0253e8e885c4138f922e6561de59bb" + integrity sha512-5wiwo0Pert7y8YtAC6Gym+ekeKojBospUEaQIPjK/djKvmONk7ZDpM986Q2OP5LEuwlmOom9Ji0XsGe78EFBeQ== git-repo-version@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-0.2.0.tgz#9a1d0019a50fc9e623c43d1c0fcc437391207d0d" + integrity sha1-mh0AGaUPyeYjxD0cD8xDc5EgfQ0= dependencies: git-repo-info "^1.0.4" git-repo-version@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-1.0.2.tgz#2c8e9bee5d970cafc0dd58480f9dc56d9afe8e4f" + integrity sha512-OPtwtHx9E8/rTMcWT+BU6GNj6Kq/O40bHJZaZAGy+pN2RXGmeKcfr0ix4M+SQuFY8vl5L/wfPSGOAtvUT/e3Qg== dependencies: git-repo-info "^1.4.1" git-tools@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" + integrity sha1-XkPllEO4pd7bOdumY9pJ55+UOXg= dependencies: spawnback "~1.0.0" git-transport-protocol@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/git-transport-protocol/-/git-transport-protocol-0.1.0.tgz#99f4dd6389b9161eded74a9e617d6ba5ed0a6c2c" + integrity sha1-mfTdY4m5Fh7e10qeYX1rpe0KbCw= dependencies: duplex "~1.0.0" emit-function "0.0.2" @@ -4658,6 +5577,7 @@ git-transport-protocol@^0.1.0: git-write-pkt-line@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/git-write-pkt-line/-/git-write-pkt-line-0.1.0.tgz#a84c1856c09011908389b2f06f911d91f6394694" + integrity sha1-qEwYVsCQEZCDibLwb5EdkfY5RpQ= dependencies: bops "0.0.3" through "~2.2.7" @@ -4665,10 +5585,12 @@ git-write-pkt-line@0.1.0: github@^14.0.0: version "14.0.0" resolved "https://registry.npmjs.org/github/-/github-14.0.0.tgz#b707ed88c33cd05e155c785d289aa6229c59a850" + integrity sha512-34/VqwhYGeYN0VHBSH49TmRWMF7emy32qjK6POiW47T/QI2u/cpuKsmrWt7a218ew/73dF4dQSJE68/HXdNfPw== glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= dependencies: glob-parent "^2.0.0" is-glob "^2.0.0" @@ -4676,12 +5598,14 @@ glob-base@^0.3.0: glob-parent@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= dependencies: is-glob "^2.0.0" "glob@3 || 4", glob@^4.3.2: version "4.5.3" resolved "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" + integrity sha1-xstz0yJsHv7wTePFbQEvAzd+4V8= dependencies: inflight "^1.0.4" inherits "2" @@ -4691,6 +5615,7 @@ glob-parent@^2.0.0: glob@7.1.2, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -4702,6 +5627,7 @@ glob@7.1.2, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: glob@^5.0.10: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= dependencies: inflight "^1.0.4" inherits "2" @@ -4712,6 +5638,7 @@ glob@^5.0.10: glob@^7.1.1, glob@^7.1.3: version "7.1.3" resolved "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -4723,6 +5650,7 @@ glob@^7.1.1, glob@^7.1.3: glob@~6.0.3: version "6.0.4" resolved "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI= dependencies: inflight "^1.0.4" inherits "2" @@ -4733,6 +5661,7 @@ glob@~6.0.3: global-modules@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== dependencies: global-prefix "^1.0.1" is-windows "^1.0.1" @@ -4741,6 +5670,7 @@ global-modules@^1.0.0: global-prefix@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= dependencies: expand-tilde "^2.0.2" homedir-polyfill "^1.0.1" @@ -4751,14 +5681,17 @@ global-prefix@^1.0.1: globals@^11.1.0, globals@^11.7.0: version "11.7.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" + integrity sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg== globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== globby@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + integrity sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0= dependencies: array-union "^1.0.1" arrify "^1.0.0" @@ -4770,6 +5703,7 @@ globby@^5.0.0: got@^6.7.1: version "6.7.1" resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" + integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA= dependencies: create-error-class "^3.0.0" duplexer3 "^0.1.4" @@ -4786,6 +5720,7 @@ got@^6.7.1: got@^8.0.1: version "8.3.2" resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" + integrity sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw== dependencies: "@sindresorhus/is" "^0.7.0" cacheable-request "^2.1.1" @@ -4808,22 +5743,27 @@ got@^8.0.1: graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= "graceful-readlink@>= 1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= growl@1.10.5: version "1.10.5" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= handlebars@^4.0.11: version "4.0.12" resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" + integrity sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA== dependencies: async "^2.5.0" optimist "^0.6.1" @@ -4834,6 +5774,7 @@ handlebars@^4.0.11: handlebars@^4.0.4: version "4.0.11" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" + integrity sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw= dependencies: async "^1.4.0" optimist "^0.6.1" @@ -4844,10 +5785,12 @@ handlebars@^4.0.4: har-schema@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= har-validator@~2.0.2: version "2.0.6" resolved "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + integrity sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0= dependencies: chalk "^1.1.1" commander "^2.9.0" @@ -4857,6 +5800,7 @@ har-validator@~2.0.2: har-validator@~5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29" + integrity sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA== dependencies: ajv "^5.3.0" har-schema "^2.0.0" @@ -4864,40 +5808,48 @@ har-validator@~5.1.0: has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= dependencies: ansi-regex "^2.0.0" has-binary2@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== dependencies: isarray "2.0.1" has-cors@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= has-symbol-support-x@^1.4.1: version "1.4.2" resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== has-to-string-tag-x@^1.2.0: version "1.4.1" resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== dependencies: has-symbol-support-x "^1.4.1" has-unicode@^2.0.0, has-unicode@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= dependencies: get-value "^2.0.3" has-values "^0.1.4" @@ -4906,6 +5858,7 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= dependencies: get-value "^2.0.6" has-values "^1.0.0" @@ -4914,10 +5867,12 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= has-values@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= dependencies: is-number "^3.0.0" kind-of "^4.0.0" @@ -4925,12 +5880,14 @@ has-values@^1.0.0: has@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: function-bind "^1.1.1" hash-for-dep@^1.0.2, hash-for-dep@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.2.3.tgz#5ec69fca32c23523972d52acb5bb65ffc3664cab" + integrity sha512-NE//rDaCFpWHViw30YM78OAGBShU+g4dnUGY3UWGyEzPOGYg/ptOjk32nEc+bC1xz+RfK5UIs6lOL6eQdrV4Ow== dependencies: broccoli-kitchen-sink-helpers "^0.3.1" heimdalljs "^0.2.3" @@ -4940,6 +5897,7 @@ hash-for-dep@^1.0.2, hash-for-dep@^1.2.3: hawk@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" + integrity sha1-h81JH5tG5OKurKM1QWdmiF0tHtk= dependencies: boom "0.4.x" cryptiles "0.2.x" @@ -4949,6 +5907,7 @@ hawk@1.1.1: hawk@~3.1.0: version "3.1.3" resolved "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + integrity sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ= dependencies: boom "2.x.x" cryptiles "2.x.x" @@ -4958,10 +5917,12 @@ hawk@~3.1.0: he@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= heimdalljs-fs-monitor@^0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.2.2.tgz#a76d98f52dbf3aa1b7c20cebb0132e2f5eeb9204" + integrity sha512-R/VhkWs8tm4x+ekLIp+oieR8b3xYK0oFDumEraGnwNMixpiKwO3+Ms5MJzDP5W5Ui1+H/57nGW5L3lHbxi20GA== dependencies: heimdalljs "^0.2.3" heimdalljs-logger "^0.1.7" @@ -4969,10 +5930,12 @@ heimdalljs-fs-monitor@^0.2.2: heimdalljs-graph@^0.3.4: version "0.3.5" resolved "https://registry.npmjs.org/heimdalljs-graph/-/heimdalljs-graph-0.3.5.tgz#420fbbc8fc3aec5963ddbbf1a5fb47921c4a5927" + integrity sha512-szOy9WZUc7eUInEBQEsoa1G2d+oYHrn6ndZPf76eh8A9ID1zWUCEEsxP3F+CvQx9+EDrg1srdyLUmfVAr8EB4g== heimdalljs-logger@^0.1.7, heimdalljs-logger@^0.1.9: version "0.1.9" resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz#d76ada4e45b7bb6f786fc9c010a68eb2e2faf176" + integrity sha1-12raTkW3u294b8nAEKaOsuL68XY= dependencies: debug "^2.2.0" heimdalljs "^0.2.0" @@ -4980,26 +5943,31 @@ heimdalljs-logger@^0.1.7, heimdalljs-logger@^0.1.9: heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3, heimdalljs@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.5.tgz#6aa54308eee793b642cff9cf94781445f37730ac" + integrity sha1-aqVDCO7nk7ZCz/nPlHgURfN3MKw= dependencies: rsvp "~3.2.1" heimdalljs@^0.3.0: version "0.3.3" resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" + integrity sha1-6S0sb3f9RtW/ULYQ0orTF1UFTQs= dependencies: rsvp "~3.2.1" hoek@0.9.x: version "0.9.1" resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" + integrity sha1-PTIkYrrfB3Fup+uFuviAec3c5QU= hoek@2.x.x: version "2.16.3" resolved "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + integrity sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0= home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + integrity sha1-42w/LSyufXRqhX440Y1fMqeILbg= dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.1" @@ -5007,24 +5975,29 @@ home-or-tmp@^2.0.0: homedir-polyfill@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + integrity sha1-TCu8inWJmP7r9e1oWA921GdotLw= dependencies: parse-passwd "^1.0.0" hosted-git-info@^2.1.4, hosted-git-info@^2.1.5, hosted-git-info@^2.4.2, hosted-git-info@^2.6.0: version "2.7.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== hosted-git-info@~2.1.4: version "2.1.5" resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" + integrity sha1-C6gdkNouJas0ozLm7HeTbhWYEYs= http-cache-semantics@3.8.1: version "3.8.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== http-errors@1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + integrity sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY= dependencies: depd "1.1.1" inherits "2.0.3" @@ -5034,6 +6007,7 @@ http-errors@1.6.2: http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: version "1.6.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= dependencies: depd "~1.1.2" inherits "2.0.3" @@ -5043,10 +6017,12 @@ http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: http-parser-js@>=0.4.0: version "0.4.13" resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.13.tgz#3bd6d6fde6e3172c9334c3b33b6c193d80fe1137" + integrity sha1-O9bW/ebjFyyTNMOzO2wZPYD+ETc= http-proxy@^1.13.1, http-proxy@^1.17.0: version "1.17.0" resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" + integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g== dependencies: eventemitter3 "^3.0.0" follow-redirects "^1.0.0" @@ -5055,6 +6031,7 @@ http-proxy@^1.13.1, http-proxy@^1.17.0: http-signature@~0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" + integrity sha1-T72sEyVZqoMjEh5UB3nAoBKyfmY= dependencies: asn1 "0.1.11" assert-plus "^0.1.5" @@ -5063,6 +6040,7 @@ http-signature@~0.10.0: http-signature@~1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + integrity sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8= dependencies: assert-plus "^0.2.0" jsprim "^1.2.2" @@ -5071,6 +6049,7 @@ http-signature@~1.1.0: http-signature@~1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= dependencies: assert-plus "^1.0.0" jsprim "^1.2.2" @@ -5079,58 +6058,70 @@ http-signature@~1.2.0: iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ== iconv-lite@0.4.23, iconv-lite@^0.4.13, iconv-lite@^0.4.4: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== dependencies: safer-buffer ">= 2.1.2 < 3" iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" iferr@^0.1.5, iferr@~0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= ignore-walk@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== dependencies: minimatch "^3.0.4" ignore@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.3.tgz#e2d58c9654d75b542529fa28d80ac95b29e4f467" + integrity sha512-Z/vAH2GGIEATQnBVXMclE2IGV6i0GyVngKThcGZ5kHgHMxLo9Ow2+XHRq1aEKEej5vOF1TPJNbvX6J/anT0M7A== ignore@^4.0.6: version "4.0.6" resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= indent-string@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= dependencies: repeating "^2.0.0" indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= inflection@^1.12.0: version "1.12.0" resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" + integrity sha1-ogCTVlbW9fa8TcdQLhrstwMihBY= inflight@^1.0.4, inflight@~1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" wrappy "1" @@ -5138,14 +6129,17 @@ inflight@^1.0.4, inflight@~1.0.4: inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= ini@^1.3.4, ini@~1.3.0, ini@~1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== init-package-json@~1.9.1: version "1.9.6" resolved "https://registry.npmjs.org/init-package-json/-/init-package-json-1.9.6.tgz#789fc2b74466a4952b9ea77c0575bc78ebd60a61" + integrity sha1-eJ/Ct0RmpJUrnqd8BXW8eOvWCmE= dependencies: glob "^7.1.1" npm-package-arg "^4.0.0 || ^5.0.0" @@ -5159,6 +6153,7 @@ init-package-json@~1.9.1: inline-source-map-comment@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" + integrity sha1-UKikTCp5DfrEQbXJTszVRiY1+vY= dependencies: chalk "^1.0.0" get-stdin "^4.0.1" @@ -5169,6 +6164,7 @@ inline-source-map-comment@^1.0.5: inquirer@^2: version "2.0.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-2.0.0.tgz#e1351687b90d150ca403ceaa3cefb1e3065bef4b" + integrity sha1-4TUWh7kNFQykA86qPO+x4wZb70s= dependencies: ansi-escapes "^1.1.0" chalk "^1.0.0" @@ -5188,6 +6184,7 @@ inquirer@^2: inquirer@^6.1.0: version "6.2.0" resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8" + integrity sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg== dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" @@ -5206,6 +6203,7 @@ inquirer@^6.1.0: into-stream@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" + integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= dependencies: from2 "^2.1.1" p-is-promise "^1.1.0" @@ -5213,66 +6211,79 @@ into-stream@^3.1.0: invariant@^2.2.2: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== dependencies: loose-envify "^1.0.0" ipaddr.js@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" + integrity sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs= ipaddr.js@1.8.0: version "1.8.0" resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" + integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4= is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= dependencies: kind-of "^3.0.2" is-accessor-descriptor@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== dependencies: kind-of "^6.0.0" is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== is-builtin-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= dependencies: builtin-modules "^1.0.0" is-callable@^1.1.1, is-callable@^1.1.3: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= dependencies: kind-of "^3.0.2" is-data-descriptor@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== dependencies: kind-of "^6.0.0" is-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== dependencies: is-accessor-descriptor "^0.1.6" is-data-descriptor "^0.1.4" @@ -5281,6 +6292,7 @@ is-descriptor@^0.1.0: is-descriptor@^1.0.0, is-descriptor@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== dependencies: is-accessor-descriptor "^1.0.0" is-data-descriptor "^1.0.0" @@ -5289,70 +6301,84 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= is-equal-shallow@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= dependencies: is-primitive "^2.0.0" is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= is-extendable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== dependencies: is-plain-object "^2.0.4" is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= is-extglob@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= is-finite@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= is-git-url@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-1.0.0.tgz#53f684cd143285b52c3244b4e6f28253527af66b" + integrity sha1-U/aEzRQyhbUsMkS05vKCU1J69ms= is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= dependencies: is-extglob "^1.0.0" is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= dependencies: is-extglob "^2.1.0" is-my-ip-valid@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824" + integrity sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ== is-my-json-valid@^2.12.4: version "2.19.0" resolved "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz#8fd6e40363cd06b963fa877d444bfb5eddc62175" + integrity sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q== dependencies: generate-function "^2.0.0" generate-object-property "^1.1.0" @@ -5363,162 +6389,197 @@ is-my-json-valid@^2.12.4: is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= dependencies: kind-of "^3.0.2" is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= dependencies: kind-of "^3.0.2" is-number@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= is-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" + integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0= is-path-in-cwd@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" + integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ== dependencies: is-path-inside "^1.0.0" is-path-inside@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= dependencies: path-is-inside "^1.0.1" is-plain-obj@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== dependencies: isobject "^3.0.1" is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= is-property@^1.0.0, is-property@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ= is-redirect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= is-reference@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.1.0.tgz#50e6ef3f64c361e2c53c0416cdc9420037f2685b" + integrity sha512-h37O/IX4efe56o9k41II1ECMqKwtqHa7/12dLDEzJIFux2x15an4WCDb0/eKdmUgRpLJ3bR0DrzDc7vOrVgRDw== dependencies: "@types/estree" "0.0.38" is-regex@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= dependencies: has "^1.0.1" is-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= is-resolvable@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ= is-stream@^1.0.0, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= is-symbol@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + integrity sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI= is-type@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" + integrity sha1-9lHYXDZdRJVdFKUdjXBh8/a0d5w= dependencies: core-util-is "~1.0.0" is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= isarray@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= isbinaryfile@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80" + integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw== dependencies: buffer-alloc "^1.2.0" isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= isstream@~0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= istextorbinary@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" + integrity sha1-2+0qb1G+L3R1to+JRlgRFBt1iHQ= dependencies: binaryextensions "1 || 2" editions "^1.1.1" @@ -5527,6 +6588,7 @@ istextorbinary@2.1.0: isurl@^1.0.0-alpha5: version "1.0.0" resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== dependencies: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" @@ -5534,26 +6596,32 @@ isurl@^1.0.0-alpha5: jquery@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" + integrity sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg== js-levenshtein@^1.1.3: version "1.1.4" resolved "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.4.tgz#3a56e3cbf589ca0081eb22cd9ba0b1290a16d26e" + integrity sha512-PxfGzSs0ztShKrUYPIn5r0MtyAhYcCwmndozzpz8YObbPnD1jFxzlBGbRnX2mIu6Z13xN6+PTu05TQFnZFlzow== js-reporters@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b" + integrity sha1-+IxgjjJKM3OpW8xFrTBeXJecRZs= "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= js-yaml@^3.12.0, js-yaml@^3.2.5, js-yaml@^3.2.7: version "3.12.0" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + integrity sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A== dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -5561,84 +6629,103 @@ js-yaml@^3.12.0, js-yaml@^3.2.5, js-yaml@^3.2.7: jsbn@~0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= jsesc@^2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + integrity sha1-5CGiqOINawgZ3yiQj3glJrlt0f4= jsesc@~0.3.x: version "0.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.3.0.tgz#1bf5ee63b4539fe2e26d0c1e99c240b97a457972" + integrity sha1-G/XuY7RTn+LibQwemcJAuXpFeXI= jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= json-buffer@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== json-schema-traverse@^0.3.0: version "0.3.1" resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-schema@0.2.3: version "0.2.3" resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= dependencies: jsonify "~0.0.0" json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + integrity sha1-NzaitCi4e72gzIO1P6PWM6NcKug= optionalDependencies: graceful-fs "^4.1.6" jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= optionalDependencies: graceful-fs "^4.1.6" jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= jsonpointer@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + integrity sha1-T9kss04OnbPInIYi7PUfm5eMbLk= jsprim@^1.2.2: version "1.4.1" resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= dependencies: assert-plus "1.0.0" extsprintf "1.3.0" @@ -5648,42 +6735,50 @@ jsprim@^1.2.2: keyv@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" + integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== dependencies: json-buffer "3.0.0" kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= dependencies: is-buffer "^1.1.5" kind-of@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== klaw@^1.0.0: version "1.3.1" resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + integrity sha1-QIhDO0azsbolnXh4XY6W9zugJDk= optionalDependencies: graceful-fs "^4.1.9" lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= leek@0.0.24: version "0.0.24" resolved "https://registry.yarnpkg.com/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" + integrity sha1-5ADlfw5g2O8r1NBo3EKKVDRdvNo= dependencies: debug "^2.1.0" lodash.assign "^3.2.0" @@ -5692,6 +6787,7 @@ leek@0.0.24: levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" @@ -5699,28 +6795,33 @@ levn@^0.3.0, levn@~0.3.0: line-stream@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/line-stream/-/line-stream-0.0.0.tgz#888b7cc7951c6a05ce4d696dd1e6b8262371bb45" + integrity sha1-iIt8x5UcagXOTWlt0ea4JiNxu0U= dependencies: through "~2.2.0" linkify-it@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" + integrity sha1-2UpGSPmxwXnWT6lykSaL22zpQ08= dependencies: uc.micro "^1.0.1" linkify-it@~1.2.0: version "1.2.4" resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" + integrity sha1-B3NSbDF8j9E71TTuHRgP+Iq/iBo= dependencies: uc.micro "^1.0.1" livereload-js@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.3.0.tgz#c3ab22e8aaf5bf3505d80d098cbad67726548c9a" + integrity sha512-j1R0/FeGa64Y+NmqfZhyoVRzcFlOZ8sNlKzHjh4VvLULFACZhn68XrX5DFg2FhMvSMJmROuFxRSa560ECWKBMg== load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -5731,14 +6832,17 @@ load-json-file@^1.0.0: loader.js@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.7.0.tgz#a1a52902001c83631efde9688b8ab3799325ef1f" + integrity sha512-9M2KvGT6duzGMgkOcTkWb+PR/Q2Oe54df/tLgHGVmFpAmtqJ553xJh6N63iFYI2yjo2PeJXbS5skHi/QpJq4vA== locate-character@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/locate-character/-/locate-character-2.0.5.tgz#f2d2614d49820ecb3c92d80d193b8db755f74c0f" + integrity sha512-n2GmejDXtOPBAZdIiEFy5dJ5N38xBCXLNOtw2WpB9kGh6pnrEuKlwYI+Tkpofc4wDtVXHtoAOJaMRlYG/oYaxg== locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= dependencies: p-locate "^2.0.0" path-exists "^3.0.0" @@ -5746,6 +6850,7 @@ locate-path@^2.0.0: locate-path@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== dependencies: p-locate "^3.0.0" path-exists "^3.0.0" @@ -5753,24 +6858,29 @@ locate-path@^3.0.0: lockfile@~1.0.1: version "1.0.4" resolved "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" + integrity sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA== dependencies: signal-exit "^3.0.2" lodash-node@^3.2.0: version "3.10.2" resolved "https://registry.yarnpkg.com/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" + integrity sha1-JZjVsbVOami0y1ROXHMJU8v2Mvc= lodash._arraycopy@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" + integrity sha1-due3wfH7klRzdIeKVi7Qaj5Q9uE= lodash._arrayeach@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" + integrity sha1-urFWsqkNPxu9XGU0AzSeXlkz754= lodash._baseassign@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + integrity sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4= dependencies: lodash._basecopy "^3.0.0" lodash.keys "^3.0.0" @@ -5778,6 +6888,7 @@ lodash._baseassign@^3.0.0: lodash._basebind@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._basebind/-/lodash._basebind-2.3.0.tgz#2b5bc452a0e106143b21869f233bdb587417d248" + integrity sha1-K1vEUqDhBhQ7IYafIzvbWHQX0kg= dependencies: lodash._basecreate "~2.3.0" lodash._setbinddata "~2.3.0" @@ -5786,6 +6897,7 @@ lodash._basebind@~2.3.0: lodash._basecallback@^3.0.0: version "3.3.1" resolved "https://registry.npmjs.org/lodash._basecallback/-/lodash._basecallback-3.3.1.tgz#b7b2bb43dc2160424a21ccf26c57e443772a8e27" + integrity sha1-t7K7Q9whYEJKIczybFfkQ3cqjic= dependencies: lodash._baseisequal "^3.0.0" lodash._bindcallback "^3.0.0" @@ -5795,6 +6907,7 @@ lodash._basecallback@^3.0.0: lodash._baseclone@^3.0.0: version "3.3.0" resolved "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz#303519bf6393fe7e42f34d8b630ef7794e3542b7" + integrity sha1-MDUZv2OT/n5C802LYw73eU41Qrc= dependencies: lodash._arraycopy "^3.0.0" lodash._arrayeach "^3.0.0" @@ -5806,10 +6919,12 @@ lodash._baseclone@^3.0.0: lodash._basecopy@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY= lodash._basecreate@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz#9b88a86a4dcff7b7f3c61d83a2fcfc0671ec9de0" + integrity sha1-m4ioak3P97fzxh2Dovz8BnHsneA= dependencies: lodash._renative "~2.3.0" lodash.isobject "~2.3.0" @@ -5818,6 +6933,7 @@ lodash._basecreate@~2.3.0: lodash._basecreatecallback@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz#37b2ab17591a339e988db3259fcd46019d7ac362" + integrity sha1-N7KrF1kaM56YjbMln81GAZ16w2I= dependencies: lodash._setbinddata "~2.3.0" lodash.bind "~2.3.0" @@ -5827,6 +6943,7 @@ lodash._basecreatecallback@~2.3.0: lodash._basecreatewrapper@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz#aa0c61ad96044c3933376131483a9759c3651247" + integrity sha1-qgxhrZYETDkzN2ExSDqXWcNlEkc= dependencies: lodash._basecreate "~2.3.0" lodash._setbinddata "~2.3.0" @@ -5836,6 +6953,7 @@ lodash._basecreatewrapper@~2.3.0: lodash._basedifference@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/lodash._basedifference/-/lodash._basedifference-3.0.3.tgz#f2c204296c2a78e02b389081b6edcac933cf629c" + integrity sha1-8sIEKWwqeOArOJCBtu3KyTPPYpw= dependencies: lodash._baseindexof "^3.0.0" lodash._cacheindexof "^3.0.0" @@ -5844,6 +6962,7 @@ lodash._basedifference@^3.0.0: lodash._baseflatten@^3.0.0: version "3.1.4" resolved "https://registry.yarnpkg.com/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" + integrity sha1-B3D/gBMa9uNPO1EXlqe6UhTmX/c= dependencies: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" @@ -5851,14 +6970,17 @@ lodash._baseflatten@^3.0.0: lodash._basefor@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" + integrity sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI= lodash._baseindexof@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" + integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw= lodash._baseisequal@^3.0.0: version "3.0.7" resolved "https://registry.npmjs.org/lodash._baseisequal/-/lodash._baseisequal-3.0.7.tgz#d8025f76339d29342767dcc887ce5cb95a5b51f1" + integrity sha1-2AJfdjOdKTQnZ9zIh85cuVpbUfE= dependencies: lodash.isarray "^3.0.0" lodash.istypedarray "^3.0.0" @@ -5867,6 +6989,7 @@ lodash._baseisequal@^3.0.0: lodash._baseuniq@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-3.0.3.tgz#2123fa0db2d69c28d5beb1c1f36d61522a740234" + integrity sha1-ISP6DbLWnCjVvrHB821hUip0AjQ= dependencies: lodash._baseindexof "^3.0.0" lodash._cacheindexof "^3.0.0" @@ -5875,14 +6998,17 @@ lodash._baseuniq@^3.0.0: lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4= lodash._cacheindexof@^3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" + integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI= lodash._createassigner@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + integrity sha1-g4pbri/aymOsIt7o4Z+k5taXCxE= dependencies: lodash._bindcallback "^3.0.0" lodash._isiterateecall "^3.0.0" @@ -5891,12 +7017,14 @@ lodash._createassigner@^3.0.0: lodash._createcache@^3.0.0: version "3.1.2" resolved "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" + integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM= dependencies: lodash._getnative "^3.0.0" lodash._createwrapper@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" + integrity sha1-0arhEC2t9EDo4G/BM6bt1/4UYHU= dependencies: lodash._basebind "~2.3.0" lodash._basecreatewrapper "~2.3.0" @@ -5905,44 +7033,54 @@ lodash._createwrapper@~2.3.0: lodash._escapehtmlchar@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.3.0.tgz#d03da6bd82eedf38dc0a5b503d740ecd0e894592" + integrity sha1-0D2mvYLu3zjcCltQPXQOzQ6JRZI= dependencies: lodash._htmlescapes "~2.3.0" lodash._escapestringchar@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._escapestringchar/-/lodash._escapestringchar-2.3.0.tgz#cce73ae60fc6da55d2bf8a0679c23ca2bab149fc" + integrity sha1-zOc65g/G2lXSv4oGecI8orqxSfw= lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= lodash._htmlescapes@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._htmlescapes/-/lodash._htmlescapes-2.3.0.tgz#1ca98863cadf1fa1d82c84f35f31e40556a04f3a" + integrity sha1-HKmIY8rfH6HYLITzXzHkBVagTzo= lodash._isiterateecall@^3.0.0: version "3.0.9" resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw= lodash._objecttypes@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz#6a3ea3987dd6eeb8021b2d5c9c303549cc2bae1e" + integrity sha1-aj6jmH3W7rgCGy1cnDA1Scwrrh4= lodash._reinterpolate@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-2.3.0.tgz#03ee9d85c0e55cbd590d71608a295bdda51128ec" + integrity sha1-A+6dhcDlXL1ZDXFgiilb3aURKOw= lodash._reinterpolate@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= lodash._renative@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._renative/-/lodash._renative-2.3.0.tgz#77d8edd4ced26dd5971f9e15a5f772e4e317fbd3" + integrity sha1-d9jt1M7SbdWXH54Vpfdy5OMX+9M= lodash._reunescapedhtml@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.3.0.tgz#db920b55ac7f3ff825939aceb9ba2c231713d24d" + integrity sha1-25ILVax/P/glk5rOubosIxcT0k0= dependencies: lodash._htmlescapes "~2.3.0" lodash.keys "~2.3.0" @@ -5950,6 +7088,7 @@ lodash._reunescapedhtml@~2.3.0: lodash._setbinddata@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz#e5610490acd13277d59858d95b5f2727f1508f04" + integrity sha1-5WEEkKzRMnfVmFjZW18nJ/FQjwQ= dependencies: lodash._renative "~2.3.0" lodash.noop "~2.3.0" @@ -5957,16 +7096,19 @@ lodash._setbinddata@~2.3.0: lodash._shimkeys@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz#611f93149e3e6c721096b48769ef29537ada8ba9" + integrity sha1-YR+TFJ4+bHIQlrSHae8pU3rai6k= dependencies: lodash._objecttypes "~2.3.0" lodash._slice@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._slice/-/lodash._slice-2.3.0.tgz#147198132859972e4680ca29a5992c855669aa5c" + integrity sha1-FHGYEyhZly5GgMoppZkshVZpqlw= lodash.assign@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + integrity sha1-POnwI0tLIiPilrj6CsH+6OvKZPo= dependencies: lodash._baseassign "^3.0.0" lodash._createassigner "^3.0.0" @@ -5975,10 +7117,12 @@ lodash.assign@^3.2.0: lodash.assignin@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + integrity sha1-uo31+4QesKPoBEIysOJjqNxqKKI= lodash.bind@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-2.3.0.tgz#c2a8e18b68e5ecc152e2b168266116fea5b016cc" + integrity sha1-wqjhi2jl7MFS4rFoJmEW/qWwFsw= dependencies: lodash._createwrapper "~2.3.0" lodash._renative "~2.3.0" @@ -5987,14 +7131,17 @@ lodash.bind@~2.3.0: lodash.castarray@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" + integrity sha1-wCUTUV4wna3dTCTGDP3c9ZdtkRU= lodash.clonedeep@^4.4.1: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= lodash.clonedeep@~3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz#a0a1e40d82a5ea89ff5b147b8444ed63d92827db" + integrity sha1-oKHkDYKl6on/WxR7hETtY9koJ9s= dependencies: lodash._baseclone "^3.0.0" lodash._bindcallback "^3.0.0" @@ -6002,12 +7149,14 @@ lodash.clonedeep@~3.0.2: lodash.debounce@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" + integrity sha1-gSIRw3ipTMKdWqTjNGzwv846ffU= dependencies: lodash._getnative "^3.0.0" lodash.defaults@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-2.3.0.tgz#a832b001f138f3bb9721c2819a2a7cc5ae21ed25" + integrity sha1-qDKwAfE487uXIcKBmip8xa4h7SU= dependencies: lodash._objecttypes "~2.3.0" lodash.keys "~2.3.0" @@ -6015,10 +7164,12 @@ lodash.defaults@~2.3.0: lodash.defaultsdeep@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.0.tgz#bec1024f85b1bd96cbea405b23c14ad6443a6f81" + integrity sha1-vsECT4WxvZbL6kBbI8FK1kQ6b4E= lodash.escape@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-2.3.0.tgz#844c38c58f844e1362ebe96726159b62cf5f2a58" + integrity sha1-hEw4xY+EThNi6+lnJhWbYs9fKlg= dependencies: lodash._escapehtmlchar "~2.3.0" lodash._reunescapedhtml "~2.3.0" @@ -6027,10 +7178,12 @@ lodash.escape@~2.3.0: lodash.find@^4.5.1: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" + integrity sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E= lodash.flatten@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" + integrity sha1-3hz1d1j49EeTGdNcPpzGDEUBk4w= dependencies: lodash._baseflatten "^3.0.0" lodash._isiterateecall "^3.0.0" @@ -6038,6 +7191,7 @@ lodash.flatten@^3.0.2: lodash.foreach@~2.3.x: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-2.3.0.tgz#083404c91e846ee77245fdf9d76519c68b2af168" + integrity sha1-CDQEyR6EbudyRf3512UZxosq8Wg= dependencies: lodash._basecreatecallback "~2.3.0" lodash.forown "~2.3.0" @@ -6045,6 +7199,7 @@ lodash.foreach@~2.3.x: lodash.forown@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.forown/-/lodash.forown-2.3.0.tgz#24fb4aaf800d45fc2dc60bfec3ce04c836a3ad7f" + integrity sha1-JPtKr4ANRfwtxgv+w84EyDajrX8= dependencies: lodash._basecreatecallback "~2.3.0" lodash._objecttypes "~2.3.0" @@ -6053,32 +7208,39 @@ lodash.forown@~2.3.0: lodash.identity@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.identity/-/lodash.identity-2.3.0.tgz#6b01a210c9485355c2a913b48b6711219a173ded" + integrity sha1-awGiEMlIU1XCqRO0i2cRIZoXPe0= lodash.isarguments@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= lodash.isfunction@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz#6b2973e47a647cf12e70d676aea13643706e5267" + integrity sha1-aylz5HpkfPEucNZ2rqE2Q3BuUmc= lodash.isobject@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-2.3.0.tgz#2e16d3fc583da9831968953f2d8e6d73434f6799" + integrity sha1-LhbT/Fg9qYMZaJU/LY5tc0NPZ5k= dependencies: lodash._objecttypes "~2.3.0" lodash.istypedarray@^3.0.0: version "3.0.6" resolved "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" + integrity sha1-yaR3SYYHUB2OhJTSg7h8OSgc72I= lodash.keys@^3.0.0: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo= dependencies: lodash._getnative "^3.0.0" lodash.isarguments "^3.0.0" @@ -6087,6 +7249,7 @@ lodash.keys@^3.0.0: lodash.keys@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-2.3.0.tgz#b350f4f92caa9f45a4a2ecf018454cf2f28ae253" + integrity sha1-s1D0+Syqn0WkouzwGEVM8vKK4lM= dependencies: lodash._renative "~2.3.0" lodash._shimkeys "~2.3.0" @@ -6095,46 +7258,56 @@ lodash.keys@~2.3.0: lodash.merge@^4.3.1, lodash.merge@^4.6.0: version "4.6.1" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" + integrity sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ== lodash.noop@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-2.3.0.tgz#3059d628d51bbf937cd2a0b6fc3a7f212a669c2c" + integrity sha1-MFnWKNUbv5N80qC2/Dp/ISpmnCw= lodash.omit@^4.1.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" + integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA= lodash.pad@^4.1.0: version "4.5.1" resolved "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz#4330949a833a7c8da22cc20f6a26c4d59debba70" + integrity sha1-QzCUmoM6fI2iLMIPaibE1Z3runA= lodash.padend@^4.1.0: version "4.6.1" resolved "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e" + integrity sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4= lodash.padstart@^4.1.0: version "4.6.1" resolved "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b" + integrity sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs= lodash.pairs@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/lodash.pairs/-/lodash.pairs-3.0.1.tgz#bbe08d5786eeeaa09a15c91ebf0dcb7d2be326a9" + integrity sha1-u+CNV4bu6qCaFckevw3LfSvjJqk= dependencies: lodash.keys "^3.0.0" lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= lodash.support@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.support/-/lodash.support-2.3.0.tgz#7eaf038af4f0d6aab776b44aa6dcfc80334c9bfd" + integrity sha1-fq8DivTw1qq3drRKptz8gDNMm/0= dependencies: lodash._renative "~2.3.0" lodash.template@^4.4.0: version "4.4.0" resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" + integrity sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A= dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings "^4.0.0" @@ -6142,6 +7315,7 @@ lodash.template@^4.4.0: lodash.template@~2.3.x: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-2.3.0.tgz#4e3e29c433b4cfea675ec835e6f12391c61fd22b" + integrity sha1-Tj4pxDO0z+pnXsg15vEjkcYf0is= dependencies: lodash._escapestringchar "~2.3.0" lodash._reinterpolate "~2.3.0" @@ -6154,12 +7328,14 @@ lodash.template@~2.3.x: lodash.templatesettings@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" + integrity sha1-K01OlbpEDZFf8IvImeRVNmZxMxY= dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-2.3.0.tgz#303d132c342710040d5a18efaa2d572fd03f8cdc" + integrity sha1-MD0TLDQnEAQNWhjvqi1XL9A/jNw= dependencies: lodash._reinterpolate "~2.3.0" lodash.escape "~2.3.0" @@ -6167,6 +7343,7 @@ lodash.templatesettings@~2.3.0: lodash.union@~3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-3.1.0.tgz#a4a3066fc15d6a7f8151cce9bdfe63dce7f5bcff" + integrity sha1-pKMGb8Fdan+BUczpvf5j3Of1vP8= dependencies: lodash._baseflatten "^3.0.0" lodash._baseuniq "^3.0.0" @@ -6175,10 +7352,12 @@ lodash.union@~3.1.0: lodash.uniq@^4.2.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= lodash.uniq@~3.2.2: version "3.2.2" resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-3.2.2.tgz#146c36f25e75d19501ba402e88ba14937f63cd8b" + integrity sha1-FGw28l510ZUBukAuiLoUk39jzYs= dependencies: lodash._basecallback "^3.0.0" lodash._baseuniq "^3.0.0" @@ -6189,16 +7368,19 @@ lodash.uniq@~3.2.2: lodash.uniqby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" + integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= lodash.values@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-2.3.0.tgz#ca96fbe60a20b0b0ec2ba2ba5fc6a765bd14a3ba" + integrity sha1-ypb75gogsLDsK6K6X8anZb0Uo7o= dependencies: lodash.keys "~2.3.0" lodash.without@~3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/lodash.without/-/lodash.without-3.2.1.tgz#d69614b3512e52294b6abab782e7ca96538ce816" + integrity sha1-1pYUs1EuUilLarq3gufKllOM6BY= dependencies: lodash._basedifference "^3.0.0" lodash.restparam "^3.0.0" @@ -6206,30 +7388,36 @@ lodash.without@~3.2.1: lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.6.1: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + integrity sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg== lodash@^4.17.11: version "4.17.11" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== dependencies: chalk "^2.0.1" longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= loose-envify@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: js-tokens "^3.0.0 || ^4.0.0" loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= dependencies: currently-unhandled "^0.4.1" signal-exit "^3.0.0" @@ -6237,54 +7425,73 @@ loud-rejection@^1.0.0: lowercase-keys@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== lru-cache@2: version "2.7.3" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI= + +lru-cache@^4.0.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" + integrity sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" magic-string@^0.24.0: version "0.24.1" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.24.1.tgz#7e38e5f126cae9f15e71f0cf8e450818ca7d5a8f" + integrity sha512-YBfNxbJiixMzxW40XqJEIldzHyh5f7CZKalo1uZffevyrPEX8Qgo9s0dmcORLHdV47UyvJg8/zD+6hQG3qvJrA== dependencies: sourcemap-codec "^1.4.1" make-array@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" + integrity sha1-M14267DFpDFU0hIToeyuriobs+8= make-dir@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== dependencies: pify "^3.0.0" makeerror@1.0.x: version "1.0.11" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= dependencies: tmpl "1.0.x" map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= dependencies: object-visit "^1.0.0" markdown-it-terminal@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/markdown-it-terminal/-/markdown-it-terminal-0.1.0.tgz#545abd8dd01c3d62353bfcea71db580b51d22bd9" + integrity sha1-VFq9jdAcPWI1O/zqcdtYC1HSK9k= dependencies: ansi-styles "^3.0.0" cardinal "^1.0.0" @@ -6295,6 +7502,7 @@ markdown-it-terminal@0.1.0: markdown-it@^4.3.0: version "4.4.0" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" + integrity sha1-PfNz2+pYepp/7z5WMRtokI91xBQ= dependencies: argparse "~1.0.2" entities "~1.1.1" @@ -6305,6 +7513,7 @@ markdown-it@^4.3.0: markdown-it@^8.3.1, markdown-it@^8.4.2: version "8.4.2" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54" + integrity sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ== dependencies: argparse "^1.0.7" entities "~1.1.1" @@ -6315,34 +7524,41 @@ markdown-it@^8.3.1, markdown-it@^8.4.2: matcher-collection@^1.0.0, matcher-collection@^1.0.4, matcher-collection@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-1.0.5.tgz#2ee095438372cb8884f058234138c05c644ec339" + integrity sha512-nUCmzKipcJEwYsBVAFh5P+d7JBuhJaW1xs85Hara9xuMLqtCVUrW6DSC0JVIkluxEH2W45nPBM/wjHtBXa/tYA== dependencies: minimatch "^3.0.2" math-random@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" + integrity sha1-izqsWIuKZuSXXjzepn97sylgH6w= mdn-links@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" + integrity sha1-4kyDuXy0xYhsw58veAcF+/4nOqU= mdurl@^1.0.1, mdurl@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= memory-streams@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.3.tgz#d9b0017b4b87f1d92f55f2745c9caacb1dc93ceb" + integrity sha512-qVQ/CjkMyMInPaaRMrwWNDvf6boRZXaT/DbQeMYcCWuXPEBf1v8qChOc9OlEVQp2uOvRXa1Qu30fLmKhY6NipA== dependencies: readable-stream "~1.0.2" meow@^3.4.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= dependencies: camelcase-keys "^2.0.0" decamelize "^1.1.2" @@ -6358,10 +7574,12 @@ meow@^3.4.0: merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= merge-trees@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-trees/-/merge-trees-1.0.1.tgz#ccbe674569787f9def17fd46e6525f5700bbd23e" + integrity sha1-zL5nRWl4f53vF/1G5lJfVwC70j4= dependencies: can-symlink "^1.0.0" fs-tree-diff "^0.5.4" @@ -6373,6 +7591,7 @@ merge-trees@^1.0.1: merge-trees@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-trees/-/merge-trees-2.0.0.tgz#a560d796e566c5d9b2c40472a2967cca48d85161" + integrity sha512-5xBbmqYBalWqmhYm51XlohhkmVOua3VAUrrWh8t9iOkaLpS6ifqm/UVuUjQCeDVJ9Vx3g2l6ihfkbLSTeKsHbw== dependencies: fs-updater "^1.0.4" heimdalljs "^0.2.5" @@ -6380,14 +7599,17 @@ merge-trees@^2.0.0: merge@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + integrity sha1-dTHjnUlJwoGma4xabgJl6LBYlNo= methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= micromatch@^2.3.11: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= dependencies: arr-diff "^2.0.0" array-unique "^0.2.1" @@ -6406,6 +7628,7 @@ micromatch@^2.3.11: micromatch@^3.0.4, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" @@ -6424,46 +7647,56 @@ micromatch@^3.0.4, micromatch@^3.1.4: "mime-db@>= 1.34.0 < 2", mime-db@~1.35.0: version "1.35.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" + integrity sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg== mime-db@~1.37.0: version "1.37.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" + integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== mime-types@^2.1.11, mime-types@^2.1.12, mime-types@^2.1.19, mime-types@~2.1.19, mime-types@~2.1.7: version "2.1.21" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" + integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg== dependencies: mime-db "~1.37.0" mime-types@^2.1.18, mime-types@~2.1.18: version "2.1.19" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" + integrity sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw== dependencies: mime-db "~1.35.0" mime-types@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" + integrity sha1-mVrhOSq4r/y/yyZB3QVOlDwNXc4= mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== mime@~1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + integrity sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA= mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== minimatch@1: version "1.0.0" resolved "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz#e0dd2120b49e1b724ce8d714c520822a9438576d" + integrity sha1-4N0hILSeG3JM6NcUxSCCKpQ4V20= dependencies: lru-cache "2" sigmund "~1.0.0" @@ -6471,30 +7704,36 @@ minimatch@1: "minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" minimatch@^2.0.1: version "2.0.10" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" + integrity sha1-jQh8OcazjAAbl/ynzm0OHoCvusc= dependencies: brace-expansion "^1.0.0" minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= minipass@^2.2.0, minipass@^2.2.1, minipass@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" + integrity sha512-/jAn9/tEX4gnpyRATxgHEOV6xbcyxgT7iUnxo9Y3+OB0zX00TgKIv/2FZCf5brBbICcwbLqVv2ImjvWWrQMSYw== dependencies: safe-buffer "^5.1.2" yallist "^3.0.0" @@ -6502,12 +7741,14 @@ minipass@^2.2.0, minipass@^2.2.1, minipass@^2.3.3: minizlib@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + integrity sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA== dependencies: minipass "^2.2.1" mixin-deep@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== dependencies: for-in "^1.0.2" is-extendable "^1.0.1" @@ -6515,16 +7756,19 @@ mixin-deep@^1.2.0: mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= dependencies: minimist "0.0.8" mktemp@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" + integrity sha1-bQUVYRyKjITkhKogABKbmOmB/ws= mocha-only-detector@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mocha-only-detector/-/mocha-only-detector-1.0.0.tgz#183c710afffcca79df172daf76c45afca3b8e37d" + integrity sha1-GDxxCv/8ynnfFy2vdsRa/KO4430= dependencies: esprima "^4.0.0" esprimaq "^0.0.1" @@ -6533,6 +7777,7 @@ mocha-only-detector@1.0.0: mocha@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" + integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== dependencies: browser-stdout "1.3.1" commander "2.15.1" @@ -6549,16 +7794,19 @@ mocha@^5.2.0: moment-timezone@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" + integrity sha1-PvR4VrAtU7cYoQpewgI6opnge/U= dependencies: moment ">= 2.6.0" "moment@>= 2.6.0": version "2.22.2" resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" + integrity sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y= morgan@^1.9.0: version "1.9.1" resolved "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz#0a8d16734a1d9afbc824b99df87e738e58e2da59" + integrity sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA== dependencies: basic-auth "~2.0.0" debug "2.6.9" @@ -6569,34 +7817,42 @@ morgan@^1.9.0: mout@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mout/-/mout-1.1.0.tgz#0b29d41e6a80fa9e2d4a5be9d602e1d9d02177f6" + integrity sha512-XsP0vf4As6BfqglxZqbqQ8SR6KQot2AgxvR0gG+WtUkf90vUXchMOZQtPf/Hml1rEffJupqL/tIrU6EYhsUQjw== ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= ms@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== mustache@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/mustache/-/mustache-3.0.0.tgz#3de22dd9ba38152f7355399a953dd4528c403338" + integrity sha512-bhBDkK/PioIbtQzRIbGUGypvc3MC4c389QnJt8KDIEJ666OidRPoXAQAHPivikfS3JkMEaWoPvcDL7YrQxtSwg== mute-stream@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" + integrity sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s= mute-stream@0.0.7, mute-stream@~0.0.4: version "0.0.7" resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= nan@^2.9.2: version "2.10.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA== nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" @@ -6613,10 +7869,12 @@ nanomatch@^1.2.9: natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= needle@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" + integrity sha512-t/ZswCM9JTWjAdXS9VpvqhI2Ct2sL2MdY4fUXqGJaGBk13ge99ObqRksRTbBE56K+wxUXwwfZYOuZHifFW9q+Q== dependencies: debug "^2.1.2" iconv-lite "^0.4.4" @@ -6625,18 +7883,22 @@ needle@^2.2.1: negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= next-tick@1: version "1.0.0" resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= nice-try@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" + integrity sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA== node-gyp@~3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-3.2.1.tgz#f5dd569970a508464cc3c15d7e9e8d2de8638dd5" + integrity sha1-9d1WmXClCEZMw8Fdfp6NLehjjdU= dependencies: fstream "^1.0.0" glob "3 || 4" @@ -6656,14 +7918,17 @@ node-gyp@~3.2.1: node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= node-modules-path@^1.0.0, node-modules-path@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" + integrity sha1-QAlrCM560OoUaAhjr0ScfHWl0cg= node-notifier@^5.0.1: version "5.2.1" resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" + integrity sha512-MIBs+AAd6dJ2SklbbE8RUDRlIVhU8MaNLh1A9SUZDUHPiZkWLFde6UNwG41yQHZEToHgJMXqyVZ9UcS/ReOVTg== dependencies: growly "^1.3.0" semver "^5.4.1" @@ -6673,6 +7938,7 @@ node-notifier@^5.0.1: node-pre-gyp@^0.10.0: version "0.10.3" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== dependencies: detect-libc "^1.0.2" mkdirp "^0.5.1" @@ -6688,22 +7954,26 @@ node-pre-gyp@^0.10.0: node-releases@^1.0.0-alpha.15: version "1.0.0-alpha.15" resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.0.0-alpha.15.tgz#bdb08730287cc50ddbfa3c1a358366a4a2f5d397" + integrity sha512-hKG6hd/g6a9OV/ARt2qrxbRhe/4WEMFohTLOB9PNyTYvvI59gICZFzt9/mMgpYUTts06qXlN8H6UjfbIRdnW8A== dependencies: semver "^5.3.0" node-uuid@~1.4.0, node-uuid@~1.4.7: version "1.4.8" resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" + integrity sha1-sEDrCSOWivq/jTL7HxfxFn/auQc= "nopt@2 || 3", nopt@^3.0.3, nopt@^3.0.6, nopt@~3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= dependencies: abbrev "1" nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= dependencies: abbrev "1" osenv "^0.1.4" @@ -6711,10 +7981,12 @@ nopt@^4.0.1: normalize-git-url@~3.0.1: version "3.0.2" resolved "https://registry.npmjs.org/normalize-git-url/-/normalize-git-url-3.0.2.tgz#8e5f14be0bdaedb73e07200310aa416c27350fc4" + integrity sha1-jl8Uvgva7bc+ByADEKpBbCc1D8Q= normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, "normalize-package-data@~1.0.1 || ^2.0.0": version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw== dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -6724,6 +7996,7 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package- normalize-package-data@~2.3.5: version "2.3.8" resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" + integrity sha1-2Bntoqne29H/pWPqQHHZNngilbs= dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -6733,12 +8006,14 @@ normalize-package-data@~2.3.5: normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= dependencies: remove-trailing-separator "^1.0.1" normalize-url@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== dependencies: prepend-http "^2.0.0" query-string "^5.0.1" @@ -6747,18 +8022,22 @@ normalize-url@2.0.1: npm-bundled@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + integrity sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow== npm-cache-filename@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" + integrity sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE= npm-git-info@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" + integrity sha1-qTPELsMh6A02RuDW6ESv6UYw4dU= npm-install-checks@~2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-2.0.1.tgz#a93540b53f04fa9d916d2733d6541f6db7d88e46" + integrity sha1-qTVAtT8E+p2RbScz1lQfbbfYjkY= dependencies: npmlog "0.1 || 1" semver "^2.3.0 || 3.x || 4 || 5" @@ -6766,6 +8045,7 @@ npm-install-checks@~2.0.1: "npm-package-arg@^3.0.0 || ^4.0.0", npm-package-arg@^4.1.1: version "4.2.1" resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" + integrity sha1-WTMD/eqF98Qid18X+et2cPaA4+w= dependencies: hosted-git-info "^2.1.5" semver "^5.1.0" @@ -6773,6 +8053,7 @@ npm-install-checks@~2.0.1: "npm-package-arg@^4.0.0 || ^5.0.0": version "5.1.2" resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-5.1.2.tgz#fb18d17bb61e60900d6312619919bd753755ab37" + integrity sha512-wJBsrf0qpypPT7A0LART18hCdyhpCMxeTtcb0X4IZO2jsP6Om7EHN1d9KSKiqD+KVH030RVNpWS9thk+pb7wzA== dependencies: hosted-git-info "^2.4.2" osenv "^0.1.4" @@ -6782,6 +8063,7 @@ npm-install-checks@~2.0.1: npm-package-arg@^6.1.0: version "6.1.0" resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" + integrity sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA== dependencies: hosted-git-info "^2.6.0" osenv "^0.1.5" @@ -6791,6 +8073,7 @@ npm-package-arg@^6.1.0: npm-package-arg@~4.1.0: version "4.1.1" resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.1.1.tgz#86d9dca985b4c5e5d59772dfd5de6919998a495a" + integrity sha1-htncqYW0xeXVl3Lf1d5pGZmKSVo= dependencies: hosted-git-info "^2.1.4" semver "4 || 5" @@ -6798,6 +8081,7 @@ npm-package-arg@~4.1.0: npm-packlist@^1.1.6: version "1.1.10" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" + integrity sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA== dependencies: ignore-walk "^3.0.1" npm-bundled "^1.0.1" @@ -6805,6 +8089,7 @@ npm-packlist@^1.1.6: npm-registry-client@~7.0.9: version "7.0.9" resolved "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-7.0.9.tgz#1baf86ee5285c4e6d38d4556208ded56049231bb" + integrity sha1-G6+G7lKFxObTjUVWII3tVgSSMbs= dependencies: chownr "^1.0.1" concat-stream "^1.4.6" @@ -6824,16 +8109,19 @@ npm-registry-client@~7.0.9: npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= dependencies: path-key "^2.0.0" npm-user-validate@~0.1.2: version "0.1.5" resolved "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-0.1.5.tgz#52465d50c2d20294a57125b996baedbf56c5004b" + integrity sha1-UkZdUMLSApSlcSW5lrrtv1bFAEs= npm@~3.5.2: version "3.5.4" resolved "http://registry.npmjs.org/npm/-/npm-3.5.4.tgz#db2f71d3daa0e7a99077edd4c213919834e95eb2" + integrity sha1-2y9x09qg56mQd+3UwhORmDTpXrI= dependencies: abbrev "~1.0.7" ansicolors "~0.3.2" @@ -6908,6 +8196,7 @@ npm@~3.5.2: "npmlog@0 || 1", "npmlog@0.1 || 1": version "1.2.1" resolved "http://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz#28e7be619609b53f7ad1dd300a10d64d716268b6" + integrity sha1-KOe+YZYJtT960d0wChDWTXFiaLY= dependencies: ansi "~0.3.0" are-we-there-yet "~1.0.0" @@ -6916,6 +8205,7 @@ npm@~3.5.2: npmlog@^4.0.0, npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" @@ -6925,6 +8215,7 @@ npmlog@^4.0.0, npmlog@^4.0.2: npmlog@~2.0.0: version "2.0.4" resolved "http://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz#98b52530f2514ca90d09ec5b22c8846722375692" + integrity sha1-mLUlMPJRTKkNCexbIsiEZyI3VpI= dependencies: ansi "~0.3.1" are-we-there-yet "~1.1.2" @@ -6933,30 +8224,37 @@ npmlog@~2.0.0: number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= oauth-sign@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" + integrity sha1-y1QPk7srIqfVlBaRoojWDo6pOG4= oauth-sign@~0.8.0: version "0.8.2" resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM= oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE= object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" @@ -6965,16 +8263,19 @@ object-copy@^0.1.0: object-keys@^1.0.8: version "1.0.12" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" + integrity sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag== object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= dependencies: isobject "^3.0.0" object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= dependencies: for-own "^0.1.4" is-extendable "^0.1.1" @@ -6982,48 +8283,57 @@ object.omit@^2.0.0: object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= dependencies: isobject "^3.0.1" on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= dependencies: ee-first "1.1.1" on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + integrity sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c= once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" once@~1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" + integrity sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA= dependencies: wrappy "1" onetime@^1.0.0: version "1.1.0" resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k= onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= dependencies: mimic-fn "^1.0.0" opener@~1.4.1: version "1.4.3" resolved "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" + integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg= optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= dependencies: minimist "~0.0.1" wordwrap "~0.0.2" @@ -7031,6 +8341,7 @@ optimist@^0.6.1: optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= dependencies: deep-is "~0.1.3" fast-levenshtein "~2.0.4" @@ -7042,6 +8353,7 @@ optionator@^0.8.2: ora@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" + integrity sha512-hNNlAd3gfv/iPmsNxYoAPLvxg7HuPozww7fFonMZvL84tP6Ox5igfk5j/+a9rtJJwqMgKK+JgWsAQik5o0HTLA== dependencies: chalk "^2.3.1" cli-cursor "^2.1.0" @@ -7053,18 +8365,22 @@ ora@^2.0.0: os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= os-shim@^0.1.2: version "0.1.3" resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + integrity sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc= os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= osenv@0, osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4, osenv@^0.1.5, osenv@~0.1.3: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" @@ -7072,56 +8388,67 @@ osenv@0, osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4, osenv@^0.1.5, osenv@~0.1.3: p-cancelable@^0.4.0: version "0.4.1" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" + integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= p-is-promise@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== dependencies: p-try "^1.0.0" p-limit@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec" + integrity sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A== dependencies: p-try "^2.0.0" p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= dependencies: p-limit "^1.1.0" p-locate@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== dependencies: p-limit "^2.0.0" p-timeout@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" + integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== dependencies: p-finally "^1.0.0" p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= p-try@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" + integrity sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ== package-json@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" + integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0= dependencies: got "^6.7.1" registry-auth-token "^3.0.1" @@ -7131,6 +8458,7 @@ package-json@^4.0.1: parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= dependencies: glob-base "^0.3.0" is-dotfile "^1.0.0" @@ -7140,86 +8468,104 @@ parse-glob@^3.0.4: parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= dependencies: error-ex "^1.2.0" parse-ms@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d" + integrity sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0= parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= parseqs@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0= dependencies: better-assert "~1.0.0" parseuri@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo= dependencies: better-assert "~1.0.0" parseurl@~1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= passwd-user@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/passwd-user/-/passwd-user-1.2.1.tgz#a01a5dc639ef007dc56364b8178569080ad3a7b8" + integrity sha1-oBpdxjnvAH3FY2S4F4VpCArTp7g= dependencies: exec-file-sync "^2.0.0" path-array@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271" + integrity sha1-fi8PNfB6IBUSK4aLfqwOssT+wnE= dependencies: array-index "^1.0.0" path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= dependencies: pinkie-promise "^2.0.0" path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= path-is-absolute@1.0.1, path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + integrity sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME= path-posix@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + integrity sha1-BrJhE/Vr6rBCVFojv6iAA8ysJg8= path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= dependencies: graceful-fs "^4.1.2" pify "^2.0.0" @@ -7228,42 +8574,51 @@ path-type@^1.0.0: pathval@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" + integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= performance-now@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" + integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= dependencies: find-up "^2.1.0" pluralize@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== portfinder@^1.0.15: version "1.0.19" resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.19.tgz#07e87914a55242dcda5b833d42f018d6875b595f" + integrity sha512-23aeQKW9KgHe6citUrG3r9HjeX6vls0h713TAa+CwTKZwNIr/pD2ApaxYF4Um3ZZyq4ar+Siv3+fhoHaIwSOSw== dependencies: async "^1.5.2" debug "^2.2.0" @@ -7272,26 +8627,32 @@ portfinder@^1.0.15: posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= prepend-http@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= prepend-http@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= pretender@^2.1.0: version "2.1.1" resolved "https://registry.npmjs.org/pretender/-/pretender-2.1.1.tgz#5085f0a1272c31d5b57c488386f69e6ca207cb35" + integrity sha512-IkidsJzaroAanw3I43tKCFm2xCpurkQr9aPXv5/jpN+LfCwDaeI8rngVWtQZTx4qqbhc5zJspnLHJ4N/25KvDQ== dependencies: "@xg-wang/whatwg-fetch" "^3.0.0" fake-xml-http-request "^2.0.0" @@ -7300,54 +8661,65 @@ pretender@^2.1.0: prettier-linter-helpers@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== dependencies: fast-diff "^1.1.2" prettier@^1.14.3: version "1.14.3" resolved "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz#90238dd4c0684b7edce5f83b0fb7328e48bd0895" + integrity sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg== pretty-ms@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-3.2.0.tgz#87a8feaf27fc18414d75441467d411d6e6098a25" + integrity sha512-ZypexbfVUGTFxb0v+m1bUyy92DHe5SyYlnyY0msyms5zd3RwyvNgyxZZsXXgoyzlxjx5MiqtXUdhUfvQbe0A2Q== dependencies: parse-ms "^1.0.0" printf@^0.5.1: version "0.5.1" resolved "https://registry.npmjs.org/printf/-/printf-0.5.1.tgz#e0466788260859ed153006dc6867f09ddf240cf3" + integrity sha512-UaE/jO0hNsrvPGQEb4LyNzcrJv9Z00tsreBduOSxMtrebvoUhxiEJ4YCHX8YHf6akwfKsC2Gyv5zv47UXhMiLg== private@^0.1.6, private@^0.1.8, private@~0.1.5: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= process-nextick-args@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== process-relative-require@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" + integrity sha1-FZDfz1uPKYO6U+OYRGtoJAtMxoo= dependencies: node-modules-path "^1.0.0" progress@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" + integrity sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8= promise-map-series@^0.2.1, promise-map-series@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" + integrity sha1-wtN3r8kyU/a9A9u3d1XriKsgqEc= dependencies: rsvp "^3.0.14" promise.prototype.finally@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz#66f161b1643636e50e7cf201dc1b84a857f3864e" + integrity sha512-7p/K2f6dI+dM8yjRQEGrTQs5hTQixUAdOGpMEA3+pVxpX5oHKRSKAXyLw9Q9HUWDTdwtoo39dSHGQtN90HcEwQ== dependencies: define-properties "^1.1.2" es-abstract "^1.9.0" @@ -7356,16 +8728,19 @@ promise.prototype.finally@^3.1.0: promzard@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" + integrity sha1-JqXW7ox97kyxIggwWs+5O6OCqe4= dependencies: read "1" proto-list@~1.2.1: version "1.2.4" resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= proxy-addr@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" + integrity sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ== dependencies: forwarded "~0.1.2" ipaddr.js "1.6.0" @@ -7373,17 +8748,25 @@ proxy-addr@~2.0.3: proxy-addr@~2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" + integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA== dependencies: forwarded "~0.1.2" ipaddr.js "1.8.0" +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + psl@^1.1.24: version "1.1.28" resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.28.tgz#4fb6ceb08a1e2214d4fd4de0ca22dae13740bc7b" + integrity sha512-+AqO1Ae+N/4r7Rvchrdm432afjT9hqJRyBN3DQv9At0tPz4hIFSGKbq64fN9dVoCow4oggIIax5/iONx0r9hZw== pump@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== dependencies: end-of-stream "^1.1.0" once "^1.3.1" @@ -7391,30 +8774,37 @@ pump@^3.0.0: punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== qs@6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + integrity sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A== qs@6.5.2, qs@^6.4.0, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== qs@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" + integrity sha1-UKk+K1r2aRwxvOpdrnjubqGQN2g= qs@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/qs/-/qs-5.2.1.tgz#801fee030e0b9450d6385adc48a4cc55b44aedfc" + integrity sha1-gB/uAw4LlFDWOFrcSKTMVbRK7fw= query-string@^5.0.1: version "5.1.1" resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== dependencies: decode-uri-component "^0.2.0" object-assign "^4.1.0" @@ -7423,6 +8813,7 @@ query-string@^5.0.1: quibble@^0.5.5: version "0.5.5" resolved "https://registry.yarnpkg.com/quibble/-/quibble-0.5.5.tgz#669fb731520a923e0a98f8076b7eb55e409f73f9" + integrity sha512-cIePu3BtGlaTW1bjFgBcLT6QMxD8PtnZDCmPJUzO+RepIz8GuXsmZIEPGFjlPxzG9zfIj4nNLPxBDlUbvr9ESg== dependencies: lodash "^4.17.2" resolve "^1.7.1" @@ -7430,6 +8821,7 @@ quibble@^0.5.5: quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" + integrity sha1-urAqJCq4+w3XWKPJd2sy+aXZRAg= dependencies: mktemp "~0.4.0" rimraf "^2.5.4" @@ -7438,6 +8830,7 @@ quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: qunit@~2.6.0: version "2.6.2" resolved "https://registry.npmjs.org/qunit/-/qunit-2.6.2.tgz#551210c5cf857258a4fe39a7fe15d9e14dfef22c" + integrity sha512-PHbKulmd4rrDhFto7iHicIstDTX7oMRvAcI7loHstvU8J7AOGwzcchONmy+EG4KU8HDk0K90o7vO0GhlYyKlOg== dependencies: commander "2.12.2" exists-stat "1.0.0" @@ -7450,6 +8843,7 @@ qunit@~2.6.0: randomatic@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.0.0.tgz#d35490030eb4f7578de292ce6dfb04a91a128923" + integrity sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA== dependencies: is-number "^4.0.0" kind-of "^6.0.0" @@ -7458,10 +8852,12 @@ randomatic@^3.0.0: range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= raw-body@2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" + integrity sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k= dependencies: bytes "3.0.0" http-errors "1.6.2" @@ -7471,6 +8867,7 @@ raw-body@2.3.2: raw-body@2.3.3: version "2.3.3" resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== dependencies: bytes "3.0.0" http-errors "1.6.3" @@ -7480,6 +8877,7 @@ raw-body@2.3.3: raw-body@~1.1.0: version "1.1.7" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + integrity sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU= dependencies: bytes "1" string_decoder "0.10" @@ -7487,6 +8885,7 @@ raw-body@~1.1.0: rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: deep-extend "^0.6.0" ini "~1.3.0" @@ -7496,12 +8895,14 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: read-cmd-shim@~1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b" + integrity sha1-LV0Vd4ajfAVdIgd8MsU/gynpHHs= dependencies: graceful-fs "^4.1.2" read-installed@~4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" + integrity sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc= dependencies: debuglog "^1.0.1" read-package-json "^2.0.0" @@ -7515,6 +8916,7 @@ read-installed@~4.0.3: "read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@~2.0.2: version "2.0.13" resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-2.0.13.tgz#2e82ebd9f613baa6d2ebe3aa72cefe3f68e41f4a" + integrity sha512-/1dZ7TRZvGrYqE0UAfN6qQb5GYBsNcqS1C0tNK601CFOJmtHI7NIGXwetEPU/OtoFHZL3hDxm4rolFFVE9Bnmg== dependencies: glob "^7.1.1" json-parse-better-errors "^1.0.1" @@ -7526,6 +8928,7 @@ read-installed@~4.0.3: read-package-tree@~5.1.2: version "5.1.6" resolved "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.1.6.tgz#4f03e83d0486856fb60d97c94882841c2a7b1b7a" + integrity sha512-FCX1aT3GWyY658wzDICef4p+n0dB+ENRct8E/Qyvppj6xVpOYerBHfUu7OP5Rt1/393Tdglguf5ju5DEX4wZNg== dependencies: debuglog "^1.0.1" dezalgo "^1.0.0" @@ -7536,6 +8939,7 @@ read-package-tree@~5.1.2: read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= dependencies: find-up "^1.0.0" read-pkg "^1.0.0" @@ -7543,6 +8947,7 @@ read-pkg-up@^1.0.1: read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" @@ -7551,12 +8956,14 @@ read-pkg@^1.0.0: read@1, read@~1.0.1, read@~1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" + integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= dependencies: mute-stream "~0.0.4" "readable-stream@1 || 2", readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -7569,6 +8976,7 @@ read@1, read@~1.0.1, read@~1.0.7: readable-stream@~1.0.2: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -7578,6 +8986,7 @@ readable-stream@~1.0.2: readable-stream@~2.0.5: version "2.0.6" resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -7589,6 +8998,7 @@ readable-stream@~2.0.5: readdir-scoped-modules@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" + integrity sha1-n6+jfShr5dksuuve4DDcm19AZ0c= dependencies: debuglog "^1.0.1" dezalgo "^1.0.0" @@ -7598,6 +9008,7 @@ readdir-scoped-modules@^1.0.0: realize-package-specifier@~3.0.1: version "3.0.3" resolved "https://registry.npmjs.org/realize-package-specifier/-/realize-package-specifier-3.0.3.tgz#d0def882952b8de3f67eba5e91199661271f41f4" + integrity sha1-0N74gpUrjeP2frpekRmWYScfQfQ= dependencies: dezalgo "^1.0.1" npm-package-arg "^4.1.1" @@ -7605,6 +9016,7 @@ realize-package-specifier@~3.0.1: recast@^0.11.3: version "0.11.23" resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" + integrity sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM= dependencies: ast-types "0.9.6" esprima "~3.1.0" @@ -7614,6 +9026,7 @@ recast@^0.11.3: redent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= dependencies: indent-string "^2.1.0" strip-indent "^1.0.1" @@ -7621,34 +9034,41 @@ redent@^1.0.0: redeyed@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" + integrity sha1-6WwZO0DAgWsArshCaY5hGF5VSYo= dependencies: esprima "~3.0.0" regenerate-unicode-properties@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz#107405afcc4a190ec5ed450ecaa00ed0cafa7a4c" + integrity sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw== dependencies: regenerate "^1.4.0" regenerate@^1.2.1, regenerate@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== regenerator-runtime@^0.10.5: version "0.10.5" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + integrity sha1-M2w+/BIgrc7dosn6tntaeVWjNlg= regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== regenerator-runtime@^0.9.5: version "0.9.6" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" + integrity sha1-0z65XQ0gAaS+OWWXB8UbDLcc4Ck= regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + integrity sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q== dependencies: babel-runtime "^6.18.0" babel-types "^6.19.0" @@ -7657,18 +9077,21 @@ regenerator-transform@^0.10.0: regenerator-transform@^0.13.3: version "0.13.3" resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.3.tgz#264bd9ff38a8ce24b06e0636496b2c856b57bcbb" + integrity sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA== dependencies: private "^0.1.6" regex-cache@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== dependencies: is-equal-shallow "^0.1.3" regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== dependencies: extend-shallow "^3.0.2" safe-regex "^1.1.0" @@ -7676,14 +9099,17 @@ regex-not@^1.0.0, regex-not@^1.0.2: regexpp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.0.tgz#b2a7534a85ca1b033bcf5ce9ff8e56d4e0755365" + integrity sha512-g2FAVtR8Uh8GO1Nv5wpxW7VFVwHcCEr4wyA8/MHiRkO8uHoR5ntAA8Uq3P1vvMTX/BeQiRVSpDGLd+Wn5HNOTA== regexpp@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + integrity sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA= dependencies: regenerate "^1.2.1" regjsgen "^0.2.0" @@ -7692,6 +9118,7 @@ regexpu-core@^2.0.0: regexpu-core@^4.1.3, regexpu-core@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.2.0.tgz#a3744fa03806cffe146dea4421a3e73bdcc47b1d" + integrity sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw== dependencies: regenerate "^1.4.0" regenerate-unicode-properties "^7.0.0" @@ -7703,6 +9130,7 @@ regexpu-core@^4.1.3, regexpu-core@^4.2.0: registry-auth-token@^3.0.1: version "3.3.2" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" + integrity sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ== dependencies: rc "^1.1.6" safe-buffer "^5.0.1" @@ -7710,32 +9138,38 @@ registry-auth-token@^3.0.1: registry-url@^3.0.3: version "3.1.0" resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI= dependencies: rc "^1.0.1" regjsgen@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc= regjsgen@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.4.0.tgz#c1eb4c89a209263f8717c782591523913ede2561" + integrity sha512-X51Lte1gCYUdlwhF28+2YMO0U6WeN0GLpgpA7LK7mbdDnkQYiwvEpmpe0F/cv5L14EbxgrdayAG3JETBv0dbXA== regjsparser@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw= dependencies: jsesc "~0.5.0" regjsparser@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.3.0.tgz#3c326da7fcfd69fa0d332575a41c8c0cdf588c96" + integrity sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA== dependencies: jsesc "~0.5.0" remote-git-tags@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/remote-git-tags/-/remote-git-tags-2.0.0.tgz#1152f39cf8b5268ae0e4307636ef741ec341664c" + integrity sha1-EVLznPi1Jorg5DB2Nu90HsNBZkw= dependencies: git-fetch-pack "^0.1.1" git-transport-protocol "^0.1.0" @@ -7743,24 +9177,29 @@ remote-git-tags@^2.0.0: remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + integrity sha1-7wiaF40Ug7quTZPrmLT55OEdmQo= repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= repeating@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= dependencies: is-finite "^1.0.0" request@2, request@^2.47.0: version "2.88.0" resolved "https://registry.npmjs.org/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -7786,6 +9225,7 @@ request@2, request@^2.47.0: request@~2.40.0: version "2.40.0" resolved "https://registry.yarnpkg.com/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" + integrity sha1-TdZw9pbx5uhC5mtLXoOTAaub62c= dependencies: forever-agent "~0.5.0" json-stringify-safe "~5.0.0" @@ -7805,6 +9245,7 @@ request@~2.40.0: request@~2.67.0: version "2.67.0" resolved "http://registry.npmjs.org/request/-/request-2.67.0.tgz#8af74780e2bf11ea0ae9aa965c11f11afd272742" + integrity sha1-ivdHgOK/EeoK6aqWXBHxGv0nJ0I= dependencies: aws-sign2 "~0.6.0" bl "~1.0.0" @@ -7830,14 +9271,17 @@ request@~2.67.0: require-dir@^0.3.0: version "0.3.2" resolved "https://registry.npmjs.org/require-dir/-/require-dir-0.3.2.tgz#c1d5c75e9fbffde9f2e6b33e383db4f594b5a6a9" + integrity sha1-wdXHXp+//eny5rM+OD209ZS1pqk= require-relative@^0.8.7: version "0.8.7" resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" + integrity sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4= require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM= dependencies: caller-path "^0.1.0" resolve-from "^1.0.0" @@ -7845,14 +9289,17 @@ require-uncached@^1.0.3: requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= reselect@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147" + integrity sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc= resolve-dir@^1.0.0, resolve-dir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= dependencies: expand-tilde "^2.0.0" global-modules "^1.0.0" @@ -7860,10 +9307,12 @@ resolve-dir@^1.0.0, resolve-dir@^1.0.1: resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY= resolve-path@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7" + integrity sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc= dependencies: http-errors "~1.6.2" path-is-absolute "1.0.1" @@ -7871,28 +9320,33 @@ resolve-path@^1.4.0: resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= resolve@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" + integrity sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw== dependencies: path-parse "^1.0.5" resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.7.1, resolve@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" + integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== dependencies: path-parse "^1.0.5" responselike@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= dependencies: lowercase-keys "^1.0.0" restore-cursor@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + integrity sha1-NGYfRohjJ/7SmRR5FSJS35LapUE= dependencies: exit-hook "^1.0.0" onetime "^1.0.0" @@ -7900,6 +9354,7 @@ restore-cursor@^1.0.1: restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= dependencies: onetime "^2.0.0" signal-exit "^3.0.2" @@ -7907,36 +9362,43 @@ restore-cursor@^2.0.0: ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== retry@^0.8.0, retry@~0.8.0: version "0.8.0" resolved "https://registry.npmjs.org/retry/-/retry-0.8.0.tgz#2367628dc0edb247b1eab649dc53ac8628ac2d5f" + integrity sha1-I2dijcDtskex6rZJ3FOshiisLV8= right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8= dependencies: align-text "^0.1.1" rimraf@2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== dependencies: glob "^7.0.5" rimraf@~2.2.6: version "2.2.8" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + integrity sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI= rimraf@~2.5.0: version "2.5.4" resolved "http://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + integrity sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ= dependencies: glob "^7.0.5" rollup-pluginutils@^2.0.1: version "2.3.0" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.3.0.tgz#478ace04bd7f6da2e724356ca798214884738fc4" + integrity sha512-xB6hsRsjdJdIYWEyYUJy/3ki5g69wrf0luHPGNK3ZSocV6HLNfio59l3dZ3TL4xUwEKgROhFi9jOCt6c5gfUWw== dependencies: estree-walker "^0.5.2" micromatch "^2.3.11" @@ -7944,6 +9406,7 @@ rollup-pluginutils@^2.0.1: rollup@^0.57.1: version "0.57.1" resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.57.1.tgz#0bb28be6151d253f67cf4a00fea48fb823c74027" + integrity sha512-I18GBqP0qJoJC1K1osYjreqA8VAKovxuI3I81RSk0Dmr4TgloI0tAULjZaox8OsJ+n7XRrhH6i0G2By/pj1LCA== dependencies: "@types/acorn" "^4.0.3" acorn "^5.5.3" @@ -7960,68 +9423,83 @@ rollup@^0.57.1: route-recognizer@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" + integrity sha1-HTZeJ/ppleCRZ199yUCowANTvSk= rsvp@3.0.14: version "3.0.14" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.14.tgz#9d2968cf36d878d3bb9a9a5a4b8e1ff55a76dd31" + integrity sha1-nSlozzbYeNO7mppaS44f9Vp23TE= rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3: version "3.6.2" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" + integrity sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw== rsvp@^4.7.0, rsvp@^4.8.1, rsvp@^4.8.2, rsvp@^4.8.3: version "4.8.3" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.3.tgz#25d4b9fdd0f95e216eb5884d9b3767d3fbfbe2cd" + integrity sha512-/OlbK31XtkPnLD2ktmZXj4g/v6q1boTDr6/3lFuDTgxVsrA3h7PH5eYyAxIvDMjRHr/DoOlzNicqDwBEo9xU7g== rsvp@^4.8.4: version "4.8.4" resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.4.tgz#b50e6b34583f3dd89329a2f23a8a2be072845911" + integrity sha512-6FomvYPfs+Jy9TfXmBpBuMWNH94SgCsZmJKcanySzgNNP6LjWxBvyLTa9KaMfDDM5oxRfrKDB0r/qeRsLwnBfA== rsvp@~3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + integrity sha1-B8tKXfJa3Z6Cbrxn3Mn9idsn2Eo= run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= dependencies: is-promise "^2.1.0" rx@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I= rxjs@^6.1.0: version "6.3.3" resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz#3c6a7fa420e844a81390fb1158a9ec614f4bad55" + integrity sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw== dependencies: tslib "^1.9.0" safe-buffer@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== safe-json-parse@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" + integrity sha1-PnZyPjjf3aE8mx0poeB//uSzC1c= safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= dependencies: ret "~0.1.10" "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sane@^2.4.1, sane@^2.5.2: version "2.5.2" resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" + integrity sha1-tNwYYcIbQn6SlQej51HiosuKs/o= dependencies: anymatch "^2.0.0" capture-exit "^1.2.0" @@ -8037,6 +9515,7 @@ sane@^2.4.1, sane@^2.5.2: sane@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/sane/-/sane-4.0.1.tgz#af1e10466e924e1b888c104bb9925a0f1beb46dd" + integrity sha512-12M/pR2HqW0aPKBAnwBerocN/6BbdAydw/gzGouHOeOpLmam46uS2xwtI+Yl5ZRqPDaakEsYtXkW9q/D5aJSdQ== dependencies: anymatch "^2.0.0" capture-exit "^1.2.0" @@ -8051,26 +9530,32 @@ sane@^4.0.0: sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== "semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.5.1, semver@^5.6.0: version "5.6.0" resolved "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== "semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== semver@^4.3.1: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + integrity sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto= semver@~5.1.0: version "5.1.1" resolved "http://registry.npmjs.org/semver/-/semver-5.1.1.tgz#a3292a373e6f3e0798da0b20641b9a9c5bc47e19" + integrity sha1-oykqNz5vPgeY2gsgZBuanFvEfhk= send@0.16.2: version "0.16.2" resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== dependencies: debug "2.6.9" depd "~1.1.2" @@ -8089,6 +9574,7 @@ send@0.16.2: serve-static@1.13.2: version "1.13.2" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" @@ -8098,10 +9584,12 @@ serve-static@1.13.2: set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= set-value@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -8111,6 +9599,7 @@ set-value@^0.4.3: set-value@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -8120,14 +9609,17 @@ set-value@^2.0.0: setprototypeof@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + integrity sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ= setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== sha@~2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae" + integrity sha1-YDCCL70smCOUn49y7WQR7lzyWq4= dependencies: graceful-fs "^4.1.2" readable-stream "^2.0.2" @@ -8135,54 +9627,65 @@ sha@~2.0.1: shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== sigmund@~1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= silent-error@^1.0.0, silent-error@^1.0.1, silent-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/silent-error/-/silent-error-1.1.0.tgz#2209706f1c850a9f1d10d0d840918b46f26e1bc9" + integrity sha1-IglwbxyFCp8dENDYQJGLRvJuG8k= dependencies: debug "^2.2.0" silent-error@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.1.1.tgz#f72af5b0d73682a2ba1778b7e32cd8aa7c2d8662" + integrity sha512-n4iEKyNcg4v6/jpb3c0/iyH2G1nzUNl7Gpqtn/mHIJK9S/q/7MCfoO4rwVOoO59qPFIc0hVHvMbiOJ0NdtxKKw== dependencies: debug "^2.2.0" slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= slice-ansi@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== dependencies: is-fullwidth-code-point "^2.0.0" slide@^1.1.3, slide@^1.1.5, slide@~1.1.3, slide@~1.1.6: version "1.1.6" resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== dependencies: define-property "^1.0.0" isobject "^3.0.0" @@ -8191,12 +9694,14 @@ snapdragon-node@^2.0.1: snapdragon-util@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== dependencies: kind-of "^3.2.0" snapdragon@^0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== dependencies: base "^0.11.1" debug "^2.2.0" @@ -8210,22 +9715,26 @@ snapdragon@^0.8.1: sntp@0.2.x: version "0.2.4" resolved "https://registry.yarnpkg.com/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" + integrity sha1-+4hfGLDzqtGJ+CSGJTa87ux1CQA= dependencies: hoek "0.9.x" sntp@1.x.x: version "1.0.9" resolved "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + integrity sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg= dependencies: hoek "2.x.x" socket.io-adapter@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" + integrity sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs= socket.io-client@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" + integrity sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ== dependencies: backo2 "1.0.2" base64-arraybuffer "0.1.5" @@ -8245,6 +9754,7 @@ socket.io-client@2.1.1: socket.io-parser@~3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" + integrity sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA== dependencies: component-emitter "1.2.1" debug "~3.1.0" @@ -8253,6 +9763,7 @@ socket.io-parser@~3.2.0: socket.io@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" + integrity sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA== dependencies: debug "~3.1.0" engine.io "~3.2.0" @@ -8264,16 +9775,19 @@ socket.io@^2.1.0: sort-keys@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= dependencies: is-plain-obj "^1.0.0" sort-object-keys@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" + integrity sha1-06bEjcKsl+a8lDZ2luA/bQnTeVI= sort-package-json@^1.15.0: version "1.16.0" resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.16.0.tgz#087f5ce05b6faca373312e7124918e0d68492d7b" + integrity sha512-QFJNxdpp7zZgSkmAIaMrteqqxGP4TkooKrGtslM2qYiML92PTYDOFOk+lG+TdvJzjheD502UFIys2qSvQljKaw== dependencies: detect-indent "^5.0.0" sort-object-keys "^1.1.2" @@ -8281,10 +9795,12 @@ sort-package-json@^1.15.0: sorted-object@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/sorted-object/-/sorted-object-1.0.0.tgz#5d1f4f9c1fb2cd48965967304e212eb44cfb6d05" + integrity sha1-XR9PnB+yzUiWWWcwTiEutEz7bQU= source-map-resolve@^0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== dependencies: atob "^2.1.1" decode-uri-component "^0.2.0" @@ -8295,12 +9811,14 @@ source-map-resolve@^0.5.0: source-map-support@^0.4.15: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== dependencies: source-map "^0.5.6" source-map-support@~0.5.6: version "0.5.6" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.6.tgz#4435cee46b1aab62b8e8610ce60f788091c51c13" + integrity sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -8308,38 +9826,46 @@ source-map-support@~0.5.6: source-map-url@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" + integrity sha1-fsrxO1e80J2opAxdJp2zN5nUqvk= source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + integrity sha1-66T12pwNyZneaAMti092FzZSA2s= dependencies: amdefine ">=0.0.4" source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0, source-map@~0.5.1: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== source-map@~0.1.x: version "0.1.43" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + integrity sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y= dependencies: amdefine ">=0.0.4" sourcemap-codec@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.1.tgz#c8fd92d91889e902a07aee392bdd2c5863958ba2" + integrity sha512-hX1eNBNuilj8yfFnECh0DzLgwKpBLMIvmhgEhixXNui8lMLBInTI8Kyxt++RwJnMNu7cAUo635L2+N1TxMJCzA== sourcemap-validator@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/sourcemap-validator/-/sourcemap-validator-1.1.0.tgz#00454547d1682186e1498a7208e022e8dfa8738f" + integrity sha512-Hmdu39KL+EoAAZ69OTk7RXXJdPRRizJvOZOWhCW9jLGfEQflCNPTlSoCXFPdKWFwwf0uzLcGR/fc7EP/PT8vRQ== dependencies: jsesc "~0.3.x" lodash.foreach "~2.3.x" @@ -8349,10 +9875,12 @@ sourcemap-validator@^1.1.0: spawn-args@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" + integrity sha1-+30L0dcP1DFr2ePew4nmX51jYbs= spawn-sync@^1.0.11, spawn-sync@^1.0.15: version "1.0.15" resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + integrity sha1-sAeZVX63+wyDdsKdROih6mfldHY= dependencies: concat-stream "^1.4.7" os-shim "^0.1.2" @@ -8360,10 +9888,12 @@ spawn-sync@^1.0.11, spawn-sync@^1.0.15: spawnback@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" + integrity sha1-9zZi9+VNlTZ+ynTWQmxnfdfqaG8= spdx-correct@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" + integrity sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" @@ -8371,10 +9901,12 @@ spdx-correct@^3.0.0: spdx-exceptions@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" + integrity sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg== spdx-expression-parse@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" @@ -8382,28 +9914,34 @@ spdx-expression-parse@^3.0.0: spdx-license-ids@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" + integrity sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA== split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== dependencies: extend-shallow "^3.0.0" sprintf-js@^1.0.3: version "1.1.1" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" + integrity sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw= sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sri-toolbox@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" + integrity sha1-p/6lw/3lXmdc8cjAbz67XCk1g14= sshpk@^1.7.0: version "1.15.1" resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.15.1.tgz#b79a089a732e346c6e0714830f36285cd38191a2" + integrity sha512-mSdgNUaidk+dRU5MhYtN9zebdzF2iG0cNPWy8HG+W8y+fT1JnSkh0fzzpjOa0L7P8i1Rscz38t0h4gPcKz43xA== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -8415,9 +9953,17 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +stagehand@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stagehand/-/stagehand-1.0.0.tgz#79515e2ad3a02c63f8720c7df9b6077ae14276d9" + integrity sha512-zrXl0QixAtSHFyN1iv04xOBgplbT4HgC8T7g+q8ESZbDNi5uZbMtxLukFVXPJ5Nl7zCYvYcrT3Mj24WYCH93hw== + dependencies: + debug "^4.1.0" + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= dependencies: define-property "^0.2.5" object-copy "^0.1.0" @@ -8425,26 +9971,32 @@ static-extend@^0.1.1: "statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2": version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= statuses@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4= statuses@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= string-template@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0= string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -8453,6 +10005,7 @@ string-width@^1.0.1: "string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" @@ -8460,16 +10013,19 @@ string-width@^1.0.1: string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.0" stringify-object-es5@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/stringify-object-es5/-/stringify-object-es5-2.5.0.tgz#057c3c9a90a127339bb9d1704a290bb7bd0a1ec5" + integrity sha1-BXw8mpChJzObudFwSikLt70KHsU= dependencies: is-plain-obj "^1.0.0" is-regexp "^1.0.0" @@ -8477,70 +10033,84 @@ stringify-object-es5@^2.5.0: stringstream@~0.0.4: version "0.0.6" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" + integrity sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA== strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= dependencies: ansi-regex "^2.0.0" strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= dependencies: ansi-regex "^3.0.0" strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= dependencies: is-utf8 "^0.2.0" strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= strip-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= dependencies: get-stdin "^4.0.1" strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= styled_string@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" + integrity sha1-0ieCvYEpVFm8Tx3xjEutjpTdEko= sum-up@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" + integrity sha1-HGYfZnBX9jvLeHWqFDi8FiUlFW4= dependencies: chalk "^1.0.0" supports-color@5.4.0, supports-color@^5.3.0: version "5.4.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== dependencies: has-flag "^3.0.0" supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" + integrity sha512-W31+GLiBmU/ZR02Ii0mVZICuNEN9daZ63xZMPDsYgPgNjMtg+atqLEGI7PPI936jYSQZxoLb/63xos8Adrx4Eg== table@^5.0.2: version "5.1.0" resolved "https://registry.npmjs.org/table/-/table-5.1.0.tgz#69a54644f6f01ad1628f8178715b408dc6bf11f7" + integrity sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg== dependencies: ajv "^6.5.3" lodash "^4.17.10" @@ -8550,6 +10120,7 @@ table@^5.0.2: tap-parser@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-7.0.0.tgz#54db35302fda2c2ccc21954ad3be22b2cba42721" + integrity sha512-05G8/LrzqOOFvZhhAk32wsGiPZ1lfUrl+iV7+OkKgfofZxiceZWMHkKmow71YsyVQ8IvGBP2EjcIjE5gL4l5lA== dependencies: events-to-array "^1.0.1" js-yaml "^3.2.7" @@ -8558,6 +10129,7 @@ tap-parser@^7.0.0: tar@^2.0.0, tar@~2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= dependencies: block-stream "*" fstream "^1.0.2" @@ -8566,6 +10138,7 @@ tar@^2.0.0, tar@~2.2.1: tar@^4: version "4.4.4" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" + integrity sha512-mq9ixIYfNF9SK0IS/h2HKMu8Q2iaCuhDDsZhdEag/FHv8fOaYld4vN7ouMgcSSt5WKZzPs8atclTcJm36OTh4w== dependencies: chownr "^1.0.1" fs-minipass "^1.2.5" @@ -8578,6 +10151,7 @@ tar@^4: temp@0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" + integrity sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k= dependencies: os-tmpdir "^1.0.0" rimraf "~2.2.6" @@ -8585,6 +10159,7 @@ temp@0.8.3: terser@^3.7.5: version "3.8.1" resolved "https://registry.yarnpkg.com/terser/-/terser-3.8.1.tgz#cb70070ac9e0a71add169dfb63c0a64fca2738ac" + integrity sha512-FRin3gKQ0vm0xPPLuxw1FqpVgv1b2pBpYCaFb5qe6A7sD749Fnq1VbDiX3CEFM0BV0fqDzFtBfgmxhxCdzKQIg== dependencies: commander "~2.16.0" source-map "~0.6.1" @@ -8593,6 +10168,7 @@ terser@^3.7.5: testdouble@^3.2.6: version "3.8.1" resolved "https://registry.yarnpkg.com/testdouble/-/testdouble-3.8.1.tgz#8c74b6807f82fb07c2387a0640b4ae594b09b964" + integrity sha512-ZOxGwLHCh47HIRqpPVAH3c/oFRu4kGgQxvDJV5db2QFH4/2JRIEUWVvnY9n4HRU5KgxVzHcL+ecjwzBE7r44Zw== dependencies: es6-map "^0.1.5" lodash "^4.17.4" @@ -8603,6 +10179,7 @@ testdouble@^3.2.6: testem@^2.9.2: version "2.13.0" resolved "https://registry.npmjs.org/testem/-/testem-2.13.0.tgz#587f3460a923779949804efac0fcc2015835dd63" + integrity sha512-n0XBuEi/3SqnXfwUWtHVIUn2/j4LouJeOJrZMfwdXmZRKr15cH7cV59e9c3rFa4AvspAn9lOXcaMBysPC5jHZg== dependencies: backbone "^1.1.2" bluebird "^3.4.6" @@ -8636,34 +10213,42 @@ testem@^2.9.2: text-table@^0.2.0, text-table@~0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= "textextensions@1 || 2": version "2.2.0" resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" + integrity sha512-j5EMxnryTvKxwH2Cq+Pb43tsf6sdEgw6Pdwxk83mPaq0ToeFJt6WE4J3s5BqY7vmjlLgkgXvhtXUxo80FyBhCA== theredoc@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/theredoc/-/theredoc-1.0.0.tgz#bcace376af6feb1873efbdd0f91ed026570ff062" + integrity sha512-KU3SA3TjRRM932jpNfD3u4Ec3bSvedyo5ITPI7zgWYnKep7BwQQaxlhI9qbO+lKJoRnoAbEVfMcAHRuKVYikDA== through@^2.3.6, through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= through@~2.2.0, through@~2.2.7: version "2.2.7" resolved "https://registry.yarnpkg.com/through/-/through-2.2.7.tgz#6e8e21200191d4eb6a99f6f010df46aa1c6eb2bd" + integrity sha1-bo4hIAGR1OtqmfbwEN9Gqhxusr0= time-zone@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/time-zone/-/time-zone-1.0.0.tgz#99c5bf55958966af6d06d83bdf3800dc82faec5d" + integrity sha1-mcW/VZWJZq9tBtg73zgA3IL67F0= timed-out@^4.0.0, timed-out@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= tiny-lr@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" + integrity sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA== dependencies: body "^5.1.0" debug "^3.1.0" @@ -8675,6 +10260,7 @@ tiny-lr@^1.1.1: tmp-sync@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" + integrity sha1-ugTZSo7ZwPNaVHOZcHkvmXpswcg= dependencies: fs-sync "^1.0.4" osenv "^0.1.0" @@ -8682,46 +10268,55 @@ tmp-sync@^1.0.0: tmp@0.0.28: version "0.0.28" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" + integrity sha1-Fyc1t/YU6nrzlmT6hM8N5OUV0SA= dependencies: os-tmpdir "~1.0.1" tmp@0.0.33, tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== dependencies: os-tmpdir "~1.0.2" tmp@^0.0.29: version "0.0.29" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" + integrity sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA= dependencies: os-tmpdir "~1.0.1" tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= to-array@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= dependencies: kind-of "^3.0.2" to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= dependencies: is-number "^3.0.0" repeat-string "^1.6.1" @@ -8729,6 +10324,7 @@ to-regex-range@^2.1.0: to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== dependencies: define-property "^2.0.2" extend-shallow "^3.0.2" @@ -8738,10 +10334,12 @@ to-regex@^3.0.1, to-regex@^3.0.2: to-utf8@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" + integrity sha1-0Xrqcv8vujm55DYBvns/9y4ImFI= tough-cookie@>=0.12.0, tough-cookie@~2.4.3: version "2.4.3" resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== dependencies: psl "^1.1.24" punycode "^1.4.1" @@ -8749,10 +10347,12 @@ tough-cookie@>=0.12.0, tough-cookie@~2.4.3: tough-cookie@~2.2.0: version "2.2.2" resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz#c83a1830f4e5ef0b93ef2a3488e724f8de016ac7" + integrity sha1-yDoYMPTl7wuT7yo0iOck+N4Basc= tree-sync@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" + integrity sha1-LPdrhYn1n/7bWNtaOsfLAT0BWLc= dependencies: debug "^2.2.0" fs-tree-diff "^0.5.6" @@ -8763,50 +10363,61 @@ tree-sync@^1.2.2: trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= tslib@^1.9.0: version "1.9.3" resolved "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" + integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= dependencies: safe-buffer "^5.0.1" tunnel-agent@~0.4.0, tunnel-agent@~0.4.1: version "0.4.3" resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + integrity sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us= tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= dependencies: prelude-ls "~1.1.2" type-detect@0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" + integrity sha1-C6XsKohWQORw6k6FBZcZANrFiCI= type-detect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" + integrity sha1-diIXzAbbJY7EiQihKY6LlRIejqI= type-detect@^4.0.0: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== type-is@~1.6.15, type-is@~1.6.16: version "1.6.16" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== dependencies: media-typer "0.3.0" mime-types "~2.1.18" @@ -8814,14 +10425,22 @@ type-is@~1.6.15, type-is@~1.6.16: typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +typescript@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.3.tgz#01b70247a6d3c2467f70c45795ef5ea18ce191d5" + integrity sha512-+81MUSyX+BaSo+u2RbozuQk/UWx6hfG0a5gHu4ANEM4sU96XbuIyAB+rWBW1u70c6a5QuZfuYICn3s2UjuHUpA== uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" + integrity sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg== uglify-js@^2.6: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" + integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0= dependencies: source-map "~0.5.1" yargs "~3.10.0" @@ -8831,6 +10450,7 @@ uglify-js@^2.6: uglify-js@^3.1.4: version "3.4.9" resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" + integrity sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q== dependencies: commander "~2.17.1" source-map "~0.6.1" @@ -8838,22 +10458,27 @@ uglify-js@^3.1.4: uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc= uid-number@0.0.6: version "0.0.6" resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== umask@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" + integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= underscore.string@^3.2.2, underscore.string@~3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" + integrity sha1-LCo/n4PmR2L9xF5s6sZRQoZCE9s= dependencies: sprintf-js "^1.0.3" util-deprecate "^1.0.2" @@ -8861,14 +10486,17 @@ underscore.string@^3.2.2, underscore.string@~3.3.4: underscore@>=1.8.3: version "1.9.1" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" + integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== unicode-match-property-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== dependencies: unicode-canonical-property-names-ecmascript "^1.0.4" unicode-property-aliases-ecmascript "^1.0.4" @@ -8876,14 +10504,17 @@ unicode-match-property-ecmascript@^1.0.4: unicode-match-property-value-ecmascript@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz#9f1dc76926d6ccf452310564fd834ace059663d4" + integrity sha512-Rx7yODZC1L/T8XKo/2kNzVAQaRE88AaMvI1EF/Xnj3GW2wzN6fop9DDWuFAKUVFH7vozkz26DzP0qyWLKLIVPQ== unicode-property-aliases-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz#5a533f31b4317ea76f17d807fa0d116546111dd0" + integrity sha512-2WSLa6OdYd2ng8oqiGIWnJqyFArvhn+5vgx5GTxMbUYjCYKUcuKS62YLFF0R/BDGlB1yzXjQOLtPAfHsgirEpg== union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= dependencies: arr-union "^3.1.0" get-value "^2.0.6" @@ -8893,32 +10524,38 @@ union-value@^1.0.0: unique-filename@~1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== dependencies: unique-slug "^2.0.0" unique-slug@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz#5e9edc6d1ce8fb264db18a507ef9bd8544451ca6" + integrity sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg== dependencies: imurmurhash "^0.1.4" unique-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo= dependencies: crypto-random-string "^1.0.0" universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= dependencies: has-value "^0.3.1" isobject "^3.0.0" @@ -8926,46 +10563,55 @@ unset-value@^1.0.0: untildify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" + integrity sha1-F+soB5h/dpUunASF/DEdBqgmouA= dependencies: os-homedir "^1.0.0" unzip-response@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" + integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c= uri-js@^4.2.2: version "4.2.2" resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== dependencies: punycode "^2.1.0" urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= url-parse-lax@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= dependencies: prepend-http "^1.0.1" url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= dependencies: prepend-http "^2.0.0" url-to-options@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== user-info@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/user-info/-/user-info-1.0.0.tgz#81c82b7ed63e674c2475667653413b3c76fde239" + integrity sha1-gcgrftY+Z0wkdWZ2U0E7PHb94jk= dependencies: os-homedir "^1.0.1" passwd-user "^1.2.1" @@ -8974,32 +10620,39 @@ user-info@^1.0.0: username-sync@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/username-sync/-/username-sync-1.0.1.tgz#1cde87eefcf94b8822984d938ba2b797426dae1f" + integrity sha1-HN6H7vz5S4gimE2Ti6K3l0Jtrh8= username@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/username/-/username-1.0.1.tgz#e1f72295e3e58e06f002c6327ce06897a99cd67f" + integrity sha1-4fcilePljgbwAsYyfOBol6mc1n8= dependencies: meow "^3.4.0" util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= util-extend@^1.0.1: version "1.0.3" resolved "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" + integrity sha1-p8IW0mdUUWljeztu3GypEZ4v+T8= utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= uuid@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== validate-npm-package-license@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" + integrity sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g== dependencies: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" @@ -9007,22 +10660,26 @@ validate-npm-package-license@^3.0.1: validate-npm-package-name@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= dependencies: builtins "^1.0.3" validate-npm-package-name@~2.2.2: version "2.2.2" resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-2.2.2.tgz#f65695b22f7324442019a3c7fa39a6e7fd299085" + integrity sha1-9laVsi9zJEQgGaPH+jmm5/0pkIU= dependencies: builtins "0.0.7" vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= verror@1.10.0: version "1.10.0" resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= dependencies: assert-plus "^1.0.0" core-util-is "1.0.2" @@ -9031,6 +10688,7 @@ verror@1.10.0: walk-sync@0.3.2, walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" + integrity sha512-FMB5VqpLqOCcqrzA9okZFc0wq0Qbmdm396qJxvQZhDpyu0W95G9JCmp74tx7iyYnyOcBtUuKJsgIKAqjozvmmQ== dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" @@ -9038,6 +10696,7 @@ walk-sync@0.3.2, walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2: walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" + integrity sha1-tJvk7mhnZXrrc2l4tWop0Q+jmWk= dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" @@ -9045,6 +10704,7 @@ walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: walk-sync@^0.3.3: version "0.3.3" resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.3.tgz#1e9f12cd4fe6e0e6d4a0715b5cc7e30711d43cd1" + integrity sha512-jQgTHmCazUngGqvHZFlr30u2VLKEKErBMLFe+fBl5mn4rh9aI/QVRog8PT1hv2vaOu4EBwigfmpRTyZrbnpRVA== dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" @@ -9052,12 +10712,14 @@ walk-sync@^0.3.3: walker@~1.0.5: version "1.0.7" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= dependencies: makeerror "1.0.x" watch-detector@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/watch-detector/-/watch-detector-0.1.0.tgz#e37b410d149e2a8bf263a4f8b71e2f667633dbf8" + integrity sha512-vfzMMfpjQc88xjETwl2HuE6PjEuxCBeyC4bQmqrHrofdfYWi/4mEJklYbNgSzpqM9PxubsiPIrE5SZ1FDyiQ2w== dependencies: heimdalljs-logger "^0.1.9" quick-temp "^0.1.8" @@ -9068,6 +10730,7 @@ watch-detector@^0.1.0: watch@~0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + integrity sha1-KAlUdsbffJDJYxOJkMClQj60uYY= dependencies: exec-sh "^0.2.0" minimist "^1.2.0" @@ -9075,12 +10738,14 @@ watch@~0.18.0: wcwidth@^1.0.0, wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= dependencies: defaults "^1.0.3" websocket-driver@>=0.5.1: version "0.7.0" resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" + integrity sha1-DK+dLXVdk67gSdS90NP+LMoqJOs= dependencies: http-parser-js ">=0.4.0" websocket-extensions ">=0.1.1" @@ -9088,60 +10753,72 @@ websocket-driver@>=0.5.1: websocket-extensions@>=0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== which@1, which@^1.2.14, which@^1.2.9, which@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" which@~1.2.1: version "1.2.14" resolved "https://registry.npmjs.org/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" + integrity sha1-mofEN48D6CfOyvGs31bHNsAcFOU= dependencies: isexe "^2.0.0" wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== dependencies: string-width "^1.0.2 || 2" window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0= wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8= wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= workerpool@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-2.3.0.tgz#86c5cbe946b55e7dc9d12b1936c8801a6e2d744d" + integrity sha512-JP5DpviEV84zDmz13QnD4FfRjZBjnTOYY2O4pGgxtlqLh47WOzQFHm8o17TE5OSfcDoKC6vHSrN4yPju93DW0Q== dependencies: object-assign "4.1.1" workerpool@^2.3.1: version "2.3.3" resolved "https://registry.npmjs.org/workerpool/-/workerpool-2.3.3.tgz#49a70089bd55e890d68cc836a19419451d7c81d7" + integrity sha512-L1ovlYHp6UObYqElXXpbd214GgbEKDED0d3sj7pRdFXjNkb2+un/AUcCkceHizO0IVI6SOGGncrcjozruCkRgA== dependencies: object-assign "4.1.1" wrappy@1, wrappy@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= write-file-atomic@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + integrity sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA== dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -9150,6 +10827,7 @@ write-file-atomic@^2.0.0: write-file-atomic@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.1.4.tgz#b1f52dc2e8dc0e3cb04d187a25f758a38a90ca3b" + integrity sha1-sfUtwujcDjywTRh6JfdYo4qQyjs= dependencies: graceful-fs "^4.1.2" imurmurhash "^0.1.4" @@ -9158,12 +10836,14 @@ write-file-atomic@~1.1.4: write@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c= dependencies: mkdirp "^0.5.1" ws@~3.3.1: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== dependencies: async-limiter "~1.0.0" safe-buffer "~5.1.0" @@ -9172,26 +10852,37 @@ ws@~3.3.1: xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= xmldom@^0.1.19: version "0.1.27" resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" + integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk= xmlhttprequest-ssl@~1.5.4: version "1.5.5" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= xtend@^4.0.0, xtend@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= yallist@^3.0.0, yallist@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" + integrity sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k= yam@^0.0.24: version "0.0.24" resolved "https://registry.yarnpkg.com/yam/-/yam-0.0.24.tgz#11e9630444735f66a561d29221407de6d037cd95" + integrity sha512-llPF60oFLV8EQimNPR6+KorSaj59L32C4c1db4cr72GaWVWapnhTS2VZeK2K2xLyEOveWtRcNa+dLJBW7EfhYQ== dependencies: fs-extra "^4.0.2" lodash.merge "^4.6.0" @@ -9199,6 +10890,7 @@ yam@^0.0.24: yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E= dependencies: camelcase "^1.0.2" cliui "^2.1.0" @@ -9208,16 +10900,19 @@ yargs@~3.10.0: yeast@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= yui@^3.18.1: version "3.18.1" resolved "https://registry.yarnpkg.com/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" + integrity sha1-4AAmnsCntvvHQcu4/L0OZRF7AUw= dependencies: request "~2.40.0" yuidocjs@^0.10.0: version "0.10.2" resolved "https://registry.yarnpkg.com/yuidocjs/-/yuidocjs-0.10.2.tgz#33924967ce619024cd70ef694e267d2f988f73f6" + integrity sha1-M5JJZ85hkCTNcO9pTiZ9L5iPc/Y= dependencies: express "^4.13.1" graceful-fs "^4.1.2" From a2fa687656cc6b183ae6ac5c830a73c959736669 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 31 Oct 2018 08:55:59 -0700 Subject: [PATCH 2398/2527] [CHORE tests] modernize integration/inverse-test (#5715) * [CHORE tests] modernize integration/inverse-test * address feedback --- tests/integration/inverse-test.js | 495 +++++++++++++----- .../inverse-relationships-test.js | 274 +--------- 2 files changed, 387 insertions(+), 382 deletions(-) diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index 870f6139bab..02bd45cdbb1 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -1,169 +1,396 @@ -import { run } from '@ember/runloop'; -import setupStore from 'dummy/tests/helpers/store'; - -import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import { setupTest } from 'ember-qunit'; import { module, test } from 'qunit'; +import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import Model from 'ember-data/model'; +import { attr, belongsTo, hasMany } from '@ember-decorators/data'; -import DS from 'ember-data'; - -let env, store, User, Job, ReflexiveModel; +module('integration/inverse-test - Model.inverseFor', function(hooks) { + setupTest(hooks); + let store; -const { attr, belongsTo } = DS; + hooks.beforeEach(function() { + let { owner } = this; -function stringify(string) { - return function() { - return string; - }; -} + class User extends Model { + @attr + name; + @belongsTo('user', { async: true, inverse: null }) + bestFriend; + @belongsTo('job', { async: false }) + job; + } + class Job extends Model { + @attr + isGood; + @belongsTo('user', { async: false }) + user; + } + class ReflexiveModel extends Model { + @belongsTo('reflexiveModel', { async: false }) + reflexiveProp; + } + owner.register('model:user', User); + owner.register('model:job', Job); + owner.register('model:reflexive-model', ReflexiveModel); -module('integration/inverse_test - inverseFor', { - beforeEach() { - User = DS.Model.extend({ - name: attr('string'), - bestFriend: belongsTo('user', { async: true, inverse: null }), - job: belongsTo('job', { async: false }), - }); + store = owner.lookup('service:store'); + }); - User.toString = stringify('user'); + test('Finds the inverse when there is only one possible available', function(assert) { + let Job = store.modelFor('job'); + let inverseDefinition = Job.inverseFor('user', store); - Job = DS.Model.extend({ - isGood: attr(), - user: belongsTo('user', { async: false }), - }); + assert.deepEqual( + inverseDefinition, + { + type: store.modelFor('user'), + name: 'job', + kind: 'belongsTo', + options: { + async: false, + }, + }, + 'Gets correct type, name and kind' + ); + }); - Job.toString = stringify('job'); + test('Finds the inverse when only one side has defined it manually', function(assert) { + let { owner } = this; + owner.unregister('model:job'); + owner.unregister('model:user'); - ReflexiveModel = DS.Model.extend({ - reflexiveProp: belongsTo('reflexive-model', { async: false }), - }); + class Job extends Model { + @belongsTo('user', { async: false }) + user; + @belongsTo('user', { inverse: 'previousJob', async: false }) + owner; + } + class User extends Model { + @belongsTo('job', { async: false }) + previousJob; + } + owner.register('model:job', Job); + owner.register('model:user', User); - ReflexiveModel.toString = stringify('reflexiveModel'); + // lookup the user model's inverse first given that it does not + // define the inverse and there are two potential matches + assert.deepEqual( + store.modelFor('user').inverseFor('previousJob', store), + { + type: Job, //the model's type + name: 'owner', //the models relationship key + kind: 'belongsTo', + options: { + inverse: 'previousJob', + async: false, + }, + }, + 'Gets correct type, name and kind' + ); - env = setupStore({ - user: User, - job: Job, - reflexiveModel: ReflexiveModel, - }); + assert.deepEqual( + store.modelFor('job').inverseFor('owner', store), + { + type: User, //the model's type + name: 'previousJob', //the models relationship key + kind: 'belongsTo', + options: { + async: false, + }, + }, + 'Gets correct type, name and kind' + ); + }); - store = env.store; + test('Returns null if inverse relationship it is manually set with a different relationship key', function(assert) { + let { owner } = this; + owner.unregister('model:job'); + owner.unregister('model:user'); - Job = store.modelFor('job'); - User = store.modelFor('user'); - ReflexiveModel = store.modelFor('reflexive-model'); - }, + class Job extends Model { + @belongsTo('user', { inverse: 'previousJob', async: false }) + user; + } + class User extends Model { + @belongsTo('job', { async: false }) + job; + } + owner.register('model:job', Job); + owner.register('model:user', User); - afterEach() { - run(env.container, 'destroy'); - }, -}); + assert.equal(User.inverseFor('job', store), null, 'There is no inverse'); + }); -test('Finds the inverse when there is only one possible available', function(assert) { - let inverseDefinition = Job.inverseFor('user', store); - - assert.deepEqual( - inverseDefinition, - { - type: User, - name: 'job', - kind: 'belongsTo', - options: { - async: false, - }, - }, - 'Gets correct type, name and kind' - ); -}); + testInDebug('Errors out if you define 2 inverses to the same model', function(assert) { + let { owner } = this; + owner.unregister('model:job'); + owner.unregister('model:user'); -test('Finds the inverse when only one side has defined it manually', function(assert) { - Job.reopen({ - owner: belongsTo('user', { inverse: 'previousJob', async: false }), - }); + class Job extends Model { + @belongsTo('user', { inverse: 'job', async: false }) + user; + @belongsTo('user', { inverse: 'job', async: false }) + owner; + } + class User extends Model { + @belongsTo('job', { async: false }) + job; + } + owner.register('model:job', Job); + owner.register('model:user', User); - User.reopen({ - previousJob: belongsTo('job', { async: false }), + assert.expectAssertion(() => { + store.modelFor('user').inverseFor('job', store); + }, /You defined the 'job' relationship on model:user, but you defined the inverse relationships of type model:job multiple times/); }); - assert.deepEqual( - Job.inverseFor('owner', store), - { - type: User, //the model's type - name: 'previousJob', //the models relationship key - kind: 'belongsTo', - options: { - async: false, - }, - }, - 'Gets correct type, name and kind' - ); + test('Caches findInverseFor return value', function(assert) { + assert.expect(1); + let Job = store.modelFor('job'); - assert.deepEqual( - User.inverseFor('previousJob', store), - { - type: Job, //the model's type - name: 'owner', //the models relationship key - kind: 'belongsTo', - options: { - inverse: 'previousJob', - async: false, - }, - }, - 'Gets correct type, name and kind' - ); -}); + let inverseForUser = Job.inverseFor('user', store); + Job.findInverseFor = function() { + assert.ok(false, 'Find is not called anymore'); + }; -test('Returns null if inverse relationship it is manually set with a different relationship key', function(assert) { - Job.reopen({ - user: belongsTo('user', { inverse: 'previousJob', async: false }), + assert.equal(inverseForUser, Job.inverseFor('user', store), 'Inverse cached succesfully'); }); - User.reopen({ - job: belongsTo('job', { async: false }), + testInDebug('Errors out if you do not define an inverse for a reflexive relationship', function( + assert + ) { + //Maybe store is evaluated lazily, so we need this :( + assert.expectWarning(() => { + store.push({ + data: { + type: 'reflexive-model', + id: '1', + }, + }); + let reflexiveModel = store.peekRecord('reflexive-model', 1); + reflexiveModel.get('reflexiveProp'); + }, /Detected a reflexive relationship by the name of 'reflexiveProp'/); }); - assert.equal(User.inverseFor('job', store), null, 'There is no inverse'); -}); + test('inverseFor is only called when inverse is not null', async function(assert) { + assert.expect(2); + let { owner } = this; + owner.unregister('model:user'); + owner.unregister('model:job'); -testInDebug('Errors out if you define 2 inverses to the same model', function(assert) { - Job.reopen({ - user: belongsTo('user', { inverse: 'job', async: false }), - owner: belongsTo('user', { inverse: 'job', async: false }), - }); + class Post extends Model { + @hasMany('comment', { async: false, inverse: null }) + comments; + } + class Comment extends Model { + @belongsTo('post', { async: false, inverse: null }) + post; + } + class User extends Model { + @hasMany('message', { async: false, inverse: 'user' }) + messages; + } + class Message extends Model { + @belongsTo('user', { async: false, inverse: 'messages' }) + user; + } + owner.register('model:post', Post); + owner.register('model:comment', Comment); + owner.register('model:user', User); + owner.register('model:message', Message); - User.reopen({ - job: belongsTo('job', { async: false }), - }); + store.modelFor('post').inverseFor = function() { + assert.notOk(true, 'Post model inverseFor is not called'); + }; - assert.expectAssertion(() => { - User.inverseFor('job', store); - }, /You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times/i); -}); + store.modelFor('comment').inverseFor = function() { + assert.notOk(true, 'Comment model inverseFor is not called'); + }; -test('Caches findInverseFor return value', function(assert) { - assert.expect(1); + store.modelFor('message').inverseFor = function() { + assert.ok(true, 'Message model inverseFor is called'); + }; - var inverseForUser = Job.inverseFor('user', store); - Job.findInverseFor = function() { - assert.ok(false, 'Find is not called anymore'); - }; + store.modelFor('user').inverseFor = function() { + assert.ok(true, 'User model inverseFor is called'); + }; - assert.equal(inverseForUser, Job.inverseFor('user', store), 'Inverse cached succesfully'); -}); - -testInDebug('Errors out if you do not define an inverse for a reflexive relationship', function( - assert -) { - //Maybe store is evaluated lazily, so we need this :( - assert.expectWarning(() => { - var reflexiveModel; - run(() => { - store.push({ - data: { - type: 'reflexive-model', + store.push({ + data: { + id: '1', + type: 'post', + relationships: { + comments: { + data: [ + { + id: '1', + type: 'comment', + }, + { + id: '2', + type: 'comment', + }, + ], + }, + }, + }, + }); + store.push({ + data: [ + { id: '1', + type: 'comment', + relationships: { + post: { + data: { + id: '1', + type: 'post', + }, + }, + }, }, - }); - reflexiveModel = store.peekRecord('reflexive-model', 1); - reflexiveModel.get('reflexiveProp'); + { + id: '2', + type: 'comment', + relationships: { + post: { + data: { + id: '1', + type: 'post', + }, + }, + }, + }, + ], + }); + store.push({ + data: { + id: '1', + type: 'user', + relationships: { + messages: { + data: [ + { + id: '1', + type: 'message', + }, + { + id: '2', + type: 'message', + }, + ], + }, + }, + }, }); - }, /Detected a reflexive relationship by the name of 'reflexiveProp'/); + store.push({ + data: [ + { + id: '1', + type: 'message', + relationships: { + user: { + data: { + id: '1', + type: 'user', + }, + }, + }, + }, + { + id: '2', + type: 'message', + relationships: { + post: { + data: { + id: '1', + type: 'user', + }, + }, + }, + }, + ], + }); + }); + + testInDebug( + "Inverse null relationships with models that don't exist throw a nice error if trying to use that relationship", + async function(assert) { + this.owner.unregister('model:user'); + class User extends Model { + @belongsTo('post', { inverse: null }) + post; + } + this.owner.register('model:user', User); + + assert.expectAssertion(() => { + store.createRecord('user', { post: null }); + }, /No model was found for/); + + // but don't error if the relationship is not used + store.createRecord('user', {}); + } + ); + + test('Inverse relationships can be explicitly nullable', function(assert) { + this.owner.unregister('model:user'); + class User extends Model { + @hasMany('post', { inverse: 'participants', async: false }) + posts; + } + class Post extends Model { + @belongsTo('user', { inverse: null, async: false }) + lastParticipant; + @hasMany('user', { inverse: 'posts', async: false }) + participants; + } + this.owner.register('model:user', User); + this.owner.register('model:post', Post); + + let user = store.createRecord('user'); + let post = store.createRecord('post'); + + assert.equal( + user.inverseFor('posts').name, + 'participants', + 'User.posts inverse is Post.participants' + ); + assert.equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); + assert.equal( + post.inverseFor('participants').name, + 'posts', + 'Post.participants inverse is User.posts' + ); + }); + + test('Null inverses are excluded from potential relationship resolutions', function(assert) { + this.owner.unregister('model:user'); + class User extends Model { + @hasMany('post', { async: false }) + posts; + } + class Post extends Model { + @belongsTo('user', { inverse: null, async: false }) + lastParticipant; + @hasMany('user', { async: false }) + participants; + } + this.owner.register('model:user', User); + this.owner.register('model:post', Post); + + let user = store.createRecord('user'); + let post = store.createRecord('post'); + + assert.equal( + user.inverseFor('posts').name, + 'participants', + 'User.posts inverse is Post.participants' + ); + assert.equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); + assert.equal( + post.inverseFor('participants').name, + 'posts', + 'Post.participants inverse is User.posts' + ); + }); }); diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index 1ffa0c46681..3e57c8c185d 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -3,21 +3,20 @@ import { createStore } from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; +import Model from 'ember-data/model'; import DS from 'ember-data'; -let { Model, hasMany, belongsTo } = DS; - var Post, Comment, Message, User; module('integration/relationships/inverse_relationships - Inverse Relationships'); test('When a record is added to a has-many relationship, the inverse belongsTo is determined automatically', function(assert) { - Post = DS.Model.extend({ + Post = Model.extend({ comments: DS.hasMany('comment', { async: false }), }); - Comment = DS.Model.extend({ + Comment = Model.extend({ post: DS.belongsTo('post', { async: false }), }); @@ -35,78 +34,12 @@ test('When a record is added to a has-many relationship, the inverse belongsTo i assert.equal(comment.get('post'), post, 'post was set on the comment'); }); -test('Inverse relationships can be explicitly nullable', function(assert) { - User = DS.Model.extend(); - - Post = DS.Model.extend({ - lastParticipant: DS.belongsTo('user', { inverse: null, async: false }), - participants: DS.hasMany('user', { inverse: 'posts', async: false }), - }); - - User.reopen({ - posts: DS.hasMany('post', { inverse: 'participants', async: false }), - }); - - var store = createStore({ - user: User, - post: Post, - }); - - let user = store.createRecord('user'); - let post = store.createRecord('post'); - - assert.equal( - user.inverseFor('posts').name, - 'participants', - 'User.posts inverse is Post.participants' - ); - assert.equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); - assert.equal( - post.inverseFor('participants').name, - 'posts', - 'Post.participants inverse is User.posts' - ); -}); - -test('Null inverses are excluded from potential relationship resolutions', function(assert) { - User = Model.extend(); - - Post = Model.extend({ - lastParticipant: belongsTo('user', { inverse: null, async: false }), - participants: hasMany('user', { async: false }), - }); - - User.reopen({ - posts: hasMany('post', { async: false }), - }); - - let store = createStore({ - user: User, - post: Post, - }); - - let user = store.createRecord('user'); - let post = store.createRecord('post'); - - assert.equal( - user.inverseFor('posts').name, - 'participants', - 'User.posts inverse is Post.participants' - ); - assert.equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); - assert.equal( - post.inverseFor('participants').name, - 'posts', - 'Post.participants inverse is User.posts' - ); -}); - test('When a record is added to a has-many relationship, the inverse belongsTo can be set explicitly', function(assert) { - Post = DS.Model.extend({ + Post = Model.extend({ comments: DS.hasMany('comment', { inverse: 'redPost', async: false }), }); - Comment = DS.Model.extend({ + Comment = Model.extend({ onePost: DS.belongsTo('post', { async: false }), twoPost: DS.belongsTo('post', { async: false }), redPost: DS.belongsTo('post', { async: false }), @@ -135,13 +68,13 @@ test('When a record is added to a has-many relationship, the inverse belongsTo c }); test("When a record's belongsTo relationship is set, it can specify the inverse hasMany to which the new child should be added", function(assert) { - Post = DS.Model.extend({ + Post = Model.extend({ meComments: DS.hasMany('comment', { async: false }), youComments: DS.hasMany('comment', { async: false }), everyoneWeKnowComments: DS.hasMany('comment', { async: false }), }); - Comment = DS.Model.extend({ + Comment = Model.extend({ post: DS.belongsTo('post', { inverse: 'youComments', async: false }), }); @@ -172,11 +105,11 @@ test("When a record's belongsTo relationship is set, it can specify the inverse }); test('When setting a belongsTo, the OneToOne invariant is respected even when other records have been previously used', function(assert) { - Post = DS.Model.extend({ + Post = Model.extend({ bestComment: DS.belongsTo('comment', { async: false }), }); - Comment = DS.Model.extend({ + Comment = Model.extend({ post: DS.belongsTo('post', { async: false }), }); @@ -206,11 +139,11 @@ test('When setting a belongsTo, the OneToOne invariant is respected even when ot }); test('When setting a belongsTo, the OneToOne invariant is transitive', function(assert) { - Post = DS.Model.extend({ + Post = Model.extend({ bestComment: DS.belongsTo('comment', { async: false }), }); - Comment = DS.Model.extend({ + Comment = Model.extend({ post: DS.belongsTo('post', { async: false }), }); @@ -241,11 +174,11 @@ test('When setting a belongsTo, the OneToOne invariant is transitive', function( }); test('When setting a belongsTo, the OneToOne invariant is commutative', function(assert) { - Post = DS.Model.extend({ + Post = Model.extend({ bestComment: DS.belongsTo('comment', { async: false }), }); - Comment = DS.Model.extend({ + Comment = Model.extend({ post: DS.belongsTo('post', { async: false }), }); @@ -277,11 +210,11 @@ test('When setting a belongsTo, the OneToOne invariant is commutative', function test('OneToNone relationship works', function(assert) { assert.expect(3); - Post = DS.Model.extend({ + Post = Model.extend({ name: DS.attr('string'), }); - Comment = DS.Model.extend({ + Comment = Model.extend({ post: DS.belongsTo('post', { async: false }), }); @@ -309,7 +242,7 @@ test('OneToNone relationship works', function(assert) { }); test('When a record is added to or removed from a polymorphic has-many relationship, the inverse belongsTo can be set explicitly', function(assert) { - User = DS.Model.extend({ + User = Model.extend({ messages: DS.hasMany('message', { async: false, inverse: 'redUser', @@ -317,7 +250,7 @@ test('When a record is added to or removed from a polymorphic has-many relations }), }); - Message = DS.Model.extend({ + Message = Model.extend({ oneUser: DS.belongsTo('user', { async: false }), twoUser: DS.belongsTo('user', { async: false }), redUser: DS.belongsTo('user', { async: false }), @@ -357,13 +290,13 @@ test('When a record is added to or removed from a polymorphic has-many relations }); test("When a record's belongsTo relationship is set, it can specify the inverse polymorphic hasMany to which the new child should be added or removed", function(assert) { - User = DS.Model.extend({ + User = Model.extend({ meMessages: DS.hasMany('message', { polymorphic: true, async: false }), youMessages: DS.hasMany('message', { polymorphic: true, async: false }), everyoneWeKnowMessages: DS.hasMany('message', { polymorphic: true, async: false }), }); - Message = DS.Model.extend({ + Message = Model.extend({ user: DS.belongsTo('user', { inverse: 'youMessages', async: false }), }); @@ -397,7 +330,7 @@ test("When a record's belongsTo relationship is set, it can specify the inverse }); test("When a record's polymorphic belongsTo relationship is set, it can specify the inverse hasMany to which the new child should be added", function(assert) { - Message = DS.Model.extend({ + Message = Model.extend({ meMessages: DS.hasMany('comment', { inverse: null, async: false }), youMessages: DS.hasMany('comment', { inverse: 'message', async: false }), everyoneWeKnowMessages: DS.hasMany('comment', { inverse: null, async: false }), @@ -443,10 +376,10 @@ test("When a record's polymorphic belongsTo relationship is set, it can specify testInDebug("Inverse relationships that don't exist throw a nice error for a hasMany", function( assert ) { - User = DS.Model.extend(); - Comment = DS.Model.extend(); + User = Model.extend(); + Comment = Model.extend(); - Post = DS.Model.extend({ + Post = Model.extend({ comments: DS.hasMany('comment', { inverse: 'testPost', async: false }), }); @@ -466,10 +399,10 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a has testInDebug("Inverse relationships that don't exist throw a nice error for a belongsTo", function( assert ) { - User = DS.Model.extend(); - Comment = DS.Model.extend(); + User = Model.extend(); + Comment = Model.extend(); - Post = DS.Model.extend({ + Post = Model.extend({ user: DS.belongsTo('user', { inverse: 'testPost', async: false }), }); @@ -484,158 +417,3 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a bel }); }, /We found no inverse relationships by the name of 'testPost' on the 'user' model/); }); - -test('inverseFor is only called when inverse is not null', function(assert) { - assert.expect(2); - Post = DS.Model.extend({ - comments: DS.hasMany('comment', { async: false, inverse: null }), - }); - - Comment = DS.Model.extend({ - post: DS.belongsTo('post', { async: false, inverse: null }), - }); - - User = DS.Model.extend({ - messages: DS.hasMany('message', { async: false, inverse: 'user' }), - }); - - Message = DS.Model.extend({ - user: DS.belongsTo('user', { async: false, inverse: 'messages' }), - }); - - var env = setupStore({ post: Post, comment: Comment, user: User, message: Message }); - var store = env.store; - - Post.inverseFor = function() { - assert.notOk(true, 'Post model inverseFor is not called'); - }; - - Comment.inverseFor = function() { - assert.notOk(true, 'Comment model inverseFor is not called'); - }; - - Message.inverseFor = function() { - assert.ok(true, 'Message model inverseFor is called'); - }; - - User.inverseFor = function() { - assert.ok(true, 'User model inverseFor is called'); - }; - - run(function() { - store.push({ - data: { - id: '1', - type: 'post', - relationships: { - comments: { - data: [ - { - id: '1', - type: 'comment', - }, - { - id: '2', - type: 'comment', - }, - ], - }, - }, - }, - }); - store.push({ - data: [ - { - id: '1', - type: 'comment', - relationships: { - post: { - data: { - id: '1', - type: 'post', - }, - }, - }, - }, - { - id: '2', - type: 'comment', - relationships: { - post: { - data: { - id: '1', - type: 'post', - }, - }, - }, - }, - ], - }); - store.push({ - data: { - id: '1', - type: 'user', - relationships: { - messages: { - data: [ - { - id: '1', - type: 'message', - }, - { - id: '2', - type: 'message', - }, - ], - }, - }, - }, - }); - store.push({ - data: [ - { - id: '1', - type: 'message', - relationships: { - user: { - data: { - id: '1', - type: 'user', - }, - }, - }, - }, - { - id: '2', - type: 'message', - relationships: { - post: { - data: { - id: '1', - type: 'user', - }, - }, - }, - }, - ], - }); - }); -}); - -testInDebug( - "Inverse null relationships with models that don't exist throw a nice error if trying to use that relationship", - function(assert) { - User = DS.Model.extend({ - post: DS.belongsTo('post', { inverse: null }), - }); - - let env = setupStore({ user: User }); - - assert.expectAssertion(() => { - env.store.createRecord('user', { post: null }); - }, /No model was found for/); - - // but don't error if the relationship is not used - env.store.createRecord('user', {}); - } -); From cec0cfa1f70ec594c4edafcea7e8b564466b986d Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 31 Oct 2018 08:59:49 -0700 Subject: [PATCH 2399/2527] [CHORE tests] modernize unit/model/lifecycle-callbacks-test (#5717) * [CHORE tests] modernize unit/model/lifecycle-callbacks-test * Fix assertion text --- tests/unit/model/lifecycle-callbacks-test.js | 1268 ++++++++++++++---- 1 file changed, 1044 insertions(+), 224 deletions(-) diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index ac3aab1ada3..aa4e823e524 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -1,298 +1,1118 @@ +import { setupTest } from 'ember-qunit'; +import { module, test } from 'qunit'; +import { settled } from '@ember/test-helpers'; import { resolve, reject } from 'rsvp'; -import { get } from '@ember/object'; +import { attr } from '@ember-decorators/data'; +import Model from 'ember-data/model'; +import Adapter from 'ember-data/adapter'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; +import { InvalidError } from 'ember-data/adapters/errors'; import { run } from '@ember/runloop'; -import { createStore } from 'dummy/tests/helpers/store'; -import { module, test } from 'qunit'; +module('unit/model - Model Lifecycle Callbacks', function(hooks) { + setupTest(hooks); + let store; -import DS from 'ember-data'; + hooks.beforeEach(function() { + store = this.owner.lookup('service:store'); + }); -module('unit/model/lifecycle_callbacks - Lifecycle Callbacks'); + test('didLoad() only fires for initial loads, not creates, not reloads', async function(assert) { + let lifecycleEventMethodCalls = 0; + class Person extends Model { + @attr + name; -test('a record receives a didLoad callback when it has finished loading', function(assert) { - assert.expect(3); + didLoad() { + lifecycleEventMethodCalls++; + } + } + this.owner.register('model:person', Person); + this.owner.register('serializer:application', JSONAPISerializer); - const Person = DS.Model.extend({ - name: DS.attr(), - didLoad() { - assert.ok('The didLoad callback was called'); - }, - }); + class AppAdapter extends Adapter { + deleteRecord() { + return resolve({ data: null }); + } + createRecord() { + return resolve({ data: { id: '0', type: 'person' } }); + } + updateRecord() { + return resolve({ data: { id: '1', type: 'person' } }); + } + findRecord() { + return resolve({ data: { id: '2', type: 'person', attributes: { name: 'Foo' } } }); + } + } + this.owner.register('adapter:application', AppAdapter); - const Adapter = DS.Adapter.extend({ - findRecord(store, type, id, snapshot) { - return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; - }, - }); + // ------ Test Create - let store = createStore({ - adapter: Adapter, - person: Person, - }); + let record = store.createRecord('person', { name: 'Chris' }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didLoad when we create locally' + ); + lifecycleEventMethodCalls = 0; + + await record.save(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didLoad when we save after we create locally' + ); + lifecycleEventMethodCalls = 0; - return run(() => { - return store.findRecord('person', 1).then(person => { - assert.equal(person.get('id'), '1', `The person's ID is available`); - assert.equal(person.get('name'), 'Foo', `The person's properties are availablez`); + // ------ Test Update + + record = store.push({ + data: { + id: '1', + type: 'person', + attributes: { + name: 'James', + }, + }, }); - }); -}); + assert.strictEqual(lifecycleEventMethodCalls, 1, 'We trigger didLoad when we push'); + lifecycleEventMethodCalls = 0; -test(`TEMPORARY: a record receives a didLoad callback once it materializes if it wasn't materialized when loaded`, function(assert) { - assert.expect(2); - let didLoadCalled = 0; - const Person = DS.Model.extend({ - name: DS.attr(), - didLoad() { - didLoadCalled++; - }, - }); + record.set('name', 'Chris'); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didLoad when we mutate locally' + ); + lifecycleEventMethodCalls = 0; - let store = createStore({ - person: Person, - }); + await record.save(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didLoad when we save after we mutate locally' + ); + lifecycleEventMethodCalls = 0; - run(() => { - store._pushInternalModel({ id: 1, type: 'person' }); - assert.equal(didLoadCalled, 0, 'didLoad was not called'); - }); - run(() => store.peekRecord('person', 1)); - assert.equal(didLoadCalled, 1, 'didLoad was called'); -}); + // ------ Test Find -test('a record receives a didUpdate callback when it has finished updating', function(assert) { - assert.expect(5); + record = await store.findRecord('person', '2'); + assert.strictEqual( + lifecycleEventMethodCalls, + 1, + 'We trigger didLoad when we first find a record' + ); + lifecycleEventMethodCalls = 0; + await record.reload(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didLoad when we reload a record' + ); + lifecycleEventMethodCalls = 0; - let callCount = 0; + // ------ Test Push - const Person = DS.Model.extend({ - bar: DS.attr('string'), - name: DS.attr('string'), + store.push({ + data: { + id: '3', + type: 'person', + attributes: { + name: 'James', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 1, + 'We trigger didLoad when we first pushed a record' + ); + lifecycleEventMethodCalls = 0; - didUpdate() { - callCount++; - assert.equal(get(this, 'isSaving'), false, 'record should be saving'); - assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); - }, - }); + store.push({ + data: { + id: '3', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didLoad when push updates to an existing same record' + ); + lifecycleEventMethodCalls = 0; - const Adapter = DS.Adapter.extend({ - findRecord(store, type, id, snapshot) { - return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; - }, + // ------ Test Push with Lazy Materialization of Record - updateRecord(store, type, snapshot) { - assert.equal(callCount, 0, 'didUpdate callback was not called until didSaveRecord is called'); + store._push({ + data: { + id: '4', + type: 'person', + attributes: { + name: 'James', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didLoad when we first push a record without materializing it' + ); + lifecycleEventMethodCalls = 0; - return resolve(); - }, - }); + store._push({ + data: { + id: '4', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didLoad when push updates to an existing non-materialized record' + ); + lifecycleEventMethodCalls = 0; - let store = createStore({ - adapter: Adapter, - person: Person, - }); + store.peekRecord('person', '4'); + assert.strictEqual( + lifecycleEventMethodCalls, + 1, + 'We trigger didLoad when we first materialize a record' + ); + lifecycleEventMethodCalls = 0; - let asyncPerson = run(() => store.findRecord('person', 1)); - - assert.equal(callCount, 0, 'precond - didUpdate callback was not called yet'); - - return run(() => { - return asyncPerson - .then(person => { - return run(() => { - person.set('bar', 'Bar'); - return person.save(); - }); - }) - .then(() => { - assert.equal(callCount, 1, 'didUpdate called after update'); - }); - }); -}); + // ------ Test Deletion of Record -test('a record receives a didCreate callback when it has finished updating', function(assert) { - assert.expect(5); + record = store.push({ + data: { + id: '5', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual(lifecycleEventMethodCalls, 1, 'We trigger didLoad on push'); + lifecycleEventMethodCalls = 0; - let callCount = 0; + record.deleteRecord(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didLoad when we first call record.deleteRecord' + ); + lifecycleEventMethodCalls = 0; - const Person = DS.Model.extend({ - didCreate() { - callCount++; - assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); - assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); - }, - }); + await record.save(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didLoad once we have saved the deletion' + ); + lifecycleEventMethodCalls = 0; - const Adapter = DS.Adapter.extend({ - createRecord(store, type, snapshot) { - assert.equal(callCount, 0, 'didCreate callback was not called until didSaveRecord is called'); + // ------ Test Unloading of Record - return resolve(); - }, - }); + record = store.push({ + data: { + id: '6', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual(lifecycleEventMethodCalls, 1, 'We trigger didLoad on push'); + lifecycleEventMethodCalls = 0; - let store = createStore({ - adapter: Adapter, - person: Person, + record.unloadRecord(); + await settled(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didLoad when we unload a record' + ); + lifecycleEventMethodCalls = 0; + + record = store.push({ + data: { + id: '6', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 1, + 'We trigger didLoad when we push a previously unloaded record' + ); }); - assert.equal(callCount, 0, 'precond - didCreate callback was not called yet'); - let person = store.createRecord('person', { id: 69, name: 'Newt Gingrich' }); + test('didUpdate() only fires for persisted updates', async function(assert) { + let lifecycleEventMethodCalls = 0; + class Person extends Model { + @attr + name; + + didUpdate() { + lifecycleEventMethodCalls++; + assert.equal(this.get('isSaving'), false, 'record should not be saving'); + assert.equal(this.get('hasDirtyAttributes'), false, 'record should not be dirty'); + } + } + this.owner.register('model:person', Person); + this.owner.register('serializer:application', JSONAPISerializer); + + class AppAdapter extends Adapter { + deleteRecord() { + return resolve({ data: null }); + } + createRecord() { + return resolve({ data: { id: '0', type: 'person' } }); + } + updateRecord() { + return resolve({ data: { id: '1', type: 'person' } }); + } + findRecord() { + return resolve({ data: { id: '2', type: 'person', attributes: { name: 'Foo' } } }); + } + } + this.owner.register('adapter:application', AppAdapter); + + // ------ Test Create + + let record = store.createRecord('person', { name: 'Chris' }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didUpdate when we create locally' + ); + lifecycleEventMethodCalls = 0; - return run(() => { - return person.save().then(() => { - assert.equal(callCount, 1, 'didCreate called after commit'); + await record.save(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didUpdate when we save after we create locally' + ); + lifecycleEventMethodCalls = 0; + + // ------ Test Update + + record = store.push({ + data: { + id: '1', + type: 'person', + attributes: { + name: 'James', + }, + }, }); - }); -}); + assert.strictEqual(lifecycleEventMethodCalls, 0, 'We do not trigger didUpdate when we push'); + lifecycleEventMethodCalls = 0; -test('a record receives a didDelete callback when it has finished deleting', function(assert) { - assert.expect(5); + record.set('name', 'Chris'); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didUpdate when we mutate locally' + ); + lifecycleEventMethodCalls = 0; - let callCount = 0; + await record.save(); + assert.strictEqual( + lifecycleEventMethodCalls, + 1, + 'We trigger didUpdate when we save after we mutate locally' + ); + lifecycleEventMethodCalls = 0; - const Person = DS.Model.extend({ - bar: DS.attr('string'), - name: DS.attr('string'), + // ------ Test Find - didDelete() { - callCount++; + record = await store.findRecord('person', '2'); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didUpdate when we first find a record' + ); + lifecycleEventMethodCalls = 0; + await record.reload(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didUpdate when we reload a record' + ); + lifecycleEventMethodCalls = 0; - assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); - assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); - }, - }); + // ------ Test Push - const Adapter = DS.Adapter.extend({ - findRecord(store, type, id, snapshot) { - return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; - }, + store.push({ + data: { + id: '3', + type: 'person', + attributes: { + name: 'James', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didUpdate when we first pushed a record' + ); + lifecycleEventMethodCalls = 0; - deleteRecord(store, type, snapshot) { - assert.equal(callCount, 0, 'didDelete callback was not called until didSaveRecord is called'); + store.push({ + data: { + id: '3', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didUpdate when push updates to an existing same record' + ); + lifecycleEventMethodCalls = 0; - return resolve(); - }, - }); + // ------ Test Push with Lazy Materialization of Record - let store = createStore({ - adapter: Adapter, - person: Person, - }); - let asyncPerson = run(() => store.findRecord('person', 1)); - - assert.equal(callCount, 0, 'precond - didDelete callback was not called yet'); - - return run(() => { - return asyncPerson - .then(person => { - return run(() => { - person.deleteRecord(); - return person.save(); - }); - }) - .then(() => { - assert.equal(callCount, 1, 'didDelete called after delete'); - }); + store._push({ + data: { + id: '4', + type: 'person', + attributes: { + name: 'James', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didUpdate when we first push a record without materializing it' + ); + lifecycleEventMethodCalls = 0; + + store._push({ + data: { + id: '4', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didUpdate when push updates to an existing non-materialized record' + ); + lifecycleEventMethodCalls = 0; + + store.peekRecord('person', '4'); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didUpdate when we first materialize a record' + ); + lifecycleEventMethodCalls = 0; + + // ------ Test Deletion of Record + + record = store.push({ + data: { + id: '5', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual(lifecycleEventMethodCalls, 0, 'We do not trigger didUpdate on push'); + lifecycleEventMethodCalls = 0; + + record.deleteRecord(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didUpdate when we first call record.deleteRecord' + ); + lifecycleEventMethodCalls = 0; + + await record.save(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didUpdate once we have saved the deletion' + ); + lifecycleEventMethodCalls = 0; + + // ------ Test Unloading of Record + + record = store.push({ + data: { + id: '6', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual(lifecycleEventMethodCalls, 0, 'We do not trigger didUpdate on push'); + lifecycleEventMethodCalls = 0; + + record.unloadRecord(); + await settled(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didUpdate when we unload a record' + ); + lifecycleEventMethodCalls = 0; + + record = store.push({ + data: { + id: '6', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didUpdate when we push a previously unloaded record' + ); }); -}); -test('an uncommited record also receives a didDelete callback when it is deleted', function(assert) { - assert.expect(4); + test('didCreate() only fires for persisted creates', async function(assert) { + let lifecycleEventMethodCalls = 0; + class Person extends Model { + @attr + name; + + didCreate() { + lifecycleEventMethodCalls++; + assert.equal(this.get('isSaving'), false, 'record should not be saving'); + assert.equal(this.get('hasDirtyAttributes'), false, 'record should not be dirty'); + } + } + this.owner.register('model:person', Person); + this.owner.register('serializer:application', JSONAPISerializer); + + class AppAdapter extends Adapter { + deleteRecord() { + return resolve({ data: null }); + } + createRecord() { + assert.equal( + lifecycleEventMethodCalls, + 0, + 'didCreate callback was not called before adapter.createRecord resolves' + ); + return resolve({ data: { id: '0', type: 'person' } }); + } + updateRecord() { + return resolve({ data: { id: '1', type: 'person' } }); + } + findRecord() { + return resolve({ data: { id: '2', type: 'person', attributes: { name: 'Foo' } } }); + } + } + this.owner.register('adapter:application', AppAdapter); + + // ------ Test Create + + let record = store.createRecord('person', { name: 'Chris' }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didCreate when we create locally' + ); + lifecycleEventMethodCalls = 0; + + await record.save(); + assert.strictEqual( + lifecycleEventMethodCalls, + 1, + 'We trigger didCreate when we save after we create locally' + ); + lifecycleEventMethodCalls = 0; + + // ------ Test Update + + record = store.push({ + data: { + id: '1', + type: 'person', + attributes: { + name: 'James', + }, + }, + }); + assert.strictEqual(lifecycleEventMethodCalls, 0, 'We do not trigger didCreate when we push'); + lifecycleEventMethodCalls = 0; - let callCount = 0; + record.set('name', 'Chris'); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didCreate when we mutate locally' + ); + lifecycleEventMethodCalls = 0; - const Person = DS.Model.extend({ - bar: DS.attr('string'), - name: DS.attr('string'), + await record.save(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didCreate when we save after we mutate locally' + ); + lifecycleEventMethodCalls = 0; - didDelete() { - callCount++; - assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); - assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); - }, + // ------ Test Find + + record = await store.findRecord('person', '2'); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didCreate when we first find a record' + ); + lifecycleEventMethodCalls = 0; + await record.reload(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didCreate when we reload a record' + ); + lifecycleEventMethodCalls = 0; + + // ------ Test Push + + store.push({ + data: { + id: '3', + type: 'person', + attributes: { + name: 'James', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didCreate when we first push a record' + ); + lifecycleEventMethodCalls = 0; + + store.push({ + data: { + id: '3', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didCreate when push updates to an existing record' + ); + lifecycleEventMethodCalls = 0; + + // ------ Test Push with Lazy Materialization of Record + + store._push({ + data: { + id: '4', + type: 'person', + attributes: { + name: 'James', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didCreate when we first push a record without materializing it' + ); + lifecycleEventMethodCalls = 0; + + store._push({ + data: { + id: '4', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didCreate when push updates to an existing non-materialized record' + ); + lifecycleEventMethodCalls = 0; + + store.peekRecord('person', '4'); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didCreate when we first materialize a record' + ); + lifecycleEventMethodCalls = 0; + + // ------ Test Deletion of Record + + record = store.push({ + data: { + id: '5', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual(lifecycleEventMethodCalls, 0, 'We do not trigger didCreate on push'); + lifecycleEventMethodCalls = 0; + + record.deleteRecord(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didCreate when we first call record.deleteRecord' + ); + lifecycleEventMethodCalls = 0; + + await record.save(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didCreate once we have saved the deletion' + ); + lifecycleEventMethodCalls = 0; + + // ------ Test Unloading of Record + + record = store.push({ + data: { + id: '6', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual(lifecycleEventMethodCalls, 0, 'We do not trigger didCreate on push'); + lifecycleEventMethodCalls = 0; + + record.unloadRecord(); + await settled(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didCreate when we unload a record' + ); + lifecycleEventMethodCalls = 0; + + record = store.push({ + data: { + id: '6', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didCreate when we push a previously unloaded record' + ); }); - let store = createStore({ - adapter: DS.Adapter.extend(), - person: Person, + test('didDelete() only fires for persisted deletions', async function(assert) { + let lifecycleEventMethodCalls = 0; + class Person extends Model { + @attr + name; + + didDelete() { + lifecycleEventMethodCalls++; + assert.equal(this.get('isSaving'), false, 'record should not be saving'); + assert.equal(this.get('hasDirtyAttributes'), false, 'record should not be dirty'); + } + } + this.owner.register('model:person', Person); + this.owner.register('serializer:application', JSONAPISerializer); + + class AppAdapter extends Adapter { + deleteRecord() { + assert.equal( + lifecycleEventMethodCalls, + 0, + 'didDelete callback was not called before adapter.deleteRecord resolves' + ); + return resolve({ data: null }); + } + createRecord() { + return resolve({ data: { id: '0', type: 'person' } }); + } + updateRecord() { + return resolve({ data: { id: '1', type: 'person' } }); + } + findRecord() { + return resolve({ data: { id: '2', type: 'person', attributes: { name: 'Foo' } } }); + } + } + this.owner.register('adapter:application', AppAdapter); + + // ------ Test Create + + let record = store.createRecord('person', { name: 'Chris' }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when we create locally' + ); + lifecycleEventMethodCalls = 0; + + await record.save(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when we save after we create locally' + ); + lifecycleEventMethodCalls = 0; + + // ------ Test Update + + record = store.push({ + data: { + id: '1', + type: 'person', + attributes: { + name: 'James', + }, + }, + }); + assert.strictEqual(lifecycleEventMethodCalls, 0, 'We do not trigger didDelete when we push'); + lifecycleEventMethodCalls = 0; + + record.set('name', 'Chris'); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when we mutate locally' + ); + lifecycleEventMethodCalls = 0; + + await record.save(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when we save after we mutate locally' + ); + lifecycleEventMethodCalls = 0; + + // ------ Test Find + + record = await store.findRecord('person', '2'); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when we first find a record' + ); + lifecycleEventMethodCalls = 0; + await record.reload(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when we reload a record' + ); + lifecycleEventMethodCalls = 0; + + // ------ Test Push + + store.push({ + data: { + id: '3', + type: 'person', + attributes: { + name: 'James', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when we first push a record' + ); + lifecycleEventMethodCalls = 0; + + store.push({ + data: { + id: '3', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when push updates to an existing record' + ); + lifecycleEventMethodCalls = 0; + + // ------ Test Push with Lazy Materialization of Record + + store._push({ + data: { + id: '4', + type: 'person', + attributes: { + name: 'James', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when we first push a record without materializing it' + ); + lifecycleEventMethodCalls = 0; + + store._push({ + data: { + id: '4', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when push updates to an existing non-materialized record' + ); + lifecycleEventMethodCalls = 0; + + store.peekRecord('person', '4'); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when we first materialize a record' + ); + lifecycleEventMethodCalls = 0; + + // ------ Test Deletion of Record + + record = store.push({ + data: { + id: '5', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + record.deleteRecord(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when we first call record.deleteRecord' + ); + lifecycleEventMethodCalls = 0; + + await record.save(); + assert.strictEqual( + lifecycleEventMethodCalls, + 1, + 'We trigger didDelete once we have saved the deletion' + ); + lifecycleEventMethodCalls = 0; + + // ------ Test Unloading of Record + + record = store.push({ + data: { + id: '6', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + record.unloadRecord(); + await settled(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when we unload a record' + ); + lifecycleEventMethodCalls = 0; + + record = store.push({ + data: { + id: '6', + type: 'person', + attributes: { + name: 'Chris', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when we reload a previously unloaded record' + ); }); - let person = store.createRecord('person', { name: 'Tomster' }); + test('didDelete() triggers for uncommitted records when the deletion is persisted', async function(assert) { + let lifecycleEventMethodCalls = 0; + class Person extends Model { + @attr + name; - assert.equal(callCount, 0, 'precond - didDelete callback was not called yet'); + didDelete() { + lifecycleEventMethodCalls++; + assert.equal(this.get('isSaving'), false, 'record should not be saving'); + assert.equal(this.get('hasDirtyAttributes'), false, 'record should not be dirty'); + } + } + this.owner.register('model:person', Person); + this.owner.register('serializer:application', JSONAPISerializer); - run(() => person.deleteRecord()); + class AppAdapter extends Adapter { + deleteRecord() { + assert.equal( + lifecycleEventMethodCalls, + 0, + 'didDelete callback was not called before adapter.deleteRecord resolves' + ); + return resolve({ data: null }); + } + } + this.owner.register('adapter:application', AppAdapter); - assert.equal(callCount, 1, 'didDelete called after delete'); -}); + // ------ Test Deletion of Record + + let record = store.createRecord('person', { name: 'Tomster' }); -test('a record receives a becameInvalid callback when it became invalid', function(assert) { - assert.expect(8); + record.deleteRecord(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when we first call record.deleteRecord' + ); + lifecycleEventMethodCalls = 0; - let callCount = 0; + await settled(); + assert.strictEqual( + lifecycleEventMethodCalls, + 1, + 'We trigger didDelete when we first call record.deleteRecord' + ); + lifecycleEventMethodCalls = 0; - const Person = DS.Model.extend({ - bar: DS.attr('string'), - name: DS.attr('string'), + await record.save(); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete once we have saved the deletion, as we secretly did previously' + ); + lifecycleEventMethodCalls = 0; - becameInvalid() { - callCount++; + // ------ Test Unloading of Record - assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); - assert.equal(get(this, 'hasDirtyAttributes'), true, 'record should be dirty'); - }, + record = store.createRecord('person', { name: 'Tomster' }); + + // ideally we could `await settled()` but Ember 2.18 does not handle `destroy()` calls in this case. + run(() => record.unloadRecord()); + + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger didDelete when we unload a record' + ); }); - const Adapter = DS.Adapter.extend({ - findRecord(store, type, id, snapshot) { - return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; - }, + test('becameInvalid() triggers when an update rejects with an error for a member', async function(assert) { + let lifecycleEventMethodCalls = 0; + class Person extends Model { + @attr + name; - updateRecord(store, type, snapshot) { - assert.equal( - callCount, - 0, - 'becameInvalid callback was not called until recordWasInvalid is called' - ); + becameInvalid() { + lifecycleEventMethodCalls++; + assert.equal(this.get('isSaving'), false, 'record should not be saving'); + assert.equal(this.get('hasDirtyAttributes'), true, 'record should not be dirty'); + } + } + this.owner.register('model:person', Person); + this.owner.register('serializer:application', JSONAPISerializer); - return reject( - new DS.InvalidError([ + class AppAdapter extends Adapter { + updateRecord() { + assert.equal( + lifecycleEventMethodCalls, + 0, + 'becameInvalid callback was not called before adapter.updateRecord resolves' + ); + let error = new InvalidError([ { title: 'Invalid Attribute', detail: 'error', source: { - pointer: '/data/attributes/bar', + pointer: '/data/attributes/name', }, }, - ]) - ); - }, - }); + ]); - let store = createStore({ - adapter: Adapter, - person: Person, - }); + return reject(error); + } + } + this.owner.register('adapter:application', AppAdapter); + + let person = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Great Name!', + }, + }, + }); + assert.strictEqual( + lifecycleEventMethodCalls, + 0, + 'We do not trigger becameInvalid when we first push the record to the store' + ); + lifecycleEventMethodCalls = 0; + + person.set('name', 'Bad Bad Name'); + + await person.save().catch(reason => { + assert.strictEqual(lifecycleEventMethodCalls, 1, 'We trigger becameInvalid when we reject'); - let asyncPerson = run(() => store.findRecord('person', 1)); - assert.equal(callCount, 0, 'precond - becameInvalid callback was not called yet'); - - // Make sure that the error handler has a chance to attach before - // save fails. - return run(() => { - return asyncPerson.then(person => { - return run(() => { - person.set('bar', 'Bar'); - return person.save().catch(reason => { - assert.ok(reason.isAdapterError, 'reason should have been an adapter error'); - - assert.equal(reason.errors.length, 1, 'reason should have one error'); - assert.equal(reason.errors[0].title, 'Invalid Attribute'); - assert.equal(callCount, 1, 'becameInvalid called after invalidating'); - }); - }); + assert.ok(reason.isAdapterError, 'reason should have been an adapter error'); + assert.equal(reason.errors.length, 1, 'reason should have one error'); + assert.equal(reason.errors[0].title, 'Invalid Attribute'); }); }); }); From a4224848002231f6a469c2ee67792bd5a17deb5e Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 31 Oct 2018 09:02:15 -0700 Subject: [PATCH 2400/2527] [CHORE is-array-like] make isArrayLike die a terrible death (#5724) --- addon/-private/system/is-array-like.js | 33 ------------------- addon/-private/system/many-array.js | 7 ++-- addon/-private/system/model/internal-model.js | 9 +++-- 3 files changed, 11 insertions(+), 38 deletions(-) delete mode 100644 addon/-private/system/is-array-like.js diff --git a/addon/-private/system/is-array-like.js b/addon/-private/system/is-array-like.js deleted file mode 100644 index b1faffab15f..00000000000 --- a/addon/-private/system/is-array-like.js +++ /dev/null @@ -1,33 +0,0 @@ -import { typeOf } from '@ember/utils'; -import EmberArray from '@ember/array'; - -/* - We're using this to detect arrays and "array-like" objects. - - This is a copy of the `isArray` method found in `ember-runtime/utils` as we're - currently unable to import non-exposed modules. - - This method was previously exposed as `Ember.isArray` but since - https://github.com/emberjs/ember.js/pull/11463 `Ember.isArray` is an alias of - `Array.isArray` hence removing the "array-like" part. - */ -export default function isArrayLike(obj) { - if (!obj || obj.setInterval) { - return false; - } - if (Array.isArray(obj)) { - return true; - } - if (EmberArray.detect(obj)) { - return true; - } - - let type = typeOf(obj); - if ('array' === type) { - return true; - } - if (obj.length !== undefined && 'object' === type) { - return true; - } - return false; -} diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index abf9448ed8d..10a0fc85889 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -5,12 +5,12 @@ import { all } from 'rsvp'; import Evented from '@ember/object/evented'; import MutableArray from '@ember/array/mutable'; +import EmberArray from '@ember/array'; import EmberObject, { get } from '@ember/object'; import { assert } from '@ember/debug'; import { PromiseArray } from './promise-proxies'; import { _objectIsAlive } from './store/common'; import diffArray from './diff-array'; -import isArrayLike from './is-array-like'; /** A `ManyArray` is a `MutableArray` that represents the contents of a has-many @@ -202,7 +202,10 @@ export default EmberObject.extend(MutableArray, Evented, { ); } if (objects) { - assert('The third argument to replace needs to be an array.', isArrayLike(objects)); + assert( + 'The third argument to replace needs to be an array.', + Array.isArray(objects) || EmberArray.detect(objects) + ); this.get('recordData').addToHasMany( this.get('key'), objects.map(obj => obj._internalModel._recordData), diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index e7dea5d390c..b6260465521 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -1,6 +1,6 @@ import { set, get } from '@ember/object'; import EmberError from '@ember/error'; -import { A } from '@ember/array'; +import { default as EmberArray, A } from '@ember/array'; import { setOwner } from '@ember/application'; import { run } from '@ember/runloop'; import { assign } from '@ember/polyfills'; @@ -14,7 +14,6 @@ import OrderedSet from '../ordered-set'; import ManyArray from '../many-array'; import { PromiseBelongsTo, PromiseManyArray } from '../promise-proxies'; import { getOwner } from '../../utils'; -import isArrayLike from '../is-array-like'; import { RecordReference, BelongsToReference, HasManyReference } from '../references'; @@ -1248,7 +1247,11 @@ export default class InternalModel { } function assertRecordsPassedToHasMany(records) { - assert(`You must pass an array of records to set a hasMany relationship`, isArrayLike(records)); + // TODO only allow native arrays + assert( + `You must pass an array of records to set a hasMany relationship`, + Array.isArray(records) || EmberArray.detect(records) + ); assert( `All elements of a hasMany relationship must be instances of DS.Model, you passed ${inspect( records From bcccd0b52fb25d8fe8cef7bc1944f3bfef278798 Mon Sep 17 00:00:00 2001 From: Felix Fichte Date: Wed, 31 Oct 2018 17:44:07 +0100 Subject: [PATCH 2401/2527] [DOC] Fixed small Docs and Code mismatches --- addon/-private/system/model/errors.js | 3 +-- addon/adapter.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index 8a8fd2e5d3d..2be135d1ec6 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -80,8 +80,7 @@ import { warn } from '@ember/debug'; @class Errors @namespace DS - @extends Ember.Object - @uses Ember.Enumerable + @extends Ember.ArrayProxy @uses Ember.Evented */ export default ArrayProxy.extend(Evented, { diff --git a/addon/adapter.js b/addon/adapter.js index f6560223268..eeaf9d2c4c5 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -57,7 +57,7 @@ import EmberObject from '@ember/object'; @class Adapter @namespace DS - @extends Ember.Object + @extends EmberObject */ export default EmberObject.extend({ From c466ae88c66044d3a77188ac50775bf4aeb51f43 Mon Sep 17 00:00:00 2001 From: Felix Fichte Date: Wed, 31 Oct 2018 17:51:49 +0100 Subject: [PATCH 2402/2527] [DOC] Reference to EmberObject always without dot --- CHANGELOG.md | 2 +- addon/-private/system/many-array.js | 2 +- addon/-private/system/model/model.js | 2 +- addon/-private/system/promise-proxies.js | 2 +- addon/serializer.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3881cba04f2..694dd4adc67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1982,7 +1982,7 @@ var Post = DS.Model.extend({ ``` **no longer works**. Instead, you should just watch each attribute like you -would with any `Ember.Object`: +would with any `EmberObject`: ```javascript var Post = DS.Model.extend({ diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 10a0fc85889..a66935cb28a 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -52,7 +52,7 @@ import diffArray from './diff-array'; @class ManyArray @namespace DS - @extends Ember.Object + @extends EmberObject @uses Ember.MutableArray, Ember.Evented */ export default EmberObject.extend(MutableArray, Evented, { diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index cf660691241..2764a693130 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -67,7 +67,7 @@ const retrieveFromCurrentState = computed('currentState', function(key) { @class Model @namespace DS - @extends Ember.Object + @extends EmberObject @uses Ember.Evented */ const Model = EmberObject.extend(Evented, { diff --git a/addon/-private/system/promise-proxies.js b/addon/-private/system/promise-proxies.js index ed4fdfd4a90..5307524862d 100644 --- a/addon/-private/system/promise-proxies.js +++ b/addon/-private/system/promise-proxies.js @@ -40,7 +40,7 @@ export const PromiseArray = ArrayProxy.extend(PromiseProxyMixin, { }); /** - A `PromiseObject` is an object that acts like both an `Ember.Object` + A `PromiseObject` is an object that acts like both an `EmberObject` and a promise. When the promise is resolved, then the resulting value will be set to the `PromiseObject`'s `content` property. This makes it easy to create data bindings with the `PromiseObject` that will diff --git a/addon/serializer.js b/addon/serializer.js index cf9d47cbbd7..b54ff2dddf9 100644 --- a/addon/serializer.js +++ b/addon/serializer.js @@ -21,7 +21,7 @@ import EmberObject from '@ember/object'; @class Serializer @namespace DS - @extends Ember.Object + @extends EmberObject */ export default EmberObject.extend({ From aa87a0ad6cc04cff12a364e0d92c271baaee8053 Mon Sep 17 00:00:00 2001 From: Adam Hawkins Date: Fri, 2 Nov 2018 21:19:02 +0530 Subject: [PATCH 2403/2527] [DOCS has-many]: clarify load/reload behavior I was bit hard by this. I expected that calling either of these methods would re-query the relationship through the adapter. This isn't the case. I further understood what was going on reading the source while implementing my own adapters. This commit hopefully clarifies the behavior. If the relationship has a "link", then `findHasMany` is called to re-query the relationship. Otherwise, all existing records are reload. --- addon/-private/system/references/has-many.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index 4c455a09dee..ec2832fc2e4 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -256,7 +256,8 @@ export default class HasManyReference extends Reference { /** Loads the relationship if it is not already loaded. If the relationship is already loaded this method does not trigger a new - load. + load. This causes a request to the specified + relationship link or reloads all items currently in the relationship. Example @@ -318,7 +319,8 @@ export default class HasManyReference extends Reference { } /** - Reloads this has-many relationship. + Reloads this has-many relationship. This causes a request to the specified + relationship link or reloads all items currently in the relationship. Example From 816a6637b0a2a269413d94b94c8c586bf128fd26 Mon Sep 17 00:00:00 2001 From: Mike North Date: Fri, 2 Nov 2018 18:26:02 -0700 Subject: [PATCH 2404/2527] fix: convert record, reference & coerceId to TypeScript (#5730) --- .../system/{coerce-id.js => coerce-id.ts} | 12 ++++- .../references/{record.js => record.ts} | 9 ++-- .../references/{reference.js => reference.ts} | 52 ++++++++++++++----- addon/-private/system/store.js | 6 +-- package.json | 1 + tsconfig.json | 1 + yarn.lock | 5 ++ 7 files changed, 61 insertions(+), 25 deletions(-) rename addon/-private/system/{coerce-id.js => coerce-id.ts} (62%) rename addon/-private/system/references/{record.js => record.ts} (95%) rename addon/-private/system/references/{reference.js => reference.ts} (67%) diff --git a/addon/-private/system/coerce-id.js b/addon/-private/system/coerce-id.ts similarity index 62% rename from addon/-private/system/coerce-id.js rename to addon/-private/system/coerce-id.ts index 18173352148..c45160a30ef 100644 --- a/addon/-private/system/coerce-id.js +++ b/addon/-private/system/coerce-id.ts @@ -4,12 +4,22 @@ // and lose type information. For example, Ember's router may put a record's // ID into the URL, and if we later try to deserialize that URL and find the // corresponding record, we will not know if it is a string or a number. -export default function coerceId(id) { +type Coercable = string | number | boolean | null | undefined | symbol; + +function coerceId(id: number | boolean | symbol): string; +function coerceId(id: null | undefined | ''): null; +function coerceId(id: string): string | null; +function coerceId(id: Coercable): string | null { if (id === null || id === undefined || id === '') { return null; } if (typeof id === 'string') { return id; } + if (typeof id === 'symbol') { + return id.toString(); + } return '' + id; } + +export default coerceId; diff --git a/addon/-private/system/references/record.js b/addon/-private/system/references/record.ts similarity index 95% rename from addon/-private/system/references/record.js rename to addon/-private/system/references/record.ts index ebc08a5680c..9a07becb36d 100644 --- a/addon/-private/system/references/record.js +++ b/addon/-private/system/references/record.ts @@ -9,11 +9,8 @@ import Reference from './reference'; @namespace DS */ export default class RecordReference extends Reference { - constructor(store, internalModel) { - super(store, internalModel); - this.type = internalModel.modelName; - this._id = internalModel.id; - } + public type = this.internalModel.modelName; + private _id = this.internalModel.id; /** The `id` of the record that this reference refers to. @@ -52,7 +49,7 @@ export default class RecordReference extends Reference { @method remoteType @return {String} 'identity' */ - remoteType() { + remoteType(): 'link' | 'id' | 'identity' { return 'identity'; } diff --git a/addon/-private/system/references/reference.js b/addon/-private/system/references/reference.ts similarity index 67% rename from addon/-private/system/references/reference.js rename to addon/-private/system/references/reference.ts index 6bb9d75eb7a..0c01378f2a3 100644 --- a/addon/-private/system/references/reference.js +++ b/addon/-private/system/references/reference.ts @@ -1,11 +1,34 @@ -export default class Reference { - constructor(store, internalModel) { - this.store = store; - this.internalModel = internalModel; - this.recordData = internalModel._recordData; +import Store from './../../system/store'; +import InternalModel from './../../system/model/internal-model'; +import { Object as JSONObject, Value as JSONValue } from 'json-typescript'; + +interface ResourceIdentifier { + links?: { + related?: string; + }; + meta?: JSONObject; +} + +function isResourceIdentiferWithRelatedLinks( + value: any +): value is ResourceIdentifier & { links: { related: string } } { + return value && value.links && value.links.related; +} + +export default abstract class Reference { + public recordData: InternalModel['_recordData']; + constructor( + // TODO: shouldn't have to instance + public store: InstanceType, + public internalModel: InternalModel + ) { + this.recordData = this.internalModel._recordData; } - _resource() {} + public _resource(): + | ResourceIdentifier + | (JSONObject & { meta?: { [k: string]: JSONValue } }) + | void {} /** This returns a string that represents how the reference will be @@ -46,12 +69,11 @@ export default class Reference { @method remoteType @return {String} The name of the remote type. This should either be "link" or "ids" */ - remoteType() { + remoteType(): 'link' | 'id' | 'identity' { let value = this._resource(); - if (value && value.links && value.links.related) { + if (isResourceIdentiferWithRelatedLinks(value)) { return 'link'; } - return 'id'; } @@ -92,11 +114,13 @@ export default class Reference { @return {String} The link Ember Data will use to fetch or reload this belongs-to relationship. */ link() { - let link = null; + let link: string | null = null; let resource = this._resource(); - if (resource && resource.links && resource.links.related) { - link = resource.links.related; + if (isResourceIdentiferWithRelatedLinks(resource)) { + if (resource.links) { + link = resource.links.related; + } } return link; } @@ -140,9 +164,9 @@ export default class Reference { @return {Object} The meta information for the belongs-to relationship. */ meta() { - let meta = null; + let meta: { [k: string]: JSONValue } | null = null; let resource = this._resource(); - if (resource && resource.meta) { + if (resource && resource.meta && typeof resource.meta === 'object') { meta = resource.meta; } return meta; diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 0cb0b2bcb15..dc1e822af94 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -62,8 +62,6 @@ function promiseRecord(internalModelPromise, label) { return promiseObject(toReturn, label); } -let Store; - // Implementors Note: // // The variables in this file are consistently named according to the following @@ -181,7 +179,7 @@ const { @namespace DS @extends Ember.Service */ -Store = Service.extend({ +const Store = Service.extend({ /** @method init @private @@ -737,8 +735,8 @@ Store = Service.extend({ @method findRecord @param {String} modelName @param {(String|Integer)} id + @param {Object} [options] @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models - @param {Object} options @return {Promise} promise */ findRecord(modelName, id, options) { diff --git a/package.json b/package.json index dfe029169ab..9f4f2f9423f 100644 --- a/package.json +++ b/package.json @@ -116,6 +116,7 @@ "execa": "^1.0.0", "github": "^14.0.0", "glob": "^7.1.3", + "json-typescript": "^1.0.1", "loader.js": "^4.7.0", "mocha": "^5.2.0", "mocha-only-detector": "1.0.0", diff --git a/tsconfig.json b/tsconfig.json index 30fb4d382c5..a8a092aec80 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "allowSyntheticDefaultImports": true, "noImplicitAny": false, "noEmitOnError": false, + "strictNullChecks": true, "noEmit": true, "skipLibCheck": true, "inlineSourceMap": true, diff --git a/yarn.lock b/yarn.lock index b395a39a2c8..aee2295e20d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6693,6 +6693,11 @@ json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +json-typescript@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-typescript/-/json-typescript-1.0.1.tgz#9d71a17627a20a61dbbf504e33561030f4eefd7f" + integrity sha512-+PBRanpdVZ/MV8jJ044EuJ1muG3Ic/jLAZYgDE0WPqBbU46D3w3e+yL4ZbxwTfGbR9ff6JZlAGeGxSmumbQl0A== + json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" From a9ad27962013ae0dc842cd32cddd15bb6ce26132 Mon Sep 17 00:00:00 2001 From: Felix Fichte Date: Sat, 3 Nov 2018 15:13:42 +0100 Subject: [PATCH 2405/2527] [DOC] Add Reference doc and AdapterError uses --- addon/-private/adapters/errors.js | 8 ++++++++ addon/-private/system/references/reference.ts | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/addon/-private/adapters/errors.js b/addon/-private/adapters/errors.js index 4591522e587..4feb710211d 100644 --- a/addon/-private/adapters/errors.js +++ b/addon/-private/adapters/errors.js @@ -164,6 +164,7 @@ AdapterError.extend = extendFn(AdapterError); @class InvalidError @namespace DS + @extends AdapterError */ export const InvalidError = extend( AdapterError, @@ -201,6 +202,7 @@ export const InvalidError = extend( @class TimeoutError @namespace DS + @extends AdapterError */ export const TimeoutError = extend(AdapterError, 'The adapter operation timed out'); @@ -212,6 +214,7 @@ export const TimeoutError = extend(AdapterError, 'The adapter operation timed ou @class AbortError @namespace DS + @extends AdapterError */ export const AbortError = extend(AdapterError, 'The adapter operation was aborted'); @@ -247,6 +250,7 @@ export const AbortError = extend(AdapterError, 'The adapter operation was aborte @class UnauthorizedError @namespace DS + @extends AdapterError */ export const UnauthorizedError = extend(AdapterError, 'The adapter operation is unauthorized'); @@ -259,6 +263,7 @@ export const UnauthorizedError = extend(AdapterError, 'The adapter operation is @class ForbiddenError @namespace DS + @extends AdapterError */ export const ForbiddenError = extend(AdapterError, 'The adapter operation is forbidden'); @@ -297,6 +302,7 @@ export const ForbiddenError = extend(AdapterError, 'The adapter operation is for @class NotFoundError @namespace DS + @extends AdapterError */ export const NotFoundError = extend(AdapterError, 'The adapter could not find the resource'); @@ -309,6 +315,7 @@ export const NotFoundError = extend(AdapterError, 'The adapter could not find th @class ConflictError @namespace DS + @extends AdapterError */ export const ConflictError = extend(AdapterError, 'The adapter operation failed due to a conflict'); @@ -319,6 +326,7 @@ export const ConflictError = extend(AdapterError, 'The adapter operation failed @class ServerError @namespace DS + @extends AdapterError */ export const ServerError = extend( AdapterError, diff --git a/addon/-private/system/references/reference.ts b/addon/-private/system/references/reference.ts index 0c01378f2a3..3ab9c830210 100644 --- a/addon/-private/system/references/reference.ts +++ b/addon/-private/system/references/reference.ts @@ -15,6 +15,13 @@ function isResourceIdentiferWithRelatedLinks( return value && value.links && value.links.related; } +/** + This is the baseClass for the different References + like RecordReference/HasManyReference/BelongsToReference + + @class Reference + @namespace DS + */ export default abstract class Reference { public recordData: InternalModel['_recordData']; constructor( From b1426263e184480755cb0ad6fe2ec9d2babc5942 Mon Sep 17 00:00:00 2001 From: Aegir Thorsteinsson Date: Mon, 5 Nov 2018 14:18:58 -0800 Subject: [PATCH 2406/2527] [BUGFIX inspector] Fix columns names in debug-adapter (#5733) * [BUGFIX inspector] Include primaryKey column and default to 'id' * [BUGFIX inspector] Always use `id` for primary key * [CHORE tests] modernize integration/debug-adapter-test * [BUGFIX inspector] Revert changes to id * [BUGFIX inspector] Add test for column names --- addon/-private/system/debug/debug-adapter.js | 10 +- tests/integration/debug-adapter-test.js | 210 +++++++++---------- 2 files changed, 109 insertions(+), 111 deletions(-) diff --git a/addon/-private/system/debug/debug-adapter.js b/addon/-private/system/debug/debug-adapter.js index 2904a93427f..67476bc5ca8 100644 --- a/addon/-private/system/debug/debug-adapter.js +++ b/addon/-private/system/debug/debug-adapter.js @@ -31,6 +31,14 @@ export default DataAdapter.extend({ return typeClass !== Model && Model.detect(typeClass); }, + columnNameToDesc(name) { + return capitalize( + underscore(name) + .replace(/_/g, ' ') + .trim() + ); + }, + columnsForType(typeClass) { let columns = [ { @@ -44,7 +52,7 @@ export default DataAdapter.extend({ if (count++ > self.attributeLimit) { return false; } - let desc = capitalize(underscore(name).replace('_', ' ')); + let desc = this.columnNameToDesc(name); columns.push({ name: name, desc: desc }); }); return columns; diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index 13a7e11a7dc..32201a15855 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -1,79 +1,52 @@ +import { setupTest } from 'ember-qunit'; import { A } from '@ember/array'; -import Application from '@ember/application'; import { get } from '@ember/object'; -import { run } from '@ember/runloop'; - +import Model from 'ember-data/model'; +import { attr } from '@ember-decorators/data'; +import Adapter from 'ember-data/adapter'; import { module, test } from 'qunit'; +import { settled } from '@ember/test-helpers'; -import DS from 'ember-data'; - -let App, store, debugAdapter; - -module('DS.DebugAdapter', { - beforeEach() { - run(function() { - App = Application.extend({ - toString() { - return 'debug-app'; - }, - }).create(); - - App.StoreService = DS.Store.extend({}); - - App.ApplicationAdapter = DS.Adapter.extend({ - shouldBackgroundReloadRecord: () => false, - }); +class Post extends Model { + @attr + title; +} - App.Post = DS.Model.extend({ - title: DS.attr('string'), - }); - - // TODO: Remove this when Ember is upgraded to >= 1.13 - App.Post.reopenClass({ - _debugContainerKey: 'model:post', - }); - }); +module('integration/debug-adapter - DS.DebugAdapter', function(hooks) { + setupTest(hooks); - store = App.__container__.lookup('service:store'); - debugAdapter = App.__container__.lookup('data-adapter:main'); + let store, debugAdapter; - let klass; + hooks.beforeEach(function() { + let { owner } = this; - if (App.__container__.factoryFor) { - klass = App.__container__.factoryFor('model:post').class; - } else { - klass = App.__container__.lookupFactory('model:post'); - } + owner.register('model:post', Post); + store = owner.lookup('service:store'); + debugAdapter = owner.lookup('data-adapter:main'); debugAdapter.reopen({ getModelTypes() { - return A([{ klass, name: 'post' }]); + return A([{ klass: Post, name: 'post' }]); }, }); - }, - afterEach() { - run(App, App.destroy); - App = store = null; - }, -}); + }); -test('Watching Model Types', function(assert) { - assert.expect(5); + test('Watching Model Types', async function(assert) { + assert.expect(5); - function added(types) { - assert.equal(types.length, 1); - assert.equal(types[0].name, 'post'); - assert.equal(types[0].count, 0); - assert.strictEqual(types[0].object, store.modelFor('post')); - } + function added(types) { + assert.equal(types.length, 1); + assert.equal(types[0].name, 'post'); + assert.equal(types[0].count, 0); + assert.strictEqual(types[0].object, store.modelFor('post')); + } - function updated(types) { - assert.equal(types[0].count, 1); - } + function updated(types) { + assert.equal(types[0].count, 1); + } - debugAdapter.watchModelTypes(added, updated); + debugAdapter.watchModelTypes(added, updated); - run(() => { store.push({ data: { type: 'post', @@ -84,12 +57,19 @@ test('Watching Model Types', function(assert) { }, }); }); -}); -test('Watching Records', function(assert) { - var post, record, addedRecords, updatedRecords, removedIndex, removedCount; + test('Watching Records', async function(assert) { + let addedRecords, updatedRecords, removedIndex, removedCount; + + this.owner.register( + 'adapter:application', + Adapter.extend({ + shouldBackgroundReloadRecord() { + return false; + }, + }) + ); - run(function() { store.push({ data: { type: 'post', @@ -99,60 +79,70 @@ test('Watching Records', function(assert) { }, }, }); - }); - var recordsAdded = function(wrappedRecords) { - addedRecords = wrappedRecords; - }; - var recordsUpdated = function(wrappedRecords) { - updatedRecords = wrappedRecords; - }; - var recordsRemoved = function(index, count) { - removedIndex = index; - removedCount = count; - }; - - let modelClassOrName; - if (debugAdapter.get('acceptsModelName')) { - modelClassOrName = 'post'; - } else { - modelClassOrName = App.__container__.lookupFactory('model:post'); - } - debugAdapter.watchRecords(modelClassOrName, recordsAdded, recordsUpdated, recordsRemoved); - - assert.equal(get(addedRecords, 'length'), 1); - record = addedRecords[0]; - assert.deepEqual(record.columnValues, { id: '1', title: 'Clean Post' }); - assert.deepEqual(record.filterValues, { isNew: false, isModified: false, isClean: true }); - assert.deepEqual(record.searchKeywords, ['1', 'Clean Post']); - assert.deepEqual(record.color, 'black'); - - run(function() { - post = store.findRecord('post', 1); - }); + var recordsAdded = function(wrappedRecords) { + addedRecords = wrappedRecords; + }; + var recordsUpdated = function(wrappedRecords) { + updatedRecords = wrappedRecords; + }; + var recordsRemoved = function(index, count) { + removedIndex = index; + removedCount = count; + }; + + debugAdapter.watchRecords('post', recordsAdded, recordsUpdated, recordsRemoved); + + assert.equal(get(addedRecords, 'length'), 1); + let record = addedRecords[0]; + assert.deepEqual(record.columnValues, { id: '1', title: 'Clean Post' }); + assert.deepEqual(record.filterValues, { isNew: false, isModified: false, isClean: true }); + assert.deepEqual(record.searchKeywords, ['1', 'Clean Post']); + assert.deepEqual(record.color, 'black'); + + let post = await store.findRecord('post', 1); - run(function() { post.set('title', 'Modified Post'); - }); - assert.equal(get(updatedRecords, 'length'), 1); - record = updatedRecords[0]; - assert.deepEqual(record.columnValues, { id: '1', title: 'Modified Post' }); - assert.deepEqual(record.filterValues, { isNew: false, isModified: true, isClean: false }); - assert.deepEqual(record.searchKeywords, ['1', 'Modified Post']); - assert.deepEqual(record.color, 'blue'); + assert.equal(get(updatedRecords, 'length'), 1); + record = updatedRecords[0]; + assert.deepEqual(record.columnValues, { id: '1', title: 'Modified Post' }); + assert.deepEqual(record.filterValues, { isNew: false, isModified: true, isClean: false }); + assert.deepEqual(record.searchKeywords, ['1', 'Modified Post']); + assert.deepEqual(record.color, 'blue'); + + post = store.createRecord('post', { id: '2', title: 'New Post' }); + + await settled(); - post = store.createRecord('post', { id: '2', title: 'New Post' }); + assert.equal(get(addedRecords, 'length'), 1); + record = addedRecords[0]; + assert.deepEqual(record.columnValues, { id: '2', title: 'New Post' }); + assert.deepEqual(record.filterValues, { isNew: true, isModified: false, isClean: false }); + assert.deepEqual(record.searchKeywords, ['2', 'New Post']); + assert.deepEqual(record.color, 'green'); - assert.equal(get(addedRecords, 'length'), 1); - record = addedRecords[0]; - assert.deepEqual(record.columnValues, { id: '2', title: 'New Post' }); - assert.deepEqual(record.filterValues, { isNew: true, isModified: false, isClean: false }); - assert.deepEqual(record.searchKeywords, ['2', 'New Post']); - assert.deepEqual(record.color, 'green'); + post.unloadRecord(); - run(post, 'unloadRecord'); + await settled(); - assert.equal(removedIndex, 1); - assert.equal(removedCount, 1); + assert.equal(removedIndex, 1); + assert.equal(removedCount, 1); + }); + + test('Column names', function(assert) { + class Person extends Model { + @attr + title; + + @attr + firstOrLastName; + } + + const columns = debugAdapter.columnsForType(Person); + + assert.equal(columns[0].desc, 'Id'); + assert.equal(columns[1].desc, 'Title'); + assert.equal(columns[2].desc, 'First or last name'); + }); }); From 1b8ed3c5a5cbf902d858731e107460579d6378f3 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Nov 2018 00:12:28 -0800 Subject: [PATCH 2407/2527] [CHORE tests] modernize integration/adapter/build-url-mixin-test --- .../adapter/build-url-mixin-test.js | 461 ++++++++---------- 1 file changed, 194 insertions(+), 267 deletions(-) diff --git a/tests/integration/adapter/build-url-mixin-test.js b/tests/integration/adapter/build-url-mixin-test.js index 5bbdaa461d6..04ac25e974a 100644 --- a/tests/integration/adapter/build-url-mixin-test.js +++ b/tests/integration/adapter/build-url-mixin-test.js @@ -1,264 +1,209 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; import { decamelize, underscore } from '@ember/string'; -import RSVP from 'rsvp'; -import { run } from '@ember/runloop'; -import setupStore from 'dummy/tests/helpers/store'; +import { resolve } from 'rsvp'; import deepCopy from 'dummy/tests/helpers/deep-copy'; import { pluralize } from 'ember-inflector'; +import RESTAdapter from 'ember-data/adapters/rest'; +import Model from 'ember-data/model'; +import attr from 'ember-data/attr'; +import { belongsTo, hasMany } from 'ember-data/relationships'; -import { module, test } from 'qunit'; +module('integration/adapter/build-url-mixin - BuildURLMixin with RESTAdapter', function(hooks) { + setupTest(hooks); -import DS from 'ember-data'; + let store, adapter, Post, Comment, passedUrl; -let env, store, adapter, Post, Comment, SuperUser; -let passedUrl; + function ajaxResponse(value) { + adapter.ajax = function(url, verb, hash) { + passedUrl = url; -module('integration/adapter/build-url-mixin - BuildURLMixin with RESTAdapter', { - beforeEach() { - Post = DS.Model.extend({ - name: DS.attr('string'), - }); + return resolve(deepCopy(value)); + }; + } - Comment = DS.Model.extend({ - name: DS.attr('string'), + hooks.beforeEach(function() { + let { owner } = this; + const PostModel = Model.extend({ + name: attr('string'), }); - - SuperUser = DS.Model.extend(); - - env = setupStore({ - post: Post, - comment: Comment, - superUser: SuperUser, - adapter: DS.RESTAdapter, + const CommentModel = Model.extend({ + name: attr('string'), }); + const SuperUser = Model.extend({}); + + owner.register('adapter:application', RESTAdapter); + owner.register('model:comment', CommentModel); + owner.register('model:post', PostModel); + owner.register('model:super-user', SuperUser); - store = env.store; - adapter = env.adapter; + store = owner.lookup('service:store'); + adapter = store.adapterFor('application'); Post = store.modelFor('post'); Comment = store.modelFor('comment'); - SuperUser = store.modelFor('super-user'); passedUrl = null; - }, -}); - -function ajaxResponse(value) { - adapter.ajax = function(url, verb, hash) { - passedUrl = url; - - return run(RSVP, 'resolve', deepCopy(value)); - }; -} + }); -test('buildURL - with host and namespace', function(assert) { - run(() => { + test('buildURL - with host and namespace', async function(assert) { adapter.setProperties({ host: 'http://example.com', namespace: 'api/v1', }); - }); - ajaxResponse({ posts: [{ id: 1 }] }); + ajaxResponse({ posts: [{ id: 1 }] }); - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, 'http://example.com/api/v1/posts/1'); - }) - ); -}); + await store.findRecord('post', 1); + + assert.equal(passedUrl, 'http://example.com/api/v1/posts/1'); + }); -test('buildURL - with relative paths in links', function(assert) { - run(() => { + test('buildURL - with relative paths in links', async function(assert) { adapter.setProperties({ host: 'http://example.com', namespace: 'api/v1', }); - }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - - ajaxResponse({ posts: [{ id: 1, links: { comments: 'comments' } }] }); - - return run(() => - store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ comments: [{ id: 1 }] }); - return post.get('comments'); - }) - .then(comments => { - assert.equal(passedUrl, 'http://example.com/api/v1/posts/1/comments'); - }) - ); -}); + Post.reopen({ comments: hasMany('comment', { async: true }) }); + Comment.reopen({ post: belongsTo('post', { async: false }) }); -test('buildURL - with absolute paths in links', function(assert) { - run(() => { + ajaxResponse({ posts: [{ id: 1, links: { comments: 'comments' } }] }); + + let post = await store.findRecord('post', 1); + ajaxResponse({ comments: [{ id: 1 }] }); + + await post.get('comments'); + assert.equal(passedUrl, 'http://example.com/api/v1/posts/1/comments'); + }); + + test('buildURL - with absolute paths in links', async function(assert) { adapter.setProperties({ host: 'http://example.com', namespace: 'api/v1', }); + + Post.reopen({ comments: hasMany('comment', { async: true }) }); + Comment.reopen({ post: belongsTo('post', { async: false }) }); + + ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); + + let post = await store.findRecord('post', 1); + + ajaxResponse({ comments: [{ id: 1 }] }); + await post.get('comments'); + assert.equal(passedUrl, 'http://example.com/api/v1/posts/1/comments'); }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - - ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - - return run(() => - store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ comments: [{ id: 1 }] }); - return post.get('comments'); - }) - .then(comments => { - assert.equal(passedUrl, 'http://example.com/api/v1/posts/1/comments'); - }) - ); -}); -test('buildURL - with absolute paths in links and protocol relative host', function(assert) { - run(() => { + test('buildURL - with absolute paths in links and protocol relative host', async function(assert) { adapter.setProperties({ host: '//example.com', namespace: 'api/v1', }); + Post.reopen({ comments: hasMany('comment', { async: true }) }); + Comment.reopen({ post: belongsTo('post', { async: false }) }); + + ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); + + let post = await store.findRecord('post', 1); + ajaxResponse({ comments: [{ id: 1 }] }); + + await post.get('comments'); + assert.equal(passedUrl, '//example.com/api/v1/posts/1/comments'); }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - - ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - - return run(() => - store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ comments: [{ id: 1 }] }); - return post.get('comments'); - }) - .then(comments => { - assert.equal(passedUrl, '//example.com/api/v1/posts/1/comments'); - }) - ); -}); -test('buildURL - with absolute paths in links and host is /', function(assert) { - run(() => { + test('buildURL - with absolute paths in links and host is /', async function(assert) { adapter.setProperties({ host: '/', namespace: 'api/v1', }); - }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - - ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - - return run(() => - store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ comments: [{ id: 1 }] }); - return post.get('comments'); - }) - .then(comments => { - assert.equal(passedUrl, '/api/v1/posts/1/comments', 'host stripped out properly'); - }) - ); -}); + Post.reopen({ comments: hasMany('comment', { async: true }) }); + Comment.reopen({ post: belongsTo('post', { async: false }) }); -test('buildURL - with full URLs in links', function(assert) { - adapter.setProperties({ - host: 'http://example.com', - namespace: 'api/v1', - }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - - ajaxResponse({ - posts: [ - { - id: 1, - links: { comments: 'http://example.com/api/v1/posts/1/comments' }, - }, - ], - }); + ajaxResponse({ posts: [{ id: 1, links: { comments: '/api/v1/posts/1/comments' } }] }); - return run(() => { - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ comments: [{ id: 1 }] }); - return post.get('comments'); - }) - .then(comments => { - assert.equal(passedUrl, 'http://example.com/api/v1/posts/1/comments'); - }); - }); -}); + let post = await store.findRecord('post', 1); + ajaxResponse({ comments: [{ id: 1 }] }); -test('buildURL - with camelized names', function(assert) { - adapter.setProperties({ - pathForType(type) { - let decamelized = decamelize(type); - return underscore(pluralize(decamelized)); - }, + await post.get('comments'); + assert.equal(passedUrl, '/api/v1/posts/1/comments', 'host stripped out properly'); }); - ajaxResponse({ superUsers: [{ id: 1 }] }); + test('buildURL - with full URLs in links', async function(assert) { + adapter.setProperties({ + host: 'http://example.com', + namespace: 'api/v1', + }); + Post.reopen({ comments: hasMany('comment', { async: true }) }); + Comment.reopen({ post: belongsTo('post', { async: false }) }); + + ajaxResponse({ + posts: [ + { + id: 1, + links: { comments: 'http://example.com/api/v1/posts/1/comments' }, + }, + ], + }); + + let post = await store.findRecord('post', 1); + ajaxResponse({ comments: [{ id: 1 }] }); + + await post.get('comments'); + assert.equal(passedUrl, 'http://example.com/api/v1/posts/1/comments'); + }); - return run(() => { - return store.findRecord('super-user', 1).then(post => { - assert.equal(passedUrl, '/super_users/1'); + test('buildURL - with camelized names', async function(assert) { + adapter.setProperties({ + pathForType(type) { + let decamelized = decamelize(type); + return underscore(pluralize(decamelized)); + }, }); + + ajaxResponse({ superUsers: [{ id: 1 }] }); + + await store.findRecord('super-user', 1); + assert.equal(passedUrl, '/super_users/1'); }); -}); -test('buildURL - buildURL takes a record from find', function(assert) { - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - adapter.buildURL = function(type, id, snapshot) { - return '/posts/' + snapshot.belongsTo('post', { id: true }) + '/comments/' + snapshot.id; - }; + test('buildURL - buildURL takes a record from find', async function(assert) { + Comment.reopen({ post: belongsTo('post', { async: false }) }); - ajaxResponse({ comments: [{ id: 1 }] }); + adapter.buildURL = function(type, id, snapshot) { + return '/posts/' + snapshot.belongsTo('post', { id: true }) + '/comments/' + snapshot.id; + }; - let post; - run(() => { - post = store.push({ + ajaxResponse({ comments: [{ id: 1 }] }); + + let post = store.push({ data: { type: 'post', id: '2', }, }); - }); - return run(() => { - return store.findRecord('comment', 1, { preload: { post: post } }).then(post => { - assert.equal(passedUrl, '/posts/2/comments/1'); - }); + await store.findRecord('comment', 1, { preload: { post } }); + + assert.equal(passedUrl, '/posts/2/comments/1'); }); -}); -test('buildURL - buildURL takes the records from findMany', function(assert) { - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - - adapter.buildURL = function(type, ids, snapshots) { - if (Array.isArray(snapshots)) { - return ( - '/posts/' + snapshots.get('firstObject').belongsTo('post', { id: true }) + '/comments/' - ); - } - return ''; - }; - adapter.coalesceFindRequests = true; - - ajaxResponse({ comments: [{ id: 1 }, { id: 2 }, { id: 3 }] }); - let post; - - return run(() => { - post = store.push({ + test('buildURL - buildURL takes the records from findMany', async function(assert) { + Comment.reopen({ post: belongsTo('post', { async: false }) }); + Post.reopen({ comments: hasMany('comment', { async: true }) }); + + adapter.buildURL = function(type, ids, snapshots) { + if (Array.isArray(snapshots)) { + return ( + '/posts/' + snapshots.get('firstObject').belongsTo('post', { id: true }) + '/comments/' + ); + } + return ''; + }; + adapter.coalesceFindRequests = true; + + ajaxResponse({ comments: [{ id: 1 }, { id: 2 }, { id: 3 }] }); + let post = store.push({ data: { type: 'post', id: '2', @@ -274,21 +219,18 @@ test('buildURL - buildURL takes the records from findMany', function(assert) { }, }); - return post.get('comments').then(post => { - assert.equal(passedUrl, '/posts/2/comments/'); - }); + await post.get('comments'); + assert.equal(passedUrl, '/posts/2/comments/'); }); -}); -test('buildURL - buildURL takes a record from create', function(assert) { - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - adapter.buildURL = function(type, id, snapshot) { - return '/posts/' + snapshot.belongsTo('post', { id: true }) + '/comments/'; - }; + test('buildURL - buildURL takes a record from create', async function(assert) { + Comment.reopen({ post: belongsTo('post', { async: false }) }); + adapter.buildURL = function(type, id, snapshot) { + return '/posts/' + snapshot.belongsTo('post', { id: true }) + '/comments/'; + }; - ajaxResponse({ comments: [{ id: 1 }] }); + ajaxResponse({ comments: [{ id: 1 }] }); - return run(() => { let post = store.push({ data: { type: 'post', @@ -297,87 +239,78 @@ test('buildURL - buildURL takes a record from create', function(assert) { }); let comment = store.createRecord('comment'); comment.set('post', post); - return comment.save().then(post => { - assert.equal(passedUrl, '/posts/2/comments/'); - }); + await comment.save(); + assert.equal(passedUrl, '/posts/2/comments/'); }); -}); -test('buildURL - buildURL takes a record from create to query a resolved async belongsTo relationship', function(assert) { - Comment.reopen({ post: DS.belongsTo('post', { async: true }) }); + test('buildURL - buildURL takes a record from create to query a resolved async belongsTo relationship', async function(assert) { + Comment.reopen({ post: belongsTo('post', { async: true }) }); + adapter.buildURL = function(type, id, snapshot) { + return '/posts/' + snapshot.belongsTo('post', { id: true }) + '/comments/'; + }; - ajaxResponse({ posts: [{ id: 2 }] }); + let post = store.push({ + data: { + id: '2', + type: 'post', + attributes: { + name: 'foo', + }, + }, + }); - return run(() => { - store.findRecord('post', 2).then(post => { - assert.equal(post.get('id'), 2); + ajaxResponse({ comments: [{ id: 1 }] }); - adapter.buildURL = function(type, id, snapshot) { - return '/posts/' + snapshot.belongsTo('post', { id: true }) + '/comments/'; - }; + let comment = store.createRecord('comment'); + comment.set('post', post); - ajaxResponse({ comments: [{ id: 1 }] }); + await comment.save(); - let comment = store.createRecord('comment'); - comment.set('post', post); - return comment.save().then(post => { - assert.equal(passedUrl, '/posts/2/comments/'); - }); - }); + assert.equal(passedUrl, '/posts/2/comments/'); }); -}); -test('buildURL - buildURL takes a record from update', function(assert) { - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - adapter.buildURL = function(type, id, snapshot) { - return '/posts/' + snapshot.belongsTo('post', { id: true }) + '/comments/' + snapshot.id; - }; + test('buildURL - buildURL takes a record from update', async function(assert) { + Comment.reopen({ post: belongsTo('post', { async: false }) }); + adapter.buildURL = function(type, id, snapshot) { + return '/posts/' + snapshot.belongsTo('post', { id: true }) + '/comments/' + snapshot.id; + }; - ajaxResponse({ comments: [{ id: 1 }] }); + ajaxResponse({ comments: [{ id: 1 }] }); - let post, comment; - run(() => { - post = store.push({ + let post = store.push({ data: { type: 'post', id: '2', }, }); - comment = store.push({ + let comment = store.push({ data: { type: 'comment', id: '1', }, }); comment.set('post', post); - }); - return run(() => { - return comment.save().then(post => { - assert.equal(passedUrl, '/posts/2/comments/1'); - }); + await comment.save(); + assert.equal(passedUrl, '/posts/2/comments/1'); }); -}); - -test('buildURL - buildURL takes a record from delete', function(assert) { - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); - adapter.buildURL = function(type, id, snapshot) { - return 'posts/' + snapshot.belongsTo('post', { id: true }) + '/comments/' + snapshot.id; - }; - ajaxResponse({ comments: [{ id: 1 }] }); + test('buildURL - buildURL takes a record from delete', async function(assert) { + Comment.reopen({ post: belongsTo('post', { async: false }) }); + Post.reopen({ comments: hasMany('comment', { async: false }) }); + adapter.buildURL = function(type, id, snapshot) { + return 'posts/' + snapshot.belongsTo('post', { id: true }) + '/comments/' + snapshot.id; + }; - let post, comment; + ajaxResponse({ comments: [{ id: 1 }] }); - run(() => { - post = store.push({ + let post = store.push({ data: { type: 'post', id: '2', }, }); - comment = store.push({ + let comment = store.push({ data: { type: 'comment', id: '1', @@ -386,25 +319,19 @@ test('buildURL - buildURL takes a record from delete', function(assert) { comment.set('post', post); comment.deleteRecord(); - }); - return run(() => { - return comment.save().then(post => { - assert.equal(passedUrl, 'posts/2/comments/1'); - }); + await comment.save(); + assert.equal(passedUrl, 'posts/2/comments/1'); }); -}); -test('buildURL - with absolute namespace', function(assert) { - run(() => { + test('buildURL - with absolute namespace', async function(assert) { adapter.setProperties({ namespace: '/api/v1', }); - }); - ajaxResponse({ posts: [{ id: 1 }] }); + ajaxResponse({ posts: [{ id: 1 }] }); - return run(store, 'findRecord', 'post', 1).then(post => { + await store.findRecord('post', 1); assert.equal(passedUrl, '/api/v1/posts/1'); }); }); From bd74157c978f3d94799c06ca5812ae35d77a81d9 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 5 Nov 2018 17:11:22 -0800 Subject: [PATCH 2408/2527] isolate accessing recordData and relationships --- addon/-private/attr.ts | 3 +- addon/-private/index.js | 5 +++ addon/-private/system/many-array.js | 5 ++- addon/-private/system/model/internal-model.js | 27 +++++++----- addon/-private/system/model/model.js | 4 +- addon/-private/system/model/record-data.js | 12 +----- addon/-private/system/record-data-for.js | 28 ++++++++++++ .../-private/system/references/belongs-to.js | 3 +- addon/-private/system/references/has-many.js | 3 +- addon/-private/system/references/reference.ts | 7 +-- .../system/relationships/state/belongs-to.js | 10 ----- .../relationships/state/relationship.js | 15 +++---- addon/-private/system/snapshot.js | 5 ++- addon/-private/system/store.js | 10 ++--- tests/integration/records/record-data-test.js | 10 ++--- tests/integration/records/unload-test.js | 4 +- .../relationships/belongs-to-test.js | 43 +++++++++++-------- .../relationships/has-many-test.js | 25 +++++------ tests/unit/model-test.js | 3 +- 19 files changed, 124 insertions(+), 98 deletions(-) create mode 100644 addon/-private/system/record-data-for.js diff --git a/addon/-private/attr.ts b/addon/-private/attr.ts index 7eb1698e67d..94d424cb3f3 100644 --- a/addon/-private/attr.ts +++ b/addon/-private/attr.ts @@ -1,6 +1,7 @@ import { computed } from '@ember/object'; import { assert } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; +import recordDataFor from './system/record-data-for'; /** @module ember-data */ @@ -19,7 +20,7 @@ function getDefaultValue(record, options, key) { } function hasValue(internalModel, key) { - return internalModel._recordData.hasAttr(key); + return recordDataFor(internalModel).hasAttr(key); } interface AttrOptions { diff --git a/addon/-private/index.js b/addon/-private/index.js index e8da57915cd..a1f3e29e5ea 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -23,6 +23,11 @@ export { } from './adapters/errors'; // maybe public ? +export { + default as recordDataFor, + relationshipsFor, + relationshipStateFor, +} from './system/record-data-for'; export { default as normalizeModelName } from './system/normalize-model-name'; export { getOwner, modelHasAttributeOrRelationshipNamedType } from './utils'; export { default as coerceId } from './system/coerce-id'; diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index a66935cb28a..8b9c91055fe 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -11,6 +11,7 @@ import { assert } from '@ember/debug'; import { PromiseArray } from './promise-proxies'; import { _objectIsAlive } from './store/common'; import diffArray from './diff-array'; +import recordDataFor from './record-data-for'; /** A `ManyArray` is a `MutableArray` that represents the contents of a has-many @@ -198,7 +199,7 @@ export default EmberObject.extend(MutableArray, Evented, { internalModels = this.currentState.slice(idx, idx + amt); this.get('recordData').removeFromHasMany( this.get('key'), - internalModels.map(im => im._recordData) + internalModels.map(im => recordDataFor(im)) ); } if (objects) { @@ -208,7 +209,7 @@ export default EmberObject.extend(MutableArray, Evented, { ); this.get('recordData').addToHasMany( this.get('key'), - objects.map(obj => obj._internalModel._recordData), + objects.map(obj => recordDataFor(obj)), idx ); } diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index b6260465521..568a9ea1fc1 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -16,6 +16,7 @@ import { PromiseBelongsTo, PromiseManyArray } from '../promise-proxies'; import { getOwner } from '../../utils'; import { RecordReference, BelongsToReference, HasManyReference } from '../references'; +import { default as recordDataFor, relationshipStateFor } from '../record-data-for'; /* The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached @@ -713,10 +714,7 @@ export default class InternalModel { } setDirtyBelongsTo(key, value) { - if (value && !value.then) { - value = extractRecordDataFromRecord(value); - } - return this._recordData.setDirtyBelongsTo(key, value); + return this._recordData.setDirtyBelongsTo(key, extractRecordDataFromRecord(value)); } setDirtyAttribute(key, value) { @@ -1217,7 +1215,7 @@ export default class InternalModel { if (!reference) { // TODO IGOR AND DAVID REFACTOR - let relationship = this._recordData._relationships.get(name); + let relationship = relationshipStateFor(this, name); if (DEBUG) { let modelName = this.modelName; @@ -1266,12 +1264,19 @@ function extractRecordDatasFromRecords(records) { return records.map(extractRecordDataFromRecord); } -function extractRecordDataFromRecord(recordOrPromiseProxy) { - // TODO @runspired async createRecord would resolve this issue - // we leak record promises to RecordData by necessity :'( - if (!recordOrPromiseProxy || (recordOrPromiseProxy && recordOrPromiseProxy.then)) { - return recordOrPromiseProxy; +function extractRecordDataFromRecord(recordOrPromiseRecord) { + if (!recordOrPromiseRecord) { + return null; + } + + if (recordOrPromiseRecord.then) { + let content = recordOrPromiseRecord.get && recordOrPromiseRecord.get('content'); + assert( + 'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.', + content !== undefined + ); + return content ? recordDataFor(content) : null; } - return recordOrPromiseProxy._internalModel._recordData; + return recordDataFor(recordOrPromiseRecord); } diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 2764a693130..134b9acd7dc 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -12,7 +12,7 @@ import { relatedTypesDescriptor, relationshipsDescriptor, } from '../relationships/ext'; - +import recordDataFor from '../record-data-for'; import Ember from 'ember'; import InternalModel from './internal-model'; import RootState from './states'; @@ -1147,7 +1147,7 @@ Object.defineProperty(Model.prototype, 'data', { until: '3.9', } ); - return this._internalModel._recordData._data; + return recordDataFor(this)._data; }, }); diff --git a/addon/-private/system/model/record-data.js b/addon/-private/system/model/record-data.js index 4c5406e241f..18dfe0fd537 100644 --- a/addon/-private/system/model/record-data.js +++ b/addon/-private/system/model/record-data.js @@ -283,16 +283,8 @@ export default class RecordData { return this._relationships.get(key).getData(); } - setDirtyBelongsTo(key, recordDataOrPromise) { - if (recordDataOrPromise === undefined) { - recordDataOrPromise = null; - } - - if (recordDataOrPromise && recordDataOrPromise.then) { - this._relationships.get(key).setRecordPromise(recordDataOrPromise); - } else { - this._relationships.get(key).setRecordData(recordDataOrPromise); - } + setDirtyBelongsTo(key, recordData) { + this._relationships.get(key).setRecordData(recordData); } setDirtyAttribute(key, value) { diff --git a/addon/-private/system/record-data-for.js b/addon/-private/system/record-data-for.js new file mode 100644 index 00000000000..02b3aff0dce --- /dev/null +++ b/addon/-private/system/record-data-for.js @@ -0,0 +1,28 @@ +/** + * Returns the RecordData instance associated with a given + * DS.Model or InternalModel. + * + * Intentionally "loose" to allow anything with an _internalModel + * property until InternalModel is eliminated. + * + * Intentionally not typed to `InternalModel` due to circular dependency + * which that creates. + * + * Overtime, this should shift to a "weakmap" based lookup in the + * "Ember.getOwner(obj)" style. + */ +export default function recordDataFor(instance) { + let internalModel = instance._internalModel || instance.internalModel || instance; + + return internalModel._recordData || null; +} + +export function relationshipsFor(instance) { + let recordData = recordDataFor(instance) || instance; + + return recordData._relationships; +} + +export function relationshipStateFor(instance, propertyName) { + return relationshipsFor(instance).get(propertyName); +} diff --git a/addon/-private/system/references/belongs-to.js b/addon/-private/system/references/belongs-to.js index e0c0ea10c10..f75d0ae4ab4 100644 --- a/addon/-private/system/references/belongs-to.js +++ b/addon/-private/system/references/belongs-to.js @@ -2,6 +2,7 @@ import { resolve } from 'rsvp'; import { assertPolymorphicType } from 'ember-data/-debug'; import Model from '../model/model'; import Reference from './reference'; +import recordDataFor from '../record-data-for'; /** A BelongsToReference is a low-level API that allows users and @@ -137,7 +138,7 @@ export default class BelongsToReference extends Reference { ); //TODO Igor cleanup, maybe move to relationship push - this.belongsToRelationship.setCanonicalRecordData(record._internalModel._recordData); + this.belongsToRelationship.setCanonicalRecordData(recordDataFor(record)); return record; }); diff --git a/addon/-private/system/references/has-many.js b/addon/-private/system/references/has-many.js index ec2832fc2e4..425f2ed42d8 100644 --- a/addon/-private/system/references/has-many.js +++ b/addon/-private/system/references/has-many.js @@ -3,6 +3,7 @@ import { get } from '@ember/object'; import Reference from './reference'; import { DEBUG } from '@glimmer/env'; import { assertPolymorphicType } from 'ember-data/-debug'; +import recordDataFor from '../record-data-for'; /** A HasManyReference is a low-level API that allows users and addon @@ -180,7 +181,7 @@ export default class HasManyReference extends Reference { this.store ); } - return record._internalModel._recordData; + return recordDataFor(record); }); this.hasManyRelationship.computeChanges(internalModels); diff --git a/addon/-private/system/references/reference.ts b/addon/-private/system/references/reference.ts index 3ab9c830210..0e55b15a6c0 100644 --- a/addon/-private/system/references/reference.ts +++ b/addon/-private/system/references/reference.ts @@ -1,5 +1,6 @@ -import Store from './../../system/store'; -import InternalModel from './../../system/model/internal-model'; +import Store from '../store'; +import InternalModel from '../model/internal-model'; +import recordDataFor from '../record-data-for'; import { Object as JSONObject, Value as JSONValue } from 'json-typescript'; interface ResourceIdentifier { @@ -29,7 +30,7 @@ export default abstract class Reference { public store: InstanceType, public internalModel: InternalModel ) { - this.recordData = this.internalModel._recordData; + this.recordData = recordDataFor(this); } public _resource(): diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index d8dcfe15c87..2a747da0963 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -116,16 +116,6 @@ export default class BelongsToRelationship extends Relationship { this.notifyBelongsToChange(); } - setRecordPromise(newPromise) { - let content = newPromise.get && newPromise.get('content'); - assert( - 'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.', - content !== undefined - ); - // TODO Igor deal with this - this.setRecordData(content ? content._internalModel._recordData : content); - } - removeRecordDataFromOwn(recordData) { if (!this.members.has(recordData)) { return; diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index a2b008a353c..6d91862bae8 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -1,7 +1,7 @@ /* global heimdall */ import { guidFor } from '@ember/object/internals'; import { get } from '@ember/object'; - +import { relationshipStateFor } from '../../record-data-for'; import { assert, warn } from '@ember/debug'; import OrderedSet from '../../ordered-set'; import _normalizeLink from '../../normalize-link'; @@ -242,7 +242,7 @@ export default class Relationship { if (!this._hasSupportForRelationships(inverseRecordData)) { return; } - let relationship = inverseRecordData._relationships.get(this.inverseKey); + let relationship = relationshipStateFor(inverseRecordData, this.inverseKey); relationship.inverseDidDematerialize(this.recordData); }); } @@ -354,8 +354,7 @@ export default class Relationship { if (!this._hasSupportForRelationships(recordData)) { return; } - let relationships = recordData._relationships; - let relationship = relationships.get(this.inverseKey); + let relationship = relationshipStateFor(recordData, this.inverseKey); // if we have only just initialized the inverse relationship, then it // already has this.recordData in its canonicalMembers, so skip the // unnecessary work. The exception to this is polymorphic @@ -417,7 +416,7 @@ export default class Relationship { this.members.addWithIndex(recordData, idx); this.notifyRecordRelationshipAdded(recordData, idx); if (this._hasSupportForRelationships(recordData) && this.inverseKey) { - recordData._relationships.get(this.inverseKey).addRecordData(this.recordData); + relationshipStateFor(recordData, this.inverseKey).addRecordData(this.recordData); } else { if (this._hasSupportForImplicitRelationships(recordData)) { if (!recordData._implicitRelationships[this.inverseKeyForImplicit]) { @@ -462,7 +461,7 @@ export default class Relationship { if (!this._hasSupportForRelationships(recordData)) { return; } - let inverseRelationship = recordData._relationships.get(this.inverseKey); + let inverseRelationship = relationshipStateFor(recordData, this.inverseKey); //Need to check for existence, as the record might unloading at the moment if (inverseRelationship) { inverseRelationship.removeRecordDataFromOwn(this.recordData); @@ -479,7 +478,7 @@ export default class Relationship { if (!this._hasSupportForRelationships(recordData)) { return; } - let inverseRelationship = recordData._relationships.get(this.inverseKey); + let inverseRelationship = relationshipStateFor(recordData, this.inverseKey); //Need to check for existence, as the record might unloading at the moment if (inverseRelationship) { inverseRelationship.removeCanonicalRecordDataFromOwn(this.recordData); @@ -514,7 +513,7 @@ export default class Relationship { const id = guidFor(inverseRecordData); if (this._hasSupportForRelationships(inverseRecordData) && seen[id] === undefined) { - const relationship = inverseRecordData._relationships.get(this.inverseKey); + const relationship = relationshipStateFor(inverseRecordData, this.inverseKey); relationship.removeCompletelyFromOwn(recordData); seen[id] = true; } diff --git a/addon/-private/system/snapshot.js b/addon/-private/system/snapshot.js index 88b208e0bc9..ca36f1bcb8b 100644 --- a/addon/-private/system/snapshot.js +++ b/addon/-private/system/snapshot.js @@ -5,6 +5,7 @@ import { inspect } from '@ember/debug'; import EmberError from '@ember/error'; import { get } from '@ember/object'; import { assign } from '@ember/polyfills'; +import { relationshipStateFor } from './record-data-for'; /** @class Snapshot @@ -240,7 +241,7 @@ export default class Snapshot { ); } - relationship = this._internalModel._recordData._relationships.get(keyName); + relationship = relationshipStateFor(this, keyName); let value = relationship.getData(); let data = value && value.data; @@ -322,7 +323,7 @@ export default class Snapshot { ); } - relationship = this._internalModel._recordData._relationships.get(keyName); + relationship = relationshipStateFor(this, keyName); let value = relationship.getData(); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index dc1e822af94..53243976341 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -28,6 +28,7 @@ import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './store/comm import { normalizeResponseHelper } from './store/serializer-response'; import { serializerForAdapter } from './store/serializers'; +import recordDataFor from './record-data-for'; import { _find, @@ -1401,7 +1402,7 @@ const Store = Service.extend({ relationshipMeta, options ).then(internalModels => { - let payload = { data: internalModels.map(im => im._recordData.getResourceIdentifier()) }; + let payload = { data: internalModels.map(im => recordDataFor(im).getResourceIdentifier()) }; if (internalModels.meta !== undefined) { payload.meta = internalModels.meta; } @@ -1484,7 +1485,7 @@ const Store = Service.extend({ relationshipMeta, options ).then(internalModel => { - let response = internalModel && internalModel._recordData.getResourceIdentifier(); + let response = internalModel && recordDataFor(internalModel).getResourceIdentifier(); parentInternalModel.linkWasLoadedForRelationship(relationshipMeta.key, { data: response }); if (internalModel === null) { return null; @@ -2871,7 +2872,7 @@ const Store = Service.extend({ recordDataFor(modelName, id, clientId) { let internalModel = this._internalModelForId(modelName, id, clientId); - return internalModel._recordData; + return recordDataFor(internalModel); }, _internalModelForRecordData(recordData) { @@ -3434,9 +3435,6 @@ function _lookupModelFactory(store, normalizedModelName) { in this case */ function _modelForMixin(store, normalizedModelName) { - // container.registry = 2.1 - // container._registry = 1.11 - 2.0 - // container = < 1.11 let owner = getOwner(store); let mixin; diff --git a/tests/integration/records/record-data-test.js b/tests/integration/records/record-data-test.js index a9b9c3f9765..bab17bdc010 100644 --- a/tests/integration/records/record-data-test.js +++ b/tests/integration/records/record-data-test.js @@ -4,7 +4,7 @@ import Model from 'ember-data/model'; import { run } from '@ember/runloop'; import { attr, belongsTo, hasMany } from '@ember-decorators/data'; import { assign } from '@ember/polyfills'; -import { RecordData } from 'ember-data/-private'; +import { RecordData, recordDataFor } from 'ember-data/-private'; class Person extends Model { @hasMany('pet', { inverse: null, async: false }) @@ -20,10 +20,6 @@ class Pet extends Model { name; } -function recordDataForRecord(record) { - return record._internalModel._recordData; -} - module('RecordData Compatibility', function(hooks) { let store; setupTest(hooks); @@ -157,11 +153,11 @@ module('RecordData Compatibility', function(hooks) { assert.equal(shen.get('name'), 'Shen', 'We found Shen'); assert.ok( - recordDataForRecord(chris) instanceof RecordData, + recordDataFor(chris) instanceof RecordData, 'We used the default record-data for person' ); assert.ok( - recordDataForRecord(shen) instanceof CustomRecordData, + recordDataFor(shen) instanceof CustomRecordData, 'We used the custom record-data for pets' ); diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 5cae3b46152..671ca5f30cf 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -6,6 +6,7 @@ import { run } from '@ember/runloop'; import { module, test } from 'qunit'; import DS from 'ember-data'; import setupStore from 'dummy/tests/helpers/store'; +import { recordDataFor } from 'ember-data/-private'; function idsFromOrderedSet(set) { return set.list.map(i => i.id); @@ -793,9 +794,8 @@ test('unloading a disconnected subgraph clears the relevant internal models', fu function countOrphanCalls(record) { let internalModel = record._internalModel; + let recordData = recordDataFor(record); let origCheck = internalModel._checkForOrphanedInternalModels; - - let recordData = internalModel._recordData; let origCleanup = recordData._cleanupOrphanedRecordDatas; internalModel._checkForOrphanedInternalModels = function() { diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index ef959776d65..f0850492ee5 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -15,7 +15,12 @@ import { reset as resetModelFactoryInjection, } from 'dummy/tests/helpers/model-factory-injection'; import DS from 'ember-data'; -import { RecordData } from 'ember-data/-private'; +import { + RecordData, + recordDataFor, + relationshipsFor, + relationshipStateFor, +} from 'ember-data/-private'; const { attr: DSattr, hasMany: DShasMany, belongsTo: DSbelongsTo } = DS; const { hash } = RSVP; @@ -1169,7 +1174,7 @@ test('belongsTo hasAnyRelationshipData async loaded', function(assert) { return run(() => { return store.findRecord('book', 1).then(book => { - let relationship = book._internalModel._relationships.get('author'); + let relationship = relationshipStateFor(book, 'author'); assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); }); @@ -1193,7 +1198,7 @@ test('belongsTo hasAnyRelationshipData sync loaded', function(assert) { return run(() => { return store.findRecord('book', 1).then(book => { - let relationship = book._internalModel._relationships.get('author'); + let relationship = relationshipStateFor(book, 'author'); assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); }); @@ -1221,7 +1226,7 @@ test('belongsTo hasAnyRelationshipData async not loaded', function(assert) { return run(() => { return store.findRecord('book', 1).then(book => { - let relationship = book._internalModel._relationships.get('author'); + let relationship = relationshipStateFor(book, 'author'); assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); }); }); @@ -1242,7 +1247,7 @@ test('belongsTo hasAnyRelationshipData sync not loaded', function(assert) { return run(() => { return store.findRecord('book', 1).then(book => { - let relationship = book._internalModel._relationships.get('author'); + let relationship = relationshipStateFor(book, 'author'); assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); }); }); @@ -1258,7 +1263,7 @@ test('belongsTo hasAnyRelationshipData NOT created', function(assert) { run(() => { let author = store.createRecord('author'); let book = store.createRecord('book', { name: 'The Greatest Book' }); - let relationship = book._internalModel._relationships.get('author'); + let relationship = relationshipStateFor(book, 'author'); assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); @@ -1267,7 +1272,7 @@ test('belongsTo hasAnyRelationshipData NOT created', function(assert) { author, }); - relationship = book._internalModel._relationships.get('author'); + relationship = relationshipStateFor(book, 'author'); assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); @@ -1282,7 +1287,7 @@ test('belongsTo hasAnyRelationshipData sync created', function(assert) { name: 'The Greatest Book', }); - let relationship = book._internalModel._relationships.get('author'); + let relationship = relationshipStateFor(book, 'author'); assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); book = store.createRecord('book', { @@ -1290,7 +1295,7 @@ test('belongsTo hasAnyRelationshipData sync created', function(assert) { author, }); - relationship = book._internalModel._relationships.get('author'); + relationship = relationshipStateFor(book, 'author'); assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); }); @@ -1307,7 +1312,7 @@ test("Model's belongsTo relationship should not be created during model creation }); assert.ok( - !user._internalModel._relationships.has('favouriteMessage'), + !relationshipsFor(user).has('favouriteMessage'), 'Newly created record should not have relationships' ); }); @@ -1321,7 +1326,7 @@ test("Model's belongsTo relationship should be created during model creation if }); assert.ok( - user._internalModel._relationships.has('favouriteMessage'), + relationshipsFor(user).has('favouriteMessage'), 'Newly created record with relationships in params passed in its constructor should have relationships' ); }); @@ -1334,7 +1339,7 @@ test("Model's belongsTo relationship should be created during 'set' method", fun user = env.store.createRecord('user'); user.set('favouriteMessage', message); assert.ok( - user._internalModel._relationships.has('favouriteMessage'), + relationshipsFor(user).has('favouriteMessage'), 'Newly created record with relationships in params passed in its constructor should have relationships' ); }); @@ -1347,7 +1352,7 @@ test("Model's belongsTo relationship should be created during 'get' method", fun user = env.store.createRecord('user'); user.get('favouriteMessage'); assert.ok( - user._internalModel._relationships.has('favouriteMessage'), + relationshipsFor(user).has('favouriteMessage'), 'Newly created record with relationships in params passed in its constructor should have relationships' ); }); @@ -2036,15 +2041,15 @@ test("belongsTo relationship doesn't trigger when model data doesn't support imp assert.notOk(book2.get('chapter')); assert.notOk(book.get('chapter')); assert.notOk( - book1._internalModel._recordData._implicitRelationships, + recordDataFor(book1)._implicitRelationships, 'no support for implicit relationship in custom RecordData' ); assert.notOk( - book2._internalModel._recordData._implicitRelationships, + recordDataFor(book2)._implicitRelationships, 'no support for implicit relationship in custom RecordData' ); assert.ok( - book._internalModel._recordData._implicitRelationships, + recordDataFor(book)._implicitRelationships, 'support for implicit relationship in default RecordData' ); @@ -2058,10 +2063,10 @@ test("belongsTo relationship doesn't trigger when model data doesn't support imp // doesn't support implicit Relationship run(() => { chapter.get('sections').removeObject(section1); - assert.notOk(section1._internalModel._recordData._implicitRelationships); + assert.notOk(recordDataFor(section1)._implicitRelationships); chapter.get('sections').removeObject(section2); - assert.notOk(section2._internalModel._recordData._implicitRelationships); + assert.notOk(recordDataFor(section2)._implicitRelationships); }); assert.equal(chapter.get('sections.length'), 0); @@ -2076,5 +2081,5 @@ test("belongsTo relationship doesn't trigger when model data doesn't support imp sections.addObject(env.store.createRecord('section', { id: 5 })); }); assert.equal(chapter.get('sections.length'), 3); - assert.notOk(sections.get('firstObject')._internalModel._recordData._implicitRelationships); + assert.notOk(recordDataFor(sections.get('firstObject'))._implicitRelationships); }); diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index cde132ce40a..23ff8d12903 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -11,6 +11,7 @@ import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test, skip } from 'qunit'; +import { relationshipStateFor, relationshipsFor } from 'ember-data/-private'; import DS from 'ember-data'; let env, store, User, Contact, Email, Phone, Message, Post, Comment; @@ -2715,7 +2716,7 @@ test('Relationship.clear removes all records correctly', function(assert) { }); run(() => { - post._internalModel._relationships.get('comments').clear(); + relationshipStateFor(post, 'comments').clear(); let comments = A(env.store.peekAll('comment')); assert.deepEqual(comments.mapBy('post'), [null, null, null]); }); @@ -2918,7 +2919,7 @@ test('hasMany hasAnyRelationshipData async loaded', function(assert) { return run(() => { return store.findRecord('chapter', 1).then(chapter => { - let relationship = chapter._internalModel._relationships.get('pages'); + let relationship = relationshipStateFor(chapter, 'pages'); assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); }); @@ -2944,7 +2945,7 @@ test('hasMany hasAnyRelationshipData sync loaded', function(assert) { return run(() => { return store.findRecord('chapter', 1).then(chapter => { - let relationship = chapter._internalModel._relationships.get('pages'); + let relationship = relationshipStateFor(chapter, 'pages'); assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); }); @@ -2974,7 +2975,7 @@ test('hasMany hasAnyRelationshipData async not loaded', function(assert) { return run(() => { return store.findRecord('chapter', 1).then(chapter => { - let relationship = chapter._internalModel._relationships.get('pages'); + let relationship = relationshipStateFor(chapter, 'pages'); assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); }); }); @@ -2995,7 +2996,7 @@ test('hasMany hasAnyRelationshipData sync not loaded', function(assert) { return run(() => { return store.findRecord('chapter', 1).then(chapter => { - let relationship = chapter._internalModel._relationships.get('pages'); + let relationship = relationshipStateFor(chapter, 'pages'); assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); }); }); @@ -3011,7 +3012,7 @@ test('hasMany hasAnyRelationshipData async created', function(assert) { let chapter = store.createRecord('chapter', { title: 'The Story Begins' }); let page = store.createRecord('page'); - let relationship = chapter._internalModel._relationships.get('pages'); + let relationship = relationshipStateFor(chapter, 'pages'); assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); chapter = store.createRecord('chapter', { @@ -3019,7 +3020,7 @@ test('hasMany hasAnyRelationshipData async created', function(assert) { pages: [page], }); - relationship = chapter._internalModel._relationships.get('pages'); + relationship = relationshipStateFor(chapter, 'pages'); assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); @@ -3027,7 +3028,7 @@ test('hasMany hasAnyRelationshipData sync created', function(assert) { assert.expect(2); let chapter = store.createRecord('chapter', { title: 'The Story Begins' }); - let relationship = chapter._internalModel._relationships.get('pages'); + let relationship = relationshipStateFor(chapter, 'pages'); assert.equal(relationship.hasAnyRelationshipData, false, 'relationship does not have data'); @@ -3035,7 +3036,7 @@ test('hasMany hasAnyRelationshipData sync created', function(assert) { title: 'The Story Begins', pages: [store.createRecord('page')], }); - relationship = chapter._internalModel._relationships.get('pages'); + relationship = relationshipStateFor(chapter, 'pages'); assert.equal(relationship.hasAnyRelationshipData, true, 'relationship has data'); }); @@ -3051,7 +3052,7 @@ test("Model's hasMany relationship should not be created during model creation", }); user = env.store.peekRecord('user', 1); assert.ok( - !user._internalModel._relationships.has('messages'), + !relationshipsFor(user).has('messages'), 'Newly created record should not have relationships' ); }); @@ -3063,7 +3064,7 @@ test("Model's belongsTo relationship should be created during 'get' method", fun user = env.store.createRecord('user'); user.get('messages'); assert.ok( - user._internalModel._relationships.has('messages'), + relationshipsFor(user).has('messages'), 'Newly created record with relationships in params passed in its constructor should have relationships' ); }); @@ -3101,7 +3102,7 @@ test('metadata is accessible when pushed as a meta property for a relationship', run(() => { assert.equal( - book._internalModel._relationships.get('chapters').meta.where, + relationshipStateFor(book, 'chapters').meta.where, 'the lefkada sea', 'meta is there' ); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 796852419ee..e81a271faf9 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -12,6 +12,7 @@ import JSONAPISerializer from 'ember-data/serializers/json-api'; import JSONSerializer from 'ember-data/serializers/json'; import { attr, hasMany, belongsTo } from '@ember-decorators/data'; import DSattr from 'ember-data/attr'; +import { recordDataFor } from 'ember-data/-private'; module('unit/model - Model', function(hooks) { setupTest(hooks); @@ -1032,7 +1033,7 @@ module('unit/model - Model', function(hooks) { }, }); - let recordData = person._internalModel._recordData; + let recordData = recordDataFor(person); assert.equal(recordData._attributes.name, undefined, 'the `_attributes` hash is clean'); set(person, 'name', 'Niceguy Dale'); From 83232916464ef440db09865ad9b97742e9348586 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Nov 2018 00:12:48 -0800 Subject: [PATCH 2409/2527] refactor away from env.container and env.registry --- tests/helpers/custom-adapter.js | 2 +- tests/helpers/store.js | 76 +++++++---- tests/integration/adapter/find-all-test.js | 12 +- tests/integration/adapter/find-test.js | 14 +- .../adapter/json-api-adapter-test.js | 2 +- .../integration/adapter/rest-adapter-test.js | 38 +++--- tests/integration/multiple-stores-test.js | 70 +++++----- .../integration/record-array-manager-test.js | 4 +- .../integration/records/delete-record-test.js | 2 +- .../integration/references/belongs-to-test.js | 2 +- tests/integration/references/has-many-test.js | 2 +- .../relationships/belongs-to-test.js | 22 +-- .../relationships/has-many-test.js | 6 +- .../relationships/json-api-links-test.js | 4 +- .../polymorphic-mixins-belongs-to-test.js | 2 +- .../polymorphic-mixins-has-many-test.js | 2 +- .../embedded-records-mixin-test.js | 129 ++++++++---------- .../serializers/json-api-serializer-test.js | 18 +-- .../serializers/json-serializer-test.js | 94 ++++++------- .../serializers/rest-serializer-test.js | 54 ++++---- tests/integration/store-test.js | 6 +- .../store/json-api-validation-test.js | 24 ++-- tests/integration/store/query-record-test.js | 8 +- tests/integration/store/query-test.js | 2 +- .../unit/model/relationships/has-many-test.js | 12 +- tests/unit/store/adapter-interop-test.js | 14 +- tests/unit/store/finders-test.js | 14 +- tests/unit/store/push-test.js | 18 +-- tests/unit/utils-test.js | 2 +- 29 files changed, 336 insertions(+), 319 deletions(-) diff --git a/tests/helpers/custom-adapter.js b/tests/helpers/custom-adapter.js index d5cc031a2f9..7e174c1520b 100644 --- a/tests/helpers/custom-adapter.js +++ b/tests/helpers/custom-adapter.js @@ -7,6 +7,6 @@ export default function(env, adapterDefinition) { adapter = DS.Adapter.extend(adapterDefinition); } let store = env.store; - env.registry.register('adapter:-custom', adapter); + env.owner.register('adapter:-custom', adapter); run(() => store.set('adapter', '-custom')); } diff --git a/tests/helpers/store.js b/tests/helpers/store.js index b2297944a58..f0ca5a9a8e3 100644 --- a/tests/helpers/store.js +++ b/tests/helpers/store.js @@ -1,26 +1,47 @@ import { dasherize } from '@ember/string'; +import { setResolver } from '@ember/test-helpers'; +import EmberObject from '@ember/object'; import Ember from 'ember'; -import DS from 'ember-data'; -import Owner from './owner'; +import Store from 'ember-data/store'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import RESTAdapter from 'ember-data/adapters/rest'; +import Adapter from 'ember-data/adapter'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; +import RESTSerializer from 'ember-data/serializers/rest'; +import JSONSerializer from 'ember-data/serializers/json'; +import config from '../../config/environment'; +import Resolver from '../../resolver'; + +const { _RegistryProxyMixin, _ContainerProxyMixin, Registry } = Ember; + +const Owner = EmberObject.extend(_RegistryProxyMixin, _ContainerProxyMixin); +const resolver = Resolver.create({ + namespace: { + modulePrefix: config.modulePrefix, + podModulePrefix: config.podModulePrefix, + }, +}); + +// TODO get us to a setApplication world instead +// seems to require killing off createStore +setResolver(resolver); export default function setupStore(options) { let container, registry, owner; let env = {}; options = options || {}; - if (Ember.Registry) { - registry = env.registry = new Ember.Registry(); - owner = Owner.create({ - __registry__: registry, - }); - container = env.container = registry.container({ - owner: owner, - }); - owner.__container__ = container; - } else { - container = env.container = new Ember.Container(); - registry = env.registry = container; - } + registry = new Registry(); + registry.optionsForType('serializer', { singleton: false }); + registry.optionsForType('adapter', { singleton: false }); + + owner = Owner.create({ __registry__: registry }); + container = registry.container({ owner }); + owner.__container__ = container; + + env.owner = owner; + env.container = container; + env.registry = registry; env.replaceContainerNormalize = function replaceContainerNormalize(fn) { if (env.registry) { @@ -42,23 +63,20 @@ export default function setupStore(options) { registry.register('model:' + dasherize(prop), options[prop]); } - registry.register( - 'service:store', - DS.Store.extend({ - adapter: adapter, - }) - ); - registry.optionsForType('serializer', { singleton: false }); registry.optionsForType('adapter', { singleton: false }); - registry.register('adapter:-default', DS.Adapter); - registry.register('serializer:-default', DS.JSONAPISerializer); - registry.register('serializer:-json', DS.JSONSerializer); - registry.register('serializer:-rest', DS.RESTSerializer); + owner.register('service:store', Store.extend({ adapter })); + owner.register('serializer:-default', JSONAPISerializer); + owner.register('serializer:-json', JSONSerializer); + owner.register('serializer:-rest', RESTSerializer); + owner.register('adapter:-default', Adapter); + owner.register('adapter:-rest', RESTAdapter); + owner.register('adapter:-json-api', JSONAPIAdapter); + + owner.inject('serializer', 'store', 'service:store'); - registry.register('adapter:-rest', DS.RESTAdapter); - registry.register('adapter:-json-api', DS.JSONAPIAdapter); + owner.inject('serializer', 'store', 'service:store'); registry.injection('serializer', 'store', 'service:store'); @@ -67,7 +85,7 @@ export default function setupStore(options) { env.restSerializer.store = env.store; env.serializer = env.store.serializerFor('-default'); env.serializer.store = env.store; - // lazily create the adapter method because some tets depend on + // lazily create the adapter method because some tests depend on // modifiying the adapter in the container after setupStore is // called Object.defineProperty(env, 'adapter', { diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index 1d1b2b01cab..afc75519e1b 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -46,7 +46,7 @@ module('integration/adapter/find-all - Finding All Records of a Type', { test("When all records for a type are requested, the store should call the adapter's `findAll` method.", assert => { assert.expect(5); - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findAll() { @@ -98,7 +98,7 @@ test('When all records for a type are requested, a rejection should reject the p assert.expect(5); let count = 0; - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findAll() { @@ -210,7 +210,7 @@ test('When all records for a type are requested, records that are created on the }); testInDebug('When all records are requested, assert the payload is not blank', assert => { - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findAll: () => resolve({}), @@ -224,7 +224,7 @@ testInDebug('When all records are requested, assert the payload is not blank', a test('isUpdating is true while records are fetched', function(assert) { let findAllDeferred = defer(); - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findAll() { @@ -265,7 +265,7 @@ test('isUpdating is true while records are fetched', function(assert) { test('isUpdating is true while records are fetched in the background', function(assert) { let findAllDeferred = defer(); - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findAll() { @@ -318,7 +318,7 @@ test('isUpdating is true while records are fetched in the background', function( test('isUpdating is false if records are not fetched in the background', function(assert) { let findAllDeferred = defer(); - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findAll() { diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 00cf5c73791..05407de0387 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -44,7 +44,7 @@ test("When a single record is requested, the adapter's find method should be cal let count = 0; - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findRecord(_, type) { @@ -74,7 +74,7 @@ test("When a single record is requested, the adapter's find method should be cal test('When a single record is requested multiple times, all .findRecord() calls are resolved after the promise is resolved', function(assert) { let deferred = defer(); - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findRecord() { @@ -113,7 +113,7 @@ test('When a single record is requested multiple times, all .findRecord() calls }); test('When a single record is requested, and the promise is rejected, .findRecord() is rejected.', function(assert) { - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findRecord() { @@ -132,7 +132,7 @@ test('When a single record is requested, and the promise is rejected, .findRecor test('When a single record is requested, and the promise is rejected, the record should be unloaded.', function(assert) { assert.expect(2); - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findRecord() { @@ -150,7 +150,7 @@ test('When a single record is requested, and the promise is rejected, the record }); testInDebug('When a single record is requested, and the payload is blank', function(assert) { - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findRecord: () => resolve({}), @@ -163,7 +163,7 @@ testInDebug('When a single record is requested, and the payload is blank', funct }); testInDebug('When multiple records are requested, and the payload is blank', function(assert) { - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ coalesceFindRequests: true, @@ -180,7 +180,7 @@ testInDebug('When multiple records are requested, and the payload is blank', fun }); testInDebug('warns when returned record has different id', function(assert) { - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findRecord() { diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index 9c117d358bc..42320fb9e70 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -952,7 +952,7 @@ test('update record - serialize hasMany', function(assert) { }, ]); - env.registry.register( + env.owner.register( 'serializer:user', DS.JSONAPISerializer.extend({ attrs: { diff --git a/tests/integration/adapter/rest-adapter-test.js b/tests/integration/adapter/rest-adapter-test.js index cff9708d1da..82e8a45c23b 100644 --- a/tests/integration/adapter/rest-adapter-test.js +++ b/tests/integration/adapter/rest-adapter-test.js @@ -160,7 +160,7 @@ test('findRecord - payload with sideloaded records of a different type', functio }); test('findRecord - payload with an serializer-specified primary key', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', @@ -182,7 +182,7 @@ test('findRecord - payload with an serializer-specified primary key', function(a }); test('findRecord - payload with a serializer-specified attribute mapping', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.RESTSerializer.extend({ attrs: { @@ -333,7 +333,7 @@ test("createRecord - findMany doesn't overwrite owner", function(assert) { }); test("createRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.RESTSerializer.extend({ primaryKey: '_id_', @@ -359,7 +359,7 @@ test("createRecord - a serializer's primary key and attributes are consulted whe test("createRecord - a serializer's attributes are consulted when building the payload if no id is pre-defined", function(assert) { let post; - env.registry.register( + env.owner.register( 'serializer:post', DS.RESTSerializer.extend({ attrs: { @@ -382,7 +382,7 @@ test("createRecord - a serializer's attributes are consulted when building the p }); test("createRecord - a serializer's attribute mapping takes precedence over keyForAttribute when building the payload", function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.RESTSerializer.extend({ attrs: { @@ -409,7 +409,7 @@ test("createRecord - a serializer's attribute mapping takes precedence over keyF }); test("createRecord - a serializer's attribute mapping takes precedence over keyForRelationship (belongsTo) when building the payload", function(assert) { - env.registry.register( + env.owner.register( 'serializer:comment', DS.RESTSerializer.extend({ attrs: { @@ -443,7 +443,7 @@ test("createRecord - a serializer's attribute mapping takes precedence over keyF }); test("createRecord - a serializer's attribute mapping takes precedence over keyForRelationship (hasMany) when building the payload", function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.RESTSerializer.extend({ attrs: { @@ -863,7 +863,7 @@ test('updateRecord - a payload with sideloaded updates pushes the updates', func test("updateRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { adapter.shouldBackgroundReloadRecord = () => false; - env.registry.register( + env.owner.register( 'serializer:post', DS.RESTSerializer.extend({ primaryKey: '_id_', @@ -1201,7 +1201,7 @@ test('findAll - returning sideloaded data loads the data', function(assert) { }); test('findAll - data is normalized through custom serializers', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', @@ -1388,7 +1388,7 @@ test('query - returning sideloaded data loads the data', function(assert) { }); test('query - data is normalized through custom serializers', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', @@ -1516,7 +1516,7 @@ testInDebug("queryRecord - returning an single object doesn't throw a deprecatio }); test('queryRecord - data is normalized through custom serializers', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', @@ -1784,7 +1784,7 @@ test('findMany - returning sideloaded data loads the data', function(assert) { test('findMany - a custom serializer is used if present', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; - env.registry.register( + env.owner.register( 'serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', @@ -1792,7 +1792,7 @@ test('findMany - a custom serializer is used if present', function(assert) { }) ); - env.registry.register( + env.owner.register( 'serializer:comment', DS.RESTSerializer.extend({ primaryKey: '_ID_', @@ -2016,7 +2016,7 @@ test('findMany - returning sideloaded data loads the data (with JSONApi Links)', test('findMany - a custom serializer is used if present', function(assert) { adapter.shouldBackgroundReloadRecord = () => false; - env.registry.register( + env.owner.register( 'serializer:post', DS.RESTSerializer.extend({ primaryKey: '_ID_', @@ -2024,7 +2024,7 @@ test('findMany - a custom serializer is used if present', function(assert) { }) ); - env.registry.register( + env.owner.register( 'serializer:comment', DS.RESTSerializer.extend({ primaryKey: '_ID_', @@ -2256,7 +2256,7 @@ test('groupRecordsForFindMany groups records correctly when singular URLs are en }); test('normalizeKey - to set up _ids and _id', function(assert) { - env.registry.register( + env.owner.register( 'serializer:application', DS.RESTSerializer.extend({ keyForAttribute(attr) { @@ -2277,7 +2277,7 @@ test('normalizeKey - to set up _ids and _id', function(assert) { }) ); - env.registry.register( + env.owner.register( 'model:post', DS.Model.extend({ name: DS.attr(), @@ -2287,7 +2287,7 @@ test('normalizeKey - to set up _ids and _id', function(assert) { }) ); - env.registry.register( + env.owner.register( 'model:user', DS.Model.extend({ createdAt: DS.attr(), @@ -2295,7 +2295,7 @@ test('normalizeKey - to set up _ids and _id', function(assert) { }) ); - env.registry.register( + env.owner.register( 'model:comment', DS.Model.extend({ body: DS.attr(), diff --git a/tests/integration/multiple-stores-test.js b/tests/integration/multiple-stores-test.js index 2081e0d6743..81172b68617 100644 --- a/tests/integration/multiple-stores-test.js +++ b/tests/integration/multiple-stores-test.js @@ -3,53 +3,61 @@ import setupStore from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; import { get } from '@ember/object'; -import DS from 'ember-data'; +import Store from 'ember-data/store'; +import attr from 'ember-data/attr'; +import { belongsTo, hasMany } from 'ember-data/relationships'; +import Model from 'ember-data/model'; +import RESTSerializer from 'ember-data/serializers/rest'; +import RESTAdapter from 'ember-data/adapters/rest'; +import Adapter from 'ember-data/adapter'; +import EmbeddedRecordsMixin from 'ember-data/serializers/embedded-records-mixin'; let env; -let SuperVillain, HomePlanet, EvilMinion; module('integration/multiple_stores - Multiple Stores Tests', { beforeEach() { - SuperVillain = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - homePlanet: DS.belongsTo('home-planet', { inverse: 'villains', async: false }), - evilMinions: DS.hasMany('evil-minion', { async: false }), + const SuperVillain = Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + homePlanet: belongsTo('home-planet', { inverse: 'villains', async: false }), + evilMinions: hasMany('evil-minion', { async: false }), }); - HomePlanet = DS.Model.extend({ - name: DS.attr('string'), - villains: DS.hasMany('super-villain', { inverse: 'homePlanet', async: false }), + const HomePlanet = Model.extend({ + name: attr('string'), + villains: hasMany('super-villain', { inverse: 'homePlanet', async: false }), }); - EvilMinion = DS.Model.extend({ - superVillain: DS.belongsTo('super-villain', { async: false }), - name: DS.attr('string'), + const EvilMinion = Model.extend({ + superVillain: belongsTo('super-villain', { async: false }), + name: attr('string'), }); - env = setupStore({ - superVillain: SuperVillain, - homePlanet: HomePlanet, - evilMinion: EvilMinion, - }); + env = setupStore({}); + + let { owner } = env; + + owner.register('model:super-villain', SuperVillain); + owner.register('model:home-planet', HomePlanet); + owner.register('model:evil-minion', EvilMinion); - env.registry.register('adapter:application', DS.RESTAdapter); - env.registry.register('serializer:application', DS.RESTSerializer); + owner.register('adapter:application', RESTAdapter); + owner.register('serializer:application', RESTSerializer); - env.registry.register('store:store-a', DS.Store); - env.registry.register('store:store-b', DS.Store); + owner.register('store:store-a', Store); + owner.register('store:store-b', Store); - env.store_a = env.container.lookup('store:store-a'); - env.store_b = env.container.lookup('store:store-b'); + env.store_a = owner.lookup('store:store-a'); + env.store_b = owner.lookup('store:store-b'); }, afterEach() { - run(env.store, 'destroy'); + run(env.container, 'destroy'); }, }); test('should be able to push into multiple stores', function(assert) { - env.registry.register( + env.owner.register( 'adapter:home-planet', - DS.RESTAdapter.extend({ + RESTAdapter.extend({ shouldBackgroundReloadRecord: () => false, }) ); @@ -81,9 +89,9 @@ test('should be able to push into multiple stores', function(assert) { }); test('embedded records should be created in multiple stores', function(assert) { - env.registry.register( + env.owner.register( 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { + RESTSerializer.extend(EmbeddedRecordsMixin, { attrs: { villains: { embedded: 'always' }, }, @@ -185,7 +193,7 @@ test('embedded records should be created in multiple stores', function(assert) { }); test('each store should have a unique instance of the serializers', function(assert) { - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend({})); + env.owner.register('serializer:home-planet', RESTSerializer.extend({})); let serializer_a = env.store_a.serializerFor('home-planet'); let serializer_b = env.store_b.serializerFor('home-planet'); @@ -208,7 +216,7 @@ test('each store should have a unique instance of the serializers', function(ass }); test('each store should have a unique instance of the adapters', function(assert) { - env.registry.register('adapter:home-planet', DS.Adapter.extend({})); + env.owner.register('adapter:home-planet', Adapter.extend({})); let adapter_a = env.store_a.adapterFor('home-planet'); let adapter_b = env.store_b.adapterFor('home-planet'); diff --git a/tests/integration/record-array-manager-test.js b/tests/integration/record-array-manager-test.js index ba276658cfd..a2958639825 100644 --- a/tests/integration/record-array-manager-test.js +++ b/tests/integration/record-array-manager-test.js @@ -29,8 +29,8 @@ module('integration/record_array_manager', { manager = store.recordArrayManager; - env.registry.register('model:car', Car); - env.registry.register('model:person', Person); + env.owner.register('model:car', Car); + env.owner.register('model:person', Person); }, }); diff --git a/tests/integration/records/delete-record-test.js b/tests/integration/records/delete-record-test.js index 116b533e824..026527b1c40 100644 --- a/tests/integration/records/delete-record-test.js +++ b/tests/integration/records/delete-record-test.js @@ -93,7 +93,7 @@ test('deleting a record that is part of a hasMany removes it from the hasMany re return EmberPromise.resolve(); }; - env.registry.register('model:group', Group); + env.owner.register('model:group', Group); run(function() { env.store.push({ diff --git a/tests/integration/references/belongs-to-test.js b/tests/integration/references/belongs-to-test.js index 818cf9aa566..efbc7ab6b92 100644 --- a/tests/integration/references/belongs-to-test.js +++ b/tests/integration/references/belongs-to-test.js @@ -324,7 +324,7 @@ testInDebug('push(record) works with polymorphic modelClass', function(assert) { var person, mafiaFamily; - env.registry.register('model:mafia-family', Family.extend()); + env.owner.register('model:mafia-family', Family.extend()); run(function() { person = env.store.push({ diff --git a/tests/integration/references/has-many-test.js b/tests/integration/references/has-many-test.js index 76c06b30cf5..2d0d2721654 100755 --- a/tests/integration/references/has-many-test.js +++ b/tests/integration/references/has-many-test.js @@ -199,7 +199,7 @@ testInDebug('push(array)', function(assert) { testInDebug('push(array) works with polymorphic type', function(assert) { var done = assert.async(); - env.registry.register('model:mafia-boss', Person.extend()); + env.owner.register('model:mafia-boss', Person.extend()); var family; run(function() { diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index f0850492ee5..514bb651c62 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -258,7 +258,7 @@ module('integration/relationship/belongs_to Belongs-To Relationships', { env.registry.optionsForType('serializer', { singleton: false }); env.registry.optionsForType('adapter', { singleton: false }); - env.registry.register( + env.owner.register( 'serializer:user', DS.JSONAPISerializer.extend({ attrs: { @@ -285,14 +285,14 @@ module('integration/relationship/belongs_to Belongs-To Relationships', { }); test('returning a null relationship from payload sets the relationship to null on both sides', function(assert) { - env.registry.register( + env.owner.register( 'model:app', DS.Model.extend({ name: DSattr('string'), team: DSbelongsTo('team', { async: true }), }) ); - env.registry.register( + env.owner.register( 'model:team', DS.Model.extend({ apps: DShasMany('app', { async: true }), @@ -642,8 +642,8 @@ test('A serializer can materialize a belongsTo as a link that gets sent back to group: DS.belongsTo({ async: true }), }); - env.registry.register('model:group', Group); - env.registry.register('model:person', Person); + env.owner.register('model:group', Group); + env.owner.register('model:person', Person); run(() => { store.push({ @@ -706,8 +706,8 @@ test('A record with an async belongsTo relationship always returns a promise for seat: DS.belongsTo('seat', { async: true }), }); - env.registry.register('model:seat', Seat); - env.registry.register('model:person', Person); + env.owner.register('model:seat', Seat); + env.owner.register('model:person', Person); run(() => { store.push({ @@ -757,8 +757,8 @@ test('A record with an async belongsTo relationship returning null should resolv group: DS.belongsTo({ async: true }), }); - env.registry.register('model:group', Group); - env.registry.register('model:person', Person); + env.owner.register('model:group', Group); + env.owner.register('model:person', Person); run(() => { store.push({ @@ -806,8 +806,8 @@ test('A record can be created with a resolved belongsTo promise', function(asser group: DS.belongsTo({ async: true }), }); - env.registry.register('model:group', Group); - env.registry.register('model:person', Person); + env.owner.register('model:group', Group); + env.owner.register('model:person', Person); run(() => { store.push({ diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 23ff8d12903..61514df6357 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -2811,7 +2811,7 @@ test('adding and removing records from hasMany relationship #2666', function(ass }); let commentId = 4; - env.registry.register( + env.owner.register( 'adapter:comment', DS.RESTAdapter.extend({ deleteRecord(record) { @@ -3111,7 +3111,7 @@ test('metadata is accessible when pushed as a meta property for a relationship', test('metadata is accessible when return from a fetchLink', function(assert) { assert.expect(1); - env.registry.register('serializer:application', DS.RESTSerializer); + env.owner.register('serializer:application', DS.RESTSerializer); env.adapter.findHasMany = function() { return resolve({ @@ -3154,7 +3154,7 @@ test('metadata is accessible when return from a fetchLink', function(assert) { test('metadata should be reset between requests', function(assert) { let counter = 0; - env.registry.register('serializer:application', DS.RESTSerializer); + env.owner.register('serializer:application', DS.RESTSerializer); env.adapter.findHasMany = function() { let data = { diff --git a/tests/integration/relationships/json-api-links-test.js b/tests/integration/relationships/json-api-links-test.js index 1655e7ff434..cce570eed29 100644 --- a/tests/integration/relationships/json-api-links-test.js +++ b/tests/integration/relationships/json-api-links-test.js @@ -43,7 +43,7 @@ test('Loading link with inverse:null on other model caches the two ends separate User = store.modelFor('user'); Organisation = store.modelFor('organisation'); - env.registry.register( + env.owner.register( 'adapter:user', DS.JSONAPISerializer.extend({ findRecord(store, type, id) { @@ -62,7 +62,7 @@ test('Loading link with inverse:null on other model caches the two ends separate }) ); - env.registry.register( + env.owner.register( 'adapter:organisation', DS.JSONAPISerializer.extend({ findRecord(store, type, id) { diff --git a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index 1f1167783f3..35a079e1180 100644 --- a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -45,7 +45,7 @@ module( notMessage: NotMessage, }); - env.registry.register('mixin:message', Message); + env.owner.register('mixin:message', Message); store = env.store; }, diff --git a/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js index 39a343b0803..a94ad3cbf03 100644 --- a/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -46,7 +46,7 @@ module( notMessage: NotMessage, }); - env.registry.register('mixin:message', Message); + env.owner.register('mixin:message', Message); store = env.store; }, diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index ba87ab65165..b6cb4b591df 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -93,14 +93,8 @@ module('integration/embedded_records_mixin - EmbeddedRecordsMixin', { env.store.modelFor('evil-minion'); env.store.modelFor('comment'); - env.registry.register('adapter:application', DS.RESTAdapter); - env.registry.register( - 'serializer:application', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin) - ); - - //env.amsSerializer = env.container.lookup("serializer:-active-model"); - //env.amsAdapter = env.container.lookup("adapter:-active-model"); + env.owner.register('adapter:application', DS.RESTAdapter); + env.owner.register('serializer:application', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin)); }, afterEach() { @@ -109,7 +103,7 @@ module('integration/embedded_records_mixin - EmbeddedRecordsMixin', { }); test('normalizeResponse with embedded objects', function(assert) { - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -166,7 +160,7 @@ test('normalizeResponse with embedded objects', function(assert) { }); test('normalizeResponse with embedded objects inside embedded objects', function(assert) { - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -174,7 +168,7 @@ test('normalizeResponse with embedded objects inside embedded objects', function }, }) ); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -249,7 +243,7 @@ test('normalizeResponse with embedded objects inside embedded objects', function }); test('normalizeResponse with embedded objects of same type', function(assert) { - env.registry.register( + env.owner.register( 'serializer:comment', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -326,7 +320,7 @@ test('normalizeResponse with embedded objects of same type', function(assert) { }); test('normalizeResponse with embedded objects inside embedded objects of same type', function(assert) { - env.registry.register( + env.owner.register( 'serializer:comment', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -426,7 +420,7 @@ test('normalizeResponse with embedded objects of same type, but from separate at reformedVillains: DS.hasMany('superVillain', { inverse: null, async: false }), }); - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -526,7 +520,7 @@ test('normalizeResponse with embedded objects of same type, but from separate at }); test('normalizeResponse with embedded objects', function(assert) { - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -589,13 +583,13 @@ test('normalizeResponse with embedded objects', function(assert) { test('normalizeResponse with embedded objects with custom primary key', function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend({ primaryKey: 'villain_id', }) ); - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -658,7 +652,7 @@ test('normalizeResponse with embedded objects with custom primary key', function test('normalizeResponse with embedded objects with identical relationship and attribute key ', function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -724,7 +718,7 @@ test('normalizeResponse with embedded objects with identical relationship and at }); test('normalizeResponse with embedded objects of same type as primary type', function(assert) { - env.registry.register( + env.owner.register( 'serializer:comment', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -810,7 +804,7 @@ test('normalizeResponse with embedded objects of same type, but from separate at reformedVillains: DS.hasMany('superVillain', { async: false }), }); - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -992,7 +986,7 @@ test('serialize supports serialize:false on non-relationship properties', functi id: '1', }); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1022,7 +1016,7 @@ test('serialize with embedded objects (hasMany relationship)', function(assert) id: '1', }); - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1061,7 +1055,7 @@ test('serialize with embedded objects and a custom keyForAttribute (hasMany rela id: '1', }); - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { keyForRelationship(key) { @@ -1109,7 +1103,7 @@ testInDebug('serialize with embedded objects (unknown hasMany relationship)', fu league = env.store.peekRecord('home-planet', 123); }); - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1141,7 +1135,7 @@ test('serialize with embedded objects (hasMany relationship) supports serialize: id: '1', }); - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1169,7 +1163,7 @@ test('serialize with (new) embedded objects (hasMany relationship)', function(as homePlanet: league, }); - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1218,7 +1212,7 @@ test('serialize with embedded objects (hasMany relationships, including related superVillain.get('secretWeapons').pushObject(secretWeapon); }); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1229,7 +1223,7 @@ test('serialize with embedded objects (hasMany relationships, including related ); var serializer, json; run(function() { - serializer = env.container.lookup('serializer:super-villain'); + serializer = env.owner.lookup('serializer:super-villain'); json = serializer.serialize(superVillain._createSnapshot()); }); @@ -1258,7 +1252,7 @@ test('serialize has many relationship using the `ids-and-types` strategy', funct minions: [yellowMinion, redMinion], }); - env.registry.register( + env.owner.register( 'serializer:commander-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1268,7 +1262,7 @@ test('serialize has many relationship using the `ids-and-types` strategy', funct ); var serializer, json; run(function() { - serializer = env.container.lookup('serializer:commander-villain'); + serializer = env.owner.lookup('serializer:commander-villain'); var snapshot = commanderVillain._createSnapshot(); json = serializer.serialize(snapshot); }); @@ -1289,7 +1283,7 @@ test('serialize has many relationship using the `ids-and-types` strategy', funct }); test('normalizeResponse with embedded object (belongsTo relationship)', function(assert) { - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1359,7 +1353,7 @@ test('normalizeResponse with embedded object (belongsTo relationship)', function }); test('serialize with embedded object (belongsTo relationship)', function(assert) { - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1396,7 +1390,7 @@ test('serialize with embedded object (belongsTo relationship)', function(assert) }); test('serialize with embedded object (polymorphic belongsTo relationship)', function(assert) { - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1442,7 +1436,7 @@ test('serialize with embedded object (polymorphic belongsTo relationship)', func }); test('serialize with embedded object (belongsTo relationship) works with different primaryKeys', function(assert) { - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { primaryKey: '_id', @@ -1451,7 +1445,7 @@ test('serialize with embedded object (belongsTo relationship) works with differe }, }) ); - env.registry.register( + env.owner.register( 'serializer:secret-lab', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { primaryKey: 'crazy_id', @@ -1488,7 +1482,7 @@ test('serialize with embedded object (belongsTo relationship) works with differe }); test('serialize with embedded object (belongsTo relationship, new no id)', function(assert) { - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1527,7 +1521,7 @@ test('serialize with embedded object (polymorphic belongsTo relationship) suppor secretLab: DS.belongsTo('secret-lab', { polymorphic: true }), }); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1564,7 +1558,7 @@ test('serialize with embedded object (belongsTo relationship) supports serialize secretLab: DS.belongsTo('secret-lab', { polymorphic: true }), }); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1601,7 +1595,7 @@ test('serialize with embedded object (belongsTo relationship) supports serialize secretLab: DS.belongsTo('secret-lab', { polymorphic: true }), }); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1634,7 +1628,7 @@ test('serialize with embedded object (belongsTo relationship) supports serialize }); test('serialize with embedded object (belongsTo relationship) supports serialize:ids', function(assert) { - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1668,7 +1662,7 @@ test('serialize with embedded object (belongsTo relationship) supports serialize }); test('serialize with embedded object (belongsTo relationship) supports serialize:id', function(assert) { - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1702,7 +1696,7 @@ test('serialize with embedded object (belongsTo relationship) supports serialize }); test('serialize with embedded object (belongsTo relationship) supports serialize:id in conjunction with deserialize:records', function(assert) { - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1736,7 +1730,7 @@ test('serialize with embedded object (belongsTo relationship) supports serialize }); test('serialize with embedded object (belongsTo relationship) supports serialize:false', function(assert) { - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1768,10 +1762,7 @@ test('serialize with embedded object (belongsTo relationship) supports serialize }); test('serialize with embedded object (belongsTo relationship) serializes the id by default if no option specified', function(assert) { - env.registry.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin) - ); + env.owner.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin)); var serializer = env.store.serializerFor('super-villain'); // records with an id, persisted @@ -1797,7 +1788,7 @@ test('serialize with embedded object (belongsTo relationship) serializes the id }); test('when related record is not present, serialize embedded record (with a belongsTo relationship) as null', function(assert) { - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1823,7 +1814,7 @@ test('when related record is not present, serialize embedded record (with a belo }); test('normalizeResponse with multiply-nested belongsTo', function(assert) { - env.registry.register( + env.owner.register( 'serializer:evil-minion', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1831,7 +1822,7 @@ test('normalizeResponse with multiply-nested belongsTo', function(assert) { }, }) ); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1919,7 +1910,7 @@ test('normalizeResponse with polymorphic hasMany', function(assert) { secretWeapons: DS.hasMany('secretWeapon', { polymorphic: true, async: false }), }); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2000,13 +1991,13 @@ test('normalizeResponse with polymorphic hasMany and custom primary key', functi secretWeapons: DS.hasMany('secretWeapon', { polymorphic: true, async: false }), }); - env.registry.register( + env.owner.register( 'serializer:light-saber', DS.RESTSerializer.extend({ primaryKey: 'custom', }) ); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2087,7 +2078,7 @@ test('normalizeResponse with polymorphic belongsTo', function(assert) { secretLab: DS.belongsTo('secretLab', { polymorphic: true, async: true }), }); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2154,7 +2145,7 @@ test('normalizeResponse with polymorphic belongsTo and custom primary key', func secretLab: DS.belongsTo('secretLab', { polymorphic: true, async: true }), }); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2162,7 +2153,7 @@ test('normalizeResponse with polymorphic belongsTo and custom primary key', func }, }) ); - env.registry.register( + env.owner.register( 'serializer:bat-cave', DS.RESTSerializer.extend({ primaryKey: 'custom', @@ -2254,7 +2245,7 @@ test('Mixin can be used with RESTSerializer which does not define keyForAttribut superVillain.get('evilMinions').pushObject(evilMinion); }); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2283,7 +2274,7 @@ test('Mixin can be used with RESTSerializer which does not define keyForAttribut }); test('normalize with custom belongsTo primary key', function(assert) { - env.registry.register( + env.owner.register( 'serializer:evil-minion', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2291,7 +2282,7 @@ test('normalize with custom belongsTo primary key', function(assert) { }, }) ); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend({ primaryKey: 'custom', @@ -2398,9 +2389,9 @@ test('serializing relationships with an embedded and without calls super when no } }, }); - env.registry.register('serializer:evil-minion', Serializer); - env.registry.register('serializer:secret-weapon', Serializer); - env.registry.register( + env.owner.register('serializer:evil-minion', Serializer); + env.owner.register('serializer:secret-weapon', Serializer); + env.owner.register( 'serializer:super-villain', Serializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2447,7 +2438,7 @@ test('serializing belongsTo correctly removes embedded foreign key', function(as secretWeapon: secretWeapon, }); - env.registry.register( + env.owner.register( 'serializer:evil-minion', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2475,7 +2466,7 @@ test('serializing embedded belongsTo respects remapped attrs key', function(asse homePlanet: homePlanet, }); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2505,7 +2496,7 @@ test('serializing embedded hasMany respects remapped attrs key', function(assert homePlanet: homePlanet, }); - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2514,7 +2505,7 @@ test('serializing embedded hasMany respects remapped attrs key', function(assert }) ); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2546,7 +2537,7 @@ test('serializing id belongsTo respects remapped attrs key', function(assert) { homePlanet: homePlanet, }); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2574,7 +2565,7 @@ test('serializing ids hasMany respects remapped attrs key', function(assert) { homePlanet: homePlanet, }); - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -2583,7 +2574,7 @@ test('serializing ids hasMany respects remapped attrs key', function(assert) { }) ); - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { diff --git a/tests/integration/serializers/json-api-serializer-test.js b/tests/integration/serializers/json-api-serializer-test.js index 8f238c1727f..f6fe59eedc2 100644 --- a/tests/integration/serializers/json-api-serializer-test.js +++ b/tests/integration/serializers/json-api-serializer-test.js @@ -259,7 +259,7 @@ testInDebug('Warns when normalizing with type missing', function(assert) { }); test('Serializer should respect the attrs hash when extracting attributes and relationships', function(assert) { - env.registry.register( + env.owner.register( 'serializer:user', DS.JSONAPISerializer.extend({ attrs: { @@ -305,7 +305,7 @@ test('Serializer should respect the attrs hash when extracting attributes and re }); test('Serializer should respect the attrs hash when serializing attributes and relationships', function(assert) { - env.registry.register( + env.owner.register( 'serializer:user', DS.JSONAPISerializer.extend({ attrs: { @@ -343,7 +343,7 @@ test('Serializer should respect the attrs hash when serializing attributes and r }); test('Serializer should respect the attrs hash when extracting attributes with not camelized keys', function(assert) { - env.registry.register( + env.owner.register( 'serializer:project', DS.JSONAPISerializer.extend({ attrs: { @@ -370,7 +370,7 @@ test('Serializer should respect the attrs hash when extracting attributes with n }); test('Serializer should respect the attrs hash when serializing attributes with not camelized keys', function(assert) { - env.registry.register( + env.owner.register( 'serializer:project', DS.JSONAPISerializer.extend({ attrs: { @@ -388,7 +388,7 @@ test('Serializer should respect the attrs hash when serializing attributes with test('options are passed to transform for serialization', function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'transform:custom', DS.Transform.extend({ serialize: function(deserialized, options) { @@ -488,7 +488,7 @@ test('a belongsTo relationship set to a new record will not show in the relation }); test('it should serialize a hasMany relationship', function(assert) { - env.registry.register( + env.owner.register( 'serializer:user', DS.JSONAPISerializer.extend({ attrs: { @@ -535,7 +535,7 @@ test('it should serialize a hasMany relationship', function(assert) { }); test('it should not include new records when serializing a hasMany relationship', function(assert) { - env.registry.register( + env.owner.register( 'serializer:user', DS.JSONAPISerializer.extend({ attrs: { @@ -583,7 +583,7 @@ test('it should not include new records when serializing a hasMany relationship' }); test('it should not include any records when serializing a hasMany relationship if they are all new', function(assert) { - env.registry.register( + env.owner.register( 'serializer:user', DS.JSONAPISerializer.extend({ attrs: { @@ -625,7 +625,7 @@ test('it should not include any records when serializing a hasMany relationship }); test('it should include an empty list when serializing an empty hasMany relationship', function(assert) { - env.registry.register( + env.owner.register( 'serializer:user', DS.JSONAPISerializer.extend({ attrs: { diff --git a/tests/integration/serializers/json-serializer-test.js b/tests/integration/serializers/json-serializer-test.js index bdec9fbc215..9ba5160f843 100644 --- a/tests/integration/serializers/json-serializer-test.js +++ b/tests/integration/serializers/json-serializer-test.js @@ -88,7 +88,7 @@ test('serializeAttribute', function(assert) { }); test('serializeAttribute respects keyForAttribute', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ keyForAttribute(key) { @@ -151,7 +151,7 @@ test('async serializeBelongsTo with null', function(assert) { }); test('serializeBelongsTo respects keyForRelationship', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ keyForRelationship(key, type) { @@ -174,7 +174,7 @@ test('serializeBelongsTo respects keyForRelationship', function(assert) { }); test('serializeHasMany respects keyForRelationship', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ keyForRelationship(key, type) { @@ -259,7 +259,7 @@ test('serializeIntoHash', function(assert) { test('serializePolymorphicType sync', function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'serializer:comment', DS.JSONSerializer.extend({ serializePolymorphicType(record, json, relationship) { @@ -294,7 +294,7 @@ test('serializePolymorphicType async', function(assert) { post: DS.belongsTo('post', { async: true }), }); - env.registry.register( + env.owner.register( 'serializer:comment', DS.JSONSerializer.extend({ serializePolymorphicType(record, json, relationship) { @@ -322,7 +322,7 @@ test('normalizeResponse normalizes each record in the array', function(assert) { var postNormalizeCount = 0; var posts = [{ id: '1', title: 'Rails is omakase' }, { id: '2', title: 'Another Post' }]; - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ normalize() { @@ -339,7 +339,7 @@ test('normalizeResponse normalizes each record in the array', function(assert) { }); test('Serializer should respect the attrs hash when extracting records', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ attrs: { @@ -373,7 +373,7 @@ test('Serializer should map `attrs` attributes directly when keyForAttribute als env = setupStore({ post: Post, }); - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ keyForAttribute: underscore, @@ -399,7 +399,7 @@ test('Serializer should respect the attrs hash when serializing records', functi Post.reopen({ parentPost: DS.belongsTo('post', { inverse: null, async: true }), }); - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ attrs: { @@ -428,8 +428,8 @@ test('Serializer should respect the attrs hash when serializing records', functi }); test('Serializer respects if embedded model has an attribute named "type" - #3726', function(assert) { - env.registry.register('serializer:child', DS.JSONSerializer); - env.registry.register( + env.owner.register('serializer:child', DS.JSONSerializer); + env.owner.register( 'serializer:parent', DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -437,13 +437,13 @@ test('Serializer respects if embedded model has an attribute named "type" - #372 }, }) ); - env.registry.register( + env.owner.register( 'model:parent', DS.Model.extend({ child: DS.belongsTo('child'), }) ); - env.registry.register( + env.owner.register( 'model:child', DS.Model.extend({ type: DS.attr(), @@ -475,8 +475,8 @@ test('Serializer respects if embedded model has an attribute named "type" - #372 }); test('Serializer respects if embedded model has a relationship named "type" - #3726', function(assert) { - env.registry.register('serializer:child', DS.JSONSerializer); - env.registry.register( + env.owner.register('serializer:child', DS.JSONSerializer); + env.owner.register( 'serializer:parent', DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -484,19 +484,19 @@ test('Serializer respects if embedded model has a relationship named "type" - #3 }, }) ); - env.registry.register( + env.owner.register( 'model:parent', DS.Model.extend({ child: DS.belongsTo('child'), }) ); - env.registry.register( + env.owner.register( 'model:child', DS.Model.extend({ type: DS.belongsTo('le-type'), }) ); - env.registry.register('model:le-type', DS.Model.extend()); + env.owner.register('model:le-type', DS.Model.extend()); var jsonHash = { id: 1, @@ -529,7 +529,7 @@ test('Serializer respects if embedded model has a relationship named "type" - #3 test('Serializer respects `serialize: false` on the attrs hash', function(assert) { assert.expect(2); - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ attrs: { @@ -550,7 +550,7 @@ test('Serializer respects `serialize: false` on the attrs hash', function(assert test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` property', function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ attrs: { @@ -571,7 +571,7 @@ test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` p test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` property', function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'serializer:comment', DS.JSONSerializer.extend({ attrs: { @@ -592,7 +592,7 @@ test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` property', function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ attrs: { @@ -613,7 +613,7 @@ test('Serializer respects `serialize: false` on the attrs hash for a `hasMany` p test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` property', function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'serializer:comment', DS.JSONSerializer.extend({ attrs: { @@ -634,7 +634,7 @@ test('Serializer respects `serialize: false` on the attrs hash for a `belongsTo` test('Serializer respects `serialize: true` on the attrs hash for a `hasMany` property', function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ attrs: { @@ -659,7 +659,7 @@ test('Serializer respects `serialize: true` on the attrs hash for a `hasMany` pr test('Serializer respects `serialize: true` on the attrs hash for a `belongsTo` property', function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'serializer:comment', DS.JSONSerializer.extend({ attrs: { @@ -690,7 +690,7 @@ test('Serializer should merge attrs from superclasses', function(assert) { anotherString: 'base_another_string_key', }, }); - env.registry.register( + env.owner.register( 'serializer:post', BaseSerializer.extend({ attrs: { @@ -714,7 +714,7 @@ test('Serializer should merge attrs from superclasses', function(assert) { }); test('Serializer should respect the primaryKey attribute when extracting records', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ primaryKey: '_ID_', @@ -731,7 +731,7 @@ test('Serializer should respect the primaryKey attribute when extracting records }); test('Serializer should respect the primaryKey attribute when serializing records', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ primaryKey: '_ID_', @@ -747,7 +747,7 @@ test('Serializer should respect the primaryKey attribute when serializing record }); test('Serializer should respect keyForAttribute when extracting records', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ keyForAttribute(key) { @@ -764,7 +764,7 @@ test('Serializer should respect keyForAttribute when extracting records', functi }); test('Serializer should respect keyForRelationship when extracting records', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ keyForRelationship(key, type) { @@ -784,7 +784,7 @@ test('Calling normalize should normalize the payload (only the passed keys)', fu var Person = DS.Model.extend({ posts: DS.hasMany('post', { async: false }), }); - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ attrs: { @@ -794,7 +794,7 @@ test('Calling normalize should normalize the payload (only the passed keys)', fu }) ); - env.registry.register('model:person', Person); + env.owner.register('model:person', Person); Post.reopen({ content: DS.attr('string'), @@ -831,7 +831,7 @@ test('serializeBelongsTo with async polymorphic', function(assert) { var json = {}; var expected = { post: '1', postTYPE: 'post' }; - env.registry.register( + env.owner.register( 'serializer:favorite', DS.JSONSerializer.extend({ serializePolymorphicType(snapshot, json, relationship) { @@ -853,7 +853,7 @@ test('serializeBelongsTo with async polymorphic', function(assert) { }); test('extractErrors respects custom key mappings', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ attrs: { @@ -885,7 +885,7 @@ test('extractErrors respects custom key mappings', function(assert) { }); test('extractErrors expects error information located on the errors property of payload', function(assert) { - env.registry.register('serializer:post', DS.JSONSerializer.extend()); + env.owner.register('serializer:post', DS.JSONSerializer.extend()); var payload = { attributeWhichWillBeRemovedinExtractErrors: ['true'], @@ -903,7 +903,7 @@ test('extractErrors expects error information located on the errors property of }); test('extractErrors leaves payload untouched if it has no errors property', function(assert) { - env.registry.register('serializer:post', DS.JSONSerializer.extend()); + env.owner.register('serializer:post', DS.JSONSerializer.extend()); var payload = { untouchedSinceNoErrorsSiblingPresent: ['true'], @@ -915,7 +915,7 @@ test('extractErrors leaves payload untouched if it has no errors property', func }); test('normalizeResponse should extract meta using extractMeta', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ extractMeta(store, modelClass, payload) { @@ -943,7 +943,7 @@ test('normalizeResponse should extract meta using extractMeta', function(assert) }); test('normalizeResponse returns empty `included` payload by default', function(assert) { - env.registry.register('serializer:post', DS.JSONSerializer.extend()); + env.owner.register('serializer:post', DS.JSONSerializer.extend()); var jsonHash = { id: '1', @@ -958,7 +958,7 @@ test('normalizeResponse returns empty `included` payload by default', function(a }); test('normalizeResponse returns empty `included` payload when relationship is undefined', function(assert) { - env.registry.register('serializer:post', DS.JSONSerializer.extend()); + env.owner.register('serializer:post', DS.JSONSerializer.extend()); var jsonHash = { id: '1', @@ -974,8 +974,8 @@ test('normalizeResponse returns empty `included` payload when relationship is un }); test('normalizeResponse respects `included` items (single response)', function(assert) { - env.registry.register('serializer:comment', DS.JSONSerializer); - env.registry.register( + env.owner.register('serializer:comment', DS.JSONSerializer); + env.owner.register( 'serializer:post', DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1001,8 +1001,8 @@ test('normalizeResponse respects `included` items (single response)', function(a }); test('normalizeResponse respects `included` items (array response)', function(assert) { - env.registry.register('serializer:comment', DS.JSONSerializer); - env.registry.register( + env.owner.register('serializer:comment', DS.JSONSerializer); + env.owner.register( 'serializer:post', DS.JSONSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -1036,7 +1036,7 @@ test('normalizeResponse respects `included` items (array response)', function(as }); testInDebug('normalizeResponse ignores unmapped attributes', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ attrs: { @@ -1063,7 +1063,7 @@ testInDebug('normalizeResponse ignores unmapped attributes', function(assert) { test('options are passed to transform for serialization', function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'transform:custom', DS.Transform.extend({ serialize: function(deserialized, options) { @@ -1086,7 +1086,7 @@ test('options are passed to transform for serialization', function(assert) { test('options are passed to transform for normalization', function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'transform:custom', DS.Transform.extend({ deserialize: function(serialized, options) { @@ -1107,7 +1107,7 @@ test('options are passed to transform for normalization', function(assert) { }); test('Serializer should respect the attrs hash in links', function(assert) { - env.registry.register( + env.owner.register( 'serializer:post', DS.JSONSerializer.extend({ attrs: { diff --git a/tests/integration/serializers/rest-serializer-test.js b/tests/integration/serializers/rest-serializer-test.js index 25739f5e10d..73aaa907c83 100644 --- a/tests/integration/serializers/rest-serializer-test.js +++ b/tests/integration/serializers/rest-serializer-test.js @@ -87,7 +87,7 @@ test('modelNameFromPayloadKey returns always same modelName even for uncountable }); test('normalizeResponse should extract meta using extractMeta', function(assert) { - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend({ extractMeta(store, modelClass, payload) { @@ -117,8 +117,8 @@ test('normalizeResponse with custom modelNameFromPayloadKey', function(assert) { var camelized = camelize(root); return singularize(camelized); }; - env.registry.register('serializer:home-planet', DS.JSONSerializer); - env.registry.register('serializer:super-villain', DS.JSONSerializer); + env.owner.register('serializer:home-planet', DS.JSONSerializer); + env.owner.register('serializer:super-villain', DS.JSONSerializer); var jsonHash = { home_planets: [ @@ -189,7 +189,7 @@ testInDebug('normalizeResponse with type and custom modelNameFromPayloadKey', fu return 'home-planet'; }; - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend({ normalize() { @@ -227,8 +227,8 @@ testInDebug('normalizeResponse with type and custom modelNameFromPayloadKey', fu testInDebug('normalizeResponse warning with custom modelNameFromPayloadKey', function(assert) { var homePlanet; var oldModelNameFromPayloadKey = env.restSerializer.modelNameFromPayloadKey; - env.registry.register('serializer:super-villain', DS.JSONSerializer); - env.registry.register('serializer:home-planet', DS.JSONSerializer); + env.owner.register('serializer:super-villain', DS.JSONSerializer); + env.owner.register('serializer:home-planet', DS.JSONSerializer); env.restSerializer.modelNameFromPayloadKey = function(root) { //return some garbage that won"t resolve in the container return 'garbage'; @@ -273,8 +273,8 @@ testInDebug('normalizeResponse warning with custom modelNameFromPayloadKey', fun testInDebug('normalizeResponse warning with custom modelNameFromPayloadKey', function(assert) { var homePlanets; - env.registry.register('serializer:super-villain', DS.JSONSerializer); - env.registry.register('serializer:home-planet', DS.JSONSerializer); + env.owner.register('serializer:super-villain', DS.JSONSerializer); + env.owner.register('serializer:home-planet', DS.JSONSerializer); env.restSerializer.modelNameFromPayloadKey = function(root) { //return some garbage that won"t resolve in the container return 'garbage'; @@ -346,8 +346,8 @@ test('serialize polymorphic when associated object is null', function(assert) { test('normalizeResponse loads secondary records with correct serializer', function(assert) { var superVillainNormalizeCount = 0; - env.registry.register('serializer:evil-minion', DS.JSONSerializer); - env.registry.register( + env.owner.register('serializer:evil-minion', DS.JSONSerializer); + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend({ normalize() { @@ -393,8 +393,8 @@ test('normalizeResponse returns null if payload contains null', function(assert) test('normalizeResponse loads secondary records with correct serializer', function(assert) { var superVillainNormalizeCount = 0; - env.registry.register('serializer:evil-minion', DS.JSONSerializer); - env.registry.register( + env.owner.register('serializer:evil-minion', DS.JSONSerializer); + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend({ normalize() { @@ -417,7 +417,7 @@ test('normalizeResponse loads secondary records with correct serializer', functi }); test('normalize should allow for different levels of normalization', function(assert) { - env.registry.register( + env.owner.register( 'serializer:application', DS.RESTSerializer.extend({ attrs: { @@ -442,7 +442,7 @@ test('normalize should allow for different levels of normalization', function(as }); test('normalize should allow for different levels of normalization - attributes', function(assert) { - env.registry.register( + env.owner.register( 'serializer:application', DS.RESTSerializer.extend({ attrs: { @@ -578,7 +578,7 @@ test('serializeIntoHash uses payloadKeyFromModelName to normalize the payload ro let league = env.store.createRecord('home-planet', { name: 'Umber', id: '123' }); let json = {}; - env.registry.register( + env.owner.register( 'serializer:home-planet', DS.RESTSerializer.extend({ payloadKeyFromModelName(modelName) { @@ -599,7 +599,7 @@ test('serializeIntoHash uses payloadKeyFromModelName to normalize the payload ro }); test('normalizeResponse with async polymorphic belongsTo, using Type', function(assert) { - env.registry.register('serializer:application', DS.RESTSerializer.extend()); + env.owner.register('serializer:application', DS.RESTSerializer.extend()); var store = env.store; env.adapter.findRecord = (store, type) => { if (type.modelName === 'doomsday-device') { @@ -638,7 +638,7 @@ test('normalizeResponse with async polymorphic belongsTo, using { return { @@ -680,7 +680,7 @@ test('normalizeResponse with async polymorphic hasMany', function(assert) { SuperVillain.reopen({ evilMinions: DS.hasMany('evil-minion', { async: true, polymorphic: true }), }); - env.registry.register('serializer:application', DS.RESTSerializer.extend()); + env.owner.register('serializer:application', DS.RESTSerializer.extend()); var store = env.store; env.adapter.findRecord = () => { return { @@ -731,7 +731,7 @@ test('normalizeResponse can load secondary records of the same type without affe ], }; var array; - env.registry.register('serializer:comment', DS.JSONSerializer); + env.owner.register('serializer:comment', DS.JSONSerializer); run(function() { array = env.restSerializer.normalizeResponse(env.store, Comment, jsonHash, '1', 'findRecord'); @@ -775,7 +775,7 @@ test('normalizeResponse can load secondary records of the same type without affe }); test("don't polymorphically deserialize base on the type key in payload when a type attribute exist", function(assert) { - env.registry.register('serializer:application', DS.RESTSerializer.extend()); + env.owner.register('serializer:application', DS.RESTSerializer.extend()); run(function() { env.store.push( @@ -800,7 +800,7 @@ test("don't polymorphically deserialize base on the type key in payload when a t }); test("don't polymorphically deserialize base on the type key in payload when a type attribute exist on a singular response", function(assert) { - env.registry.register('serializer:application', DS.RESTSerializer.extend()); + env.owner.register('serializer:application', DS.RESTSerializer.extend()); run(function() { env.store.push( @@ -822,7 +822,7 @@ test("don't polymorphically deserialize base on the type key in payload when a t }); test("don't polymorphically deserialize based on the type key in payload when a relationship exists named type", function(assert) { - env.registry.register('serializer:application', DS.RESTSerializer.extend()); + env.owner.register('serializer:application', DS.RESTSerializer.extend()); env.adapter.findRecord = () => { return { @@ -846,7 +846,7 @@ test("don't polymorphically deserialize based on the type key in payload when a }); test('Serializer should respect the attrs hash in links', function(assert) { - env.registry.register( + env.owner.register( 'serializer:super-villain', DS.RESTSerializer.extend({ attrs: { @@ -876,8 +876,8 @@ test('Serializer should respect the attrs hash in links', function(assert) { // https://github.com/emberjs/data/issues/3805 test('normalizes sideloaded single record so that it sideloads correctly - belongsTo - GH-3805', function(assert) { - env.registry.register('serializer:evil-minion', DS.JSONSerializer); - env.registry.register('serializer:doomsday-device', DS.RESTSerializer.extend()); + env.owner.register('serializer:evil-minion', DS.JSONSerializer); + env.owner.register('serializer:doomsday-device', DS.RESTSerializer.extend()); let payload = { doomsdayDevice: { id: 1, @@ -911,8 +911,8 @@ test('normalizes sideloaded single record so that it sideloads correctly - belon // https://github.com/emberjs/data/issues/3805 test('normalizes sideloaded single record so that it sideloads correctly - hasMany - GH-3805', function(assert) { - env.registry.register('serializer:super-villain', DS.JSONSerializer); - env.registry.register('serializer:home-planet', DS.RESTSerializer.extend()); + env.owner.register('serializer:super-villain', DS.JSONSerializer); + env.owner.register('serializer:home-planet', DS.RESTSerializer.extend()); let payload = { homePlanet: { id: 1, diff --git a/tests/integration/store-test.js b/tests/integration/store-test.js index 47f0931cd60..9ef2e293ee6 100644 --- a/tests/integration/store-test.js +++ b/tests/integration/store-test.js @@ -39,8 +39,8 @@ function initializeStore(adapter) { }); store = env.store; - env.registry.register('model:car', Car); - env.registry.register('model:person', Person); + env.owner.register('model:car', Car); + env.owner.register('model:person', Person); } module('integration/store - destroy', { @@ -265,7 +265,7 @@ test('store#findRecord fetches record from server when cached record is not pres initializeStore(DS.RESTAdapter.extend()); - env.registry.register('serializer:application', DS.RESTSerializer); + env.owner.register('serializer:application', DS.RESTSerializer); ajaxResponse({ cars: [ { diff --git a/tests/integration/store/json-api-validation-test.js b/tests/integration/store/json-api-validation-test.js index 4728e67f92f..583a246de1c 100644 --- a/tests/integration/store/json-api-validation-test.js +++ b/tests/integration/store/json-api-validation-test.js @@ -8,7 +8,7 @@ import DS from 'ember-data'; var Person, store, env; function payloadError(payload, expectedError, assert) { - env.registry.register( + env.owner.register( 'serializer:person', DS.Serializer.extend({ normalizeResponse(store, type, pld) { @@ -16,7 +16,7 @@ function payloadError(payload, expectedError, assert) { }, }) ); - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findRecord() { @@ -33,8 +33,8 @@ function payloadError(payload, expectedError, assert) { expectedError, `Payload ${JSON.stringify(payload)} should throw error ${expectedError}` ); - env.registry.unregister('serializer:person'); - env.registry.unregister('adapter:person'); + env.owner.unregister('serializer:person'); + env.owner.unregister('adapter:person'); } module('integration/store/json-validation', { @@ -63,14 +63,14 @@ module('integration/store/json-validation', { testInDebug( "when normalizeResponse returns undefined (or doesn't return), throws an error", function(assert) { - env.registry.register( + env.owner.register( 'serializer:person', DS.Serializer.extend({ normalizeResponse() {}, }) ); - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findRecord() { @@ -88,7 +88,7 @@ testInDebug( ); testInDebug('when normalizeResponse returns null, throws an error', function(assert) { - env.registry.register( + env.owner.register( 'serializer:person', DS.Serializer.extend({ normalizeResponse() { @@ -97,7 +97,7 @@ testInDebug('when normalizeResponse returns null, throws an error', function(ass }) ); - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findRecord() { @@ -114,7 +114,7 @@ testInDebug('when normalizeResponse returns null, throws an error', function(ass }); testInDebug('when normalizeResponse returns an empty object, throws an error', function(assert) { - env.registry.register( + env.owner.register( 'serializer:person', DS.Serializer.extend({ normalizeResponse() { @@ -123,7 +123,7 @@ testInDebug('when normalizeResponse returns an empty object, throws an error', f }) ); - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findRecord() { @@ -142,7 +142,7 @@ testInDebug('when normalizeResponse returns an empty object, throws an error', f testInDebug( 'when normalizeResponse returns a document with both data and errors, throws an error', function(assert) { - env.registry.register( + env.owner.register( 'serializer:person', DS.Serializer.extend({ normalizeResponse() { @@ -154,7 +154,7 @@ testInDebug( }) ); - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ findRecord() { diff --git a/tests/integration/store/query-record-test.js b/tests/integration/store/query-record-test.js index 1edff1cc00f..9eec0051e44 100644 --- a/tests/integration/store/query-record-test.js +++ b/tests/integration/store/query-record-test.js @@ -44,7 +44,7 @@ testInDebug('It raises an assertion when no query hash is passed', function(asse test("When a record is requested, the adapter's queryRecord method should be called.", function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ queryRecord(store, type, query) { @@ -60,7 +60,7 @@ test("When a record is requested, the adapter's queryRecord method should be cal }); test('When a record is requested, and the promise is rejected, .queryRecord() is rejected.', function(assert) { - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ queryRecord(store, type, query) { @@ -79,7 +79,7 @@ test('When a record is requested, and the promise is rejected, .queryRecord() is test("When a record is requested, the serializer's normalizeQueryRecordResponse method should be called.", function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'serializer:person', DS.JSONAPISerializer.extend({ normalizeQueryRecordResponse(store, primaryModelClass, payload, id, requestType) { @@ -93,7 +93,7 @@ test("When a record is requested, the serializer's normalizeQueryRecordResponse }) ); - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ queryRecord(store, type, query) { diff --git a/tests/integration/store/query-test.js b/tests/integration/store/query-test.js index 411e2aac19a..d99b943d8ac 100644 --- a/tests/integration/store/query-test.js +++ b/tests/integration/store/query-test.js @@ -27,7 +27,7 @@ module('integration/store/query', { test('meta is proxied correctly on the PromiseArray', function(assert) { let defered = RSVP.defer(); - env.registry.register( + env.owner.register( 'adapter:person', DS.Adapter.extend({ query(store, type, query) { diff --git a/tests/unit/model/relationships/has-many-test.js b/tests/unit/model/relationships/has-many-test.js index 44190d467be..422c081968a 100644 --- a/tests/unit/model/relationships/has-many-test.js +++ b/tests/unit/model/relationships/has-many-test.js @@ -34,9 +34,9 @@ test('hasMany handles pre-loaded relationships', function(assert) { pets: DS.hasMany('pet', { async: false }), }); - env.registry.register('model:tag', Tag); - env.registry.register('model:pet', Pet); - env.registry.register('model:person', Person); + env.owner.register('model:tag', Tag); + env.owner.register('model:pet', Pet); + env.owner.register('model:person', Person); env.adapter.findRecord = function(store, type, id, snapshot) { if (type === Tag && id === '12') { @@ -798,9 +798,9 @@ test('hasMany lazily loads async relationships', function(assert) { pets: DS.hasMany('pet', { async: false }), }); - env.registry.register('model:tag', Tag); - env.registry.register('model:pet', Pet); - env.registry.register('model:person', Person); + env.owner.register('model:tag', Tag); + env.owner.register('model:pet', Pet); + env.owner.register('model:person', Person); env.adapter.findRecord = function(store, type, id, snapshot) { if (type === Tag && id === '12') { diff --git a/tests/unit/store/adapter-interop-test.js b/tests/unit/store/adapter-interop-test.js index 576faf6cfaf..5e753025617 100644 --- a/tests/unit/store/adapter-interop-test.js +++ b/tests/unit/store/adapter-interop-test.js @@ -285,7 +285,7 @@ test('Find with query calls the correct normalizeResponse', function(assert) { let { store } = env; - env.registry.register('serializer:application', ApplicationSerializer); + env.owner.register('serializer:application', ApplicationSerializer); run(() => store.query('person', passedQuery)); assert.equal(callCount, 1, 'normalizeQueryResponse was called'); @@ -475,7 +475,7 @@ test('initial values of belongsTo can be passed in as the third argument to find friend: DS.belongsTo('person', { inverse: null, async: true }), }); - env.registry.register('model:person', Person); + env.owner.register('model:person', Person); return run(() => { store.push({ @@ -512,7 +512,7 @@ test('initial values of belongsTo can be passed in as the third argument to find friend: DS.belongsTo('person', { async: true, inverse: null }), }); - env.registry.register('model:person', Person); + env.owner.register('model:person', Person); return run(() => { return store.findRecord('person', 1, { preload: { friend: 2 } }).then(() => { @@ -547,7 +547,7 @@ test('initial values of hasMany can be passed in as the third argument to find a friends: DS.hasMany('person', { inverse: null, async: true }), }); - env.registry.register('model:person', Person); + env.owner.register('model:person', Person); return run(() => { store.push({ @@ -585,7 +585,7 @@ test('initial values of hasMany can be passed in as the third argument to find a friends: DS.hasMany('person', { async: true, inverse: null }), }); - env.registry.register('model:person', Person); + env.owner.register('model:person', Person); return run(() => store.findRecord('person', 1, { preload: { friends: [2] } })); }); @@ -611,7 +611,7 @@ test('initial empty values of hasMany can be passed in as the third argument to friends: DS.hasMany('person', { inverse: null, async: true }), }); - env.registry.register('model:person', Person); + env.owner.register('model:person', Person); return run(() => { return store.findRecord('person', 1, { preload: { friends: [] } }); @@ -638,7 +638,7 @@ test('initial values of hasMany can be passed in as the third argument to find a friends: DS.hasMany('person', { async: true, inverse: null }), }); - env.registry.register('model:person', Person); + env.owner.register('model:person', Person); return run(() => store.findRecord('person', 1, { preload: { friends: [] } })); }); diff --git a/tests/unit/store/finders-test.js b/tests/unit/store/finders-test.js index 58d167c207f..5e53eb1484f 100644 --- a/tests/unit/store/finders-test.js +++ b/tests/unit/store/finders-test.js @@ -34,7 +34,7 @@ test('findRecord does not load a serializer until the adapter promise resolves', let deferedFind = defer(); - this.env.registry.register( + this.env.owner.register( 'adapter:person', DS.Adapter.extend({ findRecord: () => deferedFind.promise, @@ -68,7 +68,7 @@ test('findMany does not load a serializer until the adapter promise resolves', f let deferedFind = defer(); - this.env.registry.register( + this.env.owner.register( 'adapter:person', DS.Adapter.extend({ findMany: () => deferedFind.promise, @@ -108,7 +108,7 @@ test('findHasMany does not load a serializer until the adapter promise resolves' let deferedFind = defer(); - this.env.registry.register( + this.env.owner.register( 'adapter:person', DS.Adapter.extend({ findHasMany: () => deferedFind.promise, @@ -168,7 +168,7 @@ test('findBelongsTo does not load a serializer until the adapter promise resolve let deferedFind = defer(); - this.env.registry.register( + this.env.owner.register( 'adapter:person', DS.Adapter.extend({ findBelongsTo: () => deferedFind.promise, @@ -223,7 +223,7 @@ test('findAll does not load a serializer until the adapter promise resolves', fu let deferedFind = defer(); - this.env.registry.register( + this.env.owner.register( 'adapter:person', DS.Adapter.extend({ findAll: () => deferedFind.promise, @@ -257,7 +257,7 @@ test('query does not load a serializer until the adapter promise resolves', func let deferedFind = defer(); - this.env.registry.register( + this.env.owner.register( 'adapter:person', DS.Adapter.extend({ query: () => deferedFind.promise, @@ -291,7 +291,7 @@ test('queryRecord does not load a serializer until the adapter promise resolves' let deferedFind = defer(); - this.env.registry.register( + this.env.owner.register( 'adapter:person', DS.Adapter.extend({ queryRecord: () => deferedFind.promise, diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index ba547923e51..867b2f9d55e 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -37,7 +37,7 @@ module('unit/store/push - DS.Store#push', { store = env.store; - env.registry.register('serializer:post', DS.RESTSerializer); + env.owner.register('serializer:post', DS.RESTSerializer); }, afterEach() { @@ -124,7 +124,7 @@ test('Supplying a model class for `push` is the same as supplying a string', fun env.adapter.shouldBackgroundReloadRecord = () => false; const Programmer = Person.extend(); - env.registry.register('model:programmer', Programmer); + env.owner.register('model:programmer', Programmer); return run(() => { store.push({ @@ -224,7 +224,7 @@ test('Calling push with partial records updates just those attributes', function }); test('Calling push on normalize allows partial updates with raw JSON', function(assert) { - env.registry.register('serializer:person', DS.RESTSerializer); + env.owner.register('serializer:person', DS.RESTSerializer); let person; run(() => { @@ -390,7 +390,7 @@ test('Calling pushPayload allows pushing singular payload properties', function( test(`Calling pushPayload should use the type's serializer for normalizing`, function(assert) { assert.expect(4); - env.registry.register( + env.owner.register( 'serializer:post', DS.RESTSerializer.extend({ normalize() { @@ -400,7 +400,7 @@ test(`Calling pushPayload should use the type's serializer for normalizing`, fun }) ); - env.registry.register( + env.owner.register( 'serializer:person', DS.RESTSerializer.extend({ normalize() { @@ -439,7 +439,7 @@ test(`Calling pushPayload should use the type's serializer for normalizing`, fun test(`Calling pushPayload without a type uses application serializer's pushPayload method`, function(assert) { assert.expect(1); - env.registry.register( + env.owner.register( 'serializer:application', DS.RESTSerializer.extend({ pushPayload() { @@ -459,7 +459,7 @@ test(`Calling pushPayload without a type uses application serializer's pushPaylo test(`Calling pushPayload without a type should use a model's serializer when normalizing`, function(assert) { assert.expect(4); - env.registry.register( + env.owner.register( 'serializer:post', DS.RESTSerializer.extend({ normalize() { @@ -469,7 +469,7 @@ test(`Calling pushPayload without a type should use a model's serializer when no }) ); - env.registry.register( + env.owner.register( 'serializer:application', DS.RESTSerializer.extend({ normalize() { @@ -506,7 +506,7 @@ test(`Calling pushPayload without a type should use a model's serializer when no }); test('Calling pushPayload allows partial updates with raw JSON', function(assert) { - env.registry.register('serializer:person', DS.RESTSerializer); + env.owner.register('serializer:person', DS.RESTSerializer); run(() => { store.pushPayload('person', { diff --git a/tests/unit/utils-test.js b/tests/unit/utils-test.js index 3bddc49fb10..09ea78a9b58 100644 --- a/tests/unit/utils-test.js +++ b/tests/unit/utils-test.js @@ -36,7 +36,7 @@ module('unit/utils', { video: Video, }); - env.registry.register('mixin:medium', Medium); + env.owner.register('mixin:medium', Medium); }, afterEach() { From d48ee83ce8c60a9e6c50faa4c23dcf6c77a7ce45 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 5 Nov 2018 14:43:02 -0800 Subject: [PATCH 2410/2527] [CHORE tests,owner,factoryFor] eliminate unnecessary fallbacks for factoryFor and getOwner, improve test isolation --- .gitignore | 2 + addon/-private/index.js | 2 +- addon/-private/system/model/internal-model.js | 13 +- addon/-private/system/store.js | 21 +- addon/-private/utils.js | 33 +- addon/serializers/json.js | 2 +- .../relationships/belongs-to-test.js | 55 +- .../acceptance/relationships/has-many-test.js | 26 +- .../adapter/client-side-delete-test.js | 114 +- .../adapter/json-api-adapter-test.js | 104 +- tests/integration/application-test.js | 250 ++-- tests/integration/injection-test.js | 171 +-- tests/integration/inverse-test.js | 495 ++----- tests/integration/records/record-data-test.js | 22 +- .../relationships/belongs-to-test.js | 10 +- .../relationships/has-many-test.js | 4 + .../inverse-relationships-test.js | 274 +++- tests/integration/setup-container-test.js | 56 - tests/test-helper.js | 4 - tests/unit/model/lifecycle-callbacks-test.js | 1268 +++-------------- tests/unit/store/push-test.js | 59 +- 21 files changed, 986 insertions(+), 1999 deletions(-) delete mode 100644 tests/integration/setup-container-test.js diff --git a/.gitignore b/.gitignore index 2d7eb569745..3f82369c2b6 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ bower_components/ npm-debug.log /DEBUG + +.vscode/ \ No newline at end of file diff --git a/addon/-private/index.js b/addon/-private/index.js index a1f3e29e5ea..cc9b9b706b3 100644 --- a/addon/-private/index.js +++ b/addon/-private/index.js @@ -29,7 +29,7 @@ export { relationshipStateFor, } from './system/record-data-for'; export { default as normalizeModelName } from './system/normalize-model-name'; -export { getOwner, modelHasAttributeOrRelationshipNamedType } from './utils'; +export { modelHasAttributeOrRelationshipNamedType } from './utils'; export { default as coerceId } from './system/coerce-id'; export { default as parseResponseHeaders } from './utils/parse-response-headers'; diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 568a9ea1fc1..877fcf5b5b8 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -1,7 +1,7 @@ import { set, get } from '@ember/object'; import EmberError from '@ember/error'; import { default as EmberArray, A } from '@ember/array'; -import { setOwner } from '@ember/application'; +import { setOwner, getOwner } from '@ember/application'; import { run } from '@ember/runloop'; import { assign } from '@ember/polyfills'; import RSVP, { Promise } from 'rsvp'; @@ -13,7 +13,6 @@ import Snapshot from '../snapshot'; import OrderedSet from '../ordered-set'; import ManyArray from '../many-array'; import { PromiseBelongsTo, PromiseManyArray } from '../promise-proxies'; -import { getOwner } from '../../utils'; import { RecordReference, BelongsToReference, HasManyReference } from '../references'; import { default as recordDataFor, relationshipStateFor } from '../record-data-for'; @@ -222,16 +221,6 @@ export default class InternalModel { return this.currentState.dirtyType; } - // DO NOT USE : purely to ease the transition in tests - get _attributes() { - return this._recordData._attributes; - } - - // DO NOT USE : purely to ease the transition in tests - get _relationships() { - return this._recordData._relationships; - } - getRecord(properties) { if (!this._record && !this._isDematerializing) { heimdall.increment(materializeRecord); diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index 53243976341..e0b52fca2b6 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -7,6 +7,7 @@ import { A } from '@ember/array'; import EmberError from '@ember/error'; import { run as emberRunLoop } from '@ember/runloop'; import { set, get, computed } from '@ember/object'; +import { getOwner } from '@ember/application'; import { assign } from '@ember/polyfills'; import { default as RSVP, Promise } from 'rsvp'; import Service from '@ember/service'; @@ -40,7 +41,6 @@ import { _queryRecord, } from './store/finders'; -import { getOwner } from '../utils'; import coerceId from './coerce-id'; import RecordArrayManager from './record-array-manager'; import InternalModel from './model/internal-model'; @@ -3393,8 +3393,7 @@ function getModelFactory(store, cache, normalizedModelName) { return null; } - // interopt with the future - let klass = getOwner(store).factoryFor ? factory.class : factory; + let klass = factory.class; assert(`'${inspect(klass)}' does not appear to be an ember-data model`, klass.isModel); // TODO: deprecate this @@ -3412,11 +3411,7 @@ function getModelFactory(store, cache, normalizedModelName) { function _lookupModelFactory(store, normalizedModelName) { let owner = getOwner(store); - if (owner.factoryFor) { - return owner.factoryFor(`model:${normalizedModelName}`); - } else { - return owner._lookupFactory(`model:${normalizedModelName}`); - } + return owner.factoryFor(`model:${normalizedModelName}`); } /* @@ -3436,14 +3431,8 @@ function _lookupModelFactory(store, normalizedModelName) { */ function _modelForMixin(store, normalizedModelName) { let owner = getOwner(store); - let mixin; - - if (owner.factoryFor) { - let MaybeMixin = owner.factoryFor(`mixin:${normalizedModelName}`); - mixin = MaybeMixin && MaybeMixin.class; - } else { - mixin = owner._lookupFactory(`mixin:${normalizedModelName}`); - } + let MaybeMixin = owner.factoryFor(`mixin:${normalizedModelName}`); + let mixin = MaybeMixin && MaybeMixin.class; if (mixin) { let ModelForMixin = Model.extend(mixin); diff --git a/addon/-private/utils.js b/addon/-private/utils.js index f3bd4ed6aaf..aecf3a50e98 100644 --- a/addon/-private/utils.js +++ b/addon/-private/utils.js @@ -1,4 +1,3 @@ -import { getOwner as emberGetOwner } from '@ember/application'; import { get } from '@ember/object'; /* @@ -13,34 +12,4 @@ function modelHasAttributeOrRelationshipNamedType(modelClass) { ); } -/* - ember-container-inject-owner is a new feature in Ember 2.3 that finally provides a public - API for looking items up. This function serves as a super simple polyfill to avoid - triggering deprecations. - */ -function getOwner(context) { - let owner; - - if (emberGetOwner) { - owner = emberGetOwner(context); - } else if (context.container) { - owner = context.container; - } - - if (owner && owner.lookupFactory && !owner._lookupFactory) { - // `owner` is a container, we are just making this work - owner._lookupFactory = function() { - return owner.lookupFactory(...arguments); - }; - - owner.register = function() { - let registry = owner.registry || owner._registry || owner; - - return registry.register(...arguments); - }; - } - - return owner; -} - -export { modelHasAttributeOrRelationshipNamedType, getOwner }; +export { modelHasAttributeOrRelationshipNamedType }; diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 5de6c37f478..dfbdcb354ef 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -2,9 +2,9 @@ import { assign, merge } from '@ember/polyfills'; import { isNone, typeOf } from '@ember/utils'; import { get } from '@ember/object'; import { assert, warn } from '@ember/debug'; +import { getOwner } from '@ember/application'; import Serializer from '../serializer'; import { - getOwner, coerceId, modelHasAttributeOrRelationshipNamedType, normalizeModelName, diff --git a/tests/acceptance/relationships/belongs-to-test.js b/tests/acceptance/relationships/belongs-to-test.js index 07c734ea5b2..5b64ac7792c 100644 --- a/tests/acceptance/relationships/belongs-to-test.js +++ b/tests/acceptance/relationships/belongs-to-test.js @@ -1,4 +1,4 @@ -import { module, skip as test } from 'qunit'; +import { module, test, skip } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import JSONAPIAdapter from 'ember-data/adapters/json-api'; import Model from 'ember-data/model'; @@ -7,7 +7,7 @@ import hbs from 'htmlbars-inline-precompile'; import { attr, hasMany, belongsTo } from '@ember-decorators/data'; import JSONAPISerializer from 'ember-data/serializers/json-api'; import Store from 'ember-data/store'; -import { resolve, reject } from 'rsvp'; +import { Promise, resolve, reject } from 'rsvp'; import { ServerError } from 'ember-data/adapters/errors'; import Ember from 'ember'; @@ -39,12 +39,30 @@ class TestAdapter extends JSONAPIAdapter { return false; } + pause() { + this.isPaused = true; + this.pausePromise = new Promise(resolve => { + this._resume = resolve; + }); + } + + resume() { + if (this.isPaused) { + this.isPaused = false; + this._resume(); + } + } + _nextPayload() { + if (this.isPaused) { + return this.pausePromise.then(() => this._nextPayload()); + } + let payload = this._payloads.shift(); if (payload === undefined) { this.assert.ok(false, 'Too many adapter requests have been made!'); - return resolve({ data: null }); + return reject(new ServerError([], 'Too many adapter requests have been made!')); } if (payload instanceof ServerError) { @@ -356,7 +374,7 @@ module('async belongs-to rendering tests', function(hooks) { assert.equal(this.element.textContent.trim(), 'Kevin has two children and one parent'); }); - test('Rendering an async belongs-to whose fetch fails does not trigger a new request', async function(assert) { + skip('Rendering an async belongs-to whose fetch fails does not trigger a new request', async function(assert) { assert.expect(15); let people = makePeopleWithRelationshipData(); let sedona = store.push({ @@ -371,23 +389,20 @@ module('async belongs-to rendering tests', function(hooks) { this.set('sedona', sedona); let originalOnError = Ember.onerror; + let hasFired = false; Ember.onerror = function(e) { - assert.ok(true, 'Children promise did reject'); - assert.equal( - e.message, - 'hard error while finding 5:has-parent-no-children', - 'Rejection has the correct message' - ); - }; - - // needed for LTS 2.12 and 2.16 - Ember.Test.adapter.exception = e => { - assert.ok(true, 'Children promise did reject'); - assert.equal( - e.message, - 'hard error while finding 5:has-parent-no-children', - 'Rejection has the correct message' - ); + if (!hasFired) { + hasFired = true; + assert.ok(true, 'Children promise did reject'); + assert.equal( + e.message, + 'hard error while finding 5:has-parent-no-children', + 'Rejection has the correct message' + ); + } else { + assert.ok(false, 'We only reject a single time'); + adapter.pause(); // prevent further recursive calls to load the relationship + } }; await render(hbs` diff --git a/tests/acceptance/relationships/has-many-test.js b/tests/acceptance/relationships/has-many-test.js index 8246239c0a7..ba26ae6662a 100644 --- a/tests/acceptance/relationships/has-many-test.js +++ b/tests/acceptance/relationships/has-many-test.js @@ -1,4 +1,4 @@ -import { module, skip as test } from 'qunit'; +import { module, test, skip } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import JSONAPIAdapter from 'ember-data/adapters/json-api'; import Model from 'ember-data/model'; @@ -287,7 +287,7 @@ module('async has-many rendering tests', function(hooks) { ); }); - test('Rendering an async hasMany whose fetch fails does not trigger a new request', async function(assert) { + skip('Rendering an async hasMany whose fetch fails does not trigger a new request', async function(assert) { assert.expect(12); let people = makePeopleWithRelationshipData(); let parent = store.push({ @@ -312,16 +312,6 @@ module('async has-many rendering tests', function(hooks) { ); }; - // needed for LTS 2.12 and 2.16 - Ember.Test.adapter.exception = e => { - assert.ok(true, 'Children promise did reject'); - assert.equal( - e.message, - 'hard error while finding 5:has-parent-no-children', - 'Rejection has the correct message' - ); - }; - await render(hbs`
        {{#each parent.children as |child|}} @@ -454,7 +444,7 @@ module('async has-many rendering tests', function(hooks) { ); }); - test('Rendering an async hasMany with a link whose fetch fails does not trigger a new request', async function(assert) { + skip('Rendering an async hasMany with a link whose fetch fails does not trigger a new request', async function(assert) { assert.expect(12); let people = makePeopleWithRelationshipLinks(true); let parent = store.push({ @@ -485,16 +475,6 @@ module('async has-many rendering tests', function(hooks) { ); }; - // needed for LTS 2.12 and 2.16 - Ember.Test.adapter.exception = e => { - assert.ok(true, 'Children promise did reject'); - assert.equal( - e.message, - 'hard error while finding link ./person/3:has-2-children-and-parent/children', - 'Rejection has the correct message' - ); - }; - await render(hbs`
          {{#each parent.children as |child|}} diff --git a/tests/integration/adapter/client-side-delete-test.js b/tests/integration/adapter/client-side-delete-test.js index c755de89971..3470a0072f7 100644 --- a/tests/integration/adapter/client-side-delete-test.js +++ b/tests/integration/adapter/client-side-delete-test.js @@ -5,6 +5,7 @@ import setupStore from 'dummy/tests/helpers/store'; import { module, test } from 'qunit'; import DS from 'ember-data'; +import { settled } from '@ember/test-helpers'; module('integration/adapter/store-adapter - client-side delete', { beforeEach() { @@ -28,7 +29,7 @@ module('integration/adapter/store-adapter - client-side delete', { }, }); -test('client-side deleted records can be added back from an inverse', function(assert) { +test('client-side deleted records can be added back from an inverse', async function(assert) { this.adapter.deleteRecord = function(store, modelClass, snapshot) { if (snapshot.adapterOptions.clientSideDelete) { return resolve(); @@ -37,69 +38,68 @@ test('client-side deleted records can be added back from an inverse', function(a assert.ok(false, 'unreachable'); }; - run(() => - this.store.push({ - data: { - id: '1', - type: 'bookstore', - relationships: { - books: { - data: [ - { - id: '1', - type: 'book', - }, - { - id: '2', - type: 'book', - }, - ], - }, + let bookstore = this.store.push({ + data: { + id: '1', + type: 'bookstore', + relationships: { + books: { + data: [ + { + id: '1', + type: 'book', + }, + { + id: '2', + type: 'book', + }, + ], }, }, - included: [ - { - id: '1', - type: 'book', - }, - { - id: '2', - type: 'book', - }, - ], - }) - ); + }, + included: [ + { + id: '1', + type: 'book', + }, + { + id: '2', + type: 'book', + }, + ], + }); - let bookstore = this.store.peekRecord('bookstore', '1'); assert.deepEqual(bookstore.get('books').mapBy('id'), ['1', '2'], 'initial hasmany loaded'); let book2 = this.store.peekRecord('book', '2'); - return run(() => book2.destroyRecord({ adapterOptions: { clientSideDelete: true } })).then(() => { - run(() => book2.unloadRecord()); - assert.equal(this.store.hasRecordForId('book', '2'), false, 'book 2 unloaded'); - assert.deepEqual(bookstore.get('books').mapBy('id'), ['1'], 'one book client-side deleted'); - - run(() => - this.store.push({ - data: { - id: '2', - type: 'book', - relationships: { - bookstore: { - data: { - id: '1', - type: 'bookstore', - }, - }, + + await book2.destroyRecord({ adapterOptions: { clientSideDelete: true } }); + + book2.unloadRecord(); + + await settled(); + + assert.equal(this.store.hasRecordForId('book', '2'), false, 'book 2 unloaded'); + assert.deepEqual(bookstore.get('books').mapBy('id'), ['1'], 'one book client-side deleted'); + + this.store.push({ + data: { + id: '2', + type: 'book', + relationships: { + bookstore: { + data: { + id: '1', + type: 'bookstore', }, }, - }) - ); - - assert.deepEqual( - bookstore.get('books').mapBy('id'), - ['1', '2'], - 'the deleted book (with same id) is pushed back into the store' - ); + }, + }, }); + + assert.deepEqual( + bookstore.get('books').mapBy('id'), + ['1', '2'], + 'the deleted book (with same id) is pushed back into the store' + ); }); diff --git a/tests/integration/adapter/json-api-adapter-test.js b/tests/integration/adapter/json-api-adapter-test.js index 42320fb9e70..5d092798117 100644 --- a/tests/integration/adapter/json-api-adapter-test.js +++ b/tests/integration/adapter/json-api-adapter-test.js @@ -864,7 +864,7 @@ test('create record', function(assert) { }); }); -test('update record', function(assert) { +test('update record', async function(assert) { assert.expect(3); ajaxResponse([ @@ -876,67 +876,65 @@ test('update record', function(assert) { }, ]); - return run(() => { - let user = store.push({ - data: { - type: 'user', - id: '1', - attributes: { - firstName: 'Yehuda', - lastName: 'Katz', - }, + let user = store.push({ + data: { + type: 'user', + id: '1', + attributes: { + firstName: 'Yehuda', + lastName: 'Katz', }, - }); + }, + }); - let company = store.push({ - data: { - type: 'company', - id: '2', - attributes: { - name: 'Tilde Inc.', - }, + let company = store.push({ + data: { + type: 'company', + id: '2', + attributes: { + name: 'Tilde Inc.', }, - }); + }, + }); - let githubHandle = store.push({ - data: { - type: 'github-handle', - id: '3', - attributes: { - username: 'wycats', - }, + let githubHandle = store.push({ + data: { + type: 'github-handle', + id: '3', + attributes: { + username: 'wycats', }, - }); + }, + }); - user.set('firstName', 'Yehuda!'); - user.set('company', company); + user.set('firstName', 'Yehuda!'); + user.set('company', company); - return user.get('handles').then(handles => { - handles.addObject(githubHandle); + let handles = await user.get('handles'); - return user.save().then(() => { - assert.equal(passedUrl[0], '/users/1'); - assert.equal(passedVerb[0], 'PATCH'); - // TODO @runspired seems mega-bad that we expect an extra `data` key - assert.deepEqual(passedHash[0], { - data: { - data: { - type: 'users', - id: '1', - attributes: { - 'first-name': 'Yehuda!', - 'last-name': 'Katz', - }, - relationships: { - company: { - data: { type: 'companies', id: '2' }, - }, - }, - }, + handles.addObject(githubHandle); + + await user.save(); + + assert.equal(passedUrl[0], '/users/1'); + assert.equal(passedVerb[0], 'PATCH'); + // TODO @runspired seems mega-bad that we expect an extra `data` key + assert.deepEqual(passedHash[0], { + data: { + data: { + type: 'users', + id: '1', + attributes: { + 'first-name': 'Yehuda!', + 'last-name': 'Katz', + }, + relationships: { + company: { + data: { type: 'companies', id: '2' }, }, - }); - }); - }); + }, + }, + }, }); }); diff --git a/tests/integration/application-test.js b/tests/integration/application-test.js index 25132ace179..74c1db3a471 100644 --- a/tests/integration/application-test.js +++ b/tests/integration/application-test.js @@ -3,180 +3,162 @@ import Service, { inject as service } from '@ember/service'; import Controller from '@ember/controller'; import Application from '@ember/application'; import { run } from '@ember/runloop'; -import Ember from 'ember'; - +import Store from 'ember-data/store'; import { module, test } from 'qunit'; - -import DS from 'ember-data'; - -const Store = DS.Store; - -let app, App, container; +import { setupTest } from 'ember-qunit'; +import JSONAPIAdapter from 'ember-data/adapters/json-api'; +import initializeEmberData from 'ember-data/setup-container'; +import initializeStoreService from 'ember-data/initialize-store-service'; /* - These tests ensure that Ember Data works with Ember.js' application + These tests ensure that Ember Data works with Ember's application initialization and dependency injection APIs. */ +module('integration/application - Injecting a Custom Store', function(hooks) { + setupTest(hooks); -function getStore() { - return lookup('service:store'); -} - -function lookup(thing) { - return run(container, 'lookup', thing); -} - -module('integration/application - Injecting a Custom Store', { - beforeEach() { - run(() => { - app = Application.create({ - StoreService: Store.extend({ isCustom: true }), - FooController: Controller.extend(), - BazController: {}, - ApplicationController: Controller.extend(), - rootElement: '#qunit-fixture', - }); - }); - - container = app.__container__; - }, + hooks.beforeEach(function() { + let { owner } = this; - afterEach() { - run(app, app.destroy); - }, -}); + owner.register('service:store', Store.extend({ isCustom: true })); + owner.register('controller:foo', Controller.extend()); + owner.register('controller:baz', {}); + owner.register('controller:application', Controller.extend()); + }); -test('If a Store property exists on an Ember.Application, it should be instantiated.', function(assert) { - run(() => { - assert.ok(getStore().get('isCustom'), 'the custom store was instantiated'); + test('If a Store property exists on an Application, it should be instantiated.', async function(assert) { + let store = this.owner.lookup('service:store'); + assert.ok(store.isCustom === true, 'the custom store was instantiated'); }); -}); -test('If a store is instantiated, it should be made available to each controller.', function(assert) { - let fooController = lookup('controller:foo'); - let isCustom = run(fooController, 'get', 'store.isCustom'); - assert.ok(isCustom, 'the custom store was injected'); -}); + test('If a store is instantiated, it should be made available to each controller.', async function(assert) { + let fooController = this.owner.lookup('controller:foo'); + let isCustom = fooController.get('store.isCustom'); + assert.ok(isCustom, 'the custom store was injected'); + }); -test('The JSONAPIAdapter is the default adapter when no custom adapter is provided', function(assert) { - run(() => { - let store = getStore(); + test('The JSONAPIAdapter is the default adapter when no custom adapter is provided', async function(assert) { + let store = this.owner.lookup('service:store'); let adapter = store.adapterFor('application'); - assert.ok(adapter instanceof DS.JSONAPIAdapter, 'default adapter should be the JSONAPIAdapter'); + assert.ok(adapter instanceof JSONAPIAdapter, 'default adapter should be the JSONAPIAdapter'); }); }); -module('integration/application - Injecting the Default Store', { - beforeEach() { - run(() => { - app = Application.create({ - FooController: Controller.extend(), - BazController: {}, - ApplicationController: Controller.extend(), - }); - }); +module('integration/application - Injecting the Default Store', function(hooks) { + setupTest(hooks); - container = app.__container__; - }, + hooks.beforeEach(function() { + let { owner } = this; - afterEach() { - run(app, 'destroy'); - }, -}); + owner.register('controller:foo', Controller.extend()); + owner.register('controller:baz', {}); + owner.register('controller:application', Controller.extend()); + }); -test('If a Store property exists on an Ember.Application, it should be instantiated.', function(assert) { - assert.ok(getStore() instanceof DS.Store, 'the store was instantiated'); -}); + test('If a Store property exists on an Application, it should be instantiated.', async function(assert) { + let store = this.owner.lookup('service:store'); + assert.ok(store instanceof Store, 'the store was instantiated'); + }); -test('If a store is instantiated, it should be made available to each controller.', function(assert) { - run(() => { - let fooController = lookup('controller:foo'); - assert.ok(fooController.get('store') instanceof DS.Store, 'the store was injected'); + test('If a store is instantiated, it should be made available to each controller.', async function(assert) { + let fooController = this.owner.lookup('controller:foo'); + assert.ok(fooController.get('store') instanceof Store, 'the store was injected'); }); -}); -test('the DS namespace should be accessible', function(assert) { - run(() => { + test('the DS namespace should be accessible', async function(assert) { assert.ok(Namespace.byName('DS') instanceof Namespace, 'the DS namespace is accessible'); }); }); -if (Ember.inject && service) { - module('integration/application - Using the store as a service', { - beforeEach() { - run(() => { - app = Application.create({ - DoodleService: Service.extend({ store: service() }), - }); - }); - - container = app.__container__; - }, - - afterEach() { - run(app, 'destroy'); - }, +module('integration/application - Using the store as a service', function(hooks) { + setupTest(hooks); + + hooks.beforeEach(function() { + let { owner } = this; + + owner.register('controller:foo', Controller.extend()); + owner.register('controller:baz', {}); + owner.register('controller:application', Controller.extend()); + owner.register('service:doodle', Service.extend({ store: service() })); + owner.register('service:second-store', Store); }); - test('The store can be injected as a service', function(assert) { - run(() => { - let doodleService = lookup('service:doodle'); - assert.ok(doodleService.get('store') instanceof Store, 'the store can be used as a service'); - }); + test('The store can be injected as a service', async function(assert) { + let doodleService = this.owner.lookup('service:doodle'); + assert.ok(doodleService.get('store') instanceof Store, 'the store can be used as a service'); }); -} -module('integration/application - Attaching initializer', { - beforeEach() { - App = Application.extend(); - }, + test('There can be multiple store services', function(assert) { + let doodleService = this.owner.lookup('service:doodle'); + let store = doodleService.get('store'); + let secondService = this.owner.lookup('service:second-store'); - afterEach() { - if (app) { - run(app, app.destroy); - } - }, + assert.ok(secondService instanceof Store, 'the store can be used as a service'); + assert.ok(store !== secondService, 'the store can be used as a service'); + }); }); -test('ember-data initializer is run', function(assert) { - let ran = false; - App.initializer({ - name: 'after-ember-data', - after: 'ember-data', - initialize() { - ran = true; - }, +module('integration/application - Attaching initializer', function(hooks) { + hooks.beforeEach(function() { + this.TestApplication = Application.extend(); + this.TestApplication.initializer({ + name: 'ember-data', + initialize: initializeEmberData, + }); + this.TestApplication.instanceInitializer({ + name: 'ember-data', + initialize: initializeStoreService, + }); + this.application = null; + this.owner = null; }); - run(() => { - app = App.create(); + hooks.afterEach(function() { + if (this.application !== null) { + run(this.application, 'destroy'); + } }); - assert.ok(ran, 'ember-data initializer was found'); -}); + test('ember-data initializer is run', async function(assert) { + let ran = false; -test('ember-data initializer does not register the store service when it was already registered', function(assert) { - let AppStore = Store.extend({ - isCustomStore: true, - }); + this.TestApplication.initializer({ + name: 'after-ember-data', + after: 'ember-data', + initialize() { + ran = true; + }, + }); - App.initializer({ - name: 'after-ember-data', - before: 'ember-data', - initialize(registry) { - registry.register('service:store', AppStore); - }, - }); + this.application = this.TestApplication.create({ autoboot: false }); + + await this.application.boot(); - run(() => { - app = App.create(); - container = app.__container__; + assert.ok(ran, 'ember-data initializer was found'); }); - let store = getStore(); - assert.ok( - store && store.get('isCustomStore'), - 'ember-data initializer does not overwrite the previous registered service store' - ); + test('ember-data initializer does not register the store service when it was already registered', async function(assert) { + let AppStore = Store.extend({ + isCustomStore: true, + }); + + this.TestApplication.initializer({ + name: 'before-ember-data', + before: 'ember-data', + initialize(registry) { + registry.register('service:store', AppStore); + }, + }); + + this.application = this.TestApplication.create({ autoboot: false }); + + await this.application.boot().then(() => (this.owner = this.application.buildInstance())); + + let store = this.owner.lookup('service:store'); + assert.ok( + store && store.get('isCustomStore'), + 'ember-data initializer does not overwrite the previous registered service store' + ); + }); }); diff --git a/tests/integration/injection-test.js b/tests/integration/injection-test.js index 4e5d80c7cbf..3ed1ccac594 100644 --- a/tests/integration/injection-test.js +++ b/tests/integration/injection-test.js @@ -1,118 +1,71 @@ -import { - setup as setupModelFactoryInjections, - reset as resetModelFactoryInjections, -} from 'dummy/tests/helpers/model-factory-injection'; -import EmberObject from '@ember/object'; -import { getOwner } from '@ember/application'; -import { run } from '@ember/runloop'; -import setupStore from 'dummy/tests/helpers/store'; -import DS from 'ember-data'; +import Model from 'ember-data/model'; +import Service from '@ember/service'; import { module, test } from 'qunit'; - -let env, hasFactoryFor, originalLookupFactory, originalOwnerLookupFactory, originalFactoryFor; - -const model = { - isModel: true, - _create() {}, -}; -const factory = { - class: model, -}; - -module('integration/injection factoryFor enabled', { - beforeEach() { - env = setupStore(); - - if (getOwner) { - let owner = getOwner(env.store); - - hasFactoryFor = !!owner.factoryFor; - originalFactoryFor = owner.factoryFor; - originalOwnerLookupFactory = owner._lookupFactory; - - if (originalFactoryFor) { - owner.factoryFor = function(/* name */) { - return factory; - }; - } else { - // Ember 2.3 - Ember 2.11 - originalOwnerLookupFactory = owner._lookupFactory; - owner._lookupFactory = function() { - return model; - }; - } - } else { - originalLookupFactory = env.store.container.lookupFactory; - env.store.container.lookupFactory = function() { - return model; - }; - } - }, - - afterEach() { - if (getOwner) { - let owner = getOwner(env.store); - - if (owner.factoryFor) { - owner.factoryFor = originalFactoryFor; - } else { - owner._lookupFactory = originalOwnerLookupFactory; - } - } else { - env.store.container.lookupFactory = originalLookupFactory; - } - - run(env.store, 'destroy'); - }, +import { setupTest } from 'ember-qunit'; + +module('integration/injection factoryFor enabled', function(hooks) { + setupTest(hooks); + let store; + let Model; + let factory; + + hooks.beforeEach(function() { + let { owner } = this; + Model = { + isModel: true, + }; + owner.register('model:super-villain', Model); + store = owner.lookup('service:store'); + + let originalFactoryFor = owner.factoryFor; + + owner.factoryFor = function interceptFactoryFor() { + factory = originalFactoryFor.call(owner, ...arguments); + return factory; + }; + }); + + test('modelFactoryFor', function(assert) { + const modelFactory = store._modelFactoryFor('super-villain'); + + assert.strictEqual(modelFactory, factory, 'expected the factory itself to be returned'); + }); + + test('modelFor', function(assert) { + const modelClass = store.modelFor('super-villain'); + + assert.strictEqual(modelClass, Model, 'expected the factory itself to be returned'); + + assert.equal( + modelClass.modelName, + 'super-villain', + 'expected the factory itself to be returned' + ); + }); }); -test('modelFactoryFor', function(assert) { - const modelFactory = env.store._modelFactoryFor('super-villain'); +module('integration/injection eager injections', function(hooks) { + setupTest(hooks); + let store; + let Apple = Service.extend(); - assert.equal( - modelFactory, - hasFactoryFor ? factory : model, - 'expected the factory itself to be returned' - ); -}); - -test('modelFor', function(assert) { - const modelFactory = env.store.modelFor('super-villain'); - - assert.equal(modelFactory, model, 'expected the factory itself to be returned'); - - // TODO: we should deprecate this next line. Resolved state on the class is fraught with peril - assert.equal( - modelFactory.modelName, - 'super-villain', - 'expected the factory itself to be returned' - ); -}); - -module('integration/injection eager injections', { - beforeEach() { - setupModelFactoryInjections(); - env = setupStore(); + hooks.beforeEach(function() { + let { owner } = this; - env.registry.injection('model:foo', 'apple', 'service:apple'); - env.registry.register('model:foo', DS.Model); - env.registry.register('service:apple', EmberObject.extend({ isService: true })); - // container injection - }, + owner.register('model:foo', Model.extend()); + owner.register('service:apple', Apple); + owner.inject('model:foo', 'apple', 'service:apple'); - afterEach() { - // can be removed once we no longer support ember versions without lookupFactory - resetModelFactoryInjections(); - - run(env.store, 'destroy'); - }, -}); + store = this.owner.lookup('service:store'); + }); -test('did inject', function(assert) { - let foo = env.store.createRecord('foo'); - let apple = foo.get('apple'); - let Apple = env.registry.registrations['service:apple']; + test('did inject', async function(assert) { + let foo = store.createRecord('foo'); + let apple = foo.get('apple'); + let appleService = this.owner.lookup('service:apple'); - assert.ok(apple, `'model:foo' instance should have an 'apple' property`); - assert.ok(apple instanceof Apple, `'model:foo'.apple should be an instance of 'service:apple'`); + assert.ok(apple, `'model:foo' instance should have an 'apple' property`); + assert.ok(apple === appleService, `'model:foo.apple' should be the apple service`); + assert.ok(apple instanceof Apple, `'model:foo'.apple should be an instance of 'service:apple'`); + }); }); diff --git a/tests/integration/inverse-test.js b/tests/integration/inverse-test.js index 02bd45cdbb1..870f6139bab 100644 --- a/tests/integration/inverse-test.js +++ b/tests/integration/inverse-test.js @@ -1,396 +1,169 @@ -import { setupTest } from 'ember-qunit'; -import { module, test } from 'qunit'; +import { run } from '@ember/runloop'; +import setupStore from 'dummy/tests/helpers/store'; + import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import Model from 'ember-data/model'; -import { attr, belongsTo, hasMany } from '@ember-decorators/data'; +import { module, test } from 'qunit'; -module('integration/inverse-test - Model.inverseFor', function(hooks) { - setupTest(hooks); - let store; +import DS from 'ember-data'; - hooks.beforeEach(function() { - let { owner } = this; +let env, store, User, Job, ReflexiveModel; - class User extends Model { - @attr - name; - @belongsTo('user', { async: true, inverse: null }) - bestFriend; - @belongsTo('job', { async: false }) - job; - } - class Job extends Model { - @attr - isGood; - @belongsTo('user', { async: false }) - user; - } - class ReflexiveModel extends Model { - @belongsTo('reflexiveModel', { async: false }) - reflexiveProp; - } - owner.register('model:user', User); - owner.register('model:job', Job); - owner.register('model:reflexive-model', ReflexiveModel); +const { attr, belongsTo } = DS; - store = owner.lookup('service:store'); - }); +function stringify(string) { + return function() { + return string; + }; +} - test('Finds the inverse when there is only one possible available', function(assert) { - let Job = store.modelFor('job'); - let inverseDefinition = Job.inverseFor('user', store); +module('integration/inverse_test - inverseFor', { + beforeEach() { + User = DS.Model.extend({ + name: attr('string'), + bestFriend: belongsTo('user', { async: true, inverse: null }), + job: belongsTo('job', { async: false }), + }); - assert.deepEqual( - inverseDefinition, - { - type: store.modelFor('user'), - name: 'job', - kind: 'belongsTo', - options: { - async: false, - }, - }, - 'Gets correct type, name and kind' - ); - }); + User.toString = stringify('user'); - test('Finds the inverse when only one side has defined it manually', function(assert) { - let { owner } = this; - owner.unregister('model:job'); - owner.unregister('model:user'); + Job = DS.Model.extend({ + isGood: attr(), + user: belongsTo('user', { async: false }), + }); - class Job extends Model { - @belongsTo('user', { async: false }) - user; - @belongsTo('user', { inverse: 'previousJob', async: false }) - owner; - } - class User extends Model { - @belongsTo('job', { async: false }) - previousJob; - } - owner.register('model:job', Job); - owner.register('model:user', User); + Job.toString = stringify('job'); - // lookup the user model's inverse first given that it does not - // define the inverse and there are two potential matches - assert.deepEqual( - store.modelFor('user').inverseFor('previousJob', store), - { - type: Job, //the model's type - name: 'owner', //the models relationship key - kind: 'belongsTo', - options: { - inverse: 'previousJob', - async: false, - }, - }, - 'Gets correct type, name and kind' - ); + ReflexiveModel = DS.Model.extend({ + reflexiveProp: belongsTo('reflexive-model', { async: false }), + }); - assert.deepEqual( - store.modelFor('job').inverseFor('owner', store), - { - type: User, //the model's type - name: 'previousJob', //the models relationship key - kind: 'belongsTo', - options: { - async: false, - }, - }, - 'Gets correct type, name and kind' - ); - }); + ReflexiveModel.toString = stringify('reflexiveModel'); - test('Returns null if inverse relationship it is manually set with a different relationship key', function(assert) { - let { owner } = this; - owner.unregister('model:job'); - owner.unregister('model:user'); + env = setupStore({ + user: User, + job: Job, + reflexiveModel: ReflexiveModel, + }); - class Job extends Model { - @belongsTo('user', { inverse: 'previousJob', async: false }) - user; - } - class User extends Model { - @belongsTo('job', { async: false }) - job; - } - owner.register('model:job', Job); - owner.register('model:user', User); + store = env.store; - assert.equal(User.inverseFor('job', store), null, 'There is no inverse'); - }); + Job = store.modelFor('job'); + User = store.modelFor('user'); + ReflexiveModel = store.modelFor('reflexive-model'); + }, - testInDebug('Errors out if you define 2 inverses to the same model', function(assert) { - let { owner } = this; - owner.unregister('model:job'); - owner.unregister('model:user'); + afterEach() { + run(env.container, 'destroy'); + }, +}); - class Job extends Model { - @belongsTo('user', { inverse: 'job', async: false }) - user; - @belongsTo('user', { inverse: 'job', async: false }) - owner; - } - class User extends Model { - @belongsTo('job', { async: false }) - job; - } - owner.register('model:job', Job); - owner.register('model:user', User); +test('Finds the inverse when there is only one possible available', function(assert) { + let inverseDefinition = Job.inverseFor('user', store); + + assert.deepEqual( + inverseDefinition, + { + type: User, + name: 'job', + kind: 'belongsTo', + options: { + async: false, + }, + }, + 'Gets correct type, name and kind' + ); +}); - assert.expectAssertion(() => { - store.modelFor('user').inverseFor('job', store); - }, /You defined the 'job' relationship on model:user, but you defined the inverse relationships of type model:job multiple times/); +test('Finds the inverse when only one side has defined it manually', function(assert) { + Job.reopen({ + owner: belongsTo('user', { inverse: 'previousJob', async: false }), }); - test('Caches findInverseFor return value', function(assert) { - assert.expect(1); - let Job = store.modelFor('job'); + User.reopen({ + previousJob: belongsTo('job', { async: false }), + }); - let inverseForUser = Job.inverseFor('user', store); - Job.findInverseFor = function() { - assert.ok(false, 'Find is not called anymore'); - }; + assert.deepEqual( + Job.inverseFor('owner', store), + { + type: User, //the model's type + name: 'previousJob', //the models relationship key + kind: 'belongsTo', + options: { + async: false, + }, + }, + 'Gets correct type, name and kind' + ); - assert.equal(inverseForUser, Job.inverseFor('user', store), 'Inverse cached succesfully'); + assert.deepEqual( + User.inverseFor('previousJob', store), + { + type: Job, //the model's type + name: 'owner', //the models relationship key + kind: 'belongsTo', + options: { + inverse: 'previousJob', + async: false, + }, + }, + 'Gets correct type, name and kind' + ); +}); + +test('Returns null if inverse relationship it is manually set with a different relationship key', function(assert) { + Job.reopen({ + user: belongsTo('user', { inverse: 'previousJob', async: false }), }); - testInDebug('Errors out if you do not define an inverse for a reflexive relationship', function( - assert - ) { - //Maybe store is evaluated lazily, so we need this :( - assert.expectWarning(() => { - store.push({ - data: { - type: 'reflexive-model', - id: '1', - }, - }); - let reflexiveModel = store.peekRecord('reflexive-model', 1); - reflexiveModel.get('reflexiveProp'); - }, /Detected a reflexive relationship by the name of 'reflexiveProp'/); + User.reopen({ + job: belongsTo('job', { async: false }), }); - test('inverseFor is only called when inverse is not null', async function(assert) { - assert.expect(2); - let { owner } = this; - owner.unregister('model:user'); - owner.unregister('model:job'); + assert.equal(User.inverseFor('job', store), null, 'There is no inverse'); +}); - class Post extends Model { - @hasMany('comment', { async: false, inverse: null }) - comments; - } - class Comment extends Model { - @belongsTo('post', { async: false, inverse: null }) - post; - } - class User extends Model { - @hasMany('message', { async: false, inverse: 'user' }) - messages; - } - class Message extends Model { - @belongsTo('user', { async: false, inverse: 'messages' }) - user; - } - owner.register('model:post', Post); - owner.register('model:comment', Comment); - owner.register('model:user', User); - owner.register('model:message', Message); +testInDebug('Errors out if you define 2 inverses to the same model', function(assert) { + Job.reopen({ + user: belongsTo('user', { inverse: 'job', async: false }), + owner: belongsTo('user', { inverse: 'job', async: false }), + }); - store.modelFor('post').inverseFor = function() { - assert.notOk(true, 'Post model inverseFor is not called'); - }; + User.reopen({ + job: belongsTo('job', { async: false }), + }); - store.modelFor('comment').inverseFor = function() { - assert.notOk(true, 'Comment model inverseFor is not called'); - }; + assert.expectAssertion(() => { + User.inverseFor('job', store); + }, /You defined the 'job' relationship on user, but you defined the inverse relationships of type job multiple times/i); +}); - store.modelFor('message').inverseFor = function() { - assert.ok(true, 'Message model inverseFor is called'); - }; +test('Caches findInverseFor return value', function(assert) { + assert.expect(1); - store.modelFor('user').inverseFor = function() { - assert.ok(true, 'User model inverseFor is called'); - }; + var inverseForUser = Job.inverseFor('user', store); + Job.findInverseFor = function() { + assert.ok(false, 'Find is not called anymore'); + }; - store.push({ - data: { - id: '1', - type: 'post', - relationships: { - comments: { - data: [ - { - id: '1', - type: 'comment', - }, - { - id: '2', - type: 'comment', - }, - ], - }, - }, - }, - }); - store.push({ - data: [ - { - id: '1', - type: 'comment', - relationships: { - post: { - data: { - id: '1', - type: 'post', - }, - }, - }, - }, - { - id: '2', - type: 'comment', - relationships: { - post: { - data: { - id: '1', - type: 'post', - }, - }, - }, - }, - ], - }); - store.push({ - data: { - id: '1', - type: 'user', - relationships: { - messages: { - data: [ - { - id: '1', - type: 'message', - }, - { - id: '2', - type: 'message', - }, - ], - }, - }, - }, - }); - store.push({ - data: [ - { + assert.equal(inverseForUser, Job.inverseFor('user', store), 'Inverse cached succesfully'); +}); + +testInDebug('Errors out if you do not define an inverse for a reflexive relationship', function( + assert +) { + //Maybe store is evaluated lazily, so we need this :( + assert.expectWarning(() => { + var reflexiveModel; + run(() => { + store.push({ + data: { + type: 'reflexive-model', id: '1', - type: 'message', - relationships: { - user: { - data: { - id: '1', - type: 'user', - }, - }, - }, - }, - { - id: '2', - type: 'message', - relationships: { - post: { - data: { - id: '1', - type: 'user', - }, - }, - }, }, - ], + }); + reflexiveModel = store.peekRecord('reflexive-model', 1); + reflexiveModel.get('reflexiveProp'); }); - }); - - testInDebug( - "Inverse null relationships with models that don't exist throw a nice error if trying to use that relationship", - async function(assert) { - this.owner.unregister('model:user'); - class User extends Model { - @belongsTo('post', { inverse: null }) - post; - } - this.owner.register('model:user', User); - - assert.expectAssertion(() => { - store.createRecord('user', { post: null }); - }, /No model was found for/); - - // but don't error if the relationship is not used - store.createRecord('user', {}); - } - ); - - test('Inverse relationships can be explicitly nullable', function(assert) { - this.owner.unregister('model:user'); - class User extends Model { - @hasMany('post', { inverse: 'participants', async: false }) - posts; - } - class Post extends Model { - @belongsTo('user', { inverse: null, async: false }) - lastParticipant; - @hasMany('user', { inverse: 'posts', async: false }) - participants; - } - this.owner.register('model:user', User); - this.owner.register('model:post', Post); - - let user = store.createRecord('user'); - let post = store.createRecord('post'); - - assert.equal( - user.inverseFor('posts').name, - 'participants', - 'User.posts inverse is Post.participants' - ); - assert.equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); - assert.equal( - post.inverseFor('participants').name, - 'posts', - 'Post.participants inverse is User.posts' - ); - }); - - test('Null inverses are excluded from potential relationship resolutions', function(assert) { - this.owner.unregister('model:user'); - class User extends Model { - @hasMany('post', { async: false }) - posts; - } - class Post extends Model { - @belongsTo('user', { inverse: null, async: false }) - lastParticipant; - @hasMany('user', { async: false }) - participants; - } - this.owner.register('model:user', User); - this.owner.register('model:post', Post); - - let user = store.createRecord('user'); - let post = store.createRecord('post'); - - assert.equal( - user.inverseFor('posts').name, - 'participants', - 'User.posts inverse is Post.participants' - ); - assert.equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); - assert.equal( - post.inverseFor('participants').name, - 'posts', - 'Post.participants inverse is User.posts' - ); - }); + }, /Detected a reflexive relationship by the name of 'reflexiveProp'/); }); diff --git a/tests/integration/records/record-data-test.js b/tests/integration/records/record-data-test.js index bab17bdc010..e8bb3b29ee6 100644 --- a/tests/integration/records/record-data-test.js +++ b/tests/integration/records/record-data-test.js @@ -105,16 +105,11 @@ module('RecordData Compatibility', function(hooks) { test(`store.unloadRecord on a record with default RecordData with relationship to a record with custom RecordData does not error`, async function(assert) { const originalCreateRecordDataFor = store.createRecordDataFor; - store.createRecordDataFor = function provideCustomRecordData( - modelName, - id, - clientId, - storeWrapper - ) { + store.createRecordDataFor = function provideCustomRecordData(modelName, id, lid, storeWrapper) { if (modelName === 'pet') { - return new CustomRecordData(modelName, id, clientId, storeWrapper); + return new CustomRecordData(modelName, id, lid, storeWrapper); } else { - return originalCreateRecordDataFor.call(this, modelName, id, clientId, storeWrapper); + return originalCreateRecordDataFor.call(this, modelName, id, lid, storeWrapper); } }; @@ -171,16 +166,11 @@ module('RecordData Compatibility', function(hooks) { test(`store.unloadRecord on a record with custom RecordData with relationship to a record with default RecordData does not error`, async function(assert) { const originalCreateRecordDataFor = store.createModelDataFor; - store.createModelDataFor = function provideCustomRecordData( - modelName, - id, - clientId, - storeWrapper - ) { + store.createModelDataFor = function provideCustomRecordData(modelName, id, lid, storeWrapper) { if (modelName === 'pet') { - return new CustomRecordData(modelName, id, clientId, storeWrapper); + return new CustomRecordData(modelName, id, lid, storeWrapper); } else { - return originalCreateRecordDataFor.call(this, modelName, id, clientId, storeWrapper); + return originalCreateRecordDataFor.call(this, modelName, id, lid, storeWrapper); } }; diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 514bb651c62..acd834d0299 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -22,6 +22,10 @@ import { relationshipStateFor, } from 'ember-data/-private'; +function getRelationshipsFor(record) { + return record._internalModel._recordData._relationships; +} + const { attr: DSattr, hasMany: DShasMany, belongsTo: DSbelongsTo } = DS; const { hash } = RSVP; @@ -1954,11 +1958,11 @@ test("belongsTo relationship doesn't trigger when model data doesn't support imp }); const createRecordDataFor = env.store.createRecordDataFor; - env.store.createRecordDataFor = function(modelName, id, clientId, storeWrapper) { + env.store.createRecordDataFor = function(modelName, id, lid, storeWrapper) { if (modelName === 'book1' || modelName === 'section') { - return new TestRecordData(modelName, id, clientId, storeWrapper, this); + return new TestRecordData(modelName, id, lid, storeWrapper, this); } - return createRecordDataFor.call(this, modelName, id, clientId, storeWrapper); + return createRecordDataFor.call(this, modelName, id, lid, storeWrapper); }; const data = { diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 61514df6357..1b56b18dd57 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -17,6 +17,10 @@ import DS from 'ember-data'; let env, store, User, Contact, Email, Phone, Message, Post, Comment; let Book, Chapter, Page; +function getRelationshipsFor(record) { + return record._internalModel._recordData._relationships; +} + const { attr, hasMany, belongsTo } = DS; module('integration/relationships/has_many - Has-Many Relationships', { diff --git a/tests/integration/relationships/inverse-relationships-test.js b/tests/integration/relationships/inverse-relationships-test.js index 3e57c8c185d..1ffa0c46681 100644 --- a/tests/integration/relationships/inverse-relationships-test.js +++ b/tests/integration/relationships/inverse-relationships-test.js @@ -3,20 +3,21 @@ import { createStore } from 'dummy/tests/helpers/store'; import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; -import Model from 'ember-data/model'; import DS from 'ember-data'; +let { Model, hasMany, belongsTo } = DS; + var Post, Comment, Message, User; module('integration/relationships/inverse_relationships - Inverse Relationships'); test('When a record is added to a has-many relationship, the inverse belongsTo is determined automatically', function(assert) { - Post = Model.extend({ + Post = DS.Model.extend({ comments: DS.hasMany('comment', { async: false }), }); - Comment = Model.extend({ + Comment = DS.Model.extend({ post: DS.belongsTo('post', { async: false }), }); @@ -34,12 +35,78 @@ test('When a record is added to a has-many relationship, the inverse belongsTo i assert.equal(comment.get('post'), post, 'post was set on the comment'); }); -test('When a record is added to a has-many relationship, the inverse belongsTo can be set explicitly', function(assert) { +test('Inverse relationships can be explicitly nullable', function(assert) { + User = DS.Model.extend(); + + Post = DS.Model.extend({ + lastParticipant: DS.belongsTo('user', { inverse: null, async: false }), + participants: DS.hasMany('user', { inverse: 'posts', async: false }), + }); + + User.reopen({ + posts: DS.hasMany('post', { inverse: 'participants', async: false }), + }); + + var store = createStore({ + user: User, + post: Post, + }); + + let user = store.createRecord('user'); + let post = store.createRecord('post'); + + assert.equal( + user.inverseFor('posts').name, + 'participants', + 'User.posts inverse is Post.participants' + ); + assert.equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); + assert.equal( + post.inverseFor('participants').name, + 'posts', + 'Post.participants inverse is User.posts' + ); +}); + +test('Null inverses are excluded from potential relationship resolutions', function(assert) { + User = Model.extend(); + Post = Model.extend({ + lastParticipant: belongsTo('user', { inverse: null, async: false }), + participants: hasMany('user', { async: false }), + }); + + User.reopen({ + posts: hasMany('post', { async: false }), + }); + + let store = createStore({ + user: User, + post: Post, + }); + + let user = store.createRecord('user'); + let post = store.createRecord('post'); + + assert.equal( + user.inverseFor('posts').name, + 'participants', + 'User.posts inverse is Post.participants' + ); + assert.equal(post.inverseFor('lastParticipant'), null, 'Post.lastParticipant has no inverse'); + assert.equal( + post.inverseFor('participants').name, + 'posts', + 'Post.participants inverse is User.posts' + ); +}); + +test('When a record is added to a has-many relationship, the inverse belongsTo can be set explicitly', function(assert) { + Post = DS.Model.extend({ comments: DS.hasMany('comment', { inverse: 'redPost', async: false }), }); - Comment = Model.extend({ + Comment = DS.Model.extend({ onePost: DS.belongsTo('post', { async: false }), twoPost: DS.belongsTo('post', { async: false }), redPost: DS.belongsTo('post', { async: false }), @@ -68,13 +135,13 @@ test('When a record is added to a has-many relationship, the inverse belongsTo c }); test("When a record's belongsTo relationship is set, it can specify the inverse hasMany to which the new child should be added", function(assert) { - Post = Model.extend({ + Post = DS.Model.extend({ meComments: DS.hasMany('comment', { async: false }), youComments: DS.hasMany('comment', { async: false }), everyoneWeKnowComments: DS.hasMany('comment', { async: false }), }); - Comment = Model.extend({ + Comment = DS.Model.extend({ post: DS.belongsTo('post', { inverse: 'youComments', async: false }), }); @@ -105,11 +172,11 @@ test("When a record's belongsTo relationship is set, it can specify the inverse }); test('When setting a belongsTo, the OneToOne invariant is respected even when other records have been previously used', function(assert) { - Post = Model.extend({ + Post = DS.Model.extend({ bestComment: DS.belongsTo('comment', { async: false }), }); - Comment = Model.extend({ + Comment = DS.Model.extend({ post: DS.belongsTo('post', { async: false }), }); @@ -139,11 +206,11 @@ test('When setting a belongsTo, the OneToOne invariant is respected even when ot }); test('When setting a belongsTo, the OneToOne invariant is transitive', function(assert) { - Post = Model.extend({ + Post = DS.Model.extend({ bestComment: DS.belongsTo('comment', { async: false }), }); - Comment = Model.extend({ + Comment = DS.Model.extend({ post: DS.belongsTo('post', { async: false }), }); @@ -174,11 +241,11 @@ test('When setting a belongsTo, the OneToOne invariant is transitive', function( }); test('When setting a belongsTo, the OneToOne invariant is commutative', function(assert) { - Post = Model.extend({ + Post = DS.Model.extend({ bestComment: DS.belongsTo('comment', { async: false }), }); - Comment = Model.extend({ + Comment = DS.Model.extend({ post: DS.belongsTo('post', { async: false }), }); @@ -210,11 +277,11 @@ test('When setting a belongsTo, the OneToOne invariant is commutative', function test('OneToNone relationship works', function(assert) { assert.expect(3); - Post = Model.extend({ + Post = DS.Model.extend({ name: DS.attr('string'), }); - Comment = Model.extend({ + Comment = DS.Model.extend({ post: DS.belongsTo('post', { async: false }), }); @@ -242,7 +309,7 @@ test('OneToNone relationship works', function(assert) { }); test('When a record is added to or removed from a polymorphic has-many relationship, the inverse belongsTo can be set explicitly', function(assert) { - User = Model.extend({ + User = DS.Model.extend({ messages: DS.hasMany('message', { async: false, inverse: 'redUser', @@ -250,7 +317,7 @@ test('When a record is added to or removed from a polymorphic has-many relations }), }); - Message = Model.extend({ + Message = DS.Model.extend({ oneUser: DS.belongsTo('user', { async: false }), twoUser: DS.belongsTo('user', { async: false }), redUser: DS.belongsTo('user', { async: false }), @@ -290,13 +357,13 @@ test('When a record is added to or removed from a polymorphic has-many relations }); test("When a record's belongsTo relationship is set, it can specify the inverse polymorphic hasMany to which the new child should be added or removed", function(assert) { - User = Model.extend({ + User = DS.Model.extend({ meMessages: DS.hasMany('message', { polymorphic: true, async: false }), youMessages: DS.hasMany('message', { polymorphic: true, async: false }), everyoneWeKnowMessages: DS.hasMany('message', { polymorphic: true, async: false }), }); - Message = Model.extend({ + Message = DS.Model.extend({ user: DS.belongsTo('user', { inverse: 'youMessages', async: false }), }); @@ -330,7 +397,7 @@ test("When a record's belongsTo relationship is set, it can specify the inverse }); test("When a record's polymorphic belongsTo relationship is set, it can specify the inverse hasMany to which the new child should be added", function(assert) { - Message = Model.extend({ + Message = DS.Model.extend({ meMessages: DS.hasMany('comment', { inverse: null, async: false }), youMessages: DS.hasMany('comment', { inverse: 'message', async: false }), everyoneWeKnowMessages: DS.hasMany('comment', { inverse: null, async: false }), @@ -376,10 +443,10 @@ test("When a record's polymorphic belongsTo relationship is set, it can specify testInDebug("Inverse relationships that don't exist throw a nice error for a hasMany", function( assert ) { - User = Model.extend(); - Comment = Model.extend(); + User = DS.Model.extend(); + Comment = DS.Model.extend(); - Post = Model.extend({ + Post = DS.Model.extend({ comments: DS.hasMany('comment', { inverse: 'testPost', async: false }), }); @@ -399,10 +466,10 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a has testInDebug("Inverse relationships that don't exist throw a nice error for a belongsTo", function( assert ) { - User = Model.extend(); - Comment = Model.extend(); + User = DS.Model.extend(); + Comment = DS.Model.extend(); - Post = Model.extend({ + Post = DS.Model.extend({ user: DS.belongsTo('user', { inverse: 'testPost', async: false }), }); @@ -417,3 +484,158 @@ testInDebug("Inverse relationships that don't exist throw a nice error for a bel }); }, /We found no inverse relationships by the name of 'testPost' on the 'user' model/); }); + +test('inverseFor is only called when inverse is not null', function(assert) { + assert.expect(2); + Post = DS.Model.extend({ + comments: DS.hasMany('comment', { async: false, inverse: null }), + }); + + Comment = DS.Model.extend({ + post: DS.belongsTo('post', { async: false, inverse: null }), + }); + + User = DS.Model.extend({ + messages: DS.hasMany('message', { async: false, inverse: 'user' }), + }); + + Message = DS.Model.extend({ + user: DS.belongsTo('user', { async: false, inverse: 'messages' }), + }); + + var env = setupStore({ post: Post, comment: Comment, user: User, message: Message }); + var store = env.store; + + Post.inverseFor = function() { + assert.notOk(true, 'Post model inverseFor is not called'); + }; + + Comment.inverseFor = function() { + assert.notOk(true, 'Comment model inverseFor is not called'); + }; + + Message.inverseFor = function() { + assert.ok(true, 'Message model inverseFor is called'); + }; + + User.inverseFor = function() { + assert.ok(true, 'User model inverseFor is called'); + }; + + run(function() { + store.push({ + data: { + id: '1', + type: 'post', + relationships: { + comments: { + data: [ + { + id: '1', + type: 'comment', + }, + { + id: '2', + type: 'comment', + }, + ], + }, + }, + }, + }); + store.push({ + data: [ + { + id: '1', + type: 'comment', + relationships: { + post: { + data: { + id: '1', + type: 'post', + }, + }, + }, + }, + { + id: '2', + type: 'comment', + relationships: { + post: { + data: { + id: '1', + type: 'post', + }, + }, + }, + }, + ], + }); + store.push({ + data: { + id: '1', + type: 'user', + relationships: { + messages: { + data: [ + { + id: '1', + type: 'message', + }, + { + id: '2', + type: 'message', + }, + ], + }, + }, + }, + }); + store.push({ + data: [ + { + id: '1', + type: 'message', + relationships: { + user: { + data: { + id: '1', + type: 'user', + }, + }, + }, + }, + { + id: '2', + type: 'message', + relationships: { + post: { + data: { + id: '1', + type: 'user', + }, + }, + }, + }, + ], + }); + }); +}); + +testInDebug( + "Inverse null relationships with models that don't exist throw a nice error if trying to use that relationship", + function(assert) { + User = DS.Model.extend({ + post: DS.belongsTo('post', { inverse: null }), + }); + + let env = setupStore({ user: User }); + + assert.expectAssertion(() => { + env.store.createRecord('user', { post: null }); + }, /No model was found for/); + + // but don't error if the relationship is not used + env.store.createRecord('user', {}); + } +); diff --git a/tests/integration/setup-container-test.js b/tests/integration/setup-container-test.js deleted file mode 100644 index fcf890a972b..00000000000 --- a/tests/integration/setup-container-test.js +++ /dev/null @@ -1,56 +0,0 @@ -import Application from '@ember/application'; -import { run } from '@ember/runloop'; -import EmberObject from '@ember/object'; - -import { module, test } from 'qunit'; - -import DS from 'ember-data'; - -const { Store, _setupContainer: setupContainer } = DS; - -let container, registry, application; - -/* - These tests ensure that Ember Data works with Ember.js' container - initialization and dependency injection API. -*/ - -module('integration/setup-container - Setting up a container', { - beforeEach() { - application = run(() => Application.create()); - - container = application.__container__; - registry = application.__registry__; - - let setupContainerArgument; - if (registry) { - setupContainerArgument = application; - } else { - // In Ember < 2.1.0 application.__registry__ is undefined so we - // pass in the registry to mimic the setup behavior. - registry = setupContainerArgument = application.registry; - } - setupContainer(setupContainerArgument); - }, - - afterEach() { - run(() => application.destroy()); - }, -}); - -test('The store should be registered into a container.', function(assert) { - assert.ok(container.lookup('service:store') instanceof Store, 'the custom store is instantiated'); -}); - -test('The store should be registered into the container as a service.', function(assert) { - assert.ok( - container.lookup('service:store') instanceof Store, - 'the store as a service is registered' - ); -}); - -test('If a store is instantiated, it should be made available to each controller.', function(assert) { - registry.register('controller:foo', EmberObject.extend({})); - let fooController = container.lookup('controller:foo'); - assert.ok(fooController.get('store') instanceof Store, 'the store was injected'); -}); diff --git a/tests/test-helper.js b/tests/test-helper.js index 0966beb4885..65ce68364a6 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -1,6 +1,4 @@ import RSVP from 'rsvp'; - -import Application from '@ember/application'; import resolver from './helpers/resolver'; import { setResolver } from '@ember/test-helpers'; import { start } from 'ember-qunit'; @@ -8,10 +6,8 @@ import { start } from 'ember-qunit'; import QUnit from 'qunit'; import DS from 'ember-data'; import { wait, asyncEqual, invokeAsync } from 'dummy/tests/helpers/async'; -import loadInitializers from 'ember-load-initializers'; setResolver(resolver); -loadInitializers(Application, 'dummy'); const { assert } = QUnit; const transforms = { diff --git a/tests/unit/model/lifecycle-callbacks-test.js b/tests/unit/model/lifecycle-callbacks-test.js index aa4e823e524..ac3aab1ada3 100644 --- a/tests/unit/model/lifecycle-callbacks-test.js +++ b/tests/unit/model/lifecycle-callbacks-test.js @@ -1,1118 +1,298 @@ -import { setupTest } from 'ember-qunit'; -import { module, test } from 'qunit'; -import { settled } from '@ember/test-helpers'; import { resolve, reject } from 'rsvp'; -import { attr } from '@ember-decorators/data'; -import Model from 'ember-data/model'; -import Adapter from 'ember-data/adapter'; -import JSONAPISerializer from 'ember-data/serializers/json-api'; -import { InvalidError } from 'ember-data/adapters/errors'; +import { get } from '@ember/object'; import { run } from '@ember/runloop'; +import { createStore } from 'dummy/tests/helpers/store'; -module('unit/model - Model Lifecycle Callbacks', function(hooks) { - setupTest(hooks); - let store; - - hooks.beforeEach(function() { - store = this.owner.lookup('service:store'); - }); - - test('didLoad() only fires for initial loads, not creates, not reloads', async function(assert) { - let lifecycleEventMethodCalls = 0; - class Person extends Model { - @attr - name; - - didLoad() { - lifecycleEventMethodCalls++; - } - } - this.owner.register('model:person', Person); - this.owner.register('serializer:application', JSONAPISerializer); - - class AppAdapter extends Adapter { - deleteRecord() { - return resolve({ data: null }); - } - createRecord() { - return resolve({ data: { id: '0', type: 'person' } }); - } - updateRecord() { - return resolve({ data: { id: '1', type: 'person' } }); - } - findRecord() { - return resolve({ data: { id: '2', type: 'person', attributes: { name: 'Foo' } } }); - } - } - this.owner.register('adapter:application', AppAdapter); - - // ------ Test Create - - let record = store.createRecord('person', { name: 'Chris' }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didLoad when we create locally' - ); - lifecycleEventMethodCalls = 0; - - await record.save(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didLoad when we save after we create locally' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Update - - record = store.push({ - data: { - id: '1', - type: 'person', - attributes: { - name: 'James', - }, - }, - }); - assert.strictEqual(lifecycleEventMethodCalls, 1, 'We trigger didLoad when we push'); - lifecycleEventMethodCalls = 0; - - record.set('name', 'Chris'); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didLoad when we mutate locally' - ); - lifecycleEventMethodCalls = 0; - - await record.save(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didLoad when we save after we mutate locally' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Find - - record = await store.findRecord('person', '2'); - assert.strictEqual( - lifecycleEventMethodCalls, - 1, - 'We trigger didLoad when we first find a record' - ); - lifecycleEventMethodCalls = 0; - await record.reload(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didLoad when we reload a record' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Push - - store.push({ - data: { - id: '3', - type: 'person', - attributes: { - name: 'James', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 1, - 'We trigger didLoad when we first pushed a record' - ); - lifecycleEventMethodCalls = 0; - - store.push({ - data: { - id: '3', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didLoad when push updates to an existing same record' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Push with Lazy Materialization of Record - - store._push({ - data: { - id: '4', - type: 'person', - attributes: { - name: 'James', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didLoad when we first push a record without materializing it' - ); - lifecycleEventMethodCalls = 0; - - store._push({ - data: { - id: '4', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didLoad when push updates to an existing non-materialized record' - ); - lifecycleEventMethodCalls = 0; - - store.peekRecord('person', '4'); - assert.strictEqual( - lifecycleEventMethodCalls, - 1, - 'We trigger didLoad when we first materialize a record' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Deletion of Record - - record = store.push({ - data: { - id: '5', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual(lifecycleEventMethodCalls, 1, 'We trigger didLoad on push'); - lifecycleEventMethodCalls = 0; - - record.deleteRecord(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didLoad when we first call record.deleteRecord' - ); - lifecycleEventMethodCalls = 0; - - await record.save(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didLoad once we have saved the deletion' - ); - lifecycleEventMethodCalls = 0; +import { module, test } from 'qunit'; - // ------ Test Unloading of Record +import DS from 'ember-data'; - record = store.push({ - data: { - id: '6', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual(lifecycleEventMethodCalls, 1, 'We trigger didLoad on push'); - lifecycleEventMethodCalls = 0; +module('unit/model/lifecycle_callbacks - Lifecycle Callbacks'); - record.unloadRecord(); - await settled(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didLoad when we unload a record' - ); - lifecycleEventMethodCalls = 0; +test('a record receives a didLoad callback when it has finished loading', function(assert) { + assert.expect(3); - record = store.push({ - data: { - id: '6', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 1, - 'We trigger didLoad when we push a previously unloaded record' - ); + const Person = DS.Model.extend({ + name: DS.attr(), + didLoad() { + assert.ok('The didLoad callback was called'); + }, }); - test('didUpdate() only fires for persisted updates', async function(assert) { - let lifecycleEventMethodCalls = 0; - class Person extends Model { - @attr - name; - - didUpdate() { - lifecycleEventMethodCalls++; - assert.equal(this.get('isSaving'), false, 'record should not be saving'); - assert.equal(this.get('hasDirtyAttributes'), false, 'record should not be dirty'); - } - } - this.owner.register('model:person', Person); - this.owner.register('serializer:application', JSONAPISerializer); - - class AppAdapter extends Adapter { - deleteRecord() { - return resolve({ data: null }); - } - createRecord() { - return resolve({ data: { id: '0', type: 'person' } }); - } - updateRecord() { - return resolve({ data: { id: '1', type: 'person' } }); - } - findRecord() { - return resolve({ data: { id: '2', type: 'person', attributes: { name: 'Foo' } } }); - } - } - this.owner.register('adapter:application', AppAdapter); - - // ------ Test Create - - let record = store.createRecord('person', { name: 'Chris' }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didUpdate when we create locally' - ); - lifecycleEventMethodCalls = 0; - - await record.save(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didUpdate when we save after we create locally' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Update - - record = store.push({ - data: { - id: '1', - type: 'person', - attributes: { - name: 'James', - }, - }, - }); - assert.strictEqual(lifecycleEventMethodCalls, 0, 'We do not trigger didUpdate when we push'); - lifecycleEventMethodCalls = 0; - - record.set('name', 'Chris'); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didUpdate when we mutate locally' - ); - lifecycleEventMethodCalls = 0; - - await record.save(); - assert.strictEqual( - lifecycleEventMethodCalls, - 1, - 'We trigger didUpdate when we save after we mutate locally' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Find - - record = await store.findRecord('person', '2'); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didUpdate when we first find a record' - ); - lifecycleEventMethodCalls = 0; - await record.reload(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didUpdate when we reload a record' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Push - - store.push({ - data: { - id: '3', - type: 'person', - attributes: { - name: 'James', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didUpdate when we first pushed a record' - ); - lifecycleEventMethodCalls = 0; - - store.push({ - data: { - id: '3', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didUpdate when push updates to an existing same record' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Push with Lazy Materialization of Record - - store._push({ - data: { - id: '4', - type: 'person', - attributes: { - name: 'James', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didUpdate when we first push a record without materializing it' - ); - lifecycleEventMethodCalls = 0; - - store._push({ - data: { - id: '4', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didUpdate when push updates to an existing non-materialized record' - ); - lifecycleEventMethodCalls = 0; - - store.peekRecord('person', '4'); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didUpdate when we first materialize a record' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Deletion of Record - - record = store.push({ - data: { - id: '5', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual(lifecycleEventMethodCalls, 0, 'We do not trigger didUpdate on push'); - lifecycleEventMethodCalls = 0; - - record.deleteRecord(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didUpdate when we first call record.deleteRecord' - ); - lifecycleEventMethodCalls = 0; - - await record.save(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didUpdate once we have saved the deletion' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Unloading of Record - - record = store.push({ - data: { - id: '6', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual(lifecycleEventMethodCalls, 0, 'We do not trigger didUpdate on push'); - lifecycleEventMethodCalls = 0; - - record.unloadRecord(); - await settled(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didUpdate when we unload a record' - ); - lifecycleEventMethodCalls = 0; - - record = store.push({ - data: { - id: '6', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didUpdate when we push a previously unloaded record' - ); + const Adapter = DS.Adapter.extend({ + findRecord(store, type, id, snapshot) { + return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; + }, }); - test('didCreate() only fires for persisted creates', async function(assert) { - let lifecycleEventMethodCalls = 0; - class Person extends Model { - @attr - name; - - didCreate() { - lifecycleEventMethodCalls++; - assert.equal(this.get('isSaving'), false, 'record should not be saving'); - assert.equal(this.get('hasDirtyAttributes'), false, 'record should not be dirty'); - } - } - this.owner.register('model:person', Person); - this.owner.register('serializer:application', JSONAPISerializer); - - class AppAdapter extends Adapter { - deleteRecord() { - return resolve({ data: null }); - } - createRecord() { - assert.equal( - lifecycleEventMethodCalls, - 0, - 'didCreate callback was not called before adapter.createRecord resolves' - ); - return resolve({ data: { id: '0', type: 'person' } }); - } - updateRecord() { - return resolve({ data: { id: '1', type: 'person' } }); - } - findRecord() { - return resolve({ data: { id: '2', type: 'person', attributes: { name: 'Foo' } } }); - } - } - this.owner.register('adapter:application', AppAdapter); - - // ------ Test Create - - let record = store.createRecord('person', { name: 'Chris' }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didCreate when we create locally' - ); - lifecycleEventMethodCalls = 0; - - await record.save(); - assert.strictEqual( - lifecycleEventMethodCalls, - 1, - 'We trigger didCreate when we save after we create locally' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Update - - record = store.push({ - data: { - id: '1', - type: 'person', - attributes: { - name: 'James', - }, - }, - }); - assert.strictEqual(lifecycleEventMethodCalls, 0, 'We do not trigger didCreate when we push'); - lifecycleEventMethodCalls = 0; - - record.set('name', 'Chris'); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didCreate when we mutate locally' - ); - lifecycleEventMethodCalls = 0; - - await record.save(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didCreate when we save after we mutate locally' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Find - - record = await store.findRecord('person', '2'); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didCreate when we first find a record' - ); - lifecycleEventMethodCalls = 0; - await record.reload(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didCreate when we reload a record' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Push - - store.push({ - data: { - id: '3', - type: 'person', - attributes: { - name: 'James', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didCreate when we first push a record' - ); - lifecycleEventMethodCalls = 0; + let store = createStore({ + adapter: Adapter, + person: Person, + }); - store.push({ - data: { - id: '3', - type: 'person', - attributes: { - name: 'Chris', - }, - }, + return run(() => { + return store.findRecord('person', 1).then(person => { + assert.equal(person.get('id'), '1', `The person's ID is available`); + assert.equal(person.get('name'), 'Foo', `The person's properties are availablez`); }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didCreate when push updates to an existing record' - ); - lifecycleEventMethodCalls = 0; + }); +}); - // ------ Test Push with Lazy Materialization of Record +test(`TEMPORARY: a record receives a didLoad callback once it materializes if it wasn't materialized when loaded`, function(assert) { + assert.expect(2); + let didLoadCalled = 0; + const Person = DS.Model.extend({ + name: DS.attr(), + didLoad() { + didLoadCalled++; + }, + }); - store._push({ - data: { - id: '4', - type: 'person', - attributes: { - name: 'James', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didCreate when we first push a record without materializing it' - ); - lifecycleEventMethodCalls = 0; + let store = createStore({ + person: Person, + }); - store._push({ - data: { - id: '4', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didCreate when push updates to an existing non-materialized record' - ); - lifecycleEventMethodCalls = 0; + run(() => { + store._pushInternalModel({ id: 1, type: 'person' }); + assert.equal(didLoadCalled, 0, 'didLoad was not called'); + }); + run(() => store.peekRecord('person', 1)); + assert.equal(didLoadCalled, 1, 'didLoad was called'); +}); - store.peekRecord('person', '4'); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didCreate when we first materialize a record' - ); - lifecycleEventMethodCalls = 0; +test('a record receives a didUpdate callback when it has finished updating', function(assert) { + assert.expect(5); - // ------ Test Deletion of Record + let callCount = 0; - record = store.push({ - data: { - id: '5', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual(lifecycleEventMethodCalls, 0, 'We do not trigger didCreate on push'); - lifecycleEventMethodCalls = 0; + const Person = DS.Model.extend({ + bar: DS.attr('string'), + name: DS.attr('string'), - record.deleteRecord(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didCreate when we first call record.deleteRecord' - ); - lifecycleEventMethodCalls = 0; + didUpdate() { + callCount++; + assert.equal(get(this, 'isSaving'), false, 'record should be saving'); + assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); + }, + }); - await record.save(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didCreate once we have saved the deletion' - ); - lifecycleEventMethodCalls = 0; + const Adapter = DS.Adapter.extend({ + findRecord(store, type, id, snapshot) { + return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; + }, - // ------ Test Unloading of Record + updateRecord(store, type, snapshot) { + assert.equal(callCount, 0, 'didUpdate callback was not called until didSaveRecord is called'); - record = store.push({ - data: { - id: '6', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual(lifecycleEventMethodCalls, 0, 'We do not trigger didCreate on push'); - lifecycleEventMethodCalls = 0; + return resolve(); + }, + }); - record.unloadRecord(); - await settled(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didCreate when we unload a record' - ); - lifecycleEventMethodCalls = 0; + let store = createStore({ + adapter: Adapter, + person: Person, + }); - record = store.push({ - data: { - id: '6', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didCreate when we push a previously unloaded record' - ); + let asyncPerson = run(() => store.findRecord('person', 1)); + + assert.equal(callCount, 0, 'precond - didUpdate callback was not called yet'); + + return run(() => { + return asyncPerson + .then(person => { + return run(() => { + person.set('bar', 'Bar'); + return person.save(); + }); + }) + .then(() => { + assert.equal(callCount, 1, 'didUpdate called after update'); + }); }); +}); - test('didDelete() only fires for persisted deletions', async function(assert) { - let lifecycleEventMethodCalls = 0; - class Person extends Model { - @attr - name; +test('a record receives a didCreate callback when it has finished updating', function(assert) { + assert.expect(5); - didDelete() { - lifecycleEventMethodCalls++; - assert.equal(this.get('isSaving'), false, 'record should not be saving'); - assert.equal(this.get('hasDirtyAttributes'), false, 'record should not be dirty'); - } - } - this.owner.register('model:person', Person); - this.owner.register('serializer:application', JSONAPISerializer); + let callCount = 0; - class AppAdapter extends Adapter { - deleteRecord() { - assert.equal( - lifecycleEventMethodCalls, - 0, - 'didDelete callback was not called before adapter.deleteRecord resolves' - ); - return resolve({ data: null }); - } - createRecord() { - return resolve({ data: { id: '0', type: 'person' } }); - } - updateRecord() { - return resolve({ data: { id: '1', type: 'person' } }); - } - findRecord() { - return resolve({ data: { id: '2', type: 'person', attributes: { name: 'Foo' } } }); - } - } - this.owner.register('adapter:application', AppAdapter); + const Person = DS.Model.extend({ + didCreate() { + callCount++; + assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); + assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); + }, + }); - // ------ Test Create + const Adapter = DS.Adapter.extend({ + createRecord(store, type, snapshot) { + assert.equal(callCount, 0, 'didCreate callback was not called until didSaveRecord is called'); - let record = store.createRecord('person', { name: 'Chris' }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when we create locally' - ); - lifecycleEventMethodCalls = 0; + return resolve(); + }, + }); - await record.save(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when we save after we create locally' - ); - lifecycleEventMethodCalls = 0; + let store = createStore({ + adapter: Adapter, + person: Person, + }); - // ------ Test Update + assert.equal(callCount, 0, 'precond - didCreate callback was not called yet'); + let person = store.createRecord('person', { id: 69, name: 'Newt Gingrich' }); - record = store.push({ - data: { - id: '1', - type: 'person', - attributes: { - name: 'James', - }, - }, + return run(() => { + return person.save().then(() => { + assert.equal(callCount, 1, 'didCreate called after commit'); }); - assert.strictEqual(lifecycleEventMethodCalls, 0, 'We do not trigger didDelete when we push'); - lifecycleEventMethodCalls = 0; - - record.set('name', 'Chris'); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when we mutate locally' - ); - lifecycleEventMethodCalls = 0; - - await record.save(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when we save after we mutate locally' - ); - lifecycleEventMethodCalls = 0; - - // ------ Test Find - - record = await store.findRecord('person', '2'); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when we first find a record' - ); - lifecycleEventMethodCalls = 0; - await record.reload(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when we reload a record' - ); - lifecycleEventMethodCalls = 0; + }); +}); - // ------ Test Push +test('a record receives a didDelete callback when it has finished deleting', function(assert) { + assert.expect(5); - store.push({ - data: { - id: '3', - type: 'person', - attributes: { - name: 'James', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when we first push a record' - ); - lifecycleEventMethodCalls = 0; + let callCount = 0; - store.push({ - data: { - id: '3', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when push updates to an existing record' - ); - lifecycleEventMethodCalls = 0; + const Person = DS.Model.extend({ + bar: DS.attr('string'), + name: DS.attr('string'), - // ------ Test Push with Lazy Materialization of Record + didDelete() { + callCount++; - store._push({ - data: { - id: '4', - type: 'person', - attributes: { - name: 'James', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when we first push a record without materializing it' - ); - lifecycleEventMethodCalls = 0; + assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); + assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); + }, + }); - store._push({ - data: { - id: '4', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when push updates to an existing non-materialized record' - ); - lifecycleEventMethodCalls = 0; + const Adapter = DS.Adapter.extend({ + findRecord(store, type, id, snapshot) { + return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; + }, - store.peekRecord('person', '4'); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when we first materialize a record' - ); - lifecycleEventMethodCalls = 0; + deleteRecord(store, type, snapshot) { + assert.equal(callCount, 0, 'didDelete callback was not called until didSaveRecord is called'); - // ------ Test Deletion of Record + return resolve(); + }, + }); - record = store.push({ - data: { - id: '5', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - record.deleteRecord(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when we first call record.deleteRecord' - ); - lifecycleEventMethodCalls = 0; + let store = createStore({ + adapter: Adapter, + person: Person, + }); + let asyncPerson = run(() => store.findRecord('person', 1)); + + assert.equal(callCount, 0, 'precond - didDelete callback was not called yet'); + + return run(() => { + return asyncPerson + .then(person => { + return run(() => { + person.deleteRecord(); + return person.save(); + }); + }) + .then(() => { + assert.equal(callCount, 1, 'didDelete called after delete'); + }); + }); +}); - await record.save(); - assert.strictEqual( - lifecycleEventMethodCalls, - 1, - 'We trigger didDelete once we have saved the deletion' - ); - lifecycleEventMethodCalls = 0; +test('an uncommited record also receives a didDelete callback when it is deleted', function(assert) { + assert.expect(4); - // ------ Test Unloading of Record + let callCount = 0; - record = store.push({ - data: { - id: '6', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - record.unloadRecord(); - await settled(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when we unload a record' - ); - lifecycleEventMethodCalls = 0; + const Person = DS.Model.extend({ + bar: DS.attr('string'), + name: DS.attr('string'), - record = store.push({ - data: { - id: '6', - type: 'person', - attributes: { - name: 'Chris', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when we reload a previously unloaded record' - ); + didDelete() { + callCount++; + assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); + assert.equal(get(this, 'hasDirtyAttributes'), false, 'record should not be dirty'); + }, }); - test('didDelete() triggers for uncommitted records when the deletion is persisted', async function(assert) { - let lifecycleEventMethodCalls = 0; - class Person extends Model { - @attr - name; - - didDelete() { - lifecycleEventMethodCalls++; - assert.equal(this.get('isSaving'), false, 'record should not be saving'); - assert.equal(this.get('hasDirtyAttributes'), false, 'record should not be dirty'); - } - } - this.owner.register('model:person', Person); - this.owner.register('serializer:application', JSONAPISerializer); - - class AppAdapter extends Adapter { - deleteRecord() { - assert.equal( - lifecycleEventMethodCalls, - 0, - 'didDelete callback was not called before adapter.deleteRecord resolves' - ); - return resolve({ data: null }); - } - } - this.owner.register('adapter:application', AppAdapter); + let store = createStore({ + adapter: DS.Adapter.extend(), + person: Person, + }); - // ------ Test Deletion of Record + let person = store.createRecord('person', { name: 'Tomster' }); - let record = store.createRecord('person', { name: 'Tomster' }); + assert.equal(callCount, 0, 'precond - didDelete callback was not called yet'); - record.deleteRecord(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when we first call record.deleteRecord' - ); - lifecycleEventMethodCalls = 0; + run(() => person.deleteRecord()); - await settled(); - assert.strictEqual( - lifecycleEventMethodCalls, - 1, - 'We trigger didDelete when we first call record.deleteRecord' - ); - lifecycleEventMethodCalls = 0; + assert.equal(callCount, 1, 'didDelete called after delete'); +}); - await record.save(); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete once we have saved the deletion, as we secretly did previously' - ); - lifecycleEventMethodCalls = 0; +test('a record receives a becameInvalid callback when it became invalid', function(assert) { + assert.expect(8); - // ------ Test Unloading of Record + let callCount = 0; - record = store.createRecord('person', { name: 'Tomster' }); + const Person = DS.Model.extend({ + bar: DS.attr('string'), + name: DS.attr('string'), - // ideally we could `await settled()` but Ember 2.18 does not handle `destroy()` calls in this case. - run(() => record.unloadRecord()); + becameInvalid() { + callCount++; - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger didDelete when we unload a record' - ); + assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); + assert.equal(get(this, 'hasDirtyAttributes'), true, 'record should be dirty'); + }, }); - test('becameInvalid() triggers when an update rejects with an error for a member', async function(assert) { - let lifecycleEventMethodCalls = 0; - class Person extends Model { - @attr - name; + const Adapter = DS.Adapter.extend({ + findRecord(store, type, id, snapshot) { + return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; + }, - becameInvalid() { - lifecycleEventMethodCalls++; - assert.equal(this.get('isSaving'), false, 'record should not be saving'); - assert.equal(this.get('hasDirtyAttributes'), true, 'record should not be dirty'); - } - } - this.owner.register('model:person', Person); - this.owner.register('serializer:application', JSONAPISerializer); + updateRecord(store, type, snapshot) { + assert.equal( + callCount, + 0, + 'becameInvalid callback was not called until recordWasInvalid is called' + ); - class AppAdapter extends Adapter { - updateRecord() { - assert.equal( - lifecycleEventMethodCalls, - 0, - 'becameInvalid callback was not called before adapter.updateRecord resolves' - ); - let error = new InvalidError([ + return reject( + new DS.InvalidError([ { title: 'Invalid Attribute', detail: 'error', source: { - pointer: '/data/attributes/name', + pointer: '/data/attributes/bar', }, }, - ]); - - return reject(error); - } - } - this.owner.register('adapter:application', AppAdapter); - - let person = store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Great Name!', - }, - }, - }); - assert.strictEqual( - lifecycleEventMethodCalls, - 0, - 'We do not trigger becameInvalid when we first push the record to the store' - ); - lifecycleEventMethodCalls = 0; - - person.set('name', 'Bad Bad Name'); + ]) + ); + }, + }); - await person.save().catch(reason => { - assert.strictEqual(lifecycleEventMethodCalls, 1, 'We trigger becameInvalid when we reject'); + let store = createStore({ + adapter: Adapter, + person: Person, + }); - assert.ok(reason.isAdapterError, 'reason should have been an adapter error'); - assert.equal(reason.errors.length, 1, 'reason should have one error'); - assert.equal(reason.errors[0].title, 'Invalid Attribute'); + let asyncPerson = run(() => store.findRecord('person', 1)); + assert.equal(callCount, 0, 'precond - becameInvalid callback was not called yet'); + + // Make sure that the error handler has a chance to attach before + // save fails. + return run(() => { + return asyncPerson.then(person => { + return run(() => { + person.set('bar', 'Bar'); + return person.save().catch(reason => { + assert.ok(reason.isAdapterError, 'reason should have been an adapter error'); + + assert.equal(reason.errors.length, 1, 'reason should have one error'); + assert.equal(reason.errors[0].title, 'Invalid Attribute'); + assert.equal(callCount, 1, 'becameInvalid called after invalidating'); + }); + }); }); }); }); diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index 867b2f9d55e..644fbd121eb 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -293,40 +293,37 @@ test('Calling push with a normalized hash containing IDs of related records retu }; return run(() => { - let person = store.push( - store.normalize('person', { - id: 'wat', - type: 'person', - attributes: { - 'first-name': 'John', - 'last-name': 'Smith', - }, - relationships: { - 'phone-numbers': { - data: [{ id: 1, type: 'phone-number' }, { id: 2, type: 'phone-number' }], - }, + let normalized = store.normalize('person', { + id: 'wat', + type: 'person', + attributes: { + 'first-name': 'John', + 'last-name': 'Smith', + }, + relationships: { + 'phone-numbers': { + data: [{ id: 1, type: 'phone-number' }, { id: 2, type: 'phone-number' }], }, - }) - ); + }, + }); + let person = store.push(normalized); return person.get('phoneNumbers').then(phoneNumbers => { - assert.deepEqual( - phoneNumbers.map(item => { - return item.getProperties('id', 'number', 'person'); - }), - [ - { - id: '1', - number: '5551212', - person: person, - }, - { - id: '2', - number: '5552121', - person: person, - }, - ] - ); + let items = phoneNumbers.map(item => { + return item ? item.getProperties('id', 'number', 'person') : null; + }); + assert.deepEqual(items, [ + { + id: '1', + number: '5551212', + person: person, + }, + { + id: '2', + number: '5552121', + person: person, + }, + ]); }); }); }); From 2a13b3595c81c2caccd1929864bc5fea31961ab0 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 6 Nov 2018 00:32:06 -0800 Subject: [PATCH 2411/2527] [CHORE tests] does a partial refactor of the unload tests to eliminate setupStore --- tests/integration/records/unload-test.js | 4899 +++++++++-------- .../relationships/belongs-to-test.js | 4 - .../relationships/has-many-test.js | 4 - 3 files changed, 2471 insertions(+), 2436 deletions(-) diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index 671ca5f30cf..0b5f1d5bcd1 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -5,7 +5,7 @@ import { get } from '@ember/object'; import { run } from '@ember/runloop'; import { module, test } from 'qunit'; import DS from 'ember-data'; -import setupStore from 'dummy/tests/helpers/store'; +import { setupTest } from 'ember-qunit'; import { recordDataFor } from 'ember-data/-private'; function idsFromOrderedSet(set) { @@ -14,9 +14,7 @@ function idsFromOrderedSet(set) { const { attr, belongsTo, hasMany, Model } = DS; -let env; - -let Person = Model.extend({ +const Person = Model.extend({ name: attr('string'), // 1:many sync cars: hasMany('car', { async: false }), @@ -49,7 +47,7 @@ Person.reopenClass({ }, }); -let House = Model.extend({ +const House = Model.extend({ person: belongsTo('person', { async: false }), }); House.reopenClass({ @@ -58,7 +56,7 @@ House.reopenClass({ }, }); -let Mortgage = Model.extend({ +const Mortgage = Model.extend({ person: belongsTo('person', { async: true }), }); Mortgage.reopenClass({ @@ -67,7 +65,7 @@ Mortgage.reopenClass({ }, }); -let Group = Model.extend({ +const Group = Model.extend({ people: hasMany('person', { async: false }), }); Group.reopenClass({ @@ -76,7 +74,7 @@ Group.reopenClass({ }, }); -let Car = Model.extend({ +const Car = Model.extend({ make: attr('string'), model: attr('string'), person: belongsTo('person', { async: false }), @@ -87,7 +85,7 @@ Car.reopenClass({ }, }); -let Boat = Model.extend({ +const Boat = Model.extend({ name: attr('string'), person: belongsTo('person', { async: true }), }); @@ -95,2868 +93,2913 @@ Boat.toString = function() { return 'Boat'; }; -let Bike = Model.extend({ +const Bike = Model.extend({ name: DS.attr(), }); Bike.toString = function() { return 'Bike'; }; -let Book = Model.extend({ +const Book = Model.extend({ person: belongsTo('person', { async: true }), }); Book.toString = function() { return 'Book'; }; -let Spoon = Model.extend({ +const Spoon = Model.extend({ person: belongsTo('person', { async: true }), }); Spoon.toString = function() { return 'Spoon'; }; -let Show = Model.extend({ +const Show = Model.extend({ person: belongsTo('person', { async: false }), }); Show.toString = function() { return 'Show'; }; -module('integration/unload - Unloading Records', { - beforeEach() { - env = setupStore({ - adapter: DS.JSONAPIAdapter, - person: Person, - car: Car, - group: Group, - house: House, - mortgage: Mortgage, - boat: Boat, - bike: Bike, - book: Book, - spoon: Spoon, - show: Show, - }); - }, +module('integration/unload - Unloading Records', function(hooks) { + setupTest(hooks); + let store, adapter; + + hooks.beforeEach(function() { + let { owner } = this; + + owner.register(`model:person`, Person); + owner.register(`model:car`, Car); + owner.register(`model:group`, Group); + owner.register(`model:house`, House); + owner.register(`model:mortgage`, Mortgage); + owner.register(`model:boat`, Boat); + owner.register(`model:bike`, Bike); + owner.register(`model:book`, Book); + owner.register(`model:spoon`, Spoon); + owner.register(`model:show`, Show); + + store = owner.lookup('service:store'); + adapter = store.adapterFor('application'); + }); - afterEach() { + test('can unload a single record', function(assert) { + let adam; run(function() { - env.container.destroy(); - }); - }, -}); - -test('can unload a single record', function(assert) { - let adam; - run(function() { - env.store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland', - }, - relationships: { - cars: { - data: [ - { - id: 1, - type: 'car', - }, - ], + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', }, - boats: { - data: [ - { - id: 2, - type: 'boat', - }, - ], + relationships: { + cars: { + data: [ + { + id: 1, + type: 'car', + }, + ], + }, + boats: { + data: [ + { + id: 2, + type: 'boat', + }, + ], + }, }, }, - }, + }); + adam = store.peekRecord('person', 1); }); - adam = env.store.peekRecord('person', 1); - }); - assert.equal(env.store.peekAll('person').get('length'), 1, 'one person record loaded'); - assert.equal(env.store._internalModelsFor('person').length, 1, 'one person internalModel loaded'); + assert.equal(store.peekAll('person').get('length'), 1, 'one person record loaded'); + assert.equal(store._internalModelsFor('person').length, 1, 'one person internalModel loaded'); + + run(function() { + adam.unloadRecord(); + }); - run(function() { - adam.unloadRecord(); + assert.equal(store.peekAll('person').get('length'), 0, 'no person records'); + assert.equal(store._internalModelsFor('person').length, 0, 'no person internalModels'); }); - assert.equal(env.store.peekAll('person').get('length'), 0, 'no person records'); - assert.equal(env.store._internalModelsFor('person').length, 0, 'no person internalModels'); -}); + test('can unload all records for a given type', function(assert) { + assert.expect(10); -test('can unload all records for a given type', function(assert) { - assert.expect(10); + let adam, bob, dudu, car; + run(function() { + store.push({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Bob Bobson', + }, + }, + ], + }); + adam = store.peekRecord('person', 1); + bob = store.peekRecord('person', 2); - let adam, bob, dudu, car; - run(function() { - env.store.push({ - data: [ - { - type: 'person', + car = store.push({ + data: { + type: 'car', id: '1', attributes: { - name: 'Adam Sunderland', + make: 'VW', + model: 'Beetle', }, - }, - { - type: 'person', - id: '2', - attributes: { - name: 'Bob Bobson', + relationships: { + person: { + data: { type: 'person', id: '1' }, + }, }, }, - ], + }); + dudu = bob = store.peekRecord('car', 1); }); - adam = env.store.peekRecord('person', 1); - bob = env.store.peekRecord('person', 2); - car = env.store.push({ - data: { - type: 'car', - id: '1', - attributes: { - make: 'VW', - model: 'Beetle', - }, - relationships: { - person: { - data: { type: 'person', id: '1' }, - }, - }, - }, + assert.equal(store.peekAll('person').get('length'), 2, 'two person records loaded'); + assert.equal(store._internalModelsFor('person').length, 2, 'two person internalModels loaded'); + assert.equal(store.peekAll('car').get('length'), 1, 'one car record loaded'); + assert.equal(store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); + + run(function() { + car.get('person'); + store.unloadAll('person'); }); - dudu = bob = env.store.peekRecord('car', 1); - }); - assert.equal(env.store.peekAll('person').get('length'), 2, 'two person records loaded'); - assert.equal( - env.store._internalModelsFor('person').length, - 2, - 'two person internalModels loaded' - ); - assert.equal(env.store.peekAll('car').get('length'), 1, 'one car record loaded'); - assert.equal(env.store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); - - run(function() { - car.get('person'); - env.store.unloadAll('person'); - }); + assert.equal(store.peekAll('person').get('length'), 0); + assert.equal(store.peekAll('car').get('length'), 1); + assert.equal(store._internalModelsFor('person').length, 0, 'zero person internalModels loaded'); + assert.equal(store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); - assert.equal(env.store.peekAll('person').get('length'), 0); - assert.equal(env.store.peekAll('car').get('length'), 1); - assert.equal( - env.store._internalModelsFor('person').length, - 0, - 'zero person internalModels loaded' - ); - assert.equal(env.store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); - - run(function() { - env.store.push({ - data: { - id: 1, - type: 'person', - attributes: { - name: 'Richard II', + run(function() { + store.push({ + data: { + id: 1, + type: 'person', + attributes: { + name: 'Richard II', + }, }, - }, + }); }); - }); - car = env.store.peekRecord('car', 1); - let person = car.get('person'); + car = store.peekRecord('car', 1); + let person = car.get('person'); - assert.ok(!!car, 'We have a car'); - assert.ok(!person, 'We dont have a person'); + assert.ok(!!car, 'We have a car'); + assert.ok(!person, 'We dont have a person'); - /* + /* @runspired believes these asserts were incorrect on master. Basically, we intentionally treat unload on a sync belongsTo as client-side delete bc "bad reason" of legacy support for the mis-use of unloadRecord. - Because of this, there should be no way to resurrect the relationship without receiving new relationship info which does not occur in this test. - He checked how master manages to do this, and discovered bad things. TL;DR because the `person` relationship is never materialized, it's state was not cleared on unload, and thus the client-side delete never happened as intended. */ - // assert.equal(person.get('id'), '1', 'Inverse can load relationship after the record is unloaded'); - // assert.equal(person.get('name'), 'Richard II', 'Inverse can load relationship after the record is unloaded'); -}); + // assert.equal(person.get('id'), '1', 'Inverse can load relationship after the record is unloaded'); + // assert.equal(person.get('name'), 'Richard II', 'Inverse can load relationship after the record is unloaded'); + }); -test('can unload all records', function(assert) { - assert.expect(8); + test('can unload all records', function(assert) { + assert.expect(8); - let adam, bob, dudu; - run(function() { - env.store.push({ - data: [ - { - type: 'person', + let adam, bob, dudu; + run(function() { + store.push({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', + }, + }, + { + type: 'person', + id: '2', + attributes: { + name: 'Bob Bobson', + }, + }, + ], + }); + adam = store.peekRecord('person', 1); + bob = store.peekRecord('person', 2); + + store.push({ + data: { + type: 'car', id: '1', attributes: { - name: 'Adam Sunderland', + make: 'VW', + model: 'Beetle', }, - }, - { - type: 'person', - id: '2', - attributes: { - name: 'Bob Bobson', + relationships: { + person: { + data: { type: 'person', id: '1' }, + }, }, }, - ], + }); + dudu = bob = store.peekRecord('car', 1); }); - adam = env.store.peekRecord('person', 1); - bob = env.store.peekRecord('person', 2); - env.store.push({ - data: { - type: 'car', - id: '1', - attributes: { - make: 'VW', - model: 'Beetle', - }, - relationships: { - person: { - data: { type: 'person', id: '1' }, - }, - }, - }, + assert.equal(store.peekAll('person').get('length'), 2, 'two person records loaded'); + assert.equal(store._internalModelsFor('person').length, 2, 'two person internalModels loaded'); + assert.equal(store.peekAll('car').get('length'), 1, 'one car record loaded'); + assert.equal(store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); + + run(function() { + store.unloadAll(); }); - dudu = bob = env.store.peekRecord('car', 1); - }); - assert.equal(env.store.peekAll('person').get('length'), 2, 'two person records loaded'); - assert.equal( - env.store._internalModelsFor('person').length, - 2, - 'two person internalModels loaded' - ); - assert.equal(env.store.peekAll('car').get('length'), 1, 'one car record loaded'); - assert.equal(env.store._internalModelsFor('car').length, 1, 'one car internalModel loaded'); - - run(function() { - env.store.unloadAll(); + assert.equal(store.peekAll('person').get('length'), 0); + assert.equal(store.peekAll('car').get('length'), 0); + assert.equal(store._internalModelsFor('person').length, 0, 'zero person internalModels loaded'); + assert.equal(store._internalModelsFor('car').length, 0, 'zero car internalModels loaded'); }); - assert.equal(env.store.peekAll('person').get('length'), 0); - assert.equal(env.store.peekAll('car').get('length'), 0); - assert.equal( - env.store._internalModelsFor('person').length, - 0, - 'zero person internalModels loaded' - ); - assert.equal(env.store._internalModelsFor('car').length, 0, 'zero car internalModels loaded'); -}); - -test('removes findAllCache after unloading all records', function(assert) { - assert.expect(4); + test('removes findAllCache after unloading all records', function(assert) { + assert.expect(4); - let adam, bob; - run(function() { - env.store.push({ - data: [ - { - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland', + let adam, bob; + run(function() { + store.push({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', + }, }, - }, - { - type: 'person', - id: '2', - attributes: { - name: 'Bob Bobson', + { + type: 'person', + id: '2', + attributes: { + name: 'Bob Bobson', + }, }, - }, - ], + ], + }); + adam = store.peekRecord('person', 1); + bob = store.peekRecord('person', 2); }); - adam = env.store.peekRecord('person', 1); - bob = env.store.peekRecord('person', 2); - }); - assert.equal(env.store.peekAll('person').get('length'), 2, 'two person records loaded'); - assert.equal( - env.store._internalModelsFor('person').length, - 2, - 'two person internalModels loaded' - ); + assert.equal(store.peekAll('person').get('length'), 2, 'two person records loaded'); + assert.equal(store._internalModelsFor('person').length, 2, 'two person internalModels loaded'); - run(function() { - env.store.peekAll('person'); - env.store.unloadAll('person'); - }); + run(function() { + store.peekAll('person'); + store.unloadAll('person'); + }); - assert.equal(env.store.peekAll('person').get('length'), 0, 'zero person records loaded'); - assert.equal( - env.store._internalModelsFor('person').length, - 0, - 'zero person internalModels loaded' - ); -}); + assert.equal(store.peekAll('person').get('length'), 0, 'zero person records loaded'); + assert.equal(store._internalModelsFor('person').length, 0, 'zero person internalModels loaded'); + }); -test('unloading all records also updates record array from peekAll()', function(assert) { - let adam, bob; - run(function() { - env.store.push({ - data: [ - { - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland', + test('unloading all records also updates record array from peekAll()', function(assert) { + let adam, bob; + run(function() { + store.push({ + data: [ + { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', + }, }, - }, - { - type: 'person', - id: '2', - attributes: { - name: 'Bob Bobson', + { + type: 'person', + id: '2', + attributes: { + name: 'Bob Bobson', + }, }, - }, - ], + ], + }); + adam = store.peekRecord('person', 1); + bob = store.peekRecord('person', 2); }); - adam = env.store.peekRecord('person', 1); - bob = env.store.peekRecord('person', 2); - }); - let all = env.store.peekAll('person'); + let all = store.peekAll('person'); - assert.equal(all.get('length'), 2); + assert.equal(all.get('length'), 2); - run(function() { - env.store.unloadAll('person'); + run(function() { + store.unloadAll('person'); + }); + assert.equal(all.get('length'), 0); }); - assert.equal(all.get('length'), 0); -}); -function makeBoatOneForPersonOne() { - return { - type: 'boat', - id: '1', - attributes: { - name: 'Boaty McBoatface', - }, - relationships: { - person: { - data: { type: 'person', id: '1' }, + function makeBoatOneForPersonOne() { + return { + type: 'boat', + id: '1', + attributes: { + name: 'Boaty McBoatface', }, - }, - }; -} - -test('unloadAll(type) does not leave stranded internalModels in relationships (rediscover via store.push)', function(assert) { - assert.expect(15); + relationships: { + person: { + data: { type: 'person', id: '1' }, + }, + }, + }; + } - let { store } = env; + test('unloadAll(type) does not leave stranded internalModels in relationships (rediscover via store.push)', function(assert) { + assert.expect(15); - let person = run(() => - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Could be Anybody', - }, - relationships: { - boats: { - data: [{ type: 'boat', id: '1' }], + let person = run(() => + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Could be Anybody', + }, + relationships: { + boats: { + data: [{ type: 'boat', id: '1' }], + }, }, }, - }, - included: [makeBoatOneForPersonOne()], - }) - ); - - let boat = store.peekRecord('boat', '1'); - let initialBoatInternalModel = boat._internalModel; - let relationshipState = person.hasMany('boats').hasManyRelationship; - let knownPeople = env.store._internalModelsFor('person'); - let knownBoats = store._internalModelsFor('boat'); - - // ensure we loaded the people and boats - assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); - assert.equal(knownBoats.models.length, 1, 'one boat record is loaded'); - assert.equal(env.store.hasRecordForId('person', '1'), true); - assert.equal(env.store.hasRecordForId('boat', '1'), true); - - // ensure the relationship was established (we reach through the async proxy here) - let peopleBoats = run(() => person.get('boats.content')); - let boatPerson = run(() => boat.get('person.content')); - - assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should be 1'); - assert.equal(relationshipState.members.size, 1, 'members size should be 1'); - assert.ok(get(peopleBoats, 'length') === 1, 'Our person has a boat'); - assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat'); - assert.ok(boatPerson === person, 'Our boat has the right person'); - - run(() => { - store.unloadAll('boat'); - }); + included: [makeBoatOneForPersonOne()], + }) + ); - // ensure that our new state is correct - assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); - assert.equal(knownBoats.models.length, 0, 'no boat records are loaded'); - assert.equal( - relationshipState.canonicalMembers.size, - 1, - 'canonical member size should still be 1' - ); - assert.equal(relationshipState.members.size, 1, 'members size should still be 1'); - assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats'); - - run(() => - store.push({ - data: makeBoatOneForPersonOne(), - }) - ); - - let reloadedBoat = store.peekRecord('boat', '1'); - let reloadedBoatInternalModel = reloadedBoat._internalModel; - - assert.ok( - reloadedBoatInternalModel === initialBoatInternalModel, - 'after an unloadAll, subsequent fetch results in the same InternalModel' - ); -}); + let boat = store.peekRecord('boat', '1'); + let initialBoatInternalModel = boat._internalModel; + let relationshipState = person.hasMany('boats').hasManyRelationship; + let knownPeople = store._internalModelsFor('person'); + let knownBoats = store._internalModelsFor('boat'); + + // ensure we loaded the people and boats + assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); + assert.equal(knownBoats.models.length, 1, 'one boat record is loaded'); + assert.equal(store.hasRecordForId('person', '1'), true); + assert.equal(store.hasRecordForId('boat', '1'), true); + + // ensure the relationship was established (we reach through the async proxy here) + let peopleBoats = run(() => person.get('boats.content')); + let boatPerson = run(() => boat.get('person.content')); + + assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should be 1'); + assert.equal(relationshipState.members.size, 1, 'members size should be 1'); + assert.ok(get(peopleBoats, 'length') === 1, 'Our person has a boat'); + assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat'); + assert.ok(boatPerson === person, 'Our boat has the right person'); + + run(() => { + store.unloadAll('boat'); + }); -test('unloadAll(type) does not leave stranded internalModels in relationships (rediscover via relationship reload)', function(assert) { - assert.expect(17); + // ensure that our new state is correct + assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); + assert.equal(knownBoats.models.length, 0, 'no boat records are loaded'); + assert.equal( + relationshipState.canonicalMembers.size, + 1, + 'canonical member size should still be 1' + ); + assert.equal(relationshipState.members.size, 1, 'members size should still be 1'); + assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats'); - let { store } = env; + run(() => + store.push({ + data: makeBoatOneForPersonOne(), + }) + ); - env.adapter.findRecord = (store, type, id) => { - assert.ok(type.modelName === 'boat', 'We refetch the boat'); - assert.ok(id === '1', 'We refetch the right boat'); - return resolve({ - data: makeBoatOneForPersonOne(), - }); - }; + let reloadedBoat = store.peekRecord('boat', '1'); + let reloadedBoatInternalModel = reloadedBoat._internalModel; - let person = run(() => - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Could be Anybody', - }, - relationships: { - boats: { - data: [{ type: 'boat', id: '1' }], - }, - }, - }, - included: [makeBoatOneForPersonOne()], - }) - ); - - let boat = store.peekRecord('boat', '1'); - let initialBoatInternalModel = boat._internalModel; - let relationshipState = person.hasMany('boats').hasManyRelationship; - let knownPeople = env.store._internalModelsFor('person'); - let knownBoats = store._internalModelsFor('boat'); - - // ensure we loaded the people and boats - assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); - assert.equal(knownBoats.models.length, 1, 'one boat record is loaded'); - assert.equal(env.store.hasRecordForId('person', '1'), true); - assert.equal(env.store.hasRecordForId('boat', '1'), true); - - // ensure the relationship was established (we reach through the async proxy here) - let peopleBoats = run(() => person.get('boats.content')); - let boatPerson = run(() => boat.get('person.content')); - - assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should be 1'); - assert.equal(relationshipState.members.size, 1, 'members size should be 1'); - assert.ok(get(peopleBoats, 'length') === 1, 'Our person has a boat'); - assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat'); - assert.ok(boatPerson === person, 'Our boat has the right person'); - - run(() => { - store.unloadAll('boat'); + assert.ok( + reloadedBoatInternalModel === initialBoatInternalModel, + 'after an unloadAll, subsequent fetch results in the same InternalModel' + ); }); - // ensure that our new state is correct - assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); - assert.equal(knownBoats.models.length, 0, 'no boat records are loaded'); - assert.equal( - relationshipState.canonicalMembers.size, - 1, - 'canonical member size should still be 1' - ); - assert.equal(relationshipState.members.size, 1, 'members size should still be 1'); - assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats'); - - run(() => person.get('boats')); - - let reloadedBoat = store.peekRecord('boat', '1'); - let reloadedBoatInternalModel = reloadedBoat._internalModel; - - assert.ok( - reloadedBoatInternalModel === initialBoatInternalModel, - 'after an unloadAll, subsequent fetch results in the same InternalModel' - ); -}); + test('unloadAll(type) does not leave stranded internalModels in relationships (rediscover via relationship reload)', function(assert) { + assert.expect(17); -test('(regression) unloadRecord followed by push in the same run-loop', function(assert) { - let { store } = env; + adapter.findRecord = (store, type, id) => { + assert.ok(type.modelName === 'boat', 'We refetch the boat'); + assert.ok(id === '1', 'We refetch the right boat'); + return resolve({ + data: makeBoatOneForPersonOne(), + }); + }; - let person = run(() => - store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Could be Anybody', - }, - relationships: { - boats: { - data: [{ type: 'boat', id: '1' }], + let person = run(() => + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Could be Anybody', + }, + relationships: { + boats: { + data: [{ type: 'boat', id: '1' }], + }, }, }, - }, - included: [makeBoatOneForPersonOne()], - }) - ); - - let boat = store.peekRecord('boat', '1'); - let initialBoatInternalModel = boat._internalModel; - let relationshipState = person.hasMany('boats').hasManyRelationship; - let knownPeople = env.store._internalModelsFor('person'); - let knownBoats = store._internalModelsFor('boat'); - - // ensure we loaded the people and boats - assert.deepEqual(knownPeople.models.map(m => m.id), ['1'], 'one person record is loaded'); - assert.deepEqual(knownBoats.models.map(m => m.id), ['1'], 'one boat record is loaded'); - assert.equal(env.store.hasRecordForId('person', '1'), true); - assert.equal(env.store.hasRecordForId('boat', '1'), true); - - // ensure the relationship was established (we reach through the async proxy here) - let peopleBoats = run(() => person.get('boats.content')); - let boatPerson = run(() => boat.get('person.content')); - - assert.deepEqual( - idsFromOrderedSet(relationshipState.canonicalMembers), - ['1'], - 'canonical member size should be 1' - ); - assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should be 1'); - assert.ok(get(peopleBoats, 'length') === 1, 'Our person has a boat'); - assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat'); - assert.ok(boatPerson === person, 'Our boat has the right person'); - - run(() => boat.unloadRecord()); - - // ensure that our new state is correct - assert.deepEqual(knownPeople.models.map(m => m.id), ['1'], 'one person record is loaded'); - assert.deepEqual(knownBoats.models.map(m => m.id), ['1'], 'one boat record is known'); - assert.ok(knownBoats.models[0] === initialBoatInternalModel, 'We still have our boat'); - assert.equal(initialBoatInternalModel.isEmpty(), true, 'Model is in the empty state'); - assert.deepEqual( - idsFromOrderedSet(relationshipState.canonicalMembers), - ['1'], - 'canonical member size should still be 1' - ); - assert.deepEqual( - idsFromOrderedSet(relationshipState.members), - ['1'], - 'members size should still be 1' - ); - assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats'); - - run(() => - store.push({ - data: makeBoatOneForPersonOne(), - }) - ); - - let reloadedBoat = store.peekRecord('boat', '1'); - let reloadedBoatInternalModel = reloadedBoat._internalModel; - - assert.deepEqual( - idsFromOrderedSet(relationshipState.canonicalMembers), - ['1'], - 'canonical member size should be 1' - ); - assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should be 1'); - assert.ok( - reloadedBoatInternalModel === initialBoatInternalModel, - 'after an unloadRecord, subsequent fetch results in the same InternalModel' - ); - - // and now the kicker, run-loop fun! - // here, we will dematerialize the record, but push it back into the store - // all in the same run-loop! - // effectively this tests that our destroySync is not stupid - run(() => { - reloadedBoat.unloadRecord(); - store.push({ - data: makeBoatOneForPersonOne(), + included: [makeBoatOneForPersonOne()], + }) + ); + + let boat = store.peekRecord('boat', '1'); + let initialBoatInternalModel = boat._internalModel; + let relationshipState = person.hasMany('boats').hasManyRelationship; + let knownPeople = store._internalModelsFor('person'); + let knownBoats = store._internalModelsFor('boat'); + + // ensure we loaded the people and boats + assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); + assert.equal(knownBoats.models.length, 1, 'one boat record is loaded'); + assert.equal(store.hasRecordForId('person', '1'), true); + assert.equal(store.hasRecordForId('boat', '1'), true); + + // ensure the relationship was established (we reach through the async proxy here) + let peopleBoats = run(() => person.get('boats.content')); + let boatPerson = run(() => boat.get('person.content')); + + assert.equal(relationshipState.canonicalMembers.size, 1, 'canonical member size should be 1'); + assert.equal(relationshipState.members.size, 1, 'members size should be 1'); + assert.ok(get(peopleBoats, 'length') === 1, 'Our person has a boat'); + assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat'); + assert.ok(boatPerson === person, 'Our boat has the right person'); + + run(() => { + store.unloadAll('boat'); }); - }); - let yaBoat = store.peekRecord('boat', '1'); - let yaBoatInternalModel = yaBoat._internalModel; - - assert.deepEqual( - idsFromOrderedSet(relationshipState.canonicalMembers), - ['1'], - 'canonical member size should be 1' - ); - assert.deepEqual(idsFromOrderedSet(relationshipState.members), ['1'], 'members size should be 1'); - assert.ok( - yaBoatInternalModel === initialBoatInternalModel, - 'after an unloadRecord, subsequent same-loop push results in the same InternalModel' - ); -}); + // ensure that our new state is correct + assert.equal(knownPeople.models.length, 1, 'one person record is loaded'); + assert.equal(knownBoats.models.length, 0, 'no boat records are loaded'); + assert.equal( + relationshipState.canonicalMembers.size, + 1, + 'canonical member size should still be 1' + ); + assert.equal(relationshipState.members.size, 1, 'members size should still be 1'); + assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats'); -test('unloading a disconnected subgraph clears the relevant internal models', function(assert) { - env.adapter.shouldBackgroundReloadRecord = () => false; + run(() => person.get('boats')); - run(() => { - env.store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Could be Anybody', - }, - relationships: { - boats: { - data: [{ type: 'boat', id: '1' }, { type: 'boat', id: '2' }], - }, - }, - }, - }); - }); + let reloadedBoat = store.peekRecord('boat', '1'); + let reloadedBoatInternalModel = reloadedBoat._internalModel; - run(() => { - env.store.push({ - data: { - type: 'boat', - id: '1', - attributes: { - name: 'Boaty McBoatface', - }, - relationships: { - person: { - data: { type: 'person', id: '1' }, - }, - }, - }, - }); + assert.ok( + reloadedBoatInternalModel === initialBoatInternalModel, + 'after an unloadAll, subsequent fetch results in the same InternalModel' + ); }); - run(() => { - env.store.push({ - data: { - type: 'boat', - id: '2', - attributes: { - name: 'The jackson', - }, - relationships: { - person: { - data: { type: 'person', id: '1' }, + test('(regression) unloadRecord followed by push in the same run-loop', function(assert) { + let person = run(() => + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Could be Anybody', + }, + relationships: { + boats: { + data: [{ type: 'boat', id: '1' }], + }, }, }, - }, - }); - }); + included: [makeBoatOneForPersonOne()], + }) + ); - assert.equal( - env.store._internalModelsFor('person').models.length, - 1, - 'one person record is loaded' - ); - assert.equal( - env.store._internalModelsFor('boat').models.length, - 2, - 'two boat records are loaded' - ); - assert.equal(env.store.hasRecordForId('person', 1), true); - assert.equal(env.store.hasRecordForId('boat', 1), true); - assert.equal(env.store.hasRecordForId('boat', 2), true); - - let checkOrphanCalls = 0; - let cleanupOrphanCalls = 0; - - function countOrphanCalls(record) { - let internalModel = record._internalModel; - let recordData = recordDataFor(record); - let origCheck = internalModel._checkForOrphanedInternalModels; - let origCleanup = recordData._cleanupOrphanedRecordDatas; + let boat = store.peekRecord('boat', '1'); + let initialBoatInternalModel = boat._internalModel; + let relationshipState = person.hasMany('boats').hasManyRelationship; + let knownPeople = store._internalModelsFor('person'); + let knownBoats = store._internalModelsFor('boat'); - internalModel._checkForOrphanedInternalModels = function() { - ++checkOrphanCalls; - return origCheck.apply(record._internalModel, arguments); - }; + // ensure we loaded the people and boats + assert.deepEqual(knownPeople.models.map(m => m.id), ['1'], 'one person record is loaded'); + assert.deepEqual(knownBoats.models.map(m => m.id), ['1'], 'one boat record is loaded'); + assert.equal(store.hasRecordForId('person', '1'), true); + assert.equal(store.hasRecordForId('boat', '1'), true); - recordData._cleanupOrphanedRecordDatas = function() { - ++cleanupOrphanCalls; - return origCleanup.apply(recordData, arguments); - }; - } - countOrphanCalls(env.store.peekRecord('person', 1)); - countOrphanCalls(env.store.peekRecord('boat', 1)); - countOrphanCalls(env.store.peekRecord('boat', 2)); - - // make sure relationships are initialized - return env.store - .peekRecord('person', 1) - .get('boats') - .then(() => { - run(() => { - env.store.peekRecord('person', 1).unloadRecord(); - env.store.peekRecord('boat', 1).unloadRecord(); - env.store.peekRecord('boat', 2).unloadRecord(); - }); + // ensure the relationship was established (we reach through the async proxy here) + let peopleBoats = run(() => person.get('boats.content')); + let boatPerson = run(() => boat.get('person.content')); + + assert.deepEqual( + idsFromOrderedSet(relationshipState.canonicalMembers), + ['1'], + 'canonical member size should be 1' + ); + assert.deepEqual( + idsFromOrderedSet(relationshipState.members), + ['1'], + 'members size should be 1' + ); + assert.ok(get(peopleBoats, 'length') === 1, 'Our person has a boat'); + assert.ok(peopleBoats.objectAt(0) === boat, 'Our person has the right boat'); + assert.ok(boatPerson === person, 'Our boat has the right person'); - assert.equal(env.store._internalModelsFor('person').models.length, 0); - assert.equal(env.store._internalModelsFor('boat').models.length, 0); + run(() => boat.unloadRecord()); - assert.equal(checkOrphanCalls, 3, 'each internalModel checks for cleanup'); - assert.equal(cleanupOrphanCalls, 3, 'each model data tries to cleanup'); - }); -}); + // ensure that our new state is correct + assert.deepEqual(knownPeople.models.map(m => m.id), ['1'], 'one person record is loaded'); + assert.deepEqual(knownBoats.models.map(m => m.id), ['1'], 'one boat record is known'); + assert.ok(knownBoats.models[0] === initialBoatInternalModel, 'We still have our boat'); + assert.equal(initialBoatInternalModel.isEmpty(), true, 'Model is in the empty state'); + assert.deepEqual( + idsFromOrderedSet(relationshipState.canonicalMembers), + ['1'], + 'canonical member size should still be 1' + ); + assert.deepEqual( + idsFromOrderedSet(relationshipState.members), + ['1'], + 'members size should still be 1' + ); + assert.ok(get(peopleBoats, 'length') === 0, 'Our person thinks they have no boats'); -test('Unloading a record twice only schedules destroy once', function(assert) { - const store = env.store; - let record; + run(() => + store.push({ + data: makeBoatOneForPersonOne(), + }) + ); - // populate initial record - run(function() { - record = store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland', - }, - }, + let reloadedBoat = store.peekRecord('boat', '1'); + let reloadedBoatInternalModel = reloadedBoat._internalModel; + + assert.deepEqual( + idsFromOrderedSet(relationshipState.canonicalMembers), + ['1'], + 'canonical member size should be 1' + ); + assert.deepEqual( + idsFromOrderedSet(relationshipState.members), + ['1'], + 'members size should be 1' + ); + assert.ok( + reloadedBoatInternalModel === initialBoatInternalModel, + 'after an unloadRecord, subsequent fetch results in the same InternalModel' + ); + + // and now the kicker, run-loop fun! + // here, we will dematerialize the record, but push it back into the store + // all in the same run-loop! + // effectively this tests that our destroySync is not stupid + run(() => { + reloadedBoat.unloadRecord(); + store.push({ + data: makeBoatOneForPersonOne(), + }); }); - }); - const internalModel = record._internalModel; + let yaBoat = store.peekRecord('boat', '1'); + let yaBoatInternalModel = yaBoat._internalModel; - run(function() { - store.unloadRecord(record); - store.unloadRecord(record); - internalModel.cancelDestroy(); + assert.deepEqual( + idsFromOrderedSet(relationshipState.canonicalMembers), + ['1'], + 'canonical member size should be 1' + ); + assert.deepEqual( + idsFromOrderedSet(relationshipState.members), + ['1'], + 'members size should be 1' + ); + assert.ok( + yaBoatInternalModel === initialBoatInternalModel, + 'after an unloadRecord, subsequent same-loop push results in the same InternalModel' + ); }); - assert.equal(internalModel.isDestroyed, false, 'We cancelled destroy'); -}); + test('unloading a disconnected subgraph clears the relevant internal models', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; -test('Cancelling destroy leaves the record in the empty state', function(assert) { - const store = env.store; - let record; + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Could be Anybody', + }, + relationships: { + boats: { + data: [{ type: 'boat', id: '1' }, { type: 'boat', id: '2' }], + }, + }, + }, + }); + }); - // populate initial record - run(function() { - record = store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland', + run(() => { + store.push({ + data: { + type: 'boat', + id: '1', + attributes: { + name: 'Boaty McBoatface', + }, + relationships: { + person: { + data: { type: 'person', id: '1' }, + }, + }, }, - }, + }); + }); + + run(() => { + store.push({ + data: { + type: 'boat', + id: '2', + attributes: { + name: 'The jackson', + }, + relationships: { + person: { + data: { type: 'person', id: '1' }, + }, + }, + }, + }); }); - }); - const internalModel = record._internalModel; - assert.equal( - internalModel.currentState.stateName, - 'root.loaded.saved', - 'We are loaded initially' - ); - - run(function() { - store.unloadRecord(record); - assert.equal(record.isDestroying, true, 'the record is destroying'); - assert.equal(internalModel.isDestroyed, false, 'the internal model is not destroyed'); - assert.equal(internalModel._isDematerializing, true, 'the internal model is dematerializing'); - internalModel.cancelDestroy(); assert.equal( - internalModel.currentState.stateName, - 'root.empty', - 'We are unloaded after unloadRecord' + store._internalModelsFor('person').models.length, + 1, + 'one person record is loaded' ); - }); + assert.equal(store._internalModelsFor('boat').models.length, 2, 'two boat records are loaded'); + assert.equal(store.hasRecordForId('person', 1), true); + assert.equal(store.hasRecordForId('boat', 1), true); + assert.equal(store.hasRecordForId('boat', 2), true); + + let checkOrphanCalls = 0; + let cleanupOrphanCalls = 0; + + function countOrphanCalls(record) { + let internalModel = record._internalModel; + let recordData = recordDataFor(record); + let origCheck = internalModel._checkForOrphanedInternalModels; + let origCleanup = recordData._cleanupOrphanedRecordDatas; + + internalModel._checkForOrphanedInternalModels = function() { + ++checkOrphanCalls; + return origCheck.apply(record._internalModel, arguments); + }; + + recordData._cleanupOrphanedRecordDatas = function() { + ++cleanupOrphanCalls; + return origCleanup.apply(recordData, arguments); + }; + } + countOrphanCalls(store.peekRecord('person', 1)); + countOrphanCalls(store.peekRecord('boat', 1)); + countOrphanCalls(store.peekRecord('boat', 2)); - assert.equal(internalModel.isDestroyed, false, 'the internal model was not destroyed'); - assert.equal( - internalModel._isDematerializing, - false, - 'the internal model is no longer dematerializing' - ); - assert.equal( - internalModel.currentState.stateName, - 'root.empty', - 'We are still unloaded after unloadRecord' - ); -}); + // make sure relationships are initialized + return store + .peekRecord('person', 1) + .get('boats') + .then(() => { + run(() => { + store.peekRecord('person', 1).unloadRecord(); + store.peekRecord('boat', 1).unloadRecord(); + store.peekRecord('boat', 2).unloadRecord(); + }); -test('after unloading a record, the record can be fetched again immediately', function(assert) { - const store = env.store; + assert.equal(store._internalModelsFor('person').models.length, 0); + assert.equal(store._internalModelsFor('boat').models.length, 0); - // stub findRecord - env.adapter.findRecord = () => { - return { - data: { - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland', - }, - }, - }; - }; + assert.equal(checkOrphanCalls, 3, 'each internalModel checks for cleanup'); + assert.equal(cleanupOrphanCalls, 3, 'each model data tries to cleanup'); + }); + }); - // populate initial record - let record = run(() => { - return store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland', - }, - relationships: { - cars: { - data: [ - { - id: 1, - type: 'car', - }, - ], + test('Unloading a record twice only schedules destroy once', function(assert) { + let record; + + // populate initial record + run(function() { + record = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', }, }, - }, - included: [ - { - type: 'car', - id: 1, + }); + }); + + const internalModel = record._internalModel; + + run(function() { + store.unloadRecord(record); + store.unloadRecord(record); + internalModel.cancelDestroy(); + }); + + assert.equal(internalModel.isDestroyed, false, 'We cancelled destroy'); + }); + + test('Cancelling destroy leaves the record in the empty state', function(assert) { + let record; + + // populate initial record + run(function() { + record = store.push({ + data: { + type: 'person', + id: '1', attributes: { - make: 'jeep', - model: 'wrangler', + name: 'Adam Sunderland', }, }, - ], + }); }); - }); - const internalModel = record._internalModel; - assert.equal( - internalModel.currentState.stateName, - 'root.loaded.saved', - 'We are loaded initially' - ); - - // we test that we can sync call unloadRecord followed by findRecord - return run(() => { - store.unloadRecord(record); - assert.equal(record.isDestroying, true, 'the record is destroying'); + const internalModel = record._internalModel; assert.equal( internalModel.currentState.stateName, - 'root.empty', - 'We are unloaded after unloadRecord' + 'root.loaded.saved', + 'We are loaded initially' ); - return store.findRecord('person', '1').then(newRecord => { - assert.ok(internalModel === newRecord._internalModel, 'the old internalModel is reused'); + + run(function() { + store.unloadRecord(record); + assert.equal(record.isDestroying, true, 'the record is destroying'); + assert.equal(internalModel.isDestroyed, false, 'the internal model is not destroyed'); + assert.equal(internalModel._isDematerializing, true, 'the internal model is dematerializing'); + internalModel.cancelDestroy(); assert.equal( - newRecord._internalModel.currentState.stateName, - 'root.loaded.saved', - 'We are loaded after findRecord' + internalModel.currentState.stateName, + 'root.empty', + 'We are unloaded after unloadRecord' ); }); - }); -}); -test('after unloading a record, the record can be fetched again immediately (purge relationship)', function(assert) { - const store = env.store; + assert.equal(internalModel.isDestroyed, false, 'the internal model was not destroyed'); + assert.equal( + internalModel._isDematerializing, + false, + 'the internal model is no longer dematerializing' + ); + assert.equal( + internalModel.currentState.stateName, + 'root.empty', + 'We are still unloaded after unloadRecord' + ); + }); - // stub findRecord - env.adapter.findRecord = () => { - return { - data: { - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland', - }, - relationships: { - cars: { - data: [], + test('after unloading a record, the record can be fetched again immediately', function(assert) { + // stub findRecord + adapter.findRecord = () => { + return { + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', }, }, - }, + }; }; - }; - // populate initial record - let record = run(() => { - return store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland', - }, - relationships: { - cars: { - data: [ - { - id: '1', - type: 'car', - }, - ], - }, - }, - }, - included: [ - { - type: 'car', + // populate initial record + let record = run(() => { + return store.push({ + data: { + type: 'person', id: '1', attributes: { - make: 'jeep', - model: 'wrangler', + name: 'Adam Sunderland', + }, + relationships: { + cars: { + data: [ + { + id: 1, + type: 'car', + }, + ], + }, }, }, - ], + included: [ + { + type: 'car', + id: 1, + attributes: { + make: 'jeep', + model: 'wrangler', + }, + }, + ], + }); }); - }); - const internalModel = record._internalModel; - assert.equal( - internalModel.currentState.stateName, - 'root.loaded.saved', - 'We are loaded initially' - ); - - // we test that we can sync call unloadRecord followed by findRecord - return run(() => { - assert.equal(record.get('cars.firstObject.make'), 'jeep'); - store.unloadRecord(record); - assert.equal(record.isDestroying, true, 'the record is destroying'); + const internalModel = record._internalModel; assert.equal( internalModel.currentState.stateName, - 'root.empty', - 'Expected the previous internal model tobe unloaded' + 'root.loaded.saved', + 'We are loaded initially' ); - return store.findRecord('person', '1').then(record => { - assert.equal( - record.get('cars.length'), - 0, - 'Expected relationship to be cleared by the new push' - ); - assert.ok(internalModel === record._internalModel, 'the old internalModel is reused'); + // we test that we can sync call unloadRecord followed by findRecord + return run(() => { + store.unloadRecord(record); + assert.equal(record.isDestroying, true, 'the record is destroying'); assert.equal( - record._internalModel.currentState.stateName, - 'root.loaded.saved', - 'Expected the NEW internal model to be loaded' + internalModel.currentState.stateName, + 'root.empty', + 'We are unloaded after unloadRecord' ); + return store.findRecord('person', '1').then(newRecord => { + assert.ok(internalModel === newRecord._internalModel, 'the old internalModel is reused'); + assert.equal( + newRecord._internalModel.currentState.stateName, + 'root.loaded.saved', + 'We are loaded after findRecord' + ); + }); }); }); -}); - -test('after unloading a record, the record can be fetched again immediately (with relationships)', function(assert) { - const store = env.store; - // stub findRecord - env.adapter.findRecord = () => { - return { - data: { - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland', - }, - }, - }; - }; - // populate initial record - let record = run(() => { - return store.push({ - data: { - type: 'person', - id: '1', - relationships: { - bike: { - data: { type: 'bike', id: '1' }, + test('after unloading a record, the record can be fetched again immediately (purge relationship)', function(assert) { + // stub findRecord + adapter.findRecord = () => { + return { + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', + }, + relationships: { + cars: { + data: [], + }, }, }, - }, + }; + }; - included: [ - { + // populate initial record + let record = run(() => { + return store.push({ + data: { + type: 'person', id: '1', - type: 'bike', attributes: { - name: 'mr bike', + name: 'Adam Sunderland', + }, + relationships: { + cars: { + data: [ + { + id: '1', + type: 'car', + }, + ], + }, }, }, - ], + included: [ + { + type: 'car', + id: '1', + attributes: { + make: 'jeep', + model: 'wrangler', + }, + }, + ], + }); }); - }); - const internalModel = record._internalModel; - const bike = store.peekRecord('bike', '1'); - assert.equal( - internalModel.currentState.stateName, - 'root.loaded.saved', - 'We are loaded initially' - ); - - assert.equal(record.get('bike.name'), 'mr bike'); - - // we test that we can sync call unloadRecord followed by findRecord - let wait = run(() => { - store.unloadRecord(record); - assert.equal(record.isDestroying, true, 'the record is destroying'); - assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); + const internalModel = record._internalModel; assert.equal( internalModel.currentState.stateName, - 'root.empty', - 'We are unloaded after unloadRecord' + 'root.loaded.saved', + 'We are loaded initially' ); - let wait = store.findRecord('person', '1').then(newRecord => { - assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); - assert.ok( - newRecord.get('bike') === bike, - 'the newRecord should retain knowledge of the bike' + // we test that we can sync call unloadRecord followed by findRecord + return run(() => { + assert.equal(record.get('cars.firstObject.make'), 'jeep'); + store.unloadRecord(record); + assert.equal(record.isDestroying, true, 'the record is destroying'); + assert.equal( + internalModel.currentState.stateName, + 'root.empty', + 'Expected the previous internal model tobe unloaded' ); - }); - assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); - return wait; + return store.findRecord('person', '1').then(record => { + assert.equal( + record.get('cars.length'), + 0, + 'Expected relationship to be cleared by the new push' + ); + assert.ok(internalModel === record._internalModel, 'the old internalModel is reused'); + assert.equal( + record._internalModel.currentState.stateName, + 'root.loaded.saved', + 'Expected the NEW internal model to be loaded' + ); + }); + }); }); - assert.equal(record.isDestroyed, true, 'the record IS destroyed'); - return wait; -}); - -test('after unloading a record, the record can be fetched again soon there after', function(assert) { - const store = env.store; - let record; - - // stub findRecord - env.adapter.findRecord = () => { - return EmberPromise.resolve({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland', + test('after unloading a record, the record can be fetched again immediately (with relationships)', function(assert) { + // stub findRecord + adapter.findRecord = () => { + return { + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', + }, }, - }, - }); - }; + }; + }; - // populate initial record - run(function() { - record = store.push({ - data: { - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland', + // populate initial record + let record = run(() => { + return store.push({ + data: { + type: 'person', + id: '1', + relationships: { + bike: { + data: { type: 'bike', id: '1' }, + }, + }, }, - }, - }); - }); - let internalModel = record._internalModel; - assert.equal( - internalModel.currentState.stateName, - 'root.loaded.saved', - 'We are loaded initially' - ); + included: [ + { + id: '1', + type: 'bike', + attributes: { + name: 'mr bike', + }, + }, + ], + }); + }); - run(function() { - store.unloadRecord(record); - assert.equal(record.isDestroying, true, 'the record is destroying'); + const internalModel = record._internalModel; + const bike = store.peekRecord('bike', '1'); assert.equal( internalModel.currentState.stateName, - 'root.empty', - 'We are unloaded after unloadRecord' + 'root.loaded.saved', + 'We are loaded initially' ); - }); - - run(function() { - store.findRecord('person', '1'); - }); - record = store.peekRecord('person', '1'); - internalModel = record._internalModel; + assert.equal(record.get('bike.name'), 'mr bike'); - assert.equal( - internalModel.currentState.stateName, - 'root.loaded.saved', - 'We are loaded after findRecord' - ); -}); - -test('after unloading a record, the record can be saved again immediately', function(assert) { - assert.expect(0); - - const store = env.store; - const data = { - data: { - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland', - }, - }, - }; - - env.adapter.createRecord = () => EmberPromise.resolve(data); + // we test that we can sync call unloadRecord followed by findRecord + let wait = run(() => { + store.unloadRecord(record); + assert.equal(record.isDestroying, true, 'the record is destroying'); + assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); + assert.equal( + internalModel.currentState.stateName, + 'root.empty', + 'We are unloaded after unloadRecord' + ); - run(() => { - // add an initial record with id '1' to the store - store.push(data); + let wait = store.findRecord('person', '1').then(newRecord => { + assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); + assert.ok( + newRecord.get('bike') === bike, + 'the newRecord should retain knowledge of the bike' + ); + }); - // unload the initial record - store.peekRecord('person', '1').unloadRecord(); + assert.equal(record.isDestroyed, false, 'the record is NOT YET destroyed'); + return wait; + }); - // create a new record that will again get id '1' from the backend - store.createRecord('person').save(); + assert.equal(record.isDestroyed, true, 'the record IS destroyed'); + return wait; }); -}); -test('after unloading a record, pushing a new copy will setup relationships', function(assert) { - const store = env.store; - const personData = { - data: { - type: 'person', - id: '1', - attributes: { - name: 'Adam Sunderland', - }, - }, - }; + test('after unloading a record, the record can be fetched again soon there after', function(assert) { + let record; - function pushCar() { - store.push({ - data: { - type: 'car', - id: '10', - attributes: { - make: 'VW', - model: 'Beetle', + // stub findRecord + adapter.findRecord = () => { + return EmberPromise.resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', + }, }, - relationships: { - person: { - data: { type: 'person', id: '1' }, + }); + }; + + // populate initial record + run(function() { + record = store.push({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', }, }, - }, + }); }); - } - run(() => { - store.push(personData); - }); + let internalModel = record._internalModel; + assert.equal( + internalModel.currentState.stateName, + 'root.loaded.saved', + 'We are loaded initially' + ); + + run(function() { + store.unloadRecord(record); + assert.equal(record.isDestroying, true, 'the record is destroying'); + assert.equal( + internalModel.currentState.stateName, + 'root.empty', + 'We are unloaded after unloadRecord' + ); + }); - let adam = env.store.peekRecord('person', 1); - assert.equal(adam.get('cars.length'), 0, 'cars hasMany starts off empty'); + run(function() { + store.findRecord('person', '1'); + }); - run(() => pushCar()); - assert.equal(adam.get('cars.length'), 1, 'pushing car setups inverse relationship'); + record = store.peekRecord('person', '1'); + internalModel = record._internalModel; - run(() => adam.get('cars.firstObject').unloadRecord()); - assert.equal(adam.get('cars.length'), 0, 'unloading car cleaned up hasMany'); + assert.equal( + internalModel.currentState.stateName, + 'root.loaded.saved', + 'We are loaded after findRecord' + ); + }); - run(() => pushCar()); - assert.equal(adam.get('cars.length'), 1, 'pushing car again setups inverse relationship'); -}); + test('after unloading a record, the record can be saved again immediately', function(assert) { + assert.expect(0); -test('1:1 sync unload', function(assert) { - run(() => - env.store.push({ + const data = { data: { - id: 1, type: 'person', - relationships: { - house: { - data: { - id: 2, - type: 'house', - }, - }, + id: '1', + attributes: { + name: 'Adam Sunderland', }, }, - included: [ - { - id: 2, - type: 'house', - }, - ], - }) - ); + }; - let person = env.store.peekRecord('person', 1); - let house = env.store.peekRecord('house', 2); + adapter.createRecord = () => EmberPromise.resolve(data); - assert.equal(person.get('house.id'), 2, 'initially relationship established lhs'); - assert.equal(house.get('person.id'), 1, 'initially relationship established rhs'); + run(() => { + // add an initial record with id '1' to the store + store.push(data); - run(() => house.unloadRecord()); + // unload the initial record + store.peekRecord('person', '1').unloadRecord(); - assert.equal(person.get('house'), null, 'unloading acts as a delete for sync relationships'); - assert.equal(env.store.hasRecordForId('house', 2), false, 'unloaded record gone from store'); + // create a new record that will again get id '1' from the backend + store.createRecord('person').save(); + }); + }); - house = run(() => - env.store.push({ + test('after unloading a record, pushing a new copy will setup relationships', function(assert) { + const personData = { data: { - id: 2, - type: 'house', + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland', + }, }, - }) - ); - - assert.equal(env.store.hasRecordForId('house', 2), true, 'unloaded record can be restored'); - assert.equal( - person.get('house'), - null, - 'restoring unloaded record does not restore relationship' - ); - assert.equal( - house.get('person'), - null, - 'restoring unloaded record does not restore relationship' - ); - - run(() => - env.store.push({ - data: { - id: 2, - type: 'house', - relationships: { - person: { - data: { - id: 1, - type: 'person', + }; + + function pushCar() { + store.push({ + data: { + type: 'car', + id: '10', + attributes: { + make: 'VW', + model: 'Beetle', + }, + relationships: { + person: { + data: { type: 'person', id: '1' }, }, }, }, - }, - }) - ); + }); + } - assert.equal(person.get('house.id'), 2, 'after unloading, relationship can be restored'); - assert.equal(house.get('person.id'), 1, 'after unloading, relationship can be restored'); -}); + run(() => { + store.push(personData); + }); -test('1:many sync unload 1 side', function(assert) { - run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - cars: { - data: [ - { + let adam = store.peekRecord('person', 1); + assert.equal(adam.get('cars.length'), 0, 'cars hasMany starts off empty'); + + run(() => pushCar()); + assert.equal(adam.get('cars.length'), 1, 'pushing car setups inverse relationship'); + + run(() => adam.get('cars.firstObject').unloadRecord()); + assert.equal(adam.get('cars.length'), 0, 'unloading car cleaned up hasMany'); + + run(() => pushCar()); + assert.equal(adam.get('cars.length'), 1, 'pushing car again setups inverse relationship'); + }); + + test('1:1 sync unload', function(assert) { + run(() => + store.push({ + data: { + id: 1, + type: 'person', + relationships: { + house: { + data: { id: 2, - type: 'car', + type: 'house', }, - { - id: 3, - type: 'car', - }, - ], + }, }, }, - }, - included: [ - { - id: 2, - type: 'car', - }, - { - id: 3, - type: 'car', - }, - ], - }) - ); - - let person = env.store.peekRecord('person', 1); - let car2 = env.store.peekRecord('car', 2); - let car3 = env.store.peekRecord('car', 3); - let cars = person.get('cars'); - - assert.equal(cars.isDestroyed, false, 'ManyArray not destroyed'); - assert.deepEqual( - person.get('cars').mapBy('id'), - ['2', '3'], - 'initialy relationship established lhs' - ); - assert.equal(car2.get('person.id'), 1, 'initially relationship established rhs'); - assert.equal(car3.get('person.id'), 1, 'initially relationship established rhs'); - - run(() => person.unloadRecord()); - - assert.equal(env.store.hasRecordForId('person', 1), false, 'unloaded record gone from store'); - - assert.equal(car2.get('person'), null, 'unloading acts as delete for sync relationships'); - assert.equal(car3.get('person'), null, 'unloading acts as delete for sync relationships'); - assert.equal(cars.isDestroyed, true, 'ManyArray destroyed'); - - person = run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - }, - }) - ); - - assert.equal(env.store.hasRecordForId('person', 1), true, 'unloaded record can be restored'); - assert.deepEqual( - person.get('cars').mapBy('id'), - [], - 'restoring unloaded record does not restore relationship' - ); - assert.equal(car2.get('person'), null, 'restoring unloaded record does not restore relationship'); - assert.equal(car3.get('person'), null, 'restoring unloaded record does not restore relationship'); - - run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - cars: { - data: [ - { - id: 2, - type: 'car', - }, - { - id: 3, - type: 'car', - }, - ], + included: [ + { + id: 2, + type: 'house', }, - }, - }, - }) - ); - - assert.equal(car2.get('person.id'), '1', 'after unloading, relationship can be restored'); - assert.equal(car3.get('person.id'), '1', 'after unloading, relationship can be restored'); - assert.deepEqual( - person.get('cars').mapBy('id'), - ['2', '3'], - 'after unloading, relationship can be restored' - ); -}); + ], + }) + ); -test('1:many sync unload many side', function(assert) { - run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - cars: { - data: [ - { - id: 2, - type: 'car', - }, - { - id: 3, - type: 'car', - }, - ], - }, - }, - }, - included: [ - { + let person = store.peekRecord('person', 1); + let house = store.peekRecord('house', 2); + + assert.equal(person.get('house.id'), 2, 'initially relationship established lhs'); + assert.equal(house.get('person.id'), 1, 'initially relationship established rhs'); + + run(() => house.unloadRecord()); + + assert.equal(person.get('house'), null, 'unloading acts as a delete for sync relationships'); + assert.equal(store.hasRecordForId('house', 2), false, 'unloaded record gone from store'); + + house = run(() => + store.push({ + data: { id: 2, - type: 'car', - }, - { - id: 3, - type: 'car', + type: 'house', }, - ], - }) - ); - - let person = env.store.peekRecord('person', 1); - let car2 = env.store.peekRecord('car', 2); - let car3 = env.store.peekRecord('car', 3); - let cars = person.get('cars'); - - assert.equal(cars.isDestroyed, false, 'ManyArray not destroyed'); - assert.deepEqual( - person.get('cars').mapBy('id'), - ['2', '3'], - 'initialy relationship established lhs' - ); - assert.equal(car2.get('person.id'), 1, 'initially relationship established rhs'); - assert.equal(car3.get('person.id'), 1, 'initially relationship established rhs'); - - run(() => car2.unloadRecord()); - - assert.equal(env.store.hasRecordForId('car', 2), false, 'unloaded record gone from store'); - - assert.equal(cars.isDestroyed, false, 'ManyArray not destroyed'); - assert.deepEqual( - person.get('cars').mapBy('id'), - ['3'], - 'unload sync relationship acts as delete' - ); - assert.equal( - car3.get('person.id'), - '1', - 'unloading one of a sync hasMany does not affect the rest' - ); - - car2 = run(() => - env.store.push({ - data: { - id: 2, - type: 'car', - }, - }) - ); - - assert.equal(env.store.hasRecordForId('car', 2), true, 'unloaded record can be restored'); - assert.deepEqual( - person.get('cars').mapBy('id'), - ['3'], - 'restoring unloaded record does not restore relationship' - ); - assert.equal(car2.get('person'), null, 'restoring unloaded record does not restore relationship'); - - run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - cars: { - data: [ - { - id: 2, - type: 'car', - }, - { - id: 3, - type: 'car', + }) + ); + + assert.equal(store.hasRecordForId('house', 2), true, 'unloaded record can be restored'); + assert.equal( + person.get('house'), + null, + 'restoring unloaded record does not restore relationship' + ); + assert.equal( + house.get('person'), + null, + 'restoring unloaded record does not restore relationship' + ); + + run(() => + store.push({ + data: { + id: 2, + type: 'house', + relationships: { + person: { + data: { + id: 1, + type: 'person', }, - ], + }, }, }, - }, - }) - ); - - assert.equal(car2.get('person.id'), '1', 'after unloading, relationship can be restored'); - assert.deepEqual( - person.get('cars').mapBy('id'), - ['2', '3'], - 'after unloading, relationship can be restored' - ); -}); + }) + ); -test('many:many sync unload', function(assert) { - run(() => - env.store.push({ - data: [ - { + assert.equal(person.get('house.id'), 2, 'after unloading, relationship can be restored'); + assert.equal(house.get('person.id'), 1, 'after unloading, relationship can be restored'); + }); + + test('1:many sync unload 1 side', function(assert) { + run(() => + store.push({ + data: { id: 1, type: 'person', relationships: { - groups: { + cars: { data: [ { - id: 3, - type: 'group', - }, - { - id: 4, - type: 'group', + id: 2, + type: 'car', }, - ], - }, - }, - }, - { - id: 2, - type: 'person', - relationships: { - groups: { - data: [ { id: 3, - type: 'group', - }, - { - id: 4, - type: 'group', + type: 'car', }, ], }, }, }, - ], - included: [ - { - id: 3, - type: 'group', - }, - { - id: 4, - type: 'group', - }, - ], - }) - ); - - let person1 = env.store.peekRecord('person', 1); - let person2 = env.store.peekRecord('person', 2); - let group3 = env.store.peekRecord('group', 3); - let group4 = env.store.peekRecord('group', 4); - let p2groups = person2.get('groups'); - let g3people = group3.get('people'); - - assert.deepEqual( - person1.get('groups').mapBy('id'), - ['3', '4'], - 'initially established relationship lhs' - ); - assert.deepEqual( - person2.get('groups').mapBy('id'), - ['3', '4'], - 'initially established relationship lhs' - ); - assert.deepEqual( - group3.get('people').mapBy('id'), - ['1', '2'], - 'initially established relationship lhs' - ); - assert.deepEqual( - group4.get('people').mapBy('id'), - ['1', '2'], - 'initially established relationship lhs' - ); - - assert.equal(p2groups.isDestroyed, false, 'groups is not destroyed'); - assert.equal(g3people.isDestroyed, false, 'people is not destroyed'); - - run(() => person2.unloadRecord()); - - assert.equal(p2groups.isDestroyed, true, 'groups (unloaded side) is destroyed'); - assert.equal(g3people.isDestroyed, false, 'people (inverse) is not destroyed'); - - assert.deepEqual( - person1.get('groups').mapBy('id'), - ['3', '4'], - 'unloaded record in many:many does not affect inverse of inverse' - ); - assert.deepEqual( - group3.get('people').mapBy('id'), - ['1'], - 'unloading acts as delete for sync relationships' - ); - assert.deepEqual( - group4.get('people').mapBy('id'), - ['1'], - 'unloading acts as delete for sync relationships' - ); - - assert.equal(env.store.hasRecordForId('person', 2), false, 'unloading removes record from store'); - - person2 = run(() => - env.store.push({ - data: { - id: 2, - type: 'person', - }, - }) - ); - - assert.equal(env.store.hasRecordForId('person', 2), true, 'unloaded record can be restored'); - assert.deepEqual( - person2.get('groups').mapBy('id'), - [], - 'restoring unloaded record does not restore relationship' - ); - assert.deepEqual( - group3.get('people').mapBy('id'), - ['1'], - 'restoring unloaded record does not restore relationship' - ); - assert.deepEqual( - group4.get('people').mapBy('id'), - ['1'], - 'restoring unloaded record does not restore relationship' - ); - - run(() => - env.store.push({ - data: { - id: 2, - type: 'person', - relationships: { - groups: { - data: [ - { - id: 3, - type: 'group', - }, - { - id: 4, - type: 'group', - }, - ], + included: [ + { + id: 2, + type: 'car', }, - }, - }, - }) - ); - - assert.deepEqual( - person2.get('groups').mapBy('id'), - ['3', '4'], - 'after unloading, relationship can be restored' - ); - assert.deepEqual( - group3.get('people').mapBy('id'), - ['1', '2'], - 'after unloading, relationship can be restored' - ); - assert.deepEqual( - group4.get('people').mapBy('id'), - ['1', '2'], - 'after unloading, relationship can be restored' - ); -}); + { + id: 3, + type: 'car', + }, + ], + }) + ); -test('1:1 async unload', function(assert) { - let findRecordCalls = 0; + let person = store.peekRecord('person', 1); + let car2 = store.peekRecord('car', 2); + let car3 = store.peekRecord('car', 3); + let cars = person.get('cars'); - env.adapter.findRecord = (store, type, id) => { - assert.equal(type, Mortgage, 'findRecord(_, type) is correct'); - assert.equal(id, '2', 'findRecord(_, _, id) is correct'); - ++findRecordCalls; + assert.equal(cars.isDestroyed, false, 'ManyArray not destroyed'); + assert.deepEqual( + person.get('cars').mapBy('id'), + ['2', '3'], + 'initialy relationship established lhs' + ); + assert.equal(car2.get('person.id'), 1, 'initially relationship established rhs'); + assert.equal(car3.get('person.id'), 1, 'initially relationship established rhs'); - return { - data: { - id: 2, - type: 'mortgage', - }, - }; - }; + run(() => person.unloadRecord()); - let person = run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - mortgage: { - data: { - id: 2, - type: 'mortgage', - }, - }, + assert.equal(store.hasRecordForId('person', 1), false, 'unloaded record gone from store'); + + assert.equal(car2.get('person'), null, 'unloading acts as delete for sync relationships'); + assert.equal(car3.get('person'), null, 'unloading acts as delete for sync relationships'); + assert.equal(cars.isDestroyed, true, 'ManyArray destroyed'); + + person = run(() => + store.push({ + data: { + id: 1, + type: 'person', }, - }, - }) - ); - let mortgage; - - return run(() => - person - .get('mortgage') - .then(asyncRecord => { - mortgage = asyncRecord; - return mortgage.get('person'); }) - .then(() => { - assert.equal( - mortgage.belongsTo('person').id(), - '1', - 'initially relationship established lhs' - ); - assert.equal( - person.belongsTo('mortgage').id(), - '2', - 'initially relationship established rhs' - ); - - run(() => mortgage.unloadRecord()); + ); - assert.equal( - person.belongsTo('mortgage').id(), - '2', - 'unload async is not treated as delete' - ); + assert.equal(store.hasRecordForId('person', 1), true, 'unloaded record can be restored'); + assert.deepEqual( + person.get('cars').mapBy('id'), + [], + 'restoring unloaded record does not restore relationship' + ); + assert.equal( + car2.get('person'), + null, + 'restoring unloaded record does not restore relationship' + ); + assert.equal( + car3.get('person'), + null, + 'restoring unloaded record does not restore relationship' + ); - return person.get('mortgage'); + run(() => + store.push({ + data: { + id: 1, + type: 'person', + relationships: { + cars: { + data: [ + { + id: 2, + type: 'car', + }, + { + id: 3, + type: 'car', + }, + ], + }, + }, + }, }) - .then(refetchedMortgage => { - assert.notEqual(mortgage, refetchedMortgage, 'the previously loaded record is not reused'); + ); - assert.equal( - person.belongsTo('mortgage').id(), - '2', - 'unload async is not treated as delete' - ); - assert.equal( - refetchedMortgage.belongsTo('person').id(), - '1', - 'unload async is not treated as delete' - ); - assert.equal(findRecordCalls, 2); + assert.equal(car2.get('person.id'), '1', 'after unloading, relationship can be restored'); + assert.equal(car3.get('person.id'), '1', 'after unloading, relationship can be restored'); + assert.deepEqual( + person.get('cars').mapBy('id'), + ['2', '3'], + 'after unloading, relationship can be restored' + ); + }); + + test('1:many sync unload many side', function(assert) { + run(() => + store.push({ + data: { + id: 1, + type: 'person', + relationships: { + cars: { + data: [ + { + id: 2, + type: 'car', + }, + { + id: 3, + type: 'car', + }, + ], + }, + }, + }, + included: [ + { + id: 2, + type: 'car', + }, + { + id: 3, + type: 'car', + }, + ], }) - ); -}); + ); -test('1:many async unload 1 side', function(assert) { - let findRecordCalls = 0; - let findManyCalls = 0; + let person = store.peekRecord('person', 1); + let car2 = store.peekRecord('car', 2); + let car3 = store.peekRecord('car', 3); + let cars = person.get('cars'); - env.adapter.coalesceFindRequests = true; + assert.equal(cars.isDestroyed, false, 'ManyArray not destroyed'); + assert.deepEqual( + person.get('cars').mapBy('id'), + ['2', '3'], + 'initialy relationship established lhs' + ); + assert.equal(car2.get('person.id'), 1, 'initially relationship established rhs'); + assert.equal(car3.get('person.id'), 1, 'initially relationship established rhs'); - env.adapter.findRecord = (store, type, id) => { - assert.equal(type, Person, 'findRecord(_, type) is correct'); - assert.deepEqual(id, '1', 'findRecord(_, _, id) is correct'); - ++findRecordCalls; + run(() => car2.unloadRecord()); - return { - data: { - id: 1, - type: 'person', - }, - }; - }; + assert.equal(store.hasRecordForId('car', 2), false, 'unloaded record gone from store'); - env.adapter.findMany = (store, type, ids) => { - assert.equal(type + '', Boat + '', 'findMany(_, type) is correct'); - assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); - ++findManyCalls; + assert.equal(cars.isDestroyed, false, 'ManyArray not destroyed'); + assert.deepEqual( + person.get('cars').mapBy('id'), + ['3'], + 'unload sync relationship acts as delete' + ); + assert.equal( + car3.get('person.id'), + '1', + 'unloading one of a sync hasMany does not affect the rest' + ); - return { - data: [ - { + car2 = run(() => + store.push({ + data: { id: 2, - type: 'boat', + type: 'car', }, - { - id: 3, - type: 'boat', + }) + ); + + assert.equal(store.hasRecordForId('car', 2), true, 'unloaded record can be restored'); + assert.deepEqual( + person.get('cars').mapBy('id'), + ['3'], + 'restoring unloaded record does not restore relationship' + ); + assert.equal( + car2.get('person'), + null, + 'restoring unloaded record does not restore relationship' + ); + + run(() => + store.push({ + data: { + id: 1, + type: 'person', + relationships: { + cars: { + data: [ + { + id: 2, + type: 'car', + }, + { + id: 3, + type: 'car', + }, + ], + }, + }, }, - ], - }; - }; + }) + ); - let person = run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - boats: { - data: [ - { - id: 2, - type: 'boat', + assert.equal(car2.get('person.id'), '1', 'after unloading, relationship can be restored'); + assert.deepEqual( + person.get('cars').mapBy('id'), + ['2', '3'], + 'after unloading, relationship can be restored' + ); + }); + + test('many:many sync unload', function(assert) { + run(() => + store.push({ + data: [ + { + id: 1, + type: 'person', + relationships: { + groups: { + data: [ + { + id: 3, + type: 'group', + }, + { + id: 4, + type: 'group', + }, + ], }, - { - id: 3, - type: 'boat', + }, + }, + { + id: 2, + type: 'person', + relationships: { + groups: { + data: [ + { + id: 3, + type: 'group', + }, + { + id: 4, + type: 'group', + }, + ], }, - ], + }, }, - }, - }, - }) - ); - let boats, boat2, boat3; - - return run(() => - person - .get('boats') - .then(asyncRecords => { - boats = asyncRecords; - [boat2, boat3] = boats.toArray(); - return EmberPromise.all([boat2, boat3].map(b => b.get('person'))); + ], + included: [ + { + id: 3, + type: 'group', + }, + { + id: 4, + type: 'group', + }, + ], }) - .then(() => { - assert.deepEqual( - person.hasMany('boats').ids(), - ['2', '3'], - 'initially relationship established lhs' - ); - assert.equal(boat2.belongsTo('person').id(), '1', 'initially relationship established rhs'); - assert.equal(boat3.belongsTo('person').id(), '1', 'initially relationship established rhs'); + ); + + let person1 = store.peekRecord('person', 1); + let person2 = store.peekRecord('person', 2); + let group3 = store.peekRecord('group', 3); + let group4 = store.peekRecord('group', 4); + let p2groups = person2.get('groups'); + let g3people = group3.get('people'); + + assert.deepEqual( + person1.get('groups').mapBy('id'), + ['3', '4'], + 'initially established relationship lhs' + ); + assert.deepEqual( + person2.get('groups').mapBy('id'), + ['3', '4'], + 'initially established relationship lhs' + ); + assert.deepEqual( + group3.get('people').mapBy('id'), + ['1', '2'], + 'initially established relationship lhs' + ); + assert.deepEqual( + group4.get('people').mapBy('id'), + ['1', '2'], + 'initially established relationship lhs' + ); - assert.equal(boats.isDestroyed, false, 'ManyArray is not destroyed'); + assert.equal(p2groups.isDestroyed, false, 'groups is not destroyed'); + assert.equal(g3people.isDestroyed, false, 'people is not destroyed'); - run(() => person.unloadRecord()); + run(() => person2.unloadRecord()); - assert.equal( - boats.isDestroyed, - false, - 'ManyArray is not destroyed when 1 side is unloaded' - ); - assert.equal(boat2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal(p2groups.isDestroyed, true, 'groups (unloaded side) is destroyed'); + assert.equal(g3people.isDestroyed, false, 'people (inverse) is not destroyed'); + + assert.deepEqual( + person1.get('groups').mapBy('id'), + ['3', '4'], + 'unloaded record in many:many does not affect inverse of inverse' + ); + assert.deepEqual( + group3.get('people').mapBy('id'), + ['1'], + 'unloading acts as delete for sync relationships' + ); + assert.deepEqual( + group4.get('people').mapBy('id'), + ['1'], + 'unloading acts as delete for sync relationships' + ); - return boat2.get('person'); + assert.equal(store.hasRecordForId('person', 2), false, 'unloading removes record from store'); + + person2 = run(() => + store.push({ + data: { + id: 2, + type: 'person', + }, }) - .then(refetchedPerson => { - assert.notEqual(person, refetchedPerson, 'the previously loaded record is not reused'); + ); - assert.deepEqual( - person.hasMany('boats').ids(), - ['2', '3'], - 'unload async is not treated as delete' - ); - assert.equal(boat2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal(store.hasRecordForId('person', 2), true, 'unloaded record can be restored'); + assert.deepEqual( + person2.get('groups').mapBy('id'), + [], + 'restoring unloaded record does not restore relationship' + ); + assert.deepEqual( + group3.get('people').mapBy('id'), + ['1'], + 'restoring unloaded record does not restore relationship' + ); + assert.deepEqual( + group4.get('people').mapBy('id'), + ['1'], + 'restoring unloaded record does not restore relationship' + ); - assert.equal(findManyCalls, 1, 'findMany called as expected'); - assert.equal(findRecordCalls, 1, 'findRecord called as expected'); + run(() => + store.push({ + data: { + id: 2, + type: 'person', + relationships: { + groups: { + data: [ + { + id: 3, + type: 'group', + }, + { + id: 4, + type: 'group', + }, + ], + }, + }, + }, }) - ); -}); + ); -test('1:many async unload many side', function(assert) { - let findManyCalls = 0; + assert.deepEqual( + person2.get('groups').mapBy('id'), + ['3', '4'], + 'after unloading, relationship can be restored' + ); + assert.deepEqual( + group3.get('people').mapBy('id'), + ['1', '2'], + 'after unloading, relationship can be restored' + ); + assert.deepEqual( + group4.get('people').mapBy('id'), + ['1', '2'], + 'after unloading, relationship can be restored' + ); + }); - env.adapter.coalesceFindRequests = true; + test('1:1 async unload', function(assert) { + let findRecordCalls = 0; - env.adapter.findMany = (store, type, ids) => { - assert.equal(type + '', Boat + '', 'findMany(_, type) is correct'); - assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); - ++findManyCalls; + adapter.findRecord = (store, type, id) => { + assert.equal(type, Mortgage, 'findRecord(_, type) is correct'); + assert.equal(id, '2', 'findRecord(_, _, id) is correct'); + ++findRecordCalls; - return { - data: [ - { + return { + data: { id: 2, - type: 'boat', - }, - { - id: 3, - type: 'boat', + type: 'mortgage', }, - ], + }; }; - }; - let person = run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - boats: { - data: [ - { + let person = run(() => + store.push({ + data: { + id: 1, + type: 'person', + relationships: { + mortgage: { + data: { id: 2, - type: 'boat', + type: 'mortgage', }, - { - id: 3, - type: 'boat', - }, - ], + }, }, }, - }, - }) - ); - let boats, boat2, boat3; - - return run(() => - person - .get('boats') - .then(asyncRecords => { - boats = asyncRecords; - [boat2, boat3] = boats.toArray(); - return EmberPromise.all([boat2, boat3].map(b => b.get('person'))); }) - .then(() => { - assert.deepEqual( - person.hasMany('boats').ids(), - ['2', '3'], - 'initially relationship established lhs' - ); - assert.equal(boat2.belongsTo('person').id(), '1', 'initially relationship established rhs'); - assert.equal(boat3.belongsTo('person').id(), '1', 'initially relationship established rhs'); - - assert.deepEqual(boats.mapBy('id'), ['2', '3'], 'many array is initially set up correctly'); - run(() => boat2.unloadRecord()); - assert.deepEqual(boats.mapBy('id'), ['3'], 'unload async removes from previous many array'); - assert.equal(boats.isDestroyed, false, 'previous ManyArray not destroyed'); - - run(() => boat3.unloadRecord()); - assert.deepEqual(boats.mapBy('id'), [], 'unload async removes from previous many array'); - assert.equal(boats.isDestroyed, false, 'previous ManyArray not destroyed'); - - assert.deepEqual( - person.hasMany('boats').ids(), - ['2', '3'], - 'unload async is not treated as delete' - ); - assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - - return person.get('boats'); - }) - .then(refetchedBoats => { - assert.equal( - boats.isDestroyed, - false, - 'previous ManyArray is not immediately destroyed after refetch' - ); - assert.equal( - boats.isDestroying, - true, - 'previous ManyArray is being destroyed immediately after refetch' - ); - assert.deepEqual(refetchedBoats.mapBy('id'), ['2', '3'], 'boats refetched'); - assert.deepEqual( - person.hasMany('boats').ids(), - ['2', '3'], - 'unload async is not treated as delete' - ); - assert.equal(boat3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - - assert.equal(findManyCalls, 2, 'findMany called as expected'); - }) - ).then(() => { - assert.equal( - boats.isDestroyed, - true, - 'previous ManyArray is destroyed in the runloop after refetching' + ); + let mortgage; + + return run(() => + person + .get('mortgage') + .then(asyncRecord => { + mortgage = asyncRecord; + return mortgage.get('person'); + }) + .then(() => { + assert.equal( + mortgage.belongsTo('person').id(), + '1', + 'initially relationship established lhs' + ); + assert.equal( + person.belongsTo('mortgage').id(), + '2', + 'initially relationship established rhs' + ); + + run(() => mortgage.unloadRecord()); + + assert.equal( + person.belongsTo('mortgage').id(), + '2', + 'unload async is not treated as delete' + ); + + return person.get('mortgage'); + }) + .then(refetchedMortgage => { + assert.notEqual( + mortgage, + refetchedMortgage, + 'the previously loaded record is not reused' + ); + + assert.equal( + person.belongsTo('mortgage').id(), + '2', + 'unload async is not treated as delete' + ); + assert.equal( + refetchedMortgage.belongsTo('person').id(), + '1', + 'unload async is not treated as delete' + ); + assert.equal(findRecordCalls, 2); + }) ); }); -}); -test('many:many async unload', function(assert) { - let findManyCalls = 0; + test('1:many async unload 1 side', function(assert) { + let findRecordCalls = 0; + let findManyCalls = 0; - env.adapter.coalesceFindRequests = true; + adapter.coalesceFindRequests = true; - env.adapter.findMany = (store, type, ids) => { - assert.equal(type + '', Person + '', 'findMany(_, type) is correct'); - assert.deepEqual(ids, ['3', '4'], 'findMany(_, _, ids) is correct'); - ++findManyCalls; + adapter.findRecord = (store, type, id) => { + assert.equal(type, Person, 'findRecord(_, type) is correct'); + assert.deepEqual(id, '1', 'findRecord(_, _, id) is correct'); + ++findRecordCalls; - return { - data: [ - { - id: 3, - type: 'person', - }, - { - id: 4, + return { + data: { + id: 1, type: 'person', }, - ], + }; }; - }; - let [person1, person2] = run(() => - env.store.push({ - data: [ - { + adapter.findMany = (store, type, ids) => { + assert.equal(type + '', Boat + '', 'findMany(_, type) is correct'); + assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); + ++findManyCalls; + + return { + data: [ + { + id: 2, + type: 'boat', + }, + { + id: 3, + type: 'boat', + }, + ], + }; + }; + + let person = run(() => + store.push({ + data: { id: 1, type: 'person', relationships: { - friends: { + boats: { data: [ { - id: 3, - type: 'person', + id: 2, + type: 'boat', }, { - id: 4, - type: 'person', + id: 3, + type: 'boat', }, ], }, }, }, - { - id: 2, + }) + ); + let boats, boat2, boat3; + + return run(() => + person + .get('boats') + .then(asyncRecords => { + boats = asyncRecords; + [boat2, boat3] = boats.toArray(); + return EmberPromise.all([boat2, boat3].map(b => b.get('person'))); + }) + .then(() => { + assert.deepEqual( + person.hasMany('boats').ids(), + ['2', '3'], + 'initially relationship established lhs' + ); + assert.equal( + boat2.belongsTo('person').id(), + '1', + 'initially relationship established rhs' + ); + assert.equal( + boat3.belongsTo('person').id(), + '1', + 'initially relationship established rhs' + ); + + assert.equal(boats.isDestroyed, false, 'ManyArray is not destroyed'); + + run(() => person.unloadRecord()); + + assert.equal( + boats.isDestroyed, + false, + 'ManyArray is not destroyed when 1 side is unloaded' + ); + assert.equal( + boat2.belongsTo('person').id(), + '1', + 'unload async is not treated as delete' + ); + assert.equal( + boat3.belongsTo('person').id(), + '1', + 'unload async is not treated as delete' + ); + + return boat2.get('person'); + }) + .then(refetchedPerson => { + assert.notEqual(person, refetchedPerson, 'the previously loaded record is not reused'); + + assert.deepEqual( + person.hasMany('boats').ids(), + ['2', '3'], + 'unload async is not treated as delete' + ); + assert.equal( + boat2.belongsTo('person').id(), + '1', + 'unload async is not treated as delete' + ); + assert.equal( + boat3.belongsTo('person').id(), + '1', + 'unload async is not treated as delete' + ); + + assert.equal(findManyCalls, 1, 'findMany called as expected'); + assert.equal(findRecordCalls, 1, 'findRecord called as expected'); + }) + ); + }); + + test('1:many async unload many side', function(assert) { + let findManyCalls = 0; + + adapter.coalesceFindRequests = true; + + adapter.findMany = (store, type, ids) => { + assert.equal(type + '', Boat + '', 'findMany(_, type) is correct'); + assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); + ++findManyCalls; + + return { + data: [ + { + id: 2, + type: 'boat', + }, + { + id: 3, + type: 'boat', + }, + ], + }; + }; + + let person = run(() => + store.push({ + data: { + id: 1, type: 'person', relationships: { - friends: { + boats: { data: [ { - id: 3, - type: 'person', + id: 2, + type: 'boat', }, { - id: 4, - type: 'person', + id: 3, + type: 'boat', }, ], }, }, }, - ], - }) - ); - - let person1Friends, person3, person4; - - return run(() => - person1 - .get('friends') - .then(asyncRecords => { - person1Friends = asyncRecords; - [person3, person4] = person1Friends.toArray(); - return EmberPromise.all([person2, person3, person4].map(b => b.get('friends'))); - }) - .then(() => { - assert.deepEqual( - person1.hasMany('friends').ids(), - ['3', '4'], - 'initially relationship established lhs' - ); - assert.deepEqual( - person2.hasMany('friends').ids(), - ['3', '4'], - 'initially relationship established lhs' - ); - assert.deepEqual( - person3.hasMany('friends').ids(), - ['1', '2'], - 'initially relationship established rhs' - ); - assert.deepEqual( - person4.hasMany('friends').ids(), - ['1', '2'], - 'initially relationship established rhs' - ); - - run(() => person3.unloadRecord()); - assert.deepEqual( - person1Friends.mapBy('id'), - ['4'], - 'unload async removes from previous many array' - ); - assert.equal(person1Friends.isDestroyed, false, 'previous ManyArray not destroyed'); - - run(() => person4.unloadRecord()); - assert.deepEqual( - person1Friends.mapBy('id'), - [], - 'unload async removes from previous many array' - ); - assert.equal(person1Friends.isDestroyed, false, 'previous ManyArray not destroyed'); - - assert.deepEqual( - person1.hasMany('friends').ids(), - ['3', '4'], - 'unload async is not treated as delete' - ); - - return person1.get('friends'); - }) - .then(refetchedFriends => { - assert.equal( - person1Friends.isDestroyed, - false, - 'previous ManyArray is not immediately destroyed after refetch' - ); - assert.equal( - person1Friends.isDestroying, - true, - 'previous ManyArray is being destroyed immediately after refetch' - ); - assert.deepEqual(refetchedFriends.mapBy('id'), ['3', '4'], 'friends refetched'); - assert.deepEqual( - person1.hasMany('friends').ids(), - ['3', '4'], - 'unload async is not treated as delete' - ); - - assert.deepEqual( - refetchedFriends.map(p => p.hasMany('friends').ids()), - [['1', '2'], ['1', '2']], - 'unload async is not treated as delete' - ); - - assert.equal(findManyCalls, 2, 'findMany called as expected'); }) - ).then(() => { - assert.equal( - person1Friends.isDestroyed, - true, - 'previous ManyArray is destroyed in the runloop after refetching' ); + let boats, boat2, boat3; + + return run(() => + person + .get('boats') + .then(asyncRecords => { + boats = asyncRecords; + [boat2, boat3] = boats.toArray(); + return EmberPromise.all([boat2, boat3].map(b => b.get('person'))); + }) + .then(() => { + assert.deepEqual( + person.hasMany('boats').ids(), + ['2', '3'], + 'initially relationship established lhs' + ); + assert.equal( + boat2.belongsTo('person').id(), + '1', + 'initially relationship established rhs' + ); + assert.equal( + boat3.belongsTo('person').id(), + '1', + 'initially relationship established rhs' + ); + + assert.deepEqual( + boats.mapBy('id'), + ['2', '3'], + 'many array is initially set up correctly' + ); + run(() => boat2.unloadRecord()); + assert.deepEqual( + boats.mapBy('id'), + ['3'], + 'unload async removes from previous many array' + ); + assert.equal(boats.isDestroyed, false, 'previous ManyArray not destroyed'); + + run(() => boat3.unloadRecord()); + assert.deepEqual(boats.mapBy('id'), [], 'unload async removes from previous many array'); + assert.equal(boats.isDestroyed, false, 'previous ManyArray not destroyed'); + + assert.deepEqual( + person.hasMany('boats').ids(), + ['2', '3'], + 'unload async is not treated as delete' + ); + assert.equal( + boat3.belongsTo('person').id(), + '1', + 'unload async is not treated as delete' + ); + + return person.get('boats'); + }) + .then(refetchedBoats => { + assert.equal( + boats.isDestroyed, + false, + 'previous ManyArray is not immediately destroyed after refetch' + ); + assert.equal( + boats.isDestroying, + true, + 'previous ManyArray is being destroyed immediately after refetch' + ); + assert.deepEqual(refetchedBoats.mapBy('id'), ['2', '3'], 'boats refetched'); + assert.deepEqual( + person.hasMany('boats').ids(), + ['2', '3'], + 'unload async is not treated as delete' + ); + assert.equal( + boat3.belongsTo('person').id(), + '1', + 'unload async is not treated as delete' + ); + + assert.equal(findManyCalls, 2, 'findMany called as expected'); + }) + ).then(() => { + assert.equal( + boats.isDestroyed, + true, + 'previous ManyArray is destroyed in the runloop after refetching' + ); + }); }); -}); - -test('1 sync : 1 async unload sync side', function(assert) { - run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - favoriteBook: { - data: { - id: 2, - type: 'book', - }, - }, - }, - }, - included: [ - { - id: 2, - type: 'book', - }, - ], - }) - ); - let person = env.store.peekRecord('person', 1); - let book = env.store.peekRecord('book', 2); + test('many:many async unload', function(assert) { + let findManyCalls = 0; - return book.get('person').then(() => { - assert.equal(person.get('favoriteBook.id'), 2, 'initially relationship established lhs'); - assert.equal(book.belongsTo('person').id(), 1, 'initially relationship established rhs'); + adapter.coalesceFindRequests = true; - run(() => book.unloadRecord()); + adapter.findMany = (store, type, ids) => { + assert.equal(type + '', Person + '', 'findMany(_, type) is correct'); + assert.deepEqual(ids, ['3', '4'], 'findMany(_, _, ids) is correct'); + ++findManyCalls; - assert.equal(person.get('book'), null, 'unloading acts as a delete for sync relationships'); - assert.equal(env.store.hasRecordForId('book', 2), false, 'unloaded record gone from store'); + return { + data: [ + { + id: 3, + type: 'person', + }, + { + id: 4, + type: 'person', + }, + ], + }; + }; - book = run(() => - env.store.push({ - data: { - id: 2, - type: 'book', - }, + let [person1, person2] = run(() => + store.push({ + data: [ + { + id: 1, + type: 'person', + relationships: { + friends: { + data: [ + { + id: 3, + type: 'person', + }, + { + id: 4, + type: 'person', + }, + ], + }, + }, + }, + { + id: 2, + type: 'person', + relationships: { + friends: { + data: [ + { + id: 3, + type: 'person', + }, + { + id: 4, + type: 'person', + }, + ], + }, + }, + }, + ], }) ); - assert.equal(env.store.hasRecordForId('book', 2), true, 'unloaded record can be restored'); - assert.equal( - person.get('book'), - null, - 'restoring unloaded record does not restore relationship' - ); - assert.equal( - book.belongsTo('person').id(), - null, - 'restoring unloaded record does not restore relationship' - ); + let person1Friends, person3, person4; + + return run(() => + person1 + .get('friends') + .then(asyncRecords => { + person1Friends = asyncRecords; + [person3, person4] = person1Friends.toArray(); + return EmberPromise.all([person2, person3, person4].map(b => b.get('friends'))); + }) + .then(() => { + assert.deepEqual( + person1.hasMany('friends').ids(), + ['3', '4'], + 'initially relationship established lhs' + ); + assert.deepEqual( + person2.hasMany('friends').ids(), + ['3', '4'], + 'initially relationship established lhs' + ); + assert.deepEqual( + person3.hasMany('friends').ids(), + ['1', '2'], + 'initially relationship established rhs' + ); + assert.deepEqual( + person4.hasMany('friends').ids(), + ['1', '2'], + 'initially relationship established rhs' + ); + + run(() => person3.unloadRecord()); + assert.deepEqual( + person1Friends.mapBy('id'), + ['4'], + 'unload async removes from previous many array' + ); + assert.equal(person1Friends.isDestroyed, false, 'previous ManyArray not destroyed'); + + run(() => person4.unloadRecord()); + assert.deepEqual( + person1Friends.mapBy('id'), + [], + 'unload async removes from previous many array' + ); + assert.equal(person1Friends.isDestroyed, false, 'previous ManyArray not destroyed'); + + assert.deepEqual( + person1.hasMany('friends').ids(), + ['3', '4'], + 'unload async is not treated as delete' + ); + + return person1.get('friends'); + }) + .then(refetchedFriends => { + assert.equal( + person1Friends.isDestroyed, + false, + 'previous ManyArray is not immediately destroyed after refetch' + ); + assert.equal( + person1Friends.isDestroying, + true, + 'previous ManyArray is being destroyed immediately after refetch' + ); + assert.deepEqual(refetchedFriends.mapBy('id'), ['3', '4'], 'friends refetched'); + assert.deepEqual( + person1.hasMany('friends').ids(), + ['3', '4'], + 'unload async is not treated as delete' + ); + + assert.deepEqual( + refetchedFriends.map(p => p.hasMany('friends').ids()), + [['1', '2'], ['1', '2']], + 'unload async is not treated as delete' + ); + + assert.equal(findManyCalls, 2, 'findMany called as expected'); + }) + ).then(() => { + assert.equal( + person1Friends.isDestroyed, + true, + 'previous ManyArray is destroyed in the runloop after refetching' + ); + }); + }); + test('1 sync : 1 async unload sync side', function(assert) { run(() => - env.store.push({ + store.push({ data: { - id: 2, - type: 'book', + id: 1, + type: 'person', relationships: { - person: { + favoriteBook: { data: { - id: 1, - type: 'person', + id: 2, + type: 'book', }, }, }, }, + included: [ + { + id: 2, + type: 'book', + }, + ], }) ); - assert.equal(person.get('favoriteBook.id'), 2, 'after unloading, relationship can be restored'); - assert.equal(book.get('person.id'), 1, 'after unloading, relationship can be restored'); - }); -}); + let person = store.peekRecord('person', 1); + let book = store.peekRecord('book', 2); -test('1 sync : 1 async unload async side', function(assert) { - let findRecordCalls = 0; + return book.get('person').then(() => { + assert.equal(person.get('favoriteBook.id'), 2, 'initially relationship established lhs'); + assert.equal(book.belongsTo('person').id(), 1, 'initially relationship established rhs'); - env.adapter.findRecord = (store, type, id) => { - assert.equal(type, Person, 'findRecord(_, type) is correct'); - assert.equal(id, '1', 'findRecord(_, _, id) is correct'); - ++findRecordCalls; + run(() => book.unloadRecord()); - return { - data: { - id: 1, - type: 'person', - }, - }; - }; + assert.equal(person.get('book'), null, 'unloading acts as a delete for sync relationships'); + assert.equal(store.hasRecordForId('book', 2), false, 'unloaded record gone from store'); - run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - favoriteBook: { - data: { - id: 2, - type: 'book', - }, + book = run(() => + store.push({ + data: { + id: 2, + type: 'book', }, - }, - }, - included: [ - { - id: 2, - type: 'book', - }, - ], - }) - ); + }) + ); - let person = env.store.peekRecord('person', 1); - let book = env.store.peekRecord('book', 2); + assert.equal(store.hasRecordForId('book', 2), true, 'unloaded record can be restored'); + assert.equal( + person.get('book'), + null, + 'restoring unloaded record does not restore relationship' + ); + assert.equal( + book.belongsTo('person').id(), + null, + 'restoring unloaded record does not restore relationship' + ); - return run(() => - book - .get('person') - .then(() => { - assert.equal(person.get('favoriteBook.id'), 2, 'initially relationship established lhs'); - assert.equal(book.belongsTo('person').id(), 1, 'initially relationship established rhs'); + run(() => + store.push({ + data: { + id: 2, + type: 'book', + relationships: { + person: { + data: { + id: 1, + type: 'person', + }, + }, + }, + }, + }) + ); - run(() => person.unloadRecord()); + assert.equal( + person.get('favoriteBook.id'), + 2, + 'after unloading, relationship can be restored' + ); + assert.equal(book.get('person.id'), 1, 'after unloading, relationship can be restored'); + }); + }); - assert.equal(book.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + test('1 sync : 1 async unload async side', function(assert) { + let findRecordCalls = 0; - return book.get('person'); - }) - .then(refetchedPerson => { - assert.notEqual(person, refetchedPerson, 'the previously loaded record is not reused'); + adapter.findRecord = (store, type, id) => { + assert.equal(type, Person, 'findRecord(_, type) is correct'); + assert.equal(id, '1', 'findRecord(_, _, id) is correct'); + ++findRecordCalls; - assert.equal(book.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - assert.equal( - refetchedPerson.get('favoriteBook.id'), - '2', - 'unload async is not treated as delete' - ); - assert.equal(findRecordCalls, 1); - }) - ); -}); + return { + data: { + id: 1, + type: 'person', + }, + }; + }; -test('1 async : many sync unload sync side', function(assert) { - run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - favoriteSpoons: { - data: [ - { + run(() => + store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteBook: { + data: { id: 2, - type: 'spoon', - }, - { - id: 3, - type: 'spoon', + type: 'book', }, - ], + }, }, }, - }, - included: [ - { - id: 2, - type: 'spoon', - }, - { - id: 3, - type: 'spoon', - }, - ], - }) - ); - - let person = env.store.peekRecord('person', 1); - let spoon2 = env.store.peekRecord('spoon', 2); - let spoon3 = env.store.peekRecord('spoon', 3); - let spoons = person.get('favoriteSpoons'); - - assert.equal(spoons.isDestroyed, false, 'ManyArray not destroyed'); - assert.deepEqual( - person.get('favoriteSpoons').mapBy('id'), - ['2', '3'], - 'initialy relationship established lhs' - ); - assert.equal(spoon2.belongsTo('person').id(), '1', 'initially relationship established rhs'); - assert.equal(spoon3.belongsTo('person').id(), '1', 'initially relationship established rhs'); - - run(() => spoon2.unloadRecord()); - - assert.equal(env.store.hasRecordForId('spoon', 2), false, 'unloaded record gone from store'); - - assert.equal(spoons.isDestroyed, false, 'ManyArray not destroyed'); - assert.deepEqual( - person.get('favoriteSpoons').mapBy('id'), - ['3'], - 'unload sync relationship acts as delete' - ); - assert.equal( - spoon3.belongsTo('person').id(), - '1', - 'unloading one of a sync hasMany does not affect the rest' - ); - - spoon2 = run(() => - env.store.push({ - data: { - id: 2, - type: 'spoon', - }, - }) - ); - - assert.equal(env.store.hasRecordForId('spoon', 2), true, 'unloaded record can be restored'); - assert.deepEqual( - person.get('favoriteSpoons').mapBy('id'), - ['3'], - 'restoring unloaded record does not restore relationship' - ); - assert.equal( - spoon2.belongsTo('person').id(), - null, - 'restoring unloaded record does not restore relationship' - ); - - run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - favoriteSpoons: { - data: [ - { - id: 2, - type: 'spoon', - }, - { - id: 3, - type: 'spoon', - }, - ], + included: [ + { + id: 2, + type: 'book', }, - }, - }, - }) - ); - - assert.equal( - spoon2.belongsTo('person').id(), - '1', - 'after unloading, relationship can be restored' - ); - assert.deepEqual( - person.get('favoriteSpoons').mapBy('id'), - ['2', '3'], - 'after unloading, relationship can be restored' - ); -}); - -test('1 async : many sync unload async side', function(assert) { - let findRecordCalls = 0; - - env.adapter.coalesceFindRequests = true; - - env.adapter.findRecord = (store, type, id) => { - assert.equal(type, Person, 'findRecord(_, type) is correct'); - assert.deepEqual(id, '1', 'findRecord(_, _, id) is correct'); - ++findRecordCalls; + ], + }) + ); - return { - data: { - id: 1, - type: 'person', - }, - }; - }; + let person = store.peekRecord('person', 1); + let book = store.peekRecord('book', 2); + + return run(() => + book + .get('person') + .then(() => { + assert.equal(person.get('favoriteBook.id'), 2, 'initially relationship established lhs'); + assert.equal(book.belongsTo('person').id(), 1, 'initially relationship established rhs'); + + run(() => person.unloadRecord()); + + assert.equal(book.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + + return book.get('person'); + }) + .then(refetchedPerson => { + assert.notEqual(person, refetchedPerson, 'the previously loaded record is not reused'); + + assert.equal(book.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal( + refetchedPerson.get('favoriteBook.id'), + '2', + 'unload async is not treated as delete' + ); + assert.equal(findRecordCalls, 1); + }) + ); + }); - let person = run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - favoriteSpoons: { - data: [ - { - id: 2, - type: 'spoon', - }, - { - id: 3, - type: 'spoon', - }, - ], + test('1 async : many sync unload sync side', function(assert) { + run(() => + store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteSpoons: { + data: [ + { + id: 2, + type: 'spoon', + }, + { + id: 3, + type: 'spoon', + }, + ], + }, }, }, - }, - included: [ - { - id: 2, - type: 'spoon', - }, - { - id: 3, - type: 'spoon', - }, - ], - }) - ); - let spoon2 = env.store.peekRecord('spoon', 2); - let spoon3 = env.store.peekRecord('spoon', 3); - let spoons = person.get('favoriteSpoons'); - - return run(() => { + included: [ + { + id: 2, + type: 'spoon', + }, + { + id: 3, + type: 'spoon', + }, + ], + }) + ); + + let person = store.peekRecord('person', 1); + let spoon2 = store.peekRecord('spoon', 2); + let spoon3 = store.peekRecord('spoon', 3); + let spoons = person.get('favoriteSpoons'); + + assert.equal(spoons.isDestroyed, false, 'ManyArray not destroyed'); assert.deepEqual( person.get('favoriteSpoons').mapBy('id'), ['2', '3'], - 'initially relationship established lhs' + 'initialy relationship established lhs' ); assert.equal(spoon2.belongsTo('person').id(), '1', 'initially relationship established rhs'); assert.equal(spoon3.belongsTo('person').id(), '1', 'initially relationship established rhs'); - assert.equal(spoons.isDestroyed, false, 'ManyArray is not destroyed'); + run(() => spoon2.unloadRecord()); - run(() => person.unloadRecord()); + assert.equal(store.hasRecordForId('spoon', 2), false, 'unloaded record gone from store'); + + assert.equal(spoons.isDestroyed, false, 'ManyArray not destroyed'); + assert.deepEqual( + person.get('favoriteSpoons').mapBy('id'), + ['3'], + 'unload sync relationship acts as delete' + ); + assert.equal( + spoon3.belongsTo('person').id(), + '1', + 'unloading one of a sync hasMany does not affect the rest' + ); + + spoon2 = run(() => + store.push({ + data: { + id: 2, + type: 'spoon', + }, + }) + ); - assert.equal(spoons.isDestroyed, false, 'ManyArray is not destroyed when 1 side is unloaded'); - assert.equal(spoon2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - assert.equal(spoon3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal(store.hasRecordForId('spoon', 2), true, 'unloaded record can be restored'); + assert.deepEqual( + person.get('favoriteSpoons').mapBy('id'), + ['3'], + 'restoring unloaded record does not restore relationship' + ); + assert.equal( + spoon2.belongsTo('person').id(), + null, + 'restoring unloaded record does not restore relationship' + ); - return spoon2.get('person'); - }).then(refetchedPerson => { - assert.notEqual(person, refetchedPerson, 'the previously loaded record is not reused'); + run(() => + store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteSpoons: { + data: [ + { + id: 2, + type: 'spoon', + }, + { + id: 3, + type: 'spoon', + }, + ], + }, + }, + }, + }) + ); + assert.equal( + spoon2.belongsTo('person').id(), + '1', + 'after unloading, relationship can be restored' + ); assert.deepEqual( person.get('favoriteSpoons').mapBy('id'), ['2', '3'], - 'unload async is not treated as delete' + 'after unloading, relationship can be restored' ); - assert.equal(spoon2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - assert.equal(spoon3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - - assert.equal(findRecordCalls, 1, 'findRecord called as expected'); }); -}); -test('1 sync : many async unload async side', function(assert) { - let findManyCalls = 0; + test('1 async : many sync unload async side', function(assert) { + let findRecordCalls = 0; - env.adapter.coalesceFindRequests = true; + adapter.coalesceFindRequests = true; - env.adapter.findMany = (store, type, ids) => { - assert.equal(type + '', Show + '', 'findMany(_, type) is correct'); - assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); - ++findManyCalls; + adapter.findRecord = (store, type, id) => { + assert.equal(type, Person, 'findRecord(_, type) is correct'); + assert.deepEqual(id, '1', 'findRecord(_, _, id) is correct'); + ++findRecordCalls; - return { - data: [ - { - id: 2, - type: 'show', - }, - { - id: 3, - type: 'show', + return { + data: { + id: 1, + type: 'person', }, - ], + }; }; - }; - let person = run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - favoriteShows: { - data: [ - { - id: 2, - type: 'show', - }, - { - id: 3, - type: 'show', - }, - ], + let person = run(() => + store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteSpoons: { + data: [ + { + id: 2, + type: 'spoon', + }, + { + id: 3, + type: 'spoon', + }, + ], + }, }, }, - }, - }) - ); - - let shows, show2, show3; - - return run(() => - person - .get('favoriteShows') - .then(asyncRecords => { - shows = asyncRecords; - [show2, show3] = shows.toArray(); - - assert.deepEqual( - person.hasMany('favoriteShows').ids(), - ['2', '3'], - 'initially relationship established lhs' - ); - assert.equal(show2.get('person.id'), '1', 'initially relationship established rhs'); - assert.equal(show3.get('person.id'), '1', 'initially relationship established rhs'); - assert.deepEqual(shows.mapBy('id'), ['2', '3'], 'many array is initially set up correctly'); + included: [ + { + id: 2, + type: 'spoon', + }, + { + id: 3, + type: 'spoon', + }, + ], + }) + ); + let spoon2 = store.peekRecord('spoon', 2); + let spoon3 = store.peekRecord('spoon', 3); + let spoons = person.get('favoriteSpoons'); + + return run(() => { + assert.deepEqual( + person.get('favoriteSpoons').mapBy('id'), + ['2', '3'], + 'initially relationship established lhs' + ); + assert.equal(spoon2.belongsTo('person').id(), '1', 'initially relationship established rhs'); + assert.equal(spoon3.belongsTo('person').id(), '1', 'initially relationship established rhs'); - run(() => show2.unloadRecord()); + assert.equal(spoons.isDestroyed, false, 'ManyArray is not destroyed'); - assert.deepEqual(shows.mapBy('id'), ['3'], 'unload async removes from previous many array'); - assert.equal(shows.isDestroyed, false, 'previous many array not destroyed'); + run(() => person.unloadRecord()); - run(() => show3.unloadRecord()); + assert.equal(spoons.isDestroyed, false, 'ManyArray is not destroyed when 1 side is unloaded'); + assert.equal(spoon2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal(spoon3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - assert.deepEqual(shows.mapBy('id'), [], 'unload async removes from previous many array'); - assert.equal(shows.isDestroyed, false, 'previous many array not destroyed'); - assert.deepEqual( - person.hasMany('favoriteShows').ids(), - ['2', '3'], - 'unload async is not treated as delete' - ); + return spoon2.get('person'); + }).then(refetchedPerson => { + assert.notEqual(person, refetchedPerson, 'the previously loaded record is not reused'); - return person.get('favoriteShows'); - }) - .then(refetchedShows => { - assert.equal( - shows.isDestroyed, - false, - 'previous ManyArray is not immediately destroyed after refetch' - ); - assert.equal( - shows.isDestroying, - true, - 'previous ManyArray is being destroyed immediately after refetch' - ); - assert.deepEqual(refetchedShows.mapBy('id'), ['2', '3'], 'shows refetched'); - assert.deepEqual( - person.hasMany('favoriteShows').ids(), - ['2', '3'], - 'unload async is not treated as delete' - ); + assert.deepEqual( + person.get('favoriteSpoons').mapBy('id'), + ['2', '3'], + 'unload async is not treated as delete' + ); + assert.equal(spoon2.belongsTo('person').id(), '1', 'unload async is not treated as delete'); + assert.equal(spoon3.belongsTo('person').id(), '1', 'unload async is not treated as delete'); - assert.equal(findManyCalls, 2, 'findMany called as expected'); - }) - ).then(() => { - assert.equal( - shows.isDestroyed, - true, - 'previous ManyArray is destroyed in the runloop after refetching' - ); + assert.equal(findRecordCalls, 1, 'findRecord called as expected'); + }); }); -}); -test('1 sync : many async unload sync side', function(assert) { - let findManyCalls = 0; + test('1 sync : many async unload async side', function(assert) { + let findManyCalls = 0; - env.adapter.coalesceFindRequests = true; + adapter.coalesceFindRequests = true; - env.adapter.findMany = (store, type, ids) => { - assert.equal(type + '', Show + '', 'findMany(_, type) is correct'); - assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); - ++findManyCalls; + adapter.findMany = (store, type, ids) => { + assert.equal(type + '', Show + '', 'findMany(_, type) is correct'); + assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); + ++findManyCalls; - return { - data: [ - { - id: 2, - type: 'show', - }, - { - id: 3, - type: 'show', - }, - ], + return { + data: [ + { + id: 2, + type: 'show', + }, + { + id: 3, + type: 'show', + }, + ], + }; }; - }; - let person = run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - favoriteShows: { - data: [ - { - id: 2, - type: 'show', - }, - { - id: 3, - type: 'show', - }, - ], + let person = run(() => + store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteShows: { + data: [ + { + id: 2, + type: 'show', + }, + { + id: 3, + type: 'show', + }, + ], + }, }, }, - }, - }) - ); - - let shows, show2, show3; - - return run(() => - person - .get('favoriteShows') - .then(asyncRecords => { - shows = asyncRecords; - [show2, show3] = shows.toArray(); - - assert.deepEqual( - person.hasMany('favoriteShows').ids(), - ['2', '3'], - 'initially relationship established lhs' - ); - assert.equal(show2.get('person.id'), '1', 'initially relationship established rhs'); - assert.equal(show3.get('person.id'), '1', 'initially relationship established rhs'); - assert.deepEqual(shows.mapBy('id'), ['2', '3'], 'many array is initially set up correctly'); + }) + ); - run(() => person.unloadRecord()); + let shows, show2, show3; + + return run(() => + person + .get('favoriteShows') + .then(asyncRecords => { + shows = asyncRecords; + [show2, show3] = shows.toArray(); + + assert.deepEqual( + person.hasMany('favoriteShows').ids(), + ['2', '3'], + 'initially relationship established lhs' + ); + assert.equal(show2.get('person.id'), '1', 'initially relationship established rhs'); + assert.equal(show3.get('person.id'), '1', 'initially relationship established rhs'); + assert.deepEqual( + shows.mapBy('id'), + ['2', '3'], + 'many array is initially set up correctly' + ); + + run(() => show2.unloadRecord()); + + assert.deepEqual( + shows.mapBy('id'), + ['3'], + 'unload async removes from previous many array' + ); + assert.equal(shows.isDestroyed, false, 'previous many array not destroyed'); + + run(() => show3.unloadRecord()); + + assert.deepEqual(shows.mapBy('id'), [], 'unload async removes from previous many array'); + assert.equal(shows.isDestroyed, false, 'previous many array not destroyed'); + assert.deepEqual( + person.hasMany('favoriteShows').ids(), + ['2', '3'], + 'unload async is not treated as delete' + ); + + return person.get('favoriteShows'); + }) + .then(refetchedShows => { + assert.equal( + shows.isDestroyed, + false, + 'previous ManyArray is not immediately destroyed after refetch' + ); + assert.equal( + shows.isDestroying, + true, + 'previous ManyArray is being destroyed immediately after refetch' + ); + assert.deepEqual(refetchedShows.mapBy('id'), ['2', '3'], 'shows refetched'); + assert.deepEqual( + person.hasMany('favoriteShows').ids(), + ['2', '3'], + 'unload async is not treated as delete' + ); + + assert.equal(findManyCalls, 2, 'findMany called as expected'); + }) + ).then(() => { + assert.equal( + shows.isDestroyed, + true, + 'previous ManyArray is destroyed in the runloop after refetching' + ); + }); + }); - assert.equal( - env.store.hasRecordForId('person', 1), - false, - 'unloaded record gone from store' - ); + test('1 sync : many async unload sync side', function(assert) { + let findManyCalls = 0; - assert.equal(shows.isDestroyed, true, 'previous manyarray immediately destroyed'); - assert.equal( - show2.get('person.id'), - null, - 'unloading acts as delete for sync relationships' - ); - assert.equal( - show3.get('person.id'), - null, - 'unloading acts as delete for sync relationships' - ); + adapter.coalesceFindRequests = true; - person = run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - }, - }) - ); + adapter.findMany = (store, type, ids) => { + assert.equal(type + '', Show + '', 'findMany(_, type) is correct'); + assert.deepEqual(ids, ['2', '3'], 'findMany(_, _, ids) is correct'); + ++findManyCalls; - assert.equal( - env.store.hasRecordForId('person', 1), - true, - 'unloaded record can be restored' - ); - assert.deepEqual( - person.hasMany('favoriteShows').ids(), - [], - 'restoring unloaded record does not restore relationship' - ); - assert.equal( - show2.get('person.id'), - null, - 'restoring unloaded record does not restore relationship' - ); - assert.equal( - show3.get('person.id'), - null, - 'restoring unloaded record does not restore relationship' - ); + return { + data: [ + { + id: 2, + type: 'show', + }, + { + id: 3, + type: 'show', + }, + ], + }; + }; - run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - favoriteShows: { - data: [ - { - id: 2, - type: 'show', - }, - { - id: 3, - type: 'show', - }, - ], + let person = run(() => + store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteShows: { + data: [ + { + id: 2, + type: 'show', }, - }, + { + id: 3, + type: 'show', + }, + ], }, - }) - ); - - assert.deepEqual( - person.hasMany('favoriteShows').ids(), - ['2', '3'], - 'relationship can be restored' - ); - - return person.get('favoriteShows'); + }, + }, }) - .then(refetchedShows => { - assert.notEqual(refetchedShows, shows, 'ManyArray not reused'); - assert.deepEqual( - refetchedShows.mapBy('id'), - ['2', '3'], - 'unload async not treated as a delete' - ); + ); - assert.equal(findManyCalls, 1, 'findMany calls as expected'); - }) - ); -}); + let shows, show2, show3; + + return run(() => + person + .get('favoriteShows') + .then(asyncRecords => { + shows = asyncRecords; + [show2, show3] = shows.toArray(); + + assert.deepEqual( + person.hasMany('favoriteShows').ids(), + ['2', '3'], + 'initially relationship established lhs' + ); + assert.equal(show2.get('person.id'), '1', 'initially relationship established rhs'); + assert.equal(show3.get('person.id'), '1', 'initially relationship established rhs'); + assert.deepEqual( + shows.mapBy('id'), + ['2', '3'], + 'many array is initially set up correctly' + ); + + run(() => person.unloadRecord()); + + assert.equal(store.hasRecordForId('person', 1), false, 'unloaded record gone from store'); + + assert.equal(shows.isDestroyed, true, 'previous manyarray immediately destroyed'); + assert.equal( + show2.get('person.id'), + null, + 'unloading acts as delete for sync relationships' + ); + assert.equal( + show3.get('person.id'), + null, + 'unloading acts as delete for sync relationships' + ); + + person = run(() => + store.push({ + data: { + id: 1, + type: 'person', + }, + }) + ); + + assert.equal(store.hasRecordForId('person', 1), true, 'unloaded record can be restored'); + assert.deepEqual( + person.hasMany('favoriteShows').ids(), + [], + 'restoring unloaded record does not restore relationship' + ); + assert.equal( + show2.get('person.id'), + null, + 'restoring unloaded record does not restore relationship' + ); + assert.equal( + show3.get('person.id'), + null, + 'restoring unloaded record does not restore relationship' + ); + + run(() => + store.push({ + data: { + id: 1, + type: 'person', + relationships: { + favoriteShows: { + data: [ + { + id: 2, + type: 'show', + }, + { + id: 3, + type: 'show', + }, + ], + }, + }, + }, + }) + ); + + assert.deepEqual( + person.hasMany('favoriteShows').ids(), + ['2', '3'], + 'relationship can be restored' + ); + + return person.get('favoriteShows'); + }) + .then(refetchedShows => { + assert.notEqual(refetchedShows, shows, 'ManyArray not reused'); + assert.deepEqual( + refetchedShows.mapBy('id'), + ['2', '3'], + 'unload async not treated as a delete' + ); + + assert.equal(findManyCalls, 1, 'findMany calls as expected'); + }) + ); + }); -test('unload invalidates link promises', function(assert) { - let isUnloaded = false; - env.adapter.coalesceFindRequests = false; + test('unload invalidates link promises', function(assert) { + let isUnloaded = false; + adapter.coalesceFindRequests = false; - env.adapter.findRecord = (/* store, type, id */) => { - assert.notOk('Records only expected to be loaded via link'); - }; + adapter.findRecord = (/* store, type, id */) => { + assert.notOk('Records only expected to be loaded via link'); + }; - env.adapter.findHasMany = (store, snapshot, link) => { - assert.equal(snapshot.modelName, 'person', 'findHasMany(_, snapshot) is correct'); - assert.equal(link, 'boats', 'findHasMany(_, _, link) is correct'); + adapter.findHasMany = (store, snapshot, link) => { + assert.equal(snapshot.modelName, 'person', 'findHasMany(_, snapshot) is correct'); + assert.equal(link, 'boats', 'findHasMany(_, _, link) is correct'); - let relationships = { - person: { - data: { - type: 'person', - id: 1, + let relationships = { + person: { + data: { + type: 'person', + id: 1, + }, }, - }, - }; + }; - let data = [ - { - id: 3, - type: 'boat', - relationships, - }, - ]; + let data = [ + { + id: 3, + type: 'boat', + relationships, + }, + ]; - if (!isUnloaded) { - data.unshift({ - id: 2, - type: 'boat', - relationships, - }); - } + if (!isUnloaded) { + data.unshift({ + id: 2, + type: 'boat', + relationships, + }); + } - return { - data, + return { + data, + }; }; - }; - let person = run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - relationships: { - boats: { - links: { related: 'boats' }, + let person = run(() => + store.push({ + data: { + id: 1, + type: 'person', + relationships: { + boats: { + links: { related: 'boats' }, + }, }, }, - }, - }) - ); - let boats, boat2, boat3; - - return run(() => - person - .get('boats') - .then(asyncRecords => { - boats = asyncRecords; - [boat2, boat3] = boats.toArray(); - }) - .then(() => { - assert.deepEqual( - person.hasMany('boats').ids(), - ['2', '3'], - 'initially relationship established rhs' - ); - assert.equal(boat2.belongsTo('person').id(), '1', 'initially relationship established rhs'); - assert.equal(boat3.belongsTo('person').id(), '1', 'initially relationship established rhs'); - - isUnloaded = true; - run(() => { - boat2.unloadRecord(); - person.get('boats'); - }); - - assert.deepEqual(boats.mapBy('id'), ['3'], 'unloaded boat is removed from ManyArray'); }) - .then(() => { - return run(() => person.get('boats')); - }) - .then(newBoats => { - assert.equal(newBoats.length, 1, 'new ManyArray has only 1 boat after unload'); - }) - ); -}); + ); + let boats, boat2, boat3; + + return run(() => + person + .get('boats') + .then(asyncRecords => { + boats = asyncRecords; + [boat2, boat3] = boats.toArray(); + }) + .then(() => { + assert.deepEqual( + person.hasMany('boats').ids(), + ['2', '3'], + 'initially relationship established rhs' + ); + assert.equal( + boat2.belongsTo('person').id(), + '1', + 'initially relationship established rhs' + ); + assert.equal( + boat3.belongsTo('person').id(), + '1', + 'initially relationship established rhs' + ); + + isUnloaded = true; + run(() => { + boat2.unloadRecord(); + person.get('boats'); + }); + + assert.deepEqual(boats.mapBy('id'), ['3'], 'unloaded boat is removed from ManyArray'); + }) + .then(() => { + return run(() => person.get('boats')); + }) + .then(newBoats => { + assert.equal(newBoats.length, 1, 'new ManyArray has only 1 boat after unload'); + }) + ); + }); -test('fetching records cancels unloading', function(assert) { - env.adapter.findRecord = (store, type, id) => { - assert.equal(type, Person, 'findRecord(_, type) is correct'); - assert.deepEqual(id, '1', 'findRecord(_, _, id) is correct'); + test('fetching records cancels unloading', function(assert) { + adapter.findRecord = (store, type, id) => { + assert.equal(type, Person, 'findRecord(_, type) is correct'); + assert.deepEqual(id, '1', 'findRecord(_, _, id) is correct'); - return { - data: { - id: 1, - type: 'person', - }, + return { + data: { + id: 1, + type: 'person', + }, + }; }; - }; - run(() => - env.store.push({ - data: { - id: 1, - type: 'person', - }, - }) - ); - - return run(() => - env.store - .findRecord('person', 1, { backgroundReload: true }) - .then(person => person.unloadRecord()) - ); + run(() => + store.push({ + data: { + id: 1, + type: 'person', + }, + }) + ); + + return run(() => + store + .findRecord('person', 1, { backgroundReload: true }) + .then(person => person.unloadRecord()) + ); + }); }); diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index acd834d0299..7672fa178ac 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -22,10 +22,6 @@ import { relationshipStateFor, } from 'ember-data/-private'; -function getRelationshipsFor(record) { - return record._internalModel._recordData._relationships; -} - const { attr: DSattr, hasMany: DShasMany, belongsTo: DSbelongsTo } = DS; const { hash } = RSVP; diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 1b56b18dd57..61514df6357 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -17,10 +17,6 @@ import DS from 'ember-data'; let env, store, User, Contact, Email, Phone, Message, Post, Comment; let Book, Chapter, Page; -function getRelationshipsFor(record) { - return record._internalModel._recordData._relationships; -} - const { attr, hasMany, belongsTo } = DS; module('integration/relationships/has_many - Has-Many Relationships', { From b044851b6b33df6b3dbe6ceb1f02e9ff7855a500 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Mon, 5 Nov 2018 18:36:02 -0800 Subject: [PATCH 2412/2527] drop use of MODEL_FACTORY_FOR --- addon/-debug/index.js | 5 +- tests/helpers/model-factory-injection.js | 20 --- tests/integration/injection-test.js | 12 +- .../relationships/belongs-to-test.js | 11 +- .../relationships/has-many-test.js | 28 ++--- .../relationships/json-api-links-test.js | 3 - .../polymorphic-mixins-belongs-to-test.js | 102 +++++++-------- .../polymorphic-mixins-has-many-test.js | 117 ++++++++---------- tests/test-helper.js | 3 + 9 files changed, 111 insertions(+), 190 deletions(-) delete mode 100644 tests/helpers/model-factory-injection.js diff --git a/addon/-debug/index.js b/addon/-debug/index.js index 900c34edf6b..e19bcf4f7e3 100644 --- a/addon/-debug/index.js +++ b/addon/-debug/index.js @@ -1,4 +1,3 @@ -import Ember from 'ember'; import { assert } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; @@ -34,9 +33,7 @@ if (DEBUG) { //once it exists in Ember return modelClass.__mixin.detect(addedModelClass.PrototypeMixin); } - if (Ember.MODEL_FACTORY_INJECTIONS) { - modelClass = modelClass.superclass; - } + return modelClass.detect(addedModelClass); }; diff --git a/tests/helpers/model-factory-injection.js b/tests/helpers/model-factory-injection.js deleted file mode 100644 index 1096af16f2e..00000000000 --- a/tests/helpers/model-factory-injection.js +++ /dev/null @@ -1,20 +0,0 @@ -import Ember from 'ember'; -import hasEmberVersion from '@ember/test-helpers/has-ember-version'; - -const ORIGINAL_MODEL_FACTORY_INJECTIONS = Ember.MODEL_FACTORY_INJECTIONS; - -export function setup(value) { - if (arguments.length > 0) { - value = arguments[0]; - } else { - value = true; - } - - if (!hasEmberVersion(2, 14)) { - Ember.MODEL_FACTORY_INJECTIONS = value; - } -} - -export function reset() { - setup(ORIGINAL_MODEL_FACTORY_INJECTIONS); -} diff --git a/tests/integration/injection-test.js b/tests/integration/injection-test.js index 3ed1ccac594..908cb738a2d 100644 --- a/tests/integration/injection-test.js +++ b/tests/integration/injection-test.js @@ -7,7 +7,6 @@ module('integration/injection factoryFor enabled', function(hooks) { setupTest(hooks); let store; let Model; - let factory; hooks.beforeEach(function() { let { owner } = this; @@ -16,19 +15,14 @@ module('integration/injection factoryFor enabled', function(hooks) { }; owner.register('model:super-villain', Model); store = owner.lookup('service:store'); - - let originalFactoryFor = owner.factoryFor; - - owner.factoryFor = function interceptFactoryFor() { - factory = originalFactoryFor.call(owner, ...arguments); - return factory; - }; }); test('modelFactoryFor', function(assert) { + let { owner } = this; + const trueFactory = owner.factoryFor('model:super-villain'); const modelFactory = store._modelFactoryFor('super-villain'); - assert.strictEqual(modelFactory, factory, 'expected the factory itself to be returned'); + assert.strictEqual(modelFactory, trueFactory, 'expected the factory itself to be returned'); }); test('modelFor', function(assert) { diff --git a/tests/integration/relationships/belongs-to-test.js b/tests/integration/relationships/belongs-to-test.js index 7672fa178ac..77d8b5940d8 100644 --- a/tests/integration/relationships/belongs-to-test.js +++ b/tests/integration/relationships/belongs-to-test.js @@ -10,10 +10,6 @@ import Store from 'ember-data/store'; import Model from 'ember-data/model'; import { attr, belongsTo } from '@ember-decorators/data'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import { - setup as setupModelFactoryInjections, - reset as resetModelFactoryInjection, -} from 'dummy/tests/helpers/model-factory-injection'; import DS from 'ember-data'; import { RecordData, @@ -279,7 +275,6 @@ module('integration/relationship/belongs_to Belongs-To Relationships', { }, afterEach() { - resetModelFactoryInjection(); run(env.container, 'destroy'); }, }); @@ -827,7 +822,7 @@ test('A record can be created with a resolved belongsTo promise', function(asser }); }); -test('polymorphic belongsTo class-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled', function(assert) { +test('polymorphic belongsTo class-checks check the superclass', function(assert) { assert.expect(1); run(() => { @@ -841,7 +836,6 @@ test('polymorphic belongsTo class-checks check the superclass when MODEL_FACTORY }); test('the subclass in a polymorphic belongsTo relationship is an instanceof its superclass', function(assert) { - setupModelFactoryInjections(false); assert.expect(1); let message = env.store.createRecord('message', { id: 1 }); @@ -858,8 +852,7 @@ test('relationshipsByName does not cache a factory', function(assert) { // An app is reset, or the container otherwise destroyed. run(env.container, 'destroy'); - // A new model for a relationship is created. Note that this may happen - // due to an extend call internal to MODEL_FACTORY_INJECTIONS. + // A new model for a relationship is created. NewMessage = Message.extend(); // A new store is created. diff --git a/tests/integration/relationships/has-many-test.js b/tests/integration/relationships/has-many-test.js index 61514df6357..052a0cf923a 100644 --- a/tests/integration/relationships/has-many-test.js +++ b/tests/integration/relationships/has-many-test.js @@ -1,9 +1,5 @@ /*eslint no-unused-vars: ["error", { "args": "none", "varsIgnorePattern": "(page)" }]*/ -import { - setup as setupModelFactoryInjections, - reset as resetModelFactoryInjections, -} from 'dummy/tests/helpers/model-factory-injection'; import { A } from '@ember/array'; import { resolve, Promise as EmberPromise, all, reject, hash } from 'rsvp'; import { get } from '@ember/object'; @@ -1497,25 +1493,19 @@ test("When a polymorphic hasMany relationship is accessed, the store can call mu }); }); -test('polymorphic hasMany type-checks check the superclass when MODEL_FACTORY_INJECTIONS is enabled', function(assert) { +test('polymorphic hasMany type-checks check the superclass', function(assert) { assert.expect(1); - setupModelFactoryInjections(); - - try { - run(function() { - let igor = env.store.createRecord('user', { name: 'Igor' }); - let comment = env.store.createRecord('comment', { - body: 'Well I thought the title was fine', - }); + run(function() { + let igor = env.store.createRecord('user', { name: 'Igor' }); + let comment = env.store.createRecord('comment', { + body: 'Well I thought the title was fine', + }); - igor.get('messages').addObject(comment); + igor.get('messages').addObject(comment); - assert.equal(igor.get('messages.firstObject.body'), 'Well I thought the title was fine'); - }); - } finally { - resetModelFactoryInjections(); - } + assert.equal(igor.get('messages.firstObject.body'), 'Well I thought the title was fine'); + }); }); test('Type can be inferred from the key of a hasMany relationship', function(assert) { diff --git a/tests/integration/relationships/json-api-links-test.js b/tests/integration/relationships/json-api-links-test.js index cce570eed29..7d819029b02 100644 --- a/tests/integration/relationships/json-api-links-test.js +++ b/tests/integration/relationships/json-api-links-test.js @@ -2,7 +2,6 @@ import { run } from '@ember/runloop'; import { get } from '@ember/object'; import { resolve } from 'rsvp'; import setupStore from 'dummy/tests/helpers/store'; -import { reset as resetModelFactoryInjection } from 'dummy/tests/helpers/model-factory-injection'; import { module, test } from 'qunit'; import DS from 'ember-data'; import JSONAPIAdapter from 'ember-data/adapters/json-api'; @@ -16,7 +15,6 @@ module('integration/relationship/json-api-links | Relationship state updates', { beforeEach() {}, afterEach() { - resetModelFactoryInjection(); run(env.container, 'destroy'); }, }); @@ -691,7 +689,6 @@ module('integration/relationship/json-api-links | Relationship fetching', { }, afterEach() { - resetModelFactoryInjection(); run(env.container, 'destroy'); env = null; }, diff --git a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js index 35a079e1180..0faa938713c 100644 --- a/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js +++ b/tests/integration/relationships/polymorphic-mixins-belongs-to-test.js @@ -1,8 +1,3 @@ -import { - setup as setupModelFactoryInjections, - reset as resetModelFactoryInjections, -} from 'dummy/tests/helpers/model-factory-injection'; - import Mixin from '@ember/object/mixin'; import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; @@ -174,9 +169,45 @@ testInDebug( test('Setting the polymorphic belongsTo gets propagated to the inverse side - model injections true', function(assert) { assert.expect(2); - setupModelFactoryInjections(); - try { + var user, video; + run(function() { + store.push({ + data: [ + { + type: 'user', + id: '1', + attributes: { + name: 'Stanley', + }, + }, + { + type: 'video', + id: '2', + attributes: { + video: 'Here comes Youtube', + }, + }, + ], + }); + user = store.peekRecord('user', 1); + video = store.peekRecord('video', 2); + }); + + run(function() { + user.set('bestMessage', video); + video.get('user').then(function(fetchedUser) { + assert.equal(fetchedUser, user, 'user got set correctly'); + }); + user.get('bestMessage').then(function(message) { + assert.equal(message, video, 'The message was set correctly'); + }); + }); +}); + +testInDebug( + 'Setting the polymorphic belongsTo with an object that does not implement the mixin errors out - model injections true', + function(assert) { var user, video; run(function() { store.push({ @@ -189,7 +220,7 @@ test('Setting the polymorphic belongsTo gets propagated to the inverse side - mo }, }, { - type: 'video', + type: 'not-message', id: '2', attributes: { video: 'Here comes Youtube', @@ -198,60 +229,13 @@ test('Setting the polymorphic belongsTo gets propagated to the inverse side - mo ], }); user = store.peekRecord('user', 1); - video = store.peekRecord('video', 2); + video = store.peekRecord('not-message', 2); }); run(function() { - user.set('bestMessage', video); - video.get('user').then(function(fetchedUser) { - assert.equal(fetchedUser, user, 'user got set correctly'); - }); - user.get('bestMessage').then(function(message) { - assert.equal(message, video, 'The message was set correctly'); - }); + assert.expectAssertion(function() { + user.set('bestMessage', video); + }, /The 'not-message' type does not implement 'message' and thus cannot be assigned to the 'bestMessage' relationship in 'user'. Make it a descendant of 'message'/); }); - } finally { - resetModelFactoryInjections(); - } -}); - -testInDebug( - 'Setting the polymorphic belongsTo with an object that does not implement the mixin errors out - model injections true', - function(assert) { - setupModelFactoryInjections(); - - try { - var user, video; - run(function() { - store.push({ - data: [ - { - type: 'user', - id: '1', - attributes: { - name: 'Stanley', - }, - }, - { - type: 'not-message', - id: '2', - attributes: { - video: 'Here comes Youtube', - }, - }, - ], - }); - user = store.peekRecord('user', 1); - video = store.peekRecord('not-message', 2); - }); - - run(function() { - assert.expectAssertion(function() { - user.set('bestMessage', video); - }, /The 'not-message' type does not implement 'message' and thus cannot be assigned to the 'bestMessage' relationship in 'user'. Make it a descendant of 'message'/); - }); - } finally { - resetModelFactoryInjections(); - } } ); diff --git a/tests/integration/relationships/polymorphic-mixins-has-many-test.js b/tests/integration/relationships/polymorphic-mixins-has-many-test.js index a94ad3cbf03..fe6db675f45 100644 --- a/tests/integration/relationships/polymorphic-mixins-has-many-test.js +++ b/tests/integration/relationships/polymorphic-mixins-has-many-test.js @@ -1,8 +1,3 @@ -import { - setup as setupModelFactoryInjections, - reset as resetModelFactoryInjections, -} from 'dummy/tests/helpers/model-factory-injection'; - import Mixin from '@ember/object/mixin'; import { run } from '@ember/runloop'; import setupStore from 'dummy/tests/helpers/store'; @@ -191,10 +186,52 @@ testInDebug( ); test('Pushing to the hasMany reflects the change on the belongsTo side - model injections true', function(assert) { - setupModelFactoryInjections(); + var user, video; + run(function() { + store.push({ + data: [ + { + type: 'user', + id: '1', + attributes: { + name: 'Stanley', + }, + relationships: { + messages: { + data: [], + }, + }, + }, + { + type: 'video', + id: '2', + attributes: { + video: 'Here comes Youtube', + }, + }, + ], + }); + user = store.peekRecord('user', 1); + video = store.peekRecord('video', 2); + }); - try { - var user, video; + run(function() { + user.get('messages').then(function(fetchedMessages) { + fetchedMessages.pushObject(video); + video.get('user').then(function(fetchedUser) { + assert.equal(fetchedUser, user, 'user got set correctly'); + }); + }); + }); +}); + +/* + Local edits +*/ +testInDebug( + 'Pushing a an object that does not implement the mixin to the mixin accepting array errors out - model injections true', + function(assert) { + var user, notMessage; run(function() { store.push({ data: [ @@ -211,7 +248,7 @@ test('Pushing to the hasMany reflects the change on the belongsTo side - model i }, }, { - type: 'video', + type: 'not-message', id: '2', attributes: { video: 'Here comes Youtube', @@ -220,69 +257,15 @@ test('Pushing to the hasMany reflects the change on the belongsTo side - model i ], }); user = store.peekRecord('user', 1); - video = store.peekRecord('video', 2); + notMessage = store.peekRecord('not-message', 2); }); run(function() { user.get('messages').then(function(fetchedMessages) { - fetchedMessages.pushObject(video); - video.get('user').then(function(fetchedUser) { - assert.equal(fetchedUser, user, 'user got set correctly'); - }); + assert.expectAssertion(function() { + fetchedMessages.pushObject(notMessage); + }, /The 'not-message' type does not implement 'message' and thus cannot be assigned to the 'messages' relationship in 'user'. Make it a descendant of 'message'/); }); }); - } finally { - resetModelFactoryInjections(); - } -}); - -/* - Local edits -*/ -testInDebug( - 'Pushing a an object that does not implement the mixin to the mixin accepting array errors out - model injections true', - function(assert) { - setupModelFactoryInjections(); - - try { - var user, notMessage; - run(function() { - store.push({ - data: [ - { - type: 'user', - id: '1', - attributes: { - name: 'Stanley', - }, - relationships: { - messages: { - data: [], - }, - }, - }, - { - type: 'not-message', - id: '2', - attributes: { - video: 'Here comes Youtube', - }, - }, - ], - }); - user = store.peekRecord('user', 1); - notMessage = store.peekRecord('not-message', 2); - }); - - run(function() { - user.get('messages').then(function(fetchedMessages) { - assert.expectAssertion(function() { - fetchedMessages.pushObject(notMessage); - }, /The 'not-message' type does not implement 'message' and thus cannot be assigned to the 'messages' relationship in 'user'. Make it a descendant of 'message'/); - }); - }); - } finally { - resetModelFactoryInjections(); - } } ); diff --git a/tests/test-helper.js b/tests/test-helper.js index 65ce68364a6..07bd3a07333 100644 --- a/tests/test-helper.js +++ b/tests/test-helper.js @@ -7,6 +7,8 @@ import QUnit from 'qunit'; import DS from 'ember-data'; import { wait, asyncEqual, invokeAsync } from 'dummy/tests/helpers/async'; +// TODO get us to a setApplication world instead +// seems to require killing off createStore setResolver(resolver); const { assert } = QUnit; @@ -28,6 +30,7 @@ QUnit.begin(() => { }); // Prevent all tests involving serialization to require a container + // TODO kill the need for this DS.JSONSerializer.reopen({ transformFor(attributeType) { return this._super(attributeType, true) || transforms[attributeType]; From a2196ae9761654d1d06ecd1ab047bc943a5d39f9 Mon Sep 17 00:00:00 2001 From: Pepe Cano Date: Fri, 9 Nov 2018 21:30:33 +0100 Subject: [PATCH 2413/2527] [DOC beta] Fix broken links --- addon/-private/system/relationships/belongs-to.js | 2 +- addon/serializers/embedded-records-mixin.js | 2 +- addon/serializers/json-api.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 121c8b82f36..00825c9d7c5 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -13,7 +13,7 @@ import { DEBUG } from '@glimmer/env'; - `async`: A boolean value used to explicitly declare this to be an async relationship. - `inverse`: A string used to identify the inverse property on a - related model in a One-To-Many relationship. See [Explicit Inverses](#toc_explicit-inverses) + related model in a One-To-Many relationship. See [Explicit Inverses](#explicit-inverses) #### One-To-One To declare a one-to-one relationship between two models, use diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index f8b4e66a228..a2c45d38108 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -77,7 +77,7 @@ import { warn } from '@ember/debug'; To successfully extract and serialize embedded records the model relationships must be set up correctly. See the - [defining relationships](/guides/models/defining-models/#toc_defining-relationships) + [defining relationships](https://guides.emberjs.com/current/models/relationships) section of the **Defining Models** guide page. Records without an `id` property are not considered embedded records, model diff --git a/addon/serializers/json-api.js b/addon/serializers/json-api.js index 923b769eb09..445d728f861 100644 --- a/addon/serializers/json-api.js +++ b/addon/serializers/json-api.js @@ -564,7 +564,7 @@ if (DEBUG) { willMergeMixin(props) { let constructor = this.constructor; warn( - `You've defined 'extractMeta' in ${constructor.toString()} which is not used for serializers extending JSONAPISerializer. Read more at https://emberjs.com/api/data/classes/DS.JSONAPISerializer.html#toc_customizing-meta on how to customize meta when using JSON API.`, + `You've defined 'extractMeta' in ${constructor.toString()} which is not used for serializers extending JSONAPISerializer. Read more at https://emberjs.com/api/data/classes/DS.JSONAPISerializer on how to customize meta when using JSON API.`, isNone(props.extractMeta) || props.extractMeta === JSONSerializer.prototype.extractMeta, { id: 'ds.serializer.json-api.extractMeta', From 4d3e02794650bd24f7211051f372d6e7bef7db04 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 9 Nov 2018 15:29:28 -0800 Subject: [PATCH 2414/2527] [CHORE tests] modernize integration/serializers/embedded-records-mixin-test (#5746) * [CHORE tests] modernize integration/serializers/embedded-records-mixin-test --- .../embedded-records-mixin-test.js | 5078 +++++++++-------- 1 file changed, 2681 insertions(+), 2397 deletions(-) diff --git a/tests/integration/serializers/embedded-records-mixin-test.js b/tests/integration/serializers/embedded-records-mixin-test.js index b6cb4b591df..d452d114d17 100644 --- a/tests/integration/serializers/embedded-records-mixin-test.js +++ b/tests/integration/serializers/embedded-records-mixin-test.js @@ -1,766 +1,359 @@ -import { w } from '@ember/string'; -import { run } from '@ember/runloop'; -import { get } from '@ember/object'; -import setupStore from 'dummy/tests/helpers/store'; - -import testInDebug from 'dummy/tests/helpers/test-in-debug'; +import { setupTest } from 'ember-qunit'; import { module, test } from 'qunit'; - -import DS from 'ember-data'; - -var HomePlanet, - SuperVillain, - CommanderVillain, - NormalMinion, - EvilMinion, - YellowMinion, - RedMinion, - SecretLab, - SecretWeapon, - BatCave, - Comment, - env, - LightSaber; - -module('integration/embedded_records_mixin - EmbeddedRecordsMixin', { - beforeEach() { - SuperVillain = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - homePlanet: DS.belongsTo('home-planet', { inverse: 'villains', async: true }), - secretLab: DS.belongsTo('secret-lab', { async: false }), - secretWeapons: DS.hasMany('secret-weapon', { async: false }), - evilMinions: DS.hasMany('evil-minion', { async: false }), - }); - HomePlanet = DS.Model.extend({ - name: DS.attr('string'), - villains: DS.hasMany('super-villain', { inverse: 'homePlanet', async: false }), - }); - SecretLab = DS.Model.extend({ - minionCapacity: DS.attr('number'), - vicinity: DS.attr('string'), - superVillain: DS.belongsTo('super-villain', { async: false }), +import testInDebug from '../../helpers/test-in-debug'; + +import Model from 'ember-data/model'; +import attr from 'ember-data/attr'; +import { belongsTo, hasMany } from 'ember-data/relationships'; + +import RESTAdapter from 'ember-data/adapters/rest'; +import RESTSerializer from 'ember-data/serializers/rest'; +import EmbeddedRecordsMixin from 'ember-data/serializers/embedded-records-mixin'; + +module('integration/embedded-records-mixin', function(hooks) { + setupTest(hooks); + let store; + + hooks.beforeEach(function() { + let { owner } = this; + + const SuperVillain = Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + homePlanet: belongsTo('home-planet', { inverse: 'villains', async: true }), + secretLab: belongsTo('secret-lab', { async: false }), + secretWeapons: hasMany('secret-weapon', { async: false }), + evilMinions: hasMany('evil-minion', { async: false }), }); - BatCave = SecretLab.extend({ - infiltrated: DS.attr('boolean'), + const HomePlanet = Model.extend({ + name: attr('string'), + villains: hasMany('super-villain', { inverse: 'homePlanet', async: false }), }); - SecretWeapon = DS.Model.extend({ - name: DS.attr('string'), - superVillain: DS.belongsTo('super-villain', { async: false }), + const SecretLab = Model.extend({ + minionCapacity: attr('number'), + vicinity: attr('string'), + superVillain: belongsTo('super-villain', { async: false }), }); - LightSaber = SecretWeapon.extend({ - color: DS.attr('string'), + const BatCave = SecretLab.extend({ + infiltrated: attr('boolean'), }); - EvilMinion = DS.Model.extend({ - superVillain: DS.belongsTo('super-villain', { async: false }), - name: DS.attr('string'), + const SecretWeapon = Model.extend({ + name: attr('string'), + superVillain: belongsTo('super-villain', { async: false }), }); - NormalMinion = DS.Model.extend({ - name: DS.attr('string'), + const LightSaber = SecretWeapon.extend({ + color: attr('string'), }); - YellowMinion = NormalMinion.extend(); - RedMinion = NormalMinion.extend(); - CommanderVillain = DS.Model.extend({ - name: DS.attr('string'), - minions: DS.hasMany('normal-minion', { polymorphic: true }), + const EvilMinion = Model.extend({ + superVillain: belongsTo('super-villain', { async: false }), + name: attr('string'), }); - Comment = DS.Model.extend({ - body: DS.attr('string'), - root: DS.attr('boolean'), - children: DS.hasMany('comment', { inverse: null, async: false }), + const Comment = Model.extend({ + body: attr('string'), + root: attr('boolean'), + children: hasMany('comment', { inverse: null, async: false }), }); - env = setupStore({ - superVillain: SuperVillain, - commanderVillain: CommanderVillain, - homePlanet: HomePlanet, - secretLab: SecretLab, - batCave: BatCave, - secretWeapon: SecretWeapon, - lightSaber: LightSaber, - evilMinion: EvilMinion, - normalMinion: NormalMinion, - yellowMinion: YellowMinion, - redMinion: RedMinion, - comment: Comment, - }); - env.store.modelFor('super-villain'); - env.store.modelFor('commander-villain'); - env.store.modelFor('home-planet'); - env.store.modelFor('secret-lab'); - env.store.modelFor('bat-cave'); - env.store.modelFor('secret-weapon'); - env.store.modelFor('light-saber'); - env.store.modelFor('evil-minion'); - env.store.modelFor('comment'); - - env.owner.register('adapter:application', DS.RESTAdapter); - env.owner.register('serializer:application', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin)); - }, - - afterEach() { - run(env.store, 'destroy'); - }, -}); - -test('normalizeResponse with embedded objects', function(assert) { - env.owner.register( - 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' }, - }, - }) - ); - - var serializer = env.store.serializerFor('home-planet'); - var json_hash = { - homePlanet: { - id: '1', - name: 'Umber', - villains: [ - { - id: '2', - firstName: 'Tom', - lastName: 'Dale', - }, - ], - }, - }; - var json; - - run(function() { - json = serializer.normalizeResponse(env.store, HomePlanet, json_hash, '1', 'findRecord'); - }); - - assert.deepEqual(json, { - data: { - id: '1', - type: 'home-planet', - attributes: { - name: 'Umber', - }, - relationships: { - villains: { - data: [{ id: '2', type: 'super-villain' }], - }, - }, - }, - included: [ - { - id: '2', - type: 'super-villain', - attributes: { - firstName: 'Tom', - lastName: 'Dale', - }, - relationships: {}, - }, - ], - }); -}); - -test('normalizeResponse with embedded objects inside embedded objects', function(assert) { - env.owner.register( - 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' }, - }, - }) - ); - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - evilMinions: { embedded: 'always' }, - }, - }) - ); - - var serializer = env.store.serializerFor('home-planet'); - var json_hash = { - homePlanet: { - id: '1', - name: 'Umber', - villains: [ - { - id: '2', - firstName: 'Tom', - lastName: 'Dale', - evilMinions: [ - { - id: '3', - name: 'Alex', - }, - ], - }, - ], - }, - }; - var json; - - run(function() { - json = serializer.normalizeResponse(env.store, HomePlanet, json_hash, '1', 'findRecord'); - }); - - assert.deepEqual(json, { - data: { - id: '1', - type: 'home-planet', - attributes: { - name: 'Umber', - }, - relationships: { - villains: { - data: [{ id: '2', type: 'super-villain' }], - }, - }, - }, - included: [ - { - id: '2', - type: 'super-villain', - attributes: { - firstName: 'Tom', - lastName: 'Dale', - }, - relationships: { - evilMinions: { - data: [{ id: '3', type: 'evil-minion' }], - }, - }, - }, - { - id: '3', - type: 'evil-minion', - attributes: { - name: 'Alex', - }, - relationships: {}, - }, - ], - }); -}); - -test('normalizeResponse with embedded objects of same type', function(assert) { - env.owner.register( - 'serializer:comment', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - children: { embedded: 'always' }, - }, - }) - ); - - var serializer = env.store.serializerFor('comment'); - - var json_hash = { - comment: { - id: '1', - body: 'Hello', - root: true, - children: [ - { - id: '2', - body: 'World', - root: false, - }, - { - id: '3', - body: 'Foo', - root: false, - }, - ], - }, - }; - var json; - run(function() { - json = serializer.normalizeResponse(env.store, Comment, json_hash, '1', 'findRecord'); - }); - - assert.deepEqual( - json, - { - data: { - id: '1', - type: 'comment', - attributes: { - body: 'Hello', - root: true, - }, - relationships: { - children: { - data: [{ id: '2', type: 'comment' }, { id: '3', type: 'comment' }], - }, - }, - }, - included: [ - { - id: '2', - type: 'comment', - attributes: { - body: 'World', - root: false, - }, - relationships: {}, - }, - { - id: '3', - type: 'comment', - attributes: { - body: 'Foo', - root: false, - }, - relationships: {}, - }, - ], - }, - 'Primary record was correct' - ); -}); -test('normalizeResponse with embedded objects inside embedded objects of same type', function(assert) { - env.owner.register( - 'serializer:comment', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - children: { embedded: 'always' }, - }, - }) - ); - - var serializer = env.store.serializerFor('comment'); - var json_hash = { - comment: { - id: '1', - body: 'Hello', - root: true, - children: [ - { - id: '2', - body: 'World', - root: false, - children: [ + owner.register('model:super-villain', SuperVillain); + owner.register('model:home-planet', HomePlanet); + owner.register('model:secret-lab', SecretLab); + owner.register('model:bat-cave', BatCave); + owner.register('model:secret-weapon', SecretWeapon); + owner.register('model:light-saber', LightSaber); + owner.register('model:evil-minion', EvilMinion); + owner.register('model:comment', Comment); + + owner.register('adapter:application', RESTAdapter); + owner.register('serializer:application', RESTSerializer.extend(EmbeddedRecordsMixin)); + + store = owner.lookup('service:store'); + }); + + module('Normalize using findRecord', function() { + test('normalizeResponse with embedded objects', async function(assert) { + this.owner.register( + 'serializer:home-planet', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); + const serializer = store.serializerFor('home-planet'); + const HomePlanet = store.modelFor('home-planet'); + const rawPayload = { + homePlanet: { + id: '1', + name: 'Umber', + villains: [ { - id: '4', - body: 'Another', - root: false, + id: '2', + firstName: 'Tom', + lastName: 'Dale', }, ], }, - { - id: '3', - body: 'Foo', - root: false, - }, - ], - }, - }; - var json; - run(function() { - json = serializer.normalizeResponse(env.store, Comment, json_hash, '1', 'findRecord'); - }); - - assert.deepEqual( - json, - { - data: { - id: '1', - type: 'comment', - attributes: { - body: 'Hello', - root: true, - }, - relationships: { - children: { - data: [{ id: '2', type: 'comment' }, { id: '3', type: 'comment' }], - }, - }, - }, - included: [ - { - id: '2', - type: 'comment', + }; + + const normalizedJsonApi = serializer.normalizeResponse( + store, + HomePlanet, + rawPayload, + '1', + 'findRecord' + ); + const expectedOutput = { + data: { + id: '1', + type: 'home-planet', attributes: { - body: 'World', - root: false, + name: 'Umber', }, relationships: { - children: { - data: [{ id: '4', type: 'comment' }], + villains: { + data: [{ id: '2', type: 'super-villain' }], }, }, }, - { - id: '4', - type: 'comment', - attributes: { - body: 'Another', - root: false, - }, - relationships: {}, - }, - { - id: '3', - type: 'comment', - attributes: { - body: 'Foo', - root: false, + included: [ + { + id: '2', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale', + }, + relationships: {}, }, - relationships: {}, - }, - ], - }, - 'Primary record was correct' - ); -}); + ], + }; -test('normalizeResponse with embedded objects of same type, but from separate attributes', function(assert) { - HomePlanet.reopen({ - reformedVillains: DS.hasMany('superVillain', { inverse: null, async: false }), - }); + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'We normalized to json-api and extracted the super-villain' + ); + }); - env.owner.register( - 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' }, - reformedVillains: { embedded: 'always' }, - }, - }) - ); - - var serializer = env.store.serializerFor('home-planet'); - var json_hash = { - homePlanet: { - id: '1', - name: 'Earth', - villains: [ - { + test('normalizeResponse with embedded objects inside embedded objects', async function(assert) { + this.owner.register( + 'serializer:home-planet', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + evilMinions: { embedded: 'always' }, + }, + }) + ); + + const serializer = store.serializerFor('home-planet'); + const HomePlanet = store.modelFor('home-planet'); + const rawPayload = { + homePlanet: { id: '1', - firstName: 'Tom', - }, - { - id: '3', - firstName: 'Yehuda', - }, - ], - reformedVillains: [ - { - id: '2', - firstName: 'Alex', - }, - { - id: '4', - firstName: 'Erik', - }, - ], - }, - }; - var json; - run(function() { - json = serializer.normalizeResponse(env.store, HomePlanet, json_hash, '1', 'findRecord'); - }); - - assert.deepEqual( - json, - { - data: { - id: '1', - type: 'home-planet', - attributes: { - name: 'Earth', - }, - relationships: { - villains: { - data: [{ id: '1', type: 'super-villain' }, { id: '3', type: 'super-villain' }], - }, - reformedVillains: { - data: [{ id: '2', type: 'super-villain' }, { id: '4', type: 'super-villain' }], - }, + name: 'Umber', + villains: [ + { + id: '2', + firstName: 'Tom', + lastName: 'Dale', + evilMinions: [ + { + id: '3', + name: 'Alex', + }, + ], + }, + ], }, - }, - included: [ - { + }; + + const normalizedJsonApi = serializer.normalizeResponse( + store, + HomePlanet, + rawPayload, + '1', + 'findRecord' + ); + const expectedOutput = { + data: { id: '1', - type: 'super-villain', - attributes: { - firstName: 'Tom', - }, - relationships: {}, - }, - { - id: '3', - type: 'super-villain', - attributes: { - firstName: 'Yehuda', - }, - relationships: {}, - }, - { - id: '2', - type: 'super-villain', + type: 'home-planet', attributes: { - firstName: 'Alex', + name: 'Umber', }, - relationships: {}, - }, - { - id: '4', - type: 'super-villain', - attributes: { - firstName: 'Erik', + relationships: { + villains: { + data: [{ id: '2', type: 'super-villain' }], + }, }, - relationships: {}, }, - ], - }, - 'Primary hash was correct' - ); -}); - -test('normalizeResponse with embedded objects', function(assert) { - env.owner.register( - 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' }, - }, - }) - ); - - var serializer = env.store.serializerFor('home-planet'); - - var json_hash = { - homePlanets: [ - { - id: '1', - name: 'Umber', - villains: [ + included: [ { - id: '1', - firstName: 'Tom', - lastName: 'Dale', - }, - ], - }, - ], - }; - var array; - - run(function() { - array = serializer.normalizeResponse(env.store, HomePlanet, json_hash, null, 'findAll'); - }); - - assert.deepEqual(array, { - data: [ - { - id: '1', - type: 'home-planet', - attributes: { - name: 'Umber', - }, - relationships: { - villains: { - data: [{ id: '1', type: 'super-villain' }], + id: '2', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale', + }, + relationships: { + evilMinions: { + data: [{ id: '3', type: 'evil-minion' }], + }, + }, }, - }, - }, - ], - included: [ - { - id: '1', - type: 'super-villain', - attributes: { - firstName: 'Tom', - lastName: 'Dale', - }, - relationships: {}, - }, - ], - }); -}); - -test('normalizeResponse with embedded objects with custom primary key', function(assert) { - assert.expect(1); - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend({ - primaryKey: 'villain_id', - }) - ); - env.owner.register( - 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' }, - }, - }) - ); - - var serializer = env.store.serializerFor('home-planet'); - - var json_hash = { - homePlanets: [ - { - id: '1', - name: 'Umber', - villains: [ { - villain_id: '2', - firstName: 'Alex', - lastName: 'Baizeau', + id: '3', + type: 'evil-minion', + attributes: { + name: 'Alex', + }, + relationships: {}, }, ], - }, - ], - }; - var array; - - run(function() { - array = serializer.normalizeResponse(env.store, HomePlanet, json_hash, null, 'findAll'); - }); - - assert.deepEqual(array, { - data: [ - { - id: '1', - type: 'home-planet', - attributes: { - name: 'Umber', - }, - relationships: { - villains: { - data: [{ id: '2', type: 'super-villain' }], - }, - }, - }, - ], - included: [ - { - id: '2', - type: 'super-villain', - attributes: { - firstName: 'Alex', - lastName: 'Baizeau', - }, - relationships: {}, - }, - ], - }); -}); + }; + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'We normalized to json-api and extracted embedded records two levels deep' + ); + }); -test('normalizeResponse with embedded objects with identical relationship and attribute key ', function(assert) { - assert.expect(1); - env.owner.register( - 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' }, - }, - //Makes the keyForRelationship and keyForAttribute collide. - keyForRelationship(key, type) { - return this.keyForAttribute(key, type); - }, - }) - ); - - var serializer = env.store.serializerFor('home-planet'); - - var json_hash = { - homePlanets: [ - { - id: '1', - name: 'Umber', - villains: [ - { - id: '1', - firstName: 'Alex', - lastName: 'Baizeau', + test('normalizeResponse with embedded objects of same type', async function(assert) { + this.owner.register( + 'serializer:comment', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + children: { embedded: 'always' }, }, - ], - }, - ], - }; - var array; - - run(function() { - array = serializer.normalizeResponse(env.store, HomePlanet, json_hash, null, 'findAll'); - }); + }) + ); - assert.deepEqual(array, { - data: [ - { - id: '1', - type: 'home-planet', - attributes: { - name: 'Umber', + const serializer = store.serializerFor('comment'); + const Comment = store.modelFor('comment'); + const rawPayload = { + comment: { + id: '1', + body: 'Hello', + root: true, + children: [ + { + id: '2', + body: 'World', + root: false, + }, + { + id: '3', + body: 'Foo', + root: false, + }, + ], }, - relationships: { - villains: { - data: [{ id: '1', type: 'super-villain' }], + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + Comment, + rawPayload, + '1', + 'findRecord' + ); + const expectedOutput = { + data: { + id: '1', + type: 'comment', + attributes: { + body: 'Hello', + root: true, + }, + relationships: { + children: { + data: [{ id: '2', type: 'comment' }, { id: '3', type: 'comment' }], + }, }, }, - }, - ], - included: [ - { - id: '1', - type: 'super-villain', - attributes: { - firstName: 'Alex', - lastName: 'Baizeau', - }, - relationships: {}, - }, - ], - }); -}); - -test('normalizeResponse with embedded objects of same type as primary type', function(assert) { - env.owner.register( - 'serializer:comment', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - children: { embedded: 'always' }, - }, - }) - ); - - var serializer = env.store.serializerFor('comment'); - - var json_hash = { - comments: [ - { - id: '1', - body: 'Hello', - root: true, - children: [ + included: [ { id: '2', - body: 'World', - root: false, + type: 'comment', + attributes: { + body: 'World', + root: false, + }, + relationships: {}, }, { id: '3', - body: 'Foo', - root: false, + type: 'comment', + attributes: { + body: 'Foo', + root: false, + }, + relationships: {}, }, ], - }, - ], - }; - var array; + }; - run(function() { - array = serializer.normalizeResponse(env.store, Comment, json_hash, null, 'findAll'); - }); + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'We normalized to json-api keeping the primary record in data and the related record of the same type in included' + ); + }); - assert.deepEqual( - array, - { - data: [ - { + test('normalizeResponse with embedded objects inside embedded objects of same type', async function(assert) { + this.owner.register( + 'serializer:comment', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + children: { embedded: 'always' }, + }, + }) + ); + + const serializer = store.serializerFor('comment'); + const Comment = store.modelFor('comment'); + const rawPayload = { + comment: { + id: '1', + body: 'Hello', + root: true, + children: [ + { + id: '2', + body: 'World', + root: false, + children: [ + { + id: '4', + body: 'Another', + root: false, + }, + ], + }, + { + id: '3', + body: 'Foo', + root: false, + }, + ], + }, + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + Comment, + rawPayload, + '1', + 'findRecord' + ); + const expectedOutput = { + data: { id: '1', type: 'comment', attributes: { @@ -773,1105 +366,1130 @@ test('normalizeResponse with embedded objects of same type as primary type', fun }, }, }, - ], - included: [ - { - id: '2', - type: 'comment', - attributes: { - body: 'World', - root: false, - }, - relationships: {}, - }, - { - id: '3', - type: 'comment', - attributes: { - body: 'Foo', - root: false, + included: [ + { + id: '2', + type: 'comment', + attributes: { + body: 'World', + root: false, + }, + relationships: { + children: { + data: [{ id: '4', type: 'comment' }], + }, + }, }, - relationships: {}, - }, - ], - }, - 'Primary array is correct' - ); -}); - -test('normalizeResponse with embedded objects of same type, but from separate attributes', function(assert) { - HomePlanet.reopen({ - reformedVillains: DS.hasMany('superVillain', { async: false }), - }); - - env.owner.register( - 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' }, - reformedVillains: { embedded: 'always' }, - }, - }) - ); - - var serializer = env.store.serializerFor('home-planet'); - var json_hash = { - homePlanets: [ - { - id: '1', - name: 'Earth', - villains: [ { - id: '1', - firstName: 'Tom', + id: '4', + type: 'comment', + attributes: { + body: 'Another', + root: false, + }, + relationships: {}, }, { id: '3', - firstName: 'Yehuda', + type: 'comment', + attributes: { + body: 'Foo', + root: false, + }, + relationships: {}, }, ], - reformedVillains: [ - { - id: '2', - firstName: 'Alex', + }; + + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'We normalized to json-api keeping the primary record in data and the related record of the same type in included multiple levels deep' + ); + }); + + test('normalizeResponse with embedded objects of same type, but from separate attributes', async function(assert) { + let { owner } = this; + const HomePlanetKlass = Model.extend({ + name: attr('string'), + villains: hasMany('super-villain', { inverse: 'homePlanet', async: false }), + reformedVillains: hasMany('superVillain', { inverse: null, async: false }), + }); + owner.unregister('model:home-planet'); + owner.register('model:home-planet', HomePlanetKlass); + owner.register( + 'serializer:home-planet', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + reformedVillains: { embedded: 'always' }, + }, + }) + ); + + const serializer = store.serializerFor('home-planet'); + const HomePlanet = store.modelFor('home-planet'); + const rawPayload = { + homePlanet: { + id: '1', + name: 'Earth', + villains: [ + { + id: '1', + firstName: 'Tom', + }, + { + id: '3', + firstName: 'Yehuda', + }, + ], + reformedVillains: [ + { + id: '2', + firstName: 'Alex', + }, + { + id: '4', + firstName: 'Erik', + }, + ], + }, + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + HomePlanet, + rawPayload, + '1', + 'findRecord' + ); + const expectedOutput = { + data: { + id: '1', + type: 'home-planet', + attributes: { + name: 'Earth', }, - { - id: '4', - firstName: 'Erik', + relationships: { + villains: { + data: [{ id: '1', type: 'super-villain' }, { id: '3', type: 'super-villain' }], + }, + reformedVillains: { + data: [{ id: '2', type: 'super-villain' }, { id: '4', type: 'super-villain' }], + }, }, - ], - }, - { - id: '2', - name: 'Mars', - villains: [ + }, + included: [ { id: '1', - firstName: 'Tom', + type: 'super-villain', + attributes: { + firstName: 'Tom', + }, + relationships: {}, }, { id: '3', - firstName: 'Yehuda', + type: 'super-villain', + attributes: { + firstName: 'Yehuda', + }, + relationships: {}, }, - ], - reformedVillains: [ { - id: '5', - firstName: 'Peter', + id: '2', + type: 'super-villain', + attributes: { + firstName: 'Alex', + }, + relationships: {}, }, { - id: '6', - firstName: 'Trek', + id: '4', + type: 'super-villain', + attributes: { + firstName: 'Erik', + }, + relationships: {}, }, ], - }, - ], - }; + }; - var json; - run(function() { - json = serializer.normalizeResponse(env.store, HomePlanet, json_hash, null, 'findAll'); - }); + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'Extracting embedded works with multiple inverses of the same type' + ); + }); - assert.deepEqual( - json, - { - data: [ - { + test('normalizeResponse with multiply-nested belongsTo', async function(assert) { + let { owner } = this; + owner.register( + 'serializer:evil-minion', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + superVillain: { embedded: 'always' }, + }, + }) + ); + owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + homePlanet: { embedded: 'always' }, + }, + }) + ); + + const serializer = store.serializerFor('evil-minion'); + const EvilMinion = store.modelFor('evil-minion'); + const rawPayload = { + evilMinion: { id: '1', - type: 'home-planet', + name: 'Alex', + superVillain: { + id: '1', + firstName: 'Tom', + lastName: 'Dale', + evilMinions: ['1'], + homePlanet: { + id: '1', + name: 'Umber', + villains: ['1'], + }, + }, + }, + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + EvilMinion, + rawPayload, + '1', + 'findRecord' + ); + const expectedOutput = { + data: { + id: '1', + type: 'evil-minion', attributes: { - name: 'Earth', + name: 'Alex', }, relationships: { - reformedVillains: { - data: [{ id: '2', type: 'super-villain' }, { id: '4', type: 'super-villain' }], + superVillain: { + data: { id: '1', type: 'super-villain' }, }, - villains: { - data: [{ id: '1', type: 'super-villain' }, { id: '3', type: 'super-villain' }], + }, + }, + included: [ + { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale', + }, + relationships: { + evilMinions: { + data: [{ id: '1', type: 'evil-minion' }], + }, + homePlanet: { + data: { id: '1', type: 'home-planet' }, + }, + }, + }, + { + id: '1', + type: 'home-planet', + attributes: { + name: 'Umber', + }, + relationships: { + villains: { + data: [{ id: '1', type: 'super-villain' }], + }, }, }, + ], + }; + + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'we normalized to json-api and extracted the multiply nested belongTos' + ); + }); + + test('normalizeResponse with polymorphic hasMany and custom primary key', async function(assert) { + let { owner } = this; + const SuperVillainClass = Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + homePlanet: belongsTo('home-planet', { inverse: 'villains', async: true }), + secretLab: belongsTo('secret-lab', { async: false }), + secretWeapons: hasMany('secretWeapon', { polymorphic: true, async: false }), + evilMinions: hasMany('evil-minion', { async: false }), + }); + + owner.register( + 'serializer:light-saber', + RESTSerializer.extend({ + primaryKey: 'custom', + }) + ); + owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretWeapons: { embedded: 'always' }, + }, + }) + ); + owner.unregister('model:super-villain'); + owner.register('model:super-villain', SuperVillainClass); + + const serializer = store.serializerFor('super-villain'); + const SuperVillain = store.modelFor('super-villain'); + const rawPayload = { + super_villain: { + id: '1', + firstName: 'Tom', + lastName: 'Dale', + secretWeapons: [ + { + custom: '1', + type: 'LightSaber', + name: "Tom's LightSaber", + color: 'Red', + }, + { + id: '1', + type: 'SecretWeapon', + name: 'The Death Star', + }, + ], }, - { - id: '2', - type: 'home-planet', + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + SuperVillain, + rawPayload, + '1', + 'findRecord' + ); + const expectedOutput = { + data: { attributes: { - name: 'Mars', + firstName: 'Tom', + lastName: 'Dale', }, + id: '1', relationships: { - reformedVillains: { - data: [{ id: '5', type: 'super-villain' }, { id: '6', type: 'super-villain' }], + secretWeapons: { + data: [{ type: 'light-saber', id: '1' }, { type: 'secret-weapon', id: '1' }], }, - villains: { - data: [{ id: '1', type: 'super-villain' }, { id: '3', type: 'super-villain' }], + }, + type: 'super-villain', + }, + included: [ + { + attributes: { + color: 'Red', + name: "Tom's LightSaber", + }, + id: '1', + relationships: {}, + type: 'light-saber', + }, + { + attributes: { + name: 'The Death Star', }, + id: '1', + relationships: {}, + type: 'secret-weapon', + }, + ], + }; + + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'we normalized to json-api and extracted the polymorphic hasMany with a custom key' + ); + }); + + test('normalizeResponse with polymorphic belongsTo', async function(assert) { + let { owner } = this; + const SuperVillainClass = Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + homePlanet: belongsTo('home-planet', { inverse: 'villains', async: true }), + secretLab: belongsTo('secretLab', { polymorphic: true, async: true }), + secretWeapons: hasMany('secret-weapon', { async: false }), + evilMinions: hasMany('evil-minion', { async: false }), + }); + + owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); + owner.unregister('model:super-villain'); + owner.register('model:super-villain', SuperVillainClass); + + const serializer = store.serializerFor('super-villain'); + const SuperVillain = store.modelFor('super-villain'); + const rawPayload = { + super_villain: { + id: '1', + firstName: 'Tom', + lastName: 'Dale', + secretLab: { + id: '1', + type: 'bat-cave', + infiltrated: true, }, }, - ], - included: [ - { + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + SuperVillain, + rawPayload, + '1', + 'findRecord' + ); + const expectedOutput = { + data: { id: '1', type: 'super-villain', attributes: { firstName: 'Tom', + lastName: 'Dale', }, - relationships: {}, - }, - { - id: '3', - type: 'super-villain', - attributes: { - firstName: 'Yehuda', + relationships: { + secretLab: { + data: { id: '1', type: 'bat-cave' }, + }, }, - relationships: {}, }, - { - id: '2', - type: 'super-villain', - attributes: { - firstName: 'Alex', + included: [ + { + id: '1', + type: 'bat-cave', + attributes: { + infiltrated: true, + }, + relationships: {}, + }, + ], + }; + + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'we normalize to json-api and extract the polymorphic belongsTo' + ); + }); + + test('normalizeResponse with polymorphic belongsTo and custom primary key', async function(assert) { + let { owner } = this; + const SuperVillainClass = Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + homePlanet: belongsTo('home-planet', { inverse: 'villains', async: true }), + secretLab: belongsTo('secretLab', { polymorphic: true, async: true }), + secretWeapons: hasMany('secret-weapon', { async: false }), + evilMinions: hasMany('evil-minion', { async: false }), + }); + + owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); + owner.register( + 'serializer:bat-cave', + RESTSerializer.extend({ + primaryKey: 'custom', + }) + ); + owner.unregister('model:super-villain'); + owner.register('model:super-villain', SuperVillainClass); + + const serializer = store.serializerFor('super-villain'); + const SuperVillain = store.modelFor('super-villain'); + const rawPayload = { + superVillain: { + id: '1', + firstName: 'Tom', + lastName: 'Dale', + secretLab: { + custom: '1', + type: 'bat-cave', + infiltrated: true, }, - relationships: {}, }, - { - id: '4', - type: 'super-villain', + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + SuperVillain, + rawPayload, + '1', + 'findRecord' + ); + const expectedOutput = { + data: { attributes: { - firstName: 'Erik', + firstName: 'Tom', + lastName: 'Dale', }, - relationships: {}, - }, - { id: '1', + relationships: { + secretLab: { + data: { + id: '1', + type: 'bat-cave', + }, + }, + }, type: 'super-villain', - attributes: { + }, + included: [ + { + attributes: { + infiltrated: true, + }, + id: '1', + relationships: {}, + type: 'bat-cave', + }, + ], + }; + + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'we normalize to json-api and extract the polymorphic belongsTo with a custom key' + ); + }); + + test('normalize with custom belongsTo primary key', async function(assert) { + let { owner } = this; + owner.register( + 'serializer:evil-minion', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + superVillain: { embedded: 'always' }, + }, + }) + ); + owner.register( + 'serializer:super-villain', + RESTSerializer.extend({ + primaryKey: 'custom', + }) + ); + + const serializer = store.serializerFor('evil-minion'); + const EvilMinion = store.modelFor('evil-minion'); + const rawPayload = { + evilMinion: { + id: '1', + name: 'Alex', + superVillain: { + custom: '1', firstName: 'Tom', + lastName: 'Dale', }, - relationships: {}, }, - { - id: '3', - type: 'super-villain', + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + EvilMinion, + rawPayload, + '1', + 'findRecord' + ); + const expectedOutput = { + data: { + id: '1', + type: 'evil-minion', attributes: { - firstName: 'Yehuda', + name: 'Alex', }, - relationships: {}, - }, - { - id: '5', - type: 'super-villain', - attributes: { - firstName: 'Peter', + relationships: { + superVillain: { + data: { id: '1', type: 'super-villain' }, + }, }, - relationships: {}, }, - { - id: '6', - type: 'super-villain', - attributes: { - firstName: 'Trek', + included: [ + { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale', + }, + relationships: {}, }, - relationships: {}, - }, - ], - }, - 'Primary array was correct' - ); -}); - -test('serialize supports serialize:false on non-relationship properties', function(assert) { - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - id: '1', - }); - - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - firstName: { serialize: false }, - }, - }) - ); - var serializer, json; - run(function() { - serializer = env.store.serializerFor('super-villain'); - json = serializer.serialize(tom._createSnapshot()); - }); - - assert.deepEqual(json, { - lastName: 'Dale', - homePlanet: null, - secretLab: null, - }); -}); - -test('serialize with embedded objects (hasMany relationship)', function(assert) { - let league = env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }); - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - homePlanet: league, - id: '1', - }); - - env.owner.register( - 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' }, - }, - }) - ); - - var serializer, json; - run(function() { - serializer = env.store.serializerFor('home-planet'); - - json = serializer.serialize(league._createSnapshot()); - }); + ], + }; - assert.deepEqual(json, { - name: 'Villain League', - villains: [ - { - id: get(tom, 'id'), - firstName: 'Tom', - lastName: 'Dale', - homePlanet: get(league, 'id'), - secretLab: null, - }, - ], + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'we normalize to json-api with custom belongsTo primary key' + ); + }); }); -}); -test('serialize with embedded objects and a custom keyForAttribute (hasMany relationship)', function(assert) { - let league = env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }); - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - homePlanet: league, - id: '1', - }); + module('Normalize using findAll', function() { + test('normalizeResponse with embedded objects', async function(assert) { + this.owner.register( + 'serializer:home-planet', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); - env.owner.register( - 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - keyForRelationship(key) { - return key + '-custom'; - }, - attrs: { - villains: { embedded: 'always' }, - }, - }) - ); - - var serializer, json; - run(function() { - serializer = env.store.serializerFor('home-planet'); - - json = serializer.serialize(league._createSnapshot()); - }); + const serializer = store.serializerFor('home-planet'); + const HomePlanet = store.modelFor('home-planet'); + const rawPayload = { + homePlanets: [ + { + id: '1', + name: 'Umber', + villains: [ + { + id: '1', + firstName: 'Tom', + lastName: 'Dale', + }, + ], + }, + ], + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + HomePlanet, + rawPayload, + null, + 'findAll' + ); + const expectedOutput = { + data: [ + { + id: '1', + type: 'home-planet', + attributes: { + name: 'Umber', + }, + relationships: { + villains: { + data: [{ id: '1', type: 'super-villain' }], + }, + }, + }, + ], + included: [ + { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + lastName: 'Dale', + }, + relationships: {}, + }, + ], + }; + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'extracts embedded records for all resources in the primary payload' + ); + }); - assert.deepEqual(json, { - name: 'Villain League', - 'villains-custom': [ - { - id: get(tom, 'id'), - firstName: 'Tom', - lastName: 'Dale', - homePlanet: get(league, 'id'), - secretLab: null, - }, - ], - }); -}); + test('normalizeResponse with embedded objects with custom primary key', async function(assert) { + let { owner } = this; + owner.register( + 'serializer:super-villain', + RESTSerializer.extend({ + primaryKey: 'villain_id', + }) + ); + owner.register( + 'serializer:home-planet', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); + const serializer = store.serializerFor('home-planet'); + const HomePlanet = store.modelFor('home-planet'); + const rawPayload = { + homePlanets: [ + { + id: '1', + name: 'Umber', + villains: [ + { + villain_id: '2', + firstName: 'Alex', + lastName: 'Baizeau', + }, + ], + }, + ], + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + HomePlanet, + rawPayload, + null, + 'findAll' + ); + const expectedOutput = { + data: [ + { + id: '1', + type: 'home-planet', + attributes: { + name: 'Umber', + }, + relationships: { + villains: { + data: [{ id: '2', type: 'super-villain' }], + }, + }, + }, + ], + included: [ + { + id: '2', + type: 'super-villain', + attributes: { + firstName: 'Alex', + lastName: 'Baizeau', + }, + relationships: {}, + }, + ], + }; -testInDebug('serialize with embedded objects (unknown hasMany relationship)', function(assert) { - var league; - run(function() { - env.store.push({ - data: { - type: 'home-planet', - id: '123', - attributes: { - name: 'Villain League', - }, - }, + assert.deepEqual(normalizedJsonApi, expectedOutput, 'works with custom primaryKey'); }); - league = env.store.peekRecord('home-planet', 123); - }); - env.owner.register( - 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' }, - }, - }) - ); - - var serializer, json; - assert.expectWarning(function() { - run(function() { - serializer = env.store.serializerFor('home-planet'); - json = serializer.serialize(league._createSnapshot()); + // TODO this is a super weird test, probably not a valid scenario to have any guarantees around + test('normalizeResponse with embedded objects with identical relationship and attribute key ', async function(assert) { + this.owner.register( + 'serializer:home-planet', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + //Makes the keyForRelationship and keyForAttribute collide. + keyForRelationship(key, type) { + if (key === 'villains') { + return 'ourVillains'; + } + return this._super(key, type); + }, + keyForAttribute(key, type) { + if (key === 'name') { + return 'ourVillains'; + } + return this._super(key, type); + }, + }) + ); + + const serializer = store.serializerFor('home-planet'); + const HomePlanet = store.modelFor('home-planet'); + const rawPayload = { + homePlanets: [ + { + id: '1', + name: 'Umber', + ourVillains: [ + { + id: '1', + firstName: 'Alex', + lastName: 'Baizeau', + }, + ], + }, + ], + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + HomePlanet, + rawPayload, + null, + 'findAll' + ); + const expectedOutput = { + data: [ + { + id: '1', + type: 'home-planet', + attributes: { + // nothing maps to the original "name" key + // instead we find the "ourVillains" object for attributes as well + // bc "name" is defined using the "string" transform, we cast it to + // a "string" + name: `${[ + { + id: '1', + firstName: 'Alex', + lastName: 'Baizeau', + }, + ]}`, + }, + // we find this key for the relationship too + relationships: { + villains: { + data: [{ id: '1', type: 'super-villain' }], + }, + }, + }, + ], + included: [ + { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Alex', + lastName: 'Baizeau', + }, + relationships: {}, + }, + ], + }; + + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'when the key for a relationship and an attribute collide, ' + ); }); - }, /The embedded relationship 'villains' is undefined for 'home-planet' with id '123'. Please include it in your original payload./); - assert.deepEqual(json, { - name: 'Villain League', - villains: [], - }); -}); - -test('serialize with embedded objects (hasMany relationship) supports serialize:false', function(assert) { - let league = env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }); - env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - homePlanet: league, - id: '1', - }); - - env.owner.register( - 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { serialize: false }, - }, - }) - ); - var serializer, json; - run(function() { - serializer = env.store.serializerFor('home-planet'); - - json = serializer.serialize(league._createSnapshot()); - }); - - assert.deepEqual(json, { - name: 'Villain League', - }); -}); - -test('serialize with (new) embedded objects (hasMany relationship)', function(assert) { - let league = env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }); - env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - homePlanet: league, - }); - - env.owner.register( - 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always' }, - }, - }) - ); - var serializer, json; - run(function() { - serializer = env.store.serializerFor('home-planet'); - - json = serializer.serialize(league._createSnapshot()); - }); - assert.deepEqual(json, { - name: 'Villain League', - villains: [ - { - firstName: 'Tom', - lastName: 'Dale', - homePlanet: get(league, 'id'), - secretLab: null, - }, - ], - }); -}); - -test('serialize with embedded objects (hasMany relationships, including related objects not embedded)', function(assert) { - let superVillain = env.store.createRecord('super-villain', { - id: 1, - firstName: 'Super', - lastName: 'Villian', - }); - let evilMinion = env.store.createRecord('evil-minion', { - id: 1, - name: 'Evil Minion', - superVillian: superVillain, - }); - let secretWeapon = env.store.createRecord('secret-weapon', { - id: 1, - name: 'Secret Weapon', - superVillain: superVillain, - }); - - run(function() { - superVillain.get('evilMinions').pushObject(evilMinion); - superVillain.get('secretWeapons').pushObject(secretWeapon); - }); - - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - evilMinions: { serialize: 'records', deserialize: 'records' }, - secretWeapons: { serialize: 'ids' }, - }, - }) - ); - var serializer, json; - run(function() { - serializer = env.owner.lookup('serializer:super-villain'); - - json = serializer.serialize(superVillain._createSnapshot()); - }); - assert.deepEqual(json, { - firstName: get(superVillain, 'firstName'), - lastName: get(superVillain, 'lastName'), - homePlanet: null, - evilMinions: [ - { - id: get(evilMinion, 'id'), - name: get(evilMinion, 'name'), - superVillain: '1', - }, - ], - secretLab: null, - secretWeapons: ['1'], - }); -}); - -test('serialize has many relationship using the `ids-and-types` strategy', function(assert) { - let yellowMinion = env.store.createRecord('yellow-minion', { id: 1, name: 'Yellowy' }); - let redMinion = env.store.createRecord('red-minion', { id: 1, name: 'Reddy' }); - let commanderVillain = env.store.createRecord('commander-villain', { - id: 1, - name: 'Jeff', - minions: [yellowMinion, redMinion], - }); - - env.owner.register( - 'serializer:commander-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - minions: { serialize: 'ids-and-types' }, - }, - }) - ); - var serializer, json; - run(function() { - serializer = env.owner.lookup('serializer:commander-villain'); - var snapshot = commanderVillain._createSnapshot(); - json = serializer.serialize(snapshot); - }); - - assert.deepEqual(json, { - name: 'Jeff', - minions: [ - { - id: '1', - type: 'yellow-minion', - }, - { - id: '1', - type: 'red-minion', - }, - ], - }); -}); - -test('normalizeResponse with embedded object (belongsTo relationship)', function(assert) { - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' }, - }, - }) - ); - - var serializer = env.store.serializerFor('super-villain'); - - var json_hash = { - super_villain: { - id: '1', - firstName: 'Tom', - lastName: 'Dale', - homePlanet: '123', - evilMinions: ['1', '2', '3'], - secretLab: { - minionCapacity: 5000, - vicinity: 'California, USA', - id: '101', - }, - secretWeapons: [], - }, - }; - let json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); - - assert.deepEqual(json, { - data: { - id: '1', - type: 'super-villain', - attributes: { - firstName: 'Tom', - lastName: 'Dale', - }, - relationships: { - evilMinions: { - data: [ - { id: '1', type: 'evil-minion' }, - { id: '2', type: 'evil-minion' }, - { id: '3', type: 'evil-minion' }, - ], - }, - homePlanet: { - data: { id: '123', type: 'home-planet' }, - }, - secretLab: { - data: { id: '101', type: 'secret-lab' }, - }, - secretWeapons: { - data: [], - }, - }, - }, - included: [ - { - id: '101', - type: 'secret-lab', - attributes: { - minionCapacity: 5000, - vicinity: 'California, USA', - }, - relationships: {}, - }, - ], - }); -}); - -test('serialize with embedded object (belongsTo relationship)', function(assert) { - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' }, - }, - }) - ); - - // records with an id, persisted - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - id: '1', - secretLab: env.store.createRecord('secret-lab', { - minionCapacity: 5000, - vicinity: 'California, USA', - id: '101', - }), - homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), - }); - - let json = env.store.serializerFor('super-villain').serialize(tom._createSnapshot()); - - assert.deepEqual(json, { - firstName: get(tom, 'firstName'), - lastName: get(tom, 'lastName'), - homePlanet: get(tom, 'homePlanet').get('id'), - secretLab: { - id: get(tom, 'secretLab').get('id'), - minionCapacity: get(tom, 'secretLab').get('minionCapacity'), - vicinity: get(tom, 'secretLab').get('vicinity'), - }, - }); -}); - -test('serialize with embedded object (polymorphic belongsTo relationship)', function(assert) { - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' }, - }, - }) - ); - - SuperVillain.reopen({ - secretLab: DS.belongsTo('secret-lab', { polymorphic: true }), - }); - - let tom = env.store.createRecord('super-villain', { - id: '1', - firstName: 'Tom', - lastName: 'Dale', - secretLab: env.store.createRecord('bat-cave', { - id: '101', - minionCapacity: 5000, - vicinity: 'California, USA', - infiltrated: true, - }), - homePlanet: env.store.createRecord('home-planet', { - id: '123', - name: 'Villain League', - }), - }); - - let json = tom.serialize(); - - assert.deepEqual(json, { - firstName: get(tom, 'firstName'), - lastName: get(tom, 'lastName'), - homePlanet: get(tom, 'homePlanet').get('id'), - secretLabType: 'batCave', - secretLab: { - id: get(tom, 'secretLab').get('id'), - minionCapacity: get(tom, 'secretLab').get('minionCapacity'), - vicinity: get(tom, 'secretLab').get('vicinity'), - infiltrated: true, - }, - }); -}); - -test('serialize with embedded object (belongsTo relationship) works with different primaryKeys', function(assert) { - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - primaryKey: '_id', - attrs: { - secretLab: { embedded: 'always' }, - }, - }) - ); - env.owner.register( - 'serializer:secret-lab', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - primaryKey: 'crazy_id', - }) - ); - - var serializer = env.store.serializerFor('super-villain'); - - // records with an id, persisted - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - id: '1', - secretLab: env.store.createRecord('secret-lab', { - minionCapacity: 5000, - vicinity: 'California, USA', - id: '101', - }), - homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), - }); - - let json = serializer.serialize(tom._createSnapshot()); - - assert.deepEqual(json, { - firstName: get(tom, 'firstName'), - lastName: get(tom, 'lastName'), - homePlanet: get(tom, 'homePlanet').get('id'), - secretLab: { - crazy_id: get(tom, 'secretLab').get('id'), - minionCapacity: get(tom, 'secretLab').get('minionCapacity'), - vicinity: get(tom, 'secretLab').get('vicinity'), - }, - }); -}); - -test('serialize with embedded object (belongsTo relationship, new no id)', function(assert) { - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' }, - }, - }) - ); - - var serializer = env.store.serializerFor('super-villain'); - - // records without ids, new - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - secretLab: env.store.createRecord('secret-lab', { - minionCapacity: 5000, - vicinity: 'California, USA', - }), - homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), - }); - let json = serializer.serialize(tom._createSnapshot()); - - assert.deepEqual(json, { - firstName: get(tom, 'firstName'), - lastName: get(tom, 'lastName'), - homePlanet: get(tom, 'homePlanet').get('id'), - secretLab: { - minionCapacity: get(tom, 'secretLab').get('minionCapacity'), - vicinity: get(tom, 'secretLab').get('vicinity'), - }, - }); -}); - -test('serialize with embedded object (polymorphic belongsTo relationship) supports serialize:ids', function(assert) { - SuperVillain.reopen({ - secretLab: DS.belongsTo('secret-lab', { polymorphic: true }), - }); - - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { serialize: 'ids' }, - }, - }) - ); - - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - id: '1', - secretLab: env.store.createRecord('bat-cave', { - minionCapacity: 5000, - vicinity: 'California, USA', - id: '101', - }), - homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), - }); - - let json = tom.serialize(); - - assert.deepEqual(json, { - firstName: get(tom, 'firstName'), - lastName: get(tom, 'lastName'), - homePlanet: get(tom, 'homePlanet').get('id'), - secretLab: get(tom, 'secretLab').get('id'), - secretLabType: 'batCave', - }); -}); - -test('serialize with embedded object (belongsTo relationship) supports serialize:id', function(assert) { - SuperVillain.reopen({ - secretLab: DS.belongsTo('secret-lab', { polymorphic: true }), - }); - - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { serialize: 'id' }, - }, - }) - ); - - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - id: '1', - secretLab: env.store.createRecord('bat-cave', { - minionCapacity: 5000, - vicinity: 'California, USA', - id: '101', - }), - homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), - }); - - let json = tom.serialize(); - - assert.deepEqual(json, { - firstName: get(tom, 'firstName'), - lastName: get(tom, 'lastName'), - homePlanet: get(tom, 'homePlanet').get('id'), - secretLab: get(tom, 'secretLab').get('id'), - secretLabType: 'batCave', - }); -}); - -test('serialize with embedded object (belongsTo relationship) supports serialize:id in conjunction with deserialize:records', function(assert) { - SuperVillain.reopen({ - secretLab: DS.belongsTo('secret-lab', { polymorphic: true }), - }); - - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { serialize: 'id', deserialize: 'records' }, - }, - }) - ); - - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - id: '1', - secretLab: env.store.createRecord('bat-cave', { - minionCapacity: 5000, - vicinity: 'California, USA', - id: '101', - }), - homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), - }); - - let json = tom.serialize(); - - assert.deepEqual(json, { - firstName: get(tom, 'firstName'), - lastName: get(tom, 'lastName'), - homePlanet: get(tom, 'homePlanet').get('id'), - secretLab: get(tom, 'secretLab').get('id'), - secretLabType: 'batCave', - }); -}); - -test('serialize with embedded object (belongsTo relationship) supports serialize:ids', function(assert) { - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { serialize: 'ids' }, - }, - }) - ); - var serializer = env.store.serializerFor('super-villain'); - - // records with an id, persisted - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - id: '1', - secretLab: env.store.createRecord('secret-lab', { - minionCapacity: 5000, - vicinity: 'California, USA', - id: '101', - }), - homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), - }); - - let json = serializer.serialize(tom._createSnapshot()); - - assert.deepEqual(json, { - firstName: get(tom, 'firstName'), - lastName: get(tom, 'lastName'), - homePlanet: get(tom, 'homePlanet').get('id'), - secretLab: get(tom, 'secretLab').get('id'), - }); -}); - -test('serialize with embedded object (belongsTo relationship) supports serialize:id', function(assert) { - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { serialize: 'id' }, - }, - }) - ); - - var serializer = env.store.serializerFor('super-villain'); - - // records with an id, persisted - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - id: '1', - secretLab: env.store.createRecord('secret-lab', { - minionCapacity: 5000, - vicinity: 'California, USA', - id: '101', - }), - homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), - }); - let json = serializer.serialize(tom._createSnapshot()); - - assert.deepEqual(json, { - firstName: get(tom, 'firstName'), - lastName: get(tom, 'lastName'), - homePlanet: get(tom, 'homePlanet').get('id'), - secretLab: get(tom, 'secretLab').get('id'), - }); -}); - -test('serialize with embedded object (belongsTo relationship) supports serialize:id in conjunction with deserialize:records', function(assert) { - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { serialize: 'id', deserialize: 'records' }, - }, - }) - ); - - var serializer = env.store.serializerFor('super-villain'); - - // records with an id, persisted - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - id: '1', - secretLab: env.store.createRecord('secret-lab', { - minionCapacity: 5000, - vicinity: 'California, USA', - id: '101', - }), - homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), - }); - let json = serializer.serialize(tom._createSnapshot()); - - assert.deepEqual(json, { - firstName: get(tom, 'firstName'), - lastName: get(tom, 'lastName'), - homePlanet: get(tom, 'homePlanet').get('id'), - secretLab: get(tom, 'secretLab').get('id'), - }); -}); - -test('serialize with embedded object (belongsTo relationship) supports serialize:false', function(assert) { - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { serialize: false }, - }, - }) - ); - var serializer = env.store.serializerFor('super-villain'); - - // records with an id, persisted - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - id: '1', - secretLab: env.store.createRecord('secret-lab', { - minionCapacity: 5000, - vicinity: 'California, USA', - id: '101', - }), - homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), - }); - let json = serializer.serialize(tom._createSnapshot()); - - assert.deepEqual(json, { - firstName: get(tom, 'firstName'), - lastName: get(tom, 'lastName'), - homePlanet: get(tom, 'homePlanet').get('id'), - }); -}); + test('normalizeResponse with embedded objects of same type as primary type', async function(assert) { + this.owner.register( + 'serializer:comment', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + children: { embedded: 'always' }, + }, + }) + ); + const serializer = store.serializerFor('comment'); + const Comment = store.modelFor('comment'); + const rawPayload = { + comments: [ + { + id: '1', + body: 'Hello', + root: true, + children: [ + { + id: '2', + body: 'World', + root: false, + }, + { + id: '3', + body: 'Foo', + root: false, + }, + ], + }, + ], + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + Comment, + rawPayload, + null, + 'findAll' + ); + const expectedOutput = { + data: [ + { + id: '1', + type: 'comment', + attributes: { + body: 'Hello', + root: true, + }, + relationships: { + children: { + data: [{ id: '2', type: 'comment' }, { id: '3', type: 'comment' }], + }, + }, + }, + ], + included: [ + { + id: '2', + type: 'comment', + attributes: { + body: 'World', + root: false, + }, + relationships: {}, + }, + { + id: '3', + type: 'comment', + attributes: { + body: 'Foo', + root: false, + }, + relationships: {}, + }, + ], + }; -test('serialize with embedded object (belongsTo relationship) serializes the id by default if no option specified', function(assert) { - env.owner.register('serializer:super-villain', DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin)); - var serializer = env.store.serializerFor('super-villain'); - - // records with an id, persisted - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - id: '1', - secretLab: env.store.createRecord('secret-lab', { - minionCapacity: 5000, - vicinity: 'California, USA', - id: '101', - }), - homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), - }); - let json = serializer.serialize(tom._createSnapshot()); + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'We normalized to json-api and data only includes the primary resources' + ); + }); - assert.deepEqual(json, { - firstName: get(tom, 'firstName'), - lastName: get(tom, 'lastName'), - homePlanet: get(tom, 'homePlanet').get('id'), - secretLab: get(tom, 'secretLab').get('id'), - }); -}); + test('normalizeResponse with embedded objects of same type, but from separate attributes', async function(assert) { + let { owner } = this; + const HomePlanetClass = Model.extend({ + name: attr('string'), + villains: hasMany('super-villain', { inverse: 'homePlanet', async: false }), + reformedVillains: hasMany('superVillain', { async: false }), + }); + owner.unregister('model:home-planet'); + owner.register('model:home-planet', HomePlanetClass); + owner.register( + 'serializer:home-planet', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + reformedVillains: { embedded: 'always' }, + }, + }) + ); + const serializer = store.serializerFor('home-planet'); + const HomePlanet = store.modelFor('home-planet'); + const rawPayload = { + homePlanets: [ + { + id: '1', + name: 'Earth', + villains: [ + { + id: '1', + firstName: 'Tom', + }, + { + id: '3', + firstName: 'Yehuda', + }, + ], + reformedVillains: [ + { + id: '2', + firstName: 'Alex', + }, + { + id: '4', + firstName: 'Erik', + }, + ], + }, + { + id: '2', + name: 'Mars', + villains: [ + { + id: '1', + firstName: 'Tom', + }, + { + id: '3', + firstName: 'Yehuda', + }, + ], + reformedVillains: [ + { + id: '5', + firstName: 'Peter', + }, + { + id: '6', + firstName: 'Trek', + }, + ], + }, + ], + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + HomePlanet, + rawPayload, + null, + 'findAll' + ); + const expectedOutput = { + data: [ + { + id: '1', + type: 'home-planet', + attributes: { + name: 'Earth', + }, + relationships: { + reformedVillains: { + data: [{ id: '2', type: 'super-villain' }, { id: '4', type: 'super-villain' }], + }, + villains: { + data: [{ id: '1', type: 'super-villain' }, { id: '3', type: 'super-villain' }], + }, + }, + }, + { + id: '2', + type: 'home-planet', + attributes: { + name: 'Mars', + }, + relationships: { + reformedVillains: { + data: [{ id: '5', type: 'super-villain' }, { id: '6', type: 'super-villain' }], + }, + villains: { + data: [{ id: '1', type: 'super-villain' }, { id: '3', type: 'super-villain' }], + }, + }, + }, + ], + included: [ + { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + }, + relationships: {}, + }, + { + id: '3', + type: 'super-villain', + attributes: { + firstName: 'Yehuda', + }, + relationships: {}, + }, + { + id: '2', + type: 'super-villain', + attributes: { + firstName: 'Alex', + }, + relationships: {}, + }, + { + id: '4', + type: 'super-villain', + attributes: { + firstName: 'Erik', + }, + relationships: {}, + }, + { + id: '1', + type: 'super-villain', + attributes: { + firstName: 'Tom', + }, + relationships: {}, + }, + { + id: '3', + type: 'super-villain', + attributes: { + firstName: 'Yehuda', + }, + relationships: {}, + }, + { + id: '5', + type: 'super-villain', + attributes: { + firstName: 'Peter', + }, + relationships: {}, + }, + { + id: '6', + type: 'super-villain', + attributes: { + firstName: 'Trek', + }, + relationships: {}, + }, + ], + }; -test('when related record is not present, serialize embedded record (with a belongsTo relationship) as null', function(assert) { - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' }, - }, - }) - ); - var serializer = env.store.serializerFor('super-villain'); - let tom = env.store.createRecord('super-villain', { - firstName: 'Tom', - lastName: 'Dale', - id: '1', - homePlanet: env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }), - }); - let json = serializer.serialize(tom._createSnapshot()); + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'We normalized to json-api and only the primary resources are in data, embedded of the same type is in included' + ); + }); - assert.deepEqual(json, { - firstName: get(tom, 'firstName'), - lastName: get(tom, 'lastName'), - homePlanet: get(tom, 'homePlanet').get('id'), - secretLab: null, - }); -}); + test('normalizeResponse with embedded object (belongsTo relationship)', async function(assert) { + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); -test('normalizeResponse with multiply-nested belongsTo', function(assert) { - env.owner.register( - 'serializer:evil-minion', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - superVillain: { embedded: 'always' }, - }, - }) - ); - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - homePlanet: { embedded: 'always' }, - }, - }) - ); - - var serializer = env.store.serializerFor('evil-minion'); - var json_hash = { - evilMinion: { - id: '1', - name: 'Alex', - superVillain: { - id: '1', - firstName: 'Tom', - lastName: 'Dale', - evilMinions: ['1'], - homePlanet: { + const serializer = store.serializerFor('super-villain'); + const SuperVillain = store.modelFor('super-villain'); + const rawPayload = { + super_villain: { id: '1', - name: 'Umber', - villains: ['1'], - }, - }, - }, - }; - var json; - - run(function() { - json = serializer.normalizeResponse(env.store, EvilMinion, json_hash, '1', 'findRecord'); - }); - - assert.deepEqual( - json, - { - data: { - id: '1', - type: 'evil-minion', - attributes: { - name: 'Alex', - }, - relationships: { - superVillain: { - data: { id: '1', type: 'super-villain' }, - }, - }, - }, - included: [ - { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + evilMinions: ['1', '2', '3'], + secretLab: { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }, + secretWeapons: [], + }, + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + SuperVillain, + rawPayload, + '1', + 'findRecord' + ); + const expectedOutput = { + data: { id: '1', type: 'super-villain', attributes: { @@ -1880,715 +1498,1381 @@ test('normalizeResponse with multiply-nested belongsTo', function(assert) { }, relationships: { evilMinions: { - data: [{ id: '1', type: 'evil-minion' }], + data: [ + { id: '1', type: 'evil-minion' }, + { id: '2', type: 'evil-minion' }, + { id: '3', type: 'evil-minion' }, + ], }, homePlanet: { - data: { id: '1', type: 'home-planet' }, + data: { id: '123', type: 'home-planet' }, + }, + secretLab: { + data: { id: '101', type: 'secret-lab' }, + }, + secretWeapons: { + data: [], }, }, }, - { + included: [ + { + id: '101', + type: 'secret-lab', + attributes: { + minionCapacity: 5000, + vicinity: 'California, USA', + }, + relationships: {}, + }, + ], + }; + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'we normalized to json-api and extracted the embedded belongsTo' + ); + }); + + test('normalizeResponse with polymorphic hasMany', async function(assert) { + let { owner } = this; + + const SuperVillainClass = Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + homePlanet: belongsTo('home-planet', { inverse: 'villains', async: true }), + secretLab: belongsTo('secret-lab', { async: false }), + secretWeapons: hasMany('secretWeapon', { polymorphic: true, async: false }), + evilMinions: hasMany('evil-minion', { async: false }), + }); + + owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretWeapons: { embedded: 'always' }, + }, + }) + ); + owner.unregister('model:super-villain'); + owner.register('model:super-villain', SuperVillainClass); + + const serializer = store.serializerFor('super-villain'); + const SuperVillain = store.modelFor('super-villain'); + const rawPayload = { + super_villain: { id: '1', - type: 'home-planet', + firstName: 'Tom', + lastName: 'Dale', + secretWeapons: [ + { + id: '1', + type: 'LightSaber', + name: "Tom's LightSaber", + color: 'Red', + }, + { + id: '1', + type: 'SecretWeapon', + name: 'The Death Star', + }, + ], + }, + }; + const normalizedJsonApi = serializer.normalizeResponse( + store, + SuperVillain, + rawPayload, + '1', + 'findAll' + ); + const expectedOutput = { + data: { + id: '1', + type: 'super-villain', attributes: { - name: 'Umber', + firstName: 'Tom', + lastName: 'Dale', }, relationships: { - villains: { - data: [{ id: '1', type: 'super-villain' }], + secretWeapons: { + data: [{ id: '1', type: 'light-saber' }, { id: '1', type: 'secret-weapon' }], + }, + }, + }, + included: [ + { + id: '1', + type: 'light-saber', + attributes: { + color: 'Red', + name: "Tom's LightSaber", }, + relationships: {}, + }, + { + id: '1', + type: 'secret-weapon', + attributes: { + name: 'The Death Star', + }, + relationships: {}, + }, + ], + }; + + assert.deepEqual( + normalizedJsonApi, + expectedOutput, + 'We normalize to json-api with a polymorphic hasMany' + ); + }); + }); + + module('Serialize', function() { + test('serialize supports serialize:false on non-relationship properties', async function(assert) { + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + firstName: { serialize: false }, + }, + }) + ); + + const serializer = store.serializerFor('super-villain'); + const tom = store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + }); + const serializedRestJson = serializer.serialize(tom._createSnapshot()); + const expectedOutput = { + lastName: 'Dale', + homePlanet: null, + secretLab: null, + }; + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We do not serialize attrs defined with serialize:false' + ); + }); + + test('Mixin can be used with RESTSerializer which does not define keyForAttribute', async function(assert) { + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + evilMinions: { serialize: 'records', deserialize: 'records' }, + }, + }) + ); + + let homePlanet = store.createRecord('home-planet', { name: 'Villain League', id: '123' }); + let secretLab = store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }); + let superVillain = store.createRecord('super-villain', { + id: '1', + firstName: 'Super', + lastName: 'Villian', + homePlanet, + secretLab, + }); + let secretWeapon = store.createRecord('secret-weapon', { + id: '1', + name: 'Secret Weapon', + superVillain, + }); + + superVillain.get('secretWeapons').pushObject(secretWeapon); + + let evilMinion = store.createRecord('evil-minion', { + id: '1', + name: 'Evil Minion', + superVillain, + }); + superVillain.get('evilMinions').pushObject(evilMinion); + + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(superVillain._createSnapshot()); + const expectedOutput = { + firstName: 'Super', + lastName: 'Villian', + homePlanet: '123', + evilMinions: [ + { + id: '1', + name: 'Evil Minion', + superVillain: '1', + }, + ], + secretLab: '101', + // "manyToOne" relation does not serialize by default + // secretWeapons: ["1"] + }; + + assert.deepEqual(serializedRestJson, expectedOutput, 'we serialize correctly'); + }); + + test('serializing relationships with an embedded and without calls super when not attr not present', async function(assert) { + let { owner } = this; + let calledSerializeBelongsTo = false; + let calledSerializeHasMany = false; + + const Serializer = RESTSerializer.extend({ + serializeBelongsTo(snapshot, json, relationship) { + calledSerializeBelongsTo = true; + return this._super(snapshot, json, relationship); + }, + + serializeHasMany(snapshot, json, relationship) { + calledSerializeHasMany = true; + let key = relationship.key; + let payloadKey = this.keyForRelationship ? this.keyForRelationship(key, 'hasMany') : key; + let relationshipType = snapshot.type.determineRelationshipType(relationship); + // "manyToOne" not supported in ActiveModelSerializer.prototype.serializeHasMany + let relationshipTypes = ['manyToNone', 'manyToMany', 'manyToOne']; + if (relationshipTypes.indexOf(relationshipType) > -1) { + json[payloadKey] = snapshot.hasMany(key, { ids: true }); + } + }, + }); + + owner.register('serializer:evil-minion', Serializer); + owner.register('serializer:secret-weapon', Serializer); + owner.register( + 'serializer:super-villain', + Serializer.extend(EmbeddedRecordsMixin, { + attrs: { + evilMinions: { serialize: 'records', deserialize: 'records' }, + // some relationships are not listed here, so super should be called on those + // e.g. secretWeapons: { serialize: 'ids' } + }, + }) + ); + + let homePlanet = store.createRecord('home-planet', { + name: 'Villain League', + id: '123', + }); + let secretLab = store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }); + let superVillain = store.createRecord('super-villain', { + id: '1', + firstName: 'Super', + lastName: 'Villian', + homePlanet, + secretLab, + }); + let secretWeapon = store.createRecord('secret-weapon', { + id: '1', + name: 'Secret Weapon', + superVillain, + }); + + superVillain.get('secretWeapons').pushObject(secretWeapon); + let evilMinion = store.createRecord('evil-minion', { + id: '1', + name: 'Evil Minion', + superVillain, + }); + superVillain.get('evilMinions').pushObject(evilMinion); + + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(superVillain._createSnapshot()); + const expectedOutput = { + firstName: 'Super', + lastName: 'Villian', + homePlanet: '123', + evilMinions: [ + { + id: '1', + name: 'Evil Minion', + superVillain: '1', }, - }, - ], - }, - 'Primary hash was correct' - ); -}); + ], + secretLab: '101', + // customized serializeHasMany method to generate ids for "manyToOne" relation + secretWeapons: ['1'], + }; + + assert.deepEqual(serializedRestJson, expectedOutput, 'we serialized correctly'); + assert.ok(calledSerializeBelongsTo); + assert.ok(calledSerializeHasMany); + }); -test('normalizeResponse with polymorphic hasMany', function(assert) { - SuperVillain.reopen({ - secretWeapons: DS.hasMany('secretWeapon', { polymorphic: true, async: false }), - }); + module('Serialize hasMany', function() { + test('serialize with embedded objects (hasMany relationship)', async function(assert) { + this.owner.register( + 'serializer:home-planet', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretWeapons: { embedded: 'always' }, - }, - }) - ); - var serializer = env.store.serializerFor('super-villain'); - - var json_hash = { - super_villain: { - id: '1', - firstName: 'Tom', - lastName: 'Dale', - secretWeapons: [ - { + let homePlanet = store.createRecord('home-planet', { + name: 'Villain League', + id: '123', + }); + store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + homePlanet, id: '1', - type: 'LightSaber', - name: "Tom's LightSaber", - color: 'Red', - }, - { + }); + const serializer = store.serializerFor('home-planet'); + const serializedRestJson = serializer.serialize(homePlanet._createSnapshot()); + const expectedOutput = { + name: 'Villain League', + villains: [ + { + id: '1', + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + secretLab: null, + }, + ], + }; + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We serialized the hasMany relationship into an embedded object' + ); + }); + + test('serialize with embedded objects and a custom keyForAttribute (hasMany relationship)', async function(assert) { + this.owner.register( + 'serializer:home-planet', + RESTSerializer.extend(EmbeddedRecordsMixin, { + keyForRelationship(key) { + return key + '-custom'; + }, + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); + let homePlanet = store.createRecord('home-planet', { + name: 'Villain League', + id: '123', + }); + store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + homePlanet, id: '1', - type: 'SecretWeapon', - name: 'The Death Star', - }, - ], - }, - }; - var json; + }); - run(function() { - json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findAll'); - }); + const serializer = store.serializerFor('home-planet'); + const serializedRestJson = serializer.serialize(homePlanet._createSnapshot()); + const expectedOutput = { + name: 'Villain League', + 'villains-custom': [ + { + id: '1', + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + secretLab: null, + }, + ], + }; + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We serialized the hasMany into an embedded format with a custom key' + ); + }); + + testInDebug('serialize with embedded objects (unknown hasMany relationship)', async function( + assert + ) { + this.owner.register( + 'serializer:home-planet', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); + + store.push({ + data: { + type: 'home-planet', + id: '123', + attributes: { + name: 'Villain League', + }, + }, + }); + const serializer = store.serializerFor('home-planet'); + let league = store.peekRecord('home-planet', 123); + let serializedRestJson; + const expectedOutput = { + name: 'Villain League', + villains: [], + }; + + assert.expectWarning(function() { + serializedRestJson = serializer.serialize(league._createSnapshot()); + }, /The embedded relationship 'villains' is undefined for 'home-planet' with id '123'. Please include it in your original payload./); + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We serialize the missing hasMany to an empty array' + ); + }); + + test('serialize with embedded objects (hasMany relationship) supports serialize:false', async function(assert) { + this.owner.register( + 'serializer:home-planet', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + villains: { serialize: false }, + }, + }) + ); - assert.deepEqual( - json, - { - data: { - id: '1', - type: 'super-villain', - attributes: { + let homePlanet = store.createRecord('home-planet', { + name: 'Villain League', + id: '123', + }); + store.createRecord('super-villain', { firstName: 'Tom', lastName: 'Dale', - }, - relationships: { - secretWeapons: { - data: [{ id: '1', type: 'light-saber' }, { id: '1', type: 'secret-weapon' }], - }, - }, - }, - included: [ - { - id: '1', - type: 'light-saber', - attributes: { - color: 'Red', - name: "Tom's LightSaber", - }, - relationships: {}, - }, - { + homePlanet, id: '1', - type: 'secret-weapon', - attributes: { - name: 'The Death Star', - }, - relationships: {}, - }, - ], - }, - 'Primary hash was correct' - ); -}); + }); -test('normalizeResponse with polymorphic hasMany and custom primary key', function(assert) { - SuperVillain.reopen({ - secretWeapons: DS.hasMany('secretWeapon', { polymorphic: true, async: false }), - }); + const serializer = store.serializerFor('home-planet'); + const serializedRestJson = serializer.serialize(homePlanet._createSnapshot()); + const expectedOutput = { + name: 'Villain League', + }; - env.owner.register( - 'serializer:light-saber', - DS.RESTSerializer.extend({ - primaryKey: 'custom', - }) - ); - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretWeapons: { embedded: 'always' }, - }, - }) - ); - var serializer = env.store.serializerFor('super-villain'); - - var json_hash = { - super_villain: { - id: '1', - firstName: 'Tom', - lastName: 'Dale', - secretWeapons: [ - { - custom: '1', - type: 'LightSaber', - name: "Tom's LightSaber", - color: 'Red', - }, - { - id: '1', - type: 'SecretWeapon', - name: 'The Death Star', - }, - ], - }, - }; - var json; + assert.deepEqual(serializedRestJson, expectedOutput, 'We do not serialize the hasMany'); + }); - run(function() { - json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); - }); + test('serialize with (new) embedded objects (hasMany relationship)', async function(assert) { + this.owner.register( + 'serializer:home-planet', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always' }, + }, + }) + ); - assert.deepEqual( - json, - { - data: { - attributes: { + let homePlanet = store.createRecord('home-planet', { + name: 'Villain League', + id: '123', + }); + store.createRecord('super-villain', { firstName: 'Tom', lastName: 'Dale', - }, - id: '1', - relationships: { - secretWeapons: { - data: [{ type: 'light-saber', id: '1' }, { type: 'secret-weapon', id: '1' }], - }, - }, - type: 'super-villain', - }, - included: [ - { - attributes: { - color: 'Red', - name: "Tom's LightSaber", - }, - id: '1', - relationships: {}, - type: 'light-saber', - }, - { - attributes: { - name: 'The Death Star', - }, - id: '1', - relationships: {}, - type: 'secret-weapon', - }, - ], - }, - 'Custom primary key of embedded hasMany is correctly normalized' - ); -}); - -test('normalizeResponse with polymorphic belongsTo', function(assert) { - SuperVillain.reopen({ - secretLab: DS.belongsTo('secretLab', { polymorphic: true, async: true }), - }); - - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' }, - }, - }) - ); - var serializer = env.store.serializerFor('super-villain'); - - var json_hash = { - super_villain: { - id: '1', - firstName: 'Tom', - lastName: 'Dale', - secretLab: { - id: '1', - type: 'bat-cave', - infiltrated: true, - }, - }, - }; - - var json; + homePlanet, + }); + const serializer = store.serializerFor('home-planet'); + const serializedRestJson = serializer.serialize(homePlanet._createSnapshot()); + const expectedOutput = { + name: 'Villain League', + villains: [ + { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + secretLab: null, + }, + ], + }; + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We embed new members of a hasMany when serializing even if they do not have IDs' + ); + }); + + test('serialize with embedded objects (hasMany relationships, including related objects not embedded)', async function(assert) { + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + evilMinions: { serialize: 'records', deserialize: 'records' }, + secretWeapons: { serialize: 'ids' }, + }, + }) + ); + + let superVillain = store.createRecord('super-villain', { + id: 1, + firstName: 'Super', + lastName: 'Villian', + }); + let evilMinion = store.createRecord('evil-minion', { + id: 1, + name: 'Evil Minion', + superVillain, + }); + let secretWeapon = store.createRecord('secret-weapon', { + id: 1, + name: 'Secret Weapon', + superVillain, + }); + + superVillain.get('evilMinions').pushObject(evilMinion); + superVillain.get('secretWeapons').pushObject(secretWeapon); + + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(superVillain._createSnapshot()); + const expectedOutput = { + firstName: 'Super', + lastName: 'Villian', + homePlanet: null, + evilMinions: [ + { + id: '1', + name: 'Evil Minion', + superVillain: '1', + }, + ], + secretLab: null, + secretWeapons: ['1'], + }; + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We only embed relationships we are told to embed' + ); + }); + + test('serialize has many relationship using the `ids-and-types` strategy', async function(assert) { + let { owner } = this; + const NormalMinion = Model.extend({ + name: attr('string'), + }); + const YellowMinion = NormalMinion.extend(); + const RedMinion = NormalMinion.extend(); + const CommanderVillain = Model.extend({ + name: attr('string'), + minions: hasMany('normal-minion', { polymorphic: true }), + }); + + owner.register('model:commander-villain', CommanderVillain); + owner.register('model:normal-minion', NormalMinion); + owner.register('model:yellow-minion', YellowMinion); + owner.register('model:red-minion', RedMinion); + owner.register( + 'serializer:commander-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + minions: { serialize: 'ids-and-types' }, + }, + }) + ); + + let yellowMinion = store.createRecord('yellow-minion', { + id: 1, + name: 'Yellowy', + }); + let redMinion = store.createRecord('red-minion', { + id: 1, + name: 'Reddy', + }); + let commanderVillain = store.createRecord('commander-villain', { + id: 1, + name: 'Jeff', + minions: [yellowMinion, redMinion], + }); + + const serializer = store.serializerFor('commander-villain'); + const serializedRestJson = serializer.serialize(commanderVillain._createSnapshot()); + const expectedOutput = { + name: 'Jeff', + minions: [ + { + id: '1', + type: 'yellow-minion', + }, + { + id: '1', + type: 'red-minion', + }, + ], + }; + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We serialized both ids and types for the hasMany' + ); + }); + + test('serializing embedded hasMany respects remapped attrs key', async function(assert) { + let { owner } = this; + owner.register( + 'serializer:home-planet', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + villains: { embedded: 'always', key: 'notable_persons' }, + }, + }) + ); + owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + homePlanet: { serialize: false }, + secretLab: { serialize: false }, + }, + }) + ); + + let homePlanet = store.createRecord('home-planet', { name: 'Hoth' }); + store.createRecord('super-villain', { + firstName: 'Ice', + lastName: 'Creature', + homePlanet: homePlanet, + }); + + const serializer = store.serializerFor('home-planet'); + const serializedRestJson = serializer.serialize(homePlanet._createSnapshot()); + const expectedOutput = { + name: 'Hoth', + notable_persons: [ + { + firstName: 'Ice', + lastName: 'Creature', + }, + ], + }; + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'we normalized to json-api and remapped the hasMany relationship' + ); + }); + + test('serializing ids hasMany respects remapped attrs key', async function(assert) { + let { owner } = this; + owner.register( + 'serializer:home-planet', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + villains: { serialize: 'ids', key: 'notable_persons' }, + }, + }) + ); + owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + homePlanet: { serialize: false }, + secretLab: { serialize: false }, + }, + }) + ); + + let homePlanet = store.createRecord('home-planet', { name: 'Hoth' }); + let superVillain = store.createRecord('super-villain', { + firstName: 'Ice', + lastName: 'Creature', + homePlanet, + }); + + const serializer = store.serializerFor('home-planet'); + const serializedRestJson = serializer.serialize(homePlanet._createSnapshot()); + const expectedOutput = { + name: 'Hoth', + notable_persons: [superVillain.id], + }; + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'we serialized respecting the custom key in attrs' + ); + }); + }); - run(function() { - json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); - }); + module('Serialize belongsTo', function() { + test('serialize with embedded object (belongsTo relationship)', async function(assert) { + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); - assert.deepEqual( - json, - { - data: { - id: '1', - type: 'super-villain', - attributes: { + // records with an id, persisted + let secretLab = store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }); + let tom = store.createRecord('super-villain', { firstName: 'Tom', lastName: 'Dale', - }, - relationships: { + id: '1', + secretLab, + homePlanet: store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(tom._createSnapshot()); + const expectedOutput = { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', secretLab: { - data: { id: '1', type: 'bat-cave' }, - }, - }, - }, - included: [ - { + id: '101', + minionCapacity: 5000, + vicinity: 'California, USA', + }, + }; + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We embed belongsTo relationships when serializing if specified' + ); + }); + + test('serialize with embedded object (polymorphic belongsTo relationship)', async function(assert) { + let { owner } = this; + owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); + const SuperVillain = Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + homePlanet: belongsTo('home-planet', { inverse: 'villains', async: true }), + secretLab: belongsTo('secret-lab', { polymorphic: true }), + secretWeapons: hasMany('secret-weapon', { async: false }), + evilMinions: hasMany('evil-minion', { async: false }), + }); + owner.unregister('model:super-villain'); + owner.register('model:super-villain', SuperVillain); + + let tom = store.createRecord('super-villain', { id: '1', - type: 'bat-cave', - attributes: { + firstName: 'Tom', + lastName: 'Dale', + secretLab: store.createRecord('bat-cave', { + id: '101', + minionCapacity: 5000, + vicinity: 'California, USA', infiltrated: true, - }, - relationships: {}, - }, - ], - }, - 'Primary has was correct' - ); -}); - -test('normalizeResponse with polymorphic belongsTo and custom primary key', function(assert) { - assert.expect(1); - - SuperVillain.reopen({ - secretLab: DS.belongsTo('secretLab', { polymorphic: true, async: true }), - }); - - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretLab: { embedded: 'always' }, - }, - }) - ); - env.owner.register( - 'serializer:bat-cave', - DS.RESTSerializer.extend({ - primaryKey: 'custom', - }) - ); - var serializer = env.store.serializerFor('super-villain'); - - var json_hash = { - superVillain: { - id: '1', - firstName: 'Tom', - lastName: 'Dale', - secretLab: { - custom: '1', - type: 'bat-cave', - infiltrated: true, - }, - }, - }; - - var json; - - run(function() { - json = serializer.normalizeResponse(env.store, SuperVillain, json_hash, '1', 'findRecord'); - }); - - assert.deepEqual( - json, - { - data: { - attributes: { + }), + homePlanet: store.createRecord('home-planet', { + id: '123', + name: 'Villain League', + }), + }); + + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(tom._createSnapshot()); + const expectedOutput = { firstName: 'Tom', lastName: 'Dale', - }, - id: '1', - relationships: { + homePlanet: '123', + secretLabType: 'batCave', secretLab: { - data: { - id: '1', - type: 'bat-cave', - }, - }, - }, - type: 'super-villain', - }, - included: [ - { - attributes: { + id: '101', + minionCapacity: 5000, + vicinity: 'California, USA', infiltrated: true, }, + }; + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'we serialized an embedded polymorphic relationship correctly' + ); + }); + + test('serialize with embedded object (belongsTo relationship) works with different primaryKeys', async function(assert) { + let { owner } = this; + owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + primaryKey: '_id', + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); + owner.register( + 'serializer:secret-lab', + RESTSerializer.extend(EmbeddedRecordsMixin, { + primaryKey: 'crazy_id', + }) + ); + + const superVillainSerializer = store.serializerFor('super-villain'); + + // records with an id, persisted + let tom = store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', id: '1', - relationships: {}, - type: 'bat-cave', - }, - ], - }, - 'Custom primary key is correctly normalized' - ); -}); - -test('Mixin can be used with RESTSerializer which does not define keyForAttribute', function(assert) { - let homePlanet = env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }); - let secretLab = env.store.createRecord('secret-lab', { - minionCapacity: 5000, - vicinity: 'California, USA', - id: '101', - }); - let superVillain = env.store.createRecord('super-villain', { - id: '1', - firstName: 'Super', - lastName: 'Villian', - homePlanet: homePlanet, - secretLab: secretLab, - }); - let secretWeapon = env.store.createRecord('secret-weapon', { - id: '1', - name: 'Secret Weapon', - superVillain: superVillain, - }); - let evilMinion; - - run(function() { - superVillain.get('secretWeapons').pushObject(secretWeapon); - evilMinion = env.store.createRecord('evil-minion', { - id: '1', - name: 'Evil Minion', - superVillian: superVillain, - }); - superVillain.get('evilMinions').pushObject(evilMinion); - }); - - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - evilMinions: { serialize: 'records', deserialize: 'records' }, - }, - }) - ); - let serializer = env.store.serializerFor('super-villain'); - let json = serializer.serialize(superVillain._createSnapshot()); - - assert.deepEqual(json, { - firstName: get(superVillain, 'firstName'), - lastName: get(superVillain, 'lastName'), - homePlanet: '123', - evilMinions: [ - { - id: get(evilMinion, 'id'), - name: get(evilMinion, 'name'), - superVillain: '1', - }, - ], - secretLab: '101', - // "manyToOne" relation does not serialize ids - // sersecretWeapons: ["1"] - }); -}); + secretLab: store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); + + const serializedRestJson = superVillainSerializer.serialize(tom._createSnapshot(), { + includeId: true, + }); + const expectedOutput = { + _id: '1', + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + secretLab: { + crazy_id: '101', + minionCapacity: 5000, + vicinity: 'California, USA', + }, + }; + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We serialize the embedded belongsTo with the correct primaryKey field' + ); + }); + + test('serialize with embedded object (belongsTo relationship, new no id)', async function(assert) { + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); -test('normalize with custom belongsTo primary key', function(assert) { - env.owner.register( - 'serializer:evil-minion', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - superVillain: { embedded: 'always' }, - }, - }) - ); - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend({ - primaryKey: 'custom', - }) - ); - - var serializer = env.store.serializerFor('evil-minion'); - var json_hash = { - evilMinion: { - id: '1', - name: 'Alex', - superVillain: { - custom: '1', - firstName: 'Tom', - lastName: 'Dale', - }, - }, - }; - var json; + const serializer = store.serializerFor('super-villain'); - run(function() { - json = serializer.normalizeResponse(env.store, EvilMinion, json_hash, '1', 'findRecord'); - }); + // records without ids, new + let tom = store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + secretLab: store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + }), + homePlanet: store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); + const serializedRestJson = serializer.serialize(tom._createSnapshot()); + const expectedOutput = { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + secretLab: { + minionCapacity: 5000, + vicinity: 'California, USA', + }, + }; + + assert.deepEqual(serializedRestJson, expectedOutput); + }); + + test('serialize with embedded object (polymorphic belongsTo relationship) supports serialize:ids', async function(assert) { + let { owner } = this; + const SuperVillain = Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + homePlanet: belongsTo('home-planet', { inverse: 'villains', async: true }), + secretLab: belongsTo('secret-lab', { polymorphic: true }), + secretWeapons: hasMany('secret-weapon', { async: false }), + evilMinions: hasMany('evil-minion', { async: false }), + }); + owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretLab: { serialize: 'ids' }, + }, + }) + ); + owner.unregister('model:super-villain'); + owner.register('model:super-villain', SuperVillain); - assert.deepEqual( - json, - { - data: { - id: '1', - type: 'evil-minion', - attributes: { - name: 'Alex', - }, - relationships: { - superVillain: { - data: { id: '1', type: 'super-villain' }, - }, - }, - }, - included: [ - { + let tom = store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', id: '1', - type: 'super-villain', - attributes: { - firstName: 'Tom', - lastName: 'Dale', - }, - relationships: {}, - }, - ], - }, - 'Primary hash was correct' - ); -}); - -test('serializing relationships with an embedded and without calls super when not attr not present', function(assert) { - let homePlanet = env.store.createRecord('home-planet', { name: 'Villain League', id: '123' }); - let secretLab = env.store.createRecord('secret-lab', { - minionCapacity: 5000, - vicinity: 'California, USA', - id: '101', - }); - let superVillain = env.store.createRecord('super-villain', { - id: '1', - firstName: 'Super', - lastName: 'Villian', - homePlanet: homePlanet, - secretLab: secretLab, - }); - let secretWeapon = env.store.createRecord('secret-weapon', { - id: '1', - name: 'Secret Weapon', - superVillain: superVillain, - }); - let evilMinion; - - run(function() { - superVillain.get('secretWeapons').pushObject(secretWeapon); - evilMinion = env.store.createRecord('evil-minion', { - id: '1', - name: 'Evil Minion', - superVillian: superVillain, - }); - superVillain.get('evilMinions').pushObject(evilMinion); - }); - - var calledSerializeBelongsTo = false; - var calledSerializeHasMany = false; - - var Serializer = DS.RESTSerializer.extend({ - serializeBelongsTo(snapshot, json, relationship) { - calledSerializeBelongsTo = true; - return this._super(snapshot, json, relationship); - }, - serializeHasMany(snapshot, json, relationship) { - calledSerializeHasMany = true; - var key = relationship.key; - var payloadKey = this.keyForRelationship ? this.keyForRelationship(key, 'hasMany') : key; - var relationshipType = snapshot.type.determineRelationshipType(relationship); - // "manyToOne" not supported in DS.ActiveModelSerializer.prototype.serializeHasMany - var relationshipTypes = w('manyToNone manyToMany manyToOne'); - if (relationshipTypes.indexOf(relationshipType) > -1) { - json[payloadKey] = snapshot.hasMany(key, { ids: true }); - } - }, - }); - env.owner.register('serializer:evil-minion', Serializer); - env.owner.register('serializer:secret-weapon', Serializer); - env.owner.register( - 'serializer:super-villain', - Serializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - evilMinions: { serialize: 'records', deserialize: 'records' }, - // some relationships are not listed here, so super should be called on those - // e.g. secretWeapons: { serialize: 'ids' } - }, - }) - ); - let serializer = env.store.serializerFor('super-villain'); - let json = serializer.serialize(superVillain._createSnapshot()); - - assert.deepEqual(json, { - firstName: get(superVillain, 'firstName'), - lastName: get(superVillain, 'lastName'), - homePlanet: '123', - evilMinions: [ - { - id: get(evilMinion, 'id'), - name: get(evilMinion, 'name'), - superVillain: '1', - }, - ], - secretLab: '101', - // customized serializeHasMany method to generate ids for "manyToOne" relation - secretWeapons: ['1'], - }); - assert.ok(calledSerializeBelongsTo); - assert.ok(calledSerializeHasMany); -}); - -test('serializing belongsTo correctly removes embedded foreign key', function(assert) { - SecretWeapon.reopen({ - superVillain: null, - }); - EvilMinion.reopen({ - secretWeapon: DS.belongsTo('secret-weapon', { async: false }), - superVillain: null, - }); - - let secretWeapon = env.store.createRecord('secret-weapon', { name: 'Secret Weapon' }); - let evilMinion = env.store.createRecord('evil-minion', { - name: 'Evil Minion', - secretWeapon: secretWeapon, - }); - - env.owner.register( - 'serializer:evil-minion', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - secretWeapon: { embedded: 'always' }, - }, - }) - ); - - let serializer = env.store.serializerFor('evil-minion'); - let json = serializer.serialize(evilMinion._createSnapshot()); - - assert.deepEqual(json, { - name: 'Evil Minion', - secretWeapon: { - name: 'Secret Weapon', - }, - }); -}); + secretLab: store.createRecord('bat-cave', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); + + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(tom._createSnapshot()); + const expectedOutput = { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + secretLab: '101', + secretLabType: 'batCave', + }; + assert.deepEqual(serializedRestJson, expectedOutput, 'We serialize the polymorphic type'); + }); + + test('serialize with embedded object (belongsTo relationship) supports serialize:id', async function(assert) { + let { owner } = this; + const SuperVillain = Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + homePlanet: belongsTo('home-planet', { inverse: 'villains', async: true }), + secretLab: belongsTo('secret-lab', { polymorphic: true }), + secretWeapons: hasMany('secret-weapon', { async: false }), + evilMinions: hasMany('evil-minion', { async: false }), + }); + + owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretLab: { serialize: 'id' }, + }, + }) + ); + owner.unregister('model:super-villain'); + owner.register('model:super-villain', SuperVillain); -test('serializing embedded belongsTo respects remapped attrs key', function(assert) { - let homePlanet = env.store.createRecord('home-planet', { name: 'Hoth' }); - let superVillain = env.store.createRecord('super-villain', { - firstName: 'Ice', - lastName: 'Creature', - homePlanet: homePlanet, - }); + let tom = store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: store.createRecord('bat-cave', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); + + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(tom._createSnapshot()); + const expectedOutput = { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + secretLab: '101', + secretLabType: 'batCave', + }; + + assert.deepEqual(serializedRestJson, expectedOutput, 'We serialize the id'); + }); + + test('serialize with embedded object (belongsTo relationship) supports serialize:id in conjunction with deserialize:records', async function(assert) { + let { owner } = this; + const SuperVillain = Model.extend({ + firstName: attr('string'), + lastName: attr('string'), + homePlanet: belongsTo('home-planet', { inverse: 'villains', async: true }), + secretLab: belongsTo('secret-lab', { polymorphic: true }), + secretWeapons: hasMany('secret-weapon', { async: false }), + evilMinions: hasMany('evil-minion', { async: false }), + }); + + owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretLab: { serialize: 'id', deserialize: 'records' }, + }, + }) + ); + owner.unregister('model:super-villain'); + owner.register('model:super-villain', SuperVillain); - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - homePlanet: { embedded: 'always', key: 'favorite_place' }, - }, - }) - ); - - let serializer = env.store.serializerFor('super-villain'); - let json = serializer.serialize(superVillain._createSnapshot()); - - assert.deepEqual(json, { - firstName: 'Ice', - lastName: 'Creature', - favorite_place: { - name: 'Hoth', - }, - secretLab: null, - }); -}); + let tom = store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: store.createRecord('bat-cave', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); + + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(tom._createSnapshot()); + const expectedOutput = { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + secretLab: '101', + secretLabType: 'batCave', + }; + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We support serialize:ids when deserialize:records is present' + ); + }); + + test('serialize with embedded object (belongsTo relationship) supports serialize:ids', async function(assert) { + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretLab: { serialize: 'ids' }, + }, + }) + ); -test('serializing embedded hasMany respects remapped attrs key', function(assert) { - let homePlanet = env.store.createRecord('home-planet', { name: 'Hoth' }); - env.store.createRecord('super-villain', { - firstName: 'Ice', - lastName: 'Creature', - homePlanet: homePlanet, - }); + // records with an id, persisted + let tom = store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); + + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(tom._createSnapshot()); + const expectedOutput = { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + secretLab: '101', + }; + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We serialized the belongsTo relationships to IDs' + ); + }); + + test('serialize with embedded object (belongsTo relationship) supports serialize:id', async function(assert) { + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretLab: { serialize: 'id' }, + }, + }) + ); - env.owner.register( - 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { embedded: 'always', key: 'notable_persons' }, - }, - }) - ); - - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - homePlanet: { serialize: false }, - secretLab: { serialize: false }, - }, - }) - ); - - let serializer = env.store.serializerFor('home-planet'); - let json = serializer.serialize(homePlanet._createSnapshot()); - - assert.deepEqual(json, { - name: 'Hoth', - notable_persons: [ - { - firstName: 'Ice', - lastName: 'Creature', - }, - ], - }); -}); + // records with an id, persisted + let tom = store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); + + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(tom._createSnapshot()); + const expectedOutput = { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + secretLab: '101', + }; + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We serialized the belongsTo relationships to IDs' + ); + }); + + test('serialize with embedded object (belongsTo relationship) supports serialize:id in conjunction with deserialize:records', async function(assert) { + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretLab: { serialize: 'id', deserialize: 'records' }, + }, + }) + ); -test('serializing id belongsTo respects remapped attrs key', function(assert) { - let homePlanet = env.store.createRecord('home-planet', { name: 'Hoth' }); - let superVillain = env.store.createRecord('super-villain', { - firstName: 'Ice', - lastName: 'Creature', - homePlanet: homePlanet, - }); + // records with an id, persisted + let tom = store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); + + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(tom._createSnapshot()); + const expectedOutput = { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + secretLab: '101', + }; + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We serialized the belongsTo relationships to IDs' + ); + }); + + test('serialize with embedded object (belongsTo relationship) supports serialize:false', async function(assert) { + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretLab: { serialize: false }, + }, + }) + ); - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - homePlanet: { serialize: 'id', key: 'favorite_place' }, - }, - }) - ); - - let serializer = env.store.serializerFor('super-villain'); - let json = serializer.serialize(superVillain._createSnapshot()); - - assert.deepEqual(json, { - firstName: 'Ice', - lastName: 'Creature', - favorite_place: homePlanet.id, - secretLab: null, - }); -}); + // records with an id, persisted + let tom = store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); + + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(tom._createSnapshot()); + const expectedOutput = { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + }; + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We do not serialize relationships that specify serialize:false' + ); + }); + + test('serialize with embedded object (belongsTo relationship) serializes the id by default if no option specified', async function(assert) { + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin) + ); + + // records with an id, persisted + let tom = store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + secretLab: store.createRecord('secret-lab', { + minionCapacity: 5000, + vicinity: 'California, USA', + id: '101', + }), + homePlanet: store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); + + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(tom._createSnapshot()); + const expectedOutput = { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + secretLab: '101', + }; + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We serialized the belongsTo relationships to IDs' + ); + }); + + test('when related record is not present, serialize embedded record (with a belongsTo relationship) as null', async function(assert) { + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretLab: { embedded: 'always' }, + }, + }) + ); -test('serializing ids hasMany respects remapped attrs key', function(assert) { - let homePlanet = env.store.createRecord('home-planet', { name: 'Hoth' }); - let superVillain = env.store.createRecord('super-villain', { - firstName: 'Ice', - lastName: 'Creature', - homePlanet: homePlanet, - }); + let tom = store.createRecord('super-villain', { + firstName: 'Tom', + lastName: 'Dale', + id: '1', + homePlanet: store.createRecord('home-planet', { name: 'Villain League', id: '123' }), + }); - env.owner.register( - 'serializer:home-planet', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - villains: { serialize: 'ids', key: 'notable_persons' }, - }, - }) - ); - - env.owner.register( - 'serializer:super-villain', - DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - homePlanet: { serialize: false }, - secretLab: { serialize: false }, - }, - }) - ); - - let serializer = env.store.serializerFor('home-planet'); - let json = serializer.serialize(homePlanet._createSnapshot()); - - assert.deepEqual(json, { - name: 'Hoth', - notable_persons: [superVillain.id], + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(tom._createSnapshot()); + const expectedOutput = { + firstName: 'Tom', + lastName: 'Dale', + homePlanet: '123', + secretLab: null, + }; + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We serialized missing belongsTo relationships to null when always embedded' + ); + }); + + test('serializing belongsTo correctly removes embedded foreign key', async function(assert) { + let { owner } = this; + const SecretWeaponClass = Model.extend({ + name: attr('string'), + }); + const EvilMinionClass = Model.extend({ + secretWeapon: belongsTo('secret-weapon', { async: false }), + name: attr('string'), + }); + + owner.register( + 'serializer:evil-minion', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + secretWeapon: { embedded: 'always' }, + }, + }) + ); + owner.unregister('model:secret-weapon'); + owner.unregister('model:evil-minion'); + owner.register('model:secret-weapon', SecretWeaponClass); + owner.register('model:evil-minion', EvilMinionClass); + + let secretWeapon = store.createRecord('secret-weapon', { name: 'Secret Weapon' }); + let evilMinion = store.createRecord('evil-minion', { + name: 'Evil Minion', + secretWeapon, + }); + + const serializer = store.serializerFor('evil-minion'); + const serializedRestJson = serializer.serialize(evilMinion._createSnapshot()); + const expectedOutput = { + name: 'Evil Minion', + secretWeapon: { + name: 'Secret Weapon', + }, + }; + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'We correctly remove the FK from the embedded inverse when serializing' + ); + }); + + test('serializing embedded belongsTo respects remapped attrs key', async function(assert) { + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + homePlanet: { embedded: 'always', key: 'favorite_place' }, + }, + }) + ); + + let homePlanet = store.createRecord('home-planet', { name: 'Hoth' }); + let superVillain = store.createRecord('super-villain', { + firstName: 'Ice', + lastName: 'Creature', + homePlanet, + }); + + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(superVillain._createSnapshot()); + const expectedOutput = { + firstName: 'Ice', + lastName: 'Creature', + favorite_place: { + name: 'Hoth', + }, + secretLab: null, + }; + + assert.deepEqual( + serializedRestJson, + expectedOutput, + 'we respect the remapped attrs key when serializing' + ); + }); + + test('serializing id belongsTo respects remapped attrs key', async function(assert) { + this.owner.register( + 'serializer:super-villain', + RESTSerializer.extend(EmbeddedRecordsMixin, { + attrs: { + homePlanet: { serialize: 'id', key: 'favorite_place' }, + }, + }) + ); + + let homePlanet = store.createRecord('home-planet', { name: 'Hoth' }); + let superVillain = store.createRecord('super-villain', { + firstName: 'Ice', + lastName: 'Creature', + homePlanet, + }); + + const serializer = store.serializerFor('super-villain'); + const serializedRestJson = serializer.serialize(superVillain._createSnapshot()); + const expectedOutput = { + firstName: 'Ice', + lastName: 'Creature', + favorite_place: homePlanet.id, + secretLab: null, + }; + + assert.deepEqual(serializedRestJson, expectedOutput, 'we serialized with remapped keys'); + }); + }); }); }); From 1d4676fab3196ca60f48495554898e620bb22869 Mon Sep 17 00:00:00 2001 From: Pepe Cano Date: Fri, 9 Nov 2018 13:43:01 +0100 Subject: [PATCH 2415/2527] [DOC beta] Add doc for `async: false` --- .../system/relationships/belongs-to.js | 27 +++++++++++++++- .../-private/system/relationships/has-many.js | 32 ++++++++++++++++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 00825c9d7c5..9f672cff7df 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -11,7 +11,7 @@ import { DEBUG } from '@glimmer/env'; `DS.belongsTo` takes an optional hash as a second parameter, currently supported options are: - - `async`: A boolean value used to explicitly declare this to be an async relationship. + - `async`: A boolean value used to explicitly declare this to be an async relationship. The default is true. - `inverse`: A string used to identify the inverse property on a related model in a One-To-Many relationship. See [Explicit Inverses](#explicit-inverses) @@ -68,6 +68,31 @@ import { DEBUG } from '@glimmer/env'; will lookup for a Post type. + #### Sync relationships + + Ember Data resolves sync relationships with the related resources + available in its local store, hence it is expected these resources + to be loaded before or along-side the primary resource. + + ```app/models/comment.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + post: DS.belongsTo('post', { + async: false + }) + }); + ``` + + In contrast to async relationship, accessing a sync relationship + will never trigger a request to fetch the resource, + and it will always return the existing local resource. + + ``` + let post = comment.get('post'); + + ``` + @namespace @method belongsTo @for DS diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index fc79e0ab45b..7b2f103a4ba 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -13,7 +13,7 @@ import { DEBUG } from '@glimmer/env'; `DS.hasMany` takes an optional hash as a second parameter, currently supported options are: - - `async`: A boolean value used to explicitly declare this to be an async relationship. + - `async`: A boolean value used to explicitly declare this to be an async relationship. The default is true. - `inverse`: A string used to identify the inverse property on a related model. #### One-To-Many @@ -105,6 +105,36 @@ import { DEBUG } from '@glimmer/env'; You can also specify an inverse on a `belongsTo`, which works how you'd expect. + #### Sync relationships + + Ember Data resolves sync relationships with the related resources + available in its local store, hence it is expected these resources + to be loaded before or along-side the primary resource. + + ```app/models/post.js + import DS from 'ember-data'; + + export default DS.Model.extend({ + comments: DS.hasMany('comment', { + async: false + }) + }); + ``` + + In contrast to async relationship, accessing a sync relationship + will never trigger a request to fetch the resources, + and it will always return an array object with the existing local resources. + + ``` + post.get('comments').forEach((comment) => { + + }); + + ``` + + If you are using `links` with sync relationships, you have to use + `ref.reload` to fetch the resources. + @namespace @method hasMany @for DS From 1b2822493613fbb1fbd154efb12904b931c86116 Mon Sep 17 00:00:00 2001 From: Pepe Cano Date: Sat, 10 Nov 2018 01:07:53 +0100 Subject: [PATCH 2416/2527] Fix doc to clarify the sync relationship return --- addon/-private/system/relationships/belongs-to.js | 4 ++-- addon/-private/system/relationships/has-many.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index 9f672cff7df..dc97d5219fe 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -85,8 +85,8 @@ import { DEBUG } from '@glimmer/env'; ``` In contrast to async relationship, accessing a sync relationship - will never trigger a request to fetch the resource, - and it will always return the existing local resource. + will always return the record (Model instance) for the existing + local resource, or null. ``` let post = comment.get('post'); diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index 7b2f103a4ba..ba200d71f67 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -122,8 +122,8 @@ import { DEBUG } from '@glimmer/env'; ``` In contrast to async relationship, accessing a sync relationship - will never trigger a request to fetch the resources, - and it will always return an array object with the existing local resources. + will always return a [DS.ManyArray](/api/data/classes/DS.ManyArray.html) instance + containing the existing local resources, or null. ``` post.get('comments').forEach((comment) => { From bbd72fbde0494110653ea6149f121ce814b884c7 Mon Sep 17 00:00:00 2001 From: Pepe Cano Date: Sat, 10 Nov 2018 01:29:46 +0100 Subject: [PATCH 2417/2527] Fix to specify the error if the expected resource has not been loaded --- addon/-private/system/relationships/belongs-to.js | 3 ++- addon/-private/system/relationships/has-many.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index dc97d5219fe..e90bee1ec54 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -86,7 +86,8 @@ import { DEBUG } from '@glimmer/env'; In contrast to async relationship, accessing a sync relationship will always return the record (Model instance) for the existing - local resource, or null. + local resource, or null. But it will error on access when + a related resource is known to exist but has not been loaded. ``` let post = comment.get('post'); diff --git a/addon/-private/system/relationships/has-many.js b/addon/-private/system/relationships/has-many.js index ba200d71f67..a142d54f7d7 100644 --- a/addon/-private/system/relationships/has-many.js +++ b/addon/-private/system/relationships/has-many.js @@ -123,7 +123,8 @@ import { DEBUG } from '@glimmer/env'; In contrast to async relationship, accessing a sync relationship will always return a [DS.ManyArray](/api/data/classes/DS.ManyArray.html) instance - containing the existing local resources, or null. + containing the existing local resources. But it will error on access + when any of the known related resources have not been loaded. ``` post.get('comments').forEach((comment) => { From 8b7de9e69f2418ef9747aa4ca51f59efff9d669c Mon Sep 17 00:00:00 2001 From: Pepe Cano Date: Sat, 10 Nov 2018 01:32:13 +0100 Subject: [PATCH 2418/2527] Rephrase doc --- addon/-private/system/relationships/belongs-to.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/relationships/belongs-to.js b/addon/-private/system/relationships/belongs-to.js index e90bee1ec54..21de15f0062 100644 --- a/addon/-private/system/relationships/belongs-to.js +++ b/addon/-private/system/relationships/belongs-to.js @@ -87,7 +87,7 @@ import { DEBUG } from '@glimmer/env'; In contrast to async relationship, accessing a sync relationship will always return the record (Model instance) for the existing local resource, or null. But it will error on access when - a related resource is known to exist but has not been loaded. + a related resource is known to exist and it has not been loaded. ``` let post = comment.get('post'); From 5012e4d863f97a27812ba3e11ebd850788788521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86gir=20Giraldo=20=C3=9Eorsteinsson?= Date: Mon, 5 Nov 2018 22:27:56 +0000 Subject: [PATCH 2419/2527] [CHORE tests] modernize integration/adapter/find-all-test --- tests/integration/adapter/find-all-test.js | 445 +++++++++------------ 1 file changed, 187 insertions(+), 258 deletions(-) diff --git a/tests/integration/adapter/find-all-test.js b/tests/integration/adapter/find-all-test.js index afc75519e1b..f3b63421267 100644 --- a/tests/integration/adapter/find-all-test.js +++ b/tests/integration/adapter/find-all-test.js @@ -1,58 +1,96 @@ -import { reject, resolve, defer } from 'rsvp'; -import { get } from '@ember/object'; +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { reject, resolve, defer, Promise } from 'rsvp'; import { run } from '@ember/runloop'; -import { createStore } from 'dummy/tests/helpers/store'; -import setupStore from 'dummy/tests/helpers/store'; +import { get } from '@ember/object'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; -import { module, test } from 'qunit'; -import DS from 'ember-data'; +import Model from 'ember-data/model'; +import { attr } from '@ember-decorators/data'; +import { settled } from '@ember/test-helpers'; -const { attr } = DS; +class Person extends Model { + @attr + updatedAt; -let Person, store, allRecords, env; + @attr + name; -module('integration/adapter/find-all - Finding All Records of a Type', { - beforeEach() { - Person = DS.Model.extend({ - updatedAt: attr('string'), - name: attr('string'), - firstName: attr('string'), - lastName: attr('string'), - }); - Person.reopenClass({ - toString() { - return 'Person'; - }, - }); + @attr + firstName; - allRecords = null; + @attr + lastName; - env = setupStore({ - person: Person, - }); - store = env.store; - }, + toString() { + return 'Person'; + } +} - afterEach() { - run(() => { - if (allRecords) { - allRecords.destroy(); - } - store.destroy(); - }); - }, -}); +module('integration/adapter/find-all - Finding All Records of a Type', function(hooks) { + setupTest(hooks); + let store; + + hooks.beforeEach(function() { + let { owner } = this; + + owner.register('model:person', Person); + store = owner.lookup('service:store'); + }); -test("When all records for a type are requested, the store should call the adapter's `findAll` method.", assert => { - assert.expect(5); + test("When all records for a type are requested, the store should call the adapter's `findAll` method.", async function(assert) { + assert.expect(5); + let adapter = store.adapterFor('person'); + + adapter.findAll = () => { + // this will get called twice + assert.ok(true, "the adapter's findAll method should be invoked"); + + return resolve({ + data: [ + { + id: 1, + type: 'person', + attributes: { + name: 'Braaaahm Dale', + }, + }, + ], + }); + }; + + let allRecords = await store.findAll('person'); + assert.equal( + get(allRecords, 'length'), + 1, + "the record array's length is 1 after a record is loaded into it" + ); + assert.equal( + allRecords.objectAt(0).get('name'), + 'Braaaahm Dale', + 'the first item in the record array is Braaaahm Dale' + ); + + let all = await store.findAll('person'); + // Only one record array per type should ever be created (identity map) + assert.strictEqual( + allRecords, + all, + 'the same record array is returned every time all records of a type are requested' + ); + }); - env.owner.register( - 'adapter:person', - DS.Adapter.extend({ - findAll() { - // this will get called twice - assert.ok(true, "the adapter's findAll method should be invoked"); + test('When all records for a type are requested, a rejection should reject the promise', async function(assert) { + assert.expect(5); + let adapter = store.adapterFor('person'); + let count = 0; + adapter.findAll = () => { + // this will get called twice + assert.ok(true, "the adapter's findAll method should be invoked"); + + if (count++ === 0) { + return reject(); + } else { return resolve({ data: [ { @@ -64,96 +102,28 @@ test("When all records for a type are requested, the store should call the adapt }, ], }); - }, - }) - ); - - return run(() => { - return store.findAll('person').then(all => { - let allRecords = all; - assert.equal( - get(all, 'length'), - 1, - "the record array's length is 1 after a record is loaded into it" - ); - assert.equal( - all.objectAt(0).get('name'), - 'Braaaahm Dale', - 'the first item in the record array is Braaaahm Dale' - ); - - return store.findAll('person').then(all => { - // Only one record array per type should ever be created (identity map) - assert.strictEqual( - allRecords, - all, - 'the same record array is returned every time all records of a type are requested' - ); - }); - }); - }); -}); + } + }; -test('When all records for a type are requested, a rejection should reject the promise', assert => { - assert.expect(5); - - let count = 0; - env.owner.register( - 'adapter:person', - DS.Adapter.extend({ - findAll() { - // this will get called twice - assert.ok(true, "the adapter's findAll method should be invoked"); - - if (count++ === 0) { - return reject(); - } else { - return resolve({ - data: [ - { - id: 1, - type: 'person', - attributes: { - name: 'Braaaahm Dale', - }, - }, - ], - }); - } - }, - }) - ); - - return run(() => { - return store - .findAll('person') - .catch(() => { - assert.ok(true, 'The rejection should get here'); - return store.findAll('person'); - }) - .then(all => { - assert.equal( - get(all, 'length'), - 1, - "the record array's length is 1 after a record is loaded into it" - ); - assert.equal( - all.objectAt(0).get('name'), - 'Braaaahm Dale', - 'the first item in the record array is Braaaahm Dale' - ); - }); + let all = await store.findAll('person').catch(() => { + assert.ok(true, 'The rejection should get here'); + return store.findAll('person'); + }); + assert.equal( + get(all, 'length'), + 1, + "the record array's length is 1 after a record is loaded into it" + ); + assert.equal( + all.objectAt(0).get('name'), + 'Braaaahm Dale', + 'the first item in the record array is Braaaahm Dale' + ); }); -}); -test('When all records for a type are requested, records that are already loaded should be returned immediately.', assert => { - assert.expect(3); - store = createStore({ - adapter: DS.Adapter.extend(), - person: Person, - }); + test('When all records for a type are requested, records that are already loaded should be returned immediately.', async assert => { + assert.expect(3); - run(() => { // Load a record from the server store.push({ data: { @@ -164,78 +134,63 @@ test('When all records for a type are requested, records that are already loaded }, }, }); + // Create a new, unsaved record in the store store.createRecord('person', { name: 'Alex MacCaw' }); - }); - - allRecords = store.peekAll('person'); - - assert.equal(get(allRecords, 'length'), 2, "the record array's length is 2"); - assert.equal( - allRecords.objectAt(0).get('name'), - 'Jeremy Ashkenas', - 'the first item in the record array is Jeremy Ashkenas' - ); - assert.equal( - allRecords.objectAt(1).get('name'), - 'Alex MacCaw', - 'the second item in the record array is Alex MacCaw' - ); -}); - -test('When all records for a type are requested, records that are created on the client should be added to the record array.', assert => { - assert.expect(3); - store = createStore({ - adapter: DS.Adapter.extend(), - person: Person, + let allRecords = store.peekAll('person'); + + assert.equal(get(allRecords, 'length'), 2, "the record array's length is 2"); + assert.equal( + allRecords.objectAt(0).get('name'), + 'Jeremy Ashkenas', + 'the first item in the record array is Jeremy Ashkenas' + ); + assert.equal( + allRecords.objectAt(1).get('name'), + 'Alex MacCaw', + 'the second item in the record array is Alex MacCaw' + ); }); - allRecords = store.peekAll('person'); + test('When all records for a type are requested, records that are created on the client should be added to the record array.', assert => { + assert.expect(3); - assert.equal( - get(allRecords, 'length'), - 0, - "precond - the record array's length is zero before any records are loaded" - ); + let allRecords = store.peekAll('person'); - store.createRecord('person', { name: 'Carsten Nielsen' }); + assert.equal( + get(allRecords, 'length'), + 0, + "precond - the record array's length is zero before any records are loaded" + ); - assert.equal(get(allRecords, 'length'), 1, "the record array's length is 1"); - assert.equal( - allRecords.objectAt(0).get('name'), - 'Carsten Nielsen', - 'the first item in the record array is Carsten Nielsen' - ); -}); + store.createRecord('person', { name: 'Carsten Nielsen' }); -testInDebug('When all records are requested, assert the payload is not blank', assert => { - env.owner.register( - 'adapter:person', - DS.Adapter.extend({ - findAll: () => resolve({}), - }) - ); - - assert.expectAssertion(() => { - run(() => store.findAll('person')); - }, /You made a 'findAll' request for 'person' records, but the adapter's response did not have any data/); -}); + assert.equal(get(allRecords, 'length'), 1, "the record array's length is 1"); + assert.equal( + allRecords.objectAt(0).get('name'), + 'Carsten Nielsen', + 'the first item in the record array is Carsten Nielsen' + ); + }); -test('isUpdating is true while records are fetched', function(assert) { - let findAllDeferred = defer(); - env.owner.register( - 'adapter:person', - DS.Adapter.extend({ - findAll() { - return findAllDeferred.promise; - }, + testInDebug('When all records are requested, assert the payload is not blank', async function( + assert + ) { + let adapter = store.adapterFor('person'); + adapter.findAll = () => resolve({}); + + assert.expectAssertion(() => { + run(() => store.findAll('person')); + }, /You made a 'findAll' request for 'person' records, but the adapter's response did not have any data/); + }); - shouldReloadAll: () => true, - }) - ); + test('isUpdating is true while records are fetched', async function(assert) { + let findAllDeferred = defer(); + let adapter = store.adapterFor('person'); + adapter.findAll = () => findAllDeferred.promise; + adapter.shouldReloadAll = () => true; - run(() => { store.push({ data: [ { @@ -244,44 +199,34 @@ test('isUpdating is true while records are fetched', function(assert) { }, ], }); - }); - let persons = store.peekAll('person'); - assert.equal(persons.get('length'), 1); + let persons = store.peekAll('person'); + assert.equal(persons.get('length'), 1); + + let promise = new Promise(async resolve => { + let persons = await store.findAll('person'); - let wait = run(() => { - return store.findAll('person').then(persons => { assert.equal(persons.get('isUpdating'), false); assert.equal(persons.get('length'), 2); + resolve(); }); - }); - assert.equal(persons.get('isUpdating'), true); + assert.equal(persons.get('isUpdating'), true); - findAllDeferred.resolve({ data: [{ id: 2, type: 'person' }] }); + findAllDeferred.resolve({ data: [{ id: 2, type: 'person' }] }); - return wait; -}); + await promise; + }); -test('isUpdating is true while records are fetched in the background', function(assert) { - let findAllDeferred = defer(); - env.owner.register( - 'adapter:person', - DS.Adapter.extend({ - findAll() { - return findAllDeferred.promise; - }, + test('isUpdating is true while records are fetched in the background', async function(assert) { + let findAllDeferred = defer(); + let adapter = store.adapterFor('person'); + adapter.findAll = () => { + return findAllDeferred.promise; + }; + adapter.shouldReloadAll = () => false; + adapter.shouldBackgroundReloadAll = () => true; - shouldReloadAll() { - return false; - }, - shouldBackgroundReloadAll() { - return true; - }, - }) - ); - - run(() => { store.push({ data: [ { @@ -290,46 +235,35 @@ test('isUpdating is true while records are fetched in the background', function( }, ], }); - }); - let persons = store.peekAll('person'); - assert.equal(persons.get('length'), 1); + let persons = store.peekAll('person'); + assert.equal(persons.get('length'), 1); - return run(() => { - return store.findAll('person').then(persons => { - assert.equal(persons.get('isUpdating'), true); - assert.equal(persons.get('length'), 1, 'persons are updated in the background'); - }); - }).then(() => { + persons = await store.findAll('person'); assert.equal(persons.get('isUpdating'), true); + assert.equal(persons.get('length'), 1, 'persons are updated in the background'); - run(() => { - findAllDeferred.resolve({ data: [{ id: 2, type: 'person' }] }); - }); + assert.equal(persons.get('isUpdating'), true); - return run(() => { - return findAllDeferred.promise.then(() => { - assert.equal(persons.get('isUpdating'), false); - assert.equal(persons.get('length'), 2); - }); - }); + findAllDeferred.resolve({ data: [{ id: 2, type: 'person' }] }); + + await settled(); + + await findAllDeferred.promise; + + assert.equal(persons.get('isUpdating'), false); + assert.equal(persons.get('length'), 2); }); -}); -test('isUpdating is false if records are not fetched in the background', function(assert) { - let findAllDeferred = defer(); - env.owner.register( - 'adapter:person', - DS.Adapter.extend({ - findAll() { - return findAllDeferred.promise; - }, - shouldReloadAll: () => false, - shouldBackgroundReloadAll: () => false, - }) - ); + test('isUpdating is false if records are not fetched in the background', async function(assert) { + let findAllDeferred = defer(); + let adapter = store.adapterFor('person'); + adapter.findAll = () => { + return findAllDeferred.promise; + }; + adapter.shouldReloadAll = () => false; + adapter.shouldBackgroundReloadAll = () => false; - run(() => { store.push({ data: [ { @@ -338,16 +272,11 @@ test('isUpdating is false if records are not fetched in the background', functio }, ], }); - }); - let persons = store.peekAll('person'); - assert.equal(persons.get('length'), 1); + let persons = store.peekAll('person'); + assert.equal(persons.get('length'), 1); - return run(() => { - return store.findAll('person').then(persons => { - assert.equal(persons.get('isUpdating'), false); - }); - }).then(() => { + persons = await store.findAll('person'); assert.equal(persons.get('isUpdating'), false); }); }); From 30c828bde8a3726b0925ff78576f2daf65a531eb Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 30 Oct 2018 11:21:44 -0700 Subject: [PATCH 2420/2527] [CHORE ts] convert InternalModelMap to typescript --- ...nal-model-map.js => internal-model-map.ts} | 53 ++++++++++--------- types/dummy/index.d.ts | 3 ++ 2 files changed, 31 insertions(+), 25 deletions(-) rename addon/-private/system/{internal-model-map.js => internal-model-map.ts} (74%) diff --git a/addon/-private/system/internal-model-map.js b/addon/-private/system/internal-model-map.ts similarity index 74% rename from addon/-private/system/internal-model-map.js rename to addon/-private/system/internal-model-map.ts index 91272048fb3..4bbef79fcb9 100644 --- a/addon/-private/system/internal-model-map.js +++ b/addon/-private/system/internal-model-map.ts @@ -1,6 +1,13 @@ import { assert } from '@ember/debug'; import InternalModel from './model/internal-model'; +interface IDDict { + [id: string]: InternalModel +} +interface MetaDict { + [key: string]: any +} + /** `InternalModelMap` is a custom storage map for internalModels of a given modelName used by `IdentityMap`. @@ -12,7 +19,13 @@ import InternalModel from './model/internal-model'; @private */ export default class InternalModelMap { - constructor(modelName) { + private _idToModel: IDDict; + private _models: InternalModel[]; + private _metadata: MetaDict|null; + + modelName: string; + + constructor(modelName: string) { this.modelName = modelName; this._idToModel = Object.create(null); this._models = []; @@ -24,19 +37,19 @@ export default class InternalModelMap { * @param id {String} * @return {InternalModel} */ - get(id) { + get(id: string): InternalModel|undefined { return this._idToModel[id]; } - has(id) { + has(id: string): boolean { return !!this._idToModel[id]; } - get length() { + get length(): number { return this._models.length; } - set(id, internalModel) { + set(id: string, internalModel: InternalModel): void { assert(`You cannot index an internalModel by an empty id'`, id); assert( `You cannot set an index for an internalModel to something other than an internalModel`, @@ -54,7 +67,7 @@ export default class InternalModelMap { this._idToModel[id] = internalModel; } - add(internalModel, id) { + add(internalModel: InternalModel, id?: string): void { assert( `You cannot re-add an already present InternalModel to the InternalModelMap.`, !this.contains(internalModel) @@ -72,7 +85,7 @@ export default class InternalModelMap { this._models.push(internalModel); } - remove(internalModel, id) { + remove(internalModel: InternalModel, id: string): void { delete this._idToModel[id]; let loc = this._models.indexOf(internalModel); @@ -82,7 +95,7 @@ export default class InternalModelMap { } } - contains(internalModel) { + contains(internalModel: InternalModel): boolean { return this._models.indexOf(internalModel) !== -1; } @@ -91,7 +104,7 @@ export default class InternalModelMap { @property models @type Array */ - get models() { + get models(): InternalModel[] { return this._models; } @@ -100,32 +113,22 @@ export default class InternalModelMap { * @property metadata * @type Object */ - get metadata() { + get metadata(): MetaDict { return this._metadata || (this._metadata = Object.create(null)); } - /** - deprecated (and unsupported) way of accessing modelClass - - @property type - @deprecated - */ - get type() { - throw new Error('InternalModelMap.type is no longer available'); - } - /** Destroy all models in the internalModelTest and wipe metadata. @method clear */ - clear() { - let models = this._models; + clear(): void { + let internalModels = this._models; this._models = []; - for (let i = 0; i < models.length; i++) { - let model = models[i]; - model.unloadRecord(); + for (let i = 0; i < internalModels.length; i++) { + let internalModel = internalModels[i]; + internalModel.unloadRecord(); } this._metadata = null; diff --git a/types/dummy/index.d.ts b/types/dummy/index.d.ts index 1ca50c1f99d..0f6f7c3ace1 100644 --- a/types/dummy/index.d.ts +++ b/types/dummy/index.d.ts @@ -3,3 +3,6 @@ * ember-data. They will not be shipped to consumers. Ember-data still relies * on some private Ember APIs -- those should be defined here as we encounter them. */ +declare module '@ember/debug' { + export function assert(msg: string, test: any): boolean; +} From b096668178ed677790f55f1fe7d5a9fa554ddc94 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 30 Oct 2018 11:24:13 -0700 Subject: [PATCH 2421/2527] [CHORE ts] convert IdentityMap to typescript --- .../{identity-map.js => identity-map.ts} | 10 +- addon/-private/system/internal-model-map.ts | 13 +- package.json | 1 + types/dummy/index.d.ts | 20 +- yarn.lock | 1437 +---------------- 5 files changed, 36 insertions(+), 1445 deletions(-) rename addon/-private/system/{identity-map.js => identity-map.ts} (87%) diff --git a/addon/-private/system/identity-map.js b/addon/-private/system/identity-map.ts similarity index 87% rename from addon/-private/system/identity-map.js rename to addon/-private/system/identity-map.ts index b649e31aedf..bbfe8124020 100644 --- a/addon/-private/system/identity-map.js +++ b/addon/-private/system/identity-map.ts @@ -1,5 +1,9 @@ import InternalModelMap from './internal-model-map'; +interface IMMDict { + [modelName: string]: InternalModelMap +} + /** `IdentityMap` is a custom storage map for records by modelName used by `DS.Store`. @@ -8,6 +12,8 @@ import InternalModelMap from './internal-model-map'; @private */ export default class IdentityMap { + private _map: IMMDict; + constructor() { this._map = Object.create(null); } @@ -21,7 +27,7 @@ export default class IdentityMap { @param modelName a previously normalized modelName @return {InternalModelMap} the InternalModelMap for the given modelName */ - retrieve(modelName) { + retrieve(modelName: string): InternalModelMap { let map = this._map[modelName]; if (map === undefined) { @@ -37,7 +43,7 @@ export default class IdentityMap { @method clear */ - clear() { + clear(): void { let map = this._map; let keys = Object.keys(map); diff --git a/addon/-private/system/internal-model-map.ts b/addon/-private/system/internal-model-map.ts index 4bbef79fcb9..a1b350ea985 100644 --- a/addon/-private/system/internal-model-map.ts +++ b/addon/-private/system/internal-model-map.ts @@ -2,10 +2,10 @@ import { assert } from '@ember/debug'; import InternalModel from './model/internal-model'; interface IDDict { - [id: string]: InternalModel + [id: string]: InternalModel; } interface MetaDict { - [key: string]: any + [key: string]: any; } /** @@ -21,7 +21,7 @@ interface MetaDict { export default class InternalModelMap { private _idToModel: IDDict; private _models: InternalModel[]; - private _metadata: MetaDict|null; + private _metadata: MetaDict | null; modelName: string; @@ -37,7 +37,7 @@ export default class InternalModelMap { * @param id {String} * @return {InternalModel} */ - get(id: string): InternalModel|undefined { + get(id: string): InternalModel | undefined { return this._idToModel[id]; } @@ -50,7 +50,10 @@ export default class InternalModelMap { } set(id: string, internalModel: InternalModel): void { - assert(`You cannot index an internalModel by an empty id'`, id); + assert( + `You cannot index an internalModel by an empty id'`, + typeof id === 'string' && id.length > 0 + ); assert( `You cannot set an index for an internalModel to something other than an internalModel`, internalModel instanceof InternalModel diff --git a/package.json b/package.json index 9f4f2f9423f..4948a170cf3 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "@types/ember-test-helpers": "~1.0.4", "@types/ember-testing-helpers": "~0.0.3", "@types/ember__test-helpers": "~0.7.6", + "@types/ember__debug": "^3.0.3", "@types/qunit": "^2.5.3", "@types/rsvp": "^4.0.2", "babel-eslint": "^10.0.1", diff --git a/types/dummy/index.d.ts b/types/dummy/index.d.ts index 0f6f7c3ace1..5ff2c23a180 100644 --- a/types/dummy/index.d.ts +++ b/types/dummy/index.d.ts @@ -3,6 +3,22 @@ * ember-data. They will not be shipped to consumers. Ember-data still relies * on some private Ember APIs -- those should be defined here as we encounter them. */ -declare module '@ember/debug' { - export function assert(msg: string, test: any): boolean; + +// Heimdall is TS now, we should be able to make this +// not suck +type TCounterToken = number; +type TTimerToken = number; + +interface ICounterDict { + [counterName: string]: TCounterToken; } + +interface IHeimdall { + registerMonitor(...counterNames: string[]): ICounterDict; + increment(counter: TCounterToken): void; + start(timerLabel: string): TTimerToken; + stop(token: TTimerToken): void; +} + +// hrm :/ +declare const heimdall: IHeimdall; diff --git a/yarn.lock b/yarn.lock index aee2295e20d..5cf35fee08c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,14 +5,12 @@ "@babel/code-frame@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" - integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== dependencies: "@babel/highlight" "^7.0.0" "@babel/core@^7.0.0": version "7.1.2" resolved "https://registry.npmjs.org/@babel/core/-/core-7.1.2.tgz#f8d2a9ceb6832887329a7b60f9d035791400ba4e" - integrity sha512-IFeSSnjXdhDaoysIlev//UzHZbdEmm7D0EIH2qtse9xK7mXEZQpYjs2P00XlP1qYsYvid79p+Zgg6tz1mp6iVw== dependencies: "@babel/code-frame" "^7.0.0" "@babel/generator" "^7.1.2" @@ -32,7 +30,6 @@ "@babel/generator@^7.1.2", "@babel/generator@^7.1.3": version "7.1.3" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.1.3.tgz#2103ec9c42d9bdad9190a6ad5ff2d456fd7b8673" - integrity sha512-ZoCZGcfIJFJuZBqxcY9OjC1KW2lWK64qrX1o4UYL3yshVhwKFYgzpWZ0vvtGMNJdTlvkw0W+HR1VnYN8q3QPFQ== dependencies: "@babel/types" "^7.1.3" jsesc "^2.5.1" @@ -43,14 +40,12 @@ "@babel/helper-annotate-as-pure@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" - integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q== dependencies: "@babel/types" "^7.0.0" "@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" - integrity sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w== dependencies: "@babel/helper-explode-assignable-expression" "^7.1.0" "@babel/types" "^7.0.0" @@ -58,7 +53,6 @@ "@babel/helper-call-delegate@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz#6a957f105f37755e8645343d3038a22e1449cc4a" - integrity sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ== dependencies: "@babel/helper-hoist-variables" "^7.0.0" "@babel/traverse" "^7.1.0" @@ -67,7 +61,6 @@ "@babel/helper-define-map@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz#3b74caec329b3c80c116290887c0dd9ae468c20c" - integrity sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg== dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/types" "^7.0.0" @@ -76,7 +69,6 @@ "@babel/helper-explode-assignable-expression@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" - integrity sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA== dependencies: "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" @@ -84,7 +76,6 @@ "@babel/helper-function-name@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" - integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== dependencies: "@babel/helper-get-function-arity" "^7.0.0" "@babel/template" "^7.1.0" @@ -93,35 +84,30 @@ "@babel/helper-get-function-arity@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" - integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== dependencies: "@babel/types" "^7.0.0" "@babel/helper-hoist-variables@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz#46adc4c5e758645ae7a45deb92bab0918c23bb88" - integrity sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w== dependencies: "@babel/types" "^7.0.0" "@babel/helper-member-expression-to-functions@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f" - integrity sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg== dependencies: "@babel/types" "^7.0.0" "@babel/helper-module-imports@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" - integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A== dependencies: "@babel/types" "^7.0.0" "@babel/helper-module-transforms@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.1.0.tgz#470d4f9676d9fad50b324cdcce5fbabbc3da5787" - integrity sha512-0JZRd2yhawo79Rcm4w0LwSMILFmFXjugG3yqf+P/UsKsRS1mJCmMwwlHDlMg7Avr9LrvSpp4ZSULO9r8jpCzcw== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-simple-access" "^7.1.0" @@ -133,26 +119,22 @@ "@babel/helper-optimise-call-expression@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" - integrity sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g== dependencies: "@babel/types" "^7.0.0" "@babel/helper-plugin-utils@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" - integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== "@babel/helper-regex@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.0.0.tgz#2c1718923b57f9bbe64705ffe5640ac64d9bdb27" - integrity sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg== dependencies: lodash "^4.17.10" "@babel/helper-remap-async-to-generator@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f" - integrity sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg== dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-wrap-function" "^7.1.0" @@ -163,7 +145,6 @@ "@babel/helper-replace-supers@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.1.0.tgz#5fc31de522ec0ef0899dc9b3e7cf6a5dd655f362" - integrity sha512-BvcDWYZRWVuDeXTYZWxekQNO5D4kO55aArwZOTFXw6rlLQA8ZaDicJR1sO47h+HrnCiDFiww0fSPV0d713KBGQ== dependencies: "@babel/helper-member-expression-to-functions" "^7.0.0" "@babel/helper-optimise-call-expression" "^7.0.0" @@ -173,7 +154,6 @@ "@babel/helper-simple-access@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" - integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w== dependencies: "@babel/template" "^7.1.0" "@babel/types" "^7.0.0" @@ -181,14 +161,12 @@ "@babel/helper-split-export-declaration@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813" - integrity sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag== dependencies: "@babel/types" "^7.0.0" "@babel/helper-wrap-function@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.1.0.tgz#8cf54e9190706067f016af8f75cb3df829cc8c66" - integrity sha512-R6HU3dete+rwsdAfrOzTlE9Mcpk4RjU3aX3gi9grtmugQY0u79X7eogUvfXA5sI81Mfq1cn6AgxihfN33STjJA== dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/template" "^7.1.0" @@ -198,7 +176,6 @@ "@babel/helpers@^7.1.2": version "7.1.2" resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.1.2.tgz#ab752e8c35ef7d39987df4e8586c63b8846234b5" - integrity sha512-Myc3pUE8eswD73aWcartxB16K6CGmHDv9KxOmD2CeOs/FaEAQodr3VYGmlvOmog60vNQ2w8QbatuahepZwrHiA== dependencies: "@babel/template" "^7.1.2" "@babel/traverse" "^7.1.0" @@ -207,7 +184,6 @@ "@babel/highlight@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" - integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== dependencies: chalk "^2.0.0" esutils "^2.0.2" @@ -216,12 +192,10 @@ "@babel/parser@^7.0.0", "@babel/parser@^7.1.2", "@babel/parser@^7.1.3": version "7.1.3" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.1.3.tgz#2c92469bac2b7fbff810b67fca07bd138b48af77" - integrity sha512-gqmspPZOMW3MIRb9HlrnbZHXI1/KHTOroBwN1NcLL6pWxzqzEKGvRTq0W/PxS45OtQGbaFikSQpkS5zbnsQm2w== "@babel/plugin-proposal-async-generator-functions@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.1.0.tgz#41c1a702e10081456e23a7b74d891922dd1bb6ce" - integrity sha512-Fq803F3Jcxo20MXUSDdmZZXrPe6BWyGcWBPPNB/M7WaUYESKDeKMOGIxEzQOjGSmW/NWb6UaPZrtTB2ekhB/ew== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-remap-async-to-generator" "^7.1.0" @@ -230,7 +204,6 @@ "@babel/plugin-proposal-class-properties@^7.0.0", "@babel/plugin-proposal-class-properties@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.1.0.tgz#9af01856b1241db60ec8838d84691aa0bd1e8df4" - integrity sha512-/PCJWN+CKt5v1xcGn4vnuu13QDoV+P7NcICP44BoonAJoPSGwVkgrXihFIQGiEjjPlUDBIw1cM7wYFLARS2/hw== dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/helper-member-expression-to-functions" "^7.0.0" @@ -242,7 +215,6 @@ "@babel/plugin-proposal-decorators@^7.0.0": version "7.1.2" resolved "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.1.2.tgz#79829bd75fced6581ec6c7ab1930e8d738e892e7" - integrity sha512-YooynBO6PmBgHvAd0fl5e5Tq/a0pEC6RqF62ouafme8FzdIVH41Mz/u1dn8fFVm4jzEJ+g/MsOxouwybJPuP8Q== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-replace-supers" "^7.1.0" @@ -252,7 +224,6 @@ "@babel/plugin-proposal-json-strings@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.0.0.tgz#3b4d7b5cf51e1f2e70f52351d28d44fc2970d01e" - integrity sha512-kfVdUkIAGJIVmHmtS/40i/fg/AGnw/rsZBCaapY5yjeO5RA9m165Xbw9KMOu2nqXP5dTFjEjHdfNdoVcHv133Q== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-json-strings" "^7.0.0" @@ -260,7 +231,6 @@ "@babel/plugin-proposal-object-rest-spread@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0.tgz#9a17b547f64d0676b6c9cecd4edf74a82ab85e7e" - integrity sha512-14fhfoPcNu7itSen7Py1iGN0gEm87hX/B+8nZPqkdmANyyYWYMY2pjA3r8WXbWVKMzfnSNS0xY8GVS0IjXi/iw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread" "^7.0.0" @@ -268,7 +238,6 @@ "@babel/plugin-proposal-optional-catch-binding@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.0.0.tgz#b610d928fe551ff7117d42c8bb410eec312a6425" - integrity sha512-JPqAvLG1s13B/AuoBjdBYvn38RqW6n1TzrQO839/sIpqLpbnXKacsAgpZHzLD83Sm8SDXMkkrAvEnJ25+0yIpw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-optional-catch-binding" "^7.0.0" @@ -276,7 +245,6 @@ "@babel/plugin-proposal-unicode-property-regex@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0.tgz#498b39cd72536cd7c4b26177d030226eba08cd33" - integrity sha512-tM3icA6GhC3ch2SkmSxv7J/hCWKISzwycub6eGsDrFDgukD4dZ/I+x81XgW0YslS6mzNuQ1Cbzh5osjIMgepPQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" @@ -285,63 +253,54 @@ "@babel/plugin-syntax-async-generators@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.0.0.tgz#bf0891dcdbf59558359d0c626fdc9490e20bc13c" - integrity sha512-im7ged00ddGKAjcZgewXmp1vxSZQQywuQXe2B1A7kajjZmDeY/ekMPmWr9zJgveSaQH0k7BcGrojQhcK06l0zA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-class-properties@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.0.0.tgz#e051af5d300cbfbcec4a7476e37a803489881634" - integrity sha512-cR12g0Qzn4sgkjrbrzWy2GE7m9vMl/sFkqZ3gIpAQdrvPDnLM8180i+ANDFIXfjHo9aqp0ccJlQ0QNZcFUbf9w== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-decorators@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.1.0.tgz#2fa7c1a7905a299c9853ebcef340306675f9cbdc" - integrity sha512-uQvRSbgQ0nQg3jsmIixXXDCgSpkBolJ9X7NYThMKCcjvE8dN2uWJUzTUNNAeuKOjARTd+wUQV0ztXpgunZYKzQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-json-strings@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.0.0.tgz#0d259a68090e15b383ce3710e01d5b23f3770cbd" - integrity sha512-UlSfNydC+XLj4bw7ijpldc1uZ/HB84vw+U6BTuqMdIEmz/LDe63w/GHtpQMdXWdqQZFeAI9PjnHe/vDhwirhKA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0.tgz#37d8fbcaf216bd658ea1aebbeb8b75e88ebc549b" - integrity sha512-5A0n4p6bIiVe5OvQPxBnesezsgFJdHhSs3uFSvaPdMqtsovajLZ+G2vZyvNe10EzJBWWo3AcHGKhAFUxqwp2dw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-optional-catch-binding@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.0.0.tgz#886f72008b3a8b185977f7cb70713b45e51ee475" - integrity sha512-Wc+HVvwjcq5qBg1w5RG9o9RVzmCaAg/Vp0erHCKpAYV8La6I94o4GQAmFYNmkzoMO6gzoOSulpKeSSz6mPEoZw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-typescript@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.0.0.tgz#90f4fe0a741ae9c0dcdc3017717c05a0cbbd5158" - integrity sha512-5fxmdqiAQVQTIS+KSvYeZuTt91wKtBTYi6JlIkvbQ6hmO+9fZE81ezxmMiFMIsxE7CdRSgzn7nQ1BChcvK9OpA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-arrow-functions@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0.tgz#a6c14875848c68a3b4b3163a486535ef25c7e749" - integrity sha512-2EZDBl1WIO/q4DIkIp4s86sdp4ZifL51MoIviLY/gG/mLSuOIEg7J8o6mhbxOTvUJkaN50n+8u41FVsr5KLy/w== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-async-to-generator@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.1.0.tgz#109e036496c51dd65857e16acab3bafdf3c57811" - integrity sha512-rNmcmoQ78IrvNCIt/R9U+cixUHeYAzgusTFgIAv+wQb9HJU4szhpDD6e5GCACmj/JP5KxuCwM96bX3L9v4ZN/g== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -350,14 +309,12 @@ "@babel/plugin-transform-block-scoped-functions@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0.tgz#482b3f75103927e37288b3b67b65f848e2aa0d07" - integrity sha512-AOBiyUp7vYTqz2Jibe1UaAWL0Hl9JUXEgjFvvvcSc9MVDItv46ViXFw2F7SVt1B5k+KWjl44eeXOAk3UDEaJjQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-block-scoping@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.0.0.tgz#1745075edffd7cdaf69fab2fb6f9694424b7e9bc" - integrity sha512-GWEMCrmHQcYWISilUrk9GDqH4enf3UmhOEbNbNrlNAX1ssH3MsS1xLOS6rdjRVPgA7XXVPn87tRkdTEoA/dxEg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" lodash "^4.17.10" @@ -365,7 +322,6 @@ "@babel/plugin-transform-classes@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.1.0.tgz#ab3f8a564361800cbc8ab1ca6f21108038432249" - integrity sha512-rNaqoD+4OCBZjM7VaskladgqnZ1LO6o2UxuWSDzljzW21pN1KXkB7BstAVweZdxQkHAujps5QMNOTWesBciKFg== dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-define-map" "^7.1.0" @@ -379,21 +335,18 @@ "@babel/plugin-transform-computed-properties@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0.tgz#2fbb8900cd3e8258f2a2ede909b90e7556185e31" - integrity sha512-ubouZdChNAv4AAWAgU7QKbB93NU5sHwInEWfp+/OzJKA02E6Woh9RVoX4sZrbRwtybky/d7baTUqwFx+HgbvMA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-destructuring@^7.0.0": version "7.1.3" resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.1.3.tgz#e69ff50ca01fac6cb72863c544e516c2b193012f" - integrity sha512-Mb9M4DGIOspH1ExHOUnn2UUXFOyVTiX84fXCd+6B5iWrQg/QMeeRmSwpZ9lnjYLSXtZwiw80ytVMr3zue0ucYw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-dotall-regex@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.0.0.tgz#73a24da69bc3c370251f43a3d048198546115e58" - integrity sha512-00THs8eJxOJUFVx1w8i1MBF4XH4PsAjKjQ1eqN/uCH3YKwP21GCKfrn6YZFZswbOk9+0cw1zGQPHVc1KBlSxig== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" @@ -402,14 +355,12 @@ "@babel/plugin-transform-duplicate-keys@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0.tgz#a0601e580991e7cace080e4cf919cfd58da74e86" - integrity sha512-w2vfPkMqRkdxx+C71ATLJG30PpwtTpW7DDdLqYt2acXU7YjztzeWW2Jk1T6hKqCLYCcEA5UQM/+xTAm+QCSnuQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-exponentiation-operator@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.1.0.tgz#9c34c2ee7fd77e02779cfa37e403a2e1003ccc73" - integrity sha512-uZt9kD1Pp/JubkukOGQml9tqAeI8NkE98oZnHZ2qHRElmeKCodbTZgOEUtujSCSLhHSBWbzNiFSDIMC4/RBTLQ== dependencies: "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -417,14 +368,12 @@ "@babel/plugin-transform-for-of@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0.tgz#f2ba4eadb83bd17dc3c7e9b30f4707365e1c3e39" - integrity sha512-TlxKecN20X2tt2UEr2LNE6aqA0oPeMT1Y3cgz8k4Dn1j5ObT8M3nl9aA37LLklx0PBZKETC9ZAf9n/6SujTuXA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-function-name@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.1.0.tgz#29c5550d5c46208e7f730516d41eeddd4affadbb" - integrity sha512-VxOa1TMlFMtqPW2IDYZQaHsFrq/dDoIjgN098NowhexhZcz3UGlvPgZXuE1jEvNygyWyxRacqDpCZt+par1FNg== dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -432,14 +381,12 @@ "@babel/plugin-transform-literals@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0.tgz#2aec1d29cdd24c407359c930cdd89e914ee8ff86" - integrity sha512-1NTDBWkeNXgpUcyoVFxbr9hS57EpZYXpje92zv0SUzjdu3enaRwF/l3cmyRnXLtIdyJASyiS6PtybK+CgKf7jA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-modules-amd@^7.0.0", "@babel/plugin-transform-modules-amd@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.1.0.tgz#f9e0a7072c12e296079b5a59f408ff5b97bf86a8" - integrity sha512-wt8P+xQ85rrnGNr2x1iV3DW32W8zrB6ctuBkYBbf5/ZzJY99Ob4MFgsZDFgczNU76iy9PWsy4EuxOliDjdKw6A== dependencies: "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -447,7 +394,6 @@ "@babel/plugin-transform-modules-commonjs@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.1.0.tgz#0a9d86451cbbfb29bd15186306897c67f6f9a05c" - integrity sha512-wtNwtMjn1XGwM0AXPspQgvmE6msSJP15CX2RVfpTSTNPLhKhaOjaIfBaVfj4iUZ/VrFSodcFedwtPg/NxwQlPA== dependencies: "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -456,7 +402,6 @@ "@babel/plugin-transform-modules-systemjs@^7.0.0": version "7.1.3" resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.1.3.tgz#2119a3e3db612fd74a19d88652efbfe9613a5db0" - integrity sha512-PvTxgjxQAq4pvVUZF3mD5gEtVDuId8NtWkJsZLEJZMZAW3TvgQl1pmydLLN1bM8huHFVVU43lf0uvjQj9FRkKw== dependencies: "@babel/helper-hoist-variables" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -464,7 +409,6 @@ "@babel/plugin-transform-modules-umd@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.1.0.tgz#a29a7d85d6f28c3561c33964442257cc6a21f2a8" - integrity sha512-enrRtn5TfRhMmbRwm7F8qOj0qEYByqUvTttPEGimcBH4CJHphjyK1Vg7sdU7JjeEmgSpM890IT/efS2nMHwYig== dependencies: "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -472,14 +416,12 @@ "@babel/plugin-transform-new-target@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz#ae8fbd89517fa7892d20e6564e641e8770c3aa4a" - integrity sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-object-super@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.1.0.tgz#b1ae194a054b826d8d4ba7ca91486d4ada0f91bb" - integrity sha512-/O02Je1CRTSk2SSJaq0xjwQ8hG4zhZGNjE8psTsSNPXyLRCODv7/PBozqT5AmQMzp7MI3ndvMhGdqp9c96tTEw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-replace-supers" "^7.1.0" @@ -487,7 +429,6 @@ "@babel/plugin-transform-parameters@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.1.0.tgz#44f492f9d618c9124026e62301c296bf606a7aed" - integrity sha512-vHV7oxkEJ8IHxTfRr3hNGzV446GAb+0hgbA7o/0Jd76s+YzccdWuTU296FOCOl/xweU4t/Ya4g41yWz80RFCRw== dependencies: "@babel/helper-call-delegate" "^7.1.0" "@babel/helper-get-function-arity" "^7.0.0" @@ -496,28 +437,24 @@ "@babel/plugin-transform-regenerator@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz#5b41686b4ed40bef874d7ed6a84bdd849c13e0c1" - integrity sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw== dependencies: regenerator-transform "^0.13.3" "@babel/plugin-transform-shorthand-properties@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0.tgz#85f8af592dcc07647541a0350e8c95c7bf419d15" - integrity sha512-g/99LI4vm5iOf5r1Gdxq5Xmu91zvjhEG5+yZDJW268AZELAu4J1EiFLnkSG3yuUsZyOipVOVUKoGPYwfsTymhw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-spread@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0.tgz#93583ce48dd8c85e53f3a46056c856e4af30b49b" - integrity sha512-L702YFy2EvirrR4shTj0g2xQp7aNwZoWNCkNu2mcoU0uyzMl0XRwDSwzB/xp6DSUFiBmEXuyAyEN16LsgVqGGQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-sticky-regex@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0.tgz#30a9d64ac2ab46eec087b8530535becd90e73366" - integrity sha512-LFUToxiyS/WD+XEWpkx/XJBrUXKewSZpzX68s+yEOtIbdnsRjpryDw9U06gYc6klYEij/+KQVRnD3nz3AoKmjw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" @@ -525,7 +462,6 @@ "@babel/plugin-transform-template-literals@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0.tgz#084f1952efe5b153ddae69eb8945f882c7a97c65" - integrity sha512-vA6rkTCabRZu7Nbl9DfLZE1imj4tzdWcg5vtdQGvj+OH9itNNB6hxuRMHuIY8SGnEt1T9g5foqs9LnrHzsqEFg== dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -533,14 +469,12 @@ "@babel/plugin-transform-typeof-symbol@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0.tgz#4dcf1e52e943e5267b7313bff347fdbe0f81cec9" - integrity sha512-1r1X5DO78WnaAIvs5uC48t41LLckxsYklJrZjNKcevyz83sF2l4RHbw29qrCPr/6ksFsdfRpT/ZgxNWHXRnffg== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-typescript@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.1.0.tgz#81e7b4be90e7317cbd04bf1163ebf06b2adee60b" - integrity sha512-TOTtVeT+fekAesiCHnPz+PSkYSdOSLyLn42DI45nxg6iCdlQY6LIj/tYqpMB0y+YicoTUiYiXqF8rG6SKfhw6Q== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-typescript" "^7.0.0" @@ -548,7 +482,6 @@ "@babel/plugin-transform-unicode-regex@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0.tgz#c6780e5b1863a76fe792d90eded9fcd5b51d68fc" - integrity sha512-uJBrJhBOEa3D033P95nPHu3nbFwFE9ZgXsfEitzoIXIwqAZWk7uXcg06yFKXz9FSxBH5ucgU/cYdX0IV8ldHKw== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" @@ -557,7 +490,6 @@ "@babel/polyfill@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.0.0.tgz#c8ff65c9ec3be6a1ba10113ebd40e8750fb90bff" - integrity sha512-dnrMRkyyr74CRelJwvgnnSUDh2ge2NCTyHVwpOdvRMHtJUyxLtMAfhBN3s64pY41zdw0kgiLPh6S20eb1NcX6Q== dependencies: core-js "^2.5.7" regenerator-runtime "^0.11.1" @@ -565,7 +497,6 @@ "@babel/preset-env@^7.0.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.1.0.tgz#e67ea5b0441cfeab1d6f41e9b5c79798800e8d11" - integrity sha512-ZLVSynfAoDHB/34A17/JCZbyrzbQj59QC1Anyueb4Bwjh373nVPq5/HMph0z+tCmcDjXDe+DlKQq9ywQuvWrQg== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -612,7 +543,6 @@ "@babel/template@^7.1.0", "@babel/template@^7.1.2": version "7.1.2" resolved "https://registry.npmjs.org/@babel/template/-/template-7.1.2.tgz#090484a574fef5a2d2d7726a674eceda5c5b5644" - integrity sha512-SY1MmplssORfFiLDcOETrW7fCLl+PavlwMh92rrGcikQaRq4iWPVH0MpwPpY3etVMx6RnDjXtr6VZYr/IbP/Ag== dependencies: "@babel/code-frame" "^7.0.0" "@babel/parser" "^7.1.2" @@ -621,7 +551,6 @@ "@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0": version "7.1.4" resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.4.tgz#f4f83b93d649b4b2c91121a9087fa2fa949ec2b4" - integrity sha512-my9mdrAIGdDiSVBuMjpn/oXYpva0/EZwWL3sm3Wcy/AVWO2eXnsoZruOT9jOGNRXU8KbCIu5zsKnXcAJ6PcV6Q== dependencies: "@babel/code-frame" "^7.0.0" "@babel/generator" "^7.1.3" @@ -636,7 +565,6 @@ "@babel/types@^7.0.0", "@babel/types@^7.1.2", "@babel/types@^7.1.3": version "7.1.3" resolved "https://registry.npmjs.org/@babel/types/-/types-7.1.3.tgz#3a767004567060c2f40fca49a304712c525ee37d" - integrity sha512-RpPOVfK+yatXyn8n4PB1NW6k9qjinrXrRR8ugBN8fD6hCy5RXI6PSbVqpOJBO9oSaY7Nom4ohj35feb0UR9hSA== dependencies: esutils "^2.0.2" lodash "^4.17.10" @@ -645,7 +573,6 @@ "@ember-decorators/babel-transforms@^2.1.2": version "2.1.2" resolved "https://registry.npmjs.org/@ember-decorators/babel-transforms/-/babel-transforms-2.1.2.tgz#b646e53ece7c18ae42cd03f320146cb1f26f4ebf" - integrity sha512-Sfa4bjtRpWytbBZK3fAaUp6/2QpMDds6uGA5K7S+Iz1JGX+PHTLDjl1/5t1UaOMokEB1Z9jMtwp4yRcullfFdg== dependencies: "@babel/plugin-proposal-class-properties" "^7.0.0" "@babel/plugin-proposal-decorators" "^7.0.0" @@ -657,7 +584,6 @@ "@ember-decorators/component@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@ember-decorators/component/-/component-3.0.0.tgz#9f31cc4eac800bedebf69ef8e432519092cd0430" - integrity sha512-974O2OQZvZNJBHqRnl/tAu15O6NAhbNU8UhQ5WggFCubojrXSwMXj8wk79aLT7Z3lcZTpNfPb5g16O0WlyXYpg== dependencies: "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" @@ -665,7 +591,6 @@ "@ember-decorators/controller@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@ember-decorators/controller/-/controller-3.0.0.tgz#1f5b0e88f7456bc869775f70cd86a56cb690f301" - integrity sha512-BESK+lVJGgTfQ6+6fygZeSqedltTHUJyX9tHzOtlRBg3MJOR0xrsS8Yh27ikJ3tlswZ21GoIV6CTsQ40pIlmLg== dependencies: "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" @@ -673,7 +598,6 @@ "@ember-decorators/data@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@ember-decorators/data/-/data-3.0.0.tgz#78c6cb8b9b14eeee4bfd265cd00c95dc09416420" - integrity sha512-VsalfSnz7a8N7AEfu8Kuzc9pFAZ1Oh/M9NNMP5lts7tmZctRPsi7u3HLYAv5Iz7etseW0DFq8hcAobZIDOPWFw== dependencies: "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" @@ -681,7 +605,6 @@ "@ember-decorators/object@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@ember-decorators/object/-/object-3.0.0.tgz#84c5d3e62d3b211ffd17a795c0c4a65c3fe52f8d" - integrity sha512-cvQDoZM+vJJniT0sZZZHS1TWdG9V9XmPBfeiaAlS1YTNQmLmNyDfmqd+/OUJUP0er/im8GjGCzMUifuZWhqdmQ== dependencies: "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" @@ -690,7 +613,6 @@ "@ember-decorators/service@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@ember-decorators/service/-/service-3.0.0.tgz#90fe410b8b2b80ad7227a85259e3a8c3852000a2" - integrity sha512-YcyH/+2AlAmOyVeKMSbc3rvT+n1ts2mPsZRGS1nKvIWB/M8cfOQrssdBj+kbQS7RTxC/sPRAnBZsvTRhRsua8g== dependencies: "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" @@ -698,7 +620,6 @@ "@ember-decorators/utils@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@ember-decorators/utils/-/utils-3.0.0.tgz#f8e82ead2c75a8eaf2cef5b1811ab54fcb28bcee" - integrity sha512-ghvNpiS9p8y/3whKB5J8PK2ESXeyk4oKYgJHyks8799lgi2MgbFeFyls6weJNKRp5Wcjen2KEBzTaf/zExZlgA== dependencies: babel-plugin-debug-macros "^0.1.11" ember-cli-babel "^6.6.0" @@ -707,7 +628,6 @@ "@ember/ordered-set@^2.0.3": version "2.0.3" resolved "https://registry.npmjs.org/@ember/ordered-set/-/ordered-set-2.0.3.tgz#2ac1ca73b3bd116063cae814898832ef434a57f9" - integrity sha512-F4yfVk6WMc4AUHxeZsC3CaKyTvO0qSZJy7WWHCFTlVDQw6vubn+FvnGdhzpN1F00EiXMI4Tv1tJdSquHcCnYrA== dependencies: ember-cli-babel "^6.16.0" ember-compatibility-helpers "^1.1.1" @@ -715,7 +635,6 @@ "@ember/test-helpers@^0.7.26": version "0.7.27" resolved "https://registry.npmjs.org/@ember/test-helpers/-/test-helpers-0.7.27.tgz#c622cabd0cbb95b34efc1e1b6274ab5a14edc138" - integrity sha512-AQESk0FTFxRY6GyZ8PharR4SC7Fju0rXqNkfNYIntAjzefZ8xEqEM4iXDj5h7gAvfx/8dA69AQ9+p7ubc+KvJg== dependencies: broccoli-funnel "^2.0.1" ember-assign-polyfill "~2.4.0" @@ -725,36 +644,30 @@ "@glimmer/di@^0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" - integrity sha1-c7/Upu5BSKgL8JLopdKbysnUzn4= "@glimmer/env@^0.1.7": version "0.1.7" resolved "https://registry.npmjs.org/@glimmer/env/-/env-0.1.7.tgz#fd2d2b55a9029c6b37a6c935e8c8871ae70dfa07" - integrity sha1-/S0rVakCnGs3psk16MiHGucN+gc= "@glimmer/resolver@^0.4.1": version "0.4.3" resolved "https://registry.yarnpkg.com/@glimmer/resolver/-/resolver-0.4.3.tgz#b1baae5c3291b4621002ccf8d7870466097e841d" - integrity sha512-UhX6vlZbWRMq6pCquSC3wfWLM9kO0PhQPD1dZ3XnyZkmsvEE94Cq+EncA9JalUuevKoJrfUFRvrZ0xaz+yar3g== dependencies: "@glimmer/di" "^0.2.0" "@sindresorhus/is@^0.7.0": version "0.7.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" - integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== "@types/acorn@^4.0.3": version "4.0.3" resolved "https://registry.yarnpkg.com/@types/acorn/-/acorn-4.0.3.tgz#d1f3e738dde52536f9aad3d3380d14e448820afd" - integrity sha512-gou/kWQkGPMZjdCKNZGDpqxLm9+ErG/pFZKPX4tvCjr0Xf4FCYYX3nAsu7aDVKJV3KUe27+mvqqyWT/9VZoM/A== dependencies: "@types/estree" "*" "@types/ember-qunit@~3.4.3": version "3.4.3" resolved "https://registry.yarnpkg.com/@types/ember-qunit/-/ember-qunit-3.4.3.tgz#ad8532e735c7a46af764f5cb7d852896e6d28bfd" - integrity sha512-dBlWUh7XMHT3dr96P2c5U5hx8dLE4RZmtwKhUeaHycsgJyH4pCX1C462Bk308fWXFN1TWasZtkl+MhtW/mj3RA== dependencies: "@types/ember" "*" "@types/ember-test-helpers" "*" @@ -762,7 +675,6 @@ "@types/ember-test-helpers@*", "@types/ember-test-helpers@~1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@types/ember-test-helpers/-/ember-test-helpers-1.0.4.tgz#db08190659339cd6018ff8f842c6df6f24d7679a" - integrity sha512-9UnLaDSRiNHZtj3Bn46kRkQKbbnb50ClpzQQ0p/raZYzHjDjUZfLpI4KOuVRfibgEj4LI+lsUKx5LQeLD09wcw== dependencies: "@types/ember" "*" "@types/htmlbars-inline-precompile" "*" @@ -772,7 +684,6 @@ "@types/ember-testing-helpers@~0.0.3": version "0.0.3" resolved "https://registry.yarnpkg.com/@types/ember-testing-helpers/-/ember-testing-helpers-0.0.3.tgz#1a6cfc484b63d19ddd822c87e4dd710597db17d9" - integrity sha512-QG3QBBR7PFzz3zhLTbsZWBgk3cNQIZYVG6rbXKMM36+YP3dcSkkWQ6CRTyQImUIfgAkYPMaWqGlGEtkuanq3Bg== dependencies: "@types/jquery" "*" "@types/rsvp" "*" @@ -780,7 +691,6 @@ "@types/ember@*", "@types/ember@~3.0.25": version "3.0.25" resolved "https://registry.yarnpkg.com/@types/ember/-/ember-3.0.25.tgz#9ab6a8be3d03a72176824bb7a59583648b6b1ced" - integrity sha512-+M4yzJ0v+Ly62clAoxmAxViFg+/2HiktQnzKh825/y9Ra3k7o4PFsas0Z7xERmRVleqtPikehwdi6BuEnPUVkw== dependencies: "@types/ember__application" "*" "@types/ember__array" "*" @@ -805,78 +715,64 @@ "@types/ember__application@*": version "3.0.5" resolved "https://registry.yarnpkg.com/@types/ember__application/-/ember__application-3.0.5.tgz#e171c5f44f58fb5600952bfde25c1dfe3785a08e" - integrity sha512-lRZZInE7g5//UQyJ2ro/wql6AcjYeFTo69SYrL2qdgHSwGemSv/A/6u5Q73OMuKZL22nNyCLoCy/Q7TrEhM/mQ== "@types/ember__array@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/ember__array/-/ember__array-3.0.3.tgz#87887852b16b7572441b9723994098f939f2a386" - integrity sha512-9RVCedNGxkXrCwOVvDaD5/RB4FbOzZLA5+BV5kcRkxjNcAQMx29BwM6/nipAKGppi1wmoPPkVpsHcJcbiuUgbQ== "@types/ember__component@*": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/ember__component/-/ember__component-3.0.4.tgz#e671213269bbf974445fb9fdd600d52ef0ae1e2a" - integrity sha512-SgUAtEqbTdexNFJsvC0EJ0wfQ3+a66xGEFojwjoeilVUaBDAhcfGzlai6Y101xfyax9kYdBX3XJ2YmtRh32rPw== dependencies: "@types/jquery" "*" "@types/ember__controller@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/ember__controller/-/ember__controller-3.0.3.tgz#622440d41ce0ae46f2610ed22670be9088cc9c2b" - integrity sha512-jJ/4SmRfAQuLS+dxB7GdS9BU1dpqA8QzKq84d1+aZkpcDiu0pD7/Xwu5FN4pbU1kBfX2w6jdQQRlnorOpuYltQ== -"@types/ember__debug@*": +"@types/ember__debug@*", "@types/ember__debug@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/ember__debug/-/ember__debug-3.0.3.tgz#b8c3481e2305b636dca4524331efd4112071902b" - integrity sha512-6cOPb5S9IX4tU4b8YwkxbnlF+mql/ejTgpMtuyNmFyp4irBV9fdKn6y1K6hvml7yDSJnhdw37/6Gs+nGi95eKQ== "@types/ember__engine@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/ember__engine/-/ember__engine-3.0.3.tgz#440e656f825f73240419367ee7637ca94b4a1780" - integrity sha512-mXaUam9NbU7mOxRDBNcnW3GYpo+NVYQPSRor6ghdABOl+Lik8frX0oqgSnknauoCVW34Q75oH3xAd1cjNWEsPA== "@types/ember__error@*": version "3.0.2" resolved "https://registry.yarnpkg.com/@types/ember__error/-/ember__error-3.0.2.tgz#a30c0e51215feaaa7a32e341c5a04bd601a01d1b" - integrity sha512-U1IsKAfoqgNTAQ7rojbAmF8ynQaovfHP9Kff1lCB1A1FLq+vtQ81CzaiEHgWWAlPfbqrFtBIYD0rwehEQ1ofRg== "@types/ember__object@*": version "3.0.5" resolved "https://registry.yarnpkg.com/@types/ember__object/-/ember__object-3.0.5.tgz#c4957cad68fffdd0959c6ca0d3469df8878b750c" - integrity sha512-0sgaktxsu86OqRNOe9lxLhqWnGGk+gNM+iuAbi7BKc5OZQHlOtAGPgHv7hUozWCW5cVK/3hMbr3ciD/vu25xsg== dependencies: "@types/rsvp" "*" "@types/ember__polyfills@*": version "3.0.2" resolved "https://registry.yarnpkg.com/@types/ember__polyfills/-/ember__polyfills-3.0.2.tgz#ccd9f510a4895abf92435c968f9e582e86a81b25" - integrity sha512-b+FT7EFsyqgRBHYLq71SJm88iLOfz/QYjdOJi72hYWXG8sBoK6GYcUzGlaQwCFgz/HFp/KH68jCDx+sHIq+kxQ== "@types/ember__routing@*": version "3.0.5" resolved "https://registry.yarnpkg.com/@types/ember__routing/-/ember__routing-3.0.5.tgz#9b193178a1cc29560992c57b04fd7d83a70f831d" - integrity sha512-G2e7WYNsLHQaoKeJUIFyVlzQUToCDm2omP9jaXHS1vzz5UYN1FXI+w2PPTC3eqcb9py/B6SzmthokaTy0VEdCA== "@types/ember__runloop@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/ember__runloop/-/ember__runloop-3.0.3.tgz#c23c9d4327ca811482422505a1f5bf1c48458f53" - integrity sha512-JQ9SK0pmdXcIpy++FpIC3tJeHtEn9sxO2QRNDR3Xe8KVnq7+ld4lmNF6DMIx9UvoyV2lJstrv/sjDqhMvIadwA== "@types/ember__service@*": version "3.0.2" resolved "https://registry.yarnpkg.com/@types/ember__service/-/ember__service-3.0.2.tgz#8265c94a599c865f633361b0e3b1efbeef393d7d" - integrity sha512-HxruUU/U3wIFk6YTX1Yl57WjosuPpawr3JJHUZktPHjFwe9uHEIoO8yc7QUeQTB9OIk3NVt05391TtOJrKON7g== "@types/ember__string@*": version "3.0.2" resolved "https://registry.yarnpkg.com/@types/ember__string/-/ember__string-3.0.2.tgz#2ffdf09baab6a641c94c0149a8ff3670f793788d" - integrity sha512-VN6HgEs7VJzPFmfVN2riQ4oroIh650YWsNOWFiq5uKzYD8kCtfrkpyRJjzGoTmS3mm8F3qIVw6Ev6KGXxQU8+A== dependencies: "@types/handlebars" "*" "@types/ember__test-helpers@~0.7.6": version "0.7.6" resolved "https://registry.yarnpkg.com/@types/ember__test-helpers/-/ember__test-helpers-0.7.6.tgz#f26050fc74cd8ce111ee9e01864a293d6a9ac7ac" - integrity sha512-TEIitF7M984drIuK1iKHWfU7BLvdp4qakC7Qwmz88HoJxjdMKHHYAIIVO+SPZdXBCmPjOmCs87bz2okMs9nU2Q== dependencies: "@types/ember" "*" "@types/ember__error" "*" @@ -885,89 +781,72 @@ "@types/ember__test@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/ember__test/-/ember__test-3.0.3.tgz#dda4721609e9e80d62af784757b8b3b76b49a07d" - integrity sha512-pedzxJh7BZBIL4tgnWv74f3EuRqbm7sRroWFhcIRhNliFUTN0GZ9p7poAp7gnwOxpYLcXOvUjkdaeaWP6rxYMA== "@types/ember__utils@*": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/ember__utils/-/ember__utils-3.0.1.tgz#f08aa24920515400fec869cbf29df69c4773f6d0" - integrity sha512-seA9IX2DCrkHxgVmtoKUVEBj6to8vqlPG7AzwB2oodLlQZiRwmrnn+fjOn+wKA5btIVIiRdxn/f41qFZXcPy6w== "@types/estree@*": version "0.0.39" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" - integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== "@types/estree@0.0.38": version "0.0.38" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.38.tgz#c1be40aa933723c608820a99a373a16d215a1ca2" - integrity sha512-F/v7t1LwS4vnXuPooJQGBRKRGIoxWUTmA4VHfqjOccFsNDThD5bfUNpITive6s352O7o384wcpEaDV8rHCehDA== "@types/handlebars@*": version "4.0.39" resolved "https://registry.yarnpkg.com/@types/handlebars/-/handlebars-4.0.39.tgz#961fb54db68030890942e6aeffe9f93a957807bd" - integrity sha512-vjaS7Q0dVqFp85QhyPSZqDKnTTCemcSHNHFvDdalO1s0Ifz5KuE64jQD5xoUkfdWwF4WpqdJEl7LsWH8rzhKJA== "@types/htmlbars-inline-precompile@*": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/htmlbars-inline-precompile/-/htmlbars-inline-precompile-1.0.0.tgz#4c283da1a7e303b269de3c6aa953acc8d8736949" - integrity sha512-J7+MkDbUl/Sb57OuniuvVr4HLlHV2ub2y31HmD9QiepLEMj0zGIv4hbyOfGHTKWCcU0r7lxcDdHdLyUjpuL21w== "@types/jquery@*": version "3.3.22" resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.22.tgz#cde55dc8f83207dffd16205b05f97ce824581735" - integrity sha512-a4JDcIhJhHYnoWCkG3xT2CZxXZeA92JeREESorg0DMQ3ZsjuKF48h7XK4l5Gl2GRa/ItGRpKMT0pyK88yRgqXQ== dependencies: "@types/sizzle" "*" "@types/node@^9.6.0": version "9.6.23" resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.23.tgz#fc429962c1b75f32bd66214a3997f660e8434f0d" - integrity sha512-d2SJJpwkiPudEQ3+9ysANN2Nvz4QJKUPoe/WL5zyQzI0RaEeZWH5K5xjvUIGszTItHQpFPdH+u51f6G/LkS8Cg== "@types/qunit@^2.5.3": version "2.5.3" resolved "https://registry.yarnpkg.com/@types/qunit/-/qunit-2.5.3.tgz#e7df363b5e1d1ba034b5fdd34b560d5ec0914225" - integrity sha512-b9xNH1wBOnY+yiCT2DiAC0yi7GCF5g6whiAFA/dpd9RtL/Jn2XR7e4yyeAQwH3TUeF00zikmYqYxS0K8+EKTKQ== "@types/rsvp@*", "@types/rsvp@^4.0.2": version "4.0.2" resolved "https://registry.yarnpkg.com/@types/rsvp/-/rsvp-4.0.2.tgz#bf9f72eaa6771292638a85bb8ce1db97e754b371" - integrity sha512-48ZwxFD1hdBj8QMOSNGA2kYuo3+SKh8OEYh5cMi7cPRZXBF9jwVPV4yqA7EcJTNlAJL0v99pEUYetl0TsufMQA== "@types/sizzle@*": version "2.3.2" resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" - integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg== "@types/tmp@^0.0.33": version "0.0.33" resolved "https://registry.npmjs.org/@types/tmp/-/tmp-0.0.33.tgz#1073c4bc824754ae3d10cfab88ab0237ba964e4d" - integrity sha1-EHPEvIJHVK49EM+riKsCN7qWTk0= "@xg-wang/whatwg-fetch@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@xg-wang/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#f7b222c012a238e7d6e89ed3d72a1e0edb58453d" - integrity sha512-ULtqA6L75RLzTNW68IiOja0XYv4Ebc3OGMzfia1xxSEMpD0mk/pMvkQX0vbCFyQmKc5xGp80Ms2WiSlXLh8hbA== abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== abbrev@~1.0.7: version "1.0.9" resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" - integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU= abortcontroller-polyfill@^1.1.9: version "1.1.9" resolved "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.1.9.tgz#9fefe359fda2e9e0932dc85e6106453ac393b2da" - integrity sha512-omvG7zOHIs3BphdH62Kh3xy8nlftAsTyp7PDa9EmC3Jz9pa6sZFYk7UhNgu9Y4sIBhj6jF0RgeFZYvPnsP5sBw== accepts@~1.3.4, accepts@~1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" - integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= dependencies: mime-types "~2.1.18" negotiator "0.6.1" @@ -975,31 +854,26 @@ accepts@~1.3.4, accepts@~1.3.5: acorn-dynamic-import@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" - integrity sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg== dependencies: acorn "^5.0.0" acorn-jsx@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-4.1.1.tgz#e8e41e48ea2fe0c896740610ab6a4ffd8add225e" - integrity sha512-JY+iV6r+cO21KtntVvFkD+iqjtdpRUpGqKWgfkCdZq1R+kbreEl8EcdcJR4SmiIgsIQT33s6QzheQ9a275Q8xw== dependencies: acorn "^5.0.3" acorn@^5.0.0, acorn@^5.0.3, acorn@^5.5.3, acorn@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" - integrity sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ== after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" - integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= ajv@^5.3.0: version "5.5.2" resolved "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= dependencies: co "^4.6.0" fast-deep-equal "^1.0.0" @@ -1009,7 +883,6 @@ ajv@^5.3.0: ajv@^6.5.3: version "6.5.4" resolved "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz#247d5274110db653706b550fcc2b797ca28cfc59" - integrity sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg== dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" @@ -1019,7 +892,6 @@ ajv@^6.5.3: align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" - integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc= dependencies: kind-of "^3.0.2" longest "^1.0.1" @@ -1028,78 +900,64 @@ align-text@^0.1.1, align-text@^0.1.3: amd-name-resolver@1.2.0, amd-name-resolver@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz#fc41b3848824b557313897d71f8d5a0184fbe679" - integrity sha512-hlSTWGS1t6/xq5YCed7YALg7tKZL3rkl7UwEZ/eCIkn8JxmM6fU6Qs/1hwtjQqfuYxlffuUcgYEm0f5xP4YKaA== dependencies: ensure-posix-path "^1.0.1" amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" - integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - integrity sha1-06ioOzGapneTZisT52HHkRQiMG4= ansi-escapes@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" - integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw== ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= ansi-styles@^3.0.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" ansi-to-html@^0.6.6: version "0.6.8" resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.6.8.tgz#2a4468b45a5d2a2c1a51eb1a1175eda8acb4f07a" - integrity sha512-wXwNl185AIu1QXuNApBiYNaWx0q+Ma1tLDVgc0HbA43GFWG8p1gcWLKKIBjQqamKe3rUkEILb6QMu9G/V14mzQ== dependencies: entities "^1.1.1" ansi@^0.3.0, ansi@~0.3.0, ansi@~0.3.1: version "0.3.1" resolved "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz#0c42d4fb17160d5a9af1e484bace1c66922c1b21" - integrity sha1-DELU+xcWDVqa8eSEus4cZpIsGyE= ansicolors@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" - integrity sha1-vgiVmQl7dKXJxKhKDNvNtivYeu8= ansicolors@~0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" - integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk= ansistyles@~0.1.3: version "0.1.3" resolved "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" - integrity sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk= anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== dependencies: micromatch "^3.1.4" normalize-path "^2.1.1" @@ -1107,22 +965,18 @@ anymatch@^2.0.0: aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== aproba@~1.0.1: version "1.0.4" resolved "https://registry.npmjs.org/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" - integrity sha1-JxNoB3XnYUyLoYbAZdTi5S0QcsA= archy@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" - integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= are-we-there-yet@~1.0.0: version "1.0.6" resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.6.tgz#a2d28c93102aa6cc96245a26cb954de06ec53f0c" - integrity sha1-otKMkxAqpsyWJFomy5VN4G7FPww= dependencies: delegates "^1.0.0" readable-stream "^2.0.0 || ^1.1.13" @@ -1130,7 +984,6 @@ are-we-there-yet@~1.0.0: are-we-there-yet@~1.1.2: version "1.1.5" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== dependencies: delegates "^1.0.0" readable-stream "^2.0.6" @@ -1138,51 +991,42 @@ are-we-there-yet@~1.1.2: argparse@^1.0.7, argparse@~1.0.2: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" arr-diff@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= dependencies: arr-flatten "^1.0.1" arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== arr-union@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= array-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" - integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= array-index@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/array-index/-/array-index-1.0.0.tgz#ec56a749ee103e4e08c790b9c353df16055b97f9" - integrity sha1-7FanSe4QPk4Ix5C5w1PfFgVbl/k= dependencies: debug "^2.2.0" es6-symbol "^3.0.2" @@ -1190,98 +1034,80 @@ array-index@^1.0.0: array-to-error@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" - integrity sha1-1ogSkm0UCXogVXmmZ+6vGFakTAc= dependencies: array-to-sentence "^1.1.0" array-to-sentence@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" - integrity sha1-yASVba+lMjJJWyBalFJ1OiWNOfw= array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= dependencies: array-uniq "^1.0.1" array-uniq@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= arraybuffer.slice@~0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" - integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= asap@^2.0.0: version "2.0.6" resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= asn1@0.1.11: version "0.1.11" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" - integrity sha1-VZvhg3bQik7E2+gId9J4GGObLfc= asn1@~0.2.3: version "0.2.4" resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== dependencies: safer-buffer "~2.1.0" assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= assert-plus@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" - integrity sha1-7nQAlBMALYTOxyGcasgRgS5yMWA= assert-plus@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - integrity sha1-104bh+ev/A24qttwIfP+SBAasjQ= assertion-error@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" - integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== assign-symbols@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= ast-types@0.9.6: version "0.9.6" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" - integrity sha1-ECyenpAF0+fjgpvwxPok7oYu6bk= async-disk-cache@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.3.3.tgz#6040486660b370e4051cd9fa9fee275e1fae3728" - integrity sha512-GyaWSbDAZCltxSobtj1m1ptXa0+zSdjWs3sM4IqnvhoRwMDHW5786sXQ1RiXbR3ZGuQe6NXMB4N0vUmW163cew== dependencies: debug "^2.1.3" heimdalljs "^0.2.3" @@ -1294,12 +1120,10 @@ async-disk-cache@^1.2.1: async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" - integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== async-promise-queue@^1.0.3, async-promise-queue@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/async-promise-queue/-/async-promise-queue-1.0.4.tgz#308baafbc74aff66a0bb6e7f4a18d4fe8434440c" - integrity sha512-GQ5X3DT+TefYuFPHdvIPXFTlKnh39U7dwtl+aUBGeKjMea9nBpv3c91DXgeyBQmY07vQ97f3Sr9XHqkamEameQ== dependencies: async "^2.4.1" debug "^2.6.8" @@ -1307,66 +1131,54 @@ async-promise-queue@^1.0.3, async-promise-queue@^1.0.4: async-some@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/async-some/-/async-some-1.0.2.tgz#4d8a81620d5958791b5b98f802d3207776e95509" - integrity sha1-TYqBYg1ZWHkbW5j4AtMgd3bpVQk= dependencies: dezalgo "^1.0.2" async@^1.4.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= async@^2.0.1, async@^2.4.1, async@^2.5.0: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" - integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ== dependencies: lodash "^4.17.10" async@~0.2.9: version "0.2.10" resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" - integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E= async@~0.9.0: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" - integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= asynckit@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= atob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" - integrity sha1-ri1acpR38onWDdf5amMUoi3Wwio= aws-sign2@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" - integrity sha1-xXED96F/wDfwLXwuZLYC6iI/fWM= aws-sign2@~0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - integrity sha1-FDQt0428yU0OW4fXY81jYSwOeU8= aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: version "1.8.0" resolved "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= dependencies: chalk "^1.1.3" esutils "^2.0.2" @@ -1375,7 +1187,6 @@ babel-code-frame@^6.26.0: babel-core@^6.26.0: version "6.26.3" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" - integrity sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA== dependencies: babel-code-frame "^6.26.0" babel-generator "^6.26.0" @@ -1400,7 +1211,6 @@ babel-core@^6.26.0: babel-eslint@^10.0.1: version "10.0.1" resolved "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz#919681dc099614cd7d31d45c8908695092a1faed" - integrity sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ== dependencies: "@babel/code-frame" "^7.0.0" "@babel/parser" "^7.0.0" @@ -1412,7 +1222,6 @@ babel-eslint@^10.0.1: babel-generator@^6.26.0: version "6.26.1" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" - integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== dependencies: babel-messages "^6.23.0" babel-runtime "^6.26.0" @@ -1426,7 +1235,6 @@ babel-generator@^6.26.0: babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" - integrity sha1-zORReto1b0IgvK6KAsKzRvmlZmQ= dependencies: babel-helper-explode-assignable-expression "^6.24.1" babel-runtime "^6.22.0" @@ -1435,7 +1243,6 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: babel-helper-call-delegate@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" - integrity sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340= dependencies: babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" @@ -1445,7 +1252,6 @@ babel-helper-call-delegate@^6.24.1: babel-helper-define-map@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" - integrity sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8= dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.26.0" @@ -1455,7 +1261,6 @@ babel-helper-define-map@^6.24.1: babel-helper-explode-assignable-expression@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" - integrity sha1-8luCz33BBDPFX3BZLVdGQArCLKo= dependencies: babel-runtime "^6.22.0" babel-traverse "^6.24.1" @@ -1464,7 +1269,6 @@ babel-helper-explode-assignable-expression@^6.24.1: babel-helper-function-name@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" - integrity sha1-00dbjAPtmCQqJbSDUasYOZ01gKk= dependencies: babel-helper-get-function-arity "^6.24.1" babel-runtime "^6.22.0" @@ -1475,7 +1279,6 @@ babel-helper-function-name@^6.24.1: babel-helper-get-function-arity@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" - integrity sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -1483,7 +1286,6 @@ babel-helper-get-function-arity@^6.24.1: babel-helper-hoist-variables@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" - integrity sha1-HssnaJydJVE+rbyZFKc/VAi+enY= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -1491,7 +1293,6 @@ babel-helper-hoist-variables@^6.24.1: babel-helper-optimise-call-expression@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" - integrity sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -1499,7 +1300,6 @@ babel-helper-optimise-call-expression@^6.24.1: babel-helper-regex@^6.24.1: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" - integrity sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI= dependencies: babel-runtime "^6.26.0" babel-types "^6.26.0" @@ -1508,7 +1308,6 @@ babel-helper-regex@^6.24.1: babel-helper-remap-async-to-generator@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" - integrity sha1-XsWBgnrXI/7N04HxySg5BnbkVRs= dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" @@ -1519,7 +1318,6 @@ babel-helper-remap-async-to-generator@^6.24.1: babel-helper-replace-supers@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" - integrity sha1-v22/5Dk40XNpohPKiov3S2qQqxo= dependencies: babel-helper-optimise-call-expression "^6.24.1" babel-messages "^6.23.0" @@ -1531,7 +1329,6 @@ babel-helper-replace-supers@^6.24.1: babel-helpers@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - integrity sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI= dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" @@ -1539,61 +1336,52 @@ babel-helpers@^6.24.1: babel-messages@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= dependencies: babel-runtime "^6.22.0" babel-plugin-check-es2015-constants@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" - integrity sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o= dependencies: babel-runtime "^6.22.0" babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.11: version "0.1.11" resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" - integrity sha512-hZw5qNNGAR02Y+yBUrtsnJHh8OXavkayPRqKGAXnIm4t5rWVpj3ArwsC7TWdpZsBguQvHAeyTxZ7s23yY60HHg== dependencies: semver "^5.3.0" babel-plugin-debug-macros@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0.tgz#0120ac20ce06ccc57bf493b667cf24b85c28da7a" - integrity sha512-Wpmw4TbhR3Eq2t3W51eBAQSdKlr+uAyF0GI4GtPfMCD12Y4cIdpKC9l0RjNTH/P9isFypSqqewMPm7//fnZlNA== dependencies: semver "^5.3.0" babel-plugin-debug-macros@^0.2.0-beta.6: version "0.2.0-beta.6" resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0-beta.6.tgz#ecdf6e408d5c863ab21740d7ad7f43f027d2f912" - integrity sha1-7N9uQI1chjqyF0DXrX9D8CfS+RI= dependencies: semver "^5.3.0" babel-plugin-ember-modules-api-polyfill@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.3.2.tgz#56ea34bea963498d070a2b7dc2ce18a92c434093" - integrity sha512-mi9gaYasj2Bd6FYD1XCvuU1RL3n4DPn+VdOORyC2nqrvK50cLHkPaq/NdsqfxtZ0WNCIigrwnTHXU3XZI80tPg== dependencies: ember-rfc176-data "^0.3.0" babel-plugin-ember-modules-api-polyfill@^2.5.0: version "2.5.0" resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.5.0.tgz#860aab9fecbf38c10d1fe0779c6979a854fff154" - integrity sha512-o1rOgWFHR0IRBjC9Dvqc2V4MKE2UvdMv/fD/c5GUMAkS6DlTjQV54iMH9sdQ3TGfXPukPKBIOpoSoH/hdfGiMg== dependencies: ember-rfc176-data "^0.3.5" babel-plugin-feature-flags@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" - integrity sha1-nIJ8+aTrmhn3JcyyOehcqwIDb8E= babel-plugin-filter-imports@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/babel-plugin-filter-imports/-/babel-plugin-filter-imports-2.0.3.tgz#21f2773d0d74558986dd7af89f6f753d5fa92da3" - integrity sha512-s2vbul45NHOI665jcJvvIdzZLMIKgUdhofGEbxXn7GxfEB6SePCUbj2qBPjV9oqHuYBQucih/tRhO/GJu8mPkg== dependencies: "@babel/types" "^7.0.0" lodash "^4.17.11" @@ -1601,12 +1389,10 @@ babel-plugin-filter-imports@^2.0.3: babel-plugin-htmlbars-inline-precompile@^0.2.5: version "0.2.6" resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.6.tgz#c00b8a3f4b32ca04bf0f0d5169fcef3b5a66d69d" - integrity sha512-H4H75TKGUFij8ukwEYWEERAgrUf16R8NSK1uDPe3QwxT8mnE1K8+/s6DVjUqbM5Pv6lSIcE4XufXdlSX+DTB6g== babel-plugin-module-resolver@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.1.1.tgz#881cf67e3d4b8400d5eaaefc1be44d2dc1fe404f" - integrity sha512-1Q77Al4ydp6nYApJ7sQ2fmgz30WuQgJZegIYuyOdbdpxenB/bSezQ3hDPsumIXGlUS4vUIv+EwFjzzXZNWtARw== dependencies: find-babel-config "^1.1.0" glob "^7.1.2" @@ -1617,32 +1403,26 @@ babel-plugin-module-resolver@^3.1.1: babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" - integrity sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU= babel-plugin-syntax-class-properties@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" - integrity sha1-1+sjt5oxf4VDlixQW4J8fWysJ94= babel-plugin-syntax-decorators@^6.1.18: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" - integrity sha1-MSVjtNvePMgGzuPkFszurd0RrAs= babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" - integrity sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4= babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" - integrity sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM= babel-plugin-transform-async-to-generator@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" - integrity sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E= dependencies: babel-helper-remap-async-to-generator "^6.24.1" babel-plugin-syntax-async-functions "^6.8.0" @@ -1651,7 +1431,6 @@ babel-plugin-transform-async-to-generator@^6.22.0: babel-plugin-transform-class-properties@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" - integrity sha1-anl2PqYdM9NvN7YRqp3vgagbRqw= dependencies: babel-helper-function-name "^6.24.1" babel-plugin-syntax-class-properties "^6.8.0" @@ -1661,7 +1440,6 @@ babel-plugin-transform-class-properties@^6.24.1: babel-plugin-transform-decorators-legacy@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.5.tgz#0e492dffa0edd70529072887f8aa86d4dd8b40a1" - integrity sha512-jYHwjzRXRelYQ1uGm353zNzf3QmtdCfvJbuYTZ4gKveK7M9H1fs3a5AKdY1JUDl0z97E30ukORW1dzhWvsabtA== dependencies: babel-plugin-syntax-decorators "^6.1.18" babel-runtime "^6.2.0" @@ -1670,21 +1448,18 @@ babel-plugin-transform-decorators-legacy@^1.3.4: babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" - integrity sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" - integrity sha1-u8UbSflk1wy42OC5ToICRs46YUE= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoping@^6.23.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" - integrity sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8= dependencies: babel-runtime "^6.26.0" babel-template "^6.26.0" @@ -1695,7 +1470,6 @@ babel-plugin-transform-es2015-block-scoping@^6.23.0: babel-plugin-transform-es2015-classes@^6.23.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" - integrity sha1-WkxYpQyclGHlZLSyo7+ryXolhNs= dependencies: babel-helper-define-map "^6.24.1" babel-helper-function-name "^6.24.1" @@ -1710,7 +1484,6 @@ babel-plugin-transform-es2015-classes@^6.23.0: babel-plugin-transform-es2015-computed-properties@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" - integrity sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM= dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" @@ -1718,14 +1491,12 @@ babel-plugin-transform-es2015-computed-properties@^6.22.0: babel-plugin-transform-es2015-destructuring@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" - integrity sha1-mXux8auWf2gtKwh2/jWNYOdlxW0= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-duplicate-keys@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" - integrity sha1-c+s9MQypaePvnskcU3QabxV2Qj4= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -1733,14 +1504,12 @@ babel-plugin-transform-es2015-duplicate-keys@^6.22.0: babel-plugin-transform-es2015-for-of@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" - integrity sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-function-name@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" - integrity sha1-g0yJhTvDaxrw86TF26qU/Y6sqos= dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" @@ -1749,14 +1518,12 @@ babel-plugin-transform-es2015-function-name@^6.22.0: babel-plugin-transform-es2015-literals@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" - integrity sha1-T1SgLWzWbPkVKAAZox0xklN3yi4= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" - integrity sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ= dependencies: babel-plugin-transform-es2015-modules-commonjs "^6.24.1" babel-runtime "^6.22.0" @@ -1765,7 +1532,6 @@ babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015 babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: version "6.26.2" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" - integrity sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q== dependencies: babel-plugin-transform-strict-mode "^6.24.1" babel-runtime "^6.26.0" @@ -1775,7 +1541,6 @@ babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-e babel-plugin-transform-es2015-modules-systemjs@^6.23.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" - integrity sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM= dependencies: babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" @@ -1784,7 +1549,6 @@ babel-plugin-transform-es2015-modules-systemjs@^6.23.0: babel-plugin-transform-es2015-modules-umd@^6.23.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" - integrity sha1-rJl+YoXNGO1hdq22B9YCNErThGg= dependencies: babel-plugin-transform-es2015-modules-amd "^6.24.1" babel-runtime "^6.22.0" @@ -1793,7 +1557,6 @@ babel-plugin-transform-es2015-modules-umd@^6.23.0: babel-plugin-transform-es2015-object-super@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" - integrity sha1-JM72muIcuDp/hgPa0CH1cusnj40= dependencies: babel-helper-replace-supers "^6.24.1" babel-runtime "^6.22.0" @@ -1801,7 +1564,6 @@ babel-plugin-transform-es2015-object-super@^6.22.0: babel-plugin-transform-es2015-parameters@^6.23.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" - integrity sha1-V6w1GrScrxSpfNE7CfZv3wpiXys= dependencies: babel-helper-call-delegate "^6.24.1" babel-helper-get-function-arity "^6.24.1" @@ -1813,7 +1575,6 @@ babel-plugin-transform-es2015-parameters@^6.23.0: babel-plugin-transform-es2015-shorthand-properties@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" - integrity sha1-JPh11nIch2YbvZmkYi5R8U3jiqA= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -1821,14 +1582,12 @@ babel-plugin-transform-es2015-shorthand-properties@^6.22.0: babel-plugin-transform-es2015-spread@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" - integrity sha1-1taKmfia7cRTbIGlQujdnxdG+NE= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-sticky-regex@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" - integrity sha1-AMHNsaynERLN8M9hJsLta0V8zbw= dependencies: babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" @@ -1837,21 +1596,18 @@ babel-plugin-transform-es2015-sticky-regex@^6.22.0: babel-plugin-transform-es2015-template-literals@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" - integrity sha1-qEs0UPfp+PH2g51taH2oS7EjbY0= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-typeof-symbol@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" - integrity sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I= dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-unicode-regex@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" - integrity sha1-04sS9C6nMj9yk4fxinxa4frrNek= dependencies: babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" @@ -1860,7 +1616,6 @@ babel-plugin-transform-es2015-unicode-regex@^6.22.0: babel-plugin-transform-exponentiation-operator@^6.22.0: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" - integrity sha1-KrDJx/MJj6SJB3cruBP+QejeOg4= dependencies: babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" babel-plugin-syntax-exponentiation-operator "^6.8.0" @@ -1869,14 +1624,12 @@ babel-plugin-transform-exponentiation-operator@^6.22.0: babel-plugin-transform-regenerator@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" - integrity sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8= dependencies: regenerator-transform "^0.10.0" babel-plugin-transform-strict-mode@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" - integrity sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g= dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" @@ -1884,7 +1637,6 @@ babel-plugin-transform-strict-mode@^6.24.1: babel-polyfill@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" - integrity sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM= dependencies: babel-runtime "^6.26.0" core-js "^2.5.0" @@ -1893,7 +1645,6 @@ babel-polyfill@^6.26.0: babel-preset-env@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" - integrity sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg== dependencies: babel-plugin-check-es2015-constants "^6.22.0" babel-plugin-syntax-trailing-function-commas "^6.22.0" @@ -1929,7 +1680,6 @@ babel-preset-env@^1.7.0: babel-register@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" - integrity sha1-btAhFz4vy0htestFxgCahW9kcHE= dependencies: babel-core "^6.26.0" babel-runtime "^6.26.0" @@ -1942,7 +1692,6 @@ babel-register@^6.26.0: babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= dependencies: core-js "^2.4.0" regenerator-runtime "^0.11.0" @@ -1950,7 +1699,6 @@ babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtim babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" - integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= dependencies: babel-runtime "^6.26.0" babel-traverse "^6.26.0" @@ -1961,7 +1709,6 @@ babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= dependencies: babel-code-frame "^6.26.0" babel-messages "^6.23.0" @@ -1976,7 +1723,6 @@ babel-traverse@^6.24.1, babel-traverse@^6.26.0: babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= dependencies: babel-runtime "^6.26.0" esutils "^2.0.2" @@ -1986,54 +1732,44 @@ babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: babel6-plugin-strip-class-callcheck@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" - integrity sha1-3oQcGr6705943gr/ssmlLuIo/d8= babel6-plugin-strip-heimdall@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" - integrity sha1-NfgO3ewff//cAJgR371G2ZZQcrY= babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== backbone@^1.1.2: version "1.3.3" resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" - integrity sha1-TMgOp8sWMaxHSInOQPL4vGg7KZk= dependencies: underscore ">=1.8.3" backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" - integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= base64-arraybuffer@0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" - integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= base64-js@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.2.tgz#024f0f72afa25b75f9c0ee73cd4f55ec1bed9784" - integrity sha1-Ak8Pcq+iW3X5wO5zzU9V7Bvtl4Q= base64id@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" - integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY= base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== dependencies: cache-base "^1.0.1" class-utils "^0.3.5" @@ -2046,62 +1782,52 @@ base@^0.11.1: basic-auth@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.0.tgz#015db3f353e02e56377755f962742e8981e7bbba" - integrity sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o= dependencies: safe-buffer "5.1.1" bcrypt-pbkdf@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= dependencies: tweetnacl "^0.14.3" better-assert@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" - integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI= dependencies: callsite "1.0.0" "binaryextensions@1 || 2": version "2.1.1" resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" - integrity sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA== bl@~1.0.0: version "1.0.3" resolved "http://registry.npmjs.org/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e" - integrity sha1-/FQhoo/UImA2w7OJGmaiW8ZNIm4= dependencies: readable-stream "~2.0.5" blank-object@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" - integrity sha1-+ZB5P76ajI3QE/syGUIL7IHV9Lk= blob@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" - integrity sha1-vPEwUspURj8w+fx+lbmkdjCpSSE= block-stream@*: version "0.0.9" resolved "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= dependencies: inherits "~2.0.0" bluebird@^3.1.1, bluebird@^3.4.6: version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" - integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA== body-parser@1.18.2: version "1.18.2" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" - integrity sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ= dependencies: bytes "3.0.0" content-type "~1.0.4" @@ -2117,7 +1843,6 @@ body-parser@1.18.2: body-parser@1.18.3: version "1.18.3" resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" - integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= dependencies: bytes "3.0.0" content-type "~1.0.4" @@ -2133,7 +1858,6 @@ body-parser@1.18.3: body@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" - integrity sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk= dependencies: continuable-cache "^0.3.1" error "^7.0.0" @@ -2143,21 +1867,18 @@ body@^5.1.0: boom@0.4.x: version "0.4.2" resolved "https://registry.yarnpkg.com/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" - integrity sha1-emNune1O/O+xnO9JR6PGffrukRs= dependencies: hoek "0.9.x" boom@2.x.x: version "2.10.1" resolved "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - integrity sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8= dependencies: hoek "2.x.x" bops@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/bops/-/bops-0.0.3.tgz#c5cbf6fea8be7401ca5ea6d1679e6c4e8b407c79" - integrity sha1-xcv2/qi+dAHKXqbRZ55sTotAfHk= dependencies: base64-js "0.0.2" to-utf8 "0.0.1" @@ -2165,7 +1886,6 @@ bops@0.0.3: bower-config@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc" - integrity sha1-hf2d82fCuNu9DKpMXyutQM2Ewsw= dependencies: graceful-fs "^4.1.3" mout "^1.0.0" @@ -2176,12 +1896,10 @@ bower-config@^1.3.0: bower-endpoint-parser@0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" - integrity sha1-ALVlrb+rby01rd3pd+l5Yqy8s/Y= brace-expansion@^1.0.0, brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" @@ -2189,7 +1907,6 @@ brace-expansion@^1.0.0, brace-expansion@^1.1.7: braces@^1.8.2: version "1.8.5" resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= dependencies: expand-range "^1.8.1" preserve "^0.2.0" @@ -2198,7 +1915,6 @@ braces@^1.8.2: braces@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: arr-flatten "^1.1.0" array-unique "^0.3.2" @@ -2214,7 +1930,6 @@ braces@^2.3.1: broccoli-amd-funnel@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/broccoli-amd-funnel/-/broccoli-amd-funnel-2.0.1.tgz#dbdbfd28841731342d538126567c25bea3f15310" - integrity sha512-VRE+0PYAN4jQfkIq3GKRj4U/4UV9rVpLan5ll6fVYV4ziVg4OEfR5GUnILEg++QtR4xSaugRxCPU5XJLDy3bNQ== dependencies: broccoli-plugin "^1.3.0" symlink-or-copy "^1.2.0" @@ -2222,7 +1937,6 @@ broccoli-amd-funnel@^2.0.1: broccoli-babel-transpiler@^6.4.5: version "6.4.5" resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.4.5.tgz#caab4a3b18d2a819fdd56e1ac3a37e8164ad4272" - integrity sha512-HY5KrCdPR8Y86HE8xElmy3ERJpOVzINDR8vgQN2niy++gMERKKOZ3UyFF+cB6ne1ykZ8EYm7yc7yiRGWP341jA== dependencies: babel-core "^6.26.0" broccoli-funnel "^2.0.1" @@ -2238,7 +1952,6 @@ broccoli-babel-transpiler@^6.4.5: broccoli-babel-transpiler@^6.5.0: version "6.5.0" resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.5.0.tgz#aa501a227b298a99742fdd0309b1eaad7124bba0" - integrity sha512-c5OLGY40Sdmv6rP230Jt8yoK49BHfOw1LXiDMu9EC9k2U6sqlpNRK78SzvByQ8IzKtBYUfeWCxeZHcvW+gH7VQ== dependencies: babel-core "^6.26.0" broccoli-funnel "^2.0.1" @@ -2254,7 +1967,6 @@ broccoli-babel-transpiler@^6.5.0: broccoli-babel-transpiler@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.0.0.tgz#bc9d0e93d70d9515b799144b54b0b958e88b6f19" - integrity sha512-EvuExT9MYCW7ulpWdO8+7xLuQYlBNBvjXF5GXrX93aor25eGVCb+xDZe+KWEcd77QMYwnYCezXvF01JRlagBrg== dependencies: "@babel/core" "^7.0.0" broccoli-funnel "^2.0.1" @@ -2270,7 +1982,6 @@ broccoli-babel-transpiler@^7.0.0: broccoli-builder@^0.18.14: version "0.18.14" resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.14.tgz#4b79e2f844de11a4e1b816c3f49c6df4776c312d" - integrity sha1-S3ni+ETeEaThuBbD9Jxt9HdsMS0= dependencies: broccoli-node-info "^1.1.0" heimdalljs "^0.2.0" @@ -2283,7 +1994,6 @@ broccoli-builder@^0.18.14: broccoli-caching-writer@^2.2.0: version "2.3.1" resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" - integrity sha1-uTz1j5Jk8AMHWGjbBXdPTn8lvQc= dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" @@ -2295,7 +2005,6 @@ broccoli-caching-writer@^2.2.0: broccoli-caching-writer@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" - integrity sha1-C9LJapc41qarWQ8HujXFFX19tHY= dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.1" @@ -2307,7 +2016,6 @@ broccoli-caching-writer@^3.0.3: broccoli-caching-writer@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" - integrity sha1-2ZXX0ZdykuSY943wWIcjD8tKXiw= dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" @@ -2321,7 +2029,6 @@ broccoli-caching-writer@~2.0.4: broccoli-clean-css@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" - integrity sha1-nbFD2a9+CuecJuOsWpuy1yDqGfo= dependencies: broccoli-persistent-filter "^1.1.6" clean-css-promise "^0.1.0" @@ -2331,7 +2038,6 @@ broccoli-clean-css@^1.1.0: broccoli-concat@^3.5.1, broccoli-concat@^3.7.3: version "3.7.3" resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-3.7.3.tgz#0dca01311567ffb13180e6b4eb111824628e4885" - integrity sha512-2Ma9h81EJ0PRb9n4sW0i8KZlcnpTQfKxcj87zvi5DFe1fd8CTDEdseHDotK2beuA2l+LbgVPfd8EHaBJKm/Y8g== dependencies: broccoli-debug "^0.6.5" broccoli-kitchen-sink-helpers "^0.3.1" @@ -2349,14 +2055,12 @@ broccoli-concat@^3.5.1, broccoli-concat@^3.7.3: broccoli-config-loader@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/broccoli-config-loader/-/broccoli-config-loader-1.0.1.tgz#d10aaf8ebc0cb45c1da5baa82720e1d88d28c80a" - integrity sha512-MDKYQ50rxhn+g17DYdfzfEM9DjTuSGu42Db37A8TQHQe8geYEcUZ4SQqZRgzdAI3aRQNlA1yBHJfOeGmOjhLIg== dependencies: broccoli-caching-writer "^3.0.3" broccoli-config-replace@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" - integrity sha1-bqh52SpbrWNNETKbUfxfSq/anAA= dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.0" @@ -2366,7 +2070,6 @@ broccoli-config-replace@^1.1.2: broccoli-debug@^0.6.1, broccoli-debug@^0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/broccoli-debug/-/broccoli-debug-0.6.4.tgz#986eb3d2005e00e3bb91f9d0a10ab137210cd150" - integrity sha512-CixMUndBqTljCc26i6ubhBrGbAWXpWBsGJFce6ZOr76Tul2Ev1xxM0tmf7OjSzdYhkr5BrPd/CNbR9VMPi+NBg== dependencies: broccoli-plugin "^1.2.1" fs-tree-diff "^0.5.2" @@ -2378,7 +2081,6 @@ broccoli-debug@^0.6.1, broccoli-debug@^0.6.4: broccoli-debug@^0.6.5: version "0.6.5" resolved "https://registry.npmjs.org/broccoli-debug/-/broccoli-debug-0.6.5.tgz#164a5cdafd8936e525e702bf8f91f39d758e2e78" - integrity sha512-RIVjHvNar9EMCLDW/FggxFRXqpjhncM/3qq87bn/y+/zR9tqEkHvTqbyOc4QnB97NO2m6342w4wGkemkaeOuWg== dependencies: broccoli-plugin "^1.2.1" fs-tree-diff "^0.5.2" @@ -2390,7 +2092,6 @@ broccoli-debug@^0.6.5: broccoli-file-creator@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-1.2.0.tgz#27f1b25b1b00e7bb7bf3d5d7abed5f4d5388df4d" - integrity sha512-l9zthHg6bAtnOfRr/ieZ1srRQEsufMZID7xGYRW3aBDv3u/3Eux+Iawl10tAGYE5pL9YB4n5X4vxkp6iNOoZ9g== dependencies: broccoli-plugin "^1.1.0" mkdirp "^0.5.1" @@ -2398,7 +2099,6 @@ broccoli-file-creator@^1.1.1: broccoli-file-creator@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-2.1.1.tgz#7351dd2496c762cfce7736ce9b49e3fce0c7b7db" - integrity sha512-YpjOExWr92C5vhnK0kmD81kM7U09kdIRZk9w4ZDCDHuHXW+VE/x6AGEOQQW3loBQQ6Jk+k+TSm8dESy4uZsnjw== dependencies: broccoli-plugin "^1.1.0" mkdirp "^0.5.1" @@ -2406,7 +2106,6 @@ broccoli-file-creator@^2.1.1: broccoli-filter@^1.0.1: version "1.3.0" resolved "https://registry.yarnpkg.com/broccoli-filter/-/broccoli-filter-1.3.0.tgz#71e3a8e32a17f309e12261919c5b1006d6766de6" - integrity sha512-VXJXw7eBfG82CFxaBDjYmyN7V72D4In2zwLVQJd/h3mBfF3CMdRTsv2L20lmRTtCv1sAHcB+LgMso90e/KYiLw== dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.0.0" @@ -2421,12 +2120,10 @@ broccoli-filter@^1.0.1: broccoli-funnel-reducer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" - integrity sha1-ETZbKnha7JsXlyo234fu8kxcwOo= broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1: version "1.2.0" resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" - integrity sha1-zdw6/F/xaFqAI0iP/3TOb7WlEpY= dependencies: array-equal "^1.0.0" blank-object "^1.0.1" @@ -2446,7 +2143,6 @@ broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1: broccoli-funnel@^2.0.0, broccoli-funnel@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-2.0.1.tgz#6823c73b675ef78fffa7ab800f083e768b51d449" - integrity sha512-C8Lnp9TVsSSiZMGEF16C0dCiNg2oJqUKwuZ1K4kVC6qRPG/2Cj/rtB5kRCC9qEbwqhX71bDbfHROx0L3J7zXQg== dependencies: array-equal "^1.0.0" blank-object "^1.0.1" @@ -2465,7 +2161,6 @@ broccoli-funnel@^2.0.0, broccoli-funnel@^2.0.1: broccoli-kitchen-sink-helpers@^0.2.5: version "0.2.9" resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" - integrity sha1-peCYbtjXb7WYS2jD8EUNOpbjbsw= dependencies: glob "^5.0.10" mkdirp "^0.5.1" @@ -2473,7 +2168,6 @@ broccoli-kitchen-sink-helpers@^0.2.5: broccoli-kitchen-sink-helpers@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" - integrity sha1-d8fBgZS5ZkFj7E/O4nk0RJJuDAY= dependencies: glob "^5.0.10" mkdirp "^0.5.1" @@ -2481,7 +2175,6 @@ broccoli-kitchen-sink-helpers@^0.3.1: broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.1: version "1.2.4" resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" - integrity sha1-oAFRm7UGfwZYnZGvopQkRaLQ/bU= dependencies: broccoli-plugin "^1.3.0" can-symlink "^1.0.0" @@ -2495,7 +2188,6 @@ broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.1: broccoli-merge-trees@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-2.0.0.tgz#10aea46dd5cebcc8b8f7d5a54f0a84a4f0bb90b9" - integrity sha1-EK6kbdXOvMi499WlTwqEpPC7kLk= dependencies: broccoli-plugin "^1.3.0" merge-trees "^1.0.1" @@ -2503,7 +2195,6 @@ broccoli-merge-trees@^2.0.0: broccoli-merge-trees@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-3.0.0.tgz#90e4959f9e3c57cf1f04fab35152f3d849468d8b" - integrity sha512-yyk4J3KSeohlzsmVaRx7ZgAq57K2wzyVtGDaARLG/WuTNlRjKeYEW+atxblvrf0zAOsYMOi8YCpMLRBQUa9jjg== dependencies: broccoli-plugin "^1.3.0" merge-trees "^2.0.0" @@ -2511,7 +2202,6 @@ broccoli-merge-trees@^3.0.0: broccoli-merge-trees@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-3.0.1.tgz#545dfe9f695cec43372b3ee7e63c7203713ea554" - integrity sha512-EFPBLbCoyCLdjJx0lxn+acWXK/GAZesXokS4OsF7HuB+WdnV76HVJPdfwp9TaXaUkrtb7eU+ymh9tY9wOGQjMQ== dependencies: broccoli-plugin "^1.3.0" merge-trees "^2.0.0" @@ -2519,7 +2209,6 @@ broccoli-merge-trees@^3.0.1: broccoli-middleware@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/broccoli-middleware/-/broccoli-middleware-2.0.1.tgz#093314f13e52fad7fa8c4254a4e4a4560c857a65" - integrity sha512-V/K5uozcEH/XJ09ZAL8aJt/W2UwJU8I8fA2FAg3u9gzs5dQrehHDtgSoKS2QjPjurRC1GSiYLcsMp36sezaQQg== dependencies: handlebars "^4.0.4" mime-types "^2.1.18" @@ -2527,7 +2216,6 @@ broccoli-middleware@^2.0.1: broccoli-module-normalizer@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/broccoli-module-normalizer/-/broccoli-module-normalizer-1.3.0.tgz#f9982d9cbb776b4ed754161cc6547784d3eb19de" - integrity sha512-0idZCOtdVG6xXoQ36Psc1ApMCr3lW5DB+WEAOEwHcUoESIBHzwcRPQTxheGIjZ5o0hxpsRYAUH5x0ErtNezbrQ== dependencies: broccoli-plugin "^1.3.0" merge-trees "^1.0.1" @@ -2537,7 +2225,6 @@ broccoli-module-normalizer@^1.3.0: broccoli-module-unification-reexporter@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/broccoli-module-unification-reexporter/-/broccoli-module-unification-reexporter-1.0.0.tgz#031909c5d3f159ec11d5f9e2346f2861db8acb3e" - integrity sha512-HTi9ua520M20aBZomaiBopsSt3yjL7J/paR3XPjieygK7+ShATBiZdn0B+ZPiniBi4I8JuMn1q0fNFUevtP//A== dependencies: broccoli-plugin "^1.3.0" mkdirp "^0.5.1" @@ -2546,12 +2233,10 @@ broccoli-module-unification-reexporter@^1.0.0: broccoli-node-info@1.1.0, broccoli-node-info@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" - integrity sha1-OqLjHgflvbUW3SUhT3xFuhxFlBI= broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz#3511bc52fc53740cda51621f58a28152d9911bc1" - integrity sha512-JwNLDvvXJlhUmr+CHcbVhCyp33NbCIAITjQZmJY9e8QzANXh3jpFWlhSFvkWghwKA8rTAKcXkW12agtiZjxr4g== dependencies: async-disk-cache "^1.2.1" async-promise-queue "^1.0.3" @@ -2570,7 +2255,6 @@ broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-p broccoli-plugin@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" - integrity sha1-c+LPoF+OoeP8FCDEDD2efcckvwI= dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -2580,7 +2264,6 @@ broccoli-plugin@1.1.0: broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" - integrity sha1-vucEqOQtoIy1jlE6qkNu+38O8e4= dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -2590,7 +2273,6 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli broccoli-rollup@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/broccoli-rollup/-/broccoli-rollup-2.1.1.tgz#0b77dc4b7560a53e998ea85f3b56772612d4988d" - integrity sha512-aky/Ovg5DbsrsJEx2QCXxHLA6ZR+9u1TNVTf85soP4gL8CjGGKQ/JU8R3BZ2ntkWzo6/83RCKzX6O+nlNKR5MQ== dependencies: "@types/node" "^9.6.0" amd-name-resolver "^1.2.0" @@ -2607,19 +2289,16 @@ broccoli-rollup@^2.1.1: broccoli-slow-trees@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" - integrity sha1-m/Kp4vjrPtOj8qvd6YjaQ3zNybQ= dependencies: heimdalljs "^0.2.1" broccoli-source@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" - integrity sha1-VPDoLItz9GWAy7xPV48LMvyo+Ak= broccoli-sri-hash@^2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" - integrity sha1-vGmQXtejga0yXMDQLe0HEyjr8/M= dependencies: broccoli-caching-writer "^2.2.0" mkdirp "^0.5.1" @@ -2630,7 +2309,6 @@ broccoli-sri-hash@^2.1.0: broccoli-stew@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-2.0.0.tgz#68f3d94f13b4a79aa15d582703574fb4c3215e50" - integrity sha512-9dtyFlWEYHI36e4wXNTo6JReCaCssx+Jq1GpkTQZaJA/2buJn+HeGzguoYPdR2VKNb3vX13fpWJFQP0TAwa7WA== dependencies: broccoli-debug "^0.6.1" broccoli-funnel "^2.0.0" @@ -2650,7 +2328,6 @@ broccoli-stew@^2.0.0: broccoli-string-replace@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" - integrity sha1-HtkvhWgK+NUDAjkl51Tk4zZ2uR8= dependencies: broccoli-persistent-filter "^1.1.5" minimatch "^3.0.3" @@ -2658,7 +2335,6 @@ broccoli-string-replace@^0.1.2: broccoli-test-helper@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/broccoli-test-helper/-/broccoli-test-helper-2.0.0.tgz#1cfbb76f7e856ad8df96d55ee2f5e0dddddf5d4f" - integrity sha512-TKwh8dBT+RcxKEG+vAoaRRhZsCMwZIHPZbCzBNCA0nUi1aoFB/LVosqwMC6H9Ipe06FxY5hpQxDLFbnBMdUPsA== dependencies: "@types/tmp" "^0.0.33" broccoli "^2.0.0" @@ -2670,7 +2346,6 @@ broccoli-test-helper@^2.0.0: broccoli-uglify-sourcemap@^2.1.1, broccoli-uglify-sourcemap@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-2.2.0.tgz#2ff49389bdf342a550c3596750ba2dde95a8f7d4" - integrity sha1-L/STib3zQqVQw1lnULot3pWo99Q= dependencies: async-promise-queue "^1.0.4" broccoli-plugin "^1.2.1" @@ -2687,7 +2362,6 @@ broccoli-uglify-sourcemap@^2.1.1, broccoli-uglify-sourcemap@^2.2.0: broccoli@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/broccoli/-/broccoli-2.0.0.tgz#7b95d6173865184697e4dab9f477591057b9410e" - integrity sha512-gCS1/nXaJpATboLpNeTPOgdqSSEauJ6bUS4+fNKNsf/m7CIxOS9MclT7DNn3VI9DARiGZxFi6hZmIEF1mD04eA== dependencies: broccoli-node-info "1.1.0" broccoli-slow-trees "^3.0.1" @@ -2711,12 +2385,10 @@ broccoli@^2.0.0: browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== browserslist@^3.2.6: version "3.2.8" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" - integrity sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ== dependencies: caniuse-lite "^1.0.30000844" electron-to-chromium "^1.3.47" @@ -2724,7 +2396,6 @@ browserslist@^3.2.6: browserslist@^4.1.0: version "4.3.3" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.3.3.tgz#88a7d9ce2e5db561e160ab660bc59cb406a0c41d" - integrity sha512-6h84UD1mmHeuQ9IucX6yzBc+KBYcBBTLYt2CXtY7GYCra6iE5kOm7oM+zuGw/0tjGtbJxjm58OvxSBmogEMCRQ== dependencies: caniuse-lite "^1.0.30000898" electron-to-chromium "^1.3.81" @@ -2733,19 +2404,16 @@ browserslist@^4.1.0: bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" - integrity sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk= dependencies: node-int64 "^0.4.0" buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== buffer-alloc@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== dependencies: buffer-alloc-unsafe "^1.1.0" buffer-fill "^1.0.0" @@ -2753,42 +2421,34 @@ buffer-alloc@^1.2.0: buffer-fill@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= buffer-from@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" - integrity sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ== builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= builtins@0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/builtins/-/builtins-0.0.7.tgz#355219cd6cf18dbe7c01cc7fd2dce765cfdc549a" - integrity sha1-NVIZzWzxjb58Acx/0tznZc/cVJo= builtins@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" - integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= bytes@1: version "1.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" - integrity sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g= bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== dependencies: collection-visit "^1.0.0" component-emitter "^1.2.1" @@ -2803,7 +2463,6 @@ cache-base@^1.0.1: cacheable-request@^2.1.1: version "2.1.4" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" - integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= dependencies: clone-response "1.0.2" get-stream "3.0.0" @@ -2816,31 +2475,26 @@ cacheable-request@^2.1.1: calculate-cache-key-for-tree@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" - integrity sha1-DD5CycE088neU1jA8WeTYn6pdtY= dependencies: json-stable-stringify "^1.0.1" caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8= dependencies: callsites "^0.2.0" callsite@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" - integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= callsites@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" - integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo= camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= dependencies: camelcase "^2.0.0" map-obj "^1.0.0" @@ -2848,46 +2502,38 @@ camelcase-keys@^2.0.0: camelcase@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" - integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk= camelcase@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= can-symlink@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" - integrity sha1-l7YH2KhLtsbiKLkC2GTstZS50hk= dependencies: tmp "0.0.28" caniuse-lite@^1.0.30000844: version "1.0.30000865" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000865.tgz#70026616e8afe6e1442f8bb4e1092987d81a2f25" - integrity sha512-vs79o1mOSKRGv/1pSkp4EXgl4ZviWeYReXw60XfacPU64uQWZwJT6vZNmxRF9O+6zu71sJwMxLK5JXxbzuVrLw== caniuse-lite@^1.0.30000898: version "1.0.30000899" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000899.tgz#6febdbbc388a7982f620ee0e3d09aab0c061389e" - integrity sha512-enC3zKfUCJxxwvUIsBkbHd54CtJw1KtIWvrK0JZxWD/fEN2knHaai45lndJ4xXAkyRAPyk60J3yagkKDWhfeMA== capture-exit@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" - integrity sha1-HF/MSJ/QqwDU8ax64QcuMXP7q28= dependencies: rsvp "^3.3.3" capture-stack-trace@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" - integrity sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0= cardinal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" - integrity sha1-UOIcGwqjdyn5N33vGWtanOyTLuk= dependencies: ansicolors "~0.2.1" redeyed "~1.0.0" @@ -2895,17 +2541,14 @@ cardinal@^1.0.0: caseless@~0.11.0: version "0.11.0" resolved "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" - integrity sha1-cVuW6phBWTzDMGeSP17GDr2k99c= caseless@~0.12.0: version "0.12.0" resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= center-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" - integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60= dependencies: align-text "^0.1.3" lazy-cache "^1.0.3" @@ -2913,28 +2556,24 @@ center-align@^0.1.1: chai-as-promised@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" - integrity sha1-GgKkM6byTa+sY7nJb6FoTbGqjaY= dependencies: check-error "^1.0.2" chai-as-promised@^7.0.0: version "7.1.1" resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" - integrity sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA== dependencies: check-error "^1.0.2" chai-files@^1.0.0, chai-files@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" - integrity sha1-DiVhD63FUbHq55wvTuefry+EIpY= dependencies: assertion-error "^1.0.1" chai@^3.3.0: version "3.5.0" resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" - integrity sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc= dependencies: assertion-error "^1.0.1" deep-eql "^0.1.3" @@ -2943,7 +2582,6 @@ chai@^3.3.0: chai@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c" - integrity sha1-D2RYS6ZC8PKs4oBiefTwbKI61zw= dependencies: assertion-error "^1.0.1" check-error "^1.0.1" @@ -2955,7 +2593,6 @@ chai@^4.1.0: chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -2966,7 +2603,6 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" - integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" @@ -2975,39 +2611,32 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4 chardet@^0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== charm@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" - integrity sha1-it02cVOm2aWBMxBSxAkJkdqZXjU= dependencies: inherits "^2.0.1" check-error@^1.0.1, check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= chownr@^1.0.1, chownr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" - integrity sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE= ci-info@^1.1.3: version "1.6.0" resolved "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" - integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" - integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== dependencies: arr-union "^3.1.0" define-property "^0.2.5" @@ -3017,12 +2646,10 @@ class-utils@^0.3.5: clean-base-url@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" - integrity sha1-yQHPCiC5ckNbDszVLQVoJKQ1G3s= clean-css-promise@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" - integrity sha1-Q/PSyN/LK/BxSBJSzZt2QzwI7ss= dependencies: array-to-error "^1.0.0" clean-css "^3.4.5" @@ -3031,7 +2658,6 @@ clean-css-promise@^0.1.0: clean-css@^3.4.5: version "3.4.28" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" - integrity sha1-vxlF6C/ICPVWlebd6uwBQA79A/8= dependencies: commander "2.8.x" source-map "0.4.x" @@ -3039,31 +2665,26 @@ clean-css@^3.4.5: clean-up-path@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clean-up-path/-/clean-up-path-1.0.0.tgz#de9e8196519912e749c9eaf67c13d64fac72a3e5" - integrity sha512-PHGlEF0Z6976qQyN6gM7kKH6EH0RdfZcc8V+QhFe36eRxV0SMH5OUBZG7Bxa9YcreNzyNbK63cGiZxdSZgosRw== cli-cursor@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - integrity sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc= dependencies: restore-cursor "^1.0.1" cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= dependencies: restore-cursor "^2.0.0" cli-spinners@^1.1.0: version "1.3.1" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" - integrity sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg== cli-table3@^0.5.1: version "0.5.1" resolved "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" - integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== dependencies: object-assign "^4.1.0" string-width "^2.1.1" @@ -3073,19 +2694,16 @@ cli-table3@^0.5.1: cli-table@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" - integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM= dependencies: colors "1.0.3" cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= cliui@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" - integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE= dependencies: center-align "^0.1.1" right-align "^0.1.1" @@ -3094,29 +2712,24 @@ cliui@^2.1.0: clone-response@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= dependencies: mimic-response "^1.0.0" clone@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= clone@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" - integrity sha1-0hfR6WERjjrJpLi7oyhVU79kfNs= clone@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= cmd-shim@~2.0.1: version "2.0.2" resolved "https://registry.npmjs.org/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb" - integrity sha1-b8vamUg6j9FdfTChlspp1oii79s= dependencies: graceful-fs "^4.1.2" mkdirp "~0.5.0" @@ -3124,17 +2737,14 @@ cmd-shim@~2.0.1: co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= dependencies: map-visit "^1.0.0" object-visit "^1.0.0" @@ -3142,29 +2752,24 @@ collection-visit@^1.0.0: color-convert@^1.9.0: version "1.9.2" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" - integrity sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg== dependencies: color-name "1.1.1" color-name@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" - integrity sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok= colors@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= colors@^1.1.2: version "1.3.1" resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.1.tgz#4accdb89cf2cabc7f982771925e9468784f32f3d" - integrity sha512-jg/vxRmv430jixZrC+La5kMbUWqIg32/JsYNZb94+JEmzceYbWKTsv1OuTp+7EaqiaWRR2tPcykibwCRgclIsw== columnify@~1.5.4: version "1.5.4" resolved "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" - integrity sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs= dependencies: strip-ansi "^3.0.0" wcwidth "^1.0.0" @@ -3172,80 +2777,66 @@ columnify@~1.5.4: combined-stream@^1.0.5, combined-stream@^1.0.6, combined-stream@~1.0.5, combined-stream@~1.0.6: version "1.0.7" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" - integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== dependencies: delayed-stream "~1.0.0" combined-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" - integrity sha1-ATfmV7qlp1QcV6w3rF/AfXO03B8= dependencies: delayed-stream "0.0.5" commander@2.12.2: version "2.12.2" resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" - integrity sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA== commander@2.15.1: version "2.15.1" resolved "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" - integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== commander@2.8.x: version "2.8.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" - integrity sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ= dependencies: graceful-readlink ">= 1.0.0" commander@^2.15.1, commander@^2.9.0: version "2.19.0" resolved "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" - integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== commander@^2.6.0, commander@~2.16.0: version "2.16.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" - integrity sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew== commander@~2.17.1: version "2.17.1" resolved "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" - integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== common-tags@^1.4.0, common-tags@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" - integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw== component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" - integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= component-emitter@1.2.1, component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" - integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= component-inherit@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" - integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= compressible@~2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7" - integrity sha1-MmxfUH+7BV9UEWeCuWmoG2einac= dependencies: mime-db ">= 1.34.0 < 2" compression@^1.7.3: version "1.7.3" resolved "https://registry.npmjs.org/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" - integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg== dependencies: accepts "~1.3.5" bytes "3.0.0" @@ -3258,12 +2849,10 @@ compression@^1.7.3: concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= concat-stream@^1.4.6, concat-stream@^1.4.7: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== dependencies: buffer-from "^1.0.0" inherits "^2.0.3" @@ -3273,7 +2862,6 @@ concat-stream@^1.4.6, concat-stream@^1.4.7: config-chain@~1.1.9: version "1.1.12" resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" - integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== dependencies: ini "^1.3.4" proto-list "~1.2.1" @@ -3281,7 +2869,6 @@ config-chain@~1.1.9: configstore@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz#5933311e95d3687efb592c528b922d9262d227e7" - integrity sha512-CmquAXFBocrzaSM8mtGPMM/HiWmyIpr4CcJl/rgY2uCObZ/S7cKU0silxslqJejl+t/T9HS8E0PUNQD81JGUEQ== dependencies: dot-prop "^4.1.0" graceful-fs "^4.1.2" @@ -3293,7 +2880,6 @@ configstore@^4.0.0: connect@^3.6.6: version "3.6.6" resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" - integrity sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ= dependencies: debug "2.6.9" finalhandler "1.1.0" @@ -3303,12 +2889,10 @@ connect@^3.6.6: console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= console-ui@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-2.2.2.tgz#b294a2934de869dd06789ab4be69555411edef29" - integrity sha1-spSik03oad0GeJq0vmlVVBHt7yk= dependencies: chalk "^2.1.0" inquirer "^2" @@ -3320,85 +2904,70 @@ console-ui@^2.2.2: consolidate@^0.15.1: version "0.15.1" resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7" - integrity sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw== dependencies: bluebird "^3.1.1" content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" - integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== continuable-cache@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" - integrity sha1-vXJ6f67XfnH/OYWskzUakSczrQ8= convert-source-map@^1.1.0: version "1.6.0" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" - integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== dependencies: safe-buffer "~5.1.1" convert-source-map@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" - integrity sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU= cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" - integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= copy-dereference@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" - integrity sha1-axMYZUIP2BtBO6mUtE02VTERUrY= copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.7: version "2.5.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" - integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw== core-object@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/core-object/-/core-object-3.1.5.tgz#fa627b87502adc98045e44678e9a8ec3b9c0d2a9" - integrity sha512-sA2/4+/PZ/KV6CKgjrVrrUVBKCkdDO02CUlQ0YKTQoYUwPYNOtOAcWlbYhd5v/1JqYaA6oZ4sDlOU4ppVw6Wbg== dependencies: chalk "^2.0.0" core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= create-error-class@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" - integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y= dependencies: capture-stack-trace "^1.0.0" cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= dependencies: lru-cache "^4.0.1" shebang-command "^1.2.0" @@ -3407,7 +2976,6 @@ cross-spawn@^5.0.1: cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== dependencies: nice-try "^1.0.4" path-key "^2.0.1" @@ -3418,138 +2986,116 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: cryptiles@0.2.x: version "0.2.2" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" - integrity sha1-7ZH/HxetE9N0gohZT4pIoNJvMlw= dependencies: boom "0.4.x" cryptiles@2.x.x: version "2.0.5" resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - integrity sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g= dependencies: boom "2.x.x" crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" - integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= ctype@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" - integrity sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8= currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= dependencies: array-find-index "^1.0.1" d@1: version "1.0.0" resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" - integrity sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8= dependencies: es5-ext "^0.10.9" dag-map@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" - integrity sha1-lxS0ct6CoYQ94vuptodpOMq0TGg= dashdash@^1.12.0: version "1.14.1" resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= dependencies: assert-plus "^1.0.0" date-time@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/date-time/-/date-time-2.1.0.tgz#0286d1b4c769633b3ca13e1e62558d2dbdc2eba2" - integrity sha512-/9+C44X7lot0IeiyfgJmETtRMhBidBYM2QFFIkGa0U1k+hSyY87Nw7PY3eDqpvCBm7I3WCSfPeZskW/YYq6m4g== dependencies: time-zone "^1.0.0" debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" debug@3.1.0, debug@^3.0.0, debug@^3.1.0, debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== dependencies: ms "2.0.0" debug@^4.0.1, debug@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" - integrity sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg== dependencies: ms "^2.1.1" debuglog@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" - integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= decamelize@^1.0.0, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= decompress-response@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= dependencies: mimic-response "^1.0.0" deep-eql@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" - integrity sha1-71WKyrjeJSBs1xOQbXTlaTDrafI= dependencies: type-detect "0.1.1" deep-eql@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== dependencies: type-detect "^4.0.0" deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= defaults@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= dependencies: clone "^1.0.2" define-properties@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" - integrity sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ= dependencies: foreach "^2.0.5" object-keys "^1.0.8" @@ -3557,21 +3103,18 @@ define-properties@^1.1.2: define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= dependencies: is-descriptor "^1.0.0" define-property@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== dependencies: is-descriptor "^1.0.2" isobject "^3.0.1" @@ -3579,7 +3122,6 @@ define-property@^2.0.2: del@^2.0.2: version "2.2.2" resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" - integrity sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag= dependencies: globby "^5.0.0" is-path-cwd "^1.0.0" @@ -3592,59 +3134,48 @@ del@^2.0.2: delayed-stream@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" - integrity sha1-1LH0OpPoKW3+AmlPRoC8N6MTxz8= delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= depd@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" - integrity sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k= depd@~1.1.1, depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= detect-file@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" - integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= detect-indent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg= dependencies: repeating "^2.0.0" detect-indent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" - integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= detect-libc@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= dezalgo@^1.0.0, dezalgo@^1.0.1, dezalgo@^1.0.2, dezalgo@~1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" - integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= dependencies: asap "^2.0.0" wrappy "1" @@ -3652,36 +3183,30 @@ dezalgo@^1.0.0, dezalgo@^1.0.1, dezalgo@^1.0.2, dezalgo@~1.0.3: diff@3.5.0, diff@^3.5.0: version "3.5.0" resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== dependencies: esutils "^2.0.2" dot-prop@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" - integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== dependencies: is-obj "^1.0.0" duplex@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/duplex/-/duplex-1.0.0.tgz#6abc5c16ec17e4c578578727126700590d3a2dda" - integrity sha1-arxcFuwX5MV4V4cnEmcAWQ06Ldo= duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= dependencies: jsbn "~0.1.0" safer-buffer "^2.1.0" @@ -3689,32 +3214,26 @@ ecc-jsbn@~0.1.1: editions@^1.1.1: version "1.3.4" resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" - integrity sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg== editor@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" - integrity sha1-YMf4e9YrzGqJT6jM1q+3gjok90I= ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= electron-to-chromium@^1.3.47: version "1.3.52" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz#d2d9f1270ba4a3b967b831c40ef71fb4d9ab5ce0" - integrity sha1-0tnxJwuko7lnuDHEDvcftNmrXOA= electron-to-chromium@^1.3.81: version "1.3.82" resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.82.tgz#7d13ae4437d2a783de3f4efba96b186c540b67b1" - integrity sha512-NI4nB2IWGcU4JVT1AE8kBb/dFor4zjLHMLsOROPahppeHrR0FG5uslxMmkp/thO1MvPjM2xhlKoY29/I60s0ew== ember-assign-polyfill@~2.4.0: version "2.4.0" resolved "https://registry.npmjs.org/ember-assign-polyfill/-/ember-assign-polyfill-2.4.0.tgz#acb00466f7d674b3e6b030acfe255b3b1f6472e1" - integrity sha512-0SnGQb9CenRqbZdIa1KFsEjT+1ijGWfAbCSaDbg5uVa5l6HPdppuTzOXK6sfEQMsd2nbrp27QWFy7W5VX6l4Ag== dependencies: ember-cli-babel "^6.6.0" ember-cli-version-checker "^2.0.0" @@ -3722,7 +3241,6 @@ ember-assign-polyfill@~2.4.0: ember-cli-app-version@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-3.2.0.tgz#7b9ad0e1b63ae0518648356ee24c703e922bc26e" - integrity sha512-fHWOJElSw8JL03FNCHrT0RdWhGpWEQ4VQ10unEwwhVZ+OANNcOLz8O2dA3D5iuB4bb0fMLwjEwYZGM62+TBs1Q== dependencies: ember-cli-babel "^6.12.0" git-repo-version "^1.0.2" @@ -3730,12 +3248,10 @@ ember-cli-app-version@^3.2.0: ember-cli-babel-plugin-helpers@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/ember-cli-babel-plugin-helpers/-/ember-cli-babel-plugin-helpers-1.0.2.tgz#d4bec0f32febc530e621ea8d66d3365727cb5e6c" - integrity sha512-tTWmHiIvadgtu0i+Zlb5Jnue69qO6dtACcddkRhhV+m9NfAr+2XNoTKRSeGL8QyRDhfWeo4rsK9dqPrU4PQ+8g== ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: version "6.16.0" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.16.0.tgz#623b4a2764ece72b65f1572fc8aeb5714a450228" - integrity sha512-rzWkVdKVk2KSbQ81TxmLli+LWdBEqF+FHE83rUQXVOV4FguJDtP1w2AW08f8QjuztbnQ5+VUGCb7H0dL8UwOVw== dependencies: amd-name-resolver "1.2.0" babel-plugin-debug-macros "^0.2.0-beta.6" @@ -3754,7 +3270,6 @@ ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-be ember-cli-babel@^7.1.2: version "7.1.2" resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-7.1.2.tgz#543c64368d6138d12656db1143c02df1f2b0ee9c" - integrity sha512-VEWn1jYlP0XYUNkMG4wHSpq4IPKO04lIuSwnH0elLwV3RcwbUstRExi3slmax+SjtlgjJTPMko8QvQ/Ul1/4rg== dependencies: "@babel/core" "^7.0.0" "@babel/plugin-transform-modules-amd" "^7.0.0" @@ -3776,7 +3291,6 @@ ember-cli-babel@^7.1.2: ember-cli-blueprint-test-helpers@^0.19.1: version "0.19.1" resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.19.1.tgz#26df9724a6cb48f7acfa391dec7ec772888b0929" - integrity sha512-lyfCvR5gxbNn5mJKfVAUj3Q5K1VyJo3miAaQ9zk2dL7ijs281C3j73WYyCK7tWBoBJ04jOzkb+YXV6jFwVpvsA== dependencies: chai "^4.1.0" chai-as-promised "^7.0.0" @@ -3790,7 +3304,6 @@ ember-cli-blueprint-test-helpers@^0.19.1: ember-cli-broccoli-sane-watcher@^2.1.1: version "2.2.2" resolved "https://registry.npmjs.org/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.2.2.tgz#9bb1b04ddeb2c086aecd8693cbaeca1d88dc160c" - integrity sha512-9OLy8x3pdNKC/6xR00IjTL8XyiQU3rb2HLyQSAqHuaZpZcSTKkbAse2ERTsELSINoo/zi/W7qPP5vd5SsHsraw== dependencies: broccoli-slow-trees "^3.0.1" heimdalljs "^0.2.1" @@ -3801,7 +3314,6 @@ ember-cli-broccoli-sane-watcher@^2.1.1: ember-cli-dependency-checker@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ember-cli-dependency-checker/-/ember-cli-dependency-checker-3.0.0.tgz#61245f5f79f881dece043303111d5f41efb8621f" - integrity sha512-Fq9PXFaZfpSHssJwt20cpHMT0AKHMKMBMGiz+Y8BsIvvY1ILaM5bzpUP8V6czm0RU5y7VxM+z7zTN9Cn1iotOA== dependencies: chalk "^2.3.0" find-yarn-workspace-root "^1.1.0" @@ -3812,12 +3324,10 @@ ember-cli-dependency-checker@^3.0.0: ember-cli-get-component-path-option@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" - integrity sha1-DXtZVVni+QUKvtgE8djv8bCLx3E= ember-cli-htmlbars-inline-precompile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.3.tgz#332ff96c06fc522965162f1090d78a615379c3c2" - integrity sha1-My/5bAb8UillFi8QkNeKYVN5w8I= dependencies: babel-plugin-htmlbars-inline-precompile "^0.2.5" ember-cli-version-checker "^2.1.2" @@ -3828,7 +3338,6 @@ ember-cli-htmlbars-inline-precompile@^1.0.0: ember-cli-htmlbars-inline-precompile@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.5.tgz#312e050c9e3dd301c55fb399fd706296cd0b1d6a" - integrity sha512-/CNEqPxroIcbY6qejrt704ZaghHLCntZKYLizFfJ2esirXoJx6fuYKBY1YyJ8GOgjfbHHKjBZuK4vFFJpkGqkQ== dependencies: babel-plugin-htmlbars-inline-precompile "^0.2.5" ember-cli-version-checker "^2.1.2" @@ -3839,7 +3348,6 @@ ember-cli-htmlbars-inline-precompile@^1.0.5: ember-cli-htmlbars@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-3.0.1.tgz#01e21f0fd05e0a6489154f26614b1041769e3e58" - integrity sha512-pyyB2s52vKTXDC5svU3IjU7GRLg2+5O81o9Ui0ZSiBS14US/bZl46H2dwcdSJAK+T+Za36ZkQM9eh1rNwOxfoA== dependencies: broccoli-persistent-filter "^1.4.3" hash-for-dep "^1.2.3" @@ -3849,7 +3357,6 @@ ember-cli-htmlbars@^3.0.1: ember-cli-inject-live-reload@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-2.0.1.tgz#1bf3a6ea1747bceddc9f62f7ca8575de6b53ddaf" - integrity sha512-vrW/3KSrku+Prqmp7ZkpCxYkabnLrTHDEvV9B1yphTP++dhiV7n7Dv9NrmyubkoF3Inm0xrbbhB5mScvvuTQSg== dependencies: clean-base-url "^1.0.0" ember-cli-version-checker "^2.1.2" @@ -3857,7 +3364,6 @@ ember-cli-inject-live-reload@^2.0.1: ember-cli-internal-test-helpers@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.9.1.tgz#d54a9124bb6408ceba83f049ba8479f4b96cdd19" - integrity sha1-1UqRJLtkCM66g/BJuoR59Lls3Rk= dependencies: chai "^3.3.0" chai-as-promised "^6.0.0" @@ -3875,34 +3381,28 @@ ember-cli-internal-test-helpers@^0.9.1: ember-cli-is-package-missing@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" - integrity sha1-bmGEyvuSY13ZPKbJRrEEKS1OM5A= ember-cli-lodash-subset@^1.0.7: version "1.0.12" resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" - integrity sha1-ry5366XcsNd/MwjTpv19NFD25Tc= ember-cli-lodash-subset@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-2.0.1.tgz#20cb68a790fe0fde2488ddfd8efbb7df6fe766f2" - integrity sha1-IMtop5D+D94kiN39jvu332/nZvI= ember-cli-normalize-entity-name@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" - integrity sha1-CxT3vLxZmqEXtf3cgeT9A8S61bc= dependencies: silent-error "^1.0.0" ember-cli-path-utils@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" - integrity sha1-Tjmvi1UwHN3FAXc5t3qAT7ogce0= ember-cli-preprocess-registry@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.2.tgz#083efb21fd922c021ceba9e08f4d9278249fc4db" - integrity sha512-YJfcDHMBEjtD505CIhM8dtu5FO2Ku+0OTs/0kdLlj9mhXlbzC+k0JAS5c/0AQ+Nh2f+qZZJ8G19ySdzWwTLSCQ== dependencies: broccoli-clean-css "^1.1.0" broccoli-funnel "^1.0.0" @@ -3915,7 +3415,6 @@ ember-cli-preprocess-registry@^3.1.2: ember-cli-pretender@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-3.0.0.tgz#dcaf772332a1e6b0fc91e4b9a7e793a1283c85ac" - integrity sha512-WpcXEiAStYFrPUfy6RElkm9EcJFjRAdD6LmMFoORG/fLjcWZya/pMSemzykZpCPMjMLHabR5ltmfvUjb4MR1ZQ== dependencies: "@xg-wang/whatwg-fetch" "^3.0.0" abortcontroller-polyfill "^1.1.9" @@ -3930,7 +3429,6 @@ ember-cli-pretender@^3.0.0: ember-cli-release@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.npmjs.org/ember-cli-release/-/ember-cli-release-1.0.0-beta.2.tgz#cb72d341293e94a1a8bcf4b73f7a6396f5b7e0c5" - integrity sha1-y3LTQSk+lKGovPS3P3pjlvW34MU= dependencies: chalk "^1.0.0" git-tools "^0.1.4" @@ -3947,7 +3445,6 @@ ember-cli-release@^1.0.0-beta.2: ember-cli-shims@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/ember-cli-shims/-/ember-cli-shims-1.2.0.tgz#0f53aff0aab80b5f29da3a9731bac56169dd941f" - integrity sha1-D1Ov8Kq4C18p2jqXMbrFYWndlB8= dependencies: broccoli-file-creator "^1.1.1" broccoli-merge-trees "^2.0.0" @@ -3958,33 +3455,28 @@ ember-cli-shims@^1.2.0: ember-cli-sri@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" - integrity sha1-lxYgk0pLkYPPeSPMA+F4uDqpB/0= dependencies: broccoli-sri-hash "^2.1.0" ember-cli-string-utils@^1.0.0, ember-cli-string-utils@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" - integrity sha1-ObZ3/CgF9VFzc1N2/O8njqpEUqE= ember-cli-test-info@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" - integrity sha1-7U6WDySel1I8+JHkrtIHLOhFd7Q= dependencies: ember-cli-string-utils "^1.0.0" ember-cli-test-loader@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/ember-cli-test-loader/-/ember-cli-test-loader-2.2.0.tgz#3fb8d5d1357e4460d3f0a092f5375e71b6f7c243" - integrity sha512-mlSXX9SciIRwGkFTX6XGyJYp4ry6oCFZRxh5jJ7VH8UXLTNx2ZACtDTwaWtNhYrWXgKyiDUvmD8enD56aePWRA== dependencies: ember-cli-babel "^6.8.1" ember-cli-typescript-blueprints@^2.0.0-beta.1: version "2.0.0-beta.1" resolved "https://registry.yarnpkg.com/ember-cli-typescript-blueprints/-/ember-cli-typescript-blueprints-2.0.0-beta.1.tgz#2db2e34ad01b5a50a4459c2f7cfc8f132b21fcea" - integrity sha512-tU1hN9Wj/nzWrSArogr/n9j8kfsv+2wueRuaIr7X+h4klb/Vb92bVkyW1xx8SW9hsWkv8n7ct8PzMmW033ws8g== dependencies: chalk "^2.4.1" ember-cli-babel "^6.6.0" @@ -4005,7 +3497,6 @@ ember-cli-typescript-blueprints@^2.0.0-beta.1: ember-cli-typescript@^2.0.0-beta.2: version "2.0.0-beta.2" resolved "https://registry.yarnpkg.com/ember-cli-typescript/-/ember-cli-typescript-2.0.0-beta.2.tgz#29bd0a7eff45b54e01d2cbc2fba05b3991a9c0d3" - integrity sha512-Wxopeo/ShTO7P9ja+CYwXM6+tww2kSMJFHCEFemWjB+tFR0318Pqa7EEYJ/lHAkIjE214B13A/qsWwhIGf3zxw== dependencies: "@babel/plugin-proposal-class-properties" "^7.1.0" "@babel/plugin-transform-typescript" "^7.1.0" @@ -4023,7 +3514,6 @@ ember-cli-typescript@^2.0.0-beta.2: ember-cli-uglify@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ember-cli-uglify/-/ember-cli-uglify-2.1.0.tgz#4a0641fe4768d7ab7d4807aca9924cc77c544184" - integrity sha512-lDzdAUfhGx5AMBsgyR54ibENVp/LRQuHNWNaP2SDjkAXDyuYFgW0iXIAfGbxF6+nYaesJ9Tr9AKOfTPlwxZDSg== dependencies: broccoli-uglify-sourcemap "^2.1.1" lodash.defaultsdeep "^4.6.0" @@ -4031,14 +3521,12 @@ ember-cli-uglify@2.1.0: ember-cli-valid-component-name@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" - integrity sha1-cVUM44fgIzBl8wswsVEKot++h+8= dependencies: silent-error "^1.0.0" ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-version-checker@^2.1.1, ember-cli-version-checker@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.1.2.tgz#305ce102390c66e4e0f1432dea9dc5c7c19fed98" - integrity sha512-sjkHGr4IGXnO3EUcY21380Xo9Qf6bC8HWH4D62bVnrQop/8uha5XgMQRoAflMCeH6suMrezQL287JUoYc2smEw== dependencies: resolve "^1.3.3" semver "^5.3.0" @@ -4046,7 +3534,6 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-ve ember-cli-yuidoc@^0.8.8: version "0.8.8" resolved "https://registry.yarnpkg.com/ember-cli-yuidoc/-/ember-cli-yuidoc-0.8.8.tgz#3858baaf85388a976024f9de40f1075fea58f606" - integrity sha1-OFi6r4U4ipdgJPneQPEHX+pY9gY= dependencies: broccoli-caching-writer "~2.0.4" broccoli-merge-trees "^1.1.1" @@ -4057,7 +3544,6 @@ ember-cli-yuidoc@^0.8.8: ember-cli@^3.5.0: version "3.5.0" resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-3.5.0.tgz#978031042611008dce82c79226b8b677d325072c" - integrity sha512-AW5eb1SG7szuSnai3CIPL9fE7eyPQS2oycyDZAGLs+An57ytK9lm1NFQWqXm3nGnvdSh1AIsoCwc683tISUozQ== dependencies: amd-name-resolver "^1.2.0" babel-plugin-transform-es2015-modules-amd "^6.24.1" @@ -4152,7 +3638,6 @@ ember-cli@^3.5.0: ember-compatibility-helpers@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.0.2.tgz#a7eb8969747d063720fe44658af5448589b437ba" - integrity sha512-pN1ezLiAM+uIKI4/BMp2hIBi6LQKxOedxKcu2mHDK+HEYuhlwki8Y2YwFSwb1w3c2YhesbkwaAJx/dvNHQGq5g== dependencies: babel-plugin-debug-macros "^0.1.11" ember-cli-version-checker "^2.1.1" @@ -4161,7 +3646,6 @@ ember-compatibility-helpers@^1.0.0: ember-compatibility-helpers@^1.1.1: version "1.1.2" resolved "https://registry.npmjs.org/ember-compatibility-helpers/-/ember-compatibility-helpers-1.1.2.tgz#ae0ee4a7a2858b5ffdf79b428c23aee85c47d93d" - integrity sha512-yN163MzERpotO8M0b+q+kXs4i3Nx6aIriiZHWv+yXQzr2TAtYlVwg9V7/3+jcurOa3oDEYDpN7y9UZ6q3mnoTg== dependencies: babel-plugin-debug-macros "^0.2.0" ember-cli-version-checker "^2.1.1" @@ -4170,7 +3654,6 @@ ember-compatibility-helpers@^1.1.1: ember-decorators@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/ember-decorators/-/ember-decorators-3.0.0.tgz#23cee0ebea3f86806cd15b638bf5ffb40870ccf4" - integrity sha512-+ELAcA5ExbXVStb3AUrqEGrH303CrbcwNfaHVe9pKxK5RxQwQmHBSLHMTOoYsObYlCgpIxhhT6WKHOn3LeYlvA== dependencies: "@ember-decorators/component" "^3.0.0" "@ember-decorators/controller" "^3.0.0" @@ -4183,33 +3666,28 @@ ember-decorators@^3.0.0: ember-disable-prototype-extensions@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" - integrity sha1-GWkTUhdlS14nj5/i2dTkm1cgMp4= ember-export-application-global@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ember-export-application-global/-/ember-export-application-global-2.0.0.tgz#8d6d7619ac8a1a3f8c43003549eb21ebed685bd2" - integrity sha1-jW12GayKGj+MQwA1Sesh6+1oW9I= dependencies: ember-cli-babel "^6.0.0-beta.7" ember-inflector@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ember-inflector/-/ember-inflector-3.0.0.tgz#7e1ee8aaa0fa773ba0905d8b7c0786354d890ee1" - integrity sha512-tLWfYolZAkLnkTvvBkjizy4Wmj8yI8wqHZFK+leh0iScHiC3r1Yh5C4qO+OMGiBTMLwfTy+YqVoE/Nu3hGNkcA== dependencies: ember-cli-babel "^6.6.0" ember-load-initializers@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ember-load-initializers/-/ember-load-initializers-1.1.0.tgz#4edacc0f3a14d9f53d241ac3e5561804c8377978" - integrity sha512-WiciFi8IXOqjyJ65M4iBNIthqcy4uXXQq5n3WxeMMhvJVk5JNSd9hynNECNz3nqfEYuZQ9c04UWkmFIQXRfl4Q== dependencies: ember-cli-babel "^6.6.0" ember-maybe-import-regenerator@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ember-maybe-import-regenerator/-/ember-maybe-import-regenerator-0.1.6.tgz#35d41828afa6d6a59bc0da3ce47f34c573d776ca" - integrity sha1-NdQYKK+m1qWbwNo85H80xXPXdso= dependencies: broccoli-funnel "^1.0.1" broccoli-merge-trees "^1.0.0" @@ -4219,7 +3697,6 @@ ember-maybe-import-regenerator@^0.1.6: ember-qunit-assert-helpers@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ember-qunit-assert-helpers/-/ember-qunit-assert-helpers-0.2.1.tgz#4a77f8ff252e47cc53db6fa7fb4becb426de8d29" - integrity sha512-3h7jdwp/Lzpri04hrSzUz0hguzzF7ldnCEb+tB+5MianGiFusYjPEu8QsUqJ6BhzXlljyX+pmMVyNe7HL6lsjA== dependencies: broccoli-filter "^1.0.1" ember-cli-babel "^6.9.0" @@ -4227,7 +3704,6 @@ ember-qunit-assert-helpers@^0.2.1: ember-qunit@^3.5.3: version "3.5.3" resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-3.5.3.tgz#bfd0bff8298c78c77e870cca43fe0826e78a0d09" - integrity sha512-FmXsI1bGsZ5th25x4KEle2fLCVURTptsQODfBt+Pg8tk9rX7y79cqny91PrhtkhE+giZ8p029tnq94SdpJ4ojg== dependencies: "@ember/test-helpers" "^0.7.26" broccoli-funnel "^2.0.1" @@ -4240,7 +3716,6 @@ ember-qunit@^3.5.3: ember-resolver@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-5.0.1.tgz#21740b92e1e4a65f94018de22aa1c73434dc3b2f" - integrity sha512-Svhs/eseIVQ6Yik+4mFpixT639FREZW2UkIYo7197bRuSL63tofKDMfE+gOXUSSudQlQSaFHFeKDr9oD+0C2GQ== dependencies: "@glimmer/resolver" "^0.4.1" babel-plugin-debug-macros "^0.1.10" @@ -4253,31 +3728,26 @@ ember-resolver@^5.0.1: ember-rfc176-data@^0.3.0, ember-rfc176-data@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.3.tgz#27fba08d540a7463a4366c48eaa19c5a44971a39" - integrity sha1-J/ugjVQKdGOkNmxI6qGcWkSXGjk= ember-rfc176-data@^0.3.5: version "0.3.5" resolved "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.3.5.tgz#f630e550572c81a5e5c7220f864c0f06eee9e977" - integrity sha512-5NfL1iTkIQDYs16/IZ7/jWCEglNsUrigLelBkBMsNcib9T3XzQwmhhVTjoSsk66s57LmWJ1bQu+2c1CAyYCV7A== ember-router-generator@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" - integrity sha1-jtLKhv8yM2MSD8FCeBkeno8TFe4= dependencies: recast "^0.11.3" ember-source-channel-url@^1.0.1, ember-source-channel-url@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ember-source-channel-url/-/ember-source-channel-url-1.1.0.tgz#73de5cc6ebc25b2120e932ec1d8f82677bfaf6ef" - integrity sha512-y1RVXmyqrdX6zq9ZejpPt7ohKNGuLMBEKaOUyxFWcYAM5gvLuo6xFerwNmXEBbu4e3//GaoasjodXi6Cl+ddUQ== dependencies: got "^8.0.1" ember-source@~3.5.0: version "3.5.0" resolved "https://registry.npmjs.org/ember-source/-/ember-source-3.5.0.tgz#2322e393125684e1e043d0eedad8fd79c6de78a8" - integrity sha512-q7GAQZI1NAxMdgqxJGKsOgmwFAmvSet33Ub5C/Cn5bkQYWlAgjR7oKiP0DlHTFSbiwmGnZZF9a/sHB7W/XIjPg== dependencies: broccoli-funnel "^2.0.1" broccoli-merge-trees "^2.0.0" @@ -4297,7 +3767,6 @@ ember-source@~3.5.0: ember-try-config@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ember-try-config/-/ember-try-config-3.0.0.tgz#012d8c90cae9eb624e2b62040bf7e76a1aa58edc" - integrity sha512-pNwHS29O1ACczkrxBKRtDY0TzTb7uPnA5eHEe+4NF6qpLK5FVnL3EtgZ8+yVYtnm1If5mZ07rIubw45vaSek7w== dependencies: ember-source-channel-url "^1.0.1" lodash "^4.6.1" @@ -4309,7 +3778,6 @@ ember-try-config@^3.0.0: ember-try@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/ember-try/-/ember-try-1.1.0.tgz#194d5843a79b5a9fc0e4c07445ebc18c08a91e78" - integrity sha512-NL1rKPz2LuyVEqwoNV+SQD4c2w1/A0rrdeT6jqTYqlt/P7y3+SWcsxyReBnImebaIu7Drtz6p9yiAsrJq5Chyg== dependencies: chalk "^2.3.0" cli-table3 "^0.5.1" @@ -4328,24 +3796,20 @@ ember-try@^1.1.0: emit-function@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/emit-function/-/emit-function-0.0.2.tgz#e3a50b3d61be1bf8ca88b924bf713157a5bec124" - integrity sha1-46ULPWG+G/jKiLkkv3ExV6W+wSQ= encodeurl@~1.0.1, encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= end-of-stream@^1.1.0: version "1.4.1" resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" - integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== dependencies: once "^1.4.0" engine.io-client@~3.2.0: version "3.2.1" resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" - integrity sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw== dependencies: component-emitter "1.2.1" component-inherit "0.0.3" @@ -4362,7 +3826,6 @@ engine.io-client@~3.2.0: engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196" - integrity sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw== dependencies: after "0.8.2" arraybuffer.slice "~0.0.7" @@ -4373,7 +3836,6 @@ engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: engine.io@~3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.0.tgz#54332506f42f2edc71690d2f2a42349359f3bf7d" - integrity sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw== dependencies: accepts "~1.3.4" base64id "1.0.0" @@ -4385,29 +3847,24 @@ engine.io@~3.2.0: ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" - integrity sha1-pls+QtC3HPxYXrd0+ZQ8jZuRsMI= entities@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" - integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" - integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA= error-ex@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" error@^7.0.0: version "7.0.2" resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" - integrity sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI= dependencies: string-template "~0.2.1" xtend "~4.0.0" @@ -4415,7 +3872,6 @@ error@^7.0.0: es-abstract@^1.9.0: version "1.12.0" resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" - integrity sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA== dependencies: es-to-primitive "^1.1.1" function-bind "^1.1.1" @@ -4426,7 +3882,6 @@ es-abstract@^1.9.0: es-to-primitive@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" - integrity sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0= dependencies: is-callable "^1.1.1" is-date-object "^1.0.1" @@ -4435,7 +3890,6 @@ es-to-primitive@^1.1.1: es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: version "0.10.45" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.45.tgz#0bfdf7b473da5919d5adf3bd25ceb754fccc3653" - integrity sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ== dependencies: es6-iterator "~2.0.3" es6-symbol "~3.1.1" @@ -4444,7 +3898,6 @@ es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: es6-iterator@~2.0.1, es6-iterator@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= dependencies: d "1" es5-ext "^0.10.35" @@ -4453,7 +3906,6 @@ es6-iterator@~2.0.1, es6-iterator@~2.0.3: es6-map@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - integrity sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA= dependencies: d "1" es5-ext "~0.10.14" @@ -4465,7 +3917,6 @@ es6-map@^0.1.5: es6-set@~0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" - integrity sha1-0rPsXU2ADO2BjbU40ol02wpzzLE= dependencies: d "1" es5-ext "~0.10.14" @@ -4476,7 +3927,6 @@ es6-set@~0.1.5: es6-symbol@3.1.1, es6-symbol@^3.0.2, es6-symbol@^3.1.1, es6-symbol@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" - integrity sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc= dependencies: d "1" es5-ext "~0.10.14" @@ -4484,24 +3934,20 @@ es6-symbol@3.1.1, es6-symbol@^3.0.2, es6-symbol@^3.1.1, es6-symbol@~3.1.1: escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= eslint-config-prettier@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-3.1.0.tgz#2c26d2cdcfa3a05f0642cd7e6e4ef3316cdabfa2" - integrity sha512-QYGfmzuc4q4J6XIhlp8vRKdI/fI0tQfQPy1dME3UOLprE+v4ssH/3W9LM2Q7h5qBcy5m0ehCrBDU2YF8q6OY8w== dependencies: get-stdin "^6.0.0" eslint-plugin-es@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-1.3.1.tgz#5acb2565db4434803d1d46a9b4cbc94b345bd028" - integrity sha512-9XcVyZiQRVeFjqHw8qHNDAZcQLqaHlOGGpeYqzYh8S4JYCWTCO3yzyen8yVmA5PratfzTRWDwCOFphtDEG+w/w== dependencies: eslint-utils "^1.3.0" regexpp "^2.0.0" @@ -4509,7 +3955,6 @@ eslint-plugin-es@^1.3.1: eslint-plugin-node@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-7.0.1.tgz#a6e054e50199b2edd85518b89b4e7b323c9f36db" - integrity sha512-lfVw3TEqThwq0j2Ba/Ckn2ABdwmL5dkOgAux1rvOk6CO7A6yGyPI2+zIxN6FyNkp1X1X/BSvKOceD6mBWSj4Yw== dependencies: eslint-plugin-es "^1.3.1" eslint-utils "^1.3.1" @@ -4521,14 +3966,12 @@ eslint-plugin-node@^7.0.1: eslint-plugin-prettier@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.0.tgz#f6b823e065f8c36529918cdb766d7a0e975ec30c" - integrity sha512-4g11opzhqq/8+AMmo5Vc2Gn7z9alZ4JqrbZ+D4i8KlSyxeQhZHlmIrY8U9Akf514MoEhogPa87Jgkq87aZ2Ohw== dependencies: prettier-linter-helpers "^1.0.0" eslint-scope@3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" - integrity sha1-PWPD7f2gLgbgGkUq2IyqzHzctug= dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" @@ -4536,7 +3979,6 @@ eslint-scope@3.7.1: eslint-scope@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" - integrity sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA== dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" @@ -4544,17 +3986,14 @@ eslint-scope@^4.0.0: eslint-utils@^1.3.0, eslint-utils@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" - integrity sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q== eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" - integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== eslint@^5.7.0: version "5.7.0" resolved "https://registry.npmjs.org/eslint/-/eslint-5.7.0.tgz#55c326d6fb2ad45fcbd0ce17c3846f025d1d819c" - integrity sha512-zYCeFQahsxffGl87U2aJ7DPyH8CbWgxBC213Y8+TCanhUTf2gEvfq3EKpHmEcozTLyPmGe9LZdMAwC/CpJBM5A== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.5.3" @@ -4598,7 +4037,6 @@ eslint@^5.7.0: espree@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/espree/-/espree-4.0.0.tgz#253998f20a0f82db5d866385799d912a83a36634" - integrity sha512-kapdTCt1bjmspxStVKX6huolXVV5ZfyZguY1lcfhVVZstce3bqxH9mcLzNn3/mlgW6wQ732+0fuG9v7h0ZQoKg== dependencies: acorn "^5.6.0" acorn-jsx "^4.1.1" @@ -4606,61 +4044,50 @@ espree@^4.0.0: esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esprima@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" - integrity sha1-U88kes2ncxPlUcOqLnM0LT+099k= esprima@~3.1.0: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= esprimaq@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" - integrity sha1-PqOkH1W6CrmPw1ZMh1gYvYkKoqM= esquery@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" - integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== dependencies: estraverse "^4.0.0" esrecurse@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== dependencies: estraverse "^4.1.0" estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= estree-walker@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.5.2.tgz#d3850be7529c9580d815600b53126515e146dd39" - integrity sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig== esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= event-emitter@~0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= dependencies: d "1" es5-ext "~0.10.14" @@ -4668,17 +4095,14 @@ event-emitter@~0.3.5: eventemitter3@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" - integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA== events-to-array@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" - integrity sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y= exec-file-sync@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/exec-file-sync/-/exec-file-sync-2.0.2.tgz#58d441db46e40de6d1f30de5be022785bd89e328" - integrity sha1-WNRB20bkDebR8w3lvgInhb2J4yg= dependencies: is-obj "^1.0.0" object-assign "^4.0.1" @@ -4687,14 +4111,12 @@ exec-file-sync@^2.0.0: exec-sh@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" - integrity sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== dependencies: merge "^1.2.0" execa@^0.10.0: version "0.10.0" resolved "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" - integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== dependencies: cross-spawn "^6.0.0" get-stream "^3.0.0" @@ -4707,7 +4129,6 @@ execa@^0.10.0: execa@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.9.0.tgz#adb7ce62cf985071f60580deb4a88b9e34712d01" - integrity sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA== dependencies: cross-spawn "^5.0.1" get-stream "^3.0.0" @@ -4720,7 +4141,6 @@ execa@^0.9.0: execa@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== dependencies: cross-spawn "^6.0.0" get-stream "^4.0.0" @@ -4733,44 +4153,36 @@ execa@^1.0.0: exists-stat@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/exists-stat/-/exists-stat-1.0.0.tgz#0660e3525a2e89d9e446129440c272edfa24b529" - integrity sha1-BmDjUlouidnkRhKUQMJy7foktSk= exists-sync@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" - integrity sha1-uRAAC+27ETs3i4L19adjgQdiLc8= exists-sync@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" - integrity sha1-l0TCxCjMA7AQYNtFTUsS8O88iHk= exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.1.0.tgz#318d545213d2b2a31499e92c35f74c94196a22f7" - integrity sha512-qEfFekfBVid4b14FNug/RNY1nv+BADnlzKGHulc+t6ZLqGY4kdHGh1iFha8lnE3sJU/1WzMzKRNxS6EvSakJUg== exit-hook@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - integrity sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g= exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= dependencies: is-posix-bracket "^0.1.0" expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= dependencies: debug "^2.3.3" define-property "^0.2.5" @@ -4783,21 +4195,18 @@ expand-brackets@^2.1.4: expand-range@^1.8.1: version "1.8.2" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= dependencies: fill-range "^2.1.0" expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" - integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= dependencies: homedir-polyfill "^1.0.1" express@^4.10.7, express@^4.13.1: version "4.16.3" resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" - integrity sha1-avilAjUNsyRuzEvs9rWjTSL37VM= dependencies: accepts "~1.3.5" array-flatten "1.1.1" @@ -4833,7 +4242,6 @@ express@^4.10.7, express@^4.13.1: express@^4.16.3: version "4.16.4" resolved "https://registry.npmjs.org/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" - integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== dependencies: accepts "~1.3.5" array-flatten "1.1.1" @@ -4869,14 +4277,12 @@ express@^4.16.3: extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= dependencies: assign-symbols "^1.0.0" is-extendable "^1.0.1" @@ -4884,12 +4290,10 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: extend@^3.0.0, extend@~3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== external-editor@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" - integrity sha1-Etew24UPf/fnCBuvQAVwAGDEYAs= dependencies: extend "^3.0.0" spawn-sync "^1.0.15" @@ -4898,7 +4302,6 @@ external-editor@^1.1.0: external-editor@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" - integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== dependencies: chardet "^0.7.0" iconv-lite "^0.4.24" @@ -4907,14 +4310,12 @@ external-editor@^3.0.0: extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= dependencies: is-extglob "^1.0.0" extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== dependencies: array-unique "^0.3.2" define-property "^1.0.0" @@ -4928,54 +4329,44 @@ extglob@^2.0.4: extsprintf@1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= extsprintf@^1.2.0: version "1.4.0" resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= fake-xml-http-request@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-2.0.0.tgz#41a92f0ca539477700cb1dafd2df251d55dac8ff" - integrity sha512-UjNnynb6eLAB0lyh2PlTEkjRJORnNsVF1hbzU+PQv89/cyBV9GDRCy7JAcLQgeCLYT+3kaumWWZKEJvbaK74eQ== fast-deep-equal@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" - integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= fast-diff@^1.1.2: version "1.2.0" resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" - integrity sha1-P7s2Y097555PftvbSjV97iXRhOs= dependencies: blank-object "^1.0.1" fast-sourcemap-concat@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/fast-sourcemap-concat/-/fast-sourcemap-concat-1.4.0.tgz#122c330d4a2afaff16ad143bc9674b87cd76c8ad" - integrity sha512-x90Wlx/2C83lfyg7h4oguTZN4MyaVfaiUSJQNpU+YEA0Odf9u659Opo44b0LfoVg9G/bOE++GdID/dkyja+XcA== dependencies: chalk "^2.0.0" fs-extra "^5.0.0" @@ -4989,28 +4380,24 @@ fast-sourcemap-concat@^1.4.0: faye-websocket@~0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" - integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= dependencies: websocket-driver ">=0.5.1" fb-watchman@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" - integrity sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg= dependencies: bser "^2.0.0" figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= dependencies: escape-string-regexp "^1.0.5" file-entry-cache@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" - integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E= dependencies: flat-cache "^1.2.1" object-assign "^4.0.1" @@ -5018,17 +4405,14 @@ file-entry-cache@^2.0.0: filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= filesize@^3.6.1: version "3.6.1" resolved "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" - integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== fill-range@^2.1.0: version "2.2.4" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" - integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== dependencies: is-number "^2.1.0" isobject "^2.0.0" @@ -5039,7 +4423,6 @@ fill-range@^2.1.0: fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= dependencies: extend-shallow "^2.0.1" is-number "^3.0.0" @@ -5049,7 +4432,6 @@ fill-range@^4.0.0: finalhandler@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" - integrity sha1-zgtoVbRYU+eRsvzGgARtiCU91/U= dependencies: debug "2.6.9" encodeurl "~1.0.1" @@ -5062,7 +4444,6 @@ finalhandler@1.1.0: finalhandler@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" - integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== dependencies: debug "2.6.9" encodeurl "~1.0.2" @@ -5075,7 +4456,6 @@ finalhandler@1.1.1: find-babel-config@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.1.0.tgz#acc01043a6749fec34429be6b64f542ebb5d6355" - integrity sha1-rMAQQ6Z0n+w0Qpvmtk9ULrtdY1U= dependencies: json5 "^0.5.1" path-exists "^3.0.0" @@ -5083,12 +4463,10 @@ find-babel-config@^1.1.0: find-index@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" - integrity sha1-UwB8ec0wBA1oFteUWOiDfVxXBe8= find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" @@ -5096,21 +4474,18 @@ find-up@^1.0.0: find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= dependencies: locate-path "^2.0.0" find-up@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== dependencies: locate-path "^3.0.0" find-yarn-workspace-root@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-1.1.0.tgz#9817b6748cb90719f4dc37b4538bb200c697356f" - integrity sha512-Ete1eGKj7EEcbIyKCOZDIVvANKmBma5kCB+pOLnHFQzfn98QdQ2UEw+9yFkciOoPScuj2O7vUswIrBdI2ueAAw== dependencies: fs-extra "^4.0.3" micromatch "^3.1.4" @@ -5118,7 +4493,6 @@ find-yarn-workspace-root@^1.1.0: findup-sync@2.0.0, findup-sync@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" - integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw= dependencies: detect-file "^1.0.0" is-glob "^3.1.0" @@ -5128,7 +4502,6 @@ findup-sync@2.0.0, findup-sync@^2.0.0: fireworm@^0.7.0: version "0.7.1" resolved "https://registry.yarnpkg.com/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" - integrity sha1-zPIPeUHxCIg/zduZOD2+bhhhx1g= dependencies: async "~0.2.9" is-type "0.0.1" @@ -5139,7 +4512,6 @@ fireworm@^0.7.0: fixturify-project@^1.5.3: version "1.5.3" resolved "https://registry.npmjs.org/fixturify-project/-/fixturify-project-1.5.3.tgz#2ba4ffec59c1d79ae6638f818c0847eb974d179b" - integrity sha512-vgH+Uo+pC6jHg7mt+FDz+j08bKFugnP6guBWeumYllQDbvxT7NQ/sf6zO4nC0XKRRsSNWsOHkO0AppaHvwF69A== dependencies: fixturify "^0.3.4" tmp "^0.0.33" @@ -5147,7 +4519,6 @@ fixturify-project@^1.5.3: fixturify@^0.3.2, fixturify@^0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/fixturify/-/fixturify-0.3.4.tgz#c676de404a7f8ee8e64d0b76118e62ec95ab7b25" - integrity sha512-Gx+KSB25b6gMc4bf7UFRTA85uE0iZR+RYur0JHh6dg4AGBh0EksOv4FCHyM7XpGmiJO7Bc7oV7vxENQBT+2WEQ== dependencies: fs-extra "^0.30.0" matcher-collection "^1.0.4" @@ -5155,7 +4526,6 @@ fixturify@^0.3.2, fixturify@^0.3.4: flat-cache@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" - integrity sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE= dependencies: circular-json "^0.3.1" del "^2.0.2" @@ -5165,41 +4535,34 @@ flat-cache@^1.2.1: follow-redirects@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.1.tgz#67a8f14f5a1f67f962c2c46469c79eaec0a90291" - integrity sha512-v9GI1hpaqq1ZZR6pBD1+kI7O24PhDvNGNodjS3MdcEqyrahCp8zbtpv+2B/krUnSmUH80lbAS7MrdeK5IylgKg== dependencies: debug "^3.1.0" for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= for-own@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= dependencies: for-in "^1.0.1" foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= forever-agent@~0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" - integrity sha1-bQ4JxJIflKJ/Y9O0nF/v8epMUTA= forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= form-data@~0.1.0: version "0.1.4" resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" - integrity sha1-kavXiKupcCsaq/qLwBAxoqyeOxI= dependencies: async "~0.9.0" combined-stream "~0.0.4" @@ -5208,7 +4571,6 @@ form-data@~0.1.0: form-data@~1.0.0-rc3: version "1.0.1" resolved "http://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" - integrity sha1-rjFduaSQf6BlUCMEpm13M0de43w= dependencies: async "^2.0.1" combined-stream "^1.0.5" @@ -5217,7 +4579,6 @@ form-data@~1.0.0-rc3: form-data@~2.3.2: version "2.3.3" resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== dependencies: asynckit "^0.4.0" combined-stream "^1.0.6" @@ -5226,24 +4587,20 @@ form-data@~2.3.2: forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= fragment-cache@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= dependencies: map-cache "^0.2.2" fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= from2@^2.1.1: version "2.3.0" resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= dependencies: inherits "^2.0.1" readable-stream "^2.0.0" @@ -5251,7 +4608,6 @@ from2@^2.1.1: fs-extra@^0.24.0: version "0.24.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" - integrity sha1-1OQ0KpZnXLeEZjOmCZJJMytTmVI= dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -5261,7 +4617,6 @@ fs-extra@^0.24.0: fs-extra@^0.30.0: version "0.30.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" - integrity sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A= dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -5272,7 +4627,6 @@ fs-extra@^0.30.0: fs-extra@^4.0.2, fs-extra@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" - integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -5281,7 +4635,6 @@ fs-extra@^4.0.2, fs-extra@^4.0.3: fs-extra@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" - integrity sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ== dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -5290,7 +4643,6 @@ fs-extra@^5.0.0: fs-extra@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b" - integrity sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA== dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -5299,7 +4651,6 @@ fs-extra@^6.0.1: fs-extra@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.0.tgz#8cc3f47ce07ef7b3593a11b9fb245f7e34c041d6" - integrity sha512-EglNDLRpmaTWiD/qraZn6HREAEAHJcJOmxNEYwq6xeMKnVMAy3GUcFB+wXt2C6k4CNvB/mP1y/U3dzvKKj5OtQ== dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -5308,14 +4659,12 @@ fs-extra@^7.0.0: fs-minipass@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" - integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== dependencies: minipass "^2.2.1" fs-sync@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" - integrity sha1-L5Tq3jGGLsCp8zocJUbfsaPz0a4= dependencies: glob "^7.1.0" iconv-lite "^0.4.13" @@ -5326,7 +4675,6 @@ fs-sync@^1.0.4: fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6, fs-tree-diff@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-0.5.7.tgz#315e2b098d5fe7f622880ac965b1b051868ac871" - integrity sha512-dJwDX6NBH7IfdfFjZAdHCZ6fIKc8LwR7kzqUhYRFJuX4g9ctG/7cuqJuwegGQsyLEykp6Z4krq+yIFMQlt7d9Q== dependencies: heimdalljs-logger "^0.1.7" object-assign "^4.1.0" @@ -5336,7 +4684,6 @@ fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5 fs-tree-diff@^0.5.9: version "0.5.9" resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.9.tgz#a4ec6182c2f5bd80b9b83c8e23e4522e6f5fd946" - integrity sha512-872G8ax0kHh01m9n/2KDzgYwouKza0Ad9iFltBpNykvROvf2AGtoOzPJgGx125aolGPER3JuC7uZFrQ7bG1AZw== dependencies: heimdalljs-logger "^0.1.7" object-assign "^4.1.0" @@ -5346,7 +4693,6 @@ fs-tree-diff@^0.5.9: fs-updater@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/fs-updater/-/fs-updater-1.0.4.tgz#2329980f99ae9176e9a0e84f7637538a182ce63b" - integrity sha512-0pJX4mJF/qLsNEwTct8CdnnRdagfb+LmjRPJ8sO+nCnAZLW0cTmz4rTgU25n+RvTuWSITiLKrGVJceJPBIPlKg== dependencies: can-symlink "^1.0.0" clean-up-path "^1.0.0" @@ -5357,7 +4703,6 @@ fs-updater@^1.0.4: fs-vacuum@~1.2.7: version "1.2.10" resolved "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36" - integrity sha1-t2Kb7AekAxolSP35n17PHMizHjY= dependencies: graceful-fs "^4.1.2" path-is-inside "^1.0.1" @@ -5366,7 +4711,6 @@ fs-vacuum@~1.2.7: fs-write-stream-atomic@~1.0.8: version "1.0.10" resolved "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= dependencies: graceful-fs "^4.1.2" iferr "^0.1.5" @@ -5376,12 +4720,10 @@ fs-write-stream-atomic@~1.0.8: fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fsevents@^1.2.3: version "1.2.4" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" - integrity sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg== dependencies: nan "^2.9.2" node-pre-gyp "^0.10.0" @@ -5389,7 +4731,6 @@ fsevents@^1.2.3: fstream-ignore@^1.0.0: version "1.0.5" resolved "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - integrity sha1-nDHa40dnAY/h0kmyTa2mfQktoQU= dependencies: fstream "^1.0.0" inherits "2" @@ -5398,7 +4739,6 @@ fstream-ignore@^1.0.0: fstream-npm@~1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/fstream-npm/-/fstream-npm-1.0.7.tgz#7ed0d1ac13d7686dd9e1bf6ceb8be273bf6d2f86" - integrity sha1-ftDRrBPXaG3Z4b9s64vic79tL4Y= dependencies: fstream-ignore "^1.0.0" inherits "2" @@ -5406,7 +4746,6 @@ fstream-npm@~1.0.7: fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.8: version "1.0.11" resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= dependencies: graceful-fs "^4.1.2" inherits "~2.0.0" @@ -5416,17 +4755,14 @@ fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.8: function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= gauge@~1.2.0, gauge@~1.2.5: version "1.2.7" resolved "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz#e9cec5483d3d4ee0ef44b60a7d99e4935e136d93" - integrity sha1-6c7FSD09TuDvRLYKfZnkk14TbZM= dependencies: ansi "^0.3.0" has-unicode "^2.0.0" @@ -5437,7 +4773,6 @@ gauge@~1.2.0, gauge@~1.2.5: gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -5451,65 +4786,54 @@ gauge@~2.7.3: generate-function@^2.0.0: version "2.3.1" resolved "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" - integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== dependencies: is-property "^1.0.2" generate-object-property@^1.1.0: version "1.2.0" resolved "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - integrity sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA= dependencies: is-property "^1.0.0" get-caller-file@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== get-func-name@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= get-stdin@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" - integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= get-stream@^4.0.0: version "4.1.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== dependencies: pump "^3.0.0" get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= getpass@^0.1.1: version "0.1.7" resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= dependencies: assert-plus "^1.0.0" git-fetch-pack@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/git-fetch-pack/-/git-fetch-pack-0.1.1.tgz#7703a32cf0db80f060d2766a34ac00d02cebcdf5" - integrity sha1-dwOjLPDbgPBg0nZqNKwA0CzrzfU= dependencies: bops "0.0.3" emit-function "0.0.2" @@ -5519,7 +4843,6 @@ git-fetch-pack@^0.1.1: git-packed-ref-parse@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/git-packed-ref-parse/-/git-packed-ref-parse-0.0.0.tgz#b85046931f3e4a65679b5de54af3a5d3df372646" - integrity sha1-uFBGkx8+SmVnm13lSvOl0983JkY= dependencies: line-stream "0.0.0" through "~2.2.7" @@ -5527,7 +4850,6 @@ git-packed-ref-parse@0.0.0: git-read-pkt-line@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/git-read-pkt-line/-/git-read-pkt-line-0.0.8.tgz#494037854ed57bd90cd55676540d86ab0cb36caa" - integrity sha1-SUA3hU7Ve9kM1VZ2VA2GqwyzbKo= dependencies: bops "0.0.3" through "~2.2.7" @@ -5535,38 +4857,32 @@ git-read-pkt-line@0.0.8: git-repo-info@^1.0.4, git-repo-info@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" - integrity sha1-KgcoIyVKr2L88HZgB9e2ZRvUGUM= git-repo-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-2.0.0.tgz#2e7a68ba3d0253e8e885c4138f922e6561de59bb" - integrity sha512-5wiwo0Pert7y8YtAC6Gym+ekeKojBospUEaQIPjK/djKvmONk7ZDpM986Q2OP5LEuwlmOom9Ji0XsGe78EFBeQ== git-repo-version@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-0.2.0.tgz#9a1d0019a50fc9e623c43d1c0fcc437391207d0d" - integrity sha1-mh0AGaUPyeYjxD0cD8xDc5EgfQ0= dependencies: git-repo-info "^1.0.4" git-repo-version@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-1.0.2.tgz#2c8e9bee5d970cafc0dd58480f9dc56d9afe8e4f" - integrity sha512-OPtwtHx9E8/rTMcWT+BU6GNj6Kq/O40bHJZaZAGy+pN2RXGmeKcfr0ix4M+SQuFY8vl5L/wfPSGOAtvUT/e3Qg== dependencies: git-repo-info "^1.4.1" git-tools@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" - integrity sha1-XkPllEO4pd7bOdumY9pJ55+UOXg= dependencies: spawnback "~1.0.0" git-transport-protocol@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/git-transport-protocol/-/git-transport-protocol-0.1.0.tgz#99f4dd6389b9161eded74a9e617d6ba5ed0a6c2c" - integrity sha1-mfTdY4m5Fh7e10qeYX1rpe0KbCw= dependencies: duplex "~1.0.0" emit-function "0.0.2" @@ -5577,7 +4893,6 @@ git-transport-protocol@^0.1.0: git-write-pkt-line@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/git-write-pkt-line/-/git-write-pkt-line-0.1.0.tgz#a84c1856c09011908389b2f06f911d91f6394694" - integrity sha1-qEwYVsCQEZCDibLwb5EdkfY5RpQ= dependencies: bops "0.0.3" through "~2.2.7" @@ -5585,12 +4900,10 @@ git-write-pkt-line@0.1.0: github@^14.0.0: version "14.0.0" resolved "https://registry.npmjs.org/github/-/github-14.0.0.tgz#b707ed88c33cd05e155c785d289aa6229c59a850" - integrity sha512-34/VqwhYGeYN0VHBSH49TmRWMF7emy32qjK6POiW47T/QI2u/cpuKsmrWt7a218ew/73dF4dQSJE68/HXdNfPw== glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= dependencies: glob-parent "^2.0.0" is-glob "^2.0.0" @@ -5598,14 +4911,12 @@ glob-base@^0.3.0: glob-parent@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= dependencies: is-glob "^2.0.0" "glob@3 || 4", glob@^4.3.2: version "4.5.3" resolved "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" - integrity sha1-xstz0yJsHv7wTePFbQEvAzd+4V8= dependencies: inflight "^1.0.4" inherits "2" @@ -5615,7 +4926,6 @@ glob-parent@^2.0.0: glob@7.1.2, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -5627,7 +4937,6 @@ glob@7.1.2, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: glob@^5.0.10: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= dependencies: inflight "^1.0.4" inherits "2" @@ -5638,7 +4947,6 @@ glob@^5.0.10: glob@^7.1.1, glob@^7.1.3: version "7.1.3" resolved "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -5650,7 +4958,6 @@ glob@^7.1.1, glob@^7.1.3: glob@~6.0.3: version "6.0.4" resolved "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" - integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI= dependencies: inflight "^1.0.4" inherits "2" @@ -5661,7 +4968,6 @@ glob@~6.0.3: global-modules@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" - integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== dependencies: global-prefix "^1.0.1" is-windows "^1.0.1" @@ -5670,7 +4976,6 @@ global-modules@^1.0.0: global-prefix@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" - integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= dependencies: expand-tilde "^2.0.2" homedir-polyfill "^1.0.1" @@ -5681,17 +4986,14 @@ global-prefix@^1.0.1: globals@^11.1.0, globals@^11.7.0: version "11.7.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" - integrity sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg== globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== globby@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" - integrity sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0= dependencies: array-union "^1.0.1" arrify "^1.0.0" @@ -5703,7 +5005,6 @@ globby@^5.0.0: got@^6.7.1: version "6.7.1" resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" - integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA= dependencies: create-error-class "^3.0.0" duplexer3 "^0.1.4" @@ -5720,7 +5021,6 @@ got@^6.7.1: got@^8.0.1: version "8.3.2" resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" - integrity sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw== dependencies: "@sindresorhus/is" "^0.7.0" cacheable-request "^2.1.1" @@ -5743,27 +5043,22 @@ got@^8.0.1: graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= "graceful-readlink@>= 1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= growl@1.10.5: version "1.10.5" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= handlebars@^4.0.11: version "4.0.12" resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" - integrity sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA== dependencies: async "^2.5.0" optimist "^0.6.1" @@ -5774,7 +5069,6 @@ handlebars@^4.0.11: handlebars@^4.0.4: version "4.0.11" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" - integrity sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw= dependencies: async "^1.4.0" optimist "^0.6.1" @@ -5785,12 +5079,10 @@ handlebars@^4.0.4: har-schema@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= har-validator@~2.0.2: version "2.0.6" resolved "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" - integrity sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0= dependencies: chalk "^1.1.1" commander "^2.9.0" @@ -5800,7 +5092,6 @@ har-validator@~2.0.2: har-validator@~5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29" - integrity sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA== dependencies: ajv "^5.3.0" har-schema "^2.0.0" @@ -5808,48 +5099,40 @@ har-validator@~5.1.0: has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= dependencies: ansi-regex "^2.0.0" has-binary2@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" - integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== dependencies: isarray "2.0.1" has-cors@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" - integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= has-symbol-support-x@^1.4.1: version "1.4.2" resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" - integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== has-to-string-tag-x@^1.2.0: version "1.4.1" resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" - integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== dependencies: has-symbol-support-x "^1.4.1" has-unicode@^2.0.0, has-unicode@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= dependencies: get-value "^2.0.3" has-values "^0.1.4" @@ -5858,7 +5141,6 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= dependencies: get-value "^2.0.6" has-values "^1.0.0" @@ -5867,12 +5149,10 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= has-values@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= dependencies: is-number "^3.0.0" kind-of "^4.0.0" @@ -5880,14 +5160,12 @@ has-values@^1.0.0: has@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== dependencies: function-bind "^1.1.1" hash-for-dep@^1.0.2, hash-for-dep@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.2.3.tgz#5ec69fca32c23523972d52acb5bb65ffc3664cab" - integrity sha512-NE//rDaCFpWHViw30YM78OAGBShU+g4dnUGY3UWGyEzPOGYg/ptOjk32nEc+bC1xz+RfK5UIs6lOL6eQdrV4Ow== dependencies: broccoli-kitchen-sink-helpers "^0.3.1" heimdalljs "^0.2.3" @@ -5897,7 +5175,6 @@ hash-for-dep@^1.0.2, hash-for-dep@^1.2.3: hawk@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" - integrity sha1-h81JH5tG5OKurKM1QWdmiF0tHtk= dependencies: boom "0.4.x" cryptiles "0.2.x" @@ -5907,7 +5184,6 @@ hawk@1.1.1: hawk@~3.1.0: version "3.1.3" resolved "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - integrity sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ= dependencies: boom "2.x.x" cryptiles "2.x.x" @@ -5917,12 +5193,10 @@ hawk@~3.1.0: he@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" - integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= heimdalljs-fs-monitor@^0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.2.2.tgz#a76d98f52dbf3aa1b7c20cebb0132e2f5eeb9204" - integrity sha512-R/VhkWs8tm4x+ekLIp+oieR8b3xYK0oFDumEraGnwNMixpiKwO3+Ms5MJzDP5W5Ui1+H/57nGW5L3lHbxi20GA== dependencies: heimdalljs "^0.2.3" heimdalljs-logger "^0.1.7" @@ -5930,12 +5204,10 @@ heimdalljs-fs-monitor@^0.2.2: heimdalljs-graph@^0.3.4: version "0.3.5" resolved "https://registry.npmjs.org/heimdalljs-graph/-/heimdalljs-graph-0.3.5.tgz#420fbbc8fc3aec5963ddbbf1a5fb47921c4a5927" - integrity sha512-szOy9WZUc7eUInEBQEsoa1G2d+oYHrn6ndZPf76eh8A9ID1zWUCEEsxP3F+CvQx9+EDrg1srdyLUmfVAr8EB4g== heimdalljs-logger@^0.1.7, heimdalljs-logger@^0.1.9: version "0.1.9" resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz#d76ada4e45b7bb6f786fc9c010a68eb2e2faf176" - integrity sha1-12raTkW3u294b8nAEKaOsuL68XY= dependencies: debug "^2.2.0" heimdalljs "^0.2.0" @@ -5943,31 +5215,26 @@ heimdalljs-logger@^0.1.7, heimdalljs-logger@^0.1.9: heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3, heimdalljs@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.5.tgz#6aa54308eee793b642cff9cf94781445f37730ac" - integrity sha1-aqVDCO7nk7ZCz/nPlHgURfN3MKw= dependencies: rsvp "~3.2.1" heimdalljs@^0.3.0: version "0.3.3" resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" - integrity sha1-6S0sb3f9RtW/ULYQ0orTF1UFTQs= dependencies: rsvp "~3.2.1" hoek@0.9.x: version "0.9.1" resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" - integrity sha1-PTIkYrrfB3Fup+uFuviAec3c5QU= hoek@2.x.x: version "2.16.3" resolved "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - integrity sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0= home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" - integrity sha1-42w/LSyufXRqhX440Y1fMqeILbg= dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.1" @@ -5975,29 +5242,24 @@ home-or-tmp@^2.0.0: homedir-polyfill@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" - integrity sha1-TCu8inWJmP7r9e1oWA921GdotLw= dependencies: parse-passwd "^1.0.0" hosted-git-info@^2.1.4, hosted-git-info@^2.1.5, hosted-git-info@^2.4.2, hosted-git-info@^2.6.0: version "2.7.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" - integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== hosted-git-info@~2.1.4: version "2.1.5" resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" - integrity sha1-C6gdkNouJas0ozLm7HeTbhWYEYs= http-cache-semantics@3.8.1: version "3.8.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" - integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== http-errors@1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" - integrity sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY= dependencies: depd "1.1.1" inherits "2.0.3" @@ -6007,7 +5269,6 @@ http-errors@1.6.2: http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: version "1.6.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= dependencies: depd "~1.1.2" inherits "2.0.3" @@ -6017,12 +5278,10 @@ http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: http-parser-js@>=0.4.0: version "0.4.13" resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.13.tgz#3bd6d6fde6e3172c9334c3b33b6c193d80fe1137" - integrity sha1-O9bW/ebjFyyTNMOzO2wZPYD+ETc= http-proxy@^1.13.1, http-proxy@^1.17.0: version "1.17.0" resolved "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" - integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g== dependencies: eventemitter3 "^3.0.0" follow-redirects "^1.0.0" @@ -6031,7 +5290,6 @@ http-proxy@^1.13.1, http-proxy@^1.17.0: http-signature@~0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" - integrity sha1-T72sEyVZqoMjEh5UB3nAoBKyfmY= dependencies: asn1 "0.1.11" assert-plus "^0.1.5" @@ -6040,7 +5298,6 @@ http-signature@~0.10.0: http-signature@~1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - integrity sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8= dependencies: assert-plus "^0.2.0" jsprim "^1.2.2" @@ -6049,7 +5306,6 @@ http-signature@~1.1.0: http-signature@~1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= dependencies: assert-plus "^1.0.0" jsprim "^1.2.2" @@ -6058,70 +5314,58 @@ http-signature@~1.2.0: iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" - integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ== iconv-lite@0.4.23, iconv-lite@^0.4.13, iconv-lite@^0.4.4: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" - integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== dependencies: safer-buffer ">= 2.1.2 < 3" iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" iferr@^0.1.5, iferr@~0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= ignore-walk@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" - integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== dependencies: minimatch "^3.0.4" ignore@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.3.tgz#e2d58c9654d75b542529fa28d80ac95b29e4f467" - integrity sha512-Z/vAH2GGIEATQnBVXMclE2IGV6i0GyVngKThcGZ5kHgHMxLo9Ow2+XHRq1aEKEej5vOF1TPJNbvX6J/anT0M7A== ignore@^4.0.6: version "4.0.6" resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= indent-string@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= dependencies: repeating "^2.0.0" indexof@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" - integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= inflection@^1.12.0: version "1.12.0" resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" - integrity sha1-ogCTVlbW9fa8TcdQLhrstwMihBY= inflight@^1.0.4, inflight@~1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" wrappy "1" @@ -6129,17 +5373,14 @@ inflight@^1.0.4, inflight@~1.0.4: inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= ini@^1.3.4, ini@~1.3.0, ini@~1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== init-package-json@~1.9.1: version "1.9.6" resolved "https://registry.npmjs.org/init-package-json/-/init-package-json-1.9.6.tgz#789fc2b74466a4952b9ea77c0575bc78ebd60a61" - integrity sha1-eJ/Ct0RmpJUrnqd8BXW8eOvWCmE= dependencies: glob "^7.1.1" npm-package-arg "^4.0.0 || ^5.0.0" @@ -6153,7 +5394,6 @@ init-package-json@~1.9.1: inline-source-map-comment@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" - integrity sha1-UKikTCp5DfrEQbXJTszVRiY1+vY= dependencies: chalk "^1.0.0" get-stdin "^4.0.1" @@ -6164,7 +5404,6 @@ inline-source-map-comment@^1.0.5: inquirer@^2: version "2.0.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-2.0.0.tgz#e1351687b90d150ca403ceaa3cefb1e3065bef4b" - integrity sha1-4TUWh7kNFQykA86qPO+x4wZb70s= dependencies: ansi-escapes "^1.1.0" chalk "^1.0.0" @@ -6184,7 +5423,6 @@ inquirer@^2: inquirer@^6.1.0: version "6.2.0" resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8" - integrity sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg== dependencies: ansi-escapes "^3.0.0" chalk "^2.0.0" @@ -6203,7 +5441,6 @@ inquirer@^6.1.0: into-stream@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" - integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= dependencies: from2 "^2.1.1" p-is-promise "^1.1.0" @@ -6211,79 +5448,66 @@ into-stream@^3.1.0: invariant@^2.2.2: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== dependencies: loose-envify "^1.0.0" ipaddr.js@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" - integrity sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs= ipaddr.js@1.8.0: version "1.8.0" resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" - integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4= is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= dependencies: kind-of "^3.0.2" is-accessor-descriptor@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== dependencies: kind-of "^6.0.0" is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== is-builtin-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= dependencies: builtin-modules "^1.0.0" is-callable@^1.1.1, is-callable@^1.1.3: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= dependencies: kind-of "^3.0.2" is-data-descriptor@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== dependencies: kind-of "^6.0.0" is-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== dependencies: is-accessor-descriptor "^0.1.6" is-data-descriptor "^0.1.4" @@ -6292,7 +5516,6 @@ is-descriptor@^0.1.0: is-descriptor@^1.0.0, is-descriptor@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== dependencies: is-accessor-descriptor "^1.0.0" is-data-descriptor "^1.0.0" @@ -6301,84 +5524,70 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= is-equal-shallow@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= dependencies: is-primitive "^2.0.0" is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= is-extendable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== dependencies: is-plain-object "^2.0.4" is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= is-extglob@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= is-finite@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= is-git-url@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-1.0.0.tgz#53f684cd143285b52c3244b4e6f28253527af66b" - integrity sha1-U/aEzRQyhbUsMkS05vKCU1J69ms= is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= dependencies: is-extglob "^1.0.0" is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= dependencies: is-extglob "^2.1.0" is-my-ip-valid@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824" - integrity sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ== is-my-json-valid@^2.12.4: version "2.19.0" resolved "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz#8fd6e40363cd06b963fa877d444bfb5eddc62175" - integrity sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q== dependencies: generate-function "^2.0.0" generate-object-property "^1.1.0" @@ -6389,197 +5598,162 @@ is-my-json-valid@^2.12.4: is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= dependencies: kind-of "^3.0.2" is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= dependencies: kind-of "^3.0.2" is-number@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= is-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" - integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" - integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0= is-path-in-cwd@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" - integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ== dependencies: is-path-inside "^1.0.0" is-path-inside@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" - integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= dependencies: path-is-inside "^1.0.1" is-plain-obj@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== dependencies: isobject "^3.0.1" is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= is-property@^1.0.0, is-property@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ= is-redirect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" - integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= is-reference@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.1.0.tgz#50e6ef3f64c361e2c53c0416cdc9420037f2685b" - integrity sha512-h37O/IX4efe56o9k41II1ECMqKwtqHa7/12dLDEzJIFux2x15an4WCDb0/eKdmUgRpLJ3bR0DrzDc7vOrVgRDw== dependencies: "@types/estree" "0.0.38" is-regex@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= dependencies: has "^1.0.1" is-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" - integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= is-resolvable@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" - integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ= is-stream@^1.0.0, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= is-symbol@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" - integrity sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI= is-type@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" - integrity sha1-9lHYXDZdRJVdFKUdjXBh8/a0d5w= dependencies: core-util-is "~1.0.0" is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= isarray@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" - integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= isbinaryfile@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80" - integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw== dependencies: buffer-alloc "^1.2.0" isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= isstream@~0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= istextorbinary@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" - integrity sha1-2+0qb1G+L3R1to+JRlgRFBt1iHQ= dependencies: binaryextensions "1 || 2" editions "^1.1.1" @@ -6588,7 +5762,6 @@ istextorbinary@2.1.0: isurl@^1.0.0-alpha5: version "1.0.0" resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" - integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== dependencies: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" @@ -6596,32 +5769,26 @@ isurl@^1.0.0-alpha5: jquery@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" - integrity sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg== js-levenshtein@^1.1.3: version "1.1.4" resolved "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.4.tgz#3a56e3cbf589ca0081eb22cd9ba0b1290a16d26e" - integrity sha512-PxfGzSs0ztShKrUYPIn5r0MtyAhYcCwmndozzpz8YObbPnD1jFxzlBGbRnX2mIu6Z13xN6+PTu05TQFnZFlzow== js-reporters@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b" - integrity sha1-+IxgjjJKM3OpW8xFrTBeXJecRZs= "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= js-yaml@^3.12.0, js-yaml@^3.2.5, js-yaml@^3.2.7: version "3.12.0" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" - integrity sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A== dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -6629,69 +5796,56 @@ js-yaml@^3.12.0, js-yaml@^3.2.5, js-yaml@^3.2.7: jsbn@~0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= jsesc@^2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" - integrity sha1-5CGiqOINawgZ3yiQj3glJrlt0f4= jsesc@~0.3.x: version "0.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.3.0.tgz#1bf5ee63b4539fe2e26d0c1e99c240b97a457972" - integrity sha1-G/XuY7RTn+LibQwemcJAuXpFeXI= jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= json-buffer@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== json-schema-traverse@^0.3.0: version "0.3.1" resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A= json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-schema@0.2.3: version "0.2.3" resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= dependencies: jsonify "~0.0.0" json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= json-typescript@^1.0.1: version "1.0.1" @@ -6701,36 +5855,30 @@ json-typescript@^1.0.1: json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - integrity sha1-NzaitCi4e72gzIO1P6PWM6NcKug= optionalDependencies: graceful-fs "^4.1.6" jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= optionalDependencies: graceful-fs "^4.1.6" jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= jsonpointer@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - integrity sha1-T9kss04OnbPInIYi7PUfm5eMbLk= jsprim@^1.2.2: version "1.4.1" resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= dependencies: assert-plus "1.0.0" extsprintf "1.3.0" @@ -6740,50 +5888,42 @@ jsprim@^1.2.2: keyv@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" - integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== dependencies: json-buffer "3.0.0" kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= dependencies: is-buffer "^1.1.5" kind-of@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== klaw@^1.0.0: version "1.3.1" resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - integrity sha1-QIhDO0azsbolnXh4XY6W9zugJDk= optionalDependencies: graceful-fs "^4.1.9" lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" - integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= leek@0.0.24: version "0.0.24" resolved "https://registry.yarnpkg.com/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" - integrity sha1-5ADlfw5g2O8r1NBo3EKKVDRdvNo= dependencies: debug "^2.1.0" lodash.assign "^3.2.0" @@ -6792,7 +5932,6 @@ leek@0.0.24: levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" @@ -6800,33 +5939,28 @@ levn@^0.3.0, levn@~0.3.0: line-stream@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/line-stream/-/line-stream-0.0.0.tgz#888b7cc7951c6a05ce4d696dd1e6b8262371bb45" - integrity sha1-iIt8x5UcagXOTWlt0ea4JiNxu0U= dependencies: through "~2.2.0" linkify-it@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" - integrity sha1-2UpGSPmxwXnWT6lykSaL22zpQ08= dependencies: uc.micro "^1.0.1" linkify-it@~1.2.0: version "1.2.4" resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" - integrity sha1-B3NSbDF8j9E71TTuHRgP+Iq/iBo= dependencies: uc.micro "^1.0.1" livereload-js@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.3.0.tgz#c3ab22e8aaf5bf3505d80d098cbad67726548c9a" - integrity sha512-j1R0/FeGa64Y+NmqfZhyoVRzcFlOZ8sNlKzHjh4VvLULFACZhn68XrX5DFg2FhMvSMJmROuFxRSa560ECWKBMg== load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -6837,17 +5971,14 @@ load-json-file@^1.0.0: loader.js@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.7.0.tgz#a1a52902001c83631efde9688b8ab3799325ef1f" - integrity sha512-9M2KvGT6duzGMgkOcTkWb+PR/Q2Oe54df/tLgHGVmFpAmtqJ553xJh6N63iFYI2yjo2PeJXbS5skHi/QpJq4vA== locate-character@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/locate-character/-/locate-character-2.0.5.tgz#f2d2614d49820ecb3c92d80d193b8db755f74c0f" - integrity sha512-n2GmejDXtOPBAZdIiEFy5dJ5N38xBCXLNOtw2WpB9kGh6pnrEuKlwYI+Tkpofc4wDtVXHtoAOJaMRlYG/oYaxg== locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= dependencies: p-locate "^2.0.0" path-exists "^3.0.0" @@ -6855,7 +5986,6 @@ locate-path@^2.0.0: locate-path@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== dependencies: p-locate "^3.0.0" path-exists "^3.0.0" @@ -6863,29 +5993,24 @@ locate-path@^3.0.0: lockfile@~1.0.1: version "1.0.4" resolved "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" - integrity sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA== dependencies: signal-exit "^3.0.2" lodash-node@^3.2.0: version "3.10.2" resolved "https://registry.yarnpkg.com/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" - integrity sha1-JZjVsbVOami0y1ROXHMJU8v2Mvc= lodash._arraycopy@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" - integrity sha1-due3wfH7klRzdIeKVi7Qaj5Q9uE= lodash._arrayeach@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" - integrity sha1-urFWsqkNPxu9XGU0AzSeXlkz754= lodash._baseassign@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" - integrity sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4= dependencies: lodash._basecopy "^3.0.0" lodash.keys "^3.0.0" @@ -6893,7 +6018,6 @@ lodash._baseassign@^3.0.0: lodash._basebind@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._basebind/-/lodash._basebind-2.3.0.tgz#2b5bc452a0e106143b21869f233bdb587417d248" - integrity sha1-K1vEUqDhBhQ7IYafIzvbWHQX0kg= dependencies: lodash._basecreate "~2.3.0" lodash._setbinddata "~2.3.0" @@ -6902,7 +6026,6 @@ lodash._basebind@~2.3.0: lodash._basecallback@^3.0.0: version "3.3.1" resolved "https://registry.npmjs.org/lodash._basecallback/-/lodash._basecallback-3.3.1.tgz#b7b2bb43dc2160424a21ccf26c57e443772a8e27" - integrity sha1-t7K7Q9whYEJKIczybFfkQ3cqjic= dependencies: lodash._baseisequal "^3.0.0" lodash._bindcallback "^3.0.0" @@ -6912,7 +6035,6 @@ lodash._basecallback@^3.0.0: lodash._baseclone@^3.0.0: version "3.3.0" resolved "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz#303519bf6393fe7e42f34d8b630ef7794e3542b7" - integrity sha1-MDUZv2OT/n5C802LYw73eU41Qrc= dependencies: lodash._arraycopy "^3.0.0" lodash._arrayeach "^3.0.0" @@ -6924,12 +6046,10 @@ lodash._baseclone@^3.0.0: lodash._basecopy@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" - integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY= lodash._basecreate@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz#9b88a86a4dcff7b7f3c61d83a2fcfc0671ec9de0" - integrity sha1-m4ioak3P97fzxh2Dovz8BnHsneA= dependencies: lodash._renative "~2.3.0" lodash.isobject "~2.3.0" @@ -6938,7 +6058,6 @@ lodash._basecreate@~2.3.0: lodash._basecreatecallback@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz#37b2ab17591a339e988db3259fcd46019d7ac362" - integrity sha1-N7KrF1kaM56YjbMln81GAZ16w2I= dependencies: lodash._setbinddata "~2.3.0" lodash.bind "~2.3.0" @@ -6948,7 +6067,6 @@ lodash._basecreatecallback@~2.3.0: lodash._basecreatewrapper@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz#aa0c61ad96044c3933376131483a9759c3651247" - integrity sha1-qgxhrZYETDkzN2ExSDqXWcNlEkc= dependencies: lodash._basecreate "~2.3.0" lodash._setbinddata "~2.3.0" @@ -6958,7 +6076,6 @@ lodash._basecreatewrapper@~2.3.0: lodash._basedifference@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/lodash._basedifference/-/lodash._basedifference-3.0.3.tgz#f2c204296c2a78e02b389081b6edcac933cf629c" - integrity sha1-8sIEKWwqeOArOJCBtu3KyTPPYpw= dependencies: lodash._baseindexof "^3.0.0" lodash._cacheindexof "^3.0.0" @@ -6967,7 +6084,6 @@ lodash._basedifference@^3.0.0: lodash._baseflatten@^3.0.0: version "3.1.4" resolved "https://registry.yarnpkg.com/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" - integrity sha1-B3D/gBMa9uNPO1EXlqe6UhTmX/c= dependencies: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" @@ -6975,17 +6091,14 @@ lodash._baseflatten@^3.0.0: lodash._basefor@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" - integrity sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI= lodash._baseindexof@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" - integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw= lodash._baseisequal@^3.0.0: version "3.0.7" resolved "https://registry.npmjs.org/lodash._baseisequal/-/lodash._baseisequal-3.0.7.tgz#d8025f76339d29342767dcc887ce5cb95a5b51f1" - integrity sha1-2AJfdjOdKTQnZ9zIh85cuVpbUfE= dependencies: lodash.isarray "^3.0.0" lodash.istypedarray "^3.0.0" @@ -6994,7 +6107,6 @@ lodash._baseisequal@^3.0.0: lodash._baseuniq@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-3.0.3.tgz#2123fa0db2d69c28d5beb1c1f36d61522a740234" - integrity sha1-ISP6DbLWnCjVvrHB821hUip0AjQ= dependencies: lodash._baseindexof "^3.0.0" lodash._cacheindexof "^3.0.0" @@ -7003,17 +6115,14 @@ lodash._baseuniq@^3.0.0: lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" - integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4= lodash._cacheindexof@^3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" - integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI= lodash._createassigner@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" - integrity sha1-g4pbri/aymOsIt7o4Z+k5taXCxE= dependencies: lodash._bindcallback "^3.0.0" lodash._isiterateecall "^3.0.0" @@ -7022,14 +6131,12 @@ lodash._createassigner@^3.0.0: lodash._createcache@^3.0.0: version "3.1.2" resolved "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" - integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM= dependencies: lodash._getnative "^3.0.0" lodash._createwrapper@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" - integrity sha1-0arhEC2t9EDo4G/BM6bt1/4UYHU= dependencies: lodash._basebind "~2.3.0" lodash._basecreatewrapper "~2.3.0" @@ -7038,54 +6145,44 @@ lodash._createwrapper@~2.3.0: lodash._escapehtmlchar@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.3.0.tgz#d03da6bd82eedf38dc0a5b503d740ecd0e894592" - integrity sha1-0D2mvYLu3zjcCltQPXQOzQ6JRZI= dependencies: lodash._htmlescapes "~2.3.0" lodash._escapestringchar@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._escapestringchar/-/lodash._escapestringchar-2.3.0.tgz#cce73ae60fc6da55d2bf8a0679c23ca2bab149fc" - integrity sha1-zOc65g/G2lXSv4oGecI8orqxSfw= lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= lodash._htmlescapes@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._htmlescapes/-/lodash._htmlescapes-2.3.0.tgz#1ca98863cadf1fa1d82c84f35f31e40556a04f3a" - integrity sha1-HKmIY8rfH6HYLITzXzHkBVagTzo= lodash._isiterateecall@^3.0.0: version "3.0.9" resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" - integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw= lodash._objecttypes@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz#6a3ea3987dd6eeb8021b2d5c9c303549cc2bae1e" - integrity sha1-aj6jmH3W7rgCGy1cnDA1Scwrrh4= lodash._reinterpolate@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-2.3.0.tgz#03ee9d85c0e55cbd590d71608a295bdda51128ec" - integrity sha1-A+6dhcDlXL1ZDXFgiilb3aURKOw= lodash._reinterpolate@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= lodash._renative@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._renative/-/lodash._renative-2.3.0.tgz#77d8edd4ced26dd5971f9e15a5f772e4e317fbd3" - integrity sha1-d9jt1M7SbdWXH54Vpfdy5OMX+9M= lodash._reunescapedhtml@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.3.0.tgz#db920b55ac7f3ff825939aceb9ba2c231713d24d" - integrity sha1-25ILVax/P/glk5rOubosIxcT0k0= dependencies: lodash._htmlescapes "~2.3.0" lodash.keys "~2.3.0" @@ -7093,7 +6190,6 @@ lodash._reunescapedhtml@~2.3.0: lodash._setbinddata@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz#e5610490acd13277d59858d95b5f2727f1508f04" - integrity sha1-5WEEkKzRMnfVmFjZW18nJ/FQjwQ= dependencies: lodash._renative "~2.3.0" lodash.noop "~2.3.0" @@ -7101,19 +6197,16 @@ lodash._setbinddata@~2.3.0: lodash._shimkeys@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz#611f93149e3e6c721096b48769ef29537ada8ba9" - integrity sha1-YR+TFJ4+bHIQlrSHae8pU3rai6k= dependencies: lodash._objecttypes "~2.3.0" lodash._slice@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash._slice/-/lodash._slice-2.3.0.tgz#147198132859972e4680ca29a5992c855669aa5c" - integrity sha1-FHGYEyhZly5GgMoppZkshVZpqlw= lodash.assign@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" - integrity sha1-POnwI0tLIiPilrj6CsH+6OvKZPo= dependencies: lodash._baseassign "^3.0.0" lodash._createassigner "^3.0.0" @@ -7122,12 +6215,10 @@ lodash.assign@^3.2.0: lodash.assignin@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" - integrity sha1-uo31+4QesKPoBEIysOJjqNxqKKI= lodash.bind@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-2.3.0.tgz#c2a8e18b68e5ecc152e2b168266116fea5b016cc" - integrity sha1-wqjhi2jl7MFS4rFoJmEW/qWwFsw= dependencies: lodash._createwrapper "~2.3.0" lodash._renative "~2.3.0" @@ -7136,17 +6227,14 @@ lodash.bind@~2.3.0: lodash.castarray@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" - integrity sha1-wCUTUV4wna3dTCTGDP3c9ZdtkRU= lodash.clonedeep@^4.4.1: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= lodash.clonedeep@~3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz#a0a1e40d82a5ea89ff5b147b8444ed63d92827db" - integrity sha1-oKHkDYKl6on/WxR7hETtY9koJ9s= dependencies: lodash._baseclone "^3.0.0" lodash._bindcallback "^3.0.0" @@ -7154,14 +6242,12 @@ lodash.clonedeep@~3.0.2: lodash.debounce@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" - integrity sha1-gSIRw3ipTMKdWqTjNGzwv846ffU= dependencies: lodash._getnative "^3.0.0" lodash.defaults@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-2.3.0.tgz#a832b001f138f3bb9721c2819a2a7cc5ae21ed25" - integrity sha1-qDKwAfE487uXIcKBmip8xa4h7SU= dependencies: lodash._objecttypes "~2.3.0" lodash.keys "~2.3.0" @@ -7169,12 +6255,10 @@ lodash.defaults@~2.3.0: lodash.defaultsdeep@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.0.tgz#bec1024f85b1bd96cbea405b23c14ad6443a6f81" - integrity sha1-vsECT4WxvZbL6kBbI8FK1kQ6b4E= lodash.escape@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-2.3.0.tgz#844c38c58f844e1362ebe96726159b62cf5f2a58" - integrity sha1-hEw4xY+EThNi6+lnJhWbYs9fKlg= dependencies: lodash._escapehtmlchar "~2.3.0" lodash._reunescapedhtml "~2.3.0" @@ -7183,12 +6267,10 @@ lodash.escape@~2.3.0: lodash.find@^4.5.1: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" - integrity sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E= lodash.flatten@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" - integrity sha1-3hz1d1j49EeTGdNcPpzGDEUBk4w= dependencies: lodash._baseflatten "^3.0.0" lodash._isiterateecall "^3.0.0" @@ -7196,7 +6278,6 @@ lodash.flatten@^3.0.2: lodash.foreach@~2.3.x: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-2.3.0.tgz#083404c91e846ee77245fdf9d76519c68b2af168" - integrity sha1-CDQEyR6EbudyRf3512UZxosq8Wg= dependencies: lodash._basecreatecallback "~2.3.0" lodash.forown "~2.3.0" @@ -7204,7 +6285,6 @@ lodash.foreach@~2.3.x: lodash.forown@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.forown/-/lodash.forown-2.3.0.tgz#24fb4aaf800d45fc2dc60bfec3ce04c836a3ad7f" - integrity sha1-JPtKr4ANRfwtxgv+w84EyDajrX8= dependencies: lodash._basecreatecallback "~2.3.0" lodash._objecttypes "~2.3.0" @@ -7213,39 +6293,32 @@ lodash.forown@~2.3.0: lodash.identity@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.identity/-/lodash.identity-2.3.0.tgz#6b01a210c9485355c2a913b48b6711219a173ded" - integrity sha1-awGiEMlIU1XCqRO0i2cRIZoXPe0= lodash.isarguments@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" - integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= lodash.isfunction@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz#6b2973e47a647cf12e70d676aea13643706e5267" - integrity sha1-aylz5HpkfPEucNZ2rqE2Q3BuUmc= lodash.isobject@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-2.3.0.tgz#2e16d3fc583da9831968953f2d8e6d73434f6799" - integrity sha1-LhbT/Fg9qYMZaJU/LY5tc0NPZ5k= dependencies: lodash._objecttypes "~2.3.0" lodash.istypedarray@^3.0.0: version "3.0.6" resolved "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" - integrity sha1-yaR3SYYHUB2OhJTSg7h8OSgc72I= lodash.keys@^3.0.0: version "3.1.2" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" - integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo= dependencies: lodash._getnative "^3.0.0" lodash.isarguments "^3.0.0" @@ -7254,7 +6327,6 @@ lodash.keys@^3.0.0: lodash.keys@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-2.3.0.tgz#b350f4f92caa9f45a4a2ecf018454cf2f28ae253" - integrity sha1-s1D0+Syqn0WkouzwGEVM8vKK4lM= dependencies: lodash._renative "~2.3.0" lodash._shimkeys "~2.3.0" @@ -7263,56 +6335,46 @@ lodash.keys@~2.3.0: lodash.merge@^4.3.1, lodash.merge@^4.6.0: version "4.6.1" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" - integrity sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ== lodash.noop@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-2.3.0.tgz#3059d628d51bbf937cd2a0b6fc3a7f212a669c2c" - integrity sha1-MFnWKNUbv5N80qC2/Dp/ISpmnCw= lodash.omit@^4.1.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" - integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA= lodash.pad@^4.1.0: version "4.5.1" resolved "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz#4330949a833a7c8da22cc20f6a26c4d59debba70" - integrity sha1-QzCUmoM6fI2iLMIPaibE1Z3runA= lodash.padend@^4.1.0: version "4.6.1" resolved "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e" - integrity sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4= lodash.padstart@^4.1.0: version "4.6.1" resolved "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b" - integrity sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs= lodash.pairs@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/lodash.pairs/-/lodash.pairs-3.0.1.tgz#bbe08d5786eeeaa09a15c91ebf0dcb7d2be326a9" - integrity sha1-u+CNV4bu6qCaFckevw3LfSvjJqk= dependencies: lodash.keys "^3.0.0" lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" - integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= lodash.support@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.support/-/lodash.support-2.3.0.tgz#7eaf038af4f0d6aab776b44aa6dcfc80334c9bfd" - integrity sha1-fq8DivTw1qq3drRKptz8gDNMm/0= dependencies: lodash._renative "~2.3.0" lodash.template@^4.4.0: version "4.4.0" resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" - integrity sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A= dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings "^4.0.0" @@ -7320,7 +6382,6 @@ lodash.template@^4.4.0: lodash.template@~2.3.x: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-2.3.0.tgz#4e3e29c433b4cfea675ec835e6f12391c61fd22b" - integrity sha1-Tj4pxDO0z+pnXsg15vEjkcYf0is= dependencies: lodash._escapestringchar "~2.3.0" lodash._reinterpolate "~2.3.0" @@ -7333,14 +6394,12 @@ lodash.template@~2.3.x: lodash.templatesettings@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" - integrity sha1-K01OlbpEDZFf8IvImeRVNmZxMxY= dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-2.3.0.tgz#303d132c342710040d5a18efaa2d572fd03f8cdc" - integrity sha1-MD0TLDQnEAQNWhjvqi1XL9A/jNw= dependencies: lodash._reinterpolate "~2.3.0" lodash.escape "~2.3.0" @@ -7348,7 +6407,6 @@ lodash.templatesettings@~2.3.0: lodash.union@~3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-3.1.0.tgz#a4a3066fc15d6a7f8151cce9bdfe63dce7f5bcff" - integrity sha1-pKMGb8Fdan+BUczpvf5j3Of1vP8= dependencies: lodash._baseflatten "^3.0.0" lodash._baseuniq "^3.0.0" @@ -7357,12 +6415,10 @@ lodash.union@~3.1.0: lodash.uniq@^4.2.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= lodash.uniq@~3.2.2: version "3.2.2" resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-3.2.2.tgz#146c36f25e75d19501ba402e88ba14937f63cd8b" - integrity sha1-FGw28l510ZUBukAuiLoUk39jzYs= dependencies: lodash._basecallback "^3.0.0" lodash._baseuniq "^3.0.0" @@ -7373,19 +6429,16 @@ lodash.uniq@~3.2.2: lodash.uniqby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" - integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= lodash.values@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-2.3.0.tgz#ca96fbe60a20b0b0ec2ba2ba5fc6a765bd14a3ba" - integrity sha1-ypb75gogsLDsK6K6X8anZb0Uo7o= dependencies: lodash.keys "~2.3.0" lodash.without@~3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/lodash.without/-/lodash.without-3.2.1.tgz#d69614b3512e52294b6abab782e7ca96538ce816" - integrity sha1-1pYUs1EuUilLarq3gufKllOM6BY= dependencies: lodash._basedifference "^3.0.0" lodash.restparam "^3.0.0" @@ -7393,36 +6446,30 @@ lodash.without@~3.2.1: lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.6.1: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" - integrity sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg== lodash@^4.17.11: version "4.17.11" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" - integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== dependencies: chalk "^2.0.1" longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" - integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= loose-envify@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: js-tokens "^3.0.0 || ^4.0.0" loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= dependencies: currently-unhandled "^0.4.1" signal-exit "^3.0.0" @@ -7430,22 +6477,18 @@ loud-rejection@^1.0.0: lowercase-keys@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" - integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== lru-cache@2: version "2.7.3" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" - integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI= lru-cache@^4.0.1: version "4.1.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" - integrity sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA== dependencies: pseudomap "^1.0.2" yallist "^2.1.2" @@ -7453,50 +6496,42 @@ lru-cache@^4.0.1: magic-string@^0.24.0: version "0.24.1" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.24.1.tgz#7e38e5f126cae9f15e71f0cf8e450818ca7d5a8f" - integrity sha512-YBfNxbJiixMzxW40XqJEIldzHyh5f7CZKalo1uZffevyrPEX8Qgo9s0dmcORLHdV47UyvJg8/zD+6hQG3qvJrA== dependencies: sourcemap-codec "^1.4.1" make-array@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" - integrity sha1-M14267DFpDFU0hIToeyuriobs+8= make-dir@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== dependencies: pify "^3.0.0" makeerror@1.0.x: version "1.0.11" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" - integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= dependencies: tmpl "1.0.x" map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= dependencies: object-visit "^1.0.0" markdown-it-terminal@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/markdown-it-terminal/-/markdown-it-terminal-0.1.0.tgz#545abd8dd01c3d62353bfcea71db580b51d22bd9" - integrity sha1-VFq9jdAcPWI1O/zqcdtYC1HSK9k= dependencies: ansi-styles "^3.0.0" cardinal "^1.0.0" @@ -7507,7 +6542,6 @@ markdown-it-terminal@0.1.0: markdown-it@^4.3.0: version "4.4.0" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" - integrity sha1-PfNz2+pYepp/7z5WMRtokI91xBQ= dependencies: argparse "~1.0.2" entities "~1.1.1" @@ -7518,7 +6552,6 @@ markdown-it@^4.3.0: markdown-it@^8.3.1, markdown-it@^8.4.2: version "8.4.2" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54" - integrity sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ== dependencies: argparse "^1.0.7" entities "~1.1.1" @@ -7529,41 +6562,34 @@ markdown-it@^8.3.1, markdown-it@^8.4.2: matcher-collection@^1.0.0, matcher-collection@^1.0.4, matcher-collection@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-1.0.5.tgz#2ee095438372cb8884f058234138c05c644ec339" - integrity sha512-nUCmzKipcJEwYsBVAFh5P+d7JBuhJaW1xs85Hara9xuMLqtCVUrW6DSC0JVIkluxEH2W45nPBM/wjHtBXa/tYA== dependencies: minimatch "^3.0.2" math-random@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" - integrity sha1-izqsWIuKZuSXXjzepn97sylgH6w= mdn-links@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" - integrity sha1-4kyDuXy0xYhsw58veAcF+/4nOqU= mdurl@^1.0.1, mdurl@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" - integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= memory-streams@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.3.tgz#d9b0017b4b87f1d92f55f2745c9caacb1dc93ceb" - integrity sha512-qVQ/CjkMyMInPaaRMrwWNDvf6boRZXaT/DbQeMYcCWuXPEBf1v8qChOc9OlEVQp2uOvRXa1Qu30fLmKhY6NipA== dependencies: readable-stream "~1.0.2" meow@^3.4.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= dependencies: camelcase-keys "^2.0.0" decamelize "^1.1.2" @@ -7579,12 +6605,10 @@ meow@^3.4.0: merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= merge-trees@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-trees/-/merge-trees-1.0.1.tgz#ccbe674569787f9def17fd46e6525f5700bbd23e" - integrity sha1-zL5nRWl4f53vF/1G5lJfVwC70j4= dependencies: can-symlink "^1.0.0" fs-tree-diff "^0.5.4" @@ -7596,7 +6620,6 @@ merge-trees@^1.0.1: merge-trees@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-trees/-/merge-trees-2.0.0.tgz#a560d796e566c5d9b2c40472a2967cca48d85161" - integrity sha512-5xBbmqYBalWqmhYm51XlohhkmVOua3VAUrrWh8t9iOkaLpS6ifqm/UVuUjQCeDVJ9Vx3g2l6ihfkbLSTeKsHbw== dependencies: fs-updater "^1.0.4" heimdalljs "^0.2.5" @@ -7604,17 +6627,14 @@ merge-trees@^2.0.0: merge@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" - integrity sha1-dTHjnUlJwoGma4xabgJl6LBYlNo= methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= micromatch@^2.3.11: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= dependencies: arr-diff "^2.0.0" array-unique "^0.2.1" @@ -7633,7 +6653,6 @@ micromatch@^2.3.11: micromatch@^3.0.4, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" @@ -7652,56 +6671,46 @@ micromatch@^3.0.4, micromatch@^3.1.4: "mime-db@>= 1.34.0 < 2", mime-db@~1.35.0: version "1.35.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" - integrity sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg== mime-db@~1.37.0: version "1.37.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" - integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== mime-types@^2.1.11, mime-types@^2.1.12, mime-types@^2.1.19, mime-types@~2.1.19, mime-types@~2.1.7: version "2.1.21" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" - integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg== dependencies: mime-db "~1.37.0" mime-types@^2.1.18, mime-types@~2.1.18: version "2.1.19" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" - integrity sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw== dependencies: mime-db "~1.35.0" mime-types@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" - integrity sha1-mVrhOSq4r/y/yyZB3QVOlDwNXc4= mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" - integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== mime@~1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" - integrity sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA= mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== minimatch@1: version "1.0.0" resolved "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz#e0dd2120b49e1b724ce8d714c520822a9438576d" - integrity sha1-4N0hILSeG3JM6NcUxSCCKpQ4V20= dependencies: lru-cache "2" sigmund "~1.0.0" @@ -7709,36 +6718,30 @@ minimatch@1: "minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" minimatch@^2.0.1: version "2.0.10" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" - integrity sha1-jQh8OcazjAAbl/ynzm0OHoCvusc= dependencies: brace-expansion "^1.0.0" minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= minipass@^2.2.0, minipass@^2.2.1, minipass@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" - integrity sha512-/jAn9/tEX4gnpyRATxgHEOV6xbcyxgT7iUnxo9Y3+OB0zX00TgKIv/2FZCf5brBbICcwbLqVv2ImjvWWrQMSYw== dependencies: safe-buffer "^5.1.2" yallist "^3.0.0" @@ -7746,14 +6749,12 @@ minipass@^2.2.0, minipass@^2.2.1, minipass@^2.3.3: minizlib@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" - integrity sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA== dependencies: minipass "^2.2.1" mixin-deep@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" - integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== dependencies: for-in "^1.0.2" is-extendable "^1.0.1" @@ -7761,19 +6762,16 @@ mixin-deep@^1.2.0: mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= dependencies: minimist "0.0.8" mktemp@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" - integrity sha1-bQUVYRyKjITkhKogABKbmOmB/ws= mocha-only-detector@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mocha-only-detector/-/mocha-only-detector-1.0.0.tgz#183c710afffcca79df172daf76c45afca3b8e37d" - integrity sha1-GDxxCv/8ynnfFy2vdsRa/KO4430= dependencies: esprima "^4.0.0" esprimaq "^0.0.1" @@ -7782,7 +6780,6 @@ mocha-only-detector@1.0.0: mocha@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" - integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== dependencies: browser-stdout "1.3.1" commander "2.15.1" @@ -7799,19 +6796,16 @@ mocha@^5.2.0: moment-timezone@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" - integrity sha1-PvR4VrAtU7cYoQpewgI6opnge/U= dependencies: moment ">= 2.6.0" "moment@>= 2.6.0": version "2.22.2" resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" - integrity sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y= morgan@^1.9.0: version "1.9.1" resolved "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz#0a8d16734a1d9afbc824b99df87e738e58e2da59" - integrity sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA== dependencies: basic-auth "~2.0.0" debug "2.6.9" @@ -7822,42 +6816,34 @@ morgan@^1.9.0: mout@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mout/-/mout-1.1.0.tgz#0b29d41e6a80fa9e2d4a5be9d602e1d9d02177f6" - integrity sha512-XsP0vf4As6BfqglxZqbqQ8SR6KQot2AgxvR0gG+WtUkf90vUXchMOZQtPf/Hml1rEffJupqL/tIrU6EYhsUQjw== ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= ms@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== mustache@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/mustache/-/mustache-3.0.0.tgz#3de22dd9ba38152f7355399a953dd4528c403338" - integrity sha512-bhBDkK/PioIbtQzRIbGUGypvc3MC4c389QnJt8KDIEJ666OidRPoXAQAHPivikfS3JkMEaWoPvcDL7YrQxtSwg== mute-stream@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" - integrity sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s= mute-stream@0.0.7, mute-stream@~0.0.4: version "0.0.7" resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= nan@^2.9.2: version "2.10.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" - integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA== nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" @@ -7874,12 +6860,10 @@ nanomatch@^1.2.9: natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= needle@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" - integrity sha512-t/ZswCM9JTWjAdXS9VpvqhI2Ct2sL2MdY4fUXqGJaGBk13ge99ObqRksRTbBE56K+wxUXwwfZYOuZHifFW9q+Q== dependencies: debug "^2.1.2" iconv-lite "^0.4.4" @@ -7888,22 +6872,18 @@ needle@^2.2.1: negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" - integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= next-tick@1: version "1.0.0" resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" - integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= nice-try@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" - integrity sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA== node-gyp@~3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-3.2.1.tgz#f5dd569970a508464cc3c15d7e9e8d2de8638dd5" - integrity sha1-9d1WmXClCEZMw8Fdfp6NLehjjdU= dependencies: fstream "^1.0.0" glob "3 || 4" @@ -7923,17 +6903,14 @@ node-gyp@~3.2.1: node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= node-modules-path@^1.0.0, node-modules-path@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" - integrity sha1-QAlrCM560OoUaAhjr0ScfHWl0cg= node-notifier@^5.0.1: version "5.2.1" resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" - integrity sha512-MIBs+AAd6dJ2SklbbE8RUDRlIVhU8MaNLh1A9SUZDUHPiZkWLFde6UNwG41yQHZEToHgJMXqyVZ9UcS/ReOVTg== dependencies: growly "^1.3.0" semver "^5.4.1" @@ -7943,7 +6920,6 @@ node-notifier@^5.0.1: node-pre-gyp@^0.10.0: version "0.10.3" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" - integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== dependencies: detect-libc "^1.0.2" mkdirp "^0.5.1" @@ -7959,26 +6935,22 @@ node-pre-gyp@^0.10.0: node-releases@^1.0.0-alpha.15: version "1.0.0-alpha.15" resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.0.0-alpha.15.tgz#bdb08730287cc50ddbfa3c1a358366a4a2f5d397" - integrity sha512-hKG6hd/g6a9OV/ARt2qrxbRhe/4WEMFohTLOB9PNyTYvvI59gICZFzt9/mMgpYUTts06qXlN8H6UjfbIRdnW8A== dependencies: semver "^5.3.0" node-uuid@~1.4.0, node-uuid@~1.4.7: version "1.4.8" resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" - integrity sha1-sEDrCSOWivq/jTL7HxfxFn/auQc= "nopt@2 || 3", nopt@^3.0.3, nopt@^3.0.6, nopt@~3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= dependencies: abbrev "1" nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= dependencies: abbrev "1" osenv "^0.1.4" @@ -7986,12 +6958,10 @@ nopt@^4.0.1: normalize-git-url@~3.0.1: version "3.0.2" resolved "https://registry.npmjs.org/normalize-git-url/-/normalize-git-url-3.0.2.tgz#8e5f14be0bdaedb73e07200310aa416c27350fc4" - integrity sha1-jl8Uvgva7bc+ByADEKpBbCc1D8Q= normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, "normalize-package-data@~1.0.1 || ^2.0.0": version "2.4.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" - integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw== dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -8001,7 +6971,6 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package- normalize-package-data@~2.3.5: version "2.3.8" resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" - integrity sha1-2Bntoqne29H/pWPqQHHZNngilbs= dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" @@ -8011,14 +6980,12 @@ normalize-package-data@~2.3.5: normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= dependencies: remove-trailing-separator "^1.0.1" normalize-url@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" - integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== dependencies: prepend-http "^2.0.0" query-string "^5.0.1" @@ -8027,22 +6994,18 @@ normalize-url@2.0.1: npm-bundled@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" - integrity sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow== npm-cache-filename@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" - integrity sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE= npm-git-info@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" - integrity sha1-qTPELsMh6A02RuDW6ESv6UYw4dU= npm-install-checks@~2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-2.0.1.tgz#a93540b53f04fa9d916d2733d6541f6db7d88e46" - integrity sha1-qTVAtT8E+p2RbScz1lQfbbfYjkY= dependencies: npmlog "0.1 || 1" semver "^2.3.0 || 3.x || 4 || 5" @@ -8050,7 +7013,6 @@ npm-install-checks@~2.0.1: "npm-package-arg@^3.0.0 || ^4.0.0", npm-package-arg@^4.1.1: version "4.2.1" resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" - integrity sha1-WTMD/eqF98Qid18X+et2cPaA4+w= dependencies: hosted-git-info "^2.1.5" semver "^5.1.0" @@ -8058,7 +7020,6 @@ npm-install-checks@~2.0.1: "npm-package-arg@^4.0.0 || ^5.0.0": version "5.1.2" resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-5.1.2.tgz#fb18d17bb61e60900d6312619919bd753755ab37" - integrity sha512-wJBsrf0qpypPT7A0LART18hCdyhpCMxeTtcb0X4IZO2jsP6Om7EHN1d9KSKiqD+KVH030RVNpWS9thk+pb7wzA== dependencies: hosted-git-info "^2.4.2" osenv "^0.1.4" @@ -8068,7 +7029,6 @@ npm-install-checks@~2.0.1: npm-package-arg@^6.1.0: version "6.1.0" resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" - integrity sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA== dependencies: hosted-git-info "^2.6.0" osenv "^0.1.5" @@ -8078,7 +7038,6 @@ npm-package-arg@^6.1.0: npm-package-arg@~4.1.0: version "4.1.1" resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.1.1.tgz#86d9dca985b4c5e5d59772dfd5de6919998a495a" - integrity sha1-htncqYW0xeXVl3Lf1d5pGZmKSVo= dependencies: hosted-git-info "^2.1.4" semver "4 || 5" @@ -8086,7 +7045,6 @@ npm-package-arg@~4.1.0: npm-packlist@^1.1.6: version "1.1.10" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" - integrity sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA== dependencies: ignore-walk "^3.0.1" npm-bundled "^1.0.1" @@ -8094,7 +7052,6 @@ npm-packlist@^1.1.6: npm-registry-client@~7.0.9: version "7.0.9" resolved "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-7.0.9.tgz#1baf86ee5285c4e6d38d4556208ded56049231bb" - integrity sha1-G6+G7lKFxObTjUVWII3tVgSSMbs= dependencies: chownr "^1.0.1" concat-stream "^1.4.6" @@ -8114,19 +7071,16 @@ npm-registry-client@~7.0.9: npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= dependencies: path-key "^2.0.0" npm-user-validate@~0.1.2: version "0.1.5" resolved "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-0.1.5.tgz#52465d50c2d20294a57125b996baedbf56c5004b" - integrity sha1-UkZdUMLSApSlcSW5lrrtv1bFAEs= npm@~3.5.2: version "3.5.4" resolved "http://registry.npmjs.org/npm/-/npm-3.5.4.tgz#db2f71d3daa0e7a99077edd4c213919834e95eb2" - integrity sha1-2y9x09qg56mQd+3UwhORmDTpXrI= dependencies: abbrev "~1.0.7" ansicolors "~0.3.2" @@ -8201,7 +7155,6 @@ npm@~3.5.2: "npmlog@0 || 1", "npmlog@0.1 || 1": version "1.2.1" resolved "http://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz#28e7be619609b53f7ad1dd300a10d64d716268b6" - integrity sha1-KOe+YZYJtT960d0wChDWTXFiaLY= dependencies: ansi "~0.3.0" are-we-there-yet "~1.0.0" @@ -8210,7 +7163,6 @@ npm@~3.5.2: npmlog@^4.0.0, npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" @@ -8220,7 +7172,6 @@ npmlog@^4.0.0, npmlog@^4.0.2: npmlog@~2.0.0: version "2.0.4" resolved "http://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz#98b52530f2514ca90d09ec5b22c8846722375692" - integrity sha1-mLUlMPJRTKkNCexbIsiEZyI3VpI= dependencies: ansi "~0.3.1" are-we-there-yet "~1.1.2" @@ -8229,37 +7180,30 @@ npmlog@~2.0.0: number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= oauth-sign@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" - integrity sha1-y1QPk7srIqfVlBaRoojWDo6pOG4= oauth-sign@~0.8.0: version "0.8.2" resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM= oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" - integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE= object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" @@ -8268,19 +7212,16 @@ object-copy@^0.1.0: object-keys@^1.0.8: version "1.0.12" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" - integrity sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag== object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= dependencies: isobject "^3.0.0" object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= dependencies: for-own "^0.1.4" is-extendable "^0.1.1" @@ -8288,57 +7229,48 @@ object.omit@^2.0.0: object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= dependencies: isobject "^3.0.1" on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= dependencies: ee-first "1.1.1" on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" - integrity sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c= once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" once@~1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" - integrity sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA= dependencies: wrappy "1" onetime@^1.0.0: version "1.1.0" resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k= onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= dependencies: mimic-fn "^1.0.0" opener@~1.4.1: version "1.4.3" resolved "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" - integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg= optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= dependencies: minimist "~0.0.1" wordwrap "~0.0.2" @@ -8346,7 +7278,6 @@ optimist@^0.6.1: optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= dependencies: deep-is "~0.1.3" fast-levenshtein "~2.0.4" @@ -8358,7 +7289,6 @@ optionator@^0.8.2: ora@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" - integrity sha512-hNNlAd3gfv/iPmsNxYoAPLvxg7HuPozww7fFonMZvL84tP6Ox5igfk5j/+a9rtJJwqMgKK+JgWsAQik5o0HTLA== dependencies: chalk "^2.3.1" cli-cursor "^2.1.0" @@ -8370,22 +7300,18 @@ ora@^2.0.0: os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= os-shim@^0.1.2: version "0.1.3" resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" - integrity sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc= os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= osenv@0, osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4, osenv@^0.1.5, osenv@~0.1.3: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" @@ -8393,67 +7319,56 @@ osenv@0, osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4, osenv@^0.1.5, osenv@~0.1.3: p-cancelable@^0.4.0: version "0.4.1" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" - integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= p-is-promise@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" - integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== dependencies: p-try "^1.0.0" p-limit@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec" - integrity sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A== dependencies: p-try "^2.0.0" p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= dependencies: p-limit "^1.1.0" p-locate@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== dependencies: p-limit "^2.0.0" p-timeout@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" - integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== dependencies: p-finally "^1.0.0" p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= p-try@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1" - integrity sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ== package-json@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" - integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0= dependencies: got "^6.7.1" registry-auth-token "^3.0.1" @@ -8463,7 +7378,6 @@ package-json@^4.0.1: parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= dependencies: glob-base "^0.3.0" is-dotfile "^1.0.0" @@ -8473,104 +7387,86 @@ parse-glob@^3.0.4: parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= dependencies: error-ex "^1.2.0" parse-ms@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d" - integrity sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0= parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" - integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= parseqs@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" - integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0= dependencies: better-assert "~1.0.0" parseuri@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" - integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo= dependencies: better-assert "~1.0.0" parseurl@~1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" - integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= passwd-user@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/passwd-user/-/passwd-user-1.2.1.tgz#a01a5dc639ef007dc56364b8178569080ad3a7b8" - integrity sha1-oBpdxjnvAH3FY2S4F4VpCArTp7g= dependencies: exec-file-sync "^2.0.0" path-array@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271" - integrity sha1-fi8PNfB6IBUSK4aLfqwOssT+wnE= dependencies: array-index "^1.0.0" path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= dependencies: pinkie-promise "^2.0.0" path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= path-is-absolute@1.0.1, path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" - integrity sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME= path-posix@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" - integrity sha1-BrJhE/Vr6rBCVFojv6iAA8ysJg8= path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= dependencies: graceful-fs "^4.1.2" pify "^2.0.0" @@ -8579,51 +7475,42 @@ path-type@^1.0.0: pathval@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" - integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= performance-now@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" - integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= dependencies: find-up "^2.1.0" pluralize@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" - integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== portfinder@^1.0.15: version "1.0.19" resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.19.tgz#07e87914a55242dcda5b833d42f018d6875b595f" - integrity sha512-23aeQKW9KgHe6citUrG3r9HjeX6vls0h713TAa+CwTKZwNIr/pD2ApaxYF4Um3ZZyq4ar+Siv3+fhoHaIwSOSw== dependencies: async "^1.5.2" debug "^2.2.0" @@ -8632,32 +7519,26 @@ portfinder@^1.0.15: posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= prepend-http@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= prepend-http@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= pretender@^2.1.0: version "2.1.1" resolved "https://registry.npmjs.org/pretender/-/pretender-2.1.1.tgz#5085f0a1272c31d5b57c488386f69e6ca207cb35" - integrity sha512-IkidsJzaroAanw3I43tKCFm2xCpurkQr9aPXv5/jpN+LfCwDaeI8rngVWtQZTx4qqbhc5zJspnLHJ4N/25KvDQ== dependencies: "@xg-wang/whatwg-fetch" "^3.0.0" fake-xml-http-request "^2.0.0" @@ -8666,65 +7547,54 @@ pretender@^2.1.0: prettier-linter-helpers@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== dependencies: fast-diff "^1.1.2" prettier@^1.14.3: version "1.14.3" resolved "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz#90238dd4c0684b7edce5f83b0fb7328e48bd0895" - integrity sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg== pretty-ms@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-3.2.0.tgz#87a8feaf27fc18414d75441467d411d6e6098a25" - integrity sha512-ZypexbfVUGTFxb0v+m1bUyy92DHe5SyYlnyY0msyms5zd3RwyvNgyxZZsXXgoyzlxjx5MiqtXUdhUfvQbe0A2Q== dependencies: parse-ms "^1.0.0" printf@^0.5.1: version "0.5.1" resolved "https://registry.npmjs.org/printf/-/printf-0.5.1.tgz#e0466788260859ed153006dc6867f09ddf240cf3" - integrity sha512-UaE/jO0hNsrvPGQEb4LyNzcrJv9Z00tsreBduOSxMtrebvoUhxiEJ4YCHX8YHf6akwfKsC2Gyv5zv47UXhMiLg== private@^0.1.6, private@^0.1.8, private@~0.1.5: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= process-nextick-args@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== process-relative-require@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" - integrity sha1-FZDfz1uPKYO6U+OYRGtoJAtMxoo= dependencies: node-modules-path "^1.0.0" progress@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" - integrity sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8= promise-map-series@^0.2.1, promise-map-series@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" - integrity sha1-wtN3r8kyU/a9A9u3d1XriKsgqEc= dependencies: rsvp "^3.0.14" promise.prototype.finally@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz#66f161b1643636e50e7cf201dc1b84a857f3864e" - integrity sha512-7p/K2f6dI+dM8yjRQEGrTQs5hTQixUAdOGpMEA3+pVxpX5oHKRSKAXyLw9Q9HUWDTdwtoo39dSHGQtN90HcEwQ== dependencies: define-properties "^1.1.2" es-abstract "^1.9.0" @@ -8733,19 +7603,16 @@ promise.prototype.finally@^3.1.0: promzard@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" - integrity sha1-JqXW7ox97kyxIggwWs+5O6OCqe4= dependencies: read "1" proto-list@~1.2.1: version "1.2.4" resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= proxy-addr@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" - integrity sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ== dependencies: forwarded "~0.1.2" ipaddr.js "1.6.0" @@ -8753,7 +7620,6 @@ proxy-addr@~2.0.3: proxy-addr@~2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" - integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA== dependencies: forwarded "~0.1.2" ipaddr.js "1.8.0" @@ -8761,17 +7627,14 @@ proxy-addr@~2.0.4: pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= psl@^1.1.24: version "1.1.28" resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.28.tgz#4fb6ceb08a1e2214d4fd4de0ca22dae13740bc7b" - integrity sha512-+AqO1Ae+N/4r7Rvchrdm432afjT9hqJRyBN3DQv9At0tPz4hIFSGKbq64fN9dVoCow4oggIIax5/iONx0r9hZw== pump@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== dependencies: end-of-stream "^1.1.0" once "^1.3.1" @@ -8779,37 +7642,30 @@ pump@^3.0.0: punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== qs@6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" - integrity sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A== qs@6.5.2, qs@^6.4.0, qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== qs@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" - integrity sha1-UKk+K1r2aRwxvOpdrnjubqGQN2g= qs@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/qs/-/qs-5.2.1.tgz#801fee030e0b9450d6385adc48a4cc55b44aedfc" - integrity sha1-gB/uAw4LlFDWOFrcSKTMVbRK7fw= query-string@^5.0.1: version "5.1.1" resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" - integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== dependencies: decode-uri-component "^0.2.0" object-assign "^4.1.0" @@ -8818,7 +7674,6 @@ query-string@^5.0.1: quibble@^0.5.5: version "0.5.5" resolved "https://registry.yarnpkg.com/quibble/-/quibble-0.5.5.tgz#669fb731520a923e0a98f8076b7eb55e409f73f9" - integrity sha512-cIePu3BtGlaTW1bjFgBcLT6QMxD8PtnZDCmPJUzO+RepIz8GuXsmZIEPGFjlPxzG9zfIj4nNLPxBDlUbvr9ESg== dependencies: lodash "^4.17.2" resolve "^1.7.1" @@ -8826,7 +7681,6 @@ quibble@^0.5.5: quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" - integrity sha1-urAqJCq4+w3XWKPJd2sy+aXZRAg= dependencies: mktemp "~0.4.0" rimraf "^2.5.4" @@ -8835,7 +7689,6 @@ quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: qunit@~2.6.0: version "2.6.2" resolved "https://registry.npmjs.org/qunit/-/qunit-2.6.2.tgz#551210c5cf857258a4fe39a7fe15d9e14dfef22c" - integrity sha512-PHbKulmd4rrDhFto7iHicIstDTX7oMRvAcI7loHstvU8J7AOGwzcchONmy+EG4KU8HDk0K90o7vO0GhlYyKlOg== dependencies: commander "2.12.2" exists-stat "1.0.0" @@ -8848,7 +7701,6 @@ qunit@~2.6.0: randomatic@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.0.0.tgz#d35490030eb4f7578de292ce6dfb04a91a128923" - integrity sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA== dependencies: is-number "^4.0.0" kind-of "^6.0.0" @@ -8857,12 +7709,10 @@ randomatic@^3.0.0: range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= raw-body@2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" - integrity sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k= dependencies: bytes "3.0.0" http-errors "1.6.2" @@ -8872,7 +7722,6 @@ raw-body@2.3.2: raw-body@2.3.3: version "2.3.3" resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" - integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== dependencies: bytes "3.0.0" http-errors "1.6.3" @@ -8882,7 +7731,6 @@ raw-body@2.3.3: raw-body@~1.1.0: version "1.1.7" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" - integrity sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU= dependencies: bytes "1" string_decoder "0.10" @@ -8890,7 +7738,6 @@ raw-body@~1.1.0: rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: deep-extend "^0.6.0" ini "~1.3.0" @@ -8900,14 +7747,12 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: read-cmd-shim@~1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b" - integrity sha1-LV0Vd4ajfAVdIgd8MsU/gynpHHs= dependencies: graceful-fs "^4.1.2" read-installed@~4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" - integrity sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc= dependencies: debuglog "^1.0.1" read-package-json "^2.0.0" @@ -8921,7 +7766,6 @@ read-installed@~4.0.3: "read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@~2.0.2: version "2.0.13" resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-2.0.13.tgz#2e82ebd9f613baa6d2ebe3aa72cefe3f68e41f4a" - integrity sha512-/1dZ7TRZvGrYqE0UAfN6qQb5GYBsNcqS1C0tNK601CFOJmtHI7NIGXwetEPU/OtoFHZL3hDxm4rolFFVE9Bnmg== dependencies: glob "^7.1.1" json-parse-better-errors "^1.0.1" @@ -8933,7 +7777,6 @@ read-installed@~4.0.3: read-package-tree@~5.1.2: version "5.1.6" resolved "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.1.6.tgz#4f03e83d0486856fb60d97c94882841c2a7b1b7a" - integrity sha512-FCX1aT3GWyY658wzDICef4p+n0dB+ENRct8E/Qyvppj6xVpOYerBHfUu7OP5Rt1/393Tdglguf5ju5DEX4wZNg== dependencies: debuglog "^1.0.1" dezalgo "^1.0.0" @@ -8944,7 +7787,6 @@ read-package-tree@~5.1.2: read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= dependencies: find-up "^1.0.0" read-pkg "^1.0.0" @@ -8952,7 +7794,6 @@ read-pkg-up@^1.0.1: read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" @@ -8961,14 +7802,12 @@ read-pkg@^1.0.0: read@1, read@~1.0.1, read@~1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" - integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= dependencies: mute-stream "~0.0.4" "readable-stream@1 || 2", readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -8981,7 +7820,6 @@ read@1, read@~1.0.1, read@~1.0.7: readable-stream@~1.0.2: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -8991,7 +7829,6 @@ readable-stream@~1.0.2: readable-stream@~2.0.5: version "2.0.6" resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -9003,7 +7840,6 @@ readable-stream@~2.0.5: readdir-scoped-modules@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" - integrity sha1-n6+jfShr5dksuuve4DDcm19AZ0c= dependencies: debuglog "^1.0.1" dezalgo "^1.0.0" @@ -9013,7 +7849,6 @@ readdir-scoped-modules@^1.0.0: realize-package-specifier@~3.0.1: version "3.0.3" resolved "https://registry.npmjs.org/realize-package-specifier/-/realize-package-specifier-3.0.3.tgz#d0def882952b8de3f67eba5e91199661271f41f4" - integrity sha1-0N74gpUrjeP2frpekRmWYScfQfQ= dependencies: dezalgo "^1.0.1" npm-package-arg "^4.1.1" @@ -9021,7 +7856,6 @@ realize-package-specifier@~3.0.1: recast@^0.11.3: version "0.11.23" resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" - integrity sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM= dependencies: ast-types "0.9.6" esprima "~3.1.0" @@ -9031,7 +7865,6 @@ recast@^0.11.3: redent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= dependencies: indent-string "^2.1.0" strip-indent "^1.0.1" @@ -9039,41 +7872,34 @@ redent@^1.0.0: redeyed@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" - integrity sha1-6WwZO0DAgWsArshCaY5hGF5VSYo= dependencies: esprima "~3.0.0" regenerate-unicode-properties@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz#107405afcc4a190ec5ed450ecaa00ed0cafa7a4c" - integrity sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw== dependencies: regenerate "^1.4.0" regenerate@^1.2.1, regenerate@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" - integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== regenerator-runtime@^0.10.5: version "0.10.5" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" - integrity sha1-M2w+/BIgrc7dosn6tntaeVWjNlg= regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== regenerator-runtime@^0.9.5: version "0.9.6" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" - integrity sha1-0z65XQ0gAaS+OWWXB8UbDLcc4Ck= regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" - integrity sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q== dependencies: babel-runtime "^6.18.0" babel-types "^6.19.0" @@ -9082,21 +7908,18 @@ regenerator-transform@^0.10.0: regenerator-transform@^0.13.3: version "0.13.3" resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.3.tgz#264bd9ff38a8ce24b06e0636496b2c856b57bcbb" - integrity sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA== dependencies: private "^0.1.6" regex-cache@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== dependencies: is-equal-shallow "^0.1.3" regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== dependencies: extend-shallow "^3.0.2" safe-regex "^1.1.0" @@ -9104,17 +7927,14 @@ regex-not@^1.0.0, regex-not@^1.0.2: regexpp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.0.tgz#b2a7534a85ca1b033bcf5ce9ff8e56d4e0755365" - integrity sha512-g2FAVtR8Uh8GO1Nv5wpxW7VFVwHcCEr4wyA8/MHiRkO8uHoR5ntAA8Uq3P1vvMTX/BeQiRVSpDGLd+Wn5HNOTA== regexpp@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" - integrity sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA= dependencies: regenerate "^1.2.1" regjsgen "^0.2.0" @@ -9123,7 +7943,6 @@ regexpu-core@^2.0.0: regexpu-core@^4.1.3, regexpu-core@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.2.0.tgz#a3744fa03806cffe146dea4421a3e73bdcc47b1d" - integrity sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw== dependencies: regenerate "^1.4.0" regenerate-unicode-properties "^7.0.0" @@ -9135,7 +7954,6 @@ regexpu-core@^4.1.3, regexpu-core@^4.2.0: registry-auth-token@^3.0.1: version "3.3.2" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" - integrity sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ== dependencies: rc "^1.1.6" safe-buffer "^5.0.1" @@ -9143,38 +7961,32 @@ registry-auth-token@^3.0.1: registry-url@^3.0.3: version "3.1.0" resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" - integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI= dependencies: rc "^1.0.1" regjsgen@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc= regjsgen@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.4.0.tgz#c1eb4c89a209263f8717c782591523913ede2561" - integrity sha512-X51Lte1gCYUdlwhF28+2YMO0U6WeN0GLpgpA7LK7mbdDnkQYiwvEpmpe0F/cv5L14EbxgrdayAG3JETBv0dbXA== regjsparser@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw= dependencies: jsesc "~0.5.0" regjsparser@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.3.0.tgz#3c326da7fcfd69fa0d332575a41c8c0cdf588c96" - integrity sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA== dependencies: jsesc "~0.5.0" remote-git-tags@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/remote-git-tags/-/remote-git-tags-2.0.0.tgz#1152f39cf8b5268ae0e4307636ef741ec341664c" - integrity sha1-EVLznPi1Jorg5DB2Nu90HsNBZkw= dependencies: git-fetch-pack "^0.1.1" git-transport-protocol "^0.1.0" @@ -9182,29 +7994,24 @@ remote-git-tags@^2.0.0: remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" - integrity sha1-7wiaF40Ug7quTZPrmLT55OEdmQo= repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= repeating@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= dependencies: is-finite "^1.0.0" request@2, request@^2.47.0: version "2.88.0" resolved "https://registry.npmjs.org/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" - integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -9230,7 +8037,6 @@ request@2, request@^2.47.0: request@~2.40.0: version "2.40.0" resolved "https://registry.yarnpkg.com/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" - integrity sha1-TdZw9pbx5uhC5mtLXoOTAaub62c= dependencies: forever-agent "~0.5.0" json-stringify-safe "~5.0.0" @@ -9250,7 +8056,6 @@ request@~2.40.0: request@~2.67.0: version "2.67.0" resolved "http://registry.npmjs.org/request/-/request-2.67.0.tgz#8af74780e2bf11ea0ae9aa965c11f11afd272742" - integrity sha1-ivdHgOK/EeoK6aqWXBHxGv0nJ0I= dependencies: aws-sign2 "~0.6.0" bl "~1.0.0" @@ -9276,17 +8081,14 @@ request@~2.67.0: require-dir@^0.3.0: version "0.3.2" resolved "https://registry.npmjs.org/require-dir/-/require-dir-0.3.2.tgz#c1d5c75e9fbffde9f2e6b33e383db4f594b5a6a9" - integrity sha1-wdXHXp+//eny5rM+OD209ZS1pqk= require-relative@^0.8.7: version "0.8.7" resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" - integrity sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4= require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM= dependencies: caller-path "^0.1.0" resolve-from "^1.0.0" @@ -9294,17 +8096,14 @@ require-uncached@^1.0.3: requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= reselect@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147" - integrity sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc= resolve-dir@^1.0.0, resolve-dir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" - integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= dependencies: expand-tilde "^2.0.0" global-modules "^1.0.0" @@ -9312,12 +8111,10 @@ resolve-dir@^1.0.0, resolve-dir@^1.0.1: resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" - integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY= resolve-path@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7" - integrity sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc= dependencies: http-errors "~1.6.2" path-is-absolute "1.0.1" @@ -9325,33 +8122,28 @@ resolve-path@^1.4.0: resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= resolve@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" - integrity sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw== dependencies: path-parse "^1.0.5" resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.7.1, resolve@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" - integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== dependencies: path-parse "^1.0.5" responselike@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= dependencies: lowercase-keys "^1.0.0" restore-cursor@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - integrity sha1-NGYfRohjJ/7SmRR5FSJS35LapUE= dependencies: exit-hook "^1.0.0" onetime "^1.0.0" @@ -9359,7 +8151,6 @@ restore-cursor@^1.0.1: restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= dependencies: onetime "^2.0.0" signal-exit "^3.0.2" @@ -9367,43 +8158,36 @@ restore-cursor@^2.0.0: ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== retry@^0.8.0, retry@~0.8.0: version "0.8.0" resolved "https://registry.npmjs.org/retry/-/retry-0.8.0.tgz#2367628dc0edb247b1eab649dc53ac8628ac2d5f" - integrity sha1-I2dijcDtskex6rZJ3FOshiisLV8= right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" - integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8= dependencies: align-text "^0.1.1" rimraf@2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== dependencies: glob "^7.0.5" rimraf@~2.2.6: version "2.2.8" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" - integrity sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI= rimraf@~2.5.0: version "2.5.4" resolved "http://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" - integrity sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ= dependencies: glob "^7.0.5" rollup-pluginutils@^2.0.1: version "2.3.0" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.3.0.tgz#478ace04bd7f6da2e724356ca798214884738fc4" - integrity sha512-xB6hsRsjdJdIYWEyYUJy/3ki5g69wrf0luHPGNK3ZSocV6HLNfio59l3dZ3TL4xUwEKgROhFi9jOCt6c5gfUWw== dependencies: estree-walker "^0.5.2" micromatch "^2.3.11" @@ -9411,7 +8195,6 @@ rollup-pluginutils@^2.0.1: rollup@^0.57.1: version "0.57.1" resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.57.1.tgz#0bb28be6151d253f67cf4a00fea48fb823c74027" - integrity sha512-I18GBqP0qJoJC1K1osYjreqA8VAKovxuI3I81RSk0Dmr4TgloI0tAULjZaox8OsJ+n7XRrhH6i0G2By/pj1LCA== dependencies: "@types/acorn" "^4.0.3" acorn "^5.5.3" @@ -9428,83 +8211,68 @@ rollup@^0.57.1: route-recognizer@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" - integrity sha1-HTZeJ/ppleCRZ199yUCowANTvSk= rsvp@3.0.14: version "3.0.14" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.14.tgz#9d2968cf36d878d3bb9a9a5a4b8e1ff55a76dd31" - integrity sha1-nSlozzbYeNO7mppaS44f9Vp23TE= rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3: version "3.6.2" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" - integrity sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw== rsvp@^4.7.0, rsvp@^4.8.1, rsvp@^4.8.2, rsvp@^4.8.3: version "4.8.3" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.3.tgz#25d4b9fdd0f95e216eb5884d9b3767d3fbfbe2cd" - integrity sha512-/OlbK31XtkPnLD2ktmZXj4g/v6q1boTDr6/3lFuDTgxVsrA3h7PH5eYyAxIvDMjRHr/DoOlzNicqDwBEo9xU7g== rsvp@^4.8.4: version "4.8.4" resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.4.tgz#b50e6b34583f3dd89329a2f23a8a2be072845911" - integrity sha512-6FomvYPfs+Jy9TfXmBpBuMWNH94SgCsZmJKcanySzgNNP6LjWxBvyLTa9KaMfDDM5oxRfrKDB0r/qeRsLwnBfA== rsvp@~3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" - integrity sha1-B8tKXfJa3Z6Cbrxn3Mn9idsn2Eo= run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= dependencies: is-promise "^2.1.0" rx@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" - integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I= rxjs@^6.1.0: version "6.3.3" resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz#3c6a7fa420e844a81390fb1158a9ec614f4bad55" - integrity sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw== dependencies: tslib "^1.9.0" safe-buffer@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== safe-json-parse@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" - integrity sha1-PnZyPjjf3aE8mx0poeB//uSzC1c= safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= dependencies: ret "~0.1.10" "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sane@^2.4.1, sane@^2.5.2: version "2.5.2" resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" - integrity sha1-tNwYYcIbQn6SlQej51HiosuKs/o= dependencies: anymatch "^2.0.0" capture-exit "^1.2.0" @@ -9520,7 +8288,6 @@ sane@^2.4.1, sane@^2.5.2: sane@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/sane/-/sane-4.0.1.tgz#af1e10466e924e1b888c104bb9925a0f1beb46dd" - integrity sha512-12M/pR2HqW0aPKBAnwBerocN/6BbdAydw/gzGouHOeOpLmam46uS2xwtI+Yl5ZRqPDaakEsYtXkW9q/D5aJSdQ== dependencies: anymatch "^2.0.0" capture-exit "^1.2.0" @@ -9535,32 +8302,26 @@ sane@^4.0.0: sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== "semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.5.1, semver@^5.6.0: version "5.6.0" resolved "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" - integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== "semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" - integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== semver@^4.3.1: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" - integrity sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto= semver@~5.1.0: version "5.1.1" resolved "http://registry.npmjs.org/semver/-/semver-5.1.1.tgz#a3292a373e6f3e0798da0b20641b9a9c5bc47e19" - integrity sha1-oykqNz5vPgeY2gsgZBuanFvEfhk= send@0.16.2: version "0.16.2" resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" - integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== dependencies: debug "2.6.9" depd "~1.1.2" @@ -9579,7 +8340,6 @@ send@0.16.2: serve-static@1.13.2: version "1.13.2" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" - integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" @@ -9589,12 +8349,10 @@ serve-static@1.13.2: set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= set-value@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" - integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -9604,7 +8362,6 @@ set-value@^0.4.3: set-value@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" - integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -9614,17 +8371,14 @@ set-value@^2.0.0: setprototypeof@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" - integrity sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ= setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" - integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== sha@~2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae" - integrity sha1-YDCCL70smCOUn49y7WQR7lzyWq4= dependencies: graceful-fs "^4.1.2" readable-stream "^2.0.2" @@ -9632,65 +8386,54 @@ sha@~2.0.1: shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== sigmund@~1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" - integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= silent-error@^1.0.0, silent-error@^1.0.1, silent-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/silent-error/-/silent-error-1.1.0.tgz#2209706f1c850a9f1d10d0d840918b46f26e1bc9" - integrity sha1-IglwbxyFCp8dENDYQJGLRvJuG8k= dependencies: debug "^2.2.0" silent-error@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.1.1.tgz#f72af5b0d73682a2ba1778b7e32cd8aa7c2d8662" - integrity sha512-n4iEKyNcg4v6/jpb3c0/iyH2G1nzUNl7Gpqtn/mHIJK9S/q/7MCfoO4rwVOoO59qPFIc0hVHvMbiOJ0NdtxKKw== dependencies: debug "^2.2.0" slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= slice-ansi@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" - integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== dependencies: is-fullwidth-code-point "^2.0.0" slide@^1.1.3, slide@^1.1.5, slide@~1.1.3, slide@~1.1.6: version "1.1.6" resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== dependencies: define-property "^1.0.0" isobject "^3.0.0" @@ -9699,14 +8442,12 @@ snapdragon-node@^2.0.1: snapdragon-util@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== dependencies: kind-of "^3.2.0" snapdragon@^0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== dependencies: base "^0.11.1" debug "^2.2.0" @@ -9720,26 +8461,22 @@ snapdragon@^0.8.1: sntp@0.2.x: version "0.2.4" resolved "https://registry.yarnpkg.com/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" - integrity sha1-+4hfGLDzqtGJ+CSGJTa87ux1CQA= dependencies: hoek "0.9.x" sntp@1.x.x: version "1.0.9" resolved "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - integrity sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg= dependencies: hoek "2.x.x" socket.io-adapter@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" - integrity sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs= socket.io-client@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" - integrity sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ== dependencies: backo2 "1.0.2" base64-arraybuffer "0.1.5" @@ -9759,7 +8496,6 @@ socket.io-client@2.1.1: socket.io-parser@~3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" - integrity sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA== dependencies: component-emitter "1.2.1" debug "~3.1.0" @@ -9768,7 +8504,6 @@ socket.io-parser@~3.2.0: socket.io@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" - integrity sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA== dependencies: debug "~3.1.0" engine.io "~3.2.0" @@ -9780,19 +8515,16 @@ socket.io@^2.1.0: sort-keys@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" - integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= dependencies: is-plain-obj "^1.0.0" sort-object-keys@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" - integrity sha1-06bEjcKsl+a8lDZ2luA/bQnTeVI= sort-package-json@^1.15.0: version "1.16.0" resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.16.0.tgz#087f5ce05b6faca373312e7124918e0d68492d7b" - integrity sha512-QFJNxdpp7zZgSkmAIaMrteqqxGP4TkooKrGtslM2qYiML92PTYDOFOk+lG+TdvJzjheD502UFIys2qSvQljKaw== dependencies: detect-indent "^5.0.0" sort-object-keys "^1.1.2" @@ -9800,12 +8532,10 @@ sort-package-json@^1.15.0: sorted-object@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/sorted-object/-/sorted-object-1.0.0.tgz#5d1f4f9c1fb2cd48965967304e212eb44cfb6d05" - integrity sha1-XR9PnB+yzUiWWWcwTiEutEz7bQU= source-map-resolve@^0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== dependencies: atob "^2.1.1" decode-uri-component "^0.2.0" @@ -9816,14 +8546,12 @@ source-map-resolve@^0.5.0: source-map-support@^0.4.15: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== dependencies: source-map "^0.5.6" source-map-support@~0.5.6: version "0.5.6" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.6.tgz#4435cee46b1aab62b8e8610ce60f788091c51c13" - integrity sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -9831,46 +8559,38 @@ source-map-support@~0.5.6: source-map-url@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" - integrity sha1-fsrxO1e80J2opAxdJp2zN5nUqvk= source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" - integrity sha1-66T12pwNyZneaAMti092FzZSA2s= dependencies: amdefine ">=0.0.4" source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0, source-map@~0.5.1: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== source-map@~0.1.x: version "0.1.43" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" - integrity sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y= dependencies: amdefine ">=0.0.4" sourcemap-codec@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.1.tgz#c8fd92d91889e902a07aee392bdd2c5863958ba2" - integrity sha512-hX1eNBNuilj8yfFnECh0DzLgwKpBLMIvmhgEhixXNui8lMLBInTI8Kyxt++RwJnMNu7cAUo635L2+N1TxMJCzA== sourcemap-validator@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/sourcemap-validator/-/sourcemap-validator-1.1.0.tgz#00454547d1682186e1498a7208e022e8dfa8738f" - integrity sha512-Hmdu39KL+EoAAZ69OTk7RXXJdPRRizJvOZOWhCW9jLGfEQflCNPTlSoCXFPdKWFwwf0uzLcGR/fc7EP/PT8vRQ== dependencies: jsesc "~0.3.x" lodash.foreach "~2.3.x" @@ -9880,12 +8600,10 @@ sourcemap-validator@^1.1.0: spawn-args@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" - integrity sha1-+30L0dcP1DFr2ePew4nmX51jYbs= spawn-sync@^1.0.11, spawn-sync@^1.0.15: version "1.0.15" resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" - integrity sha1-sAeZVX63+wyDdsKdROih6mfldHY= dependencies: concat-stream "^1.4.7" os-shim "^0.1.2" @@ -9893,12 +8611,10 @@ spawn-sync@^1.0.11, spawn-sync@^1.0.15: spawnback@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" - integrity sha1-9zZi9+VNlTZ+ynTWQmxnfdfqaG8= spdx-correct@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" - integrity sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" @@ -9906,12 +8622,10 @@ spdx-correct@^3.0.0: spdx-exceptions@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" - integrity sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg== spdx-expression-parse@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" @@ -9919,34 +8633,28 @@ spdx-expression-parse@^3.0.0: spdx-license-ids@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" - integrity sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA== split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== dependencies: extend-shallow "^3.0.0" sprintf-js@^1.0.3: version "1.1.1" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" - integrity sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw= sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sri-toolbox@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" - integrity sha1-p/6lw/3lXmdc8cjAbz67XCk1g14= sshpk@^1.7.0: version "1.15.1" resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.15.1.tgz#b79a089a732e346c6e0714830f36285cd38191a2" - integrity sha512-mSdgNUaidk+dRU5MhYtN9zebdzF2iG0cNPWy8HG+W8y+fT1JnSkh0fzzpjOa0L7P8i1Rscz38t0h4gPcKz43xA== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -9961,14 +8669,12 @@ sshpk@^1.7.0: stagehand@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stagehand/-/stagehand-1.0.0.tgz#79515e2ad3a02c63f8720c7df9b6077ae14276d9" - integrity sha512-zrXl0QixAtSHFyN1iv04xOBgplbT4HgC8T7g+q8ESZbDNi5uZbMtxLukFVXPJ5Nl7zCYvYcrT3Mj24WYCH93hw== dependencies: debug "^4.1.0" static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= dependencies: define-property "^0.2.5" object-copy "^0.1.0" @@ -9976,32 +8682,26 @@ static-extend@^0.1.1: "statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2": version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= statuses@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" - integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4= statuses@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" - integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= string-template@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" - integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0= string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -10010,7 +8710,6 @@ string-width@^1.0.1: "string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" @@ -10018,19 +8717,16 @@ string-width@^1.0.1: string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.0" stringify-object-es5@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/stringify-object-es5/-/stringify-object-es5-2.5.0.tgz#057c3c9a90a127339bb9d1704a290bb7bd0a1ec5" - integrity sha1-BXw8mpChJzObudFwSikLt70KHsU= dependencies: is-plain-obj "^1.0.0" is-regexp "^1.0.0" @@ -10038,84 +8734,70 @@ stringify-object-es5@^2.5.0: stringstream@~0.0.4: version "0.0.6" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" - integrity sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA== strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= dependencies: ansi-regex "^2.0.0" strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= dependencies: ansi-regex "^3.0.0" strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= dependencies: is-utf8 "^0.2.0" strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= strip-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= dependencies: get-stdin "^4.0.1" strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= styled_string@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" - integrity sha1-0ieCvYEpVFm8Tx3xjEutjpTdEko= sum-up@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" - integrity sha1-HGYfZnBX9jvLeHWqFDi8FiUlFW4= dependencies: chalk "^1.0.0" supports-color@5.4.0, supports-color@^5.3.0: version "5.4.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" - integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== dependencies: has-flag "^3.0.0" supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" - integrity sha512-W31+GLiBmU/ZR02Ii0mVZICuNEN9daZ63xZMPDsYgPgNjMtg+atqLEGI7PPI936jYSQZxoLb/63xos8Adrx4Eg== table@^5.0.2: version "5.1.0" resolved "https://registry.npmjs.org/table/-/table-5.1.0.tgz#69a54644f6f01ad1628f8178715b408dc6bf11f7" - integrity sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg== dependencies: ajv "^6.5.3" lodash "^4.17.10" @@ -10125,7 +8807,6 @@ table@^5.0.2: tap-parser@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-7.0.0.tgz#54db35302fda2c2ccc21954ad3be22b2cba42721" - integrity sha512-05G8/LrzqOOFvZhhAk32wsGiPZ1lfUrl+iV7+OkKgfofZxiceZWMHkKmow71YsyVQ8IvGBP2EjcIjE5gL4l5lA== dependencies: events-to-array "^1.0.1" js-yaml "^3.2.7" @@ -10134,7 +8815,6 @@ tap-parser@^7.0.0: tar@^2.0.0, tar@~2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= dependencies: block-stream "*" fstream "^1.0.2" @@ -10143,7 +8823,6 @@ tar@^2.0.0, tar@~2.2.1: tar@^4: version "4.4.4" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" - integrity sha512-mq9ixIYfNF9SK0IS/h2HKMu8Q2iaCuhDDsZhdEag/FHv8fOaYld4vN7ouMgcSSt5WKZzPs8atclTcJm36OTh4w== dependencies: chownr "^1.0.1" fs-minipass "^1.2.5" @@ -10156,7 +8835,6 @@ tar@^4: temp@0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" - integrity sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k= dependencies: os-tmpdir "^1.0.0" rimraf "~2.2.6" @@ -10164,7 +8842,6 @@ temp@0.8.3: terser@^3.7.5: version "3.8.1" resolved "https://registry.yarnpkg.com/terser/-/terser-3.8.1.tgz#cb70070ac9e0a71add169dfb63c0a64fca2738ac" - integrity sha512-FRin3gKQ0vm0xPPLuxw1FqpVgv1b2pBpYCaFb5qe6A7sD749Fnq1VbDiX3CEFM0BV0fqDzFtBfgmxhxCdzKQIg== dependencies: commander "~2.16.0" source-map "~0.6.1" @@ -10173,7 +8850,6 @@ terser@^3.7.5: testdouble@^3.2.6: version "3.8.1" resolved "https://registry.yarnpkg.com/testdouble/-/testdouble-3.8.1.tgz#8c74b6807f82fb07c2387a0640b4ae594b09b964" - integrity sha512-ZOxGwLHCh47HIRqpPVAH3c/oFRu4kGgQxvDJV5db2QFH4/2JRIEUWVvnY9n4HRU5KgxVzHcL+ecjwzBE7r44Zw== dependencies: es6-map "^0.1.5" lodash "^4.17.4" @@ -10184,7 +8860,6 @@ testdouble@^3.2.6: testem@^2.9.2: version "2.13.0" resolved "https://registry.npmjs.org/testem/-/testem-2.13.0.tgz#587f3460a923779949804efac0fcc2015835dd63" - integrity sha512-n0XBuEi/3SqnXfwUWtHVIUn2/j4LouJeOJrZMfwdXmZRKr15cH7cV59e9c3rFa4AvspAn9lOXcaMBysPC5jHZg== dependencies: backbone "^1.1.2" bluebird "^3.4.6" @@ -10218,42 +8893,34 @@ testem@^2.9.2: text-table@^0.2.0, text-table@~0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= "textextensions@1 || 2": version "2.2.0" resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" - integrity sha512-j5EMxnryTvKxwH2Cq+Pb43tsf6sdEgw6Pdwxk83mPaq0ToeFJt6WE4J3s5BqY7vmjlLgkgXvhtXUxo80FyBhCA== theredoc@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/theredoc/-/theredoc-1.0.0.tgz#bcace376af6feb1873efbdd0f91ed026570ff062" - integrity sha512-KU3SA3TjRRM932jpNfD3u4Ec3bSvedyo5ITPI7zgWYnKep7BwQQaxlhI9qbO+lKJoRnoAbEVfMcAHRuKVYikDA== through@^2.3.6, through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= through@~2.2.0, through@~2.2.7: version "2.2.7" resolved "https://registry.yarnpkg.com/through/-/through-2.2.7.tgz#6e8e21200191d4eb6a99f6f010df46aa1c6eb2bd" - integrity sha1-bo4hIAGR1OtqmfbwEN9Gqhxusr0= time-zone@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/time-zone/-/time-zone-1.0.0.tgz#99c5bf55958966af6d06d83bdf3800dc82faec5d" - integrity sha1-mcW/VZWJZq9tBtg73zgA3IL67F0= timed-out@^4.0.0, timed-out@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= tiny-lr@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" - integrity sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA== dependencies: body "^5.1.0" debug "^3.1.0" @@ -10265,7 +8932,6 @@ tiny-lr@^1.1.1: tmp-sync@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" - integrity sha1-ugTZSo7ZwPNaVHOZcHkvmXpswcg= dependencies: fs-sync "^1.0.4" osenv "^0.1.0" @@ -10273,55 +8939,46 @@ tmp-sync@^1.0.0: tmp@0.0.28: version "0.0.28" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" - integrity sha1-Fyc1t/YU6nrzlmT6hM8N5OUV0SA= dependencies: os-tmpdir "~1.0.1" tmp@0.0.33, tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== dependencies: os-tmpdir "~1.0.2" tmp@^0.0.29: version "0.0.29" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" - integrity sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA= dependencies: os-tmpdir "~1.0.1" tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" - integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= to-array@0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" - integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= dependencies: kind-of "^3.0.2" to-regex-range@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= dependencies: is-number "^3.0.0" repeat-string "^1.6.1" @@ -10329,7 +8986,6 @@ to-regex-range@^2.1.0: to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== dependencies: define-property "^2.0.2" extend-shallow "^3.0.2" @@ -10339,12 +8995,10 @@ to-regex@^3.0.1, to-regex@^3.0.2: to-utf8@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" - integrity sha1-0Xrqcv8vujm55DYBvns/9y4ImFI= tough-cookie@>=0.12.0, tough-cookie@~2.4.3: version "2.4.3" resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" - integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== dependencies: psl "^1.1.24" punycode "^1.4.1" @@ -10352,12 +9006,10 @@ tough-cookie@>=0.12.0, tough-cookie@~2.4.3: tough-cookie@~2.2.0: version "2.2.2" resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz#c83a1830f4e5ef0b93ef2a3488e724f8de016ac7" - integrity sha1-yDoYMPTl7wuT7yo0iOck+N4Basc= tree-sync@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" - integrity sha1-LPdrhYn1n/7bWNtaOsfLAT0BWLc= dependencies: debug "^2.2.0" fs-tree-diff "^0.5.6" @@ -10368,61 +9020,50 @@ tree-sync@^1.2.2: trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= tslib@^1.9.0: version "1.9.3" resolved "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" - integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= dependencies: safe-buffer "^5.0.1" tunnel-agent@~0.4.0, tunnel-agent@~0.4.1: version "0.4.3" resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" - integrity sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us= tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= dependencies: prelude-ls "~1.1.2" type-detect@0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" - integrity sha1-C6XsKohWQORw6k6FBZcZANrFiCI= type-detect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" - integrity sha1-diIXzAbbJY7EiQihKY6LlRIejqI= type-detect@^4.0.0: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== type-is@~1.6.15, type-is@~1.6.16: version "1.6.16" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" - integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== dependencies: media-typer "0.3.0" mime-types "~2.1.18" @@ -10430,22 +9071,18 @@ type-is@~1.6.15, type-is@~1.6.16: typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= typescript@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.3.tgz#01b70247a6d3c2467f70c45795ef5ea18ce191d5" - integrity sha512-+81MUSyX+BaSo+u2RbozuQk/UWx6hfG0a5gHu4ANEM4sU96XbuIyAB+rWBW1u70c6a5QuZfuYICn3s2UjuHUpA== uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" - integrity sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg== uglify-js@^2.6: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" - integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0= dependencies: source-map "~0.5.1" yargs "~3.10.0" @@ -10455,7 +9092,6 @@ uglify-js@^2.6: uglify-js@^3.1.4: version "3.4.9" resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" - integrity sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q== dependencies: commander "~2.17.1" source-map "~0.6.1" @@ -10463,27 +9099,22 @@ uglify-js@^3.1.4: uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" - integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc= uid-number@0.0.6: version "0.0.6" resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== umask@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" - integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= underscore.string@^3.2.2, underscore.string@~3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" - integrity sha1-LCo/n4PmR2L9xF5s6sZRQoZCE9s= dependencies: sprintf-js "^1.0.3" util-deprecate "^1.0.2" @@ -10491,17 +9122,14 @@ underscore.string@^3.2.2, underscore.string@~3.3.4: underscore@>=1.8.3: version "1.9.1" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" - integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== unicode-match-property-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== dependencies: unicode-canonical-property-names-ecmascript "^1.0.4" unicode-property-aliases-ecmascript "^1.0.4" @@ -10509,17 +9137,14 @@ unicode-match-property-ecmascript@^1.0.4: unicode-match-property-value-ecmascript@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz#9f1dc76926d6ccf452310564fd834ace059663d4" - integrity sha512-Rx7yODZC1L/T8XKo/2kNzVAQaRE88AaMvI1EF/Xnj3GW2wzN6fop9DDWuFAKUVFH7vozkz26DzP0qyWLKLIVPQ== unicode-property-aliases-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz#5a533f31b4317ea76f17d807fa0d116546111dd0" - integrity sha512-2WSLa6OdYd2ng8oqiGIWnJqyFArvhn+5vgx5GTxMbUYjCYKUcuKS62YLFF0R/BDGlB1yzXjQOLtPAfHsgirEpg== union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" - integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= dependencies: arr-union "^3.1.0" get-value "^2.0.6" @@ -10529,38 +9154,32 @@ union-value@^1.0.0: unique-filename@~1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== dependencies: unique-slug "^2.0.0" unique-slug@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz#5e9edc6d1ce8fb264db18a507ef9bd8544451ca6" - integrity sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg== dependencies: imurmurhash "^0.1.4" unique-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" - integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo= dependencies: crypto-random-string "^1.0.0" universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= dependencies: has-value "^0.3.1" isobject "^3.0.0" @@ -10568,55 +9187,46 @@ unset-value@^1.0.0: untildify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" - integrity sha1-F+soB5h/dpUunASF/DEdBqgmouA= dependencies: os-homedir "^1.0.0" unzip-response@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" - integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c= uri-js@^4.2.2: version "4.2.2" resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== dependencies: punycode "^2.1.0" urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= url-parse-lax@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= dependencies: prepend-http "^1.0.1" url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= dependencies: prepend-http "^2.0.0" url-to-options@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" - integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== user-info@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/user-info/-/user-info-1.0.0.tgz#81c82b7ed63e674c2475667653413b3c76fde239" - integrity sha1-gcgrftY+Z0wkdWZ2U0E7PHb94jk= dependencies: os-homedir "^1.0.1" passwd-user "^1.2.1" @@ -10625,39 +9235,32 @@ user-info@^1.0.0: username-sync@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/username-sync/-/username-sync-1.0.1.tgz#1cde87eefcf94b8822984d938ba2b797426dae1f" - integrity sha1-HN6H7vz5S4gimE2Ti6K3l0Jtrh8= username@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/username/-/username-1.0.1.tgz#e1f72295e3e58e06f002c6327ce06897a99cd67f" - integrity sha1-4fcilePljgbwAsYyfOBol6mc1n8= dependencies: meow "^3.4.0" util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= util-extend@^1.0.1: version "1.0.3" resolved "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" - integrity sha1-p8IW0mdUUWljeztu3GypEZ4v+T8= utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= uuid@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== validate-npm-package-license@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" - integrity sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g== dependencies: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" @@ -10665,26 +9268,22 @@ validate-npm-package-license@^3.0.1: validate-npm-package-name@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" - integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= dependencies: builtins "^1.0.3" validate-npm-package-name@~2.2.2: version "2.2.2" resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-2.2.2.tgz#f65695b22f7324442019a3c7fa39a6e7fd299085" - integrity sha1-9laVsi9zJEQgGaPH+jmm5/0pkIU= dependencies: builtins "0.0.7" vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= verror@1.10.0: version "1.10.0" resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= dependencies: assert-plus "^1.0.0" core-util-is "1.0.2" @@ -10693,7 +9292,6 @@ verror@1.10.0: walk-sync@0.3.2, walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" - integrity sha512-FMB5VqpLqOCcqrzA9okZFc0wq0Qbmdm396qJxvQZhDpyu0W95G9JCmp74tx7iyYnyOcBtUuKJsgIKAqjozvmmQ== dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" @@ -10701,7 +9299,6 @@ walk-sync@0.3.2, walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2: walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" - integrity sha1-tJvk7mhnZXrrc2l4tWop0Q+jmWk= dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" @@ -10709,7 +9306,6 @@ walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: walk-sync@^0.3.3: version "0.3.3" resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.3.tgz#1e9f12cd4fe6e0e6d4a0715b5cc7e30711d43cd1" - integrity sha512-jQgTHmCazUngGqvHZFlr30u2VLKEKErBMLFe+fBl5mn4rh9aI/QVRog8PT1hv2vaOu4EBwigfmpRTyZrbnpRVA== dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" @@ -10717,14 +9313,12 @@ walk-sync@^0.3.3: walker@~1.0.5: version "1.0.7" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" - integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= dependencies: makeerror "1.0.x" watch-detector@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/watch-detector/-/watch-detector-0.1.0.tgz#e37b410d149e2a8bf263a4f8b71e2f667633dbf8" - integrity sha512-vfzMMfpjQc88xjETwl2HuE6PjEuxCBeyC4bQmqrHrofdfYWi/4mEJklYbNgSzpqM9PxubsiPIrE5SZ1FDyiQ2w== dependencies: heimdalljs-logger "^0.1.9" quick-temp "^0.1.8" @@ -10735,7 +9329,6 @@ watch-detector@^0.1.0: watch@~0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" - integrity sha1-KAlUdsbffJDJYxOJkMClQj60uYY= dependencies: exec-sh "^0.2.0" minimist "^1.2.0" @@ -10743,14 +9336,12 @@ watch@~0.18.0: wcwidth@^1.0.0, wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= dependencies: defaults "^1.0.3" websocket-driver@>=0.5.1: version "0.7.0" resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" - integrity sha1-DK+dLXVdk67gSdS90NP+LMoqJOs= dependencies: http-parser-js ">=0.4.0" websocket-extensions ">=0.1.1" @@ -10758,72 +9349,60 @@ websocket-driver@>=0.5.1: websocket-extensions@>=0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" - integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== which@1, which@^1.2.14, which@^1.2.9, which@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" which@~1.2.1: version "1.2.14" resolved "https://registry.npmjs.org/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" - integrity sha1-mofEN48D6CfOyvGs31bHNsAcFOU= dependencies: isexe "^2.0.0" wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== dependencies: string-width "^1.0.2 || 2" window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0= wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8= wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= workerpool@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-2.3.0.tgz#86c5cbe946b55e7dc9d12b1936c8801a6e2d744d" - integrity sha512-JP5DpviEV84zDmz13QnD4FfRjZBjnTOYY2O4pGgxtlqLh47WOzQFHm8o17TE5OSfcDoKC6vHSrN4yPju93DW0Q== dependencies: object-assign "4.1.1" workerpool@^2.3.1: version "2.3.3" resolved "https://registry.npmjs.org/workerpool/-/workerpool-2.3.3.tgz#49a70089bd55e890d68cc836a19419451d7c81d7" - integrity sha512-L1ovlYHp6UObYqElXXpbd214GgbEKDED0d3sj7pRdFXjNkb2+un/AUcCkceHizO0IVI6SOGGncrcjozruCkRgA== dependencies: object-assign "4.1.1" wrappy@1, wrappy@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= write-file-atomic@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" - integrity sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA== dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -10832,7 +9411,6 @@ write-file-atomic@^2.0.0: write-file-atomic@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.1.4.tgz#b1f52dc2e8dc0e3cb04d187a25f758a38a90ca3b" - integrity sha1-sfUtwujcDjywTRh6JfdYo4qQyjs= dependencies: graceful-fs "^4.1.2" imurmurhash "^0.1.4" @@ -10841,14 +9419,12 @@ write-file-atomic@~1.1.4: write@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" - integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c= dependencies: mkdirp "^0.5.1" ws@~3.3.1: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" - integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== dependencies: async-limiter "~1.0.0" safe-buffer "~5.1.0" @@ -10857,37 +9433,30 @@ ws@~3.3.1: xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" - integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= xmldom@^0.1.19: version "0.1.27" resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" - integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk= xmlhttprequest-ssl@~1.5.4: version "1.5.5" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" - integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= xtend@^4.0.0, xtend@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= yallist@^3.0.0, yallist@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" - integrity sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k= yam@^0.0.24: version "0.0.24" resolved "https://registry.yarnpkg.com/yam/-/yam-0.0.24.tgz#11e9630444735f66a561d29221407de6d037cd95" - integrity sha512-llPF60oFLV8EQimNPR6+KorSaj59L32C4c1db4cr72GaWVWapnhTS2VZeK2K2xLyEOveWtRcNa+dLJBW7EfhYQ== dependencies: fs-extra "^4.0.2" lodash.merge "^4.6.0" @@ -10895,7 +9464,6 @@ yam@^0.0.24: yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" - integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E= dependencies: camelcase "^1.0.2" cliui "^2.1.0" @@ -10905,19 +9473,16 @@ yargs@~3.10.0: yeast@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" - integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= yui@^3.18.1: version "3.18.1" resolved "https://registry.yarnpkg.com/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" - integrity sha1-4AAmnsCntvvHQcu4/L0OZRF7AUw= dependencies: request "~2.40.0" yuidocjs@^0.10.0: version "0.10.2" resolved "https://registry.yarnpkg.com/yuidocjs/-/yuidocjs-0.10.2.tgz#33924967ce619024cd70ef694e267d2f988f73f6" - integrity sha1-M5JJZ85hkCTNcO9pTiZ9L5iPc/Y= dependencies: express "^4.13.1" graceful-fs "^4.1.2" From 5b47a278d31352dabad3bc79f869d0db8ea9b5a6 Mon Sep 17 00:00:00 2001 From: Igor Terzic Date: Wed, 21 Nov 2018 19:05:05 -0800 Subject: [PATCH 2422/2527] Add *.ts to `.npmignore` Don't publish .ts files in order to not make them public api until we are confident in our typings. --- .npmignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.npmignore b/.npmignore index a032d9a0a41..0351cb31a82 100644 --- a/.npmignore +++ b/.npmignore @@ -33,3 +33,9 @@ yarn.lock **/*.rb node-tests/ lib/version-replace.js + +# typescript +# +# avoid publishing .d.ts or .ts files +# until they have become enforced "public" APIs +*.ts From 7ecc5498d9f7f3591a69f9e75bc43f44b1828ded Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 21 Nov 2018 20:41:37 -0800 Subject: [PATCH 2423/2527] Address late feedback from #5727 --- addon/-private/system/identity-map.ts | 11 ++------- addon/-private/system/internal-model-map.ts | 25 +++++---------------- addon/-private/types.ts | 1 + 3 files changed, 9 insertions(+), 28 deletions(-) create mode 100644 addon/-private/types.ts diff --git a/addon/-private/system/identity-map.ts b/addon/-private/system/identity-map.ts index bbfe8124020..101d5fd6fab 100644 --- a/addon/-private/system/identity-map.ts +++ b/addon/-private/system/identity-map.ts @@ -1,8 +1,5 @@ import InternalModelMap from './internal-model-map'; - -interface IMMDict { - [modelName: string]: InternalModelMap -} +import { Dict } from '../types'; /** `IdentityMap` is a custom storage map for records by modelName @@ -12,11 +9,7 @@ interface IMMDict { @private */ export default class IdentityMap { - private _map: IMMDict; - - constructor() { - this._map = Object.create(null); - } + private _map: Dict = Object.create(null); /** Retrieves the `InternalModelMap` for a given modelName, diff --git a/addon/-private/system/internal-model-map.ts b/addon/-private/system/internal-model-map.ts index a1b350ea985..504b1c77866 100644 --- a/addon/-private/system/internal-model-map.ts +++ b/addon/-private/system/internal-model-map.ts @@ -1,12 +1,6 @@ import { assert } from '@ember/debug'; import InternalModel from './model/internal-model'; - -interface IDDict { - [id: string]: InternalModel; -} -interface MetaDict { - [key: string]: any; -} +import { Dict } from '../types'; /** `InternalModelMap` is a custom storage map for internalModels of a given modelName @@ -19,18 +13,11 @@ interface MetaDict { @private */ export default class InternalModelMap { - private _idToModel: IDDict; - private _models: InternalModel[]; - private _metadata: MetaDict | null; - - modelName: string; + private _idToModel: Dict = Object.create(null); + private _models: InternalModel[] = []; + private _metadata: Dict | null = null; - constructor(modelName: string) { - this.modelName = modelName; - this._idToModel = Object.create(null); - this._models = []; - this._metadata = null; - } + constructor(public modelName: string) {} /** * @method get @@ -116,7 +103,7 @@ export default class InternalModelMap { * @property metadata * @type Object */ - get metadata(): MetaDict { + get metadata(): Dict { return this._metadata || (this._metadata = Object.create(null)); } diff --git a/addon/-private/types.ts b/addon/-private/types.ts new file mode 100644 index 00000000000..8cfd8e98fe2 --- /dev/null +++ b/addon/-private/types.ts @@ -0,0 +1 @@ +export type Dict = { [KK in K]: V }; From 6b15f525b5b905e66cdeb8e2c61439de5a6930c7 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 20 Nov 2018 06:45:03 -0800 Subject: [PATCH 2424/2527] [FEAT recordDataFor] implements WeakMap based RecordData lookups --- addon/-private/system/model/internal-model.js | 6 +++ .../-private/system/model/record-data-map.ts | 44 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 addon/-private/system/model/record-data-map.ts diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 877fcf5b5b8..f9e4cbc63d8 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -16,6 +16,7 @@ import { PromiseBelongsTo, PromiseManyArray } from '../promise-proxies'; import { RecordReference, BelongsToReference, HasManyReference } from '../references'; import { default as recordDataFor, relationshipStateFor } from '../record-data-for'; +import { setRecordDataFor } from './record-data-map'; /* The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached @@ -92,6 +93,7 @@ export default class InternalModel { this.clientId = clientId; this._recordData = store._createRecordData(modelName, id, clientId, this); + setRecordDataFor(this, this._recordData); // this ensure ordered set can quickly identify this as unique this[Ember.GUID_KEY] = InternalModelReferenceId++ + 'internal-model'; @@ -284,7 +286,11 @@ export default class InternalModel { createOptions.container = store.container; } + let recordData = this._recordData; + setRecordDataFor(createOptions, recordData); this._record = store._modelFactoryFor(this.modelName).create(createOptions); + // TODO should we unmap createOptions after record construction? + setRecordDataFor(this._record, recordData); this._triggerDeferredTriggers(); heimdall.stop(token); diff --git a/addon/-private/system/model/record-data-map.ts b/addon/-private/system/model/record-data-map.ts new file mode 100644 index 00000000000..30e44a0be83 --- /dev/null +++ b/addon/-private/system/model/record-data-map.ts @@ -0,0 +1,44 @@ +import { DEBUG } from '@glimmer/env'; + +// TODO is there a way to import classes without causing cyclical imports for rollup? +// maybe strip "typing" imports prior to rollup? +type InternalModel = object; +type CreateOptions = object; +type Record = object; +type RecordData = object; + +type Mappable = InternalModel | CreateOptions | Record; + +const RecordDataMap = new WeakMap(); + +export function getRecordDataFor(instance: Mappable): RecordData | null { + let recordData = RecordDataMap.get(instance); + + if (DEBUG) { + if (recordData === undefined) { + throw new Error( + `Attempted to retrieve the RecordData mapped to ${instance} but no mapping exists!` + ); + } + } + + return recordData || null; +} + +export function setRecordDataFor(instance: Mappable, recordData: RecordData): void { + if (DEBUG) { + let existing = RecordDataMap.get(instance); + if (existing !== undefined) { + // even re-setting to the same instance is a mistake + if (existing === recordData) { + throw new Error( + `Attempting to create RecordData mapping for ${instance} but this same mapping has already been created!` + ); + } + throw new Error( + `Cannot create RecordData mapping for ${instance} as a different mapping already exists!` + ); + } + } + RecordDataMap.set(instance, recordData); +} From f27bbf0edd3a7cfeada5f60d6904b31bd91514f3 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 20 Nov 2018 07:28:29 -0800 Subject: [PATCH 2425/2527] [FEAT attr] move internalModel logic for attributes into attr --- addon/-private/attr.ts | 63 ++++++++++++++----- addon/-private/system/model/internal-model.js | 36 +++-------- addon/-private/system/model/model.js | 42 ++++++++----- .../-private/system/model/record-data-map.ts | 47 ++++++++++---- ember-cli-build.js | 3 + package.json | 1 + .../adapter/client-side-delete-test.js | 2 +- tests/integration/application-test.js | 6 +- tests/integration/debug-adapter-test.js | 3 +- tests/unit/model-test.js | 11 +--- yarn.lock | 9 ++- 11 files changed, 133 insertions(+), 90 deletions(-) diff --git a/addon/-private/attr.ts b/addon/-private/attr.ts index 94d424cb3f3..da210661022 100644 --- a/addon/-private/attr.ts +++ b/addon/-private/attr.ts @@ -1,14 +1,15 @@ import { computed } from '@ember/object'; import { assert } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; -import recordDataFor from './system/record-data-for'; +import Model from './system/model/model'; +import { getRecordDataFor } from './system/model/record-data-map'; /** @module ember-data */ -function getDefaultValue(record, options, key) { +function getDefaultValue(record, options, propertyName) { if (typeof options.defaultValue === 'function') { - return options.defaultValue.apply(null, arguments); + return options.defaultValue.call(null, record, options, propertyName); } else { let defaultValue = options.defaultValue; assert( @@ -19,10 +20,6 @@ function getDefaultValue(record, options, key) { } } -function hasValue(internalModel, key) { - return recordDataFor(internalModel).hasAttr(key); -} - interface AttrOptions { defaultValue?: string | null | (() => any); } @@ -127,7 +124,7 @@ export default function attr(type?: string | AttrOptions, options?: AttrOptions) }; return computed({ - get(key) { + get(key: string) { if (DEBUG) { if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) { throw new Error( @@ -135,22 +132,54 @@ export default function attr(type?: string | AttrOptions, options?: AttrOptions) ); } } - let internalModel = this._internalModel; - if (hasValue(internalModel, key)) { - return internalModel.getAttributeValue(key); + + let recordData = getRecordDataFor(this); + if (recordData.hasAttr(key)) { + return recordData.getAttr(key); } else { return getDefaultValue(this, options, key); } }, - set(key, value) { + set(key: string, value: any) { if (DEBUG) { - if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) { - throw new Error( - `'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your attr on ${this.constructor.toString()}` - ); + if (this instanceof Model) { + if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) { + throw new Error( + `'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your attr on ${this.constructor.toString()}` + ); + } } } - return this._internalModel.setDirtyAttribute(key, value); + let recordData = getRecordDataFor(this); + if (this instanceof Model) { + updateViaInternalModel(this, key, value); + } else { + recordData.setDirtyAttribute(key, value); + } + + return recordData.getAttr(key); }, }).meta(meta); } + +function updateViaInternalModel(record: InstanceType, key: string, value: any): void { + let recordData = getRecordDataFor(record); + let internalModel = record._internalModel; + + if (internalModel.isDeleted()) { + throw new Error( + `Attempted to set '${key}' to '${value}' on the deleted record ${internalModel}` + ); + } + + let currentValue = recordData.getAttr(key); + if (currentValue !== value) { + recordData.setDirtyAttribute(key, value); + let isDirty = recordData.isAttrDirty(key); + + internalModel.send('didSetProperty', { + name: key, + isDirty: isDirty, + }); + } +} diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index f9e4cbc63d8..73a1f0a5e90 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -12,11 +12,12 @@ import RootState from './states'; import Snapshot from '../snapshot'; import OrderedSet from '../ordered-set'; import ManyArray from '../many-array'; +import Model from './model'; import { PromiseBelongsTo, PromiseManyArray } from '../promise-proxies'; import { RecordReference, BelongsToReference, HasManyReference } from '../references'; import { default as recordDataFor, relationshipStateFor } from '../record-data-for'; -import { setRecordDataFor } from './record-data-map'; +import { setRecordDataFor, RECORD_DATA_KEY } from './record-data-map'; /* The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached @@ -93,7 +94,6 @@ export default class InternalModel { this.clientId = clientId; this._recordData = store._createRecordData(modelName, id, clientId, this); - setRecordDataFor(this, this._recordData); // this ensure ordered set can quickly identify this as unique this[Ember.GUID_KEY] = InternalModelReferenceId++ + 'internal-model'; @@ -287,10 +287,14 @@ export default class InternalModel { } let recordData = this._recordData; - setRecordDataFor(createOptions, recordData); + createOptions[RECORD_DATA_KEY] = recordData; this._record = store._modelFactoryFor(this.modelName).create(createOptions); - // TODO should we unmap createOptions after record construction? - setRecordDataFor(this._record, recordData); + // mapping of record to recordData is handled by `Model` itself. + // but for custom Models (see the `modelFactoryFor` RFC) it is done + // here to ensure that it happens. + if (!(this._record instanceof Model)) { + setRecordDataFor(this._record, recordData); + } this._triggerDeferredTriggers(); heimdall.stop(token); @@ -699,10 +703,6 @@ export default class InternalModel { this.pushedData(); } - getAttributeValue(key) { - return this._recordData.getAttr(key); - } - setDirtyHasMany(key, records) { assertRecordsPassedToHasMany(records); return this._recordData.setDirtyHasMany(key, extractRecordDatasFromRecords(records)); @@ -712,24 +712,6 @@ export default class InternalModel { return this._recordData.setDirtyBelongsTo(key, extractRecordDataFromRecord(value)); } - setDirtyAttribute(key, value) { - if (this.isDeleted()) { - throw new EmberError(`Attempted to set '${key}' to '${value}' on the deleted record ${this}`); - } - - let currentValue = this.getAttributeValue(key); - if (currentValue !== value) { - this._recordData.setDirtyAttribute(key, value); - let isDirty = this._recordData.isAttrDirty(key); - this.send('didSetProperty', { - name: key, - isDirty: isDirty, - }); - } - - return value; - } - get isDestroyed() { return this._isDestroyed; } diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 134b9acd7dc..8d6d000310f 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1,4 +1,5 @@ import { isNone } from '@ember/utils'; +import { lte } from 'ember-compatibility-helpers'; import EmberError from '@ember/error'; import Evented from '@ember/object/evented'; import EmberObject, { computed, get } from '@ember/object'; @@ -12,7 +13,7 @@ import { relatedTypesDescriptor, relationshipsDescriptor, } from '../relationships/ext'; -import recordDataFor from '../record-data-for'; +import { setRecordDataFor, getRecordDataFor } from './record-data-map'; import Ember from 'ember'; import InternalModel from './internal-model'; import RootState from './states'; @@ -76,6 +77,16 @@ const Model = EmberObject.extend(Evented, { this[property.name] = property.descriptor.value; }, + init(createArgs) { + // with DS.Model we guarantee that `attr` `belongsTo` and `hasMany` can be accessed + // during `init` once `_super` has been called. This is necessary so that the above + // can be true. Custom Model classes that also want this guarantee will need to do + // the same. + let recordData = getRecordDataFor(createArgs); + setRecordDataFor(this, recordData); + this._super(createArgs); + }, + /** If this property is `true` the record is in the `empty` state. Empty is the first state all records enter after they have @@ -1147,7 +1158,7 @@ Object.defineProperty(Model.prototype, 'data', { until: '3.9', } ); - return recordDataFor(this)._data; + return getRecordDataFor(this)._data; }, }); @@ -1195,15 +1206,15 @@ if (DEBUG) { }; Model.reopen({ - init() { - this._super(...arguments); - - if (!this._internalModel) { + init(createArgs) { + if (!createArgs || !createArgs._internalModel) { throw new EmberError( 'You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.' ); } + this._super(createArgs); + if ( !isDefaultEmptyDescriptor(this, '_internalModel') || !(this._internalModel instanceof InternalModel) @@ -1213,16 +1224,6 @@ if (DEBUG) { ); } - if ( - !isDefaultEmptyDescriptor(this, 'recordData') || - this.recordData !== undefined || - this.recordData !== this._internalModel.recordData - ) { - throw new Error( - `'recordData' is a reserved property name on instances of classes extending Model. Please choose a different property name for ${this.constructor.toString()}` - ); - } - if ( !isDefaultEmptyDescriptor(this, 'currentState') || this.get('currentState') !== this._internalModel.currentState @@ -1243,6 +1244,15 @@ if (DEBUG) { }); } +// primarily for 2.18 LTS support, not needed >= 3.1 +if (lte('3.0.9000')) { + Model.reopenClass({ + create(createArgs) { + return new this(createArgs); + }, + }); +} + Model.reopenClass({ isModel: true, diff --git a/addon/-private/system/model/record-data-map.ts b/addon/-private/system/model/record-data-map.ts index 30e44a0be83..456c636ccbe 100644 --- a/addon/-private/system/model/record-data-map.ts +++ b/addon/-private/system/model/record-data-map.ts @@ -1,28 +1,51 @@ import { DEBUG } from '@glimmer/env'; -// TODO is there a way to import classes without causing cyclical imports for rollup? -// maybe strip "typing" imports prior to rollup? -type InternalModel = object; +/** + * Generally we use a WeakMap to store the 1:1 mapping between + * Record/CreateOptions and RecordData. + * + * However, we have no guarantee that the CreateOptions we pass to + * `factory.create(createOptions)` are the same object that we receive + * as the first arg to `Model.init()` (in fact, they are not!). + * + * For this reason, we use this randomly generated string key to store + * the mapping for CreateOptions. This maintains isolation without + * resulting in a performance hit. + */ +export const RECORD_DATA_KEY = `${Date.now()}-record-data`; + +// TODO TS: create a specific interface type CreateOptions = object; +// TODO TS: create a specific interface type Record = object; -type RecordData = object; +// TODO TS: create a specific interface +type RecordData = { + hasAttr(key); + getAttr(key); + setDirtyAttribute(key, value); + isAttrDirty(key); +}; -type Mappable = InternalModel | CreateOptions | Record; +type Mappable = CreateOptions | Record; const RecordDataMap = new WeakMap(); -export function getRecordDataFor(instance: Mappable): RecordData | null { +export function getRecordDataFor(instance: Mappable): RecordData { let recordData = RecordDataMap.get(instance); - if (DEBUG) { - if (recordData === undefined) { - throw new Error( - `Attempted to retrieve the RecordData mapped to ${instance} but no mapping exists!` - ); + if (recordData === undefined) { + if (instance[RECORD_DATA_KEY] !== undefined) { + return instance[RECORD_DATA_KEY]; } + + // TODO can we strip this in prod without throwing Typescript Errors? + debugger; + throw new Error( + `Attempted to retrieve the RecordData mapped to ${instance} but no mapping exists!` + ); } - return recordData || null; + return recordData; } export function setRecordDataFor(instance: Mappable, recordData: RecordData): void { diff --git a/ember-cli-build.js b/ember-cli-build.js index aa2951398b8..419e4e955a2 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -7,6 +7,9 @@ module.exports = function(defaults) { 'ember-cli-babel': { throwUnlessParallelizable: true, }, + 'ember-cli-uglify': { + enabled: false, + }, }); /* diff --git a/package.json b/package.json index 4948a170cf3..2b1b2f0b170 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "broccoli-rollup": "^2.1.1", "calculate-cache-key-for-tree": "^1.1.0", "chalk": "^2.4.1", + "ember-compatibility-helpers": "^1.1.2", "ember-cli-babel": "^7.1.2", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.1.0", diff --git a/tests/integration/adapter/client-side-delete-test.js b/tests/integration/adapter/client-side-delete-test.js index 3470a0072f7..e8bf2c6609b 100644 --- a/tests/integration/adapter/client-side-delete-test.js +++ b/tests/integration/adapter/client-side-delete-test.js @@ -75,7 +75,7 @@ test('client-side deleted records can be added back from an inverse', async func await book2.destroyRecord({ adapterOptions: { clientSideDelete: true } }); - book2.unloadRecord(); + run(() => book2.unloadRecord()); await settled(); diff --git a/tests/integration/application-test.js b/tests/integration/application-test.js index 74c1db3a471..76769a4f5b7 100644 --- a/tests/integration/application-test.js +++ b/tests/integration/application-test.js @@ -133,7 +133,7 @@ module('integration/application - Attaching initializer', function(hooks) { this.application = this.TestApplication.create({ autoboot: false }); - await this.application.boot(); + await run(() => this.application.boot()); assert.ok(ran, 'ember-data initializer was found'); }); @@ -153,7 +153,9 @@ module('integration/application - Attaching initializer', function(hooks) { this.application = this.TestApplication.create({ autoboot: false }); - await this.application.boot().then(() => (this.owner = this.application.buildInstance())); + await run(() => this.application.boot()).then( + () => (this.owner = this.application.buildInstance()) + ); let store = this.owner.lookup('service:store'); assert.ok( diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index 32201a15855..0481542bcf5 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -1,4 +1,5 @@ import { setupTest } from 'ember-qunit'; +import { run } from '@ember/runloop'; import { A } from '@ember/array'; import { get } from '@ember/object'; import Model from 'ember-data/model'; @@ -122,7 +123,7 @@ module('integration/debug-adapter - DS.DebugAdapter', function(hooks) { assert.deepEqual(record.searchKeywords, ['2', 'New Post']); assert.deepEqual(record.color, 'green'); - post.unloadRecord(); + run(() => post.unloadRecord()); await settled(); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index e81a271faf9..264e7b6b4a1 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -149,7 +149,7 @@ module('unit/model - Model', function(hooks) { 'the deleted person is not removed from store (no unload called)' ); - assert.expectAssertion(() => { + assert.throws(() => { set(record, 'isArchived', true); }, /Attempted to set 'isArchived' to 'true' on the deleted record /); @@ -676,12 +676,6 @@ module('unit/model - Model', function(hooks) { @attr('string') name; } - class NativePostWithRecordData extends Model { - @attr('string', { defaultValue: 'hello' }) - recordData; - @attr('string') - name; - } class NativePostWithCurrentState extends Model { @attr('string') currentState; @@ -690,7 +684,6 @@ module('unit/model - Model', function(hooks) { } const PROP_MAP = { _internalModel: NativePostWithInternalModel, - recordData: NativePostWithRecordData, currentState: NativePostWithCurrentState, }; @@ -730,7 +723,7 @@ module('unit/model - Model', function(hooks) { }); } - ['recordData', '_internalModel', 'currentState'].forEach(testReservedProperty); + ['_internalModel', 'currentState'].forEach(testReservedProperty); testInDebug( 'A subclass of Model throws an error when calling create() directly', diff --git a/yarn.lock b/yarn.lock index 5cf35fee08c..06da36cecbe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3643,7 +3643,7 @@ ember-compatibility-helpers@^1.0.0: ember-cli-version-checker "^2.1.1" semver "^5.4.1" -ember-compatibility-helpers@^1.1.1: +ember-compatibility-helpers@^1.1.1, ember-compatibility-helpers@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/ember-compatibility-helpers/-/ember-compatibility-helpers-1.1.2.tgz#ae0ee4a7a2858b5ffdf79b428c23aee85c47d93d" dependencies: @@ -3746,8 +3746,8 @@ ember-source-channel-url@^1.0.1, ember-source-channel-url@^1.1.0: got "^8.0.1" ember-source@~3.5.0: - version "3.5.0" - resolved "https://registry.npmjs.org/ember-source/-/ember-source-3.5.0.tgz#2322e393125684e1e043d0eedad8fd79c6de78a8" + version "3.5.1" + resolved "https://registry.npmjs.org/ember-source/-/ember-source-3.5.1.tgz#fed88dc675f031b499642dd19819f7f4d558d3fd" dependencies: broccoli-funnel "^2.0.1" broccoli-merge-trees "^2.0.0" @@ -5768,7 +5768,7 @@ isurl@^1.0.0-alpha5: jquery@^3.3.1: version "3.3.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" + resolved "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" js-levenshtein@^1.1.3: version "1.1.4" @@ -5850,7 +5850,6 @@ json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: json-typescript@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-typescript/-/json-typescript-1.0.1.tgz#9d71a17627a20a61dbbf504e33561030f4eefd7f" - integrity sha512-+PBRanpdVZ/MV8jJ044EuJ1muG3Ic/jLAZYgDE0WPqBbU46D3w3e+yL4ZbxwTfGbR9ff6JZlAGeGxSmumbQl0A== json5@^0.5.0, json5@^0.5.1: version "0.5.1" From f873ef4222588b0906d20e2286d3cacbc04302f8 Mon Sep 17 00:00:00 2001 From: Igor Terzic Date: Tue, 27 Nov 2018 17:27:32 -0800 Subject: [PATCH 2426/2527] Revert "Add *.ts to `.npmignore`" --- .npmignore | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.npmignore b/.npmignore index 0351cb31a82..a032d9a0a41 100644 --- a/.npmignore +++ b/.npmignore @@ -33,9 +33,3 @@ yarn.lock **/*.rb node-tests/ lib/version-replace.js - -# typescript -# -# avoid publishing .d.ts or .ts files -# until they have become enforced "public" APIs -*.ts From b4a88cf82ddc1e7dcb4e6447d28cb782ca195ba2 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 28 Nov 2018 18:32:47 -0800 Subject: [PATCH 2427/2527] Update Release instructions --- RELEASE.md | 63 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 215ac40859f..39bfdbc89d9 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -6,50 +6,65 @@ lot of manual steps. The following steps navigate us through some of the release gotchas and will hopefully result in a successful release. +We cut fixes to released branches from their release branch. +We cut new `major/minor` releases from the `beta` branch. +We cut new `beta` releases from the `master` branch. + STEPS: ------ +Assuming that the remote `origin` is `git@github.com:emberjs/data.git` + +* For patches to `release` + * checkout `release` and ensure it is up todate with `origin/release` (`git fetch origin`). DO NOT WORK FROM A LOCAL `release` branch THAT DIFFERS +* For new major/minor releases + * Ensure `git fetch origin` is up todate for `origin/beta`. DO NOT WORK FROM A LOCAL `beta` branch THAT DIFFERS + * reset `release` to match `beta` +* For new beta releases + * Ensure `git getch origin` is up todate for `origin/master`. DO NOT WORK FROM A LOCAL `master` branch THAT DIFFERS + * checkout `beta` + * reset `beta` to match `origin/master` * ensure that the `ember-source` version in `package.json` matches only the minor range for the `ember-data` version we are releasing * E.G. `"ember-data": "3.4.1"` should have `"ember-source": "~3.4.0"`. For betas/canary, pointing at the last minor release is OK. * See https://github.com/emberjs/data/issues/5607 for the importance of this step. * ensure that the last two LTS releases of Ember (and only the last two) are included in `travis.yml`. * See https://github.com/emberjs/data/issues/5607 for the importance of this step. -* generate changelog (`PRIOR_VERSION=v2.0.0 HEAD=release ./bin/changelog`) +* `rm -rf node_modules dist` +* `yarn` +* generate changelog (`PRIOR_VERSION=v2.0.0 HEAD=release ./bin/changelog`) IT IS IMPORTANT THAT ALL CHANGES ARE ON THE REMOTE BRANCH SPECIFIED BY HEAD * prepend changelog output to `CHANGELOG.md` * edit changelog output to be as user-friendly as possible (drop [INTERNAL] changes, non-code changes, etc.) - * If this is the release branch make sure to pr the changelog to the master branch and cherry pick it to the release branch. - * If this is the beta branch the changelogs do not need to be pred to the master branch as master will be updated when the beta goes to release. * Bump version in package.json * `git add package.json` * `git commit -m "Release Ember Data X.Y.Z-beta.n"` * Git tag version * `git tag vX.Y.Z-beta.n` -* Do a production build. - * `rm -rf node_modules; yarn install; npm run build:production` -* Publish to NPM - * `npm publish` or `npm publish --tag beta` or `npm publish --tag release-1-13` -* Update the `/builds/` page on the website - * `cd ../website` - * Edit `lastRelease`, `futureVersion` and `date` values for the release channel we are releasing ([beta](https://github.com/ember-learn/builds/blob/master/app/fixtures/ember-data/beta.js) or [release](https://github.com/ember-learn/builds/blob/master/app/fixtures/ember-data/release.js). -* Write a Release Blog Post (Does not happen for beta releases) +* Push the changes and the tag to upsteam + * `git push origin release` `git push origin --tags` +* Do a production build (this is because _____) + * `yarn build:production` +* If this is a patch to the latest release: `npm publish` +* Else if this is a patch to beta, `npm publish --tag beta` +* Else publish the specific version `npm publish --tag release-3-5` where this is the "minor" but without the patch. +* Visit [Ember Data Releases](https://github.com/emberjs/data/releases) + * Click on the "more recent tags" + * Click on the tag just published + * Edit the tag, adding a meaningful title and attaching the changelog (see other releases for examples) + * Click pre-release for beta releases + * Publish the release! +* Submit a PR to `ember-learn/builds` to update the builds for this channel + +For releases of new Major/Minor versions + + * Write a Release Blog Post (Does not happen for beta releases) * Commits since last release: `git log --oneline release..beta | wc -l`. * Contributors since last release: `git shortlog -s -n release...beta | wc -l` + * Submit a Pull request to the https://github.com/ember-cli/ember-cli to update the version of Ember Data * (per request by @rwjblue and is also a great idea to make upgrading/new apps easier) -* Bump version in package.json back to a canary version -* For beta.1 releases, branch beta from master and update https://github.com/emberjs/data/blob/master/config/features.json to have `false` values instead of `null` and update the version in package.json - - -Tag the release - -1. Under `Releases` on GitHub choose `Draft New Release` -* enter the new version number as the tag prefixed with `v` e.g. (`v0.1.12`) -* for release title choose a great name, no pressure -* in the description paste the changelog items for this release only -* click pre-release for beta releases -* publish the release Announce release! 1. on Twitter -* then crosslink Twitter post on Discord [#dev-ember-data](https://discordapp.com/channels/480462759797063690/480501977931972608) and [#ember-data](https://discordapp.com/channels/480462759797063690/486549196837486592) +* then crosslink Twitter post on slack #dev-ember-data and #ember-data + From 4167cbab5b717d9f281b191314e81602bbd708e0 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 28 Nov 2018 18:34:05 -0800 Subject: [PATCH 2428/2527] Restore links --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 39bfdbc89d9..f98cfe998b4 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -66,5 +66,5 @@ For releases of new Major/Minor versions Announce release! 1. on Twitter -* then crosslink Twitter post on slack #dev-ember-data and #ember-data +* then crosslink Twitter post on Discord [#dev-ember-data](https://discordapp.com/channels/480462759797063690/480501977931972608) and [#ember-data](https://discordapp.com/channels/480462759797063690/486549196837486592) From f2783457140a11671c06aa1d2337f6ef8971368b Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 28 Nov 2018 18:35:38 -0800 Subject: [PATCH 2429/2527] Restore other links --- RELEASE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASE.md b/RELEASE.md index f98cfe998b4..d375385ddf0 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -53,6 +53,8 @@ Assuming that the remote `origin` is `git@github.com:emberjs/data.git` * Click pre-release for beta releases * Publish the release! * Submit a PR to `ember-learn/builds` to update the builds for this channel + * File to edit for [beta](https://github.com/ember-learn/builds/blob/master/app/fixtures/ember-data/beta.js + * File to edit for [release](https://github.com/ember-learn/builds/blob/master/app/fixtures/ember-data/release.js) For releases of new Major/Minor versions From 4f25a447e44ca3fd77b9dffe7c530d131141d3a4 Mon Sep 17 00:00:00 2001 From: Igor Terzic Date: Wed, 28 Nov 2018 18:40:57 -0800 Subject: [PATCH 2430/2527] Update RELEASE.md --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index d375385ddf0..1b886c0de1a 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -6,7 +6,7 @@ lot of manual steps. The following steps navigate us through some of the release gotchas and will hopefully result in a successful release. -We cut fixes to released branches from their release branch. +We cut new `patch` releases from their released branch. We cut new `major/minor` releases from the `beta` branch. We cut new `beta` releases from the `master` branch. From 2481e83e1b4d80d856ad668c57306e6b10dafe20 Mon Sep 17 00:00:00 2001 From: Igor Terzic Date: Wed, 28 Nov 2018 18:41:21 -0800 Subject: [PATCH 2431/2527] Update RELEASE.md --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 1b886c0de1a..3ebf94c0455 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -16,7 +16,7 @@ STEPS: Assuming that the remote `origin` is `git@github.com:emberjs/data.git` * For patches to `release` - * checkout `release` and ensure it is up todate with `origin/release` (`git fetch origin`). DO NOT WORK FROM A LOCAL `release` branch THAT DIFFERS + * checkout `release` and ensure it is up to date with `origin/release` (`git fetch origin`). DO NOT WORK FROM A LOCAL `release` branch THAT DIFFERS * For new major/minor releases * Ensure `git fetch origin` is up todate for `origin/beta`. DO NOT WORK FROM A LOCAL `beta` branch THAT DIFFERS * reset `release` to match `beta` From d6616eb1966644117a52d6d9a401d8908344eaec Mon Sep 17 00:00:00 2001 From: "David J. Hamilton" Date: Thu, 29 Nov 2018 17:56:16 -0800 Subject: [PATCH 2432/2527] [BUGFIX beta] Make _recordData lazy --- addon/-private/system/model/internal-model.js | 21 ++++++- tests/integration/records/record-data-test.js | 59 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index 73a1f0a5e90..c8ec5d495f4 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -93,7 +93,7 @@ export default class InternalModel { this.modelName = modelName; this.clientId = clientId; - this._recordData = store._createRecordData(modelName, id, clientId, this); + this.__recordData = null; // this ensure ordered set can quickly identify this as unique this[Ember.GUID_KEY] = InternalModelReferenceId++ + 'internal-model'; @@ -144,6 +144,17 @@ export default class InternalModel { return this._recordReference; } + get _recordData() { + if (this.__recordData === null) { + this._recordData = this.store._createRecordData(this.modelName, this.id, this.clientId, this); + } + return this.__recordData; + } + + set _recordData(newValue) { + this.__recordData = newValue; + } + get _recordArrays() { if (this.__recordArrays === null) { this.__recordArrays = new OrderedSet(); @@ -764,6 +775,10 @@ export default class InternalModel { hasChangedAttributes() { heimdall.increment(hasChangedAttributes); + if (this.isLoading() && !this.isReloading) { + // no need to instantiate _recordData in this case + return false; + } return this._recordData.hasChangedAttributes(); } @@ -776,6 +791,10 @@ export default class InternalModel { */ changedAttributes() { heimdall.increment(changedAttributes); + if (this.isLoading() && !this.isReloading) { + // no need to calculate changed attributes when calling `findRecord` + return {}; + } return this._recordData.changedAttributes(); } diff --git a/tests/integration/records/record-data-test.js b/tests/integration/records/record-data-test.js index e8bb3b29ee6..780db925daa 100644 --- a/tests/integration/records/record-data-test.js +++ b/tests/integration/records/record-data-test.js @@ -5,6 +5,7 @@ import { run } from '@ember/runloop'; import { attr, belongsTo, hasMany } from '@ember-decorators/data'; import { assign } from '@ember/polyfills'; import { RecordData, recordDataFor } from 'ember-data/-private'; +import { resolve } from 'rsvp'; class Person extends Model { @hasMany('pet', { inverse: null, async: false }) @@ -216,4 +217,62 @@ module('RecordData Compatibility', function(hooks) { assert.ok(false, 'expected `unloadRecord()` not to throw'); } }); + + test(`store.findRecord does not eagerly instantiate record data`, async function(assert) { + let recordDataInstances = 0; + class TestRecordData extends CustomRecordData { + constructor() { + super(...arguments); + ++recordDataInstances; + } + } + + store.createRecordDataFor = function(modelName, id, lid, storeWrapper) { + return new TestRecordData(modelName, id, lid, storeWrapper); + }; + this.owner.register( + 'adapter:pet', + class TestAdapter { + static create() { + return new TestAdapter(...arguments); + } + + findRecord() { + assert.equal( + recordDataInstances, + 0, + 'no instance created from findRecord before adapter promise resolves' + ); + + return resolve({ + data: { + id: '1', + type: 'pet', + attributes: { + name: 'Loki', + }, + }, + }); + } + } + ); + this.owner.register( + 'serializer:pet', + class TestSerializer { + static create() { + return new TestSerializer(...arguments); + } + + normalizeResponse(store, modelClass, payload) { + return payload; + } + } + ); + + assert.equal(recordDataInstances, 0, 'initially no instances'); + + await store.findRecord('pet', '1'); + + assert.equal(recordDataInstances, 1, 'record data created after promise fulfills'); + }); }); From 1b065295d66b37313e62770624f5dab760deeee8 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Tue, 4 Dec 2018 18:38:56 -0800 Subject: [PATCH 2433/2527] [FEAT errors] eliminate the call to warn for add/remove/clear --- addon/-private/system/model/errors.js | 181 +++++++++++++----------- tests/integration/records/error-test.js | 36 ++--- tests/unit/model/errors-test.js | 51 +++---- 3 files changed, 125 insertions(+), 143 deletions(-) diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index 2be135d1ec6..f1b85e89f79 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -3,7 +3,6 @@ import Evented from '@ember/object/evented'; import ArrayProxy from '@ember/array/proxy'; import { set, get, computed } from '@ember/object'; import { makeArray, A } from '@ember/array'; -import { warn } from '@ember/debug'; /** @module ember-data @@ -186,27 +185,42 @@ export default ArrayProxy.extend(Evented, { isEmpty: not('length').readOnly(), /** - Adds error messages to a given attribute and sends - `becameInvalid` event to the record. - - Example: - - ```javascript - if (!user.get('username') { - user.get('errors').add('username', 'This field is required'); - } - ``` - - @method add - @param {String} attribute - @param {(Array|String)} messages - @deprecated - */ + Manually adds errors to the record. This will triger the `becameInvalid` event/ lifecycle method on + the record and transition the record into an `invalid` state. + + Example + ```javascript + let errors = get(user, 'errors'); + + // add multiple errors + errors.add('password', [ + 'Must be at least 12 characters', + 'Must contain at least one symbol', + 'Cannot contain your name' + ]); + + errors.errorsFor('password'); + // => + // [ + // { attribute: 'password', message: 'Must be at least 12 characters' }, + // { attribute: 'password', message: 'Must contain at least one symbol' }, + // { attribute: 'password', message: 'Cannot contain your name' }, + // ] + + // add a single error + errors.add('username', 'This field is required'); + + errors.errorsFor('password'); + // => + // [ + // { attribute: 'username', message: 'This field is required' }, + // ] + ``` + @method add + @param {string} attribute - the property name of an attribute or relationship + @param {string[]|string} messages - an error message or array of error messages for the attribute + */ add(attribute, messages) { - warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.add', - }); - let wasEmpty = get(this, 'isEmpty'); this._add(attribute, messages); @@ -257,45 +271,32 @@ export default ArrayProxy.extend(Evented, { }, /** - Removes all error messages from the given attribute and sends - `becameValid` event to the record if there no more errors left. - - Example: - - ```app/models/user.js - import DS from 'ember-data'; - - export default DS.Model.extend({ - email: DS.attr('string'), - twoFactorAuth: DS.attr('boolean'), - phone: DS.attr('string') - }); - ``` - - ```app/routes/user/edit.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - actions: { - save: function(user) { - if (!user.get('twoFactorAuth')) { - user.get('errors').remove('phone'); - } - user.save(); - } - } - }); - ``` - - @method remove - @param {String} attribute - @deprecated - */ + Manually removes all errors for a given member from the record. + This will transition the record into a `valid` state, and + triggers the `becameValid` event and lifecycle method. + + Example: + + ```javascript + let errors = get('user', errors); + errors.add('phone', ['error-1', 'error-2']); + + errors.errorsFor('phone'); + // => + // [ + // { attribute: 'phone', message: 'error-1' }, + // { attribute: 'phone', message: 'error-2' }, + // ] + + errors.remove('phone'); + + errors.errorsFor('phone'); + // => undefined + ``` + @method remove + @param {string} member - the property name of an attribute or relationship + */ remove(attribute) { - warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.remove', - }); - if (get(this, 'isEmpty')) { return; } @@ -327,32 +328,44 @@ export default ArrayProxy.extend(Evented, { }, /** - Removes all error messages and sends `becameValid` event - to the record. - - Example: - - ```app/routes/user/edit.js - import Route from '@ember/routing/route'; - - export default Route.extend({ - actions: { - retrySave: function(user) { - user.get('errors').clear(); - user.save(); - } - } - }); - ``` - - @method clear - @deprecated - */ + Manually clears all errors for the record. + This will transition the record into a `valid` state, and + will trigger the `becameValid` event and lifecycle method. + + Example: + + ```javascript + let errors = get('user', errors); + errors.add('username', ['error-a']); + errors.add('phone', ['error-1', 'error-2']); + + errors.errorsFor('username'); + // => + // [ + // { attribute: 'username', message: 'error-a' }, + // ] + + errors.errorsFor('phone'); + // => + // [ + // { attribute: 'phone', message: 'error-1' }, + // { attribute: 'phone', message: 'error-2' }, + // ] + + errors.clear(); + + errors.errorsFor('username'); + // => undefined + + errors.errorsFor('phone'); + // => undefined + + errors.get('messages') + // => [] + ``` + @method remove + */ clear() { - warn(`Interacting with a record errors object will no longer change the record state.`, false, { - id: 'ds.errors.clear', - }); - if (get(this, 'isEmpty')) { return; } diff --git a/tests/integration/records/error-test.js b/tests/integration/records/error-test.js index 851950316fc..354b2ca1ff9 100644 --- a/tests/integration/records/error-test.js +++ b/tests/integration/records/error-test.js @@ -8,12 +8,6 @@ import RSVP from 'rsvp'; var env, store, Person; var attr = DS.attr; -function updateErrors(func, assert) { - assert.expectWarning(function() { - run(func); - }, 'Interacting with a record errors object will no longer change the record state.'); -} - module('integration/records/error', { beforeEach: function() { Person = DS.Model.extend({ @@ -36,8 +30,6 @@ module('integration/records/error', { }); testInDebug('adding errors during root.loaded.created.invalid works', function(assert) { - assert.expect(5); - var person = run(() => { store.push({ data: { @@ -59,11 +51,11 @@ testInDebug('adding errors during root.loaded.created.invalid works', function(a assert.equal(person._internalModel.currentState.stateName, 'root.loaded.updated.uncommitted'); - updateErrors(() => person.get('errors').add('firstName', 'is invalid'), assert); + person.get('errors').add('firstName', 'is invalid'); assert.equal(person._internalModel.currentState.stateName, 'root.loaded.updated.invalid'); - updateErrors(() => person.get('errors').add('lastName', 'is invalid'), assert); + person.get('errors').add('lastName', 'is invalid'); assert.deepEqual(person.get('errors').toArray(), [ { attribute: 'firstName', message: 'is invalid' }, @@ -72,8 +64,6 @@ testInDebug('adding errors during root.loaded.created.invalid works', function(a }); testInDebug('adding errors root.loaded.created.invalid works', function(assert) { - assert.expect(5); - let person = store.createRecord('person', { id: 'wat', firstName: 'Yehuda', @@ -87,11 +77,11 @@ testInDebug('adding errors root.loaded.created.invalid works', function(assert) assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); - updateErrors(() => person.get('errors').add('firstName', 'is invalid'), assert); + person.get('errors').add('firstName', 'is invalid'); assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); - updateErrors(() => person.get('errors').add('lastName', 'is invalid'), assert); + person.get('errors').add('lastName', 'is invalid'); assert.deepEqual(person.get('errors').toArray(), [ { attribute: 'firstName', message: 'is invalid' }, @@ -100,8 +90,6 @@ testInDebug('adding errors root.loaded.created.invalid works', function(assert) }); testInDebug('adding errors root.loaded.created.invalid works add + remove + add', function(assert) { - assert.expect(7); - let person = store.createRecord('person', { id: 'wat', firstName: 'Yehuda', @@ -113,15 +101,15 @@ testInDebug('adding errors root.loaded.created.invalid works add + remove + add' assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); - updateErrors(() => person.get('errors').add('firstName', 'is invalid'), assert); + person.get('errors').add('firstName', 'is invalid'); assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); - updateErrors(() => person.get('errors').remove('firstName'), assert); + person.get('errors').remove('firstName'); assert.deepEqual(person.get('errors').toArray(), []); - updateErrors(() => person.get('errors').add('firstName', 'is invalid'), assert); + person.get('errors').add('firstName', 'is invalid'); assert.deepEqual(person.get('errors').toArray(), [ { attribute: 'firstName', message: 'is invalid' }, @@ -131,8 +119,6 @@ testInDebug('adding errors root.loaded.created.invalid works add + remove + add' testInDebug('adding errors root.loaded.created.invalid works add + (remove, add)', function( assert ) { - assert.expect(6); - let person = store.createRecord('person', { id: 'wat', firstName: 'Yehuda', @@ -144,16 +130,16 @@ testInDebug('adding errors root.loaded.created.invalid works add + (remove, add) assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.uncommitted'); - updateErrors(() => { + { person.get('errors').add('firstName', 'is invalid'); - }, assert); + } assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); - updateErrors(() => { + { person.get('errors').remove('firstName'); person.get('errors').add('firstName', 'is invalid'); - }, assert); + } assert.equal(person._internalModel.currentState.stateName, 'root.loaded.created.invalid'); diff --git a/tests/unit/model/errors-test.js b/tests/unit/model/errors-test.js index 0cffcb12fd0..a341f349d5f 100644 --- a/tests/unit/model/errors-test.js +++ b/tests/unit/model/errors-test.js @@ -12,13 +12,6 @@ module('unit/model/errors', { }, }); -function updateErrors(func, assert) { - assert.expectWarning( - func, - 'Interacting with a record errors object will no longer change the record state.' - ); -} - AssertPrototype.becameInvalid = function becameInvalid(eventName) { if (eventName === 'becameInvalid') { this.ok(true, 'becameInvalid send'); @@ -40,33 +33,29 @@ AssertPrototype.unexpectedSend = function unexpectedSend(eventName) { }.bind(AssertPrototype); testInDebug('add error', function(assert) { - assert.expect(10); - errors.trigger = assert.becameInvalid; - updateErrors(() => errors.add('firstName', 'error'), assert); + errors.add('firstName', 'error'); errors.trigger = assert.unexpectedSend; assert.ok(errors.has('firstName'), 'it has firstName errors'); assert.equal(errors.get('length'), 1, 'it has 1 error'); - updateErrors(() => errors.add('firstName', ['error1', 'error2']), assert); + errors.add('firstName', ['error1', 'error2']); assert.equal(errors.get('length'), 3, 'it has 3 errors'); assert.ok(!errors.get('isEmpty'), 'it is not empty'); - updateErrors(() => errors.add('lastName', 'error'), assert); - updateErrors(() => errors.add('lastName', 'error'), assert); + errors.add('lastName', 'error'); + errors.add('lastName', 'error'); assert.equal(errors.get('length'), 4, 'it has 4 errors'); }); testInDebug('get error', function(assert) { - assert.expect(11); - assert.ok(errors.get('firstObject') === undefined, 'returns undefined'); errors.trigger = assert.becameInvalid; - updateErrors(() => errors.add('firstName', 'error'), assert); + errors.add('firstName', 'error'); errors.trigger = assert.unexpectedSend; assert.ok(errors.get('firstName').length === 1, 'returns errors'); assert.deepEqual(errors.get('firstObject'), { attribute: 'firstName', message: 'error' }); - updateErrors(() => errors.add('firstName', 'error2'), assert); + errors.add('firstName', 'error2'); assert.ok(errors.get('firstName').length === 2, 'returns errors'); - updateErrors(() => errors.add('lastName', 'error3'), assert); + errors.add('lastName', 'error3'); assert.deepEqual(errors.toArray(), [ { attribute: 'firstName', message: 'error' }, { attribute: 'firstName', message: 'error2' }, @@ -80,44 +69,38 @@ testInDebug('get error', function(assert) { }); testInDebug('remove error', function(assert) { - assert.expect(8); - errors.trigger = assert.becameInvalid; - updateErrors(() => errors.add('firstName', 'error'), assert); + errors.add('firstName', 'error'); errors.trigger = assert.becameValid; - updateErrors(() => errors.remove('firstName'), assert); + errors.remove('firstName'); errors.trigger = assert.unexpectedSend; assert.ok(!errors.has('firstName'), 'it has no firstName errors'); assert.equal(errors.get('length'), 0, 'it has 0 error'); assert.ok(errors.get('isEmpty'), 'it is empty'); - updateErrors(() => errors.remove('firstName'), assert); + errors.remove('firstName'); }); testInDebug('remove same errors fromm different attributes', function(assert) { - assert.expect(9); - errors.trigger = assert.becameInvalid; - updateErrors(() => errors.add('firstName', 'error'), assert); - updateErrors(() => errors.add('lastName', 'error'), assert); + errors.add('firstName', 'error'); + errors.add('lastName', 'error'); errors.trigger = assert.unexpectedSend; assert.equal(errors.get('length'), 2, 'it has 2 error'); - updateErrors(() => errors.remove('firstName'), assert); + errors.remove('firstName'); assert.equal(errors.get('length'), 1, 'it has 1 error'); errors.trigger = assert.becameValid; - updateErrors(() => errors.remove('lastName'), assert); + errors.remove('lastName'); assert.ok(errors.get('isEmpty'), 'it is empty'); }); testInDebug('clear errors', function(assert) { - assert.expect(8); - errors.trigger = assert.becameInvalid; - updateErrors(() => errors.add('firstName', ['error', 'error1']), assert); + errors.add('firstName', ['error', 'error1']); assert.equal(errors.get('length'), 2, 'it has 2 errors'); errors.trigger = assert.becameValid; - updateErrors(() => errors.clear(), assert); + errors.clear(); errors.trigger = assert.unexpectedSend; assert.ok(!errors.has('firstName'), 'it has no firstName errors'); assert.equal(errors.get('length'), 0, 'it has 0 error'); - updateErrors(() => errors.clear(), assert); + errors.clear(); }); From dd0243ec42cfabd892e5b432ec0d0122294d3c45 Mon Sep 17 00:00:00 2001 From: Igor Terzic Date: Tue, 4 Dec 2018 18:30:19 -0800 Subject: [PATCH 2434/2527] Revert "Ui layer cleanup" --- addon/-private/attr.ts | 63 +++++------------ addon/-private/system/model/internal-model.js | 32 ++++++--- addon/-private/system/model/model.js | 42 +++++------- .../-private/system/model/record-data-map.ts | 67 ------------------- ember-cli-build.js | 3 - package.json | 1 - .../adapter/client-side-delete-test.js | 2 +- tests/integration/application-test.js | 6 +- tests/integration/debug-adapter-test.js | 3 +- tests/unit/model-test.js | 11 ++- yarn.lock | 9 +-- 11 files changed, 73 insertions(+), 166 deletions(-) delete mode 100644 addon/-private/system/model/record-data-map.ts diff --git a/addon/-private/attr.ts b/addon/-private/attr.ts index da210661022..94d424cb3f3 100644 --- a/addon/-private/attr.ts +++ b/addon/-private/attr.ts @@ -1,15 +1,14 @@ import { computed } from '@ember/object'; import { assert } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; -import Model from './system/model/model'; -import { getRecordDataFor } from './system/model/record-data-map'; +import recordDataFor from './system/record-data-for'; /** @module ember-data */ -function getDefaultValue(record, options, propertyName) { +function getDefaultValue(record, options, key) { if (typeof options.defaultValue === 'function') { - return options.defaultValue.call(null, record, options, propertyName); + return options.defaultValue.apply(null, arguments); } else { let defaultValue = options.defaultValue; assert( @@ -20,6 +19,10 @@ function getDefaultValue(record, options, propertyName) { } } +function hasValue(internalModel, key) { + return recordDataFor(internalModel).hasAttr(key); +} + interface AttrOptions { defaultValue?: string | null | (() => any); } @@ -124,7 +127,7 @@ export default function attr(type?: string | AttrOptions, options?: AttrOptions) }; return computed({ - get(key: string) { + get(key) { if (DEBUG) { if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) { throw new Error( @@ -132,54 +135,22 @@ export default function attr(type?: string | AttrOptions, options?: AttrOptions) ); } } - - let recordData = getRecordDataFor(this); - if (recordData.hasAttr(key)) { - return recordData.getAttr(key); + let internalModel = this._internalModel; + if (hasValue(internalModel, key)) { + return internalModel.getAttributeValue(key); } else { return getDefaultValue(this, options, key); } }, - set(key: string, value: any) { + set(key, value) { if (DEBUG) { - if (this instanceof Model) { - if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) { - throw new Error( - `'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your attr on ${this.constructor.toString()}` - ); - } + if (['_internalModel', 'recordData', 'currentState'].indexOf(key) !== -1) { + throw new Error( + `'${key}' is a reserved property name on instances of classes extending Model. Please choose a different property name for your attr on ${this.constructor.toString()}` + ); } } - let recordData = getRecordDataFor(this); - if (this instanceof Model) { - updateViaInternalModel(this, key, value); - } else { - recordData.setDirtyAttribute(key, value); - } - - return recordData.getAttr(key); + return this._internalModel.setDirtyAttribute(key, value); }, }).meta(meta); } - -function updateViaInternalModel(record: InstanceType, key: string, value: any): void { - let recordData = getRecordDataFor(record); - let internalModel = record._internalModel; - - if (internalModel.isDeleted()) { - throw new Error( - `Attempted to set '${key}' to '${value}' on the deleted record ${internalModel}` - ); - } - - let currentValue = recordData.getAttr(key); - if (currentValue !== value) { - recordData.setDirtyAttribute(key, value); - let isDirty = recordData.isAttrDirty(key); - - internalModel.send('didSetProperty', { - name: key, - isDirty: isDirty, - }); - } -} diff --git a/addon/-private/system/model/internal-model.js b/addon/-private/system/model/internal-model.js index c8ec5d495f4..7864bba386f 100644 --- a/addon/-private/system/model/internal-model.js +++ b/addon/-private/system/model/internal-model.js @@ -12,12 +12,10 @@ import RootState from './states'; import Snapshot from '../snapshot'; import OrderedSet from '../ordered-set'; import ManyArray from '../many-array'; -import Model from './model'; import { PromiseBelongsTo, PromiseManyArray } from '../promise-proxies'; import { RecordReference, BelongsToReference, HasManyReference } from '../references'; import { default as recordDataFor, relationshipStateFor } from '../record-data-for'; -import { setRecordDataFor, RECORD_DATA_KEY } from './record-data-map'; /* The TransitionChainMap caches the `state.enters`, `state.setups`, and final state reached @@ -297,15 +295,7 @@ export default class InternalModel { createOptions.container = store.container; } - let recordData = this._recordData; - createOptions[RECORD_DATA_KEY] = recordData; this._record = store._modelFactoryFor(this.modelName).create(createOptions); - // mapping of record to recordData is handled by `Model` itself. - // but for custom Models (see the `modelFactoryFor` RFC) it is done - // here to ensure that it happens. - if (!(this._record instanceof Model)) { - setRecordDataFor(this._record, recordData); - } this._triggerDeferredTriggers(); heimdall.stop(token); @@ -714,6 +704,10 @@ export default class InternalModel { this.pushedData(); } + getAttributeValue(key) { + return this._recordData.getAttr(key); + } + setDirtyHasMany(key, records) { assertRecordsPassedToHasMany(records); return this._recordData.setDirtyHasMany(key, extractRecordDatasFromRecords(records)); @@ -723,6 +717,24 @@ export default class InternalModel { return this._recordData.setDirtyBelongsTo(key, extractRecordDataFromRecord(value)); } + setDirtyAttribute(key, value) { + if (this.isDeleted()) { + throw new EmberError(`Attempted to set '${key}' to '${value}' on the deleted record ${this}`); + } + + let currentValue = this.getAttributeValue(key); + if (currentValue !== value) { + this._recordData.setDirtyAttribute(key, value); + let isDirty = this._recordData.isAttrDirty(key); + this.send('didSetProperty', { + name: key, + isDirty: isDirty, + }); + } + + return value; + } + get isDestroyed() { return this._isDestroyed; } diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 8d6d000310f..134b9acd7dc 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1,5 +1,4 @@ import { isNone } from '@ember/utils'; -import { lte } from 'ember-compatibility-helpers'; import EmberError from '@ember/error'; import Evented from '@ember/object/evented'; import EmberObject, { computed, get } from '@ember/object'; @@ -13,7 +12,7 @@ import { relatedTypesDescriptor, relationshipsDescriptor, } from '../relationships/ext'; -import { setRecordDataFor, getRecordDataFor } from './record-data-map'; +import recordDataFor from '../record-data-for'; import Ember from 'ember'; import InternalModel from './internal-model'; import RootState from './states'; @@ -77,16 +76,6 @@ const Model = EmberObject.extend(Evented, { this[property.name] = property.descriptor.value; }, - init(createArgs) { - // with DS.Model we guarantee that `attr` `belongsTo` and `hasMany` can be accessed - // during `init` once `_super` has been called. This is necessary so that the above - // can be true. Custom Model classes that also want this guarantee will need to do - // the same. - let recordData = getRecordDataFor(createArgs); - setRecordDataFor(this, recordData); - this._super(createArgs); - }, - /** If this property is `true` the record is in the `empty` state. Empty is the first state all records enter after they have @@ -1158,7 +1147,7 @@ Object.defineProperty(Model.prototype, 'data', { until: '3.9', } ); - return getRecordDataFor(this)._data; + return recordDataFor(this)._data; }, }); @@ -1206,15 +1195,15 @@ if (DEBUG) { }; Model.reopen({ - init(createArgs) { - if (!createArgs || !createArgs._internalModel) { + init() { + this._super(...arguments); + + if (!this._internalModel) { throw new EmberError( 'You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.' ); } - this._super(createArgs); - if ( !isDefaultEmptyDescriptor(this, '_internalModel') || !(this._internalModel instanceof InternalModel) @@ -1224,6 +1213,16 @@ if (DEBUG) { ); } + if ( + !isDefaultEmptyDescriptor(this, 'recordData') || + this.recordData !== undefined || + this.recordData !== this._internalModel.recordData + ) { + throw new Error( + `'recordData' is a reserved property name on instances of classes extending Model. Please choose a different property name for ${this.constructor.toString()}` + ); + } + if ( !isDefaultEmptyDescriptor(this, 'currentState') || this.get('currentState') !== this._internalModel.currentState @@ -1244,15 +1243,6 @@ if (DEBUG) { }); } -// primarily for 2.18 LTS support, not needed >= 3.1 -if (lte('3.0.9000')) { - Model.reopenClass({ - create(createArgs) { - return new this(createArgs); - }, - }); -} - Model.reopenClass({ isModel: true, diff --git a/addon/-private/system/model/record-data-map.ts b/addon/-private/system/model/record-data-map.ts deleted file mode 100644 index 456c636ccbe..00000000000 --- a/addon/-private/system/model/record-data-map.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { DEBUG } from '@glimmer/env'; - -/** - * Generally we use a WeakMap to store the 1:1 mapping between - * Record/CreateOptions and RecordData. - * - * However, we have no guarantee that the CreateOptions we pass to - * `factory.create(createOptions)` are the same object that we receive - * as the first arg to `Model.init()` (in fact, they are not!). - * - * For this reason, we use this randomly generated string key to store - * the mapping for CreateOptions. This maintains isolation without - * resulting in a performance hit. - */ -export const RECORD_DATA_KEY = `${Date.now()}-record-data`; - -// TODO TS: create a specific interface -type CreateOptions = object; -// TODO TS: create a specific interface -type Record = object; -// TODO TS: create a specific interface -type RecordData = { - hasAttr(key); - getAttr(key); - setDirtyAttribute(key, value); - isAttrDirty(key); -}; - -type Mappable = CreateOptions | Record; - -const RecordDataMap = new WeakMap(); - -export function getRecordDataFor(instance: Mappable): RecordData { - let recordData = RecordDataMap.get(instance); - - if (recordData === undefined) { - if (instance[RECORD_DATA_KEY] !== undefined) { - return instance[RECORD_DATA_KEY]; - } - - // TODO can we strip this in prod without throwing Typescript Errors? - debugger; - throw new Error( - `Attempted to retrieve the RecordData mapped to ${instance} but no mapping exists!` - ); - } - - return recordData; -} - -export function setRecordDataFor(instance: Mappable, recordData: RecordData): void { - if (DEBUG) { - let existing = RecordDataMap.get(instance); - if (existing !== undefined) { - // even re-setting to the same instance is a mistake - if (existing === recordData) { - throw new Error( - `Attempting to create RecordData mapping for ${instance} but this same mapping has already been created!` - ); - } - throw new Error( - `Cannot create RecordData mapping for ${instance} as a different mapping already exists!` - ); - } - } - RecordDataMap.set(instance, recordData); -} diff --git a/ember-cli-build.js b/ember-cli-build.js index 419e4e955a2..aa2951398b8 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -7,9 +7,6 @@ module.exports = function(defaults) { 'ember-cli-babel': { throwUnlessParallelizable: true, }, - 'ember-cli-uglify': { - enabled: false, - }, }); /* diff --git a/package.json b/package.json index 2b1b2f0b170..4948a170cf3 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "broccoli-rollup": "^2.1.1", "calculate-cache-key-for-tree": "^1.1.0", "chalk": "^2.4.1", - "ember-compatibility-helpers": "^1.1.2", "ember-cli-babel": "^7.1.2", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.1.0", diff --git a/tests/integration/adapter/client-side-delete-test.js b/tests/integration/adapter/client-side-delete-test.js index e8bf2c6609b..3470a0072f7 100644 --- a/tests/integration/adapter/client-side-delete-test.js +++ b/tests/integration/adapter/client-side-delete-test.js @@ -75,7 +75,7 @@ test('client-side deleted records can be added back from an inverse', async func await book2.destroyRecord({ adapterOptions: { clientSideDelete: true } }); - run(() => book2.unloadRecord()); + book2.unloadRecord(); await settled(); diff --git a/tests/integration/application-test.js b/tests/integration/application-test.js index 76769a4f5b7..74c1db3a471 100644 --- a/tests/integration/application-test.js +++ b/tests/integration/application-test.js @@ -133,7 +133,7 @@ module('integration/application - Attaching initializer', function(hooks) { this.application = this.TestApplication.create({ autoboot: false }); - await run(() => this.application.boot()); + await this.application.boot(); assert.ok(ran, 'ember-data initializer was found'); }); @@ -153,9 +153,7 @@ module('integration/application - Attaching initializer', function(hooks) { this.application = this.TestApplication.create({ autoboot: false }); - await run(() => this.application.boot()).then( - () => (this.owner = this.application.buildInstance()) - ); + await this.application.boot().then(() => (this.owner = this.application.buildInstance())); let store = this.owner.lookup('service:store'); assert.ok( diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index 0481542bcf5..32201a15855 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -1,5 +1,4 @@ import { setupTest } from 'ember-qunit'; -import { run } from '@ember/runloop'; import { A } from '@ember/array'; import { get } from '@ember/object'; import Model from 'ember-data/model'; @@ -123,7 +122,7 @@ module('integration/debug-adapter - DS.DebugAdapter', function(hooks) { assert.deepEqual(record.searchKeywords, ['2', 'New Post']); assert.deepEqual(record.color, 'green'); - run(() => post.unloadRecord()); + post.unloadRecord(); await settled(); diff --git a/tests/unit/model-test.js b/tests/unit/model-test.js index 264e7b6b4a1..e81a271faf9 100644 --- a/tests/unit/model-test.js +++ b/tests/unit/model-test.js @@ -149,7 +149,7 @@ module('unit/model - Model', function(hooks) { 'the deleted person is not removed from store (no unload called)' ); - assert.throws(() => { + assert.expectAssertion(() => { set(record, 'isArchived', true); }, /Attempted to set 'isArchived' to 'true' on the deleted record /); @@ -676,6 +676,12 @@ module('unit/model - Model', function(hooks) { @attr('string') name; } + class NativePostWithRecordData extends Model { + @attr('string', { defaultValue: 'hello' }) + recordData; + @attr('string') + name; + } class NativePostWithCurrentState extends Model { @attr('string') currentState; @@ -684,6 +690,7 @@ module('unit/model - Model', function(hooks) { } const PROP_MAP = { _internalModel: NativePostWithInternalModel, + recordData: NativePostWithRecordData, currentState: NativePostWithCurrentState, }; @@ -723,7 +730,7 @@ module('unit/model - Model', function(hooks) { }); } - ['_internalModel', 'currentState'].forEach(testReservedProperty); + ['recordData', '_internalModel', 'currentState'].forEach(testReservedProperty); testInDebug( 'A subclass of Model throws an error when calling create() directly', diff --git a/yarn.lock b/yarn.lock index 06da36cecbe..5cf35fee08c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3643,7 +3643,7 @@ ember-compatibility-helpers@^1.0.0: ember-cli-version-checker "^2.1.1" semver "^5.4.1" -ember-compatibility-helpers@^1.1.1, ember-compatibility-helpers@^1.1.2: +ember-compatibility-helpers@^1.1.1: version "1.1.2" resolved "https://registry.npmjs.org/ember-compatibility-helpers/-/ember-compatibility-helpers-1.1.2.tgz#ae0ee4a7a2858b5ffdf79b428c23aee85c47d93d" dependencies: @@ -3746,8 +3746,8 @@ ember-source-channel-url@^1.0.1, ember-source-channel-url@^1.1.0: got "^8.0.1" ember-source@~3.5.0: - version "3.5.1" - resolved "https://registry.npmjs.org/ember-source/-/ember-source-3.5.1.tgz#fed88dc675f031b499642dd19819f7f4d558d3fd" + version "3.5.0" + resolved "https://registry.npmjs.org/ember-source/-/ember-source-3.5.0.tgz#2322e393125684e1e043d0eedad8fd79c6de78a8" dependencies: broccoli-funnel "^2.0.1" broccoli-merge-trees "^2.0.0" @@ -5768,7 +5768,7 @@ isurl@^1.0.0-alpha5: jquery@^3.3.1: version "3.3.1" - resolved "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" js-levenshtein@^1.1.3: version "1.1.4" @@ -5850,6 +5850,7 @@ json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: json-typescript@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-typescript/-/json-typescript-1.0.1.tgz#9d71a17627a20a61dbbf504e33561030f4eefd7f" + integrity sha512-+PBRanpdVZ/MV8jJ044EuJ1muG3Ic/jLAZYgDE0WPqBbU46D3w3e+yL4ZbxwTfGbR9ff6JZlAGeGxSmumbQl0A== json5@^0.5.0, json5@^0.5.1: version "0.5.1" From 54561e4da3eef11608adea14c466973a83a48907 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Fri, 7 Dec 2018 10:04:12 -0800 Subject: [PATCH 2435/2527] Bump json-typescript from 1.0.1 to 1.1.0 (#5775) Bumps [json-typescript](https://github.com/mike-north/json-typescript) from 1.0.1 to 1.1.0. - [Release notes](https://github.com/mike-north/json-typescript/releases) - [Changelog](https://github.com/mike-north/json-typescript/blob/master/CHANGELOG.md) - [Commits](https://github.com/mike-north/json-typescript/compare/v1.0.1...v1.1.0) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4948a170cf3..ef8de2ada36 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "execa": "^1.0.0", "github": "^14.0.0", "glob": "^7.1.3", - "json-typescript": "^1.0.1", + "json-typescript": "^1.1.0", "loader.js": "^4.7.0", "mocha": "^5.2.0", "mocha-only-detector": "1.0.0", diff --git a/yarn.lock b/yarn.lock index 5cf35fee08c..96cf764aff4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5847,10 +5847,10 @@ json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" -json-typescript@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-typescript/-/json-typescript-1.0.1.tgz#9d71a17627a20a61dbbf504e33561030f4eefd7f" - integrity sha512-+PBRanpdVZ/MV8jJ044EuJ1muG3Ic/jLAZYgDE0WPqBbU46D3w3e+yL4ZbxwTfGbR9ff6JZlAGeGxSmumbQl0A== +json-typescript@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/json-typescript/-/json-typescript-1.1.0.tgz#5369013526d516b13bde1ae2bbc541386dd12c72" + integrity sha512-6BzXAzBSfO4L3+IdCLISVQUzR4Wq946Xk2u7ChUAnvftyj/Ec1YgRmBOjw9Rw4wpdtvX678HPIYtYaGYr9fb9w== json5@^0.5.0, json5@^0.5.1: version "0.5.1" From ddee73964a5c854aeed685e678263a260153f9e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Fri, 7 Dec 2018 10:05:58 -0800 Subject: [PATCH 2436/2527] [Security] Bump merge from 1.2.0 to 1.2.1 (#5777) Bumps [merge](https://github.com/yeikos/js.merge) from 1.2.0 to 1.2.1. **This update includes security fixes.** - [Release notes](https://github.com/yeikos/js.merge/releases) - [Commits](https://github.com/yeikos/js.merge/compare/v1.2.0...v1.2.1) Signed-off-by: dependabot[bot] --- yarn.lock | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index 96cf764aff4..ec6f81be5db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6625,8 +6625,9 @@ merge-trees@^2.0.0: heimdalljs "^0.2.5" merge@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + version "1.2.1" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" + integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== methods@~1.1.2: version "1.1.2" From a083ebb52926cec77fe8a14d565616531ed1b825 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Fri, 7 Dec 2018 10:06:31 -0800 Subject: [PATCH 2437/2527] Bump broccoli-merge-trees from 3.0.1 to 3.0.2 (#5776) Bumps [broccoli-merge-trees](https://github.com/broccolijs/broccoli-merge-trees) from 3.0.1 to 3.0.2. - [Release notes](https://github.com/broccolijs/broccoli-merge-trees/releases) - [Changelog](https://github.com/broccolijs/broccoli-merge-trees/blob/master/CHANGELOG.md) - [Commits](https://github.com/broccolijs/broccoli-merge-trees/compare/v3.0.1...v3.0.2) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 14 ++++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index ef8de2ada36..2f1fe44df82 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "broccoli-debug": "^0.6.5", "broccoli-file-creator": "^2.1.1", "broccoli-funnel": "^2.0.1", - "broccoli-merge-trees": "^3.0.1", + "broccoli-merge-trees": "^3.0.2", "broccoli-rollup": "^2.1.1", "calculate-cache-key-for-tree": "^1.1.0", "chalk": "^2.4.1", diff --git a/yarn.lock b/yarn.lock index ec6f81be5db..ab6ddf3cd06 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2192,16 +2192,10 @@ broccoli-merge-trees@^2.0.0: broccoli-plugin "^1.3.0" merge-trees "^1.0.1" -broccoli-merge-trees@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-3.0.0.tgz#90e4959f9e3c57cf1f04fab35152f3d849468d8b" - dependencies: - broccoli-plugin "^1.3.0" - merge-trees "^2.0.0" - -broccoli-merge-trees@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-3.0.1.tgz#545dfe9f695cec43372b3ee7e63c7203713ea554" +broccoli-merge-trees@^3.0.0, broccoli-merge-trees@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-3.0.2.tgz#f33b451994225522b5c9bcf27d59decfd8ba537d" + integrity sha512-ZyPAwrOdlCddduFbsMyyFzJUrvW6b04pMvDiAQZrCwghlvgowJDY+EfoXn+eR1RRA5nmGHJ+B68T63VnpRiT1A== dependencies: broccoli-plugin "^1.3.0" merge-trees "^2.0.0" From e78e7795a6b5f50771311bce3dead1d0bbc7a72c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Fri, 7 Dec 2018 10:07:01 -0800 Subject: [PATCH 2438/2527] [Security] Bump underscore.string from 3.3.4 to 3.3.5 (#5779) Bumps [underscore.string](https://github.com/epeli/underscore.string) from 3.3.4 to 3.3.5. **This update includes security fixes.** - [Release notes](https://github.com/epeli/underscore.string/releases) - [Changelog](https://github.com/epeli/underscore.string/blob/master/CHANGELOG.markdown) - [Commits](https://github.com/epeli/underscore.string/compare/3.3.4...3.3.5) Signed-off-by: dependabot[bot] --- yarn.lock | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index ab6ddf3cd06..3ba5969e2da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9108,8 +9108,9 @@ umask@~1.1.0: resolved "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" underscore.string@^3.2.2, underscore.string@~3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" + version "3.3.5" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.5.tgz#fc2ad255b8bd309e239cbc5816fd23a9b7ea4023" + integrity sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg== dependencies: sprintf-js "^1.0.3" util-deprecate "^1.0.2" From 58b7963ae6c04f272f022b37c8804e965dc047b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Fri, 7 Dec 2018 10:07:34 -0800 Subject: [PATCH 2439/2527] Bump ember-cli-babel from 7.1.2 to 7.1.4 (#5780) Bumps [ember-cli-babel](https://github.com/babel/ember-cli-babel) from 7.1.2 to 7.1.4. - [Release notes](https://github.com/babel/ember-cli-babel/releases) - [Changelog](https://github.com/babel/ember-cli-babel/blob/master/CHANGELOG.md) - [Commits](https://github.com/babel/ember-cli-babel/compare/v7.1.2...v7.1.4) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 40 +++++++++++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 2f1fe44df82..3bddf923612 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "broccoli-rollup": "^2.1.1", "calculate-cache-key-for-tree": "^1.1.0", "chalk": "^2.4.1", - "ember-cli-babel": "^7.1.2", + "ember-cli-babel": "^7.1.4", "ember-cli-path-utils": "^1.0.0", "ember-cli-string-utils": "^1.1.0", "ember-cli-test-info": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 3ba5969e2da..409b4ac1443 100644 --- a/yarn.lock +++ b/yarn.lock @@ -903,6 +903,14 @@ amd-name-resolver@1.2.0, amd-name-resolver@^1.2.0: dependencies: ensure-posix-path "^1.0.1" +amd-name-resolver@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-1.2.1.tgz#cea40abff394268307df647ce340c83eda6e9cfc" + integrity sha512-cm0sUV2S8L6pwq0wpu0cHdA2KeEAmCVKy+R/qeZl/VxEn3JmU8WMM0IQrKyrnMXLXbULkZ7ptTaX8vKA0NhNvQ== + dependencies: + ensure-posix-path "^1.0.1" + object-hash "^1.3.1" + amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -1979,6 +1987,22 @@ broccoli-babel-transpiler@^7.0.0: rsvp "^4.8.3" workerpool "^2.3.1" +broccoli-babel-transpiler@^7.1.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.1.1.tgz#4202cd0653845083ee744fb4eaa4a2b50292f03f" + integrity sha512-iZE6yxDcEe4XSMEyqyyS+wtkNAsPUGJNleJoVu26Vt2Al8/GqRI5+wc7qquPb71I1W7AtqbkaqsgDFDqBoIYKw== + dependencies: + "@babel/core" "^7.0.0" + broccoli-funnel "^2.0.1" + broccoli-merge-trees "^3.0.0" + broccoli-persistent-filter "^1.4.3" + clone "^2.1.2" + hash-for-dep "^1.2.3" + heimdalljs-logger "^0.1.9" + json-stable-stringify "^1.0.1" + rsvp "^4.8.3" + workerpool "^2.3.1" + broccoli-builder@^0.18.14: version "0.18.14" resolved "https://registry.npmjs.org/broccoli-builder/-/broccoli-builder-0.18.14.tgz#4b79e2f844de11a4e1b816c3f49c6df4776c312d" @@ -3261,19 +3285,20 @@ ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-be ember-cli-version-checker "^2.1.2" semver "^5.5.0" -ember-cli-babel@^7.1.2: - version "7.1.2" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-7.1.2.tgz#543c64368d6138d12656db1143c02df1f2b0ee9c" +ember-cli-babel@^7.1.4: + version "7.1.4" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.1.4.tgz#5f2b6ba2156d8dce2681aea92689b57ffbc71ccb" + integrity sha512-NmYtGSaFfXiwMX6NvpQ78u2LTWKmQjTvEKxTiFRumH0kRZ3PNiipLf2SqInUiAIHVUR2e6ihyAt5sL4mPCjK/w== dependencies: "@babel/core" "^7.0.0" "@babel/plugin-transform-modules-amd" "^7.0.0" "@babel/polyfill" "^7.0.0" "@babel/preset-env" "^7.0.0" - amd-name-resolver "1.2.0" + amd-name-resolver "^1.2.1" babel-plugin-debug-macros "^0.2.0-beta.6" babel-plugin-ember-modules-api-polyfill "^2.5.0" babel-plugin-module-resolver "^3.1.1" - broccoli-babel-transpiler "^7.0.0" + broccoli-babel-transpiler "^7.1.0" broccoli-debug "^0.6.4" broccoli-funnel "^2.0.1" broccoli-source "^1.1.0" @@ -7204,6 +7229,11 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" +object-hash@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df" + integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA== + object-keys@^1.0.8: version "1.0.12" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" From 31aa21730dd55453b810e6fecbe436aa6d2e70b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 10 Dec 2018 10:40:57 -0800 Subject: [PATCH 2440/2527] Bump typescript from 3.1.3 to 3.2.2 (#5789) Bumps [typescript](https://github.com/Microsoft/TypeScript) from 3.1.3 to 3.2.2. - [Release notes](https://github.com/Microsoft/TypeScript/releases) - [Commits](https://github.com/Microsoft/TypeScript/compare/v3.1.3...v3.2.2) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 3bddf923612..1aa4ec9e060 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "prettier": "^1.14.3", "rimraf": "^2.6.2", "rsvp": "^4.8.4", - "typescript": "~3.1.3" + "typescript": "~3.2.2" }, "engines": { "node": ">= 6.0.0" diff --git a/yarn.lock b/yarn.lock index 409b4ac1443..e7e92abe3f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9097,9 +9097,10 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.3.tgz#01b70247a6d3c2467f70c45795ef5ea18ce191d5" +typescript@~3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.2.tgz#fe8101c46aa123f8353523ebdcf5730c2ae493e5" + integrity sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg== uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5" From 7a880f5966220ae8b8b64698f3f546ecafb017a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 10 Dec 2018 10:41:19 -0800 Subject: [PATCH 2441/2527] Bump ember-cli from 3.5.0 to 3.5.1 (#5788) Bumps [ember-cli](https://github.com/ember-cli/ember-cli) from 3.5.0 to 3.5.1. - [Release notes](https://github.com/ember-cli/ember-cli/releases) - [Changelog](https://github.com/ember-cli/ember-cli/blob/master/CHANGELOG.md) - [Commits](https://github.com/ember-cli/ember-cli/compare/v3.5.0...v3.5.1) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 1aa4ec9e060..f5fa968787c 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "broccoli-uglify-sourcemap": "^2.2.0", "co": "^4.6.0", "common-tags": "^1.8.0", - "ember-cli": "^3.5.0", + "ember-cli": "^3.5.1", "ember-cli-app-version": "^3.2.0", "ember-cli-blueprint-test-helpers": "^0.19.1", "ember-cli-dependency-checker": "^3.0.0", diff --git a/yarn.lock b/yarn.lock index e7e92abe3f5..64f13282091 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3560,9 +3560,10 @@ ember-cli-yuidoc@^0.8.8: rsvp "3.0.14" yuidocjs "^0.10.0" -ember-cli@^3.5.0: - version "3.5.0" - resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-3.5.0.tgz#978031042611008dce82c79226b8b677d325072c" +ember-cli@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-3.5.1.tgz#a1c7295eed935726891d40a81e0cc389f2d15fdf" + integrity sha512-oJylJwBIIH5IdgrnSXjA/Z64SSu7gZMyqtMBfMA8aGcBh2Bcb5dMDHpwwWXV4Crp1TGImhdtbwOtMAkzZT6Qpw== dependencies: amd-name-resolver "^1.2.0" babel-plugin-transform-es2015-modules-amd "^6.24.1" From 5e2ed597d183ab5223ac10cd5e3211359c9072e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 10 Dec 2018 10:41:56 -0800 Subject: [PATCH 2442/2527] Bump prettier from 1.14.3 to 1.15.3 (#5787) Bumps [prettier](https://github.com/prettier/prettier) from 1.14.3 to 1.15.3. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/master/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/1.14.3...1.15.3) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index f5fa968787c..a02bca73a4d 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,7 @@ "loader.js": "^4.7.0", "mocha": "^5.2.0", "mocha-only-detector": "1.0.0", - "prettier": "^1.14.3", + "prettier": "^1.15.3", "rimraf": "^2.6.2", "rsvp": "^4.8.4", "typescript": "~3.2.2" diff --git a/yarn.lock b/yarn.lock index 64f13282091..d7876cfa406 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7576,9 +7576,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^1.14.3: - version "1.14.3" - resolved "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz#90238dd4c0684b7edce5f83b0fb7328e48bd0895" +prettier@^1.15.3: + version "1.15.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.15.3.tgz#1feaac5bdd181237b54dbe65d874e02a1472786a" + integrity sha512-gAU9AGAPMaKb3NNSUUuhhFAS7SCO4ALTN4nRIn6PJ075Qd28Yn2Ig2ahEJWdJwJmlEBTUfC7mMUSFy8MwsOCfg== pretty-ms@^3.1.0: version "3.2.0" From fa3387482084554fbf613b01908f70ecd8b621d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 10 Dec 2018 10:42:27 -0800 Subject: [PATCH 2443/2527] Bump eslint from 5.7.0 to 5.10.0 (#5785) Bumps [eslint](https://github.com/eslint/eslint) from 5.7.0 to 5.10.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v5.7.0...v5.10.0) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 42 ++++++++++++++++++++++-------------------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index a02bca73a4d..b0ee89b128d 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "ember-source": "~3.5.0", "ember-source-channel-url": "^1.1.0", "ember-try": "^1.1.0", - "eslint": "^5.7.0", + "eslint": "^5.10.0", "eslint-config-prettier": "^3.1.0", "eslint-plugin-node": "^7.0.1", "eslint-plugin-prettier": "^3.0.0", diff --git a/yarn.lock b/yarn.lock index d7876cfa406..20f43f1d1bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -857,16 +857,20 @@ acorn-dynamic-import@^3.0.0: dependencies: acorn "^5.0.0" -acorn-jsx@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-4.1.1.tgz#e8e41e48ea2fe0c896740610ab6a4ffd8add225e" - dependencies: - acorn "^5.0.3" +acorn-jsx@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" + integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== -acorn@^5.0.0, acorn@^5.0.3, acorn@^5.5.3, acorn@^5.6.0: +acorn@^5.0.0, acorn@^5.5.3: version "5.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" +acorn@^6.0.2: + version "6.0.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.4.tgz#77377e7353b72ec5104550aa2d2097a2fd40b754" + integrity sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg== + after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" @@ -4011,9 +4015,10 @@ eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@^5.7.0: - version "5.7.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-5.7.0.tgz#55c326d6fb2ad45fcbd0ce17c3846f025d1d819c" +eslint@^5.10.0: + version "5.10.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.10.0.tgz#24adcbe92bf5eb1fc2d2f2b1eebe0c5e0713903a" + integrity sha512-HpqzC+BHULKlnPwWae9MaVZ5AXJKpkxCVXQHrFaRw3hbDj26V/9ArYM4Rr/SQ8pi6qUPLXSSXC4RBJlyq2Z2OQ== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.5.3" @@ -4024,7 +4029,7 @@ eslint@^5.7.0: eslint-scope "^4.0.0" eslint-utils "^1.3.1" eslint-visitor-keys "^1.0.0" - espree "^4.0.0" + espree "^5.0.0" esquery "^1.0.1" esutils "^2.0.2" file-entry-cache "^2.0.0" @@ -4034,7 +4039,6 @@ eslint@^5.7.0: ignore "^4.0.6" imurmurhash "^0.1.4" inquirer "^6.1.0" - is-resolvable "^1.1.0" js-yaml "^3.12.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" @@ -4054,12 +4058,14 @@ eslint@^5.7.0: table "^5.0.2" text-table "^0.2.0" -espree@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-4.0.0.tgz#253998f20a0f82db5d866385799d912a83a36634" +espree@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.0.tgz#fc7f984b62b36a0f543b13fb9cd7b9f4a7f5b65c" + integrity sha512-1MpUfwsdS9MMoN7ZXqAr9e9UKdVHDcvrJpyx7mm1WuQlx/ygErEQBzgi5Nh5qBHIoYweprhtMkTCb9GhcAIcsA== dependencies: - acorn "^5.6.0" - acorn-jsx "^4.1.1" + acorn "^6.0.2" + acorn-jsx "^5.0.0" + eslint-visitor-keys "^1.0.0" esprima@^4.0.0: version "4.0.1" @@ -5701,10 +5707,6 @@ is-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" -is-resolvable@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" From 5052c28522038f73c0c33d612a1764c239f21abf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 10 Dec 2018 10:42:57 -0800 Subject: [PATCH 2444/2527] Bump babel-plugin-filter-imports from 2.0.3 to 2.0.4 (#5786) Bumps [babel-plugin-filter-imports](https://github.com/ember-cli/babel-plugin-filter-imports) from 2.0.3 to 2.0.4. - [Release notes](https://github.com/ember-cli/babel-plugin-filter-imports/releases) - [Changelog](https://github.com/ember-cli/babel-plugin-filter-imports/blob/master/CHANGELOG.md) - [Commits](https://github.com/ember-cli/babel-plugin-filter-imports/compare/2.0.3...2.0.4) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index b0ee89b128d..b7fb4b8d5a2 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "@ember/ordered-set": "^2.0.3", "@glimmer/env": "^0.1.7", "babel-plugin-feature-flags": "^0.3.1", - "babel-plugin-filter-imports": "^2.0.3", + "babel-plugin-filter-imports": "^2.0.4", "babel6-plugin-strip-class-callcheck": "^6.0.0", "babel6-plugin-strip-heimdall": "^6.0.1", "broccoli-debug": "^0.6.5", diff --git a/yarn.lock b/yarn.lock index 20f43f1d1bf..c1b549acb23 100644 --- a/yarn.lock +++ b/yarn.lock @@ -570,6 +570,15 @@ lodash "^4.17.10" to-fast-properties "^2.0.0" +"@babel/types@^7.1.5": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.2.0.tgz#7941c5b2d8060e06f9601d6be7c223eef906d5d8" + integrity sha512-b4v7dyfApuKDvmPb+O488UlGuR1WbwMXFsO/cyqMrnfvRAChZKJAYeeglWTjUO1b9UghKKgepAQM5tsvBJca6A== + dependencies: + esutils "^2.0.2" + lodash "^4.17.10" + to-fast-properties "^2.0.0" + "@ember-decorators/babel-transforms@^2.1.2": version "2.1.2" resolved "https://registry.npmjs.org/@ember-decorators/babel-transforms/-/babel-transforms-2.1.2.tgz#b646e53ece7c18ae42cd03f320146cb1f26f4ebf" @@ -1391,11 +1400,12 @@ babel-plugin-feature-flags@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" -babel-plugin-filter-imports@^2.0.3: - version "2.0.3" - resolved "https://registry.npmjs.org/babel-plugin-filter-imports/-/babel-plugin-filter-imports-2.0.3.tgz#21f2773d0d74558986dd7af89f6f753d5fa92da3" +babel-plugin-filter-imports@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-2.0.4.tgz#9209b708ed3b228349c4e6f660358bf02685e803" + integrity sha512-Ra4VylqMFsmTJCUeLRJ/OP2ZqO0cCJQK2HKihNTnoKP4f8IhxHKL4EkbmfkwGjXCeDyXd0xQ6UTK8Nd+h9V/SQ== dependencies: - "@babel/types" "^7.0.0" + "@babel/types" "^7.1.5" lodash "^4.17.11" babel-plugin-htmlbars-inline-precompile@^0.2.5: From a1ee7ce93c3bb854f7ff4553bb2b688ecd6063f2 Mon Sep 17 00:00:00 2001 From: Igor Terzic Date: Fri, 7 Dec 2018 18:46:39 -0800 Subject: [PATCH 2445/2527] SetUknownProperty test for model --- tests/unit/model/init-properties-test.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/unit/model/init-properties-test.js b/tests/unit/model/init-properties-test.js index 5cbc74d852c..a5c4e9a6ad6 100644 --- a/tests/unit/model/init-properties-test.js +++ b/tests/unit/model/init-properties-test.js @@ -261,3 +261,25 @@ test('store.queryRecord(type, query) makes properties available during record in run(() => store.queryRecord('post', { id: '1' })); }); + +test('Model class does not get properties passed to setUknownProperty accidentaly', function(assert) { + assert.expect(2); + // If we end up passing additional properties to init in modelClasses, we will need to come up with a strategy for + // how to get setUnknownProperty to continue working + let { store } = setupStore({ + adapter: JSONAPIAdapter.extend(), + post: Model.extend({ + title: attr(), + setUnknownProperty: function(key, value) { + assert.equal(key, 'randomProp', 'Passed the correct key to setUknownProperty'); + assert.equal(value, 'An unknown prop', 'Passed the correct value to setUknownProperty'); + }, + }), + }); + run(() => { + store.createRecord('post', { + title: 'My Post', + randomProp: 'An unknown prop', + }); + }); +}); From 3cb9cbdb3107c3c82b0d89a0f65c665b5887ea4e Mon Sep 17 00:00:00 2001 From: Igor Terzic Date: Wed, 12 Dec 2018 14:07:40 -0800 Subject: [PATCH 2446/2527] Update init-properties-test.js --- tests/unit/model/init-properties-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/model/init-properties-test.js b/tests/unit/model/init-properties-test.js index a5c4e9a6ad6..02524f0d1bf 100644 --- a/tests/unit/model/init-properties-test.js +++ b/tests/unit/model/init-properties-test.js @@ -262,7 +262,7 @@ test('store.queryRecord(type, query) makes properties available during record in run(() => store.queryRecord('post', { id: '1' })); }); -test('Model class does not get properties passed to setUknownProperty accidentaly', function(assert) { +test('Model class does not get properties passed to setUknownProperty accidentally', function(assert) { assert.expect(2); // If we end up passing additional properties to init in modelClasses, we will need to come up with a strategy for // how to get setUnknownProperty to continue working From 4c539f466a21e91499ff18ba0318827db1f27252 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 12 Dec 2018 15:18:38 -0800 Subject: [PATCH 2447/2527] update changelog --- CHANGELOG.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 694dd4adc67..88babcec944 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ ### Master +### Release 3.6.0 (December 12, 2018) + +- [#5671](https://github.com/emberjs/data/pull/5671) Fix issue preventing coalescing of belongsTo +- [#5700](https://github.com/emberjs/data/pull/5700) [CHORE] remove deprecations targeted for 3.5 (#5700) +- [#5733](https://github.com/emberjs/data/pull/5733) [BUGFIX inspector] Fix columns names in debug-adapter (#5733) + +### Release 3.5.2 (November 29, 2018) + +- [#5766](https://github.com/emberjs/data/pull/5766) [BUGFIX] update ember-cli-babel to ensure @ember/canary-features is available +- [#5769](https://github.com/emberjs/data/pull/5769) [BUGFIX beta] backport #5767 Make _recordData lazy + +### Release 3.5.1 (November 28, 2018) + +- [#5762](https://github.com/emberjs/data/pull/5762) [BUGFIX unloadRecord] bfs compatibility for custom RecordData (#5703) + ### Release 3.5.0 (October 12, 2018) - [#5491](https://github.com/emberjs/data/pull/5491) [Feature] Add MU support for model and model-test blueprints @@ -1982,7 +1997,7 @@ var Post = DS.Model.extend({ ``` **no longer works**. Instead, you should just watch each attribute like you -would with any `EmberObject`: +would with any `Ember.Object`: ```javascript var Post = DS.Model.extend({ From cf259c402190ddc9d3dfe7392f49191da528d501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miros=C5=82aw=20Hankus?= Date: Sat, 19 Jan 2019 22:14:50 +0100 Subject: [PATCH 2448/2527] stop calling A as constructor --- addon/-private/system/model/errors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/-private/system/model/errors.js b/addon/-private/system/model/errors.js index f1b85e89f79..f2e16b82c4c 100644 --- a/addon/-private/system/model/errors.js +++ b/addon/-private/system/model/errors.js @@ -125,7 +125,7 @@ export default ArrayProxy.extend(Evented, { let map = get(this, 'errorsByAttributeName'); if (!map.has(attribute)) { - map.set(attribute, new A()); + map.set(attribute, A()); } return map.get(attribute); From ebd4de2c990f5d3d603316da48ba14cdb99f919d Mon Sep 17 00:00:00 2001 From: Bryan Crotaz Date: Sun, 6 Jan 2019 14:05:16 +0000 Subject: [PATCH 2449/2527] use assign instead of merge to remove deprecation --- addon/-private/system/store/finders.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index 7d3a7aa2419..e929c72f48f 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -8,7 +8,7 @@ import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './common'; import { normalizeResponseHelper } from './serializer-response'; import { serializerForAdapter } from './serializers'; -import { merge } from '@ember/polyfills'; +import { assign } from '@ember/polyfills'; function payloadIsNotBlank(adapterPayload) { if (Array.isArray(adapterPayload)) { @@ -301,7 +301,7 @@ function fixRelationshipData(relationshipData, relationshipKind, { id, modelName payload.push(parentRelationshipData); } else { payload = relationshipData || {}; - merge(payload, parentRelationshipData); + assign(payload, parentRelationshipData); } return payload; From e4e254c41f4752185497e0c0dfa15541fb625606 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Wed, 30 Jan 2019 09:20:24 -0500 Subject: [PATCH 2450/2527] Update broken link to DS.attr docs Closes #5816 --- addon/transforms/string.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/transforms/string.js b/addon/transforms/string.js index c4aeac50781..0229236e70e 100644 --- a/addon/transforms/string.js +++ b/addon/transforms/string.js @@ -5,7 +5,7 @@ import Transform from './transform'; The `DS.StringTransform` class is used to serialize and deserialize string attributes on Ember Data record objects. This transform is used when `string` is passed as the type parameter to the - [DS.attr](../../data#method_attr) function. + [DS.attr](./DS/methods/attr?anchor=attr) function. Usage From 50057353b92c79c13952db62a73eb9d247639ed4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 11 Dec 2018 05:47:56 +0000 Subject: [PATCH 2451/2527] Bump ember-source from 3.5.0 to 3.6.0 Bumps [ember-source](https://github.com/emberjs/ember.js) from 3.5.0 to 3.6.0. - [Release notes](https://github.com/emberjs/ember.js/releases) - [Changelog](https://github.com/emberjs/ember.js/blob/master/CHANGELOG.md) - [Commits](https://github.com/emberjs/ember.js/compare/v3.5.0...v3.6.0) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index b7fb4b8d5a2..90270f926b8 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "ember-qunit": "^3.5.3", "ember-qunit-assert-helpers": "^0.2.1", "ember-resolver": "^5.0.1", - "ember-source": "~3.5.0", + "ember-source": "~3.6.0", "ember-source-channel-url": "^1.1.0", "ember-try": "^1.1.0", "eslint": "^5.10.0", diff --git a/yarn.lock b/yarn.lock index c1b549acb23..75aa65d9947 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3299,7 +3299,7 @@ ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-be ember-cli-version-checker "^2.1.2" semver "^5.5.0" -ember-cli-babel@^7.1.4: +ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4: version "7.1.4" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.1.4.tgz#5f2b6ba2156d8dce2681aea92689b57ffbc71ccb" integrity sha512-NmYtGSaFfXiwMX6NvpQ78u2LTWKmQjTvEKxTiFRumH0kRZ3PNiipLf2SqInUiAIHVUR2e6ihyAt5sL4mPCjK/w== @@ -3779,19 +3779,20 @@ ember-source-channel-url@^1.0.1, ember-source-channel-url@^1.1.0: dependencies: got "^8.0.1" -ember-source@~3.5.0: - version "3.5.0" - resolved "https://registry.npmjs.org/ember-source/-/ember-source-3.5.0.tgz#2322e393125684e1e043d0eedad8fd79c6de78a8" +ember-source@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-3.6.0.tgz#0229b4fe6802dcfadb81e27ebcf50fff166889ec" + integrity sha512-Es6BE/lYxwiLPHZpFOcl2tQaOppvabIffQfcOJR9OzdM8ZgM06UR+tqdxrhO05UmD8MqHGc1FT/RmQlKuGZg0Q== dependencies: broccoli-funnel "^2.0.1" broccoli-merge-trees "^2.0.0" chalk "^2.3.0" + ember-cli-babel "^7.1.3" ember-cli-get-component-path-option "^1.0.0" ember-cli-is-package-missing "^1.0.0" ember-cli-normalize-entity-name "^1.0.0" ember-cli-path-utils "^1.0.0" ember-cli-string-utils "^1.1.0" - ember-cli-valid-component-name "^1.0.0" ember-cli-version-checker "^2.1.0" ember-router-generator "^1.2.3" inflection "^1.12.0" From 782081f45d5b0cb956ed9dc8eb2df124dd658866 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 12 Dec 2018 06:03:53 +0000 Subject: [PATCH 2452/2527] Bump @babel/plugin-transform-typescript from 7.1.0 to 7.2.0 Bumps [@babel/plugin-transform-typescript](https://github.com/babel/babel) from 7.1.0 to 7.2.0. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md) - [Commits](https://github.com/babel/babel/compare/v7.1.0...v7.2.0) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 90270f926b8..f8bc0b8f32d 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "silent-error": "^1.1.1" }, "devDependencies": { - "@babel/plugin-transform-typescript": "^7.1.0", + "@babel/plugin-transform-typescript": "^7.2.0", "@ember-decorators/babel-transforms": "^2.1.2", "@ember-decorators/data": "^3.0.0", "@types/ember": "~3.0.25", diff --git a/yarn.lock b/yarn.lock index 75aa65d9947..e0783e7ca8f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -286,9 +286,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-typescript@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.0.0.tgz#90f4fe0a741ae9c0dcdc3017717c05a0cbbd5158" +"@babel/plugin-syntax-typescript@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.2.0.tgz#55d240536bd314dcbbec70fd949c5cabaed1de29" + integrity sha512-WhKr6yu6yGpGcNMVgIBuI9MkredpVc7Y3YR4UzEZmDztHoL6wV56YBHLhWnjO1EvId1B32HrD3DRFc+zSoKI1g== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -472,12 +473,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-typescript@^7.1.0": - version "7.1.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.1.0.tgz#81e7b4be90e7317cbd04bf1163ebf06b2adee60b" +"@babel/plugin-transform-typescript@^7.1.0", "@babel/plugin-transform-typescript@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.2.0.tgz#bce7c06300434de6a860ae8acf6a442ef74a99d1" + integrity sha512-EnI7i2/gJ7ZNr2MuyvN2Hu+BHJENlxWte5XygPvfj/MbvtOkWor9zcnHpMMQL2YYaaCcqtIvJUyJ7QVfoGs7ew== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-typescript" "^7.0.0" + "@babel/plugin-syntax-typescript" "^7.2.0" "@babel/plugin-transform-unicode-regex@^7.0.0": version "7.0.0" From 9eb3097ca0423de9111d194410ab6b19ad1c028c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 12 Dec 2018 06:03:21 +0000 Subject: [PATCH 2453/2527] Bump broccoli-stew from 2.0.0 to 2.0.1 Bumps [broccoli-stew](https://github.com/stefanpenner/broccoli-stew) from 2.0.0 to 2.0.1. - [Release notes](https://github.com/stefanpenner/broccoli-stew/releases) - [Commits](https://github.com/stefanpenner/broccoli-stew/compare/v2.0.0...v2.0.1) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 52 +++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index f8bc0b8f32d..3f4e279ca18 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "babel-eslint": "^10.0.1", "broccoli-babel-transpiler": "^7.0.0", "broccoli-concat": "^3.7.3", - "broccoli-stew": "^2.0.0", + "broccoli-stew": "^2.0.1", "broccoli-string-replace": "^0.1.2", "broccoli-test-helper": "^2.0.0", "broccoli-uglify-sourcemap": "^2.2.0", diff --git a/yarn.lock b/yarn.lock index e0783e7ca8f..e15f8de7cce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2107,7 +2107,7 @@ broccoli-config-replace@^1.1.2: debug "^2.2.0" fs-extra "^0.24.0" -broccoli-debug@^0.6.1, broccoli-debug@^0.6.4: +broccoli-debug@^0.6.4: version "0.6.4" resolved "https://registry.yarnpkg.com/broccoli-debug/-/broccoli-debug-0.6.4.tgz#986eb3d2005e00e3bb91f9d0a10ab137210cd150" dependencies: @@ -2232,7 +2232,7 @@ broccoli-merge-trees@^2.0.0: broccoli-plugin "^1.3.0" merge-trees "^1.0.1" -broccoli-merge-trees@^3.0.0, broccoli-merge-trees@^3.0.2: +broccoli-merge-trees@^3.0.0, broccoli-merge-trees@^3.0.1, broccoli-merge-trees@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-3.0.2.tgz#f33b451994225522b5c9bcf27d59decfd8ba537d" integrity sha512-ZyPAwrOdlCddduFbsMyyFzJUrvW6b04pMvDiAQZrCwghlvgowJDY+EfoXn+eR1RRA5nmGHJ+B68T63VnpRiT1A== @@ -2286,6 +2286,25 @@ broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-p symlink-or-copy "^1.0.1" walk-sync "^0.3.1" +broccoli-persistent-filter@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-2.1.1.tgz#7bb2b1015baedf5cf58b5b2608495f3d78f81b12" + integrity sha512-2VCbLJqMg/AWJ6WTmv83X13a6DD3BS7Gngc932jrg1snVqsB8LJDyJh+Hd9v1tQ/vMA+4vbWgwk4tDmI/tAZWg== + dependencies: + async-disk-cache "^1.2.1" + async-promise-queue "^1.0.3" + broccoli-plugin "^1.0.0" + fs-tree-diff "^0.5.2" + hash-for-dep "^1.0.2" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + mkdirp "^0.5.1" + promise-map-series "^0.2.1" + rimraf "^2.6.1" + rsvp "^4.7.0" + symlink-or-copy "^1.0.1" + walk-sync "^0.3.1" + broccoli-plugin@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" @@ -2304,6 +2323,16 @@ broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli rimraf "^2.3.4" symlink-or-copy "^1.1.8" +broccoli-plugin@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.1.tgz#a26315732fb99ed2d9fb58f12a1e14e986b4fabd" + integrity sha512-DW8XASZkmorp+q7J4EeDEZz+LoyKLAd2XZULXyD9l4m9/hAKV3vjHmB1kiUshcWAYMgTP1m2i4NnqCE/23h6AQ== + dependencies: + promise-map-series "^0.2.1" + quick-temp "^0.1.3" + rimraf "^2.3.4" + symlink-or-copy "^1.1.8" + broccoli-rollup@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/broccoli-rollup/-/broccoli-rollup-2.1.1.tgz#0b77dc4b7560a53e998ea85f3b56772612d4988d" @@ -2340,24 +2369,25 @@ broccoli-sri-hash@^2.1.0: sri-toolbox "^0.2.0" symlink-or-copy "^1.0.1" -broccoli-stew@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-2.0.0.tgz#68f3d94f13b4a79aa15d582703574fb4c3215e50" +broccoli-stew@^2.0.0, broccoli-stew@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-2.0.1.tgz#d0a507b79bf5fea9ff84032ae837dc48670ab1dc" + integrity sha512-EUzgkbYF4m8YVD2bkEa7OfYJ11V3dQ+yPuxdz/nFh8eMEn6dhOujtuSBnOWsvGDgsS9oqNZgx/MHJxI6Rr3AqQ== dependencies: - broccoli-debug "^0.6.1" + broccoli-debug "^0.6.5" broccoli-funnel "^2.0.0" - broccoli-merge-trees "^3.0.0" - broccoli-persistent-filter "^1.1.6" - broccoli-plugin "^1.3.0" + broccoli-merge-trees "^3.0.1" + broccoli-persistent-filter "^2.1.1" + broccoli-plugin "^1.3.1" chalk "^2.4.1" debug "^3.1.0" ensure-posix-path "^1.0.1" fs-extra "^6.0.1" minimatch "^3.0.4" resolve "^1.8.1" - rsvp "^4.8.3" + rsvp "^4.8.4" symlink-or-copy "^1.2.0" - walk-sync "^0.3.0" + walk-sync "^0.3.3" broccoli-string-replace@^0.1.2: version "0.1.2" From 8dab07932180a7109e773669c645663cb3df28d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Fri, 7 Dec 2018 16:47:08 +0000 Subject: [PATCH 2454/2527] Bump @ember-decorators/data from 3.0.0 to 3.1.5 Bumps [@ember-decorators/data](https://github.com/ember-decorators/ember-decorators) from 3.0.0 to 3.1.5. - [Release notes](https://github.com/ember-decorators/ember-decorators/releases) - [Commits](https://github.com/ember-decorators/ember-decorators/compare/v3.0.0...v3.1.5) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 46 ++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 3f4e279ca18..df3f468fd97 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "devDependencies": { "@babel/plugin-transform-typescript": "^7.2.0", "@ember-decorators/babel-transforms": "^2.1.2", - "@ember-decorators/data": "^3.0.0", + "@ember-decorators/data": "^3.1.5", "@types/ember": "~3.0.25", "@types/ember-qunit": "~3.4.3", "@types/ember-test-helpers": "~1.0.4", diff --git a/yarn.lock b/yarn.lock index e15f8de7cce..0ba4640f286 100644 --- a/yarn.lock +++ b/yarn.lock @@ -606,12 +606,13 @@ "@ember-decorators/utils" "^3.0.0" ember-cli-babel "^6.6.0" -"@ember-decorators/data@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@ember-decorators/data/-/data-3.0.0.tgz#78c6cb8b9b14eeee4bfd265cd00c95dc09416420" +"@ember-decorators/data@^3.0.0", "@ember-decorators/data@^3.1.5": + version "3.1.5" + resolved "https://registry.yarnpkg.com/@ember-decorators/data/-/data-3.1.5.tgz#84494a8b5d55e9328789f37d84dd52e2f4d51cd3" + integrity sha512-R7QlEU9MxqPiQRpL+fdECdyCwMbPp8+XK+zo3gieJyCjhjP1p9Ssn+HZcSIdv4EMfdD3XL5FwePcZ+j/X4HU+Q== dependencies: - "@ember-decorators/utils" "^3.0.0" - ember-cli-babel "^6.6.0" + "@ember-decorators/utils" "^3.1.5" + ember-cli-babel "^7.1.3" "@ember-decorators/object@^3.0.0": version "3.0.0" @@ -636,6 +637,17 @@ ember-cli-babel "^6.6.0" ember-compatibility-helpers "^1.0.0" +"@ember-decorators/utils@^3.1.5": + version "3.1.5" + resolved "https://registry.yarnpkg.com/@ember-decorators/utils/-/utils-3.1.5.tgz#8f692582329a88553192e998012c7ca59e547c37" + integrity sha512-SqckJdUgnsZGZw6XHdRMeOk7YEdXHOZjJNOeJgNzjUdhS9jWSNu3OQrXcwYjJZBW8ICdqV87lpJB/rozTCezoQ== + dependencies: + babel-plugin-debug-macros "^0.1.11" + ember-cli-babel "^7.1.3" + ember-cli-version-checker "^2.1.2" + ember-compatibility-helpers "^1.1.2" + semver "^5.6.0" + "@ember/ordered-set@^2.0.3": version "2.0.3" resolved "https://registry.npmjs.org/@ember/ordered-set/-/ordered-set-2.0.3.tgz#2ac1ca73b3bd116063cae814898832ef434a57f9" @@ -3353,6 +3365,28 @@ ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4: ensure-posix-path "^1.0.2" semver "^5.5.0" +ember-cli-babel@^7.1.3: + version "7.1.4" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.1.4.tgz#5f2b6ba2156d8dce2681aea92689b57ffbc71ccb" + integrity sha512-NmYtGSaFfXiwMX6NvpQ78u2LTWKmQjTvEKxTiFRumH0kRZ3PNiipLf2SqInUiAIHVUR2e6ihyAt5sL4mPCjK/w== + dependencies: + "@babel/core" "^7.0.0" + "@babel/plugin-transform-modules-amd" "^7.0.0" + "@babel/polyfill" "^7.0.0" + "@babel/preset-env" "^7.0.0" + amd-name-resolver "^1.2.1" + babel-plugin-debug-macros "^0.2.0-beta.6" + babel-plugin-ember-modules-api-polyfill "^2.5.0" + babel-plugin-module-resolver "^3.1.1" + broccoli-babel-transpiler "^7.1.0" + broccoli-debug "^0.6.4" + broccoli-funnel "^2.0.1" + broccoli-source "^1.1.0" + clone "^2.1.2" + ember-cli-version-checker "^2.1.2" + ensure-posix-path "^1.0.2" + semver "^5.5.0" + ember-cli-blueprint-test-helpers@^0.19.1: version "0.19.1" resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.19.1.tgz#26df9724a6cb48f7acfa391dec7ec772888b0929" @@ -3709,7 +3743,7 @@ ember-compatibility-helpers@^1.0.0: ember-cli-version-checker "^2.1.1" semver "^5.4.1" -ember-compatibility-helpers@^1.1.1: +ember-compatibility-helpers@^1.1.1, ember-compatibility-helpers@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/ember-compatibility-helpers/-/ember-compatibility-helpers-1.1.2.tgz#ae0ee4a7a2858b5ffdf79b428c23aee85c47d93d" dependencies: From 91a1e283522661638b1b05780103462e9b1e4c2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 30 Jan 2019 22:35:47 +0000 Subject: [PATCH 2455/2527] Bump ember-decorators from 3.0.0 to 5.1.2 Bumps [ember-decorators](https://github.com/ember-decorators/ember-decorators) from 3.0.0 to 5.1.2. - [Release notes](https://github.com/ember-decorators/ember-decorators/releases) - [Commits](https://github.com/ember-decorators/ember-decorators/compare/v3.0.0...v5.1.2) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 149 ++++++++++++++++++++++++++------------------------- 2 files changed, 76 insertions(+), 75 deletions(-) diff --git a/package.json b/package.json index df3f468fd97..da542bd23a7 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "ember-cli-typescript-blueprints": "^2.0.0-beta.1", "ember-cli-uglify": "2.1.0", "ember-cli-yuidoc": "^0.8.8", - "ember-decorators": "^3.0.0", + "ember-decorators": "^5.1.2", "ember-disable-prototype-extensions": "^1.1.3", "ember-export-application-global": "^2.0.0", "ember-load-initializers": "^1.1.0", diff --git a/yarn.lock b/yarn.lock index 0ba4640f286..b65137e8f1a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -592,21 +592,23 @@ ember-cli-babel-plugin-helpers "^1.0.0" ember-cli-version-checker "^2.1.0" -"@ember-decorators/component@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@ember-decorators/component/-/component-3.0.0.tgz#9f31cc4eac800bedebf69ef8e432519092cd0430" +"@ember-decorators/component@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@ember-decorators/component/-/component-5.1.2.tgz#67ef09b083f7e94f0669e726b66a25cfdb44de4d" + integrity sha512-p72OP3D+pJ/XNXx8zqzkeHY5CGdQRDrxXrXJTezphTV7iBIrs9yMNfnXGIbN8QnItPV65OF8VbhjmzH7AN+LPg== dependencies: - "@ember-decorators/utils" "^3.0.0" - ember-cli-babel "^6.6.0" + "@ember-decorators/utils" "^5.1.2" + ember-cli-babel "^7.1.3" -"@ember-decorators/controller@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@ember-decorators/controller/-/controller-3.0.0.tgz#1f5b0e88f7456bc869775f70cd86a56cb690f301" +"@ember-decorators/controller@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@ember-decorators/controller/-/controller-5.1.2.tgz#afb45a3ec4e9e4abc9bd4ab17ba53693bf21b5a2" + integrity sha512-9QcMHqXWICrmH7ifXuwNxOG4lzOh5mdcr5ZlBYP6kDou2KJGtzV/jA0GlAd83gCkHZ984b1ZY129rwYVnU54xA== dependencies: - "@ember-decorators/utils" "^3.0.0" - ember-cli-babel "^6.6.0" + "@ember-decorators/utils" "^5.1.2" + ember-cli-babel "^7.1.3" -"@ember-decorators/data@^3.0.0", "@ember-decorators/data@^3.1.5": +"@ember-decorators/data@^3.1.5": version "3.1.5" resolved "https://registry.yarnpkg.com/@ember-decorators/data/-/data-3.1.5.tgz#84494a8b5d55e9328789f37d84dd52e2f4d51cd3" integrity sha512-R7QlEU9MxqPiQRpL+fdECdyCwMbPp8+XK+zo3gieJyCjhjP1p9Ssn+HZcSIdv4EMfdD3XL5FwePcZ+j/X4HU+Q== @@ -614,28 +616,29 @@ "@ember-decorators/utils" "^3.1.5" ember-cli-babel "^7.1.3" -"@ember-decorators/object@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@ember-decorators/object/-/object-3.0.0.tgz#84c5d3e62d3b211ffd17a795c0c4a65c3fe52f8d" +"@ember-decorators/data@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@ember-decorators/data/-/data-5.1.2.tgz#ae77cdf245284be63619190bebf81bee39af5b88" + integrity sha512-BqyhqdSf6JyaJuAhxBN6WYnBbXuFi1zR97dhNyRaM3gRgCu2HUePWPP5mTE6TsDVbcu2Vb536rjoV3ebhsPJqg== dependencies: - "@ember-decorators/utils" "^3.0.0" - ember-cli-babel "^6.6.0" - ember-compatibility-helpers "^1.0.0" + "@ember-decorators/utils" "^5.1.2" + ember-cli-babel "^7.1.3" -"@ember-decorators/service@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@ember-decorators/service/-/service-3.0.0.tgz#90fe410b8b2b80ad7227a85259e3a8c3852000a2" +"@ember-decorators/object@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@ember-decorators/object/-/object-5.1.2.tgz#575ad09bf891b283b0ccdad1ff58154f41a855a5" + integrity sha512-7JnMvBnRz3EpEv2p7fr63GvzyJSfqdXDfUKb/1RdRySF+IvcM8vvMOWyNOpgBvg5wBfmXlcnf2n6OQ9ZQey3wg== dependencies: - "@ember-decorators/utils" "^3.0.0" - ember-cli-babel "^6.6.0" + "@ember-decorators/utils" "^5.1.2" + ember-cli-babel "^7.1.3" -"@ember-decorators/utils@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@ember-decorators/utils/-/utils-3.0.0.tgz#f8e82ead2c75a8eaf2cef5b1811ab54fcb28bcee" +"@ember-decorators/service@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@ember-decorators/service/-/service-5.1.2.tgz#b547b2fbb4a5a2fd30cdc83fcd1345c52458099b" + integrity sha512-8b+oIdn672d/no8e1R7+bAPq+FnVNTjQetmXeJVGqtqA+hTA2FtOfJcch8AZDGfyBxL2V5S50n+K8R1WuEHxFg== dependencies: - babel-plugin-debug-macros "^0.1.11" - ember-cli-babel "^6.6.0" - ember-compatibility-helpers "^1.0.0" + "@ember-decorators/utils" "^5.1.2" + ember-cli-babel "^7.1.3" "@ember-decorators/utils@^3.1.5": version "3.1.5" @@ -648,6 +651,17 @@ ember-compatibility-helpers "^1.1.2" semver "^5.6.0" +"@ember-decorators/utils@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@ember-decorators/utils/-/utils-5.1.2.tgz#23ff1561ae6ecde14799d5df2a985fa134ca5269" + integrity sha512-EwaL93W0TDN9HjNCwVpYRtMShljP7y1vM4CUkF9lSMGcEqChl1HZemuJ2D2Lx+mIpPQhz8yskkPwCuvs9l3qGQ== + dependencies: + babel-plugin-debug-macros "^0.2.0" + ember-cli-babel "^7.1.3" + ember-cli-version-checker "^3.0.0" + ember-compatibility-helpers "^1.1.2" + semver "^5.6.0" + "@ember/ordered-set@^2.0.3": version "2.0.3" resolved "https://registry.npmjs.org/@ember/ordered-set/-/ordered-set-2.0.3.tgz#2ac1ca73b3bd116063cae814898832ef434a57f9" @@ -3325,7 +3339,7 @@ ember-cli-babel-plugin-helpers@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/ember-cli-babel-plugin-helpers/-/ember-cli-babel-plugin-helpers-1.0.2.tgz#d4bec0f32febc530e621ea8d66d3365727cb5e6c" -ember-cli-babel@^6.0.0, ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: +ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: version "6.16.0" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.16.0.tgz#623b4a2764ece72b65f1572fc8aeb5714a450228" dependencies: @@ -3365,28 +3379,6 @@ ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4: ensure-posix-path "^1.0.2" semver "^5.5.0" -ember-cli-babel@^7.1.3: - version "7.1.4" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.1.4.tgz#5f2b6ba2156d8dce2681aea92689b57ffbc71ccb" - integrity sha512-NmYtGSaFfXiwMX6NvpQ78u2LTWKmQjTvEKxTiFRumH0kRZ3PNiipLf2SqInUiAIHVUR2e6ihyAt5sL4mPCjK/w== - dependencies: - "@babel/core" "^7.0.0" - "@babel/plugin-transform-modules-amd" "^7.0.0" - "@babel/polyfill" "^7.0.0" - "@babel/preset-env" "^7.0.0" - amd-name-resolver "^1.2.1" - babel-plugin-debug-macros "^0.2.0-beta.6" - babel-plugin-ember-modules-api-polyfill "^2.5.0" - babel-plugin-module-resolver "^3.1.1" - broccoli-babel-transpiler "^7.1.0" - broccoli-debug "^0.6.4" - broccoli-funnel "^2.0.1" - broccoli-source "^1.1.0" - clone "^2.1.2" - ember-cli-version-checker "^2.1.2" - ensure-posix-path "^1.0.2" - semver "^5.5.0" - ember-cli-blueprint-test-helpers@^0.19.1: version "0.19.1" resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.19.1.tgz#26df9724a6cb48f7acfa391dec7ec772888b0929" @@ -3630,6 +3622,14 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-ve resolve "^1.3.3" semver "^5.3.0" +ember-cli-version-checker@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-3.0.1.tgz#2d084d2b261374582c68edb658a7df3a10112749" + integrity sha512-hX2tGrFVt8PyaiWclZr8XFNUPSnA+Ax4bMifDIVVtYY8RQZG8LZf9AGyTj4XImkBBWBtgKyOeQ0ovg3kgos4JA== + dependencies: + resolve "^1.9.0" + semver "^5.6.0" + ember-cli-yuidoc@^0.8.8: version "0.8.8" resolved "https://registry.yarnpkg.com/ember-cli-yuidoc/-/ember-cli-yuidoc-0.8.8.tgz#3858baaf85388a976024f9de40f1075fea58f606" @@ -3735,14 +3735,6 @@ ember-cli@^3.5.1: watch-detector "^0.1.0" yam "^0.0.24" -ember-compatibility-helpers@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.0.2.tgz#a7eb8969747d063720fe44658af5448589b437ba" - dependencies: - babel-plugin-debug-macros "^0.1.11" - ember-cli-version-checker "^2.1.1" - semver "^5.4.1" - ember-compatibility-helpers@^1.1.1, ember-compatibility-helpers@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/ember-compatibility-helpers/-/ember-compatibility-helpers-1.1.2.tgz#ae0ee4a7a2858b5ffdf79b428c23aee85c47d93d" @@ -3751,16 +3743,17 @@ ember-compatibility-helpers@^1.1.1, ember-compatibility-helpers@^1.1.2: ember-cli-version-checker "^2.1.1" semver "^5.4.1" -ember-decorators@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/ember-decorators/-/ember-decorators-3.0.0.tgz#23cee0ebea3f86806cd15b638bf5ffb40870ccf4" - dependencies: - "@ember-decorators/component" "^3.0.0" - "@ember-decorators/controller" "^3.0.0" - "@ember-decorators/data" "^3.0.0" - "@ember-decorators/object" "^3.0.0" - "@ember-decorators/service" "^3.0.0" - ember-cli-babel "^6.0.0" +ember-decorators@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/ember-decorators/-/ember-decorators-5.1.2.tgz#e4fc1b029a03e3f09fb6ae24ac4e6cf4177e4378" + integrity sha512-Vc99rlNWFY6VJEn1mtxVytLxb+vu31IKzPw4qqbG+ypynbKNEH7a5U44hxp0BH5S5Fl4U03tnyEIDc7K/rZ6kQ== + dependencies: + "@ember-decorators/component" "^5.1.2" + "@ember-decorators/controller" "^5.1.2" + "@ember-decorators/data" "^5.1.2" + "@ember-decorators/object" "^5.1.2" + "@ember-decorators/service" "^5.1.2" + ember-cli-babel "^7.1.3" semver "^5.5.0" ember-disable-prototype-extensions@^1.1.3: @@ -7561,6 +7554,11 @@ path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + path-posix@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" @@ -8241,6 +8239,13 @@ resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, dependencies: path-parse "^1.0.5" +resolve@^1.9.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" + integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== + dependencies: + path-parse "^1.0.6" + responselike@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" @@ -8409,14 +8414,10 @@ sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -"semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.5.1, semver@^5.6.0: +"semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.6.0" resolved "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" -"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" - semver@^4.3.1: version "4.3.6" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" From 909bb048a0e5ccb729c6df5f1598382bcb740b1f Mon Sep 17 00:00:00 2001 From: Rimian Perkins Date: Tue, 8 Jan 2019 11:27:40 +1100 Subject: [PATCH 2456/2527] [Docs] link to specs --- addon/serializers/json.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index dfbdcb354ef..47492a0b271 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -1310,7 +1310,7 @@ const JSONSerializer = Serializer.extend({ property of the payload object. This serializer expects this `errors` object to be an Array similar - to the following, compliant with the JSON-API specification: + to the following, compliant with the https://jsonapi.org/format/#errors specification: ```js { From f5b26e885bba1a145e743368728f16fc646db2a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 11 Dec 2018 05:46:42 +0000 Subject: [PATCH 2457/2527] Bump ember-cli-htmlbars-inline-precompile from 1.0.5 to 2.0.0 Bumps [ember-cli-htmlbars-inline-precompile](https://github.com/ember-cli/ember-cli-htmlbars-inline-precompile) from 1.0.5 to 2.0.0. - [Release notes](https://github.com/ember-cli/ember-cli-htmlbars-inline-precompile/releases) - [Changelog](https://github.com/ember-cli/ember-cli-htmlbars-inline-precompile/blob/master/CHANGELOG.md) - [Commits](https://github.com/ember-cli/ember-cli-htmlbars-inline-precompile/compare/v1.0.5...v2.0.0) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index da542bd23a7..9fd7a4dd76a 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "ember-cli-blueprint-test-helpers": "^0.19.1", "ember-cli-dependency-checker": "^3.0.0", "ember-cli-htmlbars": "^3.0.1", - "ember-cli-htmlbars-inline-precompile": "^1.0.5", + "ember-cli-htmlbars-inline-precompile": "^2.0.0", "ember-cli-inject-live-reload": "^2.0.1", "ember-cli-internal-test-helpers": "^0.9.1", "ember-cli-pretender": "^3.0.0", diff --git a/yarn.lock b/yarn.lock index b65137e8f1a..597ce751224 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1440,6 +1440,11 @@ babel-plugin-htmlbars-inline-precompile@^0.2.5: version "0.2.6" resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.6.tgz#c00b8a3f4b32ca04bf0f0d5169fcef3b5a66d69d" +babel-plugin-htmlbars-inline-precompile@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-1.0.0.tgz#a9d2f6eaad8a3f3d361602de593a8cbef8179c22" + integrity sha512-4jvKEHR1bAX03hBDZ94IXsYCj3bwk9vYsn6ux6JZNL2U5pvzCWjqyrGahfsGNrhERyxw8IqcirOi9Q6WCo3dkQ== + babel-plugin-module-resolver@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.1.1.tgz#881cf67e3d4b8400d5eaaefc1be44d2dc1fe404f" @@ -3426,11 +3431,12 @@ ember-cli-htmlbars-inline-precompile@^1.0.0: heimdalljs-logger "^0.1.9" silent-error "^1.1.0" -ember-cli-htmlbars-inline-precompile@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.5.tgz#312e050c9e3dd301c55fb399fd706296cd0b1d6a" +ember-cli-htmlbars-inline-precompile@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-2.0.0.tgz#8cbc941370ac6e728ae3d49c4164b3c7131d6118" + integrity sha512-oqqmT31ZG+md5UgCsumFulGXZvC3SbHnhLZ24uc5vKQuzA1c5cZmbOxb+1CnqLIovPCbcJWE3pL9kUMHiBh5oQ== dependencies: - babel-plugin-htmlbars-inline-precompile "^0.2.5" + babel-plugin-htmlbars-inline-precompile "^1.0.0" ember-cli-version-checker "^2.1.2" hash-for-dep "^1.2.3" heimdalljs-logger "^0.1.9" From 4bea385eb3f5fff7ad3a940d2ef9d9e6bcfac165 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 11 Dec 2018 05:47:20 +0000 Subject: [PATCH 2458/2527] Bump eslint-plugin-node from 7.0.1 to 8.0.0 Bumps [eslint-plugin-node](https://github.com/mysticatea/eslint-plugin-node) from 7.0.1 to 8.0.0. - [Release notes](https://github.com/mysticatea/eslint-plugin-node/releases) - [Commits](https://github.com/mysticatea/eslint-plugin-node/compare/v7.0.1...v8.0.0) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 9fd7a4dd76a..d4514af5797 100644 --- a/package.json +++ b/package.json @@ -112,7 +112,7 @@ "ember-try": "^1.1.0", "eslint": "^5.10.0", "eslint-config-prettier": "^3.1.0", - "eslint-plugin-node": "^7.0.1", + "eslint-plugin-node": "^8.0.0", "eslint-plugin-prettier": "^3.0.0", "execa": "^1.0.0", "github": "^14.0.0", diff --git a/yarn.lock b/yarn.lock index 597ce751224..3caa150907a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4052,13 +4052,14 @@ eslint-plugin-es@^1.3.1: eslint-utils "^1.3.0" regexpp "^2.0.0" -eslint-plugin-node@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-7.0.1.tgz#a6e054e50199b2edd85518b89b4e7b323c9f36db" +eslint-plugin-node@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-8.0.0.tgz#fb9e8911f4543514f154bb6a5924b599aa645568" + integrity sha512-Y+ln8iQ52scz9+rSPnSWRaAxeWaoJZ4wIveDR0vLHkuSZGe44Vk1J4HX7WvEP5Cm+iXPE8ixo7OM7gAO3/OKpQ== dependencies: eslint-plugin-es "^1.3.1" eslint-utils "^1.3.1" - ignore "^4.0.2" + ignore "^5.0.2" minimatch "^3.0.4" resolve "^1.8.1" semver "^5.5.0" @@ -5439,14 +5440,15 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" -ignore@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.3.tgz#e2d58c9654d75b542529fa28d80ac95b29e4f467" - ignore@^4.0.6: version "4.0.6" resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" +ignore@^5.0.2: + version "5.0.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.0.4.tgz#33168af4a21e99b00c5d41cbadb6a6cb49903a45" + integrity sha512-WLsTMEhsQuXpCiG173+f3aymI43SXa+fB1rSfbzyP4GkPP+ZFVuO0/3sFUGNBtifisPeDcl/uD/Y2NxZ7xFq4g== + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" From fbe4bcfd1183d48e2f855fd815338835ac29a92b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 31 Jan 2019 06:16:39 +0000 Subject: [PATCH 2459/2527] Bump ember-cli-dependency-checker from 3.0.0 to 3.1.0 Bumps [ember-cli-dependency-checker](https://github.com/quaertym/ember-cli-dependency-checker) from 3.0.0 to 3.1.0. - [Release notes](https://github.com/quaertym/ember-cli-dependency-checker/releases) - [Commits](https://github.com/quaertym/ember-cli-dependency-checker/compare/v3.0.0...v3.1.0) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index d4514af5797..65ba67a613d 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "ember-cli": "^3.5.1", "ember-cli-app-version": "^3.2.0", "ember-cli-blueprint-test-helpers": "^0.19.1", - "ember-cli-dependency-checker": "^3.0.0", + "ember-cli-dependency-checker": "^3.1.0", "ember-cli-htmlbars": "^3.0.1", "ember-cli-htmlbars-inline-precompile": "^2.0.0", "ember-cli-inject-live-reload": "^2.0.1", diff --git a/yarn.lock b/yarn.lock index 3caa150907a..5077ad0d200 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3407,9 +3407,10 @@ ember-cli-broccoli-sane-watcher@^2.1.1: rsvp "^3.0.18" sane "^2.4.1" -ember-cli-dependency-checker@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-dependency-checker/-/ember-cli-dependency-checker-3.0.0.tgz#61245f5f79f881dece043303111d5f41efb8621f" +ember-cli-dependency-checker@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ember-cli-dependency-checker/-/ember-cli-dependency-checker-3.1.0.tgz#b39c6b537a1457d77892edf5ddcfa025cd1401e2" + integrity sha512-Y/V2senOyIjQnZohYeZeXs59rWHI2m8KRF9IesMv1ypLRSc/h/QS6UX51wAyaZnxcgU6ljFXpqL5x38UxM3XzA== dependencies: chalk "^2.3.0" find-yarn-workspace-root "^1.1.0" @@ -8241,13 +8242,7 @@ resolve@1.5.0: dependencies: path-parse "^1.0.5" -resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.7.1, resolve@^1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" - dependencies: - path-parse "^1.0.5" - -resolve@^1.9.0: +resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.7.1, resolve@^1.8.1, resolve@^1.9.0: version "1.10.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== From e01d7e94d894df4133360b90876dbfc12fb28e14 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 31 Jan 2019 06:16:21 +0000 Subject: [PATCH 2460/2527] Bump eslint-plugin-prettier from 3.0.0 to 3.0.1 Bumps [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier) from 3.0.0 to 3.0.1. - [Release notes](https://github.com/prettier/eslint-plugin-prettier/releases) - [Changelog](https://github.com/prettier/eslint-plugin-prettier/blob/master/CHANGELOG.md) - [Commits](https://github.com/prettier/eslint-plugin-prettier/compare/v3.0.0...v3.0.1) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 65ba67a613d..533f6b90f67 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "eslint": "^5.10.0", "eslint-config-prettier": "^3.1.0", "eslint-plugin-node": "^8.0.0", - "eslint-plugin-prettier": "^3.0.0", + "eslint-plugin-prettier": "^3.0.1", "execa": "^1.0.0", "github": "^14.0.0", "glob": "^7.1.3", diff --git a/yarn.lock b/yarn.lock index 5077ad0d200..00710f892a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4065,9 +4065,10 @@ eslint-plugin-node@^8.0.0: resolve "^1.8.1" semver "^5.5.0" -eslint-plugin-prettier@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.0.tgz#f6b823e065f8c36529918cdb766d7a0e975ec30c" +eslint-plugin-prettier@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.1.tgz#19d521e3981f69dd6d14f64aec8c6a6ac6eb0b0d" + integrity sha512-/PMttrarPAY78PLvV3xfWibMOdMDl57hmlQ2XqFeA37wd+CJ7WSxV7txqjVPHi/AAFKd2lX0ZqfsOc/i5yFCSQ== dependencies: prettier-linter-helpers "^1.0.0" From fde8ca81c6f547918d5c7aaca68a92924fe32680 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 31 Jan 2019 06:16:37 +0000 Subject: [PATCH 2461/2527] Bump ember-qunit from 3.5.3 to 4.2.0 Bumps [ember-qunit](https://github.com/emberjs/ember-qunit) from 3.5.3 to 4.2.0. - [Release notes](https://github.com/emberjs/ember-qunit/releases) - [Changelog](https://github.com/emberjs/ember-qunit/blob/master/CHANGELOG.md) - [Commits](https://github.com/emberjs/ember-qunit/compare/v3.5.3...v4.2.0) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 149 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 89 insertions(+), 62 deletions(-) diff --git a/package.json b/package.json index 533f6b90f67..2d68bd81676 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "ember-export-application-global": "^2.0.0", "ember-load-initializers": "^1.1.0", "ember-maybe-import-regenerator": "^0.1.6", - "ember-qunit": "^3.5.3", + "ember-qunit": "^4.2.0", "ember-qunit-assert-helpers": "^0.2.1", "ember-resolver": "^5.0.1", "ember-source": "~3.6.0", diff --git a/yarn.lock b/yarn.lock index 00710f892a6..c71c39e9f96 100644 --- a/yarn.lock +++ b/yarn.lock @@ -441,6 +441,16 @@ dependencies: regenerator-transform "^0.13.3" +"@babel/plugin-transform-runtime@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.2.0.tgz#566bc43f7d0aedc880eaddbd29168d0f248966ea" + integrity sha512-jIgkljDdq4RYDnJyQsiWbdvGeei/0MOTtSHKO/rfbd/mXBxNpdlulMx49L0HQ4pug1fXannxoqCI+fYSle9eSw== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + resolve "^1.8.1" + semver "^5.5.1" + "@babel/plugin-transform-shorthand-properties@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0.tgz#85f8af592dcc07647541a0350e8c95c7bf419d15" @@ -542,6 +552,13 @@ js-levenshtein "^1.1.3" semver "^5.3.0" +"@babel/runtime@^7.2.0": + version "7.3.1" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.1.tgz#574b03e8e8a9898eaf4a872a92ea20b7846f6f2a" + integrity sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA== + dependencies: + regenerator-runtime "^0.12.0" + "@babel/template@^7.1.0", "@babel/template@^7.1.2": version "7.1.2" resolved "https://registry.npmjs.org/@babel/template/-/template-7.1.2.tgz#090484a574fef5a2d2d7726a674eceda5c5b5644" @@ -669,14 +686,16 @@ ember-cli-babel "^6.16.0" ember-compatibility-helpers "^1.1.1" -"@ember/test-helpers@^0.7.26": - version "0.7.27" - resolved "https://registry.npmjs.org/@ember/test-helpers/-/test-helpers-0.7.27.tgz#c622cabd0cbb95b34efc1e1b6274ab5a14edc138" +"@ember/test-helpers@^1.1.0": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@ember/test-helpers/-/test-helpers-1.3.1.tgz#575b30f4b74c888ea8510c6adffb855876c93a3d" + integrity sha512-j/o5ouq/i64PHkpkcq5Ji26cqxezHhMFRIiehdBmJQo/dVI3gAEsJJh0+qeDD8MrT8WhFT9oqLcicfjEWDEvaA== dependencies: + broccoli-debug "^0.6.5" broccoli-funnel "^2.0.1" - ember-assign-polyfill "~2.4.0" - ember-cli-babel "^6.12.0" - ember-cli-htmlbars-inline-precompile "^1.0.0" + ember-assign-polyfill "^2.6.0" + ember-cli-babel "^7.4.0" + ember-cli-htmlbars-inline-precompile "^2.1.0" "@glimmer/di@^0.2.0": version "0.2.0" @@ -1418,11 +1437,12 @@ babel-plugin-ember-modules-api-polyfill@^2.3.2: dependencies: ember-rfc176-data "^0.3.0" -babel-plugin-ember-modules-api-polyfill@^2.5.0: - version "2.5.0" - resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.5.0.tgz#860aab9fecbf38c10d1fe0779c6979a854fff154" +babel-plugin-ember-modules-api-polyfill@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.6.0.tgz#9524a65ef0c31ee82536a19c243fbaec1b977cbb" + integrity sha512-BSbLv3+ju1mcUUoPe7vPJgnGawrNxp6LfFBRHlNOKeMlQlml9Wo2MRRUrbpNDlmVc761xSKj8+cde7R0Lwpq7g== dependencies: - ember-rfc176-data "^0.3.5" + ember-rfc176-data "^0.3.6" babel-plugin-feature-flags@^0.3.1: version "0.3.1" @@ -1436,10 +1456,6 @@ babel-plugin-filter-imports@^2.0.4: "@babel/types" "^7.1.5" lodash "^4.17.11" -babel-plugin-htmlbars-inline-precompile@^0.2.5: - version "0.2.6" - resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-0.2.6.tgz#c00b8a3f4b32ca04bf0f0d5169fcef3b5a66d69d" - babel-plugin-htmlbars-inline-precompile@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-1.0.0.tgz#a9d2f6eaad8a3f3d361602de593a8cbef8179c22" @@ -3326,11 +3342,12 @@ electron-to-chromium@^1.3.81: version "1.3.82" resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.82.tgz#7d13ae4437d2a783de3f4efba96b186c540b67b1" -ember-assign-polyfill@~2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/ember-assign-polyfill/-/ember-assign-polyfill-2.4.0.tgz#acb00466f7d674b3e6b030acfe255b3b1f6472e1" +ember-assign-polyfill@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/ember-assign-polyfill/-/ember-assign-polyfill-2.6.0.tgz#07847e3357ee35b33f886a0b5fbec6873f6860eb" + integrity sha512-Y8NzOmHI/g4PuJ+xC14eTYiQbigNYddyHB8FY2kuQMxThTEIDE7SJtgttJrYYcPciOu0Tnb5ff36iO46LeiXkw== dependencies: - ember-cli-babel "^6.6.0" + ember-cli-babel "^6.16.0" ember-cli-version-checker "^2.0.0" ember-cli-app-version@^3.2.0: @@ -3344,7 +3361,7 @@ ember-cli-babel-plugin-helpers@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/ember-cli-babel-plugin-helpers/-/ember-cli-babel-plugin-helpers-1.0.2.tgz#d4bec0f32febc530e621ea8d66d3365727cb5e6c" -ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.0: +ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.9.0: version "6.16.0" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.16.0.tgz#623b4a2764ece72b65f1572fc8aeb5714a450228" dependencies: @@ -3362,18 +3379,20 @@ ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6 ember-cli-version-checker "^2.1.2" semver "^5.5.0" -ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4: - version "7.1.4" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.1.4.tgz#5f2b6ba2156d8dce2681aea92689b57ffbc71ccb" - integrity sha512-NmYtGSaFfXiwMX6NvpQ78u2LTWKmQjTvEKxTiFRumH0kRZ3PNiipLf2SqInUiAIHVUR2e6ihyAt5sL4mPCjK/w== +ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4, ember-cli-babel@^7.2.0, ember-cli-babel@^7.4.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.4.1.tgz#9892f5883f5a6b1f0f86fb1331fc491338f372ad" + integrity sha512-h6qZKHyULm5SYhvjNOeXvLl3kHaBdh37g5QqTTiC/vMiWP/xnyNp2bMoq52qq+SLm/bE8+5UcVTKjrNl0+IqXA== dependencies: "@babel/core" "^7.0.0" "@babel/plugin-transform-modules-amd" "^7.0.0" + "@babel/plugin-transform-runtime" "^7.2.0" "@babel/polyfill" "^7.0.0" "@babel/preset-env" "^7.0.0" + "@babel/runtime" "^7.2.0" amd-name-resolver "^1.2.1" babel-plugin-debug-macros "^0.2.0-beta.6" - babel-plugin-ember-modules-api-polyfill "^2.5.0" + babel-plugin-ember-modules-api-polyfill "^2.6.0" babel-plugin-module-resolver "^3.1.1" broccoli-babel-transpiler "^7.1.0" broccoli-debug "^0.6.4" @@ -3422,20 +3441,21 @@ ember-cli-get-component-path-option@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" -ember-cli-htmlbars-inline-precompile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-1.0.3.tgz#332ff96c06fc522965162f1090d78a615379c3c2" +ember-cli-htmlbars-inline-precompile@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-2.0.0.tgz#8cbc941370ac6e728ae3d49c4164b3c7131d6118" + integrity sha512-oqqmT31ZG+md5UgCsumFulGXZvC3SbHnhLZ24uc5vKQuzA1c5cZmbOxb+1CnqLIovPCbcJWE3pL9kUMHiBh5oQ== dependencies: - babel-plugin-htmlbars-inline-precompile "^0.2.5" + babel-plugin-htmlbars-inline-precompile "^1.0.0" ember-cli-version-checker "^2.1.2" hash-for-dep "^1.2.3" heimdalljs-logger "^0.1.9" silent-error "^1.1.0" -ember-cli-htmlbars-inline-precompile@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-2.0.0.tgz#8cbc941370ac6e728ae3d49c4164b3c7131d6118" - integrity sha512-oqqmT31ZG+md5UgCsumFulGXZvC3SbHnhLZ24uc5vKQuzA1c5cZmbOxb+1CnqLIovPCbcJWE3pL9kUMHiBh5oQ== +ember-cli-htmlbars-inline-precompile@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-2.1.0.tgz#61b91ff1879d44ae504cadb46fb1f2604995ae08" + integrity sha512-BylIHduwQkncPhnj0ZyorBuljXbTzLgRo6kuHf1W+IHFxThFl2xG+r87BVwsqx4Mn9MTgW9SE0XWjwBJcSWd6Q== dependencies: babel-plugin-htmlbars-inline-precompile "^1.0.0" ember-cli-version-checker "^2.1.2" @@ -3801,17 +3821,18 @@ ember-qunit-assert-helpers@^0.2.1: broccoli-filter "^1.0.1" ember-cli-babel "^6.9.0" -ember-qunit@^3.5.3: - version "3.5.3" - resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-3.5.3.tgz#bfd0bff8298c78c77e870cca43fe0826e78a0d09" +ember-qunit@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-4.2.0.tgz#376bf2eb6340f492e9cf9b5cb55b7dd74e8de600" + integrity sha512-bsyc8vx8MFkfExsD4i3aLuffns8Yb/qtfA2C+Ghwy/6HYPujcxR/PcZ1j9ZzbCIvO8Fr2oxykZU3rWbVHE6EhA== dependencies: - "@ember/test-helpers" "^0.7.26" + "@ember/test-helpers" "^1.1.0" broccoli-funnel "^2.0.1" - broccoli-merge-trees "^2.0.0" + broccoli-merge-trees "^3.0.2" common-tags "^1.4.0" - ember-cli-babel "^6.8.2" + ember-cli-babel "^7.2.0" ember-cli-test-loader "^2.2.0" - qunit "~2.6.0" + qunit "^2.8.0" ember-resolver@^5.0.1: version "5.0.1" @@ -3829,9 +3850,10 @@ ember-rfc176-data@^0.3.0, ember-rfc176-data@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.3.tgz#27fba08d540a7463a4366c48eaa19c5a44971a39" -ember-rfc176-data@^0.3.5: - version "0.3.5" - resolved "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.3.5.tgz#f630e550572c81a5e5c7220f864c0f06eee9e977" +ember-rfc176-data@^0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.6.tgz#7138db8dfccec39c9a832adfbd4c49d670028907" + integrity sha512-kPY94VCukPUPj+/6sZ9KvphD42KnpX2IS31p5z07OFVIviDogR0cQuld5c7Irzfgq7a0YACj0HlToROFn7dLYQ== ember-router-generator@^1.2.3: version "1.2.3" @@ -4255,10 +4277,6 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -exists-stat@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/exists-stat/-/exists-stat-1.0.0.tgz#0660e3525a2e89d9e446129440c272edfa24b529" - exists-sync@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" @@ -4595,7 +4613,7 @@ find-yarn-workspace-root@^1.1.0: fs-extra "^4.0.3" micromatch "^3.1.4" -findup-sync@2.0.0, findup-sync@^2.0.0: +findup-sync@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" dependencies: @@ -7045,6 +7063,11 @@ node-uuid@~1.4.0, node-uuid@~1.4.7: version "1.4.8" resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" +node-watch@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/node-watch/-/node-watch-0.6.0.tgz#ab0703b60cd270783698e57a428faa0010ed8fd0" + integrity sha512-XAgTL05z75ptd7JSVejH1a2Dm1zmXYhuDr9l230Qk6Z7/7GPcnAs/UyJJ4ggsXSvWil8iOzwQLW0zuGUvHpG8g== + "nopt@2 || 3", nopt@^3.0.3, nopt@^3.0.6, nopt@~3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" @@ -7800,17 +7823,16 @@ quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: rimraf "^2.5.4" underscore.string "~3.3.4" -qunit@~2.6.0: - version "2.6.2" - resolved "https://registry.npmjs.org/qunit/-/qunit-2.6.2.tgz#551210c5cf857258a4fe39a7fe15d9e14dfef22c" +qunit@^2.8.0: + version "2.9.1" + resolved "https://registry.yarnpkg.com/qunit/-/qunit-2.9.1.tgz#e11008d62e5f19ded60a20899a0cf7c3ec573b2d" + integrity sha512-ipXgW4SD557GrQtiBhj+g7eHk76pmSIYKglEXuAD/WsC06XzXDc4r9qlm4DSG5LxqxvpgK8naGlJ1Zcnj9/NdQ== dependencies: commander "2.12.2" - exists-stat "1.0.0" - findup-sync "2.0.0" js-reporters "1.2.1" + minimatch "3.0.4" + node-watch "0.6.0" resolve "1.5.0" - sane "^2.5.2" - walk-sync "0.3.2" randomatic@^3.0.0: version "3.0.0" @@ -8007,6 +8029,11 @@ regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" +regenerator-runtime@^0.12.0: + version "0.12.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" + integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== + regenerator-runtime@^0.9.5: version "0.9.6" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" @@ -8385,7 +8412,7 @@ safe-regex@^1.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" -sane@^2.4.1, sane@^2.5.2: +sane@^2.4.1: version "2.5.2" resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" dependencies: @@ -9402,16 +9429,16 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -walk-sync@0.3.2, walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" +walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" -walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: - version "0.2.7" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" +walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" From 076a933d80ef58a15809c29d655a9f8e78b33f9d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 31 Jan 2019 06:15:37 +0000 Subject: [PATCH 2462/2527] Bump ember-cli-version-checker from 2.1.2 to 3.0.1 Bumps [ember-cli-version-checker](https://github.com/rwjblue/ember-cli-version-checker) from 2.1.2 to 3.0.1. - [Release notes](https://github.com/rwjblue/ember-cli-version-checker/releases) - [Changelog](https://github.com/ember-cli/ember-cli-version-checker/blob/master/CHANGELOG.md) - [Commits](https://github.com/rwjblue/ember-cli-version-checker/compare/v2.1.2...v3.0.1) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2d68bd81676..1bd823d8880 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "ember-cli-string-utils": "^1.1.0", "ember-cli-test-info": "^1.0.0", "ember-cli-typescript": "^2.0.0-beta.2", - "ember-cli-version-checker": "^2.1.2", + "ember-cli-version-checker": "^3.0.1", "ember-inflector": "^3.0.0", "git-repo-info": "^2.0.0", "heimdalljs": "^0.3.0", diff --git a/yarn.lock b/yarn.lock index c71c39e9f96..24724d1a739 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3649,7 +3649,7 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-ve resolve "^1.3.3" semver "^5.3.0" -ember-cli-version-checker@^3.0.0: +ember-cli-version-checker@^3.0.0, ember-cli-version-checker@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-3.0.1.tgz#2d084d2b261374582c68edb658a7df3a10112749" integrity sha512-hX2tGrFVt8PyaiWclZr8XFNUPSnA+Ax4bMifDIVVtYY8RQZG8LZf9AGyTj4XImkBBWBtgKyOeQ0ovg3kgos4JA== From bfa7b134a21852007333782a0df41ff111050fc4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 31 Jan 2019 00:22:28 +0000 Subject: [PATCH 2463/2527] Bump @ember-decorators/data from 3.1.5 to 5.1.2 Bumps [@ember-decorators/data](https://github.com/ember-decorators/ember-decorators) from 3.1.5 to 5.1.2. - [Release notes](https://github.com/ember-decorators/ember-decorators/releases) - [Commits](https://github.com/ember-decorators/ember-decorators/compare/v3.1.5...v5.1.2) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 21 +-------------------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 1bd823d8880..35526c63929 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "devDependencies": { "@babel/plugin-transform-typescript": "^7.2.0", "@ember-decorators/babel-transforms": "^2.1.2", - "@ember-decorators/data": "^3.1.5", + "@ember-decorators/data": "^5.1.2", "@types/ember": "~3.0.25", "@types/ember-qunit": "~3.4.3", "@types/ember-test-helpers": "~1.0.4", diff --git a/yarn.lock b/yarn.lock index 24724d1a739..32a792614e4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -625,14 +625,6 @@ "@ember-decorators/utils" "^5.1.2" ember-cli-babel "^7.1.3" -"@ember-decorators/data@^3.1.5": - version "3.1.5" - resolved "https://registry.yarnpkg.com/@ember-decorators/data/-/data-3.1.5.tgz#84494a8b5d55e9328789f37d84dd52e2f4d51cd3" - integrity sha512-R7QlEU9MxqPiQRpL+fdECdyCwMbPp8+XK+zo3gieJyCjhjP1p9Ssn+HZcSIdv4EMfdD3XL5FwePcZ+j/X4HU+Q== - dependencies: - "@ember-decorators/utils" "^3.1.5" - ember-cli-babel "^7.1.3" - "@ember-decorators/data@^5.1.2": version "5.1.2" resolved "https://registry.yarnpkg.com/@ember-decorators/data/-/data-5.1.2.tgz#ae77cdf245284be63619190bebf81bee39af5b88" @@ -657,17 +649,6 @@ "@ember-decorators/utils" "^5.1.2" ember-cli-babel "^7.1.3" -"@ember-decorators/utils@^3.1.5": - version "3.1.5" - resolved "https://registry.yarnpkg.com/@ember-decorators/utils/-/utils-3.1.5.tgz#8f692582329a88553192e998012c7ca59e547c37" - integrity sha512-SqckJdUgnsZGZw6XHdRMeOk7YEdXHOZjJNOeJgNzjUdhS9jWSNu3OQrXcwYjJZBW8ICdqV87lpJB/rozTCezoQ== - dependencies: - babel-plugin-debug-macros "^0.1.11" - ember-cli-babel "^7.1.3" - ember-cli-version-checker "^2.1.2" - ember-compatibility-helpers "^1.1.2" - semver "^5.6.0" - "@ember-decorators/utils@^5.1.2": version "5.1.2" resolved "https://registry.yarnpkg.com/@ember-decorators/utils/-/utils-5.1.2.tgz#23ff1561ae6ecde14799d5df2a985fa134ca5269" @@ -1413,7 +1394,7 @@ babel-plugin-check-es2015-constants@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-debug-macros@^0.1.10, babel-plugin-debug-macros@^0.1.11: +babel-plugin-debug-macros@^0.1.10: version "0.1.11" resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" dependencies: From 4a4822d62c3d59e0f978d289ae70faf92731180f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 31 Jan 2019 06:15:54 +0000 Subject: [PATCH 2464/2527] Bump @types/ember__test-helpers from 0.7.6 to 0.7.7 Bumps [@types/ember__test-helpers](https://github.com/DefinitelyTyped/DefinitelyTyped) from 0.7.6 to 0.7.7. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 35526c63929..27faef27257 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "@types/ember-qunit": "~3.4.3", "@types/ember-test-helpers": "~1.0.4", "@types/ember-testing-helpers": "~0.0.3", - "@types/ember__test-helpers": "~0.7.6", + "@types/ember__test-helpers": "~0.7.7", "@types/ember__debug": "^3.0.3", "@types/qunit": "^2.5.3", "@types/rsvp": "^4.0.2", diff --git a/yarn.lock b/yarn.lock index 32a792614e4..f2108124044 100644 --- a/yarn.lock +++ b/yarn.lock @@ -807,11 +807,13 @@ dependencies: "@types/handlebars" "*" -"@types/ember__test-helpers@~0.7.6": - version "0.7.6" - resolved "https://registry.yarnpkg.com/@types/ember__test-helpers/-/ember__test-helpers-0.7.6.tgz#f26050fc74cd8ce111ee9e01864a293d6a9ac7ac" +"@types/ember__test-helpers@~0.7.7": + version "0.7.7" + resolved "https://registry.yarnpkg.com/@types/ember__test-helpers/-/ember__test-helpers-0.7.7.tgz#b11832e5e622c1e61f96d8477845a84b5ec348c3" + integrity sha512-Agvz+92jejB/Fy4jf0qhii6bOeXrPXZUWkGGlbNT5VXppRbQaQirjML/NSoGm93dU/o2JD/E9Ax8ZOFSthGkDw== dependencies: "@types/ember" "*" + "@types/ember__application" "*" "@types/ember__error" "*" "@types/htmlbars-inline-precompile" "*" From 9117aa007dcfc10f024886940ef7d6284445913b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 31 Jan 2019 06:16:15 +0000 Subject: [PATCH 2465/2527] Bump @types/ember-qunit from 3.4.3 to 3.4.5 Bumps [@types/ember-qunit](https://github.com/DefinitelyTyped/DefinitelyTyped) from 3.4.3 to 3.4.5. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 27faef27257..065a7c7cf99 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@ember-decorators/babel-transforms": "^2.1.2", "@ember-decorators/data": "^5.1.2", "@types/ember": "~3.0.25", - "@types/ember-qunit": "~3.4.3", + "@types/ember-qunit": "~3.4.5", "@types/ember-test-helpers": "~1.0.4", "@types/ember-testing-helpers": "~0.0.3", "@types/ember__test-helpers": "~0.7.7", diff --git a/yarn.lock b/yarn.lock index f2108124044..bcd477725b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -702,9 +702,10 @@ dependencies: "@types/estree" "*" -"@types/ember-qunit@~3.4.3": - version "3.4.3" - resolved "https://registry.yarnpkg.com/@types/ember-qunit/-/ember-qunit-3.4.3.tgz#ad8532e735c7a46af764f5cb7d852896e6d28bfd" +"@types/ember-qunit@~3.4.5": + version "3.4.5" + resolved "https://registry.yarnpkg.com/@types/ember-qunit/-/ember-qunit-3.4.5.tgz#791e4919a88b8d2ac982e4d73564a2c4c08fec6a" + integrity sha512-Nk9hubQdaBUbRgw68dkcLsAt9n9WIHFX3vj5e75Cht5MVizz7j6hW6O5zGtM1QPp62+2/TgUqGIEYMv4nlw1uQ== dependencies: "@types/ember" "*" "@types/ember-test-helpers" "*" From f3c659ef6de91a685fd99359fa1dd0282fd56031 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 14 Feb 2019 04:51:26 +0000 Subject: [PATCH 2466/2527] [Security] Bump handlebars from 4.0.11 to 4.1.0 Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.0.11 to 4.1.0. **This update includes security fixes.** - [Release notes](https://github.com/wycats/handlebars.js/releases) - [Changelog](https://github.com/wycats/handlebars.js/blob/v4.1.0/release-notes.md) - [Commits](https://github.com/wycats/handlebars.js/compare/v4.0.11...v4.1.0) Signed-off-by: dependabot[bot] --- yarn.lock | 96 +++++-------------------------------------------------- 1 file changed, 8 insertions(+), 88 deletions(-) diff --git a/yarn.lock b/yarn.lock index bcd477725b7..e00e27a4e75 100644 --- a/yarn.lock +++ b/yarn.lock @@ -933,14 +933,6 @@ ajv@^6.5.3: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -align-text@^0.1.1, align-text@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" - dependencies: - kind-of "^3.0.2" - longest "^1.0.1" - repeat-string "^1.5.2" - amd-name-resolver@1.2.0, amd-name-resolver@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz#fc41b3848824b557313897d71f8d5a0184fbe679" @@ -1186,7 +1178,7 @@ async-some@~1.0.2: dependencies: dezalgo "^1.0.2" -async@^1.4.0, async@^1.5.2: +async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -2594,10 +2586,6 @@ camelcase-keys@^2.0.0: camelcase "^2.0.0" map-obj "^1.0.0" -camelcase@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" - camelcase@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" @@ -2641,13 +2629,6 @@ caseless@~0.12.0: version "0.12.0" resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" -center-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" - dependencies: - align-text "^0.1.3" - lazy-cache "^1.0.3" - chai-as-promised@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" @@ -2796,14 +2777,6 @@ cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" -cliui@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" - dependencies: - center-align "^0.1.1" - right-align "^0.1.1" - wordwrap "0.0.2" - clone-response@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" @@ -3148,7 +3121,7 @@ debuglog@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" -decamelize@^1.0.0, decamelize@^1.1.2: +decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -5163,9 +5136,10 @@ growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" -handlebars@^4.0.11: - version "4.0.12" - resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5" +handlebars@^4.0.11, handlebars@^4.0.4: + version "4.1.0" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.0.tgz#0d6a6f34ff1f63cecec8423aa4169827bf787c3a" + integrity sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w== dependencies: async "^2.5.0" optimist "^0.6.1" @@ -5173,16 +5147,6 @@ handlebars@^4.0.11: optionalDependencies: uglify-js "^3.1.4" -handlebars@^4.0.4: - version "4.0.11" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" - dependencies: - async "^1.4.0" - optimist "^0.6.1" - source-map "^0.4.4" - optionalDependencies: - uglify-js "^2.6" - har-schema@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" @@ -6021,10 +5985,6 @@ klaw@^1.0.0: optionalDependencies: graceful-fs "^4.1.9" -lazy-cache@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" - leek@0.0.24: version "0.0.24" resolved "https://registry.yarnpkg.com/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" @@ -6561,10 +6521,6 @@ log-symbols@^2.2.0: dependencies: chalk "^2.0.1" -longest@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" - loose-envify@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -8289,12 +8245,6 @@ retry@^0.8.0, retry@~0.8.0: version "0.8.0" resolved "https://registry.npmjs.org/retry/-/retry-0.8.0.tgz#2367628dc0edb247b1eab649dc53ac8628ac2d5f" -right-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" - dependencies: - align-text "^0.1.1" - rimraf@2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" @@ -8686,13 +8636,13 @@ source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" -source-map@0.4.x, source-map@^0.4.2, source-map@^0.4.4: +source-map@0.4.x, source-map@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: amdefine ">=0.0.4" -source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0, source-map@~0.5.1: +source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -9203,15 +9153,6 @@ uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" -uglify-js@^2.6: - version "2.8.29" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" - dependencies: - source-map "~0.5.1" - yargs "~3.10.0" - optionalDependencies: - uglify-to-browserify "~1.0.0" - uglify-js@^3.1.4: version "3.4.9" resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" @@ -9219,10 +9160,6 @@ uglify-js@^3.1.4: commander "~2.17.1" source-map "~0.6.1" -uglify-to-browserify@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" - uid-number@0.0.6: version "0.0.6" resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" @@ -9492,14 +9429,6 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.2 || 2" -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" @@ -9585,15 +9514,6 @@ yam@^0.0.24: fs-extra "^4.0.2" lodash.merge "^4.6.0" -yargs@~3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" - dependencies: - camelcase "^1.0.2" - cliui "^2.1.0" - decamelize "^1.0.0" - window-size "0.1.0" - yeast@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" From 87db6f612e1c657694e9e658745ede38f54d365c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 12 Feb 2019 06:26:35 +0000 Subject: [PATCH 2467/2527] Bump broccoli-babel-transpiler from 7.0.0 to 7.1.2 Bumps [broccoli-babel-transpiler](https://github.com/babel/broccoli-babel-transpiler) from 7.0.0 to 7.1.2. - [Release notes](https://github.com/babel/broccoli-babel-transpiler/releases) - [Changelog](https://github.com/babel/broccoli-babel-transpiler/blob/master/CHANGELOG.md) - [Commits](https://github.com/babel/broccoli-babel-transpiler/compare/v7.0.0...v7.1.2) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 61 ++++++++-------------------------------------------- 2 files changed, 10 insertions(+), 53 deletions(-) diff --git a/package.json b/package.json index 065a7c7cf99..ee81be1108a 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "@types/qunit": "^2.5.3", "@types/rsvp": "^4.0.2", "babel-eslint": "^10.0.1", - "broccoli-babel-transpiler": "^7.0.0", + "broccoli-babel-transpiler": "^7.1.2", "broccoli-concat": "^3.7.3", "broccoli-stew": "^2.0.1", "broccoli-string-replace": "^0.1.2", diff --git a/yarn.lock b/yarn.lock index e00e27a4e75..b806dbc6dac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1981,22 +1981,7 @@ broccoli-amd-funnel@^2.0.1: broccoli-plugin "^1.3.0" symlink-or-copy "^1.2.0" -broccoli-babel-transpiler@^6.4.5: - version "6.4.5" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.4.5.tgz#caab4a3b18d2a819fdd56e1ac3a37e8164ad4272" - dependencies: - babel-core "^6.26.0" - broccoli-funnel "^2.0.1" - broccoli-merge-trees "^2.0.0" - broccoli-persistent-filter "^1.4.3" - clone "^2.0.0" - hash-for-dep "^1.2.3" - heimdalljs-logger "^0.1.7" - json-stable-stringify "^1.0.0" - rsvp "^4.8.2" - workerpool "^2.3.0" - -broccoli-babel-transpiler@^6.5.0: +broccoli-babel-transpiler@^6.4.5, broccoli-babel-transpiler@^6.5.0: version "6.5.0" resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.5.0.tgz#aa501a227b298a99742fdd0309b1eaad7124bba0" dependencies: @@ -2011,27 +1996,13 @@ broccoli-babel-transpiler@^6.5.0: rsvp "^4.8.2" workerpool "^2.3.0" -broccoli-babel-transpiler@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.0.0.tgz#bc9d0e93d70d9515b799144b54b0b958e88b6f19" - dependencies: - "@babel/core" "^7.0.0" - broccoli-funnel "^2.0.1" - broccoli-merge-trees "^3.0.0" - broccoli-persistent-filter "^1.4.3" - clone "^2.1.2" - hash-for-dep "^1.2.3" - heimdalljs-logger "^0.1.9" - json-stable-stringify "^1.0.1" - rsvp "^4.8.3" - workerpool "^2.3.1" - -broccoli-babel-transpiler@^7.1.0: - version "7.1.1" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.1.1.tgz#4202cd0653845083ee744fb4eaa4a2b50292f03f" - integrity sha512-iZE6yxDcEe4XSMEyqyyS+wtkNAsPUGJNleJoVu26Vt2Al8/GqRI5+wc7qquPb71I1W7AtqbkaqsgDFDqBoIYKw== +broccoli-babel-transpiler@^7.1.0, broccoli-babel-transpiler@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.1.2.tgz#fb5d6f8b9a805627ac3f2914ac9d86e82ca2413b" + integrity sha512-rljx86xgZJ2BjWt+xCSVfvyt3ONpCdMMXzMpeeVpAGdBHj3bqQICdPHZDAbzn1vKY/LIPsJZftvdxql1jiLGzw== dependencies: "@babel/core" "^7.0.0" + "@babel/polyfill" "^7.0.0" broccoli-funnel "^2.0.1" broccoli-merge-trees "^3.0.0" broccoli-persistent-filter "^1.4.3" @@ -2787,11 +2758,7 @@ clone@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" -clone@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" - -clone@^2.1.2: +clone@^2.0.0, clone@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" @@ -8296,11 +8263,7 @@ rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3 version "3.6.2" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" -rsvp@^4.7.0, rsvp@^4.8.1, rsvp@^4.8.2, rsvp@^4.8.3: - version "4.8.3" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.3.tgz#25d4b9fdd0f95e216eb5884d9b3767d3fbfbe2cd" - -rsvp@^4.8.4: +rsvp@^4.7.0, rsvp@^4.8.1, rsvp@^4.8.2, rsvp@^4.8.3, rsvp@^4.8.4: version "4.8.4" resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.4.tgz#b50e6b34583f3dd89329a2f23a8a2be072845911" @@ -9437,13 +9400,7 @@ wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" -workerpool@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-2.3.0.tgz#86c5cbe946b55e7dc9d12b1936c8801a6e2d744d" - dependencies: - object-assign "4.1.1" - -workerpool@^2.3.1: +workerpool@^2.3.0, workerpool@^2.3.1: version "2.3.3" resolved "https://registry.npmjs.org/workerpool/-/workerpool-2.3.3.tgz#49a70089bd55e890d68cc836a19419451d7c81d7" dependencies: From a092e2955c5f0202bbf9dab2f201f4048fc40427 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 12 Feb 2019 06:26:59 +0000 Subject: [PATCH 2468/2527] Bump typescript from 3.2.2 to 3.3.3 Bumps [typescript](https://github.com/Microsoft/TypeScript) from 3.2.2 to 3.3.3. - [Release notes](https://github.com/Microsoft/TypeScript/releases) - [Commits](https://github.com/Microsoft/TypeScript/commits) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index ee81be1108a..a76394c2a80 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "prettier": "^1.15.3", "rimraf": "^2.6.2", "rsvp": "^4.8.4", - "typescript": "~3.2.2" + "typescript": "~3.3.3" }, "engines": { "node": ">= 6.0.0" diff --git a/yarn.lock b/yarn.lock index b806dbc6dac..3ba36f0004c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9107,10 +9107,10 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@~3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.2.tgz#fe8101c46aa123f8353523ebdcf5730c2ae493e5" - integrity sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg== +typescript@~3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.3.tgz#f1657fc7daa27e1a8930758ace9ae8da31403221" + integrity sha512-Y21Xqe54TBVp+VDSNbuDYdGw0BpoR/Q6wo/+35M8PAU0vipahnyduJWirxxdxjsAkS7hue53x2zp8gz7F05u0A== uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5" From 5b1c81532b0279325d38f9cdaff6517d44a07f67 Mon Sep 17 00:00:00 2001 From: Bujorel Tecu Date: Fri, 15 Feb 2019 15:06:00 -0500 Subject: [PATCH 2469/2527] Use `filter` instead of `find` due to IE11 --- addon/-private/system/many-array.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/many-array.js b/addon/-private/system/many-array.js index 8b9c91055fe..95cdf7095d2 100644 --- a/addon/-private/system/many-array.js +++ b/addon/-private/system/many-array.js @@ -138,7 +138,8 @@ export default EmberObject.extend(MutableArray, Evented, { // TODO: if(DEBUG) anyUnloaded() { - let unloaded = this.currentState.find(im => im._isDematerializing || !im.isLoaded()); + // Use `filter[0]` as opposed to `find` because of IE11 + let unloaded = this.currentState.filter(im => im._isDematerializing || !im.isLoaded())[0]; return !!unloaded; }, From 82e1591829f327771a5d91021c528ef82a4a705b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 7 Feb 2019 06:02:00 +0000 Subject: [PATCH 2470/2527] Bump ember-cli-pretender from 3.0.0 to 3.1.1 Bumps [ember-cli-pretender](https://github.com/rwjblue/ember-cli-pretender) from 3.0.0 to 3.1.1. - [Release notes](https://github.com/rwjblue/ember-cli-pretender/releases) - [Changelog](https://github.com/rwjblue/ember-cli-pretender/blob/master/CHANGELOG.md) - [Commits](https://github.com/rwjblue/ember-cli-pretender/compare/v3.0.0...v3.1.1) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index a76394c2a80..9e4c703f57c 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "ember-cli-htmlbars-inline-precompile": "^2.0.0", "ember-cli-inject-live-reload": "^2.0.1", "ember-cli-internal-test-helpers": "^0.9.1", - "ember-cli-pretender": "^3.0.0", + "ember-cli-pretender": "^3.1.1", "ember-cli-release": "^1.0.0-beta.2", "ember-cli-shims": "^1.2.0", "ember-cli-sri": "^2.1.1", diff --git a/yarn.lock b/yarn.lock index 3ba36f0004c..67564a82fd8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3454,19 +3454,19 @@ ember-cli-preprocess-registry@^3.1.2: process-relative-require "^1.0.0" silent-error "^1.0.0" -ember-cli-pretender@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-3.0.0.tgz#dcaf772332a1e6b0fc91e4b9a7e793a1283c85ac" +ember-cli-pretender@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/ember-cli-pretender/-/ember-cli-pretender-3.1.1.tgz#289c41683de266fec8bfaf5b7b7f6026aaefc8cf" + integrity sha512-RGGj9la0138bgHUxyaGDHCZydmdpW+BFN9v0vMBzNPeXsaexCZotaFTIZDCNcKWPx8jtRHR8AXf318VRGXLJsw== dependencies: - "@xg-wang/whatwg-fetch" "^3.0.0" abortcontroller-polyfill "^1.1.9" broccoli-funnel "^2.0.1" broccoli-merge-trees "^3.0.0" ember-cli-babel "^6.6.0" fake-xml-http-request "^2.0.0" pretender "^2.1.0" - resolve "^1.2.0" route-recognizer "^0.3.3" + whatwg-fetch "^3.0.0" ember-cli-release@^1.0.0-beta.2: version "1.0.0-beta.2" @@ -8177,7 +8177,7 @@ resolve@1.5.0: dependencies: path-parse "^1.0.5" -resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.7.1, resolve@^1.8.1, resolve@^1.9.0: +resolve@^1.1.6, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.7.1, resolve@^1.8.1, resolve@^1.9.0: version "1.10.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== @@ -9374,6 +9374,11 @@ websocket-extensions@>=0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" +whatwg-fetch@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" + integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== + which@1, which@^1.2.14, which@^1.2.9, which@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" From 39bcf3a598abe43f27e27bef08ad7e47d79d1751 Mon Sep 17 00:00:00 2001 From: Xaser Acheron Date: Wed, 6 Feb 2019 17:06:10 -0600 Subject: [PATCH 2471/2527] [BUGFIX build] suppress circular dependency warning from rollup --- index.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/index.js b/index.js index b0153fd117d..eee6b7fc7a8 100644 --- a/index.js +++ b/index.js @@ -42,6 +42,12 @@ module.exports = { } }, + _suppressCircularDependencyWarnings(message, next) { + if (message.code !== 'CIRCULAR_DEPENDENCY') { + next(message); + } + }, + getOutputDirForVersion() { let VersionChecker = require('ember-cli-version-checker'); let checker = new VersionChecker(this); @@ -120,6 +126,7 @@ module.exports = { 'ember-data/adapters/errors', '@ember/ordered-set', ], + onwarn: this._suppressCircularDependencyWarnings, // cache: true|false Defaults to true }, }); From a701ee6053d7316ddc63eabd90be092c55fe6d60 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 20 Feb 2019 16:06:52 -0800 Subject: [PATCH 2472/2527] bump all the deps --- package.json | 12 +- yarn.lock | 4446 +++++++++++++++++++++++--------------------------- 2 files changed, 2023 insertions(+), 2435 deletions(-) diff --git a/package.json b/package.json index 9e4c703f57c..ef2bcbf419a 100644 --- a/package.json +++ b/package.json @@ -64,14 +64,14 @@ }, "devDependencies": { "@babel/plugin-transform-typescript": "^7.2.0", - "@ember-decorators/babel-transforms": "^2.1.2", + "@ember-decorators/babel-transforms": "^5.1.3", "@ember-decorators/data": "^5.1.2", "@types/ember": "~3.0.25", "@types/ember-qunit": "~3.4.5", "@types/ember-test-helpers": "~1.0.4", "@types/ember-testing-helpers": "~0.0.3", - "@types/ember__test-helpers": "~0.7.7", "@types/ember__debug": "^3.0.3", + "@types/ember__test-helpers": "~0.7.7", "@types/qunit": "^2.5.3", "@types/rsvp": "^4.0.2", "babel-eslint": "^10.0.1", @@ -102,16 +102,16 @@ "ember-decorators": "^5.1.2", "ember-disable-prototype-extensions": "^1.1.3", "ember-export-application-global": "^2.0.0", - "ember-load-initializers": "^1.1.0", + "ember-load-initializers": "^2.0.0", "ember-maybe-import-regenerator": "^0.1.6", "ember-qunit": "^4.2.0", "ember-qunit-assert-helpers": "^0.2.1", "ember-resolver": "^5.0.1", - "ember-source": "~3.6.0", + "ember-source": "~3.8.0", "ember-source-channel-url": "^1.1.0", "ember-try": "^1.1.0", "eslint": "^5.10.0", - "eslint-config-prettier": "^3.1.0", + "eslint-config-prettier": "^4.0.0", "eslint-plugin-node": "^8.0.0", "eslint-plugin-prettier": "^3.0.1", "execa": "^1.0.0", @@ -119,7 +119,7 @@ "glob": "^7.1.3", "json-typescript": "^1.1.0", "loader.js": "^4.7.0", - "mocha": "^5.2.0", + "mocha": "^6.0.0", "mocha-only-detector": "1.0.0", "prettier": "^1.15.3", "rimraf": "^2.6.2", diff --git a/yarn.lock b/yarn.lock index 67564a82fd8..8ad822f8edc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,31 +9,31 @@ "@babel/highlight" "^7.0.0" "@babel/core@^7.0.0": - version "7.1.2" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.1.2.tgz#f8d2a9ceb6832887329a7b60f9d035791400ba4e" + version "7.3.3" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.3.3.tgz#d090d157b7c5060d05a05acaebc048bd2b037947" dependencies: "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.1.2" - "@babel/helpers" "^7.1.2" - "@babel/parser" "^7.1.2" - "@babel/template" "^7.1.2" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.1.2" + "@babel/generator" "^7.3.3" + "@babel/helpers" "^7.2.0" + "@babel/parser" "^7.3.3" + "@babel/template" "^7.2.2" + "@babel/traverse" "^7.2.2" + "@babel/types" "^7.3.3" convert-source-map "^1.1.0" - debug "^3.1.0" - json5 "^0.5.0" - lodash "^4.17.10" + debug "^4.1.0" + json5 "^2.1.0" + lodash "^4.17.11" resolve "^1.3.2" semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.1.2", "@babel/generator@^7.1.3": - version "7.1.3" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.1.3.tgz#2103ec9c42d9bdad9190a6ad5ff2d456fd7b8673" +"@babel/generator@^7.2.2", "@babel/generator@^7.3.3": + version "7.3.3" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.3.3.tgz#185962ade59a52e00ca2bdfcfd1d58e528d4e39e" dependencies: - "@babel/types" "^7.1.3" + "@babel/types" "^7.3.3" jsesc "^2.5.1" - lodash "^4.17.10" + lodash "^4.17.11" source-map "^0.5.0" trim-right "^1.0.1" @@ -58,6 +58,16 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-create-class-features-plugin@^7.3.0": + version "7.3.2" + resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.2.tgz#ba1685603eb1c9f2f51c9106d5180135c163fe73" + dependencies: + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.2.3" + "@babel/helper-define-map@^7.1.0": version "7.1.0" resolved "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz#3b74caec329b3c80c116290887c0dd9ae468c20c" @@ -106,14 +116,14 @@ "@babel/types" "^7.0.0" "@babel/helper-module-transforms@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.1.0.tgz#470d4f9676d9fad50b324cdcce5fbabbc3da5787" + version "7.2.2" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.2.2.tgz#ab2f8e8d231409f8370c883d20c335190284b963" dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-simple-access" "^7.1.0" "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/template" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/template" "^7.2.2" + "@babel/types" "^7.2.2" lodash "^4.17.10" "@babel/helper-optimise-call-expression@^7.0.0": @@ -142,13 +152,13 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" -"@babel/helper-replace-supers@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.1.0.tgz#5fc31de522ec0ef0899dc9b3e7cf6a5dd655f362" +"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.2.3": + version "7.2.3" + resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.2.3.tgz#19970020cf22677d62b3a689561dbd9644d8c5e5" dependencies: "@babel/helper-member-expression-to-functions" "^7.0.0" "@babel/helper-optimise-call-expression" "^7.0.0" - "@babel/traverse" "^7.1.0" + "@babel/traverse" "^7.2.3" "@babel/types" "^7.0.0" "@babel/helper-simple-access@^7.1.0": @@ -165,21 +175,21 @@ "@babel/types" "^7.0.0" "@babel/helper-wrap-function@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.1.0.tgz#8cf54e9190706067f016af8f75cb3df829cc8c66" + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/template" "^7.1.0" "@babel/traverse" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/types" "^7.2.0" -"@babel/helpers@^7.1.2": - version "7.1.2" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.1.2.tgz#ab752e8c35ef7d39987df4e8586c63b8846234b5" +"@babel/helpers@^7.2.0": + version "7.3.1" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.3.1.tgz#949eec9ea4b45d3210feb7dc1c22db664c9e44b9" dependencies: "@babel/template" "^7.1.2" - "@babel/traverse" "^7.1.0" - "@babel/types" "^7.1.2" + "@babel/traverse" "^7.1.5" + "@babel/types" "^7.3.0" "@babel/highlight@^7.0.0": version "7.0.0" @@ -189,140 +199,128 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.1.2", "@babel/parser@^7.1.3": - version "7.1.3" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.1.3.tgz#2c92469bac2b7fbff810b67fca07bd138b48af77" +"@babel/parser@^7.0.0", "@babel/parser@^7.2.2", "@babel/parser@^7.2.3", "@babel/parser@^7.3.3": + version "7.3.3" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.3.3.tgz#092d450db02bdb6ccb1ca8ffd47d8774a91aef87" -"@babel/plugin-proposal-async-generator-functions@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.1.0.tgz#41c1a702e10081456e23a7b74d891922dd1bb6ce" +"@babel/plugin-proposal-async-generator-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-remap-async-to-generator" "^7.1.0" - "@babel/plugin-syntax-async-generators" "^7.0.0" + "@babel/plugin-syntax-async-generators" "^7.2.0" -"@babel/plugin-proposal-class-properties@^7.0.0", "@babel/plugin-proposal-class-properties@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.1.0.tgz#9af01856b1241db60ec8838d84691aa0bd1e8df4" +"@babel/plugin-proposal-class-properties@^7.1.0": + version "7.3.3" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.3.tgz#e69ee114a834a671293ace001708cc1682ed63f9" dependencies: - "@babel/helper-function-name" "^7.1.0" - "@babel/helper-member-expression-to-functions" "^7.0.0" - "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/helper-create-class-features-plugin" "^7.3.0" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.1.0" - "@babel/plugin-syntax-class-properties" "^7.0.0" -"@babel/plugin-proposal-decorators@^7.0.0": - version "7.1.2" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.1.2.tgz#79829bd75fced6581ec6c7ab1930e8d738e892e7" +"@babel/plugin-proposal-decorators@^7.1.2": + version "7.3.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.3.0.tgz#637ba075fa780b1f75d08186e8fb4357d03a72a7" dependencies: + "@babel/helper-create-class-features-plugin" "^7.3.0" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.1.0" - "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/plugin-syntax-decorators" "^7.1.0" + "@babel/plugin-syntax-decorators" "^7.2.0" -"@babel/plugin-proposal-json-strings@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.0.0.tgz#3b4d7b5cf51e1f2e70f52351d28d44fc2970d01e" +"@babel/plugin-proposal-json-strings@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317" dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-json-strings" "^7.0.0" + "@babel/plugin-syntax-json-strings" "^7.2.0" -"@babel/plugin-proposal-object-rest-spread@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0.tgz#9a17b547f64d0676b6c9cecd4edf74a82ab85e7e" +"@babel/plugin-proposal-object-rest-spread@^7.3.1": + version "7.3.2" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.2.tgz#6d1859882d4d778578e41f82cc5d7bf3d5daf6c1" dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" -"@babel/plugin-proposal-optional-catch-binding@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.0.0.tgz#b610d928fe551ff7117d42c8bb410eec312a6425" +"@babel/plugin-proposal-optional-catch-binding@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5" dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.0.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" -"@babel/plugin-proposal-unicode-property-regex@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0.tgz#498b39cd72536cd7c4b26177d030226eba08cd33" +"@babel/plugin-proposal-unicode-property-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.2.0.tgz#abe7281fe46c95ddc143a65e5358647792039520" dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" regexpu-core "^4.2.0" -"@babel/plugin-syntax-async-generators@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.0.0.tgz#bf0891dcdbf59558359d0c626fdc9490e20bc13c" - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-class-properties@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.0.0.tgz#e051af5d300cbfbcec4a7476e37a803489881634" +"@babel/plugin-syntax-async-generators@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-decorators@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.1.0.tgz#2fa7c1a7905a299c9853ebcef340306675f9cbdc" +"@babel/plugin-syntax-decorators@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.2.0.tgz#c50b1b957dcc69e4b1127b65e1c33eef61570c1b" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-json-strings@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.0.0.tgz#0d259a68090e15b383ce3710e01d5b23f3770cbd" +"@babel/plugin-syntax-json-strings@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-object-rest-spread@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0.tgz#37d8fbcaf216bd658ea1aebbeb8b75e88ebc549b" +"@babel/plugin-syntax-object-rest-spread@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-optional-catch-binding@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.0.0.tgz#886f72008b3a8b185977f7cb70713b45e51ee475" +"@babel/plugin-syntax-optional-catch-binding@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz#a94013d6eda8908dfe6a477e7f9eda85656ecf5c" dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-typescript@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.2.0.tgz#55d240536bd314dcbbec70fd949c5cabaed1de29" - integrity sha512-WhKr6yu6yGpGcNMVgIBuI9MkredpVc7Y3YR4UzEZmDztHoL6wV56YBHLhWnjO1EvId1B32HrD3DRFc+zSoKI1g== + version "7.3.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz#a7cc3f66119a9f7ebe2de5383cce193473d65991" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-arrow-functions@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0.tgz#a6c14875848c68a3b4b3163a486535ef25c7e749" +"@babel/plugin-transform-arrow-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-async-to-generator@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.1.0.tgz#109e036496c51dd65857e16acab3bafdf3c57811" +"@babel/plugin-transform-async-to-generator@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.2.0.tgz#68b8a438663e88519e65b776f8938f3445b1a2ff" dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-remap-async-to-generator" "^7.1.0" -"@babel/plugin-transform-block-scoped-functions@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0.tgz#482b3f75103927e37288b3b67b65f848e2aa0d07" +"@babel/plugin-transform-block-scoped-functions@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-block-scoping@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.0.0.tgz#1745075edffd7cdaf69fab2fb6f9694424b7e9bc" +"@babel/plugin-transform-block-scoping@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.2.0.tgz#f17c49d91eedbcdf5dd50597d16f5f2f770132d4" dependencies: "@babel/helper-plugin-utils" "^7.0.0" lodash "^4.17.10" -"@babel/plugin-transform-classes@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.1.0.tgz#ab3f8a564361800cbc8ab1ca6f21108038432249" +"@babel/plugin-transform-classes@^7.2.0": + version "7.3.3" + resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.3.tgz#a0532d6889c534d095e8f604e9257f91386c4b51" dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-define-map" "^7.1.0" @@ -333,103 +331,109 @@ "@babel/helper-split-export-declaration" "^7.0.0" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0.tgz#2fbb8900cd3e8258f2a2ede909b90e7556185e31" +"@babel/plugin-transform-computed-properties@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-destructuring@^7.0.0": - version "7.1.3" - resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.1.3.tgz#e69ff50ca01fac6cb72863c544e516c2b193012f" +"@babel/plugin-transform-destructuring@^7.2.0": + version "7.3.2" + resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.3.2.tgz#f2f5520be055ba1c38c41c0e094d8a461dd78f2d" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-dotall-regex@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.0.0.tgz#73a24da69bc3c370251f43a3d048198546115e58" +"@babel/plugin-transform-dotall-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.2.0.tgz#f0aabb93d120a8ac61e925ea0ba440812dbe0e49" dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" regexpu-core "^4.1.3" -"@babel/plugin-transform-duplicate-keys@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0.tgz#a0601e580991e7cace080e4cf919cfd58da74e86" +"@babel/plugin-transform-duplicate-keys@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz#d952c4930f312a4dbfff18f0b2914e60c35530b3" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-exponentiation-operator@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.1.0.tgz#9c34c2ee7fd77e02779cfa37e403a2e1003ccc73" +"@babel/plugin-transform-exponentiation-operator@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008" dependencies: "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-for-of@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0.tgz#f2ba4eadb83bd17dc3c7e9b30f4707365e1c3e39" +"@babel/plugin-transform-for-of@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.2.0.tgz#ab7468befa80f764bb03d3cb5eef8cc998e1cad9" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-function-name@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.1.0.tgz#29c5550d5c46208e7f730516d41eeddd4affadbb" +"@babel/plugin-transform-function-name@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.2.0.tgz#f7930362829ff99a3174c39f0afcc024ef59731a" dependencies: "@babel/helper-function-name" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-literals@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0.tgz#2aec1d29cdd24c407359c930cdd89e914ee8ff86" +"@babel/plugin-transform-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-modules-amd@^7.0.0", "@babel/plugin-transform-modules-amd@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.1.0.tgz#f9e0a7072c12e296079b5a59f408ff5b97bf86a8" +"@babel/plugin-transform-modules-amd@^7.0.0", "@babel/plugin-transform-modules-amd@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz#82a9bce45b95441f617a24011dc89d12da7f4ee6" dependencies: "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-modules-commonjs@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.1.0.tgz#0a9d86451cbbfb29bd15186306897c67f6f9a05c" +"@babel/plugin-transform-modules-commonjs@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.2.0.tgz#c4f1933f5991d5145e9cfad1dfd848ea1727f404" dependencies: "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-simple-access" "^7.1.0" -"@babel/plugin-transform-modules-systemjs@^7.0.0": - version "7.1.3" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.1.3.tgz#2119a3e3db612fd74a19d88652efbfe9613a5db0" +"@babel/plugin-transform-modules-systemjs@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.2.0.tgz#912bfe9e5ff982924c81d0937c92d24994bb9068" dependencies: "@babel/helper-hoist-variables" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-modules-umd@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.1.0.tgz#a29a7d85d6f28c3561c33964442257cc6a21f2a8" +"@babel/plugin-transform-modules-umd@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz#7678ce75169f0877b8eb2235538c074268dd01ae" dependencies: "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-named-capturing-groups-regex@^7.3.0": + version "7.3.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.3.0.tgz#140b52985b2d6ef0cb092ef3b29502b990f9cd50" + dependencies: + regexp-tree "^0.1.0" + "@babel/plugin-transform-new-target@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz#ae8fbd89517fa7892d20e6564e641e8770c3aa4a" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-object-super@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.1.0.tgz#b1ae194a054b826d8d4ba7ca91486d4ada0f91bb" +"@babel/plugin-transform-object-super@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz#b35d4c10f56bab5d650047dad0f1d8e8814b6598" dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-replace-supers" "^7.1.0" -"@babel/plugin-transform-parameters@^7.1.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.1.0.tgz#44f492f9d618c9124026e62301c296bf606a7aed" +"@babel/plugin-transform-parameters@^7.2.0": + version "7.3.3" + resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.3.3.tgz#3a873e07114e1a5bee17d04815662c8317f10e30" dependencies: "@babel/helper-call-delegate" "^7.1.0" "@babel/helper-get-function-arity" "^7.0.0" @@ -443,216 +447,202 @@ "@babel/plugin-transform-runtime@^7.2.0": version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.2.0.tgz#566bc43f7d0aedc880eaddbd29168d0f248966ea" - integrity sha512-jIgkljDdq4RYDnJyQsiWbdvGeei/0MOTtSHKO/rfbd/mXBxNpdlulMx49L0HQ4pug1fXannxoqCI+fYSle9eSw== + resolved "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.2.0.tgz#566bc43f7d0aedc880eaddbd29168d0f248966ea" dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" resolve "^1.8.1" semver "^5.5.1" -"@babel/plugin-transform-shorthand-properties@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0.tgz#85f8af592dcc07647541a0350e8c95c7bf419d15" +"@babel/plugin-transform-shorthand-properties@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-spread@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0.tgz#93583ce48dd8c85e53f3a46056c856e4af30b49b" +"@babel/plugin-transform-spread@^7.2.0": + version "7.2.2" + resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz#3103a9abe22f742b6d406ecd3cd49b774919b406" dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-sticky-regex@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0.tgz#30a9d64ac2ab46eec087b8530535becd90e73366" +"@babel/plugin-transform-sticky-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1" dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" -"@babel/plugin-transform-template-literals@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0.tgz#084f1952efe5b153ddae69eb8945f882c7a97c65" +"@babel/plugin-transform-template-literals@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.2.0.tgz#d87ed01b8eaac7a92473f608c97c089de2ba1e5b" dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-typeof-symbol@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0.tgz#4dcf1e52e943e5267b7313bff347fdbe0f81cec9" +"@babel/plugin-transform-typeof-symbol@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2" dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-typescript@^7.1.0", "@babel/plugin-transform-typescript@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.2.0.tgz#bce7c06300434de6a860ae8acf6a442ef74a99d1" - integrity sha512-EnI7i2/gJ7ZNr2MuyvN2Hu+BHJENlxWte5XygPvfj/MbvtOkWor9zcnHpMMQL2YYaaCcqtIvJUyJ7QVfoGs7ew== + version "7.3.2" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.3.2.tgz#59a7227163e55738842f043d9e5bd7c040447d96" dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-typescript" "^7.2.0" -"@babel/plugin-transform-unicode-regex@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0.tgz#c6780e5b1863a76fe792d90eded9fcd5b51d68fc" +"@babel/plugin-transform-unicode-regex@^7.2.0": + version "7.2.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.2.0.tgz#4eb8db16f972f8abb5062c161b8b115546ade08b" dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-regex" "^7.0.0" regexpu-core "^4.1.3" "@babel/polyfill@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.0.0.tgz#c8ff65c9ec3be6a1ba10113ebd40e8750fb90bff" + version "7.2.5" + resolved "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.2.5.tgz#6c54b964f71ad27edddc567d065e57e87ed7fa7d" dependencies: core-js "^2.5.7" - regenerator-runtime "^0.11.1" + regenerator-runtime "^0.12.0" "@babel/preset-env@^7.0.0": - version "7.1.0" - resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.1.0.tgz#e67ea5b0441cfeab1d6f41e9b5c79798800e8d11" + version "7.3.1" + resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.3.1.tgz#389e8ca6b17ae67aaf9a2111665030be923515db" dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-async-generator-functions" "^7.1.0" - "@babel/plugin-proposal-json-strings" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.0.0" - "@babel/plugin-syntax-async-generators" "^7.0.0" - "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.0.0" - "@babel/plugin-transform-arrow-functions" "^7.0.0" - "@babel/plugin-transform-async-to-generator" "^7.1.0" - "@babel/plugin-transform-block-scoped-functions" "^7.0.0" - "@babel/plugin-transform-block-scoping" "^7.0.0" - "@babel/plugin-transform-classes" "^7.1.0" - "@babel/plugin-transform-computed-properties" "^7.0.0" - "@babel/plugin-transform-destructuring" "^7.0.0" - "@babel/plugin-transform-dotall-regex" "^7.0.0" - "@babel/plugin-transform-duplicate-keys" "^7.0.0" - "@babel/plugin-transform-exponentiation-operator" "^7.1.0" - "@babel/plugin-transform-for-of" "^7.0.0" - "@babel/plugin-transform-function-name" "^7.1.0" - "@babel/plugin-transform-literals" "^7.0.0" - "@babel/plugin-transform-modules-amd" "^7.1.0" - "@babel/plugin-transform-modules-commonjs" "^7.1.0" - "@babel/plugin-transform-modules-systemjs" "^7.0.0" - "@babel/plugin-transform-modules-umd" "^7.1.0" + "@babel/plugin-proposal-async-generator-functions" "^7.2.0" + "@babel/plugin-proposal-json-strings" "^7.2.0" + "@babel/plugin-proposal-object-rest-spread" "^7.3.1" + "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.2.0" + "@babel/plugin-syntax-async-generators" "^7.2.0" + "@babel/plugin-syntax-json-strings" "^7.2.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + "@babel/plugin-transform-arrow-functions" "^7.2.0" + "@babel/plugin-transform-async-to-generator" "^7.2.0" + "@babel/plugin-transform-block-scoped-functions" "^7.2.0" + "@babel/plugin-transform-block-scoping" "^7.2.0" + "@babel/plugin-transform-classes" "^7.2.0" + "@babel/plugin-transform-computed-properties" "^7.2.0" + "@babel/plugin-transform-destructuring" "^7.2.0" + "@babel/plugin-transform-dotall-regex" "^7.2.0" + "@babel/plugin-transform-duplicate-keys" "^7.2.0" + "@babel/plugin-transform-exponentiation-operator" "^7.2.0" + "@babel/plugin-transform-for-of" "^7.2.0" + "@babel/plugin-transform-function-name" "^7.2.0" + "@babel/plugin-transform-literals" "^7.2.0" + "@babel/plugin-transform-modules-amd" "^7.2.0" + "@babel/plugin-transform-modules-commonjs" "^7.2.0" + "@babel/plugin-transform-modules-systemjs" "^7.2.0" + "@babel/plugin-transform-modules-umd" "^7.2.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.3.0" "@babel/plugin-transform-new-target" "^7.0.0" - "@babel/plugin-transform-object-super" "^7.1.0" - "@babel/plugin-transform-parameters" "^7.1.0" + "@babel/plugin-transform-object-super" "^7.2.0" + "@babel/plugin-transform-parameters" "^7.2.0" "@babel/plugin-transform-regenerator" "^7.0.0" - "@babel/plugin-transform-shorthand-properties" "^7.0.0" - "@babel/plugin-transform-spread" "^7.0.0" - "@babel/plugin-transform-sticky-regex" "^7.0.0" - "@babel/plugin-transform-template-literals" "^7.0.0" - "@babel/plugin-transform-typeof-symbol" "^7.0.0" - "@babel/plugin-transform-unicode-regex" "^7.0.0" - browserslist "^4.1.0" + "@babel/plugin-transform-shorthand-properties" "^7.2.0" + "@babel/plugin-transform-spread" "^7.2.0" + "@babel/plugin-transform-sticky-regex" "^7.2.0" + "@babel/plugin-transform-template-literals" "^7.2.0" + "@babel/plugin-transform-typeof-symbol" "^7.2.0" + "@babel/plugin-transform-unicode-regex" "^7.2.0" + browserslist "^4.3.4" invariant "^2.2.2" js-levenshtein "^1.1.3" semver "^5.3.0" "@babel/runtime@^7.2.0": version "7.3.1" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.1.tgz#574b03e8e8a9898eaf4a872a92ea20b7846f6f2a" - integrity sha512-7jGW8ppV0ant637pIqAcFfQDDH1orEPGJb8aXfUozuCU3QqX7rX4DA8iwrbPrR1hcH0FTTHz47yQnk+bl5xHQA== + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.1.tgz#574b03e8e8a9898eaf4a872a92ea20b7846f6f2a" dependencies: regenerator-runtime "^0.12.0" -"@babel/template@^7.1.0", "@babel/template@^7.1.2": - version "7.1.2" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.1.2.tgz#090484a574fef5a2d2d7726a674eceda5c5b5644" +"@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2": + version "7.2.2" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" dependencies: "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.1.2" - "@babel/types" "^7.1.2" + "@babel/parser" "^7.2.2" + "@babel/types" "^7.2.2" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0": - version "7.1.4" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.4.tgz#f4f83b93d649b4b2c91121a9087fa2fa949ec2b4" +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.2.2", "@babel/traverse@^7.2.3": + version "7.2.3" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8" dependencies: "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.1.3" + "@babel/generator" "^7.2.2" "@babel/helper-function-name" "^7.1.0" "@babel/helper-split-export-declaration" "^7.0.0" - "@babel/parser" "^7.1.3" - "@babel/types" "^7.1.3" - debug "^3.1.0" + "@babel/parser" "^7.2.3" + "@babel/types" "^7.2.2" + debug "^4.1.0" globals "^11.1.0" lodash "^4.17.10" -"@babel/types@^7.0.0", "@babel/types@^7.1.2", "@babel/types@^7.1.3": - version "7.1.3" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.1.3.tgz#3a767004567060c2f40fca49a304712c525ee37d" - dependencies: - esutils "^2.0.2" - lodash "^4.17.10" - to-fast-properties "^2.0.0" - -"@babel/types@^7.1.5": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.2.0.tgz#7941c5b2d8060e06f9601d6be7c223eef906d5d8" - integrity sha512-b4v7dyfApuKDvmPb+O488UlGuR1WbwMXFsO/cyqMrnfvRAChZKJAYeeglWTjUO1b9UghKKgepAQM5tsvBJca6A== +"@babel/types@^7.0.0", "@babel/types@^7.1.5", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.3.3" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.3.3.tgz#6c44d1cdac2a7625b624216657d5bc6c107ab436" dependencies: esutils "^2.0.2" - lodash "^4.17.10" + lodash "^4.17.11" to-fast-properties "^2.0.0" -"@ember-decorators/babel-transforms@^2.1.2": - version "2.1.2" - resolved "https://registry.npmjs.org/@ember-decorators/babel-transforms/-/babel-transforms-2.1.2.tgz#b646e53ece7c18ae42cd03f320146cb1f26f4ebf" +"@ember-decorators/babel-transforms@^5.1.3": + version "5.1.3" + resolved "https://registry.npmjs.org/@ember-decorators/babel-transforms/-/babel-transforms-5.1.3.tgz#90bc10eb03c513e6fd21c818868a3c44eba55efc" dependencies: - "@babel/plugin-proposal-class-properties" "^7.0.0" - "@babel/plugin-proposal-decorators" "^7.0.0" - babel-plugin-transform-class-properties "^6.24.1" - babel-plugin-transform-decorators-legacy "^1.3.4" + "@babel/plugin-proposal-class-properties" "^7.1.0" + "@babel/plugin-proposal-decorators" "^7.1.2" ember-cli-babel-plugin-helpers "^1.0.0" - ember-cli-version-checker "^2.1.0" + ember-cli-version-checker "^3.0.0" -"@ember-decorators/component@^5.1.2": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@ember-decorators/component/-/component-5.1.2.tgz#67ef09b083f7e94f0669e726b66a25cfdb44de4d" - integrity sha512-p72OP3D+pJ/XNXx8zqzkeHY5CGdQRDrxXrXJTezphTV7iBIrs9yMNfnXGIbN8QnItPV65OF8VbhjmzH7AN+LPg== +"@ember-decorators/component@^5.1.3": + version "5.1.3" + resolved "https://registry.npmjs.org/@ember-decorators/component/-/component-5.1.3.tgz#f78c78f8b67ec88bbd00002ef855afb0c8d87f66" dependencies: - "@ember-decorators/utils" "^5.1.2" + "@ember-decorators/utils" "^5.1.3" ember-cli-babel "^7.1.3" -"@ember-decorators/controller@^5.1.2": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@ember-decorators/controller/-/controller-5.1.2.tgz#afb45a3ec4e9e4abc9bd4ab17ba53693bf21b5a2" - integrity sha512-9QcMHqXWICrmH7ifXuwNxOG4lzOh5mdcr5ZlBYP6kDou2KJGtzV/jA0GlAd83gCkHZ984b1ZY129rwYVnU54xA== +"@ember-decorators/controller@^5.1.3": + version "5.1.3" + resolved "https://registry.npmjs.org/@ember-decorators/controller/-/controller-5.1.3.tgz#3fc6c8001716eed42bae468dbd3b5a6cb5160222" dependencies: - "@ember-decorators/utils" "^5.1.2" + "@ember-decorators/utils" "^5.1.3" ember-cli-babel "^7.1.3" + ember-compatibility-helpers "^1.1.2" -"@ember-decorators/data@^5.1.2": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@ember-decorators/data/-/data-5.1.2.tgz#ae77cdf245284be63619190bebf81bee39af5b88" - integrity sha512-BqyhqdSf6JyaJuAhxBN6WYnBbXuFi1zR97dhNyRaM3gRgCu2HUePWPP5mTE6TsDVbcu2Vb536rjoV3ebhsPJqg== +"@ember-decorators/data@^5.1.2", "@ember-decorators/data@^5.1.3": + version "5.1.3" + resolved "https://registry.npmjs.org/@ember-decorators/data/-/data-5.1.3.tgz#a2bee8be053bb4a61c3666839d1d431cd37389c1" dependencies: - "@ember-decorators/utils" "^5.1.2" + "@ember-decorators/utils" "^5.1.3" ember-cli-babel "^7.1.3" + ember-compatibility-helpers "^1.1.2" -"@ember-decorators/object@^5.1.2": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@ember-decorators/object/-/object-5.1.2.tgz#575ad09bf891b283b0ccdad1ff58154f41a855a5" - integrity sha512-7JnMvBnRz3EpEv2p7fr63GvzyJSfqdXDfUKb/1RdRySF+IvcM8vvMOWyNOpgBvg5wBfmXlcnf2n6OQ9ZQey3wg== +"@ember-decorators/object@^5.1.3": + version "5.1.3" + resolved "https://registry.npmjs.org/@ember-decorators/object/-/object-5.1.3.tgz#3b85eaf47d18ab3c9f271cc9c216cbdb62c8263d" dependencies: - "@ember-decorators/utils" "^5.1.2" + "@ember-decorators/utils" "^5.1.3" ember-cli-babel "^7.1.3" + ember-compatibility-helpers "^1.1.2" -"@ember-decorators/service@^5.1.2": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@ember-decorators/service/-/service-5.1.2.tgz#b547b2fbb4a5a2fd30cdc83fcd1345c52458099b" - integrity sha512-8b+oIdn672d/no8e1R7+bAPq+FnVNTjQetmXeJVGqtqA+hTA2FtOfJcch8AZDGfyBxL2V5S50n+K8R1WuEHxFg== +"@ember-decorators/service@^5.1.3": + version "5.1.3" + resolved "https://registry.npmjs.org/@ember-decorators/service/-/service-5.1.3.tgz#4034277d0c428388d47b48886dea35bccebc9d09" dependencies: - "@ember-decorators/utils" "^5.1.2" + "@ember-decorators/utils" "^5.1.3" ember-cli-babel "^7.1.3" + ember-compatibility-helpers "^1.1.2" -"@ember-decorators/utils@^5.1.2": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@ember-decorators/utils/-/utils-5.1.2.tgz#23ff1561ae6ecde14799d5df2a985fa134ca5269" - integrity sha512-EwaL93W0TDN9HjNCwVpYRtMShljP7y1vM4CUkF9lSMGcEqChl1HZemuJ2D2Lx+mIpPQhz8yskkPwCuvs9l3qGQ== +"@ember-decorators/utils@^5.1.3": + version "5.1.3" + resolved "https://registry.npmjs.org/@ember-decorators/utils/-/utils-5.1.3.tgz#c9ae884ce51943718a2ce9b5ed7abe6677645756" dependencies: babel-plugin-debug-macros "^0.2.0" ember-cli-babel "^7.1.3" @@ -667,20 +657,19 @@ ember-cli-babel "^6.16.0" ember-compatibility-helpers "^1.1.1" -"@ember/test-helpers@^1.1.0": - version "1.3.1" - resolved "https://registry.yarnpkg.com/@ember/test-helpers/-/test-helpers-1.3.1.tgz#575b30f4b74c888ea8510c6adffb855876c93a3d" - integrity sha512-j/o5ouq/i64PHkpkcq5Ji26cqxezHhMFRIiehdBmJQo/dVI3gAEsJJh0+qeDD8MrT8WhFT9oqLcicfjEWDEvaA== +"@ember/test-helpers@^1.3.2": + version "1.4.0" + resolved "https://registry.npmjs.org/@ember/test-helpers/-/test-helpers-1.4.0.tgz#46082b6ad1a628a846ad18827bd87026fa478f2d" dependencies: broccoli-debug "^0.6.5" - broccoli-funnel "^2.0.1" + broccoli-funnel "^2.0.2" ember-assign-polyfill "^2.6.0" - ember-cli-babel "^7.4.0" + ember-cli-babel "^7.4.2" ember-cli-htmlbars-inline-precompile "^2.1.0" "@glimmer/di@^0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@glimmer/di/-/di-0.2.0.tgz#73bfd4a6ee4148a80bf092e8a5d29bcac9d4ce7e" + version "0.2.1" + resolved "https://registry.npmjs.org/@glimmer/di/-/di-0.2.1.tgz#5286b6b32040232b751138f6d006130c728d4b3d" "@glimmer/env@^0.1.7": version "0.1.7" @@ -688,31 +677,30 @@ "@glimmer/resolver@^0.4.1": version "0.4.3" - resolved "https://registry.yarnpkg.com/@glimmer/resolver/-/resolver-0.4.3.tgz#b1baae5c3291b4621002ccf8d7870466097e841d" + resolved "https://registry.npmjs.org/@glimmer/resolver/-/resolver-0.4.3.tgz#b1baae5c3291b4621002ccf8d7870466097e841d" dependencies: "@glimmer/di" "^0.2.0" "@sindresorhus/is@^0.7.0": version "0.7.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" + resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" "@types/acorn@^4.0.3": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/acorn/-/acorn-4.0.3.tgz#d1f3e738dde52536f9aad3d3380d14e448820afd" + version "4.0.5" + resolved "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.5.tgz#e29fdf884695e77be4e99e67d748f5147255752d" dependencies: "@types/estree" "*" "@types/ember-qunit@~3.4.5": version "3.4.5" - resolved "https://registry.yarnpkg.com/@types/ember-qunit/-/ember-qunit-3.4.5.tgz#791e4919a88b8d2ac982e4d73564a2c4c08fec6a" - integrity sha512-Nk9hubQdaBUbRgw68dkcLsAt9n9WIHFX3vj5e75Cht5MVizz7j6hW6O5zGtM1QPp62+2/TgUqGIEYMv4nlw1uQ== + resolved "https://registry.npmjs.org/@types/ember-qunit/-/ember-qunit-3.4.5.tgz#791e4919a88b8d2ac982e4d73564a2c4c08fec6a" dependencies: "@types/ember" "*" "@types/ember-test-helpers" "*" "@types/ember-test-helpers@*", "@types/ember-test-helpers@~1.0.4": version "1.0.4" - resolved "https://registry.yarnpkg.com/@types/ember-test-helpers/-/ember-test-helpers-1.0.4.tgz#db08190659339cd6018ff8f842c6df6f24d7679a" + resolved "https://registry.npmjs.org/@types/ember-test-helpers/-/ember-test-helpers-1.0.4.tgz#db08190659339cd6018ff8f842c6df6f24d7679a" dependencies: "@types/ember" "*" "@types/htmlbars-inline-precompile" "*" @@ -721,14 +709,14 @@ "@types/ember-testing-helpers@~0.0.3": version "0.0.3" - resolved "https://registry.yarnpkg.com/@types/ember-testing-helpers/-/ember-testing-helpers-0.0.3.tgz#1a6cfc484b63d19ddd822c87e4dd710597db17d9" + resolved "https://registry.npmjs.org/@types/ember-testing-helpers/-/ember-testing-helpers-0.0.3.tgz#1a6cfc484b63d19ddd822c87e4dd710597db17d9" dependencies: "@types/jquery" "*" "@types/rsvp" "*" "@types/ember@*", "@types/ember@~3.0.25": - version "3.0.25" - resolved "https://registry.yarnpkg.com/@types/ember/-/ember-3.0.25.tgz#9ab6a8be3d03a72176824bb7a59583648b6b1ced" + version "3.0.27" + resolved "https://registry.npmjs.org/@types/ember/-/ember-3.0.27.tgz#2915984038f3ae3609142f8e700b4a783a30be5d" dependencies: "@types/ember__application" "*" "@types/ember__array" "*" @@ -751,67 +739,96 @@ "@types/rsvp" "*" "@types/ember__application@*": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/ember__application/-/ember__application-3.0.5.tgz#e171c5f44f58fb5600952bfde25c1dfe3785a08e" + version "3.0.6" + resolved "https://registry.npmjs.org/@types/ember__application/-/ember__application-3.0.6.tgz#0898e82ab707f34bb0088565dc718354ca7c3e12" + dependencies: + "@types/ember__application" "*" + "@types/ember__engine" "*" + "@types/ember__object" "*" + "@types/ember__routing" "*" "@types/ember__array@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/ember__array/-/ember__array-3.0.3.tgz#87887852b16b7572441b9723994098f939f2a386" + version "3.0.4" + resolved "https://registry.npmjs.org/@types/ember__array/-/ember__array-3.0.4.tgz#6b04b9188da1c315d808304c989a6e7ed24d7ad3" + dependencies: + "@types/ember__array" "*" + "@types/ember__object" "*" "@types/ember__component@*": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/ember__component/-/ember__component-3.0.4.tgz#e671213269bbf974445fb9fdd600d52ef0ae1e2a" + version "3.0.5" + resolved "https://registry.npmjs.org/@types/ember__component/-/ember__component-3.0.5.tgz#ae0a64d53ec3bff7a100347fac52320cba068c22" dependencies: + "@types/ember__component" "*" + "@types/ember__object" "*" "@types/jquery" "*" "@types/ember__controller@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/ember__controller/-/ember__controller-3.0.3.tgz#622440d41ce0ae46f2610ed22670be9088cc9c2b" + version "3.0.4" + resolved "https://registry.npmjs.org/@types/ember__controller/-/ember__controller-3.0.4.tgz#27b7da14770c3b5eb48c70eea6ebab13fa8987da" + dependencies: + "@types/ember__object" "*" "@types/ember__debug@*", "@types/ember__debug@^3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/ember__debug/-/ember__debug-3.0.3.tgz#b8c3481e2305b636dca4524331efd4112071902b" + version "3.0.4" + resolved "https://registry.npmjs.org/@types/ember__debug/-/ember__debug-3.0.4.tgz#cdf87a580688a0e3053820eff6f390fbb7ba0e80" + dependencies: + "@types/ember__debug" "*" + "@types/ember__engine" "*" + "@types/ember__object" "*" "@types/ember__engine@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/ember__engine/-/ember__engine-3.0.3.tgz#440e656f825f73240419367ee7637ca94b4a1780" + version "3.0.4" + resolved "https://registry.npmjs.org/@types/ember__engine/-/ember__engine-3.0.4.tgz#7e79d72653f5c7fd9f6d828d32540be372128aca" + dependencies: + "@types/ember__engine" "*" + "@types/ember__object" "*" "@types/ember__error@*": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/ember__error/-/ember__error-3.0.2.tgz#a30c0e51215feaaa7a32e341c5a04bd601a01d1b" + version "3.0.3" + resolved "https://registry.npmjs.org/@types/ember__error/-/ember__error-3.0.3.tgz#73e5d9f05212d7965e7c2f4df39abdbf5ea41ab1" "@types/ember__object@*": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/ember__object/-/ember__object-3.0.5.tgz#c4957cad68fffdd0959c6ca0d3469df8878b750c" + version "3.0.7" + resolved "https://registry.npmjs.org/@types/ember__object/-/ember__object-3.0.7.tgz#c0423965fb3402f8b8c6dc2b2e78e2468e5522ac" dependencies: + "@types/ember__object" "*" "@types/rsvp" "*" "@types/ember__polyfills@*": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/ember__polyfills/-/ember__polyfills-3.0.2.tgz#ccd9f510a4895abf92435c968f9e582e86a81b25" + version "3.0.4" + resolved "https://registry.npmjs.org/@types/ember__polyfills/-/ember__polyfills-3.0.4.tgz#445ea6609521e499d375755a528b19fabff4828d" "@types/ember__routing@*": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@types/ember__routing/-/ember__routing-3.0.5.tgz#9b193178a1cc29560992c57b04fd7d83a70f831d" + version "3.0.7" + resolved "https://registry.npmjs.org/@types/ember__routing/-/ember__routing-3.0.7.tgz#73f54958ae0a7d28a8da0f91e928a8a48eab02b9" + dependencies: + "@types/ember__component" "*" + "@types/ember__controller" "*" + "@types/ember__object" "*" + "@types/ember__routing" "*" + "@types/ember__service" "*" "@types/ember__runloop@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/ember__runloop/-/ember__runloop-3.0.3.tgz#c23c9d4327ca811482422505a1f5bf1c48458f53" + version "3.0.4" + resolved "https://registry.npmjs.org/@types/ember__runloop/-/ember__runloop-3.0.4.tgz#74442fc6feb9006f9a136bf352c57d2beb974bd9" + dependencies: + "@types/ember__runloop" "*" "@types/ember__service@*": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/ember__service/-/ember__service-3.0.2.tgz#8265c94a599c865f633361b0e3b1efbeef393d7d" + version "3.0.3" + resolved "https://registry.npmjs.org/@types/ember__service/-/ember__service-3.0.3.tgz#1c43997be716d557f3553c0d27707f62fbabb26d" + dependencies: + "@types/ember__object" "*" "@types/ember__string@*": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/ember__string/-/ember__string-3.0.2.tgz#2ffdf09baab6a641c94c0149a8ff3670f793788d" + version "3.0.5" + resolved "https://registry.npmjs.org/@types/ember__string/-/ember__string-3.0.5.tgz#b3b2dc872ffd6f49ac564061a9796ca8cc9ff7ca" dependencies: "@types/handlebars" "*" "@types/ember__test-helpers@~0.7.7": version "0.7.7" - resolved "https://registry.yarnpkg.com/@types/ember__test-helpers/-/ember__test-helpers-0.7.7.tgz#b11832e5e622c1e61f96d8477845a84b5ec348c3" - integrity sha512-Agvz+92jejB/Fy4jf0qhii6bOeXrPXZUWkGGlbNT5VXppRbQaQirjML/NSoGm93dU/o2JD/E9Ax8ZOFSthGkDw== + resolved "https://registry.npmjs.org/@types/ember__test-helpers/-/ember__test-helpers-0.7.7.tgz#b11832e5e622c1e61f96d8477845a84b5ec348c3" dependencies: "@types/ember" "*" "@types/ember__application" "*" @@ -819,50 +836,52 @@ "@types/htmlbars-inline-precompile" "*" "@types/ember__test@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/ember__test/-/ember__test-3.0.3.tgz#dda4721609e9e80d62af784757b8b3b76b49a07d" + version "3.0.4" + resolved "https://registry.npmjs.org/@types/ember__test/-/ember__test-3.0.4.tgz#ce5d13dc6f781281cc5914ff3ec1454b0878901a" + dependencies: + "@types/ember__application" "*" "@types/ember__utils@*": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/ember__utils/-/ember__utils-3.0.1.tgz#f08aa24920515400fec869cbf29df69c4773f6d0" + version "3.0.2" + resolved "https://registry.npmjs.org/@types/ember__utils/-/ember__utils-3.0.2.tgz#d4c32007d0c84c95faa9221a1582b87ac3b1b4f3" -"@types/estree@*": +"@types/estree@*", "@types/estree@0.0.39": version "0.0.39" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" - -"@types/estree@0.0.38": - version "0.0.38" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.38.tgz#c1be40aa933723c608820a99a373a16d215a1ca2" + resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" "@types/handlebars@*": - version "4.0.39" - resolved "https://registry.yarnpkg.com/@types/handlebars/-/handlebars-4.0.39.tgz#961fb54db68030890942e6aeffe9f93a957807bd" + version "4.0.40" + resolved "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.0.40.tgz#b714e13d296a75bff3f199316d1311933ca79ffd" "@types/htmlbars-inline-precompile@*": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/htmlbars-inline-precompile/-/htmlbars-inline-precompile-1.0.0.tgz#4c283da1a7e303b269de3c6aa953acc8d8736949" + version "1.0.1" + resolved "https://registry.npmjs.org/@types/htmlbars-inline-precompile/-/htmlbars-inline-precompile-1.0.1.tgz#de564513fabb165746aecd76369c87bd85e5bbb4" "@types/jquery@*": - version "3.3.22" - resolved "https://registry.yarnpkg.com/@types/jquery/-/jquery-3.3.22.tgz#cde55dc8f83207dffd16205b05f97ce824581735" + version "3.3.29" + resolved "https://registry.npmjs.org/@types/jquery/-/jquery-3.3.29.tgz#680a2219ce3c9250483722fccf5570d1e2d08abd" dependencies: "@types/sizzle" "*" +"@types/minimatch@^3.0.3": + version "3.0.3" + resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" + "@types/node@^9.6.0": - version "9.6.23" - resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.23.tgz#fc429962c1b75f32bd66214a3997f660e8434f0d" + version "9.6.42" + resolved "https://registry.npmjs.org/@types/node/-/node-9.6.42.tgz#96fd9c8cf15fbf2c16fe525fc2be97c49cdd0c2f" "@types/qunit@^2.5.3": - version "2.5.3" - resolved "https://registry.yarnpkg.com/@types/qunit/-/qunit-2.5.3.tgz#e7df363b5e1d1ba034b5fdd34b560d5ec0914225" + version "2.5.4" + resolved "https://registry.npmjs.org/@types/qunit/-/qunit-2.5.4.tgz#0518940acc6013259a8619a1ec34ce0e4ff8d1c4" "@types/rsvp@*", "@types/rsvp@^4.0.2": version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/rsvp/-/rsvp-4.0.2.tgz#bf9f72eaa6771292638a85bb8ce1db97e754b371" + resolved "https://registry.npmjs.org/@types/rsvp/-/rsvp-4.0.2.tgz#bf9f72eaa6771292638a85bb8ce1db97e754b371" "@types/sizzle@*": version "2.3.2" - resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" + resolved "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" "@types/tmp@^0.0.33": version "0.0.33" @@ -874,112 +893,108 @@ abbrev@1: version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" abbrev@~1.0.7: version "1.0.9" resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" abortcontroller-polyfill@^1.1.9: - version "1.1.9" - resolved "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.1.9.tgz#9fefe359fda2e9e0932dc85e6106453ac393b2da" + version "1.2.5" + resolved "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.2.5.tgz#a091ba2d0ea7bae64d6a5f474089a6ab495cec2b" accepts@~1.3.4, accepts@~1.3.5: version "1.3.5" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" dependencies: mime-types "~2.1.18" negotiator "0.6.1" acorn-dynamic-import@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" + resolved "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" dependencies: acorn "^5.0.0" acorn-jsx@^5.0.0: version "5.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" - integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" acorn@^5.0.0, acorn@^5.5.3: - version "5.7.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" + version "5.7.3" + resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" -acorn@^6.0.2: - version "6.0.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.4.tgz#77377e7353b72ec5104550aa2d2097a2fd40b754" - integrity sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg== +acorn@^6.0.7: + version "6.1.0" + resolved "https://registry.npmjs.org/acorn/-/acorn-6.1.0.tgz#b0a3be31752c97a0f7013c5f4903b71a05db6818" after@0.8.2: version "0.8.2" - resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" - -ajv@^5.3.0: - version "5.5.2" - resolved "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" + resolved "https://registry.npmjs.org/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" -ajv@^6.5.3: - version "6.5.4" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz#247d5274110db653706b550fcc2b797ca28cfc59" +ajv@^6.5.5, ajv@^6.9.1: + version "6.9.1" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz#a4d3683d74abc5670e75f0b16520f70a20ea8dc1" dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" -amd-name-resolver@1.2.0, amd-name-resolver@^1.2.0: +amd-name-resolver@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz#fc41b3848824b557313897d71f8d5a0184fbe679" + resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz#fc41b3848824b557313897d71f8d5a0184fbe679" dependencies: ensure-posix-path "^1.0.1" -amd-name-resolver@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-1.2.1.tgz#cea40abff394268307df647ce340c83eda6e9cfc" - integrity sha512-cm0sUV2S8L6pwq0wpu0cHdA2KeEAmCVKy+R/qeZl/VxEn3JmU8WMM0IQrKyrnMXLXbULkZ7ptTaX8vKA0NhNvQ== +amd-name-resolver@^1.2.0, amd-name-resolver@^1.2.1, amd-name-resolver@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-1.3.1.tgz#ffe71c683c6e7191fc4ae1bb3aaed15abea135d9" dependencies: ensure-posix-path "^1.0.1" object-hash "^1.3.1" amdefine@>=0.0.4: version "1.0.1" - resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-colors@3.2.3: + version "3.2.3" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" ansi-escapes@^1.1.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" -ansi-escapes@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" +ansi-escapes@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" ansi-regex@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" ansi-regex@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-regex@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" ansi-styles@^2.2.1: version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@^3.0.0, ansi-styles@^3.2.1: +ansi-styles@^3.0.0, ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" dependencies: color-convert "^1.9.0" ansi-to-html@^0.6.6: - version "0.6.8" - resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.6.8.tgz#2a4468b45a5d2a2c1a51eb1a1175eda8acb4f07a" + version "0.6.10" + resolved "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.10.tgz#412114353bac2589a034db7ec5b371b8ba771131" dependencies: entities "^1.1.1" @@ -989,7 +1004,7 @@ ansi@^0.3.0, ansi@~0.3.0, ansi@~0.3.1: ansicolors@~0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" + resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" ansicolors@~0.3.2: version "0.3.2" @@ -1001,14 +1016,14 @@ ansistyles@~0.1.3: anymatch@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" dependencies: micromatch "^3.1.4" normalize-path "^2.1.1" aproba@^1.0.3: version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" aproba@~1.0.1: version "1.0.4" @@ -1027,46 +1042,40 @@ are-we-there-yet@~1.0.0: are-we-there-yet@~1.1.2: version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" dependencies: delegates "^1.0.0" readable-stream "^2.0.6" argparse@^1.0.7, argparse@~1.0.2: version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" dependencies: sprintf-js "~1.0.2" -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - dependencies: - arr-flatten "^1.0.1" - arr-diff@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" -arr-flatten@^1.0.1, arr-flatten@^1.1.0: +arr-flatten@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" arr-union@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + resolved "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" array-equal@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + resolved "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" array-find-index@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + resolved "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" array-flatten@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" array-index@^1.0.0: version "1.0.0" @@ -1077,39 +1086,21 @@ array-index@^1.0.0: array-to-error@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" + resolved "https://registry.npmjs.org/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" dependencies: array-to-sentence "^1.1.0" array-to-sentence@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" - -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - dependencies: - array-uniq "^1.0.1" - -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + resolved "https://registry.npmjs.org/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" array-unique@^0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" arraybuffer.slice@~0.0.7: version "0.0.7" - resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" - -arrify@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" asap@^2.0.0: version "2.0.6" @@ -1117,7 +1108,7 @@ asap@^2.0.0: asn1@0.1.11: version "0.1.11" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" asn1@~0.2.3: version "0.2.4" @@ -1131,27 +1122,31 @@ assert-plus@1.0.0, assert-plus@^1.0.0: assert-plus@^0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" assert-plus@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" -assertion-error@^1.0.1: +assertion-error@^1.0.1, assertion-error@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" assign-symbols@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" ast-types@0.9.6: version "0.9.6" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" async-disk-cache@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.3.3.tgz#6040486660b370e4051cd9fa9fee275e1fae3728" + version "1.3.4" + resolved "https://registry.npmjs.org/async-disk-cache/-/async-disk-cache-1.3.4.tgz#a5c9f72f199a9933583659f57a0e11377884f816" dependencies: debug "^2.1.3" heimdalljs "^0.2.3" @@ -1159,15 +1154,15 @@ async-disk-cache@^1.2.1: mkdirp "^0.5.0" rimraf "^2.5.3" rsvp "^3.0.18" - username-sync "1.0.1" + username-sync "^1.0.2" async-limiter@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + resolved "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" async-promise-queue@^1.0.3, async-promise-queue@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/async-promise-queue/-/async-promise-queue-1.0.4.tgz#308baafbc74aff66a0bb6e7f4a18d4fe8434440c" + resolved "https://registry.npmjs.org/async-promise-queue/-/async-promise-queue-1.0.4.tgz#308baafbc74aff66a0bb6e7f4a18d4fe8434440c" dependencies: async "^2.4.1" debug "^2.6.8" @@ -1180,33 +1175,33 @@ async-some@~1.0.2: async@^1.5.2: version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" async@^2.0.1, async@^2.4.1, async@^2.5.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" + version "2.6.2" + resolved "https://registry.npmjs.org/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" dependencies: - lodash "^4.17.10" + lodash "^4.17.11" async@~0.2.9: version "0.2.10" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + resolved "https://registry.npmjs.org/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" async@~0.9.0: version "0.9.2" - resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" asynckit@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" atob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" + version "2.1.2" + resolved "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" aws-sign2@~0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" aws-sign2@~0.6.0: version "0.6.0" @@ -1222,7 +1217,7 @@ aws4@^1.8.0: babel-code-frame@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: chalk "^1.1.3" esutils "^2.0.2" @@ -1230,7 +1225,7 @@ babel-code-frame@^6.26.0: babel-core@^6.26.0: version "6.26.3" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + resolved "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" dependencies: babel-code-frame "^6.26.0" babel-generator "^6.26.0" @@ -1265,7 +1260,7 @@ babel-eslint@^10.0.1: babel-generator@^6.26.0: version "6.26.1" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + resolved "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" dependencies: babel-messages "^6.23.0" babel-runtime "^6.26.0" @@ -1278,7 +1273,7 @@ babel-generator@^6.26.0: babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + resolved "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" dependencies: babel-helper-explode-assignable-expression "^6.24.1" babel-runtime "^6.22.0" @@ -1286,7 +1281,7 @@ babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: babel-helper-call-delegate@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + resolved "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" dependencies: babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" @@ -1295,7 +1290,7 @@ babel-helper-call-delegate@^6.24.1: babel-helper-define-map@^6.24.1: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + resolved "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.26.0" @@ -1304,7 +1299,7 @@ babel-helper-define-map@^6.24.1: babel-helper-explode-assignable-expression@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + resolved "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" dependencies: babel-runtime "^6.22.0" babel-traverse "^6.24.1" @@ -1312,7 +1307,7 @@ babel-helper-explode-assignable-expression@^6.24.1: babel-helper-function-name@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + resolved "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" dependencies: babel-helper-get-function-arity "^6.24.1" babel-runtime "^6.22.0" @@ -1322,28 +1317,28 @@ babel-helper-function-name@^6.24.1: babel-helper-get-function-arity@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + resolved "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-helper-hoist-variables@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + resolved "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-helper-optimise-call-expression@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + resolved "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-helper-regex@^6.24.1: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + resolved "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" dependencies: babel-runtime "^6.26.0" babel-types "^6.26.0" @@ -1351,7 +1346,7 @@ babel-helper-regex@^6.24.1: babel-helper-remap-async-to-generator@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + resolved "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" @@ -1361,7 +1356,7 @@ babel-helper-remap-async-to-generator@^6.24.1: babel-helper-replace-supers@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + resolved "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" dependencies: babel-helper-optimise-call-expression "^6.24.1" babel-messages "^6.23.0" @@ -1372,74 +1367,65 @@ babel-helper-replace-supers@^6.24.1: babel-helpers@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + resolved "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" babel-messages@^6.23.0: version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + resolved "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" dependencies: babel-runtime "^6.22.0" babel-plugin-check-es2015-constants@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + resolved "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" dependencies: babel-runtime "^6.22.0" babel-plugin-debug-macros@^0.1.10: version "0.1.11" - resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" + resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.1.11.tgz#6c562bf561fccd406ce14ab04f42c218cf956605" dependencies: semver "^5.3.0" -babel-plugin-debug-macros@^0.2.0: +babel-plugin-debug-macros@^0.2.0, babel-plugin-debug-macros@^0.2.0-beta.6: version "0.2.0" resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0.tgz#0120ac20ce06ccc57bf493b667cf24b85c28da7a" dependencies: semver "^5.3.0" -babel-plugin-debug-macros@^0.2.0-beta.6: - version "0.2.0-beta.6" - resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0-beta.6.tgz#ecdf6e408d5c863ab21740d7ad7f43f027d2f912" +babel-plugin-debug-macros@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.3.0.tgz#7a025944faef0777804ef3518c54e8b040197397" dependencies: semver "^5.3.0" -babel-plugin-ember-modules-api-polyfill@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.3.2.tgz#56ea34bea963498d070a2b7dc2ce18a92c434093" - dependencies: - ember-rfc176-data "^0.3.0" - babel-plugin-ember-modules-api-polyfill@^2.6.0: version "2.6.0" - resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.6.0.tgz#9524a65ef0c31ee82536a19c243fbaec1b977cbb" - integrity sha512-BSbLv3+ju1mcUUoPe7vPJgnGawrNxp6LfFBRHlNOKeMlQlml9Wo2MRRUrbpNDlmVc761xSKj8+cde7R0Lwpq7g== + resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.6.0.tgz#9524a65ef0c31ee82536a19c243fbaec1b977cbb" dependencies: ember-rfc176-data "^0.3.6" babel-plugin-feature-flags@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" + resolved "https://registry.npmjs.org/babel-plugin-feature-flags/-/babel-plugin-feature-flags-0.3.1.tgz#9c827cf9a4eb9a19f725ccb239e85cab02036fc1" babel-plugin-filter-imports@^2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-2.0.4.tgz#9209b708ed3b228349c4e6f660358bf02685e803" - integrity sha512-Ra4VylqMFsmTJCUeLRJ/OP2ZqO0cCJQK2HKihNTnoKP4f8IhxHKL4EkbmfkwGjXCeDyXd0xQ6UTK8Nd+h9V/SQ== + resolved "https://registry.npmjs.org/babel-plugin-filter-imports/-/babel-plugin-filter-imports-2.0.4.tgz#9209b708ed3b228349c4e6f660358bf02685e803" dependencies: "@babel/types" "^7.1.5" lodash "^4.17.11" babel-plugin-htmlbars-inline-precompile@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-1.0.0.tgz#a9d2f6eaad8a3f3d361602de593a8cbef8179c22" - integrity sha512-4jvKEHR1bAX03hBDZ94IXsYCj3bwk9vYsn6ux6JZNL2U5pvzCWjqyrGahfsGNrhERyxw8IqcirOi9Q6WCo3dkQ== + resolved "https://registry.npmjs.org/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-1.0.0.tgz#a9d2f6eaad8a3f3d361602de593a8cbef8179c22" babel-plugin-module-resolver@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.1.1.tgz#881cf67e3d4b8400d5eaaefc1be44d2dc1fe404f" + version "3.2.0" + resolved "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.2.0.tgz#ddfa5e301e3b9aa12d852a9979f18b37881ff5a7" dependencies: find-babel-config "^1.1.0" glob "^7.1.2" @@ -1449,64 +1435,39 @@ babel-plugin-module-resolver@^3.1.1: babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" - -babel-plugin-syntax-class-properties@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" - -babel-plugin-syntax-decorators@^6.1.18: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" + resolved "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" babel-plugin-syntax-exponentiation-operator@^6.8.0: version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + resolved "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + resolved "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" babel-plugin-transform-async-to-generator@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + resolved "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" dependencies: babel-helper-remap-async-to-generator "^6.24.1" babel-plugin-syntax-async-functions "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-class-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" - dependencies: - babel-helper-function-name "^6.24.1" - babel-plugin-syntax-class-properties "^6.8.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-decorators-legacy@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators-legacy/-/babel-plugin-transform-decorators-legacy-1.3.5.tgz#0e492dffa0edd70529072887f8aa86d4dd8b40a1" - dependencies: - babel-plugin-syntax-decorators "^6.1.18" - babel-runtime "^6.2.0" - babel-template "^6.3.0" - babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-block-scoping@^6.23.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" dependencies: babel-runtime "^6.26.0" babel-template "^6.26.0" @@ -1516,7 +1477,7 @@ babel-plugin-transform-es2015-block-scoping@^6.23.0: babel-plugin-transform-es2015-classes@^6.23.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" dependencies: babel-helper-define-map "^6.24.1" babel-helper-function-name "^6.24.1" @@ -1530,33 +1491,33 @@ babel-plugin-transform-es2015-classes@^6.23.0: babel-plugin-transform-es2015-computed-properties@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" babel-plugin-transform-es2015-destructuring@^6.23.0: version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-duplicate-keys@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-plugin-transform-es2015-for-of@^6.23.0: version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-function-name@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" dependencies: babel-helper-function-name "^6.24.1" babel-runtime "^6.22.0" @@ -1564,13 +1525,13 @@ babel-plugin-transform-es2015-function-name@^6.22.0: babel-plugin-transform-es2015-literals@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" dependencies: babel-plugin-transform-es2015-modules-commonjs "^6.24.1" babel-runtime "^6.22.0" @@ -1578,7 +1539,7 @@ babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015 babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: version "6.26.2" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" dependencies: babel-plugin-transform-strict-mode "^6.24.1" babel-runtime "^6.26.0" @@ -1587,7 +1548,7 @@ babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-e babel-plugin-transform-es2015-modules-systemjs@^6.23.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" dependencies: babel-helper-hoist-variables "^6.24.1" babel-runtime "^6.22.0" @@ -1595,7 +1556,7 @@ babel-plugin-transform-es2015-modules-systemjs@^6.23.0: babel-plugin-transform-es2015-modules-umd@^6.23.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" dependencies: babel-plugin-transform-es2015-modules-amd "^6.24.1" babel-runtime "^6.22.0" @@ -1603,14 +1564,14 @@ babel-plugin-transform-es2015-modules-umd@^6.23.0: babel-plugin-transform-es2015-object-super@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" dependencies: babel-helper-replace-supers "^6.24.1" babel-runtime "^6.22.0" babel-plugin-transform-es2015-parameters@^6.23.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" dependencies: babel-helper-call-delegate "^6.24.1" babel-helper-get-function-arity "^6.24.1" @@ -1621,20 +1582,20 @@ babel-plugin-transform-es2015-parameters@^6.23.0: babel-plugin-transform-es2015-shorthand-properties@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-plugin-transform-es2015-spread@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-sticky-regex@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" dependencies: babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" @@ -1642,19 +1603,19 @@ babel-plugin-transform-es2015-sticky-regex@^6.22.0: babel-plugin-transform-es2015-template-literals@^6.22.0: version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-typeof-symbol@^6.23.0: version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" dependencies: babel-runtime "^6.22.0" babel-plugin-transform-es2015-unicode-regex@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" dependencies: babel-helper-regex "^6.24.1" babel-runtime "^6.22.0" @@ -1662,7 +1623,7 @@ babel-plugin-transform-es2015-unicode-regex@^6.22.0: babel-plugin-transform-exponentiation-operator@^6.22.0: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + resolved "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" dependencies: babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" babel-plugin-syntax-exponentiation-operator "^6.8.0" @@ -1670,20 +1631,20 @@ babel-plugin-transform-exponentiation-operator@^6.22.0: babel-plugin-transform-regenerator@^6.22.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + resolved "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" dependencies: regenerator-transform "^0.10.0" babel-plugin-transform-strict-mode@^6.24.1: version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + resolved "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" dependencies: babel-runtime "^6.22.0" babel-types "^6.24.1" babel-polyfill@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + resolved "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" dependencies: babel-runtime "^6.26.0" core-js "^2.5.0" @@ -1691,7 +1652,7 @@ babel-polyfill@^6.26.0: babel-preset-env@^1.7.0: version "1.7.0" - resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" + resolved "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" dependencies: babel-plugin-check-es2015-constants "^6.22.0" babel-plugin-syntax-trailing-function-commas "^6.22.0" @@ -1726,7 +1687,7 @@ babel-preset-env@^1.7.0: babel-register@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + resolved "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" dependencies: babel-core "^6.26.0" babel-runtime "^6.26.0" @@ -1736,16 +1697,16 @@ babel-register@^6.26.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: +babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: core-js "^2.4.0" regenerator-runtime "^0.11.0" -babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: +babel-template@^6.24.1, babel-template@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + resolved "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" dependencies: babel-runtime "^6.26.0" babel-traverse "^6.26.0" @@ -1755,7 +1716,7 @@ babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0: babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + resolved "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" dependencies: babel-code-frame "^6.26.0" babel-messages "^6.23.0" @@ -1769,7 +1730,7 @@ babel-traverse@^6.24.1, babel-traverse@^6.26.0: babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + resolved "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" dependencies: babel-runtime "^6.26.0" esutils "^2.0.2" @@ -1778,45 +1739,45 @@ babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: babel6-plugin-strip-class-callcheck@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" + resolved "https://registry.npmjs.org/babel6-plugin-strip-class-callcheck/-/babel6-plugin-strip-class-callcheck-6.0.0.tgz#de841c1abebbd39f78de0affb2c9a52ee228fddf" babel6-plugin-strip-heimdall@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" + resolved "https://registry.npmjs.org/babel6-plugin-strip-heimdall/-/babel6-plugin-strip-heimdall-6.0.1.tgz#35f80eddec1f7fffdc009811dfbd46d9965072b6" babylon@^6.18.0: version "6.18.0" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" backbone@^1.1.2: - version "1.3.3" - resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.3.3.tgz#4cc80ea7cb1631ac474889ce40f2f8bc683b2999" + version "1.4.0" + resolved "https://registry.npmjs.org/backbone/-/backbone-1.4.0.tgz#54db4de9df7c3811c3f032f34749a4cd27f3bd12" dependencies: underscore ">=1.8.3" backo2@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" balanced-match@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" base64-arraybuffer@0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + resolved "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" base64-js@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.2.tgz#024f0f72afa25b75f9c0ee73cd4f55ec1bed9784" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-0.0.2.tgz#024f0f72afa25b75f9c0ee73cd4f55ec1bed9784" base64id@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + resolved "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" base@^0.11.1: version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" dependencies: cache-base "^1.0.1" class-utils "^0.3.5" @@ -1827,10 +1788,10 @@ base@^0.11.1: pascalcase "^0.1.1" basic-auth@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.0.tgz#015db3f353e02e56377755f962742e8981e7bbba" + version "2.0.1" + resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" dependencies: - safe-buffer "5.1.1" + safe-buffer "5.1.2" bcrypt-pbkdf@^1.0.0: version "1.0.2" @@ -1840,27 +1801,27 @@ bcrypt-pbkdf@^1.0.0: better-assert@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + resolved "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" dependencies: callsite "1.0.0" "binaryextensions@1 || 2": - version "2.1.1" - resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935" + version "2.1.2" + resolved "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.2.tgz#c83c3d74233ba7674e4f313cb2a2b70f54e94b7c" bl@~1.0.0: version "1.0.3" - resolved "http://registry.npmjs.org/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e" + resolved "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e" dependencies: readable-stream "~2.0.5" blank-object@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" + resolved "https://registry.npmjs.org/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" -blob@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" +blob@0.0.5: + version "0.0.5" + resolved "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" block-stream@*: version "0.0.9" @@ -1869,23 +1830,8 @@ block-stream@*: inherits "~2.0.0" bluebird@^3.1.1, bluebird@^3.4.6: - version "3.5.1" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" - -body-parser@1.18.2: - version "1.18.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" - dependencies: - 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" + version "3.5.3" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" body-parser@1.18.3: version "1.18.3" @@ -1904,7 +1850,7 @@ body-parser@1.18.3: body@^5.1.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" + resolved "https://registry.npmjs.org/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" dependencies: continuable-cache "^0.3.1" error "^7.0.0" @@ -1913,7 +1859,7 @@ body@^5.1.0: boom@0.4.x: version "0.4.2" - resolved "https://registry.yarnpkg.com/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" + resolved "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz#7a636e9ded4efcefb19cef4947a3c67dfaee911b" dependencies: hoek "0.9.x" @@ -1925,14 +1871,14 @@ boom@2.x.x: bops@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/bops/-/bops-0.0.3.tgz#c5cbf6fea8be7401ca5ea6d1679e6c4e8b407c79" + resolved "https://registry.npmjs.org/bops/-/bops-0.0.3.tgz#c5cbf6fea8be7401ca5ea6d1679e6c4e8b407c79" dependencies: base64-js "0.0.2" to-utf8 "0.0.1" bower-config@^1.3.0: version "1.4.1" - resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc" + resolved "https://registry.npmjs.org/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc" dependencies: graceful-fs "^4.1.3" mout "^1.0.0" @@ -1942,26 +1888,18 @@ bower-config@^1.3.0: bower-endpoint-parser@0.2.2: version "0.2.2" - resolved "https://registry.yarnpkg.com/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" + resolved "https://registry.npmjs.org/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" brace-expansion@^1.0.0, brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" dependencies: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - braces@^2.3.1: version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + resolved "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" dependencies: arr-flatten "^1.1.0" array-unique "^0.3.2" @@ -1981,9 +1919,9 @@ broccoli-amd-funnel@^2.0.1: broccoli-plugin "^1.3.0" symlink-or-copy "^1.2.0" -broccoli-babel-transpiler@^6.4.5, broccoli-babel-transpiler@^6.5.0: - version "6.5.0" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.5.0.tgz#aa501a227b298a99742fdd0309b1eaad7124bba0" +broccoli-babel-transpiler@^6.5.0: + version "6.5.1" + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.5.1.tgz#a4afc8d3b59b441518eb9a07bd44149476e30738" dependencies: babel-core "^6.26.0" broccoli-funnel "^2.0.1" @@ -1996,10 +1934,9 @@ broccoli-babel-transpiler@^6.4.5, broccoli-babel-transpiler@^6.5.0: rsvp "^4.8.2" workerpool "^2.3.0" -broccoli-babel-transpiler@^7.1.0, broccoli-babel-transpiler@^7.1.2: +broccoli-babel-transpiler@^7.1.1, broccoli-babel-transpiler@^7.1.2: version "7.1.2" - resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.1.2.tgz#fb5d6f8b9a805627ac3f2914ac9d86e82ca2413b" - integrity sha512-rljx86xgZJ2BjWt+xCSVfvyt3ONpCdMMXzMpeeVpAGdBHj3bqQICdPHZDAbzn1vKY/LIPsJZftvdxql1jiLGzw== + resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.1.2.tgz#fb5d6f8b9a805627ac3f2914ac9d86e82ca2413b" dependencies: "@babel/core" "^7.0.0" "@babel/polyfill" "^7.0.0" @@ -2027,7 +1964,7 @@ broccoli-builder@^0.18.14: broccoli-caching-writer@^2.2.0: version "2.3.1" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" @@ -2038,7 +1975,7 @@ broccoli-caching-writer@^2.2.0: broccoli-caching-writer@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.1" @@ -2049,7 +1986,7 @@ broccoli-caching-writer@^3.0.3: broccoli-caching-writer@~2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" + resolved "https://registry.npmjs.org/broccoli-caching-writer/-/broccoli-caching-writer-2.0.4.tgz#d995d7d1977292e498f78df05887230fcb4a5e2c" dependencies: broccoli-kitchen-sink-helpers "^0.2.5" broccoli-plugin "1.1.0" @@ -2062,14 +1999,14 @@ broccoli-caching-writer@~2.0.4: broccoli-clean-css@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" + resolved "https://registry.npmjs.org/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" dependencies: broccoli-persistent-filter "^1.1.6" clean-css-promise "^0.1.0" inline-source-map-comment "^1.0.5" json-stable-stringify "^1.0.0" -broccoli-concat@^3.5.1, broccoli-concat@^3.7.3: +broccoli-concat@^3.7.3: version "3.7.3" resolved "https://registry.npmjs.org/broccoli-concat/-/broccoli-concat-3.7.3.tgz#0dca01311567ffb13180e6b4eb111824628e4885" dependencies: @@ -2094,25 +2031,14 @@ broccoli-config-loader@^1.0.1: broccoli-config-replace@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" + resolved "https://registry.npmjs.org/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.2.0" debug "^2.2.0" fs-extra "^0.24.0" -broccoli-debug@^0.6.4: - version "0.6.4" - resolved "https://registry.yarnpkg.com/broccoli-debug/-/broccoli-debug-0.6.4.tgz#986eb3d2005e00e3bb91f9d0a10ab137210cd150" - dependencies: - broccoli-plugin "^1.2.1" - fs-tree-diff "^0.5.2" - heimdalljs "^0.2.1" - heimdalljs-logger "^0.1.7" - symlink-or-copy "^1.1.8" - tree-sync "^1.2.2" - -broccoli-debug@^0.6.5: +broccoli-debug@^0.6.4, broccoli-debug@^0.6.5: version "0.6.5" resolved "https://registry.npmjs.org/broccoli-debug/-/broccoli-debug-0.6.5.tgz#164a5cdafd8936e525e702bf8f91f39d758e2e78" dependencies: @@ -2125,21 +2051,21 @@ broccoli-debug@^0.6.5: broccoli-file-creator@^1.1.1: version "1.2.0" - resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-1.2.0.tgz#27f1b25b1b00e7bb7bf3d5d7abed5f4d5388df4d" + resolved "https://registry.npmjs.org/broccoli-file-creator/-/broccoli-file-creator-1.2.0.tgz#27f1b25b1b00e7bb7bf3d5d7abed5f4d5388df4d" dependencies: broccoli-plugin "^1.1.0" mkdirp "^0.5.1" broccoli-file-creator@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-2.1.1.tgz#7351dd2496c762cfce7736ce9b49e3fce0c7b7db" + resolved "https://registry.npmjs.org/broccoli-file-creator/-/broccoli-file-creator-2.1.1.tgz#7351dd2496c762cfce7736ce9b49e3fce0c7b7db" dependencies: broccoli-plugin "^1.1.0" mkdirp "^0.5.1" broccoli-filter@^1.0.1: version "1.3.0" - resolved "https://registry.yarnpkg.com/broccoli-filter/-/broccoli-filter-1.3.0.tgz#71e3a8e32a17f309e12261919c5b1006d6766de6" + resolved "https://registry.npmjs.org/broccoli-filter/-/broccoli-filter-1.3.0.tgz#71e3a8e32a17f309e12261919c5b1006d6766de6" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" broccoli-plugin "^1.0.0" @@ -2153,11 +2079,11 @@ broccoli-filter@^1.0.1: broccoli-funnel-reducer@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" + resolved "https://registry.npmjs.org/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1: version "1.2.0" - resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" + resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" dependencies: array-equal "^1.0.0" blank-object "^1.0.1" @@ -2174,9 +2100,9 @@ broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1: symlink-or-copy "^1.0.0" walk-sync "^0.3.1" -broccoli-funnel@^2.0.0, broccoli-funnel@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-2.0.1.tgz#6823c73b675ef78fffa7ab800f083e768b51d449" +broccoli-funnel@^2.0.0, broccoli-funnel@^2.0.1, broccoli-funnel@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-2.0.2.tgz#0edf629569bc10bd02cc525f74b9a38e71366a75" dependencies: array-equal "^1.0.0" blank-object "^1.0.1" @@ -2194,21 +2120,21 @@ broccoli-funnel@^2.0.0, broccoli-funnel@^2.0.1: broccoli-kitchen-sink-helpers@^0.2.5: version "0.2.9" - resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" + resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" dependencies: glob "^5.0.10" mkdirp "^0.5.1" broccoli-kitchen-sink-helpers@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" + resolved "https://registry.npmjs.org/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" dependencies: glob "^5.0.10" mkdirp "^0.5.1" broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.1: version "1.2.4" - resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" + resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" dependencies: broccoli-plugin "^1.3.0" can-symlink "^1.0.0" @@ -2220,16 +2146,15 @@ broccoli-merge-trees@^1.0.0, broccoli-merge-trees@^1.1.1: symlink-or-copy "^1.0.0" broccoli-merge-trees@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-2.0.0.tgz#10aea46dd5cebcc8b8f7d5a54f0a84a4f0bb90b9" + version "2.0.1" + resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-2.0.1.tgz#14d4b7fc1a90318c12b16f843e6ba2693808100c" dependencies: broccoli-plugin "^1.3.0" merge-trees "^1.0.1" broccoli-merge-trees@^3.0.0, broccoli-merge-trees@^3.0.1, broccoli-merge-trees@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-3.0.2.tgz#f33b451994225522b5c9bcf27d59decfd8ba537d" - integrity sha512-ZyPAwrOdlCddduFbsMyyFzJUrvW6b04pMvDiAQZrCwghlvgowJDY+EfoXn+eR1RRA5nmGHJ+B68T63VnpRiT1A== + resolved "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-3.0.2.tgz#f33b451994225522b5c9bcf27d59decfd8ba537d" dependencies: broccoli-plugin "^1.3.0" merge-trees "^2.0.0" @@ -2243,7 +2168,7 @@ broccoli-middleware@^2.0.1: broccoli-module-normalizer@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/broccoli-module-normalizer/-/broccoli-module-normalizer-1.3.0.tgz#f9982d9cbb776b4ed754161cc6547784d3eb19de" + resolved "https://registry.npmjs.org/broccoli-module-normalizer/-/broccoli-module-normalizer-1.3.0.tgz#f9982d9cbb776b4ed754161cc6547784d3eb19de" dependencies: broccoli-plugin "^1.3.0" merge-trees "^1.0.1" @@ -2252,7 +2177,7 @@ broccoli-module-normalizer@^1.3.0: broccoli-module-unification-reexporter@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/broccoli-module-unification-reexporter/-/broccoli-module-unification-reexporter-1.0.0.tgz#031909c5d3f159ec11d5f9e2346f2861db8acb3e" + resolved "https://registry.npmjs.org/broccoli-module-unification-reexporter/-/broccoli-module-unification-reexporter-1.0.0.tgz#031909c5d3f159ec11d5f9e2346f2861db8acb3e" dependencies: broccoli-plugin "^1.3.0" mkdirp "^0.5.1" @@ -2260,11 +2185,11 @@ broccoli-module-unification-reexporter@^1.0.0: broccoli-node-info@1.1.0, broccoli-node-info@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" + resolved "https://registry.npmjs.org/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.3.tgz#3511bc52fc53740cda51621f58a28152d9911bc1" + version "1.4.6" + resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.6.tgz#80762d19000880a77da33c34373299c0f6a3e615" dependencies: async-disk-cache "^1.2.1" async-promise-queue "^1.0.3" @@ -2281,14 +2206,13 @@ broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-p walk-sync "^0.3.1" broccoli-persistent-filter@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-2.1.1.tgz#7bb2b1015baedf5cf58b5b2608495f3d78f81b12" - integrity sha512-2VCbLJqMg/AWJ6WTmv83X13a6DD3BS7Gngc932jrg1snVqsB8LJDyJh+Hd9v1tQ/vMA+4vbWgwk4tDmI/tAZWg== + version "2.2.0" + resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-2.2.0.tgz#e38b51c287a6684eb3490b9d7d62b76c88ad5fb1" dependencies: async-disk-cache "^1.2.1" async-promise-queue "^1.0.3" broccoli-plugin "^1.0.0" - fs-tree-diff "^0.5.2" + fs-tree-diff "^1.0.2" hash-for-dep "^1.0.2" heimdalljs "^0.2.1" heimdalljs-logger "^0.1.7" @@ -2297,30 +2221,20 @@ broccoli-persistent-filter@^2.1.1: rimraf "^2.6.1" rsvp "^4.7.0" symlink-or-copy "^1.0.1" - walk-sync "^0.3.1" + walk-sync "^1.0.0" broccoli-plugin@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" + resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" rimraf "^2.3.4" symlink-or-copy "^1.0.1" -broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.0.tgz#bee704a8e42da08cb58e513aaa436efb7f0ef1ee" - dependencies: - promise-map-series "^0.2.1" - quick-temp "^0.1.3" - rimraf "^2.3.4" - symlink-or-copy "^1.1.8" - -broccoli-plugin@^1.3.1: +broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0, broccoli-plugin@^1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.1.tgz#a26315732fb99ed2d9fb58f12a1e14e986b4fabd" - integrity sha512-DW8XASZkmorp+q7J4EeDEZz+LoyKLAd2XZULXyD9l4m9/hAKV3vjHmB1kiUshcWAYMgTP1m2i4NnqCE/23h6AQ== + resolved "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.3.1.tgz#a26315732fb99ed2d9fb58f12a1e14e986b4fabd" dependencies: promise-map-series "^0.2.1" quick-temp "^0.1.3" @@ -2329,7 +2243,7 @@ broccoli-plugin@^1.3.1: broccoli-rollup@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/broccoli-rollup/-/broccoli-rollup-2.1.1.tgz#0b77dc4b7560a53e998ea85f3b56772612d4988d" + resolved "https://registry.npmjs.org/broccoli-rollup/-/broccoli-rollup-2.1.1.tgz#0b77dc4b7560a53e998ea85f3b56772612d4988d" dependencies: "@types/node" "^9.6.0" amd-name-resolver "^1.2.0" @@ -2345,17 +2259,17 @@ broccoli-rollup@^2.1.1: broccoli-slow-trees@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" + resolved "https://registry.npmjs.org/broccoli-slow-trees/-/broccoli-slow-trees-3.0.1.tgz#9bf2a9e2f8eb3ed3a3f2abdde988da437ccdc9b4" dependencies: heimdalljs "^0.2.1" broccoli-source@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" + resolved "https://registry.npmjs.org/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" broccoli-sri-hash@^2.1.0: version "2.1.2" - resolved "https://registry.yarnpkg.com/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" + resolved "https://registry.npmjs.org/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" dependencies: broccoli-caching-writer "^2.2.0" mkdirp "^0.5.1" @@ -2365,8 +2279,7 @@ broccoli-sri-hash@^2.1.0: broccoli-stew@^2.0.0, broccoli-stew@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-2.0.1.tgz#d0a507b79bf5fea9ff84032ae837dc48670ab1dc" - integrity sha512-EUzgkbYF4m8YVD2bkEa7OfYJ11V3dQ+yPuxdz/nFh8eMEn6dhOujtuSBnOWsvGDgsS9oqNZgx/MHJxI6Rr3AqQ== + resolved "https://registry.npmjs.org/broccoli-stew/-/broccoli-stew-2.0.1.tgz#d0a507b79bf5fea9ff84032ae837dc48670ab1dc" dependencies: broccoli-debug "^0.6.5" broccoli-funnel "^2.0.0" @@ -2385,7 +2298,7 @@ broccoli-stew@^2.0.0, broccoli-stew@^2.0.1: broccoli-string-replace@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" + resolved "https://registry.npmjs.org/broccoli-string-replace/-/broccoli-string-replace-0.1.2.tgz#1ed92f85680af8d503023925e754e4e33676b91f" dependencies: broccoli-persistent-filter "^1.1.5" minimatch "^3.0.3" @@ -2403,7 +2316,7 @@ broccoli-test-helper@^2.0.0: broccoli-uglify-sourcemap@^2.1.1, broccoli-uglify-sourcemap@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-2.2.0.tgz#2ff49389bdf342a550c3596750ba2dde95a8f7d4" + resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-2.2.0.tgz#2ff49389bdf342a550c3596750ba2dde95a8f7d4" dependencies: async-promise-queue "^1.0.4" broccoli-plugin "^1.2.1" @@ -2418,8 +2331,8 @@ broccoli-uglify-sourcemap@^2.1.1, broccoli-uglify-sourcemap@^2.2.0: workerpool "^2.3.0" broccoli@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/broccoli/-/broccoli-2.0.0.tgz#7b95d6173865184697e4dab9f477591057b9410e" + version "2.0.1" + resolved "https://registry.npmjs.org/broccoli/-/broccoli-2.0.1.tgz#3611d643bf4b2666b565dc24cc5307fc80f62bf6" dependencies: broccoli-node-info "1.1.0" broccoli-slow-trees "^3.0.1" @@ -2442,26 +2355,26 @@ broccoli@^2.0.0: browser-stdout@1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" browserslist@^3.2.6: version "3.2.8" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" dependencies: caniuse-lite "^1.0.30000844" electron-to-chromium "^1.3.47" -browserslist@^4.1.0: - version "4.3.3" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.3.3.tgz#88a7d9ce2e5db561e160ab660bc59cb406a0c41d" +browserslist@^4.3.4: + version "4.4.1" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.4.1.tgz#42e828954b6b29a7a53e352277be429478a69062" dependencies: - caniuse-lite "^1.0.30000898" - electron-to-chromium "^1.3.81" - node-releases "^1.0.0-alpha.15" + caniuse-lite "^1.0.30000929" + electron-to-chromium "^1.3.103" + node-releases "^1.1.3" bser@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" + resolved "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" dependencies: node-int64 "^0.4.0" @@ -2481,12 +2394,12 @@ buffer-fill@^1.0.0: resolved "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" buffer-from@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" + version "1.1.1" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" builtin-modules@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" builtins@0.0.7: version "0.0.7" @@ -2494,19 +2407,19 @@ builtins@0.0.7: builtins@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + resolved "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" bytes@1: version "1.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" + resolved "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" bytes@3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" cache-base@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" dependencies: collection-visit "^1.0.0" component-emitter "^1.2.1" @@ -2520,7 +2433,7 @@ cache-base@^1.0.1: cacheable-request@^2.1.1: version "2.1.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" + resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" dependencies: clone-response "1.0.2" get-stream "3.0.0" @@ -2532,62 +2445,56 @@ cacheable-request@^2.1.1: calculate-cache-key-for-tree@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" + resolved "https://registry.npmjs.org/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-1.1.0.tgz#0c3e42c9c134f3c9de5358c0f16793627ea976d6" dependencies: json-stable-stringify "^1.0.1" -caller-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" - dependencies: - callsites "^0.2.0" - callsite@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + resolved "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" -callsites@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" +callsites@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3" camelcase-keys@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" dependencies: camelcase "^2.0.0" map-obj "^1.0.0" camelcase@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + +camelcase@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" can-symlink@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" + resolved "https://registry.npmjs.org/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" dependencies: tmp "0.0.28" -caniuse-lite@^1.0.30000844: - version "1.0.30000865" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000865.tgz#70026616e8afe6e1442f8bb4e1092987d81a2f25" - -caniuse-lite@^1.0.30000898: - version "1.0.30000899" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000899.tgz#6febdbbc388a7982f620ee0e3d09aab0c061389e" +caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30000929: + version "1.0.30000938" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000938.tgz#b64bf1427438df40183fce910fe24e34feda7a3f" capture-exit@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" + resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" dependencies: rsvp "^3.3.3" capture-stack-trace@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" + version "1.0.1" + resolved "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d" cardinal@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" + resolved "https://registry.npmjs.org/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" dependencies: ansicolors "~0.2.1" redeyed "~1.0.0" @@ -2602,44 +2509,44 @@ caseless@~0.12.0: chai-as-promised@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" + resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" dependencies: check-error "^1.0.2" chai-as-promised@^7.0.0: version "7.1.1" - resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" + resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" dependencies: check-error "^1.0.2" chai-files@^1.0.0, chai-files@^1.1.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" + resolved "https://registry.npmjs.org/chai-files/-/chai-files-1.4.0.tgz#0e25610fadc551b1eae79c2f4ee79faf2f842296" dependencies: assertion-error "^1.0.1" chai@^3.3.0: version "3.5.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" + resolved "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" dependencies: assertion-error "^1.0.1" deep-eql "^0.1.3" type-detect "^1.0.0" chai@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c" + version "4.2.0" + resolved "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" dependencies: - assertion-error "^1.0.1" - check-error "^1.0.1" - deep-eql "^3.0.0" + assertion-error "^1.1.0" + check-error "^1.0.2" + deep-eql "^3.0.1" get-func-name "^2.0.0" - pathval "^1.0.0" - type-detect "^4.0.0" + pathval "^1.1.0" + type-detect "^4.0.5" chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -2647,9 +2554,9 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" @@ -2661,29 +2568,29 @@ chardet@^0.7.0: charm@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" + resolved "https://registry.npmjs.org/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" dependencies: inherits "^2.0.1" -check-error@^1.0.1, check-error@^1.0.2: +check-error@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" -chownr@^1.0.1, chownr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" +chownr@^1.0.1: + version "1.1.1" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" -ci-info@^1.1.3: - version "1.6.0" - resolved "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" +chownr@~1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" -circular-json@^0.3.1: - version "0.3.3" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" class-utils@^0.3.5: version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" dependencies: arr-union "^3.1.0" define-property "^0.2.5" @@ -2692,11 +2599,11 @@ class-utils@^0.3.5: clean-base-url@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" + resolved "https://registry.npmjs.org/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" clean-css-promise@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" + resolved "https://registry.npmjs.org/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" dependencies: array-to-error "^1.0.0" clean-css "^3.4.5" @@ -2704,30 +2611,30 @@ clean-css-promise@^0.1.0: clean-css@^3.4.5: version "3.4.28" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" + resolved "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" dependencies: commander "2.8.x" source-map "0.4.x" clean-up-path@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/clean-up-path/-/clean-up-path-1.0.0.tgz#de9e8196519912e749c9eaf67c13d64fac72a3e5" + resolved "https://registry.npmjs.org/clean-up-path/-/clean-up-path-1.0.0.tgz#de9e8196519912e749c9eaf67c13d64fac72a3e5" cli-cursor@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" dependencies: restore-cursor "^1.0.1" cli-cursor@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: restore-cursor "^2.0.0" cli-spinners@^1.1.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" + resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" cli-table3@^0.5.1: version "0.5.1" @@ -2740,23 +2647,31 @@ cli-table3@^0.5.1: cli-table@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + resolved "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" dependencies: colors "1.0.3" cli-width@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" clone-response@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" dependencies: mimic-response "^1.0.0" clone@^1.0.2: version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" clone@^2.0.0, clone@^2.1.2: version "2.1.2" @@ -2771,36 +2686,36 @@ cmd-shim@~2.0.1: co@^4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" code-point-at@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" collection-visit@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + resolved "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" dependencies: map-visit "^1.0.0" object-visit "^1.0.0" color-convert@^1.9.0: - version "1.9.2" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" dependencies: - color-name "1.1.1" + color-name "1.1.3" -color-name@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" colors@1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + resolved "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" colors@^1.1.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.1.tgz#4accdb89cf2cabc7f982771925e9468784f32f3d" + version "1.3.3" + resolved "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" columnify@~1.5.4: version "1.5.4" @@ -2817,57 +2732,49 @@ combined-stream@^1.0.5, combined-stream@^1.0.6, combined-stream@~1.0.5, combined combined-stream@~0.0.4: version "0.0.7" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" dependencies: delayed-stream "0.0.5" commander@2.12.2: version "2.12.2" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" - -commander@2.15.1: - version "2.15.1" - resolved "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" + resolved "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" commander@2.8.x: version "2.8.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + resolved "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" dependencies: graceful-readlink ">= 1.0.0" -commander@^2.15.1, commander@^2.9.0: +commander@^2.15.1, commander@^2.6.0, commander@^2.9.0: version "2.19.0" resolved "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" -commander@^2.6.0, commander@~2.16.0: - version "2.16.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" - commander@~2.17.1: version "2.17.1" resolved "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" common-tags@^1.4.0, common-tags@^1.8.0: version "1.8.0" - resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" + resolved "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" component-bind@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + resolved "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" component-emitter@1.2.1, component-emitter@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" component-inherit@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + resolved "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" compressible@~2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7" + version "2.0.16" + resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.16.tgz#a49bf9858f3821b64ce1be0296afc7380466a77f" dependencies: - mime-db ">= 1.34.0 < 2" + mime-db ">= 1.38.0 < 2" compression@^1.7.3: version "1.7.3" @@ -2883,11 +2790,11 @@ compression@^1.7.3: concat-map@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" concat-stream@^1.4.6, concat-stream@^1.4.7: version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" dependencies: buffer-from "^1.0.0" inherits "^2.0.3" @@ -2914,7 +2821,7 @@ configstore@^4.0.0: connect@^3.6.6: version "3.6.6" - resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" + resolved "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" dependencies: debug "2.6.9" finalhandler "1.1.0" @@ -2923,11 +2830,11 @@ connect@^3.6.6: console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" console-ui@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-2.2.2.tgz#b294a2934de869dd06789ab4be69555411edef29" + version "2.2.3" + resolved "https://registry.npmjs.org/console-ui/-/console-ui-2.2.3.tgz#134b92e632f2c0088f78e52b20f1ca22a95b9a91" dependencies: chalk "^2.1.0" inquirer "^2" @@ -2938,79 +2845,67 @@ console-ui@^2.2.2: consolidate@^0.15.1: version "0.15.1" - resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7" + resolved "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7" dependencies: bluebird "^3.1.1" content-disposition@0.5.2: version "0.5.2" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" content-type@~1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" continuable-cache@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" + resolved "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" -convert-source-map@^1.1.0: +convert-source-map@^1.1.0, convert-source-map@^1.5.1: version "1.6.0" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" dependencies: safe-buffer "~5.1.1" -convert-source-map@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" - cookie-signature@1.0.6: version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" cookie@0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" copy-dereference@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" + resolved "https://registry.npmjs.org/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" copy-descriptor@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.7: - version "2.5.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" + version "2.6.5" + resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" core-object@^3.1.5: version "3.1.5" - resolved "https://registry.yarnpkg.com/core-object/-/core-object-3.1.5.tgz#fa627b87502adc98045e44678e9a8ec3b9c0d2a9" + resolved "https://registry.npmjs.org/core-object/-/core-object-3.1.5.tgz#fa627b87502adc98045e44678e9a8ec3b9c0d2a9" dependencies: chalk "^2.0.0" core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" create-error-class@^3.0.0: version "3.0.2" - resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" + resolved "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" dependencies: capture-stack-trace "^1.0.0" -cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" dependencies: nice-try "^1.0.4" path-key "^2.0.1" @@ -3020,7 +2915,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: cryptiles@0.2.x: version "0.2.2" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" + resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" dependencies: boom "0.4.x" @@ -3032,27 +2927,27 @@ cryptiles@2.x.x: crypto-random-string@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" ctype@0.5.3: version "0.5.3" - resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" + resolved "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" currently-unhandled@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + resolved "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" dependencies: array-find-index "^1.0.1" d@1: version "1.0.0" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + resolved "https://registry.npmjs.org/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" dependencies: es5-ext "^0.10.9" dag-map@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" + resolved "https://registry.npmjs.org/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" dashdash@^1.12.0: version "1.14.1" @@ -3062,113 +2957,106 @@ dashdash@^1.12.0: date-time@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/date-time/-/date-time-2.1.0.tgz#0286d1b4c769633b3ca13e1e62558d2dbdc2eba2" + resolved "https://registry.npmjs.org/date-time/-/date-time-2.1.0.tgz#0286d1b4c769633b3ca13e1e62558d2dbdc2eba2" dependencies: time-zone "^1.0.0" -debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: +debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: ms "2.0.0" -debug@3.1.0, debug@^3.0.0, debug@^3.1.0, debug@~3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" +debug@3.2.6, debug@^3.1.0, debug@^3.2.6: + version "3.2.6" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" dependencies: - ms "2.0.0" + ms "^2.1.1" -debug@^4.0.1, debug@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" +debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@~4.1.0: + version "4.1.1" + resolved "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" dependencies: ms "^2.1.1" +debug@~3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + debuglog@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" -decamelize@^1.1.2: +decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" decode-uri-component@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" decompress-response@^3.3.0: version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" dependencies: mimic-response "^1.0.0" deep-eql@^0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" + resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" dependencies: type-detect "0.1.1" -deep-eql@^3.0.0: +deep-eql@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" dependencies: type-detect "^4.0.0" deep-extend@^0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" deep-is@~0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" defaults@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" dependencies: clone "^1.0.2" define-properties@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + version "1.1.3" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" dependencies: - foreach "^2.0.5" - object-keys "^1.0.8" + object-keys "^1.0.12" define-property@^0.2.5: version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" dependencies: is-descriptor "^1.0.0" define-property@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + resolved "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" dependencies: is-descriptor "^1.0.2" isobject "^3.0.1" -del@^2.0.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" - dependencies: - globby "^5.0.0" - is-path-cwd "^1.0.0" - is-path-in-cwd "^1.0.0" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" - rimraf "^2.2.8" - delayed-stream@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" delayed-stream@~1.0.0: version "1.0.0" @@ -3176,37 +3064,29 @@ delayed-stream@~1.0.0: delegates@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" -depd@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" - -depd@~1.1.1, depd@~1.1.2: +depd@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" destroy@~1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" detect-file@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + resolved "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" detect-indent@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" dependencies: repeating "^2.0.0" detect-indent@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" - -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" dezalgo@^1.0.0, dezalgo@^1.0.1, dezalgo@^1.0.2, dezalgo@~1.0.3: version "1.0.3" @@ -3219,25 +3099,25 @@ diff@3.5.0, diff@^3.5.0: version "3.5.0" resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" dependencies: esutils "^2.0.2" dot-prop@^4.1.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" dependencies: is-obj "^1.0.0" duplex@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/duplex/-/duplex-1.0.0.tgz#6abc5c16ec17e4c578578727126700590d3a2dda" + resolved "https://registry.npmjs.org/duplex/-/duplex-1.0.0.tgz#6abc5c16ec17e4c578578727126700590d3a2dda" duplexer3@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" ecc-jsbn@~0.1.1: version "0.1.2" @@ -3248,7 +3128,7 @@ ecc-jsbn@~0.1.1: editions@^1.1.1: version "1.3.4" - resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" + resolved "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" editor@~1.0.0: version "1.0.0" @@ -3256,27 +3136,22 @@ editor@~1.0.0: ee-first@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - -electron-to-chromium@^1.3.47: - version "1.3.52" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.52.tgz#d2d9f1270ba4a3b967b831c40ef71fb4d9ab5ce0" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" -electron-to-chromium@^1.3.81: - version "1.3.82" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.82.tgz#7d13ae4437d2a783de3f4efba96b186c540b67b1" +electron-to-chromium@^1.3.103, electron-to-chromium@^1.3.47: + version "1.3.113" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.113.tgz#b1ccf619df7295aea17bc6951dc689632629e4a9" ember-assign-polyfill@^2.6.0: version "2.6.0" - resolved "https://registry.yarnpkg.com/ember-assign-polyfill/-/ember-assign-polyfill-2.6.0.tgz#07847e3357ee35b33f886a0b5fbec6873f6860eb" - integrity sha512-Y8NzOmHI/g4PuJ+xC14eTYiQbigNYddyHB8FY2kuQMxThTEIDE7SJtgttJrYYcPciOu0Tnb5ff36iO46LeiXkw== + resolved "https://registry.npmjs.org/ember-assign-polyfill/-/ember-assign-polyfill-2.6.0.tgz#07847e3357ee35b33f886a0b5fbec6873f6860eb" dependencies: ember-cli-babel "^6.16.0" ember-cli-version-checker "^2.0.0" ember-cli-app-version@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/ember-cli-app-version/-/ember-cli-app-version-3.2.0.tgz#7b9ad0e1b63ae0518648356ee24c703e922bc26e" + resolved "https://registry.npmjs.org/ember-cli-app-version/-/ember-cli-app-version-3.2.0.tgz#7b9ad0e1b63ae0518648356ee24c703e922bc26e" dependencies: ember-cli-babel "^6.12.0" git-repo-version "^1.0.2" @@ -3286,16 +3161,16 @@ ember-cli-babel-plugin-helpers@^1.0.0: resolved "https://registry.npmjs.org/ember-cli-babel-plugin-helpers/-/ember-cli-babel-plugin-helpers-1.0.2.tgz#d4bec0f32febc530e621ea8d66d3365727cb5e6c" ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.9.0: - version "6.16.0" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.16.0.tgz#623b4a2764ece72b65f1572fc8aeb5714a450228" + version "6.18.0" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.18.0.tgz#3f6435fd275172edeff2b634ee7b29ce74318957" dependencies: amd-name-resolver "1.2.0" babel-plugin-debug-macros "^0.2.0-beta.6" - babel-plugin-ember-modules-api-polyfill "^2.3.2" + babel-plugin-ember-modules-api-polyfill "^2.6.0" babel-plugin-transform-es2015-modules-amd "^6.24.0" babel-polyfill "^6.26.0" babel-preset-env "^1.7.0" - broccoli-babel-transpiler "^6.4.5" + broccoli-babel-transpiler "^6.5.0" broccoli-debug "^0.6.4" broccoli-funnel "^2.0.0" broccoli-source "^1.1.0" @@ -3303,10 +3178,9 @@ ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6 ember-cli-version-checker "^2.1.2" semver "^5.5.0" -ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4, ember-cli-babel@^7.2.0, ember-cli-babel@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.4.1.tgz#9892f5883f5a6b1f0f86fb1331fc491338f372ad" - integrity sha512-h6qZKHyULm5SYhvjNOeXvLl3kHaBdh37g5QqTTiC/vMiWP/xnyNp2bMoq52qq+SLm/bE8+5UcVTKjrNl0+IqXA== +ember-cli-babel@^7.0.0, ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4, ember-cli-babel@^7.2.0, ember-cli-babel@^7.4.2: + version "7.4.3" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-7.4.3.tgz#1ff35ffd54c6206d72635686f4e5bb1674c9eae5" dependencies: "@babel/core" "^7.0.0" "@babel/plugin-transform-modules-amd" "^7.0.0" @@ -3315,10 +3189,10 @@ ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4, ember-cli-babel@^7.2.0, ember-cl "@babel/preset-env" "^7.0.0" "@babel/runtime" "^7.2.0" amd-name-resolver "^1.2.1" - babel-plugin-debug-macros "^0.2.0-beta.6" + babel-plugin-debug-macros "^0.3.0" babel-plugin-ember-modules-api-polyfill "^2.6.0" babel-plugin-module-resolver "^3.1.1" - broccoli-babel-transpiler "^7.1.0" + broccoli-babel-transpiler "^7.1.2" broccoli-debug "^0.6.4" broccoli-funnel "^2.0.1" broccoli-source "^1.1.0" @@ -3328,32 +3202,31 @@ ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4, ember-cli-babel@^7.2.0, ember-cl semver "^5.5.0" ember-cli-blueprint-test-helpers@^0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.19.1.tgz#26df9724a6cb48f7acfa391dec7ec772888b0929" + version "0.19.2" + resolved "https://registry.npmjs.org/ember-cli-blueprint-test-helpers/-/ember-cli-blueprint-test-helpers-0.19.2.tgz#9e563cd81ab39931253ced0982c5d02475895401" dependencies: chai "^4.1.0" chai-as-promised "^7.0.0" chai-files "^1.0.0" - debug "^3.0.0" + debug "^4.1.0" ember-cli-internal-test-helpers "^0.9.1" - fs-extra "^5.0.0" + fs-extra "^7.0.0" testdouble "^3.2.6" tmp-sync "^1.0.0" -ember-cli-broccoli-sane-watcher@^2.1.1: - version "2.2.2" - resolved "https://registry.npmjs.org/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-2.2.2.tgz#9bb1b04ddeb2c086aecd8693cbaeca1d88dc160c" +ember-cli-broccoli-sane-watcher@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/ember-cli-broccoli-sane-watcher/-/ember-cli-broccoli-sane-watcher-3.0.0.tgz#dc1812c047e1ceec4413d3c41b51a9ffc61b4cfe" dependencies: broccoli-slow-trees "^3.0.1" heimdalljs "^0.2.1" heimdalljs-logger "^0.1.7" rsvp "^3.0.18" - sane "^2.4.1" + sane "^4.0.0" ember-cli-dependency-checker@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/ember-cli-dependency-checker/-/ember-cli-dependency-checker-3.1.0.tgz#b39c6b537a1457d77892edf5ddcfa025cd1401e2" - integrity sha512-Y/V2senOyIjQnZohYeZeXs59rWHI2m8KRF9IesMv1ypLRSc/h/QS6UX51wAyaZnxcgU6ljFXpqL5x38UxM3XzA== + resolved "https://registry.npmjs.org/ember-cli-dependency-checker/-/ember-cli-dependency-checker-3.1.0.tgz#b39c6b537a1457d77892edf5ddcfa025cd1401e2" dependencies: chalk "^2.3.0" find-yarn-workspace-root "^1.1.0" @@ -3363,23 +3236,11 @@ ember-cli-dependency-checker@^3.1.0: ember-cli-get-component-path-option@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" - -ember-cli-htmlbars-inline-precompile@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-2.0.0.tgz#8cbc941370ac6e728ae3d49c4164b3c7131d6118" - integrity sha512-oqqmT31ZG+md5UgCsumFulGXZvC3SbHnhLZ24uc5vKQuzA1c5cZmbOxb+1CnqLIovPCbcJWE3pL9kUMHiBh5oQ== - dependencies: - babel-plugin-htmlbars-inline-precompile "^1.0.0" - ember-cli-version-checker "^2.1.2" - hash-for-dep "^1.2.3" - heimdalljs-logger "^0.1.9" - silent-error "^1.1.0" + resolved "https://registry.npmjs.org/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" -ember-cli-htmlbars-inline-precompile@^2.1.0: +ember-cli-htmlbars-inline-precompile@^2.0.0, ember-cli-htmlbars-inline-precompile@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-2.1.0.tgz#61b91ff1879d44ae504cadb46fb1f2604995ae08" - integrity sha512-BylIHduwQkncPhnj0ZyorBuljXbTzLgRo6kuHf1W+IHFxThFl2xG+r87BVwsqx4Mn9MTgW9SE0XWjwBJcSWd6Q== + resolved "https://registry.npmjs.org/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-2.1.0.tgz#61b91ff1879d44ae504cadb46fb1f2604995ae08" dependencies: babel-plugin-htmlbars-inline-precompile "^1.0.0" ember-cli-version-checker "^2.1.2" @@ -3405,7 +3266,7 @@ ember-cli-inject-live-reload@^2.0.1: ember-cli-internal-test-helpers@^0.9.1: version "0.9.1" - resolved "https://registry.yarnpkg.com/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.9.1.tgz#d54a9124bb6408ceba83f049ba8479f4b96cdd19" + resolved "https://registry.npmjs.org/ember-cli-internal-test-helpers/-/ember-cli-internal-test-helpers-0.9.1.tgz#d54a9124bb6408ceba83f049ba8479f4b96cdd19" dependencies: chai "^3.3.0" chai-as-promised "^6.0.0" @@ -3422,25 +3283,25 @@ ember-cli-internal-test-helpers@^0.9.1: ember-cli-is-package-missing@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" + resolved "https://registry.npmjs.org/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" ember-cli-lodash-subset@^1.0.7: version "1.0.12" - resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" + resolved "https://registry.npmjs.org/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" ember-cli-lodash-subset@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-2.0.1.tgz#20cb68a790fe0fde2488ddfd8efbb7df6fe766f2" + resolved "https://registry.npmjs.org/ember-cli-lodash-subset/-/ember-cli-lodash-subset-2.0.1.tgz#20cb68a790fe0fde2488ddfd8efbb7df6fe766f2" ember-cli-normalize-entity-name@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" + resolved "https://registry.npmjs.org/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" dependencies: silent-error "^1.0.0" ember-cli-path-utils@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" + resolved "https://registry.npmjs.org/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" ember-cli-preprocess-registry@^3.1.2: version "3.1.2" @@ -3456,8 +3317,7 @@ ember-cli-preprocess-registry@^3.1.2: ember-cli-pretender@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-pretender/-/ember-cli-pretender-3.1.1.tgz#289c41683de266fec8bfaf5b7b7f6026aaefc8cf" - integrity sha512-RGGj9la0138bgHUxyaGDHCZydmdpW+BFN9v0vMBzNPeXsaexCZotaFTIZDCNcKWPx8jtRHR8AXf318VRGXLJsw== + resolved "https://registry.npmjs.org/ember-cli-pretender/-/ember-cli-pretender-3.1.1.tgz#289c41683de266fec8bfaf5b7b7f6026aaefc8cf" dependencies: abortcontroller-polyfill "^1.1.9" broccoli-funnel "^2.0.1" @@ -3486,7 +3346,7 @@ ember-cli-release@^1.0.0-beta.2: ember-cli-shims@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/ember-cli-shims/-/ember-cli-shims-1.2.0.tgz#0f53aff0aab80b5f29da3a9731bac56169dd941f" + resolved "https://registry.npmjs.org/ember-cli-shims/-/ember-cli-shims-1.2.0.tgz#0f53aff0aab80b5f29da3a9731bac56169dd941f" dependencies: broccoli-file-creator "^1.1.1" broccoli-merge-trees "^2.0.0" @@ -3496,29 +3356,29 @@ ember-cli-shims@^1.2.0: ember-cli-sri@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" + resolved "https://registry.npmjs.org/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" dependencies: broccoli-sri-hash "^2.1.0" ember-cli-string-utils@^1.0.0, ember-cli-string-utils@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" + resolved "https://registry.npmjs.org/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" ember-cli-test-info@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" + resolved "https://registry.npmjs.org/ember-cli-test-info/-/ember-cli-test-info-1.0.0.tgz#ed4e960f249e97523cf891e4aed2072ce84577b4" dependencies: ember-cli-string-utils "^1.0.0" ember-cli-test-loader@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/ember-cli-test-loader/-/ember-cli-test-loader-2.2.0.tgz#3fb8d5d1357e4460d3f0a092f5375e71b6f7c243" + resolved "https://registry.npmjs.org/ember-cli-test-loader/-/ember-cli-test-loader-2.2.0.tgz#3fb8d5d1357e4460d3f0a092f5375e71b6f7c243" dependencies: ember-cli-babel "^6.8.1" ember-cli-typescript-blueprints@^2.0.0-beta.1: version "2.0.0-beta.1" - resolved "https://registry.yarnpkg.com/ember-cli-typescript-blueprints/-/ember-cli-typescript-blueprints-2.0.0-beta.1.tgz#2db2e34ad01b5a50a4459c2f7cfc8f132b21fcea" + resolved "https://registry.npmjs.org/ember-cli-typescript-blueprints/-/ember-cli-typescript-blueprints-2.0.0-beta.1.tgz#2db2e34ad01b5a50a4459c2f7cfc8f132b21fcea" dependencies: chalk "^2.4.1" ember-cli-babel "^6.6.0" @@ -3537,53 +3397,52 @@ ember-cli-typescript-blueprints@^2.0.0-beta.1: silent-error "^1.1.0" ember-cli-typescript@^2.0.0-beta.2: - version "2.0.0-beta.2" - resolved "https://registry.yarnpkg.com/ember-cli-typescript/-/ember-cli-typescript-2.0.0-beta.2.tgz#29bd0a7eff45b54e01d2cbc2fba05b3991a9c0d3" + version "2.0.0-rc.2" + resolved "https://registry.npmjs.org/ember-cli-typescript/-/ember-cli-typescript-2.0.0-rc.2.tgz#d8253097279ed292c20e739ee72f8fb994dbb6b7" dependencies: "@babel/plugin-proposal-class-properties" "^7.1.0" "@babel/plugin-transform-typescript" "^7.1.0" ansi-to-html "^0.6.6" - debug "^3.1.0" + debug "^4.0.0" ember-cli-babel-plugin-helpers "^1.0.0" - execa "^0.9.0" - fs-extra "^5.0.0" + execa "^1.0.0" + fs-extra "^7.0.0" resolve "^1.5.0" rsvp "^4.8.1" semver "^5.5.1" stagehand "^1.0.0" - walk-sync "^0.3.2" + walk-sync "^1.0.0" ember-cli-uglify@2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/ember-cli-uglify/-/ember-cli-uglify-2.1.0.tgz#4a0641fe4768d7ab7d4807aca9924cc77c544184" + resolved "https://registry.npmjs.org/ember-cli-uglify/-/ember-cli-uglify-2.1.0.tgz#4a0641fe4768d7ab7d4807aca9924cc77c544184" dependencies: broccoli-uglify-sourcemap "^2.1.1" lodash.defaultsdeep "^4.6.0" ember-cli-valid-component-name@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" + resolved "https://registry.npmjs.org/ember-cli-valid-component-name/-/ember-cli-valid-component-name-1.0.0.tgz#71550ce387e0233065f30b30b1510aa2dfbe87ef" dependencies: silent-error "^1.0.0" ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-version-checker@^2.1.1, ember-cli-version-checker@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.1.2.tgz#305ce102390c66e4e0f1432dea9dc5c7c19fed98" + version "2.2.0" + resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-2.2.0.tgz#47771b731fe0962705e27c8199a9e3825709f3b3" dependencies: resolve "^1.3.3" semver "^5.3.0" ember-cli-version-checker@^3.0.0, ember-cli-version-checker@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-3.0.1.tgz#2d084d2b261374582c68edb658a7df3a10112749" - integrity sha512-hX2tGrFVt8PyaiWclZr8XFNUPSnA+Ax4bMifDIVVtYY8RQZG8LZf9AGyTj4XImkBBWBtgKyOeQ0ovg3kgos4JA== + resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-3.0.1.tgz#2d084d2b261374582c68edb658a7df3a10112749" dependencies: resolve "^1.9.0" semver "^5.6.0" ember-cli-yuidoc@^0.8.8: version "0.8.8" - resolved "https://registry.yarnpkg.com/ember-cli-yuidoc/-/ember-cli-yuidoc-0.8.8.tgz#3858baaf85388a976024f9de40f1075fea58f606" + resolved "https://registry.npmjs.org/ember-cli-yuidoc/-/ember-cli-yuidoc-0.8.8.tgz#3858baaf85388a976024f9de40f1075fea58f606" dependencies: broccoli-caching-writer "~2.0.4" broccoli-merge-trees "^1.1.1" @@ -3592,19 +3451,19 @@ ember-cli-yuidoc@^0.8.8: yuidocjs "^0.10.0" ember-cli@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-3.5.1.tgz#a1c7295eed935726891d40a81e0cc389f2d15fdf" - integrity sha512-oJylJwBIIH5IdgrnSXjA/Z64SSu7gZMyqtMBfMA8aGcBh2Bcb5dMDHpwwWXV4Crp1TGImhdtbwOtMAkzZT6Qpw== + version "3.7.1" + resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-3.7.1.tgz#f307bcd68aaf083612717ab32133120272d89170" dependencies: - amd-name-resolver "^1.2.0" - babel-plugin-transform-es2015-modules-amd "^6.24.1" + "@babel/plugin-transform-modules-amd" "^7.2.0" + amd-name-resolver "^1.3.1" + babel-plugin-module-resolver "^3.1.1" bower-config "^1.3.0" bower-endpoint-parser "0.2.2" broccoli "^2.0.0" broccoli-amd-funnel "^2.0.1" - broccoli-babel-transpiler "^6.5.0" + broccoli-babel-transpiler "^7.1.1" broccoli-builder "^0.18.14" - broccoli-concat "^3.5.1" + broccoli-concat "^3.7.3" broccoli-config-loader "^1.0.1" broccoli-config-replace "^1.1.2" broccoli-debug "^0.6.4" @@ -3619,7 +3478,7 @@ ember-cli@^3.5.1: calculate-cache-key-for-tree "^1.1.0" capture-exit "^1.2.0" chalk "^2.4.1" - ci-info "^1.1.3" + ci-info "^2.0.0" clean-base-url "^1.0.0" compression "^1.7.3" configstore "^4.0.0" @@ -3627,14 +3486,14 @@ ember-cli@^3.5.1: core-object "^3.1.5" dag-map "^2.0.2" diff "^3.5.0" - ember-cli-broccoli-sane-watcher "^2.1.1" + ember-cli-broccoli-sane-watcher "^3.0.0" ember-cli-is-package-missing "^1.0.0" ember-cli-lodash-subset "^2.0.1" ember-cli-normalize-entity-name "^1.0.0" ember-cli-preprocess-registry "^3.1.2" ember-cli-string-utils "^1.1.0" ensure-posix-path "^1.0.2" - execa "^0.10.0" + execa "^1.0.0" exit "^0.1.2" express "^4.16.3" filesize "^3.6.1" @@ -3643,8 +3502,8 @@ ember-cli@^3.5.1: fixturify "^0.3.4" fixturify-project "^1.5.3" fs-extra "^7.0.0" - fs-tree-diff "^0.5.7" - get-caller-file "^1.0.0" + fs-tree-diff "^1.0.0" + get-caller-file "^2.0.0" git-repo-info "^2.0.0" glob "^7.1.2" heimdalljs "^0.2.5" @@ -3682,56 +3541,55 @@ ember-cli@^3.5.1: tree-sync "^1.2.2" uuid "^3.3.2" validate-npm-package-name "^3.0.0" - walk-sync "^0.3.2" + walk-sync "^1.0.0" watch-detector "^0.1.0" - yam "^0.0.24" + yam "^1.0.0" ember-compatibility-helpers@^1.1.1, ember-compatibility-helpers@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/ember-compatibility-helpers/-/ember-compatibility-helpers-1.1.2.tgz#ae0ee4a7a2858b5ffdf79b428c23aee85c47d93d" + version "1.2.0" + resolved "https://registry.npmjs.org/ember-compatibility-helpers/-/ember-compatibility-helpers-1.2.0.tgz#feee16c5e9ef1b1f1e53903b241740ad4b01097e" dependencies: babel-plugin-debug-macros "^0.2.0" ember-cli-version-checker "^2.1.1" semver "^5.4.1" ember-decorators@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/ember-decorators/-/ember-decorators-5.1.2.tgz#e4fc1b029a03e3f09fb6ae24ac4e6cf4177e4378" - integrity sha512-Vc99rlNWFY6VJEn1mtxVytLxb+vu31IKzPw4qqbG+ypynbKNEH7a5U44hxp0BH5S5Fl4U03tnyEIDc7K/rZ6kQ== - dependencies: - "@ember-decorators/component" "^5.1.2" - "@ember-decorators/controller" "^5.1.2" - "@ember-decorators/data" "^5.1.2" - "@ember-decorators/object" "^5.1.2" - "@ember-decorators/service" "^5.1.2" + version "5.1.3" + resolved "https://registry.npmjs.org/ember-decorators/-/ember-decorators-5.1.3.tgz#dafcca32e7acaa68ddb88420f6cd8e78a9edc35a" + dependencies: + "@ember-decorators/component" "^5.1.3" + "@ember-decorators/controller" "^5.1.3" + "@ember-decorators/data" "^5.1.3" + "@ember-decorators/object" "^5.1.3" + "@ember-decorators/service" "^5.1.3" ember-cli-babel "^7.1.3" semver "^5.5.0" ember-disable-prototype-extensions@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" + resolved "https://registry.npmjs.org/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" ember-export-application-global@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ember-export-application-global/-/ember-export-application-global-2.0.0.tgz#8d6d7619ac8a1a3f8c43003549eb21ebed685bd2" + resolved "https://registry.npmjs.org/ember-export-application-global/-/ember-export-application-global-2.0.0.tgz#8d6d7619ac8a1a3f8c43003549eb21ebed685bd2" dependencies: ember-cli-babel "^6.0.0-beta.7" ember-inflector@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/ember-inflector/-/ember-inflector-3.0.0.tgz#7e1ee8aaa0fa773ba0905d8b7c0786354d890ee1" + resolved "https://registry.npmjs.org/ember-inflector/-/ember-inflector-3.0.0.tgz#7e1ee8aaa0fa773ba0905d8b7c0786354d890ee1" dependencies: ember-cli-babel "^6.6.0" -ember-load-initializers@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/ember-load-initializers/-/ember-load-initializers-1.1.0.tgz#4edacc0f3a14d9f53d241ac3e5561804c8377978" +ember-load-initializers@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ember-load-initializers/-/ember-load-initializers-2.0.0.tgz#d4b3108dd14edb0f9dc3735553cc96dadd8a80cb" dependencies: - ember-cli-babel "^6.6.0" + ember-cli-babel "^7.0.0" ember-maybe-import-regenerator@^0.1.6: version "0.1.6" - resolved "https://registry.yarnpkg.com/ember-maybe-import-regenerator/-/ember-maybe-import-regenerator-0.1.6.tgz#35d41828afa6d6a59bc0da3ce47f34c573d776ca" + resolved "https://registry.npmjs.org/ember-maybe-import-regenerator/-/ember-maybe-import-regenerator-0.1.6.tgz#35d41828afa6d6a59bc0da3ce47f34c573d776ca" dependencies: broccoli-funnel "^1.0.1" broccoli-merge-trees "^1.0.0" @@ -3739,67 +3597,60 @@ ember-maybe-import-regenerator@^0.1.6: regenerator-runtime "^0.9.5" ember-qunit-assert-helpers@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/ember-qunit-assert-helpers/-/ember-qunit-assert-helpers-0.2.1.tgz#4a77f8ff252e47cc53db6fa7fb4becb426de8d29" + version "0.2.2" + resolved "https://registry.npmjs.org/ember-qunit-assert-helpers/-/ember-qunit-assert-helpers-0.2.2.tgz#6fec8a33fd0d2c3fb6202f849291a309581727a4" dependencies: broccoli-filter "^1.0.1" ember-cli-babel "^6.9.0" ember-qunit@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-4.2.0.tgz#376bf2eb6340f492e9cf9b5cb55b7dd74e8de600" - integrity sha512-bsyc8vx8MFkfExsD4i3aLuffns8Yb/qtfA2C+Ghwy/6HYPujcxR/PcZ1j9ZzbCIvO8Fr2oxykZU3rWbVHE6EhA== + version "4.4.0" + resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-4.4.0.tgz#813d7b1febc5a35b86db64c4a54ea5bf91a5fbf0" dependencies: - "@ember/test-helpers" "^1.1.0" - broccoli-funnel "^2.0.1" + "@ember/test-helpers" "^1.3.2" + broccoli-funnel "^2.0.2" broccoli-merge-trees "^3.0.2" common-tags "^1.4.0" - ember-cli-babel "^7.2.0" + ember-cli-babel "^7.4.2" ember-cli-test-loader "^2.2.0" - qunit "^2.8.0" + qunit "^2.9.1" ember-resolver@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-5.0.1.tgz#21740b92e1e4a65f94018de22aa1c73434dc3b2f" + version "5.1.1" + resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-5.1.1.tgz#ffc2b12e9a50b56f9f48f8c239b10d00a142dc42" dependencies: "@glimmer/resolver" "^0.4.1" babel-plugin-debug-macros "^0.1.10" - broccoli-funnel "^2.0.1" + broccoli-funnel "^2.0.2" broccoli-merge-trees "^3.0.0" - ember-cli-babel "^6.8.1" - ember-cli-version-checker "^2.0.0" - resolve "^1.3.3" - -ember-rfc176-data@^0.3.0, ember-rfc176-data@^0.3.1: - version "0.3.3" - resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.3.tgz#27fba08d540a7463a4366c48eaa19c5a44971a39" + ember-cli-babel "^6.16.0" + ember-cli-version-checker "^3.0.0" + resolve "^1.10.0" -ember-rfc176-data@^0.3.6: +ember-rfc176-data@^0.3.1, ember-rfc176-data@^0.3.6: version "0.3.6" - resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.6.tgz#7138db8dfccec39c9a832adfbd4c49d670028907" - integrity sha512-kPY94VCukPUPj+/6sZ9KvphD42KnpX2IS31p5z07OFVIviDogR0cQuld5c7Irzfgq7a0YACj0HlToROFn7dLYQ== + resolved "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.3.6.tgz#7138db8dfccec39c9a832adfbd4c49d670028907" ember-router-generator@^1.2.3: version "1.2.3" - resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" + resolved "https://registry.npmjs.org/ember-router-generator/-/ember-router-generator-1.2.3.tgz#8ed2ca86ff323363120fc14278191e9e8f1315ee" dependencies: recast "^0.11.3" ember-source-channel-url@^1.0.1, ember-source-channel-url@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/ember-source-channel-url/-/ember-source-channel-url-1.1.0.tgz#73de5cc6ebc25b2120e932ec1d8f82677bfaf6ef" + resolved "https://registry.npmjs.org/ember-source-channel-url/-/ember-source-channel-url-1.1.0.tgz#73de5cc6ebc25b2120e932ec1d8f82677bfaf6ef" dependencies: got "^8.0.1" -ember-source@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-3.6.0.tgz#0229b4fe6802dcfadb81e27ebcf50fff166889ec" - integrity sha512-Es6BE/lYxwiLPHZpFOcl2tQaOppvabIffQfcOJR9OzdM8ZgM06UR+tqdxrhO05UmD8MqHGc1FT/RmQlKuGZg0Q== +ember-source@~3.8.0: + version "3.8.0" + resolved "https://registry.npmjs.org/ember-source/-/ember-source-3.8.0.tgz#b84ba995d5049514a146c6df20c2fe20de08f211" dependencies: broccoli-funnel "^2.0.1" - broccoli-merge-trees "^2.0.0" + broccoli-merge-trees "^3.0.2" chalk "^2.3.0" - ember-cli-babel "^7.1.3" + ember-cli-babel "^7.2.0" ember-cli-get-component-path-option "^1.0.0" ember-cli-is-package-missing "^1.0.0" ember-cli-normalize-entity-name "^1.0.0" @@ -3809,11 +3660,11 @@ ember-source@~3.6.0: ember-router-generator "^1.2.3" inflection "^1.12.0" jquery "^3.3.1" - resolve "^1.6.0" + resolve "^1.9.0" ember-try-config@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/ember-try-config/-/ember-try-config-3.0.0.tgz#012d8c90cae9eb624e2b62040bf7e76a1aa58edc" + resolved "https://registry.npmjs.org/ember-try-config/-/ember-try-config-3.0.0.tgz#012d8c90cae9eb624e2b62040bf7e76a1aa58edc" dependencies: ember-source-channel-url "^1.0.1" lodash "^4.6.1" @@ -3842,11 +3693,15 @@ ember-try@^1.1.0: emit-function@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/emit-function/-/emit-function-0.0.2.tgz#e3a50b3d61be1bf8ca88b924bf713157a5bec124" + resolved "https://registry.npmjs.org/emit-function/-/emit-function-0.0.2.tgz#e3a50b3d61be1bf8ca88b924bf713157a5bec124" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" encodeurl@~1.0.1, encodeurl@~1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" end-of-stream@^1.1.0: version "1.4.1" @@ -3854,9 +3709,9 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" -engine.io-client@~3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" +engine.io-client@~3.3.1: + version "3.3.2" + resolved "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.3.2.tgz#04e068798d75beda14375a264bb3d742d7bc33aa" dependencies: component-emitter "1.2.1" component-inherit "0.0.3" @@ -3866,143 +3721,118 @@ engine.io-client@~3.2.0: indexof "0.0.1" parseqs "0.0.5" parseuri "0.0.5" - ws "~3.3.1" + ws "~6.1.0" xmlhttprequest-ssl "~1.5.4" yeast "0.1.2" engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196" + version "2.1.3" + resolved "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" dependencies: after "0.8.2" arraybuffer.slice "~0.0.7" base64-arraybuffer "0.1.5" - blob "0.0.4" + blob "0.0.5" has-binary2 "~1.0.2" -engine.io@~3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.0.tgz#54332506f42f2edc71690d2f2a42349359f3bf7d" +engine.io@~3.3.1: + version "3.3.2" + resolved "https://registry.npmjs.org/engine.io/-/engine.io-3.3.2.tgz#18cbc8b6f36e9461c5c0f81df2b830de16058a59" dependencies: accepts "~1.3.4" base64id "1.0.0" cookie "0.3.1" debug "~3.1.0" engine.io-parser "~2.1.0" - ws "~3.3.1" - -ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz#a65b3e42d0b71cfc585eb774f9943c8d9b91b0c2" - -entities@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + ws "~6.1.0" -entities@~1.1.1: +ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2, ensure-posix-path@^1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + resolved "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.1.1.tgz#3c62bdb19fa4681544289edb2b382adc029179ce" + +entities@^1.1.1, entities@~1.1.1: + version "1.1.2" + resolved "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" error-ex@^1.2.0: version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" dependencies: is-arrayish "^0.2.1" error@^7.0.0: version "7.0.2" - resolved "https://registry.yarnpkg.com/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" + resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" dependencies: string-template "~0.2.1" xtend "~4.0.0" -es-abstract@^1.9.0: - version "1.12.0" - resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" +es-abstract@^1.5.1, es-abstract@^1.9.0: + version "1.13.0" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" dependencies: - es-to-primitive "^1.1.1" + es-to-primitive "^1.2.0" function-bind "^1.1.1" - has "^1.0.1" - is-callable "^1.1.3" + has "^1.0.3" + is-callable "^1.1.4" is-regex "^1.0.4" + object-keys "^1.0.12" -es-to-primitive@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" +es-to-primitive@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" dependencies: - is-callable "^1.1.1" + is-callable "^1.1.4" is-date-object "^1.0.1" - is-symbol "^1.0.1" + is-symbol "^1.0.2" es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.45" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.45.tgz#0bfdf7b473da5919d5adf3bd25ceb754fccc3653" + version "0.10.47" + resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.47.tgz#d24232e1380daad5449a817be19bde9729024a11" dependencies: es6-iterator "~2.0.3" es6-symbol "~3.1.1" next-tick "1" -es6-iterator@~2.0.1, es6-iterator@~2.0.3: +es6-iterator@~2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" dependencies: d "1" es5-ext "^0.10.35" es6-symbol "^3.1.1" -es6-map@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-set "~0.1.5" - es6-symbol "~3.1.1" - event-emitter "~0.3.5" - -es6-set@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-symbol "3.1.1" - event-emitter "~0.3.5" - -es6-symbol@3.1.1, es6-symbol@^3.0.2, es6-symbol@^3.1.1, es6-symbol@~3.1.1: +es6-symbol@^3.0.2, es6-symbol@^3.1.1, es6-symbol@~3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" dependencies: d "1" es5-ext "~0.10.14" escape-html@~1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -eslint-config-prettier@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-3.1.0.tgz#2c26d2cdcfa3a05f0642cd7e6e4ef3316cdabfa2" +eslint-config-prettier@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-4.0.0.tgz#16cedeea0a56e74de60dcbbe3be0ab2c645405b9" dependencies: get-stdin "^6.0.0" eslint-plugin-es@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-1.3.1.tgz#5acb2565db4434803d1d46a9b4cbc94b345bd028" + version "1.4.0" + resolved "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-1.4.0.tgz#475f65bb20c993fc10e8c8fe77d1d60068072da6" dependencies: eslint-utils "^1.3.0" - regexpp "^2.0.0" + regexpp "^2.0.1" eslint-plugin-node@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-8.0.0.tgz#fb9e8911f4543514f154bb6a5924b599aa645568" - integrity sha512-Y+ln8iQ52scz9+rSPnSWRaAxeWaoJZ4wIveDR0vLHkuSZGe44Vk1J4HX7WvEP5Cm+iXPE8ixo7OM7gAO3/OKpQ== + version "8.0.1" + resolved "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-8.0.1.tgz#55ae3560022863d141fa7a11799532340a685964" dependencies: eslint-plugin-es "^1.3.1" eslint-utils "^1.3.1" @@ -4013,147 +3843,136 @@ eslint-plugin-node@^8.0.0: eslint-plugin-prettier@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.1.tgz#19d521e3981f69dd6d14f64aec8c6a6ac6eb0b0d" - integrity sha512-/PMttrarPAY78PLvV3xfWibMOdMDl57hmlQ2XqFeA37wd+CJ7WSxV7txqjVPHi/AAFKd2lX0ZqfsOc/i5yFCSQ== + resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.1.tgz#19d521e3981f69dd6d14f64aec8c6a6ac6eb0b0d" dependencies: prettier-linter-helpers "^1.0.0" eslint-scope@3.7.1: version "3.7.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" eslint-scope@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" eslint-utils@^1.3.0, eslint-utils@^1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" + resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" eslint-visitor-keys@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" eslint@^5.10.0: - version "5.10.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.10.0.tgz#24adcbe92bf5eb1fc2d2f2b1eebe0c5e0713903a" - integrity sha512-HpqzC+BHULKlnPwWae9MaVZ5AXJKpkxCVXQHrFaRw3hbDj26V/9ArYM4Rr/SQ8pi6qUPLXSSXC4RBJlyq2Z2OQ== + version "5.14.1" + resolved "https://registry.npmjs.org/eslint/-/eslint-5.14.1.tgz#490a28906be313685c55ccd43a39e8d22efc04ba" dependencies: "@babel/code-frame" "^7.0.0" - ajv "^6.5.3" + ajv "^6.9.1" chalk "^2.1.0" cross-spawn "^6.0.5" debug "^4.0.1" - doctrine "^2.1.0" + doctrine "^3.0.0" eslint-scope "^4.0.0" eslint-utils "^1.3.1" eslint-visitor-keys "^1.0.0" - espree "^5.0.0" + espree "^5.0.1" esquery "^1.0.1" esutils "^2.0.2" - file-entry-cache "^2.0.0" + file-entry-cache "^5.0.1" functional-red-black-tree "^1.0.1" glob "^7.1.2" globals "^11.7.0" ignore "^4.0.6" + import-fresh "^3.0.0" imurmurhash "^0.1.4" - inquirer "^6.1.0" + inquirer "^6.2.2" js-yaml "^3.12.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" - lodash "^4.17.5" + lodash "^4.17.11" minimatch "^3.0.4" mkdirp "^0.5.1" natural-compare "^1.4.0" optionator "^0.8.2" path-is-inside "^1.0.2" - pluralize "^7.0.0" progress "^2.0.0" regexpp "^2.0.1" - require-uncached "^1.0.3" semver "^5.5.1" strip-ansi "^4.0.0" strip-json-comments "^2.0.1" - table "^5.0.2" + table "^5.2.3" text-table "^0.2.0" -espree@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.0.tgz#fc7f984b62b36a0f543b13fb9cd7b9f4a7f5b65c" - integrity sha512-1MpUfwsdS9MMoN7ZXqAr9e9UKdVHDcvrJpyx7mm1WuQlx/ygErEQBzgi5Nh5qBHIoYweprhtMkTCb9GhcAIcsA== +espree@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" dependencies: - acorn "^6.0.2" + acorn "^6.0.7" acorn-jsx "^5.0.0" eslint-visitor-keys "^1.0.0" esprima@^4.0.0: version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" esprima@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" + resolved "https://registry.npmjs.org/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" esprima@~3.1.0: version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + resolved "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" esprimaq@^0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" + resolved "https://registry.npmjs.org/esprimaq/-/esprimaq-0.0.1.tgz#3ea3a41f55ba0ab98fc3564c875818bd890aa2a3" esquery@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" dependencies: estraverse "^4.0.0" esrecurse@^4.1.0: version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" dependencies: estraverse "^4.1.0" estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" -estree-walker@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.5.2.tgz#d3850be7529c9580d815600b53126515e146dd39" +estree-walker@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.0.tgz#5d865327c44a618dde5699f763891ae31f257dae" esutils@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" etag@~1.8.1: version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - -event-emitter@~0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - dependencies: - d "1" - es5-ext "~0.10.14" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" eventemitter3@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" events-to-array@^1.0.1: version "1.1.2" - resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" + resolved "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" exec-file-sync@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/exec-file-sync/-/exec-file-sync-2.0.2.tgz#58d441db46e40de6d1f30de5be022785bd89e328" + resolved "https://registry.npmjs.org/exec-file-sync/-/exec-file-sync-2.0.2.tgz#58d441db46e40de6d1f30de5be022785bd89e328" dependencies: is-obj "^1.0.0" object-assign "^4.0.1" @@ -4161,33 +3980,13 @@ exec-file-sync@^2.0.0: exec-sh@^0.2.0: version "0.2.2" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" + resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" dependencies: merge "^1.2.0" -execa@^0.10.0: - version "0.10.0" - resolved "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" - dependencies: - cross-spawn "^6.0.0" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -execa@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.9.0.tgz#adb7ce62cf985071f60580deb4a88b9e34712d01" - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" +exec-sh@^0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz#6738de2eb7c8e671d0366aea0b0db8c6f7d7391b" execa@^1.0.0: version "1.0.0" @@ -4203,33 +4002,27 @@ execa@^1.0.0: exists-sync@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" + resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.3.tgz#b910000bedbb113b378b82f5f5a7638107622dcf" exists-sync@0.0.4: version "0.0.4" - resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" + resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" exists-sync@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.1.0.tgz#318d545213d2b2a31499e92c35f74c94196a22f7" + resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.1.0.tgz#318d545213d2b2a31499e92c35f74c94196a22f7" exit-hook@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" exit@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - dependencies: - is-posix-bracket "^0.1.0" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" expand-brackets@^2.1.4: version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" dependencies: debug "^2.3.3" define-property "^0.2.5" @@ -4239,54 +4032,13 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - dependencies: - fill-range "^2.1.0" - expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" dependencies: homedir-polyfill "^1.0.1" -express@^4.10.7, express@^4.13.1: - version "4.16.3" - resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" - dependencies: - accepts "~1.3.5" - array-flatten "1.1.1" - body-parser "1.18.2" - content-disposition "0.5.2" - content-type "~1.0.4" - cookie "0.3.1" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.1.1" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.2" - path-to-regexp "0.1.7" - proxy-addr "~2.0.3" - qs "6.5.1" - range-parser "~1.2.0" - safe-buffer "5.1.1" - send "0.16.2" - serve-static "1.13.2" - setprototypeof "1.1.0" - statuses "~1.4.0" - type-is "~1.6.16" - utils-merge "1.0.1" - vary "~1.1.2" - -express@^4.16.3: +express@^4.10.7, express@^4.13.1, express@^4.16.3: version "4.16.4" resolved "https://registry.npmjs.org/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" dependencies: @@ -4323,30 +4075,30 @@ express@^4.16.3: extend-shallow@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" dependencies: assign-symbols "^1.0.0" is-extendable "^1.0.1" extend@^3.0.0, extend@~3.0.0, extend@~3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" external-editor@^1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" + resolved "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" dependencies: extend "^3.0.0" spawn-sync "^1.0.15" tmp "^0.0.29" -external-editor@^3.0.0: +external-editor@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" dependencies: @@ -4354,15 +4106,9 @@ external-editor@^3.0.0: iconv-lite "^0.4.24" tmp "^0.0.33" -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - dependencies: - is-extglob "^1.0.0" - extglob@^2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + resolved "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" dependencies: array-unique "^0.3.2" define-property "^1.0.0" @@ -4385,13 +4131,9 @@ fake-xml-http-request@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-2.0.0.tgz#41a92f0ca539477700cb1dafd2df251d55dac8ff" -fast-deep-equal@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" - fast-deep-equal@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" fast-diff@^1.1.2: version "1.2.0" @@ -4399,15 +4141,15 @@ fast-diff@^1.1.2: fast-json-stable-stringify@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" fast-levenshtein@~2.0.4: version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" + resolved "https://registry.npmjs.org/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" dependencies: blank-object "^1.0.1" @@ -4426,50 +4168,35 @@ fast-sourcemap-concat@^1.4.0: faye-websocket@~0.10.0: version "0.10.0" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" dependencies: websocket-driver ">=0.5.1" fb-watchman@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" dependencies: bser "^2.0.0" figures@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + resolved "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" dependencies: escape-string-regexp "^1.0.5" -file-entry-cache@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" dependencies: - flat-cache "^1.2.1" - object-assign "^4.0.1" - -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + flat-cache "^2.0.1" filesize@^3.6.1: version "3.6.1" resolved "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" -fill-range@^2.1.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^3.0.0" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - fill-range@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" dependencies: extend-shallow "^2.0.1" is-number "^3.0.0" @@ -4478,7 +4205,7 @@ fill-range@^4.0.0: finalhandler@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" dependencies: debug "2.6.9" encodeurl "~1.0.1" @@ -4490,7 +4217,7 @@ finalhandler@1.1.0: finalhandler@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" dependencies: debug "2.6.9" encodeurl "~1.0.2" @@ -4508,19 +4235,19 @@ find-babel-config@^1.1.0: path-exists "^3.0.0" find-index@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/find-index/-/find-index-1.1.0.tgz#53007c79cd30040d6816d79458e8837d5c5705ef" + version "1.1.1" + resolved "https://registry.npmjs.org/find-index/-/find-index-1.1.1.tgz#4b221f8d46b7f8bea33d8faed953f3ca7a081cbc" find-up@^1.0.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" find-up@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" dependencies: locate-path "^2.0.0" @@ -4531,13 +4258,13 @@ find-up@^3.0.0: locate-path "^3.0.0" find-yarn-workspace-root@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-1.1.0.tgz#9817b6748cb90719f4dc37b4538bb200c697356f" + version "1.2.1" + resolved "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-1.2.1.tgz#40eb8e6e7c2502ddfaa2577c176f221422f860db" dependencies: fs-extra "^4.0.3" micromatch "^3.1.4" -findup-sync@^2.0.0: +findup-sync@2.0.0, findup-sync@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" dependencies: @@ -4548,7 +4275,7 @@ findup-sync@^2.0.0: fireworm@^0.7.0: version "0.7.1" - resolved "https://registry.yarnpkg.com/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" + resolved "https://registry.npmjs.org/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" dependencies: async "~0.2.9" is-type "0.0.1" @@ -4565,43 +4292,42 @@ fixturify-project@^1.5.3: fixturify@^0.3.2, fixturify@^0.3.4: version "0.3.4" - resolved "https://registry.yarnpkg.com/fixturify/-/fixturify-0.3.4.tgz#c676de404a7f8ee8e64d0b76118e62ec95ab7b25" + resolved "https://registry.npmjs.org/fixturify/-/fixturify-0.3.4.tgz#c676de404a7f8ee8e64d0b76118e62ec95ab7b25" dependencies: fs-extra "^0.30.0" matcher-collection "^1.0.4" -flat-cache@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" dependencies: - circular-json "^0.3.1" - del "^2.0.2" - graceful-fs "^4.1.2" - write "^0.2.1" + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" -follow-redirects@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.1.tgz#67a8f14f5a1f67f962c2c46469c79eaec0a90291" +flat@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" dependencies: - debug "^3.1.0" + is-buffer "~2.0.3" -for-in@^1.0.1, for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" +flatted@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916" -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" +follow-redirects@^1.0.0: + version "1.7.0" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" dependencies: - for-in "^1.0.1" + debug "^3.2.6" -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" forever-agent@~0.5.0: version "0.5.2" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" forever-agent@~0.6.1: version "0.6.1" @@ -4609,7 +4335,7 @@ forever-agent@~0.6.1: form-data@~0.1.0: version "0.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" + resolved "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" dependencies: async "~0.9.0" combined-stream "~0.0.4" @@ -4617,7 +4343,7 @@ form-data@~0.1.0: form-data@~1.0.0-rc3: version "1.0.1" - resolved "http://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" + resolved "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" dependencies: async "^2.0.1" combined-stream "^1.0.5" @@ -4633,28 +4359,28 @@ form-data@~2.3.2: forwarded@~0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" fragment-cache@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + resolved "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" dependencies: map-cache "^0.2.2" fresh@0.5.2: version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" from2@^2.1.1: version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + resolved "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" dependencies: inherits "^2.0.1" readable-stream "^2.0.0" fs-extra@^0.24.0: version "0.24.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -4663,7 +4389,7 @@ fs-extra@^0.24.0: fs-extra@^0.30.0: version "0.30.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" dependencies: graceful-fs "^4.1.2" jsonfile "^2.1.0" @@ -4673,7 +4399,7 @@ fs-extra@^0.30.0: fs-extra@^4.0.2, fs-extra@^4.0.3: version "4.0.3" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -4681,7 +4407,7 @@ fs-extra@^4.0.2, fs-extra@^4.0.3: fs-extra@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -4689,29 +4415,23 @@ fs-extra@^5.0.0: fs-extra@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b" dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" universalify "^0.1.0" fs-extra@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.0.tgz#8cc3f47ce07ef7b3593a11b9fb245f7e34c041d6" + version "7.0.1" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" universalify "^0.1.0" -fs-minipass@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" - dependencies: - minipass "^2.2.1" - fs-sync@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/fs-sync/-/fs-sync-1.0.4.tgz#2f94eade31862ec0a9f33a1c2546dfb1a3f3d1ae" + version "1.0.6" + resolved "https://registry.npmjs.org/fs-sync/-/fs-sync-1.0.6.tgz#13f1d33a82edf441805fcc7cf6fabe246936166d" dependencies: glob "^7.1.0" iconv-lite "^0.4.13" @@ -4719,18 +4439,18 @@ fs-sync@^1.0.4: mkdirp "^0.5.1" rimraf "^2.1.4" -fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6, fs-tree-diff@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-0.5.7.tgz#315e2b098d5fe7f622880ac965b1b051868ac871" +fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6, fs-tree-diff@^0.5.7, fs-tree-diff@^0.5.9: + version "0.5.9" + resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.9.tgz#a4ec6182c2f5bd80b9b83c8e23e4522e6f5fd946" dependencies: heimdalljs-logger "^0.1.7" object-assign "^4.1.0" path-posix "^1.0.0" symlink-or-copy "^1.1.8" -fs-tree-diff@^0.5.9: - version "0.5.9" - resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-0.5.9.tgz#a4ec6182c2f5bd80b9b83c8e23e4522e6f5fd946" +fs-tree-diff@^1.0.0, fs-tree-diff@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-1.0.2.tgz#0e2931733a85b55feb3472c0b89a20b0c03ac0de" dependencies: heimdalljs-logger "^0.1.7" object-assign "^4.1.0" @@ -4739,7 +4459,7 @@ fs-tree-diff@^0.5.9: fs-updater@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/fs-updater/-/fs-updater-1.0.4.tgz#2329980f99ae9176e9a0e84f7637538a182ce63b" + resolved "https://registry.npmjs.org/fs-updater/-/fs-updater-1.0.4.tgz#2329980f99ae9176e9a0e84f7637538a182ce63b" dependencies: can-symlink "^1.0.0" clean-up-path "^1.0.0" @@ -4766,14 +4486,7 @@ fs-write-stream-atomic@~1.0.8: fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -fsevents@^1.2.3: - version "1.2.4" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" - dependencies: - nan "^2.9.2" - node-pre-gyp "^0.10.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" fstream-ignore@^1.0.0: version "1.0.5" @@ -4801,11 +4514,11 @@ fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.8: function-bind@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" functional-red-black-tree@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" gauge@~1.2.0, gauge@~1.2.5: version "1.2.7" @@ -4819,7 +4532,7 @@ gauge@~1.2.0, gauge@~1.2.5: gauge@~2.7.3: version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -4842,17 +4555,21 @@ generate-object-property@^1.1.0: dependencies: is-property "^1.0.0" -get-caller-file@^1.0.0: +get-caller-file@^1.0.1: version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + +get-caller-file@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.1.tgz#25835260d3a2b9665fcdbb08cb039a7bbf7011c0" get-func-name@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" get-stdin@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" get-stdin@^6.0.0: version "6.0.0" @@ -4860,7 +4577,7 @@ get-stdin@^6.0.0: get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" get-stream@^4.0.0: version "4.1.0" @@ -4870,7 +4587,7 @@ get-stream@^4.0.0: get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" getpass@^0.1.1: version "0.1.7" @@ -4880,7 +4597,7 @@ getpass@^0.1.1: git-fetch-pack@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/git-fetch-pack/-/git-fetch-pack-0.1.1.tgz#7703a32cf0db80f060d2766a34ac00d02cebcdf5" + resolved "https://registry.npmjs.org/git-fetch-pack/-/git-fetch-pack-0.1.1.tgz#7703a32cf0db80f060d2766a34ac00d02cebcdf5" dependencies: bops "0.0.3" emit-function "0.0.2" @@ -4889,47 +4606,47 @@ git-fetch-pack@^0.1.1: git-packed-ref-parse@0.0.0: version "0.0.0" - resolved "https://registry.yarnpkg.com/git-packed-ref-parse/-/git-packed-ref-parse-0.0.0.tgz#b85046931f3e4a65679b5de54af3a5d3df372646" + resolved "https://registry.npmjs.org/git-packed-ref-parse/-/git-packed-ref-parse-0.0.0.tgz#b85046931f3e4a65679b5de54af3a5d3df372646" dependencies: line-stream "0.0.0" through "~2.2.7" git-read-pkt-line@0.0.8: version "0.0.8" - resolved "https://registry.yarnpkg.com/git-read-pkt-line/-/git-read-pkt-line-0.0.8.tgz#494037854ed57bd90cd55676540d86ab0cb36caa" + resolved "https://registry.npmjs.org/git-read-pkt-line/-/git-read-pkt-line-0.0.8.tgz#494037854ed57bd90cd55676540d86ab0cb36caa" dependencies: bops "0.0.3" through "~2.2.7" git-repo-info@^1.0.4, git-repo-info@^1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" + resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-1.4.1.tgz#2a072823254aaf62fcf0766007d7b6651bd41943" git-repo-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-2.0.0.tgz#2e7a68ba3d0253e8e885c4138f922e6561de59bb" + version "2.1.0" + resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-2.1.0.tgz#13d1f753c75bc2994432e65a71e35377ff563813" git-repo-version@0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-0.2.0.tgz#9a1d0019a50fc9e623c43d1c0fcc437391207d0d" + resolved "https://registry.npmjs.org/git-repo-version/-/git-repo-version-0.2.0.tgz#9a1d0019a50fc9e623c43d1c0fcc437391207d0d" dependencies: git-repo-info "^1.0.4" git-repo-version@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/git-repo-version/-/git-repo-version-1.0.2.tgz#2c8e9bee5d970cafc0dd58480f9dc56d9afe8e4f" + resolved "https://registry.npmjs.org/git-repo-version/-/git-repo-version-1.0.2.tgz#2c8e9bee5d970cafc0dd58480f9dc56d9afe8e4f" dependencies: git-repo-info "^1.4.1" git-tools@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" + resolved "https://registry.npmjs.org/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" dependencies: spawnback "~1.0.0" git-transport-protocol@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/git-transport-protocol/-/git-transport-protocol-0.1.0.tgz#99f4dd6389b9161eded74a9e617d6ba5ed0a6c2c" + resolved "https://registry.npmjs.org/git-transport-protocol/-/git-transport-protocol-0.1.0.tgz#99f4dd6389b9161eded74a9e617d6ba5ed0a6c2c" dependencies: duplex "~1.0.0" emit-function "0.0.2" @@ -4939,7 +4656,7 @@ git-transport-protocol@^0.1.0: git-write-pkt-line@0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/git-write-pkt-line/-/git-write-pkt-line-0.1.0.tgz#a84c1856c09011908389b2f06f911d91f6394694" + resolved "https://registry.npmjs.org/git-write-pkt-line/-/git-write-pkt-line-0.1.0.tgz#a84c1856c09011908389b2f06f911d91f6394694" dependencies: bops "0.0.3" through "~2.2.7" @@ -4948,19 +4665,6 @@ github@^14.0.0: version "14.0.0" resolved "https://registry.npmjs.org/github/-/github-14.0.0.tgz#b707ed88c33cd05e155c785d289aa6229c59a850" -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - dependencies: - is-glob "^2.0.0" - "glob@3 || 4", glob@^4.3.2: version "4.5.3" resolved "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" @@ -4970,9 +4674,9 @@ glob-parent@^2.0.0: minimatch "^2.0.1" once "^1.3.0" -glob@7.1.2, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" +glob@7.1.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3: + version "7.1.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -4983,7 +4687,7 @@ glob@7.1.2, glob@^7.0.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.2: glob@^5.0.10: version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: inflight "^1.0.4" inherits "2" @@ -4991,17 +4695,6 @@ glob@^5.0.10: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.1, glob@^7.1.3: - version "7.1.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@~6.0.3: version "6.0.4" resolved "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" @@ -5014,7 +4707,7 @@ glob@~6.0.3: global-modules@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + resolved "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" dependencies: global-prefix "^1.0.1" is-windows "^1.0.1" @@ -5022,7 +4715,7 @@ global-modules@^1.0.0: global-prefix@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" dependencies: expand-tilde "^2.0.2" homedir-polyfill "^1.0.1" @@ -5031,27 +4724,16 @@ global-prefix@^1.0.1: which "^1.2.14" globals@^11.1.0, globals@^11.7.0: - version "11.7.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" + version "11.11.0" + resolved "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz#dcf93757fa2de5486fbeed7118538adf789e9c2e" globals@^9.18.0: version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - -globby@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" - dependencies: - array-union "^1.0.1" - arrify "^1.0.0" - glob "^7.0.3" - object-assign "^4.0.1" - pify "^2.0.0" - pinkie-promise "^2.0.0" + resolved "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" got@^6.7.1: version "6.7.1" - resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" + resolved "https://registry.npmjs.org/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" dependencies: create-error-class "^3.0.0" duplexer3 "^0.1.4" @@ -5067,7 +4749,7 @@ got@^6.7.1: got@^8.0.1: version "8.3.2" - resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" + resolved "https://registry.npmjs.org/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" dependencies: "@sindresorhus/is" "^0.7.0" cacheable-request "^2.1.1" @@ -5088,25 +4770,24 @@ got@^8.0.1: url-to-options "^1.0.1" graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.2: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + version "4.1.15" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" "graceful-readlink@>= 1.0.0": version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + resolved "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" growl@1.10.5: version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + resolved "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" growly@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" handlebars@^4.0.11, handlebars@^4.0.4: version "4.1.0" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.0.tgz#0d6a6f34ff1f63cecec8423aa4169827bf787c3a" - integrity sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w== + resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz#0d6a6f34ff1f63cecec8423aa4169827bf787c3a" dependencies: async "^2.5.0" optimist "^0.6.1" @@ -5128,49 +4809,53 @@ har-validator@~2.0.2: pinkie-promise "^2.0.0" har-validator@~5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29" + version "5.1.3" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" dependencies: - ajv "^5.3.0" + ajv "^6.5.5" har-schema "^2.0.0" has-ansi@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" dependencies: ansi-regex "^2.0.0" has-binary2@~1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + resolved "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" dependencies: isarray "2.0.1" has-cors@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + resolved "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" has-symbol-support-x@^1.4.1: version "1.4.2" - resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + resolved "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" has-to-string-tag-x@^1.2.0: version "1.4.1" - resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + resolved "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" dependencies: has-symbol-support-x "^1.4.1" has-unicode@^2.0.0, has-unicode@~2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" has-value@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + resolved "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" dependencies: get-value "^2.0.3" has-values "^0.1.4" @@ -5178,7 +4863,7 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + resolved "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" dependencies: get-value "^2.0.6" has-values "^1.0.0" @@ -5186,33 +4871,34 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + resolved "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" has-values@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + resolved "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" dependencies: is-number "^3.0.0" kind-of "^4.0.0" -has@^1.0.1: +has@^1.0.1, has@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" dependencies: function-bind "^1.1.1" hash-for-dep@^1.0.2, hash-for-dep@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.2.3.tgz#5ec69fca32c23523972d52acb5bb65ffc3664cab" + version "1.4.7" + resolved "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.4.7.tgz#ea6f9d8e2f9e784fc48ca60c40ea886bdb41aa54" dependencies: broccoli-kitchen-sink-helpers "^0.3.1" heimdalljs "^0.2.3" heimdalljs-logger "^0.1.7" + path-root "^0.1.1" resolve "^1.4.0" hawk@1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" + resolved "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz#87cd491f9b46e4e2aeaca335416766885d2d1ed9" dependencies: boom "0.4.x" cryptiles "0.2.x" @@ -5228,9 +4914,9 @@ hawk@~3.1.0: hoek "2.x.x" sntp "1.x.x" -he@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" +he@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" heimdalljs-fs-monitor@^0.2.2: version "0.2.2" @@ -5244,27 +4930,27 @@ heimdalljs-graph@^0.3.4: resolved "https://registry.npmjs.org/heimdalljs-graph/-/heimdalljs-graph-0.3.5.tgz#420fbbc8fc3aec5963ddbbf1a5fb47921c4a5927" heimdalljs-logger@^0.1.7, heimdalljs-logger@^0.1.9: - version "0.1.9" - resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.9.tgz#d76ada4e45b7bb6f786fc9c010a68eb2e2faf176" + version "0.1.10" + resolved "https://registry.npmjs.org/heimdalljs-logger/-/heimdalljs-logger-0.1.10.tgz#90cad58aabb1590a3c7e640ddc6a4cd3a43faaf7" dependencies: debug "^2.2.0" - heimdalljs "^0.2.0" + heimdalljs "^0.2.6" -heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3, heimdalljs@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.5.tgz#6aa54308eee793b642cff9cf94781445f37730ac" +heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3, heimdalljs@^0.2.5, heimdalljs@^0.2.6: + version "0.2.6" + resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.2.6.tgz#b0eebabc412813aeb9542f9cc622cb58dbdcd9fe" dependencies: rsvp "~3.2.1" heimdalljs@^0.3.0: version "0.3.3" - resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" + resolved "https://registry.npmjs.org/heimdalljs/-/heimdalljs-0.3.3.tgz#e92d2c6f77fd46d5bf50b610d28ad31755054d0b" dependencies: rsvp "~3.2.1" hoek@0.9.x: version "0.9.1" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" + resolved "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" hoek@2.x.x: version "2.16.3" @@ -5272,20 +4958,20 @@ hoek@2.x.x: home-or-tmp@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.1" homedir-polyfill@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" dependencies: parse-passwd "^1.0.0" hosted-git-info@^2.1.4, hosted-git-info@^2.1.5, hosted-git-info@^2.4.2, hosted-git-info@^2.6.0: version "2.7.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" hosted-git-info@~2.1.4: version "2.1.5" @@ -5293,20 +4979,11 @@ hosted-git-info@~2.1.4: http-cache-semantics@3.8.1: version "3.8.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" - -http-errors@1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" - dependencies: - depd "1.1.1" - inherits "2.0.3" - setprototypeof "1.0.3" - statuses ">= 1.3.1 < 2" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: version "1.6.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" dependencies: depd "~1.1.2" inherits "2.0.3" @@ -5314,8 +4991,8 @@ http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: statuses ">= 1.4.0 < 2" http-parser-js@>=0.4.0: - version "0.4.13" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.13.tgz#3bd6d6fde6e3172c9334c3b33b6c193d80fe1137" + version "0.5.0" + resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.0.tgz#d65edbede84349d0dc30320815a15d39cc3cbbd8" http-proxy@^1.13.1, http-proxy@^1.17.0: version "1.17.0" @@ -5327,7 +5004,7 @@ http-proxy@^1.13.1, http-proxy@^1.17.0: http-signature@~0.10.0: version "0.10.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz#4fbdac132559aa8323121e540779c0a012b27e66" dependencies: asn1 "0.1.11" assert-plus "^0.1.5" @@ -5349,17 +5026,13 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -iconv-lite@0.4.19: - version "0.4.19" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" - -iconv-lite@0.4.23, iconv-lite@^0.4.13, iconv-lite@^0.4.4: +iconv-lite@0.4.23: version "0.4.23" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.4.24: +iconv-lite@^0.4.13, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" dependencies: @@ -5369,53 +5042,53 @@ iferr@^0.1.5, iferr@~0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" -ignore-walk@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" - dependencies: - minimatch "^3.0.4" - ignore@^4.0.6: version "4.0.6" resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" ignore@^5.0.2: - version "5.0.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.0.4.tgz#33168af4a21e99b00c5d41cbadb6a6cb49903a45" - integrity sha512-WLsTMEhsQuXpCiG173+f3aymI43SXa+fB1rSfbzyP4GkPP+ZFVuO0/3sFUGNBtifisPeDcl/uD/Y2NxZ7xFq4g== + version "5.0.5" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.0.5.tgz#c663c548d6ce186fb33616a8ccb5d46e56bdbbf9" + +import-fresh@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz#a3d897f420cab0e671236897f75bc14b4885c390" + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" indent-string@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" dependencies: repeating "^2.0.0" indexof@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" inflection@^1.12.0: version "1.12.0" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" + resolved "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" inflight@^1.0.4, inflight@~1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" dependencies: once "^1.3.0" wrappy "1" inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" ini@^1.3.4, ini@~1.3.0, ini@~1.3.4: version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" init-package-json@~1.9.1: version "1.9.6" @@ -5432,7 +5105,7 @@ init-package-json@~1.9.1: inline-source-map-comment@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" + resolved "https://registry.npmjs.org/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" dependencies: chalk "^1.0.0" get-stdin "^4.0.1" @@ -5442,7 +5115,7 @@ inline-source-map-comment@^1.0.5: inquirer@^2: version "2.0.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-2.0.0.tgz#e1351687b90d150ca403ceaa3cefb1e3065bef4b" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-2.0.0.tgz#e1351687b90d150ca403ceaa3cefb1e3065bef4b" dependencies: ansi-escapes "^1.1.0" chalk "^1.0.0" @@ -5459,40 +5132,44 @@ inquirer@^2: strip-ansi "^3.0.0" through "^2.3.6" -inquirer@^6.1.0: - version "6.2.0" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8" +inquirer@^6.2.2: + version "6.2.2" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz#46941176f65c9eb20804627149b743a218f25406" dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" + ansi-escapes "^3.2.0" + chalk "^2.4.2" cli-cursor "^2.1.0" cli-width "^2.0.0" - external-editor "^3.0.0" + external-editor "^3.0.3" figures "^2.0.0" - lodash "^4.17.10" + lodash "^4.17.11" mute-stream "0.0.7" run-async "^2.2.0" - rxjs "^6.1.0" + rxjs "^6.4.0" string-width "^2.1.0" - strip-ansi "^4.0.0" + strip-ansi "^5.0.0" through "^2.3.6" into-stream@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" + resolved "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" dependencies: from2 "^2.1.1" p-is-promise "^1.1.0" invariant@^2.2.2: version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" dependencies: loose-envify "^1.0.0" -ipaddr.js@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" ipaddr.js@1.8.0: version "1.8.0" @@ -5500,53 +5177,57 @@ ipaddr.js@1.8.0: is-accessor-descriptor@^0.1.6: version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" dependencies: kind-of "^3.0.2" is-accessor-descriptor@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" dependencies: kind-of "^6.0.0" is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" is-buffer@^1.1.5: version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-buffer@~2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" is-builtin-module@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" dependencies: builtin-modules "^1.0.0" -is-callable@^1.1.1, is-callable@^1.1.3: +is-callable@^1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" is-data-descriptor@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" dependencies: kind-of "^3.0.2" is-data-descriptor@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" dependencies: kind-of "^6.0.0" is-date-object@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" is-descriptor@^0.1.0: version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" dependencies: is-accessor-descriptor "^0.1.6" is-data-descriptor "^0.1.4" @@ -5554,69 +5235,49 @@ is-descriptor@^0.1.0: is-descriptor@^1.0.0, is-descriptor@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" dependencies: is-accessor-descriptor "^1.0.0" is-data-descriptor "^1.0.0" kind-of "^6.0.2" -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - dependencies: - is-primitive "^2.0.0" - is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" is-extendable@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" dependencies: is-plain-object "^2.0.4" -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - is-extglob@^2.1.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" is-finite@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + resolved "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" is-git-url@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-1.0.0.tgz#53f684cd143285b52c3244b4e6f28253527af66b" - -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - dependencies: - is-extglob "^1.0.0" + resolved "https://registry.npmjs.org/is-git-url/-/is-git-url-1.0.0.tgz#53f684cd143285b52c3244b4e6f28253527af66b" is-glob@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" dependencies: is-extglob "^2.1.0" @@ -5634,67 +5295,33 @@ is-my-json-valid@^2.12.4: jsonpointer "^4.0.0" xtend "^4.0.0" -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - dependencies: - kind-of "^3.0.2" - is-number@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" dependencies: kind-of "^3.0.2" -is-number@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - is-obj@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" is-object@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" - -is-path-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" - -is-path-in-cwd@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" - dependencies: - is-path-inside "^1.0.0" - -is-path-inside@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" - dependencies: - path-is-inside "^1.0.1" + resolved "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" is-plain-obj@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" dependencies: isobject "^3.0.1" -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - is-promise@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" is-property@^1.0.0, is-property@^1.0.2: version "1.0.2" @@ -5702,39 +5329,41 @@ is-property@^1.0.0, is-property@^1.0.2: is-redirect@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + resolved "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" is-reference@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.1.0.tgz#50e6ef3f64c361e2c53c0416cdc9420037f2685b" + version "1.1.1" + resolved "https://registry.npmjs.org/is-reference/-/is-reference-1.1.1.tgz#bf2cda150a877f04d48caaf8fd70c03d8bed5e2d" dependencies: - "@types/estree" "0.0.38" + "@types/estree" "0.0.39" is-regex@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" dependencies: has "^1.0.1" is-regexp@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + resolved "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + resolved "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" is-stream@^1.0.0, is-stream@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" -is-symbol@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" +is-symbol@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" + dependencies: + has-symbols "^1.0.0" is-type@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" + resolved "https://registry.npmjs.org/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" dependencies: core-util-is "~1.0.0" @@ -5744,23 +5373,27 @@ is-typedarray@~1.0.0: is-utf8@^0.2.0: version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" isarray@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" isarray@1.0.0, isarray@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" isarray@2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" isbinaryfile@^3.0.3: version "3.0.3" @@ -5770,17 +5403,17 @@ isbinaryfile@^3.0.3: isexe@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" isobject@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" isstream@~0.1.2: version "0.1.2" @@ -5788,7 +5421,7 @@ isstream@~0.1.2: istextorbinary@2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" + resolved "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" dependencies: binaryextensions "1 || 2" editions "^1.1.1" @@ -5796,73 +5429,76 @@ istextorbinary@2.1.0: isurl@^1.0.0-alpha5: version "1.0.0" - resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + resolved "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" dependencies: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" jquery@^3.3.1: version "3.3.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" + resolved "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" js-levenshtein@^1.1.3: - version "1.1.4" - resolved "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.4.tgz#3a56e3cbf589ca0081eb22cd9ba0b1290a16d26e" + version "1.1.6" + resolved "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" js-reporters@1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b" + resolved "https://registry.npmjs.org/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b" "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" js-tokens@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" -js-yaml@^3.12.0, js-yaml@^3.2.5, js-yaml@^3.2.7: +js-yaml@3.12.0: version "3.12.0" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" dependencies: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^3.12.0, js-yaml@^3.2.5, js-yaml@^3.2.7: + version "3.12.1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" jsesc@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" jsesc@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + version "2.5.2" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" jsesc@~0.3.x: version "0.3.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.3.0.tgz#1bf5ee63b4539fe2e26d0c1e99c240b97a457972" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.3.0.tgz#1bf5ee63b4539fe2e26d0c1e99c240b97a457972" jsesc@~0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" json-buffer@3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - json-schema-traverse@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" json-schema@0.2.3: version "0.2.3" @@ -5870,11 +5506,11 @@ json-schema@0.2.3: json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: jsonify "~0.0.0" @@ -5884,28 +5520,33 @@ json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: json-typescript@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/json-typescript/-/json-typescript-1.1.0.tgz#5369013526d516b13bde1ae2bbc541386dd12c72" - integrity sha512-6BzXAzBSfO4L3+IdCLISVQUzR4Wq946Xk2u7ChUAnvftyj/Ec1YgRmBOjw9Rw4wpdtvX678HPIYtYaGYr9fb9w== + resolved "https://registry.npmjs.org/json-typescript/-/json-typescript-1.1.0.tgz#5369013526d516b13bde1ae2bbc541386dd12c72" -json5@^0.5.0, json5@^0.5.1: +json5@^0.5.1: version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + resolved "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +json5@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" + dependencies: + minimist "^1.2.0" jsonfile@^2.1.0: version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" optionalDependencies: graceful-fs "^4.1.6" jsonfile@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" optionalDependencies: graceful-fs "^4.1.6" jsonify@~0.0.0: version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" jsonpointer@^4.0.0: version "4.0.1" @@ -5922,39 +5563,45 @@ jsprim@^1.2.2: keyv@3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" + resolved "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" dependencies: json-buffer "3.0.0" kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" dependencies: is-buffer "^1.1.5" kind-of@^5.0.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" klaw@^1.0.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + resolved "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" optionalDependencies: graceful-fs "^4.1.9" +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + dependencies: + invert-kv "^2.0.0" + leek@0.0.24: version "0.0.24" - resolved "https://registry.yarnpkg.com/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" + resolved "https://registry.npmjs.org/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" dependencies: debug "^2.1.0" lodash.assign "^3.2.0" @@ -5962,36 +5609,36 @@ leek@0.0.24: levn@^0.3.0, levn@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" line-stream@0.0.0: version "0.0.0" - resolved "https://registry.yarnpkg.com/line-stream/-/line-stream-0.0.0.tgz#888b7cc7951c6a05ce4d696dd1e6b8262371bb45" + resolved "https://registry.npmjs.org/line-stream/-/line-stream-0.0.0.tgz#888b7cc7951c6a05ce4d696dd1e6b8262371bb45" dependencies: through "~2.2.0" linkify-it@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" + version "2.1.0" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-2.1.0.tgz#c4caf38a6cd7ac2212ef3c7d2bde30a91561f9db" dependencies: uc.micro "^1.0.1" linkify-it@~1.2.0: version "1.2.4" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" + resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a" dependencies: uc.micro "^1.0.1" livereload-js@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.3.0.tgz#c3ab22e8aaf5bf3505d80d098cbad67726548c9a" + version "2.4.0" + resolved "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz#447c31cf1ea9ab52fc20db615c5ddf678f78009c" load-json-file@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -6001,15 +5648,15 @@ load-json-file@^1.0.0: loader.js@^4.7.0: version "4.7.0" - resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.7.0.tgz#a1a52902001c83631efde9688b8ab3799325ef1f" + resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.7.0.tgz#a1a52902001c83631efde9688b8ab3799325ef1f" locate-character@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/locate-character/-/locate-character-2.0.5.tgz#f2d2614d49820ecb3c92d80d193b8db755f74c0f" + resolved "https://registry.npmjs.org/locate-character/-/locate-character-2.0.5.tgz#f2d2614d49820ecb3c92d80d193b8db755f74c0f" locate-path@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" dependencies: p-locate "^2.0.0" path-exists "^3.0.0" @@ -6029,7 +5676,7 @@ lockfile@~1.0.1: lodash-node@^3.2.0: version "3.10.2" - resolved "https://registry.yarnpkg.com/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" + resolved "https://registry.npmjs.org/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" lodash._arraycopy@^3.0.0: version "3.0.0" @@ -6041,14 +5688,14 @@ lodash._arrayeach@^3.0.0: lodash._baseassign@^3.0.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + resolved "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" dependencies: lodash._basecopy "^3.0.0" lodash.keys "^3.0.0" lodash._basebind@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._basebind/-/lodash._basebind-2.3.0.tgz#2b5bc452a0e106143b21869f233bdb587417d248" + resolved "https://registry.npmjs.org/lodash._basebind/-/lodash._basebind-2.3.0.tgz#2b5bc452a0e106143b21869f233bdb587417d248" dependencies: lodash._basecreate "~2.3.0" lodash._setbinddata "~2.3.0" @@ -6076,11 +5723,11 @@ lodash._baseclone@^3.0.0: lodash._basecopy@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + resolved "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" lodash._basecreate@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz#9b88a86a4dcff7b7f3c61d83a2fcfc0671ec9de0" + resolved "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz#9b88a86a4dcff7b7f3c61d83a2fcfc0671ec9de0" dependencies: lodash._renative "~2.3.0" lodash.isobject "~2.3.0" @@ -6088,7 +5735,7 @@ lodash._basecreate@~2.3.0: lodash._basecreatecallback@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz#37b2ab17591a339e988db3259fcd46019d7ac362" + resolved "https://registry.npmjs.org/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz#37b2ab17591a339e988db3259fcd46019d7ac362" dependencies: lodash._setbinddata "~2.3.0" lodash.bind "~2.3.0" @@ -6097,7 +5744,7 @@ lodash._basecreatecallback@~2.3.0: lodash._basecreatewrapper@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz#aa0c61ad96044c3933376131483a9759c3651247" + resolved "https://registry.npmjs.org/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz#aa0c61ad96044c3933376131483a9759c3651247" dependencies: lodash._basecreate "~2.3.0" lodash._setbinddata "~2.3.0" @@ -6114,7 +5761,7 @@ lodash._basedifference@^3.0.0: lodash._baseflatten@^3.0.0: version "3.1.4" - resolved "https://registry.yarnpkg.com/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" + resolved "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" dependencies: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" @@ -6145,7 +5792,7 @@ lodash._baseuniq@^3.0.0: lodash._bindcallback@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" lodash._cacheindexof@^3.0.0: version "3.0.2" @@ -6153,7 +5800,7 @@ lodash._cacheindexof@^3.0.0: lodash._createassigner@^3.0.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + resolved "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" dependencies: lodash._bindcallback "^3.0.0" lodash._isiterateecall "^3.0.0" @@ -6167,7 +5814,7 @@ lodash._createcache@^3.0.0: lodash._createwrapper@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" + resolved "https://registry.npmjs.org/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" dependencies: lodash._basebind "~2.3.0" lodash._basecreatewrapper "~2.3.0" @@ -6175,69 +5822,69 @@ lodash._createwrapper@~2.3.0: lodash._escapehtmlchar@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.3.0.tgz#d03da6bd82eedf38dc0a5b503d740ecd0e894592" + resolved "https://registry.npmjs.org/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.3.0.tgz#d03da6bd82eedf38dc0a5b503d740ecd0e894592" dependencies: lodash._htmlescapes "~2.3.0" lodash._escapestringchar@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._escapestringchar/-/lodash._escapestringchar-2.3.0.tgz#cce73ae60fc6da55d2bf8a0679c23ca2bab149fc" + resolved "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.3.0.tgz#cce73ae60fc6da55d2bf8a0679c23ca2bab149fc" lodash._getnative@^3.0.0: version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" lodash._htmlescapes@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._htmlescapes/-/lodash._htmlescapes-2.3.0.tgz#1ca98863cadf1fa1d82c84f35f31e40556a04f3a" + resolved "https://registry.npmjs.org/lodash._htmlescapes/-/lodash._htmlescapes-2.3.0.tgz#1ca98863cadf1fa1d82c84f35f31e40556a04f3a" lodash._isiterateecall@^3.0.0: version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + resolved "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" lodash._objecttypes@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz#6a3ea3987dd6eeb8021b2d5c9c303549cc2bae1e" + resolved "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz#6a3ea3987dd6eeb8021b2d5c9c303549cc2bae1e" lodash._reinterpolate@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-2.3.0.tgz#03ee9d85c0e55cbd590d71608a295bdda51128ec" + resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-2.3.0.tgz#03ee9d85c0e55cbd590d71608a295bdda51128ec" lodash._reinterpolate@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" lodash._renative@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._renative/-/lodash._renative-2.3.0.tgz#77d8edd4ced26dd5971f9e15a5f772e4e317fbd3" + resolved "https://registry.npmjs.org/lodash._renative/-/lodash._renative-2.3.0.tgz#77d8edd4ced26dd5971f9e15a5f772e4e317fbd3" lodash._reunescapedhtml@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.3.0.tgz#db920b55ac7f3ff825939aceb9ba2c231713d24d" + resolved "https://registry.npmjs.org/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.3.0.tgz#db920b55ac7f3ff825939aceb9ba2c231713d24d" dependencies: lodash._htmlescapes "~2.3.0" lodash.keys "~2.3.0" lodash._setbinddata@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz#e5610490acd13277d59858d95b5f2727f1508f04" + resolved "https://registry.npmjs.org/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz#e5610490acd13277d59858d95b5f2727f1508f04" dependencies: lodash._renative "~2.3.0" lodash.noop "~2.3.0" lodash._shimkeys@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz#611f93149e3e6c721096b48769ef29537ada8ba9" + resolved "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz#611f93149e3e6c721096b48769ef29537ada8ba9" dependencies: lodash._objecttypes "~2.3.0" lodash._slice@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash._slice/-/lodash._slice-2.3.0.tgz#147198132859972e4680ca29a5992c855669aa5c" + resolved "https://registry.npmjs.org/lodash._slice/-/lodash._slice-2.3.0.tgz#147198132859972e4680ca29a5992c855669aa5c" lodash.assign@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" dependencies: lodash._baseassign "^3.0.0" lodash._createassigner "^3.0.0" @@ -6245,11 +5892,11 @@ lodash.assign@^3.2.0: lodash.assignin@^4.1.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + resolved "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" lodash.bind@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-2.3.0.tgz#c2a8e18b68e5ecc152e2b168266116fea5b016cc" + resolved "https://registry.npmjs.org/lodash.bind/-/lodash.bind-2.3.0.tgz#c2a8e18b68e5ecc152e2b168266116fea5b016cc" dependencies: lodash._createwrapper "~2.3.0" lodash._renative "~2.3.0" @@ -6257,11 +5904,11 @@ lodash.bind@~2.3.0: lodash.castarray@^4.4.0: version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" + resolved "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" lodash.clonedeep@^4.4.1: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" lodash.clonedeep@~3.0.2: version "3.0.2" @@ -6272,24 +5919,24 @@ lodash.clonedeep@~3.0.2: lodash.debounce@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" + resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" dependencies: lodash._getnative "^3.0.0" lodash.defaults@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-2.3.0.tgz#a832b001f138f3bb9721c2819a2a7cc5ae21ed25" + resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-2.3.0.tgz#a832b001f138f3bb9721c2819a2a7cc5ae21ed25" dependencies: lodash._objecttypes "~2.3.0" lodash.keys "~2.3.0" lodash.defaultsdeep@^4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.0.tgz#bec1024f85b1bd96cbea405b23c14ad6443a6f81" + resolved "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.0.tgz#bec1024f85b1bd96cbea405b23c14ad6443a6f81" lodash.escape@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-2.3.0.tgz#844c38c58f844e1362ebe96726159b62cf5f2a58" + resolved "https://registry.npmjs.org/lodash.escape/-/lodash.escape-2.3.0.tgz#844c38c58f844e1362ebe96726159b62cf5f2a58" dependencies: lodash._escapehtmlchar "~2.3.0" lodash._reunescapedhtml "~2.3.0" @@ -6297,25 +5944,25 @@ lodash.escape@~2.3.0: lodash.find@^4.5.1: version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" + resolved "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" lodash.flatten@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" + resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" dependencies: lodash._baseflatten "^3.0.0" lodash._isiterateecall "^3.0.0" lodash.foreach@~2.3.x: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-2.3.0.tgz#083404c91e846ee77245fdf9d76519c68b2af168" + resolved "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-2.3.0.tgz#083404c91e846ee77245fdf9d76519c68b2af168" dependencies: lodash._basecreatecallback "~2.3.0" lodash.forown "~2.3.0" lodash.forown@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.forown/-/lodash.forown-2.3.0.tgz#24fb4aaf800d45fc2dc60bfec3ce04c836a3ad7f" + resolved "https://registry.npmjs.org/lodash.forown/-/lodash.forown-2.3.0.tgz#24fb4aaf800d45fc2dc60bfec3ce04c836a3ad7f" dependencies: lodash._basecreatecallback "~2.3.0" lodash._objecttypes "~2.3.0" @@ -6323,23 +5970,23 @@ lodash.forown@~2.3.0: lodash.identity@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.identity/-/lodash.identity-2.3.0.tgz#6b01a210c9485355c2a913b48b6711219a173ded" + resolved "https://registry.npmjs.org/lodash.identity/-/lodash.identity-2.3.0.tgz#6b01a210c9485355c2a913b48b6711219a173ded" lodash.isarguments@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" lodash.isarray@^3.0.0: version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" lodash.isfunction@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz#6b2973e47a647cf12e70d676aea13643706e5267" + resolved "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz#6b2973e47a647cf12e70d676aea13643706e5267" lodash.isobject@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-2.3.0.tgz#2e16d3fc583da9831968953f2d8e6d73434f6799" + resolved "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.3.0.tgz#2e16d3fc583da9831968953f2d8e6d73434f6799" dependencies: lodash._objecttypes "~2.3.0" @@ -6349,7 +5996,7 @@ lodash.istypedarray@^3.0.0: lodash.keys@^3.0.0: version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" dependencies: lodash._getnative "^3.0.0" lodash.isarguments "^3.0.0" @@ -6357,7 +6004,7 @@ lodash.keys@^3.0.0: lodash.keys@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-2.3.0.tgz#b350f4f92caa9f45a4a2ecf018454cf2f28ae253" + resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.3.0.tgz#b350f4f92caa9f45a4a2ecf018454cf2f28ae253" dependencies: lodash._renative "~2.3.0" lodash._shimkeys "~2.3.0" @@ -6365,15 +6012,15 @@ lodash.keys@~2.3.0: lodash.merge@^4.3.1, lodash.merge@^4.6.0: version "4.6.1" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" lodash.noop@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-2.3.0.tgz#3059d628d51bbf937cd2a0b6fc3a7f212a669c2c" + resolved "https://registry.npmjs.org/lodash.noop/-/lodash.noop-2.3.0.tgz#3059d628d51bbf937cd2a0b6fc3a7f212a669c2c" lodash.omit@^4.1.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" + resolved "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" lodash.pad@^4.1.0: version "4.5.1" @@ -6395,11 +6042,11 @@ lodash.pairs@^3.0.0: lodash.restparam@^3.0.0: version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" lodash.support@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.support/-/lodash.support-2.3.0.tgz#7eaf038af4f0d6aab776b44aa6dcfc80334c9bfd" + resolved "https://registry.npmjs.org/lodash.support/-/lodash.support-2.3.0.tgz#7eaf038af4f0d6aab776b44aa6dcfc80334c9bfd" dependencies: lodash._renative "~2.3.0" @@ -6412,7 +6059,7 @@ lodash.template@^4.4.0: lodash.template@~2.3.x: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-2.3.0.tgz#4e3e29c433b4cfea675ec835e6f12391c61fd22b" + resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-2.3.0.tgz#4e3e29c433b4cfea675ec835e6f12391c61fd22b" dependencies: lodash._escapestringchar "~2.3.0" lodash._reinterpolate "~2.3.0" @@ -6424,13 +6071,13 @@ lodash.template@~2.3.x: lodash.templatesettings@^4.0.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" + resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" dependencies: lodash._reinterpolate "~3.0.0" lodash.templatesettings@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-2.3.0.tgz#303d132c342710040d5a18efaa2d572fd03f8cdc" + resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-2.3.0.tgz#303d132c342710040d5a18efaa2d572fd03f8cdc" dependencies: lodash._reinterpolate "~2.3.0" lodash.escape "~2.3.0" @@ -6445,7 +6092,7 @@ lodash.union@~3.1.0: lodash.uniq@^4.2.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" lodash.uniq@~3.2.2: version "3.2.2" @@ -6459,11 +6106,11 @@ lodash.uniq@~3.2.2: lodash.uniqby@^4.7.0: version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" + resolved "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" lodash.values@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-2.3.0.tgz#ca96fbe60a20b0b0ec2ba2ba5fc6a765bd14a3ba" + resolved "https://registry.npmjs.org/lodash.values/-/lodash.values-2.3.0.tgz#ca96fbe60a20b0b0ec2ba2ba5fc6a765bd14a3ba" dependencies: lodash.keys "~2.3.0" @@ -6474,91 +6121,86 @@ lodash.without@~3.2.1: lodash._basedifference "^3.0.0" lodash.restparam "^3.0.0" -lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.6.1: - version "4.17.10" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" - -lodash@^4.17.11: +lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1: version "4.17.11" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" -log-symbols@^2.2.0: +log-symbols@2.2.0, log-symbols@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" dependencies: chalk "^2.0.1" loose-envify@^1.0.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" dependencies: js-tokens "^3.0.0 || ^4.0.0" loud-rejection@^1.0.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + resolved "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" dependencies: currently-unhandled "^0.4.1" signal-exit "^3.0.0" lowercase-keys@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" lowercase-keys@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" lru-cache@2: version "2.7.3" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" -lru-cache@^4.0.1: - version "4.1.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - magic-string@^0.24.0: version "0.24.1" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.24.1.tgz#7e38e5f126cae9f15e71f0cf8e450818ca7d5a8f" + resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.24.1.tgz#7e38e5f126cae9f15e71f0cf8e450818ca7d5a8f" dependencies: sourcemap-codec "^1.4.1" make-array@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" + resolved "https://registry.npmjs.org/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" make-dir@^1.0.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" dependencies: pify "^3.0.0" makeerror@1.0.x: version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" dependencies: tmpl "1.0.x" +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + dependencies: + p-defer "^1.0.0" + map-cache@^0.2.2: version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" map-visit@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + resolved "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" dependencies: object-visit "^1.0.0" markdown-it-terminal@0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/markdown-it-terminal/-/markdown-it-terminal-0.1.0.tgz#545abd8dd01c3d62353bfcea71db580b51d22bd9" + resolved "https://registry.npmjs.org/markdown-it-terminal/-/markdown-it-terminal-0.1.0.tgz#545abd8dd01c3d62353bfcea71db580b51d22bd9" dependencies: ansi-styles "^3.0.0" cardinal "^1.0.0" @@ -6568,7 +6210,7 @@ markdown-it-terminal@0.1.0: markdown-it@^4.3.0: version "4.4.0" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-4.4.0.tgz#3df373dbea587a9a7fef3e56311b68908f75c414" dependencies: argparse "~1.0.2" entities "~1.1.1" @@ -6578,7 +6220,7 @@ markdown-it@^4.3.0: markdown-it@^8.3.1, markdown-it@^8.4.2: version "8.4.2" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54" dependencies: argparse "^1.0.7" entities "~1.1.1" @@ -6586,37 +6228,41 @@ markdown-it@^8.3.1, markdown-it@^8.4.2: mdurl "^1.0.1" uc.micro "^1.0.5" -matcher-collection@^1.0.0, matcher-collection@^1.0.4, matcher-collection@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-1.0.5.tgz#2ee095438372cb8884f058234138c05c644ec339" +matcher-collection@^1.0.0, matcher-collection@^1.0.4, matcher-collection@^1.0.5, matcher-collection@^1.1.1: + version "1.1.2" + resolved "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.1.2.tgz#1076f506f10ca85897b53d14ef54f90a5c426838" dependencies: minimatch "^3.0.2" -math-random@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" - mdn-links@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" + resolved "https://registry.npmjs.org/mdn-links/-/mdn-links-0.1.0.tgz#e24c83b97cb4c5886cc39f2f780705fbfe273aa5" mdurl@^1.0.1, mdurl@~1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + resolved "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" media-typer@0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +mem@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz#aeb9be2d21f47e78af29e4ac5978e8afa2ca5b8a" + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^1.0.0" + p-is-promise "^2.0.0" memory-streams@^0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.3.tgz#d9b0017b4b87f1d92f55f2745c9caacb1dc93ceb" + resolved "https://registry.npmjs.org/memory-streams/-/memory-streams-0.1.3.tgz#d9b0017b4b87f1d92f55f2745c9caacb1dc93ceb" dependencies: readable-stream "~1.0.2" meow@^3.4.0: version "3.7.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + resolved "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" dependencies: camelcase-keys "^2.0.0" decamelize "^1.1.2" @@ -6631,11 +6277,11 @@ meow@^3.4.0: merge-descriptors@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" merge-trees@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-trees/-/merge-trees-1.0.1.tgz#ccbe674569787f9def17fd46e6525f5700bbd23e" + resolved "https://registry.npmjs.org/merge-trees/-/merge-trees-1.0.1.tgz#ccbe674569787f9def17fd46e6525f5700bbd23e" dependencies: can-symlink "^1.0.0" fs-tree-diff "^0.5.4" @@ -6646,41 +6292,22 @@ merge-trees@^1.0.1: merge-trees@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-trees/-/merge-trees-2.0.0.tgz#a560d796e566c5d9b2c40472a2967cca48d85161" + resolved "https://registry.npmjs.org/merge-trees/-/merge-trees-2.0.0.tgz#a560d796e566c5d9b2c40472a2967cca48d85161" dependencies: fs-updater "^1.0.4" heimdalljs "^0.2.5" merge@^1.2.0: version "1.2.1" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" - integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== + resolved "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" methods@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - -micromatch@^2.3.11: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" -micromatch@^3.0.4, micromatch@^3.1.4: +micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" @@ -6696,45 +6323,35 @@ micromatch@^3.0.4, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -"mime-db@>= 1.34.0 < 2", mime-db@~1.35.0: - version "1.35.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" +"mime-db@>= 1.38.0 < 2", mime-db@~1.38.0: + version "1.38.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad" -mime-db@~1.37.0: - version "1.37.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" - -mime-types@^2.1.11, mime-types@^2.1.12, mime-types@^2.1.19, mime-types@~2.1.19, mime-types@~2.1.7: - version "2.1.21" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" - dependencies: - mime-db "~1.37.0" - -mime-types@^2.1.18, mime-types@~2.1.18: - version "2.1.19" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" +mime-types@^2.1.11, mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.19, mime-types@~2.1.18, mime-types@~2.1.19, mime-types@~2.1.7: + version "2.1.22" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd" dependencies: - mime-db "~1.35.0" + mime-db "~1.38.0" mime-types@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" mime@1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + resolved "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" mime@~1.2.11: version "1.2.11" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" + resolved "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" mimic-fn@^1.0.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" mimic-response@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" minimatch@1: version "1.0.0" @@ -6745,91 +6362,97 @@ minimatch@1: "minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: brace-expansion "^1.1.7" minimatch@^2.0.1: version "2.0.10" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" dependencies: brace-expansion "^1.0.0" minimist@0.0.8: version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" minimist@~0.0.1: version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" -minipass@^2.2.0, minipass@^2.2.1, minipass@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" +minipass@^2.2.0: + version "2.3.5" + resolved "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" dependencies: safe-buffer "^5.1.2" yallist "^3.0.0" -minizlib@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" - dependencies: - minipass "^2.2.1" - mixin-deep@^1.2.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" dependencies: for-in "^1.0.2" is-extendable "^1.0.1" mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" mktemp@~0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" + resolved "https://registry.npmjs.org/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" mocha-only-detector@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/mocha-only-detector/-/mocha-only-detector-1.0.0.tgz#183c710afffcca79df172daf76c45afca3b8e37d" + resolved "https://registry.npmjs.org/mocha-only-detector/-/mocha-only-detector-1.0.0.tgz#183c710afffcca79df172daf76c45afca3b8e37d" dependencies: esprima "^4.0.0" esprimaq "^0.0.1" glob "^4.3.2" -mocha@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" +mocha@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/mocha/-/mocha-6.0.0.tgz#b558da6245a09581aa4a1c6aee9e0fa6ad0e1767" dependencies: + ansi-colors "3.2.3" browser-stdout "1.3.1" - commander "2.15.1" - debug "3.1.0" + debug "3.2.6" diff "3.5.0" escape-string-regexp "1.0.5" - glob "7.1.2" + findup-sync "2.0.0" + glob "7.1.3" growl "1.10.5" - he "1.1.1" + he "1.2.0" + js-yaml "3.12.0" + log-symbols "2.2.0" minimatch "3.0.4" mkdirp "0.5.1" - supports-color "5.4.0" + ms "2.1.1" + node-environment-flags "1.0.4" + object.assign "4.1.0" + strip-json-comments "2.0.1" + supports-color "6.0.0" + which "1.3.1" + wide-align "1.1.3" + yargs "12.0.5" + yargs-parser "11.1.1" + yargs-unparser "1.5.0" moment-timezone@^0.3.0: version "0.3.1" - resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" + resolved "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" dependencies: moment ">= 2.6.0" "moment@>= 2.6.0": - version "2.22.2" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" + version "2.24.0" + resolved "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" morgan@^1.9.0: version "1.9.1" @@ -6843,35 +6466,35 @@ morgan@^1.9.0: mout@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/mout/-/mout-1.1.0.tgz#0b29d41e6a80fa9e2d4a5be9d602e1d9d02177f6" + resolved "https://registry.npmjs.org/mout/-/mout-1.1.0.tgz#0b29d41e6a80fa9e2d4a5be9d602e1d9d02177f6" ms@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" -ms@^2.1.1: +ms@2.1.1, ms@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" mustache@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/mustache/-/mustache-3.0.0.tgz#3de22dd9ba38152f7355399a953dd4528c403338" + version "3.0.1" + resolved "https://registry.npmjs.org/mustache/-/mustache-3.0.1.tgz#873855f23aa8a95b150fb96d9836edbc5a1d248a" mute-stream@0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" -mute-stream@0.0.7, mute-stream@~0.0.4: +mute-stream@0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" -nan@^2.9.2: - version "2.10.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" +mute-stream@~0.0.4: + version "0.0.8" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" nanomatch@^1.2.9: version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" dependencies: arr-diff "^4.0.0" array-unique "^0.3.2" @@ -6887,27 +6510,25 @@ nanomatch@^1.2.9: natural-compare@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - -needle@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" - dependencies: - debug "^2.1.2" - iconv-lite "^0.4.4" - sax "^1.2.4" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" negotiator@0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" next-tick@1: version "1.0.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + +node-environment-flags@1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" + resolved "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.4.tgz#0b784a6551426bfc16d3b2208424dcbc2b2ff038" + dependencies: + object.getownpropertydescriptors "^2.0.3" node-gyp@~3.2.1: version "3.2.1" @@ -6930,39 +6551,25 @@ node-gyp@~3.2.1: node-int64@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" node-modules-path@^1.0.0, node-modules-path@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.1.tgz#40096b08ce7ad0ea14680863af449c7c75a5d1c8" + version "1.0.2" + resolved "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.2.tgz#e3acede9b7baf4bc336e3496b58e5b40d517056e" node-notifier@^5.0.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" + version "5.4.0" + resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.0.tgz#7b455fdce9f7de0c63538297354f3db468426e6a" dependencies: growly "^1.3.0" - semver "^5.4.1" + is-wsl "^1.1.0" + semver "^5.5.0" shellwords "^0.1.1" which "^1.3.0" -node-pre-gyp@^0.10.0: - version "0.10.3" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" - -node-releases@^1.0.0-alpha.15: - version "1.0.0-alpha.15" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.0.0-alpha.15.tgz#bdb08730287cc50ddbfa3c1a358366a4a2f5d397" +node-releases@^1.1.3: + version "1.1.8" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.8.tgz#32a63fff63c5e51b7e0f540ac95947d220fc6862" dependencies: semver "^5.3.0" @@ -6972,32 +6579,24 @@ node-uuid@~1.4.0, node-uuid@~1.4.7: node-watch@0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/node-watch/-/node-watch-0.6.0.tgz#ab0703b60cd270783698e57a428faa0010ed8fd0" - integrity sha512-XAgTL05z75ptd7JSVejH1a2Dm1zmXYhuDr9l230Qk6Z7/7GPcnAs/UyJJ4ggsXSvWil8iOzwQLW0zuGUvHpG8g== + resolved "https://registry.npmjs.org/node-watch/-/node-watch-0.6.0.tgz#ab0703b60cd270783698e57a428faa0010ed8fd0" "nopt@2 || 3", nopt@^3.0.3, nopt@^3.0.6, nopt@~3.0.6: version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - dependencies: - abbrev "1" - -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: abbrev "1" - osenv "^0.1.4" normalize-git-url@~3.0.1: version "3.0.2" resolved "https://registry.npmjs.org/normalize-git-url/-/normalize-git-url-3.0.2.tgz#8e5f14be0bdaedb73e07200310aa416c27350fc4" normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, "normalize-package-data@~1.0.1 || ^2.0.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" + version "2.5.0" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" dependencies: hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" + resolve "^1.10.0" semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" @@ -7010,31 +6609,27 @@ normalize-package-data@~2.3.5: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.1, normalize-path@^2.1.1: +normalize-path@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: remove-trailing-separator "^1.0.1" normalize-url@2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" dependencies: prepend-http "^2.0.0" query-string "^5.0.1" sort-keys "^2.0.0" -npm-bundled@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" - npm-cache-filename@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" npm-git-info@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" + resolved "https://registry.npmjs.org/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" npm-install-checks@~2.0.1: version "2.0.1" @@ -7075,13 +6670,6 @@ npm-package-arg@~4.1.0: hosted-git-info "^2.1.4" semver "4 || 5" -npm-packlist@^1.1.6: - version "1.1.10" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - npm-registry-client@~7.0.9: version "7.0.9" resolved "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-7.0.9.tgz#1baf86ee5285c4e6d38d4556208ded56049231bb" @@ -7103,7 +6691,7 @@ npm-registry-client@~7.0.9: npm-run-path@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" dependencies: path-key "^2.0.0" @@ -7113,7 +6701,7 @@ npm-user-validate@~0.1.2: npm@~3.5.2: version "3.5.4" - resolved "http://registry.npmjs.org/npm/-/npm-3.5.4.tgz#db2f71d3daa0e7a99077edd4c213919834e95eb2" + resolved "https://registry.npmjs.org/npm/-/npm-3.5.4.tgz#db2f71d3daa0e7a99077edd4c213919834e95eb2" dependencies: abbrev "~1.0.7" ansicolors "~0.3.2" @@ -7187,15 +6775,15 @@ npm@~3.5.2: "npmlog@0 || 1", "npmlog@0.1 || 1": version "1.2.1" - resolved "http://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz#28e7be619609b53f7ad1dd300a10d64d716268b6" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz#28e7be619609b53f7ad1dd300a10d64d716268b6" dependencies: ansi "~0.3.0" are-we-there-yet "~1.0.0" gauge "~1.2.0" -npmlog@^4.0.0, npmlog@^4.0.2: +npmlog@^4.0.0: version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" @@ -7204,7 +6792,7 @@ npmlog@^4.0.0, npmlog@^4.0.2: npmlog@~2.0.0: version "2.0.4" - resolved "http://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz#98b52530f2514ca90d09ec5b22c8846722375692" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz#98b52530f2514ca90d09ec5b22c8846722375692" dependencies: ansi "~0.3.1" are-we-there-yet "~1.1.2" @@ -7212,11 +6800,11 @@ npmlog@~2.0.0: number-is-nan@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" oauth-sign@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" oauth-sign@~0.8.0: version "0.8.2" @@ -7228,15 +6816,15 @@ oauth-sign@~0.9.0: object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" object-component@0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + resolved "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" object-copy@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" @@ -7244,45 +6832,53 @@ object-copy@^0.1.0: object-hash@^1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df" - integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA== + resolved "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df" -object-keys@^1.0.8: - version "1.0.12" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" +object-keys@^1.0.11, object-keys@^1.0.12: + version "1.1.0" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz#11bd22348dd2e096a045ab06f6c85bcc340fa032" object-visit@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + resolved "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" dependencies: isobject "^3.0.0" -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" +object.assign@4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" object.pick@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + resolved "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" dependencies: isobject "^3.0.1" on-finished@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" dependencies: ee-first "1.1.1" on-headers@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" @@ -7294,11 +6890,11 @@ once@~1.3.3: onetime@^1.0.0: version "1.1.0" - resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + resolved "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" onetime@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + resolved "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" dependencies: mimic-fn "^1.0.0" @@ -7308,14 +6904,14 @@ opener@~1.4.1: optimist@^0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + resolved "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" dependencies: minimist "~0.0.1" wordwrap "~0.0.2" optionator@^0.8.2: version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: deep-is "~0.1.3" fast-levenshtein "~2.0.4" @@ -7326,7 +6922,7 @@ optionator@^0.8.2: ora@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" + resolved "https://registry.npmjs.org/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" dependencies: chalk "^2.3.1" cli-cursor "^2.1.0" @@ -7337,50 +6933,66 @@ ora@^2.0.0: os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" os-shim@^0.1.2: version "0.1.3" - resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" + resolved "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" osenv@0, osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4, osenv@^0.1.5, osenv@~0.1.3: version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" p-cancelable@^0.4.0: version "0.4.1" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" + resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" p-finally@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" p-is-promise@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + resolved "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + +p-is-promise@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz#7554e3d572109a87e1f3f53f6a7d85d1b194f4c5" p-limit@^1.1.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" dependencies: p-try "^1.0.0" p-limit@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec" + version "2.1.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz#1d5a0d20fb12707c758a655f6bbc4386b5930d68" dependencies: p-try "^2.0.0" p-locate@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" dependencies: p-limit "^1.1.0" @@ -7392,13 +7004,13 @@ p-locate@^3.0.0: p-timeout@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" + resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" dependencies: p-finally "^1.0.0" p-try@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" p-try@^2.0.0: version "2.0.0" @@ -7406,59 +7018,56 @@ p-try@^2.0.0: package-json@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" + resolved "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" dependencies: got "^6.7.1" registry-auth-token "^3.0.1" registry-url "^3.0.3" semver "^5.1.0" -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" +parent-module@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.0.tgz#df250bdc5391f4a085fb589dad761f5ad6b865b5" dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" + callsites "^3.0.0" parse-json@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" dependencies: error-ex "^1.2.0" parse-ms@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d" + resolved "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d" parse-passwd@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" parseqs@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + resolved "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" dependencies: better-assert "~1.0.0" parseuri@0.0.5: version "0.0.5" - resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + resolved "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" dependencies: better-assert "~1.0.0" parseurl@~1.3.2: version "1.3.2" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" pascalcase@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" passwd-user@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/passwd-user/-/passwd-user-1.2.1.tgz#a01a5dc639ef007dc56364b8178569080ad3a7b8" + resolved "https://registry.npmjs.org/passwd-user/-/passwd-user-1.2.1.tgz#a01a5dc639ef007dc56364b8178569080ad3a7b8" dependencies: exec-file-sync "^2.0.0" @@ -7470,54 +7079,59 @@ path-array@^1.0.0: path-exists@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" dependencies: pinkie-promise "^2.0.0" path-exists@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" path-is-absolute@1.0.1, path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - -path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" -path-parse@^1.0.6: +path-parse@^1.0.5, path-parse@^1.0.6: version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" path-posix@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + resolved "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + +path-root-regex@^0.1.0: + version "0.1.2" + resolved "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" + +path-root@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" + dependencies: + path-root-regex "^0.1.0" path-to-regexp@0.1.7: version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" path-type@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" dependencies: graceful-fs "^4.1.2" pify "^2.0.0" pinkie-promise "^2.0.0" -pathval@^1.0.0: +pathval@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" + resolved "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" performance-now@^2.1.0: version "2.1.0" @@ -7525,21 +7139,21 @@ performance-now@^2.1.0: pify@^2.0.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" pify@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" pinkie-promise@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" pkg-up@^2.0.0: version "2.0.0" @@ -7547,13 +7161,9 @@ pkg-up@^2.0.0: dependencies: find-up "^2.1.0" -pluralize@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" - portfinder@^1.0.15: - version "1.0.19" - resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.19.tgz#07e87914a55242dcda5b833d42f018d6875b595f" + version "1.0.20" + resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz#bea68632e54b2e13ab7b0c4775e9b41bf270e44a" dependencies: async "^1.5.2" debug "^2.2.0" @@ -7561,23 +7171,19 @@ portfinder@^1.0.15: posix-character-classes@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + resolved "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" prelude-ls@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" prepend-http@^1.0.1: version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" prepend-http@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" pretender@^2.1.0: version "2.1.1" @@ -7594,13 +7200,12 @@ prettier-linter-helpers@^1.0.0: fast-diff "^1.1.2" prettier@^1.15.3: - version "1.15.3" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.15.3.tgz#1feaac5bdd181237b54dbe65d874e02a1472786a" - integrity sha512-gAU9AGAPMaKb3NNSUUuhhFAS7SCO4ALTN4nRIn6PJ075Qd28Yn2Ig2ahEJWdJwJmlEBTUfC7mMUSFy8MwsOCfg== + version "1.16.4" + resolved "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz#73e37e73e018ad2db9c76742e2647e21790c9717" pretty-ms@^3.1.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-3.2.0.tgz#87a8feaf27fc18414d75441467d411d6e6098a25" + resolved "https://registry.npmjs.org/pretty-ms/-/pretty-ms-3.2.0.tgz#87a8feaf27fc18414d75441467d411d6e6098a25" dependencies: parse-ms "^1.0.0" @@ -7610,7 +7215,7 @@ printf@^0.5.1: private@^0.1.6, private@^0.1.8, private@~0.1.5: version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + resolved "https://registry.npmjs.org/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" process-nextick-args@~1.0.6: version "1.0.7" @@ -7618,21 +7223,21 @@ process-nextick-args@~1.0.6: process-nextick-args@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" process-relative-require@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" + resolved "https://registry.npmjs.org/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" dependencies: node-modules-path "^1.0.0" progress@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" + version "2.0.3" + resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" promise-map-series@^0.2.1, promise-map-series@^0.2.3: version "0.2.3" - resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" + resolved "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" dependencies: rsvp "^3.0.14" @@ -7654,13 +7259,6 @@ proto-list@~1.2.1: version "1.2.4" resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" -proxy-addr@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" - dependencies: - forwarded "~0.1.2" - ipaddr.js "1.6.0" - proxy-addr@~2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" @@ -7668,13 +7266,9 @@ proxy-addr@~2.0.4: forwarded "~0.1.2" ipaddr.js "1.8.0" -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - -psl@^1.1.24: - version "1.1.28" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.28.tgz#4fb6ceb08a1e2214d4fd4de0ca22dae13740bc7b" +psl@^1.1.24, psl@^1.1.28: + version "1.1.31" + resolved "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" pump@^3.0.0: version "3.0.0" @@ -7685,23 +7279,23 @@ pump@^3.0.0: punycode@^1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - -qs@6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" -qs@6.5.2, qs@^6.4.0, qs@~6.5.2: +qs@6.5.2, qs@~6.5.2: version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + +qs@^6.4.0: + version "6.6.0" + resolved "https://registry.npmjs.org/qs/-/qs-6.6.0.tgz#a99c0f69a8d26bf7ef012f871cdabb0aee4424c2" qs@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" + resolved "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" qs@~5.2.0: version "5.2.1" @@ -7709,7 +7303,7 @@ qs@~5.2.0: query-string@^5.0.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + resolved "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" dependencies: decode-uri-component "^0.2.0" object-assign "^4.1.0" @@ -7717,23 +7311,22 @@ query-string@^5.0.1: quibble@^0.5.5: version "0.5.5" - resolved "https://registry.yarnpkg.com/quibble/-/quibble-0.5.5.tgz#669fb731520a923e0a98f8076b7eb55e409f73f9" + resolved "https://registry.npmjs.org/quibble/-/quibble-0.5.5.tgz#669fb731520a923e0a98f8076b7eb55e409f73f9" dependencies: lodash "^4.17.2" resolve "^1.7.1" quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: version "0.1.8" - resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" + resolved "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" dependencies: mktemp "~0.4.0" rimraf "^2.5.4" underscore.string "~3.3.4" -qunit@^2.8.0: +qunit@^2.9.1: version "2.9.1" - resolved "https://registry.yarnpkg.com/qunit/-/qunit-2.9.1.tgz#e11008d62e5f19ded60a20899a0cf7c3ec573b2d" - integrity sha512-ipXgW4SD557GrQtiBhj+g7eHk76pmSIYKglEXuAD/WsC06XzXDc4r9qlm4DSG5LxqxvpgK8naGlJ1Zcnj9/NdQ== + resolved "https://registry.npmjs.org/qunit/-/qunit-2.9.1.tgz#e11008d62e5f19ded60a20899a0cf7c3ec573b2d" dependencies: commander "2.12.2" js-reporters "1.2.1" @@ -7741,26 +7334,9 @@ qunit@^2.8.0: node-watch "0.6.0" resolve "1.5.0" -randomatic@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.0.0.tgz#d35490030eb4f7578de292ce6dfb04a91a128923" - dependencies: - is-number "^4.0.0" - kind-of "^6.0.0" - math-random "^1.0.1" - range-parser@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - -raw-body@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" - dependencies: - bytes "3.0.0" - http-errors "1.6.2" - iconv-lite "0.4.19" - unpipe "1.0.0" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" raw-body@2.3.3: version "2.3.3" @@ -7773,14 +7349,14 @@ raw-body@2.3.3: raw-body@~1.1.0: version "1.1.7" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" dependencies: bytes "1" string_decoder "0.10" -rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: +rc@^1.0.1, rc@^1.1.6: version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" dependencies: deep-extend "^0.6.0" ini "~1.3.0" @@ -7829,14 +7405,14 @@ read-package-tree@~5.1.2: read-pkg-up@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" dependencies: find-up "^1.0.0" read-pkg "^1.0.0" read-pkg@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" @@ -7850,7 +7426,7 @@ read@1, read@~1.0.1, read@~1.0.7: "readable-stream@1 || 2", readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -7862,7 +7438,7 @@ read@1, read@~1.0.1, read@~1.0.7: readable-stream@~1.0.2: version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -7871,7 +7447,7 @@ readable-stream@~1.0.2: readable-stream@~2.0.5: version "2.0.6" - resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" dependencies: core-util-is "~1.0.0" inherits "~2.0.1" @@ -7898,7 +7474,7 @@ realize-package-specifier@~3.0.1: recast@^0.11.3: version "0.11.23" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" + resolved "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" dependencies: ast-types "0.9.6" esprima "~3.1.0" @@ -7907,14 +7483,14 @@ recast@^0.11.3: redent@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + resolved "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" dependencies: indent-string "^2.1.0" strip-indent "^1.0.1" redeyed@~1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" + resolved "https://registry.npmjs.org/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" dependencies: esprima "~3.0.0" @@ -7926,28 +7502,27 @@ regenerate-unicode-properties@^7.0.0: regenerate@^1.2.1, regenerate@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" regenerator-runtime@^0.10.5: version "0.10.5" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" -regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1: +regenerator-runtime@^0.11.0: version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" regenerator-runtime@^0.12.0: version "0.12.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" - integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" regenerator-runtime@^0.9.5: version "0.9.6" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" regenerator-transform@^0.10.0: version "0.10.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" dependencies: babel-runtime "^6.18.0" babel-types "^6.19.0" @@ -7959,22 +7534,16 @@ regenerator-transform@^0.13.3: dependencies: private "^0.1.6" -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - dependencies: - is-equal-shallow "^0.1.3" - regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + resolved "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" dependencies: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexpp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.0.tgz#b2a7534a85ca1b033bcf5ce9ff8e56d4e0755365" +regexp-tree@^0.1.0: + version "0.1.5" + resolved "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.5.tgz#7cd71fca17198d04b4176efd79713f2998009397" regexpp@^2.0.1: version "2.0.1" @@ -7982,78 +7551,78 @@ regexpp@^2.0.1: regexpu-core@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" dependencies: regenerate "^1.2.1" regjsgen "^0.2.0" regjsparser "^0.1.4" regexpu-core@^4.1.3, regexpu-core@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.2.0.tgz#a3744fa03806cffe146dea4421a3e73bdcc47b1d" + version "4.4.0" + resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.4.0.tgz#8d43e0d1266883969720345e70c275ee0aec0d32" dependencies: regenerate "^1.4.0" regenerate-unicode-properties "^7.0.0" - regjsgen "^0.4.0" - regjsparser "^0.3.0" + regjsgen "^0.5.0" + regjsparser "^0.6.0" unicode-match-property-ecmascript "^1.0.4" unicode-match-property-value-ecmascript "^1.0.2" registry-auth-token@^3.0.1: version "3.3.2" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" + resolved "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" dependencies: rc "^1.1.6" safe-buffer "^5.0.1" registry-url@^3.0.3: version "3.1.0" - resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + resolved "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" dependencies: rc "^1.0.1" regjsgen@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" -regjsgen@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.4.0.tgz#c1eb4c89a209263f8717c782591523913ede2561" +regjsgen@^0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd" regjsparser@^0.1.4: version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" dependencies: jsesc "~0.5.0" -regjsparser@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.3.0.tgz#3c326da7fcfd69fa0d332575a41c8c0cdf588c96" +regjsparser@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c" dependencies: jsesc "~0.5.0" remote-git-tags@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/remote-git-tags/-/remote-git-tags-2.0.0.tgz#1152f39cf8b5268ae0e4307636ef741ec341664c" + resolved "https://registry.npmjs.org/remote-git-tags/-/remote-git-tags-2.0.0.tgz#1152f39cf8b5268ae0e4307636ef741ec341664c" dependencies: git-fetch-pack "^0.1.1" git-transport-protocol "^0.1.0" remove-trailing-separator@^1.0.1: version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + version "1.1.3" + resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" -repeat-string@^1.5.2, repeat-string@^1.6.1: +repeat-string@^1.6.1: version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" repeating@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + resolved "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" dependencies: is-finite "^1.0.0" @@ -8084,7 +7653,7 @@ request@2, request@^2.47.0: request@~2.40.0: version "2.40.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" + resolved "https://registry.npmjs.org/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" dependencies: forever-agent "~0.5.0" json-stringify-safe "~5.0.0" @@ -8103,7 +7672,7 @@ request@~2.40.0: request@~2.67.0: version "2.67.0" - resolved "http://registry.npmjs.org/request/-/request-2.67.0.tgz#8af74780e2bf11ea0ae9aa965c11f11afd272742" + resolved "https://registry.npmjs.org/request/-/request-2.67.0.tgz#8af74780e2bf11ea0ae9aa965c11f11afd272742" dependencies: aws-sign2 "~0.6.0" bl "~1.0.0" @@ -8130,20 +7699,21 @@ require-dir@^0.3.0: version "0.3.2" resolved "https://registry.npmjs.org/require-dir/-/require-dir-0.3.2.tgz#c1d5c75e9fbffde9f2e6b33e383db4f594b5a6a9" +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + require-relative@^0.8.7: version "0.8.7" - resolved "https://registry.yarnpkg.com/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" - -require-uncached@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" - dependencies: - caller-path "^0.1.0" - resolve-from "^1.0.0" + resolved "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz#7999539fc9e047a37928fa196f8e1563dabd36de" requires-port@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" reselect@^3.0.1: version "3.0.1" @@ -8151,14 +7721,14 @@ reselect@^3.0.1: resolve-dir@^1.0.0, resolve-dir@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + resolved "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" dependencies: expand-tilde "^2.0.0" global-modules "^1.0.0" -resolve-from@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" resolve-path@^1.4.0: version "1.4.0" @@ -8169,75 +7739,74 @@ resolve-path@^1.4.0: resolve-url@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" resolve@1.5.0: version "1.5.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: path-parse "^1.0.5" -resolve@^1.1.6, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.7.1, resolve@^1.8.1, resolve@^1.9.0: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.7.1, resolve@^1.8.1, resolve@^1.9.0: version "1.10.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" - integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== + resolved "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" dependencies: path-parse "^1.0.6" responselike@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" dependencies: lowercase-keys "^1.0.0" restore-cursor@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" dependencies: exit-hook "^1.0.0" onetime "^1.0.0" restore-cursor@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" dependencies: onetime "^2.0.0" signal-exit "^3.0.2" ret@~0.1.10: version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" retry@^0.8.0, retry@~0.8.0: version "0.8.0" resolved "https://registry.npmjs.org/retry/-/retry-0.8.0.tgz#2367628dc0edb247b1eab649dc53ac8628ac2d5f" -rimraf@2, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" +rimraf@2, rimraf@2.6.3, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: + version "2.6.3" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" dependencies: - glob "^7.0.5" + glob "^7.1.3" rimraf@~2.2.6: version "2.2.8" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" rimraf@~2.5.0: version "2.5.4" - resolved "http://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" dependencies: glob "^7.0.5" rollup-pluginutils@^2.0.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.3.0.tgz#478ace04bd7f6da2e724356ca798214884738fc4" + version "2.4.1" + resolved "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.4.1.tgz#de43ab54965bbf47843599a7f3adceb723de38db" dependencies: - estree-walker "^0.5.2" - micromatch "^2.3.11" + estree-walker "^0.6.0" + micromatch "^3.1.10" rollup@^0.57.1: version "0.57.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.57.1.tgz#0bb28be6151d253f67cf4a00fea48fb823c74027" + resolved "https://registry.npmjs.org/rollup/-/rollup-0.57.1.tgz#0bb28be6151d253f67cf4a00fea48fb823c74027" dependencies: "@types/acorn" "^4.0.3" acorn "^5.5.3" @@ -8252,16 +7821,16 @@ rollup@^0.57.1: sourcemap-codec "^1.4.1" route-recognizer@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.3.tgz#1d365e27fa6995e091675f7dc940a8c00353bd29" + version "0.3.4" + resolved "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.3.4.tgz#39ab1ffbce1c59e6d2bdca416f0932611e4f3ca3" rsvp@3.0.14: version "3.0.14" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.0.14.tgz#9d2968cf36d878d3bb9a9a5a4b8e1ff55a76dd31" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.0.14.tgz#9d2968cf36d878d3bb9a9a5a4b8e1ff55a76dd31" rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.1.0, rsvp@^3.3.3: version "3.6.2" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" rsvp@^4.7.0, rsvp@^4.8.1, rsvp@^4.8.2, rsvp@^4.8.3, rsvp@^4.8.4: version "4.8.4" @@ -8269,68 +7838,49 @@ rsvp@^4.7.0, rsvp@^4.8.1, rsvp@^4.8.2, rsvp@^4.8.3, rsvp@^4.8.4: rsvp@~3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" run-async@^2.2.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + resolved "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" dependencies: is-promise "^2.1.0" rx@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + resolved "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" -rxjs@^6.1.0: - version "6.3.3" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz#3c6a7fa420e844a81390fb1158a9ec614f4bad55" +rxjs@^6.4.0: + version "6.4.0" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504" dependencies: tslib "^1.9.0" -safe-buffer@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" safe-json-parse@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" + resolved "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" safe-regex@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" dependencies: ret "~0.1.10" "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - -sane@^2.4.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" - dependencies: - anymatch "^2.0.0" - capture-exit "^1.2.0" - exec-sh "^0.2.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - watch "~0.18.0" - optionalDependencies: - fsevents "^1.2.3" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" sane@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/sane/-/sane-4.0.1.tgz#af1e10466e924e1b888c104bb9925a0f1beb46dd" + version "4.0.2" + resolved "https://registry.npmjs.org/sane/-/sane-4.0.2.tgz#5bd4a3f1268fd7a921a2dc657047de635c8f8f25" dependencies: anymatch "^2.0.0" capture-exit "^1.2.0" - exec-sh "^0.2.0" + exec-sh "^0.3.2" execa "^1.0.0" fb-watchman "^2.0.0" micromatch "^3.1.4" @@ -8338,25 +7888,21 @@ sane@^4.0.0: walker "~1.0.5" watch "~0.18.0" -sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - "semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.6.0" resolved "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" semver@^4.3.1: version "4.3.6" - resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + resolved "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" semver@~5.1.0: version "5.1.1" - resolved "http://registry.npmjs.org/semver/-/semver-5.1.1.tgz#a3292a373e6f3e0798da0b20641b9a9c5bc47e19" + resolved "https://registry.npmjs.org/semver/-/semver-5.1.1.tgz#a3292a373e6f3e0798da0b20641b9a9c5bc47e19" send@0.16.2: version "0.16.2" - resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + resolved "https://registry.npmjs.org/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" dependencies: debug "2.6.9" depd "~1.1.2" @@ -8374,20 +7920,20 @@ send@0.16.2: serve-static@1.13.2: version "1.13.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" parseurl "~1.3.2" send "0.16.2" -set-blocking@~2.0.0: +set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" set-value@^0.4.3: version "0.4.3" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + resolved "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -8396,20 +7942,16 @@ set-value@^0.4.3: set-value@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + resolved "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" is-plain-object "^2.0.3" split-string "^3.0.1" -setprototypeof@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" - setprototypeof@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" sha@~2.0.1: version "2.0.1" @@ -8420,17 +7962,17 @@ sha@~2.0.1: shebang-command@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" dependencies: shebang-regex "^1.0.0" shebang-regex@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" shellwords@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" sigmund@~1.0.0: version "1.0.1" @@ -8438,15 +7980,9 @@ sigmund@~1.0.0: signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - -silent-error@^1.0.0, silent-error@^1.0.1, silent-error@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/silent-error/-/silent-error-1.1.0.tgz#2209706f1c850a9f1d10d0d840918b46f26e1bc9" - dependencies: - debug "^2.2.0" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" -silent-error@^1.1.1: +silent-error@^1.0.0, silent-error@^1.0.1, silent-error@^1.1.0, silent-error@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/silent-error/-/silent-error-1.1.1.tgz#f72af5b0d73682a2ba1778b7e32cd8aa7c2d8662" dependencies: @@ -8454,12 +7990,14 @@ silent-error@^1.1.1: slash@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" -slice-ansi@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" slide@^1.1.3, slide@^1.1.5, slide@~1.1.3, slide@~1.1.6: @@ -8468,7 +8006,7 @@ slide@^1.1.3, slide@^1.1.5, slide@~1.1.3, slide@~1.1.6: snapdragon-node@^2.0.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" dependencies: define-property "^1.0.0" isobject "^3.0.0" @@ -8476,13 +8014,13 @@ snapdragon-node@^2.0.1: snapdragon-util@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + resolved "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" dependencies: kind-of "^3.2.0" snapdragon@^0.8.1: version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + resolved "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" dependencies: base "^0.11.1" debug "^2.2.0" @@ -8495,7 +8033,7 @@ snapdragon@^0.8.1: sntp@0.2.x: version "0.2.4" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" + resolved "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz#fb885f18b0f3aad189f824862536bceeec750900" dependencies: hoek "0.9.x" @@ -8507,49 +8045,49 @@ sntp@1.x.x: socket.io-adapter@~1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" + resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" -socket.io-client@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" +socket.io-client@2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.2.0.tgz#84e73ee3c43d5020ccc1a258faeeb9aec2723af7" dependencies: backo2 "1.0.2" base64-arraybuffer "0.1.5" component-bind "1.0.0" component-emitter "1.2.1" debug "~3.1.0" - engine.io-client "~3.2.0" + engine.io-client "~3.3.1" has-binary2 "~1.0.2" has-cors "1.1.0" indexof "0.0.1" object-component "0.0.3" parseqs "0.0.5" parseuri "0.0.5" - socket.io-parser "~3.2.0" + socket.io-parser "~3.3.0" to-array "0.1.4" -socket.io-parser@~3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" +socket.io-parser@~3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f" dependencies: component-emitter "1.2.1" debug "~3.1.0" isarray "2.0.1" socket.io@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" + version "2.2.0" + resolved "https://registry.npmjs.org/socket.io/-/socket.io-2.2.0.tgz#f0f633161ef6712c972b307598ecd08c9b1b4d5b" dependencies: - debug "~3.1.0" - engine.io "~3.2.0" + debug "~4.1.0" + engine.io "~3.3.1" has-binary2 "~1.0.2" socket.io-adapter "~1.1.0" - socket.io-client "2.1.1" - socket.io-parser "~3.2.0" + socket.io-client "2.2.0" + socket.io-parser "~3.3.0" sort-keys@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" dependencies: is-plain-obj "^1.0.0" @@ -8558,8 +8096,8 @@ sort-object-keys@^1.1.2: resolved "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.2.tgz#d3a6c48dc2ac97e6bc94367696e03f6d09d37952" sort-package-json@^1.15.0: - version "1.16.0" - resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.16.0.tgz#087f5ce05b6faca373312e7124918e0d68492d7b" + version "1.19.0" + resolved "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.19.0.tgz#3e6819147d75680832890523e753b8992166a442" dependencies: detect-indent "^5.0.0" sort-object-keys "^1.1.2" @@ -8570,7 +8108,7 @@ sorted-object@~1.0.0: source-map-resolve@^0.5.0: version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + resolved "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" dependencies: atob "^2.1.1" decode-uri-component "^0.2.0" @@ -8580,52 +8118,52 @@ source-map-resolve@^0.5.0: source-map-support@^0.4.15: version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" dependencies: source-map "^0.5.6" -source-map-support@~0.5.6: - version "0.5.6" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.6.tgz#4435cee46b1aab62b8e8610ce60f788091c51c13" +source-map-support@~0.5.9: + version "0.5.10" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz#2214080bc9d51832511ee2bab96e3c2f9353120c" dependencies: buffer-from "^1.0.0" source-map "^0.6.0" source-map-url@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" + resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" source-map-url@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" source-map@0.4.x, source-map@^0.4.2: version "0.4.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: amdefine ">=0.0.4" source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0: version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" source-map@~0.1.x: version "0.1.43" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" dependencies: amdefine ">=0.0.4" sourcemap-codec@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.1.tgz#c8fd92d91889e902a07aee392bdd2c5863958ba2" + version "1.4.4" + resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz#c63ea927c029dd6bd9a2b7fa03b3fec02ad56e9f" sourcemap-validator@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/sourcemap-validator/-/sourcemap-validator-1.1.0.tgz#00454547d1682186e1498a7208e022e8dfa8738f" + resolved "https://registry.npmjs.org/sourcemap-validator/-/sourcemap-validator-1.1.0.tgz#00454547d1682186e1498a7208e022e8dfa8738f" dependencies: jsesc "~0.3.x" lodash.foreach "~2.3.x" @@ -8634,62 +8172,62 @@ sourcemap-validator@^1.1.0: spawn-args@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" + resolved "https://registry.npmjs.org/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" spawn-sync@^1.0.11, spawn-sync@^1.0.15: version "1.0.15" - resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" + resolved "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" dependencies: concat-stream "^1.4.7" os-shim "^0.1.2" spawnback@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" + resolved "https://registry.npmjs.org/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" spdx-correct@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" + version "3.1.0" + resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz#2c7ae61056c714a5b9b9b2b2af7d311ef5c78fe9" + version "2.2.0" + resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" spdx-expression-parse@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87" + version "3.0.3" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz#81c0ce8f21474756148bbb5f3bfc0f36bf15d76e" split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + resolved "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" dependencies: extend-shallow "^3.0.0" sprintf-js@^1.0.3: - version "1.1.1" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.1.tgz#36be78320afe5801f6cea3ee78b6e5aab940ea0c" + version "1.1.2" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" sri-toolbox@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" + resolved "https://registry.npmjs.org/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" sshpk@^1.7.0: - version "1.15.1" - resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.15.1.tgz#b79a089a732e346c6e0714830f36285cd38191a2" + version "1.16.1" + resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -8703,40 +8241,40 @@ sshpk@^1.7.0: stagehand@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/stagehand/-/stagehand-1.0.0.tgz#79515e2ad3a02c63f8720c7df9b6077ae14276d9" + resolved "https://registry.npmjs.org/stagehand/-/stagehand-1.0.0.tgz#79515e2ad3a02c63f8720c7df9b6077ae14276d9" dependencies: debug "^4.1.0" static-extend@^0.1.1: version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + resolved "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" dependencies: define-property "^0.2.5" object-copy "^0.1.0" -"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2": +"statuses@>= 1.4.0 < 2": version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" statuses@~1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" statuses@~1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" strict-uri-encode@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" string-template@~0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" string-width@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" @@ -8744,104 +8282,124 @@ string-width@^1.0.1: "string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string-width@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/string-width/-/string-width-3.0.0.tgz#5a1690a57cc78211fffd9bf24bbe24d090604eb1" + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.0.0" + string_decoder@0.10, string_decoder@~0.10.x: version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" string_decoder@~1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" dependencies: safe-buffer "~5.1.0" stringify-object-es5@^2.5.0: version "2.5.0" - resolved "https://registry.yarnpkg.com/stringify-object-es5/-/stringify-object-es5-2.5.0.tgz#057c3c9a90a127339bb9d1704a290bb7bd0a1ec5" + resolved "https://registry.npmjs.org/stringify-object-es5/-/stringify-object-es5-2.5.0.tgz#057c3c9a90a127339bb9d1704a290bb7bd0a1ec5" dependencies: is-plain-obj "^1.0.0" is-regexp "^1.0.0" stringstream@~0.0.4: version "0.0.6" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" + resolved "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" dependencies: ansi-regex "^2.0.0" strip-ansi@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" dependencies: ansi-regex "^3.0.0" +strip-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" + dependencies: + ansi-regex "^4.0.0" + strip-bom@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" dependencies: is-utf8 "^0.2.0" strip-bom@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" strip-eof@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" strip-indent@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" dependencies: get-stdin "^4.0.1" -strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: +strip-json-comments@2.0.1, strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" styled_string@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" + resolved "https://registry.npmjs.org/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" sum-up@^1.0.1: version "1.0.3" - resolved "https://registry.yarnpkg.com/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" + resolved "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" dependencies: chalk "^1.0.0" -supports-color@5.4.0, supports-color@^5.3.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" +supports-color@6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" dependencies: has-flag "^3.0.0" supports-color@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + dependencies: + has-flag "^3.0.0" symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" + resolved "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#5d49108e2ab824a34069b68974486c290020b393" -table@^5.0.2: - version "5.1.0" - resolved "https://registry.npmjs.org/table/-/table-5.1.0.tgz#69a54644f6f01ad1628f8178715b408dc6bf11f7" +table@^5.2.3: + version "5.2.3" + resolved "https://registry.npmjs.org/table/-/table-5.2.3.tgz#cde0cc6eb06751c009efab27e8c820ca5b67b7f2" dependencies: - ajv "^6.5.3" - lodash "^4.17.10" - slice-ansi "1.0.0" - string-width "^2.1.1" + ajv "^6.9.1" + lodash "^4.17.11" + slice-ansi "^2.1.0" + string-width "^3.0.0" tap-parser@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-7.0.0.tgz#54db35302fda2c2ccc21954ad3be22b2cba42721" + resolved "https://registry.npmjs.org/tap-parser/-/tap-parser-7.0.0.tgz#54db35302fda2c2ccc21954ad3be22b2cba42721" dependencies: events-to-array "^1.0.1" js-yaml "^3.2.7" @@ -8855,46 +8413,33 @@ tar@^2.0.0, tar@~2.2.1: fstream "^1.0.2" inherits "2" -tar@^4: - version "4.4.4" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" - dependencies: - chownr "^1.0.1" - fs-minipass "^1.2.5" - minipass "^2.3.3" - minizlib "^1.1.0" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.2" - temp@0.8.3: version "0.8.3" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" + resolved "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" dependencies: os-tmpdir "^1.0.0" rimraf "~2.2.6" terser@^3.7.5: - version "3.8.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-3.8.1.tgz#cb70070ac9e0a71add169dfb63c0a64fca2738ac" + version "3.16.1" + resolved "https://registry.npmjs.org/terser/-/terser-3.16.1.tgz#5b0dd4fa1ffd0b0b43c2493b2c364fd179160493" dependencies: - commander "~2.16.0" + commander "~2.17.1" source-map "~0.6.1" - source-map-support "~0.5.6" + source-map-support "~0.5.9" testdouble@^3.2.6: - version "3.8.1" - resolved "https://registry.yarnpkg.com/testdouble/-/testdouble-3.8.1.tgz#8c74b6807f82fb07c2387a0640b4ae594b09b964" + version "3.10.0" + resolved "https://registry.npmjs.org/testdouble/-/testdouble-3.10.0.tgz#5bb0149da39d3d5afc085dbea9bc5e45d0c1470f" dependencies: - es6-map "^0.1.5" - lodash "^4.17.4" + lodash "^4.17.11" quibble "^0.5.5" stringify-object-es5 "^2.5.0" theredoc "^1.0.0" testem@^2.9.2: - version "2.13.0" - resolved "https://registry.npmjs.org/testem/-/testem-2.13.0.tgz#587f3460a923779949804efac0fcc2015835dd63" + version "2.14.0" + resolved "https://registry.npmjs.org/testem/-/testem-2.14.0.tgz#418a9a15843f68381659c6a486abb4ea48d06c29" dependencies: backbone "^1.1.2" bluebird "^3.4.6" @@ -8930,28 +8475,28 @@ text-table@^0.2.0, text-table@~0.2.0: resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" "textextensions@1 || 2": - version "2.2.0" - resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" + version "2.4.0" + resolved "https://registry.npmjs.org/textextensions/-/textextensions-2.4.0.tgz#6a143a985464384cc2cff11aea448cd5b018e72b" theredoc@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/theredoc/-/theredoc-1.0.0.tgz#bcace376af6feb1873efbdd0f91ed026570ff062" + resolved "https://registry.npmjs.org/theredoc/-/theredoc-1.0.0.tgz#bcace376af6feb1873efbdd0f91ed026570ff062" through@^2.3.6, through@^2.3.8: version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" through@~2.2.0, through@~2.2.7: version "2.2.7" - resolved "https://registry.yarnpkg.com/through/-/through-2.2.7.tgz#6e8e21200191d4eb6a99f6f010df46aa1c6eb2bd" + resolved "https://registry.npmjs.org/through/-/through-2.2.7.tgz#6e8e21200191d4eb6a99f6f010df46aa1c6eb2bd" time-zone@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/time-zone/-/time-zone-1.0.0.tgz#99c5bf55958966af6d06d83bdf3800dc82faec5d" + resolved "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz#99c5bf55958966af6d06d83bdf3800dc82faec5d" timed-out@^4.0.0, timed-out@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" tiny-lr@^1.1.1: version "1.1.1" @@ -8966,61 +8511,61 @@ tiny-lr@^1.1.1: tmp-sync@^1.0.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" + resolved "https://registry.npmjs.org/tmp-sync/-/tmp-sync-1.1.2.tgz#ba04d94a8ed9c0f35a54739970792f997a6cc1c8" dependencies: fs-sync "^1.0.4" osenv "^0.1.0" tmp@0.0.28: version "0.0.28" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" dependencies: os-tmpdir "~1.0.1" tmp@0.0.33, tmp@^0.0.33: version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" dependencies: os-tmpdir "~1.0.2" tmp@^0.0.29: version "0.0.29" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" dependencies: os-tmpdir "~1.0.1" tmpl@1.0.x: version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" to-array@0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + resolved "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" to-fast-properties@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" to-object-path@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" dependencies: kind-of "^3.0.2" to-regex-range@^2.1.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" dependencies: is-number "^3.0.0" repeat-string "^1.6.1" to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + resolved "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" dependencies: define-property "^2.0.2" extend-shallow "^3.0.2" @@ -9029,36 +8574,44 @@ to-regex@^3.0.1, to-regex@^3.0.2: to-utf8@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" + resolved "https://registry.npmjs.org/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" -tough-cookie@>=0.12.0, tough-cookie@~2.4.3: - version "2.4.3" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" +tough-cookie@>=0.12.0: + version "3.0.1" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" dependencies: - psl "^1.1.24" - punycode "^1.4.1" + ip-regex "^2.1.0" + psl "^1.1.28" + punycode "^2.1.1" tough-cookie@~2.2.0: version "2.2.2" resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz#c83a1830f4e5ef0b93ef2a3488e724f8de016ac7" +tough-cookie@~2.4.3: + version "2.4.3" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + dependencies: + psl "^1.1.24" + punycode "^1.4.1" + tree-sync@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.2.2.tgz#2cf76b8589f59ffedb58db5a3ac7cb013d0158b7" + version "1.4.0" + resolved "https://registry.npmjs.org/tree-sync/-/tree-sync-1.4.0.tgz#314598d13abaf752547d9335b8f95d9a137100d6" dependencies: debug "^2.2.0" fs-tree-diff "^0.5.6" mkdirp "^0.5.1" quick-temp "^0.1.5" - walk-sync "^0.2.7" + walk-sync "^0.3.3" trim-newlines@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" trim-right@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" tslib@^1.9.0: version "1.9.3" @@ -9080,41 +8633,40 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: type-check@~0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" dependencies: prelude-ls "~1.1.2" type-detect@0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" type-detect@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" -type-detect@^4.0.0: +type-detect@^4.0.0, type-detect@^4.0.5: version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" -type-is@~1.6.15, type-is@~1.6.16: +type-is@~1.6.16: version "1.6.16" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" dependencies: media-typer "0.3.0" mime-types "~2.1.18" typedarray@^0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" typescript@~3.3.3: version "3.3.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.3.tgz#f1657fc7daa27e1a8930758ace9ae8da31403221" - integrity sha512-Y21Xqe54TBVp+VDSNbuDYdGw0BpoR/Q6wo/+35M8PAU0vipahnyduJWirxxdxjsAkS7hue53x2zp8gz7F05u0A== + resolved "https://registry.npmjs.org/typescript/-/typescript-3.3.3.tgz#f1657fc7daa27e1a8930758ace9ae8da31403221" uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" + version "1.0.6" + resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" uglify-js@^3.1.4: version "3.4.9" @@ -9127,25 +8679,20 @@ uid-number@0.0.6: version "0.0.6" resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" -ultron@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - umask@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" underscore.string@^3.2.2, underscore.string@~3.3.4: version "3.3.5" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.5.tgz#fc2ad255b8bd309e239cbc5816fd23a9b7ea4023" - integrity sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg== + resolved "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz#fc2ad255b8bd309e239cbc5816fd23a9b7ea4023" dependencies: sprintf-js "^1.0.3" util-deprecate "^1.0.2" underscore@>=1.8.3: version "1.9.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" + resolved "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" @@ -9168,7 +8715,7 @@ unicode-property-aliases-ecmascript@^1.0.4: union-value@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + resolved "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" dependencies: arr-union "^3.1.0" get-value "^2.0.6" @@ -9189,34 +8736,34 @@ unique-slug@^2.0.0: unique-string@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + resolved "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" dependencies: crypto-random-string "^1.0.0" universalify@^0.1.0: version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" unset-value@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + resolved "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" dependencies: has-value "^0.3.1" isobject "^3.0.0" untildify@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" + resolved "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" dependencies: os-homedir "^1.0.0" unzip-response@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" + resolved "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" uri-js@^4.2.2: version "4.2.2" @@ -9226,49 +8773,49 @@ uri-js@^4.2.2: urix@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" url-parse-lax@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" dependencies: prepend-http "^1.0.1" url-parse-lax@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" dependencies: prepend-http "^2.0.0" url-to-options@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + resolved "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" use@^3.1.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + resolved "https://registry.npmjs.org/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" user-info@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/user-info/-/user-info-1.0.0.tgz#81c82b7ed63e674c2475667653413b3c76fde239" + resolved "https://registry.npmjs.org/user-info/-/user-info-1.0.0.tgz#81c82b7ed63e674c2475667653413b3c76fde239" dependencies: os-homedir "^1.0.1" passwd-user "^1.2.1" username "^1.0.1" -username-sync@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/username-sync/-/username-sync-1.0.1.tgz#1cde87eefcf94b8822984d938ba2b797426dae1f" +username-sync@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/username-sync/-/username-sync-1.0.2.tgz#0a3697909fb7b5768d29e2921f573acfdd427592" username@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/username/-/username-1.0.1.tgz#e1f72295e3e58e06f002c6327ce06897a99cd67f" + resolved "https://registry.npmjs.org/username/-/username-1.0.1.tgz#e1f72295e3e58e06f002c6327ce06897a99cd67f" dependencies: meow "^3.4.0" util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" util-extend@^1.0.1: version "1.0.3" @@ -9276,22 +8823,22 @@ util-extend@^1.0.1: utils-merge@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" uuid@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" validate-npm-package-license@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338" + version "3.0.4" + resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" dependencies: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" validate-npm-package-name@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" dependencies: builtins "^1.0.3" @@ -9303,7 +8850,7 @@ validate-npm-package-name@~2.2.2: vary@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" verror@1.10.0: version "1.10.0" @@ -9313,36 +8860,37 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -walk-sync@^0.2.0, walk-sync@^0.2.5, walk-sync@^0.2.7: +walk-sync@^0.2.0, walk-sync@^0.2.5: version "0.2.7" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" -walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.2.tgz#4827280afc42d0e035367c4a4e31eeac0d136f75" +walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2, walk-sync@^0.3.3: + version "0.3.4" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.4.tgz#cf78486cc567d3a96b5b2237c6108017a5ffb9a4" dependencies: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" -walk-sync@^0.3.3: - version "0.3.3" - resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.3.tgz#1e9f12cd4fe6e0e6d4a0715b5cc7e30711d43cd1" +walk-sync@^1.0.0: + version "1.1.3" + resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-1.1.3.tgz#3b7b6468f068b5eba2278c931c57db3d39092969" dependencies: - ensure-posix-path "^1.0.0" - matcher-collection "^1.0.0" + "@types/minimatch" "^3.0.3" + ensure-posix-path "^1.1.0" + matcher-collection "^1.1.1" walker@~1.0.5: version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" dependencies: makeerror "1.0.x" watch-detector@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/watch-detector/-/watch-detector-0.1.0.tgz#e37b410d149e2a8bf263a4f8b71e2f667633dbf8" + resolved "https://registry.npmjs.org/watch-detector/-/watch-detector-0.1.0.tgz#e37b410d149e2a8bf263a4f8b71e2f667633dbf8" dependencies: heimdalljs-logger "^0.1.9" quick-temp "^0.1.8" @@ -9352,36 +8900,39 @@ watch-detector@^0.1.0: watch@~0.18.0: version "0.18.0" - resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + resolved "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" dependencies: exec-sh "^0.2.0" minimist "^1.2.0" wcwidth@^1.0.0, wcwidth@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" dependencies: defaults "^1.0.3" websocket-driver@>=0.5.1: version "0.7.0" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" + resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" dependencies: http-parser-js ">=0.4.0" websocket-extensions ">=0.1.1" websocket-extensions@>=0.1.1: version "0.1.3" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" whatwg-fetch@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" - integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== + resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" -which@1, which@^1.2.14, which@^1.2.9, which@^1.3.0: +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + +which@1, which@1.3.1, which@^1.2.14, which@^1.2.9, which@^1.3.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" dependencies: isexe "^2.0.0" @@ -9391,19 +8942,19 @@ which@~1.2.1: dependencies: isexe "^2.0.0" -wide-align@^1.1.0: +wide-align@1.1.3, wide-align@^1.1.0: version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" dependencies: string-width "^1.0.2 || 2" wordwrap@~0.0.2: version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" wordwrap@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" workerpool@^2.3.0, workerpool@^2.3.1: version "2.3.3" @@ -9411,13 +8962,20 @@ workerpool@^2.3.0, workerpool@^2.3.1: dependencies: object-assign "4.1.1" +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrappy@1, wrappy@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" write-file-atomic@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + version "2.4.2" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz#a7181706dfba17855d221140a9c06e15fcdd87b9" dependencies: graceful-fs "^4.1.11" imurmurhash "^0.1.4" @@ -9431,64 +8989,94 @@ write-file-atomic@~1.1.4: imurmurhash "^0.1.4" slide "^1.1.5" -write@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" +write@1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" dependencies: mkdirp "^0.5.1" -ws@~3.3.1: - version "3.3.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" +ws@~6.1.0: + version "6.1.4" + resolved "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" dependencies: async-limiter "~1.0.0" - safe-buffer "~5.1.0" - ultron "~1.1.0" xdg-basedir@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" xmldom@^0.1.19: version "0.1.27" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" + resolved "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" xmlhttprequest-ssl@~1.5.4: version "1.5.5" - resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" xtend@^4.0.0, xtend@~4.0.0: version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" +"y18n@^3.2.1 || ^4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" -yallist@^3.0.0, yallist@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" +yallist@^3.0.0: + version "3.0.3" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" -yam@^0.0.24: - version "0.0.24" - resolved "https://registry.yarnpkg.com/yam/-/yam-0.0.24.tgz#11e9630444735f66a561d29221407de6d037cd95" +yam@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/yam/-/yam-1.0.0.tgz#7f6c91dc0f5de75a031e6da6b3907c3d25ab0de5" dependencies: fs-extra "^4.0.2" lodash.merge "^4.6.0" +yargs-parser@11.1.1, yargs-parser@^11.1.1: + version "11.1.1" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-unparser@1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz#f2bb2a7e83cbc87bb95c8e572828a06c9add6e0d" + dependencies: + flat "^4.1.0" + lodash "^4.17.11" + yargs "^12.0.5" + +yargs@12.0.5, yargs@^12.0.5: + version "12.0.5" + resolved "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" + dependencies: + cliui "^4.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^11.1.1" + yeast@0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + resolved "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" yui@^3.18.1: version "3.18.1" - resolved "https://registry.yarnpkg.com/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" + resolved "https://registry.npmjs.org/yui/-/yui-3.18.1.tgz#e000269ec0a7b6fbc741cbb8fcbd0e65117b014c" dependencies: request "~2.40.0" yuidocjs@^0.10.0: version "0.10.2" - resolved "https://registry.yarnpkg.com/yuidocjs/-/yuidocjs-0.10.2.tgz#33924967ce619024cd70ef694e267d2f988f73f6" + resolved "https://registry.npmjs.org/yuidocjs/-/yuidocjs-0.10.2.tgz#33924967ce619024cd70ef694e267d2f988f73f6" dependencies: express "^4.13.1" graceful-fs "^4.1.2" From 5a8da0eda8d193b2a317debdfa31881ed0265851 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 20 Feb 2019 16:44:42 -0800 Subject: [PATCH 2473/2527] fix for ember 3.8+ --- addon/-private/adapters/errors.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/addon/-private/adapters/errors.js b/addon/-private/adapters/errors.js index 4feb710211d..b01a4df5f57 100644 --- a/addon/-private/adapters/errors.js +++ b/addon/-private/adapters/errors.js @@ -76,7 +76,18 @@ const PRIMARY_ATTRIBUTE_KEY = 'base'; */ export function AdapterError(errors, message = 'Adapter operation failed') { this.isAdapterError = true; - EmberError.call(this, message); + let error = EmberError.call(this, message); + + // in ember 3.8+ Error is a Native Error and we don't + // gain these automatically from the EmberError.call + this.stack = error.stack; + this.description = error.description; + this.fileName = error.fileName; + this.lineNumber = error.lineNumber; + this.message = error.message; + this.name = error.name; + this.number = error.number; + this.code = error.code; this.errors = errors || [ { From ea0f5cac962f01cc6c798f43d6b77788814d9eaf Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 20 Feb 2019 17:18:39 -0800 Subject: [PATCH 2474/2527] update changelog for 3.8 and bump version --- CHANGELOG.md | 16 ++++++++++++++++ package.json | 4 ++-- yarn.lock | 48 +++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88babcec944..ef30f88e152 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ ### Master +### Release 3.8.0 (February 20, 2019) + +- [#5671](https://github.com/emberjs/data/pull/5671) Use _scheduleFetch instead of _fetchRecord for belongsTo relationship (#5671) +- [#5702](https://github.com/emberjs/data/pull/5702) [CHORE reference] update reference to be ES2015 +- [#5763](https://github.com/emberjs/data/pull/5763) Update Release instructions +- [#5736](https://github.com/emberjs/data/pull/5736) [DOC] Add Reference doc and AdapterError uses +- [#5733](https://github.com/emberjs/data/pull/5733) [BUGFIX inspector] Fix columns names in debug-adapter (#5733) +- [#5735](https://github.com/emberjs/data/pull/5735) Clarify load/reload behavior +- [#5721](https://github.com/emberjs/data/pull/5721) [BUGFIX 5720] - assert that replacing has-many with non-array throws assertion +- [#5749](https://github.com/emberjs/data/pull/5749) [DOC beta] Fix broken links +- [#5743](https://github.com/emberjs/data/pull/5743) drop use of MODEL_FACTORY_FOR + +### Release 3.7.0 (January 8, 2019) + +- Re-release of 3.6.0 + ### Release 3.6.0 (December 12, 2018) - [#5671](https://github.com/emberjs/data/pull/5671) Fix issue preventing coalescing of belongsTo diff --git a/package.json b/package.json index ef2bcbf419a..cc647ffecf2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ember-data", - "version": "3.5.0", + "version": "3.9.0-canary", "description": "A data layer for your Ember applications.", "repository": "git://github.com/emberjs/data.git", "directories": { @@ -115,7 +115,7 @@ "eslint-plugin-node": "^8.0.0", "eslint-plugin-prettier": "^3.0.1", "execa": "^1.0.0", - "github": "^14.0.0", + "github": "^1.1.1", "glob": "^7.1.3", "json-typescript": "^1.1.0", "loader.js": "^4.7.0", diff --git a/yarn.lock b/yarn.lock index 8ad822f8edc..814a43897ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -932,6 +932,13 @@ after@0.8.2: version "0.8.2" resolved "https://registry.npmjs.org/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" +agent-base@2: + version "2.1.1" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" + dependencies: + extend "~3.0.0" + semver "~5.0.1" + ajv@^6.5.5, ajv@^6.9.1: version "6.9.1" resolved "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz#a4d3683d74abc5670e75f0b16520f70a20ea8dc1" @@ -2961,7 +2968,7 @@ date-time@^2.1.0: dependencies: time-zone "^1.0.0" -debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: +debug@2, debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -4086,7 +4093,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@^3.0.0, extend@~3.0.0, extend@~3.0.2: +extend@3, extend@^3.0.0, extend@~3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -4315,6 +4322,13 @@ flatted@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916" +follow-redirects@0.0.7: + version "0.0.7" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919" + dependencies: + debug "^2.2.0" + stream-consume "^0.1.0" + follow-redirects@^1.0.0: version "1.7.0" resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" @@ -4661,9 +4675,13 @@ git-write-pkt-line@0.1.0: bops "0.0.3" through "~2.2.7" -github@^14.0.0: - version "14.0.0" - resolved "https://registry.npmjs.org/github/-/github-14.0.0.tgz#b707ed88c33cd05e155c785d289aa6229c59a850" +github@^1.1.1: + version "1.4.0" + resolved "https://registry.npmjs.org/github/-/github-1.4.0.tgz#60aed8f16ffe381a3ca6dc6dba5bdd64445b7856" + dependencies: + follow-redirects "0.0.7" + https-proxy-agent "^1.0.0" + mime "^1.2.11" "glob@3 || 4", glob@^4.3.2: version "4.5.3" @@ -5026,6 +5044,14 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +https-proxy-agent@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" + dependencies: + agent-base "2" + debug "2" + extend "3" + iconv-lite@0.4.23: version "0.4.23" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" @@ -6341,6 +6367,10 @@ mime@1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" +mime@^1.2.11: + version "1.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + mime@~1.2.11: version "1.2.11" resolved "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" @@ -7896,6 +7926,10 @@ semver@^4.3.1: version "4.3.6" resolved "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" +semver@~5.0.1: + version "5.0.3" + resolved "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" + semver@~5.1.0: version "5.1.1" resolved "https://registry.npmjs.org/semver/-/semver-5.1.1.tgz#a3292a373e6f3e0798da0b20641b9a9c5bc47e19" @@ -8264,6 +8298,10 @@ statuses@~1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" +stream-consume@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz#d3bdb598c2bd0ae82b8cac7ac50b1107a7996c48" + strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" From 44fa7b6174980d7684e05036d08c531d74e00876 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 22 Feb 2019 14:56:10 -0800 Subject: [PATCH 2475/2527] [BUGFIX tsc] ts:precompile needs RSVP Promise not native promise to be documented --- addon/-private/system/references/record.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/-private/system/references/record.ts b/addon/-private/system/references/record.ts index 9a07becb36d..daaac916018 100644 --- a/addon/-private/system/references/record.ts +++ b/addon/-private/system/references/record.ts @@ -1,4 +1,4 @@ -import { resolve } from 'rsvp'; +import RSVP, { resolve } from 'rsvp'; import Reference from './reference'; /** @@ -81,9 +81,9 @@ export default class RecordReference extends Reference { @method push @param objectOrPromise {Promise|Object} - @return Promise a promise for the value (record or relationship) + @return RSVP.Promise a promise for the value (record or relationship) */ - push(objectOrPromise) { + push(objectOrPromise): RSVP.Promise { return resolve(objectOrPromise).then(data => { return this.store.push(data); }); From 9edbab85e836bbfb4a8e3e4101e1896861e4323b Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 22 Feb 2019 18:37:54 -0800 Subject: [PATCH 2476/2527] fix yarn.lock to remove broccoli-persistent-filter 2.2.0 --- yarn.lock | 245 +++++++++++++++++++++++++----------------------------- 1 file changed, 113 insertions(+), 132 deletions(-) diff --git a/yarn.lock b/yarn.lock index 814a43897ee..dcec655b370 100644 --- a/yarn.lock +++ b/yarn.lock @@ -658,13 +658,13 @@ ember-compatibility-helpers "^1.1.1" "@ember/test-helpers@^1.3.2": - version "1.4.0" - resolved "https://registry.npmjs.org/@ember/test-helpers/-/test-helpers-1.4.0.tgz#46082b6ad1a628a846ad18827bd87026fa478f2d" + version "1.5.0" + resolved "https://registry.npmjs.org/@ember/test-helpers/-/test-helpers-1.5.0.tgz#a480181c412778294e317c256d04ca52e63c813a" dependencies: broccoli-debug "^0.6.5" broccoli-funnel "^2.0.2" ember-assign-polyfill "^2.6.0" - ember-cli-babel "^7.4.2" + ember-cli-babel "^7.4.3" ember-cli-htmlbars-inline-precompile "^2.1.0" "@glimmer/di@^0.2.0": @@ -940,8 +940,8 @@ agent-base@2: semver "~5.0.1" ajv@^6.5.5, ajv@^6.9.1: - version "6.9.1" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.9.1.tgz#a4d3683d74abc5670e75f0b16520f70a20ea8dc1" + version "6.9.2" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.9.2.tgz#4927adb83e7f48e5a32b45729744c71ec39c9c7b" dependencies: fast-deep-equal "^2.0.1" fast-json-stable-stringify "^2.0.0" @@ -977,6 +977,10 @@ ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" +ansi-regex@*, ansi-regex@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" + ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -985,10 +989,6 @@ ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" -ansi-regex@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" - ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -1091,16 +1091,6 @@ array-index@^1.0.0: debug "^2.2.0" es6-symbol "^3.0.2" -array-to-error@^1.0.0: - version "1.1.1" - resolved "https://registry.npmjs.org/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" - dependencies: - array-to-sentence "^1.1.0" - -array-to-sentence@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" - array-unique@^0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -1409,11 +1399,11 @@ babel-plugin-debug-macros@^0.3.0: dependencies: semver "^5.3.0" -babel-plugin-ember-modules-api-polyfill@^2.6.0: - version "2.6.0" - resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.6.0.tgz#9524a65ef0c31ee82536a19c243fbaec1b977cbb" +babel-plugin-ember-modules-api-polyfill@^2.6.0, babel-plugin-ember-modules-api-polyfill@^2.7.0: + version "2.7.0" + resolved "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.7.0.tgz#dcd6a9999da0d47d8c9185362bda6244ca525f4a" dependencies: - ember-rfc176-data "^0.3.6" + ember-rfc176-data "^0.3.7" babel-plugin-feature-flags@^0.3.1: version "0.3.1" @@ -2004,14 +1994,14 @@ broccoli-caching-writer@~2.0.4: symlink-or-copy "^1.0.0" walk-sync "^0.2.0" -broccoli-clean-css@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" +broccoli-clean-css@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/broccoli-clean-css/-/broccoli-clean-css-2.0.1.tgz#1bf48a43d7626522621351c696e5f9441f628db2" dependencies: - broccoli-persistent-filter "^1.1.6" - clean-css-promise "^0.1.0" - inline-source-map-comment "^1.0.5" - json-stable-stringify "^1.0.0" + broccoli-persistent-filter "^1.2.13" + clean-css-promise "^2.0.1" + json-stable-stringify "^1.0.1" + source-map-to-comment "^1.1.0" broccoli-concat@^3.7.3: version "3.7.3" @@ -2088,7 +2078,7 @@ broccoli-funnel-reducer@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" -broccoli-funnel@^1.0.0, broccoli-funnel@^1.0.1: +broccoli-funnel@^1.0.1: version "1.2.0" resolved "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" dependencies: @@ -2194,7 +2184,7 @@ broccoli-node-info@1.1.0, broccoli-node-info@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" -broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.4.3: +broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.2.13, broccoli-persistent-filter@^1.4.3: version "1.4.6" resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.6.tgz#80762d19000880a77da33c34373299c0f6a3e615" dependencies: @@ -2213,8 +2203,8 @@ broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.1.6, broccoli-p walk-sync "^0.3.1" broccoli-persistent-filter@^2.1.1: - version "2.2.0" - resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-2.2.0.tgz#e38b51c287a6684eb3490b9d7d62b76c88ad5fb1" + version "2.2.1" + resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-2.2.1.tgz#d2a911ec02ebbbcfb382242c517159cb7a9c10d7" dependencies: async-disk-cache "^1.2.1" async-promise-queue "^1.0.3" @@ -2608,20 +2598,17 @@ clean-base-url@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" -clean-css-promise@^0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" +clean-css-promise@^2.0.1: + version "2.1.0" + resolved "https://registry.npmjs.org/clean-css-promise/-/clean-css-promise-2.1.0.tgz#2a43936585d56547d7fa0913ff2156f5652d77da" dependencies: - array-to-error "^1.0.0" - clean-css "^3.4.5" - pinkie-promise "^2.0.0" + clean-css "^4.1.9" -clean-css@^3.4.5: - version "3.4.28" - resolved "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" +clean-css@^4.1.9: + version "4.2.1" + resolved "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" dependencies: - commander "2.8.x" - source-map "0.4.x" + source-map "~0.6.0" clean-up-path@^1.0.0: version "1.0.0" @@ -2747,12 +2734,6 @@ commander@2.12.2: version "2.12.2" resolved "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" -commander@2.8.x: - version "2.8.1" - resolved "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" - dependencies: - graceful-readlink ">= 1.0.0" - commander@^2.15.1, commander@^2.6.0, commander@^2.9.0: version "2.19.0" resolved "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" @@ -2974,7 +2955,7 @@ debug@2, debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, de dependencies: ms "2.0.0" -debug@3.2.6, debug@^3.1.0, debug@^3.2.6: +debug@3.2.6, debug@^3.0.1, debug@^3.1.0, debug@^3.2.6: version "3.2.6" resolved "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" dependencies: @@ -2992,7 +2973,7 @@ debug@~3.1.0: dependencies: ms "2.0.0" -debuglog@^1.0.1: +debuglog@*, debuglog@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -3185,9 +3166,9 @@ ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6 ember-cli-version-checker "^2.1.2" semver "^5.5.0" -ember-cli-babel@^7.0.0, ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4, ember-cli-babel@^7.2.0, ember-cli-babel@^7.4.2: - version "7.4.3" - resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-7.4.3.tgz#1ff35ffd54c6206d72635686f4e5bb1674c9eae5" +ember-cli-babel@^7.0.0, ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4, ember-cli-babel@^7.2.0, ember-cli-babel@^7.4.2, ember-cli-babel@^7.4.3: + version "7.5.0" + resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-7.5.0.tgz#af654dcef23630391d2efe85aaa3bdf8b6ca17b7" dependencies: "@babel/core" "^7.0.0" "@babel/plugin-transform-modules-amd" "^7.0.0" @@ -3197,7 +3178,7 @@ ember-cli-babel@^7.0.0, ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4, ember-cl "@babel/runtime" "^7.2.0" amd-name-resolver "^1.2.1" babel-plugin-debug-macros "^0.3.0" - babel-plugin-ember-modules-api-polyfill "^2.6.0" + babel-plugin-ember-modules-api-polyfill "^2.7.0" babel-plugin-module-resolver "^3.1.1" broccoli-babel-transpiler "^7.1.2" broccoli-debug "^0.6.4" @@ -3292,10 +3273,6 @@ ember-cli-is-package-missing@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" -ember-cli-lodash-subset@^1.0.7: - version "1.0.12" - resolved "https://registry.npmjs.org/ember-cli-lodash-subset/-/ember-cli-lodash-subset-1.0.12.tgz#af2e77eba5dcb0d77f3308d3a6fd7d3450f6e537" - ember-cli-lodash-subset@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/ember-cli-lodash-subset/-/ember-cli-lodash-subset-2.0.1.tgz#20cb68a790fe0fde2488ddfd8efbb7df6fe766f2" @@ -3311,16 +3288,13 @@ ember-cli-path-utils@^1.0.0: resolved "https://registry.npmjs.org/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" ember-cli-preprocess-registry@^3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.1.2.tgz#083efb21fd922c021ceba9e08f4d9278249fc4db" + version "3.2.1" + resolved "https://registry.npmjs.org/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.2.1.tgz#e8592e11ce186113c52bc0a53ee19efc4c405963" dependencies: - broccoli-clean-css "^1.1.0" - broccoli-funnel "^1.0.0" - broccoli-merge-trees "^1.0.0" - debug "^2.2.0" - ember-cli-lodash-subset "^1.0.7" + broccoli-clean-css "^2.0.1" + broccoli-funnel "^2.0.1" + debug "^3.0.1" process-relative-require "^1.0.0" - silent-error "^1.0.0" ember-cli-pretender@^3.1.1: version "3.1.1" @@ -3623,8 +3597,8 @@ ember-qunit@^4.2.0: qunit "^2.9.1" ember-resolver@^5.0.1: - version "5.1.1" - resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-5.1.1.tgz#ffc2b12e9a50b56f9f48f8c239b10d00a142dc42" + version "5.1.3" + resolved "https://registry.npmjs.org/ember-resolver/-/ember-resolver-5.1.3.tgz#d2a5a856d53911552c022649cdc7b0408a7908ae" dependencies: "@glimmer/resolver" "^0.4.1" babel-plugin-debug-macros "^0.1.10" @@ -3634,9 +3608,9 @@ ember-resolver@^5.0.1: ember-cli-version-checker "^3.0.0" resolve "^1.10.0" -ember-rfc176-data@^0.3.1, ember-rfc176-data@^0.3.6: - version "0.3.6" - resolved "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.3.6.tgz#7138db8dfccec39c9a832adfbd4c49d670028907" +ember-rfc176-data@^0.3.1, ember-rfc176-data@^0.3.7: + version "0.3.7" + resolved "https://registry.npmjs.org/ember-rfc176-data/-/ember-rfc176-data-0.3.7.tgz#ecff7d74987d09296d3703343fed934515a4be33" ember-router-generator@^1.2.3: version "1.2.3" @@ -3794,8 +3768,8 @@ es-to-primitive@^1.2.0: is-symbol "^1.0.2" es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.47" - resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.47.tgz#d24232e1380daad5449a817be19bde9729024a11" + version "0.10.48" + resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.48.tgz#9a0b31eeded39e64453bcedf6f9d50bbbfb43850" dependencies: es6-iterator "~2.0.3" es6-symbol "~3.1.1" @@ -4791,10 +4765,6 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, version "4.1.15" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" -"graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - growl@1.10.5: version "1.10.5" resolved "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" @@ -4982,8 +4952,8 @@ home-or-tmp@^2.0.0: os-tmpdir "^1.0.1" homedir-polyfill@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + version "1.0.3" + resolved "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" dependencies: parse-passwd "^1.0.0" @@ -5083,7 +5053,7 @@ import-fresh@^3.0.0: parent-module "^1.0.0" resolve-from "^4.0.0" -imurmurhash@^0.1.4: +imurmurhash@*, imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -5129,16 +5099,6 @@ init-package-json@~1.9.1: validate-npm-package-license "^3.0.1" validate-npm-package-name "^3.0.0" -inline-source-map-comment@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" - dependencies: - chalk "^1.0.0" - get-stdin "^4.0.1" - minimist "^1.1.1" - sum-up "^1.0.1" - xtend "^4.0.0" - inquirer@^2: version "2.0.0" resolved "https://registry.npmjs.org/inquirer/-/inquirer-2.0.0.tgz#e1351687b90d150ca403ceaa3cefb1e3065bef4b" @@ -5796,7 +5756,7 @@ lodash._basefor@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" -lodash._baseindexof@^3.0.0: +lodash._baseindexof@*, lodash._baseindexof@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" @@ -5808,6 +5768,13 @@ lodash._baseisequal@^3.0.0: lodash.istypedarray "^3.0.0" lodash.keys "^3.0.0" +lodash._baseuniq@*: + version "4.6.0" + resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" + dependencies: + lodash._createset "~4.0.0" + lodash._root "~3.0.0" + lodash._baseuniq@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-3.0.3.tgz#2123fa0db2d69c28d5beb1c1f36d61522a740234" @@ -5816,11 +5783,11 @@ lodash._baseuniq@^3.0.0: lodash._cacheindexof "^3.0.0" lodash._createcache "^3.0.0" -lodash._bindcallback@^3.0.0: +lodash._bindcallback@*, lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" -lodash._cacheindexof@^3.0.0: +lodash._cacheindexof@*, lodash._cacheindexof@^3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" @@ -5832,12 +5799,16 @@ lodash._createassigner@^3.0.0: lodash._isiterateecall "^3.0.0" lodash.restparam "^3.0.0" -lodash._createcache@^3.0.0: +lodash._createcache@*, lodash._createcache@^3.0.0: version "3.1.2" resolved "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" dependencies: lodash._getnative "^3.0.0" +lodash._createset@~4.0.0: + version "4.0.3" + resolved "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" + lodash._createwrapper@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" @@ -5856,7 +5827,7 @@ lodash._escapestringchar@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.3.0.tgz#cce73ae60fc6da55d2bf8a0679c23ca2bab149fc" -lodash._getnative@^3.0.0: +lodash._getnative@*, lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" @@ -5891,6 +5862,10 @@ lodash._reunescapedhtml@~2.3.0: lodash._htmlescapes "~2.3.0" lodash.keys "~2.3.0" +lodash._root@~3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + lodash._setbinddata@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz#e5610490acd13277d59858d95b5f2727f1508f04" @@ -5998,10 +5973,14 @@ lodash.identity@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/lodash.identity/-/lodash.identity-2.3.0.tgz#6b01a210c9485355c2a913b48b6711219a173ded" -lodash.isarguments@^3.0.0: +lodash.isarguments@*, lodash.isarguments@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" +lodash.isarray@*: + version "4.0.0" + resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-4.0.0.tgz#2aca496b28c4ca6d726715313590c02e6ea34403" + lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" @@ -6020,6 +5999,10 @@ lodash.istypedarray@^3.0.0: version "3.0.6" resolved "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" +lodash.keys@*: + version "4.2.0" + resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-4.2.0.tgz#a08602ac12e4fb83f91fc1fb7a360a4d9ba35205" + lodash.keys@^3.0.0: version "3.1.2" resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" @@ -6066,7 +6049,7 @@ lodash.pairs@^3.0.0: dependencies: lodash.keys "^3.0.0" -lodash.restparam@^3.0.0: +lodash.restparam@*, lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" @@ -6447,8 +6430,8 @@ mocha-only-detector@1.0.0: glob "^4.3.2" mocha@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/mocha/-/mocha-6.0.0.tgz#b558da6245a09581aa4a1c6aee9e0fa6ad0e1767" + version "6.0.1" + resolved "https://registry.npmjs.org/mocha/-/mocha-6.0.1.tgz#c287da87913fa0edc4c44850ba8bc4fdbf20d3ea" dependencies: ansi-colors "3.2.3" browser-stdout "1.3.1" @@ -6903,8 +6886,8 @@ on-finished@~2.3.0: ee-first "1.1.1" on-headers@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + version "1.0.2" + resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" @@ -7129,7 +7112,7 @@ path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" -path-parse@^1.0.5, path-parse@^1.0.6: +path-parse@^1.0.6: version "1.0.6" resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" @@ -7355,14 +7338,14 @@ quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: underscore.string "~3.3.4" qunit@^2.9.1: - version "2.9.1" - resolved "https://registry.npmjs.org/qunit/-/qunit-2.9.1.tgz#e11008d62e5f19ded60a20899a0cf7c3ec573b2d" + version "2.9.2" + resolved "https://registry.npmjs.org/qunit/-/qunit-2.9.2.tgz#97919440c9c0ae838bcd3c33a2ee42f35c5ef4a0" dependencies: commander "2.12.2" js-reporters "1.2.1" minimatch "3.0.4" node-watch "0.6.0" - resolve "1.5.0" + resolve "1.9.0" range-parser@~1.2.0: version "1.2.0" @@ -7486,7 +7469,7 @@ readable-stream@~2.0.5: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readdir-scoped-modules@^1.0.0: +readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" dependencies: @@ -7559,8 +7542,8 @@ regenerator-transform@^0.10.0: private "^0.1.6" regenerator-transform@^0.13.3: - version "0.13.3" - resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.3.tgz#264bd9ff38a8ce24b06e0636496b2c856b57bcbb" + version "0.13.4" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.4.tgz#18f6763cf1382c69c36df76c6ce122cc694284fb" dependencies: private "^0.1.6" @@ -7771,11 +7754,11 @@ resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" -resolve@1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" +resolve@1.9.0: + version "1.9.0" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06" dependencies: - path-parse "^1.0.5" + path-parse "^1.0.6" resolve@^1.1.6, resolve@^1.10.0, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.7.1, resolve@^1.8.1, resolve@^1.9.0: version "1.10.0" @@ -8163,6 +8146,10 @@ source-map-support@~0.5.9: buffer-from "^1.0.0" source-map "^0.6.0" +source-map-to-comment@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/source-map-to-comment/-/source-map-to-comment-1.1.0.tgz#e518c40bc7399b2e23c8e331a11635a97750e9c3" + source-map-url@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" @@ -8171,7 +8158,7 @@ source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" -source-map@0.4.x, source-map@^0.4.2: +source-map@^0.4.2: version "0.4.4" resolved "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: @@ -8181,7 +8168,7 @@ source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0: version "0.5.7" resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -8354,6 +8341,12 @@ stringstream@~0.0.4: version "0.0.6" resolved "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" +strip-ansi@*, strip-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" + dependencies: + ansi-regex "^4.0.0" + strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -8366,12 +8359,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" - dependencies: - ansi-regex "^4.0.0" - strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -8400,12 +8387,6 @@ styled_string@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" -sum-up@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" - dependencies: - chalk "^1.0.0" - supports-color@6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" @@ -8699,8 +8680,8 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" typescript@~3.3.3: - version "3.3.3" - resolved "https://registry.npmjs.org/typescript/-/typescript-3.3.3.tgz#f1657fc7daa27e1a8930758ace9ae8da31403221" + version "3.3.3333" + resolved "https://registry.npmjs.org/typescript/-/typescript-3.3.3333.tgz#171b2c5af66c59e9431199117a3bcadc66fdcfd6" uc.micro@^1.0.0, uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" @@ -8867,7 +8848,7 @@ uuid@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" -validate-npm-package-license@^3.0.1: +validate-npm-package-license@*, validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" dependencies: From 54b132bd94438b5e5f4ca73268bc6b7d9f9085ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 26 Feb 2019 06:20:46 +0000 Subject: [PATCH 2477/2527] Bump broccoli-uglify-sourcemap from 2.2.0 to 3.0.0 Bumps [broccoli-uglify-sourcemap](https://github.com/ember-cli/broccoli-uglify-sourcemap) from 2.2.0 to 3.0.0. - [Release notes](https://github.com/ember-cli/broccoli-uglify-sourcemap/releases) - [Changelog](https://github.com/ember-cli/broccoli-uglify-sourcemap/blob/master/CHANGELOG.md) - [Commits](https://github.com/ember-cli/broccoli-uglify-sourcemap/compare/v2.2.0...v3.0.0) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 93 ++++++++++++++++++++++++++-------------------------- 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index cc647ffecf2..232d1a84c35 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "broccoli-stew": "^2.0.1", "broccoli-string-replace": "^0.1.2", "broccoli-test-helper": "^2.0.0", - "broccoli-uglify-sourcemap": "^2.2.0", + "broccoli-uglify-sourcemap": "^3.0.0", "co": "^4.6.0", "common-tags": "^1.8.0", "ember-cli": "^3.5.1", diff --git a/yarn.lock b/yarn.lock index dcec655b370..cbbcdcb65cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -977,10 +977,6 @@ ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" -ansi-regex@*, ansi-regex@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" - ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -989,6 +985,10 @@ ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" +ansi-regex@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -2311,7 +2311,7 @@ broccoli-test-helper@^2.0.0: tmp "^0.0.33" walk-sync "^0.3.3" -broccoli-uglify-sourcemap@^2.1.1, broccoli-uglify-sourcemap@^2.2.0: +broccoli-uglify-sourcemap@^2.1.1: version "2.2.0" resolved "https://registry.npmjs.org/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-2.2.0.tgz#2ff49389bdf342a550c3596750ba2dde95a8f7d4" dependencies: @@ -2327,6 +2327,22 @@ broccoli-uglify-sourcemap@^2.1.1, broccoli-uglify-sourcemap@^2.2.0: walk-sync "^0.3.2" workerpool "^2.3.0" +broccoli-uglify-sourcemap@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-3.0.0.tgz#680a23e5e2df0abb0d921a71323c975f1e237524" + dependencies: + async-promise-queue "^1.0.4" + broccoli-plugin "^1.2.1" + debug "^4.1.0" + lodash.defaultsdeep "^4.6.0" + matcher-collection "^1.0.5" + mkdirp "^0.5.0" + source-map-url "^0.4.0" + symlink-or-copy "^1.0.1" + terser "^3.16.1" + walk-sync "^1.1.3" + workerpool "^3.1.1" + broccoli@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/broccoli/-/broccoli-2.0.1.tgz#3611d643bf4b2666b565dc24cc5307fc80f62bf6" @@ -2973,7 +2989,7 @@ debug@~3.1.0: dependencies: ms "2.0.0" -debuglog@*, debuglog@^1.0.1: +debuglog@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -5053,7 +5069,7 @@ import-fresh@^3.0.0: parent-module "^1.0.0" resolve-from "^4.0.0" -imurmurhash@*, imurmurhash@^0.1.4: +imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -5756,7 +5772,7 @@ lodash._basefor@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" -lodash._baseindexof@*, lodash._baseindexof@^3.0.0: +lodash._baseindexof@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" @@ -5768,13 +5784,6 @@ lodash._baseisequal@^3.0.0: lodash.istypedarray "^3.0.0" lodash.keys "^3.0.0" -lodash._baseuniq@*: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" - dependencies: - lodash._createset "~4.0.0" - lodash._root "~3.0.0" - lodash._baseuniq@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-3.0.3.tgz#2123fa0db2d69c28d5beb1c1f36d61522a740234" @@ -5783,11 +5792,11 @@ lodash._baseuniq@^3.0.0: lodash._cacheindexof "^3.0.0" lodash._createcache "^3.0.0" -lodash._bindcallback@*, lodash._bindcallback@^3.0.0: +lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" -lodash._cacheindexof@*, lodash._cacheindexof@^3.0.0: +lodash._cacheindexof@^3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" @@ -5799,16 +5808,12 @@ lodash._createassigner@^3.0.0: lodash._isiterateecall "^3.0.0" lodash.restparam "^3.0.0" -lodash._createcache@*, lodash._createcache@^3.0.0: +lodash._createcache@^3.0.0: version "3.1.2" resolved "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" dependencies: lodash._getnative "^3.0.0" -lodash._createset@~4.0.0: - version "4.0.3" - resolved "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" - lodash._createwrapper@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" @@ -5827,7 +5832,7 @@ lodash._escapestringchar@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.3.0.tgz#cce73ae60fc6da55d2bf8a0679c23ca2bab149fc" -lodash._getnative@*, lodash._getnative@^3.0.0: +lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" @@ -5862,10 +5867,6 @@ lodash._reunescapedhtml@~2.3.0: lodash._htmlescapes "~2.3.0" lodash.keys "~2.3.0" -lodash._root@~3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" - lodash._setbinddata@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz#e5610490acd13277d59858d95b5f2727f1508f04" @@ -5973,14 +5974,10 @@ lodash.identity@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/lodash.identity/-/lodash.identity-2.3.0.tgz#6b01a210c9485355c2a913b48b6711219a173ded" -lodash.isarguments@*, lodash.isarguments@^3.0.0: +lodash.isarguments@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" -lodash.isarray@*: - version "4.0.0" - resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-4.0.0.tgz#2aca496b28c4ca6d726715313590c02e6ea34403" - lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" @@ -5999,10 +5996,6 @@ lodash.istypedarray@^3.0.0: version "3.0.6" resolved "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" -lodash.keys@*: - version "4.2.0" - resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-4.2.0.tgz#a08602ac12e4fb83f91fc1fb7a360a4d9ba35205" - lodash.keys@^3.0.0: version "3.1.2" resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" @@ -6049,7 +6042,7 @@ lodash.pairs@^3.0.0: dependencies: lodash.keys "^3.0.0" -lodash.restparam@*, lodash.restparam@^3.0.0: +lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" @@ -7469,7 +7462,7 @@ readable-stream@~2.0.5: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: +readdir-scoped-modules@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" dependencies: @@ -8341,12 +8334,6 @@ stringstream@~0.0.4: version "0.0.6" resolved "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" -strip-ansi@*, strip-ansi@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" - dependencies: - ansi-regex "^4.0.0" - strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -8359,6 +8346,12 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz#f78f68b5d0866c20b2c9b8c61b5298508dc8756f" + dependencies: + ansi-regex "^4.0.0" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" @@ -8439,7 +8432,7 @@ temp@0.8.3: os-tmpdir "^1.0.0" rimraf "~2.2.6" -terser@^3.7.5: +terser@^3.16.1, terser@^3.7.5: version "3.16.1" resolved "https://registry.npmjs.org/terser/-/terser-3.16.1.tgz#5b0dd4fa1ffd0b0b43c2493b2c364fd179160493" dependencies: @@ -8848,7 +8841,7 @@ uuid@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" -validate-npm-package-license@*, validate-npm-package-license@^3.0.1: +validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" dependencies: @@ -8893,7 +8886,7 @@ walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2, walk-sync@^0.3.3: ensure-posix-path "^1.0.0" matcher-collection "^1.0.0" -walk-sync@^1.0.0: +walk-sync@^1.0.0, walk-sync@^1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-1.1.3.tgz#3b7b6468f068b5eba2278c931c57db3d39092969" dependencies: @@ -8981,6 +8974,12 @@ workerpool@^2.3.0, workerpool@^2.3.1: dependencies: object-assign "4.1.1" +workerpool@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-3.1.1.tgz#9decea76b73c2f91de1b5bec1019f8a474b3a620" + dependencies: + object-assign "4.1.1" + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" From 9451c52772668461819b5d8f8af37f9b512a0184 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 26 Feb 2019 06:21:25 +0000 Subject: [PATCH 2478/2527] Bump ember-qunit from 4.4.0 to 4.4.1 Bumps [ember-qunit](https://github.com/emberjs/ember-qunit) from 4.4.0 to 4.4.1. - [Release notes](https://github.com/emberjs/ember-qunit/releases) - [Changelog](https://github.com/emberjs/ember-qunit/blob/master/CHANGELOG.md) - [Commits](https://github.com/emberjs/ember-qunit/compare/v4.4.0...v4.4.1) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 232d1a84c35..8114334b14f 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "ember-export-application-global": "^2.0.0", "ember-load-initializers": "^2.0.0", "ember-maybe-import-regenerator": "^0.1.6", - "ember-qunit": "^4.2.0", + "ember-qunit": "^4.4.1", "ember-qunit-assert-helpers": "^0.2.1", "ember-resolver": "^5.0.1", "ember-source": "~3.8.0", diff --git a/yarn.lock b/yarn.lock index cbbcdcb65cb..3e26a6d4569 100644 --- a/yarn.lock +++ b/yarn.lock @@ -657,9 +657,9 @@ ember-cli-babel "^6.16.0" ember-compatibility-helpers "^1.1.1" -"@ember/test-helpers@^1.3.2": +"@ember/test-helpers@^1.5.0": version "1.5.0" - resolved "https://registry.npmjs.org/@ember/test-helpers/-/test-helpers-1.5.0.tgz#a480181c412778294e317c256d04ca52e63c813a" + resolved "https://registry.yarnpkg.com/@ember/test-helpers/-/test-helpers-1.5.0.tgz#a480181c412778294e317c256d04ca52e63c813a" dependencies: broccoli-debug "^0.6.5" broccoli-funnel "^2.0.2" @@ -3182,7 +3182,7 @@ ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.0.0-beta.7, ember-cli-babel@^6 ember-cli-version-checker "^2.1.2" semver "^5.5.0" -ember-cli-babel@^7.0.0, ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4, ember-cli-babel@^7.2.0, ember-cli-babel@^7.4.2, ember-cli-babel@^7.4.3: +ember-cli-babel@^7.0.0, ember-cli-babel@^7.1.3, ember-cli-babel@^7.1.4, ember-cli-babel@^7.2.0, ember-cli-babel@^7.4.3, ember-cli-babel@^7.5.0: version "7.5.0" resolved "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-7.5.0.tgz#af654dcef23630391d2efe85aaa3bdf8b6ca17b7" dependencies: @@ -3600,17 +3600,17 @@ ember-qunit-assert-helpers@^0.2.1: broccoli-filter "^1.0.1" ember-cli-babel "^6.9.0" -ember-qunit@^4.2.0: - version "4.4.0" - resolved "https://registry.npmjs.org/ember-qunit/-/ember-qunit-4.4.0.tgz#813d7b1febc5a35b86db64c4a54ea5bf91a5fbf0" +ember-qunit@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-4.4.1.tgz#3654cadf9fa7e2287fe7b61fc7f19c3eb06222b5" dependencies: - "@ember/test-helpers" "^1.3.2" + "@ember/test-helpers" "^1.5.0" broccoli-funnel "^2.0.2" broccoli-merge-trees "^3.0.2" common-tags "^1.4.0" - ember-cli-babel "^7.4.2" + ember-cli-babel "^7.5.0" ember-cli-test-loader "^2.2.0" - qunit "^2.9.1" + qunit "^2.9.2" ember-resolver@^5.0.1: version "5.1.3" @@ -7330,9 +7330,9 @@ quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: rimraf "^2.5.4" underscore.string "~3.3.4" -qunit@^2.9.1: +qunit@^2.9.2: version "2.9.2" - resolved "https://registry.npmjs.org/qunit/-/qunit-2.9.2.tgz#97919440c9c0ae838bcd3c33a2ee42f35c5ef4a0" + resolved "https://registry.yarnpkg.com/qunit/-/qunit-2.9.2.tgz#97919440c9c0ae838bcd3c33a2ee42f35c5ef4a0" dependencies: commander "2.12.2" js-reporters "1.2.1" From 41a3b809858ec3ff42118cb2534f6c2406e388f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 26 Feb 2019 06:22:10 +0000 Subject: [PATCH 2479/2527] Bump broccoli-babel-transpiler from 7.1.2 to 7.2.0 Bumps [broccoli-babel-transpiler](https://github.com/babel/broccoli-babel-transpiler) from 7.1.2 to 7.2.0. - [Release notes](https://github.com/babel/broccoli-babel-transpiler/releases) - [Changelog](https://github.com/babel/broccoli-babel-transpiler/blob/master/CHANGELOG.md) - [Commits](https://github.com/babel/broccoli-babel-transpiler/compare/v7.1.2...v7.2.0) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 82 +++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 60 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 8114334b14f..1a2940444d3 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "@types/qunit": "^2.5.3", "@types/rsvp": "^4.0.2", "babel-eslint": "^10.0.1", - "broccoli-babel-transpiler": "^7.1.2", + "broccoli-babel-transpiler": "^7.2.0", "broccoli-concat": "^3.7.3", "broccoli-stew": "^2.0.1", "broccoli-string-replace": "^0.1.2", diff --git a/yarn.lock b/yarn.lock index 3e26a6d4569..ecdd15f0ad3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8,17 +8,17 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/core@^7.0.0": - version "7.3.3" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.3.3.tgz#d090d157b7c5060d05a05acaebc048bd2b037947" +"@babel/core@^7.0.0", "@babel/core@^7.3.3": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.4.tgz#921a5a13746c21e32445bf0798680e9d11a6530b" dependencies: "@babel/code-frame" "^7.0.0" - "@babel/generator" "^7.3.3" + "@babel/generator" "^7.3.4" "@babel/helpers" "^7.2.0" - "@babel/parser" "^7.3.3" + "@babel/parser" "^7.3.4" "@babel/template" "^7.2.2" - "@babel/traverse" "^7.2.2" - "@babel/types" "^7.3.3" + "@babel/traverse" "^7.3.4" + "@babel/types" "^7.3.4" convert-source-map "^1.1.0" debug "^4.1.0" json5 "^2.1.0" @@ -27,7 +27,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.2.2", "@babel/generator@^7.3.3": +"@babel/generator@^7.2.2": version "7.3.3" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.3.3.tgz#185962ade59a52e00ca2bdfcfd1d58e528d4e39e" dependencies: @@ -37,6 +37,16 @@ source-map "^0.5.0" trim-right "^1.0.1" +"@babel/generator@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.4.tgz#9aa48c1989257877a9d971296e5b73bfe72e446e" + dependencies: + "@babel/types" "^7.3.4" + jsesc "^2.5.1" + lodash "^4.17.11" + source-map "^0.5.0" + trim-right "^1.0.1" + "@babel/helper-annotate-as-pure@^7.0.0": version "7.0.0" resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" @@ -199,10 +209,14 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.2.2", "@babel/parser@^7.2.3", "@babel/parser@^7.3.3": +"@babel/parser@^7.0.0", "@babel/parser@^7.2.2", "@babel/parser@^7.2.3": version "7.3.3" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.3.3.tgz#092d450db02bdb6ccb1ca8ffd47d8774a91aef87" +"@babel/parser@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.4.tgz#a43357e4bbf4b92a437fb9e465c192848287f27c" + "@babel/plugin-proposal-async-generator-functions@^7.2.0": version "7.2.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" @@ -570,7 +584,7 @@ "@babel/parser" "^7.2.2" "@babel/types" "^7.2.2" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.2.2", "@babel/traverse@^7.2.3": +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.2.3": version "7.2.3" resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8" dependencies: @@ -584,6 +598,20 @@ globals "^11.1.0" lodash "^4.17.10" +"@babel/traverse@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.3.4.tgz#1330aab72234f8dea091b08c4f8b9d05c7119e06" + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.3.4" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/parser" "^7.3.4" + "@babel/types" "^7.3.4" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.11" + "@babel/types@^7.0.0", "@babel/types@^7.1.5", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3": version "7.3.3" resolved "https://registry.npmjs.org/@babel/types/-/types-7.3.3.tgz#6c44d1cdac2a7625b624216657d5bc6c107ab436" @@ -592,6 +620,14 @@ lodash "^4.17.11" to-fast-properties "^2.0.0" +"@babel/types@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.4.tgz#bf482eaeaffb367a28abbf9357a94963235d90ed" + dependencies: + esutils "^2.0.2" + lodash "^4.17.11" + to-fast-properties "^2.0.0" + "@ember-decorators/babel-transforms@^5.1.3": version "5.1.3" resolved "https://registry.npmjs.org/@ember-decorators/babel-transforms/-/babel-transforms-5.1.3.tgz#90bc10eb03c513e6fd21c818868a3c44eba55efc" @@ -1931,21 +1967,21 @@ broccoli-babel-transpiler@^6.5.0: rsvp "^4.8.2" workerpool "^2.3.0" -broccoli-babel-transpiler@^7.1.1, broccoli-babel-transpiler@^7.1.2: - version "7.1.2" - resolved "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.1.2.tgz#fb5d6f8b9a805627ac3f2914ac9d86e82ca2413b" +broccoli-babel-transpiler@^7.1.1, broccoli-babel-transpiler@^7.1.2, broccoli-babel-transpiler@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.2.0.tgz#5c0d694c4055106abb385e2d3d88936d35b7cb18" dependencies: - "@babel/core" "^7.0.0" + "@babel/core" "^7.3.3" "@babel/polyfill" "^7.0.0" - broccoli-funnel "^2.0.1" - broccoli-merge-trees "^3.0.0" - broccoli-persistent-filter "^1.4.3" + broccoli-funnel "^2.0.2" + broccoli-merge-trees "^3.0.2" + broccoli-persistent-filter "^2.2.1" clone "^2.1.2" - hash-for-dep "^1.2.3" + hash-for-dep "^1.4.7" heimdalljs-logger "^0.1.9" json-stable-stringify "^1.0.1" - rsvp "^4.8.3" - workerpool "^2.3.1" + rsvp "^4.8.4" + workerpool "^3.1.1" broccoli-builder@^0.18.14: version "0.18.14" @@ -2202,7 +2238,7 @@ broccoli-persistent-filter@^1.1.5, broccoli-persistent-filter@^1.2.13, broccoli- symlink-or-copy "^1.0.1" walk-sync "^0.3.1" -broccoli-persistent-filter@^2.1.1: +broccoli-persistent-filter@^2.1.1, broccoli-persistent-filter@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-2.2.1.tgz#d2a911ec02ebbbcfb382242c517159cb7a9c10d7" dependencies: @@ -4890,7 +4926,7 @@ has@^1.0.1, has@^1.0.3: dependencies: function-bind "^1.1.1" -hash-for-dep@^1.0.2, hash-for-dep@^1.2.3: +hash-for-dep@^1.0.2, hash-for-dep@^1.2.3, hash-for-dep@^1.4.7: version "1.4.7" resolved "https://registry.npmjs.org/hash-for-dep/-/hash-for-dep-1.4.7.tgz#ea6f9d8e2f9e784fc48ca60c40ea886bdb41aa54" dependencies: @@ -8968,7 +9004,7 @@ wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" -workerpool@^2.3.0, workerpool@^2.3.1: +workerpool@^2.3.0: version "2.3.3" resolved "https://registry.npmjs.org/workerpool/-/workerpool-2.3.3.tgz#49a70089bd55e890d68cc836a19419451d7c81d7" dependencies: From 1ebff8cb4bcd848e797a056f8cab9a80405772d8 Mon Sep 17 00:00:00 2001 From: Rajasegar Chandran Date: Mon, 4 Mar 2019 14:56:09 +0530 Subject: [PATCH 2480/2527] [DOCS] [BUGFIX] Get model relationships by string Fixes #5804 Access relationships by model name like relationships.get('user'); --- addon/-private/system/model/model.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/model/model.js b/addon/-private/system/model/model.js index 134b9acd7dc..62f79fb4409 100644 --- a/addon/-private/system/model/model.js +++ b/addon/-private/system/model/model.js @@ -1512,10 +1512,10 @@ Model.reopenClass({ import Post from 'app/models/post'; let relationships = Ember.get(Blog, 'relationships'); - relationships.get(User); + relationships.get('user'); //=> [ { name: 'users', kind: 'hasMany' }, // { name: 'owner', kind: 'belongsTo' } ] - relationships.get(Post); + relationships.get('post'); //=> [ { name: 'posts', kind: 'hasMany' } ] ``` From 1dbe10158fc3b5e36bdf3fb202b744a82a8a1756 Mon Sep 17 00:00:00 2001 From: Rajasegar Chandran Date: Mon, 4 Mar 2019 15:02:24 +0530 Subject: [PATCH 2481/2527] [DOCS] [BUGFIX] generateIdForRecord api doc #5803 Fixes #5803 Missing type param in generateIdForRecord api doc --- addon/adapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/adapter.js b/addon/adapter.js index eeaf9d2c4c5..4c6c916d448 100644 --- a/addon/adapter.js +++ b/addon/adapter.js @@ -242,7 +242,7 @@ export default EmberObject.extend({ import { v4 } from 'uuid'; export default DS.Adapter.extend({ - generateIdForRecord(store, inputProperties) { + generateIdForRecord(store, type, inputProperties) { return v4(); } }); From a095bebf1ac94a116dcfd1919fd454c962b0bb13 Mon Sep 17 00:00:00 2001 From: Rajasegar Chandran Date: Mon, 4 Mar 2019 14:46:19 +0530 Subject: [PATCH 2482/2527] [DOCS] [BUGFIX] Adding type to forEach app serializer Fixes #5819 Adding type in the normalize example of app serializer fields.forEach should have field as the second param --- addon/serializers/json.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/serializers/json.js b/addon/serializers/json.js index 47492a0b271..a3eb5f7eaab 100644 --- a/addon/serializers/json.js +++ b/addon/serializers/json.js @@ -515,7 +515,7 @@ const JSONSerializer = Serializer.extend({ normalize(typeClass, hash) { var fields = get(typeClass, 'fields'); - fields.forEach(function(field) { + fields.forEach(function(type, field) { var payloadField = underscore(field); if (field === payloadField) { return; } From d99e7f57479aba862612a0fd2847647133697c23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 4 Mar 2019 06:09:11 +0000 Subject: [PATCH 2483/2527] Bump @ember-decorators/babel-transforms from 5.1.3 to 5.1.4 Bumps [@ember-decorators/babel-transforms](https://github.com/ember-decorators/ember-decorators) from 5.1.3 to 5.1.4. - [Release notes](https://github.com/ember-decorators/ember-decorators/releases) - [Commits](https://github.com/ember-decorators/ember-decorators/compare/v5.1.3...v5.1.4) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 1a2940444d3..18ff08ada4c 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ }, "devDependencies": { "@babel/plugin-transform-typescript": "^7.2.0", - "@ember-decorators/babel-transforms": "^5.1.3", + "@ember-decorators/babel-transforms": "^5.1.4", "@ember-decorators/data": "^5.1.2", "@types/ember": "~3.0.25", "@types/ember-qunit": "~3.4.5", diff --git a/yarn.lock b/yarn.lock index ecdd15f0ad3..3fdff6c0eb8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -628,9 +628,9 @@ lodash "^4.17.11" to-fast-properties "^2.0.0" -"@ember-decorators/babel-transforms@^5.1.3": - version "5.1.3" - resolved "https://registry.npmjs.org/@ember-decorators/babel-transforms/-/babel-transforms-5.1.3.tgz#90bc10eb03c513e6fd21c818868a3c44eba55efc" +"@ember-decorators/babel-transforms@^5.1.4": + version "5.1.4" + resolved "https://registry.yarnpkg.com/@ember-decorators/babel-transforms/-/babel-transforms-5.1.4.tgz#e26e0480425e4b6e43be75e24ba85103a02d5459" dependencies: "@babel/plugin-proposal-class-properties" "^7.1.0" "@babel/plugin-proposal-decorators" "^7.1.2" From 4d5107e3f122b77d8a7b9a7e612b1377693557e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 4 Mar 2019 06:10:20 +0000 Subject: [PATCH 2484/2527] Bump eslint from 5.14.1 to 5.15.0 Bumps [eslint](https://github.com/eslint/eslint) from 5.14.1 to 5.15.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v5.14.1...v5.15.0) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 18ff08ada4c..99c7c1dd96f 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "ember-source": "~3.8.0", "ember-source-channel-url": "^1.1.0", "ember-try": "^1.1.0", - "eslint": "^5.10.0", + "eslint": "^5.15.0", "eslint-config-prettier": "^4.0.0", "eslint-plugin-node": "^8.0.0", "eslint-plugin-prettier": "^3.0.1", diff --git a/yarn.lock b/yarn.lock index 3fdff6c0eb8..70a248987b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3887,9 +3887,9 @@ eslint-scope@3.7.1: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-scope@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" +eslint-scope@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.2.tgz#5f10cd6cabb1965bf479fa65745673439e21cb0e" dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" @@ -3902,9 +3902,9 @@ eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@^5.10.0: - version "5.14.1" - resolved "https://registry.npmjs.org/eslint/-/eslint-5.14.1.tgz#490a28906be313685c55ccd43a39e8d22efc04ba" +eslint@^5.15.0: + version "5.15.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.15.0.tgz#f313a2f7c7628d39adeefdba4a9c41f842012c9e" dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.9.1" @@ -3912,7 +3912,7 @@ eslint@^5.10.0: cross-spawn "^6.0.5" debug "^4.0.1" doctrine "^3.0.0" - eslint-scope "^4.0.0" + eslint-scope "^4.0.2" eslint-utils "^1.3.1" eslint-visitor-keys "^1.0.0" espree "^5.0.1" From 9d71d168e6afaf1905f2400c10e44cab5d99d27d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 4 Mar 2019 06:09:29 +0000 Subject: [PATCH 2485/2527] Bump ember-cli-version-checker from 3.0.1 to 3.1.1 Bumps [ember-cli-version-checker](https://github.com/rwjblue/ember-cli-version-checker) from 3.0.1 to 3.1.1. - [Release notes](https://github.com/rwjblue/ember-cli-version-checker/releases) - [Changelog](https://github.com/ember-cli/ember-cli-version-checker/blob/master/CHANGELOG.md) - [Commits](https://github.com/rwjblue/ember-cli-version-checker/compare/v3.0.1...v3.1.1) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 99c7c1dd96f..1e6c8bcc648 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "ember-cli-string-utils": "^1.1.0", "ember-cli-test-info": "^1.0.0", "ember-cli-typescript": "^2.0.0-beta.2", - "ember-cli-version-checker": "^3.0.1", + "ember-cli-version-checker": "^3.1.1", "ember-inflector": "^3.0.0", "git-repo-info": "^2.0.0", "heimdalljs": "^0.3.0", diff --git a/yarn.lock b/yarn.lock index 70a248987b4..8ac5901ea53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3466,11 +3466,11 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-ve resolve "^1.3.3" semver "^5.3.0" -ember-cli-version-checker@^3.0.0, ember-cli-version-checker@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-3.0.1.tgz#2d084d2b261374582c68edb658a7df3a10112749" +ember-cli-version-checker@^3.0.0, ember-cli-version-checker@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-3.1.1.tgz#30337ff33b892011177166750889cc7d61710acc" dependencies: - resolve "^1.9.0" + resolve-package-path "^1.0.11" semver "^5.6.0" ember-cli-yuidoc@^0.8.8: @@ -7772,6 +7772,13 @@ resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" +resolve-package-path@^1.0.11: + version "1.1.1" + resolved "https://registry.yarnpkg.com/resolve-package-path/-/resolve-package-path-1.1.1.tgz#39db6201f7db8800207d8f82cc8005ee30c9200e" + dependencies: + path-root "^0.1.1" + resolve "^1.10.0" + resolve-path@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7" From 6f5332a01e1b074459bdc52fae11e9d95d5937f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 4 Mar 2019 06:09:17 +0000 Subject: [PATCH 2486/2527] Bump ember-cli from 3.7.1 to 3.8.1 Bumps [ember-cli](https://github.com/ember-cli/ember-cli) from 3.7.1 to 3.8.1. - [Release notes](https://github.com/ember-cli/ember-cli/releases) - [Changelog](https://github.com/ember-cli/ember-cli/blob/master/CHANGELOG.md) - [Commits](https://github.com/ember-cli/ember-cli/compare/v3.7.1...v3.8.1) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 366 ++++++++------------------------------------------- 2 files changed, 55 insertions(+), 313 deletions(-) diff --git a/package.json b/package.json index 1e6c8bcc648..9b57dfb8001 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "broccoli-uglify-sourcemap": "^3.0.0", "co": "^4.6.0", "common-tags": "^1.8.0", - "ember-cli": "^3.5.1", + "ember-cli": "^3.8.1", "ember-cli-app-version": "^3.2.0", "ember-cli-blueprint-test-helpers": "^0.19.1", "ember-cli-dependency-checker": "^3.1.0", diff --git a/yarn.lock b/yarn.lock index 8ac5901ea53..7fabe278283 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1005,10 +1005,6 @@ ansi-colors@3.2.3: version "3.2.3" resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" -ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" @@ -1112,10 +1108,6 @@ array-equal@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" -array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -2506,17 +2498,6 @@ callsites@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3" -camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - -camelcase@^2.0.0: - version "2.1.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - camelcase@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" @@ -2537,6 +2518,12 @@ capture-exit@^1.2.0: dependencies: rsvp "^3.3.3" +capture-exit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + dependencies: + rsvp "^4.8.4" + capture-stack-trace@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d" @@ -2603,7 +2590,7 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" dependencies: @@ -2666,21 +2653,15 @@ clean-up-path@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/clean-up-path/-/clean-up-path-1.0.0.tgz#de9e8196519912e749c9eaf67c13d64fac72a3e5" -cli-cursor@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - dependencies: - restore-cursor "^1.0.1" - cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: restore-cursor "^2.0.0" -cli-spinners@^1.1.0: - version "1.3.1" - resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" +cli-spinners@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.0.0.tgz#4b078756fc17a8f72043fdc9f1f14bf4fa87e2df" cli-table3@^0.5.1: version "0.5.1" @@ -2832,7 +2813,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.6, concat-stream@^1.4.7: +concat-stream@^1.4.6: version "1.6.2" resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" dependencies: @@ -2872,16 +2853,15 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" -console-ui@^2.2.2: - version "2.2.3" - resolved "https://registry.npmjs.org/console-ui/-/console-ui-2.2.3.tgz#134b92e632f2c0088f78e52b20f1ca22a95b9a91" +console-ui@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-3.0.0.tgz#8abee8f701f4c3729953f74233624623f0f72100" dependencies: chalk "^2.1.0" - inquirer "^2" + inquirer "^6" json-stable-stringify "^1.0.1" - ora "^2.0.0" + ora "^3.0.0" through "^2.3.8" - user-info "^1.0.0" consolidate@^0.15.1: version "0.15.1" @@ -2973,12 +2953,6 @@ ctype@0.5.3: version "0.5.3" resolved "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - dependencies: - array-find-index "^1.0.1" - d@1: version "1.0.0" resolved "https://registry.npmjs.org/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" @@ -3029,7 +3003,7 @@ debuglog@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" -decamelize@^1.1.2, decamelize@^1.2.0: +decamelize@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -3135,10 +3109,14 @@ dezalgo@^1.0.0, dezalgo@^1.0.1, dezalgo@^1.0.2, dezalgo@~1.0.3: asap "^2.0.0" wrappy "1" -diff@3.5.0, diff@^3.5.0: +diff@3.5.0: version "3.5.0" resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" +diff@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff" + doctrine@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" @@ -3483,10 +3461,11 @@ ember-cli-yuidoc@^0.8.8: rsvp "3.0.14" yuidocjs "^0.10.0" -ember-cli@^3.5.1: - version "3.7.1" - resolved "https://registry.npmjs.org/ember-cli/-/ember-cli-3.7.1.tgz#f307bcd68aaf083612717ab32133120272d89170" +ember-cli@^3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-3.8.1.tgz#2a4f66cf9da3c9665658690e615479af32749807" dependencies: + "@babel/core" "^7.0.0" "@babel/plugin-transform-modules-amd" "^7.2.0" amd-name-resolver "^1.3.1" babel-plugin-module-resolver "^3.1.1" @@ -3509,22 +3488,23 @@ ember-cli@^3.5.1: broccoli-source "^1.1.0" broccoli-stew "^2.0.0" calculate-cache-key-for-tree "^1.1.0" - capture-exit "^1.2.0" - chalk "^2.4.1" + capture-exit "^2.0.0" + chalk "^2.4.2" ci-info "^2.0.0" clean-base-url "^1.0.0" compression "^1.7.3" configstore "^4.0.0" - console-ui "^2.2.2" + console-ui "^3.0.0" core-object "^3.1.5" dag-map "^2.0.2" - diff "^3.5.0" + diff "^4.0.1" ember-cli-broccoli-sane-watcher "^3.0.0" ember-cli-is-package-missing "^1.0.0" ember-cli-lodash-subset "^2.0.1" ember-cli-normalize-entity-name "^1.0.0" ember-cli-preprocess-registry "^3.1.2" ember-cli-string-utils "^1.1.0" + ember-source-channel-url "^1.1.0" ensure-posix-path "^1.0.2" execa "^1.0.0" exit "^0.1.2" @@ -3532,8 +3512,6 @@ ember-cli@^3.5.1: filesize "^3.6.1" find-up "^3.0.0" find-yarn-workspace-root "^1.1.0" - fixturify "^0.3.4" - fixturify-project "^1.5.3" fs-extra "^7.0.0" fs-tree-diff "^1.0.0" get-caller-file "^2.0.0" @@ -3547,7 +3525,7 @@ ember-cli@^3.5.1: inflection "^1.12.0" is-git-url "^1.0.0" isbinaryfile "^3.0.3" - js-yaml "^3.12.0" + js-yaml "^3.12.1" json-stable-stringify "^1.0.1" leek "0.0.24" lodash.template "^4.4.0" @@ -3568,7 +3546,7 @@ ember-cli@^3.5.1: silent-error "^1.1.0" sort-package-json "^1.15.0" symlink-or-copy "^1.2.0" - temp "0.8.3" + temp "0.9.0" testem "^2.9.2" tiny-lr "^1.1.1" tree-sync "^1.2.2" @@ -3787,12 +3765,6 @@ entities@^1.1.1, entities@~1.1.1: version "1.1.2" resolved "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" -error-ex@^1.2.0: - version "1.3.2" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - dependencies: - is-arrayish "^0.2.1" - error@^7.0.0: version "7.0.2" resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz#a5f75fff4d9926126ddac0ea5dc38e689153cb02" @@ -4003,14 +3975,6 @@ events-to-array@^1.0.1: version "1.1.2" resolved "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" -exec-file-sync@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/exec-file-sync/-/exec-file-sync-2.0.2.tgz#58d441db46e40de6d1f30de5be022785bd89e328" - dependencies: - is-obj "^1.0.0" - object-assign "^4.0.1" - spawn-sync "^1.0.11" - exec-sh@^0.2.0: version "0.2.2" resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" @@ -4045,10 +4009,6 @@ exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/exists-sync/-/exists-sync-0.1.0.tgz#318d545213d2b2a31499e92c35f74c94196a22f7" -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - exit@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -4123,14 +4083,6 @@ extend@3, extend@^3.0.0, extend@~3.0.0, extend@~3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" -external-editor@^1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b" - dependencies: - extend "^3.0.0" - spawn-sync "^1.0.15" - tmp "^0.0.29" - external-editor@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" @@ -4271,13 +4223,6 @@ find-index@^1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/find-index/-/find-index-1.1.1.tgz#4b221f8d46b7f8bea33d8faed953f3ca7a081cbc" -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - find-up@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" @@ -4316,14 +4261,7 @@ fireworm@^0.7.0: lodash.flatten "^3.0.2" minimatch "^3.0.2" -fixturify-project@^1.5.3: - version "1.5.3" - resolved "https://registry.npmjs.org/fixturify-project/-/fixturify-project-1.5.3.tgz#2ba4ffec59c1d79ae6638f818c0847eb974d179b" - dependencies: - fixturify "^0.3.4" - tmp "^0.0.33" - -fixturify@^0.3.2, fixturify@^0.3.4: +fixturify@^0.3.2: version "0.3.4" resolved "https://registry.npmjs.org/fixturify/-/fixturify-0.3.4.tgz#c676de404a7f8ee8e64d0b76118e62ec95ab7b25" dependencies: @@ -4607,10 +4545,6 @@ get-func-name@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - get-stdin@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" @@ -5109,12 +5043,6 @@ imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - dependencies: - repeating "^2.0.0" - indexof@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" @@ -5151,26 +5079,7 @@ init-package-json@~1.9.1: validate-npm-package-license "^3.0.1" validate-npm-package-name "^3.0.0" -inquirer@^2: - version "2.0.0" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-2.0.0.tgz#e1351687b90d150ca403ceaa3cefb1e3065bef4b" - dependencies: - ansi-escapes "^1.1.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" - cli-width "^2.0.0" - external-editor "^1.1.0" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.6" - pinkie-promise "^2.0.0" - run-async "^2.2.0" - rx "^4.1.0" - string-width "^2.0.0" - strip-ansi "^3.0.0" - through "^2.3.6" - -inquirer@^6.2.2: +inquirer@^6, inquirer@^6.2.2: version "6.2.2" resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz#46941176f65c9eb20804627149b743a218f25406" dependencies: @@ -5225,10 +5134,6 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -5409,10 +5314,6 @@ is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -5499,9 +5400,9 @@ js-yaml@3.12.0: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@^3.12.0, js-yaml@^3.2.5, js-yaml@^3.2.7: - version "3.12.1" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600" +js-yaml@^3.12.0, js-yaml@^3.12.1, js-yaml@^3.2.5, js-yaml@^3.2.7: + version "3.12.2" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.2.tgz#ef1d067c5a9d9cb65bd72f285b5d8105c77f14fc" dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -5674,16 +5575,6 @@ livereload-js@^2.3.0: version "2.4.0" resolved "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz#447c31cf1ea9ab52fc20db615c5ddf678f78009c" -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - loader.js@^4.7.0: version "4.7.0" resolved "https://registry.npmjs.org/loader.js/-/loader.js-4.7.0.tgz#a1a52902001c83631efde9688b8ab3799325ef1f" @@ -6159,7 +6050,7 @@ lodash.without@~3.2.1: lodash._basedifference "^3.0.0" lodash.restparam "^3.0.0" -lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1: +lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.6.1: version "4.17.11" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" @@ -6175,13 +6066,6 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - lowercase-keys@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" @@ -6226,10 +6110,6 @@ map-cache@^0.2.2: version "0.2.2" resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" -map-obj@^1.0.0, map-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - map-visit@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" @@ -6298,21 +6178,6 @@ memory-streams@^0.1.3: dependencies: readable-stream "~1.0.2" -meow@^3.4.0: - version "3.7.0" - resolved "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" - merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -6418,7 +6283,7 @@ minimist@0.0.8: version "0.0.8" resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: +minimist@^1.1.1, minimist@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -6522,10 +6387,6 @@ mustache@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/mustache/-/mustache-3.0.1.tgz#873855f23aa8a95b150fb96d9836edbc5a1d248a" -mute-stream@0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db" - mute-stream@0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -6633,7 +6494,7 @@ normalize-git-url@~3.0.1: version "3.0.2" resolved "https://registry.npmjs.org/normalize-git-url/-/normalize-git-url-3.0.2.tgz#8e5f14be0bdaedb73e07200310aa416c27350fc4" -normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, "normalize-package-data@~1.0.1 || ^2.0.0": +normalize-package-data@^2.0.0, "normalize-package-data@~1.0.1 || ^2.0.0": version "2.5.0" resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" dependencies: @@ -6856,7 +6717,7 @@ oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" -object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@4.1.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -6930,10 +6791,6 @@ once@~1.3.3: dependencies: wrappy "1" -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - onetime@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" @@ -6962,18 +6819,18 @@ optionator@^0.8.2: type-check "~0.3.2" wordwrap "~1.0.0" -ora@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" +ora@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-3.2.0.tgz#67e98a7e11f7f0ac95deaaaf11bb04de3d09e481" dependencies: - chalk "^2.3.1" + chalk "^2.4.2" cli-cursor "^2.1.0" - cli-spinners "^1.1.0" + cli-spinners "^2.0.0" log-symbols "^2.2.0" - strip-ansi "^4.0.0" + strip-ansi "^5.0.0" wcwidth "^1.0.1" -os-homedir@^1.0.0, os-homedir@^1.0.1: +os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" @@ -6985,10 +6842,6 @@ os-locale@^3.0.0: lcid "^2.0.0" mem "^4.0.0" -os-shim@^0.1.2: - version "0.1.3" - resolved "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" - os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -7073,12 +6926,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - dependencies: - error-ex "^1.2.0" - parse-ms@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d" @@ -7107,24 +6954,12 @@ pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" -passwd-user@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/passwd-user/-/passwd-user-1.2.1.tgz#a01a5dc639ef007dc56364b8178569080ad3a7b8" - dependencies: - exec-file-sync "^2.0.0" - path-array@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271" dependencies: array-index "^1.0.0" -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - dependencies: - pinkie-promise "^2.0.0" - path-exists@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -7163,14 +6998,6 @@ path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - pathval@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" @@ -7179,10 +7006,6 @@ performance-now@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" -pify@^2.0.0: - version "2.3.0" - resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - pify@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" @@ -7445,21 +7268,6 @@ read-package-tree@~5.1.2: read-package-json "^2.0.0" readdir-scoped-modules "^1.0.0" -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - read@1, read@~1.0.1, read@~1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" @@ -7523,13 +7331,6 @@ recast@^0.11.3: private "~0.1.5" source-map "~0.5.0" -redent@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - redeyed@~1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" @@ -7808,13 +7609,6 @@ responselike@1.0.2: dependencies: lowercase-keys "^1.0.0" -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -7830,16 +7624,12 @@ retry@^0.8.0, retry@~0.8.0: version "0.8.0" resolved "https://registry.npmjs.org/retry/-/retry-0.8.0.tgz#2367628dc0edb247b1eab649dc53ac8628ac2d5f" -rimraf@2, rimraf@2.6.3, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: +rimraf@2, rimraf@2.6.3, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@~2.6.2: version "2.6.3" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" dependencies: glob "^7.1.3" -rimraf@~2.2.6: - version "2.2.8" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" - rimraf@~2.5.0: version "2.5.4" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" @@ -7895,10 +7685,6 @@ run-async@^2.2.0: dependencies: is-promise "^2.1.0" -rx@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" - rxjs@^6.4.0: version "6.4.0" resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504" @@ -8231,13 +8017,6 @@ spawn-args@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" -spawn-sync@^1.0.11, spawn-sync@^1.0.15: - version "1.0.15" - resolved "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476" - dependencies: - concat-stream "^1.4.7" - os-shim "^0.1.2" - spawnback@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" @@ -8395,12 +8174,6 @@ strip-ansi@^5.0.0: dependencies: ansi-regex "^4.0.0" -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - dependencies: - is-utf8 "^0.2.0" - strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -8409,12 +8182,6 @@ strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - dependencies: - get-stdin "^4.0.1" - strip-json-comments@2.0.1, strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -8468,12 +8235,11 @@ tar@^2.0.0, tar@~2.2.1: fstream "^1.0.2" inherits "2" -temp@0.8.3: - version "0.8.3" - resolved "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" +temp@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/temp/-/temp-0.9.0.tgz#61391795a11bd9738d4c4d7f55f012cb8f55edaa" dependencies: - os-tmpdir "^1.0.0" - rimraf "~2.2.6" + rimraf "~2.6.2" terser@^3.16.1, terser@^3.7.5: version "3.16.1" @@ -8583,12 +8349,6 @@ tmp@0.0.33, tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" -tmp@^0.0.29: - version "0.0.29" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0" - dependencies: - os-tmpdir "~1.0.1" - tmpl@1.0.x: version "1.0.4" resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -8660,10 +8420,6 @@ tree-sync@^1.2.2: quick-temp "^0.1.5" walk-sync "^0.3.3" -trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - trim-right@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" @@ -8850,24 +8606,10 @@ use@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" -user-info@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/user-info/-/user-info-1.0.0.tgz#81c82b7ed63e674c2475667653413b3c76fde239" - dependencies: - os-homedir "^1.0.1" - passwd-user "^1.2.1" - username "^1.0.1" - username-sync@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/username-sync/-/username-sync-1.0.2.tgz#0a3697909fb7b5768d29e2921f573acfdd427592" -username@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/username/-/username-1.0.1.tgz#e1f72295e3e58e06f002c6327ce06897a99cd67f" - dependencies: - meow "^3.4.0" - util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" From d13e7840e6dead927842f095c3c8f2a4537abf50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20SA=C4=9EDI=C3=87?= Date: Thu, 28 Feb 2019 14:47:15 +0300 Subject: [PATCH 2487/2527] [DOC serializeHasMany ] Update ember-data imports --- addon/serializers/embedded-records-mixin.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/serializers/embedded-records-mixin.js b/addon/serializers/embedded-records-mixin.js index a2c45d38108..454e119cc34 100644 --- a/addon/serializers/embedded-records-mixin.js +++ b/addon/serializers/embedded-records-mixin.js @@ -261,7 +261,7 @@ export default Mixin.create({ Use a custom (type) serializer for the post model to configure embedded comments ```app/serializers/post.js - import DS from 'ember-data; + import DS from 'ember-data'; export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -300,7 +300,7 @@ export default Mixin.create({ To embed the `ids` for a related object (using a hasMany relationship): ```app/serializers/post.js - import DS from 'ember-data; + import DS from 'ember-data'; export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { @@ -348,7 +348,7 @@ export default Mixin.create({ ``` ```app/serializers/user.js - import DS from 'ember-data; + import DS from 'ember-data'; export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { From a859631e8ee173b42045b77188543e23308a37bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 4 Mar 2019 20:23:28 +0000 Subject: [PATCH 2488/2527] Bump @ember-decorators/data from 5.1.3 to 5.1.4 Bumps [@ember-decorators/data](https://github.com/ember-decorators/ember-decorators) from 5.1.3 to 5.1.4. - [Release notes](https://github.com/ember-decorators/ember-decorators/releases) - [Commits](https://github.com/ember-decorators/ember-decorators/compare/v5.1.3...v5.1.4) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 9b57dfb8001..bc0e465018e 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "devDependencies": { "@babel/plugin-transform-typescript": "^7.2.0", "@ember-decorators/babel-transforms": "^5.1.4", - "@ember-decorators/data": "^5.1.2", + "@ember-decorators/data": "^5.1.4", "@types/ember": "~3.0.25", "@types/ember-qunit": "~3.4.5", "@types/ember-test-helpers": "~1.0.4", diff --git a/yarn.lock b/yarn.lock index 7fabe278283..ffe48b6a990 100644 --- a/yarn.lock +++ b/yarn.lock @@ -652,11 +652,11 @@ ember-cli-babel "^7.1.3" ember-compatibility-helpers "^1.1.2" -"@ember-decorators/data@^5.1.2", "@ember-decorators/data@^5.1.3": - version "5.1.3" - resolved "https://registry.npmjs.org/@ember-decorators/data/-/data-5.1.3.tgz#a2bee8be053bb4a61c3666839d1d431cd37389c1" +"@ember-decorators/data@^5.1.3", "@ember-decorators/data@^5.1.4": + version "5.1.4" + resolved "https://registry.yarnpkg.com/@ember-decorators/data/-/data-5.1.4.tgz#08e0fefe83ce855bcc5837bd8ea7feb5ecefb2ac" dependencies: - "@ember-decorators/utils" "^5.1.3" + "@ember-decorators/utils" "^5.1.4" ember-cli-babel "^7.1.3" ember-compatibility-helpers "^1.1.2" @@ -676,9 +676,9 @@ ember-cli-babel "^7.1.3" ember-compatibility-helpers "^1.1.2" -"@ember-decorators/utils@^5.1.3": - version "5.1.3" - resolved "https://registry.npmjs.org/@ember-decorators/utils/-/utils-5.1.3.tgz#c9ae884ce51943718a2ce9b5ed7abe6677645756" +"@ember-decorators/utils@^5.1.3", "@ember-decorators/utils@^5.1.4": + version "5.1.4" + resolved "https://registry.yarnpkg.com/@ember-decorators/utils/-/utils-5.1.4.tgz#e8a18e614b3bd282c548803fd5e94d49d8fbaeee" dependencies: babel-plugin-debug-macros "^0.2.0" ember-cli-babel "^7.1.3" From f8a908b034b06171319b3e53b5ca3498a336e22a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 4 Mar 2019 20:15:00 +0000 Subject: [PATCH 2489/2527] Bump mocha from 6.0.1 to 6.0.2 Bumps [mocha](https://github.com/mochajs/mocha) from 6.0.1 to 6.0.2. - [Release notes](https://github.com/mochajs/mocha/releases) - [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md) - [Commits](https://github.com/mochajs/mocha/compare/v6.0.1...v6.0.2) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index bc0e465018e..6e816fef78f 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "glob": "^7.1.3", "json-typescript": "^1.1.0", "loader.js": "^4.7.0", - "mocha": "^6.0.0", + "mocha": "^6.0.2", "mocha-only-detector": "1.0.0", "prettier": "^1.15.3", "rimraf": "^2.6.2", diff --git a/yarn.lock b/yarn.lock index ffe48b6a990..698992572ba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6323,9 +6323,9 @@ mocha-only-detector@1.0.0: esprimaq "^0.0.1" glob "^4.3.2" -mocha@^6.0.0: - version "6.0.1" - resolved "https://registry.npmjs.org/mocha/-/mocha-6.0.1.tgz#c287da87913fa0edc4c44850ba8bc4fdbf20d3ea" +mocha@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.0.2.tgz#cdc1a6fdf66472c079b5605bac59d29807702d2c" dependencies: ansi-colors "3.2.3" browser-stdout "1.3.1" From 07d96e8d30299a070796a41a7c24679f98ff1371 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 4 Mar 2019 21:13:13 +0000 Subject: [PATCH 2490/2527] Bump ember-decorators from 5.1.3 to 5.1.4 Bumps [ember-decorators](https://github.com/ember-decorators/ember-decorators) from 5.1.3 to 5.1.4. - [Release notes](https://github.com/ember-decorators/ember-decorators/releases) - [Commits](https://github.com/ember-decorators/ember-decorators/compare/v5.1.3...v5.1.4) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 52 ++++++++++++++++++++++++++-------------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 6e816fef78f..cbf921a46c1 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "ember-cli-typescript-blueprints": "^2.0.0-beta.1", "ember-cli-uglify": "2.1.0", "ember-cli-yuidoc": "^0.8.8", - "ember-decorators": "^5.1.2", + "ember-decorators": "^5.1.4", "ember-disable-prototype-extensions": "^1.1.3", "ember-export-application-global": "^2.0.0", "ember-load-initializers": "^2.0.0", diff --git a/yarn.lock b/yarn.lock index 698992572ba..e7c7306e806 100644 --- a/yarn.lock +++ b/yarn.lock @@ -637,22 +637,22 @@ ember-cli-babel-plugin-helpers "^1.0.0" ember-cli-version-checker "^3.0.0" -"@ember-decorators/component@^5.1.3": - version "5.1.3" - resolved "https://registry.npmjs.org/@ember-decorators/component/-/component-5.1.3.tgz#f78c78f8b67ec88bbd00002ef855afb0c8d87f66" +"@ember-decorators/component@^5.1.4": + version "5.1.4" + resolved "https://registry.yarnpkg.com/@ember-decorators/component/-/component-5.1.4.tgz#bb1fba00fc025366cf1f60252b76c07ac8b6fbbe" dependencies: - "@ember-decorators/utils" "^5.1.3" + "@ember-decorators/utils" "^5.1.4" ember-cli-babel "^7.1.3" -"@ember-decorators/controller@^5.1.3": - version "5.1.3" - resolved "https://registry.npmjs.org/@ember-decorators/controller/-/controller-5.1.3.tgz#3fc6c8001716eed42bae468dbd3b5a6cb5160222" +"@ember-decorators/controller@^5.1.4": + version "5.1.4" + resolved "https://registry.yarnpkg.com/@ember-decorators/controller/-/controller-5.1.4.tgz#8dd322bccd81a97892979bd44c92c9aa9d4fe272" dependencies: - "@ember-decorators/utils" "^5.1.3" + "@ember-decorators/utils" "^5.1.4" ember-cli-babel "^7.1.3" ember-compatibility-helpers "^1.1.2" -"@ember-decorators/data@^5.1.3", "@ember-decorators/data@^5.1.4": +"@ember-decorators/data@^5.1.4": version "5.1.4" resolved "https://registry.yarnpkg.com/@ember-decorators/data/-/data-5.1.4.tgz#08e0fefe83ce855bcc5837bd8ea7feb5ecefb2ac" dependencies: @@ -660,23 +660,23 @@ ember-cli-babel "^7.1.3" ember-compatibility-helpers "^1.1.2" -"@ember-decorators/object@^5.1.3": - version "5.1.3" - resolved "https://registry.npmjs.org/@ember-decorators/object/-/object-5.1.3.tgz#3b85eaf47d18ab3c9f271cc9c216cbdb62c8263d" +"@ember-decorators/object@^5.1.4": + version "5.1.4" + resolved "https://registry.yarnpkg.com/@ember-decorators/object/-/object-5.1.4.tgz#41ea33864cf742b42e47b6d13b6edf8baa5e7b28" dependencies: - "@ember-decorators/utils" "^5.1.3" + "@ember-decorators/utils" "^5.1.4" ember-cli-babel "^7.1.3" ember-compatibility-helpers "^1.1.2" -"@ember-decorators/service@^5.1.3": - version "5.1.3" - resolved "https://registry.npmjs.org/@ember-decorators/service/-/service-5.1.3.tgz#4034277d0c428388d47b48886dea35bccebc9d09" +"@ember-decorators/service@^5.1.4": + version "5.1.4" + resolved "https://registry.yarnpkg.com/@ember-decorators/service/-/service-5.1.4.tgz#a42525245eff3fc327845bdbca4bb38f9e3a6663" dependencies: - "@ember-decorators/utils" "^5.1.3" + "@ember-decorators/utils" "^5.1.4" ember-cli-babel "^7.1.3" ember-compatibility-helpers "^1.1.2" -"@ember-decorators/utils@^5.1.3", "@ember-decorators/utils@^5.1.4": +"@ember-decorators/utils@^5.1.4": version "5.1.4" resolved "https://registry.yarnpkg.com/@ember-decorators/utils/-/utils-5.1.4.tgz#e8a18e614b3bd282c548803fd5e94d49d8fbaeee" dependencies: @@ -3564,15 +3564,15 @@ ember-compatibility-helpers@^1.1.1, ember-compatibility-helpers@^1.1.2: ember-cli-version-checker "^2.1.1" semver "^5.4.1" -ember-decorators@^5.1.2: - version "5.1.3" - resolved "https://registry.npmjs.org/ember-decorators/-/ember-decorators-5.1.3.tgz#dafcca32e7acaa68ddb88420f6cd8e78a9edc35a" +ember-decorators@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/ember-decorators/-/ember-decorators-5.1.4.tgz#d574fbfab85bb3938f1dd18f5a0b1569ea0eb4cb" dependencies: - "@ember-decorators/component" "^5.1.3" - "@ember-decorators/controller" "^5.1.3" - "@ember-decorators/data" "^5.1.3" - "@ember-decorators/object" "^5.1.3" - "@ember-decorators/service" "^5.1.3" + "@ember-decorators/component" "^5.1.4" + "@ember-decorators/controller" "^5.1.4" + "@ember-decorators/data" "^5.1.4" + "@ember-decorators/object" "^5.1.4" + "@ember-decorators/service" "^5.1.4" ember-cli-babel "^7.1.3" semver "^5.5.0" From 388dbe77ea65110bea184ddcee2850c492ada44d Mon Sep 17 00:00:00 2001 From: Igor Terzic Date: Mon, 25 Feb 2019 20:10:23 -0800 Subject: [PATCH 2491/2527] Stop resurecting internalModels while fetching After fixes in snapshots, we no longer need to do this --- addon/-private/system/store.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index e0b52fca2b6..96a433dc38c 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -965,18 +965,6 @@ const Store = Service.extend({ seeking[internalModel.id] = pendingItem; } - for (let i = 0; i < totalItems; i++) { - let internalModel = internalModels[i]; - // We may have unloaded the record after scheduling this fetch, in which - // case we must cancel the destroy. This is because we require a record - // to build a snapshot. This is not fundamental: this cancelation code - // can be removed when snapshots can be created for internal models that - // have no records. - if (internalModel.hasScheduledDestroy()) { - internalModels[i].cancelDestroy(); - } - } - function _fetchRecord(recordResolverPair) { let recordFetch = store._fetchRecord( recordResolverPair.internalModel, From 1c9287464121f4a3b0667de8d0917c424fc1fd70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Mon, 4 Mar 2019 20:13:55 +0000 Subject: [PATCH 2492/2527] Bump eslint-config-prettier from 4.0.0 to 4.1.0 Bumps [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) from 4.0.0 to 4.1.0. - [Release notes](https://github.com/prettier/eslint-config-prettier/releases) - [Changelog](https://github.com/prettier/eslint-config-prettier/blob/master/CHANGELOG.md) - [Commits](https://github.com/prettier/eslint-config-prettier/compare/v4.0.0...v4.1.0) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index cbf921a46c1..d069bfcd7db 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "ember-source-channel-url": "^1.1.0", "ember-try": "^1.1.0", "eslint": "^5.15.0", - "eslint-config-prettier": "^4.0.0", + "eslint-config-prettier": "^4.1.0", "eslint-plugin-node": "^8.0.0", "eslint-plugin-prettier": "^3.0.1", "execa": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index e7c7306e806..b3cc558c700 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3822,9 +3822,9 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1 version "1.0.5" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -eslint-config-prettier@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-4.0.0.tgz#16cedeea0a56e74de60dcbbe3be0ab2c645405b9" +eslint-config-prettier@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-4.1.0.tgz#181364895899fff9fd3605fecb5c4f20e7d5f395" dependencies: get-stdin "^6.0.0" From 2858c32dbc9458bb28f95c31a5afdeb7a499ea35 Mon Sep 17 00:00:00 2001 From: Rajasegar Date: Mon, 4 Mar 2019 14:34:46 +0530 Subject: [PATCH 2493/2527] [DOCS] [BUGFIX] recordRef push param must be with type Fixes #5808 Added type to push data with value "user" --- addon/-private/system/references/record.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/references/record.ts b/addon/-private/system/references/record.ts index daaac916018..51b599825db 100644 --- a/addon/-private/system/references/record.ts +++ b/addon/-private/system/references/record.ts @@ -74,7 +74,13 @@ export default class RecordReference extends Reference { let userRef = store.getReference('user', 1); // provide data for reference - userRef.push({ data: { id: 1, username: "@user" }}).then(function(user) { + userRef.push({ + data: { + id: "1", + type: "user", + username: "@user" + } + }).then(function(user) { userRef.value() === user; }); ``` From 328e1b4ff81ac3beb5688bed60717b049f7aa671 Mon Sep 17 00:00:00 2001 From: Rajasegar Chandran Date: Tue, 5 Mar 2019 09:31:11 +0530 Subject: [PATCH 2494/2527] [DOCS] [BUGFIX] Added attributes wrapper object 1. Added attributes wrapper object around username when pushing userRef --- addon/-private/system/references/record.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/references/record.ts b/addon/-private/system/references/record.ts index 51b599825db..db2f6ba176d 100644 --- a/addon/-private/system/references/record.ts +++ b/addon/-private/system/references/record.ts @@ -78,7 +78,9 @@ export default class RecordReference extends Reference { data: { id: "1", type: "user", - username: "@user" + attributes: { + username: "@user" + } } }).then(function(user) { userRef.value() === user; From 8cae7c2b025e98ff23605e0143362a57e8248316 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 5 Mar 2019 05:37:19 +0000 Subject: [PATCH 2495/2527] Bump ember-cli-version-checker from 3.1.1 to 3.1.2 Bumps [ember-cli-version-checker](https://github.com/rwjblue/ember-cli-version-checker) from 3.1.1 to 3.1.2. - [Release notes](https://github.com/rwjblue/ember-cli-version-checker/releases) - [Changelog](https://github.com/ember-cli/ember-cli-version-checker/blob/master/CHANGELOG.md) - [Commits](https://github.com/rwjblue/ember-cli-version-checker/compare/v3.1.1...v3.1.2) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index d069bfcd7db..47c593333ec 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "ember-cli-string-utils": "^1.1.0", "ember-cli-test-info": "^1.0.0", "ember-cli-typescript": "^2.0.0-beta.2", - "ember-cli-version-checker": "^3.1.1", + "ember-cli-version-checker": "^3.1.2", "ember-inflector": "^3.0.0", "git-repo-info": "^2.0.0", "heimdalljs": "^0.3.0", diff --git a/yarn.lock b/yarn.lock index b3cc558c700..1748fed90ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3444,11 +3444,11 @@ ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.0, ember-cli-ve resolve "^1.3.3" semver "^5.3.0" -ember-cli-version-checker@^3.0.0, ember-cli-version-checker@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-3.1.1.tgz#30337ff33b892011177166750889cc7d61710acc" +ember-cli-version-checker@^3.0.0, ember-cli-version-checker@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-3.1.2.tgz#baee5cc621d5259d9011b5ef60fe6fbe61bd57c7" dependencies: - resolve-package-path "^1.0.11" + resolve-package-path "^1.1.1" semver "^5.6.0" ember-cli-yuidoc@^0.8.8: @@ -7573,7 +7573,7 @@ resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" -resolve-package-path@^1.0.11: +resolve-package-path@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/resolve-package-path/-/resolve-package-path-1.1.1.tgz#39db6201f7db8800207d8f82cc8005ee30c9200e" dependencies: From 42eb47e03c8b1118841ed12fad0349e5faebaa43 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Tue, 5 Mar 2019 05:37:02 +0000 Subject: [PATCH 2496/2527] Bump eslint from 5.15.0 to 5.15.1 Bumps [eslint](https://github.com/eslint/eslint) from 5.15.0 to 5.15.1. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v5.15.0...v5.15.1) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 47c593333ec..5cfa1df7b8c 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "ember-source": "~3.8.0", "ember-source-channel-url": "^1.1.0", "ember-try": "^1.1.0", - "eslint": "^5.15.0", + "eslint": "^5.15.1", "eslint-config-prettier": "^4.1.0", "eslint-plugin-node": "^8.0.0", "eslint-plugin-prettier": "^3.0.1", diff --git a/yarn.lock b/yarn.lock index 1748fed90ed..c99e115e2d1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3874,9 +3874,9 @@ eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@^5.15.0: - version "5.15.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.15.0.tgz#f313a2f7c7628d39adeefdba4a9c41f842012c9e" +eslint@^5.15.1: + version "5.15.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.15.1.tgz#8266b089fd5391e0009a047050795b1d73664524" dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.9.1" From a8ff9a78b85818d15532fbe06df2e3d4792f789f Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Sat, 16 Feb 2019 14:22:36 +0100 Subject: [PATCH 2497/2527] Update blueprints to use native JS classes --- .eslintignore | 1 + blueprints/adapter/index.js | 5 +- .../__root__/__path__/__name__.js | 4 + blueprints/edition-detector.js | 12 ++ blueprints/model/index.js | 5 +- .../__root__/__path__/__name__.js | 6 + blueprints/serializer/index.js | 5 +- .../__root__/__path__/__name__.js | 4 + blueprints/transform/index.js | 5 +- .../__root__/__path__/__name__.js | 12 ++ node-tests/blueprints/adapter-test.js | 166 ++++++++++++++++ node-tests/blueprints/model-test.js | 186 ++++++++++++++++++ node-tests/blueprints/serializer-test.js | 177 +++++++++++++++++ node-tests/blueprints/transform-test.js | 117 +++++++++++ node-tests/helpers/setup-test-environment.js | 15 ++ 15 files changed, 712 insertions(+), 8 deletions(-) create mode 100644 blueprints/adapter/native-files/__root__/__path__/__name__.js create mode 100644 blueprints/edition-detector.js create mode 100644 blueprints/model/native-files/__root__/__path__/__name__.js create mode 100644 blueprints/serializer/native-files/__root__/__path__/__name__.js create mode 100644 blueprints/transform/native-files/__root__/__path__/__name__.js create mode 100644 node-tests/helpers/setup-test-environment.js diff --git a/.eslintignore b/.eslintignore index 0d169ddba78..5bdf749fccd 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,3 +4,4 @@ node-tests/fixtures/ blueprints/*/mocha-files/ blueprints/*/qunit-files/ blueprints/*/files/ +blueprints/*/native-files/ diff --git a/blueprints/adapter/index.js b/blueprints/adapter/index.js index 43269d3cdb9..3da434cfb09 100644 --- a/blueprints/adapter/index.js +++ b/blueprints/adapter/index.js @@ -2,8 +2,9 @@ const extendFromApplicationEntity = require('../../lib/utilities/extend-from-app const isModuleUnificationProject = require('../../lib/utilities/module-unification') .isModuleUnificationProject; const path = require('path'); +const useEditionDetector = require('../edition-detector'); -module.exports = { +module.exports = useEditionDetector({ description: 'Generates an ember-data adapter.', availableOptions: [{ name: 'base-class', type: String }], @@ -27,4 +28,4 @@ module.exports = { locals(options) { return extendFromApplicationEntity('adapter', 'DS.JSONAPIAdapter', options); }, -}; +}); diff --git a/blueprints/adapter/native-files/__root__/__path__/__name__.js b/blueprints/adapter/native-files/__root__/__path__/__name__.js new file mode 100644 index 00000000000..5661a61649c --- /dev/null +++ b/blueprints/adapter/native-files/__root__/__path__/__name__.js @@ -0,0 +1,4 @@ +<%= importStatement %> + +export default class <%= classifiedModuleName %>Adapter extends <%= baseClass %> { +} diff --git a/blueprints/edition-detector.js b/blueprints/edition-detector.js new file mode 100644 index 00000000000..9c62029c700 --- /dev/null +++ b/blueprints/edition-detector.js @@ -0,0 +1,12 @@ +'use strict'; + +const path = require('path'); + +module.exports = function(blueprint) { + blueprint.filesPath = function() { + let rootPath = process.env.EMBER_VERSION === 'OCTANE' ? 'native-files' : 'files'; + return path.join(this.path, rootPath); + }; + + return blueprint; +}; diff --git a/blueprints/model/index.js b/blueprints/model/index.js index 102322acdec..fd085042d90 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -4,8 +4,9 @@ const EOL = require('os').EOL; const isModuleUnificationProject = require('../../lib/utilities/module-unification') .isModuleUnificationProject; const path = require('path'); +const useEditionDetector = require('../edition-detector'); -module.exports = { +module.exports = useEditionDetector({ description: 'Generates an ember-data model.', anonymousOptions: ['name', 'attr:type'], @@ -74,7 +75,7 @@ module.exports = { needs: needs, }; }, -}; +}); function dsAttr(name, type) { switch (type) { diff --git a/blueprints/model/native-files/__root__/__path__/__name__.js b/blueprints/model/native-files/__root__/__path__/__name__.js new file mode 100644 index 00000000000..d4ed41f9c76 --- /dev/null +++ b/blueprints/model/native-files/__root__/__path__/__name__.js @@ -0,0 +1,6 @@ +import DS from 'ember-data'; +const { Model } = DS; + +export default class <%= classifiedModuleName %>Model extends Model { +<%= attrs.length ? attrs : '' %> +} diff --git a/blueprints/serializer/index.js b/blueprints/serializer/index.js index 98ad38a9443..7388b042031 100644 --- a/blueprints/serializer/index.js +++ b/blueprints/serializer/index.js @@ -2,8 +2,9 @@ const extendFromApplicationEntity = require('../../lib/utilities/extend-from-app const isModuleUnificationProject = require('../../lib/utilities/module-unification') .isModuleUnificationProject; const path = require('path'); +const useEditionDetector = require('../edition-detector'); -module.exports = { +module.exports = useEditionDetector({ description: 'Generates an ember-data serializer.', availableOptions: [{ name: 'base-class', type: String }], @@ -27,4 +28,4 @@ module.exports = { locals(options) { return extendFromApplicationEntity('serializer', 'DS.JSONAPISerializer', options); }, -}; +}); diff --git a/blueprints/serializer/native-files/__root__/__path__/__name__.js b/blueprints/serializer/native-files/__root__/__path__/__name__.js new file mode 100644 index 00000000000..b1cb9a75cb6 --- /dev/null +++ b/blueprints/serializer/native-files/__root__/__path__/__name__.js @@ -0,0 +1,4 @@ +<%= importStatement %> + +export default class <%= classifiedModuleName %>Serializer extends <%= baseClass %> { +} diff --git a/blueprints/transform/index.js b/blueprints/transform/index.js index 07908a5d3bc..6eec410b89d 100644 --- a/blueprints/transform/index.js +++ b/blueprints/transform/index.js @@ -1,8 +1,9 @@ const isModuleUnificationProject = require('../../lib/utilities/module-unification') .isModuleUnificationProject; const path = require('path'); +const useEditionDetector = require('../edition-detector'); -module.exports = { +module.exports = useEditionDetector({ description: 'Generates an ember-data value transform.', fileMapTokens(options) { @@ -20,4 +21,4 @@ module.exports = { }; } }, -}; +}); diff --git a/blueprints/transform/native-files/__root__/__path__/__name__.js b/blueprints/transform/native-files/__root__/__path__/__name__.js new file mode 100644 index 00000000000..82964161fed --- /dev/null +++ b/blueprints/transform/native-files/__root__/__path__/__name__.js @@ -0,0 +1,12 @@ +import DS from 'ember-data'; +const { Transform } = DS; + +export default class <%= classifiedModuleName %>Transform extends Transform { + deserialize(serialized) { + return serialized; + } + + serialize(deserialized) { + return deserialized; + } +} diff --git a/node-tests/blueprints/adapter-test.js b/node-tests/blueprints/adapter-test.js index 72cdab0bf93..cbeb65dc643 100644 --- a/node-tests/blueprints/adapter-test.js +++ b/node-tests/blueprints/adapter-test.js @@ -15,6 +15,9 @@ const SilentError = require('silent-error'); const generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); const fixture = require('../helpers/fixture'); +const setupTestEnvironment = require('../helpers/setup-test-environment'); +const enableOctane = setupTestEnvironment.enableOctane; + describe('Acceptance: generate and destroy adapter blueprints', function() { setupTestHooks(this); @@ -314,4 +317,167 @@ describe('Acceptance: generate and destroy adapter blueprints', function() { }); }); }); + + describe('octane', function() { + enableOctane(); + + beforeEach(function() { + return emberNew({ isModuleUnification: true }); + }); + + it('adapter', function() { + let args = ['adapter', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/adapter.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default class FooAdapter extends DS.JSONAPIAdapter {'); + + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + + it('adapter extends application adapter if it exists', function() { + let args = ['adapter', 'foo']; + + return emberGenerate(['adapter', 'application'], { isModuleUnification: true }).then(() => + emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/adapter.js')) + .to.contain("import ApplicationAdapter from '../application/adapter';") + .to.contain('export default class FooAdapter extends ApplicationAdapter {'); + + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ) + ); + }); + + it('adapter with --base-class', function() { + let args = ['adapter', 'foo', '--base-class=bar']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/adapter.js')) + .to.contain("import BarAdapter from '../bar/adapter';") + .to.contain('export default class FooAdapter extends BarAdapter {'); + + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + + it('adapter when is named "application"', function() { + let args = ['adapter', 'application']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/application/adapter.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default class ApplicationAdapter extends DS.JSONAPIAdapter {'); + + expect(_file('src/data/models/application/adapter-test.js')).to.equal( + fixture('adapter-test/application-default.js') + ); + }, + { isModuleUnification: true } + ); + }); + + it('adapter-test', function() { + let args = ['adapter-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + + describe('adapter-test with ember-cli-qunit@4.1.0', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-qunit', delete: true }, + ]); + generateFakePackageManifest('ember-cli-qunit', '4.1.0'); + }); + + it('adapter-test-test foo', function() { + return emberGenerateDestroy( + ['adapter-test', 'foo'], + _file => { + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/foo-default.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); + + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('adapter-test for mocha v0.12+', function() { + let args = ['adapter-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/foo-mocha-0.12.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); + + describe('with ember-mocha v0.14+', function() { + beforeEach(function() { + modifyPackages([{ name: 'ember-qunit', delete: true }, { name: 'ember-mocha', dev: true }]); + generateFakePackageManifest('ember-mocha', '0.14.0'); + }); + + it('adapter-test for mocha v0.14+', function() { + let args = ['adapter-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/adapter-test.js')).to.equal( + fixture('adapter-test/mocha-rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); + }); }); diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index c4e6db794c7..c95978ede76 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -12,6 +12,9 @@ const expect = chai.expect; const generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); const fixture = require('../helpers/fixture'); +const setupTestEnvironment = require('../helpers/setup-test-environment'); +const enableOctane = setupTestEnvironment.enableOctane; + describe('Acceptance: generate and destroy model blueprints', function() { setupTestHooks(this); @@ -340,4 +343,187 @@ describe('Acceptance: generate and destroy model blueprints', function() { }); }); }); + + describe('octane', function() { + enableOctane(); + beforeEach(function() { + return emberNew({ isModuleUnification: true }); + }); + + it('model', function() { + let args = ['model', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/model.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default class FooModel extends Model {'); + + expect(_file('src/data/models/foo/model-test.js')).to.equal( + fixture('model-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + + it('model with attrs', function() { + let args = [ + 'model', + 'foo', + 'misc', + 'skills:array', + 'isActive:boolean', + 'birthday:date', + 'someObject:object', + 'age:number', + 'name:string', + 'customAttr:custom-transform', + ]; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/model.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default class FooModel extends Model {') + .to.contain('misc: DS.attr()') + .to.contain("skills: DS.attr('array')") + .to.contain("isActive: DS.attr('boolean')") + .to.contain("birthday: DS.attr('date')") + .to.contain("someObject: DS.attr('object')") + .to.contain("age: DS.attr('number')") + .to.contain("name: DS.attr('string')") + .to.contain("customAttr: DS.attr('custom-transform')"); + + expect(_file('src/data/models/foo/model-test.js')).to.equal( + fixture('model-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + + it('model with belongsTo', function() { + let args = ['model', 'comment', 'post:belongs-to', 'author:belongs-to:user']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/comment/model.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default class CommentModel extends Model {') + .to.contain("post: DS.belongsTo('post')") + .to.contain("author: DS.belongsTo('user')"); + + expect(_file('src/data/models/comment/model-test.js')).to.equal( + fixture('model-test/comment-default.js') + ); + }, + { isModuleUnification: true } + ); + }); + + it('model with hasMany', function() { + let args = ['model', 'post', 'comments:has-many', 'otherComments:has-many:comment']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/post/model.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default class PostModel extends Model {') + .to.contain("comments: DS.hasMany('comment')") + .to.contain("otherComments: DS.hasMany('comment')"); + + expect(_file('src/data/models/post/model-test.js')).to.equal( + fixture('model-test/post-default.js') + ); + }, + { isModuleUnification: true } + ); + }); + + it('model-test', function() { + let args = ['model-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/model-test.js')).to.equal( + fixture('model-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + + describe('model-test with ember-cli-qunit@4.1.0', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-qunit', delete: true }, + ]); + generateFakePackageManifest('ember-cli-qunit', '4.1.0'); + }); + + it('model-test-test foo', function() { + return emberGenerateDestroy( + ['model-test', 'foo'], + _file => { + expect(_file('src/data/models/foo/model-test.js')).to.equal( + fixture('model-test/foo-default.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); + + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('model-test for mocha v0.12+', function() { + let args = ['model-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/model-test.js')).to.equal( + fixture('model-test/foo-mocha-0.12.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); + + describe('with ember-mocha v0.14+', function() { + beforeEach(function() { + modifyPackages([{ name: 'ember-qunit', delete: true }, { name: 'ember-mocha', dev: true }]); + generateFakePackageManifest('ember-mocha', '0.14.0'); + }); + + it('model-test for mocha v0.14+', function() { + let args = ['model-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/model-test.js')).to.equal( + fixture('model-test/mocha-rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); + }); }); diff --git a/node-tests/blueprints/serializer-test.js b/node-tests/blueprints/serializer-test.js index 23169cc78a7..20e5f956f7f 100644 --- a/node-tests/blueprints/serializer-test.js +++ b/node-tests/blueprints/serializer-test.js @@ -15,6 +15,9 @@ const SilentError = require('silent-error'); const generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); const fixture = require('../helpers/fixture'); +const setupTestEnvironment = require('../helpers/setup-test-environment'); +const enableOctane = setupTestEnvironment.enableOctane; + describe('Acceptance: generate and destroy serializer blueprints', function() { setupTestHooks(this); @@ -325,4 +328,178 @@ describe('Acceptance: generate and destroy serializer blueprints', function() { }); }); }); + + describe('octane', function() { + enableOctane(); + + beforeEach(function() { + return emberNew({ isModuleUnification: true }); + }); + + it('serializer', function() { + let args = ['serializer', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/serializer.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default class FooSerializer extends DS.JSONAPISerializer {'); + + expect(_file('src/data/models/foo/serializer-test.js')).to.equal( + fixture('serializer-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + + it('serializer extends application serializer if it exists', function() { + let args = ['serializer', 'foo']; + + return emberGenerate(['serializer', 'application'], { isModuleUnification: true }).then(() => + emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/serializer.js')) + .to.contain("import ApplicationSerializer from '../application/serializer';") + .to.contain('export default class FooSerializer extends ApplicationSerializer {'); + + expect(_file('src/data/models/foo/serializer-test.js')).to.equal( + fixture('serializer-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ) + ); + }); + + it('serializer with --base-class', function() { + let args = ['serializer', 'foo', '--base-class=bar']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/serializer.js')) + .to.contain("import BarSerializer from '../bar/serializer';") + .to.contain('export default class FooSerializer extends BarSerializer'); + + expect(_file('src/data/models/foo/serializer-test.js')).to.equal( + fixture('serializer-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + + xit('serializer throws when --base-class is same as name', function() { + let args = ['serializer', 'foo', '--base-class=foo']; + + return expect(emberGenerate(args, { isModuleUnification: true })).to.be.rejectedWith( + SilentError, + /Serializers cannot extend from themself/ + ); + }); + + it('serializer when is named "application"', function() { + let args = ['serializer', 'application']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/application/serializer.js')) + .to.contain("import DS from 'ember-data';") + .to.contain( + 'export default class ApplicationSerializer extends DS.JSONAPISerializer {' + ); + + expect(_file('src/data/models/application/serializer-test.js')).to.equal( + fixture('serializer-test/application-default.js') + ); + }, + { isModuleUnification: true } + ); + }); + + it('serializer-test', function() { + let args = ['serializer-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/serializer-test.js')).to.equal( + fixture('serializer-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + + describe('serializer-test with ember-cli-qunit@4.1.0', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-qunit', delete: true }, + ]); + generateFakePackageManifest('ember-cli-qunit', '4.1.0'); + }); + + it('serializer-test-test foo', function() { + return emberGenerateDestroy( + ['serializer-test', 'foo'], + _file => { + expect(_file('src/data/models/foo/serializer-test.js')).to.equal( + fixture('serializer-test/foo-default.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); + + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('serializer-test for mocha v0.12+', function() { + let args = ['serializer-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/serializer-test.js')).to.equal( + fixture('serializer-test/foo-mocha-0.12.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); + + describe('with ember-mocha v0.14+', function() { + beforeEach(function() { + modifyPackages([{ name: 'ember-qunit', delete: true }, { name: 'ember-mocha', dev: true }]); + generateFakePackageManifest('ember-mocha', '0.14.0'); + }); + + it('serializer-test for mocha v0.14+', function() { + let args = ['serializer-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/models/foo/serializer-test.js')).to.equal( + fixture('serializer-test/mocha-rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); + }); }); diff --git a/node-tests/blueprints/transform-test.js b/node-tests/blueprints/transform-test.js index 987893e267d..fe4b8da2fb0 100644 --- a/node-tests/blueprints/transform-test.js +++ b/node-tests/blueprints/transform-test.js @@ -12,6 +12,9 @@ const expect = chai.expect; const generateFakePackageManifest = require('../helpers/generate-fake-package-manifest'); const fixture = require('../helpers/fixture'); +const setupTestEnvironment = require('../helpers/setup-test-environment'); +const enableOctane = setupTestEnvironment.enableOctane; + describe('Acceptance: generate and destroy transform blueprints', function() { setupTestHooks(this); @@ -218,4 +221,118 @@ describe('Acceptance: generate and destroy transform blueprints', function() { }); }); }); + + describe('octane', function() { + describe('in app', function() { + enableOctane(); + + beforeEach(function() { + return emberNew({ isModuleUnification: true }); + }); + + it('transform', function() { + let args = ['transform', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/transforms/foo.js')) + .to.contain("import DS from 'ember-data';") + .to.contain('export default class FooTransform extends Transform {') + .to.contain('deserialize(serialized) {') + .to.contain('serialize(deserialized) {'); + + expect(_file('src/data/transforms/foo-test.js')).to.equal( + fixture('transform-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + + it('transform-test', function() { + let args = ['transform-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/transforms/foo-test.js')).to.equal( + fixture('transform-test/rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + + describe('transform-test with ember-cli-qunit@4.1.0', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-qunit', delete: true }, + ]); + generateFakePackageManifest('ember-cli-qunit', '4.1.0'); + }); + + it('transform-test-test foo', function() { + return emberGenerateDestroy( + ['transform-test', 'foo'], + _file => { + expect(_file('src/data/transforms/foo-test.js')).to.equal( + fixture('transform-test/default.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); + + describe('with ember-cli-mocha v0.12+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-cli-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-cli-mocha', '0.12.0'); + }); + + it('transform-test for mocha v0.12+', function() { + let args = ['transform-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/transforms/foo-test.js')).to.equal( + fixture('transform-test/mocha-0.12.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); + + describe('with ember-mocha v0.14+', function() { + beforeEach(function() { + modifyPackages([ + { name: 'ember-qunit', delete: true }, + { name: 'ember-mocha', dev: true }, + ]); + generateFakePackageManifest('ember-mocha', '0.14.0'); + }); + + it('transform-test for mocha v0.14+', function() { + let args = ['transform-test', 'foo']; + + return emberGenerateDestroy( + args, + _file => { + expect(_file('src/data/transforms/foo-test.js')).to.equal( + fixture('transform-test/mocha-rfc232.js') + ); + }, + { isModuleUnification: true } + ); + }); + }); + }); + }); }); diff --git a/node-tests/helpers/setup-test-environment.js b/node-tests/helpers/setup-test-environment.js new file mode 100644 index 00000000000..ed95e52ef98 --- /dev/null +++ b/node-tests/helpers/setup-test-environment.js @@ -0,0 +1,15 @@ +function enableOctane() { + beforeEach(function() { + process.env.EMBER_CLI_MODULE_UNIFICATION = true; + process.env.EMBER_VERSION = 'OCTANE'; + }); + + afterEach(function() { + delete process.env.EMBER_CLI_MODULE_UNIFICATION; + delete process.env.EMBER_VERSION; + }); +} + +module.exports = { + enableOctane, +}; From d18a29f6c8dce129636868dfe60f00d0041140c0 Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Fri, 22 Feb 2019 05:30:11 +0100 Subject: [PATCH 2498/2527] Model blueprint: refactor the creation of the `attrs` variable --- blueprints/model/index.js | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/blueprints/model/index.js b/blueprints/model/index.js index fd085042d90..c7ccded3a27 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -48,16 +48,27 @@ module.exports = useEditionDetector({ let attr; if (/has-many/.test(dasherizedType)) { let camelizedNamePlural = inflection.pluralize(camelizedName); - attr = dsAttr(dasherizedForeignModelSingular, dasherizedType); - attrs.push(camelizedNamePlural + ': ' + attr); + attr = { + name: dasherizedForeignModelSingular, + type: dasherizedType, + propertyName: camelizedNamePlural + }; } else if (/belongs-to/.test(dasherizedType)) { - attr = dsAttr(dasherizedForeignModel, dasherizedType); - attrs.push(camelizedName + ': ' + attr); + attr = { + name: dasherizedForeignModel, + type: dasherizedType, + propertyName: camelizedName + }; } else { - attr = dsAttr(dasherizedName, dasherizedType); - attrs.push(camelizedName + ': ' + attr); + attr = { + name: dasherizedName, + type: dasherizedType, + propertyName: camelizedName + }; } + attrs.push(attr); + if (/has-many|belongs-to/.test(dasherizedType)) { needs.push("'model:" + dasherizedForeignModelSingular + "'"); } @@ -67,7 +78,11 @@ module.exports = useEditionDetector({ return needs.indexOf(need) === i; }); + attrs = attrs.map(function(attr) { + return attr.propertyName + ': ' + dsAttr(attr.name, attr.type); + }); attrs = attrs.join(',' + EOL + ' '); + needs = ' needs: [' + needsDeduplicated.join(', ') + ']'; return { From 2c2abcf4c417f30b13798ed992594949cf37209d Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Fri, 22 Feb 2019 06:24:40 +0100 Subject: [PATCH 2499/2527] Model blueprint generates `attr` with decorators --- blueprints/model/index.js | 79 +++++++++++++++++++++-------- node-tests/blueprints/model-test.js | 24 ++++----- 2 files changed, 69 insertions(+), 34 deletions(-) diff --git a/blueprints/model/index.js b/blueprints/model/index.js index c7ccded3a27..bed9d8d453a 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -51,22 +51,21 @@ module.exports = useEditionDetector({ attr = { name: dasherizedForeignModelSingular, type: dasherizedType, - propertyName: camelizedNamePlural + propertyName: camelizedNamePlural, }; } else if (/belongs-to/.test(dasherizedType)) { attr = { name: dasherizedForeignModel, type: dasherizedType, - propertyName: camelizedName + propertyName: camelizedName, }; } else { attr = { name: dasherizedName, type: dasherizedType, - propertyName: camelizedName + propertyName: camelizedName, }; } - attrs.push(attr); if (/has-many|belongs-to/.test(dasherizedType)) { @@ -74,15 +73,20 @@ module.exports = useEditionDetector({ } } + let attrTransformer, attrSeparator; + if (process.env.EMBER_VERSION === 'OCTANE') { + attrTransformer = nativeAttr; + attrSeparator = ';'; + } else { + attrTransformer = classicAttr; + attrSeparator = ','; + } + attrs = attrs.map(attrTransformer); + attrs = attrs.join(attrSeparator + EOL + ' '); + let needsDeduplicated = needs.filter(function(need, i) { return needs.indexOf(need) === i; }); - - attrs = attrs.map(function(attr) { - return attr.propertyName + ': ' + dsAttr(attr.name, attr.type); - }); - attrs = attrs.join(',' + EOL + ' '); - needs = ' needs: [' + needsDeduplicated.join(', ') + ']'; return { @@ -92,17 +96,48 @@ module.exports = useEditionDetector({ }, }); -function dsAttr(name, type) { - switch (type) { - case 'belongs-to': - return "DS.belongsTo('" + name + "')"; - case 'has-many': - return "DS.hasMany('" + name + "')"; - case '': - //"If you don't specify the type of the attribute, it will be whatever was provided by the server" - //https://emberjs.com/guides/models/defining-models/ - return 'DS.attr()'; - default: - return "DS.attr('" + type + "')"; +function nativeAttr(attr) { + let name = attr.name, + type = attr.type, + propertyName = attr.propertyName, + result; + + if (type === 'belongs-to') { + if (name === propertyName) { + result = '@DS.belongsTo'; + } else { + result = "@DS.belongsTo('" + name + "')"; + } + } else if (type === 'has-many') { + if (inflection.pluralize(name) === propertyName) { + result = '@DS.hasMany'; + } else { + result = "@DS.hasMany('" + name + "')"; + } + } else if (type === '') { + result = '@DS.attr'; + } else { + result = "@DS.attr('" + type + "')"; + } + return result + ' ' + propertyName; +} + +function classicAttr(attr) { + let name = attr.name, + type = attr.type, + propertyName = attr.propertyName, + result; + + if (type === 'belongs-to') { + result = "DS.belongsTo('" + name + "')"; + } else if (type === 'has-many') { + result = "DS.hasMany('" + name + "')"; + } else if (type === '') { + //"If you don't specify the type of the attribute, it will be whatever was provided by the server" + //https://emberjs.com/guides/models/defining-models/ + result = 'DS.attr()'; + } else { + result = "DS.attr('" + type + "')"; } + return propertyName + ': ' + result; } diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index c95978ede76..a699a011a24 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -388,14 +388,14 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('src/data/models/foo/model.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default class FooModel extends Model {') - .to.contain('misc: DS.attr()') - .to.contain("skills: DS.attr('array')") - .to.contain("isActive: DS.attr('boolean')") - .to.contain("birthday: DS.attr('date')") - .to.contain("someObject: DS.attr('object')") - .to.contain("age: DS.attr('number')") - .to.contain("name: DS.attr('string')") - .to.contain("customAttr: DS.attr('custom-transform')"); + .to.contain('@DS.attr misc') + .to.contain("@DS.attr('array') skills") + .to.contain("@DS.attr('boolean') isActive") + .to.contain("@DS.attr('date') birthday") + .to.contain("@DS.attr('object') someObject") + .to.contain("@DS.attr('number') age") + .to.contain("@DS.attr('string') name") + .to.contain("@DS.attr('custom-transform') customAttr"); expect(_file('src/data/models/foo/model-test.js')).to.equal( fixture('model-test/rfc232.js') @@ -414,8 +414,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('src/data/models/comment/model.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default class CommentModel extends Model {') - .to.contain("post: DS.belongsTo('post')") - .to.contain("author: DS.belongsTo('user')"); + .to.contain('@DS.belongsTo post') + .to.contain("@DS.belongsTo('user') author"); expect(_file('src/data/models/comment/model-test.js')).to.equal( fixture('model-test/comment-default.js') @@ -434,8 +434,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('src/data/models/post/model.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default class PostModel extends Model {') - .to.contain("comments: DS.hasMany('comment')") - .to.contain("otherComments: DS.hasMany('comment')"); + .to.contain('@DS.hasMany comments') + .to.contain("@DS.hasMany('comment') otherComments"); expect(_file('src/data/models/post/model-test.js')).to.equal( fixture('model-test/post-default.js') From 076134992a2dae7d68c7f232caba51e5f6f1d4cd Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Sat, 2 Mar 2019 06:29:33 +0100 Subject: [PATCH 2500/2527] Fix missing semicolon on Native syntax --- blueprints/model/index.js | 26 +++++++++++++++++--------- node-tests/blueprints/model-test.js | 24 ++++++++++++------------ 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/blueprints/model/index.js b/blueprints/model/index.js index bed9d8d453a..82bbd85781a 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -73,16 +73,24 @@ module.exports = useEditionDetector({ } } - let attrTransformer, attrSeparator; - if (process.env.EMBER_VERSION === 'OCTANE') { - attrTransformer = nativeAttr; - attrSeparator = ';'; - } else { - attrTransformer = classicAttr; - attrSeparator = ','; + if (attrs.length) { + let isOctane = process.env.EMBER_VERSION === 'OCTANE'; + + let attrTransformer, attrSeparator; + if (isOctane) { + attrTransformer = nativeAttr; + attrSeparator = ';'; + } else { + attrTransformer = classicAttr; + attrSeparator = ','; + } + + attrs = attrs.map(attrTransformer); + attrs = ' ' + attrs.join(attrSeparator + EOL + ' '); + if (isOctane) { + attrs = attrs + attrSeparator; + } } - attrs = attrs.map(attrTransformer); - attrs = attrs.join(attrSeparator + EOL + ' '); let needsDeduplicated = needs.filter(function(need, i) { return needs.indexOf(need) === i; diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index a699a011a24..643e0ddfe97 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -388,14 +388,14 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('src/data/models/foo/model.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default class FooModel extends Model {') - .to.contain('@DS.attr misc') - .to.contain("@DS.attr('array') skills") - .to.contain("@DS.attr('boolean') isActive") - .to.contain("@DS.attr('date') birthday") - .to.contain("@DS.attr('object') someObject") - .to.contain("@DS.attr('number') age") - .to.contain("@DS.attr('string') name") - .to.contain("@DS.attr('custom-transform') customAttr"); + .to.contain('@DS.attr misc;') + .to.contain("@DS.attr('array') skills;") + .to.contain("@DS.attr('boolean') isActive;") + .to.contain("@DS.attr('date') birthday;") + .to.contain("@DS.attr('object') someObject;") + .to.contain("@DS.attr('number') age;") + .to.contain("@DS.attr('string') name;") + .to.contain("@DS.attr('custom-transform') customAttr;"); expect(_file('src/data/models/foo/model-test.js')).to.equal( fixture('model-test/rfc232.js') @@ -414,8 +414,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('src/data/models/comment/model.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default class CommentModel extends Model {') - .to.contain('@DS.belongsTo post') - .to.contain("@DS.belongsTo('user') author"); + .to.contain('@DS.belongsTo post;') + .to.contain("@DS.belongsTo('user') author;"); expect(_file('src/data/models/comment/model-test.js')).to.equal( fixture('model-test/comment-default.js') @@ -434,8 +434,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('src/data/models/post/model.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default class PostModel extends Model {') - .to.contain('@DS.hasMany comments') - .to.contain("@DS.hasMany('comment') otherComments"); + .to.contain('@DS.hasMany comments;') + .to.contain("@DS.hasMany('comment') otherComments;"); expect(_file('src/data/models/post/model-test.js')).to.equal( fixture('model-test/post-default.js') From 7007097bd0a1b86d1c99fcbc9eea01742ab3781d Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Sat, 2 Mar 2019 06:40:40 +0100 Subject: [PATCH 2501/2527] The Model blueprint test validates attr whitespaces and separators --- node-tests/blueprints/model-test.js | 72 ++++++++++++++--------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index 643e0ddfe97..cb92ae2dd11 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -53,14 +53,14 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('app/models/foo.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default DS.Model.extend(') - .to.contain('misc: DS.attr()') - .to.contain("skills: DS.attr('array')") - .to.contain("isActive: DS.attr('boolean')") - .to.contain("birthday: DS.attr('date')") - .to.contain("someObject: DS.attr('object')") - .to.contain("age: DS.attr('number')") - .to.contain("name: DS.attr('string')") - .to.contain("customAttr: DS.attr('custom-transform')"); + .to.contain(' misc: DS.attr(),') + .to.contain(" skills: DS.attr('array'),") + .to.contain(" isActive: DS.attr('boolean'),") + .to.contain(" birthday: DS.attr('date'),") + .to.contain(" someObject: DS.attr('object'),") + .to.contain(" age: DS.attr('number'),") + .to.contain(" name: DS.attr('string'),") + .to.contain(" customAttr: DS.attr('custom-transform')"); expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/rfc232.js')); }); @@ -73,8 +73,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('app/models/comment.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default DS.Model.extend(') - .to.contain("post: DS.belongsTo('post')") - .to.contain("author: DS.belongsTo('user')"); + .to.contain(" post: DS.belongsTo('post'),") + .to.contain(" author: DS.belongsTo('user')"); expect(_file('tests/unit/models/comment-test.js')).to.equal( fixture('model-test/comment-default.js') @@ -89,8 +89,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('app/models/post.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default DS.Model.extend(') - .to.contain("comments: DS.hasMany('comment')") - .to.contain("otherComments: DS.hasMany('comment')"); + .to.contain(" comments: DS.hasMany('comment')") + .to.contain(" otherComments: DS.hasMany('comment')"); expect(_file('tests/unit/models/post-test.js')).to.equal( fixture('model-test/post-default.js') @@ -205,14 +205,14 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('src/data/models/foo/model.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default DS.Model.extend(') - .to.contain('misc: DS.attr()') - .to.contain("skills: DS.attr('array')") - .to.contain("isActive: DS.attr('boolean')") - .to.contain("birthday: DS.attr('date')") - .to.contain("someObject: DS.attr('object')") - .to.contain("age: DS.attr('number')") - .to.contain("name: DS.attr('string')") - .to.contain("customAttr: DS.attr('custom-transform')"); + .to.contain(' misc: DS.attr(),') + .to.contain(" skills: DS.attr('array'),") + .to.contain(" isActive: DS.attr('boolean'),") + .to.contain(" birthday: DS.attr('date'),") + .to.contain(" someObject: DS.attr('object'),") + .to.contain(" age: DS.attr('number'),") + .to.contain(" name: DS.attr('string'),") + .to.contain(" customAttr: DS.attr('custom-transform')"); expect(_file('src/data/models/foo/model-test.js')).to.equal( fixture('model-test/rfc232.js') @@ -231,8 +231,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('src/data/models/comment/model.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default DS.Model.extend(') - .to.contain("post: DS.belongsTo('post')") - .to.contain("author: DS.belongsTo('user')"); + .to.contain(" post: DS.belongsTo('post'),") + .to.contain(" author: DS.belongsTo('user')"); expect(_file('src/data/models/comment/model-test.js')).to.equal( fixture('model-test/comment-default.js') @@ -251,8 +251,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('src/data/models/post/model.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default DS.Model.extend(') - .to.contain("comments: DS.hasMany('comment')") - .to.contain("otherComments: DS.hasMany('comment')"); + .to.contain(" comments: DS.hasMany('comment'),") + .to.contain(" otherComments: DS.hasMany('comment')"); expect(_file('src/data/models/post/model-test.js')).to.equal( fixture('model-test/post-default.js') @@ -388,14 +388,14 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('src/data/models/foo/model.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default class FooModel extends Model {') - .to.contain('@DS.attr misc;') - .to.contain("@DS.attr('array') skills;") - .to.contain("@DS.attr('boolean') isActive;") - .to.contain("@DS.attr('date') birthday;") - .to.contain("@DS.attr('object') someObject;") - .to.contain("@DS.attr('number') age;") - .to.contain("@DS.attr('string') name;") - .to.contain("@DS.attr('custom-transform') customAttr;"); + .to.contain(' @DS.attr misc;') + .to.contain(" @DS.attr('array') skills;") + .to.contain(" @DS.attr('boolean') isActive;") + .to.contain(" @DS.attr('date') birthday;") + .to.contain(" @DS.attr('object') someObject;") + .to.contain(" @DS.attr('number') age;") + .to.contain(" @DS.attr('string') name;") + .to.contain(" @DS.attr('custom-transform') customAttr;"); expect(_file('src/data/models/foo/model-test.js')).to.equal( fixture('model-test/rfc232.js') @@ -414,8 +414,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('src/data/models/comment/model.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default class CommentModel extends Model {') - .to.contain('@DS.belongsTo post;') - .to.contain("@DS.belongsTo('user') author;"); + .to.contain(' @DS.belongsTo post;') + .to.contain(" @DS.belongsTo('user') author;"); expect(_file('src/data/models/comment/model-test.js')).to.equal( fixture('model-test/comment-default.js') @@ -434,8 +434,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { expect(_file('src/data/models/post/model.js')) .to.contain("import DS from 'ember-data';") .to.contain('export default class PostModel extends Model {') - .to.contain('@DS.hasMany comments;') - .to.contain("@DS.hasMany('comment') otherComments;"); + .to.contain(' @DS.hasMany comments;') + .to.contain(" @DS.hasMany('comment') otherComments;"); expect(_file('src/data/models/post/model-test.js')).to.equal( fixture('model-test/post-default.js') From a3b642b4d493365cda92c6e5c7820171f3896f4a Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Thu, 7 Mar 2019 12:58:12 +0100 Subject: [PATCH 2502/2527] Improve Model Blueprint syntax on Octane apps --- blueprints/model/index.js | 38 +++++++++++++++---- .../__root__/__path__/__name__.js | 2 +- node-tests/blueprints/model-test.js | 27 +++++++------ 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/blueprints/model/index.js b/blueprints/model/index.js index 82bbd85781a..399b61698df 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -31,6 +31,10 @@ module.exports = useEditionDetector({ let attrs = []; let needs = []; let entityOptions = options.entity.options; + let includeHasMany = false; + let includeBelongsTo = false; + let includeAttr = false; + let importedModules = null; for (let name in entityOptions) { let type = entityOptions[name] || ''; @@ -47,6 +51,7 @@ module.exports = useEditionDetector({ let attr; if (/has-many/.test(dasherizedType)) { + includeHasMany = true; let camelizedNamePlural = inflection.pluralize(camelizedName); attr = { name: dasherizedForeignModelSingular, @@ -54,12 +59,14 @@ module.exports = useEditionDetector({ propertyName: camelizedNamePlural, }; } else if (/belongs-to/.test(dasherizedType)) { + includeBelongsTo = true; attr = { name: dasherizedForeignModel, type: dasherizedType, propertyName: camelizedName, }; } else { + includeAttr = true; attr = { name: dasherizedName, type: dasherizedType, @@ -73,9 +80,9 @@ module.exports = useEditionDetector({ } } - if (attrs.length) { - let isOctane = process.env.EMBER_VERSION === 'OCTANE'; + let isOctane = process.env.EMBER_VERSION === 'OCTANE'; + if (attrs.length) { let attrTransformer, attrSeparator; if (isOctane) { attrTransformer = nativeAttr; @@ -97,7 +104,22 @@ module.exports = useEditionDetector({ }); needs = ' needs: [' + needsDeduplicated.join(', ') + ']'; + if (isOctane) { + importedModules = ['Model']; + if (includeAttr) { + importedModules.push('attr'); + } + if (includeBelongsTo) { + importedModules.push('belongsTo'); + } + if (includeHasMany) { + importedModules.push('hasMany'); + } + importedModules = importedModules.join(', '); + } + return { + importedModules: importedModules, attrs: attrs, needs: needs, }; @@ -112,20 +134,20 @@ function nativeAttr(attr) { if (type === 'belongs-to') { if (name === propertyName) { - result = '@DS.belongsTo'; + result = '@belongsTo'; } else { - result = "@DS.belongsTo('" + name + "')"; + result = "@belongsTo('" + name + "')"; } } else if (type === 'has-many') { if (inflection.pluralize(name) === propertyName) { - result = '@DS.hasMany'; + result = '@hasMany'; } else { - result = "@DS.hasMany('" + name + "')"; + result = "@hasMany('" + name + "')"; } } else if (type === '') { - result = '@DS.attr'; + result = '@attr'; } else { - result = "@DS.attr('" + type + "')"; + result = "@attr('" + type + "')"; } return result + ' ' + propertyName; } diff --git a/blueprints/model/native-files/__root__/__path__/__name__.js b/blueprints/model/native-files/__root__/__path__/__name__.js index d4ed41f9c76..6808bf44cf8 100644 --- a/blueprints/model/native-files/__root__/__path__/__name__.js +++ b/blueprints/model/native-files/__root__/__path__/__name__.js @@ -1,5 +1,5 @@ import DS from 'ember-data'; -const { Model } = DS; +const { <%= importedModules %> } = DS; export default class <%= classifiedModuleName %>Model extends Model { <%= attrs.length ? attrs : '' %> diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index cb92ae2dd11..94e781a9927 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -387,15 +387,16 @@ describe('Acceptance: generate and destroy model blueprints', function() { _file => { expect(_file('src/data/models/foo/model.js')) .to.contain("import DS from 'ember-data';") + .to.contain('const { Model, attr } = DS;') .to.contain('export default class FooModel extends Model {') - .to.contain(' @DS.attr misc;') - .to.contain(" @DS.attr('array') skills;") - .to.contain(" @DS.attr('boolean') isActive;") - .to.contain(" @DS.attr('date') birthday;") - .to.contain(" @DS.attr('object') someObject;") - .to.contain(" @DS.attr('number') age;") - .to.contain(" @DS.attr('string') name;") - .to.contain(" @DS.attr('custom-transform') customAttr;"); + .to.contain(' @attr misc;') + .to.contain(" @attr('array') skills;") + .to.contain(" @attr('boolean') isActive;") + .to.contain(" @attr('date') birthday;") + .to.contain(" @attr('object') someObject;") + .to.contain(" @attr('number') age;") + .to.contain(" @attr('string') name;") + .to.contain(" @attr('custom-transform') customAttr;"); expect(_file('src/data/models/foo/model-test.js')).to.equal( fixture('model-test/rfc232.js') @@ -413,9 +414,10 @@ describe('Acceptance: generate and destroy model blueprints', function() { _file => { expect(_file('src/data/models/comment/model.js')) .to.contain("import DS from 'ember-data';") + .to.contain('const { Model, belongsTo } = DS;') .to.contain('export default class CommentModel extends Model {') - .to.contain(' @DS.belongsTo post;') - .to.contain(" @DS.belongsTo('user') author;"); + .to.contain(' @belongsTo post;') + .to.contain(" @belongsTo('user') author;"); expect(_file('src/data/models/comment/model-test.js')).to.equal( fixture('model-test/comment-default.js') @@ -433,9 +435,10 @@ describe('Acceptance: generate and destroy model blueprints', function() { _file => { expect(_file('src/data/models/post/model.js')) .to.contain("import DS from 'ember-data';") + .to.contain('const { Model, hasMany } = DS;') .to.contain('export default class PostModel extends Model {') - .to.contain(' @DS.hasMany comments;') - .to.contain(" @DS.hasMany('comment') otherComments;"); + .to.contain(' @hasMany comments;') + .to.contain(" @hasMany('comment') otherComments;"); expect(_file('src/data/models/post/model-test.js')).to.equal( fixture('model-test/post-default.js') From dc84946997cb1cc32b36ea21bd59f1aa6e6801be Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Thu, 7 Mar 2019 13:22:06 +0100 Subject: [PATCH 2503/2527] Improve Model Blueprint syntax on Classic apps --- .../model/files/__root__/__path__/__name__.js | 3 +- blueprints/model/index.js | 35 +++++---- node-tests/blueprints/model-test.js | 72 ++++++++++--------- 3 files changed, 58 insertions(+), 52 deletions(-) diff --git a/blueprints/model/files/__root__/__path__/__name__.js b/blueprints/model/files/__root__/__path__/__name__.js index 3661e07bc60..eacb7a17e62 100644 --- a/blueprints/model/files/__root__/__path__/__name__.js +++ b/blueprints/model/files/__root__/__path__/__name__.js @@ -1,5 +1,6 @@ import DS from 'ember-data'; +const { <%= importedModules %> } = DS; -export default DS.Model.extend({ +export default Model.extend({ <%= attrs.length ? ' ' + attrs : '' %> }); diff --git a/blueprints/model/index.js b/blueprints/model/index.js index 399b61698df..7fed2c30d57 100644 --- a/blueprints/model/index.js +++ b/blueprints/model/index.js @@ -34,7 +34,6 @@ module.exports = useEditionDetector({ let includeHasMany = false; let includeBelongsTo = false; let includeAttr = false; - let importedModules = null; for (let name in entityOptions) { let type = entityOptions[name] || ''; @@ -80,10 +79,10 @@ module.exports = useEditionDetector({ } } - let isOctane = process.env.EMBER_VERSION === 'OCTANE'; - if (attrs.length) { let attrTransformer, attrSeparator; + + let isOctane = process.env.EMBER_VERSION === 'OCTANE'; if (isOctane) { attrTransformer = nativeAttr; attrSeparator = ';'; @@ -104,19 +103,17 @@ module.exports = useEditionDetector({ }); needs = ' needs: [' + needsDeduplicated.join(', ') + ']'; - if (isOctane) { - importedModules = ['Model']; - if (includeAttr) { - importedModules.push('attr'); - } - if (includeBelongsTo) { - importedModules.push('belongsTo'); - } - if (includeHasMany) { - importedModules.push('hasMany'); - } - importedModules = importedModules.join(', '); + let importedModules = ['Model']; + if (includeAttr) { + importedModules.push('attr'); + } + if (includeBelongsTo) { + importedModules.push('belongsTo'); + } + if (includeHasMany) { + importedModules.push('hasMany'); } + importedModules = importedModules.join(', '); return { importedModules: importedModules, @@ -159,15 +156,15 @@ function classicAttr(attr) { result; if (type === 'belongs-to') { - result = "DS.belongsTo('" + name + "')"; + result = "belongsTo('" + name + "')"; } else if (type === 'has-many') { - result = "DS.hasMany('" + name + "')"; + result = "hasMany('" + name + "')"; } else if (type === '') { //"If you don't specify the type of the attribute, it will be whatever was provided by the server" //https://emberjs.com/guides/models/defining-models/ - result = 'DS.attr()'; + result = 'attr()'; } else { - result = "DS.attr('" + type + "')"; + result = "attr('" + type + "')"; } return propertyName + ': ' + result; } diff --git a/node-tests/blueprints/model-test.js b/node-tests/blueprints/model-test.js index 94e781a9927..2758e48fc62 100644 --- a/node-tests/blueprints/model-test.js +++ b/node-tests/blueprints/model-test.js @@ -29,7 +29,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { return emberGenerateDestroy(args, _file => { expect(_file('app/models/foo.js')) .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.Model.extend('); + .to.contain('const { Model } = DS;') + .to.contain('export default Model.extend('); expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/rfc232.js')); }); @@ -52,15 +53,16 @@ describe('Acceptance: generate and destroy model blueprints', function() { return emberGenerateDestroy(args, _file => { expect(_file('app/models/foo.js')) .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.Model.extend(') - .to.contain(' misc: DS.attr(),') - .to.contain(" skills: DS.attr('array'),") - .to.contain(" isActive: DS.attr('boolean'),") - .to.contain(" birthday: DS.attr('date'),") - .to.contain(" someObject: DS.attr('object'),") - .to.contain(" age: DS.attr('number'),") - .to.contain(" name: DS.attr('string'),") - .to.contain(" customAttr: DS.attr('custom-transform')"); + .to.contain('const { Model, attr } = DS;') + .to.contain('export default Model.extend(') + .to.contain(' misc: attr(),') + .to.contain(" skills: attr('array'),") + .to.contain(" isActive: attr('boolean'),") + .to.contain(" birthday: attr('date'),") + .to.contain(" someObject: attr('object'),") + .to.contain(" age: attr('number'),") + .to.contain(" name: attr('string'),") + .to.contain(" customAttr: attr('custom-transform')"); expect(_file('tests/unit/models/foo-test.js')).to.equal(fixture('model-test/rfc232.js')); }); @@ -72,9 +74,10 @@ describe('Acceptance: generate and destroy model blueprints', function() { return emberGenerateDestroy(args, _file => { expect(_file('app/models/comment.js')) .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.Model.extend(') - .to.contain(" post: DS.belongsTo('post'),") - .to.contain(" author: DS.belongsTo('user')"); + .to.contain('const { Model, belongsTo } = DS;') + .to.contain('export default Model.extend(') + .to.contain(" post: belongsTo('post'),") + .to.contain(" author: belongsTo('user')"); expect(_file('tests/unit/models/comment-test.js')).to.equal( fixture('model-test/comment-default.js') @@ -88,9 +91,10 @@ describe('Acceptance: generate and destroy model blueprints', function() { return emberGenerateDestroy(args, _file => { expect(_file('app/models/post.js')) .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.Model.extend(') - .to.contain(" comments: DS.hasMany('comment')") - .to.contain(" otherComments: DS.hasMany('comment')"); + .to.contain('const { Model, hasMany } = DS;') + .to.contain('export default Model.extend(') + .to.contain(" comments: hasMany('comment')") + .to.contain(" otherComments: hasMany('comment')"); expect(_file('tests/unit/models/post-test.js')).to.equal( fixture('model-test/post-default.js') @@ -175,7 +179,8 @@ describe('Acceptance: generate and destroy model blueprints', function() { _file => { expect(_file('src/data/models/foo/model.js')) .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.Model.extend('); + .to.contain('const { Model } = DS;') + .to.contain('export default Model.extend('); expect(_file('src/data/models/foo/model-test.js')).to.equal( fixture('model-test/rfc232.js') @@ -204,15 +209,16 @@ describe('Acceptance: generate and destroy model blueprints', function() { _file => { expect(_file('src/data/models/foo/model.js')) .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.Model.extend(') - .to.contain(' misc: DS.attr(),') - .to.contain(" skills: DS.attr('array'),") - .to.contain(" isActive: DS.attr('boolean'),") - .to.contain(" birthday: DS.attr('date'),") - .to.contain(" someObject: DS.attr('object'),") - .to.contain(" age: DS.attr('number'),") - .to.contain(" name: DS.attr('string'),") - .to.contain(" customAttr: DS.attr('custom-transform')"); + .to.contain('const { Model, attr } = DS;') + .to.contain('export default Model.extend(') + .to.contain(' misc: attr(),') + .to.contain(" skills: attr('array'),") + .to.contain(" isActive: attr('boolean'),") + .to.contain(" birthday: attr('date'),") + .to.contain(" someObject: attr('object'),") + .to.contain(" age: attr('number'),") + .to.contain(" name: attr('string'),") + .to.contain(" customAttr: attr('custom-transform')"); expect(_file('src/data/models/foo/model-test.js')).to.equal( fixture('model-test/rfc232.js') @@ -230,9 +236,10 @@ describe('Acceptance: generate and destroy model blueprints', function() { _file => { expect(_file('src/data/models/comment/model.js')) .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.Model.extend(') - .to.contain(" post: DS.belongsTo('post'),") - .to.contain(" author: DS.belongsTo('user')"); + .to.contain('const { Model, belongsTo } = DS;') + .to.contain('export default Model.extend(') + .to.contain(" post: belongsTo('post'),") + .to.contain(" author: belongsTo('user')"); expect(_file('src/data/models/comment/model-test.js')).to.equal( fixture('model-test/comment-default.js') @@ -250,9 +257,10 @@ describe('Acceptance: generate and destroy model blueprints', function() { _file => { expect(_file('src/data/models/post/model.js')) .to.contain("import DS from 'ember-data';") - .to.contain('export default DS.Model.extend(') - .to.contain(" comments: DS.hasMany('comment'),") - .to.contain(" otherComments: DS.hasMany('comment')"); + .to.contain('const { Model, hasMany } = DS;') + .to.contain('export default Model.extend(') + .to.contain(" comments: hasMany('comment'),") + .to.contain(" otherComments: hasMany('comment')"); expect(_file('src/data/models/post/model-test.js')).to.equal( fixture('model-test/post-default.js') From 9318dc748e011c3ff07a8f2e6d23e9f797484e9f Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Thu, 7 Mar 2019 13:30:44 +0100 Subject: [PATCH 2504/2527] Fix wrong indentation on Model Blueprint for Classic apps --- blueprints/model/files/__root__/__path__/__name__.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blueprints/model/files/__root__/__path__/__name__.js b/blueprints/model/files/__root__/__path__/__name__.js index eacb7a17e62..d6f162587b0 100644 --- a/blueprints/model/files/__root__/__path__/__name__.js +++ b/blueprints/model/files/__root__/__path__/__name__.js @@ -2,5 +2,5 @@ import DS from 'ember-data'; const { <%= importedModules %> } = DS; export default Model.extend({ -<%= attrs.length ? ' ' + attrs : '' %> +<%= attrs.length ? attrs : '' %> }); From 441805afa16f7011d4b3437d3b6f032475cd47ac Mon Sep 17 00:00:00 2001 From: Ryan Toronto Date: Fri, 1 Mar 2019 12:25:45 -0500 Subject: [PATCH 2505/2527] Do not warn or clear sync relationships if they have known data This PR makes changes the known to be empty behavior. It allows a second get request without an include string will keep any relationship data that the model knows about. --- addon/-private/system/model/record-data.js | 5 +- .../relationships/state/relationship.js | 2 +- tests/unit/store/push-test.js | 63 +++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/addon/-private/system/model/record-data.js b/addon/-private/system/model/record-data.js index 18dfe0fd537..832b7227863 100644 --- a/addon/-private/system/model/record-data.js +++ b/addon/-private/system/model/record-data.js @@ -92,6 +92,7 @@ export default class RecordData { // in debug, assert payload validity eagerly let relationshipData = data.relationships[relationshipName]; + if (DEBUG) { let store = this.store; let recordData = this; @@ -102,11 +103,12 @@ export default class RecordData { if (relationshipData.links) { let isAsync = relationshipMeta.options && relationshipMeta.options.async !== false; + let relationship = this._relationships.get(relationshipName); warn( `You pushed a record of type '${ this.modelName }' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload. EmberData will treat this relationship as known-to-be-empty.`, - isAsync || relationshipData.data, + isAsync || relationshipData.data || relationship.hasAnyRelationshipData, { id: 'ds.store.push-link-for-sync-relationship', } @@ -144,6 +146,7 @@ export default class RecordData { } } } + let relationship = this._relationships.get(relationshipName); relationship.push(relationshipData); diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 6d91862bae8..a758c834311 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -637,7 +637,7 @@ export default class Relationship { if (payload.data !== undefined) { hasRelationshipDataProperty = true; this.updateData(payload.data, initial); - } else if (this.isAsync === false) { + } else if (this.isAsync === false && !this.hasAnyRelationshipData) { hasRelationshipDataProperty = true; let data = this.kind === 'hasMany' ? [] : null; diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index 644fbd121eb..c000a4bf595 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -606,6 +606,69 @@ testInDebug( } ); +testInDebug( + 'Calling push with a link for a non async relationship should not reset an existing relationship', + function(assert) { + Person.reopen({ + phoneNumbers: hasMany('phone-number', { async: false }), + }); + + // GET /persons/1?include=phone-numbers + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + relationships: { + phoneNumbers: { + data: [ + { type: 'phone-number', id: '2' } + ], + links: { + related: '/api/people/1/phone-numbers', + }, + }, + }, + }, + included: [{ + type: 'phone-number', + id: '2', + attributes: { + number: '1-800-DATA' + } + }] + }); + }); + + let person = store.peekRecord('person', 1); + + assert.equal(person.phoneNumbers.length, 1); + assert.equal(person.phoneNumbers.firstObject.number, '1-800-DATA'); + + // GET /persons/1 + assert.expectNoWarning(() => { + run(() => { + store.push({ + data: { + type: 'person', + id: '1', + relationships: { + phoneNumbers: { + links: { + related: '/api/people/1/phone-numbers', + }, + }, + }, + }, + }); + }); + }); + + assert.equal(person.phoneNumbers.length, 1); + assert.equal(person.phoneNumbers.firstObject.number, '1-800-DATA'); + } +); + testInDebug('Calling push with an unknown model name throws an assertion error', function(assert) { assert.expectAssertion(() => { run(() => { From 47d8d4012572c160fd6a051faf684d12a7b6a1f0 Mon Sep 17 00:00:00 2001 From: Ryan Toronto Date: Fri, 1 Mar 2019 12:32:07 -0500 Subject: [PATCH 2506/2527] fix eslint errors --- tests/unit/store/push-test.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index c000a4bf595..c8bbe26f5fc 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -621,22 +621,22 @@ testInDebug( id: '1', relationships: { phoneNumbers: { - data: [ - { type: 'phone-number', id: '2' } - ], + data: [{ type: 'phone-number', id: '2' }], links: { related: '/api/people/1/phone-numbers', }, }, }, }, - included: [{ - type: 'phone-number', - id: '2', - attributes: { - number: '1-800-DATA' - } - }] + included: [ + { + type: 'phone-number', + id: '2', + attributes: { + number: '1-800-DATA', + }, + }, + ], }); }); From d43d3a5a184558965c794740de2ed3a716db0256 Mon Sep 17 00:00:00 2001 From: Ryan Toronto Date: Fri, 8 Mar 2019 16:44:31 -0500 Subject: [PATCH 2507/2527] Update tests * Don't reopen class, use original relationship * Don't use Ember.run --- tests/unit/store/push-test.js | 62 +++++++++++++++-------------------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index c8bbe26f5fc..f4b9ddbd699 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -609,35 +609,29 @@ testInDebug( testInDebug( 'Calling push with a link for a non async relationship should not reset an existing relationship', function(assert) { - Person.reopen({ - phoneNumbers: hasMany('phone-number', { async: false }), - }); - // GET /persons/1?include=phone-numbers - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - relationships: { - phoneNumbers: { - data: [{ type: 'phone-number', id: '2' }], - links: { - related: '/api/people/1/phone-numbers', - }, + store.push({ + data: { + type: 'person', + id: '1', + relationships: { + phoneNumbers: { + data: [{ type: 'phone-number', id: '2' }], + links: { + related: '/api/people/1/phone-numbers', }, }, }, - included: [ - { - type: 'phone-number', - id: '2', - attributes: { - number: '1-800-DATA', - }, + }, + included: [ + { + type: 'phone-number', + id: '2', + attributes: { + number: '1-800-DATA', }, - ], - }); + }, + ], }); let person = store.peekRecord('person', 1); @@ -647,20 +641,18 @@ testInDebug( // GET /persons/1 assert.expectNoWarning(() => { - run(() => { - store.push({ - data: { - type: 'person', - id: '1', - relationships: { - phoneNumbers: { - links: { - related: '/api/people/1/phone-numbers', - }, + store.push({ + data: { + type: 'person', + id: '1', + relationships: { + phoneNumbers: { + links: { + related: '/api/people/1/phone-numbers', }, }, }, - }); + }, }); }); From 825cf8babe23a51f8db0700e076b970f46ba17e9 Mon Sep 17 00:00:00 2001 From: Cyrille David Date: Sat, 9 Mar 2019 14:13:07 +0100 Subject: [PATCH 2508/2527] Remove ember-cli-release According to RELEASE.md, release is not done through this tool. Let's remove it, as it triggers a long list of warnings. --- package.json | 1 - yarn.lock | 1276 ++------------------------------------------------ 2 files changed, 39 insertions(+), 1238 deletions(-) diff --git a/package.json b/package.json index 5cfa1df7b8c..a645916e094 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,6 @@ "ember-cli-inject-live-reload": "^2.0.1", "ember-cli-internal-test-helpers": "^0.9.1", "ember-cli-pretender": "^3.1.1", - "ember-cli-release": "^1.0.0-beta.2", "ember-cli-shims": "^1.2.0", "ember-cli-sri": "^2.1.1", "ember-cli-test-loader": "^2.2.0", diff --git a/yarn.lock b/yarn.lock index c99e115e2d1..0842600ce7a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -931,10 +931,6 @@ abbrev@1: version "1.1.1" resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" -abbrev@~1.0.7: - version "1.0.9" - resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" - abortcontroller-polyfill@^1.1.9: version "1.2.5" resolved "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.2.5.tgz#a091ba2d0ea7bae64d6a5f474089a6ab495cec2b" @@ -975,7 +971,7 @@ agent-base@2: extend "~3.0.0" semver "~5.0.1" -ajv@^6.5.5, ajv@^6.9.1: +ajv@^6.9.1: version "6.9.2" resolved "https://registry.npmjs.org/ajv/-/ajv-6.9.2.tgz#4927adb83e7f48e5a32b45729744c71ec39c9c7b" dependencies: @@ -1037,22 +1033,10 @@ ansi-to-html@^0.6.6: dependencies: entities "^1.1.1" -ansi@^0.3.0, ansi@~0.3.0, ansi@~0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz#0c42d4fb17160d5a9af1e484bace1c66922c1b21" - ansicolors@~0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" -ansicolors@~0.3.2: - version "0.3.2" - resolved "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" - -ansistyles@~0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539" - anymatch@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -1064,21 +1048,6 @@ aproba@^1.0.3: version "1.2.0" resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" -aproba@~1.0.1: - version "1.0.4" - resolved "https://registry.npmjs.org/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" - -archy@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" - -are-we-there-yet@~1.0.0: - version "1.0.6" - resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.0.6.tgz#a2d28c93102aa6cc96245a26cb954de06ec53f0c" - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.0 || ^1.1.13" - are-we-there-yet@~1.1.2: version "1.1.5" resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" @@ -1112,13 +1081,6 @@ array-flatten@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" -array-index@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/array-index/-/array-index-1.0.0.tgz#ec56a749ee103e4e08c790b9c353df16055b97f9" - dependencies: - debug "^2.2.0" - es6-symbol "^3.0.2" - array-unique@^0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -1127,32 +1089,14 @@ arraybuffer.slice@~0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" -asap@^2.0.0: - version "2.0.6" - resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - asn1@0.1.11: version "0.1.11" resolved "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - assert-plus@^0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - assertion-error@^1.0.1, assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" @@ -1192,17 +1136,11 @@ async-promise-queue@^1.0.3, async-promise-queue@^1.0.4: async "^2.4.1" debug "^2.6.8" -async-some@~1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/async-some/-/async-some-1.0.2.tgz#4d8a81620d5958791b5b98f802d3207776e95509" - dependencies: - dezalgo "^1.0.2" - async@^1.5.2: version "1.5.2" resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@^2.0.1, async@^2.4.1, async@^2.5.0: +async@^2.4.1, async@^2.5.0: version "2.6.2" resolved "https://registry.npmjs.org/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" dependencies: @@ -1216,10 +1154,6 @@ async@~0.9.0: version "0.9.2" resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - atob@^2.1.1: version "2.1.2" resolved "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" @@ -1228,18 +1162,6 @@ aws-sign2@~0.5.0: version "0.5.0" resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz#c57103f7a17fc037f02d7c2e64b602ea223f7d63" -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - -aws4@^1.8.0: - version "1.8.0" - resolved "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" - babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -1818,12 +1740,6 @@ basic-auth@~2.0.0: dependencies: safe-buffer "5.1.2" -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - dependencies: - tweetnacl "^0.14.3" - better-assert@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" @@ -1834,12 +1750,6 @@ better-assert@~1.0.0: version "2.1.2" resolved "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.2.tgz#c83c3d74233ba7674e4f313cb2a2b70f54e94b7c" -bl@~1.0.0: - version "1.0.3" - resolved "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e" - dependencies: - readable-stream "~2.0.5" - blank-object@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" @@ -1848,12 +1758,6 @@ blob@0.0.5: version "0.0.5" resolved "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" -block-stream@*: - version "0.0.9" - resolved "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - dependencies: - inherits "~2.0.0" - bluebird@^3.1.1, bluebird@^3.4.6: version "3.5.3" resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" @@ -1888,12 +1792,6 @@ boom@0.4.x: dependencies: hoek "0.9.x" -boom@2.x.x: - version "2.10.1" - resolved "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - dependencies: - hoek "2.x.x" - bops@0.0.3: version "0.0.3" resolved "https://registry.npmjs.org/bops/-/bops-0.0.3.tgz#c5cbf6fea8be7401ca5ea6d1679e6c4e8b407c79" @@ -2438,14 +2336,6 @@ buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" -builtin-modules@^1.0.0: - version "1.1.1" - resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - -builtins@0.0.7: - version "0.0.7" - resolved "https://registry.npmjs.org/builtins/-/builtins-0.0.7.tgz#355219cd6cf18dbe7c01cc7fd2dce765cfdc549a" - builtins@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" @@ -2535,14 +2425,6 @@ cardinal@^1.0.0: ansicolors "~0.2.1" redeyed "~1.0.0" -caseless@~0.11.0: - version "0.11.0" - resolved "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - chai-as-promised@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-6.0.0.tgz#1a02a433a6f24dafac63b9c96fa1684db1aa8da6" @@ -2580,7 +2462,7 @@ chai@^4.1.0: pathval "^1.1.0" type-detect "^4.0.5" -chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: +chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -2612,14 +2494,6 @@ check-error@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" -chownr@^1.0.1: - version "1.1.1" - resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" - -chownr@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" - ci-info@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" @@ -2704,13 +2578,6 @@ clone@^2.0.0, clone@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" -cmd-shim@~2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb" - dependencies: - graceful-fs "^4.1.2" - mkdirp "~0.5.0" - co@^4.6.0: version "4.6.0" resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -2744,19 +2611,6 @@ colors@^1.1.2: version "1.3.3" resolved "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" -columnify@~1.5.4: - version "1.5.4" - resolved "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" - dependencies: - strip-ansi "^3.0.0" - wcwidth "^1.0.0" - -combined-stream@^1.0.5, combined-stream@^1.0.6, combined-stream@~1.0.5, combined-stream@~1.0.6: - version "1.0.7" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" - dependencies: - delayed-stream "~1.0.0" - combined-stream@~0.0.4: version "0.0.7" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz#0137e657baa5a7541c57ac37ac5fc07d73b4dc1f" @@ -2767,7 +2621,7 @@ commander@2.12.2: version "2.12.2" resolved "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" -commander@^2.15.1, commander@^2.6.0, commander@^2.9.0: +commander@^2.15.1, commander@^2.6.0: version "2.19.0" resolved "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" @@ -2813,22 +2667,6 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.6: - version "1.6.2" - resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -config-chain@~1.1.9: - version "1.1.12" - resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - configstore@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz#5933311e95d3687efb592c528b922d9262d227e7" @@ -2913,7 +2751,7 @@ core-object@^3.1.5: dependencies: chalk "^2.0.0" -core-util-is@1.0.2, core-util-is@~1.0.0: +core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -2939,12 +2777,6 @@ cryptiles@0.2.x: dependencies: boom "0.4.x" -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - dependencies: - boom "2.x.x" - crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" @@ -2953,22 +2785,10 @@ ctype@0.5.3: version "0.5.3" resolved "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" -d@1: - version "1.0.0" - resolved "https://registry.npmjs.org/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" - dependencies: - es5-ext "^0.10.9" - dag-map@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" - date-time@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/date-time/-/date-time-2.1.0.tgz#0286d1b4c769633b3ca13e1e62558d2dbdc2eba2" @@ -2999,10 +2819,6 @@ debug@~3.1.0: dependencies: ms "2.0.0" -debuglog@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" - decamelize@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -3072,10 +2888,6 @@ delayed-stream@0.0.5: version "0.0.5" resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz#d4b1f43a93e8296dfe02694f4680bc37a313c73f" -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - delegates@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -3102,13 +2914,6 @@ detect-indent@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" -dezalgo@^1.0.0, dezalgo@^1.0.1, dezalgo@^1.0.2, dezalgo@~1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" - dependencies: - asap "^2.0.0" - wrappy "1" - diff@3.5.0: version "3.5.0" resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -3137,21 +2942,10 @@ duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - editions@^1.1.1: version "1.3.4" resolved "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" -editor@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742" - ee-first@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -3339,22 +3133,6 @@ ember-cli-pretender@^3.1.1: route-recognizer "^0.3.3" whatwg-fetch "^3.0.0" -ember-cli-release@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.npmjs.org/ember-cli-release/-/ember-cli-release-1.0.0-beta.2.tgz#cb72d341293e94a1a8bcf4b73f7a6396f5b7e0c5" - dependencies: - chalk "^1.0.0" - git-tools "^0.1.4" - make-array "^0.1.2" - merge "^1.2.0" - moment-timezone "^0.3.0" - nopt "^3.0.3" - npm "~3.5.2" - require-dir "^0.3.0" - rsvp "^3.0.17" - semver "^4.3.1" - silent-error "^1.0.0" - ember-cli-shims@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/ember-cli-shims/-/ember-cli-shims-1.2.0.tgz#0f53aff0aab80b5f29da3a9731bac56169dd941f" @@ -3791,29 +3569,6 @@ es-to-primitive@^1.2.0: is-date-object "^1.0.1" is-symbol "^1.0.2" -es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.48" - resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.48.tgz#9a0b31eeded39e64453bcedf6f9d50bbbfb43850" - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.1" - next-tick "1" - -es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-symbol@^3.0.2, es6-symbol@^3.1.1, es6-symbol@~3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" - dependencies: - d "1" - es5-ext "~0.10.14" - escape-html@~1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -4079,7 +3834,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@3, extend@^3.0.0, extend@~3.0.0, extend@~3.0.2: +extend@3, extend@^3.0.0, extend@~3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -4104,14 +3859,6 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - fake-xml-http-request@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/fake-xml-http-request/-/fake-xml-http-request-2.0.0.tgz#41a92f0ca539477700cb1dafd2df251d55dac8ff" @@ -4307,10 +4054,6 @@ forever-agent@~0.5.0: version "0.5.2" resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - form-data@~0.1.0: version "0.1.4" resolved "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" @@ -4319,22 +4062,6 @@ form-data@~0.1.0: combined-stream "~0.0.4" mime "~1.2.11" -form-data@~1.0.0-rc3: - version "1.0.1" - resolved "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" - dependencies: - async "^2.0.1" - combined-stream "^1.0.5" - mime-types "^2.1.11" - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - forwarded@~0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -4445,51 +4172,10 @@ fs-updater@^1.0.4: heimdalljs-logger "^0.1.9" rimraf "^2.6.2" -fs-vacuum@~1.2.7: - version "1.2.10" - resolved "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36" - dependencies: - graceful-fs "^4.1.2" - path-is-inside "^1.0.1" - rimraf "^2.5.2" - -fs-write-stream-atomic@~1.0.8: - version "1.0.10" - resolved "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" - dependencies: - graceful-fs "^4.1.2" - iferr "^0.1.5" - imurmurhash "^0.1.4" - readable-stream "1 || 2" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" -fstream-ignore@^1.0.0: - version "1.0.5" - resolved "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" - -fstream-npm@~1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/fstream-npm/-/fstream-npm-1.0.7.tgz#7ed0d1ac13d7686dd9e1bf6ceb8be273bf6d2f86" - dependencies: - fstream-ignore "^1.0.0" - inherits "2" - -fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.8: - version "1.0.11" - resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" - function-bind@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -4498,16 +4184,6 @@ functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" -gauge@~1.2.0, gauge@~1.2.5: - version "1.2.7" - resolved "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz#e9cec5483d3d4ee0ef44b60a7d99e4935e136d93" - dependencies: - ansi "^0.3.0" - has-unicode "^2.0.0" - lodash.pad "^4.1.0" - lodash.padend "^4.1.0" - lodash.padstart "^4.1.0" - gauge@~2.7.3: version "2.7.4" resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -4521,18 +4197,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -generate-function@^2.0.0: - version "2.3.1" - resolved "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" - dependencies: - is-property "^1.0.2" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - dependencies: - is-property "^1.0.0" - get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" @@ -4563,12 +4227,6 @@ get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" - git-fetch-pack@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/git-fetch-pack/-/git-fetch-pack-0.1.1.tgz#7703a32cf0db80f060d2766a34ac00d02cebcdf5" @@ -4612,12 +4270,6 @@ git-repo-version@^1.0.2: dependencies: git-repo-info "^1.4.1" -git-tools@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/git-tools/-/git-tools-0.1.4.tgz#5e43e59443b8a5dedb39dba663da49e79f943978" - dependencies: - spawnback "~1.0.0" - git-transport-protocol@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/git-transport-protocol/-/git-transport-protocol-0.1.0.tgz#99f4dd6389b9161eded74a9e617d6ba5ed0a6c2c" @@ -4643,16 +4295,7 @@ github@^1.1.1: https-proxy-agent "^1.0.0" mime "^1.2.11" -"glob@3 || 4", glob@^4.3.2: - version "4.5.3" - resolved "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "^2.0.1" - once "^1.3.0" - -glob@7.1.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3: +glob@7.1.3, glob@^7.0.4, glob@^7.1.0, glob@^7.1.2, glob@^7.1.3: version "7.1.3" resolved "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" dependencies: @@ -4663,19 +4306,18 @@ glob@7.1.3, glob@^7.0.4, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2, glo once "^1.3.0" path-is-absolute "^1.0.0" -glob@^5.0.10: - version "5.0.15" - resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" +glob@^4.3.2: + version "4.5.3" + resolved "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f" dependencies: inflight "^1.0.4" inherits "2" - minimatch "2 || 3" + minimatch "^2.0.1" once "^1.3.0" - path-is-absolute "^1.0.0" -glob@~6.0.3: - version "6.0.4" - resolved "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" +glob@^5.0.10: + version "5.0.15" + resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" dependencies: inflight "^1.0.4" inherits "2" @@ -4747,7 +4389,7 @@ got@^8.0.1: url-parse-lax "^3.0.0" url-to-options "^1.0.1" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.2: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.15" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" @@ -4769,26 +4411,6 @@ handlebars@^4.0.11, handlebars@^4.0.4: optionalDependencies: uglify-js "^3.1.4" -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - -har-validator@~2.0.2: - version "2.0.6" - resolved "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" - dependencies: - chalk "^1.1.1" - commander "^2.9.0" - is-my-json-valid "^2.12.4" - pinkie-promise "^2.0.0" - -har-validator@~5.1.0: - version "5.1.3" - resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - dependencies: - ajv "^6.5.5" - har-schema "^2.0.0" - has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -4823,7 +4445,7 @@ has-to-string-tag-x@^1.2.0: dependencies: has-symbol-support-x "^1.4.1" -has-unicode@^2.0.0, has-unicode@~2.0.0: +has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -4879,15 +4501,6 @@ hawk@1.1.1: hoek "0.9.x" sntp "0.2.x" -hawk@~3.1.0: - version "3.1.3" - resolved "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - he@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" @@ -4926,10 +4539,6 @@ hoek@0.9.x: version "0.9.1" resolved "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -4943,14 +4552,10 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" -hosted-git-info@^2.1.4, hosted-git-info@^2.1.5, hosted-git-info@^2.4.2, hosted-git-info@^2.6.0: +hosted-git-info@^2.6.0: version "2.7.1" resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" -hosted-git-info@~2.1.4: - version "2.1.5" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" - http-cache-semantics@3.8.1: version "3.8.1" resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" @@ -4984,22 +4589,6 @@ http-signature@~0.10.0: assert-plus "^0.1.5" ctype "0.5.3" -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - https-proxy-agent@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" @@ -5020,10 +4609,6 @@ iconv-lite@^0.4.13, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -iferr@^0.1.5, iferr@~0.1.5: - version "0.1.5" - resolved "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" - ignore@^4.0.6: version "4.0.6" resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -5051,34 +4636,21 @@ inflection@^1.12.0: version "1.12.0" resolved "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" -inflight@^1.0.4, inflight@~1.0.4: +inflight@^1.0.4: version "1.0.6" resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" dependencies: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" -ini@^1.3.4, ini@~1.3.0, ini@~1.3.4: +ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" -init-package-json@~1.9.1: - version "1.9.6" - resolved "https://registry.npmjs.org/init-package-json/-/init-package-json-1.9.6.tgz#789fc2b74466a4952b9ea77c0575bc78ebd60a61" - dependencies: - glob "^7.1.1" - npm-package-arg "^4.0.0 || ^5.0.0" - promzard "^0.3.0" - read "~1.0.1" - read-package-json "1 || 2" - semver "2.x || 3.x || 4 || 5" - validate-npm-package-license "^3.0.1" - validate-npm-package-name "^3.0.0" - inquirer@^6, inquirer@^6.2.2: version "6.2.2" resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz#46941176f65c9eb20804627149b743a218f25406" @@ -5142,12 +4714,6 @@ is-buffer@~2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" -is-builtin-module@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - dependencies: - builtin-modules "^1.0.0" - is-callable@^1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" @@ -5224,20 +4790,6 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-my-ip-valid@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824" - -is-my-json-valid@^2.12.4: - version "2.19.0" - resolved "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz#8fd6e40363cd06b963fa877d444bfb5eddc62175" - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - is-my-ip-valid "^1.0.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - is-number@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -5266,10 +4818,6 @@ is-promise@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" -is-property@^1.0.0, is-property@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - is-redirect@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" @@ -5310,10 +4858,6 @@ is-type@0.0.1: dependencies: core-util-is "~1.0.0" -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -5354,10 +4898,6 @@ isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - istextorbinary@2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" @@ -5407,10 +4947,6 @@ js-yaml@^3.12.0, js-yaml@^3.12.1, js-yaml@^3.2.5, js-yaml@^3.2.7: argparse "^1.0.7" esprima "^4.0.0" -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - jsesc@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" @@ -5431,18 +4967,10 @@ json-buffer@3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -5453,7 +4981,7 @@ json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: dependencies: jsonify "~0.0.0" -json-stringify-safe@~5.0.0, json-stringify-safe@~5.0.1: +json-stringify-safe@~5.0.0: version "5.0.1" resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -5487,19 +5015,6 @@ jsonify@~0.0.0: version "0.0.0" resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - keyv@3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" @@ -5597,24 +5112,10 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" -lockfile@~1.0.1: - version "1.0.4" - resolved "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" - dependencies: - signal-exit "^3.0.2" - lodash-node@^3.2.0: version "3.10.2" resolved "https://registry.npmjs.org/lodash-node/-/lodash-node-3.10.2.tgz#2598d5b1b54e6a68b4cb544e5c730953cbf632f7" -lodash._arraycopy@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" - -lodash._arrayeach@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz#bab156b2a90d3f1bbd5c653403349e5e5933ef9e" - lodash._baseassign@^3.0.0: version "3.2.0" resolved "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" @@ -5630,26 +5131,6 @@ lodash._basebind@~2.3.0: lodash._setbinddata "~2.3.0" lodash.isobject "~2.3.0" -lodash._basecallback@^3.0.0: - version "3.3.1" - resolved "https://registry.npmjs.org/lodash._basecallback/-/lodash._basecallback-3.3.1.tgz#b7b2bb43dc2160424a21ccf26c57e443772a8e27" - dependencies: - lodash._baseisequal "^3.0.0" - lodash._bindcallback "^3.0.0" - lodash.isarray "^3.0.0" - lodash.pairs "^3.0.0" - -lodash._baseclone@^3.0.0: - version "3.3.0" - resolved "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz#303519bf6393fe7e42f34d8b630ef7794e3542b7" - dependencies: - lodash._arraycopy "^3.0.0" - lodash._arrayeach "^3.0.0" - lodash._baseassign "^3.0.0" - lodash._basefor "^3.0.0" - lodash.isarray "^3.0.0" - lodash.keys "^3.0.0" - lodash._basecopy@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" @@ -5680,14 +5161,6 @@ lodash._basecreatewrapper@~2.3.0: lodash._slice "~2.3.0" lodash.isobject "~2.3.0" -lodash._basedifference@^3.0.0: - version "3.0.3" - resolved "https://registry.npmjs.org/lodash._basedifference/-/lodash._basedifference-3.0.3.tgz#f2c204296c2a78e02b389081b6edcac933cf629c" - dependencies: - lodash._baseindexof "^3.0.0" - lodash._cacheindexof "^3.0.0" - lodash._createcache "^3.0.0" - lodash._baseflatten@^3.0.0: version "3.1.4" resolved "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" @@ -5695,38 +5168,10 @@ lodash._baseflatten@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" -lodash._basefor@^3.0.0: - version "3.0.3" - resolved "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz#7550b4e9218ef09fad24343b612021c79b4c20c2" - -lodash._baseindexof@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" - -lodash._baseisequal@^3.0.0: - version "3.0.7" - resolved "https://registry.npmjs.org/lodash._baseisequal/-/lodash._baseisequal-3.0.7.tgz#d8025f76339d29342767dcc887ce5cb95a5b51f1" - dependencies: - lodash.isarray "^3.0.0" - lodash.istypedarray "^3.0.0" - lodash.keys "^3.0.0" - -lodash._baseuniq@^3.0.0: - version "3.0.3" - resolved "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-3.0.3.tgz#2123fa0db2d69c28d5beb1c1f36d61522a740234" - dependencies: - lodash._baseindexof "^3.0.0" - lodash._cacheindexof "^3.0.0" - lodash._createcache "^3.0.0" - lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" -lodash._cacheindexof@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" - lodash._createassigner@^3.0.0: version "3.1.1" resolved "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" @@ -5735,12 +5180,6 @@ lodash._createassigner@^3.0.0: lodash._isiterateecall "^3.0.0" lodash.restparam "^3.0.0" -lodash._createcache@^3.0.0: - version "3.1.2" - resolved "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" - dependencies: - lodash._getnative "^3.0.0" - lodash._createwrapper@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz#d1aae1102dadf440e8e06fc133a6edd7fe146075" @@ -5839,13 +5278,6 @@ lodash.clonedeep@^4.4.1: version "4.5.0" resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" -lodash.clonedeep@~3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz#a0a1e40d82a5ea89ff5b147b8444ed63d92827db" - dependencies: - lodash._baseclone "^3.0.0" - lodash._bindcallback "^3.0.0" - lodash.debounce@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" @@ -5919,10 +5351,6 @@ lodash.isobject@~2.3.0: dependencies: lodash._objecttypes "~2.3.0" -lodash.istypedarray@^3.0.0: - version "3.0.6" - resolved "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62" - lodash.keys@^3.0.0: version "3.1.2" resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" @@ -5951,24 +5379,6 @@ lodash.omit@^4.1.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" -lodash.pad@^4.1.0: - version "4.5.1" - resolved "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz#4330949a833a7c8da22cc20f6a26c4d59debba70" - -lodash.padend@^4.1.0: - version "4.6.1" - resolved "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e" - -lodash.padstart@^4.1.0: - version "4.6.1" - resolved "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b" - -lodash.pairs@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/lodash.pairs/-/lodash.pairs-3.0.1.tgz#bbe08d5786eeeaa09a15c91ebf0dcb7d2be326a9" - dependencies: - lodash.keys "^3.0.0" - lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" @@ -6011,28 +5421,10 @@ lodash.templatesettings@~2.3.0: lodash._reinterpolate "~2.3.0" lodash.escape "~2.3.0" -lodash.union@~3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-3.1.0.tgz#a4a3066fc15d6a7f8151cce9bdfe63dce7f5bcff" - dependencies: - lodash._baseflatten "^3.0.0" - lodash._baseuniq "^3.0.0" - lodash.restparam "^3.0.0" - lodash.uniq@^4.2.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" -lodash.uniq@~3.2.2: - version "3.2.2" - resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-3.2.2.tgz#146c36f25e75d19501ba402e88ba14937f63cd8b" - dependencies: - lodash._basecallback "^3.0.0" - lodash._baseuniq "^3.0.0" - lodash._getnative "^3.0.0" - lodash._isiterateecall "^3.0.0" - lodash.isarray "^3.0.0" - lodash.uniqby@^4.7.0: version "4.7.0" resolved "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" @@ -6043,13 +5435,6 @@ lodash.values@~2.3.0: dependencies: lodash.keys "~2.3.0" -lodash.without@~3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/lodash.without/-/lodash.without-3.2.1.tgz#d69614b3512e52294b6abab782e7ca96538ce816" - dependencies: - lodash._basedifference "^3.0.0" - lodash.restparam "^3.0.0" - lodash@^4.0.0, lodash@^4.16.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.6.1: version "4.17.11" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" @@ -6074,20 +5459,12 @@ lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" -lru-cache@2: - version "2.7.3" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" - magic-string@^0.24.0: version "0.24.1" resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.24.1.tgz#7e38e5f126cae9f15e71f0cf8e450818ca7d5a8f" dependencies: sourcemap-codec "^1.4.1" -make-array@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/make-array/-/make-array-0.1.2.tgz#335e36ebb0c5a43154d21213a1ecaeae2a1bb3ef" - make-dir@^1.0.0: version "1.3.0" resolved "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" @@ -6230,7 +5607,7 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: version "1.38.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad" -mime-types@^2.1.11, mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.19, mime-types@~2.1.18, mime-types@~2.1.19, mime-types@~2.1.7: +mime-types@^2.1.18, mime-types@^2.1.19, mime-types@~2.1.18: version "2.1.22" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd" dependencies: @@ -6260,13 +5637,6 @@ mimic-response@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" -minimatch@1: - version "1.0.0" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz#e0dd2120b49e1b724ce8d714c520822a9438576d" - dependencies: - lru-cache "2" - sigmund "~1.0.0" - "minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -6305,7 +5675,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: @@ -6351,16 +5721,6 @@ mocha@^6.0.2: yargs-parser "11.1.1" yargs-unparser "1.5.0" -moment-timezone@^0.3.0: - version "0.3.1" - resolved "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.3.1.tgz#3ef47856b02d53b718a10a5ec2023aa299e07bf5" - dependencies: - moment ">= 2.6.0" - -"moment@>= 2.6.0": - version "2.24.0" - resolved "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" - morgan@^1.9.0: version "1.9.1" resolved "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz#0a8d16734a1d9afbc824b99df87e738e58e2da59" @@ -6391,10 +5751,6 @@ mute-stream@0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" -mute-stream@~0.0.4: - version "0.0.8" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -6419,10 +5775,6 @@ negotiator@0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" -next-tick@1: - version "1.0.0" - resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" - nice-try@^1.0.4: version "1.0.5" resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -6433,25 +5785,6 @@ node-environment-flags@1.0.4: dependencies: object.getownpropertydescriptors "^2.0.3" -node-gyp@~3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-3.2.1.tgz#f5dd569970a508464cc3c15d7e9e8d2de8638dd5" - dependencies: - fstream "^1.0.0" - glob "3 || 4" - graceful-fs "^4.1.2" - minimatch "1" - mkdirp "^0.5.0" - nopt "2 || 3" - npmlog "0 || 1" - osenv "0" - path-array "^1.0.0" - request "2" - rimraf "2" - semver "2.x || 3.x || 4 || 5" - tar "^2.0.0" - which "1" - node-int64@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -6476,7 +5809,7 @@ node-releases@^1.1.3: dependencies: semver "^5.3.0" -node-uuid@~1.4.0, node-uuid@~1.4.7: +node-uuid@~1.4.0: version "1.4.8" resolved "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" @@ -6484,34 +5817,12 @@ node-watch@0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/node-watch/-/node-watch-0.6.0.tgz#ab0703b60cd270783698e57a428faa0010ed8fd0" -"nopt@2 || 3", nopt@^3.0.3, nopt@^3.0.6, nopt@~3.0.6: +nopt@^3.0.6: version "3.0.6" resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: abbrev "1" -normalize-git-url@~3.0.1: - version "3.0.2" - resolved "https://registry.npmjs.org/normalize-git-url/-/normalize-git-url-3.0.2.tgz#8e5f14be0bdaedb73e07200310aa416c27350fc4" - -normalize-package-data@^2.0.0, "normalize-package-data@~1.0.1 || ^2.0.0": - version "2.5.0" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-package-data@~2.3.5: - version "2.3.8" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" - dependencies: - hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" @@ -6526,37 +5837,10 @@ normalize-url@2.0.1: query-string "^5.0.1" sort-keys "^2.0.0" -npm-cache-filename@~1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11" - npm-git-info@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/npm-git-info/-/npm-git-info-1.0.3.tgz#a933c42ec321e80d3646e0d6e844afe94630e1d5" -npm-install-checks@~2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-2.0.1.tgz#a93540b53f04fa9d916d2733d6541f6db7d88e46" - dependencies: - npmlog "0.1 || 1" - semver "^2.3.0 || 3.x || 4 || 5" - -"npm-package-arg@^3.0.0 || ^4.0.0", npm-package-arg@^4.1.1: - version "4.2.1" - resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" - dependencies: - hosted-git-info "^2.1.5" - semver "^5.1.0" - -"npm-package-arg@^4.0.0 || ^5.0.0": - version "5.1.2" - resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-5.1.2.tgz#fb18d17bb61e60900d6312619919bd753755ab37" - dependencies: - hosted-git-info "^2.4.2" - osenv "^0.1.4" - semver "^5.1.0" - validate-npm-package-name "^3.0.0" - npm-package-arg@^6.1.0: version "6.1.0" resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" @@ -6566,124 +5850,12 @@ npm-package-arg@^6.1.0: semver "^5.5.0" validate-npm-package-name "^3.0.0" -npm-package-arg@~4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-4.1.1.tgz#86d9dca985b4c5e5d59772dfd5de6919998a495a" - dependencies: - hosted-git-info "^2.1.4" - semver "4 || 5" - -npm-registry-client@~7.0.9: - version "7.0.9" - resolved "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-7.0.9.tgz#1baf86ee5285c4e6d38d4556208ded56049231bb" - dependencies: - chownr "^1.0.1" - concat-stream "^1.4.6" - graceful-fs "^4.1.2" - mkdirp "^0.5.0" - normalize-package-data "~1.0.1 || ^2.0.0" - npm-package-arg "^3.0.0 || ^4.0.0" - once "^1.3.0" - request "^2.47.0" - retry "^0.8.0" - rimraf "2" - semver "2 >=2.2.1 || 3.x || 4 || 5" - slide "^1.1.3" - optionalDependencies: - npmlog "~2.0.0" - npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" dependencies: path-key "^2.0.0" -npm-user-validate@~0.1.2: - version "0.1.5" - resolved "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-0.1.5.tgz#52465d50c2d20294a57125b996baedbf56c5004b" - -npm@~3.5.2: - version "3.5.4" - resolved "https://registry.npmjs.org/npm/-/npm-3.5.4.tgz#db2f71d3daa0e7a99077edd4c213919834e95eb2" - dependencies: - abbrev "~1.0.7" - ansicolors "~0.3.2" - ansistyles "~0.1.3" - aproba "~1.0.1" - archy "~1.0.0" - async-some "~1.0.2" - chownr "~1.0.1" - cmd-shim "~2.0.1" - columnify "~1.5.4" - config-chain "~1.1.9" - dezalgo "~1.0.3" - editor "~1.0.0" - fs-vacuum "~1.2.7" - fs-write-stream-atomic "~1.0.8" - fstream "~1.0.8" - fstream-npm "~1.0.7" - glob "~6.0.3" - graceful-fs "~4.1.2" - has-unicode "~2.0.0" - hosted-git-info "~2.1.4" - iferr "~0.1.5" - inflight "~1.0.4" - inherits "~2.0.1" - ini "~1.3.4" - init-package-json "~1.9.1" - lockfile "~1.0.1" - lodash.clonedeep "~3.0.2" - lodash.union "~3.1.0" - lodash.uniq "~3.2.2" - lodash.without "~3.2.1" - mkdirp "~0.5.1" - node-gyp "~3.2.1" - nopt "~3.0.6" - normalize-git-url "~3.0.1" - normalize-package-data "~2.3.5" - npm-cache-filename "~1.0.2" - npm-install-checks "~2.0.1" - npm-package-arg "~4.1.0" - npm-registry-client "~7.0.9" - npm-user-validate "~0.1.2" - npmlog "~2.0.0" - once "~1.3.3" - opener "~1.4.1" - osenv "~0.1.3" - path-is-inside "~1.0.1" - read "~1.0.7" - read-cmd-shim "~1.0.1" - read-installed "~4.0.3" - read-package-json "~2.0.2" - read-package-tree "~5.1.2" - readable-stream "~2.0.5" - realize-package-specifier "~3.0.1" - request "~2.67.0" - retry "~0.8.0" - rimraf "~2.5.0" - semver "~5.1.0" - sha "~2.0.1" - slide "~1.1.6" - sorted-object "~1.0.0" - tar "~2.2.1" - text-table "~0.2.0" - uid-number "0.0.6" - umask "~1.1.0" - unique-filename "~1.1.0" - unpipe "~1.0.0" - validate-npm-package-name "~2.2.2" - which "~1.2.1" - wrappy "~1.0.1" - write-file-atomic "~1.1.4" - -"npmlog@0 || 1", "npmlog@0.1 || 1": - version "1.2.1" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz#28e7be619609b53f7ad1dd300a10d64d716268b6" - dependencies: - ansi "~0.3.0" - are-we-there-yet "~1.0.0" - gauge "~1.2.0" - npmlog@^4.0.0: version "4.1.2" resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -6693,14 +5865,6 @@ npmlog@^4.0.0: gauge "~2.7.3" set-blocking "~2.0.0" -npmlog@~2.0.0: - version "2.0.4" - resolved "https://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz#98b52530f2514ca90d09ec5b22c8846722375692" - dependencies: - ansi "~0.3.1" - are-we-there-yet "~1.1.2" - gauge "~1.2.5" - number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -6709,14 +5873,6 @@ oauth-sign@~0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" -oauth-sign@~0.8.0: - version "0.8.2" - resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - object-assign@4.1.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -6785,22 +5941,12 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -once@~1.3.3: - version "1.3.3" - resolved "https://registry.npmjs.org/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" - dependencies: - wrappy "1" - onetime@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" dependencies: mimic-fn "^1.0.0" -opener@~1.4.1: - version "1.4.3" - resolved "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" - optimist@^0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" @@ -6846,7 +5992,7 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -osenv@0, osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.4, osenv@^0.1.5, osenv@~0.1.3: +osenv@^0.1.0, osenv@^0.1.3, osenv@^0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" dependencies: @@ -6954,12 +6100,6 @@ pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" -path-array@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/path-array/-/path-array-1.0.1.tgz#7e2f0f35f07a2015122b868b7eac0eb2c4fec271" - dependencies: - array-index "^1.0.0" - path-exists@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -6968,7 +6108,7 @@ path-is-absolute@1.0.1, path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.1: +path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" @@ -7002,24 +6142,10 @@ pathval@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - pify@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" @@ -7082,10 +6208,6 @@ private@^0.1.6, private@^0.1.8, private@~0.1.5: version "0.1.8" resolved "https://registry.npmjs.org/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - process-nextick-args@~2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" @@ -7114,16 +6236,6 @@ promise.prototype.finally@^3.1.0: es-abstract "^1.9.0" function-bind "^1.1.1" -promzard@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" - dependencies: - read "1" - -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - proxy-addr@~2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" @@ -7131,7 +6243,7 @@ proxy-addr@~2.0.4: forwarded "~0.1.2" ipaddr.js "1.8.0" -psl@^1.1.24, psl@^1.1.28: +psl@^1.1.28: version "1.1.31" resolved "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" @@ -7142,15 +6254,11 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" -qs@6.5.2, qs@~6.5.2: +qs@6.5.2: version "6.5.2" resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -7162,10 +6270,6 @@ qs@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" -qs@~5.2.0: - version "5.2.1" - resolved "https://registry.npmjs.org/qs/-/qs-5.2.1.tgz#801fee030e0b9450d6385adc48a4cc55b44aedfc" - query-string@^5.0.1: version "5.1.1" resolved "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" @@ -7228,53 +6332,7 @@ rc@^1.0.1, rc@^1.1.6: minimist "^1.2.0" strip-json-comments "~2.0.1" -read-cmd-shim@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b" - dependencies: - graceful-fs "^4.1.2" - -read-installed@~4.0.3: - version "4.0.3" - resolved "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" - dependencies: - debuglog "^1.0.1" - read-package-json "^2.0.0" - readdir-scoped-modules "^1.0.0" - semver "2 || 3 || 4 || 5" - slide "~1.1.3" - util-extend "^1.0.1" - optionalDependencies: - graceful-fs "^4.1.2" - -"read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@~2.0.2: - version "2.0.13" - resolved "https://registry.npmjs.org/read-package-json/-/read-package-json-2.0.13.tgz#2e82ebd9f613baa6d2ebe3aa72cefe3f68e41f4a" - dependencies: - glob "^7.1.1" - json-parse-better-errors "^1.0.1" - normalize-package-data "^2.0.0" - slash "^1.0.0" - optionalDependencies: - graceful-fs "^4.1.2" - -read-package-tree@~5.1.2: - version "5.1.6" - resolved "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.1.6.tgz#4f03e83d0486856fb60d97c94882841c2a7b1b7a" - dependencies: - debuglog "^1.0.1" - dezalgo "^1.0.0" - once "^1.3.0" - read-package-json "^2.0.0" - readdir-scoped-modules "^1.0.0" - -read@1, read@~1.0.1, read@~1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" - dependencies: - mute-stream "~0.0.4" - -"readable-stream@1 || 2", readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: +readable-stream@^2.0.0, readable-stream@^2.0.6: version "2.3.6" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -7295,33 +6353,6 @@ readable-stream@~1.0.2: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@~2.0.5: - version "2.0.6" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - -readdir-scoped-modules@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" - dependencies: - debuglog "^1.0.1" - dezalgo "^1.0.0" - graceful-fs "^4.1.2" - once "^1.3.0" - -realize-package-specifier@~3.0.1: - version "3.0.3" - resolved "https://registry.npmjs.org/realize-package-specifier/-/realize-package-specifier-3.0.3.tgz#d0def882952b8de3f67eba5e91199661271f41f4" - dependencies: - dezalgo "^1.0.1" - npm-package-arg "^4.1.1" - recast@^0.11.3: version "0.11.23" resolved "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" @@ -7469,31 +6500,6 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request@2, request@^2.47.0: - version "2.88.0" - resolved "https://registry.npmjs.org/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.0" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.4.3" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - request@~2.40.0: version "2.40.0" resolved "https://registry.npmjs.org/request/-/request-2.40.0.tgz#4dd670f696f1e6e842e66b4b5e839301ab9beb67" @@ -7513,35 +6519,6 @@ request@~2.40.0: tough-cookie ">=0.12.0" tunnel-agent "~0.4.0" -request@~2.67.0: - version "2.67.0" - resolved "https://registry.npmjs.org/request/-/request-2.67.0.tgz#8af74780e2bf11ea0ae9aa965c11f11afd272742" - dependencies: - aws-sign2 "~0.6.0" - bl "~1.0.0" - caseless "~0.11.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~1.0.0-rc3" - har-validator "~2.0.2" - hawk "~3.1.0" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - node-uuid "~1.4.7" - oauth-sign "~0.8.0" - qs "~5.2.0" - stringstream "~0.0.4" - tough-cookie "~2.2.0" - tunnel-agent "~0.4.1" - -require-dir@^0.3.0: - version "0.3.2" - resolved "https://registry.npmjs.org/require-dir/-/require-dir-0.3.2.tgz#c1d5c75e9fbffde9f2e6b33e383db4f594b5a6a9" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -7620,22 +6597,12 @@ ret@~0.1.10: version "0.1.15" resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" -retry@^0.8.0, retry@~0.8.0: - version "0.8.0" - resolved "https://registry.npmjs.org/retry/-/retry-0.8.0.tgz#2367628dc0edb247b1eab649dc53ac8628ac2d5f" - -rimraf@2, rimraf@2.6.3, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@~2.6.2: +rimraf@2.6.3, rimraf@^2.1.4, rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.3.4, rimraf@^2.4.1, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@~2.6.2: version "2.6.3" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" dependencies: glob "^7.1.3" -rimraf@~2.5.0: - version "2.5.4" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" - dependencies: - glob "^7.0.5" - rollup-pluginutils@^2.0.1: version "2.4.1" resolved "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.4.1.tgz#de43ab54965bbf47843599a7f3adceb723de38db" @@ -7705,7 +6672,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -7723,22 +6690,14 @@ sane@^4.0.0: walker "~1.0.5" watch "~0.18.0" -"semver@2 >=2.2.1 || 3.x || 4 || 5", "semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.6.0" resolved "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" -semver@^4.3.1: - version "4.3.6" - resolved "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" - semver@~5.0.1: version "5.0.3" resolved "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" -semver@~5.1.0: - version "5.1.1" - resolved "https://registry.npmjs.org/semver/-/semver-5.1.1.tgz#a3292a373e6f3e0798da0b20641b9a9c5bc47e19" - send@0.16.2: version "0.16.2" resolved "https://registry.npmjs.org/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" @@ -7792,13 +6751,6 @@ setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" -sha@~2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae" - dependencies: - graceful-fs "^4.1.2" - readable-stream "^2.0.2" - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -7813,10 +6765,6 @@ shellwords@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" -sigmund@~1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" - signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -7839,10 +6787,6 @@ slice-ansi@^2.1.0: astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" -slide@^1.1.3, slide@^1.1.5, slide@~1.1.3, slide@~1.1.6: - version "1.1.6" - resolved "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -7876,12 +6820,6 @@ sntp@0.2.x: dependencies: hoek "0.9.x" -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - dependencies: - hoek "2.x.x" - socket.io-adapter@~1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" @@ -7941,10 +6879,6 @@ sort-package-json@^1.15.0: detect-indent "^5.0.0" sort-object-keys "^1.1.2" -sorted-object@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/sorted-object/-/sorted-object-1.0.0.tgz#5d1f4f9c1fb2cd48965967304e212eb44cfb6d05" - source-map-resolve@^0.5.0: version "0.5.2" resolved "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" @@ -8017,32 +6951,6 @@ spawn-args@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" -spawnback@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/spawnback/-/spawnback-1.0.0.tgz#f73662f7e54d95367eca74d6426c677dd7ea686f" - -spdx-correct@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.2.0" - resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" - -spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.3" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz#81c0ce8f21474756148bbb5f3bfc0f36bf15d76e" - split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -8061,20 +6969,6 @@ sri-toolbox@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - stagehand@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/stagehand/-/stagehand-1.0.0.tgz#79515e2ad3a02c63f8720c7df9b6077ae14276d9" @@ -8227,14 +7121,6 @@ tap-parser@^7.0.0: js-yaml "^3.2.7" minipass "^2.2.0" -tar@^2.0.0, tar@~2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" - temp@0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/temp/-/temp-0.9.0.tgz#61391795a11bd9738d4c4d7f55f012cb8f55edaa" @@ -8291,7 +7177,7 @@ testem@^2.9.2: tmp "0.0.33" xmldom "^0.1.19" -text-table@^0.2.0, text-table@~0.2.0: +text-table@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -8399,17 +7285,6 @@ tough-cookie@>=0.12.0: psl "^1.1.28" punycode "^2.1.1" -tough-cookie@~2.2.0: - version "2.2.2" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz#c83a1830f4e5ef0b93ef2a3488e724f8de016ac7" - -tough-cookie@~2.4.3: - version "2.4.3" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" - dependencies: - psl "^1.1.24" - punycode "^1.4.1" - tree-sync@^1.2.2: version "1.4.0" resolved "https://registry.npmjs.org/tree-sync/-/tree-sync-1.4.0.tgz#314598d13abaf752547d9335b8f95d9a137100d6" @@ -8428,20 +7303,10 @@ tslib@^1.9.0: version "1.9.3" resolved "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" - -tunnel-agent@~0.4.0, tunnel-agent@~0.4.1: +tunnel-agent@~0.4.0: version "0.4.3" resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - type-check@~0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -8467,10 +7332,6 @@ type-is@~1.6.16: media-typer "0.3.0" mime-types "~2.1.18" -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - typescript@~3.3.3: version "3.3.3333" resolved "https://registry.npmjs.org/typescript/-/typescript-3.3.3333.tgz#171b2c5af66c59e9431199117a3bcadc66fdcfd6" @@ -8486,14 +7347,6 @@ uglify-js@^3.1.4: commander "~2.17.1" source-map "~0.6.1" -uid-number@0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - -umask@~1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" - underscore.string@^3.2.2, underscore.string@~3.3.4: version "3.3.5" resolved "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz#fc2ad255b8bd309e239cbc5816fd23a9b7ea4023" @@ -8533,18 +7386,6 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^0.4.3" -unique-filename@~1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - dependencies: - unique-slug "^2.0.0" - -unique-slug@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz#5e9edc6d1ce8fb264db18a507ef9bd8544451ca6" - dependencies: - imurmurhash "^0.1.4" - unique-string@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" @@ -8614,10 +7455,6 @@ util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" -util-extend@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f" - utils-merge@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -8626,37 +7463,16 @@ uuid@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - validate-npm-package-name@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" dependencies: builtins "^1.0.3" -validate-npm-package-name@~2.2.2: - version "2.2.2" - resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-2.2.2.tgz#f65695b22f7324442019a3c7fa39a6e7fd299085" - dependencies: - builtins "0.0.7" - vary@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" -verror@1.10.0: - version "1.10.0" - resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - walk-sync@^0.2.0, walk-sync@^0.2.5: version "0.2.7" resolved "https://registry.npmjs.org/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" @@ -8702,7 +7518,7 @@ watch@~0.18.0: exec-sh "^0.2.0" minimist "^1.2.0" -wcwidth@^1.0.0, wcwidth@^1.0.1: +wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" dependencies: @@ -8727,18 +7543,12 @@ which-module@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" -which@1, which@1.3.1, which@^1.2.14, which@^1.2.9, which@^1.3.0: +which@1.3.1, which@^1.2.14, which@^1.2.9, which@^1.3.0: version "1.3.1" resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" dependencies: isexe "^2.0.0" -which@~1.2.1: - version "1.2.14" - resolved "https://registry.npmjs.org/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" - dependencies: - isexe "^2.0.0" - wide-align@1.1.3, wide-align@^1.1.0: version "1.1.3" resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" @@ -8772,7 +7582,7 @@ wrap-ansi@^2.0.0: string-width "^1.0.1" strip-ansi "^3.0.1" -wrappy@1, wrappy@~1.0.1: +wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -8784,14 +7594,6 @@ write-file-atomic@^2.0.0: imurmurhash "^0.1.4" signal-exit "^3.0.2" -write-file-atomic@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.1.4.tgz#b1f52dc2e8dc0e3cb04d187a25f758a38a90ca3b" - dependencies: - graceful-fs "^4.1.2" - imurmurhash "^0.1.4" - slide "^1.1.5" - write@1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" @@ -8816,7 +7618,7 @@ xmlhttprequest-ssl@~1.5.4: version "1.5.5" resolved "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" -xtend@^4.0.0, xtend@~4.0.0: +xtend@~4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" From 85b14c5af46cba934865dcaf52c49f239246b5e7 Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 19 Oct 2018 11:44:30 +0200 Subject: [PATCH 2509/2527] fix: ensure missing resource linkage isn't normalized incorrectly fixes #5706 --- addon/-private/system/store/finders.js | 15 +-- .../inverse-relationship-load-test.js | 94 +++++++++++++++++++ 2 files changed, 103 insertions(+), 6 deletions(-) diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index e929c72f48f..d51206b46b2 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -202,12 +202,15 @@ function ensureRelationshipIsSetToParent( until: '3.8', }); } - relationships[inverseKey] = relationships[inverseKey] || {}; - relationships[inverseKey].data = fixRelationshipData( - relationshipData, - kind, - parentInternalModel - ); + + if (kind !== 'hasMany' || typeof relationshipData !== 'undefined') { + relationships[inverseKey] = relationships[inverseKey] || {}; + relationships[inverseKey].data = fixRelationshipData( + relationshipData, + kind, + parentInternalModel + ); + } } } diff --git a/tests/integration/relationships/inverse-relationship-load-test.js b/tests/integration/relationships/inverse-relationship-load-test.js index e224fbdb471..d642df61eaa 100644 --- a/tests/integration/relationships/inverse-relationship-load-test.js +++ b/tests/integration/relationships/inverse-relationship-load-test.js @@ -4892,4 +4892,98 @@ module('inverse relationship load test', function(hooks) { ); assert.equal(pal2Dogs.get('firstObject.id'), '2', 'hasMany relationship has correct records'); }); + + test("loading belongsTo doesn't remove inverse relationship for other instances", async function(assert) { + let { owner } = this; + + const scooby = { + id: '1', + type: 'dog', + attributes: { + name: 'Scooby', + }, + relationships: { + person: { + data: { id: '1', type: 'person' }, + links: { related: 'http://example.com/dogs/1/person' }, + }, + }, + }; + const scrappy = { + id: '2', + type: 'dog', + attributes: { + name: 'Scrappy', + }, + relationships: { + person: { + data: { id: '1', type: 'person' }, + links: { related: 'http://example.com/dogs/1/person' }, + }, + }, + }; + owner.register( + 'adapter:application', + JSONAPIAdapter.extend({ + deleteRecord: () => resolve({ data: null }), + findBelongsTo: () => { + return resolve({ + data: { + type: 'person', + id: '1', + attributes: { + name: 'John Churchill', + }, + relationships: { + dogs: { + links: { + related: 'http://example.com/person/1/dogs', + }, + }, + }, + }, + }); + }, + findRecord: (_store, _type, id) => { + const dog = id === '1' ? scooby : scrappy; + return resolve({ + data: dog, + }); + }, + }) + ); + + class Person extends Model { + @hasMany('dog', { + async: false, + }) + dogs; + } + + owner.register('model:person', Person); + + class Dog extends Model { + @belongsTo('person', { + async: true, + }) + person; + + @attr('string') + name; + } + + owner.register('model:dog', Dog); + + // load em into store + let dog1 = await owner.lookup('service:store').findRecord('dog', '1'); + let dog2 = await owner.lookup('service:store').findRecord('dog', '2'); + + assert.equal(dog1.belongsTo('person').id(), '1'); + assert.equal(dog2.belongsTo('person').id(), '1'); + + await dog1.get('person'); + + assert.equal(dog1.belongsTo('person').id(), '1'); + assert.equal(dog2.belongsTo('person').id(), '1'); + }); }); From 6097f5379e1cbd48d75698a326d76c72b6a15299 Mon Sep 17 00:00:00 2001 From: Ryan Toronto Date: Sat, 9 Mar 2019 14:00:28 -0500 Subject: [PATCH 2510/2527] Use #get for 2.18 CI tests --- tests/unit/store/push-test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/store/push-test.js b/tests/unit/store/push-test.js index f4b9ddbd699..e4596766d31 100644 --- a/tests/unit/store/push-test.js +++ b/tests/unit/store/push-test.js @@ -636,8 +636,8 @@ testInDebug( let person = store.peekRecord('person', 1); - assert.equal(person.phoneNumbers.length, 1); - assert.equal(person.phoneNumbers.firstObject.number, '1-800-DATA'); + assert.equal(person.get('phoneNumbers.length'), 1); + assert.equal(person.get('phoneNumbers.firstObject.number'), '1-800-DATA'); // GET /persons/1 assert.expectNoWarning(() => { @@ -656,8 +656,8 @@ testInDebug( }); }); - assert.equal(person.phoneNumbers.length, 1); - assert.equal(person.phoneNumbers.firstObject.number, '1-800-DATA'); + assert.equal(person.get('phoneNumbers.length'), 1); + assert.equal(person.get('phoneNumbers.firstObject.number'), '1-800-DATA'); } ); From 75517093521b25a756b3522acb69b2aeb507107a Mon Sep 17 00:00:00 2001 From: Ryan Toronto Date: Sat, 9 Mar 2019 14:00:34 -0500 Subject: [PATCH 2511/2527] Wrap in Ember.run for 2.18 CI tests --- tests/integration/adapter/client-side-delete-test.js | 2 +- tests/integration/application-test.js | 6 ++++-- tests/integration/debug-adapter-test.js | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/integration/adapter/client-side-delete-test.js b/tests/integration/adapter/client-side-delete-test.js index 3470a0072f7..e8bf2c6609b 100644 --- a/tests/integration/adapter/client-side-delete-test.js +++ b/tests/integration/adapter/client-side-delete-test.js @@ -75,7 +75,7 @@ test('client-side deleted records can be added back from an inverse', async func await book2.destroyRecord({ adapterOptions: { clientSideDelete: true } }); - book2.unloadRecord(); + run(() => book2.unloadRecord()); await settled(); diff --git a/tests/integration/application-test.js b/tests/integration/application-test.js index 74c1db3a471..1c965b679ff 100644 --- a/tests/integration/application-test.js +++ b/tests/integration/application-test.js @@ -133,7 +133,7 @@ module('integration/application - Attaching initializer', function(hooks) { this.application = this.TestApplication.create({ autoboot: false }); - await this.application.boot(); + await run(() => this.application.boot()); assert.ok(ran, 'ember-data initializer was found'); }); @@ -153,7 +153,9 @@ module('integration/application - Attaching initializer', function(hooks) { this.application = this.TestApplication.create({ autoboot: false }); - await this.application.boot().then(() => (this.owner = this.application.buildInstance())); + await run(() => + this.application.boot().then(() => (this.owner = this.application.buildInstance())) + ); let store = this.owner.lookup('service:store'); assert.ok( diff --git a/tests/integration/debug-adapter-test.js b/tests/integration/debug-adapter-test.js index 32201a15855..43e999ac09e 100644 --- a/tests/integration/debug-adapter-test.js +++ b/tests/integration/debug-adapter-test.js @@ -1,6 +1,7 @@ import { setupTest } from 'ember-qunit'; import { A } from '@ember/array'; import { get } from '@ember/object'; +import { run } from '@ember/runloop'; import Model from 'ember-data/model'; import { attr } from '@ember-decorators/data'; import Adapter from 'ember-data/adapter'; @@ -122,7 +123,7 @@ module('integration/debug-adapter - DS.DebugAdapter', function(hooks) { assert.deepEqual(record.searchKeywords, ['2', 'New Post']); assert.deepEqual(record.color, 'green'); - post.unloadRecord(); + run(() => post.unloadRecord()); await settled(); From 6727e77b1fb432db4c282d16a8e142a5018e9432 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 6 Mar 2019 05:32:58 +0000 Subject: [PATCH 2512/2527] Bump @types/ember-test-helpers from 1.0.4 to 1.0.5 Bumps [@types/ember-test-helpers](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/ember-test-helpers) from 1.0.4 to 1.0.5. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/ember-test-helpers) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index a645916e094..5bf485a8bad 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "@ember-decorators/data": "^5.1.4", "@types/ember": "~3.0.25", "@types/ember-qunit": "~3.4.5", - "@types/ember-test-helpers": "~1.0.4", + "@types/ember-test-helpers": "~1.0.5", "@types/ember-testing-helpers": "~0.0.3", "@types/ember__debug": "^3.0.3", "@types/ember__test-helpers": "~0.7.7", diff --git a/yarn.lock b/yarn.lock index 0842600ce7a..71d2e9a9373 100644 --- a/yarn.lock +++ b/yarn.lock @@ -734,9 +734,9 @@ "@types/ember" "*" "@types/ember-test-helpers" "*" -"@types/ember-test-helpers@*", "@types/ember-test-helpers@~1.0.4": - version "1.0.4" - resolved "https://registry.npmjs.org/@types/ember-test-helpers/-/ember-test-helpers-1.0.4.tgz#db08190659339cd6018ff8f842c6df6f24d7679a" +"@types/ember-test-helpers@*", "@types/ember-test-helpers@~1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/ember-test-helpers/-/ember-test-helpers-1.0.5.tgz#b0a8a3b9386ddf372eef11ba95487be806674ca2" dependencies: "@types/ember" "*" "@types/htmlbars-inline-precompile" "*" From e4bf5478a98b6a26f435af5eb39a21588e821cc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Wed, 6 Mar 2019 05:33:14 +0000 Subject: [PATCH 2513/2527] Bump @types/ember__test-helpers from 0.7.7 to 0.7.8 Bumps [@types/ember__test-helpers](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/ember__test-helpers) from 0.7.7 to 0.7.8. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/ember__test-helpers) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 5bf485a8bad..d6c88154eeb 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "@types/ember-test-helpers": "~1.0.5", "@types/ember-testing-helpers": "~0.0.3", "@types/ember__debug": "^3.0.3", - "@types/ember__test-helpers": "~0.7.7", + "@types/ember__test-helpers": "~0.7.8", "@types/qunit": "^2.5.3", "@types/rsvp": "^4.0.2", "babel-eslint": "^10.0.1", diff --git a/yarn.lock b/yarn.lock index 71d2e9a9373..58fc3a3555e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -862,9 +862,9 @@ dependencies: "@types/handlebars" "*" -"@types/ember__test-helpers@~0.7.7": - version "0.7.7" - resolved "https://registry.npmjs.org/@types/ember__test-helpers/-/ember__test-helpers-0.7.7.tgz#b11832e5e622c1e61f96d8477845a84b5ec348c3" +"@types/ember__test-helpers@~0.7.8": + version "0.7.8" + resolved "https://registry.yarnpkg.com/@types/ember__test-helpers/-/ember__test-helpers-0.7.8.tgz#16d6e060ec88e5510756d00e8f191fa48d9e0362" dependencies: "@types/ember" "*" "@types/ember__application" "*" From df6d4e1e63073025eaccad28867d2a07c0644d46 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Fri, 8 Mar 2019 06:15:42 +0000 Subject: [PATCH 2514/2527] Bump @types/ember from 3.0.27 to 3.0.29 Bumps [@types/ember](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/ember) from 3.0.27 to 3.0.29. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/ember) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d6c88154eeb..109a86c5638 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "@babel/plugin-transform-typescript": "^7.2.0", "@ember-decorators/babel-transforms": "^5.1.4", "@ember-decorators/data": "^5.1.4", - "@types/ember": "~3.0.25", + "@types/ember": "~3.0.29", "@types/ember-qunit": "~3.4.5", "@types/ember-test-helpers": "~1.0.5", "@types/ember-testing-helpers": "~0.0.3", diff --git a/yarn.lock b/yarn.lock index 58fc3a3555e..a14eafa49f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -750,9 +750,9 @@ "@types/jquery" "*" "@types/rsvp" "*" -"@types/ember@*", "@types/ember@~3.0.25": - version "3.0.27" - resolved "https://registry.npmjs.org/@types/ember/-/ember-3.0.27.tgz#2915984038f3ae3609142f8e700b4a783a30be5d" +"@types/ember@*", "@types/ember@~3.0.29": + version "3.0.29" + resolved "https://registry.yarnpkg.com/@types/ember/-/ember-3.0.29.tgz#a437a60a41f8df9cba52de267bfd0007566eae41" dependencies: "@types/ember__application" "*" "@types/ember__array" "*" @@ -769,7 +769,6 @@ "@types/ember__string" "*" "@types/ember__test" "*" "@types/ember__utils" "*" - "@types/handlebars" "*" "@types/htmlbars-inline-precompile" "*" "@types/jquery" "*" "@types/rsvp" "*" From 231c760b7721015f968f7d62b5d2904763417744 Mon Sep 17 00:00:00 2001 From: Christian Date: Sat, 9 Mar 2019 19:50:45 +0100 Subject: [PATCH 2515/2527] fix: coerce ids before warning for mismatch --- addon/-private/system/store/finders.js | 3 +- tests/integration/adapter/find-test.js | 40 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/addon/-private/system/store/finders.js b/addon/-private/system/store/finders.js index d51206b46b2..c678aa4454f 100644 --- a/addon/-private/system/store/finders.js +++ b/addon/-private/system/store/finders.js @@ -3,6 +3,7 @@ import { Promise } from 'rsvp'; import { assert, warn, deprecate } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; import Ember from 'ember'; +import coerceId from '../coerce-id'; import { _bind, _guard, _objectIsAlive, guardDestroyedStore } from './common'; @@ -52,7 +53,7 @@ export function _find(adapter, store, modelClass, id, internalModel, options) { `You requested a record of type '${modelName}' with id '${id}' but the adapter returned a payload with primary data having an id of '${ payload.data.id }'. Use 'store.findRecord()' when the requested id is the same as the one returned by the adapter. In other cases use 'store.queryRecord()' instead https://emberjs.com/api/data/classes/DS.Store.html#method_queryRecord`, - payload.data.id === id, + coerceId(payload.data.id) === coerceId(id), { id: 'ds.store.findRecord.id-mismatch', } diff --git a/tests/integration/adapter/find-test.js b/tests/integration/adapter/find-test.js index 05407de0387..397b5e568af 100644 --- a/tests/integration/adapter/find-test.js +++ b/tests/integration/adapter/find-test.js @@ -4,6 +4,7 @@ import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; import DS from 'ember-data'; +import JSONAPISerializer from 'ember-data/serializers/json-api'; const { attr } = DS; @@ -202,3 +203,42 @@ testInDebug('warns when returned record has different id', function(assert) { /You requested a record of type 'person' with id 'me' but the adapter returned a payload with primary data having an id of '1'/ ); }); + +testInDebug('coerces ids before warning when returned record has different id', async function( + assert +) { + env.owner.register( + 'serializer:application', + JSONAPISerializer.extend({ + normalizeResponse(_, __, payload) { + return payload; + }, + }) + ); + + env.owner.register( + 'adapter:person', + DS.Adapter.extend({ + findRecord() { + return { + data: { + id: 1, + type: 'person', + attributes: { + name: 'Braaaahm Dale', + }, + }, + }; + }, + }) + ); + + assert.expectNoWarning( + () => run(() => env.store.findRecord('person', 1)), + /You requested a record of type 'person' with id '1' but the adapter returned a payload with primary data having an id of '1'/ + ); + assert.expectNoWarning( + () => run(() => env.store.findRecord('person', '1')), + /You requested a record of type 'person' with id '1' but the adapter returned a payload with primary data having an id of '1'/ + ); +}); From 140abb795333492cf564e29acbc198666c680356 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 22 Feb 2019 19:01:17 -0800 Subject: [PATCH 2516/2527] add yarn policy --- .yarn/releases/yarn-1.13.0.js | 136098 +++++++++++++++++++++++++++++++ .yarnrc | 7 + 2 files changed, 136105 insertions(+) create mode 100755 .yarn/releases/yarn-1.13.0.js create mode 100644 .yarnrc diff --git a/.yarn/releases/yarn-1.13.0.js b/.yarn/releases/yarn-1.13.0.js new file mode 100755 index 00000000000..4a4cb0d3de9 --- /dev/null +++ b/.yarn/releases/yarn-1.13.0.js @@ -0,0 +1,136098 @@ +#!/usr/bin/env node +module.exports = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // identity function for calling harmony imports with the correct context +/******/ __webpack_require__.i = function(value) { return value; }; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 520); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports) { + +module.exports = require("path"); + +/***/ }), +/* 1 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["a"] = __extends; +/* unused harmony export __assign */ +/* unused harmony export __rest */ +/* unused harmony export __decorate */ +/* unused harmony export __param */ +/* unused harmony export __metadata */ +/* unused harmony export __awaiter */ +/* unused harmony export __generator */ +/* unused harmony export __exportStar */ +/* unused harmony export __values */ +/* unused harmony export __read */ +/* unused harmony export __spread */ +/* unused harmony export __await */ +/* unused harmony export __asyncGenerator */ +/* unused harmony export __asyncDelegator */ +/* unused harmony export __asyncValues */ +/* unused harmony export __makeTemplateObject */ +/* unused harmony export __importStar */ +/* unused harmony export __importDefault */ +/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at http://www.apache.org/licenses/LICENSE-2.0 + +THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED +WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +MERCHANTABLITY OR NON-INFRINGEMENT. + +See the Apache Version 2.0 License for specific language governing permissions +and limitations under the License. +***************************************************************************** */ +/* global Reflect, Promise */ + +var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); +}; + +function __extends(d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +} + +var __assign = function() { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + } + return __assign.apply(this, arguments); +} + +function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +} + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +} + +function __param(paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } +} + +function __metadata(metadataKey, metadataValue) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); +} + +function __awaiter(thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +function __generator(thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +} + +function __exportStar(m, exports) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; +} + +function __values(o) { + var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; + if (m) return m.call(o); + return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; +} + +function __read(o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +} + +function __spread() { + for (var ar = [], i = 0; i < arguments.length; i++) + ar = ar.concat(__read(arguments[i])); + return ar; +} + +function __await(v) { + return this instanceof __await ? (this.v = v, this) : new __await(v); +} + +function __asyncGenerator(thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; + function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } +} + +function __asyncDelegator(o) { + var i, p; + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } +} + +function __asyncValues(o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } +} + +function __makeTemplateObject(cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; +}; + +function __importStar(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result.default = mod; + return result; +} + +function __importDefault(mod) { + return (mod && mod.__esModule) ? mod : { default: mod }; +} + + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.__esModule = true; + +var _promise = __webpack_require__(216); + +var _promise2 = _interopRequireDefault(_promise); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = function (fn) { + return function () { + var gen = fn.apply(this, arguments); + return new _promise2.default(function (resolve, reject) { + function step(key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + + if (info.done) { + resolve(value); + } else { + return _promise2.default.resolve(value).then(function (value) { + step("next", value); + }, function (err) { + step("throw", err); + }); + } + } + + return step("next"); + }); + }; +}; + +/***/ }), +/* 3 */ +/***/ (function(module, exports) { + +module.exports = require("util"); + +/***/ }), +/* 4 */ +/***/ (function(module, exports) { + +module.exports = require("fs"); + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getFirstSuitableFolder = exports.readFirstAvailableStream = exports.makeTempDir = exports.hardlinksWork = exports.writeFilePreservingEol = exports.getFileSizeOnDisk = exports.walk = exports.symlink = exports.find = exports.readJsonAndFile = exports.readJson = exports.readFileAny = exports.hardlinkBulk = exports.copyBulk = exports.unlink = exports.glob = exports.link = exports.chmod = exports.lstat = exports.exists = exports.mkdirp = exports.stat = exports.access = exports.rename = exports.readdir = exports.realpath = exports.readlink = exports.writeFile = exports.open = exports.readFileBuffer = exports.lockQueue = exports.constants = undefined; + +var _asyncToGenerator2; + +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} + +let buildActionsForCopy = (() => { + var _ref = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, events, possibleExtraneous, reporter) { + + // + let build = (() => { + var _ref5 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { + const src = data.src, + dest = data.dest, + type = data.type; + + const onFresh = data.onFresh || noop; + const onDone = data.onDone || noop; + + // TODO https://github.com/yarnpkg/yarn/issues/3751 + // related to bundled dependencies handling + if (files.has(dest.toLowerCase())) { + reporter.verbose(`The case-insensitive file ${dest} shouldn't be copied twice in one bulk copy`); + } else { + files.add(dest.toLowerCase()); + } + + if (type === 'symlink') { + yield mkdirp((_path || _load_path()).default.dirname(dest)); + onFresh(); + actions.symlink.push({ + dest, + linkname: src + }); + onDone(); + return; + } + + if (events.ignoreBasenames.indexOf((_path || _load_path()).default.basename(src)) >= 0) { + // ignored file + return; + } + + const srcStat = yield lstat(src); + let srcFiles; + + if (srcStat.isDirectory()) { + srcFiles = yield readdir(src); + } + + let destStat; + try { + // try accessing the destination + destStat = yield lstat(dest); + } catch (e) { + // proceed if destination doesn't exist, otherwise error + if (e.code !== 'ENOENT') { + throw e; + } + } + + // if destination exists + if (destStat) { + const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); + const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); + const bothFiles = srcStat.isFile() && destStat.isFile(); + + // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving + // us modes that aren't valid. investigate this, it's generally safe to proceed. + + /* if (srcStat.mode !== destStat.mode) { + try { + await access(dest, srcStat.mode); + } catch (err) {} + } */ + + if (bothFiles && artifactFiles.has(dest)) { + // this file gets changed during build, likely by a custom install script. Don't bother checking it. + onDone(); + reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); + return; + } + + if (bothFiles && srcStat.size === destStat.size && (0, (_fsNormalized || _load_fsNormalized()).fileDatesEqual)(srcStat.mtime, destStat.mtime)) { + // we can safely assume this is the same file + onDone(); + reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.size, +srcStat.mtime)); + return; + } + + if (bothSymlinks) { + const srcReallink = yield readlink(src); + if (srcReallink === (yield readlink(dest))) { + // if both symlinks are the same then we can continue on + onDone(); + reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); + return; + } + } + + if (bothFolders) { + // mark files that aren't in this folder as possibly extraneous + const destFiles = yield readdir(dest); + invariant(srcFiles, 'src files not initialised'); + + for (var _iterator4 = destFiles, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { + var _ref6; + + if (_isArray4) { + if (_i4 >= _iterator4.length) break; + _ref6 = _iterator4[_i4++]; + } else { + _i4 = _iterator4.next(); + if (_i4.done) break; + _ref6 = _i4.value; + } + + const file = _ref6; + + if (srcFiles.indexOf(file) < 0) { + const loc = (_path || _load_path()).default.join(dest, file); + possibleExtraneous.add(loc); + + if ((yield lstat(loc)).isDirectory()) { + for (var _iterator5 = yield readdir(loc), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { + var _ref7; + + if (_isArray5) { + if (_i5 >= _iterator5.length) break; + _ref7 = _iterator5[_i5++]; + } else { + _i5 = _iterator5.next(); + if (_i5.done) break; + _ref7 = _i5.value; + } + + const file = _ref7; + + possibleExtraneous.add((_path || _load_path()).default.join(loc, file)); + } + } + } + } + } + } + + if (destStat && destStat.isSymbolicLink()) { + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dest); + destStat = null; + } + + if (srcStat.isSymbolicLink()) { + onFresh(); + const linkname = yield readlink(src); + actions.symlink.push({ + dest, + linkname + }); + onDone(); + } else if (srcStat.isDirectory()) { + if (!destStat) { + reporter.verbose(reporter.lang('verboseFileFolder', dest)); + yield mkdirp(dest); + } + + const destParts = dest.split((_path || _load_path()).default.sep); + while (destParts.length) { + files.add(destParts.join((_path || _load_path()).default.sep).toLowerCase()); + destParts.pop(); + } + + // push all files to queue + invariant(srcFiles, 'src files not initialised'); + let remaining = srcFiles.length; + if (!remaining) { + onDone(); + } + for (var _iterator6 = srcFiles, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { + var _ref8; + + if (_isArray6) { + if (_i6 >= _iterator6.length) break; + _ref8 = _iterator6[_i6++]; + } else { + _i6 = _iterator6.next(); + if (_i6.done) break; + _ref8 = _i6.value; + } + + const file = _ref8; + + queue.push({ + dest: (_path || _load_path()).default.join(dest, file), + onFresh, + onDone: function (_onDone) { + function onDone() { + return _onDone.apply(this, arguments); + } + + onDone.toString = function () { + return _onDone.toString(); + }; + + return onDone; + }(function () { + if (--remaining === 0) { + onDone(); + } + }), + src: (_path || _load_path()).default.join(src, file) + }); + } + } else if (srcStat.isFile()) { + onFresh(); + actions.file.push({ + src, + dest, + atime: srcStat.atime, + mtime: srcStat.mtime, + mode: srcStat.mode + }); + onDone(); + } else { + throw new Error(`unsure how to copy this: ${src}`); + } + }); + + return function build(_x5) { + return _ref5.apply(this, arguments); + }; + })(); + + const artifactFiles = new Set(events.artifactFiles || []); + const files = new Set(); + + // initialise events + for (var _iterator = queue, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref2; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref2 = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref2 = _i.value; + } + + const item = _ref2; + + const onDone = item.onDone; + item.onDone = function () { + events.onProgress(item.dest); + if (onDone) { + onDone(); + } + }; + } + events.onStart(queue.length); + + // start building actions + const actions = { + file: [], + symlink: [], + link: [] + }; + + // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items + // at a time due to the requirement to push items onto the queue + while (queue.length) { + const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); + yield Promise.all(items.map(build)); + } + + // simulate the existence of some files to prevent considering them extraneous + for (var _iterator2 = artifactFiles, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref3; + + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref3 = _iterator2[_i2++]; + } else { + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref3 = _i2.value; + } + + const file = _ref3; + + if (possibleExtraneous.has(file)) { + reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); + possibleExtraneous.delete(file); + } + } + + for (var _iterator3 = possibleExtraneous, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref4; + + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref4 = _iterator3[_i3++]; + } else { + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref4 = _i3.value; + } + + const loc = _ref4; + + if (files.has(loc.toLowerCase())) { + possibleExtraneous.delete(loc); + } + } + + return actions; + }); + + return function buildActionsForCopy(_x, _x2, _x3, _x4) { + return _ref.apply(this, arguments); + }; +})(); + +let buildActionsForHardlink = (() => { + var _ref9 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, events, possibleExtraneous, reporter) { + + // + let build = (() => { + var _ref13 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { + const src = data.src, + dest = data.dest; + + const onFresh = data.onFresh || noop; + const onDone = data.onDone || noop; + if (files.has(dest.toLowerCase())) { + // Fixes issue https://github.com/yarnpkg/yarn/issues/2734 + // When bulk hardlinking we have A -> B structure that we want to hardlink to A1 -> B1, + // package-linker passes that modules A1 and B1 need to be hardlinked, + // the recursive linking algorithm of A1 ends up scheduling files in B1 to be linked twice which will case + // an exception. + onDone(); + return; + } + files.add(dest.toLowerCase()); + + if (events.ignoreBasenames.indexOf((_path || _load_path()).default.basename(src)) >= 0) { + // ignored file + return; + } + + const srcStat = yield lstat(src); + let srcFiles; + + if (srcStat.isDirectory()) { + srcFiles = yield readdir(src); + } + + const destExists = yield exists(dest); + if (destExists) { + const destStat = yield lstat(dest); + + const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); + const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); + const bothFiles = srcStat.isFile() && destStat.isFile(); + + if (srcStat.mode !== destStat.mode) { + try { + yield access(dest, srcStat.mode); + } catch (err) { + // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving + // us modes that aren't valid. investigate this, it's generally safe to proceed. + reporter.verbose(err); + } + } + + if (bothFiles && artifactFiles.has(dest)) { + // this file gets changed during build, likely by a custom install script. Don't bother checking it. + onDone(); + reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); + return; + } + + // correct hardlink + if (bothFiles && srcStat.ino !== null && srcStat.ino === destStat.ino) { + onDone(); + reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.ino)); + return; + } + + if (bothSymlinks) { + const srcReallink = yield readlink(src); + if (srcReallink === (yield readlink(dest))) { + // if both symlinks are the same then we can continue on + onDone(); + reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); + return; + } + } + + if (bothFolders) { + // mark files that aren't in this folder as possibly extraneous + const destFiles = yield readdir(dest); + invariant(srcFiles, 'src files not initialised'); + + for (var _iterator10 = destFiles, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { + var _ref14; + + if (_isArray10) { + if (_i10 >= _iterator10.length) break; + _ref14 = _iterator10[_i10++]; + } else { + _i10 = _iterator10.next(); + if (_i10.done) break; + _ref14 = _i10.value; + } + + const file = _ref14; + + if (srcFiles.indexOf(file) < 0) { + const loc = (_path || _load_path()).default.join(dest, file); + possibleExtraneous.add(loc); + + if ((yield lstat(loc)).isDirectory()) { + for (var _iterator11 = yield readdir(loc), _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { + var _ref15; + + if (_isArray11) { + if (_i11 >= _iterator11.length) break; + _ref15 = _iterator11[_i11++]; + } else { + _i11 = _iterator11.next(); + if (_i11.done) break; + _ref15 = _i11.value; + } + + const file = _ref15; + + possibleExtraneous.add((_path || _load_path()).default.join(loc, file)); + } + } + } + } + } + } + + if (srcStat.isSymbolicLink()) { + onFresh(); + const linkname = yield readlink(src); + actions.symlink.push({ + dest, + linkname + }); + onDone(); + } else if (srcStat.isDirectory()) { + reporter.verbose(reporter.lang('verboseFileFolder', dest)); + yield mkdirp(dest); + + const destParts = dest.split((_path || _load_path()).default.sep); + while (destParts.length) { + files.add(destParts.join((_path || _load_path()).default.sep).toLowerCase()); + destParts.pop(); + } + + // push all files to queue + invariant(srcFiles, 'src files not initialised'); + let remaining = srcFiles.length; + if (!remaining) { + onDone(); + } + for (var _iterator12 = srcFiles, _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) { + var _ref16; + + if (_isArray12) { + if (_i12 >= _iterator12.length) break; + _ref16 = _iterator12[_i12++]; + } else { + _i12 = _iterator12.next(); + if (_i12.done) break; + _ref16 = _i12.value; + } + + const file = _ref16; + + queue.push({ + onFresh, + src: (_path || _load_path()).default.join(src, file), + dest: (_path || _load_path()).default.join(dest, file), + onDone: function (_onDone2) { + function onDone() { + return _onDone2.apply(this, arguments); + } + + onDone.toString = function () { + return _onDone2.toString(); + }; + + return onDone; + }(function () { + if (--remaining === 0) { + onDone(); + } + }) + }); + } + } else if (srcStat.isFile()) { + onFresh(); + actions.link.push({ + src, + dest, + removeDest: destExists + }); + onDone(); + } else { + throw new Error(`unsure how to copy this: ${src}`); + } + }); + + return function build(_x10) { + return _ref13.apply(this, arguments); + }; + })(); + + const artifactFiles = new Set(events.artifactFiles || []); + const files = new Set(); + + // initialise events + for (var _iterator7 = queue, _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { + var _ref10; + + if (_isArray7) { + if (_i7 >= _iterator7.length) break; + _ref10 = _iterator7[_i7++]; + } else { + _i7 = _iterator7.next(); + if (_i7.done) break; + _ref10 = _i7.value; + } + + const item = _ref10; + + const onDone = item.onDone || noop; + item.onDone = function () { + events.onProgress(item.dest); + onDone(); + }; + } + events.onStart(queue.length); + + // start building actions + const actions = { + file: [], + symlink: [], + link: [] + }; + + // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items + // at a time due to the requirement to push items onto the queue + while (queue.length) { + const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); + yield Promise.all(items.map(build)); + } + + // simulate the existence of some files to prevent considering them extraneous + for (var _iterator8 = artifactFiles, _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { + var _ref11; + + if (_isArray8) { + if (_i8 >= _iterator8.length) break; + _ref11 = _iterator8[_i8++]; + } else { + _i8 = _iterator8.next(); + if (_i8.done) break; + _ref11 = _i8.value; + } + + const file = _ref11; + + if (possibleExtraneous.has(file)) { + reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); + possibleExtraneous.delete(file); + } + } + + for (var _iterator9 = possibleExtraneous, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { + var _ref12; + + if (_isArray9) { + if (_i9 >= _iterator9.length) break; + _ref12 = _iterator9[_i9++]; + } else { + _i9 = _iterator9.next(); + if (_i9.done) break; + _ref12 = _i9.value; + } + + const loc = _ref12; + + if (files.has(loc.toLowerCase())) { + possibleExtraneous.delete(loc); + } + } + + return actions; + }); + + return function buildActionsForHardlink(_x6, _x7, _x8, _x9) { + return _ref9.apply(this, arguments); + }; +})(); + +let copyBulk = exports.copyBulk = (() => { + var _ref17 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, reporter, _events) { + const events = { + onStart: _events && _events.onStart || noop, + onProgress: _events && _events.onProgress || noop, + possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), + ignoreBasenames: _events && _events.ignoreBasenames || [], + artifactFiles: _events && _events.artifactFiles || [] + }; + + const actions = yield buildActionsForCopy(queue, events, events.possibleExtraneous, reporter); + events.onStart(actions.file.length + actions.symlink.length + actions.link.length); + + const fileActions = actions.file; + + const currentlyWriting = new Map(); + + yield (_promise || _load_promise()).queue(fileActions, (() => { + var _ref18 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { + let writePromise; + while (writePromise = currentlyWriting.get(data.dest)) { + yield writePromise; + } + + reporter.verbose(reporter.lang('verboseFileCopy', data.src, data.dest)); + const copier = (0, (_fsNormalized || _load_fsNormalized()).copyFile)(data, function () { + return currentlyWriting.delete(data.dest); + }); + currentlyWriting.set(data.dest, copier); + events.onProgress(data.dest); + return copier; + }); + + return function (_x14) { + return _ref18.apply(this, arguments); + }; + })(), CONCURRENT_QUEUE_ITEMS); + + // we need to copy symlinks last as they could reference files we were copying + const symlinkActions = actions.symlink; + yield (_promise || _load_promise()).queue(symlinkActions, function (data) { + const linkname = (_path || _load_path()).default.resolve((_path || _load_path()).default.dirname(data.dest), data.linkname); + reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); + return symlink(linkname, data.dest); + }); + }); + + return function copyBulk(_x11, _x12, _x13) { + return _ref17.apply(this, arguments); + }; +})(); + +let hardlinkBulk = exports.hardlinkBulk = (() => { + var _ref19 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (queue, reporter, _events) { + const events = { + onStart: _events && _events.onStart || noop, + onProgress: _events && _events.onProgress || noop, + possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), + artifactFiles: _events && _events.artifactFiles || [], + ignoreBasenames: [] + }; + + const actions = yield buildActionsForHardlink(queue, events, events.possibleExtraneous, reporter); + events.onStart(actions.file.length + actions.symlink.length + actions.link.length); + + const fileActions = actions.link; + + yield (_promise || _load_promise()).queue(fileActions, (() => { + var _ref20 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (data) { + reporter.verbose(reporter.lang('verboseFileLink', data.src, data.dest)); + if (data.removeDest) { + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(data.dest); + } + yield link(data.src, data.dest); + }); + + return function (_x18) { + return _ref20.apply(this, arguments); + }; + })(), CONCURRENT_QUEUE_ITEMS); + + // we need to copy symlinks last as they could reference files we were copying + const symlinkActions = actions.symlink; + yield (_promise || _load_promise()).queue(symlinkActions, function (data) { + const linkname = (_path || _load_path()).default.resolve((_path || _load_path()).default.dirname(data.dest), data.linkname); + reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); + return symlink(linkname, data.dest); + }); + }); + + return function hardlinkBulk(_x15, _x16, _x17) { + return _ref19.apply(this, arguments); + }; +})(); + +let readFileAny = exports.readFileAny = (() => { + var _ref21 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (files) { + for (var _iterator13 = files, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) { + var _ref22; + + if (_isArray13) { + if (_i13 >= _iterator13.length) break; + _ref22 = _iterator13[_i13++]; + } else { + _i13 = _iterator13.next(); + if (_i13.done) break; + _ref22 = _i13.value; + } + + const file = _ref22; + + if (yield exists(file)) { + return readFile(file); + } + } + return null; + }); + + return function readFileAny(_x19) { + return _ref21.apply(this, arguments); + }; +})(); + +let readJson = exports.readJson = (() => { + var _ref23 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { + return (yield readJsonAndFile(loc)).object; + }); + + return function readJson(_x20) { + return _ref23.apply(this, arguments); + }; +})(); + +let readJsonAndFile = exports.readJsonAndFile = (() => { + var _ref24 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { + const file = yield readFile(loc); + try { + return { + object: (0, (_map || _load_map()).default)(JSON.parse(stripBOM(file))), + content: file + }; + } catch (err) { + err.message = `${loc}: ${err.message}`; + throw err; + } + }); + + return function readJsonAndFile(_x21) { + return _ref24.apply(this, arguments); + }; +})(); + +let find = exports.find = (() => { + var _ref25 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (filename, dir) { + const parts = dir.split((_path || _load_path()).default.sep); + + while (parts.length) { + const loc = parts.concat(filename).join((_path || _load_path()).default.sep); + + if (yield exists(loc)) { + return loc; + } else { + parts.pop(); + } + } + + return false; + }); + + return function find(_x22, _x23) { + return _ref25.apply(this, arguments); + }; +})(); + +let symlink = exports.symlink = (() => { + var _ref26 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (src, dest) { + if (process.platform !== 'win32') { + // use relative paths otherwise which will be retained if the directory is moved + src = (_path || _load_path()).default.relative((_path || _load_path()).default.dirname(dest), src); + // When path.relative returns an empty string for the current directory, we should instead use + // '.', which is a valid fs.symlink target. + src = src || '.'; + } + + try { + const stats = yield lstat(dest); + if (stats.isSymbolicLink()) { + const resolved = dest; + if (resolved === src) { + return; + } + } + } catch (err) { + if (err.code !== 'ENOENT') { + throw err; + } + } + + // We use rimraf for unlink which never throws an ENOENT on missing target + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dest); + + if (process.platform === 'win32') { + // use directory junctions if possible on win32, this requires absolute paths + yield fsSymlink(src, dest, 'junction'); + } else { + yield fsSymlink(src, dest); + } + }); + + return function symlink(_x24, _x25) { + return _ref26.apply(this, arguments); + }; +})(); + +let walk = exports.walk = (() => { + var _ref27 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (dir, relativeDir, ignoreBasenames = new Set()) { + let files = []; + + let filenames = yield readdir(dir); + if (ignoreBasenames.size) { + filenames = filenames.filter(function (name) { + return !ignoreBasenames.has(name); + }); + } + + for (var _iterator14 = filenames, _isArray14 = Array.isArray(_iterator14), _i14 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) { + var _ref28; + + if (_isArray14) { + if (_i14 >= _iterator14.length) break; + _ref28 = _iterator14[_i14++]; + } else { + _i14 = _iterator14.next(); + if (_i14.done) break; + _ref28 = _i14.value; + } + + const name = _ref28; + + const relative = relativeDir ? (_path || _load_path()).default.join(relativeDir, name) : name; + const loc = (_path || _load_path()).default.join(dir, name); + const stat = yield lstat(loc); + + files.push({ + relative, + basename: name, + absolute: loc, + mtime: +stat.mtime + }); + + if (stat.isDirectory()) { + files = files.concat((yield walk(loc, relative, ignoreBasenames))); + } + } + + return files; + }); + + return function walk(_x26, _x27) { + return _ref27.apply(this, arguments); + }; +})(); + +let getFileSizeOnDisk = exports.getFileSizeOnDisk = (() => { + var _ref29 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (loc) { + const stat = yield lstat(loc); + const size = stat.size, + blockSize = stat.blksize; + + + return Math.ceil(size / blockSize) * blockSize; + }); + + return function getFileSizeOnDisk(_x28) { + return _ref29.apply(this, arguments); + }; +})(); + +let getEolFromFile = (() => { + var _ref30 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (path) { + if (!(yield exists(path))) { + return undefined; + } + + const buffer = yield readFileBuffer(path); + + for (let i = 0; i < buffer.length; ++i) { + if (buffer[i] === cr) { + return '\r\n'; + } + if (buffer[i] === lf) { + return '\n'; + } + } + return undefined; + }); + + return function getEolFromFile(_x29) { + return _ref30.apply(this, arguments); + }; +})(); + +let writeFilePreservingEol = exports.writeFilePreservingEol = (() => { + var _ref31 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (path, data) { + const eol = (yield getEolFromFile(path)) || (_os || _load_os()).default.EOL; + if (eol !== '\n') { + data = data.replace(/\n/g, eol); + } + yield writeFile(path, data); + }); + + return function writeFilePreservingEol(_x30, _x31) { + return _ref31.apply(this, arguments); + }; +})(); + +let hardlinksWork = exports.hardlinksWork = (() => { + var _ref32 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (dir) { + const filename = 'test-file' + Math.random(); + const file = (_path || _load_path()).default.join(dir, filename); + const fileLink = (_path || _load_path()).default.join(dir, filename + '-link'); + try { + yield writeFile(file, 'test'); + yield link(file, fileLink); + } catch (err) { + return false; + } finally { + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(file); + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(fileLink); + } + return true; + }); + + return function hardlinksWork(_x32) { + return _ref32.apply(this, arguments); + }; +})(); + +// not a strict polyfill for Node's fs.mkdtemp + + +let makeTempDir = exports.makeTempDir = (() => { + var _ref33 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (prefix) { + const dir = (_path || _load_path()).default.join((_os || _load_os()).default.tmpdir(), `yarn-${prefix || ''}-${Date.now()}-${Math.random()}`); + yield (0, (_fsNormalized || _load_fsNormalized()).unlink)(dir); + yield mkdirp(dir); + return dir; + }); + + return function makeTempDir(_x33) { + return _ref33.apply(this, arguments); + }; +})(); + +let readFirstAvailableStream = exports.readFirstAvailableStream = (() => { + var _ref34 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (paths) { + for (var _iterator15 = paths, _isArray15 = Array.isArray(_iterator15), _i15 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) { + var _ref35; + + if (_isArray15) { + if (_i15 >= _iterator15.length) break; + _ref35 = _iterator15[_i15++]; + } else { + _i15 = _iterator15.next(); + if (_i15.done) break; + _ref35 = _i15.value; + } + + const path = _ref35; + + try { + const fd = yield open(path, 'r'); + return (_fs || _load_fs()).default.createReadStream(path, { fd }); + } catch (err) { + // Try the next one + } + } + return null; + }); + + return function readFirstAvailableStream(_x34) { + return _ref34.apply(this, arguments); + }; +})(); + +let getFirstSuitableFolder = exports.getFirstSuitableFolder = (() => { + var _ref36 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (paths, mode = constants.W_OK | constants.X_OK) { + const result = { + skipped: [], + folder: null + }; + + for (var _iterator16 = paths, _isArray16 = Array.isArray(_iterator16), _i16 = 0, _iterator16 = _isArray16 ? _iterator16 : _iterator16[Symbol.iterator]();;) { + var _ref37; + + if (_isArray16) { + if (_i16 >= _iterator16.length) break; + _ref37 = _iterator16[_i16++]; + } else { + _i16 = _iterator16.next(); + if (_i16.done) break; + _ref37 = _i16.value; + } + + const folder = _ref37; + + try { + yield mkdirp(folder); + yield access(folder, mode); + + result.folder = folder; + + return result; + } catch (error) { + result.skipped.push({ + error, + folder + }); + } + } + return result; + }); + + return function getFirstSuitableFolder(_x35) { + return _ref36.apply(this, arguments); + }; +})(); + +exports.copy = copy; +exports.readFile = readFile; +exports.readFileRaw = readFileRaw; +exports.normalizeOS = normalizeOS; + +var _fs; + +function _load_fs() { + return _fs = _interopRequireDefault(__webpack_require__(4)); +} + +var _glob; + +function _load_glob() { + return _glob = _interopRequireDefault(__webpack_require__(93)); +} + +var _os; + +function _load_os() { + return _os = _interopRequireDefault(__webpack_require__(46)); +} + +var _path; + +function _load_path() { + return _path = _interopRequireDefault(__webpack_require__(0)); +} + +var _blockingQueue; + +function _load_blockingQueue() { + return _blockingQueue = _interopRequireDefault(__webpack_require__(103)); +} + +var _promise; + +function _load_promise() { + return _promise = _interopRequireWildcard(__webpack_require__(47)); +} + +var _promise2; + +function _load_promise2() { + return _promise2 = __webpack_require__(47); +} + +var _map; + +function _load_map() { + return _map = _interopRequireDefault(__webpack_require__(28)); +} + +var _fsNormalized; + +function _load_fsNormalized() { + return _fsNormalized = __webpack_require__(207); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const constants = exports.constants = typeof (_fs || _load_fs()).default.constants !== 'undefined' ? (_fs || _load_fs()).default.constants : { + R_OK: (_fs || _load_fs()).default.R_OK, + W_OK: (_fs || _load_fs()).default.W_OK, + X_OK: (_fs || _load_fs()).default.X_OK +}; + +const lockQueue = exports.lockQueue = new (_blockingQueue || _load_blockingQueue()).default('fs lock'); + +const readFileBuffer = exports.readFileBuffer = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readFile); +const open = exports.open = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.open); +const writeFile = exports.writeFile = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.writeFile); +const readlink = exports.readlink = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readlink); +const realpath = exports.realpath = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.realpath); +const readdir = exports.readdir = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.readdir); +const rename = exports.rename = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.rename); +const access = exports.access = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.access); +const stat = exports.stat = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.stat); +const mkdirp = exports.mkdirp = (0, (_promise2 || _load_promise2()).promisify)(__webpack_require__(136)); +const exists = exports.exists = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.exists, true); +const lstat = exports.lstat = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.lstat); +const chmod = exports.chmod = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.chmod); +const link = exports.link = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.link); +const glob = exports.glob = (0, (_promise2 || _load_promise2()).promisify)((_glob || _load_glob()).default); +exports.unlink = (_fsNormalized || _load_fsNormalized()).unlink; + +// fs.copyFile uses the native file copying instructions on the system, performing much better +// than any JS-based solution and consumes fewer resources. Repeated testing to fine tune the +// concurrency level revealed 128 as the sweet spot on a quad-core, 16 CPU Intel system with SSD. + +const CONCURRENT_QUEUE_ITEMS = (_fs || _load_fs()).default.copyFile ? 128 : 4; + +const fsSymlink = (0, (_promise2 || _load_promise2()).promisify)((_fs || _load_fs()).default.symlink); +const invariant = __webpack_require__(8); +const stripBOM = __webpack_require__(151); + +const noop = () => {}; + +function copy(src, dest, reporter) { + return copyBulk([{ src, dest }], reporter); +} + +function _readFile(loc, encoding) { + return new Promise((resolve, reject) => { + (_fs || _load_fs()).default.readFile(loc, encoding, function (err, content) { + if (err) { + reject(err); + } else { + resolve(content); + } + }); + }); +} + +function readFile(loc) { + return _readFile(loc, 'utf8').then(normalizeOS); +} + +function readFileRaw(loc) { + return _readFile(loc, 'binary'); +} + +function normalizeOS(body) { + return body.replace(/\r\n/g, '\n'); +} + +const cr = '\r'.charCodeAt(0); +const lf = '\n'.charCodeAt(0); + +/***/ }), +/* 6 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subscriber; }); +/* unused harmony export SafeSubscriber */ +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_isFunction__ = __webpack_require__(145); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Observer__ = __webpack_require__(392); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Subscription__ = __webpack_require__(24); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__internal_symbol_rxSubscriber__ = __webpack_require__(289); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__config__ = __webpack_require__(176); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__util_hostReportError__ = __webpack_require__(291); +/** PURE_IMPORTS_START tslib,_util_isFunction,_Observer,_Subscription,_internal_symbol_rxSubscriber,_config,_util_hostReportError PURE_IMPORTS_END */ + + + + + + + +var Subscriber = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](Subscriber, _super); + function Subscriber(destinationOrNext, error, complete) { + var _this = _super.call(this) || this; + _this.syncErrorValue = null; + _this.syncErrorThrown = false; + _this.syncErrorThrowable = false; + _this.isStopped = false; + _this._parentSubscription = null; + switch (arguments.length) { + case 0: + _this.destination = __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]; + break; + case 1: + if (!destinationOrNext) { + _this.destination = __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]; + break; + } + if (typeof destinationOrNext === 'object') { + if (destinationOrNext instanceof Subscriber) { + _this.syncErrorThrowable = destinationOrNext.syncErrorThrowable; + _this.destination = destinationOrNext; + destinationOrNext.add(_this); + } + else { + _this.syncErrorThrowable = true; + _this.destination = new SafeSubscriber(_this, destinationOrNext); + } + break; + } + default: + _this.syncErrorThrowable = true; + _this.destination = new SafeSubscriber(_this, destinationOrNext, error, complete); + break; + } + return _this; + } + Subscriber.prototype[__WEBPACK_IMPORTED_MODULE_4__internal_symbol_rxSubscriber__["a" /* rxSubscriber */]] = function () { return this; }; + Subscriber.create = function (next, error, complete) { + var subscriber = new Subscriber(next, error, complete); + subscriber.syncErrorThrowable = false; + return subscriber; + }; + Subscriber.prototype.next = function (value) { + if (!this.isStopped) { + this._next(value); + } + }; + Subscriber.prototype.error = function (err) { + if (!this.isStopped) { + this.isStopped = true; + this._error(err); + } + }; + Subscriber.prototype.complete = function () { + if (!this.isStopped) { + this.isStopped = true; + this._complete(); + } + }; + Subscriber.prototype.unsubscribe = function () { + if (this.closed) { + return; + } + this.isStopped = true; + _super.prototype.unsubscribe.call(this); + }; + Subscriber.prototype._next = function (value) { + this.destination.next(value); + }; + Subscriber.prototype._error = function (err) { + this.destination.error(err); + this.unsubscribe(); + }; + Subscriber.prototype._complete = function () { + this.destination.complete(); + this.unsubscribe(); + }; + Subscriber.prototype._unsubscribeAndRecycle = function () { + var _a = this, _parent = _a._parent, _parents = _a._parents; + this._parent = null; + this._parents = null; + this.unsubscribe(); + this.closed = false; + this.isStopped = false; + this._parent = _parent; + this._parents = _parents; + this._parentSubscription = null; + return this; + }; + return Subscriber; +}(__WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */])); + +var SafeSubscriber = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](SafeSubscriber, _super); + function SafeSubscriber(_parentSubscriber, observerOrNext, error, complete) { + var _this = _super.call(this) || this; + _this._parentSubscriber = _parentSubscriber; + var next; + var context = _this; + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isFunction__["a" /* isFunction */])(observerOrNext)) { + next = observerOrNext; + } + else if (observerOrNext) { + next = observerOrNext.next; + error = observerOrNext.error; + complete = observerOrNext.complete; + if (observerOrNext !== __WEBPACK_IMPORTED_MODULE_2__Observer__["a" /* empty */]) { + context = Object.create(observerOrNext); + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isFunction__["a" /* isFunction */])(context.unsubscribe)) { + _this.add(context.unsubscribe.bind(context)); + } + context.unsubscribe = _this.unsubscribe.bind(_this); + } + } + _this._context = context; + _this._next = next; + _this._error = error; + _this._complete = complete; + return _this; + } + SafeSubscriber.prototype.next = function (value) { + if (!this.isStopped && this._next) { + var _parentSubscriber = this._parentSubscriber; + if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(this._next, value); + } + else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) { + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.error = function (err) { + if (!this.isStopped) { + var _parentSubscriber = this._parentSubscriber; + var useDeprecatedSynchronousErrorHandling = __WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling; + if (this._error) { + if (!useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(this._error, err); + this.unsubscribe(); + } + else { + this.__tryOrSetError(_parentSubscriber, this._error, err); + this.unsubscribe(); + } + } + else if (!_parentSubscriber.syncErrorThrowable) { + this.unsubscribe(); + if (useDeprecatedSynchronousErrorHandling) { + throw err; + } + __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); + } + else { + if (useDeprecatedSynchronousErrorHandling) { + _parentSubscriber.syncErrorValue = err; + _parentSubscriber.syncErrorThrown = true; + } + else { + __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); + } + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.complete = function () { + var _this = this; + if (!this.isStopped) { + var _parentSubscriber = this._parentSubscriber; + if (this._complete) { + var wrappedComplete = function () { return _this._complete.call(_this._context); }; + if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) { + this.__tryOrUnsub(wrappedComplete); + this.unsubscribe(); + } + else { + this.__tryOrSetError(_parentSubscriber, wrappedComplete); + this.unsubscribe(); + } + } + else { + this.unsubscribe(); + } + } + }; + SafeSubscriber.prototype.__tryOrUnsub = function (fn, value) { + try { + fn.call(this._context, value); + } + catch (err) { + this.unsubscribe(); + if (__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + throw err; + } + else { + __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); + } + } + }; + SafeSubscriber.prototype.__tryOrSetError = function (parent, fn, value) { + if (!__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + throw new Error('bad call'); + } + try { + fn.call(this._context, value); + } + catch (err) { + if (__WEBPACK_IMPORTED_MODULE_5__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + parent.syncErrorValue = err; + parent.syncErrorThrown = true; + return true; + } + else { + __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_6__util_hostReportError__["a" /* hostReportError */])(err); + return true; + } + } + return false; + }; + SafeSubscriber.prototype._unsubscribe = function () { + var _parentSubscriber = this._parentSubscriber; + this._context = null; + this._parentSubscriber = null; + _parentSubscriber.unsubscribe(); + }; + return SafeSubscriber; +}(Subscriber)); + +//# sourceMappingURL=Subscriber.js.map + + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +class MessageError extends Error { + constructor(msg, code) { + super(msg); + this.code = code; + } + +} + +exports.MessageError = MessageError; +class ProcessSpawnError extends MessageError { + constructor(msg, code, process) { + super(msg, code); + this.process = process; + } + +} + +exports.ProcessSpawnError = ProcessSpawnError; +class SecurityError extends MessageError {} + +exports.SecurityError = SecurityError; +class ProcessTermError extends MessageError {} + +exports.ProcessTermError = ProcessTermError; +class ResponseError extends Error { + constructor(msg, responseCode) { + super(msg); + this.responseCode = responseCode; + } + +} + +exports.ResponseError = ResponseError; +class OneTimePasswordError extends Error {} +exports.OneTimePasswordError = OneTimePasswordError; + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + + +/** + * 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 NODE_ENV = process.env.NODE_ENV; + +var invariant = function(condition, format, a, b, c, d, e, f) { + if (NODE_ENV !== 'production') { + if (format === undefined) { + throw new Error('invariant requires an error message argument'); + } + } + + 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; + + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getPathKey = getPathKey; +const os = __webpack_require__(46); +const path = __webpack_require__(0); +const userHome = __webpack_require__(61).default; + +var _require = __webpack_require__(214); + +const getCacheDir = _require.getCacheDir, + getConfigDir = _require.getConfigDir, + getDataDir = _require.getDataDir; + +const isWebpackBundle = __webpack_require__(268); + +const DEPENDENCY_TYPES = exports.DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'optionalDependencies', 'peerDependencies']; +const OWNED_DEPENDENCY_TYPES = exports.OWNED_DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'optionalDependencies']; + +const RESOLUTIONS = exports.RESOLUTIONS = 'resolutions'; +const MANIFEST_FIELDS = exports.MANIFEST_FIELDS = [RESOLUTIONS, ...DEPENDENCY_TYPES]; + +const SUPPORTED_NODE_VERSIONS = exports.SUPPORTED_NODE_VERSIONS = '^4.8.0 || ^5.7.0 || ^6.2.2 || >=8.0.0'; + +const YARN_REGISTRY = exports.YARN_REGISTRY = 'https://registry.yarnpkg.com'; +const NPM_REGISTRY_RE = exports.NPM_REGISTRY_RE = /https?:\/\/registry\.npmjs\.org/g; + +const YARN_DOCS = exports.YARN_DOCS = 'https://yarnpkg.com/en/docs/cli/'; +const YARN_INSTALLER_SH = exports.YARN_INSTALLER_SH = 'https://yarnpkg.com/install.sh'; +const YARN_INSTALLER_MSI = exports.YARN_INSTALLER_MSI = 'https://yarnpkg.com/latest.msi'; + +const SELF_UPDATE_VERSION_URL = exports.SELF_UPDATE_VERSION_URL = 'https://yarnpkg.com/latest-version'; + +// cache version, bump whenever we make backwards incompatible changes +const CACHE_VERSION = exports.CACHE_VERSION = 4; + +// lockfile version, bump whenever we make backwards incompatible changes +const LOCKFILE_VERSION = exports.LOCKFILE_VERSION = 1; + +// max amount of network requests to perform concurrently +const NETWORK_CONCURRENCY = exports.NETWORK_CONCURRENCY = 8; + +// HTTP timeout used when downloading packages +const NETWORK_TIMEOUT = exports.NETWORK_TIMEOUT = 30 * 1000; // in milliseconds + +// max amount of child processes to execute concurrently +const CHILD_CONCURRENCY = exports.CHILD_CONCURRENCY = 5; + +const REQUIRED_PACKAGE_KEYS = exports.REQUIRED_PACKAGE_KEYS = ['name', 'version', '_uid']; + +function getPreferredCacheDirectories() { + const preferredCacheDirectories = [getCacheDir()]; + + if (process.getuid) { + // $FlowFixMe: process.getuid exists, dammit + preferredCacheDirectories.push(path.join(os.tmpdir(), `.yarn-cache-${process.getuid()}`)); + } + + preferredCacheDirectories.push(path.join(os.tmpdir(), `.yarn-cache`)); + + return preferredCacheDirectories; +} + +const PREFERRED_MODULE_CACHE_DIRECTORIES = exports.PREFERRED_MODULE_CACHE_DIRECTORIES = getPreferredCacheDirectories(); +const CONFIG_DIRECTORY = exports.CONFIG_DIRECTORY = getConfigDir(); +const DATA_DIRECTORY = exports.DATA_DIRECTORY = getDataDir(); +const LINK_REGISTRY_DIRECTORY = exports.LINK_REGISTRY_DIRECTORY = path.join(DATA_DIRECTORY, 'link'); +const GLOBAL_MODULE_DIRECTORY = exports.GLOBAL_MODULE_DIRECTORY = path.join(DATA_DIRECTORY, 'global'); + +const NODE_BIN_PATH = exports.NODE_BIN_PATH = process.execPath; +const YARN_BIN_PATH = exports.YARN_BIN_PATH = getYarnBinPath(); + +// Webpack needs to be configured with node.__dirname/__filename = false +function getYarnBinPath() { + if (isWebpackBundle) { + return __filename; + } else { + return path.join(__dirname, '..', 'bin', 'yarn.js'); + } +} + +const NODE_MODULES_FOLDER = exports.NODE_MODULES_FOLDER = 'node_modules'; +const NODE_PACKAGE_JSON = exports.NODE_PACKAGE_JSON = 'package.json'; + +const PNP_FILENAME = exports.PNP_FILENAME = '.pnp.js'; + +const POSIX_GLOBAL_PREFIX = exports.POSIX_GLOBAL_PREFIX = `${process.env.DESTDIR || ''}/usr/local`; +const FALLBACK_GLOBAL_PREFIX = exports.FALLBACK_GLOBAL_PREFIX = path.join(userHome, '.yarn'); + +const META_FOLDER = exports.META_FOLDER = '.yarn-meta'; +const INTEGRITY_FILENAME = exports.INTEGRITY_FILENAME = '.yarn-integrity'; +const LOCKFILE_FILENAME = exports.LOCKFILE_FILENAME = 'yarn.lock'; +const METADATA_FILENAME = exports.METADATA_FILENAME = '.yarn-metadata.json'; +const TARBALL_FILENAME = exports.TARBALL_FILENAME = '.yarn-tarball.tgz'; +const CLEAN_FILENAME = exports.CLEAN_FILENAME = '.yarnclean'; + +const NPM_LOCK_FILENAME = exports.NPM_LOCK_FILENAME = 'package-lock.json'; +const NPM_SHRINKWRAP_FILENAME = exports.NPM_SHRINKWRAP_FILENAME = 'npm-shrinkwrap.json'; + +const DEFAULT_INDENT = exports.DEFAULT_INDENT = ' '; +const SINGLE_INSTANCE_PORT = exports.SINGLE_INSTANCE_PORT = 31997; +const SINGLE_INSTANCE_FILENAME = exports.SINGLE_INSTANCE_FILENAME = '.yarn-single-instance'; + +const ENV_PATH_KEY = exports.ENV_PATH_KEY = getPathKey(process.platform, process.env); + +function getPathKey(platform, env) { + let pathKey = 'PATH'; + + // windows calls its path "Path" usually, but this is not guaranteed. + if (platform === 'win32') { + pathKey = 'Path'; + + for (const key in env) { + if (key.toLowerCase() === 'path') { + pathKey = key; + } + } + } + + return pathKey; +} + +const VERSION_COLOR_SCHEME = exports.VERSION_COLOR_SCHEME = { + major: 'red', + premajor: 'red', + minor: 'yellow', + preminor: 'yellow', + patch: 'green', + prepatch: 'green', + prerelease: 'red', + unchanged: 'white', + unknown: 'red' +}; + +/***/ }), +/* 10 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Observable; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__util_canReportError__ = __webpack_require__(290); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_toSubscriber__ = __webpack_require__(902); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__internal_symbol_observable__ = __webpack_require__(109); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_pipe__ = __webpack_require__(292); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__config__ = __webpack_require__(176); +/** PURE_IMPORTS_START _util_canReportError,_util_toSubscriber,_internal_symbol_observable,_util_pipe,_config PURE_IMPORTS_END */ + + + + + +var Observable = /*@__PURE__*/ (function () { + function Observable(subscribe) { + this._isScalar = false; + if (subscribe) { + this._subscribe = subscribe; + } + } + Observable.prototype.lift = function (operator) { + var observable = new Observable(); + observable.source = this; + observable.operator = operator; + return observable; + }; + Observable.prototype.subscribe = function (observerOrNext, error, complete) { + var operator = this.operator; + var sink = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_toSubscriber__["a" /* toSubscriber */])(observerOrNext, error, complete); + if (operator) { + operator.call(sink, this.source); + } + else { + sink.add(this.source || (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ? + this._subscribe(sink) : + this._trySubscribe(sink)); + } + if (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + if (sink.syncErrorThrowable) { + sink.syncErrorThrowable = false; + if (sink.syncErrorThrown) { + throw sink.syncErrorValue; + } + } + } + return sink; + }; + Observable.prototype._trySubscribe = function (sink) { + try { + return this._subscribe(sink); + } + catch (err) { + if (__WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].useDeprecatedSynchronousErrorHandling) { + sink.syncErrorThrown = true; + sink.syncErrorValue = err; + } + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__util_canReportError__["a" /* canReportError */])(sink)) { + sink.error(err); + } + else { + console.warn(err); + } + } + }; + Observable.prototype.forEach = function (next, promiseCtor) { + var _this = this; + promiseCtor = getPromiseCtor(promiseCtor); + return new promiseCtor(function (resolve, reject) { + var subscription; + subscription = _this.subscribe(function (value) { + try { + next(value); + } + catch (err) { + reject(err); + if (subscription) { + subscription.unsubscribe(); + } + } + }, reject, resolve); + }); + }; + Observable.prototype._subscribe = function (subscriber) { + var source = this.source; + return source && source.subscribe(subscriber); + }; + Observable.prototype[__WEBPACK_IMPORTED_MODULE_2__internal_symbol_observable__["a" /* observable */]] = function () { + return this; + }; + Observable.prototype.pipe = function () { + var operations = []; + for (var _i = 0; _i < arguments.length; _i++) { + operations[_i] = arguments[_i]; + } + if (operations.length === 0) { + return this; + } + return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_pipe__["b" /* pipeFromArray */])(operations)(this); + }; + Observable.prototype.toPromise = function (promiseCtor) { + var _this = this; + promiseCtor = getPromiseCtor(promiseCtor); + return new promiseCtor(function (resolve, reject) { + var value; + _this.subscribe(function (x) { return value = x; }, function (err) { return reject(err); }, function () { return resolve(value); }); + }); + }; + Observable.create = function (subscribe) { + return new Observable(subscribe); + }; + return Observable; +}()); + +function getPromiseCtor(promiseCtor) { + if (!promiseCtor) { + promiseCtor = __WEBPACK_IMPORTED_MODULE_4__config__["a" /* config */].Promise || Promise; + } + if (!promiseCtor) { + throw new Error('no Promise impl found'); + } + return promiseCtor; +} +//# sourceMappingURL=Observable.js.map + + +/***/ }), +/* 11 */ +/***/ (function(module, exports) { + +module.exports = require("crypto"); + +/***/ }), +/* 12 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return OuterSubscriber; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Subscriber__ = __webpack_require__(6); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + + +var OuterSubscriber = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](OuterSubscriber, _super); + function OuterSubscriber() { + return _super !== null && _super.apply(this, arguments) || this; + } + OuterSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.destination.next(innerValue); + }; + OuterSubscriber.prototype.notifyError = function (error, innerSub) { + this.destination.error(error); + }; + OuterSubscriber.prototype.notifyComplete = function (innerSub) { + this.destination.complete(); + }; + return OuterSubscriber; +}(__WEBPACK_IMPORTED_MODULE_1__Subscriber__["a" /* Subscriber */])); + +//# sourceMappingURL=OuterSubscriber.js.map + + +/***/ }), +/* 13 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (immutable) */ __webpack_exports__["a"] = subscribeToResult; +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__InnerSubscriber__ = __webpack_require__(77); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__subscribeTo__ = __webpack_require__(418); +/** PURE_IMPORTS_START _InnerSubscriber,_subscribeTo PURE_IMPORTS_END */ + + +function subscribeToResult(outerSubscriber, result, outerValue, outerIndex, destination) { + if (destination === void 0) { + destination = new __WEBPACK_IMPORTED_MODULE_0__InnerSubscriber__["a" /* InnerSubscriber */](outerSubscriber, outerValue, outerIndex); + } + if (destination.closed) { + return; + } + return __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__subscribeTo__["a" /* subscribeTo */])(result)(destination); +} +//# sourceMappingURL=subscribeToResult.js.map + + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* eslint-disable node/no-deprecated-api */ + + + +var buffer = __webpack_require__(80) +var Buffer = buffer.Buffer + +var safer = {} + +var key + +for (key in buffer) { + if (!buffer.hasOwnProperty(key)) continue + if (key === 'SlowBuffer' || key === 'Buffer') continue + safer[key] = buffer[key] +} + +var Safer = safer.Buffer = {} +for (key in Buffer) { + if (!Buffer.hasOwnProperty(key)) continue + if (key === 'allocUnsafe' || key === 'allocUnsafeSlow') continue + Safer[key] = Buffer[key] +} + +safer.Buffer.prototype = Buffer.prototype + +if (!Safer.from || Safer.from === Uint8Array.from) { + Safer.from = function (value, encodingOrOffset, length) { + if (typeof value === 'number') { + throw new TypeError('The "value" argument must not be of type number. Received type ' + typeof value) + } + if (value && typeof value.length === 'undefined') { + throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type ' + typeof value) + } + return Buffer(value, encodingOrOffset, length) + } +} + +if (!Safer.alloc) { + Safer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('The "size" argument must be of type number. Received type ' + typeof size) + } + if (size < 0 || size >= 2 * (1 << 30)) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') + } + var buf = Buffer(size) + if (!fill || fill.length === 0) { + buf.fill(0) + } else if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + return buf + } +} + +if (!safer.kStringMaxLength) { + try { + safer.kStringMaxLength = process.binding('buffer').kStringMaxLength + } catch (e) { + // we can't determine kStringMaxLength in environments where process.binding + // is unsupported, so let's not set it + } +} + +if (!safer.constants) { + safer.constants = { + MAX_LENGTH: safer.kMaxLength + } + if (safer.kStringMaxLength) { + safer.constants.MAX_STRING_LENGTH = safer.kStringMaxLength + } +} + +module.exports = safer + + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright (c) 2012, Mark Cavage. All rights reserved. +// Copyright 2015 Joyent, Inc. + +var assert = __webpack_require__(27); +var Stream = __webpack_require__(22).Stream; +var util = __webpack_require__(3); + + +///--- Globals + +/* JSSTYLED */ +var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/; + + +///--- Internal + +function _capitalize(str) { + return (str.charAt(0).toUpperCase() + str.slice(1)); +} + +function _toss(name, expected, oper, arg, actual) { + throw new assert.AssertionError({ + message: util.format('%s (%s) is required', name, expected), + actual: (actual === undefined) ? typeof (arg) : actual(arg), + expected: expected, + operator: oper || '===', + stackStartFunction: _toss.caller + }); +} + +function _getClass(arg) { + return (Object.prototype.toString.call(arg).slice(8, -1)); +} + +function noop() { + // Why even bother with asserts? +} + + +///--- Exports + +var types = { + bool: { + check: function (arg) { return typeof (arg) === 'boolean'; } + }, + func: { + check: function (arg) { return typeof (arg) === 'function'; } + }, + string: { + check: function (arg) { return typeof (arg) === 'string'; } + }, + object: { + check: function (arg) { + return typeof (arg) === 'object' && arg !== null; + } + }, + number: { + check: function (arg) { + return typeof (arg) === 'number' && !isNaN(arg); + } + }, + finite: { + check: function (arg) { + return typeof (arg) === 'number' && !isNaN(arg) && isFinite(arg); + } + }, + buffer: { + check: function (arg) { return Buffer.isBuffer(arg); }, + operator: 'Buffer.isBuffer' + }, + array: { + check: function (arg) { return Array.isArray(arg); }, + operator: 'Array.isArray' + }, + stream: { + check: function (arg) { return arg instanceof Stream; }, + operator: 'instanceof', + actual: _getClass + }, + date: { + check: function (arg) { return arg instanceof Date; }, + operator: 'instanceof', + actual: _getClass + }, + regexp: { + check: function (arg) { return arg instanceof RegExp; }, + operator: 'instanceof', + actual: _getClass + }, + uuid: { + check: function (arg) { + return typeof (arg) === 'string' && UUID_REGEXP.test(arg); + }, + operator: 'isUUID' + } +}; + +function _setExports(ndebug) { + var keys = Object.keys(types); + var out; + + /* re-export standard assert */ + if (process.env.NODE_NDEBUG) { + out = noop; + } else { + out = function (arg, msg) { + if (!arg) { + _toss(msg, 'true', arg); + } + }; + } + + /* standard checks */ + keys.forEach(function (k) { + if (ndebug) { + out[k] = noop; + return; + } + var type = types[k]; + out[k] = function (arg, msg) { + if (!type.check(arg)) { + _toss(msg, k, type.operator, arg, type.actual); + } + }; + }); + + /* optional checks */ + keys.forEach(function (k) { + var name = 'optional' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + out[name] = function (arg, msg) { + if (arg === undefined || arg === null) { + return; + } + if (!type.check(arg)) { + _toss(msg, k, type.operator, arg, type.actual); + } + }; + }); + + /* arrayOf checks */ + keys.forEach(function (k) { + var name = 'arrayOf' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + var expected = '[' + k + ']'; + out[name] = function (arg, msg) { + if (!Array.isArray(arg)) { + _toss(msg, expected, type.operator, arg, type.actual); + } + var i; + for (i = 0; i < arg.length; i++) { + if (!type.check(arg[i])) { + _toss(msg, expected, type.operator, arg, type.actual); + } + } + }; + }); + + /* optionalArrayOf checks */ + keys.forEach(function (k) { + var name = 'optionalArrayOf' + _capitalize(k); + if (ndebug) { + out[name] = noop; + return; + } + var type = types[k]; + var expected = '[' + k + ']'; + out[name] = function (arg, msg) { + if (arg === undefined || arg === null) { + return; + } + if (!Array.isArray(arg)) { + _toss(msg, expected, type.operator, arg, type.actual); + } + var i; + for (i = 0; i < arg.length; i++) { + if (!type.check(arg[i])) { + _toss(msg, expected, type.operator, arg, type.actual); + } + } + }; + }); + + /* re-export built-in assertions */ + Object.keys(assert).forEach(function (k) { + if (k === 'AssertionError') { + out[k] = assert[k]; + return; + } + if (ndebug) { + out[k] = noop; + return; + } + out[k] = assert[k]; + }); + + /* export ourselves (for unit tests _only_) */ + out._setExports = _setExports; + + return out; +} + +module.exports = _setExports(process.env.NODE_NDEBUG); + + +/***/ }), +/* 16 */ +/***/ (function(module, exports) { + +// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 +var global = module.exports = typeof window != 'undefined' && window.Math == Math + ? window : typeof self != 'undefined' && self.Math == Math ? self + // eslint-disable-next-line no-new-func + : Function('return this')(); +if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef + + +/***/ }), +/* 17 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.sortAlpha = sortAlpha; +exports.sortOptionsByFlags = sortOptionsByFlags; +exports.entries = entries; +exports.removePrefix = removePrefix; +exports.removeSuffix = removeSuffix; +exports.addSuffix = addSuffix; +exports.hyphenate = hyphenate; +exports.camelCase = camelCase; +exports.compareSortedArrays = compareSortedArrays; +exports.sleep = sleep; +const _camelCase = __webpack_require__(219); + +function sortAlpha(a, b) { + // sort alphabetically in a deterministic way + const shortLen = Math.min(a.length, b.length); + for (let i = 0; i < shortLen; i++) { + const aChar = a.charCodeAt(i); + const bChar = b.charCodeAt(i); + if (aChar !== bChar) { + return aChar - bChar; + } + } + return a.length - b.length; +} + +function sortOptionsByFlags(a, b) { + const aOpt = a.flags.replace(/-/g, ''); + const bOpt = b.flags.replace(/-/g, ''); + return sortAlpha(aOpt, bOpt); +} + +function entries(obj) { + const entries = []; + if (obj) { + for (const key in obj) { + entries.push([key, obj[key]]); + } + } + return entries; +} + +function removePrefix(pattern, prefix) { + if (pattern.startsWith(prefix)) { + pattern = pattern.slice(prefix.length); + } + + return pattern; +} + +function removeSuffix(pattern, suffix) { + if (pattern.endsWith(suffix)) { + return pattern.slice(0, -suffix.length); + } + + return pattern; +} + +function addSuffix(pattern, suffix) { + if (!pattern.endsWith(suffix)) { + return pattern + suffix; + } + + return pattern; +} + +function hyphenate(str) { + return str.replace(/[A-Z]/g, match => { + return '-' + match.charAt(0).toLowerCase(); + }); +} + +function camelCase(str) { + if (/[A-Z]/.test(str)) { + return null; + } else { + return _camelCase(str); + } +} + +function compareSortedArrays(array1, array2) { + if (array1.length !== array2.length) { + return false; + } + for (let i = 0, len = array1.length; i < len; i++) { + if (array1[i] !== array2[i]) { + return false; + } + } + return true; +} + +function sleep(ms) { + return new Promise(resolve => { + setTimeout(resolve, ms); + }); +} + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.stringify = exports.parse = undefined; + +var _asyncToGenerator2; + +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} + +var _parse; + +function _load_parse() { + return _parse = __webpack_require__(98); +} + +Object.defineProperty(exports, 'parse', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_parse || _load_parse()).default; + } +}); + +var _stringify; + +function _load_stringify() { + return _stringify = __webpack_require__(190); +} + +Object.defineProperty(exports, 'stringify', { + enumerable: true, + get: function get() { + return _interopRequireDefault(_stringify || _load_stringify()).default; + } +}); +exports.implodeEntry = implodeEntry; +exports.explodeEntry = explodeEntry; + +var _misc; + +function _load_misc() { + return _misc = __webpack_require__(17); +} + +var _normalizePattern; + +function _load_normalizePattern() { + return _normalizePattern = __webpack_require__(36); +} + +var _parse2; + +function _load_parse2() { + return _parse2 = _interopRequireDefault(__webpack_require__(98)); +} + +var _constants; + +function _load_constants() { + return _constants = __webpack_require__(9); +} + +var _fs; + +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(5)); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const invariant = __webpack_require__(8); + +const path = __webpack_require__(0); +const ssri = __webpack_require__(71); + +function getName(pattern) { + return (0, (_normalizePattern || _load_normalizePattern()).normalizePattern)(pattern).name; +} + +function blankObjectUndefined(obj) { + return obj && Object.keys(obj).length ? obj : undefined; +} + +function keyForRemote(remote) { + return remote.resolved || (remote.reference && remote.hash ? `${remote.reference}#${remote.hash}` : null); +} + +function serializeIntegrity(integrity) { + // We need this because `Integrity.toString()` does not use sorting to ensure a stable string output + // See https://git.io/vx2Hy + return integrity.toString().split(' ').sort().join(' '); +} + +function implodeEntry(pattern, obj) { + const inferredName = getName(pattern); + const integrity = obj.integrity ? serializeIntegrity(obj.integrity) : ''; + const imploded = { + name: inferredName === obj.name ? undefined : obj.name, + version: obj.version, + uid: obj.uid === obj.version ? undefined : obj.uid, + resolved: obj.resolved, + registry: obj.registry === 'npm' ? undefined : obj.registry, + dependencies: blankObjectUndefined(obj.dependencies), + optionalDependencies: blankObjectUndefined(obj.optionalDependencies), + permissions: blankObjectUndefined(obj.permissions), + prebuiltVariants: blankObjectUndefined(obj.prebuiltVariants) + }; + if (integrity) { + imploded.integrity = integrity; + } + return imploded; +} + +function explodeEntry(pattern, obj) { + obj.optionalDependencies = obj.optionalDependencies || {}; + obj.dependencies = obj.dependencies || {}; + obj.uid = obj.uid || obj.version; + obj.permissions = obj.permissions || {}; + obj.registry = obj.registry || 'npm'; + obj.name = obj.name || getName(pattern); + const integrity = obj.integrity; + if (integrity && integrity.isIntegrity) { + obj.integrity = ssri.parse(integrity); + } + return obj; +} + +class Lockfile { + constructor({ cache, source, parseResultType } = {}) { + this.source = source || ''; + this.cache = cache; + this.parseResultType = parseResultType; + } + + // source string if the `cache` was parsed + + + // if true, we're parsing an old yarn file and need to update integrity fields + hasEntriesExistWithoutIntegrity() { + if (!this.cache) { + return false; + } + + for (const key in this.cache) { + // $FlowFixMe - `this.cache` is clearly defined at this point + if (!/^.*@(file:|http)/.test(key) && this.cache[key] && !this.cache[key].integrity) { + return true; + } + } + + return false; + } + + static fromDirectory(dir, reporter) { + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + // read the manifest in this directory + const lockfileLoc = path.join(dir, (_constants || _load_constants()).LOCKFILE_FILENAME); + + let lockfile; + let rawLockfile = ''; + let parseResult; + + if (yield (_fs || _load_fs()).exists(lockfileLoc)) { + rawLockfile = yield (_fs || _load_fs()).readFile(lockfileLoc); + parseResult = (0, (_parse2 || _load_parse2()).default)(rawLockfile, lockfileLoc); + + if (reporter) { + if (parseResult.type === 'merge') { + reporter.info(reporter.lang('lockfileMerged')); + } else if (parseResult.type === 'conflict') { + reporter.warn(reporter.lang('lockfileConflict')); + } + } + + lockfile = parseResult.object; + } else if (reporter) { + reporter.info(reporter.lang('noLockfileFound')); + } + + return new Lockfile({ cache: lockfile, source: rawLockfile, parseResultType: parseResult && parseResult.type }); + })(); + } + + getLocked(pattern) { + const cache = this.cache; + if (!cache) { + return undefined; + } + + const shrunk = pattern in cache && cache[pattern]; + + if (typeof shrunk === 'string') { + return this.getLocked(shrunk); + } else if (shrunk) { + explodeEntry(pattern, shrunk); + return shrunk; + } + + return undefined; + } + + removePattern(pattern) { + const cache = this.cache; + if (!cache) { + return; + } + delete cache[pattern]; + } + + getLockfile(patterns) { + const lockfile = {}; + const seen = new Map(); + + // order by name so that lockfile manifest is assigned to the first dependency with this manifest + // the others that have the same remoteKey will just refer to the first + // ordering allows for consistency in lockfile when it is serialized + const sortedPatternsKeys = Object.keys(patterns).sort((_misc || _load_misc()).sortAlpha); + + for (var _iterator = sortedPatternsKeys, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref = _i.value; + } + + const pattern = _ref; + + const pkg = patterns[pattern]; + const remote = pkg._remote, + ref = pkg._reference; + + invariant(ref, 'Package is missing a reference'); + invariant(remote, 'Package is missing a remote'); + + const remoteKey = keyForRemote(remote); + const seenPattern = remoteKey && seen.get(remoteKey); + if (seenPattern) { + // no point in duplicating it + lockfile[pattern] = seenPattern; + + // if we're relying on our name being inferred and two of the patterns have + // different inferred names then we need to set it + if (!seenPattern.name && getName(pattern) !== pkg.name) { + seenPattern.name = pkg.name; + } + continue; + } + const obj = implodeEntry(pattern, { + name: pkg.name, + version: pkg.version, + uid: pkg._uid, + resolved: remote.resolved, + integrity: remote.integrity, + registry: remote.registry, + dependencies: pkg.dependencies, + peerDependencies: pkg.peerDependencies, + optionalDependencies: pkg.optionalDependencies, + permissions: ref.permissions, + prebuiltVariants: pkg.prebuiltVariants + }); + + lockfile[pattern] = obj; + + if (remoteKey) { + seen.set(remoteKey, obj); + } + } + + return lockfile; + } +} +exports.default = Lockfile; + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +var store = __webpack_require__(126)('wks'); +var uid = __webpack_require__(130); +var Symbol = __webpack_require__(16).Symbol; +var USE_SYMBOL = typeof Symbol == 'function'; + +var $exports = module.exports = function (name) { + return store[name] || (store[name] = + USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name)); +}; + +$exports.store = store; + + +/***/ }), +/* 20 */ +/***/ (function(module, exports) { + +exports = module.exports = SemVer; + +// The debug function is excluded entirely from the minified version. +/* nomin */ var debug; +/* nomin */ if (typeof process === 'object' && + /* nomin */ process.env && + /* nomin */ process.env.NODE_DEBUG && + /* nomin */ /\bsemver\b/i.test(process.env.NODE_DEBUG)) + /* nomin */ debug = function() { + /* nomin */ var args = Array.prototype.slice.call(arguments, 0); + /* nomin */ args.unshift('SEMVER'); + /* nomin */ console.log.apply(console, args); + /* nomin */ }; +/* nomin */ else + /* nomin */ debug = function() {}; + +// Note: this is the semver.org version of the spec that it implements +// Not necessarily the package version of this code. +exports.SEMVER_SPEC_VERSION = '2.0.0'; + +var MAX_LENGTH = 256; +var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; + +// Max safe segment length for coercion. +var MAX_SAFE_COMPONENT_LENGTH = 16; + +// The actual regexps go on exports.re +var re = exports.re = []; +var src = exports.src = []; +var R = 0; + +// The following Regular Expressions can be used for tokenizing, +// validating, and parsing SemVer version strings. + +// ## Numeric Identifier +// A single `0`, or a non-zero digit followed by zero or more digits. + +var NUMERICIDENTIFIER = R++; +src[NUMERICIDENTIFIER] = '0|[1-9]\\d*'; +var NUMERICIDENTIFIERLOOSE = R++; +src[NUMERICIDENTIFIERLOOSE] = '[0-9]+'; + + +// ## Non-numeric Identifier +// Zero or more digits, followed by a letter or hyphen, and then zero or +// more letters, digits, or hyphens. + +var NONNUMERICIDENTIFIER = R++; +src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*'; + + +// ## Main Version +// Three dot-separated numeric identifiers. + +var MAINVERSION = R++; +src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' + + '(' + src[NUMERICIDENTIFIER] + ')\\.' + + '(' + src[NUMERICIDENTIFIER] + ')'; + +var MAINVERSIONLOOSE = R++; +src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[NUMERICIDENTIFIERLOOSE] + ')'; + +// ## Pre-release Version Identifier +// A numeric identifier, or a non-numeric identifier. + +var PRERELEASEIDENTIFIER = R++; +src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] + + '|' + src[NONNUMERICIDENTIFIER] + ')'; + +var PRERELEASEIDENTIFIERLOOSE = R++; +src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] + + '|' + src[NONNUMERICIDENTIFIER] + ')'; + + +// ## Pre-release Version +// Hyphen, followed by one or more dot-separated pre-release version +// identifiers. + +var PRERELEASE = R++; +src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] + + '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))'; + +var PRERELEASELOOSE = R++; +src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] + + '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))'; + +// ## Build Metadata Identifier +// Any combination of digits, letters, or hyphens. + +var BUILDIDENTIFIER = R++; +src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+'; + +// ## Build Metadata +// Plus sign, followed by one or more period-separated build metadata +// identifiers. + +var BUILD = R++; +src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + + '(?:\\.' + src[BUILDIDENTIFIER] + ')*))'; + + +// ## Full Version String +// A main version, followed optionally by a pre-release version and +// build metadata. + +// Note that the only major, minor, patch, and pre-release sections of +// the version string are capturing groups. The build metadata is not a +// capturing group, because it should not ever be used in version +// comparison. + +var FULL = R++; +var FULLPLAIN = 'v?' + src[MAINVERSION] + + src[PRERELEASE] + '?' + + src[BUILD] + '?'; + +src[FULL] = '^' + FULLPLAIN + '$'; + +// like full, but allows v1.2.3 and =1.2.3, which people do sometimes. +// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty +// common in the npm registry. +var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] + + src[PRERELEASELOOSE] + '?' + + src[BUILD] + '?'; + +var LOOSE = R++; +src[LOOSE] = '^' + LOOSEPLAIN + '$'; + +var GTLT = R++; +src[GTLT] = '((?:<|>)?=?)'; + +// Something like "2.*" or "1.2.x". +// Note that "x.x" is a valid xRange identifer, meaning "any version" +// Only the first item is strictly required. +var XRANGEIDENTIFIERLOOSE = R++; +src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*'; +var XRANGEIDENTIFIER = R++; +src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*'; + +var XRANGEPLAIN = R++; +src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + + '(?:' + src[PRERELEASE] + ')?' + + src[BUILD] + '?' + + ')?)?'; + +var XRANGEPLAINLOOSE = R++; +src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:' + src[PRERELEASELOOSE] + ')?' + + src[BUILD] + '?' + + ')?)?'; + +var XRANGE = R++; +src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$'; +var XRANGELOOSE = R++; +src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$'; + +// Coercion. +// Extract anything that could conceivably be a part of a valid semver +var COERCE = R++; +src[COERCE] = '(?:^|[^\\d])' + + '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:$|[^\\d])'; + +// Tilde ranges. +// Meaning is "reasonably at or greater than" +var LONETILDE = R++; +src[LONETILDE] = '(?:~>?)'; + +var TILDETRIM = R++; +src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+'; +re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g'); +var tildeTrimReplace = '$1~'; + +var TILDE = R++; +src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$'; +var TILDELOOSE = R++; +src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$'; + +// Caret ranges. +// Meaning is "at least and backwards compatible with" +var LONECARET = R++; +src[LONECARET] = '(?:\\^)'; + +var CARETTRIM = R++; +src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+'; +re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g'); +var caretTrimReplace = '$1^'; + +var CARET = R++; +src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$'; +var CARETLOOSE = R++; +src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$'; + +// A simple gt/lt/eq thing, or just "" to indicate "any version" +var COMPARATORLOOSE = R++; +src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$'; +var COMPARATOR = R++; +src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$'; + + +// An expression to strip any whitespace between the gtlt and the thing +// it modifies, so that `> 1.2.3` ==> `>1.2.3` +var COMPARATORTRIM = R++; +src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] + + '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')'; + +// this one has to use the /g flag +re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g'); +var comparatorTrimReplace = '$1$2$3'; + + +// Something like `1.2.3 - 1.2.4` +// Note that these all use the loose form, because they'll be +// checked against either the strict or loose comparator form +// later. +var HYPHENRANGE = R++; +src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' + + '\\s+-\\s+' + + '(' + src[XRANGEPLAIN] + ')' + + '\\s*$'; + +var HYPHENRANGELOOSE = R++; +src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' + + '\\s+-\\s+' + + '(' + src[XRANGEPLAINLOOSE] + ')' + + '\\s*$'; + +// Star ranges basically just allow anything at all. +var STAR = R++; +src[STAR] = '(<|>)?=?\\s*\\*'; + +// Compile to actual regexp objects. +// All are flag-free, unless they were created above with a flag. +for (var i = 0; i < R; i++) { + debug(i, src[i]); + if (!re[i]) + re[i] = new RegExp(src[i]); +} + +exports.parse = parse; +function parse(version, loose) { + if (version instanceof SemVer) + return version; + + if (typeof version !== 'string') + return null; + + if (version.length > MAX_LENGTH) + return null; + + var r = loose ? re[LOOSE] : re[FULL]; + if (!r.test(version)) + return null; + + try { + return new SemVer(version, loose); + } catch (er) { + return null; + } +} + +exports.valid = valid; +function valid(version, loose) { + var v = parse(version, loose); + return v ? v.version : null; +} + + +exports.clean = clean; +function clean(version, loose) { + var s = parse(version.trim().replace(/^[=v]+/, ''), loose); + return s ? s.version : null; +} + +exports.SemVer = SemVer; + +function SemVer(version, loose) { + if (version instanceof SemVer) { + if (version.loose === loose) + return version; + else + version = version.version; + } else if (typeof version !== 'string') { + throw new TypeError('Invalid Version: ' + version); + } + + if (version.length > MAX_LENGTH) + throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters') + + if (!(this instanceof SemVer)) + return new SemVer(version, loose); + + debug('SemVer', version, loose); + this.loose = loose; + var m = version.trim().match(loose ? re[LOOSE] : re[FULL]); + + if (!m) + throw new TypeError('Invalid Version: ' + version); + + this.raw = version; + + // these are actually numbers + this.major = +m[1]; + this.minor = +m[2]; + this.patch = +m[3]; + + if (this.major > MAX_SAFE_INTEGER || this.major < 0) + throw new TypeError('Invalid major version') + + if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) + throw new TypeError('Invalid minor version') + + if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) + throw new TypeError('Invalid patch version') + + // numberify any prerelease numeric ids + if (!m[4]) + this.prerelease = []; + else + this.prerelease = m[4].split('.').map(function(id) { + if (/^[0-9]+$/.test(id)) { + var num = +id; + if (num >= 0 && num < MAX_SAFE_INTEGER) + return num; + } + return id; + }); + + this.build = m[5] ? m[5].split('.') : []; + this.format(); +} + +SemVer.prototype.format = function() { + this.version = this.major + '.' + this.minor + '.' + this.patch; + if (this.prerelease.length) + this.version += '-' + this.prerelease.join('.'); + return this.version; +}; + +SemVer.prototype.toString = function() { + return this.version; +}; + +SemVer.prototype.compare = function(other) { + debug('SemVer.compare', this.version, this.loose, other); + if (!(other instanceof SemVer)) + other = new SemVer(other, this.loose); + + return this.compareMain(other) || this.comparePre(other); +}; + +SemVer.prototype.compareMain = function(other) { + if (!(other instanceof SemVer)) + other = new SemVer(other, this.loose); + + return compareIdentifiers(this.major, other.major) || + compareIdentifiers(this.minor, other.minor) || + compareIdentifiers(this.patch, other.patch); +}; + +SemVer.prototype.comparePre = function(other) { + if (!(other instanceof SemVer)) + other = new SemVer(other, this.loose); + + // NOT having a prerelease is > having one + if (this.prerelease.length && !other.prerelease.length) + return -1; + else if (!this.prerelease.length && other.prerelease.length) + return 1; + else if (!this.prerelease.length && !other.prerelease.length) + return 0; + + var i = 0; + do { + var a = this.prerelease[i]; + var b = other.prerelease[i]; + debug('prerelease compare', i, a, b); + if (a === undefined && b === undefined) + return 0; + else if (b === undefined) + return 1; + else if (a === undefined) + return -1; + else if (a === b) + continue; + else + return compareIdentifiers(a, b); + } while (++i); +}; + +// preminor will bump the version up to the next minor release, and immediately +// down to pre-release. premajor and prepatch work the same way. +SemVer.prototype.inc = function(release, identifier) { + switch (release) { + case 'premajor': + this.prerelease.length = 0; + this.patch = 0; + this.minor = 0; + this.major++; + this.inc('pre', identifier); + break; + case 'preminor': + this.prerelease.length = 0; + this.patch = 0; + this.minor++; + this.inc('pre', identifier); + break; + case 'prepatch': + // If this is already a prerelease, it will bump to the next version + // drop any prereleases that might already exist, since they are not + // relevant at this point. + this.prerelease.length = 0; + this.inc('patch', identifier); + this.inc('pre', identifier); + break; + // If the input is a non-prerelease version, this acts the same as + // prepatch. + case 'prerelease': + if (this.prerelease.length === 0) + this.inc('patch', identifier); + this.inc('pre', identifier); + break; + + case 'major': + // If this is a pre-major version, bump up to the same major version. + // Otherwise increment major. + // 1.0.0-5 bumps to 1.0.0 + // 1.1.0 bumps to 2.0.0 + if (this.minor !== 0 || this.patch !== 0 || this.prerelease.length === 0) + this.major++; + this.minor = 0; + this.patch = 0; + this.prerelease = []; + break; + case 'minor': + // If this is a pre-minor version, bump up to the same minor version. + // Otherwise increment minor. + // 1.2.0-5 bumps to 1.2.0 + // 1.2.1 bumps to 1.3.0 + if (this.patch !== 0 || this.prerelease.length === 0) + this.minor++; + this.patch = 0; + this.prerelease = []; + break; + case 'patch': + // If this is not a pre-release version, it will increment the patch. + // If it is a pre-release it will bump up to the same patch version. + // 1.2.0-5 patches to 1.2.0 + // 1.2.0 patches to 1.2.1 + if (this.prerelease.length === 0) + this.patch++; + this.prerelease = []; + break; + // This probably shouldn't be used publicly. + // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction. + case 'pre': + if (this.prerelease.length === 0) + this.prerelease = [0]; + else { + var i = this.prerelease.length; + while (--i >= 0) { + if (typeof this.prerelease[i] === 'number') { + this.prerelease[i]++; + i = -2; + } + } + if (i === -1) // didn't increment anything + this.prerelease.push(0); + } + if (identifier) { + // 1.2.0-beta.1 bumps to 1.2.0-beta.2, + // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 + if (this.prerelease[0] === identifier) { + if (isNaN(this.prerelease[1])) + this.prerelease = [identifier, 0]; + } else + this.prerelease = [identifier, 0]; + } + break; + + default: + throw new Error('invalid increment argument: ' + release); + } + this.format(); + this.raw = this.version; + return this; +}; + +exports.inc = inc; +function inc(version, release, loose, identifier) { + if (typeof(loose) === 'string') { + identifier = loose; + loose = undefined; + } + + try { + return new SemVer(version, loose).inc(release, identifier).version; + } catch (er) { + return null; + } +} + +exports.diff = diff; +function diff(version1, version2) { + if (eq(version1, version2)) { + return null; + } else { + var v1 = parse(version1); + var v2 = parse(version2); + if (v1.prerelease.length || v2.prerelease.length) { + for (var key in v1) { + if (key === 'major' || key === 'minor' || key === 'patch') { + if (v1[key] !== v2[key]) { + return 'pre'+key; + } + } + } + return 'prerelease'; + } + for (var key in v1) { + if (key === 'major' || key === 'minor' || key === 'patch') { + if (v1[key] !== v2[key]) { + return key; + } + } + } + } +} + +exports.compareIdentifiers = compareIdentifiers; + +var numeric = /^[0-9]+$/; +function compareIdentifiers(a, b) { + var anum = numeric.test(a); + var bnum = numeric.test(b); + + if (anum && bnum) { + a = +a; + b = +b; + } + + return (anum && !bnum) ? -1 : + (bnum && !anum) ? 1 : + a < b ? -1 : + a > b ? 1 : + 0; +} + +exports.rcompareIdentifiers = rcompareIdentifiers; +function rcompareIdentifiers(a, b) { + return compareIdentifiers(b, a); +} + +exports.major = major; +function major(a, loose) { + return new SemVer(a, loose).major; +} + +exports.minor = minor; +function minor(a, loose) { + return new SemVer(a, loose).minor; +} + +exports.patch = patch; +function patch(a, loose) { + return new SemVer(a, loose).patch; +} + +exports.compare = compare; +function compare(a, b, loose) { + return new SemVer(a, loose).compare(new SemVer(b, loose)); +} + +exports.compareLoose = compareLoose; +function compareLoose(a, b) { + return compare(a, b, true); +} + +exports.rcompare = rcompare; +function rcompare(a, b, loose) { + return compare(b, a, loose); +} + +exports.sort = sort; +function sort(list, loose) { + return list.sort(function(a, b) { + return exports.compare(a, b, loose); + }); +} + +exports.rsort = rsort; +function rsort(list, loose) { + return list.sort(function(a, b) { + return exports.rcompare(a, b, loose); + }); +} + +exports.gt = gt; +function gt(a, b, loose) { + return compare(a, b, loose) > 0; +} + +exports.lt = lt; +function lt(a, b, loose) { + return compare(a, b, loose) < 0; +} + +exports.eq = eq; +function eq(a, b, loose) { + return compare(a, b, loose) === 0; +} + +exports.neq = neq; +function neq(a, b, loose) { + return compare(a, b, loose) !== 0; +} + +exports.gte = gte; +function gte(a, b, loose) { + return compare(a, b, loose) >= 0; +} + +exports.lte = lte; +function lte(a, b, loose) { + return compare(a, b, loose) <= 0; +} + +exports.cmp = cmp; +function cmp(a, op, b, loose) { + var ret; + switch (op) { + case '===': + if (typeof a === 'object') a = a.version; + if (typeof b === 'object') b = b.version; + ret = a === b; + break; + case '!==': + if (typeof a === 'object') a = a.version; + if (typeof b === 'object') b = b.version; + ret = a !== b; + break; + case '': case '=': case '==': ret = eq(a, b, loose); break; + case '!=': ret = neq(a, b, loose); break; + case '>': ret = gt(a, b, loose); break; + case '>=': ret = gte(a, b, loose); break; + case '<': ret = lt(a, b, loose); break; + case '<=': ret = lte(a, b, loose); break; + default: throw new TypeError('Invalid operator: ' + op); + } + return ret; +} + +exports.Comparator = Comparator; +function Comparator(comp, loose) { + if (comp instanceof Comparator) { + if (comp.loose === loose) + return comp; + else + comp = comp.value; + } + + if (!(this instanceof Comparator)) + return new Comparator(comp, loose); + + debug('comparator', comp, loose); + this.loose = loose; + this.parse(comp); + + if (this.semver === ANY) + this.value = ''; + else + this.value = this.operator + this.semver.version; + + debug('comp', this); +} + +var ANY = {}; +Comparator.prototype.parse = function(comp) { + var r = this.loose ? re[COMPARATORLOOSE] : re[COMPARATOR]; + var m = comp.match(r); + + if (!m) + throw new TypeError('Invalid comparator: ' + comp); + + this.operator = m[1]; + if (this.operator === '=') + this.operator = ''; + + // if it literally is just '>' or '' then allow anything. + if (!m[2]) + this.semver = ANY; + else + this.semver = new SemVer(m[2], this.loose); +}; + +Comparator.prototype.toString = function() { + return this.value; +}; + +Comparator.prototype.test = function(version) { + debug('Comparator.test', version, this.loose); + + if (this.semver === ANY) + return true; + + if (typeof version === 'string') + version = new SemVer(version, this.loose); + + return cmp(version, this.operator, this.semver, this.loose); +}; + +Comparator.prototype.intersects = function(comp, loose) { + if (!(comp instanceof Comparator)) { + throw new TypeError('a Comparator is required'); + } + + var rangeTmp; + + if (this.operator === '') { + rangeTmp = new Range(comp.value, loose); + return satisfies(this.value, rangeTmp, loose); + } else if (comp.operator === '') { + rangeTmp = new Range(this.value, loose); + return satisfies(comp.semver, rangeTmp, loose); + } + + var sameDirectionIncreasing = + (this.operator === '>=' || this.operator === '>') && + (comp.operator === '>=' || comp.operator === '>'); + var sameDirectionDecreasing = + (this.operator === '<=' || this.operator === '<') && + (comp.operator === '<=' || comp.operator === '<'); + var sameSemVer = this.semver.version === comp.semver.version; + var differentDirectionsInclusive = + (this.operator === '>=' || this.operator === '<=') && + (comp.operator === '>=' || comp.operator === '<='); + var oppositeDirectionsLessThan = + cmp(this.semver, '<', comp.semver, loose) && + ((this.operator === '>=' || this.operator === '>') && + (comp.operator === '<=' || comp.operator === '<')); + var oppositeDirectionsGreaterThan = + cmp(this.semver, '>', comp.semver, loose) && + ((this.operator === '<=' || this.operator === '<') && + (comp.operator === '>=' || comp.operator === '>')); + + return sameDirectionIncreasing || sameDirectionDecreasing || + (sameSemVer && differentDirectionsInclusive) || + oppositeDirectionsLessThan || oppositeDirectionsGreaterThan; +}; + + +exports.Range = Range; +function Range(range, loose) { + if (range instanceof Range) { + if (range.loose === loose) { + return range; + } else { + return new Range(range.raw, loose); + } + } + + if (range instanceof Comparator) { + return new Range(range.value, loose); + } + + if (!(this instanceof Range)) + return new Range(range, loose); + + this.loose = loose; + + // First, split based on boolean or || + this.raw = range; + this.set = range.split(/\s*\|\|\s*/).map(function(range) { + return this.parseRange(range.trim()); + }, this).filter(function(c) { + // throw out any that are not relevant for whatever reason + return c.length; + }); + + if (!this.set.length) { + throw new TypeError('Invalid SemVer Range: ' + range); + } + + this.format(); +} + +Range.prototype.format = function() { + this.range = this.set.map(function(comps) { + return comps.join(' ').trim(); + }).join('||').trim(); + return this.range; +}; + +Range.prototype.toString = function() { + return this.range; +}; + +Range.prototype.parseRange = function(range) { + var loose = this.loose; + range = range.trim(); + debug('range', range, loose); + // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` + var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE]; + range = range.replace(hr, hyphenReplace); + debug('hyphen replace', range); + // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` + range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace); + debug('comparator trim', range, re[COMPARATORTRIM]); + + // `~ 1.2.3` => `~1.2.3` + range = range.replace(re[TILDETRIM], tildeTrimReplace); + + // `^ 1.2.3` => `^1.2.3` + range = range.replace(re[CARETTRIM], caretTrimReplace); + + // normalize spaces + range = range.split(/\s+/).join(' '); + + // At this point, the range is completely trimmed and + // ready to be split into comparators. + + var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR]; + var set = range.split(' ').map(function(comp) { + return parseComparator(comp, loose); + }).join(' ').split(/\s+/); + if (this.loose) { + // in loose mode, throw out any that are not valid comparators + set = set.filter(function(comp) { + return !!comp.match(compRe); + }); + } + set = set.map(function(comp) { + return new Comparator(comp, loose); + }); + + return set; +}; + +Range.prototype.intersects = function(range, loose) { + if (!(range instanceof Range)) { + throw new TypeError('a Range is required'); + } + + return this.set.some(function(thisComparators) { + return thisComparators.every(function(thisComparator) { + return range.set.some(function(rangeComparators) { + return rangeComparators.every(function(rangeComparator) { + return thisComparator.intersects(rangeComparator, loose); + }); + }); + }); + }); +}; + +// Mostly just for testing and legacy API reasons +exports.toComparators = toComparators; +function toComparators(range, loose) { + return new Range(range, loose).set.map(function(comp) { + return comp.map(function(c) { + return c.value; + }).join(' ').trim().split(' '); + }); +} + +// comprised of xranges, tildes, stars, and gtlt's at this point. +// already replaced the hyphen ranges +// turn into a set of JUST comparators. +function parseComparator(comp, loose) { + debug('comp', comp); + comp = replaceCarets(comp, loose); + debug('caret', comp); + comp = replaceTildes(comp, loose); + debug('tildes', comp); + comp = replaceXRanges(comp, loose); + debug('xrange', comp); + comp = replaceStars(comp, loose); + debug('stars', comp); + return comp; +} + +function isX(id) { + return !id || id.toLowerCase() === 'x' || id === '*'; +} + +// ~, ~> --> * (any, kinda silly) +// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0 +// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0 +// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0 +// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0 +// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0 +function replaceTildes(comp, loose) { + return comp.trim().split(/\s+/).map(function(comp) { + return replaceTilde(comp, loose); + }).join(' '); +} + +function replaceTilde(comp, loose) { + var r = loose ? re[TILDELOOSE] : re[TILDE]; + return comp.replace(r, function(_, M, m, p, pr) { + debug('tilde', comp, _, M, m, p, pr); + var ret; + + if (isX(M)) + ret = ''; + else if (isX(m)) + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; + else if (isX(p)) + // ~1.2 == >=1.2.0 <1.3.0 + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; + else if (pr) { + debug('replaceTilde pr', pr); + if (pr.charAt(0) !== '-') + pr = '-' + pr; + ret = '>=' + M + '.' + m + '.' + p + pr + + ' <' + M + '.' + (+m + 1) + '.0'; + } else + // ~1.2.3 == >=1.2.3 <1.3.0 + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + (+m + 1) + '.0'; + + debug('tilde return', ret); + return ret; + }); +} + +// ^ --> * (any, kinda silly) +// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0 +// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0 +// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0 +// ^1.2.3 --> >=1.2.3 <2.0.0 +// ^1.2.0 --> >=1.2.0 <2.0.0 +function replaceCarets(comp, loose) { + return comp.trim().split(/\s+/).map(function(comp) { + return replaceCaret(comp, loose); + }).join(' '); +} + +function replaceCaret(comp, loose) { + debug('caret', comp, loose); + var r = loose ? re[CARETLOOSE] : re[CARET]; + return comp.replace(r, function(_, M, m, p, pr) { + debug('caret', comp, _, M, m, p, pr); + var ret; + + if (isX(M)) + ret = ''; + else if (isX(m)) + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; + else if (isX(p)) { + if (M === '0') + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; + else + ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0'; + } else if (pr) { + debug('replaceCaret pr', pr); + if (pr.charAt(0) !== '-') + pr = '-' + pr; + if (M === '0') { + if (m === '0') + ret = '>=' + M + '.' + m + '.' + p + pr + + ' <' + M + '.' + m + '.' + (+p + 1); + else + ret = '>=' + M + '.' + m + '.' + p + pr + + ' <' + M + '.' + (+m + 1) + '.0'; + } else + ret = '>=' + M + '.' + m + '.' + p + pr + + ' <' + (+M + 1) + '.0.0'; + } else { + debug('no pr'); + if (M === '0') { + if (m === '0') + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + m + '.' + (+p + 1); + else + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + (+m + 1) + '.0'; + } else + ret = '>=' + M + '.' + m + '.' + p + + ' <' + (+M + 1) + '.0.0'; + } + + debug('caret return', ret); + return ret; + }); +} + +function replaceXRanges(comp, loose) { + debug('replaceXRanges', comp, loose); + return comp.split(/\s+/).map(function(comp) { + return replaceXRange(comp, loose); + }).join(' '); +} + +function replaceXRange(comp, loose) { + comp = comp.trim(); + var r = loose ? re[XRANGELOOSE] : re[XRANGE]; + return comp.replace(r, function(ret, gtlt, M, m, p, pr) { + debug('xRange', comp, ret, gtlt, M, m, p, pr); + var xM = isX(M); + var xm = xM || isX(m); + var xp = xm || isX(p); + var anyX = xp; + + if (gtlt === '=' && anyX) + gtlt = ''; + + if (xM) { + if (gtlt === '>' || gtlt === '<') { + // nothing is allowed + ret = '<0.0.0'; + } else { + // nothing is forbidden + ret = '*'; + } + } else if (gtlt && anyX) { + // replace X with 0 + if (xm) + m = 0; + if (xp) + p = 0; + + if (gtlt === '>') { + // >1 => >=2.0.0 + // >1.2 => >=1.3.0 + // >1.2.3 => >= 1.2.4 + gtlt = '>='; + if (xm) { + M = +M + 1; + m = 0; + p = 0; + } else if (xp) { + m = +m + 1; + p = 0; + } + } else if (gtlt === '<=') { + // <=0.7.x is actually <0.8.0, since any 0.7.x should + // pass. Similarly, <=7.x is actually <8.0.0, etc. + gtlt = '<'; + if (xm) + M = +M + 1; + else + m = +m + 1; + } + + ret = gtlt + M + '.' + m + '.' + p; + } else if (xm) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0'; + } else if (xp) { + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0'; + } + + debug('xRange return', ret); + + return ret; + }); +} + +// Because * is AND-ed with everything else in the comparator, +// and '' means "any version", just remove the *s entirely. +function replaceStars(comp, loose) { + debug('replaceStars', comp, loose); + // Looseness is ignored here. star is always as loose as it gets! + return comp.trim().replace(re[STAR], ''); +} + +// This function is passed to string.replace(re[HYPHENRANGE]) +// M, m, patch, prerelease, build +// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 +// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do +// 1.2 - 3.4 => >=1.2.0 <3.5.0 +function hyphenReplace($0, + from, fM, fm, fp, fpr, fb, + to, tM, tm, tp, tpr, tb) { + + if (isX(fM)) + from = ''; + else if (isX(fm)) + from = '>=' + fM + '.0.0'; + else if (isX(fp)) + from = '>=' + fM + '.' + fm + '.0'; + else + from = '>=' + from; + + if (isX(tM)) + to = ''; + else if (isX(tm)) + to = '<' + (+tM + 1) + '.0.0'; + else if (isX(tp)) + to = '<' + tM + '.' + (+tm + 1) + '.0'; + else if (tpr) + to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr; + else + to = '<=' + to; + + return (from + ' ' + to).trim(); +} + + +// if ANY of the sets match ALL of its comparators, then pass +Range.prototype.test = function(version) { + if (!version) + return false; + + if (typeof version === 'string') + version = new SemVer(version, this.loose); + + for (var i = 0; i < this.set.length; i++) { + if (testSet(this.set[i], version)) + return true; + } + return false; +}; + +function testSet(set, version) { + for (var i = 0; i < set.length; i++) { + if (!set[i].test(version)) + return false; + } + + if (version.prerelease.length) { + // Find the set of versions that are allowed to have prereleases + // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 + // That should allow `1.2.3-pr.2` to pass. + // However, `1.2.4-alpha.notready` should NOT be allowed, + // even though it's within the range set by the comparators. + for (var i = 0; i < set.length; i++) { + debug(set[i].semver); + if (set[i].semver === ANY) + continue; + + if (set[i].semver.prerelease.length > 0) { + var allowed = set[i].semver; + if (allowed.major === version.major && + allowed.minor === version.minor && + allowed.patch === version.patch) + return true; + } + } + + // Version has a -pre, but it's not one of the ones we like. + return false; + } + + return true; +} + +exports.satisfies = satisfies; +function satisfies(version, range, loose) { + try { + range = new Range(range, loose); + } catch (er) { + return false; + } + return range.test(version); +} + +exports.maxSatisfying = maxSatisfying; +function maxSatisfying(versions, range, loose) { + var max = null; + var maxSV = null; + try { + var rangeObj = new Range(range, loose); + } catch (er) { + return null; + } + versions.forEach(function (v) { + if (rangeObj.test(v)) { // satisfies(v, range, loose) + if (!max || maxSV.compare(v) === -1) { // compare(max, v, true) + max = v; + maxSV = new SemVer(max, loose); + } + } + }) + return max; +} + +exports.minSatisfying = minSatisfying; +function minSatisfying(versions, range, loose) { + var min = null; + var minSV = null; + try { + var rangeObj = new Range(range, loose); + } catch (er) { + return null; + } + versions.forEach(function (v) { + if (rangeObj.test(v)) { // satisfies(v, range, loose) + if (!min || minSV.compare(v) === 1) { // compare(min, v, true) + min = v; + minSV = new SemVer(min, loose); + } + } + }) + return min; +} + +exports.validRange = validRange; +function validRange(range, loose) { + try { + // Return '*' instead of '' so that truthiness works. + // This will throw if it's invalid anyway + return new Range(range, loose).range || '*'; + } catch (er) { + return null; + } +} + +// Determine if version is less than all the versions possible in the range +exports.ltr = ltr; +function ltr(version, range, loose) { + return outside(version, range, '<', loose); +} + +// Determine if version is greater than all the versions possible in the range. +exports.gtr = gtr; +function gtr(version, range, loose) { + return outside(version, range, '>', loose); +} + +exports.outside = outside; +function outside(version, range, hilo, loose) { + version = new SemVer(version, loose); + range = new Range(range, loose); + + var gtfn, ltefn, ltfn, comp, ecomp; + switch (hilo) { + case '>': + gtfn = gt; + ltefn = lte; + ltfn = lt; + comp = '>'; + ecomp = '>='; + break; + case '<': + gtfn = lt; + ltefn = gte; + ltfn = gt; + comp = '<'; + ecomp = '<='; + break; + default: + throw new TypeError('Must provide a hilo val of "<" or ">"'); + } + + // If it satisifes the range it is not outside + if (satisfies(version, range, loose)) { + return false; + } + + // From now on, variable terms are as if we're in "gtr" mode. + // but note that everything is flipped for the "ltr" function. + + for (var i = 0; i < range.set.length; ++i) { + var comparators = range.set[i]; + + var high = null; + var low = null; + + comparators.forEach(function(comparator) { + if (comparator.semver === ANY) { + comparator = new Comparator('>=0.0.0') + } + high = high || comparator; + low = low || comparator; + if (gtfn(comparator.semver, high.semver, loose)) { + high = comparator; + } else if (ltfn(comparator.semver, low.semver, loose)) { + low = comparator; + } + }); + + // If the edge version comparator has a operator then our version + // isn't outside it + if (high.operator === comp || high.operator === ecomp) { + return false; + } + + // If the lowest version comparator has an operator and our version + // is less than it then it isn't higher than the range + if ((!low.operator || low.operator === comp) && + ltefn(version, low.semver)) { + return false; + } else if (low.operator === ecomp && ltfn(version, low.semver)) { + return false; + } + } + return true; +} + +exports.prerelease = prerelease; +function prerelease(version, loose) { + var parsed = parse(version, loose); + return (parsed && parsed.prerelease.length) ? parsed.prerelease : null; +} + +exports.intersects = intersects; +function intersects(r1, r2, loose) { + r1 = new Range(r1, loose) + r2 = new Range(r2, loose) + return r1.intersects(r2) +} + +exports.coerce = coerce; +function coerce(version) { + if (version instanceof SemVer) + return version; + + if (typeof version !== 'string') + return null; + + var match = version.match(re[COERCE]); + + if (match == null) + return null; + + return parse((match[1] || '0') + '.' + (match[2] || '0') + '.' + (match[3] || '0')); +} + + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +exports.__esModule = true; + +var _assign = __webpack_require__(558); + +var _assign2 = _interopRequireDefault(_assign); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = _assign2.default || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; +}; + +/***/ }), +/* 22 */ +/***/ (function(module, exports) { + +module.exports = require("stream"); + +/***/ }), +/* 23 */ +/***/ (function(module, exports) { + +module.exports = require("url"); + +/***/ }), +/* 24 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subscription; }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__util_isArray__ = __webpack_require__(40); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_isObject__ = __webpack_require__(416); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util_isFunction__ = __webpack_require__(145); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__util_tryCatch__ = __webpack_require__(51); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__util_errorObject__ = __webpack_require__(44); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__ = __webpack_require__(413); +/** PURE_IMPORTS_START _util_isArray,_util_isObject,_util_isFunction,_util_tryCatch,_util_errorObject,_util_UnsubscriptionError PURE_IMPORTS_END */ + + + + + + +var Subscription = /*@__PURE__*/ (function () { + function Subscription(unsubscribe) { + this.closed = false; + this._parent = null; + this._parents = null; + this._subscriptions = null; + if (unsubscribe) { + this._unsubscribe = unsubscribe; + } + } + Subscription.prototype.unsubscribe = function () { + var hasErrors = false; + var errors; + if (this.closed) { + return; + } + var _a = this, _parent = _a._parent, _parents = _a._parents, _unsubscribe = _a._unsubscribe, _subscriptions = _a._subscriptions; + this.closed = true; + this._parent = null; + this._parents = null; + this._subscriptions = null; + var index = -1; + var len = _parents ? _parents.length : 0; + while (_parent) { + _parent.remove(this); + _parent = ++index < len && _parents[index] || null; + } + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_2__util_isFunction__["a" /* isFunction */])(_unsubscribe)) { + var trial = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_tryCatch__["a" /* tryCatch */])(_unsubscribe).call(this); + if (trial === __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */]) { + hasErrors = true; + errors = errors || (__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */] ? + flattenUnsubscriptionErrors(__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e.errors) : [__WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e]); + } + } + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__util_isArray__["a" /* isArray */])(_subscriptions)) { + index = -1; + len = _subscriptions.length; + while (++index < len) { + var sub = _subscriptions[index]; + if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__util_isObject__["a" /* isObject */])(sub)) { + var trial = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__util_tryCatch__["a" /* tryCatch */])(sub.unsubscribe).call(sub); + if (trial === __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */]) { + hasErrors = true; + errors = errors || []; + var err = __WEBPACK_IMPORTED_MODULE_4__util_errorObject__["a" /* errorObject */].e; + if (err instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */]) { + errors = errors.concat(flattenUnsubscriptionErrors(err.errors)); + } + else { + errors.push(err); + } + } + } + } + } + if (hasErrors) { + throw new __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */](errors); + } + }; + Subscription.prototype.add = function (teardown) { + if (!teardown || (teardown === Subscription.EMPTY)) { + return Subscription.EMPTY; + } + if (teardown === this) { + return this; + } + var subscription = teardown; + switch (typeof teardown) { + case 'function': + subscription = new Subscription(teardown); + case 'object': + if (subscription.closed || typeof subscription.unsubscribe !== 'function') { + return subscription; + } + else if (this.closed) { + subscription.unsubscribe(); + return subscription; + } + else if (typeof subscription._addParent !== 'function') { + var tmp = subscription; + subscription = new Subscription(); + subscription._subscriptions = [tmp]; + } + break; + default: + throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.'); + } + var subscriptions = this._subscriptions || (this._subscriptions = []); + subscriptions.push(subscription); + subscription._addParent(this); + return subscription; + }; + Subscription.prototype.remove = function (subscription) { + var subscriptions = this._subscriptions; + if (subscriptions) { + var subscriptionIndex = subscriptions.indexOf(subscription); + if (subscriptionIndex !== -1) { + subscriptions.splice(subscriptionIndex, 1); + } + } + }; + Subscription.prototype._addParent = function (parent) { + var _a = this, _parent = _a._parent, _parents = _a._parents; + if (!_parent || _parent === parent) { + this._parent = parent; + } + else if (!_parents) { + this._parents = [parent]; + } + else if (_parents.indexOf(parent) === -1) { + _parents.push(parent); + } + }; + Subscription.EMPTY = (function (empty) { + empty.closed = true; + return empty; + }(new Subscription())); + return Subscription; +}()); + +function flattenUnsubscriptionErrors(errors) { + return errors.reduce(function (errs, err) { return errs.concat((err instanceof __WEBPACK_IMPORTED_MODULE_5__util_UnsubscriptionError__["a" /* UnsubscriptionError */]) ? err.errors : err); }, []); +} +//# sourceMappingURL=Subscription.js.map + + +/***/ }), +/* 25 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright 2015 Joyent, Inc. + +module.exports = { + bufferSplit: bufferSplit, + addRSAMissing: addRSAMissing, + calculateDSAPublic: calculateDSAPublic, + calculateED25519Public: calculateED25519Public, + calculateX25519Public: calculateX25519Public, + mpNormalize: mpNormalize, + mpDenormalize: mpDenormalize, + ecNormalize: ecNormalize, + countZeros: countZeros, + assertCompatible: assertCompatible, + isCompatible: isCompatible, + opensslKeyDeriv: opensslKeyDeriv, + opensshCipherInfo: opensshCipherInfo, + publicFromPrivateECDSA: publicFromPrivateECDSA, + zeroPadToLength: zeroPadToLength, + writeBitString: writeBitString, + readBitString: readBitString +}; + +var assert = __webpack_require__(15); +var Buffer = __webpack_require__(14).Buffer; +var PrivateKey = __webpack_require__(32); +var Key = __webpack_require__(26); +var crypto = __webpack_require__(11); +var algs = __webpack_require__(31); +var asn1 = __webpack_require__(60); + +var ec, jsbn; +var nacl; + +var MAX_CLASS_DEPTH = 3; + +function isCompatible(obj, klass, needVer) { + if (obj === null || typeof (obj) !== 'object') + return (false); + if (needVer === undefined) + needVer = klass.prototype._sshpkApiVersion; + if (obj instanceof klass && + klass.prototype._sshpkApiVersion[0] == needVer[0]) + return (true); + var proto = Object.getPrototypeOf(obj); + var depth = 0; + while (proto.constructor.name !== klass.name) { + proto = Object.getPrototypeOf(proto); + if (!proto || ++depth > MAX_CLASS_DEPTH) + return (false); + } + if (proto.constructor.name !== klass.name) + return (false); + var ver = proto._sshpkApiVersion; + if (ver === undefined) + ver = klass._oldVersionDetect(obj); + if (ver[0] != needVer[0] || ver[1] < needVer[1]) + return (false); + return (true); +} + +function assertCompatible(obj, klass, needVer, name) { + if (name === undefined) + name = 'object'; + assert.ok(obj, name + ' must not be null'); + assert.object(obj, name + ' must be an object'); + if (needVer === undefined) + needVer = klass.prototype._sshpkApiVersion; + if (obj instanceof klass && + klass.prototype._sshpkApiVersion[0] == needVer[0]) + return; + var proto = Object.getPrototypeOf(obj); + var depth = 0; + while (proto.constructor.name !== klass.name) { + proto = Object.getPrototypeOf(proto); + assert.ok(proto && ++depth <= MAX_CLASS_DEPTH, + name + ' must be a ' + klass.name + ' instance'); + } + assert.strictEqual(proto.constructor.name, klass.name, + name + ' must be a ' + klass.name + ' instance'); + var ver = proto._sshpkApiVersion; + if (ver === undefined) + ver = klass._oldVersionDetect(obj); + assert.ok(ver[0] == needVer[0] && ver[1] >= needVer[1], + name + ' must be compatible with ' + klass.name + ' klass ' + + 'version ' + needVer[0] + '.' + needVer[1]); +} + +var CIPHER_LEN = { + 'des-ede3-cbc': { key: 7, iv: 8 }, + 'aes-128-cbc': { key: 16, iv: 16 } +}; +var PKCS5_SALT_LEN = 8; + +function opensslKeyDeriv(cipher, salt, passphrase, count) { + assert.buffer(salt, 'salt'); + assert.buffer(passphrase, 'passphrase'); + assert.number(count, 'iteration count'); + + var clen = CIPHER_LEN[cipher]; + assert.object(clen, 'supported cipher'); + + salt = salt.slice(0, PKCS5_SALT_LEN); + + var D, D_prev, bufs; + var material = Buffer.alloc(0); + while (material.length < clen.key + clen.iv) { + bufs = []; + if (D_prev) + bufs.push(D_prev); + bufs.push(passphrase); + bufs.push(salt); + D = Buffer.concat(bufs); + for (var j = 0; j < count; ++j) + D = crypto.createHash('md5').update(D).digest(); + material = Buffer.concat([material, D]); + D_prev = D; + } + + return ({ + key: material.slice(0, clen.key), + iv: material.slice(clen.key, clen.key + clen.iv) + }); +} + +/* Count leading zero bits on a buffer */ +function countZeros(buf) { + var o = 0, obit = 8; + while (o < buf.length) { + var mask = (1 << obit); + if ((buf[o] & mask) === mask) + break; + obit--; + if (obit < 0) { + o++; + obit = 8; + } + } + return (o*8 + (8 - obit) - 1); +} + +function bufferSplit(buf, chr) { + assert.buffer(buf); + assert.string(chr); + + var parts = []; + var lastPart = 0; + var matches = 0; + for (var i = 0; i < buf.length; ++i) { + if (buf[i] === chr.charCodeAt(matches)) + ++matches; + else if (buf[i] === chr.charCodeAt(0)) + matches = 1; + else + matches = 0; + + if (matches >= chr.length) { + var newPart = i + 1; + parts.push(buf.slice(lastPart, newPart - matches)); + lastPart = newPart; + matches = 0; + } + } + if (lastPart <= buf.length) + parts.push(buf.slice(lastPart, buf.length)); + + return (parts); +} + +function ecNormalize(buf, addZero) { + assert.buffer(buf); + if (buf[0] === 0x00 && buf[1] === 0x04) { + if (addZero) + return (buf); + return (buf.slice(1)); + } else if (buf[0] === 0x04) { + if (!addZero) + return (buf); + } else { + while (buf[0] === 0x00) + buf = buf.slice(1); + if (buf[0] === 0x02 || buf[0] === 0x03) + throw (new Error('Compressed elliptic curve points ' + + 'are not supported')); + if (buf[0] !== 0x04) + throw (new Error('Not a valid elliptic curve point')); + if (!addZero) + return (buf); + } + var b = Buffer.alloc(buf.length + 1); + b[0] = 0x0; + buf.copy(b, 1); + return (b); +} + +function readBitString(der, tag) { + if (tag === undefined) + tag = asn1.Ber.BitString; + var buf = der.readString(tag, true); + assert.strictEqual(buf[0], 0x00, 'bit strings with unused bits are ' + + 'not supported (0x' + buf[0].toString(16) + ')'); + return (buf.slice(1)); +} + +function writeBitString(der, buf, tag) { + if (tag === undefined) + tag = asn1.Ber.BitString; + var b = Buffer.alloc(buf.length + 1); + b[0] = 0x00; + buf.copy(b, 1); + der.writeBuffer(b, tag); +} + +function mpNormalize(buf) { + assert.buffer(buf); + while (buf.length > 1 && buf[0] === 0x00 && (buf[1] & 0x80) === 0x00) + buf = buf.slice(1); + if ((buf[0] & 0x80) === 0x80) { + var b = Buffer.alloc(buf.length + 1); + b[0] = 0x00; + buf.copy(b, 1); + buf = b; + } + return (buf); +} + +function mpDenormalize(buf) { + assert.buffer(buf); + while (buf.length > 1 && buf[0] === 0x00) + buf = buf.slice(1); + return (buf); +} + +function zeroPadToLength(buf, len) { + assert.buffer(buf); + assert.number(len); + while (buf.length > len) { + assert.equal(buf[0], 0x00); + buf = buf.slice(1); + } + while (buf.length < len) { + var b = Buffer.alloc(buf.length + 1); + b[0] = 0x00; + buf.copy(b, 1); + buf = b; + } + return (buf); +} + +function bigintToMpBuf(bigint) { + var buf = Buffer.from(bigint.toByteArray()); + buf = mpNormalize(buf); + return (buf); +} + +function calculateDSAPublic(g, p, x) { + assert.buffer(g); + assert.buffer(p); + assert.buffer(x); + try { + var bigInt = __webpack_require__(74).BigInteger; + } catch (e) { + throw (new Error('To load a PKCS#8 format DSA private key, ' + + 'the node jsbn library is required.')); + } + g = new bigInt(g); + p = new bigInt(p); + x = new bigInt(x); + var y = g.modPow(x, p); + var ybuf = bigintToMpBuf(y); + return (ybuf); +} + +function calculateED25519Public(k) { + assert.buffer(k); + + if (nacl === undefined) + nacl = __webpack_require__(69); + + var kp = nacl.sign.keyPair.fromSeed(new Uint8Array(k)); + return (Buffer.from(kp.publicKey)); +} + +function calculateX25519Public(k) { + assert.buffer(k); + + if (nacl === undefined) + nacl = __webpack_require__(69); + + var kp = nacl.box.keyPair.fromSeed(new Uint8Array(k)); + return (Buffer.from(kp.publicKey)); +} + +function addRSAMissing(key) { + assert.object(key); + assertCompatible(key, PrivateKey, [1, 1]); + try { + var bigInt = __webpack_require__(74).BigInteger; + } catch (e) { + throw (new Error('To write a PEM private key from ' + + 'this source, the node jsbn lib is required.')); + } + + var d = new bigInt(key.part.d.data); + var buf; + + if (!key.part.dmodp) { + var p = new bigInt(key.part.p.data); + var dmodp = d.mod(p.subtract(1)); + + buf = bigintToMpBuf(dmodp); + key.part.dmodp = {name: 'dmodp', data: buf}; + key.parts.push(key.part.dmodp); + } + if (!key.part.dmodq) { + var q = new bigInt(key.part.q.data); + var dmodq = d.mod(q.subtract(1)); + + buf = bigintToMpBuf(dmodq); + key.part.dmodq = {name: 'dmodq', data: buf}; + key.parts.push(key.part.dmodq); + } +} + +function publicFromPrivateECDSA(curveName, priv) { + assert.string(curveName, 'curveName'); + assert.buffer(priv); + if (ec === undefined) + ec = __webpack_require__(132); + if (jsbn === undefined) + jsbn = __webpack_require__(74).BigInteger; + var params = algs.curves[curveName]; + var p = new jsbn(params.p); + var a = new jsbn(params.a); + var b = new jsbn(params.b); + var curve = new ec.ECCurveFp(p, a, b); + var G = curve.decodePointHex(params.G.toString('hex')); + + var d = new jsbn(mpNormalize(priv)); + var pub = G.multiply(d); + pub = Buffer.from(curve.encodePointHex(pub), 'hex'); + + var parts = []; + parts.push({name: 'curve', data: Buffer.from(curveName)}); + parts.push({name: 'Q', data: pub}); + + var key = new Key({type: 'ecdsa', curve: curve, parts: parts}); + return (key); +} + +function opensshCipherInfo(cipher) { + var inf = {}; + switch (cipher) { + case '3des-cbc': + inf.keySize = 24; + inf.blockSize = 8; + inf.opensslName = 'des-ede3-cbc'; + break; + case 'blowfish-cbc': + inf.keySize = 16; + inf.blockSize = 8; + inf.opensslName = 'bf-cbc'; + break; + case 'aes128-cbc': + case 'aes128-ctr': + case 'aes128-gcm@openssh.com': + inf.keySize = 16; + inf.blockSize = 16; + inf.opensslName = 'aes-128-' + cipher.slice(7, 10); + break; + case 'aes192-cbc': + case 'aes192-ctr': + case 'aes192-gcm@openssh.com': + inf.keySize = 24; + inf.blockSize = 16; + inf.opensslName = 'aes-192-' + cipher.slice(7, 10); + break; + case 'aes256-cbc': + case 'aes256-ctr': + case 'aes256-gcm@openssh.com': + inf.keySize = 32; + inf.blockSize = 16; + inf.opensslName = 'aes-256-' + cipher.slice(7, 10); + break; + default: + throw (new Error( + 'Unsupported openssl cipher "' + cipher + '"')); + } + return (inf); +} + + +/***/ }), +/* 26 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright 2017 Joyent, Inc. + +module.exports = Key; + +var assert = __webpack_require__(15); +var algs = __webpack_require__(31); +var crypto = __webpack_require__(11); +var Fingerprint = __webpack_require__(147); +var Signature = __webpack_require__(68); +var DiffieHellman = __webpack_require__(293).DiffieHellman; +var errs = __webpack_require__(67); +var utils = __webpack_require__(25); +var PrivateKey = __webpack_require__(32); +var edCompat; + +try { + edCompat = __webpack_require__(426); +} catch (e) { + /* Just continue through, and bail out if we try to use it. */ +} + +var InvalidAlgorithmError = errs.InvalidAlgorithmError; +var KeyParseError = errs.KeyParseError; + +var formats = {}; +formats['auto'] = __webpack_require__(427); +formats['pem'] = __webpack_require__(79); +formats['pkcs1'] = __webpack_require__(295); +formats['pkcs8'] = __webpack_require__(148); +formats['rfc4253'] = __webpack_require__(96); +formats['ssh'] = __webpack_require__(428); +formats['ssh-private'] = __webpack_require__(183); +formats['openssh'] = formats['ssh-private']; +formats['dnssec'] = __webpack_require__(294); + +function Key(opts) { + assert.object(opts, 'options'); + assert.arrayOfObject(opts.parts, 'options.parts'); + assert.string(opts.type, 'options.type'); + assert.optionalString(opts.comment, 'options.comment'); + + var algInfo = algs.info[opts.type]; + if (typeof (algInfo) !== 'object') + throw (new InvalidAlgorithmError(opts.type)); + + var partLookup = {}; + for (var i = 0; i < opts.parts.length; ++i) { + var part = opts.parts[i]; + partLookup[part.name] = part; + } + + this.type = opts.type; + this.parts = opts.parts; + this.part = partLookup; + this.comment = undefined; + this.source = opts.source; + + /* for speeding up hashing/fingerprint operations */ + this._rfc4253Cache = opts._rfc4253Cache; + this._hashCache = {}; + + var sz; + this.curve = undefined; + if (this.type === 'ecdsa') { + var curve = this.part.curve.data.toString(); + this.curve = curve; + sz = algs.curves[curve].size; + } else if (this.type === 'ed25519' || this.type === 'curve25519') { + sz = 256; + this.curve = 'curve25519'; + } else { + var szPart = this.part[algInfo.sizePart]; + sz = szPart.data.length; + sz = sz * 8 - utils.countZeros(szPart.data); + } + this.size = sz; +} + +Key.formats = formats; + +Key.prototype.toBuffer = function (format, options) { + if (format === undefined) + format = 'ssh'; + assert.string(format, 'format'); + assert.object(formats[format], 'formats[format]'); + assert.optionalObject(options, 'options'); + + if (format === 'rfc4253') { + if (this._rfc4253Cache === undefined) + this._rfc4253Cache = formats['rfc4253'].write(this); + return (this._rfc4253Cache); + } + + return (formats[format].write(this, options)); +}; + +Key.prototype.toString = function (format, options) { + return (this.toBuffer(format, options).toString()); +}; + +Key.prototype.hash = function (algo) { + assert.string(algo, 'algorithm'); + algo = algo.toLowerCase(); + if (algs.hashAlgs[algo] === undefined) + throw (new InvalidAlgorithmError(algo)); + + if (this._hashCache[algo]) + return (this._hashCache[algo]); + var hash = crypto.createHash(algo). + update(this.toBuffer('rfc4253')).digest(); + this._hashCache[algo] = hash; + return (hash); +}; + +Key.prototype.fingerprint = function (algo) { + if (algo === undefined) + algo = 'sha256'; + assert.string(algo, 'algorithm'); + var opts = { + type: 'key', + hash: this.hash(algo), + algorithm: algo + }; + return (new Fingerprint(opts)); +}; + +Key.prototype.defaultHashAlgorithm = function () { + var hashAlgo = 'sha1'; + if (this.type === 'rsa') + hashAlgo = 'sha256'; + if (this.type === 'dsa' && this.size > 1024) + hashAlgo = 'sha256'; + if (this.type === 'ed25519') + hashAlgo = 'sha512'; + if (this.type === 'ecdsa') { + if (this.size <= 256) + hashAlgo = 'sha256'; + else if (this.size <= 384) + hashAlgo = 'sha384'; + else + hashAlgo = 'sha512'; + } + return (hashAlgo); +}; + +Key.prototype.createVerify = function (hashAlgo) { + if (hashAlgo === undefined) + hashAlgo = this.defaultHashAlgorithm(); + assert.string(hashAlgo, 'hash algorithm'); + + /* ED25519 is not supported by OpenSSL, use a javascript impl. */ + if (this.type === 'ed25519' && edCompat !== undefined) + return (new edCompat.Verifier(this, hashAlgo)); + if (this.type === 'curve25519') + throw (new Error('Curve25519 keys are not suitable for ' + + 'signing or verification')); + + var v, nm, err; + try { + nm = hashAlgo.toUpperCase(); + v = crypto.createVerify(nm); + } catch (e) { + err = e; + } + if (v === undefined || (err instanceof Error && + err.message.match(/Unknown message digest/))) { + nm = 'RSA-'; + nm += hashAlgo.toUpperCase(); + v = crypto.createVerify(nm); + } + assert.ok(v, 'failed to create verifier'); + var oldVerify = v.verify.bind(v); + var key = this.toBuffer('pkcs8'); + var curve = this.curve; + var self = this; + v.verify = function (signature, fmt) { + if (Signature.isSignature(signature, [2, 0])) { + if (signature.type !== self.type) + return (false); + if (signature.hashAlgorithm && + signature.hashAlgorithm !== hashAlgo) + return (false); + if (signature.curve && self.type === 'ecdsa' && + signature.curve !== curve) + return (false); + return (oldVerify(key, signature.toBuffer('asn1'))); + + } else if (typeof (signature) === 'string' || + Buffer.isBuffer(signature)) { + return (oldVerify(key, signature, fmt)); + + /* + * Avoid doing this on valid arguments, walking the prototype + * chain can be quite slow. + */ + } else if (Signature.isSignature(signature, [1, 0])) { + throw (new Error('signature was created by too old ' + + 'a version of sshpk and cannot be verified')); + + } else { + throw (new TypeError('signature must be a string, ' + + 'Buffer, or Signature object')); + } + }; + return (v); +}; + +Key.prototype.createDiffieHellman = function () { + if (this.type === 'rsa') + throw (new Error('RSA keys do not support Diffie-Hellman')); + + return (new DiffieHellman(this)); +}; +Key.prototype.createDH = Key.prototype.createDiffieHellman; + +Key.parse = function (data, format, options) { + if (typeof (data) !== 'string') + assert.buffer(data, 'data'); + if (format === undefined) + format = 'auto'; + assert.string(format, 'format'); + if (typeof (options) === 'string') + options = { filename: options }; + assert.optionalObject(options, 'options'); + if (options === undefined) + options = {}; + assert.optionalString(options.filename, 'options.filename'); + if (options.filename === undefined) + options.filename = '(unnamed)'; + + assert.object(formats[format], 'formats[format]'); + + try { + var k = formats[format].read(data, options); + if (k instanceof PrivateKey) + k = k.toPublic(); + if (!k.comment) + k.comment = options.filename; + return (k); + } catch (e) { + if (e.name === 'KeyEncryptedError') + throw (e); + throw (new KeyParseError(options.filename, format, e)); + } +}; + +Key.isKey = function (obj, ver) { + return (utils.isCompatible(obj, Key, ver)); +}; + +/* + * API versions for Key: + * [1,0] -- initial ver, may take Signature for createVerify or may not + * [1,1] -- added pkcs1, pkcs8 formats + * [1,2] -- added auto, ssh-private, openssh formats + * [1,3] -- added defaultHashAlgorithm + * [1,4] -- added ed support, createDH + * [1,5] -- first explicitly tagged version + * [1,6] -- changed ed25519 part names + */ +Key.prototype._sshpkApiVersion = [1, 6]; + +Key._oldVersionDetect = function (obj) { + assert.func(obj.toBuffer); + assert.func(obj.fingerprint); + if (obj.createDH) + return ([1, 4]); + if (obj.defaultHashAlgorithm) + return ([1, 3]); + if (obj.formats['auto']) + return ([1, 2]); + if (obj.formats['pkcs1']) + return ([1, 1]); + return ([1, 0]); +}; + + +/***/ }), +/* 27 */ +/***/ (function(module, exports) { + +module.exports = require("assert"); + +/***/ }), +/* 28 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = nullify; +function nullify(obj = {}) { + if (Array.isArray(obj)) { + for (var _iterator = obj, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref = _i.value; + } + + const item = _ref; + + nullify(item); + } + } else if (obj !== null && typeof obj === 'object' || typeof obj === 'function') { + Object.setPrototypeOf(obj, null); + + // for..in can only be applied to 'object', not 'function' + if (typeof obj === 'object') { + for (const key in obj) { + nullify(obj[key]); + } + } + } + + return obj; +} + +/***/ }), +/* 29 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const escapeStringRegexp = __webpack_require__(360); +const ansiStyles = __webpack_require__(477); +const stdoutColor = __webpack_require__(565).stdout; + +const template = __webpack_require__(566); + +const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); + +// `supportsColor.level` → `ansiStyles.color[name]` mapping +const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; + +// `color-convert` models to exclude from the Chalk API due to conflicts and such +const skipModels = new Set(['gray']); + +const styles = Object.create(null); + +function applyOptions(obj, options) { + options = options || {}; + + // Detect level if not set manually + const scLevel = stdoutColor ? stdoutColor.level : 0; + obj.level = options.level === undefined ? scLevel : options.level; + obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; +} + +function Chalk(options) { + // We check for this.template here since calling `chalk.constructor()` + // by itself will have a `this` of a previously constructed chalk object + if (!this || !(this instanceof Chalk) || this.template) { + const chalk = {}; + applyOptions(chalk, options); + + chalk.template = function () { + const args = [].slice.call(arguments); + return chalkTag.apply(null, [chalk.template].concat(args)); + }; + + Object.setPrototypeOf(chalk, Chalk.prototype); + Object.setPrototypeOf(chalk.template, chalk); + + chalk.template.constructor = Chalk; + + return chalk.template; + } + + applyOptions(this, options); +} + +// Use bright blue on Windows as the normal blue color is illegible +if (isSimpleWindowsTerm) { + ansiStyles.blue.open = '\u001B[94m'; +} + +for (const key of Object.keys(ansiStyles)) { + ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); + + styles[key] = { + get() { + const codes = ansiStyles[key]; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); + } + }; +} + +styles.visible = { + get() { + return build.call(this, this._styles || [], true, 'visible'); + } +}; + +ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); +for (const model of Object.keys(ansiStyles.color.ansi)) { + if (skipModels.has(model)) { + continue; + } + + styles[model] = { + get() { + const level = this.level; + return function () { + const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); + const codes = { + open, + close: ansiStyles.color.close, + closeRe: ansiStyles.color.closeRe + }; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + }; + } + }; +} + +ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); +for (const model of Object.keys(ansiStyles.bgColor.ansi)) { + if (skipModels.has(model)) { + continue; + } + + const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); + styles[bgModel] = { + get() { + const level = this.level; + return function () { + const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); + const codes = { + open, + close: ansiStyles.bgColor.close, + closeRe: ansiStyles.bgColor.closeRe + }; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + }; + } + }; +} + +const proto = Object.defineProperties(() => {}, styles); + +function build(_styles, _empty, key) { + const builder = function () { + return applyStyle.apply(builder, arguments); + }; + + builder._styles = _styles; + builder._empty = _empty; + + const self = this; + + Object.defineProperty(builder, 'level', { + enumerable: true, + get() { + return self.level; + }, + set(level) { + self.level = level; + } + }); + + Object.defineProperty(builder, 'enabled', { + enumerable: true, + get() { + return self.enabled; + }, + set(enabled) { + self.enabled = enabled; + } + }); + + // See below for fix regarding invisible grey/dim combination on Windows + builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; + + // `__proto__` is used because we must return a function, but there is + // no way to create a function with a different prototype + builder.__proto__ = proto; // eslint-disable-line no-proto + + return builder; +} + +function applyStyle() { + // Support varags, but simply cast to string in case there's only one arg + const args = arguments; + const argsLen = args.length; + let str = String(arguments[0]); + + if (argsLen === 0) { + return ''; + } + + if (argsLen > 1) { + // Don't slice `arguments`, it prevents V8 optimizations + for (let a = 1; a < argsLen; a++) { + str += ' ' + args[a]; + } + } + + if (!this.enabled || this.level <= 0 || !str) { + return this._empty ? '' : str; + } + + // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, + // see https://github.com/chalk/chalk/issues/58 + // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. + const originalDim = ansiStyles.dim.open; + if (isSimpleWindowsTerm && this.hasGrey) { + ansiStyles.dim.open = ''; + } + + for (const code of this._styles.slice().reverse()) { + // Replace any instances already present with a re-opening code + // otherwise only the part of the string until said closing code + // will be colored, and the rest will simply be 'plain'. + str = code.open + str.replace(code.closeRe, code.open) + code.close; + + // Close the styling before a linebreak and reopen + // after next line to fix a bleed issue on macOS + // https://github.com/chalk/chalk/pull/92 + str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); + } + + // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue + ansiStyles.dim.open = originalDim; + + return str; +} + +function chalkTag(chalk, strings) { + if (!Array.isArray(strings)) { + // If chalk() was called by itself or with a string, + // return the string itself as a string. + return [].slice.call(arguments, 1).join(' '); + } + + const args = [].slice.call(arguments, 2); + const parts = [strings.raw[0]]; + + for (let i = 1; i < strings.length; i++) { + parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); + parts.push(String(strings.raw[i])); + } + + return template(chalk, parts.join('')); +} + +Object.defineProperties(Chalk.prototype, styles); + +module.exports = Chalk(); // eslint-disable-line new-cap +module.exports.supportsColor = stdoutColor; +module.exports.default = module.exports; // For TypeScript + + +/***/ }), +/* 30 */ +/***/ (function(module, exports) { + +var core = module.exports = { version: '2.5.7' }; +if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef + + +/***/ }), +/* 31 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright 2015 Joyent, Inc. + +var Buffer = __webpack_require__(14).Buffer; + +var algInfo = { + 'dsa': { + parts: ['p', 'q', 'g', 'y'], + sizePart: 'p' + }, + 'rsa': { + parts: ['e', 'n'], + sizePart: 'n' + }, + 'ecdsa': { + parts: ['curve', 'Q'], + sizePart: 'Q' + }, + 'ed25519': { + parts: ['A'], + sizePart: 'A' + } +}; +algInfo['curve25519'] = algInfo['ed25519']; + +var algPrivInfo = { + 'dsa': { + parts: ['p', 'q', 'g', 'y', 'x'] + }, + 'rsa': { + parts: ['n', 'e', 'd', 'iqmp', 'p', 'q'] + }, + 'ecdsa': { + parts: ['curve', 'Q', 'd'] + }, + 'ed25519': { + parts: ['A', 'k'] + } +}; +algPrivInfo['curve25519'] = algPrivInfo['ed25519']; + +var hashAlgs = { + 'md5': true, + 'sha1': true, + 'sha256': true, + 'sha384': true, + 'sha512': true +}; + +/* + * Taken from + * http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf + */ +var curves = { + 'nistp256': { + size: 256, + pkcs8oid: '1.2.840.10045.3.1.7', + p: Buffer.from(('00' + + 'ffffffff 00000001 00000000 00000000' + + '00000000 ffffffff ffffffff ffffffff'). + replace(/ /g, ''), 'hex'), + a: Buffer.from(('00' + + 'FFFFFFFF 00000001 00000000 00000000' + + '00000000 FFFFFFFF FFFFFFFF FFFFFFFC'). + replace(/ /g, ''), 'hex'), + b: Buffer.from(( + '5ac635d8 aa3a93e7 b3ebbd55 769886bc' + + '651d06b0 cc53b0f6 3bce3c3e 27d2604b'). + replace(/ /g, ''), 'hex'), + s: Buffer.from(('00' + + 'c49d3608 86e70493 6a6678e1 139d26b7' + + '819f7e90'). + replace(/ /g, ''), 'hex'), + n: Buffer.from(('00' + + 'ffffffff 00000000 ffffffff ffffffff' + + 'bce6faad a7179e84 f3b9cac2 fc632551'). + replace(/ /g, ''), 'hex'), + G: Buffer.from(('04' + + '6b17d1f2 e12c4247 f8bce6e5 63a440f2' + + '77037d81 2deb33a0 f4a13945 d898c296' + + '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16' + + '2bce3357 6b315ece cbb64068 37bf51f5'). + replace(/ /g, ''), 'hex') + }, + 'nistp384': { + size: 384, + pkcs8oid: '1.3.132.0.34', + p: Buffer.from(('00' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff fffffffe' + + 'ffffffff 00000000 00000000 ffffffff'). + replace(/ /g, ''), 'hex'), + a: Buffer.from(('00' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE' + + 'FFFFFFFF 00000000 00000000 FFFFFFFC'). + replace(/ /g, ''), 'hex'), + b: Buffer.from(( + 'b3312fa7 e23ee7e4 988e056b e3f82d19' + + '181d9c6e fe814112 0314088f 5013875a' + + 'c656398d 8a2ed19d 2a85c8ed d3ec2aef'). + replace(/ /g, ''), 'hex'), + s: Buffer.from(('00' + + 'a335926a a319a27a 1d00896a 6773a482' + + '7acdac73'). + replace(/ /g, ''), 'hex'), + n: Buffer.from(('00' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff c7634d81 f4372ddf' + + '581a0db2 48b0a77a ecec196a ccc52973'). + replace(/ /g, ''), 'hex'), + G: Buffer.from(('04' + + 'aa87ca22 be8b0537 8eb1c71e f320ad74' + + '6e1d3b62 8ba79b98 59f741e0 82542a38' + + '5502f25d bf55296c 3a545e38 72760ab7' + + '3617de4a 96262c6f 5d9e98bf 9292dc29' + + 'f8f41dbd 289a147c e9da3113 b5f0b8c0' + + '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f'). + replace(/ /g, ''), 'hex') + }, + 'nistp521': { + size: 521, + pkcs8oid: '1.3.132.0.35', + p: Buffer.from(( + '01ffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffff').replace(/ /g, ''), 'hex'), + a: Buffer.from(('01FF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFC'). + replace(/ /g, ''), 'hex'), + b: Buffer.from(('51' + + '953eb961 8e1c9a1f 929a21a0 b68540ee' + + 'a2da725b 99b315f3 b8b48991 8ef109e1' + + '56193951 ec7e937b 1652c0bd 3bb1bf07' + + '3573df88 3d2c34f1 ef451fd4 6b503f00'). + replace(/ /g, ''), 'hex'), + s: Buffer.from(('00' + + 'd09e8800 291cb853 96cc6717 393284aa' + + 'a0da64ba').replace(/ /g, ''), 'hex'), + n: Buffer.from(('01ff' + + 'ffffffff ffffffff ffffffff ffffffff' + + 'ffffffff ffffffff ffffffff fffffffa' + + '51868783 bf2f966b 7fcc0148 f709a5d0' + + '3bb5c9b8 899c47ae bb6fb71e 91386409'). + replace(/ /g, ''), 'hex'), + G: Buffer.from(('04' + + '00c6 858e06b7 0404e9cd 9e3ecb66 2395b442' + + '9c648139 053fb521 f828af60 6b4d3dba' + + 'a14b5e77 efe75928 fe1dc127 a2ffa8de' + + '3348b3c1 856a429b f97e7e31 c2e5bd66' + + '0118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9' + + '98f54449 579b4468 17afbd17 273e662c' + + '97ee7299 5ef42640 c550b901 3fad0761' + + '353c7086 a272c240 88be9476 9fd16650'). + replace(/ /g, ''), 'hex') + } +}; + +module.exports = { + info: algInfo, + privInfo: algPrivInfo, + hashAlgs: hashAlgs, + curves: curves +}; + + +/***/ }), +/* 32 */ +/***/ (function(module, exports, __webpack_require__) { + +// Copyright 2017 Joyent, Inc. + +module.exports = PrivateKey; + +var assert = __webpack_require__(15); +var Buffer = __webpack_require__(14).Buffer; +var algs = __webpack_require__(31); +var crypto = __webpack_require__(11); +var Fingerprint = __webpack_require__(147); +var Signature = __webpack_require__(68); +var errs = __webpack_require__(67); +var util = __webpack_require__(3); +var utils = __webpack_require__(25); +var dhe = __webpack_require__(293); +var generateECDSA = dhe.generateECDSA; +var generateED25519 = dhe.generateED25519; +var edCompat; +var nacl; + +try { + edCompat = __webpack_require__(426); +} catch (e) { + /* Just continue through, and bail out if we try to use it. */ +} + +var Key = __webpack_require__(26); + +var InvalidAlgorithmError = errs.InvalidAlgorithmError; +var KeyParseError = errs.KeyParseError; +var KeyEncryptedError = errs.KeyEncryptedError; + +var formats = {}; +formats['auto'] = __webpack_require__(427); +formats['pem'] = __webpack_require__(79); +formats['pkcs1'] = __webpack_require__(295); +formats['pkcs8'] = __webpack_require__(148); +formats['rfc4253'] = __webpack_require__(96); +formats['ssh-private'] = __webpack_require__(183); +formats['openssh'] = formats['ssh-private']; +formats['ssh'] = formats['ssh-private']; +formats['dnssec'] = __webpack_require__(294); + +function PrivateKey(opts) { + assert.object(opts, 'options'); + Key.call(this, opts); + + this._pubCache = undefined; +} +util.inherits(PrivateKey, Key); + +PrivateKey.formats = formats; + +PrivateKey.prototype.toBuffer = function (format, options) { + if (format === undefined) + format = 'pkcs1'; + assert.string(format, 'format'); + assert.object(formats[format], 'formats[format]'); + assert.optionalObject(options, 'options'); + + return (formats[format].write(this, options)); +}; + +PrivateKey.prototype.hash = function (algo) { + return (this.toPublic().hash(algo)); +}; + +PrivateKey.prototype.toPublic = function () { + if (this._pubCache) + return (this._pubCache); + + var algInfo = algs.info[this.type]; + var pubParts = []; + for (var i = 0; i < algInfo.parts.length; ++i) { + var p = algInfo.parts[i]; + pubParts.push(this.part[p]); + } + + this._pubCache = new Key({ + type: this.type, + source: this, + parts: pubParts + }); + if (this.comment) + this._pubCache.comment = this.comment; + return (this._pubCache); +}; + +PrivateKey.prototype.derive = function (newType) { + assert.string(newType, 'type'); + var priv, pub, pair; + + if (this.type === 'ed25519' && newType === 'curve25519') { + if (nacl === undefined) + nacl = __webpack_require__(69); + + priv = this.part.k.data; + if (priv[0] === 0x00) + priv = priv.slice(1); + + pair = nacl.box.keyPair.fromSecretKey(new Uint8Array(priv)); + pub = Buffer.from(pair.publicKey); + + return (new PrivateKey({ + type: 'curve25519', + parts: [ + { name: 'A', data: utils.mpNormalize(pub) }, + { name: 'k', data: utils.mpNormalize(priv) } + ] + })); + } else if (this.type === 'curve25519' && newType === 'ed25519') { + if (nacl === undefined) + nacl = __webpack_require__(69); + + priv = this.part.k.data; + if (priv[0] === 0x00) + priv = priv.slice(1); + + pair = nacl.sign.keyPair.fromSeed(new Uint8Array(priv)); + pub = Buffer.from(pair.publicKey); + + return (new PrivateKey({ + type: 'ed25519', + parts: [ + { name: 'A', data: utils.mpNormalize(pub) }, + { name: 'k', data: utils.mpNormalize(priv) } + ] + })); + } + throw (new Error('Key derivation not supported from ' + this.type + + ' to ' + newType)); +}; + +PrivateKey.prototype.createVerify = function (hashAlgo) { + return (this.toPublic().createVerify(hashAlgo)); +}; + +PrivateKey.prototype.createSign = function (hashAlgo) { + if (hashAlgo === undefined) + hashAlgo = this.defaultHashAlgorithm(); + assert.string(hashAlgo, 'hash algorithm'); + + /* ED25519 is not supported by OpenSSL, use a javascript impl. */ + if (this.type === 'ed25519' && edCompat !== undefined) + return (new edCompat.Signer(this, hashAlgo)); + if (this.type === 'curve25519') + throw (new Error('Curve25519 keys are not suitable for ' + + 'signing or verification')); + + var v, nm, err; + try { + nm = hashAlgo.toUpperCase(); + v = crypto.createSign(nm); + } catch (e) { + err = e; + } + if (v === undefined || (err instanceof Error && + err.message.match(/Unknown message digest/))) { + nm = 'RSA-'; + nm += hashAlgo.toUpperCase(); + v = crypto.createSign(nm); + } + assert.ok(v, 'failed to create verifier'); + var oldSign = v.sign.bind(v); + var key = this.toBuffer('pkcs1'); + var type = this.type; + var curve = this.curve; + v.sign = function () { + var sig = oldSign(key); + if (typeof (sig) === 'string') + sig = Buffer.from(sig, 'binary'); + sig = Signature.parse(sig, type, 'asn1'); + sig.hashAlgorithm = hashAlgo; + sig.curve = curve; + return (sig); + }; + return (v); +}; + +PrivateKey.parse = function (data, format, options) { + if (typeof (data) !== 'string') + assert.buffer(data, 'data'); + if (format === undefined) + format = 'auto'; + assert.string(format, 'format'); + if (typeof (options) === 'string') + options = { filename: options }; + assert.optionalObject(options, 'options'); + if (options === undefined) + options = {}; + assert.optionalString(options.filename, 'options.filename'); + if (options.filename === undefined) + options.filename = '(unnamed)'; + + assert.object(formats[format], 'formats[format]'); + + try { + var k = formats[format].read(data, options); + assert.ok(k instanceof PrivateKey, 'key is not a private key'); + if (!k.comment) + k.comment = options.filename; + return (k); + } catch (e) { + if (e.name === 'KeyEncryptedError') + throw (e); + throw (new KeyParseError(options.filename, format, e)); + } +}; + +PrivateKey.isPrivateKey = function (obj, ver) { + return (utils.isCompatible(obj, PrivateKey, ver)); +}; + +PrivateKey.generate = function (type, options) { + if (options === undefined) + options = {}; + assert.object(options, 'options'); + + switch (type) { + case 'ecdsa': + if (options.curve === undefined) + options.curve = 'nistp256'; + assert.string(options.curve, 'options.curve'); + return (generateECDSA(options.curve)); + case 'ed25519': + return (generateED25519()); + default: + throw (new Error('Key generation not supported with key ' + + 'type "' + type + '"')); + } +}; + +/* + * API versions for PrivateKey: + * [1,0] -- initial ver + * [1,1] -- added auto, pkcs[18], openssh/ssh-private formats + * [1,2] -- added defaultHashAlgorithm + * [1,3] -- added derive, ed, createDH + * [1,4] -- first tagged version + * [1,5] -- changed ed25519 part names and format + */ +PrivateKey.prototype._sshpkApiVersion = [1, 5]; + +PrivateKey._oldVersionDetect = function (obj) { + assert.func(obj.toPublic); + assert.func(obj.createSign); + if (obj.derive) + return ([1, 3]); + if (obj.defaultHashAlgorithm) + return ([1, 2]); + if (obj.formats['auto']) + return ([1, 1]); + return ([1, 0]); +}; + + +/***/ }), +/* 33 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.wrapLifecycle = exports.run = exports.install = exports.Install = undefined; + +var _extends2; + +function _load_extends() { + return _extends2 = _interopRequireDefault(__webpack_require__(21)); +} + +var _asyncToGenerator2; + +function _load_asyncToGenerator() { + return _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(2)); +} + +let install = exports.install = (() => { + var _ref29 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, lockfile) { + yield wrapLifecycle(config, flags, (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const install = new Install(flags, config, reporter, lockfile); + yield install.init(); + })); + }); + + return function install(_x7, _x8, _x9, _x10) { + return _ref29.apply(this, arguments); + }; +})(); + +let run = exports.run = (() => { + var _ref31 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, reporter, flags, args) { + let lockfile; + let error = 'installCommandRenamed'; + if (flags.lockfile === false) { + lockfile = new (_lockfile || _load_lockfile()).default(); + } else { + lockfile = yield (_lockfile || _load_lockfile()).default.fromDirectory(config.lockfileFolder, reporter); + } + + if (args.length) { + const exampleArgs = args.slice(); + + if (flags.saveDev) { + exampleArgs.push('--dev'); + } + if (flags.savePeer) { + exampleArgs.push('--peer'); + } + if (flags.saveOptional) { + exampleArgs.push('--optional'); + } + if (flags.saveExact) { + exampleArgs.push('--exact'); + } + if (flags.saveTilde) { + exampleArgs.push('--tilde'); + } + let command = 'add'; + if (flags.global) { + error = 'globalFlagRemoved'; + command = 'global add'; + } + throw new (_errors || _load_errors()).MessageError(reporter.lang(error, `yarn ${command} ${exampleArgs.join(' ')}`)); + } + + yield install(config, reporter, flags, lockfile); + }); + + return function run(_x11, _x12, _x13, _x14) { + return _ref31.apply(this, arguments); + }; +})(); + +let wrapLifecycle = exports.wrapLifecycle = (() => { + var _ref32 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (config, flags, factory) { + yield config.executeLifecycleScript('preinstall'); + + yield factory(); + + // npm behaviour, seems kinda funky but yay compatibility + yield config.executeLifecycleScript('install'); + yield config.executeLifecycleScript('postinstall'); + + if (!config.production) { + if (!config.disablePrepublish) { + yield config.executeLifecycleScript('prepublish'); + } + yield config.executeLifecycleScript('prepare'); + } + }); + + return function wrapLifecycle(_x15, _x16, _x17) { + return _ref32.apply(this, arguments); + }; +})(); + +exports.hasWrapper = hasWrapper; +exports.setFlags = setFlags; + +var _hooks; + +function _load_hooks() { + return _hooks = __webpack_require__(549); +} + +var _index; + +function _load_index() { + return _index = _interopRequireDefault(__webpack_require__(209)); +} + +var _errors; + +function _load_errors() { + return _errors = __webpack_require__(7); +} + +var _integrityChecker; + +function _load_integrityChecker() { + return _integrityChecker = _interopRequireDefault(__webpack_require__(198)); +} + +var _lockfile; + +function _load_lockfile() { + return _lockfile = _interopRequireDefault(__webpack_require__(18)); +} + +var _lockfile2; + +function _load_lockfile2() { + return _lockfile2 = __webpack_require__(18); +} + +var _packageFetcher; + +function _load_packageFetcher() { + return _packageFetcher = _interopRequireWildcard(__webpack_require__(199)); +} + +var _packageInstallScripts; + +function _load_packageInstallScripts() { + return _packageInstallScripts = _interopRequireDefault(__webpack_require__(528)); +} + +var _packageCompatibility; + +function _load_packageCompatibility() { + return _packageCompatibility = _interopRequireWildcard(__webpack_require__(333)); +} + +var _packageResolver; + +function _load_packageResolver() { + return _packageResolver = _interopRequireDefault(__webpack_require__(335)); +} + +var _packageLinker; + +function _load_packageLinker() { + return _packageLinker = _interopRequireDefault(__webpack_require__(200)); +} + +var _index2; + +function _load_index2() { + return _index2 = __webpack_require__(52); +} + +var _index3; + +function _load_index3() { + return _index3 = __webpack_require__(55); +} + +var _autoclean; + +function _load_autoclean() { + return _autoclean = __webpack_require__(322); +} + +var _constants; + +function _load_constants() { + return _constants = _interopRequireWildcard(__webpack_require__(9)); +} + +var _normalizePattern; + +function _load_normalizePattern() { + return _normalizePattern = __webpack_require__(36); +} + +var _fs; + +function _load_fs() { + return _fs = _interopRequireWildcard(__webpack_require__(5)); +} + +var _map; + +function _load_map() { + return _map = _interopRequireDefault(__webpack_require__(28)); +} + +var _yarnVersion; + +function _load_yarnVersion() { + return _yarnVersion = __webpack_require__(112); +} + +var _generatePnpMap; + +function _load_generatePnpMap() { + return _generatePnpMap = __webpack_require__(547); +} + +var _workspaceLayout; + +function _load_workspaceLayout() { + return _workspaceLayout = _interopRequireDefault(__webpack_require__(84)); +} + +var _resolutionMap; + +function _load_resolutionMap() { + return _resolutionMap = _interopRequireDefault(__webpack_require__(203)); +} + +var _guessName; + +function _load_guessName() { + return _guessName = _interopRequireDefault(__webpack_require__(160)); +} + +var _audit; + +function _load_audit() { + return _audit = _interopRequireDefault(__webpack_require__(321)); +} + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +const deepEqual = __webpack_require__(598); + +const emoji = __webpack_require__(271); +const invariant = __webpack_require__(8); +const path = __webpack_require__(0); +const semver = __webpack_require__(20); +const uuid = __webpack_require__(111); +const ssri = __webpack_require__(71); + +const ONE_DAY = 1000 * 60 * 60 * 24; + +/** + * Try and detect the installation method for Yarn and provide a command to update it with. + */ + +function getUpdateCommand(installationMethod) { + if (installationMethod === 'tar') { + return `curl --compressed -o- -L ${(_constants || _load_constants()).YARN_INSTALLER_SH} | bash`; + } + + if (installationMethod === 'homebrew') { + return 'brew upgrade yarn'; + } + + if (installationMethod === 'deb') { + return 'sudo apt-get update && sudo apt-get install yarn'; + } + + if (installationMethod === 'rpm') { + return 'sudo yum install yarn'; + } + + if (installationMethod === 'npm') { + return 'npm install --global yarn'; + } + + if (installationMethod === 'chocolatey') { + return 'choco upgrade yarn'; + } + + if (installationMethod === 'apk') { + return 'apk update && apk add -u yarn'; + } + + return null; +} + +function getUpdateInstaller(installationMethod) { + // Windows + if (installationMethod === 'msi') { + return (_constants || _load_constants()).YARN_INSTALLER_MSI; + } + + return null; +} + +function normalizeFlags(config, rawFlags) { + const flags = { + // install + har: !!rawFlags.har, + ignorePlatform: !!rawFlags.ignorePlatform, + ignoreEngines: !!rawFlags.ignoreEngines, + ignoreScripts: !!rawFlags.ignoreScripts, + ignoreOptional: !!rawFlags.ignoreOptional, + force: !!rawFlags.force, + flat: !!rawFlags.flat, + lockfile: rawFlags.lockfile !== false, + pureLockfile: !!rawFlags.pureLockfile, + updateChecksums: !!rawFlags.updateChecksums, + skipIntegrityCheck: !!rawFlags.skipIntegrityCheck, + frozenLockfile: !!rawFlags.frozenLockfile, + linkDuplicates: !!rawFlags.linkDuplicates, + checkFiles: !!rawFlags.checkFiles, + audit: !!rawFlags.audit, + + // add + peer: !!rawFlags.peer, + dev: !!rawFlags.dev, + optional: !!rawFlags.optional, + exact: !!rawFlags.exact, + tilde: !!rawFlags.tilde, + ignoreWorkspaceRootCheck: !!rawFlags.ignoreWorkspaceRootCheck, + + // outdated, update-interactive + includeWorkspaceDeps: !!rawFlags.includeWorkspaceDeps, + + // add, remove, update + workspaceRootIsCwd: rawFlags.workspaceRootIsCwd !== false + }; + + if (config.getOption('ignore-scripts')) { + flags.ignoreScripts = true; + } + + if (config.getOption('ignore-platform')) { + flags.ignorePlatform = true; + } + + if (config.getOption('ignore-engines')) { + flags.ignoreEngines = true; + } + + if (config.getOption('ignore-optional')) { + flags.ignoreOptional = true; + } + + if (config.getOption('force')) { + flags.force = true; + } + + return flags; +} + +class Install { + constructor(flags, config, reporter, lockfile) { + this.rootManifestRegistries = []; + this.rootPatternsToOrigin = (0, (_map || _load_map()).default)(); + this.lockfile = lockfile; + this.reporter = reporter; + this.config = config; + this.flags = normalizeFlags(config, flags); + this.resolutions = (0, (_map || _load_map()).default)(); // Legacy resolutions field used for flat install mode + this.resolutionMap = new (_resolutionMap || _load_resolutionMap()).default(config); // Selective resolutions for nested dependencies + this.resolver = new (_packageResolver || _load_packageResolver()).default(config, lockfile, this.resolutionMap); + this.integrityChecker = new (_integrityChecker || _load_integrityChecker()).default(config); + this.linker = new (_packageLinker || _load_packageLinker()).default(config, this.resolver); + this.scripts = new (_packageInstallScripts || _load_packageInstallScripts()).default(config, this.resolver, this.flags.force); + } + + /** + * Create a list of dependency requests from the current directories manifests. + */ + + fetchRequestFromCwd(excludePatterns = [], ignoreUnusedPatterns = false) { + var _this = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const patterns = []; + const deps = []; + let resolutionDeps = []; + const manifest = {}; + + const ignorePatterns = []; + const usedPatterns = []; + let workspaceLayout; + + // some commands should always run in the context of the entire workspace + const cwd = _this.flags.includeWorkspaceDeps || _this.flags.workspaceRootIsCwd ? _this.config.lockfileFolder : _this.config.cwd; + + // non-workspaces are always root, otherwise check for workspace root + const cwdIsRoot = !_this.config.workspaceRootFolder || _this.config.lockfileFolder === cwd; + + // exclude package names that are in install args + const excludeNames = []; + for (var _iterator = excludePatterns, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref = _i.value; + } + + const pattern = _ref; + + if ((0, (_index3 || _load_index3()).getExoticResolver)(pattern)) { + excludeNames.push((0, (_guessName || _load_guessName()).default)(pattern)); + } else { + // extract the name + const parts = (0, (_normalizePattern || _load_normalizePattern()).normalizePattern)(pattern); + excludeNames.push(parts.name); + } + } + + const stripExcluded = function stripExcluded(manifest) { + for (var _iterator2 = excludeNames, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref2; + + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref2 = _iterator2[_i2++]; + } else { + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref2 = _i2.value; + } + + const exclude = _ref2; + + if (manifest.dependencies && manifest.dependencies[exclude]) { + delete manifest.dependencies[exclude]; + } + if (manifest.devDependencies && manifest.devDependencies[exclude]) { + delete manifest.devDependencies[exclude]; + } + if (manifest.optionalDependencies && manifest.optionalDependencies[exclude]) { + delete manifest.optionalDependencies[exclude]; + } + } + }; + + for (var _iterator3 = Object.keys((_index2 || _load_index2()).registries), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref3; + + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref3 = _iterator3[_i3++]; + } else { + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref3 = _i3.value; + } + + const registry = _ref3; + + const filename = (_index2 || _load_index2()).registries[registry].filename; + + const loc = path.join(cwd, filename); + if (!(yield (_fs || _load_fs()).exists(loc))) { + continue; + } + + _this.rootManifestRegistries.push(registry); + + const projectManifestJson = yield _this.config.readJson(loc); + yield (0, (_index || _load_index()).default)(projectManifestJson, cwd, _this.config, cwdIsRoot); + + Object.assign(_this.resolutions, projectManifestJson.resolutions); + Object.assign(manifest, projectManifestJson); + + _this.resolutionMap.init(_this.resolutions); + for (var _iterator4 = Object.keys(_this.resolutionMap.resolutionsByPackage), _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { + var _ref4; + + if (_isArray4) { + if (_i4 >= _iterator4.length) break; + _ref4 = _iterator4[_i4++]; + } else { + _i4 = _iterator4.next(); + if (_i4.done) break; + _ref4 = _i4.value; + } + + const packageName = _ref4; + + for (var _iterator8 = _this.resolutionMap.resolutionsByPackage[packageName], _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { + var _ref9; + + if (_isArray8) { + if (_i8 >= _iterator8.length) break; + _ref9 = _iterator8[_i8++]; + } else { + _i8 = _iterator8.next(); + if (_i8.done) break; + _ref9 = _i8.value; + } + + const _ref8 = _ref9; + const pattern = _ref8.pattern; + + resolutionDeps = [...resolutionDeps, { registry, pattern, optional: false, hint: 'resolution' }]; + } + } + + const pushDeps = function pushDeps(depType, manifest, { hint, optional }, isUsed) { + if (ignoreUnusedPatterns && !isUsed) { + return; + } + // We only take unused dependencies into consideration to get deterministic hoisting. + // Since flat mode doesn't care about hoisting and everything is top level and specified then we can safely + // leave these out. + if (_this.flags.flat && !isUsed) { + return; + } + const depMap = manifest[depType]; + for (const name in depMap) { + if (excludeNames.indexOf(name) >= 0) { + continue; + } + + let pattern = name; + if (!_this.lockfile.getLocked(pattern)) { + // when we use --save we save the dependency to the lockfile with just the name rather than the + // version combo + pattern += '@' + depMap[name]; + } + + // normalization made sure packages are mentioned only once + if (isUsed) { + usedPatterns.push(pattern); + } else { + ignorePatterns.push(pattern); + } + + _this.rootPatternsToOrigin[pattern] = depType; + patterns.push(pattern); + deps.push({ pattern, registry, hint, optional, workspaceName: manifest.name, workspaceLoc: manifest._loc }); + } + }; + + if (cwdIsRoot) { + pushDeps('dependencies', projectManifestJson, { hint: null, optional: false }, true); + pushDeps('devDependencies', projectManifestJson, { hint: 'dev', optional: false }, !_this.config.production); + pushDeps('optionalDependencies', projectManifestJson, { hint: 'optional', optional: true }, true); + } + + if (_this.config.workspaceRootFolder) { + const workspaceLoc = cwdIsRoot ? loc : path.join(_this.config.lockfileFolder, filename); + const workspacesRoot = path.dirname(workspaceLoc); + + let workspaceManifestJson = projectManifestJson; + if (!cwdIsRoot) { + // the manifest we read before was a child workspace, so get the root + workspaceManifestJson = yield _this.config.readJson(workspaceLoc); + yield (0, (_index || _load_index()).default)(workspaceManifestJson, workspacesRoot, _this.config, true); + } + + const workspaces = yield _this.config.resolveWorkspaces(workspacesRoot, workspaceManifestJson); + workspaceLayout = new (_workspaceLayout || _load_workspaceLayout()).default(workspaces, _this.config); + + // add virtual manifest that depends on all workspaces, this way package hoisters and resolvers will work fine + const workspaceDependencies = (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.dependencies); + for (var _iterator5 = Object.keys(workspaces), _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { + var _ref5; + + if (_isArray5) { + if (_i5 >= _iterator5.length) break; + _ref5 = _iterator5[_i5++]; + } else { + _i5 = _iterator5.next(); + if (_i5.done) break; + _ref5 = _i5.value; + } + + const workspaceName = _ref5; + + const workspaceManifest = workspaces[workspaceName].manifest; + workspaceDependencies[workspaceName] = workspaceManifest.version; + + // include dependencies from all workspaces + if (_this.flags.includeWorkspaceDeps) { + pushDeps('dependencies', workspaceManifest, { hint: null, optional: false }, true); + pushDeps('devDependencies', workspaceManifest, { hint: 'dev', optional: false }, !_this.config.production); + pushDeps('optionalDependencies', workspaceManifest, { hint: 'optional', optional: true }, true); + } + } + const virtualDependencyManifest = { + _uid: '', + name: `workspace-aggregator-${uuid.v4()}`, + version: '1.0.0', + _registry: 'npm', + _loc: workspacesRoot, + dependencies: workspaceDependencies, + devDependencies: (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.devDependencies), + optionalDependencies: (0, (_extends2 || _load_extends()).default)({}, workspaceManifestJson.optionalDependencies), + private: workspaceManifestJson.private, + workspaces: workspaceManifestJson.workspaces + }; + workspaceLayout.virtualManifestName = virtualDependencyManifest.name; + const virtualDep = {}; + virtualDep[virtualDependencyManifest.name] = virtualDependencyManifest.version; + workspaces[virtualDependencyManifest.name] = { loc: workspacesRoot, manifest: virtualDependencyManifest }; + + // ensure dependencies that should be excluded are stripped from the correct manifest + stripExcluded(cwdIsRoot ? virtualDependencyManifest : workspaces[projectManifestJson.name].manifest); + + pushDeps('workspaces', { workspaces: virtualDep }, { hint: 'workspaces', optional: false }, true); + + const implicitWorkspaceDependencies = (0, (_extends2 || _load_extends()).default)({}, workspaceDependencies); + + for (var _iterator6 = (_constants || _load_constants()).OWNED_DEPENDENCY_TYPES, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { + var _ref6; + + if (_isArray6) { + if (_i6 >= _iterator6.length) break; + _ref6 = _iterator6[_i6++]; + } else { + _i6 = _iterator6.next(); + if (_i6.done) break; + _ref6 = _i6.value; + } + + const type = _ref6; + + for (var _iterator7 = Object.keys(projectManifestJson[type] || {}), _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { + var _ref7; + + if (_isArray7) { + if (_i7 >= _iterator7.length) break; + _ref7 = _iterator7[_i7++]; + } else { + _i7 = _iterator7.next(); + if (_i7.done) break; + _ref7 = _i7.value; + } + + const dependencyName = _ref7; + + delete implicitWorkspaceDependencies[dependencyName]; + } + } + + pushDeps('dependencies', { dependencies: implicitWorkspaceDependencies }, { hint: 'workspaces', optional: false }, true); + } + + break; + } + + // inherit root flat flag + if (manifest.flat) { + _this.flags.flat = true; + } + + return { + requests: [...resolutionDeps, ...deps], + patterns, + manifest, + usedPatterns, + ignorePatterns, + workspaceLayout + }; + })(); + } + + /** + * TODO description + */ + + prepareRequests(requests) { + return requests; + } + + preparePatterns(patterns) { + return patterns; + } + preparePatternsForLinking(patterns, cwdManifest, cwdIsRoot) { + return patterns; + } + + prepareManifests() { + var _this2 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const manifests = yield _this2.config.getRootManifests(); + return manifests; + })(); + } + + bailout(patterns, workspaceLayout) { + var _this3 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + // We don't want to skip the audit - it could yield important errors + if (_this3.flags.audit) { + return false; + } + // PNP is so fast that the integrity check isn't pertinent + if (_this3.config.plugnplayEnabled) { + return false; + } + if (_this3.flags.skipIntegrityCheck || _this3.flags.force) { + return false; + } + const lockfileCache = _this3.lockfile.cache; + if (!lockfileCache) { + return false; + } + const lockfileClean = _this3.lockfile.parseResultType === 'success'; + const match = yield _this3.integrityChecker.check(patterns, lockfileCache, _this3.flags, workspaceLayout); + if (_this3.flags.frozenLockfile && (!lockfileClean || match.missingPatterns.length > 0)) { + throw new (_errors || _load_errors()).MessageError(_this3.reporter.lang('frozenLockfileError')); + } + + const haveLockfile = yield (_fs || _load_fs()).exists(path.join(_this3.config.lockfileFolder, (_constants || _load_constants()).LOCKFILE_FILENAME)); + + const lockfileIntegrityPresent = !_this3.lockfile.hasEntriesExistWithoutIntegrity(); + const integrityBailout = lockfileIntegrityPresent || !_this3.config.autoAddIntegrity; + + if (match.integrityMatches && haveLockfile && lockfileClean && integrityBailout) { + _this3.reporter.success(_this3.reporter.lang('upToDate')); + return true; + } + + if (match.integrityFileMissing && haveLockfile) { + // Integrity file missing, force script installations + _this3.scripts.setForce(true); + return false; + } + + if (match.hardRefreshRequired) { + // e.g. node version doesn't match, force script installations + _this3.scripts.setForce(true); + return false; + } + + if (!patterns.length && !match.integrityFileMissing) { + _this3.reporter.success(_this3.reporter.lang('nothingToInstall')); + yield _this3.createEmptyManifestFolders(); + yield _this3.saveLockfileAndIntegrity(patterns, workspaceLayout); + return true; + } + + return false; + })(); + } + + /** + * Produce empty folders for all used root manifests. + */ + + createEmptyManifestFolders() { + var _this4 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + if (_this4.config.modulesFolder) { + // already created + return; + } + + for (var _iterator9 = _this4.rootManifestRegistries, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { + var _ref10; + + if (_isArray9) { + if (_i9 >= _iterator9.length) break; + _ref10 = _iterator9[_i9++]; + } else { + _i9 = _iterator9.next(); + if (_i9.done) break; + _ref10 = _i9.value; + } + + const registryName = _ref10; + const folder = _this4.config.registries[registryName].folder; + + yield (_fs || _load_fs()).mkdirp(path.join(_this4.config.lockfileFolder, folder)); + } + })(); + } + + /** + * TODO description + */ + + markIgnored(patterns) { + for (var _iterator10 = patterns, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { + var _ref11; + + if (_isArray10) { + if (_i10 >= _iterator10.length) break; + _ref11 = _iterator10[_i10++]; + } else { + _i10 = _iterator10.next(); + if (_i10.done) break; + _ref11 = _i10.value; + } + + const pattern = _ref11; + + const manifest = this.resolver.getStrictResolvedPattern(pattern); + const ref = manifest._reference; + invariant(ref, 'expected package reference'); + + // just mark the package as ignored. if the package is used by a required package, the hoister + // will take care of that. + ref.ignore = true; + } + } + + /** + * helper method that gets only recent manifests + * used by global.ls command + */ + getFlattenedDeps() { + var _this5 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + var _ref12 = yield _this5.fetchRequestFromCwd(); + + const depRequests = _ref12.requests, + rawPatterns = _ref12.patterns; + + + yield _this5.resolver.init(depRequests, {}); + + const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this5.resolver.getManifests(), _this5.config); + _this5.resolver.updateManifests(manifests); + + return _this5.flatten(rawPatterns); + })(); + } + + /** + * TODO description + */ + + init() { + var _this6 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.checkUpdate(); + + // warn if we have a shrinkwrap + if (yield (_fs || _load_fs()).exists(path.join(_this6.config.lockfileFolder, (_constants || _load_constants()).NPM_SHRINKWRAP_FILENAME))) { + _this6.reporter.warn(_this6.reporter.lang('shrinkwrapWarning')); + } + + // warn if we have an npm lockfile + if (yield (_fs || _load_fs()).exists(path.join(_this6.config.lockfileFolder, (_constants || _load_constants()).NPM_LOCK_FILENAME))) { + _this6.reporter.warn(_this6.reporter.lang('npmLockfileWarning')); + } + + let flattenedTopLevelPatterns = []; + const steps = []; + + var _ref13 = yield _this6.fetchRequestFromCwd(); + + const depRequests = _ref13.requests, + rawPatterns = _ref13.patterns, + ignorePatterns = _ref13.ignorePatterns, + workspaceLayout = _ref13.workspaceLayout, + manifest = _ref13.manifest; + + let topLevelPatterns = []; + + const artifacts = yield _this6.integrityChecker.getArtifacts(); + if (artifacts) { + _this6.linker.setArtifacts(artifacts); + _this6.scripts.setArtifacts(artifacts); + } + + if (!_this6.flags.ignoreEngines && typeof manifest.engines === 'object') { + steps.push((() => { + var _ref14 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { + _this6.reporter.step(curr, total, _this6.reporter.lang('checkingManifest'), emoji.get('mag')); + yield _this6.checkCompatibility(); + }); + + return function (_x, _x2) { + return _ref14.apply(this, arguments); + }; + })()); + } + + const audit = new (_audit || _load_audit()).default(_this6.config, _this6.reporter); + let auditFoundProblems = false; + + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('resolveStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.reporter.step(curr, total, _this6.reporter.lang('resolvingPackages'), emoji.get('mag')); + yield _this6.resolver.init(_this6.prepareRequests(depRequests), { + isFlat: _this6.flags.flat, + isFrozen: _this6.flags.frozenLockfile, + workspaceLayout + }); + topLevelPatterns = _this6.preparePatterns(rawPatterns); + flattenedTopLevelPatterns = yield _this6.flatten(topLevelPatterns); + return { bailout: !_this6.flags.audit && (yield _this6.bailout(topLevelPatterns, workspaceLayout)) }; + })); + }); + + if (_this6.flags.audit) { + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('auditStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.reporter.step(curr, total, _this6.reporter.lang('auditRunning'), emoji.get('mag')); + if (_this6.flags.offline) { + _this6.reporter.warn(_this6.reporter.lang('auditOffline')); + return { bailout: false }; + } + const preparedManifests = yield _this6.prepareManifests(); + // $FlowFixMe - Flow considers `m` in the map operation to be "mixed", so does not recognize `m.object` + const mergedManifest = Object.assign({}, ...Object.values(preparedManifests).map(function (m) { + return m.object; + })); + const auditVulnerabilityCounts = yield audit.performAudit(mergedManifest, _this6.resolver, _this6.linker, topLevelPatterns); + auditFoundProblems = auditVulnerabilityCounts.info || auditVulnerabilityCounts.low || auditVulnerabilityCounts.moderate || auditVulnerabilityCounts.high || auditVulnerabilityCounts.critical; + return { bailout: yield _this6.bailout(topLevelPatterns, workspaceLayout) }; + })); + }); + } + + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('fetchStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.markIgnored(ignorePatterns); + _this6.reporter.step(curr, total, _this6.reporter.lang('fetchingPackages'), emoji.get('truck')); + const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this6.resolver.getManifests(), _this6.config); + _this6.resolver.updateManifests(manifests); + yield (_packageCompatibility || _load_packageCompatibility()).check(_this6.resolver.getManifests(), _this6.config, _this6.flags.ignoreEngines); + })); + }); + + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('linkStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + // remove integrity hash to make this operation atomic + yield _this6.integrityChecker.removeIntegrityFile(); + _this6.reporter.step(curr, total, _this6.reporter.lang('linkingDependencies'), emoji.get('link')); + flattenedTopLevelPatterns = _this6.preparePatternsForLinking(flattenedTopLevelPatterns, manifest, _this6.config.lockfileFolder === _this6.config.cwd); + yield _this6.linker.init(flattenedTopLevelPatterns, workspaceLayout, { + linkDuplicates: _this6.flags.linkDuplicates, + ignoreOptional: _this6.flags.ignoreOptional + }); + })); + }); + + if (_this6.config.plugnplayEnabled) { + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('pnpStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const pnpPath = `${_this6.config.lockfileFolder}/${(_constants || _load_constants()).PNP_FILENAME}`; + + const code = yield (0, (_generatePnpMap || _load_generatePnpMap()).generatePnpMap)(_this6.config, flattenedTopLevelPatterns, { + resolver: _this6.resolver, + reporter: _this6.reporter, + targetPath: pnpPath, + workspaceLayout + }); + + try { + const file = yield (_fs || _load_fs()).readFile(pnpPath); + if (file === code) { + return; + } + } catch (error) {} + + yield (_fs || _load_fs()).writeFile(pnpPath, code); + yield (_fs || _load_fs()).chmod(pnpPath, 0o755); + })); + }); + } + + steps.push(function (curr, total) { + return (0, (_hooks || _load_hooks()).callThroughHook)('buildStep', (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + _this6.reporter.step(curr, total, _this6.flags.force ? _this6.reporter.lang('rebuildingPackages') : _this6.reporter.lang('buildingFreshPackages'), emoji.get('hammer')); + + if (_this6.flags.ignoreScripts) { + _this6.reporter.warn(_this6.reporter.lang('ignoredScripts')); + } else { + yield _this6.scripts.init(flattenedTopLevelPatterns); + } + })); + }); + + if (_this6.flags.har) { + steps.push((() => { + var _ref21 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { + const formattedDate = new Date().toISOString().replace(/:/g, '-'); + const filename = `yarn-install_${formattedDate}.har`; + _this6.reporter.step(curr, total, _this6.reporter.lang('savingHar', filename), emoji.get('black_circle_for_record')); + yield _this6.config.requestManager.saveHar(filename); + }); + + return function (_x3, _x4) { + return _ref21.apply(this, arguments); + }; + })()); + } + + if (yield _this6.shouldClean()) { + steps.push((() => { + var _ref22 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* (curr, total) { + _this6.reporter.step(curr, total, _this6.reporter.lang('cleaningModules'), emoji.get('recycle')); + yield (0, (_autoclean || _load_autoclean()).clean)(_this6.config, _this6.reporter); + }); + + return function (_x5, _x6) { + return _ref22.apply(this, arguments); + }; + })()); + } + + let currentStep = 0; + for (var _iterator11 = steps, _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { + var _ref23; + + if (_isArray11) { + if (_i11 >= _iterator11.length) break; + _ref23 = _iterator11[_i11++]; + } else { + _i11 = _iterator11.next(); + if (_i11.done) break; + _ref23 = _i11.value; + } + + const step = _ref23; + + const stepResult = yield step(++currentStep, steps.length); + if (stepResult && stepResult.bailout) { + if (_this6.flags.audit) { + audit.summary(); + } + if (auditFoundProblems) { + _this6.reporter.warn(_this6.reporter.lang('auditRunAuditForDetails')); + } + _this6.maybeOutputUpdate(); + return flattenedTopLevelPatterns; + } + } + + // fin! + if (_this6.flags.audit) { + audit.summary(); + } + if (auditFoundProblems) { + _this6.reporter.warn(_this6.reporter.lang('auditRunAuditForDetails')); + } + yield _this6.saveLockfileAndIntegrity(topLevelPatterns, workspaceLayout); + yield _this6.persistChanges(); + _this6.maybeOutputUpdate(); + _this6.config.requestManager.clearCache(); + return flattenedTopLevelPatterns; + })(); + } + + checkCompatibility() { + var _this7 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + var _ref24 = yield _this7.fetchRequestFromCwd(); + + const manifest = _ref24.manifest; + + yield (_packageCompatibility || _load_packageCompatibility()).checkOne((0, (_extends2 || _load_extends()).default)({ _reference: {} }, manifest), _this7.config, _this7.flags.ignoreEngines); + })(); + } + + persistChanges() { + var _this8 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + // get all the different registry manifests in this folder + const manifests = yield _this8.config.getRootManifests(); + + if (yield _this8.applyChanges(manifests)) { + yield _this8.config.saveRootManifests(manifests); + } + })(); + } + + applyChanges(manifests) { + let hasChanged = false; + + if (this.config.plugnplayPersist) { + const object = manifests.npm.object; + + + if (typeof object.installConfig !== 'object') { + object.installConfig = {}; + } + + if (this.config.plugnplayEnabled && object.installConfig.pnp !== true) { + object.installConfig.pnp = true; + hasChanged = true; + } else if (!this.config.plugnplayEnabled && typeof object.installConfig.pnp !== 'undefined') { + delete object.installConfig.pnp; + hasChanged = true; + } + + if (Object.keys(object.installConfig).length === 0) { + delete object.installConfig; + } + } + + return Promise.resolve(hasChanged); + } + + /** + * Check if we should run the cleaning step. + */ + + shouldClean() { + return (_fs || _load_fs()).exists(path.join(this.config.lockfileFolder, (_constants || _load_constants()).CLEAN_FILENAME)); + } + + /** + * TODO + */ + + flatten(patterns) { + var _this9 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + if (!_this9.flags.flat) { + return patterns; + } + + const flattenedPatterns = []; + + for (var _iterator12 = _this9.resolver.getAllDependencyNamesByLevelOrder(patterns), _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) { + var _ref25; + + if (_isArray12) { + if (_i12 >= _iterator12.length) break; + _ref25 = _iterator12[_i12++]; + } else { + _i12 = _iterator12.next(); + if (_i12.done) break; + _ref25 = _i12.value; + } + + const name = _ref25; + + const infos = _this9.resolver.getAllInfoForPackageName(name).filter(function (manifest) { + const ref = manifest._reference; + invariant(ref, 'expected package reference'); + return !ref.ignore; + }); + + if (infos.length === 0) { + continue; + } + + if (infos.length === 1) { + // single version of this package + // take out a single pattern as multiple patterns may have resolved to this package + flattenedPatterns.push(_this9.resolver.patternsByPackage[name][0]); + continue; + } + + const options = infos.map(function (info) { + const ref = info._reference; + invariant(ref, 'expected reference'); + return { + // TODO `and is required by {PARENT}`, + name: _this9.reporter.lang('manualVersionResolutionOption', ref.patterns.join(', '), info.version), + + value: info.version + }; + }); + const versions = infos.map(function (info) { + return info.version; + }); + let version; + + const resolutionVersion = _this9.resolutions[name]; + if (resolutionVersion && versions.indexOf(resolutionVersion) >= 0) { + // use json `resolution` version + version = resolutionVersion; + } else { + version = yield _this9.reporter.select(_this9.reporter.lang('manualVersionResolution', name), _this9.reporter.lang('answer'), options); + _this9.resolutions[name] = version; + } + + flattenedPatterns.push(_this9.resolver.collapseAllVersionsOfPackage(name, version)); + } + + // save resolutions to their appropriate root manifest + if (Object.keys(_this9.resolutions).length) { + const manifests = yield _this9.config.getRootManifests(); + + for (const name in _this9.resolutions) { + const version = _this9.resolutions[name]; + + const patterns = _this9.resolver.patternsByPackage[name]; + if (!patterns) { + continue; + } + + let manifest; + for (var _iterator13 = patterns, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) { + var _ref26; + + if (_isArray13) { + if (_i13 >= _iterator13.length) break; + _ref26 = _iterator13[_i13++]; + } else { + _i13 = _iterator13.next(); + if (_i13.done) break; + _ref26 = _i13.value; + } + + const pattern = _ref26; + + manifest = _this9.resolver.getResolvedPattern(pattern); + if (manifest) { + break; + } + } + invariant(manifest, 'expected manifest'); + + const ref = manifest._reference; + invariant(ref, 'expected reference'); + + const object = manifests[ref.registry].object; + object.resolutions = object.resolutions || {}; + object.resolutions[name] = version; + } + + yield _this9.config.saveRootManifests(manifests); + } + + return flattenedPatterns; + })(); + } + + /** + * Remove offline tarballs that are no longer required + */ + + pruneOfflineMirror(lockfile) { + var _this10 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const mirror = _this10.config.getOfflineMirrorPath(); + if (!mirror) { + return; + } + + const requiredTarballs = new Set(); + for (const dependency in lockfile) { + const resolved = lockfile[dependency].resolved; + if (resolved) { + const basename = path.basename(resolved.split('#')[0]); + if (dependency[0] === '@' && basename[0] !== '@') { + requiredTarballs.add(`${dependency.split('/')[0]}-${basename}`); + } + requiredTarballs.add(basename); + } + } + + const mirrorFiles = yield (_fs || _load_fs()).walk(mirror); + for (var _iterator14 = mirrorFiles, _isArray14 = Array.isArray(_iterator14), _i14 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) { + var _ref27; + + if (_isArray14) { + if (_i14 >= _iterator14.length) break; + _ref27 = _iterator14[_i14++]; + } else { + _i14 = _iterator14.next(); + if (_i14.done) break; + _ref27 = _i14.value; + } + + const file = _ref27; + + const isTarball = path.extname(file.basename) === '.tgz'; + // if using experimental-pack-script-packages-in-mirror flag, don't unlink prebuilt packages + const hasPrebuiltPackage = file.relative.startsWith('prebuilt/'); + if (isTarball && !hasPrebuiltPackage && !requiredTarballs.has(file.basename)) { + yield (_fs || _load_fs()).unlink(file.absolute); + } + } + })(); + } + + /** + * Save updated integrity and lockfiles. + */ + + saveLockfileAndIntegrity(patterns, workspaceLayout) { + var _this11 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const resolvedPatterns = {}; + Object.keys(_this11.resolver.patterns).forEach(function (pattern) { + if (!workspaceLayout || !workspaceLayout.getManifestByPattern(pattern)) { + resolvedPatterns[pattern] = _this11.resolver.patterns[pattern]; + } + }); + + // TODO this code is duplicated in a few places, need a common way to filter out workspace patterns from lockfile + patterns = patterns.filter(function (p) { + return !workspaceLayout || !workspaceLayout.getManifestByPattern(p); + }); + + const lockfileBasedOnResolver = _this11.lockfile.getLockfile(resolvedPatterns); + + if (_this11.config.pruneOfflineMirror) { + yield _this11.pruneOfflineMirror(lockfileBasedOnResolver); + } + + // write integrity hash + if (!_this11.config.plugnplayEnabled) { + yield _this11.integrityChecker.save(patterns, lockfileBasedOnResolver, _this11.flags, workspaceLayout, _this11.scripts.getArtifacts()); + } + + // --no-lockfile or --pure-lockfile or --frozen-lockfile + if (_this11.flags.lockfile === false || _this11.flags.pureLockfile || _this11.flags.frozenLockfile) { + return; + } + + const lockFileHasAllPatterns = patterns.every(function (p) { + return _this11.lockfile.getLocked(p); + }); + const lockfilePatternsMatch = Object.keys(_this11.lockfile.cache || {}).every(function (p) { + return lockfileBasedOnResolver[p]; + }); + const resolverPatternsAreSameAsInLockfile = Object.keys(lockfileBasedOnResolver).every(function (pattern) { + const manifest = _this11.lockfile.getLocked(pattern); + return manifest && manifest.resolved === lockfileBasedOnResolver[pattern].resolved && deepEqual(manifest.prebuiltVariants, lockfileBasedOnResolver[pattern].prebuiltVariants); + }); + const integrityPatternsAreSameAsInLockfile = Object.keys(lockfileBasedOnResolver).every(function (pattern) { + const existingIntegrityInfo = lockfileBasedOnResolver[pattern].integrity; + if (!existingIntegrityInfo) { + // if this entry does not have an integrity, no need to re-write the lockfile because of it + return true; + } + const manifest = _this11.lockfile.getLocked(pattern); + if (manifest && manifest.integrity) { + const manifestIntegrity = ssri.stringify(manifest.integrity); + return manifestIntegrity === existingIntegrityInfo; + } + return false; + }); + + // remove command is followed by install with force, lockfile will be rewritten in any case then + if (!_this11.flags.force && _this11.lockfile.parseResultType === 'success' && lockFileHasAllPatterns && lockfilePatternsMatch && resolverPatternsAreSameAsInLockfile && integrityPatternsAreSameAsInLockfile && patterns.length) { + return; + } + + // build lockfile location + const loc = path.join(_this11.config.lockfileFolder, (_constants || _load_constants()).LOCKFILE_FILENAME); + + // write lockfile + const lockSource = (0, (_lockfile2 || _load_lockfile2()).stringify)(lockfileBasedOnResolver, false, _this11.config.enableLockfileVersions); + yield (_fs || _load_fs()).writeFilePreservingEol(loc, lockSource); + + _this11._logSuccessSaveLockfile(); + })(); + } + + _logSuccessSaveLockfile() { + this.reporter.success(this.reporter.lang('savedLockfile')); + } + + /** + * Load the dependency graph of the current install. Only does package resolving and wont write to the cwd. + */ + hydrate(ignoreUnusedPatterns) { + var _this12 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + const request = yield _this12.fetchRequestFromCwd([], ignoreUnusedPatterns); + const depRequests = request.requests, + rawPatterns = request.patterns, + ignorePatterns = request.ignorePatterns, + workspaceLayout = request.workspaceLayout; + + + yield _this12.resolver.init(depRequests, { + isFlat: _this12.flags.flat, + isFrozen: _this12.flags.frozenLockfile, + workspaceLayout + }); + yield _this12.flatten(rawPatterns); + _this12.markIgnored(ignorePatterns); + + // fetch packages, should hit cache most of the time + const manifests = yield (_packageFetcher || _load_packageFetcher()).fetch(_this12.resolver.getManifests(), _this12.config); + _this12.resolver.updateManifests(manifests); + yield (_packageCompatibility || _load_packageCompatibility()).check(_this12.resolver.getManifests(), _this12.config, _this12.flags.ignoreEngines); + + // expand minimal manifests + for (var _iterator15 = _this12.resolver.getManifests(), _isArray15 = Array.isArray(_iterator15), _i15 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) { + var _ref28; + + if (_isArray15) { + if (_i15 >= _iterator15.length) break; + _ref28 = _iterator15[_i15++]; + } else { + _i15 = _iterator15.next(); + if (_i15.done) break; + _ref28 = _i15.value; + } + + const manifest = _ref28; + + const ref = manifest._reference; + invariant(ref, 'expected reference'); + const type = ref.remote.type; + // link specifier won't ever hit cache + + let loc = ''; + if (type === 'link') { + continue; + } else if (type === 'workspace') { + if (!ref.remote.reference) { + continue; + } + loc = ref.remote.reference; + } else { + loc = _this12.config.generateModuleCachePath(ref); + } + const newPkg = yield _this12.config.readManifest(loc); + yield _this12.resolver.updateManifest(ref, newPkg); + } + + return request; + })(); + } + + /** + * Check for updates every day and output a nag message if there's a newer version. + */ + + checkUpdate() { + if (this.config.nonInteractive) { + // don't show upgrade dialog on CI or non-TTY terminals + return; + } + + // don't check if disabled + if (this.config.getOption('disable-self-update-check')) { + return; + } + + // only check for updates once a day + const lastUpdateCheck = Number(this.config.getOption('lastUpdateCheck')) || 0; + if (lastUpdateCheck && Date.now() - lastUpdateCheck < ONE_DAY) { + return; + } + + // don't bug for updates on tagged releases + if ((_yarnVersion || _load_yarnVersion()).version.indexOf('-') >= 0) { + return; + } + + this._checkUpdate().catch(() => { + // swallow errors + }); + } + + _checkUpdate() { + var _this13 = this; + + return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () { + let latestVersion = yield _this13.config.requestManager.request({ + url: (_constants || _load_constants()).SELF_UPDATE_VERSION_URL + }); + invariant(typeof latestVersion === 'string', 'expected string'); + latestVersion = latestVersion.trim(); + if (!semver.valid(latestVersion)) { + return; + } + + // ensure we only check for updates periodically + _this13.config.registries.yarn.saveHomeConfig({ + lastUpdateCheck: Date.now() + }); + + if (semver.gt(latestVersion, (_yarnVersion || _load_yarnVersion()).version)) { + const installationMethod = yield (0, (_yarnVersion || _load_yarnVersion()).getInstallationMethod)(); + _this13.maybeOutputUpdate = function () { + _this13.reporter.warn(_this13.reporter.lang('yarnOutdated', latestVersion, (_yarnVersion || _load_yarnVersion()).version)); + + const command = getUpdateCommand(installationMethod); + if (command) { + _this13.reporter.info(_this13.reporter.lang('yarnOutdatedCommand')); + _this13.reporter.command(command); + } else { + const installer = getUpdateInstaller(installationMethod); + if (installer) { + _this13.reporter.info(_this13.reporter.lang('yarnOutdatedInstaller', installer)); + } + } + }; + } + })(); + } + + /** + * Method to override with a possible upgrade message. + */ + + maybeOutputUpdate() {} +} + +exports.Install = Install; +function hasWrapper(commander, args) { + return true; +} + +function setFlags(commander) { + commander.description('Yarn install is used to install all dependencies for a project.'); + commander.usage('install [flags]'); + commander.option('-A, --audit', 'Run vulnerability audit on installed packages'); + commander.option('-g, --global', 'DEPRECATED'); + commander.option('-S, --save', 'DEPRECATED - save package to your `dependencies`'); + commander.option('-D, --save-dev', 'DEPRECATED - save package to your `devDependencies`'); + commander.option('-P, --save-peer', 'DEPRECATED - save package to your `peerDependencies`'); + commander.option('-O, --save-optional', 'DEPRECATED - save package to your `optionalDependencies`'); + commander.option('-E, --save-exact', 'DEPRECATED'); + commander.option('-T, --save-tilde', 'DEPRECATED'); +} + +/***/ }), +/* 34 */ +/***/ (function(module, exports, __webpack_require__) { + +var isObject = __webpack_require__(49); +module.exports = function (it) { + if (!isObject(it)) throw TypeError(it + ' is not an object!'); + return it; +}; + + +/***/ }), +/* 35 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return SubjectSubscriber; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Subject; }); +/* unused harmony export AnonymousSubject */ +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_tslib__ = __webpack_require__(1); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Observable__ = __webpack_require__(10); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Subscriber__ = __webpack_require__(6); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Subscription__ = __webpack_require__(24); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__ = __webpack_require__(180); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__SubjectSubscription__ = __webpack_require__(394); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__internal_symbol_rxSubscriber__ = __webpack_require__(289); +/** PURE_IMPORTS_START tslib,_Observable,_Subscriber,_Subscription,_util_ObjectUnsubscribedError,_SubjectSubscription,_internal_symbol_rxSubscriber PURE_IMPORTS_END */ + + + + + + + +var SubjectSubscriber = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](SubjectSubscriber, _super); + function SubjectSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.destination = destination; + return _this; + } + return SubjectSubscriber; +}(__WEBPACK_IMPORTED_MODULE_2__Subscriber__["a" /* Subscriber */])); + +var Subject = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](Subject, _super); + function Subject() { + var _this = _super.call(this) || this; + _this.observers = []; + _this.closed = false; + _this.isStopped = false; + _this.hasError = false; + _this.thrownError = null; + return _this; + } + Subject.prototype[__WEBPACK_IMPORTED_MODULE_6__internal_symbol_rxSubscriber__["a" /* rxSubscriber */]] = function () { + return new SubjectSubscriber(this); + }; + Subject.prototype.lift = function (operator) { + var subject = new AnonymousSubject(this, this); + subject.operator = operator; + return subject; + }; + Subject.prototype.next = function (value) { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + if (!this.isStopped) { + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].next(value); + } + } + }; + Subject.prototype.error = function (err) { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + this.hasError = true; + this.thrownError = err; + this.isStopped = true; + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].error(err); + } + this.observers.length = 0; + }; + Subject.prototype.complete = function () { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + this.isStopped = true; + var observers = this.observers; + var len = observers.length; + var copy = observers.slice(); + for (var i = 0; i < len; i++) { + copy[i].complete(); + } + this.observers.length = 0; + }; + Subject.prototype.unsubscribe = function () { + this.isStopped = true; + this.closed = true; + this.observers = null; + }; + Subject.prototype._trySubscribe = function (subscriber) { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + else { + return _super.prototype._trySubscribe.call(this, subscriber); + } + }; + Subject.prototype._subscribe = function (subscriber) { + if (this.closed) { + throw new __WEBPACK_IMPORTED_MODULE_4__util_ObjectUnsubscribedError__["a" /* ObjectUnsubscribedError */](); + } + else if (this.hasError) { + subscriber.error(this.thrownError); + return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; + } + else if (this.isStopped) { + subscriber.complete(); + return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; + } + else { + this.observers.push(subscriber); + return new __WEBPACK_IMPORTED_MODULE_5__SubjectSubscription__["a" /* SubjectSubscription */](this, subscriber); + } + }; + Subject.prototype.asObservable = function () { + var observable = new __WEBPACK_IMPORTED_MODULE_1__Observable__["a" /* Observable */](); + observable.source = this; + return observable; + }; + Subject.create = function (destination, source) { + return new AnonymousSubject(destination, source); + }; + return Subject; +}(__WEBPACK_IMPORTED_MODULE_1__Observable__["a" /* Observable */])); + +var AnonymousSubject = /*@__PURE__*/ (function (_super) { + __WEBPACK_IMPORTED_MODULE_0_tslib__["a" /* __extends */](AnonymousSubject, _super); + function AnonymousSubject(destination, source) { + var _this = _super.call(this) || this; + _this.destination = destination; + _this.source = source; + return _this; + } + AnonymousSubject.prototype.next = function (value) { + var destination = this.destination; + if (destination && destination.next) { + destination.next(value); + } + }; + AnonymousSubject.prototype.error = function (err) { + var destination = this.destination; + if (destination && destination.error) { + this.destination.error(err); + } + }; + AnonymousSubject.prototype.complete = function () { + var destination = this.destination; + if (destination && destination.complete) { + this.destination.complete(); + } + }; + AnonymousSubject.prototype._subscribe = function (subscriber) { + var source = this.source; + if (source) { + return this.source.subscribe(subscriber); + } + else { + return __WEBPACK_IMPORTED_MODULE_3__Subscription__["a" /* Subscription */].EMPTY; + } + }; + return AnonymousSubject; +}(Subject)); + +//# sourceMappingURL=Subject.js.map + + +/***/ }), +/* 36 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.normalizePattern = normalizePattern; + +/** + * Explode and normalize a pattern into its name and range. + */ + +function normalizePattern(pattern) { + let hasVersion = false; + let range = 'latest'; + let name = pattern; + + // if we're a scope then remove the @ and add it back later + let isScoped = false; + if (name[0] === '@') { + isScoped = true; + name = name.slice(1); + } + + // take first part as the name + const parts = name.split('@'); + if (parts.length > 1) { + name = parts.shift(); + range = parts.join('@'); + + if (range) { + hasVersion = true; + } else { + range = '*'; + } + } + + // add back @ scope suffix + if (isScoped) { + name = `@${name}`; + } + + return { name, range, hasVersion }; +} + +/***/ }), +/* 37 */ +/***/ (function(module, exports, __webpack_require__) { + +/* WEBPACK VAR INJECTION */(function(module) {var __WEBPACK_AMD_DEFINE_RESULT__;/** + * @license + * Lodash + * Copyright JS Foundation and other contributors + * Released under MIT license + * Based on Underscore.js 1.8.3 + * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + */ +;(function() { + + /** Used as a safe reference for `undefined` in pre-ES5 environments. */ + var undefined; + + /** Used as the semantic version number. */ + var VERSION = '4.17.10'; + + /** Used as the size to enable large array optimizations. */ + var LARGE_ARRAY_SIZE = 200; + + /** Error message constants. */ + var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.', + FUNC_ERROR_TEXT = 'Expected a function'; + + /** Used to stand-in for `undefined` hash values. */ + var HASH_UNDEFINED = '__lodash_hash_undefined__'; + + /** Used as the maximum memoize cache size. */ + var MAX_MEMOIZE_SIZE = 500; + + /** Used as the internal argument placeholder. */ + var PLACEHOLDER = '__lodash_placeholder__'; + + /** Used to compose bitmasks for cloning. */ + var CLONE_DEEP_FLAG = 1, + CLONE_FLAT_FLAG = 2, + CLONE_SYMBOLS_FLAG = 4; + + /** Used to compose bitmasks for value comparisons. */ + var COMPARE_PARTIAL_FLAG = 1, + COMPARE_UNORDERED_FLAG = 2; + + /** Used to compose bitmasks for function metadata. */ + var WRAP_BIND_FLAG = 1, + WRAP_BIND_KEY_FLAG = 2, + WRAP_CURRY_BOUND_FLAG = 4, + WRAP_CURRY_FLAG = 8, + WRAP_CURRY_RIGHT_FLAG = 16, + WRAP_PARTIAL_FLAG = 32, + WRAP_PARTIAL_RIGHT_FLAG = 64, + WRAP_ARY_FLAG = 128, + WRAP_REARG_FLAG = 256, + WRAP_FLIP_FLAG = 512; + + /** Used as default options for `_.truncate`. */ + var DEFAULT_TRUNC_LENGTH = 30, + DEFAULT_TRUNC_OMISSION = '...'; + + /** Used to detect hot functions by number of calls within a span of milliseconds. */ + var HOT_COUNT = 800, + HOT_SPAN = 16; + + /** Used to indicate the type of lazy iteratees. */ + var LAZY_FILTER_FLAG = 1, + LAZY_MAP_FLAG = 2, + LAZY_WHILE_FLAG = 3; + + /** Used as references for various `Number` constants. */ + var INFINITY = 1 / 0, + MAX_SAFE_INTEGER = 9007199254740991, + MAX_INTEGER = 1.7976931348623157e+308, + NAN = 0 / 0; + + /** Used as references for the maximum length and index of an array. */ + var MAX_ARRAY_LENGTH = 4294967295, + MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, + HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; + + /** Used to associate wrap methods with their bit flags. */ + var wrapFlags = [ + ['ary', WRAP_ARY_FLAG], + ['bind', WRAP_BIND_FLAG], + ['bindKey', WRAP_BIND_KEY_FLAG], + ['curry', WRAP_CURRY_FLAG], + ['curryRight', WRAP_CURRY_RIGHT_FLAG], + ['flip', WRAP_FLIP_FLAG], + ['partial', WRAP_PARTIAL_FLAG], + ['partialRight', WRAP_PARTIAL_RIGHT_FLAG], + ['rearg', WRAP_REARG_FLAG] + ]; + + /** `Object#toString` result references. */ + var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + asyncTag = '[object AsyncFunction]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + domExcTag = '[object DOMException]', + errorTag = '[object Error]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + mapTag = '[object Map]', + numberTag = '[object Number]', + nullTag = '[object Null]', + objectTag = '[object Object]', + promiseTag = '[object Promise]', + proxyTag = '[object Proxy]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + symbolTag = '[object Symbol]', + undefinedTag = '[object Undefined]', + weakMapTag = '[object WeakMap]', + weakSetTag = '[object WeakSet]'; + + var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + + /** Used to match empty string literals in compiled template source. */ + var reEmptyStringLeading = /\b__p \+= '';/g, + reEmptyStringMiddle = /\b(__p \+=) '' \+/g, + reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; + + /** Used to match HTML entities and HTML characters. */ + var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, + reUnescapedHtml = /[&<>"']/g, + reHasEscapedHtml = RegExp(reEscapedHtml.source), + reHasUnescapedHtml = RegExp(reUnescapedHtml.source); + + /** Used to match template delimiters. */ + var reEscape = /<%-([\s\S]+?)%>/g, + reEvaluate = /<%([\s\S]+?)%>/g, + reInterpolate = /<%=([\s\S]+?)%>/g; + + /** Used to match property names within property paths. */ + var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/, + rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; + + /** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ + var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, + reHasRegExpChar = RegExp(reRegExpChar.source); + + /** Used to match leading and trailing whitespace. */ + var reTrim = /^\s+|\s+$/g, + reTrimStart = /^\s+/, + reTrimEnd = /\s+$/; + + /** Used to match wrap detail comments. */ + var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, + reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, + reSplitDetails = /,? & /; + + /** Used to match words composed of alphanumeric characters. */ + var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; + + /** Used to match backslashes in property paths. */ + var reEscapeChar = /\\(\\)?/g; + + /** + * Used to match + * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components). + */ + var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; + + /** Used to match `RegExp` flags from their coerced string values. */ + var reFlags = /\w*$/; + + /** Used to detect bad signed hexadecimal string values. */ + var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; + + /** Used to detect binary string values. */ + var reIsBinary = /^0b[01]+$/i; + + /** Used to detect host constructors (Safari). */ + var reIsHostCtor = /^\[object .+?Constructor\]$/; + + /** Used to detect octal string values. */ + var reIsOctal = /^0o[0-7]+$/i; + + /** Used to detect unsigned integer values. */ + var reIsUint = /^(?:0|[1-9]\d*)$/; + + /** Used to match Latin Unicode letters (excluding mathematical operators). */ + var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g; + + /** Used to ensure capturing order of template delimiters. */ + var reNoMatch = /($^)/; + + /** Used to match unescaped characters in compiled string literals. */ + var reUnescapedString = /['\n\r\u2028\u2029\\]/g; + + /** Used to compose unicode character classes. */ + var rsAstralRange = '\\ud800-\\udfff', + rsComboMarksRange = '\\u0300-\\u036f', + reComboHalfMarksRange = '\\ufe20-\\ufe2f', + rsComboSymbolsRange = '\\u20d0-\\u20ff', + rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, + rsDingbatRange = '\\u2700-\\u27bf', + rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff', + rsMathOpRange = '\\xac\\xb1\\xd7\\xf7', + rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf', + rsPunctuationRange = '\\u2000-\\u206f', + rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000', + rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde', + rsVarRange = '\\ufe0e\\ufe0f', + rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange; + + /** Used to compose unicode capture groups. */ + var rsApos = "['\u2019]", + rsAstral = '[' + rsAstralRange + ']', + rsBreak = '[' + rsBreakRange + ']', + rsCombo = '[' + rsComboRange + ']', + rsDigits = '\\d+', + rsDingbat = '[' + rsDingbatRange + ']', + rsLower = '[' + rsLowerRange + ']', + rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']', + rsFitz = '\\ud83c[\\udffb-\\udfff]', + rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', + rsNonAstral = '[^' + rsAstralRange + ']', + rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', + rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', + rsUpper = '[' + rsUpperRange + ']', + rsZWJ = '\\u200d'; + + /** Used to compose unicode regexes. */ + var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')', + rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')', + rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?', + rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?', + reOptMod = rsModifier + '?', + rsOptVar = '[' + rsVarRange + ']?', + rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', + rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])', + rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])', + rsSeq = rsOptVar + reOptMod + rsOptJoin, + rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq, + rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; + + /** Used to match apostrophes. */ + var reApos = RegExp(rsApos, 'g'); + + /** + * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and + * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols). + */ + var reComboMark = RegExp(rsCombo, 'g'); + + /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ + var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); + + /** Used to match complex or compound words. */ + var reUnicodeWord = RegExp([ + rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')', + rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')', + rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower, + rsUpper + '+' + rsOptContrUpper, + rsOrdUpper, + rsOrdLower, + rsDigits, + rsEmoji + ].join('|'), 'g'); + + /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ + var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); + + /** Used to detect strings that need a more robust regexp to match words. */ + var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/; + + /** Used to assign default `context` object properties. */ + var contextProps = [ + 'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array', + 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', + 'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', + 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', + '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout' + ]; + + /** Used to make template sourceURLs easier to identify. */ + var templateCounter = -1; + + /** Used to identify `toStringTag` values of typed arrays. */ + var typedArrayTags = {}; + typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = + typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = + typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = + typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = + typedArrayTags[uint32Tag] = true; + typedArrayTags[argsTag] = typedArrayTags[arrayTag] = + typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = + typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = + typedArrayTags[errorTag] = typedArrayTags[funcTag] = + typedArrayTags[mapTag] = typedArrayTags[numberTag] = + typedArrayTags[objectTag] = typedArrayTags[regexpTag] = + typedArrayTags[setTag] = typedArrayTags[stringTag] = + typedArrayTags[weakMapTag] = false; + + /** Used to identify `toStringTag` values supported by `_.clone`. */ + var cloneableTags = {}; + cloneableTags[argsTag] = cloneableTags[arrayTag] = + cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = + cloneableTags[boolTag] = cloneableTags[dateTag] = + cloneableTags[float32Tag] = cloneableTags[float64Tag] = + cloneableTags[int8Tag] = cloneableTags[int16Tag] = + cloneableTags[int32Tag] = cloneableTags[mapTag] = + cloneableTags[numberTag] = cloneableTags[objectTag] = + cloneableTags[regexpTag] = cloneableTags[setTag] = + cloneableTags[stringTag] = cloneableTags[symbolTag] = + cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = + cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; + cloneableTags[errorTag] = cloneableTags[funcTag] = + cloneableTags[weakMapTag] = false; + + /** Used to map Latin Unicode letters to basic Latin letters. */ + var deburredLetters = { + // Latin-1 Supplement block. + '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', + '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', + '\xc7': 'C', '\xe7': 'c', + '\xd0': 'D', '\xf0': 'd', + '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', + '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', + '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', + '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', + '\xd1': 'N', '\xf1': 'n', + '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', + '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', + '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', + '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', + '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', + '\xc6': 'Ae', '\xe6': 'ae', + '\xde': 'Th', '\xfe': 'th', + '\xdf': 'ss', + // Latin Extended-A block. + '\u0100': 'A', '\u0102': 'A', '\u0104': 'A', + '\u0101': 'a', '\u0103': 'a', '\u0105': 'a', + '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C', + '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c', + '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd', + '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E', + '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e', + '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G', + '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g', + '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h', + '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I', + '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i', + '\u0134': 'J', '\u0135': 'j', + '\u0136': 'K', '\u0137': 'k', '\u0138': 'k', + '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L', + '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l', + '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N', + '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n', + '\u014c': 'O', '\u014e': 'O', '\u0150': 'O', + '\u014d': 'o', '\u014f': 'o', '\u0151': 'o', + '\u0154': 'R', '\u0156': 'R', '\u0158': 'R', + '\u0155': 'r', '\u0157': 'r', '\u0159': 'r', + '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S', + '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's', + '\u0162': 'T', '\u0164': 'T', '\u0166': 'T', + '\u0163': 't', '\u0165': 't', '\u0167': 't', + '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U', + '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u', + '\u0174': 'W', '\u0175': 'w', + '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y', + '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z', + '\u017a': 'z', '\u017c': 'z', '\u017e': 'z', + '\u0132': 'IJ', '\u0133': 'ij', + '\u0152': 'Oe', '\u0153': 'oe', + '\u0149': "'n", '\u017f': 's' + }; + + /** Used to map characters to HTML entities. */ + var htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + + /** Used to map HTML entities to characters. */ + var htmlUnescapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'" + }; + + /** Used to escape characters for inclusion in compiled string literals. */ + var stringEscapes = { + '\\': '\\', + "'": "'", + '\n': 'n', + '\r': 'r', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + /** Built-in method references without a dependency on `root`. */ + var freeParseFloat = parseFloat, + freeParseInt = parseInt; + + /** Detect free variable `global` from Node.js. */ + var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + + /** Detect free variable `self`. */ + var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + + /** Used as a reference to the global object. */ + var root = freeGlobal || freeSelf || Function('return this')(); + + /** Detect free variable `exports`. */ + var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + + /** Detect free variable `module`. */ + var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + + /** Detect the popular CommonJS extension `module.exports`. */ + var moduleExports = freeModule && freeModule.exports === freeExports; + + /** Detect free variable `process` from Node.js. */ + var freeProcess = moduleExports && freeGlobal.process; + + /** Used to access faster Node.js helpers. */ + var nodeUtil = (function() { + try { + // Use `util.types` for Node.js 10+. + var types = freeModule && freeModule.require && freeModule.require('util').types; + + if (types) { + return types; + } + + // Legacy `process.binding('util')` for Node.js < 10. + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) {} + }()); + + /* Node.js helper references. */ + var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer, + nodeIsDate = nodeUtil && nodeUtil.isDate, + nodeIsMap = nodeUtil && nodeUtil.isMap, + nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, + nodeIsSet = nodeUtil && nodeUtil.isSet, + nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; + + /*--------------------------------------------------------------------------*/ + + /** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ + function apply(func, thisArg, args) { + switch (args.length) { + case 0: return func.call(thisArg); + case 1: return func.call(thisArg, args[0]); + case 2: return func.call(thisArg, args[0], args[1]); + case 3: return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); + } + + /** + * A specialized version of `baseAggregator` for arrays. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform keys. + * @param {Object} accumulator The initial aggregated object. + * @returns {Function} Returns `accumulator`. + */ + function arrayAggregator(array, setter, iteratee, accumulator) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + var value = array[index]; + setter(accumulator, value, iteratee(value), array); + } + return accumulator; + } + + /** + * A specialized version of `_.forEach` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEach(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.forEachRight` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEachRight(array, iteratee) { + var length = array == null ? 0 : array.length; + + while (length--) { + if (iteratee(array[length], length, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.every` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + */ + function arrayEvery(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } + } + return true; + } + + /** + * A specialized version of `_.filter` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function arrayFilter(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result[resIndex++] = value; + } + } + return result; + } + + /** + * A specialized version of `_.includes` for arrays without support for + * specifying an index to search from. + * + * @private + * @param {Array} [array] The array to inspect. + * @param {*} target The value to search for. + * @returns {boolean} Returns `true` if `target` is found, else `false`. + */ + function arrayIncludes(array, value) { + var length = array == null ? 0 : array.length; + return !!length && baseIndexOf(array, value, 0) > -1; + } + + /** + * This function is like `arrayIncludes` except that it accepts a comparator. + * + * @private + * @param {Array} [array] The array to inspect. + * @param {*} target The value to search for. + * @param {Function} comparator The comparator invoked per element. + * @returns {boolean} Returns `true` if `target` is found, else `false`. + */ + function arrayIncludesWith(array, value, comparator) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (comparator(value, array[index])) { + return true; + } + } + return false; + } + + /** + * A specialized version of `_.map` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function arrayMap(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; + } + + /** + * Appends the elements of `values` to `array`. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to append. + * @returns {Array} Returns `array`. + */ + function arrayPush(array, values) { + var index = -1, + length = values.length, + offset = array.length; + + while (++index < length) { + array[offset + index] = values[index]; + } + return array; + } + + /** + * A specialized version of `_.reduce` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initAccum] Specify using the first element of `array` as + * the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduce(array, iteratee, accumulator, initAccum) { + var index = -1, + length = array == null ? 0 : array.length; + + if (initAccum && length) { + accumulator = array[++index]; + } + while (++index < length) { + accumulator = iteratee(accumulator, array[index], index, array); + } + return accumulator; + } + + /** + * A specialized version of `_.reduceRight` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initAccum] Specify using the last element of `array` as + * the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduceRight(array, iteratee, accumulator, initAccum) { + var length = array == null ? 0 : array.length; + if (initAccum && length) { + accumulator = array[--length]; + } + while (length--) { + accumulator = iteratee(accumulator, array[length], length, array); + } + return accumulator; + } + + /** + * A specialized version of `_.some` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function arraySome(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; + } + + /** + * Gets the size of an ASCII `string`. + * + * @private + * @param {string} string The string inspect. + * @returns {number} Returns the string size. + */ + var asciiSize = baseProperty('length'); + + /** + * Converts an ASCII `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function asciiToArray(string) { + return string.split(''); + } + + /** + * Splits an ASCII `string` into an array of its words. + * + * @private + * @param {string} The string to inspect. + * @returns {Array} Returns the words of `string`. + */ + function asciiWords(string) { + return string.match(reAsciiWord) || []; + } + + /** + * The base implementation of methods like `_.findKey` and `_.findLastKey`, + * without support for iteratee shorthands, which iterates over `collection` + * using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the found element or its key, else `undefined`. + */ + function baseFindKey(collection, predicate, eachFunc) { + var result; + eachFunc(collection, function(value, key, collection) { + if (predicate(value, key, collection)) { + result = key; + return false; + } + }); + return result; + } + + /** + * The base implementation of `_.findIndex` and `_.findLastIndex` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {number} fromIndex The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseFindIndex(array, predicate, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 1 : -1); + + while ((fromRight ? index-- : ++index < length)) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.indexOf` without `fromIndex` bounds checks. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOf(array, value, fromIndex) { + return value === value + ? strictIndexOf(array, value, fromIndex) + : baseFindIndex(array, baseIsNaN, fromIndex); + } + + /** + * This function is like `baseIndexOf` except that it accepts a comparator. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @param {Function} comparator The comparator invoked per element. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOfWith(array, value, fromIndex, comparator) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (comparator(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.isNaN` without support for number objects. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + */ + function baseIsNaN(value) { + return value !== value; + } + + /** + * The base implementation of `_.mean` and `_.meanBy` without support for + * iteratee shorthands. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {number} Returns the mean. + */ + function baseMean(array, iteratee) { + var length = array == null ? 0 : array.length; + return length ? (baseSum(array, iteratee) / length) : NAN; + } + + /** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new accessor function. + */ + function baseProperty(key) { + return function(object) { + return object == null ? undefined : object[key]; + }; + } + + /** + * The base implementation of `_.propertyOf` without support for deep paths. + * + * @private + * @param {Object} object The object to query. + * @returns {Function} Returns the new accessor function. + */ + function basePropertyOf(object) { + return function(key) { + return object == null ? undefined : object[key]; + }; + } + + /** + * The base implementation of `_.reduce` and `_.reduceRight`, without support + * for iteratee shorthands, which iterates over `collection` using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} accumulator The initial value. + * @param {boolean} initAccum Specify using the first or last element of + * `collection` as the initial value. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the accumulated value. + */ + function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { + eachFunc(collection, function(value, index, collection) { + accumulator = initAccum + ? (initAccum = false, value) + : iteratee(accumulator, value, index, collection); + }); + return accumulator; + } + + /** + * The base implementation of `_.sortBy` which uses `comparer` to define the + * sort order of `array` and replaces criteria objects with their corresponding + * values. + * + * @private + * @param {Array} array The array to sort. + * @param {Function} comparer The function to define sort order. + * @returns {Array} Returns `array`. + */ + function baseSortBy(array, comparer) { + var length = array.length; + + array.sort(comparer); + while (length--) { + array[length] = array[length].value; + } + return array; + } + + /** + * The base implementation of `_.sum` and `_.sumBy` without support for + * iteratee shorthands. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {number} Returns the sum. + */ + function baseSum(array, iteratee) { + var result, + index = -1, + length = array.length; + + while (++index < length) { + var current = iteratee(array[index]); + if (current !== undefined) { + result = result === undefined ? current : (result + current); + } + } + return result; + } + + /** + * The base implementation of `_.times` without support for iteratee shorthands + * or max array length checks. + * + * @private + * @param {number} n The number of times to invoke `iteratee`. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the array of results. + */ + function baseTimes(n, iteratee) { + var index = -1, + result = Array(n); + + while (++index < n) { + result[index] = iteratee(index); + } + return result; + } + + /** + * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array + * of key-value pairs for `object` corresponding to the property names of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the key-value pairs. + */ + function baseToPairs(object, props) { + return arrayMap(props, function(key) { + return [key, object[key]]; + }); + } + + /** + * The base implementation of `_.unary` without support for storing metadata. + * + * @private + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + */ + function baseUnary(func) { + return function(value) { + return func(value); + }; + } + + /** + * The base implementation of `_.values` and `_.valuesIn` which creates an + * array of `object` property values corresponding to the property names + * of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the array of property values. + */ + function baseValues(object, props) { + return arrayMap(props, function(key) { + return object[key]; + }); + } + + /** + * Checks if a `cache` value for `key` exists. + * + * @private + * @param {Object} cache The cache to query. + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function cacheHas(cache, key) { + return cache.has(key); + } + + /** + * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the first unmatched string symbol. + */ + function charsStartIndex(strSymbols, chrSymbols) { + var index = -1, + length = strSymbols.length; + + while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; + } + + /** + * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the last unmatched string symbol. + */ + function charsEndIndex(strSymbols, chrSymbols) { + var index = strSymbols.length; + + while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} + return index; + } + + /** + * Gets the number of `placeholder` occurrences in `array`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} placeholder The placeholder to search for. + * @returns {number} Returns the placeholder count. + */ + function countHolders(array, placeholder) { + var length = array.length, + result = 0; + + while (length--) { + if (array[length] === placeholder) { + ++result; + } + } + return result; + } + + /** + * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A + * letters to basic Latin letters. + * + * @private + * @param {string} letter The matched letter to deburr. + * @returns {string} Returns the deburred letter. + */ + var deburrLetter = basePropertyOf(deburredLetters); + + /** + * Used by `_.escape` to convert characters to HTML entities. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + var escapeHtmlChar = basePropertyOf(htmlEscapes); + + /** + * Used by `_.template` to escape characters for inclusion in compiled string literals. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + function escapeStringChar(chr) { + return '\\' + stringEscapes[chr]; + } + + /** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function getValue(object, key) { + return object == null ? undefined : object[key]; + } + + /** + * Checks if `string` contains Unicode symbols. + * + * @private + * @param {string} string The string to inspect. + * @returns {boolean} Returns `true` if a symbol is found, else `false`. + */ + function hasUnicode(string) { + return reHasUnicode.test(string); + } + + /** + * Checks if `string` contains a word composed of Unicode symbols. + * + * @private + * @param {string} string The string to inspect. + * @returns {boolean} Returns `true` if a word is found, else `false`. + */ + function hasUnicodeWord(string) { + return reHasUnicodeWord.test(string); + } + + /** + * Converts `iterator` to an array. + * + * @private + * @param {Object} iterator The iterator to convert. + * @returns {Array} Returns the converted array. + */ + function iteratorToArray(iterator) { + var data, + result = []; + + while (!(data = iterator.next()).done) { + result.push(data.value); + } + return result; + } + + /** + * Converts `map` to its key-value pairs. + * + * @private + * @param {Object} map The map to convert. + * @returns {Array} Returns the key-value pairs. + */ + function mapToArray(map) { + var index = -1, + result = Array(map.size); + + map.forEach(function(value, key) { + result[++index] = [key, value]; + }); + return result; + } + + /** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ + function overArg(func, transform) { + return function(arg) { + return func(transform(arg)); + }; + } + + /** + * Replaces all `placeholder` elements in `array` with an internal placeholder + * and returns an array of their indexes. + * + * @private + * @param {Array} array The array to modify. + * @param {*} placeholder The placeholder to replace. + * @returns {Array} Returns the new array of placeholder indexes. + */ + function replaceHolders(array, placeholder) { + var index = -1, + length = array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (value === placeholder || value === PLACEHOLDER) { + array[index] = PLACEHOLDER; + result[resIndex++] = index; + } + } + return result; + } + + /** + * Gets the value at `key`, unless `key` is "__proto__". + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function safeGet(object, key) { + return key == '__proto__' + ? undefined + : object[key]; + } + + /** + * Converts `set` to an array of its values. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the values. + */ + function setToArray(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = value; + }); + return result; + } + + /** + * Converts `set` to its value-value pairs. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the value-value pairs. + */ + function setToPairs(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function(value) { + result[++index] = [value, value]; + }); + return result; + } + + /** + * A specialized version of `_.indexOf` which performs strict equality + * comparisons of values, i.e. `===`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function strictIndexOf(array, value, fromIndex) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * A specialized version of `_.lastIndexOf` which performs strict equality + * comparisons of values, i.e. `===`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function strictLastIndexOf(array, value, fromIndex) { + var index = fromIndex + 1; + while (index--) { + if (array[index] === value) { + return index; + } + } + return index; + } + + /** + * Gets the number of symbols in `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the string size. + */ + function stringSize(string) { + return hasUnicode(string) + ? unicodeSize(string) + : asciiSize(string); + } + + /** + * Converts `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function stringToArray(string) { + return hasUnicode(string) + ? unicodeToArray(string) + : asciiToArray(string); + } + + /** + * Used by `_.unescape` to convert HTML entities to characters. + * + * @private + * @param {string} chr The matched character to unescape. + * @returns {string} Returns the unescaped character. + */ + var unescapeHtmlChar = basePropertyOf(htmlUnescapes); + + /** + * Gets the size of a Unicode `string`. + * + * @private + * @param {string} string The string inspect. + * @returns {number} Returns the string size. + */ + function unicodeSize(string) { + var result = reUnicode.lastIndex = 0; + while (reUnicode.test(string)) { + ++result; + } + return result; + } + + /** + * Converts a Unicode `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function unicodeToArray(string) { + return string.match(reUnicode) || []; + } + + /** + * Splits a Unicode `string` into an array of its words. + * + * @private + * @param {string} The string to inspect. + * @returns {Array} Returns the words of `string`. + */ + function unicodeWords(string) { + return string.match(reUnicodeWord) || []; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Create a new pristine `lodash` function using the `context` object. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Util + * @param {Object} [context=root] The context object. + * @returns {Function} Returns a new `lodash` function. + * @example + * + * _.mixin({ 'foo': _.constant('foo') }); + * + * var lodash = _.runInContext(); + * lodash.mixin({ 'bar': lodash.constant('bar') }); + * + * _.isFunction(_.foo); + * // => true + * _.isFunction(_.bar); + * // => false + * + * lodash.isFunction(lodash.foo); + * // => false + * lodash.isFunction(lodash.bar); + * // => true + * + * // Create a suped-up `defer` in Node.js. + * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer; + */ + var runInContext = (function runInContext(context) { + context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps)); + + /** Built-in constructor references. */ + var Array = context.Array, + Date = context.Date, + Error = context.Error, + Function = context.Function, + Math = context.Math, + Object = context.Object, + RegExp = context.RegExp, + String = context.String, + TypeError = context.TypeError; + + /** Used for built-in method references. */ + var arrayProto = Array.prototype, + funcProto = Function.prototype, + objectProto = Object.prototype; + + /** Used to detect overreaching core-js shims. */ + var coreJsData = context['__core-js_shared__']; + + /** Used to resolve the decompiled source of functions. */ + var funcToString = funcProto.toString; + + /** Used to check objects for own properties. */ + var hasOwnProperty = objectProto.hasOwnProperty; + + /** Used to generate unique IDs. */ + var idCounter = 0; + + /** Used to detect methods masquerading as native. */ + var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; + }()); + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString = objectProto.toString; + + /** Used to infer the `Object` constructor. */ + var objectCtorString = funcToString.call(Object); + + /** Used to restore the original `_` reference in `_.noConflict`. */ + var oldDash = root._; + + /** Used to detect if a method is native. */ + var reIsNative = RegExp('^' + + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' + ); + + /** Built-in value references. */ + var Buffer = moduleExports ? context.Buffer : undefined, + Symbol = context.Symbol, + Uint8Array = context.Uint8Array, + allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined, + getPrototype = overArg(Object.getPrototypeOf, Object), + objectCreate = Object.create, + propertyIsEnumerable = objectProto.propertyIsEnumerable, + splice = arrayProto.splice, + spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined, + symIterator = Symbol ? Symbol.iterator : undefined, + symToStringTag = Symbol ? Symbol.toStringTag : undefined; + + var defineProperty = (function() { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} + }()); + + /** Mocked built-ins. */ + var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout, + ctxNow = Date && Date.now !== root.Date.now && Date.now, + ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout; + + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeCeil = Math.ceil, + nativeFloor = Math.floor, + nativeGetSymbols = Object.getOwnPropertySymbols, + nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, + nativeIsFinite = context.isFinite, + nativeJoin = arrayProto.join, + nativeKeys = overArg(Object.keys, Object), + nativeMax = Math.max, + nativeMin = Math.min, + nativeNow = Date.now, + nativeParseInt = context.parseInt, + nativeRandom = Math.random, + nativeReverse = arrayProto.reverse; + + /* Built-in method references that are verified to be native. */ + var DataView = getNative(context, 'DataView'), + Map = getNative(context, 'Map'), + Promise = getNative(context, 'Promise'), + Set = getNative(context, 'Set'), + WeakMap = getNative(context, 'WeakMap'), + nativeCreate = getNative(Object, 'create'); + + /** Used to store function metadata. */ + var metaMap = WeakMap && new WeakMap; + + /** Used to lookup unminified function names. */ + var realNames = {}; + + /** Used to detect maps, sets, and weakmaps. */ + var dataViewCtorString = toSource(DataView), + mapCtorString = toSource(Map), + promiseCtorString = toSource(Promise), + setCtorString = toSource(Set), + weakMapCtorString = toSource(WeakMap); + + /** Used to convert symbols to primitives and strings. */ + var symbolProto = Symbol ? Symbol.prototype : undefined, + symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, + symbolToString = symbolProto ? symbolProto.toString : undefined; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` object which wraps `value` to enable implicit method + * chain sequences. Methods that operate on and return arrays, collections, + * and functions can be chained together. Methods that retrieve a single value + * or may return a primitive value will automatically end the chain sequence + * and return the unwrapped value. Otherwise, the value must be unwrapped + * with `_#value`. + * + * Explicit chain sequences, which must be unwrapped with `_#value`, may be + * enabled using `_.chain`. + * + * The execution of chained methods is lazy, that is, it's deferred until + * `_#value` is implicitly or explicitly called. + * + * Lazy evaluation allows several methods to support shortcut fusion. + * Shortcut fusion is an optimization to merge iteratee calls; this avoids + * the creation of intermediate arrays and can greatly reduce the number of + * iteratee executions. Sections of a chain sequence qualify for shortcut + * fusion if the section is applied to an array and iteratees accept only + * one argument. The heuristic for whether a section qualifies for shortcut + * fusion is subject to change. + * + * Chaining is supported in custom builds as long as the `_#value` method is + * directly or indirectly included in the build. + * + * In addition to lodash methods, wrappers have `Array` and `String` methods. + * + * The wrapper `Array` methods are: + * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` + * + * The wrapper `String` methods are: + * `replace` and `split` + * + * The wrapper methods that support shortcut fusion are: + * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, + * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, + * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` + * + * The chainable wrapper methods are: + * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, + * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, + * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, + * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, + * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, + * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, + * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, + * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, + * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, + * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, + * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, + * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, + * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, + * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, + * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, + * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, + * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, + * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, + * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, + * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, + * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, + * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, + * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, + * `zipObject`, `zipObjectDeep`, and `zipWith` + * + * The wrapper methods that are **not** chainable by default are: + * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, + * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, + * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, + * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, + * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`, + * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`, + * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`, + * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, + * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, + * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, + * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, + * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, + * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`, + * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`, + * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, + * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`, + * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, + * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`, + * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, + * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`, + * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`, + * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`, + * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`, + * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`, + * `upperFirst`, `value`, and `words` + * + * @name _ + * @constructor + * @category Seq + * @param {*} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var wrapped = _([1, 2, 3]); + * + * // Returns an unwrapped value. + * wrapped.reduce(_.add); + * // => 6 + * + * // Returns a wrapped value. + * var squares = wrapped.map(square); + * + * _.isArray(squares); + * // => false + * + * _.isArray(squares.value()); + * // => true + */ + function lodash(value) { + if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { + if (value instanceof LodashWrapper) { + return value; + } + if (hasOwnProperty.call(value, '__wrapped__')) { + return wrapperClone(value); + } + } + return new LodashWrapper(value); + } + + /** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} proto The object to inherit from. + * @returns {Object} Returns the new object. + */ + var baseCreate = (function() { + function object() {} + return function(proto) { + if (!isObject(proto)) { + return {}; + } + if (objectCreate) { + return objectCreate(proto); + } + object.prototype = proto; + var result = new object; + object.prototype = undefined; + return result; + }; + }()); + + /** + * The function whose prototype chain sequence wrappers inherit from. + * + * @private + */ + function baseLodash() { + // No operation performed. + } + + /** + * The base constructor for creating `lodash` wrapper objects. + * + * @private + * @param {*} value The value to wrap. + * @param {boolean} [chainAll] Enable explicit method chain sequences. + */ + function LodashWrapper(value, chainAll) { + this.__wrapped__ = value; + this.__actions__ = []; + this.__chain__ = !!chainAll; + this.__index__ = 0; + this.__values__ = undefined; + } + + /** + * By default, the template delimiters used by lodash are like those in + * embedded Ruby (ERB) as well as ES2015 template strings. Change the + * following template settings to use alternative delimiters. + * + * @static + * @memberOf _ + * @type {Object} + */ + lodash.templateSettings = { + + /** + * Used to detect `data` property values to be HTML-escaped. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'escape': reEscape, + + /** + * Used to detect code to be evaluated. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'evaluate': reEvaluate, + + /** + * Used to detect `data` property values to inject. + * + * @memberOf _.templateSettings + * @type {RegExp} + */ + 'interpolate': reInterpolate, + + /** + * Used to reference the data object in the template text. + * + * @memberOf _.templateSettings + * @type {string} + */ + 'variable': '', + + /** + * Used to import variables into the compiled template. + * + * @memberOf _.templateSettings + * @type {Object} + */ + 'imports': { + + /** + * A reference to the `lodash` function. + * + * @memberOf _.templateSettings.imports + * @type {Function} + */ + '_': lodash + } + }; + + // Ensure wrappers are instances of `baseLodash`. + lodash.prototype = baseLodash.prototype; + lodash.prototype.constructor = lodash; + + LodashWrapper.prototype = baseCreate(baseLodash.prototype); + LodashWrapper.prototype.constructor = LodashWrapper; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. + * + * @private + * @constructor + * @param {*} value The value to wrap. + */ + function LazyWrapper(value) { + this.__wrapped__ = value; + this.__actions__ = []; + this.__dir__ = 1; + this.__filtered__ = false; + this.__iteratees__ = []; + this.__takeCount__ = MAX_ARRAY_LENGTH; + this.__views__ = []; + } + + /** + * Creates a clone of the lazy wrapper object. + * + * @private + * @name clone + * @memberOf LazyWrapper + * @returns {Object} Returns the cloned `LazyWrapper` object. + */ + function lazyClone() { + var result = new LazyWrapper(this.__wrapped__); + result.__actions__ = copyArray(this.__actions__); + result.__dir__ = this.__dir__; + result.__filtered__ = this.__filtered__; + result.__iteratees__ = copyArray(this.__iteratees__); + result.__takeCount__ = this.__takeCount__; + result.__views__ = copyArray(this.__views__); + return result; + } + + /** + * Reverses the direction of lazy iteration. + * + * @private + * @name reverse + * @memberOf LazyWrapper + * @returns {Object} Returns the new reversed `LazyWrapper` object. + */ + function lazyReverse() { + if (this.__filtered__) { + var result = new LazyWrapper(this); + result.__dir__ = -1; + result.__filtered__ = true; + } else { + result = this.clone(); + result.__dir__ *= -1; + } + return result; + } + + /** + * Extracts the unwrapped value from its lazy wrapper. + * + * @private + * @name value + * @memberOf LazyWrapper + * @returns {*} Returns the unwrapped value. + */ + function lazyValue() { + var array = this.__wrapped__.value(), + dir = this.__dir__, + isArr = isArray(array), + isRight = dir < 0, + arrLength = isArr ? array.length : 0, + view = getView(0, arrLength, this.__views__), + start = view.start, + end = view.end, + length = end - start, + index = isRight ? end : (start - 1), + iteratees = this.__iteratees__, + iterLength = iteratees.length, + resIndex = 0, + takeCount = nativeMin(length, this.__takeCount__); + + if (!isArr || (!isRight && arrLength == length && takeCount == length)) { + return baseWrapperValue(array, this.__actions__); + } + var result = []; + + outer: + while (length-- && resIndex < takeCount) { + index += dir; + + var iterIndex = -1, + value = array[index]; + + while (++iterIndex < iterLength) { + var data = iteratees[iterIndex], + iteratee = data.iteratee, + type = data.type, + computed = iteratee(value); + + if (type == LAZY_MAP_FLAG) { + value = computed; + } else if (!computed) { + if (type == LAZY_FILTER_FLAG) { + continue outer; + } else { + break outer; + } + } + } + result[resIndex++] = value; + } + return result; + } + + // Ensure `LazyWrapper` is an instance of `baseLodash`. + LazyWrapper.prototype = baseCreate(baseLodash.prototype); + LazyWrapper.prototype.constructor = LazyWrapper; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a hash object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ + function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; + } + + /** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; + } + + /** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED ? undefined : result; + } + return hasOwnProperty.call(data, key) ? data[key] : undefined; + } + + /** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); + } + + /** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ + function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + return this; + } + + // Add methods to `Hash`. + Hash.prototype.clear = hashClear; + Hash.prototype['delete'] = hashDelete; + Hash.prototype.get = hashGet; + Hash.prototype.has = hashHas; + Hash.prototype.set = hashSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ + function listCacheClear() { + this.__data__ = []; + this.size = 0; + } + + /** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + --this.size; + return true; + } + + /** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + return index < 0 ? undefined : data[index][1]; + } + + /** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; + } + + /** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ + function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; + } + + // Add methods to `ListCache`. + ListCache.prototype.clear = listCacheClear; + ListCache.prototype['delete'] = listCacheDelete; + ListCache.prototype.get = listCacheGet; + ListCache.prototype.has = listCacheHas; + ListCache.prototype.set = listCacheSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a map cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function MapCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ + function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map || ListCache), + 'string': new Hash + }; + } + + /** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); + this.size -= result ? 1 : 0; + return result; + } + + /** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function mapCacheGet(key) { + return getMapData(this, key).get(key); + } + + /** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function mapCacheHas(key) { + return getMapData(this, key).has(key); + } + + /** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ + function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; + + data.set(key, value); + this.size += data.size == size ? 0 : 1; + return this; + } + + // Add methods to `MapCache`. + MapCache.prototype.clear = mapCacheClear; + MapCache.prototype['delete'] = mapCacheDelete; + MapCache.prototype.get = mapCacheGet; + MapCache.prototype.has = mapCacheHas; + MapCache.prototype.set = mapCacheSet; + + /*------------------------------------------------------------------------*/ + + /** + * + * Creates an array cache object to store unique values. + * + * @private + * @constructor + * @param {Array} [values] The values to cache. + */ + function SetCache(values) { + var index = -1, + length = values == null ? 0 : values.length; + + this.__data__ = new MapCache; + while (++index < length) { + this.add(values[index]); + } + } + + /** + * Adds `value` to the array cache. + * + * @private + * @name add + * @memberOf SetCache + * @alias push + * @param {*} value The value to cache. + * @returns {Object} Returns the cache instance. + */ + function setCacheAdd(value) { + this.__data__.set(value, HASH_UNDEFINED); + return this; + } + + /** + * Checks if `value` is in the array cache. + * + * @private + * @name has + * @memberOf SetCache + * @param {*} value The value to search for. + * @returns {number} Returns `true` if `value` is found, else `false`. + */ + function setCacheHas(value) { + return this.__data__.has(value); + } + + // Add methods to `SetCache`. + SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; + SetCache.prototype.has = setCacheHas; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a stack cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Stack(entries) { + var data = this.__data__ = new ListCache(entries); + this.size = data.size; + } + + /** + * Removes all key-value entries from the stack. + * + * @private + * @name clear + * @memberOf Stack + */ + function stackClear() { + this.__data__ = new ListCache; + this.size = 0; + } + + /** + * Removes `key` and its value from the stack. + * + * @private + * @name delete + * @memberOf Stack + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function stackDelete(key) { + var data = this.__data__, + result = data['delete'](key); + + this.size = data.size; + return result; + } + + /** + * Gets the stack value for `key`. + * + * @private + * @name get + * @memberOf Stack + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function stackGet(key) { + return this.__data__.get(key); + } + + /** + * Checks if a stack value for `key` exists. + * + * @private + * @name has + * @memberOf Stack + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function stackHas(key) { + return this.__data__.has(key); + } + + /** + * Sets the stack `key` to `value`. + * + * @private + * @name set + * @memberOf Stack + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the stack cache instance. + */ + function stackSet(key, value) { + var data = this.__data__; + if (data instanceof ListCache) { + var pairs = data.__data__; + if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { + pairs.push([key, value]); + this.size = ++data.size; + return this; + } + data = this.__data__ = new MapCache(pairs); + } + data.set(key, value); + this.size = data.size; + return this; + } + + // Add methods to `Stack`. + Stack.prototype.clear = stackClear; + Stack.prototype['delete'] = stackDelete; + Stack.prototype.get = stackGet; + Stack.prototype.has = stackHas; + Stack.prototype.set = stackSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of the enumerable property names of the array-like `value`. + * + * @private + * @param {*} value The value to query. + * @param {boolean} inherited Specify returning inherited property names. + * @returns {Array} Returns the array of property names. + */ + function arrayLikeKeys(value, inherited) { + var isArr = isArray(value), + isArg = !isArr && isArguments(value), + isBuff = !isArr && !isArg && isBuffer(value), + isType = !isArr && !isArg && !isBuff && isTypedArray(value), + skipIndexes = isArr || isArg || isBuff || isType, + result = skipIndexes ? baseTimes(value.length, String) : [], + length = result.length; + + for (var key in value) { + if ((inherited || hasOwnProperty.call(value, key)) && + !(skipIndexes && ( + // Safari 9 has enumerable `arguments.length` in strict mode. + key == 'length' || + // Node.js 0.10 has enumerable non-index properties on buffers. + (isBuff && (key == 'offset' || key == 'parent')) || + // PhantomJS 2 has enumerable non-index properties on typed arrays. + (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || + // Skip index properties. + isIndex(key, length) + ))) { + result.push(key); + } + } + return result; + } + + /** + * A specialized version of `_.sample` for arrays. + * + * @private + * @param {Array} array The array to sample. + * @returns {*} Returns the random element. + */ + function arraySample(array) { + var length = array.length; + return length ? array[baseRandom(0, length - 1)] : undefined; + } + + /** + * A specialized version of `_.sampleSize` for arrays. + * + * @private + * @param {Array} array The array to sample. + * @param {number} n The number of elements to sample. + * @returns {Array} Returns the random elements. + */ + function arraySampleSize(array, n) { + return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length)); + } + + /** + * A specialized version of `_.shuffle` for arrays. + * + * @private + * @param {Array} array The array to shuffle. + * @returns {Array} Returns the new shuffled array. + */ + function arrayShuffle(array) { + return shuffleSelf(copyArray(array)); + } + + /** + * This function is like `assignValue` except that it doesn't assign + * `undefined` values. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignMergeValue(object, key, value) { + if ((value !== undefined && !eq(object[key], value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } + } + + /** + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } + } + + /** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; + } + + /** + * Aggregates elements of `collection` on `accumulator` with keys transformed + * by `iteratee` and values set by `setter`. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform keys. + * @param {Object} accumulator The initial aggregated object. + * @returns {Function} Returns `accumulator`. + */ + function baseAggregator(collection, setter, iteratee, accumulator) { + baseEach(collection, function(value, key, collection) { + setter(accumulator, value, iteratee(value), collection); + }); + return accumulator; + } + + /** + * The base implementation of `_.assign` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ + function baseAssign(object, source) { + return object && copyObject(source, keys(source), object); + } + + /** + * The base implementation of `_.assignIn` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ + function baseAssignIn(object, source) { + return object && copyObject(source, keysIn(source), object); + } + + /** + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function baseAssignValue(object, key, value) { + if (key == '__proto__' && defineProperty) { + defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } + } + + /** + * The base implementation of `_.at` without support for individual paths. + * + * @private + * @param {Object} object The object to iterate over. + * @param {string[]} paths The property paths to pick. + * @returns {Array} Returns the picked elements. + */ + function baseAt(object, paths) { + var index = -1, + length = paths.length, + result = Array(length), + skip = object == null; + + while (++index < length) { + result[index] = skip ? undefined : get(object, paths[index]); + } + return result; + } + + /** + * The base implementation of `_.clamp` which doesn't coerce arguments. + * + * @private + * @param {number} number The number to clamp. + * @param {number} [lower] The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the clamped number. + */ + function baseClamp(number, lower, upper) { + if (number === number) { + if (upper !== undefined) { + number = number <= upper ? number : upper; + } + if (lower !== undefined) { + number = number >= lower ? number : lower; + } + } + return number; + } + + /** + * The base implementation of `_.clone` and `_.cloneDeep` which tracks + * traversed objects. + * + * @private + * @param {*} value The value to clone. + * @param {boolean} bitmask The bitmask flags. + * 1 - Deep clone + * 2 - Flatten inherited properties + * 4 - Clone symbols + * @param {Function} [customizer] The function to customize cloning. + * @param {string} [key] The key of `value`. + * @param {Object} [object] The parent object of `value`. + * @param {Object} [stack] Tracks traversed objects and their clone counterparts. + * @returns {*} Returns the cloned value. + */ + function baseClone(value, bitmask, customizer, key, object, stack) { + var result, + isDeep = bitmask & CLONE_DEEP_FLAG, + isFlat = bitmask & CLONE_FLAT_FLAG, + isFull = bitmask & CLONE_SYMBOLS_FLAG; + + if (customizer) { + result = object ? customizer(value, key, object, stack) : customizer(value); + } + if (result !== undefined) { + return result; + } + if (!isObject(value)) { + return value; + } + var isArr = isArray(value); + if (isArr) { + result = initCloneArray(value); + if (!isDeep) { + return copyArray(value, result); + } + } else { + var tag = getTag(value), + isFunc = tag == funcTag || tag == genTag; + + if (isBuffer(value)) { + return cloneBuffer(value, isDeep); + } + if (tag == objectTag || tag == argsTag || (isFunc && !object)) { + result = (isFlat || isFunc) ? {} : initCloneObject(value); + if (!isDeep) { + return isFlat + ? copySymbolsIn(value, baseAssignIn(result, value)) + : copySymbols(value, baseAssign(result, value)); + } + } else { + if (!cloneableTags[tag]) { + return object ? value : {}; + } + result = initCloneByTag(value, tag, isDeep); + } + } + // Check for circular references and return its corresponding clone. + stack || (stack = new Stack); + var stacked = stack.get(value); + if (stacked) { + return stacked; + } + stack.set(value, result); + + if (isSet(value)) { + value.forEach(function(subValue) { + result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack)); + }); + + return result; + } + + if (isMap(value)) { + value.forEach(function(subValue, key) { + result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack)); + }); + + return result; + } + + var keysFunc = isFull + ? (isFlat ? getAllKeysIn : getAllKeys) + : (isFlat ? keysIn : keys); + + var props = isArr ? undefined : keysFunc(value); + arrayEach(props || value, function(subValue, key) { + if (props) { + key = subValue; + subValue = value[key]; + } + // Recursively populate clone (susceptible to call stack limits). + assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack)); + }); + return result; + } + + /** + * The base implementation of `_.conforms` which doesn't clone `source`. + * + * @private + * @param {Object} source The object of property predicates to conform to. + * @returns {Function} Returns the new spec function. + */ + function baseConforms(source) { + var props = keys(source); + return function(object) { + return baseConformsTo(object, source, props); + }; + } + + /** + * The base implementation of `_.conformsTo` which accepts `props` to check. + * + * @private + * @param {Object} object The object to inspect. + * @param {Object} source The object of property predicates to conform to. + * @returns {boolean} Returns `true` if `object` conforms, else `false`. + */ + function baseConformsTo(object, source, props) { + var length = props.length; + if (object == null) { + return !length; + } + object = Object(object); + while (length--) { + var key = props[length], + predicate = source[key], + value = object[key]; + + if ((value === undefined && !(key in object)) || !predicate(value)) { + return false; + } + } + return true; + } + + /** + * The base implementation of `_.delay` and `_.defer` which accepts `args` + * to provide to `func`. + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {Array} args The arguments to provide to `func`. + * @returns {number|Object} Returns the timer id or timeout object. + */ + function baseDelay(func, wait, args) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return setTimeout(function() { func.apply(undefined, args); }, wait); + } + + /** + * The base implementation of methods like `_.difference` without support + * for excluding multiple arrays or iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Array} values The values to exclude. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + */ + function baseDifference(array, values, iteratee, comparator) { + var index = -1, + includes = arrayIncludes, + isCommon = true, + length = array.length, + result = [], + valuesLength = values.length; + + if (!length) { + return result; + } + if (iteratee) { + values = arrayMap(values, baseUnary(iteratee)); + } + if (comparator) { + includes = arrayIncludesWith; + isCommon = false; + } + else if (values.length >= LARGE_ARRAY_SIZE) { + includes = cacheHas; + isCommon = false; + values = new SetCache(values); + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee == null ? value : iteratee(value); + + value = (comparator || value !== 0) ? value : 0; + if (isCommon && computed === computed) { + var valuesIndex = valuesLength; + while (valuesIndex--) { + if (values[valuesIndex] === computed) { + continue outer; + } + } + result.push(value); + } + else if (!includes(values, computed, comparator)) { + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.forEach` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + */ + var baseEach = createBaseEach(baseForOwn); + + /** + * The base implementation of `_.forEachRight` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + */ + var baseEachRight = createBaseEach(baseForOwnRight, true); + + /** + * The base implementation of `_.every` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false` + */ + function baseEvery(collection, predicate) { + var result = true; + baseEach(collection, function(value, index, collection) { + result = !!predicate(value, index, collection); + return result; + }); + return result; + } + + /** + * The base implementation of methods like `_.max` and `_.min` which accepts a + * `comparator` to determine the extremum value. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The iteratee invoked per iteration. + * @param {Function} comparator The comparator used to compare values. + * @returns {*} Returns the extremum value. + */ + function baseExtremum(array, iteratee, comparator) { + var index = -1, + length = array.length; + + while (++index < length) { + var value = array[index], + current = iteratee(value); + + if (current != null && (computed === undefined + ? (current === current && !isSymbol(current)) + : comparator(current, computed) + )) { + var computed = current, + result = value; + } + } + return result; + } + + /** + * The base implementation of `_.fill` without an iteratee call guard. + * + * @private + * @param {Array} array The array to fill. + * @param {*} value The value to fill `array` with. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns `array`. + */ + function baseFill(array, value, start, end) { + var length = array.length; + + start = toInteger(start); + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = (end === undefined || end > length) ? length : toInteger(end); + if (end < 0) { + end += length; + } + end = start > end ? 0 : toLength(end); + while (start < end) { + array[start++] = value; + } + return array; + } + + /** + * The base implementation of `_.filter` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function baseFilter(collection, predicate) { + var result = []; + baseEach(collection, function(value, index, collection) { + if (predicate(value, index, collection)) { + result.push(value); + } + }); + return result; + } + + /** + * The base implementation of `_.flatten` with support for restricting flattening. + * + * @private + * @param {Array} array The array to flatten. + * @param {number} depth The maximum recursion depth. + * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. + * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. + * @param {Array} [result=[]] The initial result value. + * @returns {Array} Returns the new flattened array. + */ + function baseFlatten(array, depth, predicate, isStrict, result) { + var index = -1, + length = array.length; + + predicate || (predicate = isFlattenable); + result || (result = []); + + while (++index < length) { + var value = array[index]; + if (depth > 0 && predicate(value)) { + if (depth > 1) { + // Recursively flatten arrays (susceptible to call stack limits). + baseFlatten(value, depth - 1, predicate, isStrict, result); + } else { + arrayPush(result, value); + } + } else if (!isStrict) { + result[result.length] = value; + } + } + return result; + } + + /** + * The base implementation of `baseForOwn` which iterates over `object` + * properties returned by `keysFunc` and invokes `iteratee` for each property. + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseFor = createBaseFor(); + + /** + * This function is like `baseFor` except that it iterates over properties + * in the opposite order. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseForRight = createBaseFor(true); + + /** + * The base implementation of `_.forOwn` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwn(object, iteratee) { + return object && baseFor(object, iteratee, keys); + } + + /** + * The base implementation of `_.forOwnRight` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwnRight(object, iteratee) { + return object && baseForRight(object, iteratee, keys); + } + + /** + * The base implementation of `_.functions` which creates an array of + * `object` function property names filtered from `props`. + * + * @private + * @param {Object} object The object to inspect. + * @param {Array} props The property names to filter. + * @returns {Array} Returns the function names. + */ + function baseFunctions(object, props) { + return arrayFilter(props, function(key) { + return isFunction(object[key]); + }); + } + + /** + * The base implementation of `_.get` without support for default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @returns {*} Returns the resolved value. + */ + function baseGet(object, path) { + path = castPath(path, object); + + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[toKey(path[index++])]; + } + return (index && index == length) ? object : undefined; + } + + /** + * The base implementation of `getAllKeys` and `getAllKeysIn` which uses + * `keysFunc` and `symbolsFunc` to get the enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Function} keysFunc The function to get the keys of `object`. + * @param {Function} symbolsFunc The function to get the symbols of `object`. + * @returns {Array} Returns the array of property names and symbols. + */ + function baseGetAllKeys(object, keysFunc, symbolsFunc) { + var result = keysFunc(object); + return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); + } + + /** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); + } + + /** + * The base implementation of `_.gt` which doesn't coerce arguments. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than `other`, + * else `false`. + */ + function baseGt(value, other) { + return value > other; + } + + /** + * The base implementation of `_.has` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ + function baseHas(object, key) { + return object != null && hasOwnProperty.call(object, key); + } + + /** + * The base implementation of `_.hasIn` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ + function baseHasIn(object, key) { + return object != null && key in Object(object); + } + + /** + * The base implementation of `_.inRange` which doesn't coerce arguments. + * + * @private + * @param {number} number The number to check. + * @param {number} start The start of the range. + * @param {number} end The end of the range. + * @returns {boolean} Returns `true` if `number` is in the range, else `false`. + */ + function baseInRange(number, start, end) { + return number >= nativeMin(start, end) && number < nativeMax(start, end); + } + + /** + * The base implementation of methods like `_.intersection`, without support + * for iteratee shorthands, that accepts an array of arrays to inspect. + * + * @private + * @param {Array} arrays The arrays to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of shared values. + */ + function baseIntersection(arrays, iteratee, comparator) { + var includes = comparator ? arrayIncludesWith : arrayIncludes, + length = arrays[0].length, + othLength = arrays.length, + othIndex = othLength, + caches = Array(othLength), + maxLength = Infinity, + result = []; + + while (othIndex--) { + var array = arrays[othIndex]; + if (othIndex && iteratee) { + array = arrayMap(array, baseUnary(iteratee)); + } + maxLength = nativeMin(array.length, maxLength); + caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120)) + ? new SetCache(othIndex && array) + : undefined; + } + array = arrays[0]; + + var index = -1, + seen = caches[0]; + + outer: + while (++index < length && result.length < maxLength) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + value = (comparator || value !== 0) ? value : 0; + if (!(seen + ? cacheHas(seen, computed) + : includes(result, computed, comparator) + )) { + othIndex = othLength; + while (--othIndex) { + var cache = caches[othIndex]; + if (!(cache + ? cacheHas(cache, computed) + : includes(arrays[othIndex], computed, comparator)) + ) { + continue outer; + } + } + if (seen) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.invert` and `_.invertBy` which inverts + * `object` with values transformed by `iteratee` and set by `setter`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform values. + * @param {Object} accumulator The initial inverted object. + * @returns {Function} Returns `accumulator`. + */ + function baseInverter(object, setter, iteratee, accumulator) { + baseForOwn(object, function(value, key, object) { + setter(accumulator, iteratee(value), key, object); + }); + return accumulator; + } + + /** + * The base implementation of `_.invoke` without support for individual + * method arguments. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the method to invoke. + * @param {Array} args The arguments to invoke the method with. + * @returns {*} Returns the result of the invoked method. + */ + function baseInvoke(object, path, args) { + path = castPath(path, object); + object = parent(object, path); + var func = object == null ? object : object[toKey(last(path))]; + return func == null ? undefined : apply(func, object, args); + } + + /** + * The base implementation of `_.isArguments`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + */ + function baseIsArguments(value) { + return isObjectLike(value) && baseGetTag(value) == argsTag; + } + + /** + * The base implementation of `_.isArrayBuffer` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. + */ + function baseIsArrayBuffer(value) { + return isObjectLike(value) && baseGetTag(value) == arrayBufferTag; + } + + /** + * The base implementation of `_.isDate` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a date object, else `false`. + */ + function baseIsDate(value) { + return isObjectLike(value) && baseGetTag(value) == dateTag; + } + + /** + * The base implementation of `_.isEqual` which supports partial comparisons + * and tracks traversed objects. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {boolean} bitmask The bitmask flags. + * 1 - Unordered comparison + * 2 - Partial comparison + * @param {Function} [customizer] The function to customize comparisons. + * @param {Object} [stack] Tracks traversed `value` and `other` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ + function baseIsEqual(value, other, bitmask, customizer, stack) { + if (value === other) { + return true; + } + if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { + return value !== value && other !== other; + } + return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); + } + + /** + * A specialized version of `baseIsEqual` for arrays and objects which performs + * deep comparisons and tracks traversed objects enabling objects with circular + * references to be compared. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} [stack] Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { + var objIsArr = isArray(object), + othIsArr = isArray(other), + objTag = objIsArr ? arrayTag : getTag(object), + othTag = othIsArr ? arrayTag : getTag(other); + + objTag = objTag == argsTag ? objectTag : objTag; + othTag = othTag == argsTag ? objectTag : othTag; + + var objIsObj = objTag == objectTag, + othIsObj = othTag == objectTag, + isSameTag = objTag == othTag; + + if (isSameTag && isBuffer(object)) { + if (!isBuffer(other)) { + return false; + } + objIsArr = true; + objIsObj = false; + } + if (isSameTag && !objIsObj) { + stack || (stack = new Stack); + return (objIsArr || isTypedArray(object)) + ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) + : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); + } + if (!(bitmask & COMPARE_PARTIAL_FLAG)) { + var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), + othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); + + if (objIsWrapped || othIsWrapped) { + var objUnwrapped = objIsWrapped ? object.value() : object, + othUnwrapped = othIsWrapped ? other.value() : other; + + stack || (stack = new Stack); + return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); + } + } + if (!isSameTag) { + return false; + } + stack || (stack = new Stack); + return equalObjects(object, other, bitmask, customizer, equalFunc, stack); + } + + /** + * The base implementation of `_.isMap` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a map, else `false`. + */ + function baseIsMap(value) { + return isObjectLike(value) && getTag(value) == mapTag; + } + + /** + * The base implementation of `_.isMatch` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Array} matchData The property names, values, and compare flags to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + */ + function baseIsMatch(object, source, matchData, customizer) { + var index = matchData.length, + length = index, + noCustomizer = !customizer; + + if (object == null) { + return !length; + } + object = Object(object); + while (index--) { + var data = matchData[index]; + if ((noCustomizer && data[2]) + ? data[1] !== object[data[0]] + : !(data[0] in object) + ) { + return false; + } + } + while (++index < length) { + data = matchData[index]; + var key = data[0], + objValue = object[key], + srcValue = data[1]; + + if (noCustomizer && data[2]) { + if (objValue === undefined && !(key in object)) { + return false; + } + } else { + var stack = new Stack; + if (customizer) { + var result = customizer(objValue, srcValue, key, object, source, stack); + } + if (!(result === undefined + ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack) + : result + )) { + return false; + } + } + } + return true; + } + + /** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ + function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; + } + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); + } + + /** + * The base implementation of `_.isRegExp` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + */ + function baseIsRegExp(value) { + return isObjectLike(value) && baseGetTag(value) == regexpTag; + } + + /** + * The base implementation of `_.isSet` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a set, else `false`. + */ + function baseIsSet(value) { + return isObjectLike(value) && getTag(value) == setTag; + } + + /** + * The base implementation of `_.isTypedArray` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + */ + function baseIsTypedArray(value) { + return isObjectLike(value) && + isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; + } + + /** + * The base implementation of `_.iteratee`. + * + * @private + * @param {*} [value=_.identity] The value to convert to an iteratee. + * @returns {Function} Returns the iteratee. + */ + function baseIteratee(value) { + // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. + // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. + if (typeof value == 'function') { + return value; + } + if (value == null) { + return identity; + } + if (typeof value == 'object') { + return isArray(value) + ? baseMatchesProperty(value[0], value[1]) + : baseMatches(value); + } + return property(value); + } + + /** + * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeys(object) { + if (!isPrototype(object)) { + return nativeKeys(object); + } + var result = []; + for (var key in Object(object)) { + if (hasOwnProperty.call(object, key) && key != 'constructor') { + result.push(key); + } + } + return result; + } + + /** + * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeysIn(object) { + if (!isObject(object)) { + return nativeKeysIn(object); + } + var isProto = isPrototype(object), + result = []; + + for (var key in object) { + if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); + } + } + return result; + } + + /** + * The base implementation of `_.lt` which doesn't coerce arguments. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than `other`, + * else `false`. + */ + function baseLt(value, other) { + return value < other; + } + + /** + * The base implementation of `_.map` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function baseMap(collection, iteratee) { + var index = -1, + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value, key, collection) { + result[++index] = iteratee(value, key, collection); + }); + return result; + } + + /** + * The base implementation of `_.matches` which doesn't clone `source`. + * + * @private + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new spec function. + */ + function baseMatches(source) { + var matchData = getMatchData(source); + if (matchData.length == 1 && matchData[0][2]) { + return matchesStrictComparable(matchData[0][0], matchData[0][1]); + } + return function(object) { + return object === source || baseIsMatch(object, source, matchData); + }; + } + + /** + * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. + * + * @private + * @param {string} path The path of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ + function baseMatchesProperty(path, srcValue) { + if (isKey(path) && isStrictComparable(srcValue)) { + return matchesStrictComparable(toKey(path), srcValue); + } + return function(object) { + var objValue = get(object, path); + return (objValue === undefined && objValue === srcValue) + ? hasIn(object, path) + : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG); + }; + } + + /** + * The base implementation of `_.merge` without support for multiple sources. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {number} srcIndex The index of `source`. + * @param {Function} [customizer] The function to customize merged values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ + function baseMerge(object, source, srcIndex, customizer, stack) { + if (object === source) { + return; + } + baseFor(source, function(srcValue, key) { + if (isObject(srcValue)) { + stack || (stack = new Stack); + baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); + } + else { + var newValue = customizer + ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack) + : undefined; + + if (newValue === undefined) { + newValue = srcValue; + } + assignMergeValue(object, key, newValue); + } + }, keysIn); + } + + /** + * A specialized version of `baseMerge` for arrays and objects which performs + * deep merges and tracks traversed objects enabling objects with circular + * references to be merged. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {string} key The key of the value to merge. + * @param {number} srcIndex The index of `source`. + * @param {Function} mergeFunc The function to merge values. + * @param {Function} [customizer] The function to customize assigned values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ + function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { + var objValue = safeGet(object, key), + srcValue = safeGet(source, key), + stacked = stack.get(srcValue); + + if (stacked) { + assignMergeValue(object, key, stacked); + return; + } + var newValue = customizer + ? customizer(objValue, srcValue, (key + ''), object, source, stack) + : undefined; + + var isCommon = newValue === undefined; + + if (isCommon) { + var isArr = isArray(srcValue), + isBuff = !isArr && isBuffer(srcValue), + isTyped = !isArr && !isBuff && isTypedArray(srcValue); + + newValue = srcValue; + if (isArr || isBuff || isTyped) { + if (isArray(objValue)) { + newValue = objValue; + } + else if (isArrayLikeObject(objValue)) { + newValue = copyArray(objValue); + } + else if (isBuff) { + isCommon = false; + newValue = cloneBuffer(srcValue, true); + } + else if (isTyped) { + isCommon = false; + newValue = cloneTypedArray(srcValue, true); + } + else { + newValue = []; + } + } + else if (isPlainObject(srcValue) || isArguments(srcValue)) { + newValue = objValue; + if (isArguments(objValue)) { + newValue = toPlainObject(objValue); + } + else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { + newValue = initCloneObject(srcValue); + } + } + else { + isCommon = false; + } + } + if (isCommon) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, newValue); + mergeFunc(newValue, srcValue, srcIndex, customizer, stack); + stack['delete'](srcValue); + } + assignMergeValue(object, key, newValue); + } + + /** + * The base implementation of `_.nth` which doesn't coerce arguments. + * + * @private + * @param {Array} array The array to query. + * @param {number} n The index of the element to return. + * @returns {*} Returns the nth element of `array`. + */ + function baseNth(array, n) { + var length = array.length; + if (!length) { + return; + } + n += n < 0 ? length : 0; + return isIndex(n, length) ? array[n] : undefined; + } + + /** + * The base implementation of `_.orderBy` without param guards. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. + * @param {string[]} orders The sort orders of `iteratees`. + * @returns {Array} Returns the new sorted array. + */ + function baseOrderBy(collection, iteratees, orders) { + var index = -1; + iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee())); + + var result = baseMap(collection, function(value, key, collection) { + var criteria = arrayMap(iteratees, function(iteratee) { + return iteratee(value); + }); + return { 'criteria': criteria, 'index': ++index, 'value': value }; + }); + + return baseSortBy(result, function(object, other) { + return compareMultiple(object, other, orders); + }); + } + + /** + * The base implementation of `_.pick` without support for individual + * property identifiers. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @returns {Object} Returns the new object. + */ + function basePick(object, paths) { + return basePickBy(object, paths, function(value, path) { + return hasIn(object, path); + }); + } + + /** + * The base implementation of `_.pickBy` without support for iteratee shorthands. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @param {Function} predicate The function invoked per property. + * @returns {Object} Returns the new object. + */ + function basePickBy(object, paths, predicate) { + var index = -1, + length = paths.length, + result = {}; + + while (++index < length) { + var path = paths[index], + value = baseGet(object, path); + + if (predicate(value, path)) { + baseSet(result, castPath(path, object), value); + } + } + return result; + } + + /** + * A specialized version of `baseProperty` which supports deep paths. + * + * @private + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new accessor function. + */ + function basePropertyDeep(path) { + return function(object) { + return baseGet(object, path); + }; + } + + /** + * The base implementation of `_.pullAllBy` without support for iteratee + * shorthands. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns `array`. + */ + function basePullAll(array, values, iteratee, comparator) { + var indexOf = comparator ? baseIndexOfWith : baseIndexOf, + index = -1, + length = values.length, + seen = array; + + if (array === values) { + values = copyArray(values); + } + if (iteratee) { + seen = arrayMap(array, baseUnary(iteratee)); + } + while (++index < length) { + var fromIndex = 0, + value = values[index], + computed = iteratee ? iteratee(value) : value; + + while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) { + if (seen !== array) { + splice.call(seen, fromIndex, 1); + } + splice.call(array, fromIndex, 1); + } + } + return array; + } + + /** + * The base implementation of `_.pullAt` without support for individual + * indexes or capturing the removed elements. + * + * @private + * @param {Array} array The array to modify. + * @param {number[]} indexes The indexes of elements to remove. + * @returns {Array} Returns `array`. + */ + function basePullAt(array, indexes) { + var length = array ? indexes.length : 0, + lastIndex = length - 1; + + while (length--) { + var index = indexes[length]; + if (length == lastIndex || index !== previous) { + var previous = index; + if (isIndex(index)) { + splice.call(array, index, 1); + } else { + baseUnset(array, index); + } + } + } + return array; + } + + /** + * The base implementation of `_.random` without support for returning + * floating-point numbers. + * + * @private + * @param {number} lower The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the random number. + */ + function baseRandom(lower, upper) { + return lower + nativeFloor(nativeRandom() * (upper - lower + 1)); + } + + /** + * The base implementation of `_.range` and `_.rangeRight` which doesn't + * coerce arguments. + * + * @private + * @param {number} start The start of the range. + * @param {number} end The end of the range. + * @param {number} step The value to increment or decrement by. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the range of numbers. + */ + function baseRange(start, end, step, fromRight) { + var index = -1, + length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), + result = Array(length); + + while (length--) { + result[fromRight ? length : ++index] = start; + start += step; + } + return result; + } + + /** + * The base implementation of `_.repeat` which doesn't coerce arguments. + * + * @private + * @param {string} string The string to repeat. + * @param {number} n The number of times to repeat the string. + * @returns {string} Returns the repeated string. + */ + function baseRepeat(string, n) { + var result = ''; + if (!string || n < 1 || n > MAX_SAFE_INTEGER) { + return result; + } + // Leverage the exponentiation by squaring algorithm for a faster repeat. + // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details. + do { + if (n % 2) { + result += string; + } + n = nativeFloor(n / 2); + if (n) { + string += string; + } + } while (n); + + return result; + } + + /** + * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + */ + function baseRest(func, start) { + return setToString(overRest(func, start, identity), func + ''); + } + + /** + * The base implementation of `_.sample`. + * + * @private + * @param {Array|Object} collection The collection to sample. + * @returns {*} Returns the random element. + */ + function baseSample(collection) { + return arraySample(values(collection)); + } + + /** + * The base implementation of `_.sampleSize` without param guards. + * + * @private + * @param {Array|Object} collection The collection to sample. + * @param {number} n The number of elements to sample. + * @returns {Array} Returns the random elements. + */ + function baseSampleSize(collection, n) { + var array = values(collection); + return shuffleSelf(array, baseClamp(n, 0, array.length)); + } + + /** + * The base implementation of `_.set`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ + function baseSet(object, path, value, customizer) { + if (!isObject(object)) { + return object; + } + path = castPath(path, object); + + var index = -1, + length = path.length, + lastIndex = length - 1, + nested = object; + + while (nested != null && ++index < length) { + var key = toKey(path[index]), + newValue = value; + + if (index != lastIndex) { + var objValue = nested[key]; + newValue = customizer ? customizer(objValue, key, nested) : undefined; + if (newValue === undefined) { + newValue = isObject(objValue) + ? objValue + : (isIndex(path[index + 1]) ? [] : {}); + } + } + assignValue(nested, key, newValue); + nested = nested[key]; + } + return object; + } + + /** + * The base implementation of `setData` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var baseSetData = !metaMap ? identity : function(func, data) { + metaMap.set(func, data); + return func; + }; + + /** + * The base implementation of `setToString` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var baseSetToString = !defineProperty ? identity : function(func, string) { + return defineProperty(func, 'toString', { + 'configurable': true, + 'enumerable': false, + 'value': constant(string), + 'writable': true + }); + }; + + /** + * The base implementation of `_.shuffle`. + * + * @private + * @param {Array|Object} collection The collection to shuffle. + * @returns {Array} Returns the new shuffled array. + */ + function baseShuffle(collection) { + return shuffleSelf(values(collection)); + } + + /** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = end > length ? length : end; + if (end < 0) { + end += length; + } + length = start > end ? 0 : ((end - start) >>> 0); + start >>>= 0; + + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; + } + + /** + * The base implementation of `_.some` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function baseSome(collection, predicate) { + var result; + + baseEach(collection, function(value, index, collection) { + result = predicate(value, index, collection); + return !result; + }); + return !!result; + } + + /** + * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which + * performs a binary search of `array` to determine the index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function baseSortedIndex(array, value, retHighest) { + var low = 0, + high = array == null ? low : array.length; + + if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) { + while (low < high) { + var mid = (low + high) >>> 1, + computed = array[mid]; + + if (computed !== null && !isSymbol(computed) && + (retHighest ? (computed <= value) : (computed < value))) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + return baseSortedIndexBy(array, value, identity, retHighest); + } + + /** + * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy` + * which invokes `iteratee` for `value` and each element of `array` to compute + * their sort ranking. The iteratee is invoked with one argument; (value). + * + * @private + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} iteratee The iteratee invoked per element. + * @param {boolean} [retHighest] Specify returning the highest qualified index. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + */ + function baseSortedIndexBy(array, value, iteratee, retHighest) { + value = iteratee(value); + + var low = 0, + high = array == null ? 0 : array.length, + valIsNaN = value !== value, + valIsNull = value === null, + valIsSymbol = isSymbol(value), + valIsUndefined = value === undefined; + + while (low < high) { + var mid = nativeFloor((low + high) / 2), + computed = iteratee(array[mid]), + othIsDefined = computed !== undefined, + othIsNull = computed === null, + othIsReflexive = computed === computed, + othIsSymbol = isSymbol(computed); + + if (valIsNaN) { + var setLow = retHighest || othIsReflexive; + } else if (valIsUndefined) { + setLow = othIsReflexive && (retHighest || othIsDefined); + } else if (valIsNull) { + setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull); + } else if (valIsSymbol) { + setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol); + } else if (othIsNull || othIsSymbol) { + setLow = false; + } else { + setLow = retHighest ? (computed <= value) : (computed < value); + } + if (setLow) { + low = mid + 1; + } else { + high = mid; + } + } + return nativeMin(high, MAX_ARRAY_INDEX); + } + + /** + * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + */ + function baseSortedUniq(array, iteratee) { + var index = -1, + length = array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + if (!index || !eq(computed, seen)) { + var seen = computed; + result[resIndex++] = value === 0 ? 0 : value; + } + } + return result; + } + + /** + * The base implementation of `_.toNumber` which doesn't ensure correct + * conversions of binary, hexadecimal, or octal string values. + * + * @private + * @param {*} value The value to process. + * @returns {number} Returns the number. + */ + function baseToNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + return +value; + } + + /** + * The base implementation of `_.toString` which doesn't convert nullish + * values to empty strings. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ + function baseToString(value) { + // Exit early for strings to avoid a performance hit in some environments. + if (typeof value == 'string') { + return value; + } + if (isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return arrayMap(value, baseToString) + ''; + } + if (isSymbol(value)) { + return symbolToString ? symbolToString.call(value) : ''; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + } + + /** + * The base implementation of `_.uniqBy` without support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new duplicate free array. + */ + function baseUniq(array, iteratee, comparator) { + var index = -1, + includes = arrayIncludes, + length = array.length, + isCommon = true, + result = [], + seen = result; + + if (comparator) { + isCommon = false; + includes = arrayIncludesWith; + } + else if (length >= LARGE_ARRAY_SIZE) { + var set = iteratee ? null : createSet(array); + if (set) { + return setToArray(set); + } + isCommon = false; + includes = cacheHas; + seen = new SetCache; + } + else { + seen = iteratee ? [] : result; + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + value = (comparator || value !== 0) ? value : 0; + if (isCommon && computed === computed) { + var seenIndex = seen.length; + while (seenIndex--) { + if (seen[seenIndex] === computed) { + continue outer; + } + } + if (iteratee) { + seen.push(computed); + } + result.push(value); + } + else if (!includes(seen, computed, comparator)) { + if (seen !== result) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.unset`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The property path to unset. + * @returns {boolean} Returns `true` if the property is deleted, else `false`. + */ + function baseUnset(object, path) { + path = castPath(path, object); + object = parent(object, path); + return object == null || delete object[toKey(last(path))]; + } + + /** + * The base implementation of `_.update`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to update. + * @param {Function} updater The function to produce the updated value. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ + function baseUpdate(object, path, updater, customizer) { + return baseSet(object, path, updater(baseGet(object, path)), customizer); + } + + /** + * The base implementation of methods like `_.dropWhile` and `_.takeWhile` + * without support for iteratee shorthands. + * + * @private + * @param {Array} array The array to query. + * @param {Function} predicate The function invoked per iteration. + * @param {boolean} [isDrop] Specify dropping elements instead of taking them. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the slice of `array`. + */ + function baseWhile(array, predicate, isDrop, fromRight) { + var length = array.length, + index = fromRight ? length : -1; + + while ((fromRight ? index-- : ++index < length) && + predicate(array[index], index, array)) {} + + return isDrop + ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length)) + : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index)); + } + + /** + * The base implementation of `wrapperValue` which returns the result of + * performing a sequence of actions on the unwrapped `value`, where each + * successive action is supplied the return value of the previous. + * + * @private + * @param {*} value The unwrapped value. + * @param {Array} actions Actions to perform to resolve the unwrapped value. + * @returns {*} Returns the resolved value. + */ + function baseWrapperValue(value, actions) { + var result = value; + if (result instanceof LazyWrapper) { + result = result.value(); + } + return arrayReduce(actions, function(result, action) { + return action.func.apply(action.thisArg, arrayPush([result], action.args)); + }, result); + } + + /** + * The base implementation of methods like `_.xor`, without support for + * iteratee shorthands, that accepts an array of arrays to inspect. + * + * @private + * @param {Array} arrays The arrays to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of values. + */ + function baseXor(arrays, iteratee, comparator) { + var length = arrays.length; + if (length < 2) { + return length ? baseUniq(arrays[0]) : []; + } + var index = -1, + result = Array(length); + + while (++index < length) { + var array = arrays[index], + othIndex = -1; + + while (++othIndex < length) { + if (othIndex != index) { + result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator); + } + } + } + return baseUniq(baseFlatten(result, 1), iteratee, comparator); + } + + /** + * This base implementation of `_.zipObject` which assigns values using `assignFunc`. + * + * @private + * @param {Array} props The property identifiers. + * @param {Array} values The property values. + * @param {Function} assignFunc The function to assign values. + * @returns {Object} Returns the new object. + */ + function baseZipObject(props, values, assignFunc) { + var index = -1, + length = props.length, + valsLength = values.length, + result = {}; + + while (++index < length) { + var value = index < valsLength ? values[index] : undefined; + assignFunc(result, props[index], value); + } + return result; + } + + /** + * Casts `value` to an empty array if it's not an array like object. + * + * @private + * @param {*} value The value to inspect. + * @returns {Array|Object} Returns the cast array-like object. + */ + function castArrayLikeObject(value) { + return isArrayLikeObject(value) ? value : []; + } + + /** + * Casts `value` to `identity` if it's not a function. + * + * @private + * @param {*} value The value to inspect. + * @returns {Function} Returns cast function. + */ + function castFunction(value) { + return typeof value == 'function' ? value : identity; + } + + /** + * Casts `value` to a path array if it's not one. + * + * @private + * @param {*} value The value to inspect. + * @param {Object} [object] The object to query keys on. + * @returns {Array} Returns the cast property path array. + */ + function castPath(value, object) { + if (isArray(value)) { + return value; + } + return isKey(value, object) ? [value] : stringToPath(toString(value)); + } + + /** + * A `baseRest` alias which can be replaced with `identity` by module + * replacement plugins. + * + * @private + * @type {Function} + * @param {Function} func The function to apply a rest parameter to. + * @returns {Function} Returns the new function. + */ + var castRest = baseRest; + + /** + * Casts `array` to a slice if it's needed. + * + * @private + * @param {Array} array The array to inspect. + * @param {number} start The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the cast slice. + */ + function castSlice(array, start, end) { + var length = array.length; + end = end === undefined ? length : end; + return (!start && end >= length) ? array : baseSlice(array, start, end); + } + + /** + * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout). + * + * @private + * @param {number|Object} id The timer id or timeout object of the timer to clear. + */ + var clearTimeout = ctxClearTimeout || function(id) { + return root.clearTimeout(id); + }; + + /** + * Creates a clone of `buffer`. + * + * @private + * @param {Buffer} buffer The buffer to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Buffer} Returns the cloned buffer. + */ + function cloneBuffer(buffer, isDeep) { + if (isDeep) { + return buffer.slice(); + } + var length = buffer.length, + result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); + + buffer.copy(result); + return result; + } + + /** + * Creates a clone of `arrayBuffer`. + * + * @private + * @param {ArrayBuffer} arrayBuffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ + function cloneArrayBuffer(arrayBuffer) { + var result = new arrayBuffer.constructor(arrayBuffer.byteLength); + new Uint8Array(result).set(new Uint8Array(arrayBuffer)); + return result; + } + + /** + * Creates a clone of `dataView`. + * + * @private + * @param {Object} dataView The data view to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned data view. + */ + function cloneDataView(dataView, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; + return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); + } + + /** + * Creates a clone of `regexp`. + * + * @private + * @param {Object} regexp The regexp to clone. + * @returns {Object} Returns the cloned regexp. + */ + function cloneRegExp(regexp) { + var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); + result.lastIndex = regexp.lastIndex; + return result; + } + + /** + * Creates a clone of the `symbol` object. + * + * @private + * @param {Object} symbol The symbol object to clone. + * @returns {Object} Returns the cloned symbol object. + */ + function cloneSymbol(symbol) { + return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; + } + + /** + * Creates a clone of `typedArray`. + * + * @private + * @param {Object} typedArray The typed array to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned typed array. + */ + function cloneTypedArray(typedArray, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; + return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); + } + + /** + * Compares values to sort them in ascending order. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {number} Returns the sort order indicator for `value`. + */ + function compareAscending(value, other) { + if (value !== other) { + var valIsDefined = value !== undefined, + valIsNull = value === null, + valIsReflexive = value === value, + valIsSymbol = isSymbol(value); + + var othIsDefined = other !== undefined, + othIsNull = other === null, + othIsReflexive = other === other, + othIsSymbol = isSymbol(other); + + if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) || + (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) || + (valIsNull && othIsDefined && othIsReflexive) || + (!valIsDefined && othIsReflexive) || + !valIsReflexive) { + return 1; + } + if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) || + (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) || + (othIsNull && valIsDefined && valIsReflexive) || + (!othIsDefined && valIsReflexive) || + !othIsReflexive) { + return -1; + } + } + return 0; + } + + /** + * Used by `_.orderBy` to compare multiple properties of a value to another + * and stable sort them. + * + * If `orders` is unspecified, all values are sorted in ascending order. Otherwise, + * specify an order of "desc" for descending or "asc" for ascending sort order + * of corresponding values. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {boolean[]|string[]} orders The order to sort by for each property. + * @returns {number} Returns the sort order indicator for `object`. + */ + function compareMultiple(object, other, orders) { + var index = -1, + objCriteria = object.criteria, + othCriteria = other.criteria, + length = objCriteria.length, + ordersLength = orders.length; + + while (++index < length) { + var result = compareAscending(objCriteria[index], othCriteria[index]); + if (result) { + if (index >= ordersLength) { + return result; + } + var order = orders[index]; + return result * (order == 'desc' ? -1 : 1); + } + } + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to provide the same value for + // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 + // for more details. + // + // This also ensures a stable sort in V8 and other engines. + // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details. + return object.index - other.index; + } + + /** + * Creates an array that is the composition of partially applied arguments, + * placeholders, and provided arguments into a single array of arguments. + * + * @private + * @param {Array} args The provided arguments. + * @param {Array} partials The arguments to prepend to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @params {boolean} [isCurried] Specify composing for a curried function. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgs(args, partials, holders, isCurried) { + var argsIndex = -1, + argsLength = args.length, + holdersLength = holders.length, + leftIndex = -1, + leftLength = partials.length, + rangeLength = nativeMax(argsLength - holdersLength, 0), + result = Array(leftLength + rangeLength), + isUncurried = !isCurried; + + while (++leftIndex < leftLength) { + result[leftIndex] = partials[leftIndex]; + } + while (++argsIndex < holdersLength) { + if (isUncurried || argsIndex < argsLength) { + result[holders[argsIndex]] = args[argsIndex]; + } + } + while (rangeLength--) { + result[leftIndex++] = args[argsIndex++]; + } + return result; + } + + /** + * This function is like `composeArgs` except that the arguments composition + * is tailored for `_.partialRight`. + * + * @private + * @param {Array} args The provided arguments. + * @param {Array} partials The arguments to append to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @params {boolean} [isCurried] Specify composing for a curried function. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgsRight(args, partials, holders, isCurried) { + var argsIndex = -1, + argsLength = args.length, + holdersIndex = -1, + holdersLength = holders.length, + rightIndex = -1, + rightLength = partials.length, + rangeLength = nativeMax(argsLength - holdersLength, 0), + result = Array(rangeLength + rightLength), + isUncurried = !isCurried; + + while (++argsIndex < rangeLength) { + result[argsIndex] = args[argsIndex]; + } + var offset = argsIndex; + while (++rightIndex < rightLength) { + result[offset + rightIndex] = partials[rightIndex]; + } + while (++holdersIndex < holdersLength) { + if (isUncurried || argsIndex < argsLength) { + result[offset + holders[holdersIndex]] = args[argsIndex++]; + } + } + return result; + } + + /** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ + function copyArray(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; + } + + /** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property identifiers to copy. + * @param {Object} [object={}] The object to copy properties to. + * @param {Function} [customizer] The function to customize copied values. + * @returns {Object} Returns `object`. + */ + function copyObject(source, props, object, customizer) { + var isNew = !object; + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + + var newValue = customizer + ? customizer(object[key], source[key], key, object, source) + : undefined; + + if (newValue === undefined) { + newValue = source[key]; + } + if (isNew) { + baseAssignValue(object, key, newValue); + } else { + assignValue(object, key, newValue); + } + } + return object; + } + + /** + * Copies own symbols of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ + function copySymbols(source, object) { + return copyObject(source, getSymbols(source), object); + } + + /** + * Copies own and inherited symbols of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ + function copySymbolsIn(source, object) { + return copyObject(source, getSymbolsIn(source), object); + } + + /** + * Creates a function like `_.groupBy`. + * + * @private + * @param {Function} setter The function to set accumulator values. + * @param {Function} [initializer] The accumulator object initializer. + * @returns {Function} Returns the new aggregator function. + */ + function createAggregator(setter, initializer) { + return function(collection, iteratee) { + var func = isArray(collection) ? arrayAggregator : baseAggregator, + accumulator = initializer ? initializer() : {}; + + return func(collection, setter, getIteratee(iteratee, 2), accumulator); + }; + } + + /** + * Creates a function like `_.assign`. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ + function createAssigner(assigner) { + return baseRest(function(object, sources) { + var index = -1, + length = sources.length, + customizer = length > 1 ? sources[length - 1] : undefined, + guard = length > 2 ? sources[2] : undefined; + + customizer = (assigner.length > 3 && typeof customizer == 'function') + ? (length--, customizer) + : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + object = Object(object); + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, index, customizer); + } + } + return object; + }); + } + + /** + * Creates a `baseEach` or `baseEachRight` function. + * + * @private + * @param {Function} eachFunc The function to iterate over a collection. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseEach(eachFunc, fromRight) { + return function(collection, iteratee) { + if (collection == null) { + return collection; + } + if (!isArrayLike(collection)) { + return eachFunc(collection, iteratee); + } + var length = collection.length, + index = fromRight ? length : -1, + iterable = Object(collection); + + while ((fromRight ? index-- : ++index < length)) { + if (iteratee(iterable[index], index, iterable) === false) { + break; + } + } + return collection; + }; + } + + /** + * Creates a base function for methods like `_.forIn` and `_.forOwn`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseFor(fromRight) { + return function(object, iteratee, keysFunc) { + var index = -1, + iterable = Object(object), + props = keysFunc(object), + length = props.length; + + while (length--) { + var key = props[fromRight ? length : ++index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; + } + + /** + * Creates a function that wraps `func` to invoke it with the optional `this` + * binding of `thisArg`. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createBind(func, bitmask, thisArg) { + var isBind = bitmask & WRAP_BIND_FLAG, + Ctor = createCtor(func); + + function wrapper() { + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return fn.apply(isBind ? thisArg : this, arguments); + } + return wrapper; + } + + /** + * Creates a function like `_.lowerFirst`. + * + * @private + * @param {string} methodName The name of the `String` case method to use. + * @returns {Function} Returns the new case function. + */ + function createCaseFirst(methodName) { + return function(string) { + string = toString(string); + + var strSymbols = hasUnicode(string) + ? stringToArray(string) + : undefined; + + var chr = strSymbols + ? strSymbols[0] + : string.charAt(0); + + var trailing = strSymbols + ? castSlice(strSymbols, 1).join('') + : string.slice(1); + + return chr[methodName]() + trailing; + }; + } + + /** + * Creates a function like `_.camelCase`. + * + * @private + * @param {Function} callback The function to combine each word. + * @returns {Function} Returns the new compounder function. + */ + function createCompounder(callback) { + return function(string) { + return arrayReduce(words(deburr(string).replace(reApos, '')), callback, ''); + }; + } + + /** + * Creates a function that produces an instance of `Ctor` regardless of + * whether it was invoked as part of a `new` expression or by `call` or `apply`. + * + * @private + * @param {Function} Ctor The constructor to wrap. + * @returns {Function} Returns the new wrapped function. + */ + function createCtor(Ctor) { + return function() { + // Use a `switch` statement to work with class constructors. See + // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist + // for more details. + var args = arguments; + switch (args.length) { + case 0: return new Ctor; + case 1: return new Ctor(args[0]); + case 2: return new Ctor(args[0], args[1]); + case 3: return new Ctor(args[0], args[1], args[2]); + case 4: return new Ctor(args[0], args[1], args[2], args[3]); + case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); + case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); + case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + } + var thisBinding = baseCreate(Ctor.prototype), + result = Ctor.apply(thisBinding, args); + + // Mimic the constructor's `return` behavior. + // See https://es5.github.io/#x13.2.2 for more details. + return isObject(result) ? result : thisBinding; + }; + } + + /** + * Creates a function that wraps `func` to enable currying. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {number} arity The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createCurry(func, bitmask, arity) { + var Ctor = createCtor(func); + + function wrapper() { + var length = arguments.length, + args = Array(length), + index = length, + placeholder = getHolder(wrapper); + + while (index--) { + args[index] = arguments[index]; + } + var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder) + ? [] + : replaceHolders(args, placeholder); + + length -= holders.length; + if (length < arity) { + return createRecurry( + func, bitmask, createHybrid, wrapper.placeholder, undefined, + args, holders, undefined, undefined, arity - length); + } + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return apply(fn, this, args); + } + return wrapper; + } + + /** + * Creates a `_.find` or `_.findLast` function. + * + * @private + * @param {Function} findIndexFunc The function to find the collection index. + * @returns {Function} Returns the new find function. + */ + function createFind(findIndexFunc) { + return function(collection, predicate, fromIndex) { + var iterable = Object(collection); + if (!isArrayLike(collection)) { + var iteratee = getIteratee(predicate, 3); + collection = keys(collection); + predicate = function(key) { return iteratee(iterable[key], key, iterable); }; + } + var index = findIndexFunc(collection, predicate, fromIndex); + return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; + }; + } + + /** + * Creates a `_.flow` or `_.flowRight` function. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new flow function. + */ + function createFlow(fromRight) { + return flatRest(function(funcs) { + var length = funcs.length, + index = length, + prereq = LodashWrapper.prototype.thru; + + if (fromRight) { + funcs.reverse(); + } + while (index--) { + var func = funcs[index]; + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (prereq && !wrapper && getFuncName(func) == 'wrapper') { + var wrapper = new LodashWrapper([], true); + } + } + index = wrapper ? index : length; + while (++index < length) { + func = funcs[index]; + + var funcName = getFuncName(func), + data = funcName == 'wrapper' ? getData(func) : undefined; + + if (data && isLaziable(data[0]) && + data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) && + !data[4].length && data[9] == 1 + ) { + wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]); + } else { + wrapper = (func.length == 1 && isLaziable(func)) + ? wrapper[funcName]() + : wrapper.thru(func); + } + } + return function() { + var args = arguments, + value = args[0]; + + if (wrapper && args.length == 1 && isArray(value)) { + return wrapper.plant(value).value(); + } + var index = 0, + result = length ? funcs[index].apply(this, args) : value; + + while (++index < length) { + result = funcs[index].call(this, result); + } + return result; + }; + }); + } + + /** + * Creates a function that wraps `func` to invoke it with optional `this` + * binding of `thisArg`, partial application, and currying. + * + * @private + * @param {Function|string} func The function or method name to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to + * the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [partialsRight] The arguments to append to those provided + * to the new function. + * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { + var isAry = bitmask & WRAP_ARY_FLAG, + isBind = bitmask & WRAP_BIND_FLAG, + isBindKey = bitmask & WRAP_BIND_KEY_FLAG, + isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG), + isFlip = bitmask & WRAP_FLIP_FLAG, + Ctor = isBindKey ? undefined : createCtor(func); + + function wrapper() { + var length = arguments.length, + args = Array(length), + index = length; + + while (index--) { + args[index] = arguments[index]; + } + if (isCurried) { + var placeholder = getHolder(wrapper), + holdersCount = countHolders(args, placeholder); + } + if (partials) { + args = composeArgs(args, partials, holders, isCurried); + } + if (partialsRight) { + args = composeArgsRight(args, partialsRight, holdersRight, isCurried); + } + length -= holdersCount; + if (isCurried && length < arity) { + var newHolders = replaceHolders(args, placeholder); + return createRecurry( + func, bitmask, createHybrid, wrapper.placeholder, thisArg, + args, newHolders, argPos, ary, arity - length + ); + } + var thisBinding = isBind ? thisArg : this, + fn = isBindKey ? thisBinding[func] : func; + + length = args.length; + if (argPos) { + args = reorder(args, argPos); + } else if (isFlip && length > 1) { + args.reverse(); + } + if (isAry && ary < length) { + args.length = ary; + } + if (this && this !== root && this instanceof wrapper) { + fn = Ctor || createCtor(fn); + } + return fn.apply(thisBinding, args); + } + return wrapper; + } + + /** + * Creates a function like `_.invertBy`. + * + * @private + * @param {Function} setter The function to set accumulator values. + * @param {Function} toIteratee The function to resolve iteratees. + * @returns {Function} Returns the new inverter function. + */ + function createInverter(setter, toIteratee) { + return function(object, iteratee) { + return baseInverter(object, setter, toIteratee(iteratee), {}); + }; + } + + /** + * Creates a function that performs a mathematical operation on two values. + * + * @private + * @param {Function} operator The function to perform the operation. + * @param {number} [defaultValue] The value used for `undefined` arguments. + * @returns {Function} Returns the new mathematical operation function. + */ + function createMathOperation(operator, defaultValue) { + return function(value, other) { + var result; + if (value === undefined && other === undefined) { + return defaultValue; + } + if (value !== undefined) { + result = value; + } + if (other !== undefined) { + if (result === undefined) { + return other; + } + if (typeof value == 'string' || typeof other == 'string') { + value = baseToString(value); + other = baseToString(other); + } else { + value = baseToNumber(value); + other = baseToNumber(other); + } + result = operator(value, other); + } + return result; + }; + } + + /** + * Creates a function like `_.over`. + * + * @private + * @param {Function} arrayFunc The function to iterate over iteratees. + * @returns {Function} Returns the new over function. + */ + function createOver(arrayFunc) { + return flatRest(function(iteratees) { + iteratees = arrayMap(iteratees, baseUnary(getIteratee())); + return baseRest(function(args) { + var thisArg = this; + return arrayFunc(iteratees, function(iteratee) { + return apply(iteratee, thisArg, args); + }); + }); + }); + } + + /** + * Creates the padding for `string` based on `length`. The `chars` string + * is truncated if the number of characters exceeds `length`. + * + * @private + * @param {number} length The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padding for `string`. + */ + function createPadding(length, chars) { + chars = chars === undefined ? ' ' : baseToString(chars); + + var charsLength = chars.length; + if (charsLength < 2) { + return charsLength ? baseRepeat(chars, length) : chars; + } + var result = baseRepeat(chars, nativeCeil(length / stringSize(chars))); + return hasUnicode(chars) + ? castSlice(stringToArray(result), 0, length).join('') + : result.slice(0, length); + } + + /** + * Creates a function that wraps `func` to invoke it with the `this` binding + * of `thisArg` and `partials` prepended to the arguments it receives. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} partials The arguments to prepend to those provided to + * the new function. + * @returns {Function} Returns the new wrapped function. + */ + function createPartial(func, bitmask, thisArg, partials) { + var isBind = bitmask & WRAP_BIND_FLAG, + Ctor = createCtor(func); + + function wrapper() { + var argsIndex = -1, + argsLength = arguments.length, + leftIndex = -1, + leftLength = partials.length, + args = Array(leftLength + argsLength), + fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + + while (++leftIndex < leftLength) { + args[leftIndex] = partials[leftIndex]; + } + while (argsLength--) { + args[leftIndex++] = arguments[++argsIndex]; + } + return apply(fn, isBind ? thisArg : this, args); + } + return wrapper; + } + + /** + * Creates a `_.range` or `_.rangeRight` function. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new range function. + */ + function createRange(fromRight) { + return function(start, end, step) { + if (step && typeof step != 'number' && isIterateeCall(start, end, step)) { + end = step = undefined; + } + // Ensure the sign of `-0` is preserved. + start = toFinite(start); + if (end === undefined) { + end = start; + start = 0; + } else { + end = toFinite(end); + } + step = step === undefined ? (start < end ? 1 : -1) : toFinite(step); + return baseRange(start, end, step, fromRight); + }; + } + + /** + * Creates a function that performs a relational operation on two values. + * + * @private + * @param {Function} operator The function to perform the operation. + * @returns {Function} Returns the new relational operation function. + */ + function createRelationalOperation(operator) { + return function(value, other) { + if (!(typeof value == 'string' && typeof other == 'string')) { + value = toNumber(value); + other = toNumber(other); + } + return operator(value, other); + }; + } + + /** + * Creates a function that wraps `func` to continue currying. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {Function} wrapFunc The function to create the `func` wrapper. + * @param {*} placeholder The placeholder value. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to + * the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) { + var isCurry = bitmask & WRAP_CURRY_FLAG, + newHolders = isCurry ? holders : undefined, + newHoldersRight = isCurry ? undefined : holders, + newPartials = isCurry ? partials : undefined, + newPartialsRight = isCurry ? undefined : partials; + + bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG); + bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG); + + if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) { + bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG); + } + var newData = [ + func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, + newHoldersRight, argPos, ary, arity + ]; + + var result = wrapFunc.apply(undefined, newData); + if (isLaziable(func)) { + setData(result, newData); + } + result.placeholder = placeholder; + return setWrapToString(result, func, bitmask); + } + + /** + * Creates a function like `_.round`. + * + * @private + * @param {string} methodName The name of the `Math` method to use when rounding. + * @returns {Function} Returns the new round function. + */ + function createRound(methodName) { + var func = Math[methodName]; + return function(number, precision) { + number = toNumber(number); + precision = precision == null ? 0 : nativeMin(toInteger(precision), 292); + if (precision) { + // Shift with exponential notation to avoid floating-point issues. + // See [MDN](https://mdn.io/round#Examples) for more details. + var pair = (toString(number) + 'e').split('e'), + value = func(pair[0] + 'e' + (+pair[1] + precision)); + + pair = (toString(value) + 'e').split('e'); + return +(pair[0] + 'e' + (+pair[1] - precision)); + } + return func(number); + }; + } + + /** + * Creates a set object of `values`. + * + * @private + * @param {Array} values The values to add to the set. + * @returns {Object} Returns the new set. + */ + var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) { + return new Set(values); + }; + + /** + * Creates a `_.toPairs` or `_.toPairsIn` function. + * + * @private + * @param {Function} keysFunc The function to get the keys of a given object. + * @returns {Function} Returns the new pairs function. + */ + function createToPairs(keysFunc) { + return function(object) { + var tag = getTag(object); + if (tag == mapTag) { + return mapToArray(object); + } + if (tag == setTag) { + return setToPairs(object); + } + return baseToPairs(object, keysFunc(object)); + }; + } + + /** + * Creates a function that either curries or invokes `func` with optional + * `this` binding and partially applied arguments. + * + * @private + * @param {Function|string} func The function or method name to wrap. + * @param {number} bitmask The bitmask flags. + * 1 - `_.bind` + * 2 - `_.bindKey` + * 4 - `_.curry` or `_.curryRight` of a bound function + * 8 - `_.curry` + * 16 - `_.curryRight` + * 32 - `_.partial` + * 64 - `_.partialRight` + * 128 - `_.rearg` + * 256 - `_.ary` + * 512 - `_.flip` + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to be partially applied. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { + var isBindKey = bitmask & WRAP_BIND_KEY_FLAG; + if (!isBindKey && typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + var length = partials ? partials.length : 0; + if (!length) { + bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG); + partials = holders = undefined; + } + ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0); + arity = arity === undefined ? arity : toInteger(arity); + length -= holders ? holders.length : 0; + + if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) { + var partialsRight = partials, + holdersRight = holders; + + partials = holders = undefined; + } + var data = isBindKey ? undefined : getData(func); + + var newData = [ + func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, + argPos, ary, arity + ]; + + if (data) { + mergeData(newData, data); + } + func = newData[0]; + bitmask = newData[1]; + thisArg = newData[2]; + partials = newData[3]; + holders = newData[4]; + arity = newData[9] = newData[9] === undefined + ? (isBindKey ? 0 : func.length) + : nativeMax(newData[9] - length, 0); + + if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) { + bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG); + } + if (!bitmask || bitmask == WRAP_BIND_FLAG) { + var result = createBind(func, bitmask, thisArg); + } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) { + result = createCurry(func, bitmask, arity); + } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) { + result = createPartial(func, bitmask, thisArg, partials); + } else { + result = createHybrid.apply(undefined, newData); + } + var setter = data ? baseSetData : setData; + return setWrapToString(setter(result, newData), func, bitmask); + } + + /** + * Used by `_.defaults` to customize its `_.assignIn` use to assign properties + * of source objects to the destination object for all destination properties + * that resolve to `undefined`. + * + * @private + * @param {*} objValue The destination value. + * @param {*} srcValue The source value. + * @param {string} key The key of the property to assign. + * @param {Object} object The parent object of `objValue`. + * @returns {*} Returns the value to assign. + */ + function customDefaultsAssignIn(objValue, srcValue, key, object) { + if (objValue === undefined || + (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) { + return srcValue; + } + return objValue; + } + + /** + * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source + * objects into destination objects that are passed thru. + * + * @private + * @param {*} objValue The destination value. + * @param {*} srcValue The source value. + * @param {string} key The key of the property to merge. + * @param {Object} object The parent object of `objValue`. + * @param {Object} source The parent object of `srcValue`. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + * @returns {*} Returns the value to assign. + */ + function customDefaultsMerge(objValue, srcValue, key, object, source, stack) { + if (isObject(objValue) && isObject(srcValue)) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, objValue); + baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack); + stack['delete'](srcValue); + } + return objValue; + } + + /** + * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain + * objects. + * + * @private + * @param {*} value The value to inspect. + * @param {string} key The key of the property to inspect. + * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`. + */ + function customOmitClone(value) { + return isPlainObject(value) ? undefined : value; + } + + /** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `array` and `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ + function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + arrLength = array.length, + othLength = other.length; + + if (arrLength != othLength && !(isPartial && othLength > arrLength)) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(array); + if (stacked && stack.get(other)) { + return stacked == other; + } + var index = -1, + result = true, + seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; + + stack.set(array, other); + stack.set(other, array); + + // Ignore non-index properties. + while (++index < arrLength) { + var arrValue = array[index], + othValue = other[index]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, arrValue, index, other, array, stack) + : customizer(arrValue, othValue, index, array, other, stack); + } + if (compared !== undefined) { + if (compared) { + continue; + } + result = false; + break; + } + // Recursively compare arrays (susceptible to call stack limits). + if (seen) { + if (!arraySome(other, function(othValue, othIndex) { + if (!cacheHas(seen, othIndex) && + (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { + return seen.push(othIndex); + } + })) { + result = false; + break; + } + } else if (!( + arrValue === othValue || + equalFunc(arrValue, othValue, bitmask, customizer, stack) + )) { + result = false; + break; + } + } + stack['delete'](array); + stack['delete'](other); + return result; + } + + /** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { + switch (tag) { + case dataViewTag: + if ((object.byteLength != other.byteLength) || + (object.byteOffset != other.byteOffset)) { + return false; + } + object = object.buffer; + other = other.buffer; + + case arrayBufferTag: + if ((object.byteLength != other.byteLength) || + !equalFunc(new Uint8Array(object), new Uint8Array(other))) { + return false; + } + return true; + + case boolTag: + case dateTag: + case numberTag: + // Coerce booleans to `1` or `0` and dates to milliseconds. + // Invalid dates are coerced to `NaN`. + return eq(+object, +other); + + case errorTag: + return object.name == other.name && object.message == other.message; + + case regexpTag: + case stringTag: + // Coerce regexes to strings and treat strings, primitives and objects, + // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring + // for more details. + return object == (other + ''); + + case mapTag: + var convert = mapToArray; + + case setTag: + var isPartial = bitmask & COMPARE_PARTIAL_FLAG; + convert || (convert = setToArray); + + if (object.size != other.size && !isPartial) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked) { + return stacked == other; + } + bitmask |= COMPARE_UNORDERED_FLAG; + + // Recursively compare objects (susceptible to call stack limits). + stack.set(object, other); + var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); + stack['delete'](object); + return result; + + case symbolTag: + if (symbolValueOf) { + return symbolValueOf.call(object) == symbolValueOf.call(other); + } + } + return false; + } + + /** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + objProps = getAllKeys(object), + objLength = objProps.length, + othProps = getAllKeys(other), + othLength = othProps.length; + + if (objLength != othLength && !isPartial) { + return false; + } + var index = objLength; + while (index--) { + var key = objProps[index]; + if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { + return false; + } + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked && stack.get(other)) { + return stacked == other; + } + var result = true; + stack.set(object, other); + stack.set(other, object); + + var skipCtor = isPartial; + while (++index < objLength) { + key = objProps[index]; + var objValue = object[key], + othValue = other[key]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, objValue, key, other, object, stack) + : customizer(objValue, othValue, key, object, other, stack); + } + // Recursively compare objects (susceptible to call stack limits). + if (!(compared === undefined + ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) + : compared + )) { + result = false; + break; + } + skipCtor || (skipCtor = key == 'constructor'); + } + if (result && !skipCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if (objCtor != othCtor && + ('constructor' in object && 'constructor' in other) && + !(typeof objCtor == 'function' && objCtor instanceof objCtor && + typeof othCtor == 'function' && othCtor instanceof othCtor)) { + result = false; + } + } + stack['delete'](object); + stack['delete'](other); + return result; + } + + /** + * A specialized version of `baseRest` which flattens the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @returns {Function} Returns the new function. + */ + function flatRest(func) { + return setToString(overRest(func, undefined, flatten), func + ''); + } + + /** + * Creates an array of own enumerable property names and symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ + function getAllKeys(object) { + return baseGetAllKeys(object, keys, getSymbols); + } + + /** + * Creates an array of own and inherited enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ + function getAllKeysIn(object) { + return baseGetAllKeys(object, keysIn, getSymbolsIn); + } + + /** + * Gets metadata for `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {*} Returns the metadata for `func`. + */ + var getData = !metaMap ? noop : function(func) { + return metaMap.get(func); + }; + + /** + * Gets the name of `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {string} Returns the function name. + */ + function getFuncName(func) { + var result = (func.name + ''), + array = realNames[result], + length = hasOwnProperty.call(realNames, result) ? array.length : 0; + + while (length--) { + var data = array[length], + otherFunc = data.func; + if (otherFunc == null || otherFunc == func) { + return data.name; + } + } + return result; + } + + /** + * Gets the argument placeholder value for `func`. + * + * @private + * @param {Function} func The function to inspect. + * @returns {*} Returns the placeholder value. + */ + function getHolder(func) { + var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func; + return object.placeholder; + } + + /** + * Gets the appropriate "iteratee" function. If `_.iteratee` is customized, + * this function returns the custom method, otherwise it returns `baseIteratee`. + * If arguments are provided, the chosen function is invoked with them and + * its result is returned. + * + * @private + * @param {*} [value] The value to convert to an iteratee. + * @param {number} [arity] The arity of the created iteratee. + * @returns {Function} Returns the chosen function or its result. + */ + function getIteratee() { + var result = lodash.iteratee || iteratee; + result = result === iteratee ? baseIteratee : result; + return arguments.length ? result(arguments[0], arguments[1]) : result; + } + + /** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ + function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; + } + + /** + * Gets the property names, values, and compare flags of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the match data of `object`. + */ + function getMatchData(object) { + var result = keys(object), + length = result.length; + + while (length--) { + var key = result[length], + value = object[key]; + + result[length] = [key, value, isStrictComparable(value)]; + } + return result; + } + + /** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ + function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; + } + + /** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ + function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; + } + + /** + * Creates an array of the own enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ + var getSymbols = !nativeGetSymbols ? stubArray : function(object) { + if (object == null) { + return []; + } + object = Object(object); + return arrayFilter(nativeGetSymbols(object), function(symbol) { + return propertyIsEnumerable.call(object, symbol); + }); + }; + + /** + * Creates an array of the own and inherited enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ + var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) { + var result = []; + while (object) { + arrayPush(result, getSymbols(object)); + object = getPrototype(object); + } + return result; + }; + + /** + * Gets the `toStringTag` of `value`. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + var getTag = baseGetTag; + + // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. + if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || + (Map && getTag(new Map) != mapTag) || + (Promise && getTag(Promise.resolve()) != promiseTag) || + (Set && getTag(new Set) != setTag) || + (WeakMap && getTag(new WeakMap) != weakMapTag)) { + getTag = function(value) { + var result = baseGetTag(value), + Ctor = result == objectTag ? value.constructor : undefined, + ctorString = Ctor ? toSource(Ctor) : ''; + + if (ctorString) { + switch (ctorString) { + case dataViewCtorString: return dataViewTag; + case mapCtorString: return mapTag; + case promiseCtorString: return promiseTag; + case setCtorString: return setTag; + case weakMapCtorString: return weakMapTag; + } + } + return result; + }; + } + + /** + * Gets the view, applying any `transforms` to the `start` and `end` positions. + * + * @private + * @param {number} start The start of the view. + * @param {number} end The end of the view. + * @param {Array} transforms The transformations to apply to the view. + * @returns {Object} Returns an object containing the `start` and `end` + * positions of the view. + */ + function getView(start, end, transforms) { + var index = -1, + length = transforms.length; + + while (++index < length) { + var data = transforms[index], + size = data.size; + + switch (data.type) { + case 'drop': start += size; break; + case 'dropRight': end -= size; break; + case 'take': end = nativeMin(end, start + size); break; + case 'takeRight': start = nativeMax(start, end - size); break; + } + } + return { 'start': start, 'end': end }; + } + + /** + * Extracts wrapper details from the `source` body comment. + * + * @private + * @param {string} source The source to inspect. + * @returns {Array} Returns the wrapper details. + */ + function getWrapDetails(source) { + var match = source.match(reWrapDetails); + return match ? match[1].split(reSplitDetails) : []; + } + + /** + * Checks if `path` exists on `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @param {Function} hasFunc The function to check properties. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + */ + function hasPath(object, path, hasFunc) { + path = castPath(path, object); + + var index = -1, + length = path.length, + result = false; + + while (++index < length) { + var key = toKey(path[index]); + if (!(result = object != null && hasFunc(object, key))) { + break; + } + object = object[key]; + } + if (result || ++index != length) { + return result; + } + length = object == null ? 0 : object.length; + return !!length && isLength(length) && isIndex(key, length) && + (isArray(object) || isArguments(object)); + } + + /** + * Initializes an array clone. + * + * @private + * @param {Array} array The array to clone. + * @returns {Array} Returns the initialized clone. + */ + function initCloneArray(array) { + var length = array.length, + result = new array.constructor(length); + + // Add properties assigned by `RegExp#exec`. + if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { + result.index = array.index; + result.input = array.input; + } + return result; + } + + /** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneObject(object) { + return (typeof object.constructor == 'function' && !isPrototype(object)) + ? baseCreate(getPrototype(object)) + : {}; + } + + /** + * Initializes an object clone based on its `toStringTag`. + * + * **Note:** This function only supports cloning values with tags of + * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`. + * + * @private + * @param {Object} object The object to clone. + * @param {string} tag The `toStringTag` of the object to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneByTag(object, tag, isDeep) { + var Ctor = object.constructor; + switch (tag) { + case arrayBufferTag: + return cloneArrayBuffer(object); + + case boolTag: + case dateTag: + return new Ctor(+object); + + case dataViewTag: + return cloneDataView(object, isDeep); + + case float32Tag: case float64Tag: + case int8Tag: case int16Tag: case int32Tag: + case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: + return cloneTypedArray(object, isDeep); + + case mapTag: + return new Ctor; + + case numberTag: + case stringTag: + return new Ctor(object); + + case regexpTag: + return cloneRegExp(object); + + case setTag: + return new Ctor; + + case symbolTag: + return cloneSymbol(object); + } + } + + /** + * Inserts wrapper `details` in a comment at the top of the `source` body. + * + * @private + * @param {string} source The source to modify. + * @returns {Array} details The details to insert. + * @returns {string} Returns the modified source. + */ + function insertWrapDetails(source, details) { + var length = details.length; + if (!length) { + return source; + } + var lastIndex = length - 1; + details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex]; + details = details.join(length > 2 ? ', ' : ' '); + return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n'); + } + + /** + * Checks if `value` is a flattenable `arguments` object or array. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. + */ + function isFlattenable(value) { + return isArray(value) || isArguments(value) || + !!(spreadableSymbol && value && value[spreadableSymbol]); + } + + /** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ + function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER : length; + + return !!length && + (type == 'number' || + (type != 'symbol' && reIsUint.test(value))) && + (value > -1 && value % 1 == 0 && value < length); + } + + /** + * Checks if the given arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, + * else `false`. + */ + function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike(object) && isIndex(index, object.length)) + : (type == 'string' && index in object) + ) { + return eq(object[index], value); + } + return false; + } + + /** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ + function isKey(value, object) { + if (isArray(value)) { + return false; + } + var type = typeof value; + if (type == 'number' || type == 'symbol' || type == 'boolean' || + value == null || isSymbol(value)) { + return true; + } + return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || + (object != null && value in Object(object)); + } + + /** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ + function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); + } + + /** + * Checks if `func` has a lazy counterpart. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` has a lazy counterpart, + * else `false`. + */ + function isLaziable(func) { + var funcName = getFuncName(func), + other = lodash[funcName]; + + if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) { + return false; + } + if (func === other) { + return true; + } + var data = getData(other); + return !!data && func === data[0]; + } + + /** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ + function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); + } + + /** + * Checks if `func` is capable of being masked. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `func` is maskable, else `false`. + */ + var isMaskable = coreJsData ? isFunction : stubFalse; + + /** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ + function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; + + return value === proto; + } + + /** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ + function isStrictComparable(value) { + return value === value && !isObject(value); + } + + /** + * A specialized version of `matchesProperty` for source values suitable + * for strict equality comparisons, i.e. `===`. + * + * @private + * @param {string} key The key of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ + function matchesStrictComparable(key, srcValue) { + return function(object) { + if (object == null) { + return false; + } + return object[key] === srcValue && + (srcValue !== undefined || (key in Object(object))); + }; + } + + /** + * A specialized version of `_.memoize` which clears the memoized function's + * cache when it exceeds `MAX_MEMOIZE_SIZE`. + * + * @private + * @param {Function} func The function to have its output memoized. + * @returns {Function} Returns the new memoized function. + */ + function memoizeCapped(func) { + var result = memoize(func, function(key) { + if (cache.size === MAX_MEMOIZE_SIZE) { + cache.clear(); + } + return key; + }); + + var cache = result.cache; + return result; + } + + /** + * Merges the function metadata of `source` into `data`. + * + * Merging metadata reduces the number of wrappers used to invoke a function. + * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` + * may be applied regardless of execution order. Methods like `_.ary` and + * `_.rearg` modify function arguments, making the order in which they are + * executed important, preventing the merging of metadata. However, we make + * an exception for a safe combined case where curried functions have `_.ary` + * and or `_.rearg` applied. + * + * @private + * @param {Array} data The destination metadata. + * @param {Array} source The source metadata. + * @returns {Array} Returns `data`. + */ + function mergeData(data, source) { + var bitmask = data[1], + srcBitmask = source[1], + newBitmask = bitmask | srcBitmask, + isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG); + + var isCombo = + ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) || + ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) || + ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG)); + + // Exit early if metadata can't be merged. + if (!(isCommon || isCombo)) { + return data; + } + // Use source `thisArg` if available. + if (srcBitmask & WRAP_BIND_FLAG) { + data[2] = source[2]; + // Set when currying a bound function. + newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG; + } + // Compose partial arguments. + var value = source[3]; + if (value) { + var partials = data[3]; + data[3] = partials ? composeArgs(partials, value, source[4]) : value; + data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4]; + } + // Compose partial right arguments. + value = source[5]; + if (value) { + partials = data[5]; + data[5] = partials ? composeArgsRight(partials, value, source[6]) : value; + data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6]; + } + // Use source `argPos` if available. + value = source[7]; + if (value) { + data[7] = value; + } + // Use source `ary` if it's smaller. + if (srcBitmask & WRAP_ARY_FLAG) { + data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); + } + // Use source `arity` if one is not provided. + if (data[9] == null) { + data[9] = source[9]; + } + // Use source `func` and merge bitmasks. + data[0] = source[0]; + data[1] = newBitmask; + + return data; + } + + /** + * This function is like + * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * except that it includes inherited enumerable properties. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function nativeKeysIn(object) { + var result = []; + if (object != null) { + for (var key in Object(object)) { + result.push(key); + } + } + return result; + } + + /** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ + function objectToString(value) { + return nativeObjectToString.call(value); + } + + /** + * A specialized version of `baseRest` which transforms the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. + */ + function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); + return function() { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); + + while (++index < length) { + array[index] = args[start + index]; + } + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); + }; + } + + /** + * Gets the parent value at `path` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} path The path to get the parent value of. + * @returns {*} Returns the parent value. + */ + function parent(object, path) { + return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1)); + } + + /** + * Reorder `array` according to the specified indexes where the element at + * the first index is assigned as the first element, the element at + * the second index is assigned as the second element, and so on. + * + * @private + * @param {Array} array The array to reorder. + * @param {Array} indexes The arranged array indexes. + * @returns {Array} Returns `array`. + */ + function reorder(array, indexes) { + var arrLength = array.length, + length = nativeMin(indexes.length, arrLength), + oldArray = copyArray(array); + + while (length--) { + var index = indexes[length]; + array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; + } + return array; + } + + /** + * Sets metadata for `func`. + * + * **Note:** If this function becomes hot, i.e. is invoked a lot in a short + * period of time, it will trip its breaker and transition to an identity + * function to avoid garbage collection pauses in V8. See + * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070) + * for more details. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var setData = shortOut(baseSetData); + + /** + * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout). + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @returns {number|Object} Returns the timer id or timeout object. + */ + var setTimeout = ctxSetTimeout || function(func, wait) { + return root.setTimeout(func, wait); + }; + + /** + * Sets the `toString` method of `func` to return `string`. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var setToString = shortOut(baseSetToString); + + /** + * Sets the `toString` method of `wrapper` to mimic the source of `reference` + * with wrapper details in a comment at the top of the source body. + * + * @private + * @param {Function} wrapper The function to modify. + * @param {Function} reference The reference function. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @returns {Function} Returns `wrapper`. + */ + function setWrapToString(wrapper, reference, bitmask) { + var source = (reference + ''); + return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask))); + } + + /** + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. + * + * @private + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. + */ + function shortOut(func) { + var count = 0, + lastCalled = 0; + + return function() { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; + } + + /** + * A specialized version of `_.shuffle` which mutates and sets the size of `array`. + * + * @private + * @param {Array} array The array to shuffle. + * @param {number} [size=array.length] The size of `array`. + * @returns {Array} Returns `array`. + */ + function shuffleSelf(array, size) { + var index = -1, + length = array.length, + lastIndex = length - 1; + + size = size === undefined ? length : size; + while (++index < size) { + var rand = baseRandom(index, lastIndex), + value = array[rand]; + + array[rand] = array[index]; + array[index] = value; + } + array.length = size; + return array; + } + + /** + * Converts `string` to a property path array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the property path array. + */ + var stringToPath = memoizeCapped(function(string) { + var result = []; + if (string.charCodeAt(0) === 46 /* . */) { + result.push(''); + } + string.replace(rePropName, function(match, number, quote, subString) { + result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; + }); + + /** + * Converts `value` to a string key if it's not a string or symbol. + * + * @private + * @param {*} value The value to inspect. + * @returns {string|symbol} Returns the key. + */ + function toKey(value) { + if (typeof value == 'string' || isSymbol(value)) { + return value; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + } + + /** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ + function toSource(func) { + if (func != null) { + try { + return funcToString.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; + } + + /** + * Updates wrapper `details` based on `bitmask` flags. + * + * @private + * @returns {Array} details The details to modify. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @returns {Array} Returns `details`. + */ + function updateWrapDetails(details, bitmask) { + arrayEach(wrapFlags, function(pair) { + var value = '_.' + pair[0]; + if ((bitmask & pair[1]) && !arrayIncludes(details, value)) { + details.push(value); + } + }); + return details.sort(); + } + + /** + * Creates a clone of `wrapper`. + * + * @private + * @param {Object} wrapper The wrapper to clone. + * @returns {Object} Returns the cloned wrapper. + */ + function wrapperClone(wrapper) { + if (wrapper instanceof LazyWrapper) { + return wrapper.clone(); + } + var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__); + result.__actions__ = copyArray(wrapper.__actions__); + result.__index__ = wrapper.__index__; + result.__values__ = wrapper.__values__; + return result; + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of elements split into groups the length of `size`. + * If `array` can't be split evenly, the final chunk will be the remaining + * elements. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to process. + * @param {number} [size=1] The length of each chunk + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the new array of chunks. + * @example + * + * _.chunk(['a', 'b', 'c', 'd'], 2); + * // => [['a', 'b'], ['c', 'd']] + * + * _.chunk(['a', 'b', 'c', 'd'], 3); + * // => [['a', 'b', 'c'], ['d']] + */ + function chunk(array, size, guard) { + if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { + size = 1; + } else { + size = nativeMax(toInteger(size), 0); + } + var length = array == null ? 0 : array.length; + if (!length || size < 1) { + return []; + } + var index = 0, + resIndex = 0, + result = Array(nativeCeil(length / size)); + + while (index < length) { + result[resIndex++] = baseSlice(array, index, (index += size)); + } + return result; + } + + /** + * Creates an array with all falsey values removed. The values `false`, `null`, + * `0`, `""`, `undefined`, and `NaN` are falsey. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to compact. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.compact([0, 1, false, 2, '', 3]); + * // => [1, 2, 3] + */ + function compact(array) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (value) { + result[resIndex++] = value; + } + } + return result; + } + + /** + * Creates a new array concatenating `array` with any additional arrays + * and/or values. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to concatenate. + * @param {...*} [values] The values to concatenate. + * @returns {Array} Returns the new concatenated array. + * @example + * + * var array = [1]; + * var other = _.concat(array, 2, [3], [[4]]); + * + * console.log(other); + * // => [1, 2, 3, [4]] + * + * console.log(array); + * // => [1] + */ + function concat() { + var length = arguments.length; + if (!length) { + return []; + } + var args = Array(length - 1), + array = arguments[0], + index = length; + + while (index--) { + args[index - 1] = arguments[index]; + } + return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)); + } + + /** + * Creates an array of `array` values not included in the other given arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. The order and references of result values are + * determined by the first array. + * + * **Note:** Unlike `_.pullAll`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @see _.without, _.xor + * @example + * + * _.difference([2, 1], [2, 3]); + * // => [1] + */ + var difference = baseRest(function(array, values) { + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) + : []; + }); + + /** + * This method is like `_.difference` except that it accepts `iteratee` which + * is invoked for each element of `array` and `values` to generate the criterion + * by which they're compared. The order and references of result values are + * determined by the first array. The iteratee is invoked with one argument: + * (value). + * + * **Note:** Unlike `_.pullAllBy`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [1.2] + * + * // The `_.property` iteratee shorthand. + * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x'); + * // => [{ 'x': 2 }] + */ + var differenceBy = baseRest(function(array, values) { + var iteratee = last(values); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)) + : []; + }); + + /** + * This method is like `_.difference` except that it accepts `comparator` + * which is invoked to compare elements of `array` to `values`. The order and + * references of result values are determined by the first array. The comparator + * is invoked with two arguments: (arrVal, othVal). + * + * **Note:** Unlike `_.pullAllWith`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * + * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual); + * // => [{ 'x': 2, 'y': 1 }] + */ + var differenceWith = baseRest(function(array, values) { + var comparator = last(values); + if (isArrayLikeObject(comparator)) { + comparator = undefined; + } + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator) + : []; + }); + + /** + * Creates a slice of `array` with `n` elements dropped from the beginning. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.drop([1, 2, 3]); + * // => [2, 3] + * + * _.drop([1, 2, 3], 2); + * // => [3] + * + * _.drop([1, 2, 3], 5); + * // => [] + * + * _.drop([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function drop(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + return baseSlice(array, n < 0 ? 0 : n, length); + } + + /** + * Creates a slice of `array` with `n` elements dropped from the end. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.dropRight([1, 2, 3]); + * // => [1, 2] + * + * _.dropRight([1, 2, 3], 2); + * // => [1] + * + * _.dropRight([1, 2, 3], 5); + * // => [] + * + * _.dropRight([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function dropRight(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + n = length - n; + return baseSlice(array, 0, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` excluding elements dropped from the end. + * Elements are dropped until `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.dropRightWhile(users, function(o) { return !o.active; }); + * // => objects for ['barney'] + * + * // The `_.matches` iteratee shorthand. + * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false }); + * // => objects for ['barney', 'fred'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.dropRightWhile(users, ['active', false]); + * // => objects for ['barney'] + * + * // The `_.property` iteratee shorthand. + * _.dropRightWhile(users, 'active'); + * // => objects for ['barney', 'fred', 'pebbles'] + */ + function dropRightWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), true, true) + : []; + } + + /** + * Creates a slice of `array` excluding elements dropped from the beginning. + * Elements are dropped until `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.dropWhile(users, function(o) { return !o.active; }); + * // => objects for ['pebbles'] + * + * // The `_.matches` iteratee shorthand. + * _.dropWhile(users, { 'user': 'barney', 'active': false }); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.dropWhile(users, ['active', false]); + * // => objects for ['pebbles'] + * + * // The `_.property` iteratee shorthand. + * _.dropWhile(users, 'active'); + * // => objects for ['barney', 'fred', 'pebbles'] + */ + function dropWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), true) + : []; + } + + /** + * Fills elements of `array` with `value` from `start` up to, but not + * including, `end`. + * + * **Note:** This method mutates `array`. + * + * @static + * @memberOf _ + * @since 3.2.0 + * @category Array + * @param {Array} array The array to fill. + * @param {*} value The value to fill `array` with. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3]; + * + * _.fill(array, 'a'); + * console.log(array); + * // => ['a', 'a', 'a'] + * + * _.fill(Array(3), 2); + * // => [2, 2, 2] + * + * _.fill([4, 6, 8, 10], '*', 1, 3); + * // => [4, '*', '*', 10] + */ + function fill(array, value, start, end) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + if (start && typeof start != 'number' && isIterateeCall(array, value, start)) { + start = 0; + end = length; + } + return baseFill(array, value, start, end); + } + + /** + * This method is like `_.find` except that it returns the index of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.findIndex(users, function(o) { return o.user == 'barney'; }); + * // => 0 + * + * // The `_.matches` iteratee shorthand. + * _.findIndex(users, { 'user': 'fred', 'active': false }); + * // => 1 + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findIndex(users, ['active', false]); + * // => 0 + * + * // The `_.property` iteratee shorthand. + * _.findIndex(users, 'active'); + * // => 2 + */ + function findIndex(array, predicate, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); + } + return baseFindIndex(array, getIteratee(predicate, 3), index); + } + + /** + * This method is like `_.findIndex` except that it iterates over elements + * of `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=array.length-1] The index to search from. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); + * // => 2 + * + * // The `_.matches` iteratee shorthand. + * _.findLastIndex(users, { 'user': 'barney', 'active': true }); + * // => 0 + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findLastIndex(users, ['active', false]); + * // => 2 + * + * // The `_.property` iteratee shorthand. + * _.findLastIndex(users, 'active'); + * // => 0 + */ + function findLastIndex(array, predicate, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = length - 1; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = fromIndex < 0 + ? nativeMax(length + index, 0) + : nativeMin(index, length - 1); + } + return baseFindIndex(array, getIteratee(predicate, 3), index, true); + } + + /** + * Flattens `array` a single level deep. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flatten([1, [2, [3, [4]], 5]]); + * // => [1, 2, [3, [4]], 5] + */ + function flatten(array) { + var length = array == null ? 0 : array.length; + return length ? baseFlatten(array, 1) : []; + } + + /** + * Recursively flattens `array`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flattenDeep([1, [2, [3, [4]], 5]]); + * // => [1, 2, 3, 4, 5] + */ + function flattenDeep(array) { + var length = array == null ? 0 : array.length; + return length ? baseFlatten(array, INFINITY) : []; + } + + /** + * Recursively flatten `array` up to `depth` times. + * + * @static + * @memberOf _ + * @since 4.4.0 + * @category Array + * @param {Array} array The array to flatten. + * @param {number} [depth=1] The maximum recursion depth. + * @returns {Array} Returns the new flattened array. + * @example + * + * var array = [1, [2, [3, [4]], 5]]; + * + * _.flattenDepth(array, 1); + * // => [1, 2, [3, [4]], 5] + * + * _.flattenDepth(array, 2); + * // => [1, 2, 3, [4], 5] + */ + function flattenDepth(array, depth) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + depth = depth === undefined ? 1 : toInteger(depth); + return baseFlatten(array, depth); + } + + /** + * The inverse of `_.toPairs`; this method returns an object composed + * from key-value `pairs`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} pairs The key-value pairs. + * @returns {Object} Returns the new object. + * @example + * + * _.fromPairs([['a', 1], ['b', 2]]); + * // => { 'a': 1, 'b': 2 } + */ + function fromPairs(pairs) { + var index = -1, + length = pairs == null ? 0 : pairs.length, + result = {}; + + while (++index < length) { + var pair = pairs[index]; + result[pair[0]] = pair[1]; + } + return result; + } + + /** + * Gets the first element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @alias first + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the first element of `array`. + * @example + * + * _.head([1, 2, 3]); + * // => 1 + * + * _.head([]); + * // => undefined + */ + function head(array) { + return (array && array.length) ? array[0] : undefined; + } + + /** + * Gets the index at which the first occurrence of `value` is found in `array` + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. If `fromIndex` is negative, it's used as the + * offset from the end of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.indexOf([1, 2, 1, 2], 2); + * // => 1 + * + * // Search from the `fromIndex`. + * _.indexOf([1, 2, 1, 2], 2, 2); + * // => 3 + */ + function indexOf(array, value, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); + } + return baseIndexOf(array, value, index); + } + + /** + * Gets all but the last element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.initial([1, 2, 3]); + * // => [1, 2] + */ + function initial(array) { + var length = array == null ? 0 : array.length; + return length ? baseSlice(array, 0, -1) : []; + } + + /** + * Creates an array of unique values that are included in all given arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. The order and references of result values are + * determined by the first array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * _.intersection([2, 1], [2, 3]); + * // => [2] + */ + var intersection = baseRest(function(arrays) { + var mapped = arrayMap(arrays, castArrayLikeObject); + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped) + : []; + }); + + /** + * This method is like `_.intersection` except that it accepts `iteratee` + * which is invoked for each element of each `arrays` to generate the criterion + * by which they're compared. The order and references of result values are + * determined by the first array. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [2.1] + * + * // The `_.property` iteratee shorthand. + * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }] + */ + var intersectionBy = baseRest(function(arrays) { + var iteratee = last(arrays), + mapped = arrayMap(arrays, castArrayLikeObject); + + if (iteratee === last(mapped)) { + iteratee = undefined; + } else { + mapped.pop(); + } + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped, getIteratee(iteratee, 2)) + : []; + }); + + /** + * This method is like `_.intersection` except that it accepts `comparator` + * which is invoked to compare elements of `arrays`. The order and references + * of result values are determined by the first array. The comparator is + * invoked with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.intersectionWith(objects, others, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }] + */ + var intersectionWith = baseRest(function(arrays) { + var comparator = last(arrays), + mapped = arrayMap(arrays, castArrayLikeObject); + + comparator = typeof comparator == 'function' ? comparator : undefined; + if (comparator) { + mapped.pop(); + } + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped, undefined, comparator) + : []; + }); + + /** + * Converts all elements in `array` into a string separated by `separator`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to convert. + * @param {string} [separator=','] The element separator. + * @returns {string} Returns the joined string. + * @example + * + * _.join(['a', 'b', 'c'], '~'); + * // => 'a~b~c' + */ + function join(array, separator) { + return array == null ? '' : nativeJoin.call(array, separator); + } + + /** + * Gets the last element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the last element of `array`. + * @example + * + * _.last([1, 2, 3]); + * // => 3 + */ + function last(array) { + var length = array == null ? 0 : array.length; + return length ? array[length - 1] : undefined; + } + + /** + * This method is like `_.indexOf` except that it iterates over elements of + * `array` from right to left. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=array.length-1] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.lastIndexOf([1, 2, 1, 2], 2); + * // => 3 + * + * // Search from the `fromIndex`. + * _.lastIndexOf([1, 2, 1, 2], 2, 2); + * // => 1 + */ + function lastIndexOf(array, value, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = length; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1); + } + return value === value + ? strictLastIndexOf(array, value, index) + : baseFindIndex(array, baseIsNaN, index, true); + } + + /** + * Gets the element at index `n` of `array`. If `n` is negative, the nth + * element from the end is returned. + * + * @static + * @memberOf _ + * @since 4.11.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=0] The index of the element to return. + * @returns {*} Returns the nth element of `array`. + * @example + * + * var array = ['a', 'b', 'c', 'd']; + * + * _.nth(array, 1); + * // => 'b' + * + * _.nth(array, -2); + * // => 'c'; + */ + function nth(array, n) { + return (array && array.length) ? baseNth(array, toInteger(n)) : undefined; + } + + /** + * Removes all given values from `array` using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove` + * to remove elements from an array by predicate. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {...*} [values] The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = ['a', 'b', 'c', 'a', 'b', 'c']; + * + * _.pull(array, 'a', 'c'); + * console.log(array); + * // => ['b', 'b'] + */ + var pull = baseRest(pullAll); + + /** + * This method is like `_.pull` except that it accepts an array of values to remove. + * + * **Note:** Unlike `_.difference`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = ['a', 'b', 'c', 'a', 'b', 'c']; + * + * _.pullAll(array, ['a', 'c']); + * console.log(array); + * // => ['b', 'b'] + */ + function pullAll(array, values) { + return (array && array.length && values && values.length) + ? basePullAll(array, values) + : array; + } + + /** + * This method is like `_.pullAll` except that it accepts `iteratee` which is + * invoked for each element of `array` and `values` to generate the criterion + * by which they're compared. The iteratee is invoked with one argument: (value). + * + * **Note:** Unlike `_.differenceBy`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns `array`. + * @example + * + * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; + * + * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x'); + * console.log(array); + * // => [{ 'x': 2 }] + */ + function pullAllBy(array, values, iteratee) { + return (array && array.length && values && values.length) + ? basePullAll(array, values, getIteratee(iteratee, 2)) + : array; + } + + /** + * This method is like `_.pullAll` except that it accepts `comparator` which + * is invoked to compare elements of `array` to `values`. The comparator is + * invoked with two arguments: (arrVal, othVal). + * + * **Note:** Unlike `_.differenceWith`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns `array`. + * @example + * + * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }]; + * + * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual); + * console.log(array); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }] + */ + function pullAllWith(array, values, comparator) { + return (array && array.length && values && values.length) + ? basePullAll(array, values, undefined, comparator) + : array; + } + + /** + * Removes elements from `array` corresponding to `indexes` and returns an + * array of removed elements. + * + * **Note:** Unlike `_.at`, this method mutates `array`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {...(number|number[])} [indexes] The indexes of elements to remove. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = ['a', 'b', 'c', 'd']; + * var pulled = _.pullAt(array, [1, 3]); + * + * console.log(array); + * // => ['a', 'c'] + * + * console.log(pulled); + * // => ['b', 'd'] + */ + var pullAt = flatRest(function(array, indexes) { + var length = array == null ? 0 : array.length, + result = baseAt(array, indexes); + + basePullAt(array, arrayMap(indexes, function(index) { + return isIndex(index, length) ? +index : index; + }).sort(compareAscending)); + + return result; + }); + + /** + * Removes all elements from `array` that `predicate` returns truthy for + * and returns an array of the removed elements. The predicate is invoked + * with three arguments: (value, index, array). + * + * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull` + * to pull elements from an array by value. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to modify. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new array of removed elements. + * @example + * + * var array = [1, 2, 3, 4]; + * var evens = _.remove(array, function(n) { + * return n % 2 == 0; + * }); + * + * console.log(array); + * // => [1, 3] + * + * console.log(evens); + * // => [2, 4] + */ + function remove(array, predicate) { + var result = []; + if (!(array && array.length)) { + return result; + } + var index = -1, + indexes = [], + length = array.length; + + predicate = getIteratee(predicate, 3); + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result.push(value); + indexes.push(index); + } + } + basePullAt(array, indexes); + return result; + } + + /** + * Reverses `array` so that the first element becomes the last, the second + * element becomes the second to last, and so on. + * + * **Note:** This method mutates `array` and is based on + * [`Array#reverse`](https://mdn.io/Array/reverse). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3]; + * + * _.reverse(array); + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + function reverse(array) { + return array == null ? array : nativeReverse.call(array); + } + + /** + * Creates a slice of `array` from `start` up to, but not including, `end`. + * + * **Note:** This method is used instead of + * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are + * returned. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function slice(array, start, end) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { + start = 0; + end = length; + } + else { + start = start == null ? 0 : toInteger(start); + end = end === undefined ? length : toInteger(end); + } + return baseSlice(array, start, end); + } + + /** + * Uses a binary search to determine the lowest index at which `value` + * should be inserted into `array` in order to maintain its sort order. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedIndex([30, 50], 40); + * // => 1 + */ + function sortedIndex(array, value) { + return baseSortedIndex(array, value); + } + + /** + * This method is like `_.sortedIndex` except that it accepts `iteratee` + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * var objects = [{ 'x': 4 }, { 'x': 5 }]; + * + * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); + * // => 0 + * + * // The `_.property` iteratee shorthand. + * _.sortedIndexBy(objects, { 'x': 4 }, 'x'); + * // => 0 + */ + function sortedIndexBy(array, value, iteratee) { + return baseSortedIndexBy(array, value, getIteratee(iteratee, 2)); + } + + /** + * This method is like `_.indexOf` except that it performs a binary + * search on a sorted `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.sortedIndexOf([4, 5, 5, 5, 6], 5); + * // => 1 + */ + function sortedIndexOf(array, value) { + var length = array == null ? 0 : array.length; + if (length) { + var index = baseSortedIndex(array, value); + if (index < length && eq(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * This method is like `_.sortedIndex` except that it returns the highest + * index at which `value` should be inserted into `array` in order to + * maintain its sort order. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * _.sortedLastIndex([4, 5, 5, 5, 6], 5); + * // => 4 + */ + function sortedLastIndex(array, value) { + return baseSortedIndex(array, value, true); + } + + /** + * This method is like `_.sortedLastIndex` except that it accepts `iteratee` + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {number} Returns the index at which `value` should be inserted + * into `array`. + * @example + * + * var objects = [{ 'x': 4 }, { 'x': 5 }]; + * + * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; }); + * // => 1 + * + * // The `_.property` iteratee shorthand. + * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x'); + * // => 1 + */ + function sortedLastIndexBy(array, value, iteratee) { + return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true); + } + + /** + * This method is like `_.lastIndexOf` except that it performs a binary + * search on a sorted `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5); + * // => 3 + */ + function sortedLastIndexOf(array, value) { + var length = array == null ? 0 : array.length; + if (length) { + var index = baseSortedIndex(array, value, true) - 1; + if (eq(array[index], value)) { + return index; + } + } + return -1; + } + + /** + * This method is like `_.uniq` except that it's designed and optimized + * for sorted arrays. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.sortedUniq([1, 1, 2]); + * // => [1, 2] + */ + function sortedUniq(array) { + return (array && array.length) + ? baseSortedUniq(array) + : []; + } + + /** + * This method is like `_.uniqBy` except that it's designed and optimized + * for sorted arrays. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor); + * // => [1.1, 2.3] + */ + function sortedUniqBy(array, iteratee) { + return (array && array.length) + ? baseSortedUniq(array, getIteratee(iteratee, 2)) + : []; + } + + /** + * Gets all but the first element of `array`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.tail([1, 2, 3]); + * // => [2, 3] + */ + function tail(array) { + var length = array == null ? 0 : array.length; + return length ? baseSlice(array, 1, length) : []; + } + + /** + * Creates a slice of `array` with `n` elements taken from the beginning. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.take([1, 2, 3]); + * // => [1] + * + * _.take([1, 2, 3], 2); + * // => [1, 2] + * + * _.take([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.take([1, 2, 3], 0); + * // => [] + */ + function take(array, n, guard) { + if (!(array && array.length)) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + return baseSlice(array, 0, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` with `n` elements taken from the end. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeRight([1, 2, 3]); + * // => [3] + * + * _.takeRight([1, 2, 3], 2); + * // => [2, 3] + * + * _.takeRight([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.takeRight([1, 2, 3], 0); + * // => [] + */ + function takeRight(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + n = length - n; + return baseSlice(array, n < 0 ? 0 : n, length); + } + + /** + * Creates a slice of `array` with elements taken from the end. Elements are + * taken until `predicate` returns falsey. The predicate is invoked with + * three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.takeRightWhile(users, function(o) { return !o.active; }); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.matches` iteratee shorthand. + * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false }); + * // => objects for ['pebbles'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.takeRightWhile(users, ['active', false]); + * // => objects for ['fred', 'pebbles'] + * + * // The `_.property` iteratee shorthand. + * _.takeRightWhile(users, 'active'); + * // => [] + */ + function takeRightWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3), false, true) + : []; + } + + /** + * Creates a slice of `array` with elements taken from the beginning. Elements + * are taken until `predicate` returns falsey. The predicate is invoked with + * three arguments: (value, index, array). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the slice of `array`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.takeWhile(users, function(o) { return !o.active; }); + * // => objects for ['barney', 'fred'] + * + * // The `_.matches` iteratee shorthand. + * _.takeWhile(users, { 'user': 'barney', 'active': false }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.takeWhile(users, ['active', false]); + * // => objects for ['barney', 'fred'] + * + * // The `_.property` iteratee shorthand. + * _.takeWhile(users, 'active'); + * // => [] + */ + function takeWhile(array, predicate) { + return (array && array.length) + ? baseWhile(array, getIteratee(predicate, 3)) + : []; + } + + /** + * Creates an array of unique values, in order, from all given arrays using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of combined values. + * @example + * + * _.union([2], [1, 2]); + * // => [2, 1] + */ + var union = baseRest(function(arrays) { + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); + }); + + /** + * This method is like `_.union` except that it accepts `iteratee` which is + * invoked for each element of each `arrays` to generate the criterion by + * which uniqueness is computed. Result values are chosen from the first + * array in which the value occurs. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of combined values. + * @example + * + * _.unionBy([2.1], [1.2, 2.3], Math.floor); + * // => [2.1, 1.2] + * + * // The `_.property` iteratee shorthand. + * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + var unionBy = baseRest(function(arrays) { + var iteratee = last(arrays); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2)); + }); + + /** + * This method is like `_.union` except that it accepts `comparator` which + * is invoked to compare elements of `arrays`. Result values are chosen from + * the first array in which the value occurs. The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of combined values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.unionWith(objects, others, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] + */ + var unionWith = baseRest(function(arrays) { + var comparator = last(arrays); + comparator = typeof comparator == 'function' ? comparator : undefined; + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator); + }); + + /** + * Creates a duplicate-free version of an array, using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons, in which only the first occurrence of each element + * is kept. The order of result values is determined by the order they occur + * in the array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniq([2, 1, 2]); + * // => [2, 1] + */ + function uniq(array) { + return (array && array.length) ? baseUniq(array) : []; + } + + /** + * This method is like `_.uniq` except that it accepts `iteratee` which is + * invoked for each element in `array` to generate the criterion by which + * uniqueness is computed. The order of result values is determined by the + * order they occur in the array. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniqBy([2.1, 1.2, 2.3], Math.floor); + * // => [2.1, 1.2] + * + * // The `_.property` iteratee shorthand. + * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + function uniqBy(array, iteratee) { + return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : []; + } + + /** + * This method is like `_.uniq` except that it accepts `comparator` which + * is invoked to compare elements of `array`. The order of result values is + * determined by the order they occur in the array.The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.uniqWith(objects, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }] + */ + function uniqWith(array, comparator) { + comparator = typeof comparator == 'function' ? comparator : undefined; + return (array && array.length) ? baseUniq(array, undefined, comparator) : []; + } + + /** + * This method is like `_.zip` except that it accepts an array of grouped + * elements and creates an array regrouping the elements to their pre-zip + * configuration. + * + * @static + * @memberOf _ + * @since 1.2.0 + * @category Array + * @param {Array} array The array of grouped elements to process. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]); + * // => [['a', 1, true], ['b', 2, false]] + * + * _.unzip(zipped); + * // => [['a', 'b'], [1, 2], [true, false]] + */ + function unzip(array) { + if (!(array && array.length)) { + return []; + } + var length = 0; + array = arrayFilter(array, function(group) { + if (isArrayLikeObject(group)) { + length = nativeMax(group.length, length); + return true; + } + }); + return baseTimes(length, function(index) { + return arrayMap(array, baseProperty(index)); + }); + } + + /** + * This method is like `_.unzip` except that it accepts `iteratee` to specify + * how regrouped values should be combined. The iteratee is invoked with the + * elements of each group: (...group). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Array + * @param {Array} array The array of grouped elements to process. + * @param {Function} [iteratee=_.identity] The function to combine + * regrouped values. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip([1, 2], [10, 20], [100, 200]); + * // => [[1, 10, 100], [2, 20, 200]] + * + * _.unzipWith(zipped, _.add); + * // => [3, 30, 300] + */ + function unzipWith(array, iteratee) { + if (!(array && array.length)) { + return []; + } + var result = unzip(array); + if (iteratee == null) { + return result; + } + return arrayMap(result, function(group) { + return apply(iteratee, undefined, group); + }); + } + + /** + * Creates an array excluding all given values using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * **Note:** Unlike `_.pull`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...*} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @see _.difference, _.xor + * @example + * + * _.without([2, 1, 2, 3], 1, 2); + * // => [3] + */ + var without = baseRest(function(array, values) { + return isArrayLikeObject(array) + ? baseDifference(array, values) + : []; + }); + + /** + * Creates an array of unique values that is the + * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference) + * of the given arrays. The order of result values is determined by the order + * they occur in the arrays. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of filtered values. + * @see _.difference, _.without + * @example + * + * _.xor([2, 1], [2, 3]); + * // => [1, 3] + */ + var xor = baseRest(function(arrays) { + return baseXor(arrayFilter(arrays, isArrayLikeObject)); + }); + + /** + * This method is like `_.xor` except that it accepts `iteratee` which is + * invoked for each element of each `arrays` to generate the criterion by + * which by which they're compared. The order of result values is determined + * by the order they occur in the arrays. The iteratee is invoked with one + * argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor); + * // => [1.2, 3.4] + * + * // The `_.property` iteratee shorthand. + * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 2 }] + */ + var xorBy = baseRest(function(arrays) { + var iteratee = last(arrays); + if (isArrayLikeObject(iteratee)) { + iteratee = undefined; + } + return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2)); + }); + + /** + * This method is like `_.xor` except that it accepts `comparator` which is + * invoked to compare elements of `arrays`. The order of result values is + * determined by the order they occur in the arrays. The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.xorWith(objects, others, _.isEqual); + * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] + */ + var xorWith = baseRest(function(arrays) { + var comparator = last(arrays); + comparator = typeof comparator == 'function' ? comparator : undefined; + return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator); + }); + + /** + * Creates an array of grouped elements, the first of which contains the + * first elements of the given arrays, the second of which contains the + * second elements of the given arrays, and so on. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zip(['a', 'b'], [1, 2], [true, false]); + * // => [['a', 1, true], ['b', 2, false]] + */ + var zip = baseRest(unzip); + + /** + * This method is like `_.fromPairs` except that it accepts two arrays, + * one of property identifiers and one of corresponding values. + * + * @static + * @memberOf _ + * @since 0.4.0 + * @category Array + * @param {Array} [props=[]] The property identifiers. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObject(['a', 'b'], [1, 2]); + * // => { 'a': 1, 'b': 2 } + */ + function zipObject(props, values) { + return baseZipObject(props || [], values || [], assignValue); + } + + /** + * This method is like `_.zipObject` except that it supports property paths. + * + * @static + * @memberOf _ + * @since 4.1.0 + * @category Array + * @param {Array} [props=[]] The property identifiers. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]); + * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } } + */ + function zipObjectDeep(props, values) { + return baseZipObject(props || [], values || [], baseSet); + } + + /** + * This method is like `_.zip` except that it accepts `iteratee` to specify + * how grouped values should be combined. The iteratee is invoked with the + * elements of each group: (...group). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @param {Function} [iteratee=_.identity] The function to combine + * grouped values. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) { + * return a + b + c; + * }); + * // => [111, 222] + */ + var zipWith = baseRest(function(arrays) { + var length = arrays.length, + iteratee = length > 1 ? arrays[length - 1] : undefined; + + iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined; + return unzipWith(arrays, iteratee); + }); + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` wrapper instance that wraps `value` with explicit method + * chain sequences enabled. The result of such sequences must be unwrapped + * with `_#value`. + * + * @static + * @memberOf _ + * @since 1.3.0 + * @category Seq + * @param {*} value The value to wrap. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'pebbles', 'age': 1 } + * ]; + * + * var youngest = _ + * .chain(users) + * .sortBy('age') + * .map(function(o) { + * return o.user + ' is ' + o.age; + * }) + * .head() + * .value(); + * // => 'pebbles is 1' + */ + function chain(value) { + var result = lodash(value); + result.__chain__ = true; + return result; + } + + /** + * This method invokes `interceptor` and returns `value`. The interceptor + * is invoked with one argument; (value). The purpose of this method is to + * "tap into" a method chain sequence in order to modify intermediate results. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @returns {*} Returns `value`. + * @example + * + * _([1, 2, 3]) + * .tap(function(array) { + * // Mutate input array. + * array.pop(); + * }) + * .reverse() + * .value(); + * // => [2, 1] + */ + function tap(value, interceptor) { + interceptor(value); + return value; + } + + /** + * This method is like `_.tap` except that it returns the result of `interceptor`. + * The purpose of this method is to "pass thru" values replacing intermediate + * results in a method chain sequence. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Seq + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @returns {*} Returns the result of `interceptor`. + * @example + * + * _(' abc ') + * .chain() + * .trim() + * .thru(function(value) { + * return [value]; + * }) + * .value(); + * // => ['abc'] + */ + function thru(value, interceptor) { + return interceptor(value); + } + + /** + * This method is the wrapper version of `_.at`. + * + * @name at + * @memberOf _ + * @since 1.0.0 + * @category Seq + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; + * + * _(object).at(['a[0].b.c', 'a[1]']).value(); + * // => [3, 4] + */ + var wrapperAt = flatRest(function(paths) { + var length = paths.length, + start = length ? paths[0] : 0, + value = this.__wrapped__, + interceptor = function(object) { return baseAt(object, paths); }; + + if (length > 1 || this.__actions__.length || + !(value instanceof LazyWrapper) || !isIndex(start)) { + return this.thru(interceptor); + } + value = value.slice(start, +start + (length ? 1 : 0)); + value.__actions__.push({ + 'func': thru, + 'args': [interceptor], + 'thisArg': undefined + }); + return new LodashWrapper(value, this.__chain__).thru(function(array) { + if (length && !array.length) { + array.push(undefined); + } + return array; + }); + }); + + /** + * Creates a `lodash` wrapper instance with explicit method chain sequences enabled. + * + * @name chain + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * // A sequence without explicit chaining. + * _(users).head(); + * // => { 'user': 'barney', 'age': 36 } + * + * // A sequence with explicit chaining. + * _(users) + * .chain() + * .head() + * .pick('user') + * .value(); + * // => { 'user': 'barney' } + */ + function wrapperChain() { + return chain(this); + } + + /** + * Executes the chain sequence and returns the wrapped result. + * + * @name commit + * @memberOf _ + * @since 3.2.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var array = [1, 2]; + * var wrapped = _(array).push(3); + * + * console.log(array); + * // => [1, 2] + * + * wrapped = wrapped.commit(); + * console.log(array); + * // => [1, 2, 3] + * + * wrapped.last(); + * // => 3 + * + * console.log(array); + * // => [1, 2, 3] + */ + function wrapperCommit() { + return new LodashWrapper(this.value(), this.__chain__); + } + + /** + * Gets the next value on a wrapped object following the + * [iterator protocol](https://mdn.io/iteration_protocols#iterator). + * + * @name next + * @memberOf _ + * @since 4.0.0 + * @category Seq + * @returns {Object} Returns the next iterator value. + * @example + * + * var wrapped = _([1, 2]); + * + * wrapped.next(); + * // => { 'done': false, 'value': 1 } + * + * wrapped.next(); + * // => { 'done': false, 'value': 2 } + * + * wrapped.next(); + * // => { 'done': true, 'value': undefined } + */ + function wrapperNext() { + if (this.__values__ === undefined) { + this.__values__ = toArray(this.value()); + } + var done = this.__index__ >= this.__values__.length, + value = done ? undefined : this.__values__[this.__index__++]; + + return { 'done': done, 'value': value }; + } + + /** + * Enables the wrapper to be iterable. + * + * @name Symbol.iterator + * @memberOf _ + * @since 4.0.0 + * @category Seq + * @returns {Object} Returns the wrapper object. + * @example + * + * var wrapped = _([1, 2]); + * + * wrapped[Symbol.iterator]() === wrapped; + * // => true + * + * Array.from(wrapped); + * // => [1, 2] + */ + function wrapperToIterator() { + return this; + } + + /** + * Creates a clone of the chain sequence planting `value` as the wrapped value. + * + * @name plant + * @memberOf _ + * @since 3.2.0 + * @category Seq + * @param {*} value The value to plant. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var wrapped = _([1, 2]).map(square); + * var other = wrapped.plant([3, 4]); + * + * other.value(); + * // => [9, 16] + * + * wrapped.value(); + * // => [1, 4] + */ + function wrapperPlant(value) { + var result, + parent = this; + + while (parent instanceof baseLodash) { + var clone = wrapperClone(parent); + clone.__index__ = 0; + clone.__values__ = undefined; + if (result) { + previous.__wrapped__ = clone; + } else { + result = clone; + } + var previous = clone; + parent = parent.__wrapped__; + } + previous.__wrapped__ = value; + return result; + } + + /** + * This method is the wrapper version of `_.reverse`. + * + * **Note:** This method mutates the wrapped array. + * + * @name reverse + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var array = [1, 2, 3]; + * + * _(array).reverse().value() + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + function wrapperReverse() { + var value = this.__wrapped__; + if (value instanceof LazyWrapper) { + var wrapped = value; + if (this.__actions__.length) { + wrapped = new LazyWrapper(this); + } + wrapped = wrapped.reverse(); + wrapped.__actions__.push({ + 'func': thru, + 'args': [reverse], + 'thisArg': undefined + }); + return new LodashWrapper(wrapped, this.__chain__); + } + return this.thru(reverse); + } + + /** + * Executes the chain sequence to resolve the unwrapped value. + * + * @name value + * @memberOf _ + * @since 0.1.0 + * @alias toJSON, valueOf + * @category Seq + * @returns {*} Returns the resolved unwrapped value. + * @example + * + * _([1, 2, 3]).value(); + * // => [1, 2, 3] + */ + function wrapperValue() { + return baseWrapperValue(this.__wrapped__, this.__actions__); + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The corresponding value of + * each key is the number of times the key was returned by `iteratee`. The + * iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.countBy([6.1, 4.2, 6.3], Math.floor); + * // => { '4': 1, '6': 2 } + * + * // The `_.property` iteratee shorthand. + * _.countBy(['one', 'two', 'three'], 'length'); + * // => { '3': 2, '5': 1 } + */ + var countBy = createAggregator(function(result, value, key) { + if (hasOwnProperty.call(result, key)) { + ++result[key]; + } else { + baseAssignValue(result, key, 1); + } + }); + + /** + * Checks if `predicate` returns truthy for **all** elements of `collection`. + * Iteration is stopped once `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index|key, collection). + * + * **Note:** This method returns `true` for + * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because + * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of + * elements of empty collections. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + * @example + * + * _.every([true, 1, null, 'yes'], Boolean); + * // => false + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * // The `_.matches` iteratee shorthand. + * _.every(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // The `_.matchesProperty` iteratee shorthand. + * _.every(users, ['active', false]); + * // => true + * + * // The `_.property` iteratee shorthand. + * _.every(users, 'active'); + * // => false + */ + function every(collection, predicate, guard) { + var func = isArray(collection) ? arrayEvery : baseEvery; + if (guard && isIterateeCall(collection, predicate, guard)) { + predicate = undefined; + } + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Iterates over elements of `collection`, returning an array of all elements + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index|key, collection). + * + * **Note:** Unlike `_.remove`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @see _.reject + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * _.filter(users, function(o) { return !o.active; }); + * // => objects for ['fred'] + * + * // The `_.matches` iteratee shorthand. + * _.filter(users, { 'age': 36, 'active': true }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.filter(users, ['active', false]); + * // => objects for ['fred'] + * + * // The `_.property` iteratee shorthand. + * _.filter(users, 'active'); + * // => objects for ['barney'] + */ + function filter(collection, predicate) { + var func = isArray(collection) ? arrayFilter : baseFilter; + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Iterates over elements of `collection`, returning the first element + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false }, + * { 'user': 'pebbles', 'age': 1, 'active': true } + * ]; + * + * _.find(users, function(o) { return o.age < 40; }); + * // => object for 'barney' + * + * // The `_.matches` iteratee shorthand. + * _.find(users, { 'age': 1, 'active': true }); + * // => object for 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.find(users, ['active', false]); + * // => object for 'fred' + * + * // The `_.property` iteratee shorthand. + * _.find(users, 'active'); + * // => object for 'barney' + */ + var find = createFind(findIndex); + + /** + * This method is like `_.find` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Collection + * @param {Array|Object} collection The collection to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=collection.length-1] The index to search from. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * _.findLast([1, 2, 3, 4], function(n) { + * return n % 2 == 1; + * }); + * // => 3 + */ + var findLast = createFind(findLastIndex); + + /** + * Creates a flattened array of values by running each element in `collection` + * thru `iteratee` and flattening the mapped results. The iteratee is invoked + * with three arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [n, n]; + * } + * + * _.flatMap([1, 2], duplicate); + * // => [1, 1, 2, 2] + */ + function flatMap(collection, iteratee) { + return baseFlatten(map(collection, iteratee), 1); + } + + /** + * This method is like `_.flatMap` except that it recursively flattens the + * mapped results. + * + * @static + * @memberOf _ + * @since 4.7.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [[[n, n]]]; + * } + * + * _.flatMapDeep([1, 2], duplicate); + * // => [1, 1, 2, 2] + */ + function flatMapDeep(collection, iteratee) { + return baseFlatten(map(collection, iteratee), INFINITY); + } + + /** + * This method is like `_.flatMap` except that it recursively flattens the + * mapped results up to `depth` times. + * + * @static + * @memberOf _ + * @since 4.7.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {number} [depth=1] The maximum recursion depth. + * @returns {Array} Returns the new flattened array. + * @example + * + * function duplicate(n) { + * return [[[n, n]]]; + * } + * + * _.flatMapDepth([1, 2], duplicate, 2); + * // => [[1, 1], [2, 2]] + */ + function flatMapDepth(collection, iteratee, depth) { + depth = depth === undefined ? 1 : toInteger(depth); + return baseFlatten(map(collection, iteratee), depth); + } + + /** + * Iterates over elements of `collection` and invokes `iteratee` for each element. + * The iteratee is invoked with three arguments: (value, index|key, collection). + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * **Note:** As with other "Collections" methods, objects with a "length" + * property are iterated like arrays. To avoid this behavior use `_.forIn` + * or `_.forOwn` for object iteration. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @alias each + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + * @see _.forEachRight + * @example + * + * _.forEach([1, 2], function(value) { + * console.log(value); + * }); + * // => Logs `1` then `2`. + * + * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a' then 'b' (iteration order is not guaranteed). + */ + function forEach(collection, iteratee) { + var func = isArray(collection) ? arrayEach : baseEach; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.forEach` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @alias eachRight + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + * @see _.forEach + * @example + * + * _.forEachRight([1, 2], function(value) { + * console.log(value); + * }); + * // => Logs `2` then `1`. + */ + function forEachRight(collection, iteratee) { + var func = isArray(collection) ? arrayEachRight : baseEachRight; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The order of grouped values + * is determined by the order they occur in `collection`. The corresponding + * value of each key is an array of elements responsible for generating the + * key. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.groupBy([6.1, 4.2, 6.3], Math.floor); + * // => { '4': [4.2], '6': [6.1, 6.3] } + * + * // The `_.property` iteratee shorthand. + * _.groupBy(['one', 'two', 'three'], 'length'); + * // => { '3': ['one', 'two'], '5': ['three'] } + */ + var groupBy = createAggregator(function(result, value, key) { + if (hasOwnProperty.call(result, key)) { + result[key].push(value); + } else { + baseAssignValue(result, key, [value]); + } + }); + + /** + * Checks if `value` is in `collection`. If `collection` is a string, it's + * checked for a substring of `value`, otherwise + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * is used for equality comparisons. If `fromIndex` is negative, it's used as + * the offset from the end of `collection`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. + * @returns {boolean} Returns `true` if `value` is found, else `false`. + * @example + * + * _.includes([1, 2, 3], 1); + * // => true + * + * _.includes([1, 2, 3], 1, 2); + * // => false + * + * _.includes({ 'a': 1, 'b': 2 }, 1); + * // => true + * + * _.includes('abcd', 'bc'); + * // => true + */ + function includes(collection, value, fromIndex, guard) { + collection = isArrayLike(collection) ? collection : values(collection); + fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0; + + var length = collection.length; + if (fromIndex < 0) { + fromIndex = nativeMax(length + fromIndex, 0); + } + return isString(collection) + ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1) + : (!!length && baseIndexOf(collection, value, fromIndex) > -1); + } + + /** + * Invokes the method at `path` of each element in `collection`, returning + * an array of the results of each invoked method. Any additional arguments + * are provided to each invoked method. If `path` is a function, it's invoked + * for, and `this` bound to, each element in `collection`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Function|string} path The path of the method to invoke or + * the function invoked per iteration. + * @param {...*} [args] The arguments to invoke each method with. + * @returns {Array} Returns the array of results. + * @example + * + * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort'); + * // => [[1, 5, 7], [1, 2, 3]] + * + * _.invokeMap([123, 456], String.prototype.split, ''); + * // => [['1', '2', '3'], ['4', '5', '6']] + */ + var invokeMap = baseRest(function(collection, path, args) { + var index = -1, + isFunc = typeof path == 'function', + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function(value) { + result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args); + }); + return result; + }); + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The corresponding value of + * each key is the last element responsible for generating the key. The + * iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * var array = [ + * { 'dir': 'left', 'code': 97 }, + * { 'dir': 'right', 'code': 100 } + * ]; + * + * _.keyBy(array, function(o) { + * return String.fromCharCode(o.code); + * }); + * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } + * + * _.keyBy(array, 'dir'); + * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } } + */ + var keyBy = createAggregator(function(result, value, key) { + baseAssignValue(result, key, value); + }); + + /** + * Creates an array of values by running each element in `collection` thru + * `iteratee`. The iteratee is invoked with three arguments: + * (value, index|key, collection). + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. + * + * The guarded methods are: + * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, + * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`, + * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`, + * `template`, `trim`, `trimEnd`, `trimStart`, and `words` + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + * @example + * + * function square(n) { + * return n * n; + * } + * + * _.map([4, 8], square); + * // => [16, 64] + * + * _.map({ 'a': 4, 'b': 8 }, square); + * // => [16, 64] (iteration order is not guaranteed) + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * // The `_.property` iteratee shorthand. + * _.map(users, 'user'); + * // => ['barney', 'fred'] + */ + function map(collection, iteratee) { + var func = isArray(collection) ? arrayMap : baseMap; + return func(collection, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.sortBy` except that it allows specifying the sort + * orders of the iteratees to sort by. If `orders` is unspecified, all values + * are sorted in ascending order. Otherwise, specify an order of "desc" for + * descending or "asc" for ascending sort order of corresponding values. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]] + * The iteratees to sort by. + * @param {string[]} [orders] The sort orders of `iteratees`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 34 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'barney', 'age': 36 } + * ]; + * + * // Sort by `user` in ascending order and by `age` in descending order. + * _.orderBy(users, ['user', 'age'], ['asc', 'desc']); + * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] + */ + function orderBy(collection, iteratees, orders, guard) { + if (collection == null) { + return []; + } + if (!isArray(iteratees)) { + iteratees = iteratees == null ? [] : [iteratees]; + } + orders = guard ? undefined : orders; + if (!isArray(orders)) { + orders = orders == null ? [] : [orders]; + } + return baseOrderBy(collection, iteratees, orders); + } + + /** + * Creates an array of elements split into two groups, the first of which + * contains elements `predicate` returns truthy for, the second of which + * contains elements `predicate` returns falsey for. The predicate is + * invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the array of grouped elements. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * _.partition(users, function(o) { return o.active; }); + * // => objects for [['fred'], ['barney', 'pebbles']] + * + * // The `_.matches` iteratee shorthand. + * _.partition(users, { 'age': 1, 'active': false }); + * // => objects for [['pebbles'], ['barney', 'fred']] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.partition(users, ['active', false]); + * // => objects for [['barney', 'pebbles'], ['fred']] + * + * // The `_.property` iteratee shorthand. + * _.partition(users, 'active'); + * // => objects for [['fred'], ['barney', 'pebbles']] + */ + var partition = createAggregator(function(result, value, key) { + result[key ? 0 : 1].push(value); + }, function() { return [[], []]; }); + + /** + * Reduces `collection` to a value which is the accumulated result of running + * each element in `collection` thru `iteratee`, where each successive + * invocation is supplied the return value of the previous. If `accumulator` + * is not given, the first element of `collection` is used as the initial + * value. The iteratee is invoked with four arguments: + * (accumulator, value, index|key, collection). + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.reduce`, `_.reduceRight`, and `_.transform`. + * + * The guarded methods are: + * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, + * and `sortBy` + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @returns {*} Returns the accumulated value. + * @see _.reduceRight + * @example + * + * _.reduce([1, 2], function(sum, n) { + * return sum + n; + * }, 0); + * // => 3 + * + * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { + * (result[value] || (result[value] = [])).push(key); + * return result; + * }, {}); + * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) + */ + function reduce(collection, iteratee, accumulator) { + var func = isArray(collection) ? arrayReduce : baseReduce, + initAccum = arguments.length < 3; + + return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach); + } + + /** + * This method is like `_.reduce` except that it iterates over elements of + * `collection` from right to left. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @returns {*} Returns the accumulated value. + * @see _.reduce + * @example + * + * var array = [[0, 1], [2, 3], [4, 5]]; + * + * _.reduceRight(array, function(flattened, other) { + * return flattened.concat(other); + * }, []); + * // => [4, 5, 2, 3, 0, 1] + */ + function reduceRight(collection, iteratee, accumulator) { + var func = isArray(collection) ? arrayReduceRight : baseReduce, + initAccum = arguments.length < 3; + + return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight); + } + + /** + * The opposite of `_.filter`; this method returns the elements of `collection` + * that `predicate` does **not** return truthy for. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @see _.filter + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true } + * ]; + * + * _.reject(users, function(o) { return !o.active; }); + * // => objects for ['fred'] + * + * // The `_.matches` iteratee shorthand. + * _.reject(users, { 'age': 40, 'active': true }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.reject(users, ['active', false]); + * // => objects for ['fred'] + * + * // The `_.property` iteratee shorthand. + * _.reject(users, 'active'); + * // => objects for ['barney'] + */ + function reject(collection, predicate) { + var func = isArray(collection) ? arrayFilter : baseFilter; + return func(collection, negate(getIteratee(predicate, 3))); + } + + /** + * Gets a random element from `collection`. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Collection + * @param {Array|Object} collection The collection to sample. + * @returns {*} Returns the random element. + * @example + * + * _.sample([1, 2, 3, 4]); + * // => 2 + */ + function sample(collection) { + var func = isArray(collection) ? arraySample : baseSample; + return func(collection); + } + + /** + * Gets `n` random elements at unique keys from `collection` up to the + * size of `collection`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Collection + * @param {Array|Object} collection The collection to sample. + * @param {number} [n=1] The number of elements to sample. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the random elements. + * @example + * + * _.sampleSize([1, 2, 3], 2); + * // => [3, 1] + * + * _.sampleSize([1, 2, 3], 4); + * // => [2, 3, 1] + */ + function sampleSize(collection, n, guard) { + if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) { + n = 1; + } else { + n = toInteger(n); + } + var func = isArray(collection) ? arraySampleSize : baseSampleSize; + return func(collection, n); + } + + /** + * Creates an array of shuffled values, using a version of the + * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to shuffle. + * @returns {Array} Returns the new shuffled array. + * @example + * + * _.shuffle([1, 2, 3, 4]); + * // => [4, 1, 3, 2] + */ + function shuffle(collection) { + var func = isArray(collection) ? arrayShuffle : baseShuffle; + return func(collection); + } + + /** + * Gets the size of `collection` by returning its length for array-like + * values or the number of own enumerable string keyed properties for objects. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @returns {number} Returns the collection size. + * @example + * + * _.size([1, 2, 3]); + * // => 3 + * + * _.size({ 'a': 1, 'b': 2 }); + * // => 2 + * + * _.size('pebbles'); + * // => 7 + */ + function size(collection) { + if (collection == null) { + return 0; + } + if (isArrayLike(collection)) { + return isString(collection) ? stringSize(collection) : collection.length; + } + var tag = getTag(collection); + if (tag == mapTag || tag == setTag) { + return collection.size; + } + return baseKeys(collection).length; + } + + /** + * Checks if `predicate` returns truthy for **any** element of `collection`. + * Iteration is stopped once `predicate` returns truthy. The predicate is + * invoked with three arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + * @example + * + * _.some([null, 0, 'yes', false], Boolean); + * // => true + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false } + * ]; + * + * // The `_.matches` iteratee shorthand. + * _.some(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // The `_.matchesProperty` iteratee shorthand. + * _.some(users, ['active', false]); + * // => true + * + * // The `_.property` iteratee shorthand. + * _.some(users, 'active'); + * // => true + */ + function some(collection, predicate, guard) { + var func = isArray(collection) ? arraySome : baseSome; + if (guard && isIterateeCall(collection, predicate, guard)) { + predicate = undefined; + } + return func(collection, getIteratee(predicate, 3)); + } + + /** + * Creates an array of elements, sorted in ascending order by the results of + * running each element in a collection thru each iteratee. This method + * performs a stable sort, that is, it preserves the original sort order of + * equal elements. The iteratees are invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {...(Function|Function[])} [iteratees=[_.identity]] + * The iteratees to sort by. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'barney', 'age': 34 } + * ]; + * + * _.sortBy(users, [function(o) { return o.user; }]); + * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] + * + * _.sortBy(users, ['user', 'age']); + * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]] + */ + var sortBy = baseRest(function(collection, iteratees) { + if (collection == null) { + return []; + } + var length = iteratees.length; + if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) { + iteratees = []; + } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) { + iteratees = [iteratees[0]]; + } + return baseOrderBy(collection, baseFlatten(iteratees, 1), []); + }); + + /*------------------------------------------------------------------------*/ + + /** + * Gets the timestamp of the number of milliseconds that have elapsed since + * the Unix epoch (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Date + * @returns {number} Returns the timestamp. + * @example + * + * _.defer(function(stamp) { + * console.log(_.now() - stamp); + * }, _.now()); + * // => Logs the number of milliseconds it took for the deferred invocation. + */ + var now = ctxNow || function() { + return root.Date.now(); + }; + + /*------------------------------------------------------------------------*/ + + /** + * The opposite of `_.before`; this method creates a function that invokes + * `func` once it's called `n` or more times. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {number} n The number of calls before `func` is invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var saves = ['profile', 'settings']; + * + * var done = _.after(saves.length, function() { + * console.log('done saving!'); + * }); + * + * _.forEach(saves, function(type) { + * asyncSave({ 'type': type, 'complete': done }); + * }); + * // => Logs 'done saving!' after the two async saves have completed. + */ + function after(n, func) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + n = toInteger(n); + return function() { + if (--n < 1) { + return func.apply(this, arguments); + } + }; + } + + /** + * Creates a function that invokes `func`, with up to `n` arguments, + * ignoring any additional arguments. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to cap arguments for. + * @param {number} [n=func.length] The arity cap. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new capped function. + * @example + * + * _.map(['6', '8', '10'], _.ary(parseInt, 1)); + * // => [6, 8, 10] + */ + function ary(func, n, guard) { + n = guard ? undefined : n; + n = (func && n == null) ? func.length : n; + return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n); + } + + /** + * Creates a function that invokes `func`, with the `this` binding and arguments + * of the created function, while it's called less than `n` times. Subsequent + * calls to the created function return the result of the last `func` invocation. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {number} n The number of calls at which `func` is no longer invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * jQuery(element).on('click', _.before(5, addContactToList)); + * // => Allows adding up to 4 contacts to the list. + */ + function before(n, func) { + var result; + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + n = toInteger(n); + return function() { + if (--n > 0) { + result = func.apply(this, arguments); + } + if (n <= 1) { + func = undefined; + } + return result; + }; + } + + /** + * Creates a function that invokes `func` with the `this` binding of `thisArg` + * and `partials` prepended to the arguments it receives. + * + * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for partially applied arguments. + * + * **Note:** Unlike native `Function#bind`, this method doesn't set the "length" + * property of bound functions. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * function greet(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * } + * + * var object = { 'user': 'fred' }; + * + * var bound = _.bind(greet, object, 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * // Bound with placeholders. + * var bound = _.bind(greet, object, _, '!'); + * bound('hi'); + * // => 'hi fred!' + */ + var bind = baseRest(function(func, thisArg, partials) { + var bitmask = WRAP_BIND_FLAG; + if (partials.length) { + var holders = replaceHolders(partials, getHolder(bind)); + bitmask |= WRAP_PARTIAL_FLAG; + } + return createWrap(func, bitmask, thisArg, partials, holders); + }); + + /** + * Creates a function that invokes the method at `object[key]` with `partials` + * prepended to the arguments it receives. + * + * This method differs from `_.bind` by allowing bound functions to reference + * methods that may be redefined or don't yet exist. See + * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern) + * for more details. + * + * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * @static + * @memberOf _ + * @since 0.10.0 + * @category Function + * @param {Object} object The object to invoke the method on. + * @param {string} key The key of the method. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var object = { + * 'user': 'fred', + * 'greet': function(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * } + * }; + * + * var bound = _.bindKey(object, 'greet', 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * object.greet = function(greeting, punctuation) { + * return greeting + 'ya ' + this.user + punctuation; + * }; + * + * bound('!'); + * // => 'hiya fred!' + * + * // Bound with placeholders. + * var bound = _.bindKey(object, 'greet', _, '!'); + * bound('hi'); + * // => 'hiya fred!' + */ + var bindKey = baseRest(function(object, key, partials) { + var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG; + if (partials.length) { + var holders = replaceHolders(partials, getHolder(bindKey)); + bitmask |= WRAP_PARTIAL_FLAG; + } + return createWrap(key, bitmask, object, partials, holders); + }); + + /** + * Creates a function that accepts arguments of `func` and either invokes + * `func` returning its result, if at least `arity` number of arguments have + * been provided, or returns a function that accepts the remaining `func` + * arguments, and so on. The arity of `func` may be specified if `func.length` + * is not sufficient. + * + * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for provided arguments. + * + * **Note:** This method doesn't set the "length" property of curried functions. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curry(abc); + * + * curried(1)(2)(3); + * // => [1, 2, 3] + * + * curried(1, 2)(3); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // Curried with placeholders. + * curried(1)(_, 3)(2); + * // => [1, 2, 3] + */ + function curry(func, arity, guard) { + arity = guard ? undefined : arity; + var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity); + result.placeholder = curry.placeholder; + return result; + } + + /** + * This method is like `_.curry` except that arguments are applied to `func` + * in the manner of `_.partialRight` instead of `_.partial`. + * + * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for provided arguments. + * + * **Note:** This method doesn't set the "length" property of curried functions. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to curry. + * @param {number} [arity=func.length] The arity of `func`. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the new curried function. + * @example + * + * var abc = function(a, b, c) { + * return [a, b, c]; + * }; + * + * var curried = _.curryRight(abc); + * + * curried(3)(2)(1); + * // => [1, 2, 3] + * + * curried(2, 3)(1); + * // => [1, 2, 3] + * + * curried(1, 2, 3); + * // => [1, 2, 3] + * + * // Curried with placeholders. + * curried(3)(1, _)(2); + * // => [1, 2, 3] + */ + function curryRight(func, arity, guard) { + arity = guard ? undefined : arity; + var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity); + result.placeholder = curryRight.placeholder; + return result; + } + + /** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked. The debounced function comes with a `cancel` method to cancel + * delayed `func` invocations and a `flush` method to immediately invoke them. + * Provide `options` to indicate whether `func` should be invoked on the + * leading and/or trailing edge of the `wait` timeout. The `func` is invoked + * with the last arguments provided to the debounced function. Subsequent + * calls to the debounced function return the result of the last `func` + * invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the debounced function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] The number of milliseconds to delay. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=false] + * Specify invoking on the leading edge of the timeout. + * @param {number} [options.maxWait] + * The maximum time `func` is allowed to be delayed before it's invoked. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // Avoid costly calculations while the window size is in flux. + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // Invoke `sendMail` when clicked, debouncing subsequent calls. + * jQuery(element).on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // Ensure `batchLog` is invoked once after 1 second of debounced calls. + * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); + * var source = new EventSource('/stream'); + * jQuery(source).on('message', debounced); + * + * // Cancel the trailing debounced invocation. + * jQuery(window).on('popstate', debounced.cancel); + */ + function debounce(func, wait, options) { + var lastArgs, + lastThis, + maxWait, + result, + timerId, + lastCallTime, + lastInvokeTime = 0, + leading = false, + maxing = false, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = toNumber(wait) || 0; + if (isObject(options)) { + leading = !!options.leading; + maxing = 'maxWait' in options; + maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + + function invokeFunc(time) { + var args = lastArgs, + thisArg = lastThis; + + lastArgs = lastThis = undefined; + lastInvokeTime = time; + result = func.apply(thisArg, args); + return result; + } + + function leadingEdge(time) { + // Reset any `maxWait` timer. + lastInvokeTime = time; + // Start the timer for the trailing edge. + timerId = setTimeout(timerExpired, wait); + // Invoke the leading edge. + return leading ? invokeFunc(time) : result; + } + + function remainingWait(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime, + timeWaiting = wait - timeSinceLastCall; + + return maxing + ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) + : timeWaiting; + } + + function shouldInvoke(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime; + + // Either this is the first call, activity has stopped and we're at the + // trailing edge, the system time has gone backwards and we're treating + // it as the trailing edge, or we've hit the `maxWait` limit. + return (lastCallTime === undefined || (timeSinceLastCall >= wait) || + (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); + } + + function timerExpired() { + var time = now(); + if (shouldInvoke(time)) { + return trailingEdge(time); + } + // Restart the timer. + timerId = setTimeout(timerExpired, remainingWait(time)); + } + + function trailingEdge(time) { + timerId = undefined; + + // Only invoke if we have `lastArgs` which means `func` has been + // debounced at least once. + if (trailing && lastArgs) { + return invokeFunc(time); + } + lastArgs = lastThis = undefined; + return result; + } + + function cancel() { + if (timerId !== undefined) { + clearTimeout(timerId); + } + lastInvokeTime = 0; + lastArgs = lastCallTime = lastThis = timerId = undefined; + } + + function flush() { + return timerId === undefined ? result : trailingEdge(now()); + } + + function debounced() { + var time = now(), + isInvoking = shouldInvoke(time); + + lastArgs = arguments; + lastThis = this; + lastCallTime = time; + + if (isInvoking) { + if (timerId === undefined) { + return leadingEdge(lastCallTime); + } + if (maxing) { + // Handle invocations in a tight loop. + timerId = setTimeout(timerExpired, wait); + return invokeFunc(lastCallTime); + } + } + if (timerId === undefined) { + timerId = setTimeout(timerExpired, wait); + } + return result; + } + debounced.cancel = cancel; + debounced.flush = flush; + return debounced; + } + + /** + * Defers invoking the `func` until the current call stack has cleared. Any + * additional arguments are provided to `func` when it's invoked. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to defer. + * @param {...*} [args] The arguments to invoke `func` with. + * @returns {number} Returns the timer id. + * @example + * + * _.defer(function(text) { + * console.log(text); + * }, 'deferred'); + * // => Logs 'deferred' after one millisecond. + */ + var defer = baseRest(function(func, args) { + return baseDelay(func, 1, args); + }); + + /** + * Invokes `func` after `wait` milliseconds. Any additional arguments are + * provided to `func` when it's invoked. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {...*} [args] The arguments to invoke `func` with. + * @returns {number} Returns the timer id. + * @example + * + * _.delay(function(text) { + * console.log(text); + * }, 1000, 'later'); + * // => Logs 'later' after one second. + */ + var delay = baseRest(function(func, wait, args) { + return baseDelay(func, toNumber(wait) || 0, args); + }); + + /** + * Creates a function that invokes `func` with arguments reversed. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to flip arguments for. + * @returns {Function} Returns the new flipped function. + * @example + * + * var flipped = _.flip(function() { + * return _.toArray(arguments); + * }); + * + * flipped('a', 'b', 'c', 'd'); + * // => ['d', 'c', 'b', 'a'] + */ + function flip(func) { + return createWrap(func, WRAP_FLIP_FLAG); + } + + /** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided, it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is used as the map cache key. The `func` + * is invoked with the `this` binding of the memoized function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the + * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) + * method interface of `clear`, `delete`, `get`, `has`, and `set`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoized function. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * var other = { 'c': 3, 'd': 4 }; + * + * var values = _.memoize(_.values); + * values(object); + * // => [1, 2] + * + * values(other); + * // => [3, 4] + * + * object.a = 2; + * values(object); + * // => [1, 2] + * + * // Modify the result cache. + * values.cache.set(object, ['a', 'b']); + * values(object); + * // => ['a', 'b'] + * + * // Replace `_.memoize.Cache`. + * _.memoize.Cache = WeakMap; + */ + function memoize(func, resolver) { + if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function() { + var args = arguments, + key = resolver ? resolver.apply(this, args) : args[0], + cache = memoized.cache; + + if (cache.has(key)) { + return cache.get(key); + } + var result = func.apply(this, args); + memoized.cache = cache.set(key, result) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || MapCache); + return memoized; + } + + // Expose `MapCache`. + memoize.Cache = MapCache; + + /** + * Creates a function that negates the result of the predicate `func`. The + * `func` predicate is invoked with the `this` binding and arguments of the + * created function. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} predicate The predicate to negate. + * @returns {Function} Returns the new negated function. + * @example + * + * function isEven(n) { + * return n % 2 == 0; + * } + * + * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); + * // => [1, 3, 5] + */ + function negate(predicate) { + if (typeof predicate != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function() { + var args = arguments; + switch (args.length) { + case 0: return !predicate.call(this); + case 1: return !predicate.call(this, args[0]); + case 2: return !predicate.call(this, args[0], args[1]); + case 3: return !predicate.call(this, args[0], args[1], args[2]); + } + return !predicate.apply(this, args); + }; + } + + /** + * Creates a function that is restricted to invoking `func` once. Repeat calls + * to the function return the value of the first invocation. The `func` is + * invoked with the `this` binding and arguments of the created function. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var initialize = _.once(createApplication); + * initialize(); + * initialize(); + * // => `createApplication` is invoked once + */ + function once(func) { + return before(2, func); + } + + /** + * Creates a function that invokes `func` with its arguments transformed. + * + * @static + * @since 4.0.0 + * @memberOf _ + * @category Function + * @param {Function} func The function to wrap. + * @param {...(Function|Function[])} [transforms=[_.identity]] + * The argument transforms. + * @returns {Function} Returns the new function. + * @example + * + * function doubled(n) { + * return n * 2; + * } + * + * function square(n) { + * return n * n; + * } + * + * var func = _.overArgs(function(x, y) { + * return [x, y]; + * }, [square, doubled]); + * + * func(9, 3); + * // => [81, 6] + * + * func(10, 5); + * // => [100, 10] + */ + var overArgs = castRest(function(func, transforms) { + transforms = (transforms.length == 1 && isArray(transforms[0])) + ? arrayMap(transforms[0], baseUnary(getIteratee())) + : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee())); + + var funcsLength = transforms.length; + return baseRest(function(args) { + var index = -1, + length = nativeMin(args.length, funcsLength); + + while (++index < length) { + args[index] = transforms[index].call(this, args[index]); + } + return apply(func, this, args); + }); + }); + + /** + * Creates a function that invokes `func` with `partials` prepended to the + * arguments it receives. This method is like `_.bind` except it does **not** + * alter the `this` binding. + * + * The `_.partial.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method doesn't set the "length" property of partially + * applied functions. + * + * @static + * @memberOf _ + * @since 0.2.0 + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * function greet(greeting, name) { + * return greeting + ' ' + name; + * } + * + * var sayHelloTo = _.partial(greet, 'hello'); + * sayHelloTo('fred'); + * // => 'hello fred' + * + * // Partially applied with placeholders. + * var greetFred = _.partial(greet, _, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + */ + var partial = baseRest(function(func, partials) { + var holders = replaceHolders(partials, getHolder(partial)); + return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders); + }); + + /** + * This method is like `_.partial` except that partially applied arguments + * are appended to the arguments it receives. + * + * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic + * builds, may be used as a placeholder for partially applied arguments. + * + * **Note:** This method doesn't set the "length" property of partially + * applied functions. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Function + * @param {Function} func The function to partially apply arguments to. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new partially applied function. + * @example + * + * function greet(greeting, name) { + * return greeting + ' ' + name; + * } + * + * var greetFred = _.partialRight(greet, 'fred'); + * greetFred('hi'); + * // => 'hi fred' + * + * // Partially applied with placeholders. + * var sayHelloTo = _.partialRight(greet, 'hello', _); + * sayHelloTo('fred'); + * // => 'hello fred' + */ + var partialRight = baseRest(function(func, partials) { + var holders = replaceHolders(partials, getHolder(partialRight)); + return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders); + }); + + /** + * Creates a function that invokes `func` with arguments arranged according + * to the specified `indexes` where the argument value at the first index is + * provided as the first argument, the argument value at the second index is + * provided as the second argument, and so on. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} func The function to rearrange arguments for. + * @param {...(number|number[])} indexes The arranged argument indexes. + * @returns {Function} Returns the new function. + * @example + * + * var rearged = _.rearg(function(a, b, c) { + * return [a, b, c]; + * }, [2, 0, 1]); + * + * rearged('b', 'c', 'a') + * // => ['a', 'b', 'c'] + */ + var rearg = flatRest(function(func, indexes) { + return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes); + }); + + /** + * Creates a function that invokes `func` with the `this` binding of the + * created function and arguments from `start` and beyond provided as + * an array. + * + * **Note:** This method is based on the + * [rest parameter](https://mdn.io/rest_parameters). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + * @example + * + * var say = _.rest(function(what, names) { + * return what + ' ' + _.initial(names).join(', ') + + * (_.size(names) > 1 ? ', & ' : '') + _.last(names); + * }); + * + * say('hello', 'fred', 'barney', 'pebbles'); + * // => 'hello fred, barney, & pebbles' + */ + function rest(func, start) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + start = start === undefined ? start : toInteger(start); + return baseRest(func, start); + } + + /** + * Creates a function that invokes `func` with the `this` binding of the + * create function and an array of arguments much like + * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply). + * + * **Note:** This method is based on the + * [spread operator](https://mdn.io/spread_operator). + * + * @static + * @memberOf _ + * @since 3.2.0 + * @category Function + * @param {Function} func The function to spread arguments over. + * @param {number} [start=0] The start position of the spread. + * @returns {Function} Returns the new function. + * @example + * + * var say = _.spread(function(who, what) { + * return who + ' says ' + what; + * }); + * + * say(['fred', 'hello']); + * // => 'fred says hello' + * + * var numbers = Promise.all([ + * Promise.resolve(40), + * Promise.resolve(36) + * ]); + * + * numbers.then(_.spread(function(x, y) { + * return x + y; + * })); + * // => a Promise of 76 + */ + function spread(func, start) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + start = start == null ? 0 : nativeMax(toInteger(start), 0); + return baseRest(function(args) { + var array = args[start], + otherArgs = castSlice(args, 0, start); + + if (array) { + arrayPush(otherArgs, array); + } + return apply(func, this, otherArgs); + }); + } + + /** + * Creates a throttled function that only invokes `func` at most once per + * every `wait` milliseconds. The throttled function comes with a `cancel` + * method to cancel delayed `func` invocations and a `flush` method to + * immediately invoke them. Provide `options` to indicate whether `func` + * should be invoked on the leading and/or trailing edge of the `wait` + * timeout. The `func` is invoked with the last arguments provided to the + * throttled function. Subsequent calls to the throttled function return the + * result of the last `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the throttled function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.throttle` and `_.debounce`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to throttle. + * @param {number} [wait=0] The number of milliseconds to throttle invocations to. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=true] + * Specify invoking on the leading edge of the timeout. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new throttled function. + * @example + * + * // Avoid excessively updating the position while scrolling. + * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); + * + * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. + * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); + * jQuery(element).on('click', throttled); + * + * // Cancel the trailing throttled invocation. + * jQuery(window).on('popstate', throttled.cancel); + */ + function throttle(func, wait, options) { + var leading = true, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (isObject(options)) { + leading = 'leading' in options ? !!options.leading : leading; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + return debounce(func, wait, { + 'leading': leading, + 'maxWait': wait, + 'trailing': trailing + }); + } + + /** + * Creates a function that accepts up to one argument, ignoring any + * additional arguments. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + * @example + * + * _.map(['6', '8', '10'], _.unary(parseInt)); + * // => [6, 8, 10] + */ + function unary(func) { + return ary(func, 1); + } + + /** + * Creates a function that provides `value` to `wrapper` as its first + * argument. Any additional arguments provided to the function are appended + * to those provided to the `wrapper`. The wrapper is invoked with the `this` + * binding of the created function. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {*} value The value to wrap. + * @param {Function} [wrapper=identity] The wrapper function. + * @returns {Function} Returns the new function. + * @example + * + * var p = _.wrap(_.escape, function(func, text) { + * return '

          ' + func(text) + '

          '; + * }); + * + * p('fred, barney, & pebbles'); + * // => '

          fred, barney, & pebbles

          ' + */ + function wrap(value, wrapper) { + return partial(castFunction(wrapper), value); + } + + /*------------------------------------------------------------------------*/ + + /** + * Casts `value` as an array if it's not one. + * + * @static + * @memberOf _ + * @since 4.4.0 + * @category Lang + * @param {*} value The value to inspect. + * @returns {Array} Returns the cast array. + * @example + * + * _.castArray(1); + * // => [1] + * + * _.castArray({ 'a': 1 }); + * // => [{ 'a': 1 }] + * + * _.castArray('abc'); + * // => ['abc'] + * + * _.castArray(null); + * // => [null] + * + * _.castArray(undefined); + * // => [undefined] + * + * _.castArray(); + * // => [] + * + * var array = [1, 2, 3]; + * console.log(_.castArray(array) === array); + * // => true + */ + function castArray() { + if (!arguments.length) { + return []; + } + var value = arguments[0]; + return isArray(value) ? value : [value]; + } + + /** + * Creates a shallow clone of `value`. + * + * **Note:** This method is loosely based on the + * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) + * and supports cloning arrays, array buffers, booleans, date objects, maps, + * numbers, `Object` objects, regexes, sets, strings, symbols, and typed + * arrays. The own enumerable properties of `arguments` objects are cloned + * as plain objects. An empty object is returned for uncloneable values such + * as error objects, functions, DOM nodes, and WeakMaps. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to clone. + * @returns {*} Returns the cloned value. + * @see _.cloneDeep + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var shallow = _.clone(objects); + * console.log(shallow[0] === objects[0]); + * // => true + */ + function clone(value) { + return baseClone(value, CLONE_SYMBOLS_FLAG); + } + + /** + * This method is like `_.clone` except that it accepts `customizer` which + * is invoked to produce the cloned value. If `customizer` returns `undefined`, + * cloning is handled by the method instead. The `customizer` is invoked with + * up to four arguments; (value [, index|key, object, stack]). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to clone. + * @param {Function} [customizer] The function to customize cloning. + * @returns {*} Returns the cloned value. + * @see _.cloneDeepWith + * @example + * + * function customizer(value) { + * if (_.isElement(value)) { + * return value.cloneNode(false); + * } + * } + * + * var el = _.cloneWith(document.body, customizer); + * + * console.log(el === document.body); + * // => false + * console.log(el.nodeName); + * // => 'BODY' + * console.log(el.childNodes.length); + * // => 0 + */ + function cloneWith(value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseClone(value, CLONE_SYMBOLS_FLAG, customizer); + } + + /** + * This method is like `_.clone` except that it recursively clones `value`. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Lang + * @param {*} value The value to recursively clone. + * @returns {*} Returns the deep cloned value. + * @see _.clone + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var deep = _.cloneDeep(objects); + * console.log(deep[0] === objects[0]); + * // => false + */ + function cloneDeep(value) { + return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG); + } + + /** + * This method is like `_.cloneWith` except that it recursively clones `value`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to recursively clone. + * @param {Function} [customizer] The function to customize cloning. + * @returns {*} Returns the deep cloned value. + * @see _.cloneWith + * @example + * + * function customizer(value) { + * if (_.isElement(value)) { + * return value.cloneNode(true); + * } + * } + * + * var el = _.cloneDeepWith(document.body, customizer); + * + * console.log(el === document.body); + * // => false + * console.log(el.nodeName); + * // => 'BODY' + * console.log(el.childNodes.length); + * // => 20 + */ + function cloneDeepWith(value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer); + } + + /** + * Checks if `object` conforms to `source` by invoking the predicate + * properties of `source` with the corresponding property values of `object`. + * + * **Note:** This method is equivalent to `_.conforms` when `source` is + * partially applied. + * + * @static + * @memberOf _ + * @since 4.14.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property predicates to conform to. + * @returns {boolean} Returns `true` if `object` conforms, else `false`. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * + * _.conformsTo(object, { 'b': function(n) { return n > 1; } }); + * // => true + * + * _.conformsTo(object, { 'b': function(n) { return n > 2; } }); + * // => false + */ + function conformsTo(object, source) { + return source == null || baseConformsTo(object, source, keys(source)); + } + + /** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ + function eq(value, other) { + return value === other || (value !== value && other !== other); + } + + /** + * Checks if `value` is greater than `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than `other`, + * else `false`. + * @see _.lt + * @example + * + * _.gt(3, 1); + * // => true + * + * _.gt(3, 3); + * // => false + * + * _.gt(1, 3); + * // => false + */ + var gt = createRelationalOperation(baseGt); + + /** + * Checks if `value` is greater than or equal to `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than or equal to + * `other`, else `false`. + * @see _.lte + * @example + * + * _.gte(3, 1); + * // => true + * + * _.gte(3, 3); + * // => true + * + * _.gte(1, 3); + * // => false + */ + var gte = createRelationalOperation(function(value, other) { + return value >= other; + }); + + /** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ + var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); + }; + + /** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ + var isArray = Array.isArray; + + /** + * Checks if `value` is classified as an `ArrayBuffer` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`. + * @example + * + * _.isArrayBuffer(new ArrayBuffer(2)); + * // => true + * + * _.isArrayBuffer(new Array(2)); + * // => false + */ + var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer; + + /** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ + function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); + } + + /** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ + function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike(value); + } + + /** + * Checks if `value` is classified as a boolean primitive or object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a boolean, else `false`. + * @example + * + * _.isBoolean(false); + * // => true + * + * _.isBoolean(null); + * // => false + */ + function isBoolean(value) { + return value === true || value === false || + (isObjectLike(value) && baseGetTag(value) == boolTag); + } + + /** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ + var isBuffer = nativeIsBuffer || stubFalse; + + /** + * Checks if `value` is classified as a `Date` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a date object, else `false`. + * @example + * + * _.isDate(new Date); + * // => true + * + * _.isDate('Mon April 23 2012'); + * // => false + */ + var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate; + + /** + * Checks if `value` is likely a DOM element. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`. + * @example + * + * _.isElement(document.body); + * // => true + * + * _.isElement(''); + * // => false + */ + function isElement(value) { + return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value); + } + + /** + * Checks if `value` is an empty object, collection, map, or set. + * + * Objects are considered empty if they have no own enumerable string keyed + * properties. + * + * Array-like values such as `arguments` objects, arrays, buffers, strings, or + * jQuery-like collections are considered empty if they have a `length` of `0`. + * Similarly, maps and sets are considered empty if they have a `size` of `0`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is empty, else `false`. + * @example + * + * _.isEmpty(null); + * // => true + * + * _.isEmpty(true); + * // => true + * + * _.isEmpty(1); + * // => true + * + * _.isEmpty([1, 2, 3]); + * // => false + * + * _.isEmpty({ 'a': 1 }); + * // => false + */ + function isEmpty(value) { + if (value == null) { + return true; + } + if (isArrayLike(value) && + (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || + isBuffer(value) || isTypedArray(value) || isArguments(value))) { + return !value.length; + } + var tag = getTag(value); + if (tag == mapTag || tag == setTag) { + return !value.size; + } + if (isPrototype(value)) { + return !baseKeys(value).length; + } + for (var key in value) { + if (hasOwnProperty.call(value, key)) { + return false; + } + } + return true; + } + + /** + * Performs a deep comparison between two values to determine if they are + * equivalent. + * + * **Note:** This method supports comparing arrays, array buffers, booleans, + * date objects, error objects, maps, numbers, `Object` objects, regexes, + * sets, strings, symbols, and typed arrays. `Object` objects are compared + * by their own, not inherited, enumerable properties. Functions and DOM + * nodes are compared by strict equality, i.e. `===`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.isEqual(object, other); + * // => true + * + * object === other; + * // => false + */ + function isEqual(value, other) { + return baseIsEqual(value, other); + } + + /** + * This method is like `_.isEqual` except that it accepts `customizer` which + * is invoked to compare values. If `customizer` returns `undefined`, comparisons + * are handled by the method instead. The `customizer` is invoked with up to + * six arguments: (objValue, othValue [, index|key, object, other, stack]). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * function isGreeting(value) { + * return /^h(?:i|ello)$/.test(value); + * } + * + * function customizer(objValue, othValue) { + * if (isGreeting(objValue) && isGreeting(othValue)) { + * return true; + * } + * } + * + * var array = ['hello', 'goodbye']; + * var other = ['hi', 'goodbye']; + * + * _.isEqualWith(array, other, customizer); + * // => true + */ + function isEqualWith(value, other, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + var result = customizer ? customizer(value, other) : undefined; + return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result; + } + + /** + * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`, + * `SyntaxError`, `TypeError`, or `URIError` object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an error object, else `false`. + * @example + * + * _.isError(new Error); + * // => true + * + * _.isError(Error); + * // => false + */ + function isError(value) { + if (!isObjectLike(value)) { + return false; + } + var tag = baseGetTag(value); + return tag == errorTag || tag == domExcTag || + (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value)); + } + + /** + * Checks if `value` is a finite primitive number. + * + * **Note:** This method is based on + * [`Number.isFinite`](https://mdn.io/Number/isFinite). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. + * @example + * + * _.isFinite(3); + * // => true + * + * _.isFinite(Number.MIN_VALUE); + * // => true + * + * _.isFinite(Infinity); + * // => false + * + * _.isFinite('3'); + * // => false + */ + function isFinite(value) { + return typeof value == 'number' && nativeIsFinite(value); + } + + /** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ + function isFunction(value) { + if (!isObject(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; + } + + /** + * Checks if `value` is an integer. + * + * **Note:** This method is based on + * [`Number.isInteger`](https://mdn.io/Number/isInteger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an integer, else `false`. + * @example + * + * _.isInteger(3); + * // => true + * + * _.isInteger(Number.MIN_VALUE); + * // => false + * + * _.isInteger(Infinity); + * // => false + * + * _.isInteger('3'); + * // => false + */ + function isInteger(value) { + return typeof value == 'number' && value == toInteger(value); + } + + /** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ + function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; + } + + /** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ + function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); + } + + /** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ + function isObjectLike(value) { + return value != null && typeof value == 'object'; + } + + /** + * Checks if `value` is classified as a `Map` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a map, else `false`. + * @example + * + * _.isMap(new Map); + * // => true + * + * _.isMap(new WeakMap); + * // => false + */ + var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; + + /** + * Performs a partial deep comparison between `object` and `source` to + * determine if `object` contains equivalent property values. + * + * **Note:** This method is equivalent to `_.matches` when `source` is + * partially applied. + * + * Partial comparisons will match empty array and empty object `source` + * values against any array or object value, respectively. See `_.isEqual` + * for a list of supported value comparisons. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * + * _.isMatch(object, { 'b': 2 }); + * // => true + * + * _.isMatch(object, { 'b': 1 }); + * // => false + */ + function isMatch(object, source) { + return object === source || baseIsMatch(object, source, getMatchData(source)); + } + + /** + * This method is like `_.isMatch` except that it accepts `customizer` which + * is invoked to compare values. If `customizer` returns `undefined`, comparisons + * are handled by the method instead. The `customizer` is invoked with five + * arguments: (objValue, srcValue, index|key, object, source). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * function isGreeting(value) { + * return /^h(?:i|ello)$/.test(value); + * } + * + * function customizer(objValue, srcValue) { + * if (isGreeting(objValue) && isGreeting(srcValue)) { + * return true; + * } + * } + * + * var object = { 'greeting': 'hello' }; + * var source = { 'greeting': 'hi' }; + * + * _.isMatchWith(object, source, customizer); + * // => true + */ + function isMatchWith(object, source, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return baseIsMatch(object, source, getMatchData(source), customizer); + } + + /** + * Checks if `value` is `NaN`. + * + * **Note:** This method is based on + * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as + * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for + * `undefined` and other non-number values. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @example + * + * _.isNaN(NaN); + * // => true + * + * _.isNaN(new Number(NaN)); + * // => true + * + * isNaN(undefined); + * // => true + * + * _.isNaN(undefined); + * // => false + */ + function isNaN(value) { + // An `NaN` primitive is the only value that is not equal to itself. + // Perform the `toStringTag` check first to avoid errors with some + // ActiveX objects in IE. + return isNumber(value) && value != +value; + } + + /** + * Checks if `value` is a pristine native function. + * + * **Note:** This method can't reliably detect native functions in the presence + * of the core-js package because core-js circumvents this kind of detection. + * Despite multiple requests, the core-js maintainer has made it clear: any + * attempt to fix the detection will be obstructed. As a result, we're left + * with little choice but to throw an error. Unfortunately, this also affects + * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill), + * which rely on core-js. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + * @example + * + * _.isNative(Array.prototype.push); + * // => true + * + * _.isNative(_); + * // => false + */ + function isNative(value) { + if (isMaskable(value)) { + throw new Error(CORE_ERROR_TEXT); + } + return baseIsNative(value); + } + + /** + * Checks if `value` is `null`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `null`, else `false`. + * @example + * + * _.isNull(null); + * // => true + * + * _.isNull(void 0); + * // => false + */ + function isNull(value) { + return value === null; + } + + /** + * Checks if `value` is `null` or `undefined`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is nullish, else `false`. + * @example + * + * _.isNil(null); + * // => true + * + * _.isNil(void 0); + * // => true + * + * _.isNil(NaN); + * // => false + */ + function isNil(value) { + return value == null; + } + + /** + * Checks if `value` is classified as a `Number` primitive or object. + * + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are + * classified as numbers, use the `_.isFinite` method. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a number, else `false`. + * @example + * + * _.isNumber(3); + * // => true + * + * _.isNumber(Number.MIN_VALUE); + * // => true + * + * _.isNumber(Infinity); + * // => true + * + * _.isNumber('3'); + * // => false + */ + function isNumber(value) { + return typeof value == 'number' || + (isObjectLike(value) && baseGetTag(value) == numberTag); + } + + /** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ + function isPlainObject(value) { + if (!isObjectLike(value) || baseGetTag(value) != objectTag) { + return false; + } + var proto = getPrototype(value); + if (proto === null) { + return true; + } + var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) == objectCtorString; + } + + /** + * Checks if `value` is classified as a `RegExp` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + * @example + * + * _.isRegExp(/abc/); + * // => true + * + * _.isRegExp('/abc/'); + * // => false + */ + var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; + + /** + * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754 + * double precision number which isn't the result of a rounded unsafe integer. + * + * **Note:** This method is based on + * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`. + * @example + * + * _.isSafeInteger(3); + * // => true + * + * _.isSafeInteger(Number.MIN_VALUE); + * // => false + * + * _.isSafeInteger(Infinity); + * // => false + * + * _.isSafeInteger('3'); + * // => false + */ + function isSafeInteger(value) { + return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER; + } + + /** + * Checks if `value` is classified as a `Set` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a set, else `false`. + * @example + * + * _.isSet(new Set); + * // => true + * + * _.isSet(new WeakSet); + * // => false + */ + var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; + + /** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ + function isString(value) { + return typeof value == 'string' || + (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); + } + + /** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ + function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); + } + + /** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ + var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + + /** + * Checks if `value` is `undefined`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + * @example + * + * _.isUndefined(void 0); + * // => true + * + * _.isUndefined(null); + * // => false + */ + function isUndefined(value) { + return value === undefined; + } + + /** + * Checks if `value` is classified as a `WeakMap` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a weak map, else `false`. + * @example + * + * _.isWeakMap(new WeakMap); + * // => true + * + * _.isWeakMap(new Map); + * // => false + */ + function isWeakMap(value) { + return isObjectLike(value) && getTag(value) == weakMapTag; + } + + /** + * Checks if `value` is classified as a `WeakSet` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a weak set, else `false`. + * @example + * + * _.isWeakSet(new WeakSet); + * // => true + * + * _.isWeakSet(new Set); + * // => false + */ + function isWeakSet(value) { + return isObjectLike(value) && baseGetTag(value) == weakSetTag; + } + + /** + * Checks if `value` is less than `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than `other`, + * else `false`. + * @see _.gt + * @example + * + * _.lt(1, 3); + * // => true + * + * _.lt(3, 3); + * // => false + * + * _.lt(3, 1); + * // => false + */ + var lt = createRelationalOperation(baseLt); + + /** + * Checks if `value` is less than or equal to `other`. + * + * @static + * @memberOf _ + * @since 3.9.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than or equal to + * `other`, else `false`. + * @see _.gte + * @example + * + * _.lte(1, 3); + * // => true + * + * _.lte(3, 3); + * // => true + * + * _.lte(3, 1); + * // => false + */ + var lte = createRelationalOperation(function(value, other) { + return value <= other; + }); + + /** + * Converts `value` to an array. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {Array} Returns the converted array. + * @example + * + * _.toArray({ 'a': 1, 'b': 2 }); + * // => [1, 2] + * + * _.toArray('abc'); + * // => ['a', 'b', 'c'] + * + * _.toArray(1); + * // => [] + * + * _.toArray(null); + * // => [] + */ + function toArray(value) { + if (!value) { + return []; + } + if (isArrayLike(value)) { + return isString(value) ? stringToArray(value) : copyArray(value); + } + if (symIterator && value[symIterator]) { + return iteratorToArray(value[symIterator]()); + } + var tag = getTag(value), + func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); + + return func(value); + } + + /** + * Converts `value` to a finite number. + * + * @static + * @memberOf _ + * @since 4.12.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted number. + * @example + * + * _.toFinite(3.2); + * // => 3.2 + * + * _.toFinite(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toFinite(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toFinite('3.2'); + * // => 3.2 + */ + function toFinite(value) { + if (!value) { + return value === 0 ? value : 0; + } + value = toNumber(value); + if (value === INFINITY || value === -INFINITY) { + var sign = (value < 0 ? -1 : 1); + return sign * MAX_INTEGER; + } + return value === value ? value : 0; + } + + /** + * Converts `value` to an integer. + * + * **Note:** This method is loosely based on + * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toInteger(3.2); + * // => 3 + * + * _.toInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toInteger(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toInteger('3.2'); + * // => 3 + */ + function toInteger(value) { + var result = toFinite(value), + remainder = result % 1; + + return result === result ? (remainder ? result - remainder : result) : 0; + } + + /** + * Converts `value` to an integer suitable for use as the length of an + * array-like object. + * + * **Note:** This method is based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toLength(3.2); + * // => 3 + * + * _.toLength(Number.MIN_VALUE); + * // => 0 + * + * _.toLength(Infinity); + * // => 4294967295 + * + * _.toLength('3.2'); + * // => 3 + */ + function toLength(value) { + return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0; + } + + /** + * Converts `value` to a number. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @example + * + * _.toNumber(3.2); + * // => 3.2 + * + * _.toNumber(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toNumber(Infinity); + * // => Infinity + * + * _.toNumber('3.2'); + * // => 3.2 + */ + function toNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + if (isObject(value)) { + var other = typeof value.valueOf == 'function' ? value.valueOf() : value; + value = isObject(other) ? (other + '') : other; + } + if (typeof value != 'string') { + return value === 0 ? value : +value; + } + value = value.replace(reTrim, ''); + var isBinary = reIsBinary.test(value); + return (isBinary || reIsOctal.test(value)) + ? freeParseInt(value.slice(2), isBinary ? 2 : 8) + : (reIsBadHex.test(value) ? NAN : +value); + } + + /** + * Converts `value` to a plain object flattening inherited enumerable string + * keyed properties of `value` to own properties of the plain object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {Object} Returns the converted plain object. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.assign({ 'a': 1 }, new Foo); + * // => { 'a': 1, 'b': 2 } + * + * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); + * // => { 'a': 1, 'b': 2, 'c': 3 } + */ + function toPlainObject(value) { + return copyObject(value, keysIn(value)); + } + + /** + * Converts `value` to a safe integer. A safe integer can be compared and + * represented correctly. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toSafeInteger(3.2); + * // => 3 + * + * _.toSafeInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toSafeInteger(Infinity); + * // => 9007199254740991 + * + * _.toSafeInteger('3.2'); + * // => 3 + */ + function toSafeInteger(value) { + return value + ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER) + : (value === 0 ? value : 0); + } + + /** + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' + */ + function toString(value) { + return value == null ? '' : baseToString(value); + } + + /*------------------------------------------------------------------------*/ + + /** + * Assigns own enumerable string keyed properties of source objects to the + * destination object. Source objects are applied from left to right. + * Subsequent sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object` and is loosely based on + * [`Object.assign`](https://mdn.io/Object/assign). + * + * @static + * @memberOf _ + * @since 0.10.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.assignIn + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * function Bar() { + * this.c = 3; + * } + * + * Foo.prototype.b = 2; + * Bar.prototype.d = 4; + * + * _.assign({ 'a': 0 }, new Foo, new Bar); + * // => { 'a': 1, 'c': 3 } + */ + var assign = createAssigner(function(object, source) { + if (isPrototype(source) || isArrayLike(source)) { + copyObject(source, keys(source), object); + return; + } + for (var key in source) { + if (hasOwnProperty.call(source, key)) { + assignValue(object, key, source[key]); + } + } + }); + + /** + * This method is like `_.assign` except that it iterates over own and + * inherited source properties. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias extend + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.assign + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * function Bar() { + * this.c = 3; + * } + * + * Foo.prototype.b = 2; + * Bar.prototype.d = 4; + * + * _.assignIn({ 'a': 0 }, new Foo, new Bar); + * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 } + */ + var assignIn = createAssigner(function(object, source) { + copyObject(source, keysIn(source), object); + }); + + /** + * This method is like `_.assignIn` except that it accepts `customizer` + * which is invoked to produce the assigned values. If `customizer` returns + * `undefined`, assignment is handled by the method instead. The `customizer` + * is invoked with five arguments: (objValue, srcValue, key, object, source). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias extendWith + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @see _.assignWith + * @example + * + * function customizer(objValue, srcValue) { + * return _.isUndefined(objValue) ? srcValue : objValue; + * } + * + * var defaults = _.partialRight(_.assignInWith, customizer); + * + * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var assignInWith = createAssigner(function(object, source, srcIndex, customizer) { + copyObject(source, keysIn(source), object, customizer); + }); + + /** + * This method is like `_.assign` except that it accepts `customizer` + * which is invoked to produce the assigned values. If `customizer` returns + * `undefined`, assignment is handled by the method instead. The `customizer` + * is invoked with five arguments: (objValue, srcValue, key, object, source). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @see _.assignInWith + * @example + * + * function customizer(objValue, srcValue) { + * return _.isUndefined(objValue) ? srcValue : objValue; + * } + * + * var defaults = _.partialRight(_.assignWith, customizer); + * + * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var assignWith = createAssigner(function(object, source, srcIndex, customizer) { + copyObject(source, keys(source), object, customizer); + }); + + /** + * Creates an array of values corresponding to `paths` of `object`. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Array} Returns the picked values. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; + * + * _.at(object, ['a[0].b.c', 'a[1]']); + * // => [3, 4] + */ + var at = flatRest(baseAt); + + /** + * Creates an object that inherits from the `prototype` object. If a + * `properties` object is given, its own enumerable string keyed properties + * are assigned to the created object. + * + * @static + * @memberOf _ + * @since 2.3.0 + * @category Object + * @param {Object} prototype The object to inherit from. + * @param {Object} [properties] The properties to assign to the object. + * @returns {Object} Returns the new object. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * function Circle() { + * Shape.call(this); + * } + * + * Circle.prototype = _.create(Shape.prototype, { + * 'constructor': Circle + * }); + * + * var circle = new Circle; + * circle instanceof Circle; + * // => true + * + * circle instanceof Shape; + * // => true + */ + function create(prototype, properties) { + var result = baseCreate(prototype); + return properties == null ? result : baseAssign(result, properties); + } + + /** + * Assigns own and inherited enumerable string keyed properties of source + * objects to the destination object for all destination properties that + * resolve to `undefined`. Source objects are applied from left to right. + * Once a property is set, additional values of the same property are ignored. + * + * **Note:** This method mutates `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.defaultsDeep + * @example + * + * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var defaults = baseRest(function(object, sources) { + object = Object(object); + + var index = -1; + var length = sources.length; + var guard = length > 2 ? sources[2] : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + length = 1; + } + + while (++index < length) { + var source = sources[index]; + var props = keysIn(source); + var propsIndex = -1; + var propsLength = props.length; + + while (++propsIndex < propsLength) { + var key = props[propsIndex]; + var value = object[key]; + + if (value === undefined || + (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) { + object[key] = source[key]; + } + } + } + + return object; + }); + + /** + * This method is like `_.defaults` except that it recursively assigns + * default properties. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 3.10.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.defaults + * @example + * + * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } }); + * // => { 'a': { 'b': 2, 'c': 3 } } + */ + var defaultsDeep = baseRest(function(args) { + args.push(undefined, customDefaultsMerge); + return apply(mergeWith, undefined, args); + }); + + /** + * This method is like `_.find` except that it returns the key of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findKey(users, function(o) { return o.age < 40; }); + * // => 'barney' (iteration order is not guaranteed) + * + * // The `_.matches` iteratee shorthand. + * _.findKey(users, { 'age': 1, 'active': true }); + * // => 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findKey(users, 'active'); + * // => 'barney' + */ + function findKey(object, predicate) { + return baseFindKey(object, getIteratee(predicate, 3), baseForOwn); + } + + /** + * This method is like `_.findKey` except that it iterates over elements of + * a collection in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findLastKey(users, function(o) { return o.age < 40; }); + * // => returns 'pebbles' assuming `_.findKey` returns 'barney' + * + * // The `_.matches` iteratee shorthand. + * _.findLastKey(users, { 'age': 36, 'active': true }); + * // => 'barney' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findLastKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findLastKey(users, 'active'); + * // => 'pebbles' + */ + function findLastKey(object, predicate) { + return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight); + } + + /** + * Iterates over own and inherited enumerable string keyed properties of an + * object and invokes `iteratee` for each property. The iteratee is invoked + * with three arguments: (value, key, object). Iteratee functions may exit + * iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 0.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forInRight + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forIn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed). + */ + function forIn(object, iteratee) { + return object == null + ? object + : baseFor(object, getIteratee(iteratee, 3), keysIn); + } + + /** + * This method is like `_.forIn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forIn + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forInRight(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'. + */ + function forInRight(object, iteratee) { + return object == null + ? object + : baseForRight(object, getIteratee(iteratee, 3), keysIn); + } + + /** + * Iterates over own enumerable string keyed properties of an object and + * invokes `iteratee` for each property. The iteratee is invoked with three + * arguments: (value, key, object). Iteratee functions may exit iteration + * early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 0.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forOwnRight + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forOwn(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a' then 'b' (iteration order is not guaranteed). + */ + function forOwn(object, iteratee) { + return object && baseForOwn(object, getIteratee(iteratee, 3)); + } + + /** + * This method is like `_.forOwn` except that it iterates over properties of + * `object` in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns `object`. + * @see _.forOwn + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.forOwnRight(new Foo, function(value, key) { + * console.log(key); + * }); + * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'. + */ + function forOwnRight(object, iteratee) { + return object && baseForOwnRight(object, getIteratee(iteratee, 3)); + } + + /** + * Creates an array of function property names from own enumerable properties + * of `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the function names. + * @see _.functionsIn + * @example + * + * function Foo() { + * this.a = _.constant('a'); + * this.b = _.constant('b'); + * } + * + * Foo.prototype.c = _.constant('c'); + * + * _.functions(new Foo); + * // => ['a', 'b'] + */ + function functions(object) { + return object == null ? [] : baseFunctions(object, keys(object)); + } + + /** + * Creates an array of function property names from own and inherited + * enumerable properties of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the function names. + * @see _.functions + * @example + * + * function Foo() { + * this.a = _.constant('a'); + * this.b = _.constant('b'); + * } + * + * Foo.prototype.c = _.constant('c'); + * + * _.functionsIn(new Foo); + * // => ['a', 'b', 'c'] + */ + function functionsIn(object) { + return object == null ? [] : baseFunctions(object, keysIn(object)); + } + + /** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.get(object, 'a[0].b.c'); + * // => 3 + * + * _.get(object, ['a', '0', 'b', 'c']); + * // => 3 + * + * _.get(object, 'a.b.c', 'default'); + * // => 'default' + */ + function get(object, path, defaultValue) { + var result = object == null ? undefined : baseGet(object, path); + return result === undefined ? defaultValue : result; + } + + /** + * Checks if `path` is a direct property of `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = { 'a': { 'b': 2 } }; + * var other = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.has(object, 'a'); + * // => true + * + * _.has(object, 'a.b'); + * // => true + * + * _.has(object, ['a', 'b']); + * // => true + * + * _.has(other, 'a'); + * // => false + */ + function has(object, path) { + return object != null && hasPath(object, path, baseHas); + } + + /** + * Checks if `path` is a direct or inherited property of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.hasIn(object, 'a'); + * // => true + * + * _.hasIn(object, 'a.b'); + * // => true + * + * _.hasIn(object, ['a', 'b']); + * // => true + * + * _.hasIn(object, 'b'); + * // => false + */ + function hasIn(object, path) { + return object != null && hasPath(object, path, baseHasIn); + } + + /** + * Creates an object composed of the inverted keys and values of `object`. + * If `object` contains duplicate values, subsequent values overwrite + * property assignments of previous values. + * + * @static + * @memberOf _ + * @since 0.7.0 + * @category Object + * @param {Object} object The object to invert. + * @returns {Object} Returns the new inverted object. + * @example + * + * var object = { 'a': 1, 'b': 2, 'c': 1 }; + * + * _.invert(object); + * // => { '1': 'c', '2': 'b' } + */ + var invert = createInverter(function(result, value, key) { + if (value != null && + typeof value.toString != 'function') { + value = nativeObjectToString.call(value); + } + + result[value] = key; + }, constant(identity)); + + /** + * This method is like `_.invert` except that the inverted object is generated + * from the results of running each element of `object` thru `iteratee`. The + * corresponding inverted value of each inverted key is an array of keys + * responsible for generating the inverted value. The iteratee is invoked + * with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.1.0 + * @category Object + * @param {Object} object The object to invert. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Object} Returns the new inverted object. + * @example + * + * var object = { 'a': 1, 'b': 2, 'c': 1 }; + * + * _.invertBy(object); + * // => { '1': ['a', 'c'], '2': ['b'] } + * + * _.invertBy(object, function(value) { + * return 'group' + value; + * }); + * // => { 'group1': ['a', 'c'], 'group2': ['b'] } + */ + var invertBy = createInverter(function(result, value, key) { + if (value != null && + typeof value.toString != 'function') { + value = nativeObjectToString.call(value); + } + + if (hasOwnProperty.call(result, value)) { + result[value].push(key); + } else { + result[value] = [key]; + } + }, getIteratee); + + /** + * Invokes the method at `path` of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the method to invoke. + * @param {...*} [args] The arguments to invoke the method with. + * @returns {*} Returns the result of the invoked method. + * @example + * + * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] }; + * + * _.invoke(object, 'a[0].b.c.slice', 1, 3); + * // => [2, 3] + */ + var invoke = baseRest(baseInvoke); + + /** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * for more details. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ + function keys(object) { + return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); + } + + /** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ + function keysIn(object) { + return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); + } + + /** + * The opposite of `_.mapValues`; this method creates an object with the + * same values as `object` and keys generated by running each own enumerable + * string keyed property of `object` thru `iteratee`. The iteratee is invoked + * with three arguments: (value, key, object). + * + * @static + * @memberOf _ + * @since 3.8.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapValues + * @example + * + * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) { + * return key + value; + * }); + * // => { 'a1': 1, 'b2': 2 } + */ + function mapKeys(object, iteratee) { + var result = {}; + iteratee = getIteratee(iteratee, 3); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, iteratee(value, key, object), value); + }); + return result; + } + + /** + * Creates an object with the same keys as `object` and values generated + * by running each own enumerable string keyed property of `object` thru + * `iteratee`. The iteratee is invoked with three arguments: + * (value, key, object). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Object} Returns the new mapped object. + * @see _.mapKeys + * @example + * + * var users = { + * 'fred': { 'user': 'fred', 'age': 40 }, + * 'pebbles': { 'user': 'pebbles', 'age': 1 } + * }; + * + * _.mapValues(users, function(o) { return o.age; }); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + * + * // The `_.property` iteratee shorthand. + * _.mapValues(users, 'age'); + * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed) + */ + function mapValues(object, iteratee) { + var result = {}; + iteratee = getIteratee(iteratee, 3); + + baseForOwn(object, function(value, key, object) { + baseAssignValue(result, key, iteratee(value, key, object)); + }); + return result; + } + + /** + * This method is like `_.assign` except that it recursively merges own and + * inherited enumerable string keyed properties of source objects into the + * destination object. Source properties that resolve to `undefined` are + * skipped if a destination value exists. Array and plain object properties + * are merged recursively. Other objects and value types are overridden by + * assignment. Source objects are applied from left to right. Subsequent + * sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * var object = { + * 'a': [{ 'b': 2 }, { 'd': 4 }] + * }; + * + * var other = { + * 'a': [{ 'c': 3 }, { 'e': 5 }] + * }; + * + * _.merge(object, other); + * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } + */ + var merge = createAssigner(function(object, source, srcIndex) { + baseMerge(object, source, srcIndex); + }); + + /** + * This method is like `_.merge` except that it accepts `customizer` which + * is invoked to produce the merged values of the destination and source + * properties. If `customizer` returns `undefined`, merging is handled by the + * method instead. The `customizer` is invoked with six arguments: + * (objValue, srcValue, key, object, source, stack). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} customizer The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * function customizer(objValue, srcValue) { + * if (_.isArray(objValue)) { + * return objValue.concat(srcValue); + * } + * } + * + * var object = { 'a': [1], 'b': [2] }; + * var other = { 'a': [3], 'b': [4] }; + * + * _.mergeWith(object, other, customizer); + * // => { 'a': [1, 3], 'b': [2, 4] } + */ + var mergeWith = createAssigner(function(object, source, srcIndex, customizer) { + baseMerge(object, source, srcIndex, customizer); + }); + + /** + * The opposite of `_.pick`; this method creates an object composed of the + * own and inherited enumerable property paths of `object` that are not omitted. + * + * **Note:** This method is considerably slower than `_.pick`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [paths] The property paths to omit. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omit(object, ['a', 'c']); + * // => { 'b': '2' } + */ + var omit = flatRest(function(object, paths) { + var result = {}; + if (object == null) { + return result; + } + var isDeep = false; + paths = arrayMap(paths, function(path) { + path = castPath(path, object); + isDeep || (isDeep = path.length > 1); + return path; + }); + copyObject(object, getAllKeysIn(object), result); + if (isDeep) { + result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone); + } + var length = paths.length; + while (length--) { + baseUnset(result, paths[length]); + } + return result; + }); + + /** + * The opposite of `_.pickBy`; this method creates an object composed of + * the own and inherited enumerable string keyed properties of `object` that + * `predicate` doesn't return truthy for. The predicate is invoked with two + * arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omitBy(object, _.isNumber); + * // => { 'b': '2' } + */ + function omitBy(object, predicate) { + return pickBy(object, negate(getIteratee(predicate))); + } + + /** + * Creates an object composed of the picked `object` properties. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pick(object, ['a', 'c']); + * // => { 'a': 1, 'c': 3 } + */ + var pick = flatRest(function(object, paths) { + return object == null ? {} : basePick(object, paths); + }); + + /** + * Creates an object composed of the `object` properties `predicate` returns + * truthy for. The predicate is invoked with two arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pickBy(object, _.isNumber); + * // => { 'a': 1, 'c': 3 } + */ + function pickBy(object, predicate) { + if (object == null) { + return {}; + } + var props = arrayMap(getAllKeysIn(object), function(prop) { + return [prop]; + }); + predicate = getIteratee(predicate); + return basePickBy(object, props, function(value, path) { + return predicate(value, path[0]); + }); + } + + /** + * This method is like `_.get` except that if the resolved value is a + * function it's invoked with the `this` binding of its parent object and + * its result is returned. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to resolve. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; + * + * _.result(object, 'a[0].b.c1'); + * // => 3 + * + * _.result(object, 'a[0].b.c2'); + * // => 4 + * + * _.result(object, 'a[0].b.c3', 'default'); + * // => 'default' + * + * _.result(object, 'a[0].b.c3', _.constant('default')); + * // => 'default' + */ + function result(object, path, defaultValue) { + path = castPath(path, object); + + var index = -1, + length = path.length; + + // Ensure the loop is entered when path is empty. + if (!length) { + length = 1; + object = undefined; + } + while (++index < length) { + var value = object == null ? undefined : object[toKey(path[index])]; + if (value === undefined) { + index = length; + value = defaultValue; + } + object = isFunction(value) ? value.call(object) : value; + } + return object; + } + + /** + * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, + * it's created. Arrays are created for missing index properties while objects + * are created for all other missing properties. Use `_.setWith` to customize + * `path` creation. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @returns {Object} Returns `object`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.set(object, 'a[0].b.c', 4); + * console.log(object.a[0].b.c); + * // => 4 + * + * _.set(object, ['x', '0', 'y', 'z'], 5); + * console.log(object.x[0].y.z); + * // => 5 + */ + function set(object, path, value) { + return object == null ? object : baseSet(object, path, value); + } + + /** + * This method is like `_.set` except that it accepts `customizer` which is + * invoked to produce the objects of `path`. If `customizer` returns `undefined` + * path creation is handled by the method instead. The `customizer` is invoked + * with three arguments: (nsValue, key, nsObject). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * var object = {}; + * + * _.setWith(object, '[0][1]', 'a', Object); + * // => { '0': { '1': 'a' } } + */ + function setWith(object, path, value, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return object == null ? object : baseSet(object, path, value, customizer); + } + + /** + * Creates an array of own enumerable string keyed-value pairs for `object` + * which can be consumed by `_.fromPairs`. If `object` is a map or set, its + * entries are returned. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias entries + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the key-value pairs. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.toPairs(new Foo); + * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed) + */ + var toPairs = createToPairs(keys); + + /** + * Creates an array of own and inherited enumerable string keyed-value pairs + * for `object` which can be consumed by `_.fromPairs`. If `object` is a map + * or set, its entries are returned. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias entriesIn + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the key-value pairs. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.toPairsIn(new Foo); + * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed) + */ + var toPairsIn = createToPairs(keysIn); + + /** + * An alternative to `_.reduce`; this method transforms `object` to a new + * `accumulator` object which is the result of running each of its own + * enumerable string keyed properties thru `iteratee`, with each invocation + * potentially mutating the `accumulator` object. If `accumulator` is not + * provided, a new object with the same `[[Prototype]]` will be used. The + * iteratee is invoked with four arguments: (accumulator, value, key, object). + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @static + * @memberOf _ + * @since 1.3.0 + * @category Object + * @param {Object} object The object to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The custom accumulator value. + * @returns {*} Returns the accumulated value. + * @example + * + * _.transform([2, 3, 4], function(result, n) { + * result.push(n *= n); + * return n % 2 == 0; + * }, []); + * // => [4, 9] + * + * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { + * (result[value] || (result[value] = [])).push(key); + * }, {}); + * // => { '1': ['a', 'c'], '2': ['b'] } + */ + function transform(object, iteratee, accumulator) { + var isArr = isArray(object), + isArrLike = isArr || isBuffer(object) || isTypedArray(object); + + iteratee = getIteratee(iteratee, 4); + if (accumulator == null) { + var Ctor = object && object.constructor; + if (isArrLike) { + accumulator = isArr ? new Ctor : []; + } + else if (isObject(object)) { + accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; + } + else { + accumulator = {}; + } + } + (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) { + return iteratee(accumulator, value, index, object); + }); + return accumulator; + } + + /** + * Removes the property at `path` of `object`. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to unset. + * @returns {boolean} Returns `true` if the property is deleted, else `false`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 7 } }] }; + * _.unset(object, 'a[0].b.c'); + * // => true + * + * console.log(object); + * // => { 'a': [{ 'b': {} }] }; + * + * _.unset(object, ['a', '0', 'b', 'c']); + * // => true + * + * console.log(object); + * // => { 'a': [{ 'b': {} }] }; + */ + function unset(object, path) { + return object == null ? true : baseUnset(object, path); + } + + /** + * This method is like `_.set` except that accepts `updater` to produce the + * value to set. Use `_.updateWith` to customize `path` creation. The `updater` + * is invoked with one argument: (value). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {Function} updater The function to produce the updated value. + * @returns {Object} Returns `object`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.update(object, 'a[0].b.c', function(n) { return n * n; }); + * console.log(object.a[0].b.c); + * // => 9 + * + * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; }); + * console.log(object.x[0].y.z); + * // => 0 + */ + function update(object, path, updater) { + return object == null ? object : baseUpdate(object, path, castFunction(updater)); + } + + /** + * This method is like `_.update` except that it accepts `customizer` which is + * invoked to produce the objects of `path`. If `customizer` returns `undefined` + * path creation is handled by the method instead. The `customizer` is invoked + * with three arguments: (nsValue, key, nsObject). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.6.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {Function} updater The function to produce the updated value. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * var object = {}; + * + * _.updateWith(object, '[0][1]', _.constant('a'), Object); + * // => { '0': { '1': 'a' } } + */ + function updateWith(object, path, updater, customizer) { + customizer = typeof customizer == 'function' ? customizer : undefined; + return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer); + } + + /** + * Creates an array of the own enumerable string keyed property values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.values(new Foo); + * // => [1, 2] (iteration order is not guaranteed) + * + * _.values('hi'); + * // => ['h', 'i'] + */ + function values(object) { + return object == null ? [] : baseValues(object, keys(object)); + } + + /** + * Creates an array of the own and inherited enumerable string keyed property + * values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.valuesIn(new Foo); + * // => [1, 2, 3] (iteration order is not guaranteed) + */ + function valuesIn(object) { + return object == null ? [] : baseValues(object, keysIn(object)); + } + + /*------------------------------------------------------------------------*/ + + /** + * Clamps `number` within the inclusive `lower` and `upper` bounds. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Number + * @param {number} number The number to clamp. + * @param {number} [lower] The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the clamped number. + * @example + * + * _.clamp(-10, -5, 5); + * // => -5 + * + * _.clamp(10, -5, 5); + * // => 5 + */ + function clamp(number, lower, upper) { + if (upper === undefined) { + upper = lower; + lower = undefined; + } + if (upper !== undefined) { + upper = toNumber(upper); + upper = upper === upper ? upper : 0; + } + if (lower !== undefined) { + lower = toNumber(lower); + lower = lower === lower ? lower : 0; + } + return baseClamp(toNumber(number), lower, upper); + } + + /** + * Checks if `n` is between `start` and up to, but not including, `end`. If + * `end` is not specified, it's set to `start` with `start` then set to `0`. + * If `start` is greater than `end` the params are swapped to support + * negative ranges. + * + * @static + * @memberOf _ + * @since 3.3.0 + * @category Number + * @param {number} number The number to check. + * @param {number} [start=0] The start of the range. + * @param {number} end The end of the range. + * @returns {boolean} Returns `true` if `number` is in the range, else `false`. + * @see _.range, _.rangeRight + * @example + * + * _.inRange(3, 2, 4); + * // => true + * + * _.inRange(4, 8); + * // => true + * + * _.inRange(4, 2); + * // => false + * + * _.inRange(2, 2); + * // => false + * + * _.inRange(1.2, 2); + * // => true + * + * _.inRange(5.2, 4); + * // => false + * + * _.inRange(-3, -2, -6); + * // => true + */ + function inRange(number, start, end) { + start = toFinite(start); + if (end === undefined) { + end = start; + start = 0; + } else { + end = toFinite(end); + } + number = toNumber(number); + return baseInRange(number, start, end); + } + + /** + * Produces a random number between the inclusive `lower` and `upper` bounds. + * If only one argument is provided a number between `0` and the given number + * is returned. If `floating` is `true`, or either `lower` or `upper` are + * floats, a floating-point number is returned instead of an integer. + * + * **Note:** JavaScript follows the IEEE-754 standard for resolving + * floating-point values which can produce unexpected results. + * + * @static + * @memberOf _ + * @since 0.7.0 + * @category Number + * @param {number} [lower=0] The lower bound. + * @param {number} [upper=1] The upper bound. + * @param {boolean} [floating] Specify returning a floating-point number. + * @returns {number} Returns the random number. + * @example + * + * _.random(0, 5); + * // => an integer between 0 and 5 + * + * _.random(5); + * // => also an integer between 0 and 5 + * + * _.random(5, true); + * // => a floating-point number between 0 and 5 + * + * _.random(1.2, 5.2); + * // => a floating-point number between 1.2 and 5.2 + */ + function random(lower, upper, floating) { + if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) { + upper = floating = undefined; + } + if (floating === undefined) { + if (typeof upper == 'boolean') { + floating = upper; + upper = undefined; + } + else if (typeof lower == 'boolean') { + floating = lower; + lower = undefined; + } + } + if (lower === undefined && upper === undefined) { + lower = 0; + upper = 1; + } + else { + lower = toFinite(lower); + if (upper === undefined) { + upper = lower; + lower = 0; + } else { + upper = toFinite(upper); + } + } + if (lower > upper) { + var temp = lower; + lower = upper; + upper = temp; + } + if (floating || lower % 1 || upper % 1) { + var rand = nativeRandom(); + return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper); + } + return baseRandom(lower, upper); + } + + /*------------------------------------------------------------------------*/ + + /** + * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the camel cased string. + * @example + * + * _.camelCase('Foo Bar'); + * // => 'fooBar' + * + * _.camelCase('--foo-bar--'); + * // => 'fooBar' + * + * _.camelCase('__FOO_BAR__'); + * // => 'fooBar' + */ + var camelCase = createCompounder(function(result, word, index) { + word = word.toLowerCase(); + return result + (index ? capitalize(word) : word); + }); + + /** + * Converts the first character of `string` to upper case and the remaining + * to lower case. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to capitalize. + * @returns {string} Returns the capitalized string. + * @example + * + * _.capitalize('FRED'); + * // => 'Fred' + */ + function capitalize(string) { + return upperFirst(toString(string).toLowerCase()); + } + + /** + * Deburrs `string` by converting + * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table) + * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A) + * letters to basic Latin letters and removing + * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to deburr. + * @returns {string} Returns the deburred string. + * @example + * + * _.deburr('déjà vu'); + * // => 'deja vu' + */ + function deburr(string) { + string = toString(string); + return string && string.replace(reLatin, deburrLetter).replace(reComboMark, ''); + } + + /** + * Checks if `string` ends with the given target string. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to inspect. + * @param {string} [target] The string to search for. + * @param {number} [position=string.length] The position to search up to. + * @returns {boolean} Returns `true` if `string` ends with `target`, + * else `false`. + * @example + * + * _.endsWith('abc', 'c'); + * // => true + * + * _.endsWith('abc', 'b'); + * // => false + * + * _.endsWith('abc', 'b', 2); + * // => true + */ + function endsWith(string, target, position) { + string = toString(string); + target = baseToString(target); + + var length = string.length; + position = position === undefined + ? length + : baseClamp(toInteger(position), 0, length); + + var end = position; + position -= target.length; + return position >= 0 && string.slice(position, end) == target; + } + + /** + * Converts the characters "&", "<", ">", '"', and "'" in `string` to their + * corresponding HTML entities. + * + * **Note:** No other characters are escaped. To escape additional + * characters use a third-party library like [_he_](https://mths.be/he). + * + * Though the ">" character is escaped for symmetry, characters like + * ">" and "/" don't need escaping in HTML and have no special meaning + * unless they're part of a tag or unquoted attribute value. See + * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) + * (under "semi-related fun fact") for more details. + * + * When working with HTML you should always + * [quote attribute values](http://wonko.com/post/html-escaping) to reduce + * XSS vectors. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escape('fred, barney, & pebbles'); + * // => 'fred, barney, & pebbles' + */ + function escape(string) { + string = toString(string); + return (string && reHasUnescapedHtml.test(string)) + ? string.replace(reUnescapedHtml, escapeHtmlChar) + : string; + } + + /** + * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", + * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escapeRegExp('[lodash](https://lodash.com/)'); + * // => '\[lodash\]\(https://lodash\.com/\)' + */ + function escapeRegExp(string) { + string = toString(string); + return (string && reHasRegExpChar.test(string)) + ? string.replace(reRegExpChar, '\\$&') + : string; + } + + /** + * Converts `string` to + * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the kebab cased string. + * @example + * + * _.kebabCase('Foo Bar'); + * // => 'foo-bar' + * + * _.kebabCase('fooBar'); + * // => 'foo-bar' + * + * _.kebabCase('__FOO_BAR__'); + * // => 'foo-bar' + */ + var kebabCase = createCompounder(function(result, word, index) { + return result + (index ? '-' : '') + word.toLowerCase(); + }); + + /** + * Converts `string`, as space separated words, to lower case. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the lower cased string. + * @example + * + * _.lowerCase('--Foo-Bar--'); + * // => 'foo bar' + * + * _.lowerCase('fooBar'); + * // => 'foo bar' + * + * _.lowerCase('__FOO_BAR__'); + * // => 'foo bar' + */ + var lowerCase = createCompounder(function(result, word, index) { + return result + (index ? ' ' : '') + word.toLowerCase(); + }); + + /** + * Converts the first character of `string` to lower case. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.lowerFirst('Fred'); + * // => 'fred' + * + * _.lowerFirst('FRED'); + * // => 'fRED' + */ + var lowerFirst = createCaseFirst('toLowerCase'); + + /** + * Pads `string` on the left and right sides if it's shorter than `length`. + * Padding characters are truncated if they can't be evenly divided by `length`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.pad('abc', 8); + * // => ' abc ' + * + * _.pad('abc', 8, '_-'); + * // => '_-abc_-_' + * + * _.pad('abc', 3); + * // => 'abc' + */ + function pad(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + if (!length || strLength >= length) { + return string; + } + var mid = (length - strLength) / 2; + return ( + createPadding(nativeFloor(mid), chars) + + string + + createPadding(nativeCeil(mid), chars) + ); + } + + /** + * Pads `string` on the right side if it's shorter than `length`. Padding + * characters are truncated if they exceed `length`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padEnd('abc', 6); + * // => 'abc ' + * + * _.padEnd('abc', 6, '_-'); + * // => 'abc_-_' + * + * _.padEnd('abc', 3); + * // => 'abc' + */ + function padEnd(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + return (length && strLength < length) + ? (string + createPadding(length - strLength, chars)) + : string; + } + + /** + * Pads `string` on the left side if it's shorter than `length`. Padding + * characters are truncated if they exceed `length`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to pad. + * @param {number} [length=0] The padding length. + * @param {string} [chars=' '] The string used as padding. + * @returns {string} Returns the padded string. + * @example + * + * _.padStart('abc', 6); + * // => ' abc' + * + * _.padStart('abc', 6, '_-'); + * // => '_-_abc' + * + * _.padStart('abc', 3); + * // => 'abc' + */ + function padStart(string, length, chars) { + string = toString(string); + length = toInteger(length); + + var strLength = length ? stringSize(string) : 0; + return (length && strLength < length) + ? (createPadding(length - strLength, chars) + string) + : string; + } + + /** + * Converts `string` to an integer of the specified radix. If `radix` is + * `undefined` or `0`, a `radix` of `10` is used unless `value` is a + * hexadecimal, in which case a `radix` of `16` is used. + * + * **Note:** This method aligns with the + * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category String + * @param {string} string The string to convert. + * @param {number} [radix=10] The radix to interpret `value` by. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {number} Returns the converted integer. + * @example + * + * _.parseInt('08'); + * // => 8 + * + * _.map(['6', '08', '10'], _.parseInt); + * // => [6, 8, 10] + */ + function parseInt(string, radix, guard) { + if (guard || radix == null) { + radix = 0; + } else if (radix) { + radix = +radix; + } + return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0); + } + + /** + * Repeats the given string `n` times. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to repeat. + * @param {number} [n=1] The number of times to repeat the string. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {string} Returns the repeated string. + * @example + * + * _.repeat('*', 3); + * // => '***' + * + * _.repeat('abc', 2); + * // => 'abcabc' + * + * _.repeat('abc', 0); + * // => '' + */ + function repeat(string, n, guard) { + if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) { + n = 1; + } else { + n = toInteger(n); + } + return baseRepeat(toString(string), n); + } + + /** + * Replaces matches for `pattern` in `string` with `replacement`. + * + * **Note:** This method is based on + * [`String#replace`](https://mdn.io/String/replace). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to modify. + * @param {RegExp|string} pattern The pattern to replace. + * @param {Function|string} replacement The match replacement. + * @returns {string} Returns the modified string. + * @example + * + * _.replace('Hi Fred', 'Fred', 'Barney'); + * // => 'Hi Barney' + */ + function replace() { + var args = arguments, + string = toString(args[0]); + + return args.length < 3 ? string : string.replace(args[1], args[2]); + } + + /** + * Converts `string` to + * [snake case](https://en.wikipedia.org/wiki/Snake_case). + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the snake cased string. + * @example + * + * _.snakeCase('Foo Bar'); + * // => 'foo_bar' + * + * _.snakeCase('fooBar'); + * // => 'foo_bar' + * + * _.snakeCase('--FOO-BAR--'); + * // => 'foo_bar' + */ + var snakeCase = createCompounder(function(result, word, index) { + return result + (index ? '_' : '') + word.toLowerCase(); + }); + + /** + * Splits `string` by `separator`. + * + * **Note:** This method is based on + * [`String#split`](https://mdn.io/String/split). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category String + * @param {string} [string=''] The string to split. + * @param {RegExp|string} separator The separator pattern to split by. + * @param {number} [limit] The length to truncate results to. + * @returns {Array} Returns the string segments. + * @example + * + * _.split('a-b-c', '-', 2); + * // => ['a', 'b'] + */ + function split(string, separator, limit) { + if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) { + separator = limit = undefined; + } + limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0; + if (!limit) { + return []; + } + string = toString(string); + if (string && ( + typeof separator == 'string' || + (separator != null && !isRegExp(separator)) + )) { + separator = baseToString(separator); + if (!separator && hasUnicode(string)) { + return castSlice(stringToArray(string), 0, limit); + } + } + return string.split(separator, limit); + } + + /** + * Converts `string` to + * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage). + * + * @static + * @memberOf _ + * @since 3.1.0 + * @category String + * @param {string} [string=''] The string to convert. + * @returns {string} Returns the start cased string. + * @example + * + * _.startCase('--foo-bar--'); + * // => 'Foo Bar' + * + * _.startCase('fooBar'); + * // => 'Foo Bar' + * + * _.startCase('__FOO_BAR__'); + * // => 'FOO BAR' + */ + var startCase = createCompounder(function(result, word, index) { + return result + (index ? ' ' : '') + upperFirst(word); + }); + + /** + * Checks if `string` starts with the given target string. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to inspect. + * @param {string} [target] The string to search for. + * @param {number} [position=0] The position to search from. + * @returns {boolean} Returns `true` if `string` starts with `target`, + * else `false`. + * @example + * + * _.startsWith('abc', 'a'); + * // => true + * + * _.startsWith('abc', 'b'); + * // => false + * + * _.startsWith('abc', 'b', 1); + * // => true + */ + function startsWith(string, target, position) { + string = toString(string); + position = position == null + ? 0 + : baseClamp(toInteger(position), 0, string.length); + + target = baseToString(target); + return string.slice(position, position + target.length) == target; + } + + /** + * Creates a compiled template function that can interpolate data properties + * in "interpolate" delimiters, HTML-escape interpolated data properties in + * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data + * properties may be accessed as free variables in the template. If a setting + * object is given, it takes precedence over `_.templateSettings` values. + * + * **Note:** In the development build `_.template` utilizes + * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) + * for easier debugging. + * + * For more information on precompiling templates see + * [lodash's custom builds documentation](https://lodash.com/custom-builds). + * + * For more information on Chrome extension sandboxes see + * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category String + * @param {string} [string=''] The template string. + * @param {Object} [options={}] The options object. + * @param {RegExp} [options.escape=_.templateSettings.escape] + * The HTML "escape" delimiter. + * @param {RegExp} [options.evaluate=_.templateSettings.evaluate] + * The "evaluate" delimiter. + * @param {Object} [options.imports=_.templateSettings.imports] + * An object to import into the template as free variables. + * @param {RegExp} [options.interpolate=_.templateSettings.interpolate] + * The "interpolate" delimiter. + * @param {string} [options.sourceURL='lodash.templateSources[n]'] + * The sourceURL of the compiled template. + * @param {string} [options.variable='obj'] + * The data object variable name. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Function} Returns the compiled template function. + * @example + * + * // Use the "interpolate" delimiter to create a compiled template. + * var compiled = _.template('hello <%= user %>!'); + * compiled({ 'user': 'fred' }); + * // => 'hello fred!' + * + * // Use the HTML "escape" delimiter to escape data property values. + * var compiled = _.template('<%- value %>'); + * compiled({ 'value': '